|
@@ -155,6 +155,9 @@ static void wdm_out_callback(struct urb *urb)
|
|
|
wake_up(&desc->wait);
|
|
|
}
|
|
|
|
|
|
+/* forward declaration */
|
|
|
+static int service_outstanding_interrupt(struct wdm_device *desc);
|
|
|
+
|
|
|
static void wdm_in_callback(struct urb *urb)
|
|
|
{
|
|
|
struct wdm_device *desc = urb->context;
|
|
@@ -189,7 +192,13 @@ static void wdm_in_callback(struct urb *urb)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- desc->rerr = status;
|
|
|
+ /*
|
|
|
+ * only set a new error if there is no previous error.
|
|
|
+ * Errors are only cleared during read/open
|
|
|
+ */
|
|
|
+ if (desc->rerr == 0)
|
|
|
+ desc->rerr = status;
|
|
|
+
|
|
|
if (length + desc->length > desc->wMaxCommand) {
|
|
|
/* The buffer would overflow */
|
|
|
set_bit(WDM_OVERFLOW, &desc->flags);
|
|
@@ -221,9 +230,19 @@ static void wdm_in_callback(struct urb *urb)
|
|
|
}
|
|
|
|
|
|
skip_error:
|
|
|
+ set_bit(WDM_READ, &desc->flags);
|
|
|
wake_up(&desc->wait);
|
|
|
|
|
|
- set_bit(WDM_READ, &desc->flags);
|
|
|
+ if (desc->rerr) {
|
|
|
+ /*
|
|
|
+ * Since there was an error, userspace may decide to not read
|
|
|
+ * any data after poll'ing.
|
|
|
+ * We should respond to further attempts from the device to send
|
|
|
+ * data, so that we can get unstuck.
|
|
|
+ */
|
|
|
+ service_outstanding_interrupt(desc);
|
|
|
+ }
|
|
|
+
|
|
|
unlock:
|
|
|
spin_unlock(&desc->iuspin);
|
|
|
}
|
|
@@ -457,17 +476,14 @@ out_free_mem:
|
|
|
}
|
|
|
|
|
|
/*
|
|
|
- * clear WDM_READ flag and possibly submit the read urb if resp_count
|
|
|
- * is non-zero.
|
|
|
+ * Submit the read urb if resp_count is non-zero.
|
|
|
*
|
|
|
* Called with desc->iuspin locked
|
|
|
*/
|
|
|
-static int clear_wdm_read_flag(struct wdm_device *desc)
|
|
|
+static int service_outstanding_interrupt(struct wdm_device *desc)
|
|
|
{
|
|
|
int rv = 0;
|
|
|
|
|
|
- clear_bit(WDM_READ, &desc->flags);
|
|
|
-
|
|
|
/* submit read urb only if the device is waiting for it */
|
|
|
if (!desc->resp_count || !--desc->resp_count)
|
|
|
goto out;
|
|
@@ -559,7 +575,8 @@ retry:
|
|
|
|
|
|
if (!desc->reslength) { /* zero length read */
|
|
|
dev_dbg(&desc->intf->dev, "%s: zero length - clearing WDM_READ\n", __func__);
|
|
|
- rv = clear_wdm_read_flag(desc);
|
|
|
+ clear_bit(WDM_READ, &desc->flags);
|
|
|
+ rv = service_outstanding_interrupt(desc);
|
|
|
spin_unlock_irq(&desc->iuspin);
|
|
|
if (rv < 0)
|
|
|
goto err;
|
|
@@ -584,8 +601,10 @@ retry:
|
|
|
|
|
|
desc->length -= cntr;
|
|
|
/* in case we had outstanding data */
|
|
|
- if (!desc->length)
|
|
|
- clear_wdm_read_flag(desc);
|
|
|
+ if (!desc->length) {
|
|
|
+ clear_bit(WDM_READ, &desc->flags);
|
|
|
+ service_outstanding_interrupt(desc);
|
|
|
+ }
|
|
|
spin_unlock_irq(&desc->iuspin);
|
|
|
rv = cntr;
|
|
|
|