blob: cdb9cfafd960b5c45730b933f0515e1b79f1bfd4 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 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
13 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
16 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17
18 ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
19 COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
20 SOFTWARE IS DISCLAIMED.
21*/
22
23#include <linux/config.h>
24#include <linux/module.h>
25
26#include <linux/types.h>
27#include <linux/errno.h>
28#include <linux/kernel.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070029#include <linux/sched.h>
30#include <linux/slab.h>
31#include <linux/poll.h>
32#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>
42
43#include <net/bluetooth/bluetooth.h>
44#include <net/bluetooth/l2cap.h>
45
46#include "hidp.h"
47
48#ifndef CONFIG_BT_HIDP_DEBUG
49#undef BT_DBG
50#define BT_DBG(D...)
51#endif
52
53#define VERSION "1.1"
54
55static DECLARE_RWSEM(hidp_session_sem);
56static LIST_HEAD(hidp_session_list);
57
58static unsigned char hidp_keycode[256] = {
59 0, 0, 0, 0, 30, 48, 46, 32, 18, 33, 34, 35, 23, 36, 37, 38,
60 50, 49, 24, 25, 16, 19, 31, 20, 22, 47, 17, 45, 21, 44, 2, 3,
61 4, 5, 6, 7, 8, 9, 10, 11, 28, 1, 14, 15, 57, 12, 13, 26,
62 27, 43, 43, 39, 40, 41, 51, 52, 53, 58, 59, 60, 61, 62, 63, 64,
63 65, 66, 67, 68, 87, 88, 99, 70,119,110,102,104,111,107,109,106,
64 105,108,103, 69, 98, 55, 74, 78, 96, 79, 80, 81, 75, 76, 77, 71,
65 72, 73, 82, 83, 86,127,116,117,183,184,185,186,187,188,189,190,
66 191,192,193,194,134,138,130,132,128,129,131,137,133,135,136,113,
67 115,114, 0, 0, 0,121, 0, 89, 93,124, 92, 94, 95, 0, 0, 0,
68 122,123, 90, 91, 85, 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 0, 0, 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, 0, 0,
72 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
73 29, 42, 56,125, 97, 54,100,126,164,166,165,163,161,115,114,113,
74 150,158,159,128,136,177,178,176,142,152,173,140
75};
76
77static unsigned char hidp_mkeyspat[] = { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 };
78
79static struct hidp_session *__hidp_get_session(bdaddr_t *bdaddr)
80{
81 struct hidp_session *session;
82 struct list_head *p;
83
84 BT_DBG("");
85
86 list_for_each(p, &hidp_session_list) {
87 session = list_entry(p, struct hidp_session, list);
88 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{
102 list_del(&session->list);
103 module_put(THIS_MODULE);
104}
105
106static void __hidp_copy_session(struct hidp_session *session, struct hidp_conninfo *ci)
107{
108 bacpy(&ci->bdaddr, &session->bdaddr);
109
110 ci->flags = session->flags;
111 ci->state = session->state;
112
113 ci->vendor = 0x0000;
114 ci->product = 0x0000;
115 ci->version = 0x0000;
116 memset(ci->name, 0, 128);
117
118 if (session->input) {
119 ci->vendor = session->input->id.vendor;
120 ci->product = session->input->id.product;
121 ci->version = session->input->id.version;
122 if (session->input->name)
123 strncpy(ci->name, session->input->name, 128);
124 else
125 strncpy(ci->name, "HID Boot Device", 128);
126 }
127}
128
129static int hidp_input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
130{
131 struct hidp_session *session = dev->private;
132 struct sk_buff *skb;
133 unsigned char newleds;
134
135 BT_DBG("input %p type %d code %d value %d", dev, type, code, value);
136
137 if (type != EV_LED)
138 return -1;
139
140 newleds = (!!test_bit(LED_KANA, dev->led) << 3) |
141 (!!test_bit(LED_COMPOSE, dev->led) << 3) |
142 (!!test_bit(LED_SCROLLL, dev->led) << 2) |
143 (!!test_bit(LED_CAPSL, dev->led) << 1) |
144 (!!test_bit(LED_NUML, dev->led));
145
146 if (session->leds == newleds)
147 return 0;
148
149 session->leds = newleds;
150
151 if (!(skb = alloc_skb(3, GFP_ATOMIC))) {
152 BT_ERR("Can't allocate memory for new frame");
153 return -ENOMEM;
154 }
155
156 *skb_put(skb, 1) = HIDP_TRANS_DATA | HIDP_DATA_RTYPE_OUPUT;
157 *skb_put(skb, 1) = 0x01;
158 *skb_put(skb, 1) = newleds;
159
160 skb_queue_tail(&session->intr_transmit, skb);
161
162 hidp_schedule(session);
163
164 return 0;
165}
166
167static void hidp_input_report(struct hidp_session *session, struct sk_buff *skb)
168{
169 struct input_dev *dev = session->input;
170 unsigned char *keys = session->keys;
171 unsigned char *udata = skb->data + 1;
172 signed char *sdata = skb->data + 1;
173 int i, size = skb->len - 1;
174
175 switch (skb->data[0]) {
176 case 0x01: /* Keyboard report */
177 for (i = 0; i < 8; i++)
178 input_report_key(dev, hidp_keycode[i + 224], (udata[0] >> i) & 1);
179
180 /* If all the key codes have been set to 0x01, it means
181 * too many keys were pressed at the same time. */
182 if (!memcmp(udata + 2, hidp_mkeyspat, 6))
183 break;
184
185 for (i = 2; i < 8; i++) {
186 if (keys[i] > 3 && memscan(udata + 2, keys[i], 6) == udata + 8) {
187 if (hidp_keycode[keys[i]])
188 input_report_key(dev, hidp_keycode[keys[i]], 0);
189 else
190 BT_ERR("Unknown key (scancode %#x) released.", keys[i]);
191 }
192
193 if (udata[i] > 3 && memscan(keys + 2, udata[i], 6) == keys + 8) {
194 if (hidp_keycode[udata[i]])
195 input_report_key(dev, hidp_keycode[udata[i]], 1);
196 else
197 BT_ERR("Unknown key (scancode %#x) pressed.", udata[i]);
198 }
199 }
200
201 memcpy(keys, udata, 8);
202 break;
203
204 case 0x02: /* Mouse report */
205 input_report_key(dev, BTN_LEFT, sdata[0] & 0x01);
206 input_report_key(dev, BTN_RIGHT, sdata[0] & 0x02);
207 input_report_key(dev, BTN_MIDDLE, sdata[0] & 0x04);
208 input_report_key(dev, BTN_SIDE, sdata[0] & 0x08);
209 input_report_key(dev, BTN_EXTRA, sdata[0] & 0x10);
210
211 input_report_rel(dev, REL_X, sdata[1]);
212 input_report_rel(dev, REL_Y, sdata[2]);
213
214 if (size > 3)
215 input_report_rel(dev, REL_WHEEL, sdata[3]);
216 break;
217 }
218
219 input_sync(dev);
220}
221
222static void hidp_idle_timeout(unsigned long arg)
223{
224 struct hidp_session *session = (struct hidp_session *) arg;
225
226 atomic_inc(&session->terminate);
227 hidp_schedule(session);
228}
229
230static inline void hidp_set_timer(struct hidp_session *session)
231{
232 if (session->idle_to > 0)
233 mod_timer(&session->timer, jiffies + HZ * session->idle_to);
234}
235
236static inline void hidp_del_timer(struct hidp_session *session)
237{
238 if (session->idle_to > 0)
239 del_timer(&session->timer);
240}
241
242static int __hidp_send_ctrl_message(struct hidp_session *session,
243 unsigned char hdr, unsigned char *data, int size)
244{
245 struct sk_buff *skb;
246
247 BT_DBG("session %p data %p size %d", session, data, size);
248
249 if (!(skb = alloc_skb(size + 1, GFP_ATOMIC))) {
250 BT_ERR("Can't allocate memory for new frame");
251 return -ENOMEM;
252 }
253
254 *skb_put(skb, 1) = hdr;
255 if (data && size > 0)
256 memcpy(skb_put(skb, size), data, size);
257
258 skb_queue_tail(&session->ctrl_transmit, skb);
259
260 return 0;
261}
262
263static int inline hidp_send_ctrl_message(struct hidp_session *session,
264 unsigned char hdr, unsigned char *data, int size)
265{
266 int err;
267
268 err = __hidp_send_ctrl_message(session, hdr, data, size);
269
270 hidp_schedule(session);
271
272 return err;
273}
274
275static inline void hidp_process_handshake(struct hidp_session *session, unsigned char param)
276{
277 BT_DBG("session %p param 0x%02x", session, param);
278
279 switch (param) {
280 case HIDP_HSHK_SUCCESSFUL:
281 /* FIXME: Call into SET_ GET_ handlers here */
282 break;
283
284 case HIDP_HSHK_NOT_READY:
285 case HIDP_HSHK_ERR_INVALID_REPORT_ID:
286 case HIDP_HSHK_ERR_UNSUPPORTED_REQUEST:
287 case HIDP_HSHK_ERR_INVALID_PARAMETER:
288 /* FIXME: Call into SET_ GET_ handlers here */
289 break;
290
291 case HIDP_HSHK_ERR_UNKNOWN:
292 break;
293
294 case HIDP_HSHK_ERR_FATAL:
295 /* Device requests a reboot, as this is the only way this error
296 * can be recovered. */
297 __hidp_send_ctrl_message(session,
298 HIDP_TRANS_HID_CONTROL | HIDP_CTRL_SOFT_RESET, NULL, 0);
299 break;
300
301 default:
302 __hidp_send_ctrl_message(session,
303 HIDP_TRANS_HANDSHAKE | HIDP_HSHK_ERR_INVALID_PARAMETER, NULL, 0);
304 break;
305 }
306}
307
308static inline void hidp_process_hid_control(struct hidp_session *session, unsigned char param)
309{
310 BT_DBG("session %p param 0x%02x", session, param);
311
312 switch (param) {
313 case HIDP_CTRL_NOP:
314 break;
315
316 case HIDP_CTRL_VIRTUAL_CABLE_UNPLUG:
317 /* Flush the transmit queues */
318 skb_queue_purge(&session->ctrl_transmit);
319 skb_queue_purge(&session->intr_transmit);
320
321 /* Kill session thread */
322 atomic_inc(&session->terminate);
323 break;
324
325 case HIDP_CTRL_HARD_RESET:
326 case HIDP_CTRL_SOFT_RESET:
327 case HIDP_CTRL_SUSPEND:
328 case HIDP_CTRL_EXIT_SUSPEND:
329 /* FIXME: We have to parse these and return no error */
330 break;
331
332 default:
333 __hidp_send_ctrl_message(session,
334 HIDP_TRANS_HANDSHAKE | HIDP_HSHK_ERR_INVALID_PARAMETER, NULL, 0);
335 break;
336 }
337}
338
339static inline void hidp_process_data(struct hidp_session *session, struct sk_buff *skb, unsigned char param)
340{
341 BT_DBG("session %p skb %p len %d param 0x%02x", session, skb, skb->len, param);
342
343 switch (param) {
344 case HIDP_DATA_RTYPE_INPUT:
345 hidp_set_timer(session);
346
347 if (session->input)
348 hidp_input_report(session, skb);
349 break;
350
351 case HIDP_DATA_RTYPE_OTHER:
352 case HIDP_DATA_RTYPE_OUPUT:
353 case HIDP_DATA_RTYPE_FEATURE:
354 break;
355
356 default:
357 __hidp_send_ctrl_message(session,
358 HIDP_TRANS_HANDSHAKE | HIDP_HSHK_ERR_INVALID_PARAMETER, NULL, 0);
359 }
360}
361
362static inline void hidp_recv_ctrl_frame(struct hidp_session *session, struct sk_buff *skb)
363{
364 unsigned char hdr, type, param;
365
366 BT_DBG("session %p skb %p len %d", session, skb, skb->len);
367
368 hdr = skb->data[0];
369 skb_pull(skb, 1);
370
371 type = hdr & HIDP_HEADER_TRANS_MASK;
372 param = hdr & HIDP_HEADER_PARAM_MASK;
373
374 switch (type) {
375 case HIDP_TRANS_HANDSHAKE:
376 hidp_process_handshake(session, param);
377 break;
378
379 case HIDP_TRANS_HID_CONTROL:
380 hidp_process_hid_control(session, param);
381 break;
382
383 case HIDP_TRANS_DATA:
384 hidp_process_data(session, skb, param);
385 break;
386
387 default:
388 __hidp_send_ctrl_message(session,
389 HIDP_TRANS_HANDSHAKE | HIDP_HSHK_ERR_UNSUPPORTED_REQUEST, NULL, 0);
390 break;
391 }
392
393 kfree_skb(skb);
394}
395
396static inline void hidp_recv_intr_frame(struct hidp_session *session, struct sk_buff *skb)
397{
398 unsigned char hdr;
399
400 BT_DBG("session %p skb %p len %d", session, skb, skb->len);
401
402 hdr = skb->data[0];
403 skb_pull(skb, 1);
404
405 if (hdr == (HIDP_TRANS_DATA | HIDP_DATA_RTYPE_INPUT)) {
406 hidp_set_timer(session);
407 if (session->input)
408 hidp_input_report(session, skb);
409 } else {
410 BT_DBG("Unsupported protocol header 0x%02x", hdr);
411 }
412
413 kfree_skb(skb);
414}
415
416static int hidp_send_frame(struct socket *sock, unsigned char *data, int len)
417{
418 struct kvec iv = { data, len };
419 struct msghdr msg;
420
421 BT_DBG("sock %p data %p len %d", sock, data, len);
422
423 if (!len)
424 return 0;
425
426 memset(&msg, 0, sizeof(msg));
427
428 return kernel_sendmsg(sock, &msg, &iv, 1, len);
429}
430
David S. Millerb03efcf2005-07-08 14:57:23 -0700431static void hidp_process_transmit(struct hidp_session *session)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700432{
433 struct sk_buff *skb;
434
435 BT_DBG("session %p", session);
436
437 while ((skb = skb_dequeue(&session->ctrl_transmit))) {
438 if (hidp_send_frame(session->ctrl_sock, skb->data, skb->len) < 0) {
439 skb_queue_head(&session->ctrl_transmit, skb);
440 break;
441 }
442
443 hidp_set_timer(session);
444 kfree_skb(skb);
445 }
446
447 while ((skb = skb_dequeue(&session->intr_transmit))) {
448 if (hidp_send_frame(session->intr_sock, skb->data, skb->len) < 0) {
449 skb_queue_head(&session->intr_transmit, skb);
450 break;
451 }
452
453 hidp_set_timer(session);
454 kfree_skb(skb);
455 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700456}
457
458static int hidp_session(void *arg)
459{
460 struct hidp_session *session = arg;
461 struct sock *ctrl_sk = session->ctrl_sock->sk;
462 struct sock *intr_sk = session->intr_sock->sk;
463 struct sk_buff *skb;
464 int vendor = 0x0000, product = 0x0000;
465 wait_queue_t ctrl_wait, intr_wait;
466
467 BT_DBG("session %p", session);
468
469 if (session->input) {
470 vendor = session->input->id.vendor;
471 product = session->input->id.product;
472 }
473
474 daemonize("khidpd_%04x%04x", vendor, product);
475 set_user_nice(current, -15);
476 current->flags |= PF_NOFREEZE;
477
478 init_waitqueue_entry(&ctrl_wait, current);
479 init_waitqueue_entry(&intr_wait, current);
480 add_wait_queue(ctrl_sk->sk_sleep, &ctrl_wait);
481 add_wait_queue(intr_sk->sk_sleep, &intr_wait);
482 while (!atomic_read(&session->terminate)) {
483 set_current_state(TASK_INTERRUPTIBLE);
484
485 if (ctrl_sk->sk_state != BT_CONNECTED || intr_sk->sk_state != BT_CONNECTED)
486 break;
487
488 while ((skb = skb_dequeue(&ctrl_sk->sk_receive_queue))) {
489 skb_orphan(skb);
490 hidp_recv_ctrl_frame(session, skb);
491 }
492
493 while ((skb = skb_dequeue(&intr_sk->sk_receive_queue))) {
494 skb_orphan(skb);
495 hidp_recv_intr_frame(session, skb);
496 }
497
498 hidp_process_transmit(session);
499
500 schedule();
501 }
502 set_current_state(TASK_RUNNING);
503 remove_wait_queue(intr_sk->sk_sleep, &intr_wait);
504 remove_wait_queue(ctrl_sk->sk_sleep, &ctrl_wait);
505
506 down_write(&hidp_session_sem);
507
508 hidp_del_timer(session);
509
510 if (intr_sk->sk_state != BT_CONNECTED)
511 wait_event_timeout(*(ctrl_sk->sk_sleep), (ctrl_sk->sk_state == BT_CLOSED), HZ);
512
513 fput(session->ctrl_sock->file);
514
515 wait_event_timeout(*(intr_sk->sk_sleep), (intr_sk->sk_state == BT_CLOSED), HZ);
516
517 fput(session->intr_sock->file);
518
519 __hidp_unlink_session(session);
520
521 if (session->input) {
522 input_unregister_device(session->input);
Dmitry Torokhov34abf912005-09-15 02:01:40 -0500523 session->input = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700524 }
525
526 up_write(&hidp_session_sem);
527
528 kfree(session);
529 return 0;
530}
531
532static inline void hidp_setup_input(struct hidp_session *session, struct hidp_connadd_req *req)
533{
534 struct input_dev *input = session->input;
535 int i;
536
537 input->private = session;
538
Dmitry Torokhov34abf912005-09-15 02:01:40 -0500539 input->name = "Bluetooth HID Boot Protocol Device";
540
Linus Torvalds1da177e2005-04-16 15:20:36 -0700541 input->id.bustype = BUS_BLUETOOTH;
542 input->id.vendor = req->vendor;
543 input->id.product = req->product;
544 input->id.version = req->version;
545
546 if (req->subclass & 0x40) {
547 set_bit(EV_KEY, input->evbit);
548 set_bit(EV_LED, input->evbit);
549 set_bit(EV_REP, input->evbit);
550
551 set_bit(LED_NUML, input->ledbit);
552 set_bit(LED_CAPSL, input->ledbit);
553 set_bit(LED_SCROLLL, input->ledbit);
554 set_bit(LED_COMPOSE, input->ledbit);
555 set_bit(LED_KANA, input->ledbit);
556
557 for (i = 0; i < sizeof(hidp_keycode); i++)
558 set_bit(hidp_keycode[i], input->keybit);
559 clear_bit(0, input->keybit);
560 }
561
562 if (req->subclass & 0x80) {
563 input->evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
564 input->keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE);
565 input->relbit[0] = BIT(REL_X) | BIT(REL_Y);
566 input->keybit[LONG(BTN_MOUSE)] |= BIT(BTN_SIDE) | BIT(BTN_EXTRA);
567 input->relbit[0] |= BIT(REL_WHEEL);
568 }
569
570 input->event = hidp_input_event;
571
572 input_register_device(input);
573}
574
575int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock, struct socket *intr_sock)
576{
577 struct hidp_session *session, *s;
578 int err;
579
580 BT_DBG("");
581
582 if (bacmp(&bt_sk(ctrl_sock->sk)->src, &bt_sk(intr_sock->sk)->src) ||
583 bacmp(&bt_sk(ctrl_sock->sk)->dst, &bt_sk(intr_sock->sk)->dst))
584 return -ENOTUNIQ;
585
586 session = kmalloc(sizeof(struct hidp_session), GFP_KERNEL);
Dmitry Torokhov34abf912005-09-15 02:01:40 -0500587 if (!session)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700588 return -ENOMEM;
589 memset(session, 0, sizeof(struct hidp_session));
590
Dmitry Torokhov34abf912005-09-15 02:01:40 -0500591 session->input = input_allocate_device();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700592 if (!session->input) {
593 kfree(session);
594 return -ENOMEM;
595 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700596
597 down_write(&hidp_session_sem);
598
599 s = __hidp_get_session(&bt_sk(ctrl_sock->sk)->dst);
600 if (s && s->state == BT_CONNECTED) {
601 err = -EEXIST;
602 goto failed;
603 }
604
605 bacpy(&session->bdaddr, &bt_sk(ctrl_sock->sk)->dst);
606
607 session->ctrl_mtu = min_t(uint, l2cap_pi(ctrl_sock->sk)->omtu, l2cap_pi(ctrl_sock->sk)->imtu);
608 session->intr_mtu = min_t(uint, l2cap_pi(intr_sock->sk)->omtu, l2cap_pi(intr_sock->sk)->imtu);
609
610 BT_DBG("ctrl mtu %d intr mtu %d", session->ctrl_mtu, session->intr_mtu);
611
612 session->ctrl_sock = ctrl_sock;
613 session->intr_sock = intr_sock;
614 session->state = BT_CONNECTED;
615
616 init_timer(&session->timer);
617
618 session->timer.function = hidp_idle_timeout;
619 session->timer.data = (unsigned long) session;
620
621 skb_queue_head_init(&session->ctrl_transmit);
622 skb_queue_head_init(&session->intr_transmit);
623
624 session->flags = req->flags & (1 << HIDP_BLUETOOTH_VENDOR_ID);
625 session->idle_to = req->idle_to;
626
627 if (session->input)
628 hidp_setup_input(session, req);
629
630 __hidp_link_session(session);
631
632 hidp_set_timer(session);
633
634 err = kernel_thread(hidp_session, session, CLONE_KERNEL);
635 if (err < 0)
636 goto unlink;
637
638 if (session->input) {
639 hidp_send_ctrl_message(session,
640 HIDP_TRANS_SET_PROTOCOL | HIDP_PROTO_BOOT, NULL, 0);
641 session->flags |= (1 << HIDP_BOOT_PROTOCOL_MODE);
642
643 session->leds = 0xff;
644 hidp_input_event(session->input, EV_LED, 0, 0);
645 }
646
647 up_write(&hidp_session_sem);
648 return 0;
649
650unlink:
651 hidp_del_timer(session);
652
653 __hidp_unlink_session(session);
654
Dmitry Torokhov34abf912005-09-15 02:01:40 -0500655 if (session->input) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700656 input_unregister_device(session->input);
Dmitry Torokhov34abf912005-09-15 02:01:40 -0500657 session->input = NULL; /* don't try to free it here */
658 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700659
660failed:
661 up_write(&hidp_session_sem);
662
Jesper Juhla51482b2005-11-08 09:41:34 -0800663 kfree(session->input);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700664 kfree(session);
665 return err;
666}
667
668int hidp_del_connection(struct hidp_conndel_req *req)
669{
670 struct hidp_session *session;
671 int err = 0;
672
673 BT_DBG("");
674
675 down_read(&hidp_session_sem);
676
677 session = __hidp_get_session(&req->bdaddr);
678 if (session) {
679 if (req->flags & (1 << HIDP_VIRTUAL_CABLE_UNPLUG)) {
680 hidp_send_ctrl_message(session,
681 HIDP_TRANS_HID_CONTROL | HIDP_CTRL_VIRTUAL_CABLE_UNPLUG, NULL, 0);
682 } else {
683 /* Flush the transmit queues */
684 skb_queue_purge(&session->ctrl_transmit);
685 skb_queue_purge(&session->intr_transmit);
686
687 /* Kill session thread */
688 atomic_inc(&session->terminate);
689 hidp_schedule(session);
690 }
691 } else
692 err = -ENOENT;
693
694 up_read(&hidp_session_sem);
695 return err;
696}
697
698int hidp_get_connlist(struct hidp_connlist_req *req)
699{
700 struct list_head *p;
701 int err = 0, n = 0;
702
703 BT_DBG("");
704
705 down_read(&hidp_session_sem);
706
707 list_for_each(p, &hidp_session_list) {
708 struct hidp_session *session;
709 struct hidp_conninfo ci;
710
711 session = list_entry(p, struct hidp_session, list);
712
713 __hidp_copy_session(session, &ci);
714
715 if (copy_to_user(req->ci, &ci, sizeof(ci))) {
716 err = -EFAULT;
717 break;
718 }
719
720 if (++n >= req->cnum)
721 break;
722
723 req->ci++;
724 }
725 req->cnum = n;
726
727 up_read(&hidp_session_sem);
728 return err;
729}
730
731int hidp_get_conninfo(struct hidp_conninfo *ci)
732{
733 struct hidp_session *session;
734 int err = 0;
735
736 down_read(&hidp_session_sem);
737
738 session = __hidp_get_session(&ci->bdaddr);
739 if (session)
740 __hidp_copy_session(session, ci);
741 else
742 err = -ENOENT;
743
744 up_read(&hidp_session_sem);
745 return err;
746}
747
748static int __init hidp_init(void)
749{
750 l2cap_load();
751
752 BT_INFO("HIDP (Human Interface Emulation) ver %s", VERSION);
753
754 return hidp_init_sockets();
755}
756
757static void __exit hidp_exit(void)
758{
759 hidp_cleanup_sockets();
760}
761
762module_init(hidp_init);
763module_exit(hidp_exit);
764
765MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
766MODULE_DESCRIPTION("Bluetooth HIDP ver " VERSION);
767MODULE_VERSION(VERSION);
768MODULE_LICENSE("GPL");
769MODULE_ALIAS("bt-proto-6");