字符驱动设备(3)
led-drv.c:
1 #include <linux/module.h> 2 #include <linux/kernel.h> 3 #include <linux/fs.h> 4 #include <linux/init.h> 5 #include <linux/delay.h> 6 #include <asm/uaccess.h> 7 #include <asm/irq.h> 8 #include <asm/io.h> 9 #include <asm/arch/regs-gpio.h> 10 #include <asm/hardware.h> 11 12 static int led_drv_open(struct inode *inode, struct file *file) 13 { 14 printk("led_open\n"); 15 16 return 0; 17 } 18 19 static ssize_t led_drv_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) 20 { 21 printk("led_write\n"); 22 23 return 0; 24 } 25 26 static struct file_operations led_fops = { 27 .owner = THIS_MODULE, 28 .open = led_drv_open, 29 .write = led_drv_write, 30 }; 31 32 /*入口函数*/ 33 static int __init led_drv_init(void) 34 { 35 register_chrdev(111, "led_drv",&led_fops); 36 37 return 0; 38 } 39 40 /*出口函数*/ 41 static int __exit led_drv_exit(void) 42 { 43 unregister_chrdev(111, "led_drv"); 44 45 return 0; 46 } 47 48 module_init(led_drv_init); 49 module_exit(led_drv_exit); 50 51 MODULE_LICENSE("GPL"); 52 MODULE_AUTHOR("ZHANGPENG");
led_drv_test.c:
1 #include <sys/types.h> 2 #include <sys/stat.h> 3 #include <fcntl.h> 4 #include <stdio.h> 5 6 int main(int argc,char **argv) 7 { 8 int fd; 9 int val = 1; 10 11 fd = open("/dev/led",O_RDWR); 12 if(fd<0) 13 { 14 printf("can't open!\n"); 15 } 16 17 write(fd,&val,4); 18 19 return 0; 20 }
Makefile:
1 KERN_DIR = /home/zhangpeng/workspace/kernel/linux-2.6.22.6 2 3 all: 4 make -C $(KERN_DIR) M=`pwd` modules 5 6 clean: 7 make -C $(KERN_DIR) M=`pwd` modules clean 8 rm -rf modules.order 9 10 obj-m += led_drv.o
编译测试过程:
1.make
2.insmod led_drv.ko //加载模块
3.arm-linux-gcc -o led_drv_test led_drv_test.c //编译测试程序
1 #include <sys/types.h> 2 #include <sys/stat.h> 3 #include <fcntl.h> 4 #include <stdio.h> 5 6 int main(int argc,char **argv) 7 { 8 int fd; 9 int val = 1; 10 11 fd = open("/dev/xxx",O_RDWR);//注意了,如果这里的"/dev/xxx"和led_drv.c里面的设备名一致,直接运行:./led_drv_test即可。或者手动创建节点也可以,例如:mknod /dev/xxx c 111 0 12 if(fd<0) 13 { 14 printf("can't open!\n"); 15 } 16 17 write(fd,&val,4); 18 19 return 0; 20 }
关于主设备号问题:
主设备号可以手动设置,也可以设置为系统自动分配。
1 int major; 2 3 /*入口函数*/ 4 static int __init led_drv_init(void) 5 { 6 major = register_chrdev(0, "led_drv",&led_fops);//默认为0会自动分配 7 8 return 0; 9 } 10 11 /*出口函数*/ 12 static int __exit led_drv_exit(void) 13 { 14 unregister_chrdev(major, "led_drv"); 15 16 return 0; 17 }
但是,这里也只是仅仅解决了主设备号生成方式的问题,与APP程序如何能打开对应的设备驱动呢?除了上述的手动创建测试程序的节点:mknod /dev/xxx c 111 0 之外,还有没有其他的改进方式呢?
1 static struct class *led_drv_class; 2 static struct class_device *led_drv_class_dev; 3 4 /*入口函数*/ 5 static int __init led_drv_init(void) 6 { 7 major = register_chrdev(0, "led_drv",&led_fops); 8 9 led_drv_class = class_create(THIS_MODULE, "led_drv"); 10 led_drv_class_dev = class_device_create(led_drv_class, NULL, MKDEV(major, 0), NULL, "led_drv"); 11 12 return 0; 13 } 14 15 /*出口函数*/ 16 static int __exit led_drv_exit(void) 17 { 18 unregister_chrdev(major, "led_drv"); 19 20 class_device_unregister(led_drv_class_dev); 21 class_destroy(led_drv_class); 22 23 return 0; 24 }
这样以来,就完成解决了驱动程序和测试程序/APP程序打开设备 open("/dev/led_drv",O_RDWR) 设备名不一致的问题了。