Ok, I took some time to implement a test fix. Again, I may have
overlooked something, so please tell me if it looks ok (I didn't yet have
a chance to test this code).
here's the fixed function (you also need to add the prototype to
dl_del_list() somewhere before it). If you feel it's ok and if the driver
still works on my boxes (I'll test tonight), then I'll submit a patch.
static int sohci_unlink_urb (urb_t * urb)
{
unsigned long flags;
ohci_t * ohci;
DECLARE_WAITQUEUE (wait, current);
if (!urb) /* just to be sure */
return -EINVAL;
if (!urb->dev || !urb->dev->bus)
return -ENODEV;
ohci = (ohci_t *) urb->dev->bus->hcpriv;
#ifdef DEBUG
urb_print (urb, "UNLINK", 1);
#endif
if (usb_pipedevice (urb->pipe) == ohci->rh.devnum) {
usb_dec_dev_use(urb->dev);
return rh_unlink_urb (urb); /* a request to the virtual root hub */
}
if (urb->hcpriv) {
/* URB active? */
if (urb->status == USB_ST_URB_PENDING && !ohci->disabled) {
urb_priv_t * urb_priv = urb->hcpriv;
urb_priv->state = URB_DEL;
/* we want to delete the TDs of an URB from an ed
* request the deletion, it will be handled at the
* next USB-frame */
spin_lock_irqsave (&usb_ed_lock, flags);
ep_rm_ed (urb->dev, urb_priv->ed);
urb_priv->ed->state |= ED_URB_DEL;
spin_unlock_irqrestore (&usb_ed_lock, flags);
if (!(urb->transfer_flags & USB_ASYNC_UNLINK)) {
if (in_interrupt()) {
volatile u16* frame_p = (volatile
u16*)&ohci->hcca.frame_no;
u16 frame_prev, frame, count;
count = 0;
writel (OHCI_INTR_SF,
&ohci->regs->intrdisable);
frame_prev = le16_to_cpu(*frame_p) & 1;
do {
mb();
frame = le16_to_cpu(*frame_p) & 1;
if (frame != frame_prev) {
if (ohci->ed_rm_list[!frame]
!= NULL)
dl_del_list (ohci,
!frame);
frame_prev = frame;
count++;
}
} while(count < 2);
writel (OHCI_INTR_SF, &ohci->regs->intrenable);
} else {
add_wait_queue (&op_wakeup, &wait);
current->state = TASK_UNINTERRUPTIBLE;
if (!schedule_timeout (HZ / 10)) /* wait until
all TDs are deleted */
err("unlink URB timeout!");
remove_wait_queue (&op_wakeup, &wait);
urb->status = -ENOENT;
usb_dec_dev_use (urb->dev);
}
} else {
/* usb_dec_dev_use done in dl_del_list() */
urb->status = -EINPROGRESS;
}
} else {
usb_dec_dev_use (urb->dev);
urb_rm_priv (urb);
if (urb->complete && (urb->transfer_flags & USB_ASYNC_UNLINK))
{
urb->complete (urb);
urb->status = 0;
} else
urb->status = -ENOENT;
}
}
return 0;
}
---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]