blob: f912d6537180b184f048b18178b08a9e877fa122 [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>
Marcel Holtmann364f6352009-08-22 14:15:53 -070043#include <linux/hidraw.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070044
45#include <net/bluetooth/bluetooth.h>
Marcel Holtmann0a85b962006-07-06 13:09:02 +020046#include <net/bluetooth/hci_core.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070047#include <net/bluetooth/l2cap.h>
48
49#include "hidp.h"
50
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +010051#define VERSION "1.2"
Linus Torvalds1da177e2005-04-16 15:20:36 -070052
53static DECLARE_RWSEM(hidp_session_sem);
54static LIST_HEAD(hidp_session_list);
55
56static unsigned char hidp_keycode[256] = {
57 0, 0, 0, 0, 30, 48, 46, 32, 18, 33, 34, 35, 23, 36, 37, 38,
58 50, 49, 24, 25, 16, 19, 31, 20, 22, 47, 17, 45, 21, 44, 2, 3,
59 4, 5, 6, 7, 8, 9, 10, 11, 28, 1, 14, 15, 57, 12, 13, 26,
60 27, 43, 43, 39, 40, 41, 51, 52, 53, 58, 59, 60, 61, 62, 63, 64,
61 65, 66, 67, 68, 87, 88, 99, 70,119,110,102,104,111,107,109,106,
62 105,108,103, 69, 98, 55, 74, 78, 96, 79, 80, 81, 75, 76, 77, 71,
63 72, 73, 82, 83, 86,127,116,117,183,184,185,186,187,188,189,190,
64 191,192,193,194,134,138,130,132,128,129,131,137,133,135,136,113,
65 115,114, 0, 0, 0,121, 0, 89, 93,124, 92, 94, 95, 0, 0, 0,
66 122,123, 90, 91, 85, 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 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
71 29, 42, 56,125, 97, 54,100,126,164,166,165,163,161,115,114,113,
72 150,158,159,128,136,177,178,176,142,152,173,140
73};
74
75static unsigned char hidp_mkeyspat[] = { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 };
76
77static struct hidp_session *__hidp_get_session(bdaddr_t *bdaddr)
78{
79 struct hidp_session *session;
80 struct list_head *p;
81
82 BT_DBG("");
83
84 list_for_each(p, &hidp_session_list) {
85 session = list_entry(p, struct hidp_session, list);
86 if (!bacmp(bdaddr, &session->bdaddr))
87 return session;
88 }
89 return NULL;
90}
91
92static void __hidp_link_session(struct hidp_session *session)
93{
94 __module_get(THIS_MODULE);
95 list_add(&session->list, &hidp_session_list);
96}
97
98static void __hidp_unlink_session(struct hidp_session *session)
99{
100 list_del(&session->list);
101 module_put(THIS_MODULE);
102}
103
104static void __hidp_copy_session(struct hidp_session *session, struct hidp_conninfo *ci)
105{
106 bacpy(&ci->bdaddr, &session->bdaddr);
107
108 ci->flags = session->flags;
109 ci->state = session->state;
110
111 ci->vendor = 0x0000;
112 ci->product = 0x0000;
113 ci->version = 0x0000;
114 memset(ci->name, 0, 128);
115
116 if (session->input) {
117 ci->vendor = session->input->id.vendor;
118 ci->product = session->input->id.product;
119 ci->version = session->input->id.version;
120 if (session->input->name)
121 strncpy(ci->name, session->input->name, 128);
122 else
123 strncpy(ci->name, "HID Boot Device", 128);
124 }
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100125
126 if (session->hid) {
127 ci->vendor = session->hid->vendor;
128 ci->product = session->hid->product;
129 ci->version = session->hid->version;
130 strncpy(ci->name, session->hid->name, 128);
131 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700132}
133
Andrew Morton91f5cca2008-02-05 03:07:58 -0800134static int hidp_queue_event(struct hidp_session *session, struct input_dev *dev,
135 unsigned int type, unsigned int code, int value)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700136{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700137 unsigned char newleds;
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100138 struct sk_buff *skb;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700139
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100140 BT_DBG("session %p type %d code %d value %d", session, type, code, value);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700141
142 if (type != EV_LED)
143 return -1;
144
145 newleds = (!!test_bit(LED_KANA, dev->led) << 3) |
146 (!!test_bit(LED_COMPOSE, dev->led) << 3) |
147 (!!test_bit(LED_SCROLLL, dev->led) << 2) |
148 (!!test_bit(LED_CAPSL, dev->led) << 1) |
149 (!!test_bit(LED_NUML, dev->led));
150
151 if (session->leds == newleds)
152 return 0;
153
154 session->leds = newleds;
155
156 if (!(skb = alloc_skb(3, GFP_ATOMIC))) {
157 BT_ERR("Can't allocate memory for new frame");
158 return -ENOMEM;
159 }
160
161 *skb_put(skb, 1) = HIDP_TRANS_DATA | HIDP_DATA_RTYPE_OUPUT;
162 *skb_put(skb, 1) = 0x01;
163 *skb_put(skb, 1) = newleds;
164
165 skb_queue_tail(&session->intr_transmit, skb);
166
167 hidp_schedule(session);
168
169 return 0;
170}
171
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100172static int hidp_hidinput_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
173{
Marcel Holtmann5be39462007-05-09 09:15:30 +0200174 struct hid_device *hid = input_get_drvdata(dev);
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100175 struct hidp_session *session = hid->driver_data;
176
177 return hidp_queue_event(session, dev, type, code, value);
178}
179
180static int hidp_input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
181{
Marcel Holtmann5be39462007-05-09 09:15:30 +0200182 struct hidp_session *session = input_get_drvdata(dev);
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100183
184 return hidp_queue_event(session, dev, type, code, value);
185}
186
Linus Torvalds1da177e2005-04-16 15:20:36 -0700187static void hidp_input_report(struct hidp_session *session, struct sk_buff *skb)
188{
189 struct input_dev *dev = session->input;
190 unsigned char *keys = session->keys;
191 unsigned char *udata = skb->data + 1;
192 signed char *sdata = skb->data + 1;
193 int i, size = skb->len - 1;
194
195 switch (skb->data[0]) {
196 case 0x01: /* Keyboard report */
197 for (i = 0; i < 8; i++)
198 input_report_key(dev, hidp_keycode[i + 224], (udata[0] >> i) & 1);
199
200 /* If all the key codes have been set to 0x01, it means
201 * too many keys were pressed at the same time. */
202 if (!memcmp(udata + 2, hidp_mkeyspat, 6))
203 break;
204
205 for (i = 2; i < 8; i++) {
206 if (keys[i] > 3 && memscan(udata + 2, keys[i], 6) == udata + 8) {
207 if (hidp_keycode[keys[i]])
208 input_report_key(dev, hidp_keycode[keys[i]], 0);
209 else
210 BT_ERR("Unknown key (scancode %#x) released.", keys[i]);
211 }
212
213 if (udata[i] > 3 && memscan(keys + 2, udata[i], 6) == keys + 8) {
214 if (hidp_keycode[udata[i]])
215 input_report_key(dev, hidp_keycode[udata[i]], 1);
216 else
217 BT_ERR("Unknown key (scancode %#x) pressed.", udata[i]);
218 }
219 }
220
221 memcpy(keys, udata, 8);
222 break;
223
224 case 0x02: /* Mouse report */
225 input_report_key(dev, BTN_LEFT, sdata[0] & 0x01);
226 input_report_key(dev, BTN_RIGHT, sdata[0] & 0x02);
227 input_report_key(dev, BTN_MIDDLE, sdata[0] & 0x04);
228 input_report_key(dev, BTN_SIDE, sdata[0] & 0x08);
229 input_report_key(dev, BTN_EXTRA, sdata[0] & 0x10);
230
231 input_report_rel(dev, REL_X, sdata[1]);
232 input_report_rel(dev, REL_Y, sdata[2]);
233
234 if (size > 3)
235 input_report_rel(dev, REL_WHEEL, sdata[3]);
236 break;
237 }
238
239 input_sync(dev);
240}
241
Andrew Morton91f5cca2008-02-05 03:07:58 -0800242static int hidp_queue_report(struct hidp_session *session,
243 unsigned char *data, int size)
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100244{
245 struct sk_buff *skb;
246
Dave Young6792b5e2007-10-20 14:15:39 +0200247 BT_DBG("session %p hid %p data %p size %d", session, session->hid, data, size);
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100248
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) = 0xa2;
255 if (size > 0)
256 memcpy(skb_put(skb, size), data, size);
257
258 skb_queue_tail(&session->intr_transmit, skb);
259
260 hidp_schedule(session);
261
262 return 0;
263}
264
265static int hidp_send_report(struct hidp_session *session, struct hid_report *report)
266{
267 unsigned char buf[32];
268 int rsize;
269
270 rsize = ((report->size - 1) >> 3) + 1 + (report->id > 0);
271 if (rsize > sizeof(buf))
272 return -EIO;
273
274 hid_output_report(report, buf);
275
276 return hidp_queue_report(session, buf, rsize);
277}
278
Linus Torvalds1da177e2005-04-16 15:20:36 -0700279static void hidp_idle_timeout(unsigned long arg)
280{
281 struct hidp_session *session = (struct hidp_session *) arg;
282
283 atomic_inc(&session->terminate);
284 hidp_schedule(session);
285}
286
Andrew Morton91f5cca2008-02-05 03:07:58 -0800287static void hidp_set_timer(struct hidp_session *session)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700288{
289 if (session->idle_to > 0)
290 mod_timer(&session->timer, jiffies + HZ * session->idle_to);
291}
292
293static inline void hidp_del_timer(struct hidp_session *session)
294{
295 if (session->idle_to > 0)
296 del_timer(&session->timer);
297}
298
299static int __hidp_send_ctrl_message(struct hidp_session *session,
300 unsigned char hdr, unsigned char *data, int size)
301{
302 struct sk_buff *skb;
303
304 BT_DBG("session %p data %p size %d", session, data, size);
305
306 if (!(skb = alloc_skb(size + 1, GFP_ATOMIC))) {
307 BT_ERR("Can't allocate memory for new frame");
308 return -ENOMEM;
309 }
310
311 *skb_put(skb, 1) = hdr;
312 if (data && size > 0)
313 memcpy(skb_put(skb, size), data, size);
314
315 skb_queue_tail(&session->ctrl_transmit, skb);
316
317 return 0;
318}
319
Dave Jonesb6f99a22007-03-22 12:27:49 -0700320static inline int hidp_send_ctrl_message(struct hidp_session *session,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700321 unsigned char hdr, unsigned char *data, int size)
322{
323 int err;
324
325 err = __hidp_send_ctrl_message(session, hdr, data, size);
326
327 hidp_schedule(session);
328
329 return err;
330}
331
Andrew Morton91f5cca2008-02-05 03:07:58 -0800332static void hidp_process_handshake(struct hidp_session *session,
333 unsigned char param)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700334{
335 BT_DBG("session %p param 0x%02x", session, param);
336
337 switch (param) {
338 case HIDP_HSHK_SUCCESSFUL:
339 /* FIXME: Call into SET_ GET_ handlers here */
340 break;
341
342 case HIDP_HSHK_NOT_READY:
343 case HIDP_HSHK_ERR_INVALID_REPORT_ID:
344 case HIDP_HSHK_ERR_UNSUPPORTED_REQUEST:
345 case HIDP_HSHK_ERR_INVALID_PARAMETER:
346 /* FIXME: Call into SET_ GET_ handlers here */
347 break;
348
349 case HIDP_HSHK_ERR_UNKNOWN:
350 break;
351
352 case HIDP_HSHK_ERR_FATAL:
353 /* Device requests a reboot, as this is the only way this error
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900354 * can be recovered. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700355 __hidp_send_ctrl_message(session,
356 HIDP_TRANS_HID_CONTROL | HIDP_CTRL_SOFT_RESET, NULL, 0);
357 break;
358
359 default:
360 __hidp_send_ctrl_message(session,
361 HIDP_TRANS_HANDSHAKE | HIDP_HSHK_ERR_INVALID_PARAMETER, NULL, 0);
362 break;
363 }
364}
365
Andrew Morton91f5cca2008-02-05 03:07:58 -0800366static void hidp_process_hid_control(struct hidp_session *session,
367 unsigned char param)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700368{
369 BT_DBG("session %p param 0x%02x", session, param);
370
Dave Youngeff001e2008-02-05 03:07:14 -0800371 if (param == HIDP_CTRL_VIRTUAL_CABLE_UNPLUG) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700372 /* Flush the transmit queues */
373 skb_queue_purge(&session->ctrl_transmit);
374 skb_queue_purge(&session->intr_transmit);
375
376 /* Kill session thread */
377 atomic_inc(&session->terminate);
Vikram Kandukuri981b1412009-07-01 11:39:58 +0530378 hidp_schedule(session);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700379 }
380}
381
Andrew Morton91f5cca2008-02-05 03:07:58 -0800382static void hidp_process_data(struct hidp_session *session, struct sk_buff *skb,
383 unsigned char param)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700384{
385 BT_DBG("session %p skb %p len %d param 0x%02x", session, skb, skb->len, param);
386
387 switch (param) {
388 case HIDP_DATA_RTYPE_INPUT:
389 hidp_set_timer(session);
390
391 if (session->input)
392 hidp_input_report(session, skb);
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100393
394 if (session->hid)
395 hid_input_report(session->hid, HID_INPUT_REPORT, skb->data, skb->len, 0);
396
Linus Torvalds1da177e2005-04-16 15:20:36 -0700397 break;
398
399 case HIDP_DATA_RTYPE_OTHER:
400 case HIDP_DATA_RTYPE_OUPUT:
401 case HIDP_DATA_RTYPE_FEATURE:
402 break;
403
404 default:
405 __hidp_send_ctrl_message(session,
406 HIDP_TRANS_HANDSHAKE | HIDP_HSHK_ERR_INVALID_PARAMETER, NULL, 0);
407 }
408}
409
Andrew Morton91f5cca2008-02-05 03:07:58 -0800410static void hidp_recv_ctrl_frame(struct hidp_session *session,
411 struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700412{
413 unsigned char hdr, type, param;
414
415 BT_DBG("session %p skb %p len %d", session, skb, skb->len);
416
417 hdr = skb->data[0];
418 skb_pull(skb, 1);
419
420 type = hdr & HIDP_HEADER_TRANS_MASK;
421 param = hdr & HIDP_HEADER_PARAM_MASK;
422
423 switch (type) {
424 case HIDP_TRANS_HANDSHAKE:
425 hidp_process_handshake(session, param);
426 break;
427
428 case HIDP_TRANS_HID_CONTROL:
429 hidp_process_hid_control(session, param);
430 break;
431
432 case HIDP_TRANS_DATA:
433 hidp_process_data(session, skb, param);
434 break;
435
436 default:
437 __hidp_send_ctrl_message(session,
438 HIDP_TRANS_HANDSHAKE | HIDP_HSHK_ERR_UNSUPPORTED_REQUEST, NULL, 0);
439 break;
440 }
441
442 kfree_skb(skb);
443}
444
Andrew Morton91f5cca2008-02-05 03:07:58 -0800445static void hidp_recv_intr_frame(struct hidp_session *session,
446 struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700447{
448 unsigned char hdr;
449
450 BT_DBG("session %p skb %p len %d", session, skb, skb->len);
451
452 hdr = skb->data[0];
453 skb_pull(skb, 1);
454
455 if (hdr == (HIDP_TRANS_DATA | HIDP_DATA_RTYPE_INPUT)) {
456 hidp_set_timer(session);
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100457
Linus Torvalds1da177e2005-04-16 15:20:36 -0700458 if (session->input)
459 hidp_input_report(session, skb);
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100460
461 if (session->hid) {
462 hid_input_report(session->hid, HID_INPUT_REPORT, skb->data, skb->len, 1);
463 BT_DBG("report len %d", skb->len);
464 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700465 } else {
466 BT_DBG("Unsupported protocol header 0x%02x", hdr);
467 }
468
469 kfree_skb(skb);
470}
471
472static int hidp_send_frame(struct socket *sock, unsigned char *data, int len)
473{
474 struct kvec iv = { data, len };
475 struct msghdr msg;
476
477 BT_DBG("sock %p data %p len %d", sock, data, len);
478
479 if (!len)
480 return 0;
481
482 memset(&msg, 0, sizeof(msg));
483
484 return kernel_sendmsg(sock, &msg, &iv, 1, len);
485}
486
David S. Millerb03efcf2005-07-08 14:57:23 -0700487static void hidp_process_transmit(struct hidp_session *session)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700488{
489 struct sk_buff *skb;
490
491 BT_DBG("session %p", session);
492
493 while ((skb = skb_dequeue(&session->ctrl_transmit))) {
494 if (hidp_send_frame(session->ctrl_sock, skb->data, skb->len) < 0) {
495 skb_queue_head(&session->ctrl_transmit, skb);
496 break;
497 }
498
499 hidp_set_timer(session);
500 kfree_skb(skb);
501 }
502
503 while ((skb = skb_dequeue(&session->intr_transmit))) {
504 if (hidp_send_frame(session->intr_sock, skb->data, skb->len) < 0) {
505 skb_queue_head(&session->intr_transmit, skb);
506 break;
507 }
508
509 hidp_set_timer(session);
510 kfree_skb(skb);
511 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700512}
513
514static int hidp_session(void *arg)
515{
516 struct hidp_session *session = arg;
517 struct sock *ctrl_sk = session->ctrl_sock->sk;
518 struct sock *intr_sk = session->intr_sock->sk;
519 struct sk_buff *skb;
520 int vendor = 0x0000, product = 0x0000;
521 wait_queue_t ctrl_wait, intr_wait;
522
523 BT_DBG("session %p", session);
524
525 if (session->input) {
526 vendor = session->input->id.vendor;
527 product = session->input->id.product;
528 }
529
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100530 if (session->hid) {
531 vendor = session->hid->vendor;
532 product = session->hid->product;
533 }
534
Linus Torvalds1da177e2005-04-16 15:20:36 -0700535 daemonize("khidpd_%04x%04x", vendor, product);
536 set_user_nice(current, -15);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700537
538 init_waitqueue_entry(&ctrl_wait, current);
539 init_waitqueue_entry(&intr_wait, current);
540 add_wait_queue(ctrl_sk->sk_sleep, &ctrl_wait);
541 add_wait_queue(intr_sk->sk_sleep, &intr_wait);
542 while (!atomic_read(&session->terminate)) {
543 set_current_state(TASK_INTERRUPTIBLE);
544
545 if (ctrl_sk->sk_state != BT_CONNECTED || intr_sk->sk_state != BT_CONNECTED)
546 break;
547
548 while ((skb = skb_dequeue(&ctrl_sk->sk_receive_queue))) {
549 skb_orphan(skb);
550 hidp_recv_ctrl_frame(session, skb);
551 }
552
553 while ((skb = skb_dequeue(&intr_sk->sk_receive_queue))) {
554 skb_orphan(skb);
555 hidp_recv_intr_frame(session, skb);
556 }
557
558 hidp_process_transmit(session);
559
560 schedule();
561 }
562 set_current_state(TASK_RUNNING);
563 remove_wait_queue(intr_sk->sk_sleep, &intr_wait);
564 remove_wait_queue(ctrl_sk->sk_sleep, &ctrl_wait);
565
566 down_write(&hidp_session_sem);
567
568 hidp_del_timer(session);
569
Linus Torvalds1da177e2005-04-16 15:20:36 -0700570 if (session->input) {
571 input_unregister_device(session->input);
Dmitry Torokhov34abf912005-09-15 02:01:40 -0500572 session->input = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700573 }
574
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100575 if (session->hid) {
576 if (session->hid->claimed & HID_CLAIMED_INPUT)
577 hidinput_disconnect(session->hid);
Marcel Holtmann364f6352009-08-22 14:15:53 -0700578 if (session->hid->claimed & HID_CLAIMED_HIDRAW)
579 hidraw_disconnect(session->hid);
Jiri Slaby85cdaf52008-05-16 11:49:15 +0200580 hid_destroy_device(session->hid);
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100581 }
582
Marcel Holtmannec8dab32008-07-14 20:13:53 +0200583 /* Wakeup user-space polling for socket errors */
584 session->intr_sock->sk->sk_err = EUNATCH;
585 session->ctrl_sock->sk->sk_err = EUNATCH;
586
587 hidp_schedule(session);
588
David Woodhouse1c398582007-07-07 14:58:39 -0400589 fput(session->intr_sock->file);
590
591 wait_event_timeout(*(ctrl_sk->sk_sleep),
592 (ctrl_sk->sk_state == BT_CLOSED), msecs_to_jiffies(500));
593
594 fput(session->ctrl_sock->file);
595
596 __hidp_unlink_session(session);
597
Linus Torvalds1da177e2005-04-16 15:20:36 -0700598 up_write(&hidp_session_sem);
599
600 kfree(session);
601 return 0;
602}
603
Marcel Holtmann0a85b962006-07-06 13:09:02 +0200604static struct device *hidp_get_device(struct hidp_session *session)
605{
606 bdaddr_t *src = &bt_sk(session->ctrl_sock->sk)->src;
607 bdaddr_t *dst = &bt_sk(session->ctrl_sock->sk)->dst;
608 struct hci_dev *hdev;
609 struct hci_conn *conn;
610
611 hdev = hci_get_route(dst, src);
612 if (!hdev)
613 return NULL;
614
615 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, dst);
Marcel Holtmann0a85b962006-07-06 13:09:02 +0200616
617 hci_dev_put(hdev);
618
Marcel Holtmannb2cfcd72006-10-15 17:31:05 +0200619 return conn ? &conn->dev : NULL;
Marcel Holtmann0a85b962006-07-06 13:09:02 +0200620}
621
Andrew Morton91f5cca2008-02-05 03:07:58 -0800622static int hidp_setup_input(struct hidp_session *session,
623 struct hidp_connadd_req *req)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700624{
Jiri Slabyc500c972008-05-16 11:49:16 +0200625 struct input_dev *input;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700626 int i;
627
Jiri Slabyc500c972008-05-16 11:49:16 +0200628 input = input_allocate_device();
629 if (!input)
630 return -ENOMEM;
631
632 session->input = input;
633
Marcel Holtmann5be39462007-05-09 09:15:30 +0200634 input_set_drvdata(input, session);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700635
Dmitry Torokhov34abf912005-09-15 02:01:40 -0500636 input->name = "Bluetooth HID Boot Protocol Device";
637
Linus Torvalds1da177e2005-04-16 15:20:36 -0700638 input->id.bustype = BUS_BLUETOOTH;
639 input->id.vendor = req->vendor;
640 input->id.product = req->product;
641 input->id.version = req->version;
642
643 if (req->subclass & 0x40) {
644 set_bit(EV_KEY, input->evbit);
645 set_bit(EV_LED, input->evbit);
646 set_bit(EV_REP, input->evbit);
647
648 set_bit(LED_NUML, input->ledbit);
649 set_bit(LED_CAPSL, input->ledbit);
650 set_bit(LED_SCROLLL, input->ledbit);
651 set_bit(LED_COMPOSE, input->ledbit);
652 set_bit(LED_KANA, input->ledbit);
653
654 for (i = 0; i < sizeof(hidp_keycode); i++)
655 set_bit(hidp_keycode[i], input->keybit);
656 clear_bit(0, input->keybit);
657 }
658
659 if (req->subclass & 0x80) {
Jiri Slaby7b19ada2007-10-18 23:40:32 -0700660 input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL);
661 input->keybit[BIT_WORD(BTN_MOUSE)] = BIT_MASK(BTN_LEFT) |
662 BIT_MASK(BTN_RIGHT) | BIT_MASK(BTN_MIDDLE);
663 input->relbit[0] = BIT_MASK(REL_X) | BIT_MASK(REL_Y);
664 input->keybit[BIT_WORD(BTN_MOUSE)] |= BIT_MASK(BTN_SIDE) |
665 BIT_MASK(BTN_EXTRA);
666 input->relbit[0] |= BIT_MASK(REL_WHEEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700667 }
668
Marcel Holtmann5be39462007-05-09 09:15:30 +0200669 input->dev.parent = hidp_get_device(session);
Marcel Holtmann0a85b962006-07-06 13:09:02 +0200670
Linus Torvalds1da177e2005-04-16 15:20:36 -0700671 input->event = hidp_input_event;
672
WANG Cong53465eb2007-09-25 22:57:31 -0700673 return input_register_device(input);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700674}
675
Marcel Holtmannf5ffd462007-02-17 23:58:53 +0100676static int hidp_open(struct hid_device *hid)
677{
678 return 0;
679}
680
681static void hidp_close(struct hid_device *hid)
682{
683}
684
Jiri Slabyc500c972008-05-16 11:49:16 +0200685static int hidp_parse(struct hid_device *hid)
686{
687 struct hidp_session *session = hid->driver_data;
688 struct hidp_connadd_req *req = session->req;
689 unsigned char *buf;
690 int ret;
691
692 buf = kmalloc(req->rd_size, GFP_KERNEL);
693 if (!buf)
694 return -ENOMEM;
695
696 if (copy_from_user(buf, req->rd_data, req->rd_size)) {
697 kfree(buf);
698 return -EFAULT;
699 }
700
701 ret = hid_parse_report(session->hid, buf, req->rd_size);
702
703 kfree(buf);
704
705 if (ret)
706 return ret;
707
708 session->req = NULL;
709
Jiri Slabyc500c972008-05-16 11:49:16 +0200710 return 0;
711}
712
713static int hidp_start(struct hid_device *hid)
714{
715 struct hidp_session *session = hid->driver_data;
716 struct hid_report *report;
717
718 list_for_each_entry(report, &hid->report_enum[HID_INPUT_REPORT].
719 report_list, list)
720 hidp_send_report(session, report);
721
722 list_for_each_entry(report, &hid->report_enum[HID_FEATURE_REPORT].
723 report_list, list)
724 hidp_send_report(session, report);
725
Jiri Slabyc500c972008-05-16 11:49:16 +0200726 return 0;
727}
728
729static void hidp_stop(struct hid_device *hid)
730{
731 struct hidp_session *session = hid->driver_data;
732
733 skb_queue_purge(&session->ctrl_transmit);
734 skb_queue_purge(&session->intr_transmit);
735
736 if (hid->claimed & HID_CLAIMED_INPUT)
737 hidinput_disconnect(hid);
738 hid->claimed = 0;
739}
740
741static struct hid_ll_driver hidp_hid_driver = {
742 .parse = hidp_parse,
743 .start = hidp_start,
744 .stop = hidp_stop,
745 .open = hidp_open,
746 .close = hidp_close,
747 .hidinput_input_event = hidp_hidinput_event,
748};
749
Jiri Slaby85cdaf52008-05-16 11:49:15 +0200750static int hidp_setup_hid(struct hidp_session *session,
Andrew Morton91f5cca2008-02-05 03:07:58 -0800751 struct hidp_connadd_req *req)
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100752{
Jiri Slabyc500c972008-05-16 11:49:16 +0200753 struct hid_device *hid;
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100754 bdaddr_t src, dst;
Jiri Slaby85cdaf52008-05-16 11:49:15 +0200755 int ret;
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100756
Jiri Slabyc500c972008-05-16 11:49:16 +0200757 hid = hid_allocate_device();
758 if (IS_ERR(hid)) {
759 ret = PTR_ERR(session->hid);
760 goto err;
761 }
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100762
Jiri Slabyc500c972008-05-16 11:49:16 +0200763 session->hid = hid;
764 session->req = req;
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100765 hid->driver_data = session;
766
Jiri Slabyc500c972008-05-16 11:49:16 +0200767 baswap(&src, &bt_sk(session->ctrl_sock->sk)->src);
768 baswap(&dst, &bt_sk(session->ctrl_sock->sk)->dst);
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100769
770 hid->bus = BUS_BLUETOOTH;
771 hid->vendor = req->vendor;
772 hid->product = req->product;
773 hid->version = req->version;
Jiri Slabyc500c972008-05-16 11:49:16 +0200774 hid->country = req->country;
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100775
776 strncpy(hid->name, req->name, 128);
777 strncpy(hid->phys, batostr(&src), 64);
778 strncpy(hid->uniq, batostr(&dst), 64);
779
Jiri Slaby85cdaf52008-05-16 11:49:15 +0200780 hid->dev.parent = hidp_get_device(session);
Jiri Slabyc500c972008-05-16 11:49:16 +0200781 hid->ll_driver = &hidp_hid_driver;
Jiri Slaby85cdaf52008-05-16 11:49:15 +0200782
783 ret = hid_add_device(hid);
Jiri Slabyc500c972008-05-16 11:49:16 +0200784 if (ret)
785 goto err_hid;
Jiri Slaby85cdaf52008-05-16 11:49:15 +0200786
Jiri Slabyc500c972008-05-16 11:49:16 +0200787 return 0;
788err_hid:
789 hid_destroy_device(hid);
790 session->hid = NULL;
791err:
Jiri Slaby85cdaf52008-05-16 11:49:15 +0200792 return ret;
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100793}
794
Linus Torvalds1da177e2005-04-16 15:20:36 -0700795int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock, struct socket *intr_sock)
796{
797 struct hidp_session *session, *s;
798 int err;
799
800 BT_DBG("");
801
802 if (bacmp(&bt_sk(ctrl_sock->sk)->src, &bt_sk(intr_sock->sk)->src) ||
803 bacmp(&bt_sk(ctrl_sock->sk)->dst, &bt_sk(intr_sock->sk)->dst))
804 return -ENOTUNIQ;
805
Marcel Holtmann25ea6db2006-07-06 15:40:09 +0200806 session = kzalloc(sizeof(struct hidp_session), GFP_KERNEL);
Dmitry Torokhov34abf912005-09-15 02:01:40 -0500807 if (!session)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700808 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700809
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100810 BT_DBG("rd_data %p rd_size %d", req->rd_data, req->rd_size);
811
Linus Torvalds1da177e2005-04-16 15:20:36 -0700812 down_write(&hidp_session_sem);
813
814 s = __hidp_get_session(&bt_sk(ctrl_sock->sk)->dst);
815 if (s && s->state == BT_CONNECTED) {
816 err = -EEXIST;
817 goto failed;
818 }
819
820 bacpy(&session->bdaddr, &bt_sk(ctrl_sock->sk)->dst);
821
822 session->ctrl_mtu = min_t(uint, l2cap_pi(ctrl_sock->sk)->omtu, l2cap_pi(ctrl_sock->sk)->imtu);
823 session->intr_mtu = min_t(uint, l2cap_pi(intr_sock->sk)->omtu, l2cap_pi(intr_sock->sk)->imtu);
824
825 BT_DBG("ctrl mtu %d intr mtu %d", session->ctrl_mtu, session->intr_mtu);
826
827 session->ctrl_sock = ctrl_sock;
828 session->intr_sock = intr_sock;
829 session->state = BT_CONNECTED;
830
Pavel Emelyanovb24b8a22008-01-23 21:20:07 -0800831 setup_timer(&session->timer, hidp_idle_timeout, (unsigned long)session);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700832
833 skb_queue_head_init(&session->ctrl_transmit);
834 skb_queue_head_init(&session->intr_transmit);
835
836 session->flags = req->flags & (1 << HIDP_BLUETOOTH_VENDOR_ID);
837 session->idle_to = req->idle_to;
838
Jiri Slabyc500c972008-05-16 11:49:16 +0200839 if (req->rd_size > 0) {
Jiri Slaby85cdaf52008-05-16 11:49:15 +0200840 err = hidp_setup_hid(session, req);
Jiri Slabyd458a9d2008-05-16 11:49:20 +0200841 if (err && err != -ENODEV)
Jiri Slabyc500c972008-05-16 11:49:16 +0200842 goto err_skb;
843 }
844
845 if (!session->hid) {
846 err = hidp_setup_input(session, req);
847 if (err < 0)
848 goto err_skb;
Jiri Slaby85cdaf52008-05-16 11:49:15 +0200849 }
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100850
Linus Torvalds1da177e2005-04-16 15:20:36 -0700851 __hidp_link_session(session);
852
853 hidp_set_timer(session);
854
855 err = kernel_thread(hidp_session, session, CLONE_KERNEL);
856 if (err < 0)
857 goto unlink;
858
859 if (session->input) {
860 hidp_send_ctrl_message(session,
861 HIDP_TRANS_SET_PROTOCOL | HIDP_PROTO_BOOT, NULL, 0);
862 session->flags |= (1 << HIDP_BOOT_PROTOCOL_MODE);
863
864 session->leds = 0xff;
865 hidp_input_event(session->input, EV_LED, 0, 0);
866 }
867
868 up_write(&hidp_session_sem);
869 return 0;
870
871unlink:
872 hidp_del_timer(session);
873
874 __hidp_unlink_session(session);
875
Jiri Slabyc500c972008-05-16 11:49:16 +0200876 if (session->input)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700877 input_unregister_device(session->input);
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100878 if (session->hid)
Jiri Slaby85cdaf52008-05-16 11:49:15 +0200879 hid_destroy_device(session->hid);
Jiri Slabyc500c972008-05-16 11:49:16 +0200880err_skb:
881 skb_queue_purge(&session->ctrl_transmit);
882 skb_queue_purge(&session->intr_transmit);
883failed:
884 up_write(&hidp_session_sem);
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100885
Marcel Holtmann5be39462007-05-09 09:15:30 +0200886 input_free_device(session->input);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700887 kfree(session);
888 return err;
889}
890
891int hidp_del_connection(struct hidp_conndel_req *req)
892{
893 struct hidp_session *session;
894 int err = 0;
895
896 BT_DBG("");
897
898 down_read(&hidp_session_sem);
899
900 session = __hidp_get_session(&req->bdaddr);
901 if (session) {
902 if (req->flags & (1 << HIDP_VIRTUAL_CABLE_UNPLUG)) {
903 hidp_send_ctrl_message(session,
904 HIDP_TRANS_HID_CONTROL | HIDP_CTRL_VIRTUAL_CABLE_UNPLUG, NULL, 0);
905 } else {
906 /* Flush the transmit queues */
907 skb_queue_purge(&session->ctrl_transmit);
908 skb_queue_purge(&session->intr_transmit);
909
Marcel Holtmannec8dab32008-07-14 20:13:53 +0200910 /* Wakeup user-space polling for socket errors */
911 session->intr_sock->sk->sk_err = EUNATCH;
912 session->ctrl_sock->sk->sk_err = EUNATCH;
913
Linus Torvalds1da177e2005-04-16 15:20:36 -0700914 /* Kill session thread */
915 atomic_inc(&session->terminate);
916 hidp_schedule(session);
917 }
918 } else
919 err = -ENOENT;
920
921 up_read(&hidp_session_sem);
922 return err;
923}
924
925int hidp_get_connlist(struct hidp_connlist_req *req)
926{
927 struct list_head *p;
928 int err = 0, n = 0;
929
930 BT_DBG("");
931
932 down_read(&hidp_session_sem);
933
934 list_for_each(p, &hidp_session_list) {
935 struct hidp_session *session;
936 struct hidp_conninfo ci;
937
938 session = list_entry(p, struct hidp_session, list);
939
940 __hidp_copy_session(session, &ci);
941
942 if (copy_to_user(req->ci, &ci, sizeof(ci))) {
943 err = -EFAULT;
944 break;
945 }
946
947 if (++n >= req->cnum)
948 break;
949
950 req->ci++;
951 }
952 req->cnum = n;
953
954 up_read(&hidp_session_sem);
955 return err;
956}
957
958int hidp_get_conninfo(struct hidp_conninfo *ci)
959{
960 struct hidp_session *session;
961 int err = 0;
962
963 down_read(&hidp_session_sem);
964
965 session = __hidp_get_session(&ci->bdaddr);
966 if (session)
967 __hidp_copy_session(session, ci);
968 else
969 err = -ENOENT;
970
971 up_read(&hidp_session_sem);
972 return err;
973}
974
Jiri Slaby85cdaf52008-05-16 11:49:15 +0200975static const struct hid_device_id hidp_table[] = {
976 { HID_BLUETOOTH_DEVICE(HID_ANY_ID, HID_ANY_ID) },
977 { }
978};
979
980static struct hid_driver hidp_driver = {
981 .name = "generic-bluetooth",
982 .id_table = hidp_table,
983};
984
Linus Torvalds1da177e2005-04-16 15:20:36 -0700985static int __init hidp_init(void)
986{
Jiri Slaby85cdaf52008-05-16 11:49:15 +0200987 int ret;
988
Linus Torvalds1da177e2005-04-16 15:20:36 -0700989 l2cap_load();
990
991 BT_INFO("HIDP (Human Interface Emulation) ver %s", VERSION);
992
Jiri Slaby85cdaf52008-05-16 11:49:15 +0200993 ret = hid_register_driver(&hidp_driver);
994 if (ret)
995 goto err;
996
997 ret = hidp_init_sockets();
998 if (ret)
999 goto err_drv;
1000
1001 return 0;
1002err_drv:
1003 hid_unregister_driver(&hidp_driver);
1004err:
1005 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001006}
1007
1008static void __exit hidp_exit(void)
1009{
1010 hidp_cleanup_sockets();
Jiri Slaby85cdaf52008-05-16 11:49:15 +02001011 hid_unregister_driver(&hidp_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001012}
1013
1014module_init(hidp_init);
1015module_exit(hidp_exit);
1016
1017MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
1018MODULE_DESCRIPTION("Bluetooth HIDP ver " VERSION);
1019MODULE_VERSION(VERSION);
1020MODULE_LICENSE("GPL");
1021MODULE_ALIAS("bt-proto-6");