[转]linux 输入设备驱动程序 事件驱动层 分析

Input subsystem系统实现分析

Edwin Rong   edwinrong@mxic.com.cn

本文将简要介绍Input system系统,通过鼠标驱动实现过程具体介绍Input System系统的实现。

Input subsystem 系统架构

 

Input subsystemDriversInput CoreHandlers三个组件构成。Drivers负责硬件和Input Core之间的操作,Handlers负责应用程序同Input Core之间的通信。Input Core 实现硬件设备的注册以及抽象设备集的注册。

硬件向应用程序反馈信息的路径为: Drivers à Input Core à Handlers à Applications

http://bbs.ednchina.com/BLOG_ARTICLE_255205.HTM

 

涉及文件

Drivers/input/input.c

Include/linux/input.h

Drivers/input/mousedev.c

Drivers/input/mouse/amimouse.c

主要数据结构

Struct input_dev  (Include/linux/input.h)

驱动层具体输入设备的描述结构,在具体硬件设备的驱动模块中定义及初始化。

如:drivers/input/mouse/amimouse.c 

static struct input_dev *amimouse_dev;  amimouse_dev amimouse_init()中初始化。

Struct input_handler

逻辑设备指的是同一类设备的抽象,如鼠标、操纵杆、键盘等。逻辑设备结构体在drivers/input/mousedev.c中定义及初始化。

在内核中,input_dev 表示一个 input设备;input_handler 来表示input设备的 interface

Struct input_handle

用来创建驱动层Dev和Handler链表的链表项结构。

系统实现

Input Subsystem系统主要由(drivers/input/input.c) input_register_device()input_register_handler()两个函数实现。Handler组件通过input_register_handler函数将逻辑设备操作结构体注册到input_handler_list链表中;drivers组件通过input_register_device组件将直接对具体硬件的操作结构体注册到input_dev_list链表中。系统可以注册8个逻辑设备结构体和256个具体硬件设备结构体。

下面结合鼠标驱动具体介绍下这两个函数。

Drivers/input/mouse/amimouse.c amimouse_init()函数首先初始化amimouse_dev硬件设备结构体,然后调用input_register_device(amimouse_dev) 函数将amimouse硬件设备注册到input_dev_list链表中。

int input_register_device(struct input_dev *dev)

{

static atomic_t input_no = ATOMIC_INIT(0);

struct input_handle *handle;

struct input_handler *handler;

struct input_device_id *id;

const char *path;

int error;

if (!dev->dynalloc) {

printk(KERN_WARNING "input: device %s is statically allocated, will not register\n"

"Please convert to input_allocate_device() or contact dtor_core@ameritech.net\n",

dev->name ? dev->name : "<Unknown>");

return -EINVAL;

}

set_bit(EV_SYN, dev->evbit);

/*

 * If delay and period are pre-set by the driver, then autorepeating

 * is handled by the driver itself and we don't do it in input.c.

 */

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;

}

INIT_LIST_HEAD(&dev->h_list);       //初始化操作函数

list_add_tail(&dev->node, &input_dev_list); //将硬件设备结构体添加到input_dev_list

//表的结尾处。

dev->cdev.class = &input_class;

snprintf(dev->cdev.class_id, sizeof(dev->cdev.class_id),

 "input%ld", (unsigned long) atomic_inc_return(&input_no) - 1);

error = class_device_add(&dev->cdev);

if (error)

return error;

error = sysfs_create_group(&dev->cdev.kobj, &input_dev_attr_group);

if (error)

goto fail1;

error = sysfs_create_group(&dev->cdev.kobj, &input_dev_id_attr_group);

if (error)

goto fail2;

error = sysfs_create_group(&dev->cdev.kobj, &input_dev_caps_attr_group);

if (error)

goto fail3;

__module_get(THIS_MODULE);

path = kobject_get_path(&dev->cdev.kobj, GFP_KERNEL);

printk(KERN_INFO "input: %s as %s\n",

dev->name ? dev->name : "Unspecified device", path ? path : "N/A");

kfree(path);

list_for_each_entry(handler, &input_handler_list, node)

//通过dev(这里指的是amimouse_dev)结构体的node成员,匹配input_handler_list//相应的处理函数。

if (!handler->blacklist || !input_match_device(handler->blacklist, dev))

if ((id = input_match_device(handler->id_table, dev)))    //设备匹配,返回id

if ((handle = handler->connect(handler, dev, id))) {

input_link_handle(handle);  //建立设备和处理函数之间的连接

if (handler->start)

handler->start(handle);

}

input_wakeup_procfs_readers();

return 0;

 fail3: sysfs_remove_group(&dev->cdev.kobj, &input_dev_id_attr_group);

 fail2: sysfs_remove_group(&dev->cdev.kobj, &input_dev_attr_group);

 fail1: class_device_del(&dev->cdev);

return error;

}

Drivers/input/mousedev.c mousedev_init()函数调用

