1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * HID driver for Logitech receivers |
4 | * |
5 | * Copyright (c) 2011 Logitech |
6 | */ |
7 | |
8 | |
9 | |
10 | #include <linux/device.h> |
11 | #include <linux/hid.h> |
12 | #include <linux/module.h> |
13 | #include <linux/kfifo.h> |
14 | #include <linux/delay.h> |
15 | #include <linux/usb.h> /* For to_usb_interface for kvm extra intf check */ |
16 | #include <asm/unaligned.h> |
17 | #include "hid-ids.h" |
18 | |
19 | #define DJ_MAX_PAIRED_DEVICES 7 |
20 | #define DJ_MAX_NUMBER_NOTIFS 8 |
21 | #define DJ_RECEIVER_INDEX 0 |
22 | #define DJ_DEVICE_INDEX_MIN 1 |
23 | #define DJ_DEVICE_INDEX_MAX 7 |
24 | |
25 | #define DJREPORT_SHORT_LENGTH 15 |
26 | #define DJREPORT_LONG_LENGTH 32 |
27 | |
28 | #define REPORT_ID_DJ_SHORT 0x20 |
29 | #define REPORT_ID_DJ_LONG 0x21 |
30 | |
31 | #define REPORT_ID_HIDPP_SHORT 0x10 |
32 | #define REPORT_ID_HIDPP_LONG 0x11 |
33 | #define REPORT_ID_HIDPP_VERY_LONG 0x12 |
34 | |
35 | #define HIDPP_REPORT_SHORT_LENGTH 7 |
36 | #define HIDPP_REPORT_LONG_LENGTH 20 |
37 | |
38 | #define HIDPP_RECEIVER_INDEX 0xff |
39 | |
40 | #define REPORT_TYPE_RFREPORT_FIRST 0x01 |
41 | #define REPORT_TYPE_RFREPORT_LAST 0x1F |
42 | |
43 | /* Command Switch to DJ mode */ |
44 | #define REPORT_TYPE_CMD_SWITCH 0x80 |
45 | #define CMD_SWITCH_PARAM_DEVBITFIELD 0x00 |
46 | #define CMD_SWITCH_PARAM_TIMEOUT_SECONDS 0x01 |
47 | #define TIMEOUT_NO_KEEPALIVE 0x00 |
48 | |
49 | /* Command to Get the list of Paired devices */ |
50 | #define REPORT_TYPE_CMD_GET_PAIRED_DEVICES 0x81 |
51 | |
52 | /* Device Paired Notification */ |
53 | #define REPORT_TYPE_NOTIF_DEVICE_PAIRED 0x41 |
54 | #define SPFUNCTION_MORE_NOTIF_EXPECTED 0x01 |
55 | #define SPFUNCTION_DEVICE_LIST_EMPTY 0x02 |
56 | #define DEVICE_PAIRED_PARAM_SPFUNCTION 0x00 |
57 | #define DEVICE_PAIRED_PARAM_EQUAD_ID_LSB 0x01 |
58 | #define DEVICE_PAIRED_PARAM_EQUAD_ID_MSB 0x02 |
59 | #define DEVICE_PAIRED_RF_REPORT_TYPE 0x03 |
60 | |
61 | /* Device Un-Paired Notification */ |
62 | #define REPORT_TYPE_NOTIF_DEVICE_UNPAIRED 0x40 |
63 | |
64 | /* Connection Status Notification */ |
65 | #define REPORT_TYPE_NOTIF_CONNECTION_STATUS 0x42 |
66 | #define CONNECTION_STATUS_PARAM_STATUS 0x00 |
67 | #define STATUS_LINKLOSS 0x01 |
68 | |
69 | /* Error Notification */ |
70 | #define REPORT_TYPE_NOTIF_ERROR 0x7F |
71 | #define NOTIF_ERROR_PARAM_ETYPE 0x00 |
72 | #define ETYPE_KEEPALIVE_TIMEOUT 0x01 |
73 | |
74 | /* supported DJ HID && RF report types */ |
75 | #define REPORT_TYPE_KEYBOARD 0x01 |
76 | #define REPORT_TYPE_MOUSE 0x02 |
77 | #define REPORT_TYPE_CONSUMER_CONTROL 0x03 |
78 | #define REPORT_TYPE_SYSTEM_CONTROL 0x04 |
79 | #define REPORT_TYPE_MEDIA_CENTER 0x08 |
80 | #define REPORT_TYPE_LEDS 0x0E |
81 | |
82 | /* RF Report types bitfield */ |
83 | #define STD_KEYBOARD BIT(1) |
84 | #define STD_MOUSE BIT(2) |
85 | #define MULTIMEDIA BIT(3) |
86 | #define POWER_KEYS BIT(4) |
87 | #define KBD_MOUSE BIT(5) |
88 | #define MEDIA_CENTER BIT(8) |
89 | #define KBD_LEDS BIT(14) |
90 | /* Fake (bitnr > NUMBER_OF_HID_REPORTS) bit to track HID++ capability */ |
91 | #define HIDPP BIT_ULL(63) |
92 | |
93 | /* HID++ Device Connected Notification */ |
94 | #define REPORT_TYPE_NOTIF_DEVICE_CONNECTED 0x41 |
95 | #define HIDPP_PARAM_PROTO_TYPE 0x00 |
96 | #define HIDPP_PARAM_DEVICE_INFO 0x01 |
97 | #define HIDPP_PARAM_EQUAD_LSB 0x02 |
98 | #define HIDPP_PARAM_EQUAD_MSB 0x03 |
99 | #define HIDPP_PARAM_27MHZ_DEVID 0x03 |
100 | #define HIDPP_DEVICE_TYPE_MASK GENMASK(3, 0) |
101 | #define HIDPP_LINK_STATUS_MASK BIT(6) |
102 | #define HIDPP_MANUFACTURER_MASK BIT(7) |
103 | #define HIDPP_27MHZ_SECURE_MASK BIT(7) |
104 | |
105 | #define HIDPP_DEVICE_TYPE_KEYBOARD 1 |
106 | #define HIDPP_DEVICE_TYPE_MOUSE 2 |
107 | |
108 | #define HIDPP_SET_REGISTER 0x80 |
109 | #define HIDPP_GET_LONG_REGISTER 0x83 |
110 | #define HIDPP_REG_CONNECTION_STATE 0x02 |
111 | #define HIDPP_REG_PAIRING_INFORMATION 0xB5 |
112 | #define HIDPP_PAIRING_INFORMATION 0x20 |
113 | #define HIDPP_FAKE_DEVICE_ARRIVAL 0x02 |
114 | |
115 | enum recvr_type { |
116 | recvr_type_dj, |
117 | recvr_type_hidpp, |
118 | recvr_type_gaming_hidpp, |
119 | recvr_type_mouse_only, |
120 | recvr_type_27mhz, |
121 | recvr_type_bluetooth, |
122 | recvr_type_dinovo, |
123 | }; |
124 | |
125 | struct dj_report { |
126 | u8 report_id; |
127 | u8 device_index; |
128 | u8 report_type; |
129 | u8 report_params[DJREPORT_SHORT_LENGTH - 3]; |
130 | }; |
131 | |
132 | struct hidpp_event { |
133 | u8 report_id; |
134 | u8 device_index; |
135 | u8 sub_id; |
136 | u8 params[HIDPP_REPORT_LONG_LENGTH - 3U]; |
137 | } __packed; |
138 | |
139 | struct dj_receiver_dev { |
140 | struct hid_device *mouse; |
141 | struct hid_device *keyboard; |
142 | struct hid_device *hidpp; |
143 | struct dj_device *paired_dj_devices[DJ_MAX_PAIRED_DEVICES + |
144 | DJ_DEVICE_INDEX_MIN]; |
145 | struct list_head list; |
146 | struct kref kref; |
147 | struct work_struct work; |
148 | struct kfifo notif_fifo; |
149 | unsigned long last_query; /* in jiffies */ |
150 | bool ready; |
151 | enum recvr_type type; |
152 | unsigned int unnumbered_application; |
153 | spinlock_t lock; |
154 | }; |
155 | |
156 | struct dj_device { |
157 | struct hid_device *hdev; |
158 | struct dj_receiver_dev *dj_receiver_dev; |
159 | u64 reports_supported; |
160 | u8 device_index; |
161 | }; |
162 | |
163 | #define WORKITEM_TYPE_EMPTY 0 |
164 | #define WORKITEM_TYPE_PAIRED 1 |
165 | #define WORKITEM_TYPE_UNPAIRED 2 |
166 | #define WORKITEM_TYPE_UNKNOWN 255 |
167 | |
168 | struct dj_workitem { |
169 | u8 type; /* WORKITEM_TYPE_* */ |
170 | u8 device_index; |
171 | u8 device_type; |
172 | u8 quad_id_msb; |
173 | u8 quad_id_lsb; |
174 | u64 reports_supported; |
175 | }; |
176 | |
177 | /* Keyboard descriptor (1) */ |
178 | static const char kbd_descriptor[] = { |
179 | 0x05, 0x01, /* USAGE_PAGE (generic Desktop) */ |
180 | 0x09, 0x06, /* USAGE (Keyboard) */ |
181 | 0xA1, 0x01, /* COLLECTION (Application) */ |
182 | 0x85, 0x01, /* REPORT_ID (1) */ |
183 | 0x95, 0x08, /* REPORT_COUNT (8) */ |
184 | 0x75, 0x01, /* REPORT_SIZE (1) */ |
185 | 0x15, 0x00, /* LOGICAL_MINIMUM (0) */ |
186 | 0x25, 0x01, /* LOGICAL_MAXIMUM (1) */ |
187 | 0x05, 0x07, /* USAGE_PAGE (Keyboard) */ |
188 | 0x19, 0xE0, /* USAGE_MINIMUM (Left Control) */ |
189 | 0x29, 0xE7, /* USAGE_MAXIMUM (Right GUI) */ |
190 | 0x81, 0x02, /* INPUT (Data,Var,Abs) */ |
191 | 0x95, 0x06, /* REPORT_COUNT (6) */ |
192 | 0x75, 0x08, /* REPORT_SIZE (8) */ |
193 | 0x15, 0x00, /* LOGICAL_MINIMUM (0) */ |
194 | 0x26, 0xFF, 0x00, /* LOGICAL_MAXIMUM (255) */ |
195 | 0x05, 0x07, /* USAGE_PAGE (Keyboard) */ |
196 | 0x19, 0x00, /* USAGE_MINIMUM (no event) */ |
197 | 0x2A, 0xFF, 0x00, /* USAGE_MAXIMUM (reserved) */ |
198 | 0x81, 0x00, /* INPUT (Data,Ary,Abs) */ |
199 | 0x85, 0x0e, /* REPORT_ID (14) */ |
200 | 0x05, 0x08, /* USAGE PAGE (LED page) */ |
201 | 0x95, 0x05, /* REPORT COUNT (5) */ |
202 | 0x75, 0x01, /* REPORT SIZE (1) */ |
203 | 0x15, 0x00, /* LOGICAL_MINIMUM (0) */ |
204 | 0x25, 0x01, /* LOGICAL_MAXIMUM (1) */ |
205 | 0x19, 0x01, /* USAGE MINIMUM (1) */ |
206 | 0x29, 0x05, /* USAGE MAXIMUM (5) */ |
207 | 0x91, 0x02, /* OUTPUT (Data, Variable, Absolute) */ |
208 | 0x95, 0x01, /* REPORT COUNT (1) */ |
209 | 0x75, 0x03, /* REPORT SIZE (3) */ |
210 | 0x91, 0x01, /* OUTPUT (Constant) */ |
211 | 0xC0 |
212 | }; |
213 | |
214 | /* Mouse descriptor (2) */ |
215 | static const char mse_descriptor[] = { |
216 | 0x05, 0x01, /* USAGE_PAGE (Generic Desktop) */ |
217 | 0x09, 0x02, /* USAGE (Mouse) */ |
218 | 0xA1, 0x01, /* COLLECTION (Application) */ |
219 | 0x85, 0x02, /* REPORT_ID = 2 */ |
220 | 0x09, 0x01, /* USAGE (pointer) */ |
221 | 0xA1, 0x00, /* COLLECTION (physical) */ |
222 | 0x05, 0x09, /* USAGE_PAGE (buttons) */ |
223 | 0x19, 0x01, /* USAGE_MIN (1) */ |
224 | 0x29, 0x10, /* USAGE_MAX (16) */ |
225 | 0x15, 0x00, /* LOGICAL_MIN (0) */ |
226 | 0x25, 0x01, /* LOGICAL_MAX (1) */ |
227 | 0x95, 0x10, /* REPORT_COUNT (16) */ |
228 | 0x75, 0x01, /* REPORT_SIZE (1) */ |
229 | 0x81, 0x02, /* INPUT (data var abs) */ |
230 | 0x05, 0x01, /* USAGE_PAGE (generic desktop) */ |
231 | 0x16, 0x01, 0xF8, /* LOGICAL_MIN (-2047) */ |
232 | 0x26, 0xFF, 0x07, /* LOGICAL_MAX (2047) */ |
233 | 0x75, 0x0C, /* REPORT_SIZE (12) */ |
234 | 0x95, 0x02, /* REPORT_COUNT (2) */ |
235 | 0x09, 0x30, /* USAGE (X) */ |
236 | 0x09, 0x31, /* USAGE (Y) */ |
237 | 0x81, 0x06, /* INPUT */ |
238 | 0x15, 0x81, /* LOGICAL_MIN (-127) */ |
239 | 0x25, 0x7F, /* LOGICAL_MAX (127) */ |
240 | 0x75, 0x08, /* REPORT_SIZE (8) */ |
241 | 0x95, 0x01, /* REPORT_COUNT (1) */ |
242 | 0x09, 0x38, /* USAGE (wheel) */ |
243 | 0x81, 0x06, /* INPUT */ |
244 | 0x05, 0x0C, /* USAGE_PAGE(consumer) */ |
245 | 0x0A, 0x38, 0x02, /* USAGE(AC Pan) */ |
246 | 0x95, 0x01, /* REPORT_COUNT (1) */ |
247 | 0x81, 0x06, /* INPUT */ |
248 | 0xC0, /* END_COLLECTION */ |
249 | 0xC0, /* END_COLLECTION */ |
250 | }; |
251 | |
252 | /* Mouse descriptor (2) for 27 MHz receiver, only 8 buttons */ |
253 | static const char mse_27mhz_descriptor[] = { |
254 | 0x05, 0x01, /* USAGE_PAGE (Generic Desktop) */ |
255 | 0x09, 0x02, /* USAGE (Mouse) */ |
256 | 0xA1, 0x01, /* COLLECTION (Application) */ |
257 | 0x85, 0x02, /* REPORT_ID = 2 */ |
258 | 0x09, 0x01, /* USAGE (pointer) */ |
259 | 0xA1, 0x00, /* COLLECTION (physical) */ |
260 | 0x05, 0x09, /* USAGE_PAGE (buttons) */ |
261 | 0x19, 0x01, /* USAGE_MIN (1) */ |
262 | 0x29, 0x08, /* USAGE_MAX (8) */ |
263 | 0x15, 0x00, /* LOGICAL_MIN (0) */ |
264 | 0x25, 0x01, /* LOGICAL_MAX (1) */ |
265 | 0x95, 0x08, /* REPORT_COUNT (8) */ |
266 | 0x75, 0x01, /* REPORT_SIZE (1) */ |
267 | 0x81, 0x02, /* INPUT (data var abs) */ |
268 | 0x05, 0x01, /* USAGE_PAGE (generic desktop) */ |
269 | 0x16, 0x01, 0xF8, /* LOGICAL_MIN (-2047) */ |
270 | 0x26, 0xFF, 0x07, /* LOGICAL_MAX (2047) */ |
271 | 0x75, 0x0C, /* REPORT_SIZE (12) */ |
272 | 0x95, 0x02, /* REPORT_COUNT (2) */ |
273 | 0x09, 0x30, /* USAGE (X) */ |
274 | 0x09, 0x31, /* USAGE (Y) */ |
275 | 0x81, 0x06, /* INPUT */ |
276 | 0x15, 0x81, /* LOGICAL_MIN (-127) */ |
277 | 0x25, 0x7F, /* LOGICAL_MAX (127) */ |
278 | 0x75, 0x08, /* REPORT_SIZE (8) */ |
279 | 0x95, 0x01, /* REPORT_COUNT (1) */ |
280 | 0x09, 0x38, /* USAGE (wheel) */ |
281 | 0x81, 0x06, /* INPUT */ |
282 | 0x05, 0x0C, /* USAGE_PAGE(consumer) */ |
283 | 0x0A, 0x38, 0x02, /* USAGE(AC Pan) */ |
284 | 0x95, 0x01, /* REPORT_COUNT (1) */ |
285 | 0x81, 0x06, /* INPUT */ |
286 | 0xC0, /* END_COLLECTION */ |
287 | 0xC0, /* END_COLLECTION */ |
288 | }; |
289 | |
290 | /* Mouse descriptor (2) for Bluetooth receiver, low-res hwheel, 12 buttons */ |
291 | static const char mse_bluetooth_descriptor[] = { |
292 | 0x05, 0x01, /* USAGE_PAGE (Generic Desktop) */ |
293 | 0x09, 0x02, /* USAGE (Mouse) */ |
294 | 0xA1, 0x01, /* COLLECTION (Application) */ |
295 | 0x85, 0x02, /* REPORT_ID = 2 */ |
296 | 0x09, 0x01, /* USAGE (pointer) */ |
297 | 0xA1, 0x00, /* COLLECTION (physical) */ |
298 | 0x05, 0x09, /* USAGE_PAGE (buttons) */ |
299 | 0x19, 0x01, /* USAGE_MIN (1) */ |
300 | 0x29, 0x08, /* USAGE_MAX (8) */ |
301 | 0x15, 0x00, /* LOGICAL_MIN (0) */ |
302 | 0x25, 0x01, /* LOGICAL_MAX (1) */ |
303 | 0x95, 0x08, /* REPORT_COUNT (8) */ |
304 | 0x75, 0x01, /* REPORT_SIZE (1) */ |
305 | 0x81, 0x02, /* INPUT (data var abs) */ |
306 | 0x05, 0x01, /* USAGE_PAGE (generic desktop) */ |
307 | 0x16, 0x01, 0xF8, /* LOGICAL_MIN (-2047) */ |
308 | 0x26, 0xFF, 0x07, /* LOGICAL_MAX (2047) */ |
309 | 0x75, 0x0C, /* REPORT_SIZE (12) */ |
310 | 0x95, 0x02, /* REPORT_COUNT (2) */ |
311 | 0x09, 0x30, /* USAGE (X) */ |
312 | 0x09, 0x31, /* USAGE (Y) */ |
313 | 0x81, 0x06, /* INPUT */ |
314 | 0x15, 0x81, /* LOGICAL_MIN (-127) */ |
315 | 0x25, 0x7F, /* LOGICAL_MAX (127) */ |
316 | 0x75, 0x08, /* REPORT_SIZE (8) */ |
317 | 0x95, 0x01, /* REPORT_COUNT (1) */ |
318 | 0x09, 0x38, /* USAGE (wheel) */ |
319 | 0x81, 0x06, /* INPUT */ |
320 | 0x05, 0x0C, /* USAGE_PAGE(consumer) */ |
321 | 0x0A, 0x38, 0x02, /* USAGE(AC Pan) */ |
322 | 0x15, 0xF9, /* LOGICAL_MIN (-7) */ |
323 | 0x25, 0x07, /* LOGICAL_MAX (7) */ |
324 | 0x75, 0x04, /* REPORT_SIZE (4) */ |
325 | 0x95, 0x01, /* REPORT_COUNT (1) */ |
326 | 0x81, 0x06, /* INPUT */ |
327 | 0x05, 0x09, /* USAGE_PAGE (buttons) */ |
328 | 0x19, 0x09, /* USAGE_MIN (9) */ |
329 | 0x29, 0x0C, /* USAGE_MAX (12) */ |
330 | 0x15, 0x00, /* LOGICAL_MIN (0) */ |
331 | 0x25, 0x01, /* LOGICAL_MAX (1) */ |
332 | 0x75, 0x01, /* REPORT_SIZE (1) */ |
333 | 0x95, 0x04, /* REPORT_COUNT (4) */ |
334 | 0x81, 0x02, /* INPUT (Data,Var,Abs) */ |
335 | 0xC0, /* END_COLLECTION */ |
336 | 0xC0, /* END_COLLECTION */ |
337 | }; |
338 | |
339 | /* Mouse descriptor (5) for Bluetooth receiver, normal-res hwheel, 8 buttons */ |
340 | static const char mse5_bluetooth_descriptor[] = { |
341 | 0x05, 0x01, /* USAGE_PAGE (Generic Desktop) */ |
342 | 0x09, 0x02, /* Usage (Mouse) */ |
343 | 0xa1, 0x01, /* Collection (Application) */ |
344 | 0x85, 0x05, /* Report ID (5) */ |
345 | 0x09, 0x01, /* Usage (Pointer) */ |
346 | 0xa1, 0x00, /* Collection (Physical) */ |
347 | 0x05, 0x09, /* Usage Page (Button) */ |
348 | 0x19, 0x01, /* Usage Minimum (1) */ |
349 | 0x29, 0x08, /* Usage Maximum (8) */ |
350 | 0x15, 0x00, /* Logical Minimum (0) */ |
351 | 0x25, 0x01, /* Logical Maximum (1) */ |
352 | 0x95, 0x08, /* Report Count (8) */ |
353 | 0x75, 0x01, /* Report Size (1) */ |
354 | 0x81, 0x02, /* Input (Data,Var,Abs) */ |
355 | 0x05, 0x01, /* Usage Page (Generic Desktop) */ |
356 | 0x16, 0x01, 0xf8, /* Logical Minimum (-2047) */ |
357 | 0x26, 0xff, 0x07, /* Logical Maximum (2047) */ |
358 | 0x75, 0x0c, /* Report Size (12) */ |
359 | 0x95, 0x02, /* Report Count (2) */ |
360 | 0x09, 0x30, /* Usage (X) */ |
361 | 0x09, 0x31, /* Usage (Y) */ |
362 | 0x81, 0x06, /* Input (Data,Var,Rel) */ |
363 | 0x15, 0x81, /* Logical Minimum (-127) */ |
364 | 0x25, 0x7f, /* Logical Maximum (127) */ |
365 | 0x75, 0x08, /* Report Size (8) */ |
366 | 0x95, 0x01, /* Report Count (1) */ |
367 | 0x09, 0x38, /* Usage (Wheel) */ |
368 | 0x81, 0x06, /* Input (Data,Var,Rel) */ |
369 | 0x05, 0x0c, /* Usage Page (Consumer Devices) */ |
370 | 0x0a, 0x38, 0x02, /* Usage (AC Pan) */ |
371 | 0x15, 0x81, /* Logical Minimum (-127) */ |
372 | 0x25, 0x7f, /* Logical Maximum (127) */ |
373 | 0x75, 0x08, /* Report Size (8) */ |
374 | 0x95, 0x01, /* Report Count (1) */ |
375 | 0x81, 0x06, /* Input (Data,Var,Rel) */ |
376 | 0xc0, /* End Collection */ |
377 | 0xc0, /* End Collection */ |
378 | }; |
379 | |
380 | /* Gaming Mouse descriptor (2) */ |
381 | static const char mse_high_res_descriptor[] = { |
382 | 0x05, 0x01, /* USAGE_PAGE (Generic Desktop) */ |
383 | 0x09, 0x02, /* USAGE (Mouse) */ |
384 | 0xA1, 0x01, /* COLLECTION (Application) */ |
385 | 0x85, 0x02, /* REPORT_ID = 2 */ |
386 | 0x09, 0x01, /* USAGE (pointer) */ |
387 | 0xA1, 0x00, /* COLLECTION (physical) */ |
388 | 0x05, 0x09, /* USAGE_PAGE (buttons) */ |
389 | 0x19, 0x01, /* USAGE_MIN (1) */ |
390 | 0x29, 0x10, /* USAGE_MAX (16) */ |
391 | 0x15, 0x00, /* LOGICAL_MIN (0) */ |
392 | 0x25, 0x01, /* LOGICAL_MAX (1) */ |
393 | 0x95, 0x10, /* REPORT_COUNT (16) */ |
394 | 0x75, 0x01, /* REPORT_SIZE (1) */ |
395 | 0x81, 0x02, /* INPUT (data var abs) */ |
396 | 0x05, 0x01, /* USAGE_PAGE (generic desktop) */ |
397 | 0x16, 0x01, 0x80, /* LOGICAL_MIN (-32767) */ |
398 | 0x26, 0xFF, 0x7F, /* LOGICAL_MAX (32767) */ |
399 | 0x75, 0x10, /* REPORT_SIZE (16) */ |
400 | 0x95, 0x02, /* REPORT_COUNT (2) */ |
401 | 0x09, 0x30, /* USAGE (X) */ |
402 | 0x09, 0x31, /* USAGE (Y) */ |
403 | 0x81, 0x06, /* INPUT */ |
404 | 0x15, 0x81, /* LOGICAL_MIN (-127) */ |
405 | 0x25, 0x7F, /* LOGICAL_MAX (127) */ |
406 | 0x75, 0x08, /* REPORT_SIZE (8) */ |
407 | 0x95, 0x01, /* REPORT_COUNT (1) */ |
408 | 0x09, 0x38, /* USAGE (wheel) */ |
409 | 0x81, 0x06, /* INPUT */ |
410 | 0x05, 0x0C, /* USAGE_PAGE(consumer) */ |
411 | 0x0A, 0x38, 0x02, /* USAGE(AC Pan) */ |
412 | 0x95, 0x01, /* REPORT_COUNT (1) */ |
413 | 0x81, 0x06, /* INPUT */ |
414 | 0xC0, /* END_COLLECTION */ |
415 | 0xC0, /* END_COLLECTION */ |
416 | }; |
417 | |
418 | /* Consumer Control descriptor (3) */ |
419 | static const char consumer_descriptor[] = { |
420 | 0x05, 0x0C, /* USAGE_PAGE (Consumer Devices) */ |
421 | 0x09, 0x01, /* USAGE (Consumer Control) */ |
422 | 0xA1, 0x01, /* COLLECTION (Application) */ |
423 | 0x85, 0x03, /* REPORT_ID = 3 */ |
424 | 0x75, 0x10, /* REPORT_SIZE (16) */ |
425 | 0x95, 0x02, /* REPORT_COUNT (2) */ |
426 | 0x15, 0x01, /* LOGICAL_MIN (1) */ |
427 | 0x26, 0xFF, 0x02, /* LOGICAL_MAX (767) */ |
428 | 0x19, 0x01, /* USAGE_MIN (1) */ |
429 | 0x2A, 0xFF, 0x02, /* USAGE_MAX (767) */ |
430 | 0x81, 0x00, /* INPUT (Data Ary Abs) */ |
431 | 0xC0, /* END_COLLECTION */ |
432 | }; /* */ |
433 | |
434 | /* System control descriptor (4) */ |
435 | static const char syscontrol_descriptor[] = { |
436 | 0x05, 0x01, /* USAGE_PAGE (Generic Desktop) */ |
437 | 0x09, 0x80, /* USAGE (System Control) */ |
438 | 0xA1, 0x01, /* COLLECTION (Application) */ |
439 | 0x85, 0x04, /* REPORT_ID = 4 */ |
440 | 0x75, 0x02, /* REPORT_SIZE (2) */ |
441 | 0x95, 0x01, /* REPORT_COUNT (1) */ |
442 | 0x15, 0x01, /* LOGICAL_MIN (1) */ |
443 | 0x25, 0x03, /* LOGICAL_MAX (3) */ |
444 | 0x09, 0x82, /* USAGE (System Sleep) */ |
445 | 0x09, 0x81, /* USAGE (System Power Down) */ |
446 | 0x09, 0x83, /* USAGE (System Wake Up) */ |
447 | 0x81, 0x60, /* INPUT (Data Ary Abs NPrf Null) */ |
448 | 0x75, 0x06, /* REPORT_SIZE (6) */ |
449 | 0x81, 0x03, /* INPUT (Cnst Var Abs) */ |
450 | 0xC0, /* END_COLLECTION */ |
451 | }; |
452 | |
453 | /* Media descriptor (8) */ |
454 | static const char media_descriptor[] = { |
455 | 0x06, 0xbc, 0xff, /* Usage Page 0xffbc */ |
456 | 0x09, 0x88, /* Usage 0x0088 */ |
457 | 0xa1, 0x01, /* BeginCollection */ |
458 | 0x85, 0x08, /* Report ID 8 */ |
459 | 0x19, 0x01, /* Usage Min 0x0001 */ |
460 | 0x29, 0xff, /* Usage Max 0x00ff */ |
461 | 0x15, 0x01, /* Logical Min 1 */ |
462 | 0x26, 0xff, 0x00, /* Logical Max 255 */ |
463 | 0x75, 0x08, /* Report Size 8 */ |
464 | 0x95, 0x01, /* Report Count 1 */ |
465 | 0x81, 0x00, /* Input */ |
466 | 0xc0, /* EndCollection */ |
467 | }; /* */ |
468 | |
469 | /* HIDPP descriptor */ |
470 | static const char hidpp_descriptor[] = { |
471 | 0x06, 0x00, 0xff, /* Usage Page (Vendor Defined Page 1) */ |
472 | 0x09, 0x01, /* Usage (Vendor Usage 1) */ |
473 | 0xa1, 0x01, /* Collection (Application) */ |
474 | 0x85, 0x10, /* Report ID (16) */ |
475 | 0x75, 0x08, /* Report Size (8) */ |
476 | 0x95, 0x06, /* Report Count (6) */ |
477 | 0x15, 0x00, /* Logical Minimum (0) */ |
478 | 0x26, 0xff, 0x00, /* Logical Maximum (255) */ |
479 | 0x09, 0x01, /* Usage (Vendor Usage 1) */ |
480 | 0x81, 0x00, /* Input (Data,Arr,Abs) */ |
481 | 0x09, 0x01, /* Usage (Vendor Usage 1) */ |
482 | 0x91, 0x00, /* Output (Data,Arr,Abs) */ |
483 | 0xc0, /* End Collection */ |
484 | 0x06, 0x00, 0xff, /* Usage Page (Vendor Defined Page 1) */ |
485 | 0x09, 0x02, /* Usage (Vendor Usage 2) */ |
486 | 0xa1, 0x01, /* Collection (Application) */ |
487 | 0x85, 0x11, /* Report ID (17) */ |
488 | 0x75, 0x08, /* Report Size (8) */ |
489 | 0x95, 0x13, /* Report Count (19) */ |
490 | 0x15, 0x00, /* Logical Minimum (0) */ |
491 | 0x26, 0xff, 0x00, /* Logical Maximum (255) */ |
492 | 0x09, 0x02, /* Usage (Vendor Usage 2) */ |
493 | 0x81, 0x00, /* Input (Data,Arr,Abs) */ |
494 | 0x09, 0x02, /* Usage (Vendor Usage 2) */ |
495 | 0x91, 0x00, /* Output (Data,Arr,Abs) */ |
496 | 0xc0, /* End Collection */ |
497 | 0x06, 0x00, 0xff, /* Usage Page (Vendor Defined Page 1) */ |
498 | 0x09, 0x04, /* Usage (Vendor Usage 0x04) */ |
499 | 0xa1, 0x01, /* Collection (Application) */ |
500 | 0x85, 0x20, /* Report ID (32) */ |
501 | 0x75, 0x08, /* Report Size (8) */ |
502 | 0x95, 0x0e, /* Report Count (14) */ |
503 | 0x15, 0x00, /* Logical Minimum (0) */ |
504 | 0x26, 0xff, 0x00, /* Logical Maximum (255) */ |
505 | 0x09, 0x41, /* Usage (Vendor Usage 0x41) */ |
506 | 0x81, 0x00, /* Input (Data,Arr,Abs) */ |
507 | 0x09, 0x41, /* Usage (Vendor Usage 0x41) */ |
508 | 0x91, 0x00, /* Output (Data,Arr,Abs) */ |
509 | 0x85, 0x21, /* Report ID (33) */ |
510 | 0x95, 0x1f, /* Report Count (31) */ |
511 | 0x15, 0x00, /* Logical Minimum (0) */ |
512 | 0x26, 0xff, 0x00, /* Logical Maximum (255) */ |
513 | 0x09, 0x42, /* Usage (Vendor Usage 0x42) */ |
514 | 0x81, 0x00, /* Input (Data,Arr,Abs) */ |
515 | 0x09, 0x42, /* Usage (Vendor Usage 0x42) */ |
516 | 0x91, 0x00, /* Output (Data,Arr,Abs) */ |
517 | 0xc0, /* End Collection */ |
518 | }; |
519 | |
520 | /* Maximum size of all defined hid reports in bytes (including report id) */ |
521 | #define MAX_REPORT_SIZE 8 |
522 | |
523 | /* Make sure all descriptors are present here */ |
524 | #define MAX_RDESC_SIZE \ |
525 | (sizeof(kbd_descriptor) + \ |
526 | sizeof(mse_bluetooth_descriptor) + \ |
527 | sizeof(mse5_bluetooth_descriptor) + \ |
528 | sizeof(consumer_descriptor) + \ |
529 | sizeof(syscontrol_descriptor) + \ |
530 | sizeof(media_descriptor) + \ |
531 | sizeof(hidpp_descriptor)) |
532 | |
533 | /* Number of possible hid report types that can be created by this driver. |
534 | * |
535 | * Right now, RF report types have the same report types (or report id's) |
536 | * than the hid report created from those RF reports. In the future |
537 | * this doesnt have to be true. |
538 | * |
539 | * For instance, RF report type 0x01 which has a size of 8 bytes, corresponds |
540 | * to hid report id 0x01, this is standard keyboard. Same thing applies to mice |
541 | * reports and consumer control, etc. If a new RF report is created, it doesn't |
542 | * has to have the same report id as its corresponding hid report, so an |
543 | * translation may have to take place for future report types. |
544 | */ |
545 | #define NUMBER_OF_HID_REPORTS 32 |
546 | static const u8 hid_reportid_size_map[NUMBER_OF_HID_REPORTS] = { |
547 | [1] = 8, /* Standard keyboard */ |
548 | [2] = 8, /* Standard mouse */ |
549 | [3] = 5, /* Consumer control */ |
550 | [4] = 2, /* System control */ |
551 | [8] = 2, /* Media Center */ |
552 | }; |
553 | |
554 | |
555 | #define LOGITECH_DJ_INTERFACE_NUMBER 0x02 |
556 | |
557 | static const struct hid_ll_driver logi_dj_ll_driver; |
558 | |
559 | static int logi_dj_recv_query_paired_devices(struct dj_receiver_dev *djrcv_dev); |
560 | static void delayedwork_callback(struct work_struct *work); |
561 | |
562 | static LIST_HEAD(dj_hdev_list); |
563 | static DEFINE_MUTEX(dj_hdev_list_lock); |
564 | |
565 | static bool recvr_type_is_bluetooth(enum recvr_type type) |
566 | { |
567 | return type == recvr_type_bluetooth || type == recvr_type_dinovo; |
568 | } |
569 | |
570 | /* |
571 | * dj/HID++ receivers are really a single logical entity, but for BIOS/Windows |
572 | * compatibility they have multiple USB interfaces. On HID++ receivers we need |
573 | * to listen for input reports on both interfaces. The functions below are used |
574 | * to create a single struct dj_receiver_dev for all interfaces belonging to |
575 | * a single USB-device / receiver. |
576 | */ |
577 | static struct dj_receiver_dev *dj_find_receiver_dev(struct hid_device *hdev, |
578 | enum recvr_type type) |
579 | { |
580 | struct dj_receiver_dev *djrcv_dev; |
581 | char sep; |
582 | |
583 | /* |
584 | * The bluetooth receiver contains a built-in hub and has separate |
585 | * USB-devices for the keyboard and mouse interfaces. |
586 | */ |
587 | sep = recvr_type_is_bluetooth(type) ? '.' : '/'; |
588 | |
589 | /* Try to find an already-probed interface from the same device */ |
590 | list_for_each_entry(djrcv_dev, &dj_hdev_list, list) { |
591 | if (djrcv_dev->mouse && |
592 | hid_compare_device_paths(hdev_a: hdev, hdev_b: djrcv_dev->mouse, separator: sep)) { |
593 | kref_get(kref: &djrcv_dev->kref); |
594 | return djrcv_dev; |
595 | } |
596 | if (djrcv_dev->keyboard && |
597 | hid_compare_device_paths(hdev_a: hdev, hdev_b: djrcv_dev->keyboard, separator: sep)) { |
598 | kref_get(kref: &djrcv_dev->kref); |
599 | return djrcv_dev; |
600 | } |
601 | if (djrcv_dev->hidpp && |
602 | hid_compare_device_paths(hdev_a: hdev, hdev_b: djrcv_dev->hidpp, separator: sep)) { |
603 | kref_get(kref: &djrcv_dev->kref); |
604 | return djrcv_dev; |
605 | } |
606 | } |
607 | |
608 | return NULL; |
609 | } |
610 | |
611 | static void dj_release_receiver_dev(struct kref *kref) |
612 | { |
613 | struct dj_receiver_dev *djrcv_dev = container_of(kref, struct dj_receiver_dev, kref); |
614 | |
615 | list_del(entry: &djrcv_dev->list); |
616 | kfifo_free(&djrcv_dev->notif_fifo); |
617 | kfree(objp: djrcv_dev); |
618 | } |
619 | |
620 | static void dj_put_receiver_dev(struct hid_device *hdev) |
621 | { |
622 | struct dj_receiver_dev *djrcv_dev = hid_get_drvdata(hdev); |
623 | |
624 | mutex_lock(&dj_hdev_list_lock); |
625 | |
626 | if (djrcv_dev->mouse == hdev) |
627 | djrcv_dev->mouse = NULL; |
628 | if (djrcv_dev->keyboard == hdev) |
629 | djrcv_dev->keyboard = NULL; |
630 | if (djrcv_dev->hidpp == hdev) |
631 | djrcv_dev->hidpp = NULL; |
632 | |
633 | kref_put(kref: &djrcv_dev->kref, release: dj_release_receiver_dev); |
634 | |
635 | mutex_unlock(lock: &dj_hdev_list_lock); |
636 | } |
637 | |
638 | static struct dj_receiver_dev *dj_get_receiver_dev(struct hid_device *hdev, |
639 | enum recvr_type type, |
640 | unsigned int application, |
641 | bool is_hidpp) |
642 | { |
643 | struct dj_receiver_dev *djrcv_dev; |
644 | |
645 | mutex_lock(&dj_hdev_list_lock); |
646 | |
647 | djrcv_dev = dj_find_receiver_dev(hdev, type); |
648 | if (!djrcv_dev) { |
649 | djrcv_dev = kzalloc(size: sizeof(*djrcv_dev), GFP_KERNEL); |
650 | if (!djrcv_dev) |
651 | goto out; |
652 | |
653 | INIT_WORK(&djrcv_dev->work, delayedwork_callback); |
654 | spin_lock_init(&djrcv_dev->lock); |
655 | if (kfifo_alloc(&djrcv_dev->notif_fifo, |
656 | DJ_MAX_NUMBER_NOTIFS * sizeof(struct dj_workitem), |
657 | GFP_KERNEL)) { |
658 | kfree(objp: djrcv_dev); |
659 | djrcv_dev = NULL; |
660 | goto out; |
661 | } |
662 | kref_init(kref: &djrcv_dev->kref); |
663 | list_add_tail(new: &djrcv_dev->list, head: &dj_hdev_list); |
664 | djrcv_dev->last_query = jiffies; |
665 | djrcv_dev->type = type; |
666 | } |
667 | |
668 | if (application == HID_GD_KEYBOARD) |
669 | djrcv_dev->keyboard = hdev; |
670 | if (application == HID_GD_MOUSE) |
671 | djrcv_dev->mouse = hdev; |
672 | if (is_hidpp) |
673 | djrcv_dev->hidpp = hdev; |
674 | |
675 | hid_set_drvdata(hdev, data: djrcv_dev); |
676 | out: |
677 | mutex_unlock(lock: &dj_hdev_list_lock); |
678 | return djrcv_dev; |
679 | } |
680 | |
681 | static void logi_dj_recv_destroy_djhid_device(struct dj_receiver_dev *djrcv_dev, |
682 | struct dj_workitem *workitem) |
683 | { |
684 | /* Called in delayed work context */ |
685 | struct dj_device *dj_dev; |
686 | unsigned long flags; |
687 | |
688 | spin_lock_irqsave(&djrcv_dev->lock, flags); |
689 | dj_dev = djrcv_dev->paired_dj_devices[workitem->device_index]; |
690 | djrcv_dev->paired_dj_devices[workitem->device_index] = NULL; |
691 | spin_unlock_irqrestore(lock: &djrcv_dev->lock, flags); |
692 | |
693 | if (dj_dev != NULL) { |
694 | hid_destroy_device(dj_dev->hdev); |
695 | kfree(objp: dj_dev); |
696 | } else { |
697 | hid_err(djrcv_dev->hidpp, "%s: can't destroy a NULL device\n" , |
698 | __func__); |
699 | } |
700 | } |
701 | |
702 | static void logi_dj_recv_add_djhid_device(struct dj_receiver_dev *djrcv_dev, |
703 | struct dj_workitem *workitem) |
704 | { |
705 | /* Called in delayed work context */ |
706 | struct hid_device *djrcv_hdev = djrcv_dev->hidpp; |
707 | struct hid_device *dj_hiddev; |
708 | struct dj_device *dj_dev; |
709 | u8 device_index = workitem->device_index; |
710 | unsigned long flags; |
711 | |
712 | /* Device index goes from 1 to 6, we need 3 bytes to store the |
713 | * semicolon, the index, and a null terminator |
714 | */ |
715 | unsigned char tmpstr[3]; |
716 | |
717 | /* We are the only one ever adding a device, no need to lock */ |
718 | if (djrcv_dev->paired_dj_devices[device_index]) { |
719 | /* The device is already known. No need to reallocate it. */ |
720 | dbg_hid("%s: device is already known\n" , __func__); |
721 | return; |
722 | } |
723 | |
724 | dj_hiddev = hid_allocate_device(); |
725 | if (IS_ERR(ptr: dj_hiddev)) { |
726 | hid_err(djrcv_hdev, "%s: hid_allocate_dev failed\n" , __func__); |
727 | return; |
728 | } |
729 | |
730 | dj_hiddev->ll_driver = &logi_dj_ll_driver; |
731 | |
732 | dj_hiddev->dev.parent = &djrcv_hdev->dev; |
733 | dj_hiddev->bus = BUS_USB; |
734 | dj_hiddev->vendor = djrcv_hdev->vendor; |
735 | dj_hiddev->product = (workitem->quad_id_msb << 8) | |
736 | workitem->quad_id_lsb; |
737 | if (workitem->device_type) { |
738 | const char *type_str = "Device" ; |
739 | |
740 | switch (workitem->device_type) { |
741 | case 0x01: type_str = "Keyboard" ; break; |
742 | case 0x02: type_str = "Mouse" ; break; |
743 | case 0x03: type_str = "Numpad" ; break; |
744 | case 0x04: type_str = "Presenter" ; break; |
745 | case 0x07: type_str = "Remote Control" ; break; |
746 | case 0x08: type_str = "Trackball" ; break; |
747 | case 0x09: type_str = "Touchpad" ; break; |
748 | } |
749 | snprintf(buf: dj_hiddev->name, size: sizeof(dj_hiddev->name), |
750 | fmt: "Logitech Wireless %s PID:%04x" , |
751 | type_str, dj_hiddev->product); |
752 | } else { |
753 | snprintf(buf: dj_hiddev->name, size: sizeof(dj_hiddev->name), |
754 | fmt: "Logitech Wireless Device PID:%04x" , |
755 | dj_hiddev->product); |
756 | } |
757 | |
758 | if (djrcv_dev->type == recvr_type_27mhz) |
759 | dj_hiddev->group = HID_GROUP_LOGITECH_27MHZ_DEVICE; |
760 | else |
761 | dj_hiddev->group = HID_GROUP_LOGITECH_DJ_DEVICE; |
762 | |
763 | memcpy(dj_hiddev->phys, djrcv_hdev->phys, sizeof(djrcv_hdev->phys)); |
764 | snprintf(buf: tmpstr, size: sizeof(tmpstr), fmt: ":%d" , device_index); |
765 | strlcat(p: dj_hiddev->phys, q: tmpstr, avail: sizeof(dj_hiddev->phys)); |
766 | |
767 | dj_dev = kzalloc(size: sizeof(struct dj_device), GFP_KERNEL); |
768 | |
769 | if (!dj_dev) { |
770 | hid_err(djrcv_hdev, "%s: failed allocating dj_dev\n" , __func__); |
771 | goto dj_device_allocate_fail; |
772 | } |
773 | |
774 | dj_dev->reports_supported = workitem->reports_supported; |
775 | dj_dev->hdev = dj_hiddev; |
776 | dj_dev->dj_receiver_dev = djrcv_dev; |
777 | dj_dev->device_index = device_index; |
778 | dj_hiddev->driver_data = dj_dev; |
779 | |
780 | spin_lock_irqsave(&djrcv_dev->lock, flags); |
781 | djrcv_dev->paired_dj_devices[device_index] = dj_dev; |
782 | spin_unlock_irqrestore(lock: &djrcv_dev->lock, flags); |
783 | |
784 | if (hid_add_device(dj_hiddev)) { |
785 | hid_err(djrcv_hdev, "%s: failed adding dj_device\n" , __func__); |
786 | goto hid_add_device_fail; |
787 | } |
788 | |
789 | return; |
790 | |
791 | hid_add_device_fail: |
792 | spin_lock_irqsave(&djrcv_dev->lock, flags); |
793 | djrcv_dev->paired_dj_devices[device_index] = NULL; |
794 | spin_unlock_irqrestore(lock: &djrcv_dev->lock, flags); |
795 | kfree(objp: dj_dev); |
796 | dj_device_allocate_fail: |
797 | hid_destroy_device(dj_hiddev); |
798 | } |
799 | |
800 | static void delayedwork_callback(struct work_struct *work) |
801 | { |
802 | struct dj_receiver_dev *djrcv_dev = |
803 | container_of(work, struct dj_receiver_dev, work); |
804 | |
805 | struct dj_workitem workitem; |
806 | unsigned long flags; |
807 | int count; |
808 | int retval; |
809 | |
810 | dbg_hid("%s\n" , __func__); |
811 | |
812 | spin_lock_irqsave(&djrcv_dev->lock, flags); |
813 | |
814 | /* |
815 | * Since we attach to multiple interfaces, we may get scheduled before |
816 | * we are bound to the HID++ interface, catch this. |
817 | */ |
818 | if (!djrcv_dev->ready) { |
819 | pr_warn("%s: delayedwork queued before hidpp interface was enumerated\n" , |
820 | __func__); |
821 | spin_unlock_irqrestore(lock: &djrcv_dev->lock, flags); |
822 | return; |
823 | } |
824 | |
825 | count = kfifo_out(&djrcv_dev->notif_fifo, &workitem, sizeof(workitem)); |
826 | |
827 | if (count != sizeof(workitem)) { |
828 | spin_unlock_irqrestore(lock: &djrcv_dev->lock, flags); |
829 | return; |
830 | } |
831 | |
832 | if (!kfifo_is_empty(&djrcv_dev->notif_fifo)) |
833 | schedule_work(work: &djrcv_dev->work); |
834 | |
835 | spin_unlock_irqrestore(lock: &djrcv_dev->lock, flags); |
836 | |
837 | switch (workitem.type) { |
838 | case WORKITEM_TYPE_PAIRED: |
839 | logi_dj_recv_add_djhid_device(djrcv_dev, workitem: &workitem); |
840 | break; |
841 | case WORKITEM_TYPE_UNPAIRED: |
842 | logi_dj_recv_destroy_djhid_device(djrcv_dev, workitem: &workitem); |
843 | break; |
844 | case WORKITEM_TYPE_UNKNOWN: |
845 | retval = logi_dj_recv_query_paired_devices(djrcv_dev); |
846 | if (retval) { |
847 | hid_err(djrcv_dev->hidpp, "%s: logi_dj_recv_query_paired_devices error: %d\n" , |
848 | __func__, retval); |
849 | } |
850 | break; |
851 | case WORKITEM_TYPE_EMPTY: |
852 | dbg_hid("%s: device list is empty\n" , __func__); |
853 | break; |
854 | } |
855 | } |
856 | |
857 | /* |
858 | * Sometimes we receive reports for which we do not have a paired dj_device |
859 | * associated with the device_index or report-type to forward the report to. |
860 | * This means that the original "device paired" notification corresponding |
861 | * to the dj_device never arrived to this driver. Possible reasons for this are: |
862 | * 1) hid-core discards all packets coming from a device during probe(). |
863 | * 2) if the receiver is plugged into a KVM switch then the pairing reports |
864 | * are only forwarded to it if the focus is on this PC. |
865 | * This function deals with this by re-asking the receiver for the list of |
866 | * connected devices in the delayed work callback. |
867 | * This function MUST be called with djrcv->lock held. |
868 | */ |
869 | static void logi_dj_recv_queue_unknown_work(struct dj_receiver_dev *djrcv_dev) |
870 | { |
871 | struct dj_workitem workitem = { .type = WORKITEM_TYPE_UNKNOWN }; |
872 | |
873 | /* Rate limit queries done because of unhandled reports to 2/sec */ |
874 | if (time_before(jiffies, djrcv_dev->last_query + HZ / 2)) |
875 | return; |
876 | |
877 | kfifo_in(&djrcv_dev->notif_fifo, &workitem, sizeof(workitem)); |
878 | schedule_work(work: &djrcv_dev->work); |
879 | } |
880 | |
881 | static void logi_dj_recv_queue_notification(struct dj_receiver_dev *djrcv_dev, |
882 | struct dj_report *dj_report) |
883 | { |
884 | /* We are called from atomic context (tasklet && djrcv->lock held) */ |
885 | struct dj_workitem workitem = { |
886 | .device_index = dj_report->device_index, |
887 | }; |
888 | |
889 | switch (dj_report->report_type) { |
890 | case REPORT_TYPE_NOTIF_DEVICE_PAIRED: |
891 | workitem.type = WORKITEM_TYPE_PAIRED; |
892 | if (dj_report->report_params[DEVICE_PAIRED_PARAM_SPFUNCTION] & |
893 | SPFUNCTION_DEVICE_LIST_EMPTY) { |
894 | workitem.type = WORKITEM_TYPE_EMPTY; |
895 | break; |
896 | } |
897 | fallthrough; |
898 | case REPORT_TYPE_NOTIF_DEVICE_UNPAIRED: |
899 | workitem.quad_id_msb = |
900 | dj_report->report_params[DEVICE_PAIRED_PARAM_EQUAD_ID_MSB]; |
901 | workitem.quad_id_lsb = |
902 | dj_report->report_params[DEVICE_PAIRED_PARAM_EQUAD_ID_LSB]; |
903 | workitem.reports_supported = get_unaligned_le32( |
904 | p: dj_report->report_params + |
905 | DEVICE_PAIRED_RF_REPORT_TYPE); |
906 | workitem.reports_supported |= HIDPP; |
907 | if (dj_report->report_type == REPORT_TYPE_NOTIF_DEVICE_UNPAIRED) |
908 | workitem.type = WORKITEM_TYPE_UNPAIRED; |
909 | break; |
910 | default: |
911 | logi_dj_recv_queue_unknown_work(djrcv_dev); |
912 | return; |
913 | } |
914 | |
915 | kfifo_in(&djrcv_dev->notif_fifo, &workitem, sizeof(workitem)); |
916 | schedule_work(work: &djrcv_dev->work); |
917 | } |
918 | |
919 | /* |
920 | * Some quad/bluetooth keyboards have a builtin touchpad in this case we see |
921 | * only 1 paired device with a device_type of REPORT_TYPE_KEYBOARD. For the |
922 | * touchpad to work we must also forward mouse input reports to the dj_hiddev |
923 | * created for the keyboard (instead of forwarding them to a second paired |
924 | * device with a device_type of REPORT_TYPE_MOUSE as we normally would). |
925 | * |
926 | * On Dinovo receivers the keyboard's touchpad and an optional paired actual |
927 | * mouse send separate input reports, INPUT(2) aka STD_MOUSE for the mouse |
928 | * and INPUT(5) aka KBD_MOUSE for the keyboard's touchpad. |
929 | * |
930 | * On MX5x00 receivers (which can also be paired with a Dinovo keyboard) |
931 | * INPUT(2) is used for both an optional paired actual mouse and for the |
932 | * keyboard's touchpad. |
933 | */ |
934 | static const u16 kbd_builtin_touchpad_ids[] = { |
935 | 0xb309, /* Dinovo Edge */ |
936 | 0xb30c, /* Dinovo Mini */ |
937 | }; |
938 | |
939 | static void logi_hidpp_dev_conn_notif_equad(struct hid_device *hdev, |
940 | struct hidpp_event *hidpp_report, |
941 | struct dj_workitem *workitem) |
942 | { |
943 | struct dj_receiver_dev *djrcv_dev = hid_get_drvdata(hdev); |
944 | int i, id; |
945 | |
946 | workitem->type = WORKITEM_TYPE_PAIRED; |
947 | workitem->device_type = hidpp_report->params[HIDPP_PARAM_DEVICE_INFO] & |
948 | HIDPP_DEVICE_TYPE_MASK; |
949 | workitem->quad_id_msb = hidpp_report->params[HIDPP_PARAM_EQUAD_MSB]; |
950 | workitem->quad_id_lsb = hidpp_report->params[HIDPP_PARAM_EQUAD_LSB]; |
951 | switch (workitem->device_type) { |
952 | case REPORT_TYPE_KEYBOARD: |
953 | workitem->reports_supported |= STD_KEYBOARD | MULTIMEDIA | |
954 | POWER_KEYS | MEDIA_CENTER | |
955 | HIDPP; |
956 | id = (workitem->quad_id_msb << 8) | workitem->quad_id_lsb; |
957 | for (i = 0; i < ARRAY_SIZE(kbd_builtin_touchpad_ids); i++) { |
958 | if (id == kbd_builtin_touchpad_ids[i]) { |
959 | if (djrcv_dev->type == recvr_type_dinovo) |
960 | workitem->reports_supported |= KBD_MOUSE; |
961 | else |
962 | workitem->reports_supported |= STD_MOUSE; |
963 | break; |
964 | } |
965 | } |
966 | break; |
967 | case REPORT_TYPE_MOUSE: |
968 | workitem->reports_supported |= STD_MOUSE | HIDPP; |
969 | if (djrcv_dev->type == recvr_type_mouse_only) |
970 | workitem->reports_supported |= MULTIMEDIA; |
971 | break; |
972 | } |
973 | } |
974 | |
975 | static void logi_hidpp_dev_conn_notif_27mhz(struct hid_device *hdev, |
976 | struct hidpp_event *hidpp_report, |
977 | struct dj_workitem *workitem) |
978 | { |
979 | workitem->type = WORKITEM_TYPE_PAIRED; |
980 | workitem->quad_id_lsb = hidpp_report->params[HIDPP_PARAM_27MHZ_DEVID]; |
981 | switch (hidpp_report->device_index) { |
982 | case 1: /* Index 1 is always a mouse */ |
983 | case 2: /* Index 2 is always a mouse */ |
984 | workitem->device_type = HIDPP_DEVICE_TYPE_MOUSE; |
985 | workitem->reports_supported |= STD_MOUSE | HIDPP; |
986 | break; |
987 | case 3: /* Index 3 is always the keyboard */ |
988 | if (hidpp_report->params[HIDPP_PARAM_DEVICE_INFO] & HIDPP_27MHZ_SECURE_MASK) { |
989 | hid_info(hdev, "Keyboard connection is encrypted\n" ); |
990 | } else { |
991 | hid_warn(hdev, "Keyboard events are send over the air in plain-text / unencrypted\n" ); |
992 | hid_warn(hdev, "See: https://gitlab.freedesktop.org/jwrdegoede/logitech-27mhz-keyboard-encryption-setup/\n" ); |
993 | } |
994 | fallthrough; |
995 | case 4: /* Index 4 is used for an optional separate numpad */ |
996 | workitem->device_type = HIDPP_DEVICE_TYPE_KEYBOARD; |
997 | workitem->reports_supported |= STD_KEYBOARD | MULTIMEDIA | |
998 | POWER_KEYS | HIDPP; |
999 | break; |
1000 | default: |
1001 | hid_warn(hdev, "%s: unexpected device-index %d" , __func__, |
1002 | hidpp_report->device_index); |
1003 | } |
1004 | } |
1005 | |
1006 | static void logi_hidpp_recv_queue_notif(struct hid_device *hdev, |
1007 | struct hidpp_event *hidpp_report) |
1008 | { |
1009 | /* We are called from atomic context (tasklet && djrcv->lock held) */ |
1010 | struct dj_receiver_dev *djrcv_dev = hid_get_drvdata(hdev); |
1011 | const char *device_type = "UNKNOWN" ; |
1012 | struct dj_workitem workitem = { |
1013 | .type = WORKITEM_TYPE_EMPTY, |
1014 | .device_index = hidpp_report->device_index, |
1015 | }; |
1016 | |
1017 | switch (hidpp_report->params[HIDPP_PARAM_PROTO_TYPE]) { |
1018 | case 0x01: |
1019 | device_type = "Bluetooth" ; |
1020 | /* Bluetooth connect packet contents is the same as (e)QUAD */ |
1021 | logi_hidpp_dev_conn_notif_equad(hdev, hidpp_report, workitem: &workitem); |
1022 | if (!(hidpp_report->params[HIDPP_PARAM_DEVICE_INFO] & |
1023 | HIDPP_MANUFACTURER_MASK)) { |
1024 | hid_info(hdev, "Non Logitech device connected on slot %d\n" , |
1025 | hidpp_report->device_index); |
1026 | workitem.reports_supported &= ~HIDPP; |
1027 | } |
1028 | break; |
1029 | case 0x02: |
1030 | device_type = "27 Mhz" ; |
1031 | logi_hidpp_dev_conn_notif_27mhz(hdev, hidpp_report, workitem: &workitem); |
1032 | break; |
1033 | case 0x03: |
1034 | device_type = "QUAD or eQUAD" ; |
1035 | logi_hidpp_dev_conn_notif_equad(hdev, hidpp_report, workitem: &workitem); |
1036 | break; |
1037 | case 0x04: |
1038 | device_type = "eQUAD step 4 DJ" ; |
1039 | logi_hidpp_dev_conn_notif_equad(hdev, hidpp_report, workitem: &workitem); |
1040 | break; |
1041 | case 0x05: |
1042 | device_type = "DFU Lite" ; |
1043 | break; |
1044 | case 0x06: |
1045 | device_type = "eQUAD step 4 Lite" ; |
1046 | logi_hidpp_dev_conn_notif_equad(hdev, hidpp_report, workitem: &workitem); |
1047 | break; |
1048 | case 0x07: |
1049 | device_type = "eQUAD step 4 Gaming" ; |
1050 | logi_hidpp_dev_conn_notif_equad(hdev, hidpp_report, workitem: &workitem); |
1051 | workitem.reports_supported |= STD_KEYBOARD; |
1052 | break; |
1053 | case 0x08: |
1054 | device_type = "eQUAD step 4 for gamepads" ; |
1055 | break; |
1056 | case 0x0a: |
1057 | device_type = "eQUAD nano Lite" ; |
1058 | logi_hidpp_dev_conn_notif_equad(hdev, hidpp_report, workitem: &workitem); |
1059 | break; |
1060 | case 0x0c: |
1061 | device_type = "eQUAD Lightspeed 1" ; |
1062 | logi_hidpp_dev_conn_notif_equad(hdev, hidpp_report, workitem: &workitem); |
1063 | workitem.reports_supported |= STD_KEYBOARD; |
1064 | break; |
1065 | case 0x0d: |
1066 | device_type = "eQUAD Lightspeed 1.1" ; |
1067 | logi_hidpp_dev_conn_notif_equad(hdev, hidpp_report, workitem: &workitem); |
1068 | workitem.reports_supported |= STD_KEYBOARD; |
1069 | break; |
1070 | case 0x0f: |
1071 | case 0x11: |
1072 | device_type = "eQUAD Lightspeed 1.2" ; |
1073 | logi_hidpp_dev_conn_notif_equad(hdev, hidpp_report, workitem: &workitem); |
1074 | workitem.reports_supported |= STD_KEYBOARD; |
1075 | break; |
1076 | } |
1077 | |
1078 | /* custom receiver device (eg. powerplay) */ |
1079 | if (hidpp_report->device_index == 7) { |
1080 | workitem.reports_supported |= HIDPP; |
1081 | } |
1082 | |
1083 | if (workitem.type == WORKITEM_TYPE_EMPTY) { |
1084 | hid_warn(hdev, |
1085 | "unusable device of type %s (0x%02x) connected on slot %d" , |
1086 | device_type, |
1087 | hidpp_report->params[HIDPP_PARAM_PROTO_TYPE], |
1088 | hidpp_report->device_index); |
1089 | return; |
1090 | } |
1091 | |
1092 | hid_info(hdev, "device of type %s (0x%02x) connected on slot %d" , |
1093 | device_type, hidpp_report->params[HIDPP_PARAM_PROTO_TYPE], |
1094 | hidpp_report->device_index); |
1095 | |
1096 | kfifo_in(&djrcv_dev->notif_fifo, &workitem, sizeof(workitem)); |
1097 | schedule_work(work: &djrcv_dev->work); |
1098 | } |
1099 | |
1100 | static void logi_dj_recv_forward_null_report(struct dj_receiver_dev *djrcv_dev, |
1101 | struct dj_report *dj_report) |
1102 | { |
1103 | /* We are called from atomic context (tasklet && djrcv->lock held) */ |
1104 | unsigned int i; |
1105 | u8 reportbuffer[MAX_REPORT_SIZE]; |
1106 | struct dj_device *djdev; |
1107 | |
1108 | djdev = djrcv_dev->paired_dj_devices[dj_report->device_index]; |
1109 | |
1110 | memset(reportbuffer, 0, sizeof(reportbuffer)); |
1111 | |
1112 | for (i = 0; i < NUMBER_OF_HID_REPORTS; i++) { |
1113 | if (djdev->reports_supported & (1 << i)) { |
1114 | reportbuffer[0] = i; |
1115 | if (hid_input_report(hid: djdev->hdev, |
1116 | type: HID_INPUT_REPORT, |
1117 | data: reportbuffer, |
1118 | size: hid_reportid_size_map[i], interrupt: 1)) { |
1119 | dbg_hid("hid_input_report error sending null " |
1120 | "report\n" ); |
1121 | } |
1122 | } |
1123 | } |
1124 | } |
1125 | |
1126 | static void logi_dj_recv_forward_dj(struct dj_receiver_dev *djrcv_dev, |
1127 | struct dj_report *dj_report) |
1128 | { |
1129 | /* We are called from atomic context (tasklet && djrcv->lock held) */ |
1130 | struct dj_device *dj_device; |
1131 | |
1132 | dj_device = djrcv_dev->paired_dj_devices[dj_report->device_index]; |
1133 | |
1134 | if ((dj_report->report_type > ARRAY_SIZE(hid_reportid_size_map) - 1) || |
1135 | (hid_reportid_size_map[dj_report->report_type] == 0)) { |
1136 | dbg_hid("invalid report type:%x\n" , dj_report->report_type); |
1137 | return; |
1138 | } |
1139 | |
1140 | if (hid_input_report(hid: dj_device->hdev, |
1141 | type: HID_INPUT_REPORT, data: &dj_report->report_type, |
1142 | size: hid_reportid_size_map[dj_report->report_type], interrupt: 1)) { |
1143 | dbg_hid("hid_input_report error\n" ); |
1144 | } |
1145 | } |
1146 | |
1147 | static void logi_dj_recv_forward_report(struct dj_device *dj_dev, u8 *data, |
1148 | int size) |
1149 | { |
1150 | /* We are called from atomic context (tasklet && djrcv->lock held) */ |
1151 | if (hid_input_report(hid: dj_dev->hdev, type: HID_INPUT_REPORT, data, size, interrupt: 1)) |
1152 | dbg_hid("hid_input_report error\n" ); |
1153 | } |
1154 | |
1155 | static void logi_dj_recv_forward_input_report(struct hid_device *hdev, |
1156 | u8 *data, int size) |
1157 | { |
1158 | struct dj_receiver_dev *djrcv_dev = hid_get_drvdata(hdev); |
1159 | struct dj_device *dj_dev; |
1160 | unsigned long flags; |
1161 | u8 report = data[0]; |
1162 | int i; |
1163 | |
1164 | if (report > REPORT_TYPE_RFREPORT_LAST) { |
1165 | hid_err(hdev, "Unexpected input report number %d\n" , report); |
1166 | return; |
1167 | } |
1168 | |
1169 | spin_lock_irqsave(&djrcv_dev->lock, flags); |
1170 | for (i = 0; i < (DJ_MAX_PAIRED_DEVICES + DJ_DEVICE_INDEX_MIN); i++) { |
1171 | dj_dev = djrcv_dev->paired_dj_devices[i]; |
1172 | if (dj_dev && (dj_dev->reports_supported & BIT(report))) { |
1173 | logi_dj_recv_forward_report(dj_dev, data, size); |
1174 | spin_unlock_irqrestore(lock: &djrcv_dev->lock, flags); |
1175 | return; |
1176 | } |
1177 | } |
1178 | |
1179 | logi_dj_recv_queue_unknown_work(djrcv_dev); |
1180 | spin_unlock_irqrestore(lock: &djrcv_dev->lock, flags); |
1181 | |
1182 | dbg_hid("No dj-devs handling input report number %d\n" , report); |
1183 | } |
1184 | |
1185 | static int logi_dj_recv_send_report(struct dj_receiver_dev *djrcv_dev, |
1186 | struct dj_report *dj_report) |
1187 | { |
1188 | struct hid_device *hdev = djrcv_dev->hidpp; |
1189 | struct hid_report *report; |
1190 | struct hid_report_enum *output_report_enum; |
1191 | u8 *data = (u8 *)(&dj_report->device_index); |
1192 | unsigned int i; |
1193 | |
1194 | output_report_enum = &hdev->report_enum[HID_OUTPUT_REPORT]; |
1195 | report = output_report_enum->report_id_hash[REPORT_ID_DJ_SHORT]; |
1196 | |
1197 | if (!report) { |
1198 | hid_err(hdev, "%s: unable to find dj report\n" , __func__); |
1199 | return -ENODEV; |
1200 | } |
1201 | |
1202 | for (i = 0; i < DJREPORT_SHORT_LENGTH - 1; i++) |
1203 | report->field[0]->value[i] = data[i]; |
1204 | |
1205 | hid_hw_request(hdev, report, reqtype: HID_REQ_SET_REPORT); |
1206 | |
1207 | return 0; |
1208 | } |
1209 | |
1210 | static int logi_dj_recv_query_hidpp_devices(struct dj_receiver_dev *djrcv_dev) |
1211 | { |
1212 | static const u8 template[] = { |
1213 | REPORT_ID_HIDPP_SHORT, |
1214 | HIDPP_RECEIVER_INDEX, |
1215 | HIDPP_SET_REGISTER, |
1216 | HIDPP_REG_CONNECTION_STATE, |
1217 | HIDPP_FAKE_DEVICE_ARRIVAL, |
1218 | 0x00, 0x00 |
1219 | }; |
1220 | u8 *hidpp_report; |
1221 | int retval; |
1222 | |
1223 | hidpp_report = kmemdup(p: template, size: sizeof(template), GFP_KERNEL); |
1224 | if (!hidpp_report) |
1225 | return -ENOMEM; |
1226 | |
1227 | retval = hid_hw_raw_request(hdev: djrcv_dev->hidpp, |
1228 | REPORT_ID_HIDPP_SHORT, |
1229 | buf: hidpp_report, len: sizeof(template), |
1230 | rtype: HID_OUTPUT_REPORT, |
1231 | reqtype: HID_REQ_SET_REPORT); |
1232 | |
1233 | kfree(objp: hidpp_report); |
1234 | return (retval < 0) ? retval : 0; |
1235 | } |
1236 | |
1237 | static int logi_dj_recv_query_paired_devices(struct dj_receiver_dev *djrcv_dev) |
1238 | { |
1239 | struct dj_report *dj_report; |
1240 | int retval; |
1241 | |
1242 | djrcv_dev->last_query = jiffies; |
1243 | |
1244 | if (djrcv_dev->type != recvr_type_dj) |
1245 | return logi_dj_recv_query_hidpp_devices(djrcv_dev); |
1246 | |
1247 | dj_report = kzalloc(size: sizeof(struct dj_report), GFP_KERNEL); |
1248 | if (!dj_report) |
1249 | return -ENOMEM; |
1250 | dj_report->report_id = REPORT_ID_DJ_SHORT; |
1251 | dj_report->device_index = HIDPP_RECEIVER_INDEX; |
1252 | dj_report->report_type = REPORT_TYPE_CMD_GET_PAIRED_DEVICES; |
1253 | retval = logi_dj_recv_send_report(djrcv_dev, dj_report); |
1254 | kfree(objp: dj_report); |
1255 | return retval; |
1256 | } |
1257 | |
1258 | |
1259 | static int logi_dj_recv_switch_to_dj_mode(struct dj_receiver_dev *djrcv_dev, |
1260 | unsigned timeout) |
1261 | { |
1262 | struct hid_device *hdev = djrcv_dev->hidpp; |
1263 | struct dj_report *dj_report; |
1264 | u8 *buf; |
1265 | int retval = 0; |
1266 | |
1267 | dj_report = kzalloc(size: sizeof(struct dj_report), GFP_KERNEL); |
1268 | if (!dj_report) |
1269 | return -ENOMEM; |
1270 | |
1271 | if (djrcv_dev->type == recvr_type_dj) { |
1272 | dj_report->report_id = REPORT_ID_DJ_SHORT; |
1273 | dj_report->device_index = HIDPP_RECEIVER_INDEX; |
1274 | dj_report->report_type = REPORT_TYPE_CMD_SWITCH; |
1275 | dj_report->report_params[CMD_SWITCH_PARAM_DEVBITFIELD] = 0x3F; |
1276 | dj_report->report_params[CMD_SWITCH_PARAM_TIMEOUT_SECONDS] = |
1277 | (u8)timeout; |
1278 | |
1279 | retval = logi_dj_recv_send_report(djrcv_dev, dj_report); |
1280 | |
1281 | /* |
1282 | * Ugly sleep to work around a USB 3.0 bug when the receiver is |
1283 | * still processing the "switch-to-dj" command while we send an |
1284 | * other command. |
1285 | * 50 msec should gives enough time to the receiver to be ready. |
1286 | */ |
1287 | msleep(msecs: 50); |
1288 | |
1289 | if (retval) |
1290 | return retval; |
1291 | } |
1292 | |
1293 | /* |
1294 | * Magical bits to set up hidpp notifications when the dj devices |
1295 | * are connected/disconnected. |
1296 | * |
1297 | * We can reuse dj_report because HIDPP_REPORT_SHORT_LENGTH is smaller |
1298 | * than DJREPORT_SHORT_LENGTH. |
1299 | */ |
1300 | buf = (u8 *)dj_report; |
1301 | |
1302 | memset(buf, 0, HIDPP_REPORT_SHORT_LENGTH); |
1303 | |
1304 | buf[0] = REPORT_ID_HIDPP_SHORT; |
1305 | buf[1] = HIDPP_RECEIVER_INDEX; |
1306 | buf[2] = 0x80; |
1307 | buf[3] = 0x00; |
1308 | buf[4] = 0x00; |
1309 | buf[5] = 0x09; |
1310 | buf[6] = 0x00; |
1311 | |
1312 | retval = hid_hw_raw_request(hdev, REPORT_ID_HIDPP_SHORT, buf, |
1313 | HIDPP_REPORT_SHORT_LENGTH, rtype: HID_OUTPUT_REPORT, |
1314 | reqtype: HID_REQ_SET_REPORT); |
1315 | |
1316 | kfree(objp: dj_report); |
1317 | return retval; |
1318 | } |
1319 | |
1320 | |
1321 | static int logi_dj_ll_open(struct hid_device *hid) |
1322 | { |
1323 | dbg_hid("%s: %s\n" , __func__, hid->phys); |
1324 | return 0; |
1325 | |
1326 | } |
1327 | |
1328 | static void logi_dj_ll_close(struct hid_device *hid) |
1329 | { |
1330 | dbg_hid("%s: %s\n" , __func__, hid->phys); |
1331 | } |
1332 | |
1333 | /* |
1334 | * Register 0xB5 is "pairing information". It is solely intended for the |
1335 | * receiver, so do not overwrite the device index. |
1336 | */ |
1337 | static u8 unifying_pairing_query[] = { REPORT_ID_HIDPP_SHORT, |
1338 | HIDPP_RECEIVER_INDEX, |
1339 | HIDPP_GET_LONG_REGISTER, |
1340 | HIDPP_REG_PAIRING_INFORMATION }; |
1341 | static u8 unifying_pairing_answer[] = { REPORT_ID_HIDPP_LONG, |
1342 | HIDPP_RECEIVER_INDEX, |
1343 | HIDPP_GET_LONG_REGISTER, |
1344 | HIDPP_REG_PAIRING_INFORMATION }; |
1345 | |
1346 | static int logi_dj_ll_raw_request(struct hid_device *hid, |
1347 | unsigned char reportnum, __u8 *buf, |
1348 | size_t count, unsigned char report_type, |
1349 | int reqtype) |
1350 | { |
1351 | struct dj_device *djdev = hid->driver_data; |
1352 | struct dj_receiver_dev *djrcv_dev = djdev->dj_receiver_dev; |
1353 | u8 *out_buf; |
1354 | int ret; |
1355 | |
1356 | if ((buf[0] == REPORT_ID_HIDPP_SHORT) || |
1357 | (buf[0] == REPORT_ID_HIDPP_LONG) || |
1358 | (buf[0] == REPORT_ID_HIDPP_VERY_LONG)) { |
1359 | if (count < 2) |
1360 | return -EINVAL; |
1361 | |
1362 | /* special case where we should not overwrite |
1363 | * the device_index */ |
1364 | if (count == 7 && !memcmp(p: buf, q: unifying_pairing_query, |
1365 | size: sizeof(unifying_pairing_query))) |
1366 | buf[4] = (buf[4] & 0xf0) | (djdev->device_index - 1); |
1367 | else |
1368 | buf[1] = djdev->device_index; |
1369 | return hid_hw_raw_request(hdev: djrcv_dev->hidpp, reportnum, buf, |
1370 | len: count, rtype: report_type, reqtype); |
1371 | } |
1372 | |
1373 | if (buf[0] != REPORT_TYPE_LEDS) |
1374 | return -EINVAL; |
1375 | |
1376 | if (djrcv_dev->type != recvr_type_dj && count >= 2) { |
1377 | if (!djrcv_dev->keyboard) { |
1378 | hid_warn(hid, "Received REPORT_TYPE_LEDS request before the keyboard interface was enumerated\n" ); |
1379 | return 0; |
1380 | } |
1381 | /* usbhid overrides the report ID and ignores the first byte */ |
1382 | return hid_hw_raw_request(hdev: djrcv_dev->keyboard, reportnum: 0, buf, len: count, |
1383 | rtype: report_type, reqtype); |
1384 | } |
1385 | |
1386 | out_buf = kzalloc(DJREPORT_SHORT_LENGTH, GFP_ATOMIC); |
1387 | if (!out_buf) |
1388 | return -ENOMEM; |
1389 | |
1390 | if (count > DJREPORT_SHORT_LENGTH - 2) |
1391 | count = DJREPORT_SHORT_LENGTH - 2; |
1392 | |
1393 | out_buf[0] = REPORT_ID_DJ_SHORT; |
1394 | out_buf[1] = djdev->device_index; |
1395 | memcpy(out_buf + 2, buf, count); |
1396 | |
1397 | ret = hid_hw_raw_request(hdev: djrcv_dev->hidpp, reportnum: out_buf[0], buf: out_buf, |
1398 | DJREPORT_SHORT_LENGTH, rtype: report_type, reqtype); |
1399 | |
1400 | kfree(objp: out_buf); |
1401 | return ret; |
1402 | } |
1403 | |
1404 | static void rdcat(char *rdesc, unsigned int *rsize, const char *data, unsigned int size) |
1405 | { |
1406 | memcpy(rdesc + *rsize, data, size); |
1407 | *rsize += size; |
1408 | } |
1409 | |
1410 | static int logi_dj_ll_parse(struct hid_device *hid) |
1411 | { |
1412 | struct dj_device *djdev = hid->driver_data; |
1413 | unsigned int rsize = 0; |
1414 | char *rdesc; |
1415 | int retval; |
1416 | |
1417 | dbg_hid("%s\n" , __func__); |
1418 | |
1419 | djdev->hdev->version = 0x0111; |
1420 | djdev->hdev->country = 0x00; |
1421 | |
1422 | rdesc = kmalloc(MAX_RDESC_SIZE, GFP_KERNEL); |
1423 | if (!rdesc) |
1424 | return -ENOMEM; |
1425 | |
1426 | if (djdev->reports_supported & STD_KEYBOARD) { |
1427 | dbg_hid("%s: sending a kbd descriptor, reports_supported: %llx\n" , |
1428 | __func__, djdev->reports_supported); |
1429 | rdcat(rdesc, rsize: &rsize, data: kbd_descriptor, size: sizeof(kbd_descriptor)); |
1430 | } |
1431 | |
1432 | if (djdev->reports_supported & STD_MOUSE) { |
1433 | dbg_hid("%s: sending a mouse descriptor, reports_supported: %llx\n" , |
1434 | __func__, djdev->reports_supported); |
1435 | if (djdev->dj_receiver_dev->type == recvr_type_gaming_hidpp || |
1436 | djdev->dj_receiver_dev->type == recvr_type_mouse_only) |
1437 | rdcat(rdesc, rsize: &rsize, data: mse_high_res_descriptor, |
1438 | size: sizeof(mse_high_res_descriptor)); |
1439 | else if (djdev->dj_receiver_dev->type == recvr_type_27mhz) |
1440 | rdcat(rdesc, rsize: &rsize, data: mse_27mhz_descriptor, |
1441 | size: sizeof(mse_27mhz_descriptor)); |
1442 | else if (recvr_type_is_bluetooth(type: djdev->dj_receiver_dev->type)) |
1443 | rdcat(rdesc, rsize: &rsize, data: mse_bluetooth_descriptor, |
1444 | size: sizeof(mse_bluetooth_descriptor)); |
1445 | else |
1446 | rdcat(rdesc, rsize: &rsize, data: mse_descriptor, |
1447 | size: sizeof(mse_descriptor)); |
1448 | } |
1449 | |
1450 | if (djdev->reports_supported & KBD_MOUSE) { |
1451 | dbg_hid("%s: sending a kbd-mouse descriptor, reports_supported: %llx\n" , |
1452 | __func__, djdev->reports_supported); |
1453 | rdcat(rdesc, rsize: &rsize, data: mse5_bluetooth_descriptor, |
1454 | size: sizeof(mse5_bluetooth_descriptor)); |
1455 | } |
1456 | |
1457 | if (djdev->reports_supported & MULTIMEDIA) { |
1458 | dbg_hid("%s: sending a multimedia report descriptor: %llx\n" , |
1459 | __func__, djdev->reports_supported); |
1460 | rdcat(rdesc, rsize: &rsize, data: consumer_descriptor, size: sizeof(consumer_descriptor)); |
1461 | } |
1462 | |
1463 | if (djdev->reports_supported & POWER_KEYS) { |
1464 | dbg_hid("%s: sending a power keys report descriptor: %llx\n" , |
1465 | __func__, djdev->reports_supported); |
1466 | rdcat(rdesc, rsize: &rsize, data: syscontrol_descriptor, size: sizeof(syscontrol_descriptor)); |
1467 | } |
1468 | |
1469 | if (djdev->reports_supported & MEDIA_CENTER) { |
1470 | dbg_hid("%s: sending a media center report descriptor: %llx\n" , |
1471 | __func__, djdev->reports_supported); |
1472 | rdcat(rdesc, rsize: &rsize, data: media_descriptor, size: sizeof(media_descriptor)); |
1473 | } |
1474 | |
1475 | if (djdev->reports_supported & KBD_LEDS) { |
1476 | dbg_hid("%s: need to send kbd leds report descriptor: %llx\n" , |
1477 | __func__, djdev->reports_supported); |
1478 | } |
1479 | |
1480 | if (djdev->reports_supported & HIDPP) { |
1481 | dbg_hid("%s: sending a HID++ descriptor, reports_supported: %llx\n" , |
1482 | __func__, djdev->reports_supported); |
1483 | rdcat(rdesc, rsize: &rsize, data: hidpp_descriptor, |
1484 | size: sizeof(hidpp_descriptor)); |
1485 | } |
1486 | |
1487 | retval = hid_parse_report(hid, start: rdesc, size: rsize); |
1488 | kfree(objp: rdesc); |
1489 | |
1490 | return retval; |
1491 | } |
1492 | |
1493 | static int logi_dj_ll_start(struct hid_device *hid) |
1494 | { |
1495 | dbg_hid("%s\n" , __func__); |
1496 | return 0; |
1497 | } |
1498 | |
1499 | static void logi_dj_ll_stop(struct hid_device *hid) |
1500 | { |
1501 | dbg_hid("%s\n" , __func__); |
1502 | } |
1503 | |
1504 | static bool logi_dj_ll_may_wakeup(struct hid_device *hid) |
1505 | { |
1506 | struct dj_device *djdev = hid->driver_data; |
1507 | struct dj_receiver_dev *djrcv_dev = djdev->dj_receiver_dev; |
1508 | |
1509 | return hid_hw_may_wakeup(hdev: djrcv_dev->hidpp); |
1510 | } |
1511 | |
1512 | static const struct hid_ll_driver logi_dj_ll_driver = { |
1513 | .parse = logi_dj_ll_parse, |
1514 | .start = logi_dj_ll_start, |
1515 | .stop = logi_dj_ll_stop, |
1516 | .open = logi_dj_ll_open, |
1517 | .close = logi_dj_ll_close, |
1518 | .raw_request = logi_dj_ll_raw_request, |
1519 | .may_wakeup = logi_dj_ll_may_wakeup, |
1520 | }; |
1521 | |
1522 | static int logi_dj_dj_event(struct hid_device *hdev, |
1523 | struct hid_report *report, u8 *data, |
1524 | int size) |
1525 | { |
1526 | struct dj_receiver_dev *djrcv_dev = hid_get_drvdata(hdev); |
1527 | struct dj_report *dj_report = (struct dj_report *) data; |
1528 | unsigned long flags; |
1529 | |
1530 | /* |
1531 | * Here we receive all data coming from iface 2, there are 3 cases: |
1532 | * |
1533 | * 1) Data is intended for this driver i. e. data contains arrival, |
1534 | * departure, etc notifications, in which case we queue them for delayed |
1535 | * processing by the work queue. We return 1 to hid-core as no further |
1536 | * processing is required from it. |
1537 | * |
1538 | * 2) Data informs a connection change, if the change means rf link |
1539 | * loss, then we must send a null report to the upper layer to discard |
1540 | * potentially pressed keys that may be repeated forever by the input |
1541 | * layer. Return 1 to hid-core as no further processing is required. |
1542 | * |
1543 | * 3) Data is an actual input event from a paired DJ device in which |
1544 | * case we forward it to the correct hid device (via hid_input_report() |
1545 | * ) and return 1 so hid-core does not anything else with it. |
1546 | */ |
1547 | |
1548 | if ((dj_report->device_index < DJ_DEVICE_INDEX_MIN) || |
1549 | (dj_report->device_index > DJ_DEVICE_INDEX_MAX)) { |
1550 | /* |
1551 | * Device index is wrong, bail out. |
1552 | * This driver can ignore safely the receiver notifications, |
1553 | * so ignore those reports too. |
1554 | */ |
1555 | if (dj_report->device_index != DJ_RECEIVER_INDEX) |
1556 | hid_err(hdev, "%s: invalid device index:%d\n" , |
1557 | __func__, dj_report->device_index); |
1558 | return false; |
1559 | } |
1560 | |
1561 | spin_lock_irqsave(&djrcv_dev->lock, flags); |
1562 | |
1563 | if (!djrcv_dev->paired_dj_devices[dj_report->device_index]) { |
1564 | /* received an event for an unknown device, bail out */ |
1565 | logi_dj_recv_queue_notification(djrcv_dev, dj_report); |
1566 | goto out; |
1567 | } |
1568 | |
1569 | switch (dj_report->report_type) { |
1570 | case REPORT_TYPE_NOTIF_DEVICE_PAIRED: |
1571 | /* pairing notifications are handled above the switch */ |
1572 | break; |
1573 | case REPORT_TYPE_NOTIF_DEVICE_UNPAIRED: |
1574 | logi_dj_recv_queue_notification(djrcv_dev, dj_report); |
1575 | break; |
1576 | case REPORT_TYPE_NOTIF_CONNECTION_STATUS: |
1577 | if (dj_report->report_params[CONNECTION_STATUS_PARAM_STATUS] == |
1578 | STATUS_LINKLOSS) { |
1579 | logi_dj_recv_forward_null_report(djrcv_dev, dj_report); |
1580 | } |
1581 | break; |
1582 | default: |
1583 | logi_dj_recv_forward_dj(djrcv_dev, dj_report); |
1584 | } |
1585 | |
1586 | out: |
1587 | spin_unlock_irqrestore(lock: &djrcv_dev->lock, flags); |
1588 | |
1589 | return true; |
1590 | } |
1591 | |
1592 | static int logi_dj_hidpp_event(struct hid_device *hdev, |
1593 | struct hid_report *report, u8 *data, |
1594 | int size) |
1595 | { |
1596 | struct dj_receiver_dev *djrcv_dev = hid_get_drvdata(hdev); |
1597 | struct hidpp_event *hidpp_report = (struct hidpp_event *) data; |
1598 | struct dj_device *dj_dev; |
1599 | unsigned long flags; |
1600 | u8 device_index = hidpp_report->device_index; |
1601 | |
1602 | if (device_index == HIDPP_RECEIVER_INDEX) { |
1603 | /* special case were the device wants to know its unifying |
1604 | * name */ |
1605 | if (size == HIDPP_REPORT_LONG_LENGTH && |
1606 | !memcmp(p: data, q: unifying_pairing_answer, |
1607 | size: sizeof(unifying_pairing_answer))) |
1608 | device_index = (data[4] & 0x0F) + 1; |
1609 | else |
1610 | return false; |
1611 | } |
1612 | |
1613 | /* |
1614 | * Data is from the HID++ collection, in this case, we forward the |
1615 | * data to the corresponding child dj device and return 0 to hid-core |
1616 | * so he data also goes to the hidraw device of the receiver. This |
1617 | * allows a user space application to implement the full HID++ routing |
1618 | * via the receiver. |
1619 | */ |
1620 | |
1621 | if ((device_index < DJ_DEVICE_INDEX_MIN) || |
1622 | (device_index > DJ_DEVICE_INDEX_MAX)) { |
1623 | /* |
1624 | * Device index is wrong, bail out. |
1625 | * This driver can ignore safely the receiver notifications, |
1626 | * so ignore those reports too. |
1627 | */ |
1628 | hid_err(hdev, "%s: invalid device index:%d\n" , __func__, |
1629 | hidpp_report->device_index); |
1630 | return false; |
1631 | } |
1632 | |
1633 | spin_lock_irqsave(&djrcv_dev->lock, flags); |
1634 | |
1635 | dj_dev = djrcv_dev->paired_dj_devices[device_index]; |
1636 | |
1637 | /* |
1638 | * With 27 MHz receivers, we do not get an explicit unpair event, |
1639 | * remove the old device if the user has paired a *different* device. |
1640 | */ |
1641 | if (djrcv_dev->type == recvr_type_27mhz && dj_dev && |
1642 | hidpp_report->sub_id == REPORT_TYPE_NOTIF_DEVICE_CONNECTED && |
1643 | hidpp_report->params[HIDPP_PARAM_PROTO_TYPE] == 0x02 && |
1644 | hidpp_report->params[HIDPP_PARAM_27MHZ_DEVID] != |
1645 | dj_dev->hdev->product) { |
1646 | struct dj_workitem workitem = { |
1647 | .device_index = hidpp_report->device_index, |
1648 | .type = WORKITEM_TYPE_UNPAIRED, |
1649 | }; |
1650 | kfifo_in(&djrcv_dev->notif_fifo, &workitem, sizeof(workitem)); |
1651 | /* logi_hidpp_recv_queue_notif will queue the work */ |
1652 | dj_dev = NULL; |
1653 | } |
1654 | |
1655 | if (dj_dev) { |
1656 | logi_dj_recv_forward_report(dj_dev, data, size); |
1657 | } else { |
1658 | if (hidpp_report->sub_id == REPORT_TYPE_NOTIF_DEVICE_CONNECTED) |
1659 | logi_hidpp_recv_queue_notif(hdev, hidpp_report); |
1660 | else |
1661 | logi_dj_recv_queue_unknown_work(djrcv_dev); |
1662 | } |
1663 | |
1664 | spin_unlock_irqrestore(lock: &djrcv_dev->lock, flags); |
1665 | |
1666 | return false; |
1667 | } |
1668 | |
1669 | static int logi_dj_raw_event(struct hid_device *hdev, |
1670 | struct hid_report *report, u8 *data, |
1671 | int size) |
1672 | { |
1673 | struct dj_receiver_dev *djrcv_dev = hid_get_drvdata(hdev); |
1674 | dbg_hid("%s, size:%d\n" , __func__, size); |
1675 | |
1676 | if (!djrcv_dev) |
1677 | return 0; |
1678 | |
1679 | if (!hdev->report_enum[HID_INPUT_REPORT].numbered) { |
1680 | |
1681 | if (djrcv_dev->unnumbered_application == HID_GD_KEYBOARD) { |
1682 | /* |
1683 | * For the keyboard, we can reuse the same report by |
1684 | * using the second byte which is constant in the USB |
1685 | * HID report descriptor. |
1686 | */ |
1687 | data[1] = data[0]; |
1688 | data[0] = REPORT_TYPE_KEYBOARD; |
1689 | |
1690 | logi_dj_recv_forward_input_report(hdev, data, size); |
1691 | |
1692 | /* restore previous state */ |
1693 | data[0] = data[1]; |
1694 | data[1] = 0; |
1695 | } |
1696 | /* |
1697 | * Mouse-only receivers send unnumbered mouse data. The 27 MHz |
1698 | * receiver uses 6 byte packets, the nano receiver 8 bytes, |
1699 | * the lightspeed receiver (Pro X Superlight) 13 bytes. |
1700 | */ |
1701 | if (djrcv_dev->unnumbered_application == HID_GD_MOUSE && |
1702 | size <= 13){ |
1703 | u8 mouse_report[14]; |
1704 | |
1705 | /* Prepend report id */ |
1706 | mouse_report[0] = REPORT_TYPE_MOUSE; |
1707 | memcpy(mouse_report + 1, data, size); |
1708 | logi_dj_recv_forward_input_report(hdev, data: mouse_report, |
1709 | size: size + 1); |
1710 | } |
1711 | |
1712 | return false; |
1713 | } |
1714 | |
1715 | switch (data[0]) { |
1716 | case REPORT_ID_DJ_SHORT: |
1717 | if (size != DJREPORT_SHORT_LENGTH) { |
1718 | hid_err(hdev, "Short DJ report bad size (%d)" , size); |
1719 | return false; |
1720 | } |
1721 | return logi_dj_dj_event(hdev, report, data, size); |
1722 | case REPORT_ID_DJ_LONG: |
1723 | if (size != DJREPORT_LONG_LENGTH) { |
1724 | hid_err(hdev, "Long DJ report bad size (%d)" , size); |
1725 | return false; |
1726 | } |
1727 | return logi_dj_dj_event(hdev, report, data, size); |
1728 | case REPORT_ID_HIDPP_SHORT: |
1729 | if (size != HIDPP_REPORT_SHORT_LENGTH) { |
1730 | hid_err(hdev, "Short HID++ report bad size (%d)" , size); |
1731 | return false; |
1732 | } |
1733 | return logi_dj_hidpp_event(hdev, report, data, size); |
1734 | case REPORT_ID_HIDPP_LONG: |
1735 | if (size != HIDPP_REPORT_LONG_LENGTH) { |
1736 | hid_err(hdev, "Long HID++ report bad size (%d)" , size); |
1737 | return false; |
1738 | } |
1739 | return logi_dj_hidpp_event(hdev, report, data, size); |
1740 | } |
1741 | |
1742 | logi_dj_recv_forward_input_report(hdev, data, size); |
1743 | |
1744 | return false; |
1745 | } |
1746 | |
1747 | static int logi_dj_probe(struct hid_device *hdev, |
1748 | const struct hid_device_id *id) |
1749 | { |
1750 | struct hid_report_enum *rep_enum; |
1751 | struct hid_report *rep; |
1752 | struct dj_receiver_dev *djrcv_dev; |
1753 | struct usb_interface *intf; |
1754 | unsigned int no_dj_interfaces = 0; |
1755 | bool has_hidpp = false; |
1756 | unsigned long flags; |
1757 | int retval; |
1758 | |
1759 | /* |
1760 | * Call to usbhid to fetch the HID descriptors of the current |
1761 | * interface subsequently call to the hid/hid-core to parse the |
1762 | * fetched descriptors. |
1763 | */ |
1764 | retval = hid_parse(hdev); |
1765 | if (retval) { |
1766 | hid_err(hdev, "%s: parse failed\n" , __func__); |
1767 | return retval; |
1768 | } |
1769 | |
1770 | /* |
1771 | * Some KVMs add an extra interface for e.g. mouse emulation. If we |
1772 | * treat these as logitech-dj interfaces then this causes input events |
1773 | * reported through this extra interface to not be reported correctly. |
1774 | * To avoid this, we treat these as generic-hid devices. |
1775 | */ |
1776 | switch (id->driver_data) { |
1777 | case recvr_type_dj: no_dj_interfaces = 3; break; |
1778 | case recvr_type_hidpp: no_dj_interfaces = 2; break; |
1779 | case recvr_type_gaming_hidpp: no_dj_interfaces = 3; break; |
1780 | case recvr_type_mouse_only: no_dj_interfaces = 2; break; |
1781 | case recvr_type_27mhz: no_dj_interfaces = 2; break; |
1782 | case recvr_type_bluetooth: no_dj_interfaces = 2; break; |
1783 | case recvr_type_dinovo: no_dj_interfaces = 2; break; |
1784 | } |
1785 | if (hid_is_usb(hdev)) { |
1786 | intf = to_usb_interface(hdev->dev.parent); |
1787 | if (intf && intf->altsetting->desc.bInterfaceNumber >= |
1788 | no_dj_interfaces) { |
1789 | hdev->quirks |= HID_QUIRK_INPUT_PER_APP; |
1790 | return hid_hw_start(hdev, HID_CONNECT_DEFAULT); |
1791 | } |
1792 | } |
1793 | |
1794 | rep_enum = &hdev->report_enum[HID_INPUT_REPORT]; |
1795 | |
1796 | /* no input reports, bail out */ |
1797 | if (list_empty(head: &rep_enum->report_list)) |
1798 | return -ENODEV; |
1799 | |
1800 | /* |
1801 | * Check for the HID++ application. |
1802 | * Note: we should theoretically check for HID++ and DJ |
1803 | * collections, but this will do. |
1804 | */ |
1805 | list_for_each_entry(rep, &rep_enum->report_list, list) { |
1806 | if (rep->application == 0xff000001) |
1807 | has_hidpp = true; |
1808 | } |
1809 | |
1810 | /* |
1811 | * Ignore interfaces without DJ/HID++ collection, they will not carry |
1812 | * any data, dont create any hid_device for them. |
1813 | */ |
1814 | if (!has_hidpp && id->driver_data == recvr_type_dj) |
1815 | return -ENODEV; |
1816 | |
1817 | /* get the current application attached to the node */ |
1818 | rep = list_first_entry(&rep_enum->report_list, struct hid_report, list); |
1819 | djrcv_dev = dj_get_receiver_dev(hdev, type: id->driver_data, |
1820 | application: rep->application, is_hidpp: has_hidpp); |
1821 | if (!djrcv_dev) { |
1822 | hid_err(hdev, "%s: dj_get_receiver_dev failed\n" , __func__); |
1823 | return -ENOMEM; |
1824 | } |
1825 | |
1826 | if (!rep_enum->numbered) |
1827 | djrcv_dev->unnumbered_application = rep->application; |
1828 | |
1829 | /* Starts the usb device and connects to upper interfaces hiddev and |
1830 | * hidraw */ |
1831 | retval = hid_hw_start(hdev, HID_CONNECT_HIDRAW|HID_CONNECT_HIDDEV); |
1832 | if (retval) { |
1833 | hid_err(hdev, "%s: hid_hw_start returned error\n" , __func__); |
1834 | goto hid_hw_start_fail; |
1835 | } |
1836 | |
1837 | if (has_hidpp) { |
1838 | retval = logi_dj_recv_switch_to_dj_mode(djrcv_dev, timeout: 0); |
1839 | if (retval < 0) { |
1840 | hid_err(hdev, "%s: logi_dj_recv_switch_to_dj_mode returned error:%d\n" , |
1841 | __func__, retval); |
1842 | goto switch_to_dj_mode_fail; |
1843 | } |
1844 | } |
1845 | |
1846 | /* This is enabling the polling urb on the IN endpoint */ |
1847 | retval = hid_hw_open(hdev); |
1848 | if (retval < 0) { |
1849 | hid_err(hdev, "%s: hid_hw_open returned error:%d\n" , |
1850 | __func__, retval); |
1851 | goto llopen_failed; |
1852 | } |
1853 | |
1854 | /* Allow incoming packets to arrive: */ |
1855 | hid_device_io_start(hid: hdev); |
1856 | |
1857 | if (has_hidpp) { |
1858 | spin_lock_irqsave(&djrcv_dev->lock, flags); |
1859 | djrcv_dev->ready = true; |
1860 | spin_unlock_irqrestore(lock: &djrcv_dev->lock, flags); |
1861 | retval = logi_dj_recv_query_paired_devices(djrcv_dev); |
1862 | if (retval < 0) { |
1863 | hid_err(hdev, "%s: logi_dj_recv_query_paired_devices error:%d\n" , |
1864 | __func__, retval); |
1865 | /* |
1866 | * This can happen with a KVM, let the probe succeed, |
1867 | * logi_dj_recv_queue_unknown_work will retry later. |
1868 | */ |
1869 | } |
1870 | } |
1871 | |
1872 | return 0; |
1873 | |
1874 | llopen_failed: |
1875 | switch_to_dj_mode_fail: |
1876 | hid_hw_stop(hdev); |
1877 | |
1878 | hid_hw_start_fail: |
1879 | dj_put_receiver_dev(hdev); |
1880 | return retval; |
1881 | } |
1882 | |
1883 | #ifdef CONFIG_PM |
1884 | static int logi_dj_reset_resume(struct hid_device *hdev) |
1885 | { |
1886 | int retval; |
1887 | struct dj_receiver_dev *djrcv_dev = hid_get_drvdata(hdev); |
1888 | |
1889 | if (!djrcv_dev || djrcv_dev->hidpp != hdev) |
1890 | return 0; |
1891 | |
1892 | retval = logi_dj_recv_switch_to_dj_mode(djrcv_dev, timeout: 0); |
1893 | if (retval < 0) { |
1894 | hid_err(hdev, "%s: logi_dj_recv_switch_to_dj_mode returned error:%d\n" , |
1895 | __func__, retval); |
1896 | } |
1897 | |
1898 | return 0; |
1899 | } |
1900 | #endif |
1901 | |
1902 | static void logi_dj_remove(struct hid_device *hdev) |
1903 | { |
1904 | struct dj_receiver_dev *djrcv_dev = hid_get_drvdata(hdev); |
1905 | struct dj_device *dj_dev; |
1906 | unsigned long flags; |
1907 | int i; |
1908 | |
1909 | dbg_hid("%s\n" , __func__); |
1910 | |
1911 | if (!djrcv_dev) |
1912 | return hid_hw_stop(hdev); |
1913 | |
1914 | /* |
1915 | * This ensures that if the work gets requeued from another |
1916 | * interface of the same receiver it will be a no-op. |
1917 | */ |
1918 | spin_lock_irqsave(&djrcv_dev->lock, flags); |
1919 | djrcv_dev->ready = false; |
1920 | spin_unlock_irqrestore(lock: &djrcv_dev->lock, flags); |
1921 | |
1922 | cancel_work_sync(work: &djrcv_dev->work); |
1923 | |
1924 | hid_hw_close(hdev); |
1925 | hid_hw_stop(hdev); |
1926 | |
1927 | /* |
1928 | * For proper operation we need access to all interfaces, so we destroy |
1929 | * the paired devices when we're unbound from any interface. |
1930 | * |
1931 | * Note we may still be bound to other interfaces, sharing the same |
1932 | * djrcv_dev, so we need locking here. |
1933 | */ |
1934 | for (i = 0; i < (DJ_MAX_PAIRED_DEVICES + DJ_DEVICE_INDEX_MIN); i++) { |
1935 | spin_lock_irqsave(&djrcv_dev->lock, flags); |
1936 | dj_dev = djrcv_dev->paired_dj_devices[i]; |
1937 | djrcv_dev->paired_dj_devices[i] = NULL; |
1938 | spin_unlock_irqrestore(lock: &djrcv_dev->lock, flags); |
1939 | if (dj_dev != NULL) { |
1940 | hid_destroy_device(dj_dev->hdev); |
1941 | kfree(objp: dj_dev); |
1942 | } |
1943 | } |
1944 | |
1945 | dj_put_receiver_dev(hdev); |
1946 | } |
1947 | |
1948 | static const struct hid_device_id logi_dj_receivers[] = { |
1949 | { /* Logitech unifying receiver (0xc52b) */ |
1950 | HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, |
1951 | USB_DEVICE_ID_LOGITECH_UNIFYING_RECEIVER), |
1952 | .driver_data = recvr_type_dj}, |
1953 | { /* Logitech unifying receiver (0xc532) */ |
1954 | HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, |
1955 | USB_DEVICE_ID_LOGITECH_UNIFYING_RECEIVER_2), |
1956 | .driver_data = recvr_type_dj}, |
1957 | |
1958 | { /* Logitech Nano mouse only receiver (0xc52f) */ |
1959 | HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, |
1960 | USB_DEVICE_ID_LOGITECH_NANO_RECEIVER), |
1961 | .driver_data = recvr_type_mouse_only}, |
1962 | { /* Logitech Nano (non DJ) receiver (0xc534) */ |
1963 | HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, |
1964 | USB_DEVICE_ID_LOGITECH_NANO_RECEIVER_2), |
1965 | .driver_data = recvr_type_hidpp}, |
1966 | |
1967 | { /* Logitech G700(s) receiver (0xc531) */ |
1968 | HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, |
1969 | USB_DEVICE_ID_LOGITECH_G700_RECEIVER), |
1970 | .driver_data = recvr_type_gaming_hidpp}, |
1971 | { /* Logitech G602 receiver (0xc537) */ |
1972 | HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, |
1973 | 0xc537), |
1974 | .driver_data = recvr_type_gaming_hidpp}, |
1975 | { /* Logitech lightspeed receiver (0xc539) */ |
1976 | HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, |
1977 | USB_DEVICE_ID_LOGITECH_NANO_RECEIVER_LIGHTSPEED_1), |
1978 | .driver_data = recvr_type_gaming_hidpp}, |
1979 | { /* Logitech powerplay receiver (0xc53a) */ |
1980 | HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, |
1981 | USB_DEVICE_ID_LOGITECH_NANO_RECEIVER_POWERPLAY), |
1982 | .driver_data = recvr_type_gaming_hidpp}, |
1983 | { /* Logitech lightspeed receiver (0xc53f) */ |
1984 | HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, |
1985 | USB_DEVICE_ID_LOGITECH_NANO_RECEIVER_LIGHTSPEED_1_1), |
1986 | .driver_data = recvr_type_gaming_hidpp}, |
1987 | { /* Logitech lightspeed receiver (0xc547) */ |
1988 | HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, |
1989 | USB_DEVICE_ID_LOGITECH_NANO_RECEIVER_LIGHTSPEED_1_2), |
1990 | .driver_data = recvr_type_gaming_hidpp}, |
1991 | |
1992 | { /* Logitech 27 MHz HID++ 1.0 receiver (0xc513) */ |
1993 | HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_MX3000_RECEIVER), |
1994 | .driver_data = recvr_type_27mhz}, |
1995 | { /* Logitech 27 MHz HID++ 1.0 receiver (0xc517) */ |
1996 | HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, |
1997 | USB_DEVICE_ID_S510_RECEIVER_2), |
1998 | .driver_data = recvr_type_27mhz}, |
1999 | { /* Logitech 27 MHz HID++ 1.0 mouse-only receiver (0xc51b) */ |
2000 | HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, |
2001 | USB_DEVICE_ID_LOGITECH_27MHZ_MOUSE_RECEIVER), |
2002 | .driver_data = recvr_type_27mhz}, |
2003 | |
2004 | { /* Logitech MX5000 HID++ / bluetooth receiver keyboard intf. (0xc70e) */ |
2005 | HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, |
2006 | USB_DEVICE_ID_MX5000_RECEIVER_KBD_DEV), |
2007 | .driver_data = recvr_type_bluetooth}, |
2008 | { /* Logitech MX5000 HID++ / bluetooth receiver mouse intf. (0xc70a) */ |
2009 | HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, |
2010 | USB_DEVICE_ID_MX5000_RECEIVER_MOUSE_DEV), |
2011 | .driver_data = recvr_type_bluetooth}, |
2012 | { /* Logitech MX5500 HID++ / bluetooth receiver keyboard intf. (0xc71b) */ |
2013 | HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, |
2014 | USB_DEVICE_ID_MX5500_RECEIVER_KBD_DEV), |
2015 | .driver_data = recvr_type_bluetooth}, |
2016 | { /* Logitech MX5500 HID++ / bluetooth receiver mouse intf. (0xc71c) */ |
2017 | HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, |
2018 | USB_DEVICE_ID_MX5500_RECEIVER_MOUSE_DEV), |
2019 | .driver_data = recvr_type_bluetooth}, |
2020 | |
2021 | { /* Logitech Dinovo Edge HID++ / bluetooth receiver keyboard intf. (0xc713) */ |
2022 | HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, |
2023 | USB_DEVICE_ID_DINOVO_EDGE_RECEIVER_KBD_DEV), |
2024 | .driver_data = recvr_type_dinovo}, |
2025 | { /* Logitech Dinovo Edge HID++ / bluetooth receiver mouse intf. (0xc714) */ |
2026 | HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, |
2027 | USB_DEVICE_ID_DINOVO_EDGE_RECEIVER_MOUSE_DEV), |
2028 | .driver_data = recvr_type_dinovo}, |
2029 | { /* Logitech DiNovo Mini HID++ / bluetooth receiver mouse intf. (0xc71e) */ |
2030 | HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, |
2031 | USB_DEVICE_ID_DINOVO_MINI_RECEIVER_KBD_DEV), |
2032 | .driver_data = recvr_type_dinovo}, |
2033 | { /* Logitech DiNovo Mini HID++ / bluetooth receiver keyboard intf. (0xc71f) */ |
2034 | HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, |
2035 | USB_DEVICE_ID_DINOVO_MINI_RECEIVER_MOUSE_DEV), |
2036 | .driver_data = recvr_type_dinovo}, |
2037 | {} |
2038 | }; |
2039 | |
2040 | MODULE_DEVICE_TABLE(hid, logi_dj_receivers); |
2041 | |
2042 | static struct hid_driver logi_djreceiver_driver = { |
2043 | .name = "logitech-djreceiver" , |
2044 | .id_table = logi_dj_receivers, |
2045 | .probe = logi_dj_probe, |
2046 | .remove = logi_dj_remove, |
2047 | .raw_event = logi_dj_raw_event, |
2048 | #ifdef CONFIG_PM |
2049 | .reset_resume = logi_dj_reset_resume, |
2050 | #endif |
2051 | }; |
2052 | |
2053 | module_hid_driver(logi_djreceiver_driver); |
2054 | |
2055 | MODULE_LICENSE("GPL" ); |
2056 | MODULE_AUTHOR("Logitech" ); |
2057 | MODULE_AUTHOR("Nestor Lopez Casado" ); |
2058 | MODULE_AUTHOR("nlopezcasad@logitech.com" ); |
2059 | |