Exemplo n.º 1
0
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;
}
Exemplo n.º 2
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;
}