blob: 2efd6cc58b6695c8ae72231a879ef1d333ecf22e [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 }
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +020091
Linus Torvalds1da177e2005-04-16 15:20:36 -070092 return NULL;
93}
94
95static void __hidp_link_session(struct hidp_session *session)
96{
97 __module_get(THIS_MODULE);
98 list_add(&session->list, &hidp_session_list);
99}
100
101static void __hidp_unlink_session(struct hidp_session *session)
102{
Marcel Holtmannedad6382009-08-22 14:22:15 -0700103 hci_conn_put_device(session->conn);
104
Linus Torvalds1da177e2005-04-16 15:20:36 -0700105 list_del(&session->list);
106 module_put(THIS_MODULE);
107}
108
109static void __hidp_copy_session(struct hidp_session *session, struct hidp_conninfo *ci)
110{
Vasiliy Kulikovd31dbf62010-10-30 18:26:31 +0400111 memset(ci, 0, sizeof(*ci));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700112 bacpy(&ci->bdaddr, &session->bdaddr);
113
114 ci->flags = session->flags;
115 ci->state = session->state;
116
117 ci->vendor = 0x0000;
118 ci->product = 0x0000;
119 ci->version = 0x0000;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700120
121 if (session->input) {
122 ci->vendor = session->input->id.vendor;
123 ci->product = session->input->id.product;
124 ci->version = session->input->id.version;
125 if (session->input->name)
126 strncpy(ci->name, session->input->name, 128);
127 else
128 strncpy(ci->name, "HID Boot Device", 128);
129 }
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100130
131 if (session->hid) {
132 ci->vendor = session->hid->vendor;
133 ci->product = session->hid->product;
134 ci->version = session->hid->version;
135 strncpy(ci->name, session->hid->name, 128);
136 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700137}
138
Andrew Morton91f5cca2008-02-05 03:07:58 -0800139static int hidp_queue_event(struct hidp_session *session, struct input_dev *dev,
140 unsigned int type, unsigned int code, int value)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700141{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700142 unsigned char newleds;
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100143 struct sk_buff *skb;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700144
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100145 BT_DBG("session %p type %d code %d value %d", session, type, code, value);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700146
147 if (type != EV_LED)
148 return -1;
149
150 newleds = (!!test_bit(LED_KANA, dev->led) << 3) |
151 (!!test_bit(LED_COMPOSE, dev->led) << 3) |
152 (!!test_bit(LED_SCROLLL, dev->led) << 2) |
153 (!!test_bit(LED_CAPSL, dev->led) << 1) |
154 (!!test_bit(LED_NUML, dev->led));
155
156 if (session->leds == newleds)
157 return 0;
158
159 session->leds = newleds;
160
Andrei Emeltchenko5a08ecc2011-01-11 17:20:20 +0200161 skb = alloc_skb(3, GFP_ATOMIC);
162 if (!skb) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700163 BT_ERR("Can't allocate memory for new frame");
164 return -ENOMEM;
165 }
166
167 *skb_put(skb, 1) = HIDP_TRANS_DATA | HIDP_DATA_RTYPE_OUPUT;
168 *skb_put(skb, 1) = 0x01;
169 *skb_put(skb, 1) = newleds;
170
171 skb_queue_tail(&session->intr_transmit, skb);
172
173 hidp_schedule(session);
174
175 return 0;
176}
177
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100178static int hidp_hidinput_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
179{
Marcel Holtmann5be39462007-05-09 09:15:30 +0200180 struct hid_device *hid = input_get_drvdata(dev);
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100181 struct hidp_session *session = hid->driver_data;
182
183 return hidp_queue_event(session, dev, type, code, value);
184}
185
186static int hidp_input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
187{
Marcel Holtmann5be39462007-05-09 09:15:30 +0200188 struct hidp_session *session = input_get_drvdata(dev);
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100189
190 return hidp_queue_event(session, dev, type, code, value);
191}
192
Linus Torvalds1da177e2005-04-16 15:20:36 -0700193static void hidp_input_report(struct hidp_session *session, struct sk_buff *skb)
194{
195 struct input_dev *dev = session->input;
196 unsigned char *keys = session->keys;
197 unsigned char *udata = skb->data + 1;
198 signed char *sdata = skb->data + 1;
199 int i, size = skb->len - 1;
200
201 switch (skb->data[0]) {
202 case 0x01: /* Keyboard report */
203 for (i = 0; i < 8; i++)
204 input_report_key(dev, hidp_keycode[i + 224], (udata[0] >> i) & 1);
205
206 /* If all the key codes have been set to 0x01, it means
207 * too many keys were pressed at the same time. */
208 if (!memcmp(udata + 2, hidp_mkeyspat, 6))
209 break;
210
211 for (i = 2; i < 8; i++) {
212 if (keys[i] > 3 && memscan(udata + 2, keys[i], 6) == udata + 8) {
213 if (hidp_keycode[keys[i]])
214 input_report_key(dev, hidp_keycode[keys[i]], 0);
215 else
216 BT_ERR("Unknown key (scancode %#x) released.", keys[i]);
217 }
218
219 if (udata[i] > 3 && memscan(keys + 2, udata[i], 6) == keys + 8) {
220 if (hidp_keycode[udata[i]])
221 input_report_key(dev, hidp_keycode[udata[i]], 1);
222 else
223 BT_ERR("Unknown key (scancode %#x) pressed.", udata[i]);
224 }
225 }
226
227 memcpy(keys, udata, 8);
228 break;
229
230 case 0x02: /* Mouse report */
231 input_report_key(dev, BTN_LEFT, sdata[0] & 0x01);
232 input_report_key(dev, BTN_RIGHT, sdata[0] & 0x02);
233 input_report_key(dev, BTN_MIDDLE, sdata[0] & 0x04);
234 input_report_key(dev, BTN_SIDE, sdata[0] & 0x08);
235 input_report_key(dev, BTN_EXTRA, sdata[0] & 0x10);
236
237 input_report_rel(dev, REL_X, sdata[1]);
238 input_report_rel(dev, REL_Y, sdata[2]);
239
240 if (size > 3)
241 input_report_rel(dev, REL_WHEEL, sdata[3]);
242 break;
243 }
244
245 input_sync(dev);
246}
247
Bastien Nocera6bf82682010-01-20 12:00:42 +0000248static int __hidp_send_ctrl_message(struct hidp_session *session,
249 unsigned char hdr, unsigned char *data, int size)
250{
251 struct sk_buff *skb;
252
253 BT_DBG("session %p data %p size %d", session, data, size);
254
David Herrmann794d1752011-08-26 14:06:02 +0200255 if (atomic_read(&session->terminate))
256 return -EIO;
257
Andrei Emeltchenko5a08ecc2011-01-11 17:20:20 +0200258 skb = alloc_skb(size + 1, GFP_ATOMIC);
259 if (!skb) {
Bastien Nocera6bf82682010-01-20 12:00:42 +0000260 BT_ERR("Can't allocate memory for new frame");
261 return -ENOMEM;
262 }
263
264 *skb_put(skb, 1) = hdr;
265 if (data && size > 0)
266 memcpy(skb_put(skb, size), data, size);
267
268 skb_queue_tail(&session->ctrl_transmit, skb);
269
270 return 0;
271}
272
273static inline int hidp_send_ctrl_message(struct hidp_session *session,
274 unsigned char hdr, unsigned char *data, int size)
275{
276 int err;
277
278 err = __hidp_send_ctrl_message(session, hdr, data, size);
279
280 hidp_schedule(session);
281
282 return err;
283}
284
Andrew Morton91f5cca2008-02-05 03:07:58 -0800285static int hidp_queue_report(struct hidp_session *session,
286 unsigned char *data, int size)
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100287{
288 struct sk_buff *skb;
289
Dave Young6792b5e2007-10-20 14:15:39 +0200290 BT_DBG("session %p hid %p data %p size %d", session, session->hid, data, size);
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100291
Andrei Emeltchenko5a08ecc2011-01-11 17:20:20 +0200292 skb = alloc_skb(size + 1, GFP_ATOMIC);
293 if (!skb) {
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100294 BT_ERR("Can't allocate memory for new frame");
295 return -ENOMEM;
296 }
297
298 *skb_put(skb, 1) = 0xa2;
299 if (size > 0)
300 memcpy(skb_put(skb, size), data, size);
301
302 skb_queue_tail(&session->intr_transmit, skb);
303
304 hidp_schedule(session);
305
306 return 0;
307}
308
309static int hidp_send_report(struct hidp_session *session, struct hid_report *report)
310{
311 unsigned char buf[32];
312 int rsize;
313
314 rsize = ((report->size - 1) >> 3) + 1 + (report->id > 0);
315 if (rsize > sizeof(buf))
316 return -EIO;
317
318 hid_output_report(report, buf);
319
320 return hidp_queue_report(session, buf, rsize);
321}
322
Alan Ott0ff17312011-01-18 03:04:40 -0500323static int hidp_get_raw_report(struct hid_device *hid,
324 unsigned char report_number,
325 unsigned char *data, size_t count,
Jiri Kosinad4bfa032010-01-29 15:03:36 +0100326 unsigned char report_type)
Jiri Kosina2da31932009-11-26 16:20:56 +0100327{
Alan Ott0ff17312011-01-18 03:04:40 -0500328 struct hidp_session *session = hid->driver_data;
329 struct sk_buff *skb;
330 size_t len;
331 int numbered_reports = hid->report_enum[report_type].numbered;
David Herrmann794d1752011-08-26 14:06:02 +0200332 int ret;
Alan Ott0ff17312011-01-18 03:04:40 -0500333
Jiri Kosinad4bfa032010-01-29 15:03:36 +0100334 switch (report_type) {
335 case HID_FEATURE_REPORT:
Alan Ott0ff17312011-01-18 03:04:40 -0500336 report_type = HIDP_TRANS_GET_REPORT | HIDP_DATA_RTYPE_FEATURE;
337 break;
338 case HID_INPUT_REPORT:
339 report_type = HIDP_TRANS_GET_REPORT | HIDP_DATA_RTYPE_INPUT;
Jiri Kosinad4bfa032010-01-29 15:03:36 +0100340 break;
341 case HID_OUTPUT_REPORT:
Alan Ott0ff17312011-01-18 03:04:40 -0500342 report_type = HIDP_TRANS_GET_REPORT | HIDP_DATA_RTYPE_OUPUT;
Jiri Kosinad4bfa032010-01-29 15:03:36 +0100343 break;
344 default:
345 return -EINVAL;
346 }
347
Alan Ott0ff17312011-01-18 03:04:40 -0500348 if (mutex_lock_interruptible(&session->report_mutex))
349 return -ERESTARTSYS;
350
351 /* Set up our wait, and send the report request to the device. */
352 session->waiting_report_type = report_type & HIDP_DATA_RTYPE_MASK;
353 session->waiting_report_number = numbered_reports ? report_number : -1;
354 set_bit(HIDP_WAITING_FOR_RETURN, &session->flags);
355 data[0] = report_number;
David Herrmann794d1752011-08-26 14:06:02 +0200356 ret = hidp_send_ctrl_message(hid->driver_data, report_type, data, 1);
357 if (ret)
358 goto err;
Alan Ott0ff17312011-01-18 03:04:40 -0500359
360 /* Wait for the return of the report. The returned report
361 gets put in session->report_return. */
362 while (test_bit(HIDP_WAITING_FOR_RETURN, &session->flags)) {
363 int res;
364
365 res = wait_event_interruptible_timeout(session->report_queue,
366 !test_bit(HIDP_WAITING_FOR_RETURN, &session->flags),
367 5*HZ);
368 if (res == 0) {
369 /* timeout */
David Herrmann794d1752011-08-26 14:06:02 +0200370 ret = -EIO;
371 goto err;
Alan Ott0ff17312011-01-18 03:04:40 -0500372 }
373 if (res < 0) {
374 /* signal */
David Herrmann794d1752011-08-26 14:06:02 +0200375 ret = -ERESTARTSYS;
376 goto err;
Alan Ott0ff17312011-01-18 03:04:40 -0500377 }
378 }
379
380 skb = session->report_return;
381 if (skb) {
382 len = skb->len < count ? skb->len : count;
383 memcpy(data, skb->data, len);
384
385 kfree_skb(skb);
386 session->report_return = NULL;
387 } else {
388 /* Device returned a HANDSHAKE, indicating protocol error. */
389 len = -EIO;
390 }
391
392 clear_bit(HIDP_WAITING_FOR_RETURN, &session->flags);
393 mutex_unlock(&session->report_mutex);
394
395 return len;
396
David Herrmann794d1752011-08-26 14:06:02 +0200397err:
Alan Ott0ff17312011-01-18 03:04:40 -0500398 clear_bit(HIDP_WAITING_FOR_RETURN, &session->flags);
399 mutex_unlock(&session->report_mutex);
David Herrmann794d1752011-08-26 14:06:02 +0200400 return ret;
Alan Ott0ff17312011-01-18 03:04:40 -0500401}
402
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403static int hidp_output_raw_report(struct hid_device *hid, unsigned char *data, size_t count,
Jiri Kosina2da31932009-11-26 16:20:56 +0100404 unsigned char report_type)
405{
Alan Ott08254112011-01-18 03:04:38 -0500406 struct hidp_session *session = hid->driver_data;
407 int ret;
408
Jiri Kosinad4bfa032010-01-29 15:03:36 +0100409 switch (report_type) {
410 case HID_FEATURE_REPORT:
411 report_type = HIDP_TRANS_SET_REPORT | HIDP_DATA_RTYPE_FEATURE;
412 break;
413 case HID_OUTPUT_REPORT:
Antonio Ospite97e1efb2011-02-20 18:26:46 +0100414 report_type = HIDP_TRANS_SET_REPORT | HIDP_DATA_RTYPE_OUPUT;
Jiri Kosinad4bfa032010-01-29 15:03:36 +0100415 break;
416 default:
417 return -EINVAL;
418 }
419
Alan Ott08254112011-01-18 03:04:38 -0500420 if (mutex_lock_interruptible(&session->report_mutex))
421 return -ERESTARTSYS;
422
423 /* Set up our wait, and send the report request to the device. */
424 set_bit(HIDP_WAITING_FOR_SEND_ACK, &session->flags);
David Herrmann794d1752011-08-26 14:06:02 +0200425 ret = hidp_send_ctrl_message(hid->driver_data, report_type, data,
426 count);
427 if (ret)
Alan Ott08254112011-01-18 03:04:38 -0500428 goto err;
Alan Ott08254112011-01-18 03:04:38 -0500429
430 /* Wait for the ACK from the device. */
431 while (test_bit(HIDP_WAITING_FOR_SEND_ACK, &session->flags)) {
432 int res;
433
434 res = wait_event_interruptible_timeout(session->report_queue,
435 !test_bit(HIDP_WAITING_FOR_SEND_ACK, &session->flags),
436 10*HZ);
437 if (res == 0) {
438 /* timeout */
439 ret = -EIO;
440 goto err;
441 }
442 if (res < 0) {
443 /* signal */
444 ret = -ERESTARTSYS;
445 goto err;
446 }
447 }
448
449 if (!session->output_report_success) {
450 ret = -EIO;
451 goto err;
452 }
453
454 ret = count;
455
456err:
457 clear_bit(HIDP_WAITING_FOR_SEND_ACK, &session->flags);
458 mutex_unlock(&session->report_mutex);
459 return ret;
Jiri Kosina2da31932009-11-26 16:20:56 +0100460}
461
Linus Torvalds1da177e2005-04-16 15:20:36 -0700462static void hidp_idle_timeout(unsigned long arg)
463{
464 struct hidp_session *session = (struct hidp_session *) arg;
465
Peter Hurley7bb59df2011-06-30 13:53:53 -0400466 atomic_inc(&session->terminate);
467 wake_up_process(session->task);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700468}
469
Andrew Morton91f5cca2008-02-05 03:07:58 -0800470static void hidp_set_timer(struct hidp_session *session)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700471{
472 if (session->idle_to > 0)
473 mod_timer(&session->timer, jiffies + HZ * session->idle_to);
474}
475
476static inline void hidp_del_timer(struct hidp_session *session)
477{
478 if (session->idle_to > 0)
479 del_timer(&session->timer);
480}
481
Andrew Morton91f5cca2008-02-05 03:07:58 -0800482static void hidp_process_handshake(struct hidp_session *session,
483 unsigned char param)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700484{
485 BT_DBG("session %p param 0x%02x", session, param);
Alan Ott08254112011-01-18 03:04:38 -0500486 session->output_report_success = 0; /* default condition */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700487
488 switch (param) {
489 case HIDP_HSHK_SUCCESSFUL:
490 /* FIXME: Call into SET_ GET_ handlers here */
Alan Ott08254112011-01-18 03:04:38 -0500491 session->output_report_success = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700492 break;
493
494 case HIDP_HSHK_NOT_READY:
495 case HIDP_HSHK_ERR_INVALID_REPORT_ID:
496 case HIDP_HSHK_ERR_UNSUPPORTED_REQUEST:
497 case HIDP_HSHK_ERR_INVALID_PARAMETER:
Gustavo F. Padovanab88f712011-10-06 22:05:37 -0300498 if (test_and_clear_bit(HIDP_WAITING_FOR_RETURN, &session->flags))
Alan Ott0ff17312011-01-18 03:04:40 -0500499 wake_up_interruptible(&session->report_queue);
Gustavo F. Padovanab88f712011-10-06 22:05:37 -0300500
Linus Torvalds1da177e2005-04-16 15:20:36 -0700501 /* FIXME: Call into SET_ GET_ handlers here */
502 break;
503
504 case HIDP_HSHK_ERR_UNKNOWN:
505 break;
506
507 case HIDP_HSHK_ERR_FATAL:
508 /* Device requests a reboot, as this is the only way this error
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900509 * can be recovered. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700510 __hidp_send_ctrl_message(session,
511 HIDP_TRANS_HID_CONTROL | HIDP_CTRL_SOFT_RESET, NULL, 0);
512 break;
513
514 default:
515 __hidp_send_ctrl_message(session,
516 HIDP_TRANS_HANDSHAKE | HIDP_HSHK_ERR_INVALID_PARAMETER, NULL, 0);
517 break;
518 }
Alan Ott08254112011-01-18 03:04:38 -0500519
520 /* Wake up the waiting thread. */
Gustavo F. Padovanab88f712011-10-06 22:05:37 -0300521 if (test_and_clear_bit(HIDP_WAITING_FOR_SEND_ACK, &session->flags))
Alan Ott08254112011-01-18 03:04:38 -0500522 wake_up_interruptible(&session->report_queue);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700523}
524
Andrew Morton91f5cca2008-02-05 03:07:58 -0800525static void hidp_process_hid_control(struct hidp_session *session,
526 unsigned char param)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700527{
528 BT_DBG("session %p param 0x%02x", session, param);
529
Dave Youngeff001e2008-02-05 03:07:14 -0800530 if (param == HIDP_CTRL_VIRTUAL_CABLE_UNPLUG) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700531 /* Flush the transmit queues */
532 skb_queue_purge(&session->ctrl_transmit);
533 skb_queue_purge(&session->intr_transmit);
534
Peter Hurley7bb59df2011-06-30 13:53:53 -0400535 atomic_inc(&session->terminate);
536 wake_up_process(current);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700537 }
538}
539
Alan Ott0ff17312011-01-18 03:04:40 -0500540/* Returns true if the passed-in skb should be freed by the caller. */
541static int hidp_process_data(struct hidp_session *session, struct sk_buff *skb,
Andrew Morton91f5cca2008-02-05 03:07:58 -0800542 unsigned char param)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700543{
Alan Ott0ff17312011-01-18 03:04:40 -0500544 int done_with_skb = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700545 BT_DBG("session %p skb %p len %d param 0x%02x", session, skb, skb->len, param);
546
547 switch (param) {
548 case HIDP_DATA_RTYPE_INPUT:
549 hidp_set_timer(session);
550
551 if (session->input)
552 hidp_input_report(session, skb);
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100553
554 if (session->hid)
555 hid_input_report(session->hid, HID_INPUT_REPORT, skb->data, skb->len, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700556 break;
557
558 case HIDP_DATA_RTYPE_OTHER:
559 case HIDP_DATA_RTYPE_OUPUT:
560 case HIDP_DATA_RTYPE_FEATURE:
561 break;
562
563 default:
564 __hidp_send_ctrl_message(session,
565 HIDP_TRANS_HANDSHAKE | HIDP_HSHK_ERR_INVALID_PARAMETER, NULL, 0);
566 }
Alan Ott0ff17312011-01-18 03:04:40 -0500567
568 if (test_bit(HIDP_WAITING_FOR_RETURN, &session->flags) &&
569 param == session->waiting_report_type) {
570 if (session->waiting_report_number < 0 ||
571 session->waiting_report_number == skb->data[0]) {
572 /* hidp_get_raw_report() is waiting on this report. */
573 session->report_return = skb;
574 done_with_skb = 0;
575 clear_bit(HIDP_WAITING_FOR_RETURN, &session->flags);
576 wake_up_interruptible(&session->report_queue);
577 }
578 }
579
580 return done_with_skb;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700581}
582
Andrew Morton91f5cca2008-02-05 03:07:58 -0800583static void hidp_recv_ctrl_frame(struct hidp_session *session,
584 struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700585{
586 unsigned char hdr, type, param;
Alan Ott0ff17312011-01-18 03:04:40 -0500587 int free_skb = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700588
589 BT_DBG("session %p skb %p len %d", session, skb, skb->len);
590
591 hdr = skb->data[0];
592 skb_pull(skb, 1);
593
594 type = hdr & HIDP_HEADER_TRANS_MASK;
595 param = hdr & HIDP_HEADER_PARAM_MASK;
596
597 switch (type) {
598 case HIDP_TRANS_HANDSHAKE:
599 hidp_process_handshake(session, param);
600 break;
601
602 case HIDP_TRANS_HID_CONTROL:
603 hidp_process_hid_control(session, param);
604 break;
605
606 case HIDP_TRANS_DATA:
Alan Ott0ff17312011-01-18 03:04:40 -0500607 free_skb = hidp_process_data(session, skb, param);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700608 break;
609
610 default:
611 __hidp_send_ctrl_message(session,
612 HIDP_TRANS_HANDSHAKE | HIDP_HSHK_ERR_UNSUPPORTED_REQUEST, NULL, 0);
613 break;
614 }
615
Alan Ott0ff17312011-01-18 03:04:40 -0500616 if (free_skb)
617 kfree_skb(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700618}
619
Andrew Morton91f5cca2008-02-05 03:07:58 -0800620static void hidp_recv_intr_frame(struct hidp_session *session,
621 struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700622{
623 unsigned char hdr;
624
625 BT_DBG("session %p skb %p len %d", session, skb, skb->len);
626
627 hdr = skb->data[0];
628 skb_pull(skb, 1);
629
630 if (hdr == (HIDP_TRANS_DATA | HIDP_DATA_RTYPE_INPUT)) {
631 hidp_set_timer(session);
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100632
Linus Torvalds1da177e2005-04-16 15:20:36 -0700633 if (session->input)
634 hidp_input_report(session, skb);
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100635
636 if (session->hid) {
637 hid_input_report(session->hid, HID_INPUT_REPORT, skb->data, skb->len, 1);
638 BT_DBG("report len %d", skb->len);
639 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700640 } else {
641 BT_DBG("Unsupported protocol header 0x%02x", hdr);
642 }
643
644 kfree_skb(skb);
645}
646
647static int hidp_send_frame(struct socket *sock, unsigned char *data, int len)
648{
649 struct kvec iv = { data, len };
650 struct msghdr msg;
651
652 BT_DBG("sock %p data %p len %d", sock, data, len);
653
654 if (!len)
655 return 0;
656
657 memset(&msg, 0, sizeof(msg));
658
659 return kernel_sendmsg(sock, &msg, &iv, 1, len);
660}
661
Gustavo F. Padovan679344e2011-10-06 20:51:37 -0300662static void hidp_process_intr_transmit(struct hidp_session *session)
663{
664 struct sk_buff *skb;
665
666 BT_DBG("session %p", session);
667
668 while ((skb = skb_dequeue(&session->intr_transmit))) {
669 if (hidp_send_frame(session->intr_sock, skb->data, skb->len) < 0) {
670 skb_queue_head(&session->intr_transmit, skb);
671 break;
672 }
673
674 hidp_set_timer(session);
675 kfree_skb(skb);
676 }
677}
678
679static void hidp_process_ctrl_transmit(struct hidp_session *session)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700680{
681 struct sk_buff *skb;
682
683 BT_DBG("session %p", session);
684
685 while ((skb = skb_dequeue(&session->ctrl_transmit))) {
686 if (hidp_send_frame(session->ctrl_sock, skb->data, skb->len) < 0) {
687 skb_queue_head(&session->ctrl_transmit, skb);
688 break;
689 }
690
691 hidp_set_timer(session);
692 kfree_skb(skb);
693 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700694}
695
696static int hidp_session(void *arg)
697{
698 struct hidp_session *session = arg;
699 struct sock *ctrl_sk = session->ctrl_sock->sk;
700 struct sock *intr_sk = session->intr_sock->sk;
701 struct sk_buff *skb;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700702 wait_queue_t ctrl_wait, intr_wait;
703
704 BT_DBG("session %p", session);
705
Linus Torvalds1da177e2005-04-16 15:20:36 -0700706 set_user_nice(current, -15);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700707
708 init_waitqueue_entry(&ctrl_wait, current);
709 init_waitqueue_entry(&intr_wait, current);
Eric Dumazetaa395142010-04-20 13:03:51 +0000710 add_wait_queue(sk_sleep(ctrl_sk), &ctrl_wait);
711 add_wait_queue(sk_sleep(intr_sk), &intr_wait);
Alan Ott0f69dca2011-01-18 03:04:37 -0500712 session->waiting_for_startup = 0;
713 wake_up_interruptible(&session->startup_queue);
Peter Hurley7bb59df2011-06-30 13:53:53 -0400714 set_current_state(TASK_INTERRUPTIBLE);
715 while (!atomic_read(&session->terminate)) {
Szymon Janc17f09a72011-03-21 14:20:01 +0100716 if (ctrl_sk->sk_state != BT_CONNECTED ||
717 intr_sk->sk_state != BT_CONNECTED)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700718 break;
719
Linus Torvalds1da177e2005-04-16 15:20:36 -0700720 while ((skb = skb_dequeue(&intr_sk->sk_receive_queue))) {
721 skb_orphan(skb);
Mat Martineau44935722011-07-22 14:53:58 -0700722 if (!skb_linearize(skb))
723 hidp_recv_intr_frame(session, skb);
724 else
725 kfree_skb(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700726 }
727
Gustavo F. Padovan679344e2011-10-06 20:51:37 -0300728 hidp_process_intr_transmit(session);
729
Gustavo F. Padovandc0da5c2011-10-06 18:02:13 -0300730 while ((skb = skb_dequeue(&ctrl_sk->sk_receive_queue))) {
731 skb_orphan(skb);
732 if (!skb_linearize(skb))
733 hidp_recv_ctrl_frame(session, skb);
734 else
735 kfree_skb(skb);
736 }
737
Gustavo F. Padovan679344e2011-10-06 20:51:37 -0300738 hidp_process_ctrl_transmit(session);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700739
740 schedule();
Peter Hurley7bb59df2011-06-30 13:53:53 -0400741 set_current_state(TASK_INTERRUPTIBLE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700742 }
743 set_current_state(TASK_RUNNING);
Eric Dumazetaa395142010-04-20 13:03:51 +0000744 remove_wait_queue(sk_sleep(intr_sk), &intr_wait);
745 remove_wait_queue(sk_sleep(ctrl_sk), &ctrl_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700746
David Herrmann794d1752011-08-26 14:06:02 +0200747 clear_bit(HIDP_WAITING_FOR_SEND_ACK, &session->flags);
748 clear_bit(HIDP_WAITING_FOR_RETURN, &session->flags);
749 wake_up_interruptible(&session->report_queue);
750
Linus Torvalds1da177e2005-04-16 15:20:36 -0700751 down_write(&hidp_session_sem);
752
753 hidp_del_timer(session);
754
Linus Torvalds1da177e2005-04-16 15:20:36 -0700755 if (session->input) {
756 input_unregister_device(session->input);
Dmitry Torokhov34abf912005-09-15 02:01:40 -0500757 session->input = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700758 }
759
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100760 if (session->hid) {
Jiri Slaby85cdaf52008-05-16 11:49:15 +0200761 hid_destroy_device(session->hid);
Marcel Holtmannedad6382009-08-22 14:22:15 -0700762 session->hid = NULL;
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100763 }
764
Marcel Holtmannec8dab32008-07-14 20:13:53 +0200765 /* Wakeup user-space polling for socket errors */
766 session->intr_sock->sk->sk_err = EUNATCH;
767 session->ctrl_sock->sk->sk_err = EUNATCH;
768
769 hidp_schedule(session);
770
David Woodhouse1c398582007-07-07 14:58:39 -0400771 fput(session->intr_sock->file);
772
Eric Dumazetaa395142010-04-20 13:03:51 +0000773 wait_event_timeout(*(sk_sleep(ctrl_sk)),
David Woodhouse1c398582007-07-07 14:58:39 -0400774 (ctrl_sk->sk_state == BT_CLOSED), msecs_to_jiffies(500));
775
776 fput(session->ctrl_sock->file);
777
778 __hidp_unlink_session(session);
779
Linus Torvalds1da177e2005-04-16 15:20:36 -0700780 up_write(&hidp_session_sem);
781
Peter Hurley1c97e942011-08-05 10:51:34 -0400782 kfree(session->rd_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700783 kfree(session);
784 return 0;
785}
786
Gustavo F. Padovan3e90dc82011-10-07 01:29:51 -0300787static struct hci_conn *hidp_get_connection(struct hidp_session *session)
Marcel Holtmann0a85b962006-07-06 13:09:02 +0200788{
789 bdaddr_t *src = &bt_sk(session->ctrl_sock->sk)->src;
790 bdaddr_t *dst = &bt_sk(session->ctrl_sock->sk)->dst;
Peter Hurley1785dbf2011-08-30 11:53:35 -0400791 struct hci_conn *conn;
Marcel Holtmann0a85b962006-07-06 13:09:02 +0200792 struct hci_dev *hdev;
Marcel Holtmann0a85b962006-07-06 13:09:02 +0200793
794 hdev = hci_get_route(dst, src);
795 if (!hdev)
796 return NULL;
797
Peter Hurley1785dbf2011-08-30 11:53:35 -0400798 hci_dev_lock_bh(hdev);
799 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, dst);
800 if (conn)
801 hci_conn_hold_device(conn);
802 hci_dev_unlock_bh(hdev);
Marcel Holtmann0a85b962006-07-06 13:09:02 +0200803
804 hci_dev_put(hdev);
805
Peter Hurley1785dbf2011-08-30 11:53:35 -0400806 return conn;
Marcel Holtmann0a85b962006-07-06 13:09:02 +0200807}
808
Andrew Morton91f5cca2008-02-05 03:07:58 -0800809static int hidp_setup_input(struct hidp_session *session,
810 struct hidp_connadd_req *req)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700811{
Jiri Slabyc500c972008-05-16 11:49:16 +0200812 struct input_dev *input;
Gustavo F. Padovan3415a5f2011-10-06 21:17:32 -0300813 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700814
Jiri Slabyc500c972008-05-16 11:49:16 +0200815 input = input_allocate_device();
816 if (!input)
817 return -ENOMEM;
818
819 session->input = input;
820
Marcel Holtmann5be39462007-05-09 09:15:30 +0200821 input_set_drvdata(input, session);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700822
Dmitry Torokhov34abf912005-09-15 02:01:40 -0500823 input->name = "Bluetooth HID Boot Protocol Device";
824
Linus Torvalds1da177e2005-04-16 15:20:36 -0700825 input->id.bustype = BUS_BLUETOOTH;
826 input->id.vendor = req->vendor;
827 input->id.product = req->product;
828 input->id.version = req->version;
829
830 if (req->subclass & 0x40) {
831 set_bit(EV_KEY, input->evbit);
832 set_bit(EV_LED, input->evbit);
833 set_bit(EV_REP, input->evbit);
834
835 set_bit(LED_NUML, input->ledbit);
836 set_bit(LED_CAPSL, input->ledbit);
837 set_bit(LED_SCROLLL, input->ledbit);
838 set_bit(LED_COMPOSE, input->ledbit);
839 set_bit(LED_KANA, input->ledbit);
840
841 for (i = 0; i < sizeof(hidp_keycode); i++)
842 set_bit(hidp_keycode[i], input->keybit);
843 clear_bit(0, input->keybit);
844 }
845
846 if (req->subclass & 0x80) {
Jiri Slaby7b19ada2007-10-18 23:40:32 -0700847 input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL);
848 input->keybit[BIT_WORD(BTN_MOUSE)] = BIT_MASK(BTN_LEFT) |
849 BIT_MASK(BTN_RIGHT) | BIT_MASK(BTN_MIDDLE);
850 input->relbit[0] = BIT_MASK(REL_X) | BIT_MASK(REL_Y);
851 input->keybit[BIT_WORD(BTN_MOUSE)] |= BIT_MASK(BTN_SIDE) |
852 BIT_MASK(BTN_EXTRA);
853 input->relbit[0] |= BIT_MASK(REL_WHEEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700854 }
855
Peter Hurley1785dbf2011-08-30 11:53:35 -0400856 input->dev.parent = &session->conn->dev;
Marcel Holtmann0a85b962006-07-06 13:09:02 +0200857
Linus Torvalds1da177e2005-04-16 15:20:36 -0700858 input->event = hidp_input_event;
859
Marcel Holtmannedad6382009-08-22 14:22:15 -0700860 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
Peter Hurley1785dbf2011-08-30 11:53:35 -0400956 hid->dev.parent = &session->conn->dev;
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 Holtmanne1aaadd2007-02-17 23:58:49 +0100983 BT_DBG("rd_data %p rd_size %d", req->rd_data, req->rd_size);
984
Linus Torvalds1da177e2005-04-16 15:20:36 -0700985 down_write(&hidp_session_sem);
986
987 s = __hidp_get_session(&bt_sk(ctrl_sock->sk)->dst);
988 if (s && s->state == BT_CONNECTED) {
Gustavo F. Padovan81b25cd2011-10-06 23:32:29 -0300989 up_write(&hidp_session_sem);
990 return -EEXIST;
991 }
992
993 session = kzalloc(sizeof(struct hidp_session), GFP_KERNEL);
994 if (!session) {
995 up_write(&hidp_session_sem);
996 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700997 }
998
Gustavo F. Padovan3e90dc82011-10-07 01:29:51 -0300999 session->conn = hidp_get_connection(session);
Peter Hurley1785dbf2011-08-30 11:53:35 -04001000 if (!session->conn) {
1001 err = -ENOTCONN;
1002 goto failed;
1003 }
1004
Linus Torvalds1da177e2005-04-16 15:20:36 -07001005 bacpy(&session->bdaddr, &bt_sk(ctrl_sock->sk)->dst);
1006
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03001007 session->ctrl_mtu = min_t(uint, l2cap_pi(ctrl_sock->sk)->chan->omtu,
1008 l2cap_pi(ctrl_sock->sk)->chan->imtu);
1009 session->intr_mtu = min_t(uint, l2cap_pi(intr_sock->sk)->chan->omtu,
1010 l2cap_pi(intr_sock->sk)->chan->imtu);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001011
1012 BT_DBG("ctrl mtu %d intr mtu %d", session->ctrl_mtu, session->intr_mtu);
1013
1014 session->ctrl_sock = ctrl_sock;
1015 session->intr_sock = intr_sock;
1016 session->state = BT_CONNECTED;
1017
Pavel Emelyanovb24b8a22008-01-23 21:20:07 -08001018 setup_timer(&session->timer, hidp_idle_timeout, (unsigned long)session);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001019
1020 skb_queue_head_init(&session->ctrl_transmit);
1021 skb_queue_head_init(&session->intr_transmit);
1022
Alan Ott0ff17312011-01-18 03:04:40 -05001023 mutex_init(&session->report_mutex);
1024 init_waitqueue_head(&session->report_queue);
Alan Ott0f69dca2011-01-18 03:04:37 -05001025 init_waitqueue_head(&session->startup_queue);
1026 session->waiting_for_startup = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001027 session->flags = req->flags & (1 << HIDP_BLUETOOTH_VENDOR_ID);
1028 session->idle_to = req->idle_to;
1029
Peter Hurley1785dbf2011-08-30 11:53:35 -04001030 __hidp_link_session(session);
1031
Jiri Slabyc500c972008-05-16 11:49:16 +02001032 if (req->rd_size > 0) {
Jiri Slaby85cdaf52008-05-16 11:49:15 +02001033 err = hidp_setup_hid(session, req);
Gustavo F. Padovan192893c2011-10-06 21:27:56 -03001034 if (err)
Marcel Holtmannedad6382009-08-22 14:22:15 -07001035 goto purge;
Jiri Slabyc500c972008-05-16 11:49:16 +02001036 }
1037
1038 if (!session->hid) {
1039 err = hidp_setup_input(session, req);
1040 if (err < 0)
Marcel Holtmannedad6382009-08-22 14:22:15 -07001041 goto purge;
Jiri Slaby85cdaf52008-05-16 11:49:15 +02001042 }
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +01001043
Linus Torvalds1da177e2005-04-16 15:20:36 -07001044 hidp_set_timer(session);
1045
Szymon Jancaabf6f82011-04-05 15:37:45 +02001046 if (session->hid) {
1047 vendor = session->hid->vendor;
1048 product = session->hid->product;
1049 } else if (session->input) {
1050 vendor = session->input->id.vendor;
1051 product = session->input->id.product;
1052 } else {
1053 vendor = 0x0000;
1054 product = 0x0000;
1055 }
1056
1057 session->task = kthread_run(hidp_session, session, "khidpd_%04x%04x",
1058 vendor, product);
1059 if (IS_ERR(session->task)) {
1060 err = PTR_ERR(session->task);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001061 goto unlink;
Szymon Jancaabf6f82011-04-05 15:37:45 +02001062 }
1063
Alan Ott0f69dca2011-01-18 03:04:37 -05001064 while (session->waiting_for_startup) {
1065 wait_event_interruptible(session->startup_queue,
1066 !session->waiting_for_startup);
1067 }
1068
Gustavo F. Padovan3415a5f2011-10-06 21:17:32 -03001069 if (session->hid)
1070 err = hid_add_device(session->hid);
1071 else
1072 err = input_register_device(session->input);
1073
Peter Hurleye9d5cb52011-08-05 10:51:26 -04001074 if (err < 0) {
1075 atomic_inc(&session->terminate);
1076 wake_up_process(session->task);
1077 up_write(&hidp_session_sem);
1078 return err;
1079 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001080
1081 if (session->input) {
1082 hidp_send_ctrl_message(session,
1083 HIDP_TRANS_SET_PROTOCOL | HIDP_PROTO_BOOT, NULL, 0);
1084 session->flags |= (1 << HIDP_BOOT_PROTOCOL_MODE);
1085
1086 session->leds = 0xff;
1087 hidp_input_event(session->input, EV_LED, 0, 0);
1088 }
1089
1090 up_write(&hidp_session_sem);
1091 return 0;
1092
1093unlink:
1094 hidp_del_timer(session);
1095
Marcel Holtmannedad6382009-08-22 14:22:15 -07001096 if (session->input) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001097 input_unregister_device(session->input);
Marcel Holtmannedad6382009-08-22 14:22:15 -07001098 session->input = NULL;
1099 }
1100
1101 if (session->hid) {
Jiri Slaby85cdaf52008-05-16 11:49:15 +02001102 hid_destroy_device(session->hid);
Marcel Holtmannedad6382009-08-22 14:22:15 -07001103 session->hid = NULL;
1104 }
1105
Michael Poole15c697c2010-02-05 12:23:43 -05001106 kfree(session->rd_data);
1107 session->rd_data = NULL;
1108
Marcel Holtmannedad6382009-08-22 14:22:15 -07001109purge:
Peter Hurley1785dbf2011-08-30 11:53:35 -04001110 __hidp_unlink_session(session);
1111
Jiri Slabyc500c972008-05-16 11:49:16 +02001112 skb_queue_purge(&session->ctrl_transmit);
1113 skb_queue_purge(&session->intr_transmit);
Marcel Holtmannedad6382009-08-22 14:22:15 -07001114
Jiri Slabyc500c972008-05-16 11:49:16 +02001115failed:
1116 up_write(&hidp_session_sem);
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +01001117
Linus Torvalds1da177e2005-04-16 15:20:36 -07001118 kfree(session);
1119 return err;
1120}
1121
1122int hidp_del_connection(struct hidp_conndel_req *req)
1123{
1124 struct hidp_session *session;
1125 int err = 0;
1126
1127 BT_DBG("");
1128
1129 down_read(&hidp_session_sem);
1130
1131 session = __hidp_get_session(&req->bdaddr);
1132 if (session) {
1133 if (req->flags & (1 << HIDP_VIRTUAL_CABLE_UNPLUG)) {
1134 hidp_send_ctrl_message(session,
1135 HIDP_TRANS_HID_CONTROL | HIDP_CTRL_VIRTUAL_CABLE_UNPLUG, NULL, 0);
1136 } else {
1137 /* Flush the transmit queues */
1138 skb_queue_purge(&session->ctrl_transmit);
1139 skb_queue_purge(&session->intr_transmit);
1140
Peter Hurley7bb59df2011-06-30 13:53:53 -04001141 atomic_inc(&session->terminate);
1142 wake_up_process(session->task);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001143 }
1144 } else
1145 err = -ENOENT;
1146
1147 up_read(&hidp_session_sem);
1148 return err;
1149}
1150
1151int hidp_get_connlist(struct hidp_connlist_req *req)
1152{
Gustavo F. Padovancd11cdd2011-10-06 17:35:31 -03001153 struct hidp_session *session;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001154 int err = 0, n = 0;
1155
1156 BT_DBG("");
1157
1158 down_read(&hidp_session_sem);
1159
Gustavo F. Padovancd11cdd2011-10-06 17:35:31 -03001160 list_for_each_entry(session, &hidp_session_list, list) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001161 struct hidp_conninfo ci;
1162
Linus Torvalds1da177e2005-04-16 15:20:36 -07001163 __hidp_copy_session(session, &ci);
1164
1165 if (copy_to_user(req->ci, &ci, sizeof(ci))) {
1166 err = -EFAULT;
1167 break;
1168 }
1169
1170 if (++n >= req->cnum)
1171 break;
1172
1173 req->ci++;
1174 }
1175 req->cnum = n;
1176
1177 up_read(&hidp_session_sem);
1178 return err;
1179}
1180
1181int hidp_get_conninfo(struct hidp_conninfo *ci)
1182{
1183 struct hidp_session *session;
1184 int err = 0;
1185
1186 down_read(&hidp_session_sem);
1187
1188 session = __hidp_get_session(&ci->bdaddr);
1189 if (session)
1190 __hidp_copy_session(session, ci);
1191 else
1192 err = -ENOENT;
1193
1194 up_read(&hidp_session_sem);
1195 return err;
1196}
1197
Jiri Slaby85cdaf52008-05-16 11:49:15 +02001198static const struct hid_device_id hidp_table[] = {
1199 { HID_BLUETOOTH_DEVICE(HID_ANY_ID, HID_ANY_ID) },
1200 { }
1201};
1202
1203static struct hid_driver hidp_driver = {
1204 .name = "generic-bluetooth",
1205 .id_table = hidp_table,
1206};
1207
Linus Torvalds1da177e2005-04-16 15:20:36 -07001208static int __init hidp_init(void)
1209{
Jiri Slaby85cdaf52008-05-16 11:49:15 +02001210 int ret;
1211
Linus Torvalds1da177e2005-04-16 15:20:36 -07001212 BT_INFO("HIDP (Human Interface Emulation) ver %s", VERSION);
1213
Jiri Slaby85cdaf52008-05-16 11:49:15 +02001214 ret = hid_register_driver(&hidp_driver);
1215 if (ret)
1216 goto err;
1217
1218 ret = hidp_init_sockets();
1219 if (ret)
1220 goto err_drv;
1221
1222 return 0;
1223err_drv:
1224 hid_unregister_driver(&hidp_driver);
1225err:
1226 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001227}
1228
1229static void __exit hidp_exit(void)
1230{
1231 hidp_cleanup_sockets();
Jiri Slaby85cdaf52008-05-16 11:49:15 +02001232 hid_unregister_driver(&hidp_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001233}
1234
1235module_init(hidp_init);
1236module_exit(hidp_exit);
1237
1238MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
1239MODULE_DESCRIPTION("Bluetooth HIDP ver " VERSION);
1240MODULE_VERSION(VERSION);
1241MODULE_LICENSE("GPL");
1242MODULE_ALIAS("bt-proto-6");