Beispiel #1
0
/**
 * This function completes the ep0 control transfer.
 */
static int32_t ep0_complete_request( pcd_struct_t * pcd)
{

    deptsiz0_data_t deptsiz;
    int is_last = 0;
    dwc_ep_t* ep = &g_dwc_eps[0];

    DBG("ep0_complete_request()\n");
    if (pcd->ep0state == EP0_STATUS)
    {
        is_last = 1;
    }
    else if (ep->xfer_len == 0)
    {
        ep->xfer_len = 0;
        ep->xfer_count = 0;
        ep->sent_zlp = 1;
        dwc_otg_ep_start_transfer( ep );
        return 1;
    }
    else if (ep->is_in)
    {
        deptsiz.d32 = dwc_read_reg32(DWC_REG_IN_EP_TSIZE(0) );
        if (deptsiz.b.xfersize == 0) {
            /* Is a Zero Len Packet needed? */
            do_setup_out_status_phase(pcd);
        }
    }
    else {
        /* ep0-OUT */
        do_setup_in_status_phase(pcd);
    }

    /* Complete the request */
    if (is_last) {
        ep->start_xfer_buff = 0;
        ep->xfer_buff = 0;
        ep->xfer_len = 0;
        return 1;
    }
    return 0;
}
Beispiel #2
0
/**
 * This function starts the Zero-Length Packet for the IN status phase
 * of a 2 stage control transfer. 
 */
static void do_setup_in_status_phase( pcd_struct_t *_pcd)
{
        dwc_ep_t *ep0 = &g_dwc_eps[0];
        if (_pcd->ep0state == EP0_STALL){
                return;
        }
                
        _pcd->ep0state = EP0_STATUS;
        
        DBG( "EP0 IN ZLP\n");
        ep0->xfer_len = 0;
        ep0->xfer_count = 0;
        ep0->is_in = 1;

        dwc_otg_ep_start_transfer( ep0 );

        /* Prepare for more SETUP Packets */
        ep0_out_start();

}
Beispiel #3
0
/**
 * This function is used to submit an I/O Request to an EP.
 *
 *	- When the request completes the request's completion callback
 *	  is called to return the request to the driver.
 *	- An EP, except control EPs, may have multiple requests
 *	  pending.
 *	- Once submitted the request cannot be examined or modified.
 *	- Each request is turned into one or more packets.
 *	- A BULK EP can queue any amount of data; the transfer is
 *	  packetized.
 *	- Zero length Packets are specified with the request 'zero'
 *	  flag.
 */
static int dwc_otg_pcd_ep_queue(struct usb_ep *_ep, 
								struct usb_request *_req, int _gfp_flags)
{
	int prevented = 0;
	dwc_otg_pcd_request_t *req;
	dwc_otg_pcd_ep_t *ep;
	dwc_otg_pcd_t	*pcd;
	unsigned long flags = 0;

	DWC_DEBUGPL(DBG_PCDV,"%s(%p,%p,%d)\n", 
				__func__, _ep, _req, _gfp_flags);
		
	req = container_of(_req, dwc_otg_pcd_request_t, req);
	if (!_req || !_req->complete || !_req->buf || 
			!list_empty(&req->queue)) 
	{
		if( !_req ) printk("bad _req\n");
		if( !_req->complete ) printk("bad _req->complete\n");
		if( !_req->buf ) printk("bad _req->buf\n");
		if( !list_empty(&req->queue) ) printk("bad list_empty\n");
		DWC_WARN("%s, bad params\n", __func__);
		return -EINVAL;
	}
		
	ep = container_of(_ep, dwc_otg_pcd_ep_t, ep);
	if (!_ep || (!ep->desc && ep->dwc_ep.num != 0)) 
	{
		DWC_WARN("%s, bad ep\n", __func__);
		return -EINVAL;
	}
	pcd = ep->pcd;

//cathy, if suspended, drop request
	if ( (GET_CORE_IF(pcd)->dev_if->suspended == 1) && (ep->dwc_ep.num != 0) )
	{
		DWC_DEBUGPL(DBG_PCDV,"%s, epnum = %d, drop request\n", __func__, ep->dwc_ep.num);
		return -ESHUTDOWN;	
	}

