aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/hid/Kconfig10
-rw-r--r--drivers/hid/Makefile2
-rw-r--r--drivers/hid/hid-core.c4
-rw-r--r--drivers/hid/hid-elo.c273
-rw-r--r--drivers/hid/hid-holtek-mouse.c77
-rw-r--r--drivers/hid/hid-ids.h2
-rw-r--r--drivers/hid/hid-input.c4
-rw-r--r--net/bluetooth/hidp/core.c56
-rw-r--r--net/bluetooth/hidp/hidp.h2
9 files changed, 419 insertions, 11 deletions
diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index fb52f3f6de80..b93e299eb272 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -217,6 +217,13 @@ config HID_ELECOM
217 ---help--- 217 ---help---
218 Support for the ELECOM BM084 (bluetooth mouse). 218 Support for the ELECOM BM084 (bluetooth mouse).
219 219
220config HID_ELO
221 tristate "ELO USB 4000/4500 touchscreen"
222 depends on USB_HID
223 ---help---
224 Support for the ELO USB 4000/4500 touchscreens. Note that this is for
225 different devices than those handled by CONFIG_TOUCHSCREEN_USB_ELO.
226
220config HID_EZKEY 227config HID_EZKEY
221 tristate "Ezkey BTC 8193 keyboard" if EXPERT 228 tristate "Ezkey BTC 8193 keyboard" if EXPERT
222 depends on HID 229 depends on HID
@@ -231,6 +238,9 @@ config HID_HOLTEK
231 Support for Holtek based devices: 238 Support for Holtek based devices:
232 - Holtek On Line Grip based game controller 239 - Holtek On Line Grip based game controller
233 - Trust GXT 18 Gaming Keyboard 240 - Trust GXT 18 Gaming Keyboard
241 - Sharkoon Drakonia / Perixx MX-2000 gaming mice
242 - Tracer Sniper TRM-503 / NOVA Gaming Slider X200 /
243 Zalman ZM-GM1
234 244
235config HOLTEK_FF 245config HOLTEK_FF
236 bool "Holtek On Line Grip force feedback support" 246 bool "Holtek On Line Grip force feedback support"
diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile
index 2065694f57ab..7a0340ace186 100644
--- a/drivers/hid/Makefile
+++ b/drivers/hid/Makefile
@@ -48,9 +48,11 @@ obj-$(CONFIG_HID_CYPRESS) += hid-cypress.o
48obj-$(CONFIG_HID_DRAGONRISE) += hid-dr.o 48obj-$(CONFIG_HID_DRAGONRISE) += hid-dr.o
49obj-$(CONFIG_HID_EMS_FF) += hid-emsff.o 49obj-$(CONFIG_HID_EMS_FF) += hid-emsff.o
50obj-$(CONFIG_HID_ELECOM) += hid-elecom.o 50obj-$(CONFIG_HID_ELECOM) += hid-elecom.o
51obj-$(CONFIG_HID_ELO) += hid-elo.o
51obj-$(CONFIG_HID_EZKEY) += hid-ezkey.o 52obj-$(CONFIG_HID_EZKEY) += hid-ezkey.o
52obj-$(CONFIG_HID_GYRATION) += hid-gyration.o 53obj-$(CONFIG_HID_GYRATION) += hid-gyration.o
53obj-$(CONFIG_HID_HOLTEK) += hid-holtek-kbd.o 54obj-$(CONFIG_HID_HOLTEK) += hid-holtek-kbd.o
55obj-$(CONFIG_HID_HOLTEK) += hid-holtek-mouse.o
54obj-$(CONFIG_HID_HOLTEK) += hid-holtekff.o 56obj-$(CONFIG_HID_HOLTEK) += hid-holtekff.o
55obj-$(CONFIG_HID_HYPERV_MOUSE) += hid-hyperv.o 57obj-$(CONFIG_HID_HYPERV_MOUSE) += hid-hyperv.o
56obj-$(CONFIG_HID_ICADE) += hid-icade.o 58obj-$(CONFIG_HID_ICADE) += hid-icade.o
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index 264f55099940..b29c956c395c 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -1573,6 +1573,8 @@ static const struct hid_device_id hid_have_special_driver[] = {
1573 { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, 0x0006) }, 1573 { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, 0x0006) },
1574 { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, 0x0011) }, 1574 { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, 0x0011) },
1575 { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_BM084) }, 1575 { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_BM084) },
1576 { HID_USB_DEVICE(USB_VENDOR_ID_ELO, 0x0009) },
1577 { HID_USB_DEVICE(USB_VENDOR_ID_ELO, 0x0030) },
1576 { HID_USB_DEVICE(USB_VENDOR_ID_EMS, USB_DEVICE_ID_EMS_TRIO_LINKER_PLUS_II) }, 1578 { HID_USB_DEVICE(USB_VENDOR_ID_EMS, USB_DEVICE_ID_EMS_TRIO_LINKER_PLUS_II) },
1577 { HID_USB_DEVICE(USB_VENDOR_ID_EZKEY, USB_DEVICE_ID_BTC_8193) }, 1579 { HID_USB_DEVICE(USB_VENDOR_ID_EZKEY, USB_DEVICE_ID_BTC_8193) },
1578 { HID_USB_DEVICE(USB_VENDOR_ID_GAMERON, USB_DEVICE_ID_GAMERON_DUAL_PSX_ADAPTOR) }, 1580 { HID_USB_DEVICE(USB_VENDOR_ID_GAMERON, USB_DEVICE_ID_GAMERON_DUAL_PSX_ADAPTOR) },
@@ -1584,6 +1586,8 @@ static const struct hid_device_id hid_have_special_driver[] = {
1584 { HID_USB_DEVICE(USB_VENDOR_ID_GYRATION, USB_DEVICE_ID_GYRATION_REMOTE_3) }, 1586 { HID_USB_DEVICE(USB_VENDOR_ID_GYRATION, USB_DEVICE_ID_GYRATION_REMOTE_3) },
1585 { HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK, USB_DEVICE_ID_HOLTEK_ON_LINE_GRIP) }, 1587 { HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK, USB_DEVICE_ID_HOLTEK_ON_LINE_GRIP) },
1586 { HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK_ALT, USB_DEVICE_ID_HOLTEK_ALT_KEYBOARD) }, 1588 { HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK_ALT, USB_DEVICE_ID_HOLTEK_ALT_KEYBOARD) },
1589 { HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK_ALT, USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A04A) },
1590 { HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK_ALT, USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A067) },
1587 { HID_USB_DEVICE(USB_VENDOR_ID_JESS2, USB_DEVICE_ID_JESS2_COLOR_RUMBLE_PAD) }, 1591 { HID_USB_DEVICE(USB_VENDOR_ID_JESS2, USB_DEVICE_ID_JESS2_COLOR_RUMBLE_PAD) },
1588 { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ION, USB_DEVICE_ID_ICADE) }, 1592 { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ION, USB_DEVICE_ID_ICADE) },
1589 { HID_USB_DEVICE(USB_VENDOR_ID_KENSINGTON, USB_DEVICE_ID_KS_SLIMBLADE) }, 1593 { HID_USB_DEVICE(USB_VENDOR_ID_KENSINGTON, USB_DEVICE_ID_KS_SLIMBLADE) },
diff --git a/drivers/hid/hid-elo.c b/drivers/hid/hid-elo.c
new file mode 100644
index 000000000000..f042a6cf8b18
--- /dev/null
+++ b/drivers/hid/hid-elo.c
@@ -0,0 +1,273 @@
1/*
2 * HID driver for ELO usb touchscreen 4000/4500
3 *
4 * Copyright (c) 2013 Jiri Slaby
5 *
6 * Data parsing taken from elousb driver by Vojtech Pavlik.
7 *
8 * This driver is licensed under the terms of GPLv2.
9 */
10
11#include <linux/hid.h>
12#include <linux/input.h>
13#include <linux/module.h>
14#include <linux/usb.h>
15#include <linux/workqueue.h>
16
17#include "hid-ids.h"
18
19#define ELO_PERIODIC_READ_INTERVAL HZ
20#define ELO_SMARTSET_CMD_TIMEOUT 2000 /* msec */
21
22/* Elo SmartSet commands */
23#define ELO_FLUSH_SMARTSET_RESPONSES 0x02 /* Flush all pending smartset responses */
24#define ELO_SEND_SMARTSET_COMMAND 0x05 /* Send a smartset command */
25#define ELO_GET_SMARTSET_RESPONSE 0x06 /* Get a smartset response */
26#define ELO_DIAG 0x64 /* Diagnostics command */
27#define ELO_SMARTSET_PACKET_SIZE 8
28
29struct elo_priv {
30 struct usb_device *usbdev;
31 struct delayed_work work;
32 unsigned char buffer[ELO_SMARTSET_PACKET_SIZE];
33};
34
35static struct workqueue_struct *wq;
36static bool use_fw_quirk = true;
37module_param(use_fw_quirk, bool, S_IRUGO);
38MODULE_PARM_DESC(use_fw_quirk, "Do periodic pokes for broken M firmwares (default = true)");
39
40static void elo_input_configured(struct hid_device *hdev,
41 struct hid_input *hidinput)
42{
43 struct input_dev *input = hidinput->input;
44
45 set_bit(BTN_TOUCH, input->keybit);
46 set_bit(ABS_PRESSURE, input->absbit);
47 input_set_abs_params(input, ABS_PRESSURE, 0, 256, 0, 0);
48}
49
50static void elo_process_data(struct input_dev *input, const u8 *data, int size)
51{
52 int press;
53
54 input_report_abs(input, ABS_X, (data[3] << 8) | data[2]);
55 input_report_abs(input, ABS_Y, (data[5] << 8) | data[4]);
56
57 press = 0;
58 if (data[1] & 0x80)
59 press = (data[7] << 8) | data[6];
60 input_report_abs(input, ABS_PRESSURE, press);
61
62 if (data[1] & 0x03) {
63 input_report_key(input, BTN_TOUCH, 1);
64 input_sync(input);
65 }
66
67 if (data[1] & 0x04)
68 input_report_key(input, BTN_TOUCH, 0);
69
70 input_sync(input);
71}
72
73static int elo_raw_event(struct hid_device *hdev, struct hid_report *report,
74 u8 *data, int size)
75{
76 struct hid_input *hidinput;
77
78 if (!(hdev->claimed & HID_CLAIMED_INPUT) || list_empty(&hdev->inputs))
79 return 0;
80
81 hidinput = list_first_entry(&hdev->inputs, struct hid_input, list);
82
83 switch (report->id) {
84 case 0:
85 if (data[0] == 'T') { /* Mandatory ELO packet marker */
86 elo_process_data(hidinput->input, data, size);
87 return 1;
88 }
89 break;
90 default: /* unknown report */
91 /* Unknown report type; pass upstream */
92 hid_info(hdev, "unknown report type %d\n", report->id);
93 break;
94 }
95
96 return 0;
97}
98
99static int elo_smartset_send_get(struct usb_device *dev, u8 command,
100 void *data)
101{
102 unsigned int pipe;
103 u8 dir;
104
105 if (command == ELO_SEND_SMARTSET_COMMAND) {
106 pipe = usb_sndctrlpipe(dev, 0);
107 dir = USB_DIR_OUT;
108 } else if (command == ELO_GET_SMARTSET_RESPONSE) {
109 pipe = usb_rcvctrlpipe(dev, 0);
110 dir = USB_DIR_IN;
111 } else
112 return -EINVAL;
113
114 return usb_control_msg(dev, pipe, command,
115 dir | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
116 0, 0, data, ELO_SMARTSET_PACKET_SIZE,
117 ELO_SMARTSET_CMD_TIMEOUT);
118}
119
120static int elo_flush_smartset_responses(struct usb_device *dev)
121{
122 return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
123 ELO_FLUSH_SMARTSET_RESPONSES,
124 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
125 0, 0, NULL, 0, USB_CTRL_SET_TIMEOUT);
126}
127
128static void elo_work(struct work_struct *work)
129{
130 struct elo_priv *priv = container_of(work, struct elo_priv, work.work);
131 struct usb_device *dev = priv->usbdev;
132 unsigned char *buffer = priv->buffer;
133 int ret;
134
135 ret = elo_flush_smartset_responses(dev);
136 if (ret < 0) {
137 dev_err(&dev->dev, "initial FLUSH_SMARTSET_RESPONSES failed, error %d\n",
138 ret);
139 goto fail;
140 }
141
142 /* send Diagnostics command */
143 *buffer = ELO_DIAG;
144 ret = elo_smartset_send_get(dev, ELO_SEND_SMARTSET_COMMAND, buffer);
145 if (ret < 0) {
146 dev_err(&dev->dev, "send Diagnostics Command failed, error %d\n",
147 ret);
148 goto fail;
149 }
150
151 /* get the result */
152 ret = elo_smartset_send_get(dev, ELO_GET_SMARTSET_RESPONSE, buffer);
153 if (ret < 0) {
154 dev_err(&dev->dev, "get Diagnostics Command response failed, error %d\n",
155 ret);
156 goto fail;
157 }
158
159 /* read the ack */
160 if (*buffer != 'A') {
161 ret = elo_smartset_send_get(dev, ELO_GET_SMARTSET_RESPONSE,
162 buffer);
163 if (ret < 0) {
164 dev_err(&dev->dev, "get acknowledge response failed, error %d\n",
165 ret);
166 goto fail;
167 }
168 }
169
170fail:
171 ret = elo_flush_smartset_responses(dev);
172 if (ret < 0)
173 dev_err(&dev->dev, "final FLUSH_SMARTSET_RESPONSES failed, error %d\n",
174 ret);
175 queue_delayed_work(wq, &priv->work, ELO_PERIODIC_READ_INTERVAL);
176}
177
178/*
179 * Not all Elo devices need the periodic HID descriptor reads.
180 * Only firmware version M needs this.
181 */
182static bool elo_broken_firmware(struct usb_device *dev)
183{
184 return use_fw_quirk && le16_to_cpu(dev->descriptor.bcdDevice) == 0x10d;
185}
186
187static int elo_probe(struct hid_device *hdev, const struct hid_device_id *id)
188{
189 struct elo_priv *priv;
190 int ret;
191
192 priv = kzalloc(sizeof(*priv), GFP_KERNEL);
193 if (!priv)
194 return -ENOMEM;
195
196 INIT_DELAYED_WORK(&priv->work, elo_work);
197 priv->usbdev = interface_to_usbdev(to_usb_interface(hdev->dev.parent));
198
199 hid_set_drvdata(hdev, priv);
200
201 ret = hid_parse(hdev);
202 if (ret) {
203 hid_err(hdev, "parse failed\n");
204 goto err_free;
205 }
206
207 ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
208 if (ret) {
209 hid_err(hdev, "hw start failed\n");
210 goto err_free;
211 }
212
213 if (elo_broken_firmware(priv->usbdev)) {
214 hid_info(hdev, "broken firmware found, installing workaround\n");
215 queue_delayed_work(wq, &priv->work, ELO_PERIODIC_READ_INTERVAL);
216 }
217
218 return 0;
219err_free:
220 kfree(priv);
221 return ret;
222}
223
224static void elo_remove(struct hid_device *hdev)
225{
226 struct elo_priv *priv = hid_get_drvdata(hdev);
227
228 hid_hw_stop(hdev);
229 flush_workqueue(wq);
230 kfree(priv);
231}
232
233static const struct hid_device_id elo_devices[] = {
234 { HID_USB_DEVICE(USB_VENDOR_ID_ELO, 0x0009), },
235 { HID_USB_DEVICE(USB_VENDOR_ID_ELO, 0x0030), },
236 { }
237};
238MODULE_DEVICE_TABLE(hid, elo_devices);
239
240static struct hid_driver elo_driver = {
241 .name = "elo",
242 .id_table = elo_devices,
243 .probe = elo_probe,
244 .remove = elo_remove,
245 .raw_event = elo_raw_event,
246 .input_configured = elo_input_configured,
247};
248
249static int __init elo_driver_init(void)
250{
251 int ret;
252
253 wq = create_singlethread_workqueue("elousb");
254 if (!wq)
255 return -ENOMEM;
256
257 ret = hid_register_driver(&elo_driver);
258 if (ret)
259 destroy_workqueue(wq);
260
261 return ret;
262}
263module_init(elo_driver_init);
264
265static void __exit elo_driver_exit(void)
266{
267 hid_unregister_driver(&elo_driver);
268 destroy_workqueue(wq);
269}
270module_exit(elo_driver_exit);
271
272MODULE_AUTHOR("Jiri Slaby <jslaby@suse.cz>");
273MODULE_LICENSE("GPL");
diff --git a/drivers/hid/hid-holtek-mouse.c b/drivers/hid/hid-holtek-mouse.c
new file mode 100644
index 000000000000..7e6db3cf46f9
--- /dev/null
+++ b/drivers/hid/hid-holtek-mouse.c
@@ -0,0 +1,77 @@
1/*
2 * HID driver for Holtek gaming mice
3 * Copyright (c) 2013 Christian Ohm
4 * Heavily inspired by various other HID drivers that adjust the report
5 * descriptor.
6*/
7
8/*
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU General Public License as published by the Free
11 * Software Foundation; either version 2 of the License, or (at your option)
12 * any later version.
13 */
14
15#include <linux/hid.h>
16#include <linux/module.h>
17#include <linux/usb.h>
18
19#include "hid-ids.h"
20
21/*
22 * The report descriptor of some Holtek based gaming mice specifies an
23 * excessively large number of consumer usages (2^15), which is more than
24 * HID_MAX_USAGES. This prevents proper parsing of the report descriptor.
25 *
26 * This driver fixes the report descriptor for:
27 * - USB ID 04d9:a067, sold as Sharkoon Drakonia and Perixx MX-2000
28 * - USB ID 04d9:a04a, sold as Tracer Sniper TRM-503, NOVA Gaming Slider X200
29 * and Zalman ZM-GM1
30 */
31
32static __u8 *holtek_mouse_report_fixup(struct hid_device *hdev, __u8 *rdesc,
33 unsigned int *rsize)
34{
35 struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
36
37 if (intf->cur_altsetting->desc.bInterfaceNumber == 1) {
38 /* Change usage maximum and logical maximum from 0x7fff to
39 * 0x2fff, so they don't exceed HID_MAX_USAGES */
40 switch (hdev->product) {
41 case USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A067:
42 if (*rsize >= 122 && rdesc[115] == 0xff && rdesc[116] == 0x7f
43 && rdesc[120] == 0xff && rdesc[121] == 0x7f) {
44 hid_info(hdev, "Fixing up report descriptor\n");
45 rdesc[116] = rdesc[121] = 0x2f;
46 }
47 break;
48 case USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A04A:
49 if (*rsize >= 113 && rdesc[106] == 0xff && rdesc[107] == 0x7f
50 && rdesc[111] == 0xff && rdesc[112] == 0x7f) {
51 hid_info(hdev, "Fixing up report descriptor\n");
52 rdesc[107] = rdesc[112] = 0x2f;
53 }
54 break;
55 }
56
57 }
58 return rdesc;
59}
60
61static const struct hid_device_id holtek_mouse_devices[] = {
62 { HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK_ALT,
63 USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A067) },
64 { HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK_ALT,
65 USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A04A) },
66 { }
67};
68MODULE_DEVICE_TABLE(hid, holtek_mouse_devices);
69
70static struct hid_driver holtek_mouse_driver = {
71 .name = "holtek_mouse",
72 .id_table = holtek_mouse_devices,
73 .report_fixup = holtek_mouse_report_fixup,
74};
75
76module_hid_driver(holtek_mouse_driver);
77MODULE_LICENSE("GPL");
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
index 38535c9243d5..a9fcb9ea6c16 100644
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
@@ -440,6 +440,8 @@
440 440
441#define USB_VENDOR_ID_HOLTEK_ALT 0x04d9 441#define USB_VENDOR_ID_HOLTEK_ALT 0x04d9
442#define USB_DEVICE_ID_HOLTEK_ALT_KEYBOARD 0xa055 442#define USB_DEVICE_ID_HOLTEK_ALT_KEYBOARD 0xa055
443#define USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A067 0xa067
444#define USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A04A 0xa04a
443 445
444#define USB_VENDOR_ID_IMATION 0x0718 446#define USB_VENDOR_ID_IMATION 0x0718
445#define USB_DEVICE_ID_DISC_STAKKA 0xd000 447#define USB_DEVICE_ID_DISC_STAKKA 0xd000
diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c
index 945b8158ec4c..c526a3ccbe5b 100644
--- a/drivers/hid/hid-input.c
+++ b/drivers/hid/hid-input.c
@@ -354,10 +354,10 @@ static int hidinput_get_battery_property(struct power_supply *psy,
354 dev->battery_report_type); 354 dev->battery_report_type);
355 355
356 if (ret != 2) { 356 if (ret != 2) {
357 if (ret >= 0) 357 ret = -ENODATA;
358 ret = -EINVAL;
359 break; 358 break;
360 } 359 }
360 ret = 0;
361 361
362 if (dev->battery_min < dev->battery_max && 362 if (dev->battery_min < dev->battery_max &&
363 buf[1] >= dev->battery_min && 363 buf[1] >= dev->battery_min &&
diff --git a/net/bluetooth/hidp/core.c b/net/bluetooth/hidp/core.c
index 940f5acb6694..46c6a148f0b3 100644
--- a/net/bluetooth/hidp/core.c
+++ b/net/bluetooth/hidp/core.c
@@ -851,6 +851,29 @@ static void hidp_session_dev_del(struct hidp_session *session)
851} 851}
852 852
853/* 853/*
854 * Asynchronous device registration
855 * HID device drivers might want to perform I/O during initialization to
856 * detect device types. Therefore, call device registration in a separate
857 * worker so the HIDP thread can schedule I/O operations.
858 * Note that this must be called after the worker thread was initialized
859 * successfully. This will then add the devices and increase session state
860 * on success, otherwise it will terminate the session thread.
861 */
862static void hidp_session_dev_work(struct work_struct *work)
863{
864 struct hidp_session *session = container_of(work,
865 struct hidp_session,
866 dev_init);
867 int ret;
868
869 ret = hidp_session_dev_add(session);
870 if (!ret)
871 atomic_inc(&session->state);
872 else
873 hidp_session_terminate(session);
874}
875
876/*
854 * Create new session object 877 * Create new session object
855 * Allocate session object, initialize static fields, copy input data into the 878 * Allocate session object, initialize static fields, copy input data into the
856 * object and take a reference to all sub-objects. 879 * object and take a reference to all sub-objects.
@@ -897,6 +920,7 @@ static int hidp_session_new(struct hidp_session **out, const bdaddr_t *bdaddr,
897 session->idle_to = req->idle_to; 920 session->idle_to = req->idle_to;
898 921
899 /* device management */ 922 /* device management */
923 INIT_WORK(&session->dev_init, hidp_session_dev_work);
900 setup_timer(&session->timer, hidp_idle_timeout, 924 setup_timer(&session->timer, hidp_idle_timeout,
901 (unsigned long)session); 925 (unsigned long)session);
902 926
@@ -1035,8 +1059,8 @@ static void hidp_session_terminate(struct hidp_session *session)
1035 * Probe HIDP session 1059 * Probe HIDP session
1036 * This is called from the l2cap_conn core when our l2cap_user object is bound 1060 * This is called from the l2cap_conn core when our l2cap_user object is bound
1037 * to the hci-connection. We get the session via the \user object and can now 1061 * to the hci-connection. We get the session via the \user object and can now
1038 * start the session thread, register the HID/input devices and link it into 1062 * start the session thread, link it into the global session list and
1039 * the global session list. 1063 * schedule HID/input device registration.
1040 * The global session-list owns its own reference to the session object so you 1064 * The global session-list owns its own reference to the session object so you
1041 * can drop your own reference after registering the l2cap_user object. 1065 * can drop your own reference after registering the l2cap_user object.
1042 */ 1066 */
@@ -1058,21 +1082,30 @@ static int hidp_session_probe(struct l2cap_conn *conn,
1058 goto out_unlock; 1082 goto out_unlock;
1059 } 1083 }
1060 1084
1085 if (session->input) {
1086 ret = hidp_session_dev_add(session);
1087 if (ret)
1088 goto out_unlock;
1089 }
1090
1061 ret = hidp_session_start_sync(session); 1091 ret = hidp_session_start_sync(session);
1062 if (ret) 1092 if (ret)
1063 goto out_unlock; 1093 goto out_del;
1064 1094
1065 ret = hidp_session_dev_add(session); 1095 /* HID device registration is async to allow I/O during probe */
1066 if (ret) 1096 if (session->input)
1067 goto out_stop; 1097 atomic_inc(&session->state);
1098 else
1099 schedule_work(&session->dev_init);
1068 1100
1069 hidp_session_get(session); 1101 hidp_session_get(session);
1070 list_add(&session->list, &hidp_session_list); 1102 list_add(&session->list, &hidp_session_list);
1071 ret = 0; 1103 ret = 0;
1072 goto out_unlock; 1104 goto out_unlock;
1073 1105
1074out_stop: 1106out_del:
1075 hidp_session_terminate(session); 1107 if (session->input)
1108 hidp_session_dev_del(session);
1076out_unlock: 1109out_unlock:
1077 up_write(&hidp_session_sem); 1110 up_write(&hidp_session_sem);
1078 return ret; 1111 return ret;
@@ -1102,7 +1135,12 @@ static void hidp_session_remove(struct l2cap_conn *conn,
1102 down_write(&hidp_session_sem); 1135 down_write(&hidp_session_sem);
1103 1136
1104 hidp_session_terminate(session); 1137 hidp_session_terminate(session);
1105 hidp_session_dev_del(session); 1138
1139 cancel_work_sync(&session->dev_init);
1140 if (session->input ||
1141 atomic_read(&session->state) > HIDP_SESSION_PREPARING)
1142 hidp_session_dev_del(session);
1143
1106 list_del(&session->list); 1144 list_del(&session->list);
1107 1145
1108 up_write(&hidp_session_sem); 1146 up_write(&hidp_session_sem);
diff --git a/net/bluetooth/hidp/hidp.h b/net/bluetooth/hidp/hidp.h
index 6162ce8606ac..9e6cc3553105 100644
--- a/net/bluetooth/hidp/hidp.h
+++ b/net/bluetooth/hidp/hidp.h
@@ -128,6 +128,7 @@ int hidp_get_conninfo(struct hidp_conninfo *ci);
128 128
129enum hidp_session_state { 129enum hidp_session_state {
130 HIDP_SESSION_IDLING, 130 HIDP_SESSION_IDLING,
131 HIDP_SESSION_PREPARING,
131 HIDP_SESSION_RUNNING, 132 HIDP_SESSION_RUNNING,
132}; 133};
133 134
@@ -156,6 +157,7 @@ struct hidp_session {
156 unsigned long idle_to; 157 unsigned long idle_to;
157 158
158 /* device management */ 159 /* device management */
160 struct work_struct dev_init;
159 struct input_dev *input; 161 struct input_dev *input;
160 struct hid_device *hid; 162 struct hid_device *hid;
161 struct timer_list timer; 163 struct timer_list timer;