Linux驱动必须先由module_init ( function_name)函数载入驱动,由module_exit (function_name )函数卸载驱动,其中function_name分别为初始化函数和清除设备的函数。
要创建一个设备,得使用dev_t devno = MKDEV(DL402_MAJOR, 0)获取设备号,其中DL402_MAJOR是接口板的主设备号,再使用函数register_chrdev_region向系统注册字符驱动,register_chrdev_region函数定义为:
int register_chrdev_region(dev_tfirst, unsigned int count, char *name);
其中第一个参数是要注册的设备号,第二个参数是要注册设备的个数,第三个是要注册设备的设备名。
注册字符设备后,用request_region(unsigned longfirst, unsigned long n, const char *name) 函数向内核申请n个I/O端口,这些端口从first开始,name参数为设备的名称,成功返回非NULL。申请了个I/O端口后,便该申请一个中断接口。
使用request_irq(unsigned int irq, irqreturn_t(*handler), unsigned long flags, const char *dev_name, void *dev_id)函数向内核申请中断接口,其中参数irq表示所要申请的硬件中断号;handler为向系统登记的中断处理子程序名;flags是申请时的选项,它决定中断处理程序的一些特性dev_name为设备名,将会出现在/proc/interrupts文件里。如果中断由某个处理程序独占,则dev_id可以为NULL。request_irq返回0表示成功,返回-INVAL表示irq>15或handler==NULL,返回-EBUSY表示中断已经被占用且不能共享。若申请失败同样取消之前的步骤。在卸载模块时需释放中断使用void free_irq(unsigned int irq,void *dev_id)。
初始化字符设备和加载字符设备,使用设备需要一系列函数,这些函数需要包含到结构体file_operations中,其中包含读、打开以及中断处理的函数,定义函数void read(void)、void open(void)、voidioctl(void),以及结构体:
static const struct file_operations fops = {
.owner = THIS_MODULE,
.read = read,
.open = open,
.unlocked_ioctl = ioctl,
};
之后,方可初始化、加载字符设备:
cdev_init(dev, &fops);
ret = cdev_add(dev, devno, 1);
cdev_add函数返回0则成功,检测其是否成功只需要检测ret是否为0,失败需要释放端口设备号、申请的内存以及申请的I/O端口号:
free_irq(0,dev);
unregister_chrdev_region(devno, 1);
release_region(0, 1);
kfree(dev);
return ret;
至此,初始化的程序以及完成,还需要卸载驱动的程序,建立函数void exit(void)为卸载驱动的函数,其中应包含释放设备号、申请的I/O端口、释放中断接口:
free_irq(0, dev);
free_irq(0, NULL);
release_region(0, 1);
kfree(dev);
最后需要动态加载初始化驱动的函数以及卸载驱动的函数:
module_init(init);
module_exit(exit);
编译、执行后,在shell界面上执行命令”lsmod”,在Module栏下看到你的设备名称则成功,安装以上来写的程序,应该看到“Test”。若要卸载设备,只需要在shell界面上执行命令”remod 设备名称”即可。