2 * HIDPP protocol for Logitech Unifying receivers
4 * Copyright (c) 2011 Logitech (c)
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.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 * Should you need to contact me, the author, you can do so by e-mail send
22 * your message to Benjamin Tissoires <benjamin.tissoires at gmail com>
27 #include <linux/device.h>
28 #include <linux/hid.h>
29 #include <linux/module.h>
30 #include <linux/slab.h>
31 #include <linux/sched.h>
33 #include "hid-logitech-hidpp.h"
35 MODULE_LICENSE("GPL");
36 MODULE_AUTHOR("Benjamin Tissoires <benjamin.tissoires@gmail.com>");
37 MODULE_AUTHOR("Nestor Lopez Casado <nlopezcasad@logitech.com>");
39 #define MAX_INIT_RETRY 5
41 enum delayed_work_type {
45 static void hidpp_print_raw_event(const char *header, u8 *data, int size)
48 unsigned char log[96];
49 unsigned char tmpstr[60];
51 snprintf(log, sizeof(tmpstr), "%s (size=%d)", header, size);
53 for (i = 0; i < size; i++) {
54 snprintf(tmpstr, sizeof(tmpstr), " %02x", data[i]);
55 strlcat(log, tmpstr, sizeof(log));
61 static int __hidpp_send_report(struct hid_device *hdev,
62 struct hidpp_report *hidpp_rept)
66 if (!hdev->hid_output_raw_report) {
67 dev_err(&hdev->dev, "%s:"
68 "hid_output_raw_report is null\n", __func__);
72 hidpp_print_raw_event("sending ", (u8 *)hidpp_rept,
73 HIDPP_REPORT_LONG_LENGTH);
74 sent_bytes = hdev->hid_output_raw_report(hdev, (u8 *) hidpp_rept,
75 sizeof(struct hidpp_report),
78 /* It seems that sending via bluetooth can return -EIO even
79 * when the message is delivered, so we have this hack: */
80 return (sent_bytes < 0 && sent_bytes != -EIO) ? sent_bytes : 0;
83 static int hidpp_send_message_sync(struct hidpp_device *hidpp_dev,
84 struct hidpp_report *message,
85 struct hidpp_report *response)
89 mutex_lock(&hidpp_dev->send_mutex);
91 hidpp_dev->send_receive_buf = response;
92 hidpp_dev->answer_available = false;
94 /* So that we can later validate the answer when it arrives
95 * in hidpp_raw_event */
98 ret = __hidpp_send_report(hidpp_dev->hid_dev, message);
101 dbg_hid("__hidpp_send_report returned err: %d\n", ret);
102 memset(response, 0, sizeof(struct hidpp_report));
106 if (!wait_event_timeout(hidpp_dev->wait, hidpp_dev->answer_available, 10*HZ)) {
107 dbg_hid("%s:timeout waiting for response\n", __func__);
108 memset(response, 0, sizeof(struct hidpp_report));
112 if (response->report_id == REPORT_ID_HIDPP_SHORT &&
113 response->fap.feature_index == HIDPP_ERROR) {
114 ret = response->fap.params[0];
115 dbg_hid("__hidpp_send_report got hidpp error %d\n", ret);
120 mutex_unlock(&hidpp_dev->send_mutex);
125 int hidpp_send_fap_command_sync(struct hidpp_device *hidpp_dev,
126 u8 feat_index, u8 funcindex_clientid, u8 *params, int param_count,
127 struct hidpp_report *response)
129 struct hidpp_report message;
131 if (param_count > sizeof(message.rap.params))
134 memset(&message, 0, sizeof(message));
135 message.report_id = REPORT_ID_HIDPP_LONG;
136 message.fap.feature_index = feat_index;
137 message.fap.funcindex_clientid = funcindex_clientid;
138 memcpy(&message.fap.params, params, param_count);
140 return hidpp_send_message_sync(hidpp_dev, &message, response);
142 EXPORT_SYMBOL_GPL(hidpp_send_fap_command_sync);
144 int hidpp_send_rap_command_sync(struct hidpp_device *hidpp_dev,
145 u8 report_id, u8 sub_id, u8 reg_address, u8 *params,
147 struct hidpp_report *response)
149 struct hidpp_report message;
151 if ((report_id != REPORT_ID_HIDPP_SHORT) &&
152 (report_id != REPORT_ID_HIDPP_LONG))
155 if (param_count > sizeof(message.rap.params))
158 memset(&message, 0, sizeof(message));
159 message.report_id = report_id;
160 /* If sending to a non-DJ device, device expects 0xff. If sending to
161 * a DJ device, this device_index will be overwritten by the DJ code: */
162 message.device_index = 0xff;
163 message.rap.sub_id = sub_id;
164 message.rap.reg_address = reg_address;
165 memcpy(&message.rap.params, params, param_count);
167 return hidpp_send_message_sync(hidpp_dev, &message, response);
169 EXPORT_SYMBOL_GPL(hidpp_send_rap_command_sync);
171 int hidpp_get_hidpp2_feature_index(struct hidpp_device *hidpp_dev,
176 struct hidpp_report response;
180 params[0] = feature_id >> 8;
181 params[1] = feature_id & 0xff;
182 ret = hidpp_send_hidpp2_sync(hidpp_dev,
183 REPORT_ID_HIDPP_LONG,
192 *feature_idx = response.rap.params[0];
195 EXPORT_SYMBOL_GPL(hidpp_get_hidpp2_feature_index);
197 static void schedule_delayed_hidpp_init(struct hidpp_device *hidpp_dev)
199 enum delayed_work_type work_type = HIDPP_INIT;
201 kfifo_in(&hidpp_dev->delayed_work_fifo, &work_type,
202 sizeof(enum delayed_work_type));
204 if (schedule_work(&hidpp_dev->work) == 0) {
205 dbg_hid("%s: did not schedule the work item,"
206 " was already queued\n",
211 void hidpp_delayed_init(struct hidpp_device *hidpp_device)
213 struct hid_device *hdev = hidpp_device->hid_dev;
216 dbg_hid("%s: hdev:%p\n", __func__, hdev);
218 if (hidpp_device->initialized)
221 if (down_trylock(&hidpp_device->hid_dev->driver_lock)) {
222 if (hidpp_device->init_retry < MAX_INIT_RETRY) {
223 dbg_hid("%s: we need to reschedule the work item."
224 "Semaphore still held on device\n", __func__);
225 schedule_delayed_hidpp_init(hidpp_device);
226 hidpp_device->init_retry++;
228 dbg_hid("%s: giving up initialization now.", __func__);
229 hidpp_device->init_retry = 0;
233 up(&hidpp_device->hid_dev->driver_lock);
235 if (hidpp_device->device_init)
236 ret = hidpp_device->device_init(hidpp_device);
239 hidpp_device->initialized = true;
241 EXPORT_SYMBOL_GPL(hidpp_delayed_init);
243 static void delayed_work_cb(struct work_struct *work)
245 struct hidpp_device *hidpp_device =
246 container_of(work, struct hidpp_device, work);
249 enum delayed_work_type work_type;
251 dbg_hid("%s\n", __func__);
253 spin_lock_irqsave(&hidpp_device->lock, flags);
255 count = kfifo_out(&hidpp_device->delayed_work_fifo, &work_type,
256 sizeof(enum delayed_work_type));
258 if (count != sizeof(enum delayed_work_type)) {
259 dev_err(&hidpp_device->hid_dev->dev, "%s: workitem triggered without "
260 "notifications available\n", __func__);
261 spin_unlock_irqrestore(&hidpp_device->lock, flags);
265 if (!kfifo_is_empty(&hidpp_device->delayed_work_fifo)) {
266 if (schedule_work(&hidpp_device->work) == 0) {
267 dbg_hid("%s: did not schedule the work item, was "
268 "already queued\n", __func__);
272 spin_unlock_irqrestore(&hidpp_device->lock, flags);
276 hidpp_delayed_init(hidpp_device);
279 dbg_hid("%s: unexpected report type\n", __func__);
283 int hidpp_init(struct hidpp_device *hidpp_dev, struct hid_device *hid_dev)
285 if (hidpp_dev->initialized)
288 hidpp_dev->init_retry = 0;
289 hidpp_dev->hid_dev = hid_dev;
290 hidpp_dev->initialized = 1;
292 INIT_WORK(&hidpp_dev->work, delayed_work_cb);
293 mutex_init(&hidpp_dev->send_mutex);
294 init_waitqueue_head(&hidpp_dev->wait);
296 spin_lock_init(&hidpp_dev->lock);
297 if (kfifo_alloc(&hidpp_dev->delayed_work_fifo,
298 4 * sizeof(struct hidpp_report),
300 dev_err(&hidpp_dev->hid_dev->dev,
301 "%s:failed allocating delayed_work_fifo\n", __func__);
302 mutex_destroy(&hidpp_dev->send_mutex);
308 EXPORT_SYMBOL_GPL(hidpp_init);
310 void hidpp_connect_change(struct hidpp_device *hidpp_dev, bool connected)
312 if ((!hidpp_dev->initialized) && (connected))
313 hidpp_delayed_init(hidpp_dev);
315 if (hidpp_dev->connect_change)
316 hidpp_dev->connect_change(hidpp_dev, connected);
318 EXPORT_SYMBOL_GPL(hidpp_connect_change);
320 void hidpp_remove(struct hidpp_device *hidpp_dev)
322 dbg_hid("%s\n", __func__);
323 cancel_work_sync(&hidpp_dev->work);
324 mutex_destroy(&hidpp_dev->send_mutex);
325 kfifo_free(&hidpp_dev->delayed_work_fifo);
326 hidpp_dev->initialized = false;
327 hidpp_dev->hid_dev = NULL;
329 EXPORT_SYMBOL_GPL(hidpp_remove);
331 int hidpp_raw_event(struct hid_device *hdev, struct hid_report *hid_report,
334 struct hidpp_device *hidpp_dev = hid_get_drvdata(hdev);
335 struct hidpp_report *report = (struct hidpp_report *)data;
336 struct hidpp_report *question = hidpp_dev->send_receive_buf;
337 struct hidpp_report *answer = hidpp_dev->send_receive_buf;
339 dbg_hid("%s\n", __func__);
341 hidpp_print_raw_event("hidpp_raw_event", data, size);
343 if (!(report->report_id == REPORT_ID_HIDPP_LONG ||
344 report->report_id == REPORT_ID_HIDPP_SHORT ||
345 (report->report_id == T651_REPORT_TYPE_MOUSE &&
346 hdev->product == USB_DEVICE_ID_WIRELESS_TOUCHPAD_T651))) {
347 dbg_hid("hid-logitech-hidpp.c:%s: ignore report_id:%d\n",
348 __func__, report->report_id);
352 /* If the mutex is locked then we have a pending answer from a
353 * previoulsly sent command
355 if (unlikely(mutex_is_locked(&hidpp_dev->send_mutex))) {
356 /* Check for a correct hidpp20 answer */
357 bool correct_answer =
358 report->fap.feature_index == question->fap.feature_index &&
359 report->fap.funcindex_clientid == question->fap.funcindex_clientid;
360 dbg_hid("%s mutex is locked, waiting for reply\n", __func__);
362 /* Check for a "correct" hidpp10 error message, this means the
363 * device is hidpp10 and does not support the command sent */
364 correct_answer = correct_answer ||
365 (report->fap.feature_index == HIDPP_ERROR &&
366 report->fap.funcindex_clientid == question->fap.feature_index &&
367 report->fap.params[0] == question->fap.funcindex_clientid);
369 if (correct_answer) {
370 hidpp_print_raw_event("answer", data, size);
372 hidpp_dev->answer_available = true;
373 wake_up(&hidpp_dev->wait);
374 /* This was an answer to a command that this driver sent
375 * we return 1 to hid-core to avoid forwarding the command
376 * upstream as it has been treated by the driver */
382 if (hidpp_dev->raw_event != NULL) {
383 return hidpp_dev->raw_event(hidpp_dev, report);
386 hidpp_print_raw_event("event not treated", data, size);
390 EXPORT_SYMBOL_GPL(hidpp_raw_event);