/*
* Now that the ASL is updated, complete the removal of any
* removed qsets.
+ *
+ * If the qset was to be reset, do so and reinsert it into the
+ * ASL if it has pending transfers.
*/
spin_lock_irq(&whc->lock);
list_for_each_entry_safe(qset, t, &whc->async_removed_list, list_node) {
qset_remove_complete(whc, qset);
+ if (qset->reset) {
+ qset_reset(whc, qset);
+ if (!list_empty(&qset->stds)) {
+ asl_qset_insert_begin(whc, qset);
+ queue_work(whc->workqueue, &whc->async_work);
+ }
+ }
}
spin_unlock_irq(&whc->lock);
else
err = qset_add_urb(whc, qset, urb, GFP_ATOMIC);
if (!err) {
- if (!qset->in_sw_list)
+ if (!qset->in_sw_list && !qset->remove)
asl_qset_insert_begin(whc, qset);
} else
usb_hcd_unlink_urb_from_ep(&whc->wusbhc.usb_hcd, urb);
struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd);
struct whc *whc = wusbhc_to_whc(wusbhc);
struct whc_qset *qset;
+ unsigned long flags;
+
+ spin_lock_irqsave(&whc->lock, flags);
qset = ep->hcpriv;
if (qset) {
qset->remove = 1;
+ qset->reset = 1;
if (usb_endpoint_xfer_bulk(&ep->desc)
|| usb_endpoint_xfer_control(&ep->desc))
queue_work(whc->workqueue, &whc->async_work);
else
queue_work(whc->workqueue, &whc->periodic_work);
-
- qset_reset(whc, qset);
}
+
+ spin_unlock_irqrestore(&whc->lock, flags);
}
/*
* Now that the PZL is updated, complete the removal of any
* removed qsets.
+ *
+ * If the qset was to be reset, do so and reinsert it into the
+ * PZL if it has pending transfers.
*/
spin_lock_irq(&whc->lock);
list_for_each_entry_safe(qset, t, &whc->periodic_removed_list, list_node) {
qset_remove_complete(whc, qset);
+ if (qset->reset) {
+ qset_reset(whc, qset);
+ if (!list_empty(&qset->stds)) {
+ qset_insert_in_sw_list(whc, qset);
+ queue_work(whc->workqueue, &whc->periodic_work);
+ }
+ }
}
spin_unlock_irq(&whc->lock);
else
err = qset_add_urb(whc, qset, urb, GFP_ATOMIC);
if (!err) {
- if (!qset->in_sw_list)
+ if (!qset->in_sw_list && !qset->remove)
qset_insert_in_sw_list(whc, qset);
} else
usb_hcd_unlink_urb_from_ep(&whc->wusbhc.usb_hcd, urb);
void qset_clear(struct whc *whc, struct whc_qset *qset)
{
qset->td_start = qset->td_end = qset->ntds = 0;
- qset->remove = 0;
qset->qh.link = cpu_to_le32(QH_LINK_NTDS(8) | QH_LINK_T);
qset->qh.status = qset->qh.status & QH_STATUS_SEQ_MASK;
*/
void qset_reset(struct whc *whc, struct whc_qset *qset)
{
- wait_for_completion(&qset->remove_complete);
+ qset->reset = 0;
qset->qh.status &= ~QH_STATUS_SEQ_MASK;
qset->qh.cur_window = cpu_to_le32((1 << qset->max_burst) - 1);
void qset_remove_complete(struct whc *whc, struct whc_qset *qset)
{
+ qset->remove = 0;
list_del_init(&qset->list_node);
complete(&qset->remove_complete);
}
unsigned in_sw_list:1;
unsigned in_hw_list:1;
unsigned remove:1;
+ unsigned reset:1;
struct urb *pause_after_urb;
struct completion remove_complete;
int max_burst;