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 }

 

posted @ 2022-03-23 16:29  咸阳梁硕  阅读(59)  评论(0)    收藏  举报