blob: b18676870d5500e0fff1ece30654b060f373db2d [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);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377 }
378}
379
Andrew Morton91f5cca2008-02-05 03:07:58 -0800380static void hidp_process_data(struct hidp_session *session, struct sk_buff *skb,
381 unsigned char param)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700382{
383 BT_DBG("session %p skb %p len %d param 0x%02x", session, skb, skb->len, param);
384
385 switch (param) {
386 case HIDP_DATA_RTYPE_INPUT:
387 hidp_set_timer(session);
388
389 if (session->input)
390 hidp_input_report(session, skb);
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100391
392 if (session->hid)
393 hid_input_report(session->hid, HID_INPUT_REPORT, skb->data, skb->len, 0);
394
Linus Torvalds1da177e2005-04-16 15:20:36 -0700395 break;
396
397 case HIDP_DATA_RTYPE_OTHER:
398 case HIDP_DATA_RTYPE_OUPUT:
399 case HIDP_DATA_RTYPE_FEATURE:
400 break;
401
402 default:
403 __hidp_send_ctrl_message(session,
404 HIDP_TRANS_HANDSHAKE | HIDP_HSHK_ERR_INVALID_PARAMETER, NULL, 0);
405 }
406}
407
Andrew Morton91f5cca2008-02-05 03:07:58 -0800408static void hidp_recv_ctrl_frame(struct hidp_session *session,
409 struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700410{
411 unsigned char hdr, type, param;
412
413 BT_DBG("session %p skb %p len %d", session, skb, skb->len);
414
415 hdr = skb->data[0];
416 skb_pull(skb, 1);
417
418 type = hdr & HIDP_HEADER_TRANS_MASK;
419 param = hdr & HIDP_HEADER_PARAM_MASK;
420
421 switch (type) {
422 case HIDP_TRANS_HANDSHAKE:
423 hidp_process_handshake(session, param);
424 break;
425
426 case HIDP_TRANS_HID_CONTROL:
427 hidp_process_hid_control(session, param);
428 break;
429
430 case HIDP_TRANS_DATA:
431 hidp_process_data(session, skb, param);
432 break;
433
434 default:
435 __hidp_send_ctrl_message(session,
436 HIDP_TRANS_HANDSHAKE | HIDP_HSHK_ERR_UNSUPPORTED_REQUEST, NULL, 0);
437 break;
438 }
439
440 kfree_skb(skb);
441}
442
Andrew Morton91f5cca2008-02-05 03:07:58 -0800443static void hidp_recv_intr_frame(struct hidp_session *session,
444 struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700445{
446 unsigned char hdr;
447
448 BT_DBG("session %p skb %p len %d", session, skb, skb->len);
449
450 hdr = skb->data[0];
451 skb_pull(skb, 1);
452
453 if (hdr == (HIDP_TRANS_DATA | HIDP_DATA_RTYPE_INPUT)) {
454 hidp_set_timer(session);
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100455
Linus Torvalds1da177e2005-04-16 15:20:36 -0700456 if (session->input)
457 hidp_input_report(session, skb);
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100458
459 if (session->hid) {
460 hid_input_report(session->hid, HID_INPUT_REPORT, skb->data, skb->len, 1);
461 BT_DBG("report len %d", skb->len);
462 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700463 } else {
464 BT_DBG("Unsupported protocol header 0x%02x", hdr);
465 }
466
467 kfree_skb(skb);
468}
469
470static int hidp_send_frame(struct socket *sock, unsigned char *data, int len)
471{
472 struct kvec iv = { data, len };
473 struct msghdr msg;
474
475 BT_DBG("sock %p data %p len %d", sock, data, len);
476
477 if (!len)
478 return 0;
479
480 memset(&msg, 0, sizeof(msg));
481
482 return kernel_sendmsg(sock, &msg, &iv, 1, len);
483}
484
David S. Millerb03efcf2005-07-08 14:57:23 -0700485static void hidp_process_transmit(struct hidp_session *session)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700486{
487 struct sk_buff *skb;
488
489 BT_DBG("session %p", session);
490
491 while ((skb = skb_dequeue(&session->ctrl_transmit))) {
492 if (hidp_send_frame(session->ctrl_sock, skb->data, skb->len) < 0) {
493 skb_queue_head(&session->ctrl_transmit, skb);
494 break;
495 }
496
497 hidp_set_timer(session);
498 kfree_skb(skb);
499 }
500
501 while ((skb = skb_dequeue(&session->intr_transmit))) {
502 if (hidp_send_frame(session->intr_sock, skb->data, skb->len) < 0) {
503 skb_queue_head(&session->intr_transmit, skb);
504 break;
505 }
506
507 hidp_set_timer(session);
508 kfree_skb(skb);
509 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700510}
511
512static int hidp_session(void *arg)
513{
514 struct hidp_session *session = arg;
515 struct sock *ctrl_sk = session->ctrl_sock->sk;
516 struct sock *intr_sk = session->intr_sock->sk;
517 struct sk_buff *skb;
518 int vendor = 0x0000, product = 0x0000;
519 wait_queue_t ctrl_wait, intr_wait;
520
521 BT_DBG("session %p", session);
522
523 if (session->input) {
524 vendor = session->input->id.vendor;
525 product = session->input->id.product;
526 }
527
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100528 if (session->hid) {
529 vendor = session->hid->vendor;
530 product = session->hid->product;
531 }
532
Linus Torvalds1da177e2005-04-16 15:20:36 -0700533 daemonize("khidpd_%04x%04x", vendor, product);
534 set_user_nice(current, -15);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700535
536 init_waitqueue_entry(&ctrl_wait, current);
537 init_waitqueue_entry(&intr_wait, current);
538 add_wait_queue(ctrl_sk->sk_sleep, &ctrl_wait);
539 add_wait_queue(intr_sk->sk_sleep, &intr_wait);
540 while (!atomic_read(&session->terminate)) {
541 set_current_state(TASK_INTERRUPTIBLE);
542
543 if (ctrl_sk->sk_state != BT_CONNECTED || intr_sk->sk_state != BT_CONNECTED)
544 break;
545
546 while ((skb = skb_dequeue(&ctrl_sk->sk_receive_queue))) {
547 skb_orphan(skb);
548 hidp_recv_ctrl_frame(session, skb);
549 }
550
551 while ((skb = skb_dequeue(&intr_sk->sk_receive_queue))) {
552 skb_orphan(skb);
553 hidp_recv_intr_frame(session, skb);
554 }
555
556 hidp_process_transmit(session);
557
558 schedule();
559 }
560 set_current_state(TASK_RUNNING);
561 remove_wait_queue(intr_sk->sk_sleep, &intr_wait);
562 remove_wait_queue(ctrl_sk->sk_sleep, &ctrl_wait);
563
564 down_write(&hidp_session_sem);
565
566 hidp_del_timer(session);
567
Linus Torvalds1da177e2005-04-16 15:20:36 -0700568 if (session->input) {
569 input_unregister_device(session->input);
Dmitry Torokhov34abf912005-09-15 02:01:40 -0500570 session->input = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700571 }
572
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100573 if (session->hid) {
574 if (session->hid->claimed & HID_CLAIMED_INPUT)
575 hidinput_disconnect(session->hid);
Jiri Slaby85cdaf52008-05-16 11:49:15 +0200576 hid_destroy_device(session->hid);
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100577 }
578
Marcel Holtmannec8dab32008-07-14 20:13:53 +0200579 /* Wakeup user-space polling for socket errors */
580 session->intr_sock->sk->sk_err = EUNATCH;
581 session->ctrl_sock->sk->sk_err = EUNATCH;
582
583 hidp_schedule(session);
584
David Woodhouse1c398582007-07-07 14:58:39 -0400585 fput(session->intr_sock->file);
586
587 wait_event_timeout(*(ctrl_sk->sk_sleep),
588 (ctrl_sk->sk_state == BT_CLOSED), msecs_to_jiffies(500));
589
590 fput(session->ctrl_sock->file);
591
592 __hidp_unlink_session(session);
593
Linus Torvalds1da177e2005-04-16 15:20:36 -0700594 up_write(&hidp_session_sem);
595
596 kfree(session);
597 return 0;
598}
599
Marcel Holtmann0a85b962006-07-06 13:09:02 +0200600static struct device *hidp_get_device(struct hidp_session *session)
601{
602 bdaddr_t *src = &bt_sk(session->ctrl_sock->sk)->src;
603 bdaddr_t *dst = &bt_sk(session->ctrl_sock->sk)->dst;
604 struct hci_dev *hdev;
605 struct hci_conn *conn;
606
607 hdev = hci_get_route(dst, src);
608 if (!hdev)
609 return NULL;
610
611 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, dst);
Marcel Holtmann0a85b962006-07-06 13:09:02 +0200612
613 hci_dev_put(hdev);
614
Marcel Holtmannb2cfcd72006-10-15 17:31:05 +0200615 return conn ? &conn->dev : NULL;
Marcel Holtmann0a85b962006-07-06 13:09:02 +0200616}
617
Andrew Morton91f5cca2008-02-05 03:07:58 -0800618static int hidp_setup_input(struct hidp_session *session,
619 struct hidp_connadd_req *req)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700620{
Jiri Slabyc500c972008-05-16 11:49:16 +0200621 struct input_dev *input;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700622 int i;
623
Jiri Slabyc500c972008-05-16 11:49:16 +0200624 input = input_allocate_device();
625 if (!input)
626 return -ENOMEM;
627
628 session->input = input;
629
Marcel Holtmann5be39462007-05-09 09:15:30 +0200630 input_set_drvdata(input, session);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700631
Dmitry Torokhov34abf912005-09-15 02:01:40 -0500632 input->name = "Bluetooth HID Boot Protocol Device";
633
Linus Torvalds1da177e2005-04-16 15:20:36 -0700634 input->id.bustype = BUS_BLUETOOTH;
635 input->id.vendor = req->vendor;
636 input->id.product = req->product;
637 input->id.version = req->version;
638
639 if (req->subclass & 0x40) {
640 set_bit(EV_KEY, input->evbit);
641 set_bit(EV_LED, input->evbit);
642 set_bit(EV_REP, input->evbit);
643
644 set_bit(LED_NUML, input->ledbit);
645 set_bit(LED_CAPSL, input->ledbit);
646 set_bit(LED_SCROLLL, input->ledbit);
647 set_bit(LED_COMPOSE, input->ledbit);
648 set_bit(LED_KANA, input->ledbit);
649
650 for (i = 0; i < sizeof(hidp_keycode); i++)
651 set_bit(hidp_keycode[i], input->keybit);
652 clear_bit(0, input->keybit);
653 }
654
655 if (req->subclass & 0x80) {
Jiri Slaby7b19ada2007-10-18 23:40:32 -0700656 input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL);
657 input->keybit[BIT_WORD(BTN_MOUSE)] = BIT_MASK(BTN_LEFT) |
658 BIT_MASK(BTN_RIGHT) | BIT_MASK(BTN_MIDDLE);
659 input->relbit[0] = BIT_MASK(REL_X) | BIT_MASK(REL_Y);
660 input->keybit[BIT_WORD(BTN_MOUSE)] |= BIT_MASK(BTN_SIDE) |
661 BIT_MASK(BTN_EXTRA);
662 input->relbit[0] |= BIT_MASK(REL_WHEEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700663 }
664
Marcel Holtmann5be39462007-05-09 09:15:30 +0200665 input->dev.parent = hidp_get_device(session);
Marcel Holtmann0a85b962006-07-06 13:09:02 +0200666
Linus Torvalds1da177e2005-04-16 15:20:36 -0700667 input->event = hidp_input_event;
668
WANG Cong53465eb2007-09-25 22:57:31 -0700669 return input_register_device(input);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700670}
671
Marcel Holtmannf5ffd462007-02-17 23:58:53 +0100672static int hidp_open(struct hid_device *hid)
673{
674 return 0;
675}
676
677static void hidp_close(struct hid_device *hid)
678{
679}
680
Jiri Slabyc500c972008-05-16 11:49:16 +0200681static int hidp_parse(struct hid_device *hid)
682{
683 struct hidp_session *session = hid->driver_data;
684 struct hidp_connadd_req *req = session->req;
685 unsigned char *buf;
686 int ret;
687
688 buf = kmalloc(req->rd_size, GFP_KERNEL);
689 if (!buf)
690 return -ENOMEM;
691
692 if (copy_from_user(buf, req->rd_data, req->rd_size)) {
693 kfree(buf);
694 return -EFAULT;
695 }
696
697 ret = hid_parse_report(session->hid, buf, req->rd_size);
698
699 kfree(buf);
700
701 if (ret)
702 return ret;
703
704 session->req = NULL;
705
Jiri Slabyc500c972008-05-16 11:49:16 +0200706 return 0;
707}
708
709static int hidp_start(struct hid_device *hid)
710{
711 struct hidp_session *session = hid->driver_data;
712 struct hid_report *report;
713
714 list_for_each_entry(report, &hid->report_enum[HID_INPUT_REPORT].
715 report_list, list)
716 hidp_send_report(session, report);
717
718 list_for_each_entry(report, &hid->report_enum[HID_FEATURE_REPORT].
719 report_list, list)
720 hidp_send_report(session, report);
721
Jiri Slabyc500c972008-05-16 11:49:16 +0200722 return 0;
723}
724
725static void hidp_stop(struct hid_device *hid)
726{
727 struct hidp_session *session = hid->driver_data;
728
729 skb_queue_purge(&session->ctrl_transmit);
730 skb_queue_purge(&session->intr_transmit);
731
732 if (hid->claimed & HID_CLAIMED_INPUT)
733 hidinput_disconnect(hid);
734 hid->claimed = 0;
735}
736
737static struct hid_ll_driver hidp_hid_driver = {
738 .parse = hidp_parse,
739 .start = hidp_start,
740 .stop = hidp_stop,
741 .open = hidp_open,
742 .close = hidp_close,
743 .hidinput_input_event = hidp_hidinput_event,
744};
745
Jiri Slaby85cdaf52008-05-16 11:49:15 +0200746static int hidp_setup_hid(struct hidp_session *session,
Andrew Morton91f5cca2008-02-05 03:07:58 -0800747 struct hidp_connadd_req *req)
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100748{
Jiri Slabyc500c972008-05-16 11:49:16 +0200749 struct hid_device *hid;
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100750 bdaddr_t src, dst;
Jiri Slaby85cdaf52008-05-16 11:49:15 +0200751 int ret;
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100752
Jiri Slabyc500c972008-05-16 11:49:16 +0200753 hid = hid_allocate_device();
754 if (IS_ERR(hid)) {
755 ret = PTR_ERR(session->hid);
756 goto err;
757 }
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100758
Jiri Slabyc500c972008-05-16 11:49:16 +0200759 session->hid = hid;
760 session->req = req;
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100761 hid->driver_data = session;
762
Jiri Slabyc500c972008-05-16 11:49:16 +0200763 baswap(&src, &bt_sk(session->ctrl_sock->sk)->src);
764 baswap(&dst, &bt_sk(session->ctrl_sock->sk)->dst);
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100765
766 hid->bus = BUS_BLUETOOTH;
767 hid->vendor = req->vendor;
768 hid->product = req->product;
769 hid->version = req->version;
Jiri Slabyc500c972008-05-16 11:49:16 +0200770 hid->country = req->country;
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100771
772 strncpy(hid->name, req->name, 128);
773 strncpy(hid->phys, batostr(&src), 64);
774 strncpy(hid->uniq, batostr(&dst), 64);
775
Jiri Slaby85cdaf52008-05-16 11:49:15 +0200776 hid->dev.parent = hidp_get_device(session);
Jiri Slabyc500c972008-05-16 11:49:16 +0200777 hid->ll_driver = &hidp_hid_driver;
Jiri Slaby85cdaf52008-05-16 11:49:15 +0200778
779 ret = hid_add_device(hid);
Jiri Slabyc500c972008-05-16 11:49:16 +0200780 if (ret)
781 goto err_hid;
Jiri Slaby85cdaf52008-05-16 11:49:15 +0200782
Jiri Slabyc500c972008-05-16 11:49:16 +0200783 return 0;
784err_hid:
785 hid_destroy_device(hid);
786 session->hid = NULL;
787err:
Jiri Slaby85cdaf52008-05-16 11:49:15 +0200788 return ret;
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100789}
790
Linus Torvalds1da177e2005-04-16 15:20:36 -0700791int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock, struct socket *intr_sock)
792{
793 struct hidp_session *session, *s;
794 int err;
795
796 BT_DBG("");
797
798 if (bacmp(&bt_sk(ctrl_sock->sk)->src, &bt_sk(intr_sock->sk)->src) ||
799 bacmp(&bt_sk(ctrl_sock->sk)->dst, &bt_sk(intr_sock->sk)->dst))
800 return -ENOTUNIQ;
801
Marcel Holtmann25ea6db2006-07-06 15:40:09 +0200802 session = kzalloc(sizeof(struct hidp_session), GFP_KERNEL);
Dmitry Torokhov34abf912005-09-15 02:01:40 -0500803 if (!session)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700804 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700805
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100806 BT_DBG("rd_data %p rd_size %d", req->rd_data, req->rd_size);
807
Linus Torvalds1da177e2005-04-16 15:20:36 -0700808 down_write(&hidp_session_sem);
809
810 s = __hidp_get_session(&bt_sk(ctrl_sock->sk)->dst);
811 if (s && s->state == BT_CONNECTED) {
812 err = -EEXIST;
813 goto failed;
814 }
815
816 bacpy(&session->bdaddr, &bt_sk(ctrl_sock->sk)->dst);
817
818 session->ctrl_mtu = min_t(uint, l2cap_pi(ctrl_sock->sk)->omtu, l2cap_pi(ctrl_sock->sk)->imtu);
819 session->intr_mtu = min_t(uint, l2cap_pi(intr_sock->sk)->omtu, l2cap_pi(intr_sock->sk)->imtu);
820
821 BT_DBG("ctrl mtu %d intr mtu %d", session->ctrl_mtu, session->intr_mtu);
822
823 session->ctrl_sock = ctrl_sock;
824 session->intr_sock = intr_sock;
825 session->state = BT_CONNECTED;
826
Pavel Emelyanovb24b8a22008-01-23 21:20:07 -0800827 setup_timer(&session->timer, hidp_idle_timeout, (unsigned long)session);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700828
829 skb_queue_head_init(&session->ctrl_transmit);
830 skb_queue_head_init(&session->intr_transmit);
831
832 session->flags = req->flags & (1 << HIDP_BLUETOOTH_VENDOR_ID);
833 session->idle_to = req->idle_to;
834
Jiri Slabyc500c972008-05-16 11:49:16 +0200835 if (req->rd_size > 0) {
Jiri Slaby85cdaf52008-05-16 11:49:15 +0200836 err = hidp_setup_hid(session, req);
Jiri Slabyd458a9d2008-05-16 11:49:20 +0200837 if (err && err != -ENODEV)
Jiri Slabyc500c972008-05-16 11:49:16 +0200838 goto err_skb;
839 }
840
841 if (!session->hid) {
842 err = hidp_setup_input(session, req);
843 if (err < 0)
844 goto err_skb;
Jiri Slaby85cdaf52008-05-16 11:49:15 +0200845 }
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100846
Linus Torvalds1da177e2005-04-16 15:20:36 -0700847 __hidp_link_session(session);
848
849 hidp_set_timer(session);
850
851 err = kernel_thread(hidp_session, session, CLONE_KERNEL);
852 if (err < 0)
853 goto unlink;
854
855 if (session->input) {
856 hidp_send_ctrl_message(session,
857 HIDP_TRANS_SET_PROTOCOL | HIDP_PROTO_BOOT, NULL, 0);
858 session->flags |= (1 << HIDP_BOOT_PROTOCOL_MODE);
859
860 session->leds = 0xff;
861 hidp_input_event(session->input, EV_LED, 0, 0);
862 }
863
864 up_write(&hidp_session_sem);
865 return 0;
866
867unlink:
868 hidp_del_timer(session);
869
870 __hidp_unlink_session(session);
871
Jiri Slabyc500c972008-05-16 11:49:16 +0200872 if (session->input)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700873 input_unregister_device(session->input);
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100874 if (session->hid)
Jiri Slaby85cdaf52008-05-16 11:49:15 +0200875 hid_destroy_device(session->hid);
Jiri Slabyc500c972008-05-16 11:49:16 +0200876err_skb:
877 skb_queue_purge(&session->ctrl_transmit);
878 skb_queue_purge(&session->intr_transmit);
879failed:
880 up_write(&hidp_session_sem);
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100881
Marcel Holtmann5be39462007-05-09 09:15:30 +0200882 input_free_device(session->input);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700883 kfree(session);
884 return err;
885}
886
887int hidp_del_connection(struct hidp_conndel_req *req)
888{
889 struct hidp_session *session;
890 int err = 0;
891
892 BT_DBG("");
893
894 down_read(&hidp_session_sem);
895
896 session = __hidp_get_session(&req->bdaddr);
897 if (session) {
898 if (req->flags & (1 << HIDP_VIRTUAL_CABLE_UNPLUG)) {
899 hidp_send_ctrl_message(session,
900 HIDP_TRANS_HID_CONTROL | HIDP_CTRL_VIRTUAL_CABLE_UNPLUG, NULL, 0);
901 } else {
902 /* Flush the transmit queues */
903 skb_queue_purge(&session->ctrl_transmit);
904 skb_queue_purge(&session->intr_transmit);
905
Marcel Holtmannec8dab32008-07-14 20:13:53 +0200906 /* Wakeup user-space polling for socket errors */
907 session->intr_sock->sk->sk_err = EUNATCH;
908 session->ctrl_sock->sk->sk_err = EUNATCH;
909
Linus Torvalds1da177e2005-04-16 15:20:36 -0700910 /* Kill session thread */
911 atomic_inc(&session->terminate);
912 hidp_schedule(session);
913 }
914 } else
915 err = -ENOENT;
916
917 up_read(&hidp_session_sem);
918 return err;
919}
920
921int hidp_get_connlist(struct hidp_connlist_req *req)
922{
923 struct list_head *p;
924 int err = 0, n = 0;
925
926 BT_DBG("");
927
928 down_read(&hidp_session_sem);
929
930 list_for_each(p, &hidp_session_list) {
931 struct hidp_session *session;
932 struct hidp_conninfo ci;
933
934 session = list_entry(p, struct hidp_session, list);
935
936 __hidp_copy_session(session, &ci);
937
938 if (copy_to_user(req->ci, &ci, sizeof(ci))) {
939 err = -EFAULT;
940 break;
941 }
942
943 if (++n >= req->cnum)
944 break;
945
946 req->ci++;
947 }
948 req->cnum = n;
949
950 up_read(&hidp_session_sem);
951 return err;
952}
953
954int hidp_get_conninfo(struct hidp_conninfo *ci)
955{
956 struct hidp_session *session;
957 int err = 0;
958
959 down_read(&hidp_session_sem);
960
961 session = __hidp_get_session(&ci->bdaddr);
962 if (session)
963 __hidp_copy_session(session, ci);
964 else
965 err = -ENOENT;
966
967 up_read(&hidp_session_sem);
968 return err;
969}
970
Jiri Slaby85cdaf52008-05-16 11:49:15 +0200971static const struct hid_device_id hidp_table[] = {
972 { HID_BLUETOOTH_DEVICE(HID_ANY_ID, HID_ANY_ID) },
973 { }
974};
975
976static struct hid_driver hidp_driver = {
977 .name = "generic-bluetooth",
978 .id_table = hidp_table,
979};
980
Linus Torvalds1da177e2005-04-16 15:20:36 -0700981static int __init hidp_init(void)
982{
Jiri Slaby85cdaf52008-05-16 11:49:15 +0200983 int ret;
984
Linus Torvalds1da177e2005-04-16 15:20:36 -0700985 l2cap_load();
986
987 BT_INFO("HIDP (Human Interface Emulation) ver %s", VERSION);
988
Jiri Slaby85cdaf52008-05-16 11:49:15 +0200989 ret = hid_register_driver(&hidp_driver);
990 if (ret)
991 goto err;
992
993 ret = hidp_init_sockets();
994 if (ret)
995 goto err_drv;
996
997 return 0;
998err_drv:
999 hid_unregister_driver(&hidp_driver);
1000err:
1001 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001002}
1003
1004static void __exit hidp_exit(void)
1005{
1006 hidp_cleanup_sockets();
Jiri Slaby85cdaf52008-05-16 11:49:15 +02001007 hid_unregister_driver(&hidp_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001008}
1009
1010module_init(hidp_init);
1011module_exit(hidp_exit);
1012
1013MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
1014MODULE_DESCRIPTION("Bluetooth HIDP ver " VERSION);
1015MODULE_VERSION(VERSION);
1016MODULE_LICENSE("GPL");
1017MODULE_ALIAS("bt-proto-6");