ChangeSet 1.1317, 2003/05/29 22:36:35-07:00, [EMAIL PROTECTED]

[PATCH] USB Multi-input quirk


 drivers/usb/input/hid-core.c  |    8 --
 drivers/usb/input/hid-input.c |  139 +++++++++++++++++++++++++++++++++---------
 drivers/usb/input/hid-lgff.c  |   11 +--
 drivers/usb/input/hid-tmff.c  |   11 +--
 drivers/usb/input/hid.h       |   10 ++-
 drivers/usb/input/pid.c       |   13 ++-
 6 files changed, 141 insertions(+), 51 deletions(-)


diff -Nru a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c
--- a/drivers/usb/input/hid-core.c      Fri May 30 11:35:12 2003
+++ b/drivers/usb/input/hid-core.c      Fri May 30 11:35:12 2003
@@ -1387,9 +1387,9 @@
        { USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS, HID_QUIRK_HIDDEV },
        { USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS1, HID_QUIRK_HIDDEV },
        { USB_VENDOR_ID_TOPMAX, USB_DEVICE_ID_TOPMAX_COBRAPAD, HID_QUIRK_BADPAD },
-       { USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_DRIVING, HID_QUIRK_BADPAD },
-       { USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_FLYING, HID_QUIRK_BADPAD },
-       { USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_FIGHTING, HID_QUIRK_BADPAD },
+       { USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_DRIVING, 
HID_QUIRK_BADPAD|HID_QUIRK_MULTI_INPUT },
+       { USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_FLYING, 
HID_QUIRK_BADPAD|HID_QUIRK_MULTI_INPUT },
+       { USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_FIGHTING, 
HID_QUIRK_BADPAD|HID_QUIRK_MULTI_INPUT },
        { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100, HID_QUIRK_IGNORE },
        { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 100, HID_QUIRK_IGNORE },
        { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 200, HID_QUIRK_IGNORE },
@@ -1628,8 +1628,6 @@
 
        hid_init_reports(hid);
        hid_dump_device(hid);
-
-       hid_ff_init(hid);
 
        if (!hidinput_connect(hid))
                hid->claimed |= HID_CLAIMED_INPUT;
diff -Nru a/drivers/usb/input/hid-input.c b/drivers/usb/input/hid-input.c
--- a/drivers/usb/input/hid-input.c     Fri May 30 11:35:12 2003
+++ b/drivers/usb/input/hid-input.c     Fri May 30 11:35:12 2003
@@ -60,9 +60,36 @@
        __s32 y;
 }  hid_hat_to_axis[] = {{ 0, 0}, { 0,-1}, { 1,-1}, { 1, 0}, { 1, 1}, { 0, 1}, {-1, 
1}, {-1, 0}, {-1,-1}};
 
