Chinaunix首页 | 论坛 | 博客
  • 博客访问: 434966
  • 博文数量: 125
  • 博客积分: 2066
  • 博客等级: 大尉
  • 技术积分: 1032
  • 用 户 组: 普通用户
  • 注册时间: 2011-04-16 14:06
文章分类

全部博文(125)

文章存档

2011年(125)

分类: LINUX

2011-04-16 14:43:40

Input subsystem 系统实现分析

 Input subsystem系统实现分析.pdf   

Input subsystem 系统实现分析
Tommy.hong@mid-fun.com
本文将简要介绍 Input system 系统,通过鼠标驱动实现过程具体介绍 Input System 系统
的实现。
Input subsystem 系统架构
Input subsystem 由 Drivers、
Input Core 和 Handlers 三个组件构成。
Drivers 负责硬件和 Input
Core 之间的操作,Handlers 负责应用程序同 Input Core 之间的通信。Input Core 实现硬件设
备的注册以及抽象设备集的注册。
硬件向应用程序反馈信息的路径为: Drivers Input Core Handlers Applications
涉及文件
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 中定义及初始化。
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 : "");
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();
}
设备文件的操作函数
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 结构体中的鼠标操作函数结构体。
static struct input_handler mousedev_handler = {
.event = mousedev_event,
.connect =
mousedev_connect,
.disconnect = mousedev_disconnect,
.fops =
&mousedev_fops,
.minor = MOUSEDEV_MINOR_BASE,
.name =
"mousedev",
.id_table =
mousedev_ids,
};
static struct file_operations mousedev_fops = {
.owner = THIS_MODULE,
.read =
mousedev_read,
.write = mousedev_write,
.poll =
mousedev_poll,
.open =
mousedev_open,
.release = mousedev_release,
.fasync = mousedev_fasync,
};
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);//打开具体设备
}
int input_open_device(struct input_handle *handle)
} else
{
if (!mousedev_mix.open && list->mousedev->exist) input_dev *dev = handle->dev;
struct
input_open_device(&list->mousedev->handle);
int err;
}
return 0;
......
}
handle->open++;
if (!dev->users++ && dev->open)
err = dev->open(dev);
if (err)
......
}
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;
}

阅读(923) | 评论(0) | 转发(1) |
给主人留下些什么吧!~~