HID: support for Petalynx Maxter remote control
[safe/jmp/linux-2.6] / drivers / hid / usbhid / hid-core.c
index bf118c0..ef7b881 100644 (file)
@@ -53,6 +53,13 @@ static unsigned int hid_mousepoll_interval;
 module_param_named(mousepoll, hid_mousepoll_interval, uint, 0644);
 MODULE_PARM_DESC(mousepoll, "Polling interval of mice");
 
+/* Quirks specified at module load time */
+static char *quirks_param[MAX_USBHID_BOOT_QUIRKS] = { [ 0 ... (MAX_USBHID_BOOT_QUIRKS - 1) ] = NULL };
+module_param_array_named(quirks, quirks_param, charp, NULL, 0444);
+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");
 /*
  * Input submission and I/O error handler.
  */
@@ -439,7 +446,7 @@ void usbhid_submit_report(struct hid_device *hid, struct hid_report *report, uns
 
 static int usb_hidinput_input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
 {
-       struct hid_device *hid = dev->private;
+       struct hid_device *hid = input_get_drvdata(dev);
        struct hid_field *field;
        int offset;
 
@@ -619,14 +626,10 @@ static void hid_free_buffers(struct usb_device *dev, struct hid_device *hid)
 {
        struct usbhid_device *usbhid = hid->driver_data;
 
-       if (usbhid->inbuf)
-               usb_buffer_free(dev, usbhid->bufsize, usbhid->inbuf, usbhid->inbuf_dma);
-       if (usbhid->outbuf)
-               usb_buffer_free(dev, usbhid->bufsize, usbhid->outbuf, usbhid->outbuf_dma);
-       if (usbhid->cr)
-               usb_buffer_free(dev, sizeof(*(usbhid->cr)), usbhid->cr, usbhid->cr_dma);
-       if (usbhid->ctrlbuf)
-               usb_buffer_free(dev, usbhid->bufsize, usbhid->ctrlbuf, usbhid->ctrlbuf_dma);
+       usb_buffer_free(dev, usbhid->bufsize, usbhid->inbuf, usbhid->inbuf_dma);
+       usb_buffer_free(dev, usbhid->bufsize, usbhid->outbuf, usbhid->outbuf_dma);
+       usb_buffer_free(dev, sizeof(*(usbhid->cr)), usbhid->cr, usbhid->cr_dma);
+       usb_buffer_free(dev, usbhid->bufsize, usbhid->ctrlbuf, usbhid->ctrlbuf_dma);
 }
 
 /*
@@ -685,6 +688,45 @@ static void hid_fixup_logitech_descriptor(unsigned char *rdesc, int rsize)
        }
 }
 
+/* Petalynx Maxter Remote has maximum for consumer page set too low */
+static void hid_fixup_petalynx_descriptor(unsigned char *rdesc, int rsize)
+{
+       if (rsize >= 60 && rdesc[39] == 0x2a
+                       && rdesc[40] == 0xf5
+                       && rdesc[41] == 0x00
+                       && rdesc[59] == 0x26
+                       && rdesc[60] == 0xf9
+                       && rdesc[61] == 0x00) {
+               info("Fixing up Petalynx Maxter Remote report descriptor");
+               rdesc[60] = 0xfa;
+               rdesc[40] = 0xfa;
+       }
+}
+
+/*
+ * 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;
@@ -751,6 +793,12 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf)
        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);
+
+       if (quirks & HID_QUIRK_PETALYNX_DESCRIPTOR)
+               hid_fixup_petalynx_descriptor(rdesc, rsize);
+
 #ifdef CONFIG_HID_DEBUG
        printk(KERN_DEBUG __FILE__ ": report descriptor (size %u, read %d) = ", rsize, n);
        for (n = 0; n < rsize; n++)
@@ -926,7 +974,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);
@@ -1072,6 +1120,9 @@ static struct usb_driver hid_driver = {
 static int __init hid_init(void)
 {
        int retval;
+       retval = usbhid_quirks_init(quirks_param);
+       if (retval)
+               goto usbhid_quirks_init_fail;
        retval = hiddev_init();
        if (retval)
                goto hiddev_init_fail;
@@ -1084,6 +1135,8 @@ static int __init hid_init(void)
 usb_register_fail:
        hiddev_exit();
 hiddev_init_fail:
+       usbhid_quirks_exit();
+usbhid_quirks_init_fail:
        return retval;
 }
 
@@ -1091,6 +1144,7 @@ static void __exit hid_exit(void)
 {
        usb_deregister(&hid_driver);
        hiddev_exit();
+       usbhid_quirks_exit();
 }
 
 module_init(hid_init);