ChangeSet 1.1248, 2003/06/18 16:54:52-07:00, [EMAIL PROTECTED]
[PATCH] USB Multi-input quirk
drivers/usb/hid-core.c | 8 +--
drivers/usb/hid-input.c | 120 +++++++++++++++++++++++++++++++++++++-----------
drivers/usb/hid.h | 10 +++-
3 files changed, 107 insertions(+), 31 deletions(-)
diff -Nru a/drivers/usb/hid-core.c b/drivers/usb/hid-core.c
--- a/drivers/usb/hid-core.c Wed Jun 18 17:35:10 2003
+++ b/drivers/usb/hid-core.c Wed Jun 18 17:35:10 2003
@@ -1146,9 +1146,9 @@
{ USB_VENDOR_ID_GRIFFIN, USB_DEVICE_ID_POWERMATE, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_GRIFFIN, USB_DEVICE_ID_SOUNDKNOB, HID_QUIRK_IGNORE },
{ 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 },
@@ -1304,7 +1304,7 @@
printk(KERN_INFO);
if (hid->claimed & HID_CLAIMED_INPUT)
- printk("input%d", hid->input.number);
+ printk("input");
if (hid->claimed == (HID_CLAIMED_INPUT | HID_CLAIMED_HIDDEV))
printk(",");
if (hid->claimed & HID_CLAIMED_HIDDEV)
diff -Nru a/drivers/usb/hid-input.c b/drivers/usb/hid-input.c
--- a/drivers/usb/hid-input.c Wed Jun 18 17:35:10 2003
+++ b/drivers/usb/hid-input.c Wed Jun 18 17:35:10 2003
@@ -63,9 +63,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;
unsigned long *bit;
@@ -310,9 +337,12 @@
void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct
hid_usage *usage, __s32 value)
{
- struct input_dev *input = &hid->input;
+ struct input_dev *input = find_input(hid, field);
int *quirks = &hid->quirks;
+ if (!input)
+ return;
+
if (usage->hat_min != usage->hat_max) {
value = (value - usage->hat_min) * 8 / (usage->hat_max -
usage->hat_min + 1) + 1;
if (value < 0 || value > 8) value = 0;
@@ -392,7 +422,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->maxapplication; i++)
if (IS_INPUT_APPLICATION(hid->application[i]))
@@ -401,35 +434,70 @@
if (i == hid->maxapplication)
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.idbus = BUS_USB;
- hid->input.idvendor = dev->descriptor.idVendor;
- hid->input.idproduct = dev->descriptor.idProduct;
- hid->input.idversion = 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.idbus = BUS_USB;
+ hidinput->input.idvendor = dev->descriptor.idVendor;
+ hidinput->input.idproduct = dev->descriptor.idProduct;
+ hidinput->input.idversion = 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);
+ if (hidinput)
+ 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/hid.h b/drivers/usb/hid.h
--- a/drivers/usb/hid.h Wed Jun 18 17:35:10 2003
+++ b/drivers/usb/hid.h Wed Jun 18 17:35:10 2003
@@ -188,6 +188,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
@@ -296,6 +297,13 @@
#define HID_CLAIMED_INPUT 1
#define HID_CLAIMED_HIDDEV 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;
@@ -318,7 +326,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 */
-------------------------------------------------------
This SF.Net email is sponsored by: INetU
Attention Web Developers & Consultants: Become An INetU Hosting Partner.
Refer Dedicated Servers. We Manage Them. You Get 10% Monthly Commission!
INetU Dedicated Managed Hosting http://www.inetu.net/partner/index.php
_______________________________________________
[EMAIL PROTECTED]
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel