Merge branch 'upstream' into for-linus
Jiri Kosina [Wed, 19 May 2010 12:04:49 +0000 (14:04 +0200)]
Conflicts:
drivers/hid/hid-wacom.c

16 files changed:
Documentation/ABI/testing/sysfs-wacom [new file with mode: 0644]
drivers/hid/Kconfig
drivers/hid/Makefile
drivers/hid/hid-3m-pct.c
drivers/hid/hid-core.c
drivers/hid/hid-ids.h
drivers/hid/hid-lg.c
drivers/hid/hid-samsung.c
drivers/hid/hid-topseed.c
drivers/hid/hid-wacom.c
drivers/hid/hid-zydacron.c [new file with mode: 0644]
drivers/hid/hidraw.c
drivers/hid/usbhid/hid-core.c
drivers/hid/usbhid/hid-quirks.c
drivers/hid/usbhid/usbkbd.c
include/linux/hid.h

diff --git a/Documentation/ABI/testing/sysfs-wacom b/Documentation/ABI/testing/sysfs-wacom
new file mode 100644 (file)
index 0000000..1517976
--- /dev/null
@@ -0,0 +1,10 @@
+What:          /sys/class/hidraw/hidraw*/device/speed
+Date:          April 2010
+Kernel Version:        2.6.35
+Contact:       linux-bluetooth@vger.kernel.org
+Description:
+               The /sys/class/hidraw/hidraw*/device/speed file controls
+               reporting speed of wacom bluetooth tablet. Reading from
+               this file returns 1 if tablet reports in high speed mode
+               or 0 otherwise. Writing to this file one of these values
+               switches reporting speed.
index 71d4c07..ac8e12d 100644 (file)
@@ -273,7 +273,7 @@ config HID_SAMSUNG
        depends on USB_HID
        default !EMBEDDED
        ---help---
-       Support for Samsung InfraRed remote control.
+       Support for Samsung InfraRed remote control or keyboards.
 
 config HID_SONY
        tristate "Sony" if EMBEDDED
@@ -332,7 +332,7 @@ config HID_TOPSEED
        depends on USB_HID
        default !EMBEDDED
        ---help---
-       Say Y if you have a TopSeed Cyberlink remote control.
+       Say Y if you have a TopSeed Cyberlink or BTC Emprex remote control.
 
 config HID_THRUSTMASTER
        tristate "ThrustMaster devices support" if EMBEDDED
@@ -357,6 +357,14 @@ config HID_WACOM
        ---help---
        Support for Wacom Graphire Bluetooth tablet.
 
+config HID_WACOM_POWER_SUPPLY
+       bool "Wacom Bluetooth devices power supply status support"
+       depends on HID_WACOM
+       select POWER_SUPPLY
+       ---help---
+         Say Y here if you want to enable power supply status monitoring for
+         Wacom Bluetooth devices.
+
 config HID_ZEROPLUS
        tristate "Zeroplus based game controller support" if EMBEDDED
        depends on USB_HID
@@ -372,6 +380,13 @@ config ZEROPLUS_FF
          Say Y here if you have a Zeroplus based game controller and want
          to have force feedback support for it.
 
+config HID_ZYDACRON
+       tristate "Zydacron remote control support" if EMBEDDED
+       depends on USB_HID
+       default !EMBEDDED
+       ---help---
+       Support for Zydacron remote control.
+
 endmenu
 
 endif # HID_SUPPORT
index 0b2618f..d1f1b44 100644 (file)
@@ -54,6 +54,7 @@ obj-$(CONFIG_HID_THRUSTMASTER)        += hid-tmff.o
 obj-$(CONFIG_HID_TOPSEED)      += hid-topseed.o
 obj-$(CONFIG_HID_TWINHAN)      += hid-twinhan.o
 obj-$(CONFIG_HID_ZEROPLUS)     += hid-zpff.o
+obj-$(CONFIG_HID_ZYDACRON)     += hid-zydacron.o
 obj-$(CONFIG_HID_WACOM)                += hid-wacom.o
 
 obj-$(CONFIG_USB_HID)          += usbhid/
index c31e0be..2a0d56b 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  HID driver for 3M PCT multitouch panels
  *
- *  Copyright (c) 2009 Stephane Chatty <chatty@enac.fr>
+ *  Copyright (c) 2009-2010 Stephane Chatty <chatty@enac.fr>
  *
  */
 
@@ -25,7 +25,7 @@ MODULE_LICENSE("GPL");
 #include "hid-ids.h"
 
 struct mmm_finger {
-       __s32 x, y;
+       __s32 x, y, w, h;
        __u8 rank;
        bool touch, valid;
 };
@@ -82,7 +82,18 @@ static int mmm_input_mapping(struct hid_device *hdev, struct hid_input *hi,
                        /* touchscreen emulation */
                        hid_map_usage(hi, usage, bit, max, EV_KEY, BTN_TOUCH);
                        return 1;
+               case HID_DG_WIDTH:
+                       hid_map_usage(hi, usage, bit, max,
+                                       EV_ABS, ABS_MT_TOUCH_MAJOR);
+                       return 1;
+               case HID_DG_HEIGHT:
+                       hid_map_usage(hi, usage, bit, max,
+                                       EV_ABS, ABS_MT_TOUCH_MINOR);
+                       input_set_abs_params(hi->input, ABS_MT_ORIENTATION,
+                                       1, 1, 0, 0);
+                       return 1;
                case HID_DG_CONTACTID:
+                       field->logical_maximum = 59;
                        hid_map_usage(hi, usage, bit, max,
                                        EV_ABS, ABS_MT_TRACKING_ID);
                        return 1;
@@ -128,9 +139,15 @@ static void mmm_filter_event(struct mmm_data *md, struct input_dev *input)
                        /* this finger is just placeholder data, ignore */
                } else if (f->touch) {
                        /* this finger is on the screen */
+                       int wide = (f->w > f->h);
                        input_event(input, EV_ABS, ABS_MT_TRACKING_ID, i);
                        input_event(input, EV_ABS, ABS_MT_POSITION_X, f->x);
                        input_event(input, EV_ABS, ABS_MT_POSITION_Y, f->y);
+                       input_event(input, EV_ABS, ABS_MT_ORIENTATION, wide);
+                       input_event(input, EV_ABS, ABS_MT_TOUCH_MAJOR,
+                                               wide ? f->w : f->h);
+                       input_event(input, EV_ABS, ABS_MT_TOUCH_MINOR,
+                                               wide ? f->h : f->w);
                        input_mt_sync(input);
                        /*
                         * touchscreen emulation: maintain the age rank
@@ -197,6 +214,14 @@ static int mmm_event(struct hid_device *hid, struct hid_field *field,
                case HID_DG_CONFIDENCE:
                        md->valid = value;
                        break;
+               case HID_DG_WIDTH:
+                       if (md->valid)
+                               md->f[md->curid].w = value;
+                       break;
+               case HID_DG_HEIGHT:
+                       if (md->valid)
+                               md->f[md->curid].h = value;
+                       break;
                case HID_DG_CONTACTID:
                        if (md->valid) {
                                md->curid = value;
@@ -255,6 +280,7 @@ static void mmm_remove(struct hid_device *hdev)
 
 static const struct hid_device_id mmm_devices[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_3M, USB_DEVICE_ID_3M1968) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_3M, USB_DEVICE_ID_3M2256) },
        { }
 };
 MODULE_DEVICE_TABLE(hid, mmm_devices);
@@ -287,5 +313,4 @@ static void __exit mmm_exit(void)
 
 module_init(mmm_init);
 module_exit(mmm_exit);
-MODULE_LICENSE("GPL");
 
index 143e788..69fdf1e 100644 (file)
@@ -653,10 +653,9 @@ int hid_parse_report(struct hid_device *device, __u8 *start,
        if (device->driver->report_fixup)
                device->driver->report_fixup(device, start, size);
 
-       device->rdesc = kmalloc(size, GFP_KERNEL);
+       device->rdesc = kmemdup(start, size, GFP_KERNEL);
        if (device->rdesc == NULL)
                return -ENOMEM;
-       memcpy(device->rdesc, start, size);
        device->rsize = size;
 
        parser = vmalloc(sizeof(struct hid_parser));
@@ -940,13 +939,8 @@ static void hid_output_field(struct hid_field *field, __u8 *data)
        unsigned count = field->report_count;
        unsigned offset = field->report_offset;
        unsigned size = field->report_size;
-       unsigned bitsused = offset + count * size;
        unsigned n;
 
-       /* make sure the unused bits in the last byte are zeros */
-       if (count > 0 && size > 0 && (bitsused % 8) != 0)
-               data[(bitsused-1)/8] &= (1 << (bitsused % 8)) - 1;
-
        for (n = 0; n < count; n++) {
                if (field->logical_minimum < 0) /* signed values */
                        implement(data, offset + n * size, size, s32ton(field->value[n], size));
@@ -966,6 +960,7 @@ void hid_output_report(struct hid_report *report, __u8 *data)
        if (report->id > 0)
                *data++ = report->id;
 
+       memset(data, 0, ((report->size - 1) >> 3) + 1);
        for (n = 0; n < report->maxfield; n++)
                hid_output_field(report->field[n], data);
 }
@@ -1167,6 +1162,8 @@ int hid_connect(struct hid_device *hdev, unsigned int connect_mask)
        unsigned int i;
        int len;
 
+       if (hdev->quirks & HID_QUIRK_HIDDEV_FORCE)
+               connect_mask |= (HID_CONNECT_HIDDEV_FORCE | HID_CONNECT_HIDDEV);
        if (hdev->bus != BUS_USB)
                connect_mask &= ~HID_CONNECT_HIDDEV;
        if (hid_hiddev(hdev))
@@ -1246,6 +1243,7 @@ EXPORT_SYMBOL_GPL(hid_disconnect);
 /* a list of devices for which there is a specialized driver on HID bus */
 static const struct hid_device_id hid_blacklist[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_3M, USB_DEVICE_ID_3M1968) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_3M, USB_DEVICE_ID_3M2256) },
        { 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_ATV_IRCONTROL) },
@@ -1290,6 +1288,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_BELKIN, USB_DEVICE_ID_FLIP_KVM) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_BTC, USB_DEVICE_ID_BTC_EMPREX_REMOTE) },
        { HID_USB_DEVICE(USB_VENDOR_ID_CHERRY, USB_DEVICE_ID_CHERRY_CYMOTION) },
        { HID_USB_DEVICE(USB_VENDOR_ID_CHERRY, USB_DEVICE_ID_CHERRY_CYMOTION_SOLAR) },
        { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_TACTICAL_PAD) },
@@ -1343,6 +1342,7 @@ static const struct hid_device_id hid_blacklist[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH) },
        { HID_USB_DEVICE(USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_PIXART_IMAGING_INC_OPTICAL_TOUCH_SCREEN) },
        { HID_USB_DEVICE(USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_IR_REMOTE) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_WIRELESS_KBD_MOUSE) },
        { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER) },
        { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER) },
        { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_VAIO_VGX_MOUSE) },
@@ -1359,8 +1359,10 @@ static const struct hid_device_id hid_blacklist[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_TWINHAN, USB_DEVICE_ID_TWINHAN_IR_REMOTE) },
        { HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_SMARTJOY_PLUS) },
        { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_GRAPHIRE_BLUETOOTH) },
+       { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS4_BLUETOOTH) },
        { HID_USB_DEVICE(USB_VENDOR_ID_ZEROPLUS, 0x0005) },
        { HID_USB_DEVICE(USB_VENDOR_ID_ZEROPLUS, 0x0030) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_ZYDACRON, USB_DEVICE_ID_ZYDACRON_REMOTE_CONTROL) },
 
        { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_PRESENTER_8K_BT) },
        { }
@@ -1757,7 +1759,7 @@ int hid_add_device(struct hid_device *hdev)
 
        /* we need to kill them here, otherwise they will stay allocated to
         * wait for coming driver */
-       if (hid_ignore(hdev))
+       if (!(hdev->quirks & HID_QUIRK_NO_IGNORE) && hid_ignore(hdev))
                return -ENODEV;
 
        /* XXX hack, any other cleaner solution after the driver core
@@ -1765,11 +1767,12 @@ int hid_add_device(struct hid_device *hdev)
        dev_set_name(&hdev->dev, "%04X:%04X:%04X.%04X", hdev->bus,
                     hdev->vendor, hdev->product, atomic_inc_return(&id));
 
+       hid_debug_register(hdev, dev_name(&hdev->dev));
        ret = device_add(&hdev->dev);
        if (!ret)
                hdev->status |= HID_STAT_ADDED;
-
-       hid_debug_register(hdev, dev_name(&hdev->dev));
+       else
+               hid_debug_unregister(hdev);
 
        return ret;
 }
index 09d2764..d55b81d 100644 (file)
@@ -20,6 +20,7 @@
 
 #define USB_VENDOR_ID_3M               0x0596
 #define USB_DEVICE_ID_3M1968           0x0500
+#define USB_DEVICE_ID_3M2256           0x0502
 
 #define USB_VENDOR_ID_A4TECH           0x09da
 #define USB_DEVICE_ID_A4TECH_WCP32PU   0x0006
 #define USB_VENDOR_ID_BERKSHIRE                0x0c98
 #define USB_DEVICE_ID_BERKSHIRE_PCWD   0x1140
 
+#define USB_VENDOR_ID_BTC              0x046e
+#define USB_DEVICE_ID_BTC_EMPREX_REMOTE        0x5578
+
 #define USB_VENDOR_ID_CH               0x068e
 #define USB_DEVICE_ID_CH_PRO_PEDALS    0x00f2
 #define USB_DEVICE_ID_CH_COMBATSTICK   0x00f4
 
 #define USB_VENDOR_ID_DRAGONRISE       0x0079
 
+#define USB_VENDOR_ID_EGALAX           0x0EEF
+#define USB_DEVICE_ID_EGALAX_TOUCHCONTROLLER   0x0001
+
 #define USB_VENDOR_ID_ELO              0x04E7
 #define USB_DEVICE_ID_ELO_TS2700       0x0020
 
 
 #define USB_VENDOR_ID_SAMSUNG          0x0419
 #define USB_DEVICE_ID_SAMSUNG_IR_REMOTE        0x0001
+#define USB_DEVICE_ID_SAMSUNG_WIRELESS_KBD_MOUSE       0x0600
 
 #define USB_VENDOR_ID_SONY                     0x054c
 #define USB_DEVICE_ID_SONY_VAIO_VGX_MOUSE      0x024b
 
 #define USB_VENDOR_ID_WACOM            0x056a
 #define USB_DEVICE_ID_WACOM_GRAPHIRE_BLUETOOTH 0x81
+#define USB_DEVICE_ID_WACOM_INTUOS4_BLUETOOTH  0xbd
 
 #define USB_VENDOR_ID_WISEGROUP                0x0925
 #define USB_DEVICE_ID_SMARTJOY_PLUS    0x0005
 
 #define USB_VENDOR_ID_ZEROPLUS         0x0c12
 
+#define USB_VENDOR_ID_ZYDACRON 0x13EC
+#define USB_DEVICE_ID_ZYDACRON_REMOTE_CONTROL  0x0006
+
 #define USB_VENDOR_ID_KYE              0x0458
 #define USB_DEVICE_ID_KYE_ERGO_525V    0x0087
 #define USB_DEVICE_ID_KYE_GPEN_560     0x5003
index 3677c90..f6433d8 100644 (file)
@@ -126,6 +126,9 @@ static int lg_wireless_mapping(struct hid_input *hi, struct hid_usage *usage,
        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;
+       /* The following two entries are Playlist 1 and 2 on the MX3200 */
+       case 0x100f: lg_map_key_clear(KEY_FN_1);                break;
+       case 0x1010: lg_map_key_clear(KEY_FN_2);                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;
@@ -137,6 +140,7 @@ static int lg_wireless_mapping(struct hid_input *hi, struct hid_usage *usage,
        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 0x101c: lg_map_key_clear(KEY_CYCLEWINDOWS);        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;
@@ -147,6 +151,11 @@ static int lg_wireless_mapping(struct hid_input *hi, struct hid_usage *usage,
        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 0x102d: lg_map_key_clear(KEY_WWW);                 break;
+       /* The following two are 'Start/answer call' and 'End/reject call'
+          on the MX3200 */
+       case 0x1031: lg_map_key_clear(KEY_OK);                  break;
+       case 0x1032: lg_map_key_clear(KEY_CANCEL);              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;
index 510dd13..bda0fd6 100644 (file)
@@ -7,6 +7,18 @@
  *  Copyright (c) 2006-2007 Jiri Kosina
  *  Copyright (c) 2007 Paul Walmsley
  *  Copyright (c) 2008 Jiri Slaby
+ *  Copyright (c) 2010 Don Prince <dhprince.devel@yahoo.co.uk>
+ *
+ *
+ *  This driver supports several HID devices:
+ *
+ *  [0419:0001] Samsung IrDA remote controller (reports as Cypress USB Mouse).
+ *     various hid report fixups for different variants.
+ *
+ *  [0419:0600] Creative Desktop Wireless 6000 keyboard/mouse combo
+ *     several key mappings used from the consumer usage page
+ *     deviate from the USB HUT 1.12 standard.
+ *
  */
 
 /*
  */
 
 #include <linux/device.h>
+#include <linux/usb.h>
 #include <linux/hid.h>
 #include <linux/module.h>
 
 #include "hid-ids.h"
 
 /*
- * Samsung IrDA remote controller (reports as Cypress USB Mouse).
- *
  * There are several variants for 0419:0001:
  *
  * 1. 184 byte report descriptor
  * 4. 171 byte report descriptor
  * Report #3 has an array field with logical range 0..1 instead of 1..3.
  */
-static inline void samsung_dev_trace(struct hid_device *hdev,
+static inline void samsung_irda_dev_trace(struct hid_device *hdev,
                unsigned int rsize)
 {
        dev_info(&hdev->dev, "fixing up Samsung IrDA %d byte report "
                        "descriptor\n", rsize);
 }
 
-static void samsung_report_fixup(struct hid_device *hdev, __u8 *rdesc,
+static void samsung_irda_report_fixup(struct hid_device *hdev, __u8 *rdesc,
                unsigned int rsize)
 {
        if (rsize == 184 && rdesc[175] == 0x25 && rdesc[176] == 0x40 &&
                        rdesc[177] == 0x75 && rdesc[178] == 0x30 &&
                        rdesc[179] == 0x95 && rdesc[180] == 0x01 &&
                        rdesc[182] == 0x40) {
-               samsung_dev_trace(hdev, 184);
+               samsung_irda_dev_trace(hdev, 184);
                rdesc[176] = 0xff;
                rdesc[178] = 0x08;
                rdesc[180] = 0x06;
@@ -65,24 +76,80 @@ static void samsung_report_fixup(struct hid_device *hdev, __u8 *rdesc,
        } else
        if (rsize == 203 && rdesc[192] == 0x15 && rdesc[193] == 0x0 &&
                        rdesc[194] == 0x25 && rdesc[195] == 0x12) {
-               samsung_dev_trace(hdev, 203);
+               samsung_irda_dev_trace(hdev, 203);
                rdesc[193] = 0x1;
                rdesc[195] = 0xf;
        } else
        if (rsize == 135 && rdesc[124] == 0x15 && rdesc[125] == 0x0 &&
                        rdesc[126] == 0x25 && rdesc[127] == 0x11) {
-               samsung_dev_trace(hdev, 135);
+               samsung_irda_dev_trace(hdev, 135);
                rdesc[125] = 0x1;
                rdesc[127] = 0xe;
        } else
        if (rsize == 171 && rdesc[160] == 0x15 && rdesc[161] == 0x0 &&
                        rdesc[162] == 0x25 && rdesc[163] == 0x01) {
-               samsung_dev_trace(hdev, 171);
+               samsung_irda_dev_trace(hdev, 171);
                rdesc[161] = 0x1;
                rdesc[163] = 0x3;
        }
 }
 
+#define samsung_kbd_mouse_map_key_clear(c) \
+       hid_map_usage_clear(hi, usage, bit, max, EV_KEY, (c))
+
+static int samsung_kbd_mouse_input_mapping(struct hid_device *hdev,
+       struct hid_input *hi, struct hid_field *field, struct hid_usage *usage,
+       unsigned long **bit, int *max)
+{
+       struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
+       unsigned short ifnum = intf->cur_altsetting->desc.bInterfaceNumber;
+
+       if (1 != ifnum || HID_UP_CONSUMER != (usage->hid & HID_USAGE_PAGE))
+               return 0;
+
+       dbg_hid("samsung wireless keyboard/mouse input mapping event [0x%x]\n",
+               usage->hid & HID_USAGE);
+
+       switch (usage->hid & HID_USAGE) {
+       /* report 2 */
+       case 0x183: samsung_kbd_mouse_map_key_clear(KEY_MEDIA); break;
+       case 0x195: samsung_kbd_mouse_map_key_clear(KEY_EMAIL); break;
+       case 0x196: samsung_kbd_mouse_map_key_clear(KEY_CALC); break;
+       case 0x197: samsung_kbd_mouse_map_key_clear(KEY_COMPUTER); break;
+       case 0x22b: samsung_kbd_mouse_map_key_clear(KEY_SEARCH); break;
+       case 0x22c: samsung_kbd_mouse_map_key_clear(KEY_WWW); break;
+       case 0x22d: samsung_kbd_mouse_map_key_clear(KEY_BACK); break;
+       case 0x22e: samsung_kbd_mouse_map_key_clear(KEY_FORWARD); break;
+       case 0x22f: samsung_kbd_mouse_map_key_clear(KEY_FAVORITES); break;
+       case 0x230: samsung_kbd_mouse_map_key_clear(KEY_REFRESH); break;
+       case 0x231: samsung_kbd_mouse_map_key_clear(KEY_STOP); break;
+       default:
+               return 0;
+       }
+
+       return 1;
+}
+
+static void samsung_report_fixup(struct hid_device *hdev, __u8 *rdesc,
+       unsigned int rsize)
+{
+       if (USB_DEVICE_ID_SAMSUNG_IR_REMOTE == hdev->product)
+               samsung_irda_report_fixup(hdev, rdesc, rsize);
+}
+
+static int samsung_input_mapping(struct hid_device *hdev, struct hid_input *hi,
+       struct hid_field *field, struct hid_usage *usage,
+       unsigned long **bit, int *max)
+{
+       int ret = 0;
+
+       if (USB_DEVICE_ID_SAMSUNG_WIRELESS_KBD_MOUSE == hdev->product)
+               ret = samsung_kbd_mouse_input_mapping(hdev,
+                       hi, field, usage, bit, max);
+
+       return ret;
+}
+
 static int samsung_probe(struct hid_device *hdev,
                const struct hid_device_id *id)
 {
@@ -95,10 +162,12 @@ static int samsung_probe(struct hid_device *hdev,
                goto err_free;
        }
 
-       if (hdev->rsize == 184) {
-               /* disable hidinput, force hiddev */
-               cmask = (cmask & ~HID_CONNECT_HIDINPUT) |
-                       HID_CONNECT_HIDDEV_FORCE;
+       if (USB_DEVICE_ID_SAMSUNG_IR_REMOTE == hdev->product) {
+               if (hdev->rsize == 184) {
+                       /* disable hidinput, force hiddev */
+                       cmask = (cmask & ~HID_CONNECT_HIDINPUT) |
+                               HID_CONNECT_HIDDEV_FORCE;
+               }
        }
 
        ret = hid_hw_start(hdev, cmask);
@@ -114,6 +183,7 @@ err_free:
 
 static const struct hid_device_id samsung_devices[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_IR_REMOTE) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_WIRELESS_KBD_MOUSE) },
        { }
 };
 MODULE_DEVICE_TABLE(hid, samsung_devices);
@@ -122,6 +192,7 @@ static struct hid_driver samsung_driver = {
        .name = "samsung",
        .id_table = samsung_devices,
        .report_fixup = samsung_report_fixup,
+       .input_mapping = samsung_input_mapping,
        .probe = samsung_probe,
 };
 
index 6925eda..2eebdcc 100644 (file)
@@ -3,6 +3,9 @@
  *
  *  Copyright (c) 2008 Lev Babiev
  *  based on hid-cherry driver
+ *
+ *  Modified to also support BTC "Emprex 3009URF III Vista MCE Remote" by
+ *  Wayne Thomas 2010.
  */
 
 /*
@@ -24,23 +27,29 @@ static int ts_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) != 0x0ffbc0000)
+       if ((usage->hid & HID_USAGE_PAGE) != HID_UP_LOGIVENDOR)
                return 0;
 
        switch (usage->hid & HID_USAGE) {
-        case 0x00d: ts_map_key_clear(KEY_HOME);           break;
-        case 0x024: ts_map_key_clear(KEY_MENU);           break;
-        case 0x025: ts_map_key_clear(KEY_TV);             break;
-        case 0x048: ts_map_key_clear(KEY_RED);            break;
-        case 0x047: ts_map_key_clear(KEY_GREEN);          break;
-        case 0x049: ts_map_key_clear(KEY_YELLOW);         break;
-        case 0x04a: ts_map_key_clear(KEY_BLUE);           break;
-        case 0x04b: ts_map_key_clear(KEY_ANGLE);          break;
-        case 0x04c: ts_map_key_clear(KEY_LANGUAGE);       break;
-        case 0x04d: ts_map_key_clear(KEY_SUBTITLE);       break;
-        case 0x031: ts_map_key_clear(KEY_AUDIO);          break;
-        case 0x032: ts_map_key_clear(KEY_TEXT);           break;
-        case 0x033: ts_map_key_clear(KEY_CHANNEL);        break;
+       case 0x00d: ts_map_key_clear(KEY_MEDIA);        break;
+       case 0x024: ts_map_key_clear(KEY_MENU);         break;
+       case 0x025: ts_map_key_clear(KEY_TV);           break;
+       case 0x031: ts_map_key_clear(KEY_AUDIO);        break;
+       case 0x032: ts_map_key_clear(KEY_TEXT);         break;
+       case 0x033: ts_map_key_clear(KEY_CHANNEL);      break;
+       case 0x047: ts_map_key_clear(KEY_MP3);          break;
+       case 0x048: ts_map_key_clear(KEY_TV2);          break;
+       case 0x049: ts_map_key_clear(KEY_CAMERA);       break;
+       case 0x04a: ts_map_key_clear(KEY_VIDEO);        break;
+       case 0x04b: ts_map_key_clear(KEY_ANGLE);        break;
+       case 0x04c: ts_map_key_clear(KEY_LANGUAGE);     break;
+       case 0x04d: ts_map_key_clear(KEY_SUBTITLE);     break;
+       case 0x050: ts_map_key_clear(KEY_RADIO);        break;
+       case 0x05a: ts_map_key_clear(KEY_TEXT);         break;
+       case 0x05b: ts_map_key_clear(KEY_RED);          break;
+       case 0x05c: ts_map_key_clear(KEY_GREEN);        break;
+       case 0x05d: ts_map_key_clear(KEY_YELLOW);       break;
+       case 0x05e: ts_map_key_clear(KEY_BLUE);         break;
        default:
                return 0;
        }
@@ -50,6 +59,7 @@ static int ts_input_mapping(struct hid_device *hdev, struct hid_input *hi,
 
 static const struct hid_device_id ts_devices[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_TOPSEED, USB_DEVICE_ID_TOPSEED_CYBERLINK) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_BTC, USB_DEVICE_ID_BTC_EMPREX_REMOTE) },
        { }
 };
 MODULE_DEVICE_TABLE(hid, ts_devices);
index f947d83..1e051f1 100644 (file)
 #include <linux/hid.h>
 #include <linux/module.h>
 #include <linux/slab.h>
+#ifdef CONFIG_HID_WACOM_POWER_SUPPLY
+#include <linux/power_supply.h>
+#endif
 
 #include "hid-ids.h"
 
 struct wacom_data {
        __u16 tool;
        unsigned char butstate;
+       unsigned char high_speed;
+#ifdef CONFIG_HID_WACOM_POWER_SUPPLY
+       int battery_capacity;
+       struct power_supply battery;
+       struct power_supply ac;
+#endif
 };
 
+#ifdef CONFIG_HID_WACOM_POWER_SUPPLY
+/*percent of battery capacity, 0 means AC online*/
+static unsigned short batcap[8] = { 1, 15, 25, 35, 50, 70, 100, 0 };
+
+static enum power_supply_property wacom_battery_props[] = {
+       POWER_SUPPLY_PROP_PRESENT,
+       POWER_SUPPLY_PROP_CAPACITY
+};
+
+static enum power_supply_property wacom_ac_props[] = {
+       POWER_SUPPLY_PROP_PRESENT,
+       POWER_SUPPLY_PROP_ONLINE
+};
+
+static int wacom_battery_get_property(struct power_supply *psy,
+                               enum power_supply_property psp,
+                               union power_supply_propval *val)
+{
+       struct wacom_data *wdata = container_of(psy,
+                                       struct wacom_data, battery);
+       int power_state = batcap[wdata->battery_capacity];
+       int ret = 0;
+
+       switch (psp) {
+       case POWER_SUPPLY_PROP_PRESENT:
+               val->intval = 1;
+               break;
+       case POWER_SUPPLY_PROP_CAPACITY:
+               /* show 100% battery capacity when charging */
+               if (power_state == 0)
+                       val->intval = 100;
+               else
+                       val->intval = power_state;
+               break;
+       default:
+               ret = -EINVAL;
+               break;
+       }
+       return ret;
+}
+
+static int wacom_ac_get_property(struct power_supply *psy,
+                               enum power_supply_property psp,
+                               union power_supply_propval *val)
+{
+       struct wacom_data *wdata = container_of(psy, struct wacom_data, ac);
+       int power_state = batcap[wdata->battery_capacity];
+       int ret = 0;
+
+       switch (psp) {
+       case POWER_SUPPLY_PROP_PRESENT:
+               /* fall through */
+       case POWER_SUPPLY_PROP_ONLINE:
+               if (power_state == 0)
+                       val->intval = 1;
+               else
+                       val->intval = 0;
+               break;
+       default:
+               ret = -EINVAL;
+               break;
+       }
+       return ret;
+}
+#endif
+
+static void wacom_poke(struct hid_device *hdev, u8 speed)
+{
+       struct wacom_data *wdata = hid_get_drvdata(hdev);
+       int limit, ret;
+       char rep_data[2];
+
+       rep_data[0] = 0x03 ; rep_data[1] = 0x00;
+       limit = 3;
+       do {
+               ret = hdev->hid_output_raw_report(hdev, rep_data, 2,
+                               HID_FEATURE_REPORT);
+       } while (ret < 0 && limit-- > 0);
+
+       if (ret >= 0) {
+               if (speed == 0)
+                       rep_data[0] = 0x05;
+               else
+                       rep_data[0] = 0x06;
+
+               rep_data[1] = 0x00;
+               limit = 3;
+               do {
+                       ret = hdev->hid_output_raw_report(hdev, rep_data, 2,
+                                       HID_FEATURE_REPORT);
+               } while (ret < 0 && limit-- > 0);
+
+               if (ret >= 0) {
+                       wdata->high_speed = speed;
+                       return;
+               }
+       }
+
+       /*
+        * Note that if the raw queries fail, it's not a hard failure and it
+        * is safe to continue
+        */
+       dev_warn(&hdev->dev, "failed to poke device, command %d, err %d\n",
+                               rep_data[0], ret);
+       return;
+}
+
+static ssize_t wacom_show_speed(struct device *dev,
+                               struct device_attribute
+                               *attr, char *buf)
+{
+       struct wacom_data *wdata = dev_get_drvdata(dev);
+
+       return snprintf(buf, PAGE_SIZE, "%i\n", wdata->high_speed);
+}
+
+static ssize_t wacom_store_speed(struct device *dev,
+                               struct device_attribute *attr,
+                               const char *buf, size_t count)
+{
+       struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+       int new_speed;
+
+       if (sscanf(buf, "%1d", &new_speed ) != 1)
+               return -EINVAL;
+
+       if (new_speed == 0 || new_speed == 1) {
+               wacom_poke(hdev, new_speed);
+               return strnlen(buf, PAGE_SIZE);
+       } else
+               return -EINVAL;
+}
+
+static DEVICE_ATTR(speed, S_IRUGO | S_IWUGO,
+               wacom_show_speed, wacom_store_speed);
+
 static int wacom_raw_event(struct hid_device *hdev, struct hid_report *report,
                u8 *raw_data, int size)
 {
@@ -148,6 +293,12 @@ static int wacom_raw_event(struct hid_device *hdev, struct hid_report *report,
                input_sync(input);
        }
 
+#ifdef CONFIG_HID_WACOM_POWER_SUPPLY
+       /* Store current battery capacity */
+       rw = (data[7] >> 2 & 0x07);
+       if (rw != wdata->battery_capacity)
+               wdata->battery_capacity = rw;
+#endif
        return 1;
 }
 
@@ -157,9 +308,7 @@ static int wacom_probe(struct hid_device *hdev,
        struct hid_input *hidinput;
        struct input_dev *input;
        struct wacom_data *wdata;
-       char rep_data[2];
        int ret;
-       int limit;
 
        wdata = kzalloc(sizeof(*wdata), GFP_KERNEL);
        if (wdata == NULL) {
@@ -182,31 +331,53 @@ static int wacom_probe(struct hid_device *hdev,
                goto err_free;
        }
 
-       /*
-        * Note that if the raw queries fail, it's not a hard failure and it
-        * is safe to continue
-        */
+       ret = device_create_file(&hdev->dev, &dev_attr_speed);
+       if (ret)
+               dev_warn(&hdev->dev,
+                       "can't create sysfs speed attribute err: %d\n", ret);
 
-       /* Set Wacom mode2 */
-       rep_data[0] = 0x03; rep_data[1] = 0x00;
-       limit = 3;
-       do {
-               ret = hdev->hid_output_raw_report(hdev, rep_data, 2,
-                               HID_FEATURE_REPORT);
-       } while (ret < 0 && limit-- > 0);
-       if (ret < 0)
-               dev_warn(&hdev->dev, "failed to poke device #1, %d\n", ret);
+       /* Set Wacom mode 2 with high reporting speed */
+       wacom_poke(hdev, 1);
 
-       /* 0x06 - high reporting speed, 0x05 - low speed */
-       rep_data[0] = 0x06; rep_data[1] = 0x00;
-       limit = 3;
-       do {
-               ret = hdev->hid_output_raw_report(hdev, rep_data, 2,
-                               HID_FEATURE_REPORT);
-       } while (ret < 0 && limit-- > 0);
-       if (ret < 0)
-               dev_warn(&hdev->dev, "failed to poke device #2, %d\n", ret);
+#ifdef CONFIG_HID_WACOM_POWER_SUPPLY
+       wdata->battery.properties = wacom_battery_props;
+       wdata->battery.num_properties = ARRAY_SIZE(wacom_battery_props);
+       wdata->battery.get_property = wacom_battery_get_property;
+       wdata->battery.name = "wacom_battery";
+       wdata->battery.type = POWER_SUPPLY_TYPE_BATTERY;
+       wdata->battery.use_for_apm = 0;
 
+       ret = power_supply_register(&hdev->dev, &wdata->battery);
+       if (ret) {
+               dev_warn(&hdev->dev,
+                       "can't create sysfs battery attribute, err: %d\n", ret);
+               /*
+                * battery attribute is not critical for the tablet, but if it
+                * failed then there is no need to create ac attribute
+                */
+               goto move_on;
+       }
+
+       wdata->ac.properties = wacom_ac_props;
+       wdata->ac.num_properties = ARRAY_SIZE(wacom_ac_props);
+       wdata->ac.get_property = wacom_ac_get_property;
+       wdata->ac.name = "wacom_ac";
+       wdata->ac.type = POWER_SUPPLY_TYPE_MAINS;
+       wdata->ac.use_for_apm = 0;
+
+       ret = power_supply_register(&hdev->dev, &wdata->ac);
+       if (ret) {
+               dev_warn(&hdev->dev,
+                       "can't create ac battery attribute, err: %d\n", ret);
+               /*
+                * ac attribute is not critical for the tablet, but if it
+                * failed then we don't want to battery attribute to exist
+                */
+               power_supply_unregister(&wdata->battery);
+       }
+
+move_on:
+#endif
        hidinput = list_entry(hdev->inputs.next, struct hid_input, list);
        input = hidinput->input;
 
@@ -251,13 +422,21 @@ err_free:
 
 static void wacom_remove(struct hid_device *hdev)
 {
+#ifdef CONFIG_HID_WACOM_POWER_SUPPLY
+       struct wacom_data *wdata = hid_get_drvdata(hdev);
+#endif
        hid_hw_stop(hdev);
+
+#ifdef CONFIG_HID_WACOM_POWER_SUPPLY
+       power_supply_unregister(&wdata->battery);
+       power_supply_unregister(&wdata->ac);
+#endif
        kfree(hid_get_drvdata(hdev));
 }
 
 static const struct hid_device_id wacom_devices[] = {
        { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_GRAPHIRE_BLUETOOTH) },
-
+       { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS4_BLUETOOTH) },
        { }
 };
 MODULE_DEVICE_TABLE(hid, wacom_devices);
diff --git a/drivers/hid/hid-zydacron.c b/drivers/hid/hid-zydacron.c
new file mode 100644 (file)
index 0000000..9e8d35a
--- /dev/null
@@ -0,0 +1,237 @@
+/*
+*  HID driver for zydacron remote control
+*
+*  Copyright (c) 2010 Don Prince <dhprince.devel@yahoo.co.uk>
+*/
+
+/*
+* 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 "hid-ids.h"
+
+struct zc_device {
+       struct input_dev        *input_ep81;
+       unsigned short          last_key[4];
+};
+
+
+/*
+* Zydacron remote control has an invalid HID report descriptor,
+* that needs fixing before we can parse it.
+*/
+static void zc_report_fixup(struct hid_device *hdev, __u8 *rdesc,
+       unsigned int rsize)
+{
+       if (rsize >= 253 &&
+               rdesc[0x96] == 0xbc && rdesc[0x97] == 0xff &&
+               rdesc[0xca] == 0xbc && rdesc[0xcb] == 0xff &&
+               rdesc[0xe1] == 0xbc && rdesc[0xe2] == 0xff) {
+                       dev_info(&hdev->dev,
+                               "fixing up zydacron remote control report "
+                               "descriptor\n");
+                       rdesc[0x96] = rdesc[0xca] = rdesc[0xe1] = 0x0c;
+                       rdesc[0x97] = rdesc[0xcb] = rdesc[0xe2] = 0x00;
+               }
+}
+
+#define zc_map_key_clear(c) \
+       hid_map_usage_clear(hi, usage, bit, max, EV_KEY, (c))
+
+static int zc_input_mapping(struct hid_device *hdev, struct hid_input *hi,
+       struct hid_field *field, struct hid_usage *usage,
+       unsigned long **bit, int *max)
+{
+       int i;
+       struct zc_device *zc = hid_get_drvdata(hdev);
+       zc->input_ep81 = hi->input;
+
+       if ((usage->hid & HID_USAGE_PAGE) != HID_UP_CONSUMER)
+               return 0;
+
+       dbg_hid("zynacron input mapping event [0x%x]\n",
+               usage->hid & HID_USAGE);
+
+       switch (usage->hid & HID_USAGE) {
+       /* report 2 */
+       case 0x10:
+               zc_map_key_clear(KEY_MODE);
+               break;
+       case 0x30:
+               zc_map_key_clear(KEY_SCREEN);
+               break;
+       case 0x70:
+               zc_map_key_clear(KEY_INFO);
+               break;
+       /* report 3 */
+       case 0x04:
+               zc_map_key_clear(KEY_RADIO);
+               break;
+       /* report 4 */
+       case 0x0d:
+               zc_map_key_clear(KEY_PVR);
+               break;
+       case 0x25:
+               zc_map_key_clear(KEY_TV);
+               break;
+       case 0x47:
+               zc_map_key_clear(KEY_AUDIO);
+               break;
+       case 0x49:
+               zc_map_key_clear(KEY_AUX);
+               break;
+       case 0x4a:
+               zc_map_key_clear(KEY_VIDEO);
+               break;
+       case 0x48:
+               zc_map_key_clear(KEY_DVD);
+               break;
+       case 0x24:
+               zc_map_key_clear(KEY_MENU);
+               break;
+       case 0x32:
+               zc_map_key_clear(KEY_TEXT);
+               break;
+       default:
+               return 0;
+       }
+
+       for (i = 0; i < 4; i++)
+               zc->last_key[i] = 0;
+
+       return 1;
+}
+
+static int zc_raw_event(struct hid_device *hdev, struct hid_report *report,
+        u8 *data, int size)
+{
+       struct zc_device *zc = hid_get_drvdata(hdev);
+       int ret = 0;
+       unsigned key;
+       unsigned short index;
+
+       if (report->id == data[0]) {
+
+               /* break keys */
+               for (index = 0; index < 4; index++) {
+                       key = zc->last_key[index];
+                       if (key) {
+                               input_event(zc->input_ep81, EV_KEY, key, 0);
+                               zc->last_key[index] = 0;
+                       }
+               }
+
+               key = 0;
+               switch (report->id) {
+               case 0x02:
+               case 0x03:
+                       switch (data[1]) {
+                       case 0x10:
+                               key = KEY_MODE;
+                               index = 0;
+                               break;
+                       case 0x30:
+                               key = KEY_SCREEN;
+                               index = 1;
+                               break;
+                       case 0x70:
+                               key = KEY_INFO;
+                               index = 2;
+                               break;
+                       case 0x04:
+                               key = KEY_RADIO;
+                               index = 3;
+                               break;
+                       }
+
+                       if (key) {
+                               input_event(zc->input_ep81, EV_KEY, key, 1);
+                               zc->last_key[index] = key;
+                       }
+
+                       ret = 1;
+                       break;
+               }
+       }
+
+       return ret;
+}
+
+static int zc_probe(struct hid_device *hdev, const struct hid_device_id *id)
+{
+       int ret;
+       struct zc_device *zc;
+
+       zc = kzalloc(sizeof(*zc), GFP_KERNEL);
+       if (zc == NULL) {
+               dev_err(&hdev->dev, "zydacron: can't alloc descriptor\n");
+               return -ENOMEM;
+       }
+
+       hid_set_drvdata(hdev, zc);
+
+       ret = hid_parse(hdev);
+       if (ret) {
+               dev_err(&hdev->dev, "zydacron: parse failed\n");
+               goto err_free;
+       }
+
+       ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
+       if (ret) {
+               dev_err(&hdev->dev, "zydacron: hw start failed\n");
+               goto err_free;
+       }
+
+       return 0;
+err_free:
+       kfree(zc);
+
+       return ret;
+}
+
+static void zc_remove(struct hid_device *hdev)
+{
+       struct zc_device *zc = hid_get_drvdata(hdev);
+
+       hid_hw_stop(hdev);
+
+       if (NULL != zc)
+               kfree(zc);
+}
+
+static const struct hid_device_id zc_devices[] = {
+       { HID_USB_DEVICE(USB_VENDOR_ID_ZYDACRON, USB_DEVICE_ID_ZYDACRON_REMOTE_CONTROL) },
+       { }
+};
+MODULE_DEVICE_TABLE(hid, zc_devices);
+
+static struct hid_driver zc_driver = {
+       .name = "zydacron",
+       .id_table = zc_devices,
+       .report_fixup = zc_report_fixup,
+       .input_mapping = zc_input_mapping,
+       .raw_event = zc_raw_event,
+       .probe = zc_probe,
+       .remove = zc_remove,
+};
+
+static int __init zc_init(void)
+{
+       return hid_register_driver(&zc_driver);
+}
+
+static void __exit zc_exit(void)
+{
+       hid_unregister_driver(&zc_driver);
+}
+
+module_init(zc_init);
+module_exit(zc_exit);
+MODULE_LICENSE("GPL");
index 6eadf1a..a9becf9 100644 (file)
@@ -311,7 +311,7 @@ static long hidraw_ioctl(struct file *file, unsigned int cmd,
                                                -EFAULT : len;
                                        break;
                                }
-                }
+               }
 
                ret = -ENOTTY;
        }
index 7b85b69..a2ebe19 100644 (file)
@@ -807,16 +807,36 @@ static int usbhid_output_raw_report(struct hid_device *hid, __u8 *buf, size_t co
        struct usb_host_interface *interface = intf->cur_altsetting;
        int ret;
 
-       ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
-               HID_REQ_SET_REPORT,
-               USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
-               ((report_type + 1) << 8) | *buf,
-               interface->desc.bInterfaceNumber, buf + 1, count - 1,
-               USB_CTRL_SET_TIMEOUT);
-
-       /* count also the report id */
-       if (ret > 0)
-               ret++;
+       if (usbhid->urbout) {
+               int actual_length;
+               int skipped_report_id = 0;
+               if (buf[0] == 0x0) {
+                       /* Don't send the Report ID */
+                       buf++;
+                       count--;
+                       skipped_report_id = 1;
+               }
+               ret = usb_interrupt_msg(dev, usbhid->urbout->pipe,
+                       buf, count, &actual_length,
+                       USB_CTRL_SET_TIMEOUT);
+               /* return the number of bytes transferred */
+               if (ret == 0) {
+                       ret = actual_length;
+                       /* count also the report id */
+                       if (skipped_report_id)
+                               ret++;
+               }
+       } else {
+               ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+                       HID_REQ_SET_REPORT,
+                       USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+                       ((report_type + 1) << 8) | *buf,
+                       interface->desc.bInterfaceNumber, buf + 1, count - 1,
+                       USB_CTRL_SET_TIMEOUT);
+               /* count also the report id */
+               if (ret > 0)
+                       ret++;
+       }
 
        return ret;
 }
