blob: fc6ec1e726527ac7b64ed084d2a766175c9401ff [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);
Marcel Holtmannedad6382009-08-22 14:22:15 -070096
97 hci_conn_hold_device(session->conn);
Linus Torvalds1da177e2005-04-16 15:20:36 -070098}
99
100static void __hidp_unlink_session(struct hidp_session *session)
101{
Marcel Holtmannedad6382009-08-22 14:22:15 -0700102 hci_conn_put_device(session->conn);
103
Linus Torvalds1da177e2005-04-16 15:20:36 -0700104 list_del(&session->list);
105 module_put(THIS_MODULE);
106}
107
108static void __hidp_copy_session(struct hidp_session *session, struct hidp_conninfo *ci)
109{
110 bacpy(&ci->bdaddr, &session->bdaddr);
111
112 ci->flags = session->flags;
113 ci->state = session->state;
114
115 ci->vendor = 0x0000;
116 ci->product = 0x0000;
117 ci->version = 0x0000;
118 memset(ci->name, 0, 128);
119
120 if (session->input) {
121 ci->vendor = session->input->id.vendor;
122 ci->product = session->input->id.product;
123 ci->version = session->input->id.version;
124 if (session->input->name)
125 strncpy(ci->name, session->input->name, 128);
126 else
127 strncpy(ci->name, "HID Boot Device", 128);
128 }
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100129
130 if (session->hid) {
131 ci->vendor = session->hid->vendor;
132 ci->product = session->hid->product;
133 ci->version = session->hid->version;
134 strncpy(ci->name, session->hid->name, 128);
135 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700136}
137
Andrew Morton91f5cca2008-02-05 03:07:58 -0800138static int hidp_queue_event(struct hidp_session *session, struct input_dev *dev,
139 unsigned int type, unsigned int code, int value)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700140{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700141 unsigned char newleds;
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100142 struct sk_buff *skb;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700143
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100144 BT_DBG("session %p type %d code %d value %d", session, type, code, value);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700145
146 if (type != EV_LED)
147 return -1;
148
149 newleds = (!!test_bit(LED_KANA, dev->led) << 3) |
150 (!!test_bit(LED_COMPOSE, dev->led) << 3) |
151 (!!test_bit(LED_SCROLLL, dev->led) << 2) |
152 (!!test_bit(LED_CAPSL, dev->led) << 1) |
153 (!!test_bit(LED_NUML, dev->led));
154
155 if (session->leds == newleds)
156 return 0;
157
158 session->leds = newleds;
159
160 if (!(skb = alloc_skb(3, GFP_ATOMIC))) {
161 BT_ERR("Can't allocate memory for new frame");
162 return -ENOMEM;
163 }
164
165 *skb_put(skb, 1) = HIDP_TRANS_DATA | HIDP_DATA_RTYPE_OUPUT;
166 *skb_put(skb, 1) = 0x01;
167 *skb_put(skb, 1) = newleds;
168
169 skb_queue_tail(&session->intr_transmit, skb);
170
171 hidp_schedule(session);
172
173 return 0;
174}
175
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100176static int hidp_hidinput_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
177{
Marcel Holtmann5be39462007-05-09 09:15:30 +0200178 struct hid_device *hid = input_get_drvdata(dev);
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100179 struct hidp_session *session = hid->driver_data;
180
181 return hidp_queue_event(session, dev, type, code, value);
182}
183
184static int hidp_input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
185{
Marcel Holtmann5be39462007-05-09 09:15:30 +0200186 struct hidp_session *session = input_get_drvdata(dev);
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100187
188 return hidp_queue_event(session, dev, type, code, value);
189}
190
Linus Torvalds1da177e2005-04-16 15:20:36 -0700191static void hidp_input_report(struct hidp_session *session, struct sk_buff *skb)
192{
193 struct input_dev *dev = session->input;
194 unsigned char *keys = session->keys;
195 unsigned char *udata = skb->data + 1;
196 signed char *sdata = skb->data + 1;
197 int i, size = skb->len - 1;
198
199 switch (skb->data[0]) {
200 case 0x01: /* Keyboard report */
201 for (i = 0; i < 8; i++)
202 input_report_key(dev, hidp_keycode[i + 224], (udata[0] >> i) & 1);
203
204 /* If all the key codes have been set to 0x01, it means
205 * too many keys were pressed at the same time. */
206 if (!memcmp(udata + 2, hidp_mkeyspat, 6))
207 break;
208
209 for (i = 2; i < 8; i++) {
210 if (keys[i] > 3 && memscan(udata + 2, keys[i], 6) == udata + 8) {
211 if (hidp_keycode[keys[i]])
212 input_report_key(dev, hidp_keycode[keys[i]], 0);
213 else
214 BT_ERR("Unknown key (scancode %#x) released.", keys[i]);
215 }
216
217 if (udata[i] > 3 && memscan(keys + 2, udata[i], 6) == keys + 8) {
218 if (hidp_keycode[udata[i]])
219 input_report_key(dev, hidp_keycode[udata[i]], 1);
220 else
221 BT_ERR("Unknown key (scancode %#x) pressed.", udata[i]);
222 }
223 }
224
225 memcpy(keys, udata, 8);
226 break;
227
228 case 0x02: /* Mouse report */
229 input_report_key(dev, BTN_LEFT, sdata[0] & 0x01);
230 input_report_key(dev, BTN_RIGHT, sdata[0] & 0x02);
231 input_report_key(dev, BTN_MIDDLE, sdata[0] & 0x04);
232 input_report_key(dev, BTN_SIDE, sdata[0] & 0x08);
233 input_report_key(dev, BTN_EXTRA, sdata[0] & 0x10);
234
235 input_report_rel(dev, REL_X, sdata[1]);
236 input_report_rel(dev, REL_Y, sdata[2]);
237
238 if (size > 3)
239 input_report_rel(dev, REL_WHEEL, sdata[3]);
240 break;
241 }
242
243 input_sync(dev);
244}
245
Bastien Nocera6bf82682010-01-20 12:00:42 +0000246static int __hidp_send_ctrl_message(struct hidp_session *session,
247 unsigned char hdr, unsigned char *data, int size)
248{
249 struct sk_buff *skb;
250
251 BT_DBG("session %p data %p size %d", session, data, size);
252
253 if (!(skb = alloc_skb(size + 1, GFP_ATOMIC))) {
254 BT_ERR("Can't allocate memory for new frame");
255 return -ENOMEM;
256 }
257
258 *skb_put(skb, 1) = hdr;
259 if (data && size > 0)
260 memcpy(skb_put(skb, size), data, size);
261
262 skb_queue_tail(&session->ctrl_transmit, skb);
263
264 return 0;
265}
266
267static inline int hidp_send_ctrl_message(struct hidp_session *session,
268 unsigned char hdr, unsigned char *data, int size)
269{
270 int err;
271
272 err = __hidp_send_ctrl_message(session, hdr, data, size);
273
274 hidp_schedule(session);
275
276 return err;
277}
278
Andrew Morton91f5cca2008-02-05 03:07:58 -0800279static int hidp_queue_report(struct hidp_session *session,
280 unsigned char *data, int size)
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100281{
282 struct sk_buff *skb;
283
Dave Young6792b5e2007-10-20 14:15:39 +0200284 BT_DBG("session %p hid %p data %p size %d", session, session->hid, data, size);
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100285
286 if (!(skb = alloc_skb(size + 1, GFP_ATOMIC))) {
287 BT_ERR("Can't allocate memory for new frame");
288 return -ENOMEM;
289 }
290
291 *skb_put(skb, 1) = 0xa2;
292 if (size > 0)
293 memcpy(skb_put(skb, size), data, size);
294
295 skb_queue_tail(&session->intr_transmit, skb);
296
297 hidp_schedule(session);
298
299 return 0;
300}
301
302static int hidp_send_report(struct hidp_session *session, struct hid_report *report)
303{
304 unsigned char buf[32];
305 int rsize;
306
307 rsize = ((report->size - 1) >> 3) + 1 + (report->id > 0);
308 if (rsize > sizeof(buf))
309 return -EIO;
310
311 hid_output_report(report, buf);
312
313 return hidp_queue_report(session, buf, rsize);
314}
315
Jiri Kosina2da31932009-11-26 16:20:56 +0100316static int hidp_output_raw_report(struct hid_device *hid, unsigned char *data, size_t count)
317{
Bastien Nocera6bf82682010-01-20 12:00:42 +0000318 if (hidp_send_ctrl_message(hid->driver_data,
319 HIDP_TRANS_SET_REPORT | HIDP_DATA_RTYPE_FEATURE,
320 data, count))
Jiri Kosina2da31932009-11-26 16:20:56 +0100321 return -ENOMEM;
322 return count;
323}
324
Linus Torvalds1da177e2005-04-16 15:20:36 -0700325static void hidp_idle_timeout(unsigned long arg)
326{
327 struct hidp_session *session = (struct hidp_session *) arg;
328
329 atomic_inc(&session->terminate);
330 hidp_schedule(session);
331}
332
Andrew Morton91f5cca2008-02-05 03:07:58 -0800333static void hidp_set_timer(struct hidp_session *session)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700334{
335 if (session->idle_to > 0)
336 mod_timer(&session->timer, jiffies + HZ * session->idle_to);
337}
338
339static inline void hidp_del_timer(struct hidp_session *session)
340{
341 if (session->idle_to > 0)
342 del_timer(&session->timer);
343}
344
Andrew Morton91f5cca2008-02-05 03:07:58 -0800345static void hidp_process_handshake(struct hidp_session *session,
346 unsigned char param)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700347{
348 BT_DBG("session %p param 0x%02x", session, param);
349
350 switch (param) {
351 case HIDP_HSHK_SUCCESSFUL:
352 /* FIXME: Call into SET_ GET_ handlers here */
353 break;
354
355 case HIDP_HSHK_NOT_READY:
356 case HIDP_HSHK_ERR_INVALID_REPORT_ID:
357 case HIDP_HSHK_ERR_UNSUPPORTED_REQUEST:
358 case HIDP_HSHK_ERR_INVALID_PARAMETER:
359 /* FIXME: Call into SET_ GET_ handlers here */
360 break;
361
362 case HIDP_HSHK_ERR_UNKNOWN:
363 break;
364
365 case HIDP_HSHK_ERR_FATAL:
366 /* Device requests a reboot, as this is the only way this error
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900367 * can be recovered. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700368 __hidp_send_ctrl_message(session,
369 HIDP_TRANS_HID_CONTROL | HIDP_CTRL_SOFT_RESET, NULL, 0);
370 break;
371
372 default:
373 __hidp_send_ctrl_message(session,
374 HIDP_TRANS_HANDSHAKE | HIDP_HSHK_ERR_INVALID_PARAMETER, NULL, 0);
375 break;
376 }
377}
378
Andrew Morton91f5cca2008-02-05 03:07:58 -0800379static void hidp_process_hid_control(struct hidp_session *session,
380 unsigned char param)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700381{
382 BT_DBG("session %p param 0x%02x", session, param);
383
Dave Youngeff001e2008-02-05 03:07:14 -0800384 if (param == HIDP_CTRL_VIRTUAL_CABLE_UNPLUG) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700385 /* Flush the transmit queues */
386 skb_queue_purge(&session->ctrl_transmit);
387 skb_queue_purge(&session->intr_transmit);
388
389 /* Kill session thread */
390 atomic_inc(&session->terminate);
Vikram Kandukuri981b1412009-07-01 11:39:58 +0530391 hidp_schedule(session);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700392 }
393}
394
Andrew Morton91f5cca2008-02-05 03:07:58 -0800395static void hidp_process_data(struct hidp_session *session, struct sk_buff *skb,
396 unsigned char param)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700397{
398 BT_DBG("session %p skb %p len %d param 0x%02x", session, skb, skb->len, param);
399
400 switch (param) {
401 case HIDP_DATA_RTYPE_INPUT:
402 hidp_set_timer(session);
403
404 if (session->input)
405 hidp_input_report(session, skb);
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100406
407 if (session->hid)
408 hid_input_report(session->hid, HID_INPUT_REPORT, skb->data, skb->len, 0);
409
Linus Torvalds1da177e2005-04-16 15:20:36 -0700410 break;
411
412 case HIDP_DATA_RTYPE_OTHER:
413 case HIDP_DATA_RTYPE_OUPUT:
414 case HIDP_DATA_RTYPE_FEATURE:
415 break;
416
417 default:
418 __hidp_send_ctrl_message(session,
419 HIDP_TRANS_HANDSHAKE | HIDP_HSHK_ERR_INVALID_PARAMETER, NULL, 0);
420 }
421}
422
Andrew Morton91f5cca2008-02-05 03:07:58 -0800423static void hidp_recv_ctrl_frame(struct hidp_session *session,
424 struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700425{
426 unsigned char hdr, type, param;
427
428 BT_DBG("session %p skb %p len %d", session, skb, skb->len);
429
430 hdr = skb->data[0];
431 skb_pull(skb, 1);
432
433 type = hdr & HIDP_HEADER_TRANS_MASK;
434 param = hdr & HIDP_HEADER_PARAM_MASK;
435
436 switch (type) {
437 case HIDP_TRANS_HANDSHAKE:
438 hidp_process_handshake(session, param);
439 break;
440
441 case HIDP_TRANS_HID_CONTROL:
442 hidp_process_hid_control(session, param);
443 break;
444
445 case HIDP_TRANS_DATA:
446 hidp_process_data(session, skb, param);
447 break;
448
449 default:
450 __hidp_send_ctrl_message(session,
451 HIDP_TRANS_HANDSHAKE | HIDP_HSHK_ERR_UNSUPPORTED_REQUEST, NULL, 0);
452 break;
453 }
454
455 kfree_skb(skb);
456}
457
Andrew Morton91f5cca2008-02-05 03:07:58 -0800458static void hidp_recv_intr_frame(struct hidp_session *session,
459 struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700460{
461 unsigned char hdr;
462
463 BT_DBG("session %p skb %p len %d", session, skb, skb->len);
464
465 hdr = skb->data[0];
466 skb_pull(skb, 1);
467
468 if (hdr == (HIDP_TRANS_DATA | HIDP_DATA_RTYPE_INPUT)) {
469 hidp_set_timer(session);
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100470
Linus Torvalds1da177e2005-04-16 15:20:36 -0700471 if (session->input)
472 hidp_input_report(session, skb);
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100473
474 if (session->hid) {
475 hid_input_report(session->hid, HID_INPUT_REPORT, skb->data, skb->len, 1);
476 BT_DBG("report len %d", skb->len);
477 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700478 } else {
479 BT_DBG("Unsupported protocol header 0x%02x", hdr);
480 }
481
482 kfree_skb(skb);
483}
484
485static int hidp_send_frame(struct socket *sock, unsigned char *data, int len)
486{
487 struct kvec iv = { data, len };
488 struct msghdr msg;
489
490 BT_DBG("sock %p data %p len %d", sock, data, len);
491
492 if (!len)
493 return 0;
494
495 memset(&msg, 0, sizeof(msg));
496
497 return kernel_sendmsg(sock, &msg, &iv, 1, len);
498}
499
David S. Millerb03efcf2005-07-08 14:57:23 -0700500static void hidp_process_transmit(struct hidp_session *session)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700501{
502 struct sk_buff *skb;
503
504 BT_DBG("session %p", session);
505
506 while ((skb = skb_dequeue(&session->ctrl_transmit))) {
507 if (hidp_send_frame(session->ctrl_sock, skb->data, skb->len) < 0) {
508 skb_queue_head(&session->ctrl_transmit, skb);
509 break;
510 }
511
512 hidp_set_timer(session);
513 kfree_skb(skb);
514 }
515
516 while ((skb = skb_dequeue(&session->intr_transmit))) {
517 if (hidp_send_frame(session->intr_sock, skb->data, skb->len) < 0) {
518 skb_queue_head(&session->intr_transmit, skb);
519 break;
520 }
521
522 hidp_set_timer(session);
523 kfree_skb(skb);
524 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700525}
526
527static int hidp_session(void *arg)
528{
529 struct hidp_session *session = arg;
530 struct sock *ctrl_sk = session->ctrl_sock->sk;
531 struct sock *intr_sk = session->intr_sock->sk;
532 struct sk_buff *skb;
533 int vendor = 0x0000, product = 0x0000;
534 wait_queue_t ctrl_wait, intr_wait;
535
536 BT_DBG("session %p", session);
537
538 if (session->input) {
539 vendor = session->input->id.vendor;
540 product = session->input->id.product;
541 }
542
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100543 if (session->hid) {
544 vendor = session->hid->vendor;
545 product = session->hid->product;
546 }
547
Linus Torvalds1da177e2005-04-16 15:20:36 -0700548 daemonize("khidpd_%04x%04x", vendor, product);
549 set_user_nice(current, -15);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700550
551 init_waitqueue_entry(&ctrl_wait, current);
552 init_waitqueue_entry(&intr_wait, current);
553 add_wait_queue(ctrl_sk->sk_sleep, &ctrl_wait);
554 add_wait_queue(intr_sk->sk_sleep, &intr_wait);
555 while (!atomic_read(&session->terminate)) {
556 set_current_state(TASK_INTERRUPTIBLE);
557
558 if (ctrl_sk->sk_state != BT_CONNECTED || intr_sk->sk_state != BT_CONNECTED)
559 break;
560
561 while ((skb = skb_dequeue(&ctrl_sk->sk_receive_queue))) {
562 skb_orphan(skb);
563 hidp_recv_ctrl_frame(session, skb);
564 }
565
566 while ((skb = skb_dequeue(&intr_sk->sk_receive_queue))) {
567 skb_orphan(skb);
568 hidp_recv_intr_frame(session, skb);
569 }
570
571 hidp_process_transmit(session);
572
573 schedule();
574 }
575 set_current_state(TASK_RUNNING);
576 remove_wait_queue(intr_sk->sk_sleep, &intr_wait);
577 remove_wait_queue(ctrl_sk->sk_sleep, &ctrl_wait);
578
579 down_write(&hidp_session_sem);
580
581 hidp_del_timer(session);
582
Linus Torvalds1da177e2005-04-16 15:20:36 -0700583 if (session->input) {
584 input_unregister_device(session->input);
Dmitry Torokhov34abf912005-09-15 02:01:40 -0500585 session->input = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700586 }
587
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100588 if (session->hid) {
Jiri Slaby85cdaf52008-05-16 11:49:15 +0200589 hid_destroy_device(session->hid);
Marcel Holtmannedad6382009-08-22 14:22:15 -0700590 session->hid = NULL;
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100591 }
592
Marcel Holtmannec8dab32008-07-14 20:13:53 +0200593 /* Wakeup user-space polling for socket errors */
594 session->intr_sock->sk->sk_err = EUNATCH;
595 session->ctrl_sock->sk->sk_err = EUNATCH;
596
597 hidp_schedule(session);
598
David Woodhouse1c398582007-07-07 14:58:39 -0400599 fput(session->intr_sock->file);
600
601 wait_event_timeout(*(ctrl_sk->sk_sleep),
602 (ctrl_sk->sk_state == BT_CLOSED), msecs_to_jiffies(500));
603
604 fput(session->ctrl_sock->file);
605
606 __hidp_unlink_session(session);
607
Linus Torvalds1da177e2005-04-16 15:20:36 -0700608 up_write(&hidp_session_sem);
609
610 kfree(session);
611 return 0;
612}
613
Marcel Holtmann0a85b962006-07-06 13:09:02 +0200614static struct device *hidp_get_device(struct hidp_session *session)
615{
616 bdaddr_t *src = &bt_sk(session->ctrl_sock->sk)->src;
617 bdaddr_t *dst = &bt_sk(session->ctrl_sock->sk)->dst;
Marcel Holtmannedad6382009-08-22 14:22:15 -0700618 struct device *device = NULL;
Marcel Holtmann0a85b962006-07-06 13:09:02 +0200619 struct hci_dev *hdev;
Marcel Holtmann0a85b962006-07-06 13:09:02 +0200620
621 hdev = hci_get_route(dst, src);
622 if (!hdev)
623 return NULL;
624
Marcel Holtmannedad6382009-08-22 14:22:15 -0700625 session->conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, dst);
626 if (session->conn)
627 device = &session->conn->dev;
Marcel Holtmann0a85b962006-07-06 13:09:02 +0200628
629 hci_dev_put(hdev);
630
Marcel Holtmannedad6382009-08-22 14:22:15 -0700631 return device;
Marcel Holtmann0a85b962006-07-06 13:09:02 +0200632}
633
Andrew Morton91f5cca2008-02-05 03:07:58 -0800634static int hidp_setup_input(struct hidp_session *session,
635 struct hidp_connadd_req *req)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700636{
Jiri Slabyc500c972008-05-16 11:49:16 +0200637 struct input_dev *input;
Marcel Holtmannedad6382009-08-22 14:22:15 -0700638 int err, i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700639
Jiri Slabyc500c972008-05-16 11:49:16 +0200640 input = input_allocate_device();
641 if (!input)
642 return -ENOMEM;
643
644 session->input = input;
645
Marcel Holtmann5be39462007-05-09 09:15:30 +0200646 input_set_drvdata(input, session);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700647
Dmitry Torokhov34abf912005-09-15 02:01:40 -0500648 input->name = "Bluetooth HID Boot Protocol Device";
649
Linus Torvalds1da177e2005-04-16 15:20:36 -0700650 input->id.bustype = BUS_BLUETOOTH;
651 input->id.vendor = req->vendor;
652 input->id.product = req->product;
653 input->id.version = req->version;
654
655 if (req->subclass & 0x40) {
656 set_bit(EV_KEY, input->evbit);
657 set_bit(EV_LED, input->evbit);
658 set_bit(EV_REP, input->evbit);
659
660 set_bit(LED_NUML, input->ledbit);
661 set_bit(LED_CAPSL, input->ledbit);
662 set_bit(LED_SCROLLL, input->ledbit);
663 set_bit(LED_COMPOSE, input->ledbit);
664 set_bit(LED_KANA, input->ledbit);
665
666 for (i = 0; i < sizeof(hidp_keycode); i++)
667 set_bit(hidp_keycode[i], input->keybit);
668 clear_bit(0, input->keybit);
669 }
670
671 if (req->subclass & 0x80) {
Jiri Slaby7b19ada2007-10-18 23:40:32 -0700672 input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL);
673 input->keybit[BIT_WORD(BTN_MOUSE)] = BIT_MASK(BTN_LEFT) |
674 BIT_MASK(BTN_RIGHT) | BIT_MASK(BTN_MIDDLE);
675 input->relbit[0] = BIT_MASK(REL_X) | BIT_MASK(REL_Y);
676 input->keybit[BIT_WORD(BTN_MOUSE)] |= BIT_MASK(BTN_SIDE) |
677 BIT_MASK(BTN_EXTRA);
678 input->relbit[0] |= BIT_MASK(REL_WHEEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700679 }
680
Marcel Holtmann5be39462007-05-09 09:15:30 +0200681 input->dev.parent = hidp_get_device(session);
Marcel Holtmann0a85b962006-07-06 13:09:02 +0200682
Linus Torvalds1da177e2005-04-16 15:20:36 -0700683 input->event = hidp_input_event;
684
Marcel Holtmannedad6382009-08-22 14:22:15 -0700685 err = input_register_device(input);
686 if (err < 0) {
687 hci_conn_put_device(session->conn);
688 return err;
689 }
690
691 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700692}
693
Marcel Holtmannf5ffd462007-02-17 23:58:53 +0100694static int hidp_open(struct hid_device *hid)
695{
696 return 0;
697}
698
699static void hidp_close(struct hid_device *hid)
700{
701}
702
Jiri Slabyc500c972008-05-16 11:49:16 +0200703static int hidp_parse(struct hid_device *hid)
704{
705 struct hidp_session *session = hid->driver_data;
Jiri Slabyc500c972008-05-16 11:49:16 +0200706
Michael Poole15c697c2010-02-05 12:23:43 -0500707 return hid_parse_report(session->hid, session->rd_data,
708 session->rd_size);
Jiri Slabyc500c972008-05-16 11:49:16 +0200709}
710
711static int hidp_start(struct hid_device *hid)
712{
713 struct hidp_session *session = hid->driver_data;
714 struct hid_report *report;
715
716 list_for_each_entry(report, &hid->report_enum[HID_INPUT_REPORT].
717 report_list, list)
718 hidp_send_report(session, report);
719
720 list_for_each_entry(report, &hid->report_enum[HID_FEATURE_REPORT].
721 report_list, list)
722 hidp_send_report(session, report);
723
Jiri Slabyc500c972008-05-16 11:49:16 +0200724 return 0;
725}
726
727static void hidp_stop(struct hid_device *hid)
728{
729 struct hidp_session *session = hid->driver_data;
730
731 skb_queue_purge(&session->ctrl_transmit);
732 skb_queue_purge(&session->intr_transmit);
733
Jiri Slabyc500c972008-05-16 11:49:16 +0200734 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;
Marcel Holtmannedad6382009-08-22 14:22:15 -0700751 int err;
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100752
Michael Poole15c697c2010-02-05 12:23:43 -0500753 session->rd_data = kzalloc(req->rd_size, GFP_KERNEL);
754 if (!session->rd_data)
755 return -ENOMEM;
756
757 if (copy_from_user(session->rd_data, req->rd_data, req->rd_size)) {
758 err = -EFAULT;
759 goto fault;
760 }
761 session->rd_size = req->rd_size;
762
Jiri Slabyc500c972008-05-16 11:49:16 +0200763 hid = hid_allocate_device();
Michael Poole15c697c2010-02-05 12:23:43 -0500764 if (IS_ERR(hid)) {
765 err = PTR_ERR(hid);
766 goto fault;
767 }
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100768
Jiri Slabyc500c972008-05-16 11:49:16 +0200769 session->hid = hid;
Michael Poole15c697c2010-02-05 12:23:43 -0500770
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100771 hid->driver_data = session;
772
Jiri Slabyc500c972008-05-16 11:49:16 +0200773 baswap(&src, &bt_sk(session->ctrl_sock->sk)->src);
774 baswap(&dst, &bt_sk(session->ctrl_sock->sk)->dst);
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100775
776 hid->bus = BUS_BLUETOOTH;
777 hid->vendor = req->vendor;
778 hid->product = req->product;
779 hid->version = req->version;
Jiri Slabyc500c972008-05-16 11:49:16 +0200780 hid->country = req->country;
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100781
782 strncpy(hid->name, req->name, 128);
783 strncpy(hid->phys, batostr(&src), 64);
784 strncpy(hid->uniq, batostr(&dst), 64);
785
Jiri Slaby85cdaf52008-05-16 11:49:15 +0200786 hid->dev.parent = hidp_get_device(session);
Jiri Slabyc500c972008-05-16 11:49:16 +0200787 hid->ll_driver = &hidp_hid_driver;
Jiri Slaby85cdaf52008-05-16 11:49:15 +0200788
Jiri Kosina2da31932009-11-26 16:20:56 +0100789 hid->hid_output_raw_report = hidp_output_raw_report;
790
Marcel Holtmannedad6382009-08-22 14:22:15 -0700791 err = hid_add_device(hid);
792 if (err < 0)
793 goto failed;
Jiri Slaby85cdaf52008-05-16 11:49:15 +0200794
Jiri Slabyc500c972008-05-16 11:49:16 +0200795 return 0;
Marcel Holtmannedad6382009-08-22 14:22:15 -0700796
797failed:
Jiri Slabyc500c972008-05-16 11:49:16 +0200798 hid_destroy_device(hid);
799 session->hid = NULL;
Marcel Holtmannedad6382009-08-22 14:22:15 -0700800
Michael Poole15c697c2010-02-05 12:23:43 -0500801fault:
802 kfree(session->rd_data);
803 session->rd_data = NULL;
804
Marcel Holtmannedad6382009-08-22 14:22:15 -0700805 return err;
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100806}
807
Linus Torvalds1da177e2005-04-16 15:20:36 -0700808int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock, struct socket *intr_sock)
809{
810 struct hidp_session *session, *s;
811 int err;
812
813 BT_DBG("");
814
815 if (bacmp(&bt_sk(ctrl_sock->sk)->src, &bt_sk(intr_sock->sk)->src) ||
816 bacmp(&bt_sk(ctrl_sock->sk)->dst, &bt_sk(intr_sock->sk)->dst))
817 return -ENOTUNIQ;
818
Marcel Holtmann25ea6db2006-07-06 15:40:09 +0200819 session = kzalloc(sizeof(struct hidp_session), GFP_KERNEL);
Dmitry Torokhov34abf912005-09-15 02:01:40 -0500820 if (!session)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700821 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700822
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100823 BT_DBG("rd_data %p rd_size %d", req->rd_data, req->rd_size);
824
Linus Torvalds1da177e2005-04-16 15:20:36 -0700825 down_write(&hidp_session_sem);
826
827 s = __hidp_get_session(&bt_sk(ctrl_sock->sk)->dst);
828 if (s && s->state == BT_CONNECTED) {
829 err = -EEXIST;
830 goto failed;
831 }
832
833 bacpy(&session->bdaddr, &bt_sk(ctrl_sock->sk)->dst);
834
835 session->ctrl_mtu = min_t(uint, l2cap_pi(ctrl_sock->sk)->omtu, l2cap_pi(ctrl_sock->sk)->imtu);
836 session->intr_mtu = min_t(uint, l2cap_pi(intr_sock->sk)->omtu, l2cap_pi(intr_sock->sk)->imtu);
837
838 BT_DBG("ctrl mtu %d intr mtu %d", session->ctrl_mtu, session->intr_mtu);
839
840 session->ctrl_sock = ctrl_sock;
841 session->intr_sock = intr_sock;
842 session->state = BT_CONNECTED;
843
Pavel Emelyanovb24b8a22008-01-23 21:20:07 -0800844 setup_timer(&session->timer, hidp_idle_timeout, (unsigned long)session);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700845
846 skb_queue_head_init(&session->ctrl_transmit);
847 skb_queue_head_init(&session->intr_transmit);
848
849 session->flags = req->flags & (1 << HIDP_BLUETOOTH_VENDOR_ID);
850 session->idle_to = req->idle_to;
851
Jiri Slabyc500c972008-05-16 11:49:16 +0200852 if (req->rd_size > 0) {
Jiri Slaby85cdaf52008-05-16 11:49:15 +0200853 err = hidp_setup_hid(session, req);
Jiri Slabyd458a9d2008-05-16 11:49:20 +0200854 if (err && err != -ENODEV)
Marcel Holtmannedad6382009-08-22 14:22:15 -0700855 goto purge;
Jiri Slabyc500c972008-05-16 11:49:16 +0200856 }
857
858 if (!session->hid) {
859 err = hidp_setup_input(session, req);
860 if (err < 0)
Marcel Holtmannedad6382009-08-22 14:22:15 -0700861 goto purge;
Jiri Slaby85cdaf52008-05-16 11:49:15 +0200862 }
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100863
Linus Torvalds1da177e2005-04-16 15:20:36 -0700864 __hidp_link_session(session);
865
866 hidp_set_timer(session);
867
868 err = kernel_thread(hidp_session, session, CLONE_KERNEL);
869 if (err < 0)
870 goto unlink;
871
872 if (session->input) {
873 hidp_send_ctrl_message(session,
874 HIDP_TRANS_SET_PROTOCOL | HIDP_PROTO_BOOT, NULL, 0);
875 session->flags |= (1 << HIDP_BOOT_PROTOCOL_MODE);
876
877 session->leds = 0xff;
878 hidp_input_event(session->input, EV_LED, 0, 0);
879 }
880
881 up_write(&hidp_session_sem);
882 return 0;
883
884unlink:
885 hidp_del_timer(session);
886
887 __hidp_unlink_session(session);
888
Marcel Holtmannedad6382009-08-22 14:22:15 -0700889 if (session->input) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700890 input_unregister_device(session->input);
Marcel Holtmannedad6382009-08-22 14:22:15 -0700891 session->input = NULL;
892 }
893
894 if (session->hid) {
Jiri Slaby85cdaf52008-05-16 11:49:15 +0200895 hid_destroy_device(session->hid);
Marcel Holtmannedad6382009-08-22 14:22:15 -0700896 session->hid = NULL;
897 }
898
Michael Poole15c697c2010-02-05 12:23:43 -0500899 kfree(session->rd_data);
900 session->rd_data = NULL;
901
Marcel Holtmannedad6382009-08-22 14:22:15 -0700902purge:
Jiri Slabyc500c972008-05-16 11:49:16 +0200903 skb_queue_purge(&session->ctrl_transmit);
904 skb_queue_purge(&session->intr_transmit);
Marcel Holtmannedad6382009-08-22 14:22:15 -0700905
Jiri Slabyc500c972008-05-16 11:49:16 +0200906failed:
907 up_write(&hidp_session_sem);
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100908
Marcel Holtmann5be39462007-05-09 09:15:30 +0200909 input_free_device(session->input);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700910 kfree(session);
911 return err;
912}
913
914int hidp_del_connection(struct hidp_conndel_req *req)
915{
916 struct hidp_session *session;
917 int err = 0;
918
919 BT_DBG("");
920
921 down_read(&hidp_session_sem);
922
923 session = __hidp_get_session(&req->bdaddr);
924 if (session) {
925 if (req->flags & (1 << HIDP_VIRTUAL_CABLE_UNPLUG)) {
926 hidp_send_ctrl_message(session,
927 HIDP_TRANS_HID_CONTROL | HIDP_CTRL_VIRTUAL_CABLE_UNPLUG, NULL, 0);
928 } else {
929 /* Flush the transmit queues */
930 skb_queue_purge(&session->ctrl_transmit);
931 skb_queue_purge(&session->intr_transmit);
932
Marcel Holtmannec8dab32008-07-14 20:13:53 +0200933 /* Wakeup user-space polling for socket errors */
934 session->intr_sock->sk->sk_err = EUNATCH;
935 session->ctrl_sock->sk->sk_err = EUNATCH;
936
Linus Torvalds1da177e2005-04-16 15:20:36 -0700937 /* Kill session thread */
938 atomic_inc(&session->terminate);
939 hidp_schedule(session);
940 }
941 } else
942 err = -ENOENT;
943
944 up_read(&hidp_session_sem);
945 return err;
946}
947
948int hidp_get_connlist(struct hidp_connlist_req *req)
949{
950 struct list_head *p;
951 int err = 0, n = 0;
952
953 BT_DBG("");
954
955 down_read(&hidp_session_sem);
956
957 list_for_each(p, &hidp_session_list) {
958 struct hidp_session *session;
959 struct hidp_conninfo ci;
960
961 session = list_entry(p, struct hidp_session, list);
962
963 __hidp_copy_session(session, &ci);
964
965 if (copy_to_user(req->ci, &ci, sizeof(ci))) {
966 err = -EFAULT;
967 break;
968 }
969
970 if (++n >= req->cnum)
971 break;
972
973 req->ci++;
974 }
975 req->cnum = n;
976
977 up_read(&hidp_session_sem);
978 return err;
979}
980
981int hidp_get_conninfo(struct hidp_conninfo *ci)
982{
983 struct hidp_session *session;
984 int err = 0;
985
986 down_read(&hidp_session_sem);
987
988 session = __hidp_get_session(&ci->bdaddr);
989 if (session)
990 __hidp_copy_session(session, ci);
991 else
992 err = -ENOENT;
993
994 up_read(&hidp_session_sem);
995 return err;
996}
997
Jiri Slaby85cdaf52008-05-16 11:49:15 +0200998static const struct hid_device_id hidp_table[] = {
999 { HID_BLUETOOTH_DEVICE(HID_ANY_ID, HID_ANY_ID) },
1000 { }
1001};
1002
1003static struct hid_driver hidp_driver = {
1004 .name = "generic-bluetooth",
1005 .id_table = hidp_table,
1006};
1007
Linus Torvalds1da177e2005-04-16 15:20:36 -07001008static int __init hidp_init(void)
1009{
Jiri Slaby85cdaf52008-05-16 11:49:15 +02001010 int ret;
1011
Linus Torvalds1da177e2005-04-16 15:20:36 -07001012 l2cap_load();
1013
1014 BT_INFO("HIDP (Human Interface Emulation) ver %s", VERSION);
1015
Jiri Slaby85cdaf52008-05-16 11:49:15 +02001016 ret = hid_register_driver(&hidp_driver);
1017 if (ret)
1018 goto err;
1019
1020 ret = hidp_init_sockets();
1021 if (ret)
1022 goto err_drv;
1023
1024 return 0;
1025err_drv:
1026 hid_unregister_driver(&hidp_driver);
1027err:
1028 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001029}
1030
1031static void __exit hidp_exit(void)
1032{
1033 hidp_cleanup_sockets();
Jiri Slaby85cdaf52008-05-16 11:49:15 +02001034 hid_unregister_driver(&hidp_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001035}
1036
1037module_init(hidp_init);
1038module_exit(hidp_exit);
1039
1040MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
1041MODULE_DESCRIPTION("Bluetooth HIDP ver " VERSION);
1042MODULE_VERSION(VERSION);
1043MODULE_LICENSE("GPL");
1044MODULE_ALIAS("bt-proto-6");