1.什么叫输入子系统?
内核的输入子系统是对分散的,多种不同类别的输入设备(如键盘,鼠标,跟踪球,操纵杆,触摸屏,加速计和手写板)等字符设备进行统一处理的一层抽象,就是在字符设备驱动上抽象出的一层。输入子系统包括两类驱动程序:事件驱动程序和设备驱动程序。事件驱动程序负责和应用程序的接口,而设备驱动程序负责和底层输入设备的通信。鼠标事件生成文件mousedev属于事件驱动程序,而PS/2鼠标驱动程序是设备驱动程序。事件驱动程序是标准的,对所有的输入类都是可用的,所以要实现的是设备驱动程序而不是事件驱动程序。设备驱动程序可以利用一个已经存在的,合适的事件驱动程序通过输入核心和用户应用程序接口。
2.输入子系统的架构是怎么样的,分为几层,是怎么实现的?
输入子系统由驱动层、系统核心层(input core)、事件处理层(event handler)三部分组成,
一个输入事件(如点击触屏)通过input driver->input core->event handler->user space 到达用户空间传递给应用程序
在这里input core是核心,linux系统提供的内核接口,作为底层驱动的开发者来说,只需编辑input driver与硬件直接打交道的这一层。那event handler事件处理层是谁来做呢,还没弄懂。---以后要弄懂
3.那首先来看input driver层,我以触屏的来分析:
注册过程:
a.首先通过input_allocate_device来峙湟桓鰅nput_dev接口,并初始化一些基本的成员
b.然后在《》里面初始化一些参数。
c.最后通过input_register_device来注册注册一个input设备
static int fts_ts_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
input_dev = input_allocate_device();//分配一个input_dev接口,并初始化一些基本的成员
.......
》 input_dev->name = "fts_ts";
input_dev->id.bustype = BUS_I2C;//总线类型是I2C
input_dev->dev.parent = &client->dev;//父设备
input_set_drvdata(input_dev, data);//保存data结构到錳nput_dev里面
i2c_set_clientdata(client, data);
__set_bit(EV_KEY, input_dev->evbit);//按键事件,每次触摸都有一个BTN_TOUCH的按键事件
__set_bit(EV_ABS, input_dev->evbit); //绝对坐标事件,触摸屏每次发送的坐标都是绝对坐标,不同于鼠标的相对坐标
__set_bit(BTN_TOUCH, input_dev->keybit);//touch类型按键
__set_bit(INPUT_PROP_DIRECT, input_dev->propbit);
input_mt_init_slots(input_dev, pdata->num_max_touches,0);
input_set_abs_params(input_dev, ABS_MT_POSITION_X, pdata->x_min, pdata->x_max, 0, 0);//这个是设置ad转换的x坐标
》 input_set_abs_params(input_dev, ABS_MT_POSITION_Y, pdata->y_min, pdata->y_max, 0, 0);//这个是设置ad转换的y坐标
...........
err = input_register_device(input_dev);//注册一个input设备
.......
}
static struct i2c_driver fts_ts_driver = {
.probe = fts_ts_probe,
.remove = fts_ts_remove,
.driver = {
.name = "fts_ts",
.owner = THIS_MODULE,
.of_match_table = fts_match_table,
#ifdef CONFIG_PM
.pm = &fts_ts_pm_ops,
#endif
},
.id_table = fts_ts_id,
};
/*******************************************************************************
* Name: fts_ts_init
* Brief:
* Input:
* Output:
* Return:
*******************************************************************************/
static int __init fts_ts_init(void)
{
printk(" ### %s\n",__func__);
return i2c_add_driver(&fts_ts_driver);
}
/*******************************************************************************
* Name: fts_ts_exit
* Brief:
* Input:
* Output:
* Return:
*******************************************************************************/
static void __exit fts_ts_exit(void)
{
printk("%s\n",__func__);
i2c_del_driver(&fts_ts_driver);
}
module_init(fts_ts_init);
module_exit(fts_ts_exit);
4.那下面来看下上述两个重要的函数:input_allocate_device()和input_register_device()
a.input_allocate_device()
这个函数也就是做一些内存分配和一些基本的初始化
struct input_dev *input_allocate_device(void)
{
struct input_dev *dev;
dev = kzalloc(sizeof(struct input_dev), GFP_KERNEL);//分配一个 input_dev 结构体,并初始化为 0
if (dev) {
dev->dev.type = &input_dev_type;/*初始化设备的类型*/
dev->dev.class = &input_class;/*设置为输入设备类*/
device_initialize(&dev->dev);/*初始化 device 结构*/
mutex_init(&dev->mutex);/*初始化互斥锁*/
spin_lock_init(&dev->event_lock);/*初始化事件自旋锁*/
INIT_LIST_HEAD(&dev->h_list);/*初始化链表*/
INIT_LIST_HEAD(&dev->node);/*初始化链表*/
__module_get(THIS_MODULE);/*模块引用技术加 1*/
}
return dev;
}
b.
input_register_device()
input_register_device()用于注册一个输入设备。那么注册过程是怎样的呢?这是一个重点,我们在下面的代码中进行注释分析:
- int input_register_device(struct input_dev *dev)
- {
- /* 用于记录输入设备名称的索引值 */
- static atomic_t input_no = ATOMIC_INIT(0);
- /* 输入事件的处理接口指针,用于和设备的事件类型进行匹配 */
- struct input_handler *handler;
- const char *path;
- int error;
- /* 默认所有的输入设备都支持EV_SYN同步事件 */
- set_bit(EV_SYN, dev->evbit);
- /*
- * 如果设备驱动没有指定重复按键(连击),系统默认提供以下的支持
- * 其中init_timer为连击产生的定时器,时间到调用input_repeat_key函数
- * 上报,REP_DELAY用于设置重复按键的键值,REP_PERIOD设置延时时间
- */
- init_timer(&dev->timer);
- if (!dev->rep[REP_DELAY] && !dev->rep[REP_PERIOD]) {
- dev->timer.data = (long) dev;
- dev->timer.function = input_repeat_key;
- dev->rep[REP_DELAY] = 250;
- dev->rep[REP_PERIOD] = 33;
- }
- /* 如果设备驱动没有设置自己的获取键值的函数,系统默认 */
- if (!dev->getkeycode)
- dev->getkeycode = input_default_getkeycode;
- /* 如果设备驱动没有指定按键重置函数,系统默认 */
- if (!dev->setkeycode)