-static void hidinput_configure_usage(struct hid_device *device, struct hid_field 
*field, struct hid_usage *usage)
+static struct input_dev *find_input(struct hid_device *hid, struct hid_field *field)
 {
-       struct input_dev *input = &device->input;
+       struct list_head *lh;
+       struct hid_input *hidinput;
+
+       list_for_each (lh, &hid->inputs) {
+               int i;
+
+               hidinput = list_entry(lh, struct hid_input, list);
+
+               for (i = 0; i < hidinput->maxfield; i++)
+                       if (hidinput->fields[i] == field)
+                               return &hidinput->input;
+       }
+
+       /* Assume we only have one input and use it */
+       if (!list_empty(&hid->inputs)) {
+               hidinput = list_entry(hid->inputs.next, struct hid_input, list);
+               return &hidinput->input;
+       }
+
+       /* This is really a bug */
+       return NULL;
+}
+
+static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_field 
*field,
+                                    struct hid_usage *usage)
+{
+       struct input_dev *input = &hidinput->input;
+       struct hid_device *device = hidinput->input.private;
        int max;
        int is_abs = 0;
        unsigned long *bit;
@@ -388,9 +415,12 @@
 
 void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct 
hid_usage *usage, __s32 value, struct pt_regs *regs)
 {
-       struct input_dev *input = &hid->input;
+       struct input_dev *input = find_input(hid, field);
        int *quirks = &hid->quirks;
 
+       if (!input)
+               return;
+
        input_regs(input, regs);
 
        if (usage->hat_min != usage->hat_max) {
@@ -443,7 +473,13 @@
 
 void hidinput_report_event(struct hid_device *hid, struct hid_report *report)
 {
-       input_sync(&hid->input);
+       struct list_head *lh;
+       struct hid_input *hidinput;
+
+       list_for_each (lh, &hid->inputs) {
+               hidinput = list_entry(lh, struct hid_input, list);
+               input_sync(&hidinput->input);
+       }
 }
 
 static int hidinput_input_event(struct input_dev *dev, unsigned int type, unsigned 
int code, int value)
@@ -490,7 +526,10 @@
        struct hid_report_enum *report_enum;
        struct hid_report *report;
        struct list_head *list;
-       int i, j, k;
+       struct hid_input *hidinput = NULL;
+       int i, j;
+
+       INIT_LIST_HEAD(&hid->inputs);
 
        for (i = 0; i < hid->maxcollection; i++)
                if (hid->collection[i].type == HID_COLLECTION_APPLICATION &&
@@ -500,37 +539,79 @@
        if (i == hid->maxcollection)
                return -1;
 
-       hid->input.private = hid;
-       hid->input.event = hidinput_input_event;
-       hid->input.open = hidinput_open;
-       hid->input.close = hidinput_close;
-
-       hid->input.name = hid->name;
-       hid->input.phys = hid->phys;
-       hid->input.uniq = hid->uniq;
-       hid->input.id.bustype = BUS_USB;
-       hid->input.id.vendor = dev->descriptor.idVendor;
-       hid->input.id.product = dev->descriptor.idProduct;
-       hid->input.id.version = dev->descriptor.bcdDevice;
-
-       for (k = HID_INPUT_REPORT; k <= HID_OUTPUT_REPORT; k++) {
-               report_enum = hid->report_enum + k;
-               list = report_enum->report_list.next;
-               while (list != &report_enum->report_list) {
-                       report = (struct hid_report *) list;
-                       for (i = 0; i < report->maxfield; i++)
-                               for (j = 0; j < report->field[i]->maxusage; j++)
-                                       hidinput_configure_usage(hid, 
report->field[i], report->field[i]->usage + j);
-                       list = list->next;
+       report_enum = hid->report_enum + HID_INPUT_REPORT;
+       list = report_enum->report_list.next;
+       while (list != &report_enum->report_list) {
+               report = (struct hid_report *) list;
+
+               if (!report->maxfield)
+                       continue;
+
+               if (!hidinput) {
+                       hidinput = kmalloc(sizeof(*hidinput), GFP_KERNEL);
+                       if (!hidinput) {
+                               err("Out of memory during hid input probe");
+                               return -1;
+                       }
+                       memset(hidinput, 0, sizeof(*hidinput));
+
+                       list_add_tail(&hidinput->list, &hid->inputs);
+
+                       hidinput->input.private = hid;
+                       hidinput->input.event = hidinput_input_event;
+                       hidinput->input.open = hidinput_open;
+                       hidinput->input.close = hidinput_close;
+
+                       hidinput->input.name = hid->name;
+                       hidinput->input.phys = hid->phys;
+                       hidinput->input.uniq = hid->uniq;
+                       hidinput->input.id.bustype = BUS_USB;
+                       hidinput->input.id.vendor = dev->descriptor.idVendor;
+                       hidinput->input.id.product = dev->descriptor.idProduct;
+                       hidinput->input.id.version = dev->descriptor.bcdDevice;
                }
+
+               for (i = 0; i < report->maxfield; i++)
+                       for (j = 0; j < report->field[i]->maxusage; j++)
+                               hidinput_configure_usage(hidinput, report->field[i],
+                                                        report->field[i]->usage + j);
+
+               if (hid->quirks & HID_QUIRK_MULTI_INPUT) {
+                       /* This will leave hidinput NULL, so that it
+                        * allocates another one if we have more inputs on
+                        * the same interface. Some devices (e.g. Happ's
+                        * UGCI) cram a lot of unrelated inputs into the
+                        * same interface. */
+                       hidinput->fields = report->field;
+                       hidinput->maxfield = report->maxfield;
+
+                       input_register_device(&hidinput->input);
+                       hidinput = NULL;
+               }
+
+               list = list->next;
        }
 
-       input_register_device(&hid->input);
+       /* This only gets called when we are a single-input (most of the
+        * time). IOW, not a HID_QUIRK_MULTI_INPUT. The hid_ff_init() is
+        * only useful in this case, and not for multi-input quirks. */
+       if (hidinput) {
+               hid_ff_init(hid);
+               input_register_device(&hidinput->input);
+       }
 
        return 0;
 }
 
 void hidinput_disconnect(struct hid_device *hid)
 {
-       input_unregister_device(&hid->input);
+       struct list_head *lh, *next;
+       struct hid_input *hidinput;
+
+       list_for_each_safe (lh, next, &hid->inputs) {
+               hidinput = list_entry(lh, struct hid_input, list);
+               input_unregister_device(&hidinput->input);
+               list_del(&hidinput->list);
+               kfree(hidinput);
+       }
 }
diff -Nru a/drivers/usb/input/hid-lgff.c b/drivers/usb/input/hid-lgff.c
--- a/drivers/usb/input/hid-lgff.c      Fri May 30 11:35:12 2003
+++ b/drivers/usb/input/hid-lgff.c      Fri May 30 11:35:12 2003
@@ -254,6 +254,7 @@
        signed short* ff;
        u16 idVendor = hid->dev->descriptor.idVendor;
        u16 idProduct = hid->dev->descriptor.idProduct;
+       struct hid_input *hidinput = list_entry(&hid->inputs, struct hid_input, list);
 
        while (dev->idVendor && (idVendor != dev->idVendor || idProduct != 
dev->idProduct))
                dev++;
@@ -261,15 +262,15 @@
        ff = dev->ff;
 
        while (*ff >= 0) {
-               set_bit(*ff, hid->input.ffbit);
+               set_bit(*ff, hidinput->input.ffbit);
                ++ff;
        }
 
-       hid->input.upload_effect = hid_lgff_upload_effect;
-       hid->input.flush = hid_lgff_flush;
+       hidinput->input.upload_effect = hid_lgff_upload_effect;
+       hidinput->input.flush = hid_lgff_flush;
 
-       set_bit(EV_FF, hid->input.evbit);
-       hid->input.ff_effects_max = LGFF_EFFECTS;
+       set_bit(EV_FF, hidinput->input.evbit);
+       hidinput->input.ff_effects_max = LGFF_EFFECTS;
 }
 
 static void hid_lgff_exit(struct hid_device* hid)
diff -Nru a/drivers/usb/input/hid-tmff.c b/drivers/usb/input/hid-tmff.c
--- a/drivers/usb/input/hid-tmff.c      Fri May 30 11:35:12 2003
+++ b/drivers/usb/input/hid-tmff.c      Fri May 30 11:35:12 2003
@@ -110,6 +110,7 @@
 {
        struct tmff_device *private;
        struct list_head *pos;
+       struct hid_input *hidinput = list_entry(&hid->inputs, struct hid_input, list);
 
        private = kmalloc(sizeof(struct tmff_device), GFP_KERNEL);
        if (!private)
@@ -154,7 +155,7 @@
                                        private->report = report;
                                        private->rumble = field;
 
-                                       set_bit(FF_RUMBLE, hid->input.ffbit);
+                                       set_bit(FF_RUMBLE, hidinput->input.ffbit);
                                        break;
 
                                default:
@@ -163,11 +164,11 @@
                        }
 
                        /* Fallthrough to here only when a valid usage is found */
-                       hid->input.upload_effect = hid_tmff_upload_effect;
-                       hid->input.flush = hid_tmff_flush;
+                       hidinput->input.upload_effect = hid_tmff_upload_effect;
+                       hidinput->input.flush = hid_tmff_flush;
 
-                       set_bit(EV_FF, hid->input.evbit);
-                       hid->input.ff_effects_max = TMFF_EFFECTS;
+                       set_bit(EV_FF, hidinput->input.evbit);
+                       hidinput->input.ff_effects_max = TMFF_EFFECTS;
                }
        }
 
diff -Nru a/drivers/usb/input/hid.h b/drivers/usb/input/hid.h
--- a/drivers/usb/input/hid.h   Fri May 30 11:35:12 2003
+++ b/drivers/usb/input/hid.h   Fri May 30 11:35:12 2003
@@ -207,6 +207,7 @@
 #define HID_QUIRK_NOGET                0x08
 #define HID_QUIRK_HIDDEV       0x10
 #define HID_QUIRK_BADPAD        0x20
+#define HID_QUIRK_MULTI_INPUT  0x40
 
 /*
  * This is the global environment of the parser. This information is
@@ -321,6 +322,13 @@
 #define HID_CTRL_RUNNING       1
 #define HID_OUT_RUNNING                2
 
+struct hid_input {
+       struct list_head list;
+       struct hid_field **fields;
+       int maxfield;
+       struct input_dev input;
+};
+
 struct hid_device {                                                    /* device 
report descriptor */
         __u8 *rdesc;
        unsigned rsize;
@@ -360,7 +368,7 @@
        unsigned claimed;                                               /* Claimed by 
hidinput, hiddev? */      
        unsigned quirks;                                                /* Various 
quirks the device can pull on us */
 
-       struct input_dev input;                                         /* The input 
structure */
+       struct list_head inputs;                                        /* The list of 
inputs */
        void *hiddev;                                                   /* The hiddev 
structure */
        int minor;                                                      /* Hiddev 
minor number */
 
diff -Nru a/drivers/usb/input/pid.c b/drivers/usb/input/pid.c
--- a/drivers/usb/input/pid.c   Fri May 30 11:35:12 2003
+++ b/drivers/usb/input/pid.c   Fri May 30 11:35:12 2003
@@ -269,7 +269,8 @@
 int hid_pid_init(struct hid_device *hid)
 {
     struct hid_ff_pid *private;
-    
+    struct hid_input *hidinput = list_entry(&hid->inputs, struct hid_input, list);
+
     private = hid->ff_private = kmalloc(sizeof(struct hid_ff_pid), GFP_KERNEL);
     if (!private) return -1;
     
@@ -289,11 +290,11 @@
     }
 
     usb_fill_control_urb(private->urbffout, hid->dev,0,(void *) 
&private->ffcr,private->ctrl_buffer,8,hid_pid_ctrl_out,hid);
-    hid->input.upload_effect = hid_pid_upload_effect;
-    hid->input.flush = hid_pid_flush;
-    hid->input.ff_effects_max = 8;  // A random default
-    set_bit(EV_FF, hid->input.evbit);
-    set_bit(EV_FF_STATUS, hid->input.evbit);
+    hidinput->input.upload_effect = hid_pid_upload_effect;
+    hidinput->input.flush = hid_pid_flush;
+    hidinput->input.ff_effects_max = 8;  // A random default
+    set_bit(EV_FF, hidinput->input.evbit);
+    set_bit(EV_FF_STATUS, hidinput->input.evbit);
 
     spin_lock_init(&private->lock);
 



-------------------------------------------------------
This SF.net email is sponsored by: eBay
Get office equipment for less on eBay!
http://adfarm.mediaplex.com/ad/ck/711-11697-6916-5
_______________________________________________
[EMAIL PROTECTED]
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel

Reply via email to