Linux input子系统学习总结(三)----Input设备驱动
Input 设备驱动 ---操作硬件获取硬件寄存器中设备输入的数据,并把数据交给核心层;
一 、设备驱动的注册步骤:
1、分配一个struct input_dev :
struct input_dev *input_dev;
2、 初始化 input_dev 这个结构体 :
3、 注册这个input_dev 设备:
Input_register_device(dev);
4、 在input设备发生输入操作时,提交所发生的事件及键值、坐标等信息:
Input_report_abs()///报告X,y的坐标值
Input_report_key()///报告触摸屏的状态,是否被按下
Input_sync () ///表示提交一个完整的报告,这样linux内核就知道哪几个数据组合起来代表一个事件
二、Linux 中输入事件的类型:
EV_SYN 0X00 同步事件
EV_KEY 0X01 按键事件
EV_REL 0X02 相对坐标
EV_ABS 0X03 绝对坐标
....
三、关键程序片段(以USB鼠标为例:drivers\hid\usbhid\usbmouse.c)
1、 module_usb_driver(usb_mouse_driver);///系统启动时注册usb_mouse_driver (在usb架构中实现)
2、 usb_mouse_probe (设备初始化,usbmouse 属于usb设备,匹配成功后注册input设备)
3、 input_register_device(mouse->dev); 注册设备驱动
4、 input_attach_handler(dev, handler);///遍历所有的input_handler,并与 dev 进行匹配
usbmouse除了可以和evdev_handler 匹配成功,还和mousedev_handler 匹配成功,所以会分别调用evdev_handler的connect 函数创建event 节点和 mousedev_handler 的connect创建mouse节点
5、 input_match_device(handler, dev);///---->handler 和 device 进行真正的匹配(通过id_table 进行匹配)
6、 handler->connect(handler, dev, id);///匹配成功调用handler的connect 函数
7、 evdev_connect()///将创建 event(0、1、2…)节点
8、 mousedev_connect()///将创建 mouse(0、1、2…)节点
9、 mousedev_create()
10、cdev_init(&mousedev->cdev, &mousedev_fops);
11、usb_mouse_irq()///最终的数据在中断里面获取到,并保存到mouse –>data 里面
12、input_report_key\ input_report_rel\ input_sync ///报告按键信息
13、input_event
14、input_handle_event(dev, type, code, value)
15、input_pass_values(dev, dev->vals, dev->num_vals);
16 、input_to_handler(handle, vals, count);
17、handler->event(handle, v->type, v->code, v->value);

