1 LED 驱动回顾
对于 LED, APP 调用 open 函数导致驱动程序的 led_open 函数被调用。在里面,把 GPIO 配置为输出引脚。安装驱动程序后并不意味着会使用对应的硬件,而 APP 要使用对应的硬件,必须先调用 open 函数。所以建议在驱动程序的open 函数中去设置引脚。
APP 继续调用 write 函数传入数值,在驱动程序的 led_write 函数根据该数值去设置 GPIO 的数据寄存器,从而控制 GPIO 的输出电平。怎么操作寄存器?从芯片手册得到对应寄存器的物理地址,在驱动程序中使用 ioremap 函数映射得到虚拟地址。驱动程序中使用虚拟地址去访问寄存器。
2 按键驱动编写思路
GPIO 按键的原理图一般有如下 2 种:
按键没被按下时,上图中左边的 GPIO 电平为高,右边的 GPIO 电平为低。
按键被按下后,上图中左边的 GPIO 电平为低,右边的 GPIO 电平为高。
回顾一下编写驱动程序的套路
对于使用查询方式的按键驱动程序,我们只需要实现 button_open、button_read
3 编程:先写框架
我们的目的写出一个容易扩展到各种芯片、各种板子的按键驱动程序,所以驱动程序分为上下两层:
① button_drv.c 分配/设置/注册 file_operations 结构体
起承上启下的作用,向上提供 button_open,button_read 供 APP 调用。
而这 2 个函数又会调用底层硬件提供的 p_button_opr 中的 init、 read函数操作硬件。
② board_xxx.c 分配/设置/注册 button_operations 结构体
这个结构体是我们自己抽象出来的,里面定义单板 xxx 的按键操作函数。这样的结构易于扩展,对于不同的单板,只需要替换 board_xxx.c 提供自己的 button_operations 结构体即可。
3.1 把按键的操作抽象出一个 button_operations 结构体
首先看看 button_drv.h,它定义了一个 button_operations 结构体,把按键的操作抽象为这个结构体
#ifndef BUTTON_DRV_H_
#define BUTTON_DRV_H_
struct button_operations {
int count;
void (*init) (int which);
int (*read) (int which);
};
void register_button_operations(struct button_operations* operaions);
void unregister_button_operations(void);
#endif
再看看 board_xxx.c,它实现了一个 button_operations 结构体,代码如下。
调用 register_button_operations 函数,把这个结构体注册到上层驱动中
// ...
// 定义button_operations结构体
static struct button_operations my_button_operations = {
.count = 2,
.init = board_xxx_button_init_gpio,
.read &#