LED驱动的分离分层法(下)
在我们讲述的第一种方法中已经使用了分层的思想。那么在此文件中我们将继续使用在此集成商增加分离的思想。原因是如果硬件上更换一个引脚来控制LED怎么办?要去修改上面结构体中的init、ctl函数。所以加这个分层的办法。

如下:我们先完成leddrv.c文件。
1 #include <linux/module.h> 2 3 #include <linux/fs.h> 4 #include <linux/errno.h> 5 #include <linux/miscdevice.h> 6 #include <linux/kernel.h> 7 #include <linux/major.h> 8 #include <linux/mutex.h> 9 #include <linux/proc_fs.h> 10 #include <linux/seq_file.h> 11 #include <linux/stat.h> 12 #include <linux/init.h> 13 #include <linux/device.h> 14 #include <linux/tty.h> 15 #include <linux/kmod.h> 16 #include <linux/gfp.h> 17 18 #include "led_opr.h" 19 20 #define LED_NUM 2 21 22 /* 1. 确定主设备号 */ 23 static int major = 0; 24 static struct class *led_class; 25 struct led_operations *p_led_opr; 26 27 28 #define MIN(a, b) (a < b ? a : b) 29 /* 2. 定义自己的file_operations结构体 */ 30 static struct file_operations led_drv = { 31 .owner = THIS_MODULE, 32 .open = led_drv_open, 33 .read = led_drv_read, 34 .write = led_drv_write, 35 .release = led_drv_close, 36 }; 37 /* 3. 实现对应的open/read/write等函数,填入file_operations结构体 */ 38 static int led_drv_open (struct inode *node, struct file *file) 39 { 40 int minor = iminor(node); 41 42 printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__); 43 /* 根据次设备号初始化LED */ 44 p_led_opr->init(minor); 45 46 return 0; 47 } 48 static ssize_t led_drv_read (struct file *file, char __user *buf, size_t size, loff_t *offset) 49 { 50 printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__); 51 return 0; 52 } 53 54 /* write(fd, &val, 1); */ 55 static ssize_t led_drv_write (struct file *file, const char __user *buf, size_t size, loff_t *offset) 56 { 57 int err; 58 char status; 59 struct inode *inode = file_inode(file); 60 int minor = iminor(inode); 61 62 printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__); 63 err = copy_from_user(&status, buf, 1); 64 65 /* 根据次设备号和status控制LED */ 66 p_led_opr->ctl(minor, status); 67 68 return 1; 69 } 70 71 static int led_drv_close (struct inode *node, struct file *file) 72 { 73 printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__); 74 return 0; 75 } 76 77 78 79 /* 4. 把file_operations结构体告诉内核:注册驱动程序 */ 80 /* 5. 谁来注册驱动程序啊?得有一个入口函数:安装驱动程序时,就会去调用这个入口函数 */ 81 static int __init led_init(void) 82 { 83 int err; 84 int i; 85 86 printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__); 87 major = register_chrdev(0, "100ask_led", &led_drv); /* /dev/led */ 88 89 90 led_class = class_create(THIS_MODULE, "100ask_led_class"); 91 err = PTR_ERR(led_class); 92 if (IS_ERR(led_class)) { 93 printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__); 94 unregister_chrdev(major, "led"); 95 return -1; 96 } 97 98 for (i = 0; i < LED_NUM; i++) 99 device_create(led_class, NULL, MKDEV(major, i), NULL, "100ask_led%d", i); /* /dev/100ask_led0,1,... */ 100 101 p_led_opr = get_board_led_opr(); 102 103 return 0; 104 } 105 106 /* 6. 有入口函数就应该有出口函数:卸载驱动程序时,就会去调用这个出口函数 */ 107 static void __exit led_exit(void) 108 { 109 int i; 110 printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__); 111 112 for (i = 0; i < LED_NUM; i++) 113 device_destroy(led_class, MKDEV(major, i)); /* /dev/100ask_led0,1,... */ 114 115 device_destroy(led_class, MKDEV(major, 0)); 116 class_destroy(led_class); 117 unregister_chrdev(major, "100ask_led"); 118 } 119 120 121 /* 7. 其他完善:提供设备信息,自动创建设备节点 */ 122 123 module_init(led_init); 124 module_exit(led_exit); 125 126 MODULE_LICENSE("GPL");
依然不变向下调用是led_opr.h文件
1 #ifndef _LED_OPR_H 2 #define _LED_OPR_H 3 4 struct led_operations { 5 int (*init) (int which); /* 初始化LED, which-哪个LED */ 6 int (*ctl) (int which, char status); /* 控制LED, which-哪个LED, status:1-亮,0-灭 */ 7 }; 8 9 struct led_operations *get_board_led_opr(void); 10 11 #endif
在如下的文件中开始实现分离。先实现init和ctl这两个在chip_dome_gpio.c文件中实现。
1 #include <linux/errno.h> 2 #include <linux/miscdevice.h> 3 #include <linux/kernel.h> 4 #include <linux/major.h> 5 #include <linux/mutex.h> 6 #include <linux/proc_fs.h> 7 #include <linux/seq_file.h> 8 #include <linux/stat.h> 9 #include <linux/init.h> 10 #include <linux/device.h> 11 #include <linux/tty.h> 12 #include <linux/kmod.h> 13 #include <linux/gfp.h> 14 #include "led_opr.h" 15 #include "led_resource.h" 16 17 static struct led_resource *led_rsc; 18 static int board_demo_led_init (int which) /* 初始化LED, which-哪个LED */ 19 { 20 //printk("%s %s line %d, led %d\n", __FILE__, __FUNCTION__, __LINE__, which); 21 if (!led_rsc) 22 { 23 led_rsc = get_led_resouce(); 24 } 25 26 printk("init gpio: group %d, pin %d\n", GROUP(led_rsc->pin), PIN(led_rsc->pin)); 27 switch(GROUP(led_rsc->pin)) 28 { 29 case 0: 30 { 31 printk("init pin of group 0 ...\n"); 32 break; 33 } 34 case 1: 35 { 36 printk("init pin of group 1 ...\n"); 37 break; 38 } 39 case 2: 40 { 41 printk("init pin of group 2 ...\n"); 42 break; 43 } 44 case 3: 45 { 46 printk("init pin of group 3 ...\n"); 47 break; 48 } 49 } 50 51 return 0; 52 } 53 54 static int board_demo_led_ctl (int which, char status) /* 控制LED, which-哪个LED, status:1-亮,0-灭 */ 55 { 56 //printk("%s %s line %d, led %d, %s\n", __FILE__, __FUNCTION__, __LINE__, which, status ? "on" : "off"); 57 printk("set led %s: group %d, pin %d\n", status ? "on" : "off", GROUP(led_rsc->pin), PIN(led_rsc->pin)); 58 59 switch(GROUP(led_rsc->pin)) 60 { 61 case 0: 62 { 63 printk("set pin of group 0 ...\n"); 64 break; 65 } 66 case 1: 67 { 68 printk("set pin of group 1 ...\n"); 69 break; 70 } 71 case 2: 72 { 73 printk("set pin of group 2 ...\n"); 74 break; 75 } 76 case 3: 77 { 78 printk("set pin of group 3 ...\n"); 79 break; 80 } 81 } 82 83 return 0; 84 } 85 86 static struct led_operations board_demo_led_opr = { 87 .init = board_demo_led_init, 88 .ctl = board_demo_led_ctl, 89 }; 90 91 struct led_operations *get_board_led_opr(void) 92 { 93 return &board_demo_led_opr; 94 }
在此文件下包含资源文件的头文件。所有的引脚的操作都是通用的。
1 #ifndef _LED_RESOURCE_H 2 #define _LED_RESOURCE_H 3 4 /* GPIO3_0 */ 5 /* bit[31:16] = group */ 6 /* bit[15:0] = which pin */ 7 #define GROUP(x) (x>>16) 8 #define PIN(x) (x&0xFFFF) 9 #define GROUP_PIN(g,p) ((g<<16) | (p)) 10 11 struct led_resource { 12 int pin; 13 }; 14 15 struct led_resource *get_led_resouce(void); 16 17 #endif
与之对应的有资源文件的c文件,每次改变引脚时候,只需要改变这个文件就可以了,不必在更改其他文件。
1 #include "led_resource.h" 2 3 static struct led_resource board_A_led = { 4 .pin = GROUP_PIN(3,1), 5 }; 6 7 struct led_resource *get_led_resouce(void) 8 { 9 return &board_A_led; 10 }

浙公网安备 33010602011771号