ARM Linux内核Input输入子系统浅解(3)

2020-05-05 15:57

if (id->flags & INPUT_DEVICE_ID_MATCH_PRODUCT) if (id->product != dev->id.product) continue;

if (id->flags & INPUT_DEVICE_ID_MATCH_VERSION) if (id->version != dev->id.version) continue;

MATCH_BIT(evbit, EV_MAX); //匹配id相关标志位 MATCH_BIT(keybit, KEY_MAX); MATCH_BIT(relbit, REL_MAX); MATCH_BIT(absbit, ABS_MAX); MATCH_BIT(mscbit, MSC_MAX); MATCH_BIT(ledbit, LED_MAX); MATCH_BIT(sndbit, SND_MAX); MATCH_BIT(ffbit, FF_MAX); MATCH_BIT(swbit, SW_MAX);

return id; }

return NULL; }

该函数用于匹配input_dev结构体和input_handler结构体里面定义的

input_device_id,若两者里面有任何相关变量不一样则匹配失败(条件真苛刻)。

再看handle = handler->connect(handler, dev, id),connect函数即为static struct input_handle *evdev_connect(struct input_handler *handler, struct input_dev *dev, struct input_device_id *id),为什么呢会是这个呢,我们先看evdev.c中的input_handler结构体定义: static struct input_handler evdev_handler = { .event = evdev_event,

.connect = evdev_connect,

.disconnect = evdev_disconnect, .fops = &evdev_fops,

.minor = EVDEV_MINOR_BASE, .name = \ .id_table = evdev_ids, };

可只这里input_handler结构体里边的connect函数即为evdev_connect函数

static struct input_handle *evdev_connect(struct input_handler *handler, struct input_dev *dev, struct input_device_id *id)

