static void int_write(int ep)
{
    int ep_num = EP_NUM(ep);
    int max = usb_drv_port_speed() ? 1024 : 64;
    int xfer_size = (endpoints[ep_num].cnt > max) ? max : endpoints[ep_num].cnt;  
    unsigned int timeout = current_tick + HZ/10;
    
    while (IIN_TXBUF(ep_num) & (1<<0)) /* TXFULL flag */
    {
        if(TIME_AFTER(current_tick, timeout))
            break;
    }
    
    IIN_TXSTAT(ep_num) = xfer_size;           /* size of the transfer */
    IIN_DMAINLMADDR(ep_num) = (uint32_t)endpoints[ep_num].buf; /* buf address */
    IIN_DMAINCTL(ep_num) = (1<<0);            /* start DMA */
    IIN_TXCON(ep_num) &= ~(1<<2);             /* clear NAK */
    
    /* Decrement by max packet size is intentional.
     * This way if we have final packet short one we will get negative len
     * after transfer, which in turn indicates we *don't* need to send
     * zero length packet. If the final packet is max sized packet we will
     * get zero len after transfer which indicates we need to send
     * zero length packet to signal host end of the transfer.
     */
    endpoints[ep_num].cnt -= max;
    endpoints[ep_num].buf += xfer_size;
}
Ejemplo n.º 2
0
static void ep_transfer(int ep, void *ptr, int len, bool out)
{
    /* disable interrupts to avoid any race */
    int oldlevel = disable_irq_save();

    struct ep_type *endpoint = &endpoints[ep][out ? DIR_OUT : DIR_IN];
    endpoint->busy   = true;
    endpoint->size   = len;
    endpoint->status = -1;

    if (out)
        DEPCTL(ep, out) &= ~DEPCTL_stall;

    int mps = usb_drv_port_speed() ? 512 : 64;
    int nb_packets = (len + mps - 1) / mps;
    if (nb_packets == 0)
        nb_packets = 1;

    DEPDMA(ep, out) = len ? (void*)PHYSICAL_ADDR(ptr) : NULL;
    DEPTSIZ(ep, out) = (nb_packets << DEPTSIZ_pkcnt_bitp) | len;
    if(out)
        discard_dcache_range(ptr, len);
    else
        commit_dcache_range(ptr, len);

    logf("pkt=%d dma=%lx", nb_packets, DEPDMA(ep, out));

//    if (!out) while (((GNPTXSTS & 0xffff) << 2) < MIN(mps, length));

    DEPCTL(ep, out) |= DEPCTL_epena | DEPCTL_cnak;

    restore_irq(oldlevel);
}
Ejemplo n.º 3
0
void INT_USB_FUNC(void)
{
    /* some bits in GINTSTS can be set even though we didn't enable the interrupt source
     * so AND it with the actual mask */
    unsigned long sts = GINTSTS & GINTMSK;
    logf("usb-drv: INT 0x%lx", sts);

    if(sts & GINTMSK_usbreset)
    {
        DCFG &= ~bitm(DCFG, devadr); /* Address 0 */
        reset_endpoints();
        usb_core_bus_reset();
    }

    if(sts & GINTMSK_enumdone)  /* enumeration done, we now know the speed */
    {
        /* Set up the maximum packet sizes accordingly */
        uint32_t maxpacket = (usb_drv_port_speed() ? 512 : 64) << DEPCTL_mps_bitp;
        for (int dir = 0; dir < 2; dir++)
        {
            bool out = dir == DIR_OUT;
            for (unsigned i = 1; i < num_eps(out); i++)
            {
                int ep = (out ? out_ep_list : in_ep_list)[i];
                DEPCTL(ep, out) &= ~(DEPCTL_mps_bits << DEPCTL_mps_bitp);
                DEPCTL(ep, out) |= maxpacket;
            }
        }
    }

    if(sts & (GINTMSK_outepintr | GINTMSK_inepintr))
    {
        unsigned long daint = DAINT;

        for (int i = 0; i < USB_NUM_ENDPOINTS; i++)
        {
            if (daint & DAINT_IN_EP(i))
                handle_ep_int(i, false);
            if (daint & DAINT_OUT_EP(i))
                handle_ep_int(i, true);
        }

        DAINT = daint;
    }

    if(sts & GINTMSK_disconnect)
        cancel_all_transfers(true);

    GINTSTS = sts;
}
Ejemplo n.º 4
0
static void ep_send(int ep, const void *ptr, int length)
{
    endpoints[ep].busy = true;
    endpoints[ep].size = length;
    DIEPCTL(ep) |= 0x8000;  /* EPx OUT ACTIVE */
    int blocksize = usb_drv_port_speed() ? 512 : 64;
    int packets = (length + blocksize - 1) / blocksize;
    if (!length)
    {
        DIEPTSIZ(ep) = 1 << 19;  /* one empty packet */
        DIEPDMA(ep) = NULL;
    }
    else
    {
        DIEPTSIZ(ep) = length | (packets << 19);
        DIEPDMA(ep) = ptr;
    }
    clean_dcache();
    DIEPCTL(ep) |= 0x84000000;  /* EPx OUT ENABLE CLEARNAK */
}
Ejemplo n.º 5
0
Archivo: main.c Proyecto: ifroz/rockbox
static void handle_std_dev_desc(struct usb_ctrlrequest *req)
{
    int size;
    const void* ptr = NULL;
    unsigned index = req->wValue & 0xff;

    switch(req->wValue >> 8)
    {
        case USB_DT_DEVICE:
            ptr = &device_descriptor;
            size = sizeof(struct usb_device_descriptor);
            break;
        case USB_DT_OTHER_SPEED_CONFIG:
        case USB_DT_CONFIG:
        {
            int max_packet_size;

            /* config desc */
            if((req->wValue >> 8) ==USB_DT_CONFIG)
            {
                max_packet_size = (usb_drv_port_speed() ? 512 : 64);
                config_descriptor.bDescriptorType = USB_DT_CONFIG;
            }
            else
            {
                max_packet_size=(usb_drv_port_speed() ? 64 : 512);
                config_descriptor.bDescriptorType = USB_DT_OTHER_SPEED_CONFIG;
            }
            size = sizeof(struct usb_config_descriptor);

            /* interface */
            memcpy(usb_buffer + size, (void *)&interface_descriptor,
                sizeof(interface_descriptor));
            size += sizeof(interface_descriptor);
            /* endpoint 1: bulk out */
            endpoint_descriptor.bEndpointAddress = EP_BULK | USB_DIR_OUT;
            endpoint_descriptor.bmAttributes = USB_ENDPOINT_XFER_BULK;
            endpoint_descriptor.wMaxPacketSize = 512;
            memcpy(usb_buffer + size, (void *)&endpoint_descriptor,
                sizeof(endpoint_descriptor));
            size += sizeof(endpoint_descriptor);
            /* endpoint 2: bulk in */
            endpoint_descriptor.bEndpointAddress = EP_BULK | USB_DIR_IN;
            endpoint_descriptor.bmAttributes = USB_ENDPOINT_XFER_BULK;
            endpoint_descriptor.wMaxPacketSize = 512;
            memcpy(usb_buffer + size, (void *)&endpoint_descriptor,
                sizeof(endpoint_descriptor));
            size += sizeof(endpoint_descriptor);
            /* endpoint 3: int in */
            endpoint_descriptor.bEndpointAddress = EP_INT | USB_DIR_IN;
            endpoint_descriptor.bmAttributes = USB_ENDPOINT_XFER_INT;
            endpoint_descriptor.wMaxPacketSize = 1024;
            memcpy(usb_buffer + size, (void *)&endpoint_descriptor,
                sizeof(endpoint_descriptor));
            size += sizeof(endpoint_descriptor);

            /* fix config descriptor */
            config_descriptor.bNumInterfaces = 1;
            config_descriptor.wTotalLength = size;
            memcpy(usb_buffer, (void *)&config_descriptor, sizeof(config_descriptor));

            ptr = usb_buffer;
            break;
        }
        case USB_DT_STRING:
            if(index < USB_NUM_STRINGS)
            {
                size = usb_strings[index]->bLength;
                ptr = usb_strings[index];
            }
            else
                usb_drv_stall(EP_CONTROL, true, true);
            break;
        default:
            break;
    }
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);
}
Ejemplo n.º 7
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;
}
Ejemplo n.º 8
0
static void handle_std_dev_desc(struct usb_ctrlrequest *req)
{
    int size;
    void* ptr = NULL;
    unsigned index = req->wValue & 0xff;

    switch(req->wValue >> 8)
    {
        case USB_DT_DEVICE:
            ptr = &device_descriptor;
            size = sizeof(struct usb_device_descriptor);
            break;
        case USB_DT_OTHER_SPEED_CONFIG:
        case USB_DT_CONFIG:
        {
            int max_packet_size;

            /* config desc */
            if((req->wValue >> 8) ==USB_DT_CONFIG)
            {
                max_packet_size = (usb_drv_port_speed() ? 512 : 64);
                config_descriptor.bDescriptorType = USB_DT_CONFIG;
            }
            else
            {
                max_packet_size=(usb_drv_port_speed() ? 64 : 512);
                config_descriptor.bDescriptorType = USB_DT_OTHER_SPEED_CONFIG;
            }
            size = sizeof(struct usb_config_descriptor);

            /* hwstub version */
            memcpy(usb_buffer + size, (void *)&version_descriptor,
                sizeof(version_descriptor));
            size += sizeof(version_descriptor);
            /* hwstub layout */
            fill_layout_info();
            memcpy(usb_buffer + size, (void *)&layout_descriptor,
                sizeof(layout_descriptor));
            size += sizeof(layout_descriptor);
            /* hwstub target */
            fill_layout_info();
            memcpy(usb_buffer + size, (void *)&target_descriptor,
                sizeof(target_descriptor));
            size += sizeof(target_descriptor);
            /* target specific descriptors */
            target_get_config_desc(usb_buffer + size, &size);
            /* fix config descriptor */
            config_descriptor.bNumInterfaces = 1;
            config_descriptor.wTotalLength = size;
            memcpy(usb_buffer, (void *)&config_descriptor, sizeof(config_descriptor));

            ptr = usb_buffer;
            break;
        }
        case USB_DT_STRING:
            if(index < USB_NUM_STRINGS)
            {
                size = usb_strings[index]->bLength;
                ptr = (void *)usb_strings[index];
            }
            else
                usb_drv_stall(EP_CONTROL, true, true);
            break;
        case HWSTUB_DT_VERSION:
            ptr = &version_descriptor;
            size = sizeof(version_descriptor);
            break;
        case HWSTUB_DT_LAYOUT:
            ptr = &layout_descriptor;
            size = sizeof(layout_descriptor);
            break;
        case HWSTUB_DT_TARGET:
            ptr = &target_descriptor;
            size = sizeof(target_descriptor);
            break;
        default:
            target_get_desc(req->wValue >> 8, &ptr);
            if(ptr != 0)
                size = ((struct usb_descriptor_header *)ptr)->bLength;
            break;
    }