aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/hid
diff options
context:
space:
mode:
authorNestor Lopez Casado <nlopezcasad@logitech.com>2011-09-15 05:34:49 -0400
committerJiri Kosina <jkosina@suse.cz>2011-09-15 05:34:49 -0400
commit534a7b8e10ec55d9f521e68c20dbb3634c25b98a (patch)
treeb6cbaad7a3fea91ff9cab6c08a2e6c4c5a6ff07f /drivers/hid
parent8f25229026c89912574558d0a4e36c8fe51b9bb4 (diff)
HID: Add full support for Logitech Unifying receivers
With this driver, all the devices paired to a single Unifying receiver are exposed to user processes in separated /input/dev nodes. Keyboards with different layouts can be treated differently, Multiplayer games on single PC (like home theater PC) can differentiate input coming from different kbds paired to the same receiver. Up to now, when Logitech Unifying receivers are connected to a Linux based system, a single keyboard and a single mouse are presented to the HID Layer, even if the Unifying receiver can pair up to six compatible devices. The Unifying receiver by default multiplexes all incoming events (from multiple keyboards/mice) into these two. Signed-off-by: Nestor Lopez Casado <nlopezcasad@logitech.com> Signed-off-by: Benjamin Tissoires <benjamin.tissoires@gmail.com> Signed-off-by: Jiri Kosina <jkosina@suse.cz>
Diffstat (limited to 'drivers/hid')
-rw-r--r--drivers/hid/Kconfig9
-rw-r--r--drivers/hid/Makefile1
-rw-r--r--drivers/hid/hid-core.c2
-rw-r--r--drivers/hid/hid-ids.h2
-rw-r--r--drivers/hid/hid-logitech-dj.c925
-rw-r--r--drivers/hid/hid-logitech-dj.h120
6 files changed, 1059 insertions, 0 deletions
diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index 410eaa902495..d2c97343fc0d 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -245,6 +245,15 @@ config HID_LOGITECH
245 ---help--- 245 ---help---
246 Support for Logitech devices that are not fully compliant with HID standard. 246 Support for Logitech devices that are not fully compliant with HID standard.
247 247
248config HID_LOGITECH_DJ
249 tristate "Logitech Unifying receivers full support"
250 depends on HID_LOGITECH
251 default m
252 ---help---
253 Say Y if you want support for Logitech Unifying receivers and devices.
254 Unifying receivers are capable of pairing up to 6 Logitech compliant
255 devices to the same receiver.
256
248config LOGITECH_FF 257config LOGITECH_FF
249 bool "Logitech force feedback support" 258 bool "Logitech force feedback support"
250 depends on HID_LOGITECH 259 depends on HID_LOGITECH
diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile
index 77c9e5d7ff97..b7ddabb0b34c 100644
--- a/drivers/hid/Makefile
+++ b/drivers/hid/Makefile
@@ -43,6 +43,7 @@ obj-$(CONFIG_HID_KEYTOUCH) += hid-keytouch.o
43obj-$(CONFIG_HID_KYE) += hid-kye.o 43obj-$(CONFIG_HID_KYE) += hid-kye.o
44obj-$(CONFIG_HID_LCPOWER) += hid-lcpower.o 44obj-$(CONFIG_HID_LCPOWER) += hid-lcpower.o
45obj-$(CONFIG_HID_LOGITECH) += hid-logitech.o 45obj-$(CONFIG_HID_LOGITECH) += hid-logitech.o
46obj-$(CONFIG_HID_LOGITECH_DJ) += hid-logitech-dj.o
46obj-$(CONFIG_HID_MAGICMOUSE) += hid-magicmouse.o 47obj-$(CONFIG_HID_MAGICMOUSE) += hid-magicmouse.o
47obj-$(CONFIG_HID_MICROSOFT) += hid-microsoft.o 48obj-$(CONFIG_HID_MICROSOFT) += hid-microsoft.o
48obj-$(CONFIG_HID_MONTEREY) += hid-monterey.o 49obj-$(CONFIG_HID_MONTEREY) += hid-monterey.o
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index 1a5cf0c9cfca..ab4ae12e0a01 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -1419,6 +1419,8 @@ static const struct hid_device_id hid_have_special_driver[] = {
1419 { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_DFP_WHEEL) }, 1419 { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_DFP_WHEEL) },
1420 { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G25_WHEEL) }, 1420 { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G25_WHEEL) },
1421 { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G27_WHEEL) }, 1421 { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G27_WHEEL) },
1422 { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_UNIFYING_RECEIVER) },
1423 { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_UNIFYING_RECEIVER_2) },
1422 { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WII_WHEEL) }, 1424 { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WII_WHEEL) },
1423 { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD2) }, 1425 { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD2) },
1424 { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_SPACETRAVELLER) }, 1426 { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_SPACETRAVELLER) },
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
index ea2c338814fe..3d065d096a07 100644
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
@@ -444,6 +444,8 @@
444#define USB_DEVICE_ID_S510_RECEIVER_2 0xc517 444#define USB_DEVICE_ID_S510_RECEIVER_2 0xc517
445#define USB_DEVICE_ID_LOGITECH_CORDLESS_DESKTOP_LX500 0xc512 445#define USB_DEVICE_ID_LOGITECH_CORDLESS_DESKTOP_LX500 0xc512
446#define USB_DEVICE_ID_MX3000_RECEIVER 0xc513 446#define USB_DEVICE_ID_MX3000_RECEIVER 0xc513
447#define USB_DEVICE_ID_LOGITECH_UNIFYING_RECEIVER 0xc52b
448#define USB_DEVICE_ID_LOGITECH_UNIFYING_RECEIVER_2 0xc532
447#define USB_DEVICE_ID_SPACETRAVELLER 0xc623 449#define USB_DEVICE_ID_SPACETRAVELLER 0xc623
448#define USB_DEVICE_ID_SPACENAVIGATOR 0xc626 450#define USB_DEVICE_ID_SPACENAVIGATOR 0xc626
449#define USB_DEVICE_ID_DINOVO_DESKTOP 0xc704 451#define USB_DEVICE_ID_DINOVO_DESKTOP 0xc704
diff --git a/drivers/hid/hid-logitech-dj.c b/drivers/hid/hid-logitech-dj.c
new file mode 100644
index 000000000000..5bb6f42a4278
--- /dev/null
+++ b/drivers/hid/hid-logitech-dj.c
@@ -0,0 +1,925 @@
1/*
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>
28#include <linux/usb.h>
29#include "usbhid/usbhid.h"
30#include "hid-ids.h"
31#include "hid-logitech-dj.h"
32
33/* Keyboard descriptor (1) */
34static const char kbd_descriptor[] = {
35 0x05, 0x01, /* USAGE_PAGE (generic Desktop) */
36 0x09, 0x06, /* USAGE (Keyboard) */
37 0xA1, 0x01, /* COLLECTION (Application) */
38 0x85, 0x01, /* REPORT_ID (1) */
39 0x95, 0x08, /* REPORT_COUNT (8) */
40 0x75, 0x01, /* REPORT_SIZE (1) */
41 0x15, 0x00, /* LOGICAL_MINIMUM (0) */
42 0x25, 0x01, /* LOGICAL_MAXIMUM (1) */
43 0x05, 0x07, /* USAGE_PAGE (Keyboard) */
44 0x19, 0xE0, /* USAGE_MINIMUM (Left Control) */
45 0x29, 0xE7, /* USAGE_MAXIMUM (Right GUI) */
46 0x81, 0x02, /* INPUT (Data,Var,Abs) */
47 0x95, 0x05, /* REPORT COUNT (5) */
48 0x05, 0x08, /* USAGE PAGE (LED page) */
49 0x19, 0x01, /* USAGE MINIMUM (1) */
50 0x29, 0x05, /* USAGE MAXIMUM (5) */
51 0x91, 0x02, /* OUTPUT (Data, Variable, Absolute) */
52 0x95, 0x01, /* REPORT COUNT (1) */
53 0x75, 0x03, /* REPORT SIZE (3) */
54 0x91, 0x01, /* OUTPUT (Constant) */
55 0x95, 0x06, /* REPORT_COUNT (6) */
56 0x75, 0x08, /* REPORT_SIZE (8) */
57 0x15, 0x00, /* LOGICAL_MINIMUM (0) */
58 0x26, 0xFF, 0x00, /* LOGICAL_MAXIMUM (255) */
59 0x05, 0x07, /* USAGE_PAGE (Keyboard) */
60 0x19, 0x00, /* USAGE_MINIMUM (no event) */
61 0x2A, 0xFF, 0x00, /* USAGE_MAXIMUM (reserved) */
62 0x81, 0x00, /* INPUT (Data,Ary,Abs) */
63 0xC0
64};
65
66/* Mouse descriptor (2) */
67static const char mse_descriptor[] = {
68 0x05, 0x01, /* USAGE_PAGE (Generic Desktop) */
69 0x09, 0x02, /* USAGE (Mouse) */
70 0xA1, 0x01, /* COLLECTION (Application) */
71 0x85, 0x02, /* REPORT_ID = 2 */
72 0x09, 0x01, /* USAGE (pointer) */
73 0xA1, 0x00, /* COLLECTION (physical) */
74 0x05, 0x09, /* USAGE_PAGE (buttons) */
75 0x19, 0x01, /* USAGE_MIN (1) */
76 0x29, 0x10, /* USAGE_MAX (16) */
77 0x15, 0x00, /* LOGICAL_MIN (0) */
78 0x25, 0x01, /* LOGICAL_MAX (1) */
79 0x95, 0x10, /* REPORT_COUNT (16) */
80 0x75, 0x01, /* REPORT_SIZE (1) */
81 0x81, 0x02, /* INPUT (data var abs) */
82 0x05, 0x01, /* USAGE_PAGE (generic desktop) */
83 0x16, 0x01, 0xF8, /* LOGICAL_MIN (-2047) */
84 0x26, 0xFF, 0x07, /* LOGICAL_MAX (2047) */
85 0x75, 0x0C, /* REPORT_SIZE (12) */
86 0x95, 0x02, /* REPORT_COUNT (2) */
87 0x09, 0x30, /* USAGE (X) */
88 0x09, 0x31, /* USAGE (Y) */
89 0x81, 0x06, /* INPUT */
90 0x15, 0x81, /* LOGICAL_MIN (-127) */
91 0x25, 0x7F, /* LOGICAL_MAX (127) */
92 0x75, 0x08, /* REPORT_SIZE (8) */
93 0x95, 0x01, /* REPORT_COUNT (1) */
94 0x09, 0x38, /* USAGE (wheel) */
95 0x81, 0x06, /* INPUT */
96 0x05, 0x0C, /* USAGE_PAGE(consumer) */
97 0x0A, 0x38, 0x02, /* USAGE(AC Pan) */
98 0x95, 0x01, /* REPORT_COUNT (1) */
99 0x81, 0x06, /* INPUT */
100 0xC0, /* END_COLLECTION */
101 0xC0, /* END_COLLECTION */
102};
103
104/* Consumer Control descriptor (3) */
105static const char consumer_descriptor[] = {
106 0x05, 0x0C, /* USAGE_PAGE (Consumer Devices) */
107 0x09, 0x01, /* USAGE (Consumer Control) */
108 0xA1, 0x01, /* COLLECTION (Application) */
109 0x85, 0x03, /* REPORT_ID = 3 */
110 0x75, 0x10, /* REPORT_SIZE (16) */
111 0x95, 0x02, /* REPORT_COUNT (2) */
112 0x15, 0x01, /* LOGICAL_MIN (1) */
113 0x26, 0x8C, 0x02, /* LOGICAL_MAX (652) */
114 0x19, 0x01, /* USAGE_MIN (1) */
115 0x2A, 0x8C, 0x02, /* USAGE_MAX (652) */
116 0x81, 0x00, /* INPUT (Data Ary Abs) */
117 0xC0, /* END_COLLECTION */
118}; /* */
119
120/* System control descriptor (4) */
121static const char syscontrol_descriptor[] = {
122 0x05, 0x01, /* USAGE_PAGE (Generic Desktop) */
123 0x09, 0x80, /* USAGE (System Control) */
124 0xA1, 0x01, /* COLLECTION (Application) */
125 0x85, 0x04, /* REPORT_ID = 4 */
126 0x75, 0x02, /* REPORT_SIZE (2) */
127 0x95, 0x01, /* REPORT_COUNT (1) */
128 0x15, 0x01, /* LOGICAL_MIN (1) */
129 0x25, 0x03, /* LOGICAL_MAX (3) */
130 0x09, 0x82, /* USAGE (System Sleep) */
131 0x09, 0x81, /* USAGE (System Power Down) */
132 0x09, 0x83, /* USAGE (System Wake Up) */
133 0x81, 0x60, /* INPUT (Data Ary Abs NPrf Null) */
134 0x75, 0x06, /* REPORT_SIZE (6) */
135 0x81, 0x03, /* INPUT (Cnst Var Abs) */
136 0xC0, /* END_COLLECTION */
137};
138
139/* Media descriptor (8) */
140static const char media_descriptor[] = {
141 0x06, 0xbc, 0xff, /* Usage Page 0xffbc */
142 0x09, 0x88, /* Usage 0x0088 */
143 0xa1, 0x01, /* BeginCollection */
144 0x85, 0x08, /* Report ID 8 */
145 0x19, 0x01, /* Usage Min 0x0001 */
146 0x29, 0xff, /* Usage Max 0x00ff */
147 0x15, 0x01, /* Logical Min 1 */
148 0x26, 0xff, 0x00, /* Logical Max 255 */
149 0x75, 0x08, /* Report Size 8 */
150 0x95, 0x01, /* Report Count 1 */
151 0x81, 0x00, /* Input */
152 0xc0, /* EndCollection */
153}; /* */
154
155/* Maximum size of all defined hid reports in bytes (including report id) */
156#define MAX_REPORT_SIZE 8
157
158/* Number of possible hid report types that can be created by this driver.
159 *
160 * Right now, RF report types have the same report types (or report id's)
161 * than the hid report created from those RF reports. In the future
162 * this doesnt have to be true.
163 *
164 * For instance, RF report type 0x01 which has a size of 8 bytes, corresponds
165 * to hid report id 0x01, this is standard keyboard. Same thing applies to mice
166 * reports and consumer control, etc. If a new RF report is created, it doesn't
167 * has to have the same report id as its corresponding hid report, so an
168 * translation may have to take place for future report types.
169 */
170#define NUMBER_OF_HID_REPORTS 32
171static const u8 hid_reportid_size_map[NUMBER_OF_HID_REPORTS] = {
172 [1] = 8, /* Standard keyboard */
173 [2] = 8, /* Standard mouse */
174 [3] = 5, /* Consumer control */
175 [4] = 2, /* System control */
176 [8] = 2, /* Media Center */
177};
178
179
180#define LOGITECH_DJ_INTERFACE_NUMBER 0x02
181
182#define DJ_DEVICE_INDEX_MIN 1
183#define DJ_DEVICE_INDEX_MAX 6
184
185static struct hid_ll_driver logi_dj_ll_driver;
186
187static int logi_dj_output_hidraw_report(struct hid_device *hid, u8 * buf,
188 size_t count,
189 unsigned char report_type);
190
191static void logi_dj_recv_destroy_djhid_device(struct dj_receiver_dev *djrcv_dev,
192 struct dj_report *dj_report)
193{
194 /* Called in delayed work context */
195 struct dj_device *dj_dev;
196 unsigned long flags;
197
198 spin_lock_irqsave(&djrcv_dev->lock, flags);
199 dj_dev = djrcv_dev->paired_dj_devices[dj_report->device_index];
200 djrcv_dev->paired_dj_devices[dj_report->device_index] = NULL;
201 spin_unlock_irqrestore(&djrcv_dev->lock, flags);
202
203 if (dj_dev != NULL) {
204 hid_destroy_device(dj_dev->hdev);
205 kfree(dj_dev);
206 } else {
207 dev_err(&djrcv_dev->hdev->dev, "%s: can't destroy a NULL device\n",
208 __func__);
209 }
210}
211
212static void logi_dj_recv_add_djhid_device(struct dj_receiver_dev *djrcv_dev,
213 struct dj_report *dj_report)
214{
215 /* Called in delayed work context */
216 struct hid_device *djrcv_hdev = djrcv_dev->hdev;
217 struct usb_interface *intf = to_usb_interface(djrcv_hdev->dev.parent);
218 struct usb_device *usbdev = interface_to_usbdev(intf);
219 struct hid_device *dj_hiddev;
220 struct dj_device *dj_dev;
221
222 /* Device index goes from 1 to 6, we need 3 bytes to store the
223 * semicolon, the index, and a null terminator
224 */
225 unsigned char tmpstr[3];
226
227 if (dj_report->report_params[DEVICE_PAIRED_PARAM_SPFUNCTION] &
228 SPFUNCTION_DEVICE_LIST_EMPTY) {
229 dbg_hid("%s: device list is empty\n", __func__);
230 return;
231 }
232
233 if ((dj_report->device_index < DJ_DEVICE_INDEX_MIN) ||
234 (dj_report->device_index > DJ_DEVICE_INDEX_MAX)) {
235 dev_err(&djrcv_hdev->dev, "%s: invalid device index:%d\n",
236 __func__, dj_report->device_index);
237 return;
238 }
239
240 dj_hiddev = hid_allocate_device();
241 if (IS_ERR(dj_hiddev)) {
242 dev_err(&djrcv_hdev->dev, "%s: hid_allocate_device failed\n",
243 __func__);
244 return;
245 }
246
247 dj_hiddev->ll_driver = &logi_dj_ll_driver;
248 dj_hiddev->hid_output_raw_report = logi_dj_output_hidraw_report;
249
250 dj_hiddev->dev.parent = &djrcv_hdev->dev;
251 dj_hiddev->bus = BUS_USB;
252 dj_hiddev->vendor = le16_to_cpu(usbdev->descriptor.idVendor);
253 dj_hiddev->product = le16_to_cpu(usbdev->descriptor.idProduct);
254 snprintf(dj_hiddev->name, sizeof(dj_hiddev->name),
255 "Logitech Unifying Device. Wireless PID:%02x%02x",
256 dj_report->report_params[DEVICE_PAIRED_PARAM_EQUAD_ID_MSB],
257 dj_report->report_params[DEVICE_PAIRED_PARAM_EQUAD_ID_LSB]);
258
259 usb_make_path(usbdev, dj_hiddev->phys, sizeof(dj_hiddev->phys));
260 snprintf(tmpstr, sizeof(tmpstr), ":%d", dj_report->device_index);
261 strlcat(dj_hiddev->phys, tmpstr, sizeof(dj_hiddev->phys));
262
263 dj_dev = kzalloc(sizeof(struct dj_device), GFP_KERNEL);
264
265 if (!dj_dev) {
266 dev_err(&djrcv_hdev->dev, "%s: failed allocating dj_device\n",
267 __func__);
268 goto dj_device_allocate_fail;
269 }
270
271 dj_dev->reports_supported = le32_to_cpu(
272 dj_report->report_params[DEVICE_PAIRED_RF_REPORT_TYPE]);
273 dj_dev->hdev = dj_hiddev;
274 dj_dev->dj_receiver_dev = djrcv_dev;
275 dj_dev->device_index = dj_report->device_index;
276 dj_hiddev->driver_data = dj_dev;
277
278 djrcv_dev->paired_dj_devices[dj_report->device_index] = dj_dev;
279
280 if (hid_add_device(dj_hiddev)) {
281 dev_err(&djrcv_hdev->dev, "%s: failed adding dj_device\n",
282 __func__);
283 goto hid_add_device_fail;
284 }
285
286 return;
287
288hid_add_device_fail:
289 djrcv_dev->paired_dj_devices[dj_report->device_index] = NULL;
290 kfree(dj_dev);
291dj_device_allocate_fail:
292 hid_destroy_device(dj_hiddev);
293}
294
295static void delayedwork_callback(struct work_struct *work)
296{
297 struct dj_receiver_dev *djrcv_dev =
298 container_of(work, struct dj_receiver_dev, work);
299
300 struct dj_report dj_report;
301 unsigned long flags;
302 int count;
303
304 dbg_hid("%s\n", __func__);
305
306 spin_lock_irqsave(&djrcv_dev->lock, flags);
307
308 count = kfifo_out(&djrcv_dev->notif_fifo, &dj_report,
309 sizeof(struct dj_report));
310
311 if (count != sizeof(struct dj_report)) {
312 dev_err(&djrcv_dev->hdev->dev, "%s: workitem triggered without "
313 "notifications available\n", __func__);
314 spin_unlock_irqrestore(&djrcv_dev->lock, flags);
315 return;
316 }
317
318 if (!kfifo_is_empty(&djrcv_dev->notif_fifo)) {
319 if (schedule_work(&djrcv_dev->work) == 0) {
320 dbg_hid("%s: did not schedule the work item, was "
321 "already queued\n", __func__);
322 }
323 }
324
325 spin_unlock_irqrestore(&djrcv_dev->lock, flags);
326
327 switch (dj_report.report_type) {
328 case REPORT_TYPE_NOTIF_DEVICE_PAIRED:
329 logi_dj_recv_add_djhid_device(djrcv_dev, &dj_report);
330 break;
331 case REPORT_TYPE_NOTIF_DEVICE_UNPAIRED:
332 logi_dj_recv_destroy_djhid_device(djrcv_dev, &dj_report);
333 break;
334 default:
335 dbg_hid("%s: unexpected report type\n", __func__);
336 }
337}
338
339static void logi_dj_recv_queue_notification(struct dj_receiver_dev *djrcv_dev,
340 struct dj_report *dj_report)
341{
342 /* We are called from atomic context (tasklet && djrcv->lock held) */
343
344 kfifo_in(&djrcv_dev->notif_fifo, dj_report, sizeof(struct dj_report));
345
346 if (schedule_work(&djrcv_dev->work) == 0) {
347 dbg_hid("%s: did not schedule the work item, was already "
348 "queued\n", __func__);
349 }
350}
351
352static void logi_dj_recv_forward_null_report(struct dj_receiver_dev *djrcv_dev,
353 struct dj_report *dj_report)
354{
355 /* We are called from atomic context (tasklet && djrcv->lock held) */
356 unsigned int i;
357 u8 reportbuffer[MAX_REPORT_SIZE];
358 struct dj_device *djdev;
359
360 djdev = djrcv_dev->paired_dj_devices[dj_report->device_index];
361
362 if (!djdev) {
363 dbg_hid("djrcv_dev->paired_dj_devices[dj_report->device_index]"
364 " is NULL, index %d\n", dj_report->device_index);
365 return;
366 }
367
368 memset(reportbuffer, 0, sizeof(reportbuffer));
369
370 for (i = 0; i < NUMBER_OF_HID_REPORTS; i++) {
371 if (djdev->reports_supported & (1 << i)) {
372 reportbuffer[0] = i;
373 if (hid_input_report(djdev->hdev,
374 HID_INPUT_REPORT,
375 reportbuffer,
376 hid_reportid_size_map[i], 1)) {
377 dbg_hid("hid_input_report error sending null "
378 "report\n");
379 }
380 }
381 }
382}
383
384static void logi_dj_recv_forward_report(struct dj_receiver_dev *djrcv_dev,
385 struct dj_report *dj_report)
386{
387 /* We are called from atomic context (tasklet && djrcv->lock held) */
388 struct dj_device *dj_device;
389
390 dj_device = djrcv_dev->paired_dj_devices[dj_report->device_index];
391
392 if (dj_device == NULL) {
393 dbg_hid("djrcv_dev->paired_dj_devices[dj_report->device_index]"
394 " is NULL, index %d\n", dj_report->device_index);
395 return;
396 }
397
398 if ((dj_report->report_type > ARRAY_SIZE(hid_reportid_size_map) - 1) ||
399 (hid_reportid_size_map[dj_report->report_type] == 0)) {
400 dbg_hid("invalid report type:%x\n", dj_report->report_type);
401 return;
402 }
403
404 if (hid_input_report(dj_device->hdev,
405 HID_INPUT_REPORT, &dj_report->report_type,
406 hid_reportid_size_map[dj_report->report_type], 1)) {
407 dbg_hid("hid_input_report error\n");
408 }
409}
410
411
412static int logi_dj_recv_send_report(struct dj_receiver_dev *djrcv_dev,
413 struct dj_report *dj_report)
414{
415 struct hid_device *hdev = djrcv_dev->hdev;
416 int sent_bytes;
417
418 if (!hdev->hid_output_raw_report) {
419 dev_err(&hdev->dev, "%s:"
420 "hid_output_raw_report is null\n", __func__);
421 return -ENODEV;
422 }
423
424 sent_bytes = hdev->hid_output_raw_report(hdev, (u8 *) dj_report,
425 sizeof(struct dj_report),
426 HID_OUTPUT_REPORT);
427
428 return (sent_bytes < 0) ? sent_bytes : 0;
429}
430
431static int logi_dj_recv_query_paired_devices(struct dj_receiver_dev *djrcv_dev)
432{
433 struct dj_report dj_report;
434
435 memset(&dj_report, 0, sizeof(dj_report));
436 dj_report.report_id = REPORT_ID_DJ_SHORT;
437 dj_report.device_index = 0xFF;
438 dj_report.report_type = REPORT_TYPE_CMD_GET_PAIRED_DEVICES;
439 return logi_dj_recv_send_report(djrcv_dev, &dj_report);
440}
441
442static int logi_dj_recv_switch_to_dj_mode(struct dj_receiver_dev *djrcv_dev,
443 unsigned timeout)
444{
445 struct dj_report dj_report;
446
447 memset(&dj_report, 0, sizeof(dj_report));
448 dj_report.report_id = REPORT_ID_DJ_SHORT;
449 dj_report.device_index = 0xFF;
450 dj_report.report_type = REPORT_TYPE_CMD_SWITCH;
451 dj_report.report_params[CMD_SWITCH_PARAM_DEVBITFIELD] = 0x1F;
452 dj_report.report_params[CMD_SWITCH_PARAM_TIMEOUT_SECONDS] = (u8)timeout;
453 return logi_dj_recv_send_report(djrcv_dev, &dj_report);
454}
455
456
457static int logi_dj_ll_open(struct hid_device *hid)
458{
459 dbg_hid("%s:%s\n", __func__, hid->phys);
460 return 0;
461
462}
463
464static void logi_dj_ll_close(struct hid_device *hid)
465{
466 dbg_hid("%s:%s\n", __func__, hid->phys);
467}
468
469static int logi_dj_output_hidraw_report(struct hid_device *hid, u8 * buf,
470 size_t count,
471 unsigned char report_type)
472{
473 /* Called by hid raw to send data */
474 dbg_hid("%s\n", __func__);
475
476 return 0;
477}
478
479static int logi_dj_ll_parse(struct hid_device *hid)
480{
481 struct dj_device *djdev = hid->driver_data;
482 int retval;
483
484 dbg_hid("%s\n", __func__);
485
486 djdev->hdev->version = 0x0111;
487 djdev->hdev->country = 0x00;
488
489 if (djdev->reports_supported & STD_KEYBOARD) {
490 dbg_hid("%s: sending a kbd descriptor, reports_supported: %x\n",
491 __func__, djdev->reports_supported);
492 retval = hid_parse_report(hid,
493 (u8 *) kbd_descriptor,
494 sizeof(kbd_descriptor));
495 if (retval) {
496 dbg_hid("%s: sending a kbd descriptor, hid_parse failed"
497 " error: %d\n", __func__, retval);
498 return retval;
499 }
500 }
501
502 if (djdev->reports_supported & STD_MOUSE) {
503 dbg_hid("%s: sending a mouse descriptor, reports_supported: "
504 "%x\n", __func__, djdev->reports_supported);
505 retval = hid_parse_report(hid,
506 (u8 *) mse_descriptor,
507 sizeof(mse_descriptor));
508 if (retval) {
509 dbg_hid("%s: sending a mouse descriptor, hid_parse "
510 "failed error: %d\n", __func__, retval);
511 return retval;
512 }
513 }
514
515 if (djdev->reports_supported & MULTIMEDIA) {
516 dbg_hid("%s: sending a multimedia report descriptor: %x\n",
517 __func__, djdev->reports_supported);
518 retval = hid_parse_report(hid,
519 (u8 *) consumer_descriptor,
520 sizeof(consumer_descriptor));
521 if (retval) {
522 dbg_hid("%s: sending a consumer_descriptor, hid_parse "
523 "failed error: %d\n", __func__, retval);
524 return retval;
525 }
526 }
527
528 if (djdev->reports_supported & POWER_KEYS) {
529 dbg_hid("%s: sending a power keys report descriptor: %x\n",
530 __func__, djdev->reports_supported);
531 retval = hid_parse_report(hid,
532 (u8 *) syscontrol_descriptor,
533 sizeof(syscontrol_descriptor));
534 if (retval) {
535 dbg_hid("%s: sending a syscontrol_descriptor, "
536 "hid_parse failed error: %d\n",
537 __func__, retval);
538 return retval;
539 }
540 }
541
542 if (djdev->reports_supported & MEDIA_CENTER) {
543 dbg_hid("%s: sending a media center report descriptor: %x\n",
544 __func__, djdev->reports_supported);
545 retval = hid_parse_report(hid,
546 (u8 *) media_descriptor,
547 sizeof(media_descriptor));
548 if (retval) {
549 dbg_hid("%s: sending a media_descriptor, hid_parse "
550 "failed error: %d\n", __func__, retval);
551 return retval;
552 }
553 }
554
555 if (djdev->reports_supported & KBD_LEDS) {
556 dbg_hid("%s: need to send kbd leds report descriptor: %x\n",
557 __func__, djdev->reports_supported);
558 }
559
560 return 0;
561}
562
563static int logi_dj_ll_input_event(struct input_dev *dev, unsigned int type,
564 unsigned int code, int value)
565{
566 /* Sent by the input layer to handle leds and Force Feedback */
567 struct hid_device *dj_hiddev = input_get_drvdata(dev);
568 struct dj_device *dj_dev = dj_hiddev->driver_data;
569
570 struct dj_receiver_dev *djrcv_dev =
571 dev_get_drvdata(dj_hiddev->dev.parent);
572 struct hid_device *dj_rcv_hiddev = djrcv_dev->hdev;
573 struct hid_report_enum *output_report_enum;
574
575 struct hid_field *field;
576 struct hid_report *report;
577 unsigned char data[8];
578 int offset;
579
580 dbg_hid("%s: %s, type:%d | code:%d | value:%d\n",
581 __func__, dev->phys, type, code, value);
582
583 if (type != EV_LED)
584 return -1;
585
586 offset = hidinput_find_field(dj_hiddev, type, code, &field);
587
588 if (offset == -1) {
589 dev_warn(&dev->dev, "event field not found\n");
590 return -1;
591 }
592 hid_set_field(field, offset, value);
593 hid_output_report(field->report, &data[0]);
594
595 output_report_enum = &dj_rcv_hiddev->report_enum[HID_OUTPUT_REPORT];
596 report = output_report_enum->report_id_hash[REPORT_ID_DJ_SHORT];
597 hid_set_field(report->field[0], 0, dj_dev->device_index);
598 hid_set_field(report->field[0], 1, REPORT_TYPE_LEDS);
599 hid_set_field(report->field[0], 2, data[1]);
600
601 usbhid_submit_report(dj_rcv_hiddev, report, USB_DIR_OUT);
602
603 return 0;
604
605}
606
607static int logi_dj_ll_start(struct hid_device *hid)
608{
609 dbg_hid("%s\n", __func__);
610 return 0;
611}
612
613static void logi_dj_ll_stop(struct hid_device *hid)
614{
615 dbg_hid("%s\n", __func__);
616}
617
618
619static struct hid_ll_driver logi_dj_ll_driver = {
620 .parse = logi_dj_ll_parse,
621 .start = logi_dj_ll_start,
622 .stop = logi_dj_ll_stop,
623 .open = logi_dj_ll_open,
624 .close = logi_dj_ll_close,
625 .hidinput_input_event = logi_dj_ll_input_event,
626};
627
628
629static int logi_dj_raw_event(struct hid_device *hdev,
630 struct hid_report *report, u8 *data,
631 int size)
632{
633 struct dj_receiver_dev *djrcv_dev = hid_get_drvdata(hdev);
634 struct dj_report *dj_report = (struct dj_report *) data;
635 unsigned long flags;
636 bool report_processed = false;
637
638 dbg_hid("%s, size:%d\n", __func__, size);
639
640 /* Here we receive all data coming from iface 2, there are 4 cases:
641 *
642 * 1) Data should continue its normal processing i.e. data does not
643 * come from the DJ collection, in which case we do nothing and
644 * return 0, so hid-core can continue normal processing (will forward
645 * to associated hidraw device)
646 *
647 * 2) Data is from DJ collection, and is intended for this driver i. e.
648 * data contains arrival, departure, etc notifications, in which case
649 * we queue them for delayed processing by the work queue. We return 1
650 * to hid-core as no further processing is required from it.
651 *
652 * 3) Data is from DJ collection, and informs a connection change,
653 * if the change means rf link loss, then we must send a null report
654 * to the upper layer to discard potentially pressed keys that may be
655 * repeated forever by the input layer. Return 1 to hid-core as no
656 * further processing is required.
657 *
658 * 4) Data is from DJ collection and is an actual input event from
659 * a paired DJ device in which case we forward it to the correct hid
660 * device (via hid_input_report() ) and return 1 so hid-core does not do
661 * anything else with it.
662 */
663
664 spin_lock_irqsave(&djrcv_dev->lock, flags);
665 if (dj_report->report_id == REPORT_ID_DJ_SHORT) {
666 switch (dj_report->report_type) {
667 case REPORT_TYPE_NOTIF_DEVICE_PAIRED:
668 case REPORT_TYPE_NOTIF_DEVICE_UNPAIRED:
669 logi_dj_recv_queue_notification(djrcv_dev, dj_report);
670 break;
671 case REPORT_TYPE_NOTIF_CONNECTION_STATUS:
672 if (dj_report->report_params[CONNECTION_STATUS_PARAM_STATUS] ==
673 STATUS_LINKLOSS) {
674 logi_dj_recv_forward_null_report(djrcv_dev, dj_report);
675 }
676 break;
677 default:
678 logi_dj_recv_forward_report(djrcv_dev, dj_report);
679 }
680 report_processed = true;
681 }
682 spin_unlock_irqrestore(&djrcv_dev->lock, flags);
683
684 return report_processed;
685}
686
687static int logi_dj_probe(struct hid_device *hdev,
688 const struct hid_device_id *id)
689{
690 struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
691 struct dj_receiver_dev *djrcv_dev;
692 int retval;
693
694 if (is_dj_device((struct dj_device *)hdev->driver_data))
695 return -ENODEV;
696
697 dbg_hid("%s called for ifnum %d\n", __func__,
698 intf->cur_altsetting->desc.bInterfaceNumber);
699
700 /* Ignore interfaces 0 and 1, they will not carry any data, dont create
701 * any hid_device for them */
702 if (intf->cur_altsetting->desc.bInterfaceNumber !=
703 LOGITECH_DJ_INTERFACE_NUMBER) {
704 dbg_hid("%s: ignoring ifnum %d\n", __func__,
705 intf->cur_altsetting->desc.bInterfaceNumber);
706 return -ENODEV;
707 }
708
709 /* Treat interface 2 */
710
711 djrcv_dev = kzalloc(sizeof(struct dj_receiver_dev), GFP_KERNEL);
712 if (!djrcv_dev) {
713 dev_err(&hdev->dev,
714 "%s:failed allocating dj_receiver_dev\n", __func__);
715 return -ENOMEM;
716 }
717 djrcv_dev->hdev = hdev;
718 INIT_WORK(&djrcv_dev->work, delayedwork_callback);
719 spin_lock_init(&djrcv_dev->lock);
720 if (kfifo_alloc(&djrcv_dev->notif_fifo,
721 DJ_MAX_NUMBER_NOTIFICATIONS * sizeof(struct dj_report),
722 GFP_KERNEL)) {
723 dev_err(&hdev->dev,
724 "%s:failed allocating notif_fifo\n", __func__);
725 kfree(djrcv_dev);
726 return -ENOMEM;
727 }
728 hid_set_drvdata(hdev, djrcv_dev);
729
730 /* Call to usbhid to fetch the HID descriptors of interface 2 and
731 * subsequently call to the hid/hid-core to parse the fetched
732 * descriptors, this will in turn create the hidraw and hiddev nodes
733 * for interface 2 of the receiver */
734 retval = hid_parse(hdev);
735 if (retval) {
736 dev_err(&hdev->dev,
737 "%s:parse of interface 2 failed\n", __func__);
738 goto hid_parse_fail;
739 }
740
741 /* Starts the usb device and connects to upper interfaces hiddev and
742 * hidraw */
743 retval = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
744 if (retval) {
745 dev_err(&hdev->dev,
746 "%s:hid_hw_start returned error\n", __func__);
747 goto hid_hw_start_fail;
748 }
749
750 retval = logi_dj_recv_switch_to_dj_mode(djrcv_dev, 0);
751 if (retval < 0) {
752 dev_err(&hdev->dev,
753 "%s:logi_dj_recv_switch_to_dj_mode returned error:%d\n",
754 __func__, retval);
755 goto switch_to_dj_mode_fail;
756 }
757
758 /* This is enabling the polling urb on the IN endpoint */
759 retval = hdev->ll_driver->open(hdev);
760 if (retval < 0) {
761 dev_err(&hdev->dev, "%s:hdev->ll_driver->open returned "
762 "error:%d\n", __func__, retval);
763 goto llopen_failed;
764 }
765
766 retval = logi_dj_recv_query_paired_devices(djrcv_dev);
767 if (retval < 0) {
768 dev_err(&hdev->dev, "%s:logi_dj_recv_query_paired_devices "
769 "error:%d\n", __func__, retval);
770 goto logi_dj_recv_query_paired_devices_failed;
771 }
772
773 return retval;
774
775logi_dj_recv_query_paired_devices_failed:
776 hdev->ll_driver->close(hdev);
777
778llopen_failed:
779switch_to_dj_mode_fail:
780 hid_hw_stop(hdev);
781
782hid_hw_start_fail:
783hid_parse_fail:
784 kfifo_free(&djrcv_dev->notif_fifo);
785 kfree(djrcv_dev);
786 hid_set_drvdata(hdev, NULL);
787 return retval;
788
789}
790
791#ifdef CONFIG_PM
792static int logi_dj_reset_resume(struct hid_device *hdev)
793{
794 int retval;
795 struct dj_receiver_dev *djrcv_dev = hid_get_drvdata(hdev);
796
797 retval = logi_dj_recv_switch_to_dj_mode(djrcv_dev, 0);
798 if (retval < 0) {
799 dev_err(&hdev->dev,
800 "%s:logi_dj_recv_switch_to_dj_mode returned error:%d\n",
801 __func__, retval);
802 }
803
804 return 0;
805}
806#endif
807
808static void logi_dj_remove(struct hid_device *hdev)
809{
810 struct dj_receiver_dev *djrcv_dev = hid_get_drvdata(hdev);
811 struct dj_device *dj_dev;
812 int i;
813
814 dbg_hid("%s\n", __func__);
815
816 cancel_work_sync(&djrcv_dev->work);
817
818 hdev->ll_driver->close(hdev);
819 hid_hw_stop(hdev);
820
821 /* I suppose that at this point the only context that can access
822 * the djrecv_data is this thread as the work item is guaranteed to
823 * have finished and no more raw_event callbacks should arrive after
824 * the remove callback was triggered so no locks are put around the
825 * code below */
826 for (i = 0; i < DJ_MAX_PAIRED_DEVICES; i++) {
827 dj_dev = djrcv_dev->paired_dj_devices[i];
828 if (dj_dev != NULL) {
829 hid_destroy_device(dj_dev->hdev);
830 kfree(dj_dev);
831 djrcv_dev->paired_dj_devices[i] = NULL;
832 }
833 }
834
835 kfifo_free(&djrcv_dev->notif_fifo);
836 kfree(djrcv_dev);
837 hid_set_drvdata(hdev, NULL);
838}
839
840static int logi_djdevice_probe(struct hid_device *hdev,
841 const struct hid_device_id *id)
842{
843 int ret;
844 struct dj_device *dj_dev = hdev->driver_data;
845
846 if (!is_dj_device(dj_dev))
847 return -ENODEV;
848
849 ret = hid_parse(hdev);
850 if (!ret)
851 ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
852
853 return ret;
854}
855
856static const struct hid_device_id logi_dj_receivers[] = {
857 {HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH,
858 USB_DEVICE_ID_LOGITECH_UNIFYING_RECEIVER)},
859 {HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH,
860 USB_DEVICE_ID_LOGITECH_UNIFYING_RECEIVER_2)},
861 {}
862};
863
864MODULE_DEVICE_TABLE(hid, logi_dj_receivers);
865
866static struct hid_driver logi_djreceiver_driver = {
867 .name = "logitech-djreceiver",
868 .id_table = logi_dj_receivers,
869 .probe = logi_dj_probe,
870 .remove = logi_dj_remove,
871 .raw_event = logi_dj_raw_event,
872#ifdef CONFIG_PM
873 .reset_resume = logi_dj_reset_resume,
874#endif
875};
876
877
878static const struct hid_device_id logi_dj_devices[] = {
879 {HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH,
880 USB_DEVICE_ID_LOGITECH_UNIFYING_RECEIVER)},
881 {HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH,
882 USB_DEVICE_ID_LOGITECH_UNIFYING_RECEIVER_2)},
883 {}
884};
885
886static struct hid_driver logi_djdevice_driver = {
887 .name = "logitech-djdevice",
888 .id_table = logi_dj_devices,
889 .probe = logi_djdevice_probe,
890};
891
892
893static int __init logi_dj_init(void)
894{
895 int retval;
896
897 dbg_hid("Logitech-DJ:%s\n", __func__);
898
899 retval = hid_register_driver(&logi_djreceiver_driver);
900 if (retval)
901 return retval;
902
903 retval = hid_register_driver(&logi_djdevice_driver);
904 if (retval)
905 hid_unregister_driver(&logi_djreceiver_driver);
906
907 return retval;
908
909}
910
911static void __exit logi_dj_exit(void)
912{
913 dbg_hid("Logitech-DJ:%s\n", __func__);
914
915 hid_unregister_driver(&logi_djdevice_driver);
916 hid_unregister_driver(&logi_djreceiver_driver);
917
918}
919
920module_init(logi_dj_init);
921module_exit(logi_dj_exit);
922MODULE_LICENSE("GPL");
923MODULE_AUTHOR("Logitech");
924MODULE_AUTHOR("Nestor Lopez Casado");
925MODULE_AUTHOR("nlopezcasad@logitech.com");
diff --git a/drivers/hid/hid-logitech-dj.h b/drivers/hid/hid-logitech-dj.h
new file mode 100644
index 000000000000..5982263acd73
--- /dev/null
+++ b/drivers/hid/hid-logitech-dj.h
@@ -0,0 +1,120 @@
1#ifndef __HID_LOGITECH_DJ_H
2#define __HID_LOGITECH_DJ_H
3
4/*
5 * HID driver for Logitech Unifying receivers
6 *
7 * Copyright (c) 2011 Logitech
8 */
9
10/*
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License version 2 as
13 * published by the Free Software Foundation.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 *
24 */
25
26#include <linux/kfifo.h>
27
28#define DJ_MAX_PAIRED_DEVICES 6
29#define DJ_MAX_NUMBER_NOTIFICATIONS 8
30
31#define DJREPORT_SHORT_LENGTH 15
32#define DJREPORT_LONG_LENGTH 32
33
34#define REPORT_ID_DJ_SHORT 0x20
35#define REPORT_ID_DJ_LONG 0x21
36
37#define REPORT_TYPE_RFREPORT_FIRST 0x01
38#define REPORT_TYPE_RFREPORT_LAST 0x1F
39
40/* Command Switch to DJ mode */
41#define REPORT_TYPE_CMD_SWITCH 0x80
42#define CMD_SWITCH_PARAM_DEVBITFIELD 0x00
43#define CMD_SWITCH_PARAM_TIMEOUT_SECONDS 0x01
44#define TIMEOUT_NO_KEEPALIVE 0x00
45
46/* Command to Get the list of Paired devices */
47#define REPORT_TYPE_CMD_GET_PAIRED_DEVICES 0x81
48
49/* Device Paired Notification */
50#define REPORT_TYPE_NOTIF_DEVICE_PAIRED 0x41
51#define SPFUNCTION_MORE_NOTIF_EXPECTED 0x01
52#define SPFUNCTION_DEVICE_LIST_EMPTY 0x02
53#define DEVICE_PAIRED_PARAM_SPFUNCTION 0x00
54#define DEVICE_PAIRED_PARAM_EQUAD_ID_LSB 0x01
55#define DEVICE_PAIRED_PARAM_EQUAD_ID_MSB 0x02
56#define DEVICE_PAIRED_RF_REPORT_TYPE 0x03
57
58/* Device Un-Paired Notification */
59#define REPORT_TYPE_NOTIF_DEVICE_UNPAIRED 0x40
60
61
62/* Connection Status Notification */
63#define REPORT_TYPE_NOTIF_CONNECTION_STATUS 0x42
64#define CONNECTION_STATUS_PARAM_STATUS 0x00
65#define STATUS_LINKLOSS 0x01
66
67/* Error Notification */
68#define REPORT_TYPE_NOTIF_ERROR 0x7F
69#define NOTIF_ERROR_PARAM_ETYPE 0x00
70#define ETYPE_KEEPALIVE_TIMEOUT 0x01
71
72/* supported DJ HID && RF report types */
73#define REPORT_TYPE_KEYBOARD 0x01
74#define REPORT_TYPE_MOUSE 0x02
75#define REPORT_TYPE_CONSUMER_CONTROL 0x03
76#define REPORT_TYPE_SYSTEM_CONTROL 0x04
77#define REPORT_TYPE_MEDIA_CENTER 0x08
78#define REPORT_TYPE_LEDS 0x0E
79
80/* RF Report types bitfield */
81#define STD_KEYBOARD 0x00000002
82#define STD_MOUSE 0x00000004
83#define MULTIMEDIA 0x00000008
84#define POWER_KEYS 0x00000010
85#define MEDIA_CENTER 0x00000100
86#define KBD_LEDS 0x00004000
87
88struct dj_report {
89 u8 report_id;
90 u8 device_index;
91 u8 report_type;
92 u8 report_params[DJREPORT_SHORT_LENGTH - 3];
93};
94
95struct dj_receiver_dev {
96 struct hid_device *hdev;
97 struct dj_device *paired_dj_devices[DJ_MAX_PAIRED_DEVICES];
98 struct work_struct work;
99 struct kfifo notif_fifo;
100 spinlock_t lock;
101};
102
103struct dj_device {
104 struct hid_device *hdev;
105 struct dj_receiver_dev *dj_receiver_dev;
106 u32 reports_supported;
107 u8 device_index;
108};
109
110/**
111 * is_dj_device - know if the given dj_device is not the receiver.
112 * @dj_dev: the dj device to test
113 *
114 * This macro tests if a struct dj_device pointer is a device created
115 * by the bus enumarator.
116 */
117#define is_dj_device(dj_dev) \
118 (&(dj_dev)->dj_receiver_dev->hdev->dev == (dj_dev)->hdev->dev.parent)
119
120#endif