blob: 2694a0a6186daec737d9345128a22ff9ac881659 [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>
Alan Ott0ff17312011-01-18 03:04:40 -050039#include <linux/mutex.h>
Szymon Jancaabf6f82011-04-05 15:37:45 +020040#include <linux/kthread.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070041#include <net/sock.h>
42
43#include <linux/input.h>
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +010044#include <linux/hid.h>
Marcel Holtmann364f6352009-08-22 14:15:53 -070045#include <linux/hidraw.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070046
47#include <net/bluetooth/bluetooth.h>
Marcel Holtmann0a85b962006-07-06 13:09:02 +020048#include <net/bluetooth/hci_core.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070049#include <net/bluetooth/l2cap.h>
50
51#include "hidp.h"
52
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +010053#define VERSION "1.2"
Linus Torvalds1da177e2005-04-16 15:20:36 -070054
55static DECLARE_RWSEM(hidp_session_sem);
56static LIST_HEAD(hidp_session_list);
57
58static unsigned char hidp_keycode[256] = {
Szymon Janc17f09a72011-03-21 14:20:01 +010059 0, 0, 0, 0, 30, 48, 46, 32, 18, 33, 34, 35, 23, 36,
60 37, 38, 50, 49, 24, 25, 16, 19, 31, 20, 22, 47, 17, 45,
61 21, 44, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 28, 1,
62 14, 15, 57, 12, 13, 26, 27, 43, 43, 39, 40, 41, 51, 52,
63 53, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 87, 88,
64 99, 70, 119, 110, 102, 104, 111, 107, 109, 106, 105, 108, 103, 69,
65 98, 55, 74, 78, 96, 79, 80, 81, 75, 76, 77, 71, 72, 73,
66 82, 83, 86, 127, 116, 117, 183, 184, 185, 186, 187, 188, 189, 190,
67 191, 192, 193, 194, 134, 138, 130, 132, 128, 129, 131, 137, 133, 135,
68 136, 113, 115, 114, 0, 0, 0, 121, 0, 89, 93, 124, 92, 94,
69 95, 0, 0, 0, 122, 123, 90, 91, 85, 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 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
74 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
75 29, 42, 56, 125, 97, 54, 100, 126, 164, 166, 165, 163, 161, 115,
76 114, 113, 150, 158, 159, 128, 136, 177, 178, 176, 142, 152, 173, 140
Linus Torvalds1da177e2005-04-16 15:20:36 -070077};
78
79static unsigned char hidp_mkeyspat[] = { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 };
80
81static struct hidp_session *__hidp_get_session(bdaddr_t *bdaddr)
82{
83 struct hidp_session *session;
Linus Torvalds1da177e2005-04-16 15:20:36 -070084
85 BT_DBG("");
86
Gustavo F. Padovancd11cdd2011-10-06 17:35:31 -030087 list_for_each_entry(session, &hidp_session_list, list) {
Linus Torvalds1da177e2005-04-16 15:20:36 -070088 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
David Herrmann794d1752011-08-26 14:06:02 +0200256 if (atomic_read(&session->terminate))
257 return -EIO;
258
Andrei Emeltchenko5a08ecc2011-01-11 17:20:20 +0200259 skb = alloc_skb(size + 1, GFP_ATOMIC);
260 if (!skb) {
Bastien Nocera6bf82682010-01-20 12:00:42 +0000261 BT_ERR("Can't allocate memory for new frame");
262 return -ENOMEM;
263 }
264
265 *skb_put(skb, 1) = hdr;
266 if (data && size > 0)
267 memcpy(skb_put(skb, size), data, size);
268
269 skb_queue_tail(&session->ctrl_transmit, skb);
270
271 return 0;
272}
273
274static inline int hidp_send_ctrl_message(struct hidp_session *session,
275 unsigned char hdr, unsigned char *data, int size)
276{
277 int err;
278
279 err = __hidp_send_ctrl_message(session, hdr, data, size);
280
281 hidp_schedule(session);
282
283 return err;
284}
285
Andrew Morton91f5cca2008-02-05 03:07:58 -0800286static int hidp_queue_report(struct hidp_session *session,
287 unsigned char *data, int size)
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100288{
289 struct sk_buff *skb;
290
Dave Young6792b5e2007-10-20 14:15:39 +0200291 BT_DBG("session %p hid %p data %p size %d", session, session->hid, data, size);
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100292
Andrei Emeltchenko5a08ecc2011-01-11 17:20:20 +0200293 skb = alloc_skb(size + 1, GFP_ATOMIC);
294 if (!skb) {
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100295 BT_ERR("Can't allocate memory for new frame");
296 return -ENOMEM;
297 }
298
299 *skb_put(skb, 1) = 0xa2;
300 if (size > 0)
301 memcpy(skb_put(skb, size), data, size);
302
303 skb_queue_tail(&session->intr_transmit, skb);
304
305 hidp_schedule(session);
306
307 return 0;
308}
309
310static int hidp_send_report(struct hidp_session *session, struct hid_report *report)
311{
312 unsigned char buf[32];
313 int rsize;
314
315 rsize = ((report->size - 1) >> 3) + 1 + (report->id > 0);
316 if (rsize > sizeof(buf))
317 return -EIO;
318
319 hid_output_report(report, buf);
320
321 return hidp_queue_report(session, buf, rsize);
322}
323
Alan Ott0ff17312011-01-18 03:04:40 -0500324static int hidp_get_raw_report(struct hid_device *hid,
325 unsigned char report_number,
326 unsigned char *data, size_t count,
Jiri Kosinad4bfa032010-01-29 15:03:36 +0100327 unsigned char report_type)
Jiri Kosina2da31932009-11-26 16:20:56 +0100328{
Alan Ott0ff17312011-01-18 03:04:40 -0500329 struct hidp_session *session = hid->driver_data;
330 struct sk_buff *skb;
331 size_t len;
332 int numbered_reports = hid->report_enum[report_type].numbered;
David Herrmann794d1752011-08-26 14:06:02 +0200333 int ret;
Alan Ott0ff17312011-01-18 03:04:40 -0500334
Jiri Kosinad4bfa032010-01-29 15:03:36 +0100335 switch (report_type) {
336 case HID_FEATURE_REPORT:
Alan Ott0ff17312011-01-18 03:04:40 -0500337 report_type = HIDP_TRANS_GET_REPORT | HIDP_DATA_RTYPE_FEATURE;
338 break;
339 case HID_INPUT_REPORT:
340 report_type = HIDP_TRANS_GET_REPORT | HIDP_DATA_RTYPE_INPUT;
Jiri Kosinad4bfa032010-01-29 15:03:36 +0100341 break;
342 case HID_OUTPUT_REPORT:
Alan Ott0ff17312011-01-18 03:04:40 -0500343 report_type = HIDP_TRANS_GET_REPORT | HIDP_DATA_RTYPE_OUPUT;
Jiri Kosinad4bfa032010-01-29 15:03:36 +0100344 break;
345 default:
346 return -EINVAL;
347 }
348
Alan Ott0ff17312011-01-18 03:04:40 -0500349 if (mutex_lock_interruptible(&session->report_mutex))
350 return -ERESTARTSYS;
351
352 /* Set up our wait, and send the report request to the device. */
353 session->waiting_report_type = report_type & HIDP_DATA_RTYPE_MASK;
354 session->waiting_report_number = numbered_reports ? report_number : -1;
355 set_bit(HIDP_WAITING_FOR_RETURN, &session->flags);
356 data[0] = report_number;
David Herrmann794d1752011-08-26 14:06:02 +0200357 ret = hidp_send_ctrl_message(hid->driver_data, report_type, data, 1);
358 if (ret)
359 goto err;
Alan Ott0ff17312011-01-18 03:04:40 -0500360
361 /* Wait for the return of the report. The returned report
362 gets put in session->report_return. */
363 while (test_bit(HIDP_WAITING_FOR_RETURN, &session->flags)) {
364 int res;
365
366 res = wait_event_interruptible_timeout(session->report_queue,
367 !test_bit(HIDP_WAITING_FOR_RETURN, &session->flags),
368 5*HZ);
369 if (res == 0) {
370 /* timeout */
David Herrmann794d1752011-08-26 14:06:02 +0200371 ret = -EIO;
372 goto err;
Alan Ott0ff17312011-01-18 03:04:40 -0500373 }
374 if (res < 0) {
375 /* signal */
David Herrmann794d1752011-08-26 14:06:02 +0200376 ret = -ERESTARTSYS;
377 goto err;
Alan Ott0ff17312011-01-18 03:04:40 -0500378 }
379 }
380
381 skb = session->report_return;
382 if (skb) {
383 len = skb->len < count ? skb->len : count;
384 memcpy(data, skb->data, len);
385
386 kfree_skb(skb);
387 session->report_return = NULL;
388 } else {
389 /* Device returned a HANDSHAKE, indicating protocol error. */
390 len = -EIO;
391 }
392
393 clear_bit(HIDP_WAITING_FOR_RETURN, &session->flags);
394 mutex_unlock(&session->report_mutex);
395
396 return len;
397
David Herrmann794d1752011-08-26 14:06:02 +0200398err:
Alan Ott0ff17312011-01-18 03:04:40 -0500399 clear_bit(HIDP_WAITING_FOR_RETURN, &session->flags);
400 mutex_unlock(&session->report_mutex);
David Herrmann794d1752011-08-26 14:06:02 +0200401 return ret;
Alan Ott0ff17312011-01-18 03:04:40 -0500402}
403
Linus Torvalds1da177e2005-04-16 15:20:36 -0700404static int hidp_output_raw_report(struct hid_device *hid, unsigned char *data, size_t count,
Jiri Kosina2da31932009-11-26 16:20:56 +0100405 unsigned char report_type)
406{
Alan Ott08254112011-01-18 03:04:38 -0500407 struct hidp_session *session = hid->driver_data;
408 int ret;
409
Jiri Kosinad4bfa032010-01-29 15:03:36 +0100410 switch (report_type) {
411 case HID_FEATURE_REPORT:
412 report_type = HIDP_TRANS_SET_REPORT | HIDP_DATA_RTYPE_FEATURE;
413 break;
414 case HID_OUTPUT_REPORT:
Antonio Ospite97e1efb2011-02-20 18:26:46 +0100415 report_type = HIDP_TRANS_SET_REPORT | HIDP_DATA_RTYPE_OUPUT;
Jiri Kosinad4bfa032010-01-29 15:03:36 +0100416 break;
417 default:
418 return -EINVAL;
419 }
420
Alan Ott08254112011-01-18 03:04:38 -0500421 if (mutex_lock_interruptible(&session->report_mutex))
422 return -ERESTARTSYS;
423
424 /* Set up our wait, and send the report request to the device. */
425 set_bit(HIDP_WAITING_FOR_SEND_ACK, &session->flags);
David Herrmann794d1752011-08-26 14:06:02 +0200426 ret = hidp_send_ctrl_message(hid->driver_data, report_type, data,
427 count);
428 if (ret)
Alan Ott08254112011-01-18 03:04:38 -0500429 goto err;
Alan Ott08254112011-01-18 03:04:38 -0500430
431 /* Wait for the ACK from the device. */
432 while (test_bit(HIDP_WAITING_FOR_SEND_ACK, &session->flags)) {
433 int res;
434
435 res = wait_event_interruptible_timeout(session->report_queue,
436 !test_bit(HIDP_WAITING_FOR_SEND_ACK, &session->flags),
437 10*HZ);
438 if (res == 0) {
439 /* timeout */
440 ret = -EIO;
441 goto err;
442 }
443 if (res < 0) {
444 /* signal */
445 ret = -ERESTARTSYS;
446 goto err;
447 }
448 }
449
450 if (!session->output_report_success) {
451 ret = -EIO;
452 goto err;
453 }
454
455 ret = count;
456
457err:
458 clear_bit(HIDP_WAITING_FOR_SEND_ACK, &session->flags);
459 mutex_unlock(&session->report_mutex);
460 return ret;
Jiri Kosina2da31932009-11-26 16:20:56 +0100461}
462
Linus Torvalds1da177e2005-04-16 15:20:36 -0700463static void hidp_idle_timeout(unsigned long arg)
464{
465 struct hidp_session *session = (struct hidp_session *) arg;
466
Peter Hurley7bb59df2011-06-30 13:53:53 -0400467 atomic_inc(&session->terminate);
468 wake_up_process(session->task);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700469}
470
Andrew Morton91f5cca2008-02-05 03:07:58 -0800471static void hidp_set_timer(struct hidp_session *session)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700472{
473 if (session->idle_to > 0)
474 mod_timer(&session->timer, jiffies + HZ * session->idle_to);
475}
476
477static inline void hidp_del_timer(struct hidp_session *session)
478{
479 if (session->idle_to > 0)
480 del_timer(&session->timer);
481}
482
Andrew Morton91f5cca2008-02-05 03:07:58 -0800483static void hidp_process_handshake(struct hidp_session *session,
484 unsigned char param)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700485{
486 BT_DBG("session %p param 0x%02x", session, param);
Alan Ott08254112011-01-18 03:04:38 -0500487 session->output_report_success = 0; /* default condition */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700488
489 switch (param) {
490 case HIDP_HSHK_SUCCESSFUL:
491 /* FIXME: Call into SET_ GET_ handlers here */
Alan Ott08254112011-01-18 03:04:38 -0500492 session->output_report_success = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700493 break;
494
495 case HIDP_HSHK_NOT_READY:
496 case HIDP_HSHK_ERR_INVALID_REPORT_ID:
497 case HIDP_HSHK_ERR_UNSUPPORTED_REQUEST:
498 case HIDP_HSHK_ERR_INVALID_PARAMETER:
Alan Ott0ff17312011-01-18 03:04:40 -0500499 if (test_bit(HIDP_WAITING_FOR_RETURN, &session->flags)) {
500 clear_bit(HIDP_WAITING_FOR_RETURN, &session->flags);
501 wake_up_interruptible(&session->report_queue);
502 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700503 /* FIXME: Call into SET_ GET_ handlers here */
504 break;
505
506 case HIDP_HSHK_ERR_UNKNOWN:
507 break;
508
509 case HIDP_HSHK_ERR_FATAL:
510 /* Device requests a reboot, as this is the only way this error
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900511 * can be recovered. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700512 __hidp_send_ctrl_message(session,
513 HIDP_TRANS_HID_CONTROL | HIDP_CTRL_SOFT_RESET, NULL, 0);
514 break;
515
516 default:
517 __hidp_send_ctrl_message(session,
518 HIDP_TRANS_HANDSHAKE | HIDP_HSHK_ERR_INVALID_PARAMETER, NULL, 0);
519 break;
520 }
Alan Ott08254112011-01-18 03:04:38 -0500521
522 /* Wake up the waiting thread. */
523 if (test_bit(HIDP_WAITING_FOR_SEND_ACK, &session->flags)) {
524 clear_bit(HIDP_WAITING_FOR_SEND_ACK, &session->flags);
525 wake_up_interruptible(&session->report_queue);
526 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700527}
528
Andrew Morton91f5cca2008-02-05 03:07:58 -0800529static void hidp_process_hid_control(struct hidp_session *session,
530 unsigned char param)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700531{
532 BT_DBG("session %p param 0x%02x", session, param);
533
Dave Youngeff001e2008-02-05 03:07:14 -0800534 if (param == HIDP_CTRL_VIRTUAL_CABLE_UNPLUG) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700535 /* Flush the transmit queues */
536 skb_queue_purge(&session->ctrl_transmit);
537 skb_queue_purge(&session->intr_transmit);
538
Peter Hurley7bb59df2011-06-30 13:53:53 -0400539 atomic_inc(&session->terminate);
540 wake_up_process(current);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700541 }
542}
543
Alan Ott0ff17312011-01-18 03:04:40 -0500544/* Returns true if the passed-in skb should be freed by the caller. */
545static int hidp_process_data(struct hidp_session *session, struct sk_buff *skb,
Andrew Morton91f5cca2008-02-05 03:07:58 -0800546 unsigned char param)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700547{
Alan Ott0ff17312011-01-18 03:04:40 -0500548 int done_with_skb = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700549 BT_DBG("session %p skb %p len %d param 0x%02x", session, skb, skb->len, param);
550
551 switch (param) {
552 case HIDP_DATA_RTYPE_INPUT:
553 hidp_set_timer(session);
554
555 if (session->input)
556 hidp_input_report(session, skb);
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100557
558 if (session->hid)
559 hid_input_report(session->hid, HID_INPUT_REPORT, skb->data, skb->len, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700560 break;
561
562 case HIDP_DATA_RTYPE_OTHER:
563 case HIDP_DATA_RTYPE_OUPUT:
564 case HIDP_DATA_RTYPE_FEATURE:
565 break;
566
567 default:
568 __hidp_send_ctrl_message(session,
569 HIDP_TRANS_HANDSHAKE | HIDP_HSHK_ERR_INVALID_PARAMETER, NULL, 0);
570 }
Alan Ott0ff17312011-01-18 03:04:40 -0500571
572 if (test_bit(HIDP_WAITING_FOR_RETURN, &session->flags) &&
573 param == session->waiting_report_type) {
574 if (session->waiting_report_number < 0 ||
575 session->waiting_report_number == skb->data[0]) {
576 /* hidp_get_raw_report() is waiting on this report. */
577 session->report_return = skb;
578 done_with_skb = 0;
579 clear_bit(HIDP_WAITING_FOR_RETURN, &session->flags);
580 wake_up_interruptible(&session->report_queue);
581 }
582 }
583
584 return done_with_skb;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700585}
586
Andrew Morton91f5cca2008-02-05 03:07:58 -0800587static void hidp_recv_ctrl_frame(struct hidp_session *session,
588 struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700589{
590 unsigned char hdr, type, param;
Alan Ott0ff17312011-01-18 03:04:40 -0500591 int free_skb = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700592
593 BT_DBG("session %p skb %p len %d", session, skb, skb->len);
594
595 hdr = skb->data[0];
596 skb_pull(skb, 1);
597
598 type = hdr & HIDP_HEADER_TRANS_MASK;
599 param = hdr & HIDP_HEADER_PARAM_MASK;
600
601 switch (type) {
602 case HIDP_TRANS_HANDSHAKE:
603 hidp_process_handshake(session, param);
604 break;
605
606 case HIDP_TRANS_HID_CONTROL:
607 hidp_process_hid_control(session, param);
608 break;
609
610 case HIDP_TRANS_DATA:
Alan Ott0ff17312011-01-18 03:04:40 -0500611 free_skb = hidp_process_data(session, skb, param);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700612 break;
613
614 default:
615 __hidp_send_ctrl_message(session,
616 HIDP_TRANS_HANDSHAKE | HIDP_HSHK_ERR_UNSUPPORTED_REQUEST, NULL, 0);
617 break;
618 }
619
Alan Ott0ff17312011-01-18 03:04:40 -0500620 if (free_skb)
621 kfree_skb(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700622}
623
Andrew Morton91f5cca2008-02-05 03:07:58 -0800624static void hidp_recv_intr_frame(struct hidp_session *session,
625 struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700626{
627 unsigned char hdr;
628
629 BT_DBG("session %p skb %p len %d", session, skb, skb->len);
630
631 hdr = skb->data[0];
632 skb_pull(skb, 1);
633
634 if (hdr == (HIDP_TRANS_DATA | HIDP_DATA_RTYPE_INPUT)) {
635 hidp_set_timer(session);
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100636
Linus Torvalds1da177e2005-04-16 15:20:36 -0700637 if (session->input)
638 hidp_input_report(session, skb);
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100639
640 if (session->hid) {
641 hid_input_report(session->hid, HID_INPUT_REPORT, skb->data, skb->len, 1);
642 BT_DBG("report len %d", skb->len);
643 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700644 } else {
645 BT_DBG("Unsupported protocol header 0x%02x", hdr);
646 }
647
648 kfree_skb(skb);
649}
650
651static int hidp_send_frame(struct socket *sock, unsigned char *data, int len)
652{
653 struct kvec iv = { data, len };
654 struct msghdr msg;
655
656 BT_DBG("sock %p data %p len %d", sock, data, len);
657
658 if (!len)
659 return 0;
660
661 memset(&msg, 0, sizeof(msg));
662
663 return kernel_sendmsg(sock, &msg, &iv, 1, len);
664}
665
David S. Millerb03efcf2005-07-08 14:57:23 -0700666static void hidp_process_transmit(struct hidp_session *session)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700667{
668 struct sk_buff *skb;
669
670 BT_DBG("session %p", session);
671
672 while ((skb = skb_dequeue(&session->ctrl_transmit))) {
673 if (hidp_send_frame(session->ctrl_sock, skb->data, skb->len) < 0) {
674 skb_queue_head(&session->ctrl_transmit, skb);
675 break;
676 }
677
678 hidp_set_timer(session);
679 kfree_skb(skb);
680 }
681
682 while ((skb = skb_dequeue(&session->intr_transmit))) {
683 if (hidp_send_frame(session->intr_sock, skb->data, skb->len) < 0) {
684 skb_queue_head(&session->intr_transmit, skb);
685 break;
686 }
687
688 hidp_set_timer(session);
689 kfree_skb(skb);
690 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700691}
692
693static int hidp_session(void *arg)
694{
695 struct hidp_session *session = arg;
696 struct sock *ctrl_sk = session->ctrl_sock->sk;
697 struct sock *intr_sk = session->intr_sock->sk;
698 struct sk_buff *skb;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700699 wait_queue_t ctrl_wait, intr_wait;
700
701 BT_DBG("session %p", session);
702
Linus Torvalds1da177e2005-04-16 15:20:36 -0700703 set_user_nice(current, -15);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700704
705 init_waitqueue_entry(&ctrl_wait, current);
706 init_waitqueue_entry(&intr_wait, current);
Eric Dumazetaa395142010-04-20 13:03:51 +0000707 add_wait_queue(sk_sleep(ctrl_sk), &ctrl_wait);
708 add_wait_queue(sk_sleep(intr_sk), &intr_wait);
Alan Ott0f69dca2011-01-18 03:04:37 -0500709 session->waiting_for_startup = 0;
710 wake_up_interruptible(&session->startup_queue);
Peter Hurley7bb59df2011-06-30 13:53:53 -0400711 set_current_state(TASK_INTERRUPTIBLE);
712 while (!atomic_read(&session->terminate)) {
Szymon Janc17f09a72011-03-21 14:20:01 +0100713 if (ctrl_sk->sk_state != BT_CONNECTED ||
714 intr_sk->sk_state != BT_CONNECTED)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700715 break;
716
Linus Torvalds1da177e2005-04-16 15:20:36 -0700717 while ((skb = skb_dequeue(&intr_sk->sk_receive_queue))) {
718 skb_orphan(skb);
Mat Martineau44935722011-07-22 14:53:58 -0700719 if (!skb_linearize(skb))
720 hidp_recv_intr_frame(session, skb);
721 else
722 kfree_skb(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700723 }
724
Gustavo F. Padovandc0da5c2011-10-06 18:02:13 -0300725 while ((skb = skb_dequeue(&ctrl_sk->sk_receive_queue))) {
726 skb_orphan(skb);
727 if (!skb_linearize(skb))
728 hidp_recv_ctrl_frame(session, skb);
729 else
730 kfree_skb(skb);
731 }
732
Linus Torvalds1da177e2005-04-16 15:20:36 -0700733 hidp_process_transmit(session);
734
735 schedule();
Peter Hurley7bb59df2011-06-30 13:53:53 -0400736 set_current_state(TASK_INTERRUPTIBLE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700737 }
738 set_current_state(TASK_RUNNING);
Eric Dumazetaa395142010-04-20 13:03:51 +0000739 remove_wait_queue(sk_sleep(intr_sk), &intr_wait);
740 remove_wait_queue(sk_sleep(ctrl_sk), &ctrl_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700741
David Herrmann794d1752011-08-26 14:06:02 +0200742 clear_bit(HIDP_WAITING_FOR_SEND_ACK, &session->flags);
743 clear_bit(HIDP_WAITING_FOR_RETURN, &session->flags);
744 wake_up_interruptible(&session->report_queue);
745
Linus Torvalds1da177e2005-04-16 15:20:36 -0700746 down_write(&hidp_session_sem);
747
748 hidp_del_timer(session);
749
Linus Torvalds1da177e2005-04-16 15:20:36 -0700750 if (session->input) {
751 input_unregister_device(session->input);
Dmitry Torokhov34abf912005-09-15 02:01:40 -0500752 session->input = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700753 }
754
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100755 if (session->hid) {
Jiri Slaby85cdaf52008-05-16 11:49:15 +0200756 hid_destroy_device(session->hid);
Marcel Holtmannedad6382009-08-22 14:22:15 -0700757 session->hid = NULL;
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100758 }
759
Marcel Holtmannec8dab32008-07-14 20:13:53 +0200760 /* Wakeup user-space polling for socket errors */
761 session->intr_sock->sk->sk_err = EUNATCH;
762 session->ctrl_sock->sk->sk_err = EUNATCH;
763
764 hidp_schedule(session);
765
David Woodhouse1c398582007-07-07 14:58:39 -0400766 fput(session->intr_sock->file);
767
Eric Dumazetaa395142010-04-20 13:03:51 +0000768 wait_event_timeout(*(sk_sleep(ctrl_sk)),
David Woodhouse1c398582007-07-07 14:58:39 -0400769 (ctrl_sk->sk_state == BT_CLOSED), msecs_to_jiffies(500));
770
771 fput(session->ctrl_sock->file);
772
773 __hidp_unlink_session(session);
774
Linus Torvalds1da177e2005-04-16 15:20:36 -0700775 up_write(&hidp_session_sem);
776
Peter Hurley1c97e942011-08-05 10:51:34 -0400777 kfree(session->rd_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700778 kfree(session);
779 return 0;
780}
781
Marcel Holtmann0a85b962006-07-06 13:09:02 +0200782static struct device *hidp_get_device(struct hidp_session *session)
783{
784 bdaddr_t *src = &bt_sk(session->ctrl_sock->sk)->src;
785 bdaddr_t *dst = &bt_sk(session->ctrl_sock->sk)->dst;
Marcel Holtmannedad6382009-08-22 14:22:15 -0700786 struct device *device = NULL;
Marcel Holtmann0a85b962006-07-06 13:09:02 +0200787 struct hci_dev *hdev;
Marcel Holtmann0a85b962006-07-06 13:09:02 +0200788
789 hdev = hci_get_route(dst, src);
790 if (!hdev)
791 return NULL;
792
Marcel Holtmannedad6382009-08-22 14:22:15 -0700793 session->conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, dst);
794 if (session->conn)
795 device = &session->conn->dev;
Marcel Holtmann0a85b962006-07-06 13:09:02 +0200796
797 hci_dev_put(hdev);
798
Marcel Holtmannedad6382009-08-22 14:22:15 -0700799 return device;
Marcel Holtmann0a85b962006-07-06 13:09:02 +0200800}
801
Andrew Morton91f5cca2008-02-05 03:07:58 -0800802static int hidp_setup_input(struct hidp_session *session,
803 struct hidp_connadd_req *req)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700804{
Jiri Slabyc500c972008-05-16 11:49:16 +0200805 struct input_dev *input;
Marcel Holtmannedad6382009-08-22 14:22:15 -0700806 int err, i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700807
Jiri Slabyc500c972008-05-16 11:49:16 +0200808 input = input_allocate_device();
809 if (!input)
810 return -ENOMEM;
811
812 session->input = input;
813
Marcel Holtmann5be39462007-05-09 09:15:30 +0200814 input_set_drvdata(input, session);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700815
Dmitry Torokhov34abf912005-09-15 02:01:40 -0500816 input->name = "Bluetooth HID Boot Protocol Device";
817
Linus Torvalds1da177e2005-04-16 15:20:36 -0700818 input->id.bustype = BUS_BLUETOOTH;
819 input->id.vendor = req->vendor;
820 input->id.product = req->product;
821 input->id.version = req->version;
822
823 if (req->subclass & 0x40) {
824 set_bit(EV_KEY, input->evbit);
825 set_bit(EV_LED, input->evbit);
826 set_bit(EV_REP, input->evbit);
827
828 set_bit(LED_NUML, input->ledbit);
829 set_bit(LED_CAPSL, input->ledbit);
830 set_bit(LED_SCROLLL, input->ledbit);
831 set_bit(LED_COMPOSE, input->ledbit);
832 set_bit(LED_KANA, input->ledbit);
833
834 for (i = 0; i < sizeof(hidp_keycode); i++)
835 set_bit(hidp_keycode[i], input->keybit);
836 clear_bit(0, input->keybit);
837 }
838
839 if (req->subclass & 0x80) {
Jiri Slaby7b19ada2007-10-18 23:40:32 -0700840 input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL);
841 input->keybit[BIT_WORD(BTN_MOUSE)] = BIT_MASK(BTN_LEFT) |
842 BIT_MASK(BTN_RIGHT) | BIT_MASK(BTN_MIDDLE);
843 input->relbit[0] = BIT_MASK(REL_X) | BIT_MASK(REL_Y);
844 input->keybit[BIT_WORD(BTN_MOUSE)] |= BIT_MASK(BTN_SIDE) |
845 BIT_MASK(BTN_EXTRA);
846 input->relbit[0] |= BIT_MASK(REL_WHEEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700847 }
848
Marcel Holtmann5be39462007-05-09 09:15:30 +0200849 input->dev.parent = hidp_get_device(session);
Marcel Holtmann0a85b962006-07-06 13:09:02 +0200850
Linus Torvalds1da177e2005-04-16 15:20:36 -0700851 input->event = hidp_input_event;
852
Marcel Holtmannedad6382009-08-22 14:22:15 -0700853 err = input_register_device(input);
854 if (err < 0) {
Peter Hurley615aedd2011-08-05 10:51:50 -0400855 input_free_device(input);
856 session->input = NULL;
Marcel Holtmannedad6382009-08-22 14:22:15 -0700857 return err;
858 }
859
860 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700861}
862
Marcel Holtmannf5ffd462007-02-17 23:58:53 +0100863static int hidp_open(struct hid_device *hid)
864{
865 return 0;
866}
867
868static void hidp_close(struct hid_device *hid)
869{
870}
871
Jiri Slabyc500c972008-05-16 11:49:16 +0200872static int hidp_parse(struct hid_device *hid)
873{
874 struct hidp_session *session = hid->driver_data;
Jiri Slabyc500c972008-05-16 11:49:16 +0200875
Michael Poole15c697c2010-02-05 12:23:43 -0500876 return hid_parse_report(session->hid, session->rd_data,
877 session->rd_size);
Jiri Slabyc500c972008-05-16 11:49:16 +0200878}
879
880static int hidp_start(struct hid_device *hid)
881{
882 struct hidp_session *session = hid->driver_data;
883 struct hid_report *report;
884
David Herrmann142c69c2011-08-26 13:27:12 +0200885 if (hid->quirks & HID_QUIRK_NO_INIT_REPORTS)
886 return 0;
887
Jiri Slabyc500c972008-05-16 11:49:16 +0200888 list_for_each_entry(report, &hid->report_enum[HID_INPUT_REPORT].
889 report_list, list)
890 hidp_send_report(session, report);
891
892 list_for_each_entry(report, &hid->report_enum[HID_FEATURE_REPORT].
893 report_list, list)
894 hidp_send_report(session, report);
895
Jiri Slabyc500c972008-05-16 11:49:16 +0200896 return 0;
897}
898
899static void hidp_stop(struct hid_device *hid)
900{
901 struct hidp_session *session = hid->driver_data;
902
903 skb_queue_purge(&session->ctrl_transmit);
904 skb_queue_purge(&session->intr_transmit);
905
Jiri Slabyc500c972008-05-16 11:49:16 +0200906 hid->claimed = 0;
907}
908
909static struct hid_ll_driver hidp_hid_driver = {
910 .parse = hidp_parse,
911 .start = hidp_start,
912 .stop = hidp_stop,
913 .open = hidp_open,
914 .close = hidp_close,
915 .hidinput_input_event = hidp_hidinput_event,
916};
917
Alan Ott0f69dca2011-01-18 03:04:37 -0500918/* This function sets up the hid device. It does not add it
919 to the HID system. That is done in hidp_add_connection(). */
Jiri Slaby85cdaf52008-05-16 11:49:15 +0200920static int hidp_setup_hid(struct hidp_session *session,
Andrew Morton91f5cca2008-02-05 03:07:58 -0800921 struct hidp_connadd_req *req)
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100922{
Jiri Slabyc500c972008-05-16 11:49:16 +0200923 struct hid_device *hid;
Marcel Holtmannedad6382009-08-22 14:22:15 -0700924 int err;
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100925
Michael Poole15c697c2010-02-05 12:23:43 -0500926 session->rd_data = kzalloc(req->rd_size, GFP_KERNEL);
927 if (!session->rd_data)
928 return -ENOMEM;
929
930 if (copy_from_user(session->rd_data, req->rd_data, req->rd_size)) {
931 err = -EFAULT;
932 goto fault;
933 }
934 session->rd_size = req->rd_size;
935
Jiri Slabyc500c972008-05-16 11:49:16 +0200936 hid = hid_allocate_device();
Michael Poole15c697c2010-02-05 12:23:43 -0500937 if (IS_ERR(hid)) {
938 err = PTR_ERR(hid);
939 goto fault;
940 }
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100941
Jiri Slabyc500c972008-05-16 11:49:16 +0200942 session->hid = hid;
Michael Poole15c697c2010-02-05 12:23:43 -0500943
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100944 hid->driver_data = session;
945
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100946 hid->bus = BUS_BLUETOOTH;
947 hid->vendor = req->vendor;
948 hid->product = req->product;
949 hid->version = req->version;
Jiri Slabyc500c972008-05-16 11:49:16 +0200950 hid->country = req->country;
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100951
952 strncpy(hid->name, req->name, 128);
Gustavo F. Padovand6b2eb22010-09-03 18:29:46 -0300953 strncpy(hid->phys, batostr(&bt_sk(session->ctrl_sock->sk)->src), 64);
954 strncpy(hid->uniq, batostr(&bt_sk(session->ctrl_sock->sk)->dst), 64);
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100955
Jiri Slaby85cdaf52008-05-16 11:49:15 +0200956 hid->dev.parent = hidp_get_device(session);
Jiri Slabyc500c972008-05-16 11:49:16 +0200957 hid->ll_driver = &hidp_hid_driver;
Jiri Slaby85cdaf52008-05-16 11:49:15 +0200958
Alan Ott0ff17312011-01-18 03:04:40 -0500959 hid->hid_get_raw_report = hidp_get_raw_report;
Jiri Kosina2da31932009-11-26 16:20:56 +0100960 hid->hid_output_raw_report = hidp_output_raw_report;
961
Jiri Slabyc500c972008-05-16 11:49:16 +0200962 return 0;
Marcel Holtmannedad6382009-08-22 14:22:15 -0700963
Michael Poole15c697c2010-02-05 12:23:43 -0500964fault:
965 kfree(session->rd_data);
966 session->rd_data = NULL;
967
Marcel Holtmannedad6382009-08-22 14:22:15 -0700968 return err;
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100969}
970
Linus Torvalds1da177e2005-04-16 15:20:36 -0700971int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock, struct socket *intr_sock)
972{
973 struct hidp_session *session, *s;
Szymon Jancaabf6f82011-04-05 15:37:45 +0200974 int vendor, product;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700975 int err;
976
977 BT_DBG("");
978
979 if (bacmp(&bt_sk(ctrl_sock->sk)->src, &bt_sk(intr_sock->sk)->src) ||
980 bacmp(&bt_sk(ctrl_sock->sk)->dst, &bt_sk(intr_sock->sk)->dst))
981 return -ENOTUNIQ;
982
Marcel Holtmann25ea6db2006-07-06 15:40:09 +0200983 session = kzalloc(sizeof(struct hidp_session), GFP_KERNEL);
Dmitry Torokhov34abf912005-09-15 02:01:40 -0500984 if (!session)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700985 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700986
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100987 BT_DBG("rd_data %p rd_size %d", req->rd_data, req->rd_size);
988
Linus Torvalds1da177e2005-04-16 15:20:36 -0700989 down_write(&hidp_session_sem);
990
991 s = __hidp_get_session(&bt_sk(ctrl_sock->sk)->dst);
992 if (s && s->state == BT_CONNECTED) {
993 err = -EEXIST;
994 goto failed;
995 }
996
997 bacpy(&session->bdaddr, &bt_sk(ctrl_sock->sk)->dst);
998
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -0300999 session->ctrl_mtu = min_t(uint, l2cap_pi(ctrl_sock->sk)->chan->omtu,
1000 l2cap_pi(ctrl_sock->sk)->chan->imtu);
1001 session->intr_mtu = min_t(uint, l2cap_pi(intr_sock->sk)->chan->omtu,
1002 l2cap_pi(intr_sock->sk)->chan->imtu);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001003
1004 BT_DBG("ctrl mtu %d intr mtu %d", session->ctrl_mtu, session->intr_mtu);
1005
1006 session->ctrl_sock = ctrl_sock;
1007 session->intr_sock = intr_sock;
1008 session->state = BT_CONNECTED;
1009
Pavel Emelyanovb24b8a22008-01-23 21:20:07 -08001010 setup_timer(&session->timer, hidp_idle_timeout, (unsigned long)session);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001011
1012 skb_queue_head_init(&session->ctrl_transmit);
1013 skb_queue_head_init(&session->intr_transmit);
1014
Alan Ott0ff17312011-01-18 03:04:40 -05001015 mutex_init(&session->report_mutex);
1016 init_waitqueue_head(&session->report_queue);
Alan Ott0f69dca2011-01-18 03:04:37 -05001017 init_waitqueue_head(&session->startup_queue);
1018 session->waiting_for_startup = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001019 session->flags = req->flags & (1 << HIDP_BLUETOOTH_VENDOR_ID);
1020 session->idle_to = req->idle_to;
1021
Jiri Slabyc500c972008-05-16 11:49:16 +02001022 if (req->rd_size > 0) {
Jiri Slaby85cdaf52008-05-16 11:49:15 +02001023 err = hidp_setup_hid(session, req);
Jiri Slabyd458a9d2008-05-16 11:49:20 +02001024 if (err && err != -ENODEV)
Marcel Holtmannedad6382009-08-22 14:22:15 -07001025 goto purge;
Jiri Slabyc500c972008-05-16 11:49:16 +02001026 }
1027
1028 if (!session->hid) {
1029 err = hidp_setup_input(session, req);
1030 if (err < 0)
Marcel Holtmannedad6382009-08-22 14:22:15 -07001031 goto purge;
Jiri Slaby85cdaf52008-05-16 11:49:15 +02001032 }
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +01001033
Linus Torvalds1da177e2005-04-16 15:20:36 -07001034 __hidp_link_session(session);
1035
1036 hidp_set_timer(session);
1037
Szymon Jancaabf6f82011-04-05 15:37:45 +02001038 if (session->hid) {
1039 vendor = session->hid->vendor;
1040 product = session->hid->product;
1041 } else if (session->input) {
1042 vendor = session->input->id.vendor;
1043 product = session->input->id.product;
1044 } else {
1045 vendor = 0x0000;
1046 product = 0x0000;
1047 }
1048
1049 session->task = kthread_run(hidp_session, session, "khidpd_%04x%04x",
1050 vendor, product);
1051 if (IS_ERR(session->task)) {
1052 err = PTR_ERR(session->task);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001053 goto unlink;
Szymon Jancaabf6f82011-04-05 15:37:45 +02001054 }
1055
Alan Ott0f69dca2011-01-18 03:04:37 -05001056 while (session->waiting_for_startup) {
1057 wait_event_interruptible(session->startup_queue,
1058 !session->waiting_for_startup);
1059 }
1060
1061 err = hid_add_device(session->hid);
Peter Hurleye9d5cb52011-08-05 10:51:26 -04001062 if (err < 0) {
1063 atomic_inc(&session->terminate);
1064 wake_up_process(session->task);
1065 up_write(&hidp_session_sem);
1066 return err;
1067 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001068
1069 if (session->input) {
1070 hidp_send_ctrl_message(session,
1071 HIDP_TRANS_SET_PROTOCOL | HIDP_PROTO_BOOT, NULL, 0);
1072 session->flags |= (1 << HIDP_BOOT_PROTOCOL_MODE);
1073
1074 session->leds = 0xff;
1075 hidp_input_event(session->input, EV_LED, 0, 0);
1076 }
1077
1078 up_write(&hidp_session_sem);
1079 return 0;
1080
1081unlink:
1082 hidp_del_timer(session);
1083
1084 __hidp_unlink_session(session);
1085
Marcel Holtmannedad6382009-08-22 14:22:15 -07001086 if (session->input) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001087 input_unregister_device(session->input);
Marcel Holtmannedad6382009-08-22 14:22:15 -07001088 session->input = NULL;
1089 }
1090
1091 if (session->hid) {
Jiri Slaby85cdaf52008-05-16 11:49:15 +02001092 hid_destroy_device(session->hid);
Marcel Holtmannedad6382009-08-22 14:22:15 -07001093 session->hid = NULL;
1094 }
1095
Michael Poole15c697c2010-02-05 12:23:43 -05001096 kfree(session->rd_data);
1097 session->rd_data = NULL;
1098
Marcel Holtmannedad6382009-08-22 14:22:15 -07001099purge:
Jiri Slabyc500c972008-05-16 11:49:16 +02001100 skb_queue_purge(&session->ctrl_transmit);
1101 skb_queue_purge(&session->intr_transmit);
Marcel Holtmannedad6382009-08-22 14:22:15 -07001102
Jiri Slabyc500c972008-05-16 11:49:16 +02001103failed:
1104 up_write(&hidp_session_sem);
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +01001105
Linus Torvalds1da177e2005-04-16 15:20:36 -07001106 kfree(session);
1107 return err;
1108}
1109
1110int hidp_del_connection(struct hidp_conndel_req *req)
1111{
1112 struct hidp_session *session;
1113 int err = 0;
1114
1115 BT_DBG("");
1116
1117 down_read(&hidp_session_sem);
1118
1119 session = __hidp_get_session(&req->bdaddr);
1120 if (session) {
1121 if (req->flags & (1 << HIDP_VIRTUAL_CABLE_UNPLUG)) {
1122 hidp_send_ctrl_message(session,
1123 HIDP_TRANS_HID_CONTROL | HIDP_CTRL_VIRTUAL_CABLE_UNPLUG, NULL, 0);
1124 } else {
1125 /* Flush the transmit queues */
1126 skb_queue_purge(&session->ctrl_transmit);
1127 skb_queue_purge(&session->intr_transmit);
1128
Peter Hurley7bb59df2011-06-30 13:53:53 -04001129 atomic_inc(&session->terminate);
1130 wake_up_process(session->task);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001131 }
1132 } else
1133 err = -ENOENT;
1134
1135 up_read(&hidp_session_sem);
1136 return err;
1137}
1138
1139int hidp_get_connlist(struct hidp_connlist_req *req)
1140{
Gustavo F. Padovancd11cdd2011-10-06 17:35:31 -03001141 struct hidp_session *session;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001142 int err = 0, n = 0;
1143
1144 BT_DBG("");
1145
1146 down_read(&hidp_session_sem);
1147
Gustavo F. Padovancd11cdd2011-10-06 17:35:31 -03001148 list_for_each_entry(session, &hidp_session_list, list) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001149 struct hidp_conninfo ci;
1150
Linus Torvalds1da177e2005-04-16 15:20:36 -07001151 __hidp_copy_session(session, &ci);
1152
1153 if (copy_to_user(req->ci, &ci, sizeof(ci))) {
1154 err = -EFAULT;
1155 break;
1156 }
1157
1158 if (++n >= req->cnum)
1159 break;
1160
1161 req->ci++;
1162 }
1163 req->cnum = n;
1164
1165 up_read(&hidp_session_sem);
1166 return err;
1167}
1168
1169int hidp_get_conninfo(struct hidp_conninfo *ci)
1170{
1171 struct hidp_session *session;
1172 int err = 0;
1173
1174 down_read(&hidp_session_sem);
1175
1176 session = __hidp_get_session(&ci->bdaddr);
1177 if (session)
1178 __hidp_copy_session(session, ci);
1179 else
1180 err = -ENOENT;
1181
1182 up_read(&hidp_session_sem);
1183 return err;
1184}
1185
Jiri Slaby85cdaf52008-05-16 11:49:15 +02001186static const struct hid_device_id hidp_table[] = {
1187 { HID_BLUETOOTH_DEVICE(HID_ANY_ID, HID_ANY_ID) },
1188 { }
1189};
1190
1191static struct hid_driver hidp_driver = {
1192 .name = "generic-bluetooth",
1193 .id_table = hidp_table,
1194};
1195
Linus Torvalds1da177e2005-04-16 15:20:36 -07001196static int __init hidp_init(void)
1197{
Jiri Slaby85cdaf52008-05-16 11:49:15 +02001198 int ret;
1199
Linus Torvalds1da177e2005-04-16 15:20:36 -07001200 BT_INFO("HIDP (Human Interface Emulation) ver %s", VERSION);
1201
Jiri Slaby85cdaf52008-05-16 11:49:15 +02001202 ret = hid_register_driver(&hidp_driver);
1203 if (ret)
1204 goto err;
1205
1206 ret = hidp_init_sockets();
1207 if (ret)
1208 goto err_drv;
1209
1210 return 0;
1211err_drv:
1212 hid_unregister_driver(&hidp_driver);
1213err:
1214 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001215}
1216
1217static void __exit hidp_exit(void)
1218{
1219 hidp_cleanup_sockets();
Jiri Slaby85cdaf52008-05-16 11:49:15 +02001220 hid_unregister_driver(&hidp_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001221}
1222
1223module_init(hidp_init);
1224module_exit(hidp_exit);
1225
1226MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
1227MODULE_DESCRIPTION("Bluetooth HIDP ver " VERSION);
1228MODULE_VERSION(VERSION);
1229MODULE_LICENSE("GPL");
1230MODULE_ALIAS("bt-proto-6");