int usb_drv_recv(int ep, void *ptr, int len)
{
    struct usb_dev_dma_desc *uc_desc = endpoints[ep][1].uc_desc;

    ep &= 0x7f;
    logf("usb_drv_recv(%d,%x,%d)\n", ep, (int)ptr, len);

    if (len > USB_DMA_DESC_RXTX_BYTES)
        panicf("usb_recv: len=%d > %d", len, USB_DMA_DESC_RXTX_BYTES);

    if ((int)ptr & 31) {
        logf("addr %08x not aligned!\n", (int)ptr);
    }

    endpoints[ep][1].state |= EP_STATE_BUSY;
    endpoints[ep][1].len = len;
    endpoints[ep][1].rc  = -1;

    /* remove data buffer from cache */
    discard_dcache_range(ptr, len);

    /* DMA setup */
    uc_desc->status    = USB_DMA_DESC_BS_HST_RDY |
                         USB_DMA_DESC_LAST |
                         len;
    if (len == 0) {
        uc_desc->status   |= USB_DMA_DESC_ZERO_LEN;
        uc_desc->data_ptr  = 0;
    } else {
        uc_desc->data_ptr  = AS3525_PHYSICAL_ADDR(ptr);
    }
    USB_OEP_DESC_PTR(ep) = AS3525_PHYSICAL_ADDR((int)&dmadescs[ep][1]);
    USB_OEP_STS(ep)      = USB_EP_STAT_OUT_RCVD; /* clear status */

    /* Make sure receive DMA is on */
    if (!(USB_DEV_CTRL & USB_DEV_CTRL_RDE)){
        USB_DEV_CTRL |= USB_DEV_CTRL_RDE;
        if (!(USB_DEV_CTRL & USB_DEV_CTRL_RDE))
            logf("failed to enable RDE!\n");
    }

    USB_OEP_CTRL(ep)    |= USB_EP_CTRL_CNAK; /* Go! */

    if (USB_OEP_CTRL(ep) & USB_EP_CTRL_NAK) {
        int i = 0;
        while (USB_OEP_CTRL(ep) & USB_EP_CTRL_NAK) {
            USB_OEP_CTRL(ep)    |= USB_EP_CTRL_CNAK; /* Go! */
            i++;
        }
        logf("ep%d CNAK needed %d retries CTRL=%x\n", ep, i, (int)USB_OEP_CTRL(ep));
    }

    return 0;
}
static void ep_send(int ep, void *ptr, int len)
{
    struct usb_dev_dma_desc *uc_desc = endpoints[ep][0].uc_desc;

    endpoints[ep][0].state |= EP_STATE_BUSY;
    endpoints[ep][0].len = len;
    endpoints[ep][0].rc = -1;

    /*
     * I'm seeing a problem where Linux sends two SETUP requests,
     * but fails to read the response from the first one.
     * We then have the response we wanted to send still in our fifo,
     * so flush the fifo before sending on the control endpoint.
     */
    if (ep == 0)
        USB_IEP_CTRL(ep) |= USB_EP_CTRL_FLUSH;

    /* Make sure data is committed to memory */
    commit_dcache_range(ptr, len);

    logf("xx%s\n", make_hex(ptr, len));

    uc_desc->status    = USB_DMA_DESC_BS_HST_RDY |
                         USB_DMA_DESC_LAST |
                         len;
    if (len == 0)
        uc_desc->status |= USB_DMA_DESC_ZERO_LEN;

    uc_desc->data_ptr  = AS3525_PHYSICAL_ADDR(ptr);

    USB_IEP_DESC_PTR(ep) = AS3525_PHYSICAL_ADDR((int)&dmadescs[ep][0]);
    USB_IEP_STS(ep)      = 0xffffffff; /* clear status */
    /* start transfer */
    USB_IEP_CTRL(ep)     |= USB_EP_CTRL_CNAK | USB_EP_CTRL_PD;
    /* HW automatically sets NAK bit later */
}
Пример #3
0
static void prepare_setup_ep0(void)
{
    logf("usb-drv: prepare EP0");
    /* setup DMA */
    DOEPDMA(0) = (unsigned long)AS3525_PHYSICAL_ADDR(&_ep0_setup_pkt);

    /* Setup EP0 OUT with the following parameters:
     * packet count = 1
     * setup packet count = 1
     * transfer size = 8 (setup packet)
     */
    DOEPTSIZ(0) = (1 << DEPTSIZ0_supcnt_bitp)
                | (1 << DEPTSIZ0_pkcnt_bitp)
                | 8;

    /* Enable endpoint, clear nak */
    ep0_state = EP0_WAIT_SETUP;
    DOEPCTL(0) |= DEPCTL_epena | DEPCTL_cnak;
}
static void reset_endpoints(int init)
{
    int i;

    /*
     * OUT EP 2 is an alias for OUT EP 0 on this HW!
     *
     * Resonates with "3 bidirectional- plus 1 in-endpoints in device mode"
     * from the datasheet, but why ep2 and not ep3?
     *
     * Reserve it here so we will skip over it in request_endpoint().
     */
    endpoints[2][1].state |= EP_STATE_ALLOCATED;

    for(i = 0; i < USB_NUM_EPS; i++) {
        /*
         * MPS sizes depending on speed:
         * LS: 8 (control), no bulk available
         * FS: 64 (control), 64 (bulk)
         * HS: 64 (control), 512 (bulk)
         *
         * We don't need to handle LS since there is no low-speed only
         * host AFAIK.
         */
        int mps = i == 0 ? 64 : (usb_drv_port_speed() ? 512 : 64);

        if (init) {
            if (endpoints[i][0].state & EP_STATE_BUSY) {
                if (endpoints[i][0].state & EP_STATE_ASYNC) {
                    endpoints[i][0].rc = -1;
                    semaphore_release(&endpoints[i][0].complete);
                } else {
                    usb_core_transfer_complete(i, USB_DIR_IN, -1, 0);
                }
            }
            endpoints[i][0].state = 0;
            semaphore_wait(&endpoints[i][0].complete, TIMEOUT_NOBLOCK);

            if (i != 2) { /* Skip the OUT EP0 alias */
                if (endpoints[i][1].state & EP_STATE_BUSY)
                    usb_core_transfer_complete(i, USB_DIR_OUT, -1, 0);
                endpoints[i][1].state = 0;
                semaphore_wait(&endpoints[i][1].complete, TIMEOUT_NOBLOCK);
                USB_OEP_SUP_PTR(i)    = 0;
            }
        }

        dma_desc_init(i, 0);
        USB_IEP_CTRL    (i) = USB_EP_CTRL_FLUSH|USB_EP_CTRL_SNAK;
        USB_IEP_MPS     (i) = mps; /* in bytes */
        /* We don't care about the 'IN token received' event */
        USB_IEP_STS_MASK(i) = USB_EP_STAT_IN; /* OF: 0x840 */
        USB_IEP_TXFSIZE (i) = mps/2; /* in dwords => mps*2 bytes */
        USB_IEP_STS     (i) = 0xffffffff; /* clear status */
        USB_IEP_DESC_PTR(i) = 0;

        if (i != 2) { /* Skip the OUT EP0 alias */
            dma_desc_init(i, 1);
            USB_OEP_CTRL    (i) = USB_EP_CTRL_FLUSH|USB_EP_CTRL_SNAK;
            USB_OEP_MPS     (i) = (mps/2 << 16) | mps;
            USB_OEP_STS_MASK(i) = USB_EP_STAT_BNA; /* OF: 0x1800 */
            USB_OEP_RXFR    (i) = 0;      /* Always 0 in OF trace? */
            USB_OEP_STS     (i) = 0xffffffff; /* clear status */
            USB_OEP_DESC_PTR(i) = 0;
        }
    }

    setup_desc_init(setup_desc);
    USB_OEP_SUP_PTR(0)    = AS3525_PHYSICAL_ADDR((int)setup_desc);
}