blob: a9f7afb6ee3501041661f37818df054bd37931fb [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>
39#include <net/sock.h>
40
41#include <linux/input.h>
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +010042#include <linux/hid.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070043
44#include <net/bluetooth/bluetooth.h>
Marcel Holtmann0a85b962006-07-06 13:09:02 +020045#include <net/bluetooth/hci_core.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070046#include <net/bluetooth/l2cap.h>
47
48#include "hidp.h"
49
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +010050#define VERSION "1.2"
Linus Torvalds1da177e2005-04-16 15:20:36 -070051
52static DECLARE_RWSEM(hidp_session_sem);
53static LIST_HEAD(hidp_session_list);
54
55static unsigned char hidp_keycode[256] = {
56 0, 0, 0, 0, 30, 48, 46, 32, 18, 33, 34, 35, 23, 36, 37, 38,
57 50, 49, 24, 25, 16, 19, 31, 20, 22, 47, 17, 45, 21, 44, 2, 3,
58 4, 5, 6, 7, 8, 9, 10, 11, 28, 1, 14, 15, 57, 12, 13, 26,
59 27, 43, 43, 39, 40, 41, 51, 52, 53, 58, 59, 60, 61, 62, 63, 64,
60 65, 66, 67, 68, 87, 88, 99, 70,119,110,102,104,111,107,109,106,
61 105,108,103, 69, 98, 55, 74, 78, 96, 79, 80, 81, 75, 76, 77, 71,
62 72, 73, 82, 83, 86,127,116,117,183,184,185,186,187,188,189,190,
63 191,192,193,194,134,138,130,132,128,129,131,137,133,135,136,113,
64 115,114, 0, 0, 0,121, 0, 89, 93,124, 92, 94, 95, 0, 0, 0,
65 122,123, 90, 91, 85, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
66 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
67 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
68 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
69 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
70 29, 42, 56,125, 97, 54,100,126,164,166,165,163,161,115,114,113,
71 150,158,159,128,136,177,178,176,142,152,173,140
72};
73
74static unsigned char hidp_mkeyspat[] = { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 };
75
76static struct hidp_session *__hidp_get_session(bdaddr_t *bdaddr)
77{
78 struct hidp_session *session;
79 struct list_head *p;
80
81 BT_DBG("");
82
83 list_for_each(p, &hidp_session_list) {
84 session = list_entry(p, struct hidp_session, list);
85 if (!bacmp(bdaddr, &session->bdaddr))
86 return session;
87 }
88 return NULL;
89}
90
91static void __hidp_link_session(struct hidp_session *session)
92{
93 __module_get(THIS_MODULE);
94 list_add(&session->list, &hidp_session_list);
95}
96
97static void __hidp_unlink_session(struct hidp_session *session)
98{
99 list_del(&session->list);
100 module_put(THIS_MODULE);
101}
102
103static void __hidp_copy_session(struct hidp_session *session, struct hidp_conninfo *ci)
104{
105 bacpy(&ci->bdaddr, &session->bdaddr);
106
107 ci->flags = session->flags;
108 ci->state = session->state;
109
110 ci->vendor = 0x0000;
111 ci->product = 0x0000;
112 ci->version = 0x0000;
113 memset(ci->name, 0, 128);
114
115 if (session->input) {
116 ci->vendor = session->input->id.vendor;
117 ci->product = session->input->id.product;
118 ci->version = session->input->id.version;
119 if (session->input->name)
120 strncpy(ci->name, session->input->name, 128);
121 else
122 strncpy(ci->name, "HID Boot Device", 128);
123 }
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100124
125 if (session->hid) {
126 ci->vendor = session->hid->vendor;
127 ci->product = session->hid->product;
128 ci->version = session->hid->version;
129 strncpy(ci->name, session->hid->name, 128);
130 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700131}
132
Andrew Morton91f5cca2008-02-05 03:07:58 -0800133static int hidp_queue_event(struct hidp_session *session, struct input_dev *dev,
134 unsigned int type, unsigned int code, int value)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700135{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700136 unsigned char newleds;
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100137 struct sk_buff *skb;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700138
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100139 BT_DBG("session %p type %d code %d value %d", session, type, code, value);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700140
141 if (type != EV_LED)
142 return -1;
143
144 newleds = (!!test_bit(LED_KANA, dev->led) << 3) |
145 (!!test_bit(LED_COMPOSE, dev->led) << 3) |
146 (!!test_bit(LED_SCROLLL, dev->led) << 2) |
147 (!!test_bit(LED_CAPSL, dev->led) << 1) |
148 (!!test_bit(LED_NUML, dev->led));
149
150 if (session->leds == newleds)
151 return 0;
152
153 session->leds = newleds;
154
155 if (!(skb = alloc_skb(3, GFP_ATOMIC))) {
156 BT_ERR("Can't allocate memory for new frame");
157 return -ENOMEM;
158 }
159
160 *skb_put(skb, 1) = HIDP_TRANS_DATA | HIDP_DATA_RTYPE_OUPUT;
161 *skb_put(skb, 1) = 0x01;
162 *skb_put(skb, 1) = newleds;
163
164 skb_queue_tail(&session->intr_transmit, skb);
165
166 hidp_schedule(session);
167
168 return 0;
169}
170
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100171static int hidp_hidinput_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
172{
Marcel Holtmann5be39462007-05-09 09:15:30 +0200173 struct hid_device *hid = input_get_drvdata(dev);
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100174 struct hidp_session *session = hid->driver_data;
175
176 return hidp_queue_event(session, dev, type, code, value);
177}
178
179static int hidp_input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
180{
Marcel Holtmann5be39462007-05-09 09:15:30 +0200181 struct hidp_session *session = input_get_drvdata(dev);
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100182
183 return hidp_queue_event(session, dev, type, code, value);
184}
185
Linus Torvalds1da177e2005-04-16 15:20:36 -0700186static void hidp_input_report(struct hidp_session *session, struct sk_buff *skb)
187{
188 struct input_dev *dev = session->input;
189 unsigned char *keys = session->keys;
190 unsigned char *udata = skb->data + 1;
191 signed char *sdata = skb->data + 1;
192 int i, size = skb->len - 1;
193
194 switch (skb->data[0]) {
195 case 0x01: /* Keyboard report */
196 for (i = 0; i < 8; i++)
197 input_report_key(dev, hidp_keycode[i + 224], (udata[0] >> i) & 1);
198
199 /* If all the key codes have been set to 0x01, it means
200 * too many keys were pressed at the same time. */
201 if (!memcmp(udata + 2, hidp_mkeyspat, 6))
202 break;
203
204 for (i = 2; i < 8; i++) {
205 if (keys[i] > 3 && memscan(udata + 2, keys[i], 6) == udata + 8) {
206 if (hidp_keycode[keys[i]])
207 input_report_key(dev, hidp_keycode[keys[i]], 0);
208 else
209 BT_ERR("Unknown key (scancode %#x) released.", keys[i]);
210 }
211
212 if (udata[i] > 3 && memscan(keys + 2, udata[i], 6) == keys + 8) {
213 if (hidp_keycode[udata[i]])
214 input_report_key(dev, hidp_keycode[udata[i]], 1);
215 else
216 BT_ERR("Unknown key (scancode %#x) pressed.", udata[i]);
217 }
218 }
219
220 memcpy(keys, udata, 8);
221 break;
222
223 case 0x02: /* Mouse report */
224 input_report_key(dev, BTN_LEFT, sdata[0] & 0x01);
225 input_report_key(dev, BTN_RIGHT, sdata[0] & 0x02);
226 input_report_key(dev, BTN_MIDDLE, sdata[0] & 0x04);
227 input_report_key(dev, BTN_SIDE, sdata[0] & 0x08);
228 input_report_key(dev, BTN_EXTRA, sdata[0] & 0x10);
229
230 input_report_rel(dev, REL_X, sdata[1]);
231 input_report_rel(dev, REL_Y, sdata[2]);
232
233 if (size > 3)
234 input_report_rel(dev, REL_WHEEL, sdata[3]);
235 break;
236 }
237
238 input_sync(dev);
239}
240
Andrew Morton91f5cca2008-02-05 03:07:58 -0800241static int hidp_queue_report(struct hidp_session *session,
242 unsigned char *data, int size)
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100243{
244 struct sk_buff *skb;
245
Dave Young6792b5e2007-10-20 14:15:39 +0200246 BT_DBG("session %p hid %p data %p size %d", session, session->hid, data, size);
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100247
248 if (!(skb = alloc_skb(size + 1, GFP_ATOMIC))) {
249 BT_ERR("Can't allocate memory for new frame");
250 return -ENOMEM;
251 }
252
253 *skb_put(skb, 1) = 0xa2;
254 if (size > 0)
255 memcpy(skb_put(skb, size), data, size);
256
257 skb_queue_tail(&session->intr_transmit, skb);
258
259 hidp_schedule(session);
260
261 return 0;
262}
263
264static int hidp_send_report(struct hidp_session *session, struct hid_report *report)
265{
266 unsigned char buf[32];
267 int rsize;
268
269 rsize = ((report->size - 1) >> 3) + 1 + (report->id > 0);
270 if (rsize > sizeof(buf))
271 return -EIO;
272
273 hid_output_report(report, buf);
274
275 return hidp_queue_report(session, buf, rsize);
276}
277
Linus Torvalds1da177e2005-04-16 15:20:36 -0700278static void hidp_idle_timeout(unsigned long arg)
279{
280 struct hidp_session *session = (struct hidp_session *) arg;
281
282 atomic_inc(&session->terminate);
283 hidp_schedule(session);
284}
285
Andrew Morton91f5cca2008-02-05 03:07:58 -0800286static void hidp_set_timer(struct hidp_session *session)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700287{
288 if (session->idle_to > 0)
289 mod_timer(&session->timer, jiffies + HZ * session->idle_to);
290}
291
292static inline void hidp_del_timer(struct hidp_session *session)
293{
294 if (session->idle_to > 0)
295 del_timer(&session->timer);
296}
297
298static int __hidp_send_ctrl_message(struct hidp_session *session,
299 unsigned char hdr, unsigned char *data, int size)
300{
301 struct sk_buff *skb;
302
303 BT_DBG("session %p data %p size %d", session, data, size);
304
305 if (!(skb = alloc_skb(size + 1, GFP_ATOMIC))) {
306 BT_ERR("Can't allocate memory for new frame");
307 return -ENOMEM;
308 }
309
310 *skb_put(skb, 1) = hdr;
311 if (data && size > 0)
312 memcpy(skb_put(skb, size), data, size);
313
314 skb_queue_tail(&session->ctrl_transmit, skb);
315
316 return 0;
317}
318
Dave Jonesb6f99a22007-03-22 12:27:49 -0700319static inline int hidp_send_ctrl_message(struct hidp_session *session,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700320 unsigned char hdr, unsigned char *data, int size)
321{
322 int err;
323
324 err = __hidp_send_ctrl_message(session, hdr, data, size);
325
326 hidp_schedule(session);
327
328 return err;
329}
330
Andrew Morton91f5cca2008-02-05 03:07:58 -0800331static void hidp_process_handshake(struct hidp_session *session,
332 unsigned char param)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700333{
334 BT_DBG("session %p param 0x%02x", session, param);
335
336 switch (param) {
337 case HIDP_HSHK_SUCCESSFUL:
338 /* FIXME: Call into SET_ GET_ handlers here */
339 break;
340
341 case HIDP_HSHK_NOT_READY:
342 case HIDP_HSHK_ERR_INVALID_REPORT_ID:
343 case HIDP_HSHK_ERR_UNSUPPORTED_REQUEST:
344 case HIDP_HSHK_ERR_INVALID_PARAMETER:
345 /* FIXME: Call into SET_ GET_ handlers here */
346 break;
347
348 case HIDP_HSHK_ERR_UNKNOWN:
349 break;
350
351 case HIDP_HSHK_ERR_FATAL:
352 /* Device requests a reboot, as this is the only way this error
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900353 * can be recovered. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700354 __hidp_send_ctrl_message(session,
355 HIDP_TRANS_HID_CONTROL | HIDP_CTRL_SOFT_RESET, NULL, 0);
356 break;
357
358 default:
359 __hidp_send_ctrl_message(session,
360 HIDP_TRANS_HANDSHAKE | HIDP_HSHK_ERR_INVALID_PARAMETER, NULL, 0);
361 break;
362 }
363}
364
Andrew Morton91f5cca2008-02-05 03:07:58 -0800365static void hidp_process_hid_control(struct hidp_session *session,
366 unsigned char param)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700367{
368 BT_DBG("session %p param 0x%02x", session, param);
369
Dave Youngeff001e2008-02-05 03:07:14 -0800370 if (param == HIDP_CTRL_VIRTUAL_CABLE_UNPLUG) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700371 /* Flush the transmit queues */
372 skb_queue_purge(&session->ctrl_transmit);
373 skb_queue_purge(&session->intr_transmit);
374
375 /* Kill session thread */
376 atomic_inc(&session->terminate);
Vikram Kandukuri981b1412009-07-01 11:39:58 +0530377 hidp_schedule(session);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700378 }
379}
380
Andrew Morton91f5cca2008-02-05 03:07:58 -0800381static void hidp_process_data(struct hidp_session *session, struct sk_buff *skb,
382 unsigned char param)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700383{
384 BT_DBG("session %p skb %p len %d param 0x%02x", session, skb, skb->len, param);
385
386 switch (param) {
387 case HIDP_DATA_RTYPE_INPUT:
388 hidp_set_timer(session);
389
390 if (session->input)
391 hidp_input_report(session, skb);
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100392
393 if (session->hid)
394 hid_input_report(session->hid, HID_INPUT_REPORT, skb->data, skb->len, 0);
395
Linus Torvalds1da177e2005-04-16 15:20:36 -0700396 break;
397
398 case HIDP_DATA_RTYPE_OTHER:
399 case HIDP_DATA_RTYPE_OUPUT:
400 case HIDP_DATA_RTYPE_FEATURE:
401 break;
402
403 default:
404 __hidp_send_ctrl_message(session,
405 HIDP_TRANS_HANDSHAKE | HIDP_HSHK_ERR_INVALID_PARAMETER, NULL, 0);
406 }
407}
408
Andrew Morton91f5cca2008-02-05 03:07:58 -0800409static void hidp_recv_ctrl_frame(struct hidp_session *session,
410 struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700411{
412 unsigned char hdr, type, param;
413
414 BT_DBG("session %p skb %p len %d", session, skb, skb->len);
415
416 hdr = skb->data[0];
417 skb_pull(skb, 1);
418
419 type = hdr & HIDP_HEADER_TRANS_MASK;
420 param = hdr & HIDP_HEADER_PARAM_MASK;
421
422 switch (type) {
423 case HIDP_TRANS_HANDSHAKE:
424 hidp_process_handshake(session, param);
425 break;
426
427 case HIDP_TRANS_HID_CONTROL:
428 hidp_process_hid_control(session, param);
429 break;
430
431 case HIDP_TRANS_DATA:
432 hidp_process_data(session, skb, param);
433 break;
434
435 default:
436 __hidp_send_ctrl_message(session,
437 HIDP_TRANS_HANDSHAKE | HIDP_HSHK_ERR_UNSUPPORTED_REQUEST, NULL, 0);
438 break;
439 }
440
441 kfree_skb(skb);
442}
443
Andrew Morton91f5cca2008-02-05 03:07:58 -0800444static void hidp_recv_intr_frame(struct hidp_session *session,
445 struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700446{
447 unsigned char hdr;
448
449 BT_DBG("session %p skb %p len %d", session, skb, skb->len);
450
451 hdr = skb->data[0];
452 skb_pull(skb, 1);
453
454 if (hdr == (HIDP_TRANS_DATA | HIDP_DATA_RTYPE_INPUT)) {
455 hidp_set_timer(session);
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100456
Linus Torvalds1da177e2005-04-16 15:20:36 -0700457 if (session->input)
458 hidp_input_report(session, skb);
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100459
460 if (session->hid) {
461 hid_input_report(session->hid, HID_INPUT_REPORT, skb->data, skb->len, 1);
462 BT_DBG("report len %d", skb->len);
463 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700464 } else {
465 BT_DBG("Unsupported protocol header 0x%02x", hdr);
466 }
467
468 kfree_skb(skb);
469}
470
471static int hidp_send_frame(struct socket *sock, unsigned char *data, int len)
472{
473 struct kvec iv = { data, len };
474 struct msghdr msg;
475
476 BT_DBG("sock %p data %p len %d", sock, data, len);
477
478 if (!len)
479 return 0;
480
481 memset(&msg, 0, sizeof(msg));
482
483 return kernel_sendmsg(sock, &msg, &iv, 1, len);
484}
485
David S. Millerb03efcf2005-07-08 14:57:23 -0700486static void hidp_process_transmit(struct hidp_session *session)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700487{
488 struct sk_buff *skb;
489
490 BT_DBG("session %p", session);
491
492 while ((skb = skb_dequeue(&session->ctrl_transmit))) {
493 if (hidp_send_frame(session->ctrl_sock, skb->data, skb->len) < 0) {
494 skb_queue_head(&session->ctrl_transmit, skb);
495 break;
496 }
497
498 hidp_set_timer(session);
499 kfree_skb(skb);
500 }
501
502 while ((skb = skb_dequeue(&session->intr_transmit))) {
503 if (hidp_send_frame(session->intr_sock, skb->data, skb->len) < 0) {
504 skb_queue_head(&session->intr_transmit, skb);
505 break;
506 }
507
508 hidp_set_timer(session);
509 kfree_skb(skb);
510 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700511}
512
513static int hidp_session(void *arg)
514{
515 struct hidp_session *session = arg;
516 struct sock *ctrl_sk = session->ctrl_sock->sk;
517 struct sock *intr_sk = session->intr_sock->sk;
518 struct sk_buff *skb;
519 int vendor = 0x0000, product = 0x0000;
520 wait_queue_t ctrl_wait, intr_wait;
521
522 BT_DBG("session %p", session);
523
524 if (session->input) {
525 vendor = session->input->id.vendor;
526 product = session->input->id.product;
527 }
528
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100529 if (session->hid) {
530 vendor = session->hid->vendor;
531 product = session->hid->product;
532 }
533
Linus Torvalds1da177e2005-04-16 15:20:36 -0700534 daemonize("khidpd_%04x%04x", vendor, product);
535 set_user_nice(current, -15);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700536
537 init_waitqueue_entry(&ctrl_wait, current);
538 init_waitqueue_entry(&intr_wait, current);
539 add_wait_queue(ctrl_sk->sk_sleep, &ctrl_wait);
540 add_wait_queue(intr_sk->sk_sleep, &intr_wait);
541 while (!atomic_read(&session->terminate)) {
542 set_current_state(TASK_INTERRUPTIBLE);
543
544 if (ctrl_sk->sk_state != BT_CONNECTED || intr_sk->sk_state != BT_CONNECTED)
545 break;
546
547 while ((skb = skb_dequeue(&ctrl_sk->sk_receive_queue))) {
548 skb_orphan(skb);
549 hidp_recv_ctrl_frame(session, skb);
550 }
551
552 while ((skb = skb_dequeue(&intr_sk->sk_receive_queue))) {
553 skb_orphan(skb);
554 hidp_recv_intr_frame(session, skb);
555 }
556
557 hidp_process_transmit(session);
558
559 schedule();
560 }
561 set_current_state(TASK_RUNNING);
562 remove_wait_queue(intr_sk->sk_sleep, &intr_wait);
563 remove_wait_queue(ctrl_sk->sk_sleep, &ctrl_wait);
564
565 down_write(&hidp_session_sem);
566
567 hidp_del_timer(session);
568
Linus Torvalds1da177e2005-04-16 15:20:36 -0700569 if (session->input) {
570 input_unregister_device(session->input);
Dmitry Torokhov34abf912005-09-15 02:01:40 -0500571 session->input = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700572 }
573
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100574 if (session->hid) {
575 if (session->hid->claimed & HID_CLAIMED_INPUT)
576 hidinput_disconnect(session->hid);
Jiri Slaby85cdaf52008-05-16 11:49:15 +0200577 hid_destroy_device(session->hid);
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100578 }
579
Marcel Holtmannec8dab32008-07-14 20:13:53 +0200580 /* Wakeup user-space polling for socket errors */
581 session->intr_sock->sk->sk_err = EUNATCH;
582 session->ctrl_sock->sk->sk_err = EUNATCH;
583
584 hidp_schedule(session);
585
David Woodhouse1c398582007-07-07 14:58:39 -0400586 fput(session->intr_sock->file);
587
588 wait_event_timeout(*(ctrl_sk->sk_sleep),
589 (ctrl_sk->sk_state == BT_CLOSED), msecs_to_jiffies(500));
590
591 fput(session->ctrl_sock->file);
592
593 __hidp_unlink_session(session);
594
Linus Torvalds1da177e2005-04-16 15:20:36 -0700595 up_write(&hidp_session_sem);
596
597 kfree(session);
598 return 0;
599}
600
Marcel Holtmann0a85b962006-07-06 13:09:02 +0200601static struct device *hidp_get_device(struct hidp_session *session)
602{
603 bdaddr_t *src = &bt_sk(session->ctrl_sock->sk)->src;
604 bdaddr_t *dst = &bt_sk(session->ctrl_sock->sk)->dst;
605 struct hci_dev *hdev;
606 struct hci_conn *conn;
607
608 hdev = hci_get_route(dst, src);
609 if (!hdev)
610 return NULL;
611
612 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, dst);
Marcel Holtmann0a85b962006-07-06 13:09:02 +0200613
614 hci_dev_put(hdev);
615
Marcel Holtmannb2cfcd72006-10-15 17:31:05 +0200616 return conn ? &conn->dev : NULL;
Marcel Holtmann0a85b962006-07-06 13:09:02 +0200617}
618
Andrew Morton91f5cca2008-02-05 03:07:58 -0800619static int hidp_setup_input(struct hidp_session *session,
620 struct hidp_connadd_req *req)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700621{
Jiri Slabyc500c972008-05-16 11:49:16 +0200622 struct input_dev *input;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700623 int i;
624
Jiri Slabyc500c972008-05-16 11:49:16 +0200625 input = input_allocate_device();
626 if (!input)
627 return -ENOMEM;
628
629 session->input = input;
630
Marcel Holtmann5be39462007-05-09 09:15:30 +0200631 input_set_drvdata(input, session);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700632
Dmitry Torokhov34abf912005-09-15 02:01:40 -0500633 input->name = "Bluetooth HID Boot Protocol Device";
634
Linus Torvalds1da177e2005-04-16 15:20:36 -0700635 input->id.bustype = BUS_BLUETOOTH;
636 input->id.vendor = req->vendor;
637 input->id.product = req->product;
638 input->id.version = req->version;
639
640 if (req->subclass & 0x40) {
641 set_bit(EV_KEY, input->evbit);
642 set_bit(EV_LED, input->evbit);
643 set_bit(EV_REP, input->evbit);
644
645 set_bit(LED_NUML, input->ledbit);
646 set_bit(LED_CAPSL, input->ledbit);
647 set_bit(LED_SCROLLL, input->ledbit);
648 set_bit(LED_COMPOSE, input->ledbit);
649 set_bit(LED_KANA, input->ledbit);
650
651 for (i = 0; i < sizeof(hidp_keycode); i++)
652 set_bit(hidp_keycode[i], input->keybit);
653 clear_bit(0, input->keybit);
654 }
655
656 if (req->subclass & 0x80) {
Jiri Slaby7b19ada2007-10-18 23:40:32 -0700657 input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL);
658 input->keybit[BIT_WORD(BTN_MOUSE)] = BIT_MASK(BTN_LEFT) |
659 BIT_MASK(BTN_RIGHT) | BIT_MASK(BTN_MIDDLE);
660 input->relbit[0] = BIT_MASK(REL_X) | BIT_MASK(REL_Y);
661 input->keybit[BIT_WORD(BTN_MOUSE)] |= BIT_MASK(BTN_SIDE) |
662 BIT_MASK(BTN_EXTRA);
663 input->relbit[0] |= BIT_MASK(REL_WHEEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700664 }
665
Marcel Holtmann5be39462007-05-09 09:15:30 +0200666 input->dev.parent = hidp_get_device(session);
Marcel Holtmann0a85b962006-07-06 13:09:02 +0200667
Linus Torvalds1da177e2005-04-16 15:20:36 -0700668 input->event = hidp_input_event;
669
WANG Cong53465eb2007-09-25 22:57:31 -0700670 return input_register_device(input);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700671}
672
Marcel Holtmannf5ffd462007-02-17 23:58:53 +0100673static int hidp_open(struct hid_device *hid)
674{
675 return 0;
676}
677
678static void hidp_close(struct hid_device *hid)
679{
680}
681
Jiri Slabyc500c972008-05-16 11:49:16 +0200682static int hidp_parse(struct hid_device *hid)
683{
684 struct hidp_session *session = hid->driver_data;
685 struct hidp_connadd_req *req = session->req;
686 unsigned char *buf;
687 int ret;
688
689 buf = kmalloc(req->rd_size, GFP_KERNEL);
690 if (!buf)
691 return -ENOMEM;
692
693 if (copy_from_user(buf, req->rd_data, req->rd_size)) {
694 kfree(buf);
695 return -EFAULT;
696 }
697
698 ret = hid_parse_report(session->hid, buf, req->rd_size);
699
700 kfree(buf);
701
702 if (ret)
703 return ret;
704
705 session->req = NULL;
706
Jiri Slabyc500c972008-05-16 11:49:16 +0200707 return 0;
708}
709
710static int hidp_start(struct hid_device *hid)
711{
712 struct hidp_session *session = hid->driver_data;
713 struct hid_report *report;
714
715 list_for_each_entry(report, &hid->report_enum[HID_INPUT_REPORT].
716 report_list, list)
717 hidp_send_report(session, report);
718
719 list_for_each_entry(report, &hid->report_enum[HID_FEATURE_REPORT].
720 report_list, list)
721 hidp_send_report(session, report);
722
Jiri Slabyc500c972008-05-16 11:49:16 +0200723 return 0;
724}
725
726static void hidp_stop(struct hid_device *hid)
727{
728 struct hidp_session *session = hid->driver_data;
729
730 skb_queue_purge(&session->ctrl_transmit);
731 skb_queue_purge(&session->intr_transmit);
732
733 if (hid->claimed & HID_CLAIMED_INPUT)
734 hidinput_disconnect(hid);
735 hid->claimed = 0;
736}
737
738static struct hid_ll_driver hidp_hid_driver = {
739 .parse = hidp_parse,
740 .start = hidp_start,
741 .stop = hidp_stop,
742 .open = hidp_open,
743 .close = hidp_close,
744 .hidinput_input_event = hidp_hidinput_event,
745};
746
Jiri Slaby85cdaf52008-05-16 11:49:15 +0200747static int hidp_setup_hid(struct hidp_session *session,
Andrew Morton91f5cca2008-02-05 03:07:58 -0800748 struct hidp_connadd_req *req)
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100749{
Jiri Slabyc500c972008-05-16 11:49:16 +0200750 struct hid_device *hid;
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100751 bdaddr_t src, dst;
Jiri Slaby85cdaf52008-05-16 11:49:15 +0200752 int ret;
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100753
Jiri Slabyc500c972008-05-16 11:49:16 +0200754 hid = hid_allocate_device();
755 if (IS_ERR(hid)) {
756 ret = PTR_ERR(session->hid);
757 goto err;
758 }
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100759
Jiri Slabyc500c972008-05-16 11:49:16 +0200760 session->hid = hid;
761 session->req = req;
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100762 hid->driver_data = session;
763
Jiri Slabyc500c972008-05-16 11:49:16 +0200764 baswap(&src, &bt_sk(session->ctrl_sock->sk)->src);
765 baswap(&dst, &bt_sk(session->ctrl_sock->sk)->dst);
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100766
767 hid->bus = BUS_BLUETOOTH;
768 hid->vendor = req->vendor;
769 hid->product = req->product;
770 hid->version = req->version;
Jiri Slabyc500c972008-05-16 11:49:16 +0200771 hid->country = req->country;
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100772
773 strncpy(hid->name, req->name, 128);
774 strncpy(hid->phys, batostr(&src), 64);
775 strncpy(hid->uniq, batostr(&dst), 64);
776
Jiri Slaby85cdaf52008-05-16 11:49:15 +0200777 hid->dev.parent = hidp_get_device(session);
Jiri Slabyc500c972008-05-16 11:49:16 +0200778 hid->ll_driver = &hidp_hid_driver;
Jiri Slaby85cdaf52008-05-16 11:49:15 +0200779
780 ret = hid_add_device(hid);
Jiri Slabyc500c972008-05-16 11:49:16 +0200781 if (ret)
782 goto err_hid;
Jiri Slaby85cdaf52008-05-16 11:49:15 +0200783
Jiri Slabyc500c972008-05-16 11:49:16 +0200784 return 0;
785err_hid:
786 hid_destroy_device(hid);
787 session->hid = NULL;
788err:
Jiri Slaby85cdaf52008-05-16 11:49:15 +0200789 return ret;
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100790}
791
Linus Torvalds1da177e2005-04-16 15:20:36 -0700792int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock, struct socket *intr_sock)
793{
794 struct hidp_session *session, *s;
795 int err;
796
797 BT_DBG("");
798
799 if (bacmp(&bt_sk(ctrl_sock->sk)->src, &bt_sk(intr_sock->sk)->src) ||
800 bacmp(&bt_sk(ctrl_sock->sk)->dst, &bt_sk(intr_sock->sk)->dst))
801 return -ENOTUNIQ;
802
Marcel Holtmann25ea6db2006-07-06 15:40:09 +0200803 session = kzalloc(sizeof(struct hidp_session), GFP_KERNEL);
Dmitry Torokhov34abf912005-09-15 02:01:40 -0500804 if (!session)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700805 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700806
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100807 BT_DBG("rd_data %p rd_size %d", req->rd_data, req->rd_size);
808
Linus Torvalds1da177e2005-04-16 15:20:36 -0700809 down_write(&hidp_session_sem);
810
811 s = __hidp_get_session(&bt_sk(ctrl_sock->sk)->dst);
812 if (s && s->state == BT_CONNECTED) {
813 err = -EEXIST;
814 goto failed;
815 }
816
817 bacpy(&session->bdaddr, &bt_sk(ctrl_sock->sk)->dst);
818
819 session->ctrl_mtu = min_t(uint, l2cap_pi(ctrl_sock->sk)->omtu, l2cap_pi(ctrl_sock->sk)->imtu);
820 session->intr_mtu = min_t(uint, l2cap_pi(intr_sock->sk)->omtu, l2cap_pi(intr_sock->sk)->imtu);
821
822 BT_DBG("ctrl mtu %d intr mtu %d", session->ctrl_mtu, session->intr_mtu);
823
824 session->ctrl_sock = ctrl_sock;
825 session->intr_sock = intr_sock;
826 session->state = BT_CONNECTED;
827
Pavel Emelyanovb24b8a22008-01-23 21:20:07 -0800828 setup_timer(&session->timer, hidp_idle_timeout, (unsigned long)session);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700829
830 skb_queue_head_init(&session->ctrl_transmit);
831 skb_queue_head_init(&session->intr_transmit);
832
833 session->flags = req->flags & (1 << HIDP_BLUETOOTH_VENDOR_ID);
834 session->idle_to = req->idle_to;
835
Jiri Slabyc500c972008-05-16 11:49:16 +0200836 if (req->rd_size > 0) {
Jiri Slaby85cdaf52008-05-16 11:49:15 +0200837 err = hidp_setup_hid(session, req);
Jiri Slabyd458a9d2008-05-16 11:49:20 +0200838 if (err && err != -ENODEV)
Jiri Slabyc500c972008-05-16 11:49:16 +0200839 goto err_skb;
840 }
841
842 if (!session->hid) {
843 err = hidp_setup_input(session, req);
844 if (err < 0)
845 goto err_skb;
Jiri Slaby85cdaf52008-05-16 11:49:15 +0200846 }
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100847
Linus Torvalds1da177e2005-04-16 15:20:36 -0700848 __hidp_link_session(session);
849
850 hidp_set_timer(session);
851
852 err = kernel_thread(hidp_session, session, CLONE_KERNEL);
853 if (err < 0)
854 goto unlink;
855
856 if (session->input) {
857 hidp_send_ctrl_message(session,
858 HIDP_TRANS_SET_PROTOCOL | HIDP_PROTO_BOOT, NULL, 0);
859 session->flags |= (1 << HIDP_BOOT_PROTOCOL_MODE);
860
861 session->leds = 0xff;
862 hidp_input_event(session->input, EV_LED, 0, 0);
863 }
864
865 up_write(&hidp_session_sem);
866 return 0;
867
868unlink:
869 hidp_del_timer(session);
870
871 __hidp_unlink_session(session);
872
Jiri Slabyc500c972008-05-16 11:49:16 +0200873 if (session->input)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700874 input_unregister_device(session->input);
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100875 if (session->hid)
Jiri Slaby85cdaf52008-05-16 11:49:15 +0200876 hid_destroy_device(session->hid);
Jiri Slabyc500c972008-05-16 11:49:16 +0200877err_skb:
878 skb_queue_purge(&session->ctrl_transmit);
879 skb_queue_purge(&session->intr_transmit);
880failed:
881 up_write(&hidp_session_sem);
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100882
Marcel Holtmann5be39462007-05-09 09:15:30 +0200883 input_free_device(session->input);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700884 kfree(session);
885 return err;
886}
887
888int hidp_del_connection(struct hidp_conndel_req *req)
889{
890 struct hidp_session *session;
891 int err = 0;
892
893 BT_DBG("");
894
895 down_read(&hidp_session_sem);
896
897 session = __hidp_get_session(&req->bdaddr);
898 if (session) {
899 if (req->flags & (1 << HIDP_VIRTUAL_CABLE_UNPLUG)) {
900 hidp_send_ctrl_message(session,
901 HIDP_TRANS_HID_CONTROL | HIDP_CTRL_VIRTUAL_CABLE_UNPLUG, NULL, 0);
902 } else {
903 /* Flush the transmit queues */
904 skb_queue_purge(&session->ctrl_transmit);
905 skb_queue_purge(&session->intr_transmit);
906
Marcel Holtmannec8dab32008-07-14 20:13:53 +0200907 /* Wakeup user-space polling for socket errors */
908 session->intr_sock->sk->sk_err = EUNATCH;
909 session->ctrl_sock->sk->sk_err = EUNATCH;
910
Linus Torvalds1da177e2005-04-16 15:20:36 -0700911 /* Kill session thread */
912 atomic_inc(&session->terminate);
913 hidp_schedule(session);
914 }
915 } else
916 err = -ENOENT;
917
918 up_read(&hidp_session_sem);
919 return err;
920}
921
922int hidp_get_connlist(struct hidp_connlist_req *req)
923{
924 struct list_head *p;
925 int err = 0, n = 0;
926
927 BT_DBG("");
928
929 down_read(&hidp_session_sem);
930
931 list_for_each(p, &hidp_session_list) {
932 struct hidp_session *session;
933 struct hidp_conninfo ci;
934
935 session = list_entry(p, struct hidp_session, list);
936
937 __hidp_copy_session(session, &ci);
938
939 if (copy_to_user(req->ci, &ci, sizeof(ci))) {
940 err = -EFAULT;
941 break;
942 }
943
944 if (++n >= req->cnum)
945 break;
946
947 req->ci++;
948 }
949 req->cnum = n;
950
951 up_read(&hidp_session_sem);
952 return err;
953}
954
955int hidp_get_conninfo(struct hidp_conninfo *ci)
956{
957 struct hidp_session *session;
958 int err = 0;
959
960 down_read(&hidp_session_sem);
961
962 session = __hidp_get_session(&ci->bdaddr);
963 if (session)
964 __hidp_copy_session(session, ci);
965 else
966 err = -ENOENT;
967
968 up_read(&hidp_session_sem);
969 return err;
970}
971
Jiri Slaby85cdaf52008-05-16 11:49:15 +0200972static const struct hid_device_id hidp_table[] = {
973 { HID_BLUETOOTH_DEVICE(HID_ANY_ID, HID_ANY_ID) },
974 { }
975};
976
977static struct hid_driver hidp_driver = {
978 .name = "generic-bluetooth",
979 .id_table = hidp_table,
980};
981
Linus Torvalds1da177e2005-04-16 15:20:36 -0700982static int __init hidp_init(void)
983{
Jiri Slaby85cdaf52008-05-16 11:49:15 +0200984 int ret;
985
Linus Torvalds1da177e2005-04-16 15:20:36 -0700986 l2cap_load();
987
988 BT_INFO("HIDP (Human Interface Emulation) ver %s", VERSION);
989
Jiri Slaby85cdaf52008-05-16 11:49:15 +0200990 ret = hid_register_driver(&hidp_driver);
991 if (ret)
992 goto err;
993
994 ret = hidp_init_sockets();
995 if (ret)
996 goto err_drv;
997
998 return 0;
999err_drv:
1000 hid_unregister_driver(&hidp_driver);
1001err:
1002 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001003}
1004
1005static void __exit hidp_exit(void)
1006{
1007 hidp_cleanup_sockets();
Jiri Slaby85cdaf52008-05-16 11:49:15 +02001008 hid_unregister_driver(&hidp_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001009}
1010
1011module_init(hidp_init);
1012module_exit(hidp_exit);
1013
1014MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
1015MODULE_DESCRIPTION("Bluetooth HIDP ver " VERSION);
1016MODULE_VERSION(VERSION);
1017MODULE_LICENSE("GPL");
1018MODULE_ALIAS("bt-proto-6");