From 5f22a7992349c5ca3842190be52d5e9a1dd7adf4 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Fri, 16 May 2008 11:49:19 +0200 Subject: HID: move logitech quirks Move them from the core and input code to a separate driver. Signed-off-by: Jiri Slaby Signed-off-by: Jiri Kosina --- drivers/hid/Kconfig | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'drivers/hid/Kconfig') diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index cacf89e65af..066e8c08c26 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -67,4 +67,17 @@ config HIDRAW source "drivers/hid/usbhid/Kconfig" +menu "Special HID drivers" + depends on HID + +config HID_LOGITECH + tristate "Logitech" + default m + depends on USB_HID + ---help--- + Support for some Logitech devices which breaks less or more + HID specification. + +endmenu + endif # HID_SUPPORT -- cgit v1.2.3-70-g09d2 From 8c19a51591d06f5226499972567f528cf6066bb7 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Wed, 18 Jun 2008 23:36:49 +0200 Subject: HID: move apple quirks Move them from the core code to a separate driver. Signed-off-by: Jiri Slaby Signed-off-by: Jiri Kosina --- drivers/hid/Kconfig | 14 ++ drivers/hid/Makefile | 1 + drivers/hid/hid-apple.c | 479 ++++++++++++++++++++++++++++++++++++++++ drivers/hid/hid-core.c | 32 +++ drivers/hid/hid-input-quirks.c | 8 - drivers/hid/hid-input.c | 221 +----------------- drivers/hid/usbhid/Kconfig | 11 - drivers/hid/usbhid/hid-core.c | 4 - drivers/hid/usbhid/hid-quirks.c | 49 ---- drivers/hid/usbhid/usbmouse.c | 5 + include/linux/hid.h | 13 -- net/bluetooth/hidp/core.c | 22 -- 12 files changed, 532 insertions(+), 327 deletions(-) create mode 100644 drivers/hid/hid-apple.c (limited to 'drivers/hid/Kconfig') diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index 066e8c08c26..41283fff514 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -70,6 +70,20 @@ source "drivers/hid/usbhid/Kconfig" menu "Special HID drivers" depends on HID +config HID_APPLE + tristate "Apple" + default m + depends on (USB_HID || BT_HIDP) + ---help--- + Support for some Apple devices which less or more break + HID specification. + + Say Y here if you want support for the special keys (Fn, Numlock) on + Apple iBooks, PowerBooks, MacBooks, MacBook Pros and aluminum USB + keyboards. + + If unsure, say M. + config HID_LOGITECH tristate "Logitech" default m diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile index cae036bfe83..4a14821ceef 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile @@ -8,6 +8,7 @@ obj-$(CONFIG_HID) += hid.o hid-$(CONFIG_HID_DEBUG) += hid-debug.o hid-$(CONFIG_HIDRAW) += hidraw.o +obj-$(CONFIG_HID_APPLE) += hid-apple.o obj-$(CONFIG_HID_LOGITECH) += hid-logitech.o obj-$(CONFIG_USB_HID) += usbhid/ diff --git a/drivers/hid/hid-apple.c b/drivers/hid/hid-apple.c new file mode 100644 index 00000000000..5642e2c685f --- /dev/null +++ b/drivers/hid/hid-apple.c @@ -0,0 +1,479 @@ +/* + * USB HID quirks support for Linux + * + * Copyright (c) 1999 Andreas Gal + * Copyright (c) 2000-2005 Vojtech Pavlik + * Copyright (c) 2005 Michael Haboustak for Concept2, Inc + * Copyright (c) 2006-2007 Jiri Kosina + * Copyright (c) 2007 Paul Walmsley + * Copyright (c) 2008 Jiri Slaby + */ + +/* + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + */ + +#include +#include +#include +#include + +#include "hid-ids.h" + +#define APPLE_RDESC_JIS 0x0001 +#define APPLE_IGNORE_MOUSE 0x0002 +#define APPLE_HAS_FN 0x0004 +#define APPLE_HIDDEV 0x0008 +#define APPLE_ISO_KEYBOARD 0x0010 +#define APPLE_MIGHTYMOUSE 0x0020 +#define APPLE_INVERT_HWHEEL 0x0040 +#define APPLE_IGNORE_HIDINPUT 0x0080 +#define APPLE_NUMLOCK_EMULATION 0x0100 + +#define APPLE_FLAG_FKEY 0x01 + +static unsigned int fnmode = 1; +module_param(fnmode, uint, 0644); +MODULE_PARM_DESC(fnmode, "Mode of fn key on Apple keyboards (0 = disabled, " + "[1] = fkeyslast, 2 = fkeysfirst)"); + +struct apple_sc { + unsigned long quirks; + unsigned int fn_on; + DECLARE_BITMAP(pressed_fn, KEY_CNT); + DECLARE_BITMAP(pressed_numlock, KEY_CNT); +}; + +struct apple_key_translation { + u16 from; + u16 to; + u8 flags; +}; + +static struct apple_key_translation apple_fn_keys[] = { + { KEY_BACKSPACE, KEY_DELETE }, + { KEY_F1, KEY_BRIGHTNESSDOWN, APPLE_FLAG_FKEY }, + { KEY_F2, KEY_BRIGHTNESSUP, APPLE_FLAG_FKEY }, + { KEY_F3, KEY_FN_F5, APPLE_FLAG_FKEY }, /* Exposé */ + { KEY_F4, KEY_FN_F4, APPLE_FLAG_FKEY }, /* Dashboard */ + { KEY_F5, KEY_KBDILLUMDOWN, APPLE_FLAG_FKEY }, + { KEY_F6, KEY_KBDILLUMUP, APPLE_FLAG_FKEY }, + { KEY_F7, KEY_PREVIOUSSONG, APPLE_FLAG_FKEY }, + { KEY_F8, KEY_PLAYPAUSE, APPLE_FLAG_FKEY }, + { KEY_F9, KEY_NEXTSONG, APPLE_FLAG_FKEY }, + { KEY_F10, KEY_MUTE, APPLE_FLAG_FKEY }, + { KEY_F11, KEY_VOLUMEDOWN, APPLE_FLAG_FKEY }, + { KEY_F12, KEY_VOLUMEUP, APPLE_FLAG_FKEY }, + { KEY_UP, KEY_PAGEUP }, + { KEY_DOWN, KEY_PAGEDOWN }, + { KEY_LEFT, KEY_HOME }, + { KEY_RIGHT, KEY_END }, + { } +}; + +static struct apple_key_translation powerbook_fn_keys[] = { + { KEY_BACKSPACE, KEY_DELETE }, + { KEY_F1, KEY_BRIGHTNESSDOWN, APPLE_FLAG_FKEY }, + { KEY_F2, KEY_BRIGHTNESSUP, APPLE_FLAG_FKEY }, + { KEY_F3, KEY_MUTE, APPLE_FLAG_FKEY }, + { KEY_F4, KEY_VOLUMEDOWN, APPLE_FLAG_FKEY }, + { KEY_F5, KEY_VOLUMEUP, APPLE_FLAG_FKEY }, + { KEY_F6, KEY_NUMLOCK, APPLE_FLAG_FKEY }, + { KEY_F7, KEY_SWITCHVIDEOMODE, APPLE_FLAG_FKEY }, + { KEY_F8, KEY_KBDILLUMTOGGLE, APPLE_FLAG_FKEY }, + { KEY_F9, KEY_KBDILLUMDOWN, APPLE_FLAG_FKEY }, + { KEY_F10, KEY_KBDILLUMUP, APPLE_FLAG_FKEY }, + { KEY_UP, KEY_PAGEUP }, + { KEY_DOWN, KEY_PAGEDOWN }, + { KEY_LEFT, KEY_HOME }, + { KEY_RIGHT, KEY_END }, + { } +}; + +static struct apple_key_translation powerbook_numlock_keys[] = { + { KEY_J, KEY_KP1 }, + { KEY_K, KEY_KP2 }, + { KEY_L, KEY_KP3 }, + { KEY_U, KEY_KP4 }, + { KEY_I, KEY_KP5 }, + { KEY_O, KEY_KP6 }, + { KEY_7, KEY_KP7 }, + { KEY_8, KEY_KP8 }, + { KEY_9, KEY_KP9 }, + { KEY_M, KEY_KP0 }, + { KEY_DOT, KEY_KPDOT }, + { KEY_SLASH, KEY_KPPLUS }, + { KEY_SEMICOLON, KEY_KPMINUS }, + { KEY_P, KEY_KPASTERISK }, + { KEY_MINUS, KEY_KPEQUAL }, + { KEY_0, KEY_KPSLASH }, + { KEY_F6, KEY_NUMLOCK }, + { KEY_KPENTER, KEY_KPENTER }, + { KEY_BACKSPACE, KEY_BACKSPACE }, + { } +}; + +static struct apple_key_translation apple_iso_keyboard[] = { + { KEY_GRAVE, KEY_102ND }, + { KEY_102ND, KEY_GRAVE }, + { } +}; + +static struct apple_key_translation *apple_find_translation( + struct apple_key_translation *table, u16 from) +{ + struct apple_key_translation *trans; + + /* Look for the translation */ + for (trans = table; trans->from; trans++) + if (trans->from == from) + return trans; + + return NULL; +} + +static int hidinput_apple_event(struct hid_device *hid, struct input_dev *input, + struct hid_usage *usage, __s32 value) +{ + struct apple_sc *asc = hid_get_drvdata(hid); + struct apple_key_translation *trans; + + if (usage->code == KEY_FN) { + asc->fn_on = !!value; + input_event(input, usage->type, usage->code, value); + return 1; + } + + if (fnmode) { + int do_translate; + + trans = apple_find_translation((hid->product < 0x220 || + hid->product >= 0x300) ? + powerbook_fn_keys : apple_fn_keys, + usage->code); + if (trans) { + if (test_bit(usage->code, asc->pressed_fn)) + do_translate = 1; + else if (trans->flags & APPLE_FLAG_FKEY) + do_translate = (fnmode == 2 && asc->fn_on) || + (fnmode == 1 && !asc->fn_on); + else + do_translate = asc->fn_on; + + if (do_translate) { + if (value) + set_bit(usage->code, asc->pressed_fn); + else + clear_bit(usage->code, asc->pressed_fn); + + input_event(input, usage->type, trans->to, + value); + + return 1; + } + } + + if (asc->quirks & APPLE_NUMLOCK_EMULATION && + (test_bit(usage->code, asc->pressed_numlock) || + test_bit(LED_NUML, input->led))) { + trans = apple_find_translation(powerbook_numlock_keys, + usage->code); + + if (trans) { + if (value) + set_bit(usage->code, + asc->pressed_numlock); + else + clear_bit(usage->code, + asc->pressed_numlock); + + input_event(input, usage->type, trans->to, + value); + } + + return 1; + } + } + + if (asc->quirks & APPLE_ISO_KEYBOARD) { + trans = apple_find_translation(apple_iso_keyboard, usage->code); + if (trans) { + input_event(input, usage->type, trans->to, value); + return 1; + } + } + + return 0; +} + +static int apple_event(struct hid_device *hdev, struct hid_field *field, + struct hid_usage *usage, __s32 value) +{ + struct apple_sc *asc = hid_get_drvdata(hdev); + + if (!(hdev->claimed & HID_CLAIMED_INPUT) || !field->hidinput || + !usage->type) + return 0; + + if ((asc->quirks & APPLE_INVERT_HWHEEL) && + usage->code == REL_HWHEEL) { + input_event(field->hidinput->input, usage->type, usage->code, + -value); + return 1; + } + + if ((asc->quirks & APPLE_HAS_FN) && + hidinput_apple_event(hdev, field->hidinput->input, + usage, value)) + return 1; + + + return 0; +} + +/* + * MacBook JIS keyboard has wrong logical maximum + */ +static void apple_report_fixup(struct hid_device *hdev, __u8 *rdesc, + unsigned int rsize) +{ + struct apple_sc *asc = hid_get_drvdata(hdev); + + if ((asc->quirks & APPLE_RDESC_JIS) && rsize >= 60 && + rdesc[53] == 0x65 && rdesc[59] == 0x65) { + dev_info(&hdev->dev, "fixing up MacBook JIS keyboard report " + "descriptor\n"); + rdesc[53] = rdesc[59] = 0xe7; + } +} + +static void apple_setup_input(struct input_dev *input) +{ + struct apple_key_translation *trans; + + set_bit(KEY_NUMLOCK, input->keybit); + + /* Enable all needed keys */ + for (trans = apple_fn_keys; trans->from; trans++) + set_bit(trans->to, input->keybit); + + for (trans = powerbook_fn_keys; trans->from; trans++) + set_bit(trans->to, input->keybit); + + for (trans = powerbook_numlock_keys; trans->from; trans++) + set_bit(trans->to, input->keybit); + + for (trans = apple_iso_keyboard; trans->from; trans++) + set_bit(trans->to, input->keybit); +} + +static int apple_input_mapping(struct hid_device *hdev, struct hid_input *hi, + struct hid_field *field, struct hid_usage *usage, + unsigned long **bit, int *max) +{ + if (usage->hid == (HID_UP_CUSTOM | 0x0003)) { + /* The fn key on Apple USB keyboards */ + set_bit(EV_REP, hi->input->evbit); + hid_map_usage_clear(hi, usage, bit, max, EV_KEY, KEY_FN); + apple_setup_input(hi->input); + return 1; + } + + /* we want the hid layer to go through standard path (set and ignore) */ + return 0; +} + +static int apple_input_mapped(struct hid_device *hdev, struct hid_input *hi, + struct hid_field *field, struct hid_usage *usage, + unsigned long **bit, int *max) +{ + struct apple_sc *asc = hid_get_drvdata(hdev); + + if (asc->quirks & APPLE_MIGHTYMOUSE) { + if (usage->hid == HID_GD_Z) + hid_map_usage(hi, usage, bit, max, EV_REL, REL_HWHEEL); + else if (usage->code == BTN_1) + hid_map_usage(hi, usage, bit, max, EV_KEY, BTN_2); + else if (usage->code == BTN_2) + hid_map_usage(hi, usage, bit, max, EV_KEY, BTN_1); + } + + return 0; +} + +static int apple_probe(struct hid_device *hdev, + const struct hid_device_id *id) +{ + unsigned long quirks = id->driver_data; + struct apple_sc *asc; + int ret; + + /* return something else or move to hid layer? device will reside + allocated */ + if (id->bus == BUS_USB && (quirks & APPLE_IGNORE_MOUSE) && + to_usb_interface(hdev->dev.parent)->cur_altsetting-> + desc.bInterfaceProtocol == USB_INTERFACE_PROTOCOL_MOUSE) + return -ENODEV; + + asc = kzalloc(sizeof(*asc), GFP_KERNEL); + if (asc == NULL) { + dev_err(&hdev->dev, "can't alloc apple descriptor\n"); + return -ENOMEM; + } + + asc->quirks = quirks; + + hid_set_drvdata(hdev, asc); + + if (quirks & APPLE_HIDDEV) + hdev->quirks |= HID_QUIRK_HIDDEV; + if (quirks & APPLE_IGNORE_HIDINPUT) + hdev->quirks |= HID_QUIRK_IGNORE_HIDINPUT; + + ret = hid_parse(hdev); + if (ret) { + dev_err(&hdev->dev, "parse failed\n"); + goto err_free; + } + + ret = hid_hw_start(hdev); + if (ret) { + dev_err(&hdev->dev, "hw start failed\n"); + goto err_free; + } + + return 0; +err_free: + kfree(asc); + return ret; +} + +static void apple_remove(struct hid_device *hdev) +{ + hid_hw_stop(hdev); + kfree(hid_get_drvdata(hdev)); +} + +static const struct hid_device_id apple_devices[] = { + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL4), + .driver_data = APPLE_HIDDEV | APPLE_IGNORE_HIDINPUT }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MIGHTYMOUSE), + .driver_data = APPLE_MIGHTYMOUSE | APPLE_INVERT_HWHEEL }, + + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ANSI), + .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN | + APPLE_IGNORE_MOUSE }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ISO), + .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN | + APPLE_IGNORE_MOUSE }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_ANSI), + .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN | + APPLE_IGNORE_MOUSE }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_ISO), + .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN | + APPLE_IGNORE_MOUSE | APPLE_ISO_KEYBOARD }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_JIS), + .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN | + APPLE_IGNORE_MOUSE }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_ANSI), + .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN | + APPLE_IGNORE_MOUSE }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_ISO), + .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN | + APPLE_IGNORE_MOUSE | APPLE_ISO_KEYBOARD }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_JIS), + .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN | + APPLE_IGNORE_MOUSE }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_ANSI), + .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN | + APPLE_IGNORE_MOUSE }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_ISO), + .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN | + APPLE_IGNORE_MOUSE | APPLE_ISO_KEYBOARD }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_JIS), + .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN | + APPLE_IGNORE_MOUSE | APPLE_RDESC_JIS}, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_ANSI), + .driver_data = APPLE_HAS_FN }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_ISO), + .driver_data = APPLE_HAS_FN | APPLE_ISO_KEYBOARD }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_JIS), + .driver_data = APPLE_HAS_FN }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_HF_ANSI), + .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN | + APPLE_IGNORE_MOUSE }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_HF_ISO), + .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN | + APPLE_IGNORE_MOUSE }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_HF_JIS), + .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN | + APPLE_IGNORE_MOUSE }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_ANSI), + .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_ISO), + .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN | + APPLE_ISO_KEYBOARD }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_JIS), + .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING_ANSI), + .driver_data = APPLE_HAS_FN | APPLE_IGNORE_MOUSE }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING_ISO), + .driver_data = APPLE_HAS_FN | APPLE_ISO_KEYBOARD | + APPLE_IGNORE_MOUSE }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING_JIS), + .driver_data = APPLE_HAS_FN | APPLE_IGNORE_MOUSE }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING2_ANSI), + .driver_data = APPLE_HAS_FN | APPLE_IGNORE_MOUSE }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING2_ISO), + .driver_data = APPLE_HAS_FN | APPLE_ISO_KEYBOARD | + APPLE_IGNORE_MOUSE }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING2_JIS), + .driver_data = APPLE_HAS_FN | APPLE_IGNORE_MOUSE }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY), + .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN | + APPLE_IGNORE_MOUSE }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY), + .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN | + APPLE_IGNORE_MOUSE }, + + /* Apple wireless Mighty Mouse */ + { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, 0x030c), + .driver_data = APPLE_MIGHTYMOUSE | APPLE_INVERT_HWHEEL }, + + { } +}; +MODULE_DEVICE_TABLE(hid, apple_devices); + +static struct hid_driver apple_driver = { + .name = "apple", + .id_table = apple_devices, + .report_fixup = apple_report_fixup, + .probe = apple_probe, + .remove = apple_remove, + .event = apple_event, + .input_mapping = apple_input_mapping, + .input_mapped = apple_input_mapped, +}; + +static int apple_init(void) +{ + int ret; + + ret = hid_register_driver(&apple_driver); + if (ret) + printk(KERN_ERR "can't register apple driver\n"); + + return ret; +} + +static void apple_exit(void) +{ + hid_unregister_driver(&apple_driver); +} + +module_init(apple_init); +module_exit(apple_exit); +MODULE_LICENSE("GPL"); diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 08470ab295b..8e3c264c9b2 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1130,6 +1130,36 @@ static const struct hid_device_id *hid_match_id(struct hid_device *hdev, } static const struct hid_device_id hid_blacklist[] = { + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL4) }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MIGHTYMOUSE) }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ANSI) }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ISO) }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_ANSI) }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_ISO) }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_JIS) }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_ANSI) }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_ISO) }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_JIS) }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_ANSI) }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_ISO) }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_JIS) }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_ANSI) }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_ISO) }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_JIS) }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_HF_ANSI) }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_HF_ISO) }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_HF_JIS) }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_ANSI) }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_ISO) }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_JIS) }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING_ANSI) }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING_ISO) }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING_JIS) }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING2_ANSI) }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING2_ISO) }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING2_JIS) }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY) }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY) }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_MX3000_RECEIVER) }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER) }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER_2) }, @@ -1144,6 +1174,8 @@ static const struct hid_device_id hid_blacklist[] = { { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_V150) }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_EXTREME_3D) }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WHEEL) }, + + { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, 0x030c) }, { } }; diff --git a/drivers/hid/hid-input-quirks.c b/drivers/hid/hid-input-quirks.c index 10451ca3a78..878e193c6d7 100644 --- a/drivers/hid/hid-input-quirks.c +++ b/drivers/hid/hid-input-quirks.c @@ -331,19 +331,11 @@ int hidinput_event_quirks(struct hid_device *hid, struct hid_field *field, struc return 1; } - if ((hid->quirks & HID_QUIRK_INVERT_HWHEEL) && (usage->code == REL_HWHEEL)) { - input_event(input, usage->type, usage->code, -value); - return 1; - } - if ((hid->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_ON) && (usage->code == REL_WHEEL)) { input_event(input, usage->type, REL_HWHEEL, value); return 1; } - if ((hid->quirks & HID_QUIRK_APPLE_HAS_FN) && hidinput_apple_event(hid, input, usage, value)) - return 1; - /* Handling MS keyboards special buttons */ if (hid->quirks & HID_QUIRK_MICROSOFT_KEYS && usage->hid == (HID_UP_MSVENDOR | 0xff05)) { diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c index 4f2bac010f5..76ddf23f196 100644 --- a/drivers/hid/hid-input.c +++ b/drivers/hid/hid-input.c @@ -32,11 +32,6 @@ #include #include -static int hid_apple_fnmode = 1; -module_param_named(pb_fnmode, hid_apple_fnmode, int, 0644); -MODULE_PARM_DESC(pb_fnmode, - "Mode of fn key on Apple keyboards (0 = disabled, 1 = fkeyslast, 2 = fkeysfirst)"); - #define unk KEY_UNKNOWN static const unsigned char hid_keyboard[256] = { @@ -73,202 +68,6 @@ static const struct { #define map_key_clear(c) hid_map_usage_clear(hidinput, usage, &bit, \ &max, EV_KEY, (c)) -#ifdef CONFIG_USB_HIDINPUT_POWERBOOK - -struct hidinput_key_translation { - u16 from; - u16 to; - u8 flags; -}; - -#define APPLE_FLAG_FKEY 0x01 - -static struct hidinput_key_translation apple_fn_keys[] = { - { KEY_BACKSPACE, KEY_DELETE }, - { KEY_F1, KEY_BRIGHTNESSDOWN, APPLE_FLAG_FKEY }, - { KEY_F2, KEY_BRIGHTNESSUP, APPLE_FLAG_FKEY }, - { KEY_F3, KEY_FN_F5, APPLE_FLAG_FKEY }, /* Exposé */ - { KEY_F4, KEY_FN_F4, APPLE_FLAG_FKEY }, /* Dashboard */ - { KEY_F5, KEY_KBDILLUMDOWN, APPLE_FLAG_FKEY }, - { KEY_F6, KEY_KBDILLUMUP, APPLE_FLAG_FKEY }, - { KEY_F7, KEY_PREVIOUSSONG, APPLE_FLAG_FKEY }, - { KEY_F8, KEY_PLAYPAUSE, APPLE_FLAG_FKEY }, - { KEY_F9, KEY_NEXTSONG, APPLE_FLAG_FKEY }, - { KEY_F10, KEY_MUTE, APPLE_FLAG_FKEY }, - { KEY_F11, KEY_VOLUMEDOWN, APPLE_FLAG_FKEY }, - { KEY_F12, KEY_VOLUMEUP, APPLE_FLAG_FKEY }, - { KEY_UP, KEY_PAGEUP }, - { KEY_DOWN, KEY_PAGEDOWN }, - { KEY_LEFT, KEY_HOME }, - { KEY_RIGHT, KEY_END }, - { } -}; - -static struct hidinput_key_translation powerbook_fn_keys[] = { - { KEY_BACKSPACE, KEY_DELETE }, - { KEY_F1, KEY_BRIGHTNESSDOWN, APPLE_FLAG_FKEY }, - { KEY_F2, KEY_BRIGHTNESSUP, APPLE_FLAG_FKEY }, - { KEY_F3, KEY_MUTE, APPLE_FLAG_FKEY }, - { KEY_F4, KEY_VOLUMEDOWN, APPLE_FLAG_FKEY }, - { KEY_F5, KEY_VOLUMEUP, APPLE_FLAG_FKEY }, - { KEY_F6, KEY_NUMLOCK, APPLE_FLAG_FKEY }, - { KEY_F7, KEY_SWITCHVIDEOMODE, APPLE_FLAG_FKEY }, - { KEY_F8, KEY_KBDILLUMTOGGLE, APPLE_FLAG_FKEY }, - { KEY_F9, KEY_KBDILLUMDOWN, APPLE_FLAG_FKEY }, - { KEY_F10, KEY_KBDILLUMUP, APPLE_FLAG_FKEY }, - { KEY_UP, KEY_PAGEUP }, - { KEY_DOWN, KEY_PAGEDOWN }, - { KEY_LEFT, KEY_HOME }, - { KEY_RIGHT, KEY_END }, - { } -}; - -static struct hidinput_key_translation powerbook_numlock_keys[] = { - { KEY_J, KEY_KP1 }, - { KEY_K, KEY_KP2 }, - { KEY_L, KEY_KP3 }, - { KEY_U, KEY_KP4 }, - { KEY_I, KEY_KP5 }, - { KEY_O, KEY_KP6 }, - { KEY_7, KEY_KP7 }, - { KEY_8, KEY_KP8 }, - { KEY_9, KEY_KP9 }, - { KEY_M, KEY_KP0 }, - { KEY_DOT, KEY_KPDOT }, - { KEY_SLASH, KEY_KPPLUS }, - { KEY_SEMICOLON, KEY_KPMINUS }, - { KEY_P, KEY_KPASTERISK }, - { KEY_MINUS, KEY_KPEQUAL }, - { KEY_0, KEY_KPSLASH }, - { KEY_F6, KEY_NUMLOCK }, - { KEY_KPENTER, KEY_KPENTER }, - { KEY_BACKSPACE, KEY_BACKSPACE }, - { } -}; - -static struct hidinput_key_translation apple_iso_keyboard[] = { - { KEY_GRAVE, KEY_102ND }, - { KEY_102ND, KEY_GRAVE }, - { } -}; - -static struct hidinput_key_translation *find_translation(struct hidinput_key_translation *table, u16 from) -{ - struct hidinput_key_translation *trans; - - /* Look for the translation */ - for (trans = table; trans->from; trans++) - if (trans->from == from) - return trans; - - return NULL; -} - -int hidinput_apple_event(struct hid_device *hid, struct input_dev *input, - struct hid_usage *usage, __s32 value) -{ - struct hidinput_key_translation *trans; - - if (usage->code == KEY_FN) { - if (value) hid->quirks |= HID_QUIRK_APPLE_FN_ON; - else hid->quirks &= ~HID_QUIRK_APPLE_FN_ON; - - input_event(input, usage->type, usage->code, value); - - return 1; - } - - if (hid_apple_fnmode) { - int do_translate; - - trans = find_translation((hid->product < 0x220 || - hid->product >= 0x300) ? - powerbook_fn_keys : apple_fn_keys, - usage->code); - if (trans) { - if (test_bit(usage->code, hid->apple_pressed_fn)) - do_translate = 1; - else if (trans->flags & APPLE_FLAG_FKEY) - do_translate = - (hid_apple_fnmode == 2 && (hid->quirks & HID_QUIRK_APPLE_FN_ON)) || - (hid_apple_fnmode == 1 && !(hid->quirks & HID_QUIRK_APPLE_FN_ON)); - else - do_translate = (hid->quirks & HID_QUIRK_APPLE_FN_ON); - - if (do_translate) { - if (value) - set_bit(usage->code, hid->apple_pressed_fn); - else - clear_bit(usage->code, hid->apple_pressed_fn); - - input_event(input, usage->type, trans->to, value); - - return 1; - } - } - - if (hid->quirks & HID_QUIRK_APPLE_NUMLOCK_EMULATION && ( - test_bit(usage->code, hid->pb_pressed_numlock) || - test_bit(LED_NUML, input->led))) { - trans = find_translation(powerbook_numlock_keys, usage->code); - - if (trans) { - if (value) - set_bit(usage->code, hid->pb_pressed_numlock); - else - clear_bit(usage->code, hid->pb_pressed_numlock); - - input_event(input, usage->type, trans->to, value); - } - - return 1; - } - } - - if (hid->quirks & HID_QUIRK_APPLE_ISO_KEYBOARD) { - trans = find_translation(apple_iso_keyboard, usage->code); - if (trans) { - input_event(input, usage->type, trans->to, value); - return 1; - } - } - - return 0; -} - -static void hidinput_apple_setup(struct input_dev *input) -{ - struct hidinput_key_translation *trans; - - set_bit(KEY_NUMLOCK, input->keybit); - - /* Enable all needed keys */ - for (trans = apple_fn_keys; trans->from; trans++) - set_bit(trans->to, input->keybit); - - for (trans = powerbook_fn_keys; trans->from; trans++) - set_bit(trans->to, input->keybit); - - for (trans = powerbook_numlock_keys; trans->from; trans++) - set_bit(trans->to, input->keybit); - - for (trans = apple_iso_keyboard; trans->from; trans++) - set_bit(trans->to, input->keybit); - -} -#else -inline int hidinput_apple_event(struct hid_device *hid, - struct input_dev *input, - struct hid_usage *usage, __s32 value) -{ - return 0; -} - -static inline void hidinput_apple_setup(struct input_dev *input) -{ -} -#endif - static inline int match_scancode(int code, int scancode) { if (scancode == 0) @@ -696,16 +495,7 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel case HID_UP_CUSTOM: /* Reported on Logitech and Apple USB keyboards */ set_bit(EV_REP, input->evbit); - switch(usage->hid & HID_USAGE) { - case 0x003: - /* The fn key on Apple USB keyboards */ - map_key_clear(KEY_FN); - hidinput_apple_setup(input); - break; - - default: goto ignore; - } - break; + goto ignore; case HID_UP_LOGIVENDOR: @@ -742,15 +532,6 @@ mapped: hidinput, field, usage, &bit, &max) < 0) goto ignore; - if (device->quirks & HID_QUIRK_MIGHTYMOUSE) { - if (usage->hid == HID_GD_Z) - map_rel(REL_HWHEEL); - else if (usage->code == BTN_1) - map_key(BTN_2); - else if (usage->code == BTN_2) - map_key(BTN_1); - } - if ((device->quirks & (HID_QUIRK_2WHEEL_MOUSE_HACK_7 | HID_QUIRK_2WHEEL_MOUSE_HACK_5 | HID_QUIRK_2WHEEL_MOUSE_HACK_B8)) && (usage->type == EV_REL) && (usage->code == REL_WHEEL)) diff --git a/drivers/hid/usbhid/Kconfig b/drivers/hid/usbhid/Kconfig index 18f09104765..177bfa1a3e5 100644 --- a/drivers/hid/usbhid/Kconfig +++ b/drivers/hid/usbhid/Kconfig @@ -24,17 +24,6 @@ config USB_HID comment "Input core support is needed for USB HID input layer or HIDBP support" depends on USB_HID && INPUT=n -config USB_HIDINPUT_POWERBOOK - bool "Enable support for Apple laptop/aluminum USB special keys" - default n - depends on USB_HID - help - Say Y here if you want support for the special keys (Fn, Numlock) on - Apple iBooks, PowerBooks, MacBooks, MacBook Pros and aluminum USB - keyboards. - - If unsure, say N. - config HID_FF bool "Force feedback support (EXPERIMENTAL)" depends on USB_HID && EXPERIMENTAL diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c index 9f5e100e95e..97268082073 100644 --- a/drivers/hid/usbhid/hid-core.c +++ b/drivers/hid/usbhid/hid-core.c @@ -791,10 +791,6 @@ static int usbhid_parse(struct hid_device *hid) quirks |= HID_QUIRK_NOGET; } - if ((quirks & HID_QUIRK_IGNORE_MOUSE) && - (interface->desc.bInterfaceProtocol == USB_INTERFACE_PROTOCOL_MOUSE)) - return -ENODEV; - if (usb_get_extra_descriptor(interface, HID_DT_HID, &hdesc) && (!interface->desc.bNumEndpoints || usb_get_extra_descriptor(&interface->endpoint[0], HID_DT_HID, &hdesc))) { diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c index 466d608ba6a..4c5ee9ecd40 100644 --- a/drivers/hid/usbhid/hid-quirks.c +++ b/drivers/hid/usbhid/hid-quirks.c @@ -49,7 +49,6 @@ static const struct hid_blacklist { { USB_VENDOR_ID_AFATECH, USB_DEVICE_ID_AFATECH_AF9016, HID_QUIRK_FULLSPEED_INTERVAL }, { USB_VENDOR_ID_BELKIN, USB_DEVICE_ID_FLIP_KVM, HID_QUIRK_HIDDEV }, - { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL4, HID_QUIRK_HIDDEV | HID_QUIRK_IGNORE_HIDINPUT }, { USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_IR_REMOTE, HID_QUIRK_HIDDEV | HID_QUIRK_IGNORE_HIDINPUT }, { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_SIDEWINDER_GV, HID_QUIRK_HIDINPUT }, @@ -59,8 +58,6 @@ static const struct hid_blacklist { { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_NE4K, HID_QUIRK_MICROSOFT_KEYS }, { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_LK6K, HID_QUIRK_MICROSOFT_KEYS }, - { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MIGHTYMOUSE, HID_QUIRK_MIGHTYMOUSE | HID_QUIRK_INVERT_HWHEEL }, - { USB_VENDOR_ID_PANTHERLORD, USB_DEVICE_ID_PANTHERLORD_TWIN_USB_JOYSTICK, HID_QUIRK_MULTI_INPUT | HID_QUIRK_SKIP_OUTPUT_REPORTS }, { USB_VENDOR_ID_PLAYDOTCOM, USB_DEVICE_ID_PLAYDOTCOM_EMS_USBII, HID_QUIRK_MULTI_INPUT }, @@ -82,35 +79,6 @@ static const struct hid_blacklist { { USB_VENDOR_ID_WISEGROUP_LTD, USB_DEVICE_ID_SMARTJOY_DUAL_PLUS, HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT }, - { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ANSI, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, - { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ISO, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, - { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_ANSI, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, - { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_ISO, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE | HID_QUIRK_APPLE_ISO_KEYBOARD}, - { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_JIS, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, - { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_ANSI, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, - { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_ISO, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE | HID_QUIRK_APPLE_ISO_KEYBOARD}, - { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_JIS, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, - { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_ANSI, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, - { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_ISO, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE | HID_QUIRK_APPLE_ISO_KEYBOARD}, - { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_JIS, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, - { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_ANSI, HID_QUIRK_APPLE_HAS_FN }, - { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_ISO, HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_APPLE_ISO_KEYBOARD }, - { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_JIS, HID_QUIRK_APPLE_HAS_FN }, - { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_HF_ANSI, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, - { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_HF_ISO, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, - { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_HF_JIS, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, - { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_ANSI, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN }, - { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_ISO, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_APPLE_ISO_KEYBOARD }, - { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_JIS, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN }, - { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING_ANSI, HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, - { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING_ISO, HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_APPLE_ISO_KEYBOARD | HID_QUIRK_IGNORE_MOUSE}, - { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING_JIS, HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE}, - { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING2_ANSI, HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE}, - { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING2_ISO, HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_APPLE_ISO_KEYBOARD | HID_QUIRK_IGNORE_MOUSE }, - { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING2_JIS, HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, - { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, - { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, - { USB_VENDOR_ID_DELL, USB_DEVICE_ID_DELL_W7658, HID_QUIRK_RESET_LEDS }, { 0, 0 } @@ -129,8 +97,6 @@ static const struct hid_rdesc_blacklist { { USB_VENDOR_ID_MONTEREY, USB_DEVICE_ID_GENIUS_KB29E, HID_QUIRK_RDESC_BUTTON_CONSUMER }, - { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_JIS, HID_QUIRK_RDESC_MACBOOK_JIS }, - { USB_VENDOR_ID_PETALYNX, USB_DEVICE_ID_PETALYNX_MAXTER_REMOTE, HID_QUIRK_RDESC_PETALYNX }, { USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_IR_REMOTE, HID_QUIRK_RDESC_SAMSUNG_REMOTE }, @@ -461,18 +427,6 @@ static void usbhid_fixup_cypress_descriptor(unsigned char *rdesc, int rsize) printk(KERN_INFO "Fixing up Cypress report descriptor\n"); } -/* - * MacBook JIS keyboard has wrong logical maximum - */ -static void usbhid_fixup_macbook_descriptor(unsigned char *rdesc, int rsize) -{ - if (rsize >= 60 && rdesc[53] == 0x65 - && rdesc[59] == 0x65) { - printk(KERN_INFO "Fixing up MacBook JIS keyboard report descriptor\n"); - rdesc[53] = rdesc[59] = 0xe7; - } -} - static void usbhid_fixup_button_consumer_descriptor(unsigned char *rdesc, int rsize) { if (rsize >= 30 && rdesc[29] == 0x05 @@ -515,9 +469,6 @@ static void __usbhid_fixup_report_descriptor(__u32 quirks, char *rdesc, unsigned if (quirks & HID_QUIRK_RDESC_PETALYNX) usbhid_fixup_petalynx_descriptor(rdesc, rsize); - if (quirks & HID_QUIRK_RDESC_MACBOOK_JIS) - usbhid_fixup_macbook_descriptor(rdesc, rsize); - if (quirks & HID_QUIRK_RDESC_BUTTON_CONSUMER) usbhid_fixup_button_consumer_descriptor(rdesc, rsize); diff --git a/drivers/hid/usbhid/usbmouse.c b/drivers/hid/usbhid/usbmouse.c index 35689ef172c..a89646a3c1f 100644 --- a/drivers/hid/usbhid/usbmouse.c +++ b/drivers/hid/usbhid/usbmouse.c @@ -31,6 +31,11 @@ #include #include +/* for apple IDs */ +#ifdef CONFIG_USB_HID_MODULE +#include "../hid-ids.h" +#endif + /* * Version Information */ diff --git a/include/linux/hid.h b/include/linux/hid.h index 0644fd33b98..75cc1531dd8 100644 --- a/include/linux/hid.h +++ b/include/linux/hid.h @@ -264,13 +264,7 @@ struct hid_item { #define HID_QUIRK_2WHEEL_MOUSE_HACK_7 0x00000080 #define HID_QUIRK_2WHEEL_MOUSE_HACK_5 0x00000100 #define HID_QUIRK_2WHEEL_MOUSE_HACK_ON 0x00000200 -#define HID_QUIRK_MIGHTYMOUSE 0x00000400 -#define HID_QUIRK_APPLE_HAS_FN 0x00000800 -#define HID_QUIRK_APPLE_FN_ON 0x00001000 -#define HID_QUIRK_INVERT_HWHEEL 0x00002000 -#define HID_QUIRK_APPLE_ISO_KEYBOARD 0x00004000 #define HID_QUIRK_SKIP_OUTPUT_REPORTS 0x00010000 -#define HID_QUIRK_IGNORE_MOUSE 0x00020000 #define HID_QUIRK_SONY_PS3_CONTROLLER 0x00040000 #define HID_QUIRK_RESET_LEDS 0x00100000 #define HID_QUIRK_HIDINPUT 0x00200000 @@ -279,7 +273,6 @@ struct hid_item { #define HID_QUIRK_HWHEEL_WHEEL_INVERT 0x04000000 #define HID_QUIRK_MICROSOFT_KEYS 0x08000000 #define HID_QUIRK_FULLSPEED_INTERVAL 0x10000000 -#define HID_QUIRK_APPLE_NUMLOCK_EMULATION 0x20000000 /* * Separate quirks for runtime report descriptor fixup @@ -288,7 +281,6 @@ struct hid_item { #define HID_QUIRK_RDESC_CYMOTION 0x00000001 #define HID_QUIRK_RDESC_SWAPPED_MIN_MAX 0x00000004 #define HID_QUIRK_RDESC_PETALYNX 0x00000008 -#define HID_QUIRK_RDESC_MACBOOK_JIS 0x00000010 #define HID_QUIRK_RDESC_BUTTON_CONSUMER 0x00000020 #define HID_QUIRK_RDESC_SAMSUNG_REMOTE 0x00000040 #define HID_QUIRK_RDESC_MICROSOFT_RECV_1028 0x00000080 @@ -475,10 +467,6 @@ struct hid_device { /* device report descriptor */ /* handler for raw output data, used by hidraw */ int (*hid_output_raw_report) (struct hid_device *, __u8 *, size_t); -#ifdef CONFIG_USB_HIDINPUT_POWERBOOK - unsigned long apple_pressed_fn[BITS_TO_LONGS(KEY_CNT)]; - unsigned long pb_pressed_numlock[BITS_TO_LONGS(KEY_CNT)]; -#endif }; static inline void *hid_get_drvdata(struct hid_device *hdev) @@ -652,7 +640,6 @@ int hidinput_find_field(struct hid_device *hid, unsigned int type, unsigned int int hidinput_mapping_quirks(struct hid_usage *, struct hid_input *, unsigned long **, int *); int hidinput_event_quirks(struct hid_device *, struct hid_field *, struct hid_usage *, __s32); -int hidinput_apple_event(struct hid_device *, struct input_dev *, struct hid_usage *, __s32); void hid_output_report(struct hid_report *report, __u8 *data); struct hid_device *hid_allocate_device(void); int hid_parse_report(struct hid_device *hid, __u8 *start, unsigned size); diff --git a/net/bluetooth/hidp/core.c b/net/bluetooth/hidp/core.c index 4ae3207e8a9..f3d830747b9 100644 --- a/net/bluetooth/hidp/core.c +++ b/net/bluetooth/hidp/core.c @@ -683,27 +683,6 @@ static void hidp_close(struct hid_device *hid) { } -static const struct { - __u16 idVendor; - __u16 idProduct; - unsigned quirks; -} hidp_blacklist[] = { - /* Apple wireless Mighty Mouse */ - { 0x05ac, 0x030c, HID_QUIRK_MIGHTYMOUSE | HID_QUIRK_INVERT_HWHEEL }, - - { } /* Terminating entry */ -}; - -static void hidp_setup_quirks(struct hid_device *hid) -{ - unsigned int n; - - for (n = 0; hidp_blacklist[n].idVendor; n++) - if (hidp_blacklist[n].idVendor == le16_to_cpu(hid->vendor) && - hidp_blacklist[n].idProduct == le16_to_cpu(hid->product)) - hid->quirks = hidp_blacklist[n].quirks; -} - static int hidp_parse(struct hid_device *hid) { struct hidp_session *session = hid->driver_data; @@ -729,7 +708,6 @@ static int hidp_parse(struct hid_device *hid) session->req = NULL; - hidp_setup_quirks(hid); return 0; } -- cgit v1.2.3-70-g09d2 From 02ae9a1a8bc1d08a8fd5f6a0b8bde400b0f891b9 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Fri, 16 May 2008 11:49:22 +0200 Subject: HID: add compat support Add compat option to hid code to allow loading of all modules on systems which don't allow autoloading because of old userspace. Signed-off-by: Jiri Slaby Signed-off-by: Jiri Kosina --- Documentation/feature-removal-schedule.txt | 7 +++++++ drivers/hid/Kconfig | 12 ++++++++++++ drivers/hid/Makefile | 4 ++++ drivers/hid/hid-apple.c | 2 ++ drivers/hid/hid-core.c | 12 ++++++++++++ drivers/hid/hid-dummy.c | 18 ++++++++++++++++++ drivers/hid/hid-logitech.c | 2 ++ include/linux/hid.h | 17 +++++++++++++++-- 8 files changed, 72 insertions(+), 2 deletions(-) create mode 100644 drivers/hid/hid-dummy.c (limited to 'drivers/hid/Kconfig') diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt index cc8093c15cf..4d2566a7d16 100644 --- a/Documentation/feature-removal-schedule.txt +++ b/Documentation/feature-removal-schedule.txt @@ -287,6 +287,13 @@ Who: Glauber Costa --------------------------- +What: remove HID compat support +When: 2.6.29 +Why: needed only as a temporary solution until distros fix themselves up +Who: Jiri Slaby + +--------------------------- + What: /sys/o2cb symlink When: January 2010 Why: /sys/fs/o2cb is the proper location for this information - /sys/o2cb diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index 41283fff514..d9d1a5671d9 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -70,6 +70,18 @@ source "drivers/hid/usbhid/Kconfig" menu "Special HID drivers" depends on HID +config HID_COMPAT + bool "Load all HID drivers on hid core load" + default y + ---help--- + Compatible option for older userspace. If you have system without udev + support of module loading through aliases and also old + module-init-tools which can't handle hid bus, choose Y here. Otherwise + say N. If you say N and your userspace is old enough, the only + functionality you loose is modules autoloading. + + If unsure, say Y. + config HID_APPLE tristate "Apple" default m diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile index 4a14821ceef..8e053eca474 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile @@ -8,6 +8,10 @@ obj-$(CONFIG_HID) += hid.o hid-$(CONFIG_HID_DEBUG) += hid-debug.o hid-$(CONFIG_HIDRAW) += hidraw.o +ifdef CONFIG_HID_COMPAT +obj-m += hid-dummy.o +endif + obj-$(CONFIG_HID_APPLE) += hid-apple.o obj-$(CONFIG_HID_LOGITECH) += hid-logitech.o diff --git a/drivers/hid/hid-apple.c b/drivers/hid/hid-apple.c index 5642e2c685f..2a68661fcea 100644 --- a/drivers/hid/hid-apple.c +++ b/drivers/hid/hid-apple.c @@ -477,3 +477,5 @@ static void apple_exit(void) module_init(apple_init); module_exit(apple_exit); MODULE_LICENSE("GPL"); + +HID_COMPAT_LOAD_DRIVER(apple); diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 8e3c264c9b2..397e1b2ffe5 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1532,6 +1532,14 @@ void hid_unregister_driver(struct hid_driver *hdrv) } EXPORT_SYMBOL_GPL(hid_unregister_driver); +#ifdef CONFIG_HID_COMPAT +static void hid_compat_load(struct work_struct *ws) +{ + request_module("hid-dummy"); +} +static DECLARE_WORK(hid_compat_work, hid_compat_load); +#endif + static int __init hid_init(void) { int ret; @@ -1546,6 +1554,10 @@ static int __init hid_init(void) if (ret) goto err_bus; +#ifdef CONFIG_HID_COMPAT + schedule_work(&hid_compat_work); +#endif + return 0; err_bus: bus_unregister(&hid_bus_type); diff --git a/drivers/hid/hid-dummy.c b/drivers/hid/hid-dummy.c new file mode 100644 index 00000000000..b76c44efe1b --- /dev/null +++ b/drivers/hid/hid-dummy.c @@ -0,0 +1,18 @@ +#include +#include +#include + +static int __init hid_dummy_init(void) +{ +#ifdef CONFIG_HID_APPLE_MODULE + HID_COMPAT_CALL_DRIVER(apple); +#endif +#ifdef CONFIG_HID_LOGITECH_MODULE + HID_COMPAT_CALL_DRIVER(logitech); +#endif + + return -EIO; +} +module_init(hid_dummy_init); + +MODULE_LICENSE("GPL"); diff --git a/drivers/hid/hid-logitech.c b/drivers/hid/hid-logitech.c index 395e42ffb4d..b2aaebe1ac0 100644 --- a/drivers/hid/hid-logitech.c +++ b/drivers/hid/hid-logitech.c @@ -310,3 +310,5 @@ static void lg_exit(void) module_init(lg_init); module_exit(lg_exit); MODULE_LICENSE("GPL"); + +HID_COMPAT_LOAD_DRIVER(logitech); diff --git a/include/linux/hid.h b/include/linux/hid.h index 75cc1531dd8..60e44e6b86e 100644 --- a/include/linux/hid.h +++ b/include/linux/hid.h @@ -790,10 +790,23 @@ dbg_hid(const char *fmt, ...) return 0; } #define dbg_hid_line dbg_hid -#endif +#endif /* HID_DEBUG */ #define err_hid(format, arg...) printk(KERN_ERR "%s: " format "\n" , \ __FILE__ , ## arg) -#endif +#endif /* HID_FF */ + +#ifdef CONFIG_HID_COMPAT +#define HID_COMPAT_LOAD_DRIVER(name) \ +void hid_compat_##name(void) { } \ +EXPORT_SYMBOL(hid_compat_##name) +#else +#define HID_COMPAT_LOAD_DRIVER(name) +#endif /* HID_COMPAT */ +#define HID_COMPAT_CALL_DRIVER(name) do { \ + extern void hid_compat_##name(void); \ + hid_compat_##name(); \ +} while (0) + #endif -- cgit v1.2.3-70-g09d2 From 78a849a682a1d5ee7b7187b08abdc48656326a4e Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Fri, 20 Jun 2008 21:26:11 +0200 Subject: HID: move microsoft quirks Move them from the core code to a separate driver. Signed-off-by: Jiri Slaby Signed-off-by: Jiri Kosina --- drivers/hid/Kconfig | 8 ++ drivers/hid/Makefile | 1 + drivers/hid/hid-core.c | 6 ++ drivers/hid/hid-dummy.c | 3 + drivers/hid/hid-ids.h | 4 +- drivers/hid/hid-input-quirks.c | 76 -------------- drivers/hid/hid-microsoft.c | 220 ++++++++++++++++++++++++++++++++++++++++ drivers/hid/usbhid/hid-quirks.c | 33 ------ include/linux/hid.h | 2 - 9 files changed, 241 insertions(+), 112 deletions(-) create mode 100644 drivers/hid/hid-microsoft.c (limited to 'drivers/hid/Kconfig') diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index d9d1a5671d9..8067b653f8b 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -104,6 +104,14 @@ config HID_LOGITECH Support for some Logitech devices which breaks less or more HID specification. +config HID_MICROSOFT + tristate "Microsoft" + default m + depends on USB_HID + ---help--- + Support for some Microsoft devices which breaks less or more + HID specification. + endmenu endif # HID_SUPPORT diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile index 8e053eca474..3dc2828fb71 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile @@ -14,6 +14,7 @@ endif obj-$(CONFIG_HID_APPLE) += hid-apple.o obj-$(CONFIG_HID_LOGITECH) += hid-logitech.o +obj-$(CONFIG_HID_MICROSOFT) += hid-microsoft.o obj-$(CONFIG_USB_HID) += usbhid/ obj-$(CONFIG_USB_MOUSE) += usbhid/ diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 5e62e010d80..db8fbd2f502 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1176,8 +1176,14 @@ static const struct hid_device_id hid_blacklist[] = { { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_V150) }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_EXTREME_3D) }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WHEEL) }, + { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_SIDEWINDER_GV) }, + { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_NE4K) }, + { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_LK6K) }, + { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_PRESENTER_8K_USB) }, + { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_WIRELESS_OPTICAL_DESKTOP_3_0) }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, 0x030c) }, + { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_PRESENTER_8K_BT) }, { } }; diff --git a/drivers/hid/hid-dummy.c b/drivers/hid/hid-dummy.c index b76c44efe1b..fe64d60f901 100644 --- a/drivers/hid/hid-dummy.c +++ b/drivers/hid/hid-dummy.c @@ -10,6 +10,9 @@ static int __init hid_dummy_init(void) #ifdef CONFIG_HID_LOGITECH_MODULE HID_COMPAT_CALL_DRIVER(logitech); #endif +#ifdef CONFIG_HID_MICROSOFT_MODULE + HID_COMPAT_CALL_DRIVER(microsoft); +#endif return -EIO; } diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 23d021bd95d..d7e548dbe7c 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -280,9 +280,11 @@ #define USB_VENDOR_ID_MICROSOFT 0x045e #define USB_DEVICE_ID_SIDEWINDER_GV 0x003b #define USB_DEVICE_ID_WIRELESS_OPTICAL_DESKTOP_3_0 0x009d -#define USB_DEVICE_ID_DESKTOP_RECV_1028 0x00f9 #define USB_DEVICE_ID_MS_NE4K 0x00db #define USB_DEVICE_ID_MS_LK6K 0x00f9 +#define USB_DEVICE_ID_MS_PRESENTER_8K_BT 0x0701 +#define USB_DEVICE_ID_MS_PRESENTER_8K_USB 0x0713 + #define USB_VENDOR_ID_MONTEREY 0x0566 #define USB_DEVICE_ID_GENIUS_KB29E 0x3004 diff --git a/drivers/hid/hid-input-quirks.c b/drivers/hid/hid-input-quirks.c index 878e193c6d7..d1b4f093dcb 100644 --- a/drivers/hid/hid-input-quirks.c +++ b/drivers/hid/hid-input-quirks.c @@ -102,50 +102,6 @@ static int quirk_chicony_tactical_pad(struct hid_usage *usage, return 1; } -static int quirk_microsoft_ergonomy_kb(struct hid_usage *usage, - struct hid_input *hidinput, unsigned long **bit, int *max) -{ - struct input_dev *input = hidinput->input; - - if ((usage->hid & HID_USAGE_PAGE) != HID_UP_MSVENDOR) - return 0; - - switch(usage->hid & HID_USAGE) { - case 0xfd06: map_key_clear(KEY_CHAT); break; - case 0xfd07: map_key_clear(KEY_PHONE); break; - case 0xff05: - set_bit(EV_REP, input->evbit); - map_key_clear(KEY_F13); - set_bit(KEY_F14, input->keybit); - set_bit(KEY_F15, input->keybit); - set_bit(KEY_F16, input->keybit); - set_bit(KEY_F17, input->keybit); - set_bit(KEY_F18, input->keybit); - default: - return 0; - } - return 1; -} - -static int quirk_microsoft_presenter_8k(struct hid_usage *usage, - struct hid_input *hidinput, unsigned long **bit, int *max) -{ - if ((usage->hid & HID_USAGE_PAGE) != HID_UP_MSVENDOR) - return 0; - - set_bit(EV_REP, hidinput->input->evbit); - switch(usage->hid & HID_USAGE) { - case 0xfd08: map_key_clear(KEY_FORWARD); break; - case 0xfd09: map_key_clear(KEY_BACK); break; - case 0xfd0b: map_key_clear(KEY_PLAYPAUSE); break; - case 0xfd0e: map_key_clear(KEY_CLOSE); break; - case 0xfd0f: map_key_clear(KEY_PLAY); break; - default: - return 0; - } - return 1; -} - static int quirk_petalynx_remote(struct hid_usage *usage, struct hid_input *hidinput, unsigned long **bit, int *max) { @@ -244,12 +200,6 @@ static int quirk_sunplus_wdesktop(struct hid_usage *usage, #define VENDOR_ID_GYRATION 0x0c16 #define DEVICE_ID_GYRATION_REMOTE 0x0002 -#define VENDOR_ID_MICROSOFT 0x045e -#define DEVICE_ID_MS4K 0x00db -#define DEVICE_ID_MS6K 0x00f9 -#define DEVICE_IS_MS_PRESENTER_8K_BT 0x0701 -#define DEVICE_ID_MS_PRESENTER_8K_USB 0x0713 - #define VENDOR_ID_MONTEREY 0x0566 #define DEVICE_ID_GENIUS_KB29E 0x3004 @@ -275,11 +225,6 @@ static const struct hid_input_blacklist { { VENDOR_ID_GYRATION, DEVICE_ID_GYRATION_REMOTE, quirk_gyration_remote }, - { VENDOR_ID_MICROSOFT, DEVICE_ID_MS4K, quirk_microsoft_ergonomy_kb }, - { VENDOR_ID_MICROSOFT, DEVICE_ID_MS6K, quirk_microsoft_ergonomy_kb }, - { VENDOR_ID_MICROSOFT, DEVICE_IS_MS_PRESENTER_8K_BT, quirk_microsoft_presenter_8k }, - { VENDOR_ID_MICROSOFT, DEVICE_ID_MS_PRESENTER_8K_USB, quirk_microsoft_presenter_8k }, - { VENDOR_ID_MONTEREY, DEVICE_ID_GENIUS_KB29E, quirk_cherry_genius_29e }, { VENDOR_ID_PETALYNX, DEVICE_ID_PETALYNX_MAXTER_REMOTE, quirk_petalynx_remote }, @@ -336,27 +281,6 @@ int hidinput_event_quirks(struct hid_device *hid, struct hid_field *field, struc return 1; } - /* Handling MS keyboards special buttons */ - if (hid->quirks & HID_QUIRK_MICROSOFT_KEYS && - usage->hid == (HID_UP_MSVENDOR | 0xff05)) { - int key = 0; - static int last_key = 0; - switch (value) { - case 0x01: key = KEY_F14; break; - case 0x02: key = KEY_F15; break; - case 0x04: key = KEY_F16; break; - case 0x08: key = KEY_F17; break; - case 0x10: key = KEY_F18; break; - default: break; - } - if (key) { - input_event(input, usage->type, key, 1); - last_key = key; - } else { - input_event(input, usage->type, last_key, 0); - } - } - /* handle the temporary quirky mapping to HWHEEL */ if (hid->quirks & HID_QUIRK_HWHEEL_WHEEL_INVERT && usage->type == EV_REL && usage->code == REL_HWHEEL) { diff --git a/drivers/hid/hid-microsoft.c b/drivers/hid/hid-microsoft.c new file mode 100644 index 00000000000..1fa8b813d44 --- /dev/null +++ b/drivers/hid/hid-microsoft.c @@ -0,0 +1,220 @@ +/* + * HID driver for some microsoft "special" devices + * + * Copyright (c) 1999 Andreas Gal + * Copyright (c) 2000-2005 Vojtech Pavlik + * Copyright (c) 2005 Michael Haboustak for Concept2, Inc + * Copyright (c) 2006-2007 Jiri Kosina + * Copyright (c) 2007 Paul Walmsley + * Copyright (c) 2008 Jiri Slaby + */ + +/* + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + */ + +#include +#include +#include +#include + +#include "hid-ids.h" + +#define MS_HIDINPUT 0x01 +#define MS_ERGONOMY 0x02 +#define MS_PRESENTER 0x04 +#define MS_RDESC 0x08 +#define MS_NOGET 0x10 + +/* + * Microsoft Wireless Desktop Receiver (Model 1028) has several + * 'Usage Min/Max' where it ought to have 'Physical Min/Max' + */ +static void ms_report_fixup(struct hid_device *hdev, __u8 *rdesc, + unsigned int rsize) +{ + unsigned long quirks = (unsigned long)hid_get_drvdata(hdev); + + if ((quirks & MS_RDESC) && rsize == 571 && rdesc[284] == 0x19 && + rdesc[286] == 0x2a && rdesc[304] == 0x19 && + rdesc[306] == 0x29 && rdesc[352] == 0x1a && + rdesc[355] == 0x2a && rdesc[557] == 0x19 && + rdesc[559] == 0x29) { + dev_info(&hdev->dev, "fixing up Microsoft Wireless Receiver " + "Model 1028 report descriptor\n"); + rdesc[284] = rdesc[304] = rdesc[557] = 0x35; + rdesc[352] = 0x36; + rdesc[286] = rdesc[355] = 0x46; + rdesc[306] = rdesc[559] = 0x45; + } +} + +#define ms_map_key_clear(c) hid_map_usage_clear(hi, usage, bit, max, \ + EV_KEY, (c)) +static int ms_ergonomy_kb_quirk(struct hid_input *hi, struct hid_usage *usage, + unsigned long **bit, int *max) +{ + struct input_dev *input = hi->input; + + switch (usage->hid & HID_USAGE) { + case 0xfd06: ms_map_key_clear(KEY_CHAT); break; + case 0xfd07: ms_map_key_clear(KEY_PHONE); break; + case 0xff05: + set_bit(EV_REP, input->evbit); + ms_map_key_clear(KEY_F13); + set_bit(KEY_F14, input->keybit); + set_bit(KEY_F15, input->keybit); + set_bit(KEY_F16, input->keybit); + set_bit(KEY_F17, input->keybit); + set_bit(KEY_F18, input->keybit); + default: + return 0; + } + return 1; +} + +static int ms_presenter_8k_quirk(struct hid_input *hi, struct hid_usage *usage, + unsigned long **bit, int *max) +{ + set_bit(EV_REP, hi->input->evbit); + switch (usage->hid & HID_USAGE) { + case 0xfd08: ms_map_key_clear(KEY_FORWARD); break; + case 0xfd09: ms_map_key_clear(KEY_BACK); break; + case 0xfd0b: ms_map_key_clear(KEY_PLAYPAUSE); break; + case 0xfd0e: ms_map_key_clear(KEY_CLOSE); break; + case 0xfd0f: ms_map_key_clear(KEY_PLAY); break; + default: + return 0; + } + return 1; +} + +static int ms_input_mapping(struct hid_device *hdev, struct hid_input *hi, + struct hid_field *field, struct hid_usage *usage, + unsigned long **bit, int *max) +{ + unsigned long quirks = (unsigned long)hid_get_drvdata(hdev); + + if ((usage->hid & HID_USAGE_PAGE) != HID_UP_MSVENDOR) + return 0; + + if (quirks & MS_ERGONOMY) { + int ret = ms_ergonomy_kb_quirk(hi, usage, bit, max); + if (ret) + return ret; + } + + if ((quirks & MS_PRESENTER) && + ms_presenter_8k_quirk(hi, usage, bit, max)) + return 1; + + return 0; +} + +static int ms_event(struct hid_device *hdev, struct hid_field *field, + struct hid_usage *usage, __s32 value) +{ + unsigned long quirks = (unsigned long)hid_get_drvdata(hdev); + + if (!(hdev->claimed & HID_CLAIMED_INPUT) || !field->hidinput || + !usage->type) + return 0; + + /* Handling MS keyboards special buttons */ + if (quirks & MS_ERGONOMY && usage->hid == (HID_UP_MSVENDOR | 0xff05)) { + struct input_dev *input = field->hidinput->input; + static unsigned int last_key = 0; + unsigned int key = 0; + switch (value) { + case 0x01: key = KEY_F14; break; + case 0x02: key = KEY_F15; break; + case 0x04: key = KEY_F16; break; + case 0x08: key = KEY_F17; break; + case 0x10: key = KEY_F18; break; + } + if (key) { + input_event(input, usage->type, key, 1); + last_key = key; + } else + input_event(input, usage->type, last_key, 0); + + return 1; + } + + return 0; +} + +static int ms_probe(struct hid_device *hdev, const struct hid_device_id *id) +{ + unsigned long quirks = id->driver_data; + int ret; + + hid_set_drvdata(hdev, (void *)quirks); + + if (quirks & MS_HIDINPUT) + hdev->quirks |= HID_QUIRK_HIDINPUT; + if (quirks & MS_NOGET) + hdev->quirks |= HID_QUIRK_NOGET; + + ret = hid_parse(hdev); + if (ret) { + dev_err(&hdev->dev, "parse failed\n"); + goto err_free; + } + + ret = hid_hw_start(hdev); + if (ret) { + dev_err(&hdev->dev, "hw start failed\n"); + goto err_free; + } + + return 0; +err_free: + return ret; +} + +static const struct hid_device_id ms_devices[] = { + { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_SIDEWINDER_GV), + .driver_data = MS_HIDINPUT }, + { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_NE4K), + .driver_data = MS_ERGONOMY }, + { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_LK6K), + .driver_data = MS_ERGONOMY | MS_RDESC }, + { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_PRESENTER_8K_USB), + .driver_data = MS_PRESENTER }, + { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_WIRELESS_OPTICAL_DESKTOP_3_0), + .driver_data = MS_NOGET }, + + { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_PRESENTER_8K_BT), + .driver_data = MS_PRESENTER }, + { } +}; +MODULE_DEVICE_TABLE(hid, ms_devices); + +static struct hid_driver ms_driver = { + .name = "microsoft", + .id_table = ms_devices, + .report_fixup = ms_report_fixup, + .input_mapping = ms_input_mapping, + .event = ms_event, + .probe = ms_probe, +}; + +static int ms_init(void) +{ + return hid_register_driver(&ms_driver); +} + +static void ms_exit(void) +{ + hid_unregister_driver(&ms_driver); +} + +module_init(ms_init); +module_exit(ms_exit); +MODULE_LICENSE("GPL"); + +HID_COMPAT_LOAD_DRIVER(microsoft); diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c index 4c5ee9ecd40..1614ed2efc1 100644 --- a/drivers/hid/usbhid/hid-quirks.c +++ b/drivers/hid/usbhid/hid-quirks.c @@ -50,14 +50,9 @@ static const struct hid_blacklist { { USB_VENDOR_ID_BELKIN, USB_DEVICE_ID_FLIP_KVM, HID_QUIRK_HIDDEV }, { USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_IR_REMOTE, HID_QUIRK_HIDDEV | HID_QUIRK_IGNORE_HIDINPUT }, - { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_SIDEWINDER_GV, HID_QUIRK_HIDINPUT }, { USB_VENDOR_ID_EZKEY, USB_DEVICE_ID_BTC_8193, HID_QUIRK_HWHEEL_WHEEL_INVERT }, - - { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_NE4K, HID_QUIRK_MICROSOFT_KEYS }, - { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_LK6K, HID_QUIRK_MICROSOFT_KEYS }, - { USB_VENDOR_ID_PANTHERLORD, USB_DEVICE_ID_PANTHERLORD_TWIN_USB_JOYSTICK, HID_QUIRK_MULTI_INPUT | HID_QUIRK_SKIP_OUTPUT_REPORTS }, { USB_VENDOR_ID_PLAYDOTCOM, USB_DEVICE_ID_PLAYDOTCOM_EMS_USBII, HID_QUIRK_MULTI_INPUT }, @@ -70,7 +65,6 @@ static const struct hid_blacklist { { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_4PORTKVMC, HID_QUIRK_NOGET }, { USB_VENDOR_ID_DMI, USB_DEVICE_ID_DMI_ENC, HID_QUIRK_NOGET }, { USB_VENDOR_ID_ELO, USB_DEVICE_ID_ELO_TS2700, HID_QUIRK_NOGET }, - { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_WIRELESS_OPTICAL_DESKTOP_3_0, HID_QUIRK_NOGET }, { USB_VENDOR_ID_PETALYNX, USB_DEVICE_ID_PETALYNX_MAXTER_REMOTE, HID_QUIRK_NOGET }, { USB_VENDOR_ID_SUN, USB_DEVICE_ID_RARITAN_KVM_DONGLE, HID_QUIRK_NOGET }, { USB_VENDOR_ID_TURBOX, USB_DEVICE_ID_TURBOX_KEYBOARD, HID_QUIRK_NOGET }, @@ -93,8 +87,6 @@ static const struct hid_rdesc_blacklist { { USB_VENDOR_ID_CHERRY, USB_DEVICE_ID_CHERRY_CYMOTION, HID_QUIRK_RDESC_CYMOTION }, - { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_DESKTOP_RECV_1028, HID_QUIRK_RDESC_MICROSOFT_RECV_1028 }, - { USB_VENDOR_ID_MONTEREY, USB_DEVICE_ID_GENIUS_KB29E, HID_QUIRK_RDESC_BUTTON_CONSUMER }, { USB_VENDOR_ID_PETALYNX, USB_DEVICE_ID_PETALYNX_MAXTER_REMOTE, HID_QUIRK_RDESC_PETALYNX }, @@ -436,28 +428,6 @@ static void usbhid_fixup_button_consumer_descriptor(unsigned char *rdesc, int rs } } -/* - * Microsoft Wireless Desktop Receiver (Model 1028) has several - * 'Usage Min/Max' where it ought to have 'Physical Min/Max' - */ -static void usbhid_fixup_microsoft_descriptor(unsigned char *rdesc, int rsize) -{ - if (rsize == 571 && rdesc[284] == 0x19 - && rdesc[286] == 0x2a - && rdesc[304] == 0x19 - && rdesc[306] == 0x29 - && rdesc[352] == 0x1a - && rdesc[355] == 0x2a - && rdesc[557] == 0x19 - && rdesc[559] == 0x29) { - printk(KERN_INFO "Fixing up Microsoft Wireless Receiver Model 1028 report descriptor\n"); - rdesc[284] = rdesc[304] = rdesc[557] = 0x35; - rdesc[352] = 0x36; - rdesc[286] = rdesc[355] = 0x46; - rdesc[306] = rdesc[559] = 0x45; - } -} - static void __usbhid_fixup_report_descriptor(__u32 quirks, char *rdesc, unsigned rsize) { if ((quirks & HID_QUIRK_RDESC_CYMOTION)) @@ -475,9 +445,6 @@ static void __usbhid_fixup_report_descriptor(__u32 quirks, char *rdesc, unsigned if (quirks & HID_QUIRK_RDESC_SAMSUNG_REMOTE) usbhid_fixup_samsung_irda_descriptor(rdesc, rsize); - if (quirks & HID_QUIRK_RDESC_MICROSOFT_RECV_1028) - usbhid_fixup_microsoft_descriptor(rdesc, rsize); - if (quirks & HID_QUIRK_RDESC_SUNPLUS_WDESKTOP) usbhid_fixup_sunplus_wdesktop(rdesc, rsize); } diff --git a/include/linux/hid.h b/include/linux/hid.h index 60e44e6b86e..1f1edd886ef 100644 --- a/include/linux/hid.h +++ b/include/linux/hid.h @@ -271,7 +271,6 @@ struct hid_item { #define HID_QUIRK_IGNORE_HIDINPUT 0x01000000 #define HID_QUIRK_2WHEEL_MOUSE_HACK_B8 0x02000000 #define HID_QUIRK_HWHEEL_WHEEL_INVERT 0x04000000 -#define HID_QUIRK_MICROSOFT_KEYS 0x08000000 #define HID_QUIRK_FULLSPEED_INTERVAL 0x10000000 /* @@ -283,7 +282,6 @@ struct hid_item { #define HID_QUIRK_RDESC_PETALYNX 0x00000008 #define HID_QUIRK_RDESC_BUTTON_CONSUMER 0x00000020 #define HID_QUIRK_RDESC_SAMSUNG_REMOTE 0x00000040 -#define HID_QUIRK_RDESC_MICROSOFT_RECV_1028 0x00000080 #define HID_QUIRK_RDESC_SUNPLUS_WDESKTOP 0x00000100 /* -- cgit v1.2.3-70-g09d2 From 90231e7eaf752856a2c13f786f36ec7f641bad28 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 23 Jun 2008 21:56:07 +0200 Subject: HID: move sunplus quirks Signed-off-by: Jiri Slaby Signed-off-by: Jiri Kosina --- drivers/hid/Kconfig | 7 ++++ drivers/hid/Makefile | 1 + drivers/hid/hid-core.c | 1 + drivers/hid/hid-dummy.c | 3 ++ drivers/hid/hid-input-quirks.c | 20 ---------- drivers/hid/hid-sunplus.c | 82 +++++++++++++++++++++++++++++++++++++++++ drivers/hid/usbhid/hid-quirks.c | 16 -------- include/linux/hid.h | 1 - 8 files changed, 94 insertions(+), 37 deletions(-) create mode 100644 drivers/hid/hid-sunplus.c (limited to 'drivers/hid/Kconfig') diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index 8067b653f8b..147223993b8 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -112,6 +112,13 @@ config HID_MICROSOFT Support for some Microsoft devices which breaks less or more HID specification. +config HID_SUNPLUS + tristate "Sunplus" + default m + depends on USB_HID + ---help--- + Support for Sunplus WDesktop input device. + endmenu endif # HID_SUPPORT diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile index 3dc2828fb71..314d5b0c70d 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile @@ -15,6 +15,7 @@ endif obj-$(CONFIG_HID_APPLE) += hid-apple.o obj-$(CONFIG_HID_LOGITECH) += hid-logitech.o obj-$(CONFIG_HID_MICROSOFT) += hid-microsoft.o +obj-$(CONFIG_HID_SUNPLUS) += hid-sunplus.o obj-$(CONFIG_USB_HID) += usbhid/ obj-$(CONFIG_USB_MOUSE) += usbhid/ diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index db8fbd2f502..e9e6dbbaaa8 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1181,6 +1181,7 @@ static const struct hid_device_id hid_blacklist[] = { { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_LK6K) }, { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_PRESENTER_8K_USB) }, { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_WIRELESS_OPTICAL_DESKTOP_3_0) }, + { HID_USB_DEVICE(USB_VENDOR_ID_SUNPLUS, USB_DEVICE_ID_SUNPLUS_WDESKTOP) }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, 0x030c) }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_PRESENTER_8K_BT) }, diff --git a/drivers/hid/hid-dummy.c b/drivers/hid/hid-dummy.c index fe64d60f901..0c833d920c3 100644 --- a/drivers/hid/hid-dummy.c +++ b/drivers/hid/hid-dummy.c @@ -13,6 +13,9 @@ static int __init hid_dummy_init(void) #ifdef CONFIG_HID_MICROSOFT_MODULE HID_COMPAT_CALL_DRIVER(microsoft); #endif +#ifdef CONFIG_HID_SUNPLUS_MODULE + HID_COMPAT_CALL_DRIVER(sunplus); +#endif return -EIO; } diff --git a/drivers/hid/hid-input-quirks.c b/drivers/hid/hid-input-quirks.c index d1b4f093dcb..a5e7163158f 100644 --- a/drivers/hid/hid-input-quirks.c +++ b/drivers/hid/hid-input-quirks.c @@ -170,21 +170,6 @@ static int quirk_btc_8193(struct hid_usage *usage, struct hid_input *hidinput, return 1; } -static int quirk_sunplus_wdesktop(struct hid_usage *usage, - struct hid_input *hidinput, unsigned long **bit, int *max) -{ - if ((usage->hid & HID_USAGE_PAGE) != HID_UP_CONSUMER) - return 0; - - switch (usage->hid & HID_USAGE) { - case 0x2003: map_key_clear(KEY_ZOOMIN); break; - case 0x2103: map_key_clear(KEY_ZOOMOUT); break; - default: - return 0; - } - return 1; -} - #define VENDOR_ID_BELKIN 0x1020 #define DEVICE_ID_BELKIN_WIRELESS_KEYBOARD 0x0006 @@ -206,9 +191,6 @@ static int quirk_sunplus_wdesktop(struct hid_usage *usage, #define VENDOR_ID_PETALYNX 0x18b1 #define DEVICE_ID_PETALYNX_MAXTER_REMOTE 0x0037 -#define VENDOR_ID_SUNPLUS 0x04fc -#define DEVICE_ID_SUNPLUS_WDESKTOP 0x05d8 - static const struct hid_input_blacklist { __u16 idVendor; __u16 idProduct; @@ -229,8 +211,6 @@ static const struct hid_input_blacklist { { VENDOR_ID_PETALYNX, DEVICE_ID_PETALYNX_MAXTER_REMOTE, quirk_petalynx_remote }, - { VENDOR_ID_SUNPLUS, DEVICE_ID_SUNPLUS_WDESKTOP, quirk_sunplus_wdesktop }, - { 0, 0, NULL } }; diff --git a/drivers/hid/hid-sunplus.c b/drivers/hid/hid-sunplus.c new file mode 100644 index 00000000000..5ba68f7dbb7 --- /dev/null +++ b/drivers/hid/hid-sunplus.c @@ -0,0 +1,82 @@ +/* + * HID driver for some sunplus "special" devices + * + * Copyright (c) 1999 Andreas Gal + * Copyright (c) 2000-2005 Vojtech Pavlik + * Copyright (c) 2005 Michael Haboustak for Concept2, Inc + * Copyright (c) 2006-2007 Jiri Kosina + * Copyright (c) 2007 Paul Walmsley + * Copyright (c) 2008 Jiri Slaby + */ + +/* + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + */ + +#include +#include +#include + +#include "hid-ids.h" + +static void sp_report_fixup(struct hid_device *hdev, __u8 *rdesc, + unsigned int rsize) +{ + if (rsize >= 107 && rdesc[104] == 0x26 && rdesc[105] == 0x80 && + rdesc[106] == 0x03) { + dev_info(&hdev->dev, "fixing up Sunplus Wireless Desktop " + "report descriptor\n"); + rdesc[105] = rdesc[110] = 0x03; + rdesc[106] = rdesc[111] = 0x21; + } +} + +#define sp_map_key_clear(c) hid_map_usage_clear(hi, usage, bit, max, \ + EV_KEY, (c)) +static int sp_input_mapping(struct hid_device *hdev, struct hid_input *hi, + struct hid_field *field, struct hid_usage *usage, + unsigned long **bit, int *max) +{ + if ((usage->hid & HID_USAGE_PAGE) != HID_UP_CONSUMER) + return 0; + + switch (usage->hid & HID_USAGE) { + case 0x2003: sp_map_key_clear(KEY_ZOOMIN); break; + case 0x2103: sp_map_key_clear(KEY_ZOOMOUT); break; + default: + return 0; + } + return 1; +} + +static const struct hid_device_id sp_devices[] = { + { HID_USB_DEVICE(USB_VENDOR_ID_SUNPLUS, USB_DEVICE_ID_SUNPLUS_WDESKTOP) }, + { } +}; +MODULE_DEVICE_TABLE(hid, sp_devices); + +static struct hid_driver sp_driver = { + .name = "sunplus", + .id_table = sp_devices, + .report_fixup = sp_report_fixup, + .input_mapping = sp_input_mapping, +}; + +static int sp_init(void) +{ + return hid_register_driver(&sp_driver); +} + +static void sp_exit(void) +{ + hid_unregister_driver(&sp_driver); +} + +module_init(sp_init); +module_exit(sp_exit); +MODULE_LICENSE("GPL"); + +HID_COMPAT_LOAD_DRIVER(sunplus); diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c index 1614ed2efc1..7f38c21e146 100644 --- a/drivers/hid/usbhid/hid-quirks.c +++ b/drivers/hid/usbhid/hid-quirks.c @@ -93,8 +93,6 @@ static const struct hid_rdesc_blacklist { { USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_IR_REMOTE, HID_QUIRK_RDESC_SAMSUNG_REMOTE }, - { USB_VENDOR_ID_SUNPLUS, USB_DEVICE_ID_SUNPLUS_WDESKTOP, HID_QUIRK_RDESC_SUNPLUS_WDESKTOP }, - { USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_1, HID_QUIRK_RDESC_SWAPPED_MIN_MAX }, { USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_2, HID_QUIRK_RDESC_SWAPPED_MIN_MAX }, @@ -342,17 +340,6 @@ static void usbhid_fixup_cymotion_descriptor(char *rdesc, int rsize) } } -static void usbhid_fixup_sunplus_wdesktop(unsigned char *rdesc, int rsize) -{ - if (rsize >= 107 && rdesc[104] == 0x26 - && rdesc[105] == 0x80 - && rdesc[106] == 0x03) { - printk(KERN_INFO "Fixing up Sunplus Wireless Desktop report descriptor\n"); - rdesc[105] = rdesc[110] = 0x03; - rdesc[106] = rdesc[111] = 0x21; - } -} - /* * Samsung IrDA remote controller (reports as Cypress USB Mouse). * @@ -444,9 +431,6 @@ static void __usbhid_fixup_report_descriptor(__u32 quirks, char *rdesc, unsigned if (quirks & HID_QUIRK_RDESC_SAMSUNG_REMOTE) usbhid_fixup_samsung_irda_descriptor(rdesc, rsize); - - if (quirks & HID_QUIRK_RDESC_SUNPLUS_WDESKTOP) - usbhid_fixup_sunplus_wdesktop(rdesc, rsize); } /** diff --git a/include/linux/hid.h b/include/linux/hid.h index 1f1edd886ef..a83d211021d 100644 --- a/include/linux/hid.h +++ b/include/linux/hid.h @@ -282,7 +282,6 @@ struct hid_item { #define HID_QUIRK_RDESC_PETALYNX 0x00000008 #define HID_QUIRK_RDESC_BUTTON_CONSUMER 0x00000020 #define HID_QUIRK_RDESC_SAMSUNG_REMOTE 0x00000040 -#define HID_QUIRK_RDESC_SUNPLUS_WDESKTOP 0x00000100 /* * This is the global environment of the parser. This information is -- cgit v1.2.3-70-g09d2 From 0f2213208f8da51bcb665309e3468f000489c04f Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 23 Jun 2008 22:54:08 +0200 Subject: HID: move cypress quirks Signed-off-by: Jiri Slaby Signed-off-by: Jiri Kosina --- drivers/hid/Kconfig | 7 ++ drivers/hid/Makefile | 1 + drivers/hid/hid-core.c | 3 + drivers/hid/hid-cypress.c | 158 ++++++++++++++++++++++++++++++++++++++++ drivers/hid/hid-dummy.c | 3 + drivers/hid/hid-input-quirks.c | 4 +- drivers/hid/hid-input.c | 6 +- drivers/hid/usbhid/hid-quirks.c | 31 -------- include/linux/hid.h | 2 - 9 files changed, 177 insertions(+), 38 deletions(-) create mode 100644 drivers/hid/hid-cypress.c (limited to 'drivers/hid/Kconfig') diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index 147223993b8..69f3420882a 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -96,6 +96,13 @@ config HID_APPLE If unsure, say M. +config HID_CYPRESS + tristate "Cypress" + default m + depends on USB_HID + ---help--- + Support for Cypress mouse and barcodes. + config HID_LOGITECH tristate "Logitech" default m diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile index 314d5b0c70d..06106620118 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile @@ -13,6 +13,7 @@ obj-m += hid-dummy.o endif obj-$(CONFIG_HID_APPLE) += hid-apple.o +obj-$(CONFIG_HID_CYPRESS) += hid-cypress.o obj-$(CONFIG_HID_LOGITECH) += hid-logitech.o obj-$(CONFIG_HID_MICROSOFT) += hid-microsoft.o obj-$(CONFIG_HID_SUNPLUS) += hid-sunplus.o diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index e9e6dbbaaa8..331670b32e6 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1162,6 +1162,9 @@ static const struct hid_device_id hid_blacklist[] = { { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING2_JIS) }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY) }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY) }, + { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_1) }, + { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_2) }, + { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_MOUSE) }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_MX3000_RECEIVER) }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER) }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER_2) }, diff --git a/drivers/hid/hid-cypress.c b/drivers/hid/hid-cypress.c new file mode 100644 index 00000000000..a1e13f15f0a --- /dev/null +++ b/drivers/hid/hid-cypress.c @@ -0,0 +1,158 @@ +/* + * HID driver for some cypress "special" devices + * + * Copyright (c) 1999 Andreas Gal + * Copyright (c) 2000-2005 Vojtech Pavlik + * Copyright (c) 2005 Michael Haboustak for Concept2, Inc + * Copyright (c) 2006-2007 Jiri Kosina + * Copyright (c) 2007 Paul Walmsley + * Copyright (c) 2008 Jiri Slaby + */ + +/* + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + */ + +#include +#include +#include +#include + +#include "hid-ids.h" + +#define CP_RDESC_SWAPPED_MIN_MAX 0x01 +#define CP_2WHEEL_MOUSE_HACK 0x02 +#define CP_2WHEEL_MOUSE_HACK_ON 0x04 + +/* + * Some USB barcode readers from cypress have usage min and usage max in + * the wrong order + */ +static void cp_report_fixup(struct hid_device *hdev, __u8 *rdesc, + unsigned int rsize) +{ + unsigned long quirks = (unsigned long)hid_get_drvdata(hdev); + unsigned int i; + + if (!(quirks & CP_RDESC_SWAPPED_MIN_MAX)) + return; + + for (i = 0; i < rsize - 4; i++) + if (rdesc[i] == 0x29 && rdesc[i + 2] == 0x19) { + __u8 tmp; + + rdesc[i] = 0x19; + rdesc[i + 2] = 0x29; + tmp = rdesc[i + 3]; + rdesc[i + 3] = rdesc[i + 1]; + rdesc[i + 1] = tmp; + } +} + +static int cp_input_mapped(struct hid_device *hdev, struct hid_input *hi, + struct hid_field *field, struct hid_usage *usage, + unsigned long **bit, int *max) +{ + unsigned long quirks = (unsigned long)hid_get_drvdata(hdev); + + if (!(quirks & CP_2WHEEL_MOUSE_HACK)) + return 0; + + if (usage->type == EV_REL && usage->code == REL_WHEEL) + set_bit(REL_HWHEEL, *bit); + if (usage->hid == 0x00090005) + return -1; + + return 0; +} + +static int cp_event(struct hid_device *hdev, struct hid_field *field, + struct hid_usage *usage, __s32 value) +{ + unsigned long quirks = (unsigned long)hid_get_drvdata(hdev); + + if (!(hdev->claimed & HID_CLAIMED_INPUT) || !field->hidinput || + !usage->type || !(quirks & CP_2WHEEL_MOUSE_HACK)) + return 0; + + if (usage->hid == 0x00090005) { + if (value) + quirks |= CP_2WHEEL_MOUSE_HACK_ON; + else + quirks &= ~CP_2WHEEL_MOUSE_HACK_ON; + hid_set_drvdata(hdev, (void *)quirks); + return 1; + } + + if (usage->code == REL_WHEEL && (quirks & CP_2WHEEL_MOUSE_HACK_ON)) { + struct input_dev *input = field->hidinput->input; + + input_event(input, usage->type, REL_HWHEEL, value); + return 1; + } + + return 0; +} + +static int cp_probe(struct hid_device *hdev, const struct hid_device_id *id) +{ + unsigned long quirks = id->driver_data; + int ret; + + hid_set_drvdata(hdev, (void *)quirks); + + ret = hid_parse(hdev); + if (ret) { + dev_err(&hdev->dev, "parse failed\n"); + goto err_free; + } + + ret = hid_hw_start(hdev); + if (ret) { + dev_err(&hdev->dev, "hw start failed\n"); + goto err_free; + } + + return 0; +err_free: + return ret; +} + +static const struct hid_device_id cp_devices[] = { + { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_1), + .driver_data = CP_RDESC_SWAPPED_MIN_MAX }, + { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_2), + .driver_data = CP_RDESC_SWAPPED_MIN_MAX }, + { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_MOUSE), + .driver_data = CP_2WHEEL_MOUSE_HACK }, + { } +}; +MODULE_DEVICE_TABLE(hid, cp_devices); + +static struct hid_driver cp_driver = { + .name = "cypress", + .id_table = cp_devices, + .report_fixup = cp_report_fixup, + .input_mapped = cp_input_mapped, + .event = cp_event, + .probe = cp_probe, +}; + +static int cp_init(void) +{ + return hid_register_driver(&cp_driver); +} + +static void cp_exit(void) +{ + hid_unregister_driver(&cp_driver); +} + +module_init(cp_init); +module_exit(cp_exit); +MODULE_LICENSE("GPL"); + +HID_COMPAT_LOAD_DRIVER(cypress); diff --git a/drivers/hid/hid-dummy.c b/drivers/hid/hid-dummy.c index 0c833d920c3..27cffe3586f 100644 --- a/drivers/hid/hid-dummy.c +++ b/drivers/hid/hid-dummy.c @@ -7,6 +7,9 @@ static int __init hid_dummy_init(void) #ifdef CONFIG_HID_APPLE_MODULE HID_COMPAT_CALL_DRIVER(apple); #endif +#ifdef CONFIG_HID_CYPRESS_MODULE + HID_COMPAT_CALL_DRIVER(cypress); +#endif #ifdef CONFIG_HID_LOGITECH_MODULE HID_COMPAT_CALL_DRIVER(logitech); #endif diff --git a/drivers/hid/hid-input-quirks.c b/drivers/hid/hid-input-quirks.c index a5e7163158f..6e7314f7b99 100644 --- a/drivers/hid/hid-input-quirks.c +++ b/drivers/hid/hid-input-quirks.c @@ -236,8 +236,8 @@ int hidinput_event_quirks(struct hid_device *hid, struct hid_field *field, struc input = field->hidinput->input; - if (((hid->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_5) && (usage->hid == 0x00090005)) - || ((hid->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_7) && (usage->hid == 0x00090007))) { + if ((hid->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_7) && + (usage->hid == 0x00090007)) { if (value) hid->quirks |= HID_QUIRK_2WHEEL_MOUSE_HACK_ON; else hid->quirks &= ~HID_QUIRK_2WHEEL_MOUSE_HACK_ON; return 1; diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c index a6223bc5c73..f1df25ab0ba 100644 --- a/drivers/hid/hid-input.c +++ b/drivers/hid/hid-input.c @@ -515,13 +515,13 @@ mapped: hidinput, field, usage, &bit, &max) < 0) goto ignore; - if ((device->quirks & (HID_QUIRK_2WHEEL_MOUSE_HACK_7 | HID_QUIRK_2WHEEL_MOUSE_HACK_5 | + if ((device->quirks & (HID_QUIRK_2WHEEL_MOUSE_HACK_7 | HID_QUIRK_2WHEEL_MOUSE_HACK_B8)) && (usage->type == EV_REL) && (usage->code == REL_WHEEL)) set_bit(REL_HWHEEL, bit); - if (((device->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_5) && (usage->hid == 0x00090005)) - || ((device->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_7) && (usage->hid == 0x00090007))) + if ((device->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_7) && + (usage->hid == 0x00090007)) goto ignore; set_bit(usage->type, input->evbit); diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c index 7f38c21e146..da80c64fb25 100644 --- a/drivers/hid/usbhid/hid-quirks.c +++ b/drivers/hid/usbhid/hid-quirks.c @@ -31,7 +31,6 @@ static const struct hid_blacklist { { USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_WCP32PU, HID_QUIRK_2WHEEL_MOUSE_HACK_7 }, { USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_X5_005D, HID_QUIRK_2WHEEL_MOUSE_HACK_B8 }, - { USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_MOUSE, HID_QUIRK_2WHEEL_MOUSE_HACK_5 }, { USB_VENDOR_ID_AASHIMA, USB_DEVICE_ID_AASHIMA_GAMEPAD, HID_QUIRK_BADPAD }, { USB_VENDOR_ID_AASHIMA, USB_DEVICE_ID_AASHIMA_PREDATOR, HID_QUIRK_BADPAD }, @@ -93,9 +92,6 @@ static const struct hid_rdesc_blacklist { { USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_IR_REMOTE, HID_QUIRK_RDESC_SAMSUNG_REMOTE }, - { USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_1, HID_QUIRK_RDESC_SWAPPED_MIN_MAX }, - { USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_2, HID_QUIRK_RDESC_SWAPPED_MIN_MAX }, - { 0, 0 } }; @@ -382,30 +378,6 @@ static void usbhid_fixup_petalynx_descriptor(unsigned char *rdesc, int rsize) } } -/* - * Some USB barcode readers from cypress have usage min and usage max in - * the wrong order - */ -static void usbhid_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) - printk(KERN_INFO "Fixing up Cypress report descriptor\n"); -} - static void usbhid_fixup_button_consumer_descriptor(unsigned char *rdesc, int rsize) { if (rsize >= 30 && rdesc[29] == 0x05 @@ -420,9 +392,6 @@ static void __usbhid_fixup_report_descriptor(__u32 quirks, char *rdesc, unsigned if ((quirks & HID_QUIRK_RDESC_CYMOTION)) usbhid_fixup_cymotion_descriptor(rdesc, rsize); - if (quirks & HID_QUIRK_RDESC_SWAPPED_MIN_MAX) - usbhid_fixup_cypress_descriptor(rdesc, rsize); - if (quirks & HID_QUIRK_RDESC_PETALYNX) usbhid_fixup_petalynx_descriptor(rdesc, rsize); diff --git a/include/linux/hid.h b/include/linux/hid.h index a83d211021d..27bfbcc1ef8 100644 --- a/include/linux/hid.h +++ b/include/linux/hid.h @@ -262,7 +262,6 @@ struct hid_item { #define HID_QUIRK_BADPAD 0x00000020 #define HID_QUIRK_MULTI_INPUT 0x00000040 #define HID_QUIRK_2WHEEL_MOUSE_HACK_7 0x00000080 -#define HID_QUIRK_2WHEEL_MOUSE_HACK_5 0x00000100 #define HID_QUIRK_2WHEEL_MOUSE_HACK_ON 0x00000200 #define HID_QUIRK_SKIP_OUTPUT_REPORTS 0x00010000 #define HID_QUIRK_SONY_PS3_CONTROLLER 0x00040000 @@ -278,7 +277,6 @@ struct hid_item { */ #define HID_QUIRK_RDESC_CYMOTION 0x00000001 -#define HID_QUIRK_RDESC_SWAPPED_MIN_MAX 0x00000004 #define HID_QUIRK_RDESC_PETALYNX 0x00000008 #define HID_QUIRK_RDESC_BUTTON_CONSUMER 0x00000020 #define HID_QUIRK_RDESC_SAMSUNG_REMOTE 0x00000040 -- cgit v1.2.3-70-g09d2 From 14a21cd459f97e3b3cc4fcde48fc5bcdb81d097e Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 23 Jun 2008 23:31:09 +0200 Subject: HID: move a4tech quirks Signed-off-by: Jiri Slaby Signed-off-by: Jiri Kosina --- drivers/hid/Kconfig | 7 ++ drivers/hid/Makefile | 1 + drivers/hid/hid-a4tech.c | 162 ++++++++++++++++++++++++++++++++++++++++ drivers/hid/hid-core.c | 2 + drivers/hid/hid-dummy.c | 3 + drivers/hid/hid-input-quirks.c | 25 ------- drivers/hid/hid-input.c | 9 --- drivers/hid/usbhid/hid-quirks.c | 4 - include/linux/hid.h | 5 -- 9 files changed, 175 insertions(+), 43 deletions(-) create mode 100644 drivers/hid/hid-a4tech.c (limited to 'drivers/hid/Kconfig') diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index 69f3420882a..01456b1d383 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -82,6 +82,13 @@ config HID_COMPAT If unsure, say Y. +config HID_A4TECH + tristate "A4 tech" + default m + depends on USB_HID + ---help--- + Support for A4 tech X5 and WOP-35 / Trust 450L mice. + config HID_APPLE tristate "Apple" default m diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile index 06106620118..ceede11eed7 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile @@ -12,6 +12,7 @@ ifdef CONFIG_HID_COMPAT obj-m += hid-dummy.o endif +obj-$(CONFIG_HID_A4TECH) += hid-a4tech.o obj-$(CONFIG_HID_APPLE) += hid-apple.o obj-$(CONFIG_HID_CYPRESS) += hid-cypress.o obj-$(CONFIG_HID_LOGITECH) += hid-logitech.o diff --git a/drivers/hid/hid-a4tech.c b/drivers/hid/hid-a4tech.c new file mode 100644 index 00000000000..26e16083a1f --- /dev/null +++ b/drivers/hid/hid-a4tech.c @@ -0,0 +1,162 @@ +/* + * HID driver for some a4tech "special" devices + * + * Copyright (c) 1999 Andreas Gal + * Copyright (c) 2000-2005 Vojtech Pavlik + * Copyright (c) 2005 Michael Haboustak for Concept2, Inc + * Copyright (c) 2006-2007 Jiri Kosina + * Copyright (c) 2007 Paul Walmsley + * Copyright (c) 2008 Jiri Slaby + */ + +/* + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + */ + +#include +#include +#include +#include + +#include "hid-ids.h" + +#define A4_2WHEEL_MOUSE_HACK_7 0x01 +#define A4_2WHEEL_MOUSE_HACK_B8 0x02 + +struct a4tech_sc { + unsigned long quirks; + unsigned int hw_wheel; + __s32 delayed_value; +}; + +static int a4_input_mapped(struct hid_device *hdev, struct hid_input *hi, + struct hid_field *field, struct hid_usage *usage, + unsigned long **bit, int *max) +{ + struct a4tech_sc *a4 = hid_get_drvdata(hdev); + + if (usage->type == EV_REL && usage->code == REL_WHEEL) + set_bit(REL_HWHEEL, *bit); + + if ((a4->quirks & A4_2WHEEL_MOUSE_HACK_7) && usage->hid == 0x00090007) + return -1; + + return 0; +} + +static int a4_event(struct hid_device *hdev, struct hid_field *field, + struct hid_usage *usage, __s32 value) +{ + struct a4tech_sc *a4 = hid_get_drvdata(hdev); + struct input_dev *input; + + if (!(hdev->claimed & HID_CLAIMED_INPUT) || !field->hidinput || + !usage->type) + return 0; + + input = field->hidinput->input; + + if (a4->quirks & A4_2WHEEL_MOUSE_HACK_B8) { + if (usage->type == EV_REL && usage->code == REL_WHEEL) { + a4->delayed_value = value; + return 1; + } + + if (usage->hid == 0x000100b8) { + input_event(input, EV_REL, value ? REL_HWHEEL : + REL_WHEEL, a4->delayed_value); + return 1; + } + } + + if ((a4->quirks & A4_2WHEEL_MOUSE_HACK_7) && usage->hid == 0x00090007) { + a4->hw_wheel = !!value; + return 1; + } + + if (usage->code == REL_WHEEL && a4->hw_wheel) { + input_event(input, usage->type, REL_HWHEEL, value); + return 1; + } + + return 0; +} + +static int a4_probe(struct hid_device *hdev, const struct hid_device_id *id) +{ + struct a4tech_sc *a4; + int ret; + + a4 = kzalloc(sizeof(*a4), GFP_KERNEL); + if (a4 == NULL) { + dev_err(&hdev->dev, "can't alloc device descriptor\n"); + ret = -ENOMEM; + goto err_free; + } + + a4->quirks = id->driver_data; + + hid_set_drvdata(hdev, a4); + + ret = hid_parse(hdev); + if (ret) { + dev_err(&hdev->dev, "parse failed\n"); + goto err_free; + } + + ret = hid_hw_start(hdev); + if (ret) { + dev_err(&hdev->dev, "hw start failed\n"); + goto err_free; + } + + return 0; +err_free: + kfree(a4); + return ret; +} + +static void a4_remove(struct hid_device *hdev) +{ + struct a4tech_sc *a4 = hid_get_drvdata(hdev); + + hid_hw_stop(hdev); + kfree(a4); +} + +static const struct hid_device_id a4_devices[] = { + { HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_WCP32PU), + .driver_data = A4_2WHEEL_MOUSE_HACK_7 }, + { HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_X5_005D), + .driver_data = A4_2WHEEL_MOUSE_HACK_B8 }, + { } +}; +MODULE_DEVICE_TABLE(hid, a4_devices); + +static struct hid_driver a4_driver = { + .name = "a4tech", + .id_table = a4_devices, + .input_mapped = a4_input_mapped, + .event = a4_event, + .probe = a4_probe, + .remove = a4_remove, +}; + +static int a4_init(void) +{ + return hid_register_driver(&a4_driver); +} + +static void a4_exit(void) +{ + hid_unregister_driver(&a4_driver); +} + +module_init(a4_init); +module_exit(a4_exit); +MODULE_LICENSE("GPL"); + +HID_COMPAT_LOAD_DRIVER(a4tech); diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 331670b32e6..be582976db2 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1132,6 +1132,8 @@ static const struct hid_device_id *hid_match_id(struct hid_device *hdev, } static const struct hid_device_id hid_blacklist[] = { + { HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_WCP32PU) }, + { HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_X5_005D) }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL4) }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MIGHTYMOUSE) }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ANSI) }, diff --git a/drivers/hid/hid-dummy.c b/drivers/hid/hid-dummy.c index 27cffe3586f..123f1c71cdf 100644 --- a/drivers/hid/hid-dummy.c +++ b/drivers/hid/hid-dummy.c @@ -4,6 +4,9 @@ static int __init hid_dummy_init(void) { +#ifdef CONFIG_HID_A4TECH_MODULE + HID_COMPAT_CALL_DRIVER(a4tech); +#endif #ifdef CONFIG_HID_APPLE_MODULE HID_COMPAT_CALL_DRIVER(apple); #endif diff --git a/drivers/hid/hid-input-quirks.c b/drivers/hid/hid-input-quirks.c index 6e7314f7b99..5bacf181a8c 100644 --- a/drivers/hid/hid-input-quirks.c +++ b/drivers/hid/hid-input-quirks.c @@ -236,31 +236,6 @@ int hidinput_event_quirks(struct hid_device *hid, struct hid_field *field, struc input = field->hidinput->input; - if ((hid->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_7) && - (usage->hid == 0x00090007)) { - if (value) hid->quirks |= HID_QUIRK_2WHEEL_MOUSE_HACK_ON; - else hid->quirks &= ~HID_QUIRK_2WHEEL_MOUSE_HACK_ON; - return 1; - } - - if ((hid->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_B8) && - (usage->type == EV_REL) && - (usage->code == REL_WHEEL)) { - hid->delayed_value = value; - return 1; - } - - if ((hid->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_B8) && - (usage->hid == 0x000100b8)) { - input_event(input, EV_REL, value ? REL_HWHEEL : REL_WHEEL, hid->delayed_value); - return 1; - } - - if ((hid->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_ON) && (usage->code == REL_WHEEL)) { - input_event(input, usage->type, REL_HWHEEL, value); - return 1; - } - /* handle the temporary quirky mapping to HWHEEL */ if (hid->quirks & HID_QUIRK_HWHEEL_WHEEL_INVERT && usage->type == EV_REL && usage->code == REL_HWHEEL) { diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c index f1df25ab0ba..1d2d0827820 100644 --- a/drivers/hid/hid-input.c +++ b/drivers/hid/hid-input.c @@ -515,15 +515,6 @@ mapped: hidinput, field, usage, &bit, &max) < 0) goto ignore; - if ((device->quirks & (HID_QUIRK_2WHEEL_MOUSE_HACK_7 | - HID_QUIRK_2WHEEL_MOUSE_HACK_B8)) && (usage->type == EV_REL) && - (usage->code == REL_WHEEL)) - set_bit(REL_HWHEEL, bit); - - if ((device->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_7) && - (usage->hid == 0x00090007)) - goto ignore; - set_bit(usage->type, input->evbit); while (usage->code <= max && test_and_set_bit(usage->code, bit)) diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c index da80c64fb25..1d12fb24829 100644 --- a/drivers/hid/usbhid/hid-quirks.c +++ b/drivers/hid/usbhid/hid-quirks.c @@ -28,10 +28,6 @@ static const struct hid_blacklist { __u16 idProduct; __u32 quirks; } hid_blacklist[] = { - - { USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_WCP32PU, HID_QUIRK_2WHEEL_MOUSE_HACK_7 }, - { USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_X5_005D, HID_QUIRK_2WHEEL_MOUSE_HACK_B8 }, - { USB_VENDOR_ID_AASHIMA, USB_DEVICE_ID_AASHIMA_GAMEPAD, HID_QUIRK_BADPAD }, { USB_VENDOR_ID_AASHIMA, USB_DEVICE_ID_AASHIMA_PREDATOR, HID_QUIRK_BADPAD }, { USB_VENDOR_ID_ALPS, USB_DEVICE_ID_IBM_GAMEPAD, HID_QUIRK_BADPAD }, diff --git a/include/linux/hid.h b/include/linux/hid.h index 27bfbcc1ef8..a7cc4af2e46 100644 --- a/include/linux/hid.h +++ b/include/linux/hid.h @@ -261,14 +261,11 @@ struct hid_item { #define HID_QUIRK_HIDDEV 0x00000010 #define HID_QUIRK_BADPAD 0x00000020 #define HID_QUIRK_MULTI_INPUT 0x00000040 -#define HID_QUIRK_2WHEEL_MOUSE_HACK_7 0x00000080 -#define HID_QUIRK_2WHEEL_MOUSE_HACK_ON 0x00000200 #define HID_QUIRK_SKIP_OUTPUT_REPORTS 0x00010000 #define HID_QUIRK_SONY_PS3_CONTROLLER 0x00040000 #define HID_QUIRK_RESET_LEDS 0x00100000 #define HID_QUIRK_HIDINPUT 0x00200000 #define HID_QUIRK_IGNORE_HIDINPUT 0x01000000 -#define HID_QUIRK_2WHEEL_MOUSE_HACK_B8 0x02000000 #define HID_QUIRK_HWHEEL_WHEEL_INVERT 0x04000000 #define HID_QUIRK_FULLSPEED_INTERVAL 0x10000000 @@ -453,8 +450,6 @@ struct hid_device { /* device report descriptor */ void *driver_data; - __s32 delayed_value; /* For A4 Tech mice hwheel quirk */ - /* hiddev event handler */ void (*hiddev_hid_event) (struct hid_device *, struct hid_field *field, struct hid_usage *, __s32); -- cgit v1.2.3-70-g09d2 From 3b239cd739a9499da08326356add3d9d992c7911 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 24 Jun 2008 20:42:25 +0200 Subject: HID: move cherry quirks Signed-off-by: Jiri Slaby Signed-off-by: Jiri Kosina --- drivers/hid/Kconfig | 7 ++++ drivers/hid/Makefile | 1 + drivers/hid/hid-cherry.c | 87 +++++++++++++++++++++++++++++++++++++++++ drivers/hid/hid-core.c | 1 + drivers/hid/hid-dummy.c | 3 ++ drivers/hid/hid-input-quirks.c | 21 ---------- drivers/hid/usbhid/hid-quirks.c | 19 --------- include/linux/hid.h | 1 - 8 files changed, 99 insertions(+), 41 deletions(-) create mode 100644 drivers/hid/hid-cherry.c (limited to 'drivers/hid/Kconfig') diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index 01456b1d383..85aabb5d971 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -103,6 +103,13 @@ config HID_APPLE If unsure, say M. +config HID_CHERRY + tristate "Cherry" + default m + depends on USB_HID + ---help--- + Support for Cherry Cymotion. + config HID_CYPRESS tristate "Cypress" default m diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile index ceede11eed7..cd6bd024767 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile @@ -14,6 +14,7 @@ endif obj-$(CONFIG_HID_A4TECH) += hid-a4tech.o obj-$(CONFIG_HID_APPLE) += hid-apple.o +obj-$(CONFIG_HID_CHERRY) += hid-cherry.o obj-$(CONFIG_HID_CYPRESS) += hid-cypress.o obj-$(CONFIG_HID_LOGITECH) += hid-logitech.o obj-$(CONFIG_HID_MICROSOFT) += hid-microsoft.o diff --git a/drivers/hid/hid-cherry.c b/drivers/hid/hid-cherry.c new file mode 100644 index 00000000000..b833b9769ab --- /dev/null +++ b/drivers/hid/hid-cherry.c @@ -0,0 +1,87 @@ +/* + * HID driver for some cherry "special" devices + * + * Copyright (c) 1999 Andreas Gal + * Copyright (c) 2000-2005 Vojtech Pavlik + * Copyright (c) 2005 Michael Haboustak for Concept2, Inc + * Copyright (c) 2006-2007 Jiri Kosina + * Copyright (c) 2007 Paul Walmsley + * Copyright (c) 2008 Jiri Slaby + */ + +/* + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + */ + +#include +#include +#include + +#include "hid-ids.h" + +/* + * Cherry Cymotion keyboard have an invalid HID report descriptor, + * that needs fixing before we can parse it. + */ +static void ch_report_fixup(struct hid_device *hdev, __u8 *rdesc, + unsigned int rsize) +{ + if (rsize >= 17 && rdesc[11] == 0x3c && rdesc[12] == 0x02) { + dev_info(&hdev->dev, "fixing up Cherry Cymotion report " + "descriptor\n"); + rdesc[11] = rdesc[16] = 0xff; + rdesc[12] = rdesc[17] = 0x03; + } +} + +#define ch_map_key_clear(c) hid_map_usage_clear(hi, usage, bit, max, \ + EV_KEY, (c)) +static int ch_input_mapping(struct hid_device *hdev, struct hid_input *hi, + struct hid_field *field, struct hid_usage *usage, + unsigned long **bit, int *max) +{ + if ((usage->hid & HID_USAGE_PAGE) != HID_UP_CONSUMER) + return 0; + + switch (usage->hid & HID_USAGE) { + case 0x301: ch_map_key_clear(KEY_PROG1); break; + case 0x302: ch_map_key_clear(KEY_PROG2); break; + case 0x303: ch_map_key_clear(KEY_PROG3); break; + default: + return 0; + } + + return 1; +} + +static const struct hid_device_id ch_devices[] = { + { HID_USB_DEVICE(USB_VENDOR_ID_CHERRY, USB_DEVICE_ID_CHERRY_CYMOTION) }, + { } +}; +MODULE_DEVICE_TABLE(hid, ch_devices); + +static struct hid_driver ch_driver = { + .name = "cherry", + .id_table = ch_devices, + .report_fixup = ch_report_fixup, + .input_mapping = ch_input_mapping, +}; + +static int ch_init(void) +{ + return hid_register_driver(&ch_driver); +} + +static void ch_exit(void) +{ + hid_unregister_driver(&ch_driver); +} + +module_init(ch_init); +module_exit(ch_exit); +MODULE_LICENSE("GPL"); + +HID_COMPAT_LOAD_DRIVER(cherry); diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index be582976db2..5acdc374285 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1164,6 +1164,7 @@ static const struct hid_device_id hid_blacklist[] = { { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING2_JIS) }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY) }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY) }, + { HID_USB_DEVICE(USB_VENDOR_ID_CHERRY, USB_DEVICE_ID_CHERRY_CYMOTION) }, { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_1) }, { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_2) }, { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_MOUSE) }, diff --git a/drivers/hid/hid-dummy.c b/drivers/hid/hid-dummy.c index 123f1c71cdf..178344ea651 100644 --- a/drivers/hid/hid-dummy.c +++ b/drivers/hid/hid-dummy.c @@ -10,6 +10,9 @@ static int __init hid_dummy_init(void) #ifdef CONFIG_HID_APPLE_MODULE HID_COMPAT_CALL_DRIVER(apple); #endif +#ifdef CONFIG_HID_CHERRY_MODULE + HID_COMPAT_CALL_DRIVER(cherry); +#endif #ifdef CONFIG_HID_CYPRESS_MODULE HID_COMPAT_CALL_DRIVER(cypress); #endif diff --git a/drivers/hid/hid-input-quirks.c b/drivers/hid/hid-input-quirks.c index 5bacf181a8c..97ee75064a0 100644 --- a/drivers/hid/hid-input-quirks.c +++ b/drivers/hid/hid-input-quirks.c @@ -38,22 +38,6 @@ static int quirk_belkin_wkbd(struct hid_usage *usage, return 1; } -static int quirk_cherry_cymotion(struct hid_usage *usage, - struct hid_input *hidinput, unsigned long **bit, int *max) -{ - if ((usage->hid & HID_USAGE_PAGE) != HID_UP_CONSUMER) - return 0; - - switch (usage->hid & HID_USAGE) { - case 0x301: map_key_clear(KEY_PROG1); break; - case 0x302: map_key_clear(KEY_PROG2); break; - case 0x303: map_key_clear(KEY_PROG3); break; - default: - return 0; - } - return 1; -} - static int quirk_gyration_remote(struct hid_usage *usage, struct hid_input *hidinput, unsigned long **bit, int *max) { @@ -173,9 +157,6 @@ static int quirk_btc_8193(struct hid_usage *usage, struct hid_input *hidinput, #define VENDOR_ID_BELKIN 0x1020 #define DEVICE_ID_BELKIN_WIRELESS_KEYBOARD 0x0006 -#define VENDOR_ID_CHERRY 0x046a -#define DEVICE_ID_CHERRY_CYMOTION 0x0023 - #define VENDOR_ID_CHICONY 0x04f2 #define DEVICE_ID_CHICONY_TACTICAL_PAD 0x0418 @@ -199,8 +180,6 @@ static const struct hid_input_blacklist { } hid_input_blacklist[] = { { VENDOR_ID_BELKIN, DEVICE_ID_BELKIN_WIRELESS_KEYBOARD, quirk_belkin_wkbd }, - { VENDOR_ID_CHERRY, DEVICE_ID_CHERRY_CYMOTION, quirk_cherry_cymotion }, - { VENDOR_ID_CHICONY, DEVICE_ID_CHICONY_TACTICAL_PAD, quirk_chicony_tactical_pad }, { VENDOR_ID_EZKEY, DEVICE_ID_BTC_8193, quirk_btc_8193 }, diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c index 1d12fb24829..0cc6e4223cd 100644 --- a/drivers/hid/usbhid/hid-quirks.c +++ b/drivers/hid/usbhid/hid-quirks.c @@ -79,9 +79,6 @@ static const struct hid_rdesc_blacklist { __u16 idProduct; __u32 quirks; } hid_rdesc_blacklist[] = { - - { USB_VENDOR_ID_CHERRY, USB_DEVICE_ID_CHERRY_CYMOTION, HID_QUIRK_RDESC_CYMOTION }, - { USB_VENDOR_ID_MONTEREY, USB_DEVICE_ID_GENIUS_KB29E, HID_QUIRK_RDESC_BUTTON_CONSUMER }, { USB_VENDOR_ID_PETALYNX, USB_DEVICE_ID_PETALYNX_MAXTER_REMOTE, HID_QUIRK_RDESC_PETALYNX }, @@ -319,19 +316,6 @@ u32 usbhid_lookup_quirk(const u16 idVendor, const u16 idProduct) EXPORT_SYMBOL_GPL(usbhid_lookup_quirk); -/* - * Cherry Cymotion keyboard have an invalid HID report descriptor, - * that needs fixing before we can parse it. - */ -static void usbhid_fixup_cymotion_descriptor(char *rdesc, int rsize) -{ - if (rsize >= 17 && rdesc[11] == 0x3c && rdesc[12] == 0x02) { - printk(KERN_INFO "Fixing up Cherry Cymotion report descriptor\n"); - rdesc[11] = rdesc[16] = 0xff; - rdesc[12] = rdesc[17] = 0x03; - } -} - /* * Samsung IrDA remote controller (reports as Cypress USB Mouse). * @@ -385,9 +369,6 @@ static void usbhid_fixup_button_consumer_descriptor(unsigned char *rdesc, int rs static void __usbhid_fixup_report_descriptor(__u32 quirks, char *rdesc, unsigned rsize) { - if ((quirks & HID_QUIRK_RDESC_CYMOTION)) - usbhid_fixup_cymotion_descriptor(rdesc, rsize); - if (quirks & HID_QUIRK_RDESC_PETALYNX) usbhid_fixup_petalynx_descriptor(rdesc, rsize); diff --git a/include/linux/hid.h b/include/linux/hid.h index a7cc4af2e46..d9ab4a3af43 100644 --- a/include/linux/hid.h +++ b/include/linux/hid.h @@ -273,7 +273,6 @@ struct hid_item { * Separate quirks for runtime report descriptor fixup */ -#define HID_QUIRK_RDESC_CYMOTION 0x00000001 #define HID_QUIRK_RDESC_PETALYNX 0x00000008 #define HID_QUIRK_RDESC_BUTTON_CONSUMER 0x00000020 #define HID_QUIRK_RDESC_SAMSUNG_REMOTE 0x00000040 -- cgit v1.2.3-70-g09d2 From 1f243e302cea1561ac881eb5d27041c5342beba4 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 24 Jun 2008 21:11:21 +0200 Subject: HID: move ezkey quirks Signed-off-by: Jiri Slaby Signed-off-by: Jiri Kosina --- drivers/hid/Kconfig | 7 +++ drivers/hid/Makefile | 1 + drivers/hid/hid-core.c | 1 + drivers/hid/hid-dummy.c | 3 ++ drivers/hid/hid-ezkey.c | 95 +++++++++++++++++++++++++++++++++++++++++ drivers/hid/hid-input-quirks.c | 37 ---------------- drivers/hid/usbhid/hid-quirks.c | 2 - include/linux/hid.h | 1 - 8 files changed, 107 insertions(+), 40 deletions(-) create mode 100644 drivers/hid/hid-ezkey.c (limited to 'drivers/hid/Kconfig') diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index 85aabb5d971..8098ad322b7 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -117,6 +117,13 @@ config HID_CYPRESS ---help--- Support for Cypress mouse and barcodes. +config HID_EZKEY + tristate "Ezkey" + default m + depends on USB_HID + ---help--- + Support for Ezkey mouse and barcodes. + config HID_LOGITECH tristate "Logitech" default m diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile index cd6bd024767..4790777f843 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile @@ -16,6 +16,7 @@ obj-$(CONFIG_HID_A4TECH) += hid-a4tech.o obj-$(CONFIG_HID_APPLE) += hid-apple.o obj-$(CONFIG_HID_CHERRY) += hid-cherry.o obj-$(CONFIG_HID_CYPRESS) += hid-cypress.o +obj-$(CONFIG_HID_EZKEY) += hid-ezkey.o obj-$(CONFIG_HID_LOGITECH) += hid-logitech.o obj-$(CONFIG_HID_MICROSOFT) += hid-microsoft.o obj-$(CONFIG_HID_SUNPLUS) += hid-sunplus.o diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 5acdc374285..84e478df057 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1168,6 +1168,7 @@ static const struct hid_device_id hid_blacklist[] = { { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_1) }, { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_2) }, { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_MOUSE) }, + { HID_USB_DEVICE(USB_VENDOR_ID_EZKEY, USB_DEVICE_ID_BTC_8193) }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_MX3000_RECEIVER) }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER) }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER_2) }, diff --git a/drivers/hid/hid-dummy.c b/drivers/hid/hid-dummy.c index 178344ea651..0dbdbb73b73 100644 --- a/drivers/hid/hid-dummy.c +++ b/drivers/hid/hid-dummy.c @@ -16,6 +16,9 @@ static int __init hid_dummy_init(void) #ifdef CONFIG_HID_CYPRESS_MODULE HID_COMPAT_CALL_DRIVER(cypress); #endif +#ifdef CONFIG_HID_EZKEY_MODULE + HID_COMPAT_CALL_DRIVER(ezkey); +#endif #ifdef CONFIG_HID_LOGITECH_MODULE HID_COMPAT_CALL_DRIVER(logitech); #endif diff --git a/drivers/hid/hid-ezkey.c b/drivers/hid/hid-ezkey.c new file mode 100644 index 00000000000..deb42f931b7 --- /dev/null +++ b/drivers/hid/hid-ezkey.c @@ -0,0 +1,95 @@ +/* + * HID driver for some ezkey "special" devices + * + * Copyright (c) 1999 Andreas Gal + * Copyright (c) 2000-2005 Vojtech Pavlik + * Copyright (c) 2005 Michael Haboustak for Concept2, Inc + * Copyright (c) 2006-2007 Jiri Kosina + * Copyright (c) 2007 Paul Walmsley + * Copyright (c) 2008 Jiri Slaby + */ + +/* + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + */ + +#include +#include +#include +#include + +#include "hid-ids.h" + +#define ez_map_rel(c) hid_map_usage(hi, usage, bit, max, EV_REL, (c)) +#define ez_map_key(c) hid_map_usage(hi, usage, bit, max, EV_KEY, (c)) + +static int ez_input_mapping(struct hid_device *hdev, struct hid_input *hi, + struct hid_field *field, struct hid_usage *usage, + unsigned long **bit, int *max) +{ + if ((usage->hid & HID_USAGE_PAGE) != HID_UP_CONSUMER) + return 0; + + switch (usage->hid & HID_USAGE) { + case 0x230: ez_map_key(BTN_MOUSE); break; + case 0x231: ez_map_rel(REL_WHEEL); break; + /* + * this keyboard has a scrollwheel implemented in + * totally broken way. We map this usage temporarily + * to HWHEEL and handle it in the event quirk handler + */ + case 0x232: ez_map_rel(REL_HWHEEL); break; + default: + return 0; + } + return 1; +} + +static int ez_event(struct hid_device *hdev, struct hid_field *field, + struct hid_usage *usage, __s32 value) +{ + if (!(hdev->claimed & HID_CLAIMED_INPUT) || !field->hidinput || + !usage->type) + return 0; + + /* handle the temporary quirky mapping to HWHEEL */ + if (usage->type == EV_REL && usage->code == REL_HWHEEL) { + struct input_dev *input = field->hidinput->input; + input_event(input, usage->type, REL_WHEEL, -value); + return 1; + } + + return 0; +} + +static const struct hid_device_id ez_devices[] = { + { HID_USB_DEVICE(USB_VENDOR_ID_EZKEY, USB_DEVICE_ID_BTC_8193) }, + { } +}; +MODULE_DEVICE_TABLE(hid, ez_devices); + +static struct hid_driver ez_driver = { + .name = "ezkey", + .id_table = ez_devices, + .input_mapping = ez_input_mapping, + .event = ez_event, +}; + +static int ez_init(void) +{ + return hid_register_driver(&ez_driver); +} + +static void ez_exit(void) +{ + hid_unregister_driver(&ez_driver); +} + +module_init(ez_init); +module_exit(ez_exit); +MODULE_LICENSE("GPL"); + +HID_COMPAT_LOAD_DRIVER(ezkey); diff --git a/drivers/hid/hid-input-quirks.c b/drivers/hid/hid-input-quirks.c index 97ee75064a0..4cd585b64ae 100644 --- a/drivers/hid/hid-input-quirks.c +++ b/drivers/hid/hid-input-quirks.c @@ -16,9 +16,6 @@ #include #include -#define map_rel(c) hid_map_usage(hidinput, usage, bit, max, EV_REL, (c)) -#define map_key(c) hid_map_usage(hidinput, usage, bit, max, EV_KEY, (c)) - #define map_key_clear(c) hid_map_usage_clear(hidinput, usage, bit, \ max, EV_KEY, (c)) @@ -132,37 +129,12 @@ static int quirk_cherry_genius_29e(struct hid_usage *usage, return 1; } -static int quirk_btc_8193(struct hid_usage *usage, struct hid_input *hidinput, - unsigned long **bit, int *max) -{ - if ((usage->hid & HID_USAGE_PAGE) != HID_UP_CONSUMER) - return 0; - - switch (usage->hid & HID_USAGE) { - case 0x230: map_key(BTN_MOUSE); break; - case 0x231: map_rel(REL_WHEEL); break; - /* - * this keyboard has a scrollwheel implemented in - * totally broken way. We map this usage temporarily - * to HWHEEL and handle it in the event quirk handler - */ - case 0x232: map_rel(REL_HWHEEL); break; - - default: - return 0; - } - return 1; -} - #define VENDOR_ID_BELKIN 0x1020 #define DEVICE_ID_BELKIN_WIRELESS_KEYBOARD 0x0006 #define VENDOR_ID_CHICONY 0x04f2 #define DEVICE_ID_CHICONY_TACTICAL_PAD 0x0418 -#define VENDOR_ID_EZKEY 0x0518 -#define DEVICE_ID_BTC_8193 0x0002 - #define VENDOR_ID_GYRATION 0x0c16 #define DEVICE_ID_GYRATION_REMOTE 0x0002 @@ -182,8 +154,6 @@ static const struct hid_input_blacklist { { VENDOR_ID_CHICONY, DEVICE_ID_CHICONY_TACTICAL_PAD, quirk_chicony_tactical_pad }, - { VENDOR_ID_EZKEY, DEVICE_ID_BTC_8193, quirk_btc_8193 }, - { VENDOR_ID_GYRATION, DEVICE_ID_GYRATION_REMOTE, quirk_gyration_remote }, { VENDOR_ID_MONTEREY, DEVICE_ID_GENIUS_KB29E, quirk_cherry_genius_29e }, @@ -215,13 +185,6 @@ int hidinput_event_quirks(struct hid_device *hid, struct hid_field *field, struc input = field->hidinput->input; - /* handle the temporary quirky mapping to HWHEEL */ - if (hid->quirks & HID_QUIRK_HWHEEL_WHEEL_INVERT && - usage->type == EV_REL && usage->code == REL_HWHEEL) { - input_event(input, usage->type, REL_WHEEL, -value); - return 1; - } - /* Gyration MCE remote "Sleep" key */ if (hid->vendor == VENDOR_ID_GYRATION && hid->product == DEVICE_ID_GYRATION_REMOTE && diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c index 0cc6e4223cd..ddc16ea159a 100644 --- a/drivers/hid/usbhid/hid-quirks.c +++ b/drivers/hid/usbhid/hid-quirks.c @@ -46,8 +46,6 @@ static const struct hid_blacklist { { USB_VENDOR_ID_BELKIN, USB_DEVICE_ID_FLIP_KVM, HID_QUIRK_HIDDEV }, { USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_IR_REMOTE, HID_QUIRK_HIDDEV | HID_QUIRK_IGNORE_HIDINPUT }, - { USB_VENDOR_ID_EZKEY, USB_DEVICE_ID_BTC_8193, HID_QUIRK_HWHEEL_WHEEL_INVERT }, - { USB_VENDOR_ID_PANTHERLORD, USB_DEVICE_ID_PANTHERLORD_TWIN_USB_JOYSTICK, HID_QUIRK_MULTI_INPUT | HID_QUIRK_SKIP_OUTPUT_REPORTS }, { USB_VENDOR_ID_PLAYDOTCOM, USB_DEVICE_ID_PLAYDOTCOM_EMS_USBII, HID_QUIRK_MULTI_INPUT }, diff --git a/include/linux/hid.h b/include/linux/hid.h index d9ab4a3af43..298cbcce3a2 100644 --- a/include/linux/hid.h +++ b/include/linux/hid.h @@ -266,7 +266,6 @@ struct hid_item { #define HID_QUIRK_RESET_LEDS 0x00100000 #define HID_QUIRK_HIDINPUT 0x00200000 #define HID_QUIRK_IGNORE_HIDINPUT 0x01000000 -#define HID_QUIRK_HWHEEL_WHEEL_INVERT 0x04000000 #define HID_QUIRK_FULLSPEED_INTERVAL 0x10000000 /* -- cgit v1.2.3-70-g09d2 From fcfacfd3594d5d2fa99fb5e7d33dee3904b1a156 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 24 Jun 2008 22:48:52 +0200 Subject: HID: move chicony quirks Signed-off-by: Jiri Slaby Signed-off-by: Jiri Kosina --- drivers/hid/Kconfig | 7 ++++ drivers/hid/Makefile | 1 + drivers/hid/hid-chicony.c | 80 ++++++++++++++++++++++++++++++++++++++++++ drivers/hid/hid-core.c | 1 + drivers/hid/hid-dummy.c | 3 ++ drivers/hid/hid-ids.h | 3 ++ drivers/hid/hid-input-quirks.c | 30 ---------------- 7 files changed, 95 insertions(+), 30 deletions(-) create mode 100644 drivers/hid/hid-chicony.c (limited to 'drivers/hid/Kconfig') diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index 8098ad322b7..1e6a5a04459 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -110,6 +110,13 @@ config HID_CHERRY ---help--- Support for Cherry Cymotion. +config HID_CHICONY + tristate "Chicony" + default m + depends on USB_HID + ---help--- + Support for Chicony Tactical pad. + config HID_CYPRESS tristate "Cypress" default m diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile index 4790777f843..a5eaa3e078b 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile @@ -15,6 +15,7 @@ endif obj-$(CONFIG_HID_A4TECH) += hid-a4tech.o obj-$(CONFIG_HID_APPLE) += hid-apple.o obj-$(CONFIG_HID_CHERRY) += hid-cherry.o +obj-$(CONFIG_HID_CHICONY) += hid-chicony.o obj-$(CONFIG_HID_CYPRESS) += hid-cypress.o obj-$(CONFIG_HID_EZKEY) += hid-ezkey.o obj-$(CONFIG_HID_LOGITECH) += hid-logitech.o diff --git a/drivers/hid/hid-chicony.c b/drivers/hid/hid-chicony.c new file mode 100644 index 00000000000..a54d4096e0f --- /dev/null +++ b/drivers/hid/hid-chicony.c @@ -0,0 +1,80 @@ +/* + * HID driver for some chicony "special" devices + * + * Copyright (c) 1999 Andreas Gal + * Copyright (c) 2000-2005 Vojtech Pavlik + * Copyright (c) 2005 Michael Haboustak for Concept2, Inc + * Copyright (c) 2006-2007 Jiri Kosina + * Copyright (c) 2007 Paul Walmsley + * Copyright (c) 2008 Jiri Slaby + */ + +/* + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + */ + +#include +#include +#include +#include + +#include "hid-ids.h" + +#define ch_map_key_clear(c) hid_map_usage_clear(hi, usage, bit, max, \ + EV_KEY, (c)) +static int ch_input_mapping(struct hid_device *hdev, struct hid_input *hi, + struct hid_field *field, struct hid_usage *usage, + unsigned long **bit, int *max) +{ + if ((usage->hid & HID_USAGE_PAGE) != HID_UP_MSVENDOR) + return 0; + + set_bit(EV_REP, hi->input->evbit); + switch (usage->hid & HID_USAGE) { + case 0xff01: ch_map_key_clear(BTN_1); break; + case 0xff02: ch_map_key_clear(BTN_2); break; + case 0xff03: ch_map_key_clear(BTN_3); break; + case 0xff04: ch_map_key_clear(BTN_4); break; + case 0xff05: ch_map_key_clear(BTN_5); break; + case 0xff06: ch_map_key_clear(BTN_6); break; + case 0xff07: ch_map_key_clear(BTN_7); break; + case 0xff08: ch_map_key_clear(BTN_8); break; + case 0xff09: ch_map_key_clear(BTN_9); break; + case 0xff0a: ch_map_key_clear(BTN_A); break; + case 0xff0b: ch_map_key_clear(BTN_B); break; + default: + return 0; + } + return 1; +} + +static const struct hid_device_id ch_devices[] = { + { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_TACTICAL_PAD) }, + { } +}; +MODULE_DEVICE_TABLE(hid, ch_devices); + +static struct hid_driver ch_driver = { + .name = "chicony", + .id_table = ch_devices, + .input_mapping = ch_input_mapping, +}; + +static int ch_init(void) +{ + return hid_register_driver(&ch_driver); +} + +static void ch_exit(void) +{ + hid_unregister_driver(&ch_driver); +} + +module_init(ch_init); +module_exit(ch_exit); +MODULE_LICENSE("GPL"); + +HID_COMPAT_LOAD_DRIVER(chicony); diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 84e478df057..0c4e7882800 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1165,6 +1165,7 @@ static const struct hid_device_id hid_blacklist[] = { { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY) }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY) }, { HID_USB_DEVICE(USB_VENDOR_ID_CHERRY, USB_DEVICE_ID_CHERRY_CYMOTION) }, + { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_TACTICAL_PAD) }, { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_1) }, { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_2) }, { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_MOUSE) }, diff --git a/drivers/hid/hid-dummy.c b/drivers/hid/hid-dummy.c index 0dbdbb73b73..0b683af41b2 100644 --- a/drivers/hid/hid-dummy.c +++ b/drivers/hid/hid-dummy.c @@ -13,6 +13,9 @@ static int __init hid_dummy_init(void) #ifdef CONFIG_HID_CHERRY_MODULE HID_COMPAT_CALL_DRIVER(cherry); #endif +#ifdef CONFIG_HID_CHICONY_MODULE + HID_COMPAT_CALL_DRIVER(chicony); +#endif #ifdef CONFIG_HID_CYPRESS_MODULE HID_COMPAT_CALL_DRIVER(cypress); #endif diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index d7e548dbe7c..11472d96e2a 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -108,6 +108,9 @@ #define USB_VENDOR_ID_CHIC 0x05fe #define USB_DEVICE_ID_CHIC_GAMEPAD 0x0014 +#define USB_VENDOR_ID_CHICONY 0x04f2 +#define USB_DEVICE_ID_CHICONY_TACTICAL_PAD 0x0418 + #define USB_VENDOR_ID_CIDC 0x1677 #define USB_VENDOR_ID_CMEDIA 0x0d8c diff --git a/drivers/hid/hid-input-quirks.c b/drivers/hid/hid-input-quirks.c index 4cd585b64ae..5f84568b9bd 100644 --- a/drivers/hid/hid-input-quirks.c +++ b/drivers/hid/hid-input-quirks.c @@ -58,31 +58,6 @@ static int quirk_gyration_remote(struct hid_usage *usage, return 1; } -static int quirk_chicony_tactical_pad(struct hid_usage *usage, - struct hid_input *hidinput, unsigned long **bit, int *max) -{ - if ((usage->hid & HID_USAGE_PAGE) != HID_UP_MSVENDOR) - return 0; - - set_bit(EV_REP, hidinput->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: - return 0; - } - return 1; -} - static int quirk_petalynx_remote(struct hid_usage *usage, struct hid_input *hidinput, unsigned long **bit, int *max) { @@ -132,9 +107,6 @@ static int quirk_cherry_genius_29e(struct hid_usage *usage, #define VENDOR_ID_BELKIN 0x1020 #define DEVICE_ID_BELKIN_WIRELESS_KEYBOARD 0x0006 -#define VENDOR_ID_CHICONY 0x04f2 -#define DEVICE_ID_CHICONY_TACTICAL_PAD 0x0418 - #define VENDOR_ID_GYRATION 0x0c16 #define DEVICE_ID_GYRATION_REMOTE 0x0002 @@ -152,8 +124,6 @@ static const struct hid_input_blacklist { } hid_input_blacklist[] = { { VENDOR_ID_BELKIN, DEVICE_ID_BELKIN_WIRELESS_KEYBOARD, quirk_belkin_wkbd }, - { VENDOR_ID_CHICONY, DEVICE_ID_CHICONY_TACTICAL_PAD, quirk_chicony_tactical_pad }, - { VENDOR_ID_GYRATION, DEVICE_ID_GYRATION_REMOTE, quirk_gyration_remote }, { VENDOR_ID_MONTEREY, DEVICE_ID_GENIUS_KB29E, quirk_cherry_genius_29e }, -- cgit v1.2.3-70-g09d2 From b5635b129b3ca3a9c879a36f58f5b8c4903d267a Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 24 Jun 2008 23:24:57 +0200 Subject: HID: move belkin quirks Signed-off-by: Jiri Slaby Signed-off-by: Jiri Kosina --- drivers/hid/Kconfig | 7 +++ drivers/hid/Makefile | 1 + drivers/hid/hid-belkin.c | 107 ++++++++++++++++++++++++++++++++++++++++ drivers/hid/hid-core.c | 2 + drivers/hid/hid-dummy.c | 3 ++ drivers/hid/hid-ids.h | 3 ++ drivers/hid/hid-input-quirks.c | 21 -------- drivers/hid/usbhid/hid-quirks.c | 1 - 8 files changed, 123 insertions(+), 22 deletions(-) create mode 100644 drivers/hid/hid-belkin.c (limited to 'drivers/hid/Kconfig') diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index 1e6a5a04459..b093f3c83e3 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -103,6 +103,13 @@ config HID_APPLE If unsure, say M. +config HID_BELKIN + tristate "Belkin" + default m + depends on USB_HID + ---help--- + Support for Belkin Flip KVM and Wireless keyboard. + config HID_CHERRY tristate "Cherry" default m diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile index a5eaa3e078b..ffb58f8001b 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile @@ -14,6 +14,7 @@ endif obj-$(CONFIG_HID_A4TECH) += hid-a4tech.o obj-$(CONFIG_HID_APPLE) += hid-apple.o +obj-$(CONFIG_HID_BELKIN) += hid-belkin.o obj-$(CONFIG_HID_CHERRY) += hid-cherry.o obj-$(CONFIG_HID_CHICONY) += hid-chicony.o obj-$(CONFIG_HID_CYPRESS) += hid-cypress.o diff --git a/drivers/hid/hid-belkin.c b/drivers/hid/hid-belkin.c new file mode 100644 index 00000000000..050b9892d7e --- /dev/null +++ b/drivers/hid/hid-belkin.c @@ -0,0 +1,107 @@ +/* + * HID driver for some belkin "special" devices + * + * Copyright (c) 1999 Andreas Gal + * Copyright (c) 2000-2005 Vojtech Pavlik + * Copyright (c) 2005 Michael Haboustak for Concept2, Inc + * Copyright (c) 2006-2007 Jiri Kosina + * Copyright (c) 2007 Paul Walmsley + * Copyright (c) 2008 Jiri Slaby + */ + +/* + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + */ + +#include +#include +#include + +#include "hid-ids.h" + +#define BELKIN_HIDDEV 0x01 +#define BELKIN_WKBD 0x02 + +#define belkin_map_key_clear(c) hid_map_usage_clear(hi, usage, bit, max, \ + EV_KEY, (c)) +static int belkin_input_mapping(struct hid_device *hdev, struct hid_input *hi, + struct hid_field *field, struct hid_usage *usage, + unsigned long **bit, int *max) +{ + unsigned long quirks = (unsigned long)hid_get_drvdata(hdev); + + if ((usage->hid & HID_USAGE_PAGE) != HID_UP_CONSUMER || + !(quirks & BELKIN_WKBD)) + return 0; + + switch (usage->hid & HID_USAGE) { + case 0x03a: belkin_map_key_clear(KEY_SOUND); break; + case 0x03b: belkin_map_key_clear(KEY_CAMERA); break; + case 0x03c: belkin_map_key_clear(KEY_DOCUMENTS); break; + default: + return 0; + } + return 1; +} + +static int belkin_probe(struct hid_device *hdev, const struct hid_device_id *id) +{ + unsigned long quirks = id->driver_data; + int ret; + + hid_set_drvdata(hdev, (void *)quirks); + + if (quirks & BELKIN_HIDDEV) + hdev->quirks |= HID_QUIRK_HIDDEV; + + ret = hid_parse(hdev); + if (ret) { + dev_err(&hdev->dev, "parse failed\n"); + goto err_free; + } + + ret = hid_hw_start(hdev); + if (ret) { + dev_err(&hdev->dev, "hw start failed\n"); + goto err_free; + } + + return 0; +err_free: + return ret; +} + +static const struct hid_device_id belkin_devices[] = { + { HID_USB_DEVICE(USB_VENDOR_ID_BELKIN, USB_DEVICE_ID_FLIP_KVM), + .driver_data = BELKIN_HIDDEV }, + { HID_USB_DEVICE(USB_VENDOR_ID_LABTEC, USB_DEVICE_ID_LABTEC_WIRELESS_KEYBOARD), + .driver_data = BELKIN_WKBD }, + { } +}; +MODULE_DEVICE_TABLE(hid, belkin_devices); + +static struct hid_driver belkin_driver = { + .name = "belkin", + .id_table = belkin_devices, + .input_mapping = belkin_input_mapping, + .probe = belkin_probe, +}; + +static int belkin_init(void) +{ + return hid_register_driver(&belkin_driver); +} + +static void belkin_exit(void) +{ + hid_unregister_driver(&belkin_driver); +} + +module_init(belkin_init); +module_exit(belkin_exit); +MODULE_LICENSE("GPL"); + +HID_COMPAT_LOAD_DRIVER(belkin); diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 0c4e7882800..81e7d70260a 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1164,12 +1164,14 @@ static const struct hid_device_id hid_blacklist[] = { { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING2_JIS) }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY) }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY) }, + { HID_USB_DEVICE(USB_VENDOR_ID_BELKIN, USB_DEVICE_ID_FLIP_KVM) }, { HID_USB_DEVICE(USB_VENDOR_ID_CHERRY, USB_DEVICE_ID_CHERRY_CYMOTION) }, { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_TACTICAL_PAD) }, { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_1) }, { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_2) }, { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_MOUSE) }, { HID_USB_DEVICE(USB_VENDOR_ID_EZKEY, USB_DEVICE_ID_BTC_8193) }, + { HID_USB_DEVICE(USB_VENDOR_ID_LABTEC, USB_DEVICE_ID_LABTEC_WIRELESS_KEYBOARD) }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_MX3000_RECEIVER) }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER) }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER_2) }, diff --git a/drivers/hid/hid-dummy.c b/drivers/hid/hid-dummy.c index 0b683af41b2..b95476c4744 100644 --- a/drivers/hid/hid-dummy.c +++ b/drivers/hid/hid-dummy.c @@ -10,6 +10,9 @@ static int __init hid_dummy_init(void) #ifdef CONFIG_HID_APPLE_MODULE HID_COMPAT_CALL_DRIVER(apple); #endif +#ifdef CONFIG_HID_BELKIN_MODULE + HID_COMPAT_CALL_DRIVER(belkin); +#endif #ifdef CONFIG_HID_CHERRY_MODULE HID_COMPAT_CALL_DRIVER(cherry); #endif diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 11472d96e2a..ebe665206a7 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -234,6 +234,9 @@ #define USB_VENDOR_ID_KBGEAR 0x084e #define USB_DEVICE_ID_KBGEAR_JAMSTUDIO 0x1001 +#define USB_VENDOR_ID_LABTEC 0x1020 +#define USB_DEVICE_ID_LABTEC_WIRELESS_KEYBOARD 0x0006 + #define USB_VENDOR_ID_LD 0x0f11 #define USB_DEVICE_ID_LD_CASSY 0x1000 #define USB_DEVICE_ID_LD_POCKETCASSY 0x1010 diff --git a/drivers/hid/hid-input-quirks.c b/drivers/hid/hid-input-quirks.c index 5f84568b9bd..d10f4776555 100644 --- a/drivers/hid/hid-input-quirks.c +++ b/drivers/hid/hid-input-quirks.c @@ -19,22 +19,6 @@ #define map_key_clear(c) hid_map_usage_clear(hidinput, usage, bit, \ max, EV_KEY, (c)) -static int quirk_belkin_wkbd(struct hid_usage *usage, - struct hid_input *hidinput, unsigned long **bit, int *max) -{ - if ((usage->hid & HID_USAGE_PAGE) != HID_UP_CONSUMER) - return 0; - - switch (usage->hid & HID_USAGE) { - case 0x03a: map_key_clear(KEY_SOUND); break; - case 0x03b: map_key_clear(KEY_CAMERA); break; - case 0x03c: map_key_clear(KEY_DOCUMENTS); break; - default: - return 0; - } - return 1; -} - static int quirk_gyration_remote(struct hid_usage *usage, struct hid_input *hidinput, unsigned long **bit, int *max) { @@ -104,9 +88,6 @@ static int quirk_cherry_genius_29e(struct hid_usage *usage, return 1; } -#define VENDOR_ID_BELKIN 0x1020 -#define DEVICE_ID_BELKIN_WIRELESS_KEYBOARD 0x0006 - #define VENDOR_ID_GYRATION 0x0c16 #define DEVICE_ID_GYRATION_REMOTE 0x0002 @@ -122,8 +103,6 @@ static const struct hid_input_blacklist { int (*quirk)(struct hid_usage *, struct hid_input *, unsigned long **, int *); } hid_input_blacklist[] = { - { VENDOR_ID_BELKIN, DEVICE_ID_BELKIN_WIRELESS_KEYBOARD, quirk_belkin_wkbd }, - { VENDOR_ID_GYRATION, DEVICE_ID_GYRATION_REMOTE, quirk_gyration_remote }, { VENDOR_ID_MONTEREY, DEVICE_ID_GENIUS_KB29E, quirk_cherry_genius_29e }, diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c index ddc16ea159a..c344ec2fad5 100644 --- a/drivers/hid/usbhid/hid-quirks.c +++ b/drivers/hid/usbhid/hid-quirks.c @@ -43,7 +43,6 @@ static const struct hid_blacklist { { USB_VENDOR_ID_AFATECH, USB_DEVICE_ID_AFATECH_AF9016, HID_QUIRK_FULLSPEED_INTERVAL }, - { USB_VENDOR_ID_BELKIN, USB_DEVICE_ID_FLIP_KVM, HID_QUIRK_HIDDEV }, { USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_IR_REMOTE, HID_QUIRK_HIDDEV | HID_QUIRK_IGNORE_HIDINPUT }, { USB_VENDOR_ID_PANTHERLORD, USB_DEVICE_ID_PANTHERLORD_TWIN_USB_JOYSTICK, HID_QUIRK_MULTI_INPUT | HID_QUIRK_SKIP_OUTPUT_REPORTS }, -- cgit v1.2.3-70-g09d2 From 1e76253220dbe66e048e55680266dd1f4af0be85 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 24 Jun 2008 23:46:21 +0200 Subject: HID: move petalynx quirks Signed-off-by: Jiri Slaby Signed-off-by: Jiri Kosina --- drivers/hid/Kconfig | 7 +++ drivers/hid/Makefile | 1 + drivers/hid/hid-core.c | 1 + drivers/hid/hid-dummy.c | 3 + drivers/hid/hid-input-quirks.c | 33 ----------- drivers/hid/hid-petalynx.c | 122 ++++++++++++++++++++++++++++++++++++++++ drivers/hid/usbhid/hid-quirks.c | 21 ------- include/linux/hid.h | 1 - 8 files changed, 134 insertions(+), 55 deletions(-) create mode 100644 drivers/hid/hid-petalynx.c (limited to 'drivers/hid/Kconfig') diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index b093f3c83e3..04f646a90d3 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -154,6 +154,13 @@ config HID_MICROSOFT Support for some Microsoft devices which breaks less or more HID specification. +config HID_PETALYNX + tristate "Petalynx" + default m + depends on USB_HID + ---help--- + Support for Petalynx Maxter remote. + config HID_SUNPLUS tristate "Sunplus" default m diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile index ffb58f8001b..359a5bae408 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile @@ -21,6 +21,7 @@ obj-$(CONFIG_HID_CYPRESS) += hid-cypress.o obj-$(CONFIG_HID_EZKEY) += hid-ezkey.o obj-$(CONFIG_HID_LOGITECH) += hid-logitech.o obj-$(CONFIG_HID_MICROSOFT) += hid-microsoft.o +obj-$(CONFIG_HID_PETALYNX) += hid-petalynx.o obj-$(CONFIG_HID_SUNPLUS) += hid-sunplus.o obj-$(CONFIG_USB_HID) += usbhid/ diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 81e7d70260a..2b7a08fe171 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1191,6 +1191,7 @@ static const struct hid_device_id hid_blacklist[] = { { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_LK6K) }, { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_PRESENTER_8K_USB) }, { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_WIRELESS_OPTICAL_DESKTOP_3_0) }, + { HID_USB_DEVICE(USB_VENDOR_ID_PETALYNX, USB_DEVICE_ID_PETALYNX_MAXTER_REMOTE) }, { HID_USB_DEVICE(USB_VENDOR_ID_SUNPLUS, USB_DEVICE_ID_SUNPLUS_WDESKTOP) }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, 0x030c) }, diff --git a/drivers/hid/hid-dummy.c b/drivers/hid/hid-dummy.c index b95476c4744..c28422c9d2b 100644 --- a/drivers/hid/hid-dummy.c +++ b/drivers/hid/hid-dummy.c @@ -31,6 +31,9 @@ static int __init hid_dummy_init(void) #ifdef CONFIG_HID_MICROSOFT_MODULE HID_COMPAT_CALL_DRIVER(microsoft); #endif +#ifdef CONFIG_HID_PETALYNX_MODULE + HID_COMPAT_CALL_DRIVER(petalynx); +#endif #ifdef CONFIG_HID_SUNPLUS_MODULE HID_COMPAT_CALL_DRIVER(sunplus); #endif diff --git a/drivers/hid/hid-input-quirks.c b/drivers/hid/hid-input-quirks.c index d10f4776555..903162a63c4 100644 --- a/drivers/hid/hid-input-quirks.c +++ b/drivers/hid/hid-input-quirks.c @@ -42,34 +42,6 @@ static int quirk_gyration_remote(struct hid_usage *usage, return 1; } -static int quirk_petalynx_remote(struct hid_usage *usage, - struct hid_input *hidinput, unsigned long **bit, int *max) -{ - if (((usage->hid & HID_USAGE_PAGE) != HID_UP_LOGIVENDOR) && - ((usage->hid & HID_USAGE_PAGE) != HID_UP_CONSUMER)) - return 0; - - if ((usage->hid & HID_USAGE_PAGE) == HID_UP_LOGIVENDOR) - switch(usage->hid & HID_USAGE) { - 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: - return 0; - } - - if ((usage->hid & HID_USAGE_PAGE) == HID_UP_CONSUMER) - switch(usage->hid & HID_USAGE) { - case 0x0f6: map_key_clear(KEY_NEXT); break; - case 0x0fa: map_key_clear(KEY_BACK); break; - default: - return 0; - } - return 1; -} - static int quirk_cherry_genius_29e(struct hid_usage *usage, struct hid_input *hidinput, unsigned long **bit, int *max) { @@ -94,9 +66,6 @@ static int quirk_cherry_genius_29e(struct hid_usage *usage, #define VENDOR_ID_MONTEREY 0x0566 #define DEVICE_ID_GENIUS_KB29E 0x3004 -#define VENDOR_ID_PETALYNX 0x18b1 -#define DEVICE_ID_PETALYNX_MAXTER_REMOTE 0x0037 - static const struct hid_input_blacklist { __u16 idVendor; __u16 idProduct; @@ -107,8 +76,6 @@ static const struct hid_input_blacklist { { VENDOR_ID_MONTEREY, DEVICE_ID_GENIUS_KB29E, quirk_cherry_genius_29e }, - { VENDOR_ID_PETALYNX, DEVICE_ID_PETALYNX_MAXTER_REMOTE, quirk_petalynx_remote }, - { 0, 0, NULL } }; diff --git a/drivers/hid/hid-petalynx.c b/drivers/hid/hid-petalynx.c new file mode 100644 index 00000000000..4109244f1d7 --- /dev/null +++ b/drivers/hid/hid-petalynx.c @@ -0,0 +1,122 @@ +/* + * HID driver for some petalynx "special" devices + * + * Copyright (c) 1999 Andreas Gal + * Copyright (c) 2000-2005 Vojtech Pavlik + * Copyright (c) 2005 Michael Haboustak for Concept2, Inc + * Copyright (c) 2006-2007 Jiri Kosina + * Copyright (c) 2007 Paul Walmsley + * Copyright (c) 2008 Jiri Slaby + */ + +/* + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + */ + +#include +#include +#include + +#include "hid-ids.h" + +/* Petalynx Maxter Remote has maximum for consumer page set too low */ +static void pl_report_fixup(struct hid_device *hdev, __u8 *rdesc, + unsigned int rsize) +{ + if (rsize >= 60 && rdesc[39] == 0x2a && rdesc[40] == 0xf5 && + rdesc[41] == 0x00 && rdesc[59] == 0x26 && + rdesc[60] == 0xf9 && rdesc[61] == 0x00) { + dev_info(&hdev->dev, "fixing up Petalynx Maxter Remote report " + "descriptor\n"); + rdesc[60] = 0xfa; + rdesc[40] = 0xfa; + } +} + +#define pl_map_key_clear(c) hid_map_usage_clear(hi, usage, bit, max, \ + EV_KEY, (c)) +static int pl_input_mapping(struct hid_device *hdev, struct hid_input *hi, + struct hid_field *field, struct hid_usage *usage, + unsigned long **bit, int *max) +{ + if ((usage->hid & HID_USAGE_PAGE) == HID_UP_LOGIVENDOR) { + switch (usage->hid & HID_USAGE) { + case 0x05a: pl_map_key_clear(KEY_TEXT); break; + case 0x05b: pl_map_key_clear(KEY_RED); break; + case 0x05c: pl_map_key_clear(KEY_GREEN); break; + case 0x05d: pl_map_key_clear(KEY_YELLOW); break; + case 0x05e: pl_map_key_clear(KEY_BLUE); break; + default: + return 0; + } + return 1; + } + + if ((usage->hid & HID_USAGE_PAGE) == HID_UP_CONSUMER) { + switch (usage->hid & HID_USAGE) { + case 0x0f6: pl_map_key_clear(KEY_NEXT); break; + case 0x0fa: pl_map_key_clear(KEY_BACK); break; + default: + return 0; + } + return 1; + } + + return 0; +} + +static int pl_probe(struct hid_device *hdev, const struct hid_device_id *id) +{ + int ret; + + hdev->quirks |= HID_QUIRK_NOGET; + + ret = hid_parse(hdev); + if (ret) { + dev_err(&hdev->dev, "parse failed\n"); + goto err_free; + } + + ret = hid_hw_start(hdev); + if (ret) { + dev_err(&hdev->dev, "hw start failed\n"); + goto err_free; + } + + return 0; +err_free: + return ret; +} + +static const struct hid_device_id pl_devices[] = { + { HID_USB_DEVICE(USB_VENDOR_ID_PETALYNX, USB_DEVICE_ID_PETALYNX_MAXTER_REMOTE) }, + { } +}; +MODULE_DEVICE_TABLE(hid, pl_devices); + +static struct hid_driver pl_driver = { + .name = "petalynx", + .id_table = pl_devices, + .report_fixup = pl_report_fixup, + .input_mapping = pl_input_mapping, + .probe = pl_probe, +}; + +static int pl_init(void) +{ + return hid_register_driver(&pl_driver); +} + +static void pl_exit(void) +{ + hid_unregister_driver(&pl_driver); +} + +module_init(pl_init); +module_exit(pl_exit); +MODULE_LICENSE("GPL"); + +HID_COMPAT_LOAD_DRIVER(petalynx); diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c index c344ec2fad5..3f977abb62b 100644 --- a/drivers/hid/usbhid/hid-quirks.c +++ b/drivers/hid/usbhid/hid-quirks.c @@ -57,7 +57,6 @@ static const struct hid_blacklist { { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_4PORTKVMC, HID_QUIRK_NOGET }, { USB_VENDOR_ID_DMI, USB_DEVICE_ID_DMI_ENC, HID_QUIRK_NOGET }, { USB_VENDOR_ID_ELO, USB_DEVICE_ID_ELO_TS2700, HID_QUIRK_NOGET }, - { USB_VENDOR_ID_PETALYNX, USB_DEVICE_ID_PETALYNX_MAXTER_REMOTE, HID_QUIRK_NOGET }, { USB_VENDOR_ID_SUN, USB_DEVICE_ID_RARITAN_KVM_DONGLE, HID_QUIRK_NOGET }, { USB_VENDOR_ID_TURBOX, USB_DEVICE_ID_TURBOX_KEYBOARD, HID_QUIRK_NOGET }, { USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_DUAL_USB_JOYPAD, HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT | HID_QUIRK_SKIP_OUTPUT_REPORTS }, @@ -78,8 +77,6 @@ static const struct hid_rdesc_blacklist { } hid_rdesc_blacklist[] = { { USB_VENDOR_ID_MONTEREY, USB_DEVICE_ID_GENIUS_KB29E, HID_QUIRK_RDESC_BUTTON_CONSUMER }, - { USB_VENDOR_ID_PETALYNX, USB_DEVICE_ID_PETALYNX_MAXTER_REMOTE, HID_QUIRK_RDESC_PETALYNX }, - { USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_IR_REMOTE, HID_QUIRK_RDESC_SAMSUNG_REMOTE }, { 0, 0 } @@ -340,21 +337,6 @@ static void usbhid_fixup_samsung_irda_descriptor(unsigned char *rdesc, } } -/* Petalynx Maxter Remote has maximum for consumer page set too low */ -static void usbhid_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) { - printk(KERN_INFO "Fixing up Petalynx Maxter Remote report descriptor\n"); - rdesc[60] = 0xfa; - rdesc[40] = 0xfa; - } -} - static void usbhid_fixup_button_consumer_descriptor(unsigned char *rdesc, int rsize) { if (rsize >= 30 && rdesc[29] == 0x05 @@ -366,9 +348,6 @@ static void usbhid_fixup_button_consumer_descriptor(unsigned char *rdesc, int rs static void __usbhid_fixup_report_descriptor(__u32 quirks, char *rdesc, unsigned rsize) { - if (quirks & HID_QUIRK_RDESC_PETALYNX) - usbhid_fixup_petalynx_descriptor(rdesc, rsize); - if (quirks & HID_QUIRK_RDESC_BUTTON_CONSUMER) usbhid_fixup_button_consumer_descriptor(rdesc, rsize); diff --git a/include/linux/hid.h b/include/linux/hid.h index 298cbcce3a2..7f4c94ffa61 100644 --- a/include/linux/hid.h +++ b/include/linux/hid.h @@ -272,7 +272,6 @@ struct hid_item { * Separate quirks for runtime report descriptor fixup */ -#define HID_QUIRK_RDESC_PETALYNX 0x00000008 #define HID_QUIRK_RDESC_BUTTON_CONSUMER 0x00000020 #define HID_QUIRK_RDESC_SAMSUNG_REMOTE 0x00000040 -- cgit v1.2.3-70-g09d2 From 3b8006e51038ef263a0404756d9e190c9a9f74d5 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Wed, 25 Jun 2008 00:07:50 +0200 Subject: HID: move monterey quirks Signed-off-by: Jiri Slaby Signed-off-by: Jiri Kosina --- drivers/hid/Kconfig | 7 ++++ drivers/hid/Makefile | 1 + drivers/hid/hid-core.c | 1 + drivers/hid/hid-dummy.c | 3 ++ drivers/hid/hid-input-quirks.c | 23 ------------ drivers/hid/hid-monterey.c | 82 +++++++++++++++++++++++++++++++++++++++++ drivers/hid/usbhid/hid-quirks.c | 14 ------- include/linux/hid.h | 1 - 8 files changed, 94 insertions(+), 38 deletions(-) create mode 100644 drivers/hid/hid-monterey.c (limited to 'drivers/hid/Kconfig') diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index 04f646a90d3..d71507a5ccc 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -154,6 +154,13 @@ config HID_MICROSOFT Support for some Microsoft devices which breaks less or more HID specification. +config HID_MONTEREY + tristate "Monterey" + default m + depends on USB_HID + ---help--- + Support for Monterey Genius KB29E. + config HID_PETALYNX tristate "Petalynx" default m diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile index 359a5bae408..48b5fb25d16 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile @@ -21,6 +21,7 @@ obj-$(CONFIG_HID_CYPRESS) += hid-cypress.o obj-$(CONFIG_HID_EZKEY) += hid-ezkey.o obj-$(CONFIG_HID_LOGITECH) += hid-logitech.o obj-$(CONFIG_HID_MICROSOFT) += hid-microsoft.o +obj-$(CONFIG_HID_MONTEREY) += hid-monterey.o obj-$(CONFIG_HID_PETALYNX) += hid-petalynx.o obj-$(CONFIG_HID_SUNPLUS) += hid-sunplus.o diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 2b7a08fe171..fa272310045 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1191,6 +1191,7 @@ static const struct hid_device_id hid_blacklist[] = { { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_LK6K) }, { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_PRESENTER_8K_USB) }, { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_WIRELESS_OPTICAL_DESKTOP_3_0) }, + { HID_USB_DEVICE(USB_VENDOR_ID_MONTEREY, USB_DEVICE_ID_GENIUS_KB29E) }, { HID_USB_DEVICE(USB_VENDOR_ID_PETALYNX, USB_DEVICE_ID_PETALYNX_MAXTER_REMOTE) }, { HID_USB_DEVICE(USB_VENDOR_ID_SUNPLUS, USB_DEVICE_ID_SUNPLUS_WDESKTOP) }, diff --git a/drivers/hid/hid-dummy.c b/drivers/hid/hid-dummy.c index c28422c9d2b..1dbb454c811 100644 --- a/drivers/hid/hid-dummy.c +++ b/drivers/hid/hid-dummy.c @@ -31,6 +31,9 @@ static int __init hid_dummy_init(void) #ifdef CONFIG_HID_MICROSOFT_MODULE HID_COMPAT_CALL_DRIVER(microsoft); #endif +#ifdef CONFIG_HID_MONTEREY_MODULE + HID_COMPAT_CALL_DRIVER(monterey); +#endif #ifdef CONFIG_HID_PETALYNX_MODULE HID_COMPAT_CALL_DRIVER(petalynx); #endif diff --git a/drivers/hid/hid-input-quirks.c b/drivers/hid/hid-input-quirks.c index 903162a63c4..1a4ba031303 100644 --- a/drivers/hid/hid-input-quirks.c +++ b/drivers/hid/hid-input-quirks.c @@ -42,30 +42,9 @@ static int quirk_gyration_remote(struct hid_usage *usage, return 1; } -static int quirk_cherry_genius_29e(struct hid_usage *usage, - struct hid_input *hidinput, unsigned long **bit, int *max) -{ - if ((usage->hid & HID_USAGE_PAGE) != HID_UP_CONSUMER) - return 0; - - switch (usage->hid & HID_USAGE) { - case 0x156: map_key_clear(KEY_WORDPROCESSOR); break; - case 0x157: map_key_clear(KEY_SPREADSHEET); break; - case 0x158: map_key_clear(KEY_PRESENTATION); break; - case 0x15c: map_key_clear(KEY_STOP); break; - - default: - return 0; - } - return 1; -} - #define VENDOR_ID_GYRATION 0x0c16 #define DEVICE_ID_GYRATION_REMOTE 0x0002 -#define VENDOR_ID_MONTEREY 0x0566 -#define DEVICE_ID_GENIUS_KB29E 0x3004 - static const struct hid_input_blacklist { __u16 idVendor; __u16 idProduct; @@ -74,8 +53,6 @@ static const struct hid_input_blacklist { } hid_input_blacklist[] = { { VENDOR_ID_GYRATION, DEVICE_ID_GYRATION_REMOTE, quirk_gyration_remote }, - { VENDOR_ID_MONTEREY, DEVICE_ID_GENIUS_KB29E, quirk_cherry_genius_29e }, - { 0, 0, NULL } }; diff --git a/drivers/hid/hid-monterey.c b/drivers/hid/hid-monterey.c new file mode 100644 index 00000000000..f3a85a065f1 --- /dev/null +++ b/drivers/hid/hid-monterey.c @@ -0,0 +1,82 @@ +/* + * HID driver for some monterey "special" devices + * + * Copyright (c) 1999 Andreas Gal + * Copyright (c) 2000-2005 Vojtech Pavlik + * Copyright (c) 2005 Michael Haboustak for Concept2, Inc + * Copyright (c) 2006-2007 Jiri Kosina + * Copyright (c) 2007 Paul Walmsley + * Copyright (c) 2008 Jiri Slaby + */ + +/* + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + */ + +#include +#include +#include + +#include "hid-ids.h" + +static void mr_report_fixup(struct hid_device *hdev, __u8 *rdesc, + unsigned int rsize) +{ + if (rsize >= 30 && rdesc[29] == 0x05 && rdesc[30] == 0x09) { + dev_info(&hdev->dev, "fixing up button/consumer in HID report " + "descriptor\n"); + rdesc[30] = 0x0c; + } +} + +#define mr_map_key_clear(c) hid_map_usage_clear(hi, usage, bit, max, \ + EV_KEY, (c)) +static int mr_input_mapping(struct hid_device *hdev, struct hid_input *hi, + struct hid_field *field, struct hid_usage *usage, + unsigned long **bit, int *max) +{ + if ((usage->hid & HID_USAGE_PAGE) != HID_UP_CONSUMER) + return 0; + + switch (usage->hid & HID_USAGE) { + case 0x156: mr_map_key_clear(KEY_WORDPROCESSOR); break; + case 0x157: mr_map_key_clear(KEY_SPREADSHEET); break; + case 0x158: mr_map_key_clear(KEY_PRESENTATION); break; + case 0x15c: mr_map_key_clear(KEY_STOP); break; + default: + return 0; + } + return 1; +} + +static const struct hid_device_id mr_devices[] = { + { HID_USB_DEVICE(USB_VENDOR_ID_MONTEREY, USB_DEVICE_ID_GENIUS_KB29E) }, + { } +}; +MODULE_DEVICE_TABLE(hid, mr_devices); + +static struct hid_driver mr_driver = { + .name = "monterey", + .id_table = mr_devices, + .report_fixup = mr_report_fixup, + .input_mapping = mr_input_mapping, +}; + +static int mr_init(void) +{ + return hid_register_driver(&mr_driver); +} + +static void mr_exit(void) +{ + hid_unregister_driver(&mr_driver); +} + +module_init(mr_init); +module_exit(mr_exit); +MODULE_LICENSE("GPL"); + +HID_COMPAT_LOAD_DRIVER(monterey); diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c index 3f977abb62b..cc1927b1b88 100644 --- a/drivers/hid/usbhid/hid-quirks.c +++ b/drivers/hid/usbhid/hid-quirks.c @@ -75,8 +75,6 @@ static const struct hid_rdesc_blacklist { __u16 idProduct; __u32 quirks; } hid_rdesc_blacklist[] = { - { USB_VENDOR_ID_MONTEREY, USB_DEVICE_ID_GENIUS_KB29E, HID_QUIRK_RDESC_BUTTON_CONSUMER }, - { USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_IR_REMOTE, HID_QUIRK_RDESC_SAMSUNG_REMOTE }, { 0, 0 } @@ -337,20 +335,8 @@ static void usbhid_fixup_samsung_irda_descriptor(unsigned char *rdesc, } } -static void usbhid_fixup_button_consumer_descriptor(unsigned char *rdesc, int rsize) -{ - if (rsize >= 30 && rdesc[29] == 0x05 - && rdesc[30] == 0x09) { - printk(KERN_INFO "Fixing up button/consumer in HID report descriptor\n"); - rdesc[30] = 0x0c; - } -} - static void __usbhid_fixup_report_descriptor(__u32 quirks, char *rdesc, unsigned rsize) { - if (quirks & HID_QUIRK_RDESC_BUTTON_CONSUMER) - usbhid_fixup_button_consumer_descriptor(rdesc, rsize); - if (quirks & HID_QUIRK_RDESC_SAMSUNG_REMOTE) usbhid_fixup_samsung_irda_descriptor(rdesc, rsize); } diff --git a/include/linux/hid.h b/include/linux/hid.h index 7f4c94ffa61..3a639bff4ab 100644 --- a/include/linux/hid.h +++ b/include/linux/hid.h @@ -272,7 +272,6 @@ struct hid_item { * Separate quirks for runtime report descriptor fixup */ -#define HID_QUIRK_RDESC_BUTTON_CONSUMER 0x00000020 #define HID_QUIRK_RDESC_SAMSUNG_REMOTE 0x00000040 /* -- cgit v1.2.3-70-g09d2 From 949f8fef77186c7361d22e1ea6f42c76ceda42b0 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Thu, 24 Jul 2008 23:35:13 +0200 Subject: HID: move gyration quirks Signed-off-by: Jiri Slaby Signed-off-by: Jiri Kosina --- drivers/hid/Kconfig | 7 +++ drivers/hid/Makefile | 1 + drivers/hid/hid-core.c | 1 + drivers/hid/hid-dummy.c | 3 ++ drivers/hid/hid-gyration.c | 96 ++++++++++++++++++++++++++++++++++++++++++ drivers/hid/hid-ids.h | 4 ++ drivers/hid/hid-input-quirks.c | 46 -------------------- 7 files changed, 112 insertions(+), 46 deletions(-) create mode 100644 drivers/hid/hid-gyration.c (limited to 'drivers/hid/Kconfig') diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index d71507a5ccc..4dcb92ac887 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -138,6 +138,13 @@ config HID_EZKEY ---help--- Support for Ezkey mouse and barcodes. +config HID_GYRATION + tristate "Gyration" + default m + depends on USB_HID + ---help--- + Support for Gyration remote. + config HID_LOGITECH tristate "Logitech" default m diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile index 48b5fb25d16..50a06f71b48 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile @@ -19,6 +19,7 @@ obj-$(CONFIG_HID_CHERRY) += hid-cherry.o obj-$(CONFIG_HID_CHICONY) += hid-chicony.o obj-$(CONFIG_HID_CYPRESS) += hid-cypress.o obj-$(CONFIG_HID_EZKEY) += hid-ezkey.o +obj-$(CONFIG_HID_GYRATION) += hid-gyration.o obj-$(CONFIG_HID_LOGITECH) += hid-logitech.o obj-$(CONFIG_HID_MICROSOFT) += hid-microsoft.o obj-$(CONFIG_HID_MONTEREY) += hid-monterey.o diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index fa272310045..53f30560b93 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1171,6 +1171,7 @@ static const struct hid_device_id hid_blacklist[] = { { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_2) }, { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_MOUSE) }, { HID_USB_DEVICE(USB_VENDOR_ID_EZKEY, USB_DEVICE_ID_BTC_8193) }, + { HID_USB_DEVICE(USB_VENDOR_ID_GYRATION, USB_DEVICE_ID_GYRATION_REMOTE) }, { HID_USB_DEVICE(USB_VENDOR_ID_LABTEC, USB_DEVICE_ID_LABTEC_WIRELESS_KEYBOARD) }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_MX3000_RECEIVER) }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER) }, diff --git a/drivers/hid/hid-dummy.c b/drivers/hid/hid-dummy.c index 1dbb454c811..1c9e7c2814a 100644 --- a/drivers/hid/hid-dummy.c +++ b/drivers/hid/hid-dummy.c @@ -25,6 +25,9 @@ static int __init hid_dummy_init(void) #ifdef CONFIG_HID_EZKEY_MODULE HID_COMPAT_CALL_DRIVER(ezkey); #endif +#ifdef CONFIG_HID_EZKEY_MODULE + HID_COMPAT_CALL_DRIVER(gyration); +#endif #ifdef CONFIG_HID_LOGITECH_MODULE HID_COMPAT_CALL_DRIVER(logitech); #endif diff --git a/drivers/hid/hid-gyration.c b/drivers/hid/hid-gyration.c new file mode 100644 index 00000000000..ac5120f542c --- /dev/null +++ b/drivers/hid/hid-gyration.c @@ -0,0 +1,96 @@ +/* + * HID driver for some gyration "special" devices + * + * Copyright (c) 1999 Andreas Gal + * Copyright (c) 2000-2005 Vojtech Pavlik + * Copyright (c) 2005 Michael Haboustak for Concept2, Inc + * Copyright (c) 2006-2007 Jiri Kosina + * Copyright (c) 2007 Paul Walmsley + * Copyright (c) 2008 Jiri Slaby + */ + +/* + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + */ + +#include +#include +#include +#include + +#include "hid-ids.h" + +#define gy_map_key_clear(c) hid_map_usage_clear(hi, usage, bit, max, \ + EV_KEY, (c)) +static int gyration_input_mapping(struct hid_device *hdev, struct hid_input *hi, + struct hid_field *field, struct hid_usage *usage, + unsigned long **bit, int *max) +{ + if ((usage->hid & HID_USAGE_PAGE) != HID_UP_LOGIVENDOR) + return 0; + + set_bit(EV_REP, hi->input->evbit); + switch (usage->hid & HID_USAGE) { + /* Reported on Gyration MCE Remote */ + case 0x00d: gy_map_key_clear(KEY_HOME); break; + case 0x024: gy_map_key_clear(KEY_DVD); break; + case 0x025: gy_map_key_clear(KEY_PVR); break; + case 0x046: gy_map_key_clear(KEY_MEDIA); break; + case 0x047: gy_map_key_clear(KEY_MP3); break; + case 0x049: gy_map_key_clear(KEY_CAMERA); break; + case 0x04a: gy_map_key_clear(KEY_VIDEO); break; + + default: + return 0; + } + return 1; +} + +static int gyration_event(struct hid_device *hdev, struct hid_field *field, + struct hid_usage *usage, __s32 value) +{ + struct input_dev *input = field->hidinput->input; + + if ((usage->hid & HID_USAGE_PAGE) == HID_UP_GENDESK && + (usage->hid & 0xff) == 0x82) { + input_event(input, usage->type, usage->code, 1); + input_sync(input); + input_event(input, usage->type, usage->code, 0); + input_sync(input); + return 1; + } + + return 0; +} + +static const struct hid_device_id gyration_devices[] = { + { HID_USB_DEVICE(USB_VENDOR_ID_GYRATION, USB_DEVICE_ID_GYRATION_REMOTE) }, + { } +}; +MODULE_DEVICE_TABLE(hid, gyration_devices); + +static struct hid_driver gyration_driver = { + .name = "gyration", + .id_table = gyration_devices, + .input_mapping = gyration_input_mapping, + .event = gyration_event, +}; + +static int gyration_init(void) +{ + return hid_register_driver(&gyration_driver); +} + +static void gyration_exit(void) +{ + hid_unregister_driver(&gyration_driver); +} + +module_init(gyration_init); +module_exit(gyration_exit); +MODULE_LICENSE("GPL"); + +HID_COMPAT_LOAD_DRIVER(gyration); diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index ebe665206a7..678f7c3f341 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -223,6 +223,10 @@ #define USB_DEVICE_ID_GTCO_1005 0x1005 #define USB_DEVICE_ID_GTCO_1006 0x1006 #define USB_DEVICE_ID_GTCO_1007 0x1007 + +#define USB_VENDOR_ID_GYRATION 0x0c16 +#define USB_DEVICE_ID_GYRATION_REMOTE 0x0002 + #define USB_VENDOR_ID_HAPP 0x078b #define USB_DEVICE_ID_UGCI_DRIVING 0x0010 #define USB_DEVICE_ID_UGCI_FLYING 0x0020 diff --git a/drivers/hid/hid-input-quirks.c b/drivers/hid/hid-input-quirks.c index 1a4ba031303..980e7456e26 100644 --- a/drivers/hid/hid-input-quirks.c +++ b/drivers/hid/hid-input-quirks.c @@ -16,43 +16,12 @@ #include #include -#define map_key_clear(c) hid_map_usage_clear(hidinput, usage, bit, \ - max, EV_KEY, (c)) - -static int quirk_gyration_remote(struct hid_usage *usage, - struct hid_input *hidinput, unsigned long **bit, int *max) -{ - if ((usage->hid & HID_USAGE_PAGE) != HID_UP_LOGIVENDOR) - return 0; - - set_bit(EV_REP, hidinput->input->evbit); - switch(usage->hid & HID_USAGE) { - /* Reported on Gyration MCE Remote */ - case 0x00d: map_key_clear(KEY_HOME); break; - case 0x024: map_key_clear(KEY_DVD); break; - case 0x025: map_key_clear(KEY_PVR); break; - case 0x046: map_key_clear(KEY_MEDIA); break; - case 0x047: map_key_clear(KEY_MP3); break; - case 0x049: map_key_clear(KEY_CAMERA); break; - case 0x04a: map_key_clear(KEY_VIDEO); break; - - default: - return 0; - } - return 1; -} - -#define VENDOR_ID_GYRATION 0x0c16 -#define DEVICE_ID_GYRATION_REMOTE 0x0002 - static const struct hid_input_blacklist { __u16 idVendor; __u16 idProduct; int (*quirk)(struct hid_usage *, struct hid_input *, unsigned long **, int *); } hid_input_blacklist[] = { - { VENDOR_ID_GYRATION, DEVICE_ID_GYRATION_REMOTE, quirk_gyration_remote }, - { 0, 0, NULL } }; @@ -74,21 +43,6 @@ int hidinput_mapping_quirks(struct hid_usage *usage, int hidinput_event_quirks(struct hid_device *hid, struct hid_field *field, struct hid_usage *usage, __s32 value) { - struct input_dev *input; - - input = field->hidinput->input; - - /* Gyration MCE remote "Sleep" key */ - if (hid->vendor == VENDOR_ID_GYRATION && - hid->product == DEVICE_ID_GYRATION_REMOTE && - (usage->hid & HID_USAGE_PAGE) == HID_UP_GENDESK && - (usage->hid & 0xff) == 0x82) { - input_event(input, usage->type, usage->code, 1); - input_sync(input); - input_event(input, usage->type, usage->code, 0); - input_sync(input); - return 1; - } return 0; } -- cgit v1.2.3-70-g09d2 From 980a3da6acdd577ee3ae192e868dc52fe4b7f2e5 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Wed, 25 Jun 2008 22:31:48 +0200 Subject: HID: move samsung quirks Signed-off-by: Jiri Slaby Signed-off-by: Jiri Kosina --- drivers/hid/Kconfig | 7 +++ drivers/hid/Makefile | 1 + drivers/hid/hid-core.c | 1 + drivers/hid/hid-dummy.c | 3 ++ drivers/hid/hid-samsung.c | 101 ++++++++++++++++++++++++++++++++++++++++ drivers/hid/usbhid/hid-quirks.c | 33 ------------- include/linux/hid.h | 6 --- 7 files changed, 113 insertions(+), 39 deletions(-) create mode 100644 drivers/hid/hid-samsung.c (limited to 'drivers/hid/Kconfig') diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index 4dcb92ac887..52b617bf2b9 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -175,6 +175,13 @@ config HID_PETALYNX ---help--- Support for Petalynx Maxter remote. +config HID_SAMSUNG + tristate "Samsung" + default m + depends on USB_HID + ---help--- + Support for Samsung IR remote. + config HID_SUNPLUS tristate "Sunplus" default m diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile index 50a06f71b48..735c371ca02 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile @@ -24,6 +24,7 @@ obj-$(CONFIG_HID_LOGITECH) += hid-logitech.o obj-$(CONFIG_HID_MICROSOFT) += hid-microsoft.o obj-$(CONFIG_HID_MONTEREY) += hid-monterey.o obj-$(CONFIG_HID_PETALYNX) += hid-petalynx.o +obj-$(CONFIG_HID_SAMSUNG) += hid-samsung.o obj-$(CONFIG_HID_SUNPLUS) += hid-sunplus.o obj-$(CONFIG_USB_HID) += usbhid/ diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 53f30560b93..1b43af072ce 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1194,6 +1194,7 @@ static const struct hid_device_id hid_blacklist[] = { { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_WIRELESS_OPTICAL_DESKTOP_3_0) }, { HID_USB_DEVICE(USB_VENDOR_ID_MONTEREY, USB_DEVICE_ID_GENIUS_KB29E) }, { HID_USB_DEVICE(USB_VENDOR_ID_PETALYNX, USB_DEVICE_ID_PETALYNX_MAXTER_REMOTE) }, + { HID_USB_DEVICE(USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_IR_REMOTE) }, { HID_USB_DEVICE(USB_VENDOR_ID_SUNPLUS, USB_DEVICE_ID_SUNPLUS_WDESKTOP) }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, 0x030c) }, diff --git a/drivers/hid/hid-dummy.c b/drivers/hid/hid-dummy.c index 1c9e7c2814a..cd21dcc4181 100644 --- a/drivers/hid/hid-dummy.c +++ b/drivers/hid/hid-dummy.c @@ -40,6 +40,9 @@ static int __init hid_dummy_init(void) #ifdef CONFIG_HID_PETALYNX_MODULE HID_COMPAT_CALL_DRIVER(petalynx); #endif +#ifdef CONFIG_HID_SAMSUNG_MODULE + HID_COMPAT_CALL_DRIVER(samsung); +#endif #ifdef CONFIG_HID_SUNPLUS_MODULE HID_COMPAT_CALL_DRIVER(sunplus); #endif diff --git a/drivers/hid/hid-samsung.c b/drivers/hid/hid-samsung.c new file mode 100644 index 00000000000..8771bfae02f --- /dev/null +++ b/drivers/hid/hid-samsung.c @@ -0,0 +1,101 @@ +/* + * HID driver for some samsung "special" devices + * + * Copyright (c) 1999 Andreas Gal + * Copyright (c) 2000-2005 Vojtech Pavlik + * Copyright (c) 2005 Michael Haboustak for Concept2, Inc + * Copyright (c) 2006-2007 Jiri Kosina + * Copyright (c) 2007 Paul Walmsley + * Copyright (c) 2008 Jiri Slaby + */ + +/* + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + */ + +#include +#include +#include + +#include "hid-ids.h" + +/* + * Samsung IrDA remote controller (reports as Cypress USB Mouse). + * + * Vendor specific report #4 has a size of 48 bit, + * and therefore is not accepted when inspecting the descriptors. + * As a workaround we reinterpret the report as: + * Variable type, count 6, size 8 bit, log. maximum 255 + * The burden to reconstruct the data is moved into user space. + */ +static void samsung_report_fixup(struct hid_device *hdev, __u8 *rdesc, + unsigned int rsize) +{ + if (rsize >= 182 && rdesc[175] == 0x25 && rdesc[176] == 0x40 && + rdesc[177] == 0x75 && rdesc[178] == 0x30 && + rdesc[179] == 0x95 && rdesc[180] == 0x01 && + rdesc[182] == 0x40) { + dev_info(&hdev->dev, "fixing up Samsung IrDA report " + "descriptor\n"); + rdesc[176] = 0xff; + rdesc[178] = 0x08; + rdesc[180] = 0x06; + rdesc[182] = 0x42; + } +} + +static int samsung_probe(struct hid_device *hdev, + const struct hid_device_id *id) +{ + int ret; + + hdev->quirks |= HID_QUIRK_HIDDEV | HID_QUIRK_IGNORE_HIDINPUT; + + ret = hid_parse(hdev); + if (ret) { + dev_err(&hdev->dev, "parse failed\n"); + goto err_free; + } + + ret = hid_hw_start(hdev); + if (ret) { + dev_err(&hdev->dev, "hw start failed\n"); + goto err_free; + } + + return 0; +err_free: + return ret; +} + +static const struct hid_device_id samsung_devices[] = { + { HID_USB_DEVICE(USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_IR_REMOTE) }, + { } +}; +MODULE_DEVICE_TABLE(hid, samsung_devices); + +static struct hid_driver samsung_driver = { + .name = "samsung", + .id_table = samsung_devices, + .report_fixup = samsung_report_fixup, + .probe = samsung_probe, +}; + +static int samsung_init(void) +{ + return hid_register_driver(&samsung_driver); +} + +static void samsung_exit(void) +{ + hid_unregister_driver(&samsung_driver); +} + +module_init(samsung_init); +module_exit(samsung_exit); +MODULE_LICENSE("GPL"); + +HID_COMPAT_LOAD_DRIVER(samsung); diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c index cc1927b1b88..d57a37997f9 100644 --- a/drivers/hid/usbhid/hid-quirks.c +++ b/drivers/hid/usbhid/hid-quirks.c @@ -43,8 +43,6 @@ static const struct hid_blacklist { { USB_VENDOR_ID_AFATECH, USB_DEVICE_ID_AFATECH_AF9016, HID_QUIRK_FULLSPEED_INTERVAL }, - { USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_IR_REMOTE, HID_QUIRK_HIDDEV | HID_QUIRK_IGNORE_HIDINPUT }, - { USB_VENDOR_ID_PANTHERLORD, USB_DEVICE_ID_PANTHERLORD_TWIN_USB_JOYSTICK, HID_QUIRK_MULTI_INPUT | HID_QUIRK_SKIP_OUTPUT_REPORTS }, { USB_VENDOR_ID_PLAYDOTCOM, USB_DEVICE_ID_PLAYDOTCOM_EMS_USBII, HID_QUIRK_MULTI_INPUT }, @@ -75,8 +73,6 @@ static const struct hid_rdesc_blacklist { __u16 idProduct; __u32 quirks; } hid_rdesc_blacklist[] = { - { USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_IR_REMOTE, HID_QUIRK_RDESC_SAMSUNG_REMOTE }, - { 0, 0 } }; @@ -308,37 +304,8 @@ u32 usbhid_lookup_quirk(const u16 idVendor, const u16 idProduct) EXPORT_SYMBOL_GPL(usbhid_lookup_quirk); -/* - * Samsung IrDA remote controller (reports as Cypress USB Mouse). - * - * Vendor specific report #4 has a size of 48 bit, - * and therefore is not accepted when inspecting the descriptors. - * As a workaround we reinterpret the report as: - * Variable type, count 6, size 8 bit, log. maximum 255 - * The burden to reconstruct the data is moved into user space. - */ -static void usbhid_fixup_samsung_irda_descriptor(unsigned char *rdesc, - int rsize) -{ - if (rsize >= 182 && rdesc[175] == 0x25 - && rdesc[176] == 0x40 - && rdesc[177] == 0x75 - && rdesc[178] == 0x30 - && rdesc[179] == 0x95 - && rdesc[180] == 0x01 - && rdesc[182] == 0x40) { - printk(KERN_INFO "Fixing up Samsung IrDA report descriptor\n"); - rdesc[176] = 0xff; - rdesc[178] = 0x08; - rdesc[180] = 0x06; - rdesc[182] = 0x42; - } -} - static void __usbhid_fixup_report_descriptor(__u32 quirks, char *rdesc, unsigned rsize) { - if (quirks & HID_QUIRK_RDESC_SAMSUNG_REMOTE) - usbhid_fixup_samsung_irda_descriptor(rdesc, rsize); } /** diff --git a/include/linux/hid.h b/include/linux/hid.h index 3a639bff4ab..5b47feecc10 100644 --- a/include/linux/hid.h +++ b/include/linux/hid.h @@ -268,12 +268,6 @@ struct hid_item { #define HID_QUIRK_IGNORE_HIDINPUT 0x01000000 #define HID_QUIRK_FULLSPEED_INTERVAL 0x10000000 -/* - * Separate quirks for runtime report descriptor fixup - */ - -#define HID_QUIRK_RDESC_SAMSUNG_REMOTE 0x00000040 - /* * This is the global environment of the parser. This information is * persistent for main-items. The global environment can be saved and -- cgit v1.2.3-70-g09d2 From bd28ce008bdc68ef5902f68d2d62cbb7fa78c415 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Wed, 25 Jun 2008 23:47:04 +0200 Subject: HID: move sony quirks Signed-off-by: Jiri Slaby Signed-off-by: Jiri Kosina --- drivers/hid/Kconfig | 7 +++ drivers/hid/Makefile | 1 + drivers/hid/hid-core.c | 1 + drivers/hid/hid-dummy.c | 3 ++ drivers/hid/hid-sony.c | 111 ++++++++++++++++++++++++++++++++++++++++ drivers/hid/usbhid/hid-core.c | 30 ----------- drivers/hid/usbhid/hid-quirks.c | 2 - include/linux/hid.h | 1 - 8 files changed, 123 insertions(+), 33 deletions(-) create mode 100644 drivers/hid/hid-sony.c (limited to 'drivers/hid/Kconfig') diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index 52b617bf2b9..7ced6476026 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -182,6 +182,13 @@ config HID_SAMSUNG ---help--- Support for Samsung IR remote. +config HID_SONY + tristate "Sony" + default m + depends on USB_HID + ---help--- + Support for Sony PS3 controller. + config HID_SUNPLUS tristate "Sunplus" default m diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile index 0141ff88008..4f39b9431eb 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile @@ -25,6 +25,7 @@ obj-$(CONFIG_HID_MICROSOFT) += hid-microsoft.o obj-$(CONFIG_HID_MONTEREY) += hid-monterey.o obj-$(CONFIG_HID_PETALYNX) += hid-petalynx.o obj-$(CONFIG_HID_SAMSUNG) += hid-samsung.o +obj-$(CONFIG_HID_SONY) += hid-sony.o obj-$(CONFIG_HID_SUNPLUS) += hid-sunplus.o obj-$(CONFIG_USB_HID) += usbhid/ diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 1b43af072ce..f527e332b59 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1195,6 +1195,7 @@ static const struct hid_device_id hid_blacklist[] = { { HID_USB_DEVICE(USB_VENDOR_ID_MONTEREY, USB_DEVICE_ID_GENIUS_KB29E) }, { HID_USB_DEVICE(USB_VENDOR_ID_PETALYNX, USB_DEVICE_ID_PETALYNX_MAXTER_REMOTE) }, { HID_USB_DEVICE(USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_IR_REMOTE) }, + { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER) }, { HID_USB_DEVICE(USB_VENDOR_ID_SUNPLUS, USB_DEVICE_ID_SUNPLUS_WDESKTOP) }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, 0x030c) }, diff --git a/drivers/hid/hid-dummy.c b/drivers/hid/hid-dummy.c index cd21dcc4181..1ef3111f7fe 100644 --- a/drivers/hid/hid-dummy.c +++ b/drivers/hid/hid-dummy.c @@ -43,6 +43,9 @@ static int __init hid_dummy_init(void) #ifdef CONFIG_HID_SAMSUNG_MODULE HID_COMPAT_CALL_DRIVER(samsung); #endif +#ifdef CONFIG_HID_SONY_MODULE + HID_COMPAT_CALL_DRIVER(sony); +#endif #ifdef CONFIG_HID_SUNPLUS_MODULE HID_COMPAT_CALL_DRIVER(sunplus); #endif diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c new file mode 100644 index 00000000000..97668c68f0a --- /dev/null +++ b/drivers/hid/hid-sony.c @@ -0,0 +1,111 @@ +/* + * HID driver for some sony "special" devices + * + * Copyright (c) 1999 Andreas Gal + * Copyright (c) 2000-2005 Vojtech Pavlik + * Copyright (c) 2005 Michael Haboustak for Concept2, Inc + * Copyright (c) 2006-2007 Jiri Kosina + * Copyright (c) 2007 Paul Walmsley + * Copyright (c) 2008 Jiri Slaby + */ + +/* + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + */ + +#include +#include +#include +#include + +#include "hid-ids.h" + +/* + * Sending HID_REQ_GET_REPORT changes the operation mode of the ps3 controller + * to "operational". Without this, the ps3 controller will not report any + * events. + */ +static int sony_set_operational(struct hid_device *hdev) +{ + struct usb_interface *intf = to_usb_interface(hdev->dev.parent); + struct usb_device *dev = interface_to_usbdev(intf); + __u16 ifnum = intf->cur_altsetting->desc.bInterfaceNumber; + int ret; + char *buf = kmalloc(18, GFP_KERNEL); + + if (!buf) + return -ENOMEM; + + ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), + HID_REQ_GET_REPORT, + USB_DIR_IN | USB_TYPE_CLASS | + USB_RECIP_INTERFACE, + (3 << 8) | 0xf2, ifnum, buf, 17, + USB_CTRL_GET_TIMEOUT); + if (ret < 0) + dev_err(&hdev->dev, "can't set operational mode\n"); + + kfree(buf); + + return ret; +} + +static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id) +{ + int ret; + + hdev->quirks |= HID_QUIRK_HIDDEV; + + ret = hid_parse(hdev); + if (ret) { + dev_err(&hdev->dev, "parse failed\n"); + goto err_free; + } + + ret = hid_hw_start(hdev); + if (ret) { + dev_err(&hdev->dev, "hw start failed\n"); + goto err_free; + } + + ret = sony_set_operational(hdev); + if (ret) + goto err_stop; + + return 0; +err_stop: + hid_hw_stop(hdev); +err_free: + return ret; +} + +static const struct hid_device_id sony_devices[] = { + { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER) }, + { } +}; +MODULE_DEVICE_TABLE(hid, sony_devices); + +static struct hid_driver sony_driver = { + .name = "sony", + .id_table = sony_devices, + .probe = sony_probe, +}; + +static int sony_init(void) +{ + return hid_register_driver(&sony_driver); +} + +static void sony_exit(void) +{ + hid_unregister_driver(&sony_driver); +} + +module_init(sony_init); +module_exit(sony_exit); +MODULE_LICENSE("GPL"); + +HID_COMPAT_LOAD_DRIVER(sony); diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c index e900d597bc2..b41d0110a75 100644 --- a/drivers/hid/usbhid/hid-core.c +++ b/drivers/hid/usbhid/hid-core.c @@ -670,32 +670,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); } -/* - * Sending HID_REQ_GET_REPORT changes the operation mode of the ps3 controller - * to "operational". Without this, the ps3 controller will not report any - * events. - */ -static void hid_fixup_sony_ps3_controller(struct usb_device *dev, int ifnum) -{ - int result; - char *buf = kmalloc(18, GFP_KERNEL); - - if (!buf) - return; - - result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), - HID_REQ_GET_REPORT, - USB_DIR_IN | USB_TYPE_CLASS | - USB_RECIP_INTERFACE, - (3 << 8) | 0xf2, ifnum, buf, 17, - USB_CTRL_GET_TIMEOUT); - - if (result < 0) - err_hid("%s failed: %d\n", __func__, result); - - kfree(buf); -} - static int usbhid_start_finish(struct hid_device *hid) { struct usb_interface *intf = to_usb_interface(hid->dev.parent); @@ -723,10 +697,6 @@ static int usbhid_start_finish(struct hid_device *hid) if ((hid->claimed & HID_CLAIMED_INPUT)) hid_ff_init(hid); - if (hid->quirks & HID_QUIRK_SONY_PS3_CONTROLLER) - hid_fixup_sony_ps3_controller(interface_to_usbdev(intf), - intf->cur_altsetting->desc.bInterfaceNumber); - printk(KERN_INFO); if (hid->claimed & HID_CLAIMED_INPUT) diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c index f66d2e43b5d..a154a7dc1e6 100644 --- a/drivers/hid/usbhid/hid-quirks.c +++ b/drivers/hid/usbhid/hid-quirks.c @@ -46,8 +46,6 @@ static const struct hid_blacklist { { USB_VENDOR_ID_PANTHERLORD, USB_DEVICE_ID_PANTHERLORD_TWIN_USB_JOYSTICK, HID_QUIRK_MULTI_INPUT | HID_QUIRK_SKIP_OUTPUT_REPORTS }, { USB_VENDOR_ID_PLAYDOTCOM, USB_DEVICE_ID_PLAYDOTCOM_EMS_USBII, HID_QUIRK_MULTI_INPUT }, - { USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER, HID_QUIRK_SONY_PS3_CONTROLLER | HID_QUIRK_HIDDEV }, - { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_UC100KM, HID_QUIRK_NOGET }, { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_CS124U, HID_QUIRK_NOGET }, { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_2PORTKVM, HID_QUIRK_NOGET }, diff --git a/include/linux/hid.h b/include/linux/hid.h index 9eac330a1df..43aa51a7fa9 100644 --- a/include/linux/hid.h +++ b/include/linux/hid.h @@ -262,7 +262,6 @@ struct hid_item { #define HID_QUIRK_BADPAD 0x00000020 #define HID_QUIRK_MULTI_INPUT 0x00000040 #define HID_QUIRK_SKIP_OUTPUT_REPORTS 0x00010000 -#define HID_QUIRK_SONY_PS3_CONTROLLER 0x00040000 #define HID_QUIRK_RESET_LEDS 0x00100000 #define HID_QUIRK_HIDINPUT 0x00200000 #define HID_QUIRK_IGNORE_HIDINPUT 0x01000000 -- cgit v1.2.3-70-g09d2 From fea6f1833b5bbff7066bcde1fa1141c9717bbad2 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Thu, 26 Jun 2008 22:25:33 +0200 Subject: HID: move dell quirks Signed-off-by: Jiri Slaby Signed-off-by: Jiri Kosina --- drivers/hid/Kconfig | 7 ++++ drivers/hid/Makefile | 1 + drivers/hid/hid-core.c | 1 + drivers/hid/hid-dell.c | 74 +++++++++++++++++++++++++++++++++++++++++ drivers/hid/hid-dummy.c | 3 ++ drivers/hid/usbhid/hid-quirks.c | 2 -- 6 files changed, 86 insertions(+), 2 deletions(-) create mode 100644 drivers/hid/hid-dell.c (limited to 'drivers/hid/Kconfig') diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index 7ced6476026..1ab067ee7e6 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -131,6 +131,13 @@ config HID_CYPRESS ---help--- Support for Cypress mouse and barcodes. +config HID_DELL + tristate "Dell" + default m + depends on USB_HID + ---help--- + Support for Dell W7658. + config HID_EZKEY tristate "Ezkey" default m diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile index 4f39b9431eb..4a756c6e3a9 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile @@ -18,6 +18,7 @@ obj-$(CONFIG_HID_BELKIN) += hid-belkin.o obj-$(CONFIG_HID_CHERRY) += hid-cherry.o obj-$(CONFIG_HID_CHICONY) += hid-chicony.o obj-$(CONFIG_HID_CYPRESS) += hid-cypress.o +obj-$(CONFIG_HID_DELL) += hid-dell.o obj-$(CONFIG_HID_EZKEY) += hid-ezkey.o obj-$(CONFIG_HID_GYRATION) += hid-gyration.o obj-$(CONFIG_HID_LOGITECH) += hid-logitech.o diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index f527e332b59..ea5f8bc900e 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1170,6 +1170,7 @@ static const struct hid_device_id hid_blacklist[] = { { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_1) }, { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_2) }, { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_MOUSE) }, + { HID_USB_DEVICE(USB_VENDOR_ID_DELL, USB_DEVICE_ID_DELL_W7658) }, { HID_USB_DEVICE(USB_VENDOR_ID_EZKEY, USB_DEVICE_ID_BTC_8193) }, { HID_USB_DEVICE(USB_VENDOR_ID_GYRATION, USB_DEVICE_ID_GYRATION_REMOTE) }, { HID_USB_DEVICE(USB_VENDOR_ID_LABTEC, USB_DEVICE_ID_LABTEC_WIRELESS_KEYBOARD) }, diff --git a/drivers/hid/hid-dell.c b/drivers/hid/hid-dell.c new file mode 100644 index 00000000000..5d1d54cfa87 --- /dev/null +++ b/drivers/hid/hid-dell.c @@ -0,0 +1,74 @@ +/* + * HID driver for some dell "special" devices + * + * Copyright (c) 1999 Andreas Gal + * Copyright (c) 2000-2005 Vojtech Pavlik + * Copyright (c) 2005 Michael Haboustak for Concept2, Inc + * Copyright (c) 2006-2007 Jiri Kosina + * Copyright (c) 2007 Paul Walmsley + * Copyright (c) 2008 Jiri Slaby + */ + +/* + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + */ + +#include +#include +#include + +#include "hid-ids.h" + +static int dell_probe(struct hid_device *hdev, const struct hid_device_id *id) +{ + int ret; + + hdev->quirks |= HID_QUIRK_RESET_LEDS; + + ret = hid_parse(hdev); + if (ret) { + dev_err(&hdev->dev, "parse failed\n"); + goto err_free; + } + + ret = hid_hw_start(hdev); + if (ret) { + dev_err(&hdev->dev, "hw start failed\n"); + goto err_free; + } + + return 0; +err_free: + return ret; +} + +static const struct hid_device_id dell_devices[] = { + { HID_USB_DEVICE(USB_VENDOR_ID_DELL, USB_DEVICE_ID_DELL_W7658) }, + { } +}; +MODULE_DEVICE_TABLE(hid, dell_devices); + +static struct hid_driver dell_driver = { + .name = "dell", + .id_table = dell_devices, + .probe = dell_probe, +}; + +static int dell_init(void) +{ + return hid_register_driver(&dell_driver); +} + +static void dell_exit(void) +{ + hid_unregister_driver(&dell_driver); +} + +module_init(dell_init); +module_exit(dell_exit); +MODULE_LICENSE("GPL"); + +HID_COMPAT_LOAD_DRIVER(dell); diff --git a/drivers/hid/hid-dummy.c b/drivers/hid/hid-dummy.c index 1ef3111f7fe..684191dcb32 100644 --- a/drivers/hid/hid-dummy.c +++ b/drivers/hid/hid-dummy.c @@ -22,6 +22,9 @@ static int __init hid_dummy_init(void) #ifdef CONFIG_HID_CYPRESS_MODULE HID_COMPAT_CALL_DRIVER(cypress); #endif +#ifdef CONFIG_HID_DELL_MODULE + HID_COMPAT_CALL_DRIVER(dell); +#endif #ifdef CONFIG_HID_EZKEY_MODULE HID_COMPAT_CALL_DRIVER(ezkey); #endif diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c index a154a7dc1e6..71bf64bc146 100644 --- a/drivers/hid/usbhid/hid-quirks.c +++ b/drivers/hid/usbhid/hid-quirks.c @@ -60,8 +60,6 @@ static const struct hid_blacklist { { USB_VENDOR_ID_WISEGROUP_LTD, USB_DEVICE_ID_SMARTJOY_DUAL_PLUS, HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT }, - { USB_VENDOR_ID_DELL, USB_DEVICE_ID_DELL_W7658, HID_QUIRK_RESET_LEDS }, - { 0, 0 } }; -- cgit v1.2.3-70-g09d2 From 606bd0a8616a0e59021cb2997e942513f24f641d Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Fri, 4 Jul 2008 23:06:45 +0200 Subject: HID: move logitech FF processing Merge the logitech force feedback processing directly into logitech driver from the usbhid core. Signed-off-by: Jiri Slaby Signed-off-by: Jiri Kosina --- drivers/hid/Kconfig | 24 +++ drivers/hid/Makefile | 8 + drivers/hid/hid-core.c | 7 + drivers/hid/hid-ids.h | 7 + drivers/hid/hid-lg.c | 342 +++++++++++++++++++++++++++++++++++++++++ drivers/hid/hid-lg.h | 18 +++ drivers/hid/hid-lg2ff.c | 116 ++++++++++++++ drivers/hid/hid-lgff.c | 153 ++++++++++++++++++ drivers/hid/hid-logitech.c | 315 ------------------------------------- drivers/hid/usbhid/Kconfig | 24 --- drivers/hid/usbhid/Makefile | 6 - drivers/hid/usbhid/hid-core.c | 1 + drivers/hid/usbhid/hid-ff.c | 12 -- drivers/hid/usbhid/hid-lg2ff.c | 114 -------------- drivers/hid/usbhid/hid-lgff.c | 151 ------------------ include/linux/hid.h | 2 - 16 files changed, 676 insertions(+), 624 deletions(-) create mode 100644 drivers/hid/hid-lg.c create mode 100644 drivers/hid/hid-lg.h create mode 100644 drivers/hid/hid-lg2ff.c create mode 100644 drivers/hid/hid-lgff.c delete mode 100644 drivers/hid/hid-logitech.c delete mode 100644 drivers/hid/usbhid/hid-lg2ff.c delete mode 100644 drivers/hid/usbhid/hid-lgff.c (limited to 'drivers/hid/Kconfig') diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index 1ab067ee7e6..4319af320ad 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -160,6 +160,30 @@ config HID_LOGITECH Support for some Logitech devices which breaks less or more HID specification. +config LOGITECH_FF + bool "Logitech force feedback" + depends on HID_LOGITECH + select INPUT_FF_MEMLESS + help + Say Y here if you have one of these devices: + - Logitech WingMan Cordless RumblePad + - Logitech WingMan Cordless RumblePad 2 + - Logitech WingMan Force 3D + - Logitech Formula Force EX + - Logitech MOMO Force wheel + + and if you want to enable force feedback for them. + Note: if you say N here, this device will still be supported, but without + force feedback. + +config LOGIRUMBLEPAD2_FF + bool "Logitech Rumblepad 2 force feedback" + depends on HID_LOGITECH + select INPUT_FF_MEMLESS + help + Say Y here if you want to enable force feedback support for Logitech + Rumblepad 2 devices. + config HID_MICROSOFT tristate "Microsoft" default m diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile index 4a756c6e3a9..300ee00913b 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile @@ -12,6 +12,14 @@ ifdef CONFIG_HID_COMPAT obj-m += hid-dummy.o endif +hid-logitech-objs := hid-lg.o +ifdef CONFIG_LOGITECH_FF + hid-logitech-objs += hid-lgff.o +endif +ifdef CONFIG_LOGIRUMBLEPAD2_FF + hid-logitech-objs += hid-lg2ff.o +endif + obj-$(CONFIG_HID_A4TECH) += hid-a4tech.o obj-$(CONFIG_HID_APPLE) += hid-apple.o obj-$(CONFIG_HID_BELKIN) += hid-belkin.o diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 699547ce257..6a730df336b 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1262,6 +1262,13 @@ static const struct hid_device_id hid_blacklist[] = { { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_V150) }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_EXTREME_3D) }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WHEEL) }, + { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD) }, + { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD2_2) }, + { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WINGMAN_F3D) }, + { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_FORCE3D_PRO) }, + { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOMO_WHEEL) }, + { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2) }, + { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD2) }, { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_SIDEWINDER_GV) }, { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_NE4K) }, { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_LK6K) }, diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 678f7c3f341..e2fd52ca68b 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -263,8 +263,14 @@ #define USB_DEVICE_ID_LOGITECH_RECEIVER 0xc101 #define USB_DEVICE_ID_LOGITECH_HARMONY_FIRST 0xc110 #define USB_DEVICE_ID_LOGITECH_HARMONY_LAST 0xc14f +#define USB_DEVICE_ID_LOGITECH_RUMBLEPAD 0xc211 #define USB_DEVICE_ID_LOGITECH_EXTREME_3D 0xc215 +#define USB_DEVICE_ID_LOGITECH_RUMBLEPAD2 0xc218 +#define USB_DEVICE_ID_LOGITECH_RUMBLEPAD2_2 0xc219 +#define USB_DEVICE_ID_LOGITECH_WINGMAN_F3D 0xc283 +#define USB_DEVICE_ID_LOGITECH_FORCE3D_PRO 0xc286 #define USB_DEVICE_ID_LOGITECH_WHEEL 0xc294 +#define USB_DEVICE_ID_LOGITECH_MOMO_WHEEL 0xc295 #define USB_DEVICE_ID_LOGITECH_ELITE_KBD 0xc30a #define USB_DEVICE_ID_LOGITECH_KBD 0xc311 #define USB_DEVICE_ID_S510_RECEIVER 0xc50c @@ -274,6 +280,7 @@ #define USB_DEVICE_ID_DINOVO_DESKTOP 0xc704 #define USB_DEVICE_ID_DINOVO_EDGE 0xc714 #define USB_DEVICE_ID_DINOVO_MINI 0xc71f +#define USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2 0xca03 #define USB_VENDOR_ID_MCC 0x09db #define USB_DEVICE_ID_MCC_PMD1024LS 0x0076 diff --git a/drivers/hid/hid-lg.c b/drivers/hid/hid-lg.c new file mode 100644 index 00000000000..406d8c82abf --- /dev/null +++ b/drivers/hid/hid-lg.c @@ -0,0 +1,342 @@ +/* + * HID driver for some logitech "special" devices + * + * Copyright (c) 1999 Andreas Gal + * Copyright (c) 2000-2005 Vojtech Pavlik + * Copyright (c) 2005 Michael Haboustak for Concept2, Inc + * Copyright (c) 2006-2007 Jiri Kosina + * Copyright (c) 2007 Paul Walmsley + * Copyright (c) 2008 Jiri Slaby + */ + +/* + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + */ + +#include +#include +#include + +#include "hid-ids.h" +#include "hid-lg.h" + +#define LG_RDESC 0x001 +#define LG_BAD_RELATIVE_KEYS 0x002 +#define LG_DUPLICATE_USAGES 0x004 +#define LG_RESET_LEDS 0x008 +#define LG_EXPANDED_KEYMAP 0x010 +#define LG_IGNORE_DOUBLED_WHEEL 0x020 +#define LG_WIRELESS 0x040 +#define LG_INVERT_HWHEEL 0x080 +#define LG_NOGET 0x100 +#define LG_FF 0x200 +#define LG_FF2 0x400 + +/* + * 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 lg_report_fixup(struct hid_device *hdev, __u8 *rdesc, + unsigned int rsize) +{ + unsigned long quirks = (unsigned long)hid_get_drvdata(hdev); + + if ((quirks & LG_RDESC) && rsize >= 90 && rdesc[83] == 0x26 && + rdesc[84] == 0x8c && rdesc[85] == 0x02) { + dev_info(&hdev->dev, "fixing up Logitech keyboard report " + "descriptor\n"); + rdesc[84] = rdesc[89] = 0x4d; + rdesc[85] = rdesc[90] = 0x10; + } +} + +#define lg_map_key_clear(c) hid_map_usage_clear(hi, usage, bit, max, \ + EV_KEY, (c)) + +static int lg_ultrax_remote_mapping(struct hid_input *hi, + struct hid_usage *usage, unsigned long **bit, int *max) +{ + if ((usage->hid & HID_USAGE_PAGE) != HID_UP_LOGIVENDOR) + return 0; + + set_bit(EV_REP, hi->input->evbit); + switch (usage->hid & HID_USAGE) { + /* Reported on Logitech Ultra X Media Remote */ + case 0x004: lg_map_key_clear(KEY_AGAIN); break; + case 0x00d: lg_map_key_clear(KEY_HOME); break; + case 0x024: lg_map_key_clear(KEY_SHUFFLE); break; + case 0x025: lg_map_key_clear(KEY_TV); break; + case 0x026: lg_map_key_clear(KEY_MENU); break; + case 0x031: lg_map_key_clear(KEY_AUDIO); break; + case 0x032: lg_map_key_clear(KEY_TEXT); break; + case 0x033: lg_map_key_clear(KEY_LAST); break; + case 0x047: lg_map_key_clear(KEY_MP3); break; + case 0x048: lg_map_key_clear(KEY_DVD); break; + case 0x049: lg_map_key_clear(KEY_MEDIA); break; + case 0x04a: lg_map_key_clear(KEY_VIDEO); break; + case 0x04b: lg_map_key_clear(KEY_ANGLE); break; + case 0x04c: lg_map_key_clear(KEY_LANGUAGE); break; + case 0x04d: lg_map_key_clear(KEY_SUBTITLE); break; + case 0x051: lg_map_key_clear(KEY_RED); break; + case 0x052: lg_map_key_clear(KEY_CLOSE); break; + + default: + return 0; + } + return 1; +} + +static int lg_wireless_mapping(struct hid_input *hi, struct hid_usage *usage, + unsigned long **bit, int *max) +{ + if ((usage->hid & HID_USAGE_PAGE) != HID_UP_CONSUMER) + return 0; + + switch (usage->hid & HID_USAGE) { + case 0x1001: lg_map_key_clear(KEY_MESSENGER); break; + case 0x1003: lg_map_key_clear(KEY_SOUND); break; + case 0x1004: lg_map_key_clear(KEY_VIDEO); break; + case 0x1005: lg_map_key_clear(KEY_AUDIO); break; + case 0x100a: lg_map_key_clear(KEY_DOCUMENTS); break; + case 0x1011: lg_map_key_clear(KEY_PREVIOUSSONG); break; + case 0x1012: lg_map_key_clear(KEY_NEXTSONG); break; + case 0x1013: lg_map_key_clear(KEY_CAMERA); break; + case 0x1014: lg_map_key_clear(KEY_MESSENGER); break; + case 0x1015: lg_map_key_clear(KEY_RECORD); break; + case 0x1016: lg_map_key_clear(KEY_PLAYER); break; + case 0x1017: lg_map_key_clear(KEY_EJECTCD); break; + case 0x1018: lg_map_key_clear(KEY_MEDIA); break; + case 0x1019: lg_map_key_clear(KEY_PROG1); break; + case 0x101a: lg_map_key_clear(KEY_PROG2); break; + case 0x101b: lg_map_key_clear(KEY_PROG3); break; + case 0x101f: lg_map_key_clear(KEY_ZOOMIN); break; + case 0x1020: lg_map_key_clear(KEY_ZOOMOUT); break; + case 0x1021: lg_map_key_clear(KEY_ZOOMRESET); break; + case 0x1023: lg_map_key_clear(KEY_CLOSE); break; + case 0x1027: lg_map_key_clear(KEY_MENU); break; + /* this one is marked as 'Rotate' */ + case 0x1028: lg_map_key_clear(KEY_ANGLE); break; + case 0x1029: lg_map_key_clear(KEY_SHUFFLE); break; + case 0x102a: lg_map_key_clear(KEY_BACK); break; + case 0x102b: lg_map_key_clear(KEY_CYCLEWINDOWS); break; + case 0x1041: lg_map_key_clear(KEY_BATTERY); break; + case 0x1042: lg_map_key_clear(KEY_WORDPROCESSOR); break; + case 0x1043: lg_map_key_clear(KEY_SPREADSHEET); break; + case 0x1044: lg_map_key_clear(KEY_PRESENTATION); break; + case 0x1045: lg_map_key_clear(KEY_UNDO); break; + case 0x1046: lg_map_key_clear(KEY_REDO); break; + case 0x1047: lg_map_key_clear(KEY_PRINT); break; + case 0x1048: lg_map_key_clear(KEY_SAVE); break; + case 0x1049: lg_map_key_clear(KEY_PROG1); break; + case 0x104a: lg_map_key_clear(KEY_PROG2); break; + case 0x104b: lg_map_key_clear(KEY_PROG3); break; + case 0x104c: lg_map_key_clear(KEY_PROG4); break; + + default: + return 0; + } + return 1; +} + +static int lg_input_mapping(struct hid_device *hdev, struct hid_input *hi, + struct hid_field *field, struct hid_usage *usage, + unsigned long **bit, int *max) +{ + /* extended mapping for certain Logitech hardware (Logitech cordless + desktop LX500) */ + static const u8 e_keymap[] = { + 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 + }; + unsigned long quirks = (unsigned long)hid_get_drvdata(hdev); + unsigned int hid = usage->hid; + + if (hdev->product == USB_DEVICE_ID_LOGITECH_RECEIVER && + lg_ultrax_remote_mapping(hi, usage, bit, max)) + return 1; + + if ((quirks & LG_WIRELESS) && lg_wireless_mapping(hi, usage, bit, max)) + return 1; + + if ((hid & HID_USAGE_PAGE) != HID_UP_BUTTON) + return 0; + + hid &= HID_USAGE; + + /* Special handling for Logitech Cordless Desktop */ + if (field->application == HID_GD_MOUSE) { + if ((quirks & LG_IGNORE_DOUBLED_WHEEL) && + (hid == 7 || hid == 8)) + return -1; + } else { + if ((quirks & LG_EXPANDED_KEYMAP) && + hid < ARRAY_SIZE(e_keymap) && + e_keymap[hid] != 0) { + hid_map_usage(hi, usage, bit, max, EV_KEY, + e_keymap[hid]); + return 1; + } + } + + return 0; +} + +static int lg_input_mapped(struct hid_device *hdev, struct hid_input *hi, + struct hid_field *field, struct hid_usage *usage, + unsigned long **bit, int *max) +{ + unsigned long quirks = (unsigned long)hid_get_drvdata(hdev); + + if ((quirks & LG_BAD_RELATIVE_KEYS) && usage->type == EV_KEY && + (field->flags & HID_MAIN_ITEM_RELATIVE)) + field->flags &= ~HID_MAIN_ITEM_RELATIVE; + + if ((quirks & LG_DUPLICATE_USAGES) && (usage->type == EV_KEY || + usage->type == EV_REL || usage->type == EV_ABS)) + clear_bit(usage->code, *bit); + + return 0; +} + +static int lg_event(struct hid_device *hdev, struct hid_field *field, + struct hid_usage *usage, __s32 value) +{ + unsigned long quirks = (unsigned long)hid_get_drvdata(hdev); + + if ((quirks & LG_INVERT_HWHEEL) && usage->code == REL_HWHEEL) { + input_event(field->hidinput->input, usage->type, usage->code, + -value); + return 1; + } + + return 0; +} + +static int lg_probe(struct hid_device *hdev, const struct hid_device_id *id) +{ + unsigned long quirks = id->driver_data; + unsigned int connect_mask = HID_CONNECT_DEFAULT; + int ret; + + hid_set_drvdata(hdev, (void *)quirks); + + if (quirks & LG_NOGET) + hdev->quirks |= HID_QUIRK_NOGET; + + ret = hid_parse(hdev); + if (ret) { + dev_err(&hdev->dev, "parse failed\n"); + goto err_free; + } + + if (quirks & (LG_FF | LG_FF2)) + connect_mask &= ~HID_CONNECT_FF; + + ret = hid_hw_start(hdev, connect_mask); + if (ret) { + dev_err(&hdev->dev, "hw start failed\n"); + goto err_free; + } + + if (quirks & LG_RESET_LEDS) + usbhid_set_leds(hdev); + + if (quirks & LG_FF) + lgff_init(hdev); + if (quirks & LG_FF2) + lg2ff_init(hdev); + + return 0; +err_free: + return ret; +} + +static const struct hid_device_id lg_devices[] = { + { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_MX3000_RECEIVER), + .driver_data = LG_RDESC | LG_WIRELESS }, + { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER), + .driver_data = LG_RDESC | LG_WIRELESS }, + { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER_2), + .driver_data = LG_RDESC | LG_WIRELESS }, + + { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RECEIVER), + .driver_data = LG_BAD_RELATIVE_KEYS }, + + { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_DESKTOP), + .driver_data = LG_DUPLICATE_USAGES }, + { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_EDGE), + .driver_data = LG_DUPLICATE_USAGES }, + { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_MINI), + .driver_data = LG_DUPLICATE_USAGES }, + + { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_KBD), + .driver_data = LG_RESET_LEDS }, + + { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_ELITE_KBD), + .driver_data = LG_IGNORE_DOUBLED_WHEEL | LG_EXPANDED_KEYMAP }, + { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_CORDLESS_DESKTOP_LX500), + .driver_data = LG_IGNORE_DOUBLED_WHEEL | LG_EXPANDED_KEYMAP }, + + { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_LX3), + .driver_data = LG_INVERT_HWHEEL }, + { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_V150), + .driver_data = LG_INVERT_HWHEEL }, + + { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_EXTREME_3D), + .driver_data = LG_NOGET }, + { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WHEEL), + .driver_data = LG_NOGET | LG_FF }, + + { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD), + .driver_data = LG_FF }, + { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD2_2), + .driver_data = LG_FF }, + { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WINGMAN_F3D), + .driver_data = LG_FF }, + { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_FORCE3D_PRO), + .driver_data = LG_FF }, + { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOMO_WHEEL), + .driver_data = LG_FF }, + { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2), + .driver_data = LG_FF }, + { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD2), + .driver_data = LG_FF2 }, + { } +}; +MODULE_DEVICE_TABLE(hid, lg_devices); + +static struct hid_driver lg_driver = { + .name = "logitech", + .id_table = lg_devices, + .report_fixup = lg_report_fixup, + .input_mapping = lg_input_mapping, + .input_mapped = lg_input_mapped, + .event = lg_event, + .probe = lg_probe, +}; + +static int lg_init(void) +{ + return hid_register_driver(&lg_driver); +} + +static void lg_exit(void) +{ + hid_unregister_driver(&lg_driver); +} + +module_init(lg_init); +module_exit(lg_exit); +MODULE_LICENSE("GPL"); + +HID_COMPAT_LOAD_DRIVER(logitech); diff --git a/drivers/hid/hid-lg.h b/drivers/hid/hid-lg.h new file mode 100644 index 00000000000..27ae750ca87 --- /dev/null +++ b/drivers/hid/hid-lg.h @@ -0,0 +1,18 @@ +#ifndef __HID_LG_H +#define __HID_LG_H + +#include + +#ifdef CONFIG_LOGITECH_FF +int lgff_init(struct hid_device *hdev); +#else +static inline int lgff_init(struct hid_device *hdev) { return -1; } +#endif + +#ifdef CONFIG_LOGIRUMBLEPAD2_FF +int lg2ff_init(struct hid_device *hdev); +#else +static inline int lg2ff_init(struct hid_device *hdev) { return -1; } +#endif + +#endif diff --git a/drivers/hid/hid-lg2ff.c b/drivers/hid/hid-lg2ff.c new file mode 100644 index 00000000000..b2e9a67aa65 --- /dev/null +++ b/drivers/hid/hid-lg2ff.c @@ -0,0 +1,116 @@ +/* + * Force feedback support for Logitech Rumblepad 2 + * + * Copyright (c) 2008 Anssi Hannula + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include +#include +#include + +#include "usbhid/usbhid.h" +#include "hid-lg.h" + +struct lg2ff_device { + struct hid_report *report; +}; + +static int play_effect(struct input_dev *dev, void *data, + struct ff_effect *effect) +{ + struct hid_device *hid = input_get_drvdata(dev); + struct lg2ff_device *lg2ff = data; + int weak, strong; + + strong = effect->u.rumble.strong_magnitude; + weak = effect->u.rumble.weak_magnitude; + + if (weak || strong) { + weak = weak * 0xff / 0xffff; + strong = strong * 0xff / 0xffff; + + lg2ff->report->field[0]->value[0] = 0x51; + lg2ff->report->field[0]->value[2] = weak; + lg2ff->report->field[0]->value[4] = strong; + } else { + lg2ff->report->field[0]->value[0] = 0xf3; + lg2ff->report->field[0]->value[2] = 0x00; + lg2ff->report->field[0]->value[4] = 0x00; + } + + usbhid_submit_report(hid, lg2ff->report, USB_DIR_OUT); + return 0; +} + +int lg2ff_init(struct hid_device *hid) +{ + struct lg2ff_device *lg2ff; + struct hid_report *report; + struct hid_input *hidinput = list_entry(hid->inputs.next, + struct hid_input, list); + struct list_head *report_list = + &hid->report_enum[HID_OUTPUT_REPORT].report_list; + struct input_dev *dev = hidinput->input; + int error; + + if (list_empty(report_list)) { + printk(KERN_ERR "hid-lg2ff: no output report found\n"); + return -ENODEV; + } + + report = list_entry(report_list->next, struct hid_report, list); + + if (report->maxfield < 1) { + printk(KERN_ERR "hid-lg2ff: output report is empty\n"); + return -ENODEV; + } + if (report->field[0]->report_count < 7) { + printk(KERN_ERR "hid-lg2ff: not enough values in the field\n"); + return -ENODEV; + } + + lg2ff = kmalloc(sizeof(struct lg2ff_device), GFP_KERNEL); + if (!lg2ff) + return -ENOMEM; + + set_bit(FF_RUMBLE, dev->ffbit); + + error = input_ff_create_memless(dev, lg2ff, play_effect); + if (error) { + kfree(lg2ff); + return error; + } + + lg2ff->report = report; + report->field[0]->value[0] = 0xf3; + report->field[0]->value[1] = 0x00; + report->field[0]->value[2] = 0x00; + report->field[0]->value[3] = 0x00; + report->field[0]->value[4] = 0x00; + report->field[0]->value[5] = 0x00; + report->field[0]->value[6] = 0x00; + + usbhid_submit_report(hid, report, USB_DIR_OUT); + + printk(KERN_INFO "Force feedback for Logitech Rumblepad 2 by " + "Anssi Hannula \n"); + + return 0; +} diff --git a/drivers/hid/hid-lgff.c b/drivers/hid/hid-lgff.c new file mode 100644 index 00000000000..e379c167ac9 --- /dev/null +++ b/drivers/hid/hid-lgff.c @@ -0,0 +1,153 @@ +/* + * Force feedback support for hid-compliant for some of the devices from + * Logitech, namely: + * - WingMan Cordless RumblePad + * - WingMan Force 3D + * + * Copyright (c) 2002-2004 Johann Deneux + * Copyright (c) 2006 Anssi Hannula + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Should you need to contact me, the author, you can do so by + * e-mail - mail your message to + */ + +#include +#include +#include + +#include "usbhid/usbhid.h" +#include "hid-lg.h" + +struct dev_type { + u16 idVendor; + u16 idProduct; + const signed short *ff; +}; + +static const signed short ff_rumble[] = { + FF_RUMBLE, + -1 +}; + +static const signed short ff_joystick[] = { + FF_CONSTANT, + -1 +}; + +static const struct dev_type devices[] = { + { 0x046d, 0xc211, ff_rumble }, + { 0x046d, 0xc219, ff_rumble }, + { 0x046d, 0xc283, ff_joystick }, + { 0x046d, 0xc286, ff_joystick }, + { 0x046d, 0xc294, ff_joystick }, + { 0x046d, 0xc295, ff_joystick }, + { 0x046d, 0xca03, ff_joystick }, +}; + +static int hid_lgff_play(struct input_dev *dev, void *data, struct ff_effect *effect) +{ + struct hid_device *hid = input_get_drvdata(dev); + struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list; + struct hid_report *report = list_entry(report_list->next, struct hid_report, list); + int x, y; + unsigned int left, right; + +#define CLAMP(x) if (x < 0) x = 0; if (x > 0xff) x = 0xff + + switch (effect->type) { + case FF_CONSTANT: + x = effect->u.ramp.start_level + 0x7f; /* 0x7f is center */ + y = effect->u.ramp.end_level + 0x7f; + CLAMP(x); + CLAMP(y); + report->field[0]->value[0] = 0x51; + report->field[0]->value[1] = 0x08; + report->field[0]->value[2] = x; + report->field[0]->value[3] = y; + dbg_hid("(x, y)=(%04x, %04x)\n", x, y); + usbhid_submit_report(hid, report, USB_DIR_OUT); + break; + + case FF_RUMBLE: + right = effect->u.rumble.strong_magnitude; + left = effect->u.rumble.weak_magnitude; + right = right * 0xff / 0xffff; + left = left * 0xff / 0xffff; + CLAMP(left); + CLAMP(right); + report->field[0]->value[0] = 0x42; + report->field[0]->value[1] = 0x00; + report->field[0]->value[2] = left; + report->field[0]->value[3] = right; + dbg_hid("(left, right)=(%04x, %04x)\n", left, right); + usbhid_submit_report(hid, report, USB_DIR_OUT); + break; + } + return 0; +} + +int lgff_init(struct hid_device* hid) +{ + struct hid_input *hidinput = list_entry(hid->inputs.next, struct hid_input, list); + struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list; + struct input_dev *dev = hidinput->input; + struct hid_report *report; + struct hid_field *field; + const signed short *ff_bits = ff_joystick; + int error; + int i; + + /* Find the report to use */ + if (list_empty(report_list)) { + err_hid("No output report found"); + return -1; + } + + /* Check that the report looks ok */ + report = list_entry(report_list->next, struct hid_report, list); + if (!report) { + err_hid("NULL output report"); + return -1; + } + + field = report->field[0]; + if (!field) { + err_hid("NULL field"); + return -1; + } + + for (i = 0; i < ARRAY_SIZE(devices); i++) { + if (dev->id.vendor == devices[i].idVendor && + dev->id.product == devices[i].idProduct) { + ff_bits = devices[i].ff; + break; + } + } + + for (i = 0; ff_bits[i] >= 0; i++) + set_bit(ff_bits[i], dev->ffbit); + + error = input_ff_create_memless(dev, NULL, hid_lgff_play); + if (error) + return error; + + printk(KERN_INFO "Force feedback for Logitech force feedback devices by Johann Deneux \n"); + + return 0; +} diff --git a/drivers/hid/hid-logitech.c b/drivers/hid/hid-logitech.c deleted file mode 100644 index df27f9aadf2..00000000000 --- a/drivers/hid/hid-logitech.c +++ /dev/null @@ -1,315 +0,0 @@ -/* - * HID driver for some logitech "special" devices - * - * Copyright (c) 1999 Andreas Gal - * Copyright (c) 2000-2005 Vojtech Pavlik - * Copyright (c) 2005 Michael Haboustak for Concept2, Inc - * Copyright (c) 2006-2007 Jiri Kosina - * Copyright (c) 2007 Paul Walmsley - * Copyright (c) 2008 Jiri Slaby - */ - -/* - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - */ - -#include -#include -#include - -#include "hid-ids.h" - -#define LG_RDESC 0x001 -#define LG_BAD_RELATIVE_KEYS 0x002 -#define LG_DUPLICATE_USAGES 0x004 -#define LG_RESET_LEDS 0x008 -#define LG_EXPANDED_KEYMAP 0x010 -#define LG_IGNORE_DOUBLED_WHEEL 0x020 -#define LG_WIRELESS 0x040 -#define LG_INVERT_HWHEEL 0x080 -#define LG_NOGET 0x100 - -/* - * 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 lg_report_fixup(struct hid_device *hdev, __u8 *rdesc, - unsigned int rsize) -{ - unsigned long quirks = (unsigned long)hid_get_drvdata(hdev); - - if ((quirks & LG_RDESC) && rsize >= 90 && rdesc[83] == 0x26 && - rdesc[84] == 0x8c && rdesc[85] == 0x02) { - dev_info(&hdev->dev, "fixing up Logitech keyboard report " - "descriptor\n"); - rdesc[84] = rdesc[89] = 0x4d; - rdesc[85] = rdesc[90] = 0x10; - } -} - -#define lg_map_key_clear(c) hid_map_usage_clear(hi, usage, bit, max, \ - EV_KEY, (c)) - -static int lg_ultrax_remote_mapping(struct hid_input *hi, - struct hid_usage *usage, unsigned long **bit, int *max) -{ - if ((usage->hid & HID_USAGE_PAGE) != HID_UP_LOGIVENDOR) - return 0; - - set_bit(EV_REP, hi->input->evbit); - switch (usage->hid & HID_USAGE) { - /* Reported on Logitech Ultra X Media Remote */ - case 0x004: lg_map_key_clear(KEY_AGAIN); break; - case 0x00d: lg_map_key_clear(KEY_HOME); break; - case 0x024: lg_map_key_clear(KEY_SHUFFLE); break; - case 0x025: lg_map_key_clear(KEY_TV); break; - case 0x026: lg_map_key_clear(KEY_MENU); break; - case 0x031: lg_map_key_clear(KEY_AUDIO); break; - case 0x032: lg_map_key_clear(KEY_TEXT); break; - case 0x033: lg_map_key_clear(KEY_LAST); break; - case 0x047: lg_map_key_clear(KEY_MP3); break; - case 0x048: lg_map_key_clear(KEY_DVD); break; - case 0x049: lg_map_key_clear(KEY_MEDIA); break; - case 0x04a: lg_map_key_clear(KEY_VIDEO); break; - case 0x04b: lg_map_key_clear(KEY_ANGLE); break; - case 0x04c: lg_map_key_clear(KEY_LANGUAGE); break; - case 0x04d: lg_map_key_clear(KEY_SUBTITLE); break; - case 0x051: lg_map_key_clear(KEY_RED); break; - case 0x052: lg_map_key_clear(KEY_CLOSE); break; - - default: - return 0; - } - return 1; -} - -static int lg_wireless_mapping(struct hid_input *hi, struct hid_usage *usage, - unsigned long **bit, int *max) -{ - if ((usage->hid & HID_USAGE_PAGE) != HID_UP_CONSUMER) - return 0; - - switch (usage->hid & HID_USAGE) { - case 0x1001: lg_map_key_clear(KEY_MESSENGER); break; - case 0x1003: lg_map_key_clear(KEY_SOUND); break; - case 0x1004: lg_map_key_clear(KEY_VIDEO); break; - case 0x1005: lg_map_key_clear(KEY_AUDIO); break; - case 0x100a: lg_map_key_clear(KEY_DOCUMENTS); break; - case 0x1011: lg_map_key_clear(KEY_PREVIOUSSONG); break; - case 0x1012: lg_map_key_clear(KEY_NEXTSONG); break; - case 0x1013: lg_map_key_clear(KEY_CAMERA); break; - case 0x1014: lg_map_key_clear(KEY_MESSENGER); break; - case 0x1015: lg_map_key_clear(KEY_RECORD); break; - case 0x1016: lg_map_key_clear(KEY_PLAYER); break; - case 0x1017: lg_map_key_clear(KEY_EJECTCD); break; - case 0x1018: lg_map_key_clear(KEY_MEDIA); break; - case 0x1019: lg_map_key_clear(KEY_PROG1); break; - case 0x101a: lg_map_key_clear(KEY_PROG2); break; - case 0x101b: lg_map_key_clear(KEY_PROG3); break; - case 0x101f: lg_map_key_clear(KEY_ZOOMIN); break; - case 0x1020: lg_map_key_clear(KEY_ZOOMOUT); break; - case 0x1021: lg_map_key_clear(KEY_ZOOMRESET); break; - case 0x1023: lg_map_key_clear(KEY_CLOSE); break; - case 0x1027: lg_map_key_clear(KEY_MENU); break; - /* this one is marked as 'Rotate' */ - case 0x1028: lg_map_key_clear(KEY_ANGLE); break; - case 0x1029: lg_map_key_clear(KEY_SHUFFLE); break; - case 0x102a: lg_map_key_clear(KEY_BACK); break; - case 0x102b: lg_map_key_clear(KEY_CYCLEWINDOWS); break; - case 0x1041: lg_map_key_clear(KEY_BATTERY); break; - case 0x1042: lg_map_key_clear(KEY_WORDPROCESSOR); break; - case 0x1043: lg_map_key_clear(KEY_SPREADSHEET); break; - case 0x1044: lg_map_key_clear(KEY_PRESENTATION); break; - case 0x1045: lg_map_key_clear(KEY_UNDO); break; - case 0x1046: lg_map_key_clear(KEY_REDO); break; - case 0x1047: lg_map_key_clear(KEY_PRINT); break; - case 0x1048: lg_map_key_clear(KEY_SAVE); break; - case 0x1049: lg_map_key_clear(KEY_PROG1); break; - case 0x104a: lg_map_key_clear(KEY_PROG2); break; - case 0x104b: lg_map_key_clear(KEY_PROG3); break; - case 0x104c: lg_map_key_clear(KEY_PROG4); break; - - default: - return 0; - } - return 1; -} - -static int lg_input_mapping(struct hid_device *hdev, struct hid_input *hi, - struct hid_field *field, struct hid_usage *usage, - unsigned long **bit, int *max) -{ - /* extended mapping for certain Logitech hardware (Logitech cordless - desktop LX500) */ - static const u8 e_keymap[] = { - 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 - }; - unsigned long quirks = (unsigned long)hid_get_drvdata(hdev); - unsigned int hid = usage->hid; - - if (hdev->product == USB_DEVICE_ID_LOGITECH_RECEIVER && - lg_ultrax_remote_mapping(hi, usage, bit, max)) - return 1; - - if ((quirks & LG_WIRELESS) && lg_wireless_mapping(hi, usage, bit, max)) - return 1; - - if ((hid & HID_USAGE_PAGE) != HID_UP_BUTTON) - return 0; - - hid &= HID_USAGE; - - /* Special handling for Logitech Cordless Desktop */ - if (field->application == HID_GD_MOUSE) { - if ((quirks & LG_IGNORE_DOUBLED_WHEEL) && - (hid == 7 || hid == 8)) - return -1; - } else { - if ((quirks & LG_EXPANDED_KEYMAP) && - hid < ARRAY_SIZE(e_keymap) && - e_keymap[hid] != 0) { - hid_map_usage(hi, usage, bit, max, EV_KEY, - e_keymap[hid]); - return 1; - } - } - - return 0; -} - -static int lg_input_mapped(struct hid_device *hdev, struct hid_input *hi, - struct hid_field *field, struct hid_usage *usage, - unsigned long **bit, int *max) -{ - unsigned long quirks = (unsigned long)hid_get_drvdata(hdev); - - if ((quirks & LG_BAD_RELATIVE_KEYS) && usage->type == EV_KEY && - (field->flags & HID_MAIN_ITEM_RELATIVE)) - field->flags &= ~HID_MAIN_ITEM_RELATIVE; - - if ((quirks & LG_DUPLICATE_USAGES) && (usage->type == EV_KEY || - usage->type == EV_REL || usage->type == EV_ABS)) - clear_bit(usage->code, *bit); - - return 0; -} - -static int lg_event(struct hid_device *hdev, struct hid_field *field, - struct hid_usage *usage, __s32 value) -{ - unsigned long quirks = (unsigned long)hid_get_drvdata(hdev); - - if ((quirks & LG_INVERT_HWHEEL) && usage->code == REL_HWHEEL) { - input_event(field->hidinput->input, usage->type, usage->code, - -value); - return 1; - } - - return 0; -} - -static int lg_probe(struct hid_device *hdev, const struct hid_device_id *id) -{ - unsigned long quirks = id->driver_data; - int ret; - - hid_set_drvdata(hdev, (void *)quirks); - - if (quirks & LG_NOGET) - hdev->quirks |= HID_QUIRK_NOGET; - - ret = hid_parse(hdev); - if (ret) { - dev_err(&hdev->dev, "parse failed\n"); - goto err_free; - } - - ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); - if (ret) { - dev_err(&hdev->dev, "hw start failed\n"); - goto err_free; - } - - if (quirks & LG_RESET_LEDS) - usbhid_set_leds(hdev); - - return 0; -err_free: - return ret; -} - -static const struct hid_device_id lg_devices[] = { - { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_MX3000_RECEIVER), - .driver_data = LG_RDESC | LG_WIRELESS }, - { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER), - .driver_data = LG_RDESC | LG_WIRELESS }, - { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER_2), - .driver_data = LG_RDESC | LG_WIRELESS }, - - { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RECEIVER), - .driver_data = LG_BAD_RELATIVE_KEYS }, - - { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_DESKTOP), - .driver_data = LG_DUPLICATE_USAGES }, - { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_EDGE), - .driver_data = LG_DUPLICATE_USAGES }, - { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_MINI), - .driver_data = LG_DUPLICATE_USAGES }, - - { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_KBD), - .driver_data = LG_RESET_LEDS }, - - { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_ELITE_KBD), - .driver_data = LG_IGNORE_DOUBLED_WHEEL | LG_EXPANDED_KEYMAP }, - { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_CORDLESS_DESKTOP_LX500), - .driver_data = LG_IGNORE_DOUBLED_WHEEL | LG_EXPANDED_KEYMAP }, - - { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_LX3), - .driver_data = LG_INVERT_HWHEEL }, - { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_V150), - .driver_data = LG_INVERT_HWHEEL }, - - { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_EXTREME_3D), - .driver_data = LG_NOGET }, - { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WHEEL), - .driver_data = LG_NOGET }, - { } -}; -MODULE_DEVICE_TABLE(hid, lg_devices); - -static struct hid_driver lg_driver = { - .name = "logitech", - .id_table = lg_devices, - .report_fixup = lg_report_fixup, - .input_mapping = lg_input_mapping, - .input_mapped = lg_input_mapped, - .event = lg_event, - .probe = lg_probe, -}; - -static int lg_init(void) -{ - return hid_register_driver(&lg_driver); -} - -static void lg_exit(void) -{ - hid_unregister_driver(&lg_driver); -} - -module_init(lg_init); -module_exit(lg_exit); -MODULE_LICENSE("GPL"); - -HID_COMPAT_LOAD_DRIVER(logitech); diff --git a/drivers/hid/usbhid/Kconfig b/drivers/hid/usbhid/Kconfig index 177bfa1a3e5..0e7e2e6d975 100644 --- a/drivers/hid/usbhid/Kconfig +++ b/drivers/hid/usbhid/Kconfig @@ -44,30 +44,6 @@ config HID_PID feedback for it. Microsoft Sidewinder Force Feedback 2 is one of such devices. -config LOGITECH_FF - bool "Logitech devices support" - depends on HID_FF - select INPUT_FF_MEMLESS if USB_HID - help - Say Y here if you have one of these devices: - - Logitech WingMan Cordless RumblePad - - Logitech WingMan Cordless RumblePad 2 - - Logitech WingMan Force 3D - - Logitech Formula Force EX - - Logitech MOMO Force wheel - - and if you want to enable force feedback for them. - Note: if you say N here, this device will still be supported, but without - force feedback. - -config LOGIRUMBLEPAD2_FF - bool "Logitech Rumblepad 2 support" - depends on HID_FF - select INPUT_FF_MEMLESS if USB_HID - help - Say Y here if you want to enable force feedback support for Logitech - Rumblepad 2 devices. - config PANTHERLORD_FF bool "PantherLord/GreenAsia based device support" depends on HID_FF diff --git a/drivers/hid/usbhid/Makefile b/drivers/hid/usbhid/Makefile index 00a7b709019..224c62dc6a3 100644 --- a/drivers/hid/usbhid/Makefile +++ b/drivers/hid/usbhid/Makefile @@ -13,12 +13,6 @@ endif ifeq ($(CONFIG_HID_PID),y) usbhid-objs += hid-pidff.o endif -ifeq ($(CONFIG_LOGITECH_FF),y) - usbhid-objs += hid-lgff.o -endif -ifeq ($(CONFIG_LOGIRUMBLEPAD2_FF),y) - usbhid-objs += hid-lg2ff.o -endif ifeq ($(CONFIG_PANTHERLORD_FF),y) usbhid-objs += hid-plff.o endif diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c index 402ace75127..4ec10aa618d 100644 --- a/drivers/hid/usbhid/hid-core.c +++ b/drivers/hid/usbhid/hid-core.c @@ -444,6 +444,7 @@ void usbhid_submit_report(struct hid_device *hid, struct hid_report *report, uns spin_unlock_irqrestore(&usbhid->ctrllock, flags); } +EXPORT_SYMBOL_GPL(usbhid_submit_report); static int usb_hidinput_input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) { diff --git a/drivers/hid/usbhid/hid-ff.c b/drivers/hid/usbhid/hid-ff.c index 1d0dac52f16..8891f60d3be 100644 --- a/drivers/hid/usbhid/hid-ff.c +++ b/drivers/hid/usbhid/hid-ff.c @@ -50,18 +50,6 @@ struct hid_ff_initializer { * be a PID device */ static struct hid_ff_initializer inits[] = { -#ifdef CONFIG_LOGITECH_FF - { 0x46d, 0xc211, hid_lgff_init }, /* Logitech Cordless rumble pad */ - { 0x46d, 0xc219, hid_lgff_init }, /* Logitech Cordless rumble pad 2 */ - { 0x46d, 0xc283, hid_lgff_init }, /* Logitech Wingman Force 3d */ - { 0x46d, 0xc286, hid_lgff_init }, /* Logitech Force 3D Pro Joystick */ - { 0x46d, 0xc294, hid_lgff_init }, /* Logitech Formula Force EX */ - { 0x46d, 0xc295, hid_lgff_init }, /* Logitech MOMO force wheel */ - { 0x46d, 0xca03, hid_lgff_init }, /* Logitech MOMO force wheel */ -#endif -#ifdef CONFIG_LOGIRUMBLEPAD2_FF - { 0x46d, 0xc218, hid_lg2ff_init }, /* Logitech Rumblepad 2 */ -#endif #ifdef CONFIG_PANTHERLORD_FF { 0x810, 0x0001, hid_plff_init }, /* "Twin USB Joystick" */ { 0xe8f, 0x0003, hid_plff_init }, /* "GreenAsia Inc. USB Joystick " */ diff --git a/drivers/hid/usbhid/hid-lg2ff.c b/drivers/hid/usbhid/hid-lg2ff.c deleted file mode 100644 index d469bd0061c..00000000000 --- a/drivers/hid/usbhid/hid-lg2ff.c +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Force feedback support for Logitech Rumblepad 2 - * - * Copyright (c) 2008 Anssi Hannula - */ - -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - - -#include -#include -#include -#include "usbhid.h" - -struct lg2ff_device { - struct hid_report *report; -}; - -static int play_effect(struct input_dev *dev, void *data, - struct ff_effect *effect) -{ - struct hid_device *hid = input_get_drvdata(dev); - struct lg2ff_device *lg2ff = data; - int weak, strong; - - strong = effect->u.rumble.strong_magnitude; - weak = effect->u.rumble.weak_magnitude; - - if (weak || strong) { - weak = weak * 0xff / 0xffff; - strong = strong * 0xff / 0xffff; - - lg2ff->report->field[0]->value[0] = 0x51; - lg2ff->report->field[0]->value[2] = weak; - lg2ff->report->field[0]->value[4] = strong; - } else { - lg2ff->report->field[0]->value[0] = 0xf3; - lg2ff->report->field[0]->value[2] = 0x00; - lg2ff->report->field[0]->value[4] = 0x00; - } - - usbhid_submit_report(hid, lg2ff->report, USB_DIR_OUT); - return 0; -} - -int hid_lg2ff_init(struct hid_device *hid) -{ - struct lg2ff_device *lg2ff; - struct hid_report *report; - struct hid_input *hidinput = list_entry(hid->inputs.next, - struct hid_input, list); - struct list_head *report_list = - &hid->report_enum[HID_OUTPUT_REPORT].report_list; - struct input_dev *dev = hidinput->input; - int error; - - if (list_empty(report_list)) { - printk(KERN_ERR "hid-lg2ff: no output report found\n"); - return -ENODEV; - } - - report = list_entry(report_list->next, struct hid_report, list); - - if (report->maxfield < 1) { - printk(KERN_ERR "hid-lg2ff: output report is empty\n"); - return -ENODEV; - } - if (report->field[0]->report_count < 7) { - printk(KERN_ERR "hid-lg2ff: not enough values in the field\n"); - return -ENODEV; - } - - lg2ff = kmalloc(sizeof(struct lg2ff_device), GFP_KERNEL); - if (!lg2ff) - return -ENOMEM; - - set_bit(FF_RUMBLE, dev->ffbit); - - error = input_ff_create_memless(dev, lg2ff, play_effect); - if (error) { - kfree(lg2ff); - return error; - } - - lg2ff->report = report; - report->field[0]->value[0] = 0xf3; - report->field[0]->value[1] = 0x00; - report->field[0]->value[2] = 0x00; - report->field[0]->value[3] = 0x00; - report->field[0]->value[4] = 0x00; - report->field[0]->value[5] = 0x00; - report->field[0]->value[6] = 0x00; - - usbhid_submit_report(hid, report, USB_DIR_OUT); - - printk(KERN_INFO "Force feedback for Logitech Rumblepad 2 by " - "Anssi Hannula \n"); - - return 0; -} diff --git a/drivers/hid/usbhid/hid-lgff.c b/drivers/hid/usbhid/hid-lgff.c deleted file mode 100644 index 4b7ab6a46d9..00000000000 --- a/drivers/hid/usbhid/hid-lgff.c +++ /dev/null @@ -1,151 +0,0 @@ -/* - * Force feedback support for hid-compliant for some of the devices from - * Logitech, namely: - * - WingMan Cordless RumblePad - * - WingMan Force 3D - * - * Copyright (c) 2002-2004 Johann Deneux - * Copyright (c) 2006 Anssi Hannula - */ - -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * Should you need to contact me, the author, you can do so by - * e-mail - mail your message to - */ - -#include -#include -#include -#include "usbhid.h" - -struct dev_type { - u16 idVendor; - u16 idProduct; - const signed short *ff; -}; - -static const signed short ff_rumble[] = { - FF_RUMBLE, - -1 -}; - -static const signed short ff_joystick[] = { - FF_CONSTANT, - -1 -}; - -static const struct dev_type devices[] = { - { 0x046d, 0xc211, ff_rumble }, - { 0x046d, 0xc219, ff_rumble }, - { 0x046d, 0xc283, ff_joystick }, - { 0x046d, 0xc286, ff_joystick }, - { 0x046d, 0xc294, ff_joystick }, - { 0x046d, 0xc295, ff_joystick }, - { 0x046d, 0xca03, ff_joystick }, -}; - -static int hid_lgff_play(struct input_dev *dev, void *data, struct ff_effect *effect) -{ - struct hid_device *hid = input_get_drvdata(dev); - struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list; - struct hid_report *report = list_entry(report_list->next, struct hid_report, list); - int x, y; - unsigned int left, right; - -#define CLAMP(x) if (x < 0) x = 0; if (x > 0xff) x = 0xff - - switch (effect->type) { - case FF_CONSTANT: - x = effect->u.ramp.start_level + 0x7f; /* 0x7f is center */ - y = effect->u.ramp.end_level + 0x7f; - CLAMP(x); - CLAMP(y); - report->field[0]->value[0] = 0x51; - report->field[0]->value[1] = 0x08; - report->field[0]->value[2] = x; - report->field[0]->value[3] = y; - dbg_hid("(x, y)=(%04x, %04x)\n", x, y); - usbhid_submit_report(hid, report, USB_DIR_OUT); - break; - - case FF_RUMBLE: - right = effect->u.rumble.strong_magnitude; - left = effect->u.rumble.weak_magnitude; - right = right * 0xff / 0xffff; - left = left * 0xff / 0xffff; - CLAMP(left); - CLAMP(right); - report->field[0]->value[0] = 0x42; - report->field[0]->value[1] = 0x00; - report->field[0]->value[2] = left; - report->field[0]->value[3] = right; - dbg_hid("(left, right)=(%04x, %04x)\n", left, right); - usbhid_submit_report(hid, report, USB_DIR_OUT); - break; - } - return 0; -} - -int hid_lgff_init(struct hid_device* hid) -{ - struct hid_input *hidinput = list_entry(hid->inputs.next, struct hid_input, list); - struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list; - struct input_dev *dev = hidinput->input; - struct hid_report *report; - struct hid_field *field; - const signed short *ff_bits = ff_joystick; - int error; - int i; - - /* Find the report to use */ - if (list_empty(report_list)) { - err_hid("No output report found"); - return -1; - } - - /* Check that the report looks ok */ - report = list_entry(report_list->next, struct hid_report, list); - if (!report) { - err_hid("NULL output report"); - return -1; - } - - field = report->field[0]; - if (!field) { - err_hid("NULL field"); - return -1; - } - - for (i = 0; i < ARRAY_SIZE(devices); i++) { - if (dev->id.vendor == devices[i].idVendor && - dev->id.product == devices[i].idProduct) { - ff_bits = devices[i].ff; - break; - } - } - - for (i = 0; ff_bits[i] >= 0; i++) - set_bit(ff_bits[i], dev->ffbit); - - error = input_ff_create_memless(dev, NULL, hid_lgff_play); - if (error) - return error; - - printk(KERN_INFO "Force feedback for Logitech force feedback devices by Johann Deneux \n"); - - return 0; -} diff --git a/include/linux/hid.h b/include/linux/hid.h index b0f03fa2ed1..15ee33e0463 100644 --- a/include/linux/hid.h +++ b/include/linux/hid.h @@ -760,8 +760,6 @@ void usbhid_set_leds(struct hid_device *hid); #ifdef CONFIG_HID_FF int hid_ff_init(struct hid_device *hid); -int hid_lgff_init(struct hid_device *hid); -int hid_lg2ff_init(struct hid_device *hid); int hid_plff_init(struct hid_device *hid); int hid_tmff_init(struct hid_device *hid); int hid_zpff_init(struct hid_device *hid); -- cgit v1.2.3-70-g09d2 From 6f3c0e509640070e3c013cd9787a7d1892276b3f Mon Sep 17 00:00:00 2001 From: Alex Chiang Date: Wed, 27 Aug 2008 13:36:18 +0200 Subject: HID: fix grammo in HID_COMPAT Kconfig help text The Kconfig option for HID_COMPAT should read "lose", not "loose". Signed-off-by: Alex Chiang Signed-off-by: Jiri Kosina --- drivers/hid/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/hid/Kconfig') diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index 4319af320ad..46337a28d1d 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -78,7 +78,7 @@ config HID_COMPAT support of module loading through aliases and also old module-init-tools which can't handle hid bus, choose Y here. Otherwise say N. If you say N and your userspace is old enough, the only - functionality you loose is modules autoloading. + functionality you lose is modules autoloading. If unsure, say Y. -- cgit v1.2.3-70-g09d2 From 5f022298aab58ddff9bccdb28b82a59109789da9 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Thu, 18 Sep 2008 19:43:32 +0200 Subject: HID: move pantherlord FF processing Move the force feedback processing into a separate module. [jkosina@suse.cz: fix Kconfig texts a little bit] Signed-off-by: Jiri Slaby Signed-off-by: Jiri Kosina --- drivers/hid/Kconfig | 16 ++++ drivers/hid/Makefile | 1 + drivers/hid/hid-core.c | 2 + drivers/hid/hid-dummy.c | 3 + drivers/hid/hid-ids.h | 2 + drivers/hid/hid-pl.c | 205 ++++++++++++++++++++++++++++++++++++++++ drivers/hid/usbhid/Kconfig | 8 -- drivers/hid/usbhid/Makefile | 3 - drivers/hid/usbhid/hid-ff.c | 4 - drivers/hid/usbhid/hid-plff.c | 139 --------------------------- drivers/hid/usbhid/hid-quirks.c | 1 - include/linux/hid.h | 1 - 12 files changed, 229 insertions(+), 156 deletions(-) create mode 100644 drivers/hid/hid-pl.c delete mode 100644 drivers/hid/usbhid/hid-plff.c (limited to 'drivers/hid/Kconfig') diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index 46337a28d1d..c836caba82d 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -199,6 +199,22 @@ config HID_MONTEREY ---help--- Support for Monterey Genius KB29E. +config HID_PANTHERLORD + tristate "Pantherlord devices support" + default m + depends on USB_HID + ---help--- + Support for PantherLord/GreenAsia based device support. + + +config PANTHERLORD_FF + bool "Pantherlord force feedback support" + depends on HID_PANTHERLORD + select INPUT_FF_MEMLESS + help + Say Y here if you have a PantherLord/GreenAsia based game controller + or adapter and want to enable force feedback support for it. + config HID_PETALYNX tristate "Petalynx" default m diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile index 300ee00913b..e6070683524 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile @@ -32,6 +32,7 @@ obj-$(CONFIG_HID_GYRATION) += hid-gyration.o obj-$(CONFIG_HID_LOGITECH) += hid-logitech.o obj-$(CONFIG_HID_MICROSOFT) += hid-microsoft.o obj-$(CONFIG_HID_MONTEREY) += hid-monterey.o +obj-$(CONFIG_HID_PANTHERLORD) += hid-pl.o obj-$(CONFIG_HID_PETALYNX) += hid-petalynx.o obj-$(CONFIG_HID_SAMSUNG) += hid-samsung.o obj-$(CONFIG_HID_SONY) += hid-sony.o diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 63c8ce5540f..48a76e791e0 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1411,6 +1411,7 @@ static const struct hid_device_id hid_ignore_list[] = { { HID_USB_DEVICE(USB_VENDOR_ID_DELORME, USB_DEVICE_ID_DELORME_EARTHMATE) }, { HID_USB_DEVICE(USB_VENDOR_ID_DELORME, USB_DEVICE_ID_DELORME_EM_LT20) }, { HID_USB_DEVICE(USB_VENDOR_ID_ESSENTIAL_REALITY, USB_DEVICE_ID_ESSENTIAL_REALITY_P5) }, + { HID_USB_DEVICE(USB_VENDOR_ID_GAMERON, USB_DEVICE_ID_GAMERON_DUAL_PSX_ADAPTOR) }, { HID_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH, 0x0001) }, { HID_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH, 0x0002) }, { HID_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH, 0x0003) }, @@ -1426,6 +1427,7 @@ static const struct hid_device_id hid_ignore_list[] = { { HID_USB_DEVICE(USB_VENDOR_ID_GOTOP, USB_DEVICE_ID_SUPER_Q2) }, { HID_USB_DEVICE(USB_VENDOR_ID_GOTOP, USB_DEVICE_ID_GOGOPEN) }, { HID_USB_DEVICE(USB_VENDOR_ID_GOTOP, USB_DEVICE_ID_PENPOWER) }, + { HID_USB_DEVICE(USB_VENDOR_ID_GREENASIA, 0x0003) }, { HID_USB_DEVICE(USB_VENDOR_ID_GRETAGMACBETH, USB_DEVICE_ID_GRETAGMACBETH_HUEY) }, { HID_USB_DEVICE(USB_VENDOR_ID_GRIFFIN, USB_DEVICE_ID_POWERMATE) }, { HID_USB_DEVICE(USB_VENDOR_ID_GRIFFIN, USB_DEVICE_ID_SOUNDKNOB) }, diff --git a/drivers/hid/hid-dummy.c b/drivers/hid/hid-dummy.c index 69dcf9b1a44..2f5d9a1a352 100644 --- a/drivers/hid/hid-dummy.c +++ b/drivers/hid/hid-dummy.c @@ -40,6 +40,9 @@ static int __init hid_dummy_init(void) #ifdef CONFIG_HID_MONTEREY_MODULE HID_COMPAT_CALL_DRIVER(monterey); #endif +#ifdef CONFIG_HID_PANTHERLORD_MODULE + HID_COMPAT_CALL_DRIVER(pantherlord); +#endif #ifdef CONFIG_HID_PETALYNX_MODULE HID_COMPAT_CALL_DRIVER(petalynx); #endif diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index fa4e4fd96f6..fdd2d13036f 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -169,6 +169,8 @@ #define USB_DEVICE_ID_GOGOPEN 0x00ce #define USB_DEVICE_ID_PENPOWER 0x00f4 +#define USB_VENDOR_ID_GREENASIA 0x0e8f + #define USB_VENDOR_ID_GRETAGMACBETH 0x0971 #define USB_DEVICE_ID_GRETAGMACBETH_HUEY 0x2005 diff --git a/drivers/hid/hid-pl.c b/drivers/hid/hid-pl.c new file mode 100644 index 00000000000..a1d1fb9da12 --- /dev/null +++ b/drivers/hid/hid-pl.c @@ -0,0 +1,205 @@ +/* + * Force feedback support for PantherLord/GreenAsia based devices + * + * The devices are distributed under various names and the same USB device ID + * can be used in both adapters and actual game controllers. + * + * 0810:0001 "Twin USB Joystick" + * - tested with PantherLord USB/PS2 2in1 Adapter + * - contains two reports, one for each port (HID_QUIRK_MULTI_INPUT) + * + * 0e8f:0003 "GreenAsia Inc. USB Joystick " + * - tested with K??ng Gaming gamepad + * + * Copyright (c) 2007 Anssi Hannula + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +/* #define DEBUG */ + +#define debug(format, arg...) pr_debug("hid-plff: " format "\n" , ## arg) + +#include +#include +#include + +#include "hid-ids.h" + +#ifdef CONFIG_PANTHERLORD_FF +#include "usbhid/usbhid.h" + +struct plff_device { + struct hid_report *report; +}; + +static int hid_plff_play(struct input_dev *dev, void *data, + struct ff_effect *effect) +{ + struct hid_device *hid = input_get_drvdata(dev); + struct plff_device *plff = data; + int left, right; + + left = effect->u.rumble.strong_magnitude; + right = effect->u.rumble.weak_magnitude; + debug("called with 0x%04x 0x%04x", left, right); + + left = left * 0x7f / 0xffff; + right = right * 0x7f / 0xffff; + + plff->report->field[0]->value[2] = left; + plff->report->field[0]->value[3] = right; + debug("running with 0x%02x 0x%02x", left, right); + usbhid_submit_report(hid, plff->report, USB_DIR_OUT); + + return 0; +} + +static int plff_init(struct hid_device *hid) +{ + struct plff_device *plff; + struct hid_report *report; + struct hid_input *hidinput; + struct list_head *report_list = + &hid->report_enum[HID_OUTPUT_REPORT].report_list; + struct list_head *report_ptr = report_list; + struct input_dev *dev; + int error; + + /* The device contains one output report per physical device, all + containing 1 field, which contains 4 ff00.0002 usages and 4 16bit + absolute values. + + The input reports also contain a field which contains + 8 ff00.0001 usages and 8 boolean values. Their meaning is + currently unknown. */ + + if (list_empty(report_list)) { + printk(KERN_ERR "hid-plff: no output reports found\n"); + return -ENODEV; + } + + list_for_each_entry(hidinput, &hid->inputs, list) { + + report_ptr = report_ptr->next; + + if (report_ptr == report_list) { + printk(KERN_ERR "hid-plff: required output report is missing\n"); + return -ENODEV; + } + + report = list_entry(report_ptr, struct hid_report, list); + if (report->maxfield < 1) { + printk(KERN_ERR "hid-plff: no fields in the report\n"); + return -ENODEV; + } + + if (report->field[0]->report_count < 4) { + printk(KERN_ERR "hid-plff: not enough values in the field\n"); + return -ENODEV; + } + + plff = kzalloc(sizeof(struct plff_device), GFP_KERNEL); + if (!plff) + return -ENOMEM; + + dev = hidinput->input; + + set_bit(FF_RUMBLE, dev->ffbit); + + error = input_ff_create_memless(dev, plff, hid_plff_play); + if (error) { + kfree(plff); + return error; + } + + plff->report = report; + plff->report->field[0]->value[0] = 0x00; + plff->report->field[0]->value[1] = 0x00; + plff->report->field[0]->value[2] = 0x00; + plff->report->field[0]->value[3] = 0x00; + usbhid_submit_report(hid, plff->report, USB_DIR_OUT); + } + + printk(KERN_INFO "hid-plff: Force feedback for PantherLord/GreenAsia " + "devices by Anssi Hannula \n"); + + return 0; +} +#else +static inline int plff_init(struct hid_device *hid) +{ + return 0; +} +#endif + +static int pl_probe(struct hid_device *hdev, const struct hid_device_id *id) +{ + int ret; + + if (id->driver_data) + hdev->quirks |= HID_QUIRK_MULTI_INPUT; + + ret = hid_parse(hdev); + if (ret) { + dev_err(&hdev->dev, "parse failed\n"); + goto err; + } + + ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT & ~HID_CONNECT_FF); + if (ret) { + dev_err(&hdev->dev, "hw start failed\n"); + goto err; + } + + plff_init(hdev); + + return 0; +err: + return ret; +} + +static const struct hid_device_id pl_devices[] = { + { HID_USB_DEVICE(USB_VENDOR_ID_GAMERON, USB_DEVICE_ID_GAMERON_DUAL_PSX_ADAPTOR), + .driver_data = 1 }, /* Twin USB Joystick */ + { HID_USB_DEVICE(USB_VENDOR_ID_GREENASIA, 0x0003), }, /* GreenAsia Inc. USB Joystick */ + { } +}; +MODULE_DEVICE_TABLE(hid, pl_devices); + +static struct hid_driver pl_driver = { + .name = "pantherlord", + .id_table = pl_devices, + .probe = pl_probe, +}; + +static int pl_init(void) +{ + return hid_register_driver(&pl_driver); +} + +static void pl_exit(void) +{ + hid_unregister_driver(&pl_driver); +} + +module_init(pl_init); +module_exit(pl_exit); +MODULE_LICENSE("GPL"); + +HID_COMPAT_LOAD_DRIVER(pantherlord); diff --git a/drivers/hid/usbhid/Kconfig b/drivers/hid/usbhid/Kconfig index 0e7e2e6d975..02c8228ed7e 100644 --- a/drivers/hid/usbhid/Kconfig +++ b/drivers/hid/usbhid/Kconfig @@ -44,14 +44,6 @@ config HID_PID feedback for it. Microsoft Sidewinder Force Feedback 2 is one of such devices. -config PANTHERLORD_FF - bool "PantherLord/GreenAsia based device support" - depends on HID_FF - select INPUT_FF_MEMLESS if USB_HID - help - Say Y here if you have a PantherLord/GreenAsia based game controller - or adapter and want to enable force feedback support for it. - config THRUSTMASTER_FF bool "ThrustMaster devices support" depends on HID_FF diff --git a/drivers/hid/usbhid/Makefile b/drivers/hid/usbhid/Makefile index 224c62dc6a3..0ee4803375b 100644 --- a/drivers/hid/usbhid/Makefile +++ b/drivers/hid/usbhid/Makefile @@ -13,9 +13,6 @@ endif ifeq ($(CONFIG_HID_PID),y) usbhid-objs += hid-pidff.o endif -ifeq ($(CONFIG_PANTHERLORD_FF),y) - usbhid-objs += hid-plff.o -endif ifeq ($(CONFIG_THRUSTMASTER_FF),y) usbhid-objs += hid-tmff.o endif diff --git a/drivers/hid/usbhid/hid-ff.c b/drivers/hid/usbhid/hid-ff.c index 8891f60d3be..a868eef0618 100644 --- a/drivers/hid/usbhid/hid-ff.c +++ b/drivers/hid/usbhid/hid-ff.c @@ -50,10 +50,6 @@ struct hid_ff_initializer { * be a PID device */ static struct hid_ff_initializer inits[] = { -#ifdef CONFIG_PANTHERLORD_FF - { 0x810, 0x0001, hid_plff_init }, /* "Twin USB Joystick" */ - { 0xe8f, 0x0003, hid_plff_init }, /* "GreenAsia Inc. USB Joystick " */ -#endif #ifdef CONFIG_THRUSTMASTER_FF { 0x44f, 0xb300, hid_tmff_init }, { 0x44f, 0xb304, hid_tmff_init }, diff --git a/drivers/hid/usbhid/hid-plff.c b/drivers/hid/usbhid/hid-plff.c deleted file mode 100644 index 9eb83cf9d22..00000000000 --- a/drivers/hid/usbhid/hid-plff.c +++ /dev/null @@ -1,139 +0,0 @@ -/* - * Force feedback support for PantherLord/GreenAsia based devices - * - * The devices are distributed under various names and the same USB device ID - * can be used in both adapters and actual game controllers. - * - * 0810:0001 "Twin USB Joystick" - * - tested with PantherLord USB/PS2 2in1 Adapter - * - contains two reports, one for each port (HID_QUIRK_MULTI_INPUT) - * - * 0e8f:0003 "GreenAsia Inc. USB Joystick " - * - tested with Köng Gaming gamepad - * - * Copyright (c) 2007 Anssi Hannula - */ - -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - - -/* #define DEBUG */ - -#define debug(format, arg...) pr_debug("hid-plff: " format "\n" , ## arg) - -#include -#include -#include -#include "usbhid.h" - -struct plff_device { - struct hid_report *report; -}; - -static int hid_plff_play(struct input_dev *dev, void *data, - struct ff_effect *effect) -{ - struct hid_device *hid = input_get_drvdata(dev); - struct plff_device *plff = data; - int left, right; - - left = effect->u.rumble.strong_magnitude; - right = effect->u.rumble.weak_magnitude; - debug("called with 0x%04x 0x%04x", left, right); - - left = left * 0x7f / 0xffff; - right = right * 0x7f / 0xffff; - - plff->report->field[0]->value[2] = left; - plff->report->field[0]->value[3] = right; - debug("running with 0x%02x 0x%02x", left, right); - usbhid_submit_report(hid, plff->report, USB_DIR_OUT); - - return 0; -} - -int hid_plff_init(struct hid_device *hid) -{ - struct plff_device *plff; - struct hid_report *report; - struct hid_input *hidinput; - struct list_head *report_list = - &hid->report_enum[HID_OUTPUT_REPORT].report_list; - struct list_head *report_ptr = report_list; - struct input_dev *dev; - int error; - - /* The device contains one output report per physical device, all - containing 1 field, which contains 4 ff00.0002 usages and 4 16bit - absolute values. - - The input reports also contain a field which contains - 8 ff00.0001 usages and 8 boolean values. Their meaning is - currently unknown. */ - - if (list_empty(report_list)) { - printk(KERN_ERR "hid-plff: no output reports found\n"); - return -ENODEV; - } - - list_for_each_entry(hidinput, &hid->inputs, list) { - - report_ptr = report_ptr->next; - - if (report_ptr == report_list) { - printk(KERN_ERR "hid-plff: required output report is missing\n"); - return -ENODEV; - } - - report = list_entry(report_ptr, struct hid_report, list); - if (report->maxfield < 1) { - printk(KERN_ERR "hid-plff: no fields in the report\n"); - return -ENODEV; - } - - if (report->field[0]->report_count < 4) { - printk(KERN_ERR "hid-plff: not enough values in the field\n"); - return -ENODEV; - } - - plff = kzalloc(sizeof(struct plff_device), GFP_KERNEL); - if (!plff) - return -ENOMEM; - - dev = hidinput->input; - - set_bit(FF_RUMBLE, dev->ffbit); - - error = input_ff_create_memless(dev, plff, hid_plff_play); - if (error) { - kfree(plff); - return error; - } - - plff->report = report; - plff->report->field[0]->value[0] = 0x00; - plff->report->field[0]->value[1] = 0x00; - plff->report->field[0]->value[2] = 0x00; - plff->report->field[0]->value[3] = 0x00; - usbhid_submit_report(hid, plff->report, USB_DIR_OUT); - } - - printk(KERN_INFO "hid-plff: Force feedback for PantherLord/GreenAsia " - "devices by Anssi Hannula \n"); - - return 0; -} diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c index d40f00904c5..47ebe045f9b 100644 --- a/drivers/hid/usbhid/hid-quirks.c +++ b/drivers/hid/usbhid/hid-quirks.c @@ -32,7 +32,6 @@ static const struct hid_blacklist { { USB_VENDOR_ID_AASHIMA, USB_DEVICE_ID_AASHIMA_PREDATOR, HID_QUIRK_BADPAD }, { USB_VENDOR_ID_ALPS, USB_DEVICE_ID_IBM_GAMEPAD, HID_QUIRK_BADPAD }, { USB_VENDOR_ID_CHIC, USB_DEVICE_ID_CHIC_GAMEPAD, HID_QUIRK_BADPAD }, - { USB_VENDOR_ID_GAMERON, USB_DEVICE_ID_GAMERON_DUAL_PSX_ADAPTOR, HID_QUIRK_MULTI_INPUT }, { 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 }, diff --git a/include/linux/hid.h b/include/linux/hid.h index 15ee33e0463..63b80806720 100644 --- a/include/linux/hid.h +++ b/include/linux/hid.h @@ -760,7 +760,6 @@ void usbhid_set_leds(struct hid_device *hid); #ifdef CONFIG_HID_FF int hid_ff_init(struct hid_device *hid); -int hid_plff_init(struct hid_device *hid); int hid_tmff_init(struct hid_device *hid); int hid_zpff_init(struct hid_device *hid); #ifdef CONFIG_HID_PID -- cgit v1.2.3-70-g09d2 From 10e41a711e55f485709b4ca157e587cf36ef5a69 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Thu, 18 Sep 2008 12:23:31 +0200 Subject: HID: move thrustmaster FF processing Signed-off-by: Jiri Slaby Signed-off-by: Jiri Kosina --- drivers/hid/Kconfig | 9 ++ drivers/hid/Makefile | 1 + drivers/hid/hid-core.c | 4 + drivers/hid/hid-dummy.c | 3 + drivers/hid/hid-ids.h | 2 + drivers/hid/hid-tmff.c | 267 ++++++++++++++++++++++++++++++++++++++++++ drivers/hid/usbhid/Kconfig | 11 -- drivers/hid/usbhid/Makefile | 3 - drivers/hid/usbhid/hid-ff.c | 6 - drivers/hid/usbhid/hid-tmff.c | 225 ----------------------------------- include/linux/hid.h | 1 - 11 files changed, 286 insertions(+), 246 deletions(-) create mode 100644 drivers/hid/hid-tmff.c delete mode 100644 drivers/hid/usbhid/hid-tmff.c (limited to 'drivers/hid/Kconfig') diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index c836caba82d..78e3ba9504f 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -243,6 +243,15 @@ config HID_SUNPLUS ---help--- Support for Sunplus WDesktop input device. +config THRUSTMASTER_FF + tristate "ThrustMaster devices support" + default m + depends on USB_HID + select INPUT_FF_MEMLESS + help + Say Y here if you have a THRUSTMASTER FireStore Dual Power 2 or + a THRUSTMASTER Ferrari GT Rumble Force or Force Feedback Wheel. + endmenu endif # HID_SUPPORT diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile index e6070683524..9bd6daf6aaa 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile @@ -37,6 +37,7 @@ obj-$(CONFIG_HID_PETALYNX) += hid-petalynx.o obj-$(CONFIG_HID_SAMSUNG) += hid-samsung.o obj-$(CONFIG_HID_SONY) += hid-sony.o obj-$(CONFIG_HID_SUNPLUS) += hid-sunplus.o +obj-$(CONFIG_THRUSTMASTER_FF) += hid-tmff.o obj-$(CONFIG_USB_HID) += usbhid/ obj-$(CONFIG_USB_MOUSE) += usbhid/ diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 48a76e791e0..b0996ff1462 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1516,6 +1516,10 @@ static const struct hid_device_id hid_ignore_list[] = { { HID_USB_DEVICE(USB_VENDOR_ID_SOUNDGRAPH, USB_DEVICE_ID_SOUNDGRAPH_IMON_LCD) }, { HID_USB_DEVICE(USB_VENDOR_ID_TENX, USB_DEVICE_ID_TENX_IBUDDY1) }, { HID_USB_DEVICE(USB_VENDOR_ID_TENX, USB_DEVICE_ID_TENX_IBUDDY2) }, + { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb300) }, + { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb304) }, + { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb651) }, + { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb654) }, { HID_USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_LABPRO) }, { HID_USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_GOTEMP) }, { HID_USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_SKIP) }, diff --git a/drivers/hid/hid-dummy.c b/drivers/hid/hid-dummy.c index 2f5d9a1a352..ae122a122fa 100644 --- a/drivers/hid/hid-dummy.c +++ b/drivers/hid/hid-dummy.c @@ -55,6 +55,9 @@ static int __init hid_dummy_init(void) #ifdef CONFIG_HID_SUNPLUS_MODULE HID_COMPAT_CALL_DRIVER(sunplus); #endif +#ifdef CONFIG_THRUSTMASTER_FF_MODULE + HID_COMPAT_CALL_DRIVER(thrustmaster); +#endif return -EIO; } diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index fdd2d13036f..b8cc0196ec0 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -357,6 +357,8 @@ #define USB_DEVICE_ID_TENX_IBUDDY1 0x0001 #define USB_DEVICE_ID_TENX_IBUDDY2 0x0002 +#define USB_VENDOR_ID_THRUSTMASTER 0x044f + #define USB_VENDOR_ID_TOPMAX 0x0663 #define USB_DEVICE_ID_TOPMAX_COBRAPAD 0x0103 diff --git a/drivers/hid/hid-tmff.c b/drivers/hid/hid-tmff.c new file mode 100644 index 00000000000..be7ebe286a1 --- /dev/null +++ b/drivers/hid/hid-tmff.c @@ -0,0 +1,267 @@ +/* + * Force feedback support for various HID compliant devices by ThrustMaster: + * ThrustMaster FireStorm Dual Power 2 + * and possibly others whose device ids haven't been added. + * + * Modified to support ThrustMaster devices by Zinx Verituse + * on 2003-01-25 from the Logitech force feedback driver, + * which is by Johann Deneux. + * + * Copyright (c) 2003 Zinx Verituse + * Copyright (c) 2002 Johann Deneux + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include + +#include "hid-ids.h" + +#include "usbhid/usbhid.h" + +/* Usages for thrustmaster devices I know about */ +#define THRUSTMASTER_USAGE_FF (HID_UP_GENDESK | 0xbb) + +static const signed short ff_rumble[] = { + FF_RUMBLE, + -1 +}; + +static const signed short ff_joystick[] = { + FF_CONSTANT, + -1 +}; + +struct tmff_device { + struct hid_report *report; + struct hid_field *ff_field; +}; + +/* Changes values from 0 to 0xffff into values from minimum to maximum */ +static inline int tmff_scale_u16(unsigned int in, int minimum, int maximum) +{ + int ret; + + ret = (in * (maximum - minimum) / 0xffff) + minimum; + if (ret < minimum) + return minimum; + if (ret > maximum) + return maximum; + return ret; +} + +/* Changes values from -0x80 to 0x7f into values from minimum to maximum */ +static inline int tmff_scale_s8(int in, int minimum, int maximum) +{ + int ret; + + ret = (((in + 0x80) * (maximum - minimum)) / 0xff) + minimum; + if (ret < minimum) + return minimum; + if (ret > maximum) + return maximum; + return ret; +} + +static int tmff_play(struct input_dev *dev, void *data, + struct ff_effect *effect) +{ + struct hid_device *hid = input_get_drvdata(dev); + struct tmff_device *tmff = data; + struct hid_field *ff_field = tmff->ff_field; + int x, y; + int left, right; /* Rumbling */ + + switch (effect->type) { + case FF_CONSTANT: + x = tmff_scale_s8(effect->u.ramp.start_level, + ff_field->logical_minimum, + ff_field->logical_maximum); + y = tmff_scale_s8(effect->u.ramp.end_level, + ff_field->logical_minimum, + ff_field->logical_maximum); + + dbg_hid("(x, y)=(%04x, %04x)\n", x, y); + ff_field->value[0] = x; + ff_field->value[1] = y; + usbhid_submit_report(hid, tmff->report, USB_DIR_OUT); + break; + + case FF_RUMBLE: + left = tmff_scale_u16(effect->u.rumble.weak_magnitude, + ff_field->logical_minimum, + ff_field->logical_maximum); + right = tmff_scale_u16(effect->u.rumble.strong_magnitude, + ff_field->logical_minimum, + ff_field->logical_maximum); + + dbg_hid("(left,right)=(%08x, %08x)\n", left, right); + ff_field->value[0] = left; + ff_field->value[1] = right; + usbhid_submit_report(hid, tmff->report, USB_DIR_OUT); + break; + } + return 0; +} + +static int tmff_init(struct hid_device *hid, const signed short *ff_bits) +{ + struct tmff_device *tmff; + struct hid_report *report; + struct list_head *report_list; + struct hid_input *hidinput = list_entry(hid->inputs.next, + struct hid_input, list); + struct input_dev *input_dev = hidinput->input; + int error; + int i; + + tmff = kzalloc(sizeof(struct tmff_device), GFP_KERNEL); + if (!tmff) + return -ENOMEM; + + /* Find the report to use */ + report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list; + list_for_each_entry(report, report_list, list) { + int fieldnum; + + for (fieldnum = 0; fieldnum < report->maxfield; ++fieldnum) { + struct hid_field *field = report->field[fieldnum]; + + if (field->maxusage <= 0) + continue; + + switch (field->usage[0].hid) { + case THRUSTMASTER_USAGE_FF: + if (field->report_count < 2) { + warn("ignoring FF field with " + "report_count < 2"); + continue; + } + + if (field->logical_maximum == + field->logical_minimum) { + warn("ignoring FF field with " + "logical_maximum == " + "logical_minimum"); + continue; + } + + if (tmff->report && tmff->report != report) { + warn("ignoring FF field in other " + "report"); + continue; + } + + if (tmff->ff_field && tmff->ff_field != field) { + warn("ignoring duplicate FF field"); + continue; + } + + tmff->report = report; + tmff->ff_field = field; + + for (i = 0; ff_bits[i] >= 0; i++) + set_bit(ff_bits[i], input_dev->ffbit); + + break; + + default: + warn("ignoring unknown output usage %08x", + field->usage[0].hid); + continue; + } + } + } + + if (!tmff->report) { + err("cant find FF field in output reports\n"); + error = -ENODEV; + goto fail; + } + + error = input_ff_create_memless(input_dev, tmff, tmff_play); + if (error) + goto fail; + + info("Force feedback for ThrustMaster devices by Zinx Verituse " + ""); + return 0; + +fail: + kfree(tmff); + return error; +} + +static int tm_probe(struct hid_device *hdev, const struct hid_device_id *id) +{ + int ret; + + ret = hid_parse(hdev); + if (ret) { + dev_err(&hdev->dev, "parse failed\n"); + goto err; + } + + ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT & ~HID_CONNECT_FF); + if (ret) { + dev_err(&hdev->dev, "hw start failed\n"); + goto err; + } + + tmff_init(hdev, (void *)id->driver_data); + + return 0; +err: + return ret; +} + +static const struct hid_device_id tm_devices[] = { + { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb300), + .driver_data = (unsigned long)ff_rumble }, + { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb304), + .driver_data = (unsigned long)ff_rumble }, + { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb651), /* FGT Rumble Force Wheel */ + .driver_data = (unsigned long)ff_rumble }, + { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb654), /* FGT Force Feedback Wheel */ + .driver_data = (unsigned long)ff_joystick }, + { } +}; +MODULE_DEVICE_TABLE(hid, tm_devices); + +static struct hid_driver tm_driver = { + .name = "thrustmaster", + .id_table = tm_devices, + .probe = tm_probe, +}; + +static int tm_init(void) +{ + return hid_register_driver(&tm_driver); +} + +static void tm_exit(void) +{ + hid_unregister_driver(&tm_driver); +} + +module_init(tm_init); +module_exit(tm_exit); +MODULE_LICENSE("GPL"); + +HID_COMPAT_LOAD_DRIVER(thrustmaster); diff --git a/drivers/hid/usbhid/Kconfig b/drivers/hid/usbhid/Kconfig index 02c8228ed7e..c236fb3deb5 100644 --- a/drivers/hid/usbhid/Kconfig +++ b/drivers/hid/usbhid/Kconfig @@ -44,17 +44,6 @@ config HID_PID feedback for it. Microsoft Sidewinder Force Feedback 2 is one of such devices. -config THRUSTMASTER_FF - bool "ThrustMaster devices support" - depends on HID_FF - select INPUT_FF_MEMLESS if USB_HID - help - Say Y here if you have a THRUSTMASTER FireStore Dual Power 2 or - a THRUSTMASTER Ferrari GT Rumble Force or Force Feedback Wheel, - and want to enable force feedback support for it. - Note: if you say N here, this device will still be supported, but without - force feedback. - config ZEROPLUS_FF bool "Zeroplus based game controller support" depends on HID_FF diff --git a/drivers/hid/usbhid/Makefile b/drivers/hid/usbhid/Makefile index 0ee4803375b..dd3b8634800 100644 --- a/drivers/hid/usbhid/Makefile +++ b/drivers/hid/usbhid/Makefile @@ -13,9 +13,6 @@ endif ifeq ($(CONFIG_HID_PID),y) usbhid-objs += hid-pidff.o endif -ifeq ($(CONFIG_THRUSTMASTER_FF),y) - usbhid-objs += hid-tmff.o -endif ifeq ($(CONFIG_ZEROPLUS_FF),y) usbhid-objs += hid-zpff.o endif diff --git a/drivers/hid/usbhid/hid-ff.c b/drivers/hid/usbhid/hid-ff.c index a868eef0618..ed3a869d54e 100644 --- a/drivers/hid/usbhid/hid-ff.c +++ b/drivers/hid/usbhid/hid-ff.c @@ -50,12 +50,6 @@ struct hid_ff_initializer { * be a PID device */ static struct hid_ff_initializer inits[] = { -#ifdef CONFIG_THRUSTMASTER_FF - { 0x44f, 0xb300, hid_tmff_init }, - { 0x44f, 0xb304, hid_tmff_init }, - { 0x44f, 0xb651, hid_tmff_init }, /* FGT Rumble Force Wheel */ - { 0x44f, 0xb654, hid_tmff_init }, /* FGT Force Feedback Wheel */ -#endif #ifdef CONFIG_ZEROPLUS_FF { 0xc12, 0x0005, hid_zpff_init }, { 0xc12, 0x0030, hid_zpff_init }, diff --git a/drivers/hid/usbhid/hid-tmff.c b/drivers/hid/usbhid/hid-tmff.c deleted file mode 100644 index 144578b1a00..00000000000 --- a/drivers/hid/usbhid/hid-tmff.c +++ /dev/null @@ -1,225 +0,0 @@ -/* - * Force feedback support for various HID compliant devices by ThrustMaster: - * ThrustMaster FireStorm Dual Power 2 - * and possibly others whose device ids haven't been added. - * - * Modified to support ThrustMaster devices by Zinx Verituse - * on 2003-01-25 from the Logitech force feedback driver, - * which is by Johann Deneux. - * - * Copyright (c) 2003 Zinx Verituse - * Copyright (c) 2002 Johann Deneux - */ - -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include - -#undef DEBUG -#include - -#include -#include "usbhid.h" - -/* Usages for thrustmaster devices I know about */ -#define THRUSTMASTER_USAGE_FF (HID_UP_GENDESK | 0xbb) - -struct dev_type { - u16 idVendor; - u16 idProduct; - const signed short *ff; -}; - -static const signed short ff_rumble[] = { - FF_RUMBLE, - -1 -}; - -static const signed short ff_joystick[] = { - FF_CONSTANT, - -1 -}; - -static const struct dev_type devices[] = { - { 0x44f, 0xb300, ff_rumble }, - { 0x44f, 0xb304, ff_rumble }, - { 0x44f, 0xb651, ff_rumble }, /* FGT Rumble Force Wheel */ - { 0x44f, 0xb654, ff_joystick }, /* FGT Force Feedback Wheel */ -}; - -struct tmff_device { - struct hid_report *report; - struct hid_field *ff_field; -}; - -/* Changes values from 0 to 0xffff into values from minimum to maximum */ -static inline int hid_tmff_scale_u16(unsigned int in, - int minimum, int maximum) -{ - int ret; - - ret = (in * (maximum - minimum) / 0xffff) + minimum; - if (ret < minimum) - return minimum; - if (ret > maximum) - return maximum; - return ret; -} - -/* Changes values from -0x80 to 0x7f into values from minimum to maximum */ -static inline int hid_tmff_scale_s8(int in, - int minimum, int maximum) -{ - int ret; - - ret = (((in + 0x80) * (maximum - minimum)) / 0xff) + minimum; - if (ret < minimum) - return minimum; - if (ret > maximum) - return maximum; - return ret; -} - -static int hid_tmff_play(struct input_dev *dev, void *data, struct ff_effect *effect) -{ - struct hid_device *hid = input_get_drvdata(dev); - struct tmff_device *tmff = data; - struct hid_field *ff_field = tmff->ff_field; - int x, y; - int left, right; /* Rumbling */ - - switch (effect->type) { - case FF_CONSTANT: - x = hid_tmff_scale_s8(effect->u.ramp.start_level, - ff_field->logical_minimum, - ff_field->logical_maximum); - y = hid_tmff_scale_s8(effect->u.ramp.end_level, - ff_field->logical_minimum, - ff_field->logical_maximum); - - dbg_hid("(x, y)=(%04x, %04x)\n", x, y); - ff_field->value[0] = x; - ff_field->value[1] = y; - usbhid_submit_report(hid, tmff->report, USB_DIR_OUT); - break; - - case FF_RUMBLE: - left = hid_tmff_scale_u16(effect->u.rumble.weak_magnitude, - ff_field->logical_minimum, - ff_field->logical_maximum); - right = hid_tmff_scale_u16(effect->u.rumble.strong_magnitude, - ff_field->logical_minimum, - ff_field->logical_maximum); - - dbg_hid("(left,right)=(%08x, %08x)\n", left, right); - ff_field->value[0] = left; - ff_field->value[1] = right; - usbhid_submit_report(hid, tmff->report, USB_DIR_OUT); - break; - } - return 0; -} - -int hid_tmff_init(struct hid_device *hid) -{ - struct tmff_device *tmff; - struct hid_report *report; - struct list_head *report_list; - struct hid_input *hidinput = list_entry(hid->inputs.next, struct hid_input, list); - struct input_dev *input_dev = hidinput->input; - const signed short *ff_bits = ff_joystick; - int error; - int i; - - tmff = kzalloc(sizeof(struct tmff_device), GFP_KERNEL); - if (!tmff) - return -ENOMEM; - - /* Find the report to use */ - report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list; - list_for_each_entry(report, report_list, list) { - int fieldnum; - - for (fieldnum = 0; fieldnum < report->maxfield; ++fieldnum) { - struct hid_field *field = report->field[fieldnum]; - - if (field->maxusage <= 0) - continue; - - switch (field->usage[0].hid) { - case THRUSTMASTER_USAGE_FF: - if (field->report_count < 2) { - warn("ignoring FF field with report_count < 2"); - continue; - } - - if (field->logical_maximum == field->logical_minimum) { - warn("ignoring FF field with logical_maximum == logical_minimum"); - continue; - } - - if (tmff->report && tmff->report != report) { - warn("ignoring FF field in other report"); - continue; - } - - if (tmff->ff_field && tmff->ff_field != field) { - warn("ignoring duplicate FF field"); - continue; - } - - tmff->report = report; - tmff->ff_field = field; - - for (i = 0; i < ARRAY_SIZE(devices); i++) { - if (input_dev->id.vendor == devices[i].idVendor && - input_dev->id.product == devices[i].idProduct) { - ff_bits = devices[i].ff; - break; - } - } - - for (i = 0; ff_bits[i] >= 0; i++) - set_bit(ff_bits[i], input_dev->ffbit); - - break; - - default: - warn("ignoring unknown output usage %08x", field->usage[0].hid); - continue; - } - } - } - - if (!tmff->report) { - err("cant find FF field in output reports\n"); - error = -ENODEV; - goto fail; - } - - error = input_ff_create_memless(input_dev, tmff, hid_tmff_play); - if (error) - goto fail; - - info("Force feedback for ThrustMaster devices by Zinx Verituse "); - return 0; - - fail: - kfree(tmff); - return error; -} - diff --git a/include/linux/hid.h b/include/linux/hid.h index 63b80806720..8266e50637b 100644 --- a/include/linux/hid.h +++ b/include/linux/hid.h @@ -760,7 +760,6 @@ void usbhid_set_leds(struct hid_device *hid); #ifdef CONFIG_HID_FF int hid_ff_init(struct hid_device *hid); -int hid_tmff_init(struct hid_device *hid); int hid_zpff_init(struct hid_device *hid); #ifdef CONFIG_HID_PID int hid_pidff_init(struct hid_device *hid); -- cgit v1.2.3-70-g09d2 From 987fbc1f7d446f4bf7063d3b756ae29db80be75e Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Thu, 18 Sep 2008 12:23:32 +0200 Subject: HID: move zeroplus FF processing Signed-off-by: Jiri Slaby Signed-off-by: Jiri Kosina --- drivers/hid/Kconfig | 8 +++ drivers/hid/Makefile | 1 + drivers/hid/hid-core.c | 2 + drivers/hid/hid-dummy.c | 3 + drivers/hid/hid-ids.h | 2 + drivers/hid/hid-zpff.c | 162 ++++++++++++++++++++++++++++++++++++++++++ drivers/hid/usbhid/Kconfig | 8 --- drivers/hid/usbhid/Makefile | 3 - drivers/hid/usbhid/hid-ff.c | 4 -- drivers/hid/usbhid/hid-zpff.c | 107 ---------------------------- include/linux/hid.h | 1 - 11 files changed, 178 insertions(+), 123 deletions(-) create mode 100644 drivers/hid/hid-zpff.c delete mode 100644 drivers/hid/usbhid/hid-zpff.c (limited to 'drivers/hid/Kconfig') diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index 78e3ba9504f..fc4f80c4006 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -252,6 +252,14 @@ config THRUSTMASTER_FF Say Y here if you have a THRUSTMASTER FireStore Dual Power 2 or a THRUSTMASTER Ferrari GT Rumble Force or Force Feedback Wheel. +config ZEROPLUS_FF + tristate "Zeroplus based game controller support" + default m + depends on USB_HID + select INPUT_FF_MEMLESS + help + Say Y here if you have a Zeroplus based game controller. + endmenu endif # HID_SUPPORT diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile index 9bd6daf6aaa..767f2950071 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile @@ -38,6 +38,7 @@ obj-$(CONFIG_HID_SAMSUNG) += hid-samsung.o obj-$(CONFIG_HID_SONY) += hid-sony.o obj-$(CONFIG_HID_SUNPLUS) += hid-sunplus.o obj-$(CONFIG_THRUSTMASTER_FF) += hid-tmff.o +obj-$(CONFIG_ZEROPLUS_FF) += hid-zpff.o obj-$(CONFIG_USB_HID) += usbhid/ obj-$(CONFIG_USB_MOUSE) += usbhid/ diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index b0996ff1462..5a23077175e 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1530,6 +1530,8 @@ static const struct hid_device_id hid_ignore_list[] = { { HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_1_PHIDGETSERVO_20) }, { HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_8_8_4_IF_KIT) }, { HID_USB_DEVICE(USB_VENDOR_ID_YEALINK, USB_DEVICE_ID_YEALINK_P1K_P4K_B2K) }, + { HID_USB_DEVICE(USB_VENDOR_ID_ZEROPLUS, 0x0005) }, + { HID_USB_DEVICE(USB_VENDOR_ID_ZEROPLUS, 0x0030) }, { } }; diff --git a/drivers/hid/hid-dummy.c b/drivers/hid/hid-dummy.c index ae122a122fa..54d1fb6fd4d 100644 --- a/drivers/hid/hid-dummy.c +++ b/drivers/hid/hid-dummy.c @@ -58,6 +58,9 @@ static int __init hid_dummy_init(void) #ifdef CONFIG_THRUSTMASTER_FF_MODULE HID_COMPAT_CALL_DRIVER(thrustmaster); #endif +#ifdef CONFIG_ZEROPLUS_FF_MODULE + HID_COMPAT_CALL_DRIVER(zeroplus); +#endif return -EIO; } diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index b8cc0196ec0..e68b6d9bcd1 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -388,6 +388,8 @@ #define USB_VENDOR_ID_YEALINK 0x6993 #define USB_DEVICE_ID_YEALINK_P1K_P4K_B2K 0xb001 +#define USB_VENDOR_ID_ZEROPLUS 0x0c12 + #define USB_VENDOR_ID_KYE 0x0458 #define USB_DEVICE_ID_KYE_GPEN_560 0x5003 diff --git a/drivers/hid/hid-zpff.c b/drivers/hid/hid-zpff.c new file mode 100644 index 00000000000..9ed04ee9d64 --- /dev/null +++ b/drivers/hid/hid-zpff.c @@ -0,0 +1,162 @@ +/* + * Force feedback support for Zeroplus based devices + * + * Copyright (c) 2005, 2006 Anssi Hannula + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include +#include +#include + +#include "hid-ids.h" + +#include "usbhid/usbhid.h" + +struct zpff_device { + struct hid_report *report; +}; + +static int zpff_play(struct input_dev *dev, void *data, + struct ff_effect *effect) +{ + struct hid_device *hid = input_get_drvdata(dev); + struct zpff_device *zpff = data; + int left, right; + + /* + * The following is specified the other way around in the Zeroplus + * datasheet but the order below is correct for the XFX Executioner; + * however it is possible that the XFX Executioner is an exception + */ + + left = effect->u.rumble.strong_magnitude; + right = effect->u.rumble.weak_magnitude; + dbg_hid("called with 0x%04x 0x%04x\n", left, right); + + left = left * 0x7f / 0xffff; + right = right * 0x7f / 0xffff; + + zpff->report->field[2]->value[0] = left; + zpff->report->field[3]->value[0] = right; + dbg_hid("running with 0x%02x 0x%02x\n", left, right); + usbhid_submit_report(hid, zpff->report, USB_DIR_OUT); + + return 0; +} + +static int zpff_init(struct hid_device *hid) +{ + struct zpff_device *zpff; + struct hid_report *report; + struct hid_input *hidinput = list_entry(hid->inputs.next, + struct hid_input, list); + struct list_head *report_list = + &hid->report_enum[HID_OUTPUT_REPORT].report_list; + struct input_dev *dev = hidinput->input; + int error; + + if (list_empty(report_list)) { + printk(KERN_ERR "hid-zpff: no output report found\n"); + return -ENODEV; + } + + report = list_entry(report_list->next, struct hid_report, list); + + if (report->maxfield < 4) { + printk(KERN_ERR "hid-zpff: not enough fields in report\n"); + return -ENODEV; + } + + zpff = kzalloc(sizeof(struct zpff_device), GFP_KERNEL); + if (!zpff) + return -ENOMEM; + + set_bit(FF_RUMBLE, dev->ffbit); + + error = input_ff_create_memless(dev, zpff, zpff_play); + if (error) { + kfree(zpff); + return error; + } + + zpff->report = report; + zpff->report->field[0]->value[0] = 0x00; + zpff->report->field[1]->value[0] = 0x02; + zpff->report->field[2]->value[0] = 0x00; + zpff->report->field[3]->value[0] = 0x00; + usbhid_submit_report(hid, zpff->report, USB_DIR_OUT); + + printk(KERN_INFO "Force feedback for Zeroplus based devices by " + "Anssi Hannula \n"); + + return 0; +} + +static int zp_probe(struct hid_device *hdev, const struct hid_device_id *id) +{ + int ret; + + ret = hid_parse(hdev); + if (ret) { + dev_err(&hdev->dev, "parse failed\n"); + goto err; + } + + ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT & ~HID_CONNECT_FF); + if (ret) { + dev_err(&hdev->dev, "hw start failed\n"); + goto err; + } + + zpff_init(hdev); + + return 0; +err: + return ret; +} + +static const struct hid_device_id zp_devices[] = { + { HID_USB_DEVICE(USB_VENDOR_ID_ZEROPLUS, 0x0005) }, + { HID_USB_DEVICE(USB_VENDOR_ID_ZEROPLUS, 0x0030) }, + { } +}; +MODULE_DEVICE_TABLE(hid, zp_devices); + +static struct hid_driver zp_driver = { + .name = "zeroplus", + .id_table = zp_devices, + .probe = zp_probe, +}; + +static int zp_init(void) +{ + return hid_register_driver(&zp_driver); +} + +static void zp_exit(void) +{ + hid_unregister_driver(&zp_driver); +} + +module_init(zp_init); +module_exit(zp_exit); +MODULE_LICENSE("GPL"); + +HID_COMPAT_LOAD_DRIVER(zeroplus); diff --git a/drivers/hid/usbhid/Kconfig b/drivers/hid/usbhid/Kconfig index c236fb3deb5..3cfc076f5f7 100644 --- a/drivers/hid/usbhid/Kconfig +++ b/drivers/hid/usbhid/Kconfig @@ -44,14 +44,6 @@ config HID_PID feedback for it. Microsoft Sidewinder Force Feedback 2 is one of such devices. -config ZEROPLUS_FF - bool "Zeroplus based game controller support" - depends on HID_FF - select INPUT_FF_MEMLESS if USB_HID - help - Say Y here if you have a Zeroplus based game controller and want to - enable force feedback for it. - config USB_HIDDEV bool "/dev/hiddev raw HID device support" depends on USB_HID diff --git a/drivers/hid/usbhid/Makefile b/drivers/hid/usbhid/Makefile index dd3b8634800..5c460fcdd75 100644 --- a/drivers/hid/usbhid/Makefile +++ b/drivers/hid/usbhid/Makefile @@ -13,9 +13,6 @@ endif ifeq ($(CONFIG_HID_PID),y) usbhid-objs += hid-pidff.o endif -ifeq ($(CONFIG_ZEROPLUS_FF),y) - usbhid-objs += hid-zpff.o -endif ifeq ($(CONFIG_HID_FF),y) usbhid-objs += hid-ff.o endif diff --git a/drivers/hid/usbhid/hid-ff.c b/drivers/hid/usbhid/hid-ff.c index ed3a869d54e..eca01a6fda5 100644 --- a/drivers/hid/usbhid/hid-ff.c +++ b/drivers/hid/usbhid/hid-ff.c @@ -50,10 +50,6 @@ struct hid_ff_initializer { * be a PID device */ static struct hid_ff_initializer inits[] = { -#ifdef CONFIG_ZEROPLUS_FF - { 0xc12, 0x0005, hid_zpff_init }, - { 0xc12, 0x0030, hid_zpff_init }, -#endif { 0, 0, hid_pidff_init} /* Matches anything */ }; diff --git a/drivers/hid/usbhid/hid-zpff.c b/drivers/hid/usbhid/hid-zpff.c deleted file mode 100644 index 5a688274f6a..00000000000 --- a/drivers/hid/usbhid/hid-zpff.c +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Force feedback support for Zeroplus based devices - * - * Copyright (c) 2005, 2006 Anssi Hannula - */ - -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - - -#include -#include -#include -#include "usbhid.h" - -struct zpff_device { - struct hid_report *report; -}; - -static int hid_zpff_play(struct input_dev *dev, void *data, - struct ff_effect *effect) -{ - struct hid_device *hid = input_get_drvdata(dev); - struct zpff_device *zpff = data; - int left, right; - - /* - * The following is specified the other way around in the Zeroplus - * datasheet but the order below is correct for the XFX Executioner; - * however it is possible that the XFX Executioner is an exception - */ - - left = effect->u.rumble.strong_magnitude; - right = effect->u.rumble.weak_magnitude; - dbg_hid("called with 0x%04x 0x%04x\n", left, right); - - left = left * 0x7f / 0xffff; - right = right * 0x7f / 0xffff; - - zpff->report->field[2]->value[0] = left; - zpff->report->field[3]->value[0] = right; - dbg_hid("running with 0x%02x 0x%02x\n", left, right); - usbhid_submit_report(hid, zpff->report, USB_DIR_OUT); - - return 0; -} - -int hid_zpff_init(struct hid_device *hid) -{ - struct zpff_device *zpff; - struct hid_report *report; - struct hid_input *hidinput = list_entry(hid->inputs.next, - struct hid_input, list); - struct list_head *report_list = - &hid->report_enum[HID_OUTPUT_REPORT].report_list; - struct input_dev *dev = hidinput->input; - int error; - - if (list_empty(report_list)) { - printk(KERN_ERR "hid-zpff: no output report found\n"); - return -ENODEV; - } - - report = list_entry(report_list->next, struct hid_report, list); - - if (report->maxfield < 4) { - printk(KERN_ERR "hid-zpff: not enough fields in report\n"); - return -ENODEV; - } - - zpff = kzalloc(sizeof(struct zpff_device), GFP_KERNEL); - if (!zpff) - return -ENOMEM; - - set_bit(FF_RUMBLE, dev->ffbit); - - error = input_ff_create_memless(dev, zpff, hid_zpff_play); - if (error) { - kfree(zpff); - return error; - } - - zpff->report = report; - zpff->report->field[0]->value[0] = 0x00; - zpff->report->field[1]->value[0] = 0x02; - zpff->report->field[2]->value[0] = 0x00; - zpff->report->field[3]->value[0] = 0x00; - usbhid_submit_report(hid, zpff->report, USB_DIR_OUT); - - printk(KERN_INFO "Force feedback for Zeroplus based devices by " - "Anssi Hannula \n"); - - return 0; -} diff --git a/include/linux/hid.h b/include/linux/hid.h index 8266e50637b..0773ba6a66f 100644 --- a/include/linux/hid.h +++ b/include/linux/hid.h @@ -760,7 +760,6 @@ void usbhid_set_leds(struct hid_device *hid); #ifdef CONFIG_HID_FF int hid_ff_init(struct hid_device *hid); -int hid_zpff_init(struct hid_device *hid); #ifdef CONFIG_HID_PID int hid_pidff_init(struct hid_device *hid); #else -- cgit v1.2.3-70-g09d2 From a48c65b35a6f993aec13d18a37f6ea71fbcb0c06 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 14 Oct 2008 22:41:43 +0200 Subject: HID: add support for Bright ABNT2 brazilian device This keyboard needs to reset the LEDS during probe. Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Jiri Kosina --- drivers/hid/Kconfig | 7 +++++ drivers/hid/Makefile | 1 + drivers/hid/hid-bright.c | 71 ++++++++++++++++++++++++++++++++++++++++++++++++ drivers/hid/hid-core.c | 1 + drivers/hid/hid-dummy.c | 3 ++ drivers/hid/hid-ids.h | 3 ++ 6 files changed, 86 insertions(+) create mode 100644 drivers/hid/hid-bright.c (limited to 'drivers/hid/Kconfig') diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index fc4f80c4006..6d7753be44f 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -110,6 +110,13 @@ config HID_BELKIN ---help--- Support for Belkin Flip KVM and Wireless keyboard. +config HID_BRIGHT + tristate "Bright" + default m + depends on USB_HID + ---help--- + Support for Bright ABNT-2 keyboard. + config HID_CHERRY tristate "Cherry" default m diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile index 767f2950071..b09e43e7413 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile @@ -23,6 +23,7 @@ endif obj-$(CONFIG_HID_A4TECH) += hid-a4tech.o obj-$(CONFIG_HID_APPLE) += hid-apple.o obj-$(CONFIG_HID_BELKIN) += hid-belkin.o +obj-$(CONFIG_HID_BRIGHT) += hid-bright.o obj-$(CONFIG_HID_CHERRY) += hid-cherry.o obj-$(CONFIG_HID_CHICONY) += hid-chicony.o obj-$(CONFIG_HID_CYPRESS) += hid-cypress.o diff --git a/drivers/hid/hid-bright.c b/drivers/hid/hid-bright.c new file mode 100644 index 00000000000..38517a117df --- /dev/null +++ b/drivers/hid/hid-bright.c @@ -0,0 +1,71 @@ +/* + * HID driver for some bright "special" devices + * + * Copyright (c) 2008 Mauro Carvalho Chehab + * + * Based on hid-dell driver + */ + +/* + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + */ + +#include +#include +#include + +#include "hid-ids.h" + +static int bright_probe(struct hid_device *hdev, const struct hid_device_id *id) +{ + int ret; + + ret = hid_parse(hdev); + if (ret) { + dev_err(&hdev->dev, "parse failed\n"); + goto err_free; + } + + ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); + if (ret) { + dev_err(&hdev->dev, "hw start failed\n"); + goto err_free; + } + + usbhid_set_leds(hdev); + + return 0; +err_free: + return ret; +} + +static const struct hid_device_id bright_devices[] = { + { HID_USB_DEVICE(USB_VENDOR_ID_BRIGHT, USB_DEVICE_ID_BRIGHT_ABNT2) }, + { } +}; +MODULE_DEVICE_TABLE(hid, bright_devices); + +static struct hid_driver bright_driver = { + .name = "bright", + .id_table = bright_devices, + .probe = bright_probe, +}; + +static int bright_init(void) +{ + return hid_register_driver(&bright_driver); +} + +static void bright_exit(void) +{ + hid_unregister_driver(&bright_driver); +} + +module_init(bright_init); +module_exit(bright_exit); +MODULE_LICENSE("GPL"); + +HID_COMPAT_LOAD_DRIVER(bright); diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 599846052fe..2cba490fcd5 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1253,6 +1253,7 @@ static const struct hid_device_id hid_blacklist[] = { { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY) }, { HID_USB_DEVICE(USB_VENDOR_ID_AVERMEDIA, USB_DEVICE_ID_AVER_FM_MR800) }, { HID_USB_DEVICE(USB_VENDOR_ID_BELKIN, USB_DEVICE_ID_FLIP_KVM) }, + { HID_USB_DEVICE(USB_VENDOR_ID_BRIGHT, USB_DEVICE_ID_BRIGHT_ABNT2) }, { HID_USB_DEVICE(USB_VENDOR_ID_CHERRY, USB_DEVICE_ID_CHERRY_CYMOTION) }, { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_TACTICAL_PAD) }, { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_1) }, diff --git a/drivers/hid/hid-dummy.c b/drivers/hid/hid-dummy.c index 54d1fb6fd4d..e148f86fb58 100644 --- a/drivers/hid/hid-dummy.c +++ b/drivers/hid/hid-dummy.c @@ -13,6 +13,9 @@ static int __init hid_dummy_init(void) #ifdef CONFIG_HID_BELKIN_MODULE HID_COMPAT_CALL_DRIVER(belkin); #endif +#ifdef CONFIG_HID_BRIGHT_MODULE + HID_COMPAT_CALL_DRIVER(bright); +#endif #ifdef CONFIG_HID_CHERRY_MODULE HID_COMPAT_CALL_DRIVER(cherry); #endif diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 11afd33cbd6..aad9ed1b406 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -103,6 +103,9 @@ #define USB_VENDOR_ID_BELKIN 0x050d #define USB_DEVICE_ID_FLIP_KVM 0x3201 +#define USB_VENDOR_ID_BRIGHT 0x1241 +#define USB_DEVICE_ID_BRIGHT_ABNT2 0x1503 + #define USB_VENDOR_ID_BERKSHIRE 0x0c98 #define USB_DEVICE_ID_BERKSHIRE_PCWD 0x1140 -- cgit v1.2.3-70-g09d2 From 9be7bbd54df3c9c393ccd19acc49f90c517d1291 Mon Sep 17 00:00:00 2001 From: Jiri Kosina Date: Tue, 14 Oct 2008 23:37:33 +0200 Subject: HID: build drivers for all quirky devices by default Once kernel configuration has CONFIG_HID turned on, let also all the specialized drivers for quirky devices to be built (unless CONFIG_EMBEDDED is specified), as usually users don't care that much which driver gives them the functionality, but when they want generic support, they probably want to have support for all the quirky devices as well. Signed-off-by: Jiri Kosina --- drivers/hid/Kconfig | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) (limited to 'drivers/hid/Kconfig') diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index 6d7753be44f..da64108de77 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -17,6 +17,25 @@ config HID tristate "Generic HID support" depends on INPUT default y + select HID_A4TECH if !EMBEDDED + select HID_APPLE if !EMBEDDED + select HID_BELKIN if !EMBEDDED + select HID_BRIGHT if !EMBEDDED + select HID_CHERRY if !EMBEDDED + select HID_CHICONY if !EMBEDDED + select HID_CYPRESS if !EMBEDDED + select HID_DELL if !EMBEDDED + select HID_EZKEY if !EMBEDDED + select HID_GYRATION if !EMBEDDED + select HID_LOGITECH if !EMBEDDED + select HID_MICROSOFT if !EMBEDDED + select HID_MONTEREY if !EMBEDDED + select HID_PANTHERLORD if !EMBEDDED + select HID_PETALYNX if !EMBEDDED + select HID_SAMSUNG if !EMBEDDED + select HID_SONY if !EMBEDDED + select HID_SUNPLUS if !EMBEDDED + ---help--- A human interface device (HID) is a type of computer device that interacts directly with and takes input from humans. The term "HID" -- cgit v1.2.3-70-g09d2