LINUX下USB1.1设备学习小记(6)_hid与input子系统(3)
来源:互联网 发布:手机查看路由器mac地址 编辑:程序博客网 时间:2024/06/06 01:41
现在回到input_attach_handler中
error = handler->connect(handler, dev, id);
现在知道handler->connect是啥了吧,就是mousedev_connect
mousedev_connect在/drivers/input/mousedev.c中
staticint mousedev_connect(struct input_handler*handler,
struct input_dev *dev,
const struct input_device_id *id)
{
struct mousedev *mousedev;
int minor;
int error;
//历遍mousedev_table数组,寻找一个为空的位置
for (minor= 0; minor < MOUSEDEV_MINORS; minor++)
if (!mousedev_table[minor])
break;
//检测数组是否满了
if (minor== MOUSEDEV_MINORS){
printk(KERN_ERR "mousedev: no more free mousedev devices\n");
return -ENFILE;
}
//创建一个鼠标设备
mousedev = mousedev_create(dev, handler, minor);
if (IS_ERR(mousedev))
return PTR_ERR(mousedev);
//添加到mice设备队列中
error = mixdev_add_device(mousedev);
if (error){
mousedev_destroy(mousedev);
return error;
}
return 0;
}
由于mice使用了31,所以这里我们这个鼠标设备的minor 就是32了
现在终于可以进入mousedev_create中的input_register_handle了
input_register_handle在/drivers/input/input.c中
int input_register_handle(struct input_handle*handle)
{
struct input_handler *handler = handle->handler;
struct input_dev *dev = handle->dev;
int error;
/*
* We take dev->mutex here to prevent race with
* input_release_device().
*/
error = mutex_lock_interruptible(&dev->mutex);
if (error)
return error;
//连接连接器到设备
list_add_tail_rcu(&handle->d_node,&dev->h_list);
mutex_unlock(&dev->mutex);
synchronize_rcu();
/*
* Since we are supposed to be called from ->connect()
* which is mutually exclusive with ->disconnect()
* we can't be racing with input_unregister_handle()
* and so separate lock is not needed here.
*/
//连接连接器与处理模块
list_add_tail(&handle->h_node,&handler->h_list);
//检测处理模块是否有start操作
if (handler->start)
handler->start(handle);
return 0;
}
注册好的鼠标设备数据结构如下
mixdev_add_device在/drivers/input/mousedev.c中
staticint mixdev_add_device(struct mousedev*mousedev)
{
int retval;
retval = mutex_lock_interruptible(&mousedev_mix->mutex);
if (retval)
return retval;
//检测是否有鼠标设备
if (mousedev_mix->open){
retval = mousedev_open_device(mousedev);
if (retval)
goto out;
mousedev->mixdev_open= 1;
}
get_device(&mousedev->dev);
//添加到mice设备队列
list_add_tail(&mousedev->mixdev_node,&mousedev_mix_list);
out:
mutex_unlock(&mousedev_mix->mutex);
return retval;
}
到这里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中
staticint input_open_file(struct inode*inode, struct file *file)
{
//计算此设备的次设备号属于哪个处理模块
struct input_handler *handler = input_table[iminor(inode)>> 5];
const struct file_operations*old_fops, *new_fops = NULL;
int err;
/* No load-on-demand here? */
//检测处理模块是否存在
//检测这个处理模块的操作集是否存在
if (!handler|| !(new_fops = fops_get(handler->fops)))
return -ENODEV;
/*
* That's _really_ odd. Usually NULL ->open means "nothing special",
* not "no device". Oh, well...
*/
//检测新操作集的open操作是否存在
if (!new_fops->open){
fops_put(new_fops);
return -ENODEV;
}
//更换操作集,将input的操作集更换为处理模块自己的
old_fops = file->f_op;
file->f_op= new_fops;
//运行新操作集中的open操作
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;
}
mousedev_open函数就是这个open操作
mousedev_open在/drivers/input/mousedev.c中
staticint mousedev_open_device(struct mousedev*mousedev)
{
int retval;
retval = mutex_lock_interruptible(&mousedev->mutex);
if (retval)
return retval;
//检测是否为mice设备
if (mousedev->minor== MOUSEDEV_MIX)
mixdev_open_devices();
//检测exist标志
else if(!mousedev->exist)
retval = -ENODEV;
//检测open是否为0
else if(!mousedev->open++){
//打开设备
retval = input_open_device(&mousedev->handle);
if (retval)
mousedev->open--;
}
mutex_unlock(&mousedev->mutex);
return retval;
}
input_open_device在/drivers/input/input.c中
int input_open_device(struct input_handle*handle)
{
struct input_dev *dev = handle->dev;
int retval;
retval = mutex_lock_interruptible(&dev->mutex);
if (retval)
return retval;
if (dev->going_away){
retval = -ENODEV;
goto out;
}
//增加计数器
handle->open++;
//检测使用数是否为0
//检测该input_dev结构是否有open操作
if (!dev->users++&& dev->open)
//执行open操作
retval = dev->open(dev);
if (retval){
dev->users--;
if (!--handle->open){
/*
* Make sure we are not delivering any more events
* through this handle
*/
synchronize_rcu();
}
}
out:
mutex_unlock(&dev->mutex);
return retval;
}
hidinput_open就是这个操作
hidinput_open在/drivers/hid/hid-input.c中
staticint hidinput_open(struct input_dev*dev)
{
struct hid_device *hid = input_get_drvdata(dev);
return hid->hid_open(hid);
}
这个open操作为usbhid_open
usbhid_open在/drivers/hid/usbhid/hid-core.c中
int usbhid_open(struct hid_device*hid)
{
struct usbhid_device *usbhid = hid->driver_data;
int res;
//增加计数器
if (!hid->open++)
{
//唤醒设备
res = usb_autopm_get_interface(usbhid->intf);
if (res< 0)
{
hid->open--;
return -EIO;
}
}
//开始in传输
if (hid_start_in(hid))
hid_io_error(hid);
return 0;
}
hid_start_in在/drivers/hid/usbhid/hid-core.c中
staticint hid_start_in(struct hid_device*hid)
{
unsigned long flags;
int rc = 0;
struct usbhid_device *usbhid = hid->driver_data;
spin_lock_irqsave(&usbhid->inlock, flags);
//检测打开标志是否大于0
//检测悬挂标志是否为0
//检测断开标志是否为0
//检测运行标志是否为0,并置这个标志为1
if (hid->open> 0 &&!test_bit(HID_SUSPENDED,&usbhid->iofl)&&
!test_bit(HID_DISCONNECTED,&usbhid->iofl)&&
!test_and_set_bit(HID_IN_RUNNING,&usbhid->iofl))
{
//发送urb
rc = usb_submit_urb(usbhid->urbin, GFP_ATOMIC);
//检测发送是否成功
if (rc!= 0)
//不成功则置运行标志为0
clear_bit(HID_IN_RUNNING,&usbhid->iofl);
}
spin_unlock_irqrestore(&usbhid->inlock, flags);
return rc;
}
到了这里终于开始发送in传输了,也就是和usb设备开始通信了
打开设备之后,如何读取这些数据呢?~
在linux中,读取数据的操作为read,在input子系统的mouse处理模块中,read操作为mousedev_read
mousedev_read在/drivers/input/mousedev.c中
static ssize_t mousedev_read(structfile *file,char __user *buffer,
size_t count, loff_t *ppos)
{
struct mousedev_client *client = file->private_data;
struct mousedev *mousedev = client->mousedev;
signed char data[sizeof(client->ps2)];
int retval = 0;
if (!client->ready&& !client->buffer&& mousedev->exist&&
(file->f_flags& O_NONBLOCK))
return -EAGAIN;
//等待数据传输
retval = wait_event_interruptible(mousedev->wait,
!mousedev->exist|| client->ready|| client->buffer);
if (retval)
return retval;
if (!mousedev->exist)
return -ENODEV;
spin_lock_irq(&client->packet_lock);
if (!client->buffer&& client->ready){
mousedev_packet(client, client->ps2);
client->buffer= client->bufsiz;
}
if (count> client->buffer)
count = client->buffer;
//拷贝数据
memcpy(data, client->ps2+ client->bufsiz- client->buffer,count);
client->buffer-= count;
spin_unlock_irq(&client->packet_lock);
//将数据从内核空间拷贝到用户空间
if (copy_to_user(buffer, data,count))
return -EFAULT;
return count;
}
谁来敲呢?~ 先回忆一下之前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中
staticvoid hid_irq_in(struct urb*urb)
{
struct hid_device *hid= urb->context;
struct usbhid_device *usbhid= hid->driver_data;
int status;
switch (urb->status){
case 0: /* success */
usbhid->retry_delay= 0;
//报告取得的数据
hid_input_report(urb->context, HID_INPUT_REPORT,
urb->transfer_buffer,
urb->actual_length, 1);
break;
case -EPIPE: /* stall */
clear_bit(HID_IN_RUNNING,&usbhid->iofl);
set_bit(HID_CLEAR_HALT,&usbhid->iofl);
schedule_work(&usbhid->reset_work);
return;
case -ECONNRESET: /* unlink */
case -ENOENT:
case -ESHUTDOWN: /* unplug */
clear_bit(HID_IN_RUNNING,&usbhid->iofl);
return;
case -EILSEQ: /* protocol error or unplug */
case -EPROTO: /* protocol error or unplug */
case -ETIME: /* protocol error or unplug */
case -ETIMEDOUT: /* Should never happen, but... */
clear_bit(HID_IN_RUNNING,&usbhid->iofl);
hid_io_error(hid);
return;
default: /* error */
warn("input irq status %d received", urb->status);
}
//再次发送urb取得数据,形成一个循环
status = usb_submit_urb(urb, GFP_ATOMIC);
//检测发送是否成功
if (status)
{
//不成功则清除运行标志
clear_bit(HID_IN_RUNNING,&usbhid->iofl);
if (status!= -EPERM)
{
err_hid("can't resubmit intr, %s-%s/input%d, status %d",
hid_to_usb_dev(hid)->bus->bus_name,
hid_to_usb_dev(hid)->devpath,
usbhid->ifnum, status);
hid_io_error(hid);
}
}
}
hid_input_report在/drivers/hid/hid-core.c中
int hid_input_report(struct hid_device*hid, int type, u8 *data, int size,int interrupt)
{
//取得对应类型的report
struct hid_report_enum *report_enum = hid->report_enum+ type;
struct hid_report *report;
int n, rsize, i;
if (!hid)
return -ENODEV;
//检测数据长度是否为空
if (!size)
{
dbg_hid("empty report\n");
return -1;
}
dbg_hid("report (size %u) (%snumbered)\n", size, report_enum->numbered? "" : "un");
n = 0; /* Normally report number is 0 */
if (report_enum->numbered){ /* Device uses numbered reports, data[0] is report number */
n = *data++;
size--;
}
/* dump the report */
dbg_hid("report %d (size %u) = ", n, size);
for (i = 0; i < size; i++)
dbg_hid_line(" %02x", data[i]);
dbg_hid_line("\n");
//检测对应的report是否存在
if (!(report= report_enum->report_id_hash[n])){
dbg_hid("undefined report_id %d received\n", n);
return -1;
}
rsize = ((report->size- 1) >> 3)+ 1;
//检测数据长度是否不足所要求的
if (size< rsize)
{
dbg_hid("report %d is too short, (%d < %d)\n", report->id, size, rsize);
memset(data+ size, 0, rsize- size);
}
//检测设备是否为hiddev类
if ((hid->claimed& HID_CLAIMED_HIDDEV)&& hid->hiddev_report_event)
hid->hiddev_report_event(hid, report);
//检测设备是否为hidraw类
if (hid->claimed& HID_CLAIMED_HIDRAW)
{
/* numbered reports need to be passed with the report num */
if (report_enum->numbered)
hidraw_report_event(hid, data- 1, size + 1);
else
hidraw_report_event(hid, data, size);
}
//历遍域
for (n = 0; n < report->maxfield; n++)
hid_input_field(hid, report->field[n], data, interrupt);
//检测设备是否为input类
if (hid->claimed& HID_CLAIMED_INPUT)
hidinput_report_event(hid, report);
return 0;
}
hid_input_field在/drivers/hid/hid-core.c中
staticvoid hid_input_field(struct hid_device*hid, struct hid_field *field,
__u8 *data,int interrupt)
{
unsigned n;
unsigned count= field->report_count;
unsigned offset = field->report_offset;
unsigned size = field->report_size;
__s32 min = field->logical_minimum;
__s32 max = field->logical_maximum;
__s32 *value;
if (!(value= kmalloc(sizeof(__s32)* count, GFP_ATOMIC)))
return;
//将数据序列转换成正确的形式
for (n = 0; n <count; n++)
{
value[n]= min < 0 ? snto32(extract(data, offset+ n * size, size), size):
extract(data, offset+ n * size, size);
if (!(field->flags& HID_MAIN_ITEM_VARIABLE)/* Ignore report if ErrorRollOver */
&& value[n]>= min && value[n]<= max
&& field->usage[value[n]- min].hid== HID_UP_KEYBOARD+ 1)
goto exit;
}
//历遍usage
for (n = 0; n <count; n++)
{
//检测是否为变量类型
if (HID_MAIN_ITEM_VARIABLE& field->flags)
{
hid_process_event(hid, field,&field->usage[n], value[n], interrupt);
continue;
}
if (field->value[n]>= min && field->value[n]<= max
&& field->usage[field->value[n]- min].hid
&&search(value, field->value[n],count))
hid_process_event(hid, field,&field->usage[field->value[n]- min], 0, interrupt);
if (value[n]>= min && value[n]<= max
&& field->usage[value[n]- min].hid
&&search(field->value, value[n],count))
hid_process_event(hid, field,&field->usage[value[n]- min], 1, interrupt);
}
//将数据拷贝进域的value中
memcpy(field->value, value,count * sizeof(__s32));
exit:
kfree(value);
}
extract(data, offset + n * size, size);
中了
这段代码负责把urb取得的数据按照我们之前注册的hid协议进行筛选
snto32负责把一个无符号数转换成有符号数
主要是这个extract
extract是一个内嵌函数,他在/drivers/hid/hid-core.c中
static__inline__ __u32 extract(__u8*report, unsigned offset, unsigned n)
{
u64 x;
if (n > 32)
printk(KERN_WARNING "HID: extract() called with n (%d) > 32! (%s)\n",
n, current->comm);
report += offset>> 3;/* adjust byte index */
offset &= 7;/* now only need bit offset into one byte */
x = get_unaligned_le64(report);
x = (x >> offset)& ((1ULL<< n)- 1);/* extract bit field */
return (u32) x;
}
首先看回忆一下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中
staticvoid hid_process_event(struct hid_device*hid, struct hid_field *field,struct hid_usage *usage, __s32 value,int interrupt)
{
hid_dump_input(usage, value);
//检测设备类型是否为input类
if (hid->claimed& HID_CLAIMED_INPUT)
hidinput_hid_event(hid, field, usage, value);
//检测设备类型是否为hiddev
//检测是否有hiddev_hid_event函数
if (hid->claimed& HID_CLAIMED_HIDDEV && interrupt && hid->hiddev_hid_event)
hid->hiddev_hid_event(hid, field, usage, value);
}
我们这里为input设备,当然进入的就是hidinput_hid_event了
hidinput_hid_event在/drivers/hid/hid-input.c中
void hidinput_hid_event(struct hid_device*hid, struct hid_field *field,struct hid_usage *usage, __s32 value)
{
struct input_dev *input;
unsigned *quirks= &hid->quirks;
if (!field->hidinput)
return;
input = field->hidinput->input;
if (!usage->type)
return;
/* handle input events for quirky devices */
if (hidinput_event_quirks(hid, field, usage, value))
return;
if (usage->hat_min< usage->hat_max|| usage->hat_dir)
{
int hat_dir = usage->hat_dir;
if (!hat_dir)
hat_dir = (value - usage->hat_min)* 8 / (usage->hat_max- usage->hat_min+ 1) + 1;
if (hat_dir< 0 || hat_dir> 8)
hat_dir = 0;
input_event(input, usage->type, usage->code, hid_hat_to_axis[hat_dir].x);
input_event(input, usage->type, usage->code+ 1, hid_hat_to_axis[hat_dir].y);
return;
}
if (usage->hid== (HID_UP_DIGITIZER | 0x003c)){ /* Invert */
*quirks = value? (*quirks| HID_QUIRK_INVERT): (*quirks& ~HID_QUIRK_INVERT);
return;
}
if (usage->hid== (HID_UP_DIGITIZER | 0x0032)){ /* InRange */
if (value){
input_event(input, usage->type,(*quirks & HID_QUIRK_INVERT) ? BTN_TOOL_RUBBER : usage->code, 1);
return;
}
input_event(input, usage->type, usage->code, 0);
input_event(input, usage->type, BTN_TOOL_RUBBER, 0);
return;
}
if (usage->hid== (HID_UP_DIGITIZER | 0x0030)&& (*quirks & HID_QUIRK_NOTOUCH)){ /* Pressure */
int a = field->logical_minimum;
int b = field->logical_maximum;
input_event(input, EV_KEY, BTN_TOUCH, value> a + ((b - a)>> 3));
}
if (usage->hid== (HID_UP_PID | 0x83UL)){ /* Simultaneous Effects Max */
dbg_hid("Maximum Effects - %d\n",value);
return;
}
if (usage->hid== (HID_UP_PID | 0x7fUL)){
dbg_hid("PID Pool Report\n");
return;
}
if ((usage->type== EV_KEY)&& (usage->code== 0))/* Key 0 is "unassigned", not KEY_UNKNOWN */
return;
if ((usage->type== EV_ABS)&& (field->flags& HID_MAIN_ITEM_RELATIVE)&&
(usage->code== ABS_VOLUME))
{
int count= abs(value);
int direction = value > 0 ? KEY_VOLUMEUP : KEY_VOLUMEDOWN;
int i;
for (i= 0; i < count; i++)
{
input_event(input, EV_KEY, direction, 1);
input_sync(input);
input_event(input, EV_KEY, direction, 0);
input_sync(input);
}
return;
}
/* report the usage code as scancode if the key status has changed */
//检测是否为按键类型
//检测按键的状态是否改变
if (usage->type== EV_KEY && !!test_bit(usage->code, input->key)!= value)
input_event(input, EV_MSC, MSC_SCAN, usage->hid);
input_event(input, usage->type, usage->code, value);
//检测域类型是否为相对值类型
//检测是否为按键类型
if ((field->flags& HID_MAIN_ITEM_RELATIVE)&& (usage->type== EV_KEY))
input_event(input, usage->type, usage->code, 0);
}
我们直接来看最主要的函数input_event(input, usage->type, usage->code, value)
首先看这个函数的参数,input设备,事件的主要类型,事件的次要类型,事件的值
换算成具体就是(鼠标,按键,鼠标左键,按下)
是不是豁然开朗呢? 这里就已经按照hid协议把取得的数据提交给input子系统了
input_event在/drivers/input/input.c中
void input_event(struct input_dev*dev,
unsigned int type, unsignedint code, int value)
{
unsigned long flags;
//检测事件类型是否已经注册
if (is_event_supported(type, dev->evbit, EV_MAX))
{
spin_lock_irqsave(&dev->event_lock, flags);
add_input_randomness(type, code, value);
input_handle_event(dev, type, code, value);
spin_unlock_irqrestore(&dev->event_lock, flags);
}
}
input_handle_event在/drivers/input/input.c中
staticvoid input_handle_event(struct input_dev*dev,
unsigned int type, unsignedint code, int value)
{
int disposition = INPUT_IGNORE_EVENT;
//判断事件类型
switch (type){
case EV_SYN:
switch (code){
case SYN_CONFIG:
disposition = INPUT_PASS_TO_ALL;
break;
case SYN_REPORT:
if (!dev->sync){
dev->sync= 1;
disposition = INPUT_PASS_TO_HANDLERS;
}
break;
}
break;
case EV_KEY:
if (is_event_supported(code, dev->keybit, KEY_MAX) &&
!!test_bit(code, dev->key)!= value){
if (value!= 2){
__change_bit(code, dev->key);
if (value)
input_start_autorepeat(dev, code);
}
disposition = INPUT_PASS_TO_HANDLERS;
}
break;
case EV_SW:
if (is_event_supported(code, dev->swbit, SW_MAX) &&
!!test_bit(code, dev->sw)!= value){
__change_bit(code, dev->sw);
disposition = INPUT_PASS_TO_HANDLERS;
}
break;
case EV_ABS:
if (is_event_supported(code, dev->absbit, ABS_MAX)) {
value = input_defuzz_abs_event(value,
dev->abs[code], dev->absfuzz[code]);
if (dev->abs[code]!= value){
dev->abs[code]= value;
disposition = INPUT_PASS_TO_HANDLERS;
}
}
break;
case EV_REL:
if (is_event_supported(code, dev->relbit, REL_MAX) && value)
disposition = INPUT_PASS_TO_HANDLERS;
break;
case EV_MSC:
if (is_event_supported(code, dev->mscbit, MSC_MAX))
disposition = INPUT_PASS_TO_ALL;
break;
case EV_LED:
if (is_event_supported(code, dev->ledbit, LED_MAX) &&
!!test_bit(code, dev->led)!= value){
__change_bit(code, dev->led);
disposition = INPUT_PASS_TO_ALL;
}
break;
case EV_SND:
if (is_event_supported(code, dev->sndbit, SND_MAX)) {
if (!!test_bit(code, dev->snd)!= !!value)
__change_bit(code, dev->snd);
disposition = INPUT_PASS_TO_ALL;
}
break;
case EV_REP:
if (code<= REP_MAX && value >= 0&& dev->rep[code]!= value){
dev->rep[code]= value;
disposition = INPUT_PASS_TO_ALL;
}
break;
case EV_FF:
if (value>= 0)
disposition = INPUT_PASS_TO_ALL;
break;
case EV_PWR:
disposition = INPUT_PASS_TO_ALL;
break;
}
if (type!= EV_SYN)
dev->sync= 0;
//判断是否为传输给设备
if ((disposition& INPUT_PASS_TO_DEVICE)&& dev->event)
dev->event(dev, type, code, value);
//判断是否为传输给处理模块
if (disposition& INPUT_PASS_TO_HANDLERS)
input_pass_event(dev, type, code, value);
}
我们这里当然是把辛辛苦苦取得的数据提交给处理模块,再发回给设备的话不就白忙乎一场了
input_pass_event在/drivers/input/input.c中
staticvoid input_pass_event(struct input_dev*dev,
unsigned int type, unsignedint code, int value)
{
struct input_handle *handle;
rcu_read_lock();
handle = rcu_dereference(dev->grab);
//检测连接器是否存在
if (handle)
//传递给处理模块
handle->handler->event(handle, type, code, value);
else
list_for_each_entry_rcu(handle,&dev->h_list, d_node)
if (handle->open)
handle->handler->event(handle,
type, code, value);
rcu_read_unlock();
}
handle->handler->event为mousedev_event
mousedev_event在/drivers/input/mousedev.c中
static void mousedev_event(struct input_handle*handle,
unsigned int type, unsignedint code, int value)
{
struct mousedev *mousedev = handle->private;
//检测事件类型
switch (type){
case EV_ABS:
/* Ignore joysticks */
if (test_bit(BTN_TRIGGER, handle->dev->keybit))
return;
if (test_bit(BTN_TOOL_FINGER, handle->dev->keybit))
mousedev_touchpad_event(handle->dev,
mousedev, code, value);
else
mousedev_abs_event(handle->dev, mousedev, code, value);
break;
case EV_REL:
mousedev_rel_event(mousedev, code, value);
break;
case EV_KEY:
if (value!= 2){
if (code== BTN_TOUCH&&
test_bit(BTN_TOOL_FINGER, handle->dev->keybit))
mousedev_touchpad_touch(mousedev, value);
else
mousedev_key_event(mousedev, code, value);
}
break;
case EV_SYN:
if (code== SYN_REPORT){
if (mousedev->touch){
mousedev->pkt_count++;
/*
* Input system eats duplicate events,
* but we need all of them to do correct
* averaging so apply present one forward
*/
fx(0)= fx(1);
fy(0)= fy(1);
}
//唤醒读取等待
mousedev_notify_readers(mousedev,&mousedev->packet);
mousedev_notify_readers(mousedev_mix,&mousedev->packet);
mousedev->packet.dx= mousedev->packet.dy=
mousedev->packet.dz= 0;
mousedev->packet.abs_event= 0;
}
break;
}
}
mousedev_key_event在/drivers/input/mousedev.c中
staticvoid mousedev_key_event(struct mousedev*mousedev,
unsigned int code, int value)
{
int index;
switch (code){
case BTN_TOUCH:
case BTN_0:
case BTN_LEFT: index= 0; break;
case BTN_STYLUS:
case BTN_1:
case BTN_RIGHT: index= 1; break;
case BTN_2:
case BTN_FORWARD:
case BTN_STYLUS2:
case BTN_MIDDLE: index= 2; break;
case BTN_3:
case BTN_BACK:
case BTN_SIDE: index= 3; break;
case BTN_4:
case BTN_EXTRA: index= 4; break;
default: return;
}
if (value){
set_bit(index,&mousedev->packet.buttons);
set_bit(index,&mousedev_mix->packet.buttons);
} else {
clear_bit(index,&mousedev->packet.buttons);
clear_bit(index,&mousedev_mix->packet.buttons);
}
}
咦? 呢么你说为啥还不唤醒读取等待? 因为数据还没分析完啊
左键,右键,中键,X轴,Y轴和滚轮现在我们只分析了一个
等所有事件分析完之后到mousedev_event中的case EV_SYN中
这是一个同步处理,也就是要唤醒等待了
mousedev_notify_readers负责这个工作
mousedev_notify_readers在/drivers/input/mousedev.c中
staticvoid mousedev_notify_readers(struct mousedev*mousedev,
struct mousedev_hw_data *packet)
{
struct mousedev_client *client;
struct mousedev_motion *p;
unsigned int new_head;
int wake_readers = 0;
rcu_read_lock();
list_for_each_entry_rcu(client,&mousedev->client_list, node){
/* Just acquire the lock, interrupts already disabled */
spin_lock(&client->packet_lock);
p = &client->packets[client->head];
if (client->ready&& p->buttons!= mousedev->packet.buttons){
new_head = (client->head+ 1) % PACKET_QUEUE_LEN;
if (new_head!= client->tail){
p = &client->packets[client->head= new_head];
memset(p, 0,sizeof(struct mousedev_motion));
}
}
if (packet->abs_event){
p->dx+= packet->x- client->pos_x;
p->dy+= packet->y- client->pos_y;
client->pos_x= packet->x;
client->pos_y= packet->y;
}
client->pos_x+= packet->dx;
client->pos_x= client->pos_x< 0 ?
0 : (client->pos_x>= xres ? xres : client->pos_x);
client->pos_y+= packet->dy;
client->pos_y= client->pos_y< 0 ?
0 : (client->pos_y>= yres ? yres : client->pos_y);
p->dx+= packet->dx;
p->dy+= packet->dy;
p->dz+= packet->dz;
p->buttons= mousedev->packet.buttons;
if (p->dx|| p->dy|| p->dz||
p->buttons!= client->last_buttons)
client->ready= 1;
spin_unlock(&client->packet_lock);
if (client->ready){
kill_fasync(&client->fasync, SIGIO, POLL_IN);
wake_readers = 1;
}
}
rcu_read_unlock();
if (wake_readers)
wake_up_interruptible(&mousedev->wait);
}
执行了这行代码之后,read操作中就会继续运行,这样我们也就read到了数据
一次usb鼠标的数据读取就完成了
而这个神奇的同步信号是哪里发出来的呢?
回到hid_input_report中看最后一行
hidinput_report_event
hidinput_report_event在/drivers/hid/hid-input.c中
void hidinput_report_event(struct hid_device*hid, struct hid_report *report)
{
struct hid_input *hidinput;
//历遍所有hidinput结构
list_for_each_entry(hidinput,&hid->inputs,list)
input_sync(hidinput->input);
}
input_sync在/include/linux/input.h中
staticinline void input_sync(struct input_dev*dev)
{
input_event(dev, EV_SYN, SYN_REPORT, 0);
}
就是在这里发送同步信号的
- LINUX下USB1.1设备学习小记(6)_hid与input子系统(3)
- LINUX下USB1.1设备学习小记(6)_hid与input子系统(3)
- LINUX下USB1.1设备学习小记(6)_hid与input子系统(3)
- LINUX下USB1.1设备学习小记(6)_hid与input子系统(1)
- LINUX下USB1.1设备学习小记(6)_hid与input子系统(1)
- LINUX下USB1.1设备学习小记(6)_hid与input子系统(2)
- LINUX下USB1.1设备学习小记(6)_hid与input子系统(2)
- LINUX下USB1.1设备学习小记
- LINUX下USB1.1设备学习小记
- LINUX下USB1.1设备学习小记(4)_uhci(3)
- LINUX下USB1.1设备学习小记(4)_uhci(3)
- LINUX下USB1.1设备学习小记(3)_host与device
- LINUX下USB1.1设备学习小记(3)_host与device
- LINUX下USB1.1设备学习小记(3)_host与device
- LINUX下USB1.1设备学习小记(5)_uhci与设备(1)
- LINUX下USB1.1设备学习小记(5)_uhci与设备(2)
- LINUX下USB1.1设备学习小记(1)
- LINUX下USB1.1设备学习小记(1)
- HTTP Header 详解
- LINUX下USB1.1设备学习小记(6)_hid与input子系统(2)
- Dos常用命令
- JAVA NIO 实例
- C#对XML操作
- LINUX下USB1.1设备学习小记(6)_hid与input子系统(3)
- 【学习点滴-数据结构-字符串】 字符串的堆分配方式实现和基本函数
- USCAO section 1.3 Calf Flac
- B2G系统简介(部分资料来源于网上)
- java基本语法汇总
- 在aspx页面向iframe中post参数
- 思维盲点
- win7 iis6 配置如何让局域网内其它用户访问
- 灵活控制 Hibernate 的日志或 SQL 输出