summaryrefslogtreecommitdiff
path: root/drivers/hid/usbhid/hid-core.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/hid/usbhid/hid-core.c')
-rw-r--r--drivers/hid/usbhid/hid-core.c125
1 files changed, 38 insertions, 87 deletions
diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c
index d91b9dac6dff..0a1f2b52a12f 100644
--- a/drivers/hid/usbhid/hid-core.c
+++ b/drivers/hid/usbhid/hid-core.c
@@ -60,6 +60,12 @@ MODULE_PARM_DESC(quirks, "Add/modify USB HID quirks by specifying "
" quirks=vendorID:productID:quirks"
" where vendorID, productID, and quirks are all in"
" 0x-prefixed hex");
+static char *rdesc_quirks_param[MAX_USBHID_BOOT_QUIRKS] = { [ 0 ... (MAX_USBHID_BOOT_QUIRKS - 1) ] = NULL };
+module_param_array_named(rdesc_quirks, rdesc_quirks_param, charp, NULL, 0444);
+MODULE_PARM_DESC(rdesc_quirks, "Add/modify report descriptor quirks by specifying "
+ " rdesc_quirks=vendorID:productID:rdesc_quirks"
+ " where vendorID, productID, and rdesc_quirks are all in"
+ " 0x-prefixed hex");
/*
* Input submission and I/O error handler.
*/
@@ -127,7 +133,7 @@ static void hid_reset(struct work_struct *work)
hid_io_error(hid);
break;
default:
- err("can't reset device, %s-%s/input%d, status %d",
+ err_hid("can't reset device, %s-%s/input%d, status %d",
hid_to_usb_dev(hid)->bus->bus_name,
hid_to_usb_dev(hid)->devpath,
usbhid->ifnum, rc);
@@ -220,7 +226,7 @@ static void hid_irq_in(struct urb *urb)
if (status) {
clear_bit(HID_IN_RUNNING, &usbhid->iofl);
if (status != -EPERM) {
- err("can't resubmit intr, %s-%s/input%d, status %d",
+ 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);
@@ -240,10 +246,10 @@ static int hid_submit_out(struct hid_device *hid)
usbhid->urbout->transfer_buffer_length = ((report->size - 1) >> 3) + 1 + (report->id > 0);
usbhid->urbout->dev = hid_to_usb_dev(hid);
- dbg("submitting out urb");
+ dbg_hid("submitting out urb\n");
if (usb_submit_urb(usbhid->urbout, GFP_ATOMIC)) {
- err("usb_submit_urb(out) failed");
+ err_hid("usb_submit_urb(out) failed");
return -1;
}
@@ -287,12 +293,12 @@ static int hid_submit_ctrl(struct hid_device *hid)
usbhid->cr->wIndex = cpu_to_le16(usbhid->ifnum);
usbhid->cr->wLength = cpu_to_le16(len);
- dbg("submitting ctrl urb: %s wValue=0x%04x wIndex=0x%04x wLength=%u",
+ dbg_hid("submitting ctrl urb: %s wValue=0x%04x wIndex=0x%04x wLength=%u\n",
usbhid->cr->bRequest == HID_REQ_SET_REPORT ? "Set_Report" : "Get_Report",
usbhid->cr->wValue, usbhid->cr->wIndex, usbhid->cr->wLength);
if (usb_submit_urb(usbhid->urbctrl, GFP_ATOMIC)) {
- err("usb_submit_urb(ctrl) failed");
+ err_hid("usb_submit_urb(ctrl) failed");
return -1;
}
@@ -474,7 +480,7 @@ int usbhid_wait_io(struct hid_device *hid)
if (!wait_event_timeout(hid->wait, (!test_bit(HID_CTRL_RUNNING, &usbhid->iofl) &&
!test_bit(HID_OUT_RUNNING, &usbhid->iofl)),
10*HZ)) {
- dbg("timeout waiting for ctrl or out queue to clear");
+ dbg_hid("timeout waiting for ctrl or out queue to clear\n");
return -1;
}
@@ -633,20 +639,6 @@ static void hid_free_buffers(struct usb_device *dev, struct hid_device *hid)
}
/*
- * Cherry Cymotion keyboard have an invalid HID report descriptor,
- * that needs fixing before we can parse it.
- */
-
-static void hid_fixup_cymotion_descriptor(char *rdesc, int rsize)
-{
- if (rsize >= 17 && rdesc[11] == 0x3c && rdesc[12] == 0x02) {
- info("Fixing up Cherry Cymotion report descriptor");
- rdesc[11] = rdesc[16] = 0xff;
- rdesc[12] = rdesc[17] = 0x03;
- }
-}
-
-/*
* Sending HID_REQ_GET_REPORT changes the operation mode of the ps3 controller
* to "operational". Without this, the ps3 controller will not report any
* events.
@@ -667,51 +659,11 @@ static void hid_fixup_sony_ps3_controller(struct usb_device *dev, int ifnum)
USB_CTRL_GET_TIMEOUT);
if (result < 0)
- err("%s failed: %d\n", __func__, result);
+ err_hid("%s failed: %d\n", __func__, result);
kfree(buf);
}
-/*
- * Certain Logitech keyboards send in report #3 keys which are far
- * above the logical maximum described in descriptor. This extends
- * the original value of 0x28c of logical maximum to 0x104d
- */
-static void hid_fixup_logitech_descriptor(unsigned char *rdesc, int rsize)
-{
- if (rsize >= 90 && rdesc[83] == 0x26
- && rdesc[84] == 0x8c
- && rdesc[85] == 0x02) {
- info("Fixing up Logitech keyboard report descriptor");
- rdesc[84] = rdesc[89] = 0x4d;
- rdesc[85] = rdesc[90] = 0x10;
- }
-}
-
-/*
- * Some USB barcode readers from cypress have usage min and usage max in
- * the wrong order
- */
-static void hid_fixup_cypress_descriptor(unsigned char *rdesc, int rsize)
-{
- short fixed = 0;
- int i;
-
- for (i = 0; i < rsize - 4; i++) {
- if (rdesc[i] == 0x29 && rdesc [i+2] == 0x19) {
- unsigned char tmp;
-
- rdesc[i] = 0x19; rdesc[i+2] = 0x29;
- tmp = rdesc[i+3];
- rdesc[i+3] = rdesc[i+1];
- rdesc[i+1] = tmp;
- }
- }
-
- if (fixed)
- info("Fixing up Cypress report descriptor");
-}
-
static struct hid_device *usb_hid_configure(struct usb_interface *intf)
{
struct usb_host_interface *interface = intf->cur_altsetting;
@@ -746,7 +698,7 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf)
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("class descriptor not present\n");
+ dbg_hid("class descriptor not present\n");
return NULL;
}
@@ -755,41 +707,34 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf)
rsize = le16_to_cpu(hdesc->desc[n].wDescriptorLength);
if (!rsize || rsize > HID_MAX_DESCRIPTOR_SIZE) {
- dbg("weird size of report descriptor (%u)", rsize);
+ dbg_hid("weird size of report descriptor (%u)\n", rsize);
return NULL;
}
if (!(rdesc = kmalloc(rsize, GFP_KERNEL))) {
- dbg("couldn't allocate rdesc memory");
+ dbg_hid("couldn't allocate rdesc memory\n");
return NULL;
}
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) {
- dbg("reading report descriptor failed");
+ dbg_hid("reading report descriptor failed\n");
kfree(rdesc);
return NULL;
}
- if ((quirks & HID_QUIRK_CYMOTION))
- hid_fixup_cymotion_descriptor(rdesc, rsize);
-
- if (quirks & HID_QUIRK_LOGITECH_DESCRIPTOR)
- hid_fixup_logitech_descriptor(rdesc, rsize);
-
- if (quirks & HID_QUIRK_SWAPPED_MIN_MAX)
- hid_fixup_cypress_descriptor(rdesc, rsize);
+ usbhid_fixup_report_descriptor(le16_to_cpu(dev->descriptor.idVendor),
+ le16_to_cpu(dev->descriptor.idProduct), rdesc,
+ rsize, rdesc_quirks_param);
-#ifdef CONFIG_HID_DEBUG
- printk(KERN_DEBUG __FILE__ ": report descriptor (size %u, read %d) = ", rsize, n);
+ dbg_hid("report descriptor (size %u, read %d) = ", rsize, n);
for (n = 0; n < rsize; n++)
- printk(" %02x", (unsigned char) rdesc[n]);
- printk("\n");
-#endif
+ dbg_hid_line(" %02x", (unsigned char) rdesc[n]);
+ dbg_hid_line("\n");
if (!(hid = hid_parse_report(rdesc, n))) {
- dbg("parsing report descriptor failed");
+ dbg_hid("parsing report descriptor failed\n");
kfree(rdesc);
return NULL;
}
@@ -798,7 +743,7 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf)
hid->quirks = quirks;
if (!(usbhid = kzalloc(sizeof(struct usbhid_device), GFP_KERNEL)))
- goto fail;
+ goto fail_no_usbhid;
hid->driver_data = usbhid;
usbhid->hid = hid;
@@ -861,7 +806,7 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf)
}
if (!usbhid->urbin) {
- err("couldn't find an input interrupt endpoint");
+ err_hid("couldn't find an input interrupt endpoint");
goto fail;
}
@@ -933,6 +878,8 @@ fail:
usb_free_urb(usbhid->urbout);
usb_free_urb(usbhid->urbctrl);
hid_free_buffers(dev, hid);
+ kfree(usbhid);
+fail_no_usbhid:
hid_free_device(hid);
return NULL;
@@ -956,7 +903,7 @@ static void hid_disconnect(struct usb_interface *intf)
usb_kill_urb(usbhid->urbctrl);
del_timer_sync(&usbhid->io_retry);
- flush_scheduled_work();
+ cancel_work_sync(&usbhid->reset_work);
if (hid->claimed & HID_CLAIMED_INPUT)
hidinput_disconnect(hid);
@@ -968,6 +915,7 @@ static void hid_disconnect(struct usb_interface *intf)
usb_free_urb(usbhid->urbout);
hid_free_buffers(hid_to_usb_dev(hid), hid);
+ kfree(usbhid);
hid_free_device(hid);
}
@@ -978,7 +926,7 @@ static int hid_probe(struct usb_interface *intf, const struct usb_device_id *id)
int i;
char *c;
- dbg("HID probe called for ifnum %d",
+ dbg_hid("HID probe called for ifnum %d\n",
intf->altsetting->desc.bInterfaceNumber);
if (!(hid = usb_hid_configure(intf)))
@@ -1064,20 +1012,22 @@ static int hid_resume(struct usb_interface *intf)
}
/* Treat USB reset pretty much the same as suspend/resume */
-static void hid_pre_reset(struct usb_interface *intf)
+static int hid_pre_reset(struct usb_interface *intf)
{
/* FIXME: What if the interface is already suspended? */
hid_suspend(intf, PMSG_ON);
+ return 0;
}
-static void hid_post_reset(struct usb_interface *intf)
+/* Same routine used for post_reset and reset_resume */
+static int hid_post_reset(struct usb_interface *intf)
{
struct usb_device *dev = interface_to_usbdev (intf);
hid_set_idle(dev, intf->cur_altsetting->desc.bInterfaceNumber, 0, 0);
/* FIXME: Any more reinitialization needed? */
- hid_resume(intf);
+ return hid_resume(intf);
}
static struct usb_device_id hid_usb_ids [] = {
@@ -1094,6 +1044,7 @@ static struct usb_driver hid_driver = {
.disconnect = hid_disconnect,
.suspend = hid_suspend,
.resume = hid_resume,
+ .reset_resume = hid_post_reset,
.pre_reset = hid_pre_reset,
.post_reset = hid_post_reset,
.id_table = hid_usb_ids,