diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-07-24 16:30:14 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-07-24 16:30:14 -0400 |
commit | e8ff13b0bf88b5e696323a1eec877783d965b3c6 (patch) | |
tree | aa55093da5ee435f0d2fa8ffede8973f426dbd67 | |
parent | 0cd5ff591ab6473355d5a6a47f7694def28e451d (diff) | |
parent | c062c4d1de57789bf15f7641a24c429eeb8a1c6a (diff) |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/hid
Pull HID updates from Jiri Kosina:
"The list of changes worth pointing out explicitly:
- We are getting 'UHID', which is a new framework for implementing HID
transport drivers in userspace (this is different from HIDRAW, which
is transport-independent and provides report parsing facilities;
uhid is for the other (transport) part of the pipeline).
It's needed for (and currently being used by) Bluetooth-LowEnergy,
as its specification mandates things we don't want in the kernel.
Written by David Herrmann.
- there have been quite a few bugs in runtime suspend/resume paths
(probably never reported to actually happen in the wild, but still).
Alan Stern fixed those.
- a few other driver updates and fixes and random new device support."
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/hid: (45 commits)
HID: add ASUS AIO keyboard model AK1D
HID: add support for Cypress barcode scanner 04B4:ED81
HID: Allow drivers to be their own listener
HID: usbhid: fix error paths in suspend
HID: usbhid: check for suspend or reset before restarting
HID: usbhid: replace HID_REPORTED_IDLE with HID_SUSPENDED
HID: usbhid: inline some simple routines
HID: usbhid: fix autosuspend calls
HID: usbhid: fix use-after-free bug
HID: hid-core: optimize in case of hidraw
HID: hidraw: fix list->buffer memleak
HID: uhid: Fix sending events with invalid data
HID: roccat: added sensor sysfs attribute for Savu
HID: Add driver for Holtek based keyboards with broken HID
HID: Add suport for the brightness control keys on HP keyboards
HID: magicmouse: Implement Multi-touch Protocol B (MT-B)
HID: magicmouse: Removing report_touches switch
HID: roccat: rename roccat_common functions to roccat_common2
HID: roccat: fix wrong hid_err usage on struct usb_device
HID: roccat: move functionality to roccat-common
...
40 files changed, 2983 insertions, 554 deletions
diff --git a/Documentation/ABI/testing/sysfs-driver-hid-lenovo-tpkbd b/Documentation/ABI/testing/sysfs-driver-hid-lenovo-tpkbd new file mode 100644 index 000000000000..57b92cbdceae --- /dev/null +++ b/Documentation/ABI/testing/sysfs-driver-hid-lenovo-tpkbd | |||
@@ -0,0 +1,38 @@ | |||
1 | What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/press_to_select | ||
2 | Date: July 2011 | ||
3 | Contact: linux-input@vger.kernel.org | ||
4 | Description: This controls if mouse clicks should be generated if the trackpoint is quickly pressed. How fast this press has to be | ||
5 | is being controlled by press_speed. | ||
6 | Values are 0 or 1. | ||
7 | |||
8 | What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/dragging | ||
9 | Date: July 2011 | ||
10 | Contact: linux-input@vger.kernel.org | ||
11 | Description: If this setting is enabled, it is possible to do dragging by pressing the trackpoint. This requires press_to_select to be enabled. | ||
12 | Values are 0 or 1. | ||
13 | |||
14 | What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/release_to_select | ||
15 | Date: July 2011 | ||
16 | Contact: linux-input@vger.kernel.org | ||
17 | Description: For details regarding this setting please refer to http://www.pc.ibm.com/ww/healthycomputing/trkpntb.html | ||
18 | Values are 0 or 1. | ||
19 | |||
20 | What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/select_right | ||
21 | Date: July 2011 | ||
22 | Contact: linux-input@vger.kernel.org | ||
23 | Description: This setting controls if the mouse click events generated by pressing the trackpoint (if press_to_select is enabled) generate | ||
24 | a left or right mouse button click. | ||
25 | Values are 0 or 1. | ||
26 | |||
27 | What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/sensitivity | ||
28 | Date: July 2011 | ||
29 | Contact: linux-input@vger.kernel.org | ||
30 | Description: This file contains the trackpoint sensitivity. | ||
31 | Values are decimal integers from 1 (lowest sensitivity) to 255 (highest sensitivity). | ||
32 | |||
33 | What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/press_speed | ||
34 | Date: July 2011 | ||
35 | Contact: linux-input@vger.kernel.org | ||
36 | Description: This setting controls how fast the trackpoint needs to be pressed to generate a mouse click if press_to_select is enabled. | ||
37 | Values are decimal integers from 1 (slowest) to 255 (fastest). | ||
38 | |||
diff --git a/Documentation/ABI/testing/sysfs-driver-hid-roccat-savu b/Documentation/ABI/testing/sysfs-driver-hid-roccat-savu new file mode 100644 index 000000000000..b42922cf6b1f --- /dev/null +++ b/Documentation/ABI/testing/sysfs-driver-hid-roccat-savu | |||
@@ -0,0 +1,77 @@ | |||
1 | What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/savu/roccatsavu<minor>/buttons | ||
2 | Date: Mai 2012 | ||
3 | Contact: Stefan Achatz <erazor_de@users.sourceforge.net> | ||
4 | Description: The mouse can store 5 profiles which can be switched by the | ||
5 | press of a button. A profile is split into general settings and | ||
6 | button settings. buttons holds informations about button layout. | ||
7 | When written, this file lets one write the respective profile | ||
8 | buttons to the mouse. The data has to be 47 bytes long. | ||
9 | The mouse will reject invalid data. | ||
10 | Which profile to write is determined by the profile number | ||
11 | contained in the data. | ||
12 | Before reading this file, control has to be written to select | ||
13 | which profile to read. | ||
14 | Users: http://roccat.sourceforge.net | ||
15 | |||
16 | What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/savu/roccatsavu<minor>/control | ||
17 | Date: Mai 2012 | ||
18 | Contact: Stefan Achatz <erazor_de@users.sourceforge.net> | ||
19 | Description: When written, this file lets one select which data from which | ||
20 | profile will be read next. The data has to be 3 bytes long. | ||
21 | This file is writeonly. | ||
22 | Users: http://roccat.sourceforge.net | ||
23 | |||
24 | What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/savu/roccatsavu<minor>/general | ||
25 | Date: Mai 2012 | ||
26 | Contact: Stefan Achatz <erazor_de@users.sourceforge.net> | ||
27 | Description: The mouse can store 5 profiles which can be switched by the | ||
28 | press of a button. A profile is split into general settings and | ||
29 | button settings. profile holds informations like resolution, sensitivity | ||
30 | and light effects. | ||
31 | When written, this file lets one write the respective profile | ||
32 | settings back to the mouse. The data has to be 43 bytes long. | ||
33 | The mouse will reject invalid data. | ||
34 | Which profile to write is determined by the profile number | ||
35 | contained in the data. | ||
36 | This file is writeonly. | ||
37 | Users: http://roccat.sourceforge.net | ||
38 | |||
39 | What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/savu/roccatsavu<minor>/info | ||
40 | Date: Mai 2012 | ||
41 | Contact: Stefan Achatz <erazor_de@users.sourceforge.net> | ||
42 | Description: When read, this file returns general data like firmware version. | ||
43 | The data is 8 bytes long. | ||
44 | This file is readonly. | ||
45 | Users: http://roccat.sourceforge.net | ||
46 | |||
47 | What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/savu/roccatsavu<minor>/macro | ||
48 | Date: Mai 2012 | ||
49 | Contact: Stefan Achatz <erazor_de@users.sourceforge.net> | ||
50 | Description: When written, this file lets one store macros with max 500 | ||
51 | keystrokes for a specific button for a specific profile. | ||
52 | Button and profile numbers are included in written data. | ||
53 | The data has to be 2083 bytes long. | ||
54 | Before reading this file, control has to be written to select | ||
55 | which profile and key to read. | ||
56 | Users: http://roccat.sourceforge.net | ||
57 | |||
58 | What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/savu/roccatsavu<minor>/profile | ||
59 | Date: Mai 2012 | ||
60 | Contact: Stefan Achatz <erazor_de@users.sourceforge.net> | ||
61 | Description: The mouse can store 5 profiles which can be switched by the | ||
62 | press of a button. profile holds number of actual profile. | ||
63 | This value is persistent, so its value determines the profile | ||
64 | that's active when the mouse is powered on next time. | ||
65 | When written, the mouse activates the set profile immediately. | ||
66 | The data has to be 3 bytes long. | ||
67 | The mouse will reject invalid data. | ||
68 | Users: http://roccat.sourceforge.net | ||
69 | |||
70 | What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/savu/roccatsavu<minor>/sensor | ||
71 | Date: July 2012 | ||
72 | Contact: Stefan Achatz <erazor_de@users.sourceforge.net> | ||
73 | Description: The mouse has a Avago ADNS-3090 sensor. | ||
74 | This file allows reading and writing of the mouse sensors registers. | ||
75 | The data has to be 4 bytes long. | ||
76 | Users: http://roccat.sourceforge.net | ||
77 | |||
diff --git a/Documentation/hid/uhid.txt b/Documentation/hid/uhid.txt new file mode 100644 index 000000000000..4627c4241ece --- /dev/null +++ b/Documentation/hid/uhid.txt | |||
@@ -0,0 +1,169 @@ | |||
1 | UHID - User-space I/O driver support for HID subsystem | ||
2 | ======================================================== | ||
3 | |||
4 | The HID subsystem needs two kinds of drivers. In this document we call them: | ||
5 | |||
6 | 1. The "HID I/O Driver" is the driver that performs raw data I/O to the | ||
7 | low-level device. Internally, they register an hid_ll_driver structure with | ||
8 | the HID core. They perform device setup, read raw data from the device and | ||
9 | push it into the HID subsystem and they provide a callback so the HID | ||
10 | subsystem can send data to the device. | ||
11 | |||
12 | 2. The "HID Device Driver" is the driver that parses HID reports and reacts on | ||
13 | them. There are generic drivers like "generic-usb" and "generic-bluetooth" | ||
14 | which adhere to the HID specification and provide the standardizes features. | ||
15 | But there may be special drivers and quirks for each non-standard device out | ||
16 | there. Internally, they use the hid_driver structure. | ||
17 | |||
18 | Historically, the USB stack was the first subsystem to provide an HID I/O | ||
19 | Driver. However, other standards like Bluetooth have adopted the HID specs and | ||
20 | may provide HID I/O Drivers, too. The UHID driver allows to implement HID I/O | ||
21 | Drivers in user-space and feed the data into the kernel HID-subsystem. | ||
22 | |||
23 | This allows user-space to operate on the same level as USB-HID, Bluetooth-HID | ||
24 | and similar. It does not provide a way to write HID Device Drivers, though. Use | ||
25 | hidraw for this purpose. | ||
26 | |||
27 | There is an example user-space application in ./samples/uhid/uhid-example.c | ||
28 | |||
29 | The UHID API | ||
30 | ------------ | ||
31 | |||
32 | UHID is accessed through a character misc-device. The minor-number is allocated | ||
33 | dynamically so you need to rely on udev (or similar) to create the device node. | ||
34 | This is /dev/uhid by default. | ||
35 | |||
36 | If a new device is detected by your HID I/O Driver and you want to register this | ||
37 | device with the HID subsystem, then you need to open /dev/uhid once for each | ||
38 | device you want to register. All further communication is done by read()'ing or | ||
39 | write()'ing "struct uhid_event" objects. Non-blocking operations are supported | ||
40 | by setting O_NONBLOCK. | ||
41 | |||
42 | struct uhid_event { | ||
43 | __u32 type; | ||
44 | union { | ||
45 | struct uhid_create_req create; | ||
46 | struct uhid_data_req data; | ||
47 | ... | ||
48 | } u; | ||
49 | }; | ||
50 | |||
51 | The "type" field contains the ID of the event. Depending on the ID different | ||
52 | payloads are sent. You must not split a single event across multiple read()'s or | ||
53 | multiple write()'s. A single event must always be sent as a whole. Furthermore, | ||
54 | only a single event can be sent per read() or write(). Pending data is ignored. | ||
55 | If you want to handle multiple events in a single syscall, then use vectored | ||
56 | I/O with readv()/writev(). | ||
57 | |||
58 | The first thing you should do is sending an UHID_CREATE event. This will | ||
59 | register the device. UHID will respond with an UHID_START event. You can now | ||
60 | start sending data to and reading data from UHID. However, unless UHID sends the | ||
61 | UHID_OPEN event, the internally attached HID Device Driver has no user attached. | ||
62 | That is, you might put your device asleep unless you receive the UHID_OPEN | ||
63 | event. If you receive the UHID_OPEN event, you should start I/O. If the last | ||
64 | user closes the HID device, you will receive an UHID_CLOSE event. This may be | ||
65 | followed by an UHID_OPEN event again and so on. There is no need to perform | ||
66 | reference-counting in user-space. That is, you will never receive multiple | ||
67 | UHID_OPEN events without an UHID_CLOSE event. The HID subsystem performs | ||
68 | ref-counting for you. | ||
69 | You may decide to ignore UHID_OPEN/UHID_CLOSE, though. I/O is allowed even | ||
70 | though the device may have no users. | ||
71 | |||
72 | If you want to send data to the HID subsystem, you send an HID_INPUT event with | ||
73 | your raw data payload. If the kernel wants to send data to the device, you will | ||
74 | read an UHID_OUTPUT or UHID_OUTPUT_EV event. | ||
75 | |||
76 | If your device disconnects, you should send an UHID_DESTROY event. This will | ||
77 | unregister the device. You can now send UHID_CREATE again to register a new | ||
78 | device. | ||
79 | If you close() the fd, the device is automatically unregistered and destroyed | ||
80 | internally. | ||
81 | |||
82 | write() | ||
83 | ------- | ||
84 | write() allows you to modify the state of the device and feed input data into | ||
85 | the kernel. The following types are supported: UHID_CREATE, UHID_DESTROY and | ||
86 | UHID_INPUT. The kernel will parse the event immediately and if the event ID is | ||
87 | not supported, it will return -EOPNOTSUPP. If the payload is invalid, then | ||
88 | -EINVAL is returned, otherwise, the amount of data that was read is returned and | ||
89 | the request was handled successfully. | ||
90 | |||
91 | UHID_CREATE: | ||
92 | This creates the internal HID device. No I/O is possible until you send this | ||
93 | event to the kernel. The payload is of type struct uhid_create_req and | ||
94 | contains information about your device. You can start I/O now. | ||
95 | |||
96 | UHID_DESTROY: | ||
97 | This destroys the internal HID device. No further I/O will be accepted. There | ||
98 | may still be pending messages that you can receive with read() but no further | ||
99 | UHID_INPUT events can be sent to the kernel. | ||
100 | You can create a new device by sending UHID_CREATE again. There is no need to | ||
101 | reopen the character device. | ||
102 | |||
103 | UHID_INPUT: | ||
104 | You must send UHID_CREATE before sending input to the kernel! This event | ||
105 | contains a data-payload. This is the raw data that you read from your device. | ||
106 | The kernel will parse the HID reports and react on it. | ||
107 | |||
108 | UHID_FEATURE_ANSWER: | ||
109 | If you receive a UHID_FEATURE request you must answer with this request. You | ||
110 | must copy the "id" field from the request into the answer. Set the "err" field | ||
111 | to 0 if no error occured or to EIO if an I/O error occurred. | ||
112 | If "err" is 0 then you should fill the buffer of the answer with the results | ||
113 | of the feature request and set "size" correspondingly. | ||
114 | |||
115 | read() | ||
116 | ------ | ||
117 | read() will return a queued ouput report. These output reports can be of type | ||
118 | UHID_START, UHID_STOP, UHID_OPEN, UHID_CLOSE, UHID_OUTPUT or UHID_OUTPUT_EV. No | ||
119 | reaction is required to any of them but you should handle them according to your | ||
120 | needs. Only UHID_OUTPUT and UHID_OUTPUT_EV have payloads. | ||
121 | |||
122 | UHID_START: | ||
123 | This is sent when the HID device is started. Consider this as an answer to | ||
124 | UHID_CREATE. This is always the first event that is sent. | ||
125 | |||
126 | UHID_STOP: | ||
127 | This is sent when the HID device is stopped. Consider this as an answer to | ||
128 | UHID_DESTROY. | ||
129 | If the kernel HID device driver closes the device manually (that is, you | ||
130 | didn't send UHID_DESTROY) then you should consider this device closed and send | ||
131 | an UHID_DESTROY event. You may want to reregister your device, though. This is | ||
132 | always the last message that is sent to you unless you reopen the device with | ||
133 | UHID_CREATE. | ||
134 | |||
135 | UHID_OPEN: | ||
136 | This is sent when the HID device is opened. That is, the data that the HID | ||
137 | device provides is read by some other process. You may ignore this event but | ||
138 | it is useful for power-management. As long as you haven't received this event | ||
139 | there is actually no other process that reads your data so there is no need to | ||
140 | send UHID_INPUT events to the kernel. | ||
141 | |||
142 | UHID_CLOSE: | ||
143 | This is sent when there are no more processes which read the HID data. It is | ||
144 | the counterpart of UHID_OPEN and you may as well ignore this event. | ||
145 | |||
146 | UHID_OUTPUT: | ||
147 | This is sent if the HID device driver wants to send raw data to the I/O | ||
148 | device. You should read the payload and forward it to the device. The payload | ||
149 | is of type "struct uhid_data_req". | ||
150 | This may be received even though you haven't received UHID_OPEN, yet. | ||
151 | |||
152 | UHID_OUTPUT_EV: | ||
153 | Same as UHID_OUTPUT but this contains a "struct input_event" as payload. This | ||
154 | is called for force-feedback, LED or similar events which are received through | ||
155 | an input device by the HID subsystem. You should convert this into raw reports | ||
156 | and send them to your device similar to events of type UHID_OUTPUT. | ||
157 | |||
158 | UHID_FEATURE: | ||
159 | This event is sent if the kernel driver wants to perform a feature request as | ||
160 | described in the HID specs. The report-type and report-number are available in | ||
161 | the payload. | ||
162 | The kernel serializes feature requests so there will never be two in parallel. | ||
163 | However, if you fail to respond with a UHID_FEATURE_ANSWER in a time-span of 5 | ||
164 | seconds, then the requests will be dropped and a new one might be sent. | ||
165 | Therefore, the payload also contains an "id" field that identifies every | ||
166 | request. | ||
167 | |||
168 | Document by: | ||
169 | David Herrmann <dh.herrmann@googlemail.com> | ||
diff --git a/MAINTAINERS b/MAINTAINERS index cda045337a9d..04ea1f23756f 100644 --- a/MAINTAINERS +++ b/MAINTAINERS | |||
@@ -6965,6 +6965,13 @@ S: Maintained | |||
6965 | F: Documentation/filesystems/ufs.txt | 6965 | F: Documentation/filesystems/ufs.txt |
6966 | F: fs/ufs/ | 6966 | F: fs/ufs/ |
6967 | 6967 | ||
6968 | UHID USERSPACE HID IO DRIVER: | ||
6969 | M: David Herrmann <dh.herrmann@googlemail.com> | ||
6970 | L: linux-input@vger.kernel.org | ||
6971 | S: Maintained | ||
6972 | F: drivers/hid/uhid.c | ||
6973 | F: include/linux/uhid.h | ||
6974 | |||
6968 | ULTRA-WIDEBAND (UWB) SUBSYSTEM: | 6975 | ULTRA-WIDEBAND (UWB) SUBSYSTEM: |
6969 | L: linux-usb@vger.kernel.org | 6976 | L: linux-usb@vger.kernel.org |
6970 | S: Orphan | 6977 | S: Orphan |
diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index 3fda8c87f02c..fbf49503508d 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig | |||
@@ -53,6 +53,27 @@ config HIDRAW | |||
53 | 53 | ||
54 | If unsure, say Y. | 54 | If unsure, say Y. |
55 | 55 | ||
56 | config UHID | ||
57 | tristate "User-space I/O driver support for HID subsystem" | ||
58 | depends on HID | ||
59 | default n | ||
60 | ---help--- | ||
61 | Say Y here if you want to provide HID I/O Drivers from user-space. | ||
62 | This allows to write I/O drivers in user-space and feed the data from | ||
63 | the device into the kernel. The kernel parses the HID reports, loads the | ||
64 | corresponding HID Device Driver or provides input devices on top of your | ||
65 | user-space device. | ||
66 | |||
67 | This driver cannot be used to parse HID-reports in user-space and write | ||
68 | special HID-drivers. You should use hidraw for that. | ||
69 | Instead, this driver allows to write the transport-layer driver in | ||
70 | user-space like USB-HID and Bluetooth-HID do in kernel-space. | ||
71 | |||
72 | If unsure, say N. | ||
73 | |||
74 | To compile this driver as a module, choose M here: the | ||
75 | module will be called uhid. | ||
76 | |||
56 | config HID_GENERIC | 77 | config HID_GENERIC |
57 | tristate "Generic HID driver" | 78 | tristate "Generic HID driver" |
58 | depends on HID | 79 | depends on HID |
@@ -193,10 +214,12 @@ config HID_EZKEY | |||
193 | Support for Ezkey BTC 8193 keyboard. | 214 | Support for Ezkey BTC 8193 keyboard. |
194 | 215 | ||
195 | config HID_HOLTEK | 216 | config HID_HOLTEK |
196 | tristate "Holtek On Line Grip based game controller support" | 217 | tristate "Holtek HID devices" |
197 | depends on USB_HID | 218 | depends on USB_HID |
198 | ---help--- | 219 | ---help--- |
199 | Say Y here if you have a Holtek On Line Grip based game controller. | 220 | Support for Holtek based devices: |
221 | - Holtek On Line Grip based game controller | ||
222 | - Trust GXT 18 Gaming Keyboard | ||
200 | 223 | ||
201 | config HOLTEK_FF | 224 | config HOLTEK_FF |
202 | bool "Holtek On Line Grip force feedback support" | 225 | bool "Holtek On Line Grip force feedback support" |
@@ -261,6 +284,19 @@ config HID_LCPOWER | |||
261 | ---help--- | 284 | ---help--- |
262 | Support for LC-Power RC1000MCE RF remote control. | 285 | Support for LC-Power RC1000MCE RF remote control. |
263 | 286 | ||
287 | config HID_LENOVO_TPKBD | ||
288 | tristate "Lenovo ThinkPad USB Keyboard with TrackPoint" | ||
289 | depends on USB_HID | ||
290 | select NEW_LEDS | ||
291 | select LEDS_CLASS | ||
292 | ---help--- | ||
293 | Support for the Lenovo ThinkPad USB Keyboard with TrackPoint. | ||
294 | |||
295 | Say Y here if you have a Lenovo ThinkPad USB Keyboard with TrackPoint | ||
296 | and would like to use device-specific features like changing the | ||
297 | sensitivity of the trackpoint, using the microphone mute button or | ||
298 | controlling the mute and microphone mute LEDs. | ||
299 | |||
264 | config HID_LOGITECH | 300 | config HID_LOGITECH |
265 | tristate "Logitech devices" if EXPERT | 301 | tristate "Logitech devices" if EXPERT |
266 | depends on USB_HID | 302 | depends on USB_HID |
diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile index ca6cc9f0485c..f975485f88b2 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile | |||
@@ -8,6 +8,7 @@ ifdef CONFIG_DEBUG_FS | |||
8 | endif | 8 | endif |
9 | 9 | ||
10 | obj-$(CONFIG_HID) += hid.o | 10 | obj-$(CONFIG_HID) += hid.o |
11 | obj-$(CONFIG_UHID) += uhid.o | ||
11 | 12 | ||
12 | obj-$(CONFIG_HID_GENERIC) += hid-generic.o | 13 | obj-$(CONFIG_HID_GENERIC) += hid-generic.o |
13 | 14 | ||
@@ -48,12 +49,14 @@ obj-$(CONFIG_HID_EMS_FF) += hid-emsff.o | |||
48 | obj-$(CONFIG_HID_ELECOM) += hid-elecom.o | 49 | obj-$(CONFIG_HID_ELECOM) += hid-elecom.o |
49 | obj-$(CONFIG_HID_EZKEY) += hid-ezkey.o | 50 | obj-$(CONFIG_HID_EZKEY) += hid-ezkey.o |
50 | obj-$(CONFIG_HID_GYRATION) += hid-gyration.o | 51 | obj-$(CONFIG_HID_GYRATION) += hid-gyration.o |
52 | obj-$(CONFIG_HID_HOLTEK) += hid-holtek-kbd.o | ||
51 | obj-$(CONFIG_HID_HOLTEK) += hid-holtekff.o | 53 | obj-$(CONFIG_HID_HOLTEK) += hid-holtekff.o |
52 | obj-$(CONFIG_HID_HYPERV_MOUSE) += hid-hyperv.o | 54 | obj-$(CONFIG_HID_HYPERV_MOUSE) += hid-hyperv.o |
53 | obj-$(CONFIG_HID_KENSINGTON) += hid-kensington.o | 55 | obj-$(CONFIG_HID_KENSINGTON) += hid-kensington.o |
54 | obj-$(CONFIG_HID_KEYTOUCH) += hid-keytouch.o | 56 | obj-$(CONFIG_HID_KEYTOUCH) += hid-keytouch.o |
55 | obj-$(CONFIG_HID_KYE) += hid-kye.o | 57 | obj-$(CONFIG_HID_KYE) += hid-kye.o |
56 | obj-$(CONFIG_HID_LCPOWER) += hid-lcpower.o | 58 | obj-$(CONFIG_HID_LCPOWER) += hid-lcpower.o |
59 | obj-$(CONFIG_HID_LENOVO_TPKBD) += hid-lenovo-tpkbd.o | ||
57 | obj-$(CONFIG_HID_LOGITECH) += hid-logitech.o | 60 | obj-$(CONFIG_HID_LOGITECH) += hid-logitech.o |
58 | obj-$(CONFIG_HID_LOGITECH_DJ) += hid-logitech-dj.o | 61 | obj-$(CONFIG_HID_LOGITECH_DJ) += hid-logitech-dj.o |
59 | obj-$(CONFIG_HID_MAGICMOUSE) += hid-magicmouse.o | 62 | obj-$(CONFIG_HID_MAGICMOUSE) += hid-magicmouse.o |
@@ -69,7 +72,8 @@ obj-$(CONFIG_HID_PICOLCD) += hid-picolcd.o | |||
69 | obj-$(CONFIG_HID_PRIMAX) += hid-primax.o | 72 | obj-$(CONFIG_HID_PRIMAX) += hid-primax.o |
70 | obj-$(CONFIG_HID_ROCCAT) += hid-roccat.o hid-roccat-common.o \ | 73 | obj-$(CONFIG_HID_ROCCAT) += hid-roccat.o hid-roccat-common.o \ |
71 | hid-roccat-arvo.o hid-roccat-isku.o hid-roccat-kone.o \ | 74 | hid-roccat-arvo.o hid-roccat-isku.o hid-roccat-kone.o \ |
72 | hid-roccat-koneplus.o hid-roccat-kovaplus.o hid-roccat-pyra.o | 75 | hid-roccat-koneplus.o hid-roccat-kovaplus.o hid-roccat-pyra.o \ |
76 | hid-roccat-savu.o | ||
73 | obj-$(CONFIG_HID_SAITEK) += hid-saitek.o | 77 | obj-$(CONFIG_HID_SAITEK) += hid-saitek.o |
74 | obj-$(CONFIG_HID_SAMSUNG) += hid-samsung.o | 78 | obj-$(CONFIG_HID_SAMSUNG) += hid-samsung.o |
75 | obj-$(CONFIG_HID_SMARTJOYPLUS) += hid-sjoy.o | 79 | obj-$(CONFIG_HID_SMARTJOYPLUS) += hid-sjoy.o |
diff --git a/drivers/hid/hid-chicony.c b/drivers/hid/hid-chicony.c index b99af346fdff..a2abb8e15727 100644 --- a/drivers/hid/hid-chicony.c +++ b/drivers/hid/hid-chicony.c | |||
@@ -60,6 +60,7 @@ static int ch_input_mapping(struct hid_device *hdev, struct hid_input *hi, | |||
60 | static const struct hid_device_id ch_devices[] = { | 60 | static const struct hid_device_id ch_devices[] = { |
61 | { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_TACTICAL_PAD) }, | 61 | { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_TACTICAL_PAD) }, |
62 | { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_WIRELESS2) }, | 62 | { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_WIRELESS2) }, |
63 | { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_AK1D) }, | ||
63 | { } | 64 | { } |
64 | }; | 65 | }; |
65 | MODULE_DEVICE_TABLE(hid, ch_devices); | 66 | MODULE_DEVICE_TABLE(hid, ch_devices); |
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 4c87276c8ddb..500844f04f93 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c | |||
@@ -1194,8 +1194,10 @@ int hid_report_raw_event(struct hid_device *hid, int type, u8 *data, int size, | |||
1194 | goto out; | 1194 | goto out; |
1195 | } | 1195 | } |
1196 | 1196 | ||
1197 | for (a = 0; a < report->maxfield; a++) | 1197 | if (hid->claimed != HID_CLAIMED_HIDRAW) { |
1198 | hid_input_field(hid, report->field[a], cdata, interrupt); | 1198 | for (a = 0; a < report->maxfield; a++) |
1199 | hid_input_field(hid, report->field[a], cdata, interrupt); | ||
1200 | } | ||
1199 | 1201 | ||
1200 | if (hid->claimed & HID_CLAIMED_INPUT) | 1202 | if (hid->claimed & HID_CLAIMED_INPUT) |
1201 | hidinput_report_event(hid, report); | 1203 | hidinput_report_event(hid, report); |
@@ -1243,6 +1245,10 @@ int hid_input_report(struct hid_device *hid, int type, u8 *data, int size, int i | |||
1243 | goto unlock; | 1245 | goto unlock; |
1244 | } | 1246 | } |
1245 | 1247 | ||
1248 | /* Avoid unnecessary overhead if debugfs is disabled */ | ||
1249 | if (list_empty(&hid->debug_list)) | ||
1250 | goto nomem; | ||
1251 | |||
1246 | buf = kmalloc(sizeof(char) * HID_DEBUG_BUFSIZE, GFP_ATOMIC); | 1252 | buf = kmalloc(sizeof(char) * HID_DEBUG_BUFSIZE, GFP_ATOMIC); |
1247 | 1253 | ||
1248 | if (!buf) | 1254 | if (!buf) |
@@ -1373,8 +1379,10 @@ int hid_connect(struct hid_device *hdev, unsigned int connect_mask) | |||
1373 | if ((connect_mask & HID_CONNECT_HIDRAW) && !hidraw_connect(hdev)) | 1379 | if ((connect_mask & HID_CONNECT_HIDRAW) && !hidraw_connect(hdev)) |
1374 | hdev->claimed |= HID_CLAIMED_HIDRAW; | 1380 | hdev->claimed |= HID_CLAIMED_HIDRAW; |
1375 | 1381 | ||
1376 | if (!hdev->claimed) { | 1382 | /* Drivers with the ->raw_event callback set are not required to connect |
1377 | hid_err(hdev, "claimed by neither input, hiddev nor hidraw\n"); | 1383 | * to any other listener. */ |
1384 | if (!hdev->claimed && !hdev->driver->raw_event) { | ||
1385 | hid_err(hdev, "device has no listeners, quitting\n"); | ||
1378 | return -ENODEV; | 1386 | return -ENODEV; |
1379 | } | 1387 | } |
1380 | 1388 | ||
@@ -1521,10 +1529,12 @@ static const struct hid_device_id hid_have_special_driver[] = { | |||
1521 | { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_TACTICAL_PAD) }, | 1529 | { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_TACTICAL_PAD) }, |
1522 | { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_WIRELESS) }, | 1530 | { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_WIRELESS) }, |
1523 | { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_WIRELESS2) }, | 1531 | { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_WIRELESS2) }, |
1532 | { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_AK1D) }, | ||
1524 | { HID_USB_DEVICE(USB_VENDOR_ID_CREATIVELABS, USB_DEVICE_ID_PRODIKEYS_PCMIDI) }, | 1533 | { HID_USB_DEVICE(USB_VENDOR_ID_CREATIVELABS, USB_DEVICE_ID_PRODIKEYS_PCMIDI) }, |
1525 | { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_1) }, | 1534 | { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_1) }, |
1526 | { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_2) }, | 1535 | { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_2) }, |
1527 | { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_3) }, | 1536 | { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_3) }, |
1537 | { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_4) }, | ||
1528 | { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_MOUSE) }, | 1538 | { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_MOUSE) }, |
1529 | { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, 0x0006) }, | 1539 | { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, 0x0006) }, |
1530 | { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, 0x0011) }, | 1540 | { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, 0x0011) }, |
@@ -1539,6 +1549,7 @@ static const struct hid_device_id hid_have_special_driver[] = { | |||
1539 | { HID_USB_DEVICE(USB_VENDOR_ID_GYRATION, USB_DEVICE_ID_GYRATION_REMOTE_2) }, | 1549 | { HID_USB_DEVICE(USB_VENDOR_ID_GYRATION, USB_DEVICE_ID_GYRATION_REMOTE_2) }, |
1540 | { HID_USB_DEVICE(USB_VENDOR_ID_GYRATION, USB_DEVICE_ID_GYRATION_REMOTE_3) }, | 1550 | { HID_USB_DEVICE(USB_VENDOR_ID_GYRATION, USB_DEVICE_ID_GYRATION_REMOTE_3) }, |
1541 | { HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK, USB_DEVICE_ID_HOLTEK_ON_LINE_GRIP) }, | 1551 | { HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK, USB_DEVICE_ID_HOLTEK_ON_LINE_GRIP) }, |
1552 | { HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK_ALT, USB_DEVICE_ID_HOLTEK_ALT_KEYBOARD) }, | ||
1542 | { HID_USB_DEVICE(USB_VENDOR_ID_KENSINGTON, USB_DEVICE_ID_KS_SLIMBLADE) }, | 1553 | { HID_USB_DEVICE(USB_VENDOR_ID_KENSINGTON, USB_DEVICE_ID_KS_SLIMBLADE) }, |
1543 | { HID_USB_DEVICE(USB_VENDOR_ID_KEYTOUCH, USB_DEVICE_ID_KEYTOUCH_IEC) }, | 1554 | { HID_USB_DEVICE(USB_VENDOR_ID_KEYTOUCH, USB_DEVICE_ID_KEYTOUCH_IEC) }, |
1544 | { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_ERGO_525V) }, | 1555 | { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_ERGO_525V) }, |
@@ -1547,6 +1558,7 @@ static const struct hid_device_id hid_have_special_driver[] = { | |||
1547 | { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_EASYPEN_M610X) }, | 1558 | { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_EASYPEN_M610X) }, |
1548 | { HID_USB_DEVICE(USB_VENDOR_ID_LABTEC, USB_DEVICE_ID_LABTEC_WIRELESS_KEYBOARD) }, | 1559 | { HID_USB_DEVICE(USB_VENDOR_ID_LABTEC, USB_DEVICE_ID_LABTEC_WIRELESS_KEYBOARD) }, |
1549 | { HID_USB_DEVICE(USB_VENDOR_ID_LCPOWER, USB_DEVICE_ID_LCPOWER_LC1000 ) }, | 1560 | { HID_USB_DEVICE(USB_VENDOR_ID_LCPOWER, USB_DEVICE_ID_LCPOWER_LC1000 ) }, |
1561 | { HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_TPKBD) }, | ||
1550 | { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_MX3000_RECEIVER) }, | 1562 | { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_MX3000_RECEIVER) }, |
1551 | { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER) }, | 1563 | { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER) }, |
1552 | { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER_2) }, | 1564 | { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER_2) }, |
@@ -1620,6 +1632,7 @@ static const struct hid_device_id hid_have_special_driver[] = { | |||
1620 | { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KOVAPLUS) }, | 1632 | { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KOVAPLUS) }, |
1621 | { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_PYRA_WIRED) }, | 1633 | { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_PYRA_WIRED) }, |
1622 | { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_PYRA_WIRELESS) }, | 1634 | { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_PYRA_WIRELESS) }, |
1635 | { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_SAVU) }, | ||
1623 | { HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_PS1000) }, | 1636 | { HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_PS1000) }, |
1624 | { HID_USB_DEVICE(USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_IR_REMOTE) }, | 1637 | { HID_USB_DEVICE(USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_IR_REMOTE) }, |
1625 | { HID_USB_DEVICE(USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_WIRELESS_KBD_MOUSE) }, | 1638 | { HID_USB_DEVICE(USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_WIRELESS_KBD_MOUSE) }, |
diff --git a/drivers/hid/hid-cypress.c b/drivers/hid/hid-cypress.c index 2f0be4c66af7..9e43aaca9774 100644 --- a/drivers/hid/hid-cypress.c +++ b/drivers/hid/hid-cypress.c | |||
@@ -129,6 +129,8 @@ static const struct hid_device_id cp_devices[] = { | |||
129 | .driver_data = CP_RDESC_SWAPPED_MIN_MAX }, | 129 | .driver_data = CP_RDESC_SWAPPED_MIN_MAX }, |
130 | { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_3), | 130 | { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_3), |
131 | .driver_data = CP_RDESC_SWAPPED_MIN_MAX }, | 131 | .driver_data = CP_RDESC_SWAPPED_MIN_MAX }, |
132 | { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_4), | ||
133 | .driver_data = CP_RDESC_SWAPPED_MIN_MAX }, | ||
132 | { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_MOUSE), | 134 | { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_MOUSE), |
133 | .driver_data = CP_2WHEEL_MOUSE_HACK }, | 135 | .driver_data = CP_2WHEEL_MOUSE_HACK }, |
134 | { } | 136 | { } |
diff --git a/drivers/hid/hid-holtek-kbd.c b/drivers/hid/hid-holtek-kbd.c new file mode 100644 index 000000000000..e0a5d1739fc3 --- /dev/null +++ b/drivers/hid/hid-holtek-kbd.c | |||
@@ -0,0 +1,183 @@ | |||
1 | /* | ||
2 | * HID driver for Holtek keyboard | ||
3 | * Copyright (c) 2012 Tom Harwood | ||
4 | */ | ||
5 | |||
6 | /* | ||
7 | * This program is free software; you can redistribute it and/or modify it | ||
8 | * under the terms of the GNU General Public License as published by the Free | ||
9 | * Software Foundation; either version 2 of the License, or (at your option) | ||
10 | * any later version. | ||
11 | */ | ||
12 | |||
13 | #include <linux/device.h> | ||
14 | #include <linux/hid.h> | ||
15 | #include <linux/module.h> | ||
16 | #include <linux/usb.h> | ||
17 | |||
18 | #include "hid-ids.h" | ||
19 | #include "usbhid/usbhid.h" | ||
20 | |||
21 | /* Holtek based keyboards (USB ID 04d9:a055) have the following issues: | ||
22 | * - The report descriptor specifies an excessively large number of consumer | ||
23 | * usages (2^15), which is more than HID_MAX_USAGES. This prevents proper | ||
24 | * parsing of the report descriptor. | ||
25 | * - The report descriptor reports on caps/scroll/num lock key presses, but | ||
26 | * doesn't have an LED output usage block. | ||
27 | * | ||
28 | * The replacement descriptor below fixes the number of consumer usages, | ||
29 | * and provides an LED output usage block. LED output events are redirected | ||
30 | * to the boot interface. | ||
31 | */ | ||
32 | |||
33 | static __u8 holtek_kbd_rdesc_fixed[] = { | ||
34 | /* Original report descriptor, with reduced number of consumer usages */ | ||
35 | 0x05, 0x01, /* Usage Page (Desktop), */ | ||
36 | 0x09, 0x80, /* Usage (Sys Control), */ | ||
37 | 0xA1, 0x01, /* Collection (Application), */ | ||
38 | 0x85, 0x01, /* Report ID (1), */ | ||
39 | 0x19, 0x81, /* Usage Minimum (Sys Power Down), */ | ||
40 | 0x29, 0x83, /* Usage Maximum (Sys Wake Up), */ | ||
41 | 0x15, 0x00, /* Logical Minimum (0), */ | ||
42 | 0x25, 0x01, /* Logical Maximum (1), */ | ||
43 | 0x95, 0x03, /* Report Count (3), */ | ||
44 | 0x75, 0x01, /* Report Size (1), */ | ||
45 | 0x81, 0x02, /* Input (Variable), */ | ||
46 | 0x95, 0x01, /* Report Count (1), */ | ||
47 | 0x75, 0x05, /* Report Size (5), */ | ||
48 | 0x81, 0x01, /* Input (Constant), */ | ||
49 | 0xC0, /* End Collection, */ | ||
50 | 0x05, 0x0C, /* Usage Page (Consumer), */ | ||
51 | 0x09, 0x01, /* Usage (Consumer Control), */ | ||
52 | 0xA1, 0x01, /* Collection (Application), */ | ||
53 | 0x85, 0x02, /* Report ID (2), */ | ||
54 | 0x19, 0x00, /* Usage Minimum (00h), */ | ||
55 | 0x2A, 0xFF, 0x2F, /* Usage Maximum (0x2FFF), previously 0x7FFF */ | ||
56 | 0x15, 0x00, /* Logical Minimum (0), */ | ||
57 | 0x26, 0xFF, 0x2F, /* Logical Maximum (0x2FFF),previously 0x7FFF*/ | ||
58 | 0x95, 0x01, /* Report Count (1), */ | ||
59 | 0x75, 0x10, /* Report Size (16), */ | ||
60 | 0x81, 0x00, /* Input, */ | ||
61 | 0xC0, /* End Collection, */ | ||
62 | 0x05, 0x01, /* Usage Page (Desktop), */ | ||
63 | 0x09, 0x06, /* Usage (Keyboard), */ | ||
64 | 0xA1, 0x01, /* Collection (Application), */ | ||
65 | 0x85, 0x03, /* Report ID (3), */ | ||
66 | 0x95, 0x38, /* Report Count (56), */ | ||
67 | 0x75, 0x01, /* Report Size (1), */ | ||
68 | 0x15, 0x00, /* Logical Minimum (0), */ | ||
69 | 0x25, 0x01, /* Logical Maximum (1), */ | ||
70 | 0x05, 0x07, /* Usage Page (Keyboard), */ | ||
71 | 0x19, 0xE0, /* Usage Minimum (KB Leftcontrol), */ | ||
72 | 0x29, 0xE7, /* Usage Maximum (KB Right GUI), */ | ||
73 | 0x19, 0x00, /* Usage Minimum (None), */ | ||
74 | 0x29, 0x2F, /* Usage Maximum (KB Lboxbracket And Lbrace),*/ | ||
75 | 0x81, 0x02, /* Input (Variable), */ | ||
76 | 0xC0, /* End Collection, */ | ||
77 | 0x05, 0x01, /* Usage Page (Desktop), */ | ||
78 | 0x09, 0x06, /* Usage (Keyboard), */ | ||
79 | 0xA1, 0x01, /* Collection (Application), */ | ||
80 | 0x85, 0x04, /* Report ID (4), */ | ||
81 | 0x95, 0x38, /* Report Count (56), */ | ||
82 | 0x75, 0x01, /* Report Size (1), */ | ||
83 | 0x15, 0x00, /* Logical Minimum (0), */ | ||
84 | 0x25, 0x01, /* Logical Maximum (1), */ | ||
85 | 0x05, 0x07, /* Usage Page (Keyboard), */ | ||
86 | 0x19, 0x30, /* Usage Minimum (KB Rboxbracket And Rbrace),*/ | ||
87 | 0x29, 0x67, /* Usage Maximum (KP Equals), */ | ||
88 | 0x81, 0x02, /* Input (Variable), */ | ||
89 | 0xC0, /* End Collection */ | ||
90 | |||
91 | /* LED usage for the boot protocol interface */ | ||
92 | 0x05, 0x01, /* Usage Page (Desktop), */ | ||
93 | 0x09, 0x06, /* Usage (Keyboard), */ | ||
94 | 0xA1, 0x01, /* Collection (Application), */ | ||
95 | 0x05, 0x08, /* Usage Page (LED), */ | ||
96 | 0x19, 0x01, /* Usage Minimum (01h), */ | ||
97 | 0x29, 0x03, /* Usage Maximum (03h), */ | ||
98 | 0x15, 0x00, /* Logical Minimum (0), */ | ||
99 | 0x25, 0x01, /* Logical Maximum (1), */ | ||
100 | 0x75, 0x01, /* Report Size (1), */ | ||
101 | 0x95, 0x03, /* Report Count (3), */ | ||
102 | 0x91, 0x02, /* Output (Variable), */ | ||
103 | 0x95, 0x05, /* Report Count (5), */ | ||
104 | 0x91, 0x01, /* Output (Constant), */ | ||
105 | 0xC0, /* End Collection */ | ||
106 | }; | ||
107 | |||
108 | static __u8 *holtek_kbd_report_fixup(struct hid_device *hdev, __u8 *rdesc, | ||
109 | unsigned int *rsize) | ||
110 | { | ||
111 | struct usb_interface *intf = to_usb_interface(hdev->dev.parent); | ||
112 | |||
113 | if (intf->cur_altsetting->desc.bInterfaceNumber == 1) { | ||
114 | rdesc = holtek_kbd_rdesc_fixed; | ||
115 | *rsize = sizeof(holtek_kbd_rdesc_fixed); | ||
116 | } | ||
117 | return rdesc; | ||
118 | } | ||
119 | |||
120 | static int holtek_kbd_input_event(struct input_dev *dev, unsigned int type, | ||
121 | unsigned int code, | ||
122 | int value) | ||
123 | { | ||
124 | struct hid_device *hid = input_get_drvdata(dev); | ||
125 | struct usb_device *usb_dev = hid_to_usb_dev(hid); | ||
126 | |||
127 | /* Locate the boot interface, to receive the LED change events */ | ||
128 | struct usb_interface *boot_interface = usb_ifnum_to_if(usb_dev, 0); | ||
129 | |||
130 | struct hid_device *boot_hid = usb_get_intfdata(boot_interface); | ||
131 | struct hid_input *boot_hid_input = list_first_entry(&boot_hid->inputs, | ||
132 | struct hid_input, list); | ||
133 | |||
134 | return boot_hid_input->input->event(boot_hid_input->input, type, code, | ||
135 | value); | ||
136 | } | ||
137 | |||
138 | static int holtek_kbd_probe(struct hid_device *hdev, | ||
139 | const struct hid_device_id *id) | ||
140 | { | ||
141 | struct usb_interface *intf = to_usb_interface(hdev->dev.parent); | ||
142 | int ret = hid_parse(hdev); | ||
143 | |||
144 | if (!ret) | ||
145 | ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); | ||
146 | |||
147 | if (!ret && intf->cur_altsetting->desc.bInterfaceNumber == 1) { | ||
148 | struct hid_input *hidinput; | ||
149 | list_for_each_entry(hidinput, &hdev->inputs, list) { | ||
150 | hidinput->input->event = holtek_kbd_input_event; | ||
151 | } | ||
152 | } | ||
153 | |||
154 | return ret; | ||
155 | } | ||
156 | |||
157 | static const struct hid_device_id holtek_kbd_devices[] = { | ||
158 | { HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK_ALT, | ||
159 | USB_DEVICE_ID_HOLTEK_ALT_KEYBOARD) }, | ||
160 | { } | ||
161 | }; | ||
162 | MODULE_DEVICE_TABLE(hid, holtek_kbd_devices); | ||
163 | |||
164 | static struct hid_driver holtek_kbd_driver = { | ||
165 | .name = "holtek_kbd", | ||
166 | .id_table = holtek_kbd_devices, | ||
167 | .report_fixup = holtek_kbd_report_fixup, | ||
168 | .probe = holtek_kbd_probe | ||
169 | }; | ||
170 | |||
171 | static int __init holtek_kbd_init(void) | ||
172 | { | ||
173 | return hid_register_driver(&holtek_kbd_driver); | ||
174 | } | ||
175 | |||
176 | static void __exit holtek_kbd_exit(void) | ||
177 | { | ||
178 | hid_unregister_driver(&holtek_kbd_driver); | ||
179 | } | ||
180 | |||
181 | module_exit(holtek_kbd_exit); | ||
182 | module_init(holtek_kbd_init); | ||
183 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 32039235cfee..41c34f21bd00 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h | |||
@@ -208,6 +208,7 @@ | |||
208 | #define USB_DEVICE_ID_CHICONY_MULTI_TOUCH 0xb19d | 208 | #define USB_DEVICE_ID_CHICONY_MULTI_TOUCH 0xb19d |
209 | #define USB_DEVICE_ID_CHICONY_WIRELESS 0x0618 | 209 | #define USB_DEVICE_ID_CHICONY_WIRELESS 0x0618 |
210 | #define USB_DEVICE_ID_CHICONY_WIRELESS2 0x1123 | 210 | #define USB_DEVICE_ID_CHICONY_WIRELESS2 0x1123 |
211 | #define USB_DEVICE_ID_CHICONY_AK1D 0x1125 | ||
211 | 212 | ||
212 | #define USB_VENDOR_ID_CHUNGHWAT 0x2247 | 213 | #define USB_VENDOR_ID_CHUNGHWAT 0x2247 |
213 | #define USB_DEVICE_ID_CHUNGHWAT_MULTITOUCH 0x0001 | 214 | #define USB_DEVICE_ID_CHUNGHWAT_MULTITOUCH 0x0001 |
@@ -237,6 +238,7 @@ | |||
237 | #define USB_DEVICE_ID_CYPRESS_BARCODE_1 0xde61 | 238 | #define USB_DEVICE_ID_CYPRESS_BARCODE_1 0xde61 |
238 | #define USB_DEVICE_ID_CYPRESS_BARCODE_2 0xde64 | 239 | #define USB_DEVICE_ID_CYPRESS_BARCODE_2 0xde64 |
239 | #define USB_DEVICE_ID_CYPRESS_BARCODE_3 0xbca1 | 240 | #define USB_DEVICE_ID_CYPRESS_BARCODE_3 0xbca1 |
241 | #define USB_DEVICE_ID_CYPRESS_BARCODE_4 0xed81 | ||
240 | #define USB_DEVICE_ID_CYPRESS_TRUETOUCH 0xc001 | 242 | #define USB_DEVICE_ID_CYPRESS_TRUETOUCH 0xc001 |
241 | 243 | ||
242 | #define USB_VENDOR_ID_DEALEXTREAME 0x10c5 | 244 | #define USB_VENDOR_ID_DEALEXTREAME 0x10c5 |
@@ -410,6 +412,9 @@ | |||
410 | #define USB_VENDOR_ID_HOLTEK 0x1241 | 412 | #define USB_VENDOR_ID_HOLTEK 0x1241 |
411 | #define USB_DEVICE_ID_HOLTEK_ON_LINE_GRIP 0x5015 | 413 | #define USB_DEVICE_ID_HOLTEK_ON_LINE_GRIP 0x5015 |
412 | 414 | ||
415 | #define USB_VENDOR_ID_HOLTEK_ALT 0x04d9 | ||
416 | #define USB_DEVICE_ID_HOLTEK_ALT_KEYBOARD 0xa055 | ||
417 | |||
413 | #define USB_VENDOR_ID_IMATION 0x0718 | 418 | #define USB_VENDOR_ID_IMATION 0x0718 |
414 | #define USB_DEVICE_ID_DISC_STAKKA 0xd000 | 419 | #define USB_DEVICE_ID_DISC_STAKKA 0xd000 |
415 | 420 | ||
@@ -479,6 +484,9 @@ | |||
479 | #define USB_DEVICE_ID_LD_HYBRID 0x2090 | 484 | #define USB_DEVICE_ID_LD_HYBRID 0x2090 |
480 | #define USB_DEVICE_ID_LD_HEATCONTROL 0x20A0 | 485 | #define USB_DEVICE_ID_LD_HEATCONTROL 0x20A0 |
481 | 486 | ||
487 | #define USB_VENDOR_ID_LENOVO 0x17ef | ||
488 | #define USB_DEVICE_ID_LENOVO_TPKBD 0x6009 | ||
489 | |||
482 | #define USB_VENDOR_ID_LG 0x1fd2 | 490 | #define USB_VENDOR_ID_LG 0x1fd2 |
483 | #define USB_DEVICE_ID_LG_MULTITOUCH 0x0064 | 491 | #define USB_DEVICE_ID_LG_MULTITOUCH 0x0064 |
484 | 492 | ||
@@ -573,6 +581,9 @@ | |||
573 | #define USB_VENDOR_ID_NINTENDO 0x057e | 581 | #define USB_VENDOR_ID_NINTENDO 0x057e |
574 | #define USB_DEVICE_ID_NINTENDO_WIIMOTE 0x0306 | 582 | #define USB_DEVICE_ID_NINTENDO_WIIMOTE 0x0306 |
575 | 583 | ||
584 | #define USB_VENDOR_ID_NOVATEK 0x0603 | ||
585 | #define USB_DEVICE_ID_NOVATEK_PCT 0x0600 | ||
586 | |||
576 | #define USB_VENDOR_ID_NTRIG 0x1b96 | 587 | #define USB_VENDOR_ID_NTRIG 0x1b96 |
577 | #define USB_DEVICE_ID_NTRIG_TOUCH_SCREEN 0x0001 | 588 | #define USB_DEVICE_ID_NTRIG_TOUCH_SCREEN 0x0001 |
578 | #define USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_1 0x0003 | 589 | #define USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_1 0x0003 |
@@ -650,6 +661,7 @@ | |||
650 | #define USB_DEVICE_ID_ROCCAT_KOVAPLUS 0x2d50 | 661 | #define USB_DEVICE_ID_ROCCAT_KOVAPLUS 0x2d50 |
651 | #define USB_DEVICE_ID_ROCCAT_PYRA_WIRED 0x2c24 | 662 | #define USB_DEVICE_ID_ROCCAT_PYRA_WIRED 0x2c24 |
652 | #define USB_DEVICE_ID_ROCCAT_PYRA_WIRELESS 0x2cf6 | 663 | #define USB_DEVICE_ID_ROCCAT_PYRA_WIRELESS 0x2cf6 |
664 | #define USB_DEVICE_ID_ROCCAT_SAVU 0x2d5a | ||
653 | 665 | ||
654 | #define USB_VENDOR_ID_SAITEK 0x06a3 | 666 | #define USB_VENDOR_ID_SAITEK 0x06a3 |
655 | #define USB_DEVICE_ID_SAITEK_RUMBLEPAD 0xff17 | 667 | #define USB_DEVICE_ID_SAITEK_RUMBLEPAD 0xff17 |
diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c index 5301006f6c15..811bfad64609 100644 --- a/drivers/hid/hid-input.c +++ b/drivers/hid/hid-input.c | |||
@@ -837,6 +837,15 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel | |||
837 | } | 837 | } |
838 | break; | 838 | break; |
839 | 839 | ||
840 | case HID_UP_HPVENDOR2: | ||
841 | set_bit(EV_REP, input->evbit); | ||
842 | switch (usage->hid & HID_USAGE) { | ||
843 | case 0x003: map_key_clear(KEY_BRIGHTNESSDOWN); break; | ||
844 | case 0x004: map_key_clear(KEY_BRIGHTNESSUP); break; | ||
845 | default: goto ignore; | ||
846 | } | ||
847 | break; | ||
848 | |||
840 | case HID_UP_MSVENDOR: | 849 | case HID_UP_MSVENDOR: |
841 | goto ignore; | 850 | goto ignore; |
842 | 851 | ||
diff --git a/drivers/hid/hid-lenovo-tpkbd.c b/drivers/hid/hid-lenovo-tpkbd.c new file mode 100644 index 000000000000..77d2df04c97b --- /dev/null +++ b/drivers/hid/hid-lenovo-tpkbd.c | |||
@@ -0,0 +1,564 @@ | |||
1 | /* | ||
2 | * HID driver for Lenovo ThinkPad USB Keyboard with TrackPoint | ||
3 | * | ||
4 | * Copyright (c) 2012 Bernhard Seibold | ||
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/module.h> | ||
15 | #include <linux/sysfs.h> | ||
16 | #include <linux/device.h> | ||
17 | #include <linux/usb.h> | ||
18 | #include <linux/hid.h> | ||
19 | #include <linux/input.h> | ||
20 | #include <linux/leds.h> | ||
21 | #include "usbhid/usbhid.h" | ||
22 | |||
23 | #include "hid-ids.h" | ||
24 | |||
25 | /* This is only used for the trackpoint part of the driver, hence _tp */ | ||
26 | struct tpkbd_data_pointer { | ||
27 | int led_state; | ||
28 | struct led_classdev led_mute; | ||
29 | struct led_classdev led_micmute; | ||
30 | int press_to_select; | ||
31 | int dragging; | ||
32 | int release_to_select; | ||
33 | int select_right; | ||
34 | int sensitivity; | ||
35 | int press_speed; | ||
36 | }; | ||
37 | |||
38 | #define map_key_clear(c) hid_map_usage_clear(hi, usage, bit, max, EV_KEY, (c)) | ||
39 | |||
40 | static int tpkbd_input_mapping(struct hid_device *hdev, | ||
41 | struct hid_input *hi, struct hid_field *field, | ||
42 | struct hid_usage *usage, unsigned long **bit, int *max) | ||
43 | { | ||
44 | struct usbhid_device *uhdev; | ||
45 | |||
46 | uhdev = (struct usbhid_device *) hdev->driver_data; | ||
47 | if (uhdev->ifnum == 1 && usage->hid == (HID_UP_BUTTON | 0x0010)) { | ||
48 | map_key_clear(KEY_MICMUTE); | ||
49 | return 1; | ||
50 | } | ||
51 | return 0; | ||
52 | } | ||
53 | |||
54 | #undef map_key_clear | ||
55 | |||
56 | static int tpkbd_features_set(struct hid_device *hdev) | ||
57 | { | ||
58 | struct hid_report *report; | ||
59 | struct tpkbd_data_pointer *data_pointer; | ||
60 | |||
61 | data_pointer = (struct tpkbd_data_pointer *) hid_get_drvdata(hdev); | ||
62 | report = hdev->report_enum[HID_FEATURE_REPORT].report_id_hash[4]; | ||
63 | |||
64 | report->field[0]->value[0] = data_pointer->press_to_select ? 0x01 : 0x02; | ||
65 | report->field[0]->value[0] |= data_pointer->dragging ? 0x04 : 0x08; | ||
66 | report->field[0]->value[0] |= data_pointer->release_to_select ? 0x10 : 0x20; | ||
67 | report->field[0]->value[0] |= data_pointer->select_right ? 0x80 : 0x40; | ||
68 | report->field[1]->value[0] = 0x03; // unknown setting, imitate windows driver | ||
69 | report->field[2]->value[0] = data_pointer->sensitivity; | ||
70 | report->field[3]->value[0] = data_pointer->press_speed; | ||
71 | |||
72 | usbhid_submit_report(hdev, report, USB_DIR_OUT); | ||
73 | return 0; | ||
74 | } | ||
75 | |||
76 | static ssize_t pointer_press_to_select_show(struct device *dev, | ||
77 | struct device_attribute *attr, | ||
78 | char *buf) | ||
79 | { | ||
80 | struct hid_device *hdev; | ||
81 | struct tpkbd_data_pointer *data_pointer; | ||
82 | |||
83 | hdev = container_of(dev, struct hid_device, dev); | ||
84 | if (hdev == NULL) | ||
85 | return -ENODEV; | ||
86 | |||
87 | data_pointer = (struct tpkbd_data_pointer *) hid_get_drvdata(hdev); | ||
88 | |||
89 | return snprintf(buf, PAGE_SIZE, "%u\n", data_pointer->press_to_select); | ||
90 | } | ||
91 | |||
92 | static ssize_t pointer_press_to_select_store(struct device *dev, | ||
93 | struct device_attribute *attr, | ||
94 | const char *buf, | ||
95 | size_t count) | ||
96 | { | ||
97 | struct hid_device *hdev; | ||
98 | struct tpkbd_data_pointer *data_pointer; | ||
99 | int value; | ||
100 | |||
101 | hdev = container_of(dev, struct hid_device, dev); | ||
102 | if (hdev == NULL) | ||
103 | return -ENODEV; | ||
104 | |||
105 | data_pointer = (struct tpkbd_data_pointer *) hid_get_drvdata(hdev); | ||
106 | |||
107 | if (kstrtoint(buf, 10, &value)) | ||
108 | return -EINVAL; | ||
109 | if (value < 0 || value > 1) | ||
110 | return -EINVAL; | ||
111 | |||
112 | data_pointer->press_to_select = value; | ||
113 | tpkbd_features_set(hdev); | ||
114 | |||
115 | return count; | ||
116 | } | ||
117 | |||
118 | static ssize_t pointer_dragging_show(struct device *dev, | ||
119 | struct device_attribute *attr, | ||
120 | char *buf) | ||
121 | { | ||
122 | struct hid_device *hdev; | ||
123 | struct tpkbd_data_pointer *data_pointer; | ||
124 | |||
125 | hdev = container_of(dev, struct hid_device, dev); | ||
126 | if (hdev == NULL) | ||
127 | return -ENODEV; | ||
128 | |||
129 | data_pointer = (struct tpkbd_data_pointer *) hid_get_drvdata(hdev); | ||
130 | |||
131 | return snprintf(buf, PAGE_SIZE, "%u\n", data_pointer->dragging); | ||
132 | } | ||
133 | |||
134 | static ssize_t pointer_dragging_store(struct device *dev, | ||
135 | struct device_attribute *attr, | ||
136 | const char *buf, | ||
137 | size_t count) | ||
138 | { | ||
139 | struct hid_device *hdev; | ||
140 | struct tpkbd_data_pointer *data_pointer; | ||
141 | int value; | ||
142 | |||
143 | hdev = container_of(dev, struct hid_device, dev); | ||
144 | if (hdev == NULL) | ||
145 | return -ENODEV; | ||
146 | |||
147 | data_pointer = (struct tpkbd_data_pointer *) hid_get_drvdata(hdev); | ||
148 | |||
149 | if (kstrtoint(buf, 10, &value)) | ||
150 | return -EINVAL; | ||
151 | if (value < 0 || value > 1) | ||
152 | return -EINVAL; | ||
153 | |||
154 | data_pointer->dragging = value; | ||
155 | tpkbd_features_set(hdev); | ||
156 | |||
157 | return count; | ||
158 | } | ||
159 | |||
160 | static ssize_t pointer_release_to_select_show(struct device *dev, | ||
161 | struct device_attribute *attr, | ||
162 | char *buf) | ||
163 | { | ||
164 | struct hid_device *hdev; | ||
165 | struct tpkbd_data_pointer *data_pointer; | ||
166 | |||
167 | hdev = container_of(dev, struct hid_device, dev); | ||
168 | if (hdev == NULL) | ||
169 | return -ENODEV; | ||
170 | |||
171 | data_pointer = (struct tpkbd_data_pointer *) hid_get_drvdata(hdev); | ||
172 | |||
173 | return snprintf(buf, PAGE_SIZE, "%u\n", data_pointer->release_to_select); | ||
174 | } | ||
175 | |||
176 | static ssize_t pointer_release_to_select_store(struct device *dev, | ||
177 | struct device_attribute *attr, | ||
178 | const char *buf, | ||
179 | size_t count) | ||
180 | { | ||
181 | struct hid_device *hdev; | ||
182 | struct tpkbd_data_pointer *data_pointer; | ||
183 | int value; | ||
184 | |||
185 | hdev = container_of(dev, struct hid_device, dev); | ||
186 | if (hdev == NULL) | ||
187 | return -ENODEV; | ||
188 | |||
189 | data_pointer = (struct tpkbd_data_pointer *) hid_get_drvdata(hdev); | ||
190 | |||
191 | if (kstrtoint(buf, 10, &value)) | ||
192 | return -EINVAL; | ||
193 | if (value < 0 || value > 1) | ||
194 | return -EINVAL; | ||
195 | |||
196 | data_pointer->release_to_select = value; | ||
197 | tpkbd_features_set(hdev); | ||
198 | |||
199 | return count; | ||
200 | } | ||
201 | |||
202 | static ssize_t pointer_select_right_show(struct device *dev, | ||
203 | struct device_attribute *attr, | ||
204 | char *buf) | ||
205 | { | ||
206 | struct hid_device *hdev; | ||
207 | struct tpkbd_data_pointer *data_pointer; | ||
208 | |||
209 | hdev = container_of(dev, struct hid_device, dev); | ||
210 | if (hdev == NULL) | ||
211 | return -ENODEV; | ||
212 | |||
213 | data_pointer = (struct tpkbd_data_pointer *) hid_get_drvdata(hdev); | ||
214 | |||
215 | return snprintf(buf, PAGE_SIZE, "%u\n", data_pointer->select_right); | ||
216 | } | ||
217 | |||
218 | static ssize_t pointer_select_right_store(struct device *dev, | ||
219 | struct device_attribute *attr, | ||
220 | const char *buf, | ||
221 | size_t count) | ||
222 | { | ||
223 | struct hid_device *hdev; | ||
224 | struct tpkbd_data_pointer *data_pointer; | ||
225 | int value; | ||
226 | |||
227 | hdev = container_of(dev, struct hid_device, dev); | ||
228 | if (hdev == NULL) | ||
229 | return -ENODEV; | ||
230 | |||
231 | data_pointer = (struct tpkbd_data_pointer *) hid_get_drvdata(hdev); | ||
232 | |||
233 | if (kstrtoint(buf, 10, &value)) | ||
234 | return -EINVAL; | ||
235 | if (value < 0 || value > 1) | ||
236 | return -EINVAL; | ||
237 | |||
238 | data_pointer->select_right = value; | ||
239 | tpkbd_features_set(hdev); | ||
240 | |||
241 | return count; | ||
242 | } | ||
243 | |||
244 | static ssize_t pointer_sensitivity_show(struct device *dev, | ||
245 | struct device_attribute *attr, | ||
246 | char *buf) | ||
247 | { | ||
248 | struct hid_device *hdev; | ||
249 | struct tpkbd_data_pointer *data_pointer; | ||
250 | |||
251 | hdev = container_of(dev, struct hid_device, dev); | ||
252 | if (hdev == NULL) | ||
253 | return -ENODEV; | ||
254 | |||
255 | data_pointer = (struct tpkbd_data_pointer *) hid_get_drvdata(hdev); | ||
256 | |||
257 | return snprintf(buf, PAGE_SIZE, "%u\n", | ||
258 | data_pointer->sensitivity); | ||
259 | } | ||
260 | |||
261 | static ssize_t pointer_sensitivity_store(struct device *dev, | ||
262 | struct device_attribute *attr, | ||
263 | const char *buf, | ||
264 | size_t count) | ||
265 | { | ||
266 | struct hid_device *hdev; | ||
267 | struct tpkbd_data_pointer *data_pointer; | ||
268 | int value; | ||
269 | |||
270 | hdev = container_of(dev, struct hid_device, dev); | ||
271 | if (hdev == NULL) | ||
272 | return -ENODEV; | ||
273 | |||
274 | data_pointer = (struct tpkbd_data_pointer *) hid_get_drvdata(hdev); | ||
275 | |||
276 | if (kstrtoint(buf, 10, &value) || value < 1 || value > 255) | ||
277 | return -EINVAL; | ||
278 | |||
279 | data_pointer->sensitivity = value; | ||
280 | tpkbd_features_set(hdev); | ||
281 | |||
282 | return count; | ||
283 | } | ||
284 | |||
285 | static ssize_t pointer_press_speed_show(struct device *dev, | ||
286 | struct device_attribute *attr, | ||
287 | char *buf) | ||
288 | { | ||
289 | struct hid_device *hdev; | ||
290 | struct tpkbd_data_pointer *data_pointer; | ||
291 | |||
292 | hdev = container_of(dev, struct hid_device, dev); | ||
293 | if (hdev == NULL) | ||
294 | return -ENODEV; | ||
295 | |||
296 | data_pointer = (struct tpkbd_data_pointer *) hid_get_drvdata(hdev); | ||
297 | |||
298 | return snprintf(buf, PAGE_SIZE, "%u\n", | ||
299 | data_pointer->press_speed); | ||
300 | } | ||
301 | |||
302 | static ssize_t pointer_press_speed_store(struct device *dev, | ||
303 | struct device_attribute *attr, | ||
304 | const char *buf, | ||
305 | size_t count) | ||
306 | { | ||
307 | struct hid_device *hdev; | ||
308 | struct tpkbd_data_pointer *data_pointer; | ||
309 | int value; | ||
310 | |||
311 | hdev = container_of(dev, struct hid_device, dev); | ||
312 | if (hdev == NULL) | ||
313 | return -ENODEV; | ||
314 | |||
315 | data_pointer = (struct tpkbd_data_pointer *) hid_get_drvdata(hdev); | ||
316 | |||
317 | if (kstrtoint(buf, 10, &value) || value < 1 || value > 255) | ||
318 | return -EINVAL; | ||
319 | |||
320 | data_pointer->press_speed = value; | ||
321 | tpkbd_features_set(hdev); | ||
322 | |||
323 | return count; | ||
324 | } | ||
325 | |||
326 | static struct device_attribute dev_attr_pointer_press_to_select = | ||
327 | __ATTR(press_to_select, S_IWUSR | S_IRUGO, | ||
328 | pointer_press_to_select_show, | ||
329 | pointer_press_to_select_store); | ||
330 | |||
331 | static struct device_attribute dev_attr_pointer_dragging = | ||
332 | __ATTR(dragging, S_IWUSR | S_IRUGO, | ||
333 | pointer_dragging_show, | ||
334 | pointer_dragging_store); | ||
335 | |||
336 | static struct device_attribute dev_attr_pointer_release_to_select = | ||
337 | __ATTR(release_to_select, S_IWUSR | S_IRUGO, | ||
338 | pointer_release_to_select_show, | ||
339 | pointer_release_to_select_store); | ||
340 | |||
341 | static struct device_attribute dev_attr_pointer_select_right = | ||
342 | __ATTR(select_right, S_IWUSR | S_IRUGO, | ||
343 | pointer_select_right_show, | ||
344 | pointer_select_right_store); | ||
345 | |||
346 | static struct device_attribute dev_attr_pointer_sensitivity = | ||
347 | __ATTR(sensitivity, S_IWUSR | S_IRUGO, | ||
348 | pointer_sensitivity_show, | ||
349 | pointer_sensitivity_store); | ||
350 | |||
351 | static struct device_attribute dev_attr_pointer_press_speed = | ||
352 | __ATTR(press_speed, S_IWUSR | S_IRUGO, | ||
353 | pointer_press_speed_show, | ||
354 | pointer_press_speed_store); | ||
355 | |||
356 | static struct attribute *tpkbd_attributes_pointer[] = { | ||
357 | &dev_attr_pointer_press_to_select.attr, | ||
358 | &dev_attr_pointer_dragging.attr, | ||
359 | &dev_attr_pointer_release_to_select.attr, | ||
360 | &dev_attr_pointer_select_right.attr, | ||
361 | &dev_attr_pointer_sensitivity.attr, | ||
362 | &dev_attr_pointer_press_speed.attr, | ||
363 | NULL | ||
364 | }; | ||
365 | |||
366 | static const struct attribute_group tpkbd_attr_group_pointer = { | ||
367 | .attrs = tpkbd_attributes_pointer, | ||
368 | }; | ||
369 | |||
370 | static enum led_brightness tpkbd_led_brightness_get( | ||
371 | struct led_classdev *led_cdev) | ||
372 | { | ||
373 | struct device *dev; | ||
374 | struct hid_device *hdev; | ||
375 | struct tpkbd_data_pointer *data_pointer; | ||
376 | int led_nr = 0; | ||
377 | |||
378 | dev = led_cdev->dev->parent; | ||
379 | hdev = container_of(dev, struct hid_device, dev); | ||
380 | data_pointer = (struct tpkbd_data_pointer *) hid_get_drvdata(hdev); | ||
381 | |||
382 | if (led_cdev == &data_pointer->led_micmute) | ||
383 | led_nr = 1; | ||
384 | |||
385 | return data_pointer->led_state & (1 << led_nr) | ||
386 | ? LED_FULL | ||
387 | : LED_OFF; | ||
388 | } | ||
389 | |||
390 | static void tpkbd_led_brightness_set(struct led_classdev *led_cdev, | ||
391 | enum led_brightness value) | ||
392 | { | ||
393 | struct device *dev; | ||
394 | struct hid_device *hdev; | ||
395 | struct hid_report *report; | ||
396 | struct tpkbd_data_pointer *data_pointer; | ||
397 | int led_nr = 0; | ||
398 | |||
399 | dev = led_cdev->dev->parent; | ||
400 | hdev = container_of(dev, struct hid_device, dev); | ||
401 | data_pointer = (struct tpkbd_data_pointer *) hid_get_drvdata(hdev); | ||
402 | |||
403 | if (led_cdev == &data_pointer->led_micmute) | ||
404 | led_nr = 1; | ||
405 | |||
406 | if (value == LED_OFF) | ||
407 | data_pointer->led_state &= ~(1 << led_nr); | ||
408 | else | ||
409 | data_pointer->led_state |= 1 << led_nr; | ||
410 | |||
411 | report = hdev->report_enum[HID_OUTPUT_REPORT].report_id_hash[3]; | ||
412 | report->field[0]->value[0] = (data_pointer->led_state >> 0) & 1; | ||
413 | report->field[0]->value[1] = (data_pointer->led_state >> 1) & 1; | ||
414 | usbhid_submit_report(hdev, report, USB_DIR_OUT); | ||
415 | } | ||
416 | |||
417 | static int tpkbd_probe_tp(struct hid_device *hdev) | ||
418 | { | ||
419 | struct device *dev = &hdev->dev; | ||
420 | struct tpkbd_data_pointer *data_pointer; | ||
421 | size_t name_sz = strlen(dev_name(dev)) + 16; | ||
422 | char *name_mute, *name_micmute; | ||
423 | int ret; | ||
424 | |||
425 | if (sysfs_create_group(&hdev->dev.kobj, | ||
426 | &tpkbd_attr_group_pointer)) { | ||
427 | hid_warn(hdev, "Could not create sysfs group\n"); | ||
428 | } | ||
429 | |||
430 | data_pointer = kzalloc(sizeof(struct tpkbd_data_pointer), GFP_KERNEL); | ||
431 | if (data_pointer == NULL) { | ||
432 | hid_err(hdev, "Could not allocate memory for driver data\n"); | ||
433 | return -ENOMEM; | ||
434 | } | ||
435 | |||
436 | // set same default values as windows driver | ||
437 | data_pointer->sensitivity = 0xa0; | ||
438 | data_pointer->press_speed = 0x38; | ||
439 | |||
440 | name_mute = kzalloc(name_sz, GFP_KERNEL); | ||
441 | if (name_mute == NULL) { | ||
442 | hid_err(hdev, "Could not allocate memory for led data\n"); | ||
443 | ret = -ENOMEM; | ||
444 | goto err; | ||
445 | } | ||
446 | snprintf(name_mute, name_sz, "%s:amber:mute", dev_name(dev)); | ||
447 | |||
448 | name_micmute = kzalloc(name_sz, GFP_KERNEL); | ||
449 | if (name_micmute == NULL) { | ||
450 | hid_err(hdev, "Could not allocate memory for led data\n"); | ||
451 | ret = -ENOMEM; | ||
452 | goto err2; | ||
453 | } | ||
454 | snprintf(name_micmute, name_sz, "%s:amber:micmute", dev_name(dev)); | ||
455 | |||
456 | hid_set_drvdata(hdev, data_pointer); | ||
457 | |||
458 | data_pointer->led_mute.name = name_mute; | ||
459 | data_pointer->led_mute.brightness_get = tpkbd_led_brightness_get; | ||
460 | data_pointer->led_mute.brightness_set = tpkbd_led_brightness_set; | ||
461 | data_pointer->led_mute.dev = dev; | ||
462 | led_classdev_register(dev, &data_pointer->led_mute); | ||
463 | |||
464 | data_pointer->led_micmute.name = name_micmute; | ||
465 | data_pointer->led_micmute.brightness_get = tpkbd_led_brightness_get; | ||
466 | data_pointer->led_micmute.brightness_set = tpkbd_led_brightness_set; | ||
467 | data_pointer->led_micmute.dev = dev; | ||
468 | led_classdev_register(dev, &data_pointer->led_micmute); | ||
469 | |||
470 | tpkbd_features_set(hdev); | ||
471 | |||
472 | return 0; | ||
473 | |||
474 | err2: | ||
475 | kfree(name_mute); | ||
476 | err: | ||
477 | kfree(data_pointer); | ||
478 | return ret; | ||
479 | } | ||
480 | |||
481 | static int tpkbd_probe(struct hid_device *hdev, | ||
482 | const struct hid_device_id *id) | ||
483 | { | ||
484 | int ret; | ||
485 | struct usbhid_device *uhdev; | ||
486 | |||
487 | ret = hid_parse(hdev); | ||
488 | if (ret) { | ||
489 | hid_err(hdev, "hid_parse failed\n"); | ||
490 | goto err_free; | ||
491 | } | ||
492 | |||
493 | ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); | ||
494 | if (ret) { | ||
495 | hid_err(hdev, "hid_hw_start failed\n"); | ||
496 | goto err_free; | ||
497 | } | ||
498 | |||
499 | uhdev = (struct usbhid_device *) hdev->driver_data; | ||
500 | |||
501 | if (uhdev->ifnum == 1) | ||
502 | return tpkbd_probe_tp(hdev); | ||
503 | |||
504 | return 0; | ||
505 | err_free: | ||
506 | return ret; | ||
507 | } | ||
508 | |||
509 | static void tpkbd_remove_tp(struct hid_device *hdev) | ||
510 | { | ||
511 | struct tpkbd_data_pointer *data_pointer; | ||
512 | |||
513 | sysfs_remove_group(&hdev->dev.kobj, | ||
514 | &tpkbd_attr_group_pointer); | ||
515 | |||
516 | data_pointer = (struct tpkbd_data_pointer *) hid_get_drvdata(hdev); | ||
517 | |||
518 | led_classdev_unregister(&data_pointer->led_micmute); | ||
519 | led_classdev_unregister(&data_pointer->led_mute); | ||
520 | |||
521 | hid_set_drvdata(hdev, NULL); | ||
522 | kfree(data_pointer); | ||
523 | } | ||
524 | |||
525 | static void tpkbd_remove(struct hid_device *hdev) | ||
526 | { | ||
527 | struct usbhid_device *uhdev; | ||
528 | |||
529 | uhdev = (struct usbhid_device *) hdev->driver_data; | ||
530 | if (uhdev->ifnum == 1) | ||
531 | tpkbd_remove_tp(hdev); | ||
532 | |||
533 | hid_hw_stop(hdev); | ||
534 | } | ||
535 | |||
536 | static const struct hid_device_id tpkbd_devices[] = { | ||
537 | { HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_TPKBD) }, | ||
538 | { } | ||
539 | }; | ||
540 | |||
541 | MODULE_DEVICE_TABLE(hid, tpkbd_devices); | ||
542 | |||
543 | static struct hid_driver tpkbd_driver = { | ||
544 | .name = "lenovo_tpkbd", | ||
545 | .id_table = tpkbd_devices, | ||
546 | .input_mapping = tpkbd_input_mapping, | ||
547 | .probe = tpkbd_probe, | ||
548 | .remove = tpkbd_remove, | ||
549 | }; | ||
550 | |||
551 | static int __init tpkbd_init(void) | ||
552 | { | ||
553 | return hid_register_driver(&tpkbd_driver); | ||
554 | } | ||
555 | |||
556 | static void __exit tpkbd_exit(void) | ||
557 | { | ||
558 | hid_unregister_driver(&tpkbd_driver); | ||
559 | } | ||
560 | |||
561 | module_init(tpkbd_init); | ||
562 | module_exit(tpkbd_exit); | ||
563 | |||
564 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/hid/hid-magicmouse.c b/drivers/hid/hid-magicmouse.c index 40ac6654f1d1..73647266daad 100644 --- a/drivers/hid/hid-magicmouse.c +++ b/drivers/hid/hid-magicmouse.c | |||
@@ -16,6 +16,7 @@ | |||
16 | 16 | ||
17 | #include <linux/device.h> | 17 | #include <linux/device.h> |
18 | #include <linux/hid.h> | 18 | #include <linux/hid.h> |
19 | #include <linux/input/mt.h> | ||
19 | #include <linux/module.h> | 20 | #include <linux/module.h> |
20 | #include <linux/slab.h> | 21 | #include <linux/slab.h> |
21 | #include <linux/usb.h> | 22 | #include <linux/usb.h> |
@@ -48,10 +49,6 @@ static bool scroll_acceleration = false; | |||
48 | module_param(scroll_acceleration, bool, 0644); | 49 | module_param(scroll_acceleration, bool, 0644); |
49 | MODULE_PARM_DESC(scroll_acceleration, "Accelerate sequential scroll events"); | 50 | MODULE_PARM_DESC(scroll_acceleration, "Accelerate sequential scroll events"); |
50 | 51 | ||
51 | static bool report_touches = true; | ||
52 | module_param(report_touches, bool, 0644); | ||
53 | MODULE_PARM_DESC(report_touches, "Emit touch records (otherwise, only use them for emulation)"); | ||
54 | |||
55 | static bool report_undeciphered; | 52 | static bool report_undeciphered; |
56 | module_param(report_undeciphered, bool, 0644); | 53 | module_param(report_undeciphered, bool, 0644); |
57 | MODULE_PARM_DESC(report_undeciphered, "Report undeciphered multi-touch state field using a MSC_RAW event"); | 54 | MODULE_PARM_DESC(report_undeciphered, "Report undeciphered multi-touch state field using a MSC_RAW event"); |
@@ -72,15 +69,6 @@ MODULE_PARM_DESC(report_undeciphered, "Report undeciphered multi-touch state fie | |||
72 | 69 | ||
73 | #define SCROLL_ACCEL_DEFAULT 7 | 70 | #define SCROLL_ACCEL_DEFAULT 7 |
74 | 71 | ||
75 | /* Single touch emulation should only begin when no touches are currently down. | ||
76 | * This is true when single_touch_id is equal to NO_TOUCHES. If multiple touches | ||
77 | * are down and the touch providing for single touch emulation is lifted, | ||
78 | * single_touch_id is equal to SINGLE_TOUCH_UP. While single touch emulation is | ||
79 | * occurring, single_touch_id corresponds with the tracking id of the touch used. | ||
80 | */ | ||
81 | #define NO_TOUCHES -1 | ||
82 | #define SINGLE_TOUCH_UP -2 | ||
83 | |||
84 | /* Touch surface information. Dimension is in hundredths of a mm, min and max | 72 | /* Touch surface information. Dimension is in hundredths of a mm, min and max |
85 | * are in units. */ | 73 | * are in units. */ |
86 | #define MOUSE_DIMENSION_X (float)9056 | 74 | #define MOUSE_DIMENSION_X (float)9056 |
@@ -129,7 +117,6 @@ struct magicmouse_sc { | |||
129 | u8 size; | 117 | u8 size; |
130 | } touches[16]; | 118 | } touches[16]; |
131 | int tracking_ids[16]; | 119 | int tracking_ids[16]; |
132 | int single_touch_id; | ||
133 | }; | 120 | }; |
134 | 121 | ||
135 | static int magicmouse_firm_touch(struct magicmouse_sc *msc) | 122 | static int magicmouse_firm_touch(struct magicmouse_sc *msc) |
@@ -268,16 +255,14 @@ static void magicmouse_emit_touch(struct magicmouse_sc *msc, int raw_id, u8 *tda | |||
268 | } | 255 | } |
269 | } | 256 | } |
270 | 257 | ||
271 | if (down) { | 258 | if (down) |
272 | msc->ntouches++; | 259 | msc->ntouches++; |
273 | if (msc->single_touch_id == NO_TOUCHES) | 260 | |
274 | msc->single_touch_id = id; | 261 | input_mt_slot(input, id); |
275 | } else if (msc->single_touch_id == id) | 262 | input_mt_report_slot_state(input, MT_TOOL_FINGER, down); |
276 | msc->single_touch_id = SINGLE_TOUCH_UP; | ||
277 | 263 | ||
278 | /* Generate the input events for this touch. */ | 264 | /* Generate the input events for this touch. */ |
279 | if (report_touches && down) { | 265 | if (down) { |
280 | input_report_abs(input, ABS_MT_TRACKING_ID, id); | ||
281 | input_report_abs(input, ABS_MT_TOUCH_MAJOR, touch_major << 2); | 266 | input_report_abs(input, ABS_MT_TOUCH_MAJOR, touch_major << 2); |
282 | input_report_abs(input, ABS_MT_TOUCH_MINOR, touch_minor << 2); | 267 | input_report_abs(input, ABS_MT_TOUCH_MINOR, touch_minor << 2); |
283 | input_report_abs(input, ABS_MT_ORIENTATION, -orientation); | 268 | input_report_abs(input, ABS_MT_ORIENTATION, -orientation); |
@@ -290,8 +275,6 @@ static void magicmouse_emit_touch(struct magicmouse_sc *msc, int raw_id, u8 *tda | |||
290 | else /* USB_DEVICE_ID_APPLE_MAGICTRACKPAD */ | 275 | else /* USB_DEVICE_ID_APPLE_MAGICTRACKPAD */ |
291 | input_event(input, EV_MSC, MSC_RAW, tdata[8]); | 276 | input_event(input, EV_MSC, MSC_RAW, tdata[8]); |
292 | } | 277 | } |
293 | |||
294 | input_mt_sync(input); | ||
295 | } | 278 | } |
296 | } | 279 | } |
297 | 280 | ||
@@ -312,12 +295,6 @@ static int magicmouse_raw_event(struct hid_device *hdev, | |||
312 | for (ii = 0; ii < npoints; ii++) | 295 | for (ii = 0; ii < npoints; ii++) |
313 | magicmouse_emit_touch(msc, ii, data + ii * 9 + 4); | 296 | magicmouse_emit_touch(msc, ii, data + ii * 9 + 4); |
314 | 297 | ||
315 | /* We don't need an MT sync here because trackpad emits a | ||
316 | * BTN_TOUCH event in a new frame when all touches are released. | ||
317 | */ | ||
318 | if (msc->ntouches == 0) | ||
319 | msc->single_touch_id = NO_TOUCHES; | ||
320 | |||
321 | clicks = data[1]; | 298 | clicks = data[1]; |
322 | 299 | ||
323 | /* The following bits provide a device specific timestamp. They | 300 | /* The following bits provide a device specific timestamp. They |
@@ -335,9 +312,6 @@ static int magicmouse_raw_event(struct hid_device *hdev, | |||
335 | for (ii = 0; ii < npoints; ii++) | 312 | for (ii = 0; ii < npoints; ii++) |
336 | magicmouse_emit_touch(msc, ii, data + ii * 8 + 6); | 313 | magicmouse_emit_touch(msc, ii, data + ii * 8 + 6); |
337 | 314 | ||
338 | if (report_touches && msc->ntouches == 0) | ||
339 | input_mt_sync(input); | ||
340 | |||
341 | /* When emulating three-button mode, it is important | 315 | /* When emulating three-button mode, it is important |
342 | * to have the current touch information before | 316 | * to have the current touch information before |
343 | * generating a click event. | 317 | * generating a click event. |
@@ -370,25 +344,17 @@ static int magicmouse_raw_event(struct hid_device *hdev, | |||
370 | input_report_rel(input, REL_Y, y); | 344 | input_report_rel(input, REL_Y, y); |
371 | } else { /* USB_DEVICE_ID_APPLE_MAGICTRACKPAD */ | 345 | } else { /* USB_DEVICE_ID_APPLE_MAGICTRACKPAD */ |
372 | input_report_key(input, BTN_MOUSE, clicks & 1); | 346 | input_report_key(input, BTN_MOUSE, clicks & 1); |
373 | input_report_key(input, BTN_TOUCH, msc->ntouches > 0); | 347 | input_mt_report_pointer_emulation(input, true); |
374 | input_report_key(input, BTN_TOOL_FINGER, msc->ntouches == 1); | ||
375 | input_report_key(input, BTN_TOOL_DOUBLETAP, msc->ntouches == 2); | ||
376 | input_report_key(input, BTN_TOOL_TRIPLETAP, msc->ntouches == 3); | ||
377 | input_report_key(input, BTN_TOOL_QUADTAP, msc->ntouches == 4); | ||
378 | if (msc->single_touch_id >= 0) { | ||
379 | input_report_abs(input, ABS_X, | ||
380 | msc->touches[msc->single_touch_id].x); | ||
381 | input_report_abs(input, ABS_Y, | ||
382 | msc->touches[msc->single_touch_id].y); | ||
383 | } | ||
384 | } | 348 | } |
385 | 349 | ||
386 | input_sync(input); | 350 | input_sync(input); |
387 | return 1; | 351 | return 1; |
388 | } | 352 | } |
389 | 353 | ||
390 | static void magicmouse_setup_input(struct input_dev *input, struct hid_device *hdev) | 354 | static int magicmouse_setup_input(struct input_dev *input, struct hid_device *hdev) |
391 | { | 355 | { |
356 | int error; | ||
357 | |||
392 | __set_bit(EV_KEY, input->evbit); | 358 | __set_bit(EV_KEY, input->evbit); |
393 | 359 | ||
394 | if (input->id.product == USB_DEVICE_ID_APPLE_MAGICMOUSE) { | 360 | if (input->id.product == USB_DEVICE_ID_APPLE_MAGICMOUSE) { |
@@ -417,62 +383,66 @@ static void magicmouse_setup_input(struct input_dev *input, struct hid_device *h | |||
417 | __set_bit(BTN_TOOL_DOUBLETAP, input->keybit); | 383 | __set_bit(BTN_TOOL_DOUBLETAP, input->keybit); |
418 | __set_bit(BTN_TOOL_TRIPLETAP, input->keybit); | 384 | __set_bit(BTN_TOOL_TRIPLETAP, input->keybit); |
419 | __set_bit(BTN_TOOL_QUADTAP, input->keybit); | 385 | __set_bit(BTN_TOOL_QUADTAP, input->keybit); |
386 | __set_bit(BTN_TOOL_QUINTTAP, input->keybit); | ||
420 | __set_bit(BTN_TOUCH, input->keybit); | 387 | __set_bit(BTN_TOUCH, input->keybit); |
421 | __set_bit(INPUT_PROP_POINTER, input->propbit); | 388 | __set_bit(INPUT_PROP_POINTER, input->propbit); |
422 | __set_bit(INPUT_PROP_BUTTONPAD, input->propbit); | 389 | __set_bit(INPUT_PROP_BUTTONPAD, input->propbit); |
423 | } | 390 | } |
424 | 391 | ||
425 | if (report_touches) { | ||
426 | __set_bit(EV_ABS, input->evbit); | ||
427 | |||
428 | input_set_abs_params(input, ABS_MT_TRACKING_ID, 0, 15, 0, 0); | ||
429 | input_set_abs_params(input, ABS_MT_TOUCH_MAJOR, 0, 255 << 2, | ||
430 | 4, 0); | ||
431 | input_set_abs_params(input, ABS_MT_TOUCH_MINOR, 0, 255 << 2, | ||
432 | 4, 0); | ||
433 | input_set_abs_params(input, ABS_MT_ORIENTATION, -31, 32, 1, 0); | ||
434 | |||
435 | /* Note: Touch Y position from the device is inverted relative | ||
436 | * to how pointer motion is reported (and relative to how USB | ||
437 | * HID recommends the coordinates work). This driver keeps | ||
438 | * the origin at the same position, and just uses the additive | ||
439 | * inverse of the reported Y. | ||
440 | */ | ||
441 | if (input->id.product == USB_DEVICE_ID_APPLE_MAGICMOUSE) { | ||
442 | input_set_abs_params(input, ABS_MT_POSITION_X, | ||
443 | MOUSE_MIN_X, MOUSE_MAX_X, 4, 0); | ||
444 | input_set_abs_params(input, ABS_MT_POSITION_Y, | ||
445 | MOUSE_MIN_Y, MOUSE_MAX_Y, 4, 0); | ||
446 | |||
447 | input_abs_set_res(input, ABS_MT_POSITION_X, | ||
448 | MOUSE_RES_X); | ||
449 | input_abs_set_res(input, ABS_MT_POSITION_Y, | ||
450 | MOUSE_RES_Y); | ||
451 | } else { /* USB_DEVICE_ID_APPLE_MAGICTRACKPAD */ | ||
452 | input_set_abs_params(input, ABS_X, TRACKPAD_MIN_X, | ||
453 | TRACKPAD_MAX_X, 4, 0); | ||
454 | input_set_abs_params(input, ABS_Y, TRACKPAD_MIN_Y, | ||
455 | TRACKPAD_MAX_Y, 4, 0); | ||
456 | input_set_abs_params(input, ABS_MT_POSITION_X, | ||
457 | TRACKPAD_MIN_X, TRACKPAD_MAX_X, 4, 0); | ||
458 | input_set_abs_params(input, ABS_MT_POSITION_Y, | ||
459 | TRACKPAD_MIN_Y, TRACKPAD_MAX_Y, 4, 0); | ||
460 | |||
461 | input_abs_set_res(input, ABS_X, TRACKPAD_RES_X); | ||
462 | input_abs_set_res(input, ABS_Y, TRACKPAD_RES_Y); | ||
463 | input_abs_set_res(input, ABS_MT_POSITION_X, | ||
464 | TRACKPAD_RES_X); | ||
465 | input_abs_set_res(input, ABS_MT_POSITION_Y, | ||
466 | TRACKPAD_RES_Y); | ||
467 | } | ||
468 | 392 | ||
469 | input_set_events_per_packet(input, 60); | 393 | __set_bit(EV_ABS, input->evbit); |
394 | |||
395 | error = input_mt_init_slots(input, 16); | ||
396 | if (error) | ||
397 | return error; | ||
398 | input_set_abs_params(input, ABS_MT_TOUCH_MAJOR, 0, 255 << 2, | ||
399 | 4, 0); | ||
400 | input_set_abs_params(input, ABS_MT_TOUCH_MINOR, 0, 255 << 2, | ||
401 | 4, 0); | ||
402 | input_set_abs_params(input, ABS_MT_ORIENTATION, -31, 32, 1, 0); | ||
403 | |||
404 | /* Note: Touch Y position from the device is inverted relative | ||
405 | * to how pointer motion is reported (and relative to how USB | ||
406 | * HID recommends the coordinates work). This driver keeps | ||
407 | * the origin at the same position, and just uses the additive | ||
408 | * inverse of the reported Y. | ||
409 | */ | ||
410 | if (input->id.product == USB_DEVICE_ID_APPLE_MAGICMOUSE) { | ||
411 | input_set_abs_params(input, ABS_MT_POSITION_X, | ||
412 | MOUSE_MIN_X, MOUSE_MAX_X, 4, 0); | ||
413 | input_set_abs_params(input, ABS_MT_POSITION_Y, | ||
414 | MOUSE_MIN_Y, MOUSE_MAX_Y, 4, 0); | ||
415 | |||
416 | input_abs_set_res(input, ABS_MT_POSITION_X, | ||
417 | MOUSE_RES_X); | ||
418 | input_abs_set_res(input, ABS_MT_POSITION_Y, | ||
419 | MOUSE_RES_Y); | ||
420 | } else { /* USB_DEVICE_ID_APPLE_MAGICTRACKPAD */ | ||
421 | input_set_abs_params(input, ABS_X, TRACKPAD_MIN_X, | ||
422 | TRACKPAD_MAX_X, 4, 0); | ||
423 | input_set_abs_params(input, ABS_Y, TRACKPAD_MIN_Y, | ||
424 | TRACKPAD_MAX_Y, 4, 0); | ||
425 | input_set_abs_params(input, ABS_MT_POSITION_X, | ||
426 | TRACKPAD_MIN_X, TRACKPAD_MAX_X, 4, 0); | ||
427 | input_set_abs_params(input, ABS_MT_POSITION_Y, | ||
428 | TRACKPAD_MIN_Y, TRACKPAD_MAX_Y, 4, 0); | ||
429 | |||
430 | input_abs_set_res(input, ABS_X, TRACKPAD_RES_X); | ||
431 | input_abs_set_res(input, ABS_Y, TRACKPAD_RES_Y); | ||
432 | input_abs_set_res(input, ABS_MT_POSITION_X, | ||
433 | TRACKPAD_RES_X); | ||
434 | input_abs_set_res(input, ABS_MT_POSITION_Y, | ||
435 | TRACKPAD_RES_Y); | ||
470 | } | 436 | } |
471 | 437 | ||
438 | input_set_events_per_packet(input, 60); | ||
439 | |||
472 | if (report_undeciphered) { | 440 | if (report_undeciphered) { |
473 | __set_bit(EV_MSC, input->evbit); | 441 | __set_bit(EV_MSC, input->evbit); |
474 | __set_bit(MSC_RAW, input->mscbit); | 442 | __set_bit(MSC_RAW, input->mscbit); |
475 | } | 443 | } |
444 | |||
445 | return 0; | ||
476 | } | 446 | } |
477 | 447 | ||
478 | static int magicmouse_input_mapping(struct hid_device *hdev, | 448 | static int magicmouse_input_mapping(struct hid_device *hdev, |
@@ -511,8 +481,6 @@ static int magicmouse_probe(struct hid_device *hdev, | |||
511 | msc->quirks = id->driver_data; | 481 | msc->quirks = id->driver_data; |
512 | hid_set_drvdata(hdev, msc); | 482 | hid_set_drvdata(hdev, msc); |
513 | 483 | ||
514 | msc->single_touch_id = NO_TOUCHES; | ||
515 | |||
516 | ret = hid_parse(hdev); | 484 | ret = hid_parse(hdev); |
517 | if (ret) { | 485 | if (ret) { |
518 | hid_err(hdev, "magicmouse hid parse failed\n"); | 486 | hid_err(hdev, "magicmouse hid parse failed\n"); |
@@ -528,8 +496,13 @@ static int magicmouse_probe(struct hid_device *hdev, | |||
528 | /* We do this after hid-input is done parsing reports so that | 496 | /* We do this after hid-input is done parsing reports so that |
529 | * hid-input uses the most natural button and axis IDs. | 497 | * hid-input uses the most natural button and axis IDs. |
530 | */ | 498 | */ |
531 | if (msc->input) | 499 | if (msc->input) { |
532 | magicmouse_setup_input(msc->input, hdev); | 500 | ret = magicmouse_setup_input(msc->input, hdev); |
501 | if (ret) { | ||
502 | hid_err(hdev, "magicmouse setup input failed (%d)\n", ret); | ||
503 | goto err_stop_hw; | ||
504 | } | ||
505 | } | ||
533 | 506 | ||
534 | if (id->product == USB_DEVICE_ID_APPLE_MAGICMOUSE) | 507 | if (id->product == USB_DEVICE_ID_APPLE_MAGICMOUSE) |
535 | report = hid_register_report(hdev, HID_INPUT_REPORT, | 508 | report = hid_register_report(hdev, HID_INPUT_REPORT, |
diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c index 76479246d4ee..59c8b5c1d2de 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c | |||
@@ -83,6 +83,7 @@ struct mt_device { | |||
83 | unsigned last_field_index; /* last field index of the report */ | 83 | unsigned last_field_index; /* last field index of the report */ |
84 | unsigned last_slot_field; /* the last field of a slot */ | 84 | unsigned last_slot_field; /* the last field of a slot */ |
85 | __s8 inputmode; /* InputMode HID feature, -1 if non-existent */ | 85 | __s8 inputmode; /* InputMode HID feature, -1 if non-existent */ |
86 | __s8 inputmode_index; /* InputMode HID feature index in the report */ | ||
86 | __s8 maxcontact_report_id; /* Maximum Contact Number HID feature, | 87 | __s8 maxcontact_report_id; /* Maximum Contact Number HID feature, |
87 | -1 if non-existent */ | 88 | -1 if non-existent */ |
88 | __u8 num_received; /* how many contacts we received */ | 89 | __u8 num_received; /* how many contacts we received */ |
@@ -260,10 +261,20 @@ static void mt_feature_mapping(struct hid_device *hdev, | |||
260 | struct hid_field *field, struct hid_usage *usage) | 261 | struct hid_field *field, struct hid_usage *usage) |
261 | { | 262 | { |
262 | struct mt_device *td = hid_get_drvdata(hdev); | 263 | struct mt_device *td = hid_get_drvdata(hdev); |
264 | int i; | ||
263 | 265 | ||
264 | switch (usage->hid) { | 266 | switch (usage->hid) { |
265 | case HID_DG_INPUTMODE: | 267 | case HID_DG_INPUTMODE: |
266 | td->inputmode = field->report->id; | 268 | td->inputmode = field->report->id; |
269 | td->inputmode_index = 0; /* has to be updated below */ | ||
270 | |||
271 | for (i=0; i < field->maxusage; i++) { | ||
272 | if (field->usage[i].hid == usage->hid) { | ||
273 | td->inputmode_index = i; | ||
274 | break; | ||
275 | } | ||
276 | } | ||
277 | |||
267 | break; | 278 | break; |
268 | case HID_DG_CONTACTMAX: | 279 | case HID_DG_CONTACTMAX: |
269 | td->maxcontact_report_id = field->report->id; | 280 | td->maxcontact_report_id = field->report->id; |
@@ -618,7 +629,7 @@ static void mt_set_input_mode(struct hid_device *hdev) | |||
618 | re = &(hdev->report_enum[HID_FEATURE_REPORT]); | 629 | re = &(hdev->report_enum[HID_FEATURE_REPORT]); |
619 | r = re->report_id_hash[td->inputmode]; | 630 | r = re->report_id_hash[td->inputmode]; |
620 | if (r) { | 631 | if (r) { |
621 | r->field[0]->value[0] = 0x02; | 632 | r->field[0]->value[td->inputmode_index] = 0x02; |
622 | usbhid_submit_report(hdev, r, USB_DIR_OUT); | 633 | usbhid_submit_report(hdev, r, USB_DIR_OUT); |
623 | } | 634 | } |
624 | } | 635 | } |
@@ -951,6 +962,11 @@ static const struct hid_device_id mt_devices[] = { | |||
951 | MT_USB_DEVICE(USB_VENDOR_ID_PANASONIC, | 962 | MT_USB_DEVICE(USB_VENDOR_ID_PANASONIC, |
952 | USB_DEVICE_ID_PANABOARD_UBT880) }, | 963 | USB_DEVICE_ID_PANABOARD_UBT880) }, |
953 | 964 | ||
965 | /* Novatek Panel */ | ||
966 | { .driver_data = MT_CLS_DEFAULT, | ||
967 | MT_USB_DEVICE(USB_VENDOR_ID_NOVATEK, | ||
968 | USB_DEVICE_ID_NOVATEK_PCT) }, | ||
969 | |||
954 | /* PenMount panels */ | 970 | /* PenMount panels */ |
955 | { .driver_data = MT_CLS_CONFIDENCE, | 971 | { .driver_data = MT_CLS_CONFIDENCE, |
956 | MT_USB_DEVICE(USB_VENDOR_ID_PENMOUNT, | 972 | MT_USB_DEVICE(USB_VENDOR_ID_PENMOUNT, |
diff --git a/drivers/hid/hid-picolcd.c b/drivers/hid/hid-picolcd.c index 45c3433f7986..27c8ebdfad01 100644 --- a/drivers/hid/hid-picolcd.c +++ b/drivers/hid/hid-picolcd.c | |||
@@ -1846,7 +1846,7 @@ static void picolcd_debug_out_report(struct picolcd_data *data, | |||
1846 | #define BUFF_SZ 256 | 1846 | #define BUFF_SZ 256 |
1847 | 1847 | ||
1848 | /* Avoid unnecessary overhead if debugfs is disabled */ | 1848 | /* Avoid unnecessary overhead if debugfs is disabled */ |
1849 | if (!hdev->debug_events) | 1849 | if (list_empty(&hdev->debug_list)) |
1850 | return; | 1850 | return; |
1851 | 1851 | ||
1852 | buff = kmalloc(BUFF_SZ, GFP_ATOMIC); | 1852 | buff = kmalloc(BUFF_SZ, GFP_ATOMIC); |
@@ -2613,11 +2613,7 @@ static int picolcd_probe(struct hid_device *hdev, | |||
2613 | goto err_cleanup_data; | 2613 | goto err_cleanup_data; |
2614 | } | 2614 | } |
2615 | 2615 | ||
2616 | /* We don't use hidinput but hid_hw_start() fails if nothing is | ||
2617 | * claimed. So spoof claimed input. */ | ||
2618 | hdev->claimed = HID_CLAIMED_INPUT; | ||
2619 | error = hid_hw_start(hdev, 0); | 2616 | error = hid_hw_start(hdev, 0); |
2620 | hdev->claimed = 0; | ||
2621 | if (error) { | 2617 | if (error) { |
2622 | hid_err(hdev, "hardware start failed\n"); | 2618 | hid_err(hdev, "hardware start failed\n"); |
2623 | goto err_cleanup_data; | 2619 | goto err_cleanup_data; |
diff --git a/drivers/hid/hid-roccat-arvo.c b/drivers/hid/hid-roccat-arvo.c index 093bfad00b02..327f9b8ed1f4 100644 --- a/drivers/hid/hid-roccat-arvo.c +++ b/drivers/hid/hid-roccat-arvo.c | |||
@@ -39,7 +39,7 @@ static ssize_t arvo_sysfs_show_mode_key(struct device *dev, | |||
39 | int retval; | 39 | int retval; |
40 | 40 | ||
41 | mutex_lock(&arvo->arvo_lock); | 41 | mutex_lock(&arvo->arvo_lock); |
42 | retval = roccat_common_receive(usb_dev, ARVO_COMMAND_MODE_KEY, | 42 | retval = roccat_common2_receive(usb_dev, ARVO_COMMAND_MODE_KEY, |
43 | &temp_buf, sizeof(struct arvo_mode_key)); | 43 | &temp_buf, sizeof(struct arvo_mode_key)); |
44 | mutex_unlock(&arvo->arvo_lock); | 44 | mutex_unlock(&arvo->arvo_lock); |
45 | if (retval) | 45 | if (retval) |
@@ -67,7 +67,7 @@ static ssize_t arvo_sysfs_set_mode_key(struct device *dev, | |||
67 | temp_buf.state = state; | 67 | temp_buf.state = state; |
68 | 68 | ||
69 | mutex_lock(&arvo->arvo_lock); | 69 | mutex_lock(&arvo->arvo_lock); |
70 | retval = roccat_common_send(usb_dev, ARVO_COMMAND_MODE_KEY, | 70 | retval = roccat_common2_send(usb_dev, ARVO_COMMAND_MODE_KEY, |
71 | &temp_buf, sizeof(struct arvo_mode_key)); | 71 | &temp_buf, sizeof(struct arvo_mode_key)); |
72 | mutex_unlock(&arvo->arvo_lock); | 72 | mutex_unlock(&arvo->arvo_lock); |
73 | if (retval) | 73 | if (retval) |
@@ -87,7 +87,7 @@ static ssize_t arvo_sysfs_show_key_mask(struct device *dev, | |||
87 | int retval; | 87 | int retval; |
88 | 88 | ||
89 | mutex_lock(&arvo->arvo_lock); | 89 | mutex_lock(&arvo->arvo_lock); |
90 | retval = roccat_common_receive(usb_dev, ARVO_COMMAND_KEY_MASK, | 90 | retval = roccat_common2_receive(usb_dev, ARVO_COMMAND_KEY_MASK, |
91 | &temp_buf, sizeof(struct arvo_key_mask)); | 91 | &temp_buf, sizeof(struct arvo_key_mask)); |
92 | mutex_unlock(&arvo->arvo_lock); | 92 | mutex_unlock(&arvo->arvo_lock); |
93 | if (retval) | 93 | if (retval) |
@@ -115,7 +115,7 @@ static ssize_t arvo_sysfs_set_key_mask(struct device *dev, | |||
115 | temp_buf.key_mask = key_mask; | 115 | temp_buf.key_mask = key_mask; |
116 | 116 | ||
117 | mutex_lock(&arvo->arvo_lock); | 117 | mutex_lock(&arvo->arvo_lock); |
118 | retval = roccat_common_send(usb_dev, ARVO_COMMAND_KEY_MASK, | 118 | retval = roccat_common2_send(usb_dev, ARVO_COMMAND_KEY_MASK, |
119 | &temp_buf, sizeof(struct arvo_key_mask)); | 119 | &temp_buf, sizeof(struct arvo_key_mask)); |
120 | mutex_unlock(&arvo->arvo_lock); | 120 | mutex_unlock(&arvo->arvo_lock); |
121 | if (retval) | 121 | if (retval) |
@@ -130,7 +130,7 @@ static int arvo_get_actual_profile(struct usb_device *usb_dev) | |||
130 | struct arvo_actual_profile temp_buf; | 130 | struct arvo_actual_profile temp_buf; |
131 | int retval; | 131 | int retval; |
132 | 132 | ||
133 | retval = roccat_common_receive(usb_dev, ARVO_COMMAND_ACTUAL_PROFILE, | 133 | retval = roccat_common2_receive(usb_dev, ARVO_COMMAND_ACTUAL_PROFILE, |
134 | &temp_buf, sizeof(struct arvo_actual_profile)); | 134 | &temp_buf, sizeof(struct arvo_actual_profile)); |
135 | 135 | ||
136 | if (retval) | 136 | if (retval) |
@@ -170,7 +170,7 @@ static ssize_t arvo_sysfs_set_actual_profile(struct device *dev, | |||
170 | temp_buf.actual_profile = profile; | 170 | temp_buf.actual_profile = profile; |
171 | 171 | ||
172 | mutex_lock(&arvo->arvo_lock); | 172 | mutex_lock(&arvo->arvo_lock); |
173 | retval = roccat_common_send(usb_dev, ARVO_COMMAND_ACTUAL_PROFILE, | 173 | retval = roccat_common2_send(usb_dev, ARVO_COMMAND_ACTUAL_PROFILE, |
174 | &temp_buf, sizeof(struct arvo_actual_profile)); | 174 | &temp_buf, sizeof(struct arvo_actual_profile)); |
175 | if (!retval) { | 175 | if (!retval) { |
176 | arvo->actual_profile = profile; | 176 | arvo->actual_profile = profile; |
@@ -194,7 +194,7 @@ static ssize_t arvo_sysfs_write(struct file *fp, | |||
194 | return -EINVAL; | 194 | return -EINVAL; |
195 | 195 | ||
196 | mutex_lock(&arvo->arvo_lock); | 196 | mutex_lock(&arvo->arvo_lock); |
197 | retval = roccat_common_send(usb_dev, command, buf, real_size); | 197 | retval = roccat_common2_send(usb_dev, command, buf, real_size); |
198 | mutex_unlock(&arvo->arvo_lock); | 198 | mutex_unlock(&arvo->arvo_lock); |
199 | 199 | ||
200 | return (retval ? retval : real_size); | 200 | return (retval ? retval : real_size); |
@@ -217,7 +217,7 @@ static ssize_t arvo_sysfs_read(struct file *fp, | |||
217 | return -EINVAL; | 217 | return -EINVAL; |
218 | 218 | ||
219 | mutex_lock(&arvo->arvo_lock); | 219 | mutex_lock(&arvo->arvo_lock); |
220 | retval = roccat_common_receive(usb_dev, command, buf, real_size); | 220 | retval = roccat_common2_receive(usb_dev, command, buf, real_size); |
221 | mutex_unlock(&arvo->arvo_lock); | 221 | mutex_unlock(&arvo->arvo_lock); |
222 | 222 | ||
223 | return (retval ? retval : real_size); | 223 | return (retval ? retval : real_size); |
diff --git a/drivers/hid/hid-roccat-common.c b/drivers/hid/hid-roccat-common.c index a6d93992c75a..74f704032627 100644 --- a/drivers/hid/hid-roccat-common.c +++ b/drivers/hid/hid-roccat-common.c | |||
@@ -16,12 +16,12 @@ | |||
16 | #include <linux/module.h> | 16 | #include <linux/module.h> |
17 | #include "hid-roccat-common.h" | 17 | #include "hid-roccat-common.h" |
18 | 18 | ||
19 | static inline uint16_t roccat_common_feature_report(uint8_t report_id) | 19 | static inline uint16_t roccat_common2_feature_report(uint8_t report_id) |
20 | { | 20 | { |
21 | return 0x300 | report_id; | 21 | return 0x300 | report_id; |
22 | } | 22 | } |
23 | 23 | ||
24 | int roccat_common_receive(struct usb_device *usb_dev, uint report_id, | 24 | int roccat_common2_receive(struct usb_device *usb_dev, uint report_id, |
25 | void *data, uint size) | 25 | void *data, uint size) |
26 | { | 26 | { |
27 | char *buf; | 27 | char *buf; |
@@ -34,16 +34,16 @@ int roccat_common_receive(struct usb_device *usb_dev, uint report_id, | |||
34 | len = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0), | 34 | len = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0), |
35 | HID_REQ_GET_REPORT, | 35 | HID_REQ_GET_REPORT, |
36 | USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN, | 36 | USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN, |
37 | roccat_common_feature_report(report_id), | 37 | roccat_common2_feature_report(report_id), |
38 | 0, buf, size, USB_CTRL_SET_TIMEOUT); | 38 | 0, buf, size, USB_CTRL_SET_TIMEOUT); |
39 | 39 | ||
40 | memcpy(data, buf, size); | 40 | memcpy(data, buf, size); |
41 | kfree(buf); | 41 | kfree(buf); |
42 | return ((len < 0) ? len : ((len != size) ? -EIO : 0)); | 42 | return ((len < 0) ? len : ((len != size) ? -EIO : 0)); |
43 | } | 43 | } |
44 | EXPORT_SYMBOL_GPL(roccat_common_receive); | 44 | EXPORT_SYMBOL_GPL(roccat_common2_receive); |
45 | 45 | ||
46 | int roccat_common_send(struct usb_device *usb_dev, uint report_id, | 46 | int roccat_common2_send(struct usb_device *usb_dev, uint report_id, |
47 | void const *data, uint size) | 47 | void const *data, uint size) |
48 | { | 48 | { |
49 | char *buf; | 49 | char *buf; |
@@ -56,13 +56,71 @@ int roccat_common_send(struct usb_device *usb_dev, uint report_id, | |||
56 | len = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0), | 56 | len = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0), |
57 | HID_REQ_SET_REPORT, | 57 | HID_REQ_SET_REPORT, |
58 | USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT, | 58 | USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT, |
59 | roccat_common_feature_report(report_id), | 59 | roccat_common2_feature_report(report_id), |
60 | 0, buf, size, USB_CTRL_SET_TIMEOUT); | 60 | 0, buf, size, USB_CTRL_SET_TIMEOUT); |
61 | 61 | ||
62 | kfree(buf); | 62 | kfree(buf); |
63 | return ((len < 0) ? len : ((len != size) ? -EIO : 0)); | 63 | return ((len < 0) ? len : ((len != size) ? -EIO : 0)); |
64 | } | 64 | } |
65 | EXPORT_SYMBOL_GPL(roccat_common_send); | 65 | EXPORT_SYMBOL_GPL(roccat_common2_send); |
66 | |||
67 | enum roccat_common2_control_states { | ||
68 | ROCCAT_COMMON_CONTROL_STATUS_OVERLOAD = 0, | ||
69 | ROCCAT_COMMON_CONTROL_STATUS_OK = 1, | ||
70 | ROCCAT_COMMON_CONTROL_STATUS_INVALID = 2, | ||
71 | ROCCAT_COMMON_CONTROL_STATUS_WAIT = 3, | ||
72 | }; | ||
73 | |||
74 | static int roccat_common2_receive_control_status(struct usb_device *usb_dev) | ||
75 | { | ||
76 | int retval; | ||
77 | struct roccat_common2_control control; | ||
78 | |||
79 | do { | ||
80 | msleep(50); | ||
81 | retval = roccat_common2_receive(usb_dev, | ||
82 | ROCCAT_COMMON_COMMAND_CONTROL, | ||
83 | &control, sizeof(struct roccat_common2_control)); | ||
84 | |||
85 | if (retval) | ||
86 | return retval; | ||
87 | |||
88 | switch (control.value) { | ||
89 | case ROCCAT_COMMON_CONTROL_STATUS_OK: | ||
90 | return 0; | ||
91 | case ROCCAT_COMMON_CONTROL_STATUS_WAIT: | ||
92 | msleep(500); | ||
93 | continue; | ||
94 | case ROCCAT_COMMON_CONTROL_STATUS_INVALID: | ||
95 | |||
96 | case ROCCAT_COMMON_CONTROL_STATUS_OVERLOAD: | ||
97 | /* seems to be critical - replug necessary */ | ||
98 | return -EINVAL; | ||
99 | default: | ||
100 | dev_err(&usb_dev->dev, | ||
101 | "roccat_common2_receive_control_status: " | ||
102 | "unknown response value 0x%x\n", | ||
103 | control.value); | ||
104 | return -EINVAL; | ||
105 | } | ||
106 | |||
107 | } while (1); | ||
108 | } | ||
109 | |||
110 | int roccat_common2_send_with_status(struct usb_device *usb_dev, | ||
111 | uint command, void const *buf, uint size) | ||
112 | { | ||
113 | int retval; | ||
114 | |||
115 | retval = roccat_common2_send(usb_dev, command, buf, size); | ||
116 | if (retval) | ||
117 | return retval; | ||
118 | |||
119 | msleep(100); | ||
120 | |||
121 | return roccat_common2_receive_control_status(usb_dev); | ||
122 | } | ||
123 | EXPORT_SYMBOL_GPL(roccat_common2_send_with_status); | ||
66 | 124 | ||
67 | MODULE_AUTHOR("Stefan Achatz"); | 125 | MODULE_AUTHOR("Stefan Achatz"); |
68 | MODULE_DESCRIPTION("USB Roccat common driver"); | 126 | MODULE_DESCRIPTION("USB Roccat common driver"); |
diff --git a/drivers/hid/hid-roccat-common.h b/drivers/hid/hid-roccat-common.h index 9a5bc61f9699..a97746a63b70 100644 --- a/drivers/hid/hid-roccat-common.h +++ b/drivers/hid/hid-roccat-common.h | |||
@@ -15,9 +15,21 @@ | |||
15 | #include <linux/usb.h> | 15 | #include <linux/usb.h> |
16 | #include <linux/types.h> | 16 | #include <linux/types.h> |
17 | 17 | ||
18 | int roccat_common_receive(struct usb_device *usb_dev, uint report_id, | 18 | enum roccat_common2_commands { |
19 | ROCCAT_COMMON_COMMAND_CONTROL = 0x4, | ||
20 | }; | ||
21 | |||
22 | struct roccat_common2_control { | ||
23 | uint8_t command; | ||
24 | uint8_t value; | ||
25 | uint8_t request; /* always 0 on requesting write check */ | ||
26 | } __packed; | ||
27 | |||
28 | int roccat_common2_receive(struct usb_device *usb_dev, uint report_id, | ||
19 | void *data, uint size); | 29 | void *data, uint size); |
20 | int roccat_common_send(struct usb_device *usb_dev, uint report_id, | 30 | int roccat_common2_send(struct usb_device *usb_dev, uint report_id, |
21 | void const *data, uint size); | 31 | void const *data, uint size); |
32 | int roccat_common2_send_with_status(struct usb_device *usb_dev, | ||
33 | uint command, void const *buf, uint size); | ||
22 | 34 | ||
23 | #endif | 35 | #endif |
diff --git a/drivers/hid/hid-roccat-isku.c b/drivers/hid/hid-roccat-isku.c index 0e4a0ab47142..5669916c2943 100644 --- a/drivers/hid/hid-roccat-isku.c +++ b/drivers/hid/hid-roccat-isku.c | |||
@@ -36,51 +36,7 @@ static void isku_profile_activated(struct isku_device *isku, uint new_profile) | |||
36 | static int isku_receive(struct usb_device *usb_dev, uint command, | 36 | static int isku_receive(struct usb_device *usb_dev, uint command, |
37 | void *buf, uint size) | 37 | void *buf, uint size) |
38 | { | 38 | { |
39 | return roccat_common_receive(usb_dev, command, buf, size); | 39 | return roccat_common2_receive(usb_dev, command, buf, size); |
40 | } | ||
41 | |||
42 | static int isku_receive_control_status(struct usb_device *usb_dev) | ||
43 | { | ||
44 | int retval; | ||
45 | struct isku_control control; | ||
46 | |||
47 | do { | ||
48 | msleep(50); | ||
49 | retval = isku_receive(usb_dev, ISKU_COMMAND_CONTROL, | ||
50 | &control, sizeof(struct isku_control)); | ||
51 | |||
52 | if (retval) | ||
53 | return retval; | ||
54 | |||
55 | switch (control.value) { | ||
56 | case ISKU_CONTROL_VALUE_STATUS_OK: | ||
57 | return 0; | ||
58 | case ISKU_CONTROL_VALUE_STATUS_WAIT: | ||
59 | continue; | ||
60 | case ISKU_CONTROL_VALUE_STATUS_INVALID: | ||
61 | /* seems to be critical - replug necessary */ | ||
62 | case ISKU_CONTROL_VALUE_STATUS_OVERLOAD: | ||
63 | return -EINVAL; | ||
64 | default: | ||
65 | hid_err(usb_dev, "isku_receive_control_status: " | ||
66 | "unknown response value 0x%x\n", | ||
67 | control.value); | ||
68 | return -EINVAL; | ||
69 | } | ||
70 | |||
71 | } while (1); | ||
72 | } | ||
73 | |||
74 | static int isku_send(struct usb_device *usb_dev, uint command, | ||
75 | void const *buf, uint size) | ||
76 | { | ||
77 | int retval; | ||
78 | |||
79 | retval = roccat_common_send(usb_dev, command, buf, size); | ||
80 | if (retval) | ||
81 | return retval; | ||
82 | |||
83 | return isku_receive_control_status(usb_dev); | ||
84 | } | 40 | } |
85 | 41 | ||
86 | static int isku_get_actual_profile(struct usb_device *usb_dev) | 42 | static int isku_get_actual_profile(struct usb_device *usb_dev) |
@@ -100,7 +56,8 @@ static int isku_set_actual_profile(struct usb_device *usb_dev, int new_profile) | |||
100 | buf.command = ISKU_COMMAND_ACTUAL_PROFILE; | 56 | buf.command = ISKU_COMMAND_ACTUAL_PROFILE; |
101 | buf.size = sizeof(struct isku_actual_profile); | 57 | buf.size = sizeof(struct isku_actual_profile); |
102 | buf.actual_profile = new_profile; | 58 | buf.actual_profile = new_profile; |
103 | return isku_send(usb_dev, ISKU_COMMAND_ACTUAL_PROFILE, &buf, | 59 | return roccat_common2_send_with_status(usb_dev, |
60 | ISKU_COMMAND_ACTUAL_PROFILE, &buf, | ||
104 | sizeof(struct isku_actual_profile)); | 61 | sizeof(struct isku_actual_profile)); |
105 | } | 62 | } |
106 | 63 | ||
@@ -197,7 +154,8 @@ static ssize_t isku_sysfs_write(struct file *fp, struct kobject *kobj, | |||
197 | return -EINVAL; | 154 | return -EINVAL; |
198 | 155 | ||
199 | mutex_lock(&isku->isku_lock); | 156 | mutex_lock(&isku->isku_lock); |
200 | retval = isku_send(usb_dev, command, (void *)buf, real_size); | 157 | retval = roccat_common2_send_with_status(usb_dev, command, |
158 | (void *)buf, real_size); | ||
201 | mutex_unlock(&isku->isku_lock); | 159 | mutex_unlock(&isku->isku_lock); |
202 | 160 | ||
203 | return retval ? retval : real_size; | 161 | return retval ? retval : real_size; |
diff --git a/drivers/hid/hid-roccat-isku.h b/drivers/hid/hid-roccat-isku.h index 075f6efaec58..605b3ce21638 100644 --- a/drivers/hid/hid-roccat-isku.h +++ b/drivers/hid/hid-roccat-isku.h | |||
@@ -25,13 +25,6 @@ struct isku_control { | |||
25 | uint8_t request; | 25 | uint8_t request; |
26 | } __packed; | 26 | } __packed; |
27 | 27 | ||
28 | enum isku_control_values { | ||
29 | ISKU_CONTROL_VALUE_STATUS_OVERLOAD = 0, | ||
30 | ISKU_CONTROL_VALUE_STATUS_OK = 1, | ||
31 | ISKU_CONTROL_VALUE_STATUS_INVALID = 2, | ||
32 | ISKU_CONTROL_VALUE_STATUS_WAIT = 3, | ||
33 | }; | ||
34 | |||
35 | struct isku_actual_profile { | 28 | struct isku_actual_profile { |
36 | uint8_t command; /* ISKU_COMMAND_ACTUAL_PROFILE */ | 29 | uint8_t command; /* ISKU_COMMAND_ACTUAL_PROFILE */ |
37 | uint8_t size; /* always 3 */ | 30 | uint8_t size; /* always 3 */ |
diff --git a/drivers/hid/hid-roccat-kone.c b/drivers/hid/hid-roccat-kone.c index 40090d602158..9ce2d0b615a4 100644 --- a/drivers/hid/hid-roccat-kone.c +++ b/drivers/hid/hid-roccat-kone.c | |||
@@ -138,7 +138,7 @@ static int kone_check_write(struct usb_device *usb_dev) | |||
138 | return 0; | 138 | return 0; |
139 | 139 | ||
140 | /* unknown answer */ | 140 | /* unknown answer */ |
141 | hid_err(usb_dev, "got retval %d when checking write\n", data); | 141 | dev_err(&usb_dev->dev, "got retval %d when checking write\n", data); |
142 | return -EIO; | 142 | return -EIO; |
143 | } | 143 | } |
144 | 144 | ||
@@ -503,7 +503,7 @@ static ssize_t kone_sysfs_set_tcu(struct device *dev, | |||
503 | 503 | ||
504 | retval = kone_set_settings(usb_dev, &kone->settings); | 504 | retval = kone_set_settings(usb_dev, &kone->settings); |
505 | if (retval) { | 505 | if (retval) { |
506 | hid_err(usb_dev, "couldn't set tcu state\n"); | 506 | dev_err(&usb_dev->dev, "couldn't set tcu state\n"); |
507 | /* | 507 | /* |
508 | * try to reread valid settings into buffer overwriting | 508 | * try to reread valid settings into buffer overwriting |
509 | * first error code | 509 | * first error code |
@@ -519,7 +519,7 @@ static ssize_t kone_sysfs_set_tcu(struct device *dev, | |||
519 | 519 | ||
520 | retval = size; | 520 | retval = size; |
521 | exit_no_settings: | 521 | exit_no_settings: |
522 | hid_err(usb_dev, "couldn't read settings\n"); | 522 | dev_err(&usb_dev->dev, "couldn't read settings\n"); |
523 | exit_unlock: | 523 | exit_unlock: |
524 | mutex_unlock(&kone->kone_lock); | 524 | mutex_unlock(&kone->kone_lock); |
525 | return retval; | 525 | return retval; |
diff --git a/drivers/hid/hid-roccat-koneplus.c b/drivers/hid/hid-roccat-koneplus.c index 59e47770fa10..f5602fec4865 100644 --- a/drivers/hid/hid-roccat-koneplus.c +++ b/drivers/hid/hid-roccat-koneplus.c | |||
@@ -39,88 +39,26 @@ static void koneplus_profile_activated(struct koneplus_device *koneplus, | |||
39 | static int koneplus_send_control(struct usb_device *usb_dev, uint value, | 39 | static int koneplus_send_control(struct usb_device *usb_dev, uint value, |
40 | enum koneplus_control_requests request) | 40 | enum koneplus_control_requests request) |
41 | { | 41 | { |
42 | struct koneplus_control control; | 42 | struct roccat_common2_control control; |
43 | 43 | ||
44 | if ((request == KONEPLUS_CONTROL_REQUEST_PROFILE_SETTINGS || | 44 | if ((request == KONEPLUS_CONTROL_REQUEST_PROFILE_SETTINGS || |
45 | request == KONEPLUS_CONTROL_REQUEST_PROFILE_BUTTONS) && | 45 | request == KONEPLUS_CONTROL_REQUEST_PROFILE_BUTTONS) && |
46 | value > 4) | 46 | value > 4) |
47 | return -EINVAL; | 47 | return -EINVAL; |
48 | 48 | ||
49 | control.command = KONEPLUS_COMMAND_CONTROL; | 49 | control.command = ROCCAT_COMMON_COMMAND_CONTROL; |
50 | control.value = value; | 50 | control.value = value; |
51 | control.request = request; | 51 | control.request = request; |
52 | 52 | ||
53 | return roccat_common_send(usb_dev, KONEPLUS_COMMAND_CONTROL, | 53 | return roccat_common2_send_with_status(usb_dev, |
54 | &control, sizeof(struct koneplus_control)); | 54 | ROCCAT_COMMON_COMMAND_CONTROL, |
55 | } | 55 | &control, sizeof(struct roccat_common2_control)); |
56 | |||
57 | static int koneplus_receive_control_status(struct usb_device *usb_dev) | ||
58 | { | ||
59 | int retval; | ||
60 | struct koneplus_control control; | ||
61 | |||
62 | do { | ||
63 | retval = roccat_common_receive(usb_dev, KONEPLUS_COMMAND_CONTROL, | ||
64 | &control, sizeof(struct koneplus_control)); | ||
65 | |||
66 | /* check if we get a completely wrong answer */ | ||
67 | if (retval) | ||
68 | return retval; | ||
69 | |||
70 | if (control.value == KONEPLUS_CONTROL_REQUEST_STATUS_OK) | ||
71 | return 0; | ||
72 | |||
73 | /* indicates that hardware needs some more time to complete action */ | ||
74 | if (control.value == KONEPLUS_CONTROL_REQUEST_STATUS_WAIT) { | ||
75 | msleep(500); /* windows driver uses 1000 */ | ||
76 | continue; | ||
77 | } | ||
78 | |||
79 | /* seems to be critical - replug necessary */ | ||
80 | if (control.value == KONEPLUS_CONTROL_REQUEST_STATUS_OVERLOAD) | ||
81 | return -EINVAL; | ||
82 | |||
83 | hid_err(usb_dev, "koneplus_receive_control_status: " | ||
84 | "unknown response value 0x%x\n", control.value); | ||
85 | return -EINVAL; | ||
86 | } while (1); | ||
87 | } | ||
88 | |||
89 | static int koneplus_send(struct usb_device *usb_dev, uint command, | ||
90 | void const *buf, uint size) | ||
91 | { | ||
92 | int retval; | ||
93 | |||
94 | retval = roccat_common_send(usb_dev, command, buf, size); | ||
95 | if (retval) | ||
96 | return retval; | ||
97 | |||
98 | return koneplus_receive_control_status(usb_dev); | ||
99 | } | ||
100 | |||
101 | static int koneplus_select_profile(struct usb_device *usb_dev, uint number, | ||
102 | enum koneplus_control_requests request) | ||
103 | { | ||
104 | int retval; | ||
105 | |||
106 | retval = koneplus_send_control(usb_dev, number, request); | ||
107 | if (retval) | ||
108 | return retval; | ||
109 | |||
110 | /* allow time to settle things - windows driver uses 500 */ | ||
111 | msleep(100); | ||
112 | |||
113 | retval = koneplus_receive_control_status(usb_dev); | ||
114 | if (retval) | ||
115 | return retval; | ||
116 | |||
117 | return 0; | ||
118 | } | 56 | } |
119 | 57 | ||
120 | static int koneplus_get_info(struct usb_device *usb_dev, | 58 | static int koneplus_get_info(struct usb_device *usb_dev, |
121 | struct koneplus_info *buf) | 59 | struct koneplus_info *buf) |
122 | { | 60 | { |
123 | return roccat_common_receive(usb_dev, KONEPLUS_COMMAND_INFO, | 61 | return roccat_common2_receive(usb_dev, KONEPLUS_COMMAND_INFO, |
124 | buf, sizeof(struct koneplus_info)); | 62 | buf, sizeof(struct koneplus_info)); |
125 | } | 63 | } |
126 | 64 | ||
@@ -129,19 +67,20 @@ static int koneplus_get_profile_settings(struct usb_device *usb_dev, | |||
129 | { | 67 | { |
130 | int retval; | 68 | int retval; |
131 | 69 | ||
132 | retval = koneplus_select_profile(usb_dev, number, | 70 | retval = koneplus_send_control(usb_dev, number, |
133 | KONEPLUS_CONTROL_REQUEST_PROFILE_SETTINGS); | 71 | KONEPLUS_CONTROL_REQUEST_PROFILE_SETTINGS); |
134 | if (retval) | 72 | if (retval) |
135 | return retval; | 73 | return retval; |
136 | 74 | ||
137 | return roccat_common_receive(usb_dev, KONEPLUS_COMMAND_PROFILE_SETTINGS, | 75 | return roccat_common2_receive(usb_dev, KONEPLUS_COMMAND_PROFILE_SETTINGS, |
138 | buf, sizeof(struct koneplus_profile_settings)); | 76 | buf, sizeof(struct koneplus_profile_settings)); |
139 | } | 77 | } |
140 | 78 | ||
141 | static int koneplus_set_profile_settings(struct usb_device *usb_dev, | 79 | static int koneplus_set_profile_settings(struct usb_device *usb_dev, |
142 | struct koneplus_profile_settings const *settings) | 80 | struct koneplus_profile_settings const *settings) |
143 | { | 81 | { |
144 | return koneplus_send(usb_dev, KONEPLUS_COMMAND_PROFILE_SETTINGS, | 82 | return roccat_common2_send_with_status(usb_dev, |
83 | KONEPLUS_COMMAND_PROFILE_SETTINGS, | ||
145 | settings, sizeof(struct koneplus_profile_settings)); | 84 | settings, sizeof(struct koneplus_profile_settings)); |
146 | } | 85 | } |
147 | 86 | ||
@@ -150,19 +89,20 @@ static int koneplus_get_profile_buttons(struct usb_device *usb_dev, | |||
150 | { | 89 | { |
151 | int retval; | 90 | int retval; |
152 | 91 | ||
153 | retval = koneplus_select_profile(usb_dev, number, | 92 | retval = koneplus_send_control(usb_dev, number, |
154 | KONEPLUS_CONTROL_REQUEST_PROFILE_BUTTONS); | 93 | KONEPLUS_CONTROL_REQUEST_PROFILE_BUTTONS); |
155 | if (retval) | 94 | if (retval) |
156 | return retval; | 95 | return retval; |
157 | 96 | ||
158 | return roccat_common_receive(usb_dev, KONEPLUS_COMMAND_PROFILE_BUTTONS, | 97 | return roccat_common2_receive(usb_dev, KONEPLUS_COMMAND_PROFILE_BUTTONS, |
159 | buf, sizeof(struct koneplus_profile_buttons)); | 98 | buf, sizeof(struct koneplus_profile_buttons)); |
160 | } | 99 | } |
161 | 100 | ||
162 | static int koneplus_set_profile_buttons(struct usb_device *usb_dev, | 101 | static int koneplus_set_profile_buttons(struct usb_device *usb_dev, |
163 | struct koneplus_profile_buttons const *buttons) | 102 | struct koneplus_profile_buttons const *buttons) |
164 | { | 103 | { |
165 | return koneplus_send(usb_dev, KONEPLUS_COMMAND_PROFILE_BUTTONS, | 104 | return roccat_common2_send_with_status(usb_dev, |
105 | KONEPLUS_COMMAND_PROFILE_BUTTONS, | ||
166 | buttons, sizeof(struct koneplus_profile_buttons)); | 106 | buttons, sizeof(struct koneplus_profile_buttons)); |
167 | } | 107 | } |
168 | 108 | ||
@@ -172,7 +112,7 @@ static int koneplus_get_actual_profile(struct usb_device *usb_dev) | |||
172 | struct koneplus_actual_profile buf; | 112 | struct koneplus_actual_profile buf; |
173 | int retval; | 113 | int retval; |
174 | 114 | ||
175 | retval = roccat_common_receive(usb_dev, KONEPLUS_COMMAND_ACTUAL_PROFILE, | 115 | retval = roccat_common2_receive(usb_dev, KONEPLUS_COMMAND_ACTUAL_PROFILE, |
176 | &buf, sizeof(struct koneplus_actual_profile)); | 116 | &buf, sizeof(struct koneplus_actual_profile)); |
177 | 117 | ||
178 | return retval ? retval : buf.actual_profile; | 118 | return retval ? retval : buf.actual_profile; |
@@ -187,7 +127,8 @@ static int koneplus_set_actual_profile(struct usb_device *usb_dev, | |||
187 | buf.size = sizeof(struct koneplus_actual_profile); | 127 | buf.size = sizeof(struct koneplus_actual_profile); |
188 | buf.actual_profile = new_profile; | 128 | buf.actual_profile = new_profile; |
189 | 129 | ||
190 | return koneplus_send(usb_dev, KONEPLUS_COMMAND_ACTUAL_PROFILE, | 130 | return roccat_common2_send_with_status(usb_dev, |
131 | KONEPLUS_COMMAND_ACTUAL_PROFILE, | ||
191 | &buf, sizeof(struct koneplus_actual_profile)); | 132 | &buf, sizeof(struct koneplus_actual_profile)); |
192 | } | 133 | } |
193 | 134 | ||
@@ -208,7 +149,7 @@ static ssize_t koneplus_sysfs_read(struct file *fp, struct kobject *kobj, | |||
208 | return -EINVAL; | 149 | return -EINVAL; |
209 | 150 | ||
210 | mutex_lock(&koneplus->koneplus_lock); | 151 | mutex_lock(&koneplus->koneplus_lock); |
211 | retval = roccat_common_receive(usb_dev, command, buf, real_size); | 152 | retval = roccat_common2_receive(usb_dev, command, buf, real_size); |
212 | mutex_unlock(&koneplus->koneplus_lock); | 153 | mutex_unlock(&koneplus->koneplus_lock); |
213 | 154 | ||
214 | if (retval) | 155 | if (retval) |
@@ -231,7 +172,8 @@ static ssize_t koneplus_sysfs_write(struct file *fp, struct kobject *kobj, | |||
231 | return -EINVAL; | 172 | return -EINVAL; |
232 | 173 | ||
233 | mutex_lock(&koneplus->koneplus_lock); | 174 | mutex_lock(&koneplus->koneplus_lock); |
234 | retval = koneplus_send(usb_dev, command, buf, real_size); | 175 | retval = roccat_common2_send_with_status(usb_dev, command, |
176 | buf, real_size); | ||
235 | mutex_unlock(&koneplus->koneplus_lock); | 177 | mutex_unlock(&koneplus->koneplus_lock); |
236 | 178 | ||
237 | if (retval) | 179 | if (retval) |
diff --git a/drivers/hid/hid-roccat-koneplus.h b/drivers/hid/hid-roccat-koneplus.h index c03332a4fa9a..7074b2a4b94b 100644 --- a/drivers/hid/hid-roccat-koneplus.h +++ b/drivers/hid/hid-roccat-koneplus.h | |||
@@ -20,32 +20,11 @@ struct koneplus_talk { | |||
20 | uint8_t data[14]; | 20 | uint8_t data[14]; |
21 | } __packed; | 21 | } __packed; |
22 | 22 | ||
23 | /* | ||
24 | * case 1: writes request 80 and reads value 1 | ||
25 | * | ||
26 | */ | ||
27 | struct koneplus_control { | ||
28 | uint8_t command; /* KONEPLUS_COMMAND_CONTROL */ | ||
29 | /* | ||
30 | * value is profile number in range 0-4 for requesting settings and buttons | ||
31 | * 1 if status ok for requesting status | ||
32 | */ | ||
33 | uint8_t value; | ||
34 | uint8_t request; | ||
35 | } __attribute__ ((__packed__)); | ||
36 | |||
37 | enum koneplus_control_requests { | 23 | enum koneplus_control_requests { |
38 | KONEPLUS_CONTROL_REQUEST_STATUS = 0x00, | ||
39 | KONEPLUS_CONTROL_REQUEST_PROFILE_SETTINGS = 0x80, | 24 | KONEPLUS_CONTROL_REQUEST_PROFILE_SETTINGS = 0x80, |
40 | KONEPLUS_CONTROL_REQUEST_PROFILE_BUTTONS = 0x90, | 25 | KONEPLUS_CONTROL_REQUEST_PROFILE_BUTTONS = 0x90, |
41 | }; | 26 | }; |
42 | 27 | ||
43 | enum koneplus_control_values { | ||
44 | KONEPLUS_CONTROL_REQUEST_STATUS_OVERLOAD = 0, | ||
45 | KONEPLUS_CONTROL_REQUEST_STATUS_OK = 1, | ||
46 | KONEPLUS_CONTROL_REQUEST_STATUS_WAIT = 3, | ||
47 | }; | ||
48 | |||
49 | struct koneplus_actual_profile { | 28 | struct koneplus_actual_profile { |
50 | uint8_t command; /* KONEPLUS_COMMAND_ACTUAL_PROFILE */ | 29 | uint8_t command; /* KONEPLUS_COMMAND_ACTUAL_PROFILE */ |
51 | uint8_t size; /* always 3 */ | 30 | uint8_t size; /* always 3 */ |
@@ -137,7 +116,6 @@ struct koneplus_tcu_image { | |||
137 | } __attribute__ ((__packed__)); | 116 | } __attribute__ ((__packed__)); |
138 | 117 | ||
139 | enum koneplus_commands { | 118 | enum koneplus_commands { |
140 | KONEPLUS_COMMAND_CONTROL = 0x4, | ||
141 | KONEPLUS_COMMAND_ACTUAL_PROFILE = 0x5, | 119 | KONEPLUS_COMMAND_ACTUAL_PROFILE = 0x5, |
142 | KONEPLUS_COMMAND_PROFILE_SETTINGS = 0x6, | 120 | KONEPLUS_COMMAND_PROFILE_SETTINGS = 0x6, |
143 | KONEPLUS_COMMAND_PROFILE_BUTTONS = 0x7, | 121 | KONEPLUS_COMMAND_PROFILE_BUTTONS = 0x7, |
diff --git a/drivers/hid/hid-roccat-kovaplus.c b/drivers/hid/hid-roccat-kovaplus.c index 112d934132c8..ca6527ac655d 100644 --- a/drivers/hid/hid-roccat-kovaplus.c +++ b/drivers/hid/hid-roccat-kovaplus.c | |||
@@ -47,69 +47,23 @@ static int kovaplus_send_control(struct usb_device *usb_dev, uint value, | |||
47 | enum kovaplus_control_requests request) | 47 | enum kovaplus_control_requests request) |
48 | { | 48 | { |
49 | int retval; | 49 | int retval; |
50 | struct kovaplus_control control; | 50 | struct roccat_common2_control control; |
51 | 51 | ||
52 | if ((request == KOVAPLUS_CONTROL_REQUEST_PROFILE_SETTINGS || | 52 | if ((request == KOVAPLUS_CONTROL_REQUEST_PROFILE_SETTINGS || |
53 | request == KOVAPLUS_CONTROL_REQUEST_PROFILE_BUTTONS) && | 53 | request == KOVAPLUS_CONTROL_REQUEST_PROFILE_BUTTONS) && |
54 | value > 4) | 54 | value > 4) |
55 | return -EINVAL; | 55 | return -EINVAL; |
56 | 56 | ||
57 | control.command = KOVAPLUS_COMMAND_CONTROL; | 57 | control.command = ROCCAT_COMMON_COMMAND_CONTROL; |
58 | control.value = value; | 58 | control.value = value; |
59 | control.request = request; | 59 | control.request = request; |
60 | 60 | ||
61 | retval = roccat_common_send(usb_dev, KOVAPLUS_COMMAND_CONTROL, | 61 | retval = roccat_common2_send(usb_dev, ROCCAT_COMMON_COMMAND_CONTROL, |
62 | &control, sizeof(struct kovaplus_control)); | 62 | &control, sizeof(struct roccat_common2_control)); |
63 | 63 | ||
64 | return retval; | 64 | return retval; |
65 | } | 65 | } |
66 | 66 | ||
67 | static int kovaplus_receive_control_status(struct usb_device *usb_dev) | ||
68 | { | ||
69 | int retval; | ||
70 | struct kovaplus_control control; | ||
71 | |||
72 | do { | ||
73 | retval = roccat_common_receive(usb_dev, KOVAPLUS_COMMAND_CONTROL, | ||
74 | &control, sizeof(struct kovaplus_control)); | ||
75 | |||
76 | /* check if we get a completely wrong answer */ | ||
77 | if (retval) | ||
78 | return retval; | ||
79 | |||
80 | if (control.value == KOVAPLUS_CONTROL_REQUEST_STATUS_OK) | ||
81 | return 0; | ||
82 | |||
83 | /* indicates that hardware needs some more time to complete action */ | ||
84 | if (control.value == KOVAPLUS_CONTROL_REQUEST_STATUS_WAIT) { | ||
85 | msleep(500); /* windows driver uses 1000 */ | ||
86 | continue; | ||
87 | } | ||
88 | |||
89 | /* seems to be critical - replug necessary */ | ||
90 | if (control.value == KOVAPLUS_CONTROL_REQUEST_STATUS_OVERLOAD) | ||
91 | return -EINVAL; | ||
92 | |||
93 | hid_err(usb_dev, "roccat_common_receive_control_status: " | ||
94 | "unknown response value 0x%x\n", control.value); | ||
95 | return -EINVAL; | ||
96 | } while (1); | ||
97 | } | ||
98 | |||
99 | static int kovaplus_send(struct usb_device *usb_dev, uint command, | ||
100 | void const *buf, uint size) | ||
101 | { | ||
102 | int retval; | ||
103 | |||
104 | retval = roccat_common_send(usb_dev, command, buf, size); | ||
105 | if (retval) | ||
106 | return retval; | ||
107 | |||
108 | msleep(100); | ||
109 | |||
110 | return kovaplus_receive_control_status(usb_dev); | ||
111 | } | ||
112 | |||
113 | static int kovaplus_select_profile(struct usb_device *usb_dev, uint number, | 67 | static int kovaplus_select_profile(struct usb_device *usb_dev, uint number, |
114 | enum kovaplus_control_requests request) | 68 | enum kovaplus_control_requests request) |
115 | { | 69 | { |
@@ -119,7 +73,7 @@ static int kovaplus_select_profile(struct usb_device *usb_dev, uint number, | |||
119 | static int kovaplus_get_info(struct usb_device *usb_dev, | 73 | static int kovaplus_get_info(struct usb_device *usb_dev, |
120 | struct kovaplus_info *buf) | 74 | struct kovaplus_info *buf) |
121 | { | 75 | { |
122 | return roccat_common_receive(usb_dev, KOVAPLUS_COMMAND_INFO, | 76 | return roccat_common2_receive(usb_dev, KOVAPLUS_COMMAND_INFO, |
123 | buf, sizeof(struct kovaplus_info)); | 77 | buf, sizeof(struct kovaplus_info)); |
124 | } | 78 | } |
125 | 79 | ||
@@ -133,14 +87,15 @@ static int kovaplus_get_profile_settings(struct usb_device *usb_dev, | |||
133 | if (retval) | 87 | if (retval) |
134 | return retval; | 88 | return retval; |
135 | 89 | ||
136 | return roccat_common_receive(usb_dev, KOVAPLUS_COMMAND_PROFILE_SETTINGS, | 90 | return roccat_common2_receive(usb_dev, KOVAPLUS_COMMAND_PROFILE_SETTINGS, |
137 | buf, sizeof(struct kovaplus_profile_settings)); | 91 | buf, sizeof(struct kovaplus_profile_settings)); |
138 | } | 92 | } |
139 | 93 | ||
140 | static int kovaplus_set_profile_settings(struct usb_device *usb_dev, | 94 | static int kovaplus_set_profile_settings(struct usb_device *usb_dev, |
141 | struct kovaplus_profile_settings const *settings) | 95 | struct kovaplus_profile_settings const *settings) |
142 | { | 96 | { |
143 | return kovaplus_send(usb_dev, KOVAPLUS_COMMAND_PROFILE_SETTINGS, | 97 | return roccat_common2_send_with_status(usb_dev, |
98 | KOVAPLUS_COMMAND_PROFILE_SETTINGS, | ||
144 | settings, sizeof(struct kovaplus_profile_settings)); | 99 | settings, sizeof(struct kovaplus_profile_settings)); |
145 | } | 100 | } |
146 | 101 | ||
@@ -154,14 +109,15 @@ static int kovaplus_get_profile_buttons(struct usb_device *usb_dev, | |||
154 | if (retval) | 109 | if (retval) |
155 | return retval; | 110 | return retval; |
156 | 111 | ||
157 | return roccat_common_receive(usb_dev, KOVAPLUS_COMMAND_PROFILE_BUTTONS, | 112 | return roccat_common2_receive(usb_dev, KOVAPLUS_COMMAND_PROFILE_BUTTONS, |
158 | buf, sizeof(struct kovaplus_profile_buttons)); | 113 | buf, sizeof(struct kovaplus_profile_buttons)); |
159 | } | 114 | } |
160 | 115 | ||
161 | static int kovaplus_set_profile_buttons(struct usb_device *usb_dev, | 116 | static int kovaplus_set_profile_buttons(struct usb_device *usb_dev, |
162 | struct kovaplus_profile_buttons const *buttons) | 117 | struct kovaplus_profile_buttons const *buttons) |
163 | { | 118 | { |
164 | return kovaplus_send(usb_dev, KOVAPLUS_COMMAND_PROFILE_BUTTONS, | 119 | return roccat_common2_send_with_status(usb_dev, |
120 | KOVAPLUS_COMMAND_PROFILE_BUTTONS, | ||
165 | buttons, sizeof(struct kovaplus_profile_buttons)); | 121 | buttons, sizeof(struct kovaplus_profile_buttons)); |
166 | } | 122 | } |
167 | 123 | ||
@@ -171,7 +127,7 @@ static int kovaplus_get_actual_profile(struct usb_device *usb_dev) | |||
171 | struct kovaplus_actual_profile buf; | 127 | struct kovaplus_actual_profile buf; |
172 | int retval; | 128 | int retval; |
173 | 129 | ||
174 | retval = roccat_common_receive(usb_dev, KOVAPLUS_COMMAND_ACTUAL_PROFILE, | 130 | retval = roccat_common2_receive(usb_dev, KOVAPLUS_COMMAND_ACTUAL_PROFILE, |
175 | &buf, sizeof(struct kovaplus_actual_profile)); | 131 | &buf, sizeof(struct kovaplus_actual_profile)); |
176 | 132 | ||
177 | return retval ? retval : buf.actual_profile; | 133 | return retval ? retval : buf.actual_profile; |
@@ -186,7 +142,8 @@ static int kovaplus_set_actual_profile(struct usb_device *usb_dev, | |||
186 | buf.size = sizeof(struct kovaplus_actual_profile); | 142 | buf.size = sizeof(struct kovaplus_actual_profile); |
187 | buf.actual_profile = new_profile; | 143 | buf.actual_profile = new_profile; |
188 | 144 | ||
189 | return kovaplus_send(usb_dev, KOVAPLUS_COMMAND_ACTUAL_PROFILE, | 145 | return roccat_common2_send_with_status(usb_dev, |
146 | KOVAPLUS_COMMAND_ACTUAL_PROFILE, | ||
190 | &buf, sizeof(struct kovaplus_actual_profile)); | 147 | &buf, sizeof(struct kovaplus_actual_profile)); |
191 | } | 148 | } |
192 | 149 | ||
diff --git a/drivers/hid/hid-roccat-kovaplus.h b/drivers/hid/hid-roccat-kovaplus.h index fb2aed44a8e0..f82daa1cdcb9 100644 --- a/drivers/hid/hid-roccat-kovaplus.h +++ b/drivers/hid/hid-roccat-kovaplus.h | |||
@@ -14,27 +14,13 @@ | |||
14 | 14 | ||
15 | #include <linux/types.h> | 15 | #include <linux/types.h> |
16 | 16 | ||
17 | struct kovaplus_control { | ||
18 | uint8_t command; /* KOVAPLUS_COMMAND_CONTROL */ | ||
19 | uint8_t value; | ||
20 | uint8_t request; | ||
21 | } __packed; | ||
22 | |||
23 | enum kovaplus_control_requests { | 17 | enum kovaplus_control_requests { |
24 | /* read after write; value = 1 */ | ||
25 | KOVAPLUS_CONTROL_REQUEST_STATUS = 0x0, | ||
26 | /* write; value = profile number range 0-4 */ | 18 | /* write; value = profile number range 0-4 */ |
27 | KOVAPLUS_CONTROL_REQUEST_PROFILE_SETTINGS = 0x10, | 19 | KOVAPLUS_CONTROL_REQUEST_PROFILE_SETTINGS = 0x10, |
28 | /* write; value = profile number range 0-4 */ | 20 | /* write; value = profile number range 0-4 */ |
29 | KOVAPLUS_CONTROL_REQUEST_PROFILE_BUTTONS = 0x20, | 21 | KOVAPLUS_CONTROL_REQUEST_PROFILE_BUTTONS = 0x20, |
30 | }; | 22 | }; |
31 | 23 | ||
32 | enum kovaplus_control_values { | ||
33 | KOVAPLUS_CONTROL_REQUEST_STATUS_OVERLOAD = 0, /* supposed */ | ||
34 | KOVAPLUS_CONTROL_REQUEST_STATUS_OK = 1, | ||
35 | KOVAPLUS_CONTROL_REQUEST_STATUS_WAIT = 3, /* supposed */ | ||
36 | }; | ||
37 | |||
38 | struct kovaplus_actual_profile { | 24 | struct kovaplus_actual_profile { |
39 | uint8_t command; /* KOVAPLUS_COMMAND_ACTUAL_PROFILE */ | 25 | uint8_t command; /* KOVAPLUS_COMMAND_ACTUAL_PROFILE */ |
40 | uint8_t size; /* always 3 */ | 26 | uint8_t size; /* always 3 */ |
@@ -75,7 +61,6 @@ struct kovaplus_a { | |||
75 | } __packed; | 61 | } __packed; |
76 | 62 | ||
77 | enum kovaplus_commands { | 63 | enum kovaplus_commands { |
78 | KOVAPLUS_COMMAND_CONTROL = 0x4, | ||
79 | KOVAPLUS_COMMAND_ACTUAL_PROFILE = 0x5, | 64 | KOVAPLUS_COMMAND_ACTUAL_PROFILE = 0x5, |
80 | KOVAPLUS_COMMAND_PROFILE_SETTINGS = 0x6, | 65 | KOVAPLUS_COMMAND_PROFILE_SETTINGS = 0x6, |
81 | KOVAPLUS_COMMAND_PROFILE_BUTTONS = 0x7, | 66 | KOVAPLUS_COMMAND_PROFILE_BUTTONS = 0x7, |
diff --git a/drivers/hid/hid-roccat-pyra.c b/drivers/hid/hid-roccat-pyra.c index df05c1b1064f..1317c177a3e2 100644 --- a/drivers/hid/hid-roccat-pyra.c +++ b/drivers/hid/hid-roccat-pyra.c | |||
@@ -42,43 +42,19 @@ static void profile_activated(struct pyra_device *pyra, | |||
42 | static int pyra_send_control(struct usb_device *usb_dev, int value, | 42 | static int pyra_send_control(struct usb_device *usb_dev, int value, |
43 | enum pyra_control_requests request) | 43 | enum pyra_control_requests request) |
44 | { | 44 | { |
45 | struct pyra_control control; | 45 | struct roccat_common2_control control; |
46 | 46 | ||
47 | if ((request == PYRA_CONTROL_REQUEST_PROFILE_SETTINGS || | 47 | if ((request == PYRA_CONTROL_REQUEST_PROFILE_SETTINGS || |
48 | request == PYRA_CONTROL_REQUEST_PROFILE_BUTTONS) && | 48 | request == PYRA_CONTROL_REQUEST_PROFILE_BUTTONS) && |
49 | (value < 0 || value > 4)) | 49 | (value < 0 || value > 4)) |
50 | return -EINVAL; | 50 | return -EINVAL; |
51 | 51 | ||
52 | control.command = PYRA_COMMAND_CONTROL; | 52 | control.command = ROCCAT_COMMON_COMMAND_CONTROL; |
53 | control.value = value; | 53 | control.value = value; |
54 | control.request = request; | 54 | control.request = request; |
55 | 55 | ||
56 | return roccat_common_send(usb_dev, PYRA_COMMAND_CONTROL, | 56 | return roccat_common2_send(usb_dev, ROCCAT_COMMON_COMMAND_CONTROL, |
57 | &control, sizeof(struct pyra_control)); | 57 | &control, sizeof(struct roccat_common2_control)); |
58 | } | ||
59 | |||
60 | static int pyra_receive_control_status(struct usb_device *usb_dev) | ||
61 | { | ||
62 | int retval; | ||
63 | struct pyra_control control; | ||
64 | |||
65 | do { | ||
66 | msleep(10); | ||
67 | retval = roccat_common_receive(usb_dev, PYRA_COMMAND_CONTROL, | ||
68 | &control, sizeof(struct pyra_control)); | ||
69 | |||
70 | /* requested too early, try again */ | ||
71 | } while (retval == -EPROTO); | ||
72 | |||
73 | if (!retval && control.command == PYRA_COMMAND_CONTROL && | ||
74 | control.request == PYRA_CONTROL_REQUEST_STATUS && | ||
75 | control.value == 1) | ||
76 | return 0; | ||
77 | else { | ||
78 | hid_err(usb_dev, "receive control status: unknown response 0x%x 0x%x\n", | ||
79 | control.request, control.value); | ||
80 | return retval ? retval : -EINVAL; | ||
81 | } | ||
82 | } | 58 | } |
83 | 59 | ||
84 | static int pyra_get_profile_settings(struct usb_device *usb_dev, | 60 | static int pyra_get_profile_settings(struct usb_device *usb_dev, |
@@ -89,7 +65,7 @@ static int pyra_get_profile_settings(struct usb_device *usb_dev, | |||
89 | PYRA_CONTROL_REQUEST_PROFILE_SETTINGS); | 65 | PYRA_CONTROL_REQUEST_PROFILE_SETTINGS); |
90 | if (retval) | 66 | if (retval) |
91 | return retval; | 67 | return retval; |
92 | return roccat_common_receive(usb_dev, PYRA_COMMAND_PROFILE_SETTINGS, | 68 | return roccat_common2_receive(usb_dev, PYRA_COMMAND_PROFILE_SETTINGS, |
93 | buf, sizeof(struct pyra_profile_settings)); | 69 | buf, sizeof(struct pyra_profile_settings)); |
94 | } | 70 | } |
95 | 71 | ||
@@ -101,51 +77,44 @@ static int pyra_get_profile_buttons(struct usb_device *usb_dev, | |||
101 | PYRA_CONTROL_REQUEST_PROFILE_BUTTONS); | 77 | PYRA_CONTROL_REQUEST_PROFILE_BUTTONS); |
102 | if (retval) | 78 | if (retval) |
103 | return retval; | 79 | return retval; |
104 | return roccat_common_receive(usb_dev, PYRA_COMMAND_PROFILE_BUTTONS, | 80 | return roccat_common2_receive(usb_dev, PYRA_COMMAND_PROFILE_BUTTONS, |
105 | buf, sizeof(struct pyra_profile_buttons)); | 81 | buf, sizeof(struct pyra_profile_buttons)); |
106 | } | 82 | } |
107 | 83 | ||
108 | static int pyra_get_settings(struct usb_device *usb_dev, | 84 | static int pyra_get_settings(struct usb_device *usb_dev, |
109 | struct pyra_settings *buf) | 85 | struct pyra_settings *buf) |
110 | { | 86 | { |
111 | return roccat_common_receive(usb_dev, PYRA_COMMAND_SETTINGS, | 87 | return roccat_common2_receive(usb_dev, PYRA_COMMAND_SETTINGS, |
112 | buf, sizeof(struct pyra_settings)); | 88 | buf, sizeof(struct pyra_settings)); |
113 | } | 89 | } |
114 | 90 | ||
115 | static int pyra_get_info(struct usb_device *usb_dev, struct pyra_info *buf) | 91 | static int pyra_get_info(struct usb_device *usb_dev, struct pyra_info *buf) |
116 | { | 92 | { |
117 | return roccat_common_receive(usb_dev, PYRA_COMMAND_INFO, | 93 | return roccat_common2_receive(usb_dev, PYRA_COMMAND_INFO, |
118 | buf, sizeof(struct pyra_info)); | 94 | buf, sizeof(struct pyra_info)); |
119 | } | 95 | } |
120 | 96 | ||
121 | static int pyra_send(struct usb_device *usb_dev, uint command, | ||
122 | void const *buf, uint size) | ||
123 | { | ||
124 | int retval; | ||
125 | retval = roccat_common_send(usb_dev, command, buf, size); | ||
126 | if (retval) | ||
127 | return retval; | ||
128 | return pyra_receive_control_status(usb_dev); | ||
129 | } | ||
130 | |||
131 | static int pyra_set_profile_settings(struct usb_device *usb_dev, | 97 | static int pyra_set_profile_settings(struct usb_device *usb_dev, |
132 | struct pyra_profile_settings const *settings) | 98 | struct pyra_profile_settings const *settings) |
133 | { | 99 | { |
134 | return pyra_send(usb_dev, PYRA_COMMAND_PROFILE_SETTINGS, settings, | 100 | return roccat_common2_send_with_status(usb_dev, |
101 | PYRA_COMMAND_PROFILE_SETTINGS, settings, | ||
135 | sizeof(struct pyra_profile_settings)); | 102 | sizeof(struct pyra_profile_settings)); |
136 | } | 103 | } |
137 | 104 | ||
138 | static int pyra_set_profile_buttons(struct usb_device *usb_dev, | 105 | static int pyra_set_profile_buttons(struct usb_device *usb_dev, |
139 | struct pyra_profile_buttons const *buttons) | 106 | struct pyra_profile_buttons const *buttons) |
140 | { | 107 | { |
141 | return pyra_send(usb_dev, PYRA_COMMAND_PROFILE_BUTTONS, buttons, | 108 | return roccat_common2_send_with_status(usb_dev, |
109 | PYRA_COMMAND_PROFILE_BUTTONS, buttons, | ||
142 | sizeof(struct pyra_profile_buttons)); | 110 | sizeof(struct pyra_profile_buttons)); |
143 | } | 111 | } |
144 | 112 | ||
145 | static int pyra_set_settings(struct usb_device *usb_dev, | 113 | static int pyra_set_settings(struct usb_device *usb_dev, |
146 | struct pyra_settings const *settings) | 114 | struct pyra_settings const *settings) |
147 | { | 115 | { |
148 | return pyra_send(usb_dev, PYRA_COMMAND_SETTINGS, settings, | 116 | return roccat_common2_send_with_status(usb_dev, |
117 | PYRA_COMMAND_SETTINGS, settings, | ||
149 | sizeof(struct pyra_settings)); | 118 | sizeof(struct pyra_settings)); |
150 | } | 119 | } |
151 | 120 | ||
diff --git a/drivers/hid/hid-roccat-pyra.h b/drivers/hid/hid-roccat-pyra.h index 0442d7fa2dcf..eada7830fa99 100644 --- a/drivers/hid/hid-roccat-pyra.h +++ b/drivers/hid/hid-roccat-pyra.h | |||
@@ -20,18 +20,7 @@ struct pyra_b { | |||
20 | uint8_t unknown; /* 1 */ | 20 | uint8_t unknown; /* 1 */ |
21 | } __attribute__ ((__packed__)); | 21 | } __attribute__ ((__packed__)); |
22 | 22 | ||
23 | struct pyra_control { | ||
24 | uint8_t command; /* PYRA_COMMAND_CONTROL */ | ||
25 | /* | ||
26 | * value is profile number for request_settings and request_buttons | ||
27 | * 1 if status ok for request_status | ||
28 | */ | ||
29 | uint8_t value; /* Range 0-4 */ | ||
30 | uint8_t request; | ||
31 | } __attribute__ ((__packed__)); | ||
32 | |||
33 | enum pyra_control_requests { | 23 | enum pyra_control_requests { |
34 | PYRA_CONTROL_REQUEST_STATUS = 0x00, | ||
35 | PYRA_CONTROL_REQUEST_PROFILE_SETTINGS = 0x10, | 24 | PYRA_CONTROL_REQUEST_PROFILE_SETTINGS = 0x10, |
36 | PYRA_CONTROL_REQUEST_PROFILE_BUTTONS = 0x20 | 25 | PYRA_CONTROL_REQUEST_PROFILE_BUTTONS = 0x20 |
37 | }; | 26 | }; |
@@ -75,7 +64,6 @@ struct pyra_info { | |||
75 | } __attribute__ ((__packed__)); | 64 | } __attribute__ ((__packed__)); |
76 | 65 | ||
77 | enum pyra_commands { | 66 | enum pyra_commands { |
78 | PYRA_COMMAND_CONTROL = 0x4, | ||
79 | PYRA_COMMAND_SETTINGS = 0x5, | 67 | PYRA_COMMAND_SETTINGS = 0x5, |
80 | PYRA_COMMAND_PROFILE_SETTINGS = 0x6, | 68 | PYRA_COMMAND_PROFILE_SETTINGS = 0x6, |
81 | PYRA_COMMAND_PROFILE_BUTTONS = 0x7, | 69 | PYRA_COMMAND_PROFILE_BUTTONS = 0x7, |
diff --git a/drivers/hid/hid-roccat-savu.c b/drivers/hid/hid-roccat-savu.c new file mode 100644 index 000000000000..014afba407e0 --- /dev/null +++ b/drivers/hid/hid-roccat-savu.c | |||
@@ -0,0 +1,316 @@ | |||
1 | /* | ||
2 | * Roccat Savu driver for Linux | ||
3 | * | ||
4 | * Copyright (c) 2012 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 | /* Roccat Savu is a gamer mouse with macro keys that can be configured in | ||
15 | * 5 profiles. | ||
16 | */ | ||
17 | |||
18 | #include <linux/device.h> | ||
19 | #include <linux/input.h> | ||
20 | #include <linux/hid.h> | ||
21 | #include <linux/module.h> | ||
22 | #include <linux/slab.h> | ||
23 | #include <linux/hid-roccat.h> | ||
24 | #include "hid-ids.h" | ||
25 | #include "hid-roccat-common.h" | ||
26 | #include "hid-roccat-savu.h" | ||
27 | |||
28 | static struct class *savu_class; | ||
29 | |||
30 | static ssize_t savu_sysfs_read(struct file *fp, struct kobject *kobj, | ||
31 | char *buf, loff_t off, size_t count, | ||
32 | size_t real_size, uint command) | ||
33 | { | ||
34 | struct device *dev = | ||
35 | container_of(kobj, struct device, kobj)->parent->parent; | ||
36 | struct savu_device *savu = hid_get_drvdata(dev_get_drvdata(dev)); | ||
37 | struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev)); | ||
38 | int retval; | ||
39 | |||
40 | if (off >= real_size) | ||
41 | return 0; | ||
42 | |||
43 | if (off != 0 || count != real_size) | ||
44 | return -EINVAL; | ||
45 | |||
46 | mutex_lock(&savu->savu_lock); | ||
47 | retval = roccat_common2_receive(usb_dev, command, buf, real_size); | ||
48 | mutex_unlock(&savu->savu_lock); | ||
49 | |||
50 | return retval ? retval : real_size; | ||
51 | } | ||
52 | |||
53 | static ssize_t savu_sysfs_write(struct file *fp, struct kobject *kobj, | ||
54 | void const *buf, loff_t off, size_t count, | ||
55 | size_t real_size, uint command) | ||
56 | { | ||
57 | struct device *dev = | ||
58 | container_of(kobj, struct device, kobj)->parent->parent; | ||
59 | struct savu_device *savu = hid_get_drvdata(dev_get_drvdata(dev)); | ||
60 | struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev)); | ||
61 | int retval; | ||
62 | |||
63 | if (off != 0 || count != real_size) | ||
64 | return -EINVAL; | ||
65 | |||
66 | mutex_lock(&savu->savu_lock); | ||
67 | retval = roccat_common2_send_with_status(usb_dev, command, | ||
68 | (void *)buf, real_size); | ||
69 | mutex_unlock(&savu->savu_lock); | ||
70 | |||
71 | return retval ? retval : real_size; | ||
72 | } | ||
73 | |||
74 | #define SAVU_SYSFS_W(thingy, THINGY) \ | ||
75 | static ssize_t savu_sysfs_write_ ## thingy(struct file *fp, \ | ||
76 | struct kobject *kobj, struct bin_attribute *attr, char *buf, \ | ||
77 | loff_t off, size_t count) \ | ||
78 | { \ | ||
79 | return savu_sysfs_write(fp, kobj, buf, off, count, \ | ||
80 | SAVU_SIZE_ ## THINGY, SAVU_COMMAND_ ## THINGY); \ | ||
81 | } | ||
82 | |||
83 | #define SAVU_SYSFS_R(thingy, THINGY) \ | ||
84 | static ssize_t savu_sysfs_read_ ## thingy(struct file *fp, \ | ||
85 | struct kobject *kobj, struct bin_attribute *attr, char *buf, \ | ||
86 | loff_t off, size_t count) \ | ||
87 | { \ | ||
88 | return savu_sysfs_read(fp, kobj, buf, off, count, \ | ||
89 | SAVU_SIZE_ ## THINGY, SAVU_COMMAND_ ## THINGY); \ | ||
90 | } | ||
91 | |||
92 | #define SAVU_SYSFS_RW(thingy, THINGY) \ | ||
93 | SAVU_SYSFS_W(thingy, THINGY) \ | ||
94 | SAVU_SYSFS_R(thingy, THINGY) | ||
95 | |||
96 | #define SAVU_BIN_ATTRIBUTE_RW(thingy, THINGY) \ | ||
97 | { \ | ||
98 | .attr = { .name = #thingy, .mode = 0660 }, \ | ||
99 | .size = SAVU_SIZE_ ## THINGY, \ | ||
100 | .read = savu_sysfs_read_ ## thingy, \ | ||
101 | .write = savu_sysfs_write_ ## thingy \ | ||
102 | } | ||
103 | |||
104 | #define SAVU_BIN_ATTRIBUTE_R(thingy, THINGY) \ | ||
105 | { \ | ||
106 | .attr = { .name = #thingy, .mode = 0440 }, \ | ||
107 | .size = SAVU_SIZE_ ## THINGY, \ | ||
108 | .read = savu_sysfs_read_ ## thingy, \ | ||
109 | } | ||
110 | |||
111 | #define SAVU_BIN_ATTRIBUTE_W(thingy, THINGY) \ | ||
112 | { \ | ||
113 | .attr = { .name = #thingy, .mode = 0220 }, \ | ||
114 | .size = SAVU_SIZE_ ## THINGY, \ | ||
115 | .write = savu_sysfs_write_ ## thingy \ | ||
116 | } | ||
117 | |||
118 | SAVU_SYSFS_W(control, CONTROL) | ||
119 | SAVU_SYSFS_RW(profile, PROFILE) | ||
120 | SAVU_SYSFS_RW(general, GENERAL) | ||
121 | SAVU_SYSFS_RW(buttons, BUTTONS) | ||
122 | SAVU_SYSFS_RW(macro, MACRO) | ||
123 | SAVU_SYSFS_R(info, INFO) | ||
124 | SAVU_SYSFS_RW(sensor, SENSOR) | ||
125 | |||
126 | static struct bin_attribute savu_bin_attributes[] = { | ||
127 | SAVU_BIN_ATTRIBUTE_W(control, CONTROL), | ||
128 | SAVU_BIN_ATTRIBUTE_RW(profile, PROFILE), | ||
129 | SAVU_BIN_ATTRIBUTE_RW(general, GENERAL), | ||
130 | SAVU_BIN_ATTRIBUTE_RW(buttons, BUTTONS), | ||
131 | SAVU_BIN_ATTRIBUTE_RW(macro, MACRO), | ||
132 | SAVU_BIN_ATTRIBUTE_R(info, INFO), | ||
133 | SAVU_BIN_ATTRIBUTE_RW(sensor, SENSOR), | ||
134 | __ATTR_NULL | ||
135 | }; | ||
136 | |||
137 | static int savu_init_savu_device_struct(struct usb_device *usb_dev, | ||
138 | struct savu_device *savu) | ||
139 | { | ||
140 | mutex_init(&savu->savu_lock); | ||
141 | |||
142 | return 0; | ||
143 | } | ||
144 | |||
145 | static int savu_init_specials(struct hid_device *hdev) | ||
146 | { | ||
147 | struct usb_interface *intf = to_usb_interface(hdev->dev.parent); | ||
148 | struct usb_device *usb_dev = interface_to_usbdev(intf); | ||
149 | struct savu_device *savu; | ||
150 | int retval; | ||
151 | |||
152 | if (intf->cur_altsetting->desc.bInterfaceProtocol | ||
153 | != USB_INTERFACE_PROTOCOL_MOUSE) { | ||
154 | hid_set_drvdata(hdev, NULL); | ||
155 | return 0; | ||
156 | } | ||
157 | |||
158 | savu = kzalloc(sizeof(*savu), GFP_KERNEL); | ||
159 | if (!savu) { | ||
160 | hid_err(hdev, "can't alloc device descriptor\n"); | ||
161 | return -ENOMEM; | ||
162 | } | ||
163 | hid_set_drvdata(hdev, savu); | ||
164 | |||
165 | retval = savu_init_savu_device_struct(usb_dev, savu); | ||
166 | if (retval) { | ||
167 | hid_err(hdev, "couldn't init struct savu_device\n"); | ||
168 | goto exit_free; | ||
169 | } | ||
170 | |||
171 | retval = roccat_connect(savu_class, hdev, | ||
172 | sizeof(struct savu_roccat_report)); | ||
173 | if (retval < 0) { | ||
174 | hid_err(hdev, "couldn't init char dev\n"); | ||
175 | } else { | ||
176 | savu->chrdev_minor = retval; | ||
177 | savu->roccat_claimed = 1; | ||
178 | } | ||
179 | |||
180 | return 0; | ||
181 | exit_free: | ||
182 | kfree(savu); | ||
183 | return retval; | ||
184 | } | ||
185 | |||
186 | static void savu_remove_specials(struct hid_device *hdev) | ||
187 | { | ||
188 | struct usb_interface *intf = to_usb_interface(hdev->dev.parent); | ||
189 | struct savu_device *savu; | ||
190 | |||
191 | if (intf->cur_altsetting->desc.bInterfaceProtocol | ||
192 | != USB_INTERFACE_PROTOCOL_MOUSE) | ||
193 | return; | ||
194 | |||
195 | savu = hid_get_drvdata(hdev); | ||
196 | if (savu->roccat_claimed) | ||
197 | roccat_disconnect(savu->chrdev_minor); | ||
198 | kfree(savu); | ||
199 | } | ||
200 | |||
201 | static int savu_probe(struct hid_device *hdev, | ||
202 | const struct hid_device_id *id) | ||
203 | { | ||
204 | int retval; | ||
205 | |||
206 | retval = hid_parse(hdev); | ||
207 | if (retval) { | ||
208 | hid_err(hdev, "parse failed\n"); | ||
209 | goto exit; | ||
210 | } | ||
211 | |||
212 | retval = hid_hw_start(hdev, HID_CONNECT_DEFAULT); | ||
213 | if (retval) { | ||
214 | hid_err(hdev, "hw start failed\n"); | ||
215 | goto exit; | ||
216 | } | ||
217 | |||
218 | retval = savu_init_specials(hdev); | ||
219 | if (retval) { | ||
220 | hid_err(hdev, "couldn't install mouse\n"); | ||
221 | goto exit_stop; | ||
222 | } | ||
223 | |||
224 | return 0; | ||
225 | |||
226 | exit_stop: | ||
227 | hid_hw_stop(hdev); | ||
228 | exit: | ||
229 | return retval; | ||
230 | } | ||
231 | |||
232 | static void savu_remove(struct hid_device *hdev) | ||
233 | { | ||
234 | savu_remove_specials(hdev); | ||
235 | hid_hw_stop(hdev); | ||
236 | } | ||
237 | |||
238 | static void savu_report_to_chrdev(struct savu_device const *savu, | ||
239 | u8 const *data) | ||
240 | { | ||
241 | struct savu_roccat_report roccat_report; | ||
242 | struct savu_mouse_report_special const *special_report; | ||
243 | |||
244 | if (data[0] != SAVU_MOUSE_REPORT_NUMBER_SPECIAL) | ||
245 | return; | ||
246 | |||
247 | special_report = (struct savu_mouse_report_special const *)data; | ||
248 | |||
249 | roccat_report.type = special_report->type; | ||
250 | roccat_report.data[0] = special_report->data[0]; | ||
251 | roccat_report.data[1] = special_report->data[1]; | ||
252 | roccat_report_event(savu->chrdev_minor, | ||
253 | (uint8_t const *)&roccat_report); | ||
254 | } | ||
255 | |||
256 | static int savu_raw_event(struct hid_device *hdev, | ||
257 | struct hid_report *report, u8 *data, int size) | ||
258 | { | ||
259 | struct usb_interface *intf = to_usb_interface(hdev->dev.parent); | ||
260 | struct savu_device *savu = hid_get_drvdata(hdev); | ||
261 | |||
262 | if (intf->cur_altsetting->desc.bInterfaceProtocol | ||
263 | != USB_INTERFACE_PROTOCOL_MOUSE) | ||
264 | return 0; | ||
265 | |||
266 | if (savu == NULL) | ||
267 | return 0; | ||
268 | |||
269 | if (savu->roccat_claimed) | ||
270 | savu_report_to_chrdev(savu, data); | ||
271 | |||
272 | return 0; | ||
273 | } | ||
274 | |||
275 | static const struct hid_device_id savu_devices[] = { | ||
276 | { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_SAVU) }, | ||
277 | { } | ||
278 | }; | ||
279 | |||
280 | MODULE_DEVICE_TABLE(hid, savu_devices); | ||
281 | |||
282 | static struct hid_driver savu_driver = { | ||
283 | .name = "savu", | ||
284 | .id_table = savu_devices, | ||
285 | .probe = savu_probe, | ||
286 | .remove = savu_remove, | ||
287 | .raw_event = savu_raw_event | ||
288 | }; | ||
289 | |||
290 | static int __init savu_init(void) | ||
291 | { | ||
292 | int retval; | ||
293 | |||
294 | savu_class = class_create(THIS_MODULE, "savu"); | ||
295 | if (IS_ERR(savu_class)) | ||
296 | return PTR_ERR(savu_class); | ||
297 | savu_class->dev_bin_attrs = savu_bin_attributes; | ||
298 | |||
299 | retval = hid_register_driver(&savu_driver); | ||
300 | if (retval) | ||
301 | class_destroy(savu_class); | ||
302 | return retval; | ||
303 | } | ||
304 | |||
305 | static void __exit savu_exit(void) | ||
306 | { | ||
307 | hid_unregister_driver(&savu_driver); | ||
308 | class_destroy(savu_class); | ||
309 | } | ||
310 | |||
311 | module_init(savu_init); | ||
312 | module_exit(savu_exit); | ||
313 | |||
314 | MODULE_AUTHOR("Stefan Achatz"); | ||
315 | MODULE_DESCRIPTION("USB Roccat Savu driver"); | ||
316 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/hid/hid-roccat-savu.h b/drivers/hid/hid-roccat-savu.h new file mode 100644 index 000000000000..9120ba72087f --- /dev/null +++ b/drivers/hid/hid-roccat-savu.h | |||
@@ -0,0 +1,87 @@ | |||
1 | #ifndef __HID_ROCCAT_SAVU_H | ||
2 | #define __HID_ROCCAT_SAVU_H | ||
3 | |||
4 | /* | ||
5 | * Copyright (c) 2012 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 | enum { | ||
18 | SAVU_SIZE_CONTROL = 0x03, | ||
19 | SAVU_SIZE_PROFILE = 0x03, | ||
20 | SAVU_SIZE_GENERAL = 0x10, | ||
21 | SAVU_SIZE_BUTTONS = 0x2f, | ||
22 | SAVU_SIZE_MACRO = 0x0823, | ||
23 | SAVU_SIZE_INFO = 0x08, | ||
24 | SAVU_SIZE_SENSOR = 0x04, | ||
25 | }; | ||
26 | |||
27 | enum savu_control_requests { | ||
28 | SAVU_CONTROL_REQUEST_GENERAL = 0x80, | ||
29 | SAVU_CONTROL_REQUEST_BUTTONS = 0x90, | ||
30 | }; | ||
31 | |||
32 | enum savu_commands { | ||
33 | SAVU_COMMAND_CONTROL = 0x4, | ||
34 | SAVU_COMMAND_PROFILE = 0x5, | ||
35 | SAVU_COMMAND_GENERAL = 0x6, | ||
36 | SAVU_COMMAND_BUTTONS = 0x7, | ||
37 | SAVU_COMMAND_MACRO = 0x8, | ||
38 | SAVU_COMMAND_INFO = 0x9, | ||
39 | SAVU_COMMAND_SENSOR = 0xc, | ||
40 | }; | ||
41 | |||
42 | struct savu_mouse_report_special { | ||
43 | uint8_t report_number; /* always 3 */ | ||
44 | uint8_t zero; | ||
45 | uint8_t type; | ||
46 | uint8_t data[2]; | ||
47 | } __packed; | ||
48 | |||
49 | enum { | ||
50 | SAVU_MOUSE_REPORT_NUMBER_SPECIAL = 3, | ||
51 | }; | ||
52 | |||
53 | enum savu_mouse_report_button_types { | ||
54 | /* data1 = new profile range 1-5 */ | ||
55 | SAVU_MOUSE_REPORT_BUTTON_TYPE_PROFILE = 0x20, | ||
56 | |||
57 | /* data1 = button number range 1-24; data2 = action */ | ||
58 | SAVU_MOUSE_REPORT_BUTTON_TYPE_QUICKLAUNCH = 0x60, | ||
59 | |||
60 | /* data1 = button number range 1-24; data2 = action */ | ||
61 | SAVU_MOUSE_REPORT_BUTTON_TYPE_TIMER = 0x80, | ||
62 | |||
63 | /* data1 = setting number range 1-5 */ | ||
64 | SAVU_MOUSE_REPORT_BUTTON_TYPE_CPI = 0xb0, | ||
65 | |||
66 | /* data1 and data2 = range 0x1-0xb */ | ||
67 | SAVU_MOUSE_REPORT_BUTTON_TYPE_SENSITIVITY = 0xc0, | ||
68 | |||
69 | /* data1 = 22 = next track... | ||
70 | * data2 = action | ||
71 | */ | ||
72 | SAVU_MOUSE_REPORT_BUTTON_TYPE_MULTIMEDIA = 0xf0, | ||
73 | }; | ||
74 | |||
75 | struct savu_roccat_report { | ||
76 | uint8_t type; | ||
77 | uint8_t data[2]; | ||
78 | } __packed; | ||
79 | |||
80 | struct savu_device { | ||
81 | int roccat_claimed; | ||
82 | int chrdev_minor; | ||
83 | |||
84 | struct mutex savu_lock; | ||
85 | }; | ||
86 | |||
87 | #endif | ||
diff --git a/drivers/hid/hid-wiimote-ext.c b/drivers/hid/hid-wiimote-ext.c index aa958706c0e5..0a1805c9b0e5 100644 --- a/drivers/hid/hid-wiimote-ext.c +++ b/drivers/hid/hid-wiimote-ext.c | |||
@@ -77,7 +77,7 @@ static __u16 wiiext_keymap[] = { | |||
77 | BTN_TR, /* WIIEXT_KEY_RT */ | 77 | BTN_TR, /* WIIEXT_KEY_RT */ |
78 | }; | 78 | }; |
79 | 79 | ||
80 | /* diable all extensions */ | 80 | /* disable all extensions */ |
81 | static void ext_disable(struct wiimote_ext *ext) | 81 | static void ext_disable(struct wiimote_ext *ext) |
82 | { | 82 | { |
83 | unsigned long flags; | 83 | unsigned long flags; |
diff --git a/drivers/hid/hidraw.c b/drivers/hid/hidraw.c index 36fa77b40ffb..3b6f7bf5a77e 100644 --- a/drivers/hid/hidraw.c +++ b/drivers/hid/hidraw.c | |||
@@ -96,6 +96,7 @@ static ssize_t hidraw_read(struct file *file, char __user *buffer, size_t count, | |||
96 | } | 96 | } |
97 | 97 | ||
98 | kfree(list->buffer[list->tail].value); | 98 | kfree(list->buffer[list->tail].value); |
99 | list->buffer[list->tail].value = NULL; | ||
99 | list->tail = (list->tail + 1) & (HIDRAW_BUFFER_SIZE - 1); | 100 | list->tail = (list->tail + 1) & (HIDRAW_BUFFER_SIZE - 1); |
100 | } | 101 | } |
101 | out: | 102 | out: |
@@ -300,6 +301,7 @@ static int hidraw_release(struct inode * inode, struct file * file) | |||
300 | struct hidraw *dev; | 301 | struct hidraw *dev; |
301 | struct hidraw_list *list = file->private_data; | 302 | struct hidraw_list *list = file->private_data; |
302 | int ret; | 303 | int ret; |
304 | int i; | ||
303 | 305 | ||
304 | mutex_lock(&minors_lock); | 306 | mutex_lock(&minors_lock); |
305 | if (!hidraw_table[minor]) { | 307 | if (!hidraw_table[minor]) { |
@@ -317,6 +319,9 @@ static int hidraw_release(struct inode * inode, struct file * file) | |||
317 | kfree(list->hidraw); | 319 | kfree(list->hidraw); |
318 | } | 320 | } |
319 | } | 321 | } |
322 | |||
323 | for (i = 0; i < HIDRAW_BUFFER_SIZE; ++i) | ||
324 | kfree(list->buffer[i].value); | ||
320 | kfree(list); | 325 | kfree(list); |
321 | ret = 0; | 326 | ret = 0; |
322 | unlock: | 327 | unlock: |
@@ -446,12 +451,17 @@ int hidraw_report_event(struct hid_device *hid, u8 *data, int len) | |||
446 | int ret = 0; | 451 | int ret = 0; |
447 | 452 | ||
448 | list_for_each_entry(list, &dev->list, node) { | 453 | list_for_each_entry(list, &dev->list, node) { |
454 | int new_head = (list->head + 1) & (HIDRAW_BUFFER_SIZE - 1); | ||
455 | |||
456 | if (new_head == list->tail) | ||
457 | continue; | ||
458 | |||
449 | if (!(list->buffer[list->head].value = kmemdup(data, len, GFP_ATOMIC))) { | 459 | if (!(list->buffer[list->head].value = kmemdup(data, len, GFP_ATOMIC))) { |
450 | ret = -ENOMEM; | 460 | ret = -ENOMEM; |
451 | break; | 461 | break; |
452 | } | 462 | } |
453 | list->buffer[list->head].len = len; | 463 | list->buffer[list->head].len = len; |
454 | list->head = (list->head + 1) & (HIDRAW_BUFFER_SIZE - 1); | 464 | list->head = new_head; |
455 | kill_fasync(&list->fasync, SIGIO, POLL_IN); | 465 | kill_fasync(&list->fasync, SIGIO, POLL_IN); |
456 | } | 466 | } |
457 | 467 | ||
diff --git a/drivers/hid/uhid.c b/drivers/hid/uhid.c new file mode 100644 index 000000000000..714cd8cc9579 --- /dev/null +++ b/drivers/hid/uhid.c | |||
@@ -0,0 +1,572 @@ | |||
1 | /* | ||
2 | * User-space I/O driver support for HID subsystem | ||
3 | * Copyright (c) 2012 David Herrmann | ||
4 | */ | ||
5 | |||
6 | /* | ||
7 | * This program is free software; you can redistribute it and/or modify it | ||
8 | * under the terms of the GNU General Public License as published by the Free | ||
9 | * Software Foundation; either version 2 of the License, or (at your option) | ||
10 | * any later version. | ||
11 | */ | ||
12 | |||
13 | #include <linux/atomic.h> | ||
14 | #include <linux/device.h> | ||
15 | #include <linux/fs.h> | ||
16 | #include <linux/hid.h> | ||
17 | #include <linux/input.h> | ||
18 | #include <linux/miscdevice.h> | ||
19 | #include <linux/module.h> | ||
20 | #include <linux/mutex.h> | ||
21 | #include <linux/poll.h> | ||
22 | #include <linux/sched.h> | ||
23 | #include <linux/spinlock.h> | ||
24 | #include <linux/uhid.h> | ||
25 | #include <linux/wait.h> | ||
26 | |||
27 | #define UHID_NAME "uhid" | ||
28 | #define UHID_BUFSIZE 32 | ||
29 | |||
30 | struct uhid_device { | ||
31 | struct mutex devlock; | ||
32 | bool running; | ||
33 | |||
34 | __u8 *rd_data; | ||
35 | uint rd_size; | ||
36 | |||
37 | struct hid_device *hid; | ||
38 | struct uhid_event input_buf; | ||
39 | |||
40 | wait_queue_head_t waitq; | ||
41 | spinlock_t qlock; | ||
42 | __u8 head; | ||
43 | __u8 tail; | ||
44 | struct uhid_event *outq[UHID_BUFSIZE]; | ||
45 | |||
46 | struct mutex report_lock; | ||
47 | wait_queue_head_t report_wait; | ||
48 | atomic_t report_done; | ||
49 | atomic_t report_id; | ||
50 | struct uhid_event report_buf; | ||
51 | }; | ||
52 | |||
53 | static struct miscdevice uhid_misc; | ||
54 | |||
55 | static void uhid_queue(struct uhid_device *uhid, struct uhid_event *ev) | ||
56 | { | ||
57 | __u8 newhead; | ||
58 | |||
59 | newhead = (uhid->head + 1) % UHID_BUFSIZE; | ||
60 | |||
61 | if (newhead != uhid->tail) { | ||
62 | uhid->outq[uhid->head] = ev; | ||
63 | uhid->head = newhead; | ||
64 | wake_up_interruptible(&uhid->waitq); | ||
65 | } else { | ||
66 | hid_warn(uhid->hid, "Output queue is full\n"); | ||
67 | kfree(ev); | ||
68 | } | ||
69 | } | ||
70 | |||
71 | static int uhid_queue_event(struct uhid_device *uhid, __u32 event) | ||
72 | { | ||
73 | unsigned long flags; | ||
74 | struct uhid_event *ev; | ||
75 | |||
76 | ev = kzalloc(sizeof(*ev), GFP_KERNEL); | ||
77 | if (!ev) | ||
78 | return -ENOMEM; | ||
79 | |||
80 | ev->type = event; | ||
81 | |||
82 | spin_lock_irqsave(&uhid->qlock, flags); | ||
83 | uhid_queue(uhid, ev); | ||
84 | spin_unlock_irqrestore(&uhid->qlock, flags); | ||
85 | |||
86 | return 0; | ||
87 | } | ||
88 | |||
89 | static int uhid_hid_start(struct hid_device *hid) | ||
90 | { | ||
91 | struct uhid_device *uhid = hid->driver_data; | ||
92 | |||
93 | return uhid_queue_event(uhid, UHID_START); | ||
94 | } | ||
95 | |||
96 | static void uhid_hid_stop(struct hid_device *hid) | ||
97 | { | ||
98 | struct uhid_device *uhid = hid->driver_data; | ||
99 | |||
100 | hid->claimed = 0; | ||
101 | uhid_queue_event(uhid, UHID_STOP); | ||
102 | } | ||
103 | |||
104 | static int uhid_hid_open(struct hid_device *hid) | ||
105 | { | ||
106 | struct uhid_device *uhid = hid->driver_data; | ||
107 | |||
108 | return uhid_queue_event(uhid, UHID_OPEN); | ||
109 | } | ||
110 | |||
111 | static void uhid_hid_close(struct hid_device *hid) | ||
112 | { | ||
113 | struct uhid_device *uhid = hid->driver_data; | ||
114 | |||
115 | uhid_queue_event(uhid, UHID_CLOSE); | ||
116 | } | ||
117 | |||
118 | static int uhid_hid_input(struct input_dev *input, unsigned int type, | ||
119 | unsigned int code, int value) | ||
120 | { | ||
121 | struct hid_device *hid = input_get_drvdata(input); | ||
122 | struct uhid_device *uhid = hid->driver_data; | ||
123 | unsigned long flags; | ||
124 | struct uhid_event *ev; | ||
125 | |||
126 | ev = kzalloc(sizeof(*ev), GFP_ATOMIC); | ||
127 | if (!ev) | ||
128 | return -ENOMEM; | ||
129 | |||
130 | ev->type = UHID_OUTPUT_EV; | ||
131 | ev->u.output_ev.type = type; | ||
132 | ev->u.output_ev.code = code; | ||
133 | ev->u.output_ev.value = value; | ||
134 | |||
135 | spin_lock_irqsave(&uhid->qlock, flags); | ||
136 | uhid_queue(uhid, ev); | ||
137 | spin_unlock_irqrestore(&uhid->qlock, flags); | ||
138 | |||
139 | return 0; | ||
140 | } | ||
141 | |||
142 | static int uhid_hid_parse(struct hid_device *hid) | ||
143 | { | ||
144 | struct uhid_device *uhid = hid->driver_data; | ||
145 | |||
146 | return hid_parse_report(hid, uhid->rd_data, uhid->rd_size); | ||
147 | } | ||
148 | |||
149 | static int uhid_hid_get_raw(struct hid_device *hid, unsigned char rnum, | ||
150 | __u8 *buf, size_t count, unsigned char rtype) | ||
151 | { | ||
152 | struct uhid_device *uhid = hid->driver_data; | ||
153 | __u8 report_type; | ||
154 | struct uhid_event *ev; | ||
155 | unsigned long flags; | ||
156 | int ret; | ||
157 | size_t uninitialized_var(len); | ||
158 | struct uhid_feature_answer_req *req; | ||
159 | |||
160 | if (!uhid->running) | ||
161 | return -EIO; | ||
162 | |||
163 | switch (rtype) { | ||
164 | case HID_FEATURE_REPORT: | ||
165 | report_type = UHID_FEATURE_REPORT; | ||
166 | break; | ||
167 | case HID_OUTPUT_REPORT: | ||
168 | report_type = UHID_OUTPUT_REPORT; | ||
169 | break; | ||
170 | case HID_INPUT_REPORT: | ||
171 | report_type = UHID_INPUT_REPORT; | ||
172 | break; | ||
173 | default: | ||
174 | return -EINVAL; | ||
175 | } | ||
176 | |||
177 | ret = mutex_lock_interruptible(&uhid->report_lock); | ||
178 | if (ret) | ||
179 | return ret; | ||
180 | |||
181 | ev = kzalloc(sizeof(*ev), GFP_KERNEL); | ||
182 | if (!ev) { | ||
183 | ret = -ENOMEM; | ||
184 | goto unlock; | ||
185 | } | ||
186 | |||
187 | spin_lock_irqsave(&uhid->qlock, flags); | ||
188 | ev->type = UHID_FEATURE; | ||
189 | ev->u.feature.id = atomic_inc_return(&uhid->report_id); | ||
190 | ev->u.feature.rnum = rnum; | ||
191 | ev->u.feature.rtype = report_type; | ||
192 | |||
193 | atomic_set(&uhid->report_done, 0); | ||
194 | uhid_queue(uhid, ev); | ||
195 | spin_unlock_irqrestore(&uhid->qlock, flags); | ||
196 | |||
197 | ret = wait_event_interruptible_timeout(uhid->report_wait, | ||
198 | atomic_read(&uhid->report_done), 5 * HZ); | ||
199 | |||
200 | /* | ||
201 | * Make sure "uhid->running" is cleared on shutdown before | ||
202 | * "uhid->report_done" is set. | ||
203 | */ | ||
204 | smp_rmb(); | ||
205 | if (!ret || !uhid->running) { | ||
206 | ret = -EIO; | ||
207 | } else if (ret < 0) { | ||
208 | ret = -ERESTARTSYS; | ||
209 | } else { | ||
210 | spin_lock_irqsave(&uhid->qlock, flags); | ||
211 | req = &uhid->report_buf.u.feature_answer; | ||
212 | |||
213 | if (req->err) { | ||
214 | ret = -EIO; | ||
215 | } else { | ||
216 | ret = 0; | ||
217 | len = min(count, | ||
218 | min_t(size_t, req->size, UHID_DATA_MAX)); | ||
219 | memcpy(buf, req->data, len); | ||
220 | } | ||
221 | |||
222 | spin_unlock_irqrestore(&uhid->qlock, flags); | ||
223 | } | ||
224 | |||
225 | atomic_set(&uhid->report_done, 1); | ||
226 | |||
227 | unlock: | ||
228 | mutex_unlock(&uhid->report_lock); | ||
229 | return ret ? ret : len; | ||
230 | } | ||
231 | |||
232 | static int uhid_hid_output_raw(struct hid_device *hid, __u8 *buf, size_t count, | ||
233 | unsigned char report_type) | ||
234 | { | ||
235 | struct uhid_device *uhid = hid->driver_data; | ||
236 | __u8 rtype; | ||
237 | unsigned long flags; | ||
238 | struct uhid_event *ev; | ||
239 | |||
240 | switch (report_type) { | ||
241 | case HID_FEATURE_REPORT: | ||
242 | rtype = UHID_FEATURE_REPORT; | ||
243 | break; | ||
244 | case HID_OUTPUT_REPORT: | ||
245 | rtype = UHID_OUTPUT_REPORT; | ||
246 | break; | ||
247 | default: | ||
248 | return -EINVAL; | ||
249 | } | ||
250 | |||
251 | if (count < 1 || count > UHID_DATA_MAX) | ||
252 | return -EINVAL; | ||
253 | |||
254 | ev = kzalloc(sizeof(*ev), GFP_KERNEL); | ||
255 | if (!ev) | ||
256 | return -ENOMEM; | ||
257 | |||
258 | ev->type = UHID_OUTPUT; | ||
259 | ev->u.output.size = count; | ||
260 | ev->u.output.rtype = rtype; | ||
261 | memcpy(ev->u.output.data, buf, count); | ||
262 | |||
263 | spin_lock_irqsave(&uhid->qlock, flags); | ||
264 | uhid_queue(uhid, ev); | ||
265 | spin_unlock_irqrestore(&uhid->qlock, flags); | ||
266 | |||
267 | return count; | ||
268 | } | ||
269 | |||
270 | static struct hid_ll_driver uhid_hid_driver = { | ||
271 | .start = uhid_hid_start, | ||
272 | .stop = uhid_hid_stop, | ||
273 | .open = uhid_hid_open, | ||
274 | .close = uhid_hid_close, | ||
275 | .hidinput_input_event = uhid_hid_input, | ||
276 | .parse = uhid_hid_parse, | ||
277 | }; | ||
278 | |||
279 | static int uhid_dev_create(struct uhid_device *uhid, | ||
280 | const struct uhid_event *ev) | ||
281 | { | ||
282 | struct hid_device *hid; | ||
283 | int ret; | ||
284 | |||
285 | if (uhid->running) | ||
286 | return -EALREADY; | ||
287 | |||
288 | uhid->rd_size = ev->u.create.rd_size; | ||
289 | if (uhid->rd_size <= 0 || uhid->rd_size > HID_MAX_DESCRIPTOR_SIZE) | ||
290 | return -EINVAL; | ||
291 | |||
292 | uhid->rd_data = kmalloc(uhid->rd_size, GFP_KERNEL); | ||
293 | if (!uhid->rd_data) | ||
294 | return -ENOMEM; | ||
295 | |||
296 | if (copy_from_user(uhid->rd_data, ev->u.create.rd_data, | ||
297 | uhid->rd_size)) { | ||
298 | ret = -EFAULT; | ||
299 | goto err_free; | ||
300 | } | ||
301 | |||
302 | hid = hid_allocate_device(); | ||
303 | if (IS_ERR(hid)) { | ||
304 | ret = PTR_ERR(hid); | ||
305 | goto err_free; | ||
306 | } | ||
307 | |||
308 | strncpy(hid->name, ev->u.create.name, 127); | ||
309 | hid->name[127] = 0; | ||
310 | strncpy(hid->phys, ev->u.create.phys, 63); | ||
311 | hid->phys[63] = 0; | ||
312 | strncpy(hid->uniq, ev->u.create.uniq, 63); | ||
313 | hid->uniq[63] = 0; | ||
314 | |||
315 | hid->ll_driver = &uhid_hid_driver; | ||
316 | hid->hid_get_raw_report = uhid_hid_get_raw; | ||
317 | hid->hid_output_raw_report = uhid_hid_output_raw; | ||
318 | hid->bus = ev->u.create.bus; | ||
319 | hid->vendor = ev->u.create.vendor; | ||
320 | hid->product = ev->u.create.product; | ||
321 | hid->version = ev->u.create.version; | ||
322 | hid->country = ev->u.create.country; | ||
323 | hid->driver_data = uhid; | ||
324 | hid->dev.parent = uhid_misc.this_device; | ||
325 | |||
326 | uhid->hid = hid; | ||
327 | uhid->running = true; | ||
328 | |||
329 | ret = hid_add_device(hid); | ||
330 | if (ret) { | ||
331 | hid_err(hid, "Cannot register HID device\n"); | ||
332 | goto err_hid; | ||
333 | } | ||
334 | |||
335 | return 0; | ||
336 | |||
337 | err_hid: | ||
338 | hid_destroy_device(hid); | ||
339 | uhid->hid = NULL; | ||
340 | uhid->running = false; | ||
341 | err_free: | ||
342 | kfree(uhid->rd_data); | ||
343 | return ret; | ||
344 | } | ||
345 | |||
346 | static int uhid_dev_destroy(struct uhid_device *uhid) | ||
347 | { | ||
348 | if (!uhid->running) | ||
349 | return -EINVAL; | ||
350 | |||
351 | /* clear "running" before setting "report_done" */ | ||
352 | uhid->running = false; | ||
353 | smp_wmb(); | ||
354 | atomic_set(&uhid->report_done, 1); | ||
355 | wake_up_interruptible(&uhid->report_wait); | ||
356 | |||
357 | hid_destroy_device(uhid->hid); | ||
358 | kfree(uhid->rd_data); | ||
359 | |||
360 | return 0; | ||
361 | } | ||
362 | |||
363 | static int uhid_dev_input(struct uhid_device *uhid, struct uhid_event *ev) | ||
364 | { | ||
365 | if (!uhid->running) | ||
366 | return -EINVAL; | ||
367 | |||
368 | hid_input_report(uhid->hid, HID_INPUT_REPORT, ev->u.input.data, | ||
369 | min_t(size_t, ev->u.input.size, UHID_DATA_MAX), 0); | ||
370 | |||
371 | return 0; | ||
372 | } | ||
373 | |||
374 | static int uhid_dev_feature_answer(struct uhid_device *uhid, | ||
375 | struct uhid_event *ev) | ||
376 | { | ||
377 | unsigned long flags; | ||
378 | |||
379 | if (!uhid->running) | ||
380 | return -EINVAL; | ||
381 | |||
382 | spin_lock_irqsave(&uhid->qlock, flags); | ||
383 | |||
384 | /* id for old report; drop it silently */ | ||
385 | if (atomic_read(&uhid->report_id) != ev->u.feature_answer.id) | ||
386 | goto unlock; | ||
387 | if (atomic_read(&uhid->report_done)) | ||
388 | goto unlock; | ||
389 | |||
390 | memcpy(&uhid->report_buf, ev, sizeof(*ev)); | ||
391 | atomic_set(&uhid->report_done, 1); | ||
392 | wake_up_interruptible(&uhid->report_wait); | ||
393 | |||
394 | unlock: | ||
395 | spin_unlock_irqrestore(&uhid->qlock, flags); | ||
396 | return 0; | ||
397 | } | ||
398 | |||
399 | static int uhid_char_open(struct inode *inode, struct file *file) | ||
400 | { | ||
401 | struct uhid_device *uhid; | ||
402 | |||
403 | uhid = kzalloc(sizeof(*uhid), GFP_KERNEL); | ||
404 | if (!uhid) | ||
405 | return -ENOMEM; | ||
406 | |||
407 | mutex_init(&uhid->devlock); | ||
408 | mutex_init(&uhid->report_lock); | ||
409 | spin_lock_init(&uhid->qlock); | ||
410 | init_waitqueue_head(&uhid->waitq); | ||
411 | init_waitqueue_head(&uhid->report_wait); | ||
412 | uhid->running = false; | ||
413 | atomic_set(&uhid->report_done, 1); | ||
414 | |||
415 | file->private_data = uhid; | ||
416 | nonseekable_open(inode, file); | ||
417 | |||
418 | return 0; | ||
419 | } | ||
420 | |||
421 | static int uhid_char_release(struct inode *inode, struct file *file) | ||
422 | { | ||
423 | struct uhid_device *uhid = file->private_data; | ||
424 | unsigned int i; | ||
425 | |||
426 | uhid_dev_destroy(uhid); | ||
427 | |||
428 | for (i = 0; i < UHID_BUFSIZE; ++i) | ||
429 | kfree(uhid->outq[i]); | ||
430 | |||
431 | kfree(uhid); | ||
432 | |||
433 | return 0; | ||
434 | } | ||
435 | |||
436 | static ssize_t uhid_char_read(struct file *file, char __user *buffer, | ||
437 | size_t count, loff_t *ppos) | ||
438 | { | ||
439 | struct uhid_device *uhid = file->private_data; | ||
440 | int ret; | ||
441 | unsigned long flags; | ||
442 | size_t len; | ||
443 | |||
444 | /* they need at least the "type" member of uhid_event */ | ||
445 | if (count < sizeof(__u32)) | ||
446 | return -EINVAL; | ||
447 | |||
448 | try_again: | ||
449 | if (file->f_flags & O_NONBLOCK) { | ||
450 | if (uhid->head == uhid->tail) | ||
451 | return -EAGAIN; | ||
452 | } else { | ||
453 | ret = wait_event_interruptible(uhid->waitq, | ||
454 | uhid->head != uhid->tail); | ||
455 | if (ret) | ||
456 | return ret; | ||
457 | } | ||
458 | |||
459 | ret = mutex_lock_interruptible(&uhid->devlock); | ||
460 | if (ret) | ||
461 | return ret; | ||
462 | |||
463 | if (uhid->head == uhid->tail) { | ||
464 | mutex_unlock(&uhid->devlock); | ||
465 | goto try_again; | ||
466 | } else { | ||
467 | len = min(count, sizeof(**uhid->outq)); | ||
468 | if (copy_to_user(buffer, uhid->outq[uhid->tail], len)) { | ||
469 | ret = -EFAULT; | ||
470 | } else { | ||
471 | kfree(uhid->outq[uhid->tail]); | ||
472 | uhid->outq[uhid->tail] = NULL; | ||
473 | |||
474 | spin_lock_irqsave(&uhid->qlock, flags); | ||
475 | uhid->tail = (uhid->tail + 1) % UHID_BUFSIZE; | ||
476 | spin_unlock_irqrestore(&uhid->qlock, flags); | ||
477 | } | ||
478 | } | ||
479 | |||
480 | mutex_unlock(&uhid->devlock); | ||
481 | return ret ? ret : len; | ||
482 | } | ||
483 | |||
484 | static ssize_t uhid_char_write(struct file *file, const char __user *buffer, | ||
485 | size_t count, loff_t *ppos) | ||
486 | { | ||
487 | struct uhid_device *uhid = file->private_data; | ||
488 | int ret; | ||
489 | size_t len; | ||
490 | |||
491 | /* we need at least the "type" member of uhid_event */ | ||
492 | if (count < sizeof(__u32)) | ||
493 | return -EINVAL; | ||
494 | |||
495 | ret = mutex_lock_interruptible(&uhid->devlock); | ||
496 | if (ret) | ||
497 | return ret; | ||
498 | |||
499 | memset(&uhid->input_buf, 0, sizeof(uhid->input_buf)); | ||
500 | len = min(count, sizeof(uhid->input_buf)); | ||
501 | if (copy_from_user(&uhid->input_buf, buffer, len)) { | ||
502 | ret = -EFAULT; | ||
503 | goto unlock; | ||
504 | } | ||
505 | |||
506 | switch (uhid->input_buf.type) { | ||
507 | case UHID_CREATE: | ||
508 | ret = uhid_dev_create(uhid, &uhid->input_buf); | ||
509 | break; | ||
510 | case UHID_DESTROY: | ||
511 | ret = uhid_dev_destroy(uhid); | ||
512 | break; | ||
513 | case UHID_INPUT: | ||
514 | ret = uhid_dev_input(uhid, &uhid->input_buf); | ||
515 | break; | ||
516 | case UHID_FEATURE_ANSWER: | ||
517 | ret = uhid_dev_feature_answer(uhid, &uhid->input_buf); | ||
518 | break; | ||
519 | default: | ||
520 | ret = -EOPNOTSUPP; | ||
521 | } | ||
522 | |||
523 | unlock: | ||
524 | mutex_unlock(&uhid->devlock); | ||
525 | |||
526 | /* return "count" not "len" to not confuse the caller */ | ||
527 | return ret ? ret : count; | ||
528 | } | ||
529 | |||
530 | static unsigned int uhid_char_poll(struct file *file, poll_table *wait) | ||
531 | { | ||
532 | struct uhid_device *uhid = file->private_data; | ||
533 | |||
534 | poll_wait(file, &uhid->waitq, wait); | ||
535 | |||
536 | if (uhid->head != uhid->tail) | ||
537 | return POLLIN | POLLRDNORM; | ||
538 | |||
539 | return 0; | ||
540 | } | ||
541 | |||
542 | static const struct file_operations uhid_fops = { | ||
543 | .owner = THIS_MODULE, | ||
544 | .open = uhid_char_open, | ||
545 | .release = uhid_char_release, | ||
546 | .read = uhid_char_read, | ||
547 | .write = uhid_char_write, | ||
548 | .poll = uhid_char_poll, | ||
549 | .llseek = no_llseek, | ||
550 | }; | ||
551 | |||
552 | static struct miscdevice uhid_misc = { | ||
553 | .fops = &uhid_fops, | ||
554 | .minor = MISC_DYNAMIC_MINOR, | ||
555 | .name = UHID_NAME, | ||
556 | }; | ||
557 | |||
558 | static int __init uhid_init(void) | ||
559 | { | ||
560 | return misc_register(&uhid_misc); | ||
561 | } | ||
562 | |||
563 | static void __exit uhid_exit(void) | ||
564 | { | ||
565 | misc_deregister(&uhid_misc); | ||
566 | } | ||
567 | |||
568 | module_init(uhid_init); | ||
569 | module_exit(uhid_exit); | ||
570 | MODULE_LICENSE("GPL"); | ||
571 | MODULE_AUTHOR("David Herrmann <dh.herrmann@gmail.com>"); | ||
572 | MODULE_DESCRIPTION("User-space I/O driver support for HID subsystem"); | ||
diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c index 482f936fc29b..dedd8e4e5c6d 100644 --- a/drivers/hid/usbhid/hid-core.c +++ b/drivers/hid/usbhid/hid-core.c | |||
@@ -84,7 +84,7 @@ static int hid_start_in(struct hid_device *hid) | |||
84 | spin_lock_irqsave(&usbhid->lock, flags); | 84 | spin_lock_irqsave(&usbhid->lock, flags); |
85 | if (hid->open > 0 && | 85 | if (hid->open > 0 && |
86 | !test_bit(HID_DISCONNECTED, &usbhid->iofl) && | 86 | !test_bit(HID_DISCONNECTED, &usbhid->iofl) && |
87 | !test_bit(HID_REPORTED_IDLE, &usbhid->iofl) && | 87 | !test_bit(HID_SUSPENDED, &usbhid->iofl) && |
88 | !test_and_set_bit(HID_IN_RUNNING, &usbhid->iofl)) { | 88 | !test_and_set_bit(HID_IN_RUNNING, &usbhid->iofl)) { |
89 | rc = usb_submit_urb(usbhid->urbin, GFP_ATOMIC); | 89 | rc = usb_submit_urb(usbhid->urbin, GFP_ATOMIC); |
90 | if (rc != 0) { | 90 | if (rc != 0) { |
@@ -207,15 +207,27 @@ static int usbhid_restart_out_queue(struct usbhid_device *usbhid) | |||
207 | int kicked; | 207 | int kicked; |
208 | int r; | 208 | int r; |
209 | 209 | ||
210 | if (!hid) | 210 | if (!hid || test_bit(HID_RESET_PENDING, &usbhid->iofl) || |
211 | test_bit(HID_SUSPENDED, &usbhid->iofl)) | ||
211 | return 0; | 212 | return 0; |
212 | 213 | ||
213 | if ((kicked = (usbhid->outhead != usbhid->outtail))) { | 214 | if ((kicked = (usbhid->outhead != usbhid->outtail))) { |
214 | hid_dbg(hid, "Kicking head %d tail %d", usbhid->outhead, usbhid->outtail); | 215 | hid_dbg(hid, "Kicking head %d tail %d", usbhid->outhead, usbhid->outtail); |
215 | 216 | ||
217 | /* Try to wake up from autosuspend... */ | ||
216 | r = usb_autopm_get_interface_async(usbhid->intf); | 218 | r = usb_autopm_get_interface_async(usbhid->intf); |
217 | if (r < 0) | 219 | if (r < 0) |
218 | return r; | 220 | return r; |
221 | |||
222 | /* | ||
223 | * If still suspended, don't submit. Submission will | ||
224 | * occur if/when resume drains the queue. | ||
225 | */ | ||
226 | if (test_bit(HID_SUSPENDED, &usbhid->iofl)) { | ||
227 | usb_autopm_put_interface_no_suspend(usbhid->intf); | ||
228 | return r; | ||
229 | } | ||
230 | |||
219 | /* Asynchronously flush queue. */ | 231 | /* Asynchronously flush queue. */ |
220 | set_bit(HID_OUT_RUNNING, &usbhid->iofl); | 232 | set_bit(HID_OUT_RUNNING, &usbhid->iofl); |
221 | if (hid_submit_out(hid)) { | 233 | if (hid_submit_out(hid)) { |
@@ -234,15 +246,27 @@ static int usbhid_restart_ctrl_queue(struct usbhid_device *usbhid) | |||
234 | int r; | 246 | int r; |
235 | 247 | ||
236 | WARN_ON(hid == NULL); | 248 | WARN_ON(hid == NULL); |
237 | if (!hid) | 249 | if (!hid || test_bit(HID_RESET_PENDING, &usbhid->iofl) || |
250 | test_bit(HID_SUSPENDED, &usbhid->iofl)) | ||
238 | return 0; | 251 | return 0; |
239 | 252 | ||
240 | if ((kicked = (usbhid->ctrlhead != usbhid->ctrltail))) { | 253 | if ((kicked = (usbhid->ctrlhead != usbhid->ctrltail))) { |
241 | hid_dbg(hid, "Kicking head %d tail %d", usbhid->ctrlhead, usbhid->ctrltail); | 254 | hid_dbg(hid, "Kicking head %d tail %d", usbhid->ctrlhead, usbhid->ctrltail); |
242 | 255 | ||
256 | /* Try to wake up from autosuspend... */ | ||
243 | r = usb_autopm_get_interface_async(usbhid->intf); | 257 | r = usb_autopm_get_interface_async(usbhid->intf); |
244 | if (r < 0) | 258 | if (r < 0) |
245 | return r; | 259 | return r; |
260 | |||
261 | /* | ||
262 | * If still suspended, don't submit. Submission will | ||
263 | * occur if/when resume drains the queue. | ||
264 | */ | ||
265 | if (test_bit(HID_SUSPENDED, &usbhid->iofl)) { | ||
266 | usb_autopm_put_interface_no_suspend(usbhid->intf); | ||
267 | return r; | ||
268 | } | ||
269 | |||
246 | /* Asynchronously flush queue. */ | 270 | /* Asynchronously flush queue. */ |
247 | set_bit(HID_CTRL_RUNNING, &usbhid->iofl); | 271 | set_bit(HID_CTRL_RUNNING, &usbhid->iofl); |
248 | if (hid_submit_ctrl(hid)) { | 272 | if (hid_submit_ctrl(hid)) { |
@@ -331,9 +355,12 @@ static int hid_submit_out(struct hid_device *hid) | |||
331 | usbhid->urbout->transfer_buffer_length = ((report->size - 1) >> 3) + | 355 | usbhid->urbout->transfer_buffer_length = ((report->size - 1) >> 3) + |
332 | 1 + (report->id > 0); | 356 | 1 + (report->id > 0); |
333 | usbhid->urbout->dev = hid_to_usb_dev(hid); | 357 | usbhid->urbout->dev = hid_to_usb_dev(hid); |
334 | memcpy(usbhid->outbuf, raw_report, | 358 | if (raw_report) { |
335 | usbhid->urbout->transfer_buffer_length); | 359 | memcpy(usbhid->outbuf, raw_report, |
336 | kfree(raw_report); | 360 | usbhid->urbout->transfer_buffer_length); |
361 | kfree(raw_report); | ||
362 | usbhid->out[usbhid->outtail].raw_report = NULL; | ||
363 | } | ||
337 | 364 | ||
338 | dbg_hid("submitting out urb\n"); | 365 | dbg_hid("submitting out urb\n"); |
339 | 366 | ||
@@ -362,8 +389,11 @@ static int hid_submit_ctrl(struct hid_device *hid) | |||
362 | if (dir == USB_DIR_OUT) { | 389 | if (dir == USB_DIR_OUT) { |
363 | usbhid->urbctrl->pipe = usb_sndctrlpipe(hid_to_usb_dev(hid), 0); | 390 | usbhid->urbctrl->pipe = usb_sndctrlpipe(hid_to_usb_dev(hid), 0); |
364 | usbhid->urbctrl->transfer_buffer_length = len; | 391 | usbhid->urbctrl->transfer_buffer_length = len; |
365 | memcpy(usbhid->ctrlbuf, raw_report, len); | 392 | if (raw_report) { |
366 | kfree(raw_report); | 393 | memcpy(usbhid->ctrlbuf, raw_report, len); |
394 | kfree(raw_report); | ||
395 | usbhid->ctrl[usbhid->ctrltail].raw_report = NULL; | ||
396 | } | ||
367 | } else { | 397 | } else { |
368 | int maxpacket, padlen; | 398 | int maxpacket, padlen; |
369 | 399 | ||
@@ -407,16 +437,6 @@ static int hid_submit_ctrl(struct hid_device *hid) | |||
407 | * Output interrupt completion handler. | 437 | * Output interrupt completion handler. |
408 | */ | 438 | */ |
409 | 439 | ||
410 | static int irq_out_pump_restart(struct hid_device *hid) | ||
411 | { | ||
412 | struct usbhid_device *usbhid = hid->driver_data; | ||
413 | |||
414 | if (usbhid->outhead != usbhid->outtail) | ||
415 | return hid_submit_out(hid); | ||
416 | else | ||
417 | return -1; | ||
418 | } | ||
419 | |||
420 | static void hid_irq_out(struct urb *urb) | 440 | static void hid_irq_out(struct urb *urb) |
421 | { | 441 | { |
422 | struct hid_device *hid = urb->context; | 442 | struct hid_device *hid = urb->context; |
@@ -441,15 +461,17 @@ static void hid_irq_out(struct urb *urb) | |||
441 | 461 | ||
442 | spin_lock_irqsave(&usbhid->lock, flags); | 462 | spin_lock_irqsave(&usbhid->lock, flags); |
443 | 463 | ||
444 | if (unplug) | 464 | if (unplug) { |
445 | usbhid->outtail = usbhid->outhead; | 465 | usbhid->outtail = usbhid->outhead; |
446 | else | 466 | } else { |
447 | usbhid->outtail = (usbhid->outtail + 1) & (HID_OUTPUT_FIFO_SIZE - 1); | 467 | usbhid->outtail = (usbhid->outtail + 1) & (HID_OUTPUT_FIFO_SIZE - 1); |
448 | 468 | ||
449 | if (!irq_out_pump_restart(hid)) { | 469 | if (usbhid->outhead != usbhid->outtail && |
450 | /* Successfully submitted next urb in queue */ | 470 | hid_submit_out(hid) == 0) { |
451 | spin_unlock_irqrestore(&usbhid->lock, flags); | 471 | /* Successfully submitted next urb in queue */ |
452 | return; | 472 | spin_unlock_irqrestore(&usbhid->lock, flags); |
473 | return; | ||
474 | } | ||
453 | } | 475 | } |
454 | 476 | ||
455 | clear_bit(HID_OUT_RUNNING, &usbhid->iofl); | 477 | clear_bit(HID_OUT_RUNNING, &usbhid->iofl); |
@@ -461,15 +483,6 @@ static void hid_irq_out(struct urb *urb) | |||
461 | /* | 483 | /* |
462 | * Control pipe completion handler. | 484 | * Control pipe completion handler. |
463 | */ | 485 | */ |
464 | static int ctrl_pump_restart(struct hid_device *hid) | ||
465 | { | ||
466 | struct usbhid_device *usbhid = hid->driver_data; | ||
467 | |||
468 | if (usbhid->ctrlhead != usbhid->ctrltail) | ||
469 | return hid_submit_ctrl(hid); | ||
470 | else | ||
471 | return -1; | ||
472 | } | ||
473 | 486 | ||
474 | static void hid_ctrl(struct urb *urb) | 487 | static void hid_ctrl(struct urb *urb) |
475 | { | 488 | { |
@@ -498,15 +511,17 @@ static void hid_ctrl(struct urb *urb) | |||
498 | hid_warn(urb->dev, "ctrl urb status %d received\n", status); | 511 | hid_warn(urb->dev, "ctrl urb status %d received\n", status); |
499 | } | 512 | } |
500 | 513 | ||
501 | if (unplug) | 514 | if (unplug) { |
502 | usbhid->ctrltail = usbhid->ctrlhead; | 515 | usbhid->ctrltail = usbhid->ctrlhead; |
503 | else | 516 | } else { |
504 | usbhid->ctrltail = (usbhid->ctrltail + 1) & (HID_CONTROL_FIFO_SIZE - 1); | 517 | usbhid->ctrltail = (usbhid->ctrltail + 1) & (HID_CONTROL_FIFO_SIZE - 1); |
505 | 518 | ||
506 | if (!ctrl_pump_restart(hid)) { | 519 | if (usbhid->ctrlhead != usbhid->ctrltail && |
507 | /* Successfully submitted next urb in queue */ | 520 | hid_submit_ctrl(hid) == 0) { |
508 | spin_unlock(&usbhid->lock); | 521 | /* Successfully submitted next urb in queue */ |
509 | return; | 522 | spin_unlock(&usbhid->lock); |
523 | return; | ||
524 | } | ||
510 | } | 525 | } |
511 | 526 | ||
512 | clear_bit(HID_CTRL_RUNNING, &usbhid->iofl); | 527 | clear_bit(HID_CTRL_RUNNING, &usbhid->iofl); |
@@ -540,49 +555,36 @@ static void __usbhid_submit_report(struct hid_device *hid, struct hid_report *re | |||
540 | usbhid->out[usbhid->outhead].report = report; | 555 | usbhid->out[usbhid->outhead].report = report; |
541 | usbhid->outhead = head; | 556 | usbhid->outhead = head; |
542 | 557 | ||
543 | /* Try to awake from autosuspend... */ | 558 | /* If the queue isn't running, restart it */ |
544 | if (usb_autopm_get_interface_async(usbhid->intf) < 0) | 559 | if (!test_bit(HID_OUT_RUNNING, &usbhid->iofl)) { |
545 | return; | 560 | usbhid_restart_out_queue(usbhid); |
546 | 561 | ||
547 | /* | 562 | /* Otherwise see if an earlier request has timed out */ |
548 | * But if still suspended, leave urb enqueued, don't submit. | 563 | } else if (time_after(jiffies, usbhid->last_out + HZ * 5)) { |
549 | * Submission will occur if/when resume() drains the queue. | 564 | |
550 | */ | 565 | /* Prevent autosuspend following the unlink */ |
551 | if (test_bit(HID_REPORTED_IDLE, &usbhid->iofl)) | 566 | usb_autopm_get_interface_no_resume(usbhid->intf); |
552 | return; | ||
553 | 567 | ||
554 | if (!test_and_set_bit(HID_OUT_RUNNING, &usbhid->iofl)) { | ||
555 | if (hid_submit_out(hid)) { | ||
556 | clear_bit(HID_OUT_RUNNING, &usbhid->iofl); | ||
557 | usb_autopm_put_interface_async(usbhid->intf); | ||
558 | } | ||
559 | wake_up(&usbhid->wait); | ||
560 | } else { | ||
561 | /* | 568 | /* |
562 | * the queue is known to run | 569 | * Prevent resubmission in case the URB completes |
563 | * but an earlier request may be stuck | 570 | * before we can unlink it. We don't want to cancel |
564 | * we may need to time out | 571 | * the wrong transfer! |
565 | * no race because the URB is blocked under | ||
566 | * spinlock | ||
567 | */ | 572 | */ |
568 | if (time_after(jiffies, usbhid->last_out + HZ * 5)) { | 573 | usb_block_urb(usbhid->urbout); |
569 | usb_block_urb(usbhid->urbout); | ||
570 | /* drop lock to not deadlock if the callback is called */ | ||
571 | spin_unlock(&usbhid->lock); | ||
572 | usb_unlink_urb(usbhid->urbout); | ||
573 | spin_lock(&usbhid->lock); | ||
574 | usb_unblock_urb(usbhid->urbout); | ||
575 | /* | ||
576 | * if the unlinking has already completed | ||
577 | * the pump will have been stopped | ||
578 | * it must be restarted now | ||
579 | */ | ||
580 | if (!test_bit(HID_OUT_RUNNING, &usbhid->iofl)) | ||
581 | if (!irq_out_pump_restart(hid)) | ||
582 | set_bit(HID_OUT_RUNNING, &usbhid->iofl); | ||
583 | 574 | ||
575 | /* Drop lock to avoid deadlock if the callback runs */ | ||
576 | spin_unlock(&usbhid->lock); | ||
584 | 577 | ||
585 | } | 578 | usb_unlink_urb(usbhid->urbout); |
579 | spin_lock(&usbhid->lock); | ||
580 | usb_unblock_urb(usbhid->urbout); | ||
581 | |||
582 | /* Unlink might have stopped the queue */ | ||
583 | if (!test_bit(HID_OUT_RUNNING, &usbhid->iofl)) | ||
584 | usbhid_restart_out_queue(usbhid); | ||
585 | |||
586 | /* Now we can allow autosuspend again */ | ||
587 | usb_autopm_put_interface_async(usbhid->intf); | ||
586 | } | 588 | } |
587 | return; | 589 | return; |
588 | } | 590 | } |
@@ -604,47 +606,36 @@ static void __usbhid_submit_report(struct hid_device *hid, struct hid_report *re | |||
604 | usbhid->ctrl[usbhid->ctrlhead].dir = dir; | 606 | usbhid->ctrl[usbhid->ctrlhead].dir = dir; |
605 | usbhid->ctrlhead = head; | 607 | usbhid->ctrlhead = head; |
606 | 608 | ||
607 | /* Try to awake from autosuspend... */ | 609 | /* If the queue isn't running, restart it */ |
608 | if (usb_autopm_get_interface_async(usbhid->intf) < 0) | 610 | if (!test_bit(HID_CTRL_RUNNING, &usbhid->iofl)) { |
609 | return; | 611 | usbhid_restart_ctrl_queue(usbhid); |
610 | 612 | ||
611 | /* | 613 | /* Otherwise see if an earlier request has timed out */ |
612 | * If already suspended, leave urb enqueued, but don't submit. | 614 | } else if (time_after(jiffies, usbhid->last_ctrl + HZ * 5)) { |
613 | * Submission will occur if/when resume() drains the queue. | 615 | |
614 | */ | 616 | /* Prevent autosuspend following the unlink */ |
615 | if (test_bit(HID_REPORTED_IDLE, &usbhid->iofl)) | 617 | usb_autopm_get_interface_no_resume(usbhid->intf); |
616 | return; | ||
617 | 618 | ||
618 | if (!test_and_set_bit(HID_CTRL_RUNNING, &usbhid->iofl)) { | ||
619 | if (hid_submit_ctrl(hid)) { | ||
620 | clear_bit(HID_CTRL_RUNNING, &usbhid->iofl); | ||
621 | usb_autopm_put_interface_async(usbhid->intf); | ||
622 | } | ||
623 | wake_up(&usbhid->wait); | ||
624 | } else { | ||
625 | /* | 619 | /* |
626 | * the queue is known to run | 620 | * Prevent resubmission in case the URB completes |
627 | * but an earlier request may be stuck | 621 | * before we can unlink it. We don't want to cancel |
628 | * we may need to time out | 622 | * the wrong transfer! |
629 | * no race because the URB is blocked under | ||
630 | * spinlock | ||
631 | */ | 623 | */ |
632 | if (time_after(jiffies, usbhid->last_ctrl + HZ * 5)) { | 624 | usb_block_urb(usbhid->urbctrl); |
633 | usb_block_urb(usbhid->urbctrl); | 625 | |
634 | /* drop lock to not deadlock if the callback is called */ | 626 | /* Drop lock to avoid deadlock if the callback runs */ |
635 | spin_unlock(&usbhid->lock); | 627 | spin_unlock(&usbhid->lock); |
636 | usb_unlink_urb(usbhid->urbctrl); | 628 | |
637 | spin_lock(&usbhid->lock); | 629 | usb_unlink_urb(usbhid->urbctrl); |
638 | usb_unblock_urb(usbhid->urbctrl); | 630 | spin_lock(&usbhid->lock); |
639 | /* | 631 | usb_unblock_urb(usbhid->urbctrl); |
640 | * if the unlinking has already completed | 632 | |
641 | * the pump will have been stopped | 633 | /* Unlink might have stopped the queue */ |
642 | * it must be restarted now | 634 | if (!test_bit(HID_CTRL_RUNNING, &usbhid->iofl)) |
643 | */ | 635 | usbhid_restart_ctrl_queue(usbhid); |
644 | if (!test_bit(HID_CTRL_RUNNING, &usbhid->iofl)) | 636 | |
645 | if (!ctrl_pump_restart(hid)) | 637 | /* Now we can allow autosuspend again */ |
646 | set_bit(HID_CTRL_RUNNING, &usbhid->iofl); | 638 | usb_autopm_put_interface_async(usbhid->intf); |
647 | } | ||
648 | } | 639 | } |
649 | } | 640 | } |
650 | 641 | ||
@@ -1002,9 +993,10 @@ static int usbhid_output_raw_report(struct hid_device *hid, __u8 *buf, size_t co | |||
1002 | 993 | ||
1003 | static void usbhid_restart_queues(struct usbhid_device *usbhid) | 994 | static void usbhid_restart_queues(struct usbhid_device *usbhid) |
1004 | { | 995 | { |
1005 | if (usbhid->urbout) | 996 | if (usbhid->urbout && !test_bit(HID_OUT_RUNNING, &usbhid->iofl)) |
1006 | usbhid_restart_out_queue(usbhid); | 997 | usbhid_restart_out_queue(usbhid); |
1007 | usbhid_restart_ctrl_queue(usbhid); | 998 | if (!test_bit(HID_CTRL_RUNNING, &usbhid->iofl)) |
999 | usbhid_restart_ctrl_queue(usbhid); | ||
1008 | } | 1000 | } |
1009 | 1001 | ||
1010 | static void hid_free_buffers(struct usb_device *dev, struct hid_device *hid) | 1002 | static void hid_free_buffers(struct usb_device *dev, struct hid_device *hid) |
@@ -1471,11 +1463,38 @@ void usbhid_put_power(struct hid_device *hid) | |||
1471 | 1463 | ||
1472 | 1464 | ||
1473 | #ifdef CONFIG_PM | 1465 | #ifdef CONFIG_PM |
1466 | static int hid_resume_common(struct hid_device *hid, bool driver_suspended) | ||
1467 | { | ||
1468 | struct usbhid_device *usbhid = hid->driver_data; | ||
1469 | int status; | ||
1470 | |||
1471 | spin_lock_irq(&usbhid->lock); | ||
1472 | clear_bit(HID_SUSPENDED, &usbhid->iofl); | ||
1473 | usbhid_mark_busy(usbhid); | ||
1474 | |||
1475 | if (test_bit(HID_CLEAR_HALT, &usbhid->iofl) || | ||
1476 | test_bit(HID_RESET_PENDING, &usbhid->iofl)) | ||
1477 | schedule_work(&usbhid->reset_work); | ||
1478 | usbhid->retry_delay = 0; | ||
1479 | |||
1480 | usbhid_restart_queues(usbhid); | ||
1481 | spin_unlock_irq(&usbhid->lock); | ||
1482 | |||
1483 | status = hid_start_in(hid); | ||
1484 | if (status < 0) | ||
1485 | hid_io_error(hid); | ||
1486 | |||
1487 | if (driver_suspended && hid->driver && hid->driver->resume) | ||
1488 | status = hid->driver->resume(hid); | ||
1489 | return status; | ||
1490 | } | ||
1491 | |||
1474 | static int hid_suspend(struct usb_interface *intf, pm_message_t message) | 1492 | static int hid_suspend(struct usb_interface *intf, pm_message_t message) |
1475 | { | 1493 | { |
1476 | struct hid_device *hid = usb_get_intfdata(intf); | 1494 | struct hid_device *hid = usb_get_intfdata(intf); |
1477 | struct usbhid_device *usbhid = hid->driver_data; | 1495 | struct usbhid_device *usbhid = hid->driver_data; |
1478 | int status; | 1496 | int status; |
1497 | bool driver_suspended = false; | ||
1479 | 1498 | ||
1480 | if (PMSG_IS_AUTO(message)) { | 1499 | if (PMSG_IS_AUTO(message)) { |
1481 | spin_lock_irq(&usbhid->lock); /* Sync with error handler */ | 1500 | spin_lock_irq(&usbhid->lock); /* Sync with error handler */ |
@@ -1486,13 +1505,14 @@ static int hid_suspend(struct usb_interface *intf, pm_message_t message) | |||
1486 | && !test_bit(HID_KEYS_PRESSED, &usbhid->iofl) | 1505 | && !test_bit(HID_KEYS_PRESSED, &usbhid->iofl) |
1487 | && (!usbhid->ledcount || ignoreled)) | 1506 | && (!usbhid->ledcount || ignoreled)) |
1488 | { | 1507 | { |
1489 | set_bit(HID_REPORTED_IDLE, &usbhid->iofl); | 1508 | set_bit(HID_SUSPENDED, &usbhid->iofl); |
1490 | spin_unlock_irq(&usbhid->lock); | 1509 | spin_unlock_irq(&usbhid->lock); |
1491 | if (hid->driver && hid->driver->suspend) { | 1510 | if (hid->driver && hid->driver->suspend) { |
1492 | status = hid->driver->suspend(hid, message); | 1511 | status = hid->driver->suspend(hid, message); |
1493 | if (status < 0) | 1512 | if (status < 0) |
1494 | return status; | 1513 | goto failed; |
1495 | } | 1514 | } |
1515 | driver_suspended = true; | ||
1496 | } else { | 1516 | } else { |
1497 | usbhid_mark_busy(usbhid); | 1517 | usbhid_mark_busy(usbhid); |
1498 | spin_unlock_irq(&usbhid->lock); | 1518 | spin_unlock_irq(&usbhid->lock); |
@@ -1505,11 +1525,14 @@ static int hid_suspend(struct usb_interface *intf, pm_message_t message) | |||
1505 | if (status < 0) | 1525 | if (status < 0) |
1506 | return status; | 1526 | return status; |
1507 | } | 1527 | } |
1528 | driver_suspended = true; | ||
1508 | spin_lock_irq(&usbhid->lock); | 1529 | spin_lock_irq(&usbhid->lock); |
1509 | set_bit(HID_REPORTED_IDLE, &usbhid->iofl); | 1530 | set_bit(HID_SUSPENDED, &usbhid->iofl); |
1510 | spin_unlock_irq(&usbhid->lock); | 1531 | spin_unlock_irq(&usbhid->lock); |
1511 | if (usbhid_wait_io(hid) < 0) | 1532 | if (usbhid_wait_io(hid) < 0) { |
1512 | return -EIO; | 1533 | status = -EIO; |
1534 | goto failed; | ||
1535 | } | ||
1513 | } | 1536 | } |
1514 | 1537 | ||
1515 | hid_cancel_delayed_stuff(usbhid); | 1538 | hid_cancel_delayed_stuff(usbhid); |
@@ -1517,14 +1540,15 @@ static int hid_suspend(struct usb_interface *intf, pm_message_t message) | |||
1517 | 1540 | ||
1518 | if (PMSG_IS_AUTO(message) && test_bit(HID_KEYS_PRESSED, &usbhid->iofl)) { | 1541 | if (PMSG_IS_AUTO(message) && test_bit(HID_KEYS_PRESSED, &usbhid->iofl)) { |
1519 | /* lost race against keypresses */ | 1542 | /* lost race against keypresses */ |
1520 | status = hid_start_in(hid); | 1543 | status = -EBUSY; |
1521 | if (status < 0) | 1544 | goto failed; |
1522 | hid_io_error(hid); | ||
1523 | usbhid_mark_busy(usbhid); | ||
1524 | return -EBUSY; | ||
1525 | } | 1545 | } |
1526 | dev_dbg(&intf->dev, "suspend\n"); | 1546 | dev_dbg(&intf->dev, "suspend\n"); |
1527 | return 0; | 1547 | return 0; |
1548 | |||
1549 | failed: | ||
1550 | hid_resume_common(hid, driver_suspended); | ||
1551 | return status; | ||
1528 | } | 1552 | } |
1529 | 1553 | ||
1530 | static int hid_resume(struct usb_interface *intf) | 1554 | static int hid_resume(struct usb_interface *intf) |
@@ -1536,23 +1560,7 @@ static int hid_resume(struct usb_interface *intf) | |||
1536 | if (!test_bit(HID_STARTED, &usbhid->iofl)) | 1560 | if (!test_bit(HID_STARTED, &usbhid->iofl)) |
1537 | return 0; | 1561 | return 0; |
1538 | 1562 | ||
1539 | clear_bit(HID_REPORTED_IDLE, &usbhid->iofl); | 1563 | status = hid_resume_common(hid, true); |
1540 | usbhid_mark_busy(usbhid); | ||
1541 | |||
1542 | if (test_bit(HID_CLEAR_HALT, &usbhid->iofl) || | ||
1543 | test_bit(HID_RESET_PENDING, &usbhid->iofl)) | ||
1544 | schedule_work(&usbhid->reset_work); | ||
1545 | usbhid->retry_delay = 0; | ||
1546 | status = hid_start_in(hid); | ||
1547 | if (status < 0) | ||
1548 | hid_io_error(hid); | ||
1549 | usbhid_restart_queues(usbhid); | ||
1550 | |||
1551 | if (status >= 0 && hid->driver && hid->driver->resume) { | ||
1552 | int ret = hid->driver->resume(hid); | ||
1553 | if (ret < 0) | ||
1554 | status = ret; | ||
1555 | } | ||
1556 | dev_dbg(&intf->dev, "resume status %d\n", status); | 1564 | dev_dbg(&intf->dev, "resume status %d\n", status); |
1557 | return 0; | 1565 | return 0; |
1558 | } | 1566 | } |
@@ -1563,7 +1571,7 @@ static int hid_reset_resume(struct usb_interface *intf) | |||
1563 | struct usbhid_device *usbhid = hid->driver_data; | 1571 | struct usbhid_device *usbhid = hid->driver_data; |
1564 | int status; | 1572 | int status; |
1565 | 1573 | ||
1566 | clear_bit(HID_REPORTED_IDLE, &usbhid->iofl); | 1574 | clear_bit(HID_SUSPENDED, &usbhid->iofl); |
1567 | status = hid_post_reset(intf); | 1575 | status = hid_post_reset(intf); |
1568 | if (status >= 0 && hid->driver && hid->driver->reset_resume) { | 1576 | if (status >= 0 && hid->driver && hid->driver->reset_resume) { |
1569 | int ret = hid->driver->reset_resume(hid); | 1577 | int ret = hid->driver->reset_resume(hid); |
diff --git a/drivers/hid/usbhid/usbhid.h b/drivers/hid/usbhid/usbhid.h index 1883d7b94870..bd87a61e5303 100644 --- a/drivers/hid/usbhid/usbhid.h +++ b/drivers/hid/usbhid/usbhid.h | |||
@@ -53,7 +53,6 @@ struct usb_interface *usbhid_find_interface(int minor); | |||
53 | #define HID_CLEAR_HALT 6 | 53 | #define HID_CLEAR_HALT 6 |
54 | #define HID_DISCONNECTED 7 | 54 | #define HID_DISCONNECTED 7 |
55 | #define HID_STARTED 8 | 55 | #define HID_STARTED 8 |
56 | #define HID_REPORTED_IDLE 9 | ||
57 | #define HID_KEYS_PRESSED 10 | 56 | #define HID_KEYS_PRESSED 10 |
58 | #define HID_NO_BANDWIDTH 11 | 57 | #define HID_NO_BANDWIDTH 11 |
59 | 58 | ||
diff --git a/include/linux/Kbuild b/include/linux/Kbuild index 8760be30b375..cb2a7d1ad47b 100644 --- a/include/linux/Kbuild +++ b/include/linux/Kbuild | |||
@@ -376,6 +376,7 @@ header-y += tty.h | |||
376 | header-y += types.h | 376 | header-y += types.h |
377 | header-y += udf_fs_i.h | 377 | header-y += udf_fs_i.h |
378 | header-y += udp.h | 378 | header-y += udp.h |
379 | header-y += uhid.h | ||
379 | header-y += uinput.h | 380 | header-y += uinput.h |
380 | header-y += uio.h | 381 | header-y += uio.h |
381 | header-y += ultrasound.h | 382 | header-y += ultrasound.h |
diff --git a/include/linux/hid.h b/include/linux/hid.h index 449fa385703d..42970de1b40c 100644 --- a/include/linux/hid.h +++ b/include/linux/hid.h | |||
@@ -200,6 +200,7 @@ struct hid_item { | |||
200 | #define HID_UP_DIGITIZER 0x000d0000 | 200 | #define HID_UP_DIGITIZER 0x000d0000 |
201 | #define HID_UP_PID 0x000f0000 | 201 | #define HID_UP_PID 0x000f0000 |
202 | #define HID_UP_HPVENDOR 0xff7f0000 | 202 | #define HID_UP_HPVENDOR 0xff7f0000 |
203 | #define HID_UP_HPVENDOR2 0xff010000 | ||
203 | #define HID_UP_MSVENDOR 0xff000000 | 204 | #define HID_UP_MSVENDOR 0xff000000 |
204 | #define HID_UP_CUSTOM 0x00ff0000 | 205 | #define HID_UP_CUSTOM 0x00ff0000 |
205 | #define HID_UP_LOGIVENDOR 0xffbc0000 | 206 | #define HID_UP_LOGIVENDOR 0xffbc0000 |
diff --git a/include/linux/uhid.h b/include/linux/uhid.h new file mode 100644 index 000000000000..9c6974f16966 --- /dev/null +++ b/include/linux/uhid.h | |||
@@ -0,0 +1,104 @@ | |||
1 | #ifndef __UHID_H_ | ||
2 | #define __UHID_H_ | ||
3 | |||
4 | /* | ||
5 | * User-space I/O driver support for HID subsystem | ||
6 | * Copyright (c) 2012 David Herrmann | ||
7 | */ | ||
8 | |||
9 | /* | ||
10 | * This program is free software; you can redistribute it and/or modify it | ||
11 | * under the terms of the GNU General Public License as published by the Free | ||
12 | * Software Foundation; either version 2 of the License, or (at your option) | ||
13 | * any later version. | ||
14 | */ | ||
15 | |||
16 | /* | ||
17 | * Public header for user-space communication. We try to keep every structure | ||
18 | * aligned but to be safe we also use __attribute__((__packed__)). Therefore, | ||
19 | * the communication should be ABI compatible even between architectures. | ||
20 | */ | ||
21 | |||
22 | #include <linux/input.h> | ||
23 | #include <linux/types.h> | ||
24 | |||
25 | enum uhid_event_type { | ||
26 | UHID_CREATE, | ||
27 | UHID_DESTROY, | ||
28 | UHID_START, | ||
29 | UHID_STOP, | ||
30 | UHID_OPEN, | ||
31 | UHID_CLOSE, | ||
32 | UHID_OUTPUT, | ||
33 | UHID_OUTPUT_EV, | ||
34 | UHID_INPUT, | ||
35 | UHID_FEATURE, | ||
36 | UHID_FEATURE_ANSWER, | ||
37 | }; | ||
38 | |||
39 | struct uhid_create_req { | ||
40 | __u8 name[128]; | ||
41 | __u8 phys[64]; | ||
42 | __u8 uniq[64]; | ||
43 | __u8 __user *rd_data; | ||
44 | __u16 rd_size; | ||
45 | |||
46 | __u16 bus; | ||
47 | __u32 vendor; | ||
48 | __u32 product; | ||
49 | __u32 version; | ||
50 | __u32 country; | ||
51 | } __attribute__((__packed__)); | ||
52 | |||
53 | #define UHID_DATA_MAX 4096 | ||
54 | |||
55 | enum uhid_report_type { | ||
56 | UHID_FEATURE_REPORT, | ||
57 | UHID_OUTPUT_REPORT, | ||
58 | UHID_INPUT_REPORT, | ||
59 | }; | ||
60 | |||
61 | struct uhid_input_req { | ||
62 | __u8 data[UHID_DATA_MAX]; | ||
63 | __u16 size; | ||
64 | } __attribute__((__packed__)); | ||
65 | |||
66 | struct uhid_output_req { | ||
67 | __u8 data[UHID_DATA_MAX]; | ||
68 | __u16 size; | ||
69 | __u8 rtype; | ||
70 | } __attribute__((__packed__)); | ||
71 | |||
72 | struct uhid_output_ev_req { | ||
73 | __u16 type; | ||
74 | __u16 code; | ||
75 | __s32 value; | ||
76 | } __attribute__((__packed__)); | ||
77 | |||
78 | struct uhid_feature_req { | ||
79 | __u32 id; | ||
80 | __u8 rnum; | ||
81 | __u8 rtype; | ||
82 | } __attribute__((__packed__)); | ||
83 | |||
84 | struct uhid_feature_answer_req { | ||
85 | __u32 id; | ||
86 | __u16 err; | ||
87 | __u16 size; | ||
88 | __u8 data[UHID_DATA_MAX]; | ||
89 | }; | ||
90 | |||
91 | struct uhid_event { | ||
92 | __u32 type; | ||
93 | |||
94 | union { | ||
95 | struct uhid_create_req create; | ||
96 | struct uhid_input_req input; | ||
97 | struct uhid_output_req output; | ||
98 | struct uhid_output_ev_req output_ev; | ||
99 | struct uhid_feature_req feature; | ||
100 | struct uhid_feature_answer_req feature_answer; | ||
101 | } u; | ||
102 | } __attribute__((__packed__)); | ||
103 | |||
104 | #endif /* __UHID_H_ */ | ||
diff --git a/samples/uhid/Makefile b/samples/uhid/Makefile new file mode 100644 index 000000000000..c95a696560a7 --- /dev/null +++ b/samples/uhid/Makefile | |||
@@ -0,0 +1,10 @@ | |||
1 | # kbuild trick to avoid linker error. Can be omitted if a module is built. | ||
2 | obj- := dummy.o | ||
3 | |||
4 | # List of programs to build | ||
5 | hostprogs-y := uhid-example | ||
6 | |||
7 | # Tell kbuild to always build the programs | ||
8 | always := $(hostprogs-y) | ||
9 | |||
10 | HOSTCFLAGS_uhid-example.o += -I$(objtree)/usr/include | ||
diff --git a/samples/uhid/uhid-example.c b/samples/uhid/uhid-example.c new file mode 100644 index 000000000000..03ce3c059a5e --- /dev/null +++ b/samples/uhid/uhid-example.c | |||
@@ -0,0 +1,381 @@ | |||
1 | /* | ||
2 | * UHID Example | ||
3 | * | ||
4 | * Copyright (c) 2012 David Herrmann <dh.herrmann@googlemail.com> | ||
5 | * | ||
6 | * The code may be used by anyone for any purpose, | ||
7 | * and can serve as a starting point for developing | ||
8 | * applications using uhid. | ||
9 | */ | ||
10 | |||
11 | /* UHID Example | ||
12 | * This example emulates a basic 3 buttons mouse with wheel over UHID. Run this | ||
13 | * program as root and then use the following keys to control the mouse: | ||
14 | * q: Quit the application | ||
15 | * 1: Toggle left button (down, up, ...) | ||
16 | * 2: Toggle right button | ||
17 | * 3: Toggle middle button | ||
18 | * a: Move mouse left | ||
19 | * d: Move mouse right | ||
20 | * w: Move mouse up | ||
21 | * s: Move mouse down | ||
22 | * r: Move wheel up | ||
23 | * f: Move wheel down | ||
24 | * | ||
25 | * If uhid is not available as /dev/uhid, then you can pass a different path as | ||
26 | * first argument. | ||
27 | * If <linux/uhid.h> is not installed in /usr, then compile this with: | ||
28 | * gcc -o ./uhid_test -Wall -I./include ./samples/uhid/uhid-example.c | ||
29 | * And ignore the warning about kernel headers. However, it is recommended to | ||
30 | * use the installed uhid.h if available. | ||
31 | */ | ||
32 | |||
33 | #include <errno.h> | ||
34 | #include <fcntl.h> | ||
35 | #include <poll.h> | ||
36 | #include <stdbool.h> | ||
37 | #include <stdio.h> | ||
38 | #include <stdlib.h> | ||
39 | #include <string.h> | ||
40 | #include <termios.h> | ||
41 | #include <unistd.h> | ||
42 | #include <linux/uhid.h> | ||
43 | |||
44 | /* HID Report Desciptor | ||
45 | * We emulate a basic 3 button mouse with wheel. This is the report-descriptor | ||
46 | * as the kernel will parse it: | ||
47 | * | ||
48 | * INPUT[INPUT] | ||
49 | * Field(0) | ||
50 | * Physical(GenericDesktop.Pointer) | ||
51 | * Application(GenericDesktop.Mouse) | ||
52 | * Usage(3) | ||
53 | * Button.0001 | ||
54 | * Button.0002 | ||
55 | * Button.0003 | ||
56 | * Logical Minimum(0) | ||
57 | * Logical Maximum(1) | ||
58 | * Report Size(1) | ||
59 | * Report Count(3) | ||
60 | * Report Offset(0) | ||
61 | * Flags( Variable Absolute ) | ||
62 | * Field(1) | ||
63 | * Physical(GenericDesktop.Pointer) | ||
64 | * Application(GenericDesktop.Mouse) | ||
65 | * Usage(3) | ||
66 | * GenericDesktop.X | ||
67 | * GenericDesktop.Y | ||
68 | * GenericDesktop.Wheel | ||
69 | * Logical Minimum(-128) | ||
70 | * Logical Maximum(127) | ||
71 | * Report Size(8) | ||
72 | * Report Count(3) | ||
73 | * Report Offset(8) | ||
74 | * Flags( Variable Relative ) | ||
75 | * | ||
76 | * This is the mapping that we expect: | ||
77 | * Button.0001 ---> Key.LeftBtn | ||
78 | * Button.0002 ---> Key.RightBtn | ||
79 | * Button.0003 ---> Key.MiddleBtn | ||
80 | * GenericDesktop.X ---> Relative.X | ||
81 | * GenericDesktop.Y ---> Relative.Y | ||
82 | * GenericDesktop.Wheel ---> Relative.Wheel | ||
83 | * | ||
84 | * This information can be verified by reading /sys/kernel/debug/hid/<dev>/rdesc | ||
85 | * This file should print the same information as showed above. | ||
86 | */ | ||
87 | |||
88 | static unsigned char rdesc[] = { | ||
89 | 0x05, 0x01, 0x09, 0x02, 0xa1, 0x01, 0x09, 0x01, | ||
90 | 0xa1, 0x00, 0x05, 0x09, 0x19, 0x01, 0x29, 0x03, | ||
91 | 0x15, 0x00, 0x25, 0x01, 0x95, 0x03, 0x75, 0x01, | ||
92 | 0x81, 0x02, 0x95, 0x01, 0x75, 0x05, 0x81, 0x01, | ||
93 | 0x05, 0x01, 0x09, 0x30, 0x09, 0x31, 0x09, 0x38, | ||
94 | 0x15, 0x80, 0x25, 0x7f, 0x75, 0x08, 0x95, 0x03, | ||
95 | 0x81, 0x06, 0xc0, 0xc0, | ||
96 | }; | ||
97 | |||
98 | static int uhid_write(int fd, const struct uhid_event *ev) | ||
99 | { | ||
100 | ssize_t ret; | ||
101 | |||
102 | ret = write(fd, ev, sizeof(*ev)); | ||
103 | if (ret < 0) { | ||
104 | fprintf(stderr, "Cannot write to uhid: %m\n"); | ||
105 | return -errno; | ||
106 | } else if (ret != sizeof(*ev)) { | ||
107 | fprintf(stderr, "Wrong size written to uhid: %ld != %lu\n", | ||
108 | ret, sizeof(ev)); | ||
109 | return -EFAULT; | ||
110 | } else { | ||
111 | return 0; | ||
112 | } | ||
113 | } | ||
114 | |||
115 | static int create(int fd) | ||
116 | { | ||
117 | struct uhid_event ev; | ||
118 | |||
119 | memset(&ev, 0, sizeof(ev)); | ||
120 | ev.type = UHID_CREATE; | ||
121 | strcpy((char*)ev.u.create.name, "test-uhid-device"); | ||
122 | ev.u.create.rd_data = rdesc; | ||
123 | ev.u.create.rd_size = sizeof(rdesc); | ||
124 | ev.u.create.bus = BUS_USB; | ||
125 | ev.u.create.vendor = 0x15d9; | ||
126 | ev.u.create.product = 0x0a37; | ||
127 | ev.u.create.version = 0; | ||
128 | ev.u.create.country = 0; | ||
129 | |||
130 | return uhid_write(fd, &ev); | ||
131 | } | ||
132 | |||
133 | static void destroy(int fd) | ||
134 | { | ||
135 | struct uhid_event ev; | ||
136 | |||
137 | memset(&ev, 0, sizeof(ev)); | ||
138 | ev.type = UHID_DESTROY; | ||
139 | |||
140 | uhid_write(fd, &ev); | ||
141 | } | ||
142 | |||
143 | static int event(int fd) | ||
144 | { | ||
145 | struct uhid_event ev; | ||
146 | ssize_t ret; | ||
147 | |||
148 | memset(&ev, 0, sizeof(ev)); | ||
149 | ret = read(fd, &ev, sizeof(ev)); | ||
150 | if (ret == 0) { | ||
151 | fprintf(stderr, "Read HUP on uhid-cdev\n"); | ||
152 | return -EFAULT; | ||
153 | } else if (ret < 0) { | ||
154 | fprintf(stderr, "Cannot read uhid-cdev: %m\n"); | ||
155 | return -errno; | ||
156 | } else if (ret != sizeof(ev)) { | ||
157 | fprintf(stderr, "Invalid size read from uhid-dev: %ld != %lu\n", | ||
158 | ret, sizeof(ev)); | ||
159 | return -EFAULT; | ||
160 | } | ||
161 | |||
162 | switch (ev.type) { | ||
163 | case UHID_START: | ||
164 | fprintf(stderr, "UHID_START from uhid-dev\n"); | ||
165 | break; | ||
166 | case UHID_STOP: | ||
167 | fprintf(stderr, "UHID_STOP from uhid-dev\n"); | ||
168 | break; | ||
169 | case UHID_OPEN: | ||
170 | fprintf(stderr, "UHID_OPEN from uhid-dev\n"); | ||
171 | break; | ||
172 | case UHID_CLOSE: | ||
173 | fprintf(stderr, "UHID_CLOSE from uhid-dev\n"); | ||
174 | break; | ||
175 | case UHID_OUTPUT: | ||
176 | fprintf(stderr, "UHID_OUTPUT from uhid-dev\n"); | ||
177 | break; | ||
178 | case UHID_OUTPUT_EV: | ||
179 | fprintf(stderr, "UHID_OUTPUT_EV from uhid-dev\n"); | ||
180 | break; | ||
181 | default: | ||
182 | fprintf(stderr, "Invalid event from uhid-dev: %u\n", ev.type); | ||
183 | } | ||
184 | |||
185 | return 0; | ||
186 | } | ||
187 | |||
188 | static bool btn1_down; | ||
189 | static bool btn2_down; | ||
190 | static bool btn3_down; | ||
191 | static signed char abs_hor; | ||
192 | static signed char abs_ver; | ||
193 | static signed char wheel; | ||
194 | |||
195 | static int send_event(int fd) | ||
196 | { | ||
197 | struct uhid_event ev; | ||
198 | |||
199 | memset(&ev, 0, sizeof(ev)); | ||
200 | ev.type = UHID_INPUT; | ||
201 | ev.u.input.size = 4; | ||
202 | |||
203 | if (btn1_down) | ||
204 | ev.u.input.data[0] |= 0x1; | ||
205 | if (btn2_down) | ||
206 | ev.u.input.data[0] |= 0x2; | ||
207 | if (btn3_down) | ||
208 | ev.u.input.data[0] |= 0x4; | ||
209 | |||
210 | ev.u.input.data[1] = abs_hor; | ||
211 | ev.u.input.data[2] = abs_ver; | ||
212 | ev.u.input.data[3] = wheel; | ||
213 | |||
214 | return uhid_write(fd, &ev); | ||
215 | } | ||
216 | |||
217 | static int keyboard(int fd) | ||
218 | { | ||
219 | char buf[128]; | ||
220 | ssize_t ret, i; | ||
221 | |||
222 | ret = read(STDIN_FILENO, buf, sizeof(buf)); | ||
223 | if (ret == 0) { | ||
224 | fprintf(stderr, "Read HUP on stdin\n"); | ||
225 | return -EFAULT; | ||
226 | } else if (ret < 0) { | ||
227 | fprintf(stderr, "Cannot read stdin: %m\n"); | ||
228 | return -errno; | ||
229 | } | ||
230 | |||
231 | for (i = 0; i < ret; ++i) { | ||
232 | switch (buf[i]) { | ||
233 | case '1': | ||
234 | btn1_down = !btn1_down; | ||
235 | ret = send_event(fd); | ||
236 | if (ret) | ||
237 | return ret; | ||
238 | break; | ||
239 | case '2': | ||
240 | btn2_down = !btn2_down; | ||
241 | ret = send_event(fd); | ||
242 | if (ret) | ||
243 | return ret; | ||
244 | break; | ||
245 | case '3': | ||
246 | btn3_down = !btn3_down; | ||
247 | ret = send_event(fd); | ||
248 | if (ret) | ||
249 | return ret; | ||
250 | break; | ||
251 | case 'a': | ||
252 | abs_hor = -20; | ||
253 | ret = send_event(fd); | ||
254 | abs_hor = 0; | ||
255 | if (ret) | ||
256 | return ret; | ||
257 | break; | ||
258 | case 'd': | ||
259 | abs_hor = 20; | ||
260 | ret = send_event(fd); | ||
261 | abs_hor = 0; | ||
262 | if (ret) | ||
263 | return ret; | ||
264 | break; | ||
265 | case 'w': | ||
266 | abs_ver = -20; | ||
267 | ret = send_event(fd); | ||
268 | abs_ver = 0; | ||
269 | if (ret) | ||
270 | return ret; | ||
271 | break; | ||
272 | case 's': | ||
273 | abs_ver = 20; | ||
274 | ret = send_event(fd); | ||
275 | abs_ver = 0; | ||
276 | if (ret) | ||
277 | return ret; | ||
278 | break; | ||
279 | case 'r': | ||
280 | wheel = 1; | ||
281 | ret = send_event(fd); | ||
282 | wheel = 0; | ||
283 | if (ret) | ||
284 | return ret; | ||
285 | break; | ||
286 | case 'f': | ||
287 | wheel = -1; | ||
288 | ret = send_event(fd); | ||
289 | wheel = 0; | ||
290 | if (ret) | ||
291 | return ret; | ||
292 | break; | ||
293 | case 'q': | ||
294 | return -ECANCELED; | ||
295 | default: | ||
296 | fprintf(stderr, "Invalid input: %c\n", buf[i]); | ||
297 | } | ||
298 | } | ||
299 | |||
300 | return 0; | ||
301 | } | ||
302 | |||
303 | int main(int argc, char **argv) | ||
304 | { | ||
305 | int fd; | ||
306 | const char *path = "/dev/uhid"; | ||
307 | struct pollfd pfds[2]; | ||
308 | int ret; | ||
309 | struct termios state; | ||
310 | |||
311 | ret = tcgetattr(STDIN_FILENO, &state); | ||
312 | if (ret) { | ||
313 | fprintf(stderr, "Cannot get tty state\n"); | ||
314 | } else { | ||
315 | state.c_lflag &= ~ICANON; | ||
316 | state.c_cc[VMIN] = 1; | ||
317 | ret = tcsetattr(STDIN_FILENO, TCSANOW, &state); | ||
318 | if (ret) | ||
319 | fprintf(stderr, "Cannot set tty state\n"); | ||
320 | } | ||
321 | |||
322 | if (argc >= 2) { | ||
323 | if (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) { | ||
324 | fprintf(stderr, "Usage: %s [%s]\n", argv[0], path); | ||
325 | return EXIT_SUCCESS; | ||
326 | } else { | ||
327 | path = argv[1]; | ||
328 | } | ||
329 | } | ||
330 | |||
331 | fprintf(stderr, "Open uhid-cdev %s\n", path); | ||
332 | fd = open(path, O_RDWR | O_CLOEXEC); | ||
333 | if (fd < 0) { | ||
334 | fprintf(stderr, "Cannot open uhid-cdev %s: %m\n", path); | ||
335 | return EXIT_FAILURE; | ||
336 | } | ||
337 | |||
338 | fprintf(stderr, "Create uhid device\n"); | ||
339 | ret = create(fd); | ||
340 | if (ret) { | ||
341 | close(fd); | ||
342 | return EXIT_FAILURE; | ||
343 | } | ||
344 | |||
345 | pfds[0].fd = STDIN_FILENO; | ||
346 | pfds[0].events = POLLIN; | ||
347 | pfds[1].fd = fd; | ||
348 | pfds[1].events = POLLIN; | ||
349 | |||
350 | fprintf(stderr, "Press 'q' to quit...\n"); | ||
351 | while (1) { | ||
352 | ret = poll(pfds, 2, -1); | ||
353 | if (ret < 0) { | ||
354 | fprintf(stderr, "Cannot poll for fds: %m\n"); | ||
355 | break; | ||
356 | } | ||
357 | if (pfds[0].revents & POLLHUP) { | ||
358 | fprintf(stderr, "Received HUP on stdin\n"); | ||
359 | break; | ||
360 | } | ||
361 | if (pfds[1].revents & POLLHUP) { | ||
362 | fprintf(stderr, "Received HUP on uhid-cdev\n"); | ||
363 | break; | ||
364 | } | ||
365 | |||
366 | if (pfds[0].revents & POLLIN) { | ||
367 | ret = keyboard(fd); | ||
368 | if (ret) | ||
369 | break; | ||
370 | } | ||
371 | if (pfds[1].revents & POLLIN) { | ||
372 | ret = event(fd); | ||
373 | if (ret) | ||
374 | break; | ||
375 | } | ||
376 | } | ||
377 | |||
378 | fprintf(stderr, "Destroy uhid device\n"); | ||
379 | destroy(fd); | ||
380 | return EXIT_SUCCESS; | ||
381 | } | ||