aboutsummaryrefslogtreecommitdiffstats
path: root/net/bluetooth/hidp
diff options
context:
space:
mode:
authorDavid Herrmann <dh.herrmann@googlemail.com>2011-08-26 08:06:02 -0400
committerGustavo F. Padovan <padovan@profusion.mobi>2011-10-06 21:15:48 -0400
commit794d175698f0e78be7f2e3f4bdbe0e7cd3f2d6ae (patch)
treee96dcec6fc0ee32252ef51214348fa0066b1f637 /net/bluetooth/hidp
parenta5fd6f300433ef7458c6d934f81f47ebd7c7e805 (diff)
Bluetooth: hidp: Stop I/O on shutdown
Current hidp driver purges the in/out queue on HID shutdown, but does not prevent further I/O. If a driver uses hidp_output_raw_report or hidp_get_raw_report during shutdown, the driver hangs for 5 or 10 seconds per call until it gets a timeout. That is, if the output queue of an HID driver has 10 messages pending, it will take 50s until hid_destroy_device() will return. The hidp_session_sem semaphore is held during shutdown so no other HID device may be added/removed during this time. This patch makes hidp_output_raw_report and hidp_get_raw_report fail if session->terminate is true. Also hidp_session will wakeup all current calls to these functions to cancel the current operations. We already purge the current I/O queues on hidp_stop(), so this data loss does not change the behaviour of the HID drivers. Signed-off-by: David Herrmann <dh.herrmann@googlemail.com> Signed-off-by: Gustavo F. Padovan <padovan@profusion.mobi>
Diffstat (limited to 'net/bluetooth/hidp')
-rw-r--r--net/bluetooth/hidp/core.c34
1 files changed, 20 insertions, 14 deletions
diff --git a/net/bluetooth/hidp/core.c b/net/bluetooth/hidp/core.c
index 075a3e920ca..d7bae2be83b 100644
--- a/net/bluetooth/hidp/core.c
+++ b/net/bluetooth/hidp/core.c
@@ -255,6 +255,9 @@ static int __hidp_send_ctrl_message(struct hidp_session *session,
255 255
256 BT_DBG("session %p data %p size %d", session, data, size); 256 BT_DBG("session %p data %p size %d", session, data, size);
257 257
258 if (atomic_read(&session->terminate))
259 return -EIO;
260
258 skb = alloc_skb(size + 1, GFP_ATOMIC); 261 skb = alloc_skb(size + 1, GFP_ATOMIC);
259 if (!skb) { 262 if (!skb) {
260 BT_ERR("Can't allocate memory for new frame"); 263 BT_ERR("Can't allocate memory for new frame");
@@ -329,6 +332,7 @@ static int hidp_get_raw_report(struct hid_device *hid,
329 struct sk_buff *skb; 332 struct sk_buff *skb;
330 size_t len; 333 size_t len;
331 int numbered_reports = hid->report_enum[report_type].numbered; 334 int numbered_reports = hid->report_enum[report_type].numbered;
335 int ret;
332 336
333 switch (report_type) { 337 switch (report_type) {
334 case HID_FEATURE_REPORT: 338 case HID_FEATURE_REPORT:
@@ -352,8 +356,9 @@ static int hidp_get_raw_report(struct hid_device *hid,
352 session->waiting_report_number = numbered_reports ? report_number : -1; 356 session->waiting_report_number = numbered_reports ? report_number : -1;
353 set_bit(HIDP_WAITING_FOR_RETURN, &session->flags); 357 set_bit(HIDP_WAITING_FOR_RETURN, &session->flags);
354 data[0] = report_number; 358 data[0] = report_number;
355 if (hidp_send_ctrl_message(hid->driver_data, report_type, data, 1)) 359 ret = hidp_send_ctrl_message(hid->driver_data, report_type, data, 1);
356 goto err_eio; 360 if (ret)
361 goto err;
357 362
358 /* Wait for the return of the report. The returned report 363 /* Wait for the return of the report. The returned report
359 gets put in session->report_return. */ 364 gets put in session->report_return. */
@@ -365,11 +370,13 @@ static int hidp_get_raw_report(struct hid_device *hid,
365 5*HZ); 370 5*HZ);
366 if (res == 0) { 371 if (res == 0) {
367 /* timeout */ 372 /* timeout */
368 goto err_eio; 373 ret = -EIO;
374 goto err;
369 } 375 }
370 if (res < 0) { 376 if (res < 0) {
371 /* signal */ 377 /* signal */
372 goto err_restartsys; 378 ret = -ERESTARTSYS;
379 goto err;
373 } 380 }
374 } 381 }
375 382
@@ -390,14 +397,10 @@ static int hidp_get_raw_report(struct hid_device *hid,
390 397
391 return len; 398 return len;
392 399
393err_restartsys: 400err:
394 clear_bit(HIDP_WAITING_FOR_RETURN, &session->flags);
395 mutex_unlock(&session->report_mutex);
396 return -ERESTARTSYS;
397err_eio:
398 clear_bit(HIDP_WAITING_FOR_RETURN, &session->flags); 401 clear_bit(HIDP_WAITING_FOR_RETURN, &session->flags);
399 mutex_unlock(&session->report_mutex); 402 mutex_unlock(&session->report_mutex);
400 return -EIO; 403 return ret;
401} 404}
402 405
403static int hidp_output_raw_report(struct hid_device *hid, unsigned char *data, size_t count, 406static int hidp_output_raw_report(struct hid_device *hid, unsigned char *data, size_t count,
@@ -422,11 +425,10 @@ static int hidp_output_raw_report(struct hid_device *hid, unsigned char *data, s
422 425
423 /* Set up our wait, and send the report request to the device. */ 426 /* Set up our wait, and send the report request to the device. */
424 set_bit(HIDP_WAITING_FOR_SEND_ACK, &session->flags); 427 set_bit(HIDP_WAITING_FOR_SEND_ACK, &session->flags);
425 if (hidp_send_ctrl_message(hid->driver_data, report_type, 428 ret = hidp_send_ctrl_message(hid->driver_data, report_type, data,
426 data, count)) { 429 count);
427 ret = -ENOMEM; 430 if (ret)
428 goto err; 431 goto err;
429 }
430 432
431 /* Wait for the ACK from the device. */ 433 /* Wait for the ACK from the device. */
432 while (test_bit(HIDP_WAITING_FOR_SEND_ACK, &session->flags)) { 434 while (test_bit(HIDP_WAITING_FOR_SEND_ACK, &session->flags)) {
@@ -739,6 +741,10 @@ static int hidp_session(void *arg)
739 remove_wait_queue(sk_sleep(intr_sk), &intr_wait); 741 remove_wait_queue(sk_sleep(intr_sk), &intr_wait);
740 remove_wait_queue(sk_sleep(ctrl_sk), &ctrl_wait); 742 remove_wait_queue(sk_sleep(ctrl_sk), &ctrl_wait);
741 743
744 clear_bit(HIDP_WAITING_FOR_SEND_ACK, &session->flags);
745 clear_bit(HIDP_WAITING_FOR_RETURN, &session->flags);
746 wake_up_interruptible(&session->report_queue);
747
742 down_write(&hidp_session_sem); 748 down_write(&hidp_session_sem);
743 749
744 hidp_del_timer(session); 750 hidp_del_timer(session);