diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2010-05-21 13:51:03 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-05-21 13:51:03 -0400 |
commit | 8b108c609adefd98577c35f0a41497a610041a6c (patch) | |
tree | f1552fdc5bf0ebcc484a88f01cd3864113adf25c /drivers/hid | |
parent | 7ce1418f95e918cfc5ad36e3ec3431145c768cd0 (diff) | |
parent | 73d5e8f77e88a4d3a154dfdbb4ed2cf461b7bf21 (diff) |
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: (59 commits)
HID: fix up 'EMBEDDED' mess in Kconfig
HID: roccat: cleanup preprocessor macros
HID: roccat: refactor special event handling
HID: roccat: fix special button support
HID: roccat: Correctly mark init and exit functions
HID: hidraw: Use Interrupt Endpoint for OUT Transfers if Available
HID: hid-samsung: remove redundant key mappings
HID: add omitted hid-zydacron.c file
HID: hid-samsung: add support for Creative Desktop Wireless 6000
HID: picolcd: Eliminate use after free
HID: Zydacron Remote Control driver
HID: Use kmemdup
HID: magicmouse: fix input registration
HID: make Prodikeys driver standalone config option
HID: Prodikeys PC-MIDI HID Driver
HID: hidraw: fix indentation
HID: ntrig: add filtering module parameters
HID: ntrig: add sysfs access to filter parameters
HID: ntrig: add sensitivity and responsiveness support
HID: add multi-input quirk for eGalax Touchcontroller
...
Diffstat (limited to 'drivers/hid')
-rw-r--r-- | drivers/hid/Kconfig | 151 | ||||
-rw-r--r-- | drivers/hid/Makefile | 6 | ||||
-rw-r--r-- | drivers/hid/hid-3m-pct.c | 31 | ||||
-rw-r--r-- | drivers/hid/hid-cando.c | 272 | ||||
-rw-r--r-- | drivers/hid/hid-core.c | 53 | ||||
-rw-r--r-- | drivers/hid/hid-egalax.c | 281 | ||||
-rw-r--r-- | drivers/hid/hid-ids.h | 25 | ||||
-rw-r--r-- | drivers/hid/hid-lg.c | 9 | ||||
-rw-r--r-- | drivers/hid/hid-magicmouse.c | 5 | ||||
-rw-r--r-- | drivers/hid/hid-ntrig.c | 526 | ||||
-rw-r--r-- | drivers/hid/hid-picolcd.c | 2631 | ||||
-rw-r--r-- | drivers/hid/hid-prodikeys.c | 910 | ||||
-rw-r--r-- | drivers/hid/hid-roccat-kone.c | 994 | ||||
-rw-r--r-- | drivers/hid/hid-roccat-kone.h | 224 | ||||
-rw-r--r-- | drivers/hid/hid-samsung.c | 95 | ||||
-rw-r--r-- | drivers/hid/hid-topseed.c | 38 | ||||
-rw-r--r-- | drivers/hid/hid-wacom.c | 229 | ||||
-rw-r--r-- | drivers/hid/hid-zydacron.c | 237 | ||||
-rw-r--r-- | drivers/hid/hidraw.c | 50 | ||||
-rw-r--r-- | drivers/hid/usbhid/hid-core.c | 73 | ||||
-rw-r--r-- | drivers/hid/usbhid/hid-quirks.c | 1 | ||||
-rw-r--r-- | drivers/hid/usbhid/hiddev.c | 19 | ||||
-rw-r--r-- | drivers/hid/usbhid/usbkbd.c | 1 |
23 files changed, 6704 insertions, 157 deletions
diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index 71d4c0703629..76ba59b9fea1 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig | |||
@@ -86,6 +86,12 @@ config HID_BELKIN | |||
86 | ---help--- | 86 | ---help--- |
87 | Support for Belkin Flip KVM and Wireless keyboard. | 87 | Support for Belkin Flip KVM and Wireless keyboard. |
88 | 88 | ||
89 | config HID_CANDO | ||
90 | tristate "Cando dual touch panel" | ||
91 | depends on USB_HID | ||
92 | ---help--- | ||
93 | Support for Cando dual touch panel. | ||
94 | |||
89 | config HID_CHERRY | 95 | config HID_CHERRY |
90 | tristate "Cherry" if EMBEDDED | 96 | tristate "Cherry" if EMBEDDED |
91 | depends on USB_HID | 97 | depends on USB_HID |
@@ -100,6 +106,21 @@ config HID_CHICONY | |||
100 | ---help--- | 106 | ---help--- |
101 | Support for Chicony Tactical pad. | 107 | Support for Chicony Tactical pad. |
102 | 108 | ||
109 | config HID_PRODIKEYS | ||
110 | tristate "Prodikeys PC-MIDI Keyboard support" | ||
111 | depends on USB_HID && SND | ||
112 | select SND_RAWMIDI | ||
113 | ---help--- | ||
114 | Support for Prodikeys PC-MIDI Keyboard device support. | ||
115 | Say Y here to enable support for this device. | ||
116 | - Prodikeys PC-MIDI keyboard. | ||
117 | The Prodikeys PC-MIDI acts as a USB Audio device, with one MIDI | ||
118 | input and one MIDI output. These MIDI jacks appear as | ||
119 | a sound "card" in the ALSA sound system. | ||
120 | Note: if you say N here, this device will still function as a basic | ||
121 | multimedia keyboard, but will lack support for the musical keyboard | ||
122 | and some additional multimedia keys. | ||
123 | |||
103 | config HID_CYPRESS | 124 | config HID_CYPRESS |
104 | tristate "Cypress" if EMBEDDED | 125 | tristate "Cypress" if EMBEDDED |
105 | depends on USB_HID | 126 | depends on USB_HID |
@@ -108,9 +129,8 @@ config HID_CYPRESS | |||
108 | Support for cypress mouse and barcode readers. | 129 | Support for cypress mouse and barcode readers. |
109 | 130 | ||
110 | config HID_DRAGONRISE | 131 | config HID_DRAGONRISE |
111 | tristate "DragonRise Inc. support" if EMBEDDED | 132 | tristate "DragonRise Inc. support" |
112 | depends on USB_HID | 133 | depends on USB_HID |
113 | default !EMBEDDED | ||
114 | ---help--- | 134 | ---help--- |
115 | Say Y here if you have DragonRise Inc.game controllers. | 135 | Say Y here if you have DragonRise Inc.game controllers. |
116 | 136 | ||
@@ -122,6 +142,12 @@ config DRAGONRISE_FF | |||
122 | Say Y here if you want to enable force feedback support for DragonRise Inc. | 142 | Say Y here if you want to enable force feedback support for DragonRise Inc. |
123 | game controllers. | 143 | game controllers. |
124 | 144 | ||
145 | config HID_EGALAX | ||
146 | tristate "eGalax multi-touch panel" | ||
147 | depends on USB_HID | ||
148 | ---help--- | ||
149 | Support for the eGalax dual-touch panel. | ||
150 | |||
125 | config HID_EZKEY | 151 | config HID_EZKEY |
126 | tristate "Ezkey" if EMBEDDED | 152 | tristate "Ezkey" if EMBEDDED |
127 | depends on USB_HID | 153 | depends on USB_HID |
@@ -137,16 +163,14 @@ config HID_KYE | |||
137 | Support for Kye/Genius Ergo Mouse. | 163 | Support for Kye/Genius Ergo Mouse. |
138 | 164 | ||
139 | config HID_GYRATION | 165 | config HID_GYRATION |
140 | tristate "Gyration" if EMBEDDED | 166 | tristate "Gyration" |
141 | depends on USB_HID | 167 | depends on USB_HID |
142 | default !EMBEDDED | ||
143 | ---help--- | 168 | ---help--- |
144 | Support for Gyration remote control. | 169 | Support for Gyration remote control. |
145 | 170 | ||
146 | config HID_TWINHAN | 171 | config HID_TWINHAN |
147 | tristate "Twinhan" if EMBEDDED | 172 | tristate "Twinhan" |
148 | depends on USB_HID | 173 | depends on USB_HID |
149 | default !EMBEDDED | ||
150 | ---help--- | 174 | ---help--- |
151 | Support for Twinhan IR remote control. | 175 | Support for Twinhan IR remote control. |
152 | 176 | ||
@@ -233,16 +257,14 @@ config HID_NTRIG | |||
233 | Support for N-Trig touch screen. | 257 | Support for N-Trig touch screen. |
234 | 258 | ||
235 | config HID_ORTEK | 259 | config HID_ORTEK |
236 | tristate "Ortek" if EMBEDDED | 260 | tristate "Ortek" |
237 | depends on USB_HID | 261 | depends on USB_HID |
238 | default !EMBEDDED | ||
239 | ---help--- | 262 | ---help--- |
240 | Support for Ortek WKB-2000 wireless keyboard + mouse trackpad. | 263 | Support for Ortek WKB-2000 wireless keyboard + mouse trackpad. |
241 | 264 | ||
242 | config HID_PANTHERLORD | 265 | config HID_PANTHERLORD |
243 | tristate "Pantherlord support" if EMBEDDED | 266 | tristate "Pantherlord support" |
244 | depends on USB_HID | 267 | depends on USB_HID |
245 | default !EMBEDDED | ||
246 | ---help--- | 268 | ---help--- |
247 | Say Y here if you have a PantherLord/GreenAsia based game controller | 269 | Say Y here if you have a PantherLord/GreenAsia based game controller |
248 | or adapter. | 270 | or adapter. |
@@ -256,29 +278,90 @@ config PANTHERLORD_FF | |||
256 | or adapter and want to enable force feedback support for it. | 278 | or adapter and want to enable force feedback support for it. |
257 | 279 | ||
258 | config HID_PETALYNX | 280 | config HID_PETALYNX |
259 | tristate "Petalynx" if EMBEDDED | 281 | tristate "Petalynx" |
260 | depends on USB_HID | 282 | depends on USB_HID |
261 | default !EMBEDDED | ||
262 | ---help--- | 283 | ---help--- |
263 | Support for Petalynx Maxter remote control. | 284 | Support for Petalynx Maxter remote control. |
264 | 285 | ||
286 | config HID_PICOLCD | ||
287 | tristate "PicoLCD (graphic version)" | ||
288 | depends on USB_HID | ||
289 | ---help--- | ||
290 | This provides support for Minibox PicoLCD devices, currently | ||
291 | only the graphical ones are supported. | ||
292 | |||
293 | This includes support for the following device features: | ||
294 | - Keypad | ||
295 | - Switching between Firmware and Flash mode | ||
296 | - EEProm / Flash access (via debugfs) | ||
297 | Features selectively enabled: | ||
298 | - Framebuffer for monochrome 256x64 display | ||
299 | - Backlight control | ||
300 | - Contrast control | ||
301 | - General purpose outputs | ||
302 | Features that are not (yet) supported: | ||
303 | - IR | ||
304 | |||
305 | config HID_PICOLCD_FB | ||
306 | bool "Framebuffer support" if EMBEDDED | ||
307 | default !EMBEDDED | ||
308 | depends on HID_PICOLCD | ||
309 | depends on HID_PICOLCD=FB || FB=y | ||
310 | select FB_DEFERRED_IO | ||
311 | select FB_SYS_FILLRECT | ||
312 | select FB_SYS_COPYAREA | ||
313 | select FB_SYS_IMAGEBLIT | ||
314 | select FB_SYS_FOPS | ||
315 | ---help--- | ||
316 | Provide access to PicoLCD's 256x64 monochrome display via a | ||
317 | frambuffer device. | ||
318 | |||
319 | config HID_PICOLCD_BACKLIGHT | ||
320 | bool "Backlight control" if EMBEDDED | ||
321 | default !EMBEDDED | ||
322 | depends on HID_PICOLCD | ||
323 | depends on HID_PICOLCD=BACKLIGHT_CLASS_DEVICE || BACKLIGHT_CLASS_DEVICE=y | ||
324 | ---help--- | ||
325 | Provide access to PicoLCD's backlight control via backlight | ||
326 | class. | ||
327 | |||
328 | config HID_PICOLCD_LCD | ||
329 | bool "Contrast control" if EMBEDDED | ||
330 | default !EMBEDDED | ||
331 | depends on HID_PICOLCD | ||
332 | depends on HID_PICOLCD=LCD_CLASS_DEVICE || LCD_CLASS_DEVICE=y | ||
333 | ---help--- | ||
334 | Provide access to PicoLCD's LCD contrast via lcd class. | ||
335 | |||
336 | config HID_PICOLCD_LEDS | ||
337 | bool "GPO via leds class" if EMBEDDED | ||
338 | default !EMBEDDED | ||
339 | depends on HID_PICOLCD | ||
340 | depends on HID_PICOLCD=LEDS_CLASS || LEDS_CLASS=y | ||
341 | ---help--- | ||
342 | Provide access to PicoLCD's GPO pins via leds class. | ||
343 | |||
265 | config HID_QUANTA | 344 | config HID_QUANTA |
266 | tristate "Quanta Optical Touch" | 345 | tristate "Quanta Optical Touch" |
267 | depends on USB_HID | 346 | depends on USB_HID |
268 | ---help--- | 347 | ---help--- |
269 | Support for Quanta Optical Touch dual-touch panels. | 348 | Support for Quanta Optical Touch dual-touch panels. |
270 | 349 | ||
350 | config HID_ROCCAT_KONE | ||
351 | tristate "Roccat Kone Mouse support" | ||
352 | depends on USB_HID | ||
353 | ---help--- | ||
354 | Support for Roccat Kone mouse. | ||
355 | |||
271 | config HID_SAMSUNG | 356 | config HID_SAMSUNG |
272 | tristate "Samsung" if EMBEDDED | 357 | tristate "Samsung" |
273 | depends on USB_HID | 358 | depends on USB_HID |
274 | default !EMBEDDED | ||
275 | ---help--- | 359 | ---help--- |
276 | Support for Samsung InfraRed remote control. | 360 | Support for Samsung InfraRed remote control or keyboards. |
277 | 361 | ||
278 | config HID_SONY | 362 | config HID_SONY |
279 | tristate "Sony" if EMBEDDED | 363 | tristate "Sony" |
280 | depends on USB_HID | 364 | depends on USB_HID |
281 | default !EMBEDDED | ||
282 | ---help--- | 365 | ---help--- |
283 | Support for Sony PS3 controller. | 366 | Support for Sony PS3 controller. |
284 | 367 | ||
@@ -289,16 +372,14 @@ config HID_STANTUM | |||
289 | Support for Stantum multitouch panel. | 372 | Support for Stantum multitouch panel. |
290 | 373 | ||
291 | config HID_SUNPLUS | 374 | config HID_SUNPLUS |
292 | tristate "Sunplus" if EMBEDDED | 375 | tristate "Sunplus" |
293 | depends on USB_HID | 376 | depends on USB_HID |
294 | default !EMBEDDED | ||
295 | ---help--- | 377 | ---help--- |
296 | Support for Sunplus wireless desktop. | 378 | Support for Sunplus wireless desktop. |
297 | 379 | ||
298 | config HID_GREENASIA | 380 | config HID_GREENASIA |
299 | tristate "GreenAsia (Product ID 0x12) support" if EMBEDDED | 381 | tristate "GreenAsia (Product ID 0x12) support" |
300 | depends on USB_HID | 382 | depends on USB_HID |
301 | default !EMBEDDED | ||
302 | ---help--- | 383 | ---help--- |
303 | Say Y here if you have a GreenAsia (Product ID 0x12) based game | 384 | Say Y here if you have a GreenAsia (Product ID 0x12) based game |
304 | controller or adapter. | 385 | controller or adapter. |
@@ -313,9 +394,8 @@ config GREENASIA_FF | |||
313 | and want to enable force feedback support for it. | 394 | and want to enable force feedback support for it. |
314 | 395 | ||
315 | config HID_SMARTJOYPLUS | 396 | config HID_SMARTJOYPLUS |
316 | tristate "SmartJoy PLUS PS2/USB adapter support" if EMBEDDED | 397 | tristate "SmartJoy PLUS PS2/USB adapter support" |
317 | depends on USB_HID | 398 | depends on USB_HID |
318 | default !EMBEDDED | ||
319 | ---help--- | 399 | ---help--- |
320 | Support for SmartJoy PLUS PS2/USB adapter. | 400 | Support for SmartJoy PLUS PS2/USB adapter. |
321 | 401 | ||
@@ -328,16 +408,14 @@ config SMARTJOYPLUS_FF | |||
328 | enable force feedback support for it. | 408 | enable force feedback support for it. |
329 | 409 | ||
330 | config HID_TOPSEED | 410 | config HID_TOPSEED |
331 | tristate "TopSeed Cyberlink remote control support" if EMBEDDED | 411 | tristate "TopSeed Cyberlink remote control support" |
332 | depends on USB_HID | 412 | depends on USB_HID |
333 | default !EMBEDDED | ||
334 | ---help--- | 413 | ---help--- |
335 | Say Y if you have a TopSeed Cyberlink remote control. | 414 | Say Y if you have a TopSeed Cyberlink or BTC Emprex remote control. |
336 | 415 | ||
337 | config HID_THRUSTMASTER | 416 | config HID_THRUSTMASTER |
338 | tristate "ThrustMaster devices support" if EMBEDDED | 417 | tristate "ThrustMaster devices support" |
339 | depends on USB_HID | 418 | depends on USB_HID |
340 | default !EMBEDDED | ||
341 | ---help--- | 419 | ---help--- |
342 | Say Y here if you have a THRUSTMASTER FireStore Dual Power 2 or | 420 | Say Y here if you have a THRUSTMASTER FireStore Dual Power 2 or |
343 | a THRUSTMASTER Ferrari GT Rumble Wheel. | 421 | a THRUSTMASTER Ferrari GT Rumble Wheel. |
@@ -357,10 +435,17 @@ config HID_WACOM | |||
357 | ---help--- | 435 | ---help--- |
358 | Support for Wacom Graphire Bluetooth tablet. | 436 | Support for Wacom Graphire Bluetooth tablet. |
359 | 437 | ||
438 | config HID_WACOM_POWER_SUPPLY | ||
439 | bool "Wacom Bluetooth devices power supply status support" | ||
440 | depends on HID_WACOM | ||
441 | select POWER_SUPPLY | ||
442 | ---help--- | ||
443 | Say Y here if you want to enable power supply status monitoring for | ||
444 | Wacom Bluetooth devices. | ||
445 | |||
360 | config HID_ZEROPLUS | 446 | config HID_ZEROPLUS |
361 | tristate "Zeroplus based game controller support" if EMBEDDED | 447 | tristate "Zeroplus based game controller support" |
362 | depends on USB_HID | 448 | depends on USB_HID |
363 | default !EMBEDDED | ||
364 | ---help--- | 449 | ---help--- |
365 | Say Y here if you have a Zeroplus based game controller. | 450 | Say Y here if you have a Zeroplus based game controller. |
366 | 451 | ||
@@ -372,6 +457,12 @@ config ZEROPLUS_FF | |||
372 | Say Y here if you have a Zeroplus based game controller and want | 457 | Say Y here if you have a Zeroplus based game controller and want |
373 | to have force feedback support for it. | 458 | to have force feedback support for it. |
374 | 459 | ||
460 | config HID_ZYDACRON | ||
461 | tristate "Zydacron remote control support" | ||
462 | depends on USB_HID | ||
463 | ---help--- | ||
464 | Support for Zydacron remote control. | ||
465 | |||
375 | endmenu | 466 | endmenu |
376 | 467 | ||
377 | endif # HID_SUPPORT | 468 | endif # HID_SUPPORT |
diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile index 0b2618f092ca..22e47eaeea32 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile | |||
@@ -26,10 +26,12 @@ obj-$(CONFIG_HID_3M_PCT) += hid-3m-pct.o | |||
26 | obj-$(CONFIG_HID_A4TECH) += hid-a4tech.o | 26 | obj-$(CONFIG_HID_A4TECH) += hid-a4tech.o |
27 | obj-$(CONFIG_HID_APPLE) += hid-apple.o | 27 | obj-$(CONFIG_HID_APPLE) += hid-apple.o |
28 | obj-$(CONFIG_HID_BELKIN) += hid-belkin.o | 28 | obj-$(CONFIG_HID_BELKIN) += hid-belkin.o |
29 | obj-$(CONFIG_HID_CANDO) += hid-cando.o | ||
29 | obj-$(CONFIG_HID_CHERRY) += hid-cherry.o | 30 | obj-$(CONFIG_HID_CHERRY) += hid-cherry.o |
30 | obj-$(CONFIG_HID_CHICONY) += hid-chicony.o | 31 | obj-$(CONFIG_HID_CHICONY) += hid-chicony.o |
31 | obj-$(CONFIG_HID_CYPRESS) += hid-cypress.o | 32 | obj-$(CONFIG_HID_CYPRESS) += hid-cypress.o |
32 | obj-$(CONFIG_HID_DRAGONRISE) += hid-drff.o | 33 | obj-$(CONFIG_HID_DRAGONRISE) += hid-drff.o |
34 | obj-$(CONFIG_HID_EGALAX) += hid-egalax.o | ||
33 | obj-$(CONFIG_HID_EZKEY) += hid-ezkey.o | 35 | obj-$(CONFIG_HID_EZKEY) += hid-ezkey.o |
34 | obj-$(CONFIG_HID_GYRATION) += hid-gyration.o | 36 | obj-$(CONFIG_HID_GYRATION) += hid-gyration.o |
35 | obj-$(CONFIG_HID_KENSINGTON) += hid-kensington.o | 37 | obj-$(CONFIG_HID_KENSINGTON) += hid-kensington.o |
@@ -41,9 +43,12 @@ obj-$(CONFIG_HID_MONTEREY) += hid-monterey.o | |||
41 | obj-$(CONFIG_HID_MOSART) += hid-mosart.o | 43 | obj-$(CONFIG_HID_MOSART) += hid-mosart.o |
42 | obj-$(CONFIG_HID_NTRIG) += hid-ntrig.o | 44 | obj-$(CONFIG_HID_NTRIG) += hid-ntrig.o |
43 | obj-$(CONFIG_HID_ORTEK) += hid-ortek.o | 45 | obj-$(CONFIG_HID_ORTEK) += hid-ortek.o |
46 | obj-$(CONFIG_HID_PRODIKEYS) += hid-prodikeys.o | ||
44 | obj-$(CONFIG_HID_QUANTA) += hid-quanta.o | 47 | obj-$(CONFIG_HID_QUANTA) += hid-quanta.o |
45 | obj-$(CONFIG_HID_PANTHERLORD) += hid-pl.o | 48 | obj-$(CONFIG_HID_PANTHERLORD) += hid-pl.o |
46 | obj-$(CONFIG_HID_PETALYNX) += hid-petalynx.o | 49 | obj-$(CONFIG_HID_PETALYNX) += hid-petalynx.o |
50 | obj-$(CONFIG_HID_PICOLCD) += hid-picolcd.o | ||
51 | obj-$(CONFIG_HID_ROCCAT_KONE) += hid-roccat-kone.o | ||
47 | obj-$(CONFIG_HID_SAMSUNG) += hid-samsung.o | 52 | obj-$(CONFIG_HID_SAMSUNG) += hid-samsung.o |
48 | obj-$(CONFIG_HID_SMARTJOYPLUS) += hid-sjoy.o | 53 | obj-$(CONFIG_HID_SMARTJOYPLUS) += hid-sjoy.o |
49 | obj-$(CONFIG_HID_SONY) += hid-sony.o | 54 | obj-$(CONFIG_HID_SONY) += hid-sony.o |
@@ -54,6 +59,7 @@ obj-$(CONFIG_HID_THRUSTMASTER) += hid-tmff.o | |||
54 | obj-$(CONFIG_HID_TOPSEED) += hid-topseed.o | 59 | obj-$(CONFIG_HID_TOPSEED) += hid-topseed.o |
55 | obj-$(CONFIG_HID_TWINHAN) += hid-twinhan.o | 60 | obj-$(CONFIG_HID_TWINHAN) += hid-twinhan.o |
56 | obj-$(CONFIG_HID_ZEROPLUS) += hid-zpff.o | 61 | obj-$(CONFIG_HID_ZEROPLUS) += hid-zpff.o |
62 | obj-$(CONFIG_HID_ZYDACRON) += hid-zydacron.o | ||
57 | obj-$(CONFIG_HID_WACOM) += hid-wacom.o | 63 | obj-$(CONFIG_HID_WACOM) += hid-wacom.o |
58 | 64 | ||
59 | obj-$(CONFIG_USB_HID) += usbhid/ | 65 | obj-$(CONFIG_USB_HID) += usbhid/ |
diff --git a/drivers/hid/hid-3m-pct.c b/drivers/hid/hid-3m-pct.c index c31e0be8ccea..2a0d56b7a02b 100644 --- a/drivers/hid/hid-3m-pct.c +++ b/drivers/hid/hid-3m-pct.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * HID driver for 3M PCT multitouch panels | 2 | * HID driver for 3M PCT multitouch panels |
3 | * | 3 | * |
4 | * Copyright (c) 2009 Stephane Chatty <chatty@enac.fr> | 4 | * Copyright (c) 2009-2010 Stephane Chatty <chatty@enac.fr> |
5 | * | 5 | * |
6 | */ | 6 | */ |
7 | 7 | ||
@@ -25,7 +25,7 @@ MODULE_LICENSE("GPL"); | |||
25 | #include "hid-ids.h" | 25 | #include "hid-ids.h" |
26 | 26 | ||
27 | struct mmm_finger { | 27 | struct mmm_finger { |
28 | __s32 x, y; | 28 | __s32 x, y, w, h; |
29 | __u8 rank; | 29 | __u8 rank; |
30 | bool touch, valid; | 30 | bool touch, valid; |
31 | }; | 31 | }; |
@@ -82,7 +82,18 @@ static int mmm_input_mapping(struct hid_device *hdev, struct hid_input *hi, | |||
82 | /* touchscreen emulation */ | 82 | /* touchscreen emulation */ |
83 | hid_map_usage(hi, usage, bit, max, EV_KEY, BTN_TOUCH); | 83 | hid_map_usage(hi, usage, bit, max, EV_KEY, BTN_TOUCH); |
84 | return 1; | 84 | return 1; |
85 | case HID_DG_WIDTH: | ||
86 | hid_map_usage(hi, usage, bit, max, | ||
87 | EV_ABS, ABS_MT_TOUCH_MAJOR); | ||
88 | return 1; | ||
89 | case HID_DG_HEIGHT: | ||
90 | hid_map_usage(hi, usage, bit, max, | ||
91 | EV_ABS, ABS_MT_TOUCH_MINOR); | ||
92 | input_set_abs_params(hi->input, ABS_MT_ORIENTATION, | ||
93 | 1, 1, 0, 0); | ||
94 | return 1; | ||
85 | case HID_DG_CONTACTID: | 95 | case HID_DG_CONTACTID: |
96 | field->logical_maximum = 59; | ||
86 | hid_map_usage(hi, usage, bit, max, | 97 | hid_map_usage(hi, usage, bit, max, |
87 | EV_ABS, ABS_MT_TRACKING_ID); | 98 | EV_ABS, ABS_MT_TRACKING_ID); |
88 | return 1; | 99 | return 1; |
@@ -128,9 +139,15 @@ static void mmm_filter_event(struct mmm_data *md, struct input_dev *input) | |||
128 | /* this finger is just placeholder data, ignore */ | 139 | /* this finger is just placeholder data, ignore */ |
129 | } else if (f->touch) { | 140 | } else if (f->touch) { |
130 | /* this finger is on the screen */ | 141 | /* this finger is on the screen */ |
142 | int wide = (f->w > f->h); | ||
131 | input_event(input, EV_ABS, ABS_MT_TRACKING_ID, i); | 143 | input_event(input, EV_ABS, ABS_MT_TRACKING_ID, i); |
132 | input_event(input, EV_ABS, ABS_MT_POSITION_X, f->x); | 144 | input_event(input, EV_ABS, ABS_MT_POSITION_X, f->x); |
133 | input_event(input, EV_ABS, ABS_MT_POSITION_Y, f->y); | 145 | input_event(input, EV_ABS, ABS_MT_POSITION_Y, f->y); |
146 | input_event(input, EV_ABS, ABS_MT_ORIENTATION, wide); | ||
147 | input_event(input, EV_ABS, ABS_MT_TOUCH_MAJOR, | ||
148 | wide ? f->w : f->h); | ||
149 | input_event(input, EV_ABS, ABS_MT_TOUCH_MINOR, | ||
150 | wide ? f->h : f->w); | ||
134 | input_mt_sync(input); | 151 | input_mt_sync(input); |
135 | /* | 152 | /* |
136 | * touchscreen emulation: maintain the age rank | 153 | * touchscreen emulation: maintain the age rank |
@@ -197,6 +214,14 @@ static int mmm_event(struct hid_device *hid, struct hid_field *field, | |||
197 | case HID_DG_CONFIDENCE: | 214 | case HID_DG_CONFIDENCE: |
198 | md->valid = value; | 215 | md->valid = value; |
199 | break; | 216 | break; |
217 | case HID_DG_WIDTH: | ||
218 | if (md->valid) | ||
219 | md->f[md->curid].w = value; | ||
220 | break; | ||
221 | case HID_DG_HEIGHT: | ||
222 | if (md->valid) | ||
223 | md->f[md->curid].h = value; | ||
224 | break; | ||
200 | case HID_DG_CONTACTID: | 225 | case HID_DG_CONTACTID: |
201 | if (md->valid) { | 226 | if (md->valid) { |
202 | md->curid = value; | 227 | md->curid = value; |
@@ -255,6 +280,7 @@ static void mmm_remove(struct hid_device *hdev) | |||
255 | 280 | ||
256 | static const struct hid_device_id mmm_devices[] = { | 281 | static const struct hid_device_id mmm_devices[] = { |
257 | { HID_USB_DEVICE(USB_VENDOR_ID_3M, USB_DEVICE_ID_3M1968) }, | 282 | { HID_USB_DEVICE(USB_VENDOR_ID_3M, USB_DEVICE_ID_3M1968) }, |
283 | { HID_USB_DEVICE(USB_VENDOR_ID_3M, USB_DEVICE_ID_3M2256) }, | ||
258 | { } | 284 | { } |
259 | }; | 285 | }; |
260 | MODULE_DEVICE_TABLE(hid, mmm_devices); | 286 | MODULE_DEVICE_TABLE(hid, mmm_devices); |
@@ -287,5 +313,4 @@ static void __exit mmm_exit(void) | |||
287 | 313 | ||
288 | module_init(mmm_init); | 314 | module_init(mmm_init); |
289 | module_exit(mmm_exit); | 315 | module_exit(mmm_exit); |
290 | MODULE_LICENSE("GPL"); | ||
291 | 316 | ||
diff --git a/drivers/hid/hid-cando.c b/drivers/hid/hid-cando.c new file mode 100644 index 000000000000..4267a6fdc277 --- /dev/null +++ b/drivers/hid/hid-cando.c | |||
@@ -0,0 +1,272 @@ | |||
1 | /* | ||
2 | * HID driver for Cando dual-touch panels | ||
3 | * | ||
4 | * Copyright (c) 2010 Stephane Chatty <chatty@enac.fr> | ||
5 | * | ||
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 | #include <linux/slab.h> | ||
19 | |||
20 | MODULE_AUTHOR("Stephane Chatty <chatty@enac.fr>"); | ||
21 | MODULE_DESCRIPTION("Cando dual-touch panel"); | ||
22 | MODULE_LICENSE("GPL"); | ||
23 | |||
24 | #include "hid-ids.h" | ||
25 | |||
26 | struct cando_data { | ||
27 | __u16 x, y; | ||
28 | __u8 id; | ||
29 | __s8 oldest; /* id of the oldest finger in previous frame */ | ||
30 | bool valid; /* valid finger data, or just placeholder? */ | ||
31 | bool first; /* is this the first finger in this frame? */ | ||
32 | __s8 firstid; /* id of the first finger in the frame */ | ||
33 | __u16 firstx, firsty; /* (x, y) of the first finger in the frame */ | ||
34 | }; | ||
35 | |||
36 | static int cando_input_mapping(struct hid_device *hdev, struct hid_input *hi, | ||
37 | struct hid_field *field, struct hid_usage *usage, | ||
38 | unsigned long **bit, int *max) | ||
39 | { | ||
40 | switch (usage->hid & HID_USAGE_PAGE) { | ||
41 | |||
42 | case HID_UP_GENDESK: | ||
43 | switch (usage->hid) { | ||
44 | case HID_GD_X: | ||
45 | hid_map_usage(hi, usage, bit, max, | ||
46 | EV_ABS, ABS_MT_POSITION_X); | ||
47 | /* touchscreen emulation */ | ||
48 | input_set_abs_params(hi->input, ABS_X, | ||
49 | field->logical_minimum, | ||
50 | field->logical_maximum, 0, 0); | ||
51 | return 1; | ||
52 | case HID_GD_Y: | ||
53 | hid_map_usage(hi, usage, bit, max, | ||
54 | EV_ABS, ABS_MT_POSITION_Y); | ||
55 | /* touchscreen emulation */ | ||
56 | input_set_abs_params(hi->input, ABS_Y, | ||
57 | field->logical_minimum, | ||
58 | field->logical_maximum, 0, 0); | ||
59 | return 1; | ||
60 | } | ||
61 | return 0; | ||
62 | |||
63 | case HID_UP_DIGITIZER: | ||
64 | switch (usage->hid) { | ||
65 | case HID_DG_TIPSWITCH: | ||
66 | case HID_DG_CONTACTMAX: | ||
67 | return -1; | ||
68 | case HID_DG_INRANGE: | ||
69 | /* touchscreen emulation */ | ||
70 | hid_map_usage(hi, usage, bit, max, EV_KEY, BTN_TOUCH); | ||
71 | return 1; | ||
72 | case HID_DG_CONTACTID: | ||
73 | hid_map_usage(hi, usage, bit, max, | ||
74 | EV_ABS, ABS_MT_TRACKING_ID); | ||
75 | return 1; | ||
76 | } | ||
77 | return 0; | ||
78 | } | ||
79 | |||
80 | return 0; | ||
81 | } | ||
82 | |||
83 | static int cando_input_mapped(struct hid_device *hdev, struct hid_input *hi, | ||
84 | struct hid_field *field, struct hid_usage *usage, | ||
85 | unsigned long **bit, int *max) | ||
86 | { | ||
87 | if (usage->type == EV_KEY || usage->type == EV_ABS) | ||
88 | clear_bit(usage->code, *bit); | ||
89 | |||
90 | return 0; | ||
91 | } | ||
92 | |||
93 | /* | ||
94 | * this function is called when a whole finger has been parsed, | ||
95 | * so that it can decide what to send to the input layer. | ||
96 | */ | ||
97 | static void cando_filter_event(struct cando_data *td, struct input_dev *input) | ||
98 | { | ||
99 | td->first = !td->first; /* touchscreen emulation */ | ||
100 | |||
101 | if (!td->valid) { | ||
102 | /* | ||
103 | * touchscreen emulation: if this is the second finger and | ||
104 | * the first was valid, the first was the oldest; if the | ||
105 | * first was not valid and there was a valid finger in the | ||
106 | * previous frame, this is a release. | ||
107 | */ | ||
108 | if (td->first) { | ||
109 | td->firstid = -1; | ||
110 | } else if (td->firstid >= 0) { | ||
111 | input_event(input, EV_ABS, ABS_X, td->firstx); | ||
112 | input_event(input, EV_ABS, ABS_Y, td->firsty); | ||
113 | td->oldest = td->firstid; | ||
114 | } else if (td->oldest >= 0) { | ||
115 | input_event(input, EV_KEY, BTN_TOUCH, 0); | ||
116 | td->oldest = -1; | ||
117 | } | ||
118 | |||
119 | return; | ||
120 | } | ||
121 | |||
122 | input_event(input, EV_ABS, ABS_MT_TRACKING_ID, td->id); | ||
123 | input_event(input, EV_ABS, ABS_MT_POSITION_X, td->x); | ||
124 | input_event(input, EV_ABS, ABS_MT_POSITION_Y, td->y); | ||
125 | |||
126 | input_mt_sync(input); | ||
127 | |||
128 | /* | ||
129 | * touchscreen emulation: if there was no touching finger previously, | ||
130 | * emit touch event | ||
131 | */ | ||
132 | if (td->oldest < 0) { | ||
133 | input_event(input, EV_KEY, BTN_TOUCH, 1); | ||
134 | td->oldest = td->id; | ||
135 | } | ||
136 | |||
137 | /* | ||
138 | * touchscreen emulation: if this is the first finger, wait for the | ||
139 | * second; the oldest is then the second if it was the oldest already | ||
140 | * or if there was no first, the first otherwise. | ||
141 | */ | ||
142 | if (td->first) { | ||
143 | td->firstx = td->x; | ||
144 | td->firsty = td->y; | ||
145 | td->firstid = td->id; | ||
146 | } else { | ||
147 | int x, y, oldest; | ||
148 | if (td->id == td->oldest || td->firstid < 0) { | ||
149 | x = td->x; | ||
150 | y = td->y; | ||
151 | oldest = td->id; | ||
152 | } else { | ||
153 | x = td->firstx; | ||
154 | y = td->firsty; | ||
155 | oldest = td->firstid; | ||
156 | } | ||
157 | input_event(input, EV_ABS, ABS_X, x); | ||
158 | input_event(input, EV_ABS, ABS_Y, y); | ||
159 | td->oldest = oldest; | ||
160 | } | ||
161 | } | ||
162 | |||
163 | |||
164 | static int cando_event(struct hid_device *hid, struct hid_field *field, | ||
165 | struct hid_usage *usage, __s32 value) | ||
166 | { | ||
167 | struct cando_data *td = hid_get_drvdata(hid); | ||
168 | |||
169 | if (hid->claimed & HID_CLAIMED_INPUT) { | ||
170 | struct input_dev *input = field->hidinput->input; | ||
171 | |||
172 | switch (usage->hid) { | ||
173 | case HID_DG_INRANGE: | ||
174 | td->valid = value; | ||
175 | break; | ||
176 | case HID_DG_CONTACTID: | ||
177 | td->id = value; | ||
178 | break; | ||
179 | case HID_GD_X: | ||
180 | td->x = value; | ||
181 | break; | ||
182 | case HID_GD_Y: | ||
183 | td->y = value; | ||
184 | cando_filter_event(td, input); | ||
185 | break; | ||
186 | case HID_DG_TIPSWITCH: | ||
187 | /* avoid interference from generic hidinput handling */ | ||
188 | break; | ||
189 | |||
190 | default: | ||
191 | /* fallback to the generic hidinput handling */ | ||
192 | return 0; | ||
193 | } | ||
194 | } | ||
195 | |||
196 | /* we have handled the hidinput part, now remains hiddev */ | ||
197 | if (hid->claimed & HID_CLAIMED_HIDDEV && hid->hiddev_hid_event) | ||
198 | hid->hiddev_hid_event(hid, field, usage, value); | ||
199 | |||
200 | return 1; | ||
201 | } | ||
202 | |||
203 | static int cando_probe(struct hid_device *hdev, const struct hid_device_id *id) | ||
204 | { | ||
205 | int ret; | ||
206 | struct cando_data *td; | ||
207 | |||
208 | td = kmalloc(sizeof(struct cando_data), GFP_KERNEL); | ||
209 | if (!td) { | ||
210 | dev_err(&hdev->dev, "cannot allocate Cando Touch data\n"); | ||
211 | return -ENOMEM; | ||
212 | } | ||
213 | hid_set_drvdata(hdev, td); | ||
214 | td->first = false; | ||
215 | td->oldest = -1; | ||
216 | td->valid = false; | ||
217 | |||
218 | ret = hid_parse(hdev); | ||
219 | if (!ret) | ||
220 | ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); | ||
221 | |||
222 | if (ret) | ||
223 | kfree(td); | ||
224 | |||
225 | return ret; | ||
226 | } | ||
227 | |||
228 | static void cando_remove(struct hid_device *hdev) | ||
229 | { | ||
230 | hid_hw_stop(hdev); | ||
231 | kfree(hid_get_drvdata(hdev)); | ||
232 | hid_set_drvdata(hdev, NULL); | ||
233 | } | ||
234 | |||
235 | static const struct hid_device_id cando_devices[] = { | ||
236 | { HID_USB_DEVICE(USB_VENDOR_ID_CANDO, | ||
237 | USB_DEVICE_ID_CANDO_MULTI_TOUCH) }, | ||
238 | { HID_USB_DEVICE(USB_VENDOR_ID_CANDO, | ||
239 | USB_DEVICE_ID_CANDO_MULTI_TOUCH_11_6) }, | ||
240 | { } | ||
241 | }; | ||
242 | MODULE_DEVICE_TABLE(hid, cando_devices); | ||
243 | |||
244 | static const struct hid_usage_id cando_grabbed_usages[] = { | ||
245 | { HID_ANY_ID, HID_ANY_ID, HID_ANY_ID }, | ||
246 | { HID_ANY_ID - 1, HID_ANY_ID - 1, HID_ANY_ID - 1} | ||
247 | }; | ||
248 | |||
249 | static struct hid_driver cando_driver = { | ||
250 | .name = "cando-touch", | ||
251 | .id_table = cando_devices, | ||
252 | .probe = cando_probe, | ||
253 | .remove = cando_remove, | ||
254 | .input_mapping = cando_input_mapping, | ||
255 | .input_mapped = cando_input_mapped, | ||
256 | .usage_table = cando_grabbed_usages, | ||
257 | .event = cando_event, | ||
258 | }; | ||
259 | |||
260 | static int __init cando_init(void) | ||
261 | { | ||
262 | return hid_register_driver(&cando_driver); | ||
263 | } | ||
264 | |||
265 | static void __exit cando_exit(void) | ||
266 | { | ||
267 | hid_unregister_driver(&cando_driver); | ||
268 | } | ||
269 | |||
270 | module_init(cando_init); | ||
271 | module_exit(cando_exit); | ||
272 | |||
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 143e788b729b..e10e314d38cc 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c | |||
@@ -653,10 +653,9 @@ int hid_parse_report(struct hid_device *device, __u8 *start, | |||
653 | if (device->driver->report_fixup) | 653 | if (device->driver->report_fixup) |
654 | device->driver->report_fixup(device, start, size); | 654 | device->driver->report_fixup(device, start, size); |
655 | 655 | ||
656 | device->rdesc = kmalloc(size, GFP_KERNEL); | 656 | device->rdesc = kmemdup(start, size, GFP_KERNEL); |
657 | if (device->rdesc == NULL) | 657 | if (device->rdesc == NULL) |
658 | return -ENOMEM; | 658 | return -ENOMEM; |
659 | memcpy(device->rdesc, start, size); | ||
660 | device->rsize = size; | 659 | device->rsize = size; |
661 | 660 | ||
662 | parser = vmalloc(sizeof(struct hid_parser)); | 661 | parser = vmalloc(sizeof(struct hid_parser)); |
@@ -940,13 +939,8 @@ static void hid_output_field(struct hid_field *field, __u8 *data) | |||
940 | unsigned count = field->report_count; | 939 | unsigned count = field->report_count; |
941 | unsigned offset = field->report_offset; | 940 | unsigned offset = field->report_offset; |
942 | unsigned size = field->report_size; | 941 | unsigned size = field->report_size; |
943 | unsigned bitsused = offset + count * size; | ||
944 | unsigned n; | 942 | unsigned n; |
945 | 943 | ||
946 | /* make sure the unused bits in the last byte are zeros */ | ||
947 | if (count > 0 && size > 0 && (bitsused % 8) != 0) | ||
948 | data[(bitsused-1)/8] &= (1 << (bitsused % 8)) - 1; | ||
949 | |||
950 | for (n = 0; n < count; n++) { | 944 | for (n = 0; n < count; n++) { |
951 | if (field->logical_minimum < 0) /* signed values */ | 945 | if (field->logical_minimum < 0) /* signed values */ |
952 | implement(data, offset + n * size, size, s32ton(field->value[n], size)); | 946 | implement(data, offset + n * size, size, s32ton(field->value[n], size)); |
@@ -966,6 +960,7 @@ void hid_output_report(struct hid_report *report, __u8 *data) | |||
966 | if (report->id > 0) | 960 | if (report->id > 0) |
967 | *data++ = report->id; | 961 | *data++ = report->id; |
968 | 962 | ||
963 | memset(data, 0, ((report->size - 1) >> 3) + 1); | ||
969 | for (n = 0; n < report->maxfield; n++) | 964 | for (n = 0; n < report->maxfield; n++) |
970 | hid_output_field(report->field[n], data); | 965 | hid_output_field(report->field[n], data); |
971 | } | 966 | } |
@@ -1086,35 +1081,28 @@ int hid_input_report(struct hid_device *hid, int type, u8 *data, int size, int i | |||
1086 | 1081 | ||
1087 | buf = kmalloc(sizeof(char) * HID_DEBUG_BUFSIZE, GFP_ATOMIC); | 1082 | buf = kmalloc(sizeof(char) * HID_DEBUG_BUFSIZE, GFP_ATOMIC); |
1088 | 1083 | ||
1089 | if (!buf) { | 1084 | if (!buf) |
1090 | report = hid_get_report(report_enum, data); | ||
1091 | goto nomem; | 1085 | goto nomem; |
1092 | } | ||
1093 | |||
1094 | snprintf(buf, HID_DEBUG_BUFSIZE - 1, | ||
1095 | "\nreport (size %u) (%snumbered)\n", size, report_enum->numbered ? "" : "un"); | ||
1096 | hid_debug_event(hid, buf); | ||
1097 | |||
1098 | report = hid_get_report(report_enum, data); | ||
1099 | if (!report) { | ||
1100 | kfree(buf); | ||
1101 | return -1; | ||
1102 | } | ||
1103 | 1086 | ||
1104 | /* dump the report */ | 1087 | /* dump the report */ |
1105 | snprintf(buf, HID_DEBUG_BUFSIZE - 1, | 1088 | snprintf(buf, HID_DEBUG_BUFSIZE - 1, |
1106 | "report %d (size %u) = ", report->id, size); | 1089 | "\nreport (size %u) (%snumbered) = ", size, report_enum->numbered ? "" : "un"); |
1107 | hid_debug_event(hid, buf); | 1090 | hid_debug_event(hid, buf); |
1091 | |||
1108 | for (i = 0; i < size; i++) { | 1092 | for (i = 0; i < size; i++) { |
1109 | snprintf(buf, HID_DEBUG_BUFSIZE - 1, | 1093 | snprintf(buf, HID_DEBUG_BUFSIZE - 1, |
1110 | " %02x", data[i]); | 1094 | " %02x", data[i]); |
1111 | hid_debug_event(hid, buf); | 1095 | hid_debug_event(hid, buf); |
1112 | } | 1096 | } |
1113 | hid_debug_event(hid, "\n"); | 1097 | hid_debug_event(hid, "\n"); |
1114 | |||
1115 | kfree(buf); | 1098 | kfree(buf); |
1116 | 1099 | ||
1117 | nomem: | 1100 | nomem: |
1101 | report = hid_get_report(report_enum, data); | ||
1102 | |||
1103 | if (!report) | ||
1104 | return -1; | ||
1105 | |||
1118 | if (hdrv && hdrv->raw_event && hid_match_report(hid, report)) { | 1106 | if (hdrv && hdrv->raw_event && hid_match_report(hid, report)) { |
1119 | ret = hdrv->raw_event(hid, report, data, size); | 1107 | ret = hdrv->raw_event(hid, report, data, size); |
1120 | if (ret != 0) | 1108 | if (ret != 0) |
@@ -1167,6 +1155,8 @@ int hid_connect(struct hid_device *hdev, unsigned int connect_mask) | |||
1167 | unsigned int i; | 1155 | unsigned int i; |
1168 | int len; | 1156 | int len; |
1169 | 1157 | ||
1158 | if (hdev->quirks & HID_QUIRK_HIDDEV_FORCE) | ||
1159 | connect_mask |= (HID_CONNECT_HIDDEV_FORCE | HID_CONNECT_HIDDEV); | ||
1170 | if (hdev->bus != BUS_USB) | 1160 | if (hdev->bus != BUS_USB) |
1171 | connect_mask &= ~HID_CONNECT_HIDDEV; | 1161 | connect_mask &= ~HID_CONNECT_HIDDEV; |
1172 | if (hid_hiddev(hdev)) | 1162 | if (hid_hiddev(hdev)) |
@@ -1246,6 +1236,7 @@ EXPORT_SYMBOL_GPL(hid_disconnect); | |||
1246 | /* a list of devices for which there is a specialized driver on HID bus */ | 1236 | /* a list of devices for which there is a specialized driver on HID bus */ |
1247 | static const struct hid_device_id hid_blacklist[] = { | 1237 | static const struct hid_device_id hid_blacklist[] = { |
1248 | { HID_USB_DEVICE(USB_VENDOR_ID_3M, USB_DEVICE_ID_3M1968) }, | 1238 | { HID_USB_DEVICE(USB_VENDOR_ID_3M, USB_DEVICE_ID_3M1968) }, |
1239 | { HID_USB_DEVICE(USB_VENDOR_ID_3M, USB_DEVICE_ID_3M2256) }, | ||
1249 | { HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_WCP32PU) }, | 1240 | { HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_WCP32PU) }, |
1250 | { HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_X5_005D) }, | 1241 | { HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_X5_005D) }, |
1251 | { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ATV_IRCONTROL) }, | 1242 | { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ATV_IRCONTROL) }, |
@@ -1290,14 +1281,19 @@ static const struct hid_device_id hid_blacklist[] = { | |||
1290 | { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY) }, | 1281 | { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY) }, |
1291 | { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY) }, | 1282 | { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY) }, |
1292 | { HID_USB_DEVICE(USB_VENDOR_ID_BELKIN, USB_DEVICE_ID_FLIP_KVM) }, | 1283 | { HID_USB_DEVICE(USB_VENDOR_ID_BELKIN, USB_DEVICE_ID_FLIP_KVM) }, |
1284 | { HID_USB_DEVICE(USB_VENDOR_ID_BTC, USB_DEVICE_ID_BTC_EMPREX_REMOTE) }, | ||
1285 | { HID_USB_DEVICE(USB_VENDOR_ID_CANDO, USB_DEVICE_ID_CANDO_MULTI_TOUCH) }, | ||
1286 | { HID_USB_DEVICE(USB_VENDOR_ID_CANDO, USB_DEVICE_ID_CANDO_MULTI_TOUCH_11_6) }, | ||
1293 | { HID_USB_DEVICE(USB_VENDOR_ID_CHERRY, USB_DEVICE_ID_CHERRY_CYMOTION) }, | 1287 | { HID_USB_DEVICE(USB_VENDOR_ID_CHERRY, USB_DEVICE_ID_CHERRY_CYMOTION) }, |
1294 | { HID_USB_DEVICE(USB_VENDOR_ID_CHERRY, USB_DEVICE_ID_CHERRY_CYMOTION_SOLAR) }, | 1288 | { HID_USB_DEVICE(USB_VENDOR_ID_CHERRY, USB_DEVICE_ID_CHERRY_CYMOTION_SOLAR) }, |
1295 | { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_TACTICAL_PAD) }, | 1289 | { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_TACTICAL_PAD) }, |
1290 | { HID_USB_DEVICE(USB_VENDOR_ID_CREATIVELABS, USB_DEVICE_ID_PRODIKEYS_PCMIDI) }, | ||
1296 | { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_1) }, | 1291 | { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_1) }, |
1297 | { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_2) }, | 1292 | { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_2) }, |
1298 | { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_3) }, | 1293 | { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_3) }, |
1299 | { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_MOUSE) }, | 1294 | { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_MOUSE) }, |
1300 | { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, 0x0006) }, | 1295 | { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, 0x0006) }, |
1296 | { HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH) }, | ||
1301 | { HID_USB_DEVICE(USB_VENDOR_ID_EZKEY, USB_DEVICE_ID_BTC_8193) }, | 1297 | { HID_USB_DEVICE(USB_VENDOR_ID_EZKEY, USB_DEVICE_ID_BTC_8193) }, |
1302 | { HID_USB_DEVICE(USB_VENDOR_ID_GAMERON, USB_DEVICE_ID_GAMERON_DUAL_PSX_ADAPTOR) }, | 1298 | { HID_USB_DEVICE(USB_VENDOR_ID_GAMERON, USB_DEVICE_ID_GAMERON_DUAL_PSX_ADAPTOR) }, |
1303 | { HID_USB_DEVICE(USB_VENDOR_ID_GAMERON, USB_DEVICE_ID_GAMERON_DUAL_PCS_ADAPTOR) }, | 1299 | { HID_USB_DEVICE(USB_VENDOR_ID_GAMERON, USB_DEVICE_ID_GAMERON_DUAL_PCS_ADAPTOR) }, |
@@ -1331,6 +1327,8 @@ static const struct hid_device_id hid_blacklist[] = { | |||
1331 | { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD2) }, | 1327 | { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD2) }, |
1332 | { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_SPACETRAVELLER) }, | 1328 | { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_SPACETRAVELLER) }, |
1333 | { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_SPACENAVIGATOR) }, | 1329 | { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_SPACENAVIGATOR) }, |
1330 | { HID_USB_DEVICE(USB_VENDOR_ID_MICROCHIP, USB_DEVICE_ID_PICOLCD) }, | ||
1331 | { HID_USB_DEVICE(USB_VENDOR_ID_MICROCHIP, USB_DEVICE_ID_PICOLCD_BOOTLOADER) }, | ||
1334 | { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_SIDEWINDER_GV) }, | 1332 | { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_SIDEWINDER_GV) }, |
1335 | { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_NE4K) }, | 1333 | { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_NE4K) }, |
1336 | { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_LK6K) }, | 1334 | { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_LK6K) }, |
@@ -1342,7 +1340,9 @@ static const struct hid_device_id hid_blacklist[] = { | |||
1342 | { HID_USB_DEVICE(USB_VENDOR_ID_PETALYNX, USB_DEVICE_ID_PETALYNX_MAXTER_REMOTE) }, | 1340 | { HID_USB_DEVICE(USB_VENDOR_ID_PETALYNX, USB_DEVICE_ID_PETALYNX_MAXTER_REMOTE) }, |
1343 | { HID_USB_DEVICE(USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH) }, | 1341 | { HID_USB_DEVICE(USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH) }, |
1344 | { HID_USB_DEVICE(USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_PIXART_IMAGING_INC_OPTICAL_TOUCH_SCREEN) }, | 1342 | { HID_USB_DEVICE(USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_PIXART_IMAGING_INC_OPTICAL_TOUCH_SCREEN) }, |
1343 | { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KONE) }, | ||
1345 | { HID_USB_DEVICE(USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_IR_REMOTE) }, | 1344 | { HID_USB_DEVICE(USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_IR_REMOTE) }, |
1345 | { HID_USB_DEVICE(USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_WIRELESS_KBD_MOUSE) }, | ||
1346 | { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER) }, | 1346 | { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER) }, |
1347 | { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER) }, | 1347 | { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER) }, |
1348 | { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_VAIO_VGX_MOUSE) }, | 1348 | { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_VAIO_VGX_MOUSE) }, |
@@ -1359,8 +1359,10 @@ static const struct hid_device_id hid_blacklist[] = { | |||
1359 | { HID_USB_DEVICE(USB_VENDOR_ID_TWINHAN, USB_DEVICE_ID_TWINHAN_IR_REMOTE) }, | 1359 | { HID_USB_DEVICE(USB_VENDOR_ID_TWINHAN, USB_DEVICE_ID_TWINHAN_IR_REMOTE) }, |
1360 | { HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_SMARTJOY_PLUS) }, | 1360 | { HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_SMARTJOY_PLUS) }, |
1361 | { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_GRAPHIRE_BLUETOOTH) }, | 1361 | { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_GRAPHIRE_BLUETOOTH) }, |
1362 | { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS4_BLUETOOTH) }, | ||
1362 | { HID_USB_DEVICE(USB_VENDOR_ID_ZEROPLUS, 0x0005) }, | 1363 | { HID_USB_DEVICE(USB_VENDOR_ID_ZEROPLUS, 0x0005) }, |
1363 | { HID_USB_DEVICE(USB_VENDOR_ID_ZEROPLUS, 0x0030) }, | 1364 | { HID_USB_DEVICE(USB_VENDOR_ID_ZEROPLUS, 0x0030) }, |
1365 | { HID_USB_DEVICE(USB_VENDOR_ID_ZYDACRON, USB_DEVICE_ID_ZYDACRON_REMOTE_CONTROL) }, | ||
1364 | 1366 | ||
1365 | { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_PRESENTER_8K_BT) }, | 1367 | { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_PRESENTER_8K_BT) }, |
1366 | { } | 1368 | { } |
@@ -1757,7 +1759,7 @@ int hid_add_device(struct hid_device *hdev) | |||
1757 | 1759 | ||
1758 | /* we need to kill them here, otherwise they will stay allocated to | 1760 | /* we need to kill them here, otherwise they will stay allocated to |
1759 | * wait for coming driver */ | 1761 | * wait for coming driver */ |
1760 | if (hid_ignore(hdev)) | 1762 | if (!(hdev->quirks & HID_QUIRK_NO_IGNORE) && hid_ignore(hdev)) |
1761 | return -ENODEV; | 1763 | return -ENODEV; |
1762 | 1764 | ||
1763 | /* XXX hack, any other cleaner solution after the driver core | 1765 | /* XXX hack, any other cleaner solution after the driver core |
@@ -1765,11 +1767,12 @@ int hid_add_device(struct hid_device *hdev) | |||
1765 | dev_set_name(&hdev->dev, "%04X:%04X:%04X.%04X", hdev->bus, | 1767 | dev_set_name(&hdev->dev, "%04X:%04X:%04X.%04X", hdev->bus, |
1766 | hdev->vendor, hdev->product, atomic_inc_return(&id)); | 1768 | hdev->vendor, hdev->product, atomic_inc_return(&id)); |
1767 | 1769 | ||
1770 | hid_debug_register(hdev, dev_name(&hdev->dev)); | ||
1768 | ret = device_add(&hdev->dev); | 1771 | ret = device_add(&hdev->dev); |
1769 | if (!ret) | 1772 | if (!ret) |
1770 | hdev->status |= HID_STAT_ADDED; | 1773 | hdev->status |= HID_STAT_ADDED; |
1771 | 1774 | else | |
1772 | hid_debug_register(hdev, dev_name(&hdev->dev)); | 1775 | hid_debug_unregister(hdev); |
1773 | 1776 | ||
1774 | return ret; | 1777 | return ret; |
1775 | } | 1778 | } |
diff --git a/drivers/hid/hid-egalax.c b/drivers/hid/hid-egalax.c new file mode 100644 index 000000000000..f44bdc084cb2 --- /dev/null +++ b/drivers/hid/hid-egalax.c | |||
@@ -0,0 +1,281 @@ | |||
1 | /* | ||
2 | * HID driver for eGalax dual-touch panels | ||
3 | * | ||
4 | * Copyright (c) 2010 Stephane Chatty <chatty@enac.fr> | ||
5 | * | ||
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 | #include <linux/usb.h> | ||
19 | #include <linux/slab.h> | ||
20 | #include "usbhid/usbhid.h" | ||
21 | |||
22 | MODULE_AUTHOR("Stephane Chatty <chatty@enac.fr>"); | ||
23 | MODULE_DESCRIPTION("eGalax dual-touch panel"); | ||
24 | MODULE_LICENSE("GPL"); | ||
25 | |||
26 | #include "hid-ids.h" | ||
27 | |||
28 | struct egalax_data { | ||
29 | __u16 x, y, z; | ||
30 | __u8 id; | ||
31 | bool first; /* is this the first finger in the frame? */ | ||
32 | bool valid; /* valid finger data, or just placeholder? */ | ||
33 | bool activity; /* at least one active finger previously? */ | ||
34 | __u16 lastx, lasty; /* latest valid (x, y) in the frame */ | ||
35 | }; | ||
36 | |||
37 | static int egalax_input_mapping(struct hid_device *hdev, struct hid_input *hi, | ||
38 | struct hid_field *field, struct hid_usage *usage, | ||
39 | unsigned long **bit, int *max) | ||
40 | { | ||
41 | switch (usage->hid & HID_USAGE_PAGE) { | ||
42 | |||
43 | case HID_UP_GENDESK: | ||
44 | switch (usage->hid) { | ||
45 | case HID_GD_X: | ||
46 | hid_map_usage(hi, usage, bit, max, | ||
47 | EV_ABS, ABS_MT_POSITION_X); | ||
48 | /* touchscreen emulation */ | ||
49 | input_set_abs_params(hi->input, ABS_X, | ||
50 | field->logical_minimum, | ||
51 | field->logical_maximum, 0, 0); | ||
52 | return 1; | ||
53 | case HID_GD_Y: | ||
54 | hid_map_usage(hi, usage, bit, max, | ||
55 | EV_ABS, ABS_MT_POSITION_Y); | ||
56 | /* touchscreen emulation */ | ||
57 | input_set_abs_params(hi->input, ABS_Y, | ||
58 | field->logical_minimum, | ||
59 | field->logical_maximum, 0, 0); | ||
60 | return 1; | ||
61 | } | ||
62 | return 0; | ||
63 | |||
64 | case HID_UP_DIGITIZER: | ||
65 | switch (usage->hid) { | ||
66 | case HID_DG_TIPSWITCH: | ||
67 | /* touchscreen emulation */ | ||
68 | hid_map_usage(hi, usage, bit, max, EV_KEY, BTN_TOUCH); | ||
69 | return 1; | ||
70 | case HID_DG_INRANGE: | ||
71 | case HID_DG_CONFIDENCE: | ||
72 | case HID_DG_CONTACTCOUNT: | ||
73 | case HID_DG_CONTACTMAX: | ||
74 | return -1; | ||
75 | case HID_DG_CONTACTID: | ||
76 | hid_map_usage(hi, usage, bit, max, | ||
77 | EV_ABS, ABS_MT_TRACKING_ID); | ||
78 | return 1; | ||
79 | case HID_DG_TIPPRESSURE: | ||
80 | hid_map_usage(hi, usage, bit, max, | ||
81 | EV_ABS, ABS_MT_PRESSURE); | ||
82 | return 1; | ||
83 | } | ||
84 | return 0; | ||
85 | } | ||
86 | |||
87 | /* ignore others (from other reports we won't get anyway) */ | ||
88 | return -1; | ||
89 | } | ||
90 | |||
91 | static int egalax_input_mapped(struct hid_device *hdev, struct hid_input *hi, | ||
92 | struct hid_field *field, struct hid_usage *usage, | ||
93 | unsigned long **bit, int *max) | ||
94 | { | ||
95 | if (usage->type == EV_KEY || usage->type == EV_ABS) | ||
96 | clear_bit(usage->code, *bit); | ||
97 | |||
98 | return 0; | ||
99 | } | ||
100 | |||
101 | /* | ||
102 | * this function is called when a whole finger has been parsed, | ||
103 | * so that it can decide what to send to the input layer. | ||
104 | */ | ||
105 | static void egalax_filter_event(struct egalax_data *td, struct input_dev *input) | ||
106 | { | ||
107 | td->first = !td->first; /* touchscreen emulation */ | ||
108 | |||
109 | if (td->valid) { | ||
110 | /* emit multitouch events */ | ||
111 | input_event(input, EV_ABS, ABS_MT_TRACKING_ID, td->id); | ||
112 | input_event(input, EV_ABS, ABS_MT_POSITION_X, td->x); | ||
113 | input_event(input, EV_ABS, ABS_MT_POSITION_Y, td->y); | ||
114 | input_event(input, EV_ABS, ABS_MT_PRESSURE, td->z); | ||
115 | |||
116 | input_mt_sync(input); | ||
117 | |||
118 | /* | ||
119 | * touchscreen emulation: store (x, y) as | ||
120 | * the last valid values in this frame | ||
121 | */ | ||
122 | td->lastx = td->x; | ||
123 | td->lasty = td->y; | ||
124 | } | ||
125 | |||
126 | /* | ||
127 | * touchscreen emulation: if this is the second finger and at least | ||
128 | * one in this frame is valid, the latest valid in the frame is | ||
129 | * the oldest on the panel, the one we want for single touch | ||
130 | */ | ||
131 | if (!td->first && td->activity) { | ||
132 | input_event(input, EV_ABS, ABS_X, td->lastx); | ||
133 | input_event(input, EV_ABS, ABS_Y, td->lasty); | ||
134 | } | ||
135 | |||
136 | if (!td->valid) { | ||
137 | /* | ||
138 | * touchscreen emulation: if the first finger is invalid | ||
139 | * and there previously was finger activity, this is a release | ||
140 | */ | ||
141 | if (td->first && td->activity) { | ||
142 | input_event(input, EV_KEY, BTN_TOUCH, 0); | ||
143 | td->activity = false; | ||
144 | } | ||
145 | return; | ||
146 | } | ||
147 | |||
148 | |||
149 | /* touchscreen emulation: if no previous activity, emit touch event */ | ||
150 | if (!td->activity) { | ||
151 | input_event(input, EV_KEY, BTN_TOUCH, 1); | ||
152 | td->activity = true; | ||
153 | } | ||
154 | } | ||
155 | |||
156 | |||
157 | static int egalax_event(struct hid_device *hid, struct hid_field *field, | ||
158 | struct hid_usage *usage, __s32 value) | ||
159 | { | ||
160 | struct egalax_data *td = hid_get_drvdata(hid); | ||
161 | |||
162 | if (hid->claimed & HID_CLAIMED_INPUT) { | ||
163 | struct input_dev *input = field->hidinput->input; | ||
164 | |||
165 | switch (usage->hid) { | ||
166 | case HID_DG_INRANGE: | ||
167 | case HID_DG_CONFIDENCE: | ||
168 | /* avoid interference from generic hidinput handling */ | ||
169 | break; | ||
170 | case HID_DG_TIPSWITCH: | ||
171 | td->valid = value; | ||
172 | break; | ||
173 | case HID_DG_TIPPRESSURE: | ||
174 | td->z = value; | ||
175 | break; | ||
176 | case HID_DG_CONTACTID: | ||
177 | td->id = value; | ||
178 | break; | ||
179 | case HID_GD_X: | ||
180 | td->x = value; | ||
181 | break; | ||
182 | case HID_GD_Y: | ||
183 | td->y = value; | ||
184 | /* this is the last field in a finger */ | ||
185 | egalax_filter_event(td, input); | ||
186 | break; | ||
187 | case HID_DG_CONTACTCOUNT: | ||
188 | /* touch emulation: this is the last field in a frame */ | ||
189 | td->first = false; | ||
190 | break; | ||
191 | |||
192 | default: | ||
193 | /* fallback to the generic hidinput handling */ | ||
194 | return 0; | ||
195 | } | ||
196 | } | ||
197 | |||
198 | /* we have handled the hidinput part, now remains hiddev */ | ||
199 | if (hid->claimed & HID_CLAIMED_HIDDEV && hid->hiddev_hid_event) | ||
200 | hid->hiddev_hid_event(hid, field, usage, value); | ||
201 | |||
202 | return 1; | ||
203 | } | ||
204 | |||
205 | static int egalax_probe(struct hid_device *hdev, const struct hid_device_id *id) | ||
206 | { | ||
207 | int ret; | ||
208 | struct egalax_data *td; | ||
209 | struct hid_report *report; | ||
210 | |||
211 | td = kmalloc(sizeof(struct egalax_data), GFP_KERNEL); | ||
212 | if (!td) { | ||
213 | dev_err(&hdev->dev, "cannot allocate eGalax data\n"); | ||
214 | return -ENOMEM; | ||
215 | } | ||
216 | hid_set_drvdata(hdev, td); | ||
217 | |||
218 | ret = hid_parse(hdev); | ||
219 | if (ret) | ||
220 | goto end; | ||
221 | |||
222 | ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); | ||
223 | if (ret) | ||
224 | goto end; | ||
225 | |||
226 | report = hdev->report_enum[HID_FEATURE_REPORT].report_id_hash[5]; | ||
227 | if (report) { | ||
228 | report->field[0]->value[0] = 2; | ||
229 | usbhid_submit_report(hdev, report, USB_DIR_OUT); | ||
230 | } | ||
231 | |||
232 | end: | ||
233 | if (ret) | ||
234 | kfree(td); | ||
235 | |||
236 | return ret; | ||
237 | } | ||
238 | |||
239 | static void egalax_remove(struct hid_device *hdev) | ||
240 | { | ||
241 | hid_hw_stop(hdev); | ||
242 | kfree(hid_get_drvdata(hdev)); | ||
243 | hid_set_drvdata(hdev, NULL); | ||
244 | } | ||
245 | |||
246 | static const struct hid_device_id egalax_devices[] = { | ||
247 | { HID_USB_DEVICE(USB_VENDOR_ID_DWAV, | ||
248 | USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH) }, | ||
249 | { } | ||
250 | }; | ||
251 | MODULE_DEVICE_TABLE(hid, egalax_devices); | ||
252 | |||
253 | static const struct hid_usage_id egalax_grabbed_usages[] = { | ||
254 | { HID_ANY_ID, HID_ANY_ID, HID_ANY_ID }, | ||
255 | { HID_ANY_ID - 1, HID_ANY_ID - 1, HID_ANY_ID - 1} | ||
256 | }; | ||
257 | |||
258 | static struct hid_driver egalax_driver = { | ||
259 | .name = "egalax-touch", | ||
260 | .id_table = egalax_devices, | ||
261 | .probe = egalax_probe, | ||
262 | .remove = egalax_remove, | ||
263 | .input_mapping = egalax_input_mapping, | ||
264 | .input_mapped = egalax_input_mapped, | ||
265 | .usage_table = egalax_grabbed_usages, | ||
266 | .event = egalax_event, | ||
267 | }; | ||
268 | |||
269 | static int __init egalax_init(void) | ||
270 | { | ||
271 | return hid_register_driver(&egalax_driver); | ||
272 | } | ||
273 | |||
274 | static void __exit egalax_exit(void) | ||
275 | { | ||
276 | hid_unregister_driver(&egalax_driver); | ||
277 | } | ||
278 | |||
279 | module_init(egalax_init); | ||
280 | module_exit(egalax_exit); | ||
281 | |||
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 09d27649a0f7..9776896cc4fc 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h | |||
@@ -20,6 +20,7 @@ | |||
20 | 20 | ||
21 | #define USB_VENDOR_ID_3M 0x0596 | 21 | #define USB_VENDOR_ID_3M 0x0596 |
22 | #define USB_DEVICE_ID_3M1968 0x0500 | 22 | #define USB_DEVICE_ID_3M1968 0x0500 |
23 | #define USB_DEVICE_ID_3M2256 0x0502 | ||
23 | 24 | ||
24 | #define USB_VENDOR_ID_A4TECH 0x09da | 25 | #define USB_VENDOR_ID_A4TECH 0x09da |
25 | #define USB_DEVICE_ID_A4TECH_WCP32PU 0x0006 | 26 | #define USB_DEVICE_ID_A4TECH_WCP32PU 0x0006 |
@@ -123,6 +124,13 @@ | |||
123 | #define USB_VENDOR_ID_BERKSHIRE 0x0c98 | 124 | #define USB_VENDOR_ID_BERKSHIRE 0x0c98 |
124 | #define USB_DEVICE_ID_BERKSHIRE_PCWD 0x1140 | 125 | #define USB_DEVICE_ID_BERKSHIRE_PCWD 0x1140 |
125 | 126 | ||
127 | #define USB_VENDOR_ID_BTC 0x046e | ||
128 | #define USB_DEVICE_ID_BTC_EMPREX_REMOTE 0x5578 | ||
129 | |||
130 | #define USB_VENDOR_ID_CANDO 0x2087 | ||
131 | #define USB_DEVICE_ID_CANDO_MULTI_TOUCH 0x0a01 | ||
132 | #define USB_DEVICE_ID_CANDO_MULTI_TOUCH_11_6 0x0b03 | ||
133 | |||
126 | #define USB_VENDOR_ID_CH 0x068e | 134 | #define USB_VENDOR_ID_CH 0x068e |
127 | #define USB_DEVICE_ID_CH_PRO_PEDALS 0x00f2 | 135 | #define USB_DEVICE_ID_CH_PRO_PEDALS 0x00f2 |
128 | #define USB_DEVICE_ID_CH_COMBATSTICK 0x00f4 | 136 | #define USB_DEVICE_ID_CH_COMBATSTICK 0x00f4 |
@@ -148,6 +156,9 @@ | |||
148 | #define USB_DEVICE_ID_CODEMERCS_IOW_FIRST 0x1500 | 156 | #define USB_DEVICE_ID_CODEMERCS_IOW_FIRST 0x1500 |
149 | #define USB_DEVICE_ID_CODEMERCS_IOW_LAST 0x15ff | 157 | #define USB_DEVICE_ID_CODEMERCS_IOW_LAST 0x15ff |
150 | 158 | ||
159 | #define USB_VENDOR_ID_CREATIVELABS 0x041e | ||
160 | #define USB_DEVICE_ID_PRODIKEYS_PCMIDI 0x2801 | ||
161 | |||
151 | #define USB_VENDOR_ID_CYGNAL 0x10c4 | 162 | #define USB_VENDOR_ID_CYGNAL 0x10c4 |
152 | #define USB_DEVICE_ID_CYGNAL_RADIO_SI470X 0x818a | 163 | #define USB_DEVICE_ID_CYGNAL_RADIO_SI470X 0x818a |
153 | 164 | ||
@@ -171,6 +182,10 @@ | |||
171 | 182 | ||
172 | #define USB_VENDOR_ID_DRAGONRISE 0x0079 | 183 | #define USB_VENDOR_ID_DRAGONRISE 0x0079 |
173 | 184 | ||
185 | #define USB_VENDOR_ID_DWAV 0x0eef | ||
186 | #define USB_DEVICE_ID_EGALAX_TOUCHCONTROLLER 0x0001 | ||
187 | #define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH 0x480d | ||
188 | |||
174 | #define USB_VENDOR_ID_ELO 0x04E7 | 189 | #define USB_VENDOR_ID_ELO 0x04E7 |
175 | #define USB_DEVICE_ID_ELO_TS2700 0x0020 | 190 | #define USB_DEVICE_ID_ELO_TS2700 0x0020 |
176 | 191 | ||
@@ -342,6 +357,8 @@ | |||
342 | #define USB_VENDOR_ID_MICROCHIP 0x04d8 | 357 | #define USB_VENDOR_ID_MICROCHIP 0x04d8 |
343 | #define USB_DEVICE_ID_PICKIT1 0x0032 | 358 | #define USB_DEVICE_ID_PICKIT1 0x0032 |
344 | #define USB_DEVICE_ID_PICKIT2 0x0033 | 359 | #define USB_DEVICE_ID_PICKIT2 0x0033 |
360 | #define USB_DEVICE_ID_PICOLCD 0xc002 | ||
361 | #define USB_DEVICE_ID_PICOLCD_BOOTLOADER 0xf002 | ||
345 | 362 | ||
346 | #define USB_VENDOR_ID_MICROSOFT 0x045e | 363 | #define USB_VENDOR_ID_MICROSOFT 0x045e |
347 | #define USB_DEVICE_ID_SIDEWINDER_GV 0x003b | 364 | #define USB_DEVICE_ID_SIDEWINDER_GV 0x003b |
@@ -400,6 +417,9 @@ | |||
400 | #define USB_VENDOR_ID_PRODIGE 0x05af | 417 | #define USB_VENDOR_ID_PRODIGE 0x05af |
401 | #define USB_DEVICE_ID_PRODIGE_CORDLESS 0x3062 | 418 | #define USB_DEVICE_ID_PRODIGE_CORDLESS 0x3062 |
402 | 419 | ||
420 | #define USB_VENDOR_ID_ROCCAT 0x1e7d | ||
421 | #define USB_DEVICE_ID_ROCCAT_KONE 0x2ced | ||
422 | |||
403 | #define USB_VENDOR_ID_SAITEK 0x06a3 | 423 | #define USB_VENDOR_ID_SAITEK 0x06a3 |
404 | #define USB_DEVICE_ID_SAITEK_RUMBLEPAD 0xff17 | 424 | #define USB_DEVICE_ID_SAITEK_RUMBLEPAD 0xff17 |
405 | 425 | ||
@@ -409,6 +429,7 @@ | |||
409 | 429 | ||
410 | #define USB_VENDOR_ID_SAMSUNG 0x0419 | 430 | #define USB_VENDOR_ID_SAMSUNG 0x0419 |
411 | #define USB_DEVICE_ID_SAMSUNG_IR_REMOTE 0x0001 | 431 | #define USB_DEVICE_ID_SAMSUNG_IR_REMOTE 0x0001 |
432 | #define USB_DEVICE_ID_SAMSUNG_WIRELESS_KBD_MOUSE 0x0600 | ||
412 | 433 | ||
413 | #define USB_VENDOR_ID_SONY 0x054c | 434 | #define USB_VENDOR_ID_SONY 0x054c |
414 | #define USB_DEVICE_ID_SONY_VAIO_VGX_MOUSE 0x024b | 435 | #define USB_DEVICE_ID_SONY_VAIO_VGX_MOUSE 0x024b |
@@ -457,6 +478,7 @@ | |||
457 | 478 | ||
458 | #define USB_VENDOR_ID_WACOM 0x056a | 479 | #define USB_VENDOR_ID_WACOM 0x056a |
459 | #define USB_DEVICE_ID_WACOM_GRAPHIRE_BLUETOOTH 0x81 | 480 | #define USB_DEVICE_ID_WACOM_GRAPHIRE_BLUETOOTH 0x81 |
481 | #define USB_DEVICE_ID_WACOM_INTUOS4_BLUETOOTH 0xbd | ||
460 | 482 | ||
461 | #define USB_VENDOR_ID_WISEGROUP 0x0925 | 483 | #define USB_VENDOR_ID_WISEGROUP 0x0925 |
462 | #define USB_DEVICE_ID_SMARTJOY_PLUS 0x0005 | 484 | #define USB_DEVICE_ID_SMARTJOY_PLUS 0x0005 |
@@ -475,6 +497,9 @@ | |||
475 | 497 | ||
476 | #define USB_VENDOR_ID_ZEROPLUS 0x0c12 | 498 | #define USB_VENDOR_ID_ZEROPLUS 0x0c12 |
477 | 499 | ||
500 | #define USB_VENDOR_ID_ZYDACRON 0x13EC | ||
501 | #define USB_DEVICE_ID_ZYDACRON_REMOTE_CONTROL 0x0006 | ||
502 | |||
478 | #define USB_VENDOR_ID_KYE 0x0458 | 503 | #define USB_VENDOR_ID_KYE 0x0458 |
479 | #define USB_DEVICE_ID_KYE_ERGO_525V 0x0087 | 504 | #define USB_DEVICE_ID_KYE_ERGO_525V 0x0087 |
480 | #define USB_DEVICE_ID_KYE_GPEN_560 0x5003 | 505 | #define USB_DEVICE_ID_KYE_GPEN_560 0x5003 |
diff --git a/drivers/hid/hid-lg.c b/drivers/hid/hid-lg.c index 3677c9037a11..f6433d8050a9 100644 --- a/drivers/hid/hid-lg.c +++ b/drivers/hid/hid-lg.c | |||
@@ -126,6 +126,9 @@ static int lg_wireless_mapping(struct hid_input *hi, struct hid_usage *usage, | |||
126 | case 0x1004: lg_map_key_clear(KEY_VIDEO); break; | 126 | case 0x1004: lg_map_key_clear(KEY_VIDEO); break; |
127 | case 0x1005: lg_map_key_clear(KEY_AUDIO); break; | 127 | case 0x1005: lg_map_key_clear(KEY_AUDIO); break; |
128 | case 0x100a: lg_map_key_clear(KEY_DOCUMENTS); break; | 128 | case 0x100a: lg_map_key_clear(KEY_DOCUMENTS); break; |
129 | /* The following two entries are Playlist 1 and 2 on the MX3200 */ | ||
130 | case 0x100f: lg_map_key_clear(KEY_FN_1); break; | ||
131 | case 0x1010: lg_map_key_clear(KEY_FN_2); break; | ||
129 | case 0x1011: lg_map_key_clear(KEY_PREVIOUSSONG); break; | 132 | case 0x1011: lg_map_key_clear(KEY_PREVIOUSSONG); break; |
130 | case 0x1012: lg_map_key_clear(KEY_NEXTSONG); break; | 133 | case 0x1012: lg_map_key_clear(KEY_NEXTSONG); break; |
131 | case 0x1013: lg_map_key_clear(KEY_CAMERA); break; | 134 | case 0x1013: lg_map_key_clear(KEY_CAMERA); break; |
@@ -137,6 +140,7 @@ static int lg_wireless_mapping(struct hid_input *hi, struct hid_usage *usage, | |||
137 | case 0x1019: lg_map_key_clear(KEY_PROG1); break; | 140 | case 0x1019: lg_map_key_clear(KEY_PROG1); break; |
138 | case 0x101a: lg_map_key_clear(KEY_PROG2); break; | 141 | case 0x101a: lg_map_key_clear(KEY_PROG2); break; |
139 | case 0x101b: lg_map_key_clear(KEY_PROG3); break; | 142 | case 0x101b: lg_map_key_clear(KEY_PROG3); break; |
143 | case 0x101c: lg_map_key_clear(KEY_CYCLEWINDOWS); break; | ||
140 | case 0x101f: lg_map_key_clear(KEY_ZOOMIN); break; | 144 | case 0x101f: lg_map_key_clear(KEY_ZOOMIN); break; |
141 | case 0x1020: lg_map_key_clear(KEY_ZOOMOUT); break; | 145 | case 0x1020: lg_map_key_clear(KEY_ZOOMOUT); break; |
142 | case 0x1021: lg_map_key_clear(KEY_ZOOMRESET); break; | 146 | case 0x1021: lg_map_key_clear(KEY_ZOOMRESET); break; |
@@ -147,6 +151,11 @@ static int lg_wireless_mapping(struct hid_input *hi, struct hid_usage *usage, | |||
147 | case 0x1029: lg_map_key_clear(KEY_SHUFFLE); break; | 151 | case 0x1029: lg_map_key_clear(KEY_SHUFFLE); break; |
148 | case 0x102a: lg_map_key_clear(KEY_BACK); break; | 152 | case 0x102a: lg_map_key_clear(KEY_BACK); break; |
149 | case 0x102b: lg_map_key_clear(KEY_CYCLEWINDOWS); break; | 153 | case 0x102b: lg_map_key_clear(KEY_CYCLEWINDOWS); break; |
154 | case 0x102d: lg_map_key_clear(KEY_WWW); break; | ||
155 | /* The following two are 'Start/answer call' and 'End/reject call' | ||
156 | on the MX3200 */ | ||
157 | case 0x1031: lg_map_key_clear(KEY_OK); break; | ||
158 | case 0x1032: lg_map_key_clear(KEY_CANCEL); break; | ||
150 | case 0x1041: lg_map_key_clear(KEY_BATTERY); break; | 159 | case 0x1041: lg_map_key_clear(KEY_BATTERY); break; |
151 | case 0x1042: lg_map_key_clear(KEY_WORDPROCESSOR); break; | 160 | case 0x1042: lg_map_key_clear(KEY_WORDPROCESSOR); break; |
152 | case 0x1043: lg_map_key_clear(KEY_SPREADSHEET); break; | 161 | case 0x1043: lg_map_key_clear(KEY_SPREADSHEET); break; |
diff --git a/drivers/hid/hid-magicmouse.c b/drivers/hid/hid-magicmouse.c index 0d471fc2ab82..f10d56a15f21 100644 --- a/drivers/hid/hid-magicmouse.c +++ b/drivers/hid/hid-magicmouse.c | |||
@@ -354,12 +354,15 @@ static int magicmouse_probe(struct hid_device *hdev, | |||
354 | goto err_free; | 354 | goto err_free; |
355 | } | 355 | } |
356 | 356 | ||
357 | ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT & ~HID_CONNECT_HIDINPUT); | 357 | ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); |
358 | if (ret) { | 358 | if (ret) { |
359 | dev_err(&hdev->dev, "magicmouse hw start failed\n"); | 359 | dev_err(&hdev->dev, "magicmouse hw start failed\n"); |
360 | goto err_free; | 360 | goto err_free; |
361 | } | 361 | } |
362 | 362 | ||
363 | /* we are handling the input ourselves */ | ||
364 | hidinput_disconnect(hdev); | ||
365 | |||
363 | report = hid_register_report(hdev, HID_INPUT_REPORT, TOUCH_REPORT_ID); | 366 | report = hid_register_report(hdev, HID_INPUT_REPORT, TOUCH_REPORT_ID); |
364 | if (!report) { | 367 | if (!report) { |
365 | dev_err(&hdev->dev, "unable to register touch report\n"); | 368 | dev_err(&hdev->dev, "unable to register touch report\n"); |
diff --git a/drivers/hid/hid-ntrig.c b/drivers/hid/hid-ntrig.c index 4777bbfa1cc2..b6b0caeeac58 100644 --- a/drivers/hid/hid-ntrig.c +++ b/drivers/hid/hid-ntrig.c | |||
@@ -24,6 +24,34 @@ | |||
24 | 24 | ||
25 | #define NTRIG_DUPLICATE_USAGES 0x001 | 25 | #define NTRIG_DUPLICATE_USAGES 0x001 |
26 | 26 | ||
27 | static unsigned int min_width; | ||
28 | module_param(min_width, uint, 0644); | ||
29 | MODULE_PARM_DESC(min_width, "Minimum touch contact width to accept."); | ||
30 | |||
31 | static unsigned int min_height; | ||
32 | module_param(min_height, uint, 0644); | ||
33 | MODULE_PARM_DESC(min_height, "Minimum touch contact height to accept."); | ||
34 | |||
35 | static unsigned int activate_slack = 1; | ||
36 | module_param(activate_slack, uint, 0644); | ||
37 | MODULE_PARM_DESC(activate_slack, "Number of touch frames to ignore at " | ||
38 | "the start of touch input."); | ||
39 | |||
40 | static unsigned int deactivate_slack = 4; | ||
41 | module_param(deactivate_slack, uint, 0644); | ||
42 | MODULE_PARM_DESC(deactivate_slack, "Number of empty frames to ignore before " | ||
43 | "deactivating touch."); | ||
44 | |||
45 | static unsigned int activation_width = 64; | ||
46 | module_param(activation_width, uint, 0644); | ||
47 | MODULE_PARM_DESC(activation_width, "Width threshold to immediately start " | ||
48 | "processing touch events."); | ||
49 | |||
50 | static unsigned int activation_height = 32; | ||
51 | module_param(activation_height, uint, 0644); | ||
52 | MODULE_PARM_DESC(activation_height, "Height threshold to immediately start " | ||
53 | "processing touch events."); | ||
54 | |||
27 | struct ntrig_data { | 55 | struct ntrig_data { |
28 | /* Incoming raw values for a single contact */ | 56 | /* Incoming raw values for a single contact */ |
29 | __u16 x, y, w, h; | 57 | __u16 x, y, w, h; |
@@ -37,6 +65,309 @@ struct ntrig_data { | |||
37 | 65 | ||
38 | __u8 mt_footer[4]; | 66 | __u8 mt_footer[4]; |
39 | __u8 mt_foot_count; | 67 | __u8 mt_foot_count; |
68 | |||
69 | /* The current activation state. */ | ||
70 | __s8 act_state; | ||
71 | |||
72 | /* Empty frames to ignore before recognizing the end of activity */ | ||
73 | __s8 deactivate_slack; | ||
74 | |||
75 | /* Frames to ignore before acknowledging the start of activity */ | ||
76 | __s8 activate_slack; | ||
77 | |||
78 | /* Minimum size contact to accept */ | ||
79 | __u16 min_width; | ||
80 | __u16 min_height; | ||
81 | |||
82 | /* Threshold to override activation slack */ | ||
83 | __u16 activation_width; | ||
84 | __u16 activation_height; | ||
85 | |||
86 | __u16 sensor_logical_width; | ||
87 | __u16 sensor_logical_height; | ||
88 | __u16 sensor_physical_width; | ||
89 | __u16 sensor_physical_height; | ||
90 | }; | ||
91 | |||
92 | |||
93 | static ssize_t show_phys_width(struct device *dev, | ||
94 | struct device_attribute *attr, | ||
95 | char *buf) | ||
96 | { | ||
97 | struct hid_device *hdev = container_of(dev, struct hid_device, dev); | ||
98 | struct ntrig_data *nd = hid_get_drvdata(hdev); | ||
99 | |||
100 | return sprintf(buf, "%d\n", nd->sensor_physical_width); | ||
101 | } | ||
102 | |||
103 | static DEVICE_ATTR(sensor_physical_width, S_IRUGO, show_phys_width, NULL); | ||
104 | |||
105 | static ssize_t show_phys_height(struct device *dev, | ||
106 | struct device_attribute *attr, | ||
107 | char *buf) | ||
108 | { | ||
109 | struct hid_device *hdev = container_of(dev, struct hid_device, dev); | ||
110 | struct ntrig_data *nd = hid_get_drvdata(hdev); | ||
111 | |||
112 | return sprintf(buf, "%d\n", nd->sensor_physical_height); | ||
113 | } | ||
114 | |||
115 | static DEVICE_ATTR(sensor_physical_height, S_IRUGO, show_phys_height, NULL); | ||
116 | |||
117 | static ssize_t show_log_width(struct device *dev, | ||
118 | struct device_attribute *attr, | ||
119 | char *buf) | ||
120 | { | ||
121 | struct hid_device *hdev = container_of(dev, struct hid_device, dev); | ||
122 | struct ntrig_data *nd = hid_get_drvdata(hdev); | ||
123 | |||
124 | return sprintf(buf, "%d\n", nd->sensor_logical_width); | ||
125 | } | ||
126 | |||
127 | static DEVICE_ATTR(sensor_logical_width, S_IRUGO, show_log_width, NULL); | ||
128 | |||
129 | static ssize_t show_log_height(struct device *dev, | ||
130 | struct device_attribute *attr, | ||
131 | char *buf) | ||
132 | { | ||
133 | struct hid_device *hdev = container_of(dev, struct hid_device, dev); | ||
134 | struct ntrig_data *nd = hid_get_drvdata(hdev); | ||
135 | |||
136 | return sprintf(buf, "%d\n", nd->sensor_logical_height); | ||
137 | } | ||
138 | |||
139 | static DEVICE_ATTR(sensor_logical_height, S_IRUGO, show_log_height, NULL); | ||
140 | |||
141 | static ssize_t show_min_width(struct device *dev, | ||
142 | struct device_attribute *attr, | ||
143 | char *buf) | ||
144 | { | ||
145 | struct hid_device *hdev = container_of(dev, struct hid_device, dev); | ||
146 | struct ntrig_data *nd = hid_get_drvdata(hdev); | ||
147 | |||
148 | return sprintf(buf, "%d\n", nd->min_width * | ||
149 | nd->sensor_physical_width / | ||
150 | nd->sensor_logical_width); | ||
151 | } | ||
152 | |||
153 | static ssize_t set_min_width(struct device *dev, | ||
154 | struct device_attribute *attr, | ||
155 | const char *buf, size_t count) | ||
156 | { | ||
157 | struct hid_device *hdev = container_of(dev, struct hid_device, dev); | ||
158 | struct ntrig_data *nd = hid_get_drvdata(hdev); | ||
159 | |||
160 | unsigned long val; | ||
161 | |||
162 | if (strict_strtoul(buf, 0, &val)) | ||
163 | return -EINVAL; | ||
164 | |||
165 | if (val > nd->sensor_physical_width) | ||
166 | return -EINVAL; | ||
167 | |||
168 | nd->min_width = val * nd->sensor_logical_width / | ||
169 | nd->sensor_physical_width; | ||
170 | |||
171 | return count; | ||
172 | } | ||
173 | |||
174 | static DEVICE_ATTR(min_width, S_IWUSR | S_IRUGO, show_min_width, set_min_width); | ||
175 | |||
176 | static ssize_t show_min_height(struct device *dev, | ||
177 | struct device_attribute *attr, | ||
178 | char *buf) | ||
179 | { | ||
180 | struct hid_device *hdev = container_of(dev, struct hid_device, dev); | ||
181 | struct ntrig_data *nd = hid_get_drvdata(hdev); | ||
182 | |||
183 | return sprintf(buf, "%d\n", nd->min_height * | ||
184 | nd->sensor_physical_height / | ||
185 | nd->sensor_logical_height); | ||
186 | } | ||
187 | |||
188 | static ssize_t set_min_height(struct device *dev, | ||
189 | struct device_attribute *attr, | ||
190 | const char *buf, size_t count) | ||
191 | { | ||
192 | struct hid_device *hdev = container_of(dev, struct hid_device, dev); | ||
193 | struct ntrig_data *nd = hid_get_drvdata(hdev); | ||
194 | |||
195 | unsigned long val; | ||
196 | |||
197 | if (strict_strtoul(buf, 0, &val)) | ||
198 | return -EINVAL; | ||
199 | |||
200 | if (val > nd->sensor_physical_height) | ||
201 | return -EINVAL; | ||
202 | |||
203 | nd->min_height = val * nd->sensor_logical_height / | ||
204 | nd->sensor_physical_height; | ||
205 | |||
206 | return count; | ||
207 | } | ||
208 | |||
209 | static DEVICE_ATTR(min_height, S_IWUSR | S_IRUGO, show_min_height, | ||
210 | set_min_height); | ||
211 | |||
212 | static ssize_t show_activate_slack(struct device *dev, | ||
213 | struct device_attribute *attr, | ||
214 | char *buf) | ||
215 | { | ||
216 | struct hid_device *hdev = container_of(dev, struct hid_device, dev); | ||
217 | struct ntrig_data *nd = hid_get_drvdata(hdev); | ||
218 | |||
219 | return sprintf(buf, "%d\n", nd->activate_slack); | ||
220 | } | ||
221 | |||
222 | static ssize_t set_activate_slack(struct device *dev, | ||
223 | struct device_attribute *attr, | ||
224 | const char *buf, size_t count) | ||
225 | { | ||
226 | struct hid_device *hdev = container_of(dev, struct hid_device, dev); | ||
227 | struct ntrig_data *nd = hid_get_drvdata(hdev); | ||
228 | |||
229 | unsigned long val; | ||
230 | |||
231 | if (strict_strtoul(buf, 0, &val)) | ||
232 | return -EINVAL; | ||
233 | |||
234 | if (val > 0x7f) | ||
235 | return -EINVAL; | ||
236 | |||
237 | nd->activate_slack = val; | ||
238 | |||
239 | return count; | ||
240 | } | ||
241 | |||
242 | static DEVICE_ATTR(activate_slack, S_IWUSR | S_IRUGO, show_activate_slack, | ||
243 | set_activate_slack); | ||
244 | |||
245 | static ssize_t show_activation_width(struct device *dev, | ||
246 | struct device_attribute *attr, | ||
247 | char *buf) | ||
248 | { | ||
249 | struct hid_device *hdev = container_of(dev, struct hid_device, dev); | ||
250 | struct ntrig_data *nd = hid_get_drvdata(hdev); | ||
251 | |||
252 | return sprintf(buf, "%d\n", nd->activation_width * | ||
253 | nd->sensor_physical_width / | ||
254 | nd->sensor_logical_width); | ||
255 | } | ||
256 | |||
257 | static ssize_t set_activation_width(struct device *dev, | ||
258 | struct device_attribute *attr, | ||
259 | const char *buf, size_t count) | ||
260 | { | ||
261 | struct hid_device *hdev = container_of(dev, struct hid_device, dev); | ||
262 | struct ntrig_data *nd = hid_get_drvdata(hdev); | ||
263 | |||
264 | unsigned long val; | ||
265 | |||
266 | if (strict_strtoul(buf, 0, &val)) | ||
267 | return -EINVAL; | ||
268 | |||
269 | if (val > nd->sensor_physical_width) | ||
270 | return -EINVAL; | ||
271 | |||
272 | nd->activation_width = val * nd->sensor_logical_width / | ||
273 | nd->sensor_physical_width; | ||
274 | |||
275 | return count; | ||
276 | } | ||
277 | |||
278 | static DEVICE_ATTR(activation_width, S_IWUSR | S_IRUGO, show_activation_width, | ||
279 | set_activation_width); | ||
280 | |||
281 | static ssize_t show_activation_height(struct device *dev, | ||
282 | struct device_attribute *attr, | ||
283 | char *buf) | ||
284 | { | ||
285 | struct hid_device *hdev = container_of(dev, struct hid_device, dev); | ||
286 | struct ntrig_data *nd = hid_get_drvdata(hdev); | ||
287 | |||
288 | return sprintf(buf, "%d\n", nd->activation_height * | ||
289 | nd->sensor_physical_height / | ||
290 | nd->sensor_logical_height); | ||
291 | } | ||
292 | |||
293 | static ssize_t set_activation_height(struct device *dev, | ||
294 | struct device_attribute *attr, | ||
295 | const char *buf, size_t count) | ||
296 | { | ||
297 | struct hid_device *hdev = container_of(dev, struct hid_device, dev); | ||
298 | struct ntrig_data *nd = hid_get_drvdata(hdev); | ||
299 | |||
300 | unsigned long val; | ||
301 | |||
302 | if (strict_strtoul(buf, 0, &val)) | ||
303 | return -EINVAL; | ||
304 | |||
305 | if (val > nd->sensor_physical_height) | ||
306 | return -EINVAL; | ||
307 | |||
308 | nd->activation_height = val * nd->sensor_logical_height / | ||
309 | nd->sensor_physical_height; | ||
310 | |||
311 | return count; | ||
312 | } | ||
313 | |||
314 | static DEVICE_ATTR(activation_height, S_IWUSR | S_IRUGO, | ||
315 | show_activation_height, set_activation_height); | ||
316 | |||
317 | static ssize_t show_deactivate_slack(struct device *dev, | ||
318 | struct device_attribute *attr, | ||
319 | char *buf) | ||
320 | { | ||
321 | struct hid_device *hdev = container_of(dev, struct hid_device, dev); | ||
322 | struct ntrig_data *nd = hid_get_drvdata(hdev); | ||
323 | |||
324 | return sprintf(buf, "%d\n", -nd->deactivate_slack); | ||
325 | } | ||
326 | |||
327 | static ssize_t set_deactivate_slack(struct device *dev, | ||
328 | struct device_attribute *attr, | ||
329 | const char *buf, size_t count) | ||
330 | { | ||
331 | struct hid_device *hdev = container_of(dev, struct hid_device, dev); | ||
332 | struct ntrig_data *nd = hid_get_drvdata(hdev); | ||
333 | |||
334 | unsigned long val; | ||
335 | |||
336 | if (strict_strtoul(buf, 0, &val)) | ||
337 | return -EINVAL; | ||
338 | |||
339 | /* | ||
340 | * No more than 8 terminal frames have been observed so far | ||
341 | * and higher slack is highly likely to leave the single | ||
342 | * touch emulation stuck down. | ||
343 | */ | ||
344 | if (val > 7) | ||
345 | return -EINVAL; | ||
346 | |||
347 | nd->deactivate_slack = -val; | ||
348 | |||
349 | return count; | ||
350 | } | ||
351 | |||
352 | static DEVICE_ATTR(deactivate_slack, S_IWUSR | S_IRUGO, show_deactivate_slack, | ||
353 | set_deactivate_slack); | ||
354 | |||
355 | static struct attribute *sysfs_attrs[] = { | ||
356 | &dev_attr_sensor_physical_width.attr, | ||
357 | &dev_attr_sensor_physical_height.attr, | ||
358 | &dev_attr_sensor_logical_width.attr, | ||
359 | &dev_attr_sensor_logical_height.attr, | ||
360 | &dev_attr_min_height.attr, | ||
361 | &dev_attr_min_width.attr, | ||
362 | &dev_attr_activate_slack.attr, | ||
363 | &dev_attr_activation_width.attr, | ||
364 | &dev_attr_activation_height.attr, | ||
365 | &dev_attr_deactivate_slack.attr, | ||
366 | NULL | ||
367 | }; | ||
368 | |||
369 | static struct attribute_group ntrig_attribute_group = { | ||
370 | .attrs = sysfs_attrs | ||
40 | }; | 371 | }; |
41 | 372 | ||
42 | /* | 373 | /* |
@@ -49,6 +380,8 @@ static int ntrig_input_mapping(struct hid_device *hdev, struct hid_input *hi, | |||
49 | struct hid_field *field, struct hid_usage *usage, | 380 | struct hid_field *field, struct hid_usage *usage, |
50 | unsigned long **bit, int *max) | 381 | unsigned long **bit, int *max) |
51 | { | 382 | { |
383 | struct ntrig_data *nd = hid_get_drvdata(hdev); | ||
384 | |||
52 | /* No special mappings needed for the pen and single touch */ | 385 | /* No special mappings needed for the pen and single touch */ |
53 | if (field->physical) | 386 | if (field->physical) |
54 | return 0; | 387 | return 0; |
@@ -62,6 +395,21 @@ static int ntrig_input_mapping(struct hid_device *hdev, struct hid_input *hi, | |||
62 | input_set_abs_params(hi->input, ABS_X, | 395 | input_set_abs_params(hi->input, ABS_X, |
63 | field->logical_minimum, | 396 | field->logical_minimum, |
64 | field->logical_maximum, 0, 0); | 397 | field->logical_maximum, 0, 0); |
398 | |||
399 | if (!nd->sensor_logical_width) { | ||
400 | nd->sensor_logical_width = | ||
401 | field->logical_maximum - | ||
402 | field->logical_minimum; | ||
403 | nd->sensor_physical_width = | ||
404 | field->physical_maximum - | ||
405 | field->physical_minimum; | ||
406 | nd->activation_width = activation_width * | ||
407 | nd->sensor_logical_width / | ||
408 | nd->sensor_physical_width; | ||
409 | nd->min_width = min_width * | ||
410 | nd->sensor_logical_width / | ||
411 | nd->sensor_physical_width; | ||
412 | } | ||
65 | return 1; | 413 | return 1; |
66 | case HID_GD_Y: | 414 | case HID_GD_Y: |
67 | hid_map_usage(hi, usage, bit, max, | 415 | hid_map_usage(hi, usage, bit, max, |
@@ -69,6 +417,21 @@ static int ntrig_input_mapping(struct hid_device *hdev, struct hid_input *hi, | |||
69 | input_set_abs_params(hi->input, ABS_Y, | 417 | input_set_abs_params(hi->input, ABS_Y, |
70 | field->logical_minimum, | 418 | field->logical_minimum, |
71 | field->logical_maximum, 0, 0); | 419 | field->logical_maximum, 0, 0); |
420 | |||
421 | if (!nd->sensor_logical_height) { | ||
422 | nd->sensor_logical_height = | ||
423 | field->logical_maximum - | ||
424 | field->logical_minimum; | ||
425 | nd->sensor_physical_height = | ||
426 | field->physical_maximum - | ||
427 | field->physical_minimum; | ||
428 | nd->activation_height = activation_height * | ||
429 | nd->sensor_logical_height / | ||
430 | nd->sensor_physical_height; | ||
431 | nd->min_height = min_height * | ||
432 | nd->sensor_logical_height / | ||
433 | nd->sensor_physical_height; | ||
434 | } | ||
72 | return 1; | 435 | return 1; |
73 | } | 436 | } |
74 | return 0; | 437 | return 0; |
@@ -201,20 +564,68 @@ static int ntrig_event (struct hid_device *hid, struct hid_field *field, | |||
201 | if (nd->mt_foot_count != 4) | 564 | if (nd->mt_foot_count != 4) |
202 | break; | 565 | break; |
203 | 566 | ||
204 | /* Pen activity signal, trigger end of touch. */ | 567 | /* Pen activity signal. */ |
205 | if (nd->mt_footer[2]) { | 568 | if (nd->mt_footer[2]) { |
569 | /* | ||
570 | * When the pen deactivates touch, we see a | ||
571 | * bogus frame with ContactCount > 0. | ||
572 | * We can | ||
573 | * save a bit of work by ensuring act_state < 0 | ||
574 | * even if deactivation slack is turned off. | ||
575 | */ | ||
576 | nd->act_state = deactivate_slack - 1; | ||
206 | nd->confidence = 0; | 577 | nd->confidence = 0; |
207 | break; | 578 | break; |
208 | } | 579 | } |
209 | 580 | ||
210 | /* If the contact was invalid */ | 581 | /* |
211 | if (!(nd->confidence && nd->mt_footer[0]) | 582 | * The first footer value indicates the presence of a |
212 | || nd->w <= 250 | 583 | * finger. |
213 | || nd->h <= 190) { | 584 | */ |
214 | nd->confidence = 0; | 585 | if (nd->mt_footer[0]) { |
586 | /* | ||
587 | * We do not want to process contacts under | ||
588 | * the size threshold, but do not want to | ||
589 | * ignore them for activation state | ||
590 | */ | ||
591 | if (nd->w < nd->min_width || | ||
592 | nd->h < nd->min_height) | ||
593 | nd->confidence = 0; | ||
594 | } else | ||
215 | break; | 595 | break; |
596 | |||
597 | if (nd->act_state > 0) { | ||
598 | /* | ||
599 | * Contact meets the activation size threshold | ||
600 | */ | ||
601 | if (nd->w >= nd->activation_width && | ||
602 | nd->h >= nd->activation_height) { | ||
603 | if (nd->id) | ||
604 | /* | ||
605 | * first contact, activate now | ||
606 | */ | ||
607 | nd->act_state = 0; | ||
608 | else { | ||
609 | /* | ||
610 | * avoid corrupting this frame | ||
611 | * but ensure next frame will | ||
612 | * be active | ||
613 | */ | ||
614 | nd->act_state = 1; | ||
615 | break; | ||
616 | } | ||
617 | } else | ||
618 | /* | ||
619 | * Defer adjusting the activation state | ||
620 | * until the end of the frame. | ||
621 | */ | ||
622 | break; | ||
216 | } | 623 | } |
217 | 624 | ||
625 | /* Discarding this contact */ | ||
626 | if (!nd->confidence) | ||
627 | break; | ||
628 | |||
218 | /* emit a normal (X, Y) for the first point only */ | 629 | /* emit a normal (X, Y) for the first point only */ |
219 | if (nd->id == 0) { | 630 | if (nd->id == 0) { |
220 | /* | 631 | /* |
@@ -227,8 +638,15 @@ static int ntrig_event (struct hid_device *hid, struct hid_field *field, | |||
227 | input_event(input, EV_ABS, ABS_X, nd->x); | 638 | input_event(input, EV_ABS, ABS_X, nd->x); |
228 | input_event(input, EV_ABS, ABS_Y, nd->y); | 639 | input_event(input, EV_ABS, ABS_Y, nd->y); |
229 | } | 640 | } |
641 | |||
642 | /* Emit MT events */ | ||
230 | input_event(input, EV_ABS, ABS_MT_POSITION_X, nd->x); | 643 | input_event(input, EV_ABS, ABS_MT_POSITION_X, nd->x); |
231 | input_event(input, EV_ABS, ABS_MT_POSITION_Y, nd->y); | 644 | input_event(input, EV_ABS, ABS_MT_POSITION_Y, nd->y); |
645 | |||
646 | /* | ||
647 | * Translate from height and width to size | ||
648 | * and orientation. | ||
649 | */ | ||
232 | if (nd->w > nd->h) { | 650 | if (nd->w > nd->h) { |
233 | input_event(input, EV_ABS, | 651 | input_event(input, EV_ABS, |
234 | ABS_MT_ORIENTATION, 1); | 652 | ABS_MT_ORIENTATION, 1); |
@@ -248,12 +666,88 @@ static int ntrig_event (struct hid_device *hid, struct hid_field *field, | |||
248 | break; | 666 | break; |
249 | 667 | ||
250 | case HID_DG_CONTACTCOUNT: /* End of a multitouch group */ | 668 | case HID_DG_CONTACTCOUNT: /* End of a multitouch group */ |
251 | if (!nd->reading_mt) | 669 | if (!nd->reading_mt) /* Just to be sure */ |
252 | break; | 670 | break; |
253 | 671 | ||
254 | nd->reading_mt = 0; | 672 | nd->reading_mt = 0; |
255 | 673 | ||
256 | if (nd->first_contact_touch) { | 674 | |
675 | /* | ||
676 | * Activation state machine logic: | ||
677 | * | ||
678 | * Fundamental states: | ||
679 | * state > 0: Inactive | ||
680 | * state <= 0: Active | ||
681 | * state < -deactivate_slack: | ||
682 | * Pen termination of touch | ||
683 | * | ||
684 | * Specific values of interest | ||
685 | * state == activate_slack | ||
686 | * no valid input since the last reset | ||
687 | * | ||
688 | * state == 0 | ||
689 | * general operational state | ||
690 | * | ||
691 | * state == -deactivate_slack | ||
692 | * read sufficient empty frames to accept | ||
693 | * the end of input and reset | ||
694 | */ | ||
695 | |||
696 | if (nd->act_state > 0) { /* Currently inactive */ | ||
697 | if (value) | ||
698 | /* | ||
699 | * Consider each live contact as | ||
700 | * evidence of intentional activity. | ||
701 | */ | ||
702 | nd->act_state = (nd->act_state > value) | ||
703 | ? nd->act_state - value | ||
704 | : 0; | ||
705 | else | ||
706 | /* | ||
707 | * Empty frame before we hit the | ||
708 | * activity threshold, reset. | ||
709 | */ | ||
710 | nd->act_state = nd->activate_slack; | ||
711 | |||
712 | /* | ||
713 | * Entered this block inactive and no | ||
714 | * coordinates sent this frame, so hold off | ||
715 | * on button state. | ||
716 | */ | ||
717 | break; | ||
718 | } else { /* Currently active */ | ||
719 | if (value && nd->act_state >= | ||
720 | nd->deactivate_slack) | ||
721 | /* | ||
722 | * Live point: clear accumulated | ||
723 | * deactivation count. | ||
724 | */ | ||
725 | nd->act_state = 0; | ||
726 | else if (nd->act_state <= nd->deactivate_slack) | ||
727 | /* | ||
728 | * We've consumed the deactivation | ||
729 | * slack, time to deactivate and reset. | ||
730 | */ | ||
731 | nd->act_state = | ||
732 | nd->activate_slack; | ||
733 | else { /* Move towards deactivation */ | ||
734 | nd->act_state--; | ||
735 | break; | ||
736 | } | ||
737 | } | ||
738 | |||
739 | if (nd->first_contact_touch && nd->act_state <= 0) { | ||
740 | /* | ||
741 | * Check to see if we're ready to start | ||
742 | * emitting touch events. | ||
743 | * | ||
744 | * Note: activation slack will decrease over | ||
745 | * the course of the frame, and it will be | ||
746 | * inconsistent from the start to the end of | ||
747 | * the frame. However if the frame starts | ||
748 | * with slack, first_contact_touch will still | ||
749 | * be 0 and we will not get to this point. | ||
750 | */ | ||
257 | input_report_key(input, BTN_TOOL_DOUBLETAP, 1); | 751 | input_report_key(input, BTN_TOOL_DOUBLETAP, 1); |
258 | input_report_key(input, BTN_TOUCH, 1); | 752 | input_report_key(input, BTN_TOUCH, 1); |
259 | } else { | 753 | } else { |
@@ -263,7 +757,7 @@ static int ntrig_event (struct hid_device *hid, struct hid_field *field, | |||
263 | break; | 757 | break; |
264 | 758 | ||
265 | default: | 759 | default: |
266 | /* fallback to the generic hidinput handling */ | 760 | /* fall-back to the generic hidinput handling */ |
267 | return 0; | 761 | return 0; |
268 | } | 762 | } |
269 | } | 763 | } |
@@ -293,6 +787,16 @@ static int ntrig_probe(struct hid_device *hdev, const struct hid_device_id *id) | |||
293 | } | 787 | } |
294 | 788 | ||
295 | nd->reading_mt = 0; | 789 | nd->reading_mt = 0; |
790 | nd->min_width = 0; | ||
791 | nd->min_height = 0; | ||
792 | nd->activate_slack = activate_slack; | ||
793 | nd->act_state = activate_slack; | ||
794 | nd->deactivate_slack = -deactivate_slack; | ||
795 | nd->sensor_logical_width = 0; | ||
796 | nd->sensor_logical_height = 0; | ||
797 | nd->sensor_physical_width = 0; | ||
798 | nd->sensor_physical_height = 0; | ||
799 | |||
296 | hid_set_drvdata(hdev, nd); | 800 | hid_set_drvdata(hdev, nd); |
297 | 801 | ||
298 | ret = hid_parse(hdev); | 802 | ret = hid_parse(hdev); |
@@ -344,6 +848,8 @@ static int ntrig_probe(struct hid_device *hdev, const struct hid_device_id *id) | |||
344 | if (report) | 848 | if (report) |
345 | usbhid_submit_report(hdev, report, USB_DIR_OUT); | 849 | usbhid_submit_report(hdev, report, USB_DIR_OUT); |
346 | 850 | ||
851 | ret = sysfs_create_group(&hdev->dev.kobj, | ||
852 | &ntrig_attribute_group); | ||
347 | 853 | ||
348 | return 0; | 854 | return 0; |
349 | err_free: | 855 | err_free: |
@@ -353,6 +859,8 @@ err_free: | |||
353 | 859 | ||
354 | static void ntrig_remove(struct hid_device *hdev) | 860 | static void ntrig_remove(struct hid_device *hdev) |
355 | { | 861 | { |
862 | sysfs_remove_group(&hdev->dev.kobj, | ||
863 | &ntrig_attribute_group); | ||
356 | hid_hw_stop(hdev); | 864 | hid_hw_stop(hdev); |
357 | kfree(hid_get_drvdata(hdev)); | 865 | kfree(hid_get_drvdata(hdev)); |
358 | } | 866 | } |
diff --git a/drivers/hid/hid-picolcd.c b/drivers/hid/hid-picolcd.c new file mode 100644 index 000000000000..7aabf65c48ef --- /dev/null +++ b/drivers/hid/hid-picolcd.c | |||
@@ -0,0 +1,2631 @@ | |||
1 | /*************************************************************************** | ||
2 | * Copyright (C) 2010 by Bruno Prémont <bonbons@linux-vserver.org> * | ||
3 | * * | ||
4 | * Based on Logitech G13 driver (v0.4) * | ||
5 | * Copyright (C) 2009 by Rick L. Vinyard, Jr. <rvinyard@cs.nmsu.edu> * | ||
6 | * * | ||
7 | * This program is free software: you can redistribute it and/or modify * | ||
8 | * it under the terms of the GNU General Public License as published by * | ||
9 | * the Free Software Foundation, version 2 of the License. * | ||
10 | * * | ||
11 | * This driver is distributed in the hope that it will be useful, but * | ||
12 | * WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * | ||
14 | * General Public License for more details. * | ||
15 | * * | ||
16 | * You should have received a copy of the GNU General Public License * | ||
17 | * along with this software. If not see <http://www.gnu.org/licenses/>. * | ||
18 | ***************************************************************************/ | ||
19 | |||
20 | #include <linux/hid.h> | ||
21 | #include <linux/hid-debug.h> | ||
22 | #include <linux/input.h> | ||
23 | #include "hid-ids.h" | ||
24 | #include "usbhid/usbhid.h" | ||
25 | #include <linux/usb.h> | ||
26 | |||
27 | #include <linux/fb.h> | ||
28 | #include <linux/vmalloc.h> | ||
29 | #include <linux/backlight.h> | ||
30 | #include <linux/lcd.h> | ||
31 | |||
32 | #include <linux/leds.h> | ||
33 | |||
34 | #include <linux/seq_file.h> | ||
35 | #include <linux/debugfs.h> | ||
36 | |||
37 | #include <linux/completion.h> | ||
38 | #include <linux/uaccess.h> | ||
39 | |||
40 | #define PICOLCD_NAME "PicoLCD (graphic)" | ||
41 | |||
42 | /* Report numbers */ | ||
43 | #define REPORT_ERROR_CODE 0x10 /* LCD: IN[16] */ | ||
44 | #define ERR_SUCCESS 0x00 | ||
45 | #define ERR_PARAMETER_MISSING 0x01 | ||
46 | #define ERR_DATA_MISSING 0x02 | ||
47 | #define ERR_BLOCK_READ_ONLY 0x03 | ||
48 | #define ERR_BLOCK_NOT_ERASABLE 0x04 | ||
49 | #define ERR_BLOCK_TOO_BIG 0x05 | ||
50 | #define ERR_SECTION_OVERFLOW 0x06 | ||
51 | #define ERR_INVALID_CMD_LEN 0x07 | ||
52 | #define ERR_INVALID_DATA_LEN 0x08 | ||
53 | #define REPORT_KEY_STATE 0x11 /* LCD: IN[2] */ | ||
54 | #define REPORT_IR_DATA 0x21 /* LCD: IN[63] */ | ||
55 | #define REPORT_EE_DATA 0x32 /* LCD: IN[63] */ | ||
56 | #define REPORT_MEMORY 0x41 /* LCD: IN[63] */ | ||
57 | #define REPORT_LED_STATE 0x81 /* LCD: OUT[1] */ | ||
58 | #define REPORT_BRIGHTNESS 0x91 /* LCD: OUT[1] */ | ||
59 | #define REPORT_CONTRAST 0x92 /* LCD: OUT[1] */ | ||
60 | #define REPORT_RESET 0x93 /* LCD: OUT[2] */ | ||
61 | #define REPORT_LCD_CMD 0x94 /* LCD: OUT[63] */ | ||
62 | #define REPORT_LCD_DATA 0x95 /* LCD: OUT[63] */ | ||
63 | #define REPORT_LCD_CMD_DATA 0x96 /* LCD: OUT[63] */ | ||
64 | #define REPORT_EE_READ 0xa3 /* LCD: OUT[63] */ | ||
65 | #define REPORT_EE_WRITE 0xa4 /* LCD: OUT[63] */ | ||
66 | #define REPORT_ERASE_MEMORY 0xb2 /* LCD: OUT[2] */ | ||
67 | #define REPORT_READ_MEMORY 0xb3 /* LCD: OUT[3] */ | ||
68 | #define REPORT_WRITE_MEMORY 0xb4 /* LCD: OUT[63] */ | ||
69 | #define REPORT_SPLASH_RESTART 0xc1 /* LCD: OUT[1] */ | ||
70 | #define REPORT_EXIT_KEYBOARD 0xef /* LCD: OUT[2] */ | ||
71 | #define REPORT_VERSION 0xf1 /* LCD: IN[2],OUT[1] Bootloader: IN[2],OUT[1] */ | ||
72 | #define REPORT_BL_ERASE_MEMORY 0xf2 /* Bootloader: IN[36],OUT[4] */ | ||
73 | #define REPORT_BL_READ_MEMORY 0xf3 /* Bootloader: IN[36],OUT[4] */ | ||
74 | #define REPORT_BL_WRITE_MEMORY 0xf4 /* Bootloader: IN[36],OUT[36] */ | ||
75 | #define REPORT_DEVID 0xf5 /* LCD: IN[5], OUT[1] Bootloader: IN[5],OUT[1] */ | ||
76 | #define REPORT_SPLASH_SIZE 0xf6 /* LCD: IN[4], OUT[1] */ | ||
77 | #define REPORT_HOOK_VERSION 0xf7 /* LCD: IN[2], OUT[1] */ | ||
78 | #define REPORT_EXIT_FLASHER 0xff /* Bootloader: OUT[2] */ | ||
79 | |||
80 | #ifdef CONFIG_HID_PICOLCD_FB | ||
81 | /* Framebuffer | ||
82 | * | ||
83 | * The PicoLCD use a Topway LCD module of 256x64 pixel | ||
84 | * This display area is tiled over 4 controllers with 8 tiles | ||
85 | * each. Each tile has 8x64 pixel, each data byte representing | ||
86 | * a 1-bit wide vertical line of the tile. | ||
87 | * | ||
88 | * The display can be updated at a tile granularity. | ||
89 | * | ||
90 | * Chip 1 Chip 2 Chip 3 Chip 4 | ||
91 | * +----------------+----------------+----------------+----------------+ | ||
92 | * | Tile 1 | Tile 1 | Tile 1 | Tile 1 | | ||
93 | * +----------------+----------------+----------------+----------------+ | ||
94 | * | Tile 2 | Tile 2 | Tile 2 | Tile 2 | | ||
95 | * +----------------+----------------+----------------+----------------+ | ||
96 | * ... | ||
97 | * +----------------+----------------+----------------+----------------+ | ||
98 | * | Tile 8 | Tile 8 | Tile 8 | Tile 8 | | ||
99 | * +----------------+----------------+----------------+----------------+ | ||
100 | */ | ||
101 | #define PICOLCDFB_NAME "picolcdfb" | ||
102 | #define PICOLCDFB_WIDTH (256) | ||
103 | #define PICOLCDFB_HEIGHT (64) | ||
104 | #define PICOLCDFB_SIZE (PICOLCDFB_WIDTH * PICOLCDFB_HEIGHT / 8) | ||
105 | |||
106 | #define PICOLCDFB_UPDATE_RATE_LIMIT 10 | ||
107 | #define PICOLCDFB_UPDATE_RATE_DEFAULT 2 | ||
108 | |||
109 | /* Framebuffer visual structures */ | ||
110 | static const struct fb_fix_screeninfo picolcdfb_fix = { | ||
111 | .id = PICOLCDFB_NAME, | ||
112 | .type = FB_TYPE_PACKED_PIXELS, | ||
113 | .visual = FB_VISUAL_MONO01, | ||
114 | .xpanstep = 0, | ||
115 | .ypanstep = 0, | ||
116 | .ywrapstep = 0, | ||
117 | .line_length = PICOLCDFB_WIDTH / 8, | ||
118 | .accel = FB_ACCEL_NONE, | ||
119 | }; | ||
120 | |||
121 | static const struct fb_var_screeninfo picolcdfb_var = { | ||
122 | .xres = PICOLCDFB_WIDTH, | ||
123 | .yres = PICOLCDFB_HEIGHT, | ||
124 | .xres_virtual = PICOLCDFB_WIDTH, | ||
125 | .yres_virtual = PICOLCDFB_HEIGHT, | ||
126 | .width = 103, | ||
127 | .height = 26, | ||
128 | .bits_per_pixel = 1, | ||
129 | .grayscale = 1, | ||
130 | }; | ||
131 | #endif /* CONFIG_HID_PICOLCD_FB */ | ||
132 | |||
133 | /* Input device | ||
134 | * | ||
135 | * The PicoLCD has an IR receiver header, a built-in keypad with 5 keys | ||
136 | * and header for 4x4 key matrix. The built-in keys are part of the matrix. | ||
137 | */ | ||
138 | static const unsigned short def_keymap[] = { | ||
139 | KEY_RESERVED, /* none */ | ||
140 | KEY_BACK, /* col 4 + row 1 */ | ||
141 | KEY_HOMEPAGE, /* col 3 + row 1 */ | ||
142 | KEY_RESERVED, /* col 2 + row 1 */ | ||
143 | KEY_RESERVED, /* col 1 + row 1 */ | ||
144 | KEY_SCROLLUP, /* col 4 + row 2 */ | ||
145 | KEY_OK, /* col 3 + row 2 */ | ||
146 | KEY_SCROLLDOWN, /* col 2 + row 2 */ | ||
147 | KEY_RESERVED, /* col 1 + row 2 */ | ||
148 | KEY_RESERVED, /* col 4 + row 3 */ | ||
149 | KEY_RESERVED, /* col 3 + row 3 */ | ||
150 | KEY_RESERVED, /* col 2 + row 3 */ | ||
151 | KEY_RESERVED, /* col 1 + row 3 */ | ||
152 | KEY_RESERVED, /* col 4 + row 4 */ | ||
153 | KEY_RESERVED, /* col 3 + row 4 */ | ||
154 | KEY_RESERVED, /* col 2 + row 4 */ | ||
155 | KEY_RESERVED, /* col 1 + row 4 */ | ||
156 | }; | ||
157 | #define PICOLCD_KEYS ARRAY_SIZE(def_keymap) | ||
158 | |||
159 | /* Description of in-progress IO operation, used for operations | ||
160 | * that trigger response from device */ | ||
161 | struct picolcd_pending { | ||
162 | struct hid_report *out_report; | ||
163 | struct hid_report *in_report; | ||
164 | struct completion ready; | ||
165 | int raw_size; | ||
166 | u8 raw_data[64]; | ||
167 | }; | ||
168 | |||
169 | /* Per device data structure */ | ||
170 | struct picolcd_data { | ||
171 | struct hid_device *hdev; | ||
172 | #ifdef CONFIG_DEBUG_FS | ||
173 | struct dentry *debug_reset; | ||
174 | struct dentry *debug_eeprom; | ||
175 | struct dentry *debug_flash; | ||
176 | struct mutex mutex_flash; | ||
177 | int addr_sz; | ||
178 | #endif | ||
179 | u8 version[2]; | ||
180 | unsigned short opmode_delay; | ||
181 | /* input stuff */ | ||
182 | u8 pressed_keys[2]; | ||
183 | struct input_dev *input_keys; | ||
184 | struct input_dev *input_cir; | ||
185 | unsigned short keycode[PICOLCD_KEYS]; | ||
186 | |||
187 | #ifdef CONFIG_HID_PICOLCD_FB | ||
188 | /* Framebuffer stuff */ | ||
189 | u8 fb_update_rate; | ||
190 | u8 fb_bpp; | ||
191 | u8 *fb_vbitmap; /* local copy of what was sent to PicoLCD */ | ||
192 | u8 *fb_bitmap; /* framebuffer */ | ||
193 | struct fb_info *fb_info; | ||
194 | struct fb_deferred_io fb_defio; | ||
195 | #endif /* CONFIG_HID_PICOLCD_FB */ | ||
196 | #ifdef CONFIG_HID_PICOLCD_LCD | ||
197 | struct lcd_device *lcd; | ||
198 | u8 lcd_contrast; | ||
199 | #endif /* CONFIG_HID_PICOLCD_LCD */ | ||
200 | #ifdef CONFIG_HID_PICOLCD_BACKLIGHT | ||
201 | struct backlight_device *backlight; | ||
202 | u8 lcd_brightness; | ||
203 | u8 lcd_power; | ||
204 | #endif /* CONFIG_HID_PICOLCD_BACKLIGHT */ | ||
205 | #ifdef CONFIG_HID_PICOLCD_LEDS | ||
206 | /* LED stuff */ | ||
207 | u8 led_state; | ||
208 | struct led_classdev *led[8]; | ||
209 | #endif /* CONFIG_HID_PICOLCD_LEDS */ | ||
210 | |||
211 | /* Housekeeping stuff */ | ||
212 | spinlock_t lock; | ||
213 | struct mutex mutex; | ||
214 | struct picolcd_pending *pending; | ||
215 | int status; | ||
216 | #define PICOLCD_BOOTLOADER 1 | ||
217 | #define PICOLCD_FAILED 2 | ||
218 | #define PICOLCD_READY_FB 4 | ||
219 | }; | ||
220 | |||
221 | |||
222 | /* Find a given report */ | ||
223 | #define picolcd_in_report(id, dev) picolcd_report(id, dev, HID_INPUT_REPORT) | ||
224 | #define picolcd_out_report(id, dev) picolcd_report(id, dev, HID_OUTPUT_REPORT) | ||
225 | |||
226 | static struct hid_report *picolcd_report(int id, struct hid_device *hdev, int dir) | ||
227 | { | ||
228 | struct list_head *feature_report_list = &hdev->report_enum[dir].report_list; | ||
229 | struct hid_report *report = NULL; | ||
230 | |||
231 | list_for_each_entry(report, feature_report_list, list) { | ||
232 | if (report->id == id) | ||
233 | return report; | ||
234 | } | ||
235 | dev_warn(&hdev->dev, "No report with id 0x%x found\n", id); | ||
236 | return NULL; | ||
237 | } | ||
238 | |||
239 | #ifdef CONFIG_DEBUG_FS | ||
240 | static void picolcd_debug_out_report(struct picolcd_data *data, | ||
241 | struct hid_device *hdev, struct hid_report *report); | ||
242 | #define usbhid_submit_report(a, b, c) \ | ||
243 | do { \ | ||
244 | picolcd_debug_out_report(hid_get_drvdata(a), a, b); \ | ||
245 | usbhid_submit_report(a, b, c); \ | ||
246 | } while (0) | ||
247 | #endif | ||
248 | |||
249 | /* Submit a report and wait for a reply from device - if device fades away | ||
250 | * or does not respond in time, return NULL */ | ||
251 | static struct picolcd_pending *picolcd_send_and_wait(struct hid_device *hdev, | ||
252 | int report_id, const u8 *raw_data, int size) | ||
253 | { | ||
254 | struct picolcd_data *data = hid_get_drvdata(hdev); | ||
255 | struct picolcd_pending *work; | ||
256 | struct hid_report *report = picolcd_out_report(report_id, hdev); | ||
257 | unsigned long flags; | ||
258 | int i, j, k; | ||
259 | |||
260 | if (!report || !data) | ||
261 | return NULL; | ||
262 | if (data->status & PICOLCD_FAILED) | ||
263 | return NULL; | ||
264 | work = kzalloc(sizeof(*work), GFP_KERNEL); | ||
265 | if (!work) | ||
266 | return NULL; | ||
267 | |||
268 | init_completion(&work->ready); | ||
269 | work->out_report = report; | ||
270 | work->in_report = NULL; | ||
271 | work->raw_size = 0; | ||
272 | |||
273 | mutex_lock(&data->mutex); | ||
274 | spin_lock_irqsave(&data->lock, flags); | ||
275 | for (i = k = 0; i < report->maxfield; i++) | ||
276 | for (j = 0; j < report->field[i]->report_count; j++) { | ||
277 | hid_set_field(report->field[i], j, k < size ? raw_data[k] : 0); | ||
278 | k++; | ||
279 | } | ||
280 | data->pending = work; | ||
281 | usbhid_submit_report(data->hdev, report, USB_DIR_OUT); | ||
282 | spin_unlock_irqrestore(&data->lock, flags); | ||
283 | wait_for_completion_interruptible_timeout(&work->ready, HZ*2); | ||
284 | spin_lock_irqsave(&data->lock, flags); | ||
285 | data->pending = NULL; | ||
286 | spin_unlock_irqrestore(&data->lock, flags); | ||
287 | mutex_unlock(&data->mutex); | ||
288 | return work; | ||
289 | } | ||
290 | |||
291 | #ifdef CONFIG_HID_PICOLCD_FB | ||
292 | /* Send a given tile to PicoLCD */ | ||
293 | static int picolcd_fb_send_tile(struct hid_device *hdev, int chip, int tile) | ||
294 | { | ||
295 | struct picolcd_data *data = hid_get_drvdata(hdev); | ||
296 | struct hid_report *report1 = picolcd_out_report(REPORT_LCD_CMD_DATA, hdev); | ||
297 | struct hid_report *report2 = picolcd_out_report(REPORT_LCD_DATA, hdev); | ||
298 | unsigned long flags; | ||
299 | u8 *tdata; | ||
300 | int i; | ||
301 | |||
302 | if (!report1 || report1->maxfield != 1 || !report2 || report2->maxfield != 1) | ||
303 | return -ENODEV; | ||
304 | |||
305 | spin_lock_irqsave(&data->lock, flags); | ||
306 | hid_set_field(report1->field[0], 0, chip << 2); | ||
307 | hid_set_field(report1->field[0], 1, 0x02); | ||
308 | hid_set_field(report1->field[0], 2, 0x00); | ||
309 | hid_set_field(report1->field[0], 3, 0x00); | ||
310 | hid_set_field(report1->field[0], 4, 0xb8 | tile); | ||
311 | hid_set_field(report1->field[0], 5, 0x00); | ||
312 | hid_set_field(report1->field[0], 6, 0x00); | ||
313 | hid_set_field(report1->field[0], 7, 0x40); | ||
314 | hid_set_field(report1->field[0], 8, 0x00); | ||
315 | hid_set_field(report1->field[0], 9, 0x00); | ||
316 | hid_set_field(report1->field[0], 10, 32); | ||
317 | |||
318 | hid_set_field(report2->field[0], 0, (chip << 2) | 0x01); | ||
319 | hid_set_field(report2->field[0], 1, 0x00); | ||
320 | hid_set_field(report2->field[0], 2, 0x00); | ||
321 | hid_set_field(report2->field[0], 3, 32); | ||
322 | |||
323 | tdata = data->fb_vbitmap + (tile * 4 + chip) * 64; | ||
324 | for (i = 0; i < 64; i++) | ||
325 | if (i < 32) | ||
326 | hid_set_field(report1->field[0], 11 + i, tdata[i]); | ||
327 | else | ||
328 | hid_set_field(report2->field[0], 4 + i - 32, tdata[i]); | ||
329 | |||
330 | usbhid_submit_report(data->hdev, report1, USB_DIR_OUT); | ||
331 | usbhid_submit_report(data->hdev, report2, USB_DIR_OUT); | ||
332 | spin_unlock_irqrestore(&data->lock, flags); | ||
333 | return 0; | ||
334 | } | ||
335 | |||
336 | /* Translate a single tile*/ | ||
337 | static int picolcd_fb_update_tile(u8 *vbitmap, const u8 *bitmap, int bpp, | ||
338 | int chip, int tile) | ||
339 | { | ||
340 | int i, b, changed = 0; | ||
341 | u8 tdata[64]; | ||
342 | u8 *vdata = vbitmap + (tile * 4 + chip) * 64; | ||
343 | |||
344 | if (bpp == 1) { | ||
345 | for (b = 7; b >= 0; b--) { | ||
346 | const u8 *bdata = bitmap + tile * 256 + chip * 8 + b * 32; | ||
347 | for (i = 0; i < 64; i++) { | ||
348 | tdata[i] <<= 1; | ||
349 | tdata[i] |= (bdata[i/8] >> (7 - i % 8)) & 0x01; | ||
350 | } | ||
351 | } | ||
352 | } else if (bpp == 8) { | ||
353 | for (b = 7; b >= 0; b--) { | ||
354 | const u8 *bdata = bitmap + (tile * 256 + chip * 8 + b * 32) * 8; | ||
355 | for (i = 0; i < 64; i++) { | ||
356 | tdata[i] <<= 1; | ||
357 | tdata[i] |= (bdata[i] & 0x80) ? 0x01 : 0x00; | ||
358 | } | ||
359 | } | ||
360 | } else { | ||
361 | /* Oops, we should never get here! */ | ||
362 | WARN_ON(1); | ||
363 | return 0; | ||
364 | } | ||
365 | |||
366 | for (i = 0; i < 64; i++) | ||
367 | if (tdata[i] != vdata[i]) { | ||
368 | changed = 1; | ||
369 | vdata[i] = tdata[i]; | ||
370 | } | ||
371 | return changed; | ||
372 | } | ||
373 | |||
374 | /* Reconfigure LCD display */ | ||
375 | static int picolcd_fb_reset(struct picolcd_data *data, int clear) | ||
376 | { | ||
377 | struct hid_report *report = picolcd_out_report(REPORT_LCD_CMD, data->hdev); | ||
378 | int i, j; | ||
379 | unsigned long flags; | ||
380 | static const u8 mapcmd[8] = { 0x00, 0x02, 0x00, 0x64, 0x3f, 0x00, 0x64, 0xc0 }; | ||
381 | |||
382 | if (!report || report->maxfield != 1) | ||
383 | return -ENODEV; | ||
384 | |||
385 | spin_lock_irqsave(&data->lock, flags); | ||
386 | for (i = 0; i < 4; i++) { | ||
387 | for (j = 0; j < report->field[0]->maxusage; j++) | ||
388 | if (j == 0) | ||
389 | hid_set_field(report->field[0], j, i << 2); | ||
390 | else if (j < sizeof(mapcmd)) | ||
391 | hid_set_field(report->field[0], j, mapcmd[j]); | ||
392 | else | ||
393 | hid_set_field(report->field[0], j, 0); | ||
394 | usbhid_submit_report(data->hdev, report, USB_DIR_OUT); | ||
395 | } | ||
396 | |||
397 | data->status |= PICOLCD_READY_FB; | ||
398 | spin_unlock_irqrestore(&data->lock, flags); | ||
399 | |||
400 | if (data->fb_bitmap) { | ||
401 | if (clear) { | ||
402 | memset(data->fb_vbitmap, 0xff, PICOLCDFB_SIZE); | ||
403 | memset(data->fb_bitmap, 0, PICOLCDFB_SIZE*data->fb_bpp); | ||
404 | } else { | ||
405 | /* invert 1 byte in each tile to force resend */ | ||
406 | for (i = 0; i < PICOLCDFB_SIZE; i += 64) | ||
407 | data->fb_vbitmap[i] = ~data->fb_vbitmap[i]; | ||
408 | } | ||
409 | } | ||
410 | |||
411 | /* schedule first output of framebuffer */ | ||
412 | if (data->fb_info) | ||
413 | schedule_delayed_work(&data->fb_info->deferred_work, 0); | ||
414 | |||
415 | return 0; | ||
416 | } | ||
417 | |||
418 | /* Update fb_vbitmap from the screen_base and send changed tiles to device */ | ||
419 | static void picolcd_fb_update(struct picolcd_data *data) | ||
420 | { | ||
421 | int chip, tile, n; | ||
422 | unsigned long flags; | ||
423 | |||
424 | spin_lock_irqsave(&data->lock, flags); | ||
425 | if (!(data->status & PICOLCD_READY_FB)) { | ||
426 | spin_unlock_irqrestore(&data->lock, flags); | ||
427 | picolcd_fb_reset(data, 0); | ||
428 | } else { | ||
429 | spin_unlock_irqrestore(&data->lock, flags); | ||
430 | } | ||
431 | |||
432 | /* | ||
433 | * Translate the framebuffer into the format needed by the PicoLCD. | ||
434 | * See display layout above. | ||
435 | * Do this one tile after the other and push those tiles that changed. | ||
436 | * | ||
437 | * Wait for our IO to complete as otherwise we might flood the queue! | ||
438 | */ | ||
439 | n = 0; | ||
440 | for (chip = 0; chip < 4; chip++) | ||
441 | for (tile = 0; tile < 8; tile++) | ||
442 | if (picolcd_fb_update_tile(data->fb_vbitmap, | ||
443 | data->fb_bitmap, data->fb_bpp, chip, tile)) { | ||
444 | n += 2; | ||
445 | if (n >= HID_OUTPUT_FIFO_SIZE / 2) { | ||
446 | usbhid_wait_io(data->hdev); | ||
447 | n = 0; | ||
448 | } | ||
449 | picolcd_fb_send_tile(data->hdev, chip, tile); | ||
450 | } | ||
451 | if (n) | ||
452 | usbhid_wait_io(data->hdev); | ||
453 | } | ||
454 | |||
455 | /* Stub to call the system default and update the image on the picoLCD */ | ||
456 | static void picolcd_fb_fillrect(struct fb_info *info, | ||
457 | const struct fb_fillrect *rect) | ||
458 | { | ||
459 | if (!info->par) | ||
460 | return; | ||
461 | sys_fillrect(info, rect); | ||
462 | |||
463 | schedule_delayed_work(&info->deferred_work, 0); | ||
464 | } | ||
465 | |||
466 | /* Stub to call the system default and update the image on the picoLCD */ | ||
467 | static void picolcd_fb_copyarea(struct fb_info *info, | ||
468 | const struct fb_copyarea *area) | ||
469 | { | ||
470 | if (!info->par) | ||
471 | return; | ||
472 | sys_copyarea(info, area); | ||
473 | |||
474 | schedule_delayed_work(&info->deferred_work, 0); | ||
475 | } | ||
476 | |||
477 | /* Stub to call the system default and update the image on the picoLCD */ | ||
478 | static void picolcd_fb_imageblit(struct fb_info *info, const struct fb_image *image) | ||
479 | { | ||
480 | if (!info->par) | ||
481 | return; | ||
482 | sys_imageblit(info, image); | ||
483 | |||
484 | schedule_delayed_work(&info->deferred_work, 0); | ||
485 | } | ||
486 | |||
487 | /* | ||
488 | * this is the slow path from userspace. they can seek and write to | ||
489 | * the fb. it's inefficient to do anything less than a full screen draw | ||
490 | */ | ||
491 | static ssize_t picolcd_fb_write(struct fb_info *info, const char __user *buf, | ||
492 | size_t count, loff_t *ppos) | ||
493 | { | ||
494 | ssize_t ret; | ||
495 | if (!info->par) | ||
496 | return -ENODEV; | ||
497 | ret = fb_sys_write(info, buf, count, ppos); | ||
498 | if (ret >= 0) | ||
499 | schedule_delayed_work(&info->deferred_work, 0); | ||
500 | return ret; | ||
501 | } | ||
502 | |||
503 | static int picolcd_fb_blank(int blank, struct fb_info *info) | ||
504 | { | ||
505 | if (!info->par) | ||
506 | return -ENODEV; | ||
507 | /* We let fb notification do this for us via lcd/backlight device */ | ||
508 | return 0; | ||
509 | } | ||
510 | |||
511 | static void picolcd_fb_destroy(struct fb_info *info) | ||
512 | { | ||
513 | struct picolcd_data *data = info->par; | ||
514 | info->par = NULL; | ||
515 | if (data) | ||
516 | data->fb_info = NULL; | ||
517 | fb_deferred_io_cleanup(info); | ||
518 | framebuffer_release(info); | ||
519 | } | ||
520 | |||
521 | static int picolcd_fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) | ||
522 | { | ||
523 | __u32 bpp = var->bits_per_pixel; | ||
524 | __u32 activate = var->activate; | ||
525 | |||
526 | /* only allow 1/8 bit depth (8-bit is grayscale) */ | ||
527 | *var = picolcdfb_var; | ||
528 | var->activate = activate; | ||
529 | if (bpp >= 8) | ||
530 | var->bits_per_pixel = 8; | ||
531 | else | ||
532 | var->bits_per_pixel = 1; | ||
533 | return 0; | ||
534 | } | ||
535 | |||
536 | static int picolcd_set_par(struct fb_info *info) | ||
537 | { | ||
538 | struct picolcd_data *data = info->par; | ||
539 | u8 *o_fb, *n_fb; | ||
540 | if (info->var.bits_per_pixel == data->fb_bpp) | ||
541 | return 0; | ||
542 | /* switch between 1/8 bit depths */ | ||
543 | if (info->var.bits_per_pixel != 1 && info->var.bits_per_pixel != 8) | ||
544 | return -EINVAL; | ||
545 | |||
546 | o_fb = data->fb_bitmap; | ||
547 | n_fb = vmalloc(PICOLCDFB_SIZE*info->var.bits_per_pixel); | ||
548 | if (!n_fb) | ||
549 | return -ENOMEM; | ||
550 | |||
551 | fb_deferred_io_cleanup(info); | ||
552 | /* translate FB content to new bits-per-pixel */ | ||
553 | if (info->var.bits_per_pixel == 1) { | ||
554 | int i, b; | ||
555 | for (i = 0; i < PICOLCDFB_SIZE; i++) { | ||
556 | u8 p = 0; | ||
557 | for (b = 0; b < 8; b++) { | ||
558 | p <<= 1; | ||
559 | p |= o_fb[i*8+b] ? 0x01 : 0x00; | ||
560 | } | ||
561 | } | ||
562 | info->fix.visual = FB_VISUAL_MONO01; | ||
563 | info->fix.line_length = PICOLCDFB_WIDTH / 8; | ||
564 | } else { | ||
565 | int i; | ||
566 | for (i = 0; i < PICOLCDFB_SIZE * 8; i++) | ||
567 | n_fb[i] = o_fb[i/8] & (0x01 << (7 - i % 8)) ? 0xff : 0x00; | ||
568 | info->fix.visual = FB_VISUAL_TRUECOLOR; | ||
569 | info->fix.line_length = PICOLCDFB_WIDTH; | ||
570 | } | ||
571 | |||
572 | data->fb_bitmap = n_fb; | ||
573 | data->fb_bpp = info->var.bits_per_pixel; | ||
574 | info->screen_base = (char __force __iomem *)n_fb; | ||
575 | info->fix.smem_start = (unsigned long)n_fb; | ||
576 | info->fix.smem_len = PICOLCDFB_SIZE*data->fb_bpp; | ||
577 | fb_deferred_io_init(info); | ||
578 | vfree(o_fb); | ||
579 | return 0; | ||
580 | } | ||
581 | |||
582 | /* Note this can't be const because of struct fb_info definition */ | ||
583 | static struct fb_ops picolcdfb_ops = { | ||
584 | .owner = THIS_MODULE, | ||
585 | .fb_destroy = picolcd_fb_destroy, | ||
586 | .fb_read = fb_sys_read, | ||
587 | .fb_write = picolcd_fb_write, | ||
588 | .fb_blank = picolcd_fb_blank, | ||
589 | .fb_fillrect = picolcd_fb_fillrect, | ||
590 | .fb_copyarea = picolcd_fb_copyarea, | ||
591 | .fb_imageblit = picolcd_fb_imageblit, | ||
592 | .fb_check_var = picolcd_fb_check_var, | ||
593 | .fb_set_par = picolcd_set_par, | ||
594 | }; | ||
595 | |||
596 | |||
597 | /* Callback from deferred IO workqueue */ | ||
598 | static void picolcd_fb_deferred_io(struct fb_info *info, struct list_head *pagelist) | ||
599 | { | ||
600 | picolcd_fb_update(info->par); | ||
601 | } | ||
602 | |||
603 | static const struct fb_deferred_io picolcd_fb_defio = { | ||
604 | .delay = HZ / PICOLCDFB_UPDATE_RATE_DEFAULT, | ||
605 | .deferred_io = picolcd_fb_deferred_io, | ||
606 | }; | ||
607 | |||
608 | |||
609 | /* | ||
610 | * The "fb_update_rate" sysfs attribute | ||
611 | */ | ||
612 | static ssize_t picolcd_fb_update_rate_show(struct device *dev, | ||
613 | struct device_attribute *attr, char *buf) | ||
614 | { | ||
615 | struct picolcd_data *data = dev_get_drvdata(dev); | ||
616 | unsigned i, fb_update_rate = data->fb_update_rate; | ||
617 | size_t ret = 0; | ||
618 | |||
619 | for (i = 1; i <= PICOLCDFB_UPDATE_RATE_LIMIT; i++) | ||
620 | if (ret >= PAGE_SIZE) | ||
621 | break; | ||
622 | else if (i == fb_update_rate) | ||
623 | ret += snprintf(buf+ret, PAGE_SIZE-ret, "[%u] ", i); | ||
624 | else | ||
625 | ret += snprintf(buf+ret, PAGE_SIZE-ret, "%u ", i); | ||
626 | if (ret > 0) | ||
627 | buf[min(ret, (size_t)PAGE_SIZE)-1] = '\n'; | ||
628 | return ret; | ||
629 | } | ||
630 | |||
631 | static ssize_t picolcd_fb_update_rate_store(struct device *dev, | ||
632 | struct device_attribute *attr, const char *buf, size_t count) | ||
633 | { | ||
634 | struct picolcd_data *data = dev_get_drvdata(dev); | ||
635 | int i; | ||
636 | unsigned u; | ||
637 | |||
638 | if (count < 1 || count > 10) | ||
639 | return -EINVAL; | ||
640 | |||
641 | i = sscanf(buf, "%u", &u); | ||
642 | if (i != 1) | ||
643 | return -EINVAL; | ||
644 | |||
645 | if (u > PICOLCDFB_UPDATE_RATE_LIMIT) | ||
646 | return -ERANGE; | ||
647 | else if (u == 0) | ||
648 | u = PICOLCDFB_UPDATE_RATE_DEFAULT; | ||
649 | |||
650 | data->fb_update_rate = u; | ||
651 | data->fb_defio.delay = HZ / data->fb_update_rate; | ||
652 | return count; | ||
653 | } | ||
654 | |||
655 | static DEVICE_ATTR(fb_update_rate, 0666, picolcd_fb_update_rate_show, | ||
656 | picolcd_fb_update_rate_store); | ||
657 | |||
658 | /* initialize Framebuffer device */ | ||
659 | static int picolcd_init_framebuffer(struct picolcd_data *data) | ||
660 | { | ||
661 | struct device *dev = &data->hdev->dev; | ||
662 | struct fb_info *info = NULL; | ||
663 | int error = -ENOMEM; | ||
664 | u8 *fb_vbitmap = NULL; | ||
665 | u8 *fb_bitmap = NULL; | ||
666 | |||
667 | fb_bitmap = vmalloc(PICOLCDFB_SIZE*picolcdfb_var.bits_per_pixel); | ||
668 | if (fb_bitmap == NULL) { | ||
669 | dev_err(dev, "can't get a free page for framebuffer\n"); | ||
670 | goto err_nomem; | ||
671 | } | ||
672 | |||
673 | fb_vbitmap = kmalloc(PICOLCDFB_SIZE, GFP_KERNEL); | ||
674 | if (fb_vbitmap == NULL) { | ||
675 | dev_err(dev, "can't alloc vbitmap image buffer\n"); | ||
676 | goto err_nomem; | ||
677 | } | ||
678 | |||
679 | data->fb_update_rate = PICOLCDFB_UPDATE_RATE_DEFAULT; | ||
680 | data->fb_defio = picolcd_fb_defio; | ||
681 | info = framebuffer_alloc(0, dev); | ||
682 | if (info == NULL) { | ||
683 | dev_err(dev, "failed to allocate a framebuffer\n"); | ||
684 | goto err_nomem; | ||
685 | } | ||
686 | |||
687 | info->fbdefio = &data->fb_defio; | ||
688 | info->screen_base = (char __force __iomem *)fb_bitmap; | ||
689 | info->fbops = &picolcdfb_ops; | ||
690 | info->var = picolcdfb_var; | ||
691 | info->fix = picolcdfb_fix; | ||
692 | info->fix.smem_len = PICOLCDFB_SIZE; | ||
693 | info->fix.smem_start = (unsigned long)fb_bitmap; | ||
694 | info->par = data; | ||
695 | info->flags = FBINFO_FLAG_DEFAULT; | ||
696 | |||
697 | data->fb_vbitmap = fb_vbitmap; | ||
698 | data->fb_bitmap = fb_bitmap; | ||
699 | data->fb_bpp = picolcdfb_var.bits_per_pixel; | ||
700 | error = picolcd_fb_reset(data, 1); | ||
701 | if (error) { | ||
702 | dev_err(dev, "failed to configure display\n"); | ||
703 | goto err_cleanup; | ||
704 | } | ||
705 | error = device_create_file(dev, &dev_attr_fb_update_rate); | ||
706 | if (error) { | ||
707 | dev_err(dev, "failed to create sysfs attributes\n"); | ||
708 | goto err_cleanup; | ||
709 | } | ||
710 | data->fb_info = info; | ||
711 | error = register_framebuffer(info); | ||
712 | if (error) { | ||
713 | dev_err(dev, "failed to register framebuffer\n"); | ||
714 | goto err_sysfs; | ||
715 | } | ||
716 | fb_deferred_io_init(info); | ||
717 | /* schedule first output of framebuffer */ | ||
718 | schedule_delayed_work(&info->deferred_work, 0); | ||
719 | return 0; | ||
720 | |||
721 | err_sysfs: | ||
722 | device_remove_file(dev, &dev_attr_fb_update_rate); | ||
723 | err_cleanup: | ||
724 | data->fb_vbitmap = NULL; | ||
725 | data->fb_bitmap = NULL; | ||
726 | data->fb_bpp = 0; | ||
727 | data->fb_info = NULL; | ||
728 | |||
729 | err_nomem: | ||
730 | framebuffer_release(info); | ||
731 | vfree(fb_bitmap); | ||
732 | kfree(fb_vbitmap); | ||
733 | return error; | ||
734 | } | ||
735 | |||
736 | static void picolcd_exit_framebuffer(struct picolcd_data *data) | ||
737 | { | ||
738 | struct fb_info *info = data->fb_info; | ||
739 | u8 *fb_vbitmap = data->fb_vbitmap; | ||
740 | u8 *fb_bitmap = data->fb_bitmap; | ||
741 | |||
742 | if (!info) | ||
743 | return; | ||
744 | |||
745 | data->fb_vbitmap = NULL; | ||
746 | data->fb_bitmap = NULL; | ||
747 | data->fb_bpp = 0; | ||
748 | data->fb_info = NULL; | ||
749 | device_remove_file(&data->hdev->dev, &dev_attr_fb_update_rate); | ||
750 | fb_deferred_io_cleanup(info); | ||
751 | unregister_framebuffer(info); | ||
752 | vfree(fb_bitmap); | ||
753 | kfree(fb_vbitmap); | ||
754 | } | ||
755 | |||
756 | #define picolcd_fbinfo(d) ((d)->fb_info) | ||
757 | #else | ||
758 | static inline int picolcd_fb_reset(struct picolcd_data *data, int clear) | ||
759 | { | ||
760 | return 0; | ||
761 | } | ||
762 | static inline int picolcd_init_framebuffer(struct picolcd_data *data) | ||
763 | { | ||
764 | return 0; | ||
765 | } | ||
766 | static inline void picolcd_exit_framebuffer(struct picolcd_data *data) | ||
767 | { | ||
768 | } | ||
769 | #define picolcd_fbinfo(d) NULL | ||
770 | #endif /* CONFIG_HID_PICOLCD_FB */ | ||
771 | |||
772 | #ifdef CONFIG_HID_PICOLCD_BACKLIGHT | ||
773 | /* | ||
774 | * backlight class device | ||
775 | */ | ||
776 | static int picolcd_get_brightness(struct backlight_device *bdev) | ||
777 | { | ||
778 | struct picolcd_data *data = bl_get_data(bdev); | ||
779 | return data->lcd_brightness; | ||
780 | } | ||
781 | |||
782 | static int picolcd_set_brightness(struct backlight_device *bdev) | ||
783 | { | ||
784 | struct picolcd_data *data = bl_get_data(bdev); | ||
785 | struct hid_report *report = picolcd_out_report(REPORT_BRIGHTNESS, data->hdev); | ||
786 | unsigned long flags; | ||
787 | |||
788 | if (!report || report->maxfield != 1 || report->field[0]->report_count != 1) | ||
789 | return -ENODEV; | ||
790 | |||
791 | data->lcd_brightness = bdev->props.brightness & 0x0ff; | ||
792 | data->lcd_power = bdev->props.power; | ||
793 | spin_lock_irqsave(&data->lock, flags); | ||
794 | hid_set_field(report->field[0], 0, data->lcd_power == FB_BLANK_UNBLANK ? data->lcd_brightness : 0); | ||
795 | usbhid_submit_report(data->hdev, report, USB_DIR_OUT); | ||
796 | spin_unlock_irqrestore(&data->lock, flags); | ||
797 | return 0; | ||
798 | } | ||
799 | |||
800 | static int picolcd_check_bl_fb(struct backlight_device *bdev, struct fb_info *fb) | ||
801 | { | ||
802 | return fb && fb == picolcd_fbinfo((struct picolcd_data *)bl_get_data(bdev)); | ||
803 | } | ||
804 | |||
805 | static const struct backlight_ops picolcd_blops = { | ||
806 | .update_status = picolcd_set_brightness, | ||
807 | .get_brightness = picolcd_get_brightness, | ||
808 | .check_fb = picolcd_check_bl_fb, | ||
809 | }; | ||
810 | |||
811 | static int picolcd_init_backlight(struct picolcd_data *data, struct hid_report *report) | ||
812 | { | ||
813 | struct device *dev = &data->hdev->dev; | ||
814 | struct backlight_device *bdev; | ||
815 | struct backlight_properties props; | ||
816 | if (!report) | ||
817 | return -ENODEV; | ||
818 | if (report->maxfield != 1 || report->field[0]->report_count != 1 || | ||
819 | report->field[0]->report_size != 8) { | ||
820 | dev_err(dev, "unsupported BRIGHTNESS report"); | ||
821 | return -EINVAL; | ||
822 | } | ||
823 | |||
824 | memset(&props, 0, sizeof(props)); | ||
825 | props.max_brightness = 0xff; | ||
826 | bdev = backlight_device_register(dev_name(dev), dev, data, | ||
827 | &picolcd_blops, &props); | ||
828 | if (IS_ERR(bdev)) { | ||
829 | dev_err(dev, "failed to register backlight\n"); | ||
830 | return PTR_ERR(bdev); | ||
831 | } | ||
832 | bdev->props.brightness = 0xff; | ||
833 | data->lcd_brightness = 0xff; | ||
834 | data->backlight = bdev; | ||
835 | picolcd_set_brightness(bdev); | ||
836 | return 0; | ||
837 | } | ||
838 | |||
839 | static void picolcd_exit_backlight(struct picolcd_data *data) | ||
840 | { | ||
841 | struct backlight_device *bdev = data->backlight; | ||
842 | |||
843 | data->backlight = NULL; | ||
844 | if (bdev) | ||
845 | backlight_device_unregister(bdev); | ||
846 | } | ||
847 | |||
848 | static inline int picolcd_resume_backlight(struct picolcd_data *data) | ||
849 | { | ||
850 | if (!data->backlight) | ||
851 | return 0; | ||
852 | return picolcd_set_brightness(data->backlight); | ||
853 | } | ||
854 | |||
855 | #ifdef CONFIG_PM | ||
856 | static void picolcd_suspend_backlight(struct picolcd_data *data) | ||
857 | { | ||
858 | int bl_power = data->lcd_power; | ||
859 | if (!data->backlight) | ||
860 | return; | ||
861 | |||
862 | data->backlight->props.power = FB_BLANK_POWERDOWN; | ||
863 | picolcd_set_brightness(data->backlight); | ||
864 | data->lcd_power = data->backlight->props.power = bl_power; | ||
865 | } | ||
866 | #endif /* CONFIG_PM */ | ||
867 | #else | ||
868 | static inline int picolcd_init_backlight(struct picolcd_data *data, | ||
869 | struct hid_report *report) | ||
870 | { | ||
871 | return 0; | ||
872 | } | ||
873 | static inline void picolcd_exit_backlight(struct picolcd_data *data) | ||
874 | { | ||
875 | } | ||
876 | static inline int picolcd_resume_backlight(struct picolcd_data *data) | ||
877 | { | ||
878 | return 0; | ||
879 | } | ||
880 | static inline void picolcd_suspend_backlight(struct picolcd_data *data) | ||
881 | { | ||
882 | } | ||
883 | #endif /* CONFIG_HID_PICOLCD_BACKLIGHT */ | ||
884 | |||
885 | #ifdef CONFIG_HID_PICOLCD_LCD | ||
886 | /* | ||
887 | * lcd class device | ||
888 | */ | ||
889 | static int picolcd_get_contrast(struct lcd_device *ldev) | ||
890 | { | ||
891 | struct picolcd_data *data = lcd_get_data(ldev); | ||
892 | return data->lcd_contrast; | ||
893 | } | ||
894 | |||
895 | static int picolcd_set_contrast(struct lcd_device *ldev, int contrast) | ||
896 | { | ||
897 | struct picolcd_data *data = lcd_get_data(ldev); | ||
898 | struct hid_report *report = picolcd_out_report(REPORT_CONTRAST, data->hdev); | ||
899 | unsigned long flags; | ||
900 | |||
901 | if (!report || report->maxfield != 1 || report->field[0]->report_count != 1) | ||
902 | return -ENODEV; | ||
903 | |||
904 | data->lcd_contrast = contrast & 0x0ff; | ||
905 | spin_lock_irqsave(&data->lock, flags); | ||
906 | hid_set_field(report->field[0], 0, data->lcd_contrast); | ||
907 | usbhid_submit_report(data->hdev, report, USB_DIR_OUT); | ||
908 | spin_unlock_irqrestore(&data->lock, flags); | ||
909 | return 0; | ||
910 | } | ||
911 | |||
912 | static int picolcd_check_lcd_fb(struct lcd_device *ldev, struct fb_info *fb) | ||
913 | { | ||
914 | return fb && fb == picolcd_fbinfo((struct picolcd_data *)lcd_get_data(ldev)); | ||
915 | } | ||
916 | |||
917 | static struct lcd_ops picolcd_lcdops = { | ||
918 | .get_contrast = picolcd_get_contrast, | ||
919 | .set_contrast = picolcd_set_contrast, | ||
920 | .check_fb = picolcd_check_lcd_fb, | ||
921 | }; | ||
922 | |||
923 | static int picolcd_init_lcd(struct picolcd_data *data, struct hid_report *report) | ||
924 | { | ||
925 | struct device *dev = &data->hdev->dev; | ||
926 | struct lcd_device *ldev; | ||
927 | |||
928 | if (!report) | ||
929 | return -ENODEV; | ||
930 | if (report->maxfield != 1 || report->field[0]->report_count != 1 || | ||
931 | report->field[0]->report_size != 8) { | ||
932 | dev_err(dev, "unsupported CONTRAST report"); | ||
933 | return -EINVAL; | ||
934 | } | ||
935 | |||
936 | ldev = lcd_device_register(dev_name(dev), dev, data, &picolcd_lcdops); | ||
937 | if (IS_ERR(ldev)) { | ||
938 | dev_err(dev, "failed to register LCD\n"); | ||
939 | return PTR_ERR(ldev); | ||
940 | } | ||
941 | ldev->props.max_contrast = 0x0ff; | ||
942 | data->lcd_contrast = 0xe5; | ||
943 | data->lcd = ldev; | ||
944 | picolcd_set_contrast(ldev, 0xe5); | ||
945 | return 0; | ||
946 | } | ||
947 | |||
948 | static void picolcd_exit_lcd(struct picolcd_data *data) | ||
949 | { | ||
950 | struct lcd_device *ldev = data->lcd; | ||
951 | |||
952 | data->lcd = NULL; | ||
953 | if (ldev) | ||
954 | lcd_device_unregister(ldev); | ||
955 | } | ||
956 | |||
957 | static inline int picolcd_resume_lcd(struct picolcd_data *data) | ||
958 | { | ||
959 | if (!data->lcd) | ||
960 | return 0; | ||
961 | return picolcd_set_contrast(data->lcd, data->lcd_contrast); | ||
962 | } | ||
963 | #else | ||
964 | static inline int picolcd_init_lcd(struct picolcd_data *data, | ||
965 | struct hid_report *report) | ||
966 | { | ||
967 | return 0; | ||
968 | } | ||
969 | static inline void picolcd_exit_lcd(struct picolcd_data *data) | ||
970 | { | ||
971 | } | ||
972 | static inline int picolcd_resume_lcd(struct picolcd_data *data) | ||
973 | { | ||
974 | return 0; | ||
975 | } | ||
976 | #endif /* CONFIG_HID_PICOLCD_LCD */ | ||
977 | |||
978 | #ifdef CONFIG_HID_PICOLCD_LEDS | ||
979 | /** | ||
980 | * LED class device | ||
981 | */ | ||
982 | static void picolcd_leds_set(struct picolcd_data *data) | ||
983 | { | ||
984 | struct hid_report *report; | ||
985 | unsigned long flags; | ||
986 | |||
987 | if (!data->led[0]) | ||
988 | return; | ||
989 | report = picolcd_out_report(REPORT_LED_STATE, data->hdev); | ||
990 | if (!report || report->maxfield != 1 || report->field[0]->report_count != 1) | ||
991 | return; | ||
992 | |||
993 | spin_lock_irqsave(&data->lock, flags); | ||
994 | hid_set_field(report->field[0], 0, data->led_state); | ||
995 | usbhid_submit_report(data->hdev, report, USB_DIR_OUT); | ||
996 | spin_unlock_irqrestore(&data->lock, flags); | ||
997 | } | ||
998 | |||
999 | static void picolcd_led_set_brightness(struct led_classdev *led_cdev, | ||
1000 | enum led_brightness value) | ||
1001 | { | ||
1002 | struct device *dev; | ||
1003 | struct hid_device *hdev; | ||
1004 | struct picolcd_data *data; | ||
1005 | int i, state = 0; | ||
1006 | |||
1007 | dev = led_cdev->dev->parent; | ||
1008 | hdev = container_of(dev, struct hid_device, dev); | ||
1009 | data = hid_get_drvdata(hdev); | ||
1010 | for (i = 0; i < 8; i++) { | ||
1011 | if (led_cdev != data->led[i]) | ||
1012 | continue; | ||
1013 | state = (data->led_state >> i) & 1; | ||
1014 | if (value == LED_OFF && state) { | ||
1015 | data->led_state &= ~(1 << i); | ||
1016 | picolcd_leds_set(data); | ||
1017 | } else if (value != LED_OFF && !state) { | ||
1018 | data->led_state |= 1 << i; | ||
1019 | picolcd_leds_set(data); | ||
1020 | } | ||
1021 | break; | ||
1022 | } | ||
1023 | } | ||
1024 | |||
1025 | static enum led_brightness picolcd_led_get_brightness(struct led_classdev *led_cdev) | ||
1026 | { | ||
1027 | struct device *dev; | ||
1028 | struct hid_device *hdev; | ||
1029 | struct picolcd_data *data; | ||
1030 | int i, value = 0; | ||
1031 | |||
1032 | dev = led_cdev->dev->parent; | ||
1033 | hdev = container_of(dev, struct hid_device, dev); | ||
1034 | data = hid_get_drvdata(hdev); | ||
1035 | for (i = 0; i < 8; i++) | ||
1036 | if (led_cdev == data->led[i]) { | ||
1037 | value = (data->led_state >> i) & 1; | ||
1038 | break; | ||
1039 | } | ||
1040 | return value ? LED_FULL : LED_OFF; | ||
1041 | } | ||
1042 | |||
1043 | static int picolcd_init_leds(struct picolcd_data *data, struct hid_report *report) | ||
1044 | { | ||
1045 | struct device *dev = &data->hdev->dev; | ||
1046 | struct led_classdev *led; | ||
1047 | size_t name_sz = strlen(dev_name(dev)) + 8; | ||
1048 | char *name; | ||
1049 | int i, ret = 0; | ||
1050 | |||
1051 | if (!report) | ||
1052 | return -ENODEV; | ||
1053 | if (report->maxfield != 1 || report->field[0]->report_count != 1 || | ||
1054 | report->field[0]->report_size != 8) { | ||
1055 | dev_err(dev, "unsupported LED_STATE report"); | ||
1056 | return -EINVAL; | ||
1057 | } | ||
1058 | |||
1059 | for (i = 0; i < 8; i++) { | ||
1060 | led = kzalloc(sizeof(struct led_classdev)+name_sz, GFP_KERNEL); | ||
1061 | if (!led) { | ||
1062 | dev_err(dev, "can't allocate memory for LED %d\n", i); | ||
1063 | ret = -ENOMEM; | ||
1064 | goto err; | ||
1065 | } | ||
1066 | name = (void *)(&led[1]); | ||
1067 | snprintf(name, name_sz, "%s::GPO%d", dev_name(dev), i); | ||
1068 | led->name = name; | ||
1069 | led->brightness = 0; | ||
1070 | led->max_brightness = 1; | ||
1071 | led->brightness_get = picolcd_led_get_brightness; | ||
1072 | led->brightness_set = picolcd_led_set_brightness; | ||
1073 | |||
1074 | data->led[i] = led; | ||
1075 | ret = led_classdev_register(dev, data->led[i]); | ||
1076 | if (ret) { | ||
1077 | data->led[i] = NULL; | ||
1078 | kfree(led); | ||
1079 | dev_err(dev, "can't register LED %d\n", i); | ||
1080 | goto err; | ||
1081 | } | ||
1082 | } | ||
1083 | return 0; | ||
1084 | err: | ||
1085 | for (i = 0; i < 8; i++) | ||
1086 | if (data->led[i]) { | ||
1087 | led = data->led[i]; | ||
1088 | data->led[i] = NULL; | ||
1089 | led_classdev_unregister(led); | ||
1090 | kfree(led); | ||
1091 | } | ||
1092 | return ret; | ||
1093 | } | ||
1094 | |||
1095 | static void picolcd_exit_leds(struct picolcd_data *data) | ||
1096 | { | ||
1097 | struct led_classdev *led; | ||
1098 | int i; | ||
1099 | |||
1100 | for (i = 0; i < 8; i++) { | ||
1101 | led = data->led[i]; | ||
1102 | data->led[i] = NULL; | ||
1103 | if (!led) | ||
1104 | continue; | ||
1105 | led_classdev_unregister(led); | ||
1106 | kfree(led); | ||
1107 | } | ||
1108 | } | ||
1109 | |||
1110 | #else | ||
1111 | static inline int picolcd_init_leds(struct picolcd_data *data, | ||
1112 | struct hid_report *report) | ||
1113 | { | ||
1114 | return 0; | ||
1115 | } | ||
1116 | static inline void picolcd_exit_leds(struct picolcd_data *data) | ||
1117 | { | ||
1118 | } | ||
1119 | static inline int picolcd_leds_set(struct picolcd_data *data) | ||
1120 | { | ||
1121 | return 0; | ||
1122 | } | ||
1123 | #endif /* CONFIG_HID_PICOLCD_LEDS */ | ||
1124 | |||
1125 | /* | ||
1126 | * input class device | ||
1127 | */ | ||
1128 | static int picolcd_raw_keypad(struct picolcd_data *data, | ||
1129 | struct hid_report *report, u8 *raw_data, int size) | ||
1130 | { | ||
1131 | /* | ||
1132 | * Keypad event | ||
1133 | * First and second data bytes list currently pressed keys, | ||
1134 | * 0x00 means no key and at most 2 keys may be pressed at same time | ||
1135 | */ | ||
1136 | int i, j; | ||
1137 | |||
1138 | /* determine newly pressed keys */ | ||
1139 | for (i = 0; i < size; i++) { | ||
1140 | unsigned int key_code; | ||
1141 | if (raw_data[i] == 0) | ||
1142 | continue; | ||
1143 | for (j = 0; j < sizeof(data->pressed_keys); j++) | ||
1144 | if (data->pressed_keys[j] == raw_data[i]) | ||
1145 | goto key_already_down; | ||
1146 | for (j = 0; j < sizeof(data->pressed_keys); j++) | ||
1147 | if (data->pressed_keys[j] == 0) { | ||
1148 | data->pressed_keys[j] = raw_data[i]; | ||
1149 | break; | ||
1150 | } | ||
1151 | input_event(data->input_keys, EV_MSC, MSC_SCAN, raw_data[i]); | ||
1152 | if (raw_data[i] < PICOLCD_KEYS) | ||
1153 | key_code = data->keycode[raw_data[i]]; | ||
1154 | else | ||
1155 | key_code = KEY_UNKNOWN; | ||
1156 | if (key_code != KEY_UNKNOWN) { | ||
1157 | dbg_hid(PICOLCD_NAME " got key press for %u:%d", | ||
1158 | raw_data[i], key_code); | ||
1159 | input_report_key(data->input_keys, key_code, 1); | ||
1160 | } | ||
1161 | input_sync(data->input_keys); | ||
1162 | key_already_down: | ||
1163 | continue; | ||
1164 | } | ||
1165 | |||
1166 | /* determine newly released keys */ | ||
1167 | for (j = 0; j < sizeof(data->pressed_keys); j++) { | ||
1168 | unsigned int key_code; | ||
1169 | if (data->pressed_keys[j] == 0) | ||
1170 | continue; | ||
1171 | for (i = 0; i < size; i++) | ||
1172 | if (data->pressed_keys[j] == raw_data[i]) | ||
1173 | goto key_still_down; | ||
1174 | input_event(data->input_keys, EV_MSC, MSC_SCAN, data->pressed_keys[j]); | ||
1175 | if (data->pressed_keys[j] < PICOLCD_KEYS) | ||
1176 | key_code = data->keycode[data->pressed_keys[j]]; | ||
1177 | else | ||
1178 | key_code = KEY_UNKNOWN; | ||
1179 | if (key_code != KEY_UNKNOWN) { | ||
1180 | dbg_hid(PICOLCD_NAME " got key release for %u:%d", | ||
1181 | data->pressed_keys[j], key_code); | ||
1182 | input_report_key(data->input_keys, key_code, 0); | ||
1183 | } | ||
1184 | input_sync(data->input_keys); | ||
1185 | data->pressed_keys[j] = 0; | ||
1186 | key_still_down: | ||
1187 | continue; | ||
1188 | } | ||
1189 | return 1; | ||
1190 | } | ||
1191 | |||
1192 | static int picolcd_raw_cir(struct picolcd_data *data, | ||
1193 | struct hid_report *report, u8 *raw_data, int size) | ||
1194 | { | ||
1195 | /* Need understanding of CIR data format to implement ... */ | ||
1196 | return 1; | ||
1197 | } | ||
1198 | |||
1199 | static int picolcd_check_version(struct hid_device *hdev) | ||
1200 | { | ||
1201 | struct picolcd_data *data = hid_get_drvdata(hdev); | ||
1202 | struct picolcd_pending *verinfo; | ||
1203 | int ret = 0; | ||
1204 | |||
1205 | if (!data) | ||
1206 | return -ENODEV; | ||
1207 | |||
1208 | verinfo = picolcd_send_and_wait(hdev, REPORT_VERSION, NULL, 0); | ||
1209 | if (!verinfo) { | ||
1210 | dev_err(&hdev->dev, "no version response from PicoLCD"); | ||
1211 | return -ENODEV; | ||
1212 | } | ||
1213 | |||
1214 | if (verinfo->raw_size == 2) { | ||
1215 | data->version[0] = verinfo->raw_data[1]; | ||
1216 | data->version[1] = verinfo->raw_data[0]; | ||
1217 | if (data->status & PICOLCD_BOOTLOADER) { | ||
1218 | dev_info(&hdev->dev, "PicoLCD, bootloader version %d.%d\n", | ||
1219 | verinfo->raw_data[1], verinfo->raw_data[0]); | ||
1220 | } else { | ||
1221 | dev_info(&hdev->dev, "PicoLCD, firmware version %d.%d\n", | ||
1222 | verinfo->raw_data[1], verinfo->raw_data[0]); | ||
1223 | } | ||
1224 | } else { | ||
1225 | dev_err(&hdev->dev, "confused, got unexpected version response from PicoLCD\n"); | ||
1226 | ret = -EINVAL; | ||
1227 | } | ||
1228 | kfree(verinfo); | ||
1229 | return ret; | ||
1230 | } | ||
1231 | |||
1232 | /* | ||
1233 | * Reset our device and wait for answer to VERSION request | ||
1234 | */ | ||
1235 | static int picolcd_reset(struct hid_device *hdev) | ||
1236 | { | ||
1237 | struct picolcd_data *data = hid_get_drvdata(hdev); | ||
1238 | struct hid_report *report = picolcd_out_report(REPORT_RESET, hdev); | ||
1239 | unsigned long flags; | ||
1240 | int error; | ||
1241 | |||
1242 | if (!data || !report || report->maxfield != 1) | ||
1243 | return -ENODEV; | ||
1244 | |||
1245 | spin_lock_irqsave(&data->lock, flags); | ||
1246 | if (hdev->product == USB_DEVICE_ID_PICOLCD_BOOTLOADER) | ||
1247 | data->status |= PICOLCD_BOOTLOADER; | ||
1248 | |||
1249 | /* perform the reset */ | ||
1250 | hid_set_field(report->field[0], 0, 1); | ||
1251 | usbhid_submit_report(hdev, report, USB_DIR_OUT); | ||
1252 | spin_unlock_irqrestore(&data->lock, flags); | ||
1253 | |||
1254 | error = picolcd_check_version(hdev); | ||
1255 | if (error) | ||
1256 | return error; | ||
1257 | |||
1258 | picolcd_resume_lcd(data); | ||
1259 | picolcd_resume_backlight(data); | ||
1260 | #ifdef CONFIG_HID_PICOLCD_FB | ||
1261 | if (data->fb_info) | ||
1262 | schedule_delayed_work(&data->fb_info->deferred_work, 0); | ||
1263 | #endif /* CONFIG_HID_PICOLCD_FB */ | ||
1264 | |||
1265 | picolcd_leds_set(data); | ||
1266 | return 0; | ||
1267 | } | ||
1268 | |||
1269 | /* | ||
1270 | * The "operation_mode" sysfs attribute | ||
1271 | */ | ||
1272 | static ssize_t picolcd_operation_mode_show(struct device *dev, | ||
1273 | struct device_attribute *attr, char *buf) | ||
1274 | { | ||
1275 | struct picolcd_data *data = dev_get_drvdata(dev); | ||
1276 | |||
1277 | if (data->status & PICOLCD_BOOTLOADER) | ||
1278 | return snprintf(buf, PAGE_SIZE, "[bootloader] lcd\n"); | ||
1279 | else | ||
1280 | return snprintf(buf, PAGE_SIZE, "bootloader [lcd]\n"); | ||
1281 | } | ||
1282 | |||
1283 | static ssize_t picolcd_operation_mode_store(struct device *dev, | ||
1284 | struct device_attribute *attr, const char *buf, size_t count) | ||
1285 | { | ||
1286 | struct picolcd_data *data = dev_get_drvdata(dev); | ||
1287 | struct hid_report *report = NULL; | ||
1288 | size_t cnt = count; | ||
1289 | int timeout = data->opmode_delay; | ||
1290 | unsigned long flags; | ||
1291 | |||
1292 | if (cnt >= 3 && strncmp("lcd", buf, 3) == 0) { | ||
1293 | if (data->status & PICOLCD_BOOTLOADER) | ||
1294 | report = picolcd_out_report(REPORT_EXIT_FLASHER, data->hdev); | ||
1295 | buf += 3; | ||
1296 | cnt -= 3; | ||
1297 | } else if (cnt >= 10 && strncmp("bootloader", buf, 10) == 0) { | ||
1298 | if (!(data->status & PICOLCD_BOOTLOADER)) | ||
1299 | report = picolcd_out_report(REPORT_EXIT_KEYBOARD, data->hdev); | ||
1300 | buf += 10; | ||
1301 | cnt -= 10; | ||
1302 | } | ||
1303 | if (!report) | ||
1304 | return -EINVAL; | ||
1305 | |||
1306 | while (cnt > 0 && (buf[cnt-1] == '\n' || buf[cnt-1] == '\r')) | ||
1307 | cnt--; | ||
1308 | if (cnt != 0) | ||
1309 | return -EINVAL; | ||
1310 | |||
1311 | spin_lock_irqsave(&data->lock, flags); | ||
1312 | hid_set_field(report->field[0], 0, timeout & 0xff); | ||
1313 | hid_set_field(report->field[0], 1, (timeout >> 8) & 0xff); | ||
1314 | usbhid_submit_report(data->hdev, report, USB_DIR_OUT); | ||
1315 | spin_unlock_irqrestore(&data->lock, flags); | ||
1316 | return count; | ||
1317 | } | ||
1318 | |||
1319 | static DEVICE_ATTR(operation_mode, 0644, picolcd_operation_mode_show, | ||
1320 | picolcd_operation_mode_store); | ||
1321 | |||
1322 | /* | ||
1323 | * The "operation_mode_delay" sysfs attribute | ||
1324 | */ | ||
1325 | static ssize_t picolcd_operation_mode_delay_show(struct device *dev, | ||
1326 | struct device_attribute *attr, char *buf) | ||
1327 | { | ||
1328 | struct picolcd_data *data = dev_get_drvdata(dev); | ||
1329 | |||
1330 | return snprintf(buf, PAGE_SIZE, "%hu\n", data->opmode_delay); | ||
1331 | } | ||
1332 | |||
1333 | static ssize_t picolcd_operation_mode_delay_store(struct device *dev, | ||
1334 | struct device_attribute *attr, const char *buf, size_t count) | ||
1335 | { | ||
1336 | struct picolcd_data *data = dev_get_drvdata(dev); | ||
1337 | unsigned u; | ||
1338 | if (sscanf(buf, "%u", &u) != 1) | ||
1339 | return -EINVAL; | ||
1340 | if (u > 30000) | ||
1341 | return -EINVAL; | ||
1342 | else | ||
1343 | data->opmode_delay = u; | ||
1344 | return count; | ||
1345 | } | ||
1346 | |||
1347 | static DEVICE_ATTR(operation_mode_delay, 0644, picolcd_operation_mode_delay_show, | ||
1348 | picolcd_operation_mode_delay_store); | ||
1349 | |||
1350 | |||
1351 | #ifdef CONFIG_DEBUG_FS | ||
1352 | /* | ||
1353 | * The "reset" file | ||
1354 | */ | ||
1355 | static int picolcd_debug_reset_show(struct seq_file *f, void *p) | ||
1356 | { | ||
1357 | if (picolcd_fbinfo((struct picolcd_data *)f->private)) | ||
1358 | seq_printf(f, "all fb\n"); | ||
1359 | else | ||
1360 | seq_printf(f, "all\n"); | ||
1361 | return 0; | ||
1362 | } | ||
1363 | |||
1364 | static int picolcd_debug_reset_open(struct inode *inode, struct file *f) | ||
1365 | { | ||
1366 | return single_open(f, picolcd_debug_reset_show, inode->i_private); | ||
1367 | } | ||
1368 | |||
1369 | static ssize_t picolcd_debug_reset_write(struct file *f, const char __user *user_buf, | ||
1370 | size_t count, loff_t *ppos) | ||
1371 | { | ||
1372 | struct picolcd_data *data = ((struct seq_file *)f->private_data)->private; | ||
1373 | char buf[32]; | ||
1374 | size_t cnt = min(count, sizeof(buf)-1); | ||
1375 | if (copy_from_user(buf, user_buf, cnt)) | ||
1376 | return -EFAULT; | ||
1377 | |||
1378 | while (cnt > 0 && (buf[cnt-1] == ' ' || buf[cnt-1] == '\n')) | ||
1379 | cnt--; | ||
1380 | buf[cnt] = '\0'; | ||
1381 | if (strcmp(buf, "all") == 0) { | ||
1382 | picolcd_reset(data->hdev); | ||
1383 | picolcd_fb_reset(data, 1); | ||
1384 | } else if (strcmp(buf, "fb") == 0) { | ||
1385 | picolcd_fb_reset(data, 1); | ||
1386 | } else { | ||
1387 | return -EINVAL; | ||
1388 | } | ||
1389 | return count; | ||
1390 | } | ||
1391 | |||
1392 | static const struct file_operations picolcd_debug_reset_fops = { | ||
1393 | .owner = THIS_MODULE, | ||
1394 | .open = picolcd_debug_reset_open, | ||
1395 | .read = seq_read, | ||
1396 | .llseek = seq_lseek, | ||
1397 | .write = picolcd_debug_reset_write, | ||
1398 | .release = single_release, | ||
1399 | }; | ||
1400 | |||
1401 | /* | ||
1402 | * The "eeprom" file | ||
1403 | */ | ||
1404 | static int picolcd_debug_eeprom_open(struct inode *i, struct file *f) | ||
1405 | { | ||
1406 | f->private_data = i->i_private; | ||
1407 | return 0; | ||
1408 | } | ||
1409 | |||
1410 | static ssize_t picolcd_debug_eeprom_read(struct file *f, char __user *u, | ||
1411 | size_t s, loff_t *off) | ||
1412 | { | ||
1413 | struct picolcd_data *data = f->private_data; | ||
1414 | struct picolcd_pending *resp; | ||
1415 | u8 raw_data[3]; | ||
1416 | ssize_t ret = -EIO; | ||
1417 | |||
1418 | if (s == 0) | ||
1419 | return -EINVAL; | ||
1420 | if (*off > 0x0ff) | ||
1421 | return 0; | ||
1422 | |||
1423 | /* prepare buffer with info about what we want to read (addr & len) */ | ||
1424 | raw_data[0] = *off & 0xff; | ||
1425 | raw_data[1] = (*off >> 8) && 0xff; | ||
1426 | raw_data[2] = s < 20 ? s : 20; | ||
1427 | if (*off + raw_data[2] > 0xff) | ||
1428 | raw_data[2] = 0x100 - *off; | ||
1429 | resp = picolcd_send_and_wait(data->hdev, REPORT_EE_READ, raw_data, | ||
1430 | sizeof(raw_data)); | ||
1431 | if (!resp) | ||
1432 | return -EIO; | ||
1433 | |||
1434 | if (resp->in_report && resp->in_report->id == REPORT_EE_DATA) { | ||
1435 | /* successful read :) */ | ||
1436 | ret = resp->raw_data[2]; | ||
1437 | if (ret > s) | ||
1438 | ret = s; | ||
1439 | if (copy_to_user(u, resp->raw_data+3, ret)) | ||
1440 | ret = -EFAULT; | ||
1441 | else | ||
1442 | *off += ret; | ||
1443 | } /* anything else is some kind of IO error */ | ||
1444 | |||
1445 | kfree(resp); | ||
1446 | return ret; | ||
1447 | } | ||
1448 | |||
1449 | static ssize_t picolcd_debug_eeprom_write(struct file *f, const char __user *u, | ||
1450 | size_t s, loff_t *off) | ||
1451 | { | ||
1452 | struct picolcd_data *data = f->private_data; | ||
1453 | struct picolcd_pending *resp; | ||
1454 | ssize_t ret = -EIO; | ||
1455 | u8 raw_data[23]; | ||
1456 | |||
1457 | if (s == 0) | ||
1458 | return -EINVAL; | ||
1459 | if (*off > 0x0ff) | ||
1460 | return -ENOSPC; | ||
1461 | |||
1462 | memset(raw_data, 0, sizeof(raw_data)); | ||
1463 | raw_data[0] = *off & 0xff; | ||
1464 | raw_data[1] = (*off >> 8) && 0xff; | ||
1465 | raw_data[2] = s < 20 ? s : 20; | ||
1466 | if (*off + raw_data[2] > 0xff) | ||
1467 | raw_data[2] = 0x100 - *off; | ||
1468 | |||
1469 | if (copy_from_user(raw_data+3, u, raw_data[2])) | ||
1470 | return -EFAULT; | ||
1471 | resp = picolcd_send_and_wait(data->hdev, REPORT_EE_WRITE, raw_data, | ||
1472 | sizeof(raw_data)); | ||
1473 | |||
1474 | if (!resp) | ||
1475 | return -EIO; | ||
1476 | |||
1477 | if (resp->in_report && resp->in_report->id == REPORT_EE_DATA) { | ||
1478 | /* check if written data matches */ | ||
1479 | if (memcmp(raw_data, resp->raw_data, 3+raw_data[2]) == 0) { | ||
1480 | *off += raw_data[2]; | ||
1481 | ret = raw_data[2]; | ||
1482 | } | ||
1483 | } | ||
1484 | kfree(resp); | ||
1485 | return ret; | ||
1486 | } | ||
1487 | |||
1488 | /* | ||
1489 | * Notes: | ||
1490 | * - read/write happens in chunks of at most 20 bytes, it's up to userspace | ||
1491 | * to loop in order to get more data. | ||
1492 | * - on write errors on otherwise correct write request the bytes | ||
1493 | * that should have been written are in undefined state. | ||
1494 | */ | ||
1495 | static const struct file_operations picolcd_debug_eeprom_fops = { | ||
1496 | .owner = THIS_MODULE, | ||
1497 | .open = picolcd_debug_eeprom_open, | ||
1498 | .read = picolcd_debug_eeprom_read, | ||
1499 | .write = picolcd_debug_eeprom_write, | ||
1500 | .llseek = generic_file_llseek, | ||
1501 | }; | ||
1502 | |||
1503 | /* | ||
1504 | * The "flash" file | ||
1505 | */ | ||
1506 | static int picolcd_debug_flash_open(struct inode *i, struct file *f) | ||
1507 | { | ||
1508 | f->private_data = i->i_private; | ||
1509 | return 0; | ||
1510 | } | ||
1511 | |||
1512 | /* record a flash address to buf (bounds check to be done by caller) */ | ||
1513 | static int _picolcd_flash_setaddr(struct picolcd_data *data, u8 *buf, long off) | ||
1514 | { | ||
1515 | buf[0] = off & 0xff; | ||
1516 | buf[1] = (off >> 8) & 0xff; | ||
1517 | if (data->addr_sz == 3) | ||
1518 | buf[2] = (off >> 16) & 0xff; | ||
1519 | return data->addr_sz == 2 ? 2 : 3; | ||
1520 | } | ||
1521 | |||
1522 | /* read a given size of data (bounds check to be done by caller) */ | ||
1523 | static ssize_t _picolcd_flash_read(struct picolcd_data *data, int report_id, | ||
1524 | char __user *u, size_t s, loff_t *off) | ||
1525 | { | ||
1526 | struct picolcd_pending *resp; | ||
1527 | u8 raw_data[4]; | ||
1528 | ssize_t ret = 0; | ||
1529 | int len_off, err = -EIO; | ||
1530 | |||
1531 | while (s > 0) { | ||
1532 | err = -EIO; | ||
1533 | len_off = _picolcd_flash_setaddr(data, raw_data, *off); | ||
1534 | raw_data[len_off] = s > 32 ? 32 : s; | ||
1535 | resp = picolcd_send_and_wait(data->hdev, report_id, raw_data, len_off+1); | ||
1536 | if (!resp || !resp->in_report) | ||
1537 | goto skip; | ||
1538 | if (resp->in_report->id == REPORT_MEMORY || | ||
1539 | resp->in_report->id == REPORT_BL_READ_MEMORY) { | ||
1540 | if (memcmp(raw_data, resp->raw_data, len_off+1) != 0) | ||
1541 | goto skip; | ||
1542 | if (copy_to_user(u+ret, resp->raw_data+len_off+1, raw_data[len_off])) { | ||
1543 | err = -EFAULT; | ||
1544 | goto skip; | ||
1545 | } | ||
1546 | *off += raw_data[len_off]; | ||
1547 | s -= raw_data[len_off]; | ||
1548 | ret += raw_data[len_off]; | ||
1549 | err = 0; | ||
1550 | } | ||
1551 | skip: | ||
1552 | kfree(resp); | ||
1553 | if (err) | ||
1554 | return ret > 0 ? ret : err; | ||
1555 | } | ||
1556 | return ret; | ||
1557 | } | ||
1558 | |||
1559 | static ssize_t picolcd_debug_flash_read(struct file *f, char __user *u, | ||
1560 | size_t s, loff_t *off) | ||
1561 | { | ||
1562 | struct picolcd_data *data = f->private_data; | ||
1563 | |||
1564 | if (s == 0) | ||
1565 | return -EINVAL; | ||
1566 | if (*off > 0x05fff) | ||
1567 | return 0; | ||
1568 | if (*off + s > 0x05fff) | ||
1569 | s = 0x06000 - *off; | ||
1570 | |||
1571 | if (data->status & PICOLCD_BOOTLOADER) | ||
1572 | return _picolcd_flash_read(data, REPORT_BL_READ_MEMORY, u, s, off); | ||
1573 | else | ||
1574 | return _picolcd_flash_read(data, REPORT_READ_MEMORY, u, s, off); | ||
1575 | } | ||
1576 | |||
1577 | /* erase block aligned to 64bytes boundary */ | ||
1578 | static ssize_t _picolcd_flash_erase64(struct picolcd_data *data, int report_id, | ||
1579 | loff_t *off) | ||
1580 | { | ||
1581 | struct picolcd_pending *resp; | ||
1582 | u8 raw_data[3]; | ||
1583 | int len_off; | ||
1584 | ssize_t ret = -EIO; | ||
1585 | |||
1586 | if (*off & 0x3f) | ||
1587 | return -EINVAL; | ||
1588 | |||
1589 | len_off = _picolcd_flash_setaddr(data, raw_data, *off); | ||
1590 | resp = picolcd_send_and_wait(data->hdev, report_id, raw_data, len_off); | ||
1591 | if (!resp || !resp->in_report) | ||
1592 | goto skip; | ||
1593 | if (resp->in_report->id == REPORT_MEMORY || | ||
1594 | resp->in_report->id == REPORT_BL_ERASE_MEMORY) { | ||
1595 | if (memcmp(raw_data, resp->raw_data, len_off) != 0) | ||
1596 | goto skip; | ||
1597 | ret = 0; | ||
1598 | } | ||
1599 | skip: | ||
1600 | kfree(resp); | ||
1601 | return ret; | ||
1602 | } | ||
1603 | |||
1604 | /* write a given size of data (bounds check to be done by caller) */ | ||
1605 | static ssize_t _picolcd_flash_write(struct picolcd_data *data, int report_id, | ||
1606 | const char __user *u, size_t s, loff_t *off) | ||
1607 | { | ||
1608 | struct picolcd_pending *resp; | ||
1609 | u8 raw_data[36]; | ||
1610 | ssize_t ret = 0; | ||
1611 | int len_off, err = -EIO; | ||
1612 | |||
1613 | while (s > 0) { | ||
1614 | err = -EIO; | ||
1615 | len_off = _picolcd_flash_setaddr(data, raw_data, *off); | ||
1616 | raw_data[len_off] = s > 32 ? 32 : s; | ||
1617 | if (copy_from_user(raw_data+len_off+1, u, raw_data[len_off])) { | ||
1618 | err = -EFAULT; | ||
1619 | break; | ||
1620 | } | ||
1621 | resp = picolcd_send_and_wait(data->hdev, report_id, raw_data, | ||
1622 | len_off+1+raw_data[len_off]); | ||
1623 | if (!resp || !resp->in_report) | ||
1624 | goto skip; | ||
1625 | if (resp->in_report->id == REPORT_MEMORY || | ||
1626 | resp->in_report->id == REPORT_BL_WRITE_MEMORY) { | ||
1627 | if (memcmp(raw_data, resp->raw_data, len_off+1+raw_data[len_off]) != 0) | ||
1628 | goto skip; | ||
1629 | *off += raw_data[len_off]; | ||
1630 | s -= raw_data[len_off]; | ||
1631 | ret += raw_data[len_off]; | ||
1632 | err = 0; | ||
1633 | } | ||
1634 | skip: | ||
1635 | kfree(resp); | ||
1636 | if (err) | ||
1637 | break; | ||
1638 | } | ||
1639 | return ret > 0 ? ret : err; | ||
1640 | } | ||
1641 | |||
1642 | static ssize_t picolcd_debug_flash_write(struct file *f, const char __user *u, | ||
1643 | size_t s, loff_t *off) | ||
1644 | { | ||
1645 | struct picolcd_data *data = f->private_data; | ||
1646 | ssize_t err, ret = 0; | ||
1647 | int report_erase, report_write; | ||
1648 | |||
1649 | if (s == 0) | ||
1650 | return -EINVAL; | ||
1651 | if (*off > 0x5fff) | ||
1652 | return -ENOSPC; | ||
1653 | if (s & 0x3f) | ||
1654 | return -EINVAL; | ||
1655 | if (*off & 0x3f) | ||
1656 | return -EINVAL; | ||
1657 | |||
1658 | if (data->status & PICOLCD_BOOTLOADER) { | ||
1659 | report_erase = REPORT_BL_ERASE_MEMORY; | ||
1660 | report_write = REPORT_BL_WRITE_MEMORY; | ||
1661 | } else { | ||
1662 | report_erase = REPORT_ERASE_MEMORY; | ||
1663 | report_write = REPORT_WRITE_MEMORY; | ||
1664 | } | ||
1665 | mutex_lock(&data->mutex_flash); | ||
1666 | while (s > 0) { | ||
1667 | err = _picolcd_flash_erase64(data, report_erase, off); | ||
1668 | if (err) | ||
1669 | break; | ||
1670 | err = _picolcd_flash_write(data, report_write, u, 64, off); | ||
1671 | if (err < 0) | ||
1672 | break; | ||
1673 | ret += err; | ||
1674 | *off += err; | ||
1675 | s -= err; | ||
1676 | if (err != 64) | ||
1677 | break; | ||
1678 | } | ||
1679 | mutex_unlock(&data->mutex_flash); | ||
1680 | return ret > 0 ? ret : err; | ||
1681 | } | ||
1682 | |||
1683 | /* | ||
1684 | * Notes: | ||
1685 | * - concurrent writing is prevented by mutex and all writes must be | ||
1686 | * n*64 bytes and 64-byte aligned, each write being preceeded by an | ||
1687 | * ERASE which erases a 64byte block. | ||
1688 | * If less than requested was written or an error is returned for an | ||
1689 | * otherwise correct write request the next 64-byte block which should | ||
1690 | * have been written is in undefined state (mostly: original, erased, | ||
1691 | * (half-)written with write error) | ||
1692 | * - reading can happend without special restriction | ||
1693 | */ | ||
1694 | static const struct file_operations picolcd_debug_flash_fops = { | ||
1695 | .owner = THIS_MODULE, | ||
1696 | .open = picolcd_debug_flash_open, | ||
1697 | .read = picolcd_debug_flash_read, | ||
1698 | .write = picolcd_debug_flash_write, | ||
1699 | .llseek = generic_file_llseek, | ||
1700 | }; | ||
1701 | |||
1702 | |||
1703 | /* | ||
1704 | * Helper code for HID report level dumping/debugging | ||
1705 | */ | ||
1706 | static const char *error_codes[] = { | ||
1707 | "success", "parameter missing", "data_missing", "block readonly", | ||
1708 | "block not erasable", "block too big", "section overflow", | ||
1709 | "invalid command length", "invalid data length", | ||
1710 | }; | ||
1711 | |||
1712 | static void dump_buff_as_hex(char *dst, size_t dst_sz, const u8 *data, | ||
1713 | const size_t data_len) | ||
1714 | { | ||
1715 | int i, j; | ||
1716 | for (i = j = 0; i < data_len && j + 3 < dst_sz; i++) { | ||
1717 | dst[j++] = hex_asc[(data[i] >> 4) & 0x0f]; | ||
1718 | dst[j++] = hex_asc[data[i] & 0x0f]; | ||
1719 | dst[j++] = ' '; | ||
1720 | } | ||
1721 | if (j < dst_sz) { | ||
1722 | dst[j--] = '\0'; | ||
1723 | dst[j] = '\n'; | ||
1724 | } else | ||
1725 | dst[j] = '\0'; | ||
1726 | } | ||
1727 | |||
1728 | static void picolcd_debug_out_report(struct picolcd_data *data, | ||
1729 | struct hid_device *hdev, struct hid_report *report) | ||
1730 | { | ||
1731 | u8 raw_data[70]; | ||
1732 | int raw_size = (report->size >> 3) + 1; | ||
1733 | char *buff; | ||
1734 | #define BUFF_SZ 256 | ||
1735 | |||
1736 | /* Avoid unnecessary overhead if debugfs is disabled */ | ||
1737 | if (!hdev->debug_events) | ||
1738 | return; | ||
1739 | |||
1740 | buff = kmalloc(BUFF_SZ, GFP_ATOMIC); | ||
1741 | if (!buff) | ||
1742 | return; | ||
1743 | |||
1744 | snprintf(buff, BUFF_SZ, "\nout report %d (size %d) = ", | ||
1745 | report->id, raw_size); | ||
1746 | hid_debug_event(hdev, buff); | ||
1747 | if (raw_size + 5 > sizeof(raw_data)) { | ||
1748 | hid_debug_event(hdev, " TOO BIG\n"); | ||
1749 | return; | ||
1750 | } else { | ||
1751 | raw_data[0] = report->id; | ||
1752 | hid_output_report(report, raw_data); | ||
1753 | dump_buff_as_hex(buff, BUFF_SZ, raw_data, raw_size); | ||
1754 | hid_debug_event(hdev, buff); | ||
1755 | } | ||
1756 | |||
1757 | switch (report->id) { | ||
1758 | case REPORT_LED_STATE: | ||
1759 | /* 1 data byte with GPO state */ | ||
1760 | snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n", | ||
1761 | "REPORT_LED_STATE", report->id, raw_size-1); | ||
1762 | hid_debug_event(hdev, buff); | ||
1763 | snprintf(buff, BUFF_SZ, "\tGPO state: 0x%02x\n", raw_data[1]); | ||
1764 | hid_debug_event(hdev, buff); | ||
1765 | break; | ||
1766 | case REPORT_BRIGHTNESS: | ||
1767 | /* 1 data byte with brightness */ | ||
1768 | snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n", | ||
1769 | "REPORT_BRIGHTNESS", report->id, raw_size-1); | ||
1770 | hid_debug_event(hdev, buff); | ||
1771 | snprintf(buff, BUFF_SZ, "\tBrightness: 0x%02x\n", raw_data[1]); | ||
1772 | hid_debug_event(hdev, buff); | ||
1773 | break; | ||
1774 | case REPORT_CONTRAST: | ||
1775 | /* 1 data byte with contrast */ | ||
1776 | snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n", | ||
1777 | "REPORT_CONTRAST", report->id, raw_size-1); | ||
1778 | hid_debug_event(hdev, buff); | ||
1779 | snprintf(buff, BUFF_SZ, "\tContrast: 0x%02x\n", raw_data[1]); | ||
1780 | hid_debug_event(hdev, buff); | ||
1781 | break; | ||
1782 | case REPORT_RESET: | ||
1783 | /* 2 data bytes with reset duration in ms */ | ||
1784 | snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n", | ||
1785 | "REPORT_RESET", report->id, raw_size-1); | ||
1786 | hid_debug_event(hdev, buff); | ||
1787 | snprintf(buff, BUFF_SZ, "\tDuration: 0x%02x%02x (%dms)\n", | ||
1788 | raw_data[2], raw_data[1], raw_data[2] << 8 | raw_data[1]); | ||
1789 | hid_debug_event(hdev, buff); | ||
1790 | break; | ||
1791 | case REPORT_LCD_CMD: | ||
1792 | /* 63 data bytes with LCD commands */ | ||
1793 | snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n", | ||
1794 | "REPORT_LCD_CMD", report->id, raw_size-1); | ||
1795 | hid_debug_event(hdev, buff); | ||
1796 | /* TODO: format decoding */ | ||
1797 | break; | ||
1798 | case REPORT_LCD_DATA: | ||
1799 | /* 63 data bytes with LCD data */ | ||
1800 | snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n", | ||
1801 | "REPORT_LCD_CMD", report->id, raw_size-1); | ||
1802 | /* TODO: format decoding */ | ||
1803 | hid_debug_event(hdev, buff); | ||
1804 | break; | ||
1805 | case REPORT_LCD_CMD_DATA: | ||
1806 | /* 63 data bytes with LCD commands and data */ | ||
1807 | snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n", | ||
1808 | "REPORT_LCD_CMD", report->id, raw_size-1); | ||
1809 | /* TODO: format decoding */ | ||
1810 | hid_debug_event(hdev, buff); | ||
1811 | break; | ||
1812 | case REPORT_EE_READ: | ||
1813 | /* 3 data bytes with read area description */ | ||
1814 | snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n", | ||
1815 | "REPORT_EE_READ", report->id, raw_size-1); | ||
1816 | hid_debug_event(hdev, buff); | ||
1817 | snprintf(buff, BUFF_SZ, "\tData address: 0x%02x%02x\n", | ||
1818 | raw_data[2], raw_data[1]); | ||
1819 | hid_debug_event(hdev, buff); | ||
1820 | snprintf(buff, BUFF_SZ, "\tData length: %d\n", raw_data[3]); | ||
1821 | hid_debug_event(hdev, buff); | ||
1822 | break; | ||
1823 | case REPORT_EE_WRITE: | ||
1824 | /* 3+1..20 data bytes with write area description */ | ||
1825 | snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n", | ||
1826 | "REPORT_EE_WRITE", report->id, raw_size-1); | ||
1827 | hid_debug_event(hdev, buff); | ||
1828 | snprintf(buff, BUFF_SZ, "\tData address: 0x%02x%02x\n", | ||
1829 | raw_data[2], raw_data[1]); | ||
1830 | hid_debug_event(hdev, buff); | ||
1831 | snprintf(buff, BUFF_SZ, "\tData length: %d\n", raw_data[3]); | ||
1832 | hid_debug_event(hdev, buff); | ||
1833 | if (raw_data[3] == 0) { | ||
1834 | snprintf(buff, BUFF_SZ, "\tNo data\n"); | ||
1835 | } else if (raw_data[3] + 4 <= raw_size) { | ||
1836 | snprintf(buff, BUFF_SZ, "\tData: "); | ||
1837 | hid_debug_event(hdev, buff); | ||
1838 | dump_buff_as_hex(buff, BUFF_SZ, raw_data+4, raw_data[3]); | ||
1839 | } else { | ||
1840 | snprintf(buff, BUFF_SZ, "\tData overflowed\n"); | ||
1841 | } | ||
1842 | hid_debug_event(hdev, buff); | ||
1843 | break; | ||
1844 | case REPORT_ERASE_MEMORY: | ||
1845 | case REPORT_BL_ERASE_MEMORY: | ||
1846 | /* 3 data bytes with pointer inside erase block */ | ||
1847 | snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n", | ||
1848 | "REPORT_ERASE_MEMORY", report->id, raw_size-1); | ||
1849 | hid_debug_event(hdev, buff); | ||
1850 | switch (data->addr_sz) { | ||
1851 | case 2: | ||
1852 | snprintf(buff, BUFF_SZ, "\tAddress inside 64 byte block: 0x%02x%02x\n", | ||
1853 | raw_data[2], raw_data[1]); | ||
1854 | break; | ||
1855 | case 3: | ||
1856 | snprintf(buff, BUFF_SZ, "\tAddress inside 64 byte block: 0x%02x%02x%02x\n", | ||
1857 | raw_data[3], raw_data[2], raw_data[1]); | ||
1858 | break; | ||
1859 | default: | ||
1860 | snprintf(buff, BUFF_SZ, "\tNot supported\n"); | ||
1861 | } | ||
1862 | hid_debug_event(hdev, buff); | ||
1863 | break; | ||
1864 | case REPORT_READ_MEMORY: | ||
1865 | case REPORT_BL_READ_MEMORY: | ||
1866 | /* 4 data bytes with read area description */ | ||
1867 | snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n", | ||
1868 | "REPORT_READ_MEMORY", report->id, raw_size-1); | ||
1869 | hid_debug_event(hdev, buff); | ||
1870 | switch (data->addr_sz) { | ||
1871 | case 2: | ||
1872 | snprintf(buff, BUFF_SZ, "\tData address: 0x%02x%02x\n", | ||
1873 | raw_data[2], raw_data[1]); | ||
1874 | hid_debug_event(hdev, buff); | ||
1875 | snprintf(buff, BUFF_SZ, "\tData length: %d\n", raw_data[3]); | ||
1876 | break; | ||
1877 | case 3: | ||
1878 | snprintf(buff, BUFF_SZ, "\tData address: 0x%02x%02x%02x\n", | ||
1879 | raw_data[3], raw_data[2], raw_data[1]); | ||
1880 | hid_debug_event(hdev, buff); | ||
1881 | snprintf(buff, BUFF_SZ, "\tData length: %d\n", raw_data[4]); | ||
1882 | break; | ||
1883 | default: | ||
1884 | snprintf(buff, BUFF_SZ, "\tNot supported\n"); | ||
1885 | } | ||
1886 | hid_debug_event(hdev, buff); | ||
1887 | break; | ||
1888 | case REPORT_WRITE_MEMORY: | ||
1889 | case REPORT_BL_WRITE_MEMORY: | ||
1890 | /* 4+1..32 data bytes with write adrea description */ | ||
1891 | snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n", | ||
1892 | "REPORT_WRITE_MEMORY", report->id, raw_size-1); | ||
1893 | hid_debug_event(hdev, buff); | ||
1894 | switch (data->addr_sz) { | ||
1895 | case 2: | ||
1896 | snprintf(buff, BUFF_SZ, "\tData address: 0x%02x%02x\n", | ||
1897 | raw_data[2], raw_data[1]); | ||
1898 | hid_debug_event(hdev, buff); | ||
1899 | snprintf(buff, BUFF_SZ, "\tData length: %d\n", raw_data[3]); | ||
1900 | hid_debug_event(hdev, buff); | ||
1901 | if (raw_data[3] == 0) { | ||
1902 | snprintf(buff, BUFF_SZ, "\tNo data\n"); | ||
1903 | } else if (raw_data[3] + 4 <= raw_size) { | ||
1904 | snprintf(buff, BUFF_SZ, "\tData: "); | ||
1905 | hid_debug_event(hdev, buff); | ||
1906 | dump_buff_as_hex(buff, BUFF_SZ, raw_data+4, raw_data[3]); | ||
1907 | } else { | ||
1908 | snprintf(buff, BUFF_SZ, "\tData overflowed\n"); | ||
1909 | } | ||
1910 | break; | ||
1911 | case 3: | ||
1912 | snprintf(buff, BUFF_SZ, "\tData address: 0x%02x%02x%02x\n", | ||
1913 | raw_data[3], raw_data[2], raw_data[1]); | ||
1914 | hid_debug_event(hdev, buff); | ||
1915 | snprintf(buff, BUFF_SZ, "\tData length: %d\n", raw_data[4]); | ||
1916 | hid_debug_event(hdev, buff); | ||
1917 | if (raw_data[4] == 0) { | ||
1918 | snprintf(buff, BUFF_SZ, "\tNo data\n"); | ||
1919 | } else if (raw_data[4] + 5 <= raw_size) { | ||
1920 | snprintf(buff, BUFF_SZ, "\tData: "); | ||
1921 | hid_debug_event(hdev, buff); | ||
1922 | dump_buff_as_hex(buff, BUFF_SZ, raw_data+5, raw_data[4]); | ||
1923 | } else { | ||
1924 | snprintf(buff, BUFF_SZ, "\tData overflowed\n"); | ||
1925 | } | ||
1926 | break; | ||
1927 | default: | ||
1928 | snprintf(buff, BUFF_SZ, "\tNot supported\n"); | ||
1929 | } | ||
1930 | hid_debug_event(hdev, buff); | ||
1931 | break; | ||
1932 | case REPORT_SPLASH_RESTART: | ||
1933 | /* TODO */ | ||
1934 | break; | ||
1935 | case REPORT_EXIT_KEYBOARD: | ||
1936 | snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n", | ||
1937 | "REPORT_EXIT_KEYBOARD", report->id, raw_size-1); | ||
1938 | hid_debug_event(hdev, buff); | ||
1939 | snprintf(buff, BUFF_SZ, "\tRestart delay: %dms (0x%02x%02x)\n", | ||
1940 | raw_data[1] | (raw_data[2] << 8), | ||
1941 | raw_data[2], raw_data[1]); | ||
1942 | hid_debug_event(hdev, buff); | ||
1943 | break; | ||
1944 | case REPORT_VERSION: | ||
1945 | snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n", | ||
1946 | "REPORT_VERSION", report->id, raw_size-1); | ||
1947 | hid_debug_event(hdev, buff); | ||
1948 | break; | ||
1949 | case REPORT_DEVID: | ||
1950 | snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n", | ||
1951 | "REPORT_DEVID", report->id, raw_size-1); | ||
1952 | hid_debug_event(hdev, buff); | ||
1953 | break; | ||
1954 | case REPORT_SPLASH_SIZE: | ||
1955 | snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n", | ||
1956 | "REPORT_SPLASH_SIZE", report->id, raw_size-1); | ||
1957 | hid_debug_event(hdev, buff); | ||
1958 | break; | ||
1959 | case REPORT_HOOK_VERSION: | ||
1960 | snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n", | ||
1961 | "REPORT_HOOK_VERSION", report->id, raw_size-1); | ||
1962 | hid_debug_event(hdev, buff); | ||
1963 | break; | ||
1964 | case REPORT_EXIT_FLASHER: | ||
1965 | snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n", | ||
1966 | "REPORT_VERSION", report->id, raw_size-1); | ||
1967 | hid_debug_event(hdev, buff); | ||
1968 | snprintf(buff, BUFF_SZ, "\tRestart delay: %dms (0x%02x%02x)\n", | ||
1969 | raw_data[1] | (raw_data[2] << 8), | ||
1970 | raw_data[2], raw_data[1]); | ||
1971 | hid_debug_event(hdev, buff); | ||
1972 | break; | ||
1973 | default: | ||
1974 | snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n", | ||
1975 | "<unknown>", report->id, raw_size-1); | ||
1976 | hid_debug_event(hdev, buff); | ||
1977 | break; | ||
1978 | } | ||
1979 | wake_up_interruptible(&hdev->debug_wait); | ||
1980 | kfree(buff); | ||
1981 | } | ||
1982 | |||
1983 | static void picolcd_debug_raw_event(struct picolcd_data *data, | ||
1984 | struct hid_device *hdev, struct hid_report *report, | ||
1985 | u8 *raw_data, int size) | ||
1986 | { | ||
1987 | char *buff; | ||
1988 | |||
1989 | #define BUFF_SZ 256 | ||
1990 | /* Avoid unnecessary overhead if debugfs is disabled */ | ||
1991 | if (!hdev->debug_events) | ||
1992 | return; | ||
1993 | |||
1994 | buff = kmalloc(BUFF_SZ, GFP_ATOMIC); | ||
1995 | if (!buff) | ||
1996 | return; | ||
1997 | |||
1998 | switch (report->id) { | ||
1999 | case REPORT_ERROR_CODE: | ||
2000 | /* 2 data bytes with affected report and error code */ | ||
2001 | snprintf(buff, BUFF_SZ, "report %s (%d, size=%d)\n", | ||
2002 | "REPORT_ERROR_CODE", report->id, size-1); | ||
2003 | hid_debug_event(hdev, buff); | ||
2004 | if (raw_data[2] < ARRAY_SIZE(error_codes)) | ||
2005 | snprintf(buff, BUFF_SZ, "\tError code 0x%02x (%s) in reply to report 0x%02x\n", | ||
2006 | raw_data[2], error_codes[raw_data[2]], raw_data[1]); | ||
2007 | else | ||
2008 | snprintf(buff, BUFF_SZ, "\tError code 0x%02x in reply to report 0x%02x\n", | ||
2009 | raw_data[2], raw_data[1]); | ||
2010 | hid_debug_event(hdev, buff); | ||
2011 | break; | ||
2012 | case REPORT_KEY_STATE: | ||
2013 | /* 2 data bytes with key state */ | ||
2014 | snprintf(buff, BUFF_SZ, "report %s (%d, size=%d)\n", | ||
2015 | "REPORT_KEY_STATE", report->id, size-1); | ||
2016 | hid_debug_event(hdev, buff); | ||
2017 | if (raw_data[1] == 0) | ||
2018 | snprintf(buff, BUFF_SZ, "\tNo key pressed\n"); | ||
2019 | else if (raw_data[2] == 0) | ||
2020 | snprintf(buff, BUFF_SZ, "\tOne key pressed: 0x%02x (%d)\n", | ||
2021 | raw_data[1], raw_data[1]); | ||
2022 | else | ||
2023 | snprintf(buff, BUFF_SZ, "\tTwo keys pressed: 0x%02x (%d), 0x%02x (%d)\n", | ||
2024 | raw_data[1], raw_data[1], raw_data[2], raw_data[2]); | ||
2025 | hid_debug_event(hdev, buff); | ||
2026 | break; | ||
2027 | case REPORT_IR_DATA: | ||
2028 | /* Up to 20 byes of IR scancode data */ | ||
2029 | snprintf(buff, BUFF_SZ, "report %s (%d, size=%d)\n", | ||
2030 | "REPORT_IR_DATA", report->id, size-1); | ||
2031 | hid_debug_event(hdev, buff); | ||
2032 | if (raw_data[1] == 0) { | ||
2033 | snprintf(buff, BUFF_SZ, "\tUnexpectedly 0 data length\n"); | ||
2034 | hid_debug_event(hdev, buff); | ||
2035 | } else if (raw_data[1] + 1 <= size) { | ||
2036 | snprintf(buff, BUFF_SZ, "\tData length: %d\n\tIR Data: ", | ||
2037 | raw_data[1]-1); | ||
2038 | hid_debug_event(hdev, buff); | ||
2039 | dump_buff_as_hex(buff, BUFF_SZ, raw_data+2, raw_data[1]-1); | ||
2040 | hid_debug_event(hdev, buff); | ||
2041 | } else { | ||
2042 | snprintf(buff, BUFF_SZ, "\tOverflowing data length: %d\n", | ||
2043 | raw_data[1]-1); | ||
2044 | hid_debug_event(hdev, buff); | ||
2045 | } | ||
2046 | break; | ||
2047 | case REPORT_EE_DATA: | ||
2048 | /* Data buffer in response to REPORT_EE_READ or REPORT_EE_WRITE */ | ||
2049 | snprintf(buff, BUFF_SZ, "report %s (%d, size=%d)\n", | ||
2050 | "REPORT_EE_DATA", report->id, size-1); | ||
2051 | hid_debug_event(hdev, buff); | ||
2052 | snprintf(buff, BUFF_SZ, "\tData address: 0x%02x%02x\n", | ||
2053 | raw_data[2], raw_data[1]); | ||
2054 | hid_debug_event(hdev, buff); | ||
2055 | snprintf(buff, BUFF_SZ, "\tData length: %d\n", raw_data[3]); | ||
2056 | hid_debug_event(hdev, buff); | ||
2057 | if (raw_data[3] == 0) { | ||
2058 | snprintf(buff, BUFF_SZ, "\tNo data\n"); | ||
2059 | hid_debug_event(hdev, buff); | ||
2060 | } else if (raw_data[3] + 4 <= size) { | ||
2061 | snprintf(buff, BUFF_SZ, "\tData: "); | ||
2062 | hid_debug_event(hdev, buff); | ||
2063 | dump_buff_as_hex(buff, BUFF_SZ, raw_data+4, raw_data[3]); | ||
2064 | hid_debug_event(hdev, buff); | ||
2065 | } else { | ||
2066 | snprintf(buff, BUFF_SZ, "\tData overflowed\n"); | ||
2067 | hid_debug_event(hdev, buff); | ||
2068 | } | ||
2069 | break; | ||
2070 | case REPORT_MEMORY: | ||
2071 | /* Data buffer in response to REPORT_READ_MEMORY or REPORT_WRTIE_MEMORY */ | ||
2072 | snprintf(buff, BUFF_SZ, "report %s (%d, size=%d)\n", | ||
2073 | "REPORT_MEMORY", report->id, size-1); | ||
2074 | hid_debug_event(hdev, buff); | ||
2075 | switch (data->addr_sz) { | ||
2076 | case 2: | ||
2077 | snprintf(buff, BUFF_SZ, "\tData address: 0x%02x%02x\n", | ||
2078 | raw_data[2], raw_data[1]); | ||
2079 | hid_debug_event(hdev, buff); | ||
2080 | snprintf(buff, BUFF_SZ, "\tData length: %d\n", raw_data[3]); | ||
2081 | hid_debug_event(hdev, buff); | ||
2082 | if (raw_data[3] == 0) { | ||
2083 | snprintf(buff, BUFF_SZ, "\tNo data\n"); | ||
2084 | } else if (raw_data[3] + 4 <= size) { | ||
2085 | snprintf(buff, BUFF_SZ, "\tData: "); | ||
2086 | hid_debug_event(hdev, buff); | ||
2087 | dump_buff_as_hex(buff, BUFF_SZ, raw_data+4, raw_data[3]); | ||
2088 | } else { | ||
2089 | snprintf(buff, BUFF_SZ, "\tData overflowed\n"); | ||
2090 | } | ||
2091 | break; | ||
2092 | case 3: | ||
2093 | snprintf(buff, BUFF_SZ, "\tData address: 0x%02x%02x%02x\n", | ||
2094 | raw_data[3], raw_data[2], raw_data[1]); | ||
2095 | hid_debug_event(hdev, buff); | ||
2096 | snprintf(buff, BUFF_SZ, "\tData length: %d\n", raw_data[4]); | ||
2097 | hid_debug_event(hdev, buff); | ||
2098 | if (raw_data[4] == 0) { | ||
2099 | snprintf(buff, BUFF_SZ, "\tNo data\n"); | ||
2100 | } else if (raw_data[4] + 5 <= size) { | ||
2101 | snprintf(buff, BUFF_SZ, "\tData: "); | ||
2102 | hid_debug_event(hdev, buff); | ||
2103 | dump_buff_as_hex(buff, BUFF_SZ, raw_data+5, raw_data[4]); | ||
2104 | } else { | ||
2105 | snprintf(buff, BUFF_SZ, "\tData overflowed\n"); | ||
2106 | } | ||
2107 | break; | ||
2108 | default: | ||
2109 | snprintf(buff, BUFF_SZ, "\tNot supported\n"); | ||
2110 | } | ||
2111 | hid_debug_event(hdev, buff); | ||
2112 | break; | ||
2113 | case REPORT_VERSION: | ||
2114 | snprintf(buff, BUFF_SZ, "report %s (%d, size=%d)\n", | ||
2115 | "REPORT_VERSION", report->id, size-1); | ||
2116 | hid_debug_event(hdev, buff); | ||
2117 | snprintf(buff, BUFF_SZ, "\tFirmware version: %d.%d\n", | ||
2118 | raw_data[2], raw_data[1]); | ||
2119 | hid_debug_event(hdev, buff); | ||
2120 | break; | ||
2121 | case REPORT_BL_ERASE_MEMORY: | ||
2122 | snprintf(buff, BUFF_SZ, "report %s (%d, size=%d)\n", | ||
2123 | "REPORT_BL_ERASE_MEMORY", report->id, size-1); | ||
2124 | hid_debug_event(hdev, buff); | ||
2125 | /* TODO */ | ||
2126 | break; | ||
2127 | case REPORT_BL_READ_MEMORY: | ||
2128 | snprintf(buff, BUFF_SZ, "report %s (%d, size=%d)\n", | ||
2129 | "REPORT_BL_READ_MEMORY", report->id, size-1); | ||
2130 | hid_debug_event(hdev, buff); | ||
2131 | /* TODO */ | ||
2132 | break; | ||
2133 | case REPORT_BL_WRITE_MEMORY: | ||
2134 | snprintf(buff, BUFF_SZ, "report %s (%d, size=%d)\n", | ||
2135 | "REPORT_BL_WRITE_MEMORY", report->id, size-1); | ||
2136 | hid_debug_event(hdev, buff); | ||
2137 | /* TODO */ | ||
2138 | break; | ||
2139 | case REPORT_DEVID: | ||
2140 | snprintf(buff, BUFF_SZ, "report %s (%d, size=%d)\n", | ||
2141 | "REPORT_DEVID", report->id, size-1); | ||
2142 | hid_debug_event(hdev, buff); | ||
2143 | snprintf(buff, BUFF_SZ, "\tSerial: 0x%02x%02x%02x%02x\n", | ||
2144 | raw_data[1], raw_data[2], raw_data[3], raw_data[4]); | ||
2145 | hid_debug_event(hdev, buff); | ||
2146 | snprintf(buff, BUFF_SZ, "\tType: 0x%02x\n", | ||
2147 | raw_data[5]); | ||
2148 | hid_debug_event(hdev, buff); | ||
2149 | break; | ||
2150 | case REPORT_SPLASH_SIZE: | ||
2151 | snprintf(buff, BUFF_SZ, "report %s (%d, size=%d)\n", | ||
2152 | "REPORT_SPLASH_SIZE", report->id, size-1); | ||
2153 | hid_debug_event(hdev, buff); | ||
2154 | snprintf(buff, BUFF_SZ, "\tTotal splash space: %d\n", | ||
2155 | (raw_data[2] << 8) | raw_data[1]); | ||
2156 | hid_debug_event(hdev, buff); | ||
2157 | snprintf(buff, BUFF_SZ, "\tUsed splash space: %d\n", | ||
2158 | (raw_data[4] << 8) | raw_data[3]); | ||
2159 | hid_debug_event(hdev, buff); | ||
2160 | break; | ||
2161 | case REPORT_HOOK_VERSION: | ||
2162 | snprintf(buff, BUFF_SZ, "report %s (%d, size=%d)\n", | ||
2163 | "REPORT_HOOK_VERSION", report->id, size-1); | ||
2164 | hid_debug_event(hdev, buff); | ||
2165 | snprintf(buff, BUFF_SZ, "\tFirmware version: %d.%d\n", | ||
2166 | raw_data[1], raw_data[2]); | ||
2167 | hid_debug_event(hdev, buff); | ||
2168 | break; | ||
2169 | default: | ||
2170 | snprintf(buff, BUFF_SZ, "report %s (%d, size=%d)\n", | ||
2171 | "<unknown>", report->id, size-1); | ||
2172 | hid_debug_event(hdev, buff); | ||
2173 | break; | ||
2174 | } | ||
2175 | wake_up_interruptible(&hdev->debug_wait); | ||
2176 | kfree(buff); | ||
2177 | } | ||
2178 | |||
2179 | static void picolcd_init_devfs(struct picolcd_data *data, | ||
2180 | struct hid_report *eeprom_r, struct hid_report *eeprom_w, | ||
2181 | struct hid_report *flash_r, struct hid_report *flash_w, | ||
2182 | struct hid_report *reset) | ||
2183 | { | ||
2184 | struct hid_device *hdev = data->hdev; | ||
2185 | |||
2186 | mutex_init(&data->mutex_flash); | ||
2187 | |||
2188 | /* reset */ | ||
2189 | if (reset) | ||
2190 | data->debug_reset = debugfs_create_file("reset", 0600, | ||
2191 | hdev->debug_dir, data, &picolcd_debug_reset_fops); | ||
2192 | |||
2193 | /* eeprom */ | ||
2194 | if (eeprom_r || eeprom_w) | ||
2195 | data->debug_eeprom = debugfs_create_file("eeprom", | ||
2196 | (eeprom_w ? S_IWUSR : 0) | (eeprom_r ? S_IRUSR : 0), | ||
2197 | hdev->debug_dir, data, &picolcd_debug_eeprom_fops); | ||
2198 | |||
2199 | /* flash */ | ||
2200 | if (flash_r && flash_r->maxfield == 1 && flash_r->field[0]->report_size == 8) | ||
2201 | data->addr_sz = flash_r->field[0]->report_count - 1; | ||
2202 | else | ||
2203 | data->addr_sz = -1; | ||
2204 | if (data->addr_sz == 2 || data->addr_sz == 3) { | ||
2205 | data->debug_flash = debugfs_create_file("flash", | ||
2206 | (flash_w ? S_IWUSR : 0) | (flash_r ? S_IRUSR : 0), | ||
2207 | hdev->debug_dir, data, &picolcd_debug_flash_fops); | ||
2208 | } else if (flash_r || flash_w) | ||
2209 | dev_warn(&hdev->dev, "Unexpected FLASH access reports, " | ||
2210 | "please submit rdesc for review\n"); | ||
2211 | } | ||
2212 | |||
2213 | static void picolcd_exit_devfs(struct picolcd_data *data) | ||
2214 | { | ||
2215 | struct dentry *dent; | ||
2216 | |||
2217 | dent = data->debug_reset; | ||
2218 | data->debug_reset = NULL; | ||
2219 | if (dent) | ||
2220 | debugfs_remove(dent); | ||
2221 | dent = data->debug_eeprom; | ||
2222 | data->debug_eeprom = NULL; | ||
2223 | if (dent) | ||
2224 | debugfs_remove(dent); | ||
2225 | dent = data->debug_flash; | ||
2226 | data->debug_flash = NULL; | ||
2227 | if (dent) | ||
2228 | debugfs_remove(dent); | ||
2229 | mutex_destroy(&data->mutex_flash); | ||
2230 | } | ||
2231 | #else | ||
2232 | static inline void picolcd_debug_raw_event(struct picolcd_data *data, | ||
2233 | struct hid_device *hdev, struct hid_report *report, | ||
2234 | u8 *raw_data, int size) | ||
2235 | { | ||
2236 | } | ||
2237 | static inline void picolcd_init_devfs(struct picolcd_data *data, | ||
2238 | struct hid_report *eeprom_r, struct hid_report *eeprom_w, | ||
2239 | struct hid_report *flash_r, struct hid_report *flash_w, | ||
2240 | struct hid_report *reset) | ||
2241 | { | ||
2242 | } | ||
2243 | static inline void picolcd_exit_devfs(struct picolcd_data *data) | ||
2244 | { | ||
2245 | } | ||
2246 | #endif /* CONFIG_DEBUG_FS */ | ||
2247 | |||
2248 | /* | ||
2249 | * Handle raw report as sent by device | ||
2250 | */ | ||
2251 | static int picolcd_raw_event(struct hid_device *hdev, | ||
2252 | struct hid_report *report, u8 *raw_data, int size) | ||
2253 | { | ||
2254 | struct picolcd_data *data = hid_get_drvdata(hdev); | ||
2255 | unsigned long flags; | ||
2256 | int ret = 0; | ||
2257 | |||
2258 | if (!data) | ||
2259 | return 1; | ||
2260 | |||
2261 | if (report->id == REPORT_KEY_STATE) { | ||
2262 | if (data->input_keys) | ||
2263 | ret = picolcd_raw_keypad(data, report, raw_data+1, size-1); | ||
2264 | } else if (report->id == REPORT_IR_DATA) { | ||
2265 | if (data->input_cir) | ||
2266 | ret = picolcd_raw_cir(data, report, raw_data+1, size-1); | ||
2267 | } else { | ||
2268 | spin_lock_irqsave(&data->lock, flags); | ||
2269 | /* | ||
2270 | * We let the caller of picolcd_send_and_wait() check if the | ||
2271 | * report we got is one of the expected ones or not. | ||
2272 | */ | ||
2273 | if (data->pending) { | ||
2274 | memcpy(data->pending->raw_data, raw_data+1, size-1); | ||
2275 | data->pending->raw_size = size-1; | ||
2276 | data->pending->in_report = report; | ||
2277 | complete(&data->pending->ready); | ||
2278 | } | ||
2279 | spin_unlock_irqrestore(&data->lock, flags); | ||
2280 | } | ||
2281 | |||
2282 | picolcd_debug_raw_event(data, hdev, report, raw_data, size); | ||
2283 | return 1; | ||
2284 | } | ||
2285 | |||
2286 | #ifdef CONFIG_PM | ||
2287 | static int picolcd_suspend(struct hid_device *hdev, pm_message_t message) | ||
2288 | { | ||
2289 | if (message.event & PM_EVENT_AUTO) | ||
2290 | return 0; | ||
2291 | |||
2292 | picolcd_suspend_backlight(hid_get_drvdata(hdev)); | ||
2293 | dbg_hid(PICOLCD_NAME " device ready for suspend\n"); | ||
2294 | return 0; | ||
2295 | } | ||
2296 | |||
2297 | static int picolcd_resume(struct hid_device *hdev) | ||
2298 | { | ||
2299 | int ret; | ||
2300 | ret = picolcd_resume_backlight(hid_get_drvdata(hdev)); | ||
2301 | if (ret) | ||
2302 | dbg_hid(PICOLCD_NAME " restoring backlight failed: %d\n", ret); | ||
2303 | return 0; | ||
2304 | } | ||
2305 | |||
2306 | static int picolcd_reset_resume(struct hid_device *hdev) | ||
2307 | { | ||
2308 | int ret; | ||
2309 | ret = picolcd_reset(hdev); | ||
2310 | if (ret) | ||
2311 | dbg_hid(PICOLCD_NAME " resetting our device failed: %d\n", ret); | ||
2312 | ret = picolcd_fb_reset(hid_get_drvdata(hdev), 0); | ||
2313 | if (ret) | ||
2314 | dbg_hid(PICOLCD_NAME " restoring framebuffer content failed: %d\n", ret); | ||
2315 | ret = picolcd_resume_lcd(hid_get_drvdata(hdev)); | ||
2316 | if (ret) | ||
2317 | dbg_hid(PICOLCD_NAME " restoring lcd failed: %d\n", ret); | ||
2318 | ret = picolcd_resume_backlight(hid_get_drvdata(hdev)); | ||
2319 | if (ret) | ||
2320 | dbg_hid(PICOLCD_NAME " restoring backlight failed: %d\n", ret); | ||
2321 | picolcd_leds_set(hid_get_drvdata(hdev)); | ||
2322 | return 0; | ||
2323 | } | ||
2324 | #endif | ||
2325 | |||
2326 | /* initialize keypad input device */ | ||
2327 | static int picolcd_init_keys(struct picolcd_data *data, | ||
2328 | struct hid_report *report) | ||
2329 | { | ||
2330 | struct hid_device *hdev = data->hdev; | ||
2331 | struct input_dev *idev; | ||
2332 | int error, i; | ||
2333 | |||
2334 | if (!report) | ||
2335 | return -ENODEV; | ||
2336 | if (report->maxfield != 1 || report->field[0]->report_count != 2 || | ||
2337 | report->field[0]->report_size != 8) { | ||
2338 | dev_err(&hdev->dev, "unsupported KEY_STATE report"); | ||
2339 | return -EINVAL; | ||
2340 | } | ||
2341 | |||
2342 | idev = input_allocate_device(); | ||
2343 | if (idev == NULL) { | ||
2344 | dev_err(&hdev->dev, "failed to allocate input device"); | ||
2345 | return -ENOMEM; | ||
2346 | } | ||
2347 | input_set_drvdata(idev, hdev); | ||
2348 | memcpy(data->keycode, def_keymap, sizeof(def_keymap)); | ||
2349 | idev->name = hdev->name; | ||
2350 | idev->phys = hdev->phys; | ||
2351 | idev->uniq = hdev->uniq; | ||
2352 | idev->id.bustype = hdev->bus; | ||
2353 | idev->id.vendor = hdev->vendor; | ||
2354 | idev->id.product = hdev->product; | ||
2355 | idev->id.version = hdev->version; | ||
2356 | idev->dev.parent = hdev->dev.parent; | ||
2357 | idev->keycode = &data->keycode; | ||
2358 | idev->keycodemax = PICOLCD_KEYS; | ||
2359 | idev->keycodesize = sizeof(data->keycode[0]); | ||
2360 | input_set_capability(idev, EV_MSC, MSC_SCAN); | ||
2361 | set_bit(EV_REP, idev->evbit); | ||
2362 | for (i = 0; i < PICOLCD_KEYS; i++) | ||
2363 | input_set_capability(idev, EV_KEY, data->keycode[i]); | ||
2364 | error = input_register_device(idev); | ||
2365 | if (error) { | ||
2366 | dev_err(&hdev->dev, "error registering the input device"); | ||
2367 | input_free_device(idev); | ||
2368 | return error; | ||
2369 | } | ||
2370 | data->input_keys = idev; | ||
2371 | return 0; | ||
2372 | } | ||
2373 | |||
2374 | static void picolcd_exit_keys(struct picolcd_data *data) | ||
2375 | { | ||
2376 | struct input_dev *idev = data->input_keys; | ||
2377 | |||
2378 | data->input_keys = NULL; | ||
2379 | if (idev) | ||
2380 | input_unregister_device(idev); | ||
2381 | } | ||
2382 | |||
2383 | /* initialize CIR input device */ | ||
2384 | static inline int picolcd_init_cir(struct picolcd_data *data, struct hid_report *report) | ||
2385 | { | ||
2386 | /* support not implemented yet */ | ||
2387 | return 0; | ||
2388 | } | ||
2389 | |||
2390 | static inline void picolcd_exit_cir(struct picolcd_data *data) | ||
2391 | { | ||
2392 | } | ||
2393 | |||
2394 | static int picolcd_probe_lcd(struct hid_device *hdev, struct picolcd_data *data) | ||
2395 | { | ||
2396 | int error; | ||
2397 | |||
2398 | error = picolcd_check_version(hdev); | ||
2399 | if (error) | ||
2400 | return error; | ||
2401 | |||
2402 | if (data->version[0] != 0 && data->version[1] != 3) | ||
2403 | dev_info(&hdev->dev, "Device with untested firmware revision, " | ||
2404 | "please submit /sys/kernel/debug/hid/%s/rdesc for this device.\n", | ||
2405 | dev_name(&hdev->dev)); | ||
2406 | |||
2407 | /* Setup keypad input device */ | ||
2408 | error = picolcd_init_keys(data, picolcd_in_report(REPORT_KEY_STATE, hdev)); | ||
2409 | if (error) | ||
2410 | goto err; | ||
2411 | |||
2412 | /* Setup CIR input device */ | ||
2413 | error = picolcd_init_cir(data, picolcd_in_report(REPORT_IR_DATA, hdev)); | ||
2414 | if (error) | ||
2415 | goto err; | ||
2416 | |||
2417 | /* Set up the framebuffer device */ | ||
2418 | error = picolcd_init_framebuffer(data); | ||
2419 | if (error) | ||
2420 | goto err; | ||
2421 | |||
2422 | /* Setup lcd class device */ | ||
2423 | error = picolcd_init_lcd(data, picolcd_out_report(REPORT_CONTRAST, hdev)); | ||
2424 | if (error) | ||
2425 | goto err; | ||
2426 | |||
2427 | /* Setup backlight class device */ | ||
2428 | error = picolcd_init_backlight(data, picolcd_out_report(REPORT_BRIGHTNESS, hdev)); | ||
2429 | if (error) | ||
2430 | goto err; | ||
2431 | |||
2432 | /* Setup the LED class devices */ | ||
2433 | error = picolcd_init_leds(data, picolcd_out_report(REPORT_LED_STATE, hdev)); | ||
2434 | if (error) | ||
2435 | goto err; | ||
2436 | |||
2437 | picolcd_init_devfs(data, picolcd_out_report(REPORT_EE_READ, hdev), | ||
2438 | picolcd_out_report(REPORT_EE_WRITE, hdev), | ||
2439 | picolcd_out_report(REPORT_READ_MEMORY, hdev), | ||
2440 | picolcd_out_report(REPORT_WRITE_MEMORY, hdev), | ||
2441 | picolcd_out_report(REPORT_RESET, hdev)); | ||
2442 | return 0; | ||
2443 | err: | ||
2444 | picolcd_exit_leds(data); | ||
2445 | picolcd_exit_backlight(data); | ||
2446 | picolcd_exit_lcd(data); | ||
2447 | picolcd_exit_framebuffer(data); | ||
2448 | picolcd_exit_cir(data); | ||
2449 | picolcd_exit_keys(data); | ||
2450 | return error; | ||
2451 | } | ||
2452 | |||
2453 | static int picolcd_probe_bootloader(struct hid_device *hdev, struct picolcd_data *data) | ||
2454 | { | ||
2455 | int error; | ||
2456 | |||
2457 | error = picolcd_check_version(hdev); | ||
2458 | if (error) | ||
2459 | return error; | ||
2460 | |||
2461 | if (data->version[0] != 1 && data->version[1] != 0) | ||
2462 | dev_info(&hdev->dev, "Device with untested bootloader revision, " | ||
2463 | "please submit /sys/kernel/debug/hid/%s/rdesc for this device.\n", | ||
2464 | dev_name(&hdev->dev)); | ||
2465 | |||
2466 | picolcd_init_devfs(data, NULL, NULL, | ||
2467 | picolcd_out_report(REPORT_BL_READ_MEMORY, hdev), | ||
2468 | picolcd_out_report(REPORT_BL_WRITE_MEMORY, hdev), NULL); | ||
2469 | return 0; | ||
2470 | } | ||
2471 | |||
2472 | static int picolcd_probe(struct hid_device *hdev, | ||
2473 | const struct hid_device_id *id) | ||
2474 | { | ||
2475 | struct picolcd_data *data; | ||
2476 | int error = -ENOMEM; | ||
2477 | |||
2478 | dbg_hid(PICOLCD_NAME " hardware probe...\n"); | ||
2479 | |||
2480 | /* | ||
2481 | * Let's allocate the picolcd data structure, set some reasonable | ||
2482 | * defaults, and associate it with the device | ||
2483 | */ | ||
2484 | data = kzalloc(sizeof(struct picolcd_data), GFP_KERNEL); | ||
2485 | if (data == NULL) { | ||
2486 | dev_err(&hdev->dev, "can't allocate space for Minibox PicoLCD device data\n"); | ||
2487 | error = -ENOMEM; | ||
2488 | goto err_no_cleanup; | ||
2489 | } | ||
2490 | |||
2491 | spin_lock_init(&data->lock); | ||
2492 | mutex_init(&data->mutex); | ||
2493 | data->hdev = hdev; | ||
2494 | data->opmode_delay = 5000; | ||
2495 | if (hdev->product == USB_DEVICE_ID_PICOLCD_BOOTLOADER) | ||
2496 | data->status |= PICOLCD_BOOTLOADER; | ||
2497 | hid_set_drvdata(hdev, data); | ||
2498 | |||
2499 | /* Parse the device reports and start it up */ | ||
2500 | error = hid_parse(hdev); | ||
2501 | if (error) { | ||
2502 | dev_err(&hdev->dev, "device report parse failed\n"); | ||
2503 | goto err_cleanup_data; | ||
2504 | } | ||
2505 | |||
2506 | /* We don't use hidinput but hid_hw_start() fails if nothing is | ||
2507 | * claimed. So spoof claimed input. */ | ||
2508 | hdev->claimed = HID_CLAIMED_INPUT; | ||
2509 | error = hid_hw_start(hdev, 0); | ||
2510 | hdev->claimed = 0; | ||
2511 | if (error) { | ||
2512 | dev_err(&hdev->dev, "hardware start failed\n"); | ||
2513 | goto err_cleanup_data; | ||
2514 | } | ||
2515 | |||
2516 | error = hdev->ll_driver->open(hdev); | ||
2517 | if (error) { | ||
2518 | dev_err(&hdev->dev, "failed to open input interrupt pipe for key and IR events\n"); | ||
2519 | goto err_cleanup_hid_hw; | ||
2520 | } | ||
2521 | |||
2522 | error = device_create_file(&hdev->dev, &dev_attr_operation_mode_delay); | ||
2523 | if (error) { | ||
2524 | dev_err(&hdev->dev, "failed to create sysfs attributes\n"); | ||
2525 | goto err_cleanup_hid_ll; | ||
2526 | } | ||
2527 | |||
2528 | error = device_create_file(&hdev->dev, &dev_attr_operation_mode); | ||
2529 | if (error) { | ||
2530 | dev_err(&hdev->dev, "failed to create sysfs attributes\n"); | ||
2531 | goto err_cleanup_sysfs1; | ||
2532 | } | ||
2533 | |||
2534 | if (data->status & PICOLCD_BOOTLOADER) | ||
2535 | error = picolcd_probe_bootloader(hdev, data); | ||
2536 | else | ||
2537 | error = picolcd_probe_lcd(hdev, data); | ||
2538 | if (error) | ||
2539 | goto err_cleanup_sysfs2; | ||
2540 | |||
2541 | dbg_hid(PICOLCD_NAME " activated and initialized\n"); | ||
2542 | return 0; | ||
2543 | |||
2544 | err_cleanup_sysfs2: | ||
2545 | device_remove_file(&hdev->dev, &dev_attr_operation_mode); | ||
2546 | err_cleanup_sysfs1: | ||
2547 | device_remove_file(&hdev->dev, &dev_attr_operation_mode_delay); | ||
2548 | err_cleanup_hid_ll: | ||
2549 | hdev->ll_driver->close(hdev); | ||
2550 | err_cleanup_hid_hw: | ||
2551 | hid_hw_stop(hdev); | ||
2552 | err_cleanup_data: | ||
2553 | kfree(data); | ||
2554 | err_no_cleanup: | ||
2555 | hid_set_drvdata(hdev, NULL); | ||
2556 | |||
2557 | return error; | ||
2558 | } | ||
2559 | |||
2560 | static void picolcd_remove(struct hid_device *hdev) | ||
2561 | { | ||
2562 | struct picolcd_data *data = hid_get_drvdata(hdev); | ||
2563 | unsigned long flags; | ||
2564 | |||
2565 | dbg_hid(PICOLCD_NAME " hardware remove...\n"); | ||
2566 | spin_lock_irqsave(&data->lock, flags); | ||
2567 | data->status |= PICOLCD_FAILED; | ||
2568 | spin_unlock_irqrestore(&data->lock, flags); | ||
2569 | |||
2570 | picolcd_exit_devfs(data); | ||
2571 | device_remove_file(&hdev->dev, &dev_attr_operation_mode); | ||
2572 | device_remove_file(&hdev->dev, &dev_attr_operation_mode_delay); | ||
2573 | hdev->ll_driver->close(hdev); | ||
2574 | hid_hw_stop(hdev); | ||
2575 | hid_set_drvdata(hdev, NULL); | ||
2576 | |||
2577 | /* Shortcut potential pending reply that will never arrive */ | ||
2578 | spin_lock_irqsave(&data->lock, flags); | ||
2579 | if (data->pending) | ||
2580 | complete(&data->pending->ready); | ||
2581 | spin_unlock_irqrestore(&data->lock, flags); | ||
2582 | |||
2583 | /* Cleanup LED */ | ||
2584 | picolcd_exit_leds(data); | ||
2585 | /* Clean up the framebuffer */ | ||
2586 | picolcd_exit_backlight(data); | ||
2587 | picolcd_exit_lcd(data); | ||
2588 | picolcd_exit_framebuffer(data); | ||
2589 | /* Cleanup input */ | ||
2590 | picolcd_exit_cir(data); | ||
2591 | picolcd_exit_keys(data); | ||
2592 | |||
2593 | mutex_destroy(&data->mutex); | ||
2594 | /* Finally, clean up the picolcd data itself */ | ||
2595 | kfree(data); | ||
2596 | } | ||
2597 | |||
2598 | static const struct hid_device_id picolcd_devices[] = { | ||
2599 | { HID_USB_DEVICE(USB_VENDOR_ID_MICROCHIP, USB_DEVICE_ID_PICOLCD) }, | ||
2600 | { HID_USB_DEVICE(USB_VENDOR_ID_MICROCHIP, USB_DEVICE_ID_PICOLCD_BOOTLOADER) }, | ||
2601 | { } | ||
2602 | }; | ||
2603 | MODULE_DEVICE_TABLE(hid, picolcd_devices); | ||
2604 | |||
2605 | static struct hid_driver picolcd_driver = { | ||
2606 | .name = "hid-picolcd", | ||
2607 | .id_table = picolcd_devices, | ||
2608 | .probe = picolcd_probe, | ||
2609 | .remove = picolcd_remove, | ||
2610 | .raw_event = picolcd_raw_event, | ||
2611 | #ifdef CONFIG_PM | ||
2612 | .suspend = picolcd_suspend, | ||
2613 | .resume = picolcd_resume, | ||
2614 | .reset_resume = picolcd_reset_resume, | ||
2615 | #endif | ||
2616 | }; | ||
2617 | |||
2618 | static int __init picolcd_init(void) | ||
2619 | { | ||
2620 | return hid_register_driver(&picolcd_driver); | ||
2621 | } | ||
2622 | |||
2623 | static void __exit picolcd_exit(void) | ||
2624 | { | ||
2625 | hid_unregister_driver(&picolcd_driver); | ||
2626 | } | ||
2627 | |||
2628 | module_init(picolcd_init); | ||
2629 | module_exit(picolcd_exit); | ||
2630 | MODULE_DESCRIPTION("Minibox graphics PicoLCD Driver"); | ||
2631 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/hid/hid-prodikeys.c b/drivers/hid/hid-prodikeys.c new file mode 100644 index 000000000000..845f428b8090 --- /dev/null +++ b/drivers/hid/hid-prodikeys.c | |||
@@ -0,0 +1,910 @@ | |||
1 | /* | ||
2 | * HID driver for the Prodikeys PC-MIDI Keyboard | ||
3 | * providing midi & extra multimedia keys functionality | ||
4 | * | ||
5 | * Copyright (c) 2009 Don Prince <dhprince.devel@yahoo.co.uk> | ||
6 | * | ||
7 | * Controls for Octave Shift Up/Down, Channel, and | ||
8 | * Sustain Duration available via sysfs. | ||
9 | * | ||
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/module.h> | ||
21 | #include <linux/usb.h> | ||
22 | #include <linux/mutex.h> | ||
23 | #include <linux/hid.h> | ||
24 | #include <sound/core.h> | ||
25 | #include <sound/initval.h> | ||
26 | #include <sound/rawmidi.h> | ||
27 | #include "usbhid/usbhid.h" | ||
28 | #include "hid-ids.h" | ||
29 | |||
30 | |||
31 | #define pk_debug(format, arg...) \ | ||
32 | pr_debug("hid-prodikeys: " format "\n" , ## arg) | ||
33 | #define pk_error(format, arg...) \ | ||
34 | pr_err("hid-prodikeys: " format "\n" , ## arg) | ||
35 | |||
36 | struct pcmidi_snd; | ||
37 | |||
38 | struct pk_device { | ||
39 | unsigned long quirks; | ||
40 | |||
41 | struct hid_device *hdev; | ||
42 | struct pcmidi_snd *pm; /* pcmidi device context */ | ||
43 | }; | ||
44 | |||
45 | struct pcmidi_snd; | ||
46 | |||
47 | struct pcmidi_sustain { | ||
48 | unsigned long in_use; | ||
49 | struct pcmidi_snd *pm; | ||
50 | struct timer_list timer; | ||
51 | unsigned char status; | ||
52 | unsigned char note; | ||
53 | unsigned char velocity; | ||
54 | }; | ||
55 | |||
56 | #define PCMIDI_SUSTAINED_MAX 32 | ||
57 | struct pcmidi_snd { | ||
58 | struct pk_device *pk; | ||
59 | unsigned short ifnum; | ||
60 | struct hid_report *pcmidi_report6; | ||
61 | struct input_dev *input_ep82; | ||
62 | unsigned short midi_mode; | ||
63 | unsigned short midi_sustain_mode; | ||
64 | unsigned short midi_sustain; | ||
65 | unsigned short midi_channel; | ||
66 | short midi_octave; | ||
67 | struct pcmidi_sustain sustained_notes[PCMIDI_SUSTAINED_MAX]; | ||
68 | unsigned short fn_state; | ||
69 | unsigned short last_key[24]; | ||
70 | spinlock_t rawmidi_in_lock; | ||
71 | struct snd_card *card; | ||
72 | struct snd_rawmidi *rwmidi; | ||
73 | struct snd_rawmidi_substream *in_substream; | ||
74 | struct snd_rawmidi_substream *out_substream; | ||
75 | unsigned long in_triggered; | ||
76 | unsigned long out_active; | ||
77 | }; | ||
78 | |||
79 | #define PK_QUIRK_NOGET 0x00010000 | ||
80 | #define PCMIDI_MIDDLE_C 60 | ||
81 | #define PCMIDI_CHANNEL_MIN 0 | ||
82 | #define PCMIDI_CHANNEL_MAX 15 | ||
83 | #define PCMIDI_OCTAVE_MIN (-2) | ||
84 | #define PCMIDI_OCTAVE_MAX 2 | ||
85 | #define PCMIDI_SUSTAIN_MIN 0 | ||
86 | #define PCMIDI_SUSTAIN_MAX 5000 | ||
87 | |||
88 | static const char shortname[] = "PC-MIDI"; | ||
89 | static const char longname[] = "Prodikeys PC-MIDI Keyboard"; | ||
90 | |||
91 | static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; | ||
92 | static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; | ||
93 | static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; | ||
94 | |||
95 | module_param_array(index, int, NULL, 0444); | ||
96 | module_param_array(id, charp, NULL, 0444); | ||
97 | module_param_array(enable, bool, NULL, 0444); | ||
98 | MODULE_PARM_DESC(index, "Index value for the PC-MIDI virtual audio driver"); | ||
99 | MODULE_PARM_DESC(id, "ID string for the PC-MIDI virtual audio driver"); | ||
100 | MODULE_PARM_DESC(enable, "Enable for the PC-MIDI virtual audio driver"); | ||
101 | |||
102 | |||
103 | /* Output routine for the sysfs channel file */ | ||
104 | static ssize_t show_channel(struct device *dev, | ||
105 | struct device_attribute *attr, char *buf) | ||
106 | { | ||
107 | struct hid_device *hdev = container_of(dev, struct hid_device, dev); | ||
108 | struct pk_device *pk = (struct pk_device *)hid_get_drvdata(hdev); | ||
109 | |||
110 | dbg_hid("pcmidi sysfs read channel=%u\n", pk->pm->midi_channel); | ||
111 | |||
112 | return sprintf(buf, "%u (min:%u, max:%u)\n", pk->pm->midi_channel, | ||
113 | PCMIDI_CHANNEL_MIN, PCMIDI_CHANNEL_MAX); | ||
114 | } | ||
115 | |||
116 | /* Input routine for the sysfs channel file */ | ||
117 | static ssize_t store_channel(struct device *dev, | ||
118 | struct device_attribute *attr, const char *buf, size_t count) | ||
119 | { | ||
120 | struct hid_device *hdev = container_of(dev, struct hid_device, dev); | ||
121 | struct pk_device *pk = (struct pk_device *)hid_get_drvdata(hdev); | ||
122 | |||
123 | unsigned channel = 0; | ||
124 | |||
125 | if (sscanf(buf, "%u", &channel) > 0 && channel <= PCMIDI_CHANNEL_MAX) { | ||
126 | dbg_hid("pcmidi sysfs write channel=%u\n", channel); | ||
127 | pk->pm->midi_channel = channel; | ||
128 | return strlen(buf); | ||
129 | } | ||
130 | return -EINVAL; | ||
131 | } | ||
132 | |||
133 | static DEVICE_ATTR(channel, S_IRUGO | S_IWUGO, show_channel, | ||
134 | store_channel); | ||
135 | |||
136 | static struct device_attribute *sysfs_device_attr_channel = { | ||
137 | &dev_attr_channel, | ||
138 | }; | ||
139 | |||
140 | /* Output routine for the sysfs sustain file */ | ||
141 | static ssize_t show_sustain(struct device *dev, | ||
142 | struct device_attribute *attr, char *buf) | ||
143 | { | ||
144 | struct hid_device *hdev = container_of(dev, struct hid_device, dev); | ||
145 | struct pk_device *pk = (struct pk_device *)hid_get_drvdata(hdev); | ||
146 | |||
147 | dbg_hid("pcmidi sysfs read sustain=%u\n", pk->pm->midi_sustain); | ||
148 | |||
149 | return sprintf(buf, "%u (off:%u, max:%u (ms))\n", pk->pm->midi_sustain, | ||
150 | PCMIDI_SUSTAIN_MIN, PCMIDI_SUSTAIN_MAX); | ||
151 | } | ||
152 | |||
153 | /* Input routine for the sysfs sustain file */ | ||
154 | static ssize_t store_sustain(struct device *dev, | ||
155 | struct device_attribute *attr, const char *buf, size_t count) | ||
156 | { | ||
157 | struct hid_device *hdev = container_of(dev, struct hid_device, dev); | ||
158 | struct pk_device *pk = (struct pk_device *)hid_get_drvdata(hdev); | ||
159 | |||
160 | unsigned sustain = 0; | ||
161 | |||
162 | if (sscanf(buf, "%u", &sustain) > 0 && sustain <= PCMIDI_SUSTAIN_MAX) { | ||
163 | dbg_hid("pcmidi sysfs write sustain=%u\n", sustain); | ||
164 | pk->pm->midi_sustain = sustain; | ||
165 | pk->pm->midi_sustain_mode = | ||
166 | (0 == sustain || !pk->pm->midi_mode) ? 0 : 1; | ||
167 | return strlen(buf); | ||
168 | } | ||
169 | return -EINVAL; | ||
170 | } | ||
171 | |||
172 | static DEVICE_ATTR(sustain, S_IRUGO | S_IWUGO, show_sustain, | ||
173 | store_sustain); | ||
174 | |||
175 | static struct device_attribute *sysfs_device_attr_sustain = { | ||
176 | &dev_attr_sustain, | ||
177 | }; | ||
178 | |||
179 | /* Output routine for the sysfs octave file */ | ||
180 | static ssize_t show_octave(struct device *dev, | ||
181 | struct device_attribute *attr, char *buf) | ||
182 | { | ||
183 | struct hid_device *hdev = container_of(dev, struct hid_device, dev); | ||
184 | struct pk_device *pk = (struct pk_device *)hid_get_drvdata(hdev); | ||
185 | |||
186 | dbg_hid("pcmidi sysfs read octave=%d\n", pk->pm->midi_octave); | ||
187 | |||
188 | return sprintf(buf, "%d (min:%d, max:%d)\n", pk->pm->midi_octave, | ||
189 | PCMIDI_OCTAVE_MIN, PCMIDI_OCTAVE_MAX); | ||
190 | } | ||
191 | |||
192 | /* Input routine for the sysfs octave file */ | ||
193 | static ssize_t store_octave(struct device *dev, | ||
194 | struct device_attribute *attr, const char *buf, size_t count) | ||
195 | { | ||
196 | struct hid_device *hdev = container_of(dev, struct hid_device, dev); | ||
197 | struct pk_device *pk = (struct pk_device *)hid_get_drvdata(hdev); | ||
198 | |||
199 | int octave = 0; | ||
200 | |||
201 | if (sscanf(buf, "%d", &octave) > 0 && | ||
202 | octave >= PCMIDI_OCTAVE_MIN && octave <= PCMIDI_OCTAVE_MAX) { | ||
203 | dbg_hid("pcmidi sysfs write octave=%d\n", octave); | ||
204 | pk->pm->midi_octave = octave; | ||
205 | return strlen(buf); | ||
206 | } | ||
207 | return -EINVAL; | ||
208 | } | ||
209 | |||
210 | static DEVICE_ATTR(octave, S_IRUGO | S_IWUGO, show_octave, | ||
211 | store_octave); | ||
212 | |||
213 | static struct device_attribute *sysfs_device_attr_octave = { | ||
214 | &dev_attr_octave, | ||
215 | }; | ||
216 | |||
217 | |||
218 | static void pcmidi_send_note(struct pcmidi_snd *pm, | ||
219 | unsigned char status, unsigned char note, unsigned char velocity) | ||
220 | { | ||
221 | unsigned long flags; | ||
222 | unsigned char buffer[3]; | ||
223 | |||
224 | buffer[0] = status; | ||
225 | buffer[1] = note; | ||
226 | buffer[2] = velocity; | ||
227 | |||
228 | spin_lock_irqsave(&pm->rawmidi_in_lock, flags); | ||
229 | |||
230 | if (!pm->in_substream) | ||
231 | goto drop_note; | ||
232 | if (!test_bit(pm->in_substream->number, &pm->in_triggered)) | ||
233 | goto drop_note; | ||
234 | |||
235 | snd_rawmidi_receive(pm->in_substream, buffer, 3); | ||
236 | |||
237 | drop_note: | ||
238 | spin_unlock_irqrestore(&pm->rawmidi_in_lock, flags); | ||
239 | |||
240 | return; | ||
241 | } | ||
242 | |||
243 | void pcmidi_sustained_note_release(unsigned long data) | ||
244 | { | ||
245 | struct pcmidi_sustain *pms = (struct pcmidi_sustain *)data; | ||
246 | |||
247 | pcmidi_send_note(pms->pm, pms->status, pms->note, pms->velocity); | ||
248 | pms->in_use = 0; | ||
249 | } | ||
250 | |||
251 | void init_sustain_timers(struct pcmidi_snd *pm) | ||
252 | { | ||
253 | struct pcmidi_sustain *pms; | ||
254 | unsigned i; | ||
255 | |||
256 | for (i = 0; i < PCMIDI_SUSTAINED_MAX; i++) { | ||
257 | pms = &pm->sustained_notes[i]; | ||
258 | pms->in_use = 0; | ||
259 | pms->pm = pm; | ||
260 | setup_timer(&pms->timer, pcmidi_sustained_note_release, | ||
261 | (unsigned long)pms); | ||
262 | } | ||
263 | } | ||
264 | |||
265 | void stop_sustain_timers(struct pcmidi_snd *pm) | ||
266 | { | ||
267 | struct pcmidi_sustain *pms; | ||
268 | unsigned i; | ||
269 | |||
270 | for (i = 0; i < PCMIDI_SUSTAINED_MAX; i++) { | ||
271 | pms = &pm->sustained_notes[i]; | ||
272 | pms->in_use = 1; | ||
273 | del_timer_sync(&pms->timer); | ||
274 | } | ||
275 | } | ||
276 | |||
277 | static int pcmidi_get_output_report(struct pcmidi_snd *pm) | ||
278 | { | ||
279 | struct hid_device *hdev = pm->pk->hdev; | ||
280 | struct hid_report *report; | ||
281 | |||
282 | list_for_each_entry(report, | ||
283 | &hdev->report_enum[HID_OUTPUT_REPORT].report_list, list) { | ||
284 | if (!(6 == report->id)) | ||
285 | continue; | ||
286 | |||
287 | if (report->maxfield < 1) { | ||
288 | dev_err(&hdev->dev, "output report is empty\n"); | ||
289 | break; | ||
290 | } | ||
291 | if (report->field[0]->report_count != 2) { | ||
292 | dev_err(&hdev->dev, "field count too low\n"); | ||
293 | break; | ||
294 | } | ||
295 | pm->pcmidi_report6 = report; | ||
296 | return 0; | ||
297 | } | ||
298 | /* should never get here */ | ||
299 | return -ENODEV; | ||
300 | } | ||
301 | |||
302 | static void pcmidi_submit_output_report(struct pcmidi_snd *pm, int state) | ||
303 | { | ||
304 | struct hid_device *hdev = pm->pk->hdev; | ||
305 | struct hid_report *report = pm->pcmidi_report6; | ||
306 | report->field[0]->value[0] = 0x01; | ||
307 | report->field[0]->value[1] = state; | ||
308 | |||
309 | usbhid_submit_report(hdev, report, USB_DIR_OUT); | ||
310 | } | ||
311 | |||
312 | static int pcmidi_handle_report1(struct pcmidi_snd *pm, u8 *data) | ||
313 | { | ||
314 | u32 bit_mask; | ||
315 | |||
316 | bit_mask = data[1]; | ||
317 | bit_mask = (bit_mask << 8) | data[2]; | ||
318 | bit_mask = (bit_mask << 8) | data[3]; | ||
319 | |||
320 | dbg_hid("pcmidi mode: %d\n", pm->midi_mode); | ||
321 | |||
322 | /*KEY_MAIL or octave down*/ | ||
323 | if (pm->midi_mode && bit_mask == 0x004000) { | ||
324 | /* octave down */ | ||
325 | pm->midi_octave--; | ||
326 | if (pm->midi_octave < -2) | ||
327 | pm->midi_octave = -2; | ||
328 | dbg_hid("pcmidi mode: %d octave: %d\n", | ||
329 | pm->midi_mode, pm->midi_octave); | ||
330 | return 1; | ||
331 | } | ||
332 | /*KEY_WWW or sustain*/ | ||
333 | else if (pm->midi_mode && bit_mask == 0x000004) { | ||
334 | /* sustain on/off*/ | ||
335 | pm->midi_sustain_mode ^= 0x1; | ||
336 | return 1; | ||
337 | } | ||
338 | |||
339 | return 0; /* continue key processing */ | ||
340 | } | ||
341 | |||
342 | static int pcmidi_handle_report3(struct pcmidi_snd *pm, u8 *data, int size) | ||
343 | { | ||
344 | struct pcmidi_sustain *pms; | ||
345 | unsigned i, j; | ||
346 | unsigned char status, note, velocity; | ||
347 | |||
348 | unsigned num_notes = (size-1)/2; | ||
349 | for (j = 0; j < num_notes; j++) { | ||
350 | note = data[j*2+1]; | ||
351 | velocity = data[j*2+2]; | ||
352 | |||
353 | if (note < 0x81) { /* note on */ | ||
354 | status = 128 + 16 + pm->midi_channel; /* 1001nnnn */ | ||
355 | note = note - 0x54 + PCMIDI_MIDDLE_C + | ||
356 | (pm->midi_octave * 12); | ||
357 | if (0 == velocity) | ||
358 | velocity = 1; /* force note on */ | ||
359 | } else { /* note off */ | ||
360 | status = 128 + pm->midi_channel; /* 1000nnnn */ | ||
361 | note = note - 0x94 + PCMIDI_MIDDLE_C + | ||
362 | (pm->midi_octave*12); | ||
363 | |||
364 | if (pm->midi_sustain_mode) { | ||
365 | for (i = 0; i < PCMIDI_SUSTAINED_MAX; i++) { | ||
366 | pms = &pm->sustained_notes[i]; | ||
367 | if (!pms->in_use) { | ||
368 | pms->status = status; | ||
369 | pms->note = note; | ||
370 | pms->velocity = velocity; | ||
371 | pms->in_use = 1; | ||
372 | |||
373 | mod_timer(&pms->timer, | ||
374 | jiffies + | ||
375 | msecs_to_jiffies(pm->midi_sustain)); | ||
376 | return 1; | ||
377 | } | ||
378 | } | ||
379 | } | ||
380 | } | ||
381 | pcmidi_send_note(pm, status, note, velocity); | ||
382 | } | ||
383 | |||
384 | return 1; | ||
385 | } | ||
386 | |||
387 | static int pcmidi_handle_report4(struct pcmidi_snd *pm, u8 *data) | ||
388 | { | ||
389 | unsigned key; | ||
390 | u32 bit_mask; | ||
391 | u32 bit_index; | ||
392 | |||
393 | bit_mask = data[1]; | ||
394 | bit_mask = (bit_mask << 8) | data[2]; | ||
395 | bit_mask = (bit_mask << 8) | data[3]; | ||
396 | |||
397 | /* break keys */ | ||
398 | for (bit_index = 0; bit_index < 24; bit_index++) { | ||
399 | key = pm->last_key[bit_index]; | ||
400 | if (!((0x01 << bit_index) & bit_mask)) { | ||
401 | input_event(pm->input_ep82, EV_KEY, | ||
402 | pm->last_key[bit_index], 0); | ||
403 | pm->last_key[bit_index] = 0; | ||
404 | } | ||
405 | } | ||
406 | |||
407 | /* make keys */ | ||
408 | for (bit_index = 0; bit_index < 24; bit_index++) { | ||
409 | key = 0; | ||
410 | switch ((0x01 << bit_index) & bit_mask) { | ||
411 | case 0x000010: /* Fn lock*/ | ||
412 | pm->fn_state ^= 0x000010; | ||
413 | if (pm->fn_state) | ||
414 | pcmidi_submit_output_report(pm, 0xc5); | ||
415 | else | ||
416 | pcmidi_submit_output_report(pm, 0xc6); | ||
417 | continue; | ||
418 | case 0x020000: /* midi launcher..send a key (qwerty) or not? */ | ||
419 | pcmidi_submit_output_report(pm, 0xc1); | ||
420 | pm->midi_mode ^= 0x01; | ||
421 | |||
422 | dbg_hid("pcmidi mode: %d\n", pm->midi_mode); | ||
423 | continue; | ||
424 | case 0x100000: /* KEY_MESSENGER or octave up */ | ||
425 | dbg_hid("pcmidi mode: %d\n", pm->midi_mode); | ||
426 | if (pm->midi_mode) { | ||
427 | pm->midi_octave++; | ||
428 | if (pm->midi_octave > 2) | ||
429 | pm->midi_octave = 2; | ||
430 | dbg_hid("pcmidi mode: %d octave: %d\n", | ||
431 | pm->midi_mode, pm->midi_octave); | ||
432 | continue; | ||
433 | } else | ||
434 | key = KEY_MESSENGER; | ||
435 | break; | ||
436 | case 0x400000: | ||
437 | key = KEY_CALENDAR; | ||
438 | break; | ||
439 | case 0x080000: | ||
440 | key = KEY_ADDRESSBOOK; | ||
441 | break; | ||
442 | case 0x040000: | ||
443 | key = KEY_DOCUMENTS; | ||
444 | break; | ||
445 | case 0x800000: | ||
446 | key = KEY_WORDPROCESSOR; | ||
447 | break; | ||
448 | case 0x200000: | ||
449 | key = KEY_SPREADSHEET; | ||
450 | break; | ||
451 | case 0x010000: | ||
452 | key = KEY_COFFEE; | ||
453 | break; | ||
454 | case 0x000100: | ||
455 | key = KEY_HELP; | ||
456 | break; | ||
457 | case 0x000200: | ||
458 | key = KEY_SEND; | ||
459 | break; | ||
460 | case 0x000400: | ||
461 | key = KEY_REPLY; | ||
462 | break; | ||
463 | case 0x000800: | ||
464 | key = KEY_FORWARDMAIL; | ||
465 | break; | ||
466 | case 0x001000: | ||
467 | key = KEY_NEW; | ||
468 | break; | ||
469 | case 0x002000: | ||
470 | key = KEY_OPEN; | ||
471 | break; | ||
472 | case 0x004000: | ||
473 | key = KEY_CLOSE; | ||
474 | break; | ||
475 | case 0x008000: | ||
476 | key = KEY_SAVE; | ||
477 | break; | ||
478 | case 0x000001: | ||
479 | key = KEY_UNDO; | ||
480 | break; | ||
481 | case 0x000002: | ||
482 | key = KEY_REDO; | ||
483 | break; | ||
484 | case 0x000004: | ||
485 | key = KEY_SPELLCHECK; | ||
486 | break; | ||
487 | case 0x000008: | ||
488 | key = KEY_PRINT; | ||
489 | break; | ||
490 | } | ||
491 | if (key) { | ||
492 | input_event(pm->input_ep82, EV_KEY, key, 1); | ||
493 | pm->last_key[bit_index] = key; | ||
494 | } | ||
495 | } | ||
496 | |||
497 | return 1; | ||
498 | } | ||
499 | |||
500 | int pcmidi_handle_report( | ||
501 | struct pcmidi_snd *pm, unsigned report_id, u8 *data, int size) | ||
502 | { | ||
503 | int ret = 0; | ||
504 | |||
505 | switch (report_id) { | ||
506 | case 0x01: /* midi keys (qwerty)*/ | ||
507 | ret = pcmidi_handle_report1(pm, data); | ||
508 | break; | ||
509 | case 0x03: /* midi keyboard (musical)*/ | ||
510 | ret = pcmidi_handle_report3(pm, data, size); | ||
511 | break; | ||
512 | case 0x04: /* multimedia/midi keys (qwerty)*/ | ||
513 | ret = pcmidi_handle_report4(pm, data); | ||
514 | break; | ||
515 | } | ||
516 | return ret; | ||
517 | } | ||
518 | |||
519 | void pcmidi_setup_extra_keys(struct pcmidi_snd *pm, struct input_dev *input) | ||
520 | { | ||
521 | /* reassigned functionality for N/A keys | ||
522 | MY PICTURES => KEY_WORDPROCESSOR | ||
523 | MY MUSIC=> KEY_SPREADSHEET | ||
524 | */ | ||
525 | unsigned int keys[] = { | ||
526 | KEY_FN, | ||
527 | KEY_MESSENGER, KEY_CALENDAR, | ||
528 | KEY_ADDRESSBOOK, KEY_DOCUMENTS, | ||
529 | KEY_WORDPROCESSOR, | ||
530 | KEY_SPREADSHEET, | ||
531 | KEY_COFFEE, | ||
532 | KEY_HELP, KEY_SEND, | ||
533 | KEY_REPLY, KEY_FORWARDMAIL, | ||
534 | KEY_NEW, KEY_OPEN, | ||
535 | KEY_CLOSE, KEY_SAVE, | ||
536 | KEY_UNDO, KEY_REDO, | ||
537 | KEY_SPELLCHECK, KEY_PRINT, | ||
538 | 0 | ||
539 | }; | ||
540 | |||
541 | unsigned int *pkeys = &keys[0]; | ||
542 | unsigned short i; | ||
543 | |||
544 | if (pm->ifnum != 1) /* only set up ONCE for interace 1 */ | ||
545 | return; | ||
546 | |||
547 | pm->input_ep82 = input; | ||
548 | |||
549 | for (i = 0; i < 24; i++) | ||
550 | pm->last_key[i] = 0; | ||
551 | |||
552 | while (*pkeys != 0) { | ||
553 | set_bit(*pkeys, pm->input_ep82->keybit); | ||
554 | ++pkeys; | ||
555 | } | ||
556 | } | ||
557 | |||
558 | static int pcmidi_set_operational(struct pcmidi_snd *pm) | ||
559 | { | ||
560 | if (pm->ifnum != 1) | ||
561 | return 0; /* only set up ONCE for interace 1 */ | ||
562 | |||
563 | pcmidi_get_output_report(pm); | ||
564 | pcmidi_submit_output_report(pm, 0xc1); | ||
565 | return 0; | ||
566 | } | ||
567 | |||
568 | static int pcmidi_snd_free(struct snd_device *dev) | ||
569 | { | ||
570 | return 0; | ||
571 | } | ||
572 | |||
573 | static int pcmidi_in_open(struct snd_rawmidi_substream *substream) | ||
574 | { | ||
575 | struct pcmidi_snd *pm = substream->rmidi->private_data; | ||
576 | |||
577 | dbg_hid("pcmidi in open\n"); | ||
578 | pm->in_substream = substream; | ||
579 | return 0; | ||
580 | } | ||
581 | |||
582 | static int pcmidi_in_close(struct snd_rawmidi_substream *substream) | ||
583 | { | ||
584 | dbg_hid("pcmidi in close\n"); | ||
585 | return 0; | ||
586 | } | ||
587 | |||
588 | static void pcmidi_in_trigger(struct snd_rawmidi_substream *substream, int up) | ||
589 | { | ||
590 | struct pcmidi_snd *pm = substream->rmidi->private_data; | ||
591 | |||
592 | dbg_hid("pcmidi in trigger %d\n", up); | ||
593 | |||
594 | pm->in_triggered = up; | ||
595 | } | ||
596 | |||
597 | static struct snd_rawmidi_ops pcmidi_in_ops = { | ||
598 | .open = pcmidi_in_open, | ||
599 | .close = pcmidi_in_close, | ||
600 | .trigger = pcmidi_in_trigger | ||
601 | }; | ||
602 | |||
603 | int pcmidi_snd_initialise(struct pcmidi_snd *pm) | ||
604 | { | ||
605 | static int dev; | ||
606 | struct snd_card *card; | ||
607 | struct snd_rawmidi *rwmidi; | ||
608 | int err; | ||
609 | |||
610 | static struct snd_device_ops ops = { | ||
611 | .dev_free = pcmidi_snd_free, | ||
612 | }; | ||
613 | |||
614 | if (pm->ifnum != 1) | ||
615 | return 0; /* only set up midi device ONCE for interace 1 */ | ||
616 | |||
617 | if (dev >= SNDRV_CARDS) | ||
618 | return -ENODEV; | ||
619 | |||
620 | if (!enable[dev]) { | ||
621 | dev++; | ||
622 | return -ENOENT; | ||
623 | } | ||
624 | |||
625 | /* Setup sound card */ | ||
626 | |||
627 | err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card); | ||
628 | if (err < 0) { | ||
629 | pk_error("failed to create pc-midi sound card\n"); | ||
630 | err = -ENOMEM; | ||
631 | goto fail; | ||
632 | } | ||
633 | pm->card = card; | ||
634 | |||
635 | /* Setup sound device */ | ||
636 | err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, pm, &ops); | ||
637 | if (err < 0) { | ||
638 | pk_error("failed to create pc-midi sound device: error %d\n", | ||
639 | err); | ||
640 | goto fail; | ||
641 | } | ||
642 | |||
643 | strncpy(card->driver, shortname, sizeof(card->driver)); | ||
644 | strncpy(card->shortname, shortname, sizeof(card->shortname)); | ||
645 | strncpy(card->longname, longname, sizeof(card->longname)); | ||
646 | |||
647 | /* Set up rawmidi */ | ||
648 | err = snd_rawmidi_new(card, card->shortname, 0, | ||
649 | 0, 1, &rwmidi); | ||
650 | if (err < 0) { | ||
651 | pk_error("failed to create pc-midi rawmidi device: error %d\n", | ||
652 | err); | ||
653 | goto fail; | ||
654 | } | ||
655 | pm->rwmidi = rwmidi; | ||
656 | strncpy(rwmidi->name, card->shortname, sizeof(rwmidi->name)); | ||
657 | rwmidi->info_flags = SNDRV_RAWMIDI_INFO_INPUT; | ||
658 | rwmidi->private_data = pm; | ||
659 | |||
660 | snd_rawmidi_set_ops(rwmidi, SNDRV_RAWMIDI_STREAM_INPUT, | ||
661 | &pcmidi_in_ops); | ||
662 | |||
663 | snd_card_set_dev(card, &pm->pk->hdev->dev); | ||
664 | |||
665 | /* create sysfs variables */ | ||
666 | err = device_create_file(&pm->pk->hdev->dev, | ||
667 | sysfs_device_attr_channel); | ||
668 | if (err < 0) { | ||
669 | pk_error("failed to create sysfs attribute channel: error %d\n", | ||
670 | err); | ||
671 | goto fail; | ||
672 | } | ||
673 | |||
674 | err = device_create_file(&pm->pk->hdev->dev, | ||
675 | sysfs_device_attr_sustain); | ||
676 | if (err < 0) { | ||
677 | pk_error("failed to create sysfs attribute sustain: error %d\n", | ||
678 | err); | ||
679 | goto fail_attr_sustain; | ||
680 | } | ||
681 | |||
682 | err = device_create_file(&pm->pk->hdev->dev, | ||
683 | sysfs_device_attr_octave); | ||
684 | if (err < 0) { | ||
685 | pk_error("failed to create sysfs attribute octave: error %d\n", | ||
686 | err); | ||
687 | goto fail_attr_octave; | ||
688 | } | ||
689 | |||
690 | spin_lock_init(&pm->rawmidi_in_lock); | ||
691 | |||
692 | init_sustain_timers(pm); | ||
693 | pcmidi_set_operational(pm); | ||
694 | |||
695 | /* register it */ | ||
696 | err = snd_card_register(card); | ||
697 | if (err < 0) { | ||
698 | pk_error("failed to register pc-midi sound card: error %d\n", | ||
699 | err); | ||
700 | goto fail_register; | ||
701 | } | ||
702 | |||
703 | dbg_hid("pcmidi_snd_initialise finished ok\n"); | ||
704 | return 0; | ||
705 | |||
706 | fail_register: | ||
707 | stop_sustain_timers(pm); | ||
708 | device_remove_file(&pm->pk->hdev->dev, sysfs_device_attr_octave); | ||
709 | fail_attr_octave: | ||
710 | device_remove_file(&pm->pk->hdev->dev, sysfs_device_attr_sustain); | ||
711 | fail_attr_sustain: | ||
712 | device_remove_file(&pm->pk->hdev->dev, sysfs_device_attr_channel); | ||
713 | fail: | ||
714 | if (pm->card) { | ||
715 | snd_card_free(pm->card); | ||
716 | pm->card = NULL; | ||
717 | } | ||
718 | return err; | ||
719 | } | ||
720 | |||
721 | int pcmidi_snd_terminate(struct pcmidi_snd *pm) | ||
722 | { | ||
723 | if (pm->card) { | ||
724 | stop_sustain_timers(pm); | ||
725 | |||
726 | device_remove_file(&pm->pk->hdev->dev, | ||
727 | sysfs_device_attr_channel); | ||
728 | device_remove_file(&pm->pk->hdev->dev, | ||
729 | sysfs_device_attr_sustain); | ||
730 | device_remove_file(&pm->pk->hdev->dev, | ||
731 | sysfs_device_attr_octave); | ||
732 | |||
733 | snd_card_disconnect(pm->card); | ||
734 | snd_card_free_when_closed(pm->card); | ||
735 | } | ||
736 | |||
737 | return 0; | ||
738 | } | ||
739 | |||
740 | /* | ||
741 | * PC-MIDI report descriptor for report id is wrong. | ||
742 | */ | ||
743 | static void pk_report_fixup(struct hid_device *hdev, __u8 *rdesc, | ||
744 | unsigned int rsize) | ||
745 | { | ||
746 | if (rsize == 178 && | ||
747 | rdesc[111] == 0x06 && rdesc[112] == 0x00 && | ||
748 | rdesc[113] == 0xff) { | ||
749 | dev_info(&hdev->dev, "fixing up pc-midi keyboard report " | ||
750 | "descriptor\n"); | ||
751 | |||
752 | rdesc[144] = 0x18; /* report 4: was 0x10 report count */ | ||
753 | } | ||
754 | } | ||
755 | |||
756 | static int pk_input_mapping(struct hid_device *hdev, struct hid_input *hi, | ||
757 | struct hid_field *field, struct hid_usage *usage, | ||
758 | unsigned long **bit, int *max) | ||
759 | { | ||
760 | struct pk_device *pk = (struct pk_device *)hid_get_drvdata(hdev); | ||
761 | struct pcmidi_snd *pm; | ||
762 | |||
763 | pm = pk->pm; | ||
764 | |||
765 | if (HID_UP_MSVENDOR == (usage->hid & HID_USAGE_PAGE) && | ||
766 | 1 == pm->ifnum) { | ||
767 | pcmidi_setup_extra_keys(pm, hi->input); | ||
768 | return 0; | ||
769 | } | ||
770 | |||
771 | return 0; | ||
772 | } | ||
773 | |||
774 | |||
775 | static int pk_raw_event(struct hid_device *hdev, struct hid_report *report, | ||
776 | u8 *data, int size) | ||
777 | { | ||
778 | struct pk_device *pk = (struct pk_device *)hid_get_drvdata(hdev); | ||
779 | int ret = 0; | ||
780 | |||
781 | if (1 == pk->pm->ifnum) { | ||
782 | if (report->id == data[0]) | ||
783 | switch (report->id) { | ||
784 | case 0x01: /* midi keys (qwerty)*/ | ||
785 | case 0x03: /* midi keyboard (musical)*/ | ||
786 | case 0x04: /* extra/midi keys (qwerty)*/ | ||
787 | ret = pcmidi_handle_report(pk->pm, | ||
788 | report->id, data, size); | ||
789 | break; | ||
790 | } | ||
791 | } | ||
792 | |||
793 | return ret; | ||
794 | } | ||
795 | |||
796 | static int pk_probe(struct hid_device *hdev, const struct hid_device_id *id) | ||
797 | { | ||
798 | int ret; | ||
799 | struct usb_interface *intf = to_usb_interface(hdev->dev.parent); | ||
800 | unsigned short ifnum = intf->cur_altsetting->desc.bInterfaceNumber; | ||
801 | unsigned long quirks = id->driver_data; | ||
802 | struct pk_device *pk; | ||
803 | struct pcmidi_snd *pm = NULL; | ||
804 | |||
805 | pk = kzalloc(sizeof(*pk), GFP_KERNEL); | ||
806 | if (pk == NULL) { | ||
807 | dev_err(&hdev->dev, "prodikeys: can't alloc descriptor\n"); | ||
808 | return -ENOMEM; | ||
809 | } | ||
810 | |||
811 | pk->hdev = hdev; | ||
812 | |||
813 | pm = kzalloc(sizeof(*pm), GFP_KERNEL); | ||
814 | if (pm == NULL) { | ||
815 | dev_err(&hdev->dev, | ||
816 | "prodikeys: can't alloc descriptor\n"); | ||
817 | ret = -ENOMEM; | ||
818 | goto err_free; | ||
819 | } | ||
820 | |||
821 | pm->pk = pk; | ||
822 | pk->pm = pm; | ||
823 | pm->ifnum = ifnum; | ||
824 | |||
825 | hid_set_drvdata(hdev, pk); | ||
826 | |||
827 | ret = hid_parse(hdev); | ||
828 | if (ret) { | ||
829 | dev_err(&hdev->dev, "prodikeys: hid parse failed\n"); | ||
830 | goto err_free; | ||
831 | } | ||
832 | |||
833 | if (quirks & PK_QUIRK_NOGET) { /* hid_parse cleared all the quirks */ | ||
834 | hdev->quirks |= HID_QUIRK_NOGET; | ||
835 | } | ||
836 | |||
837 | ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); | ||
838 | if (ret) { | ||
839 | dev_err(&hdev->dev, "prodikeys: hw start failed\n"); | ||
840 | goto err_free; | ||
841 | } | ||
842 | |||
843 | ret = pcmidi_snd_initialise(pm); | ||
844 | if (ret < 0) | ||
845 | goto err_stop; | ||
846 | |||
847 | return 0; | ||
848 | err_stop: | ||
849 | hid_hw_stop(hdev); | ||
850 | err_free: | ||
851 | if (pm != NULL) | ||
852 | kfree(pm); | ||
853 | |||
854 | kfree(pk); | ||
855 | return ret; | ||
856 | } | ||
857 | |||
858 | static void pk_remove(struct hid_device *hdev) | ||
859 | { | ||
860 | struct pk_device *pk = (struct pk_device *)hid_get_drvdata(hdev); | ||
861 | struct pcmidi_snd *pm; | ||
862 | |||
863 | pm = pk->pm; | ||
864 | if (pm) { | ||
865 | pcmidi_snd_terminate(pm); | ||
866 | kfree(pm); | ||
867 | } | ||
868 | |||
869 | hid_hw_stop(hdev); | ||
870 | |||
871 | kfree(pk); | ||
872 | } | ||
873 | |||
874 | static const struct hid_device_id pk_devices[] = { | ||
875 | {HID_USB_DEVICE(USB_VENDOR_ID_CREATIVELABS, | ||
876 | USB_DEVICE_ID_PRODIKEYS_PCMIDI), | ||
877 | .driver_data = PK_QUIRK_NOGET}, | ||
878 | { } | ||
879 | }; | ||
880 | MODULE_DEVICE_TABLE(hid, pk_devices); | ||
881 | |||
882 | static struct hid_driver pk_driver = { | ||
883 | .name = "prodikeys", | ||
884 | .id_table = pk_devices, | ||
885 | .report_fixup = pk_report_fixup, | ||
886 | .input_mapping = pk_input_mapping, | ||
887 | .raw_event = pk_raw_event, | ||
888 | .probe = pk_probe, | ||
889 | .remove = pk_remove, | ||
890 | }; | ||
891 | |||
892 | static int pk_init(void) | ||
893 | { | ||
894 | int ret; | ||
895 | |||
896 | ret = hid_register_driver(&pk_driver); | ||
897 | if (ret) | ||
898 | printk(KERN_ERR "can't register prodikeys driver\n"); | ||
899 | |||
900 | return ret; | ||
901 | } | ||
902 | |||
903 | static void pk_exit(void) | ||
904 | { | ||
905 | hid_unregister_driver(&pk_driver); | ||
906 | } | ||
907 | |||
908 | module_init(pk_init); | ||
909 | module_exit(pk_exit); | ||
910 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/hid/hid-roccat-kone.c b/drivers/hid/hid-roccat-kone.c new file mode 100644 index 000000000000..66e694054ba2 --- /dev/null +++ b/drivers/hid/hid-roccat-kone.c | |||
@@ -0,0 +1,994 @@ | |||
1 | /* | ||
2 | * Roccat Kone driver for Linux | ||
3 | * | ||
4 | * Copyright (c) 2010 Stefan Achatz <erazor_de@users.sourceforge.net> | ||
5 | */ | ||
6 | |||
7 | /* | ||
8 | * This program is free software; you can redistribute it and/or modify it | ||
9 | * under the terms of the GNU General Public License as published by the Free | ||
10 | * Software Foundation; either version 2 of the License, or (at your option) | ||
11 | * any later version. | ||
12 | */ | ||
13 | |||
14 | /* | ||
15 | * Roccat Kone is a gamer mouse which consists of a mouse part and a keyboard | ||
16 | * part. The keyboard part enables the mouse to execute stored macros with mixed | ||
17 | * key- and button-events. | ||
18 | * | ||
19 | * TODO implement on-the-fly polling-rate change | ||
20 | * The windows driver has the ability to change the polling rate of the | ||
21 | * device on the press of a mousebutton. | ||
22 | * Is it possible to remove and reinstall the urb in raw-event- or any | ||
23 | * other handler, or to defer this action to be executed somewhere else? | ||
24 | * | ||
25 | * TODO implement notification mechanism for overlong macro execution | ||
26 | * If user wants to execute an overlong macro only the names of macroset | ||
27 | * and macro are given. Should userland tap hidraw or is there an | ||
28 | * additional streaming mechanism? | ||
29 | * | ||
30 | * TODO is it possible to overwrite group for sysfs attributes via udev? | ||
31 | */ | ||
32 | |||
33 | #include <linux/device.h> | ||
34 | #include <linux/input.h> | ||
35 | #include <linux/hid.h> | ||
36 | #include <linux/usb.h> | ||
37 | #include <linux/module.h> | ||
38 | #include <linux/slab.h> | ||
39 | #include "hid-ids.h" | ||
40 | #include "hid-roccat-kone.h" | ||
41 | |||
42 | static void kone_set_settings_checksum(struct kone_settings *settings) | ||
43 | { | ||
44 | uint16_t checksum = 0; | ||
45 | unsigned char *address = (unsigned char *)settings; | ||
46 | int i; | ||
47 | |||
48 | for (i = 0; i < sizeof(struct kone_settings) - 2; ++i, ++address) | ||
49 | checksum += *address; | ||
50 | settings->checksum = cpu_to_le16(checksum); | ||
51 | } | ||
52 | |||
53 | /* | ||
54 | * Checks success after writing data to mouse | ||
55 | * On success returns 0 | ||
56 | * On failure returns errno | ||
57 | */ | ||
58 | static int kone_check_write(struct usb_device *usb_dev) | ||
59 | { | ||
60 | int len; | ||
61 | unsigned char *data; | ||
62 | |||
63 | data = kmalloc(1, GFP_KERNEL); | ||
64 | if (!data) | ||
65 | return -ENOMEM; | ||
66 | |||
67 | do { | ||
68 | /* | ||
69 | * Mouse needs 50 msecs until it says ok, but there are | ||
70 | * 30 more msecs needed for next write to work. | ||
71 | */ | ||
72 | msleep(80); | ||
73 | |||
74 | len = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0), | ||
75 | USB_REQ_CLEAR_FEATURE, | ||
76 | USB_TYPE_CLASS | USB_RECIP_INTERFACE | | ||
77 | USB_DIR_IN, | ||
78 | kone_command_confirm_write, 0, data, 1, | ||
79 | USB_CTRL_SET_TIMEOUT); | ||
80 | |||
81 | if (len != 1) { | ||
82 | kfree(data); | ||
83 | return -EIO; | ||
84 | } | ||
85 | |||
86 | /* | ||
87 | * value of 3 seems to mean something like | ||
88 | * "not finished yet, but it looks good" | ||
89 | * So check again after a moment. | ||
90 | */ | ||
91 | } while (*data == 3); | ||
92 | |||
93 | if (*data == 1) { /* everything alright */ | ||
94 | kfree(data); | ||
95 | return 0; | ||
96 | } else { /* unknown answer */ | ||
97 | dev_err(&usb_dev->dev, "got retval %d when checking write\n", | ||
98 | *data); | ||
99 | kfree(data); | ||
100 | return -EIO; | ||
101 | } | ||
102 | } | ||
103 | |||
104 | /* | ||
105 | * Reads settings from mouse and stores it in @buf | ||
106 | * @buf has to be alloced with GFP_KERNEL | ||
107 | * On success returns 0 | ||
108 | * On failure returns errno | ||
109 | */ | ||
110 | static int kone_get_settings(struct usb_device *usb_dev, | ||
111 | struct kone_settings *buf) | ||
112 | { | ||
113 | int len; | ||
114 | |||
115 | len = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0), | ||
116 | USB_REQ_CLEAR_FEATURE, | ||
117 | USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN, | ||
118 | kone_command_settings, 0, buf, | ||
119 | sizeof(struct kone_settings), USB_CTRL_SET_TIMEOUT); | ||
120 | |||
121 | if (len != sizeof(struct kone_settings)) | ||
122 | return -EIO; | ||
123 | |||
124 | return 0; | ||
125 | } | ||
126 | |||
127 | /* | ||
128 | * Writes settings from @buf to mouse | ||
129 | * On success returns 0 | ||
130 | * On failure returns errno | ||
131 | */ | ||
132 | static int kone_set_settings(struct usb_device *usb_dev, | ||
133 | struct kone_settings const *settings) | ||
134 | { | ||
135 | int len; | ||
136 | |||
137 | len = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0), | ||
138 | USB_REQ_SET_CONFIGURATION, | ||
139 | USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT, | ||
140 | kone_command_settings, 0, (char *)settings, | ||
141 | sizeof(struct kone_settings), | ||
142 | USB_CTRL_SET_TIMEOUT); | ||
143 | |||
144 | if (len != sizeof(struct kone_settings)) | ||
145 | return -EIO; | ||
146 | |||
147 | if (kone_check_write(usb_dev)) | ||
148 | return -EIO; | ||
149 | |||
150 | return 0; | ||
151 | } | ||
152 | |||
153 | /* | ||
154 | * Reads profile data from mouse and stores it in @buf | ||
155 | * @number: profile number to read | ||
156 | * On success returns 0 | ||
157 | * On failure returns errno | ||
158 | */ | ||
159 | static int kone_get_profile(struct usb_device *usb_dev, | ||
160 | struct kone_profile *buf, int number) | ||
161 | { | ||
162 | int len; | ||
163 | |||
164 | if (number < 1 || number > 5) | ||
165 | return -EINVAL; | ||
166 | |||
167 | len = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0), | ||
168 | USB_REQ_CLEAR_FEATURE, | ||
169 | USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN, | ||
170 | kone_command_profile, number, buf, | ||
171 | sizeof(struct kone_profile), USB_CTRL_SET_TIMEOUT); | ||
172 | |||
173 | if (len != sizeof(struct kone_profile)) | ||
174 | return -EIO; | ||
175 | |||
176 | return 0; | ||
177 | } | ||
178 | |||
179 | /* | ||
180 | * Writes profile data to mouse. | ||
181 | * @number: profile number to write | ||
182 | * On success returns 0 | ||
183 | * On failure returns errno | ||
184 | */ | ||
185 | static int kone_set_profile(struct usb_device *usb_dev, | ||
186 | struct kone_profile const *profile, int number) | ||
187 | { | ||
188 | int len; | ||
189 | |||
190 | if (number < 1 || number > 5) | ||
191 | return -EINVAL; | ||
192 | |||
193 | len = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0), | ||
194 | USB_REQ_SET_CONFIGURATION, | ||
195 | USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT, | ||
196 | kone_command_profile, number, (char *)profile, | ||
197 | sizeof(struct kone_profile), | ||
198 | USB_CTRL_SET_TIMEOUT); | ||
199 | |||
200 | if (len != sizeof(struct kone_profile)) | ||
201 | return len; | ||
202 | |||
203 | if (kone_check_write(usb_dev)) | ||
204 | return -EIO; | ||
205 | |||
206 | return 0; | ||
207 | } | ||
208 | |||
209 | /* | ||
210 | * Reads value of "fast-clip-weight" and stores it in @result | ||
211 | * On success returns 0 | ||
212 | * On failure returns errno | ||
213 | */ | ||
214 | static int kone_get_weight(struct usb_device *usb_dev, int *result) | ||
215 | { | ||
216 | int len; | ||
217 | uint8_t *data; | ||
218 | |||
219 | data = kmalloc(1, GFP_KERNEL); | ||
220 | if (!data) | ||
221 | return -ENOMEM; | ||
222 | |||
223 | len = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0), | ||
224 | USB_REQ_CLEAR_FEATURE, | ||
225 | USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN, | ||
226 | kone_command_weight, 0, data, 1, USB_CTRL_SET_TIMEOUT); | ||
227 | |||
228 | if (len != 1) { | ||
229 | kfree(data); | ||
230 | return -EIO; | ||
231 | } | ||
232 | *result = (int)*data; | ||
233 | kfree(data); | ||
234 | return 0; | ||
235 | } | ||
236 | |||
237 | /* | ||
238 | * Reads firmware_version of mouse and stores it in @result | ||
239 | * On success returns 0 | ||
240 | * On failure returns errno | ||
241 | */ | ||
242 | static int kone_get_firmware_version(struct usb_device *usb_dev, int *result) | ||
243 | { | ||
244 | int len; | ||
245 | unsigned char *data; | ||
246 | |||
247 | data = kmalloc(2, GFP_KERNEL); | ||
248 | if (!data) | ||
249 | return -ENOMEM; | ||
250 | |||
251 | len = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0), | ||
252 | USB_REQ_CLEAR_FEATURE, | ||
253 | USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN, | ||
254 | kone_command_firmware_version, 0, data, 2, | ||
255 | USB_CTRL_SET_TIMEOUT); | ||
256 | |||
257 | if (len != 2) { | ||
258 | kfree(data); | ||
259 | return -EIO; | ||
260 | } | ||
261 | *result = le16_to_cpu(*data); | ||
262 | kfree(data); | ||
263 | return 0; | ||
264 | } | ||
265 | |||
266 | static ssize_t kone_sysfs_read_settings(struct kobject *kobj, | ||
267 | struct bin_attribute *attr, char *buf, | ||
268 | loff_t off, size_t count) { | ||
269 | struct device *dev = container_of(kobj, struct device, kobj); | ||
270 | struct kone_device *kone = hid_get_drvdata(dev_get_drvdata(dev)); | ||
271 | |||
272 | if (off >= sizeof(struct kone_settings)) | ||
273 | return 0; | ||
274 | |||
275 | if (off + count > sizeof(struct kone_settings)) | ||
276 | count = sizeof(struct kone_settings) - off; | ||
277 | |||
278 | mutex_lock(&kone->kone_lock); | ||
279 | memcpy(buf, &kone->settings + off, count); | ||
280 | mutex_unlock(&kone->kone_lock); | ||
281 | |||
282 | return count; | ||
283 | } | ||
284 | |||
285 | /* | ||
286 | * Writing settings automatically activates startup_profile. | ||
287 | * This function keeps values in kone_device up to date and assumes that in | ||
288 | * case of error the old data is still valid | ||
289 | */ | ||
290 | static ssize_t kone_sysfs_write_settings(struct kobject *kobj, | ||
291 | struct bin_attribute *attr, char *buf, | ||
292 | loff_t off, size_t count) { | ||
293 | struct device *dev = container_of(kobj, struct device, kobj); | ||
294 | struct kone_device *kone = hid_get_drvdata(dev_get_drvdata(dev)); | ||
295 | struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev)); | ||
296 | int retval = 0, difference; | ||
297 | |||
298 | /* I need to get my data in one piece */ | ||
299 | if (off != 0 || count != sizeof(struct kone_settings)) | ||
300 | return -EINVAL; | ||
301 | |||
302 | mutex_lock(&kone->kone_lock); | ||
303 | difference = memcmp(buf, &kone->settings, sizeof(struct kone_settings)); | ||
304 | if (difference) { | ||
305 | retval = kone_set_settings(usb_dev, | ||
306 | (struct kone_settings const *)buf); | ||
307 | if (!retval) | ||
308 | memcpy(&kone->settings, buf, | ||
309 | sizeof(struct kone_settings)); | ||
310 | } | ||
311 | mutex_unlock(&kone->kone_lock); | ||
312 | |||
313 | if (retval) | ||
314 | return retval; | ||
315 | |||
316 | /* | ||
317 | * If we get here, treat settings as okay and update actual values | ||
318 | * according to startup_profile | ||
319 | */ | ||
320 | kone->actual_profile = kone->settings.startup_profile; | ||
321 | kone->actual_dpi = kone->profiles[kone->actual_profile - 1].startup_dpi; | ||
322 | |||
323 | return sizeof(struct kone_settings); | ||
324 | } | ||
325 | |||
326 | static ssize_t kone_sysfs_read_profilex(struct kobject *kobj, | ||
327 | struct bin_attribute *attr, char *buf, | ||
328 | loff_t off, size_t count, int number) { | ||
329 | struct device *dev = container_of(kobj, struct device, kobj); | ||
330 | struct kone_device *kone = hid_get_drvdata(dev_get_drvdata(dev)); | ||
331 | |||
332 | if (off >= sizeof(struct kone_profile)) | ||
333 | return 0; | ||
334 | |||
335 | if (off + count > sizeof(struct kone_profile)) | ||
336 | count = sizeof(struct kone_profile) - off; | ||
337 | |||
338 | mutex_lock(&kone->kone_lock); | ||
339 | memcpy(buf, &kone->profiles[number - 1], sizeof(struct kone_profile)); | ||
340 | mutex_unlock(&kone->kone_lock); | ||
341 | |||
342 | return count; | ||
343 | } | ||
344 | |||
345 | static ssize_t kone_sysfs_read_profile1(struct kobject *kobj, | ||
346 | struct bin_attribute *attr, char *buf, | ||
347 | loff_t off, size_t count) { | ||
348 | return kone_sysfs_read_profilex(kobj, attr, buf, off, count, 1); | ||
349 | } | ||
350 | |||
351 | static ssize_t kone_sysfs_read_profile2(struct kobject *kobj, | ||
352 | struct bin_attribute *attr, char *buf, | ||
353 | loff_t off, size_t count) { | ||
354 | return kone_sysfs_read_profilex(kobj, attr, buf, off, count, 2); | ||
355 | } | ||
356 | |||
357 | static ssize_t kone_sysfs_read_profile3(struct kobject *kobj, | ||
358 | struct bin_attribute *attr, char *buf, | ||
359 | loff_t off, size_t count) { | ||
360 | return kone_sysfs_read_profilex(kobj, attr, buf, off, count, 3); | ||
361 | } | ||
362 | |||
363 | static ssize_t kone_sysfs_read_profile4(struct kobject *kobj, | ||
364 | struct bin_attribute *attr, char *buf, | ||
365 | loff_t off, size_t count) { | ||
366 | return kone_sysfs_read_profilex(kobj, attr, buf, off, count, 4); | ||
367 | } | ||
368 | |||
369 | static ssize_t kone_sysfs_read_profile5(struct kobject *kobj, | ||
370 | struct bin_attribute *attr, char *buf, | ||
371 | loff_t off, size_t count) { | ||
372 | return kone_sysfs_read_profilex(kobj, attr, buf, off, count, 5); | ||
373 | } | ||
374 | |||
375 | /* Writes data only if different to stored data */ | ||
376 | static ssize_t kone_sysfs_write_profilex(struct kobject *kobj, | ||
377 | struct bin_attribute *attr, char *buf, | ||
378 | loff_t off, size_t count, int number) { | ||
379 | struct device *dev = container_of(kobj, struct device, kobj); | ||
380 | struct kone_device *kone = hid_get_drvdata(dev_get_drvdata(dev)); | ||
381 | struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev)); | ||
382 | struct kone_profile *profile; | ||
383 | int retval = 0, difference; | ||
384 | |||
385 | /* I need to get my data in one piece */ | ||
386 | if (off != 0 || count != sizeof(struct kone_profile)) | ||
387 | return -EINVAL; | ||
388 | |||
389 | profile = &kone->profiles[number - 1]; | ||
390 | |||
391 | mutex_lock(&kone->kone_lock); | ||
392 | difference = memcmp(buf, profile, sizeof(struct kone_profile)); | ||
393 | if (difference) { | ||
394 | retval = kone_set_profile(usb_dev, | ||
395 | (struct kone_profile const *)buf, number); | ||
396 | if (!retval) | ||
397 | memcpy(profile, buf, sizeof(struct kone_profile)); | ||
398 | } | ||
399 | mutex_unlock(&kone->kone_lock); | ||
400 | |||
401 | if (retval) | ||
402 | return retval; | ||
403 | |||
404 | return sizeof(struct kone_profile); | ||
405 | } | ||
406 | |||
407 | static ssize_t kone_sysfs_write_profile1(struct kobject *kobj, | ||
408 | struct bin_attribute *attr, char *buf, | ||
409 | loff_t off, size_t count) { | ||
410 | return kone_sysfs_write_profilex(kobj, attr, buf, off, count, 1); | ||
411 | } | ||
412 | |||
413 | static ssize_t kone_sysfs_write_profile2(struct kobject *kobj, | ||
414 | struct bin_attribute *attr, char *buf, | ||
415 | loff_t off, size_t count) { | ||
416 | return kone_sysfs_write_profilex(kobj, attr, buf, off, count, 2); | ||
417 | } | ||
418 | |||
419 | static ssize_t kone_sysfs_write_profile3(struct kobject *kobj, | ||
420 | struct bin_attribute *attr, char *buf, | ||
421 | loff_t off, size_t count) { | ||
422 | return kone_sysfs_write_profilex(kobj, attr, buf, off, count, 3); | ||
423 | } | ||
424 | |||
425 | static ssize_t kone_sysfs_write_profile4(struct kobject *kobj, | ||
426 | struct bin_attribute *attr, char *buf, | ||
427 | loff_t off, size_t count) { | ||
428 | return kone_sysfs_write_profilex(kobj, attr, buf, off, count, 4); | ||
429 | } | ||
430 | |||
431 | static ssize_t kone_sysfs_write_profile5(struct kobject *kobj, | ||
432 | struct bin_attribute *attr, char *buf, | ||
433 | loff_t off, size_t count) { | ||
434 | return kone_sysfs_write_profilex(kobj, attr, buf, off, count, 5); | ||
435 | } | ||
436 | |||
437 | static ssize_t kone_sysfs_show_actual_profile(struct device *dev, | ||
438 | struct device_attribute *attr, char *buf) | ||
439 | { | ||
440 | struct kone_device *kone = hid_get_drvdata(dev_get_drvdata(dev)); | ||
441 | return snprintf(buf, PAGE_SIZE, "%d\n", kone->actual_profile); | ||
442 | } | ||
443 | |||
444 | static ssize_t kone_sysfs_show_actual_dpi(struct device *dev, | ||
445 | struct device_attribute *attr, char *buf) | ||
446 | { | ||
447 | struct kone_device *kone = hid_get_drvdata(dev_get_drvdata(dev)); | ||
448 | return snprintf(buf, PAGE_SIZE, "%d\n", kone->actual_dpi); | ||
449 | } | ||
450 | |||
451 | /* weight is read each time, since we don't get informed when it's changed */ | ||
452 | static ssize_t kone_sysfs_show_weight(struct device *dev, | ||
453 | struct device_attribute *attr, char *buf) | ||
454 | { | ||
455 | struct kone_device *kone = hid_get_drvdata(dev_get_drvdata(dev)); | ||
456 | struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev)); | ||
457 | int weight = 0; | ||
458 | int retval; | ||
459 | |||
460 | mutex_lock(&kone->kone_lock); | ||
461 | retval = kone_get_weight(usb_dev, &weight); | ||
462 | mutex_unlock(&kone->kone_lock); | ||
463 | |||
464 | if (retval) | ||
465 | return retval; | ||
466 | return snprintf(buf, PAGE_SIZE, "%d\n", weight); | ||
467 | } | ||
468 | |||
469 | static ssize_t kone_sysfs_show_firmware_version(struct device *dev, | ||
470 | struct device_attribute *attr, char *buf) | ||
471 | { | ||
472 | struct kone_device *kone = hid_get_drvdata(dev_get_drvdata(dev)); | ||
473 | return snprintf(buf, PAGE_SIZE, "%d\n", kone->firmware_version); | ||
474 | } | ||
475 | |||
476 | static ssize_t kone_sysfs_show_tcu(struct device *dev, | ||
477 | struct device_attribute *attr, char *buf) | ||
478 | { | ||
479 | struct kone_device *kone = hid_get_drvdata(dev_get_drvdata(dev)); | ||
480 | return snprintf(buf, PAGE_SIZE, "%d\n", kone->settings.tcu); | ||
481 | } | ||
482 | |||
483 | static int kone_tcu_command(struct usb_device *usb_dev, int number) | ||
484 | { | ||
485 | int len; | ||
486 | char *value; | ||
487 | |||
488 | value = kmalloc(1, GFP_KERNEL); | ||
489 | if (!value) | ||
490 | return -ENOMEM; | ||
491 | |||
492 | *value = number; | ||
493 | |||
494 | len = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0), | ||
495 | USB_REQ_SET_CONFIGURATION, | ||
496 | USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT, | ||
497 | kone_command_calibrate, 0, value, 1, | ||
498 | USB_CTRL_SET_TIMEOUT); | ||
499 | |||
500 | kfree(value); | ||
501 | return ((len != 1) ? -EIO : 0); | ||
502 | } | ||
503 | |||
504 | /* | ||
505 | * Calibrating the tcu is the only action that changes settings data inside the | ||
506 | * mouse, so this data needs to be reread | ||
507 | */ | ||
508 | static ssize_t kone_sysfs_set_tcu(struct device *dev, | ||
509 | struct device_attribute *attr, char const *buf, size_t size) | ||
510 | { | ||
511 | struct kone_device *kone = hid_get_drvdata(dev_get_drvdata(dev)); | ||
512 | struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev)); | ||
513 | int retval; | ||
514 | unsigned long state; | ||
515 | |||
516 | retval = strict_strtoul(buf, 10, &state); | ||
517 | if (retval) | ||
518 | return retval; | ||
519 | |||
520 | if (state != 0 && state != 1) | ||
521 | return -EINVAL; | ||
522 | |||
523 | mutex_lock(&kone->kone_lock); | ||
524 | |||
525 | if (state == 1) { /* state activate */ | ||
526 | retval = kone_tcu_command(usb_dev, 1); | ||
527 | if (retval) | ||
528 | goto exit_unlock; | ||
529 | retval = kone_tcu_command(usb_dev, 2); | ||
530 | if (retval) | ||
531 | goto exit_unlock; | ||
532 | ssleep(5); /* tcu needs this time for calibration */ | ||
533 | retval = kone_tcu_command(usb_dev, 3); | ||
534 | if (retval) | ||
535 | goto exit_unlock; | ||
536 | retval = kone_tcu_command(usb_dev, 0); | ||
537 | if (retval) | ||
538 | goto exit_unlock; | ||
539 | retval = kone_tcu_command(usb_dev, 4); | ||
540 | if (retval) | ||
541 | goto exit_unlock; | ||
542 | /* | ||
543 | * Kone needs this time to settle things. | ||
544 | * Reading settings too early will result in invalid data. | ||
545 | * Roccat's driver waits 1 sec, maybe this time could be | ||
546 | * shortened. | ||
547 | */ | ||
548 | ssleep(1); | ||
549 | } | ||
550 | |||
551 | /* calibration changes values in settings, so reread */ | ||
552 | retval = kone_get_settings(usb_dev, &kone->settings); | ||
553 | if (retval) | ||
554 | goto exit_no_settings; | ||
555 | |||
556 | /* only write settings back if activation state is different */ | ||
557 | if (kone->settings.tcu != state) { | ||
558 | kone->settings.tcu = state; | ||
559 | kone_set_settings_checksum(&kone->settings); | ||
560 | |||
561 | retval = kone_set_settings(usb_dev, &kone->settings); | ||
562 | if (retval) { | ||
563 | dev_err(&usb_dev->dev, "couldn't set tcu state\n"); | ||
564 | /* | ||
565 | * try to reread valid settings into buffer overwriting | ||
566 | * first error code | ||
567 | */ | ||
568 | retval = kone_get_settings(usb_dev, &kone->settings); | ||
569 | if (retval) | ||
570 | goto exit_no_settings; | ||
571 | goto exit_unlock; | ||
572 | } | ||
573 | } | ||
574 | |||
575 | retval = size; | ||
576 | exit_no_settings: | ||
577 | dev_err(&usb_dev->dev, "couldn't read settings\n"); | ||
578 | exit_unlock: | ||
579 | mutex_unlock(&kone->kone_lock); | ||
580 | return retval; | ||
581 | } | ||
582 | |||
583 | static ssize_t kone_sysfs_show_startup_profile(struct device *dev, | ||
584 | struct device_attribute *attr, char *buf) | ||
585 | { | ||
586 | struct kone_device *kone = hid_get_drvdata(dev_get_drvdata(dev)); | ||
587 | return snprintf(buf, PAGE_SIZE, "%d\n", kone->settings.startup_profile); | ||
588 | } | ||
589 | |||
590 | static ssize_t kone_sysfs_set_startup_profile(struct device *dev, | ||
591 | struct device_attribute *attr, char const *buf, size_t size) | ||
592 | { | ||
593 | struct kone_device *kone = hid_get_drvdata(dev_get_drvdata(dev)); | ||
594 | struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev)); | ||
595 | int retval; | ||
596 | unsigned long new_startup_profile; | ||
597 | |||
598 | retval = strict_strtoul(buf, 10, &new_startup_profile); | ||
599 | if (retval) | ||
600 | return retval; | ||
601 | |||
602 | if (new_startup_profile < 1 || new_startup_profile > 5) | ||
603 | return -EINVAL; | ||
604 | |||
605 | mutex_lock(&kone->kone_lock); | ||
606 | |||
607 | kone->settings.startup_profile = new_startup_profile; | ||
608 | kone_set_settings_checksum(&kone->settings); | ||
609 | |||
610 | retval = kone_set_settings(usb_dev, &kone->settings); | ||
611 | |||
612 | mutex_unlock(&kone->kone_lock); | ||
613 | |||
614 | if (retval) | ||
615 | return retval; | ||
616 | |||
617 | /* changing the startup profile immediately activates this profile */ | ||
618 | kone->actual_profile = new_startup_profile; | ||
619 | kone->actual_dpi = kone->profiles[kone->actual_profile - 1].startup_dpi; | ||
620 | |||
621 | return size; | ||
622 | } | ||
623 | |||
624 | /* | ||
625 | * This file is used by userland software to find devices that are handled by | ||
626 | * this driver. This provides a consistent way for actual and older kernels | ||
627 | * where this driver replaced usbhid instead of generic-usb. | ||
628 | * Driver capabilities are determined by version number. | ||
629 | */ | ||
630 | static ssize_t kone_sysfs_show_driver_version(struct device *dev, | ||
631 | struct device_attribute *attr, char *buf) | ||
632 | { | ||
633 | return snprintf(buf, PAGE_SIZE, ROCCAT_KONE_DRIVER_VERSION "\n"); | ||
634 | } | ||
635 | |||
636 | /* | ||
637 | * Read actual dpi settings. | ||
638 | * Returns raw value for further processing. Refer to enum kone_polling_rates to | ||
639 | * get real value. | ||
640 | */ | ||
641 | static DEVICE_ATTR(actual_dpi, 0440, kone_sysfs_show_actual_dpi, NULL); | ||
642 | |||
643 | static DEVICE_ATTR(actual_profile, 0440, kone_sysfs_show_actual_profile, NULL); | ||
644 | |||
645 | /* | ||
646 | * The mouse can be equipped with one of four supplied weights from 5 to 20 | ||
647 | * grams which are recognized and its value can be read out. | ||
648 | * This returns the raw value reported by the mouse for easy evaluation by | ||
649 | * software. Refer to enum kone_weights to get corresponding real weight. | ||
650 | */ | ||
651 | static DEVICE_ATTR(weight, 0440, kone_sysfs_show_weight, NULL); | ||
652 | |||
653 | /* | ||
654 | * Prints firmware version stored in mouse as integer. | ||
655 | * The raw value reported by the mouse is returned for easy evaluation, to get | ||
656 | * the real version number the decimal point has to be shifted 2 positions to | ||
657 | * the left. E.g. a value of 138 means 1.38. | ||
658 | */ | ||
659 | static DEVICE_ATTR(firmware_version, 0440, | ||
660 | kone_sysfs_show_firmware_version, NULL); | ||
661 | |||
662 | /* | ||
663 | * Prints state of Tracking Control Unit as number where 0 = off and 1 = on | ||
664 | * Writing 0 deactivates tcu and writing 1 calibrates and activates the tcu | ||
665 | */ | ||
666 | static DEVICE_ATTR(tcu, 0660, kone_sysfs_show_tcu, kone_sysfs_set_tcu); | ||
667 | |||
668 | /* Prints and takes the number of the profile the mouse starts with */ | ||
669 | static DEVICE_ATTR(startup_profile, 0660, | ||
670 | kone_sysfs_show_startup_profile, | ||
671 | kone_sysfs_set_startup_profile); | ||
672 | |||
673 | static DEVICE_ATTR(kone_driver_version, 0440, | ||
674 | kone_sysfs_show_driver_version, NULL); | ||
675 | |||
676 | static struct attribute *kone_attributes[] = { | ||
677 | &dev_attr_actual_dpi.attr, | ||
678 | &dev_attr_actual_profile.attr, | ||
679 | &dev_attr_weight.attr, | ||
680 | &dev_attr_firmware_version.attr, | ||
681 | &dev_attr_tcu.attr, | ||
682 | &dev_attr_startup_profile.attr, | ||
683 | &dev_attr_kone_driver_version.attr, | ||
684 | NULL | ||
685 | }; | ||
686 | |||
687 | static struct attribute_group kone_attribute_group = { | ||
688 | .attrs = kone_attributes | ||
689 | }; | ||
690 | |||
691 | static struct bin_attribute kone_settings_attr = { | ||
692 | .attr = { .name = "settings", .mode = 0660 }, | ||
693 | .size = sizeof(struct kone_settings), | ||
694 | .read = kone_sysfs_read_settings, | ||
695 | .write = kone_sysfs_write_settings | ||
696 | }; | ||
697 | |||
698 | static struct bin_attribute kone_profile1_attr = { | ||
699 | .attr = { .name = "profile1", .mode = 0660 }, | ||
700 | .size = sizeof(struct kone_profile), | ||
701 | .read = kone_sysfs_read_profile1, | ||
702 | .write = kone_sysfs_write_profile1 | ||
703 | }; | ||
704 | |||
705 | static struct bin_attribute kone_profile2_attr = { | ||
706 | .attr = { .name = "profile2", .mode = 0660 }, | ||
707 | .size = sizeof(struct kone_profile), | ||
708 | .read = kone_sysfs_read_profile2, | ||
709 | .write = kone_sysfs_write_profile2 | ||
710 | }; | ||
711 | |||
712 | static struct bin_attribute kone_profile3_attr = { | ||
713 | .attr = { .name = "profile3", .mode = 0660 }, | ||
714 | .size = sizeof(struct kone_profile), | ||
715 | .read = kone_sysfs_read_profile3, | ||
716 | .write = kone_sysfs_write_profile3 | ||
717 | }; | ||
718 | |||
719 | static struct bin_attribute kone_profile4_attr = { | ||
720 | .attr = { .name = "profile4", .mode = 0660 }, | ||
721 | .size = sizeof(struct kone_profile), | ||
722 | .read = kone_sysfs_read_profile4, | ||
723 | .write = kone_sysfs_write_profile4 | ||
724 | }; | ||
725 | |||
726 | static struct bin_attribute kone_profile5_attr = { | ||
727 | .attr = { .name = "profile5", .mode = 0660 }, | ||
728 | .size = sizeof(struct kone_profile), | ||
729 | .read = kone_sysfs_read_profile5, | ||
730 | .write = kone_sysfs_write_profile5 | ||
731 | }; | ||
732 | |||
733 | static int kone_create_sysfs_attributes(struct usb_interface *intf) | ||
734 | { | ||
735 | int retval; | ||
736 | |||
737 | retval = sysfs_create_group(&intf->dev.kobj, &kone_attribute_group); | ||
738 | if (retval) | ||
739 | goto exit_1; | ||
740 | |||
741 | retval = sysfs_create_bin_file(&intf->dev.kobj, &kone_settings_attr); | ||
742 | if (retval) | ||
743 | goto exit_2; | ||
744 | |||
745 | retval = sysfs_create_bin_file(&intf->dev.kobj, &kone_profile1_attr); | ||
746 | if (retval) | ||
747 | goto exit_3; | ||
748 | |||
749 | retval = sysfs_create_bin_file(&intf->dev.kobj, &kone_profile2_attr); | ||
750 | if (retval) | ||
751 | goto exit_4; | ||
752 | |||
753 | retval = sysfs_create_bin_file(&intf->dev.kobj, &kone_profile3_attr); | ||
754 | if (retval) | ||
755 | goto exit_5; | ||
756 | |||
757 | retval = sysfs_create_bin_file(&intf->dev.kobj, &kone_profile4_attr); | ||
758 | if (retval) | ||
759 | goto exit_6; | ||
760 | |||
761 | retval = sysfs_create_bin_file(&intf->dev.kobj, &kone_profile5_attr); | ||
762 | if (retval) | ||
763 | goto exit_7; | ||
764 | |||
765 | return 0; | ||
766 | |||
767 | exit_7: | ||
768 | sysfs_remove_bin_file(&intf->dev.kobj, &kone_profile4_attr); | ||
769 | exit_6: | ||
770 | sysfs_remove_bin_file(&intf->dev.kobj, &kone_profile3_attr); | ||
771 | exit_5: | ||
772 | sysfs_remove_bin_file(&intf->dev.kobj, &kone_profile2_attr); | ||
773 | exit_4: | ||
774 | sysfs_remove_bin_file(&intf->dev.kobj, &kone_profile1_attr); | ||
775 | exit_3: | ||
776 | sysfs_remove_bin_file(&intf->dev.kobj, &kone_settings_attr); | ||
777 | exit_2: | ||
778 | sysfs_remove_group(&intf->dev.kobj, &kone_attribute_group); | ||
779 | exit_1: | ||
780 | return retval; | ||
781 | } | ||
782 | |||
783 | static void kone_remove_sysfs_attributes(struct usb_interface *intf) | ||
784 | { | ||
785 | sysfs_remove_bin_file(&intf->dev.kobj, &kone_profile5_attr); | ||
786 | sysfs_remove_bin_file(&intf->dev.kobj, &kone_profile4_attr); | ||
787 | sysfs_remove_bin_file(&intf->dev.kobj, &kone_profile3_attr); | ||
788 | sysfs_remove_bin_file(&intf->dev.kobj, &kone_profile2_attr); | ||
789 | sysfs_remove_bin_file(&intf->dev.kobj, &kone_profile1_attr); | ||
790 | sysfs_remove_bin_file(&intf->dev.kobj, &kone_settings_attr); | ||
791 | sysfs_remove_group(&intf->dev.kobj, &kone_attribute_group); | ||
792 | } | ||
793 | |||
794 | static int kone_init_kone_device_struct(struct usb_device *usb_dev, | ||
795 | struct kone_device *kone) | ||
796 | { | ||
797 | uint i; | ||
798 | int retval; | ||
799 | |||
800 | mutex_init(&kone->kone_lock); | ||
801 | |||
802 | for (i = 0; i < 5; ++i) { | ||
803 | retval = kone_get_profile(usb_dev, &kone->profiles[i], i + 1); | ||
804 | if (retval) | ||
805 | return retval; | ||
806 | } | ||
807 | |||
808 | retval = kone_get_settings(usb_dev, &kone->settings); | ||
809 | if (retval) | ||
810 | return retval; | ||
811 | |||
812 | retval = kone_get_firmware_version(usb_dev, &kone->firmware_version); | ||
813 | if (retval) | ||
814 | return retval; | ||
815 | |||
816 | kone->actual_profile = kone->settings.startup_profile; | ||
817 | kone->actual_dpi = kone->profiles[kone->actual_profile].startup_dpi; | ||
818 | |||
819 | return 0; | ||
820 | } | ||
821 | |||
822 | /* | ||
823 | * Since IGNORE_MOUSE quirk moved to hid-apple, there is no way to bind only to | ||
824 | * mousepart if usb_hid is compiled into the kernel and kone is compiled as | ||
825 | * module. | ||
826 | * Secial behaviour is bound only to mousepart since only mouseevents contain | ||
827 | * additional notifications. | ||
828 | */ | ||
829 | static int kone_init_specials(struct hid_device *hdev) | ||
830 | { | ||
831 | struct usb_interface *intf = to_usb_interface(hdev->dev.parent); | ||
832 | struct usb_device *usb_dev = interface_to_usbdev(intf); | ||
833 | struct kone_device *kone; | ||
834 | int retval; | ||
835 | |||
836 | if (intf->cur_altsetting->desc.bInterfaceProtocol | ||
837 | == USB_INTERFACE_PROTOCOL_MOUSE) { | ||
838 | |||
839 | kone = kzalloc(sizeof(*kone), GFP_KERNEL); | ||
840 | if (!kone) { | ||
841 | dev_err(&hdev->dev, "can't alloc device descriptor\n"); | ||
842 | return -ENOMEM; | ||
843 | } | ||
844 | hid_set_drvdata(hdev, kone); | ||
845 | |||
846 | retval = kone_init_kone_device_struct(usb_dev, kone); | ||
847 | if (retval) { | ||
848 | dev_err(&hdev->dev, | ||
849 | "couldn't init struct kone_device\n"); | ||
850 | goto exit_free; | ||
851 | } | ||
852 | retval = kone_create_sysfs_attributes(intf); | ||
853 | if (retval) { | ||
854 | dev_err(&hdev->dev, "cannot create sysfs files\n"); | ||
855 | goto exit_free; | ||
856 | } | ||
857 | } else { | ||
858 | hid_set_drvdata(hdev, NULL); | ||
859 | } | ||
860 | |||
861 | return 0; | ||
862 | exit_free: | ||
863 | kfree(kone); | ||
864 | return retval; | ||
865 | } | ||
866 | |||
867 | |||
868 | static void kone_remove_specials(struct hid_device *hdev) | ||
869 | { | ||
870 | struct usb_interface *intf = to_usb_interface(hdev->dev.parent); | ||
871 | |||
872 | if (intf->cur_altsetting->desc.bInterfaceProtocol | ||
873 | == USB_INTERFACE_PROTOCOL_MOUSE) { | ||
874 | kone_remove_sysfs_attributes(intf); | ||
875 | kfree(hid_get_drvdata(hdev)); | ||
876 | } | ||
877 | } | ||
878 | |||
879 | static int kone_probe(struct hid_device *hdev, const struct hid_device_id *id) | ||
880 | { | ||
881 | int retval; | ||
882 | |||
883 | retval = hid_parse(hdev); | ||
884 | if (retval) { | ||
885 | dev_err(&hdev->dev, "parse failed\n"); | ||
886 | goto exit; | ||
887 | } | ||
888 | |||
889 | retval = hid_hw_start(hdev, HID_CONNECT_DEFAULT); | ||
890 | if (retval) { | ||
891 | dev_err(&hdev->dev, "hw start failed\n"); | ||
892 | goto exit; | ||
893 | } | ||
894 | |||
895 | retval = kone_init_specials(hdev); | ||
896 | if (retval) { | ||
897 | dev_err(&hdev->dev, "couldn't install mouse\n"); | ||
898 | goto exit_stop; | ||
899 | } | ||
900 | |||
901 | return 0; | ||
902 | |||
903 | exit_stop: | ||
904 | hid_hw_stop(hdev); | ||
905 | exit: | ||
906 | return retval; | ||
907 | } | ||
908 | |||
909 | static void kone_remove(struct hid_device *hdev) | ||
910 | { | ||
911 | kone_remove_specials(hdev); | ||
912 | hid_hw_stop(hdev); | ||
913 | } | ||
914 | |||
915 | /* handle special events and keep actual profile and dpi values up to date */ | ||
916 | static void kone_keep_values_up_to_date(struct kone_device *kone, | ||
917 | struct kone_mouse_event const *event) | ||
918 | { | ||
919 | switch (event->event) { | ||
920 | case kone_mouse_event_switch_profile: | ||
921 | case kone_mouse_event_osd_profile: | ||
922 | kone->actual_profile = event->value; | ||
923 | kone->actual_dpi = kone->profiles[kone->actual_profile - 1]. | ||
924 | startup_dpi; | ||
925 | break; | ||
926 | case kone_mouse_event_switch_dpi: | ||
927 | case kone_mouse_event_osd_dpi: | ||
928 | kone->actual_dpi = event->value; | ||
929 | break; | ||
930 | } | ||
931 | } | ||
932 | |||
933 | /* | ||
934 | * Is called for keyboard- and mousepart. | ||
935 | * Only mousepart gets informations about special events in its extended event | ||
936 | * structure. | ||
937 | */ | ||
938 | static int kone_raw_event(struct hid_device *hdev, struct hid_report *report, | ||
939 | u8 *data, int size) | ||
940 | { | ||
941 | struct kone_device *kone = hid_get_drvdata(hdev); | ||
942 | struct kone_mouse_event *event = (struct kone_mouse_event *)data; | ||
943 | |||
944 | /* keyboard events are always processed by default handler */ | ||
945 | if (size != sizeof(struct kone_mouse_event)) | ||
946 | return 0; | ||
947 | |||
948 | /* | ||
949 | * Firmware 1.38 introduced new behaviour for tilt and special buttons. | ||
950 | * Pressed button is reported in each movement event. | ||
951 | * Workaround sends only one event per press. | ||
952 | */ | ||
953 | if (memcmp(&kone->last_mouse_event.tilt, &event->tilt, 5)) | ||
954 | memcpy(&kone->last_mouse_event, event, | ||
955 | sizeof(struct kone_mouse_event)); | ||
956 | else | ||
957 | memset(&event->tilt, 0, 5); | ||
958 | |||
959 | kone_keep_values_up_to_date(kone, event); | ||
960 | |||
961 | return 0; /* always do further processing */ | ||
962 | } | ||
963 | |||
964 | static const struct hid_device_id kone_devices[] = { | ||
965 | { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KONE) }, | ||
966 | { } | ||
967 | }; | ||
968 | |||
969 | MODULE_DEVICE_TABLE(hid, kone_devices); | ||
970 | |||
971 | static struct hid_driver kone_driver = { | ||
972 | .name = "kone", | ||
973 | .id_table = kone_devices, | ||
974 | .probe = kone_probe, | ||
975 | .remove = kone_remove, | ||
976 | .raw_event = kone_raw_event | ||
977 | }; | ||
978 | |||
979 | static int __init kone_init(void) | ||
980 | { | ||
981 | return hid_register_driver(&kone_driver); | ||
982 | } | ||
983 | |||
984 | static void __exit kone_exit(void) | ||
985 | { | ||
986 | hid_unregister_driver(&kone_driver); | ||
987 | } | ||
988 | |||
989 | module_init(kone_init); | ||
990 | module_exit(kone_exit); | ||
991 | |||
992 | MODULE_AUTHOR("Stefan Achatz"); | ||
993 | MODULE_DESCRIPTION("USB Roccat Kone driver"); | ||
994 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/hid/hid-roccat-kone.h b/drivers/hid/hid-roccat-kone.h new file mode 100644 index 000000000000..b413b10a7f8a --- /dev/null +++ b/drivers/hid/hid-roccat-kone.h | |||
@@ -0,0 +1,224 @@ | |||
1 | #ifndef __HID_ROCCAT_KONE_H | ||
2 | #define __HID_ROCCAT_KONE_H | ||
3 | |||
4 | /* | ||
5 | * Copyright (c) 2010 Stefan Achatz <erazor_de@users.sourceforge.net> | ||
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/types.h> | ||
16 | |||
17 | #define ROCCAT_KONE_DRIVER_VERSION "v0.3.1" | ||
18 | |||
19 | #pragma pack(push) | ||
20 | #pragma pack(1) | ||
21 | |||
22 | struct kone_keystroke { | ||
23 | uint8_t key; | ||
24 | uint8_t action; | ||
25 | uint16_t period; /* in milliseconds */ | ||
26 | }; | ||
27 | |||
28 | enum kone_keystroke_buttons { | ||
29 | kone_keystroke_button_1 = 0xf0, /* left mouse button */ | ||
30 | kone_keystroke_button_2 = 0xf1, /* right mouse button */ | ||
31 | kone_keystroke_button_3 = 0xf2, /* wheel */ | ||
32 | kone_keystroke_button_9 = 0xf3, /* side button up */ | ||
33 | kone_keystroke_button_8 = 0xf4 /* side button down */ | ||
34 | }; | ||
35 | |||
36 | enum kone_keystroke_actions { | ||
37 | kone_keystroke_action_press = 0, | ||
38 | kone_keystroke_action_release = 1 | ||
39 | }; | ||
40 | |||
41 | struct kone_button_info { | ||
42 | uint8_t number; /* range 1-8 */ | ||
43 | uint8_t type; | ||
44 | uint8_t macro_type; /* 0 = short, 1 = overlong */ | ||
45 | uint8_t macro_set_name[16]; /* can be max 15 chars long */ | ||
46 | uint8_t macro_name[16]; /* can be max 15 chars long */ | ||
47 | uint8_t count; | ||
48 | struct kone_keystroke keystrokes[20]; | ||
49 | }; | ||
50 | |||
51 | enum kone_button_info_types { | ||
52 | /* valid button types until firmware 1.32 */ | ||
53 | kone_button_info_type_button_1 = 0x1, /* click (left mouse button) */ | ||
54 | kone_button_info_type_button_2 = 0x2, /* menu (right mouse button)*/ | ||
55 | kone_button_info_type_button_3 = 0x3, /* scroll (wheel) */ | ||
56 | kone_button_info_type_double_click = 0x4, | ||
57 | kone_button_info_type_key = 0x5, | ||
58 | kone_button_info_type_macro = 0x6, | ||
59 | kone_button_info_type_off = 0x7, | ||
60 | /* TODO clarify function and rename */ | ||
61 | kone_button_info_type_osd_xy_prescaling = 0x8, | ||
62 | kone_button_info_type_osd_dpi = 0x9, | ||
63 | kone_button_info_type_osd_profile = 0xa, | ||
64 | kone_button_info_type_button_9 = 0xb, /* ie forward */ | ||
65 | kone_button_info_type_button_8 = 0xc, /* ie backward */ | ||
66 | kone_button_info_type_dpi_up = 0xd, /* internal */ | ||
67 | kone_button_info_type_dpi_down = 0xe, /* internal */ | ||
68 | kone_button_info_type_button_7 = 0xf, /* tilt left */ | ||
69 | kone_button_info_type_button_6 = 0x10, /* tilt right */ | ||
70 | kone_button_info_type_profile_up = 0x11, /* internal */ | ||
71 | kone_button_info_type_profile_down = 0x12, /* internal */ | ||
72 | /* additional valid button types since firmware 1.38 */ | ||
73 | kone_button_info_type_multimedia_open_player = 0x20, | ||
74 | kone_button_info_type_multimedia_next_track = 0x21, | ||
75 | kone_button_info_type_multimedia_prev_track = 0x22, | ||
76 | kone_button_info_type_multimedia_play_pause = 0x23, | ||
77 | kone_button_info_type_multimedia_stop = 0x24, | ||
78 | kone_button_info_type_multimedia_mute = 0x25, | ||
79 | kone_button_info_type_multimedia_volume_up = 0x26, | ||
80 | kone_button_info_type_multimedia_volume_down = 0x27 | ||
81 | }; | ||
82 | |||
83 | enum kone_button_info_numbers { | ||
84 | kone_button_top = 1, | ||
85 | kone_button_wheel_tilt_left = 2, | ||
86 | kone_button_wheel_tilt_right = 3, | ||
87 | kone_button_forward = 4, | ||
88 | kone_button_backward = 5, | ||
89 | kone_button_middle = 6, | ||
90 | kone_button_plus = 7, | ||
91 | kone_button_minus = 8, | ||
92 | }; | ||
93 | |||
94 | struct kone_light_info { | ||
95 | uint8_t number; /* number of light 1-5 */ | ||
96 | uint8_t mod; /* 1 = on, 2 = off */ | ||
97 | uint8_t red; /* range 0x00-0xff */ | ||
98 | uint8_t green; /* range 0x00-0xff */ | ||
99 | uint8_t blue; /* range 0x00-0xff */ | ||
100 | }; | ||
101 | |||
102 | struct kone_profile { | ||
103 | uint16_t size; /* always 975 */ | ||
104 | uint16_t unused; /* always 0 */ | ||
105 | |||
106 | /* | ||
107 | * range 1-5 | ||
108 | * This number does not need to correspond with location where profile | ||
109 | * saved | ||
110 | */ | ||
111 | uint8_t profile; /* range 1-5 */ | ||
112 | |||
113 | uint16_t main_sensitivity; /* range 100-1000 */ | ||
114 | uint8_t xy_sensitivity_enabled; /* 1 = on, 2 = off */ | ||
115 | uint16_t x_sensitivity; /* range 100-1000 */ | ||
116 | uint16_t y_sensitivity; /* range 100-1000 */ | ||
117 | uint8_t dpi_rate; /* bit 1 = 800, ... */ | ||
118 | uint8_t startup_dpi; /* range 1-6 */ | ||
119 | uint8_t polling_rate; /* 1 = 125Hz, 2 = 500Hz, 3 = 1000Hz */ | ||
120 | /* kone has no dcu | ||
121 | * value is always 2 in firmwares <= 1.32 and | ||
122 | * 1 in firmwares > 1.32 | ||
123 | */ | ||
124 | uint8_t dcu_flag; | ||
125 | uint8_t light_effect_1; /* range 1-3 */ | ||
126 | uint8_t light_effect_2; /* range 1-5 */ | ||
127 | uint8_t light_effect_3; /* range 1-4 */ | ||
128 | uint8_t light_effect_speed; /* range 0-255 */ | ||
129 | |||
130 | struct kone_light_info light_infos[5]; | ||
131 | /* offset is kone_button_info_numbers - 1 */ | ||
132 | struct kone_button_info button_infos[8]; | ||
133 | |||
134 | uint16_t checksum; /* \brief holds checksum of struct */ | ||
135 | }; | ||
136 | |||
137 | enum kone_polling_rates { | ||
138 | kone_polling_rate_125 = 1, | ||
139 | kone_polling_rate_500 = 2, | ||
140 | kone_polling_rate_1000 = 3 | ||
141 | }; | ||
142 | |||
143 | struct kone_settings { | ||
144 | uint16_t size; /* always 36 */ | ||
145 | uint8_t startup_profile; /* 1-5 */ | ||
146 | uint8_t unknown1; | ||
147 | uint8_t tcu; /* 0 = off, 1 = on */ | ||
148 | uint8_t unknown2[23]; | ||
149 | uint8_t calibration_data[4]; | ||
150 | uint8_t unknown3[2]; | ||
151 | uint16_t checksum; | ||
152 | }; | ||
153 | |||
154 | /* | ||
155 | * 12 byte mouse event read by interrupt_read | ||
156 | */ | ||
157 | struct kone_mouse_event { | ||
158 | uint8_t report_number; /* always 1 */ | ||
159 | uint8_t button; | ||
160 | uint16_t x; | ||
161 | uint16_t y; | ||
162 | uint8_t wheel; /* up = 1, down = -1 */ | ||
163 | uint8_t tilt; /* right = 1, left = -1 */ | ||
164 | uint8_t unknown; | ||
165 | uint8_t event; | ||
166 | uint8_t value; /* press = 0, release = 1 */ | ||
167 | uint8_t macro_key; /* 0 to 8 */ | ||
168 | }; | ||
169 | |||
170 | enum kone_mouse_events { | ||
171 | /* osd events are thought to be display on screen */ | ||
172 | kone_mouse_event_osd_dpi = 0xa0, | ||
173 | kone_mouse_event_osd_profile = 0xb0, | ||
174 | /* TODO clarify meaning and occurence of kone_mouse_event_calibration */ | ||
175 | kone_mouse_event_calibration = 0xc0, | ||
176 | kone_mouse_event_call_overlong_macro = 0xe0, | ||
177 | /* switch events notify if user changed values with mousebutton click */ | ||
178 | kone_mouse_event_switch_dpi = 0xf0, | ||
179 | kone_mouse_event_switch_profile = 0xf1 | ||
180 | }; | ||
181 | |||
182 | enum kone_commands { | ||
183 | kone_command_profile = 0x5a, | ||
184 | kone_command_settings = 0x15a, | ||
185 | kone_command_firmware_version = 0x25a, | ||
186 | kone_command_weight = 0x45a, | ||
187 | kone_command_calibrate = 0x55a, | ||
188 | kone_command_confirm_write = 0x65a, | ||
189 | kone_command_firmware = 0xe5a | ||
190 | }; | ||
191 | |||
192 | #pragma pack(pop) | ||
193 | |||
194 | struct kone_device { | ||
195 | /* | ||
196 | * Storing actual values when we get informed about changes since there | ||
197 | * is no way of getting this information from the device on demand | ||
198 | */ | ||
199 | int actual_profile, actual_dpi; | ||
200 | /* Used for neutralizing abnormal button behaviour */ | ||
201 | struct kone_mouse_event last_mouse_event; | ||
202 | |||
203 | /* | ||
204 | * It's unlikely that multiple sysfs attributes are accessed at a time, | ||
205 | * so only one mutex is used to secure hardware access and profiles and | ||
206 | * settings of this struct. | ||
207 | */ | ||
208 | struct mutex kone_lock; | ||
209 | |||
210 | /* | ||
211 | * Storing the data here reduces IO and ensures that data is available | ||
212 | * when its needed (E.g. interrupt handler). | ||
213 | */ | ||
214 | struct kone_profile profiles[5]; | ||
215 | struct kone_settings settings; | ||
216 | |||
217 | /* | ||
218 | * firmware doesn't change unless firmware update is implemented, | ||
219 | * so it's read only once | ||
220 | */ | ||
221 | int firmware_version; | ||
222 | }; | ||
223 | |||
224 | #endif | ||
diff --git a/drivers/hid/hid-samsung.c b/drivers/hid/hid-samsung.c index 510dd1340597..bda0fd60c98d 100644 --- a/drivers/hid/hid-samsung.c +++ b/drivers/hid/hid-samsung.c | |||
@@ -7,6 +7,18 @@ | |||
7 | * Copyright (c) 2006-2007 Jiri Kosina | 7 | * Copyright (c) 2006-2007 Jiri Kosina |
8 | * Copyright (c) 2007 Paul Walmsley | 8 | * Copyright (c) 2007 Paul Walmsley |
9 | * Copyright (c) 2008 Jiri Slaby | 9 | * Copyright (c) 2008 Jiri Slaby |
10 | * Copyright (c) 2010 Don Prince <dhprince.devel@yahoo.co.uk> | ||
11 | * | ||
12 | * | ||
13 | * This driver supports several HID devices: | ||
14 | * | ||
15 | * [0419:0001] Samsung IrDA remote controller (reports as Cypress USB Mouse). | ||
16 | * various hid report fixups for different variants. | ||
17 | * | ||
18 | * [0419:0600] Creative Desktop Wireless 6000 keyboard/mouse combo | ||
19 | * several key mappings used from the consumer usage page | ||
20 | * deviate from the USB HUT 1.12 standard. | ||
21 | * | ||
10 | */ | 22 | */ |
11 | 23 | ||
12 | /* | 24 | /* |
@@ -17,14 +29,13 @@ | |||
17 | */ | 29 | */ |
18 | 30 | ||
19 | #include <linux/device.h> | 31 | #include <linux/device.h> |
32 | #include <linux/usb.h> | ||
20 | #include <linux/hid.h> | 33 | #include <linux/hid.h> |
21 | #include <linux/module.h> | 34 | #include <linux/module.h> |
22 | 35 | ||
23 | #include "hid-ids.h" | 36 | #include "hid-ids.h" |
24 | 37 | ||
25 | /* | 38 | /* |
26 | * Samsung IrDA remote controller (reports as Cypress USB Mouse). | ||
27 | * | ||
28 | * There are several variants for 0419:0001: | 39 | * There are several variants for 0419:0001: |
29 | * | 40 | * |
30 | * 1. 184 byte report descriptor | 41 | * 1. 184 byte report descriptor |
@@ -43,21 +54,21 @@ | |||
43 | * 4. 171 byte report descriptor | 54 | * 4. 171 byte report descriptor |
44 | * Report #3 has an array field with logical range 0..1 instead of 1..3. | 55 | * Report #3 has an array field with logical range 0..1 instead of 1..3. |
45 | */ | 56 | */ |
46 | static inline void samsung_dev_trace(struct hid_device *hdev, | 57 | static inline void samsung_irda_dev_trace(struct hid_device *hdev, |
47 | unsigned int rsize) | 58 | unsigned int rsize) |
48 | { | 59 | { |
49 | dev_info(&hdev->dev, "fixing up Samsung IrDA %d byte report " | 60 | dev_info(&hdev->dev, "fixing up Samsung IrDA %d byte report " |
50 | "descriptor\n", rsize); | 61 | "descriptor\n", rsize); |
51 | } | 62 | } |
52 | 63 | ||
53 | static void samsung_report_fixup(struct hid_device *hdev, __u8 *rdesc, | 64 | static void samsung_irda_report_fixup(struct hid_device *hdev, __u8 *rdesc, |
54 | unsigned int rsize) | 65 | unsigned int rsize) |
55 | { | 66 | { |
56 | if (rsize == 184 && rdesc[175] == 0x25 && rdesc[176] == 0x40 && | 67 | if (rsize == 184 && rdesc[175] == 0x25 && rdesc[176] == 0x40 && |
57 | rdesc[177] == 0x75 && rdesc[178] == 0x30 && | 68 | rdesc[177] == 0x75 && rdesc[178] == 0x30 && |
58 | rdesc[179] == 0x95 && rdesc[180] == 0x01 && | 69 | rdesc[179] == 0x95 && rdesc[180] == 0x01 && |
59 | rdesc[182] == 0x40) { | 70 | rdesc[182] == 0x40) { |
60 | samsung_dev_trace(hdev, 184); | 71 | samsung_irda_dev_trace(hdev, 184); |
61 | rdesc[176] = 0xff; | 72 | rdesc[176] = 0xff; |
62 | rdesc[178] = 0x08; | 73 | rdesc[178] = 0x08; |
63 | rdesc[180] = 0x06; | 74 | rdesc[180] = 0x06; |
@@ -65,24 +76,80 @@ static void samsung_report_fixup(struct hid_device *hdev, __u8 *rdesc, | |||
65 | } else | 76 | } else |
66 | if (rsize == 203 && rdesc[192] == 0x15 && rdesc[193] == 0x0 && | 77 | if (rsize == 203 && rdesc[192] == 0x15 && rdesc[193] == 0x0 && |
67 | rdesc[194] == 0x25 && rdesc[195] == 0x12) { | 78 | rdesc[194] == 0x25 && rdesc[195] == 0x12) { |
68 | samsung_dev_trace(hdev, 203); | 79 | samsung_irda_dev_trace(hdev, 203); |
69 | rdesc[193] = 0x1; | 80 | rdesc[193] = 0x1; |
70 | rdesc[195] = 0xf; | 81 | rdesc[195] = 0xf; |
71 | } else | 82 | } else |
72 | if (rsize == 135 && rdesc[124] == 0x15 && rdesc[125] == 0x0 && | 83 | if (rsize == 135 && rdesc[124] == 0x15 && rdesc[125] == 0x0 && |
73 | rdesc[126] == 0x25 && rdesc[127] == 0x11) { | 84 | rdesc[126] == 0x25 && rdesc[127] == 0x11) { |
74 | samsung_dev_trace(hdev, 135); | 85 | samsung_irda_dev_trace(hdev, 135); |
75 | rdesc[125] = 0x1; | 86 | rdesc[125] = 0x1; |
76 | rdesc[127] = 0xe; | 87 | rdesc[127] = 0xe; |
77 | } else | 88 | } else |
78 | if (rsize == 171 && rdesc[160] == 0x15 && rdesc[161] == 0x0 && | 89 | if (rsize == 171 && rdesc[160] == 0x15 && rdesc[161] == 0x0 && |
79 | rdesc[162] == 0x25 && rdesc[163] == 0x01) { | 90 | rdesc[162] == 0x25 && rdesc[163] == 0x01) { |
80 | samsung_dev_trace(hdev, 171); | 91 | samsung_irda_dev_trace(hdev, 171); |
81 | rdesc[161] = 0x1; | 92 | rdesc[161] = 0x1; |
82 | rdesc[163] = 0x3; | 93 | rdesc[163] = 0x3; |
83 | } | 94 | } |
84 | } | 95 | } |
85 | 96 | ||
97 | #define samsung_kbd_mouse_map_key_clear(c) \ | ||
98 | hid_map_usage_clear(hi, usage, bit, max, EV_KEY, (c)) | ||
99 | |||
100 | static int samsung_kbd_mouse_input_mapping(struct hid_device *hdev, | ||
101 | struct hid_input *hi, struct hid_field *field, struct hid_usage *usage, | ||
102 | unsigned long **bit, int *max) | ||
103 | { | ||
104 | struct usb_interface *intf = to_usb_interface(hdev->dev.parent); | ||
105 | unsigned short ifnum = intf->cur_altsetting->desc.bInterfaceNumber; | ||
106 | |||
107 | if (1 != ifnum || HID_UP_CONSUMER != (usage->hid & HID_USAGE_PAGE)) | ||
108 | return 0; | ||
109 | |||
110 | dbg_hid("samsung wireless keyboard/mouse input mapping event [0x%x]\n", | ||
111 | usage->hid & HID_USAGE); | ||
112 | |||
113 | switch (usage->hid & HID_USAGE) { | ||
114 | /* report 2 */ | ||
115 | case 0x183: samsung_kbd_mouse_map_key_clear(KEY_MEDIA); break; | ||
116 | case 0x195: samsung_kbd_mouse_map_key_clear(KEY_EMAIL); break; | ||
117 | case 0x196: samsung_kbd_mouse_map_key_clear(KEY_CALC); break; | ||
118 | case 0x197: samsung_kbd_mouse_map_key_clear(KEY_COMPUTER); break; | ||
119 | case 0x22b: samsung_kbd_mouse_map_key_clear(KEY_SEARCH); break; | ||
120 | case 0x22c: samsung_kbd_mouse_map_key_clear(KEY_WWW); break; | ||
121 | case 0x22d: samsung_kbd_mouse_map_key_clear(KEY_BACK); break; | ||
122 | case 0x22e: samsung_kbd_mouse_map_key_clear(KEY_FORWARD); break; | ||
123 | case 0x22f: samsung_kbd_mouse_map_key_clear(KEY_FAVORITES); break; | ||
124 | case 0x230: samsung_kbd_mouse_map_key_clear(KEY_REFRESH); break; | ||
125 | case 0x231: samsung_kbd_mouse_map_key_clear(KEY_STOP); break; | ||
126 | default: | ||
127 | return 0; | ||
128 | } | ||
129 | |||
130 | return 1; | ||
131 | } | ||
132 | |||
133 | static void samsung_report_fixup(struct hid_device *hdev, __u8 *rdesc, | ||
134 | unsigned int rsize) | ||
135 | { | ||
136 | if (USB_DEVICE_ID_SAMSUNG_IR_REMOTE == hdev->product) | ||
137 | samsung_irda_report_fixup(hdev, rdesc, rsize); | ||
138 | } | ||
139 | |||
140 | static int samsung_input_mapping(struct hid_device *hdev, struct hid_input *hi, | ||
141 | struct hid_field *field, struct hid_usage *usage, | ||
142 | unsigned long **bit, int *max) | ||
143 | { | ||
144 | int ret = 0; | ||
145 | |||
146 | if (USB_DEVICE_ID_SAMSUNG_WIRELESS_KBD_MOUSE == hdev->product) | ||
147 | ret = samsung_kbd_mouse_input_mapping(hdev, | ||
148 | hi, field, usage, bit, max); | ||
149 | |||
150 | return ret; | ||
151 | } | ||
152 | |||
86 | static int samsung_probe(struct hid_device *hdev, | 153 | static int samsung_probe(struct hid_device *hdev, |
87 | const struct hid_device_id *id) | 154 | const struct hid_device_id *id) |
88 | { | 155 | { |
@@ -95,10 +162,12 @@ static int samsung_probe(struct hid_device *hdev, | |||
95 | goto err_free; | 162 | goto err_free; |
96 | } | 163 | } |
97 | 164 | ||
98 | if (hdev->rsize == 184) { | 165 | if (USB_DEVICE_ID_SAMSUNG_IR_REMOTE == hdev->product) { |
99 | /* disable hidinput, force hiddev */ | 166 | if (hdev->rsize == 184) { |
100 | cmask = (cmask & ~HID_CONNECT_HIDINPUT) | | 167 | /* disable hidinput, force hiddev */ |
101 | HID_CONNECT_HIDDEV_FORCE; | 168 | cmask = (cmask & ~HID_CONNECT_HIDINPUT) | |
169 | HID_CONNECT_HIDDEV_FORCE; | ||
170 | } | ||
102 | } | 171 | } |
103 | 172 | ||
104 | ret = hid_hw_start(hdev, cmask); | 173 | ret = hid_hw_start(hdev, cmask); |
@@ -114,6 +183,7 @@ err_free: | |||
114 | 183 | ||
115 | static const struct hid_device_id samsung_devices[] = { | 184 | static const struct hid_device_id samsung_devices[] = { |
116 | { HID_USB_DEVICE(USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_IR_REMOTE) }, | 185 | { HID_USB_DEVICE(USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_IR_REMOTE) }, |
186 | { HID_USB_DEVICE(USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_WIRELESS_KBD_MOUSE) }, | ||
117 | { } | 187 | { } |
118 | }; | 188 | }; |
119 | MODULE_DEVICE_TABLE(hid, samsung_devices); | 189 | MODULE_DEVICE_TABLE(hid, samsung_devices); |
@@ -122,6 +192,7 @@ static struct hid_driver samsung_driver = { | |||
122 | .name = "samsung", | 192 | .name = "samsung", |
123 | .id_table = samsung_devices, | 193 | .id_table = samsung_devices, |
124 | .report_fixup = samsung_report_fixup, | 194 | .report_fixup = samsung_report_fixup, |
195 | .input_mapping = samsung_input_mapping, | ||
125 | .probe = samsung_probe, | 196 | .probe = samsung_probe, |
126 | }; | 197 | }; |
127 | 198 | ||
diff --git a/drivers/hid/hid-topseed.c b/drivers/hid/hid-topseed.c index 6925eda1081a..2eebdcc57bcf 100644 --- a/drivers/hid/hid-topseed.c +++ b/drivers/hid/hid-topseed.c | |||
@@ -3,6 +3,9 @@ | |||
3 | * | 3 | * |
4 | * Copyright (c) 2008 Lev Babiev | 4 | * Copyright (c) 2008 Lev Babiev |
5 | * based on hid-cherry driver | 5 | * based on hid-cherry driver |
6 | * | ||
7 | * Modified to also support BTC "Emprex 3009URF III Vista MCE Remote" by | ||
8 | * Wayne Thomas 2010. | ||
6 | */ | 9 | */ |
7 | 10 | ||
8 | /* | 11 | /* |
@@ -24,23 +27,29 @@ static int ts_input_mapping(struct hid_device *hdev, struct hid_input *hi, | |||
24 | struct hid_field *field, struct hid_usage *usage, | 27 | struct hid_field *field, struct hid_usage *usage, |
25 | unsigned long **bit, int *max) | 28 | unsigned long **bit, int *max) |
26 | { | 29 | { |
27 | if ((usage->hid & HID_USAGE_PAGE) != 0x0ffbc0000) | 30 | if ((usage->hid & HID_USAGE_PAGE) != HID_UP_LOGIVENDOR) |
28 | return 0; | 31 | return 0; |
29 | 32 | ||
30 | switch (usage->hid & HID_USAGE) { | 33 | switch (usage->hid & HID_USAGE) { |
31 | case 0x00d: ts_map_key_clear(KEY_HOME); break; | 34 | case 0x00d: ts_map_key_clear(KEY_MEDIA); break; |
32 | case 0x024: ts_map_key_clear(KEY_MENU); break; | 35 | case 0x024: ts_map_key_clear(KEY_MENU); break; |
33 | case 0x025: ts_map_key_clear(KEY_TV); break; | 36 | case 0x025: ts_map_key_clear(KEY_TV); break; |
34 | case 0x048: ts_map_key_clear(KEY_RED); break; | 37 | case 0x031: ts_map_key_clear(KEY_AUDIO); break; |
35 | case 0x047: ts_map_key_clear(KEY_GREEN); break; | 38 | case 0x032: ts_map_key_clear(KEY_TEXT); break; |
36 | case 0x049: ts_map_key_clear(KEY_YELLOW); break; | 39 | case 0x033: ts_map_key_clear(KEY_CHANNEL); break; |
37 | case 0x04a: ts_map_key_clear(KEY_BLUE); break; | 40 | case 0x047: ts_map_key_clear(KEY_MP3); break; |
38 | case 0x04b: ts_map_key_clear(KEY_ANGLE); break; | 41 | case 0x048: ts_map_key_clear(KEY_TV2); break; |
39 | case 0x04c: ts_map_key_clear(KEY_LANGUAGE); break; | 42 | case 0x049: ts_map_key_clear(KEY_CAMERA); break; |
40 | case 0x04d: ts_map_key_clear(KEY_SUBTITLE); break; | 43 | case 0x04a: ts_map_key_clear(KEY_VIDEO); break; |
41 | case 0x031: ts_map_key_clear(KEY_AUDIO); break; | 44 | case 0x04b: ts_map_key_clear(KEY_ANGLE); break; |
42 | case 0x032: ts_map_key_clear(KEY_TEXT); break; | 45 | case 0x04c: ts_map_key_clear(KEY_LANGUAGE); break; |
43 | case 0x033: ts_map_key_clear(KEY_CHANNEL); break; | 46 | case 0x04d: ts_map_key_clear(KEY_SUBTITLE); break; |
47 | case 0x050: ts_map_key_clear(KEY_RADIO); break; | ||
48 | case 0x05a: ts_map_key_clear(KEY_TEXT); break; | ||
49 | case 0x05b: ts_map_key_clear(KEY_RED); break; | ||
50 | case 0x05c: ts_map_key_clear(KEY_GREEN); break; | ||
51 | case 0x05d: ts_map_key_clear(KEY_YELLOW); break; | ||
52 | case 0x05e: ts_map_key_clear(KEY_BLUE); break; | ||
44 | default: | 53 | default: |
45 | return 0; | 54 | return 0; |
46 | } | 55 | } |
@@ -50,6 +59,7 @@ static int ts_input_mapping(struct hid_device *hdev, struct hid_input *hi, | |||
50 | 59 | ||
51 | static const struct hid_device_id ts_devices[] = { | 60 | static const struct hid_device_id ts_devices[] = { |
52 | { HID_USB_DEVICE(USB_VENDOR_ID_TOPSEED, USB_DEVICE_ID_TOPSEED_CYBERLINK) }, | 61 | { HID_USB_DEVICE(USB_VENDOR_ID_TOPSEED, USB_DEVICE_ID_TOPSEED_CYBERLINK) }, |
62 | { HID_USB_DEVICE(USB_VENDOR_ID_BTC, USB_DEVICE_ID_BTC_EMPREX_REMOTE) }, | ||
53 | { } | 63 | { } |
54 | }; | 64 | }; |
55 | MODULE_DEVICE_TABLE(hid, ts_devices); | 65 | MODULE_DEVICE_TABLE(hid, ts_devices); |
diff --git a/drivers/hid/hid-wacom.c b/drivers/hid/hid-wacom.c index f947d8337e21..1e051f1171e4 100644 --- a/drivers/hid/hid-wacom.c +++ b/drivers/hid/hid-wacom.c | |||
@@ -22,14 +22,159 @@ | |||
22 | #include <linux/hid.h> | 22 | #include <linux/hid.h> |
23 | #include <linux/module.h> | 23 | #include <linux/module.h> |
24 | #include <linux/slab.h> | 24 | #include <linux/slab.h> |
25 | #ifdef CONFIG_HID_WACOM_POWER_SUPPLY | ||
26 | #include <linux/power_supply.h> | ||
27 | #endif | ||
25 | 28 | ||
26 | #include "hid-ids.h" | 29 | #include "hid-ids.h" |
27 | 30 | ||
28 | struct wacom_data { | 31 | struct wacom_data { |
29 | __u16 tool; | 32 | __u16 tool; |
30 | unsigned char butstate; | 33 | unsigned char butstate; |
34 | unsigned char high_speed; | ||
35 | #ifdef CONFIG_HID_WACOM_POWER_SUPPLY | ||
36 | int battery_capacity; | ||
37 | struct power_supply battery; | ||
38 | struct power_supply ac; | ||
39 | #endif | ||
31 | }; | 40 | }; |
32 | 41 | ||
42 | #ifdef CONFIG_HID_WACOM_POWER_SUPPLY | ||
43 | /*percent of battery capacity, 0 means AC online*/ | ||
44 | static unsigned short batcap[8] = { 1, 15, 25, 35, 50, 70, 100, 0 }; | ||
45 | |||
46 | static enum power_supply_property wacom_battery_props[] = { | ||
47 | POWER_SUPPLY_PROP_PRESENT, | ||
48 | POWER_SUPPLY_PROP_CAPACITY | ||
49 | }; | ||
50 | |||
51 | static enum power_supply_property wacom_ac_props[] = { | ||
52 | POWER_SUPPLY_PROP_PRESENT, | ||
53 | POWER_SUPPLY_PROP_ONLINE | ||
54 | }; | ||
55 | |||
56 | static int wacom_battery_get_property(struct power_supply *psy, | ||
57 | enum power_supply_property psp, | ||
58 | union power_supply_propval *val) | ||
59 | { | ||
60 | struct wacom_data *wdata = container_of(psy, | ||
61 | struct wacom_data, battery); | ||
62 | int power_state = batcap[wdata->battery_capacity]; | ||
63 | int ret = 0; | ||
64 | |||
65 | switch (psp) { | ||
66 | case POWER_SUPPLY_PROP_PRESENT: | ||
67 | val->intval = 1; | ||
68 | break; | ||
69 | case POWER_SUPPLY_PROP_CAPACITY: | ||
70 | /* show 100% battery capacity when charging */ | ||
71 | if (power_state == 0) | ||
72 | val->intval = 100; | ||
73 | else | ||
74 | val->intval = power_state; | ||
75 | break; | ||
76 | default: | ||
77 | ret = -EINVAL; | ||
78 | break; | ||
79 | } | ||
80 | return ret; | ||
81 | } | ||
82 | |||
83 | static int wacom_ac_get_property(struct power_supply *psy, | ||
84 | enum power_supply_property psp, | ||
85 | union power_supply_propval *val) | ||
86 | { | ||
87 | struct wacom_data *wdata = container_of(psy, struct wacom_data, ac); | ||
88 | int power_state = batcap[wdata->battery_capacity]; | ||
89 | int ret = 0; | ||
90 | |||
91 | switch (psp) { | ||
92 | case POWER_SUPPLY_PROP_PRESENT: | ||
93 | /* fall through */ | ||
94 | case POWER_SUPPLY_PROP_ONLINE: | ||
95 | if (power_state == 0) | ||
96 | val->intval = 1; | ||
97 | else | ||
98 | val->intval = 0; | ||
99 | break; | ||
100 | default: | ||
101 | ret = -EINVAL; | ||
102 | break; | ||
103 | } | ||
104 | return ret; | ||
105 | } | ||
106 | #endif | ||
107 | |||
108 | static void wacom_poke(struct hid_device *hdev, u8 speed) | ||
109 | { | ||
110 | struct wacom_data *wdata = hid_get_drvdata(hdev); | ||
111 | int limit, ret; | ||
112 | char rep_data[2]; | ||
113 | |||
114 | rep_data[0] = 0x03 ; rep_data[1] = 0x00; | ||
115 | limit = 3; | ||
116 | do { | ||
117 | ret = hdev->hid_output_raw_report(hdev, rep_data, 2, | ||
118 | HID_FEATURE_REPORT); | ||
119 | } while (ret < 0 && limit-- > 0); | ||
120 | |||
121 | if (ret >= 0) { | ||
122 | if (speed == 0) | ||
123 | rep_data[0] = 0x05; | ||
124 | else | ||
125 | rep_data[0] = 0x06; | ||
126 | |||
127 | rep_data[1] = 0x00; | ||
128 | limit = 3; | ||
129 | do { | ||
130 | ret = hdev->hid_output_raw_report(hdev, rep_data, 2, | ||
131 | HID_FEATURE_REPORT); | ||
132 | } while (ret < 0 && limit-- > 0); | ||
133 | |||
134 | if (ret >= 0) { | ||
135 | wdata->high_speed = speed; | ||
136 | return; | ||
137 | } | ||
138 | } | ||
139 | |||
140 | /* | ||
141 | * Note that if the raw queries fail, it's not a hard failure and it | ||
142 | * is safe to continue | ||
143 | */ | ||
144 | dev_warn(&hdev->dev, "failed to poke device, command %d, err %d\n", | ||
145 | rep_data[0], ret); | ||
146 | return; | ||
147 | } | ||
148 | |||
149 | static ssize_t wacom_show_speed(struct device *dev, | ||
150 | struct device_attribute | ||
151 | *attr, char *buf) | ||
152 | { | ||
153 | struct wacom_data *wdata = dev_get_drvdata(dev); | ||
154 | |||
155 | return snprintf(buf, PAGE_SIZE, "%i\n", wdata->high_speed); | ||
156 | } | ||
157 | |||
158 | static ssize_t wacom_store_speed(struct device *dev, | ||
159 | struct device_attribute *attr, | ||
160 | const char *buf, size_t count) | ||
161 | { | ||
162 | struct hid_device *hdev = container_of(dev, struct hid_device, dev); | ||
163 | int new_speed; | ||
164 | |||
165 | if (sscanf(buf, "%1d", &new_speed ) != 1) | ||
166 | return -EINVAL; | ||
167 | |||
168 | if (new_speed == 0 || new_speed == 1) { | ||
169 | wacom_poke(hdev, new_speed); | ||
170 | return strnlen(buf, PAGE_SIZE); | ||
171 | } else | ||
172 | return -EINVAL; | ||
173 | } | ||
174 | |||
175 | static DEVICE_ATTR(speed, S_IRUGO | S_IWUGO, | ||
176 | wacom_show_speed, wacom_store_speed); | ||
177 | |||
33 | static int wacom_raw_event(struct hid_device *hdev, struct hid_report *report, | 178 | static int wacom_raw_event(struct hid_device *hdev, struct hid_report *report, |
34 | u8 *raw_data, int size) | 179 | u8 *raw_data, int size) |
35 | { | 180 | { |
@@ -148,6 +293,12 @@ static int wacom_raw_event(struct hid_device *hdev, struct hid_report *report, | |||
148 | input_sync(input); | 293 | input_sync(input); |
149 | } | 294 | } |
150 | 295 | ||
296 | #ifdef CONFIG_HID_WACOM_POWER_SUPPLY | ||
297 | /* Store current battery capacity */ | ||
298 | rw = (data[7] >> 2 & 0x07); | ||
299 | if (rw != wdata->battery_capacity) | ||
300 | wdata->battery_capacity = rw; | ||
301 | #endif | ||
151 | return 1; | 302 | return 1; |
152 | } | 303 | } |
153 | 304 | ||
@@ -157,9 +308,7 @@ static int wacom_probe(struct hid_device *hdev, | |||
157 | struct hid_input *hidinput; | 308 | struct hid_input *hidinput; |
158 | struct input_dev *input; | 309 | struct input_dev *input; |
159 | struct wacom_data *wdata; | 310 | struct wacom_data *wdata; |
160 | char rep_data[2]; | ||
161 | int ret; | 311 | int ret; |
162 | int limit; | ||
163 | 312 | ||
164 | wdata = kzalloc(sizeof(*wdata), GFP_KERNEL); | 313 | wdata = kzalloc(sizeof(*wdata), GFP_KERNEL); |
165 | if (wdata == NULL) { | 314 | if (wdata == NULL) { |
@@ -182,31 +331,53 @@ static int wacom_probe(struct hid_device *hdev, | |||
182 | goto err_free; | 331 | goto err_free; |
183 | } | 332 | } |
184 | 333 | ||
185 | /* | 334 | ret = device_create_file(&hdev->dev, &dev_attr_speed); |
186 | * Note that if the raw queries fail, it's not a hard failure and it | 335 | if (ret) |
187 | * is safe to continue | 336 | dev_warn(&hdev->dev, |
188 | */ | 337 | "can't create sysfs speed attribute err: %d\n", ret); |
189 | 338 | ||
190 | /* Set Wacom mode2 */ | 339 | /* Set Wacom mode 2 with high reporting speed */ |
191 | rep_data[0] = 0x03; rep_data[1] = 0x00; | 340 | wacom_poke(hdev, 1); |
192 | limit = 3; | ||
193 | do { | ||
194 | ret = hdev->hid_output_raw_report(hdev, rep_data, 2, | ||
195 | HID_FEATURE_REPORT); | ||
196 | } while (ret < 0 && limit-- > 0); | ||
197 | if (ret < 0) | ||
198 | dev_warn(&hdev->dev, "failed to poke device #1, %d\n", ret); | ||
199 | 341 | ||
200 | /* 0x06 - high reporting speed, 0x05 - low speed */ | 342 | #ifdef CONFIG_HID_WACOM_POWER_SUPPLY |
201 | rep_data[0] = 0x06; rep_data[1] = 0x00; | 343 | wdata->battery.properties = wacom_battery_props; |
202 | limit = 3; | 344 | wdata->battery.num_properties = ARRAY_SIZE(wacom_battery_props); |
203 | do { | 345 | wdata->battery.get_property = wacom_battery_get_property; |
204 | ret = hdev->hid_output_raw_report(hdev, rep_data, 2, | 346 | wdata->battery.name = "wacom_battery"; |
205 | HID_FEATURE_REPORT); | 347 | wdata->battery.type = POWER_SUPPLY_TYPE_BATTERY; |
206 | } while (ret < 0 && limit-- > 0); | 348 | wdata->battery.use_for_apm = 0; |
207 | if (ret < 0) | ||
208 | dev_warn(&hdev->dev, "failed to poke device #2, %d\n", ret); | ||
209 | 349 | ||
350 | ret = power_supply_register(&hdev->dev, &wdata->battery); | ||
351 | if (ret) { | ||
352 | dev_warn(&hdev->dev, | ||
353 | "can't create sysfs battery attribute, err: %d\n", ret); | ||
354 | /* | ||
355 | * battery attribute is not critical for the tablet, but if it | ||
356 | * failed then there is no need to create ac attribute | ||
357 | */ | ||
358 | goto move_on; | ||
359 | } | ||
360 | |||
361 | wdata->ac.properties = wacom_ac_props; | ||
362 | wdata->ac.num_properties = ARRAY_SIZE(wacom_ac_props); | ||
363 | wdata->ac.get_property = wacom_ac_get_property; | ||
364 | wdata->ac.name = "wacom_ac"; | ||
365 | wdata->ac.type = POWER_SUPPLY_TYPE_MAINS; | ||
366 | wdata->ac.use_for_apm = 0; | ||
367 | |||
368 | ret = power_supply_register(&hdev->dev, &wdata->ac); | ||
369 | if (ret) { | ||
370 | dev_warn(&hdev->dev, | ||
371 | "can't create ac battery attribute, err: %d\n", ret); | ||
372 | /* | ||
373 | * ac attribute is not critical for the tablet, but if it | ||
374 | * failed then we don't want to battery attribute to exist | ||
375 | */ | ||
376 | power_supply_unregister(&wdata->battery); | ||
377 | } | ||
378 | |||
379 | move_on: | ||
380 | #endif | ||
210 | hidinput = list_entry(hdev->inputs.next, struct hid_input, list); | 381 | hidinput = list_entry(hdev->inputs.next, struct hid_input, list); |
211 | input = hidinput->input; | 382 | input = hidinput->input; |
212 | 383 | ||
@@ -251,13 +422,21 @@ err_free: | |||
251 | 422 | ||
252 | static void wacom_remove(struct hid_device *hdev) | 423 | static void wacom_remove(struct hid_device *hdev) |
253 | { | 424 | { |
425 | #ifdef CONFIG_HID_WACOM_POWER_SUPPLY | ||
426 | struct wacom_data *wdata = hid_get_drvdata(hdev); | ||
427 | #endif | ||
254 | hid_hw_stop(hdev); | 428 | hid_hw_stop(hdev); |
429 | |||
430 | #ifdef CONFIG_HID_WACOM_POWER_SUPPLY | ||
431 | power_supply_unregister(&wdata->battery); | ||
432 | power_supply_unregister(&wdata->ac); | ||
433 | #endif | ||
255 | kfree(hid_get_drvdata(hdev)); | 434 | kfree(hid_get_drvdata(hdev)); |
256 | } | 435 | } |
257 | 436 | ||
258 | static const struct hid_device_id wacom_devices[] = { | 437 | static const struct hid_device_id wacom_devices[] = { |
259 | { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_GRAPHIRE_BLUETOOTH) }, | 438 | { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_GRAPHIRE_BLUETOOTH) }, |
260 | 439 | { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS4_BLUETOOTH) }, | |
261 | { } | 440 | { } |
262 | }; | 441 | }; |
263 | MODULE_DEVICE_TABLE(hid, wacom_devices); | 442 | MODULE_DEVICE_TABLE(hid, wacom_devices); |
diff --git a/drivers/hid/hid-zydacron.c b/drivers/hid/hid-zydacron.c new file mode 100644 index 000000000000..9e8d35a203e4 --- /dev/null +++ b/drivers/hid/hid-zydacron.c | |||
@@ -0,0 +1,237 @@ | |||
1 | /* | ||
2 | * HID driver for zydacron remote control | ||
3 | * | ||
4 | * Copyright (c) 2010 Don Prince <dhprince.devel@yahoo.co.uk> | ||
5 | */ | ||
6 | |||
7 | /* | ||
8 | * This program is free software; you can redistribute it and/or modify it | ||
9 | * under the terms of the GNU General Public License as published by the Free | ||
10 | * Software Foundation; either version 2 of the License, or (at your option) | ||
11 | * any later version. | ||
12 | */ | ||
13 | |||
14 | #include <linux/device.h> | ||
15 | #include <linux/hid.h> | ||
16 | #include <linux/module.h> | ||
17 | |||
18 | #include "hid-ids.h" | ||
19 | |||
20 | struct zc_device { | ||
21 | struct input_dev *input_ep81; | ||
22 | unsigned short last_key[4]; | ||
23 | }; | ||
24 | |||
25 | |||
26 | /* | ||
27 | * Zydacron remote control has an invalid HID report descriptor, | ||
28 | * that needs fixing before we can parse it. | ||
29 | */ | ||
30 | static void zc_report_fixup(struct hid_device *hdev, __u8 *rdesc, | ||
31 | unsigned int rsize) | ||
32 | { | ||
33 | if (rsize >= 253 && | ||
34 | rdesc[0x96] == 0xbc && rdesc[0x97] == 0xff && | ||
35 | rdesc[0xca] == 0xbc && rdesc[0xcb] == 0xff && | ||
36 | rdesc[0xe1] == 0xbc && rdesc[0xe2] == 0xff) { | ||
37 | dev_info(&hdev->dev, | ||
38 | "fixing up zydacron remote control report " | ||
39 | "descriptor\n"); | ||
40 | rdesc[0x96] = rdesc[0xca] = rdesc[0xe1] = 0x0c; | ||
41 | rdesc[0x97] = rdesc[0xcb] = rdesc[0xe2] = 0x00; | ||
42 | } | ||
43 | } | ||
44 | |||
45 | #define zc_map_key_clear(c) \ | ||
46 | hid_map_usage_clear(hi, usage, bit, max, EV_KEY, (c)) | ||
47 | |||
48 | static int zc_input_mapping(struct hid_device *hdev, struct hid_input *hi, | ||
49 | struct hid_field *field, struct hid_usage *usage, | ||
50 | unsigned long **bit, int *max) | ||
51 | { | ||
52 | int i; | ||
53 | struct zc_device *zc = hid_get_drvdata(hdev); | ||
54 | zc->input_ep81 = hi->input; | ||
55 | |||
56 | if ((usage->hid & HID_USAGE_PAGE) != HID_UP_CONSUMER) | ||
57 | return 0; | ||
58 | |||
59 | dbg_hid("zynacron input mapping event [0x%x]\n", | ||
60 | usage->hid & HID_USAGE); | ||
61 | |||
62 | switch (usage->hid & HID_USAGE) { | ||
63 | /* report 2 */ | ||
64 | case 0x10: | ||
65 | zc_map_key_clear(KEY_MODE); | ||
66 | break; | ||
67 | case 0x30: | ||
68 | zc_map_key_clear(KEY_SCREEN); | ||
69 | break; | ||
70 | case 0x70: | ||
71 | zc_map_key_clear(KEY_INFO); | ||
72 | break; | ||
73 | /* report 3 */ | ||
74 | case 0x04: | ||
75 | zc_map_key_clear(KEY_RADIO); | ||
76 | break; | ||
77 | /* report 4 */ | ||
78 | case 0x0d: | ||
79 | zc_map_key_clear(KEY_PVR); | ||
80 | break; | ||
81 | case 0x25: | ||
82 | zc_map_key_clear(KEY_TV); | ||
83 | break; | ||
84 | case 0x47: | ||
85 | zc_map_key_clear(KEY_AUDIO); | ||
86 | break; | ||
87 | case 0x49: | ||
88 | zc_map_key_clear(KEY_AUX); | ||
89 | break; | ||
90 | case 0x4a: | ||
91 | zc_map_key_clear(KEY_VIDEO); | ||
92 | break; | ||
93 | case 0x48: | ||
94 | zc_map_key_clear(KEY_DVD); | ||
95 | break; | ||
96 | case 0x24: | ||
97 | zc_map_key_clear(KEY_MENU); | ||
98 | break; | ||
99 | case 0x32: | ||
100 | zc_map_key_clear(KEY_TEXT); | ||
101 | break; | ||
102 | default: | ||
103 | return 0; | ||
104 | } | ||
105 | |||
106 | for (i = 0; i < 4; i++) | ||
107 | zc->last_key[i] = 0; | ||
108 | |||
109 | return 1; | ||
110 | } | ||
111 | |||
112 | static int zc_raw_event(struct hid_device *hdev, struct hid_report *report, | ||
113 | u8 *data, int size) | ||
114 | { | ||
115 | struct zc_device *zc = hid_get_drvdata(hdev); | ||
116 | int ret = 0; | ||
117 | unsigned key; | ||
118 | unsigned short index; | ||
119 | |||
120 | if (report->id == data[0]) { | ||
121 | |||
122 | /* break keys */ | ||
123 | for (index = 0; index < 4; index++) { | ||
124 | key = zc->last_key[index]; | ||
125 | if (key) { | ||
126 | input_event(zc->input_ep81, EV_KEY, key, 0); | ||
127 | zc->last_key[index] = 0; | ||
128 | } | ||
129 | } | ||
130 | |||
131 | key = 0; | ||
132 | switch (report->id) { | ||
133 | case 0x02: | ||
134 | case 0x03: | ||
135 | switch (data[1]) { | ||
136 | case 0x10: | ||
137 | key = KEY_MODE; | ||
138 | index = 0; | ||
139 | break; | ||
140 | case 0x30: | ||
141 | key = KEY_SCREEN; | ||
142 | index = 1; | ||
143 | break; | ||
144 | case 0x70: | ||
145 | key = KEY_INFO; | ||
146 | index = 2; | ||
147 | break; | ||
148 | case 0x04: | ||
149 | key = KEY_RADIO; | ||
150 | index = 3; | ||
151 | break; | ||
152 | } | ||
153 | |||
154 | if (key) { | ||
155 | input_event(zc->input_ep81, EV_KEY, key, 1); | ||
156 | zc->last_key[index] = key; | ||
157 | } | ||
158 | |||
159 | ret = 1; | ||
160 | break; | ||
161 | } | ||
162 | } | ||
163 | |||
164 | return ret; | ||
165 | } | ||
166 | |||
167 | static int zc_probe(struct hid_device *hdev, const struct hid_device_id *id) | ||
168 | { | ||
169 | int ret; | ||
170 | struct zc_device *zc; | ||
171 | |||
172 | zc = kzalloc(sizeof(*zc), GFP_KERNEL); | ||
173 | if (zc == NULL) { | ||
174 | dev_err(&hdev->dev, "zydacron: can't alloc descriptor\n"); | ||
175 | return -ENOMEM; | ||
176 | } | ||
177 | |||
178 | hid_set_drvdata(hdev, zc); | ||
179 | |||
180 | ret = hid_parse(hdev); | ||
181 | if (ret) { | ||
182 | dev_err(&hdev->dev, "zydacron: parse failed\n"); | ||
183 | goto err_free; | ||
184 | } | ||
185 | |||
186 | ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); | ||
187 | if (ret) { | ||
188 | dev_err(&hdev->dev, "zydacron: hw start failed\n"); | ||
189 | goto err_free; | ||
190 | } | ||
191 | |||
192 | return 0; | ||
193 | err_free: | ||
194 | kfree(zc); | ||
195 | |||
196 | return ret; | ||
197 | } | ||
198 | |||
199 | static void zc_remove(struct hid_device *hdev) | ||
200 | { | ||
201 | struct zc_device *zc = hid_get_drvdata(hdev); | ||
202 | |||
203 | hid_hw_stop(hdev); | ||
204 | |||
205 | if (NULL != zc) | ||
206 | kfree(zc); | ||
207 | } | ||
208 | |||
209 | static const struct hid_device_id zc_devices[] = { | ||
210 | { HID_USB_DEVICE(USB_VENDOR_ID_ZYDACRON, USB_DEVICE_ID_ZYDACRON_REMOTE_CONTROL) }, | ||
211 | { } | ||
212 | }; | ||
213 | MODULE_DEVICE_TABLE(hid, zc_devices); | ||
214 | |||
215 | static struct hid_driver zc_driver = { | ||
216 | .name = "zydacron", | ||
217 | .id_table = zc_devices, | ||
218 | .report_fixup = zc_report_fixup, | ||
219 | .input_mapping = zc_input_mapping, | ||
220 | .raw_event = zc_raw_event, | ||
221 | .probe = zc_probe, | ||
222 | .remove = zc_remove, | ||
223 | }; | ||
224 | |||
225 | static int __init zc_init(void) | ||
226 | { | ||
227 | return hid_register_driver(&zc_driver); | ||
228 | } | ||
229 | |||
230 | static void __exit zc_exit(void) | ||
231 | { | ||
232 | hid_unregister_driver(&zc_driver); | ||
233 | } | ||
234 | |||
235 | module_init(zc_init); | ||
236 | module_exit(zc_exit); | ||
237 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/hid/hidraw.c b/drivers/hid/hidraw.c index 6eadf1a9b3cc..3ccd47850677 100644 --- a/drivers/hid/hidraw.c +++ b/drivers/hid/hidraw.c | |||
@@ -106,38 +106,48 @@ out: | |||
106 | static ssize_t hidraw_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) | 106 | static ssize_t hidraw_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) |
107 | { | 107 | { |
108 | unsigned int minor = iminor(file->f_path.dentry->d_inode); | 108 | unsigned int minor = iminor(file->f_path.dentry->d_inode); |
109 | /* FIXME: What stops hidraw_table going NULL */ | 109 | struct hid_device *dev; |
110 | struct hid_device *dev = hidraw_table[minor]->hid; | ||
111 | __u8 *buf; | 110 | __u8 *buf; |
112 | int ret = 0; | 111 | int ret = 0; |
113 | 112 | ||
114 | if (!dev->hid_output_raw_report) | 113 | mutex_lock(&minors_lock); |
115 | return -ENODEV; | 114 | dev = hidraw_table[minor]->hid; |
115 | |||
116 | if (!dev->hid_output_raw_report) { | ||
117 | ret = -ENODEV; | ||
118 | goto out; | ||
119 | } | ||
116 | 120 | ||
117 | if (count > HID_MAX_BUFFER_SIZE) { | 121 | if (count > HID_MAX_BUFFER_SIZE) { |
118 | printk(KERN_WARNING "hidraw: pid %d passed too large report\n", | 122 | printk(KERN_WARNING "hidraw: pid %d passed too large report\n", |
119 | task_pid_nr(current)); | 123 | task_pid_nr(current)); |
120 | return -EINVAL; | 124 | ret = -EINVAL; |
125 | goto out; | ||
121 | } | 126 | } |
122 | 127 | ||
123 | if (count < 2) { | 128 | if (count < 2) { |
124 | printk(KERN_WARNING "hidraw: pid %d passed too short report\n", | 129 | printk(KERN_WARNING "hidraw: pid %d passed too short report\n", |
125 | task_pid_nr(current)); | 130 | task_pid_nr(current)); |
126 | return -EINVAL; | 131 | ret = -EINVAL; |
132 | goto out; | ||
127 | } | 133 | } |
128 | 134 | ||
129 | buf = kmalloc(count * sizeof(__u8), GFP_KERNEL); | 135 | buf = kmalloc(count * sizeof(__u8), GFP_KERNEL); |
130 | if (!buf) | 136 | if (!buf) { |
131 | return -ENOMEM; | 137 | ret = -ENOMEM; |
138 | goto out; | ||
139 | } | ||
132 | 140 | ||
133 | if (copy_from_user(buf, buffer, count)) { | 141 | if (copy_from_user(buf, buffer, count)) { |
134 | ret = -EFAULT; | 142 | ret = -EFAULT; |
135 | goto out; | 143 | goto out_free; |
136 | } | 144 | } |
137 | 145 | ||
138 | ret = dev->hid_output_raw_report(dev, buf, count, HID_OUTPUT_REPORT); | 146 | ret = dev->hid_output_raw_report(dev, buf, count, HID_OUTPUT_REPORT); |
139 | out: | 147 | out_free: |
140 | kfree(buf); | 148 | kfree(buf); |
149 | out: | ||
150 | mutex_unlock(&minors_lock); | ||
141 | return ret; | 151 | return ret; |
142 | } | 152 | } |
143 | 153 | ||
@@ -165,11 +175,8 @@ static int hidraw_open(struct inode *inode, struct file *file) | |||
165 | goto out; | 175 | goto out; |
166 | } | 176 | } |
167 | 177 | ||
168 | lock_kernel(); | ||
169 | mutex_lock(&minors_lock); | 178 | mutex_lock(&minors_lock); |
170 | if (!hidraw_table[minor]) { | 179 | if (!hidraw_table[minor]) { |
171 | printk(KERN_EMERG "hidraw device with minor %d doesn't exist\n", | ||
172 | minor); | ||
173 | kfree(list); | 180 | kfree(list); |
174 | err = -ENODEV; | 181 | err = -ENODEV; |
175 | goto out_unlock; | 182 | goto out_unlock; |
@@ -197,7 +204,6 @@ static int hidraw_open(struct inode *inode, struct file *file) | |||
197 | 204 | ||
198 | out_unlock: | 205 | out_unlock: |
199 | mutex_unlock(&minors_lock); | 206 | mutex_unlock(&minors_lock); |
200 | unlock_kernel(); | ||
201 | out: | 207 | out: |
202 | return err; | 208 | return err; |
203 | 209 | ||
@@ -209,11 +215,8 @@ static int hidraw_release(struct inode * inode, struct file * file) | |||
209 | struct hidraw *dev; | 215 | struct hidraw *dev; |
210 | struct hidraw_list *list = file->private_data; | 216 | struct hidraw_list *list = file->private_data; |
211 | 217 | ||
212 | if (!hidraw_table[minor]) { | 218 | if (!hidraw_table[minor]) |
213 | printk(KERN_EMERG "hidraw device with minor %d doesn't exist\n", | ||
214 | minor); | ||
215 | return -ENODEV; | 219 | return -ENODEV; |
216 | } | ||
217 | 220 | ||
218 | list_del(&list->node); | 221 | list_del(&list->node); |
219 | dev = hidraw_table[minor]; | 222 | dev = hidraw_table[minor]; |
@@ -238,11 +241,12 @@ static long hidraw_ioctl(struct file *file, unsigned int cmd, | |||
238 | struct inode *inode = file->f_path.dentry->d_inode; | 241 | struct inode *inode = file->f_path.dentry->d_inode; |
239 | unsigned int minor = iminor(inode); | 242 | unsigned int minor = iminor(inode); |
240 | long ret = 0; | 243 | long ret = 0; |
241 | /* FIXME: What stops hidraw_table going NULL */ | 244 | struct hidraw *dev; |
242 | struct hidraw *dev = hidraw_table[minor]; | ||
243 | void __user *user_arg = (void __user*) arg; | 245 | void __user *user_arg = (void __user*) arg; |
244 | 246 | ||
245 | lock_kernel(); | 247 | mutex_lock(&minors_lock); |
248 | dev = hidraw_table[minor]; | ||
249 | |||
246 | switch (cmd) { | 250 | switch (cmd) { |
247 | case HIDIOCGRDESCSIZE: | 251 | case HIDIOCGRDESCSIZE: |
248 | if (put_user(dev->hid->rsize, (int __user *)arg)) | 252 | if (put_user(dev->hid->rsize, (int __user *)arg)) |
@@ -311,11 +315,11 @@ static long hidraw_ioctl(struct file *file, unsigned int cmd, | |||
311 | -EFAULT : len; | 315 | -EFAULT : len; |
312 | break; | 316 | break; |
313 | } | 317 | } |
314 | } | 318 | } |
315 | 319 | ||
316 | ret = -ENOTTY; | 320 | ret = -ENOTTY; |
317 | } | 321 | } |
318 | unlock_kernel(); | 322 | mutex_unlock(&minors_lock); |
319 | return ret; | 323 | return ret; |
320 | } | 324 | } |
321 | 325 | ||
diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c index df619756b7ae..1ebd3244eb85 100644 --- a/drivers/hid/usbhid/hid-core.c +++ b/drivers/hid/usbhid/hid-core.c | |||
@@ -623,6 +623,7 @@ int usbhid_wait_io(struct hid_device *hid) | |||
623 | 623 | ||
624 | return 0; | 624 | return 0; |
625 | } | 625 | } |
626 | EXPORT_SYMBOL_GPL(usbhid_wait_io); | ||
626 | 627 | ||
627 | static int hid_set_idle(struct usb_device *dev, int ifnum, int report, int idle) | 628 | static int hid_set_idle(struct usb_device *dev, int ifnum, int report, int idle) |
628 | { | 629 | { |
@@ -806,16 +807,36 @@ static int usbhid_output_raw_report(struct hid_device *hid, __u8 *buf, size_t co | |||
806 | struct usb_host_interface *interface = intf->cur_altsetting; | 807 | struct usb_host_interface *interface = intf->cur_altsetting; |
807 | int ret; | 808 | int ret; |
808 | 809 | ||
809 | ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), | 810 | if (usbhid->urbout) { |
810 | HID_REQ_SET_REPORT, | 811 | int actual_length; |
811 | USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE, | 812 | int skipped_report_id = 0; |
812 | ((report_type + 1) << 8) | *buf, | 813 | if (buf[0] == 0x0) { |
813 | interface->desc.bInterfaceNumber, buf + 1, count - 1, | 814 | /* Don't send the Report ID */ |
814 | USB_CTRL_SET_TIMEOUT); | 815 | buf++; |
815 | 816 | count--; | |
816 | /* count also the report id */ | 817 | skipped_report_id = 1; |
817 | if (ret > 0) | 818 | } |
818 | ret++; | 819 | ret = usb_interrupt_msg(dev, usbhid->urbout->pipe, |
820 | buf, count, &actual_length, | ||
821 | USB_CTRL_SET_TIMEOUT); | ||
822 | /* return the number of bytes transferred */ | ||
823 | if (ret == 0) { | ||
824 | ret = actual_length; | ||
825 | /* count also the report id */ | ||
826 | if (skipped_report_id) | ||
827 | ret++; | ||
828 | } | ||
829 | } else { | ||
830 | ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), | ||
831 | HID_REQ_SET_REPORT, | ||
832 | USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE, | ||
833 | ((report_type + 1) << 8) | *buf, | ||
834 | interface->desc.bInterfaceNumber, buf + 1, count - 1, | ||
835 | USB_CTRL_SET_TIMEOUT); | ||
836 | /* count also the report id */ | ||
837 | if (ret > 0) | ||
838 | ret++; | ||
839 | } | ||
819 | 840 | ||
820 | return ret; | 841 | return ret; |
821 | } | 842 | } |
@@ -1017,12 +1038,15 @@ static int usbhid_start(struct hid_device *hid) | |||
1017 | /* Some keyboards don't work until their LEDs have been set. | 1038 | /* Some keyboards don't work until their LEDs have been set. |
1018 | * Since BIOSes do set the LEDs, it must be safe for any device | 1039 | * Since BIOSes do set the LEDs, it must be safe for any device |
1019 | * that supports the keyboard boot protocol. | 1040 | * that supports the keyboard boot protocol. |
1041 | * In addition, enable remote wakeup by default for all keyboard | ||
1042 | * devices supporting the boot protocol. | ||
1020 | */ | 1043 | */ |
1021 | if (interface->desc.bInterfaceSubClass == USB_INTERFACE_SUBCLASS_BOOT && | 1044 | if (interface->desc.bInterfaceSubClass == USB_INTERFACE_SUBCLASS_BOOT && |
1022 | interface->desc.bInterfaceProtocol == | 1045 | interface->desc.bInterfaceProtocol == |
1023 | USB_INTERFACE_PROTOCOL_KEYBOARD) | 1046 | USB_INTERFACE_PROTOCOL_KEYBOARD) { |
1024 | usbhid_set_leds(hid); | 1047 | usbhid_set_leds(hid); |
1025 | 1048 | device_set_wakeup_enable(&dev->dev, 1); | |
1049 | } | ||
1026 | return 0; | 1050 | return 0; |
1027 | 1051 | ||
1028 | fail: | 1052 | fail: |
@@ -1131,6 +1155,7 @@ static int usbhid_probe(struct usb_interface *intf, const struct usb_device_id * | |||
1131 | hid->vendor = le16_to_cpu(dev->descriptor.idVendor); | 1155 | hid->vendor = le16_to_cpu(dev->descriptor.idVendor); |
1132 | hid->product = le16_to_cpu(dev->descriptor.idProduct); | 1156 | hid->product = le16_to_cpu(dev->descriptor.idProduct); |
1133 | hid->name[0] = 0; | 1157 | hid->name[0] = 0; |
1158 | hid->quirks = usbhid_lookup_quirk(hid->vendor, hid->product); | ||
1134 | if (intf->cur_altsetting->desc.bInterfaceProtocol == | 1159 | if (intf->cur_altsetting->desc.bInterfaceProtocol == |
1135 | USB_INTERFACE_PROTOCOL_MOUSE) | 1160 | USB_INTERFACE_PROTOCOL_MOUSE) |
1136 | hid->type = HID_TYPE_USBMOUSE; | 1161 | hid->type = HID_TYPE_USBMOUSE; |
@@ -1287,6 +1312,11 @@ static int hid_suspend(struct usb_interface *intf, pm_message_t message) | |||
1287 | { | 1312 | { |
1288 | set_bit(HID_REPORTED_IDLE, &usbhid->iofl); | 1313 | set_bit(HID_REPORTED_IDLE, &usbhid->iofl); |
1289 | spin_unlock_irq(&usbhid->lock); | 1314 | spin_unlock_irq(&usbhid->lock); |
1315 | if (hid->driver && hid->driver->suspend) { | ||
1316 | status = hid->driver->suspend(hid, message); | ||
1317 | if (status < 0) | ||
1318 | return status; | ||
1319 | } | ||
1290 | } else { | 1320 | } else { |
1291 | usbhid_mark_busy(usbhid); | 1321 | usbhid_mark_busy(usbhid); |
1292 | spin_unlock_irq(&usbhid->lock); | 1322 | spin_unlock_irq(&usbhid->lock); |
@@ -1294,6 +1324,11 @@ static int hid_suspend(struct usb_interface *intf, pm_message_t message) | |||
1294 | } | 1324 | } |
1295 | 1325 | ||
1296 | } else { | 1326 | } else { |
1327 | if (hid->driver && hid->driver->suspend) { | ||
1328 | status = hid->driver->suspend(hid, message); | ||
1329 | if (status < 0) | ||
1330 | return status; | ||
1331 | } | ||
1297 | spin_lock_irq(&usbhid->lock); | 1332 | spin_lock_irq(&usbhid->lock); |
1298 | set_bit(HID_REPORTED_IDLE, &usbhid->iofl); | 1333 | set_bit(HID_REPORTED_IDLE, &usbhid->iofl); |
1299 | spin_unlock_irq(&usbhid->lock); | 1334 | spin_unlock_irq(&usbhid->lock); |
@@ -1348,6 +1383,11 @@ static int hid_resume(struct usb_interface *intf) | |||
1348 | hid_io_error(hid); | 1383 | hid_io_error(hid); |
1349 | usbhid_restart_queues(usbhid); | 1384 | usbhid_restart_queues(usbhid); |
1350 | 1385 | ||
1386 | if (status >= 0 && hid->driver && hid->driver->resume) { | ||
1387 | int ret = hid->driver->resume(hid); | ||
1388 | if (ret < 0) | ||
1389 | status = ret; | ||
1390 | } | ||
1351 | dev_dbg(&intf->dev, "resume status %d\n", status); | 1391 | dev_dbg(&intf->dev, "resume status %d\n", status); |
1352 | return 0; | 1392 | return 0; |
1353 | } | 1393 | } |
@@ -1356,9 +1396,16 @@ static int hid_reset_resume(struct usb_interface *intf) | |||
1356 | { | 1396 | { |
1357 | struct hid_device *hid = usb_get_intfdata(intf); | 1397 | struct hid_device *hid = usb_get_intfdata(intf); |
1358 | struct usbhid_device *usbhid = hid->driver_data; | 1398 | struct usbhid_device *usbhid = hid->driver_data; |
1399 | int status; | ||
1359 | 1400 | ||
1360 | clear_bit(HID_REPORTED_IDLE, &usbhid->iofl); | 1401 | clear_bit(HID_REPORTED_IDLE, &usbhid->iofl); |
1361 | return hid_post_reset(intf); | 1402 | status = hid_post_reset(intf); |
1403 | if (status >= 0 && hid->driver && hid->driver->reset_resume) { | ||
1404 | int ret = hid->driver->reset_resume(hid); | ||
1405 | if (ret < 0) | ||
1406 | status = ret; | ||
1407 | } | ||
1408 | return status; | ||
1362 | } | 1409 | } |
1363 | 1410 | ||
1364 | #endif /* CONFIG_PM */ | 1411 | #endif /* CONFIG_PM */ |
diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c index 1152f9b5fd44..5ff8d327f33a 100644 --- a/drivers/hid/usbhid/hid-quirks.c +++ b/drivers/hid/usbhid/hid-quirks.c | |||
@@ -33,6 +33,7 @@ static const struct hid_blacklist { | |||
33 | { USB_VENDOR_ID_AASHIMA, USB_DEVICE_ID_AASHIMA_PREDATOR, HID_QUIRK_BADPAD }, | 33 | { USB_VENDOR_ID_AASHIMA, USB_DEVICE_ID_AASHIMA_PREDATOR, HID_QUIRK_BADPAD }, |
34 | { USB_VENDOR_ID_ALPS, USB_DEVICE_ID_IBM_GAMEPAD, HID_QUIRK_BADPAD }, | 34 | { USB_VENDOR_ID_ALPS, USB_DEVICE_ID_IBM_GAMEPAD, HID_QUIRK_BADPAD }, |
35 | { USB_VENDOR_ID_CHIC, USB_DEVICE_ID_CHIC_GAMEPAD, HID_QUIRK_BADPAD }, | 35 | { USB_VENDOR_ID_CHIC, USB_DEVICE_ID_CHIC_GAMEPAD, HID_QUIRK_BADPAD }, |
36 | { USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH, HID_QUIRK_MULTI_INPUT }, | ||
36 | { USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_DRIVING, HID_QUIRK_BADPAD | HID_QUIRK_MULTI_INPUT }, | 37 | { USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_DRIVING, HID_QUIRK_BADPAD | HID_QUIRK_MULTI_INPUT }, |
37 | { USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_FLYING, HID_QUIRK_BADPAD | HID_QUIRK_MULTI_INPUT }, | 38 | { USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_FLYING, HID_QUIRK_BADPAD | HID_QUIRK_MULTI_INPUT }, |
38 | { USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_FIGHTING, HID_QUIRK_BADPAD | HID_QUIRK_MULTI_INPUT }, | 39 | { USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_FIGHTING, HID_QUIRK_BADPAD | HID_QUIRK_MULTI_INPUT }, |
diff --git a/drivers/hid/usbhid/hiddev.c b/drivers/hid/usbhid/hiddev.c index 433602aed468..c24d2fa3e3b6 100644 --- a/drivers/hid/usbhid/hiddev.c +++ b/drivers/hid/usbhid/hiddev.c | |||
@@ -267,6 +267,7 @@ static int hiddev_open(struct inode *inode, struct file *file) | |||
267 | struct hiddev_list *list; | 267 | struct hiddev_list *list; |
268 | int res, i; | 268 | int res, i; |
269 | 269 | ||
270 | /* See comment in hiddev_connect() for BKL explanation */ | ||
270 | lock_kernel(); | 271 | lock_kernel(); |
271 | i = iminor(inode) - HIDDEV_MINOR_BASE; | 272 | i = iminor(inode) - HIDDEV_MINOR_BASE; |
272 | 273 | ||
@@ -894,8 +895,22 @@ int hiddev_connect(struct hid_device *hid, unsigned int force) | |||
894 | hiddev->hid = hid; | 895 | hiddev->hid = hid; |
895 | hiddev->exist = 1; | 896 | hiddev->exist = 1; |
896 | 897 | ||
897 | /* when lock_kernel() usage is fixed in usb_open(), | 898 | /* |
898 | * we could also fix it here */ | 899 | * BKL here is used to avoid race after usb_register_dev(). |
900 | * Once the device node has been created, open() could happen on it. | ||
901 | * The code below will then fail, as hiddev_table hasn't been | ||
902 | * updated. | ||
903 | * | ||
904 | * The obvious fix -- introducing mutex to guard hiddev_table[] | ||
905 | * doesn't work, as usb_open() and usb_register_dev() both take | ||
906 | * minor_rwsem, thus we'll have ABBA deadlock. | ||
907 | * | ||
908 | * Before BKL pushdown, usb_open() had been acquiring it in right | ||
909 | * order, so _open() was safe to use it to protect from this race. | ||
910 | * Now the order is different, but AB-BA deadlock still doesn't occur | ||
911 | * as BKL is dropped on schedule() (i.e. while sleeping on | ||
912 | * minor_rwsem). Fugly. | ||
913 | */ | ||
899 | lock_kernel(); | 914 | lock_kernel(); |
900 | retval = usb_register_dev(usbhid->intf, &hiddev_class); | 915 | retval = usb_register_dev(usbhid->intf, &hiddev_class); |
901 | if (retval) { | 916 | if (retval) { |
diff --git a/drivers/hid/usbhid/usbkbd.c b/drivers/hid/usbhid/usbkbd.c index bb14c8270af3..a948605564fb 100644 --- a/drivers/hid/usbhid/usbkbd.c +++ b/drivers/hid/usbhid/usbkbd.c | |||
@@ -311,6 +311,7 @@ static int usb_kbd_probe(struct usb_interface *iface, | |||
311 | goto fail2; | 311 | goto fail2; |
312 | 312 | ||
313 | usb_set_intfdata(iface, kbd); | 313 | usb_set_intfdata(iface, kbd); |
314 | device_set_wakeup_enable(&dev->dev, 1); | ||
314 | return 0; | 315 | return 0; |
315 | 316 | ||
316 | fail2: | 317 | fail2: |