blob: 9ece9aca40a0793dbdc40bfe6df7bc1942b60d32 [file] [log] [blame]
Nestor Lopez Casado534a7b82011-09-15 11:34:49 +02001/*
2 * HID driver for Logitech Unifying receivers
3 *
4 * Copyright (c) 2011 Logitech
5 */
6
7/*
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 *
22 */
23
24
25#include <linux/device.h>
26#include <linux/hid.h>
27#include <linux/module.h>
Benjamin Tissoires8cb37462014-09-30 13:18:26 -040028#include <linux/kfifo.h>
Benjamin Tissoires82c0beb2019-04-20 13:21:47 +020029#include <linux/delay.h>
Jonathan Nieder44d27f72012-05-11 16:17:16 +020030#include <asm/unaligned.h>
Nestor Lopez Casado534a7b82011-09-15 11:34:49 +020031#include "hid-ids.h"
Benjamin Tissoires8cb37462014-09-30 13:18:26 -040032
33#define DJ_MAX_PAIRED_DEVICES 6
Benjamin Tissoires4fcad952019-04-20 13:21:48 +020034#define DJ_MAX_NUMBER_NOTIFS 8
Benjamin Tissoires8cb37462014-09-30 13:18:26 -040035#define DJ_RECEIVER_INDEX 0
36#define DJ_DEVICE_INDEX_MIN 1
37#define DJ_DEVICE_INDEX_MAX 6
38
39#define DJREPORT_SHORT_LENGTH 15
40#define DJREPORT_LONG_LENGTH 32
41
42#define REPORT_ID_DJ_SHORT 0x20
43#define REPORT_ID_DJ_LONG 0x21
44
Benjamin Tissoires925f0f32014-09-30 13:18:29 -040045#define REPORT_ID_HIDPP_SHORT 0x10
46#define REPORT_ID_HIDPP_LONG 0x11
47
48#define HIDPP_REPORT_SHORT_LENGTH 7
49#define HIDPP_REPORT_LONG_LENGTH 20
50
51#define HIDPP_RECEIVER_INDEX 0xff
52
53#define REPORT_TYPE_RFREPORT_FIRST 0x01
Benjamin Tissoires8cb37462014-09-30 13:18:26 -040054#define REPORT_TYPE_RFREPORT_LAST 0x1F
55
56/* Command Switch to DJ mode */
57#define REPORT_TYPE_CMD_SWITCH 0x80
58#define CMD_SWITCH_PARAM_DEVBITFIELD 0x00
59#define CMD_SWITCH_PARAM_TIMEOUT_SECONDS 0x01
60#define TIMEOUT_NO_KEEPALIVE 0x00
61
62/* Command to Get the list of Paired devices */
63#define REPORT_TYPE_CMD_GET_PAIRED_DEVICES 0x81
64
65/* Device Paired Notification */
66#define REPORT_TYPE_NOTIF_DEVICE_PAIRED 0x41
67#define SPFUNCTION_MORE_NOTIF_EXPECTED 0x01
68#define SPFUNCTION_DEVICE_LIST_EMPTY 0x02
69#define DEVICE_PAIRED_PARAM_SPFUNCTION 0x00
70#define DEVICE_PAIRED_PARAM_EQUAD_ID_LSB 0x01
71#define DEVICE_PAIRED_PARAM_EQUAD_ID_MSB 0x02
72#define DEVICE_PAIRED_RF_REPORT_TYPE 0x03
73
74/* Device Un-Paired Notification */
75#define REPORT_TYPE_NOTIF_DEVICE_UNPAIRED 0x40
76
Benjamin Tissoires8cb37462014-09-30 13:18:26 -040077/* Connection Status Notification */
78#define REPORT_TYPE_NOTIF_CONNECTION_STATUS 0x42
79#define CONNECTION_STATUS_PARAM_STATUS 0x00
80#define STATUS_LINKLOSS 0x01
81
82/* Error Notification */
83#define REPORT_TYPE_NOTIF_ERROR 0x7F
84#define NOTIF_ERROR_PARAM_ETYPE 0x00
85#define ETYPE_KEEPALIVE_TIMEOUT 0x01
86
87/* supported DJ HID && RF report types */
88#define REPORT_TYPE_KEYBOARD 0x01
89#define REPORT_TYPE_MOUSE 0x02
90#define REPORT_TYPE_CONSUMER_CONTROL 0x03
91#define REPORT_TYPE_SYSTEM_CONTROL 0x04
92#define REPORT_TYPE_MEDIA_CENTER 0x08
93#define REPORT_TYPE_LEDS 0x0E
94
95/* RF Report types bitfield */
Benjamin Tissoiresa17dd1f2019-04-20 13:21:45 +020096#define STD_KEYBOARD BIT(1)
97#define STD_MOUSE BIT(2)
98#define MULTIMEDIA BIT(3)
99#define POWER_KEYS BIT(4)
100#define MEDIA_CENTER BIT(8)
101#define KBD_LEDS BIT(14)
Benjamin Tissoires8cb37462014-09-30 13:18:26 -0400102
Hans de Goede74808f92019-04-20 13:21:54 +0200103/* HID++ Device Connected Notification */
104#define REPORT_TYPE_NOTIF_DEVICE_CONNECTED 0x41
105#define HIDPP_PARAM_PROTO_TYPE 0x00
106#define HIDPP_PARAM_DEVICE_INFO 0x01
107#define HIDPP_PARAM_EQUAD_LSB 0x02
108#define HIDPP_PARAM_EQUAD_MSB 0x03
109#define HIDPP_DEVICE_TYPE_MASK GENMASK(3, 0)
110#define HIDPP_LINK_STATUS_MASK BIT(6)
111
112#define HIDPP_SET_REGISTER 0x80
Benjamin Tissoiresc0340412019-04-20 13:21:46 +0200113#define HIDPP_GET_LONG_REGISTER 0x83
Hans de Goede74808f92019-04-20 13:21:54 +0200114#define HIDPP_REG_CONNECTION_STATE 0x02
Benjamin Tissoiresc0340412019-04-20 13:21:46 +0200115#define HIDPP_REG_PAIRING_INFORMATION 0xB5
116#define HIDPP_PAIRING_INFORMATION 0x20
Hans de Goede74808f92019-04-20 13:21:54 +0200117#define HIDPP_FAKE_DEVICE_ARRIVAL 0x02
118
119enum recvr_type {
120 recvr_type_dj,
121 recvr_type_hidpp,
Benjamin Tissoiresf5fb57a2019-04-20 13:21:55 +0200122 recvr_type_gaming_hidpp,
Hans de Goede74808f92019-04-20 13:21:54 +0200123};
Benjamin Tissoiresc0340412019-04-20 13:21:46 +0200124
Benjamin Tissoires8cb37462014-09-30 13:18:26 -0400125struct dj_report {
126 u8 report_id;
127 u8 device_index;
128 u8 report_type;
129 u8 report_params[DJREPORT_SHORT_LENGTH - 3];
130};
131
Benjamin Tissoires7bb56a52019-04-20 13:21:44 +0200132struct 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
Benjamin Tissoires8cb37462014-09-30 13:18:26 -0400139struct dj_receiver_dev {
Hans de Goedea1d97cc2019-04-20 13:21:52 +0200140 struct hid_device *mouse;
141 struct hid_device *keyboard;
Hans de Goede0ee75542019-04-20 13:21:51 +0200142 struct hid_device *hidpp;
Benjamin Tissoires8cb37462014-09-30 13:18:26 -0400143 struct dj_device *paired_dj_devices[DJ_MAX_PAIRED_DEVICES +
144 DJ_DEVICE_INDEX_MIN];
Hans de Goedea1d97cc2019-04-20 13:21:52 +0200145 struct list_head list;
146 struct kref kref;
Benjamin Tissoires8cb37462014-09-30 13:18:26 -0400147 struct work_struct work;
148 struct kfifo notif_fifo;
Hans de Goedeb6aeedd2019-04-20 13:21:53 +0200149 unsigned long last_query; /* in jiffies */
Hans de Goedea1d97cc2019-04-20 13:21:52 +0200150 bool ready;
Hans de Goede74808f92019-04-20 13:21:54 +0200151 enum recvr_type type;
152 unsigned int unnumbered_application;
Benjamin Tissoires8cb37462014-09-30 13:18:26 -0400153 spinlock_t lock;
Benjamin Tissoires8cb37462014-09-30 13:18:26 -0400154};
155
156struct dj_device {
157 struct hid_device *hdev;
158 struct dj_receiver_dev *dj_receiver_dev;
159 u32 reports_supported;
160 u8 device_index;
161};
Nestor Lopez Casado534a7b82011-09-15 11:34:49 +0200162
Benjamin Tissoires4fcad952019-04-20 13:21:48 +0200163#define WORKITEM_TYPE_EMPTY 0
164#define WORKITEM_TYPE_PAIRED 1
165#define WORKITEM_TYPE_UNPAIRED 2
166#define WORKITEM_TYPE_UNKNOWN 255
167
168struct dj_workitem {
169 u8 type; /* WORKITEM_TYPE_* */
170 u8 device_index;
171 u8 quad_id_msb;
172 u8 quad_id_lsb;
173 u32 reports_supported;
174};
175
Nestor Lopez Casado534a7b82011-09-15 11:34:49 +0200176/* Keyboard descriptor (1) */
177static const char kbd_descriptor[] = {
178 0x05, 0x01, /* USAGE_PAGE (generic Desktop) */
179 0x09, 0x06, /* USAGE (Keyboard) */
180 0xA1, 0x01, /* COLLECTION (Application) */
181 0x85, 0x01, /* REPORT_ID (1) */
182 0x95, 0x08, /* REPORT_COUNT (8) */
183 0x75, 0x01, /* REPORT_SIZE (1) */
184 0x15, 0x00, /* LOGICAL_MINIMUM (0) */
185 0x25, 0x01, /* LOGICAL_MAXIMUM (1) */
186 0x05, 0x07, /* USAGE_PAGE (Keyboard) */
187 0x19, 0xE0, /* USAGE_MINIMUM (Left Control) */
188 0x29, 0xE7, /* USAGE_MAXIMUM (Right GUI) */
189 0x81, 0x02, /* INPUT (Data,Var,Abs) */
Nestor Lopez Casado534a7b82011-09-15 11:34:49 +0200190 0x95, 0x06, /* REPORT_COUNT (6) */
191 0x75, 0x08, /* REPORT_SIZE (8) */
192 0x15, 0x00, /* LOGICAL_MINIMUM (0) */
193 0x26, 0xFF, 0x00, /* LOGICAL_MAXIMUM (255) */
194 0x05, 0x07, /* USAGE_PAGE (Keyboard) */
195 0x19, 0x00, /* USAGE_MINIMUM (no event) */
196 0x2A, 0xFF, 0x00, /* USAGE_MAXIMUM (reserved) */
197 0x81, 0x00, /* INPUT (Data,Ary,Abs) */
Benjamin Tissoires0e40d352014-02-05 16:33:17 -0500198 0x85, 0x0e, /* REPORT_ID (14) */
199 0x05, 0x08, /* USAGE PAGE (LED page) */
200 0x95, 0x05, /* REPORT COUNT (5) */
201 0x75, 0x01, /* REPORT SIZE (1) */
202 0x15, 0x00, /* LOGICAL_MINIMUM (0) */
203 0x25, 0x01, /* LOGICAL_MAXIMUM (1) */
204 0x19, 0x01, /* USAGE MINIMUM (1) */
205 0x29, 0x05, /* USAGE MAXIMUM (5) */
206 0x91, 0x02, /* OUTPUT (Data, Variable, Absolute) */
207 0x95, 0x01, /* REPORT COUNT (1) */
208 0x75, 0x03, /* REPORT SIZE (3) */
209 0x91, 0x01, /* OUTPUT (Constant) */
Nestor Lopez Casado534a7b82011-09-15 11:34:49 +0200210 0xC0
211};
212
213/* Mouse descriptor (2) */
214static const char mse_descriptor[] = {
215 0x05, 0x01, /* USAGE_PAGE (Generic Desktop) */
216 0x09, 0x02, /* USAGE (Mouse) */
217 0xA1, 0x01, /* COLLECTION (Application) */
218 0x85, 0x02, /* REPORT_ID = 2 */
219 0x09, 0x01, /* USAGE (pointer) */
220 0xA1, 0x00, /* COLLECTION (physical) */
221 0x05, 0x09, /* USAGE_PAGE (buttons) */
222 0x19, 0x01, /* USAGE_MIN (1) */
223 0x29, 0x10, /* USAGE_MAX (16) */
224 0x15, 0x00, /* LOGICAL_MIN (0) */
225 0x25, 0x01, /* LOGICAL_MAX (1) */
226 0x95, 0x10, /* REPORT_COUNT (16) */
227 0x75, 0x01, /* REPORT_SIZE (1) */
228 0x81, 0x02, /* INPUT (data var abs) */
229 0x05, 0x01, /* USAGE_PAGE (generic desktop) */
230 0x16, 0x01, 0xF8, /* LOGICAL_MIN (-2047) */
231 0x26, 0xFF, 0x07, /* LOGICAL_MAX (2047) */
232 0x75, 0x0C, /* REPORT_SIZE (12) */
233 0x95, 0x02, /* REPORT_COUNT (2) */
234 0x09, 0x30, /* USAGE (X) */
235 0x09, 0x31, /* USAGE (Y) */
236 0x81, 0x06, /* INPUT */
237 0x15, 0x81, /* LOGICAL_MIN (-127) */
238 0x25, 0x7F, /* LOGICAL_MAX (127) */
239 0x75, 0x08, /* REPORT_SIZE (8) */
240 0x95, 0x01, /* REPORT_COUNT (1) */
241 0x09, 0x38, /* USAGE (wheel) */
242 0x81, 0x06, /* INPUT */
243 0x05, 0x0C, /* USAGE_PAGE(consumer) */
244 0x0A, 0x38, 0x02, /* USAGE(AC Pan) */
245 0x95, 0x01, /* REPORT_COUNT (1) */
246 0x81, 0x06, /* INPUT */
247 0xC0, /* END_COLLECTION */
248 0xC0, /* END_COLLECTION */
249};
250
Benjamin Tissoiresf5fb57a2019-04-20 13:21:55 +0200251/* Gaming Mouse descriptor (2) */
252static const char mse_high_res_descriptor[] = {
253 0x05, 0x01, /* USAGE_PAGE (Generic Desktop) */
254 0x09, 0x02, /* USAGE (Mouse) */
255 0xA1, 0x01, /* COLLECTION (Application) */
256 0x85, 0x02, /* REPORT_ID = 2 */
257 0x09, 0x01, /* USAGE (pointer) */
258 0xA1, 0x00, /* COLLECTION (physical) */
259 0x05, 0x09, /* USAGE_PAGE (buttons) */
260 0x19, 0x01, /* USAGE_MIN (1) */
261 0x29, 0x10, /* USAGE_MAX (16) */
262 0x15, 0x00, /* LOGICAL_MIN (0) */
263 0x25, 0x01, /* LOGICAL_MAX (1) */
264 0x95, 0x10, /* REPORT_COUNT (16) */
265 0x75, 0x01, /* REPORT_SIZE (1) */
266 0x81, 0x02, /* INPUT (data var abs) */
267 0x05, 0x01, /* USAGE_PAGE (generic desktop) */
268 0x16, 0x01, 0x80, /* LOGICAL_MIN (-32767) */
269 0x26, 0xFF, 0x7F, /* LOGICAL_MAX (32767) */
270 0x75, 0x10, /* REPORT_SIZE (16) */
271 0x95, 0x02, /* REPORT_COUNT (2) */
272 0x09, 0x30, /* USAGE (X) */
273 0x09, 0x31, /* USAGE (Y) */
274 0x81, 0x06, /* INPUT */
275 0x15, 0x81, /* LOGICAL_MIN (-127) */
276 0x25, 0x7F, /* LOGICAL_MAX (127) */
277 0x75, 0x08, /* REPORT_SIZE (8) */
278 0x95, 0x01, /* REPORT_COUNT (1) */
279 0x09, 0x38, /* USAGE (wheel) */
280 0x81, 0x06, /* INPUT */
281 0x05, 0x0C, /* USAGE_PAGE(consumer) */
282 0x0A, 0x38, 0x02, /* USAGE(AC Pan) */
283 0x95, 0x01, /* REPORT_COUNT (1) */
284 0x81, 0x06, /* INPUT */
285 0xC0, /* END_COLLECTION */
286 0xC0, /* END_COLLECTION */
287};
288
Nestor Lopez Casado534a7b82011-09-15 11:34:49 +0200289/* Consumer Control descriptor (3) */
290static const char consumer_descriptor[] = {
291 0x05, 0x0C, /* USAGE_PAGE (Consumer Devices) */
292 0x09, 0x01, /* USAGE (Consumer Control) */
293 0xA1, 0x01, /* COLLECTION (Application) */
294 0x85, 0x03, /* REPORT_ID = 3 */
295 0x75, 0x10, /* REPORT_SIZE (16) */
296 0x95, 0x02, /* REPORT_COUNT (2) */
297 0x15, 0x01, /* LOGICAL_MIN (1) */
298 0x26, 0x8C, 0x02, /* LOGICAL_MAX (652) */
299 0x19, 0x01, /* USAGE_MIN (1) */
300 0x2A, 0x8C, 0x02, /* USAGE_MAX (652) */
301 0x81, 0x00, /* INPUT (Data Ary Abs) */
302 0xC0, /* END_COLLECTION */
303}; /* */
304
305/* System control descriptor (4) */
306static const char syscontrol_descriptor[] = {
307 0x05, 0x01, /* USAGE_PAGE (Generic Desktop) */
308 0x09, 0x80, /* USAGE (System Control) */
309 0xA1, 0x01, /* COLLECTION (Application) */
310 0x85, 0x04, /* REPORT_ID = 4 */
311 0x75, 0x02, /* REPORT_SIZE (2) */
312 0x95, 0x01, /* REPORT_COUNT (1) */
313 0x15, 0x01, /* LOGICAL_MIN (1) */
314 0x25, 0x03, /* LOGICAL_MAX (3) */
315 0x09, 0x82, /* USAGE (System Sleep) */
316 0x09, 0x81, /* USAGE (System Power Down) */
317 0x09, 0x83, /* USAGE (System Wake Up) */
318 0x81, 0x60, /* INPUT (Data Ary Abs NPrf Null) */
319 0x75, 0x06, /* REPORT_SIZE (6) */
320 0x81, 0x03, /* INPUT (Cnst Var Abs) */
321 0xC0, /* END_COLLECTION */
322};
323
324/* Media descriptor (8) */
325static const char media_descriptor[] = {
326 0x06, 0xbc, 0xff, /* Usage Page 0xffbc */
327 0x09, 0x88, /* Usage 0x0088 */
328 0xa1, 0x01, /* BeginCollection */
329 0x85, 0x08, /* Report ID 8 */
330 0x19, 0x01, /* Usage Min 0x0001 */
331 0x29, 0xff, /* Usage Max 0x00ff */
332 0x15, 0x01, /* Logical Min 1 */
333 0x26, 0xff, 0x00, /* Logical Max 255 */
334 0x75, 0x08, /* Report Size 8 */
335 0x95, 0x01, /* Report Count 1 */
336 0x81, 0x00, /* Input */
337 0xc0, /* EndCollection */
338}; /* */
339
Benjamin Tissoires925f0f32014-09-30 13:18:29 -0400340/* HIDPP descriptor */
341static const char hidpp_descriptor[] = {
342 0x06, 0x00, 0xff, /* Usage Page (Vendor Defined Page 1) */
343 0x09, 0x01, /* Usage (Vendor Usage 1) */
344 0xa1, 0x01, /* Collection (Application) */
345 0x85, 0x10, /* Report ID (16) */
346 0x75, 0x08, /* Report Size (8) */
347 0x95, 0x06, /* Report Count (6) */
348 0x15, 0x00, /* Logical Minimum (0) */
349 0x26, 0xff, 0x00, /* Logical Maximum (255) */
350 0x09, 0x01, /* Usage (Vendor Usage 1) */
351 0x81, 0x00, /* Input (Data,Arr,Abs) */
352 0x09, 0x01, /* Usage (Vendor Usage 1) */
353 0x91, 0x00, /* Output (Data,Arr,Abs) */
354 0xc0, /* End Collection */
355 0x06, 0x00, 0xff, /* Usage Page (Vendor Defined Page 1) */
356 0x09, 0x02, /* Usage (Vendor Usage 2) */
357 0xa1, 0x01, /* Collection (Application) */
358 0x85, 0x11, /* Report ID (17) */
359 0x75, 0x08, /* Report Size (8) */
360 0x95, 0x13, /* Report Count (19) */
361 0x15, 0x00, /* Logical Minimum (0) */
362 0x26, 0xff, 0x00, /* Logical Maximum (255) */
363 0x09, 0x02, /* Usage (Vendor Usage 2) */
364 0x81, 0x00, /* Input (Data,Arr,Abs) */
365 0x09, 0x02, /* Usage (Vendor Usage 2) */
366 0x91, 0x00, /* Output (Data,Arr,Abs) */
367 0xc0, /* End Collection */
368 0x06, 0x00, 0xff, /* Usage Page (Vendor Defined Page 1) */
369 0x09, 0x04, /* Usage (Vendor Usage 0x04) */
370 0xa1, 0x01, /* Collection (Application) */
371 0x85, 0x20, /* Report ID (32) */
372 0x75, 0x08, /* Report Size (8) */
373 0x95, 0x0e, /* Report Count (14) */
374 0x15, 0x00, /* Logical Minimum (0) */
375 0x26, 0xff, 0x00, /* Logical Maximum (255) */
376 0x09, 0x41, /* Usage (Vendor Usage 0x41) */
377 0x81, 0x00, /* Input (Data,Arr,Abs) */
378 0x09, 0x41, /* Usage (Vendor Usage 0x41) */
379 0x91, 0x00, /* Output (Data,Arr,Abs) */
380 0x85, 0x21, /* Report ID (33) */
381 0x95, 0x1f, /* Report Count (31) */
382 0x15, 0x00, /* Logical Minimum (0) */
383 0x26, 0xff, 0x00, /* Logical Maximum (255) */
384 0x09, 0x42, /* Usage (Vendor Usage 0x42) */
385 0x81, 0x00, /* Input (Data,Arr,Abs) */
386 0x09, 0x42, /* Usage (Vendor Usage 0x42) */
387 0x91, 0x00, /* Output (Data,Arr,Abs) */
388 0xc0, /* End Collection */
389};
390
Nestor Lopez Casado534a7b82011-09-15 11:34:49 +0200391/* Maximum size of all defined hid reports in bytes (including report id) */
392#define MAX_REPORT_SIZE 8
393
Henrik Rydberg2a039bf2012-04-22 14:21:39 +0200394/* Make sure all descriptors are present here */
395#define MAX_RDESC_SIZE \
396 (sizeof(kbd_descriptor) + \
397 sizeof(mse_descriptor) + \
398 sizeof(consumer_descriptor) + \
399 sizeof(syscontrol_descriptor) + \
Benjamin Tissoires925f0f32014-09-30 13:18:29 -0400400 sizeof(media_descriptor) + \
401 sizeof(hidpp_descriptor))
Henrik Rydberg2a039bf2012-04-22 14:21:39 +0200402
Nestor Lopez Casado534a7b82011-09-15 11:34:49 +0200403/* Number of possible hid report types that can be created by this driver.
404 *
405 * Right now, RF report types have the same report types (or report id's)
406 * than the hid report created from those RF reports. In the future
407 * this doesnt have to be true.
408 *
409 * For instance, RF report type 0x01 which has a size of 8 bytes, corresponds
410 * to hid report id 0x01, this is standard keyboard. Same thing applies to mice
411 * reports and consumer control, etc. If a new RF report is created, it doesn't
412 * has to have the same report id as its corresponding hid report, so an
413 * translation may have to take place for future report types.
414 */
415#define NUMBER_OF_HID_REPORTS 32
416static const u8 hid_reportid_size_map[NUMBER_OF_HID_REPORTS] = {
417 [1] = 8, /* Standard keyboard */
418 [2] = 8, /* Standard mouse */
419 [3] = 5, /* Consumer control */
420 [4] = 2, /* System control */
421 [8] = 2, /* Media Center */
422};
423
424
425#define LOGITECH_DJ_INTERFACE_NUMBER 0x02
426
Nestor Lopez Casado534a7b82011-09-15 11:34:49 +0200427static struct hid_ll_driver logi_dj_ll_driver;
428
Nestor Lopez Casadoc63e0e32013-07-18 06:21:30 -0700429static int logi_dj_recv_query_paired_devices(struct dj_receiver_dev *djrcv_dev);
Hans de Goedea1d97cc2019-04-20 13:21:52 +0200430static void delayedwork_callback(struct work_struct *work);
431
432static LIST_HEAD(dj_hdev_list);
433static DEFINE_MUTEX(dj_hdev_list_lock);
434
435/*
436 * dj/HID++ receivers are really a single logical entity, but for BIOS/Windows
437 * compatibility they have multiple USB interfaces. On HID++ receivers we need
438 * to listen for input reports on both interfaces. The functions below are used
439 * to create a single struct dj_receiver_dev for all interfaces belonging to
440 * a single USB-device / receiver.
441 */
442static struct dj_receiver_dev *dj_find_receiver_dev(struct hid_device *hdev)
443{
444 struct dj_receiver_dev *djrcv_dev;
445
446 /* Try to find an already-probed interface from the same device */
447 list_for_each_entry(djrcv_dev, &dj_hdev_list, list) {
448 if (djrcv_dev->mouse &&
449 hid_compare_device_paths(hdev, djrcv_dev->mouse, '/')) {
450 kref_get(&djrcv_dev->kref);
451 return djrcv_dev;
452 }
453 if (djrcv_dev->keyboard &&
454 hid_compare_device_paths(hdev, djrcv_dev->keyboard, '/')) {
455 kref_get(&djrcv_dev->kref);
456 return djrcv_dev;
457 }
458 if (djrcv_dev->hidpp &&
459 hid_compare_device_paths(hdev, djrcv_dev->hidpp, '/')) {
460 kref_get(&djrcv_dev->kref);
461 return djrcv_dev;
462 }
463 }
464
465 return NULL;
466}
467
468static void dj_release_receiver_dev(struct kref *kref)
469{
470 struct dj_receiver_dev *djrcv_dev = container_of(kref, struct dj_receiver_dev, kref);
471
472 list_del(&djrcv_dev->list);
473 kfifo_free(&djrcv_dev->notif_fifo);
474 kfree(djrcv_dev);
475}
476
477static void dj_put_receiver_dev(struct hid_device *hdev)
478{
479 struct dj_receiver_dev *djrcv_dev = hid_get_drvdata(hdev);
480
481 mutex_lock(&dj_hdev_list_lock);
482
483 if (djrcv_dev->mouse == hdev)
484 djrcv_dev->mouse = NULL;
485 if (djrcv_dev->keyboard == hdev)
486 djrcv_dev->keyboard = NULL;
487 if (djrcv_dev->hidpp == hdev)
488 djrcv_dev->hidpp = NULL;
489
490 kref_put(&djrcv_dev->kref, dj_release_receiver_dev);
491
492 mutex_unlock(&dj_hdev_list_lock);
493}
494
495static struct dj_receiver_dev *dj_get_receiver_dev(struct hid_device *hdev,
Hans de Goede74808f92019-04-20 13:21:54 +0200496 enum recvr_type type,
Hans de Goedea1d97cc2019-04-20 13:21:52 +0200497 unsigned int application,
498 bool is_hidpp)
499{
500 struct dj_receiver_dev *djrcv_dev;
501
502 mutex_lock(&dj_hdev_list_lock);
503
504 djrcv_dev = dj_find_receiver_dev(hdev);
505 if (!djrcv_dev) {
506 djrcv_dev = kzalloc(sizeof(*djrcv_dev), GFP_KERNEL);
507 if (!djrcv_dev)
508 goto out;
509
510 INIT_WORK(&djrcv_dev->work, delayedwork_callback);
511 spin_lock_init(&djrcv_dev->lock);
512 if (kfifo_alloc(&djrcv_dev->notif_fifo,
513 DJ_MAX_NUMBER_NOTIFS * sizeof(struct dj_workitem),
514 GFP_KERNEL)) {
515 kfree(djrcv_dev);
516 djrcv_dev = NULL;
517 goto out;
518 }
519 kref_init(&djrcv_dev->kref);
520 list_add_tail(&djrcv_dev->list, &dj_hdev_list);
Hans de Goedeb6aeedd2019-04-20 13:21:53 +0200521 djrcv_dev->last_query = jiffies;
Hans de Goede74808f92019-04-20 13:21:54 +0200522 djrcv_dev->type = type;
Hans de Goedea1d97cc2019-04-20 13:21:52 +0200523 }
524
525 if (application == HID_GD_KEYBOARD)
526 djrcv_dev->keyboard = hdev;
527 if (application == HID_GD_MOUSE)
528 djrcv_dev->mouse = hdev;
529 if (is_hidpp)
530 djrcv_dev->hidpp = hdev;
531
532 hid_set_drvdata(hdev, djrcv_dev);
533out:
534 mutex_unlock(&dj_hdev_list_lock);
535 return djrcv_dev;
536}
Nestor Lopez Casado534a7b82011-09-15 11:34:49 +0200537
538static void logi_dj_recv_destroy_djhid_device(struct dj_receiver_dev *djrcv_dev,
Benjamin Tissoires4fcad952019-04-20 13:21:48 +0200539 struct dj_workitem *workitem)
Nestor Lopez Casado534a7b82011-09-15 11:34:49 +0200540{
541 /* Called in delayed work context */
542 struct dj_device *dj_dev;
543 unsigned long flags;
544
545 spin_lock_irqsave(&djrcv_dev->lock, flags);
Benjamin Tissoires4fcad952019-04-20 13:21:48 +0200546 dj_dev = djrcv_dev->paired_dj_devices[workitem->device_index];
547 djrcv_dev->paired_dj_devices[workitem->device_index] = NULL;
Nestor Lopez Casado534a7b82011-09-15 11:34:49 +0200548 spin_unlock_irqrestore(&djrcv_dev->lock, flags);
549
550 if (dj_dev != NULL) {
551 hid_destroy_device(dj_dev->hdev);
552 kfree(dj_dev);
553 } else {
Hans de Goede0ee75542019-04-20 13:21:51 +0200554 hid_err(djrcv_dev->hidpp, "%s: can't destroy a NULL device\n",
Nestor Lopez Casado534a7b82011-09-15 11:34:49 +0200555 __func__);
556 }
557}
558
559static void logi_dj_recv_add_djhid_device(struct dj_receiver_dev *djrcv_dev,
Benjamin Tissoires4fcad952019-04-20 13:21:48 +0200560 struct dj_workitem *workitem)
Nestor Lopez Casado534a7b82011-09-15 11:34:49 +0200561{
562 /* Called in delayed work context */
Hans de Goede0ee75542019-04-20 13:21:51 +0200563 struct hid_device *djrcv_hdev = djrcv_dev->hidpp;
Nestor Lopez Casado534a7b82011-09-15 11:34:49 +0200564 struct hid_device *dj_hiddev;
565 struct dj_device *dj_dev;
Benjamin Tissoires4fcad952019-04-20 13:21:48 +0200566 u8 device_index = workitem->device_index;
Hans de Goedef41d7662019-04-20 13:21:50 +0200567 unsigned long flags;
Nestor Lopez Casado534a7b82011-09-15 11:34:49 +0200568
569 /* Device index goes from 1 to 6, we need 3 bytes to store the
570 * semicolon, the index, and a null terminator
571 */
572 unsigned char tmpstr[3];
573
Hans de Goedef41d7662019-04-20 13:21:50 +0200574 /* We are the only one ever adding a device, no need to lock */
Benjamin Tissoires4fcad952019-04-20 13:21:48 +0200575 if (djrcv_dev->paired_dj_devices[device_index]) {
Nestor Lopez Casadoc63e0e32013-07-18 06:21:30 -0700576 /* The device is already known. No need to reallocate it. */
577 dbg_hid("%s: device is already known\n", __func__);
578 return;
579 }
580
Nestor Lopez Casado534a7b82011-09-15 11:34:49 +0200581 dj_hiddev = hid_allocate_device();
582 if (IS_ERR(dj_hiddev)) {
583 dev_err(&djrcv_hdev->dev, "%s: hid_allocate_device failed\n",
584 __func__);
585 return;
586 }
587
588 dj_hiddev->ll_driver = &logi_dj_ll_driver;
Nestor Lopez Casado534a7b82011-09-15 11:34:49 +0200589
590 dj_hiddev->dev.parent = &djrcv_hdev->dev;
591 dj_hiddev->bus = BUS_USB;
Benjamin Tissoires82c0beb2019-04-20 13:21:47 +0200592 dj_hiddev->vendor = djrcv_hdev->vendor;
Benjamin Tissoires4fcad952019-04-20 13:21:48 +0200593 dj_hiddev->product = (workitem->quad_id_msb << 8) |
594 workitem->quad_id_lsb;
Nestor Lopez Casado534a7b82011-09-15 11:34:49 +0200595 snprintf(dj_hiddev->name, sizeof(dj_hiddev->name),
Benjamin Tissoiresd6102742014-09-30 13:18:25 -0400596 "Logitech Unifying Device. Wireless PID:%04x",
597 dj_hiddev->product);
598
599 dj_hiddev->group = HID_GROUP_LOGITECH_DJ_DEVICE;
Nestor Lopez Casado534a7b82011-09-15 11:34:49 +0200600
Benjamin Tissoires82c0beb2019-04-20 13:21:47 +0200601 memcpy(dj_hiddev->phys, djrcv_hdev->phys, sizeof(djrcv_hdev->phys));
Benjamin Tissoires4fcad952019-04-20 13:21:48 +0200602 snprintf(tmpstr, sizeof(tmpstr), ":%d", device_index);
Nestor Lopez Casado534a7b82011-09-15 11:34:49 +0200603 strlcat(dj_hiddev->phys, tmpstr, sizeof(dj_hiddev->phys));
604
605 dj_dev = kzalloc(sizeof(struct dj_device), GFP_KERNEL);
606
607 if (!dj_dev) {
608 dev_err(&djrcv_hdev->dev, "%s: failed allocating dj_device\n",
609 __func__);
610 goto dj_device_allocate_fail;
611 }
612
Benjamin Tissoires4fcad952019-04-20 13:21:48 +0200613 dj_dev->reports_supported = workitem->reports_supported;
Nestor Lopez Casado534a7b82011-09-15 11:34:49 +0200614 dj_dev->hdev = dj_hiddev;
615 dj_dev->dj_receiver_dev = djrcv_dev;
Benjamin Tissoires4fcad952019-04-20 13:21:48 +0200616 dj_dev->device_index = device_index;
Nestor Lopez Casado534a7b82011-09-15 11:34:49 +0200617 dj_hiddev->driver_data = dj_dev;
618
Hans de Goedef41d7662019-04-20 13:21:50 +0200619 spin_lock_irqsave(&djrcv_dev->lock, flags);
Benjamin Tissoires4fcad952019-04-20 13:21:48 +0200620 djrcv_dev->paired_dj_devices[device_index] = dj_dev;
Hans de Goedef41d7662019-04-20 13:21:50 +0200621 spin_unlock_irqrestore(&djrcv_dev->lock, flags);
Nestor Lopez Casado534a7b82011-09-15 11:34:49 +0200622
623 if (hid_add_device(dj_hiddev)) {
624 dev_err(&djrcv_hdev->dev, "%s: failed adding dj_device\n",
625 __func__);
626 goto hid_add_device_fail;
627 }
628
629 return;
630
631hid_add_device_fail:
Hans de Goedef41d7662019-04-20 13:21:50 +0200632 spin_lock_irqsave(&djrcv_dev->lock, flags);
Benjamin Tissoires4fcad952019-04-20 13:21:48 +0200633 djrcv_dev->paired_dj_devices[device_index] = NULL;
Hans de Goedef41d7662019-04-20 13:21:50 +0200634 spin_unlock_irqrestore(&djrcv_dev->lock, flags);
Nestor Lopez Casado534a7b82011-09-15 11:34:49 +0200635 kfree(dj_dev);
636dj_device_allocate_fail:
637 hid_destroy_device(dj_hiddev);
638}
639
640static void delayedwork_callback(struct work_struct *work)
641{
642 struct dj_receiver_dev *djrcv_dev =
643 container_of(work, struct dj_receiver_dev, work);
644
Benjamin Tissoires4fcad952019-04-20 13:21:48 +0200645 struct dj_workitem workitem;
Nestor Lopez Casado534a7b82011-09-15 11:34:49 +0200646 unsigned long flags;
647 int count;
Nestor Lopez Casadoc63e0e32013-07-18 06:21:30 -0700648 int retval;
Nestor Lopez Casado534a7b82011-09-15 11:34:49 +0200649
650 dbg_hid("%s\n", __func__);
651
652 spin_lock_irqsave(&djrcv_dev->lock, flags);
653
Hans de Goedea1d97cc2019-04-20 13:21:52 +0200654 /*
655 * Since we attach to multiple interfaces, we may get scheduled before
656 * we are bound to the HID++ interface, catch this.
657 */
658 if (!djrcv_dev->ready) {
659 pr_warn("%s: delayedwork queued before hidpp interface was enumerated\n",
660 __func__);
661 spin_unlock_irqrestore(&djrcv_dev->lock, flags);
662 return;
663 }
664
Benjamin Tissoires4fcad952019-04-20 13:21:48 +0200665 count = kfifo_out(&djrcv_dev->notif_fifo, &workitem, sizeof(workitem));
Nestor Lopez Casado534a7b82011-09-15 11:34:49 +0200666
Benjamin Tissoires4fcad952019-04-20 13:21:48 +0200667 if (count != sizeof(workitem)) {
Hans de Goede0ee75542019-04-20 13:21:51 +0200668 hid_err(djrcv_dev->hidpp, "delayedwork queued without workitems available\n");
Nestor Lopez Casado534a7b82011-09-15 11:34:49 +0200669 spin_unlock_irqrestore(&djrcv_dev->lock, flags);
670 return;
671 }
672
673 if (!kfifo_is_empty(&djrcv_dev->notif_fifo)) {
674 if (schedule_work(&djrcv_dev->work) == 0) {
675 dbg_hid("%s: did not schedule the work item, was "
676 "already queued\n", __func__);
677 }
678 }
679
680 spin_unlock_irqrestore(&djrcv_dev->lock, flags);
681
Benjamin Tissoires4fcad952019-04-20 13:21:48 +0200682 switch (workitem.type) {
683 case WORKITEM_TYPE_PAIRED:
684 logi_dj_recv_add_djhid_device(djrcv_dev, &workitem);
Nestor Lopez Casado534a7b82011-09-15 11:34:49 +0200685 break;
Benjamin Tissoires4fcad952019-04-20 13:21:48 +0200686 case WORKITEM_TYPE_UNPAIRED:
687 logi_dj_recv_destroy_djhid_device(djrcv_dev, &workitem);
688 break;
689 case WORKITEM_TYPE_UNKNOWN:
690 retval = logi_dj_recv_query_paired_devices(djrcv_dev);
691 if (retval) {
Hans de Goede0ee75542019-04-20 13:21:51 +0200692 hid_err(djrcv_dev->hidpp, "%s: logi_dj_recv_query_paired_devices error: %d\n",
Benjamin Tissoires4fcad952019-04-20 13:21:48 +0200693 __func__, retval);
694 }
695 break;
696 case WORKITEM_TYPE_EMPTY:
697 dbg_hid("%s: device list is empty\n", __func__);
698 break;
699 }
700}
701
Hans de Goedeb6aeedd2019-04-20 13:21:53 +0200702/*
703 * Sometimes we receive reports for which we do not have a paired dj_device
704 * associated with the device_index or report-type to forward the report to.
705 * This means that the original "device paired" notification corresponding
706 * to the dj_device never arrived to this driver. Possible reasons for this are:
707 * 1) hid-core discards all packets coming from a device during probe().
708 * 2) if the receiver is plugged into a KVM switch then the pairing reports
709 * are only forwarded to it if the focus is on this PC.
710 * This function deals with this by re-asking the receiver for the list of
711 * connected devices in the delayed work callback.
712 * This function MUST be called with djrcv->lock held.
713 */
714static void logi_dj_recv_queue_unknown_work(struct dj_receiver_dev *djrcv_dev)
715{
716 struct dj_workitem workitem = { .type = WORKITEM_TYPE_UNKNOWN };
717
718 /* Rate limit queries done because of unhandeled reports to 2/sec */
719 if (time_before(jiffies, djrcv_dev->last_query + HZ / 2))
720 return;
721
722 kfifo_in(&djrcv_dev->notif_fifo, &workitem, sizeof(workitem));
723 schedule_work(&djrcv_dev->work);
724}
725
Benjamin Tissoires4fcad952019-04-20 13:21:48 +0200726static void logi_dj_recv_queue_notification(struct dj_receiver_dev *djrcv_dev,
727 struct dj_report *dj_report)
728{
729 /* We are called from atomic context (tasklet && djrcv->lock held) */
730 struct dj_workitem workitem = {
731 .device_index = dj_report->device_index,
732 };
733
734 switch (dj_report->report_type) {
735 case REPORT_TYPE_NOTIF_DEVICE_PAIRED:
736 workitem.type = WORKITEM_TYPE_PAIRED;
737 if (dj_report->report_params[DEVICE_PAIRED_PARAM_SPFUNCTION] &
738 SPFUNCTION_DEVICE_LIST_EMPTY) {
739 workitem.type = WORKITEM_TYPE_EMPTY;
740 break;
741 }
742 /* fall-through */
Nestor Lopez Casado534a7b82011-09-15 11:34:49 +0200743 case REPORT_TYPE_NOTIF_DEVICE_UNPAIRED:
Benjamin Tissoires4fcad952019-04-20 13:21:48 +0200744 workitem.quad_id_msb =
745 dj_report->report_params[DEVICE_PAIRED_PARAM_EQUAD_ID_MSB];
746 workitem.quad_id_lsb =
747 dj_report->report_params[DEVICE_PAIRED_PARAM_EQUAD_ID_LSB];
748 workitem.reports_supported = get_unaligned_le32(
749 dj_report->report_params +
750 DEVICE_PAIRED_RF_REPORT_TYPE);
751 if (dj_report->report_type == REPORT_TYPE_NOTIF_DEVICE_UNPAIRED)
752 workitem.type = WORKITEM_TYPE_UNPAIRED;
Nestor Lopez Casado534a7b82011-09-15 11:34:49 +0200753 break;
754 default:
Hans de Goedeb6aeedd2019-04-20 13:21:53 +0200755 logi_dj_recv_queue_unknown_work(djrcv_dev);
756 return;
Nestor Lopez Casado534a7b82011-09-15 11:34:49 +0200757 }
Nestor Lopez Casado534a7b82011-09-15 11:34:49 +0200758
Benjamin Tissoires4fcad952019-04-20 13:21:48 +0200759 kfifo_in(&djrcv_dev->notif_fifo, &workitem, sizeof(workitem));
Nestor Lopez Casado534a7b82011-09-15 11:34:49 +0200760
761 if (schedule_work(&djrcv_dev->work) == 0) {
762 dbg_hid("%s: did not schedule the work item, was already "
763 "queued\n", __func__);
764 }
765}
766
Hans de Goede74808f92019-04-20 13:21:54 +0200767static void logi_hidpp_dev_conn_notif_equad(struct hidpp_event *hidpp_report,
768 struct dj_workitem *workitem)
769{
770 workitem->type = WORKITEM_TYPE_PAIRED;
771 workitem->quad_id_msb = hidpp_report->params[HIDPP_PARAM_EQUAD_MSB];
772 workitem->quad_id_lsb = hidpp_report->params[HIDPP_PARAM_EQUAD_LSB];
773 switch (hidpp_report->params[HIDPP_PARAM_DEVICE_INFO] &
774 HIDPP_DEVICE_TYPE_MASK) {
775 case REPORT_TYPE_KEYBOARD:
776 workitem->reports_supported |= STD_KEYBOARD | MULTIMEDIA |
777 POWER_KEYS | MEDIA_CENTER;
778 break;
779 case REPORT_TYPE_MOUSE:
780 workitem->reports_supported |= STD_MOUSE;
781 break;
782 }
783}
784
785static void logi_hidpp_recv_queue_notif(struct hid_device *hdev,
786 struct hidpp_event *hidpp_report)
787{
788 /* We are called from atomic context (tasklet && djrcv->lock held) */
789 struct dj_receiver_dev *djrcv_dev = hid_get_drvdata(hdev);
790 const char *device_type = "UNKNOWN";
791 struct dj_workitem workitem = {
792 .type = WORKITEM_TYPE_EMPTY,
793 .device_index = hidpp_report->device_index,
794 };
795
796 switch (hidpp_report->params[HIDPP_PARAM_PROTO_TYPE]) {
797 case 0x01:
798 device_type = "Bluetooth";
799 break;
800 case 0x02:
801 device_type = "27 Mhz";
802 break;
803 case 0x03:
804 device_type = "QUAD or eQUAD";
805 logi_hidpp_dev_conn_notif_equad(hidpp_report, &workitem);
806 break;
807 case 0x04:
808 device_type = "eQUAD step 4 DJ";
809 logi_hidpp_dev_conn_notif_equad(hidpp_report, &workitem);
810 break;
811 case 0x05:
812 device_type = "DFU Lite";
813 break;
814 case 0x06:
815 device_type = "eQUAD step 4 Lite";
816 logi_hidpp_dev_conn_notif_equad(hidpp_report, &workitem);
817 break;
818 case 0x07:
819 device_type = "eQUAD step 4 Gaming";
820 break;
821 case 0x08:
822 device_type = "eQUAD step 4 for gamepads";
823 break;
824 case 0x0a:
825 device_type = "eQUAD nano Lite";
826 logi_hidpp_dev_conn_notif_equad(hidpp_report, &workitem);
827 break;
828 case 0x0c:
829 device_type = "eQUAD Lightspeed";
Benjamin Tissoiresf5fb57a2019-04-20 13:21:55 +0200830 logi_hidpp_dev_conn_notif_equad(hidpp_report, &workitem);
831 workitem.reports_supported |= STD_KEYBOARD;
Hans de Goede74808f92019-04-20 13:21:54 +0200832 break;
833 }
834
835 if (workitem.type == WORKITEM_TYPE_EMPTY) {
836 hid_warn(hdev,
837 "unusable device of type %s (0x%02x) connected on slot %d",
838 device_type,
839 hidpp_report->params[HIDPP_PARAM_PROTO_TYPE],
840 hidpp_report->device_index);
841 return;
842 }
843
844 hid_info(hdev, "device of type %s (0x%02x) connected on slot %d",
845 device_type, hidpp_report->params[HIDPP_PARAM_PROTO_TYPE],
846 hidpp_report->device_index);
847
848
849 kfifo_in(&djrcv_dev->notif_fifo, &workitem, sizeof(workitem));
850
851 if (schedule_work(&djrcv_dev->work) == 0) {
852 dbg_hid("%s: did not schedule the work item, was already queued\n",
853 __func__);
854 }
855}
856
Nestor Lopez Casado534a7b82011-09-15 11:34:49 +0200857static void logi_dj_recv_forward_null_report(struct dj_receiver_dev *djrcv_dev,
858 struct dj_report *dj_report)
859{
860 /* We are called from atomic context (tasklet && djrcv->lock held) */
861 unsigned int i;
862 u8 reportbuffer[MAX_REPORT_SIZE];
863 struct dj_device *djdev;
864
865 djdev = djrcv_dev->paired_dj_devices[dj_report->device_index];
866
Nestor Lopez Casado534a7b82011-09-15 11:34:49 +0200867 memset(reportbuffer, 0, sizeof(reportbuffer));
868
869 for (i = 0; i < NUMBER_OF_HID_REPORTS; i++) {
870 if (djdev->reports_supported & (1 << i)) {
871 reportbuffer[0] = i;
872 if (hid_input_report(djdev->hdev,
873 HID_INPUT_REPORT,
874 reportbuffer,
875 hid_reportid_size_map[i], 1)) {
876 dbg_hid("hid_input_report error sending null "
877 "report\n");
878 }
879 }
880 }
881}
882
Benjamin Tissoires83898232019-04-20 13:21:43 +0200883static void logi_dj_recv_forward_dj(struct dj_receiver_dev *djrcv_dev,
884 struct dj_report *dj_report)
Nestor Lopez Casado534a7b82011-09-15 11:34:49 +0200885{
886 /* We are called from atomic context (tasklet && djrcv->lock held) */
887 struct dj_device *dj_device;
888
889 dj_device = djrcv_dev->paired_dj_devices[dj_report->device_index];
890
Nestor Lopez Casado534a7b82011-09-15 11:34:49 +0200891 if ((dj_report->report_type > ARRAY_SIZE(hid_reportid_size_map) - 1) ||
892 (hid_reportid_size_map[dj_report->report_type] == 0)) {
893 dbg_hid("invalid report type:%x\n", dj_report->report_type);
894 return;
895 }
896
897 if (hid_input_report(dj_device->hdev,
898 HID_INPUT_REPORT, &dj_report->report_type,
899 hid_reportid_size_map[dj_report->report_type], 1)) {
900 dbg_hid("hid_input_report error\n");
901 }
902}
903
Benjamin Tissoires83898232019-04-20 13:21:43 +0200904static void logi_dj_recv_forward_report(struct dj_device *dj_dev, u8 *data,
905 int size)
Benjamin Tissoires925f0f32014-09-30 13:18:29 -0400906{
907 /* We are called from atomic context (tasklet && djrcv->lock held) */
908 if (hid_input_report(dj_dev->hdev, HID_INPUT_REPORT, data, size, 1))
909 dbg_hid("hid_input_report error\n");
910}
Nestor Lopez Casado534a7b82011-09-15 11:34:49 +0200911
Hans de Goede74808f92019-04-20 13:21:54 +0200912static void logi_dj_recv_forward_input_report(struct hid_device *hdev,
913 u8 *data, int size)
914{
915 struct dj_receiver_dev *djrcv_dev = hid_get_drvdata(hdev);
916 struct dj_device *dj_dev;
917 unsigned long flags;
918 u8 report = data[0];
919 int i;
920
921 if (report > REPORT_TYPE_RFREPORT_LAST) {
922 hid_err(hdev, "Unexpect input report number %d\n", report);
923 return;
924 }
925
926 spin_lock_irqsave(&djrcv_dev->lock, flags);
927 for (i = 0; i < (DJ_MAX_PAIRED_DEVICES + DJ_DEVICE_INDEX_MIN); i++) {
928 dj_dev = djrcv_dev->paired_dj_devices[i];
929 if (dj_dev && (dj_dev->reports_supported & BIT(report))) {
930 logi_dj_recv_forward_report(dj_dev, data, size);
931 spin_unlock_irqrestore(&djrcv_dev->lock, flags);
932 return;
933 }
934 }
935
936 logi_dj_recv_queue_unknown_work(djrcv_dev);
937 spin_unlock_irqrestore(&djrcv_dev->lock, flags);
938
939 dbg_hid("No dj-devs handling input report number %d\n", report);
940}
941
Nestor Lopez Casado534a7b82011-09-15 11:34:49 +0200942static int logi_dj_recv_send_report(struct dj_receiver_dev *djrcv_dev,
943 struct dj_report *dj_report)
944{
Hans de Goede0ee75542019-04-20 13:21:51 +0200945 struct hid_device *hdev = djrcv_dev->hidpp;
Benjamin Tissoiresdcd90062013-03-05 17:09:00 +0100946 struct hid_report *report;
947 struct hid_report_enum *output_report_enum;
948 u8 *data = (u8 *)(&dj_report->device_index);
Kees Cook297502a2013-09-11 21:56:56 +0200949 unsigned int i;
Nestor Lopez Casado534a7b82011-09-15 11:34:49 +0200950
Benjamin Tissoiresdcd90062013-03-05 17:09:00 +0100951 output_report_enum = &hdev->report_enum[HID_OUTPUT_REPORT];
952 report = output_report_enum->report_id_hash[REPORT_ID_DJ_SHORT];
953
954 if (!report) {
955 dev_err(&hdev->dev, "%s: unable to find dj report\n", __func__);
Nestor Lopez Casado534a7b82011-09-15 11:34:49 +0200956 return -ENODEV;
957 }
958
Kees Cook297502a2013-09-11 21:56:56 +0200959 for (i = 0; i < DJREPORT_SHORT_LENGTH - 1; i++)
Benjamin Tissoiresdcd90062013-03-05 17:09:00 +0100960 report->field[0]->value[i] = data[i];
Nestor Lopez Casado534a7b82011-09-15 11:34:49 +0200961
Jiri Kosina83a44ac2013-03-09 10:58:13 +0100962 hid_hw_request(hdev, report, HID_REQ_SET_REPORT);
Benjamin Tissoiresdcd90062013-03-05 17:09:00 +0100963
964 return 0;
Nestor Lopez Casado534a7b82011-09-15 11:34:49 +0200965}
966
Hans de Goede74808f92019-04-20 13:21:54 +0200967static int logi_dj_recv_query_hidpp_devices(struct dj_receiver_dev *djrcv_dev)
968{
969 const u8 template[] = {REPORT_ID_HIDPP_SHORT,
970 HIDPP_RECEIVER_INDEX,
971 HIDPP_SET_REGISTER,
972 HIDPP_REG_CONNECTION_STATE,
973 HIDPP_FAKE_DEVICE_ARRIVAL,
974 0x00, 0x00};
975 u8 *hidpp_report;
976 int retval;
977
978 hidpp_report = kmemdup(template, sizeof(template), GFP_KERNEL);
979 if (!hidpp_report)
980 return -ENOMEM;
981
982 retval = hid_hw_raw_request(djrcv_dev->hidpp,
983 REPORT_ID_HIDPP_SHORT,
984 hidpp_report, sizeof(template),
985 HID_OUTPUT_REPORT,
986 HID_REQ_SET_REPORT);
987
988 kfree(hidpp_report);
989 return 0;
990}
991
Nestor Lopez Casado534a7b82011-09-15 11:34:49 +0200992static int logi_dj_recv_query_paired_devices(struct dj_receiver_dev *djrcv_dev)
993{
Marc Dionned8dc3492012-06-01 18:12:14 -0400994 struct dj_report *dj_report;
995 int retval;
Nestor Lopez Casado534a7b82011-09-15 11:34:49 +0200996
Hans de Goedeb6aeedd2019-04-20 13:21:53 +0200997 djrcv_dev->last_query = jiffies;
998
Hans de Goede74808f92019-04-20 13:21:54 +0200999 if (djrcv_dev->type != recvr_type_dj)
1000 return logi_dj_recv_query_hidpp_devices(djrcv_dev);
1001
Alan Cox8a55ade2012-09-04 15:10:08 +01001002 dj_report = kzalloc(sizeof(struct dj_report), GFP_KERNEL);
Marc Dionned8dc3492012-06-01 18:12:14 -04001003 if (!dj_report)
1004 return -ENOMEM;
1005 dj_report->report_id = REPORT_ID_DJ_SHORT;
1006 dj_report->device_index = 0xFF;
1007 dj_report->report_type = REPORT_TYPE_CMD_GET_PAIRED_DEVICES;
1008 retval = logi_dj_recv_send_report(djrcv_dev, dj_report);
1009 kfree(dj_report);
1010 return retval;
Nestor Lopez Casado534a7b82011-09-15 11:34:49 +02001011}
1012
Nestor Lopez Casadoc63e0e32013-07-18 06:21:30 -07001013
Nestor Lopez Casado534a7b82011-09-15 11:34:49 +02001014static int logi_dj_recv_switch_to_dj_mode(struct dj_receiver_dev *djrcv_dev,
1015 unsigned timeout)
1016{
Hans de Goede0ee75542019-04-20 13:21:51 +02001017 struct hid_device *hdev = djrcv_dev->hidpp;
Marc Dionned8dc3492012-06-01 18:12:14 -04001018 struct dj_report *dj_report;
Benjamin Tissoires6a9ddc82014-09-30 13:18:31 -04001019 u8 *buf;
Hans de Goede74808f92019-04-20 13:21:54 +02001020 int retval = 0;
Nestor Lopez Casado534a7b82011-09-15 11:34:49 +02001021
Alan Cox8a55ade2012-09-04 15:10:08 +01001022 dj_report = kzalloc(sizeof(struct dj_report), GFP_KERNEL);
Marc Dionned8dc3492012-06-01 18:12:14 -04001023 if (!dj_report)
1024 return -ENOMEM;
Benjamin Tisssoires42c22db2014-01-08 17:18:45 -05001025
Hans de Goede74808f92019-04-20 13:21:54 +02001026 if (djrcv_dev->type == recvr_type_dj) {
1027 dj_report->report_id = REPORT_ID_DJ_SHORT;
1028 dj_report->device_index = 0xFF;
1029 dj_report->report_type = REPORT_TYPE_CMD_SWITCH;
1030 dj_report->report_params[CMD_SWITCH_PARAM_DEVBITFIELD] = 0x3F;
1031 dj_report->report_params[CMD_SWITCH_PARAM_TIMEOUT_SECONDS] =
1032 (u8)timeout;
1033
1034 retval = logi_dj_recv_send_report(djrcv_dev, dj_report);
1035
1036 /*
1037 * Ugly sleep to work around a USB 3.0 bug when the receiver is
1038 * still processing the "switch-to-dj" command while we send an
1039 * other command.
1040 * 50 msec should gives enough time to the receiver to be ready.
1041 */
1042 msleep(50);
1043 }
Benjamin Tisssoires42c22db2014-01-08 17:18:45 -05001044
Benjamin Tissoires6a9ddc82014-09-30 13:18:31 -04001045 /*
1046 * Magical bits to set up hidpp notifications when the dj devices
1047 * are connected/disconnected.
1048 *
1049 * We can reuse dj_report because HIDPP_REPORT_SHORT_LENGTH is smaller
1050 * than DJREPORT_SHORT_LENGTH.
1051 */
1052 buf = (u8 *)dj_report;
1053
1054 memset(buf, 0, HIDPP_REPORT_SHORT_LENGTH);
1055
1056 buf[0] = REPORT_ID_HIDPP_SHORT;
1057 buf[1] = 0xFF;
1058 buf[2] = 0x80;
1059 buf[3] = 0x00;
1060 buf[4] = 0x00;
1061 buf[5] = 0x09;
1062 buf[6] = 0x00;
1063
1064 hid_hw_raw_request(hdev, REPORT_ID_HIDPP_SHORT, buf,
1065 HIDPP_REPORT_SHORT_LENGTH, HID_OUTPUT_REPORT,
1066 HID_REQ_SET_REPORT);
1067
1068 kfree(dj_report);
Marc Dionned8dc3492012-06-01 18:12:14 -04001069 return retval;
Nestor Lopez Casado534a7b82011-09-15 11:34:49 +02001070}
1071
1072
1073static int logi_dj_ll_open(struct hid_device *hid)
1074{
1075 dbg_hid("%s:%s\n", __func__, hid->phys);
1076 return 0;
1077
1078}
1079
1080static void logi_dj_ll_close(struct hid_device *hid)
1081{
1082 dbg_hid("%s:%s\n", __func__, hid->phys);
1083}
1084
Benjamin Tissoires8dba3022017-03-27 16:59:21 +02001085/*
1086 * Register 0xB5 is "pairing information". It is solely intended for the
1087 * receiver, so do not overwrite the device index.
1088 */
Benjamin Tissoiresc0340412019-04-20 13:21:46 +02001089static u8 unifying_pairing_query[] = { REPORT_ID_HIDPP_SHORT,
1090 HIDPP_RECEIVER_INDEX,
1091 HIDPP_GET_LONG_REGISTER,
1092 HIDPP_REG_PAIRING_INFORMATION };
1093static u8 unifying_pairing_answer[] = { REPORT_ID_HIDPP_LONG,
1094 HIDPP_RECEIVER_INDEX,
1095 HIDPP_GET_LONG_REGISTER,
1096 HIDPP_REG_PAIRING_INFORMATION };
Benjamin Tissoires33797822014-09-30 13:18:30 -04001097
Benjamin Tissoiresbd27e202014-02-10 12:58:53 -05001098static int logi_dj_ll_raw_request(struct hid_device *hid,
1099 unsigned char reportnum, __u8 *buf,
1100 size_t count, unsigned char report_type,
1101 int reqtype)
Nestor Lopez Casado534a7b82011-09-15 11:34:49 +02001102{
Benjamin Tissoires0e40d352014-02-05 16:33:17 -05001103 struct dj_device *djdev = hid->driver_data;
1104 struct dj_receiver_dev *djrcv_dev = djdev->dj_receiver_dev;
1105 u8 *out_buf;
1106 int ret;
Nestor Lopez Casado534a7b82011-09-15 11:34:49 +02001107
Benjamin Tissoires925f0f32014-09-30 13:18:29 -04001108 if ((buf[0] == REPORT_ID_HIDPP_SHORT) ||
1109 (buf[0] == REPORT_ID_HIDPP_LONG)) {
1110 if (count < 2)
1111 return -EINVAL;
1112
Benjamin Tissoires33797822014-09-30 13:18:30 -04001113 /* special case where we should not overwrite
1114 * the device_index */
Benjamin Tissoires8dba3022017-03-27 16:59:21 +02001115 if (count == 7 && !memcmp(buf, unifying_pairing_query,
1116 sizeof(unifying_pairing_query)))
1117 buf[4] = (buf[4] & 0xf0) | (djdev->device_index - 1);
Benjamin Tissoires33797822014-09-30 13:18:30 -04001118 else
1119 buf[1] = djdev->device_index;
Hans de Goede0ee75542019-04-20 13:21:51 +02001120 return hid_hw_raw_request(djrcv_dev->hidpp, reportnum, buf,
Benjamin Tissoires925f0f32014-09-30 13:18:29 -04001121 count, report_type, reqtype);
1122 }
1123
Benjamin Tissoires0e40d352014-02-05 16:33:17 -05001124 if (buf[0] != REPORT_TYPE_LEDS)
1125 return -EINVAL;
1126
Hans de Goede74808f92019-04-20 13:21:54 +02001127 if (djrcv_dev->type != recvr_type_dj && count >= 2) {
1128 if (!djrcv_dev->keyboard) {
1129 hid_warn(hid, "Received REPORT_TYPE_LEDS request before the keyboard interface was enumerated\n");
1130 return 0;
1131 }
1132 /* usbhid overrides the report ID and ignores the first byte */
1133 return hid_hw_raw_request(djrcv_dev->keyboard, 0, buf, count,
1134 report_type, reqtype);
1135 }
1136
Benjamin Tissoires0e40d352014-02-05 16:33:17 -05001137 out_buf = kzalloc(DJREPORT_SHORT_LENGTH, GFP_ATOMIC);
1138 if (!out_buf)
1139 return -ENOMEM;
1140
Jiri Kosina51217e62014-08-21 09:56:47 -05001141 if (count > DJREPORT_SHORT_LENGTH - 2)
Benjamin Tissoires0e40d352014-02-05 16:33:17 -05001142 count = DJREPORT_SHORT_LENGTH - 2;
1143
1144 out_buf[0] = REPORT_ID_DJ_SHORT;
1145 out_buf[1] = djdev->device_index;
1146 memcpy(out_buf + 2, buf, count);
1147
Hans de Goede0ee75542019-04-20 13:21:51 +02001148 ret = hid_hw_raw_request(djrcv_dev->hidpp, out_buf[0], out_buf,
Benjamin Tissoiresbd27e202014-02-10 12:58:53 -05001149 DJREPORT_SHORT_LENGTH, report_type, reqtype);
Benjamin Tissoires0e40d352014-02-05 16:33:17 -05001150
1151 kfree(out_buf);
1152 return ret;
Nestor Lopez Casado534a7b82011-09-15 11:34:49 +02001153}
1154
Dan Carpenter6d603322013-10-19 12:08:59 +03001155static void rdcat(char *rdesc, unsigned int *rsize, const char *data, unsigned int size)
Henrik Rydberg2a039bf2012-04-22 14:21:39 +02001156{
Dan Carpenter6d603322013-10-19 12:08:59 +03001157 memcpy(rdesc + *rsize, data, size);
Henrik Rydberg2a039bf2012-04-22 14:21:39 +02001158 *rsize += size;
1159}
1160
Nestor Lopez Casado534a7b82011-09-15 11:34:49 +02001161static int logi_dj_ll_parse(struct hid_device *hid)
1162{
1163 struct dj_device *djdev = hid->driver_data;
Henrik Rydberg2a039bf2012-04-22 14:21:39 +02001164 unsigned int rsize = 0;
1165 char *rdesc;
Nestor Lopez Casado534a7b82011-09-15 11:34:49 +02001166 int retval;
1167
1168 dbg_hid("%s\n", __func__);
1169
1170 djdev->hdev->version = 0x0111;
1171 djdev->hdev->country = 0x00;
1172
Henrik Rydberg2a039bf2012-04-22 14:21:39 +02001173 rdesc = kmalloc(MAX_RDESC_SIZE, GFP_KERNEL);
1174 if (!rdesc)
1175 return -ENOMEM;
1176
Nestor Lopez Casado534a7b82011-09-15 11:34:49 +02001177 if (djdev->reports_supported & STD_KEYBOARD) {
1178 dbg_hid("%s: sending a kbd descriptor, reports_supported: %x\n",
1179 __func__, djdev->reports_supported);
Dan Carpenter6d603322013-10-19 12:08:59 +03001180 rdcat(rdesc, &rsize, kbd_descriptor, sizeof(kbd_descriptor));
Nestor Lopez Casado534a7b82011-09-15 11:34:49 +02001181 }
1182
1183 if (djdev->reports_supported & STD_MOUSE) {
1184 dbg_hid("%s: sending a mouse descriptor, reports_supported: "
1185 "%x\n", __func__, djdev->reports_supported);
Benjamin Tissoiresf5fb57a2019-04-20 13:21:55 +02001186 if (djdev->dj_receiver_dev->type == recvr_type_gaming_hidpp)
1187 rdcat(rdesc, &rsize, mse_high_res_descriptor,
1188 sizeof(mse_high_res_descriptor));
1189 else
1190 rdcat(rdesc, &rsize, mse_descriptor,
1191 sizeof(mse_descriptor));
Nestor Lopez Casado534a7b82011-09-15 11:34:49 +02001192 }
1193
1194 if (djdev->reports_supported & MULTIMEDIA) {
1195 dbg_hid("%s: sending a multimedia report descriptor: %x\n",
1196 __func__, djdev->reports_supported);
Dan Carpenter6d603322013-10-19 12:08:59 +03001197 rdcat(rdesc, &rsize, consumer_descriptor, sizeof(consumer_descriptor));
Nestor Lopez Casado534a7b82011-09-15 11:34:49 +02001198 }
1199
1200 if (djdev->reports_supported & POWER_KEYS) {
1201 dbg_hid("%s: sending a power keys report descriptor: %x\n",
1202 __func__, djdev->reports_supported);
Dan Carpenter6d603322013-10-19 12:08:59 +03001203 rdcat(rdesc, &rsize, syscontrol_descriptor, sizeof(syscontrol_descriptor));
Nestor Lopez Casado534a7b82011-09-15 11:34:49 +02001204 }
1205
1206 if (djdev->reports_supported & MEDIA_CENTER) {
1207 dbg_hid("%s: sending a media center report descriptor: %x\n",
1208 __func__, djdev->reports_supported);
Dan Carpenter6d603322013-10-19 12:08:59 +03001209 rdcat(rdesc, &rsize, media_descriptor, sizeof(media_descriptor));
Nestor Lopez Casado534a7b82011-09-15 11:34:49 +02001210 }
1211
1212 if (djdev->reports_supported & KBD_LEDS) {
1213 dbg_hid("%s: need to send kbd leds report descriptor: %x\n",
1214 __func__, djdev->reports_supported);
1215 }
1216
Benjamin Tissoires925f0f32014-09-30 13:18:29 -04001217 rdcat(rdesc, &rsize, hidpp_descriptor, sizeof(hidpp_descriptor));
1218
Henrik Rydberg2a039bf2012-04-22 14:21:39 +02001219 retval = hid_parse_report(hid, rdesc, rsize);
1220 kfree(rdesc);
1221
1222 return retval;
Nestor Lopez Casado534a7b82011-09-15 11:34:49 +02001223}
1224
Nestor Lopez Casado534a7b82011-09-15 11:34:49 +02001225static int logi_dj_ll_start(struct hid_device *hid)
1226{
1227 dbg_hid("%s\n", __func__);
1228 return 0;
1229}
1230
1231static void logi_dj_ll_stop(struct hid_device *hid)
1232{
1233 dbg_hid("%s\n", __func__);
1234}
1235
1236
1237static struct hid_ll_driver logi_dj_ll_driver = {
1238 .parse = logi_dj_ll_parse,
1239 .start = logi_dj_ll_start,
1240 .stop = logi_dj_ll_stop,
1241 .open = logi_dj_ll_open,
1242 .close = logi_dj_ll_close,
Benjamin Tissoiresbd27e202014-02-10 12:58:53 -05001243 .raw_request = logi_dj_ll_raw_request,
Nestor Lopez Casado534a7b82011-09-15 11:34:49 +02001244};
1245
Benjamin Tissoires925f0f32014-09-30 13:18:29 -04001246static int logi_dj_dj_event(struct hid_device *hdev,
Nestor Lopez Casado534a7b82011-09-15 11:34:49 +02001247 struct hid_report *report, u8 *data,
1248 int size)
1249{
1250 struct dj_receiver_dev *djrcv_dev = hid_get_drvdata(hdev);
1251 struct dj_report *dj_report = (struct dj_report *) data;
1252 unsigned long flags;
Nestor Lopez Casado534a7b82011-09-15 11:34:49 +02001253
Benjamin Tissoires925f0f32014-09-30 13:18:29 -04001254 /*
1255 * Here we receive all data coming from iface 2, there are 3 cases:
Nestor Lopez Casado534a7b82011-09-15 11:34:49 +02001256 *
Benjamin Tissoires925f0f32014-09-30 13:18:29 -04001257 * 1) Data is intended for this driver i. e. data contains arrival,
1258 * departure, etc notifications, in which case we queue them for delayed
1259 * processing by the work queue. We return 1 to hid-core as no further
1260 * processing is required from it.
Nestor Lopez Casado534a7b82011-09-15 11:34:49 +02001261 *
Benjamin Tissoires925f0f32014-09-30 13:18:29 -04001262 * 2) Data informs a connection change, if the change means rf link
1263 * loss, then we must send a null report to the upper layer to discard
1264 * potentially pressed keys that may be repeated forever by the input
1265 * layer. Return 1 to hid-core as no further processing is required.
Nestor Lopez Casado534a7b82011-09-15 11:34:49 +02001266 *
Benjamin Tissoires925f0f32014-09-30 13:18:29 -04001267 * 3) Data is an actual input event from a paired DJ device in which
1268 * case we forward it to the correct hid device (via hid_input_report()
1269 * ) and return 1 so hid-core does not anything else with it.
Nestor Lopez Casado534a7b82011-09-15 11:34:49 +02001270 */
Benjamin Tissoires5abfe852014-08-22 16:16:05 -04001271
Jiri Kosinaad3e14d2014-08-21 09:57:17 -05001272 if ((dj_report->device_index < DJ_DEVICE_INDEX_MIN) ||
1273 (dj_report->device_index > DJ_DEVICE_INDEX_MAX)) {
Benjamin Tissoires5abfe852014-08-22 16:16:05 -04001274 /*
1275 * Device index is wrong, bail out.
1276 * This driver can ignore safely the receiver notifications,
1277 * so ignore those reports too.
1278 */
1279 if (dj_report->device_index != DJ_RECEIVER_INDEX)
1280 dev_err(&hdev->dev, "%s: invalid device index:%d\n",
Jiri Kosinaad3e14d2014-08-21 09:57:17 -05001281 __func__, dj_report->device_index);
1282 return false;
1283 }
Nestor Lopez Casado534a7b82011-09-15 11:34:49 +02001284
1285 spin_lock_irqsave(&djrcv_dev->lock, flags);
Benjamin Tissoires368d4e592014-08-22 16:16:06 -04001286
1287 if (!djrcv_dev->paired_dj_devices[dj_report->device_index]) {
1288 /* received an event for an unknown device, bail out */
1289 logi_dj_recv_queue_notification(djrcv_dev, dj_report);
1290 goto out;
1291 }
1292
Benjamin Tissoires5abfe852014-08-22 16:16:05 -04001293 switch (dj_report->report_type) {
1294 case REPORT_TYPE_NOTIF_DEVICE_PAIRED:
Benjamin Tissoires368d4e592014-08-22 16:16:06 -04001295 /* pairing notifications are handled above the switch */
1296 break;
Benjamin Tissoires5abfe852014-08-22 16:16:05 -04001297 case REPORT_TYPE_NOTIF_DEVICE_UNPAIRED:
1298 logi_dj_recv_queue_notification(djrcv_dev, dj_report);
1299 break;
1300 case REPORT_TYPE_NOTIF_CONNECTION_STATUS:
1301 if (dj_report->report_params[CONNECTION_STATUS_PARAM_STATUS] ==
1302 STATUS_LINKLOSS) {
1303 logi_dj_recv_forward_null_report(djrcv_dev, dj_report);
Nestor Lopez Casado534a7b82011-09-15 11:34:49 +02001304 }
Benjamin Tissoires5abfe852014-08-22 16:16:05 -04001305 break;
1306 default:
Benjamin Tissoires83898232019-04-20 13:21:43 +02001307 logi_dj_recv_forward_dj(djrcv_dev, dj_report);
Nestor Lopez Casado534a7b82011-09-15 11:34:49 +02001308 }
Benjamin Tissoires368d4e592014-08-22 16:16:06 -04001309
1310out:
Nestor Lopez Casado534a7b82011-09-15 11:34:49 +02001311 spin_unlock_irqrestore(&djrcv_dev->lock, flags);
1312
Benjamin Tissoires5abfe852014-08-22 16:16:05 -04001313 return true;
Nestor Lopez Casado534a7b82011-09-15 11:34:49 +02001314}
1315
Benjamin Tissoires925f0f32014-09-30 13:18:29 -04001316static int logi_dj_hidpp_event(struct hid_device *hdev,
1317 struct hid_report *report, u8 *data,
1318 int size)
1319{
1320 struct dj_receiver_dev *djrcv_dev = hid_get_drvdata(hdev);
Benjamin Tissoires7bb56a52019-04-20 13:21:44 +02001321 struct hidpp_event *hidpp_report = (struct hidpp_event *) data;
Hans de Goede74808f92019-04-20 13:21:54 +02001322 struct dj_device *dj_dev;
Benjamin Tissoires925f0f32014-09-30 13:18:29 -04001323 unsigned long flags;
Benjamin Tissoires7bb56a52019-04-20 13:21:44 +02001324 u8 device_index = hidpp_report->device_index;
Benjamin Tissoires925f0f32014-09-30 13:18:29 -04001325
Benjamin Tissoires33797822014-09-30 13:18:30 -04001326 if (device_index == HIDPP_RECEIVER_INDEX) {
1327 /* special case were the device wants to know its unifying
1328 * name */
1329 if (size == HIDPP_REPORT_LONG_LENGTH &&
Benjamin Tissoires8dba3022017-03-27 16:59:21 +02001330 !memcmp(data, unifying_pairing_answer,
1331 sizeof(unifying_pairing_answer)))
Benjamin Tissoires33797822014-09-30 13:18:30 -04001332 device_index = (data[4] & 0x0F) + 1;
1333 else
1334 return false;
1335 }
Benjamin Tissoires925f0f32014-09-30 13:18:29 -04001336
1337 /*
1338 * Data is from the HID++ collection, in this case, we forward the
1339 * data to the corresponding child dj device and return 0 to hid-core
1340 * so he data also goes to the hidraw device of the receiver. This
1341 * allows a user space application to implement the full HID++ routing
1342 * via the receiver.
1343 */
1344
1345 if ((device_index < DJ_DEVICE_INDEX_MIN) ||
1346 (device_index > DJ_DEVICE_INDEX_MAX)) {
1347 /*
1348 * Device index is wrong, bail out.
1349 * This driver can ignore safely the receiver notifications,
1350 * so ignore those reports too.
1351 */
1352 dev_err(&hdev->dev, "%s: invalid device index:%d\n",
Benjamin Tissoires7bb56a52019-04-20 13:21:44 +02001353 __func__, hidpp_report->device_index);
Benjamin Tissoires925f0f32014-09-30 13:18:29 -04001354 return false;
1355 }
1356
1357 spin_lock_irqsave(&djrcv_dev->lock, flags);
1358
Hans de Goede74808f92019-04-20 13:21:54 +02001359 dj_dev = djrcv_dev->paired_dj_devices[device_index];
1360 if (dj_dev) {
1361 logi_dj_recv_forward_report(dj_dev, data, size);
1362 } else {
1363 if (hidpp_report->sub_id == REPORT_TYPE_NOTIF_DEVICE_CONNECTED)
1364 logi_hidpp_recv_queue_notif(hdev, hidpp_report);
1365 else
1366 logi_dj_recv_queue_unknown_work(djrcv_dev);
1367 }
Benjamin Tissoires925f0f32014-09-30 13:18:29 -04001368
Benjamin Tissoires925f0f32014-09-30 13:18:29 -04001369 spin_unlock_irqrestore(&djrcv_dev->lock, flags);
1370
1371 return false;
1372}
1373
1374static int logi_dj_raw_event(struct hid_device *hdev,
1375 struct hid_report *report, u8 *data,
1376 int size)
1377{
Hans de Goede74808f92019-04-20 13:21:54 +02001378 struct dj_receiver_dev *djrcv_dev = hid_get_drvdata(hdev);
Benjamin Tissoires925f0f32014-09-30 13:18:29 -04001379 dbg_hid("%s, size:%d\n", __func__, size);
1380
Hans de Goede74808f92019-04-20 13:21:54 +02001381 if (!hdev->report_enum[HID_INPUT_REPORT].numbered) {
1382
1383 if (djrcv_dev->unnumbered_application == HID_GD_KEYBOARD) {
1384 /*
1385 * For the keyboard, we can reuse the same report by
1386 * using the second byte which is constant in the USB
1387 * HID report descriptor.
1388 */
1389 data[1] = data[0];
1390 data[0] = REPORT_TYPE_KEYBOARD;
1391
1392 logi_dj_recv_forward_input_report(hdev, data, size);
1393
1394 /* restore previous state */
1395 data[0] = data[1];
1396 data[1] = 0;
1397 }
1398
1399 return false;
1400 }
1401
Benjamin Tissoires925f0f32014-09-30 13:18:29 -04001402 switch (data[0]) {
1403 case REPORT_ID_DJ_SHORT:
Peter Wuf254ae92014-12-16 16:55:21 +01001404 if (size != DJREPORT_SHORT_LENGTH) {
1405 dev_err(&hdev->dev, "DJ report of bad size (%d)", size);
1406 return false;
1407 }
Benjamin Tissoires925f0f32014-09-30 13:18:29 -04001408 return logi_dj_dj_event(hdev, report, data, size);
Benjamin Tissoiresf5fb57a2019-04-20 13:21:55 +02001409 case REPORT_ID_DJ_LONG:
1410 if (size != DJREPORT_LONG_LENGTH) {
1411 dev_err(&hdev->dev, "DJ report of bad size (%d)", size);
1412 return false;
1413 }
1414 return logi_dj_dj_event(hdev, report, data, size);
Benjamin Tissoires925f0f32014-09-30 13:18:29 -04001415 case REPORT_ID_HIDPP_SHORT:
Peter Wuf254ae92014-12-16 16:55:21 +01001416 if (size != HIDPP_REPORT_SHORT_LENGTH) {
1417 dev_err(&hdev->dev,
1418 "Short HID++ report of bad size (%d)", size);
1419 return false;
1420 }
1421 return logi_dj_hidpp_event(hdev, report, data, size);
Benjamin Tissoires925f0f32014-09-30 13:18:29 -04001422 case REPORT_ID_HIDPP_LONG:
Peter Wuf254ae92014-12-16 16:55:21 +01001423 if (size != HIDPP_REPORT_LONG_LENGTH) {
1424 dev_err(&hdev->dev,
1425 "Long HID++ report of bad size (%d)", size);
1426 return false;
1427 }
Benjamin Tissoires925f0f32014-09-30 13:18:29 -04001428 return logi_dj_hidpp_event(hdev, report, data, size);
1429 }
1430
Hans de Goede74808f92019-04-20 13:21:54 +02001431 logi_dj_recv_forward_input_report(hdev, data, size);
1432
Benjamin Tissoires925f0f32014-09-30 13:18:29 -04001433 return false;
1434}
1435
Nestor Lopez Casado534a7b82011-09-15 11:34:49 +02001436static int logi_dj_probe(struct hid_device *hdev,
1437 const struct hid_device_id *id)
1438{
Benjamin Tissoires82c0beb2019-04-20 13:21:47 +02001439 struct hid_report_enum *rep_enum;
1440 struct hid_report *rep;
Nestor Lopez Casado534a7b82011-09-15 11:34:49 +02001441 struct dj_receiver_dev *djrcv_dev;
Benjamin Tissoires82c0beb2019-04-20 13:21:47 +02001442 bool has_hidpp = false;
Hans de Goedea1d97cc2019-04-20 13:21:52 +02001443 unsigned long flags;
Nestor Lopez Casado534a7b82011-09-15 11:34:49 +02001444 int retval;
1445
Benjamin Tissoires82c0beb2019-04-20 13:21:47 +02001446 /*
1447 * Call to usbhid to fetch the HID descriptors of the current
1448 * interface subsequently call to the hid/hid-core to parse the
1449 * fetched descriptors.
1450 */
1451 retval = hid_parse(hdev);
1452 if (retval) {
1453 dev_err(&hdev->dev,
1454 "%s:parse failed\n", __func__);
1455 return retval;
Nestor Lopez Casado534a7b82011-09-15 11:34:49 +02001456 }
1457
Benjamin Tissoires82c0beb2019-04-20 13:21:47 +02001458 rep_enum = &hdev->report_enum[HID_INPUT_REPORT];
1459
Hans de Goede74808f92019-04-20 13:21:54 +02001460 /* no input reports, bail out */
1461 if (list_empty(&rep_enum->report_list))
1462 return -ENODEV;
1463
Benjamin Tissoires82c0beb2019-04-20 13:21:47 +02001464 /*
1465 * Check for the HID++ application.
1466 * Note: we should theoretically check for HID++ and DJ
1467 * collections, but this will do.
1468 */
1469 list_for_each_entry(rep, &rep_enum->report_list, list) {
1470 if (rep->application == 0xff000001)
1471 has_hidpp = true;
1472 }
1473
1474 /*
1475 * Ignore interfaces without DJ/HID++ collection, they will not carry
1476 * any data, dont create any hid_device for them.
1477 */
Hans de Goede74808f92019-04-20 13:21:54 +02001478 if (!has_hidpp && id->driver_data == recvr_type_dj)
Benjamin Tissoires82c0beb2019-04-20 13:21:47 +02001479 return -ENODEV;
1480
Hans de Goedea1d97cc2019-04-20 13:21:52 +02001481 /* get the current application attached to the node */
1482 rep = list_first_entry(&rep_enum->report_list, struct hid_report, list);
Hans de Goede74808f92019-04-20 13:21:54 +02001483 djrcv_dev = dj_get_receiver_dev(hdev, id->driver_data,
Hans de Goedea1d97cc2019-04-20 13:21:52 +02001484 rep->application, has_hidpp);
Nestor Lopez Casado534a7b82011-09-15 11:34:49 +02001485 if (!djrcv_dev) {
1486 dev_err(&hdev->dev,
1487 "%s:failed allocating dj_receiver_dev\n", __func__);
1488 return -ENOMEM;
1489 }
Kees Cook297502a2013-09-11 21:56:56 +02001490
Hans de Goede74808f92019-04-20 13:21:54 +02001491 if (!rep_enum->numbered)
1492 djrcv_dev->unnumbered_application = rep->application;
1493
Nestor Lopez Casado534a7b82011-09-15 11:34:49 +02001494 /* Starts the usb device and connects to upper interfaces hiddev and
1495 * hidraw */
Hans de Goede74808f92019-04-20 13:21:54 +02001496 retval = hid_hw_start(hdev, HID_CONNECT_HIDRAW|HID_CONNECT_HIDDEV);
Nestor Lopez Casado534a7b82011-09-15 11:34:49 +02001497 if (retval) {
1498 dev_err(&hdev->dev,
1499 "%s:hid_hw_start returned error\n", __func__);
1500 goto hid_hw_start_fail;
1501 }
1502
Hans de Goede74808f92019-04-20 13:21:54 +02001503 if (has_hidpp) {
1504 retval = logi_dj_recv_switch_to_dj_mode(djrcv_dev, 0);
1505 if (retval < 0) {
1506 hid_err(hdev, "%s: logi_dj_recv_switch_to_dj_mode returned error:%d\n",
1507 __func__, retval);
1508 goto switch_to_dj_mode_fail;
1509 }
Nestor Lopez Casado534a7b82011-09-15 11:34:49 +02001510 }
1511
1512 /* This is enabling the polling urb on the IN endpoint */
Benjamin Tissoiresddf75402013-07-12 11:01:02 +02001513 retval = hid_hw_open(hdev);
Nestor Lopez Casado534a7b82011-09-15 11:34:49 +02001514 if (retval < 0) {
Benjamin Tissoiresddf75402013-07-12 11:01:02 +02001515 dev_err(&hdev->dev, "%s:hid_hw_open returned error:%d\n",
1516 __func__, retval);
Nestor Lopez Casado534a7b82011-09-15 11:34:49 +02001517 goto llopen_failed;
1518 }
1519
Andrew de los Reyesa9dd22b72013-02-18 09:20:22 -08001520 /* Allow incoming packets to arrive: */
1521 hid_device_io_start(hdev);
1522
Hans de Goede74808f92019-04-20 13:21:54 +02001523 if (has_hidpp) {
1524 spin_lock_irqsave(&djrcv_dev->lock, flags);
1525 djrcv_dev->ready = true;
1526 spin_unlock_irqrestore(&djrcv_dev->lock, flags);
1527 retval = logi_dj_recv_query_paired_devices(djrcv_dev);
1528 if (retval < 0) {
1529 hid_err(hdev, "%s: logi_dj_recv_query_paired_devices error:%d\n",
1530 __func__, retval);
1531 goto logi_dj_recv_query_paired_devices_failed;
1532 }
Nestor Lopez Casado534a7b82011-09-15 11:34:49 +02001533 }
1534
1535 return retval;
1536
1537logi_dj_recv_query_paired_devices_failed:
Benjamin Tissoiresddf75402013-07-12 11:01:02 +02001538 hid_hw_close(hdev);
Nestor Lopez Casado534a7b82011-09-15 11:34:49 +02001539
1540llopen_failed:
1541switch_to_dj_mode_fail:
1542 hid_hw_stop(hdev);
1543
1544hid_hw_start_fail:
Hans de Goedea1d97cc2019-04-20 13:21:52 +02001545 dj_put_receiver_dev(hdev);
Nestor Lopez Casado534a7b82011-09-15 11:34:49 +02001546 return retval;
Nestor Lopez Casado534a7b82011-09-15 11:34:49 +02001547}
1548
1549#ifdef CONFIG_PM
1550static int logi_dj_reset_resume(struct hid_device *hdev)
1551{
1552 int retval;
1553 struct dj_receiver_dev *djrcv_dev = hid_get_drvdata(hdev);
1554
Hans de Goede74808f92019-04-20 13:21:54 +02001555 if (djrcv_dev->hidpp != hdev)
1556 return 0;
1557
Nestor Lopez Casado534a7b82011-09-15 11:34:49 +02001558 retval = logi_dj_recv_switch_to_dj_mode(djrcv_dev, 0);
1559 if (retval < 0) {
1560 dev_err(&hdev->dev,
1561 "%s:logi_dj_recv_switch_to_dj_mode returned error:%d\n",
1562 __func__, retval);
1563 }
1564
1565 return 0;
1566}
1567#endif
1568
1569static void logi_dj_remove(struct hid_device *hdev)
1570{
1571 struct dj_receiver_dev *djrcv_dev = hid_get_drvdata(hdev);
1572 struct dj_device *dj_dev;
Hans de Goedea1d97cc2019-04-20 13:21:52 +02001573 unsigned long flags;
Nestor Lopez Casado534a7b82011-09-15 11:34:49 +02001574 int i;
1575
1576 dbg_hid("%s\n", __func__);
1577
Hans de Goedea1d97cc2019-04-20 13:21:52 +02001578 /*
1579 * This ensures that if the work gets requeued from another
1580 * interface of the same receiver it will be a no-op.
1581 */
1582 spin_lock_irqsave(&djrcv_dev->lock, flags);
1583 djrcv_dev->ready = false;
1584 spin_unlock_irqrestore(&djrcv_dev->lock, flags);
1585
Nestor Lopez Casado534a7b82011-09-15 11:34:49 +02001586 cancel_work_sync(&djrcv_dev->work);
1587
Benjamin Tissoiresddf75402013-07-12 11:01:02 +02001588 hid_hw_close(hdev);
Nestor Lopez Casado534a7b82011-09-15 11:34:49 +02001589 hid_hw_stop(hdev);
1590
Hans de Goedea1d97cc2019-04-20 13:21:52 +02001591 /*
1592 * For proper operation we need access to all interfaces, so we destroy
1593 * the paired devices when we're unbound from any interface.
1594 *
1595 * Note we may still be bound to other interfaces, sharing the same
1596 * djrcv_dev, so we need locking here.
1597 */
Nestor Lopez Casado844580f2011-09-20 15:59:03 +02001598 for (i = 0; i < (DJ_MAX_PAIRED_DEVICES + DJ_DEVICE_INDEX_MIN); i++) {
Hans de Goedea1d97cc2019-04-20 13:21:52 +02001599 spin_lock_irqsave(&djrcv_dev->lock, flags);
Nestor Lopez Casado534a7b82011-09-15 11:34:49 +02001600 dj_dev = djrcv_dev->paired_dj_devices[i];
Hans de Goedea1d97cc2019-04-20 13:21:52 +02001601 djrcv_dev->paired_dj_devices[i] = NULL;
1602 spin_unlock_irqrestore(&djrcv_dev->lock, flags);
Nestor Lopez Casado534a7b82011-09-15 11:34:49 +02001603 if (dj_dev != NULL) {
1604 hid_destroy_device(dj_dev->hdev);
1605 kfree(dj_dev);
Nestor Lopez Casado534a7b82011-09-15 11:34:49 +02001606 }
1607 }
1608
Hans de Goedea1d97cc2019-04-20 13:21:52 +02001609 dj_put_receiver_dev(hdev);
Nestor Lopez Casado534a7b82011-09-15 11:34:49 +02001610}
1611
Nestor Lopez Casado534a7b82011-09-15 11:34:49 +02001612static const struct hid_device_id logi_dj_receivers[] = {
1613 {HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH,
Hans de Goede74808f92019-04-20 13:21:54 +02001614 USB_DEVICE_ID_LOGITECH_UNIFYING_RECEIVER),
1615 .driver_data = recvr_type_dj},
Nestor Lopez Casado534a7b82011-09-15 11:34:49 +02001616 {HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH,
Hans de Goede74808f92019-04-20 13:21:54 +02001617 USB_DEVICE_ID_LOGITECH_UNIFYING_RECEIVER_2),
1618 .driver_data = recvr_type_dj},
1619 { /* Logitech Nano (non DJ) receiver */
1620 HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH,
1621 USB_DEVICE_ID_LOGITECH_NANO_RECEIVER),
1622 .driver_data = recvr_type_hidpp},
1623 { /* Logitech Nano (non DJ) receiver */
1624 HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH,
1625 USB_DEVICE_ID_LOGITECH_NANO_RECEIVER_2),
1626 .driver_data = recvr_type_hidpp},
Benjamin Tissoiresf5fb57a2019-04-20 13:21:55 +02001627 { /* Logitech gaming receiver (0xc539) */
1628 HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH,
1629 USB_DEVICE_ID_LOGITECH_NANO_RECEIVER_GAMING),
1630 .driver_data = recvr_type_gaming_hidpp},
Nestor Lopez Casado534a7b82011-09-15 11:34:49 +02001631 {}
1632};
1633
1634MODULE_DEVICE_TABLE(hid, logi_dj_receivers);
1635
1636static struct hid_driver logi_djreceiver_driver = {
1637 .name = "logitech-djreceiver",
1638 .id_table = logi_dj_receivers,
1639 .probe = logi_dj_probe,
1640 .remove = logi_dj_remove,
1641 .raw_event = logi_dj_raw_event,
1642#ifdef CONFIG_PM
1643 .reset_resume = logi_dj_reset_resume,
1644#endif
1645};
1646
Benjamin Tissoiresab94e562014-09-30 13:18:28 -04001647module_hid_driver(logi_djreceiver_driver);
Nestor Lopez Casado534a7b82011-09-15 11:34:49 +02001648
Nestor Lopez Casado534a7b82011-09-15 11:34:49 +02001649MODULE_LICENSE("GPL");
1650MODULE_AUTHOR("Logitech");
1651MODULE_AUTHOR("Nestor Lopez Casado");
1652MODULE_AUTHOR("nlopezcasad@logitech.com");