input子系统源代码跟读1

输入子系统的意义

为驱动定义一个标准的编程格式,对于驱动,我们只需要关注input_register_device这个函数去注册设备,以及input_dev这个结构体去决定我们需要提交的事件type,code,value。
为用户空间获取的数据格式是统一的(input_event的结构体),在app层,只需要判断type,code,从而获取value就可以知道输入设备的状态。
针对输入设备: button, keyboard, mouse, ts, gsensor, joystick

输入子系统整体框架

	应用层
	------------------------------------
	input handler 数据处理层: drivers/input/evdev.c
		1, 和用户进行交互,实现fops
		2, 不知道数据是如何得到,但是知道如何将数据交给用户
	
	
	-------------------------------------
	input core层--drivers/input/input.c
		1,维护了两个链表
		2, 为上下两层提供接口
	
	
	---------------------------------------
	input device层: 输入设备硬件层--自己去写
		自带的input device代码:
			drivers/input/touchscreen/
			
		1, 初始化硬件,获取硬件中数据
		2, 知道得到数据,但是不知道如何将数据给用
		
	-------------------------------------------

使用输入子系统示例

先来看一下,如果我们要是用输入子系统,大概是一个怎么样的框架吧,以鼠标为例。

//初始化阶段
struct input_dev* minput_dev;
minput_dev = input_allocate_device();
minput_dev->name = "sc usb";
set_bit(EV_KEY, minput_dev->evbit);
set_bit(EV_REL, minput_dev->evbit);
set_bit(BTN_LEFT, minput_dev->keybit);
set_bit(BTN_RIGHT, minput_dev->keybit);
set_bit(BTN_MIDDLE, minput_dev->keybit);
set_bit(REL_X, minput_dev->relbit);
set_bit(REL_Y, minput_dev->relbit);
set_bit(REL_WHEEL, minput_dev->relbit);
input_register_device(myusb.minput_dev);
**//上报数据阶段,按下为1,松开为0**
input_report_key(dev, BTN_LEFT,   data[1] & 0x01);
input_report_key(dev, BTN_RIGHT,  data[1] & 0x02);
input_report_key(dev, BTN_MIDDLE, data[1] & 0x04);
input_report_rel(dev, REL_X,     data[2]);
input_report_rel(dev, REL_Y,     data[3]);
input_report_rel(dev, REL_WHEEL, data[5]);
input_sync(dev);
//下面是input_dev 结构体,我只列出了比较有用的。
struct input_dev {
	const char *name;
	unsigned long evbit[BITS_TO_LONGS(EV_CNT)];
	unsigned long keybit[BITS_TO_LONGS(KEY_CNT)];
	unsigned long relbit[BITS_TO_LONGS(REL_CNT)];
	unsigned long absbit[BITS_TO_LONGS(ABS_CNT)];
	struct device dev;
	struct list_head	h_list;
	struct list_head	node;
};
#define EV_SYN			0x00
#define EV_KEY			0x01
#define EV_REL			0x02
#define EV_ABS			0x03
#define EV_MSC			0x04
#define EV_SW			0x05
#define EV_LED			0x11
#define EV_SND			0x12
#define EV_REP			0x14
#define EV_FF			0x15
#define EV_PWR			0x16
#define EV_FF_STATUS		0x17
#define EV_MAX			0x1f
#define EV_CNT			(EV_MAX+1)
//下面代码指,使能哪一个功能,我们这里使能了按键,使能了相对位移
set_bit(EV_KEY, minput_dev->evbit);
set_bit(EV_REL, minput_dev->evbit);
//说明使能哪些按键(鼠标左键、右键、中建),使能哪个方向的相对位移
set_bit(BTN_LEFT, minput_dev->keybit);
set_bit(BTN_RIGHT, minput_dev->keybit);
set_bit(BTN_MIDDLE, minput_dev->keybit);
set_bit(REL_X, minput_dev->relbit);
set_bit(REL_Y, minput_dev->relbit);
set_bit(REL_WHEEL, minput_dev->relbit);
//上报数据函数原型,value对应:按下为1,松开为0,需要我们自己赋值
input_report_key(struct input_dev *dev, unsigned int code, int value)
//下面函数代表一次完整的上报结束
input_sync(dev);

