blob: 5383e6c7d09d022ab470d9c94256cca73fb2521f [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{
Vasiliy Kulikovd31dbf62010-10-30 18:26:31 +0400110 memset(ci, 0, sizeof(*ci));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700111 bacpy(&ci->bdaddr, &session->bdaddr);
112
113 ci->flags = session->flags;
114 ci->state = session->state;
115
116 ci->vendor = 0x0000;
117 ci->product = 0x0000;
118 ci->version = 0x0000;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700119
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 Kosinad4bfa032010-01-29 15:03:36 +0100316static int hidp_output_raw_report(struct hid_device *hid, unsigned char *data, size_t count,
317 unsigned char report_type)
Jiri Kosina2da31932009-11-26 16:20:56 +0100318{
Alan Ott08254112011-01-18 03:04:38 -0500319 struct hidp_session *session = hid->driver_data;
320 int ret;
321
Jiri Kosinad4bfa032010-01-29 15:03:36 +0100322 switch (report_type) {
323 case HID_FEATURE_REPORT:
324 report_type = HIDP_TRANS_SET_REPORT | HIDP_DATA_RTYPE_FEATURE;
325 break;
326 case HID_OUTPUT_REPORT:
327 report_type = HIDP_TRANS_DATA | HIDP_DATA_RTYPE_OUPUT;
328 break;
329 default:
330 return -EINVAL;
331 }
332
Alan Ott08254112011-01-18 03:04:38 -0500333 if (mutex_lock_interruptible(&session->report_mutex))
334 return -ERESTARTSYS;
335
336 /* Set up our wait, and send the report request to the device. */
337 set_bit(HIDP_WAITING_FOR_SEND_ACK, &session->flags);
Jiri Kosinad4bfa032010-01-29 15:03:36 +0100338 if (hidp_send_ctrl_message(hid->driver_data, report_type,
Alan Ott08254112011-01-18 03:04:38 -0500339 data, count)) {
340 ret = -ENOMEM;
341 goto err;
342 }
343
344 /* Wait for the ACK from the device. */
345 while (test_bit(HIDP_WAITING_FOR_SEND_ACK, &session->flags)) {
346 int res;
347
348 res = wait_event_interruptible_timeout(session->report_queue,
349 !test_bit(HIDP_WAITING_FOR_SEND_ACK, &session->flags),
350 10*HZ);
351 if (res == 0) {
352 /* timeout */
353 ret = -EIO;
354 goto err;
355 }
356 if (res < 0) {
357 /* signal */
358 ret = -ERESTARTSYS;
359 goto err;
360 }
361 }
362
363 if (!session->output_report_success) {
364 ret = -EIO;
365 goto err;
366 }
367
368 ret = count;
369
370err:
371 clear_bit(HIDP_WAITING_FOR_SEND_ACK, &session->flags);
372 mutex_unlock(&session->report_mutex);
373 return ret;
Jiri Kosina2da31932009-11-26 16:20:56 +0100374}
375
Linus Torvalds1da177e2005-04-16 15:20:36 -0700376static void hidp_idle_timeout(unsigned long arg)
377{
378 struct hidp_session *session = (struct hidp_session *) arg;
379
380 atomic_inc(&session->terminate);
381 hidp_schedule(session);
382}
383
Andrew Morton91f5cca2008-02-05 03:07:58 -0800384static void hidp_set_timer(struct hidp_session *session)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700385{
386 if (session->idle_to > 0)
387 mod_timer(&session->timer, jiffies + HZ * session->idle_to);
388}
389
390static inline void hidp_del_timer(struct hidp_session *session)
391{
392 if (session->idle_to > 0)
393 del_timer(&session->timer);
394}
395
Andrew Morton91f5cca2008-02-05 03:07:58 -0800396static void hidp_process_handshake(struct hidp_session *session,
397 unsigned char param)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700398{
399 BT_DBG("session %p param 0x%02x", session, param);
Alan Ott08254112011-01-18 03:04:38 -0500400 session->output_report_success = 0; /* default condition */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700401
402 switch (param) {
403 case HIDP_HSHK_SUCCESSFUL:
404 /* FIXME: Call into SET_ GET_ handlers here */
Alan Ott08254112011-01-18 03:04:38 -0500405 session->output_report_success = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700406 break;
407
408 case HIDP_HSHK_NOT_READY:
409 case HIDP_HSHK_ERR_INVALID_REPORT_ID:
410 case HIDP_HSHK_ERR_UNSUPPORTED_REQUEST:
411 case HIDP_HSHK_ERR_INVALID_PARAMETER:
412 /* FIXME: Call into SET_ GET_ handlers here */
413 break;
414
415 case HIDP_HSHK_ERR_UNKNOWN:
416 break;
417
418 case HIDP_HSHK_ERR_FATAL:
419 /* Device requests a reboot, as this is the only way this error
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900420 * can be recovered. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700421 __hidp_send_ctrl_message(session,
422 HIDP_TRANS_HID_CONTROL | HIDP_CTRL_SOFT_RESET, NULL, 0);
423 break;
424
425 default:
426 __hidp_send_ctrl_message(session,
427 HIDP_TRANS_HANDSHAKE | HIDP_HSHK_ERR_INVALID_PARAMETER, NULL, 0);
428 break;
429 }
Alan Ott08254112011-01-18 03:04:38 -0500430
431 /* Wake up the waiting thread. */
432 if (test_bit(HIDP_WAITING_FOR_SEND_ACK, &session->flags)) {
433 clear_bit(HIDP_WAITING_FOR_SEND_ACK, &session->flags);
434 wake_up_interruptible(&session->report_queue);
435 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700436}
437
Andrew Morton91f5cca2008-02-05 03:07:58 -0800438static void hidp_process_hid_control(struct hidp_session *session,
439 unsigned char param)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700440{
441 BT_DBG("session %p param 0x%02x", session, param);
442
Dave Youngeff001e2008-02-05 03:07:14 -0800443 if (param == HIDP_CTRL_VIRTUAL_CABLE_UNPLUG) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700444 /* Flush the transmit queues */
445 skb_queue_purge(&session->ctrl_transmit);
446 skb_queue_purge(&session->intr_transmit);
447
448 /* Kill session thread */
449 atomic_inc(&session->terminate);
Vikram Kandukuri981b1412009-07-01 11:39:58 +0530450 hidp_schedule(session);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700451 }
452}
453
Andrew Morton91f5cca2008-02-05 03:07:58 -0800454static void hidp_process_data(struct hidp_session *session, struct sk_buff *skb,
455 unsigned char param)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700456{
457 BT_DBG("session %p skb %p len %d param 0x%02x", session, skb, skb->len, param);
458
459 switch (param) {
460 case HIDP_DATA_RTYPE_INPUT:
461 hidp_set_timer(session);
462
463 if (session->input)
464 hidp_input_report(session, skb);
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100465
466 if (session->hid)
467 hid_input_report(session->hid, HID_INPUT_REPORT, skb->data, skb->len, 0);
468
Linus Torvalds1da177e2005-04-16 15:20:36 -0700469 break;
470
471 case HIDP_DATA_RTYPE_OTHER:
472 case HIDP_DATA_RTYPE_OUPUT:
473 case HIDP_DATA_RTYPE_FEATURE:
474 break;
475
476 default:
477 __hidp_send_ctrl_message(session,
478 HIDP_TRANS_HANDSHAKE | HIDP_HSHK_ERR_INVALID_PARAMETER, NULL, 0);
479 }
480}
481
Andrew Morton91f5cca2008-02-05 03:07:58 -0800482static void hidp_recv_ctrl_frame(struct hidp_session *session,
483 struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700484{
485 unsigned char hdr, type, param;
486
487 BT_DBG("session %p skb %p len %d", session, skb, skb->len);
488
489 hdr = skb->data[0];
490 skb_pull(skb, 1);
491
492 type = hdr & HIDP_HEADER_TRANS_MASK;
493 param = hdr & HIDP_HEADER_PARAM_MASK;
494
495 switch (type) {
496 case HIDP_TRANS_HANDSHAKE:
497 hidp_process_handshake(session, param);
498 break;
499
500 case HIDP_TRANS_HID_CONTROL:
501 hidp_process_hid_control(session, param);
502 break;
503
504 case HIDP_TRANS_DATA:
505 hidp_process_data(session, skb, param);
506 break;
507
508 default:
509 __hidp_send_ctrl_message(session,
510 HIDP_TRANS_HANDSHAKE | HIDP_HSHK_ERR_UNSUPPORTED_REQUEST, NULL, 0);
511 break;
512 }
513
514 kfree_skb(skb);
515}
516
Andrew Morton91f5cca2008-02-05 03:07:58 -0800517static void hidp_recv_intr_frame(struct hidp_session *session,
518 struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700519{
520 unsigned char hdr;
521
522 BT_DBG("session %p skb %p len %d", session, skb, skb->len);
523
524 hdr = skb->data[0];
525 skb_pull(skb, 1);
526
527 if (hdr == (HIDP_TRANS_DATA | HIDP_DATA_RTYPE_INPUT)) {
528 hidp_set_timer(session);
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100529
Linus Torvalds1da177e2005-04-16 15:20:36 -0700530 if (session->input)
531 hidp_input_report(session, skb);
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100532
533 if (session->hid) {
534 hid_input_report(session->hid, HID_INPUT_REPORT, skb->data, skb->len, 1);
535 BT_DBG("report len %d", skb->len);
536 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700537 } else {
538 BT_DBG("Unsupported protocol header 0x%02x", hdr);
539 }
540
541 kfree_skb(skb);
542}
543
544static int hidp_send_frame(struct socket *sock, unsigned char *data, int len)
545{
546 struct kvec iv = { data, len };
547 struct msghdr msg;
548
549 BT_DBG("sock %p data %p len %d", sock, data, len);
550
551 if (!len)
552 return 0;
553
554 memset(&msg, 0, sizeof(msg));
555
556 return kernel_sendmsg(sock, &msg, &iv, 1, len);
557}
558
David S. Millerb03efcf2005-07-08 14:57:23 -0700559static void hidp_process_transmit(struct hidp_session *session)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700560{
561 struct sk_buff *skb;
562
563 BT_DBG("session %p", session);
564
565 while ((skb = skb_dequeue(&session->ctrl_transmit))) {
566 if (hidp_send_frame(session->ctrl_sock, skb->data, skb->len) < 0) {
567 skb_queue_head(&session->ctrl_transmit, skb);
568 break;
569 }
570
571 hidp_set_timer(session);
572 kfree_skb(skb);
573 }
574
575 while ((skb = skb_dequeue(&session->intr_transmit))) {
576 if (hidp_send_frame(session->intr_sock, skb->data, skb->len) < 0) {
577 skb_queue_head(&session->intr_transmit, skb);
578 break;
579 }
580
581 hidp_set_timer(session);
582 kfree_skb(skb);
583 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700584}
585
586static int hidp_session(void *arg)
587{
588 struct hidp_session *session = arg;
589 struct sock *ctrl_sk = session->ctrl_sock->sk;
590 struct sock *intr_sk = session->intr_sock->sk;
591 struct sk_buff *skb;
592 int vendor = 0x0000, product = 0x0000;
593 wait_queue_t ctrl_wait, intr_wait;
594
595 BT_DBG("session %p", session);
596
597 if (session->input) {
598 vendor = session->input->id.vendor;
599 product = session->input->id.product;
600 }
601
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100602 if (session->hid) {
603 vendor = session->hid->vendor;
604 product = session->hid->product;
605 }
606
Linus Torvalds1da177e2005-04-16 15:20:36 -0700607 daemonize("khidpd_%04x%04x", vendor, product);
608 set_user_nice(current, -15);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700609
610 init_waitqueue_entry(&ctrl_wait, current);
611 init_waitqueue_entry(&intr_wait, current);
Eric Dumazetaa395142010-04-20 13:03:51 +0000612 add_wait_queue(sk_sleep(ctrl_sk), &ctrl_wait);
613 add_wait_queue(sk_sleep(intr_sk), &intr_wait);
Alan Ott0f69dca2011-01-18 03:04:37 -0500614 session->waiting_for_startup = 0;
615 wake_up_interruptible(&session->startup_queue);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700616 while (!atomic_read(&session->terminate)) {
617 set_current_state(TASK_INTERRUPTIBLE);
618
619 if (ctrl_sk->sk_state != BT_CONNECTED || intr_sk->sk_state != BT_CONNECTED)
620 break;
621
622 while ((skb = skb_dequeue(&ctrl_sk->sk_receive_queue))) {
623 skb_orphan(skb);
624 hidp_recv_ctrl_frame(session, skb);
625 }
626
627 while ((skb = skb_dequeue(&intr_sk->sk_receive_queue))) {
628 skb_orphan(skb);
629 hidp_recv_intr_frame(session, skb);
630 }
631
632 hidp_process_transmit(session);
633
634 schedule();
635 }
636 set_current_state(TASK_RUNNING);
Eric Dumazetaa395142010-04-20 13:03:51 +0000637 remove_wait_queue(sk_sleep(intr_sk), &intr_wait);
638 remove_wait_queue(sk_sleep(ctrl_sk), &ctrl_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700639
640 down_write(&hidp_session_sem);
641
642 hidp_del_timer(session);
643
Linus Torvalds1da177e2005-04-16 15:20:36 -0700644 if (session->input) {
645 input_unregister_device(session->input);
Dmitry Torokhov34abf912005-09-15 02:01:40 -0500646 session->input = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700647 }
648
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100649 if (session->hid) {
Jiri Slaby85cdaf52008-05-16 11:49:15 +0200650 hid_destroy_device(session->hid);
Marcel Holtmannedad6382009-08-22 14:22:15 -0700651 session->hid = NULL;
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100652 }
653
Marcel Holtmannec8dab32008-07-14 20:13:53 +0200654 /* Wakeup user-space polling for socket errors */
655 session->intr_sock->sk->sk_err = EUNATCH;
656 session->ctrl_sock->sk->sk_err = EUNATCH;
657
658 hidp_schedule(session);
659
David Woodhouse1c398582007-07-07 14:58:39 -0400660 fput(session->intr_sock->file);
661
Eric Dumazetaa395142010-04-20 13:03:51 +0000662 wait_event_timeout(*(sk_sleep(ctrl_sk)),
David Woodhouse1c398582007-07-07 14:58:39 -0400663 (ctrl_sk->sk_state == BT_CLOSED), msecs_to_jiffies(500));
664
665 fput(session->ctrl_sock->file);
666
667 __hidp_unlink_session(session);
668
Linus Torvalds1da177e2005-04-16 15:20:36 -0700669 up_write(&hidp_session_sem);
670
671 kfree(session);
672 return 0;
673}
674
Marcel Holtmann0a85b962006-07-06 13:09:02 +0200675static struct device *hidp_get_device(struct hidp_session *session)
676{
677 bdaddr_t *src = &bt_sk(session->ctrl_sock->sk)->src;
678 bdaddr_t *dst = &bt_sk(session->ctrl_sock->sk)->dst;
Marcel Holtmannedad6382009-08-22 14:22:15 -0700679 struct device *device = NULL;
Marcel Holtmann0a85b962006-07-06 13:09:02 +0200680 struct hci_dev *hdev;
Marcel Holtmann0a85b962006-07-06 13:09:02 +0200681
682 hdev = hci_get_route(dst, src);
683 if (!hdev)
684 return NULL;
685
Marcel Holtmannedad6382009-08-22 14:22:15 -0700686 session->conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, dst);
687 if (session->conn)
688 device = &session->conn->dev;
Marcel Holtmann0a85b962006-07-06 13:09:02 +0200689
690 hci_dev_put(hdev);
691
Marcel Holtmannedad6382009-08-22 14:22:15 -0700692 return device;
Marcel Holtmann0a85b962006-07-06 13:09:02 +0200693}
694
Andrew Morton91f5cca2008-02-05 03:07:58 -0800695static int hidp_setup_input(struct hidp_session *session,
696 struct hidp_connadd_req *req)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700697{
Jiri Slabyc500c972008-05-16 11:49:16 +0200698 struct input_dev *input;
Marcel Holtmannedad6382009-08-22 14:22:15 -0700699 int err, i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700700
Jiri Slabyc500c972008-05-16 11:49:16 +0200701 input = input_allocate_device();
702 if (!input)
703 return -ENOMEM;
704
705 session->input = input;
706
Marcel Holtmann5be39462007-05-09 09:15:30 +0200707 input_set_drvdata(input, session);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708
Dmitry Torokhov34abf912005-09-15 02:01:40 -0500709 input->name = "Bluetooth HID Boot Protocol Device";
710
Linus Torvalds1da177e2005-04-16 15:20:36 -0700711 input->id.bustype = BUS_BLUETOOTH;
712 input->id.vendor = req->vendor;
713 input->id.product = req->product;
714 input->id.version = req->version;
715
716 if (req->subclass & 0x40) {
717 set_bit(EV_KEY, input->evbit);
718 set_bit(EV_LED, input->evbit);
719 set_bit(EV_REP, input->evbit);
720
721 set_bit(LED_NUML, input->ledbit);
722 set_bit(LED_CAPSL, input->ledbit);
723 set_bit(LED_SCROLLL, input->ledbit);
724 set_bit(LED_COMPOSE, input->ledbit);
725 set_bit(LED_KANA, input->ledbit);
726
727 for (i = 0; i < sizeof(hidp_keycode); i++)
728 set_bit(hidp_keycode[i], input->keybit);
729 clear_bit(0, input->keybit);
730 }
731
732 if (req->subclass & 0x80) {
Jiri Slaby7b19ada2007-10-18 23:40:32 -0700733 input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL);
734 input->keybit[BIT_WORD(BTN_MOUSE)] = BIT_MASK(BTN_LEFT) |
735 BIT_MASK(BTN_RIGHT) | BIT_MASK(BTN_MIDDLE);
736 input->relbit[0] = BIT_MASK(REL_X) | BIT_MASK(REL_Y);
737 input->keybit[BIT_WORD(BTN_MOUSE)] |= BIT_MASK(BTN_SIDE) |
738 BIT_MASK(BTN_EXTRA);
739 input->relbit[0] |= BIT_MASK(REL_WHEEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700740 }
741
Marcel Holtmann5be39462007-05-09 09:15:30 +0200742 input->dev.parent = hidp_get_device(session);
Marcel Holtmann0a85b962006-07-06 13:09:02 +0200743
Linus Torvalds1da177e2005-04-16 15:20:36 -0700744 input->event = hidp_input_event;
745
Marcel Holtmannedad6382009-08-22 14:22:15 -0700746 err = input_register_device(input);
747 if (err < 0) {
748 hci_conn_put_device(session->conn);
749 return err;
750 }
751
752 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700753}
754
Marcel Holtmannf5ffd462007-02-17 23:58:53 +0100755static int hidp_open(struct hid_device *hid)
756{
757 return 0;
758}
759
760static void hidp_close(struct hid_device *hid)
761{
762}
763
Jiri Slabyc500c972008-05-16 11:49:16 +0200764static int hidp_parse(struct hid_device *hid)
765{
766 struct hidp_session *session = hid->driver_data;
Jiri Slabyc500c972008-05-16 11:49:16 +0200767
Michael Poole15c697c2010-02-05 12:23:43 -0500768 return hid_parse_report(session->hid, session->rd_data,
769 session->rd_size);
Jiri Slabyc500c972008-05-16 11:49:16 +0200770}
771
772static int hidp_start(struct hid_device *hid)
773{
774 struct hidp_session *session = hid->driver_data;
775 struct hid_report *report;
776
777 list_for_each_entry(report, &hid->report_enum[HID_INPUT_REPORT].
778 report_list, list)
779 hidp_send_report(session, report);
780
781 list_for_each_entry(report, &hid->report_enum[HID_FEATURE_REPORT].
782 report_list, list)
783 hidp_send_report(session, report);
784
Jiri Slabyc500c972008-05-16 11:49:16 +0200785 return 0;
786}
787
788static void hidp_stop(struct hid_device *hid)
789{
790 struct hidp_session *session = hid->driver_data;
791
792 skb_queue_purge(&session->ctrl_transmit);
793 skb_queue_purge(&session->intr_transmit);
794
Jiri Slabyc500c972008-05-16 11:49:16 +0200795 hid->claimed = 0;
796}
797
798static struct hid_ll_driver hidp_hid_driver = {
799 .parse = hidp_parse,
800 .start = hidp_start,
801 .stop = hidp_stop,
802 .open = hidp_open,
803 .close = hidp_close,
804 .hidinput_input_event = hidp_hidinput_event,
805};
806
Alan Ott0f69dca2011-01-18 03:04:37 -0500807/* This function sets up the hid device. It does not add it
808 to the HID system. That is done in hidp_add_connection(). */
Jiri Slaby85cdaf52008-05-16 11:49:15 +0200809static int hidp_setup_hid(struct hidp_session *session,
Andrew Morton91f5cca2008-02-05 03:07:58 -0800810 struct hidp_connadd_req *req)
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100811{
Jiri Slabyc500c972008-05-16 11:49:16 +0200812 struct hid_device *hid;
Marcel Holtmannedad6382009-08-22 14:22:15 -0700813 int err;
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100814
Michael Poole15c697c2010-02-05 12:23:43 -0500815 session->rd_data = kzalloc(req->rd_size, GFP_KERNEL);
816 if (!session->rd_data)
817 return -ENOMEM;
818
819 if (copy_from_user(session->rd_data, req->rd_data, req->rd_size)) {
820 err = -EFAULT;
821 goto fault;
822 }
823 session->rd_size = req->rd_size;
824
Jiri Slabyc500c972008-05-16 11:49:16 +0200825 hid = hid_allocate_device();
Michael Poole15c697c2010-02-05 12:23:43 -0500826 if (IS_ERR(hid)) {
827 err = PTR_ERR(hid);
828 goto fault;
829 }
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100830
Jiri Slabyc500c972008-05-16 11:49:16 +0200831 session->hid = hid;
Michael Poole15c697c2010-02-05 12:23:43 -0500832
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100833 hid->driver_data = session;
834
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100835 hid->bus = BUS_BLUETOOTH;
836 hid->vendor = req->vendor;
837 hid->product = req->product;
838 hid->version = req->version;
Jiri Slabyc500c972008-05-16 11:49:16 +0200839 hid->country = req->country;
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100840
841 strncpy(hid->name, req->name, 128);
Gustavo F. Padovand6b2eb22010-09-03 18:29:46 -0300842 strncpy(hid->phys, batostr(&bt_sk(session->ctrl_sock->sk)->src), 64);
843 strncpy(hid->uniq, batostr(&bt_sk(session->ctrl_sock->sk)->dst), 64);
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100844
Jiri Slaby85cdaf52008-05-16 11:49:15 +0200845 hid->dev.parent = hidp_get_device(session);
Jiri Slabyc500c972008-05-16 11:49:16 +0200846 hid->ll_driver = &hidp_hid_driver;
Jiri Slaby85cdaf52008-05-16 11:49:15 +0200847
Jiri Kosina2da31932009-11-26 16:20:56 +0100848 hid->hid_output_raw_report = hidp_output_raw_report;
849
Jiri Slabyc500c972008-05-16 11:49:16 +0200850 return 0;
Marcel Holtmannedad6382009-08-22 14:22:15 -0700851
Michael Poole15c697c2010-02-05 12:23:43 -0500852fault:
853 kfree(session->rd_data);
854 session->rd_data = NULL;
855
Marcel Holtmannedad6382009-08-22 14:22:15 -0700856 return err;
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100857}
858
Linus Torvalds1da177e2005-04-16 15:20:36 -0700859int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock, struct socket *intr_sock)
860{
861 struct hidp_session *session, *s;
862 int err;
863
864 BT_DBG("");
865
866 if (bacmp(&bt_sk(ctrl_sock->sk)->src, &bt_sk(intr_sock->sk)->src) ||
867 bacmp(&bt_sk(ctrl_sock->sk)->dst, &bt_sk(intr_sock->sk)->dst))
868 return -ENOTUNIQ;
869
Marcel Holtmann25ea6db2006-07-06 15:40:09 +0200870 session = kzalloc(sizeof(struct hidp_session), GFP_KERNEL);
Dmitry Torokhov34abf912005-09-15 02:01:40 -0500871 if (!session)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700872 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700873
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100874 BT_DBG("rd_data %p rd_size %d", req->rd_data, req->rd_size);
875
Linus Torvalds1da177e2005-04-16 15:20:36 -0700876 down_write(&hidp_session_sem);
877
878 s = __hidp_get_session(&bt_sk(ctrl_sock->sk)->dst);
879 if (s && s->state == BT_CONNECTED) {
880 err = -EEXIST;
881 goto failed;
882 }
883
884 bacpy(&session->bdaddr, &bt_sk(ctrl_sock->sk)->dst);
885
886 session->ctrl_mtu = min_t(uint, l2cap_pi(ctrl_sock->sk)->omtu, l2cap_pi(ctrl_sock->sk)->imtu);
887 session->intr_mtu = min_t(uint, l2cap_pi(intr_sock->sk)->omtu, l2cap_pi(intr_sock->sk)->imtu);
888
889 BT_DBG("ctrl mtu %d intr mtu %d", session->ctrl_mtu, session->intr_mtu);
890
891 session->ctrl_sock = ctrl_sock;
892 session->intr_sock = intr_sock;
893 session->state = BT_CONNECTED;
894
Pavel Emelyanovb24b8a22008-01-23 21:20:07 -0800895 setup_timer(&session->timer, hidp_idle_timeout, (unsigned long)session);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700896
897 skb_queue_head_init(&session->ctrl_transmit);
898 skb_queue_head_init(&session->intr_transmit);
899
Alan Ott0f69dca2011-01-18 03:04:37 -0500900 init_waitqueue_head(&session->startup_queue);
901 session->waiting_for_startup = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700902 session->flags = req->flags & (1 << HIDP_BLUETOOTH_VENDOR_ID);
903 session->idle_to = req->idle_to;
904
Jiri Slabyc500c972008-05-16 11:49:16 +0200905 if (req->rd_size > 0) {
Jiri Slaby85cdaf52008-05-16 11:49:15 +0200906 err = hidp_setup_hid(session, req);
Jiri Slabyd458a9d2008-05-16 11:49:20 +0200907 if (err && err != -ENODEV)
Marcel Holtmannedad6382009-08-22 14:22:15 -0700908 goto purge;
Jiri Slabyc500c972008-05-16 11:49:16 +0200909 }
910
911 if (!session->hid) {
912 err = hidp_setup_input(session, req);
913 if (err < 0)
Marcel Holtmannedad6382009-08-22 14:22:15 -0700914 goto purge;
Jiri Slaby85cdaf52008-05-16 11:49:15 +0200915 }
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100916
Linus Torvalds1da177e2005-04-16 15:20:36 -0700917 __hidp_link_session(session);
918
919 hidp_set_timer(session);
920
921 err = kernel_thread(hidp_session, session, CLONE_KERNEL);
922 if (err < 0)
923 goto unlink;
Alan Ott0f69dca2011-01-18 03:04:37 -0500924 while (session->waiting_for_startup) {
925 wait_event_interruptible(session->startup_queue,
926 !session->waiting_for_startup);
927 }
928
929 err = hid_add_device(session->hid);
930 if (err < 0)
931 goto err_add_device;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700932
933 if (session->input) {
934 hidp_send_ctrl_message(session,
935 HIDP_TRANS_SET_PROTOCOL | HIDP_PROTO_BOOT, NULL, 0);
936 session->flags |= (1 << HIDP_BOOT_PROTOCOL_MODE);
937
938 session->leds = 0xff;
939 hidp_input_event(session->input, EV_LED, 0, 0);
940 }
941
942 up_write(&hidp_session_sem);
943 return 0;
944
Alan Ott0f69dca2011-01-18 03:04:37 -0500945err_add_device:
946 hid_destroy_device(session->hid);
947 session->hid = NULL;
948 atomic_inc(&session->terminate);
949 hidp_schedule(session);
950
Linus Torvalds1da177e2005-04-16 15:20:36 -0700951unlink:
952 hidp_del_timer(session);
953
954 __hidp_unlink_session(session);
955
Marcel Holtmannedad6382009-08-22 14:22:15 -0700956 if (session->input) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700957 input_unregister_device(session->input);
Marcel Holtmannedad6382009-08-22 14:22:15 -0700958 session->input = NULL;
959 }
960
961 if (session->hid) {
Jiri Slaby85cdaf52008-05-16 11:49:15 +0200962 hid_destroy_device(session->hid);
Marcel Holtmannedad6382009-08-22 14:22:15 -0700963 session->hid = NULL;
964 }
965
Michael Poole15c697c2010-02-05 12:23:43 -0500966 kfree(session->rd_data);
967 session->rd_data = NULL;
968
Marcel Holtmannedad6382009-08-22 14:22:15 -0700969purge:
Jiri Slabyc500c972008-05-16 11:49:16 +0200970 skb_queue_purge(&session->ctrl_transmit);
971 skb_queue_purge(&session->intr_transmit);
Marcel Holtmannedad6382009-08-22 14:22:15 -0700972
Jiri Slabyc500c972008-05-16 11:49:16 +0200973failed:
974 up_write(&hidp_session_sem);
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100975
Marcel Holtmann5be39462007-05-09 09:15:30 +0200976 input_free_device(session->input);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700977 kfree(session);
978 return err;
979}
980
981int hidp_del_connection(struct hidp_conndel_req *req)
982{
983 struct hidp_session *session;
984 int err = 0;
985
986 BT_DBG("");
987
988 down_read(&hidp_session_sem);
989
990 session = __hidp_get_session(&req->bdaddr);
991 if (session) {
992 if (req->flags & (1 << HIDP_VIRTUAL_CABLE_UNPLUG)) {
993 hidp_send_ctrl_message(session,
994 HIDP_TRANS_HID_CONTROL | HIDP_CTRL_VIRTUAL_CABLE_UNPLUG, NULL, 0);
995 } else {
996 /* Flush the transmit queues */
997 skb_queue_purge(&session->ctrl_transmit);
998 skb_queue_purge(&session->intr_transmit);
999
Marcel Holtmannec8dab32008-07-14 20:13:53 +02001000 /* Wakeup user-space polling for socket errors */
1001 session->intr_sock->sk->sk_err = EUNATCH;
1002 session->ctrl_sock->sk->sk_err = EUNATCH;
1003
Linus Torvalds1da177e2005-04-16 15:20:36 -07001004 /* Kill session thread */
1005 atomic_inc(&session->terminate);
1006 hidp_schedule(session);
1007 }
1008 } else
1009 err = -ENOENT;
1010
1011 up_read(&hidp_session_sem);
1012 return err;
1013}
1014
1015int hidp_get_connlist(struct hidp_connlist_req *req)
1016{
1017 struct list_head *p;
1018 int err = 0, n = 0;
1019
1020 BT_DBG("");
1021
1022 down_read(&hidp_session_sem);
1023
1024 list_for_each(p, &hidp_session_list) {
1025 struct hidp_session *session;
1026 struct hidp_conninfo ci;
1027
1028 session = list_entry(p, struct hidp_session, list);
1029
1030 __hidp_copy_session(session, &ci);
1031
1032 if (copy_to_user(req->ci, &ci, sizeof(ci))) {
1033 err = -EFAULT;
1034 break;
1035 }
1036
1037 if (++n >= req->cnum)
1038 break;
1039
1040 req->ci++;
1041 }
1042 req->cnum = n;
1043
1044 up_read(&hidp_session_sem);
1045 return err;
1046}
1047
1048int hidp_get_conninfo(struct hidp_conninfo *ci)
1049{
1050 struct hidp_session *session;
1051 int err = 0;
1052
1053 down_read(&hidp_session_sem);
1054
1055 session = __hidp_get_session(&ci->bdaddr);
1056 if (session)
1057 __hidp_copy_session(session, ci);
1058 else
1059 err = -ENOENT;
1060
1061 up_read(&hidp_session_sem);
1062 return err;
1063}
1064
Jiri Slaby85cdaf52008-05-16 11:49:15 +02001065static const struct hid_device_id hidp_table[] = {
1066 { HID_BLUETOOTH_DEVICE(HID_ANY_ID, HID_ANY_ID) },
1067 { }
1068};
1069
1070static struct hid_driver hidp_driver = {
1071 .name = "generic-bluetooth",
1072 .id_table = hidp_table,
1073};
1074
Linus Torvalds1da177e2005-04-16 15:20:36 -07001075static int __init hidp_init(void)
1076{
Jiri Slaby85cdaf52008-05-16 11:49:15 +02001077 int ret;
1078
Linus Torvalds1da177e2005-04-16 15:20:36 -07001079 l2cap_load();
1080
1081 BT_INFO("HIDP (Human Interface Emulation) ver %s", VERSION);
1082
Jiri Slaby85cdaf52008-05-16 11:49:15 +02001083 ret = hid_register_driver(&hidp_driver);
1084 if (ret)
1085 goto err;
1086
1087 ret = hidp_init_sockets();
1088 if (ret)
1089 goto err_drv;
1090
1091 return 0;
1092err_drv:
1093 hid_unregister_driver(&hidp_driver);
1094err:
1095 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001096}
1097
1098static void __exit hidp_exit(void)
1099{
1100 hidp_cleanup_sockets();
Jiri Slaby85cdaf52008-05-16 11:49:15 +02001101 hid_unregister_driver(&hidp_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001102}
1103
1104module_init(hidp_init);
1105module_exit(hidp_exit);
1106
1107MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
1108MODULE_DESCRIPTION("Bluetooth HIDP ver " VERSION);
1109MODULE_VERSION(VERSION);
1110MODULE_LICENSE("GPL");
1111MODULE_ALIAS("bt-proto-6");