Example #1
0
static int hci_submit_urb (struct urb * urb)
{
	hci_t * hci;
	unsigned int pipe = urb->pipe;
	unsigned long flags;
	int ret;

	if (!urb->dev || !urb->dev->bus || urb->hcpriv) 
		return -EINVAL;

	if (usb_endpoint_halted (urb->dev, 
				usb_pipeendpoint (pipe), usb_pipeout (pipe))) 
		return -EPIPE;
	
	hci = (hci_t *) urb->dev->bus->hcpriv;
	
	/* a request to the virtual root hub */
	if (usb_pipedevice (pipe) == hci->rh.devnum) {
		return rh_submit_urb (urb);	
	}

	if (urb_debug)
		urb_print (urb, "SUB", usb_pipein (pipe));

	/* queue the URB to its endpoint-queue */
	 
	spin_lock_irqsave (&usb_urb_lock, flags);	
	ret = hcs_urb_queue (hci, urb);
	spin_unlock_irqrestore (&usb_urb_lock, flags);

	return ret;

}
Example #2
0
/***************************************************************************
 * Function Name : rh_int_timer_do
 * 
 * This function is called when the timer expires.  It gets the the port 
 * change data and pass along to the upper protocol.
 * 
 * Note:  The virtual root hub interrupt pipe are polled by the timer
 *        every "interval" ms
 *
 * Input:  ptr = ptr to the urb
 *
 * Return: none  
 **************************************************************************/
static void rh_int_timer_do (unsigned long ptr)
{
	int len;
	struct urb *urb = (struct urb *) ptr;
	hci_t *hci = urb->dev->bus->hcpriv;

	DBGFUNC ("enter rh_int_timer_do\n");

	if (hci->rh.send) {
		len = rh_send_irq (hci, urb->transfer_buffer,
				   urb->transfer_buffer_length);
		if (len > 0) {
			urb->actual_length = len;
			if (urb_debug == 2)
				urb_print (urb, "RET-t(rh)",
					   usb_pipeout (urb->pipe));

			if (urb->complete) {
				urb->complete (urb, NULL);
			}
		}
	}

	/* re-activate the timer */
	rh_init_int_timer (urb);
}
Example #3
0
//transfer buffer must be aligned on an 8 bytes boundary
static int hci_submit_urb (urb_t * urb)
{
	hci_t * hci;
	unsigned int pipe = urb->pipe;
	unsigned long flags;
	int ret;

	if (!urb->dev || !urb->dev->bus || urb->hcpriv) return -EINVAL;
#if BURST_TRANSFER_SIZE >= 8
	if ( ((int)urb->transfer_buffer) & 7) {
		if ( (urb->transfer_buffer_length >8) ||
		     ( ( ((int)urb->transfer_buffer) & 1 ) && (urb->transfer_buffer_length >1) ) ) {
			printk(KERN_ERR __FILE__  ": improper alignment, size %d bytes\n",urb->transfer_buffer_length);
			return -EINVAL;
		}
	}
#endif
	if (usb_endpoint_halted (urb->dev,
				usb_pipeendpoint (pipe), usb_pipeout (pipe)))
		return -EPIPE;

	hci = (hci_t *) urb->dev->bus->hcpriv;

	/* a request to the virtual root hub */
	if (usb_pipedevice (pipe) == hci->rh.devnum) {
		return rh_submit_urb (urb);
	}

	if (urb_debug)
		urb_print (urb, "SUB", usb_pipein (pipe));

	/* queue the URB to its endpoint-queue */

	spin_lock_irqsave (&hci->urb_list_lock, flags);
	ret = hcs_urb_queue (hci, urb);
	spin_unlock_irqrestore (&hci->urb_list_lock, flags);

	return ret;

}
Example #4
0
/*
 * decouple the URB from the HC queues (TDs, urb_priv);
 * reporting is always done
 * asynchronously, and we might be dealing with an urb that's
 * partially transferred, or an ED with other urbs being unlinked.
 */
