android底层驱动学习之linux输入子系统的理解

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);


至此,input drive就完成了。

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()用于注册一个输入设备。那么注册过程是怎样的呢?这是一个重点,我们在下面的代码中进行注释分析:

[cpp]  view plain   copy
  1. int input_register_device(struct input_dev *dev)  
  2. {  
  3.     /* 用于记录输入设备名称的索引值 */  
  4.     static atomic_t input_no = ATOMIC_INIT(0);  
  5.     /* 输入事件的处理接口指针,用于和设备的事件类型进行匹配 */  
  6.     struct input_handler *handler;  
  7.     const char *path;  
  8.     int error;  
  9.   
  10.     /* 默认所有的输入设备都支持EV_SYN同步事件 */  
  11.     set_bit(EV_SYN, dev->evbit);  
  12.   
  13.     /* 
  14.      * 如果设备驱动没有指定重复按键(连击),系统默认提供以下的支持 
  15.      * 其中init_timer为连击产生的定时器,时间到调用input_repeat_key函数 
  16.      * 上报,REP_DELAY用于设置重复按键的键值,REP_PERIOD设置延时时间 
  17.      */  
  18.     init_timer(&dev->timer);  
  19.     if (!dev->rep[REP_DELAY] && !dev->rep[REP_PERIOD]) {  
  20.         dev->timer.data = (long) dev;  
  21.         dev->timer.function = input_repeat_key;  
  22.         dev->rep[REP_DELAY] = 250;  
  23.         dev->rep[REP_PERIOD] = 33;  
  24.     }  
  25.   
  26.     /* 如果设备驱动没有设置自己的获取键值的函数,系统默认 */  
  27.     if (!dev->getkeycode)  
  28.         dev->getkeycode = input_default_getkeycode;  
  29.   
  30.     /* 如果设备驱动没有指定按键重置函数,系统默认 */  
  31.     if (!dev->setkeycode)  
  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值