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]

Reply via email to