分享好友

×
取消 复制
返回小栈
LINUX下USB1.1设备学习小记(6)_hid与input子系统(3)
飘絮絮絮丶2020-06-03 16:11:29

现在回到input_attach_handler中
error = handler->connect(handler, dev, id);
现在知道handler->connect是啥了吧,就是mousedev_connect
mousedev_connect在/drivers/input/mousedev.c中

static int 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;
}

注册好的鼠标设备数据结构 

 
回到mousedev_connect,现在到mixdev_add_device
mixdev_add_device在/drivers/input/mousedev.c中

static int 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;
}

因为现在还没有鼠标设备,所以是不会进入到mousedev_open_device中的
到这里input子系统中的注册就完毕了,结合hid中的数据结构,

 
回到hid_probe中,剩下的hiddev和hidraw与鼠标无关,我就不分析了
继续回到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中

static int 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;
}

这样就狸猫换太子进入到了mouse处理模块的open中
mousedev_open函数就是这个open操作
mousedev_open在/drivers/input/mousedev.c中

static int 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
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;
}

这里的open操作是有的
hidinput_open就是这个操作
hidinput_open在/drivers/hid/hid-input.c中

static int hidinput_open(struct input_dev *dev)
{
    struct hid_device *hid = input_get_drvdata(dev);
    return hid->hid_open(hid);
}

很简单继续运行open
这个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
hid_start_in在/drivers/hid/usbhid/hid-core.c中

static int 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(struct file *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中

static void 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);
        }
    }
}

urb取得数据成功的话会执行hid_input_report
hid_input_report在/drivers/hid/hid-core.c中

int hid_input_report(struct hid_device *hid, int type, u8 *data, int size, intinterrupt)
{
    //取得对应类型的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 (= 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 (= 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;
}

hiddev和hidraw我们不关心,看之后的hid_input_field
hid_input_field在/drivers/hid/hid-core.c中

static void 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 (= 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 (= 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);
}

其中的大学问就在value[n] = min < 0 ? snto32(extract(data, offset + n * size, size), size) :
          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 (> 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 = (>> 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中

static void 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, structhid_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 + ((- 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 (= 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);
}

hidinput_hid_event的任务很简单,就是根据事件类型进行一下处理
我们直接来看最主要的函数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, unsigned int 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
input_handle_event在/drivers/input/input.c中

static void input_handle_event(struct input_dev *dev,
             unsigned int type, unsigned int 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中

static void input_pass_event(struct input_dev *dev,
             unsigned int type, unsigned int 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, unsigned int 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() = fx(1);
                fy() = 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;
    }
}

我们这里为key类型,当然是进入到mousedev_key_event中了
mousedev_key_event在/drivers/input/mousedev.c中

static void 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中

static void 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->- client->pos_x;
            p->dy += packet->- 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);
}

我们只看最后一行wake_up_interruptible
执行了这行代码之后,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
input_sync在/include/linux/input.h中

static inline void input_sync(struct input_dev *dev)
{
    input_event(dev, EV_SYN, SYN_REPORT, 0);
}

就是在这里发送同步信号的
 

到此学习就结束了,希望我这小小的学习经验能帮上大家 = 3=)/


文章来源CU社区:LINUX下USB1.1设备学习小记(6)_hid与input子系统(3)

0
0
戳我,来吐槽~