static void handle_in_ep(int ep)
{
    int ep_sts = USB_IEP_STS(ep) & ~USB_IEP_STS_MASK(ep);

    if (ep > 3)
        panicf("in_ep > 3?!");

    USB_IEP_STS(ep) = ep_sts; /* ack */

    if (ep_sts & USB_EP_STAT_BNA) { /* Buffer was not set up */
        int ctrl = USB_IEP_CTRL(ep);
        logf("ep%d IN, status %x ctrl %x (BNA)\n", ep, ep_sts, ctrl);
        panicf("ep%d IN 0x%x 0x%x (BNA)", ep, ep_sts, ctrl);
    }

    if (ep_sts & USB_EP_STAT_TDC) {
        endpoints[ep][0].state &= ~EP_STATE_BUSY;
        endpoints[ep][0].rc = 0;
        logf("EP%d %x %stx done len %x stat %08x\n",
             ep, ep_sts, endpoints[ep][0].state & EP_STATE_ASYNC ? "async " :"",
             endpoints[ep][0].len,
             endpoints[ep][0].uc_desc->status);
        if (endpoints[ep][0].state & EP_STATE_ASYNC) {
            endpoints[ep][0].state &= ~EP_STATE_ASYNC;
            usb_core_transfer_complete(ep, USB_DIR_IN, 0, endpoints[ep][0].len);
        } else {
            semaphore_release(&endpoints[ep][0].complete);
        }
        ep_sts &= ~USB_EP_STAT_TDC;
    }

    if (ep_sts) {
        logf("ep%d IN, hwstat %lx, epstat %x\n", ep, USB_IEP_STS(ep), endpoints[ep][0].state);
        panicf("ep%d IN 0x%x", ep, ep_sts);
    }
}
/* UDC ISR function */
void INT_UDC(void)
{
    uint32_t txstat, rxstat;
    int tmp, ep_num;
    
    /* read what caused UDC irq */
    uint32_t intsrc = INT2FLAG & 0x7fffff;
    
    if (intsrc & (1<<1)) /* setup interrupt */
    {
        setup_received();
    }
    else if (intsrc & (1<<2)) /* ep0 in interrupt */
    {
        txstat = TX0STAT; /* read clears flags */
        
        /* TODO handle errors */
        if (txstat & (1<<18)) /* check TxACK flag */
        {
            if (ctrlep[DIR_IN].cnt >= 0)
            {
                /* we still have data to send (or ZLP) */
                ctr_write();
            }
            else
            {
                /* final ack received */
                usb_core_transfer_complete(0,                   /* ep */
                                           USB_DIR_IN,          /* dir */
                                           0,                   /* status */
                                           ctrlep[DIR_IN].len); /* length */
                
                /* release semaphore for blocking transfer */
                if (ctrlep[DIR_IN].block)
                    semaphore_release(&ctrlep[DIR_IN].complete);
            }
        }
    }
    else if (intsrc & (1<<3)) /* ep0 out interrupt */
    {
        rxstat = RX0STAT;

        /* TODO handle errors */
        if (rxstat & (1<<18)) /* RxACK */
        {
            if (ctrlep[DIR_OUT].cnt > 0)
                ctr_read();
            else
                usb_core_transfer_complete(0,                    /* ep */
                                           USB_DIR_OUT,          /* dir */
                                           0,                    /* status */
                                           ctrlep[DIR_OUT].len); /* length */                
        }
    }
    else if (intsrc & (1<<4)) /* usb reset */
    {
        usb_drv_init();
    }
    else if (intsrc & (1<<5)) /* usb resume */
    {
        TX0CON |= (1<<0); /* TxClr */
        TX0CON &= ~(1<<0);
        RX0CON |= (1<<1); /* RxClr */
        RX0CON &= (1<<1);
    }
    else if (intsrc & (1<<6)) /* usb suspend */
    {
    }
    else if (intsrc & (1<<7)) /* usb connect */
    {
    }
    else
    {
        /* lets figure out which ep generated irq */
        tmp = intsrc >> 7;
        for (ep_num=1; ep_num < 15; ep_num++)
        {
            tmp >>= ep_num;
            if (tmp & 0x01)
                break;
        }
        
        if (intsrc & ((1<<8)|(1<<11)|(1<<14)|(1<<17)|(1<<20)))
        {
            /* bulk out */
            rxstat = BOUT_RXSTAT(ep_num);
            
            /* TODO handle errors */
            if (rxstat & (1<<18)) /* RxACK */
            {
                if (endpoints[ep_num].cnt > 0)
                    blk_read(ep_num);
                else
                    usb_core_transfer_complete(ep_num,               /* ep */
                                               USB_DIR_OUT,          /* dir */
                                               0,                    /* status */
                                               endpoints[ep_num].len); /* length */                
            }
        }
        else if (intsrc & ((1<<9)|(1<<12)|(1<<15)|(1<<18)|(1<<21)))
        {
            /* bulk in */
            txstat = BIN_TXSTAT(ep_num);
            
            /* TODO handle errors */
            if (txstat & (1<<18)) /* check TxACK flag */
            {
                if (endpoints[ep_num].cnt >= 0)
                {
                    /* we still have data to send (or ZLP) */
                    blk_write(ep_num);
                }
                else
                {
                    /* final ack received */
                    usb_core_transfer_complete(ep_num,                   /* ep */
                                               USB_DIR_IN,          /* dir */
                                               0,                   /* status */
                                               endpoints[ep_num].len); /* length */
                
                    /* release semaphore for blocking transfer */
                    if (endpoints[ep_num].block)
                        semaphore_release(&endpoints[ep_num].complete);
                }
            }
        }
        else if (intsrc & ((1<<10)|(1<13)|(1<<16)|(1<<19)|(1<<22)))
        {
            /* int in */
            txstat = IIN_TXSTAT(ep_num);

            /* TODO handle errors */
            if (txstat & (1<<18)) /* check TxACK flag */
            {
                if (endpoints[ep_num].cnt >= 0)
                {
                    /* we still have data to send (or ZLP) */
                    int_write(ep_num);
                }
                else
                {
                    /* final ack received */
                    usb_core_transfer_complete(ep_num,                   /* ep */
                                               USB_DIR_IN,          /* dir */
                                               0,                   /* status */
                                               endpoints[ep_num].len); /* length */
                
                    /* release semaphore for blocking transfer */
                    if (endpoints[ep_num].block)
                        semaphore_release(&endpoints[ep_num].complete);
                }
            }
        }
    }
}
示例#3
0
/* IRQ handler */
void INT_USB_FUNC(void)
{
    int i;
    uint32_t ints = GINTSTS;
    uint32_t epints;
    if (ints & 0x1000)  /* bus reset */
    {
        DCFG = 4;  /* Address 0 */
        reset_endpoints(1);
        usb_core_bus_reset();
    }

    if (ints & 0x2000)  /* enumeration done, we now know the speed */
    {
        /* Set up the maximum packet sizes accordingly */
        uint32_t maxpacket = usb_drv_port_speed() ? 512 : 64;
        DIEPCTL1 = (DIEPCTL1 & ~0x000003FF) | maxpacket;
        DOEPCTL2 = (DOEPCTL2 & ~0x000003FF) | maxpacket;
        DIEPCTL3 = (DIEPCTL3 & ~0x000003FF) | maxpacket;
        DOEPCTL4 = (DOEPCTL4 & ~0x000003FF) | maxpacket;
    }

    if (ints & 0x40000)  /* IN EP event */
        for (i = 0; i < 4; i += i + 1)  // 0, 1, 3
            if ((epints = DIEPINT(i)))
            {
                if (epints & 1)  /* Transfer completed */
                {
                    invalidate_dcache();
                    int bytes = endpoints[i].size - (DIEPTSIZ(i) & 0x3FFFF);
                    if (endpoints[i].busy)
                    {
                        endpoints[i].busy = false;
                        endpoints[i].rc = 0;
                        endpoints[i].done = true;
                        usb_core_transfer_complete(i, USB_DIR_IN, 0, bytes);
                        semaphore_release(&endpoints[i].complete);
                    }
                }
                if (epints & 4)  /* AHB error */
                    panicf("USB: AHB error on IN EP%d", i);
                if (epints & 8)  /* Timeout */
                {
                    if (endpoints[i].busy)
                    {
                        endpoints[i].busy = false;
                        endpoints[i].rc = 1;
                        endpoints[i].done = true;
                        semaphore_release(&endpoints[i].complete);
                    }
                }
                DIEPINT(i) = epints;
            }

    if (ints & 0x80000)  /* OUT EP event */
        for (i = 0; i < USB_NUM_ENDPOINTS; i += 2)
            if ((epints = DOEPINT(i)))
            {
                if (epints & 1)  /* Transfer completed */
                {
                    invalidate_dcache();
                    int bytes = endpoints[i].size - (DOEPTSIZ(i) & 0x3FFFF);
                    if (endpoints[i].busy)
                    {
                        endpoints[i].busy = false;
                        endpoints[i].rc = 0;
                        endpoints[i].done = true;
                        usb_core_transfer_complete(i, USB_DIR_OUT, 0, bytes);
                        semaphore_release(&endpoints[i].complete);
                    }
                }
                if (epints & 4)  /* AHB error */
                    panicf("USB: AHB error on OUT EP%d", i);
                if (epints & 8)  /* SETUP phase done */
                {
                    invalidate_dcache();
                    if (i == 0)
                    {
                        if (ctrlreq.bRequest == 5)
                        {
                            /* Already set the new address here,
                               before passing the packet to the core.
                               See below (usb_drv_set_address) for details. */
                            DCFG = (DCFG & ~0x7F0) | (ctrlreq.wValue << 4);
                        }
                        usb_core_control_request(&ctrlreq);
                    }
                    else panicf("USB: SETUP done on OUT EP%d!?", i);
                }
                /* Make sure EP0 OUT is set up to accept the next request */
                if (!i)
                {
                    DOEPTSIZ0 = 0x20080040;
                    DOEPDMA0 = &ctrlreq;
                    DOEPCTL0 |= 0x84000000;
                }
                DOEPINT(i) = epints;
            }

    GINTSTS = ints;
}
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);
}
示例#5
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;
}