static int admhc_urb_dequeue(struct usb_hcd *hcd, struct urb *urb,
		int status)
{
	struct admhcd *ahcd = hcd_to_admhcd(hcd);
	unsigned long flags;
	int ret;

	spin_lock_irqsave(&ahcd->lock, flags);

#ifdef ADMHC_VERBOSE_DEBUG
	urb_print(ahcd, urb, "DEQUEUE", 1, status);
#endif
	ret = usb_hcd_check_unlink_urb(hcd, urb, status);
	if (ret) {
		/* Do nothing */
		;
	} else if (HC_IS_RUNNING(hcd->state)) {
		struct urb_priv *urb_priv;

		/* Unless an IRQ completed the unlink while it was being
		 * handed to us, flag it for unlink and giveback, and force
		 * some upcoming INTR_SF to call finish_unlinks()
		 */
		urb_priv = urb->hcpriv;
		if (urb_priv) {
			if (urb_priv->ed->state == ED_OPER)
				start_ed_unlink(ahcd, urb_priv->ed);
		}
	} else {
		/*
		 * with HC dead, we won't respect hc queue pointers
		 * any more ... just clean up every urb's memory.
		 */
		if (urb->hcpriv)
			finish_urb(ahcd, urb, status);
	}
	spin_unlock_irqrestore(&ahcd->lock, flags);

	return ret;
}
Example #5
0
static int hcs_return_urb (hci_t * hci, struct urb * urb, int resub_ok)
{	
	struct usb_device * dev = urb->dev;
	int resubmit = 0;

	if (urb_debug)
		urb_print (urb, "RET", usb_pipeout (urb->pipe));
	
  	resubmit = urb->interval && resub_ok;
 	
	urb->dev = urb->hcpriv = NULL;

	if (urb->complete) 
		urb->complete (urb); /* call complete */
	
	if (resubmit) { /* requeue the URB */
		urb->dev = dev;		
		hcs_urb_queue (hci, urb);
	}

	return 0;
}
Example #6
0
static int hcs_return_urb (hci_t * hci, urb_t * urb, int resub_ok)
{
	int resubmit = 0;
	struct dmaWork* dw=NULL;

	if (urb_debug)
		urb_print (urb, "RET", usb_pipeout (urb->pipe));

  	resubmit = urb->interval && resub_ok;


	if (!resubmit) {
		urb->dev = NULL;
		dw = urb->hcpriv;
		urb->hcpriv = NULL;
	}
	if (urb->complete) {
		if ((!resubmit)||!IntervalStatus(urb)) {
			urb->complete (urb); /* call complete */
		}
	}
	if (resubmit) { /* requeue the URB */
		if (!usb_pipeint (urb->pipe) || (urb->interval==0)) {
			urb->start_frame = hci->frame_no;
			hcs_urb_queue (hci, urb);
		} else {
			urb->start_frame = hci->frame_no + urb->interval;
			list_add (&urb->urb_list, &hci->waiting_intr_list);
			hc116x_enable_sofint(hci);
		}
	} else {
		if (dw) FreeDmaWork(hci,dw);		//this also wakes anyone waiting on its destruction
	}

	return 0;
}
Example #7
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;
}
Example #8
0
/*****************************************************************
 *
 * Function Name: hc_interrupt
 *
 * Interrupt service routine. 
 *
 * 1) determine the causes of interrupt
 * 2) clears all interrupts
 * 3) calls appropriate function to service the interrupt
 *
 * Input:  irq = interrupt line associated with the controller 
 *         hci = data structure for the host controller
 *         r = holds the snapshot of the processor's context before 
 *             the processor entered interrupt code. (not used here) 
 *
 * Return value  : None.
 *                
 *****************************************************************/
