Esempio n. 1
0
static void handle_ep0_complete(bool is_ack)
{
    switch(ep0_state)
    {
        case EP0_WAIT_SETUP:
            panicf("usb-drv: EP0 completion while waiting for SETUP");
        case EP0_WAIT_ACK:
            if(is_ack)
                /* everything is done, prepare next setup */
                prepare_setup_ep0();
            else
                panicf("usb-drv: EP0 data completion while waiting for ACK");
            break;
        case EP0_WAIT_DATA:
            if(is_ack)
                panicf("usb-drv: EP0 ACK while waiting for data completion");
            else
                /* everything is done, prepare next setup */
                prepare_setup_ep0();
            break;
        case EP0_WAIT_DATA_ACK:
            /* update state */
            if(is_ack)
                ep0_state = EP0_WAIT_DATA;
            else
                ep0_state = EP0_WAIT_ACK;
            break;
        default:
            panicf("usb-drv: invalid EP0 state");
    }
    logf("usb-drv: EP0 state updated to %d", ep0_state);
}
Esempio n. 2
0
static void reset_endpoints(void)
{
    for (int dir = 0; dir < 2; dir++)
    {
        bool out = dir == DIR_OUT;
        for (unsigned i = 0; i < num_eps(dir == DIR_OUT); i++)
        {
            int ep = ((dir == DIR_IN) ? in_ep_list : out_ep_list)[i];
            struct ep_type *endpoint = &endpoints[ep][out];
            endpoint->active = false;
            endpoint->busy   = false;
            endpoint->status = -1;
            endpoint->done   = true;
            semaphore_release(&endpoint->complete);

            if (i != 0)
                DEPCTL(ep, out) = DEPCTL_setd0pid;
        }
        DEPCTL(0, out) = /*(DEPCTL_MPS_64 << DEPCTL_mps_bitp) | */ DEPCTL_usbactep;
    }

    /* Setup next chain for IN eps */
    for (unsigned i = 0; i < num_eps(false); i++)
    {
        int ep = in_ep_list[i];
        int next_ep = in_ep_list[(i + 1) % num_eps(false)];
        DEPCTL(ep, false) |= next_ep << DEPCTL_nextep_bitp;
    }

    prepare_setup_ep0();
}
Esempio n. 3
0
static void handle_ep_int(int ep, bool out)
{
    unsigned long sts = DEPINT(ep, out);
    struct ep_type *endpoint = &endpoints[ep][out ? DIR_OUT : DIR_IN];

    logf("%s(%d %s): sts = 0x%lx", __func__, ep, out?"OUT":"IN", sts);

    if(sts & DEPINT_ahberr)
        panicf("usb-drv: ahb error on EP%d %s", ep, out ? "OUT" : "IN");

    if(sts & DEPINT_xfercompl)
    {
        discard_dma_buffer_cache();
        if(endpoint->busy)
        {
            endpoint->busy = false;
            endpoint->status = 0;
            /* works even for EP0 */
            int size = (DEPTSIZ(ep, out) & DEPTSIZ_xfersize_bits);
            int transfered = endpoint->size - size;
            if(ep == 0)
            {
                bool is_ack = endpoint->size == 0;
                switch(ep0_state)
                {
                case EP0_WAIT_SETUP:
                    panicf("usb-drv: EP0 completion while waiting for SETUP");
                case EP0_WAIT_DATA_ACK:
                    ep0_state = is_ack ? EP0_WAIT_DATA : EP0_WAIT_ACK;
                    break;
                case EP0_WAIT_ACK:
                case EP0_WAIT_DATA:
                    if((!is_ack && ep0_state == EP0_WAIT_ACK) || (is_ack && ep0_state == EP0_WAIT_DATA))
                        panicf("usb-drv: bad EP0 state");

                    prepare_setup_ep0();
                    break;
                }
            }
            if (!out)
                endpoint->size = size;
            usb_core_transfer_complete(ep, out ? USB_DIR_OUT : USB_DIR_IN, 0, transfered);
            endpoint->done = true;
            semaphore_release(&endpoint->complete);
        }
    }

    if(!out && (sts & DIEPINT_timeout)) {
        if (endpoint->busy)
        {
            endpoint->busy = false;
            endpoint->status = 1;
            endpoint->done = true;
            semaphore_release(&endpoint->complete);
        }
    }

    if(out && (sts & DOEPINT_setup))
    {
        discard_dma_buffer_cache();
        if(ep != 0)
            panicf("usb-drv: setup not on EP0, this is impossible");
        if((DEPTSIZ(ep, true) & DEPTSIZ_xfersize_bits) != 0)
        {
            logf("usb-drv: ignore spurious setup (xfersize=%ld)", DOEPTSIZ(ep) & DEPTSIZ_xfersize_bits);
            prepare_setup_ep0();
        }
        else
        {
            if(ep0_state == EP0_WAIT_SETUP)
            {
                bool data_phase = ep0_setup_pkt->wLength != 0;
                ep0_state = data_phase ? EP0_WAIT_DATA_ACK : EP0_WAIT_ACK;
            }

            logf("  rt=%x r=%x", ep0_setup_pkt->bRequestType, ep0_setup_pkt->bRequest);

            if(ep0_setup_pkt->bRequestType == USB_TYPE_STANDARD &&
               ep0_setup_pkt->bRequest     == USB_REQ_SET_ADDRESS)
                DCFG = (DCFG & ~bitm(DCFG, devadr)) | (ep0_setup_pkt->wValue << DCFG_devadr_bitp);

            usb_core_control_request(ep0_setup_pkt);
        }
    }

    DEPINT(ep, out) = sts;
}