1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25#include <linux/device.h>
26#include <linux/hid.h>
27#include <linux/module.h>
28#include <linux/usb.h>
29#include <asm/unaligned.h>
30#include "hid-ids.h"
31#include "hid-logitech-dj.h"
32
33
34static const char kbd_descriptor[] = {
35 0x05, 0x01,
36 0x09, 0x06,
37 0xA1, 0x01,
38 0x85, 0x01,
39 0x95, 0x08,
40 0x75, 0x01,
41 0x15, 0x00,
42 0x25, 0x01,
43 0x05, 0x07,
44 0x19, 0xE0,
45 0x29, 0xE7,
46 0x81, 0x02,
47 0x95, 0x06,
48 0x75, 0x08,
49 0x15, 0x00,
50 0x26, 0xFF, 0x00,
51 0x05, 0x07,
52 0x19, 0x00,
53 0x2A, 0xFF, 0x00,
54 0x81, 0x00,
55 0x85, 0x0e,
56 0x05, 0x08,
57 0x95, 0x05,
58 0x75, 0x01,
59 0x15, 0x00,
60 0x25, 0x01,
61 0x19, 0x01,
62 0x29, 0x05,
63 0x91, 0x02,
64 0x95, 0x01,
65 0x75, 0x03,
66 0x91, 0x01,
67 0xC0
68};
69
70
71static const char mse_descriptor[] = {
72 0x05, 0x01,
73 0x09, 0x02,
74 0xA1, 0x01,
75 0x85, 0x02,
76 0x09, 0x01,
77 0xA1, 0x00,
78 0x05, 0x09,
79 0x19, 0x01,
80 0x29, 0x10,
81 0x15, 0x00,
82 0x25, 0x01,
83 0x95, 0x10,
84 0x75, 0x01,
85 0x81, 0x02,
86 0x05, 0x01,
87 0x16, 0x01, 0xF8,
88 0x26, 0xFF, 0x07,
89 0x75, 0x0C,
90 0x95, 0x02,
91 0x09, 0x30,
92 0x09, 0x31,
93 0x81, 0x06,
94 0x15, 0x81,
95 0x25, 0x7F,
96 0x75, 0x08,
97 0x95, 0x01,
98 0x09, 0x38,
99 0x81, 0x06,
100 0x05, 0x0C,
101 0x0A, 0x38, 0x02,
102 0x95, 0x01,
103 0x81, 0x06,
104 0xC0,
105 0xC0,
106};
107
108
109static const char consumer_descriptor[] = {
110 0x05, 0x0C,
111 0x09, 0x01,
112 0xA1, 0x01,
113 0x85, 0x03,
114 0x75, 0x10,
115 0x95, 0x02,
116 0x15, 0x01,
117 0x26, 0x8C, 0x02,
118 0x19, 0x01,
119 0x2A, 0x8C, 0x02,
120 0x81, 0x00,
121 0xC0,
122};
123
124
125static const char syscontrol_descriptor[] = {
126 0x05, 0x01,
127 0x09, 0x80,
128 0xA1, 0x01,
129 0x85, 0x04,
130 0x75, 0x02,
131 0x95, 0x01,
132 0x15, 0x01,
133 0x25, 0x03,
134 0x09, 0x82,
135 0x09, 0x81,
136 0x09, 0x83,
137 0x81, 0x60,
138 0x75, 0x06,
139 0x81, 0x03,
140 0xC0,
141};
142
143
144static const char media_descriptor[] = {
145 0x06, 0xbc, 0xff,
146 0x09, 0x88,
147 0xa1, 0x01,
148 0x85, 0x08,
149 0x19, 0x01,
150 0x29, 0xff,
151 0x15, 0x01,
152 0x26, 0xff, 0x00,
153 0x75, 0x08,
154 0x95, 0x01,
155 0x81, 0x00,
156 0xc0,
157};
158
159
160#define MAX_REPORT_SIZE 8
161
162
163#define MAX_RDESC_SIZE \
164 (sizeof(kbd_descriptor) + \
165 sizeof(mse_descriptor) + \
166 sizeof(consumer_descriptor) + \
167 sizeof(syscontrol_descriptor) + \
168 sizeof(media_descriptor))
169
170
171
172
173
174
175
176
177
178
179
180
181
182#define NUMBER_OF_HID_REPORTS 32
183static const u8 hid_reportid_size_map[NUMBER_OF_HID_REPORTS] = {
184 [1] = 8,
185 [2] = 8,
186 [3] = 5,
187 [4] = 2,
188 [8] = 2,
189};
190
191
192#define LOGITECH_DJ_INTERFACE_NUMBER 0x02
193
194static struct hid_ll_driver logi_dj_ll_driver;
195
196static int logi_dj_recv_query_paired_devices(struct dj_receiver_dev *djrcv_dev);
197
198static void logi_dj_recv_destroy_djhid_device(struct dj_receiver_dev *djrcv_dev,
199 struct dj_report *dj_report)
200{
201
202 struct dj_device *dj_dev;
203 unsigned long flags;
204
205 spin_lock_irqsave(&djrcv_dev->lock, flags);
206 dj_dev = djrcv_dev->paired_dj_devices[dj_report->device_index];
207 djrcv_dev->paired_dj_devices[dj_report->device_index] = NULL;
208 spin_unlock_irqrestore(&djrcv_dev->lock, flags);
209
210 if (dj_dev != NULL) {
211 hid_destroy_device(dj_dev->hdev);
212 kfree(dj_dev);
213 } else {
214 dev_err(&djrcv_dev->hdev->dev, "%s: can't destroy a NULL device\n",
215 __func__);
216 }
217}
218
219static void logi_dj_recv_add_djhid_device(struct dj_receiver_dev *djrcv_dev,
220 struct dj_report *dj_report)
221{
222
223 struct hid_device *djrcv_hdev = djrcv_dev->hdev;
224 struct usb_interface *intf = to_usb_interface(djrcv_hdev->dev.parent);
225 struct usb_device *usbdev = interface_to_usbdev(intf);
226 struct hid_device *dj_hiddev;
227 struct dj_device *dj_dev;
228
229
230
231
232 unsigned char tmpstr[3];
233
234 if (dj_report->report_params[DEVICE_PAIRED_PARAM_SPFUNCTION] &
235 SPFUNCTION_DEVICE_LIST_EMPTY) {
236 dbg_hid("%s: device list is empty\n", __func__);
237 djrcv_dev->querying_devices = false;
238 return;
239 }
240
241 if (djrcv_dev->paired_dj_devices[dj_report->device_index]) {
242
243 dbg_hid("%s: device is already known\n", __func__);
244 return;
245 }
246
247 dj_hiddev = hid_allocate_device();
248 if (IS_ERR(dj_hiddev)) {
249 dev_err(&djrcv_hdev->dev, "%s: hid_allocate_device failed\n",
250 __func__);
251 return;
252 }
253
254 dj_hiddev->ll_driver = &logi_dj_ll_driver;
255
256 dj_hiddev->dev.parent = &djrcv_hdev->dev;
257 dj_hiddev->bus = BUS_USB;
258 dj_hiddev->vendor = le16_to_cpu(usbdev->descriptor.idVendor);
259 dj_hiddev->product = le16_to_cpu(usbdev->descriptor.idProduct);
260 snprintf(dj_hiddev->name, sizeof(dj_hiddev->name),
261 "Logitech Unifying Device. Wireless PID:%02x%02x",
262 dj_report->report_params[DEVICE_PAIRED_PARAM_EQUAD_ID_MSB],
263 dj_report->report_params[DEVICE_PAIRED_PARAM_EQUAD_ID_LSB]);
264
265 usb_make_path(usbdev, dj_hiddev->phys, sizeof(dj_hiddev->phys));
266 snprintf(tmpstr, sizeof(tmpstr), ":%d", dj_report->device_index);
267 strlcat(dj_hiddev->phys, tmpstr, sizeof(dj_hiddev->phys));
268
269 dj_dev = kzalloc(sizeof(struct dj_device), GFP_KERNEL);
270
271 if (!dj_dev) {
272 dev_err(&djrcv_hdev->dev, "%s: failed allocating dj_device\n",
273 __func__);
274 goto dj_device_allocate_fail;
275 }
276
277 dj_dev->reports_supported = get_unaligned_le32(
278 dj_report->report_params + DEVICE_PAIRED_RF_REPORT_TYPE);
279 dj_dev->hdev = dj_hiddev;
280 dj_dev->dj_receiver_dev = djrcv_dev;
281 dj_dev->device_index = dj_report->device_index;
282 dj_hiddev->driver_data = dj_dev;
283
284 djrcv_dev->paired_dj_devices[dj_report->device_index] = dj_dev;
285
286 if (hid_add_device(dj_hiddev)) {
287 dev_err(&djrcv_hdev->dev, "%s: failed adding dj_device\n",
288 __func__);
289 goto hid_add_device_fail;
290 }
291
292 return;
293
294hid_add_device_fail:
295 djrcv_dev->paired_dj_devices[dj_report->device_index] = NULL;
296 kfree(dj_dev);
297dj_device_allocate_fail:
298 hid_destroy_device(dj_hiddev);
299}
300
301static void delayedwork_callback(struct work_struct *work)
302{
303 struct dj_receiver_dev *djrcv_dev =
304 container_of(work, struct dj_receiver_dev, work);
305
306 struct dj_report dj_report;
307 unsigned long flags;
308 int count;
309 int retval;
310
311 dbg_hid("%s\n", __func__);
312
313 spin_lock_irqsave(&djrcv_dev->lock, flags);
314
315 count = kfifo_out(&djrcv_dev->notif_fifo, &dj_report,
316 sizeof(struct dj_report));
317
318 if (count != sizeof(struct dj_report)) {
319 dev_err(&djrcv_dev->hdev->dev, "%s: workitem triggered without "
320 "notifications available\n", __func__);
321 spin_unlock_irqrestore(&djrcv_dev->lock, flags);
322 return;
323 }
324
325 if (!kfifo_is_empty(&djrcv_dev->notif_fifo)) {
326 if (schedule_work(&djrcv_dev->work) == 0) {
327 dbg_hid("%s: did not schedule the work item, was "
328 "already queued\n", __func__);
329 }
330 }
331
332 spin_unlock_irqrestore(&djrcv_dev->lock, flags);
333
334 switch (dj_report.report_type) {
335 case REPORT_TYPE_NOTIF_DEVICE_PAIRED:
336 logi_dj_recv_add_djhid_device(djrcv_dev, &dj_report);
337 break;
338 case REPORT_TYPE_NOTIF_DEVICE_UNPAIRED:
339 logi_dj_recv_destroy_djhid_device(djrcv_dev, &dj_report);
340 break;
341 default:
342
343
344
345
346
347
348
349 if (!djrcv_dev->paired_dj_devices[dj_report.device_index]) {
350
351
352 retval = logi_dj_recv_query_paired_devices(djrcv_dev);
353 if (!retval) {
354
355 break;
356 }
357 dev_err(&djrcv_dev->hdev->dev,
358 "%s:logi_dj_recv_query_paired_devices "
359 "error:%d\n", __func__, retval);
360 }
361 dbg_hid("%s: unexpected report type\n", __func__);
362 }
363}
364
365static void logi_dj_recv_queue_notification(struct dj_receiver_dev *djrcv_dev,
366 struct dj_report *dj_report)
367{
368
369
370 kfifo_in(&djrcv_dev->notif_fifo, dj_report, sizeof(struct dj_report));
371
372 if (schedule_work(&djrcv_dev->work) == 0) {
373 dbg_hid("%s: did not schedule the work item, was already "
374 "queued\n", __func__);
375 }
376}
377
378static void logi_dj_recv_forward_null_report(struct dj_receiver_dev *djrcv_dev,
379 struct dj_report *dj_report)
380{
381
382 unsigned int i;
383 u8 reportbuffer[MAX_REPORT_SIZE];
384 struct dj_device *djdev;
385
386 djdev = djrcv_dev->paired_dj_devices[dj_report->device_index];
387
388 memset(reportbuffer, 0, sizeof(reportbuffer));
389
390 for (i = 0; i < NUMBER_OF_HID_REPORTS; i++) {
391 if (djdev->reports_supported & (1 << i)) {
392 reportbuffer[0] = i;
393 if (hid_input_report(djdev->hdev,
394 HID_INPUT_REPORT,
395 reportbuffer,
396 hid_reportid_size_map[i], 1)) {
397 dbg_hid("hid_input_report error sending null "
398 "report\n");
399 }
400 }
401 }
402}
403
404static void logi_dj_recv_forward_report(struct dj_receiver_dev *djrcv_dev,
405 struct dj_report *dj_report)
406{
407
408 struct dj_device *dj_device;
409
410 dj_device = djrcv_dev->paired_dj_devices[dj_report->device_index];
411
412 if ((dj_report->report_type > ARRAY_SIZE(hid_reportid_size_map) - 1) ||
413 (hid_reportid_size_map[dj_report->report_type] == 0)) {
414 dbg_hid("invalid report type:%x\n", dj_report->report_type);
415 return;
416 }
417
418 if (hid_input_report(dj_device->hdev,
419 HID_INPUT_REPORT, &dj_report->report_type,
420 hid_reportid_size_map[dj_report->report_type], 1)) {
421 dbg_hid("hid_input_report error\n");
422 }
423}
424
425
426static int logi_dj_recv_send_report(struct dj_receiver_dev *djrcv_dev,
427 struct dj_report *dj_report)
428{
429 struct hid_device *hdev = djrcv_dev->hdev;
430 struct hid_report *report;
431 struct hid_report_enum *output_report_enum;
432 u8 *data = (u8 *)(&dj_report->device_index);
433 unsigned int i;
434
435 output_report_enum = &hdev->report_enum[HID_OUTPUT_REPORT];
436 report = output_report_enum->report_id_hash[REPORT_ID_DJ_SHORT];
437
438 if (!report) {
439 dev_err(&hdev->dev, "%s: unable to find dj report\n", __func__);
440 return -ENODEV;
441 }
442
443 for (i = 0; i < DJREPORT_SHORT_LENGTH - 1; i++)
444 report->field[0]->value[i] = data[i];
445
446 hid_hw_request(hdev, report, HID_REQ_SET_REPORT);
447
448 return 0;
449}
450
451static int logi_dj_recv_query_paired_devices(struct dj_receiver_dev *djrcv_dev)
452{
453 struct dj_report *dj_report;
454 int retval;
455
456
457 if (djrcv_dev->querying_devices)
458 return 0;
459
460 dj_report = kzalloc(sizeof(struct dj_report), GFP_KERNEL);
461 if (!dj_report)
462 return -ENOMEM;
463 dj_report->report_id = REPORT_ID_DJ_SHORT;
464 dj_report->device_index = 0xFF;
465 dj_report->report_type = REPORT_TYPE_CMD_GET_PAIRED_DEVICES;
466 retval = logi_dj_recv_send_report(djrcv_dev, dj_report);
467 kfree(dj_report);
468 return retval;
469}
470
471
472static int logi_dj_recv_switch_to_dj_mode(struct dj_receiver_dev *djrcv_dev,
473 unsigned timeout)
474{
475 struct dj_report *dj_report;
476 int retval;
477
478 dj_report = kzalloc(sizeof(struct dj_report), GFP_KERNEL);
479 if (!dj_report)
480 return -ENOMEM;
481 dj_report->report_id = REPORT_ID_DJ_SHORT;
482 dj_report->device_index = 0xFF;
483 dj_report->report_type = REPORT_TYPE_CMD_SWITCH;
484 dj_report->report_params[CMD_SWITCH_PARAM_DEVBITFIELD] = 0x3F;
485 dj_report->report_params[CMD_SWITCH_PARAM_TIMEOUT_SECONDS] = (u8)timeout;
486 retval = logi_dj_recv_send_report(djrcv_dev, dj_report);
487 kfree(dj_report);
488
489
490
491
492
493
494 msleep(50);
495
496 return retval;
497}
498
499
500static int logi_dj_ll_open(struct hid_device *hid)
501{
502 dbg_hid("%s:%s\n", __func__, hid->phys);
503 return 0;
504
505}
506
507static void logi_dj_ll_close(struct hid_device *hid)
508{
509 dbg_hid("%s:%s\n", __func__, hid->phys);
510}
511
512static int logi_dj_ll_raw_request(struct hid_device *hid,
513 unsigned char reportnum, __u8 *buf,
514 size_t count, unsigned char report_type,
515 int reqtype)
516{
517 struct dj_device *djdev = hid->driver_data;
518 struct dj_receiver_dev *djrcv_dev = djdev->dj_receiver_dev;
519 u8 *out_buf;
520 int ret;
521
522 if (buf[0] != REPORT_TYPE_LEDS)
523 return -EINVAL;
524
525 out_buf = kzalloc(DJREPORT_SHORT_LENGTH, GFP_ATOMIC);
526 if (!out_buf)
527 return -ENOMEM;
528
529 if (count > DJREPORT_SHORT_LENGTH - 2)
530 count = DJREPORT_SHORT_LENGTH - 2;
531
532 out_buf[0] = REPORT_ID_DJ_SHORT;
533 out_buf[1] = djdev->device_index;
534 memcpy(out_buf + 2, buf, count);
535
536 ret = hid_hw_raw_request(djrcv_dev->hdev, out_buf[0], out_buf,
537 DJREPORT_SHORT_LENGTH, report_type, reqtype);
538
539 kfree(out_buf);
540 return ret;
541}
542
543static void rdcat(char *rdesc, unsigned int *rsize, const char *data, unsigned int size)
544{
545 memcpy(rdesc + *rsize, data, size);
546 *rsize += size;
547}
548
549static int logi_dj_ll_parse(struct hid_device *hid)
550{
551 struct dj_device *djdev = hid->driver_data;
552 unsigned int rsize = 0;
553 char *rdesc;
554 int retval;
555
556 dbg_hid("%s\n", __func__);
557
558 djdev->hdev->version = 0x0111;
559 djdev->hdev->country = 0x00;
560
561 rdesc = kmalloc(MAX_RDESC_SIZE, GFP_KERNEL);
562 if (!rdesc)
563 return -ENOMEM;
564
565 if (djdev->reports_supported & STD_KEYBOARD) {
566 dbg_hid("%s: sending a kbd descriptor, reports_supported: %x\n",
567 __func__, djdev->reports_supported);
568 rdcat(rdesc, &rsize, kbd_descriptor, sizeof(kbd_descriptor));
569 }
570
571 if (djdev->reports_supported & STD_MOUSE) {
572 dbg_hid("%s: sending a mouse descriptor, reports_supported: "
573 "%x\n", __func__, djdev->reports_supported);
574 rdcat(rdesc, &rsize, mse_descriptor, sizeof(mse_descriptor));
575 }
576
577 if (djdev->reports_supported & MULTIMEDIA) {
578 dbg_hid("%s: sending a multimedia report descriptor: %x\n",
579 __func__, djdev->reports_supported);
580 rdcat(rdesc, &rsize, consumer_descriptor, sizeof(consumer_descriptor));
581 }
582
583 if (djdev->reports_supported & POWER_KEYS) {
584 dbg_hid("%s: sending a power keys report descriptor: %x\n",
585 __func__, djdev->reports_supported);
586 rdcat(rdesc, &rsize, syscontrol_descriptor, sizeof(syscontrol_descriptor));
587 }
588
589 if (djdev->reports_supported & MEDIA_CENTER) {
590 dbg_hid("%s: sending a media center report descriptor: %x\n",
591 __func__, djdev->reports_supported);
592 rdcat(rdesc, &rsize, media_descriptor, sizeof(media_descriptor));
593 }
594
595 if (djdev->reports_supported & KBD_LEDS) {
596 dbg_hid("%s: need to send kbd leds report descriptor: %x\n",
597 __func__, djdev->reports_supported);
598 }
599
600 retval = hid_parse_report(hid, rdesc, rsize);
601 kfree(rdesc);
602
603 return retval;
604}
605
606static int logi_dj_ll_start(struct hid_device *hid)
607{
608 dbg_hid("%s\n", __func__);
609 return 0;
610}
611
612static void logi_dj_ll_stop(struct hid_device *hid)
613{
614 dbg_hid("%s\n", __func__);
615}
616
617
618static struct hid_ll_driver logi_dj_ll_driver = {
619 .parse = logi_dj_ll_parse,
620 .start = logi_dj_ll_start,
621 .stop = logi_dj_ll_stop,
622 .open = logi_dj_ll_open,
623 .close = logi_dj_ll_close,
624 .raw_request = logi_dj_ll_raw_request,
625};
626
627
628static int logi_dj_raw_event(struct hid_device *hdev,
629 struct hid_report *report, u8 *data,
630 int size)
631{
632 struct dj_receiver_dev *djrcv_dev = hid_get_drvdata(hdev);
633 struct dj_report *dj_report = (struct dj_report *) data;
634 unsigned long flags;
635
636 dbg_hid("%s, size:%d\n", __func__, size);
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663 if (data[0] != REPORT_ID_DJ_SHORT)
664 return false;
665
666 if ((dj_report->device_index < DJ_DEVICE_INDEX_MIN) ||
667 (dj_report->device_index > DJ_DEVICE_INDEX_MAX)) {
668
669
670
671
672
673 if (dj_report->device_index != DJ_RECEIVER_INDEX)
674 dev_err(&hdev->dev, "%s: invalid device index:%d\n",
675 __func__, dj_report->device_index);
676 return false;
677 }
678
679 spin_lock_irqsave(&djrcv_dev->lock, flags);
680
681 if (!djrcv_dev->paired_dj_devices[dj_report->device_index]) {
682
683 logi_dj_recv_queue_notification(djrcv_dev, dj_report);
684 goto out;
685 }
686
687 switch (dj_report->report_type) {
688 case REPORT_TYPE_NOTIF_DEVICE_PAIRED:
689
690 break;
691 case REPORT_TYPE_NOTIF_DEVICE_UNPAIRED:
692 logi_dj_recv_queue_notification(djrcv_dev, dj_report);
693 break;
694 case REPORT_TYPE_NOTIF_CONNECTION_STATUS:
695 if (dj_report->report_params[CONNECTION_STATUS_PARAM_STATUS] ==
696 STATUS_LINKLOSS) {
697 logi_dj_recv_forward_null_report(djrcv_dev, dj_report);
698 }
699 break;
700 default:
701 logi_dj_recv_forward_report(djrcv_dev, dj_report);
702 }
703
704out:
705 spin_unlock_irqrestore(&djrcv_dev->lock, flags);
706
707 return true;
708}
709
710static int logi_dj_probe(struct hid_device *hdev,
711 const struct hid_device_id *id)
712{
713 struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
714 struct dj_receiver_dev *djrcv_dev;
715 int retval;
716
717 if (is_dj_device((struct dj_device *)hdev->driver_data))
718 return -ENODEV;
719
720 dbg_hid("%s called for ifnum %d\n", __func__,
721 intf->cur_altsetting->desc.bInterfaceNumber);
722
723
724
725 if (intf->cur_altsetting->desc.bInterfaceNumber !=
726 LOGITECH_DJ_INTERFACE_NUMBER) {
727 dbg_hid("%s: ignoring ifnum %d\n", __func__,
728 intf->cur_altsetting->desc.bInterfaceNumber);
729 return -ENODEV;
730 }
731
732
733
734 djrcv_dev = kzalloc(sizeof(struct dj_receiver_dev), GFP_KERNEL);
735 if (!djrcv_dev) {
736 dev_err(&hdev->dev,
737 "%s:failed allocating dj_receiver_dev\n", __func__);
738 return -ENOMEM;
739 }
740 djrcv_dev->hdev = hdev;
741 INIT_WORK(&djrcv_dev->work, delayedwork_callback);
742 spin_lock_init(&djrcv_dev->lock);
743 if (kfifo_alloc(&djrcv_dev->notif_fifo,
744 DJ_MAX_NUMBER_NOTIFICATIONS * sizeof(struct dj_report),
745 GFP_KERNEL)) {
746 dev_err(&hdev->dev,
747 "%s:failed allocating notif_fifo\n", __func__);
748 kfree(djrcv_dev);
749 return -ENOMEM;
750 }
751 hid_set_drvdata(hdev, djrcv_dev);
752
753
754
755
756
757 retval = hid_parse(hdev);
758 if (retval) {
759 dev_err(&hdev->dev,
760 "%s:parse of interface 2 failed\n", __func__);
761 goto hid_parse_fail;
762 }
763
764 if (!hid_validate_values(hdev, HID_OUTPUT_REPORT, REPORT_ID_DJ_SHORT,
765 0, DJREPORT_SHORT_LENGTH - 1)) {
766 retval = -ENODEV;
767 goto hid_parse_fail;
768 }
769
770
771
772 retval = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
773 if (retval) {
774 dev_err(&hdev->dev,
775 "%s:hid_hw_start returned error\n", __func__);
776 goto hid_hw_start_fail;
777 }
778
779 retval = logi_dj_recv_switch_to_dj_mode(djrcv_dev, 0);
780 if (retval < 0) {
781 dev_err(&hdev->dev,
782 "%s:logi_dj_recv_switch_to_dj_mode returned error:%d\n",
783 __func__, retval);
784 goto switch_to_dj_mode_fail;
785 }
786
787
788 retval = hid_hw_open(hdev);
789 if (retval < 0) {
790 dev_err(&hdev->dev, "%s:hid_hw_open returned error:%d\n",
791 __func__, retval);
792 goto llopen_failed;
793 }
794
795
796 hid_device_io_start(hdev);
797
798 retval = logi_dj_recv_query_paired_devices(djrcv_dev);
799 if (retval < 0) {
800 dev_err(&hdev->dev, "%s:logi_dj_recv_query_paired_devices "
801 "error:%d\n", __func__, retval);
802 goto logi_dj_recv_query_paired_devices_failed;
803 }
804
805 return retval;
806
807logi_dj_recv_query_paired_devices_failed:
808 hid_hw_close(hdev);
809
810llopen_failed:
811switch_to_dj_mode_fail:
812 hid_hw_stop(hdev);
813
814hid_hw_start_fail:
815hid_parse_fail:
816 kfifo_free(&djrcv_dev->notif_fifo);
817 kfree(djrcv_dev);
818 hid_set_drvdata(hdev, NULL);
819 return retval;
820
821}
822
823#ifdef CONFIG_PM
824static int logi_dj_reset_resume(struct hid_device *hdev)
825{
826 int retval;
827 struct dj_receiver_dev *djrcv_dev = hid_get_drvdata(hdev);
828
829 retval = logi_dj_recv_switch_to_dj_mode(djrcv_dev, 0);
830 if (retval < 0) {
831 dev_err(&hdev->dev,
832 "%s:logi_dj_recv_switch_to_dj_mode returned error:%d\n",
833 __func__, retval);
834 }
835
836 return 0;
837}
838#endif
839
840static void logi_dj_remove(struct hid_device *hdev)
841{
842 struct dj_receiver_dev *djrcv_dev = hid_get_drvdata(hdev);
843 struct dj_device *dj_dev;
844 int i;
845
846 dbg_hid("%s\n", __func__);
847
848 cancel_work_sync(&djrcv_dev->work);
849
850 hid_hw_close(hdev);
851 hid_hw_stop(hdev);
852
853
854
855
856
857
858 for (i = 0; i < (DJ_MAX_PAIRED_DEVICES + DJ_DEVICE_INDEX_MIN); i++) {
859 dj_dev = djrcv_dev->paired_dj_devices[i];
860 if (dj_dev != NULL) {
861 hid_destroy_device(dj_dev->hdev);
862 kfree(dj_dev);
863 djrcv_dev->paired_dj_devices[i] = NULL;
864 }
865 }
866
867 kfifo_free(&djrcv_dev->notif_fifo);
868 kfree(djrcv_dev);
869 hid_set_drvdata(hdev, NULL);
870}
871
872static int logi_djdevice_probe(struct hid_device *hdev,
873 const struct hid_device_id *id)
874{
875 int ret;
876 struct dj_device *dj_dev = hdev->driver_data;
877
878 if (!is_dj_device(dj_dev))
879 return -ENODEV;
880
881 ret = hid_parse(hdev);
882 if (!ret)
883 ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
884
885 return ret;
886}
887
888static const struct hid_device_id logi_dj_receivers[] = {
889 {HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH,
890 USB_DEVICE_ID_LOGITECH_UNIFYING_RECEIVER)},
891 {HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH,
892 USB_DEVICE_ID_LOGITECH_UNIFYING_RECEIVER_2)},
893 {}
894};
895
896MODULE_DEVICE_TABLE(hid, logi_dj_receivers);
897
898static struct hid_driver logi_djreceiver_driver = {
899 .name = "logitech-djreceiver",
900 .id_table = logi_dj_receivers,
901 .probe = logi_dj_probe,
902 .remove = logi_dj_remove,
903 .raw_event = logi_dj_raw_event,
904#ifdef CONFIG_PM
905 .reset_resume = logi_dj_reset_resume,
906#endif
907};
908
909
910static const struct hid_device_id logi_dj_devices[] = {
911 {HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH,
912 USB_DEVICE_ID_LOGITECH_UNIFYING_RECEIVER)},
913 {HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH,
914 USB_DEVICE_ID_LOGITECH_UNIFYING_RECEIVER_2)},
915 {}
916};
917
918static struct hid_driver logi_djdevice_driver = {
919 .name = "logitech-djdevice",
920 .id_table = logi_dj_devices,
921 .probe = logi_djdevice_probe,
922};
923
924
925static int __init logi_dj_init(void)
926{
927 int retval;
928
929 dbg_hid("Logitech-DJ:%s\n", __func__);
930
931 retval = hid_register_driver(&logi_djreceiver_driver);
932 if (retval)
933 return retval;
934
935 retval = hid_register_driver(&logi_djdevice_driver);
936 if (retval)
937 hid_unregister_driver(&logi_djreceiver_driver);
938
939 return retval;
940
941}
942
943static void __exit logi_dj_exit(void)
944{
945 dbg_hid("Logitech-DJ:%s\n", __func__);
946
947 hid_unregister_driver(&logi_djdevice_driver);
948 hid_unregister_driver(&logi_djreceiver_driver);
949
950}
951
952module_init(logi_dj_init);
953module_exit(logi_dj_exit);
954MODULE_LICENSE("GPL");
955MODULE_AUTHOR("Logitech");
956MODULE_AUTHOR("Nestor Lopez Casado");
957MODULE_AUTHOR("nlopezcasad@logitech.com");
958