Commit 8606ab6d30dbaaafff985bd462bf33c36997eae9
Exists in
master
and in
4 other branches
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/hid
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/hid: (22 commits) HID: fix error condition propagation in hid-sony driver HID: fix reference count leak hidraw HID: add proper support for pensketch 12x9 tablet HID: don't allow DealExtreme usb-radio be handled by usb hid driver HID: fix default Kconfig setting for TopSpeed driver HID: driver for TopSeed Cyberlink quirky remote HID: make boot protocol drivers depend on EMBEDDED HID: avoid sparse warning in HID_COMPAT_LOAD_DRIVER HID: hiddev cleanup -- handle all error conditions properly HID: force feedback driver for GreenAsia 0x12 PID HID: switch specialized drivers from "default y" to !EMBEDDED HID: set proper dev.parent in hidraw HID: add dynids facility HID: use GFP_KERNEL in hid_alloc_buffers HID: usbhid, use usb_endpoint_xfer_int HID: move usbhid flags to usbhid.h HID: add n-trig digitizer support HID: add phys and name ioctls to hidraw HID: struct device - replace bus_id with dev_name(), dev_set_name() HID: automatically call usbhid_set_leds in usbhid driver ...
Showing 20 changed files Side-by-side Diff
- drivers/hid/Kconfig
- drivers/hid/Makefile
- drivers/hid/hid-bright.c
- drivers/hid/hid-core.c
- drivers/hid/hid-dell.c
- drivers/hid/hid-dummy.c
- drivers/hid/hid-gaff.c
- drivers/hid/hid-ids.h
- drivers/hid/hid-lg.c
- drivers/hid/hid-ntrig.c
- drivers/hid/hid-sony.c
- drivers/hid/hid-topseed.c
- drivers/hid/hidraw.c
- drivers/hid/usbhid/Kconfig
- drivers/hid/usbhid/hid-core.c
- drivers/hid/usbhid/hid-quirks.c
- drivers/hid/usbhid/hiddev.c
- drivers/hid/usbhid/usbhid.h
- include/linux/hid.h
- include/linux/hidraw.h
drivers/hid/Kconfig
... | ... | @@ -85,14 +85,14 @@ |
85 | 85 | config HID_A4TECH |
86 | 86 | tristate "A4 tech" if EMBEDDED |
87 | 87 | depends on USB_HID |
88 | - default y | |
88 | + default !EMBEDDED | |
89 | 89 | ---help--- |
90 | 90 | Support for A4 tech X5 and WOP-35 / Trust 450L mice. |
91 | 91 | |
92 | 92 | config HID_APPLE |
93 | 93 | tristate "Apple" if EMBEDDED |
94 | 94 | depends on (USB_HID || BT_HIDP) |
95 | - default y | |
95 | + default !EMBEDDED | |
96 | 96 | ---help--- |
97 | 97 | Support for some Apple devices which less or more break |
98 | 98 | HID specification. |
99 | 99 | |
100 | 100 | |
101 | 101 | |
102 | 102 | |
103 | 103 | |
104 | 104 | |
105 | 105 | |
106 | 106 | |
... | ... | @@ -103,64 +103,49 @@ |
103 | 103 | config HID_BELKIN |
104 | 104 | tristate "Belkin" if EMBEDDED |
105 | 105 | depends on USB_HID |
106 | - default y | |
106 | + default !EMBEDDED | |
107 | 107 | ---help--- |
108 | 108 | Support for Belkin Flip KVM and Wireless keyboard. |
109 | 109 | |
110 | -config HID_BRIGHT | |
111 | - tristate "Bright" if EMBEDDED | |
112 | - depends on USB_HID | |
113 | - default y | |
114 | - ---help--- | |
115 | - Support for Bright ABNT-2 keyboard. | |
116 | - | |
117 | 110 | config HID_CHERRY |
118 | 111 | tristate "Cherry" if EMBEDDED |
119 | 112 | depends on USB_HID |
120 | - default y | |
113 | + default !EMBEDDED | |
121 | 114 | ---help--- |
122 | 115 | Support for Cherry Cymotion keyboard. |
123 | 116 | |
124 | 117 | config HID_CHICONY |
125 | 118 | tristate "Chicony" if EMBEDDED |
126 | 119 | depends on USB_HID |
127 | - default y | |
120 | + default !EMBEDDED | |
128 | 121 | ---help--- |
129 | 122 | Support for Chicony Tactical pad. |
130 | 123 | |
131 | 124 | config HID_CYPRESS |
132 | 125 | tristate "Cypress" if EMBEDDED |
133 | 126 | depends on USB_HID |
134 | - default y | |
127 | + default !EMBEDDED | |
135 | 128 | ---help--- |
136 | 129 | Support for cypress mouse and barcode readers. |
137 | 130 | |
138 | -config HID_DELL | |
139 | - tristate "Dell" if EMBEDDED | |
140 | - depends on USB_HID | |
141 | - default y | |
142 | - ---help--- | |
143 | - Support for quirky Dell HID hardware that require | |
144 | - special LED handling (W7658 and SK8115 models) | |
145 | - | |
146 | 131 | config HID_EZKEY |
147 | 132 | tristate "Ezkey" if EMBEDDED |
148 | 133 | depends on USB_HID |
149 | - default y | |
134 | + default !EMBEDDED | |
150 | 135 | ---help--- |
151 | 136 | Support for Ezkey BTC 8193 keyboard. |
152 | 137 | |
153 | 138 | config HID_GYRATION |
154 | 139 | tristate "Gyration" if EMBEDDED |
155 | 140 | depends on USB_HID |
156 | - default y | |
141 | + default !EMBEDDED | |
157 | 142 | ---help--- |
158 | 143 | Support for Gyration remote control. |
159 | 144 | |
160 | 145 | config HID_LOGITECH |
161 | 146 | tristate "Logitech" if EMBEDDED |
162 | 147 | depends on USB_HID |
163 | - default y | |
148 | + default !EMBEDDED | |
164 | 149 | ---help--- |
165 | 150 | Support for Logitech devices that are not fully compliant with HID standard. |
166 | 151 | |
167 | 152 | |
168 | 153 | |
169 | 154 | |
... | ... | @@ -191,21 +176,28 @@ |
191 | 176 | config HID_MICROSOFT |
192 | 177 | tristate "Microsoft" if EMBEDDED |
193 | 178 | depends on USB_HID |
194 | - default y | |
179 | + default !EMBEDDED | |
195 | 180 | ---help--- |
196 | 181 | Support for Microsoft devices that are not fully compliant with HID standard. |
197 | 182 | |
198 | 183 | config HID_MONTEREY |
199 | 184 | tristate "Monterey" if EMBEDDED |
200 | 185 | depends on USB_HID |
201 | - default y | |
186 | + default !EMBEDDED | |
202 | 187 | ---help--- |
203 | 188 | Support for Monterey Genius KB29E. |
204 | 189 | |
190 | +config HID_NTRIG | |
191 | + tristate "NTrig" if EMBEDDED | |
192 | + depends on USB_HID | |
193 | + default !EMBEDDED | |
194 | + ---help--- | |
195 | + Support for N-Trig touch screen. | |
196 | + | |
205 | 197 | config HID_PANTHERLORD |
206 | 198 | tristate "Pantherlord devices support" if EMBEDDED |
207 | 199 | depends on USB_HID |
208 | - default y | |
200 | + default !EMBEDDED | |
209 | 201 | ---help--- |
210 | 202 | Support for PantherLord/GreenAsia based device support. |
211 | 203 | |
212 | 204 | |
213 | 205 | |
214 | 206 | |
215 | 207 | |
... | ... | @@ -220,30 +212,46 @@ |
220 | 212 | config HID_PETALYNX |
221 | 213 | tristate "Petalynx" if EMBEDDED |
222 | 214 | depends on USB_HID |
223 | - default y | |
215 | + default !EMBEDDED | |
224 | 216 | ---help--- |
225 | 217 | Support for Petalynx Maxter remote control. |
226 | 218 | |
227 | 219 | config HID_SAMSUNG |
228 | 220 | tristate "Samsung" if EMBEDDED |
229 | 221 | depends on USB_HID |
230 | - default y | |
222 | + default !EMBEDDED | |
231 | 223 | ---help--- |
232 | 224 | Support for Samsung InfraRed remote control. |
233 | 225 | |
234 | 226 | config HID_SONY |
235 | 227 | tristate "Sony" if EMBEDDED |
236 | 228 | depends on USB_HID |
237 | - default y | |
229 | + default !EMBEDDED | |
238 | 230 | ---help--- |
239 | 231 | Support for Sony PS3 controller. |
240 | 232 | |
241 | 233 | config HID_SUNPLUS |
242 | 234 | tristate "Sunplus" if EMBEDDED |
243 | 235 | depends on USB_HID |
244 | - default y | |
236 | + default !EMBEDDED | |
245 | 237 | ---help--- |
246 | 238 | Support for Sunplus wireless desktop. |
239 | + | |
240 | +config GREENASIA_FF | |
241 | + tristate "GreenAsia (Product ID 0x12) force feedback support" | |
242 | + depends on USB_HID | |
243 | + select INPUT_FF_MEMLESS | |
244 | + ---help--- | |
245 | + Say Y here if you have a GreenAsia (Product ID 0x12) based game controller | |
246 | + (like MANTA Warior MM816 and SpeedLink Strike2 SL-6635) or adapter | |
247 | + and want to enable force feedback support for it. | |
248 | + | |
249 | +config HID_TOPSEED | |
250 | + tristate "TopSeed Cyberlink remote control support" if EMBEDDED | |
251 | + depends on USB_HID | |
252 | + default !EMBEDDED | |
253 | + ---help--- | |
254 | + Say Y if you have a TopSeed Cyberlink remote control. | |
247 | 255 | |
248 | 256 | config THRUSTMASTER_FF |
249 | 257 | tristate "ThrustMaster devices support" |
drivers/hid/Makefile
... | ... | @@ -23,22 +23,23 @@ |
23 | 23 | obj-$(CONFIG_HID_A4TECH) += hid-a4tech.o |
24 | 24 | obj-$(CONFIG_HID_APPLE) += hid-apple.o |
25 | 25 | obj-$(CONFIG_HID_BELKIN) += hid-belkin.o |
26 | -obj-$(CONFIG_HID_BRIGHT) += hid-bright.o | |
27 | 26 | obj-$(CONFIG_HID_CHERRY) += hid-cherry.o |
28 | 27 | obj-$(CONFIG_HID_CHICONY) += hid-chicony.o |
29 | 28 | obj-$(CONFIG_HID_CYPRESS) += hid-cypress.o |
30 | -obj-$(CONFIG_HID_DELL) += hid-dell.o | |
31 | 29 | obj-$(CONFIG_HID_EZKEY) += hid-ezkey.o |
32 | 30 | obj-$(CONFIG_HID_GYRATION) += hid-gyration.o |
33 | 31 | obj-$(CONFIG_HID_LOGITECH) += hid-logitech.o |
34 | 32 | obj-$(CONFIG_HID_MICROSOFT) += hid-microsoft.o |
35 | 33 | obj-$(CONFIG_HID_MONTEREY) += hid-monterey.o |
34 | +obj-$(CONFIG_HID_NTRIG) += hid-ntrig.o | |
36 | 35 | obj-$(CONFIG_HID_PANTHERLORD) += hid-pl.o |
37 | 36 | obj-$(CONFIG_HID_PETALYNX) += hid-petalynx.o |
38 | 37 | obj-$(CONFIG_HID_SAMSUNG) += hid-samsung.o |
39 | 38 | obj-$(CONFIG_HID_SONY) += hid-sony.o |
40 | 39 | obj-$(CONFIG_HID_SUNPLUS) += hid-sunplus.o |
40 | +obj-$(CONFIG_GREENASIA_FF) += hid-gaff.o | |
41 | 41 | obj-$(CONFIG_THRUSTMASTER_FF) += hid-tmff.o |
42 | +obj-$(CONFIG_HID_TOPSEED) += hid-topseed.o | |
42 | 43 | obj-$(CONFIG_ZEROPLUS_FF) += hid-zpff.o |
43 | 44 | |
44 | 45 | obj-$(CONFIG_USB_HID) += usbhid/ |
drivers/hid/hid-bright.c
1 | -/* | |
2 | - * HID driver for some bright "special" devices | |
3 | - * | |
4 | - * Copyright (c) 2008 Mauro Carvalho Chehab <mchehab@redhat.com> | |
5 | - * | |
6 | - * Based on hid-dell driver | |
7 | - */ | |
8 | - | |
9 | -/* | |
10 | - * This program is free software; you can redistribute it and/or modify it | |
11 | - * under the terms of the GNU General Public License as published by the Free | |
12 | - * Software Foundation; either version 2 of the License, or (at your option) | |
13 | - * any later version. | |
14 | - */ | |
15 | - | |
16 | -#include <linux/device.h> | |
17 | -#include <linux/hid.h> | |
18 | -#include <linux/module.h> | |
19 | - | |
20 | -#include "hid-ids.h" | |
21 | - | |
22 | -static int bright_probe(struct hid_device *hdev, const struct hid_device_id *id) | |
23 | -{ | |
24 | - int ret; | |
25 | - | |
26 | - ret = hid_parse(hdev); | |
27 | - if (ret) { | |
28 | - dev_err(&hdev->dev, "parse failed\n"); | |
29 | - goto err_free; | |
30 | - } | |
31 | - | |
32 | - ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); | |
33 | - if (ret) { | |
34 | - dev_err(&hdev->dev, "hw start failed\n"); | |
35 | - goto err_free; | |
36 | - } | |
37 | - | |
38 | - usbhid_set_leds(hdev); | |
39 | - | |
40 | - return 0; | |
41 | -err_free: | |
42 | - return ret; | |
43 | -} | |
44 | - | |
45 | -static const struct hid_device_id bright_devices[] = { | |
46 | - { HID_USB_DEVICE(USB_VENDOR_ID_BRIGHT, USB_DEVICE_ID_BRIGHT_ABNT2) }, | |
47 | - { } | |
48 | -}; | |
49 | -MODULE_DEVICE_TABLE(hid, bright_devices); | |
50 | - | |
51 | -static struct hid_driver bright_driver = { | |
52 | - .name = "bright", | |
53 | - .id_table = bright_devices, | |
54 | - .probe = bright_probe, | |
55 | -}; | |
56 | - | |
57 | -static int bright_init(void) | |
58 | -{ | |
59 | - return hid_register_driver(&bright_driver); | |
60 | -} | |
61 | - | |
62 | -static void bright_exit(void) | |
63 | -{ | |
64 | - hid_unregister_driver(&bright_driver); | |
65 | -} | |
66 | - | |
67 | -module_init(bright_init); | |
68 | -module_exit(bright_exit); | |
69 | -MODULE_LICENSE("GPL"); | |
70 | - | |
71 | -HID_COMPAT_LOAD_DRIVER(bright); |
drivers/hid/hid-core.c
... | ... | @@ -1256,19 +1256,16 @@ |
1256 | 1256 | { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY) }, |
1257 | 1257 | { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY) }, |
1258 | 1258 | { HID_USB_DEVICE(USB_VENDOR_ID_BELKIN, USB_DEVICE_ID_FLIP_KVM) }, |
1259 | - { HID_USB_DEVICE(USB_VENDOR_ID_BRIGHT, USB_DEVICE_ID_BRIGHT_ABNT2) }, | |
1260 | 1259 | { HID_USB_DEVICE(USB_VENDOR_ID_CHERRY, USB_DEVICE_ID_CHERRY_CYMOTION) }, |
1261 | 1260 | { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_TACTICAL_PAD) }, |
1262 | 1261 | { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_1) }, |
1263 | 1262 | { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_2) }, |
1264 | 1263 | { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_MOUSE) }, |
1265 | - { HID_USB_DEVICE(USB_VENDOR_ID_DELL, USB_DEVICE_ID_DELL_W7658) }, | |
1266 | - { HID_USB_DEVICE(USB_VENDOR_ID_DELL, USB_DEVICE_ID_DELL_SK8115) }, | |
1267 | 1264 | { HID_USB_DEVICE(USB_VENDOR_ID_EZKEY, USB_DEVICE_ID_BTC_8193) }, |
1268 | - { HID_USB_DEVICE(USB_VENDOR_ID_GENERIC_13BA, USB_DEVICE_ID_GENERIC_13BA_KBD_MOUSE) }, | |
1269 | 1265 | { HID_USB_DEVICE(USB_VENDOR_ID_GAMERON, USB_DEVICE_ID_GAMERON_DUAL_PSX_ADAPTOR) }, |
1270 | 1266 | { HID_USB_DEVICE(USB_VENDOR_ID_GAMERON, USB_DEVICE_ID_GAMERON_DUAL_PCS_ADAPTOR) }, |
1271 | 1267 | { HID_USB_DEVICE(USB_VENDOR_ID_GREENASIA, 0x0003) }, |
1268 | + { HID_USB_DEVICE(USB_VENDOR_ID_GREENASIA, 0x0012) }, | |
1272 | 1269 | { HID_USB_DEVICE(USB_VENDOR_ID_GYRATION, USB_DEVICE_ID_GYRATION_REMOTE) }, |
1273 | 1270 | { HID_USB_DEVICE(USB_VENDOR_ID_GYRATION, USB_DEVICE_ID_GYRATION_REMOTE_2) }, |
1274 | 1271 | { HID_USB_DEVICE(USB_VENDOR_ID_LABTEC, USB_DEVICE_ID_LABTEC_WIRELESS_KEYBOARD) }, |
... | ... | @@ -1279,7 +1276,6 @@ |
1279 | 1276 | { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_DESKTOP) }, |
1280 | 1277 | { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_EDGE) }, |
1281 | 1278 | { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_MINI) }, |
1282 | - { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_KBD) }, | |
1283 | 1279 | { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_ELITE_KBD) }, |
1284 | 1280 | { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_CORDLESS_DESKTOP_LX500) }, |
1285 | 1281 | { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_EXTREME_3D) }, |
1286 | 1282 | |
1287 | 1283 | |
1288 | 1284 | |
... | ... | @@ -1297,23 +1293,105 @@ |
1297 | 1293 | { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_PRESENTER_8K_USB) }, |
1298 | 1294 | { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_WIRELESS_OPTICAL_DESKTOP_3_0) }, |
1299 | 1295 | { HID_USB_DEVICE(USB_VENDOR_ID_MONTEREY, USB_DEVICE_ID_GENIUS_KB29E) }, |
1296 | + { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN) }, | |
1300 | 1297 | { HID_USB_DEVICE(USB_VENDOR_ID_PETALYNX, USB_DEVICE_ID_PETALYNX_MAXTER_REMOTE) }, |
1301 | 1298 | { HID_USB_DEVICE(USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_IR_REMOTE) }, |
1302 | 1299 | { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER) }, |
1303 | 1300 | { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_VAIO_VGX_MOUSE) }, |
1304 | 1301 | { HID_USB_DEVICE(USB_VENDOR_ID_SUNPLUS, USB_DEVICE_ID_SUNPLUS_WDESKTOP) }, |
1302 | + { HID_USB_DEVICE(USB_VENDOR_ID_TOPSEED, USB_DEVICE_ID_TOPSEED_CYBERLINK) }, | |
1305 | 1303 | |
1306 | 1304 | { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, 0x030c) }, |
1307 | 1305 | { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_PRESENTER_8K_BT) }, |
1308 | 1306 | { } |
1309 | 1307 | }; |
1310 | 1308 | |
1309 | +struct hid_dynid { | |
1310 | + struct list_head list; | |
1311 | + struct hid_device_id id; | |
1312 | +}; | |
1313 | + | |
1314 | +/** | |
1315 | + * store_new_id - add a new HID device ID to this driver and re-probe devices | |
1316 | + * @driver: target device driver | |
1317 | + * @buf: buffer for scanning device ID data | |
1318 | + * @count: input size | |
1319 | + * | |
1320 | + * Adds a new dynamic hid device ID to this driver, | |
1321 | + * and causes the driver to probe for all devices again. | |
1322 | + */ | |
1323 | +static ssize_t store_new_id(struct device_driver *drv, const char *buf, | |
1324 | + size_t count) | |
1325 | +{ | |
1326 | + struct hid_driver *hdrv = container_of(drv, struct hid_driver, driver); | |
1327 | + struct hid_dynid *dynid; | |
1328 | + __u32 bus, vendor, product; | |
1329 | + unsigned long driver_data = 0; | |
1330 | + int ret; | |
1331 | + | |
1332 | + ret = sscanf(buf, "%x %x %x %lx", | |
1333 | + &bus, &vendor, &product, &driver_data); | |
1334 | + if (ret < 3) | |
1335 | + return -EINVAL; | |
1336 | + | |
1337 | + dynid = kzalloc(sizeof(*dynid), GFP_KERNEL); | |
1338 | + if (!dynid) | |
1339 | + return -ENOMEM; | |
1340 | + | |
1341 | + dynid->id.bus = bus; | |
1342 | + dynid->id.vendor = vendor; | |
1343 | + dynid->id.product = product; | |
1344 | + dynid->id.driver_data = driver_data; | |
1345 | + | |
1346 | + spin_lock(&hdrv->dyn_lock); | |
1347 | + list_add_tail(&dynid->list, &hdrv->dyn_list); | |
1348 | + spin_unlock(&hdrv->dyn_lock); | |
1349 | + | |
1350 | + ret = 0; | |
1351 | + if (get_driver(&hdrv->driver)) { | |
1352 | + ret = driver_attach(&hdrv->driver); | |
1353 | + put_driver(&hdrv->driver); | |
1354 | + } | |
1355 | + | |
1356 | + return ret ? : count; | |
1357 | +} | |
1358 | +static DRIVER_ATTR(new_id, S_IWUSR, NULL, store_new_id); | |
1359 | + | |
1360 | +static void hid_free_dynids(struct hid_driver *hdrv) | |
1361 | +{ | |
1362 | + struct hid_dynid *dynid, *n; | |
1363 | + | |
1364 | + spin_lock(&hdrv->dyn_lock); | |
1365 | + list_for_each_entry_safe(dynid, n, &hdrv->dyn_list, list) { | |
1366 | + list_del(&dynid->list); | |
1367 | + kfree(dynid); | |
1368 | + } | |
1369 | + spin_unlock(&hdrv->dyn_lock); | |
1370 | +} | |
1371 | + | |
1372 | +static const struct hid_device_id *hid_match_device(struct hid_device *hdev, | |
1373 | + struct hid_driver *hdrv) | |
1374 | +{ | |
1375 | + struct hid_dynid *dynid; | |
1376 | + | |
1377 | + spin_lock(&hdrv->dyn_lock); | |
1378 | + list_for_each_entry(dynid, &hdrv->dyn_list, list) { | |
1379 | + if (hid_match_one_id(hdev, &dynid->id)) { | |
1380 | + spin_unlock(&hdrv->dyn_lock); | |
1381 | + return &dynid->id; | |
1382 | + } | |
1383 | + } | |
1384 | + spin_unlock(&hdrv->dyn_lock); | |
1385 | + | |
1386 | + return hid_match_id(hdev, hdrv->id_table); | |
1387 | +} | |
1388 | + | |
1311 | 1389 | static int hid_bus_match(struct device *dev, struct device_driver *drv) |
1312 | 1390 | { |
1313 | 1391 | struct hid_driver *hdrv = container_of(drv, struct hid_driver, driver); |
1314 | 1392 | struct hid_device *hdev = container_of(dev, struct hid_device, dev); |
1315 | 1393 | |
1316 | - if (!hid_match_id(hdev, hdrv->id_table)) | |
1394 | + if (!hid_match_device(hdev, hdrv)) | |
1317 | 1395 | return 0; |
1318 | 1396 | |
1319 | 1397 | /* generic wants all non-blacklisted */ |
... | ... | @@ -1332,7 +1410,7 @@ |
1332 | 1410 | int ret = 0; |
1333 | 1411 | |
1334 | 1412 | if (!hdev->driver) { |
1335 | - id = hid_match_id(hdev, hdrv->id_table); | |
1413 | + id = hid_match_device(hdev, hdrv); | |
1336 | 1414 | if (id == NULL) |
1337 | 1415 | return -ENODEV; |
1338 | 1416 | |
... | ... | @@ -1420,6 +1498,7 @@ |
1420 | 1498 | { HID_USB_DEVICE(USB_VENDOR_ID_CMEDIA, USB_DEVICE_ID_CM109) }, |
1421 | 1499 | { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_HIDCOM) }, |
1422 | 1500 | { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_ULTRAMOUSE) }, |
1501 | + { HID_USB_DEVICE(USB_VENDOR_ID_DEALEXTREAME, USB_DEVICE_ID_DEALEXTREAME_RADIO_SI4701) }, | |
1423 | 1502 | { HID_USB_DEVICE(USB_VENDOR_ID_DELORME, USB_DEVICE_ID_DELORME_EARTHMATE) }, |
1424 | 1503 | { HID_USB_DEVICE(USB_VENDOR_ID_DELORME, USB_DEVICE_ID_DELORME_EM_LT20) }, |
1425 | 1504 | { HID_USB_DEVICE(USB_VENDOR_ID_ESSENTIAL_REALITY, USB_DEVICE_ID_ESSENTIAL_REALITY_P5) }, |
... | ... | @@ -1577,6 +1656,9 @@ |
1577 | 1656 | { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING2_ANSI) }, |
1578 | 1657 | { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING2_ISO) }, |
1579 | 1658 | { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING2_JIS) }, |
1659 | + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING3_ANSI) }, | |
1660 | + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING3_ISO) }, | |
1661 | + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING3_JIS) }, | |
1580 | 1662 | { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY) }, |
1581 | 1663 | { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY) }, |
1582 | 1664 | { } |
... | ... | @@ -1618,9 +1700,10 @@ |
1618 | 1700 | if (hid_ignore(hdev)) |
1619 | 1701 | return -ENODEV; |
1620 | 1702 | |
1621 | - /* XXX hack, any other cleaner solution < 20 bus_id bytes? */ | |
1622 | - sprintf(hdev->dev.bus_id, "%04X:%04X:%04X.%04X", hdev->bus, | |
1623 | - hdev->vendor, hdev->product, atomic_inc_return(&id)); | |
1703 | + /* XXX hack, any other cleaner solution after the driver core | |
1704 | + * is converted to allow more than 20 bytes as the device name? */ | |
1705 | + dev_set_name(&hdev->dev, "%04X:%04X:%04X.%04X", hdev->bus, | |
1706 | + hdev->vendor, hdev->product, atomic_inc_return(&id)); | |
1624 | 1707 | |
1625 | 1708 | ret = device_add(&hdev->dev); |
1626 | 1709 | if (!ret) |
1627 | 1710 | |
1628 | 1711 | |
1629 | 1712 | |
... | ... | @@ -1695,18 +1778,33 @@ |
1695 | 1778 | int __hid_register_driver(struct hid_driver *hdrv, struct module *owner, |
1696 | 1779 | const char *mod_name) |
1697 | 1780 | { |
1781 | + int ret; | |
1782 | + | |
1698 | 1783 | hdrv->driver.name = hdrv->name; |
1699 | 1784 | hdrv->driver.bus = &hid_bus_type; |
1700 | 1785 | hdrv->driver.owner = owner; |
1701 | 1786 | hdrv->driver.mod_name = mod_name; |
1702 | 1787 | |
1703 | - return driver_register(&hdrv->driver); | |
1788 | + INIT_LIST_HEAD(&hdrv->dyn_list); | |
1789 | + spin_lock_init(&hdrv->dyn_lock); | |
1790 | + | |
1791 | + ret = driver_register(&hdrv->driver); | |
1792 | + if (ret) | |
1793 | + return ret; | |
1794 | + | |
1795 | + ret = driver_create_file(&hdrv->driver, &driver_attr_new_id); | |
1796 | + if (ret) | |
1797 | + driver_unregister(&hdrv->driver); | |
1798 | + | |
1799 | + return ret; | |
1704 | 1800 | } |
1705 | 1801 | EXPORT_SYMBOL_GPL(__hid_register_driver); |
1706 | 1802 | |
1707 | 1803 | void hid_unregister_driver(struct hid_driver *hdrv) |
1708 | 1804 | { |
1805 | + driver_remove_file(&hdrv->driver, &driver_attr_new_id); | |
1709 | 1806 | driver_unregister(&hdrv->driver); |
1807 | + hid_free_dynids(hdrv); | |
1710 | 1808 | } |
1711 | 1809 | EXPORT_SYMBOL_GPL(hid_unregister_driver); |
1712 | 1810 |
drivers/hid/hid-dell.c
1 | -/* | |
2 | - * HID driver for some dell "special" devices | |
3 | - * | |
4 | - * Copyright (c) 1999 Andreas Gal | |
5 | - * Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz> | |
6 | - * Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc | |
7 | - * Copyright (c) 2006-2007 Jiri Kosina | |
8 | - * Copyright (c) 2007 Paul Walmsley | |
9 | - * Copyright (c) 2008 Jiri Slaby | |
10 | - */ | |
11 | - | |
12 | -/* | |
13 | - * This program is free software; you can redistribute it and/or modify it | |
14 | - * under the terms of the GNU General Public License as published by the Free | |
15 | - * Software Foundation; either version 2 of the License, or (at your option) | |
16 | - * any later version. | |
17 | - */ | |
18 | - | |
19 | -#include <linux/device.h> | |
20 | -#include <linux/hid.h> | |
21 | -#include <linux/module.h> | |
22 | - | |
23 | -#include "hid-ids.h" | |
24 | - | |
25 | -static int dell_probe(struct hid_device *hdev, const struct hid_device_id *id) | |
26 | -{ | |
27 | - int ret; | |
28 | - | |
29 | - ret = hid_parse(hdev); | |
30 | - if (ret) { | |
31 | - dev_err(&hdev->dev, "parse failed\n"); | |
32 | - goto err_free; | |
33 | - } | |
34 | - | |
35 | - ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); | |
36 | - if (ret) { | |
37 | - dev_err(&hdev->dev, "hw start failed\n"); | |
38 | - goto err_free; | |
39 | - } | |
40 | - | |
41 | - usbhid_set_leds(hdev); | |
42 | - | |
43 | - return 0; | |
44 | -err_free: | |
45 | - return ret; | |
46 | -} | |
47 | - | |
48 | -static const struct hid_device_id dell_devices[] = { | |
49 | - { HID_USB_DEVICE(USB_VENDOR_ID_DELL, USB_DEVICE_ID_DELL_W7658) }, | |
50 | - { HID_USB_DEVICE(USB_VENDOR_ID_DELL, USB_DEVICE_ID_DELL_SK8115) }, | |
51 | - { HID_USB_DEVICE(USB_VENDOR_ID_GENERIC_13BA, USB_DEVICE_ID_GENERIC_13BA_KBD_MOUSE) }, | |
52 | - { } | |
53 | -}; | |
54 | -MODULE_DEVICE_TABLE(hid, dell_devices); | |
55 | - | |
56 | -static struct hid_driver dell_driver = { | |
57 | - .name = "dell", | |
58 | - .id_table = dell_devices, | |
59 | - .probe = dell_probe, | |
60 | -}; | |
61 | - | |
62 | -static int dell_init(void) | |
63 | -{ | |
64 | - return hid_register_driver(&dell_driver); | |
65 | -} | |
66 | - | |
67 | -static void dell_exit(void) | |
68 | -{ | |
69 | - hid_unregister_driver(&dell_driver); | |
70 | -} | |
71 | - | |
72 | -module_init(dell_init); | |
73 | -module_exit(dell_exit); | |
74 | -MODULE_LICENSE("GPL"); | |
75 | - | |
76 | -HID_COMPAT_LOAD_DRIVER(dell); |
drivers/hid/hid-dummy.c
... | ... | @@ -43,6 +43,9 @@ |
43 | 43 | #ifdef CONFIG_HID_MONTEREY_MODULE |
44 | 44 | HID_COMPAT_CALL_DRIVER(monterey); |
45 | 45 | #endif |
46 | +#ifdef CONFIG_HID_NTRIG_MODULE | |
47 | + HID_COMPAT_CALL_DRIVER(ntrig); | |
48 | +#endif | |
46 | 49 | #ifdef CONFIG_HID_PANTHERLORD_MODULE |
47 | 50 | HID_COMPAT_CALL_DRIVER(pantherlord); |
48 | 51 | #endif |
... | ... | @@ -57,6 +60,9 @@ |
57 | 60 | #endif |
58 | 61 | #ifdef CONFIG_HID_SUNPLUS_MODULE |
59 | 62 | HID_COMPAT_CALL_DRIVER(sunplus); |
63 | +#endif | |
64 | +#ifdef CONFIG_GREENASIA_FF_MODULE | |
65 | + HID_COMPAT_CALL_DRIVER(greenasia); | |
60 | 66 | #endif |
61 | 67 | #ifdef CONFIG_THRUSTMASTER_FF_MODULE |
62 | 68 | HID_COMPAT_CALL_DRIVER(thrustmaster); |
drivers/hid/hid-gaff.c
1 | +/* | |
2 | + * Force feedback support for GreenAsia (Product ID 0x12) based devices | |
3 | + * | |
4 | + * The devices are distributed under various names and the same USB device ID | |
5 | + * can be used in many game controllers. | |
6 | + * | |
7 | + * | |
8 | + * 0e8f:0012 "GreenAsia Inc. USB Joystick " | |
9 | + * - tested with MANTA Warior MM816 and SpeedLink Strike2 SL-6635. | |
10 | + * | |
11 | + * Copyright (c) 2008 Lukasz Lubojanski <lukasz@lubojanski.info> | |
12 | + */ | |
13 | + | |
14 | +/* | |
15 | + * This program is free software; you can redistribute it and/or modify | |
16 | + * it under the terms of the GNU General Public License as published by | |
17 | + * the Free Software Foundation; either version 2 of the License, or | |
18 | + * (at your option) any later version. | |
19 | + * | |
20 | + * This program is distributed in the hope that it will be useful, | |
21 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
22 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
23 | + * GNU General Public License for more details. | |
24 | + * | |
25 | + * You should have received a copy of the GNU General Public License | |
26 | + * along with this program; if not, write to the Free Software | |
27 | + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
28 | + */ | |
29 | + | |
30 | +#include <linux/input.h> | |
31 | +#include <linux/usb.h> | |
32 | +#include <linux/hid.h> | |
33 | +#include "hid-ids.h" | |
34 | +#include "usbhid/usbhid.h" | |
35 | + | |
36 | +struct gaff_device { | |
37 | + struct hid_report *report; | |
38 | +}; | |
39 | + | |
40 | +static int hid_gaff_play(struct input_dev *dev, void *data, | |
41 | + struct ff_effect *effect) | |
42 | +{ | |
43 | + struct hid_device *hid = input_get_drvdata(dev); | |
44 | + struct gaff_device *gaff = data; | |
45 | + int left, right; | |
46 | + | |
47 | + left = effect->u.rumble.strong_magnitude; | |
48 | + right = effect->u.rumble.weak_magnitude; | |
49 | + | |
50 | + dbg_hid("called with 0x%04x 0x%04x", left, right); | |
51 | + | |
52 | + left = left * 0xfe / 0xffff; | |
53 | + right = right * 0xfe / 0xffff; | |
54 | + | |
55 | + gaff->report->field[0]->value[0] = 0x51; | |
56 | + gaff->report->field[0]->value[1] = 0x0; | |
57 | + gaff->report->field[0]->value[2] = right; | |
58 | + gaff->report->field[0]->value[3] = 0; | |
59 | + gaff->report->field[0]->value[4] = left; | |
60 | + gaff->report->field[0]->value[5] = 0; | |
61 | + dbg_hid("running with 0x%02x 0x%02x", left, right); | |
62 | + usbhid_submit_report(hid, gaff->report, USB_DIR_OUT); | |
63 | + | |
64 | + gaff->report->field[0]->value[0] = 0xfa; | |
65 | + gaff->report->field[0]->value[1] = 0xfe; | |
66 | + gaff->report->field[0]->value[2] = 0x0; | |
67 | + gaff->report->field[0]->value[4] = 0x0; | |
68 | + | |
69 | + usbhid_submit_report(hid, gaff->report, USB_DIR_OUT); | |
70 | + | |
71 | + return 0; | |
72 | +} | |
73 | + | |
74 | +static int gaff_init(struct hid_device *hid) | |
75 | +{ | |
76 | + struct gaff_device *gaff; | |
77 | + struct hid_report *report; | |
78 | + struct hid_input *hidinput = list_entry(hid->inputs.next, | |
79 | + struct hid_input, list); | |
80 | + struct list_head *report_list = | |
81 | + &hid->report_enum[HID_OUTPUT_REPORT].report_list; | |
82 | + struct list_head *report_ptr = report_list; | |
83 | + struct input_dev *dev = hidinput->input; | |
84 | + int error; | |
85 | + | |
86 | + if (list_empty(report_list)) { | |
87 | + dev_err(&hid->dev, "no output reports found\n"); | |
88 | + return -ENODEV; | |
89 | + } | |
90 | + | |
91 | + report_ptr = report_ptr->next; | |
92 | + | |
93 | + report = list_entry(report_ptr, struct hid_report, list); | |
94 | + if (report->maxfield < 1) { | |
95 | + dev_err(&hid->dev, "no fields in the report\n"); | |
96 | + return -ENODEV; | |
97 | + } | |
98 | + | |
99 | + if (report->field[0]->report_count < 6) { | |
100 | + dev_err(&hid->dev, "not enough values in the field\n"); | |
101 | + return -ENODEV; | |
102 | + } | |
103 | + | |
104 | + gaff = kzalloc(sizeof(struct gaff_device), GFP_KERNEL); | |
105 | + if (!gaff) | |
106 | + return -ENOMEM; | |
107 | + | |
108 | + set_bit(FF_RUMBLE, dev->ffbit); | |
109 | + | |
110 | + error = input_ff_create_memless(dev, gaff, hid_gaff_play); | |
111 | + if (error) { | |
112 | + kfree(gaff); | |
113 | + return error; | |
114 | + } | |
115 | + | |
116 | + gaff->report = report; | |
117 | + gaff->report->field[0]->value[0] = 0x51; | |
118 | + gaff->report->field[0]->value[1] = 0x00; | |
119 | + gaff->report->field[0]->value[2] = 0x00; | |
120 | + gaff->report->field[0]->value[3] = 0x00; | |
121 | + usbhid_submit_report(hid, gaff->report, USB_DIR_OUT); | |
122 | + | |
123 | + gaff->report->field[0]->value[0] = 0xfa; | |
124 | + gaff->report->field[0]->value[1] = 0xfe; | |
125 | + | |
126 | + usbhid_submit_report(hid, gaff->report, USB_DIR_OUT); | |
127 | + | |
128 | + dev_info(&hid->dev, "Force Feedback for GreenAsia 0x12" | |
129 | + " devices by Lukasz Lubojanski <lukasz@lubojanski.info>\n"); | |
130 | + | |
131 | + return 0; | |
132 | +} | |
133 | + | |
134 | +static int ga_probe(struct hid_device *hdev, const struct hid_device_id *id) | |
135 | +{ | |
136 | + int ret; | |
137 | + | |
138 | + dev_dbg(&hdev->dev, "Greenasia HID hardware probe..."); | |
139 | + | |
140 | + ret = hid_parse(hdev); | |
141 | + if (ret) { | |
142 | + dev_err(&hdev->dev, "parse failed\n"); | |
143 | + goto err; | |
144 | + } | |
145 | + | |
146 | + ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT & ~HID_CONNECT_FF); | |
147 | + if (ret) { | |
148 | + dev_err(&hdev->dev, "hw start failed\n"); | |
149 | + goto err; | |
150 | + } | |
151 | + | |
152 | + gaff_init(hdev); | |
153 | + | |
154 | + return 0; | |
155 | +err: | |
156 | + return ret; | |
157 | +} | |
158 | + | |
159 | +static const struct hid_device_id ga_devices[] = { | |
160 | + { HID_USB_DEVICE(USB_VENDOR_ID_GREENASIA, 0x0012), }, | |
161 | + { } | |
162 | +}; | |
163 | +MODULE_DEVICE_TABLE(hid, ga_devices); | |
164 | + | |
165 | +static struct hid_driver ga_driver = { | |
166 | + .name = "greenasia", | |
167 | + .id_table = ga_devices, | |
168 | + .probe = ga_probe, | |
169 | +}; | |
170 | + | |
171 | +static int __init ga_init(void) | |
172 | +{ | |
173 | + return hid_register_driver(&ga_driver); | |
174 | +} | |
175 | + | |
176 | +static void __exit ga_exit(void) | |
177 | +{ | |
178 | + hid_unregister_driver(&ga_driver); | |
179 | +} | |
180 | + | |
181 | +module_init(ga_init); | |
182 | +module_exit(ga_exit); | |
183 | +MODULE_LICENSE("GPL"); | |
184 | + | |
185 | +HID_COMPAT_LOAD_DRIVER(greenasia); |
drivers/hid/hid-ids.h
... | ... | @@ -107,9 +107,6 @@ |
107 | 107 | #define USB_VENDOR_ID_BELKIN 0x050d |
108 | 108 | #define USB_DEVICE_ID_FLIP_KVM 0x3201 |
109 | 109 | |
110 | -#define USB_VENDOR_ID_BRIGHT 0x1241 | |
111 | -#define USB_DEVICE_ID_BRIGHT_ABNT2 0x1503 | |
112 | - | |
113 | 110 | #define USB_VENDOR_ID_BERKSHIRE 0x0c98 |
114 | 111 | #define USB_DEVICE_ID_BERKSHIRE_PCWD 0x1140 |
115 | 112 | |
... | ... | @@ -141,9 +138,8 @@ |
141 | 138 | #define USB_DEVICE_ID_CYPRESS_BARCODE_1 0xde61 |
142 | 139 | #define USB_DEVICE_ID_CYPRESS_BARCODE_2 0xde64 |
143 | 140 | |
144 | -#define USB_VENDOR_ID_DELL 0x413c | |
145 | -#define USB_DEVICE_ID_DELL_W7658 0x2005 | |
146 | -#define USB_DEVICE_ID_DELL_SK8115 0x2105 | |
141 | +#define USB_VENDOR_ID_DEALEXTREAME 0x10c5 | |
142 | +#define USB_DEVICE_ID_DEALEXTREAME_RADIO_SI4701 0x819a | |
147 | 143 | |
148 | 144 | #define USB_VENDOR_ID_DELORME 0x1163 |
149 | 145 | #define USB_DEVICE_ID_DELORME_EARTHMATE 0x0100 |
... | ... | @@ -167,9 +163,6 @@ |
167 | 163 | |
168 | 164 | #define USB_VENDOR_ID_GENERAL_TOUCH 0x0dfc |
169 | 165 | |
170 | -#define USB_VENDOR_ID_GENERIC_13BA 0x13ba | |
171 | -#define USB_DEVICE_ID_GENERIC_13BA_KBD_MOUSE 0x0017 | |
172 | - | |
173 | 166 | #define USB_VENDOR_ID_GLAB 0x06c2 |
174 | 167 | #define USB_DEVICE_ID_4_PHIDGETSERVO_30 0x0038 |
175 | 168 | #define USB_DEVICE_ID_1_PHIDGETSERVO_30 0x0039 |
... | ... | @@ -292,7 +285,6 @@ |
292 | 285 | #define USB_DEVICE_ID_LOGITECH_WHEEL 0xc294 |
293 | 286 | #define USB_DEVICE_ID_LOGITECH_MOMO_WHEEL 0xc295 |
294 | 287 | #define USB_DEVICE_ID_LOGITECH_ELITE_KBD 0xc30a |
295 | -#define USB_DEVICE_ID_LOGITECH_KBD 0xc311 | |
296 | 288 | #define USB_DEVICE_ID_S510_RECEIVER 0xc50c |
297 | 289 | #define USB_DEVICE_ID_S510_RECEIVER_2 0xc517 |
298 | 290 | #define USB_DEVICE_ID_LOGITECH_CORDLESS_DESKTOP_LX500 0xc512 |
... | ... | @@ -339,6 +331,9 @@ |
339 | 331 | #define USB_VENDOR_ID_NEC 0x073e |
340 | 332 | #define USB_DEVICE_ID_NEC_USB_GAME_PAD 0x0301 |
341 | 333 | |
334 | +#define USB_VENDOR_ID_NTRIG 0x1b96 | |
335 | +#define USB_DEVICE_ID_NTRIG_TOUCH_SCREEN 0x0001 | |
336 | + | |
342 | 337 | #define USB_VENDOR_ID_ONTRAK 0x0a07 |
343 | 338 | #define USB_DEVICE_ID_ONTRAK_ADU100 0x0064 |
344 | 339 | |
345 | 340 | |
... | ... | @@ -383,8 +378,14 @@ |
383 | 378 | #define USB_VENDOR_ID_TOPMAX 0x0663 |
384 | 379 | #define USB_DEVICE_ID_TOPMAX_COBRAPAD 0x0103 |
385 | 380 | |
381 | +#define USB_VENDOR_ID_TOPSEED 0x0766 | |
382 | +#define USB_DEVICE_ID_TOPSEED_CYBERLINK 0x0204 | |
383 | + | |
386 | 384 | #define USB_VENDOR_ID_TURBOX 0x062a |
387 | 385 | #define USB_DEVICE_ID_TURBOX_KEYBOARD 0x0201 |
386 | + | |
387 | +#define USB_VENDOR_ID_UCLOGIC 0x5543 | |
388 | +#define USB_DEVICE_ID_UCLOGIC_TABLET_PF1209 0x0042 | |
388 | 389 | |
389 | 390 | #define USB_VENDOR_ID_VERNIER 0x08f7 |
390 | 391 | #define USB_DEVICE_ID_VERNIER_LABPRO 0x0001 |
drivers/hid/hid-lg.c
... | ... | @@ -26,7 +26,6 @@ |
26 | 26 | #define LG_RDESC 0x001 |
27 | 27 | #define LG_BAD_RELATIVE_KEYS 0x002 |
28 | 28 | #define LG_DUPLICATE_USAGES 0x004 |
29 | -#define LG_RESET_LEDS 0x008 | |
30 | 29 | #define LG_EXPANDED_KEYMAP 0x010 |
31 | 30 | #define LG_IGNORE_DOUBLED_WHEEL 0x020 |
32 | 31 | #define LG_WIRELESS 0x040 |
... | ... | @@ -248,9 +247,6 @@ |
248 | 247 | goto err_free; |
249 | 248 | } |
250 | 249 | |
251 | - if (quirks & LG_RESET_LEDS) | |
252 | - usbhid_set_leds(hdev); | |
253 | - | |
254 | 250 | if (quirks & LG_FF) |
255 | 251 | lgff_init(hdev); |
256 | 252 | if (quirks & LG_FF2) |
... | ... | @@ -278,9 +274,6 @@ |
278 | 274 | .driver_data = LG_DUPLICATE_USAGES }, |
279 | 275 | { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_MINI), |
280 | 276 | .driver_data = LG_DUPLICATE_USAGES }, |
281 | - | |
282 | - { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_KBD), | |
283 | - .driver_data = LG_RESET_LEDS }, | |
284 | 277 | |
285 | 278 | { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_ELITE_KBD), |
286 | 279 | .driver_data = LG_IGNORE_DOUBLED_WHEEL | LG_EXPANDED_KEYMAP }, |
drivers/hid/hid-ntrig.c
1 | +/* | |
2 | + * HID driver for some ntrig "special" devices | |
3 | + * | |
4 | + * Copyright (c) 1999 Andreas Gal | |
5 | + * Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz> | |
6 | + * Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc | |
7 | + * Copyright (c) 2006-2007 Jiri Kosina | |
8 | + * Copyright (c) 2007 Paul Walmsley | |
9 | + * Copyright (c) 2008 Jiri Slaby | |
10 | + * Copyright (c) 2008 Rafi Rubin | |
11 | + * | |
12 | + */ | |
13 | + | |
14 | +/* | |
15 | + * This program is free software; you can redistribute it and/or modify it | |
16 | + * under the terms of the GNU General Public License as published by the Free | |
17 | + * Software Foundation; either version 2 of the License, or (at your option) | |
18 | + * any later version. | |
19 | + */ | |
20 | + | |
21 | +#include <linux/device.h> | |
22 | +#include <linux/hid.h> | |
23 | +#include <linux/module.h> | |
24 | + | |
25 | +#include "hid-ids.h" | |
26 | + | |
27 | +#define NTRIG_DUPLICATE_USAGES 0x001 | |
28 | + | |
29 | +#define nt_map_key_clear(c) hid_map_usage_clear(hi, usage, bit, max, \ | |
30 | + EV_KEY, (c)) | |
31 | + | |
32 | +static int ntrig_input_mapping(struct hid_device *hdev, struct hid_input *hi, | |
33 | + struct hid_field *field, struct hid_usage *usage, | |
34 | + unsigned long **bit, int *max) | |
35 | +{ | |
36 | + if ((usage->hid & HID_USAGE_PAGE) == HID_UP_DIGITIZER && | |
37 | + (usage->hid & 0xff) == 0x47) { | |
38 | + nt_map_key_clear(BTN_TOOL_DOUBLETAP); | |
39 | + return 1; | |
40 | + } | |
41 | + return 0; | |
42 | +} | |
43 | + | |
44 | +static int ntrig_input_mapped(struct hid_device *hdev, struct hid_input *hi, | |
45 | + struct hid_field *field, struct hid_usage *usage, | |
46 | + unsigned long **bit, int *max) | |
47 | +{ | |
48 | + if (usage->type == EV_KEY || usage->type == EV_REL | |
49 | + || usage->type == EV_ABS) | |
50 | + clear_bit(usage->code, *bit); | |
51 | + | |
52 | + return 0; | |
53 | +} | |
54 | +static const struct hid_device_id ntrig_devices[] = { | |
55 | + { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN), | |
56 | + .driver_data = NTRIG_DUPLICATE_USAGES }, | |
57 | + { } | |
58 | +}; | |
59 | +MODULE_DEVICE_TABLE(hid, ntrig_devices); | |
60 | + | |
61 | +static struct hid_driver ntrig_driver = { | |
62 | + .name = "ntrig", | |
63 | + .id_table = ntrig_devices, | |
64 | + .input_mapping = ntrig_input_mapping, | |
65 | + .input_mapped = ntrig_input_mapped, | |
66 | +}; | |
67 | + | |
68 | +static int ntrig_init(void) | |
69 | +{ | |
70 | + return hid_register_driver(&ntrig_driver); | |
71 | +} | |
72 | + | |
73 | +static void ntrig_exit(void) | |
74 | +{ | |
75 | + hid_unregister_driver(&ntrig_driver); | |
76 | +} | |
77 | + | |
78 | +module_init(ntrig_init); | |
79 | +module_exit(ntrig_exit); | |
80 | +MODULE_LICENSE("GPL"); | |
81 | + | |
82 | +HID_COMPAT_LOAD_DRIVER(ntrig); |
drivers/hid/hid-sony.c
drivers/hid/hid-topseed.c
1 | +/* | |
2 | + * HID driver for TopSeed Cyberlink remote | |
3 | + * | |
4 | + * Copyright (c) 2008 Lev Babiev | |
5 | + * based on hid-cherry driver | |
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/device.h> | |
16 | +#include <linux/hid.h> | |
17 | +#include <linux/module.h> | |
18 | + | |
19 | +#include "hid-ids.h" | |
20 | + | |
21 | +#define ts_map_key_clear(c) hid_map_usage_clear(hi, usage, bit, max, \ | |
22 | + EV_KEY, (c)) | |
23 | +static int ts_input_mapping(struct hid_device *hdev, struct hid_input *hi, | |
24 | + struct hid_field *field, struct hid_usage *usage, | |
25 | + unsigned long **bit, int *max) | |
26 | +{ | |
27 | + if ((usage->hid & HID_USAGE_PAGE) != 0x0ffbc0000) | |
28 | + return 0; | |
29 | + | |
30 | + switch (usage->hid & HID_USAGE) { | |
31 | + case 0x00d: ts_map_key_clear(KEY_HOME); break; | |
32 | + case 0x024: ts_map_key_clear(KEY_MENU); break; | |
33 | + case 0x025: ts_map_key_clear(KEY_TV); break; | |
34 | + case 0x048: ts_map_key_clear(KEY_RED); break; | |
35 | + case 0x047: ts_map_key_clear(KEY_GREEN); break; | |
36 | + case 0x049: ts_map_key_clear(KEY_YELLOW); break; | |
37 | + case 0x04a: ts_map_key_clear(KEY_BLUE); break; | |
38 | + case 0x04b: ts_map_key_clear(KEY_ANGLE); break; | |
39 | + case 0x04c: ts_map_key_clear(KEY_LANGUAGE); break; | |
40 | + case 0x04d: ts_map_key_clear(KEY_SUBTITLE); break; | |
41 | + case 0x031: ts_map_key_clear(KEY_AUDIO); break; | |
42 | + case 0x032: ts_map_key_clear(KEY_TEXT); break; | |
43 | + case 0x033: ts_map_key_clear(KEY_CHANNEL); break; | |
44 | + default: | |
45 | + return 0; | |
46 | + } | |
47 | + | |
48 | + return 1; | |
49 | +} | |
50 | + | |
51 | +static const struct hid_device_id ts_devices[] = { | |
52 | + { HID_USB_DEVICE(USB_VENDOR_ID_TOPSEED, USB_DEVICE_ID_TOPSEED_CYBERLINK) }, | |
53 | + { } | |
54 | +}; | |
55 | +MODULE_DEVICE_TABLE(hid, ts_devices); | |
56 | + | |
57 | +static struct hid_driver ts_driver = { | |
58 | + .name = "topseed", | |
59 | + .id_table = ts_devices, | |
60 | + .input_mapping = ts_input_mapping, | |
61 | +}; | |
62 | + | |
63 | +static int ts_init(void) | |
64 | +{ | |
65 | + return hid_register_driver(&ts_driver); | |
66 | +} | |
67 | + | |
68 | +static void ts_exit(void) | |
69 | +{ | |
70 | + hid_unregister_driver(&ts_driver); | |
71 | +} | |
72 | + | |
73 | +module_init(ts_init); | |
74 | +module_exit(ts_exit); | |
75 | +MODULE_LICENSE("GPL"); | |
76 | + | |
77 | +HID_COMPAT_LOAD_DRIVER(topseed); |
drivers/hid/hidraw.c
... | ... | @@ -208,7 +208,7 @@ |
208 | 208 | |
209 | 209 | list_del(&list->node); |
210 | 210 | dev = hidraw_table[minor]; |
211 | - if (!dev->open--) { | |
211 | + if (!--dev->open) { | |
212 | 212 | if (list->hidraw->exist) |
213 | 213 | dev->hid->ll_driver->close(dev->hid); |
214 | 214 | else |
... | ... | @@ -265,6 +265,34 @@ |
265 | 265 | break; |
266 | 266 | } |
267 | 267 | default: |
268 | + { | |
269 | + struct hid_device *hid = dev->hid; | |
270 | + if (_IOC_TYPE(cmd) != 'H' || _IOC_DIR(cmd) != _IOC_READ) | |
271 | + return -EINVAL; | |
272 | + | |
273 | + if (_IOC_NR(cmd) == _IOC_NR(HIDIOCGRAWNAME(0))) { | |
274 | + int len; | |
275 | + if (!hid->name) | |
276 | + return 0; | |
277 | + len = strlen(hid->name) + 1; | |
278 | + if (len > _IOC_SIZE(cmd)) | |
279 | + len = _IOC_SIZE(cmd); | |
280 | + return copy_to_user(user_arg, hid->name, len) ? | |
281 | + -EFAULT : len; | |
282 | + } | |
283 | + | |
284 | + if (_IOC_NR(cmd) == _IOC_NR(HIDIOCGRAWPHYS(0))) { | |
285 | + int len; | |
286 | + if (!hid->phys) | |
287 | + return 0; | |
288 | + len = strlen(hid->phys) + 1; | |
289 | + if (len > _IOC_SIZE(cmd)) | |
290 | + len = _IOC_SIZE(cmd); | |
291 | + return copy_to_user(user_arg, hid->phys, len) ? | |
292 | + -EFAULT : len; | |
293 | + } | |
294 | + } | |
295 | + | |
268 | 296 | ret = -ENOTTY; |
269 | 297 | } |
270 | 298 | unlock_kernel(); |
... | ... | @@ -329,7 +357,7 @@ |
329 | 357 | goto out; |
330 | 358 | } |
331 | 359 | |
332 | - dev->dev = device_create(hidraw_class, NULL, MKDEV(hidraw_major, minor), | |
360 | + dev->dev = device_create(hidraw_class, &hid->dev, MKDEV(hidraw_major, minor), | |
333 | 361 | NULL, "%s%d", "hidraw", minor); |
334 | 362 | |
335 | 363 | if (IS_ERR(dev->dev)) { |
drivers/hid/usbhid/Kconfig
drivers/hid/usbhid/hid-core.c
... | ... | @@ -4,7 +4,7 @@ |
4 | 4 | * Copyright (c) 1999 Andreas Gal |
5 | 5 | * Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz> |
6 | 6 | * Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc |
7 | - * Copyright (c) 2006-2007 Jiri Kosina | |
7 | + * Copyright (c) 2006-2008 Jiri Kosina | |
8 | 8 | */ |
9 | 9 | |
10 | 10 | /* |
... | ... | @@ -641,9 +641,7 @@ |
641 | 641 | unsigned int size; |
642 | 642 | |
643 | 643 | list_for_each_entry(report, &hid->report_enum[type].report_list, list) { |
644 | - size = ((report->size - 1) >> 3) + 1; | |
645 | - if (type == HID_INPUT_REPORT && hid->report_enum[type].numbered) | |
646 | - size++; | |
644 | + size = ((report->size - 1) >> 3) + 1 + hid->report_enum[type].numbered; | |
647 | 645 | if (*max < size) |
648 | 646 | *max = size; |
649 | 647 | } |
650 | 648 | |
... | ... | @@ -653,14 +651,17 @@ |
653 | 651 | { |
654 | 652 | struct usbhid_device *usbhid = hid->driver_data; |
655 | 653 | |
656 | - if (!(usbhid->inbuf = usb_buffer_alloc(dev, usbhid->bufsize, GFP_ATOMIC, &usbhid->inbuf_dma))) | |
654 | + usbhid->inbuf = usb_buffer_alloc(dev, usbhid->bufsize, GFP_KERNEL, | |
655 | + &usbhid->inbuf_dma); | |
656 | + usbhid->outbuf = usb_buffer_alloc(dev, usbhid->bufsize, GFP_KERNEL, | |
657 | + &usbhid->outbuf_dma); | |
658 | + usbhid->cr = usb_buffer_alloc(dev, sizeof(*usbhid->cr), GFP_KERNEL, | |
659 | + &usbhid->cr_dma); | |
660 | + usbhid->ctrlbuf = usb_buffer_alloc(dev, usbhid->bufsize, GFP_KERNEL, | |
661 | + &usbhid->ctrlbuf_dma); | |
662 | + if (!usbhid->inbuf || !usbhid->outbuf || !usbhid->cr || | |
663 | + !usbhid->ctrlbuf) | |
657 | 664 | return -1; |
658 | - if (!(usbhid->outbuf = usb_buffer_alloc(dev, usbhid->bufsize, GFP_ATOMIC, &usbhid->outbuf_dma))) | |
659 | - return -1; | |
660 | - if (!(usbhid->cr = usb_buffer_alloc(dev, sizeof(*(usbhid->cr)), GFP_ATOMIC, &usbhid->cr_dma))) | |
661 | - return -1; | |
662 | - if (!(usbhid->ctrlbuf = usb_buffer_alloc(dev, usbhid->bufsize, GFP_ATOMIC, &usbhid->ctrlbuf_dma))) | |
663 | - return -1; | |
664 | 665 | |
665 | 666 | return 0; |
666 | 667 | } |
... | ... | @@ -807,7 +808,7 @@ |
807 | 808 | int interval; |
808 | 809 | |
809 | 810 | endpoint = &interface->endpoint[n].desc; |
810 | - if ((endpoint->bmAttributes & 3) != 3) /* Not an interrupt endpoint */ | |
811 | + if (!usb_endpoint_xfer_int(endpoint)) | |
811 | 812 | continue; |
812 | 813 | |
813 | 814 | interval = endpoint->bInterval; |
... | ... | @@ -875,6 +876,15 @@ |
875 | 876 | hid_dump_device(hid); |
876 | 877 | |
877 | 878 | set_bit(HID_STARTED, &usbhid->iofl); |
879 | + | |
880 | + /* Some keyboards don't work until their LEDs have been set. | |
881 | + * Since BIOSes do set the LEDs, it must be safe for any device | |
882 | + * that supports the keyboard boot protocol. | |
883 | + */ | |
884 | + if (interface->desc.bInterfaceSubClass == USB_INTERFACE_SUBCLASS_BOOT && | |
885 | + interface->desc.bInterfaceProtocol == | |
886 | + USB_INTERFACE_PROTOCOL_KEYBOARD) | |
887 | + usbhid_set_leds(hid); | |
878 | 888 | |
879 | 889 | return 0; |
880 | 890 |
drivers/hid/usbhid/hid-quirks.c
... | ... | @@ -54,6 +54,7 @@ |
54 | 54 | { USB_VENDOR_ID_ELO, USB_DEVICE_ID_ELO_TS2700, HID_QUIRK_NOGET }, |
55 | 55 | { USB_VENDOR_ID_SUN, USB_DEVICE_ID_RARITAN_KVM_DONGLE, HID_QUIRK_NOGET }, |
56 | 56 | { USB_VENDOR_ID_TURBOX, USB_DEVICE_ID_TURBOX_KEYBOARD, HID_QUIRK_NOGET }, |
57 | + { USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_PF1209, HID_QUIRK_MULTI_INPUT }, | |
57 | 58 | { USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_DUAL_USB_JOYPAD, HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT | HID_QUIRK_SKIP_OUTPUT_REPORTS }, |
58 | 59 | { USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_QUAD_USB_JOYPAD, HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT }, |
59 | 60 |
drivers/hid/usbhid/hiddev.c
... | ... | @@ -49,6 +49,7 @@ |
49 | 49 | struct hiddev { |
50 | 50 | int exist; |
51 | 51 | int open; |
52 | + struct mutex existancelock; | |
52 | 53 | wait_queue_head_t wait; |
53 | 54 | struct hid_device *hid; |
54 | 55 | struct list_head list; |
... | ... | @@ -63,6 +64,7 @@ |
63 | 64 | struct fasync_struct *fasync; |
64 | 65 | struct hiddev *hiddev; |
65 | 66 | struct list_head node; |
67 | + struct mutex thread_lock; | |
66 | 68 | }; |
67 | 69 | |
68 | 70 | static struct hiddev *hiddev_table[HIDDEV_MINORS]; |
69 | 71 | |
70 | 72 | |
71 | 73 | |
72 | 74 | |
73 | 75 | |
74 | 76 | |
... | ... | @@ -264,29 +266,48 @@ |
264 | 266 | static int hiddev_open(struct inode *inode, struct file *file) |
265 | 267 | { |
266 | 268 | struct hiddev_list *list; |
267 | - unsigned long flags; | |
269 | + int res; | |
268 | 270 | |
269 | 271 | int i = iminor(inode) - HIDDEV_MINOR_BASE; |
270 | 272 | |
271 | - if (i >= HIDDEV_MINORS || !hiddev_table[i]) | |
273 | + if (i >= HIDDEV_MINORS || i < 0 || !hiddev_table[i]) | |
272 | 274 | return -ENODEV; |
273 | 275 | |
274 | 276 | if (!(list = kzalloc(sizeof(struct hiddev_list), GFP_KERNEL))) |
275 | 277 | return -ENOMEM; |
278 | + mutex_init(&list->thread_lock); | |
276 | 279 | |
277 | 280 | list->hiddev = hiddev_table[i]; |
278 | 281 | |
279 | - spin_lock_irqsave(&list->hiddev->list_lock, flags); | |
280 | - list_add_tail(&list->node, &hiddev_table[i]->list); | |
281 | - spin_unlock_irqrestore(&list->hiddev->list_lock, flags); | |
282 | 282 | |
283 | 283 | file->private_data = list; |
284 | 284 | |
285 | - if (!list->hiddev->open++) | |
286 | - if (list->hiddev->exist) | |
287 | - usbhid_open(hiddev_table[i]->hid); | |
285 | + /* | |
286 | + * no need for locking because the USB major number | |
287 | + * is shared which usbcore guards against disconnect | |
288 | + */ | |
289 | + if (list->hiddev->exist) { | |
290 | + if (!list->hiddev->open++) { | |
291 | + res = usbhid_open(hiddev_table[i]->hid); | |
292 | + if (res < 0) { | |
293 | + res = -EIO; | |
294 | + goto bail; | |
295 | + } | |
296 | + } | |
297 | + } else { | |
298 | + res = -ENODEV; | |
299 | + goto bail; | |
300 | + } | |
288 | 301 | |
302 | + spin_lock_irq(&list->hiddev->list_lock); | |
303 | + list_add_tail(&list->node, &hiddev_table[i]->list); | |
304 | + spin_unlock_irq(&list->hiddev->list_lock); | |
305 | + | |
289 | 306 | return 0; |
307 | +bail: | |
308 | + file->private_data = NULL; | |
309 | + kfree(list->hiddev); | |
310 | + return res; | |
290 | 311 | } |
291 | 312 | |
292 | 313 | /* |
... | ... | @@ -305,7 +326,7 @@ |
305 | 326 | DECLARE_WAITQUEUE(wait, current); |
306 | 327 | struct hiddev_list *list = file->private_data; |
307 | 328 | int event_size; |
308 | - int retval = 0; | |
329 | + int retval; | |
309 | 330 | |
310 | 331 | event_size = ((list->flags & HIDDEV_FLAG_UREF) != 0) ? |
311 | 332 | sizeof(struct hiddev_usage_ref) : sizeof(struct hiddev_event); |
312 | 333 | |
... | ... | @@ -313,10 +334,14 @@ |
313 | 334 | if (count < event_size) |
314 | 335 | return 0; |
315 | 336 | |
337 | + /* lock against other threads */ | |
338 | + retval = mutex_lock_interruptible(&list->thread_lock); | |
339 | + if (retval) | |
340 | + return -ERESTARTSYS; | |
341 | + | |
316 | 342 | while (retval == 0) { |
317 | 343 | if (list->head == list->tail) { |
318 | - add_wait_queue(&list->hiddev->wait, &wait); | |
319 | - set_current_state(TASK_INTERRUPTIBLE); | |
344 | + prepare_to_wait(&list->hiddev->wait, &wait, TASK_INTERRUPTIBLE); | |
320 | 345 | |
321 | 346 | while (list->head == list->tail) { |
322 | 347 | if (file->f_flags & O_NONBLOCK) { |
323 | 348 | |
324 | 349 | |
325 | 350 | |
326 | 351 | |
327 | 352 | |
328 | 353 | |
329 | 354 | |
330 | 355 | |
331 | 356 | |
332 | 357 | |
333 | 358 | |
... | ... | @@ -332,35 +357,45 @@ |
332 | 357 | break; |
333 | 358 | } |
334 | 359 | |
360 | + /* let O_NONBLOCK tasks run */ | |
361 | + mutex_unlock(&list->thread_lock); | |
335 | 362 | schedule(); |
363 | + if (mutex_lock_interruptible(&list->thread_lock)) | |
364 | + return -EINTR; | |
336 | 365 | set_current_state(TASK_INTERRUPTIBLE); |
337 | 366 | } |
367 | + finish_wait(&list->hiddev->wait, &wait); | |
338 | 368 | |
339 | - set_current_state(TASK_RUNNING); | |
340 | - remove_wait_queue(&list->hiddev->wait, &wait); | |
341 | 369 | } |
342 | 370 | |
343 | - if (retval) | |
371 | + if (retval) { | |
372 | + mutex_unlock(&list->thread_lock); | |
344 | 373 | return retval; |
374 | + } | |
345 | 375 | |
346 | 376 | |
347 | 377 | while (list->head != list->tail && |
348 | 378 | retval + event_size <= count) { |
349 | 379 | if ((list->flags & HIDDEV_FLAG_UREF) == 0) { |
350 | - if (list->buffer[list->tail].field_index != | |
351 | - HID_FIELD_INDEX_NONE) { | |
380 | + if (list->buffer[list->tail].field_index != HID_FIELD_INDEX_NONE) { | |
352 | 381 | struct hiddev_event event; |
382 | + | |
353 | 383 | event.hid = list->buffer[list->tail].usage_code; |
354 | 384 | event.value = list->buffer[list->tail].value; |
355 | - if (copy_to_user(buffer + retval, &event, sizeof(struct hiddev_event))) | |
385 | + if (copy_to_user(buffer + retval, &event, sizeof(struct hiddev_event))) { | |
386 | + mutex_unlock(&list->thread_lock); | |
356 | 387 | return -EFAULT; |
388 | + } | |
357 | 389 | retval += sizeof(struct hiddev_event); |
358 | 390 | } |
359 | 391 | } else { |
360 | 392 | if (list->buffer[list->tail].field_index != HID_FIELD_INDEX_NONE || |
361 | 393 | (list->flags & HIDDEV_FLAG_REPORT) != 0) { |
362 | - if (copy_to_user(buffer + retval, list->buffer + list->tail, sizeof(struct hiddev_usage_ref))) | |
394 | + | |
395 | + if (copy_to_user(buffer + retval, list->buffer + list->tail, sizeof(struct hiddev_usage_ref))) { | |
396 | + mutex_unlock(&list->thread_lock); | |
363 | 397 | return -EFAULT; |
398 | + } | |
364 | 399 | retval += sizeof(struct hiddev_usage_ref); |
365 | 400 | } |
366 | 401 | } |
... | ... | @@ -368,6 +403,7 @@ |
368 | 403 | } |
369 | 404 | |
370 | 405 | } |
406 | + mutex_unlock(&list->thread_lock); | |
371 | 407 | |
372 | 408 | return retval; |
373 | 409 | } |
... | ... | @@ -555,7 +591,7 @@ |
555 | 591 | struct hid_field *field; |
556 | 592 | struct usbhid_device *usbhid = hid->driver_data; |
557 | 593 | void __user *user_arg = (void __user *)arg; |
558 | - int i; | |
594 | + int i, r; | |
559 | 595 | |
560 | 596 | /* Called without BKL by compat methods so no BKL taken */ |
561 | 597 | |
562 | 598 | |
563 | 599 | |
... | ... | @@ -619,10 +655,22 @@ |
619 | 655 | } |
620 | 656 | |
621 | 657 | case HIDIOCGSTRING: |
622 | - return hiddev_ioctl_string(hiddev, cmd, user_arg); | |
658 | + mutex_lock(&hiddev->existancelock); | |
659 | + if (!hiddev->exist) | |
660 | + r = hiddev_ioctl_string(hiddev, cmd, user_arg); | |
661 | + else | |
662 | + r = -ENODEV; | |
663 | + mutex_unlock(&hiddev->existancelock); | |
664 | + return r; | |
623 | 665 | |
624 | 666 | case HIDIOCINITREPORT: |
667 | + mutex_lock(&hiddev->existancelock); | |
668 | + if (!hiddev->exist) { | |
669 | + mutex_unlock(&hiddev->existancelock); | |
670 | + return -ENODEV; | |
671 | + } | |
625 | 672 | usbhid_init_reports(hid); |
673 | + mutex_unlock(&hiddev->existancelock); | |
626 | 674 | |
627 | 675 | return 0; |
628 | 676 | |
... | ... | @@ -636,8 +684,12 @@ |
636 | 684 | if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL) |
637 | 685 | return -EINVAL; |
638 | 686 | |
639 | - usbhid_submit_report(hid, report, USB_DIR_IN); | |
640 | - usbhid_wait_io(hid); | |
687 | + mutex_lock(&hiddev->existancelock); | |
688 | + if (hiddev->exist) { | |
689 | + usbhid_submit_report(hid, report, USB_DIR_IN); | |
690 | + usbhid_wait_io(hid); | |
691 | + } | |
692 | + mutex_unlock(&hiddev->existancelock); | |
641 | 693 | |
642 | 694 | return 0; |
643 | 695 | |
... | ... | @@ -651,8 +703,12 @@ |
651 | 703 | if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL) |
652 | 704 | return -EINVAL; |
653 | 705 | |
654 | - usbhid_submit_report(hid, report, USB_DIR_OUT); | |
655 | - usbhid_wait_io(hid); | |
706 | + mutex_lock(&hiddev->existancelock); | |
707 | + if (hiddev->exist) { | |
708 | + usbhid_submit_report(hid, report, USB_DIR_OUT); | |
709 | + usbhid_wait_io(hid); | |
710 | + } | |
711 | + mutex_unlock(&hiddev->existancelock); | |
656 | 712 | |
657 | 713 | return 0; |
658 | 714 | |
... | ... | @@ -710,7 +766,13 @@ |
710 | 766 | case HIDIOCGUSAGES: |
711 | 767 | case HIDIOCSUSAGES: |
712 | 768 | case HIDIOCGCOLLECTIONINDEX: |
713 | - return hiddev_ioctl_usage(hiddev, cmd, user_arg); | |
769 | + mutex_lock(&hiddev->existancelock); | |
770 | + if (hiddev->exist) | |
771 | + r = hiddev_ioctl_usage(hiddev, cmd, user_arg); | |
772 | + else | |
773 | + r = -ENODEV; | |
774 | + mutex_unlock(&hiddev->existancelock); | |
775 | + return r; | |
714 | 776 | |
715 | 777 | case HIDIOCGCOLLECTIONINFO: |
716 | 778 | if (copy_from_user(&cinfo, user_arg, sizeof(cinfo))) |
717 | 779 | |
718 | 780 | |
... | ... | @@ -808,24 +870,23 @@ |
808 | 870 | if (!(hiddev = kzalloc(sizeof(struct hiddev), GFP_KERNEL))) |
809 | 871 | return -1; |
810 | 872 | |
873 | + init_waitqueue_head(&hiddev->wait); | |
874 | + INIT_LIST_HEAD(&hiddev->list); | |
875 | + spin_lock_init(&hiddev->list_lock); | |
876 | + mutex_init(&hiddev->existancelock); | |
877 | + hiddev->hid = hid; | |
878 | + hiddev->exist = 1; | |
879 | + | |
811 | 880 | retval = usb_register_dev(usbhid->intf, &hiddev_class); |
812 | 881 | if (retval) { |
813 | 882 | err_hid("Not able to get a minor for this device."); |
814 | 883 | kfree(hiddev); |
815 | 884 | return -1; |
885 | + } else { | |
886 | + hid->minor = usbhid->intf->minor; | |
887 | + hiddev_table[usbhid->intf->minor - HIDDEV_MINOR_BASE] = hiddev; | |
816 | 888 | } |
817 | 889 | |
818 | - init_waitqueue_head(&hiddev->wait); | |
819 | - INIT_LIST_HEAD(&hiddev->list); | |
820 | - spin_lock_init(&hiddev->list_lock); | |
821 | - hiddev->hid = hid; | |
822 | - hiddev->exist = 1; | |
823 | - | |
824 | - hid->minor = usbhid->intf->minor; | |
825 | - hid->hiddev = hiddev; | |
826 | - | |
827 | - hiddev_table[usbhid->intf->minor - HIDDEV_MINOR_BASE] = hiddev; | |
828 | - | |
829 | 890 | return 0; |
830 | 891 | } |
831 | 892 | |
832 | 893 | |
... | ... | @@ -839,7 +900,9 @@ |
839 | 900 | struct hiddev *hiddev = hid->hiddev; |
840 | 901 | struct usbhid_device *usbhid = hid->driver_data; |
841 | 902 | |
903 | + mutex_lock(&hiddev->existancelock); | |
842 | 904 | hiddev->exist = 0; |
905 | + mutex_unlock(&hiddev->existancelock); | |
843 | 906 | |
844 | 907 | hiddev_table[hiddev->hid->minor - HIDDEV_MINOR_BASE] = NULL; |
845 | 908 | usb_deregister_dev(usbhid->intf, &hiddev_class); |
drivers/hid/usbhid/usbhid.h
... | ... | @@ -40,6 +40,16 @@ |
40 | 40 | void usbhid_init_reports(struct hid_device *hid); |
41 | 41 | void usbhid_submit_report(struct hid_device *hid, struct hid_report *report, unsigned char dir); |
42 | 42 | |
43 | +/* iofl flags */ | |
44 | +#define HID_CTRL_RUNNING 1 | |
45 | +#define HID_OUT_RUNNING 2 | |
46 | +#define HID_IN_RUNNING 3 | |
47 | +#define HID_RESET_PENDING 4 | |
48 | +#define HID_SUSPENDED 5 | |
49 | +#define HID_CLEAR_HALT 6 | |
50 | +#define HID_DISCONNECTED 7 | |
51 | +#define HID_STARTED 8 | |
52 | + | |
43 | 53 | /* |
44 | 54 | * USB-specific HID struct, to be pointed to |
45 | 55 | * from struct hid_device->driver_data |
include/linux/hid.h
... | ... | @@ -403,15 +403,6 @@ |
403 | 403 | #define HID_STAT_ADDED 1 |
404 | 404 | #define HID_STAT_PARSED 2 |
405 | 405 | |
406 | -#define HID_CTRL_RUNNING 1 | |
407 | -#define HID_OUT_RUNNING 2 | |
408 | -#define HID_IN_RUNNING 3 | |
409 | -#define HID_RESET_PENDING 4 | |
410 | -#define HID_SUSPENDED 5 | |
411 | -#define HID_CLEAR_HALT 6 | |
412 | -#define HID_DISCONNECTED 7 | |
413 | -#define HID_STARTED 8 | |
414 | - | |
415 | 406 | struct hid_input { |
416 | 407 | struct list_head list; |
417 | 408 | struct hid_report *report; |
... | ... | @@ -540,6 +531,8 @@ |
540 | 531 | * @name: driver name (e.g. "Footech_bar-wheel") |
541 | 532 | * @id_table: which devices is this driver for (must be non-NULL for probe |
542 | 533 | * to be called) |
534 | + * @dyn_list: list of dynamically added device ids | |
535 | + * @dyn_lock: lock protecting @dyn_list | |
543 | 536 | * @probe: new device inserted |
544 | 537 | * @remove: device removed (NULL if not a hot-plug capable driver) |
545 | 538 | * @report_table: on which reports to call raw_event (NULL means all) |
... | ... | @@ -567,6 +560,9 @@ |
567 | 560 | char *name; |
568 | 561 | const struct hid_device_id *id_table; |
569 | 562 | |
563 | + struct list_head dyn_list; | |
564 | + spinlock_t dyn_lock; | |
565 | + | |
570 | 566 | int (*probe)(struct hid_device *dev, const struct hid_device_id *id); |
571 | 567 | void (*remove)(struct hid_device *dev); |
572 | 568 | |
... | ... | @@ -797,6 +793,8 @@ |
797 | 793 | |
798 | 794 | #ifdef CONFIG_HID_COMPAT |
799 | 795 | #define HID_COMPAT_LOAD_DRIVER(name) \ |
796 | +/* prototype to avoid sparse warning */ \ | |
797 | +extern void hid_compat_##name(void); \ | |
800 | 798 | void hid_compat_##name(void) { } \ |
801 | 799 | EXPORT_SYMBOL(hid_compat_##name) |
802 | 800 | #else |
include/linux/hidraw.h
... | ... | @@ -33,6 +33,8 @@ |
33 | 33 | #define HIDIOCGRDESCSIZE _IOR('H', 0x01, int) |
34 | 34 | #define HIDIOCGRDESC _IOR('H', 0x02, struct hidraw_report_descriptor) |
35 | 35 | #define HIDIOCGRAWINFO _IOR('H', 0x03, struct hidraw_devinfo) |
36 | +#define HIDIOCGRAWNAME(len) _IOC(_IOC_READ, 'H', 0x04, len) | |
37 | +#define HIDIOCGRAWPHYS(len) _IOC(_IOC_READ, 'H', 0x05, len) | |
36 | 38 | |
37 | 39 | #define HIDRAW_FIRST_MINOR 0 |
38 | 40 | #define HIDRAW_MAX_DEVICES 64 |