diff options
Diffstat (limited to 'drivers')
41 files changed, 5012 insertions, 2770 deletions
diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index cacf89e65af..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" @@ -67,4 +86,206 @@ config HIDRAW 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 lose is modules autoloading. + + 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 + 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_BELKIN + tristate "Belkin" + default m + depends on USB_HID + ---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 + depends on USB_HID + ---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 + depends on USB_HID + ---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 + depends on USB_HID + ---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 + depends on USB_HID + ---help--- + 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 + depends on USB_HID + ---help--- + 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_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 + depends on USB_HID + ---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_SONY + tristate "Sony" + default m + depends on USB_HID + ---help--- + Support for Sony PS3 controller. + +config HID_SUNPLUS + tristate "Sunplus" + default m + depends on USB_HID + ---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. + +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 275dc522c73..b09e43e7413 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile @@ -1,13 +1,46 @@ # # Makefile for the HID driver # -hid-objs := hid-core.o hid-input.o hid-input-quirks.o +hid-objs := hid-core.o hid-input.o 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 + +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 +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 +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 +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 +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/ obj-$(CONFIG_USB_KBD) += usbhid/ diff --git a/drivers/hid/hid-a4tech.c b/drivers/hid/hid-a4tech.c new file mode 100644 index 00000000000..ebca00e6c10 --- /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 <vojtech@suse.cz> + * Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> 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 <linux/device.h> +#include <linux/input.h> +#include <linux/hid.h> +#include <linux/module.h> + +#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, HID_CONNECT_DEFAULT); + 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-apple.c b/drivers/hid/hid-apple.c new file mode 100644 index 00000000000..fd7f896b34f --- /dev/null +++ b/drivers/hid/hid-apple.c @@ -0,0 +1,484 @@ +/* + * USB HID quirks support for Linux + * + * Copyright (c) 1999 Andreas Gal + * Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz> + * Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc + * Copyright (c) 2006-2007 Jiri Kosina + * Copyright (c) 2007 Paul Walmsley + * Copyright (c) 2008 Jiri Slaby <jirislaby@gmail.com> + */ + +/* + * 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 <linux/device.h> +#include <linux/hid.h> +#include <linux/module.h> +#include <linux/usb.h> + +#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; + unsigned int connect_mask = HID_CONNECT_DEFAULT; + 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); + + ret = hid_parse(hdev); + if (ret) { + dev_err(&hdev->dev, "parse failed\n"); + goto err_free; + } + + if (quirks & APPLE_HIDDEV) + connect_mask |= HID_CONNECT_HIDDEV_FORCE; + if (quirks & APPLE_IGNORE_HIDINPUT) + connect_mask &= ~HID_CONNECT_HIDINPUT; + + ret = hid_hw_start(hdev, connect_mask); + 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_ATV_IRCONTROL), + .driver_data = APPLE_HIDDEV | APPLE_IGNORE_HIDINPUT }, + { 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 | APPLE_RDESC_JIS }, + { 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 |