Beispiel #1
0
/**
 * Checks that the max transfer size allowed in a host channel is large enough
 * to handle the maximum data transfer in a single (micro)frame for a periodic
 * transfer.
 *
 * @param hcd The HCD state structure for the DWC OTG controller.
 * @param qh QH for a periodic endpoint.
 *
 * @return 0 if successful, negative error code otherwise.
 */
static int check_max_xfer_size(dwc_otg_hcd_t *hcd, dwc_otg_qh_t *qh)
{
	int		status;
	uint32_t 	max_xfer_size;
	uint32_t	max_channel_xfer_size;

	status = 0;

	max_xfer_size = dwc_max_packet(qh->maxp) * dwc_hb_mult(qh->maxp);
	max_channel_xfer_size = hcd->core_if->core_params->max_transfer_size;

	if (max_xfer_size > max_channel_xfer_size) {
		DWC_NOTICE("%s: Periodic xfer length %d > "
			    "max xfer length for channel %d\n",
			    __func__, max_xfer_size, max_channel_xfer_size);
		status = -ENOSPC;
	}

	return status;
}
/** Initializes a QH structure.
 *
 * @param[in] _hcd The HCD state structure for the DWC OTG controller.
 * @param[in] _qh The QH to init.
 * @param[in] _urb Holds the information about the device/endpoint that we need
 * to initialize the QH. */
#define SCHEDULE_SLOP 10
#define SCHEDULE_SPLIT_SLOP	10  /* 1 == 125us,  10 -> 1.25ms, 20 -> 2.5ms, */
void dwc_otg_hcd_qh_init(dwc_otg_hcd_t * _hcd, dwc_otg_qh_t * _qh,
			 struct urb *_urb)
{
	memset(_qh, 0, sizeof(dwc_otg_qh_t));

	/* Initialize QH */
	switch (usb_pipetype(_urb->pipe)) {
	case PIPE_CONTROL:
		_qh->ep_type = USB_ENDPOINT_XFER_CONTROL;
		break;
	case PIPE_BULK:
		_qh->ep_type = USB_ENDPOINT_XFER_BULK;
		break;
	case PIPE_ISOCHRONOUS:
		_qh->ep_type = USB_ENDPOINT_XFER_ISOC;
		break;
	case PIPE_INTERRUPT:
		_qh->ep_type = USB_ENDPOINT_XFER_INT;
		break;
	}

	_qh->ep_is_in = usb_pipein(_urb->pipe) ? 1 : 0;

	_qh->data_toggle = DWC_OTG_HC_PID_DATA0;
	_qh->maxp =
	    usb_maxpacket(_urb->dev, _urb->pipe, !(usb_pipein(_urb->pipe)));
	INIT_LIST_HEAD(&_qh->qtd_list);
	INIT_LIST_HEAD(&_qh->qh_list_entry);
	_qh->channel = NULL;

	/* FS/LS Enpoint on HS Hub 
	 * NOT virtual root hub */
	_qh->do_split = 0;
	if (((_urb->dev->speed == USB_SPEED_LOW) ||
	     (_urb->dev->speed == USB_SPEED_FULL)) &&
	    (_urb->dev->tt) && (_urb->dev->tt->hub)
	    && (_urb->dev->tt->hub->devnum != 1)) {
		DWC_DEBUGPL(DBG_HCD,
			    "QH init: EP %d: TT found at hub addr %d, for port %d\n",
			    usb_pipeendpoint(_urb->pipe),
			    _urb->dev->tt->hub->devnum, _urb->dev->ttport);
		_qh->do_split = 1;
	}

	if (_qh->ep_type == USB_ENDPOINT_XFER_INT ||
	    _qh->ep_type == USB_ENDPOINT_XFER_ISOC) {
		/* Compute scheduling parameters once and save them. */
		hprt0_data_t hprt;

		/** @todo Account for split transfers in the bus time. */
		int bytecount =
		    dwc_hb_mult(_qh->maxp) * dwc_max_packet(_qh->maxp);
		int usecs = /*FIXME: hardcode to highspeed, to fix Full/Low speed device via Hub*/
		    usb_calc_bus_time(/*_urb->dev->speed*/USB_SPEED_HIGH, usb_pipein(_urb->pipe),
				      (_qh->ep_type == USB_ENDPOINT_XFER_ISOC),
				      bytecount);
		_qh->usecs = NS_TO_US(usecs);
		/* Start in a slightly future (micro)frame. */
		_qh->sched_frame = dwc_frame_num_inc(_hcd->frame_number,
						     SCHEDULE_SLOP);
		_qh->interval = _urb->interval;
#if 0
		/* Increase interrupt polling rate for debugging. */
		if (_qh->ep_type == USB_ENDPOINT_XFER_INT) {
			_qh->interval = 8;
		}
#endif
		hprt.d32 = dwc_read_reg32(_hcd->core_if->host_if->hprt0);
		if ((hprt.b.prtspd == DWC_HPRT0_PRTSPD_HIGH_SPEED) &&
		    ((_urb->dev->speed == USB_SPEED_LOW) ||
		     (_urb->dev->speed == USB_SPEED_FULL))) {
			_qh->interval *= 8;
			_qh->sched_frame |= 0x7;
			_qh->start_split_frame = _qh->sched_frame;
		}

	}else{
		if(_qh->do_split){
			_qh->interval = SCHEDULE_SPLIT_SLOP;
			_qh->sched_frame = dwc_frame_num_inc(_hcd->frame_number,
						     _qh->interval);

		};
	}

	DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD QH Initialized\n");
	DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH  - qh = %p\n", _qh);
	DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH  - Device Address = %d\n",
		    _urb->dev->devnum);
	DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH  - Endpoint %d, %s\n",
		    usb_pipeendpoint(_urb->pipe),
		    usb_pipein(_urb->pipe) == USB_DIR_IN ? "IN" : "OUT");
	DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH  - Speed = %s\n", ( {
			 char *speed;
			 switch(_urb->dev->speed) {
				case USB_SPEED_LOW:
					speed = "low"; break; 
				case USB_SPEED_FULL:
					speed = "full"; break; 
				case USB_SPEED_HIGH:
					speed = "high"; break; 
				default:
					 speed = "?"; break;};
			 speed;})) ;
Beispiel #3
0
void dwc_otg_hcd_qh_init(dwc_otg_hcd_t *hcd, dwc_otg_qh_t *qh, struct urb *urb)
{
	char *speed, *type;
	memset (qh, 0, sizeof (dwc_otg_qh_t));

	/* Initialize QH */
	switch (usb_pipetype(urb->pipe)) {
	case PIPE_CONTROL:
		qh->ep_type = USB_ENDPOINT_XFER_CONTROL;
		break;
	case PIPE_BULK:
		qh->ep_type = USB_ENDPOINT_XFER_BULK;
		break;
	case PIPE_ISOCHRONOUS:
		qh->ep_type = USB_ENDPOINT_XFER_ISOC;
		break;
	case PIPE_INTERRUPT:
		qh->ep_type = USB_ENDPOINT_XFER_INT;
		break;
	}

	qh->ep_is_in = usb_pipein(urb->pipe) ? 1 : 0;

	qh->data_toggle = DWC_OTG_HC_PID_DATA0;
	qh->maxp = usb_maxpacket(urb->dev, urb->pipe, !(usb_pipein(urb->pipe)));
	INIT_LIST_HEAD(&qh->qtd_list);
	INIT_LIST_HEAD(&qh->qh_list_entry);
	qh->channel = NULL;

	/* FS/LS Enpoint on HS Hub
	 * NOT virtual root hub */
	qh->do_split = 0;
	if (((urb->dev->speed == USB_SPEED_LOW) ||
	     (urb->dev->speed == USB_SPEED_FULL)) &&
	     (urb->dev->tt) && (urb->dev->tt->hub) && (urb->dev->tt->hub->devnum != 1))
	{
		DWC_DEBUGPL(DBG_HCD, "QH init: EP %d: TT found at hub addr %d, for port %d\n",
			   usb_pipeendpoint(urb->pipe), urb->dev->tt->hub->devnum,
			   urb->dev->ttport);
		qh->do_split = 1;
	}

	if (qh->ep_type == USB_ENDPOINT_XFER_INT ||
	    qh->ep_type == USB_ENDPOINT_XFER_ISOC) {
		/* Compute scheduling parameters once and save them. */
		hprt0_data_t hprt;

		/** @todo Account for split transfers in the bus time. */
		int bytecount = dwc_hb_mult(qh->maxp) * dwc_max_packet(qh->maxp);

		/* FIXME: work-around patch by Steven */
		qh->usecs = NS_TO_US(usb_calc_bus_time(urb->dev->speed,
					       usb_pipein(urb->pipe),
					       (qh->ep_type == USB_ENDPOINT_XFER_ISOC),
					       bytecount));

		/* Start in a slightly future (micro)frame. */
		qh->sched_frame = dwc_frame_num_inc(hcd->frame_number,
						     SCHEDULE_SLOP);
		qh->interval = urb->interval;
#if 0
		/* Increase interrupt polling rate for debugging. */
		if (qh->ep_type == USB_ENDPOINT_XFER_INT) {
			qh->interval = 8;
		}
#endif
		hprt.d32 = dwc_read_reg32(hcd->core_if->host_if->hprt0);
		if ((hprt.b.prtspd == DWC_HPRT0_PRTSPD_HIGH_SPEED) &&
		    ((urb->dev->speed == USB_SPEED_LOW) ||
		     (urb->dev->speed == USB_SPEED_FULL))) {
			qh->interval *= 8;
			qh->sched_frame |= 0x7;
			qh->start_split_frame = qh->sched_frame;
		}

	}

	DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD QH Initialized\n");
	DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH  - qh = %p\n", qh);
	DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH  - Device Address = %d\n",
		    urb->dev->devnum);
	DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH  - Endpoint %d, %s\n",
		    usb_pipeendpoint(urb->pipe),
		    usb_pipein(urb->pipe) == USB_DIR_IN ? "IN" : "OUT");

	switch(urb->dev->speed) {
	case USB_SPEED_LOW:
		speed = "low";
		break;
	case USB_SPEED_FULL:
		speed = "full";
		break;
	case USB_SPEED_HIGH:
		speed = "high";
		break;
	default:
		speed = "?";
		break;
	}
	DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH  - Speed = %s\n", speed);

	switch (qh->ep_type) {
	case USB_ENDPOINT_XFER_ISOC:
		type = "isochronous";
		break;
	case USB_ENDPOINT_XFER_INT:
		type = "interrupt";
		break;
	case USB_ENDPOINT_XFER_CONTROL:
		type = "control";
		break;
	case USB_ENDPOINT_XFER_BULK:
		type = "bulk";
		break;
	default:
		type = "?";
		break;
	}
	DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH  - Type = %s\n",type);

#ifdef DEBUG
	if (qh->ep_type == USB_ENDPOINT_XFER_INT) {
		DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH - usecs = %d\n",
			    qh->usecs);
		DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH - interval = %d\n",
			    qh->interval);
	}
#endif
	qh->dw_align_buf = NULL;
	return;
}