1.框架小结
1、入口input_init
:注册类,注册驱动
class_create(&input_class);
register_chrdev(INPUT_MAJOR, "input", &input_fops);
2、打开驱动,将真正的file_operations
引入执行open
,该文件同时储存input_table
struct input_handler *handle = imput_table[minor >> 5] //8bit >> 5 = 3bit(8个索引)
这里此设备号中的低5位用作特殊处理
3、input_register_handler
,初始化input_table
处理函数,添加实际的handler
,加入全局链表input_handler_list
,同时调用connect
建立handler
和dev
连接
4、input_register_device
注册具体的input_dev
,加入到全局链表input_dev_list
,同时调用connect
建立handler
和dev
的连接
5、connect
建立链接关系,这里有一个新的连接结构handler
,包含了handler
和input_dev
,这里具体的新建一个evdev
结构变量,成员变量指向上面创建的dev
和handler
,分配此设备好创建设备。调用input_register_handler
,创建一个管理结构
6、app
读取数据最终会调用到handler
和file
中的read
,阻塞方式如果进入休眠会被中断调用handler
和event
来唤醒
2.有架构驱动与无架构驱动的对比
无架构驱动
1.确定主设备号
2.编写file_oprention结构体编写硬件相关操作
3.构造class结构,自动创建dev设备节点
4.注册设备驱动
5.定义入口和出口
输入子系统架构
input.c完成了主设备的注册,驱动设备注册,在这个框架下需要实现硬件设备驱动的程序即可。
input_device设备驱动
input_handler处理架构
1.向内核申请input_dev结构体
2.设置input_dev的成员
3.注册input_dev驱动设备
4.初始化定时器和中断
5.写中断服务函数
6.写定时器超时函数
7.在出口函数中,释放中断函数,删除定时器,卸载驱动,释放驱动
3.关键函数、结构体解析
input_dev :设备结构
struct input_dev {
const char *name;
const char *phys;
const char *uniq;
struct input_id id;
unsigned long propbit[BITS_TO_LONGS(INPUT_PROP_CNT)];
unsigned long evbit[BITS_TO_LONGS(EV_CNT)]; // 支持哪些事件
/* EN_SYN:同步事件,当使用input_event()函数后就要使用这个上报同步事件
* EN_KEY:键盘事件
* EV_REL:相对坐标事件,eg:鼠标
* EV_ABS:绝对坐标事件,eg:摇杆,触摸屏
* EV_MSC:其他事件,功能
* EV_LED:LED灯事件
* EV_SND:声音事件
* EV_REP:重复键盘按键事件(内部有一个定时器,若有按键事件一直按下/松动,就重复定时,时间一到就上报事件)
* EV_FF: 受力事件
* EV_PWR:电源事件
* EV_FF_STATUB: 受力状态事件
*/
unsigned long keybit[BITS_TO_LONGS(KEY_CNT)]; // 存放支持的按键值
unsigned long relbit[BITS_TO_LONGS(REL_CNT)]; // 存放支持的相对坐标
unsigned long absbit[BITS_TO_LONGS(ABS_CNT)]; // 存放支持的绝对坐标
unsigned long mscbit[BITS_TO_LONGS(MSC_CNT)]; // 存放支持的其他事件,也就是功能
unsigned long ledbit[BITS_TO_LONGS(LED_CNT)]; // 存放支持的各种状态的LED
unsigned long sndbit[BITS_TO_LONGS(SND_CNT)]; // 存放支持的各种声音
unsigned long ffbit[BITS_TO_LONGS(FF_CNT)]; // 存放支持的受力设备
unsigned long swbit[BITS_TO_LONGS(SW_CNT)]; // 存放支持的开关功能
unsigned int hint_events_per_packet;
unsigned int keycodemax;
unsigned int keycodesize;
void *keycode;
int (*setkeycode)(struct input_dev *dev,
const struct input_keymap_entry *ke,
unsigned int *old_keycode);
int (*getkeycode)(struct input_dev *dev,
struct input_keymap_entry *ke);
struct ff_device *ff;
unsigned int repeat_key;
struct timer_list timer;
int rep[REP_CNT];
struct input_mt_slot *mt;
int mtsize;
int slot;
int trkid;
struct input_absinfo *absinfo;
unsigned long key[BITS_TO_LONGS(KEY_CNT)];
unsigned long led[BITS_TO_LONGS(LED_CNT)];
unsigned long snd[BITS_TO_LONGS(SND_CNT)];
unsigned long sw[BITS_TO_LONGS(SW_CNT)];
int (*open)(struct input_dev *dev);
void (*close)(struct input_dev *dev);
int (*flush)(struct input_dev *dev, struct file *file);
int (*event)(struct input_dev *dev, unsigned int type, unsigned int code, int value);
struct input_handle __rcu *grab;
spinlock_t event_lock;
struct mutex mutex;
unsigned int users;
bool going_away;
bool sync;
struct device dev;
struct list_head h_list;
struct list_head node;
};
input_allocate_device:向内核申请一个input_dev设备,然后返回这个设备
struct input_dev *input_allocate_device(void)
input_free_device:释放这个结构体,一般在驱动出口函数
void input_free_device(struct input_dev *dev)
EXPORT_SYMBOL(input_free_device);
input_unregister_device:卸载/sys/class/input目录下的input_dev这类设备,一般在驱动的出口处写
void input_unregister_device(struct input_dev *dev)
EXPORT_SYMBOL(input_unregister_device); //标签内定义的函数或者符号对全部内核代码公开
set_bit:用来设置为变量,这里用来设置支持的事件类型
static inline void set_bit(int nr, volatile unsigned long *addr)
eg: set_bit(KEY_L, buttons_dev->keybit);
input_event:事件上报
void input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
//dev:要上报那个input驱动设备事件
//type:要上报的事件类型:eg:按键填EV_KEY
//code:对应事件里支持那个变量,eg:如按下按键L,则填入KEY_L
//value:对应变量里的数值,eg:松开按键填入0,按下按键填入1
//注意上报完事件之后需要调用input_sync来同步事件
input_sync:同时事件,其实上报事件并未把事件上报给内核,而是存储在某个地方,由intput_sync来实现上报
static inline void input_sync(struct input_dev *dev)
{
input_event(dev, EV_SYN, SYN_REPORT, 0);
}
4.源码解析
struct pin_desc{
int irq;
char *name;
unsigned int pin;
unsigned int key_val;
};
struct pin_desc pins_desc[4] = {
{IRQ_EINT0, "S2", S3C2410_GPF0, KEY_L},
{IRQ_EINT2, "S3", S3C2410_GPF2, KEY_S},
{IRQ_EINT11, "S4", S3C2410_GPG3, KEY_ENTER},
{IRQ_EINT19, "S5", S3C2410_GPG11, KEY_LEFTSHIFT},
};
static struct input_dev *buttons_dev; //硬件设备
static struct pin_desc *irq_pd;
static struct timer_list buttons_timer;
static irqreturn_t buttons_irq(int irq, void *dev_id)
{
/* 10ms后启动定时器 */
irq_pd = (struct pin_desc *)dev_id;
mod_timer(&buttons_timer, jiffies+HZ/100);
return IRQ_RETVAL(IRQ_HANDLED);
}
static void buttons_timer_function(unsigned long data)
{
struct pin_desc * pindesc = irq_pd;
unsigned int pinval;
if (!pindesc)
return;
pinval = s3c2410_gpio_getpin(pindesc->pin);
if (pinval)
{
/* 松开 : 最后一个参数: 0-松开, 1-按下 */
input_event(buttons_dev, EV_KEY, pindesc->key_val, 0);
input_sync(buttons_dev);
}
else
{
/* 按下 */
input_event(buttons_dev, EV_KEY, pindesc->key_val, 1);
input_sync(buttons_dev);
}
}
static int buttons_init(void)
{
int i;
/* 1. 分配一个input_dev结构体 */
buttons_dev = input_allocate_device();
/* 2. 设置 */
/* 2.1 能产生哪类事件 */
set_bit(EV_KEY, buttons_dev->evbit);
set_bit(EV_REP, buttons_dev->evbit);
/* 2.2 能产生这类操作里的哪些事件: L,S,ENTER,LEFTSHIT */
set_bit(KEY_L, buttons_dev->keybit);
set_bit(KEY_S, buttons_dev->keybit);
set_bit(KEY_ENTER, buttons_dev->keybit);
set_bit(KEY_LEFTSHIFT, buttons_dev->keybit);
/* 3. 注册 */
input_register_device(buttons_dev);
/* 4. 硬件相关的操作 */
init_timer(&buttons_timer);
buttons_timer.function = buttons_timer_function;
add_timer(&buttons_timer);
// 注册中断
for (i = 0; i < 4; i++)
{
request_irq(pins_desc[i].irq, buttons_irq, IRQT_BOTHEDGE, pins_desc[i].name, &pins_desc[i]);
}
return 0;
}
static void buttons_exit(void)
{
int i;
for (i = 0; i < 4; i++)
{
free_irq(pins_desc[i].irq, &pins_desc[i]);
}
del_timer(&buttons_timer);
input_unregister_device(buttons_dev);
input_free_device(buttons_dev);
}
module_init(buttons_init);
module_exit(buttons_exit);
MODULE_LICENSE("GPL");