|
@@ -701,17 +701,84 @@ static void hid_fixup_sony_ps3_controller(struct usb_device *dev, int ifnum)
|
|
|
kfree(buf);
|
|
|
}
|
|
|
|
|
|
-static struct hid_device *usb_hid_configure(struct usb_interface *intf)
|
|
|
+static int usbhid_start_finish(struct hid_device *hid)
|
|
|
{
|
|
|
+ struct usb_interface *intf = to_usb_interface(hid->dev.parent);
|
|
|
+ char path[64], *type;
|
|
|
+ unsigned int i;
|
|
|
+
|
|
|
+ usbhid_init_reports(hid);
|
|
|
+ hid_dump_device(hid);
|
|
|
+ if (hid->quirks & HID_QUIRK_RESET_LEDS)
|
|
|
+ usbhid_set_leds(hid);
|
|
|
+
|
|
|
+ if (!hidinput_connect(hid))
|
|
|
+ hid->claimed |= HID_CLAIMED_INPUT;
|
|
|
+ if (!hiddev_connect(hid))
|
|
|
+ hid->claimed |= HID_CLAIMED_HIDDEV;
|
|
|
+ if (!hidraw_connect(hid))
|
|
|
+ hid->claimed |= HID_CLAIMED_HIDRAW;
|
|
|
+
|
|
|
+ if (!hid->claimed) {
|
|
|
+ printk(KERN_ERR "HID device claimed by neither input, hiddev "
|
|
|
+ "nor hidraw\n");
|
|
|
+ return -ENODEV;
|
|
|
+ }
|
|
|
+
|
|
|
+ if ((hid->claimed & HID_CLAIMED_INPUT))
|
|
|
+ hid_ff_init(hid);
|
|
|
+
|
|
|
+ if (hid->quirks & HID_QUIRK_SONY_PS3_CONTROLLER)
|
|
|
+ hid_fixup_sony_ps3_controller(interface_to_usbdev(intf),
|
|
|
+ intf->cur_altsetting->desc.bInterfaceNumber);
|
|
|
+
|
|
|
+ printk(KERN_INFO);
|
|
|
+
|
|
|
+ if (hid->claimed & HID_CLAIMED_INPUT)
|
|
|
+ printk("input");
|
|
|
+ if ((hid->claimed & HID_CLAIMED_INPUT) &&
|
|
|
+ ((hid->claimed & HID_CLAIMED_HIDDEV) ||
|
|
|
+ hid->claimed & HID_CLAIMED_HIDRAW))
|
|
|
+ printk(",");
|
|
|
+ if (hid->claimed & HID_CLAIMED_HIDDEV)
|
|
|
+ printk("hiddev%d", hid->minor);
|
|
|
+ if ((hid->claimed & HID_CLAIMED_INPUT) &&
|
|
|
+ (hid->claimed & HID_CLAIMED_HIDDEV) &&
|
|
|
+ (hid->claimed & HID_CLAIMED_HIDRAW))
|
|
|
+ printk(",");
|
|
|
+ if (hid->claimed & HID_CLAIMED_HIDRAW)
|
|
|
+ printk("hidraw%d", ((struct hidraw *)hid->hidraw)->minor);
|
|
|
+
|
|
|
+ type = "Device";
|
|
|
+ for (i = 0; i < hid->maxcollection; i++) {
|
|
|
+ if (hid->collection[i].type == HID_COLLECTION_APPLICATION &&
|
|
|
+ (hid->collection[i].usage & HID_USAGE_PAGE) ==
|
|
|
+ HID_UP_GENDESK &&
|
|
|
+ (hid->collection[i].usage & 0xffff) <
|
|
|
+ ARRAY_SIZE(hid_types)) {
|
|
|
+ type = hid_types[hid->collection[i].usage & 0xffff];
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ usb_make_path(interface_to_usbdev(intf), path, 63);
|
|
|
+
|
|
|
+ printk(": USB HID v%x.%02x %s [%s] on %s\n",
|
|
|
+ hid->version >> 8, hid->version & 0xff, type, hid->name, path);
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static int usbhid_parse(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 hid_descriptor *hdesc;
|
|
|
- struct hid_device *hid;
|
|
|
u32 quirks = 0;
|
|
|
- unsigned int insize = 0, rsize = 0;
|
|
|
+ unsigned int rsize = 0;
|
|
|
char *rdesc;
|
|
|
- int n, len;
|
|
|
- struct usbhid_device *usbhid;
|
|
|
+ int ret, n;
|
|
|
|
|
|
quirks = usbhid_lookup_quirk(le16_to_cpu(dev->descriptor.idVendor),
|
|
|
le16_to_cpu(dev->descriptor.idProduct));
|
|
@@ -725,40 +792,44 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf)
|
|
|
}
|
|
|
|
|
|
if (quirks & HID_QUIRK_IGNORE)
|
|
|
- return NULL;
|
|
|
+ return -ENODEV;
|
|
|
|
|
|
if ((quirks & HID_QUIRK_IGNORE_MOUSE) &&
|
|
|
(interface->desc.bInterfaceProtocol == USB_INTERFACE_PROTOCOL_MOUSE))
|
|
|
- return NULL;
|
|
|
-
|
|
|
+ return -ENODEV;
|
|
|
|
|
|
if (usb_get_extra_descriptor(interface, HID_DT_HID, &hdesc) &&
|
|
|
(!interface->desc.bNumEndpoints ||
|
|
|
usb_get_extra_descriptor(&interface->endpoint[0], HID_DT_HID, &hdesc))) {
|
|
|
dbg_hid("class descriptor not present\n");
|
|
|
- return NULL;
|
|
|
+ return -ENODEV;
|
|
|
}
|
|
|
|
|
|
+ hid->version = le16_to_cpu(hdesc->bcdHID);
|
|
|
+ hid->country = hdesc->bCountryCode;
|
|
|
+
|
|
|
for (n = 0; n < hdesc->bNumDescriptors; n++)
|
|
|
if (hdesc->desc[n].bDescriptorType == HID_DT_REPORT)
|
|
|
rsize = le16_to_cpu(hdesc->desc[n].wDescriptorLength);
|
|
|
|
|
|
if (!rsize || rsize > HID_MAX_DESCRIPTOR_SIZE) {
|
|
|
dbg_hid("weird size of report descriptor (%u)\n", rsize);
|
|
|
- return NULL;
|
|
|
+ return -EINVAL;
|
|
|
}
|
|
|
|
|
|
if (!(rdesc = kmalloc(rsize, GFP_KERNEL))) {
|
|
|
dbg_hid("couldn't allocate rdesc memory\n");
|
|
|
- return NULL;
|
|
|
+ return -ENOMEM;
|
|
|
}
|
|
|
|
|
|
hid_set_idle(dev, interface->desc.bInterfaceNumber, 0, 0);
|
|
|
|
|
|
- if ((n = hid_get_class_descriptor(dev, interface->desc.bInterfaceNumber, HID_DT_REPORT, rdesc, rsize)) < 0) {
|
|
|
+ ret = hid_get_class_descriptor(dev, interface->desc.bInterfaceNumber,
|
|
|
+ HID_DT_REPORT, rdesc, rsize);
|
|
|
+ if (ret < 0) {
|
|
|
dbg_hid("reading report descriptor failed\n");
|
|
|
kfree(rdesc);
|
|
|
- return NULL;
|
|
|
+ goto err;
|
|
|
}
|
|
|
|
|
|
usbhid_fixup_report_descriptor(le16_to_cpu(dev->descriptor.idVendor),
|
|
@@ -770,24 +841,36 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf)
|
|
|
dbg_hid_line(" %02x", (unsigned char) rdesc[n]);
|
|
|
dbg_hid_line("\n");
|
|
|
|
|
|
- hid = hid_allocate_device();
|
|
|
- if (IS_ERR(hid)) {
|
|
|
- kfree(rdesc);
|
|
|
- return NULL;
|
|
|
- }
|
|
|
-
|
|
|
- if (hid_parse_report(hid, rdesc, n)) {
|
|
|
+ ret = hid_parse_report(hid, rdesc, rsize);
|
|
|
+ kfree(rdesc);
|
|
|
+ if (ret) {
|
|
|
dbg_hid("parsing report descriptor failed\n");
|
|
|
- hid_destroy_device(hid);
|
|
|
- kfree(rdesc);
|
|
|
- return NULL;
|
|
|
+ goto err;
|
|
|
}
|
|
|
|
|
|
- kfree(rdesc);
|
|
|
hid->quirks = quirks;
|
|
|
|
|
|
- if (!(usbhid = kzalloc(sizeof(struct usbhid_device), GFP_KERNEL)))
|
|
|
- goto fail_no_usbhid;
|
|
|
+ return 0;
|
|
|
+err:
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
+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;
|
|
|
+ unsigned int n, insize = 0;
|
|
|
+ int ret;
|
|
|
+
|
|
|
+ WARN_ON(hid->driver_data);
|
|
|
+
|
|
|
+ usbhid = kzalloc(sizeof(struct usbhid_device), GFP_KERNEL);
|
|
|
+ if (usbhid == NULL) {
|
|
|
+ ret = -ENOMEM;
|
|
|
+ goto err;
|
|
|
+ }
|
|
|
|
|
|
hid->driver_data = usbhid;
|
|
|
usbhid->hid = hid;
|
|
@@ -805,27 +888,12 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf)
|
|
|
if (insize > HID_MAX_BUFFER_SIZE)
|
|
|
insize = HID_MAX_BUFFER_SIZE;
|
|
|
|
|
|
- if (hid_alloc_buffers(dev, hid))
|
|
|
+ if (hid_alloc_buffers(dev, hid)) {
|
|
|
+ ret = -ENOMEM;
|
|
|
goto fail;
|
|
|
-
|
|
|
- hid->name[0] = 0;
|
|
|
-
|
|
|
- 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));
|
|
|
-
|
|
|
for (n = 0; n < interface->desc.bNumEndpoints; n++) {
|
|
|
-
|
|
|
struct usb_endpoint_descriptor *endpoint;
|
|
|
int pipe;
|
|
|
int interval;
|
|
@@ -837,7 +905,7 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf)
|
|
|
interval = endpoint->bInterval;
|
|
|
|
|
|
/* Some vendors give fullspeed interval on highspeed devides */
|
|
|
- if (quirks & HID_QUIRK_FULLSPEED_INTERVAL &&
|
|
|
+ if (hid->quirks & HID_QUIRK_FULLSPEED_INTERVAL &&
|
|
|
dev->speed == USB_SPEED_HIGH) {
|
|
|
interval = fls(endpoint->bInterval*8);
|
|
|
printk(KERN_INFO "%s: Fixing fullspeed to highspeed interval: %d -> %d\n",
|
|
@@ -848,6 +916,7 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf)
|
|
|
if (hid->collection->usage == HID_GD_MOUSE && hid_mousepoll_interval > 0)
|
|
|
interval = hid_mousepoll_interval;
|
|
|
|
|
|
+ ret = -ENOMEM;
|
|
|
if (usb_endpoint_dir_in(endpoint)) {
|
|
|
if (usbhid->urbin)
|
|
|
continue;
|
|
@@ -873,6 +942,7 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf)
|
|
|
|
|
|
if (!usbhid->urbin) {
|
|
|
err_hid("couldn't find an input interrupt endpoint");
|
|
|
+ ret = -ENODEV;
|
|
|
goto fail;
|
|
|
}
|
|
|
|
|
@@ -884,44 +954,26 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf)
|
|
|
spin_lock_init(&usbhid->outlock);
|
|
|
spin_lock_init(&usbhid->ctrllock);
|
|
|
|
|
|
- hid->version = le16_to_cpu(hdesc->bcdHID);
|
|
|
- hid->country = hdesc->bCountryCode;
|
|
|
- hid->dev.parent = &intf->dev;
|
|
|
usbhid->intf = intf;
|
|
|
usbhid->ifnum = interface->desc.bInterfaceNumber;
|
|
|
|
|
|
- hid->bus = BUS_USB;
|
|
|
- hid->vendor = le16_to_cpu(dev->descriptor.idVendor);
|
|
|
- hid->product = 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->urbctrl = usb_alloc_urb(0, GFP_KERNEL);
|
|
|
- if (!usbhid->urbctrl)
|
|
|
+ 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->setup_dma = usbhid->cr_dma;
|
|
|
usbhid->urbctrl->transfer_dma = usbhid->ctrlbuf_dma;
|
|
|
usbhid->urbctrl->transfer_flags |= (URB_NO_TRANSFER_DMA_MAP | URB_NO_SETUP_DMA_MAP);
|
|
|
- hid->hidinput_input_event = usb_hidinput_input_event;
|
|
|
- hid->hid_open = usbhid_open;
|
|
|
- hid->hid_close = usbhid_close;
|
|
|
-#ifdef CONFIG_USB_HIDDEV
|
|
|
- hid->hiddev_hid_event = hiddev_hid_event;
|
|
|
- hid->hiddev_report_event = hiddev_report_event;
|
|
|
-#endif
|
|
|
- hid->hid_output_raw_report = usbhid_output_raw_report;
|
|
|
- return hid;
|
|
|
+
|
|
|
+ ret = usbhid_start_finish(hid);
|
|
|
+ if (ret)
|
|
|
+ goto fail;
|
|
|
+
|
|
|
+ return 0;
|
|
|
|
|
|
fail:
|
|
|
usb_free_urb(usbhid->urbin);
|
|
@@ -929,24 +981,18 @@ fail:
|
|
|
usb_free_urb(usbhid->urbctrl);
|
|
|
hid_free_buffers(dev, hid);
|
|
|
kfree(usbhid);
|
|
|
-fail_no_usbhid:
|
|
|
- hid_destroy_device(hid);
|
|
|
-
|
|
|
- return NULL;
|
|
|
+err:
|
|
|
+ return ret;
|
|
|
}
|
|
|
|
|
|
-static void hid_disconnect(struct usb_interface *intf)
|
|
|
+static void usbhid_stop(struct hid_device *hid)
|
|
|
{
|
|
|
- struct hid_device *hid = usb_get_intfdata (intf);
|
|
|
- struct usbhid_device *usbhid;
|
|
|
+ struct usbhid_device *usbhid = hid->driver_data;
|
|
|
|
|
|
- if (!hid)
|
|
|
+ if (WARN_ON(!usbhid))
|
|
|
return;
|
|
|
|
|
|
- usbhid = hid->driver_data;
|
|
|
-
|
|
|
spin_lock_irq(&usbhid->inlock); /* Sync with error handler */
|
|
|
- usb_set_intfdata(intf, NULL);
|
|
|
set_bit(HID_DISCONNECTED, &usbhid->iofl);
|
|
|
spin_unlock_irq(&usbhid->inlock);
|
|
|
usb_kill_urb(usbhid->urbin);
|
|
@@ -963,93 +1009,99 @@ static void hid_disconnect(struct usb_interface *intf)
|
|
|
if (hid->claimed & HID_CLAIMED_HIDRAW)
|
|
|
hidraw_disconnect(hid);
|
|
|
|
|
|
+ hid->claimed = 0;
|
|
|
+
|
|
|
usb_free_urb(usbhid->urbin);
|
|
|
usb_free_urb(usbhid->urbctrl);
|
|
|
usb_free_urb(usbhid->urbout);
|
|
|
|
|
|
hid_free_buffers(hid_to_usb_dev(hid), hid);
|
|
|
kfree(usbhid);
|
|
|
- hid_destroy_device(hid);
|
|
|
+ hid->driver_data = NULL;
|
|
|
}
|
|
|
|
|
|
+static struct hid_ll_driver usb_hid_driver = {
|
|
|
+ .parse = usbhid_parse,
|
|
|
+ .start = usbhid_start,
|
|
|
+ .stop = usbhid_stop,
|
|
|
+ .open = usbhid_open,
|
|
|
+ .close = usbhid_close,
|
|
|
+ .hidinput_input_event = usb_hidinput_input_event,
|
|
|
+};
|
|
|
+
|
|
|
static int hid_probe(struct usb_interface *intf, const struct usb_device_id *id)
|
|
|
{
|
|
|
+ struct usb_device *dev = interface_to_usbdev(intf);
|
|
|
struct hid_device *hid;
|
|
|
- char path[64];
|
|
|
- int i, ret;
|
|
|
- char *c;
|
|
|
+ size_t len;
|
|
|
+ int ret;
|
|
|
|
|
|
dbg_hid("HID probe called for ifnum %d\n",
|
|
|
intf->altsetting->desc.bInterfaceNumber);
|
|
|
|
|
|
- if (!(hid = usb_hid_configure(intf)))
|
|
|
- return -ENODEV;
|
|
|
-
|
|
|
- usbhid_init_reports(hid);
|
|
|
- hid_dump_device(hid);
|
|
|
- if (hid->quirks & HID_QUIRK_RESET_LEDS)
|
|
|
- usbhid_set_leds(hid);
|
|
|
-
|
|
|
- if (!hidinput_connect(hid))
|
|
|
- hid->claimed |= HID_CLAIMED_INPUT;
|
|
|
- if (!hiddev_connect(hid))
|
|
|
- hid->claimed |= HID_CLAIMED_HIDDEV;
|
|
|
- if (!hidraw_connect(hid))
|
|
|
- hid->claimed |= HID_CLAIMED_HIDRAW;
|
|
|
+ hid = hid_allocate_device();
|
|
|
+ if (IS_ERR(hid))
|
|
|
+ return PTR_ERR(hid);
|
|
|
|
|
|
usb_set_intfdata(intf, hid);
|
|
|
+ hid->ll_driver = &usb_hid_driver;
|
|
|
+ hid->hid_output_raw_report = usbhid_output_raw_report;
|
|
|
+#ifdef CONFIG_USB_HIDDEV
|
|
|
+ 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;
|
|
|
|
|
|
- if (!hid->claimed) {
|
|
|
- printk ("HID device claimed by neither input, hiddev nor hidraw\n");
|
|
|
- hid_disconnect(intf);
|
|
|
- return -ENODEV;
|
|
|
- }
|
|
|
-
|
|
|
- if ((hid->claimed & HID_CLAIMED_INPUT))
|
|
|
- hid_ff_init(hid);
|
|
|
-
|
|
|
- if (hid->quirks & HID_QUIRK_SONY_PS3_CONTROLLER)
|
|
|
- hid_fixup_sony_ps3_controller(interface_to_usbdev(intf),
|
|
|
- intf->cur_altsetting->desc.bInterfaceNumber);
|
|
|
-
|
|
|
- printk(KERN_INFO);
|
|
|
-
|
|
|
- if (hid->claimed & HID_CLAIMED_INPUT)
|
|
|
- printk("input");
|
|
|
- if ((hid->claimed & HID_CLAIMED_INPUT) && ((hid->claimed & HID_CLAIMED_HIDDEV) ||
|
|
|
- hid->claimed & HID_CLAIMED_HIDRAW))
|
|
|
- printk(",");
|
|
|
- if (hid->claimed & HID_CLAIMED_HIDDEV)
|
|
|
- printk("hiddev%d", hid->minor);
|
|
|
- if ((hid->claimed & HID_CLAIMED_INPUT) && (hid->claimed & HID_CLAIMED_HIDDEV) &&
|
|
|
- (hid->claimed & HID_CLAIMED_HIDRAW))
|
|
|
- printk(",");
|
|
|
- if (hid->claimed & HID_CLAIMED_HIDRAW)
|
|
|
- printk("hidraw%d", ((struct hidraw*)hid->hidraw)->minor);
|
|
|
+ if (dev->manufacturer)
|
|
|
+ strlcpy(hid->name, dev->manufacturer, sizeof(hid->name));
|
|
|
|
|
|
- c = "Device";
|
|
|
- for (i = 0; i < hid->maxcollection; i++) {
|
|
|
- if (hid->collection[i].type == HID_COLLECTION_APPLICATION &&
|
|
|
- (hid->collection[i].usage & HID_USAGE_PAGE) == HID_UP_GENDESK &&
|
|
|
- (hid->collection[i].usage & 0xffff) < ARRAY_SIZE(hid_types)) {
|
|
|
- c = hid_types[hid->collection[i].usage & 0xffff];
|
|
|
- break;
|
|
|
- }
|
|
|
+ if (dev->product) {
|
|
|
+ if (dev->manufacturer)
|
|
|
+ strlcat(hid->name, " ", sizeof(hid->name));
|
|
|
+ strlcat(hid->name, dev->product, sizeof(hid->name));
|
|
|
}
|
|
|
|
|
|
- usb_make_path(interface_to_usbdev(intf), path, 63);
|
|
|
+ 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));
|
|
|
|
|
|
- printk(": USB HID v%x.%02x %s [%s] on %s\n",
|
|
|
- hid->version >> 8, hid->version & 0xff, c, hid->name, path);
|
|
|
+ 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;
|
|
|
|
|
|
ret = hid_add_device(hid);
|
|
|
if (ret) {
|
|
|
dev_err(&intf->dev, "can't add hid device: %d\n", ret);
|
|
|
- hid_disconnect(intf);
|
|
|
+ goto err;
|
|
|
}
|
|
|
+
|
|
|
+ return 0;
|
|
|
+err:
|
|
|
+ hid_destroy_device(hid);
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
+static void hid_disconnect(struct usb_interface *intf)
|
|
|
+{
|
|
|
+ struct hid_device *hid = usb_get_intfdata(intf);
|
|
|
+
|
|
|
+ if (WARN_ON(!hid))
|
|
|
+ return;
|
|
|
+
|
|
|
+ hid_destroy_device(hid);
|
|
|
+}
|
|
|
+
|
|
|
static int hid_suspend(struct usb_interface *intf, pm_message_t message)
|
|
|
{
|
|
|
struct hid_device *hid = usb_get_intfdata (intf);
|