	if (!pcd->driver || pcd->gadget.speed == USB_SPEED_UNKNOWN) 
	{
		DWC_DEBUGPL(DBG_PCDV, "gadget.speed=%d\n", pcd->gadget.speed);
		DWC_WARN("%s, bogus device state\n", __func__);
		return -ESHUTDOWN;
	}


	DWC_DEBUGPL(DBG_PCD, "%s queue req %p, len %d buf %p\n",
				   _ep->name, _req, _req->length, _req->buf);

	if (!GET_CORE_IF(pcd)->core_params->opt) 
	{
		if (ep->dwc_ep.num != 0) 
		{
			DWC_ERROR("%s queue req %p, len %d buf %p\n",
					  _ep->name, _req, _req->length, _req->buf);
		}
	}

	SPIN_LOCK_IRQSAVE(&ep->pcd->lock, flags);

#if defined(DEBUG) & defined(VERBOSE)
	dump_msg(_req->buf, _req->length);
#endif	

	_req->status = -EINPROGRESS;
	_req->actual = 0;

	/* 
	 * For EP0 IN without premature status, zlp is required?
	 */
	if (ep->dwc_ep.num == 0 && ep->dwc_ep.is_in) 
	{
		DWC_DEBUGPL(DBG_PCDV, "%s-OUT ZLP\n", _ep->name);
		//_req->zero = 1;
	}

	/* Start the transfer */
	if (list_empty(&ep->queue) && !ep->stopped) 
	{
		/* EP0 Transfer? */
		if (ep->dwc_ep.num == 0) 
		{
			switch (pcd->ep0state) 
			{
			case EP0_IN_DATA_PHASE:
				DWC_DEBUGPL(DBG_PCD, 
								"%s ep0: EP0_IN_DATA_PHASE\n", 
								__func__);
				break;

			case EP0_OUT_DATA_PHASE:
				DWC_DEBUGPL(DBG_PCD, 
								"%s ep0: EP0_OUT_DATA_PHASE\n", 
								__func__);
				if (pcd->request_config) 
				{ 
					/* Complete STATUS PHASE */
					ep->dwc_ep.is_in = 1;
					pcd->ep0state = EP0_STATUS;
				}
				break;
						
			default:
				DWC_DEBUGPL(DBG_ANY, "ep0: odd state %d\n", 
											pcd->ep0state);
				SPIN_UNLOCK_IRQRESTORE(&pcd->lock, flags);
				return -EL2HLT;
			}
			ep->dwc_ep.dma_addr = (u32)_req->buf & ~Uncache_Mask;   //_req->dma;	//cathy
			ep->dwc_ep.start_xfer_buff = _req->buf;
			ep->dwc_ep.xfer_buff = _req->buf;
			ep->dwc_ep.xfer_len = _req->length;
			ep->dwc_ep.xfer_count = 0;
			ep->dwc_ep.sent_zlp = 0;
			ep->dwc_ep.total_len = ep->dwc_ep.xfer_len;
			dwc_otg_ep0_start_transfer( GET_CORE_IF(pcd), 
										&ep->dwc_ep );
		} 
		else 
		{
			/* Setup and start the Transfer */
			ep->dwc_ep.dma_addr = (u32)_req->buf  & ~Uncache_Mask;   //_req->dma;	//cathy
			//ep->dwc_ep.dma_addr = _req->dma;
			ep->dwc_ep.start_xfer_buff = _req->buf;
			ep->dwc_ep.xfer_buff = _req->buf;
			ep->dwc_ep.xfer_len = _req->length;
			ep->dwc_ep.xfer_count = 0;
			ep->dwc_ep.sent_zlp = 0;
			ep->dwc_ep.total_len = ep->dwc_ep.xfer_len;
			dwc_otg_ep_start_transfer( GET_CORE_IF(pcd), 
									   &ep->dwc_ep );
		}
	}

	if ((req != 0) || prevented) 
	{
		++pcd->request_pending;
		list_add_tail(&req->queue, &ep->queue);
//cathy
#if 0
		if (ep->dwc_ep.is_in && ep->stopped && !(GET_CORE_IF(pcd)->dma_enable)) 
		{
			/** @todo NGS Create a function for this. */
			diepmsk_data_t diepmsk = { .d32 = 0};
			diepmsk.b.intktxfemp = 1;
			dwc_modify_reg32( &GET_CORE_IF(pcd)->dev_if->dev_global_regs->diepmsk, 0, diepmsk.d32 );
		}
#endif		
	}