static void hc_interrupt (int irq, void *__hci, struct pt_regs *r)
{
	char ii;
	hci_t *hci = __hci;
	int isExcessNak = 0;
	int urb_state = 0;
	char tmpIrq = 0;

	/* Get value from interrupt status register */

	ii = SL811Read (hci, SL11H_INTSTATREG);

	if (ii & SL11H_INTMASK_INSRMV) {
		/* Device insertion or removal detected for the USB port */

		SL811Write (hci, SL11H_INTENBLREG, 0);
		SL811Write (hci, SL11H_CTLREG1, 0);
		mdelay (100);	// wait for device stable 
		handleInsRmvIntr (hci);
		return;
	}

	/* Clear all interrupts */

	SL811Write (hci, SL11H_INTSTATREG, 0xff);

	if (ii & SL11H_INTMASK_XFERDONE) {
		/* USB Done interrupt occurred */

		urb_state = sh_done_list (hci, &isExcessNak);
#ifdef WARNING
		if (hci->td_array->len > 0)
			printk ("WARNING: IRQ, td_array->len = 0x%x, s/b:0\n",
				hci->td_array->len);
#endif
		if (hci->td_array->len == 0 && !isExcessNak
		    && !(ii & SL11H_INTMASK_SOFINTR) && (urb_state == 0)) {
			if (urb_state == 0) {
				/* All urb_state has not been finished yet! 
				 * continue with the current urb transaction 
				 */

				if (hci->last_packet_nak == 0) {
					if (!usb_pipecontrol
					    (hci->td_array->td[0].urb->pipe))
						sh_add_packet (hci, hci->td_array-> td[0].urb);
				}
			} else {
				/* The last transaction has completed:
				 * schedule the next transaction 
				 */

				sh_schedule_trans (hci, 0);
			}
		}
		SL811Write (hci, SL11H_INTSTATREG, 0xff);
		return;
	}

	if (ii & SL11H_INTMASK_SOFINTR) {
		hci->frame_number = (hci->frame_number + 1) % 2048;
		if (hci->td_array->len == 0)
			sh_schedule_trans (hci, 1);
		else {
			if (sofWaitCnt++ > 100) {
				/* The last transaction has not completed.
				 * Need to retire the current td, and let
				 * it transmit again later on.
				 * (THIS NEEDS TO BE WORK ON MORE, IT SHOULD NEVER 
				 *  GET TO THIS POINT)
				 */

				DBGERR ("SOF interrupt: td_array->len = 0x%x, s/b: 0\n",
					hci->td_array->len);
				urb_print (hci->td_array->td[hci->td_array->len - 1].urb,
					   "INTERRUPT", 0);
				sh_done_list (hci, &isExcessNak);
				SL811Write (hci, SL11H_INTSTATREG, 0xff);
				hci->td_array->len = 0;
				sofWaitCnt = 0;
			}
		}
		tmpIrq = SL811Read (hci, SL11H_INTSTATREG) & SL811Read (hci, SL11H_INTENBLREG);
		if (tmpIrq) {
			DBG ("IRQ occurred while service SOF: irq = 0x%x\n",
			     tmpIrq);

			/* If we receive a DONE IRQ after schedule, need to 
			 * handle DONE IRQ again 
			 */

			if (tmpIrq & SL11H_INTMASK_XFERDONE) {
				DBGERR ("IRQ occurred while service SOF: irq = 0x%x\n",
					tmpIrq);
				urb_state = sh_done_list (hci, &isExcessNak);
			}
			SL811Write (hci, SL11H_INTSTATREG, 0xff);
		}
	} else {
		DBG ("SL811 ISR: unknown, int = 0x%x \n", ii);
	}

	SL811Write (hci, SL11H_INTSTATREG, 0xff);
	return;
}
Example #9
0
/*
 * queue up an urb for anything except the root hub
 */