这些就是input的全部代码了,还是比较简单的,接下来我们进行源码分析。

代码跟读—drivers/input/input.c

1.drivers/input/input.c
static int __init input_init(void)
	|
	class_register(&input_class) //注册input class类
	input_proc_init()  //在proc目录下,生成各种文件
		|
		proc_mkdir("bus/input", NULL);
		proc_create("devices", 0, proc_bus_input_dir, &input_devices_fileops);
		proc_create("handlers", 0, proc_bus_input_dir,&input_handlers_fileops); 
	//申请设备号13,生成input_fops,
	register_chrdev(INPUT_MAJOR, "input", &input_fops);  

代码跟读—drivers/input/evdev.c

首先是几个结构体和宏定义需要我们掌握
#define EVDEV_MINOR_BASE 64
#define EVDEV_MINORS 32

static struct input_handler evdev_handler = {
	.event		= evdev_event,
	.connect	= evdev_connect,
	.disconnect	= evdev_disconnect,
	.fops		= &evdev_fops,
	.minor		= EVDEV_MINOR_BASE,          64
	.name		= "evdev",
	.id_table	= evdev_ids,
};

struct evdev {
	int minor;
	struct input_handle handle;
	struct evdev_client __rcu *grab;
	struct list_head client_list;
	struct device dev;
};

struct input_handle {
	void *private;
	int open;
	const char *name;
	struct input_dev *dev;
	struct input_handler *handler;
	struct list_head	d_node;
	struct list_head	h_node;
};
下面分析注册handler
```input_register_handler(&evdev_handler)
	|
	INIT_LIST_HEAD(&handler->h_list);  //初始化handler链表
	//64 = 2,在input_table[2]存放evdev_handler
	if (input_table[handler->minor >> 5]) {
			retval = -EBUSY;
			goto out;
		}
	input_table[handler->minor >> 5] = handler;
	list_add_tail(&handler->node, &input_handler_list); //将node节点放入input_handler_list中
	//在input_dev_list链表中遍历dev节点,将handler和dev进行匹配
	list_for_each_entry(dev, &input_dev_list, node)
	input_attach_handler(dev, handler);
		|
		//如果匹配成功,调用handler中的connect方法
		handler->connect(handler, dev, id);

调用的connect方法:
.connect        = evdev_connect,
evdev_connect(struct input_handler *handler, struct input_dev *dev,const struct input_device_id *id)
	|
	//从0到32,在evdev_table[]中找一个空的数组
	for (minor = 0; minor < EVDEV_MINORS; minor++)
		if (!evdev_table[minor])
			break;
	//初始化client_list
	INIT_LIST_HEAD(&evdev->client_list);			
	//初始化等待队列头
	init_waitqueue_head(&evdev->wait);
	//对evdev进行初始化,生成设备节点,所以我们会看到设备节点 event0 1 2 3
	dev_set_name(&evdev->dev, "event%d", minor);
	evdev->exist = true;
	evdev->minor = minor;
	evdev->handle.dev = input_get_device(dev);
	evdev->handle.name = dev_name(&evdev->dev);
	evdev->handle.handler = handler;
	evdev->handle.private = evdev;
	evdev->dev.devt = MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + minor);
	evdev->dev.class = &input_class;
	evdev->dev.parent = &dev->dev;
	evdev->dev.release = evdev_free;
	device_initialize(&evdev->dev);
	device_add(&evdev->dev)
	//inputdev, input handler, input handle建立双向关系
	input_register_handle(&evdev->handle);
		|
		list_add_tail_rcu(&handle->d_node, &dev->h_list);
		list_add_tail_rcu(&handle->h_node, &handler->h_list);
	//把当前的evdev放入evdev_table[]
	evdev_install_chrdev(evdev);
		|
		evdev_table[evdev->minor] = evdev;



## dev和handler怎么匹配
匹配机制是,全部匹配,因为他的条件是.driver_info = 1,所有dev都满足这个条件,所以全部匹配
static const struct input_device_id evdev_ids[] = {
	{ .driver_info = 1 },	/* Matches all devices */
	{ },			/* Terminating zero entry */
};


## 初始化部分的代码到这里就结束了,下一章是应用和驱动是如何交互
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值