aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorAlan Ott <alan@signal11.us>2011-01-18 03:04:38 -0500
committerJiri Kosina <jkosina@suse.cz>2011-02-11 09:05:49 -0500
commit0825411ade21a39ac63b3e011d092b1f95b5f3f5 (patch)
treec69a0088e46c93ef1a0916030af3e02c4cce04e9 /net
parent0f69dca20f77dc374b67e17e10b30cec37e778c4 (diff)
HID: bt: Wait for ACK on Sent Reports
Wait for an ACK from the device before returning from hidp_output_raw_report(). This way, failures can be returned to the user application. Also, it prevents ACK/NAK packets from an output packet from being confused with ACK/NAK packets from an input request packet. Signed-off-by: Alan Ott <alan@signal11.us> Acked-by: Gustavo F. Padovan <padovan@profusion.mobi> Signed-off-by: Jiri Kosina <jkosina@suse.cz>
Diffstat (limited to 'net')
-rw-r--r--net/bluetooth/hidp/core.c54
-rw-r--r--net/bluetooth/hidp/hidp.h4
2 files changed, 55 insertions, 3 deletions
diff --git a/net/bluetooth/hidp/core.c b/net/bluetooth/hidp/core.c
index 67cc4bc82c68..5383e6c7d09d 100644
--- a/net/bluetooth/hidp/core.c
+++ b/net/bluetooth/hidp/core.c
@@ -316,6 +316,9 @@ static int hidp_send_report(struct hidp_session *session, struct hid_report *rep
316static int hidp_output_raw_report(struct hid_device *hid, unsigned char *data, size_t count, 316static int hidp_output_raw_report(struct hid_device *hid, unsigned char *data, size_t count,
317 unsigned char report_type) 317 unsigned char report_type)
318{ 318{
319 struct hidp_session *session = hid->driver_data;
320 int ret;
321
319 switch (report_type) { 322 switch (report_type) {
320 case HID_FEATURE_REPORT: 323 case HID_FEATURE_REPORT:
321 report_type = HIDP_TRANS_SET_REPORT | HIDP_DATA_RTYPE_FEATURE; 324 report_type = HIDP_TRANS_SET_REPORT | HIDP_DATA_RTYPE_FEATURE;
@@ -327,10 +330,47 @@ static int hidp_output_raw_report(struct hid_device *hid, unsigned char *data, s
327 return -EINVAL; 330 return -EINVAL;
328 } 331 }
329 332
333 if (mutex_lock_interruptible(&session->report_mutex))
334 return -ERESTARTSYS;
335
336 /* Set up our wait, and send the report request to the device. */
337 set_bit(HIDP_WAITING_FOR_SEND_ACK, &session->flags);
330 if (hidp_send_ctrl_message(hid->driver_data, report_type, 338 if (hidp_send_ctrl_message(hid->driver_data, report_type,
331 data, count)) 339 data, count)) {
332 return -ENOMEM; 340 ret = -ENOMEM;
333 return count; 341 goto err;
342 }
343
344 /* Wait for the ACK from the device. */
345 while (test_bit(HIDP_WAITING_FOR_SEND_ACK, &session->flags)) {
346 int res;
347
348 res = wait_event_interruptible_timeout(session->report_queue,
349 !test_bit(HIDP_WAITING_FOR_SEND_ACK, &session->flags),
350 10*HZ);
351 if (res == 0) {
352 /* timeout */
353 ret = -EIO;
354 goto err;
355 }
356 if (res < 0) {
357 /* signal */
358 ret = -ERESTARTSYS;
359 goto err;
360 }
361 }
362
363 if (!session->output_report_success) {
364 ret = -EIO;
365 goto err;
366 }
367
368 ret = count;
369
370err:
371 clear_bit(HIDP_WAITING_FOR_SEND_ACK, &session->flags);
372 mutex_unlock(&session->report_mutex);
373 return ret;
334} 374}
335 375
336static void hidp_idle_timeout(unsigned long arg) 376static void hidp_idle_timeout(unsigned long arg)
@@ -357,10 +397,12 @@ static void hidp_process_handshake(struct hidp_session *session,
357 unsigned char param) 397 unsigned char param)
358{ 398{
359 BT_DBG("session %p param 0x%02x", session, param); 399 BT_DBG("session %p param 0x%02x", session, param);
400 session->output_report_success = 0; /* default condition */
360 401
361 switch (param) { 402 switch (param) {
362 case HIDP_HSHK_SUCCESSFUL: 403 case HIDP_HSHK_SUCCESSFUL:
363 /* FIXME: Call into SET_ GET_ handlers here */ 404 /* FIXME: Call into SET_ GET_ handlers here */
405 session->output_report_success = 1;
364 break; 406 break;
365 407
366 case HIDP_HSHK_NOT_READY: 408 case HIDP_HSHK_NOT_READY:
@@ -385,6 +427,12 @@ static void hidp_process_handshake(struct hidp_session *session,
385 HIDP_TRANS_HANDSHAKE | HIDP_HSHK_ERR_INVALID_PARAMETER, NULL, 0); 427 HIDP_TRANS_HANDSHAKE | HIDP_HSHK_ERR_INVALID_PARAMETER, NULL, 0);
386 break; 428 break;
387 } 429 }
430
431 /* Wake up the waiting thread. */
432 if (test_bit(HIDP_WAITING_FOR_SEND_ACK, &session->flags)) {
433 clear_bit(HIDP_WAITING_FOR_SEND_ACK, &session->flags);
434 wake_up_interruptible(&session->report_queue);
435 }
388} 436}
389 437
390static void hidp_process_hid_control(struct hidp_session *session, 438static void hidp_process_hid_control(struct hidp_session *session,
diff --git a/net/bluetooth/hidp/hidp.h b/net/bluetooth/hidp/hidp.h
index 2cc35dc8fa03..92e093e61f27 100644
--- a/net/bluetooth/hidp/hidp.h
+++ b/net/bluetooth/hidp/hidp.h
@@ -80,6 +80,7 @@
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_SEND_ACK 11
83 84
84struct hidp_connadd_req { 85struct hidp_connadd_req {
85 int ctrl_sock; // Connected control socket 86 int ctrl_sock; // Connected control socket
@@ -154,6 +155,9 @@ struct hidp_session {
154 struct sk_buff_head ctrl_transmit; 155 struct sk_buff_head ctrl_transmit;
155 struct sk_buff_head intr_transmit; 156 struct sk_buff_head intr_transmit;
156 157
158 /* Used in hidp_output_raw_report() */
159 int output_report_success; /* boolean */
160
157 /* Report descriptor */ 161 /* Report descriptor */
158 __u8 *rd_data; 162 __u8 *rd_data;
159 uint rd_size; 163 uint rd_size;