您的位置:首页 > 运维架构 > 网站架构

输入子系统架构

2013-09-28 17:10 148 查看
输入子系统有三层组成:核心层、事件处理层、设备层。其中后两者实现向核心层注册。

核心层:

input_init(void)

err = class_register(&input_class);

register_chrdev(INPUT_MAJOR, "input", &input_fops);

当我们打开设备文件的时候那么就会调用input_fops操作函数:

input_open_file

handler = input_table[iminor(inode) >> 5]; //获取事件处理操作函数集

new_fops = fops_get(handler->fops);

file->f_op = new_fops; //对设备文件的读写操作,核心层把该功能交给了对应的事件处理层的操作函数集

err = new_fops->open(inode, file);

注意:设备层对应于我们的硬件设备,事件处理层对应我们的设备处理程序,只有这两者一一绑定了才有设备文件产生,也才有上面的打开操作,这样就保证了三层共在,设备文件的产生见下面。

事件处理层:

通过核心层提供的函数来注册:

input_register_handler //注册事件处理

input_table[handler->minor >> 5] = handler; //把设置好的事件处理结构体放到数组

list_add_tail(&handler->node, &input_handler_list); //把事件处理结构体放到事件处理链表

list_for_each_entry(dev, &input_dev_list) //事件处理层扫描设备层链表,寻找是否有匹配的,如果有调用下面函数

input_attach_handler(dev, handler);

id = input_match_device(handler, dev); //判断是否匹配

error = handler->connect(handler, dev, id); //如果匹配进行绑定,通过evdev->handle结构体把处理层和设备层拌在一起,并且产生设备文件,最后把绑定好的handle向上注册input_register_handle(&evdev->handle);

evdev->dev.devt = MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + minor); //设备节点

error = input_register_handle(&evdev->handle); //注册handle

list_add_tail_rcu(&handle->d_node, &dev->h_list);

1、事件处理层首先要实现对某些设备操作的函数集,因为核心层会间接把这些功能较到事件处理层来实现;

2、要实现和设备层进行绑定,绑定成功后产生设备文件,并且应该在注册的时候就要寻找对应的设备进行绑定。

3、设备层在注册的时候也需要和事件处理层进行绑定,所以无论是设备层还是处理层一注册都需要放到各自对应的链表,具体如下。

4、这里的绑定函数是在处理层实现的,调用地方就是设备注册如果和对应的处理层绑定成功或者处理层注册时候和设备层绑定成功时候调用。

设备层:

通过核心层的input_register_device向上注册。

input_register_device

list_add_tail(&dev->node, &input_dev_list); //放到设备层链表

list_for_each_entry(handler, &input_handler_list, node)

input_attach_handler(dev, handler); //匹配处理层链表的元素看看是否有合适,能绑定的 ,可以的话调用该函数,这个函数和上面的一样。

所以如果设备层和处理层有绑定成的,那么就会产生设备文件,并且注册一个handle,这个handle绑定了匹配成功的设备层和处理层。

现在就剩下一个问题:处理层如何知道自己的功能可以用在设备层上?

其实输入子系统就是设备从上报事件,处理层处理事件,所以处理层负责实现处理事件,而设备层负责告诉处理层自己支持上报哪些事件,这样就可以知道处理层是不是知道自己能否驱动设备的事件了。所以处理层要提供“自己支持什么事件的处理”,也就是id_table成员:

struct input_device_id {

kernel_ulong_t flags;

__u16 bustype;

__u16 vendor;

__u16 product;

__u16 version;

kernel_ulong_t evbit[INPUT_DEVICE_ID_EV_MAX / BITS_PER_LONG + 1];

kernel_ulong_t keybit[INPUT_DEVICE_ID_KEY_MAX / BITS_PER_LONG + 1];

kernel_ulong_t relbit[INPUT_DEVICE_ID_REL_MAX / BITS_PER_LONG + 1];

kernel_ulong_t absbit[INPUT_DEVICE_ID_ABS_MAX / BITS_PER_LONG + 1];

kernel_ulong_t mscbit[INPUT_DEVICE_ID_MSC_MAX / BITS_PER_LONG + 1];

kernel_ulong_t ledbit[INPUT_DEVICE_ID_LED_MAX / BITS_PER_LONG + 1];

kernel_ulong_t sndbit[INPUT_DEVICE_ID_SND_MAX / BITS_PER_LONG + 1];

kernel_ulong_t ffbit[INPUT_DEVICE_ID_FF_MAX / BITS_PER_LONG + 1];

kernel_ulong_t swbit[INPUT_DEVICE_ID_SW_MAX / BITS_PER_LONG + 1];

kernel_ulong_t driver_info;

};

所以处理层负责实现支持处理哪些设备事件?负责实现匹配函数和绑定函数,这都是在处理层实现。

而设备层也需要设置自己上报的是哪些事件,这样就可以了。

我们可以知道;

输入子系统设备文件读写操作:核心层的open函数--->核心层转交给处理层---->处理层的读写操作;

处理层和设备层的绑定:

1、注册处理层:设置处理层结构体--->把处理层结构体放到处理层链表---->扫描设备层链表---->通过调用处理层的匹配函数来匹配设备层和处理层--->如果匹配,那么调用处理层的绑定函数来绑定两者--->产生设备文件,绑定所用结构体client->handle,client放到文件节点结果体的私有数据,以便读写时候获得client->handle结构体。

2、注册设备层:设置设备层结构体--->把设备层结构体放到处理层链表---->扫描处理层结构体链表---->通过调用处理层的匹配函数来匹配设备层和处理层--->如果匹配,那么调用处理层的绑定函数来绑定两者--->产生设备文件,绑定所用结构体client->handle,client放到文件节点结果体的私有数据,以便读写时候获得client->handle结构体。

读设备文件:如果没有事件可以读,那么就阻塞,等待上报事件发生--->上报事件是通过设备来产生的input_event,实质上也就是通过hande找到该设备对应处理层结构体hangdler,然后带调用处理层的event函数,填充俩面的结构体--->读阻塞停止,读操作返回。

对于驱动编写者主要就是负责事件处理层和设备层,其中猪猪要就是设备层,而实现了的处理层一般可以我们直接使用了。

设备层编很简单:1、设置设备支持哪些事件、2、向核心层注册设备、3、实现上报事件。

支持哪些设备?

1. #define EV_SYN 0x00 /*表示同步事件*/

2. #define EV_KEY 0x01 /*键盘或者按键,表示一个键码*/

3. #define EV_REL 0x02 /*鼠标设备,表示一个相对的光标位置结果*/

4. #define EV_ABS 0x03 /*手写板产生的值,其是一个绝对整数值*/

5. #define EV_MSC 0x04 /*其他类型*/

6. #define EV_LED 0x11 /*LED灯设备*/

7. #define EV_SND 0x12 /*蜂鸣器,输入声音*/

8. #define EV_REP 0x14 /*允许重复按键类型*/

9. #define EV_PWR 0x16 /*电源管理事件*/

向上层注册设备:

int input_register_device(struct input_dev *dev)

上报事件:( 在设备某种情况下上报,例如触摸上报事件就是在触摸情况下上报)

void input_report_key(struct input_dev *dev, unsigned int code, int value); //上报按键事件

void input_report_rel(struct input_dev *dev, unsigned int code, int value); //上报相对坐标事件

void input_report_abs(struct input_dev *dev, unsigned int code, int value); //上报绝对坐标事件
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: