Commit 1f17689c authored by Ben Collins's avatar Ben Collins Committed by Greg Kroah-Hartman

[PATCH] USB Multi-input quirk

parent a98b28b1
...@@ -1387,9 +1387,9 @@ struct hid_blacklist { ...@@ -1387,9 +1387,9 @@ struct hid_blacklist {
{ USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS, HID_QUIRK_HIDDEV }, { 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_MGE, USB_DEVICE_ID_MGE_UPS1, HID_QUIRK_HIDDEV },
{ USB_VENDOR_ID_TOPMAX, USB_DEVICE_ID_TOPMAX_COBRAPAD, HID_QUIRK_BADPAD }, { 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_DRIVING, HID_QUIRK_BADPAD|HID_QUIRK_MULTI_INPUT },
{ USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_FLYING, HID_QUIRK_BADPAD }, { 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 }, { 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, 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 + 100, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 200, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 200, HID_QUIRK_IGNORE },
...@@ -1629,8 +1629,6 @@ static int hid_probe (struct usb_interface *intf, const struct usb_device_id *id ...@@ -1629,8 +1629,6 @@ static int hid_probe (struct usb_interface *intf, const struct usb_device_id *id
hid_init_reports(hid); hid_init_reports(hid);
hid_dump_device(hid); hid_dump_device(hid);
hid_ff_init(hid);
if (!hidinput_connect(hid)) if (!hidinput_connect(hid))
hid->claimed |= HID_CLAIMED_INPUT; hid->claimed |= HID_CLAIMED_INPUT;
if (!hiddev_connect(hid)) if (!hiddev_connect(hid))
......
...@@ -60,9 +60,36 @@ static struct { ...@@ -60,9 +60,36 @@ static struct {
__s32 y; __s32 y;
} hid_hat_to_axis[] = {{ 0, 0}, { 0,-1}, { 1,-1}, { 1, 0}, { 1, 1}, { 0, 1}, {-1, 1}, {-1, 0}, {-1,-1}}; } 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 max;
int is_abs = 0; int is_abs = 0;
unsigned long *bit; unsigned long *bit;
...@@ -388,9 +415,12 @@ static void hidinput_configure_usage(struct hid_device *device, struct hid_field ...@@ -388,9 +415,12 @@ static void hidinput_configure_usage(struct hid_device *device, struct hid_field
void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct hid_usage *usage, __s32 value, struct pt_regs *regs) 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; int *quirks = &hid->quirks;
if (!input)
return;
input_regs(input, regs); input_regs(input, regs);
if (usage->hat_min != usage->hat_max) { if (usage->hat_min != usage->hat_max) {
...@@ -443,7 +473,13 @@ void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct ...@@ -443,7 +473,13 @@ void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct
void hidinput_report_event(struct hid_device *hid, struct hid_report *report) 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) static int hidinput_input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
...@@ -490,7 +526,10 @@ int hidinput_connect(struct hid_device *hid) ...@@ -490,7 +526,10 @@ int hidinput_connect(struct hid_device *hid)
struct hid_report_enum *report_enum; struct hid_report_enum *report_enum;
struct hid_report *report; struct hid_report *report;
struct list_head *list; 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++) for (i = 0; i < hid->maxcollection; i++)
if (hid->collection[i].type == HID_COLLECTION_APPLICATION && if (hid->collection[i].type == HID_COLLECTION_APPLICATION &&
...@@ -500,37 +539,79 @@ int hidinput_connect(struct hid_device *hid) ...@@ -500,37 +539,79 @@ int hidinput_connect(struct hid_device *hid)
if (i == hid->maxcollection) if (i == hid->maxcollection)
return -1; return -1;
hid->input.private = hid; report_enum = hid->report_enum + HID_INPUT_REPORT;
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; list = report_enum->report_list.next;
while (list != &report_enum->report_list) { while (list != &report_enum->report_list) {
report = (struct hid_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 (i = 0; i < report->maxfield; i++)
for (j = 0; j < report->field[i]->maxusage; j++) for (j = 0; j < report->field[i]->maxusage; j++)
hidinput_configure_usage(hid, report->field[i], report->field[i]->usage + j); hidinput_configure_usage(hidinput, report->field[i],
list = list->next; 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; return 0;
} }
void hidinput_disconnect(struct hid_device *hid) 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);
}
} }
...@@ -254,6 +254,7 @@ static void hid_lgff_input_init(struct hid_device* hid) ...@@ -254,6 +254,7 @@ static void hid_lgff_input_init(struct hid_device* hid)
signed short* ff; signed short* ff;
u16 idVendor = hid->dev->descriptor.idVendor; u16 idVendor = hid->dev->descriptor.idVendor;
u16 idProduct = hid->dev->descriptor.idProduct; 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)) while (dev->idVendor && (idVendor != dev->idVendor || idProduct != dev->idProduct))
dev++; dev++;
...@@ -261,15 +262,15 @@ static void hid_lgff_input_init(struct hid_device* hid) ...@@ -261,15 +262,15 @@ static void hid_lgff_input_init(struct hid_device* hid)
ff = dev->ff; ff = dev->ff;
while (*ff >= 0) { while (*ff >= 0) {
set_bit(*ff, hid->input.ffbit); set_bit(*ff, hidinput->input.ffbit);
++ff; ++ff;
} }
hid->input.upload_effect = hid_lgff_upload_effect; hidinput->input.upload_effect = hid_lgff_upload_effect;
hid->input.flush = hid_lgff_flush; hidinput->input.flush = hid_lgff_flush;
set_bit(EV_FF, hid->input.evbit); set_bit(EV_FF, hidinput->input.evbit);
hid->input.ff_effects_max = LGFF_EFFECTS; hidinput->input.ff_effects_max = LGFF_EFFECTS;
} }
static void hid_lgff_exit(struct hid_device* hid) static void hid_lgff_exit(struct hid_device* hid)
......
...@@ -110,6 +110,7 @@ int hid_tmff_init(struct hid_device *hid) ...@@ -110,6 +110,7 @@ int hid_tmff_init(struct hid_device *hid)
{ {
struct tmff_device *private; struct tmff_device *private;
struct list_head *pos; struct list_head *pos;
struct hid_input *hidinput = list_entry(&hid->inputs, struct hid_input, list);
private = kmalloc(sizeof(struct tmff_device), GFP_KERNEL); private = kmalloc(sizeof(struct tmff_device), GFP_KERNEL);
if (!private) if (!private)
...@@ -154,7 +155,7 @@ int hid_tmff_init(struct hid_device *hid) ...@@ -154,7 +155,7 @@ int hid_tmff_init(struct hid_device *hid)
private->report = report; private->report = report;
private->rumble = field; private->rumble = field;
set_bit(FF_RUMBLE, hid->input.ffbit); set_bit(FF_RUMBLE, hidinput->input.ffbit);
break; break;
default: default:
...@@ -163,11 +164,11 @@ int hid_tmff_init(struct hid_device *hid) ...@@ -163,11 +164,11 @@ int hid_tmff_init(struct hid_device *hid)
} }
/* Fallthrough to here only when a valid usage is found */ /* Fallthrough to here only when a valid usage is found */
hid->input.upload_effect = hid_tmff_upload_effect; hidinput->input.upload_effect = hid_tmff_upload_effect;
hid->input.flush = hid_tmff_flush; hidinput->input.flush = hid_tmff_flush;
set_bit(EV_FF, hid->input.evbit); set_bit(EV_FF, hidinput->input.evbit);
hid->input.ff_effects_max = TMFF_EFFECTS; hidinput->input.ff_effects_max = TMFF_EFFECTS;
} }
} }
......
...@@ -207,6 +207,7 @@ struct hid_item { ...@@ -207,6 +207,7 @@ struct hid_item {
#define HID_QUIRK_NOGET 0x08 #define HID_QUIRK_NOGET 0x08
#define HID_QUIRK_HIDDEV 0x10 #define HID_QUIRK_HIDDEV 0x10
#define HID_QUIRK_BADPAD 0x20 #define HID_QUIRK_BADPAD 0x20
#define HID_QUIRK_MULTI_INPUT 0x40
/* /*
* This is the global environment of the parser. This information is * This is the global environment of the parser. This information is
...@@ -321,6 +322,13 @@ struct hid_control_fifo { ...@@ -321,6 +322,13 @@ struct hid_control_fifo {
#define HID_CTRL_RUNNING 1 #define HID_CTRL_RUNNING 1
#define HID_OUT_RUNNING 2 #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 */ struct hid_device { /* device report descriptor */
__u8 *rdesc; __u8 *rdesc;
unsigned rsize; unsigned rsize;
...@@ -360,7 +368,7 @@ struct hid_device { /* device report descriptor */ ...@@ -360,7 +368,7 @@ struct hid_device { /* device report descriptor */
unsigned claimed; /* Claimed by hidinput, hiddev? */ unsigned claimed; /* Claimed by hidinput, hiddev? */
unsigned quirks; /* Various quirks the device can pull on us */ 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 */ void *hiddev; /* The hiddev structure */
int minor; /* Hiddev minor number */ int minor; /* Hiddev minor number */
......
...@@ -269,6 +269,7 @@ static int hid_pid_upload_effect(struct input_dev *dev, ...@@ -269,6 +269,7 @@ static int hid_pid_upload_effect(struct input_dev *dev,
int hid_pid_init(struct hid_device *hid) int hid_pid_init(struct hid_device *hid)
{ {
struct hid_ff_pid *private; 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); private = hid->ff_private = kmalloc(sizeof(struct hid_ff_pid), GFP_KERNEL);
if (!private) return -1; if (!private) return -1;
...@@ -289,11 +290,11 @@ int hid_pid_init(struct hid_device *hid) ...@@ -289,11 +290,11 @@ int hid_pid_init(struct hid_device *hid)
} }
usb_fill_control_urb(private->urbffout, hid->dev,0,(void *) &private->ffcr,private->ctrl_buffer,8,hid_pid_ctrl_out,hid); 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; hidinput->input.upload_effect = hid_pid_upload_effect;
hid->input.flush = hid_pid_flush; hidinput->input.flush = hid_pid_flush;
hid->input.ff_effects_max = 8; // A random default hidinput->input.ff_effects_max = 8; // A random default
set_bit(EV_FF, hid->input.evbit); set_bit(EV_FF, hidinput->input.evbit);
set_bit(EV_FF_STATUS, hid->input.evbit); set_bit(EV_FF_STATUS, hidinput->input.evbit);
spin_lock_init(&private->lock); spin_lock_init(&private->lock);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment