diff options
Diffstat (limited to 'net/bluetooth/hidp')
-rw-r--r-- | net/bluetooth/hidp/Kconfig | 2 | ||||
-rw-r--r-- | net/bluetooth/hidp/core.c | 310 | ||||
-rw-r--r-- | net/bluetooth/hidp/hidp.h | 20 | ||||
-rw-r--r-- | net/bluetooth/hidp/sock.c | 7 |
4 files changed, 261 insertions, 78 deletions
diff --git a/net/bluetooth/hidp/Kconfig b/net/bluetooth/hidp/Kconfig index 98fdfa1fbddd..86a91543172a 100644 --- a/net/bluetooth/hidp/Kconfig +++ b/net/bluetooth/hidp/Kconfig | |||
@@ -1,6 +1,6 @@ | |||
1 | config BT_HIDP | 1 | config BT_HIDP |
2 | tristate "HIDP protocol support" | 2 | tristate "HIDP protocol support" |
3 | depends on BT && BT_L2CAP && INPUT | 3 | depends on BT && BT_L2CAP && INPUT && HID_SUPPORT |
4 | select HID | 4 | select HID |
5 | help | 5 | help |
6 | HIDP (Human Interface Device Protocol) is a transport layer | 6 | HIDP (Human Interface Device Protocol) is a transport layer |
diff --git a/net/bluetooth/hidp/core.c b/net/bluetooth/hidp/core.c index bfe641b7dfaf..43b4c2deb7cc 100644 --- a/net/bluetooth/hidp/core.c +++ b/net/bluetooth/hidp/core.c | |||
@@ -36,6 +36,8 @@ | |||
36 | #include <linux/file.h> | 36 | #include <linux/file.h> |
37 | #include <linux/init.h> | 37 | #include <linux/init.h> |
38 | #include <linux/wait.h> | 38 | #include <linux/wait.h> |
39 | #include <linux/mutex.h> | ||
40 | #include <linux/kthread.h> | ||
39 | #include <net/sock.h> | 41 | #include <net/sock.h> |
40 | 42 | ||
41 | #include <linux/input.h> | 43 | #include <linux/input.h> |
@@ -54,22 +56,24 @@ static DECLARE_RWSEM(hidp_session_sem); | |||
54 | static LIST_HEAD(hidp_session_list); | 56 | static LIST_HEAD(hidp_session_list); |
55 | 57 | ||
56 | static unsigned char hidp_keycode[256] = { | 58 | static unsigned char hidp_keycode[256] = { |
57 | 0, 0, 0, 0, 30, 48, 46, 32, 18, 33, 34, 35, 23, 36, 37, 38, | 59 | 0, 0, 0, 0, 30, 48, 46, 32, 18, 33, 34, 35, 23, 36, |
58 | 50, 49, 24, 25, 16, 19, 31, 20, 22, 47, 17, 45, 21, 44, 2, 3, | 60 | 37, 38, 50, 49, 24, 25, 16, 19, 31, 20, 22, 47, 17, 45, |
59 | 4, 5, 6, 7, 8, 9, 10, 11, 28, 1, 14, 15, 57, 12, 13, 26, | 61 | 21, 44, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 28, 1, |
60 | 27, 43, 43, 39, 40, 41, 51, 52, 53, 58, 59, 60, 61, 62, 63, 64, | 62 | 14, 15, 57, 12, 13, 26, 27, 43, 43, 39, 40, 41, 51, 52, |
61 | 65, 66, 67, 68, 87, 88, 99, 70,119,110,102,104,111,107,109,106, | 63 | 53, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 87, 88, |
62 | 105,108,103, 69, 98, 55, 74, 78, 96, 79, 80, 81, 75, 76, 77, 71, | 64 | 99, 70, 119, 110, 102, 104, 111, 107, 109, 106, 105, 108, 103, 69, |
63 | 72, 73, 82, 83, 86,127,116,117,183,184,185,186,187,188,189,190, | 65 | 98, 55, 74, 78, 96, 79, 80, 81, 75, 76, 77, 71, 72, 73, |
64 | 191,192,193,194,134,138,130,132,128,129,131,137,133,135,136,113, | 66 | 82, 83, 86, 127, 116, 117, 183, 184, 185, 186, 187, 188, 189, 190, |
65 | 115,114, 0, 0, 0,121, 0, 89, 93,124, 92, 94, 95, 0, 0, 0, | 67 | 191, 192, 193, 194, 134, 138, 130, 132, 128, 129, 131, 137, 133, 135, |
66 | 122,123, 90, 91, 85, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | 68 | 136, 113, 115, 114, 0, 0, 0, 121, 0, 89, 93, 124, 92, 94, |
67 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | 69 | 95, 0, 0, 0, 122, 123, 90, 91, 85, 0, 0, 0, 0, 0, |
68 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | 70 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
69 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | 71 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
70 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | 72 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
71 | 29, 42, 56,125, 97, 54,100,126,164,166,165,163,161,115,114,113, | 73 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
72 | 150,158,159,128,136,177,178,176,142,152,173,140 | 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 | ||
73 | }; | 77 | }; |
74 | 78 | ||
75 | static unsigned char hidp_mkeyspat[] = { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 }; | 79 | static unsigned char hidp_mkeyspat[] = { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 }; |
@@ -107,6 +111,7 @@ static void __hidp_unlink_session(struct hidp_session *session) | |||
107 | 111 | ||
108 | static void __hidp_copy_session(struct hidp_session *session, struct hidp_conninfo *ci) | 112 | static void __hidp_copy_session(struct hidp_session *session, struct hidp_conninfo *ci) |
109 | { | 113 | { |
114 | memset(ci, 0, sizeof(*ci)); | ||
110 | bacpy(&ci->bdaddr, &session->bdaddr); | 115 | bacpy(&ci->bdaddr, &session->bdaddr); |
111 | 116 | ||
112 | ci->flags = session->flags; | 117 | ci->flags = session->flags; |
@@ -115,7 +120,6 @@ static void __hidp_copy_session(struct hidp_session *session, struct hidp_connin | |||
115 | ci->vendor = 0x0000; | 120 | ci->vendor = 0x0000; |
116 | ci->product = 0x0000; | 121 | ci->product = 0x0000; |
117 | ci->version = 0x0000; | 122 | ci->version = 0x0000; |
118 | memset(ci->name, 0, 128); | ||
119 | 123 | ||
120 | if (session->input) { | 124 | if (session->input) { |
121 | ci->vendor = session->input->id.vendor; | 125 | ci->vendor = session->input->id.vendor; |
@@ -157,7 +161,8 @@ static int hidp_queue_event(struct hidp_session *session, struct input_dev *dev, | |||
157 | 161 | ||
158 | session->leds = newleds; | 162 | session->leds = newleds; |
159 | 163 | ||
160 | if (!(skb = alloc_skb(3, GFP_ATOMIC))) { | 164 | skb = alloc_skb(3, GFP_ATOMIC); |
165 | if (!skb) { | ||
161 | BT_ERR("Can't allocate memory for new frame"); | 166 | BT_ERR("Can't allocate memory for new frame"); |
162 | return -ENOMEM; | 167 | return -ENOMEM; |
163 | } | 168 | } |
@@ -250,7 +255,8 @@ static int __hidp_send_ctrl_message(struct hidp_session *session, | |||
250 | 255 | ||
251 | BT_DBG("session %p data %p size %d", session, data, size); | 256 | BT_DBG("session %p data %p size %d", session, data, size); |
252 | 257 | ||
253 | if (!(skb = alloc_skb(size + 1, GFP_ATOMIC))) { | 258 | skb = alloc_skb(size + 1, GFP_ATOMIC); |
259 | if (!skb) { | ||
254 | BT_ERR("Can't allocate memory for new frame"); | 260 | BT_ERR("Can't allocate memory for new frame"); |
255 | return -ENOMEM; | 261 | return -ENOMEM; |
256 | } | 262 | } |
@@ -283,7 +289,8 @@ static int hidp_queue_report(struct hidp_session *session, | |||
283 | 289 | ||
284 | BT_DBG("session %p hid %p data %p size %d", session, session->hid, data, size); | 290 | BT_DBG("session %p hid %p data %p size %d", session, session->hid, data, size); |
285 | 291 | ||
286 | if (!(skb = alloc_skb(size + 1, GFP_ATOMIC))) { | 292 | skb = alloc_skb(size + 1, GFP_ATOMIC); |
293 | if (!skb) { | ||
287 | BT_ERR("Can't allocate memory for new frame"); | 294 | BT_ERR("Can't allocate memory for new frame"); |
288 | return -ENOMEM; | 295 | return -ENOMEM; |
289 | } | 296 | } |
@@ -313,24 +320,144 @@ static int hidp_send_report(struct hidp_session *session, struct hid_report *rep | |||
313 | return hidp_queue_report(session, buf, rsize); | 320 | return hidp_queue_report(session, buf, rsize); |
314 | } | 321 | } |
315 | 322 | ||
323 | static int hidp_get_raw_report(struct hid_device *hid, | ||
324 | unsigned char report_number, | ||
325 | unsigned char *data, size_t count, | ||
326 | unsigned char report_type) | ||
327 | { | ||
328 | 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; | ||
332 | |||
333 | switch (report_type) { | ||
334 | case HID_FEATURE_REPORT: | ||
335 | report_type = HIDP_TRANS_GET_REPORT | HIDP_DATA_RTYPE_FEATURE; | ||
336 | break; | ||
337 | case HID_INPUT_REPORT: | ||
338 | report_type = HIDP_TRANS_GET_REPORT | HIDP_DATA_RTYPE_INPUT; | ||
339 | break; | ||
340 | case HID_OUTPUT_REPORT: | ||
341 | report_type = HIDP_TRANS_GET_REPORT | HIDP_DATA_RTYPE_OUPUT; | ||
342 | break; | ||
343 | default: | ||
344 | return -EINVAL; | ||
345 | } | ||
346 | |||
347 | if (mutex_lock_interruptible(&session->report_mutex)) | ||
348 | return -ERESTARTSYS; | ||
349 | |||
350 | /* Set up our wait, and send the report request to the device. */ | ||
351 | session->waiting_report_type = report_type & HIDP_DATA_RTYPE_MASK; | ||
352 | session->waiting_report_number = numbered_reports ? report_number : -1; | ||
353 | set_bit(HIDP_WAITING_FOR_RETURN, &session->flags); | ||
354 | data[0] = report_number; | ||
355 | if (hidp_send_ctrl_message(hid->driver_data, report_type, data, 1)) | ||
356 | goto err_eio; | ||
357 | |||
358 | /* Wait for the return of the report. The returned report | ||
359 | gets put in session->report_return. */ | ||
360 | while (test_bit(HIDP_WAITING_FOR_RETURN, &session->flags)) { | ||
361 | int res; | ||
362 | |||
363 | res = wait_event_interruptible_timeout(session->report_queue, | ||
364 | !test_bit(HIDP_WAITING_FOR_RETURN, &session->flags), | ||
365 | 5*HZ); | ||
366 | if (res == 0) { | ||
367 | /* timeout */ | ||
368 | goto err_eio; | ||
369 | } | ||
370 | if (res < 0) { | ||
371 | /* signal */ | ||
372 | goto err_restartsys; | ||
373 | } | ||
374 | } | ||
375 | |||
376 | skb = session->report_return; | ||
377 | if (skb) { | ||
378 | len = skb->len < count ? skb->len : count; | ||
379 | memcpy(data, skb->data, len); | ||
380 | |||
381 | kfree_skb(skb); | ||
382 | session->report_return = NULL; | ||
383 | } else { | ||
384 | /* Device returned a HANDSHAKE, indicating protocol error. */ | ||
385 | len = -EIO; | ||
386 | } | ||
387 | |||
388 | clear_bit(HIDP_WAITING_FOR_RETURN, &session->flags); | ||
389 | mutex_unlock(&session->report_mutex); | ||
390 | |||
391 | return len; | ||
392 | |||
393 | err_restartsys: | ||
394 | clear_bit(HIDP_WAITING_FOR_RETURN, &session->flags); | ||
395 | mutex_unlock(&session->report_mutex); | ||
396 | return -ERESTARTSYS; | ||
397 | err_eio: | ||
398 | clear_bit(HIDP_WAITING_FOR_RETURN, &session->flags); | ||
399 | mutex_unlock(&session->report_mutex); | ||
400 | return -EIO; | ||
401 | } | ||
402 | |||
316 | static int hidp_output_raw_report(struct hid_device *hid, unsigned char *data, size_t count, | 403 | static int hidp_output_raw_report(struct hid_device *hid, unsigned char *data, size_t count, |
317 | unsigned char report_type) | 404 | unsigned char report_type) |
318 | { | 405 | { |
406 | struct hidp_session *session = hid->driver_data; | ||
407 | int ret; | ||
408 | |||
319 | switch (report_type) { | 409 | switch (report_type) { |
320 | case HID_FEATURE_REPORT: | 410 | case HID_FEATURE_REPORT: |
321 | report_type = HIDP_TRANS_SET_REPORT | HIDP_DATA_RTYPE_FEATURE; | 411 | report_type = HIDP_TRANS_SET_REPORT | HIDP_DATA_RTYPE_FEATURE; |
322 | break; | 412 | break; |
323 | case HID_OUTPUT_REPORT: | 413 | case HID_OUTPUT_REPORT: |
324 | report_type = HIDP_TRANS_DATA | HIDP_DATA_RTYPE_OUPUT; | 414 | report_type = HIDP_TRANS_SET_REPORT | HIDP_DATA_RTYPE_OUPUT; |
325 | break; | 415 | break; |
326 | default: | 416 | default: |
327 | return -EINVAL; | 417 | return -EINVAL; |
328 | } | 418 | } |
329 | 419 | ||
420 | 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); | ||
330 | if (hidp_send_ctrl_message(hid->driver_data, report_type, | 425 | if (hidp_send_ctrl_message(hid->driver_data, report_type, |
331 | data, count)) | 426 | data, count)) { |
332 | return -ENOMEM; | 427 | ret = -ENOMEM; |
333 | return count; | 428 | goto err; |
429 | } | ||
430 | |||
431 | /* Wait for the ACK from the device. */ | ||
432 | while (test_bit(HIDP_WAITING_FOR_SEND_ACK, &session->flags)) { | ||
433 | int res; | ||
434 | |||
435 | res = wait_event_interruptible_timeout(session->report_queue, | ||
436 | !test_bit(HIDP_WAITING_FOR_SEND_ACK, &session->flags), | ||
437 | 10*HZ); | ||
438 | if (res == 0) { | ||
439 | /* timeout */ | ||
440 | ret = -EIO; | ||
441 | goto err; | ||
442 | } | ||
443 | if (res < 0) { | ||
444 | /* signal */ | ||
445 | ret = -ERESTARTSYS; | ||
446 | goto err; | ||
447 | } | ||
448 | } | ||
449 | |||
450 | if (!session->output_report_success) { | ||
451 | ret = -EIO; | ||
452 | goto err; | ||
453 | } | ||
454 | |||
455 | ret = count; | ||
456 | |||
457 | err: | ||
458 | clear_bit(HIDP_WAITING_FOR_SEND_ACK, &session->flags); | ||
459 | mutex_unlock(&session->report_mutex); | ||
460 | return ret; | ||
334 | } | 461 | } |
335 | 462 | ||
336 | static void hidp_idle_timeout(unsigned long arg) | 463 | static void hidp_idle_timeout(unsigned long arg) |
@@ -338,7 +465,7 @@ static void hidp_idle_timeout(unsigned long arg) | |||
338 | struct hidp_session *session = (struct hidp_session *) arg; | 465 | struct hidp_session *session = (struct hidp_session *) arg; |
339 | 466 | ||
340 | atomic_inc(&session->terminate); | 467 | atomic_inc(&session->terminate); |
341 | hidp_schedule(session); | 468 | wake_up_process(session->task); |
342 | } | 469 | } |
343 | 470 | ||
344 | static void hidp_set_timer(struct hidp_session *session) | 471 | static void hidp_set_timer(struct hidp_session *session) |
@@ -357,16 +484,22 @@ static void hidp_process_handshake(struct hidp_session *session, | |||
357 | unsigned char param) | 484 | unsigned char param) |
358 | { | 485 | { |
359 | BT_DBG("session %p param 0x%02x", session, param); | 486 | BT_DBG("session %p param 0x%02x", session, param); |
487 | session->output_report_success = 0; /* default condition */ | ||
360 | 488 | ||
361 | switch (param) { | 489 | switch (param) { |
362 | case HIDP_HSHK_SUCCESSFUL: | 490 | case HIDP_HSHK_SUCCESSFUL: |
363 | /* FIXME: Call into SET_ GET_ handlers here */ | 491 | /* FIXME: Call into SET_ GET_ handlers here */ |
492 | session->output_report_success = 1; | ||
364 | break; | 493 | break; |
365 | 494 | ||
366 | case HIDP_HSHK_NOT_READY: | 495 | case HIDP_HSHK_NOT_READY: |
367 | case HIDP_HSHK_ERR_INVALID_REPORT_ID: | 496 | case HIDP_HSHK_ERR_INVALID_REPORT_ID: |
368 | case HIDP_HSHK_ERR_UNSUPPORTED_REQUEST: | 497 | case HIDP_HSHK_ERR_UNSUPPORTED_REQUEST: |
369 | case HIDP_HSHK_ERR_INVALID_PARAMETER: | 498 | case HIDP_HSHK_ERR_INVALID_PARAMETER: |
499 | if (test_bit(HIDP_WAITING_FOR_RETURN, &session->flags)) { | ||
500 | clear_bit(HIDP_WAITING_FOR_RETURN, &session->flags); | ||
501 | wake_up_interruptible(&session->report_queue); | ||
502 | } | ||
370 | /* FIXME: Call into SET_ GET_ handlers here */ | 503 | /* FIXME: Call into SET_ GET_ handlers here */ |
371 | break; | 504 | break; |
372 | 505 | ||
@@ -385,6 +518,12 @@ static void hidp_process_handshake(struct hidp_session *session, | |||
385 | HIDP_TRANS_HANDSHAKE | HIDP_HSHK_ERR_INVALID_PARAMETER, NULL, 0); | 518 | HIDP_TRANS_HANDSHAKE | HIDP_HSHK_ERR_INVALID_PARAMETER, NULL, 0); |
386 | break; | 519 | break; |
387 | } | 520 | } |
521 | |||
522 | /* Wake up the waiting thread. */ | ||
523 | if (test_bit(HIDP_WAITING_FOR_SEND_ACK, &session->flags)) { | ||
524 | clear_bit(HIDP_WAITING_FOR_SEND_ACK, &session->flags); | ||
525 | wake_up_interruptible(&session->report_queue); | ||
526 | } | ||
388 | } | 527 | } |
389 | 528 | ||
390 | static void hidp_process_hid_control(struct hidp_session *session, | 529 | static void hidp_process_hid_control(struct hidp_session *session, |
@@ -397,15 +536,16 @@ static void hidp_process_hid_control(struct hidp_session *session, | |||
397 | skb_queue_purge(&session->ctrl_transmit); | 536 | skb_queue_purge(&session->ctrl_transmit); |
398 | skb_queue_purge(&session->intr_transmit); | 537 | skb_queue_purge(&session->intr_transmit); |
399 | 538 | ||
400 | /* Kill session thread */ | ||
401 | atomic_inc(&session->terminate); | 539 | atomic_inc(&session->terminate); |
402 | hidp_schedule(session); | 540 | wake_up_process(current); |
403 | } | 541 | } |
404 | } | 542 | } |
405 | 543 | ||
406 | static void hidp_process_data(struct hidp_session *session, struct sk_buff *skb, | 544 | /* Returns true if the passed-in skb should be freed by the caller. */ |
545 | static int hidp_process_data(struct hidp_session *session, struct sk_buff *skb, | ||
407 | unsigned char param) | 546 | unsigned char param) |
408 | { | 547 | { |
548 | int done_with_skb = 1; | ||
409 | BT_DBG("session %p skb %p len %d param 0x%02x", session, skb, skb->len, param); | 549 | BT_DBG("session %p skb %p len %d param 0x%02x", session, skb, skb->len, param); |
410 | 550 | ||
411 | switch (param) { | 551 | switch (param) { |
@@ -417,7 +557,6 @@ static void hidp_process_data(struct hidp_session *session, struct sk_buff *skb, | |||
417 | 557 | ||
418 | if (session->hid) | 558 | if (session->hid) |
419 | hid_input_report(session->hid, HID_INPUT_REPORT, skb->data, skb->len, 0); | 559 | hid_input_report(session->hid, HID_INPUT_REPORT, skb->data, skb->len, 0); |
420 | |||
421 | break; | 560 | break; |
422 | 561 | ||
423 | case HIDP_DATA_RTYPE_OTHER: | 562 | case HIDP_DATA_RTYPE_OTHER: |
@@ -429,12 +568,27 @@ static void hidp_process_data(struct hidp_session *session, struct sk_buff *skb, | |||
429 | __hidp_send_ctrl_message(session, | 568 | __hidp_send_ctrl_message(session, |
430 | HIDP_TRANS_HANDSHAKE | HIDP_HSHK_ERR_INVALID_PARAMETER, NULL, 0); | 569 | HIDP_TRANS_HANDSHAKE | HIDP_HSHK_ERR_INVALID_PARAMETER, NULL, 0); |
431 | } | 570 | } |
571 | |||
572 | if (test_bit(HIDP_WAITING_FOR_RETURN, &session->flags) && | ||
573 | param == session->waiting_report_type) { | ||
574 | if (session->waiting_report_number < 0 || | ||
575 | session->waiting_report_number == skb->data[0]) { | ||
576 | /* hidp_get_raw_report() is waiting on this report. */ | ||
577 | session->report_return = skb; | ||
578 | done_with_skb = 0; | ||
579 | clear_bit(HIDP_WAITING_FOR_RETURN, &session->flags); | ||
580 | wake_up_interruptible(&session->report_queue); | ||
581 | } | ||
582 | } | ||
583 | |||
584 | return done_with_skb; | ||
432 | } | 585 | } |
433 | 586 | ||
434 | static void hidp_recv_ctrl_frame(struct hidp_session *session, | 587 | static void hidp_recv_ctrl_frame(struct hidp_session *session, |
435 | struct sk_buff *skb) | 588 | struct sk_buff *skb) |
436 | { | 589 | { |
437 | unsigned char hdr, type, param; | 590 | unsigned char hdr, type, param; |
591 | int free_skb = 1; | ||
438 | 592 | ||
439 | BT_DBG("session %p skb %p len %d", session, skb, skb->len); | 593 | BT_DBG("session %p skb %p len %d", session, skb, skb->len); |
440 | 594 | ||
@@ -454,7 +608,7 @@ static void hidp_recv_ctrl_frame(struct hidp_session *session, | |||
454 | break; | 608 | break; |
455 | 609 | ||
456 | case HIDP_TRANS_DATA: | 610 | case HIDP_TRANS_DATA: |
457 | hidp_process_data(session, skb, param); | 611 | free_skb = hidp_process_data(session, skb, param); |
458 | break; | 612 | break; |
459 | 613 | ||
460 | default: | 614 | default: |
@@ -463,7 +617,8 @@ static void hidp_recv_ctrl_frame(struct hidp_session *session, | |||
463 | break; | 617 | break; |
464 | } | 618 | } |
465 | 619 | ||
466 | kfree_skb(skb); | 620 | if (free_skb) |
621 | kfree_skb(skb); | ||
467 | } | 622 | } |
468 | 623 | ||
469 | static void hidp_recv_intr_frame(struct hidp_session *session, | 624 | static void hidp_recv_intr_frame(struct hidp_session *session, |
@@ -541,32 +696,22 @@ static int hidp_session(void *arg) | |||
541 | struct sock *ctrl_sk = session->ctrl_sock->sk; | 696 | struct sock *ctrl_sk = session->ctrl_sock->sk; |
542 | struct sock *intr_sk = session->intr_sock->sk; | 697 | struct sock *intr_sk = session->intr_sock->sk; |
543 | struct sk_buff *skb; | 698 | struct sk_buff *skb; |
544 | int vendor = 0x0000, product = 0x0000; | ||
545 | wait_queue_t ctrl_wait, intr_wait; | 699 | wait_queue_t ctrl_wait, intr_wait; |
546 | 700 | ||
547 | BT_DBG("session %p", session); | 701 | BT_DBG("session %p", session); |
548 | 702 | ||
549 | if (session->input) { | ||
550 | vendor = session->input->id.vendor; | ||
551 | product = session->input->id.product; | ||
552 | } | ||
553 | |||
554 | if (session->hid) { | ||
555 | vendor = session->hid->vendor; | ||
556 | product = session->hid->product; | ||
557 | } | ||
558 | |||
559 | daemonize("khidpd_%04x%04x", vendor, product); | ||
560 | set_user_nice(current, -15); | 703 | set_user_nice(current, -15); |
561 | 704 | ||
562 | init_waitqueue_entry(&ctrl_wait, current); | 705 | init_waitqueue_entry(&ctrl_wait, current); |
563 | init_waitqueue_entry(&intr_wait, current); | 706 | init_waitqueue_entry(&intr_wait, current); |
564 | add_wait_queue(sk_sleep(ctrl_sk), &ctrl_wait); | 707 | add_wait_queue(sk_sleep(ctrl_sk), &ctrl_wait); |
565 | add_wait_queue(sk_sleep(intr_sk), &intr_wait); | 708 | add_wait_queue(sk_sleep(intr_sk), &intr_wait); |
709 | session->waiting_for_startup = 0; | ||
710 | wake_up_interruptible(&session->startup_queue); | ||
711 | set_current_state(TASK_INTERRUPTIBLE); | ||
566 | while (!atomic_read(&session->terminate)) { | 712 | while (!atomic_read(&session->terminate)) { |
567 | set_current_state(TASK_INTERRUPTIBLE); | 713 | if (ctrl_sk->sk_state != BT_CONNECTED || |
568 | 714 | intr_sk->sk_state != BT_CONNECTED) | |
569 | if (ctrl_sk->sk_state != BT_CONNECTED || intr_sk->sk_state != BT_CONNECTED) | ||
570 | break; | 715 | break; |
571 | 716 | ||
572 | while ((skb = skb_dequeue(&ctrl_sk->sk_receive_queue))) { | 717 | while ((skb = skb_dequeue(&ctrl_sk->sk_receive_queue))) { |
@@ -582,6 +727,7 @@ static int hidp_session(void *arg) | |||
582 | hidp_process_transmit(session); | 727 | hidp_process_transmit(session); |
583 | 728 | ||
584 | schedule(); | 729 | schedule(); |
730 | set_current_state(TASK_INTERRUPTIBLE); | ||
585 | } | 731 | } |
586 | set_current_state(TASK_RUNNING); | 732 | set_current_state(TASK_RUNNING); |
587 | remove_wait_queue(sk_sleep(intr_sk), &intr_wait); | 733 | remove_wait_queue(sk_sleep(intr_sk), &intr_wait); |
@@ -754,11 +900,12 @@ static struct hid_ll_driver hidp_hid_driver = { | |||
754 | .hidinput_input_event = hidp_hidinput_event, | 900 | .hidinput_input_event = hidp_hidinput_event, |
755 | }; | 901 | }; |
756 | 902 | ||
903 | /* This function sets up the hid device. It does not add it | ||
904 | to the HID system. That is done in hidp_add_connection(). */ | ||
757 | static int hidp_setup_hid(struct hidp_session *session, | 905 | static int hidp_setup_hid(struct hidp_session *session, |
758 | struct hidp_connadd_req *req) | 906 | struct hidp_connadd_req *req) |
759 | { | 907 | { |
760 | struct hid_device *hid; | 908 | struct hid_device *hid; |
761 | bdaddr_t src, dst; | ||
762 | int err; | 909 | int err; |
763 | 910 | ||
764 | session->rd_data = kzalloc(req->rd_size, GFP_KERNEL); | 911 | session->rd_data = kzalloc(req->rd_size, GFP_KERNEL); |
@@ -781,9 +928,6 @@ static int hidp_setup_hid(struct hidp_session *session, | |||
781 | 928 | ||
782 | hid->driver_data = session; | 929 | hid->driver_data = session; |
783 | 930 | ||
784 | baswap(&src, &bt_sk(session->ctrl_sock->sk)->src); | ||
785 | baswap(&dst, &bt_sk(session->ctrl_sock->sk)->dst); | ||
786 | |||
787 | hid->bus = BUS_BLUETOOTH; | 931 | hid->bus = BUS_BLUETOOTH; |
788 | hid->vendor = req->vendor; | 932 | hid->vendor = req->vendor; |
789 | hid->product = req->product; | 933 | hid->product = req->product; |
@@ -791,24 +935,17 @@ static int hidp_setup_hid(struct hidp_session *session, | |||
791 | hid->country = req->country; | 935 | hid->country = req->country; |
792 | 936 | ||
793 | strncpy(hid->name, req->name, 128); | 937 | strncpy(hid->name, req->name, 128); |
794 | strncpy(hid->phys, batostr(&src), 64); | 938 | strncpy(hid->phys, batostr(&bt_sk(session->ctrl_sock->sk)->src), 64); |
795 | strncpy(hid->uniq, batostr(&dst), 64); | 939 | strncpy(hid->uniq, batostr(&bt_sk(session->ctrl_sock->sk)->dst), 64); |
796 | 940 | ||
797 | hid->dev.parent = hidp_get_device(session); | 941 | hid->dev.parent = hidp_get_device(session); |
798 | hid->ll_driver = &hidp_hid_driver; | 942 | hid->ll_driver = &hidp_hid_driver; |
799 | 943 | ||
944 | hid->hid_get_raw_report = hidp_get_raw_report; | ||
800 | hid->hid_output_raw_report = hidp_output_raw_report; | 945 | hid->hid_output_raw_report = hidp_output_raw_report; |
801 | 946 | ||
802 | err = hid_add_device(hid); | ||
803 | if (err < 0) | ||
804 | goto failed; | ||
805 | |||
806 | return 0; | 947 | return 0; |
807 | 948 | ||
808 | failed: | ||
809 | hid_destroy_device(hid); | ||
810 | session->hid = NULL; | ||
811 | |||
812 | fault: | 949 | fault: |
813 | kfree(session->rd_data); | 950 | kfree(session->rd_data); |
814 | session->rd_data = NULL; | 951 | session->rd_data = NULL; |
@@ -819,6 +956,7 @@ fault: | |||
819 | int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock, struct socket *intr_sock) | 956 | int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock, struct socket *intr_sock) |
820 | { | 957 | { |
821 | struct hidp_session *session, *s; | 958 | struct hidp_session *session, *s; |
959 | int vendor, product; | ||
822 | int err; | 960 | int err; |
823 | 961 | ||
824 | BT_DBG(""); | 962 | BT_DBG(""); |
@@ -843,8 +981,10 @@ int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock, | |||
843 | 981 | ||
844 | bacpy(&session->bdaddr, &bt_sk(ctrl_sock->sk)->dst); | 982 | bacpy(&session->bdaddr, &bt_sk(ctrl_sock->sk)->dst); |
845 | 983 | ||
846 | session->ctrl_mtu = min_t(uint, l2cap_pi(ctrl_sock->sk)->omtu, l2cap_pi(ctrl_sock->sk)->imtu); | 984 | session->ctrl_mtu = min_t(uint, l2cap_pi(ctrl_sock->sk)->chan->omtu, |
847 | session->intr_mtu = min_t(uint, l2cap_pi(intr_sock->sk)->omtu, l2cap_pi(intr_sock->sk)->imtu); | 985 | l2cap_pi(ctrl_sock->sk)->chan->imtu); |
986 | session->intr_mtu = min_t(uint, l2cap_pi(intr_sock->sk)->chan->omtu, | ||
987 | l2cap_pi(intr_sock->sk)->chan->imtu); | ||
848 | 988 | ||
849 | BT_DBG("ctrl mtu %d intr mtu %d", session->ctrl_mtu, session->intr_mtu); | 989 | BT_DBG("ctrl mtu %d intr mtu %d", session->ctrl_mtu, session->intr_mtu); |
850 | 990 | ||
@@ -857,6 +997,10 @@ int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock, | |||
857 | skb_queue_head_init(&session->ctrl_transmit); | 997 | skb_queue_head_init(&session->ctrl_transmit); |
858 | skb_queue_head_init(&session->intr_transmit); | 998 | skb_queue_head_init(&session->intr_transmit); |
859 | 999 | ||
1000 | mutex_init(&session->report_mutex); | ||
1001 | init_waitqueue_head(&session->report_queue); | ||
1002 | init_waitqueue_head(&session->startup_queue); | ||
1003 | session->waiting_for_startup = 1; | ||
860 | session->flags = req->flags & (1 << HIDP_BLUETOOTH_VENDOR_ID); | 1004 | session->flags = req->flags & (1 << HIDP_BLUETOOTH_VENDOR_ID); |
861 | session->idle_to = req->idle_to; | 1005 | session->idle_to = req->idle_to; |
862 | 1006 | ||
@@ -876,9 +1020,32 @@ int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock, | |||
876 | 1020 | ||
877 | hidp_set_timer(session); | 1021 | hidp_set_timer(session); |
878 | 1022 | ||
879 | err = kernel_thread(hidp_session, session, CLONE_KERNEL); | 1023 | if (session->hid) { |
880 | if (err < 0) | 1024 | vendor = session->hid->vendor; |
1025 | product = session->hid->product; | ||
1026 | } else if (session->input) { | ||
1027 | vendor = session->input->id.vendor; | ||
1028 | product = session->input->id.product; | ||
1029 | } else { | ||
1030 | vendor = 0x0000; | ||
1031 | product = 0x0000; | ||
1032 | } | ||
1033 | |||
1034 | session->task = kthread_run(hidp_session, session, "khidpd_%04x%04x", | ||
1035 | vendor, product); | ||
1036 | if (IS_ERR(session->task)) { | ||
1037 | err = PTR_ERR(session->task); | ||
881 | goto unlink; | 1038 | goto unlink; |
1039 | } | ||
1040 | |||
1041 | while (session->waiting_for_startup) { | ||
1042 | wait_event_interruptible(session->startup_queue, | ||
1043 | !session->waiting_for_startup); | ||
1044 | } | ||
1045 | |||
1046 | err = hid_add_device(session->hid); | ||
1047 | if (err < 0) | ||
1048 | goto err_add_device; | ||
882 | 1049 | ||
883 | if (session->input) { | 1050 | if (session->input) { |
884 | hidp_send_ctrl_message(session, | 1051 | hidp_send_ctrl_message(session, |
@@ -892,6 +1059,12 @@ int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock, | |||
892 | up_write(&hidp_session_sem); | 1059 | up_write(&hidp_session_sem); |
893 | return 0; | 1060 | return 0; |
894 | 1061 | ||
1062 | err_add_device: | ||
1063 | hid_destroy_device(session->hid); | ||
1064 | session->hid = NULL; | ||
1065 | atomic_inc(&session->terminate); | ||
1066 | wake_up_process(session->task); | ||
1067 | |||
895 | unlink: | 1068 | unlink: |
896 | hidp_del_timer(session); | 1069 | hidp_del_timer(session); |
897 | 1070 | ||
@@ -941,13 +1114,8 @@ int hidp_del_connection(struct hidp_conndel_req *req) | |||
941 | skb_queue_purge(&session->ctrl_transmit); | 1114 | skb_queue_purge(&session->ctrl_transmit); |
942 | skb_queue_purge(&session->intr_transmit); | 1115 | skb_queue_purge(&session->intr_transmit); |
943 | 1116 | ||
944 | /* Wakeup user-space polling for socket errors */ | ||
945 | session->intr_sock->sk->sk_err = EUNATCH; | ||
946 | session->ctrl_sock->sk->sk_err = EUNATCH; | ||
947 | |||
948 | /* Kill session thread */ | ||
949 | atomic_inc(&session->terminate); | 1117 | atomic_inc(&session->terminate); |
950 | hidp_schedule(session); | 1118 | wake_up_process(session->task); |
951 | } | 1119 | } |
952 | } else | 1120 | } else |
953 | err = -ENOENT; | 1121 | err = -ENOENT; |
@@ -1020,8 +1188,6 @@ static int __init hidp_init(void) | |||
1020 | { | 1188 | { |
1021 | int ret; | 1189 | int ret; |
1022 | 1190 | ||
1023 | l2cap_load(); | ||
1024 | |||
1025 | BT_INFO("HIDP (Human Interface Emulation) ver %s", VERSION); | 1191 | BT_INFO("HIDP (Human Interface Emulation) ver %s", VERSION); |
1026 | 1192 | ||
1027 | ret = hid_register_driver(&hidp_driver); | 1193 | ret = hid_register_driver(&hidp_driver); |
diff --git a/net/bluetooth/hidp/hidp.h b/net/bluetooth/hidp/hidp.h index 8d934a19da0a..af1bcc823f26 100644 --- a/net/bluetooth/hidp/hidp.h +++ b/net/bluetooth/hidp/hidp.h | |||
@@ -80,10 +80,12 @@ | |||
80 | #define HIDP_VIRTUAL_CABLE_UNPLUG 0 | 80 | #define HIDP_VIRTUAL_CABLE_UNPLUG 0 |
81 | #define HIDP_BOOT_PROTOCOL_MODE 1 | 81 | #define HIDP_BOOT_PROTOCOL_MODE 1 |
82 | #define HIDP_BLUETOOTH_VENDOR_ID 9 | 82 | #define HIDP_BLUETOOTH_VENDOR_ID 9 |
83 | #define HIDP_WAITING_FOR_RETURN 10 | ||
84 | #define HIDP_WAITING_FOR_SEND_ACK 11 | ||
83 | 85 | ||
84 | struct hidp_connadd_req { | 86 | struct hidp_connadd_req { |
85 | int ctrl_sock; // Connected control socket | 87 | int ctrl_sock; /* Connected control socket */ |
86 | int intr_sock; // Connteted interrupt socket | 88 | int intr_sock; /* Connected interrupt socket */ |
87 | __u16 parser; | 89 | __u16 parser; |
88 | __u16 rd_size; | 90 | __u16 rd_size; |
89 | __u8 __user *rd_data; | 91 | __u8 __user *rd_data; |
@@ -141,6 +143,7 @@ struct hidp_session { | |||
141 | uint intr_mtu; | 143 | uint intr_mtu; |
142 | 144 | ||
143 | atomic_t terminate; | 145 | atomic_t terminate; |
146 | struct task_struct *task; | ||
144 | 147 | ||
145 | unsigned char keys[8]; | 148 | unsigned char keys[8]; |
146 | unsigned char leds; | 149 | unsigned char leds; |
@@ -154,9 +157,22 @@ struct hidp_session { | |||
154 | struct sk_buff_head ctrl_transmit; | 157 | struct sk_buff_head ctrl_transmit; |
155 | struct sk_buff_head intr_transmit; | 158 | struct sk_buff_head intr_transmit; |
156 | 159 | ||
160 | /* Used in hidp_get_raw_report() */ | ||
161 | int waiting_report_type; /* HIDP_DATA_RTYPE_* */ | ||
162 | int waiting_report_number; /* -1 for not numbered */ | ||
163 | struct mutex report_mutex; | ||
164 | struct sk_buff *report_return; | ||
165 | wait_queue_head_t report_queue; | ||
166 | |||
167 | /* Used in hidp_output_raw_report() */ | ||
168 | int output_report_success; /* boolean */ | ||
169 | |||
157 | /* Report descriptor */ | 170 | /* Report descriptor */ |
158 | __u8 *rd_data; | 171 | __u8 *rd_data; |
159 | uint rd_size; | 172 | uint rd_size; |
173 | |||
174 | wait_queue_head_t startup_queue; | ||
175 | int waiting_for_startup; | ||
160 | }; | 176 | }; |
161 | 177 | ||
162 | static inline void hidp_schedule(struct hidp_session *session) | 178 | static inline void hidp_schedule(struct hidp_session *session) |
diff --git a/net/bluetooth/hidp/sock.c b/net/bluetooth/hidp/sock.c index 250dfd46237d..178ac7f127ad 100644 --- a/net/bluetooth/hidp/sock.c +++ b/net/bluetooth/hidp/sock.c | |||
@@ -85,7 +85,8 @@ static int hidp_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long | |||
85 | return err; | 85 | return err; |
86 | } | 86 | } |
87 | 87 | ||
88 | if (csock->sk->sk_state != BT_CONNECTED || isock->sk->sk_state != BT_CONNECTED) { | 88 | if (csock->sk->sk_state != BT_CONNECTED || |
89 | isock->sk->sk_state != BT_CONNECTED) { | ||
89 | sockfd_put(csock); | 90 | sockfd_put(csock); |
90 | sockfd_put(isock); | 91 | sockfd_put(isock); |
91 | return -EBADFD; | 92 | return -EBADFD; |
@@ -140,8 +141,8 @@ static int hidp_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long | |||
140 | 141 | ||
141 | #ifdef CONFIG_COMPAT | 142 | #ifdef CONFIG_COMPAT |
142 | struct compat_hidp_connadd_req { | 143 | struct compat_hidp_connadd_req { |
143 | int ctrl_sock; // Connected control socket | 144 | int ctrl_sock; /* Connected control socket */ |
144 | int intr_sock; // Connteted interrupt socket | 145 | int intr_sock; /* Connected interrupt socket */ |
145 | __u16 parser; | 146 | __u16 parser; |
146 | __u16 rd_size; | 147 | __u16 rd_size; |
147 | compat_uptr_t rd_data; | 148 | compat_uptr_t rd_data; |