]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
Merge branch 'for-3.12/i2c-hid' into for-next
authorJiri Kosina <jkosina@suse.cz>
Tue, 20 Aug 2013 10:27:00 +0000 (12:27 +0200)
committerJiri Kosina <jkosina@suse.cz>
Tue, 20 Aug 2013 10:27:00 +0000 (12:27 +0200)
34 files changed:
Documentation/devicetree/bindings/hid/hid-over-i2c.txt [new file with mode: 0644]
Documentation/hid/uhid.txt
drivers/hid/Kconfig
drivers/hid/Makefile
drivers/hid/hid-a4tech.c
drivers/hid/hid-apple.c
drivers/hid/hid-core.c
drivers/hid/hid-holtekff.c
drivers/hid/hid-ids.h
drivers/hid/hid-input.c
drivers/hid/hid-kye.c
drivers/hid/hid-logitech-dj.c
drivers/hid/hid-magicmouse.c
drivers/hid/hid-multitouch.c
drivers/hid/hid-ntrig.c
drivers/hid/hid-picolcd_debugfs.c
drivers/hid/hid-roccat-arvo.c
drivers/hid/hid-roccat-isku.c
drivers/hid/hid-roccat-kone.c
drivers/hid/hid-roccat-koneplus.c
drivers/hid/hid-roccat-kovaplus.c
drivers/hid/hid-sony.c
drivers/hid/hid-wiimote-core.c
drivers/hid/hid-xinmo.c [new file with mode: 0644]
drivers/hid/hid-zydacron.c
drivers/hid/hidraw.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/uapi/linux/uhid.h
net/bluetooth/hidp/core.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 14ef6ab6979093605784dfe824c03ff931dd108c..3d7c9f67b6d7631504b9fbaed82fff152e295bb0 100644 (file)
@@ -743,6 +743,14 @@ config HID_WIIMOTE
        To compile this driver as a module, choose M here: the
        module will be called hid-wiimote.
 
+config HID_XINMO
+       tristate "Xin-Mo non-fully compliant devices"
+       depends on HID
+       ---help---
+       Support for Xin-Mo devices that are not fully compliant with the HID
+       standard. Currently only supports the Xin-Mo Dual Arcade. Say Y here
+       if you have a Xin-Mo Dual Arcade controller.
+
 config HID_ZEROPLUS
        tristate "Zeroplus based game controller support"
        depends on HID
index 6f687287e2125168fbfa46ab0f8d9384a08dc797..a959f4aecaf5754d1fd9499b1bad386e57615df5 100644 (file)
@@ -110,6 +110,7 @@ obj-$(CONFIG_HID_TIVO)              += hid-tivo.o
 obj-$(CONFIG_HID_TOPSEED)      += hid-topseed.o
 obj-$(CONFIG_HID_TWINHAN)      += hid-twinhan.o
 obj-$(CONFIG_HID_UCLOGIC)      += hid-uclogic.o
+obj-$(CONFIG_HID_XINMO)                += hid-xinmo.o
 obj-$(CONFIG_HID_ZEROPLUS)     += hid-zpff.o
 obj-$(CONFIG_HID_ZYDACRON)     += hid-zydacron.o
 obj-$(CONFIG_HID_WACOM)                += hid-wacom.o
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 36668d1aca8fc2133299e93cf994857d78cbea2e..3efe19f4deaed585548615e1fa1cb4fbc5ffeed7 100644 (file)
@@ -450,7 +450,7 @@ static int hid_parser_local(struct hid_parser *parser, struct hid_item *item)
                        }
                        parser->local.delimiter_depth--;
                }
-               return 1;
+               return 0;
 
        case HID_LOCAL_ITEM_TAG_USAGE:
 
@@ -1128,7 +1128,8 @@ static void hid_output_field(const struct hid_device *hid,
 }
 
 /*
- * Create a report.
+ * Create a report. 'data' has to be allocated using
+ * hid_alloc_report_buf() so that it has proper size.
  */
 
 void hid_output_report(struct hid_report *report, __u8 *data)
@@ -1144,6 +1145,22 @@ void hid_output_report(struct hid_report *report, __u8 *data)
 }
 EXPORT_SYMBOL_GPL(hid_output_report);
 
+/*
+ * Allocator for buffer that is going to be passed to hid_output_report()
+ */
+u8 *hid_alloc_report_buf(struct hid_report *report, gfp_t flags)
+{
+       /*
+        * 7 extra bytes are necessary to achieve proper functionality
+        * of implement() working on 8 byte chunks
+        */
+
+       int len = ((report->size - 1) >> 3) + 1 + (report->id > 0) + 7;
+
+       return kmalloc(len, flags);
+}
+EXPORT_SYMBOL_GPL(hid_alloc_report_buf);
+
 /*
  * Set a field value. The report this field belongs to has to be
  * created and transferred to the device, to set this value in the
@@ -1597,6 +1614,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_KENSINGTON, USB_DEVICE_ID_KS_SLIMBLADE) },
        { HID_USB_DEVICE(USB_VENDOR_ID_KEYTOUCH, USB_DEVICE_ID_KEYTOUCH_IEC) },
        { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_GENIUS_GILA_GAMING_MOUSE) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_GENIUS_GX_IMPERATOR) },
        { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_ERGO_525V) },
        { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_EASYPEN_I405X) },
        { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_MOUSEPEN_I608X) },
@@ -1736,6 +1754,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_MEDIA_TABLET_14_1_INCH) },
        { HID_USB_DEVICE(USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_SIRIUS_BATTERY_FREE_TABLET) },
        { HID_USB_DEVICE(USB_VENDOR_ID_X_TENSIONS, USB_DEVICE_ID_SPEEDLINK_VAD_CEZANNE) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_XIN_MO, USB_DEVICE_ID_XIN_MO_DUAL_ARCADE) },
        { 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) },
index 9a8f051245258973f53ad84f8debef8b2f6db7e9..9325545fc3ae1cac4e3919c1120af6841590d4f4 100644 (file)
@@ -98,7 +98,7 @@ static void holtekff_send(struct holtekff_device *holtekff,
                holtekff->field->value[i] = data[i];
        }
 
-       dbg_hid("sending %*ph\n", 7, data);
+       dbg_hid("sending %7ph\n", data);
 
        hid_hw_request(hid, holtekff->field->report, HID_REQ_SET_REPORT);
 }
index ffe4c7ae3340150cdcfb8c9f3db9c241422cf8eb..4f01a52c98abda7f60252debf6dacaa53c80ab35 100644 (file)
 #define USB_VENDOR_ID_KYE              0x0458
 #define USB_DEVICE_ID_KYE_ERGO_525V    0x0087
 #define USB_DEVICE_ID_GENIUS_GILA_GAMING_MOUSE 0x0138
+#define USB_DEVICE_ID_GENIUS_GX_IMPERATOR      0x4018
 #define USB_DEVICE_ID_KYE_GPEN_560     0x5003
 #define USB_DEVICE_ID_KYE_EASYPEN_I405X        0x5010
 #define USB_DEVICE_ID_KYE_MOUSEPEN_I608X       0x5011
 #define USB_VENDOR_ID_XAT      0x2505
 #define USB_DEVICE_ID_XAT_CSR  0x0220
 
+#define USB_VENDOR_ID_XIN_MO                   0x16c0
+#define USB_DEVICE_ID_XIN_MO_DUAL_ARCADE       0x05e1
+
 #define USB_VENDOR_ID_XIROKU           0x1477
 #define USB_DEVICE_ID_XIROKU_SPX       0x1006
 #define USB_DEVICE_ID_XIROKU_MPX       0x1007
index 7480799e535cb229a8bae89cf3795d1a5e91b738..308eee8fc7c3b1145b62b5508404d24655c355f9 100644 (file)
@@ -1137,6 +1137,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);
@@ -1183,7 +1251,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;
@@ -1278,6 +1349,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++) {
@@ -1379,6 +1451,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 1e2ee2aa84a023fc5e4412c7fe8c04666a3e6a8e..73845120295eba6f678679715c9ca3f97917a643 100644 (file)
@@ -268,6 +268,26 @@ static __u8 easypen_m610x_rdesc_fixed[] = {
        0xC0                          /*  End Collection                  */
 };
 
+static __u8 *kye_consumer_control_fixup(struct hid_device *hdev, __u8 *rdesc,
+               unsigned int *rsize, int offset, const char *device_name) {
+       /*
+        * the fixup that need to be done:
+        *   - change Usage Maximum in the Comsumer Control
+        *     (report ID 3) to a reasonable value
+        */
+       if (*rsize >= offset + 31 &&
+           /* Usage Page (Consumer Devices) */
+           rdesc[offset] == 0x05 && rdesc[offset + 1] == 0x0c &&
+           /* Usage (Consumer Control) */
+           rdesc[offset + 2] == 0x09 && rdesc[offset + 3] == 0x01 &&
+           /*   Usage Maximum > 12287 */
+           rdesc[offset + 10] == 0x2a && rdesc[offset + 12] > 0x2f) {
+               hid_info(hdev, "fixing up %s report descriptor\n", device_name);
+               rdesc[offset + 12] = 0x2f;
+       }
+       return rdesc;
+}
+
 static __u8 *kye_report_fixup(struct hid_device *hdev, __u8 *rdesc,
                unsigned int *rsize)
 {
@@ -315,23 +335,12 @@ static __u8 *kye_report_fixup(struct hid_device *hdev, __u8 *rdesc,
                }
                break;
        case USB_DEVICE_ID_GENIUS_GILA_GAMING_MOUSE:
-               /*
-                * the fixup that need to be done:
-                *   - change Usage Maximum in the Comsumer Control
-                *     (report ID 3) to a reasonable value
-                */
-               if (*rsize >= 135 &&
-                       /* Usage Page (Consumer Devices) */
-                       rdesc[104] == 0x05 && rdesc[105] == 0x0c &&
-                       /* Usage (Consumer Control) */
-                       rdesc[106] == 0x09 && rdesc[107] == 0x01 &&
-                       /*   Usage Maximum > 12287 */
-                       rdesc[114] == 0x2a && rdesc[116] > 0x2f) {
-                       hid_info(hdev,
-                                "fixing up Genius Gila Gaming Mouse "
-                                "report descriptor\n");
-                       rdesc[116] = 0x2f;
-               }
+               rdesc = kye_consumer_control_fixup(hdev, rdesc, rsize, 104,
+                                       "Genius Gila Gaming Mouse");
+               break;
+       case USB_DEVICE_ID_GENIUS_GX_IMPERATOR:
+               rdesc = kye_consumer_control_fixup(hdev, rdesc, rsize, 83,
+                                       "Genius Gx Imperator Keyboard");
                break;
        }
        return rdesc;
@@ -428,6 +437,8 @@ static const struct hid_device_id kye_devices[] = {
                                USB_DEVICE_ID_KYE_EASYPEN_M610X) },
        { HID_USB_DEVICE(USB_VENDOR_ID_KYE,
                                USB_DEVICE_ID_GENIUS_GILA_GAMING_MOUSE) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_KYE,
+                               USB_DEVICE_ID_GENIUS_GX_IMPERATOR) },
        { }
 };
 MODULE_DEVICE_TABLE(hid, kye_devices);
index cd33084c78602146d42efca60e358d08f00da219..7800b141056243400bfa316b7289e2c8431aa82a 100644 (file)
@@ -619,7 +619,7 @@ static int logi_dj_ll_input_event(struct input_dev *dev, unsigned int type,
 
        struct hid_field *field;
        struct hid_report *report;
-       unsigned char data[8];
+       unsigned char *data;
        int offset;
 
        dbg_hid("%s: %s, type:%d | code:%d | value:%d\n",
@@ -635,6 +635,13 @@ static int logi_dj_ll_input_event(struct input_dev *dev, unsigned int type,
                return -1;
        }
        hid_set_field(field, offset, value);
+
+       data = hid_alloc_report_buf(field->report, GFP_ATOMIC);
+       if (!data) {
+               dev_warn(&dev->dev, "failed to allocate report buf memory\n");
+               return -1;
+       }
+
        hid_output_report(field->report, &data[0]);
 
        output_report_enum = &dj_rcv_hiddev->report_enum[HID_OUTPUT_REPORT];
@@ -645,8 +652,9 @@ static int logi_dj_ll_input_event(struct input_dev *dev, unsigned int type,
 
        hid_hw_request(dj_rcv_hiddev, report, HID_REQ_SET_REPORT);
 
-       return 0;
+       kfree(data);
 
+       return 0;
 }
 
 static int logi_dj_ll_start(struct hid_device *hid)
@@ -801,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;
        }
 
@@ -821,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:
@@ -863,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 5bc37343eb22b3de7f3cca6163c6f1fd9a10dd4b..3b43d1cfa9368609302de46a73658779199d446f 100644 (file)
@@ -36,7 +36,7 @@ MODULE_PARM_DESC(emulate_scroll_wheel, "Emulate a scroll wheel");
 static unsigned int scroll_speed = 32;
 static int param_set_scroll_speed(const char *val, struct kernel_param *kp) {
        unsigned long speed;
-       if (!val || strict_strtoul(val, 0, &speed) || speed > 63)
+       if (!val || kstrtoul(val, 0, &speed) || speed > 63)
                return -EINVAL;
        scroll_speed = speed;
        return 0;
@@ -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..0fe00e2552f23aebbdbeb408ef18a7be46d115c9 100644 (file)
@@ -261,17 +261,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)
@@ -415,13 +404,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 +910,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 +937,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 +958,7 @@ 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);
+       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 +971,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 +983,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 +1023,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[] = {
index ef95102515e4d499143dd02a831481902d674b1e..98d1fdf7d8cd0d2e3d5c7ae6b240e15085a951d7 100644 (file)
@@ -237,7 +237,7 @@ static ssize_t set_min_width(struct device *dev,
 
        unsigned long val;
 
-       if (strict_strtoul(buf, 0, &val))
+       if (kstrtoul(buf, 0, &val))
                return -EINVAL;
 
        if (val > nd->sensor_physical_width)
@@ -272,7 +272,7 @@ static ssize_t set_min_height(struct device *dev,
 
        unsigned long val;
 
-       if (strict_strtoul(buf, 0, &val))
+       if (kstrtoul(buf, 0, &val))
                return -EINVAL;
 
        if (val > nd->sensor_physical_height)
@@ -306,7 +306,7 @@ static ssize_t set_activate_slack(struct device *dev,
 
        unsigned long val;
 
-       if (strict_strtoul(buf, 0, &val))
+       if (kstrtoul(buf, 0, &val))
                return -EINVAL;
 
        if (val > 0x7f)
@@ -341,7 +341,7 @@ static ssize_t set_activation_width(struct device *dev,
 
        unsigned long val;
 
-       if (strict_strtoul(buf, 0, &val))
+       if (kstrtoul(buf, 0, &val))
                return -EINVAL;
 
        if (val > nd->sensor_physical_width)
@@ -377,7 +377,7 @@ static ssize_t set_activation_height(struct device *dev,
 
        unsigned long val;
 
-       if (strict_strtoul(buf, 0, &val))
+       if (kstrtoul(buf, 0, &val))
                return -EINVAL;
 
        if (val > nd->sensor_physical_height)
@@ -411,7 +411,7 @@ static ssize_t set_deactivate_slack(struct device *dev,
 
        unsigned long val;
 
-       if (strict_strtoul(buf, 0, &val))
+       if (kstrtoul(buf, 0, &val))
                return -EINVAL;
 
        /*
index 59ab8e157e6b249d025ea26d4bd0ba4b2bb7f227..024cdf3c2297f91d6288cd13cf75e3a4c4881991 100644 (file)
@@ -394,7 +394,7 @@ static void dump_buff_as_hex(char *dst, size_t dst_sz, const u8 *data,
 void picolcd_debug_out_report(struct picolcd_data *data,
                struct hid_device *hdev, struct hid_report *report)
 {
-       u8 raw_data[70];
+       u8 *raw_data;
        int raw_size = (report->size >> 3) + 1;
        char *buff;
 #define BUFF_SZ 256
@@ -407,20 +407,20 @@ void picolcd_debug_out_report(struct picolcd_data *data,
        if (!buff)
                return;
 
-       snprintf(buff, BUFF_SZ, "\nout report %d (size %d) =  ",
-                       report->id, raw_size);
-       hid_debug_event(hdev, buff);
-       if (raw_size + 5 > sizeof(raw_data)) {
+       raw_data = hid_alloc_report_buf(report, GFP_ATOMIC);
+       if (!raw_data) {
                kfree(buff);
-               hid_debug_event(hdev, " TOO BIG\n");
                return;
-       } else {
-               raw_data[0] = report->id;
-               hid_output_report(report, raw_data);
-               dump_buff_as_hex(buff, BUFF_SZ, raw_data, raw_size);
-               hid_debug_event(hdev, buff);
        }
 
+       snprintf(buff, BUFF_SZ, "\nout report %d (size %d) =  ",
+                       report->id, raw_size);
+       hid_debug_event(hdev, buff);
+       raw_data[0] = report->id;
+       hid_output_report(report, raw_data);
+       dump_buff_as_hex(buff, BUFF_SZ, raw_data, raw_size);
+       hid_debug_event(hdev, buff);
+
        switch (report->id) {
        case REPORT_LED_STATE:
                /* 1 data byte with GPO state */
@@ -644,6 +644,7 @@ void picolcd_debug_out_report(struct picolcd_data *data,
                break;
        }
        wake_up_interruptible(&hdev->debug_wait);
+       kfree(raw_data);
        kfree(buff);
 }
 
index 327f9b8ed1f4ea3cea3e89166c29570a9539d306..071ee9e2fd9fea5c4d40165e60e6f1b71e5bd7a4 100644 (file)
@@ -59,7 +59,7 @@ static ssize_t arvo_sysfs_set_mode_key(struct device *dev,
        unsigned long state;
        int retval;
 
-       retval = strict_strtoul(buf, 10, &state);
+       retval = kstrtoul(buf, 10, &state);
        if (retval)
                return retval;
 
@@ -107,7 +107,7 @@ static ssize_t arvo_sysfs_set_key_mask(struct device *dev,
        unsigned long key_mask;
        int retval;
 
-       retval = strict_strtoul(buf, 10, &key_mask);
+       retval = kstrtoul(buf, 10, &key_mask);
        if (retval)
                return retval;
 
@@ -159,7 +159,7 @@ static ssize_t arvo_sysfs_set_actual_profile(struct device *dev,
        unsigned long profile;
        int retval;
 
-       retval = strict_strtoul(buf, 10, &profile);
+       retval = kstrtoul(buf, 10, &profile);
        if (retval)
                return retval;
 
index 8023751d525766ae16b32f8a8943f8c5f9b0796e..5dd0ea4eb4f71ec6cfc210b5a71a8b648a709461 100644 (file)
@@ -82,7 +82,7 @@ static ssize_t isku_sysfs_set_actual_profile(struct device *dev,
        isku = hid_get_drvdata(dev_get_drvdata(dev));
        usb_dev = interface_to_usbdev(to_usb_interface(dev));
 
-       retval = strict_strtoul(buf, 10, &profile);
+       retval = kstrtoul(buf, 10, &profile);
        if (retval)
                return retval;
 
index 7fae070788fa2e4b03fb9281e792aaf9e24065a4..00ab287f73849b94d85c3d4bf603733273396fc6 100644 (file)
@@ -456,7 +456,7 @@ static ssize_t kone_sysfs_set_tcu(struct device *dev,
        kone = hid_get_drvdata(dev_get_drvdata(dev));
        usb_dev = interface_to_usbdev(to_usb_interface(dev));
 
-       retval = strict_strtoul(buf, 10, &state);
+       retval = kstrtoul(buf, 10, &state);
        if (retval)
                return retval;
 
@@ -545,7 +545,7 @@ static ssize_t kone_sysfs_set_startup_profile(struct device *dev,
        kone = hid_get_drvdata(dev_get_drvdata(dev));
        usb_dev = interface_to_usbdev(to_usb_interface(dev));
 
-       retval = strict_strtoul(buf, 10, &new_startup_profile);
+       retval = kstrtoul(buf, 10, &new_startup_profile);
        if (retval)
                return retval;
 
index 6a48fa3c7da913e487e5aa0b1538ba5aff19bbb1..26b9663ddf4746ce1590733745d77f512c46d8c0 100644 (file)
@@ -246,7 +246,7 @@ static ssize_t koneplus_sysfs_set_actual_profile(struct device *dev,
        koneplus = hid_get_drvdata(dev_get_drvdata(dev));
        usb_dev = interface_to_usbdev(to_usb_interface(dev));
 
-       retval = strict_strtoul(buf, 10, &profile);
+       retval = kstrtoul(buf, 10, &profile);
        if (retval)
                return retval;
 
index b8b37789b864bbeb3c4de24047658172518b25ec..c2a17e45c99cb6fa49443e68c0b37fe9f7839f99 100644 (file)
@@ -282,7 +282,7 @@ static ssize_t kovaplus_sysfs_set_actual_profile(struct device *dev,
        kovaplus = hid_get_drvdata(dev_get_drvdata(dev));
        usb_dev = interface_to_usbdev(to_usb_interface(dev));
 
-       retval = strict_strtoul(buf, 10, &profile);
+       retval = kstrtoul(buf, 10, &profile);
        if (retval)
                return retval;
 
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..660209824e5618d827b186ba9cfc1ac201708e5e 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;
                }
diff --git a/drivers/hid/hid-xinmo.c b/drivers/hid/hid-xinmo.c
new file mode 100644 (file)
index 0000000..6153e50
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ *  HID driver for Xin-Mo devices, currently only the Dual Arcade controller.
+ *  Fixes the negative axis event values (the devices sends -2) to match the
+ *  logical axis minimum of the HID report descriptor (the report announces
+ *  -1). It is needed because hid-input discards out of bounds values.
+ *  (This module is based on "hid-saitek" and "hid-lg".)
+ *
+ *  Copyright (c) 2013 Olivier Scherler
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ */
+
+#include <linux/device.h>
+#include <linux/hid.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+
+#include "hid-ids.h"
+
+/*
+ * Fix negative events that are out of bounds.
+ */
+static int xinmo_event(struct hid_device *hdev, struct hid_field *field,
+               struct hid_usage *usage, __s32 value)
+{
+       switch (usage->code) {
+       case ABS_X:
+       case ABS_Y:
+       case ABS_Z:
+       case ABS_RX:
+               if (value < -1) {
+                       input_event(field->hidinput->input, usage->type,
+                               usage->code, -1);
+                       return 1;
+               }
+               break;
+       }
+
+       return 0;
+}
+
+static const struct hid_device_id xinmo_devices[] = {
+       { HID_USB_DEVICE(USB_VENDOR_ID_XIN_MO, USB_DEVICE_ID_XIN_MO_DUAL_ARCADE) },
+       { }
+};
+
+MODULE_DEVICE_TABLE(hid, xinmo_devices);
+
+static struct hid_driver xinmo_driver = {
+       .name = "xinmo",
+       .id_table = xinmo_devices,
+       .event = xinmo_event
+};
+
+static int __init xinmo_init(void)
+{
+       return hid_register_driver(&xinmo_driver);
+}
+
+static void __exit xinmo_exit(void)
+{
+       hid_unregister_driver(&xinmo_driver);
+}
+
+module_init(xinmo_init);
+module_exit(xinmo_exit);
+MODULE_LICENSE("GPL");
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 6f1feb2c2e97b5defb0628d92bfc98a719449685..dbfe300746c65e35bf1ea38c454ba0695f7e0a4e 100644 (file)
@@ -113,7 +113,7 @@ static ssize_t hidraw_send_report(struct file *file, const char __user *buffer,
        __u8 *buf;
        int ret = 0;
 
-       if (!hidraw_table[minor]) {
+       if (!hidraw_table[minor] || !hidraw_table[minor]->exist) {
                ret = -ENODEV;
                goto out;
        }
@@ -261,7 +261,7 @@ static int hidraw_open(struct inode *inode, struct file *file)
        }
 
        mutex_lock(&minors_lock);
-       if (!hidraw_table[minor]) {
+       if (!hidraw_table[minor] || !hidraw_table[minor]->exist) {
                err = -ENODEV;
                goto out_unlock;
        }
@@ -302,39 +302,38 @@ static int hidraw_fasync(int fd, struct file *file, int on)
        return fasync_helper(fd, file, on, &list->fasync);
 }
 
+static void drop_ref(struct hidraw *hidraw, int exists_bit)
+{
+       if (exists_bit) {
+               hid_hw_close(hidraw->hid);
+               hidraw->exist = 0;
+               if (hidraw->open)
+                       wake_up_interruptible(&hidraw->wait);
+       } else {
+               --hidraw->open;
+       }
+
+       if (!hidraw->open && !hidraw->exist) {
+               device_destroy(hidraw_class, MKDEV(hidraw_major, hidraw->minor));
+               hidraw_table[hidraw->minor] = NULL;
+               kfree(hidraw);
+       }
+}
+
 static int hidraw_release(struct inode * inode, struct file * file)
 {
        unsigned int minor = iminor(inode);
-       struct hidraw *dev;
        struct hidraw_list *list = file->private_data;
-       int ret;
-       int i;
 
        mutex_lock(&minors_lock);
-       if (!hidraw_table[minor]) {
-               ret = -ENODEV;
-               goto unlock;
-       }
 
        list_del(&list->node);
-       dev = hidraw_table[minor];
-       if (!--dev->open) {
-               if (list->hidraw->exist) {
-                       hid_hw_power(dev->hid, PM_HINT_NORMAL);
-                       hid_hw_close(dev->hid);
-               } else {
-                       kfree(list->hidraw);
-               }
-       }
-
-       for (i = 0; i < HIDRAW_BUFFER_SIZE; ++i)
-               kfree(list->buffer[i].value);
        kfree(list);
-       ret = 0;
-unlock:
-       mutex_unlock(&minors_lock);
 
-       return ret;
+       drop_ref(hidraw_table[minor], 0);
+
+       mutex_unlock(&minors_lock);
+       return 0;
 }
 
 static long hidraw_ioctl(struct file *file, unsigned int cmd,
@@ -539,18 +538,9 @@ void hidraw_disconnect(struct hid_device *hid)
        struct hidraw *hidraw = hid->hidraw;
 
        mutex_lock(&minors_lock);
-       hidraw->exist = 0;
-
-       device_destroy(hidraw_class, MKDEV(hidraw_major, hidraw->minor));
 
-       hidraw_table[hidraw->minor] = NULL;
+       drop_ref(hidraw, 1);
 
-       if (hidraw->open) {
-               hid_hw_close(hid);
-               wake_up_interruptible(&hidraw->wait);
-       } else {
-               kfree(hidraw);
-       }
        mutex_unlock(&minors_lock);
 }
 EXPORT_SYMBOL_GPL(hidraw_disconnect);
index d2e0eea2bf7975352292b9f95a92c6f8bef0c31f..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)
@@ -824,8 +801,8 @@ static int i2c_hid_fetch_hid_descriptor(struct i2c_hid *ihid)
         * bytes 2-3 -> bcdVersion (has to be 1.00) */
        ret = i2c_hid_command(client, &hid_descr_cmd, ihid->hdesc_buffer, 4);
 
-       i2c_hid_dbg(ihid, "%s, ihid->hdesc_buffer: %*ph\n",
-                       __func__, 4, ihid->hdesc_buffer);
+       i2c_hid_dbg(ihid, "%s, ihid->hdesc_buffer: %4ph\n", __func__,
+                       ihid->hdesc_buffer);
 
        if (ret) {
                dev_err(&client->dev,
@@ -934,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)
 {
@@ -955,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,
@@ -1096,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 fc307e0422afc92c31bfac65d410244d5859e804..f53f2d52e677b4f80b1bd454e673f2ec0a7ce816 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 99418285222cf118cbc09e4d9029c80ba3493fcf..bd38cdfbbba64fbb9fe76b6307f436f3f63f02f9 100644 (file)
@@ -535,7 +535,6 @@ static void __usbhid_submit_report(struct hid_device *hid, struct hid_report *re
 {
        int head;
        struct usbhid_device *usbhid = hid->driver_data;
-       int len = ((report->size - 1) >> 3) + 1 + (report->id > 0);
 
        if ((hid->quirks & HID_QUIRK_NOGET) && dir == USB_DIR_IN)
                return;
@@ -546,7 +545,7 @@ static void __usbhid_submit_report(struct hid_device *hid, struct hid_report *re
                        return;
                }
 
-               usbhid->out[usbhid->outhead].raw_report = kmalloc(len, GFP_ATOMIC);
+               usbhid->out[usbhid->outhead].raw_report = hid_alloc_report_buf(report, GFP_ATOMIC);
                if (!usbhid->out[usbhid->outhead].raw_report) {
                        hid_warn(hid, "output queueing failed\n");
                        return;
@@ -595,7 +594,7 @@ static void __usbhid_submit_report(struct hid_device *hid, struct hid_report *re
        }
 
        if (dir == USB_DIR_OUT) {
-               usbhid->ctrl[usbhid->ctrlhead].raw_report = kmalloc(len, GFP_ATOMIC);
+               usbhid->ctrl[usbhid->ctrlhead].raw_report = hid_alloc_report_buf(report, GFP_ATOMIC);
                if (!usbhid->ctrl[usbhid->ctrlhead].raw_report) {
                        hid_warn(hid, "control queueing failed\n");
                        return;
@@ -649,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;
@@ -857,7 +800,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;
@@ -867,7 +810,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
@@ -1274,7 +1216,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,
@@ -1368,8 +1309,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)
@@ -1402,7 +1341,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)
@@ -1522,15 +1460,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 0c48991b0402d0d93110b8a4fa9cd42d615279c2..5a4e789b9e978dcbb7065bdd167dc7ab64f2c38a 100644 (file)
@@ -456,6 +456,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 */
@@ -744,6 +745,7 @@ struct hid_field *hidinput_get_led_field(struct hid_device *hid);
 unsigned int hidinput_count_leds(struct hid_device *hid);
 __s32 hidinput_calc_abs_res(const struct hid_field *field, __u16 code);
 void hid_output_report(struct hid_report *report, __u8 *data);
+u8 *hid_alloc_report_buf(struct hid_report *report, gfp_t flags);
 struct hid_device *hid_allocate_device(void);
 struct hid_report *hid_register_report(struct hid_device *device, unsigned type, unsigned id);
 int hid_parse_report(struct hid_device *hid, __u8 *start, unsigned size);
@@ -989,7 +991,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 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 0c699cdc3696edbdf7e7c3d3e213a88979da662e..d38ab152700698baf92f3e7dc128495f3beca713 100644 (file)
@@ -225,17 +225,22 @@ static void hidp_input_report(struct hidp_session *session, struct sk_buff *skb)
 
 static int hidp_send_report(struct hidp_session *session, struct hid_report *report)
 {
-       unsigned char buf[32], hdr;
-       int rsize;
+       unsigned char hdr;
+       u8 *buf;
+       int rsize, ret;
 
-       rsize = ((report->size - 1) >> 3) + 1 + (report->id > 0);
-       if (rsize > sizeof(buf))
+       buf = hid_alloc_report_buf(report, GFP_ATOMIC);
+       if (!buf)
                return -EIO;
 
        hid_output_report(report, buf);
        hdr = HIDP_TRANS_DATA | HIDP_DATA_RTYPE_OUPUT;
 
-       return hidp_send_intr_message(session, hdr, buf, rsize);
+       rsize = ((report->size - 1) >> 3) + 1 + (report->id > 0);
+       ret = hidp_send_intr_message(session, hdr, buf, rsize);
+
+       kfree(buf);
+       return ret;
 }
 
 static int hidp_get_raw_report(struct hid_device *hid,