diff options
28 files changed, 6907 insertions, 157 deletions
diff --git a/Documentation/ABI/testing/sysfs-driver-hid-picolcd b/Documentation/ABI/testing/sysfs-driver-hid-picolcd new file mode 100644 index 000000000000..08579e7e1e89 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-driver-hid-picolcd | |||
| @@ -0,0 +1,43 @@ | |||
| 1 | What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/operation_mode | ||
| 2 | Date: March 2010 | ||
| 3 | Contact: Bruno Prémont <bonbons@linux-vserver.org> | ||
| 4 | Description: Make it possible to switch the PicoLCD device between LCD | ||
| 5 | (firmware) and bootloader (flasher) operation modes. | ||
| 6 | |||
| 7 | Reading: returns list of available modes, the active mode being | ||
| 8 | enclosed in brackets ('[' and ']') | ||
| 9 | |||
| 10 | Writing: causes operation mode switch. Permitted values are | ||
| 11 | the non-active mode names listed when read. | ||
| 12 | |||
| 13 | Note: when switching mode the current PicoLCD HID device gets | ||
| 14 | disconnected and reconnects after above delay (see attribute | ||
| 15 | operation_mode_delay for its value). | ||
| 16 | |||
| 17 | |||
| 18 | What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/operation_mode_delay | ||
| 19 | Date: April 2010 | ||
| 20 | Contact: Bruno Prémont <bonbons@linux-vserver.org> | ||
| 21 | Description: Delay PicoLCD waits before restarting in new mode when | ||
| 22 | operation_mode has changed. | ||
| 23 | |||
| 24 | Reading/Writing: It is expressed in ms and permitted range is | ||
| 25 | 0..30000ms. | ||
| 26 | |||
| 27 | |||
| 28 | What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/fb_update_rate | ||
| 29 | Date: March 2010 | ||
| 30 | Contact: Bruno Prémont <bonbons@linux-vserver.org> | ||
| 31 | Description: Make it possible to adjust defio refresh rate. | ||
| 32 | |||
| 33 | Reading: returns list of available refresh rates (expressed in Hz), | ||
| 34 | the active refresh rate being enclosed in brackets ('[' and ']') | ||
| 35 | |||
| 36 | Writing: accepts new refresh rate expressed in integer Hz | ||
| 37 | within permitted rates. | ||
| 38 | |||
| 39 | Note: As device can barely do 2 complete refreshes a second | ||
| 40 | it only makes sense to adjust this value if only one or two | ||
| 41 | tiles get changed and it's not appropriate to expect the application | ||
| 42 | to flush it's tiny changes explicitely at higher than default rate. | ||
| 43 | |||
diff --git a/Documentation/ABI/testing/sysfs-driver-hid-prodikeys b/Documentation/ABI/testing/sysfs-driver-hid-prodikeys new file mode 100644 index 000000000000..05d988c29a83 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-driver-hid-prodikeys | |||
| @@ -0,0 +1,29 @@ | |||
| 1 | What: /sys/bus/hid/drivers/prodikeys/.../channel | ||
| 2 | Date: April 2010 | ||
| 3 | KernelVersion: 2.6.34 | ||
| 4 | Contact: Don Prince <dhprince.devel@yahoo.co.uk> | ||
| 5 | Description: | ||
| 6 | Allows control (via software) the midi channel to which | ||
| 7 | that the pc-midi keyboard will output.midi data. | ||
| 8 | Range: 0..15 | ||
| 9 | Type: Read/write | ||
| 10 | What: /sys/bus/hid/drivers/prodikeys/.../sustain | ||
| 11 | Date: April 2010 | ||
| 12 | KernelVersion: 2.6.34 | ||
| 13 | Contact: Don Prince <dhprince.devel@yahoo.co.uk> | ||
| 14 | Description: | ||
| 15 | Allows control (via software) the sustain duration of a | ||
| 16 | note held by the pc-midi driver. | ||
| 17 | 0 means sustain mode is disabled. | ||
| 18 | Range: 0..5000 (milliseconds) | ||
| 19 | Type: Read/write | ||
| 20 | What: /sys/bus/hid/drivers/prodikeys/.../octave | ||
| 21 | Date: April 2010 | ||
| 22 | KernelVersion: 2.6.34 | ||
| 23 | Contact: Don Prince <dhprince.devel@yahoo.co.uk> | ||
| 24 | Description: | ||
| 25 | Controls the octave shift modifier in the pc-midi driver. | ||
| 26 | The octave can be shifted via software up/down 2 octaves. | ||
| 27 | 0 means the no ocatve shift. | ||
| 28 | Range: -2..2 (minus 2 to plus 2) | ||
| 29 | Type: Read/Write | ||
diff --git a/Documentation/ABI/testing/sysfs-driver-hid-roccat-kone b/Documentation/ABI/testing/sysfs-driver-hid-roccat-kone new file mode 100644 index 000000000000..88340a23ce91 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-driver-hid-roccat-kone | |||
| @@ -0,0 +1,111 @@ | |||
| 1 | What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/actual_dpi | ||
| 2 | Date: March 2010 | ||
| 3 | Contact: Stefan Achatz <erazor_de@users.sourceforge.net> | ||
| 4 | Description: It is possible to switch the dpi setting of the mouse with the | ||
| 5 | press of a button. | ||
| 6 | When read, this file returns the raw number of the actual dpi | ||
| 7 | setting reported by the mouse. This number has to be further | ||
| 8 | processed to receive the real dpi value. | ||
| 9 | |||
| 10 | VALUE DPI | ||
| 11 | 1 800 | ||
| 12 | 2 1200 | ||
| 13 | 3 1600 | ||
| 14 | 4 2000 | ||
| 15 | 5 2400 | ||
| 16 | 6 3200 | ||
| 17 | |||
| 18 | This file is readonly. | ||
| 19 | |||
| 20 | What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/actual_profile | ||
| 21 | Date: March 2010 | ||
| 22 | Contact: Stefan Achatz <erazor_de@users.sourceforge.net> | ||
| 23 | Description: When read, this file returns the number of the actual profile. | ||
| 24 | This file is readonly. | ||
| 25 | |||
| 26 | What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/firmware_version | ||
| 27 | Date: March 2010 | ||
| 28 | Contact: Stefan Achatz <erazor_de@users.sourceforge.net> | ||
| 29 | Description: When read, this file returns the raw integer version number of the | ||
| 30 | firmware reported by the mouse. Using the integer value eases | ||
| 31 | further usage in other programs. To receive the real version | ||
| 32 | number the decimal point has to be shifted 2 positions to the | ||
| 33 | left. E.g. a returned value of 138 means 1.38 | ||
| 34 | This file is readonly. | ||
| 35 | |||
| 36 | What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/kone_driver_version | ||
| 37 | Date: March 2010 | ||
| 38 | Contact: Stefan Achatz <erazor_de@users.sourceforge.net> | ||
| 39 | Description: When read, this file returns the driver version. | ||
| 40 | The format of the string is "v<major>.<minor>.<patchlevel>". | ||
| 41 | This attribute is used by the userland tools to find the sysfs- | ||
| 42 | paths of installed kone-mice and determine the capabilites of | ||
| 43 | the driver. Versions of this driver for old kernels replace | ||
| 44 | usbhid instead of generic-usb. The way to scan for this file | ||
| 45 | has been chosen to provide a consistent way for all supported | ||
| 46 | kernel versions. | ||
| 47 | This file is readonly. | ||
| 48 | |||
| 49 | What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/profile[1-5] | ||
| 50 | Date: March 2010 | ||
| 51 | Contact: Stefan Achatz <erazor_de@users.sourceforge.net> | ||
| 52 | Description: The mouse can store 5 profiles which can be switched by the | ||
| 53 | press of a button. A profile holds informations like button | ||
| 54 | mappings, sensitivity, the colors of the 5 leds and light | ||
| 55 | effects. | ||
| 56 | When read, these files return the respective profile. The | ||
| 57 | returned data is 975 bytes in size. | ||
| 58 | When written, this file lets one write the respective profile | ||
| 59 | data back to the mouse. The data has to be 975 bytes long. | ||
| 60 | The mouse will reject invalid data, whereas the profile number | ||
| 61 | stored in the profile doesn't need to fit the number of the | ||
| 62 | store. | ||
| 63 | |||
| 64 | What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/settings | ||
| 65 | Date: March 2010 | ||
| 66 | Contact: Stefan Achatz <erazor_de@users.sourceforge.net> | ||
| 67 | Description: When read, this file returns the settings stored in the mouse. | ||
| 68 | The size of the data is 36 bytes and holds information like the | ||
| 69 | startup_profile, tcu state and calibration_data. | ||
| 70 | When written, this file lets write settings back to the mouse. | ||
| 71 | The data has to be 36 bytes long. The mouse will reject invalid | ||
| 72 | data. | ||
| 73 | |||
| 74 | What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/startup_profile | ||
| 75 | Date: March 2010 | ||
| 76 | Contact: Stefan Achatz <erazor_de@users.sourceforge.net> | ||
| 77 | Description: The integer value of this attribute ranges from 1 to 5. | ||
| 78 | When read, this attribute returns the number of the profile | ||
| 79 | that's active when the mouse is powered on. | ||
| 80 | When written, this file sets the number of the startup profile | ||
| 81 | and the mouse activates this profile immediately. | ||
| 82 | |||
| 83 | What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/tcu | ||
| 84 | Date: March 2010 | ||
| 85 | Contact: Stefan Achatz <erazor_de@users.sourceforge.net> | ||
| 86 | Description: The mouse has a "Tracking Control Unit" which lets the user | ||
| 87 | calibrate the laser power to fit the mousepad surface. | ||
| 88 | When read, this file returns the current state of the TCU, | ||
| 89 | where 0 means off and 1 means on. | ||
| 90 | Writing 0 in this file will switch the TCU off. | ||
| 91 | Writing 1 in this file will start the calibration which takes | ||
| 92 | around 6 seconds to complete and activates the TCU. | ||
| 93 | |||
| 94 | What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/weight | ||
| 95 | Date: March 2010 | ||
| 96 | Contact: Stefan Achatz <erazor_de@users.sourceforge.net> | ||
| 97 | Description: The mouse can be equipped with one of four supplied weights | ||
| 98 | ranging from 5 to 20 grams which are recognized by the mouse | ||
| 99 | and its value can be read out. When read, this file returns the | ||
| 100 | raw value returned by the mouse which eases further processing | ||
| 101 | in other software. | ||
| 102 | The values map to the weights as follows: | ||
| 103 | |||
| 104 | VALUE WEIGHT | ||
| 105 | 0 none | ||
| 106 | 1 5g | ||
| 107 | 2 10g | ||
| 108 | 3 15g | ||
| 109 | 4 20g | ||
| 110 | |||
| 111 | This file is readonly. | ||
diff --git a/Documentation/ABI/testing/sysfs-wacom b/Documentation/ABI/testing/sysfs-wacom new file mode 100644 index 000000000000..1517976e25c4 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-wacom | |||
| @@ -0,0 +1,10 @@ | |||
| 1 | What: /sys/class/hidraw/hidraw*/device/speed | ||
| 2 | Date: April 2010 | ||
| 3 | Kernel Version: 2.6.35 | ||
| 4 | Contact: linux-bluetooth@vger.kernel.org | ||
| 5 | Description: | ||
| 6 | The /sys/class/hidraw/hidraw*/device/speed file controls | ||
| 7 | reporting speed of wacom bluetooth tablet. Reading from | ||
| 8 | this file returns 1 if tablet reports in high speed mode | ||
| 9 | or 0 otherwise. Writing to this file one of these values | ||
| 10 | switches reporting speed. | ||
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: |
diff --git a/include/linux/hid.h b/include/linux/hid.h index b1344ec4b7fc..895001f7f4b2 100644 --- a/include/linux/hid.h +++ b/include/linux/hid.h | |||
| @@ -308,11 +308,13 @@ struct hid_item { | |||
| 308 | #define HID_QUIRK_NOTOUCH 0x00000002 | 308 | #define HID_QUIRK_NOTOUCH 0x00000002 |
| 309 | #define HID_QUIRK_IGNORE 0x00000004 | 309 | #define HID_QUIRK_IGNORE 0x00000004 |
| 310 | #define HID_QUIRK_NOGET 0x00000008 | 310 | #define HID_QUIRK_NOGET 0x00000008 |
| 311 | #define HID_QUIRK_HIDDEV_FORCE 0x00000010 | ||
| 311 | #define HID_QUIRK_BADPAD 0x00000020 | 312 | #define HID_QUIRK_BADPAD 0x00000020 |
| 312 | #define HID_QUIRK_MULTI_INPUT 0x00000040 | 313 | #define HID_QUIRK_MULTI_INPUT 0x00000040 |
| 313 | #define HID_QUIRK_SKIP_OUTPUT_REPORTS 0x00010000 | 314 | #define HID_QUIRK_SKIP_OUTPUT_REPORTS 0x00010000 |
| 314 | #define HID_QUIRK_FULLSPEED_INTERVAL 0x10000000 | 315 | #define HID_QUIRK_FULLSPEED_INTERVAL 0x10000000 |
| 315 | #define HID_QUIRK_NO_INIT_REPORTS 0x20000000 | 316 | #define HID_QUIRK_NO_INIT_REPORTS 0x20000000 |
| 317 | #define HID_QUIRK_NO_IGNORE 0x40000000 | ||
| 316 | 318 | ||
| 317 | /* | 319 | /* |
| 318 | * This is the global environment of the parser. This information is | 320 | * This is the global environment of the parser. This information is |
| @@ -589,6 +591,9 @@ struct hid_usage_id { | |||
| 589 | * @report_fixup: called before report descriptor parsing (NULL means nop) | 591 | * @report_fixup: called before report descriptor parsing (NULL means nop) |
| 590 | * @input_mapping: invoked on input registering before mapping an usage | 592 | * @input_mapping: invoked on input registering before mapping an usage |
| 591 | * @input_mapped: invoked on input registering after mapping an usage | 593 | * @input_mapped: invoked on input registering after mapping an usage |
| 594 | * @suspend: invoked on suspend (NULL means nop) | ||
| 595 | * @resume: invoked on resume if device was not reset (NULL means nop) | ||
| 596 | * @reset_resume: invoked on resume if device was reset (NULL means nop) | ||
| 592 | * | 597 | * |
| 593 | * raw_event and event should return 0 on no action performed, 1 when no | 598 | * raw_event and event should return 0 on no action performed, 1 when no |
| 594 | * further processing should be done and negative on error | 599 | * further processing should be done and negative on error |
| @@ -629,6 +634,11 @@ struct hid_driver { | |||
| 629 | int (*input_mapped)(struct hid_device *hdev, | 634 | int (*input_mapped)(struct hid_device *hdev, |
| 630 | struct hid_input *hidinput, struct hid_field *field, | 635 | struct hid_input *hidinput, struct hid_field *field, |
| 631 | struct hid_usage *usage, unsigned long **bit, int *max); | 636 | struct hid_usage *usage, unsigned long **bit, int *max); |
| 637 | #ifdef CONFIG_PM | ||
| 638 | int (*suspend)(struct hid_device *hdev, pm_message_t message); | ||
| 639 | int (*resume)(struct hid_device *hdev); | ||
| 640 | int (*reset_resume)(struct hid_device *hdev); | ||
| 641 | #endif | ||
| 632 | /* private: */ | 642 | /* private: */ |
| 633 | struct device_driver driver; | 643 | struct device_driver driver; |
| 634 | }; | 644 | }; |
