blob: 569750010fd320518001adf61ea501a577f5feb7 [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
Andrew Morton91f5cca2008-02-05 03:07:58 -0800246static int hidp_queue_report(struct hidp_session *session,
247 unsigned char *data, int size)
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100248{
249 struct sk_buff *skb;
250
Dave Young6792b5e2007-10-20 14:15:39 +0200251 BT_DBG("session %p hid %p data %p size %d", session, session->hid, data, size);
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100252
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) = 0xa2;
259 if (size > 0)
260 memcpy(skb_put(skb, size), data, size);
261
262 skb_queue_tail(&session->intr_transmit, skb);
263
264 hidp_schedule(session);
265
266 return 0;
267}
268
269static int hidp_send_report(struct hidp_session *session, struct hid_report *report)
270{
271 unsigned char buf[32];
272 int rsize;
273
274 rsize = ((report->size - 1) >> 3) + 1 + (report->id > 0);
275 if (rsize > sizeof(buf))
276 return -EIO;
277
278 hid_output_report(report, buf);
279
280 return hidp_queue_report(session, buf, rsize);
281}
282
Jiri Kosina2da31932009-11-26 16:20:56 +0100283static int hidp_output_raw_report(struct hid_device *hid, unsigned char *data, size_t count)
284{
285 if (hidp_queue_report(hid->driver_data, data, count))
286 return -ENOMEM;
287 return count;
288}
289
Linus Torvalds1da177e2005-04-16 15:20:36 -0700290static void hidp_idle_timeout(unsigned long arg)
291{
292 struct hidp_session *session = (struct hidp_session *) arg;
293
294 atomic_inc(&session->terminate);
295 hidp_schedule(session);
296}
297
Andrew Morton91f5cca2008-02-05 03:07:58 -0800298static void hidp_set_timer(struct hidp_session *session)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700299{
300 if (session->idle_to > 0)
301 mod_timer(&session->timer, jiffies + HZ * session->idle_to);
302}
303
304static inline void hidp_del_timer(struct hidp_session *session)
305{
306 if (session->idle_to > 0)
307 del_timer(&session->timer);
308}
309
310static int __hidp_send_ctrl_message(struct hidp_session *session,
311 unsigned char hdr, unsigned char *data, int size)
312{
313 struct sk_buff *skb;
314
315 BT_DBG("session %p data %p size %d", session, data, size);
316
317 if (!(skb = alloc_skb(size + 1, GFP_ATOMIC))) {
318 BT_ERR("Can't allocate memory for new frame");
319 return -ENOMEM;
320 }
321
322 *skb_put(skb, 1) = hdr;
323 if (data && size > 0)
324 memcpy(skb_put(skb, size), data, size);
325
326 skb_queue_tail(&session->ctrl_transmit, skb);
327
328 return 0;
329}
330
Dave Jonesb6f99a22007-03-22 12:27:49 -0700331static inline int hidp_send_ctrl_message(struct hidp_session *session,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700332 unsigned char hdr, unsigned char *data, int size)
333{
334 int err;
335
336 err = __hidp_send_ctrl_message(session, hdr, data, size);
337
338 hidp_schedule(session);
339
340 return err;
341}
342
Andrew Morton91f5cca2008-02-05 03:07:58 -0800343static void hidp_process_handshake(struct hidp_session *session,
344 unsigned char param)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700345{
346 BT_DBG("session %p param 0x%02x", session, param);
347
348 switch (param) {
349 case HIDP_HSHK_SUCCESSFUL:
350 /* FIXME: Call into SET_ GET_ handlers here */
351 break;
352
353 case HIDP_HSHK_NOT_READY:
354 case HIDP_HSHK_ERR_INVALID_REPORT_ID:
355 case HIDP_HSHK_ERR_UNSUPPORTED_REQUEST:
356 case HIDP_HSHK_ERR_INVALID_PARAMETER:
357 /* FIXME: Call into SET_ GET_ handlers here */
358 break;
359
360 case HIDP_HSHK_ERR_UNKNOWN:
361 break;
362
363 case HIDP_HSHK_ERR_FATAL:
364 /* Device requests a reboot, as this is the only way this error
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900365 * can be recovered. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700366 __hidp_send_ctrl_message(session,
367 HIDP_TRANS_HID_CONTROL | HIDP_CTRL_SOFT_RESET, NULL, 0);
368 break;
369
370 default:
371 __hidp_send_ctrl_message(session,
372 HIDP_TRANS_HANDSHAKE | HIDP_HSHK_ERR_INVALID_PARAMETER, NULL, 0);
373 break;
374 }
375}
376
Andrew Morton91f5cca2008-02-05 03:07:58 -0800377static void hidp_process_hid_control(struct hidp_session *session,
378 unsigned char param)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700379{
380 BT_DBG("session %p param 0x%02x", session, param);
381
Dave Youngeff001e2008-02-05 03:07:14 -0800382 if (param == HIDP_CTRL_VIRTUAL_CABLE_UNPLUG) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700383 /* Flush the transmit queues */
384 skb_queue_purge(&session->ctrl_transmit);
385 skb_queue_purge(&session->intr_transmit);
386
387 /* Kill session thread */
388 atomic_inc(&session->terminate);
Vikram Kandukuri981b1412009-07-01 11:39:58 +0530389 hidp_schedule(session);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700390 }
391}
392
Andrew Morton91f5cca2008-02-05 03:07:58 -0800393static void hidp_process_data(struct hidp_session *session, struct sk_buff *skb,
394 unsigned char param)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700395{
396 BT_DBG("session %p skb %p len %d param 0x%02x", session, skb, skb->len, param);
397
398 switch (param) {
399 case HIDP_DATA_RTYPE_INPUT:
400 hidp_set_timer(session);
401
402 if (session->input)
403 hidp_input_report(session, skb);
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100404
405 if (session->hid)
406 hid_input_report(session->hid, HID_INPUT_REPORT, skb->data, skb->len, 0);
407
Linus Torvalds1da177e2005-04-16 15:20:36 -0700408 break;
409
410 case HIDP_DATA_RTYPE_OTHER:
411 case HIDP_DATA_RTYPE_OUPUT:
412 case HIDP_DATA_RTYPE_FEATURE:
413 break;
414
415 default:
416 __hidp_send_ctrl_message(session,
417 HIDP_TRANS_HANDSHAKE | HIDP_HSHK_ERR_INVALID_PARAMETER, NULL, 0);
418 }
419}
420
Andrew Morton91f5cca2008-02-05 03:07:58 -0800421static void hidp_recv_ctrl_frame(struct hidp_session *session,
422 struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700423{
424 unsigned char hdr, type, param;
425
426 BT_DBG("session %p skb %p len %d", session, skb, skb->len);
427
428 hdr = skb->data[0];
429 skb_pull(skb, 1);
430
431 type = hdr & HIDP_HEADER_TRANS_MASK;
432 param = hdr & HIDP_HEADER_PARAM_MASK;
433
434 switch (type) {
435 case HIDP_TRANS_HANDSHAKE:
436 hidp_process_handshake(session, param);
437 break;
438
439 case HIDP_TRANS_HID_CONTROL:
440 hidp_process_hid_control(session, param);
441 break;
442
443 case HIDP_TRANS_DATA:
444 hidp_process_data(session, skb, param);
445 break;
446
447 default:
448 __hidp_send_ctrl_message(session,
449 HIDP_TRANS_HANDSHAKE | HIDP_HSHK_ERR_UNSUPPORTED_REQUEST, NULL, 0);
450 break;
451 }
452
453 kfree_skb(skb);
454}
455
Andrew Morton91f5cca2008-02-05 03:07:58 -0800456static void hidp_recv_intr_frame(struct hidp_session *session,
457 struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700458{
459 unsigned char hdr;
460
461 BT_DBG("session %p skb %p len %d", session, skb, skb->len);
462
463 hdr = skb->data[0];
464 skb_pull(skb, 1);
465
466 if (hdr == (HIDP_TRANS_DATA | HIDP_DATA_RTYPE_INPUT)) {
467 hidp_set_timer(session);
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100468
Linus Torvalds1da177e2005-04-16 15:20:36 -0700469 if (session->input)
470 hidp_input_report(session, skb);
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100471
472 if (session->hid) {
473 hid_input_report(session->hid, HID_INPUT_REPORT, skb->data, skb->len, 1);
474 BT_DBG("report len %d", skb->len);
475 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700476 } else {
477 BT_DBG("Unsupported protocol header 0x%02x", hdr);
478 }
479
480 kfree_skb(skb);
481}
482
483static int hidp_send_frame(struct socket *sock, unsigned char *data, int len)
484{
485 struct kvec iv = { data, len };
486 struct msghdr msg;
487
488 BT_DBG("sock %p data %p len %d", sock, data, len);
489
490 if (!len)
491 return 0;
492
493 memset(&msg, 0, sizeof(msg));
494
495 return kernel_sendmsg(sock, &msg, &iv, 1, len);
496}
497
David S. Millerb03efcf2005-07-08 14:57:23 -0700498static void hidp_process_transmit(struct hidp_session *session)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700499{
500 struct sk_buff *skb;
501
502 BT_DBG("session %p", session);
503
504 while ((skb = skb_dequeue(&session->ctrl_transmit))) {
505 if (hidp_send_frame(session->ctrl_sock, skb->data, skb->len) < 0) {
506 skb_queue_head(&session->ctrl_transmit, skb);
507 break;
508 }
509
510 hidp_set_timer(session);
511 kfree_skb(skb);
512 }
513
514 while ((skb = skb_dequeue(&session->intr_transmit))) {
515 if (hidp_send_frame(session->intr_sock, skb->data, skb->len) < 0) {
516 skb_queue_head(&session->intr_transmit, skb);
517 break;
518 }
519
520 hidp_set_timer(session);
521 kfree_skb(skb);
522 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700523}
524
525static int hidp_session(void *arg)
526{
527 struct hidp_session *session = arg;
528 struct sock *ctrl_sk = session->ctrl_sock->sk;
529 struct sock *intr_sk = session->intr_sock->sk;
530 struct sk_buff *skb;
531 int vendor = 0x0000, product = 0x0000;
532 wait_queue_t ctrl_wait, intr_wait;
533
534 BT_DBG("session %p", session);
535
536 if (session->input) {
537 vendor = session->input->id.vendor;
538 product = session->input->id.product;
539 }
540
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100541 if (session->hid) {
542 vendor = session->hid->vendor;
543 product = session->hid->product;
544 }
545
Linus Torvalds1da177e2005-04-16 15:20:36 -0700546 daemonize("khidpd_%04x%04x", vendor, product);
547 set_user_nice(current, -15);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700548
549 init_waitqueue_entry(&ctrl_wait, current);
550 init_waitqueue_entry(&intr_wait, current);
551 add_wait_queue(ctrl_sk->sk_sleep, &ctrl_wait);
552 add_wait_queue(intr_sk->sk_sleep, &intr_wait);
553 while (!atomic_read(&session->terminate)) {
554 set_current_state(TASK_INTERRUPTIBLE);
555
556 if (ctrl_sk->sk_state != BT_CONNECTED || intr_sk->sk_state != BT_CONNECTED)
557 break;
558
559 while ((skb = skb_dequeue(&ctrl_sk->sk_receive_queue))) {
560 skb_orphan(skb);
561 hidp_recv_ctrl_frame(session, skb);
562 }
563
564 while ((skb = skb_dequeue(&intr_sk->sk_receive_queue))) {
565 skb_orphan(skb);
566 hidp_recv_intr_frame(session, skb);
567 }
568
569 hidp_process_transmit(session);
570
571 schedule();
572 }
573 set_current_state(TASK_RUNNING);
574 remove_wait_queue(intr_sk->sk_sleep, &intr_wait);
575 remove_wait_queue(ctrl_sk->sk_sleep, &ctrl_wait);
576
577 down_write(&hidp_session_sem);
578
579 hidp_del_timer(session);
580
Linus Torvalds1da177e2005-04-16 15:20:36 -0700581 if (session->input) {
582 input_unregister_device(session->input);
Dmitry Torokhov34abf912005-09-15 02:01:40 -0500583 session->input = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700584 }
585
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100586 if (session->hid) {
Jiri Slaby85cdaf52008-05-16 11:49:15 +0200587 hid_destroy_device(session->hid);
Marcel Holtmannedad6382009-08-22 14:22:15 -0700588 session->hid = NULL;
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100589 }
590
Marcel Holtmannec8dab32008-07-14 20:13:53 +0200591 /* Wakeup user-space polling for socket errors */
592 session->intr_sock->sk->sk_err = EUNATCH;
593 session->ctrl_sock->sk->sk_err = EUNATCH;
594
595 hidp_schedule(session);
596
David Woodhouse1c398582007-07-07 14:58:39 -0400597 fput(session->intr_sock->file);
598
599 wait_event_timeout(*(ctrl_sk->sk_sleep),
600 (ctrl_sk->sk_state == BT_CLOSED), msecs_to_jiffies(500));
601
602 fput(session->ctrl_sock->file);
603
604 __hidp_unlink_session(session);
605
Linus Torvalds1da177e2005-04-16 15:20:36 -0700606 up_write(&hidp_session_sem);
607
608 kfree(session);
609 return 0;
610}
611
Marcel Holtmann0a85b962006-07-06 13:09:02 +0200612static struct device *hidp_get_device(struct hidp_session *session)
613{
614 bdaddr_t *src = &bt_sk(session->ctrl_sock->sk)->src;
615 bdaddr_t *dst = &bt_sk(session->ctrl_sock->sk)->dst;
Marcel Holtmannedad6382009-08-22 14:22:15 -0700616 struct device *device = NULL;
Marcel Holtmann0a85b962006-07-06 13:09:02 +0200617 struct hci_dev *hdev;
Marcel Holtmann0a85b962006-07-06 13:09:02 +0200618
619 hdev = hci_get_route(dst, src);
620 if (!hdev)
621 return NULL;
622
Marcel Holtmannedad6382009-08-22 14:22:15 -0700623 session->conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, dst);
624 if (session->conn)
625 device = &session->conn->dev;
Marcel Holtmann0a85b962006-07-06 13:09:02 +0200626
627 hci_dev_put(hdev);
628
Marcel Holtmannedad6382009-08-22 14:22:15 -0700629 return device;
Marcel Holtmann0a85b962006-07-06 13:09:02 +0200630}
631
Andrew Morton91f5cca2008-02-05 03:07:58 -0800632static int hidp_setup_input(struct hidp_session *session,
633 struct hidp_connadd_req *req)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700634{
Jiri Slabyc500c972008-05-16 11:49:16 +0200635 struct input_dev *input;
Marcel Holtmannedad6382009-08-22 14:22:15 -0700636 int err, i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700637
Jiri Slabyc500c972008-05-16 11:49:16 +0200638 input = input_allocate_device();
639 if (!input)
640 return -ENOMEM;
641
642 session->input = input;
643
Marcel Holtmann5be39462007-05-09 09:15:30 +0200644 input_set_drvdata(input, session);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700645
Dmitry Torokhov34abf912005-09-15 02:01:40 -0500646 input->name = "Bluetooth HID Boot Protocol Device";
647
Linus Torvalds1da177e2005-04-16 15:20:36 -0700648 input->id.bustype = BUS_BLUETOOTH;
649 input->id.vendor = req->vendor;
650 input->id.product = req->product;
651 input->id.version = req->version;
652
653 if (req->subclass & 0x40) {
654 set_bit(EV_KEY, input->evbit);
655 set_bit(EV_LED, input->evbit);
656 set_bit(EV_REP, input->evbit);
657
658 set_bit(LED_NUML, input->ledbit);
659 set_bit(LED_CAPSL, input->ledbit);
660 set_bit(LED_SCROLLL, input->ledbit);
661 set_bit(LED_COMPOSE, input->ledbit);
662 set_bit(LED_KANA, input->ledbit);
663
664 for (i = 0; i < sizeof(hidp_keycode); i++)
665 set_bit(hidp_keycode[i], input->keybit);
666 clear_bit(0, input->keybit);
667 }
668
669 if (req->subclass & 0x80) {
Jiri Slaby7b19ada2007-10-18 23:40:32 -0700670 input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL);
671 input->keybit[BIT_WORD(BTN_MOUSE)] = BIT_MASK(BTN_LEFT) |
672 BIT_MASK(BTN_RIGHT) | BIT_MASK(BTN_MIDDLE);
673 input->relbit[0] = BIT_MASK(REL_X) | BIT_MASK(REL_Y);
674 input->keybit[BIT_WORD(BTN_MOUSE)] |= BIT_MASK(BTN_SIDE) |
675 BIT_MASK(BTN_EXTRA);
676 input->relbit[0] |= BIT_MASK(REL_WHEEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700677 }
678
Marcel Holtmann5be39462007-05-09 09:15:30 +0200679 input->dev.parent = hidp_get_device(session);
Marcel Holtmann0a85b962006-07-06 13:09:02 +0200680
Linus Torvalds1da177e2005-04-16 15:20:36 -0700681 input->event = hidp_input_event;
682
Marcel Holtmannedad6382009-08-22 14:22:15 -0700683 err = input_register_device(input);
684 if (err < 0) {
685 hci_conn_put_device(session->conn);
686 return err;
687 }
688
689 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700690}
691
Marcel Holtmannf5ffd462007-02-17 23:58:53 +0100692static int hidp_open(struct hid_device *hid)
693{
694 return 0;
695}
696
697static void hidp_close(struct hid_device *hid)
698{
699}
700
Jiri Slabyc500c972008-05-16 11:49:16 +0200701static int hidp_parse(struct hid_device *hid)
702{
703 struct hidp_session *session = hid->driver_data;
704 struct hidp_connadd_req *req = session->req;
705 unsigned char *buf;
706 int ret;
707
708 buf = kmalloc(req->rd_size, GFP_KERNEL);
709 if (!buf)
710 return -ENOMEM;
711
712 if (copy_from_user(buf, req->rd_data, req->rd_size)) {
713 kfree(buf);
714 return -EFAULT;
715 }
716
717 ret = hid_parse_report(session->hid, buf, req->rd_size);
718
719 kfree(buf);
720
721 if (ret)
722 return ret;
723
724 session->req = NULL;
725
Jiri Slabyc500c972008-05-16 11:49:16 +0200726 return 0;
727}
728
729static int hidp_start(struct hid_device *hid)
730{
731 struct hidp_session *session = hid->driver_data;
732 struct hid_report *report;
733
734 list_for_each_entry(report, &hid->report_enum[HID_INPUT_REPORT].
735 report_list, list)
736 hidp_send_report(session, report);
737
738 list_for_each_entry(report, &hid->report_enum[HID_FEATURE_REPORT].
739 report_list, list)
740 hidp_send_report(session, report);
741
Jiri Slabyc500c972008-05-16 11:49:16 +0200742 return 0;
743}
744
745static void hidp_stop(struct hid_device *hid)
746{
747 struct hidp_session *session = hid->driver_data;
748
749 skb_queue_purge(&session->ctrl_transmit);
750 skb_queue_purge(&session->intr_transmit);
751
Jiri Slabyc500c972008-05-16 11:49:16 +0200752 hid->claimed = 0;
753}
754
755static struct hid_ll_driver hidp_hid_driver = {
756 .parse = hidp_parse,
757 .start = hidp_start,
758 .stop = hidp_stop,
759 .open = hidp_open,
760 .close = hidp_close,
761 .hidinput_input_event = hidp_hidinput_event,
762};
763
Jiri Slaby85cdaf52008-05-16 11:49:15 +0200764static int hidp_setup_hid(struct hidp_session *session,
Andrew Morton91f5cca2008-02-05 03:07:58 -0800765 struct hidp_connadd_req *req)
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100766{
Jiri Slabyc500c972008-05-16 11:49:16 +0200767 struct hid_device *hid;
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100768 bdaddr_t src, dst;
Marcel Holtmannedad6382009-08-22 14:22:15 -0700769 int err;
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100770
Jiri Slabyc500c972008-05-16 11:49:16 +0200771 hid = hid_allocate_device();
Marcel Holtmannedad6382009-08-22 14:22:15 -0700772 if (IS_ERR(hid))
773 return PTR_ERR(session->hid);
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100774
Jiri Slabyc500c972008-05-16 11:49:16 +0200775 session->hid = hid;
776 session->req = req;
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100777 hid->driver_data = session;
778
Jiri Slabyc500c972008-05-16 11:49:16 +0200779 baswap(&src, &bt_sk(session->ctrl_sock->sk)->src);
780 baswap(&dst, &bt_sk(session->ctrl_sock->sk)->dst);
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100781
782 hid->bus = BUS_BLUETOOTH;
783 hid->vendor = req->vendor;
784 hid->product = req->product;
785 hid->version = req->version;
Jiri Slabyc500c972008-05-16 11:49:16 +0200786 hid->country = req->country;
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100787
788 strncpy(hid->name, req->name, 128);
789 strncpy(hid->phys, batostr(&src), 64);
790 strncpy(hid->uniq, batostr(&dst), 64);
791
Jiri Slaby85cdaf52008-05-16 11:49:15 +0200792 hid->dev.parent = hidp_get_device(session);
Jiri Slabyc500c972008-05-16 11:49:16 +0200793 hid->ll_driver = &hidp_hid_driver;
Jiri Slaby85cdaf52008-05-16 11:49:15 +0200794
Jiri Kosina2da31932009-11-26 16:20:56 +0100795 hid->hid_output_raw_report = hidp_output_raw_report;
796
Marcel Holtmannedad6382009-08-22 14:22:15 -0700797 err = hid_add_device(hid);
798 if (err < 0)
799 goto failed;
Jiri Slaby85cdaf52008-05-16 11:49:15 +0200800
Jiri Slabyc500c972008-05-16 11:49:16 +0200801 return 0;
Marcel Holtmannedad6382009-08-22 14:22:15 -0700802
803failed:
Jiri Slabyc500c972008-05-16 11:49:16 +0200804 hid_destroy_device(hid);
805 session->hid = NULL;
Marcel Holtmannedad6382009-08-22 14:22:15 -0700806
807 return err;
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100808}
809
Linus Torvalds1da177e2005-04-16 15:20:36 -0700810int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock, struct socket *intr_sock)
811{
812 struct hidp_session *session, *s;
813 int err;
814
815 BT_DBG("");
816
817 if (bacmp(&bt_sk(ctrl_sock->sk)->src, &bt_sk(intr_sock->sk)->src) ||
818 bacmp(&bt_sk(ctrl_sock->sk)->dst, &bt_sk(intr_sock->sk)->dst))
819 return -ENOTUNIQ;
820
Marcel Holtmann25ea6db2006-07-06 15:40:09 +0200821 session = kzalloc(sizeof(struct hidp_session), GFP_KERNEL);
Dmitry Torokhov34abf912005-09-15 02:01:40 -0500822 if (!session)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700823 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700824
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100825 BT_DBG("rd_data %p rd_size %d", req->rd_data, req->rd_size);
826
Linus Torvalds1da177e2005-04-16 15:20:36 -0700827 down_write(&hidp_session_sem);
828
829 s = __hidp_get_session(&bt_sk(ctrl_sock->sk)->dst);
830 if (s && s->state == BT_CONNECTED) {
831 err = -EEXIST;
832 goto failed;
833 }
834
835 bacpy(&session->bdaddr, &bt_sk(ctrl_sock->sk)->dst);
836
837 session->ctrl_mtu = min_t(uint, l2cap_pi(ctrl_sock->sk)->omtu, l2cap_pi(ctrl_sock->sk)->imtu);
838 session->intr_mtu = min_t(uint, l2cap_pi(intr_sock->sk)->omtu, l2cap_pi(intr_sock->sk)->imtu);
839
840 BT_DBG("ctrl mtu %d intr mtu %d", session->ctrl_mtu, session->intr_mtu);
841
842 session->ctrl_sock = ctrl_sock;
843 session->intr_sock = intr_sock;
844 session->state = BT_CONNECTED;
845
Pavel Emelyanovb24b8a22008-01-23 21:20:07 -0800846 setup_timer(&session->timer, hidp_idle_timeout, (unsigned long)session);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700847
848 skb_queue_head_init(&session->ctrl_transmit);
849 skb_queue_head_init(&session->intr_transmit);
850
851 session->flags = req->flags & (1 << HIDP_BLUETOOTH_VENDOR_ID);
852 session->idle_to = req->idle_to;
853
Jiri Slabyc500c972008-05-16 11:49:16 +0200854 if (req->rd_size > 0) {
Jiri Slaby85cdaf52008-05-16 11:49:15 +0200855 err = hidp_setup_hid(session, req);
Jiri Slabyd458a9d2008-05-16 11:49:20 +0200856 if (err && err != -ENODEV)
Marcel Holtmannedad6382009-08-22 14:22:15 -0700857 goto purge;
Jiri Slabyc500c972008-05-16 11:49:16 +0200858 }
859
860 if (!session->hid) {
861 err = hidp_setup_input(session, req);
862 if (err < 0)
Marcel Holtmannedad6382009-08-22 14:22:15 -0700863 goto purge;
Jiri Slaby85cdaf52008-05-16 11:49:15 +0200864 }
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100865
Linus Torvalds1da177e2005-04-16 15:20:36 -0700866 __hidp_link_session(session);
867
868 hidp_set_timer(session);
869
870 err = kernel_thread(hidp_session, session, CLONE_KERNEL);
871 if (err < 0)
872 goto unlink;
873
874 if (session->input) {
875 hidp_send_ctrl_message(session,
876 HIDP_TRANS_SET_PROTOCOL | HIDP_PROTO_BOOT, NULL, 0);
877 session->flags |= (1 << HIDP_BOOT_PROTOCOL_MODE);
878
879 session->leds = 0xff;
880 hidp_input_event(session->input, EV_LED, 0, 0);
881 }
882
883 up_write(&hidp_session_sem);
884 return 0;
885
886unlink:
887 hidp_del_timer(session);
888
889 __hidp_unlink_session(session);
890
Marcel Holtmannedad6382009-08-22 14:22:15 -0700891 if (session->input) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700892 input_unregister_device(session->input);
Marcel Holtmannedad6382009-08-22 14:22:15 -0700893 session->input = NULL;
894 }
895
896 if (session->hid) {
Jiri Slaby85cdaf52008-05-16 11:49:15 +0200897 hid_destroy_device(session->hid);
Marcel Holtmannedad6382009-08-22 14:22:15 -0700898 session->hid = NULL;
899 }
900
901purge:
Jiri Slabyc500c972008-05-16 11:49:16 +0200902 skb_queue_purge(&session->ctrl_transmit);
903 skb_queue_purge(&session->intr_transmit);
Marcel Holtmannedad6382009-08-22 14:22:15 -0700904
Jiri Slabyc500c972008-05-16 11:49:16 +0200905failed:
906 up_write(&hidp_session_sem);
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100907
Marcel Holtmann5be39462007-05-09 09:15:30 +0200908 input_free_device(session->input);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700909 kfree(session);
910 return err;
911}
912
913int hidp_del_connection(struct hidp_conndel_req *req)
914{
915 struct hidp_session *session;
916 int err = 0;
917
918 BT_DBG("");
919
920 down_read(&hidp_session_sem);
921
922 session = __hidp_get_session(&req->bdaddr);
923 if (session) {
924 if (req->flags & (1 << HIDP_VIRTUAL_CABLE_UNPLUG)) {
925 hidp_send_ctrl_message(session,
926 HIDP_TRANS_HID_CONTROL | HIDP_CTRL_VIRTUAL_CABLE_UNPLUG, NULL, 0);
927 } else {
928 /* Flush the transmit queues */
929 skb_queue_purge(&session->ctrl_transmit);
930 skb_queue_purge(&session->intr_transmit);
931
Marcel Holtmannec8dab32008-07-14 20:13:53 +0200932 /* Wakeup user-space polling for socket errors */
933 session->intr_sock->sk->sk_err = EUNATCH;
934 session->ctrl_sock->sk->sk_err = EUNATCH;
935
Linus Torvalds1da177e2005-04-16 15:20:36 -0700936 /* Kill session thread */
937 atomic_inc(&session->terminate);
938 hidp_schedule(session);
939 }
940 } else
941 err = -ENOENT;
942
943 up_read(&hidp_session_sem);
944 return err;
945}
946
947int hidp_get_connlist(struct hidp_connlist_req *req)
948{
949 struct list_head *p;
950 int err = 0, n = 0;
951
952 BT_DBG("");
953
954 down_read(&hidp_session_sem);
955
956 list_for_each(p, &hidp_session_list) {
957 struct hidp_session *session;
958 struct hidp_conninfo ci;
959
960 session = list_entry(p, struct hidp_session, list);
961
962 __hidp_copy_session(session, &ci);
963
964 if (copy_to_user(req->ci, &ci, sizeof(ci))) {
965 err = -EFAULT;
966 break;
967 }
968
969 if (++n >= req->cnum)
970 break;
971
972 req->ci++;
973 }
974 req->cnum = n;
975
976 up_read(&hidp_session_sem);
977 return err;
978}
979
980int hidp_get_conninfo(struct hidp_conninfo *ci)
981{
982 struct hidp_session *session;
983 int err = 0;
984
985 down_read(&hidp_session_sem);
986
987 session = __hidp_get_session(&ci->bdaddr);
988 if (session)
989 __hidp_copy_session(session, ci);
990 else
991 err = -ENOENT;
992
993 up_read(&hidp_session_sem);
994 return err;
995}
996
Jiri Slaby85cdaf52008-05-16 11:49:15 +0200997static const struct hid_device_id hidp_table[] = {
998 { HID_BLUETOOTH_DEVICE(HID_ANY_ID, HID_ANY_ID) },
999 { }
1000};
1001
1002static struct hid_driver hidp_driver = {
1003 .name = "generic-bluetooth",
1004 .id_table = hidp_table,
1005};
1006
Linus Torvalds1da177e2005-04-16 15:20:36 -07001007static int __init hidp_init(void)
1008{
Jiri Slaby85cdaf52008-05-16 11:49:15 +02001009 int ret;
1010
Linus Torvalds1da177e2005-04-16 15:20:36 -07001011 l2cap_load();
1012
1013 BT_INFO("HIDP (Human Interface Emulation) ver %s", VERSION);
1014
Jiri Slaby85cdaf52008-05-16 11:49:15 +02001015 ret = hid_register_driver(&hidp_driver);
1016 if (ret)
1017 goto err;
1018
1019 ret = hidp_init_sockets();
1020 if (ret)
1021 goto err_drv;
1022
1023 return 0;
1024err_drv:
1025 hid_unregister_driver(&hidp_driver);
1026err:
1027 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001028}
1029
1030static void __exit hidp_exit(void)
1031{
1032 hidp_cleanup_sockets();
Jiri Slaby85cdaf52008-05-16 11:49:15 +02001033 hid_unregister_driver(&hidp_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001034}
1035
1036module_init(hidp_init);
1037module_exit(hidp_exit);
1038
1039MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
1040MODULE_DESCRIPTION("Bluetooth HIDP ver " VERSION);
1041MODULE_VERSION(VERSION);
1042MODULE_LICENSE("GPL");
1043MODULE_ALIAS("bt-proto-6");