blob: 6cb1d9e8eac5e6fd85c78864aee8badbdc608b93 [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
Gustavo F. Padovan679344e2011-10-06 20:51:37 -0300666static void hidp_process_intr_transmit(struct hidp_session *session)
667{
668 struct sk_buff *skb;
669
670 BT_DBG("session %p", session);
671
672 while ((skb = skb_dequeue(&session->intr_transmit))) {
673 if (hidp_send_frame(session->intr_sock, skb->data, skb->len) < 0) {
674 skb_queue_head(&session->intr_transmit, skb);
675 break;
676 }
677
678 hidp_set_timer(session);
679 kfree_skb(skb);
680 }
681}
682
683static void hidp_process_ctrl_transmit(struct hidp_session *session)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684{
685 struct sk_buff *skb;
686
687 BT_DBG("session %p", session);
688
689 while ((skb = skb_dequeue(&session->ctrl_transmit))) {
690 if (hidp_send_frame(session->ctrl_sock, skb->data, skb->len) < 0) {
691 skb_queue_head(&session->ctrl_transmit, skb);
692 break;
693 }
694
695 hidp_set_timer(session);
696 kfree_skb(skb);
697 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700698}
699
700static int hidp_session(void *arg)
701{
702 struct hidp_session *session = arg;
703 struct sock *ctrl_sk = session->ctrl_sock->sk;
704 struct sock *intr_sk = session->intr_sock->sk;
705 struct sk_buff *skb;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700706 wait_queue_t ctrl_wait, intr_wait;
707
708 BT_DBG("session %p", session);
709
Linus Torvalds1da177e2005-04-16 15:20:36 -0700710 set_user_nice(current, -15);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700711
712 init_waitqueue_entry(&ctrl_wait, current);
713 init_waitqueue_entry(&intr_wait, current);
Eric Dumazetaa395142010-04-20 13:03:51 +0000714 add_wait_queue(sk_sleep(ctrl_sk), &ctrl_wait);
715 add_wait_queue(sk_sleep(intr_sk), &intr_wait);
Alan Ott0f69dca2011-01-18 03:04:37 -0500716 session->waiting_for_startup = 0;
717 wake_up_interruptible(&session->startup_queue);
Peter Hurley7bb59df2011-06-30 13:53:53 -0400718 set_current_state(TASK_INTERRUPTIBLE);
719 while (!atomic_read(&session->terminate)) {
Szymon Janc17f09a72011-03-21 14:20:01 +0100720 if (ctrl_sk->sk_state != BT_CONNECTED ||
721 intr_sk->sk_state != BT_CONNECTED)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700722 break;
723
Linus Torvalds1da177e2005-04-16 15:20:36 -0700724 while ((skb = skb_dequeue(&intr_sk->sk_receive_queue))) {
725 skb_orphan(skb);
Mat Martineau44935722011-07-22 14:53:58 -0700726 if (!skb_linearize(skb))
727 hidp_recv_intr_frame(session, skb);
728 else
729 kfree_skb(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700730 }
731
Gustavo F. Padovan679344e2011-10-06 20:51:37 -0300732 hidp_process_intr_transmit(session);
733
Gustavo F. Padovandc0da5c2011-10-06 18:02:13 -0300734 while ((skb = skb_dequeue(&ctrl_sk->sk_receive_queue))) {
735 skb_orphan(skb);
736 if (!skb_linearize(skb))
737 hidp_recv_ctrl_frame(session, skb);
738 else
739 kfree_skb(skb);
740 }
741
Gustavo F. Padovan679344e2011-10-06 20:51:37 -0300742 hidp_process_ctrl_transmit(session);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700743
744 schedule();
Peter Hurley7bb59df2011-06-30 13:53:53 -0400745 set_current_state(TASK_INTERRUPTIBLE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700746 }
747 set_current_state(TASK_RUNNING);
Eric Dumazetaa395142010-04-20 13:03:51 +0000748 remove_wait_queue(sk_sleep(intr_sk), &intr_wait);
749 remove_wait_queue(sk_sleep(ctrl_sk), &ctrl_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700750
David Herrmann794d1752011-08-26 14:06:02 +0200751 clear_bit(HIDP_WAITING_FOR_SEND_ACK, &session->flags);
752 clear_bit(HIDP_WAITING_FOR_RETURN, &session->flags);
753 wake_up_interruptible(&session->report_queue);
754
Linus Torvalds1da177e2005-04-16 15:20:36 -0700755 down_write(&hidp_session_sem);
756
757 hidp_del_timer(session);
758
Linus Torvalds1da177e2005-04-16 15:20:36 -0700759 if (session->input) {
760 input_unregister_device(session->input);
Dmitry Torokhov34abf912005-09-15 02:01:40 -0500761 session->input = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700762 }
763
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100764 if (session->hid) {
Jiri Slaby85cdaf52008-05-16 11:49:15 +0200765 hid_destroy_device(session->hid);
Marcel Holtmannedad6382009-08-22 14:22:15 -0700766 session->hid = NULL;
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100767 }
768
Marcel Holtmannec8dab32008-07-14 20:13:53 +0200769 /* Wakeup user-space polling for socket errors */
770 session->intr_sock->sk->sk_err = EUNATCH;
771 session->ctrl_sock->sk->sk_err = EUNATCH;
772
773 hidp_schedule(session);
774
David Woodhouse1c398582007-07-07 14:58:39 -0400775 fput(session->intr_sock->file);
776
Eric Dumazetaa395142010-04-20 13:03:51 +0000777 wait_event_timeout(*(sk_sleep(ctrl_sk)),
David Woodhouse1c398582007-07-07 14:58:39 -0400778 (ctrl_sk->sk_state == BT_CLOSED), msecs_to_jiffies(500));
779
780 fput(session->ctrl_sock->file);
781
782 __hidp_unlink_session(session);
783
Linus Torvalds1da177e2005-04-16 15:20:36 -0700784 up_write(&hidp_session_sem);
785
Peter Hurley1c97e942011-08-05 10:51:34 -0400786 kfree(session->rd_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700787 kfree(session);
788 return 0;
789}
790
Marcel Holtmann0a85b962006-07-06 13:09:02 +0200791static struct device *hidp_get_device(struct hidp_session *session)
792{
793 bdaddr_t *src = &bt_sk(session->ctrl_sock->sk)->src;
794 bdaddr_t *dst = &bt_sk(session->ctrl_sock->sk)->dst;
Marcel Holtmannedad6382009-08-22 14:22:15 -0700795 struct device *device = NULL;
Marcel Holtmann0a85b962006-07-06 13:09:02 +0200796 struct hci_dev *hdev;
Marcel Holtmann0a85b962006-07-06 13:09:02 +0200797
798 hdev = hci_get_route(dst, src);
799 if (!hdev)
800 return NULL;
801
Marcel Holtmannedad6382009-08-22 14:22:15 -0700802 session->conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, dst);
803 if (session->conn)
804 device = &session->conn->dev;
Marcel Holtmann0a85b962006-07-06 13:09:02 +0200805
806 hci_dev_put(hdev);
807
Marcel Holtmannedad6382009-08-22 14:22:15 -0700808 return device;
Marcel Holtmann0a85b962006-07-06 13:09:02 +0200809}
810
Andrew Morton91f5cca2008-02-05 03:07:58 -0800811static int hidp_setup_input(struct hidp_session *session,
812 struct hidp_connadd_req *req)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700813{
Jiri Slabyc500c972008-05-16 11:49:16 +0200814 struct input_dev *input;
Marcel Holtmannedad6382009-08-22 14:22:15 -0700815 int err, i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700816
Jiri Slabyc500c972008-05-16 11:49:16 +0200817 input = input_allocate_device();
818 if (!input)
819 return -ENOMEM;
820
821 session->input = input;
822
Marcel Holtmann5be39462007-05-09 09:15:30 +0200823 input_set_drvdata(input, session);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700824
Dmitry Torokhov34abf912005-09-15 02:01:40 -0500825 input->name = "Bluetooth HID Boot Protocol Device";
826
Linus Torvalds1da177e2005-04-16 15:20:36 -0700827 input->id.bustype = BUS_BLUETOOTH;
828 input->id.vendor = req->vendor;
829 input->id.product = req->product;
830 input->id.version = req->version;
831
832 if (req->subclass & 0x40) {
833 set_bit(EV_KEY, input->evbit);
834 set_bit(EV_LED, input->evbit);
835 set_bit(EV_REP, input->evbit);
836
837 set_bit(LED_NUML, input->ledbit);
838 set_bit(LED_CAPSL, input->ledbit);
839 set_bit(LED_SCROLLL, input->ledbit);
840 set_bit(LED_COMPOSE, input->ledbit);
841 set_bit(LED_KANA, input->ledbit);
842
843 for (i = 0; i < sizeof(hidp_keycode); i++)
844 set_bit(hidp_keycode[i], input->keybit);
845 clear_bit(0, input->keybit);
846 }
847
848 if (req->subclass & 0x80) {
Jiri Slaby7b19ada2007-10-18 23:40:32 -0700849 input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL);
850 input->keybit[BIT_WORD(BTN_MOUSE)] = BIT_MASK(BTN_LEFT) |
851 BIT_MASK(BTN_RIGHT) | BIT_MASK(BTN_MIDDLE);
852 input->relbit[0] = BIT_MASK(REL_X) | BIT_MASK(REL_Y);
853 input->keybit[BIT_WORD(BTN_MOUSE)] |= BIT_MASK(BTN_SIDE) |
854 BIT_MASK(BTN_EXTRA);
855 input->relbit[0] |= BIT_MASK(REL_WHEEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700856 }
857
Marcel Holtmann5be39462007-05-09 09:15:30 +0200858 input->dev.parent = hidp_get_device(session);
Marcel Holtmann0a85b962006-07-06 13:09:02 +0200859
Linus Torvalds1da177e2005-04-16 15:20:36 -0700860 input->event = hidp_input_event;
861
Marcel Holtmannedad6382009-08-22 14:22:15 -0700862 err = input_register_device(input);
863 if (err < 0) {
Peter Hurley615aedd2011-08-05 10:51:50 -0400864 input_free_device(input);
865 session->input = NULL;
Marcel Holtmannedad6382009-08-22 14:22:15 -0700866 return err;
867 }
868
869 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700870}
871
Marcel Holtmannf5ffd462007-02-17 23:58:53 +0100872static int hidp_open(struct hid_device *hid)
873{
874 return 0;
875}
876
877static void hidp_close(struct hid_device *hid)
878{
879}
880
Jiri Slabyc500c972008-05-16 11:49:16 +0200881static int hidp_parse(struct hid_device *hid)
882{
883 struct hidp_session *session = hid->driver_data;
Jiri Slabyc500c972008-05-16 11:49:16 +0200884
Michael Poole15c697c2010-02-05 12:23:43 -0500885 return hid_parse_report(session->hid, session->rd_data,
886 session->rd_size);
Jiri Slabyc500c972008-05-16 11:49:16 +0200887}
888
889static int hidp_start(struct hid_device *hid)
890{
891 struct hidp_session *session = hid->driver_data;
892 struct hid_report *report;
893
David Herrmann142c69c2011-08-26 13:27:12 +0200894 if (hid->quirks & HID_QUIRK_NO_INIT_REPORTS)
895 return 0;
896
Jiri Slabyc500c972008-05-16 11:49:16 +0200897 list_for_each_entry(report, &hid->report_enum[HID_INPUT_REPORT].
898 report_list, list)
899 hidp_send_report(session, report);
900
901 list_for_each_entry(report, &hid->report_enum[HID_FEATURE_REPORT].
902 report_list, list)
903 hidp_send_report(session, report);
904
Jiri Slabyc500c972008-05-16 11:49:16 +0200905 return 0;
906}
907
908static void hidp_stop(struct hid_device *hid)
909{
910 struct hidp_session *session = hid->driver_data;
911
912 skb_queue_purge(&session->ctrl_transmit);
913 skb_queue_purge(&session->intr_transmit);
914
Jiri Slabyc500c972008-05-16 11:49:16 +0200915 hid->claimed = 0;
916}
917
918static struct hid_ll_driver hidp_hid_driver = {
919 .parse = hidp_parse,
920 .start = hidp_start,
921 .stop = hidp_stop,
922 .open = hidp_open,
923 .close = hidp_close,
924 .hidinput_input_event = hidp_hidinput_event,
925};
926
Alan Ott0f69dca2011-01-18 03:04:37 -0500927/* This function sets up the hid device. It does not add it
928 to the HID system. That is done in hidp_add_connection(). */
Jiri Slaby85cdaf52008-05-16 11:49:15 +0200929static int hidp_setup_hid(struct hidp_session *session,
Andrew Morton91f5cca2008-02-05 03:07:58 -0800930 struct hidp_connadd_req *req)
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100931{
Jiri Slabyc500c972008-05-16 11:49:16 +0200932 struct hid_device *hid;
Marcel Holtmannedad6382009-08-22 14:22:15 -0700933 int err;
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100934
Michael Poole15c697c2010-02-05 12:23:43 -0500935 session->rd_data = kzalloc(req->rd_size, GFP_KERNEL);
936 if (!session->rd_data)
937 return -ENOMEM;
938
939 if (copy_from_user(session->rd_data, req->rd_data, req->rd_size)) {
940 err = -EFAULT;
941 goto fault;
942 }
943 session->rd_size = req->rd_size;
944
Jiri Slabyc500c972008-05-16 11:49:16 +0200945 hid = hid_allocate_device();
Michael Poole15c697c2010-02-05 12:23:43 -0500946 if (IS_ERR(hid)) {
947 err = PTR_ERR(hid);
948 goto fault;
949 }
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100950
Jiri Slabyc500c972008-05-16 11:49:16 +0200951 session->hid = hid;
Michael Poole15c697c2010-02-05 12:23:43 -0500952
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100953 hid->driver_data = session;
954
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100955 hid->bus = BUS_BLUETOOTH;
956 hid->vendor = req->vendor;
957 hid->product = req->product;
958 hid->version = req->version;
Jiri Slabyc500c972008-05-16 11:49:16 +0200959 hid->country = req->country;
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100960
961 strncpy(hid->name, req->name, 128);
Gustavo F. Padovand6b2eb22010-09-03 18:29:46 -0300962 strncpy(hid->phys, batostr(&bt_sk(session->ctrl_sock->sk)->src), 64);
963 strncpy(hid->uniq, batostr(&bt_sk(session->ctrl_sock->sk)->dst), 64);
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100964
Jiri Slaby85cdaf52008-05-16 11:49:15 +0200965 hid->dev.parent = hidp_get_device(session);
Jiri Slabyc500c972008-05-16 11:49:16 +0200966 hid->ll_driver = &hidp_hid_driver;
Jiri Slaby85cdaf52008-05-16 11:49:15 +0200967
Alan Ott0ff17312011-01-18 03:04:40 -0500968 hid->hid_get_raw_report = hidp_get_raw_report;
Jiri Kosina2da31932009-11-26 16:20:56 +0100969 hid->hid_output_raw_report = hidp_output_raw_report;
970
Jiri Slabyc500c972008-05-16 11:49:16 +0200971 return 0;
Marcel Holtmannedad6382009-08-22 14:22:15 -0700972
Michael Poole15c697c2010-02-05 12:23:43 -0500973fault:
974 kfree(session->rd_data);
975 session->rd_data = NULL;
976
Marcel Holtmannedad6382009-08-22 14:22:15 -0700977 return err;
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100978}
979
Linus Torvalds1da177e2005-04-16 15:20:36 -0700980int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock, struct socket *intr_sock)
981{
982 struct hidp_session *session, *s;
Szymon Jancaabf6f82011-04-05 15:37:45 +0200983 int vendor, product;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700984 int err;
985
986 BT_DBG("");
987
988 if (bacmp(&bt_sk(ctrl_sock->sk)->src, &bt_sk(intr_sock->sk)->src) ||
989 bacmp(&bt_sk(ctrl_sock->sk)->dst, &bt_sk(intr_sock->sk)->dst))
990 return -ENOTUNIQ;
991
Marcel Holtmann25ea6db2006-07-06 15:40:09 +0200992 session = kzalloc(sizeof(struct hidp_session), GFP_KERNEL);
Dmitry Torokhov34abf912005-09-15 02:01:40 -0500993 if (!session)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700994 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700995
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100996 BT_DBG("rd_data %p rd_size %d", req->rd_data, req->rd_size);
997
Linus Torvalds1da177e2005-04-16 15:20:36 -0700998 down_write(&hidp_session_sem);
999
1000 s = __hidp_get_session(&bt_sk(ctrl_sock->sk)->dst);
1001 if (s && s->state == BT_CONNECTED) {
1002 err = -EEXIST;
1003 goto failed;
1004 }
1005
1006 bacpy(&session->bdaddr, &bt_sk(ctrl_sock->sk)->dst);
1007
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03001008 session->ctrl_mtu = min_t(uint, l2cap_pi(ctrl_sock->sk)->chan->omtu,
1009 l2cap_pi(ctrl_sock->sk)->chan->imtu);
1010 session->intr_mtu = min_t(uint, l2cap_pi(intr_sock->sk)->chan->omtu,
1011 l2cap_pi(intr_sock->sk)->chan->imtu);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001012
1013 BT_DBG("ctrl mtu %d intr mtu %d", session->ctrl_mtu, session->intr_mtu);
1014
1015 session->ctrl_sock = ctrl_sock;
1016 session->intr_sock = intr_sock;
1017 session->state = BT_CONNECTED;
1018
Pavel Emelyanovb24b8a22008-01-23 21:20:07 -08001019 setup_timer(&session->timer, hidp_idle_timeout, (unsigned long)session);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001020
1021 skb_queue_head_init(&session->ctrl_transmit);
1022 skb_queue_head_init(&session->intr_transmit);
1023
Alan Ott0ff17312011-01-18 03:04:40 -05001024 mutex_init(&session->report_mutex);
1025 init_waitqueue_head(&session->report_queue);
Alan Ott0f69dca2011-01-18 03:04:37 -05001026 init_waitqueue_head(&session->startup_queue);
1027 session->waiting_for_startup = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001028 session->flags = req->flags & (1 << HIDP_BLUETOOTH_VENDOR_ID);
1029 session->idle_to = req->idle_to;
1030
Jiri Slabyc500c972008-05-16 11:49:16 +02001031 if (req->rd_size > 0) {
Jiri Slaby85cdaf52008-05-16 11:49:15 +02001032 err = hidp_setup_hid(session, req);
Jiri Slabyd458a9d2008-05-16 11:49:20 +02001033 if (err && err != -ENODEV)
Marcel Holtmannedad6382009-08-22 14:22:15 -07001034 goto purge;
Jiri Slabyc500c972008-05-16 11:49:16 +02001035 }
1036
1037 if (!session->hid) {
1038 err = hidp_setup_input(session, req);
1039 if (err < 0)
Marcel Holtmannedad6382009-08-22 14:22:15 -07001040 goto purge;
Jiri Slaby85cdaf52008-05-16 11:49:15 +02001041 }
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +01001042
Linus Torvalds1da177e2005-04-16 15:20:36 -07001043 __hidp_link_session(session);
1044
1045 hidp_set_timer(session);
1046
Szymon Jancaabf6f82011-04-05 15:37:45 +02001047 if (session->hid) {
1048 vendor = session->hid->vendor;
1049 product = session->hid->product;
1050 } else if (session->input) {
1051 vendor = session->input->id.vendor;
1052 product = session->input->id.product;
1053 } else {
1054 vendor = 0x0000;
1055 product = 0x0000;
1056 }
1057
1058 session->task = kthread_run(hidp_session, session, "khidpd_%04x%04x",
1059 vendor, product);
1060 if (IS_ERR(session->task)) {
1061 err = PTR_ERR(session->task);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001062 goto unlink;
Szymon Jancaabf6f82011-04-05 15:37:45 +02001063 }
1064
Alan Ott0f69dca2011-01-18 03:04:37 -05001065 while (session->waiting_for_startup) {
1066 wait_event_interruptible(session->startup_queue,
1067 !session->waiting_for_startup);
1068 }
1069
1070 err = hid_add_device(session->hid);
Peter Hurleye9d5cb52011-08-05 10:51:26 -04001071 if (err < 0) {
1072 atomic_inc(&session->terminate);
1073 wake_up_process(session->task);
1074 up_write(&hidp_session_sem);
1075 return err;
1076 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001077
1078 if (session->input) {
1079 hidp_send_ctrl_message(session,
1080 HIDP_TRANS_SET_PROTOCOL | HIDP_PROTO_BOOT, NULL, 0);
1081 session->flags |= (1 << HIDP_BOOT_PROTOCOL_MODE);
1082
1083 session->leds = 0xff;
1084 hidp_input_event(session->input, EV_LED, 0, 0);
1085 }
1086
1087 up_write(&hidp_session_sem);
1088 return 0;
1089
1090unlink:
1091 hidp_del_timer(session);
1092
1093 __hidp_unlink_session(session);
1094
Marcel Holtmannedad6382009-08-22 14:22:15 -07001095 if (session->input) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001096 input_unregister_device(session->input);
Marcel Holtmannedad6382009-08-22 14:22:15 -07001097 session->input = NULL;
1098 }
1099
1100 if (session->hid) {
Jiri Slaby85cdaf52008-05-16 11:49:15 +02001101 hid_destroy_device(session->hid);
Marcel Holtmannedad6382009-08-22 14:22:15 -07001102 session->hid = NULL;
1103 }
1104
Michael Poole15c697c2010-02-05 12:23:43 -05001105 kfree(session->rd_data);
1106 session->rd_data = NULL;
1107
Marcel Holtmannedad6382009-08-22 14:22:15 -07001108purge:
Jiri Slabyc500c972008-05-16 11:49:16 +02001109 skb_queue_purge(&session->ctrl_transmit);
1110 skb_queue_purge(&session->intr_transmit);
Marcel Holtmannedad6382009-08-22 14:22:15 -07001111
Jiri Slabyc500c972008-05-16 11:49:16 +02001112failed:
1113 up_write(&hidp_session_sem);
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +01001114
Linus Torvalds1da177e2005-04-16 15:20:36 -07001115 kfree(session);
1116 return err;
1117}
1118
1119int hidp_del_connection(struct hidp_conndel_req *req)
1120{
1121 struct hidp_session *session;
1122 int err = 0;
1123
1124 BT_DBG("");
1125
1126 down_read(&hidp_session_sem);
1127
1128 session = __hidp_get_session(&req->bdaddr);
1129 if (session) {
1130 if (req->flags & (1 << HIDP_VIRTUAL_CABLE_UNPLUG)) {
1131 hidp_send_ctrl_message(session,
1132 HIDP_TRANS_HID_CONTROL | HIDP_CTRL_VIRTUAL_CABLE_UNPLUG, NULL, 0);
1133 } else {
1134 /* Flush the transmit queues */
1135 skb_queue_purge(&session->ctrl_transmit);
1136 skb_queue_purge(&session->intr_transmit);
1137
Peter Hurley7bb59df2011-06-30 13:53:53 -04001138 atomic_inc(&session->terminate);
1139 wake_up_process(session->task);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001140 }
1141 } else
1142 err = -ENOENT;
1143
1144 up_read(&hidp_session_sem);
1145 return err;
1146}
1147
1148int hidp_get_connlist(struct hidp_connlist_req *req)
1149{
Gustavo F. Padovancd11cdd2011-10-06 17:35:31 -03001150 struct hidp_session *session;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001151 int err = 0, n = 0;
1152
1153 BT_DBG("");
1154
1155 down_read(&hidp_session_sem);
1156
Gustavo F. Padovancd11cdd2011-10-06 17:35:31 -03001157 list_for_each_entry(session, &hidp_session_list, list) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001158 struct hidp_conninfo ci;
1159
Linus Torvalds1da177e2005-04-16 15:20:36 -07001160 __hidp_copy_session(session, &ci);
1161
1162 if (copy_to_user(req->ci, &ci, sizeof(ci))) {
1163 err = -EFAULT;
1164 break;
1165 }
1166
1167 if (++n >= req->cnum)
1168 break;
1169
1170 req->ci++;
1171 }
1172 req->cnum = n;
1173
1174 up_read(&hidp_session_sem);
1175 return err;
1176}
1177
1178int hidp_get_conninfo(struct hidp_conninfo *ci)
1179{
1180 struct hidp_session *session;
1181 int err = 0;
1182
1183 down_read(&hidp_session_sem);
1184
1185 session = __hidp_get_session(&ci->bdaddr);
1186 if (session)
1187 __hidp_copy_session(session, ci);
1188 else
1189 err = -ENOENT;
1190
1191 up_read(&hidp_session_sem);
1192 return err;
1193}
1194
Jiri Slaby85cdaf52008-05-16 11:49:15 +02001195static const struct hid_device_id hidp_table[] = {
1196 { HID_BLUETOOTH_DEVICE(HID_ANY_ID, HID_ANY_ID) },
1197 { }
1198};
1199
1200static struct hid_driver hidp_driver = {
1201 .name = "generic-bluetooth",
1202 .id_table = hidp_table,
1203};
1204
Linus Torvalds1da177e2005-04-16 15:20:36 -07001205static int __init hidp_init(void)
1206{
Jiri Slaby85cdaf52008-05-16 11:49:15 +02001207 int ret;
1208
Linus Torvalds1da177e2005-04-16 15:20:36 -07001209 BT_INFO("HIDP (Human Interface Emulation) ver %s", VERSION);
1210
Jiri Slaby85cdaf52008-05-16 11:49:15 +02001211 ret = hid_register_driver(&hidp_driver);
1212 if (ret)
1213 goto err;
1214
1215 ret = hidp_init_sockets();
1216 if (ret)
1217 goto err_drv;
1218
1219 return 0;
1220err_drv:
1221 hid_unregister_driver(&hidp_driver);
1222err:
1223 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001224}
1225
1226static void __exit hidp_exit(void)
1227{
1228 hidp_cleanup_sockets();
Jiri Slaby85cdaf52008-05-16 11:49:15 +02001229 hid_unregister_driver(&hidp_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001230}
1231
1232module_init(hidp_init);
1233module_exit(hidp_exit);
1234
1235MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
1236MODULE_DESCRIPTION("Bluetooth HIDP ver " VERSION);
1237MODULE_VERSION(VERSION);
1238MODULE_LICENSE("GPL");
1239MODULE_ALIAS("bt-proto-6");