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;
}
}
- 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);
}
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);
}
}
/*
- * 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;
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;
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;