blob: e01a9246c14dd94b61c4f691ba8d6f0ac7f20c57 [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>
Linus Torvalds1da177e2005-04-16 15:20:36 -070024#include <linux/file.h>
Szymon Jancaabf6f82011-04-05 15:37:45 +020025#include <linux/kthread.h>
Marcel Holtmann364f6352009-08-22 14:15:53 -070026#include <linux/hidraw.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070027
28#include <net/bluetooth/bluetooth.h>
Marcel Holtmann0a85b962006-07-06 13:09:02 +020029#include <net/bluetooth/hci_core.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070030#include <net/bluetooth/l2cap.h>
31
32#include "hidp.h"
33
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +010034#define VERSION "1.2"
Linus Torvalds1da177e2005-04-16 15:20:36 -070035
36static DECLARE_RWSEM(hidp_session_sem);
37static LIST_HEAD(hidp_session_list);
38
39static unsigned char hidp_keycode[256] = {
Szymon Janc17f09a72011-03-21 14:20:01 +010040 0, 0, 0, 0, 30, 48, 46, 32, 18, 33, 34, 35, 23, 36,
41 37, 38, 50, 49, 24, 25, 16, 19, 31, 20, 22, 47, 17, 45,
42 21, 44, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 28, 1,
43 14, 15, 57, 12, 13, 26, 27, 43, 43, 39, 40, 41, 51, 52,
44 53, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 87, 88,
45 99, 70, 119, 110, 102, 104, 111, 107, 109, 106, 105, 108, 103, 69,
46 98, 55, 74, 78, 96, 79, 80, 81, 75, 76, 77, 71, 72, 73,
47 82, 83, 86, 127, 116, 117, 183, 184, 185, 186, 187, 188, 189, 190,
48 191, 192, 193, 194, 134, 138, 130, 132, 128, 129, 131, 137, 133, 135,
49 136, 113, 115, 114, 0, 0, 0, 121, 0, 89, 93, 124, 92, 94,
50 95, 0, 0, 0, 122, 123, 90, 91, 85, 0, 0, 0, 0, 0,
51 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
52 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
53 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
54 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
55 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
56 29, 42, 56, 125, 97, 54, 100, 126, 164, 166, 165, 163, 161, 115,
57 114, 113, 150, 158, 159, 128, 136, 177, 178, 176, 142, 152, 173, 140
Linus Torvalds1da177e2005-04-16 15:20:36 -070058};
59
60static unsigned char hidp_mkeyspat[] = { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 };
61
62static struct hidp_session *__hidp_get_session(bdaddr_t *bdaddr)
63{
64 struct hidp_session *session;
Linus Torvalds1da177e2005-04-16 15:20:36 -070065
66 BT_DBG("");
67
Gustavo F. Padovancd11cdd2011-10-06 17:35:31 -030068 list_for_each_entry(session, &hidp_session_list, list) {
Linus Torvalds1da177e2005-04-16 15:20:36 -070069 if (!bacmp(bdaddr, &session->bdaddr))
70 return session;
71 }
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +020072
Linus Torvalds1da177e2005-04-16 15:20:36 -070073 return NULL;
74}
75
Linus Torvalds1da177e2005-04-16 15:20:36 -070076static void __hidp_copy_session(struct hidp_session *session, struct hidp_conninfo *ci)
77{
Vasiliy Kulikovd31dbf62010-10-30 18:26:31 +040078 memset(ci, 0, sizeof(*ci));
Linus Torvalds1da177e2005-04-16 15:20:36 -070079 bacpy(&ci->bdaddr, &session->bdaddr);
80
81 ci->flags = session->flags;
David Herrmanndcc07642013-04-06 20:28:40 +020082 ci->state = BT_CONNECTED;
Linus Torvalds1da177e2005-04-16 15:20:36 -070083
84 ci->vendor = 0x0000;
85 ci->product = 0x0000;
86 ci->version = 0x0000;
Linus Torvalds1da177e2005-04-16 15:20:36 -070087
88 if (session->input) {
89 ci->vendor = session->input->id.vendor;
90 ci->product = session->input->id.product;
91 ci->version = session->input->id.version;
92 if (session->input->name)
93 strncpy(ci->name, session->input->name, 128);
94 else
95 strncpy(ci->name, "HID Boot Device", 128);
96 }
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +010097
98 if (session->hid) {
99 ci->vendor = session->hid->vendor;
100 ci->product = session->hid->product;
101 ci->version = session->hid->version;
102 strncpy(ci->name, session->hid->name, 128);
103 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700104}
105
Andrew Morton91f5cca2008-02-05 03:07:58 -0800106static int hidp_queue_event(struct hidp_session *session, struct input_dev *dev,
107 unsigned int type, unsigned int code, int value)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700108{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700109 unsigned char newleds;
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100110 struct sk_buff *skb;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700111
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100112 BT_DBG("session %p type %d code %d value %d", session, type, code, value);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700113
114 if (type != EV_LED)
115 return -1;
116
117 newleds = (!!test_bit(LED_KANA, dev->led) << 3) |
118 (!!test_bit(LED_COMPOSE, dev->led) << 3) |
119 (!!test_bit(LED_SCROLLL, dev->led) << 2) |
120 (!!test_bit(LED_CAPSL, dev->led) << 1) |
121 (!!test_bit(LED_NUML, dev->led));
122
123 if (session->leds == newleds)
124 return 0;
125
126 session->leds = newleds;
127
Andrei Emeltchenko5a08ecc2011-01-11 17:20:20 +0200128 skb = alloc_skb(3, GFP_ATOMIC);
129 if (!skb) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700130 BT_ERR("Can't allocate memory for new frame");
131 return -ENOMEM;
132 }
133
134 *skb_put(skb, 1) = HIDP_TRANS_DATA | HIDP_DATA_RTYPE_OUPUT;
135 *skb_put(skb, 1) = 0x01;
136 *skb_put(skb, 1) = newleds;
137
138 skb_queue_tail(&session->intr_transmit, skb);
139
140 hidp_schedule(session);
141
142 return 0;
143}
144
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100145static int hidp_hidinput_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
146{
Marcel Holtmann5be39462007-05-09 09:15:30 +0200147 struct hid_device *hid = input_get_drvdata(dev);
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100148 struct hidp_session *session = hid->driver_data;
149
150 return hidp_queue_event(session, dev, type, code, value);
151}
152
153static int hidp_input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
154{
Marcel Holtmann5be39462007-05-09 09:15:30 +0200155 struct hidp_session *session = input_get_drvdata(dev);
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100156
157 return hidp_queue_event(session, dev, type, code, value);
158}
159
Linus Torvalds1da177e2005-04-16 15:20:36 -0700160static void hidp_input_report(struct hidp_session *session, struct sk_buff *skb)
161{
162 struct input_dev *dev = session->input;
163 unsigned char *keys = session->keys;
164 unsigned char *udata = skb->data + 1;
165 signed char *sdata = skb->data + 1;
166 int i, size = skb->len - 1;
167
168 switch (skb->data[0]) {
169 case 0x01: /* Keyboard report */
170 for (i = 0; i < 8; i++)
171 input_report_key(dev, hidp_keycode[i + 224], (udata[0] >> i) & 1);
172
173 /* If all the key codes have been set to 0x01, it means
174 * too many keys were pressed at the same time. */
175 if (!memcmp(udata + 2, hidp_mkeyspat, 6))
176 break;
177
178 for (i = 2; i < 8; i++) {
179 if (keys[i] > 3 && memscan(udata + 2, keys[i], 6) == udata + 8) {
180 if (hidp_keycode[keys[i]])
181 input_report_key(dev, hidp_keycode[keys[i]], 0);
182 else
183 BT_ERR("Unknown key (scancode %#x) released.", keys[i]);
184 }
185
186 if (udata[i] > 3 && memscan(keys + 2, udata[i], 6) == keys + 8) {
187 if (hidp_keycode[udata[i]])
188 input_report_key(dev, hidp_keycode[udata[i]], 1);
189 else
190 BT_ERR("Unknown key (scancode %#x) pressed.", udata[i]);
191 }
192 }
193
194 memcpy(keys, udata, 8);
195 break;
196
197 case 0x02: /* Mouse report */
198 input_report_key(dev, BTN_LEFT, sdata[0] & 0x01);
199 input_report_key(dev, BTN_RIGHT, sdata[0] & 0x02);
200 input_report_key(dev, BTN_MIDDLE, sdata[0] & 0x04);
201 input_report_key(dev, BTN_SIDE, sdata[0] & 0x08);
202 input_report_key(dev, BTN_EXTRA, sdata[0] & 0x10);
203
204 input_report_rel(dev, REL_X, sdata[1]);
205 input_report_rel(dev, REL_Y, sdata[2]);
206
207 if (size > 3)
208 input_report_rel(dev, REL_WHEEL, sdata[3]);
209 break;
210 }
211
212 input_sync(dev);
213}
214
Bastien Nocera6bf82682010-01-20 12:00:42 +0000215static int __hidp_send_ctrl_message(struct hidp_session *session,
Gustavo Padovan1d0c4da2012-06-09 19:22:42 -0300216 unsigned char hdr, unsigned char *data,
217 int size)
Bastien Nocera6bf82682010-01-20 12:00:42 +0000218{
219 struct sk_buff *skb;
220
221 BT_DBG("session %p data %p size %d", session, data, size);
222
David Herrmann794d1752011-08-26 14:06:02 +0200223 if (atomic_read(&session->terminate))
224 return -EIO;
225
Andrei Emeltchenko5a08ecc2011-01-11 17:20:20 +0200226 skb = alloc_skb(size + 1, GFP_ATOMIC);
227 if (!skb) {
Bastien Nocera6bf82682010-01-20 12:00:42 +0000228 BT_ERR("Can't allocate memory for new frame");
229 return -ENOMEM;
230 }
231
232 *skb_put(skb, 1) = hdr;
233 if (data && size > 0)
234 memcpy(skb_put(skb, size), data, size);
235
236 skb_queue_tail(&session->ctrl_transmit, skb);
237
238 return 0;
239}
240
Gustavo Padovan6039aa72012-05-23 04:04:18 -0300241static int hidp_send_ctrl_message(struct hidp_session *session,
Bastien Nocera6bf82682010-01-20 12:00:42 +0000242 unsigned char hdr, unsigned char *data, int size)
243{
244 int err;
245
246 err = __hidp_send_ctrl_message(session, hdr, data, size);
247
248 hidp_schedule(session);
249
250 return err;
251}
252
Andrew Morton91f5cca2008-02-05 03:07:58 -0800253static int hidp_queue_report(struct hidp_session *session,
254 unsigned char *data, int size)
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100255{
256 struct sk_buff *skb;
257
Dave Young6792b5e2007-10-20 14:15:39 +0200258 BT_DBG("session %p hid %p data %p size %d", session, session->hid, data, size);
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100259
Andrei Emeltchenko5a08ecc2011-01-11 17:20:20 +0200260 skb = alloc_skb(size + 1, GFP_ATOMIC);
261 if (!skb) {
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100262 BT_ERR("Can't allocate memory for new frame");
263 return -ENOMEM;
264 }
265
266 *skb_put(skb, 1) = 0xa2;
267 if (size > 0)
268 memcpy(skb_put(skb, size), data, size);
269
270 skb_queue_tail(&session->intr_transmit, skb);
271
272 hidp_schedule(session);
273
274 return 0;
275}
276
277static int hidp_send_report(struct hidp_session *session, struct hid_report *report)
278{
279 unsigned char buf[32];
280 int rsize;
281
282 rsize = ((report->size - 1) >> 3) + 1 + (report->id > 0);
283 if (rsize > sizeof(buf))
284 return -EIO;
285
286 hid_output_report(report, buf);
287
288 return hidp_queue_report(session, buf, rsize);
289}
290
Alan Ott0ff17312011-01-18 03:04:40 -0500291static int hidp_get_raw_report(struct hid_device *hid,
292 unsigned char report_number,
293 unsigned char *data, size_t count,
Jiri Kosinad4bfa032010-01-29 15:03:36 +0100294 unsigned char report_type)
Jiri Kosina2da31932009-11-26 16:20:56 +0100295{
Alan Ott0ff17312011-01-18 03:04:40 -0500296 struct hidp_session *session = hid->driver_data;
297 struct sk_buff *skb;
298 size_t len;
299 int numbered_reports = hid->report_enum[report_type].numbered;
David Herrmann794d1752011-08-26 14:06:02 +0200300 int ret;
Alan Ott0ff17312011-01-18 03:04:40 -0500301
Karl Reltonfd86c9b2013-02-20 18:16:19 +0000302 if (atomic_read(&session->terminate))
303 return -EIO;
304
Jiri Kosinad4bfa032010-01-29 15:03:36 +0100305 switch (report_type) {
306 case HID_FEATURE_REPORT:
Alan Ott0ff17312011-01-18 03:04:40 -0500307 report_type = HIDP_TRANS_GET_REPORT | HIDP_DATA_RTYPE_FEATURE;
308 break;
309 case HID_INPUT_REPORT:
310 report_type = HIDP_TRANS_GET_REPORT | HIDP_DATA_RTYPE_INPUT;
Jiri Kosinad4bfa032010-01-29 15:03:36 +0100311 break;
312 case HID_OUTPUT_REPORT:
Alan Ott0ff17312011-01-18 03:04:40 -0500313 report_type = HIDP_TRANS_GET_REPORT | HIDP_DATA_RTYPE_OUPUT;
Jiri Kosinad4bfa032010-01-29 15:03:36 +0100314 break;
315 default:
316 return -EINVAL;
317 }
318
Alan Ott0ff17312011-01-18 03:04:40 -0500319 if (mutex_lock_interruptible(&session->report_mutex))
320 return -ERESTARTSYS;
321
322 /* Set up our wait, and send the report request to the device. */
323 session->waiting_report_type = report_type & HIDP_DATA_RTYPE_MASK;
324 session->waiting_report_number = numbered_reports ? report_number : -1;
325 set_bit(HIDP_WAITING_FOR_RETURN, &session->flags);
326 data[0] = report_number;
David Herrmann794d1752011-08-26 14:06:02 +0200327 ret = hidp_send_ctrl_message(hid->driver_data, report_type, data, 1);
328 if (ret)
329 goto err;
Alan Ott0ff17312011-01-18 03:04:40 -0500330
331 /* Wait for the return of the report. The returned report
332 gets put in session->report_return. */
David Herrmanne3492dc2013-04-06 20:28:41 +0200333 while (test_bit(HIDP_WAITING_FOR_RETURN, &session->flags) &&
334 !atomic_read(&session->terminate)) {
Alan Ott0ff17312011-01-18 03:04:40 -0500335 int res;
336
337 res = wait_event_interruptible_timeout(session->report_queue,
David Herrmanne3492dc2013-04-06 20:28:41 +0200338 !test_bit(HIDP_WAITING_FOR_RETURN, &session->flags)
339 || atomic_read(&session->terminate),
Alan Ott0ff17312011-01-18 03:04:40 -0500340 5*HZ);
341 if (res == 0) {
342 /* timeout */
David Herrmann794d1752011-08-26 14:06:02 +0200343 ret = -EIO;
344 goto err;
Alan Ott0ff17312011-01-18 03:04:40 -0500345 }
346 if (res < 0) {
347 /* signal */
David Herrmann794d1752011-08-26 14:06:02 +0200348 ret = -ERESTARTSYS;
349 goto err;
Alan Ott0ff17312011-01-18 03:04:40 -0500350 }
351 }
352
353 skb = session->report_return;
354 if (skb) {
355 len = skb->len < count ? skb->len : count;
356 memcpy(data, skb->data, len);
357
358 kfree_skb(skb);
359 session->report_return = NULL;
360 } else {
361 /* Device returned a HANDSHAKE, indicating protocol error. */
362 len = -EIO;
363 }
364
365 clear_bit(HIDP_WAITING_FOR_RETURN, &session->flags);
366 mutex_unlock(&session->report_mutex);
367
368 return len;
369
David Herrmann794d1752011-08-26 14:06:02 +0200370err:
Alan Ott0ff17312011-01-18 03:04:40 -0500371 clear_bit(HIDP_WAITING_FOR_RETURN, &session->flags);
372 mutex_unlock(&session->report_mutex);
David Herrmann794d1752011-08-26 14:06:02 +0200373 return ret;
Alan Ott0ff17312011-01-18 03:04:40 -0500374}
375
Linus Torvalds1da177e2005-04-16 15:20:36 -0700376static int hidp_output_raw_report(struct hid_device *hid, unsigned char *data, size_t count,
Jiri Kosina2da31932009-11-26 16:20:56 +0100377 unsigned char report_type)
378{
Alan Ott08254112011-01-18 03:04:38 -0500379 struct hidp_session *session = hid->driver_data;
380 int ret;
381
Jiri Kosinad4bfa032010-01-29 15:03:36 +0100382 switch (report_type) {
383 case HID_FEATURE_REPORT:
384 report_type = HIDP_TRANS_SET_REPORT | HIDP_DATA_RTYPE_FEATURE;
385 break;
386 case HID_OUTPUT_REPORT:
Antonio Ospite97e1efb2011-02-20 18:26:46 +0100387 report_type = HIDP_TRANS_SET_REPORT | HIDP_DATA_RTYPE_OUPUT;
Jiri Kosinad4bfa032010-01-29 15:03:36 +0100388 break;
389 default:
390 return -EINVAL;
391 }
392
Alan Ott08254112011-01-18 03:04:38 -0500393 if (mutex_lock_interruptible(&session->report_mutex))
394 return -ERESTARTSYS;
395
396 /* Set up our wait, and send the report request to the device. */
397 set_bit(HIDP_WAITING_FOR_SEND_ACK, &session->flags);
David Herrmann794d1752011-08-26 14:06:02 +0200398 ret = hidp_send_ctrl_message(hid->driver_data, report_type, data,
399 count);
400 if (ret)
Alan Ott08254112011-01-18 03:04:38 -0500401 goto err;
Alan Ott08254112011-01-18 03:04:38 -0500402
403 /* Wait for the ACK from the device. */
David Herrmanne3492dc2013-04-06 20:28:41 +0200404 while (test_bit(HIDP_WAITING_FOR_SEND_ACK, &session->flags) &&
405 !atomic_read(&session->terminate)) {
Alan Ott08254112011-01-18 03:04:38 -0500406 int res;
407
408 res = wait_event_interruptible_timeout(session->report_queue,
David Herrmanne3492dc2013-04-06 20:28:41 +0200409 !test_bit(HIDP_WAITING_FOR_SEND_ACK, &session->flags)
410 || atomic_read(&session->terminate),
Alan Ott08254112011-01-18 03:04:38 -0500411 10*HZ);
412 if (res == 0) {
413 /* timeout */
414 ret = -EIO;
415 goto err;
416 }
417 if (res < 0) {
418 /* signal */
419 ret = -ERESTARTSYS;
420 goto err;
421 }
422 }
423
424 if (!session->output_report_success) {
425 ret = -EIO;
426 goto err;
427 }
428
429 ret = count;
430
431err:
432 clear_bit(HIDP_WAITING_FOR_SEND_ACK, &session->flags);
433 mutex_unlock(&session->report_mutex);
434 return ret;
Jiri Kosina2da31932009-11-26 16:20:56 +0100435}
436
Linus Torvalds1da177e2005-04-16 15:20:36 -0700437static void hidp_idle_timeout(unsigned long arg)
438{
439 struct hidp_session *session = (struct hidp_session *) arg;
440
Peter Hurley7bb59df2011-06-30 13:53:53 -0400441 atomic_inc(&session->terminate);
442 wake_up_process(session->task);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700443}
444
Andrew Morton91f5cca2008-02-05 03:07:58 -0800445static void hidp_set_timer(struct hidp_session *session)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700446{
447 if (session->idle_to > 0)
448 mod_timer(&session->timer, jiffies + HZ * session->idle_to);
449}
450
Gustavo Padovan6039aa72012-05-23 04:04:18 -0300451static void hidp_del_timer(struct hidp_session *session)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700452{
453 if (session->idle_to > 0)
454 del_timer(&session->timer);
455}
456
Andrew Morton91f5cca2008-02-05 03:07:58 -0800457static void hidp_process_handshake(struct hidp_session *session,
458 unsigned char param)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700459{
460 BT_DBG("session %p param 0x%02x", session, param);
Alan Ott08254112011-01-18 03:04:38 -0500461 session->output_report_success = 0; /* default condition */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700462
463 switch (param) {
464 case HIDP_HSHK_SUCCESSFUL:
465 /* FIXME: Call into SET_ GET_ handlers here */
Alan Ott08254112011-01-18 03:04:38 -0500466 session->output_report_success = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700467 break;
468
469 case HIDP_HSHK_NOT_READY:
470 case HIDP_HSHK_ERR_INVALID_REPORT_ID:
471 case HIDP_HSHK_ERR_UNSUPPORTED_REQUEST:
472 case HIDP_HSHK_ERR_INVALID_PARAMETER:
Gustavo F. Padovanab88f712011-10-06 22:05:37 -0300473 if (test_and_clear_bit(HIDP_WAITING_FOR_RETURN, &session->flags))
Alan Ott0ff17312011-01-18 03:04:40 -0500474 wake_up_interruptible(&session->report_queue);
Gustavo F. Padovanab88f712011-10-06 22:05:37 -0300475
Linus Torvalds1da177e2005-04-16 15:20:36 -0700476 /* FIXME: Call into SET_ GET_ handlers here */
477 break;
478
479 case HIDP_HSHK_ERR_UNKNOWN:
480 break;
481
482 case HIDP_HSHK_ERR_FATAL:
483 /* Device requests a reboot, as this is the only way this error
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900484 * can be recovered. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700485 __hidp_send_ctrl_message(session,
486 HIDP_TRANS_HID_CONTROL | HIDP_CTRL_SOFT_RESET, NULL, 0);
487 break;
488
489 default:
490 __hidp_send_ctrl_message(session,
491 HIDP_TRANS_HANDSHAKE | HIDP_HSHK_ERR_INVALID_PARAMETER, NULL, 0);
492 break;
493 }
Alan Ott08254112011-01-18 03:04:38 -0500494
495 /* Wake up the waiting thread. */
Gustavo F. Padovanab88f712011-10-06 22:05:37 -0300496 if (test_and_clear_bit(HIDP_WAITING_FOR_SEND_ACK, &session->flags))
Alan Ott08254112011-01-18 03:04:38 -0500497 wake_up_interruptible(&session->report_queue);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700498}
499
Andrew Morton91f5cca2008-02-05 03:07:58 -0800500static void hidp_process_hid_control(struct hidp_session *session,
501 unsigned char param)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700502{
503 BT_DBG("session %p param 0x%02x", session, param);
504
Dave Youngeff001e2008-02-05 03:07:14 -0800505 if (param == HIDP_CTRL_VIRTUAL_CABLE_UNPLUG) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700506 /* Flush the transmit queues */
507 skb_queue_purge(&session->ctrl_transmit);
508 skb_queue_purge(&session->intr_transmit);
509
Peter Hurley7bb59df2011-06-30 13:53:53 -0400510 atomic_inc(&session->terminate);
511 wake_up_process(current);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700512 }
513}
514
Alan Ott0ff17312011-01-18 03:04:40 -0500515/* Returns true if the passed-in skb should be freed by the caller. */
516static int hidp_process_data(struct hidp_session *session, struct sk_buff *skb,
Andrew Morton91f5cca2008-02-05 03:07:58 -0800517 unsigned char param)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700518{
Alan Ott0ff17312011-01-18 03:04:40 -0500519 int done_with_skb = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700520 BT_DBG("session %p skb %p len %d param 0x%02x", session, skb, skb->len, param);
521
522 switch (param) {
523 case HIDP_DATA_RTYPE_INPUT:
524 hidp_set_timer(session);
525
526 if (session->input)
527 hidp_input_report(session, skb);
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100528
529 if (session->hid)
530 hid_input_report(session->hid, HID_INPUT_REPORT, skb->data, skb->len, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700531 break;
532
533 case HIDP_DATA_RTYPE_OTHER:
534 case HIDP_DATA_RTYPE_OUPUT:
535 case HIDP_DATA_RTYPE_FEATURE:
536 break;
537
538 default:
539 __hidp_send_ctrl_message(session,
540 HIDP_TRANS_HANDSHAKE | HIDP_HSHK_ERR_INVALID_PARAMETER, NULL, 0);
541 }
Alan Ott0ff17312011-01-18 03:04:40 -0500542
543 if (test_bit(HIDP_WAITING_FOR_RETURN, &session->flags) &&
544 param == session->waiting_report_type) {
545 if (session->waiting_report_number < 0 ||
546 session->waiting_report_number == skb->data[0]) {
547 /* hidp_get_raw_report() is waiting on this report. */
548 session->report_return = skb;
549 done_with_skb = 0;
550 clear_bit(HIDP_WAITING_FOR_RETURN, &session->flags);
551 wake_up_interruptible(&session->report_queue);
552 }
553 }
554
555 return done_with_skb;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700556}
557
Andrew Morton91f5cca2008-02-05 03:07:58 -0800558static void hidp_recv_ctrl_frame(struct hidp_session *session,
559 struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700560{
561 unsigned char hdr, type, param;
Alan Ott0ff17312011-01-18 03:04:40 -0500562 int free_skb = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700563
564 BT_DBG("session %p skb %p len %d", session, skb, skb->len);
565
566 hdr = skb->data[0];
567 skb_pull(skb, 1);
568
569 type = hdr & HIDP_HEADER_TRANS_MASK;
570 param = hdr & HIDP_HEADER_PARAM_MASK;
571
572 switch (type) {
573 case HIDP_TRANS_HANDSHAKE:
574 hidp_process_handshake(session, param);
575 break;
576
577 case HIDP_TRANS_HID_CONTROL:
578 hidp_process_hid_control(session, param);
579 break;
580
581 case HIDP_TRANS_DATA:
Alan Ott0ff17312011-01-18 03:04:40 -0500582 free_skb = hidp_process_data(session, skb, param);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700583 break;
584
585 default:
586 __hidp_send_ctrl_message(session,
587 HIDP_TRANS_HANDSHAKE | HIDP_HSHK_ERR_UNSUPPORTED_REQUEST, NULL, 0);
588 break;
589 }
590
Alan Ott0ff17312011-01-18 03:04:40 -0500591 if (free_skb)
592 kfree_skb(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700593}
594
Andrew Morton91f5cca2008-02-05 03:07:58 -0800595static void hidp_recv_intr_frame(struct hidp_session *session,
596 struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700597{
598 unsigned char hdr;
599
600 BT_DBG("session %p skb %p len %d", session, skb, skb->len);
601
602 hdr = skb->data[0];
603 skb_pull(skb, 1);
604
605 if (hdr == (HIDP_TRANS_DATA | HIDP_DATA_RTYPE_INPUT)) {
606 hidp_set_timer(session);
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100607
Linus Torvalds1da177e2005-04-16 15:20:36 -0700608 if (session->input)
609 hidp_input_report(session, skb);
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100610
611 if (session->hid) {
612 hid_input_report(session->hid, HID_INPUT_REPORT, skb->data, skb->len, 1);
613 BT_DBG("report len %d", skb->len);
614 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700615 } else {
616 BT_DBG("Unsupported protocol header 0x%02x", hdr);
617 }
618
619 kfree_skb(skb);
620}
621
622static int hidp_send_frame(struct socket *sock, unsigned char *data, int len)
623{
624 struct kvec iv = { data, len };
625 struct msghdr msg;
626
627 BT_DBG("sock %p data %p len %d", sock, data, len);
628
629 if (!len)
630 return 0;
631
632 memset(&msg, 0, sizeof(msg));
633
634 return kernel_sendmsg(sock, &msg, &iv, 1, len);
635}
636
Gustavo F. Padovan679344e2011-10-06 20:51:37 -0300637static void hidp_process_intr_transmit(struct hidp_session *session)
638{
639 struct sk_buff *skb;
640
641 BT_DBG("session %p", session);
642
643 while ((skb = skb_dequeue(&session->intr_transmit))) {
644 if (hidp_send_frame(session->intr_sock, skb->data, skb->len) < 0) {
645 skb_queue_head(&session->intr_transmit, skb);
646 break;
647 }
648
649 hidp_set_timer(session);
650 kfree_skb(skb);
651 }
652}
653
654static void hidp_process_ctrl_transmit(struct hidp_session *session)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700655{
656 struct sk_buff *skb;
657
658 BT_DBG("session %p", session);
659
660 while ((skb = skb_dequeue(&session->ctrl_transmit))) {
661 if (hidp_send_frame(session->ctrl_sock, skb->data, skb->len) < 0) {
662 skb_queue_head(&session->ctrl_transmit, skb);
663 break;
664 }
665
666 hidp_set_timer(session);
667 kfree_skb(skb);
668 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700669}
670
671static int hidp_session(void *arg)
672{
673 struct hidp_session *session = arg;
674 struct sock *ctrl_sk = session->ctrl_sock->sk;
675 struct sock *intr_sk = session->intr_sock->sk;
676 struct sk_buff *skb;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700677 wait_queue_t ctrl_wait, intr_wait;
678
679 BT_DBG("session %p", session);
680
David Herrmann25df0842011-11-01 17:27:50 +0100681 __module_get(THIS_MODULE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700682 set_user_nice(current, -15);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700683
684 init_waitqueue_entry(&ctrl_wait, current);
685 init_waitqueue_entry(&intr_wait, current);
Eric Dumazetaa395142010-04-20 13:03:51 +0000686 add_wait_queue(sk_sleep(ctrl_sk), &ctrl_wait);
687 add_wait_queue(sk_sleep(intr_sk), &intr_wait);
Alan Ott0f69dca2011-01-18 03:04:37 -0500688 session->waiting_for_startup = 0;
689 wake_up_interruptible(&session->startup_queue);
Peter Hurley7bb59df2011-06-30 13:53:53 -0400690 set_current_state(TASK_INTERRUPTIBLE);
691 while (!atomic_read(&session->terminate)) {
Szymon Janc17f09a72011-03-21 14:20:01 +0100692 if (ctrl_sk->sk_state != BT_CONNECTED ||
693 intr_sk->sk_state != BT_CONNECTED)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700694 break;
695
Linus Torvalds1da177e2005-04-16 15:20:36 -0700696 while ((skb = skb_dequeue(&intr_sk->sk_receive_queue))) {
697 skb_orphan(skb);
Mat Martineau44935722011-07-22 14:53:58 -0700698 if (!skb_linearize(skb))
699 hidp_recv_intr_frame(session, skb);
700 else
701 kfree_skb(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700702 }
703
Gustavo F. Padovan679344e2011-10-06 20:51:37 -0300704 hidp_process_intr_transmit(session);
705
Gustavo F. Padovandc0da5c2011-10-06 18:02:13 -0300706 while ((skb = skb_dequeue(&ctrl_sk->sk_receive_queue))) {
707 skb_orphan(skb);
708 if (!skb_linearize(skb))
709 hidp_recv_ctrl_frame(session, skb);
710 else
711 kfree_skb(skb);
712 }
713
Gustavo F. Padovan679344e2011-10-06 20:51:37 -0300714 hidp_process_ctrl_transmit(session);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700715
716 schedule();
Peter Hurley7bb59df2011-06-30 13:53:53 -0400717 set_current_state(TASK_INTERRUPTIBLE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700718 }
719 set_current_state(TASK_RUNNING);
Karl Reltonfd86c9b2013-02-20 18:16:19 +0000720 atomic_inc(&session->terminate);
Eric Dumazetaa395142010-04-20 13:03:51 +0000721 remove_wait_queue(sk_sleep(intr_sk), &intr_wait);
722 remove_wait_queue(sk_sleep(ctrl_sk), &ctrl_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700723
David Herrmann794d1752011-08-26 14:06:02 +0200724 clear_bit(HIDP_WAITING_FOR_SEND_ACK, &session->flags);
725 clear_bit(HIDP_WAITING_FOR_RETURN, &session->flags);
726 wake_up_interruptible(&session->report_queue);
727
Linus Torvalds1da177e2005-04-16 15:20:36 -0700728 down_write(&hidp_session_sem);
729
730 hidp_del_timer(session);
731
Linus Torvalds1da177e2005-04-16 15:20:36 -0700732 if (session->input) {
733 input_unregister_device(session->input);
Dmitry Torokhov34abf912005-09-15 02:01:40 -0500734 session->input = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700735 }
736
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100737 if (session->hid) {
Jiri Slaby85cdaf52008-05-16 11:49:15 +0200738 hid_destroy_device(session->hid);
Marcel Holtmannedad6382009-08-22 14:22:15 -0700739 session->hid = NULL;
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100740 }
741
Marcel Holtmannec8dab32008-07-14 20:13:53 +0200742 /* Wakeup user-space polling for socket errors */
743 session->intr_sock->sk->sk_err = EUNATCH;
744 session->ctrl_sock->sk->sk_err = EUNATCH;
745
746 hidp_schedule(session);
747
David Woodhouse1c398582007-07-07 14:58:39 -0400748 fput(session->intr_sock->file);
749
Eric Dumazetaa395142010-04-20 13:03:51 +0000750 wait_event_timeout(*(sk_sleep(ctrl_sk)),
David Woodhouse1c398582007-07-07 14:58:39 -0400751 (ctrl_sk->sk_state == BT_CLOSED), msecs_to_jiffies(500));
752
753 fput(session->ctrl_sock->file);
754
David Herrmannfc225c32013-04-06 20:28:38 +0200755 list_del(&session->list);
David Woodhouse1c398582007-07-07 14:58:39 -0400756
Linus Torvalds1da177e2005-04-16 15:20:36 -0700757 up_write(&hidp_session_sem);
758
Peter Hurley1c97e942011-08-05 10:51:34 -0400759 kfree(session->rd_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700760 kfree(session);
David Herrmann25df0842011-11-01 17:27:50 +0100761 module_put_and_exit(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700762 return 0;
763}
764
Gustavo F. Padovan3e90dc82011-10-07 01:29:51 -0300765static struct hci_conn *hidp_get_connection(struct hidp_session *session)
Marcel Holtmann0a85b962006-07-06 13:09:02 +0200766{
767 bdaddr_t *src = &bt_sk(session->ctrl_sock->sk)->src;
768 bdaddr_t *dst = &bt_sk(session->ctrl_sock->sk)->dst;
Peter Hurley1785dbf2011-08-30 11:53:35 -0400769 struct hci_conn *conn;
Marcel Holtmann0a85b962006-07-06 13:09:02 +0200770 struct hci_dev *hdev;
Marcel Holtmann0a85b962006-07-06 13:09:02 +0200771
772 hdev = hci_get_route(dst, src);
773 if (!hdev)
774 return NULL;
775
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300776 hci_dev_lock(hdev);
Peter Hurley1785dbf2011-08-30 11:53:35 -0400777 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, dst);
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300778 hci_dev_unlock(hdev);
Marcel Holtmann0a85b962006-07-06 13:09:02 +0200779
780 hci_dev_put(hdev);
781
Peter Hurley1785dbf2011-08-30 11:53:35 -0400782 return conn;
Marcel Holtmann0a85b962006-07-06 13:09:02 +0200783}
784
Andrew Morton91f5cca2008-02-05 03:07:58 -0800785static int hidp_setup_input(struct hidp_session *session,
786 struct hidp_connadd_req *req)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700787{
Jiri Slabyc500c972008-05-16 11:49:16 +0200788 struct input_dev *input;
Gustavo F. Padovan3415a5f2011-10-06 21:17:32 -0300789 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700790
Jiri Slabyc500c972008-05-16 11:49:16 +0200791 input = input_allocate_device();
792 if (!input)
793 return -ENOMEM;
794
795 session->input = input;
796
Marcel Holtmann5be39462007-05-09 09:15:30 +0200797 input_set_drvdata(input, session);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700798
Dmitry Torokhov34abf912005-09-15 02:01:40 -0500799 input->name = "Bluetooth HID Boot Protocol Device";
800
Linus Torvalds1da177e2005-04-16 15:20:36 -0700801 input->id.bustype = BUS_BLUETOOTH;
802 input->id.vendor = req->vendor;
803 input->id.product = req->product;
804 input->id.version = req->version;
805
806 if (req->subclass & 0x40) {
807 set_bit(EV_KEY, input->evbit);
808 set_bit(EV_LED, input->evbit);
809 set_bit(EV_REP, input->evbit);
810
811 set_bit(LED_NUML, input->ledbit);
812 set_bit(LED_CAPSL, input->ledbit);
813 set_bit(LED_SCROLLL, input->ledbit);
814 set_bit(LED_COMPOSE, input->ledbit);
815 set_bit(LED_KANA, input->ledbit);
816
817 for (i = 0; i < sizeof(hidp_keycode); i++)
818 set_bit(hidp_keycode[i], input->keybit);
819 clear_bit(0, input->keybit);
820 }
821
822 if (req->subclass & 0x80) {
Jiri Slaby7b19ada2007-10-18 23:40:32 -0700823 input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL);
824 input->keybit[BIT_WORD(BTN_MOUSE)] = BIT_MASK(BTN_LEFT) |
825 BIT_MASK(BTN_RIGHT) | BIT_MASK(BTN_MIDDLE);
826 input->relbit[0] = BIT_MASK(REL_X) | BIT_MASK(REL_Y);
827 input->keybit[BIT_WORD(BTN_MOUSE)] |= BIT_MASK(BTN_SIDE) |
828 BIT_MASK(BTN_EXTRA);
829 input->relbit[0] |= BIT_MASK(REL_WHEEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700830 }
831
Peter Hurley1785dbf2011-08-30 11:53:35 -0400832 input->dev.parent = &session->conn->dev;
Marcel Holtmann0a85b962006-07-06 13:09:02 +0200833
Linus Torvalds1da177e2005-04-16 15:20:36 -0700834 input->event = hidp_input_event;
835
Marcel Holtmannedad6382009-08-22 14:22:15 -0700836 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700837}
838
Marcel Holtmannf5ffd462007-02-17 23:58:53 +0100839static int hidp_open(struct hid_device *hid)
840{
841 return 0;
842}
843
844static void hidp_close(struct hid_device *hid)
845{
846}
847
Jiri Slabyc500c972008-05-16 11:49:16 +0200848static int hidp_parse(struct hid_device *hid)
849{
850 struct hidp_session *session = hid->driver_data;
Jiri Slabyc500c972008-05-16 11:49:16 +0200851
Michael Poole15c697c2010-02-05 12:23:43 -0500852 return hid_parse_report(session->hid, session->rd_data,
853 session->rd_size);
Jiri Slabyc500c972008-05-16 11:49:16 +0200854}
855
856static int hidp_start(struct hid_device *hid)
857{
858 struct hidp_session *session = hid->driver_data;
859 struct hid_report *report;
860
David Herrmann142c69c2011-08-26 13:27:12 +0200861 if (hid->quirks & HID_QUIRK_NO_INIT_REPORTS)
862 return 0;
863
Jiri Slabyc500c972008-05-16 11:49:16 +0200864 list_for_each_entry(report, &hid->report_enum[HID_INPUT_REPORT].
865 report_list, list)
866 hidp_send_report(session, report);
867
868 list_for_each_entry(report, &hid->report_enum[HID_FEATURE_REPORT].
869 report_list, list)
870 hidp_send_report(session, report);
871
Jiri Slabyc500c972008-05-16 11:49:16 +0200872 return 0;
873}
874
875static void hidp_stop(struct hid_device *hid)
876{
877 struct hidp_session *session = hid->driver_data;
878
879 skb_queue_purge(&session->ctrl_transmit);
880 skb_queue_purge(&session->intr_transmit);
881
Jiri Slabyc500c972008-05-16 11:49:16 +0200882 hid->claimed = 0;
883}
884
885static struct hid_ll_driver hidp_hid_driver = {
886 .parse = hidp_parse,
887 .start = hidp_start,
888 .stop = hidp_stop,
889 .open = hidp_open,
890 .close = hidp_close,
891 .hidinput_input_event = hidp_hidinput_event,
892};
893
Alan Ott0f69dca2011-01-18 03:04:37 -0500894/* This function sets up the hid device. It does not add it
895 to the HID system. That is done in hidp_add_connection(). */
Jiri Slaby85cdaf52008-05-16 11:49:15 +0200896static int hidp_setup_hid(struct hidp_session *session,
Andrew Morton91f5cca2008-02-05 03:07:58 -0800897 struct hidp_connadd_req *req)
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100898{
Jiri Slabyc500c972008-05-16 11:49:16 +0200899 struct hid_device *hid;
Marcel Holtmannedad6382009-08-22 14:22:15 -0700900 int err;
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100901
Michael Poole15c697c2010-02-05 12:23:43 -0500902 session->rd_data = kzalloc(req->rd_size, GFP_KERNEL);
903 if (!session->rd_data)
904 return -ENOMEM;
905
906 if (copy_from_user(session->rd_data, req->rd_data, req->rd_size)) {
907 err = -EFAULT;
908 goto fault;
909 }
910 session->rd_size = req->rd_size;
911
Jiri Slabyc500c972008-05-16 11:49:16 +0200912 hid = hid_allocate_device();
Michael Poole15c697c2010-02-05 12:23:43 -0500913 if (IS_ERR(hid)) {
914 err = PTR_ERR(hid);
915 goto fault;
916 }
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100917
Jiri Slabyc500c972008-05-16 11:49:16 +0200918 session->hid = hid;
Michael Poole15c697c2010-02-05 12:23:43 -0500919
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100920 hid->driver_data = session;
921
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100922 hid->bus = BUS_BLUETOOTH;
923 hid->vendor = req->vendor;
924 hid->product = req->product;
925 hid->version = req->version;
Jiri Slabyc500c972008-05-16 11:49:16 +0200926 hid->country = req->country;
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100927
Anderson Lizardo0a9ab9b2013-01-06 18:28:53 -0400928 strncpy(hid->name, req->name, sizeof(req->name) - 1);
Andrei Emeltchenkofcb73332012-09-25 12:49:44 +0300929
930 snprintf(hid->phys, sizeof(hid->phys), "%pMR",
931 &bt_sk(session->ctrl_sock->sk)->src);
932
933 snprintf(hid->uniq, sizeof(hid->uniq), "%pMR",
934 &bt_sk(session->ctrl_sock->sk)->dst);
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100935
Peter Hurley1785dbf2011-08-30 11:53:35 -0400936 hid->dev.parent = &session->conn->dev;
Jiri Slabyc500c972008-05-16 11:49:16 +0200937 hid->ll_driver = &hidp_hid_driver;
Jiri Slaby85cdaf52008-05-16 11:49:15 +0200938
Alan Ott0ff17312011-01-18 03:04:40 -0500939 hid->hid_get_raw_report = hidp_get_raw_report;
Jiri Kosina2da31932009-11-26 16:20:56 +0100940 hid->hid_output_raw_report = hidp_output_raw_report;
941
Lamarque V. Souza4529eef2012-12-06 12:39:55 -0200942 /* True if device is blacklisted in drivers/hid/hid-core.c */
943 if (hid_ignore(hid)) {
944 hid_destroy_device(session->hid);
945 session->hid = NULL;
946 return -ENODEV;
947 }
948
Jiri Slabyc500c972008-05-16 11:49:16 +0200949 return 0;
Marcel Holtmannedad6382009-08-22 14:22:15 -0700950
Michael Poole15c697c2010-02-05 12:23:43 -0500951fault:
952 kfree(session->rd_data);
953 session->rd_data = NULL;
954
Marcel Holtmannedad6382009-08-22 14:22:15 -0700955 return err;
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100956}
957
Linus Torvalds1da177e2005-04-16 15:20:36 -0700958int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock, struct socket *intr_sock)
959{
960 struct hidp_session *session, *s;
Szymon Jancaabf6f82011-04-05 15:37:45 +0200961 int vendor, product;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700962 int err;
963
964 BT_DBG("");
965
David Herrmannb3916db2013-04-05 14:57:34 +0200966 if (!l2cap_is_socket(ctrl_sock) || !l2cap_is_socket(intr_sock))
967 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700968 if (bacmp(&bt_sk(ctrl_sock->sk)->src, &bt_sk(intr_sock->sk)->src) ||
969 bacmp(&bt_sk(ctrl_sock->sk)->dst, &bt_sk(intr_sock->sk)->dst))
970 return -ENOTUNIQ;
971
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +0100972 BT_DBG("rd_data %p rd_size %d", req->rd_data, req->rd_size);
973
Linus Torvalds1da177e2005-04-16 15:20:36 -0700974 down_write(&hidp_session_sem);
975
976 s = __hidp_get_session(&bt_sk(ctrl_sock->sk)->dst);
David Herrmanndcc07642013-04-06 20:28:40 +0200977 if (s) {
Gustavo F. Padovan81b25cd2011-10-06 23:32:29 -0300978 up_write(&hidp_session_sem);
979 return -EEXIST;
980 }
981
982 session = kzalloc(sizeof(struct hidp_session), GFP_KERNEL);
983 if (!session) {
984 up_write(&hidp_session_sem);
985 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700986 }
987
988 bacpy(&session->bdaddr, &bt_sk(ctrl_sock->sk)->dst);
989
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -0300990 session->ctrl_mtu = min_t(uint, l2cap_pi(ctrl_sock->sk)->chan->omtu,
991 l2cap_pi(ctrl_sock->sk)->chan->imtu);
992 session->intr_mtu = min_t(uint, l2cap_pi(intr_sock->sk)->chan->omtu,
993 l2cap_pi(intr_sock->sk)->chan->imtu);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700994
995 BT_DBG("ctrl mtu %d intr mtu %d", session->ctrl_mtu, session->intr_mtu);
996
997 session->ctrl_sock = ctrl_sock;
998 session->intr_sock = intr_sock;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700999
Gustavo F. Padovan3c32fa92011-10-20 17:21:34 -02001000 session->conn = hidp_get_connection(session);
1001 if (!session->conn) {
1002 err = -ENOTCONN;
1003 goto failed;
1004 }
1005
Pavel Emelyanovb24b8a22008-01-23 21:20:07 -08001006 setup_timer(&session->timer, hidp_idle_timeout, (unsigned long)session);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001007
1008 skb_queue_head_init(&session->ctrl_transmit);
1009 skb_queue_head_init(&session->intr_transmit);
1010
Alan Ott0ff17312011-01-18 03:04:40 -05001011 mutex_init(&session->report_mutex);
1012 init_waitqueue_head(&session->report_queue);
Alan Ott0f69dca2011-01-18 03:04:37 -05001013 init_waitqueue_head(&session->startup_queue);
1014 session->waiting_for_startup = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001015 session->flags = req->flags & (1 << HIDP_BLUETOOTH_VENDOR_ID);
1016 session->idle_to = req->idle_to;
1017
David Herrmannfc225c32013-04-06 20:28:38 +02001018 list_add(&session->list, &hidp_session_list);
Peter Hurley1785dbf2011-08-30 11:53:35 -04001019
Jiri Slabyc500c972008-05-16 11:49:16 +02001020 if (req->rd_size > 0) {
Jiri Slaby85cdaf52008-05-16 11:49:15 +02001021 err = hidp_setup_hid(session, req);
Lamarque V. Souza4529eef2012-12-06 12:39:55 -02001022 if (err && err != -ENODEV)
Marcel Holtmannedad6382009-08-22 14:22:15 -07001023 goto purge;
Jiri Slabyc500c972008-05-16 11:49:16 +02001024 }
1025
1026 if (!session->hid) {
1027 err = hidp_setup_input(session, req);
1028 if (err < 0)
Marcel Holtmannedad6382009-08-22 14:22:15 -07001029 goto purge;
Jiri Slaby85cdaf52008-05-16 11:49:15 +02001030 }
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +01001031
Linus Torvalds1da177e2005-04-16 15:20:36 -07001032 hidp_set_timer(session);
1033
Szymon Jancaabf6f82011-04-05 15:37:45 +02001034 if (session->hid) {
1035 vendor = session->hid->vendor;
1036 product = session->hid->product;
1037 } else if (session->input) {
1038 vendor = session->input->id.vendor;
1039 product = session->input->id.product;
1040 } else {
1041 vendor = 0x0000;
1042 product = 0x0000;
1043 }
1044
1045 session->task = kthread_run(hidp_session, session, "khidpd_%04x%04x",
1046 vendor, product);
1047 if (IS_ERR(session->task)) {
1048 err = PTR_ERR(session->task);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001049 goto unlink;
Szymon Jancaabf6f82011-04-05 15:37:45 +02001050 }
1051
Alan Ott0f69dca2011-01-18 03:04:37 -05001052 while (session->waiting_for_startup) {
1053 wait_event_interruptible(session->startup_queue,
1054 !session->waiting_for_startup);
1055 }
1056
Gustavo F. Padovan3415a5f2011-10-06 21:17:32 -03001057 if (session->hid)
1058 err = hid_add_device(session->hid);
1059 else
1060 err = input_register_device(session->input);
1061
Peter Hurleye9d5cb52011-08-05 10:51:26 -04001062 if (err < 0) {
1063 atomic_inc(&session->terminate);
1064 wake_up_process(session->task);
1065 up_write(&hidp_session_sem);
1066 return err;
1067 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001068
1069 if (session->input) {
1070 hidp_send_ctrl_message(session,
1071 HIDP_TRANS_SET_PROTOCOL | HIDP_PROTO_BOOT, NULL, 0);
1072 session->flags |= (1 << HIDP_BOOT_PROTOCOL_MODE);
1073
1074 session->leds = 0xff;
1075 hidp_input_event(session->input, EV_LED, 0, 0);
1076 }
1077
1078 up_write(&hidp_session_sem);
1079 return 0;
1080
1081unlink:
1082 hidp_del_timer(session);
1083
Marcel Holtmannedad6382009-08-22 14:22:15 -07001084 if (session->input) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001085 input_unregister_device(session->input);
Marcel Holtmannedad6382009-08-22 14:22:15 -07001086 session->input = NULL;
1087 }
1088
1089 if (session->hid) {
Jiri Slaby85cdaf52008-05-16 11:49:15 +02001090 hid_destroy_device(session->hid);
Marcel Holtmannedad6382009-08-22 14:22:15 -07001091 session->hid = NULL;
1092 }
1093
Michael Poole15c697c2010-02-05 12:23:43 -05001094 kfree(session->rd_data);
1095 session->rd_data = NULL;
1096
Marcel Holtmannedad6382009-08-22 14:22:15 -07001097purge:
David Herrmannfc225c32013-04-06 20:28:38 +02001098 list_del(&session->list);
Peter Hurley1785dbf2011-08-30 11:53:35 -04001099
Jiri Slabyc500c972008-05-16 11:49:16 +02001100 skb_queue_purge(&session->ctrl_transmit);
1101 skb_queue_purge(&session->intr_transmit);
Marcel Holtmannedad6382009-08-22 14:22:15 -07001102
Jiri Slabyc500c972008-05-16 11:49:16 +02001103failed:
1104 up_write(&hidp_session_sem);
Marcel Holtmanne1aaadd2007-02-17 23:58:49 +01001105
Linus Torvalds1da177e2005-04-16 15:20:36 -07001106 kfree(session);
1107 return err;
1108}
1109
1110int hidp_del_connection(struct hidp_conndel_req *req)
1111{
1112 struct hidp_session *session;
1113 int err = 0;
1114
1115 BT_DBG("");
1116
1117 down_read(&hidp_session_sem);
1118
1119 session = __hidp_get_session(&req->bdaddr);
1120 if (session) {
1121 if (req->flags & (1 << HIDP_VIRTUAL_CABLE_UNPLUG)) {
1122 hidp_send_ctrl_message(session,
1123 HIDP_TRANS_HID_CONTROL | HIDP_CTRL_VIRTUAL_CABLE_UNPLUG, NULL, 0);
1124 } else {
1125 /* Flush the transmit queues */
1126 skb_queue_purge(&session->ctrl_transmit);
1127 skb_queue_purge(&session->intr_transmit);
1128
Peter Hurley7bb59df2011-06-30 13:53:53 -04001129 atomic_inc(&session->terminate);
1130 wake_up_process(session->task);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001131 }
1132 } else
1133 err = -ENOENT;
1134
1135 up_read(&hidp_session_sem);
1136 return err;
1137}
1138
1139int hidp_get_connlist(struct hidp_connlist_req *req)
1140{
Gustavo F. Padovancd11cdd2011-10-06 17:35:31 -03001141 struct hidp_session *session;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001142 int err = 0, n = 0;
1143
1144 BT_DBG("");
1145
1146 down_read(&hidp_session_sem);
1147
Gustavo F. Padovancd11cdd2011-10-06 17:35:31 -03001148 list_for_each_entry(session, &hidp_session_list, list) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001149 struct hidp_conninfo ci;
1150
Linus Torvalds1da177e2005-04-16 15:20:36 -07001151 __hidp_copy_session(session, &ci);
1152
1153 if (copy_to_user(req->ci, &ci, sizeof(ci))) {
1154 err = -EFAULT;
1155 break;
1156 }
1157
1158 if (++n >= req->cnum)
1159 break;
1160
1161 req->ci++;
1162 }
1163 req->cnum = n;
1164
1165 up_read(&hidp_session_sem);
1166 return err;
1167}
1168
1169int hidp_get_conninfo(struct hidp_conninfo *ci)
1170{
1171 struct hidp_session *session;
1172 int err = 0;
1173
1174 down_read(&hidp_session_sem);
1175
1176 session = __hidp_get_session(&ci->bdaddr);
1177 if (session)
1178 __hidp_copy_session(session, ci);
1179 else
1180 err = -ENOENT;
1181
1182 up_read(&hidp_session_sem);
1183 return err;
1184}
1185
1186static int __init hidp_init(void)
1187{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001188 BT_INFO("HIDP (Human Interface Emulation) ver %s", VERSION);
1189
Henrik Rydberg8215d552012-04-23 12:07:07 +02001190 return hidp_init_sockets();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001191}
1192
1193static void __exit hidp_exit(void)
1194{
1195 hidp_cleanup_sockets();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001196}
1197
1198module_init(hidp_init);
1199module_exit(hidp_exit);
1200
1201MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
1202MODULE_DESCRIPTION("Bluetooth HIDP ver " VERSION);
1203MODULE_VERSION(VERSION);
1204MODULE_LICENSE("GPL");
1205MODULE_ALIAS("bt-proto-6");