- 写驱动程序要去操作硬件,但是操作硬件并不是主要的,主要的是要理解驱动程序的框架
 - Linux驱动 = 驱动框架+硬件操作 = 驱动框架+单片机
 - 实际工作中,更多的是去理解修改别人的驱动程序
 - 面向对象
- 字符设备驱动程序抽象出一个 file_operations 结构体
 - 我们写的程序针对硬件部分抽象出 led_operations 结构体
 
 - 分层
- 前面的 LED 驱动程序就分为 2 层:
 
 
① 上层实现硬件无关的操作,比如注册字符设备驱动:leddrv.c
② 下层实现硬件相关的操作,比如 board_A.c 实现单板 A 的 LED 操作
- 分离
- 之前的board_x.c的代码跟硬件绑定的得太死了,操作某个灯就操作某个寄存器,如果想换个灯就需要换个寄存器
 - 对于同一款芯片,它的GPIO引脚操作是类似的
 - 既然引脚操作那么有规律,并且这是跟主芯片相关的,那可以针对该芯片写出比较通用的硬件操作代码
 - 对于某一款芯片,可以写出一个GPIO的驱动程序,让它支持所有的GPIO操作
 - 比如 board_A.c 使用芯片 chipY,那就可以写出:chipY_gpio.c,它实现芯片 Y 的 GPIO 操作,适用于芯片 Y 的所有 GPIO 引脚。
 
- 左边是led资源(实现led_resource),右边是某款芯片通用的硬件驱动
 - 以面向对象的思想,在 board_A_led.c 中实现 led_resouce 结构体,它定义“资源”──要用哪一个引脚
 
 - 修改内核打印级别
 - 程序仍分为上下结构:上层 leddrv.c 向内核注册 file_operations 结构体;下层 chip_demo_gpio.c 提供 led_operations 结构体来操作硬件。
 - 下层的代码分为 2 个:chip_demo_gpio.c 实现通用的 GPIO 操作,board_A_led.c 指定使用哪个 GPIO,即“资源”。
 - 这样当不同的板子使用不同gpio时,只需修改board_x_led.c指定哪个gpio即可(修改资源)
 - led_resource.h
```c
/ GPIO3_0 /
/ bit[31:16] = group /
/ bit[15:0]  = which pin /
define GROUP(x) (x>>16)
define PIN(x) (x&0xFFFF)
define GROUP_PIN(g,p) ((g<<16) | (p))
 
struct led_resource { int pin; };
struct led_resource *get_led_resouce(void);
- board_A_led.c中实现资源的确定```cstatic struct led_resource board_A_led = {.pin = GROUP_PIN(3,1),};struct led_resource *get_led_resouce(void){return &board_A_led;}
chip_demo_gpio.c 中实现了通用的 GPIO 操作,只需包含资源即可
static struct led_resource *led_rsc;static int board_demo_led_init (int which) /* 初始化LED, which-哪个LED */{//printk("%s %s line %d, led %d\n", __FILE__, __FUNCTION__, __LINE__, which);if (!led_rsc){led_rsc = get_led_resouce(); /* 获取资源 */}printk("init gpio: group %d, pin %d\n", GROUP(led_rsc->pin), PIN(led_rsc->pin));/* 根据资源进行初始化 */switch(GROUP(led_rsc->pin)){case 0:{printk("init pin of group 0 ...\n");break;}case 1:{printk("init pin of group 1 ...\n");break;}case 2:{printk("init pin of group 2 ...\n");break;}case 3:{printk("init pin of group 3 ...\n");break;}}return 0;}
makefile修改成 ```makefile
参考内核源码drivers/char/ipmi/Makefile
要想把a.c, b.c编译成ab.ko, 可以这样指定:
ab-y := a.o b.o
obj-m += ab.o
leddrv.c chip_demo_gpio.c board_A_led.c 编译成 100ask.ko
100ask_led-y := leddrv.o chip_demo_gpio.o board_A_led.o obj-m += 100ask_led.o ```
- 课后练习
使用“分离”的思想,去改造前面写的 LED 驱动程序:实现 led_resouce,在里面可以指定要使用哪一个 LED;改造led_operations,让它能支持更多 GPIO。
 
注意:作为练习,led_operations 结构体不需要写得很完善,不需要支持所有 GPIO,你可以只支持若干个 GPIO 即可。