static struct usb_driver usb_mouse_driver = {
.name = "usbmouse",
.probe = usb_mouse_probe,///当有新的usbmouse加入时,系统会进行匹配,匹配成功后则调用probe函数,完成设备的初始化
.disconnect = usb_mouse_disconnect,
.id_table = usb_mouse_id_table,
};
module_usb_driver(usb_mouse_driver);///系统启动时注册usb_mouse_driver
static int usb_mouse_probe(struct usb_interface *intf, const struct usb_device_id *id)
{
struct usb_device *dev = interface_to_usbdev(intf);
struct usb_host_interface *interface;
struct usb_endpoint_descriptor *endpoint;
struct usb_mouse *mouse;
struct input_dev *input_dev;
int pipe, maxp;
int error = -ENOMEM; interface = intf->cur_altsetting; if (interface->desc.bNumEndpoints != )
return -ENODEV; endpoint = &interface->endpoint[].desc;
if (!usb_endpoint_is_int_in(endpoint))
return -ENODEV; pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);
maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe)); mouse = kzalloc(sizeof(struct usb_mouse), GFP_KERNEL);
input_dev = input_allocate_device();
if (!mouse || !input_dev)
goto fail1; mouse->data = usb_alloc_coherent(dev, , GFP_ATOMIC, &mouse->data_dma);
if (!mouse->data)
goto fail1; mouse->irq = usb_alloc_urb(, GFP_KERNEL);
if (!mouse->irq)
goto fail2; mouse->usbdev = dev;
mouse->dev = input_dev; if (dev->manufacturer)
strlcpy(mouse->name, dev->manufacturer, sizeof(mouse->name)); if (dev->product) {
if (dev->manufacturer)
strlcat(mouse->name, " ", sizeof(mouse->name));
strlcat(mouse->name, dev->product, sizeof(mouse->name));
} if (!strlen(mouse->name))
snprintf(mouse->name, sizeof(mouse->name),
"USB HIDBP Mouse %04x:%04x",
le16_to_cpu(dev->descriptor.idVendor),
le16_to_cpu(dev->descriptor.idProduct)); usb_make_path(dev, mouse->phys, sizeof(mouse->phys));
strlcat(mouse->phys, "/input0", sizeof(mouse->phys)); input_dev->name = mouse->name;
input_dev->phys = mouse->phys;
usb_to_input_id(dev, &input_dev->id);
input_dev->dev.parent = &intf->dev; ////evbit 关于设备支持事件类型的 bitmap
input_dev->evbit[] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL); ///BIT_MASK 找到参数值所在的 bit位
input_dev->keybit[BIT_WORD(BTN_MOUSE)] = BIT_MASK(BTN_LEFT) | ///鼠标支持左键、右键、中键三个按键
BIT_MASK(BTN_RIGHT) | BIT_MASK(BTN_MIDDLE);
input_dev->relbit[] = BIT_MASK(REL_X) | BIT_MASK(REL_Y); ///REL_X REL_Y 表示鼠标的位置信息
input_dev->keybit[BIT_WORD(BTN_MOUSE)] |= BIT_MASK(BTN_SIDE) | ///在已有按键的基础上加上一个边键和一个而外的键
BIT_MASK(BTN_EXTRA);
input_dev->relbit[] |= BIT_MASK(REL_WHEEL);///给相对事件加上滚轮的事件 input_set_drvdata(input_dev, mouse); input_dev->open = usb_mouse_open;
input_dev->close = usb_mouse_close; usb_fill_int_urb(mouse->irq, dev, pipe, mouse->data,
(maxp > ? : maxp),
usb_mouse_irq, mouse, endpoint->bInterval);
mouse->irq->transfer_dma = mouse->data_dma;
mouse->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; error = input_register_device(mouse->dev);
if (error)
goto fail3; usb_set_intfdata(intf, mouse);
return ; fail3:
usb_free_urb(mouse->irq);
fail2:
usb_free_coherent(dev, , mouse->data, mouse->data_dma);
fail1:
input_free_device(input_dev);
kfree(mouse);
return error;
}
int input_register_device(struct input_dev *dev)
{
struct input_devres *devres = NULL;
struct input_handler *handler;
unsigned int packet_size;
const char *path;
int error; if (dev->devres_managed) {
devres = devres_alloc(devm_input_device_unregister,
sizeof(struct input_devres), GFP_KERNEL);
if (!devres)
return -ENOMEM; devres->input = dev;
} /* Every input device generates EV_SYN/SYN_REPORT events. */
__set_bit(EV_SYN, dev->evbit); /* KEY_RESERVED is not supposed to be transmitted to userspace. */
__clear_bit(KEY_RESERVED, dev->keybit); /* Make sure that bitmasks not mentioned in dev->evbit are clean. */
input_cleanse_bitmasks(dev); packet_size = input_estimate_events_per_packet(dev);
if (dev->hint_events_per_packet < packet_size)
dev->hint_events_per_packet = packet_size; dev->max_vals = dev->hint_events_per_packet + ;
dev->vals = kcalloc(dev->max_vals, sizeof(*dev->vals), GFP_KERNEL);
if (!dev->vals) {
error = -ENOMEM;
goto err_devres_free;
} /*
* 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.
*/
if (!dev->rep[REP_DELAY] && !dev->rep[REP_PERIOD]) {
dev->timer.data = (long) dev;
dev->timer.function = input_repeat_key;
dev->rep[REP_DELAY] = ;
dev->rep[REP_PERIOD] = ;
} if (!dev->getkeycode)
dev->getkeycode = input_default_getkeycode; if (!dev->setkeycode)
dev->setkeycode = input_default_setkeycode; error = device_add(&dev->dev);
if (error)
goto err_free_vals; path = kobject_get_path(&dev->dev.kobj, GFP_KERNEL);
pr_info("%s as %s\n",
dev->name ? dev->name : "Unspecified device",
path ? path : "N/A");
kfree(path); error = mutex_lock_interruptible(&input_mutex);
if (error)
goto err_device_del; list_add_tail(&dev->node, &input_dev_list); list_for_each_entry(handler, &input_handler_list, node)
input_attach_handler(dev, handler);////遍历所有的input_handler,并与 dev 进行匹配 input_wakeup_procfs_readers(); mutex_unlock(&input_mutex); if (dev->devres_managed) {
dev_dbg(dev->dev.parent, "%s: registering %s with devres.\n",
__func__, dev_name(&dev->dev));
devres_add(dev->dev.parent, devres);
}
return ; err_device_del:
device_del(&dev->dev);
err_free_vals:
kfree(dev->vals);
dev->vals = NULL;
err_devres_free:
devres_free(devres);
return error;
}
static int input_attach_handler(struct input_dev *dev, struct input_handler *handler)
{
const struct input_device_id *id;
int error; id = input_match_device(handler, dev);////---->handler 和 device 进行真正的匹配
if (!id)
return -ENODEV; error = handler->connect(handler, dev, id);///如果返回id不为空就执行handler 的 connect ---> 调用 evdev.c 的 connect 函数
if (error && error != -ENODEV)
pr_err("failed to attach handler %s to device %s, error: %d\n",
handler->name, kobject_name(&dev->dev.kobj), error); return error;
}
查看设备在系统中对应的节点信息(包括设备名称ID对应的handler等),例如usb鼠标对应的节点信息如下:

鼠标对应的事件驱动为mouse1 和event3,因为它和两个事件驱动匹配成功;

Event 节点里面存放的数据都是没有经过处理的原始数据流,通过命令$cat event3可以看到鼠标输入的数据,但是mouse 节点里面的数据是经过处理的有结构的数据,直接对应鼠标点击或滑动的具体坐标,应用程序可以直接读取使用,可以通过命令$cat mouse1可以看到鼠标输入的数据


Linux input子系统学习总结(三)----Input设备驱动的更多相关文章
- input子系统学习笔记六 按键驱动实例分析下【转】
转自:http://blog.chinaunix.net/uid-20776117-id-3212095.html 本文接着input子系统学习笔记五 按键驱动实例分析上接续分析这个按键驱动实例! i ...
- Linux时间子系统之(三):用户空间接口函数
专题文档汇总目录 Notes:用户空间时间相关接口函数: 类型 API 精度 说明 时间 time stime time_t 精度为秒级 逐渐要被淘汰.需要定义__ARCH_WANT_SYS_TIME ...
- Linux内核分析(五)----字符设备驱动实现
原文:Linux内核分析(五)----字符设备驱动实现 Linux内核分析(五) 昨天我们对linux内核的子系统进行简单的认识,今天我们正式进入驱动的开发,我们今后的学习为了避免大家没有硬件的缺陷, ...
- Linux input子系统学习总结(一)---- 三个重要的结构体
一 . 总体架构 图 上层是图形界面和应用程序,通过监听设备节点,获取用户相应的输入事件,根据输入事件来做出相应的反应:eventX (X从0开始)表示 按键事件,mice 表示鼠标事件 Input ...
- Linux input子系统学习总结(二)----Input事件驱动
Input 事件驱动: (主要文件 :drivers/input/evdev.c . drivers/input/input.h)基于kernel 4.0 一. 关键函数调用顺序: 1.inp ...
- linux输入子系统(6)-input子系统介绍及结构图
注:本系列转自: http://www.ourunix.org/post/290.html input子系统介绍 输入设备(如按键,键盘,触摸屏,鼠标,蜂鸣器等)是典型的字符设备,其一 ...
- linux 输入子系统(4)---- input子系统的初始化
Input子系统的初始化函数为input_init(),如下: static int __init input_init(void) { int err; input_init_abs_bypass( ...
- Html5学习进阶三 Input 类型
HTML5 新的 Input 类型 HTML5 拥有多个新的表单输入类型.这些新特性提供了更好的输入控制和验证. 本章全面介绍这些新的输入类型: email url number range Date ...
- linux内核I2C子系统学习(三)
写设备驱动: 四部曲: 构建i2c_driver 注册i2c_driver 构建i2c_client ( 第一种方法:注册字符设备驱动.第二种方法:通过板文件的i2c_board_info填充,然后注 ...
随机推荐
- 【HLSDK系列】groupinfo的基本用法
如果你经常写AMXX,你应该会知道有个 pev->groupinfo 变量,但我猜大部分人都不会用这个变量,这个变量涉及很多实体处理功能,下面列举几个最常用的. ① 玩家与非玩家实体之间的碰撞检 ...
- 【开发工具IDE】eclipse的SVN提交忽略target等多余文件
这个build失败的解决方案就是不要把你项目的 target目录放在src repository 里面,还有 .project 和 .classpath最好也别放到src repository 里. ...
- 【刷题】洛谷 P3834 【模板】可持久化线段树 1(主席树)
题目背景 这是个非常经典的主席树入门题--静态区间第K小 数据已经过加强,请使用主席树.同时请注意常数优化 题目描述 如题,给定N个正整数构成的序列,将对于指定的闭区间查询其区间内的第K小值. 输入输 ...
- 【刷题】洛谷 P3455 [POI2007]ZAP-Queries
题目描述 Byteasar the Cryptographer works on breaking the code of BSA (Byteotian Security Agency). He ha ...
- win7下解决烦人的管理员权限问题
禁不住诱惑,用上win7了.可是,对system下的文件进行编辑时候,老是碰到什么必须拥有管理员权限才能进行操作,删除文件或者文件夹也遇到一样的问题.我就纳闷了,我不就是超级管理员吗?我怎么就没有权限 ...
- 【BZOJ1914】数三角形(组合数,极角排序)
[BZOJ1914]数三角形(组合数,极角排序) 题面 BZOJ权限题 良心洛谷 题解 这种姿势很吼啊,表示计算几何啥的一窍不通来着. 题目就是这样,正难则反,所以我们不考虑过原点的三角形, 反过来, ...
- 【51Nod1773】A国的贸易 解题报告
[51Nod1773]A国的贸易 Description 给出一个长度为 \(2^n\) 的序列,编号从\(0\)开始.每次操作后,如果 \(i\) 与 \(j\) 的二进制表示只差一位则第 \(i\ ...
- 百度地图JS API不能使用position:fixed
用于放置百度地图的dom元素及其任何一级父元素设置position:fixed属性时,js会报如下错误: Uncaught TypeError: Cannot read property 'offse ...
- HYSBZ(BZOJ) 4300 绝世好题(位运算,递推)
HYSBZ(BZOJ) 4300 绝世好题(位运算,递推) Description 给定一个长度为n的数列ai,求ai的子序列bi的最长长度,满足bi&bi-1!=0(2<=i<= ...
- poi excel导入纯数字单元格显示科学计数法的处理
POI读取Excel文件时,对纯数字单元格的处理 用POI读取Excel文件的时候,可能会遇到这样的问题:Excel文件中某一单元格中的数据为数字,例如12345678910123. 正常读取的话 ...