{

1 struct evdev *evdev; //定义一个evdev结构体指针 struct class_device *cdev; int minor;

2 for (minor = 0; minor < EVDEV_MINORS && evdev_table[minor]; minor++); if (minor == EVDEV_MINORS) {

printk(KERN_ERR \devices\\n\ return NULL; }

3 if (!(evdev = kzalloc(sizeof(struct evdev), GFP_KERNEL))) return NULL;

INIT_LIST_HEAD(&evdev->list);

init_waitqueue_head(&evdev->wait);

evdev->exist = 1;

evdev->minor = minor; evdev->handle.dev = dev;

evdev->handle.name = evdev->name; evdev->handle.handler = handler; evdev->handle.private = evdev;

sprintf(evdev->name, \

evdev_table[minor] = evdev;

cdev = class_device_create(&input_class, &dev->cdev,

MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + minor), dev->cdev.dev, evdev->name);

/* temporary symlink to keep userspace happy */

sysfs_create_link(&input_class.subsys.kset.kobj, &cdev->kobj, evdev->name);

return &evdev->handle; }

先看1处,这里有个定义在evdev.c里边的新面孔 struct evdev { int exist; int open; int minor;

char name[16];

struct input_handle handle; //关联input_handler和input_dev的input_handle

wait_queue_head_t wait; struct evdev_list *grab; struct list_head list; };

evdev这个结构体就是拿来应用开发操作的,在这里就是触摸屏对应的设备文件实体,结构体前边定义了记录设备的一些信息(设备号,打开状态、设备名字等),这里还定义了一个input_handle的实体handle,没错这个handle就是要用来关联input_dev和input_handler的,后面还有一行加粗的部分后面再做介绍。 再看2处,evdev_table[]是一个全局变量的数组,在evdev.c中有定义 #define EVDEV_MINORS 32

static struct evdev *evdev_table[EVDEV_MINORS];

在前面已经说明了,一个device可以对应多个handler,而一个handler也可处理多个device,这里体现出了后者。既然evdev这个结构体是对应的设备文件实体,因为这个handler可能会处理多个device,因此该handler要处理n个device就会应该有n个evdev实体,而这些实体的地址存放在evdev_table[]这个指针数组中,也就是说该handler最多只能处理EVDEV_MINORS个device,而2处的这几句代码就是要遍历evdev_table[]这个数组看还有没有空着的位置,有的话才会继续进行下面的程序。

再看3处,开辟一个evdev结构体的内存空间,前面有说明过kzalloc函数,这里不再说明。

后面的代码就是为evdev结构体变量赋初始值了,其中

init_waitqueue_head(&evdev->wait)初始化等待队列,具体介绍结合/linux/wait.h和查看相关资料(本人不懂)。

函数最后得到evdev结构体内的hanlde地址并返回,此时返回到我们的int input_register_device(struct input_dev *dev)函数里面,最后一句 input_link_handle(handle),进入到该函数中发现

static void input_link_handle(struct input_handle *handle) {

list_add_tail(&handle->d_node, &handle->dev->h_list); list_add_tail(&handle->h_node, &handle->handler->h_list); }

在该函数中也只是将handle中的d_node和h_node分别接入到input_dev和input_handler的h_list中,此时input_dev、input_handler、input_handle三者形成了如图2所示的关系。

至此设备注册过程算是全部完成了,但是貌似还有点乱。在整个设备的注册过程中函数的嵌套一个接着一个,不仅函数嵌套,结构体也使用了结构体和函数嵌套等,在各个函数内也用了大量的结构体指针等等。但是在整个过程中

input_dev、input_handler、input_handle这三个结构体变量的实体也都只有一个。其中input_dev结构体实体在xxx_ts.c中直接定义了一个input_dev的指针全局变量:

struct input_dev *tsdev;

并在初始化函数中开辟了一个input_dev的内存空间并让tsdev指针指向它:

w55fa95_dev = input_allocate_device();

input_handler结构体在evdev.c中也直接被定义了并初始化了 static struct input_handler evdev_handler = { .event = evdev_event,

.connect = evdev_connect,

.disconnect = evdev_disconnect, .fops = &evdev_fops,

.minor = EVDEV_MINOR_BASE, .name = \ .id_table = evdev_ids, };

而关联input_dev和input_handler的input_handle则是在调用链接连接函数static struct input_handle *evdev_connect(struct input_handler *handler, struct input_dev *dev, struct input_device_id *id)的时候,在该函数的内部调用evdev = kzalloc(sizeof(struct evdev), GFP_KERNEL)开辟了一个evdev结构体的内存空间时创建了,input_handle就是使用了evdev结构体内部定义的input_handle。

一个完整input设备系统不仅要有设备,还需要有处理程序

input_handler,而上文中主要介绍的是设备注册、生成、以及和handler搭配的一个过程,而handler在何时生成的?

第三章、input_handler的注册。

Input_handler是要和用户层打交道的,在evdev.c中直接定义了一个input_handler结构体并初始化了一些内部成员变量。 static struct input_handler evdev_handler = { .event = evdev_event,

.connect = evdev_connect,

.disconnect = evdev_disconnect,

.fops = &evdev_fops, //用户对设备操作的函数指针 .minor = EVDEV_MINOR_BASE, .name = \

.id_table = evdev_ids, //指向一个evedev的指针数组 };

先看第一行加粗的代码,evedev_fops结构体的定义如下 static struct file_operations evdev_fops = { .owner = THIS_MODULE, .read = evdev_read, .write = evdev_write, .poll = evdev_poll, .open = evdev_open, .release = evdev_release, .unlocked_ioctl = evdev_ioctl,

#ifdef CONFIG_COMPAT

.compat_ioctl = evdev_ioctl_compat, #endif

.fasync = evdev_fasync, .flush = evdev_flush };

相信做过linux设备驱动编程的对这都很熟悉了,就是一大堆的用户接口函数,包括对设备的open、close、read、write、ioctl等函数。

再看第二行代码加粗的部分.id_table = evdev_ids, id.table就是前面所说过要和input_dev的id匹配的这么一个结构体,这里让它初始化为evdev_ids,在看evdev_ids的定义:

static struct input_device_id evdev_ids[] = {

{ .driver_info = 1 }, /* Matches all devices */ { }, /* Terminating zero entry */ };

MODULE_DEVICE_TABLE(input, evdev_ids);

这里是一个结构体数组,令数组中第一个结构体的该成员变量driver_info的值为1,其他成员变量均未定义,说明这个handler对所有device的id都能匹配得上。数组中的第二个结构体为空表示结束,用来标识结束配合下面的MODULE_DEVICE_TABLE(input, evdev_ids)使用,关于

MODULE_DEVICE_TABLE宏定义介绍自行查看相关文献(我也不懂)。

接下来进入正题,input_handler的注册!

Input_handler的注册和input_dev的注册很相似,大同小异罢了,在evdev.c源码中显示定义并初始化了一个input_handler结构体并直接给相关的成员变量赋值了,就是本章开始所将的部分,然后再初始化函数中注册一个input_handler:

static int __init evdev_init(void) {

input_register_handler(&evdev_handler); return 0; }

这里只调用了一个input_register_handler()函数,看起来应该是很简单的样子(相比input_dev的注册),继续跟踪进入到该函数中:

void input_register_handler(struct input_handler *handler) {

struct input_dev *dev;

struct input_handle *handle; struct input_device_id *id;

if (!handler) return;

INIT_LIST_HEAD(&handler->h_list);


ARM Linux内核Input输入子系统浅解(3).doc 将本文的Word文档下载到电脑 下载失败或者文档不完整,请联系客服人员解决!

下一篇:行政村(居)基本情况进行调查摸底表

相关阅读
本类排行
× 注册会员免费下载(下载后可以自由复制和排版)

马上注册会员

注:下载文档有可能“只有目录或者内容不全”等情况,请下载之前注意辨别,如果您已付费且无法下载或内容有问题,请联系我们协助你处理。
微信: QQ: