]> git.kernelconcepts.de Git - karo-tx-linux.git/commitdiff
Merge branches 'for-3.12/devm', 'for-3.12/i2c-hid', 'for-3.12/i2c-hid-dt', 'for-3...
authorJiri Kosina <jkosina@suse.cz>
Fri, 6 Sep 2013 09:58:37 +0000 (11:58 +0200)
committerJiri Kosina <jkosina@suse.cz>
Fri, 6 Sep 2013 09:58:37 +0000 (11:58 +0200)
24 files changed:
Documentation/devicetree/bindings/hid/hid-over-i2c.txt [new file with mode: 0644]
Documentation/hid/uhid.txt
drivers/hid/hid-a4tech.c
drivers/hid/hid-apple.c
drivers/hid/hid-core.c
drivers/hid/hid-input.c
drivers/hid/hid-logitech-dj.c
drivers/hid/hid-magicmouse.c
drivers/hid/hid-multitouch.c
drivers/hid/hid-sony.c
drivers/hid/hid-wiimote-core.c
drivers/hid/hid-wiimote-modules.c
drivers/hid/hid-wiimote.h
drivers/hid/hid-zydacron.c
drivers/hid/i2c-hid/i2c-hid.c
drivers/hid/uhid.c
drivers/hid/usbhid/hid-core.c
drivers/hid/usbhid/usbhid.h
include/linux/hid.h
include/linux/i2c/i2c-hid.h
include/linux/mod_devicetable.h
include/uapi/linux/input.h
include/uapi/linux/uhid.h
samples/uhid/uhid-example.c

diff --git a/Documentation/devicetree/bindings/hid/hid-over-i2c.txt b/Documentation/devicetree/bindings/hid/hid-over-i2c.txt
new file mode 100644 (file)
index 0000000..488edcb
--- /dev/null
@@ -0,0 +1,28 @@
+* HID over I2C Device-Tree bindings
+
+HID over I2C provides support for various Human Interface Devices over the
+I2C bus. These devices can be for example touchpads, keyboards, touch screens
+or sensors.
+
+The specification has been written by Microsoft and is currently available here:
+http://msdn.microsoft.com/en-us/library/windows/hardware/hh852380.aspx
+
+If this binding is used, the kernel module i2c-hid will handle the communication
+with the device and the generic hid core layer will handle the protocol.
+
+Required properties:
+- compatible: must be "hid-over-i2c"
+- reg: i2c slave address
+- hid-descr-addr: HID descriptor address
+- interrupt-parent: the phandle for the interrupt controller
+- interrupts: interrupt line
+
+Example:
+
+       i2c-hid-dev@2c {
+               compatible = "hid-over-i2c";
+               reg = <0x2c>;
+               hid-descr-addr = <0x0020>;
+               interrupt-parent = <&gpx3>;
+               interrupts = <3 2>;
+       };
index 3c741214dfbbb028044be22a88c5359f7ba49646..dc35a2b75eeec08743b5e55614508a881589d3c0 100644 (file)
@@ -149,11 +149,13 @@ needs. Only UHID_OUTPUT and UHID_OUTPUT_EV have payloads.
   is of type "struct uhid_data_req".
   This may be received even though you haven't received UHID_OPEN, yet.
 
-  UHID_OUTPUT_EV:
+  UHID_OUTPUT_EV (obsolete):
   Same as UHID_OUTPUT but this contains a "struct input_event" as payload. This
   is called for force-feedback, LED or similar events which are received through
   an input device by the HID subsystem. You should convert this into raw reports
   and send them to your device similar to events of type UHID_OUTPUT.
+  This is no longer sent by newer kernels. Instead, HID core converts it into a
+  raw output report and sends it via UHID_OUTPUT.
 
   UHID_FEATURE:
   This event is sent if the kernel driver wants to perform a feature request as
index 7c5507e94820cc93b8867884dad993244431668a..9428ea7cdf8a00dc686e00c6da77be5cb60215b7 100644 (file)
@@ -90,11 +90,10 @@ 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);
+       a4 = devm_kzalloc(&hdev->dev, sizeof(*a4), GFP_KERNEL);
        if (a4 == NULL) {
                hid_err(hdev, "can't alloc device descriptor\n");
-               ret = -ENOMEM;
-               goto err_free;
+               return -ENOMEM;
        }
 
        a4->quirks = id->driver_data;
@@ -104,27 +103,16 @@ static int a4_probe(struct hid_device *hdev, const struct hid_device_id *id)
        ret = hid_parse(hdev);
        if (ret) {
                hid_err(hdev, "parse failed\n");
-               goto err_free;
+               return ret;
        }
 
        ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
        if (ret) {
                hid_err(hdev, "hw start failed\n");
-               goto err_free;
+               return ret;
        }
 
        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[] = {
@@ -144,7 +132,6 @@ static struct hid_driver a4_driver = {
        .input_mapped = a4_input_mapped,
        .event = a4_event,
        .probe = a4_probe,
-       .remove = a4_remove,
 };
 module_hid_driver(a4_driver);
 
index c7710b5c69afbf009d0e9f2d727668e6cdae5045..881cf7b4f9a433f8ae3e0f6721b3789aa66731f7 100644 (file)
@@ -349,7 +349,7 @@ static int apple_probe(struct hid_device *hdev,
        unsigned int connect_mask = HID_CONNECT_DEFAULT;
        int ret;
 
-       asc = kzalloc(sizeof(*asc), GFP_KERNEL);
+       asc = devm_kzalloc(&hdev->dev, sizeof(*asc), GFP_KERNEL);
        if (asc == NULL) {
                hid_err(hdev, "can't alloc apple descriptor\n");
                return -ENOMEM;
@@ -362,7 +362,7 @@ static int apple_probe(struct hid_device *hdev,
        ret = hid_parse(hdev);
        if (ret) {
                hid_err(hdev, "parse failed\n");
-               goto err_free;
+               return ret;
        }
 
        if (quirks & APPLE_HIDDEV)
@@ -373,19 +373,10 @@ static int apple_probe(struct hid_device *hdev,
        ret = hid_hw_start(hdev, connect_mask);
        if (ret) {
                hid_err(hdev, "hw start failed\n");
-               goto err_free;
+               return ret;
        }
 
        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[] = {
@@ -551,7 +542,6 @@ static struct hid_driver apple_driver = {
        .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,
index 2ac13ca6edaa8324856fa48adbfa84ac1530f7e5..2c778542e40ddf3bb71de1f967076cb38aac41a6 100644 (file)
@@ -681,12 +681,61 @@ static u8 *fetch_item(__u8 *start, __u8 *end, struct hid_item *item)
        return NULL;
 }
 
-static void hid_scan_usage(struct hid_device *hid, u32 usage)
+static void hid_scan_input_usage(struct hid_parser *parser, u32 usage)
 {
+       struct hid_device *hid = parser->device;
+
        if (usage == HID_DG_CONTACTID)
                hid->group = HID_GROUP_MULTITOUCH;
 }
 
+static void hid_scan_feature_usage(struct hid_parser *parser, u32 usage)
+{
+       if (usage == 0xff0000c5 && parser->global.report_count == 256 &&
+           parser->global.report_size == 8)
+               parser->scan_flags |= HID_SCAN_FLAG_MT_WIN_8;
+}
+
+static void hid_scan_collection(struct hid_parser *parser, unsigned type)
+{
+       struct hid_device *hid = parser->device;
+
+       if (((parser->global.usage_page << 16) == HID_UP_SENSOR) &&
+           type == HID_COLLECTION_PHYSICAL)
+               hid->group = HID_GROUP_SENSOR_HUB;
+}
+
+static int hid_scan_main(struct hid_parser *parser, struct hid_item *item)
+{
+       __u32 data;
+       int i;
+
+       data = item_udata(item);
+
+       switch (item->tag) {
+       case HID_MAIN_ITEM_TAG_BEGIN_COLLECTION:
+               hid_scan_collection(parser, data & 0xff);
+               break;
+       case HID_MAIN_ITEM_TAG_END_COLLECTION:
+               break;
+       case HID_MAIN_ITEM_TAG_INPUT:
+               for (i = 0; i < parser->local.usage_index; i++)
+                       hid_scan_input_usage(parser, parser->local.usage[i]);
+               break;
+       case HID_MAIN_ITEM_TAG_OUTPUT:
+               break;
+       case HID_MAIN_ITEM_TAG_FEATURE:
+               for (i = 0; i < parser->local.usage_index; i++)
+                       hid_scan_feature_usage(parser, parser->local.usage[i]);
+               break;
+       }
+
+       /* Reset the local parser environment */
+       memset(&parser->local, 0, sizeof(parser->local));
+
+       return 0;
+}
+
 /*
  * Scan a report descriptor before the device is added to the bus.
  * Sets device groups and other properties that determine what driver
@@ -694,48 +743,41 @@ static void hid_scan_usage(struct hid_device *hid, u32 usage)
  */
 static int hid_scan_report(struct hid_device *hid)
 {
-       unsigned int page = 0, delim = 0;
+       struct hid_parser *parser;
+       struct hid_item item;
        __u8 *start = hid->dev_rdesc;
        __u8 *end = start + hid->dev_rsize;
-       unsigned int u, u_min = 0, u_max = 0;
-       struct hid_item item;
+       static int (*dispatch_type[])(struct hid_parser *parser,
+                                     struct hid_item *item) = {
+               hid_scan_main,
+               hid_parser_global,
+               hid_parser_local,
+               hid_parser_reserved
+       };
 
+       parser = vzalloc(sizeof(struct hid_parser));
+       if (!parser)
+               return -ENOMEM;
+
+       parser->device = hid;
        hid->group = HID_GROUP_GENERIC;
-       while ((start = fetch_item(start, end, &item)) != NULL) {
-               if (item.format != HID_ITEM_FORMAT_SHORT)
-                       return -EINVAL;
-               if (item.type == HID_ITEM_TYPE_GLOBAL) {
-                       if (item.tag == HID_GLOBAL_ITEM_TAG_USAGE_PAGE)
-                               page = item_udata(&item) << 16;
-               } else if (item.type == HID_ITEM_TYPE_LOCAL) {
-                       if (delim > 1)
-                               break;
-                       u = item_udata(&item);
-                       if (item.size <= 2)
-                               u += page;
-                       switch (item.tag) {
-                       case HID_LOCAL_ITEM_TAG_DELIMITER:
-                               delim += !!u;
-                               break;
-                       case HID_LOCAL_ITEM_TAG_USAGE:
-                               hid_scan_usage(hid, u);
-                               break;
-                       case HID_LOCAL_ITEM_TAG_USAGE_MINIMUM:
-                               u_min = u;
-                               break;
-                       case HID_LOCAL_ITEM_TAG_USAGE_MAXIMUM:
-                               u_max = u;
-                               for (u = u_min; u <= u_max; u++)
-                                       hid_scan_usage(hid, u);
-                               break;
-                       }
-               } else if (page == HID_UP_SENSOR &&
-                       item.type == HID_ITEM_TYPE_MAIN &&
-                       item.tag == HID_MAIN_ITEM_TAG_BEGIN_COLLECTION &&
-                       (item_udata(&item) & 0xff) == HID_COLLECTION_PHYSICAL)
-                       hid->group = HID_GROUP_SENSOR_HUB;
-       }
 
+       /*
+        * The parsing is simpler than the one in hid_open_report() as we should
+        * be robust against hid errors. Those errors will be raised by
+        * hid_open_report() anyway.
+        */
+       while ((start = fetch_item(start, end, &item)) != NULL)
+               dispatch_type[item.type](parser, &item);
+
+       /*
+        * Handle special flags set during scanning.
+        */
+       if ((parser->scan_flags & HID_SCAN_FLAG_MT_WIN_8) &&
+           (hid->group == HID_GROUP_MULTITOUCH))
+               hid->group = HID_GROUP_MULTITOUCH_WIN_8;
+
+       vfree(parser);
        return 0;
 }
 
index 3fc4034a43678e0282b8e9c4bba42bd3648eeee6..b420f4a0fd28101e0e697a48e581fe31826f9a56 100644 (file)
@@ -1145,6 +1145,74 @@ unsigned int hidinput_count_leds(struct hid_device *hid)
 }
 EXPORT_SYMBOL_GPL(hidinput_count_leds);
 
+static void hidinput_led_worker(struct work_struct *work)
+{
+       struct hid_device *hid = container_of(work, struct hid_device,
+                                             led_work);
+       struct hid_field *field;
+       struct hid_report *report;
+       int len;
+       __u8 *buf;
+
+       field = hidinput_get_led_field(hid);
+       if (!field)
+               return;
+
+       /*
+        * field->report is accessed unlocked regarding HID core. So there might
+        * be another incoming SET-LED request from user-space, which changes
+        * the LED state while we assemble our outgoing buffer. However, this
+        * doesn't matter as hid_output_report() correctly converts it into a
+        * boolean value no matter what information is currently set on the LED
+        * field (even garbage). So the remote device will always get a valid
+        * request.
+        * And in case we send a wrong value, a next led worker is spawned
+        * for every SET-LED request so the following worker will send the
+        * correct value, guaranteed!
+        */
+
+       report = field->report;
+
+       /* use custom SET_REPORT request if possible (asynchronous) */
+       if (hid->ll_driver->request)
+               return hid->ll_driver->request(hid, report, HID_REQ_SET_REPORT);
+
+       /* fall back to generic raw-output-report */
+       len = ((report->size - 1) >> 3) + 1 + (report->id > 0);
+       buf = kmalloc(len, GFP_KERNEL);
+       if (!buf)
+               return;
+
+       hid_output_report(report, buf);
+       /* synchronous output report */
+       hid->hid_output_raw_report(hid, buf, len, HID_OUTPUT_REPORT);
+       kfree(buf);
+}
+
+static int hidinput_input_event(struct input_dev *dev, unsigned int type,
+                               unsigned int code, int value)
+{
+       struct hid_device *hid = input_get_drvdata(dev);
+       struct hid_field *field;
+       int offset;
+
+       if (type == EV_FF)
+               return input_ff_event(dev, type, code, value);
+
+       if (type != EV_LED)
+               return -1;
+
+       if ((offset = hidinput_find_field(hid, type, code, &field)) == -1) {
+               hid_warn(dev, "event field not found\n");
+               return -1;
+       }
+
+       hid_set_field(field, offset, value);
+
+       schedule_work(&hid->led_work);
+       return 0;
+}
+
 static int hidinput_open(struct input_dev *dev)
 {
        struct hid_device *hid = input_get_drvdata(dev);
@@ -1191,7 +1259,10 @@ static struct hid_input *hidinput_allocate(struct hid_device *hid)
        }
 
        input_set_drvdata(input_dev, hid);
-       input_dev->event = hid->ll_driver->hidinput_input_event;
+       if (hid->ll_driver->hidinput_input_event)
+               input_dev->event = hid->ll_driver->hidinput_input_event;
+       else if (hid->ll_driver->request || hid->hid_output_raw_report)
+               input_dev->event = hidinput_input_event;
        input_dev->open = hidinput_open;
        input_dev->close = hidinput_close;
        input_dev->setkeycode = hidinput_setkeycode;
@@ -1286,6 +1357,7 @@ int hidinput_connect(struct hid_device *hid, unsigned int force)
        int i, j, k;
 
        INIT_LIST_HEAD(&hid->inputs);
+       INIT_WORK(&hid->led_work, hidinput_led_worker);
 
        if (!force) {
                for (i = 0; i < hid->maxcollection; i++) {
@@ -1387,6 +1459,12 @@ void hidinput_disconnect(struct hid_device *hid)
                input_unregister_device(hidinput->input);
                kfree(hidinput);
        }
+
+       /* led_work is spawned by input_dev callbacks, but doesn't access the
+        * parent input_dev at all. Once all input devices are removed, we
+        * know that led_work will never get restarted, so we can cancel it
+        * synchronously and are safe. */
+       cancel_work_sync(&hid->led_work);
 }
 EXPORT_SYMBOL_GPL(hidinput_disconnect);
 
index d0e5963c1ba189a877ece23123839d8f3a29df8c..7800b141056243400bfa316b7289e2c8431aa82a 100644 (file)
@@ -809,10 +809,10 @@ static int logi_dj_probe(struct hid_device *hdev,
        }
 
        /* This is enabling the polling urb on the IN endpoint */
-       retval = hdev->ll_driver->open(hdev);
+       retval = hid_hw_open(hdev);
        if (retval < 0) {
-               dev_err(&hdev->dev, "%s:hdev->ll_driver->open returned "
-                       "error:%d\n", __func__, retval);
+               dev_err(&hdev->dev, "%s:hid_hw_open returned error:%d\n",
+                       __func__, retval);
                goto llopen_failed;
        }
 
@@ -829,7 +829,7 @@ static int logi_dj_probe(struct hid_device *hdev,
        return retval;
 
 logi_dj_recv_query_paired_devices_failed:
-       hdev->ll_driver->close(hdev);
+       hid_hw_close(hdev);
 
 llopen_failed:
 switch_to_dj_mode_fail:
@@ -871,7 +871,7 @@ static void logi_dj_remove(struct hid_device *hdev)
 
        cancel_work_sync(&djrcv_dev->work);
 
-       hdev->ll_driver->close(hdev);
+       hid_hw_close(hdev);
        hid_hw_stop(hdev);
 
        /* I suppose that at this point the only context that can access
index a32f5a24b27ceadcdfe33e05a8fe9715eed4d38a..3b43d1cfa9368609302de46a73658779199d446f 100644 (file)
@@ -484,7 +484,7 @@ static int magicmouse_probe(struct hid_device *hdev,
        struct hid_report *report;
        int ret;
 
-       msc = kzalloc(sizeof(*msc), GFP_KERNEL);
+       msc = devm_kzalloc(&hdev->dev, sizeof(*msc), GFP_KERNEL);
        if (msc == NULL) {
                hid_err(hdev, "can't alloc magicmouse descriptor\n");
                return -ENOMEM;
@@ -498,13 +498,13 @@ static int magicmouse_probe(struct hid_device *hdev,
        ret = hid_parse(hdev);
        if (ret) {
                hid_err(hdev, "magicmouse hid parse failed\n");
-               goto err_free;
+               return ret;
        }
 
        ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
        if (ret) {
                hid_err(hdev, "magicmouse hw start failed\n");
-               goto err_free;
+               return ret;
        }
 
        if (!msc->input) {
@@ -548,19 +548,9 @@ static int magicmouse_probe(struct hid_device *hdev,
        return 0;
 err_stop_hw:
        hid_hw_stop(hdev);
-err_free:
-       kfree(msc);
        return ret;
 }
 
-static void magicmouse_remove(struct hid_device *hdev)
-{
-       struct magicmouse_sc *msc = hid_get_drvdata(hdev);
-
-       hid_hw_stop(hdev);
-       kfree(msc);
-}
-
 static const struct hid_device_id magic_mice[] = {
        { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE,
                USB_DEVICE_ID_APPLE_MAGICMOUSE), .driver_data = 0 },
@@ -574,7 +564,6 @@ static struct hid_driver magicmouse_driver = {
        .name = "magicmouse",
        .id_table = magic_mice,
        .probe = magicmouse_probe,
-       .remove = magicmouse_remove,
        .raw_event = magicmouse_raw_event,
        .input_mapping = magicmouse_input_mapping,
        .input_configured = magicmouse_input_configured,
index cb0e361d7a4be8e5e790f9ab250ffbfd17c52fe7..ac28f08c38660b0051500242f8562b587007cf90 100644 (file)
@@ -133,6 +133,7 @@ static void mt_post_parse(struct mt_device *td);
 #define MT_CLS_NSMU                            0x000a
 #define MT_CLS_DUAL_CONTACT_NUMBER             0x0010
 #define MT_CLS_DUAL_CONTACT_ID                 0x0011
+#define MT_CLS_WIN_8                           0x0012
 
 /* vendor specific classes */
 #define MT_CLS_3M                              0x0101
@@ -205,6 +206,11 @@ static struct mt_class mt_classes[] = {
                        MT_QUIRK_CONTACT_CNT_ACCURATE |
                        MT_QUIRK_SLOT_IS_CONTACTID,
                .maxcontacts = 2 },
+       { .name = MT_CLS_WIN_8,
+               .quirks = MT_QUIRK_ALWAYS_VALID |
+                       MT_QUIRK_IGNORE_DUPLICATES |
+                       MT_QUIRK_HOVERING |
+                       MT_QUIRK_CONTACT_CNT_ACCURATE },
 
        /*
         * vendor specific classes
@@ -261,17 +267,6 @@ static struct mt_class mt_classes[] = {
        { }
 };
 
-static void mt_free_input_name(struct hid_input *hi)
-{
-       struct hid_device *hdev = hi->report->device;
-       const char *name = hi->input->name;
-
-       if (name != hdev->name) {
-               hi->input->name = hdev->name;
-               kfree(name);
-       }
-}
-
 static ssize_t mt_show_quirks(struct device *dev,
                           struct device_attribute *attr,
                           char *buf)
@@ -343,19 +338,6 @@ static void mt_feature_mapping(struct hid_device *hdev,
                        td->maxcontacts = td->mtclass.maxcontacts;
 
                break;
-       case 0xff0000c5:
-               if (field->report_count == 256 && field->report_size == 8) {
-                       /* Win 8 devices need special quirks */
-                       __s32 *quirks = &td->mtclass.quirks;
-                       *quirks |= MT_QUIRK_ALWAYS_VALID;
-                       *quirks |= MT_QUIRK_IGNORE_DUPLICATES;
-                       *quirks |= MT_QUIRK_HOVERING;
-                       *quirks |= MT_QUIRK_CONTACT_CNT_ACCURATE;
-                       *quirks &= ~MT_QUIRK_NOT_SEEN_MEANS_UP;
-                       *quirks &= ~MT_QUIRK_VALID_IS_INRANGE;
-                       *quirks &= ~MT_QUIRK_VALID_IS_CONFIDENCE;
-               }
-               break;
        }
 }
 
@@ -415,13 +397,6 @@ static void mt_pen_report(struct hid_device *hid, struct hid_report *report)
 static void mt_pen_input_configured(struct hid_device *hdev,
                                        struct hid_input *hi)
 {
-       char *name = kzalloc(strlen(hi->input->name) + 5, GFP_KERNEL);
-       if (name) {
-               sprintf(name, "%s Pen", hi->input->name);
-               mt_free_input_name(hi);
-               hi->input->name = name;
-       }
-
        /* force BTN_STYLUS to allow tablet matching in udev */
        __set_bit(BTN_STYLUS, hi->input->keybit);
 }
@@ -928,16 +903,26 @@ static void mt_post_parse(struct mt_device *td)
 static void mt_input_configured(struct hid_device *hdev, struct hid_input *hi)
 {
        struct mt_device *td = hid_get_drvdata(hdev);
-       char *name = kstrdup(hdev->name, GFP_KERNEL);
-
-       if (name)
-               hi->input->name = name;
+       char *name;
+       const char *suffix = NULL;
 
        if (hi->report->id == td->mt_report_id)
                mt_touch_input_configured(hdev, hi);
 
-       if (hi->report->id == td->pen_report_id)
+       if (hi->report->field[0]->physical == HID_DG_STYLUS) {
+               suffix = "Pen";
                mt_pen_input_configured(hdev, hi);
+       }
+
+       if (suffix) {
+               name = devm_kzalloc(&hi->input->dev,
+                                   strlen(hdev->name) + strlen(suffix) + 2,
+                                   GFP_KERNEL);
+               if (name) {
+                       sprintf(name, "%s %s", hdev->name, suffix);
+                       hi->input->name = name;
+               }
+       }
 }
 
 static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
@@ -945,7 +930,6 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
        int ret, i;
        struct mt_device *td;
        struct mt_class *mtclass = mt_classes; /* MT_CLS_DEFAULT */
-       struct hid_input *hi;
 
        for (i = 0; mt_classes[i].name ; i++) {
                if (id->driver_data == mt_classes[i].name) {
@@ -967,7 +951,19 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
        hdev->quirks |= HID_QUIRK_MULTI_INPUT;
        hdev->quirks |= HID_QUIRK_NO_EMPTY_INPUT;
 
-       td = kzalloc(sizeof(struct mt_device), GFP_KERNEL);
+       /*
+        * Handle special quirks for Windows 8 certified devices.
+        */
+       if (id->group == HID_GROUP_MULTITOUCH_WIN_8)
+               /*
+                * Some multitouch screens do not like to be polled for input
+                * reports. Fortunately, the Win8 spec says that all touches
+                * should be sent during each report, making the initialization
+                * of input reports unnecessary.
+                */
+               hdev->quirks |= HID_QUIRK_NO_INIT_INPUT_REPORTS;
+
+       td = devm_kzalloc(&hdev->dev, sizeof(struct mt_device), GFP_KERNEL);
        if (!td) {
                dev_err(&hdev->dev, "cannot allocate multitouch data\n");
                return -ENOMEM;
@@ -980,11 +976,11 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
        td->pen_report_id = -1;
        hid_set_drvdata(hdev, td);
 
-       td->fields = kzalloc(sizeof(struct mt_fields), GFP_KERNEL);
+       td->fields = devm_kzalloc(&hdev->dev, sizeof(struct mt_fields),
+                                 GFP_KERNEL);
        if (!td->fields) {
                dev_err(&hdev->dev, "cannot allocate multitouch fields data\n");
-               ret = -ENOMEM;
-               goto fail;
+               return -ENOMEM;
        }
 
        if (id->vendor == HID_ANY_ID && id->product == HID_ANY_ID)
@@ -992,29 +988,22 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
 
        ret = hid_parse(hdev);
        if (ret != 0)
-               goto fail;
+               return ret;
 
        ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
        if (ret)
-               goto hid_fail;
+               return ret;
 
        ret = sysfs_create_group(&hdev->dev.kobj, &mt_attribute_group);
 
        mt_set_maxcontacts(hdev);
        mt_set_input_mode(hdev);
 
-       kfree(td->fields);
+       /* release .fields memory as it is not used anymore */
+       devm_kfree(&hdev->dev, td->fields);
        td->fields = NULL;
 
        return 0;
-
-hid_fail:
-       list_for_each_entry(hi, &hdev->inputs, list)
-               mt_free_input_name(hi);
-fail:
-       kfree(td->fields);
-       kfree(td);
-       return ret;
 }
 
 #ifdef CONFIG_PM
@@ -1039,17 +1028,8 @@ static int mt_resume(struct hid_device *hdev)
 
 static void mt_remove(struct hid_device *hdev)
 {
-       struct mt_device *td = hid_get_drvdata(hdev);
-       struct hid_input *hi;
-
        sysfs_remove_group(&hdev->dev.kobj, &mt_attribute_group);
-       list_for_each_entry(hi, &hdev->inputs, list)
-               mt_free_input_name(hi);
-
        hid_hw_stop(hdev);
-
-       kfree(td);
-       hid_set_drvdata(hdev, NULL);
 }
 
 static const struct hid_device_id mt_devices[] = {
@@ -1371,6 +1351,11 @@ static const struct hid_device_id mt_devices[] = {
 
        /* Generic MT device */
        { HID_DEVICE(HID_BUS_ANY, HID_GROUP_MULTITOUCH, HID_ANY_ID, HID_ANY_ID) },
+
+       /* Generic Win 8 certified MT device */
+       {  .driver_data = MT_CLS_WIN_8,
+               HID_DEVICE(HID_BUS_ANY, HID_GROUP_MULTITOUCH_WIN_8,
+                       HID_ANY_ID, HID_ANY_ID) },
        { }
 };
 MODULE_DEVICE_TABLE(hid, mt_devices);
index 87fbe2924cfac3852ee8b202b8aaeb8500de0080..30dbb6b40bbf17e93c63b2bd6d3eb3b7f8111593 100644 (file)
@@ -624,7 +624,7 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
        struct sony_sc *sc;
        unsigned int connect_mask = HID_CONNECT_DEFAULT;
 
-       sc = kzalloc(sizeof(*sc), GFP_KERNEL);
+       sc = devm_kzalloc(&hdev->dev, sizeof(*sc), GFP_KERNEL);
        if (sc == NULL) {
                hid_err(hdev, "can't alloc sony descriptor\n");
                return -ENOMEM;
@@ -636,7 +636,7 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
        ret = hid_parse(hdev);
        if (ret) {
                hid_err(hdev, "parse failed\n");
-               goto err_free;
+               return ret;
        }
 
        if (sc->quirks & VAIO_RDESC_CONSTANT)
@@ -649,7 +649,7 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
        ret = hid_hw_start(hdev, connect_mask);
        if (ret) {
                hid_err(hdev, "hw start failed\n");
-               goto err_free;
+               return ret;
        }
 
        if (sc->quirks & SIXAXIS_CONTROLLER_USB) {
@@ -669,8 +669,6 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
        return 0;
 err_stop:
        hid_hw_stop(hdev);
-err_free:
-       kfree(sc);
        return ret;
 }
 
@@ -682,7 +680,6 @@ static void sony_remove(struct hid_device *hdev)
                buzz_remove(hdev);
 
        hid_hw_stop(hdev);
-       kfree(sc);
 }
 
 static const struct hid_device_id sony_devices[] = {
index 0c06054cab8f01033404f35375c0e12584db3c51..bd2bc4a1f3781e94897d9877064b553f18ea3604 100644 (file)
@@ -212,10 +212,12 @@ static __u8 select_drm(struct wiimote_data *wdata)
 
        if (ir == WIIPROTO_FLAG_IR_BASIC) {
                if (wdata->state.flags & WIIPROTO_FLAG_ACCEL) {
-                       if (ext)
-                               return WIIPROTO_REQ_DRM_KAIE;
-                       else
-                               return WIIPROTO_REQ_DRM_KAI;
+                       /* GEN10 and ealier devices bind IR formats to DRMs.
+                        * Hence, we cannot use DRM_KAI here as it might be
+                        * bound to IR_EXT. Use DRM_KAIE unconditionally so we
+                        * work with all devices and our parsers can use the
+                        * fixed formats, too. */
+                       return WIIPROTO_REQ_DRM_KAIE;
                } else {
                        return WIIPROTO_REQ_DRM_KIE;
                }
@@ -439,8 +441,7 @@ static __u8 wiimote_cmd_read_ext(struct wiimote_data *wdata, __u8 *rmem)
        if (ret != 6)
                return WIIMOTE_EXT_NONE;
 
-       hid_dbg(wdata->hdev, "extension ID: %02x:%02x %02x:%02x %02x:%02x\n",
-               rmem[0], rmem[1], rmem[2], rmem[3], rmem[4], rmem[5]);
+       hid_dbg(wdata->hdev, "extension ID: %6phC\n", rmem);
 
        if (rmem[0] == 0xff && rmem[1] == 0xff && rmem[2] == 0xff &&
            rmem[3] == 0xff && rmem[4] == 0xff && rmem[5] == 0xff)
@@ -454,6 +455,12 @@ static __u8 wiimote_cmd_read_ext(struct wiimote_data *wdata, __u8 *rmem)
                return WIIMOTE_EXT_BALANCE_BOARD;
        if (rmem[4] == 0x01 && rmem[5] == 0x20)
                return WIIMOTE_EXT_PRO_CONTROLLER;
+       if (rmem[0] == 0x01 && rmem[1] == 0x00 &&
+           rmem[4] == 0x01 && rmem[5] == 0x03)
+               return WIIMOTE_EXT_GUITAR_HERO_DRUMS;
+       if (rmem[0] == 0x00 && rmem[1] == 0x00 &&
+           rmem[4] == 0x01 && rmem[5] == 0x03)
+               return WIIMOTE_EXT_GUITAR_HERO_GUITAR;
 
        return WIIMOTE_EXT_UNKNOWN;
 }
@@ -487,6 +494,8 @@ static bool wiimote_cmd_map_mp(struct wiimote_data *wdata, __u8 exttype)
        /* map MP with correct pass-through mode */
        switch (exttype) {
        case WIIMOTE_EXT_CLASSIC_CONTROLLER:
+       case WIIMOTE_EXT_GUITAR_HERO_DRUMS:
+       case WIIMOTE_EXT_GUITAR_HERO_GUITAR:
                wmem = 0x07;
                break;
        case WIIMOTE_EXT_NUNCHUK:
@@ -510,14 +519,12 @@ static bool wiimote_cmd_read_mp(struct wiimote_data *wdata, __u8 *rmem)
        if (ret != 6)
                return false;
 
-       hid_dbg(wdata->hdev, "motion plus ID: %02x:%02x %02x:%02x %02x:%02x\n",
-               rmem[0], rmem[1], rmem[2], rmem[3], rmem[4], rmem[5]);
+       hid_dbg(wdata->hdev, "motion plus ID: %6phC\n", rmem);
 
        if (rmem[5] == 0x05)
                return true;
 
-       hid_info(wdata->hdev, "unknown motion plus ID: %02x:%02x %02x:%02x %02x:%02x\n",
-                rmem[0], rmem[1], rmem[2], rmem[3], rmem[4], rmem[5]);
+       hid_info(wdata->hdev, "unknown motion plus ID: %6phC\n", rmem);
 
        return false;
 }
@@ -533,8 +540,7 @@ static __u8 wiimote_cmd_read_mp_mapped(struct wiimote_data *wdata)
        if (ret != 6)
                return WIIMOTE_MP_NONE;
 
-       hid_dbg(wdata->hdev, "mapped motion plus ID: %02x:%02x %02x:%02x %02x:%02x\n",
-               rmem[0], rmem[1], rmem[2], rmem[3], rmem[4], rmem[5]);
+       hid_dbg(wdata->hdev, "mapped motion plus ID: %6phC\n", rmem);
 
        if (rmem[0] == 0xff && rmem[1] == 0xff && rmem[2] == 0xff &&
            rmem[3] == 0xff && rmem[4] == 0xff && rmem[5] == 0xff)
@@ -1077,6 +1083,8 @@ static const char *wiimote_exttype_names[WIIMOTE_EXT_NUM] = {
        [WIIMOTE_EXT_CLASSIC_CONTROLLER] = "Nintendo Wii Classic Controller",
        [WIIMOTE_EXT_BALANCE_BOARD] = "Nintendo Wii Balance Board",
        [WIIMOTE_EXT_PRO_CONTROLLER] = "Nintendo Wii U Pro Controller",
+       [WIIMOTE_EXT_GUITAR_HERO_DRUMS] = "Nintendo Wii Guitar Hero Drums",
+       [WIIMOTE_EXT_GUITAR_HERO_GUITAR] = "Nintendo Wii Guitar Hero Guitar",
 };
 
 /*
@@ -1126,9 +1134,8 @@ static void wiimote_init_hotplug(struct wiimote_data *wdata)
                wiimote_ext_unload(wdata);
 
                if (exttype == WIIMOTE_EXT_UNKNOWN) {
-                       hid_info(wdata->hdev, "cannot detect extension; %02x:%02x %02x:%02x %02x:%02x\n",
-                                extdata[0], extdata[1], extdata[2],
-                                extdata[3], extdata[4], extdata[5]);
+                       hid_info(wdata->hdev, "cannot detect extension; %6phC\n",
+                                extdata);
                } else if (exttype == WIIMOTE_EXT_NONE) {
                        spin_lock_irq(&wdata->state.lock);
                        wdata->state.exttype = WIIMOTE_EXT_NONE;
@@ -1663,6 +1670,10 @@ static ssize_t wiimote_ext_show(struct device *dev,
                return sprintf(buf, "balanceboard\n");
        case WIIMOTE_EXT_PRO_CONTROLLER:
                return sprintf(buf, "procontroller\n");
+       case WIIMOTE_EXT_GUITAR_HERO_DRUMS:
+               return sprintf(buf, "drums\n");
+       case WIIMOTE_EXT_GUITAR_HERO_GUITAR:
+               return sprintf(buf, "guitar\n");
        case WIIMOTE_EXT_UNKNOWN:
                /* fallthrough */
        default:
index 2e7d644dba18a6fc1169c7b83ee7eded30f6e09f..7e124c351e67e9b73d15e11fef42708e61ea61a4 100644 (file)
@@ -1833,6 +1833,396 @@ static const struct wiimod_ops wiimod_pro = {
        .in_ext = wiimod_pro_in_ext,
 };
 
+/*
+ * Drums
+ * Guitar-Hero, Rock-Band and other games came bundled with drums which can
+ * be plugged as extension to a Wiimote. Drum-reports are still not entirely
+ * figured out, but the most important information is known.
+ * We create a separate device for drums and report all information via this
+ * input device.
+ */
+
+static inline void wiimod_drums_report_pressure(struct wiimote_data *wdata,
+                                               __u8 none, __u8 which,
+                                               __u8 pressure, __u8 onoff,
+                                               __u8 *store, __u16 code,
+                                               __u8 which_code)
+{
+       static const __u8 default_pressure = 3;
+
+       if (!none && which == which_code) {
+               *store = pressure;
+               input_report_abs(wdata->extension.input, code, *store);
+       } else if (onoff != !!*store) {
+               *store = onoff ? default_pressure : 0;
+               input_report_abs(wdata->extension.input, code, *store);
+       }
+}
+
+static void wiimod_drums_in_ext(struct wiimote_data *wdata, const __u8 *ext)
+{
+       __u8 pressure, which, none, hhp, sx, sy;
+       __u8 o, r, y, g, b, bass, bm, bp;
+
+       /*   Byte |  8  |  7  |  6  |  5  |  4  |  3  |  2  |  1  |
+        *   -----+-----+-----+-----+-----+-----+-----+-----+-----+
+        *    1   |  0  |  0  |              SX <5:0>             |
+        *    2   |  0  |  0  |              SY <5:0>             |
+        *   -----+-----+-----+-----------------------------+-----+
+        *    3   | HPP | NON |         WHICH <5:1>         |  ?  |
+        *   -----+-----+-----+-----+-----+-----+-----+-----+-----+
+        *    4   |   SOFT <7:5>    |  0  |  1  |  1  |  0  |  ?  |
+        *   -----+-----+-----+-----+-----+-----+-----+-----+-----+
+        *    5   |  ?  |  1  |  1  | B-  |  1  | B+  |  1  |  ?  |
+        *   -----+-----+-----+-----+-----+-----+-----+-----+-----+
+        *    6   |  O  |  R  |  Y  |  G  |  B  | BSS |  1  |  1  |
+        *   -----+-----+-----+-----+-----+-----+-----+-----+-----+
+        * All buttons are 0 if pressed
+        *
+        * With Motion+ enabled, the following bits will get invalid:
+        *   Byte |  8  |  7  |  6  |  5  |  4  |  3  |  2  |  1  |
+        *   -----+-----+-----+-----+-----+-----+-----+-----+-----+
+        *    1   |  0  |  0  |              SX <5:1>       |XXXXX|
+        *    2   |  0  |  0  |              SY <5:1>       |XXXXX|
+        *   -----+-----+-----+-----------------------------+-----+
+        *    3   | HPP | NON |         WHICH <5:1>         |  ?  |
+        *   -----+-----+-----+-----+-----+-----+-----+-----+-----+
+        *    4   |   SOFT <7:5>    |  0  |  1  |  1  |  0  |  ?  |
+        *   -----+-----+-----+-----+-----+-----+-----+-----+-----+
+        *    5   |  ?  |  1  |  1  | B-  |  1  | B+  |  1  |XXXXX|
+        *   -----+-----+-----+-----+-----+-----+-----+-----+-----+
+        *    6   |  O  |  R  |  Y  |  G  |  B  | BSS |XXXXX|XXXXX|
+        *   -----+-----+-----+-----+-----+-----+-----+-----+-----+
+        */
+
+       pressure = 7 - (ext[3] >> 5);
+       which = (ext[2] >> 1) & 0x1f;
+       none = !!(ext[2] & 0x40);
+       hhp = !(ext[2] & 0x80);
+       sx = ext[0] & 0x3f;
+       sy = ext[1] & 0x3f;
+       o = !(ext[5] & 0x80);
+       r = !(ext[5] & 0x40);
+       y = !(ext[5] & 0x20);
+       g = !(ext[5] & 0x10);
+       b = !(ext[5] & 0x08);
+       bass = !(ext[5] & 0x04);
+       bm = !(ext[4] & 0x10);
+       bp = !(ext[4] & 0x04);
+
+       wiimod_drums_report_pressure(wdata, none, which, pressure,
+                                    o, &wdata->state.pressure_drums[0],
+                                    ABS_CYMBAL_RIGHT, 0x0e);
+       wiimod_drums_report_pressure(wdata, none, which, pressure,
+                                    r, &wdata->state.pressure_drums[1],
+                                    ABS_TOM_LEFT, 0x19);
+       wiimod_drums_report_pressure(wdata, none, which, pressure,
+                                    y, &wdata->state.pressure_drums[2],
+                                    ABS_CYMBAL_LEFT, 0x11);
+       wiimod_drums_report_pressure(wdata, none, which, pressure,
+                                    g, &wdata->state.pressure_drums[3],
+                                    ABS_TOM_FAR_RIGHT, 0x12);
+       wiimod_drums_report_pressure(wdata, none, which, pressure,
+                                    b, &wdata->state.pressure_drums[4],
+                                    ABS_TOM_RIGHT, 0x0f);
+
+       /* Bass shares pressure with hi-hat (set via hhp) */
+       wiimod_drums_report_pressure(wdata, none, hhp ? 0xff : which, pressure,
+                                    bass, &wdata->state.pressure_drums[5],
+                                    ABS_BASS, 0x1b);
+       /* Hi-hat has no on/off values, just pressure. Force to off/0. */
+       wiimod_drums_report_pressure(wdata, none, hhp ? which : 0xff, pressure,
+                                    0, &wdata->state.pressure_drums[6],
+                                    ABS_HI_HAT, 0x0e);
+
+       input_report_abs(wdata->extension.input, ABS_X, sx - 0x20);
+       input_report_abs(wdata->extension.input, ABS_Y, sy - 0x20);
+
+       input_report_key(wdata->extension.input, BTN_START, bp);
+       input_report_key(wdata->extension.input, BTN_SELECT, bm);
+
+       input_sync(wdata->extension.input);
+}
+
+static int wiimod_drums_open(struct input_dev *dev)
+{
+       struct wiimote_data *wdata = input_get_drvdata(dev);
+       unsigned long flags;
+
+       spin_lock_irqsave(&wdata->state.lock, flags);
+       wdata->state.flags |= WIIPROTO_FLAG_EXT_USED;
+       wiiproto_req_drm(wdata, WIIPROTO_REQ_NULL);
+       spin_unlock_irqrestore(&wdata->state.lock, flags);
+
+       return 0;
+}
+
+static void wiimod_drums_close(struct input_dev *dev)
+{
+       struct wiimote_data *wdata = input_get_drvdata(dev);
+       unsigned long flags;
+
+       spin_lock_irqsave(&wdata->state.lock, flags);
+       wdata->state.flags &= ~WIIPROTO_FLAG_EXT_USED;
+       wiiproto_req_drm(wdata, WIIPROTO_REQ_NULL);
+       spin_unlock_irqrestore(&wdata->state.lock, flags);
+}
+
+static int wiimod_drums_probe(const struct wiimod_ops *ops,
+                             struct wiimote_data *wdata)
+{
+       int ret;
+
+       wdata->extension.input = input_allocate_device();
+       if (!wdata->extension.input)
+               return -ENOMEM;
+
+       input_set_drvdata(wdata->extension.input, wdata);
+       wdata->extension.input->open = wiimod_drums_open;
+       wdata->extension.input->close = wiimod_drums_close;
+       wdata->extension.input->dev.parent = &wdata->hdev->dev;
+       wdata->extension.input->id.bustype = wdata->hdev->bus;
+       wdata->extension.input->id.vendor = wdata->hdev->vendor;
+       wdata->extension.input->id.product = wdata->hdev->product;
+       wdata->extension.input->id.version = wdata->hdev->version;
+       wdata->extension.input->name = WIIMOTE_NAME " Drums";
+
+       set_bit(EV_KEY, wdata->extension.input->evbit);
+       set_bit(BTN_START, wdata->extension.input->keybit);
+       set_bit(BTN_SELECT, wdata->extension.input->keybit);
+
+       set_bit(EV_ABS, wdata->extension.input->evbit);
+       set_bit(ABS_X, wdata->extension.input->absbit);
+       set_bit(ABS_Y, wdata->extension.input->absbit);
+       set_bit(ABS_TOM_LEFT, wdata->extension.input->absbit);
+       set_bit(ABS_TOM_RIGHT, wdata->extension.input->absbit);
+       set_bit(ABS_TOM_FAR_RIGHT, wdata->extension.input->absbit);
+       set_bit(ABS_CYMBAL_LEFT, wdata->extension.input->absbit);
+       set_bit(ABS_CYMBAL_RIGHT, wdata->extension.input->absbit);
+       set_bit(ABS_BASS, wdata->extension.input->absbit);
+       set_bit(ABS_HI_HAT, wdata->extension.input->absbit);
+       input_set_abs_params(wdata->extension.input,
+                            ABS_X, -32, 31, 1, 1);
+       input_set_abs_params(wdata->extension.input,
+                            ABS_Y, -32, 31, 1, 1);
+       input_set_abs_params(wdata->extension.input,
+                            ABS_TOM_LEFT, 0, 7, 0, 0);
+       input_set_abs_params(wdata->extension.input,
+                            ABS_TOM_RIGHT, 0, 7, 0, 0);
+       input_set_abs_params(wdata->extension.input,
+                            ABS_TOM_FAR_RIGHT, 0, 7, 0, 0);
+       input_set_abs_params(wdata->extension.input,
+                            ABS_CYMBAL_LEFT, 0, 7, 0, 0);
+       input_set_abs_params(wdata->extension.input,
+                            ABS_CYMBAL_RIGHT, 0, 7, 0, 0);
+       input_set_abs_params(wdata->extension.input,
+                            ABS_BASS, 0, 7, 0, 0);
+       input_set_abs_params(wdata->extension.input,
+                            ABS_HI_HAT, 0, 7, 0, 0);
+
+       ret = input_register_device(wdata->extension.input);
+       if (ret)
+               goto err_free;
+
+       return 0;
+
+err_free:
+       input_free_device(wdata->extension.input);
+       wdata->extension.input = NULL;
+       return ret;
+}
+
+static void wiimod_drums_remove(const struct wiimod_ops *ops,
+                               struct wiimote_data *wdata)
+{
+       if (!wdata->extension.input)
+               return;
+
+       input_unregister_device(wdata->extension.input);
+       wdata->extension.input = NULL;
+}
+
+static const struct wiimod_ops wiimod_drums = {
+       .flags = 0,
+       .arg = 0,
+       .probe = wiimod_drums_probe,
+       .remove = wiimod_drums_remove,
+       .in_ext = wiimod_drums_in_ext,
+};
+
+/*
+ * Guitar
+ * Guitar-Hero, Rock-Band and other games came bundled with guitars which can
+ * be plugged as extension to a Wiimote.
+ * We create a separate device for guitars and report all information via this
+ * input device.
+ */
+
+static void wiimod_guitar_in_ext(struct wiimote_data *wdata, const __u8 *ext)
+{
+       __u8 sx, sy, tb, wb, bd, bm, bp, bo, br, bb, bg, by, bu;
+
+       /*   Byte |  8  |  7  |  6  |  5  |  4  |  3  |  2  |  1  |
+        *   -----+-----+-----+-----+-----+-----+-----+-----+-----+
+        *    1   |  0  |  0  |              SX <5:0>             |
+        *    2   |  0  |  0  |              SY <5:0>             |
+        *   -----+-----+-----+-----+-----------------------------+
+        *    3   |  0  |  0  |  0  |      TB <4:0>               |
+        *   -----+-----+-----+-----+-----------------------------+
+        *    4   |  0  |  0  |  0  |      WB <4:0>               |
+        *   -----+-----+-----+-----+-----+-----+-----+-----+-----+
+        *    5   |  1  | BD  |  1  | B-  |  1  | B+  |  1  |  1  |
+        *   -----+-----+-----+-----+-----+-----+-----+-----+-----+
+        *    6   | BO  | BR  | BB  | BG  | BY  |  1  |  1  | BU  |
+        *   -----+-----+-----+-----+-----+-----+-----+-----+-----+
+        * All buttons are 0 if pressed
+        *
+        * With Motion+ enabled, the following bits will get invalid:
+        *   Byte |  8  |  7  |  6  |  5  |  4  |  3  |  2  |  1  |
+        *   -----+-----+-----+-----+-----+-----+-----+-----+-----+
+        *    1   |  0  |  0  |              SX <5:1>       |XXXXX|
+        *    2   |  0  |  0  |              SY <5:1>       |XXXXX|
+        *   -----+-----+-----+-----+-----------------------+-----+
+        *    3   |  0  |  0  |  0  |      TB <4:0>               |
+        *   -----+-----+-----+-----+-----------------------------+
+        *    4   |  0  |  0  |  0  |      WB <4:0>               |
+        *   -----+-----+-----+-----+-----+-----+-----+-----+-----+
+        *    5   |  1  | BD  |  1  | B-  |  1  | B+  |  1  |XXXXX|
+        *   -----+-----+-----+-----+-----+-----+-----+-----+-----+
+        *    6   | BO  | BR  | BB  | BG  | BY  |  1  |XXXXX|XXXXX|
+        *   -----+-----+-----+-----+-----+-----+-----+-----+-----+
+        */
+
+       sx = ext[0] & 0x3f;
+       sy = ext[1] & 0x3f;
+       tb = ext[2] & 0x1f;
+       wb = ext[3] & 0x1f;
+       bd = !(ext[4] & 0x40);
+       bm = !(ext[4] & 0x10);
+       bp = !(ext[4] & 0x04);
+       bo = !(ext[5] & 0x80);
+       br = !(ext[5] & 0x40);
+       bb = !(ext[5] & 0x20);
+       bg = !(ext[5] & 0x10);
+       by = !(ext[5] & 0x08);
+       bu = !(ext[5] & 0x01);
+
+       input_report_abs(wdata->extension.input, ABS_X, sx - 0x20);
+       input_report_abs(wdata->extension.input, ABS_Y, sy - 0x20);
+       input_report_abs(wdata->extension.input, ABS_FRET_BOARD, tb);
+       input_report_abs(wdata->extension.input, ABS_WHAMMY_BAR, wb - 0x10);
+
+       input_report_key(wdata->extension.input, BTN_MODE, bm);
+       input_report_key(wdata->extension.input, BTN_START, bp);
+       input_report_key(wdata->extension.input, BTN_STRUM_BAR_UP, bu);
+       input_report_key(wdata->extension.input, BTN_STRUM_BAR_DOWN, bd);
+       input_report_key(wdata->extension.input, BTN_FRET_FAR_UP, bg);
+       input_report_key(wdata->extension.input, BTN_FRET_UP, br);
+       input_report_key(wdata->extension.input, BTN_FRET_MID, by);
+       input_report_key(wdata->extension.input, BTN_FRET_LOW, bb);
+       input_report_key(wdata->extension.input, BTN_FRET_FAR_LOW, bo);
+
+       input_sync(wdata->extension.input);
+}
+
+static int wiimod_guitar_open(struct input_dev *dev)
+{
+       struct wiimote_data *wdata = input_get_drvdata(dev);
+       unsigned long flags;
+
+       spin_lock_irqsave(&wdata->state.lock, flags);
+       wdata->state.flags |= WIIPROTO_FLAG_EXT_USED;
+       wiiproto_req_drm(wdata, WIIPROTO_REQ_NULL);
+       spin_unlock_irqrestore(&wdata->state.lock, flags);
+
+       return 0;
+}
+
+static void wiimod_guitar_close(struct input_dev *dev)
+{
+       struct wiimote_data *wdata = input_get_drvdata(dev);
+       unsigned long flags;
+
+       spin_lock_irqsave(&wdata->state.lock, flags);
+       wdata->state.flags &= ~WIIPROTO_FLAG_EXT_USED;
+       wiiproto_req_drm(wdata, WIIPROTO_REQ_NULL);
+       spin_unlock_irqrestore(&wdata->state.lock, flags);
+}
+
+static int wiimod_guitar_probe(const struct wiimod_ops *ops,
+                              struct wiimote_data *wdata)
+{
+       int ret;
+
+       wdata->extension.input = input_allocate_device();
+       if (!wdata->extension.input)
+               return -ENOMEM;
+
+       input_set_drvdata(wdata->extension.input, wdata);
+       wdata->extension.input->open = wiimod_guitar_open;
+       wdata->extension.input->close = wiimod_guitar_close;
+       wdata->extension.input->dev.parent = &wdata->hdev->dev;
+       wdata->extension.input->id.bustype = wdata->hdev->bus;
+       wdata->extension.input->id.vendor = wdata->hdev->vendor;
+       wdata->extension.input->id.product = wdata->hdev->product;
+       wdata->extension.input->id.version = wdata->hdev->version;
+       wdata->extension.input->name = WIIMOTE_NAME " Guitar";
+
+       set_bit(EV_KEY, wdata->extension.input->evbit);
+       set_bit(BTN_MODE, wdata->extension.input->keybit);
+       set_bit(BTN_START, wdata->extension.input->keybit);
+       set_bit(BTN_FRET_FAR_UP, wdata->extension.input->keybit);
+       set_bit(BTN_FRET_UP, wdata->extension.input->keybit);
+       set_bit(BTN_FRET_MID, wdata->extension.input->keybit);
+       set_bit(BTN_FRET_LOW, wdata->extension.input->keybit);
+       set_bit(BTN_FRET_FAR_LOW, wdata->extension.input->keybit);
+       set_bit(BTN_STRUM_BAR_UP, wdata->extension.input->keybit);
+       set_bit(BTN_STRUM_BAR_DOWN, wdata->extension.input->keybit);
+
+       set_bit(EV_ABS, wdata->extension.input->evbit);
+       set_bit(ABS_X, wdata->extension.input->absbit);
+       set_bit(ABS_Y, wdata->extension.input->absbit);
+       set_bit(ABS_FRET_BOARD, wdata->extension.input->absbit);
+       set_bit(ABS_WHAMMY_BAR, wdata->extension.input->absbit);
+       input_set_abs_params(wdata->extension.input,
+                            ABS_X, -32, 31, 1, 1);
+       input_set_abs_params(wdata->extension.input,
+                            ABS_Y, -32, 31, 1, 1);
+       input_set_abs_params(wdata->extension.input,
+                            ABS_FRET_BOARD, 0, 0x1f, 1, 1);
+       input_set_abs_params(wdata->extension.input,
+                            ABS_WHAMMY_BAR, 0, 0x0f, 1, 1);
+
+       ret = input_register_device(wdata->extension.input);
+       if (ret)
+               goto err_free;
+
+       return 0;
+
+err_free:
+       input_free_device(wdata->extension.input);
+       wdata->extension.input = NULL;
+       return ret;
+}
+
+static void wiimod_guitar_remove(const struct wiimod_ops *ops,
+                                struct wiimote_data *wdata)
+{
+       if (!wdata->extension.input)
+               return;
+
+       input_unregister_device(wdata->extension.input);
+       wdata->extension.input = NULL;
+}
+
+static const struct wiimod_ops wiimod_guitar = {
+       .flags = 0,
+       .arg = 0,
+       .probe = wiimod_guitar_probe,
+       .remove = wiimod_guitar_remove,
+       .in_ext = wiimod_guitar_in_ext,
+};
+
 /*
  * Builtin Motion Plus
  * This module simply sets the WIIPROTO_FLAG_BUILTIN_MP protocol flag which
@@ -2083,4 +2473,6 @@ const struct wiimod_ops *wiimod_ext_table[WIIMOTE_EXT_NUM] = {
        [WIIMOTE_EXT_CLASSIC_CONTROLLER] = &wiimod_classic,
        [WIIMOTE_EXT_BALANCE_BOARD] = &wiimod_bboard,
        [WIIMOTE_EXT_PRO_CONTROLLER] = &wiimod_pro,
+       [WIIMOTE_EXT_GUITAR_HERO_DRUMS] = &wiimod_drums,
+       [WIIMOTE_EXT_GUITAR_HERO_GUITAR] = &wiimod_guitar,
 };
index f1474f372c0bba1c56b3f7bd0c5eda82be29ef85..379cdfb6bd258bea39c04341cf8d497b206c730e 100644 (file)
@@ -88,6 +88,8 @@ enum wiimote_exttype {
        WIIMOTE_EXT_CLASSIC_CONTROLLER,
        WIIMOTE_EXT_BALANCE_BOARD,
        WIIMOTE_EXT_PRO_CONTROLLER,
+       WIIMOTE_EXT_GUITAR_HERO_DRUMS,
+       WIIMOTE_EXT_GUITAR_HERO_GUITAR,
        WIIMOTE_EXT_NUM,
 };
 
@@ -135,6 +137,7 @@ struct wiimote_state {
 
        /* calibration data */
        __u16 calib_bboard[4][3];
+       __u8 pressure_drums[7];
 };
 
 struct wiimote_data {
index e4cddeccd6b51691bffc955a62569ead5e6d480e..1a660bd97ab2118f092403c71e237f620f6671ff 100644 (file)
@@ -169,7 +169,7 @@ 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);
+       zc = devm_kzalloc(&hdev->dev, sizeof(*zc), GFP_KERNEL);
        if (zc == NULL) {
                hid_err(hdev, "can't alloc descriptor\n");
                return -ENOMEM;
@@ -180,28 +180,16 @@ static int zc_probe(struct hid_device *hdev, const struct hid_device_id *id)
        ret = hid_parse(hdev);
        if (ret) {
                hid_err(hdev, "parse failed\n");
-               goto err_free;
+               return ret;
        }
 
        ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
        if (ret) {
                hid_err(hdev, "hw start failed\n");
-               goto err_free;
+               return ret;
        }
 
        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);
-       kfree(zc);
 }
 
 static const struct hid_device_id zc_devices[] = {
@@ -217,7 +205,6 @@ static struct hid_driver zc_driver = {
        .input_mapping = zc_input_mapping,
        .raw_event = zc_raw_event,
        .probe = zc_probe,
-       .remove = zc_remove,
 };
 module_hid_driver(zc_driver);
 
index 3cb7d966da9ee50f38651f3c055a7d8eff7f0189..c1336193b04ba3deb92c3edf2468551f3f6933a9 100644 (file)
@@ -35,6 +35,7 @@
 #include <linux/hid.h>
 #include <linux/mutex.h>
 #include <linux/acpi.h>
+#include <linux/of.h>
 
 #include <linux/i2c/i2c-hid.h>
 
@@ -756,29 +757,6 @@ static int i2c_hid_power(struct hid_device *hid, int lvl)
        return ret;
 }
 
-static int i2c_hid_hidinput_input_event(struct input_dev *dev,
-               unsigned int type, unsigned int code, int value)
-{
-       struct hid_device *hid = input_get_drvdata(dev);
-       struct hid_field *field;
-       int offset;
-
-       if (type == EV_FF)
-               return input_ff_event(dev, type, code, value);
-
-       if (type != EV_LED)
-               return -1;
-
-       offset = hidinput_find_field(hid, type, code, &field);
-
-       if (offset == -1) {
-               hid_warn(dev, "event field not found\n");
-               return -1;
-       }
-
-       return hid_set_field(field, offset, value);
-}
-
 static struct hid_ll_driver i2c_hid_ll_driver = {
        .parse = i2c_hid_parse,
        .start = i2c_hid_start,
@@ -787,7 +765,6 @@ static struct hid_ll_driver i2c_hid_ll_driver = {
        .close = i2c_hid_close,
        .power = i2c_hid_power,
        .request = i2c_hid_request,
-       .hidinput_input_event = i2c_hid_hidinput_input_event,
 };
 
 static int i2c_hid_init_irq(struct i2c_client *client)
@@ -897,8 +874,9 @@ static int i2c_hid_acpi_pdata(struct i2c_client *client,
        params[1].integer.value = 1;
        params[2].type = ACPI_TYPE_INTEGER;
        params[2].integer.value = 1; /* HID function */
-       params[3].type = ACPI_TYPE_INTEGER;
-       params[3].integer.value = 0;
+       params[3].type = ACPI_TYPE_PACKAGE;
+       params[3].package.count = 0;
+       params[3].package.elements = NULL;
 
        if (ACPI_FAILURE(acpi_evaluate_object(handle, "_DSM", &input, &buf))) {
                dev_err(&client->dev, "device _DSM execution failed\n");
@@ -933,6 +911,42 @@ static inline int i2c_hid_acpi_pdata(struct i2c_client *client,
 }
 #endif
 
+#ifdef CONFIG_OF
+static int i2c_hid_of_probe(struct i2c_client *client,
+               struct i2c_hid_platform_data *pdata)
+{
+       struct device *dev = &client->dev;
+       u32 val;
+       int ret;
+
+       ret = of_property_read_u32(dev->of_node, "hid-descr-addr", &val);
+       if (ret) {
+               dev_err(&client->dev, "HID register address not provided\n");
+               return -ENODEV;
+       }
+       if (val >> 16) {
+               dev_err(&client->dev, "Bad HID register address: 0x%08x\n",
+                       val);
+               return -EINVAL;
+       }
+       pdata->hid_descriptor_address = val;
+
+       return 0;
+}
+
+static const struct of_device_id i2c_hid_of_match[] = {
+       { .compatible = "hid-over-i2c" },
+       {},
+};
+MODULE_DEVICE_TABLE(of, i2c_hid_of_match);
+#else
+static inline int i2c_hid_of_probe(struct i2c_client *client,
+               struct i2c_hid_platform_data *pdata)
+{
+       return -ENODEV;
+}
+#endif
+
 static int i2c_hid_probe(struct i2c_client *client,
                         const struct i2c_device_id *dev_id)
 {
@@ -954,7 +968,11 @@ static int i2c_hid_probe(struct i2c_client *client,
        if (!ihid)
                return -ENOMEM;
 
-       if (!platform_data) {
+       if (client->dev.of_node) {
+               ret = i2c_hid_of_probe(client, &ihid->pdata);
+               if (ret)
+                       goto err;
+       } else if (!platform_data) {
                ret = i2c_hid_acpi_pdata(client, &ihid->pdata);
                if (ret) {
                        dev_err(&client->dev,
@@ -1095,6 +1113,7 @@ static struct i2c_driver i2c_hid_driver = {
                .owner  = THIS_MODULE,
                .pm     = &i2c_hid_pm,
                .acpi_match_table = ACPI_PTR(i2c_hid_acpi_match),
+               .of_match_table = of_match_ptr(i2c_hid_of_match),
        },
 
        .probe          = i2c_hid_probe,
index 9ab7dfc6c72cf129d5445c7531563d9119c1cf87..5bf2fb785844919bbc27ad20160b98a998102aa5 100644 (file)
@@ -116,30 +116,6 @@ static void uhid_hid_close(struct hid_device *hid)
        uhid_queue_event(uhid, UHID_CLOSE);
 }
 
-static int uhid_hid_input(struct input_dev *input, unsigned int type,
-                         unsigned int code, int value)
-{
-       struct hid_device *hid = input_get_drvdata(input);
-       struct uhid_device *uhid = hid->driver_data;
-       unsigned long flags;
-       struct uhid_event *ev;
-
-       ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
-       if (!ev)
-               return -ENOMEM;
-
-       ev->type = UHID_OUTPUT_EV;
-       ev->u.output_ev.type = type;
-       ev->u.output_ev.code = code;
-       ev->u.output_ev.value = value;
-
-       spin_lock_irqsave(&uhid->qlock, flags);
-       uhid_queue(uhid, ev);
-       spin_unlock_irqrestore(&uhid->qlock, flags);
-
-       return 0;
-}
-
 static int uhid_hid_parse(struct hid_device *hid)
 {
        struct uhid_device *uhid = hid->driver_data;
@@ -273,7 +249,6 @@ static struct hid_ll_driver uhid_hid_driver = {
        .stop = uhid_hid_stop,
        .open = uhid_hid_open,
        .close = uhid_hid_close,
-       .hidinput_input_event = uhid_hid_input,
        .parse = uhid_hid_parse,
 };
 
index ada164e1b3a1fd909c8c6a437dc2cc5cb424a845..44df131d390a0e5cbb92d5701cab2f01a872fc9a 100644 (file)
@@ -648,62 +648,6 @@ static void usbhid_submit_report(struct hid_device *hid, struct hid_report *repo
        spin_unlock_irqrestore(&usbhid->lock, flags);
 }
 
-/* Workqueue routine to send requests to change LEDs */
-static void hid_led(struct work_struct *work)
-{
-       struct usbhid_device *usbhid =
-               container_of(work, struct usbhid_device, led_work);
-       struct hid_device *hid = usbhid->hid;
-       struct hid_field *field;
-       unsigned long flags;
-
-       field = hidinput_get_led_field(hid);
-       if (!field) {
-               hid_warn(hid, "LED event field not found\n");
-               return;
-       }
-
-       spin_lock_irqsave(&usbhid->lock, flags);
-       if (!test_bit(HID_DISCONNECTED, &usbhid->iofl)) {
-               usbhid->ledcount = hidinput_count_leds(hid);
-               hid_dbg(usbhid->hid, "New ledcount = %u\n", usbhid->ledcount);
-               __usbhid_submit_report(hid, field->report, USB_DIR_OUT);
-       }
-       spin_unlock_irqrestore(&usbhid->lock, flags);
-}
-
-static int usb_hidinput_input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
-{
-       struct hid_device *hid = input_get_drvdata(dev);
-       struct usbhid_device *usbhid = hid->driver_data;
-       struct hid_field *field;
-       unsigned long flags;
-       int offset;
-
-       if (type == EV_FF)
-               return input_ff_event(dev, type, code, value);
-
-       if (type != EV_LED)
-               return -1;
-
-       if ((offset = hidinput_find_field(hid, type, code, &field)) == -1) {
-               hid_warn(dev, "event field not found\n");
-               return -1;
-       }
-
-       spin_lock_irqsave(&usbhid->lock, flags);
-       hid_set_field(field, offset, value);
-       spin_unlock_irqrestore(&usbhid->lock, flags);
-
-       /*
-        * Defer performing requested LED action.
-        * This is more likely gather all LED changes into a single URB.
-        */
-       schedule_work(&usbhid->led_work);
-
-       return 0;
-}
-
 static int usbhid_wait_io(struct hid_device *hid)
 {
        struct usbhid_device *usbhid = hid->driver_data;
@@ -806,12 +750,17 @@ void usbhid_init_reports(struct hid_device *hid)
 {
        struct hid_report *report;
        struct usbhid_device *usbhid = hid->driver_data;
+       struct hid_report_enum *report_enum;
        int err, ret;
 
-       list_for_each_entry(report, &hid->report_enum[HID_INPUT_REPORT].report_list, list)
-               usbhid_submit_report(hid, report, USB_DIR_IN);
+       if (!(hid->quirks & HID_QUIRK_NO_INIT_INPUT_REPORTS)) {
+               report_enum = &hid->report_enum[HID_INPUT_REPORT];
+               list_for_each_entry(report, &report_enum->report_list, list)
+                       usbhid_submit_report(hid, report, USB_DIR_IN);
+       }
 
-       list_for_each_entry(report, &hid->report_enum[HID_FEATURE_REPORT].report_list, list)
+       report_enum = &hid->report_enum[HID_FEATURE_REPORT];
+       list_for_each_entry(report, &report_enum->report_list, list)
                usbhid_submit_report(hid, report, USB_DIR_IN);
 
        err = 0;
@@ -856,7 +805,7 @@ static int hid_find_field_early(struct hid_device *hid, unsigned int page,
        return -1;
 }
 
-void usbhid_set_leds(struct hid_device *hid)
+static void usbhid_set_leds(struct hid_device *hid)
 {
        struct hid_field *field;
        int offset;
@@ -866,7 +815,6 @@ void usbhid_set_leds(struct hid_device *hid)
                usbhid_submit_report(hid, field->report, USB_DIR_OUT);
        }
 }
-EXPORT_SYMBOL_GPL(usbhid_set_leds);
 
 /*
  * Traverse the supplied list of reports and find the longest
@@ -1273,7 +1221,6 @@ static struct hid_ll_driver usb_hid_driver = {
        .open = usbhid_open,
        .close = usbhid_close,
        .power = usbhid_power,
-       .hidinput_input_event = usb_hidinput_input_event,
        .request = usbhid_request,
        .wait = usbhid_wait_io,
        .idle = usbhid_idle,
@@ -1367,8 +1314,6 @@ static int usbhid_probe(struct usb_interface *intf, const struct usb_device_id *
        setup_timer(&usbhid->io_retry, hid_retry_timeout, (unsigned long) hid);
        spin_lock_init(&usbhid->lock);
 
-       INIT_WORK(&usbhid->led_work, hid_led);
-
        ret = hid_add_device(hid);
        if (ret) {
                if (ret != -ENODEV)
@@ -1401,7 +1346,6 @@ static void hid_cancel_delayed_stuff(struct usbhid_device *usbhid)
 {
        del_timer_sync(&usbhid->io_retry);
        cancel_work_sync(&usbhid->reset_work);
-       cancel_work_sync(&usbhid->led_work);
 }
 
 static void hid_cease_io(struct usbhid_device *usbhid)
@@ -1521,15 +1465,17 @@ static int hid_suspend(struct usb_interface *intf, pm_message_t message)
        struct usbhid_device *usbhid = hid->driver_data;
        int status = 0;
        bool driver_suspended = false;
+       unsigned int ledcount;
 
        if (PMSG_IS_AUTO(message)) {
+               ledcount = hidinput_count_leds(hid);
                spin_lock_irq(&usbhid->lock);   /* Sync with error handler */
                if (!test_bit(HID_RESET_PENDING, &usbhid->iofl)
                    && !test_bit(HID_CLEAR_HALT, &usbhid->iofl)
                    && !test_bit(HID_OUT_RUNNING, &usbhid->iofl)
                    && !test_bit(HID_CTRL_RUNNING, &usbhid->iofl)
                    && !test_bit(HID_KEYS_PRESSED, &usbhid->iofl)
-                   && (!usbhid->ledcount || ignoreled))
+                   && (!ledcount || ignoreled))
                {
                        set_bit(HID_SUSPENDED, &usbhid->iofl);
                        spin_unlock_irq(&usbhid->lock);
index dbb6af6991350d4e09b2c7ca484411065afdc75c..f633c24ce28b8d8f81d831c37059992914e7c32b 100644 (file)
@@ -92,9 +92,6 @@ struct usbhid_device {
        unsigned int retry_delay;                                       /* Delay length in ms */
        struct work_struct reset_work;                                  /* Task context for resets */
        wait_queue_head_t wait;                                         /* For sleeping */
-       int ledcount;                                                   /* counting the number of active leds */
-
-       struct work_struct led_work;                                    /* Task context for setting LEDs */
 };
 
 #define        hid_to_usb_dev(hid_dev) \
index 729bf27aac8fff7515ad7f2e4f42db2690ba916a..ee1ffc5e19c9fd3d8b2c9ab4c481953455417d4c 100644 (file)
@@ -285,6 +285,7 @@ struct hid_item {
 #define HID_QUIRK_MULTI_INPUT                  0x00000040
 #define HID_QUIRK_HIDINPUT_FORCE               0x00000080
 #define HID_QUIRK_NO_EMPTY_INPUT               0x00000100
+#define HID_QUIRK_NO_INIT_INPUT_REPORTS                0x00000200
 #define HID_QUIRK_SKIP_OUTPUT_REPORTS          0x00010000
 #define HID_QUIRK_FULLSPEED_INTERVAL           0x10000000
 #define HID_QUIRK_NO_INIT_REPORTS              0x20000000
@@ -297,6 +298,7 @@ struct hid_item {
 #define HID_GROUP_GENERIC                      0x0001
 #define HID_GROUP_MULTITOUCH                   0x0002
 #define HID_GROUP_SENSOR_HUB                   0x0003
+#define HID_GROUP_MULTITOUCH_WIN_8             0x0004
 
 /*
  * This is the global environment of the parser. This information is
@@ -458,6 +460,7 @@ struct hid_device {                                                 /* device report descriptor */
        enum hid_type type;                                             /* device type (mouse, kbd, ...) */
        unsigned country;                                               /* HID country */
        struct hid_report_enum report_enum[HID_REPORT_TYPES];
+       struct work_struct led_work;                                    /* delayed LED worker */
 
        struct semaphore driver_lock;                                   /* protects the current driver, except during input */
        struct semaphore driver_input_lock;                             /* protects the current driver */
@@ -534,6 +537,8 @@ static inline void hid_set_drvdata(struct hid_device *hdev, void *data)
 #define HID_GLOBAL_STACK_SIZE 4
 #define HID_COLLECTION_STACK_SIZE 4
 
+#define HID_SCAN_FLAG_MT_WIN_8                 0x00000001
+
 struct hid_parser {
        struct hid_global     global;
        struct hid_global     global_stack[HID_GLOBAL_STACK_SIZE];
@@ -542,6 +547,7 @@ struct hid_parser {
        unsigned              collection_stack[HID_COLLECTION_STACK_SIZE];
        unsigned              collection_stack_ptr;
        struct hid_device    *device;
+       unsigned              scan_flags;
 };
 
 struct hid_class_descriptor {
@@ -992,7 +998,6 @@ int hid_report_raw_event(struct hid_device *hid, int type, u8 *data, int size,
 u32 usbhid_lookup_quirk(const u16 idVendor, const u16 idProduct);
 int usbhid_quirks_init(char **quirks_param);
 void usbhid_quirks_exit(void);
-void usbhid_set_leds(struct hid_device *hid);
 
 #ifdef CONFIG_HID_PID
 int hid_pidff_init(struct hid_device *hid);
index 60e411d764d4d67bf69d52936baf8f844bc097e2..7aa901d920585949b2ecf6c546d65cb004daceea 100644 (file)
@@ -19,7 +19,8 @@
  * @hid_descriptor_address: i2c register where the HID descriptor is stored.
  *
  * Note that it is the responsibility of the platform driver (or the acpi 5.0
- * driver) to setup the irq related to the gpio in the struct i2c_board_info.
+ * driver, or the flattened device tree) to setup the irq related to the gpio in
+ * the struct i2c_board_info.
  * The platform driver should also setup the gpio according to the device:
  *
  * A typical example is the following:
index 45e921401b067b68c9912f82af1c19a1a8c6d048..329aa307cb7727ad3a593aadb99f30e3f77e027b 100644 (file)
@@ -277,7 +277,7 @@ struct pcmcia_device_id {
 #define INPUT_DEVICE_ID_KEY_MIN_INTERESTING    0x71
 #define INPUT_DEVICE_ID_KEY_MAX                0x2ff
 #define INPUT_DEVICE_ID_REL_MAX                0x0f
-#define INPUT_DEVICE_ID_ABS_MAX                0x3f
+#define INPUT_DEVICE_ID_ABS_MAX                0x4f
 #define INPUT_DEVICE_ID_MSC_MAX                0x07
 #define INPUT_DEVICE_ID_LED_MAX                0x0f
 #define INPUT_DEVICE_ID_SND_MAX                0x07
index d584047b072bf28e534f9aaf3445e8132866eb19..76457eef172ae05ce63ca22c17700f2271b8e39e 100644 (file)
@@ -716,6 +716,14 @@ struct input_keymap_entry {
 #define BTN_DPAD_LEFT          0x222
 #define BTN_DPAD_RIGHT         0x223
 
+#define BTN_FRET_FAR_UP                0x224
+#define BTN_FRET_UP            0x225
+#define BTN_FRET_MID           0x226
+#define BTN_FRET_LOW           0x227
+#define BTN_FRET_FAR_LOW       0x228
+#define BTN_STRUM_BAR_UP       0x229
+#define BTN_STRUM_BAR_DOWN     0x22a
+
 #define BTN_TRIGGER_HAPPY              0x2c0
 #define BTN_TRIGGER_HAPPY1             0x2c0
 #define BTN_TRIGGER_HAPPY2             0x2c1
@@ -829,8 +837,21 @@ struct input_keymap_entry {
 #define ABS_MT_TOOL_X          0x3c    /* Center X tool position */
 #define ABS_MT_TOOL_Y          0x3d    /* Center Y tool position */
 
-
-#define ABS_MAX                        0x3f
+/* Drums and guitars (mostly toys) */
+#define ABS_TOM_FAR_LEFT       0x40
+#define ABS_TOM_LEFT           0x41
+#define ABS_TOM_RIGHT          0x42
+#define ABS_TOM_FAR_RIGHT      0x43
+#define ABS_CYMBAL_FAR_LEFT    0x44
+#define ABS_CYMBAL_LEFT                0x45
+#define ABS_CYMBAL_RIGHT       0x46
+#define ABS_CYMBAL_FAR_RIGHT   0x47
+#define ABS_BASS               0x48
+#define ABS_HI_HAT             0x49
+#define ABS_FRET_BOARD         0x4a    /* Guitar fret board, vertical pos */
+#define ABS_WHAMMY_BAR         0x4b    /* Guitar whammy bar (or vibrato) */
+
+#define ABS_MAX                        0x4f
 #define ABS_CNT                        (ABS_MAX+1)
 
 /*
index e9ed951e2b09c11bd010520e5ff0119b201ae1c9..414b74be4da1695bf677e599b8aaf5ec8500679c 100644 (file)
@@ -30,7 +30,7 @@ enum uhid_event_type {
        UHID_OPEN,
        UHID_CLOSE,
        UHID_OUTPUT,
-       UHID_OUTPUT_EV,
+       UHID_OUTPUT_EV,                 /* obsolete! */
        UHID_INPUT,
        UHID_FEATURE,
        UHID_FEATURE_ANSWER,
@@ -69,6 +69,8 @@ struct uhid_output_req {
        __u8 rtype;
 } __attribute__((__packed__));
 
+/* Obsolete! Newer kernels will no longer send these events but instead convert
+ * it into raw output reports via UHID_OUTPUT. */
 struct uhid_output_ev_req {
        __u16 type;
        __u16 code;
index 03ce3c059a5e7b56db61363e6e63e97a19e299d2..7d58a4b8d324caf689ae5d256e1b39c822cd8a52 100644 (file)
@@ -1,14 +1,15 @@
 /*
  * UHID Example
  *
- * Copyright (c) 2012 David Herrmann <dh.herrmann@googlemail.com>
+ * Copyright (c) 2012-2013 David Herrmann <dh.herrmann@gmail.com>
  *
  * The code may be used by anyone for any purpose,
  * and can serve as a starting point for developing
  * applications using uhid.
  */
 
-/* UHID Example
+/*
+ * UHID Example
  * This example emulates a basic 3 buttons mouse with wheel over UHID. Run this
  * program as root and then use the following keys to control the mouse:
  *   q: Quit the application
  *   r: Move wheel up
  *   f: Move wheel down
  *
+ * Additionally to 3 button mouse, 3 keyboard LEDs are also supported (LED_NUML,
+ * LED_CAPSL and LED_SCROLLL). The device doesn't generate any related keyboard
+ * events, though. You need to manually write the EV_LED/LED_XY/1 activation
+ * input event to the evdev device to see it being sent to this device.
+ *
  * If uhid is not available as /dev/uhid, then you can pass a different path as
  * first argument.
  * If <linux/uhid.h> is not installed in /usr, then compile this with:
 #include <unistd.h>
 #include <linux/uhid.h>
 
-/* HID Report Desciptor
- * We emulate a basic 3 button mouse with wheel. This is the report-descriptor
- * as the kernel will parse it:
+/*
+ * HID Report Desciptor
+ * We emulate a basic 3 button mouse with wheel and 3 keyboard LEDs. This is
+ * the report-descriptor as the kernel will parse it:
  *
- * INPUT[INPUT]
+ * INPUT(1)[INPUT]
  *   Field(0)
  *     Physical(GenericDesktop.Pointer)
  *     Application(GenericDesktop.Mouse)
  *     Report Count(3)
  *     Report Offset(8)
  *     Flags( Variable Relative )
+ * OUTPUT(2)[OUTPUT]
+ *   Field(0)
+ *     Application(GenericDesktop.Keyboard)
+ *     Usage(3)
+ *       LED.NumLock
+ *       LED.CapsLock
+ *       LED.ScrollLock
+ *     Logical Minimum(0)
+ *     Logical Maximum(1)
+ *     Report Size(1)
+ *     Report Count(3)
+ *     Report Offset(0)
+ *     Flags( Variable Absolute )
  *
  * This is the mapping that we expect:
  *   Button.0001 ---> Key.LeftBtn
  *   GenericDesktop.X ---> Relative.X
  *   GenericDesktop.Y ---> Relative.Y
  *   GenericDesktop.Wheel ---> Relative.Wheel
+ *   LED.NumLock ---> LED.NumLock
+ *   LED.CapsLock ---> LED.CapsLock
+ *   LED.ScrollLock ---> LED.ScrollLock
  *
  * This information can be verified by reading /sys/kernel/debug/hid/<dev>/rdesc
  * This file should print the same information as showed above.
  */
 
 static unsigned char rdesc[] = {
-       0x05, 0x01, 0x09, 0x02, 0xa1, 0x01, 0x09, 0x01,
-       0xa1, 0x00, 0x05, 0x09, 0x19, 0x01, 0x29, 0x03,
-       0x15, 0x00, 0x25, 0x01, 0x95, 0x03, 0x75, 0x01,
-       0x81, 0x02, 0x95, 0x01, 0x75, 0x05, 0x81, 0x01,
-       0x05, 0x01, 0x09, 0x30, 0x09, 0x31, 0x09, 0x38,
-       0x15, 0x80, 0x25, 0x7f, 0x75, 0x08, 0x95, 0x03,
-       0x81, 0x06, 0xc0, 0xc0,
+       0x05, 0x01,     /* USAGE_PAGE (Generic Desktop) */
+       0x09, 0x02,     /* USAGE (Mouse) */
+       0xa1, 0x01,     /* COLLECTION (Application) */
+       0x09, 0x01,             /* USAGE (Pointer) */
+       0xa1, 0x00,             /* COLLECTION (Physical) */
+       0x85, 0x01,                     /* REPORT_ID (1) */
+       0x05, 0x09,                     /* USAGE_PAGE (Button) */
+       0x19, 0x01,                     /* USAGE_MINIMUM (Button 1) */
+       0x29, 0x03,                     /* USAGE_MAXIMUM (Button 3) */
+       0x15, 0x00,                     /* LOGICAL_MINIMUM (0) */
+       0x25, 0x01,                     /* LOGICAL_MAXIMUM (1) */
+       0x95, 0x03,                     /* REPORT_COUNT (3) */
+       0x75, 0x01,                     /* REPORT_SIZE (1) */
+       0x81, 0x02,                     /* INPUT (Data,Var,Abs) */
+       0x95, 0x01,                     /* REPORT_COUNT (1) */
+       0x75, 0x05,                     /* REPORT_SIZE (5) */
+       0x81, 0x01,                     /* INPUT (Cnst,Var,Abs) */
+       0x05, 0x01,                     /* USAGE_PAGE (Generic Desktop) */
+       0x09, 0x30,                     /* USAGE (X) */
+       0x09, 0x31,                     /* USAGE (Y) */
+       0x09, 0x38,                     /* USAGE (WHEEL) */
+       0x15, 0x81,                     /* LOGICAL_MINIMUM (-127) */
+       0x25, 0x7f,                     /* LOGICAL_MAXIMUM (127) */
+       0x75, 0x08,                     /* REPORT_SIZE (8) */
+       0x95, 0x03,                     /* REPORT_COUNT (3) */
+       0x81, 0x06,                     /* INPUT (Data,Var,Rel) */
+       0xc0,                   /* END_COLLECTION */
+       0xc0,           /* END_COLLECTION */
+       0x05, 0x01,     /* USAGE_PAGE (Generic Desktop) */
+       0x09, 0x06,     /* USAGE (Keyboard) */
+       0xa1, 0x01,     /* COLLECTION (Application) */
+       0x85, 0x02,             /* REPORT_ID (2) */
+       0x05, 0x08,             /* USAGE_PAGE (Led) */
+       0x19, 0x01,             /* USAGE_MINIMUM (1) */
+       0x29, 0x03,             /* USAGE_MAXIMUM (3) */
+       0x15, 0x00,             /* LOGICAL_MINIMUM (0) */
+       0x25, 0x01,             /* LOGICAL_MAXIMUM (1) */
+       0x95, 0x03,             /* REPORT_COUNT (3) */
+       0x75, 0x01,             /* REPORT_SIZE (1) */
+       0x91, 0x02,             /* Output (Data,Var,Abs) */
+       0x95, 0x01,             /* REPORT_COUNT (1) */
+       0x75, 0x05,             /* REPORT_SIZE (5) */
+       0x91, 0x01,             /* Output (Cnst,Var,Abs) */
+       0xc0,           /* END_COLLECTION */
 };
 
 static int uhid_write(int fd, const struct uhid_event *ev)
@@ -140,6 +200,27 @@ static void destroy(int fd)
        uhid_write(fd, &ev);
 }
 
+/* This parses raw output reports sent by the kernel to the device. A normal
+ * uhid program shouldn't do this but instead just forward the raw report.
+ * However, for ducomentational purposes, we try to detect LED events here and
+ * print debug messages for it. */
+static void handle_output(struct uhid_event *ev)
+{
+       /* LED messages are adverised via OUTPUT reports; ignore the rest */
+       if (ev->u.output.rtype != UHID_OUTPUT_REPORT)
+               return;
+       /* LED reports have length 2 bytes */
+       if (ev->u.output.size != 2)
+               return;
+       /* first byte is report-id which is 0x02 for LEDs in our rdesc */
+       if (ev->u.output.data[0] != 0x2)
+               return;
+
+       /* print flags payload */
+       fprintf(stderr, "LED output report received with flags %x\n",
+               ev->u.output.data[1]);
+}
+
 static int event(int fd)
 {
        struct uhid_event ev;
@@ -174,6 +255,7 @@ static int event(int fd)
                break;
        case UHID_OUTPUT:
                fprintf(stderr, "UHID_OUTPUT from uhid-dev\n");
+               handle_output(&ev);
                break;
        case UHID_OUTPUT_EV:
                fprintf(stderr, "UHID_OUTPUT_EV from uhid-dev\n");
@@ -198,18 +280,19 @@ static int send_event(int fd)
 
        memset(&ev, 0, sizeof(ev));
        ev.type = UHID_INPUT;
-       ev.u.input.size = 4;
+       ev.u.input.size = 5;
 
+       ev.u.input.data[0] = 0x1;
        if (btn1_down)
-               ev.u.input.data[0] |= 0x1;
+               ev.u.input.data[1] |= 0x1;
        if (btn2_down)
-               ev.u.input.data[0] |= 0x2;
+               ev.u.input.data[1] |= 0x2;
        if (btn3_down)
-               ev.u.input.data[0] |= 0x4;
+               ev.u.input.data[1] |= 0x4;
 
-       ev.u.input.data[1] = abs_hor;
-       ev.u.input.data[2] = abs_ver;
-       ev.u.input.data[3] = wheel;
+       ev.u.input.data[2] = abs_hor;
+       ev.u.input.data[3] = abs_ver;
+       ev.u.input.data[4] = wheel;
 
        return uhid_write(fd, &ev);
 }