static int admhc_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
		gfp_t mem_flags)
{
	struct admhcd	*ahcd = hcd_to_admhcd(hcd);
	struct ed	*ed;
	struct urb_priv	*urb_priv;
	unsigned int	pipe = urb->pipe;
	int		td_cnt = 0;
	unsigned long	flags;
	int		ret = 0;

#ifdef ADMHC_VERBOSE_DEBUG
	spin_lock_irqsave(&ahcd->lock, flags);
	urb_print(ahcd, urb, "ENQEUE", usb_pipein(pipe), -EINPROGRESS);
	spin_unlock_irqrestore(&ahcd->lock, flags);
#endif

	/* every endpoint has an ed, locate and maybe (re)initialize it */
	ed = ed_get(ahcd, urb->ep, urb->dev, pipe, urb->interval);
	if (!ed)
		return -ENOMEM;

	/* for the private part of the URB we need the number of TDs */
	switch (ed->type) {
	case PIPE_CONTROL:
		if (urb->transfer_buffer_length > TD_DATALEN_MAX)
			/* td_submit_urb() doesn't yet handle these */
			return -EMSGSIZE;

		/* 1 TD for setup, 1 for ACK, plus ... */
		td_cnt = 2;
		/* FALLTHROUGH */
	case PIPE_BULK:
		/* one TD for every 4096 Bytes (can be upto 8K) */
		td_cnt += urb->transfer_buffer_length / TD_DATALEN_MAX;
		/* ... and for any remaining bytes ... */
		if ((urb->transfer_buffer_length % TD_DATALEN_MAX) != 0)
			td_cnt++;
		/* ... and maybe a zero length packet to wrap it up */
		if (td_cnt == 0)
			td_cnt++;
		else if ((urb->transfer_flags & URB_ZERO_PACKET) != 0
			&& (urb->transfer_buffer_length
				% usb_maxpacket(urb->dev, pipe,
					usb_pipeout (pipe))) == 0)
			td_cnt++;
		break;
	case PIPE_INTERRUPT:
		/*
		 * for Interrupt IN/OUT transactions, each ED contains
		 * only 1 TD.
		 * TODO: check transfer_buffer_length?
		 */
		td_cnt = 1;
		break;
	case PIPE_ISOCHRONOUS:
		/* number of packets from URB */
		td_cnt = urb->number_of_packets;
		break;
	}

	urb_priv = urb_priv_alloc(ahcd, td_cnt, mem_flags);
	if (!urb_priv)
		return -ENOMEM;

	urb_priv->ed = ed;

	spin_lock_irqsave(&ahcd->lock, flags);
	/* don't submit to a dead HC */
	if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) {
		ret = -ENODEV;
		goto fail;
	}
	if (!HC_IS_RUNNING(hcd->state)) {
		ret = -ENODEV;
		goto fail;
	}

	ret = usb_hcd_link_urb_to_ep(hcd, urb);
	if (ret)
		goto fail;

	/* schedule the ed if needed */
	if (ed->state == ED_IDLE) {
		ret = ed_schedule(ahcd, ed);
		if (ret < 0) {
			usb_hcd_unlink_urb_from_ep(hcd, urb);
			goto fail;
		}
		if (ed->type == PIPE_ISOCHRONOUS) {
			u16	frame = admhc_frame_no(ahcd);

			/* delay a few frames before the first TD */
			frame += max_t (u16, 8, ed->interval);
			frame &= ~(ed->interval - 1);
			frame |= ed->branch;
			urb->start_frame = frame;

			/* yes, only URB_ISO_ASAP is supported, and
			 * urb->start_frame is never used as input.
			 */
		}
	} else if (ed->type == PIPE_ISOCHRONOUS)
		urb->start_frame = ed->last_iso + ed->interval;

	/* fill the TDs and link them to the ed; and
	 * enable that part of the schedule, if needed
	 * and update count of queued periodic urbs
	 */
	urb->hcpriv = urb_priv;
	td_submit_urb(ahcd, urb);

#ifdef ADMHC_VERBOSE_DEBUG
	admhc_dump_ed(ahcd, "admhc_urb_enqueue", urb_priv->ed, 1);
#endif

fail:
	if (ret)
		urb_priv_free(ahcd, urb_priv);

	spin_unlock_irqrestore(&ahcd->lock, flags);
	return ret;
}