blob: 04f77842eb1837128ea7a1d6a9ad5d2e91b467a7 [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] = {
Szymon Janc17f09a72011-03-21 14:20:01 +010057 0, 0, 0, 0, 30, 48, 46, 32, 18, 33, 34, 35, 23, 36,
58 37, 38, 50, 49, 24, 25, 16, 19, 31, 20, 22, 47, 17, 45,
59 21, 44, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 28, 1,
60 14, 15, 57, 12, 13, 26, 27, 43, 43, 39, 40, 41, 51, 52,
61 53, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 87, 88,
62 99, 70, 119, 110, 102, 104, 111, 107, 109, 106, 105, 108, 103, 69,
63 98, 55, 74, 78, 96, 79, 80, 81, 75, 76, 77, 71, 72, 73,
64 82, 83, 86, 127, 116, 117, 183, 184, 185, 186, 187, 188, 189, 190,
65 191, 192, 193, 194, 134, 138, 130, 132, 128, 129, 131, 137, 133, 135,
66 136, 113, 115, 114, 0, 0, 0, 121, 0, 89, 93, 124, 92, 94,
67 95, 0, 0, 0, 122, 123, 90, 91, 85, 0, 0, 0, 0, 0,
68 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,
70 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
71 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
72 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
73 29, 42, 56, 125, 97, 54, 100, 126, 164, 166, 165, 163, 161, 115,
74 114, 113, 150, 158, 159, 128, 136, 177, 178, 176, 142, 152, 173, 140
Linus Torvalds1da177e2005-04-16 15:20:36 -070075};
76
77static unsigned char hidp_mkeyspat[] = { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 };
78
79static struct hidp_session *__hidp_get_session(bdaddr_t *bdaddr)
80{
81 struct hidp_session *session;
82 struct list_head *p;
83
84 BT_DBG("");
85
86 list_for_each(p, &hidp_session_list) {
87 session = list_entry(p, struct hidp_session, list);
88 if (!bacmp(bdaddr, &session->bdaddr))
89 return session;
90 }
91 return NULL;
92}
93
94static void __hidp_link_session(struct hidp_session *session)
95{
96 __module_get(THIS_MODULE);
97 list_add(&session->list, &hidp_session_list);
Marcel Holtmannedad6382009-08-22 14:22:15 -070098
99 hci_conn_hold_device(session->conn);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700100}
101
102static void __hidp_unlink_session(struct hidp_session *session)
103{
Marcel Holtmannedad6382009-08-22 14:22:15 -0700104 hci_conn_put_device(session->conn);
105
Linus Torvalds1da177e2005-04-16 15:20:36 -0700106 list_del(&session->list);
107 module_put(THIS_MODULE);
108}
109
110static void __hidp_copy_session(struct hidp_session *session, struct hidp_conninfo *ci)
111{
Vasiliy Kulikovd31dbf62010-10-30 18:26:31 +0400112 memset(ci, 0, sizeof(*ci));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700113 bacpy(&ci->bdaddr, &session->bdaddr);
114
115 ci->flags = session->flags;
116 ci->state = session->state;
117
118 ci->vendor = 0x0000;
119 ci->product = 0x0000;
120 ci->version = 0x0000;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700121
122 if (session->input) {
123 ci->vendor = session->input->id.vendor;
124 ci->product = session->input->id.product;
125 ci->version = session->input->id.version;
126 if (session->input->name)
127 strncpy(ci->name, session->input->name, 128);
128 else
129 strncpy(ci->name, "HID Boot Device", 128);
130 }
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100131
132 if (session->hid) {
133 ci->vendor = session->hid->vendor;
134 ci->product = session->hid->product;
135 ci->version = session->hid->version;
136 strncpy(ci->name, session->hid->name, 128);
137 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700138}
139
Andrew Morton91f5cca2008-02-05 03:07:58 -0800140static int hidp_queue_event(struct hidp_session *session, struct input_dev *dev,
141 unsigned int type, unsigned int code, int value)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700142{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700143 unsigned char newleds;
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100144 struct sk_buff *skb;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700145
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100146 BT_DBG("session %p type %d code %d value %d", session, type, code, value);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700147
148 if (type != EV_LED)
149 return -1;
150
151 newleds = (!!test_bit(LED_KANA, dev->led) << 3) |
152 (!!test_bit(LED_COMPOSE, dev->led) << 3) |
153 (!!test_bit(LED_SCROLLL, dev->led) << 2) |
154 (!!test_bit(LED_CAPSL, dev->led) << 1) |
155 (!!test_bit(LED_NUML, dev->led));
156
157 if (session->leds == newleds)
158 return 0;
159
160 session->leds = newleds;
161
Andrei Emeltchenko5a08ecc2011-01-11 17:20:20 +0200162 skb = alloc_skb(3, GFP_ATOMIC);
163 if (!skb) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700164 BT_ERR("Can't allocate memory for new frame");
165 return -ENOMEM;
166 }
167
168 *skb_put(skb, 1) = HIDP_TRANS_DATA | HIDP_DATA_RTYPE_OUPUT;
169 *skb_put(skb, 1) = 0x01;
170 *skb_put(skb, 1) = newleds;
171
172 skb_queue_tail(&session->intr_transmit, skb);
173
174 hidp_schedule(session);
175
176 return 0;
177}
178
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100179static int hidp_hidinput_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
180{
Marcel Holtmann5be39462007-05-09 09:15:30 +0200181 struct hid_device *hid = input_get_drvdata(dev);
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100182 struct hidp_session *session = hid->driver_data;
183
184 return hidp_queue_event(session, dev, type, code, value);
185}
186
187static int hidp_input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
188{
Marcel Holtmann5be39462007-05-09 09:15:30 +0200189 struct hidp_session *session = input_get_drvdata(dev);
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100190
191 return hidp_queue_event(session, dev, type, code, value);
192}
193
Linus Torvalds1da177e2005-04-16 15:20:36 -0700194static void hidp_input_report(struct hidp_session *session, struct sk_buff *skb)
195{
196 struct input_dev *dev = session->input;
197 unsigned char *keys = session->keys;
198 unsigned char *udata = skb->data + 1;
199 signed char *sdata = skb->data + 1;
200 int i, size = skb->len - 1;
201
202 switch (skb->data[0]) {
203 case 0x01: /* Keyboard report */
204 for (i = 0; i < 8; i++)
205 input_report_key(dev, hidp_keycode[i + 224], (udata[0] >> i) & 1);
206
207 /* If all the key codes have been set to 0x01, it means
208 * too many keys were pressed at the same time. */
209 if (!memcmp(udata + 2, hidp_mkeyspat, 6))
210 break;
211
212 for (i = 2; i < 8; i++) {
213 if (keys[i] > 3 && memscan(udata + 2, keys[i], 6) == udata + 8) {
214 if (hidp_keycode[keys[i]])
215 input_report_key(dev, hidp_keycode[keys[i]], 0);
216 else
217 BT_ERR("Unknown key (scancode %#x) released.", keys[i]);
218 }
219
220 if (udata[i] > 3 && memscan(keys + 2, udata[i], 6) == keys + 8) {
221 if (hidp_keycode[udata[i]])
222 input_report_key(dev, hidp_keycode[udata[i]], 1);
223 else
224 BT_ERR("Unknown key (scancode %#x) pressed.", udata[i]);
225 }
226 }
227
228 memcpy(keys, udata, 8);
229 break;
230
231 case 0x02: /* Mouse report */
232 input_report_key(dev, BTN_LEFT, sdata[0] & 0x01);
233 input_report_key(dev, BTN_RIGHT, sdata[0] & 0x02);
234 input_report_key(dev, BTN_MIDDLE, sdata[0] & 0x04);
235 input_report_key(dev, BTN_SIDE, sdata[0] & 0x08);
236 input_report_key(dev, BTN_EXTRA, sdata[0] & 0x10);
237
238 input_report_rel(dev, REL_X, sdata[1]);
239 input_report_rel(dev, REL_Y, sdata[2]);
240
241 if (size > 3)
242 input_report_rel(dev, REL_WHEEL, sdata[3]);
243 break;
244 }
245
246 input_sync(dev);
247}
248
Bastien Nocera6bf82682010-01-20 12:00:42 +0000249static int __hidp_send_ctrl_message(struct hidp_session *session,
250 unsigned char hdr, unsigned char *data, int size)
251{
252 struct sk_buff *skb;
253
254 BT_DBG("session %p data %p size %d", session, data, size);
255
Andrei Emeltchenko5a08ecc2011-01-11 17:20:20 +0200256 skb = alloc_skb(size + 1, GFP_ATOMIC);
257 if (!skb) {
Bastien Nocera6bf82682010-01-20 12:00:42 +0000258 BT_ERR("Can't allocate memory for new frame");
259 return -ENOMEM;
260 }
261
262 *skb_put(skb, 1) = hdr;
263 if (data && size > 0)
264 memcpy(skb_put(skb, size), data, size);
265
266 skb_queue_tail(&session->ctrl_transmit, skb);
267
268 return 0;
269}
270
271static inline int hidp_send_ctrl_message(struct hidp_session *session,
272 unsigned char hdr, unsigned char *data, int size)
273{
274 int err;
275
276 err = __hidp_send_ctrl_message(session, hdr, data, size);
277
278 hidp_schedule(session);
279
280 return err;
281}
282
Andrew Morton91f5cca2008-02-05 03:07:58 -0800283static int hidp_queue_report(struct hidp_session *session,
284 unsigned char *data, int size)
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100285{
286 struct sk_buff *skb;
287
Dave Young6792b5e2007-10-20 14:15:39 +0200288 BT_DBG("session %p hid %p data %p size %d", session, session->hid, data, size);
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100289
Andrei Emeltchenko5a08ecc2011-01-11 17:20:20 +0200290 skb = alloc_skb(size + 1, GFP_ATOMIC);
291 if (!skb) {
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100292 BT_ERR("Can't allocate memory for new frame");
293 return -ENOMEM;
294 }
295
296 *skb_put(skb, 1) = 0xa2;
297 if (size > 0)
298 memcpy(skb_put(skb, size), data, size);
299
300 skb_queue_tail(&session->intr_transmit, skb);
301
302 hidp_schedule(session);
303
304 return 0;
305}
306
307static int hidp_send_report(struct hidp_session *session, struct hid_report *report)
308{
309 unsigned char buf[32];
310 int rsize;
311
312 rsize = ((report->size - 1) >> 3) + 1 + (report->id > 0);
313 if (rsize > sizeof(buf))
314 return -EIO;
315
316 hid_output_report(report, buf);
317
318 return hidp_queue_report(session, buf, rsize);
319}
320
Jiri Kosinad4bfa032010-01-29 15:03:36 +0100321static int hidp_output_raw_report(struct hid_device *hid, unsigned char *data, size_t count,
322 unsigned char report_type)
Jiri Kosina2da31932009-11-26 16:20:56 +0100323{
Jiri Kosinad4bfa032010-01-29 15:03:36 +0100324 switch (report_type) {
325 case HID_FEATURE_REPORT:
326 report_type = HIDP_TRANS_SET_REPORT | HIDP_DATA_RTYPE_FEATURE;
327 break;
328 case HID_OUTPUT_REPORT:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700329 report_type = HIDP_TRANS_DATA | HIDP_DATA_RTYPE_OUPUT;
Jiri Kosinad4bfa032010-01-29 15:03:36 +0100330 break;
331 default:
332 return -EINVAL;
333 }
334
335 if (hidp_send_ctrl_message(hid->driver_data, report_type,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700336 data, count))
337 return -ENOMEM;
338 return count;
Jiri Kosina2da31932009-11-26 16:20:56 +0100339}
340
Linus Torvalds1da177e2005-04-16 15:20:36 -0700341static void hidp_idle_timeout(unsigned long arg)
342{
343 struct hidp_session *session = (struct hidp_session *) arg;
344
Peter Hurley6fc43002011-06-30 13:53:53 -0400345 atomic_inc(&session->terminate);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700346 hidp_schedule(session);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700347}
348
Andrew Morton91f5cca2008-02-05 03:07:58 -0800349static void hidp_set_timer(struct hidp_session *session)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700350{
351 if (session->idle_to > 0)
352 mod_timer(&session->timer, jiffies + HZ * session->idle_to);
353}
354
355static inline void hidp_del_timer(struct hidp_session *session)
356{
357 if (session->idle_to > 0)
358 del_timer(&session->timer);
359}
360
Andrew Morton91f5cca2008-02-05 03:07:58 -0800361static void hidp_process_handshake(struct hidp_session *session,
362 unsigned char param)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700363{
364 BT_DBG("session %p param 0x%02x", session, param);
365
366 switch (param) {
367 case HIDP_HSHK_SUCCESSFUL:
368 /* FIXME: Call into SET_ GET_ handlers here */
369 break;
370
371 case HIDP_HSHK_NOT_READY:
372 case HIDP_HSHK_ERR_INVALID_REPORT_ID:
373 case HIDP_HSHK_ERR_UNSUPPORTED_REQUEST:
374 case HIDP_HSHK_ERR_INVALID_PARAMETER:
375 /* FIXME: Call into SET_ GET_ handlers here */
376 break;
377
378 case HIDP_HSHK_ERR_UNKNOWN:
379 break;
380
381 case HIDP_HSHK_ERR_FATAL:
382 /* Device requests a reboot, as this is the only way this error
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900383 * can be recovered. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700384 __hidp_send_ctrl_message(session,
385 HIDP_TRANS_HID_CONTROL | HIDP_CTRL_SOFT_RESET, NULL, 0);
386 break;
387
388 default:
389 __hidp_send_ctrl_message(session,
390 HIDP_TRANS_HANDSHAKE | HIDP_HSHK_ERR_INVALID_PARAMETER, NULL, 0);
391 break;
392 }
393}
394
Andrew Morton91f5cca2008-02-05 03:07:58 -0800395static void hidp_process_hid_control(struct hidp_session *session,
396 unsigned char param)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700397{
398 BT_DBG("session %p param 0x%02x", session, param);
399
Dave Youngeff001e2008-02-05 03:07:14 -0800400 if (param == HIDP_CTRL_VIRTUAL_CABLE_UNPLUG) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700401 /* Flush the transmit queues */
402 skb_queue_purge(&session->ctrl_transmit);
403 skb_queue_purge(&session->intr_transmit);
404
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700405 /* Kill session thread */
Peter Hurley6fc43002011-06-30 13:53:53 -0400406 atomic_inc(&session->terminate);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700407 hidp_schedule(session);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700408 }
409}
410
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700411static void hidp_process_data(struct hidp_session *session, struct sk_buff *skb,
Andrew Morton91f5cca2008-02-05 03:07:58 -0800412 unsigned char param)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700413{
414 BT_DBG("session %p skb %p len %d param 0x%02x", session, skb, skb->len, param);
415
416 switch (param) {
417 case HIDP_DATA_RTYPE_INPUT:
418 hidp_set_timer(session);
419
420 if (session->input)
421 hidp_input_report(session, skb);
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100422
423 if (session->hid)
424 hid_input_report(session->hid, HID_INPUT_REPORT, skb->data, skb->len, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700425
Linus Torvalds1da177e2005-04-16 15:20:36 -0700426 break;
427
428 case HIDP_DATA_RTYPE_OTHER:
429 case HIDP_DATA_RTYPE_OUPUT:
430 case HIDP_DATA_RTYPE_FEATURE:
431 break;
432
433 default:
434 __hidp_send_ctrl_message(session,
435 HIDP_TRANS_HANDSHAKE | HIDP_HSHK_ERR_INVALID_PARAMETER, NULL, 0);
436 }
437}
438
Andrew Morton91f5cca2008-02-05 03:07:58 -0800439static void hidp_recv_ctrl_frame(struct hidp_session *session,
440 struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700441{
442 unsigned char hdr, type, param;
443
444 BT_DBG("session %p skb %p len %d", session, skb, skb->len);
445
446 hdr = skb->data[0];
447 skb_pull(skb, 1);
448
449 type = hdr & HIDP_HEADER_TRANS_MASK;
450 param = hdr & HIDP_HEADER_PARAM_MASK;
451
452 switch (type) {
453 case HIDP_TRANS_HANDSHAKE:
454 hidp_process_handshake(session, param);
455 break;
456
457 case HIDP_TRANS_HID_CONTROL:
458 hidp_process_hid_control(session, param);
459 break;
460
461 case HIDP_TRANS_DATA:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700462 hidp_process_data(session, skb, param);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700463 break;
464
465 default:
466 __hidp_send_ctrl_message(session,
467 HIDP_TRANS_HANDSHAKE | HIDP_HSHK_ERR_UNSUPPORTED_REQUEST, NULL, 0);
468 break;
469 }
470
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700471 kfree_skb(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700472}
473
Andrew Morton91f5cca2008-02-05 03:07:58 -0800474static void hidp_recv_intr_frame(struct hidp_session *session,
475 struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700476{
477 unsigned char hdr;
478
479 BT_DBG("session %p skb %p len %d", session, skb, skb->len);
480
481 hdr = skb->data[0];
482 skb_pull(skb, 1);
483
484 if (hdr == (HIDP_TRANS_DATA | HIDP_DATA_RTYPE_INPUT)) {
485 hidp_set_timer(session);
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100486
Linus Torvalds1da177e2005-04-16 15:20:36 -0700487 if (session->input)
488 hidp_input_report(session, skb);
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100489
490 if (session->hid) {
491 hid_input_report(session->hid, HID_INPUT_REPORT, skb->data, skb->len, 1);
492 BT_DBG("report len %d", skb->len);
493 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700494 } else {
495 BT_DBG("Unsupported protocol header 0x%02x", hdr);
496 }
497
498 kfree_skb(skb);
499}
500
501static int hidp_send_frame(struct socket *sock, unsigned char *data, int len)
502{
503 struct kvec iv = { data, len };
504 struct msghdr msg;
505
506 BT_DBG("sock %p data %p len %d", sock, data, len);
507
508 if (!len)
509 return 0;
510
511 memset(&msg, 0, sizeof(msg));
512
513 return kernel_sendmsg(sock, &msg, &iv, 1, len);
514}
515
David S. Millerb03efcf2005-07-08 14:57:23 -0700516static void hidp_process_transmit(struct hidp_session *session)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700517{
518 struct sk_buff *skb;
519
520 BT_DBG("session %p", session);
521
522 while ((skb = skb_dequeue(&session->ctrl_transmit))) {
523 if (hidp_send_frame(session->ctrl_sock, skb->data, skb->len) < 0) {
524 skb_queue_head(&session->ctrl_transmit, skb);
525 break;
526 }
527
528 hidp_set_timer(session);
529 kfree_skb(skb);
530 }
531
532 while ((skb = skb_dequeue(&session->intr_transmit))) {
533 if (hidp_send_frame(session->intr_sock, skb->data, skb->len) < 0) {
534 skb_queue_head(&session->intr_transmit, skb);
535 break;
536 }
537
538 hidp_set_timer(session);
539 kfree_skb(skb);
540 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700541}
542
543static int hidp_session(void *arg)
544{
545 struct hidp_session *session = arg;
546 struct sock *ctrl_sk = session->ctrl_sock->sk;
547 struct sock *intr_sk = session->intr_sock->sk;
548 struct sk_buff *skb;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700549 int vendor = 0x0000, product = 0x0000;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700550 wait_queue_t ctrl_wait, intr_wait;
551
552 BT_DBG("session %p", session);
553
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700554 if (session->input) {
555 vendor = session->input->id.vendor;
556 product = session->input->id.product;
557 }
558
559 if (session->hid) {
560 vendor = session->hid->vendor;
561 product = session->hid->product;
562 }
563
564 daemonize("khidpd_%04x%04x", vendor, product);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700565 set_user_nice(current, -15);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700566
567 init_waitqueue_entry(&ctrl_wait, current);
568 init_waitqueue_entry(&intr_wait, current);
Eric Dumazetaa395142010-04-20 13:03:51 +0000569 add_wait_queue(sk_sleep(ctrl_sk), &ctrl_wait);
570 add_wait_queue(sk_sleep(intr_sk), &intr_wait);
Peter Hurley6fc43002011-06-30 13:53:53 -0400571 while (!atomic_read(&session->terminate)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700572 set_current_state(TASK_INTERRUPTIBLE);
573
Szymon Janc17f09a72011-03-21 14:20:01 +0100574 if (ctrl_sk->sk_state != BT_CONNECTED ||
575 intr_sk->sk_state != BT_CONNECTED)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700576 break;
577
578 while ((skb = skb_dequeue(&ctrl_sk->sk_receive_queue))) {
579 skb_orphan(skb);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700580 if (!skb_linearize(skb))
581 hidp_recv_ctrl_frame(session, skb);
582 else
583 kfree_skb(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700584 }
585
586 while ((skb = skb_dequeue(&intr_sk->sk_receive_queue))) {
587 skb_orphan(skb);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700588 if (!skb_linearize(skb))
589 hidp_recv_intr_frame(session, skb);
590 else
591 kfree_skb(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700592 }
593
594 hidp_process_transmit(session);
595
596 schedule();
597 }
598 set_current_state(TASK_RUNNING);
Eric Dumazetaa395142010-04-20 13:03:51 +0000599 remove_wait_queue(sk_sleep(intr_sk), &intr_wait);
600 remove_wait_queue(sk_sleep(ctrl_sk), &ctrl_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700601
602 down_write(&hidp_session_sem);
603
604 hidp_del_timer(session);
605
Linus Torvalds1da177e2005-04-16 15:20:36 -0700606 if (session->input) {
607 input_unregister_device(session->input);
Dmitry Torokhov34abf912005-09-15 02:01:40 -0500608 session->input = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700609 }
610
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100611 if (session->hid) {
Jiri Slaby85cdaf52008-05-16 11:49:15 +0200612 hid_destroy_device(session->hid);
Marcel Holtmannedad6382009-08-22 14:22:15 -0700613 session->hid = NULL;
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100614 }
615
Marcel Holtmannec8dab32008-07-14 20:13:53 +0200616 /* Wakeup user-space polling for socket errors */
617 session->intr_sock->sk->sk_err = EUNATCH;
618 session->ctrl_sock->sk->sk_err = EUNATCH;
619
620 hidp_schedule(session);
621
David Woodhouse1c398582007-07-07 14:58:39 -0400622 fput(session->intr_sock->file);
623
Eric Dumazetaa395142010-04-20 13:03:51 +0000624 wait_event_timeout(*(sk_sleep(ctrl_sk)),
David Woodhouse1c398582007-07-07 14:58:39 -0400625 (ctrl_sk->sk_state == BT_CLOSED), msecs_to_jiffies(500));
626
627 fput(session->ctrl_sock->file);
628
629 __hidp_unlink_session(session);
630
Linus Torvalds1da177e2005-04-16 15:20:36 -0700631 up_write(&hidp_session_sem);
632
633 kfree(session);
634 return 0;
635}
636
Marcel Holtmann0a85b962006-07-06 13:09:02 +0200637static struct device *hidp_get_device(struct hidp_session *session)
638{
639 bdaddr_t *src = &bt_sk(session->ctrl_sock->sk)->src;
640 bdaddr_t *dst = &bt_sk(session->ctrl_sock->sk)->dst;
Marcel Holtmannedad6382009-08-22 14:22:15 -0700641 struct device *device = NULL;
Marcel Holtmann0a85b962006-07-06 13:09:02 +0200642 struct hci_dev *hdev;
Marcel Holtmann0a85b962006-07-06 13:09:02 +0200643
644 hdev = hci_get_route(dst, src);
645 if (!hdev)
646 return NULL;
647
Marcel Holtmannedad6382009-08-22 14:22:15 -0700648 session->conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, dst);
649 if (session->conn)
650 device = &session->conn->dev;
Marcel Holtmann0a85b962006-07-06 13:09:02 +0200651
652 hci_dev_put(hdev);
653
Marcel Holtmannedad6382009-08-22 14:22:15 -0700654 return device;
Marcel Holtmann0a85b962006-07-06 13:09:02 +0200655}
656
Andrew Morton91f5cca2008-02-05 03:07:58 -0800657static int hidp_setup_input(struct hidp_session *session,
658 struct hidp_connadd_req *req)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700659{
Jiri Slabyc500c972008-05-16 11:49:16 +0200660 struct input_dev *input;
Marcel Holtmannedad6382009-08-22 14:22:15 -0700661 int err, i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700662
Jiri Slabyc500c972008-05-16 11:49:16 +0200663 input = input_allocate_device();
664 if (!input)
665 return -ENOMEM;
666
667 session->input = input;
668
Marcel Holtmann5be39462007-05-09 09:15:30 +0200669 input_set_drvdata(input, session);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700670
Dmitry Torokhov34abf912005-09-15 02:01:40 -0500671 input->name = "Bluetooth HID Boot Protocol Device";
672
Linus Torvalds1da177e2005-04-16 15:20:36 -0700673 input->id.bustype = BUS_BLUETOOTH;
674 input->id.vendor = req->vendor;
675 input->id.product = req->product;
676 input->id.version = req->version;
677
678 if (req->subclass & 0x40) {
679 set_bit(EV_KEY, input->evbit);
680 set_bit(EV_LED, input->evbit);
681 set_bit(EV_REP, input->evbit);
682
683 set_bit(LED_NUML, input->ledbit);
684 set_bit(LED_CAPSL, input->ledbit);
685 set_bit(LED_SCROLLL, input->ledbit);
686 set_bit(LED_COMPOSE, input->ledbit);
687 set_bit(LED_KANA, input->ledbit);
688
689 for (i = 0; i < sizeof(hidp_keycode); i++)
690 set_bit(hidp_keycode[i], input->keybit);
691 clear_bit(0, input->keybit);
692 }
693
694 if (req->subclass & 0x80) {
Jiri Slaby7b19ada2007-10-18 23:40:32 -0700695 input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL);
696 input->keybit[BIT_WORD(BTN_MOUSE)] = BIT_MASK(BTN_LEFT) |
697 BIT_MASK(BTN_RIGHT) | BIT_MASK(BTN_MIDDLE);
698 input->relbit[0] = BIT_MASK(REL_X) | BIT_MASK(REL_Y);
699 input->keybit[BIT_WORD(BTN_MOUSE)] |= BIT_MASK(BTN_SIDE) |
700 BIT_MASK(BTN_EXTRA);
701 input->relbit[0] |= BIT_MASK(REL_WHEEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700702 }
703
Marcel Holtmann5be39462007-05-09 09:15:30 +0200704 input->dev.parent = hidp_get_device(session);
Marcel Holtmann0a85b962006-07-06 13:09:02 +0200705
Linus Torvalds1da177e2005-04-16 15:20:36 -0700706 input->event = hidp_input_event;
707
Marcel Holtmannedad6382009-08-22 14:22:15 -0700708 err = input_register_device(input);
709 if (err < 0) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700710 hci_conn_put_device(session->conn);
Marcel Holtmannedad6382009-08-22 14:22:15 -0700711 return err;
712 }
713
714 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700715}
716
Marcel Holtmannf5ffd462007-02-17 23:58:53 +0100717static int hidp_open(struct hid_device *hid)
718{
719 return 0;
720}
721
722static void hidp_close(struct hid_device *hid)
723{
724}
725
Jiri Slabyc500c972008-05-16 11:49:16 +0200726static int hidp_parse(struct hid_device *hid)
727{
728 struct hidp_session *session = hid->driver_data;
Jiri Slabyc500c972008-05-16 11:49:16 +0200729
Michael Poole15c697c2010-02-05 12:23:43 -0500730 return hid_parse_report(session->hid, session->rd_data,
731 session->rd_size);
Jiri Slabyc500c972008-05-16 11:49:16 +0200732}
733
734static int hidp_start(struct hid_device *hid)
735{
736 struct hidp_session *session = hid->driver_data;
737 struct hid_report *report;
738
739 list_for_each_entry(report, &hid->report_enum[HID_INPUT_REPORT].
740 report_list, list)
741 hidp_send_report(session, report);
742
743 list_for_each_entry(report, &hid->report_enum[HID_FEATURE_REPORT].
744 report_list, list)
745 hidp_send_report(session, report);
746
Jiri Slabyc500c972008-05-16 11:49:16 +0200747 return 0;
748}
749
750static void hidp_stop(struct hid_device *hid)
751{
752 struct hidp_session *session = hid->driver_data;
753
754 skb_queue_purge(&session->ctrl_transmit);
755 skb_queue_purge(&session->intr_transmit);
756
Jiri Slabyc500c972008-05-16 11:49:16 +0200757 hid->claimed = 0;
758}
759
760static struct hid_ll_driver hidp_hid_driver = {
761 .parse = hidp_parse,
762 .start = hidp_start,
763 .stop = hidp_stop,
764 .open = hidp_open,
765 .close = hidp_close,
766 .hidinput_input_event = hidp_hidinput_event,
767};
768
Jiri Slaby85cdaf52008-05-16 11:49:15 +0200769static int hidp_setup_hid(struct hidp_session *session,
Andrew Morton91f5cca2008-02-05 03:07:58 -0800770 struct hidp_connadd_req *req)
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100771{
Jiri Slabyc500c972008-05-16 11:49:16 +0200772 struct hid_device *hid;
Marcel Holtmannedad6382009-08-22 14:22:15 -0700773 int err;
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100774
Michael Poole15c697c2010-02-05 12:23:43 -0500775 session->rd_data = kzalloc(req->rd_size, GFP_KERNEL);
776 if (!session->rd_data)
777 return -ENOMEM;
778
779 if (copy_from_user(session->rd_data, req->rd_data, req->rd_size)) {
780 err = -EFAULT;
781 goto fault;
782 }
783 session->rd_size = req->rd_size;
784
Jiri Slabyc500c972008-05-16 11:49:16 +0200785 hid = hid_allocate_device();
Michael Poole15c697c2010-02-05 12:23:43 -0500786 if (IS_ERR(hid)) {
787 err = PTR_ERR(hid);
788 goto fault;
789 }
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100790
Jiri Slabyc500c972008-05-16 11:49:16 +0200791 session->hid = hid;
Michael Poole15c697c2010-02-05 12:23:43 -0500792
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100793 hid->driver_data = session;
794
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100795 hid->bus = BUS_BLUETOOTH;
796 hid->vendor = req->vendor;
797 hid->product = req->product;
798 hid->version = req->version;
Jiri Slabyc500c972008-05-16 11:49:16 +0200799 hid->country = req->country;
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100800
801 strncpy(hid->name, req->name, 128);
Gustavo F. Padovand6b2eb22010-09-03 18:29:46 -0300802 strncpy(hid->phys, batostr(&bt_sk(session->ctrl_sock->sk)->src), 64);
803 strncpy(hid->uniq, batostr(&bt_sk(session->ctrl_sock->sk)->dst), 64);
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100804
Jiri Slaby85cdaf52008-05-16 11:49:15 +0200805 hid->dev.parent = hidp_get_device(session);
Jiri Slabyc500c972008-05-16 11:49:16 +0200806 hid->ll_driver = &hidp_hid_driver;
Jiri Slaby85cdaf52008-05-16 11:49:15 +0200807
Jiri Kosina2da31932009-11-26 16:20:56 +0100808 hid->hid_output_raw_report = hidp_output_raw_report;
809
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700810 err = hid_add_device(hid);
811 if (err < 0)
812 goto failed;
813
Jiri Slabyc500c972008-05-16 11:49:16 +0200814 return 0;
Marcel Holtmannedad6382009-08-22 14:22:15 -0700815
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700816failed:
817 hid_destroy_device(hid);
818 session->hid = NULL;
819
Michael Poole15c697c2010-02-05 12:23:43 -0500820fault:
821 kfree(session->rd_data);
822 session->rd_data = NULL;
823
Marcel Holtmannedad6382009-08-22 14:22:15 -0700824 return err;
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100825}
826
Linus Torvalds1da177e2005-04-16 15:20:36 -0700827int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock, struct socket *intr_sock)
828{
829 struct hidp_session *session, *s;
830 int err;
831
832 BT_DBG("");
833
834 if (bacmp(&bt_sk(ctrl_sock->sk)->src, &bt_sk(intr_sock->sk)->src) ||
835 bacmp(&bt_sk(ctrl_sock->sk)->dst, &bt_sk(intr_sock->sk)->dst))
836 return -ENOTUNIQ;
837
Marcel Holtmann25ea6db2006-07-06 15:40:09 +0200838 session = kzalloc(sizeof(struct hidp_session), GFP_KERNEL);
Dmitry Torokhov34abf912005-09-15 02:01:40 -0500839 if (!session)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700840 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700841
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100842 BT_DBG("rd_data %p rd_size %d", req->rd_data, req->rd_size);
843
Linus Torvalds1da177e2005-04-16 15:20:36 -0700844 down_write(&hidp_session_sem);
845
846 s = __hidp_get_session(&bt_sk(ctrl_sock->sk)->dst);
847 if (s && s->state == BT_CONNECTED) {
848 err = -EEXIST;
849 goto failed;
850 }
851
852 bacpy(&session->bdaddr, &bt_sk(ctrl_sock->sk)->dst);
853
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700854 session->ctrl_mtu = min_t(uint, l2cap_pi(ctrl_sock->sk)->omtu, l2cap_pi(ctrl_sock->sk)->imtu);
855 session->intr_mtu = min_t(uint, l2cap_pi(intr_sock->sk)->omtu, l2cap_pi(intr_sock->sk)->imtu);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700856
857 BT_DBG("ctrl mtu %d intr mtu %d", session->ctrl_mtu, session->intr_mtu);
858
859 session->ctrl_sock = ctrl_sock;
860 session->intr_sock = intr_sock;
861 session->state = BT_CONNECTED;
862
Pavel Emelyanovb24b8a22008-01-23 21:20:07 -0800863 setup_timer(&session->timer, hidp_idle_timeout, (unsigned long)session);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700864
865 skb_queue_head_init(&session->ctrl_transmit);
866 skb_queue_head_init(&session->intr_transmit);
867
868 session->flags = req->flags & (1 << HIDP_BLUETOOTH_VENDOR_ID);
869 session->idle_to = req->idle_to;
870
Jiri Slabyc500c972008-05-16 11:49:16 +0200871 if (req->rd_size > 0) {
Jiri Slaby85cdaf52008-05-16 11:49:15 +0200872 err = hidp_setup_hid(session, req);
Jiri Slabyd458a9d2008-05-16 11:49:20 +0200873 if (err && err != -ENODEV)
Marcel Holtmannedad6382009-08-22 14:22:15 -0700874 goto purge;
Jiri Slabyc500c972008-05-16 11:49:16 +0200875 }
876
877 if (!session->hid) {
878 err = hidp_setup_input(session, req);
879 if (err < 0)
Marcel Holtmannedad6382009-08-22 14:22:15 -0700880 goto purge;
Jiri Slaby85cdaf52008-05-16 11:49:15 +0200881 }
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100882
Linus Torvalds1da177e2005-04-16 15:20:36 -0700883 __hidp_link_session(session);
884
885 hidp_set_timer(session);
886
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700887 err = kernel_thread(hidp_session, session, CLONE_KERNEL);
888 if (err < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700889 goto unlink;
890
891 if (session->input) {
892 hidp_send_ctrl_message(session,
893 HIDP_TRANS_SET_PROTOCOL | HIDP_PROTO_BOOT, NULL, 0);
894 session->flags |= (1 << HIDP_BOOT_PROTOCOL_MODE);
895
896 session->leds = 0xff;
897 hidp_input_event(session->input, EV_LED, 0, 0);
898 }
899
900 up_write(&hidp_session_sem);
901 return 0;
902
903unlink:
904 hidp_del_timer(session);
905
906 __hidp_unlink_session(session);
907
Marcel Holtmannedad6382009-08-22 14:22:15 -0700908 if (session->input) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700909 input_unregister_device(session->input);
Marcel Holtmannedad6382009-08-22 14:22:15 -0700910 session->input = NULL;
911 }
912
913 if (session->hid) {
Jiri Slaby85cdaf52008-05-16 11:49:15 +0200914 hid_destroy_device(session->hid);
Marcel Holtmannedad6382009-08-22 14:22:15 -0700915 session->hid = NULL;
916 }
917
Michael Poole15c697c2010-02-05 12:23:43 -0500918 kfree(session->rd_data);
919 session->rd_data = NULL;
920
Marcel Holtmannedad6382009-08-22 14:22:15 -0700921purge:
Jiri Slabyc500c972008-05-16 11:49:16 +0200922 skb_queue_purge(&session->ctrl_transmit);
923 skb_queue_purge(&session->intr_transmit);
Marcel Holtmannedad6382009-08-22 14:22:15 -0700924
Jiri Slabyc500c972008-05-16 11:49:16 +0200925failed:
926 up_write(&hidp_session_sem);
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100927
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700928 input_free_device(session->input);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700929 kfree(session);
930 return err;
931}
932
933int hidp_del_connection(struct hidp_conndel_req *req)
934{
935 struct hidp_session *session;
936 int err = 0;
937
938 BT_DBG("");
939
940 down_read(&hidp_session_sem);
941
942 session = __hidp_get_session(&req->bdaddr);
943 if (session) {
944 if (req->flags & (1 << HIDP_VIRTUAL_CABLE_UNPLUG)) {
945 hidp_send_ctrl_message(session,
946 HIDP_TRANS_HID_CONTROL | HIDP_CTRL_VIRTUAL_CABLE_UNPLUG, NULL, 0);
947 } else {
948 /* Flush the transmit queues */
949 skb_queue_purge(&session->ctrl_transmit);
950 skb_queue_purge(&session->intr_transmit);
951
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700952 /* Wakeup user-space polling for socket errors */
953 session->intr_sock->sk->sk_err = EUNATCH;
954 session->ctrl_sock->sk->sk_err = EUNATCH;
955
956 /* Kill session thread */
Peter Hurley6fc43002011-06-30 13:53:53 -0400957 atomic_inc(&session->terminate);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700958 hidp_schedule(session);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700959 }
960 } else
961 err = -ENOENT;
962
963 up_read(&hidp_session_sem);
964 return err;
965}
966
967int hidp_get_connlist(struct hidp_connlist_req *req)
968{
969 struct list_head *p;
970 int err = 0, n = 0;
971
972 BT_DBG("");
973
974 down_read(&hidp_session_sem);
975
976 list_for_each(p, &hidp_session_list) {
977 struct hidp_session *session;
978 struct hidp_conninfo ci;
979
980 session = list_entry(p, struct hidp_session, list);
981
982 __hidp_copy_session(session, &ci);
983
984 if (copy_to_user(req->ci, &ci, sizeof(ci))) {
985 err = -EFAULT;
986 break;
987 }
988
989 if (++n >= req->cnum)
990 break;
991
992 req->ci++;
993 }
994 req->cnum = n;
995
996 up_read(&hidp_session_sem);
997 return err;
998}
999
1000int hidp_get_conninfo(struct hidp_conninfo *ci)
1001{
1002 struct hidp_session *session;
1003 int err = 0;
1004
1005 down_read(&hidp_session_sem);
1006
1007 session = __hidp_get_session(&ci->bdaddr);
1008 if (session)
1009 __hidp_copy_session(session, ci);
1010 else
1011 err = -ENOENT;
1012
1013 up_read(&hidp_session_sem);
1014 return err;
1015}
1016
Jiri Slaby85cdaf52008-05-16 11:49:15 +02001017static const struct hid_device_id hidp_table[] = {
1018 { HID_BLUETOOTH_DEVICE(HID_ANY_ID, HID_ANY_ID) },
1019 { }
1020};
1021
1022static struct hid_driver hidp_driver = {
1023 .name = "generic-bluetooth",
1024 .id_table = hidp_table,
1025};
1026
Linus Torvalds1da177e2005-04-16 15:20:36 -07001027static int __init hidp_init(void)
1028{
Jiri Slaby85cdaf52008-05-16 11:49:15 +02001029 int ret;
1030
Linus Torvalds1da177e2005-04-16 15:20:36 -07001031 BT_INFO("HIDP (Human Interface Emulation) ver %s", VERSION);
1032
Jiri Slaby85cdaf52008-05-16 11:49:15 +02001033 ret = hid_register_driver(&hidp_driver);
1034 if (ret)
1035 goto err;
1036
1037 ret = hidp_init_sockets();
1038 if (ret)
1039 goto err_drv;
1040
1041 return 0;
1042err_drv:
1043 hid_unregister_driver(&hidp_driver);
1044err:
1045 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001046}
1047
1048static void __exit hidp_exit(void)
1049{
1050 hidp_cleanup_sockets();
Jiri Slaby85cdaf52008-05-16 11:49:15 +02001051 hid_unregister_driver(&hidp_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001052}
1053
1054module_init(hidp_init);
1055module_exit(hidp_exit);
1056
1057MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
1058MODULE_DESCRIPTION("Bluetooth HIDP ver " VERSION);
1059MODULE_VERSION(VERSION);
1060MODULE_LICENSE("GPL");
1061MODULE_ALIAS("bt-proto-6");