Commit 36b77410 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/hid

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/hid:
  HID: handle cases of volume knobs generating relative values
  HID: Logitech keyboard 0xc311 needs reset leds quirk
  HID: support for logitech cordless desktop LX500 special mapping
  HID: fix autocentering of PID devices
  HID: separate quirks for report descriptor fixup
  HID: Add NOGET quirk for all NCR devices
  HID: support for Petalynx Maxter remote control
  HID: fix mismatch between hid-input HUT find/search mapping and the HUT
  HID: support for Gameron dual psx adaptor
  USB HID: avoid flush_scheduled_work()
  HID: Use menuconfig objects
  HID: force hid-input for Microsoft SideWinder GameVoice device
  HID: input mapping for Chicony KU-0418 tactical pad
  HID: make debugging output runtime-configurable
parents 71ba22fa feb485d4
# #
# HID driver configuration # HID driver configuration
# #
menu "HID Devices" menuconfig HID_SUPPORT
bool "HID Devices"
depends on INPUT depends on INPUT
default y
if HID_SUPPORT
config HID config HID
tristate "Generic HID support" tristate "Generic HID support"
...@@ -24,6 +28,7 @@ config HID ...@@ -24,6 +28,7 @@ config HID
config HID_DEBUG config HID_DEBUG
bool "HID debugging support" bool "HID debugging support"
default y if !EMBEDDED
depends on HID depends on HID
---help--- ---help---
This option lets the HID layer output diagnostics about its internal This option lets the HID layer output diagnostics about its internal
...@@ -38,5 +43,4 @@ config HID_DEBUG ...@@ -38,5 +43,4 @@ config HID_DEBUG
source "drivers/hid/usbhid/Kconfig" source "drivers/hid/usbhid/Kconfig"
endmenu endif # HID_SUPPORT
This diff is collapsed.
...@@ -347,6 +347,9 @@ static void resolv_usage_page(unsigned page) { ...@@ -347,6 +347,9 @@ static void resolv_usage_page(unsigned page) {
void hid_resolv_usage(unsigned usage) { void hid_resolv_usage(unsigned usage) {
const struct hid_usage_entry *p; const struct hid_usage_entry *p;
if (!hid_debug)
return;
resolv_usage_page(usage >> 16); resolv_usage_page(usage >> 16);
printk("."); printk(".");
for (p = hid_usage_table; p->description; p++) for (p = hid_usage_table; p->description; p++)
...@@ -369,6 +372,9 @@ __inline__ static void tab(int n) { ...@@ -369,6 +372,9 @@ __inline__ static void tab(int n) {
void hid_dump_field(struct hid_field *field, int n) { void hid_dump_field(struct hid_field *field, int n) {
int j; int j;
if (!hid_debug)
return;
if (field->physical) { if (field->physical) {
tab(n); tab(n);
printk("Physical("); printk("Physical(");
...@@ -466,6 +472,9 @@ void hid_dump_device(struct hid_device *device) { ...@@ -466,6 +472,9 @@ void hid_dump_device(struct hid_device *device) {
unsigned i,k; unsigned i,k;
static char *table[] = {"INPUT", "OUTPUT", "FEATURE"}; static char *table[] = {"INPUT", "OUTPUT", "FEATURE"};
if (!hid_debug)
return;
for (i = 0; i < HID_REPORT_TYPES; i++) { for (i = 0; i < HID_REPORT_TYPES; i++) {
report_enum = device->report_enum + i; report_enum = device->report_enum + i;
list = report_enum->report_list.next; list = report_enum->report_list.next;
...@@ -489,6 +498,9 @@ void hid_dump_device(struct hid_device *device) { ...@@ -489,6 +498,9 @@ void hid_dump_device(struct hid_device *device) {
EXPORT_SYMBOL_GPL(hid_dump_device); EXPORT_SYMBOL_GPL(hid_dump_device);
void hid_dump_input(struct hid_usage *usage, __s32 value) { void hid_dump_input(struct hid_usage *usage, __s32 value) {
if (!hid_debug)
return;
printk("hid-debug: input "); printk("hid-debug: input ");
hid_resolv_usage(usage->hid); hid_resolv_usage(usage->hid);
printk(" = %d\n", value); printk(" = %d\n", value);
...@@ -758,6 +770,9 @@ static char **names[EV_MAX + 1] = { ...@@ -758,6 +770,9 @@ static char **names[EV_MAX + 1] = {
void hid_resolv_event(__u8 type, __u16 code) { void hid_resolv_event(__u8 type, __u16 code) {
if (!hid_debug)
return;
printk("%s.%s", events[type] ? events[type] : "?", printk("%s.%s", events[type] ? events[type] : "?",
names[type] ? (names[type][code] ? names[type][code] : "?") : "?"); names[type] ? (names[type][code] ? names[type][code] : "?") : "?");
} }
......
...@@ -60,6 +60,19 @@ static const unsigned char hid_keyboard[256] = { ...@@ -60,6 +60,19 @@ static const unsigned char hid_keyboard[256] = {
150,158,159,128,136,177,178,176,142,152,173,140,unk,unk,unk,unk 150,158,159,128,136,177,178,176,142,152,173,140,unk,unk,unk,unk
}; };
/* extended mapping for certain Logitech hardware (Logitech cordless desktop LX500) */
#define LOGITECH_EXPANDED_KEYMAP_SIZE 80
static int logitech_expanded_keymap[LOGITECH_EXPANDED_KEYMAP_SIZE] = {
0,216, 0,213,175,156, 0, 0, 0, 0,
144, 0, 0, 0, 0, 0, 0, 0, 0,212,
174,167,152,161,112, 0, 0, 0,154, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0,183,184,185,186,187,
188,189,190,191,192,193,194, 0, 0, 0
};
static const struct { static const struct {
__s32 x; __s32 x;
__s32 y; __s32 y;
...@@ -308,9 +321,7 @@ static int hidinput_setkeycode(struct input_dev *dev, int scancode, ...@@ -308,9 +321,7 @@ static int hidinput_setkeycode(struct input_dev *dev, int scancode,
clear_bit(old_keycode, dev->keybit); clear_bit(old_keycode, dev->keybit);
set_bit(usage->code, dev->keybit); set_bit(usage->code, dev->keybit);
#ifdef CONFIG_HID_DEBUG dbg_hid(KERN_DEBUG "Assigned keycode %d to HID usage code %x\n", keycode, scancode);
printk (KERN_DEBUG "Assigned keycode %d to HID usage code %x\n", keycode, scancode);
#endif
/* Set the keybit for the old keycode if the old keycode is used /* Set the keybit for the old keycode if the old keycode is used
* by another key */ * by another key */
if (hidinput_find_key (hid, 0, old_keycode)) if (hidinput_find_key (hid, 0, old_keycode))
...@@ -333,11 +344,9 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel ...@@ -333,11 +344,9 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
field->hidinput = hidinput; field->hidinput = hidinput;
#ifdef CONFIG_HID_DEBUG dbg_hid("Mapping: ");
printk(KERN_DEBUG "Mapping: ");
hid_resolv_usage(usage->hid); hid_resolv_usage(usage->hid);
printk(" ---> "); dbg_hid_line(" ---> ");
#endif
if (field->flags & HID_MAIN_ITEM_CONSTANT) if (field->flags & HID_MAIN_ITEM_CONSTANT)
goto ignore; goto ignore;
...@@ -378,6 +387,21 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel ...@@ -378,6 +387,21 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
} }
} }
/* Special handling for Logitech Cordless Desktop */
if (field->application != HID_GD_MOUSE) {
if (device->quirks & HID_QUIRK_LOGITECH_EXPANDED_KEYMAP) {
int hid = usage->hid & HID_USAGE;
if (hid < LOGITECH_EXPANDED_KEYMAP_SIZE && logitech_expanded_keymap[hid] != 0)
code = logitech_expanded_keymap[hid];
}
} else {
if (device->quirks & HID_QUIRK_LOGITECH_IGNORE_DOUBLED_WHEEL) {
int hid = usage->hid & HID_USAGE;
if (hid == 7 || hid == 8)
goto ignore;
}
}
map_key(code); map_key(code);
break; break;
...@@ -566,6 +590,11 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel ...@@ -566,6 +590,11 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
case 0x0e5: map_key_clear(KEY_BASSBOOST); break; case 0x0e5: map_key_clear(KEY_BASSBOOST); break;
case 0x0e9: map_key_clear(KEY_VOLUMEUP); break; case 0x0e9: map_key_clear(KEY_VOLUMEUP); break;
case 0x0ea: map_key_clear(KEY_VOLUMEDOWN); break; case 0x0ea: map_key_clear(KEY_VOLUMEDOWN); break;
/* reserved in HUT 1.12. Reported on Petalynx remote */
case 0x0f6: map_key_clear(KEY_NEXT); break;
case 0x0fa: map_key_clear(KEY_BACK); break;
case 0x183: map_key_clear(KEY_CONFIG); break; case 0x183: map_key_clear(KEY_CONFIG); break;
case 0x184: map_key_clear(KEY_WORDPROCESSOR); break; case 0x184: map_key_clear(KEY_WORDPROCESSOR); break;
case 0x185: map_key_clear(KEY_EDITOR); break; case 0x185: map_key_clear(KEY_EDITOR); break;
...@@ -598,7 +627,9 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel ...@@ -598,7 +627,9 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
case 0x21b: map_key_clear(KEY_COPY); break; case 0x21b: map_key_clear(KEY_COPY); break;
case 0x21c: map_key_clear(KEY_CUT); break; case 0x21c: map_key_clear(KEY_CUT); break;
case 0x21d: map_key_clear(KEY_PASTE); break; case 0x21d: map_key_clear(KEY_PASTE); break;
case 0x221: map_key_clear(KEY_FIND); break; case 0x21f: map_key_clear(KEY_FIND); break;
case 0x221: map_key_clear(KEY_SEARCH); break;
case 0x222: map_key_clear(KEY_GOTO); break;
case 0x223: map_key_clear(KEY_HOMEPAGE); break; case 0x223: map_key_clear(KEY_HOMEPAGE); break;
case 0x224: map_key_clear(KEY_BACK); break; case 0x224: map_key_clear(KEY_BACK); break;
case 0x225: map_key_clear(KEY_FORWARD); break; case 0x225: map_key_clear(KEY_FORWARD); break;
...@@ -688,7 +719,28 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel ...@@ -688,7 +719,28 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
break; break;
case HID_UP_MSVENDOR: case HID_UP_MSVENDOR:
goto ignore;
/* special case - Chicony Chicony KU-0418 tactical pad */
if (device->vendor == 0x04f2 && device->product == 0x0418) {
set_bit(EV_REP, input->evbit);
switch(usage->hid & HID_USAGE) {
case 0xff01: map_key_clear(BTN_1); break;
case 0xff02: map_key_clear(BTN_2); break;
case 0xff03: map_key_clear(BTN_3); break;
case 0xff04: map_key_clear(BTN_4); break;
case 0xff05: map_key_clear(BTN_5); break;
case 0xff06: map_key_clear(BTN_6); break;
case 0xff07: map_key_clear(BTN_7); break;
case 0xff08: map_key_clear(BTN_8); break;
case 0xff09: map_key_clear(BTN_9); break;
case 0xff0a: map_key_clear(BTN_A); break;
case 0xff0b: map_key_clear(BTN_B); break;
default: goto ignore;
}
} else {
goto ignore;
}
break;
case HID_UP_CUSTOM: /* Reported on Logitech and Powerbook USB keyboards */ case HID_UP_CUSTOM: /* Reported on Logitech and Powerbook USB keyboards */
...@@ -704,10 +756,10 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel ...@@ -704,10 +756,10 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
} }
break; break;
case HID_UP_LOGIVENDOR: /* Reported on Logitech Ultra X Media Remote */ case HID_UP_LOGIVENDOR:
set_bit(EV_REP, input->evbit); set_bit(EV_REP, input->evbit);
switch(usage->hid & HID_USAGE) { switch(usage->hid & HID_USAGE) {
/* Reported on Logitech Ultra X Media Remote */
case 0x004: map_key_clear(KEY_AGAIN); break; case 0x004: map_key_clear(KEY_AGAIN); break;
case 0x00d: map_key_clear(KEY_HOME); break; case 0x00d: map_key_clear(KEY_HOME); break;
case 0x024: map_key_clear(KEY_SHUFFLE); break; case 0x024: map_key_clear(KEY_SHUFFLE); break;
...@@ -725,6 +777,14 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel ...@@ -725,6 +777,14 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
case 0x04d: map_key_clear(KEY_SUBTITLE); break; case 0x04d: map_key_clear(KEY_SUBTITLE); break;
case 0x051: map_key_clear(KEY_RED); break; case 0x051: map_key_clear(KEY_RED); break;
case 0x052: map_key_clear(KEY_CLOSE); break; case 0x052: map_key_clear(KEY_CLOSE); break;
/* Reported on Petalynx Maxter remote */
case 0x05a: map_key_clear(KEY_TEXT); break;
case 0x05b: map_key_clear(KEY_RED); break;
case 0x05c: map_key_clear(KEY_GREEN); break;
case 0x05d: map_key_clear(KEY_YELLOW); break;
case 0x05e: map_key_clear(KEY_BLUE); break;
default: goto ignore; default: goto ignore;
} }
break; break;
...@@ -818,16 +878,24 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel ...@@ -818,16 +878,24 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
field->dpad = usage->code; field->dpad = usage->code;
} }
/* for those devices which produce Consumer volume usage as relative,
* we emulate pressing volumeup/volumedown appropriate number of times
* in hidinput_hid_event()
*/
if ((usage->type == EV_ABS) && (field->flags & HID_MAIN_ITEM_RELATIVE) &&
(usage->code == ABS_VOLUME)) {
set_bit(KEY_VOLUMEUP, input->keybit);
set_bit(KEY_VOLUMEDOWN, input->keybit);
}
hid_resolv_event(usage->type, usage->code); hid_resolv_event(usage->type, usage->code);
#ifdef CONFIG_HID_DEBUG
printk("\n"); dbg_hid_line("\n");
#endif
return; return;
ignore: ignore:
#ifdef CONFIG_HID_DEBUG dbg_hid_line("IGNORED\n");
printk("IGNORED\n");
#endif
return; return;
} }
...@@ -896,18 +964,33 @@ void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct ...@@ -896,18 +964,33 @@ void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct
} }
if (usage->hid == (HID_UP_PID | 0x83UL)) { /* Simultaneous Effects Max */ if (usage->hid == (HID_UP_PID | 0x83UL)) { /* Simultaneous Effects Max */
dbg("Maximum Effects - %d",value); dbg_hid("Maximum Effects - %d\n",value);
return; return;
} }
if (usage->hid == (HID_UP_PID | 0x7fUL)) { if (usage->hid == (HID_UP_PID | 0x7fUL)) {
dbg("PID Pool Report\n"); dbg_hid("PID Pool Report\n");
return; return;
} }
if ((usage->type == EV_KEY) && (usage->code == 0)) /* Key 0 is "unassigned", not KEY_UNKNOWN */ if ((usage->type == EV_KEY) && (usage->code == 0)) /* Key 0 is "unassigned", not KEY_UNKNOWN */
return; return;
if ((usage->type == EV_ABS) && (field->flags & HID_MAIN_ITEM_RELATIVE) &&
(usage->code == ABS_VOLUME)) {
int count = abs(value);
int direction = value > 0 ? KEY_VOLUMEUP : KEY_VOLUMEDOWN;
int i;
for (i = 0; i < count; i++) {
input_event(input, EV_KEY, direction, 1);
input_sync(input);
input_event(input, EV_KEY, direction, 0);
input_sync(input);
}
return;
}
input_event(input, usage->type, usage->code, value); input_event(input, usage->type, usage->code, value);
if ((field->flags & HID_MAIN_ITEM_RELATIVE) && (usage->type == EV_KEY)) if ((field->flags & HID_MAIN_ITEM_RELATIVE) && (usage->type == EV_KEY))
...@@ -976,7 +1059,7 @@ int hidinput_connect(struct hid_device *hid) ...@@ -976,7 +1059,7 @@ int hidinput_connect(struct hid_device *hid)
if (IS_INPUT_APPLICATION(hid->collection[i].usage)) if (IS_INPUT_APPLICATION(hid->collection[i].usage))
break; break;
if (i == hid->maxcollection) if (i == hid->maxcollection && (hid->quirks & HID_QUIRK_HIDINPUT) == 0)
return -1; return -1;
if (hid->quirks & HID_QUIRK_SKIP_OUTPUT_REPORTS) if (hid->quirks & HID_QUIRK_SKIP_OUTPUT_REPORTS)
...@@ -994,7 +1077,7 @@ int hidinput_connect(struct hid_device *hid) ...@@ -994,7 +1077,7 @@ int hidinput_connect(struct hid_device *hid)
if (!hidinput || !input_dev) { if (!hidinput || !input_dev) {
kfree(hidinput); kfree(hidinput);
input_free_device(input_dev); input_free_device(input_dev);
err("Out of memory during hid input probe"); err_hid("Out of memory during hid input probe");
return -1; return -1;
} }
......
...@@ -60,6 +60,12 @@ MODULE_PARM_DESC(quirks, "Add/modify USB HID quirks by specifying " ...@@ -60,6 +60,12 @@ MODULE_PARM_DESC(quirks, "Add/modify USB HID quirks by specifying "
" quirks=vendorID:productID:quirks" " quirks=vendorID:productID:quirks"
" where vendorID, productID, and quirks are all in" " where vendorID, productID, and quirks are all in"
" 0x-prefixed hex"); " 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. * Input submission and I/O error handler.
*/ */
...@@ -127,7 +133,7 @@ static void hid_reset(struct work_struct *work) ...@@ -127,7 +133,7 @@ static void hid_reset(struct work_struct *work)
hid_io_error(hid); hid_io_error(hid);
break; break;
default: 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)->bus->bus_name,
hid_to_usb_dev(hid)->devpath, hid_to_usb_dev(hid)->devpath,
usbhid->ifnum, rc); usbhid->ifnum, rc);
...@@ -220,7 +226,7 @@ static void hid_irq_in(struct urb *urb) ...@@ -220,7 +226,7 @@ static void hid_irq_in(struct urb *urb)
if (status) { if (status) {
clear_bit(HID_IN_RUNNING, &usbhid->iofl); clear_bit(HID_IN_RUNNING, &usbhid->iofl);
if (status != -EPERM) { 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)->bus->bus_name,
hid_to_usb_dev(hid)->devpath, hid_to_usb_dev(hid)->devpath,
usbhid->ifnum, status); usbhid->ifnum, status);
...@@ -240,10 +246,10 @@ static int hid_submit_out(struct hid_device *hid) ...@@ -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->transfer_buffer_length = ((report->size - 1) >> 3) + 1 + (report->id > 0);
usbhid->urbout->dev = hid_to_usb_dev(hid); 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)) { if (usb_submit_urb(usbhid->urbout, GFP_ATOMIC)) {
err("usb_submit_urb(out) failed"); err_hid("usb_submit_urb(out) failed");
return -1; return -1;
} }
...@@ -287,12 +293,12 @@ static int hid_submit_ctrl(struct hid_device *hid) ...@@ -287,12 +293,12 @@ static int hid_submit_ctrl(struct hid_device *hid)
usbhid->cr->wIndex = cpu_to_le16(usbhid->ifnum); usbhid->cr->wIndex = cpu_to_le16(usbhid->ifnum);
usbhid->cr->wLength = cpu_to_le16(len); 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->bRequest == HID_REQ_SET_REPORT ? "Set_Report" : "Get_Report",
usbhid->cr->wValue, usbhid->cr->wIndex, usbhid->cr->wLength); usbhid->cr->wValue, usbhid->cr->wIndex, usbhid->cr->wLength);
if (usb_submit_urb(usbhid->urbctrl, GFP_ATOMIC)) { if (usb_submit_urb(usbhid->urbctrl, GFP_ATOMIC)) {
err("usb_submit_urb(ctrl) failed"); err_hid("usb_submit_urb(ctrl) failed");
return -1; return -1;
} }
...@@ -474,7 +480,7 @@ int usbhid_wait_io(struct hid_device *hid) ...@@ -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) && if (!wait_event_timeout(hid->wait, (!test_bit(HID_CTRL_RUNNING, &usbhid->iofl) &&
!test_bit(HID_OUT_RUNNING, &usbhid->iofl)), !test_bit(HID_OUT_RUNNING, &usbhid->iofl)),
10*HZ)) { 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; return -1;
} }
...@@ -632,20 +638,6 @@ static void hid_free_buffers(struct usb_device *dev, struct hid_device *hid) ...@@ -632,20 +638,6 @@ static void hid_free_buffers(struct usb_device *dev, struct hid_device *hid)
usb_buffer_free(dev, usbhid->bufsize, usbhid->ctrlbuf, usbhid->ctrlbuf_dma); usb_buffer_free(dev, usbhid->bufsize, usbhid->ctrlbuf, usbhid->ctrlbuf_dma);
} }
/*
* 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 * Sending HID_REQ_GET_REPORT changes the operation mode of the ps3 controller
* to "operational". Without this, the ps3 controller will not report any * to "operational". Without this, the ps3 controller will not report any
...@@ -667,51 +659,11 @@ static void hid_fixup_sony_ps3_controller(struct usb_device *dev, int ifnum) ...@@ -667,51 +659,11 @@ static void hid_fixup_sony_ps3_controller(struct usb_device *dev, int ifnum)
USB_CTRL_GET_TIMEOUT); USB_CTRL_GET_TIMEOUT);
if (result < 0) if (result < 0)
err("%s failed: %d\n", __func__, result); err_hid("%s failed: %d\n", __func__, result);
kfree(buf); 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) static struct hid_device *usb_hid_configure(struct usb_interface *intf)
{ {
struct usb_host_interface *interface = intf->cur_altsetting; struct usb_host_interface *interface = intf->cur_altsetting;
...@@ -746,7 +698,7 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf) ...@@ -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) && if (usb_get_extra_descriptor(interface, HID_DT_HID, &hdesc) &&
(!interface->desc.bNumEndpoints || (!interface->desc.bNumEndpoints ||
usb_get_extra_descriptor(&interface->endpoint[0], HID_DT_HID, &hdesc))) { 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; return NULL;
} }
...@@ -755,41 +707,34 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf) ...@@ -755,41 +707,34 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf)
rsize = le16_to_cpu(hdesc->desc[n].wDescriptorLength); rsize = le16_to_cpu(hdesc->desc[n].wDescriptorLength);
if (!rsize || rsize > HID_MAX_DESCRIPTOR_SIZE) { 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; return NULL;
} }
if (!(rdesc = kmalloc(rsize, GFP_KERNEL))) { if (!(rdesc = kmalloc(rsize, GFP_KERNEL))) {
dbg("couldn't allocate rdesc memory"); dbg_hid("couldn't allocate rdesc memory\n");
return NULL; return NULL;
} }
hid_set_idle(dev, interface->desc.bInterfaceNumber, 0, 0); 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) { 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); kfree(rdesc);
return NULL; return NULL;
} }
if ((quirks & HID_QUIRK_CYMOTION)) usbhid_fixup_report_descriptor(le16_to_cpu(dev->descriptor.idVendor),
hid_fixup_cymotion_descriptor(rdesc, rsize); le16_to_cpu(dev->descriptor.idProduct), rdesc,
rsize, rdesc_quirks_param);
if (quirks & HID_QUIRK_LOGITECH_DESCRIPTOR) dbg_hid("report descriptor (size %u, read %d) = ", rsize, n);
hid_fixup_logitech_descriptor(rdesc, rsize);
if (quirks & HID_QUIRK_SWAPPED_MIN_MAX)
hid_fixup_cypress_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++) for (n = 0; n < rsize; n++)
printk(" %02x", (unsigned char) rdesc[n]); dbg_hid_line(" %02x", (unsigned char) rdesc[n]);
printk("\n"); dbg_hid_line("\n");
#endif
if (!(hid = hid_parse_report(rdesc, n))) { if (!(hid = hid_parse_report(rdesc, n))) {
dbg("parsing report descriptor failed"); dbg_hid("parsing report descriptor failed\n");
kfree(rdesc); kfree(rdesc);
return NULL; return NULL;
} }
...@@ -861,7 +806,7 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf) ...@@ -861,7 +806,7 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf)
} }
if (!usbhid->urbin) { if (!usbhid->urbin) {
err("couldn't find an input interrupt endpoint"); err_hid("couldn't find an input interrupt endpoint");
goto fail; goto fail;
} }
...@@ -956,7 +901,7 @@ static void hid_disconnect(struct usb_interface *intf) ...@@ -956,7 +901,7 @@ static void hid_disconnect(struct usb_interface *intf)
usb_kill_urb(usbhid->urbctrl); usb_kill_urb(usbhid->urbctrl);
del_timer_sync(&usbhid->io_retry); del_timer_sync(&usbhid->io_retry);
flush_scheduled_work(); cancel_work_sync(&usbhid->reset_work);
if (hid->claimed & HID_CLAIMED_INPUT) if (hid->claimed & HID_CLAIMED_INPUT)
hidinput_disconnect(hid); hidinput_disconnect(hid);
...@@ -978,7 +923,7 @@ static int hid_probe(struct usb_interface *intf, const struct usb_device_id *id) ...@@ -978,7 +923,7 @@ static int hid_probe(struct usb_interface *intf, const struct usb_device_id *id)
int i; int i;
char *c; char *c;
dbg("HID probe called for ifnum %d", dbg_hid("HID probe called for ifnum %d\n",
intf->altsetting->desc.bInterfaceNumber); intf->altsetting->desc.bInterfaceNumber);
if (!(hid = usb_hid_configure(intf))) if (!(hid = usb_hid_configure(intf)))
......
...@@ -78,7 +78,7 @@ static int hid_lgff_play(struct input_dev *dev, void *data, struct ff_effect *ef ...@@ -78,7 +78,7 @@ static int hid_lgff_play(struct input_dev *dev, void *data, struct ff_effect *ef
report->field[0]->value[1] = 0x08; report->field[0]->value[1] = 0x08;
report->field[0]->value[2] = x; report->field[0]->value[2] = x;
report->field[0]->value[3] = y; report->field[0]->value[3] = y;
dbg("(x, y)=(%04x, %04x)", x, y); dbg_hid("(x, y)=(%04x, %04x)\n", x, y);
usbhid_submit_report(hid, report, USB_DIR_OUT); usbhid_submit_report(hid, report, USB_DIR_OUT);
break; break;
...@@ -93,7 +93,7 @@ static int hid_lgff_play(struct input_dev *dev, void *data, struct ff_effect *ef ...@@ -93,7 +93,7 @@ static int hid_lgff_play(struct input_dev *dev, void *data, struct ff_effect *ef
report->field[0]->value[1] = 0x00; report->field[0]->value[1] = 0x00;
report->field[0]->value[2] = left; report->field[0]->value[2] = left;
report->field[0]->value[3] = right; report->field[0]->value[3] = right;
dbg("(left, right)=(%04x, %04x)", left, right); dbg_hid("(left, right)=(%04x, %04x)\n", left, right);
usbhid_submit_report(hid, report, USB_DIR_OUT); usbhid_submit_report(hid, report, USB_DIR_OUT);
break; break;
} }
...@@ -113,20 +113,20 @@ int hid_lgff_init(struct hid_device* hid) ...@@ -113,20 +113,20 @@ int hid_lgff_init(struct hid_device* hid)
/* Find the report to use */ /* Find the report to use */
if (list_empty(report_list)) { if (list_empty(report_list)) {
err("No output report found"); err_hid("No output report found");
return -1; return -1;
} }
/* Check that the report looks ok */ /* Check that the report looks ok */
report = list_entry(report_list->next, struct hid_report, list); report = list_entry(report_list->next, struct hid_report, list);
if (!report) { if (!report) {
err("NULL output report"); err_hid("NULL output report");
return -1; return -1;
} }
field = report->field[0]; field = report->field[0];
if (!field) { if (!field) {
err("NULL field"); err_hid("NULL field");
return -1; return -1;
} }
......
...@@ -738,6 +738,7 @@ static void pidff_autocenter(struct pidff_device *pidff, u16 magnitude) ...@@ -738,6 +738,7 @@ static void pidff_autocenter(struct pidff_device *pidff, u16 magnitude)
pidff->set_effect[PID_TRIGGER_BUTTON].value[0] = 0; pidff->set_effect[PID_TRIGGER_BUTTON].value[0] = 0;
pidff->set_effect[PID_TRIGGER_REPEAT_INT].value[0] = 0; pidff->set_effect[PID_TRIGGER_REPEAT_INT].value[0] = 0;
pidff_set(&pidff->set_effect[PID_GAIN], magnitude); pidff_set(&pidff->set_effect[PID_GAIN], magnitude);
pidff->set_effect[PID_DIRECTION_ENABLE].value[0] = 1;
pidff->set_effect[PID_START_DELAY].value[0] = 0; pidff->set_effect[PID_START_DELAY].value[0] = 0;
usbhid_submit_report(pidff->hid, pidff->reports[PID_SET_EFFECT], usbhid_submit_report(pidff->hid, pidff->reports[PID_SET_EFFECT],
......
This diff is collapsed.
...@@ -70,7 +70,7 @@ static int hid_tmff_play(struct input_dev *dev, void *data, struct ff_effect *ef ...@@ -70,7 +70,7 @@ static int hid_tmff_play(struct input_dev *dev, void *data, struct ff_effect *ef
tmff->rumble->value[0] = left; tmff->rumble->value[0] = left;
tmff->rumble->value[1] = right; tmff->rumble->value[1] = right;
dbg("(left,right)=(%08x, %08x)", left, right); dbg_hid("(left,right)=(%08x, %08x)\n", left, right);
usbhid_submit_report(hid, tmff->report, USB_DIR_OUT); usbhid_submit_report(hid, tmff->report, USB_DIR_OUT);
return 0; return 0;
......
...@@ -21,10 +21,6 @@ ...@@ -21,10 +21,6 @@
*/ */
/* #define DEBUG */
#define debug(format, arg...) pr_debug("hid-zpff: " format "\n" , ## arg)
#include <linux/input.h> #include <linux/input.h>
#include <linux/usb.h> #include <linux/usb.h>
#include <linux/hid.h> #include <linux/hid.h>
...@@ -49,14 +45,14 @@ static int hid_zpff_play(struct input_dev *dev, void *data, ...@@ -49,14 +45,14 @@ static int hid_zpff_play(struct input_dev *dev, void *data,
left = effect->u.rumble.strong_magnitude; left = effect->u.rumble.strong_magnitude;
right = effect->u.rumble.weak_magnitude; right = effect->u.rumble.weak_magnitude;
debug("called with 0x%04x 0x%04x", left, right); dbg_hid("called with 0x%04x 0x%04x\n", left, right);
left = left * 0x7f / 0xffff; left = left * 0x7f / 0xffff;
right = right * 0x7f / 0xffff; right = right * 0x7f / 0xffff;
zpff->report->field[2]->value[0] = left; zpff->report->field[2]->value[0] = left;
zpff->report->field[3]->value[0] = right; zpff->report->field[3]->value[0] = right;
debug("running with 0x%02x 0x%02x", left, right); dbg_hid("running with 0x%02x 0x%02x\n", left, right);
usbhid_submit_report(hid, zpff->report, USB_DIR_OUT); usbhid_submit_report(hid, zpff->report, USB_DIR_OUT);
return 0; return 0;
......
...@@ -779,7 +779,7 @@ int hiddev_connect(struct hid_device *hid) ...@@ -779,7 +779,7 @@ int hiddev_connect(struct hid_device *hid)
retval = usb_register_dev(usbhid->intf, &hiddev_class); retval = usb_register_dev(usbhid->intf, &hiddev_class);
if (retval) { if (retval) {
err("Not able to get a minor for this device."); err_hid("Not able to get a minor for this device.");
kfree(hiddev); kfree(hiddev);
return -1; return -1;
} }
......
...@@ -125,7 +125,7 @@ static void usb_kbd_irq(struct urb *urb) ...@@ -125,7 +125,7 @@ static void usb_kbd_irq(struct urb *urb)
resubmit: resubmit:
i = usb_submit_urb (urb, GFP_ATOMIC); i = usb_submit_urb (urb, GFP_ATOMIC);
if (i) if (i)
err ("can't resubmit intr, %s-%s/input0, status %d", err_hid ("can't resubmit intr, %s-%s/input0, status %d",
kbd->usbdev->bus->bus_name, kbd->usbdev->bus->bus_name,
kbd->usbdev->devpath, i); kbd->usbdev->devpath, i);
} }
...@@ -151,7 +151,7 @@ static int usb_kbd_event(struct input_dev *dev, unsigned int type, ...@@ -151,7 +151,7 @@ static int usb_kbd_event(struct input_dev *dev, unsigned int type,
*(kbd->leds) = kbd->newleds; *(kbd->leds) = kbd->newleds;
kbd->led->dev = kbd->usbdev; kbd->led->dev = kbd->usbdev;
if (usb_submit_urb(kbd->led, GFP_ATOMIC)) if (usb_submit_urb(kbd->led, GFP_ATOMIC))
err("usb_submit_urb(leds) failed"); err_hid("usb_submit_urb(leds) failed");
return 0; return 0;
} }
...@@ -169,7 +169,7 @@ static void usb_kbd_led(struct urb *urb) ...@@ -169,7 +169,7 @@ static void usb_kbd_led(struct urb *urb)
*(kbd->leds) = kbd->newleds; *(kbd->leds) = kbd->newleds;
kbd->led->dev = kbd->usbdev; kbd->led->dev = kbd->usbdev;
if (usb_submit_urb(kbd->led, GFP_ATOMIC)) if (usb_submit_urb(kbd->led, GFP_ATOMIC))
err("usb_submit_urb(leds) failed"); err_hid("usb_submit_urb(leds) failed");
} }
static int usb_kbd_open(struct input_dev *dev) static int usb_kbd_open(struct input_dev *dev)
......
...@@ -263,19 +263,28 @@ struct hid_item { ...@@ -263,19 +263,28 @@ struct hid_item {
#define HID_QUIRK_2WHEEL_MOUSE_HACK_5 0x00000100 #define HID_QUIRK_2WHEEL_MOUSE_HACK_5 0x00000100
#define HID_QUIRK_2WHEEL_MOUSE_HACK_ON 0x00000200 #define HID_QUIRK_2WHEEL_MOUSE_HACK_ON 0x00000200
#define HID_QUIRK_MIGHTYMOUSE 0x00000400 #define HID_QUIRK_MIGHTYMOUSE 0x00000400
#define HID_QUIRK_CYMOTION 0x00000800 #define HID_QUIRK_POWERBOOK_HAS_FN 0x00000800
#define HID_QUIRK_POWERBOOK_HAS_FN 0x00001000 #define HID_QUIRK_POWERBOOK_FN_ON 0x00001000
#define HID_QUIRK_POWERBOOK_FN_ON 0x00002000 #define HID_QUIRK_INVERT_HWHEEL 0x00002000
#define HID_QUIRK_INVERT_HWHEEL 0x00004000 #define HID_QUIRK_POWERBOOK_ISO_KEYBOARD 0x00004000
#define HID_QUIRK_POWERBOOK_ISO_KEYBOARD 0x00008000 #define HID_QUIRK_BAD_RELATIVE_KEYS 0x00008000
#define HID_QUIRK_BAD_RELATIVE_KEYS 0x00010000 #define HID_QUIRK_SKIP_OUTPUT_REPORTS 0x00010000
#define HID_QUIRK_SKIP_OUTPUT_REPORTS 0x00020000 #define HID_QUIRK_IGNORE_MOUSE 0x00020000
#define HID_QUIRK_IGNORE_MOUSE 0x00040000 #define HID_QUIRK_SONY_PS3_CONTROLLER 0x00040000
#define HID_QUIRK_SONY_PS3_CONTROLLER 0x00080000 #define HID_QUIRK_DUPLICATE_USAGES 0x00080000
#define HID_QUIRK_LOGITECH_DESCRIPTOR 0x00100000 #define HID_QUIRK_RESET_LEDS 0x00100000
#define HID_QUIRK_DUPLICATE_USAGES 0x00200000 #define HID_QUIRK_HIDINPUT 0x00200000
#define HID_QUIRK_RESET_LEDS 0x00400000 #define HID_QUIRK_LOGITECH_IGNORE_DOUBLED_WHEEL 0x00400000
#define HID_QUIRK_SWAPPED_MIN_MAX 0x00800000 #define HID_QUIRK_LOGITECH_EXPANDED_KEYMAP 0x00800000
/*
* Separate quirks for runtime report descriptor fixup
*/
#define HID_QUIRK_RDESC_CYMOTION 0x00000001
#define HID_QUIRK_RDESC_LOGITECH 0x00000002
#define HID_QUIRK_RDESC_SWAPPED_MIN_MAX 0x00000004
#define HID_QUIRK_RDESC_PETALYNX 0x00000008
/* /*
* This is the global environment of the parser. This information is * This is the global environment of the parser. This information is
...@@ -488,6 +497,11 @@ struct hid_descriptor { ...@@ -488,6 +497,11 @@ struct hid_descriptor {
#define IS_INPUT_APPLICATION(a) (((a >= 0x00010000) && (a <= 0x00010008)) || (a == 0x00010080) || (a == 0x000c0001)) #define IS_INPUT_APPLICATION(a) (((a >= 0x00010000) && (a <= 0x00010008)) || (a == 0x00010080) || (a == 0x000c0001))
/* HID core API */ /* HID core API */
#ifdef CONFIG_HID_DEBUG
extern int hid_debug;
#endif
extern void hidinput_hid_event(struct hid_device *, struct hid_field *, struct hid_usage *, __s32); extern void hidinput_hid_event(struct hid_device *, struct hid_field *, struct hid_usage *, __s32);
extern void hidinput_report_event(struct hid_device *hid, struct hid_report *report); extern void hidinput_report_event(struct hid_device *hid, struct hid_report *report);
extern int hidinput_connect(struct hid_device *); extern int hidinput_connect(struct hid_device *);
...@@ -506,6 +520,7 @@ u32 usbhid_lookup_quirk(const u16 idVendor, const u16 idProduct); ...@@ -506,6 +520,7 @@ u32 usbhid_lookup_quirk(const u16 idVendor, const u16 idProduct);
int usbhid_modify_dquirk(const u16 idVendor, const u16 idProduct, const u32 quirks); int usbhid_modify_dquirk(const u16 idVendor, const u16 idProduct, const u32 quirks);
int usbhid_quirks_init(char **quirks_param); int usbhid_quirks_init(char **quirks_param);
void usbhid_quirks_exit(void); void usbhid_quirks_exit(void);
void usbhid_fixup_report_descriptor(const u16, const u16, char *, unsigned, char **);
#ifdef CONFIG_HID_FF #ifdef CONFIG_HID_FF
int hid_ff_init(struct hid_device *hid); int hid_ff_init(struct hid_device *hid);
...@@ -523,14 +538,19 @@ static inline int hid_pidff_init(struct hid_device *hid) { return -ENODEV; } ...@@ -523,14 +538,19 @@ static inline int hid_pidff_init(struct hid_device *hid) { return -ENODEV; }
#else #else
static inline int hid_ff_init(struct hid_device *hid) { return -1; } static inline int hid_ff_init(struct hid_device *hid) { return -1; }
#endif #endif
#ifdef DEBUG
#define dbg(format, arg...) printk(KERN_DEBUG "%s: " format "\n" , \ #ifdef CONFIG_HID_DEBUG
__FILE__ , ## arg) #define dbg_hid(format, arg...) if (hid_debug) \
printk(KERN_DEBUG "%s: " format ,\
__FILE__ , ## arg)
#define dbg_hid_line(format, arg...) if (hid_debug) \
printk(format, ## arg)
#else #else
#define dbg(format, arg...) do {} while (0) #define dbg_hid(format, arg...) do {} while (0)
#define dbg_hid_line dbg_hid
#endif #endif
#define err(format, arg...) printk(KERN_ERR "%s: " format "\n" , \ #define err_hid(format, arg...) printk(KERN_ERR "%s: " format "\n" , \
__FILE__ , ## arg) __FILE__ , ## arg)
#endif #endif
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