第一个字符设备驱动程序——first_drv 1、编写驱动程序first_drv.c (1)编写函数first_drv_open()等 (2)在内核中挂载驱动程序 1)定义一个staticstruct file_operations first_drv_fops={ .owner = THIS_MODULE, /* 这是一个宏,推向编译模块时自动创建的__this_module变量*/ .open = first_drv_open, .write = first_drv_write, } 2)把这个结构在内核注册: register_chrdev(unsigned intmajor, const char * name, const struct file_operations * fops) 3)驱动入口调用注册函数: intfirst_drv_init(viod) { register_chrdev(111,"first_drv", &first_drv_fops); return 0; } 4)修饰调用入口函数: module_init(first_drv_init) (3)卸载驱动程序 void first_drv_exit(void) { unregister_chrdev(111,”first_dev”) } 修饰卸载函数: module_exit(first_drv_exit); (4)MODULE_LICENSE(GPL); 2、编译first_drv.c: 使用Makefile: KERN_DIR =/work/system/linux-2.6.22.6 //使用/work/system/linux-2.6.22.6/Makefile all: make-C $(KERN_DIR) M=`pwd` modules clean: make-C $(KERN_DIR) M=`pwd` modules clean rm-rf modules.order obj-m += first_drv.o 得到first_drv.ko 文件 3、加载first_drv.ko (1)/first_drv$ cp first_drv.ko /home/first_fs //复制到之前制作的根文件系统 (2)将first_fs根文件系统下载到开发板上并启动 (3)#insmod first_drv.ko //加载first_drv.ko模块 (4)#cat /proc/devices //打印出目前内核中支持的设备 4、创建first_drv设备节点 #mknod /dev/xxx c 111 0 设备节点的名称可以随便取,这里设为xxx 问题:如何确定创建设备节点的主设备号? 方法一:#cat proc/devices //查看单板中还有哪些空缺主设备号,选一个未使用的即可 方法二: int major; int first_drv_init(viod) { major = register_chrdev(0, "first_drv",&first_drv_fops); return 0; } void first_drv_exit(void) { unregister_chrdev(major, ”first_dev”) } 将主设备号设为0,系统自动分配 (1)手动设置:将分配的主设备号为设备节点的主设备号 (2)自动设置:使用mdev,当我们注册(加载)一个驱动设备时,系统会在/sys目录下自动生成这个设备节点的相关信息, mdev会根据系统信息自动创建设备节点 1)在first_drv.c中添加: static struct class *firstdrv_class; static struct class_device *firstdrv_class_dev; 2)int first_drv_init(viod) { major= register_chrdev(0, "first_drv", &first_drv_fops); firstdrv_class = class_create(THIS_MODULE,"firstdrv"); firstdrv_class_dev = class_device_create(firstdrv_class,NULL, MKDEV(major, 0), NULL, "xxx"); return 0; } 相应的,在卸载驱动是同样添加: voidfirst_drv_exit(void) { unregister_chrdev(major,”first_dev”); class_device_unregister(firstdrv_class_dev); class_destory (firstdrv_class); } 重新编译即可 5、写一个测试程序firstdrvtest.c #include #include #include #include staticstruct class *firstdrv_class; static struct class_device *firstdrv_class_dev; int main(int argc, char **argv) { int fd; int val = 1; fd = open("/dev/xxx",O_RDWR); //相应的执行驱动程序里的first_drv_open函数 if (fd < 0) { printf("can'topen!n"); } write("/dev/xxx",O_RDWR); // //相应的执行驱动程序里的first_drv_write函数 return 0; } Question: 为什么open、write与first_drv_open、first_drv_write相对应? 6、编译firstdrvtest.c first_drv$ ARM-linux-gcc –o firstdrvtest firstdrvtest.c first_drv$ chmod +x firstdrvtest //增加可执行属性,否则执行时会出现-sh:./firstdrvtest: Permission denied first_drv$ cp firstdrvtest /home/book/first_fs 7、#./firstdrvtest //执行 附first_drv.c: #include #include #include #include #include #include #include #include #include #include staticint first_drv_open(struct inode *inode, struct file *file) { printk("first_drv_openn"); return 0; } staticssize_t first_drv_write(struct file *file, const char __user *buf, size_tcount, loff_t * ppos) { printk("first_drv_writen"); return 0; } staticstruct file_operations first_drv_fops = { .owner = THIS_MODULE, /* 这是一个宏,推向编译模块时自动创建的__this_module变量 */ .open = first_drv_open, .write = first_drv_write, }; intfirst_drv_init(void) { major=register_chrdev(0,"first_drv", &first_drv_fops); firstdrv_class =class_create(THIS_MODULE, "firstdrv"); firstdrv_class_dev =class_device_create(firstdrv_class, NULL, MKDEV(major, 0), NULL,"xxx"); return 0; } voidfirst_drv_exit(void) { unregister_chrdev(major,"first_drv"); class_device_unregister(firstdrv_class_dev); class_destroy (firstdrv_class); } module_init(first_drv_init); module_exit(first_drv_exit); MODULE_LICENSE("GPL");
|