现在回到input_attach_handler中
error = handler->connect(handler, dev, id);
现在知道handler->connect是啥了吧,就是mousedev_connect
mousedev_connect在/drivers/input/mousedev.c中
|
由于mice使用了31,所以这里我们这个鼠标设备的minor 就是32了
现在终于可以进入mousedev_create中的input_register_handle了
input_register_handle在/drivers/input/input.c中
|
注册好的鼠标设备数据结构如下

mixdev_add_device在/drivers/input/mousedev.c中
|
到这里input子系统中的注册就完毕了,结合hid中的数据结构,如下图

继续回到hub_port_connect_change中,就剩下一个hub_power_remaining函数,这是一个关于电流分配的函数,对于电流的认识还不足,也不分析了
跳回到hub_events中
最后一个处理
if (!hdev->parent && !hub->busy_bits[0])
usb_enable_root_hub_irq(hdev->bus);
因为uhci中没有hub_irq_enable这个操作,所以这个函数对于uhci来说是没有作用的
这样一个usb鼠标从头到尾的注册过成就分析好了
最后来看看在linux中是如何取得这个usb鼠标的数据的
在linux中,使用一个设备需要先open,当我们打开鼠标的字符文件后就来到了input_open_file中,至于input子系统的原理,有时间的话我会在写一篇详细的文章来解析
input_open_file在/drivers/input/input.c中
|
mousedev_open函数就是这个open操作
mousedev_open在/drivers/input/mousedev.c中
|
input_open_device在/drivers/input/input.c中
|
hidinput_open就是这个操作
hidinput_open在/drivers/hid/hid-input.c中
|
这个open操作为usbhid_open
usbhid_open在/drivers/hid/usbhid/hid-core.c中
|
hid_start_in在/drivers/hid/usbhid/hid-core.c中
|
到了这里终于开始发送in传输了,也就是和usb设备开始通信了
打开设备之后,如何读取这些数据呢?~
在linux中,读取数据的操作为read,在input子系统的mouse处理模块中,read操作为mousedev_read
mousedev_read在/drivers/input/mousedev.c中
|
谁来敲呢?~ 先回忆一下之前open操作中是不是发送了一个in传输?
呢么大家都知道urb是有一个完成函数的
呢么这个完成函数是啥呢?
回到usb_hid_configure中
usb_fill_int_urb(usbhid->urbin, dev, pipe, usbhid->inbuf, insize,hid_irq_in, hid, interval);
hid_irq_in!没错,就是他了
hid_irq_in在/drivers/hid/usbhid/hid-core.c中
|
hid_input_report在/drivers/hid/hid-core.c中
|
hid_input_field在/drivers/hid/hid-core.c中
|
extract(data, offset + n * size, size);
中了
这段代码负责把urb取得的数据按照我们之前注册的hid协议进行筛选
snto32负责把一个无符号数转换成有符号数
主要是这个extract
extract是一个内嵌函数,他在/drivers/hid/hid-core.c中
|
首先看回忆一下usb鼠标发送来的是什么数据
我们之前写报告描述符时是这样定义鼠标的数据的
一共4个字节,第1字节的前3位分别为左键,中键和右键,然后有5位的占位来凑足1个字节
之后是3字节,X轴使用1字节,Y轴使用1字节,滚轮使用1字节
呢么这里如何处理呢?
首先是计算大的偏移,因为3个键为第一字节的第一位开始的连续3bit,所以这里是没有偏移的, field->report_offset也正确的表示为0x0
所以这里report += offset >> 3为report += 0 >> 3,report的数值没有改变
这里有一个小细节,就是>>3,也就是说大偏移的基本单位是字节,所以需要5个bit占位符,这样才能正确的计算之后的X轴数据的起始位置
然后取得偏移的底3位offset &= 7; 也就是只要bit的偏移量,左键的偏移为0,右键的偏移为1,中键的偏移为2
然后是x = get_unaligned_le64(report);把report的值赋给x,至于get_unaligned_le64是什么意思,我也不是很清楚,请大家指教
最后就是取得数据了x = (x >> offset) & ((1ULL << n) - 1);
首先偏移,然后按照数据的长度取得数据,
(1ULL << n) – 1我举个例子来说明,我只需要3bit的数据,呢么就是(1 << 3) – 1,1 << 3换算成2进制就是1000,然后减1,不就是111了么,然后与上数据就能得到3个bit长度的数据了
现在我举个例子来说明总体流程,鼠标的中键按下了
呢么数据按照2进制来看就是00000100
经过了左键和右键数据取得后,现在到中键,中键的数据大偏移为0,小偏移为2,数据长度为1个bit
首先是0000100 += 2 >> 3 ,report为0000100不变
然后 2 &= 7 , offset变成了2
最后x = (x >> offset) & ((1ULL << n) - 1)就是 x = ((0000100) >> 2 & 1)
最后x = 1 ,正确的取得了数据
取得正确的数据后就要上报
hid_process_event负责完成这个任务
hid_process_event在/drivers/hid/hid-core.c中
|
我们这里为input设备,当然进入的就是hidinput_hid_event了
hidinput_hid_event在/drivers/hid/hid-input.c中
|
我们直接来看最主要的函数input_event(input, usage->type, usage->code, value)
首先看这个函数的参数,input设备,事件的主要类型,事件的次要类型,事件的值
换算成具体就是(鼠标,按键,鼠标左键,按下)
是不是豁然开朗呢? 这里就已经按照hid协议把取得的数据提交给input子系统了
input_event在/drivers/input/input.c中
|
input_handle_event在/drivers/input/input.c中
|
我们这里当然是把辛辛苦苦取得的数据提交给处理模块,再发回给设备的话不就白忙乎一场了
input_pass_event在/drivers/input/input.c中
|
handle->handler->event为mousedev_event
mousedev_event在/drivers/input/mousedev.c中
|
mousedev_key_event在/drivers/input/mousedev.c中
|
咦? 呢么你说为啥还不唤醒读取等待? 因为数据还没分析完啊
左键,右键,中键,X轴,Y轴和滚轮现在我们只分析了一个
等所有事件分析完之后到mousedev_event中的case EV_SYN中
这是一个同步处理,也就是要唤醒等待了
mousedev_notify_readers负责这个工作
mousedev_notify_readers在/drivers/input/mousedev.c中
|
执行了这行代码之后,read操作中就会继续运行,这样我们也就read到了数据
一次usb鼠标的数据读取就完成了
而这个神奇的同步信号是哪里发出来的呢?
回到hid_input_report中看最后一行
hidinput_report_event
hidinput_report_event在/drivers/hid/hid-input.c中
|
input_sync在/include/linux/input.h中
|
就是在这里发送同步信号的
到此学习就结束了,希望我这小小的学习经验能帮上大家 = 3=)/