基于mini2440的led驱动编写的总结(可以成为模板)
该驱动用到I/O常见的端口操作函数:s3c2410_gpio_cfgpin和s3c2410_gpio_setpin。前一函数实现了设置端口的状态为输入/输出/其他,后一函数实现了端口输出高/低电平。主要谈一下前一个函数的一些重要语句。首先是原型:s3c2410_gpio_cfgpin(unsignedint pin,unsigned intfunction),那么我们在驱动中怎么运用呢?比如:s3c2410_gpio_cfgpin(S3C2410_GPB(5),S3C2410_GPB_OUTPUT),那么里面两个函数是怎么操作的?请看下面的这几个定义:
1、#defineS3C2410_GPB(_nr)
2、enum s3c_gpio_number{
......
}//定义同上
3、#define S3C2410_GPIO_NEXT(__gpio)\
4、CONFIG_S3C_GPIO_SPACE的定义在.config文件中,见下面:
......
#
#power managment
#
CONFIG_S3C_LOWLEVEL_UART_PORT=0
CONFIG_S3C_GPIO_SPACE=0
......
5、#defineS3C2410_GPIO_A_NR
由以上所有定义可以得知以下结论:S3C2410_GPB(5)-->(S3C2410_GPIO_B_START+5)-->S3C2410_GPIO_NEXT(S3C2410_GPIO_A)+5-->((S3C2410_GPIO_A_START)+ S3C2410_GPIO_A_NR) + CONFIG_S3C_GPIO_SPACE + 0)+5,
这就表示从GPA首地址+GPA个数+GPB的偏移个数是当前GPB的I/O的偏移量。即GPB(5)等于32+0+5=37,即pin=37。至于这怎么和GPB端口的寄存器扯上关系的有待进一步深入内核。
另外在/arch/arm/mach-s3c2410/include/mach/regs-gpio.h的第45行有如下定义:
#defineS3C2410_GPIO_LEAVE
#defineS3C2410_GPIO_INPUT
#defineS3C2410_GPIO_OUTPUT
这时我们开始讲编写整个驱动的流程,其中分为两种方法。
方法一、(将LED注册为混杂设备)
a:首先确定file_operation中要填写几个操作函数,这里因为注册为混杂设备所以只有ioctl操作。
b:其次编写ioctl的实现。
c:注册LED为misc设备:
static struct miscdevicemisc={
}
d:编写初始化函数与退出函数。
具体程序如下:
#include<linux/miscdevice.h>
#include <linux/delay.h>
#include <asm/irq.h>
#include <mach/regs-gpio.h>
#include <mach/hardware.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/mm.h>
#include <linux/fs.h>
#include <linux/types.h>
#include <linux/delay.h>
#include <linux/moduleparam.h>
#include <linux/slab.h>
#include <linux/errno.h>
#include <linux/ioctl.h>
#include <linux/cdev.h>
#include <linux/string.h>
#include <linux/list.h>
#include <linux/pci.h>
#include <linux/gpio.h>
#include <asm/uaccess.h>
#include <asm/atomic.h>
#include <asm/unistd.h>
#define DEVICE_NAME "leds"
static unsigned longled_table [] = {
};
static unsigned intled_cfg_table [] = {
};
static intsbc2440_leds_ioctl(
{
switch(cmd)
}
static structfile_operations dev_fops = {
};
static structmiscdevice misc = {
};
static int __initmini2440_leds_init(void)
{
}
static void __exitmini2440_leds_exit(void)
{
}
module_init(mini2440_leds_init);
module_exit(mini2440_leds_exit);
方法二:(将LED注册为普通字符设备)
步骤与上面类似除还得编写open函数,但不用加上注册那个misc设备。具体程序如下:
#include<linux/delay.h>
#include <asm/irq.h>
#include <mach/regs-gpio.h>
#include <mach/hardware.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/mm.h>
#include <linux/fs.h>
#include <linux/types.h>
#include <linux/delay.h>
#include <linux/moduleparam.h>
#include <linux/slab.h>
#include <linux/errno.h>
#include <linux/ioctl.h>
#include <linux/cdev.h>
#include <linux/string.h>
#include <linux/list.h>
#include <linux/pci.h>
#include <linux/gpio.h>
#include <asm/uaccess.h>
#include <asm/atomic.h>
#include <asm/unistd.h>
#define DEVICE_NAME"leds"
//将端口做成数组,以便于编写
static unsigned longled_table [] = {
};
static unsigned intled_cfg_table [] = {
};
//open函数的实现,其形参不能改变,这是模板
stativ intmini2440_leds_open(struct inode *inode,struct file*file)
{
}
//ioctl函数的实现,里面的形参是固定格式,不需更改
static intmini2440_leds_ioctl(
{
switch(cmd)
{
}
//最重要的结构体之一
static structfile_operations mini2440_leds_fops = {
};
//初始化函数以及退出函数的写法,记住他们的格式
static int __initmini2440_leds__init(void)
{
if(ret<0)
{
printk(DEVICE_NAME"can not registermajor\n");
returnret;
}
printk(DEVICE_NAME"initialized!\n");
}
static void __exitmini2440_leds_exit(void)
{
}
module_init(mini2440_leds_init);
module_exit(mini2440_leds_exit);