- 写驱动程序要去操作硬件,但是操作硬件并不是主要的,主要的是要理解驱动程序的框架
- 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中实现资源的确定
```c
static 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 即可。