面向对线
驱动设计的思想跟面向对象的思想类似,就是实现分层分离。
- 字符设备驱动程序抽象出一个
file_operations
结构体; - 我们的程序针对硬件部分抽象出
led_operations
结构体。
分层
上下分层,比如我们写的 LED 驱动程序分为两层:
- 上层实现硬件无关的操作,比如注册字符设备驱动:leddrv.c
- 下层实现硬件相关的操作,比如 board_A.c 实现单板 A 的 LED 操作,board_B.c 实现单板 B 的 LED 操作。
分离
在分层的基础上还可以进一步改进?
在 board_A.c 中,实现了一个 led_operations
,为 LED 引脚实现了初始化函数和控制函数:
static struct led_operations board_demo_led_opr = {
.num = 1,
.init = board_demo_led_init,
.ctl = board_demo_led_ctl,
};
如果硬件要更换一个引脚来控制 LED,就要对上面结构体中的 init、ctl 函数进行更改,比较麻烦。
对于同一个主芯片,操作 led 的步骤是一样的,因此我们可以针对该芯片写出比较通用的硬件操作代码。
比如 board_A.c 使用芯片 chipY,那就可以写出 chipY_gpio.c,它实现芯片 Y 的 GPIO 操作,适用于芯片 Y 的所有 GPIO 引脚。
使用时,我们只需要在 board_A_led. c 中指定使用哪个引脚即可。
程序仍然分为上下结构:上层还是向内核注册 [[4. 驱动入门#^caba23|file_operations]] ;
下层的代码分为两个:chip_demo_gpio. c 实现通用的 GPIO 操作,board_A_led. c 指定使用哪个 GPIO, 即“资源”。
led_resource. h 定义了 led_resource 结构体,用来描述 GPIO:
/* 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_r esouce(void);
board_A_led. c 指定使用哪个 GPIO, 它实现了一个 led_resource 结构体,并提供访问函数:
#include "led_resource.h"
static struct led_resource board_A_led = {
.pin = GROUP_PIN(3,1),
};
struct led_resource *get_led_resource(void)
{
return &board_A_led;
}
然后在 chip_demo_gpio. c 中,首先获得 board_A_led. c 实现的 led_resource 结构体,然后再进行其他操作:
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;
}
static int board_demo_led_ctl (int which, char status) /* 控制LED, which-哪个 LED, status:1-亮,0-灭 */
{
//printk("%s %s line %d, led %d, %s\n", __FILE__, __FUNCTION__, __LINE__, which, status ? "on" : "off");
printk("set led %s: group %d, pin %d\n", status ? "on" : "off", GROUP(led_rsc->pin), PIN(led_rsc->pin));
switch(GROUP(led_rsc->pin))
{
case 0:
{
printk("set pin of group 0 ...\n");
break;
}
case 1:
{
printk("set pin of group 1 ...\n");
break;
}
case 2:
{
printk("set pin of group 2 ...\n");
break;
}
case 3:
{
printk("set pin of group 3 ...\n");
break;
}
}
return 0;
}
static struct led_operations board_demo_led_opr = {
.init = board_demo_led_init,
.ctl = board_demo_led_ctl,
};
struct led_operations *get_board_led_opr(void)
{
return &board_demo_led_opr;
}