blob: 217ef476156049378323ef6f685ad824ac110d3d [file] [log] [blame]
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +09001/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002 HIDP implementation for Linux Bluetooth stack (BlueZ).
3 Copyright (C) 2003-2004 Marcel Holtmann <marcel@holtmann.org>
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License version 2 as
7 published by the Free Software Foundation;
8
9 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
10 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
11 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
12 IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +090013 CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
14 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
Linus Torvalds1da177e2005-04-16 15:20:36 -070016 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +090018 ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
19 COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
Linus Torvalds1da177e2005-04-16 15:20:36 -070020 SOFTWARE IS DISCLAIMED.
21*/
22
Linus Torvalds1da177e2005-04-16 15:20:36 -070023#include <linux/module.h>
24
25#include <linux/types.h>
26#include <linux/errno.h>
27#include <linux/kernel.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070028#include <linux/sched.h>
29#include <linux/slab.h>
30#include <linux/poll.h>
Rafael J. Wysocki83144182007-07-17 04:03:35 -070031#include <linux/freezer.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070032#include <linux/fcntl.h>
33#include <linux/skbuff.h>
34#include <linux/socket.h>
35#include <linux/ioctl.h>
36#include <linux/file.h>
37#include <linux/init.h>
38#include <linux/wait.h>
Alan Ott0ff17312011-01-18 03:04:40 -050039#include <linux/mutex.h>
Szymon Jancaabf6f82011-04-05 15:37:45 +020040#include <linux/kthread.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070041#include <net/sock.h>
42
43#include <linux/input.h>
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +010044#include <linux/hid.h>
Marcel Holtmann364f6352009-08-22 14:15:53 -070045#include <linux/hidraw.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070046
47#include <net/bluetooth/bluetooth.h>
Marcel Holtmann0a85b962006-07-06 13:09:02 +020048#include <net/bluetooth/hci_core.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070049#include <net/bluetooth/l2cap.h>
50
51#include "hidp.h"
52
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +010053#define VERSION "1.2"
Linus Torvalds1da177e2005-04-16 15:20:36 -070054
55static DECLARE_RWSEM(hidp_session_sem);
56static LIST_HEAD(hidp_session_list);
57
58static unsigned char hidp_keycode[256] = {
Szymon Janc17f09a72011-03-21 14:20:01 +010059 0, 0, 0, 0, 30, 48, 46, 32, 18, 33, 34, 35, 23, 36,
60 37, 38, 50, 49, 24, 25, 16, 19, 31, 20, 22, 47, 17, 45,
61 21, 44, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 28, 1,
62 14, 15, 57, 12, 13, 26, 27, 43, 43, 39, 40, 41, 51, 52,
63 53, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 87, 88,
64 99, 70, 119, 110, 102, 104, 111, 107, 109, 106, 105, 108, 103, 69,
65 98, 55, 74, 78, 96, 79, 80, 81, 75, 76, 77, 71, 72, 73,
66 82, 83, 86, 127, 116, 117, 183, 184, 185, 186, 187, 188, 189, 190,
67 191, 192, 193, 194, 134, 138, 130, 132, 128, 129, 131, 137, 133, 135,
68 136, 113, 115, 114, 0, 0, 0, 121, 0, 89, 93, 124, 92, 94,
69 95, 0, 0, 0, 122, 123, 90, 91, 85, 0, 0, 0, 0, 0,
70 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
71 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
72 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
73 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
74 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
75 29, 42, 56, 125, 97, 54, 100, 126, 164, 166, 165, 163, 161, 115,
76 114, 113, 150, 158, 159, 128, 136, 177, 178, 176, 142, 152, 173, 140
Linus Torvalds1da177e2005-04-16 15:20:36 -070077};
78
79static unsigned char hidp_mkeyspat[] = { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 };
80
81static struct hidp_session *__hidp_get_session(bdaddr_t *bdaddr)
82{
83 struct hidp_session *session;
Linus Torvalds1da177e2005-04-16 15:20:36 -070084
85 BT_DBG("");
86
Gustavo F. Padovancd11cdd2011-10-06 17:35:31 -030087 list_for_each_entry(session, &hidp_session_list, list) {
Linus Torvalds1da177e2005-04-16 15:20:36 -070088 if (!bacmp(bdaddr, &session->bdaddr))
89 return session;
90 }
91 return NULL;
92}
93
94static void __hidp_link_session(struct hidp_session *session)
95{
96 __module_get(THIS_MODULE);
97 list_add(&session->list, &hidp_session_list);
98}
99
100static void __hidp_unlink_session(struct hidp_session *session)
101{
Marcel Holtmannedad6382009-08-22 14:22:15 -0700102 hci_conn_put_device(session->conn);
103
Linus Torvalds1da177e2005-04-16 15:20:36 -0700104 list_del(&session->list);
105 module_put(THIS_MODULE);
106}
107
108static void __hidp_copy_session(struct hidp_session *session, struct hidp_conninfo *ci)
109{
Vasiliy Kulikovd31dbf62010-10-30 18:26:31 +0400110 memset(ci, 0, sizeof(*ci));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700111 bacpy(&ci->bdaddr, &session->bdaddr);
112
113 ci->flags = session->flags;
114 ci->state = session->state;
115
116 ci->vendor = 0x0000;
117 ci->product = 0x0000;
118 ci->version = 0x0000;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700119
120 if (session->input) {
121 ci->vendor = session->input->id.vendor;
122 ci->product = session->input->id.product;
123 ci->version = session->input->id.version;
124 if (session->input->name)
125 strncpy(ci->name, session->input->name, 128);
126 else
127 strncpy(ci->name, "HID Boot Device", 128);
128 }
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100129
130 if (session->hid) {
131 ci->vendor = session->hid->vendor;
132 ci->product = session->hid->product;
133 ci->version = session->hid->version;
134 strncpy(ci->name, session->hid->name, 128);
135 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700136}
137
Andrew Morton91f5cca2008-02-05 03:07:58 -0800138static int hidp_queue_event(struct hidp_session *session, struct input_dev *dev,
139 unsigned int type, unsigned int code, int value)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700140{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700141 unsigned char newleds;
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100142 struct sk_buff *skb;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700143
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100144 BT_DBG("session %p type %d code %d value %d", session, type, code, value);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700145
146 if (type != EV_LED)
147 return -1;
148
149 newleds = (!!test_bit(LED_KANA, dev->led) << 3) |
150 (!!test_bit(LED_COMPOSE, dev->led) << 3) |
151 (!!test_bit(LED_SCROLLL, dev->led) << 2) |
152 (!!test_bit(LED_CAPSL, dev->led) << 1) |
153 (!!test_bit(LED_NUML, dev->led));
154
155 if (session->leds == newleds)
156 return 0;
157
158 session->leds = newleds;
159
Andrei Emeltchenko5a08ecc2011-01-11 17:20:20 +0200160 skb = alloc_skb(3, GFP_ATOMIC);
161 if (!skb) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700162 BT_ERR("Can't allocate memory for new frame");
163 return -ENOMEM;
164 }
165
166 *skb_put(skb, 1) = HIDP_TRANS_DATA | HIDP_DATA_RTYPE_OUPUT;
167 *skb_put(skb, 1) = 0x01;
168 *skb_put(skb, 1) = newleds;
169
170 skb_queue_tail(&session->intr_transmit, skb);
171
172 hidp_schedule(session);
173
174 return 0;
175}
176
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100177static int hidp_hidinput_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
178{
Marcel Holtmann5be39462007-05-09 09:15:30 +0200179 struct hid_device *hid = input_get_drvdata(dev);
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100180 struct hidp_session *session = hid->driver_data;
181
182 return hidp_queue_event(session, dev, type, code, value);
183}
184
185static int hidp_input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
186{
Marcel Holtmann5be39462007-05-09 09:15:30 +0200187 struct hidp_session *session = input_get_drvdata(dev);
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100188
189 return hidp_queue_event(session, dev, type, code, value);
190}
191
Linus Torvalds1da177e2005-04-16 15:20:36 -0700192static void hidp_input_report(struct hidp_session *session, struct sk_buff *skb)
193{
194 struct input_dev *dev = session->input;
195 unsigned char *keys = session->keys;
196 unsigned char *udata = skb->data + 1;
197 signed char *sdata = skb->data + 1;
198 int i, size = skb->len - 1;
199
200 switch (skb->data[0]) {
201 case 0x01: /* Keyboard report */
202 for (i = 0; i < 8; i++)
203 input_report_key(dev, hidp_keycode[i + 224], (udata[0] >> i) & 1);
204
205 /* If all the key codes have been set to 0x01, it means
206 * too many keys were pressed at the same time. */
207 if (!memcmp(udata + 2, hidp_mkeyspat, 6))
208 break;
209
210 for (i = 2; i < 8; i++) {
211 if (keys[i] > 3 && memscan(udata + 2, keys[i], 6) == udata + 8) {
212 if (hidp_keycode[keys[i]])
213 input_report_key(dev, hidp_keycode[keys[i]], 0);
214 else
215 BT_ERR("Unknown key (scancode %#x) released.", keys[i]);
216 }
217
218 if (udata[i] > 3 && memscan(keys + 2, udata[i], 6) == keys + 8) {
219 if (hidp_keycode[udata[i]])
220 input_report_key(dev, hidp_keycode[udata[i]], 1);
221 else
222 BT_ERR("Unknown key (scancode %#x) pressed.", udata[i]);
223 }
224 }
225
226 memcpy(keys, udata, 8);
227 break;
228
229 case 0x02: /* Mouse report */
230 input_report_key(dev, BTN_LEFT, sdata[0] & 0x01);
231 input_report_key(dev, BTN_RIGHT, sdata[0] & 0x02);
232 input_report_key(dev, BTN_MIDDLE, sdata[0] & 0x04);
233 input_report_key(dev, BTN_SIDE, sdata[0] & 0x08);
234 input_report_key(dev, BTN_EXTRA, sdata[0] & 0x10);
235
236 input_report_rel(dev, REL_X, sdata[1]);
237 input_report_rel(dev, REL_Y, sdata[2]);
238
239 if (size > 3)
240 input_report_rel(dev, REL_WHEEL, sdata[3]);
241 break;
242 }
243
244 input_sync(dev);
245}
246
Bastien Nocera6bf82682010-01-20 12:00:42 +0000247static int __hidp_send_ctrl_message(struct hidp_session *session,
248 unsigned char hdr, unsigned char *data, int size)
249{
250 struct sk_buff *skb;
251
252 BT_DBG("session %p data %p size %d", session, data, size);
253
David Herrmann794d1752011-08-26 14:06:02 +0200254 if (atomic_read(&session->terminate))
255 return -EIO;
256
Andrei Emeltchenko5a08ecc2011-01-11 17:20:20 +0200257 skb = alloc_skb(size + 1, GFP_ATOMIC);
258 if (!skb) {
Bastien Nocera6bf82682010-01-20 12:00:42 +0000259 BT_ERR("Can't allocate memory for new frame");
260 return -ENOMEM;
261 }
262
263 *skb_put(skb, 1) = hdr;
264 if (data && size > 0)
265 memcpy(skb_put(skb, size), data, size);
266
267 skb_queue_tail(&session->ctrl_transmit, skb);
268
269 return 0;
270}
271
272static inline int hidp_send_ctrl_message(struct hidp_session *session,
273 unsigned char hdr, unsigned char *data, int size)
274{
275 int err;
276
277 err = __hidp_send_ctrl_message(session, hdr, data, size);
278
279 hidp_schedule(session);
280
281 return err;
282}
283
Andrew Morton91f5cca2008-02-05 03:07:58 -0800284static int hidp_queue_report(struct hidp_session *session,
285 unsigned char *data, int size)
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100286{
287 struct sk_buff *skb;
288
Dave Young6792b5e2007-10-20 14:15:39 +0200289 BT_DBG("session %p hid %p data %p size %d", session, session->hid, data, size);
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100290
Andrei Emeltchenko5a08ecc2011-01-11 17:20:20 +0200291 skb = alloc_skb(size + 1, GFP_ATOMIC);
292 if (!skb) {
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100293 BT_ERR("Can't allocate memory for new frame");
294 return -ENOMEM;
295 }
296
297 *skb_put(skb, 1) = 0xa2;
298 if (size > 0)
299 memcpy(skb_put(skb, size), data, size);
300
301 skb_queue_tail(&session->intr_transmit, skb);
302
303 hidp_schedule(session);
304
305 return 0;
306}
307
308static int hidp_send_report(struct hidp_session *session, struct hid_report *report)
309{
310 unsigned char buf[32];
311 int rsize;
312
313 rsize = ((report->size - 1) >> 3) + 1 + (report->id > 0);
314 if (rsize > sizeof(buf))
315 return -EIO;
316
317 hid_output_report(report, buf);
318
319 return hidp_queue_report(session, buf, rsize);
320}
321
Alan Ott0ff17312011-01-18 03:04:40 -0500322static int hidp_get_raw_report(struct hid_device *hid,
323 unsigned char report_number,
324 unsigned char *data, size_t count,
Jiri Kosinad4bfa032010-01-29 15:03:36 +0100325 unsigned char report_type)
Jiri Kosina2da31932009-11-26 16:20:56 +0100326{
Alan Ott0ff17312011-01-18 03:04:40 -0500327 struct hidp_session *session = hid->driver_data;
328 struct sk_buff *skb;
329 size_t len;
330 int numbered_reports = hid->report_enum[report_type].numbered;
David Herrmann794d1752011-08-26 14:06:02 +0200331 int ret;
Alan Ott0ff17312011-01-18 03:04:40 -0500332
Jiri Kosinad4bfa032010-01-29 15:03:36 +0100333 switch (report_type) {
334 case HID_FEATURE_REPORT:
Alan Ott0ff17312011-01-18 03:04:40 -0500335 report_type = HIDP_TRANS_GET_REPORT | HIDP_DATA_RTYPE_FEATURE;
336 break;
337 case HID_INPUT_REPORT:
338 report_type = HIDP_TRANS_GET_REPORT | HIDP_DATA_RTYPE_INPUT;
Jiri Kosinad4bfa032010-01-29 15:03:36 +0100339 break;
340 case HID_OUTPUT_REPORT:
Alan Ott0ff17312011-01-18 03:04:40 -0500341 report_type = HIDP_TRANS_GET_REPORT | HIDP_DATA_RTYPE_OUPUT;
Jiri Kosinad4bfa032010-01-29 15:03:36 +0100342 break;
343 default:
344 return -EINVAL;
345 }
346
Alan Ott0ff17312011-01-18 03:04:40 -0500347 if (mutex_lock_interruptible(&session->report_mutex))
348 return -ERESTARTSYS;
349
350 /* Set up our wait, and send the report request to the device. */
351 session->waiting_report_type = report_type & HIDP_DATA_RTYPE_MASK;
352 session->waiting_report_number = numbered_reports ? report_number : -1;
353 set_bit(HIDP_WAITING_FOR_RETURN, &session->flags);
354 data[0] = report_number;
David Herrmann794d1752011-08-26 14:06:02 +0200355 ret = hidp_send_ctrl_message(hid->driver_data, report_type, data, 1);
356 if (ret)
357 goto err;
Alan Ott0ff17312011-01-18 03:04:40 -0500358
359 /* Wait for the return of the report. The returned report
360 gets put in session->report_return. */
361 while (test_bit(HIDP_WAITING_FOR_RETURN, &session->flags)) {
362 int res;
363
364 res = wait_event_interruptible_timeout(session->report_queue,
365 !test_bit(HIDP_WAITING_FOR_RETURN, &session->flags),
366 5*HZ);
367 if (res == 0) {
368 /* timeout */
David Herrmann794d1752011-08-26 14:06:02 +0200369 ret = -EIO;
370 goto err;
Alan Ott0ff17312011-01-18 03:04:40 -0500371 }
372 if (res < 0) {
373 /* signal */
David Herrmann794d1752011-08-26 14:06:02 +0200374 ret = -ERESTARTSYS;
375 goto err;
Alan Ott0ff17312011-01-18 03:04:40 -0500376 }
377 }
378
379 skb = session->report_return;
380 if (skb) {
381 len = skb->len < count ? skb->len : count;
382 memcpy(data, skb->data, len);
383
384 kfree_skb(skb);
385 session->report_return = NULL;
386 } else {
387 /* Device returned a HANDSHAKE, indicating protocol error. */
388 len = -EIO;
389 }
390
391 clear_bit(HIDP_WAITING_FOR_RETURN, &session->flags);
392 mutex_unlock(&session->report_mutex);
393
394 return len;
395
David Herrmann794d1752011-08-26 14:06:02 +0200396err:
Alan Ott0ff17312011-01-18 03:04:40 -0500397 clear_bit(HIDP_WAITING_FOR_RETURN, &session->flags);
398 mutex_unlock(&session->report_mutex);
David Herrmann794d1752011-08-26 14:06:02 +0200399 return ret;
Alan Ott0ff17312011-01-18 03:04:40 -0500400}
401
Linus Torvalds1da177e2005-04-16 15:20:36 -0700402static int hidp_output_raw_report(struct hid_device *hid, unsigned char *data, size_t count,
Jiri Kosina2da31932009-11-26 16:20:56 +0100403 unsigned char report_type)
404{
Alan Ott08254112011-01-18 03:04:38 -0500405 struct hidp_session *session = hid->driver_data;
406 int ret;
407
Jiri Kosinad4bfa032010-01-29 15:03:36 +0100408 switch (report_type) {
409 case HID_FEATURE_REPORT:
410 report_type = HIDP_TRANS_SET_REPORT | HIDP_DATA_RTYPE_FEATURE;
411 break;
412 case HID_OUTPUT_REPORT:
Antonio Ospite97e1efb2011-02-20 18:26:46 +0100413 report_type = HIDP_TRANS_SET_REPORT | HIDP_DATA_RTYPE_OUPUT;
Jiri Kosinad4bfa032010-01-29 15:03:36 +0100414 break;
415 default:
416 return -EINVAL;
417 }
418
Alan Ott08254112011-01-18 03:04:38 -0500419 if (mutex_lock_interruptible(&session->report_mutex))
420 return -ERESTARTSYS;
421
422 /* Set up our wait, and send the report request to the device. */
423 set_bit(HIDP_WAITING_FOR_SEND_ACK, &session->flags);
David Herrmann794d1752011-08-26 14:06:02 +0200424 ret = hidp_send_ctrl_message(hid->driver_data, report_type, data,
425 count);
426 if (ret)
Alan Ott08254112011-01-18 03:04:38 -0500427 goto err;
Alan Ott08254112011-01-18 03:04:38 -0500428
429 /* Wait for the ACK from the device. */
430 while (test_bit(HIDP_WAITING_FOR_SEND_ACK, &session->flags)) {
431 int res;
432
433 res = wait_event_interruptible_timeout(session->report_queue,
434 !test_bit(HIDP_WAITING_FOR_SEND_ACK, &session->flags),
435 10*HZ);
436 if (res == 0) {
437 /* timeout */
438 ret = -EIO;
439 goto err;
440 }
441 if (res < 0) {
442 /* signal */
443 ret = -ERESTARTSYS;
444 goto err;
445 }
446 }
447
448 if (!session->output_report_success) {
449 ret = -EIO;
450 goto err;
451 }
452
453 ret = count;
454
455err:
456 clear_bit(HIDP_WAITING_FOR_SEND_ACK, &session->flags);
457 mutex_unlock(&session->report_mutex);
458 return ret;
Jiri Kosina2da31932009-11-26 16:20:56 +0100459}
460
Linus Torvalds1da177e2005-04-16 15:20:36 -0700461static void hidp_idle_timeout(unsigned long arg)
462{
463 struct hidp_session *session = (struct hidp_session *) arg;
464
Peter Hurley7bb59df2011-06-30 13:53:53 -0400465 atomic_inc(&session->terminate);
466 wake_up_process(session->task);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700467}
468
Andrew Morton91f5cca2008-02-05 03:07:58 -0800469static void hidp_set_timer(struct hidp_session *session)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700470{
471 if (session->idle_to > 0)
472 mod_timer(&session->timer, jiffies + HZ * session->idle_to);
473}
474
475static inline void hidp_del_timer(struct hidp_session *session)
476{
477 if (session->idle_to > 0)
478 del_timer(&session->timer);
479}
480
Andrew Morton91f5cca2008-02-05 03:07:58 -0800481static void hidp_process_handshake(struct hidp_session *session,
482 unsigned char param)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700483{
484 BT_DBG("session %p param 0x%02x", session, param);
Alan Ott08254112011-01-18 03:04:38 -0500485 session->output_report_success = 0; /* default condition */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700486
487 switch (param) {
488 case HIDP_HSHK_SUCCESSFUL:
489 /* FIXME: Call into SET_ GET_ handlers here */
Alan Ott08254112011-01-18 03:04:38 -0500490 session->output_report_success = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700491 break;
492
493 case HIDP_HSHK_NOT_READY:
494 case HIDP_HSHK_ERR_INVALID_REPORT_ID:
495 case HIDP_HSHK_ERR_UNSUPPORTED_REQUEST:
496 case HIDP_HSHK_ERR_INVALID_PARAMETER:
Gustavo F. Padovanab88f712011-10-06 22:05:37 -0300497 if (test_and_clear_bit(HIDP_WAITING_FOR_RETURN, &session->flags))
Alan Ott0ff17312011-01-18 03:04:40 -0500498 wake_up_interruptible(&session->report_queue);
Gustavo F. Padovanab88f712011-10-06 22:05:37 -0300499
Linus Torvalds1da177e2005-04-16 15:20:36 -0700500 /* FIXME: Call into SET_ GET_ handlers here */
501 break;
502
503 case HIDP_HSHK_ERR_UNKNOWN:
504 break;
505
506 case HIDP_HSHK_ERR_FATAL:
507 /* Device requests a reboot, as this is the only way this error
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900508 * can be recovered. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700509 __hidp_send_ctrl_message(session,
510 HIDP_TRANS_HID_CONTROL | HIDP_CTRL_SOFT_RESET, NULL, 0);
511 break;
512
513 default:
514 __hidp_send_ctrl_message(session,
515 HIDP_TRANS_HANDSHAKE | HIDP_HSHK_ERR_INVALID_PARAMETER, NULL, 0);
516 break;
517 }
Alan Ott08254112011-01-18 03:04:38 -0500518
519 /* Wake up the waiting thread. */
Gustavo F. Padovanab88f712011-10-06 22:05:37 -0300520 if (test_and_clear_bit(HIDP_WAITING_FOR_SEND_ACK, &session->flags))
Alan Ott08254112011-01-18 03:04:38 -0500521 wake_up_interruptible(&session->report_queue);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700522}
523
Andrew Morton91f5cca2008-02-05 03:07:58 -0800524static void hidp_process_hid_control(struct hidp_session *session,
525 unsigned char param)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700526{
527 BT_DBG("session %p param 0x%02x", session, param);
528
Dave Youngeff001e2008-02-05 03:07:14 -0800529 if (param == HIDP_CTRL_VIRTUAL_CABLE_UNPLUG) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700530 /* Flush the transmit queues */
531 skb_queue_purge(&session->ctrl_transmit);
532 skb_queue_purge(&session->intr_transmit);
533
Peter Hurley7bb59df2011-06-30 13:53:53 -0400534 atomic_inc(&session->terminate);
535 wake_up_process(current);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700536 }
537}
538
Alan Ott0ff17312011-01-18 03:04:40 -0500539/* Returns true if the passed-in skb should be freed by the caller. */
540static int hidp_process_data(struct hidp_session *session, struct sk_buff *skb,
Andrew Morton91f5cca2008-02-05 03:07:58 -0800541 unsigned char param)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700542{
Alan Ott0ff17312011-01-18 03:04:40 -0500543 int done_with_skb = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700544 BT_DBG("session %p skb %p len %d param 0x%02x", session, skb, skb->len, param);
545
546 switch (param) {
547 case HIDP_DATA_RTYPE_INPUT:
548 hidp_set_timer(session);
549
550 if (session->input)
551 hidp_input_report(session, skb);
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100552
553 if (session->hid)
554 hid_input_report(session->hid, HID_INPUT_REPORT, skb->data, skb->len, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700555 break;
556
557 case HIDP_DATA_RTYPE_OTHER:
558 case HIDP_DATA_RTYPE_OUPUT:
559 case HIDP_DATA_RTYPE_FEATURE:
560 break;
561
562 default:
563 __hidp_send_ctrl_message(session,
564 HIDP_TRANS_HANDSHAKE | HIDP_HSHK_ERR_INVALID_PARAMETER, NULL, 0);
565 }
Alan Ott0ff17312011-01-18 03:04:40 -0500566
567 if (test_bit(HIDP_WAITING_FOR_RETURN, &session->flags) &&
568 param == session->waiting_report_type) {
569 if (session->waiting_report_number < 0 ||
570 session->waiting_report_number == skb->data[0]) {
571 /* hidp_get_raw_report() is waiting on this report. */
572 session->report_return = skb;
573 done_with_skb = 0;
574 clear_bit(HIDP_WAITING_FOR_RETURN, &session->flags);
575 wake_up_interruptible(&session->report_queue);
576 }
577 }
578
579 return done_with_skb;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700580}
581
Andrew Morton91f5cca2008-02-05 03:07:58 -0800582static void hidp_recv_ctrl_frame(struct hidp_session *session,
583 struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700584{
585 unsigned char hdr, type, param;
Alan Ott0ff17312011-01-18 03:04:40 -0500586 int free_skb = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700587
588 BT_DBG("session %p skb %p len %d", session, skb, skb->len);
589
590 hdr = skb->data[0];
591 skb_pull(skb, 1);
592
593 type = hdr & HIDP_HEADER_TRANS_MASK;
594 param = hdr & HIDP_HEADER_PARAM_MASK;
595
596 switch (type) {
597 case HIDP_TRANS_HANDSHAKE:
598 hidp_process_handshake(session, param);
599 break;
600
601 case HIDP_TRANS_HID_CONTROL:
602 hidp_process_hid_control(session, param);
603 break;
604
605 case HIDP_TRANS_DATA:
Alan Ott0ff17312011-01-18 03:04:40 -0500606 free_skb = hidp_process_data(session, skb, param);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700607 break;
608
609 default:
610 __hidp_send_ctrl_message(session,
611 HIDP_TRANS_HANDSHAKE | HIDP_HSHK_ERR_UNSUPPORTED_REQUEST, NULL, 0);
612 break;
613 }
614
Alan Ott0ff17312011-01-18 03:04:40 -0500615 if (free_skb)
616 kfree_skb(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700617}
618
Andrew Morton91f5cca2008-02-05 03:07:58 -0800619static void hidp_recv_intr_frame(struct hidp_session *session,
620 struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700621{
622 unsigned char hdr;
623
624 BT_DBG("session %p skb %p len %d", session, skb, skb->len);
625
626 hdr = skb->data[0];
627 skb_pull(skb, 1);
628
629 if (hdr == (HIDP_TRANS_DATA | HIDP_DATA_RTYPE_INPUT)) {
630 hidp_set_timer(session);
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100631
Linus Torvalds1da177e2005-04-16 15:20:36 -0700632 if (session->input)
633 hidp_input_report(session, skb);
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100634
635 if (session->hid) {
636 hid_input_report(session->hid, HID_INPUT_REPORT, skb->data, skb->len, 1);
637 BT_DBG("report len %d", skb->len);
638 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700639 } else {
640 BT_DBG("Unsupported protocol header 0x%02x", hdr);
641 }
642
643 kfree_skb(skb);
644}
645
646static int hidp_send_frame(struct socket *sock, unsigned char *data, int len)
647{
648 struct kvec iv = { data, len };
649 struct msghdr msg;
650
651 BT_DBG("sock %p data %p len %d", sock, data, len);
652
653 if (!len)
654 return 0;
655
656 memset(&msg, 0, sizeof(msg));
657
658 return kernel_sendmsg(sock, &msg, &iv, 1, len);
659}
660
Gustavo F. Padovan679344e2011-10-06 20:51:37 -0300661static void hidp_process_intr_transmit(struct hidp_session *session)
662{
663 struct sk_buff *skb;
664
665 BT_DBG("session %p", session);
666
667 while ((skb = skb_dequeue(&session->intr_transmit))) {
668 if (hidp_send_frame(session->intr_sock, skb->data, skb->len) < 0) {
669 skb_queue_head(&session->intr_transmit, skb);
670 break;
671 }
672
673 hidp_set_timer(session);
674 kfree_skb(skb);
675 }
676}
677
678static void hidp_process_ctrl_transmit(struct hidp_session *session)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700679{
680 struct sk_buff *skb;
681
682 BT_DBG("session %p", session);
683
684 while ((skb = skb_dequeue(&session->ctrl_transmit))) {
685 if (hidp_send_frame(session->ctrl_sock, skb->data, skb->len) < 0) {
686 skb_queue_head(&session->ctrl_transmit, skb);
687 break;
688 }
689
690 hidp_set_timer(session);
691 kfree_skb(skb);
692 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700693}
694
695static int hidp_session(void *arg)
696{
697 struct hidp_session *session = arg;
698 struct sock *ctrl_sk = session->ctrl_sock->sk;
699 struct sock *intr_sk = session->intr_sock->sk;
700 struct sk_buff *skb;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700701 wait_queue_t ctrl_wait, intr_wait;
702
703 BT_DBG("session %p", session);
704
Linus Torvalds1da177e2005-04-16 15:20:36 -0700705 set_user_nice(current, -15);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700706
707 init_waitqueue_entry(&ctrl_wait, current);
708 init_waitqueue_entry(&intr_wait, current);
Eric Dumazetaa395142010-04-20 13:03:51 +0000709 add_wait_queue(sk_sleep(ctrl_sk), &ctrl_wait);
710 add_wait_queue(sk_sleep(intr_sk), &intr_wait);
Alan Ott0f69dca2011-01-18 03:04:37 -0500711 session->waiting_for_startup = 0;
712 wake_up_interruptible(&session->startup_queue);
Peter Hurley7bb59df2011-06-30 13:53:53 -0400713 set_current_state(TASK_INTERRUPTIBLE);
714 while (!atomic_read(&session->terminate)) {
Szymon Janc17f09a72011-03-21 14:20:01 +0100715 if (ctrl_sk->sk_state != BT_CONNECTED ||
716 intr_sk->sk_state != BT_CONNECTED)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700717 break;
718
Linus Torvalds1da177e2005-04-16 15:20:36 -0700719 while ((skb = skb_dequeue(&intr_sk->sk_receive_queue))) {
720 skb_orphan(skb);
Mat Martineau44935722011-07-22 14:53:58 -0700721 if (!skb_linearize(skb))
722 hidp_recv_intr_frame(session, skb);
723 else
724 kfree_skb(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700725 }
726
Gustavo F. Padovan679344e2011-10-06 20:51:37 -0300727 hidp_process_intr_transmit(session);
728
Gustavo F. Padovandc0da5c2011-10-06 18:02:13 -0300729 while ((skb = skb_dequeue(&ctrl_sk->sk_receive_queue))) {
730 skb_orphan(skb);
731 if (!skb_linearize(skb))
732 hidp_recv_ctrl_frame(session, skb);
733 else
734 kfree_skb(skb);
735 }
736
Gustavo F. Padovan679344e2011-10-06 20:51:37 -0300737 hidp_process_ctrl_transmit(session);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700738
739 schedule();
Peter Hurley7bb59df2011-06-30 13:53:53 -0400740 set_current_state(TASK_INTERRUPTIBLE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700741 }
742 set_current_state(TASK_RUNNING);
Eric Dumazetaa395142010-04-20 13:03:51 +0000743 remove_wait_queue(sk_sleep(intr_sk), &intr_wait);
744 remove_wait_queue(sk_sleep(ctrl_sk), &ctrl_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700745
David Herrmann794d1752011-08-26 14:06:02 +0200746 clear_bit(HIDP_WAITING_FOR_SEND_ACK, &session->flags);
747 clear_bit(HIDP_WAITING_FOR_RETURN, &session->flags);
748 wake_up_interruptible(&session->report_queue);
749
Linus Torvalds1da177e2005-04-16 15:20:36 -0700750 down_write(&hidp_session_sem);
751
752 hidp_del_timer(session);
753
Linus Torvalds1da177e2005-04-16 15:20:36 -0700754 if (session->input) {
755 input_unregister_device(session->input);
Dmitry Torokhov34abf912005-09-15 02:01:40 -0500756 session->input = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700757 }
758
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100759 if (session->hid) {
Jiri Slaby85cdaf52008-05-16 11:49:15 +0200760 hid_destroy_device(session->hid);
Marcel Holtmannedad6382009-08-22 14:22:15 -0700761 session->hid = NULL;
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100762 }
763
Marcel Holtmannec8dab32008-07-14 20:13:53 +0200764 /* Wakeup user-space polling for socket errors */
765 session->intr_sock->sk->sk_err = EUNATCH;
766 session->ctrl_sock->sk->sk_err = EUNATCH;
767
768 hidp_schedule(session);
769
David Woodhouse1c398582007-07-07 14:58:39 -0400770 fput(session->intr_sock->file);
771
Eric Dumazetaa395142010-04-20 13:03:51 +0000772 wait_event_timeout(*(sk_sleep(ctrl_sk)),
David Woodhouse1c398582007-07-07 14:58:39 -0400773 (ctrl_sk->sk_state == BT_CLOSED), msecs_to_jiffies(500));
774
775 fput(session->ctrl_sock->file);
776
777 __hidp_unlink_session(session);
778
Linus Torvalds1da177e2005-04-16 15:20:36 -0700779 up_write(&hidp_session_sem);
780
Peter Hurley1c97e942011-08-05 10:51:34 -0400781 kfree(session->rd_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700782 kfree(session);
783 return 0;
784}
785
Gustavo F. Padovan3e90dc82011-10-07 01:29:51 -0300786static struct hci_conn *hidp_get_connection(struct hidp_session *session)
Marcel Holtmann0a85b962006-07-06 13:09:02 +0200787{
788 bdaddr_t *src = &bt_sk(session->ctrl_sock->sk)->src;
789 bdaddr_t *dst = &bt_sk(session->ctrl_sock->sk)->dst;
Peter Hurley1785dbf2011-08-30 11:53:35 -0400790 struct hci_conn *conn;
Marcel Holtmann0a85b962006-07-06 13:09:02 +0200791 struct hci_dev *hdev;
Marcel Holtmann0a85b962006-07-06 13:09:02 +0200792
793 hdev = hci_get_route(dst, src);
794 if (!hdev)
795 return NULL;
796
Peter Hurley1785dbf2011-08-30 11:53:35 -0400797 hci_dev_lock_bh(hdev);
798 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, dst);
799 if (conn)
800 hci_conn_hold_device(conn);
801 hci_dev_unlock_bh(hdev);
Marcel Holtmann0a85b962006-07-06 13:09:02 +0200802
803 hci_dev_put(hdev);
804
Peter Hurley1785dbf2011-08-30 11:53:35 -0400805 return conn;
Marcel Holtmann0a85b962006-07-06 13:09:02 +0200806}
807
Andrew Morton91f5cca2008-02-05 03:07:58 -0800808static int hidp_setup_input(struct hidp_session *session,
809 struct hidp_connadd_req *req)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700810{
Jiri Slabyc500c972008-05-16 11:49:16 +0200811 struct input_dev *input;
Gustavo F. Padovan3415a5f2011-10-06 21:17:32 -0300812 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700813
Jiri Slabyc500c972008-05-16 11:49:16 +0200814 input = input_allocate_device();
815 if (!input)
816 return -ENOMEM;
817
818 session->input = input;
819
Marcel Holtmann5be39462007-05-09 09:15:30 +0200820 input_set_drvdata(input, session);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700821
Dmitry Torokhov34abf912005-09-15 02:01:40 -0500822 input->name = "Bluetooth HID Boot Protocol Device";
823
Linus Torvalds1da177e2005-04-16 15:20:36 -0700824 input->id.bustype = BUS_BLUETOOTH;
825 input->id.vendor = req->vendor;
826 input->id.product = req->product;
827 input->id.version = req->version;
828
829 if (req->subclass & 0x40) {
830 set_bit(EV_KEY, input->evbit);
831 set_bit(EV_LED, input->evbit);
832 set_bit(EV_REP, input->evbit);
833
834 set_bit(LED_NUML, input->ledbit);
835 set_bit(LED_CAPSL, input->ledbit);
836 set_bit(LED_SCROLLL, input->ledbit);
837 set_bit(LED_COMPOSE, input->ledbit);
838 set_bit(LED_KANA, input->ledbit);
839
840 for (i = 0; i < sizeof(hidp_keycode); i++)
841 set_bit(hidp_keycode[i], input->keybit);
842 clear_bit(0, input->keybit);
843 }
844
845 if (req->subclass & 0x80) {
Jiri Slaby7b19ada2007-10-18 23:40:32 -0700846 input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL);
847 input->keybit[BIT_WORD(BTN_MOUSE)] = BIT_MASK(BTN_LEFT) |
848 BIT_MASK(BTN_RIGHT) | BIT_MASK(BTN_MIDDLE);
849 input->relbit[0] = BIT_MASK(REL_X) | BIT_MASK(REL_Y);
850 input->keybit[BIT_WORD(BTN_MOUSE)] |= BIT_MASK(BTN_SIDE) |
851 BIT_MASK(BTN_EXTRA);
852 input->relbit[0] |= BIT_MASK(REL_WHEEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700853 }
854
Peter Hurley1785dbf2011-08-30 11:53:35 -0400855 input->dev.parent = &session->conn->dev;
Marcel Holtmann0a85b962006-07-06 13:09:02 +0200856
Linus Torvalds1da177e2005-04-16 15:20:36 -0700857 input->event = hidp_input_event;
858
Marcel Holtmannedad6382009-08-22 14:22:15 -0700859 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700860}
861
Marcel Holtmannf5ffd462007-02-17 23:58:53 +0100862static int hidp_open(struct hid_device *hid)
863{
864 return 0;
865}
866
867static void hidp_close(struct hid_device *hid)
868{
869}
870
Jiri Slabyc500c972008-05-16 11:49:16 +0200871static int hidp_parse(struct hid_device *hid)
872{
873 struct hidp_session *session = hid->driver_data;
Jiri Slabyc500c972008-05-16 11:49:16 +0200874
Michael Poole15c697c2010-02-05 12:23:43 -0500875 return hid_parse_report(session->hid, session->rd_data,
876 session->rd_size);
Jiri Slabyc500c972008-05-16 11:49:16 +0200877}
878
879static int hidp_start(struct hid_device *hid)
880{
881 struct hidp_session *session = hid->driver_data;
882 struct hid_report *report;
883
David Herrmann142c69c2011-08-26 13:27:12 +0200884 if (hid->quirks & HID_QUIRK_NO_INIT_REPORTS)
885 return 0;
886
Jiri Slabyc500c972008-05-16 11:49:16 +0200887 list_for_each_entry(report, &hid->report_enum[HID_INPUT_REPORT].
888 report_list, list)
889 hidp_send_report(session, report);
890
891 list_for_each_entry(report, &hid->report_enum[HID_FEATURE_REPORT].
892 report_list, list)
893 hidp_send_report(session, report);
894
Jiri Slabyc500c972008-05-16 11:49:16 +0200895 return 0;
896}
897
898static void hidp_stop(struct hid_device *hid)
899{
900 struct hidp_session *session = hid->driver_data;
901
902 skb_queue_purge(&session->ctrl_transmit);
903 skb_queue_purge(&session->intr_transmit);
904
Jiri Slabyc500c972008-05-16 11:49:16 +0200905 hid->claimed = 0;
906}
907
908static struct hid_ll_driver hidp_hid_driver = {
909 .parse = hidp_parse,
910 .start = hidp_start,
911 .stop = hidp_stop,
912 .open = hidp_open,
913 .close = hidp_close,
914 .hidinput_input_event = hidp_hidinput_event,
915};
916
Alan Ott0f69dca2011-01-18 03:04:37 -0500917/* This function sets up the hid device. It does not add it
918 to the HID system. That is done in hidp_add_connection(). */
Jiri Slaby85cdaf52008-05-16 11:49:15 +0200919static int hidp_setup_hid(struct hidp_session *session,
Andrew Morton91f5cca2008-02-05 03:07:58 -0800920 struct hidp_connadd_req *req)
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100921{
Jiri Slabyc500c972008-05-16 11:49:16 +0200922 struct hid_device *hid;
Marcel Holtmannedad6382009-08-22 14:22:15 -0700923 int err;
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100924
Michael Poole15c697c2010-02-05 12:23:43 -0500925 session->rd_data = kzalloc(req->rd_size, GFP_KERNEL);
926 if (!session->rd_data)
927 return -ENOMEM;
928
929 if (copy_from_user(session->rd_data, req->rd_data, req->rd_size)) {
930 err = -EFAULT;
931 goto fault;
932 }
933 session->rd_size = req->rd_size;
934
Jiri Slabyc500c972008-05-16 11:49:16 +0200935 hid = hid_allocate_device();
Michael Poole15c697c2010-02-05 12:23:43 -0500936 if (IS_ERR(hid)) {
937 err = PTR_ERR(hid);
938 goto fault;
939 }
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100940
Jiri Slabyc500c972008-05-16 11:49:16 +0200941 session->hid = hid;
Michael Poole15c697c2010-02-05 12:23:43 -0500942
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100943 hid->driver_data = session;
944
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100945 hid->bus = BUS_BLUETOOTH;
946 hid->vendor = req->vendor;
947 hid->product = req->product;
948 hid->version = req->version;
Jiri Slabyc500c972008-05-16 11:49:16 +0200949 hid->country = req->country;
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100950
951 strncpy(hid->name, req->name, 128);
Gustavo F. Padovand6b2eb22010-09-03 18:29:46 -0300952 strncpy(hid->phys, batostr(&bt_sk(session->ctrl_sock->sk)->src), 64);
953 strncpy(hid->uniq, batostr(&bt_sk(session->ctrl_sock->sk)->dst), 64);
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100954
Peter Hurley1785dbf2011-08-30 11:53:35 -0400955 hid->dev.parent = &session->conn->dev;
Jiri Slabyc500c972008-05-16 11:49:16 +0200956 hid->ll_driver = &hidp_hid_driver;
Jiri Slaby85cdaf52008-05-16 11:49:15 +0200957
Alan Ott0ff17312011-01-18 03:04:40 -0500958 hid->hid_get_raw_report = hidp_get_raw_report;
Jiri Kosina2da31932009-11-26 16:20:56 +0100959 hid->hid_output_raw_report = hidp_output_raw_report;
960
Jiri Slabyc500c972008-05-16 11:49:16 +0200961 return 0;
Marcel Holtmannedad6382009-08-22 14:22:15 -0700962
Michael Poole15c697c2010-02-05 12:23:43 -0500963fault:
964 kfree(session->rd_data);
965 session->rd_data = NULL;
966
Marcel Holtmannedad6382009-08-22 14:22:15 -0700967 return err;
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100968}
969
Linus Torvalds1da177e2005-04-16 15:20:36 -0700970int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock, struct socket *intr_sock)
971{
972 struct hidp_session *session, *s;
Szymon Jancaabf6f82011-04-05 15:37:45 +0200973 int vendor, product;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700974 int err;
975
976 BT_DBG("");
977
978 if (bacmp(&bt_sk(ctrl_sock->sk)->src, &bt_sk(intr_sock->sk)->src) ||
979 bacmp(&bt_sk(ctrl_sock->sk)->dst, &bt_sk(intr_sock->sk)->dst))
980 return -ENOTUNIQ;
981
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100982 BT_DBG("rd_data %p rd_size %d", req->rd_data, req->rd_size);
983
Linus Torvalds1da177e2005-04-16 15:20:36 -0700984 down_write(&hidp_session_sem);
985
986 s = __hidp_get_session(&bt_sk(ctrl_sock->sk)->dst);
987 if (s && s->state == BT_CONNECTED) {
Gustavo F. Padovan81b25cd2011-10-06 23:32:29 -0300988 up_write(&hidp_session_sem);
989 return -EEXIST;
990 }
991
992 session = kzalloc(sizeof(struct hidp_session), GFP_KERNEL);
993 if (!session) {
994 up_write(&hidp_session_sem);
995 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700996 }
997
Gustavo F. Padovan3e90dc82011-10-07 01:29:51 -0300998 session->conn = hidp_get_connection(session);
Peter Hurley1785dbf2011-08-30 11:53:35 -0400999 if (!session->conn) {
1000 err = -ENOTCONN;
1001 goto failed;
1002 }
1003
Linus Torvalds1da177e2005-04-16 15:20:36 -07001004 bacpy(&session->bdaddr, &bt_sk(ctrl_sock->sk)->dst);
1005
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03001006 session->ctrl_mtu = min_t(uint, l2cap_pi(ctrl_sock->sk)->chan->omtu,
1007 l2cap_pi(ctrl_sock->sk)->chan->imtu);
1008 session->intr_mtu = min_t(uint, l2cap_pi(intr_sock->sk)->chan->omtu,
1009 l2cap_pi(intr_sock->sk)->chan->imtu);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001010
1011 BT_DBG("ctrl mtu %d intr mtu %d", session->ctrl_mtu, session->intr_mtu);
1012
1013 session->ctrl_sock = ctrl_sock;
1014 session->intr_sock = intr_sock;
1015 session->state = BT_CONNECTED;
1016
Pavel Emelyanovb24b8a22008-01-23 21:20:07 -08001017 setup_timer(&session->timer, hidp_idle_timeout, (unsigned long)session);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001018
1019 skb_queue_head_init(&session->ctrl_transmit);
1020 skb_queue_head_init(&session->intr_transmit);
1021
Alan Ott0ff17312011-01-18 03:04:40 -05001022 mutex_init(&session->report_mutex);
1023 init_waitqueue_head(&session->report_queue);
Alan Ott0f69dca2011-01-18 03:04:37 -05001024 init_waitqueue_head(&session->startup_queue);
1025 session->waiting_for_startup = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001026 session->flags = req->flags & (1 << HIDP_BLUETOOTH_VENDOR_ID);
1027 session->idle_to = req->idle_to;
1028
Peter Hurley1785dbf2011-08-30 11:53:35 -04001029 __hidp_link_session(session);
1030
Jiri Slabyc500c972008-05-16 11:49:16 +02001031 if (req->rd_size > 0) {
Jiri Slaby85cdaf52008-05-16 11:49:15 +02001032 err = hidp_setup_hid(session, req);
Gustavo F. Padovan192893c2011-10-06 21:27:56 -03001033 if (err)
Marcel Holtmannedad6382009-08-22 14:22:15 -07001034 goto purge;
Jiri Slabyc500c972008-05-16 11:49:16 +02001035 }
1036
1037 if (!session->hid) {
1038 err = hidp_setup_input(session, req);
1039 if (err < 0)
Marcel Holtmannedad6382009-08-22 14:22:15 -07001040 goto purge;
Jiri Slaby85cdaf52008-05-16 11:49:15 +02001041 }
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +01001042
Linus Torvalds1da177e2005-04-16 15:20:36 -07001043 hidp_set_timer(session);
1044
Szymon Jancaabf6f82011-04-05 15:37:45 +02001045 if (session->hid) {
1046 vendor = session->hid->vendor;
1047 product = session->hid->product;
1048 } else if (session->input) {
1049 vendor = session->input->id.vendor;
1050 product = session->input->id.product;
1051 } else {
1052 vendor = 0x0000;
1053 product = 0x0000;
1054 }
1055
1056 session->task = kthread_run(hidp_session, session, "khidpd_%04x%04x",
1057 vendor, product);
1058 if (IS_ERR(session->task)) {
1059 err = PTR_ERR(session->task);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001060 goto unlink;
Szymon Jancaabf6f82011-04-05 15:37:45 +02001061 }
1062
Alan Ott0f69dca2011-01-18 03:04:37 -05001063 while (session->waiting_for_startup) {
1064 wait_event_interruptible(session->startup_queue,
1065 !session->waiting_for_startup);
1066 }
1067
Gustavo F. Padovan3415a5f2011-10-06 21:17:32 -03001068 if (session->hid)
1069 err = hid_add_device(session->hid);
1070 else
1071 err = input_register_device(session->input);
1072
Peter Hurleye9d5cb52011-08-05 10:51:26 -04001073 if (err < 0) {
1074 atomic_inc(&session->terminate);
1075 wake_up_process(session->task);
1076 up_write(&hidp_session_sem);
1077 return err;
1078 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001079
1080 if (session->input) {
1081 hidp_send_ctrl_message(session,
1082 HIDP_TRANS_SET_PROTOCOL | HIDP_PROTO_BOOT, NULL, 0);
1083 session->flags |= (1 << HIDP_BOOT_PROTOCOL_MODE);
1084
1085 session->leds = 0xff;
1086 hidp_input_event(session->input, EV_LED, 0, 0);
1087 }
1088
1089 up_write(&hidp_session_sem);
1090 return 0;
1091
1092unlink:
1093 hidp_del_timer(session);
1094
Marcel Holtmannedad6382009-08-22 14:22:15 -07001095 if (session->input) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001096 input_unregister_device(session->input);
Marcel Holtmannedad6382009-08-22 14:22:15 -07001097 session->input = NULL;
1098 }
1099
1100 if (session->hid) {
Jiri Slaby85cdaf52008-05-16 11:49:15 +02001101 hid_destroy_device(session->hid);
Marcel Holtmannedad6382009-08-22 14:22:15 -07001102 session->hid = NULL;
1103 }
1104
Michael Poole15c697c2010-02-05 12:23:43 -05001105 kfree(session->rd_data);
1106 session->rd_data = NULL;
1107
Marcel Holtmannedad6382009-08-22 14:22:15 -07001108purge:
Peter Hurley1785dbf2011-08-30 11:53:35 -04001109 __hidp_unlink_session(session);
1110
Jiri Slabyc500c972008-05-16 11:49:16 +02001111 skb_queue_purge(&session->ctrl_transmit);
1112 skb_queue_purge(&session->intr_transmit);
Marcel Holtmannedad6382009-08-22 14:22:15 -07001113
Jiri Slabyc500c972008-05-16 11:49:16 +02001114failed:
1115 up_write(&hidp_session_sem);
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +01001116
Linus Torvalds1da177e2005-04-16 15:20:36 -07001117 kfree(session);
1118 return err;
1119}
1120
1121int hidp_del_connection(struct hidp_conndel_req *req)
1122{
1123 struct hidp_session *session;
1124 int err = 0;
1125
1126 BT_DBG("");
1127
1128 down_read(&hidp_session_sem);
1129
1130 session = __hidp_get_session(&req->bdaddr);
1131 if (session) {
1132 if (req->flags & (1 << HIDP_VIRTUAL_CABLE_UNPLUG)) {
1133 hidp_send_ctrl_message(session,
1134 HIDP_TRANS_HID_CONTROL | HIDP_CTRL_VIRTUAL_CABLE_UNPLUG, NULL, 0);
1135 } else {
1136 /* Flush the transmit queues */
1137 skb_queue_purge(&session->ctrl_transmit);
1138 skb_queue_purge(&session->intr_transmit);
1139
Peter Hurley7bb59df2011-06-30 13:53:53 -04001140 atomic_inc(&session->terminate);
1141 wake_up_process(session->task);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001142 }
1143 } else
1144 err = -ENOENT;
1145
1146 up_read(&hidp_session_sem);
1147 return err;
1148}
1149
1150int hidp_get_connlist(struct hidp_connlist_req *req)
1151{
Gustavo F. Padovancd11cdd2011-10-06 17:35:31 -03001152 struct hidp_session *session;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001153 int err = 0, n = 0;
1154
1155 BT_DBG("");
1156
1157 down_read(&hidp_session_sem);
1158
Gustavo F. Padovancd11cdd2011-10-06 17:35:31 -03001159 list_for_each_entry(session, &hidp_session_list, list) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001160 struct hidp_conninfo ci;
1161
Linus Torvalds1da177e2005-04-16 15:20:36 -07001162 __hidp_copy_session(session, &ci);
1163
1164 if (copy_to_user(req->ci, &ci, sizeof(ci))) {
1165 err = -EFAULT;
1166 break;
1167 }
1168
1169 if (++n >= req->cnum)
1170 break;
1171
1172 req->ci++;
1173 }
1174 req->cnum = n;
1175
1176 up_read(&hidp_session_sem);
1177 return err;
1178}
1179
1180int hidp_get_conninfo(struct hidp_conninfo *ci)
1181{
1182 struct hidp_session *session;
1183 int err = 0;
1184
1185 down_read(&hidp_session_sem);
1186
1187 session = __hidp_get_session(&ci->bdaddr);
1188 if (session)
1189 __hidp_copy_session(session, ci);
1190 else
1191 err = -ENOENT;
1192
1193 up_read(&hidp_session_sem);
1194 return err;
1195}
1196
Jiri Slaby85cdaf52008-05-16 11:49:15 +02001197static const struct hid_device_id hidp_table[] = {
1198 { HID_BLUETOOTH_DEVICE(HID_ANY_ID, HID_ANY_ID) },
1199 { }
1200};
1201
1202static struct hid_driver hidp_driver = {
1203 .name = "generic-bluetooth",
1204 .id_table = hidp_table,
1205};
1206
Linus Torvalds1da177e2005-04-16 15:20:36 -07001207static int __init hidp_init(void)
1208{
Jiri Slaby85cdaf52008-05-16 11:49:15 +02001209 int ret;
1210
Linus Torvalds1da177e2005-04-16 15:20:36 -07001211 BT_INFO("HIDP (Human Interface Emulation) ver %s", VERSION);
1212
Jiri Slaby85cdaf52008-05-16 11:49:15 +02001213 ret = hid_register_driver(&hidp_driver);
1214 if (ret)
1215 goto err;
1216
1217 ret = hidp_init_sockets();
1218 if (ret)
1219 goto err_drv;
1220
1221 return 0;
1222err_drv:
1223 hid_unregister_driver(&hidp_driver);
1224err:
1225 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001226}
1227
1228static void __exit hidp_exit(void)
1229{
1230 hidp_cleanup_sockets();
Jiri Slaby85cdaf52008-05-16 11:49:15 +02001231 hid_unregister_driver(&hidp_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001232}
1233
1234module_init(hidp_init);
1235module_exit(hidp_exit);
1236
1237MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
1238MODULE_DESCRIPTION("Bluetooth HIDP ver " VERSION);
1239MODULE_VERSION(VERSION);
1240MODULE_LICENSE("GPL");
1241MODULE_ALIAS("bt-proto-6");