赞
踩
HID是Human Interface Devices的缩写,翻译成中文即为人机交互设备。这里的人机交互设备是一个宏观上面的概念,任何设备只要符合HID spec都可以称之为HID设备,常见的HID设备有鼠标键盘,游戏操纵杆等等。
usb鼠标在android代码中没有使用linux中常用的drivers/hid/usbhid/usbmouse.c驱动,而是使用了hid-generic驱动【注:从内核配置可知,内核选项配置了CONFIG_HID,CONFIG_USB_HID,CONFIG_HID_GENERIC,但是没有配置CONFIG_USB_KBD,CONFIG_USB_MOUSE选项】。
注意有两个hid-core.c文件,分别为hid/hid-core.c和hid/usbhid/hid-core.c文件。前者注册hid总线,后者注册hid device。
在内核启动时,注册了hid总线驱动,在drivers/hid/hid-core.c中注册了一个名为hid_bus_type的hid总线。
- static int __init hid_init(void)
- {
- int ret;
- ret = bus_register(&hid_bus_type);//---->
- ret = hidraw_init();
- hid_debug_init();
- return 0;
- }
-
- static struct bus_type hid_bus_type = {
- .name = "hid",
- .dev_groups = hid_dev_groups,
- .drv_groups = hid_drv_groups,
- .match = hid_bus_match,
- .probe = hid_device_probe,
- .remove = hid_device_remove,
- .uevent = hid_uevent,
- };
在hid-generic.c中定义了module_hid_driver(hid_generic),这个宏实际上是调用__hid_register_driver(drivers/hid/)接口注册一个hid_driver,并把它挂接在hid_bus_type总线驱动链表上。
- static const struct hid_device_id hid_table[] = {
- { HID_DEVICE(HID_BUS_ANY, HID_GROUP_GENERIC, HID_ANY_ID, HID_ANY_ID) },
- { }
- };
- static struct hid_driver hid_generic = {
- .name = "hid-generic",
- .id_table = hid_table,
- };
- module_hid_driver(hid_generic);
- //usb鼠标将和hid_generic匹配
在drivers/hid/usbhid/hid-core.c中定义了hid_driver,它是个usb_driver,并且调用usb_register_driver接口注册到了usb总线(usb_bus_type)上。
- static int __init hid_init(void)
- {
- int retval = -ENOMEM;
- retval = usbhid_quirks_init(quirks_param);
- retval = usb_register(&hid_driver); //---->
- return 0;
- }
-
- static struct usb_driver hid_driver = {
- .name = "usbhid",
- .probe = usbhid_probe,
- .disconnect = usbhid_disconnect,
- #ifdef CONFIG_PM
- .suspend = hid_suspend,
- .resume = hid_resume,
- .reset_resume = hid_reset_resume,
- #endif
- .pre_reset = hid_pre_reset,
- .post_reset = hid_post_reset,
- .id_table = hid_usb_ids,
- .supports_autosuspend = 1,
- };
-
- static const struct usb_device_id hid_usb_ids[] = {
- { .match_flags = USB_DEVICE_ID_MATCH_INT_CLASS,
- .bInterfaceClass = USB_INTERFACE_CLASS_HID },//所有ClassID为USB_INTERFACE_CLASS_HID的设备都会被这个驱动所匹配.所以,所有USB HID设备都会由这个module来驱动。
- { } /* Terminating entry */
- };
当hid设备插入usb口以后会调用usb_driver的probe函数,这一点由《USB驱动》可知。
- static int usbhid_probe(struct usb_interface *intf, const struct usb_device_id *id)
- {
- struct usb_host_interface *interface = intf->cur_altsetting;
- struct usb_device *dev = interface_to_usbdev(intf);
- struct usbhid_device *usbhid;
- struct hid_device *hid;
- unsigned int n, has_in = 0;
- size_t len;
- int ret;
-
- dbg_hid("HID probe called for ifnum %d\n",
- intf->altsetting->desc.bInterfaceNumber);
-
- for (n = 0; n < interface->desc.bNumEndpoints; n++)
- if (usb_endpoint_is_int_in(&interface->endpoint[n].desc))
- has_in++;
- if (!has_in) {
- hid_err(intf, "couldn't find an input interrupt endpoint\n");
- return -ENODEV;
- }
-
- //分配一个struct hid_device设备
- hid = hid_allocate_device();
-
- //把这个接口和hid设备关联
- usb_set_intfdata(intf, hid);
- //安装hid底层驱动,其实是个回调usb hid的回调驱动函数集,具体硬件操作依靠它来实现,hid core层(而不是usb hid core层)回调它。
- hid->ll_driver = &usb_hid_driver;
- hid->ff_init = hid_pidff_init;
- #ifdef CONFIG_USB_HIDDEV
- hid->hiddev_connect = hiddev_connect;
- hid->hiddev_disconnect = hiddev_disconnect;
- hid->hiddev_hid_event = hiddev_hid_event;
- hid->hiddev_report_event = hiddev_report_event;
- #endif
- hid->dev.parent = &intf->dev;
- hid->bus = BUS_USB;
- hid->vendor = le16_to_cpu(dev->descriptor.idVendor);
- hid->product = le16_to_cpu(dev->descriptor.idProduct);
- hid->name[0] = 0;
- hid->quirks = usbhid_lookup_quirk(hid->vendor, hid->product);
- if (intf->cur_altsetting->desc.bInterfaceProtocol ==
- USB_INTERFACE_PROTOCOL_MOUSE)
- hid->type = HID_TYPE_USBMOUSE;
- else if (intf->cur_altsetting->desc.bInterfaceProtocol == 0)
- hid->type = HID_TYPE_USBNONE;
-
- if (dev->manufacturer)
- strlcpy(hid->name, dev->manufacturer, sizeof(hid->name));
-
- if (dev->product) {
- if (dev->manufacturer)
- strlcat(hid->name, " ", sizeof(hid->name));
- strlcat(hid->name, dev->product, sizeof(hid->name));
- }
-
- if (!strlen(hid->name))
- snprintf(hid->name, sizeof(hid->name), "HID %04x:%04x",
- le16_to_cpu(dev->descriptor.idVendor),
- le16_to_cpu(dev->descriptor.idProduct));
-
- usb_make_path(dev, hid->phys, sizeof(hid->phys));
- strlcat(hid->phys, "/input", sizeof(hid->phys));
- len = strlen(hid->phys);
- if (len < sizeof(hid->phys) - 1)
- snprintf(hid->phys + len, sizeof(hid->phys) - len,
- "%d", intf->altsetting[0].desc.bInterfaceNumber);
-
- if (usb_string(dev, dev->descriptor.iSerialNumber, hid->uniq, 64) <= 0)
- hid->uniq[0] = 0;
-
- //分配一个usbhid设备,同时也是一个hid_device,继承hid_device
- usbhid = kzalloc(sizeof(*usbhid), GFP_KERNEL);
-
- hid->driver_data = usbhid;
- usbhid->hid = hid;
- usbhid->intf = intf;
- usbhid->ifnum = interface->desc.bInterfaceNumber;
-
- init_waitqueue_head(&usbhid->wait);
- INIT_WORK(&usbhid->reset_work, hid_reset);
- setup_timer(&usbhid->io_retry, hid_retry_timeout, (unsigned long) hid);
- spin_lock_init(&usbhid->lock);
-
- //向hid核心层添加一个hid_device设备,同时也会获取HID report报告描述符
- ret = hid_add_device(hid);
- return 0;
- err_free:
- kfree(usbhid);
- err:
- hid_destroy_device(hid);
- return ret;
- }
-
- int hid_add_device(struct hid_device *hdev)
- {
- static atomic_t id = ATOMIC_INIT(0);
- int ret;
-
- if (WARN_ON(hdev->status & HID_STAT_ADDED))
- return -EBUSY;
-
- /* we need to kill them here, otherwise they will stay allocated to
- * wait for coming driver */
- if (hid_ignore(hdev))
- return -ENODEV;
-
- /*
- * Check for the mandatory transport channel.
- */
- if (!hdev->ll_driver->raw_request) {
- hid_err(hdev, "transport driver missing .raw_request()\n");
- return -EINVAL;
- }
-
- /*
- * Read the device report descriptor once and use as template
- * for the driver-specific modifications.
- */
- ret = hdev->ll_driver->parse(hdev);
- if (ret)
- return ret;
- if (!hdev->dev_rdesc)
- return -ENODEV;
-
- /*
- * Scan generic devices for group information
- */
- if (hid_ignore_special_drivers) {
- hdev->group = HID_GROUP_GENERIC;
- } else if (!hdev->group &&
- !hid_match_id(hdev, hid_have_special_driver)) {
- ret = hid_scan_report(hdev);
- if (ret)
- hid_warn(hdev, "bad device descriptor (%d)\n", ret);
- }
-
- /* XXX hack, any other cleaner solution after the driver core
- * is converted to allow more than 20 bytes as the device name? */
- dev_set_name(&hdev->dev, "%04X:%04X:%04X.%04X", hdev->bus,
- hdev->vendor, hdev->product, atomic_inc_return(&id));
-
- hid_debug_register(hdev, dev_name(&hdev->dev));
- //这里会调用hid_bus的hid_device_probe函数
- ret = device_add(&hdev->dev);
- if (!ret)
- hdev->status |= HID_STAT_ADDED;
- else
- hid_debug_unregister(hdev);
-
- return ret;
- }
-
- static int hid_device_probe(struct device *dev)
- {
- struct hid_driver *hdrv = to_hid_driver(dev->driver);
- struct hid_device *hdev = to_hid_device(dev);
- const struct hid_device_id *id;
- int ret = 0;
-
- if (down_interruptible(&hdev->driver_input_lock)) {
- ret = -EINTR;
- goto end;
- }
- hdev->io_started = false;
-
- //第1次添加hid_device时,一定是为空
- if (!hdev->driver) {
- //在注册hid_device时就会调用hid_bus_type总线的match函数,这里再调用一次
- id = hid_match_device(hdev, hdrv);
- if (id == NULL) {
- ret = -ENODEV;
- goto unlock;
- }
-
- hdev->driver = hdrv;
- //hid_generic驱动没有probe函数
- if (hdrv->probe) {
- ret = hdrv->probe(hdev, id);
- } else { /* default probe 会调用这个函数,这里会对hid_add_device函数中获取到的HID report描述符进行解析*/
- ret = hid_open_report(hdev);
- if (!ret)
- //调用hid_ll_driver相关接口
- ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); //---->
- }
- if (ret) {
- hid_close_report(hdev);
- hdev->driver = NULL;
- }
- }
- unlock:
- if (!hdev->io_started)
- up(&hdev->driver_input_lock);
- end:
-
- return ret;
- }
- int hid_hw_start(struct hid_device *hdev, unsigned int connect_mask)
- {
- int error;
-
- error = hdev->ll_driver->start(hdev); //启动设备,
- if (error)
- return error;
-
- if (connect_mask) {
- error = hid_connect(hdev, connect_mask); //将设备与HID框架关联起来---->
- if (error) {
- hdev->ll_driver->stop(hdev);
- return error;
- }
- }
-
- return 0;
- }
-
- int hid_connect(struct hid_device *hdev, unsigned int connect_mask)
- {
- static const char *types[] = { "Device", "Pointer", "Mouse", "Device",
- "Joystick", "Gamepad", "Keyboard", "Keypad",
- "Multi-Axis Controller"
- };
- const char *type, *bus;
- char buf[64] = "";
- unsigned int i;
- int len;
- int ret;
-
- if (hdev->quirks & HID_QUIRK_HIDDEV_FORCE)
- connect_mask |= (HID_CONNECT_HIDDEV_FORCE | HID_CONNECT_HIDDEV);
- if (hdev->quirks & HID_QUIRK_HIDINPUT_FORCE)
- connect_mask |= HID_CONNECT_HIDINPUT_FORCE;
- if (hdev->bus != BUS_USB) //如果不是USB总线,那么去掉HID_CONNECT_HIDDEV标记
- connect_mask &= ~HID_CONNECT_HIDDEV;
- if (hid_hiddev(hdev)) //匹配某些特定vendorID和productID
- connect_mask |= HID_CONNECT_HIDDEV_FORCE;
-
- if ((connect_mask & HID_CONNECT_HIDINPUT) && !hidinput_connect(hdev, //input设备--->
- connect_mask & HID_CONNECT_HIDINPUT_FORCE))
- hdev->claimed |= HID_CLAIMED_INPUT;
-
- if ((connect_mask & HID_CONNECT_HIDDEV) && hdev->hiddev_connect &&
- !hdev->hiddev_connect(hdev, //hiddev设备
- connect_mask & HID_CONNECT_HIDDEV_FORCE))
- hdev->claimed |= HID_CLAIMED_HIDDEV;
- if ((connect_mask & HID_CONNECT_HIDRAW) && !hidraw_connect(hdev)) //hidraw设备
- hdev->claimed |= HID_CLAIMED_HIDRAW;
-
- if (connect_mask & HID_CONNECT_DRIVER)
- hdev->claimed |= HID_CLAIMED_DRIVER;
-
- /* Drivers with the ->raw_event callback set are not required to connect
- * to any other listener. */
- if (!hdev->claimed && !hdev->driver->raw_event) {
- hid_err(hdev, "device has no listeners, quitting\n");
- return -ENODEV;
- }
-
- if ((hdev->claimed & HID_CLAIMED_INPUT) &&
- (connect_mask & HID_CONNECT_FF) && hdev->ff_init)
- hdev->ff_init(hdev);
-
- len = 0;
- if (hdev->claimed & HID_CLAIMED_INPUT)
- len += sprintf(buf + len, "input");
- if (hdev->claimed & HID_CLAIMED_HIDDEV)
- len += sprintf(buf + len, "%shiddev%d", len ? "," : "",
- ((struct hiddev *)hdev->hiddev)->minor);
- if (hdev->claimed & HID_CLAIMED_HIDRAW)
- len += sprintf(buf + len, "%shidraw%d", len ? "," : "",
- ((struct hidraw *)hdev->hidraw)->minor);
-
- type = "Device";
- for (i = 0; i < hdev->maxcollection; i++) {
- struct hid_collection *col = &hdev->collection[i];
- if (col->type == HID_COLLECTION_APPLICATION &&
- (col->usage & HID_USAGE_PAGE) == HID_UP_GENDESK &&
- (col->usage & 0xffff) < ARRAY_SIZE(types)) {
- type = types[col->usage & 0xffff];
- break;
- }
- }
-
- switch (hdev->bus) {
- case BUS_USB:
- bus = "USB";
- break;
- case BUS_BLUETOOTH:
- bus = "BLUETOOTH";
- break;
- case BUS_I2C:
- bus = "I2C";
- break;
- default:
- bus = "<UNKNOWN>";
- }
-
- ret = device_create_file(&hdev->dev, &dev_attr_country);
- if (ret)
- hid_warn(hdev,
- "can't create sysfs country code attribute err: %d\n", ret);
-
- hid_info(hdev, "%s: %s HID v%x.%02x %s [%s] on %s\n",
- buf, bus, hdev->version >> 8, hdev->version & 0xff,
- type, hdev->name, hdev->phys);
-
- return 0;
- }
HID中最常用的是input设备,使用hidinput_connect登记到系统。hidinput_connect的主要作用是对hiddev中的每一个report,都建立一个input_dev设备,并登记到input框架中。
- int hidinput_connect(struct hid_device *hid, unsigned int force)
- {
- struct hid_driver *drv = hid->driver;
- struct hid_report *report;
- struct hid_input *next, *hidinput = NULL;
- int i, k;
-
- INIT_LIST_HEAD(&hid->inputs);
- INIT_WORK(&hid->led_work, hidinput_led_worker);
-
- if (!force) {
- for (i = 0; i < hid->maxcollection; i++) {
- struct hid_collection *col = &hid->collection[i];
- if (col->type == HID_COLLECTION_APPLICATION ||
- col->type == HID_COLLECTION_PHYSICAL)
- if (IS_INPUT_APPLICATION(col->usage))
- break;
- }
-
- if (i == hid->maxcollection)
- return -1;
- }
-
- report_features(hid);
-
- //对每一个report,建立一个input设备
- for (k = HID_INPUT_REPORT; k <= HID_OUTPUT_REPORT; k++) {
- if (k == HID_OUTPUT_REPORT &&
- hid->quirks & HID_QUIRK_SKIP_OUTPUT_REPORTS)
- continue;
-
- list_for_each_entry(report, &hid->report_enum[k].report_list, list) {
-
- if (!report->maxfield)
- continue;
-
- /*
- * Find the previous hidinput report attached
- * to this report id.
- */
- if (hid->quirks & HID_QUIRK_MULTI_INPUT)
- hidinput = hidinput_match(report);
-
- if (!hidinput) {
- hidinput = hidinput_allocate(hid);
- if (!hidinput)
- goto out_unwind;
- }
-
- hidinput_configure_usages(hidinput, report); //---->
-
- if (hid->quirks & HID_QUIRK_MULTI_INPUT)
- hidinput->report = report;
- }
- }
-
- list_for_each_entry_safe(hidinput, next, &hid->inputs, list) {
- if ((hid->quirks & HID_QUIRK_NO_EMPTY_INPUT) &&
- !hidinput_has_been_populated(hidinput)) {
- /* no need to register an input device not populated */
- hidinput_cleanup_hidinput(hid, hidinput);
- continue;
- }
-
- if (drv->input_configured &&
- drv->input_configured(hid, hidinput))
- goto out_unwind;
- if (input_register_device(hidinput->input)) //将设备注册到Input子系统
- goto out_unwind;
- hidinput->registered = true;
- }
-
- if (list_empty(&hid->inputs)) {
- hid_err(hid, "No inputs registered, leaving\n");
- goto out_unwind;
- }
-
- return 0;
-
- out_unwind:
- /* unwind the ones we already registered */
- hidinput_disconnect(hid);
-
- return -1;
- }
hidinput是一个将hid数据转为input格式的协议转换者,转换完毕之后,将数据发送给hidinput->input 这个真正的连接到mousedev_handler驱动上input_dev设备, 这样当hid设备上传数据,引发irq中断
drivers/hid/usbhid/hid-core.c
- //hid->ll_driver = &usb_hid_driver
- struct hid_ll_driver usb_hid_driver = {
- .parse = usbhid_parse,
- .start = usbhid_start,
- .stop = usbhid_stop,
- .open = usbhid_open,
- .close = usbhid_close,
- .power = usbhid_power,
- .request = usbhid_request,
- .wait = usbhid_wait_io,
- .raw_request = usbhid_raw_request,
- .output_report = usbhid_output_report,
- .idle = usbhid_idle,
- };
- //启动HID设备
- static int usbhid_start(struct hid_device *hid)
- {
- struct usb_interface *intf = to_usb_interface(hid->dev.parent);
- struct usb_host_interface *interface = intf->cur_altsetting;
- struct usb_device *dev = interface_to_usbdev(intf);
- struct usbhid_device *usbhid = hid->driver_data;
- unsigned int n, insize = 0;
- int ret;
-
- clear_bit(HID_DISCONNECTED, &usbhid->iofl);
-
- usbhid->bufsize = HID_MIN_BUFFER_SIZE;
- hid_find_max_report(hid, HID_INPUT_REPORT, &usbhid->bufsize);
- hid_find_max_report(hid, HID_OUTPUT_REPORT, &usbhid->bufsize);
- hid_find_max_report(hid, HID_FEATURE_REPORT, &usbhid->bufsize);
-
- if (usbhid->bufsize > HID_MAX_BUFFER_SIZE)
- usbhid->bufsize = HID_MAX_BUFFER_SIZE;
-
- hid_find_max_report(hid, HID_INPUT_REPORT, &insize);
-
- if (insize > HID_MAX_BUFFER_SIZE)
- insize = HID_MAX_BUFFER_SIZE;
-
- if (hid_alloc_buffers(dev, hid)) {
- ret = -ENOMEM;
- goto fail;
- }
-
- for (n = 0; n < interface->desc.bNumEndpoints; n++) {
- struct usb_endpoint_descriptor *endpoint;
- int pipe;
- int interval;
-
- endpoint = &interface->endpoint[n].desc;
- if (!usb_endpoint_xfer_int(endpoint))
- continue;
-
- interval = endpoint->bInterval;
-
- /* Some vendors give fullspeed interval on highspeed devides */
- if (hid->quirks & HID_QUIRK_FULLSPEED_INTERVAL &&
- dev->speed == USB_SPEED_HIGH) {
- interval = fls(endpoint->bInterval*8);
- pr_info("%s: Fixing fullspeed to highspeed interval: %d -> %d\n",
- hid->name, endpoint->bInterval, interval);
- }
-
- /* Change the polling interval of mice and joysticks. */
- switch (hid->collection->usage) {
- case HID_GD_MOUSE:
- if (hid_mousepoll_interval > 0)
- interval = hid_mousepoll_interval;
- break;
- case HID_GD_JOYSTICK:
- if (hid_jspoll_interval > 0)
- interval = hid_jspoll_interval;
- break;
- }
-
- ret = -ENOMEM;
- if (usb_endpoint_dir_in(endpoint)) {
- if (usbhid->urbin)
- continue;
- if (!(usbhid->urbin = usb_alloc_urb(0, GFP_KERNEL)))
- goto fail;
- pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);
- usb_fill_int_urb(usbhid->urbin, dev, pipe, usbhid->inbuf, insize,
- hid_irq_in, hid, interval); //中断函数hid_irq_in
- usbhid->urbin->transfer_dma = usbhid->inbuf_dma;
- usbhid->urbin->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
- } else {
- if (usbhid->urbout)
- continue;
- if (!(usbhid->urbout = usb_alloc_urb(0, GFP_KERNEL)))
- goto fail;
- pipe = usb_sndintpipe(dev, endpoint->bEndpointAddress);
- usb_fill_int_urb(usbhid->urbout, dev, pipe, usbhid->outbuf, 0,
- hid_irq_out, hid, interval);
- usbhid->urbout->transfer_dma = usbhid->outbuf_dma;
- usbhid->urbout->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
- }
- }
-
- usbhid->urbctrl = usb_alloc_urb(0, GFP_KERNEL);
- if (!usbhid->urbctrl) {
- ret = -ENOMEM;
- goto fail;
- }
-
- usb_fill_control_urb(usbhid->urbctrl, dev, 0, (void *) usbhid->cr,
- usbhid->ctrlbuf, 1, hid_ctrl, hid);
- usbhid->urbctrl->transfer_dma = usbhid->ctrlbuf_dma;
- usbhid->urbctrl->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
-
- set_bit(HID_STARTED, &usbhid->iofl);
-
- if (hid->quirks & HID_QUIRK_ALWAYS_POLL) {
- ret = usb_autopm_get_interface(usbhid->intf);
- if (ret)
- goto fail;
- set_bit(HID_IN_POLLING, &usbhid->iofl);
- usbhid->intf->needs_remote_wakeup = 1;
- ret = hid_start_in(hid);
- if (ret) {
- dev_err(&hid->dev,
- "failed to start in urb: %d\n", ret);
- }
- usb_autopm_put_interface(usbhid->intf);
- }
-
- /* Some keyboards don't work until their LEDs have been set.
- * Since BIOSes do set the LEDs, it must be safe for any device
- * that supports the keyboard boot protocol.
- * In addition, enable remote wakeup by default for all keyboard
- * devices supporting the boot protocol.
- */
- if (interface->desc.bInterfaceSubClass == USB_INTERFACE_SUBCLASS_BOOT &&
- interface->desc.bInterfaceProtocol ==
- USB_INTERFACE_PROTOCOL_KEYBOARD) {
- usbhid_set_leds(hid);
- device_set_wakeup_enable(&dev->dev, 1);
- }
- return 0;
-
- fail:
- usb_free_urb(usbhid->urbin);
- usb_free_urb(usbhid->urbout);
- usb_free_urb(usbhid->urbctrl);
- usbhid->urbin = NULL;
- usbhid->urbout = NULL;
- usbhid->urbctrl = NULL;
- hid_free_buffers(dev, hid);
- return ret;
- }
-
- /*
- * Input interrupt completion handler.
- */
- 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;
- if (!test_bit(HID_OPENED, &usbhid->iofl))
- break;
- usbhid_mark_busy(usbhid);
- if (!test_bit(HID_RESUME_RUNNING, &usbhid->iofl)) {
- //hid_input_report--->
- hid_input_report(urb->context, HID_INPUT_REPORT,
- urb->transfer_buffer,
- urb->actual_length, 1);
- /*
- * autosuspend refused while keys are pressed
- * because most keyboards don't wake up when
- * a key is released
- */
- if (hid_check_keys_pressed(hid))
- set_bit(HID_KEYS_PRESSED, &usbhid->iofl);
- else
- clear_bit(HID_KEYS_PRESSED, &usbhid->iofl);
- }
- break;
- case -EPIPE: /* stall */
- usbhid_mark_busy(usbhid);
- 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... */
- usbhid_mark_busy(usbhid);
- clear_bit(HID_IN_RUNNING, &usbhid->iofl);
- hid_io_error(hid);
- return;
- default: /* error */
- hid_warn(urb->dev, "input irq status %d received\n",
- urb->status);
- }
-
- status = usb_submit_urb(urb, GFP_ATOMIC);
- if (status) {
- clear_bit(HID_IN_RUNNING, &usbhid->iofl);
- if (status != -EPERM) {
- hid_err(hid, "can't resubmit intr, %s-%s/input%d, status %d\n",
- hid_to_usb_dev(hid)->bus->bus_name,
- hid_to_usb_dev(hid)->devpath,
- usbhid->ifnum, status);
- hid_io_error(hid);
- }
- }
- }
-
- int hid_input_report(struct hid_device *hid, int type, u8 *data, u32 size, int interrupt)
- {
- struct hid_report_enum *report_enum;
- struct hid_driver *hdrv;
- struct hid_report *report;
- int ret = 0;
-
- if (!hid)
- return -ENODEV;
-
- if (down_trylock(&hid->driver_input_lock))
- return -EBUSY;
-
- if (!hid->driver) {
- ret = -ENODEV;
- goto unlock;
- }
- report_enum = hid->report_enum + type;
- hdrv = hid->driver;
-
- if (!size) {
- dbg_hid("empty report\n");
- ret = -1;
- goto unlock;
- }
-
- /* Avoid unnecessary overhead if debugfs is disabled */
- if (!list_empty(&hid->debug_list))
- hid_dump_report(hid, type, data, size);
-
- report = hid_get_report(report_enum, data);
-
- if (!report) {
- ret = -1;
- goto unlock;
- }
-
- if (hdrv && hdrv->raw_event && hid_match_report(hid, report)) {
- ret = hdrv->raw_event(hid, report, data, size);
- if (ret < 0)
- goto unlock;
- }
-
- ret = hid_report_raw_event(hid, type, data, size, interrupt);//--->
-
- unlock:
- up(&hid->driver_input_lock);
- return ret;
- }
-
- int hid_report_raw_event(struct hid_device *hid, int type, u8 *data, u32 size,
- int interrupt)
- {
- struct hid_report_enum *report_enum = hid->report_enum + type;
- struct hid_report *report;
- struct hid_driver *hdrv;
- unsigned int a;
- u32 rsize, csize = size;
- u8 *cdata = data;
- int ret = 0;
-
- report = hid_get_report(report_enum, data);
- if (!report)
- goto out;
-
- if (report_enum->numbered) {
- cdata++;
- csize--;
- }
-
- rsize = ((report->size - 1) >> 3) + 1;
-
- if (rsize > HID_MAX_BUFFER_SIZE)
- rsize = HID_MAX_BUFFER_SIZE;
-
- if (csize < rsize) {
- dbg_hid("report %d is too short, (%d < %d)\n", report->id,
- csize, rsize);
- memset(cdata + csize, 0, rsize - csize);
- }
-
- if ((hid->claimed & HID_CLAIMED_HIDDEV) && hid->hiddev_report_event)
- hid->hiddev_report_event(hid, report);
- if (hid->claimed & HID_CLAIMED_HIDRAW) {
- ret = hidraw_report_event(hid, data, size);
- if (ret)
- goto out;
- }
-
- if (hid->claimed != HID_CLAIMED_HIDRAW && report->maxfield) {
- for (a = 0; a < report->maxfield; a++)
- hid_input_field(hid, report->field[a], cdata, interrupt);
- hdrv = hid->driver;
- if (hdrv && hdrv->report)
- hdrv->report(hid, report);
- }
-
- if (hid->claimed & HID_CLAIMED_INPUT)
- hidinput_report_event(hid, report); //--->
- out:
- return ret;
- }
-
- void hidinput_report_event(struct hid_device *hid, struct hid_report *report)
- {
- struct hid_input *hidinput;
-
- if (hid->quirks & HID_QUIRK_NO_INPUT_SYNC)
- return;
-
- list_for_each_entry(hidinput, &hid->inputs, list)
- input_sync(hidinput->input); //上报数据至input-core层
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。