@@ -1019,12 +1039,15 @@ static int usbhid_start(struct hid_device *hid)
        /* Some keyboards don't work until their LEDs have been set.
         * Since BIOSes do set the LEDs, it must be safe for any device
         * that supports the keyboard boot protocol.
+        * In addition, enable remote wakeup by default for all keyboard
+        * devices supporting the boot protocol.
         */
        if (interface->desc.bInterfaceSubClass == USB_INTERFACE_SUBCLASS_BOOT &&
                        interface->desc.bInterfaceProtocol ==
-                               USB_INTERFACE_PROTOCOL_KEYBOARD)
+                               USB_INTERFACE_PROTOCOL_KEYBOARD) {
                usbhid_set_leds(hid);
-
+               device_set_wakeup_enable(&dev->dev, 1);
+       }
        return 0;
 
 fail:
@@ -1133,6 +1156,7 @@ static int usbhid_probe(struct usb_interface *intf, const struct usb_device_id *
        hid->vendor = le16_to_cpu(dev->descriptor.idVendor);
        hid->product = le16_to_cpu(dev->descriptor.idProduct);
        hid->name[0] = 0;
+       hid->quirks = usbhid_lookup_quirk(hid->vendor, hid->product);
        if (intf->cur_altsetting->desc.bInterfaceProtocol ==
                        USB_INTERFACE_PROTOCOL_MOUSE)
                hid->type = HID_TYPE_USBMOUSE;
index 1152f9b..7a6bda2 100644 (file)
@@ -33,6 +33,7 @@ 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_EGALAX, USB_DEVICE_ID_EGALAX_TOUCHCONTROLLER, 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 },
index f843443..b2fd0b0 100644 (file)
@@ -313,6 +313,7 @@ static int usb_kbd_probe(struct usb_interface *iface,
                goto fail2;
 
        usb_set_intfdata(iface, kbd);
+       device_set_wakeup_enable(&dev->dev, 1);
        return 0;
 
 fail2: 
index b1344ec..f1f2b6f 100644 (file)
@@ -308,11 +308,13 @@ struct hid_item {
 #define HID_QUIRK_NOTOUCH                      0x00000002
 #define HID_QUIRK_IGNORE                       0x00000004
 #define HID_QUIRK_NOGET                                0x00000008
+#define HID_QUIRK_HIDDEV_FORCE                 0x00000010
 #define HID_QUIRK_BADPAD                       0x00000020
 #define HID_QUIRK_MULTI_INPUT                  0x00000040
 #define HID_QUIRK_SKIP_OUTPUT_REPORTS          0x00010000
 #define HID_QUIRK_FULLSPEED_INTERVAL           0x10000000
 #define HID_QUIRK_NO_INIT_REPORTS              0x20000000
+#define HID_QUIRK_NO_IGNORE                    0x40000000
 
 /*
  * This is the global environment of the parser. This information is