static int hci_unlink_urb (urb_t * urb) { hci_t * hci; if (!urb) /* just to be sure */ return -EINVAL; if (!urb->dev || !urb->dev->bus) return -ENODEV; hci = (hci_t *) urb->dev->bus->hcpriv; /* a request to the virtual root hub */ if (usb_pipedevice (urb->pipe) == hci->rh.devnum) { return rh_unlink_urb (urb); } if (!list_empty (&urb->urb_list)) { /* URB active? */ unsigned long flags; spin_lock_irqsave (&hci->urb_list_lock, flags); if (SetCancel(hci,urb)) { //not in active DMA chain list_del (&urb->urb_list); //remove from probable endpoint queue list_add (&urb->urb_list, &hci->return_list); } spin_unlock_irqrestore (&hci->urb_list_lock, flags); if (!(urb->transfer_flags & (USB_ASYNC_UNLINK | USB_TIMEOUT_KILLED)) ) { /* synchron without callback */ WaitForIdle(hci, urb); } } else { /* hcd does not own URB but we keep the driver happy anyway */ if (urb->complete && (urb->transfer_flags & USB_ASYNC_UNLINK)) { // unsigned long flags; urb->status = -ENOENT; urb->actual_length = 0; // spin_lock_irqsave (&hci->urb_list_lock, flags); urb->complete (urb); // spin_unlock_irqrestore (&hci->urb_list_lock, flags); urb->status = 0; } else { urb->status = -ENOENT; } } return 0; }
static int hci_unlink_urb (struct urb * urb) { unsigned long flags; hci_t * hci; DECLARE_WAITQUEUE (wait, current); void * comp = NULL; if (!urb) /* just to be sure */ return -EINVAL; if (!urb->dev || !urb->dev->bus) return -ENODEV; hci = (hci_t *) urb->dev->bus->hcpriv; /* a request to the virtual root hub */ if (usb_pipedevice (urb->pipe) == hci->rh.devnum) { return rh_unlink_urb (urb); } if (urb_debug) urb_print (urb, "UNLINK", 1); spin_lock_irqsave (&usb_urb_lock, flags); /* HACK: It seems the HID driver sometimes tries to unlink * URBs which have never been submitted - and hence whose * urb_list field has never been initialized. This causes * crashes on unplug */ if ( (urb->urb_list.prev && urb->urb_list.next) && !list_empty (&urb->urb_list)) { /* URB active? */ if (urb->transfer_flags & (USB_ASYNC_UNLINK | USB_TIMEOUT_KILLED)) { /* asynchron with callback */ list_del (&urb->urb_list); /* relink the urb to the del list */ list_add (&urb->urb_list, &hci->del_list); comp = urb->complete; urb->complete = NULL; spin_unlock_irqrestore (&usb_urb_lock, flags); } else { /* synchron without callback */ add_wait_queue (&hci->waitq, &wait); set_current_state (TASK_UNINTERRUPTIBLE); list_del (&urb->urb_list); /* relink the urb to the del list */ list_add (&urb->urb_list, &hci->del_list); spin_unlock_irqrestore (&usb_urb_lock, flags); schedule_timeout(HZ/50); if (!list_empty (&urb->urb_list)) list_del (&urb->urb_list); urb->complete = comp; urb->hcpriv = NULL; remove_wait_queue (&hci->waitq, &wait); } } else { /* hcd does not own URB but we keep the driver happy anyway */ spin_unlock_irqrestore (&usb_urb_lock, flags); if (urb->complete && (urb->transfer_flags & USB_ASYNC_UNLINK)) { urb->status = -ENOENT; urb->actual_length = 0; urb->complete (urb); urb->status = 0; } else { urb->status = -ENOENT; } } return 0; }