input_register_handler(&mousedev_handler) 函数将mousedev_handler鼠标类设备处理函数结构体注册到input_handler_list链表中。

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); //初始化处理函数链表

if (handler->fops != NULL)

input_table[handler->minor >> 5] = handler; 

list_add_tail(&handler->node, &input_handler_list); //将处理函数结构体添加到

//input_handler_list链表中

list_for_each_entry(dev, &input_dev_list, node)

if (!handler->blacklist || !input_match_device(handler->blacklist, dev))

if ((id = input_match_device(handler->id_table, dev)))

if ((handle = handler->connect(handler, dev, id))) {

input_link_handle(handle);

if (handler->start)

handler->start(handle);

}

input_wakeup_procfs_readers();

}

每个input_dev 和 input_handler 是要关联上才能工作的,在注册 input_dev 或者 input_handler的时候,都会遍历上面的列表,找到相匹配的,然后调用 input_handler 的 connect函数来将它们联系到一起。通常在input_handler 的 connect函数中,就会创建 input_handle, input_handle就是负责将 input_dev 和 input_handler 联系在一起的,如图所示:

这里需要额外说明一下的是: input_dev 中的 h_node 是 input_handle 链表的list节点,也就是说,一个input_dev,可以对应多个 input_handle.

当设备产生 input event 的时候,例如按下了一个键,驱动就会调用 input_handler 中的 event 函数,同时,如果input_dev 支持的话,也会调用 input_dev 的 event 函数。这样,设备产生的事件就会被驱动记录下来。当用户层的程序需要获知这些事件的时候,会调用 input_handler中的 struct file_operations *fops 中的相应函数,例如 read 等等。

设备文件的操作函数

Open()函数

输入设备子系统通过register_chrdev(INPUT_MAJOR, "input", &input_fops)注册到系统中,文件操作结构体input_fops包括了对open()函数的初始化。

static struct file_operations input_fops = {

.owner = THIS_MODULE,

.open = input_open_file,

};

应用程序打开设备文件的时候,首先要执行input_open_file()函数。我们来看一下input_open_file()函数作了些什么。

static int input_open_file(struct inode *inode, struct file *file)

{

struct input_handler *handler = input_table[iminor(inode) >> 5]; //根据次设备号在input_table[]数组中查询相对应的处理函数。Input_table[]input_register_handler()函数中初始化。

const struct file_operations *old_fops, *new_fops = NULL;

int err;

/* No load-on-demand here? */

if (!handler || !(new_fops = fops_get(handler->fops))) //获取handler结构体中的文件处理成//fops。对于鼠标类设备来讲,这里获得的就是drivers/input/mousedev.c文件中 //mousedev_handler结构体中的鼠标操作函数结构体。

New_fops=mousedev_fops

通过这个结构体就可以调用鼠标类的其他操作函数(read, write……)。也就是说执行input_open_file()也就相当于执行mousedev_fops.open()函数,也就是执行鼠标类设备文件mousedev_open()函数。

static int mousedev_open(struct inode * inode, struct file * file)

{

struct mousedev_list *list;

struct input_handle *handle;

struct mousedev *mousedev;

int i;

#ifdef CONFIG_INPUT_MOUSEDEV_PSAUX

if (imajor(inode) == MISC_MAJOR)

i = MOUSEDEV_MIX;

else

#endif

i = iminor(inode) - MOUSEDEV_MINOR_BASE; //获取次设备号

if (i >= MOUSEDEV_MINORS || !mousedev_table[i])

return -ENODEV;

if (!(list = kzalloc(sizeof(struct mousedev_list), GFP_KERNEL)))

return -ENOMEM;

spin_lock_init(&list->packet_lock);

list->pos_x = xres / 2;

list->pos_y = yres / 2;

list->mousedev = mousedev_table[i]; //通过次设备号获取具体鼠标设备的信息结构体

list_add_tail(&list->node, &mousedev_table[i]->list);

file->private_data = list;

if (!list->mousedev->open++) {

if (list->mousedev->minor == MOUSEDEV_MIX) {

list_for_each_entry(handle, &mousedev_handler.h_list, h_node) {

mousedev = handle->private;

if (!mousedev->open && mousedev->exist)

input_open_device(handle);//打开具体设备

}

} else

if (!mousedev_mix.open && list->mousedev->exist)

input_open_device(&list->mousedev->handle);

}

return 0;

 }

return -ENODEV;

/*

 * That's _really_ odd. Usually NULL ->open means "nothing special",

 * not "no device". Oh, well...

 */

if (!new_fops->open) {

fops_put(new_fops);

return -ENODEV;

}

old_fops = file->f_op;

file->f_op = new_fops;

err = new_fops->open(inode, file);//打开设备文件

if (err) {

fops_put(file->f_op);

file->f_op = fops_get(old_fops);

}

fops_put(old_fops);

return err;

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值