Index: firmware/export/config.h =================================================================== --- firmware/export/config.h (revision 14237) +++ firmware/export/config.h (working copy) @@ -334,7 +334,7 @@ #define ICODE_ATTR __attribute__ ((section(".icode"))) #define ICONST_ATTR __attribute__ ((section(".irodata"))) #define IDATA_ATTR __attribute__ ((section(".idata"))) -#define IBSS_ATTR __attribute__ ((section(".ibss"))) +#define IBSS_ATTR #define USE_IRAM #if CONFIG_CPU != SH7034 #define IRAM_STEAL Index: firmware/target/arm/usb-fw-pp502x.c =================================================================== --- firmware/target/arm/usb-fw-pp502x.c (revision 14237) +++ firmware/target/arm/usb-fw-pp502x.c (working copy) @@ -85,9 +85,8 @@ outl(inl(0x70000028) | 0x2, 0x70000028); udelay(0x186A0); + arcotg_init(); - dr_controller_setup(); - #if defined(IPOD_COLOR) || defined(IPOD_4G) \ || defined(IPOD_MINI) || defined(IPOD_MINI2G) /* GPIO C bit 1 is firewire detect */ Index: firmware/target/arm/system-pp502x.c =================================================================== --- firmware/target/arm/system-pp502x.c (revision 14237) +++ firmware/target/arm/system-pp502x.c (working copy) @@ -29,6 +29,7 @@ extern void TIMER2(void); extern void ipod_mini_button_int(void); /* iPod Mini 1st gen only */ extern void ipod_4g_button_int(void); /* iPod 4th gen and higher only */ +extern void usb_int(void); #ifdef SANSA_E200 extern void button_int(void); extern void clickwheel_int(void); @@ -39,9 +40,10 @@ { if(CURRENT_CORE == CPU) { - if (CPU_INT_STAT & TIMER1_MASK) + if (CPU_INT_STAT & TIMER1_MASK) { TIMER1(); - else if (CPU_INT_STAT & TIMER2_MASK) + usb_int(); + } else if (CPU_INT_STAT & TIMER2_MASK) TIMER2(); #if defined(IPOD_MINI) /* Mini 1st gen only, mini 2nd gen uses iPod 4G code */ else if (CPU_HI_INT_STAT & GPIO_MASK) Index: firmware/drivers/arcotg_udc.c =================================================================== --- firmware/drivers/arcotg_udc.c (revision 14237) +++ firmware/drivers/arcotg_udc.c (working copy) @@ -31,105 +31,620 @@ * KIND, either express or implied. * ****************************************************************************/ -#include "arcotg_udc.h" #include "logf.h" +#include "kernel.h" +#include "system.h" +#include -static int timeout; +#define UOG_USBCMD (*(volatile int *)0xc5000140) +#define UOG_USBSTS (*(volatile int *)0xc5000144) +#define UOG_DEVICEADDR (*(volatile int *)0xc5000154) +#define UOG_ENDPOINTLISTADDR (*(volatile int *)0xc5000158) +#define UOG_PORTSC0 (*(volatile int *)0xc5000184) +#define UOG_USBMODE (*(volatile int *)0xc50001a8) +#define UOG_ENDPTSETUPSTAT (*(volatile int *)0xc50001ac) +#define UOG_ENDPTPRIME (*(volatile int *)0xc50001b0) +#define UOG_ENDPTFLUSH (*(volatile int *)0xc50001b4) +#define UOG_ENDPTSTAT (*(volatile int *)0xc50001b8) +#define UOG_ENDPTCOMPLETE (*(volatile int *)0xc50001bc) +#define UOG_ENDPTCTRL0 (*(volatile int *)0xc50001c0) +#define UOG_ENDPTCTRL0 (*(volatile int *)0xc50001c0) +#define UOG_CONTROL (*(volatile int *)0xc5000600) -/* @qh_addr is the aligned virt addr of ep QH addr - * it is used to set endpointlistaddr Reg */ -/* was static int dr_controller_setup(void *qh_addr) */ -int dr_controller_setup(void) +#define MAX_PACKET_SIZE 64 + +#define MIN(x, y) ((x) < (y) ? (x) : (y)) + +#define ERROR_TIMEOUT (-3) +#define ERROR_UNKNOWN (-7) + +#define PRIME_TIMER 1000000 +#define TRANSFER_TIMER 10000000 +#define RESET_TIMER 50000000 + +#define OWN_VENDOR_ID 0x6666 +#define OWN_PRODUCT_ID 0xe200 +#define OWN_PRODUCT_REV 0x0001 + +#define BUFFER_SIZE 4096 + +#define USB_BUS_RESET (UOG_USBSTS & (1 << 6)) + +#define PRIME_TIMER 100000 +#define TRANSFER_TIMER 1000000 +#define RESET_TIMER 5000000 + +/* forward declaration */ +void usb_handle_reset(); + +struct dtd { + unsigned int next_dtd; + unsigned int dtd_token; + unsigned int buf_ptr0; + unsigned int buf_ptr1; + unsigned int buf_ptr2; + unsigned int buf_ptr3; + unsigned int buf_ptr4; + unsigned int pad; /* pad to 32 bytes */ +} __attribute((packed)); + +struct dqh { + unsigned int endpt_cap; + unsigned int cur_dtd; + struct dtd dtd_ovrl; + unsigned int setup_buf[2]; + unsigned int pad[4]; /* pad to 64 bytes */ +} __attribute((packed)); + +struct spkt { + unsigned char bmRequestType; + unsigned char bRequest; + unsigned short wValue; + unsigned short wIndex; + unsigned short wLength; +} __attribute((packed)); + +struct devdsc { + unsigned char bLength; + unsigned char bDescriptorType; + unsigned short bcdUSB; + unsigned char bDeviceClass; + unsigned char bDeviceSubClass; + unsigned char bDeviceProtocol; + unsigned char bMaxPacketSize0; + unsigned short idVendor; + unsigned short idProduct; + unsigned short bcdDevice; + unsigned char iManufacturer; + unsigned char iProduct; + unsigned char iSerialNumber; + unsigned char bNumConfigurations; +} __attribute((packed)); + +struct dqdsc { + unsigned char bLength; + unsigned char bDescriptorType; + unsigned short bcdUSB; + unsigned char bDeviceClass; + unsigned char bDeviceSubClass; + unsigned char bDeviceProtocol; + unsigned char bMaxPacketSize0; + unsigned char bNumConfigurations; + unsigned char bReserved; +} __attribute((packed)); + +struct confdsc { + unsigned char bLength; + unsigned char bDescriptorType; + unsigned short wTotalLength; + unsigned char bNumInterfaces; + unsigned char bConfigurationValue; + unsigned char iConfiguration; + unsigned char bmAttributes; + unsigned char bMaxPower; +} __attribute((packed)); + +struct ifdsc { + unsigned char bLength; + unsigned char bDescriptorType; + unsigned char bInterfaceNumber; + unsigned char bAlternateSetting; + unsigned char bNumEndpoints; + unsigned char bInterfaceClass; + unsigned char bInterfaceSubClass; + unsigned char bInterfaceProtocol; + unsigned char iInterface; +} __attribute((packed)); + +struct epdsc { + unsigned char bLength; + unsigned char bDescriptorType; + unsigned char bEndpointAddress; + unsigned char bmAttributes; + unsigned short wMaxPacketSize; + unsigned char bInterval; +} __attribute((packed)); + +#define DEVDSC_INIT \ + .bcdUSB = 0x0200, \ + .bDeviceClass = 0xff, \ + .bDeviceSubClass = 0xff, \ + .bDeviceProtocol = 0xff, \ + .bMaxPacketSize0 = MAX_PACKET_SIZE, \ + .bNumConfigurations = 1 + + +struct devdsc devdsc __attribute__ ((section(".ibss"))) = { + .bLength = sizeof(struct devdsc), + .bDescriptorType = 1, + .idVendor = OWN_VENDOR_ID, + .idProduct = OWN_PRODUCT_ID, + .bcdDevice = OWN_PRODUCT_REV, + DEVDSC_INIT +}; + +struct dqdsc dqdsc __attribute__ ((section(".ibss"))) = { + .bLength = sizeof(struct dqdsc), + .bDescriptorType = 6, + DEVDSC_INIT +}; + +struct confdata { + struct confdsc conf; + struct ifdsc iface; +} __attribute((packed)); + +struct confdata confdata __attribute__ ((section(".ibss"))) = { + .conf.bLength = sizeof(struct confdsc), + .conf.bDescriptorType = 2, + .conf.wTotalLength = sizeof(struct confdata), + .conf.bNumInterfaces = 1, + .conf.bConfigurationValue = 1, + .conf.bmAttributes = 0xc0, + .conf.bMaxPower = 250, + + .iface.bLength = sizeof(struct ifdsc), + .iface.bDescriptorType = 4, + .iface.bInterfaceNumber = 0, + .iface.bAlternateSetting = 0, + .iface.bNumEndpoints = 0, + .iface.bInterfaceClass = 0xff, + .iface.bInterfaceSubClass = 0xff, + .iface.bInterfaceProtocol = 0xff, +}; + +struct dtd dev_td[2] __attribute((aligned (32))) __attribute__ ((section(".ibss"))); + +#define HOST2DEV 0 +#define DEV2HOST 1 + +struct dqh dev_qh[2] __attribute((aligned (1 << 11))) __attribute__ ((section(".ibss"))); + +unsigned char buffer[BUFFER_SIZE] __attribute((aligned (1 << 12))) __attribute__ ((section(".ibss"))); + +void +dqh_init(int dir) { -#if 0 - struct arc_usb_config *config; + struct dqh * const dqh = &dev_qh[dir]; - config = udc_controller->config; + memset(dqh, 0, sizeof(*dqh)); - /* before here, make sure usb_slave_regs has been initialized */ - if (!qh_addr) - return -EINVAL; -#endif + dqh->endpt_cap = (MAX_PACKET_SIZE << 16); - /* Stop and reset the usb controller */ - UDC_USBCMD &= ~USB_CMD_RUN_STOP; + dqh->dtd_ovrl.next_dtd = 1; + dqh->dtd_ovrl.dtd_token = 0; +} - UDC_USBCMD |= USB_CMD_CTRL_RESET; +void +dtd_init(int dir, void * buf, int size) +{ + struct dtd * const dtd = &dev_td[dir]; - /* Wait for reset to complete */ - timeout = 10000000; - while ((UDC_USBCMD & USB_CMD_CTRL_RESET) && - --timeout) { - continue; + dtd->next_dtd = 1; + dtd->dtd_token = (size << 16) | (1 << 7); + + dtd->buf_ptr0 = (unsigned int)buf; + dtd->buf_ptr1 = 0; + dtd->buf_ptr2 = 0; + dtd->buf_ptr3 = 0; + dtd->buf_ptr4 = 0; +} + +int +dtd_enqueue(int dir) +{ + + unsigned int timeout = PRIME_TIMER; + const unsigned int mask = 1 << (dir * 16); + struct dqh * const dqh = &dev_qh[dir]; + struct dtd * const dtd = &dev_td[dir]; + + dqh->dtd_ovrl.next_dtd = (unsigned int)dtd; + dqh->dtd_ovrl.dtd_token &= ~0xc0; + + logf("flushing icache"); + /* flush cache */ + flush_icache(); + + UOG_ENDPTPRIME |= mask; + + while ((UOG_ENDPTPRIME & mask) || (timeout--) > 0) { + if (USB_BUS_RESET) { + usb_handle_reset(); } - if (timeout == 0) { - logf("%s: TIMEOUT", __FUNCTION__); - return -ETIMEDOUT; + } + + if ((timeout--) <= 0) { + logf("timeout->prime"); + } + + if ((UOG_ENDPTSTAT & mask) == 0) { + logf("Endptstat 0x%x", UOG_ENDPTSTAT); + logf("HW_ERROR"); + } + + return 0; +} + +int +dtd_wait(int dir) +{ + const unsigned int mask = 1 << (dir * 16); + unsigned int timeout = TRANSFER_TIMER; + struct dtd * const dtd = &dev_td[dir]; + + for (;;) { + if (USB_BUS_RESET) { + usb_handle_reset(); } - /* Set the controller as device mode and disable setup lockout */ - UDC_USBMODE |= (USB_MODE_CTRL_MODE_DEVICE | USB_MODE_SETUP_LOCK_OFF); + if ((UOG_ENDPTCOMPLETE & mask) != 0) { + UOG_ENDPTCOMPLETE |= mask; + } - /* Clear the setup status */ - UDC_USBSTS = 0; -#if 0 - UDC_ENDPOINTLISTADDR = (unsigned int)qh_addr & USB_EP_LIST_ADDRESS_MASK; - - VDBG("qh_addr=0x%x epla_reg=0x%8x", qh_addr, UOG_ASYNCLISTADDR); -#endif - UDC_PORTSC1 = (UDC_PORTSC1 & ~PORTSCX_PHY_TYPE_SEL) | PORTSCX_PTS_UTMI; -#if 0 - if (config->set_vbus_power) - config->set_vbus_power(0); -#endif + if ((dtd->dtd_token & (1 << 7)) == 0) { + return 0; + } + if ((timeout--) <= 0) { + return ERROR_TIMEOUT; + } + + } +} + +int +dtd_execute(int dir) +{ + int ret; + + ret = dtd_enqueue(dir); + + if (ret == 0) { + ret = dtd_wait(dir); + } + + return ret; +} + +int +usb_send(const void * buf, int size) +{ + const char * ptr = buf; + int todo, done = 0; + int error; + + do { + if (USB_BUS_RESET) { + usb_handle_reset(); + } + + todo = MIN(size, BUFFER_SIZE); + + memcpy(buffer, ptr, todo); + + dtd_init(DEV2HOST, buffer, todo); + error = dtd_execute(DEV2HOST); + + if (error) { + done = error; + break; + } + + size -= todo; + ptr += todo; + done += todo; + + } while (size > 0); + + return done; +} + +int +usb_receive(void * buf, int size) +{ + char * ptr = buf; + int todo, done = 0; + int error; + + do { + if (USB_BUS_RESET) { + usb_handle_reset(); + } + + todo = MIN(size, BUFFER_SIZE); + + dtd_init(HOST2DEV, buffer, size); + error = dtd_execute(HOST2DEV); + + if (error) { + done = error; + break; + } + + memcpy(ptr, buffer, todo); + + size -= todo; + ptr += todo; + done += todo; + + } while (size > 0); + + return done; +} + +int +usb_ack(struct spkt * s, int error) +{ + if (USB_BUS_RESET) { + usb_handle_reset(); + } + + if (error) { + UOG_ENDPTCTRL0 |= 1 << 16; /* stall */ return 0; + } + + if (s->bmRequestType & 0x80) { + return usb_receive(NULL, 0); + } else { + return usb_send(NULL, 0); + } } + +int +usb_handle_setup_dev_get_desc(struct spkt * s) +{ + int ret; -/* just Enable DR irq reg and Set Dr controller Run */ -/* was static void dr_controller_run(struct arcotg_udc *udc) */ -void dr_controller_run(void) + switch (s->wValue >> 8) { + case 0x01 : /* device descriptor */ + ret = usb_send(&devdsc, MIN(sizeof(devdsc), s->wLength)); + break; + case 0x02 : /* configuration descriptor */ + ret = usb_send(&confdata, MIN(sizeof(confdata), s->wLength)); + break; + case 0x06 : /* device qualifier descriptor */ + ret = usb_send(&dqdsc, MIN(sizeof(dqdsc), s->wLength)); + break; + default : + ret = ERROR_UNKNOWN; + } + + return ret; +} + +int +usb_handle_setup_dev_std(struct spkt * s) { - /*Enable DR irq reg */ - UDC_USBINTR = USB_INTR_INT_EN | USB_INTR_ERR_INT_EN | - USB_INTR_PTC_DETECT_EN | USB_INTR_RESET_EN | - USB_INTR_DEVICE_SUSPEND | USB_INTR_SYS_ERR_EN; -#if 0 - /* Clear stopped bit */ - udc->stopped = 0; -#endif - /* Set the controller as device mode */ - UDC_USBMODE |= USB_MODE_CTRL_MODE_DEVICE; + const unsigned char conf = 1; + const unsigned short status = 0; + int ret, error = 0; - /* Set controller to Run */ - UDC_USBCMD |= USB_CMD_RUN_STOP; + switch (s->bRequest) { + case 0x00 : /* get status */ + ret = usb_send(&status, MIN(sizeof(status), s->wLength)); + break; + case 0x05 : /* set address */ + ret = 0; + break; + case 0x06 : /* get descriptor */ + ret = usb_handle_setup_dev_get_desc(s); + break; + case 0x08 : /* get configuration */ + ret = usb_send(&conf, MIN(sizeof(conf), s->wLength)); + break; + case 0x09 : /* set configuration */ + ret = 0; + break; + default : + ret = ERROR_UNKNOWN; + } - return; + if (ret < 0) { + error = ret; + } + + /* ACK the transfer */ + + usb_ack(s, error); + + if (s->bRequest == 0x05) { /* set address, must be set after ack */ + UOG_DEVICEADDR = s->wValue << 25; + } + + return 0; } -/* just Enable DR irq reg and Set Dr controller Run */ -/* was static void dr_controller_stop(struct arcotg_udc *udc) */ -void dr_controller_stop(void) +int +usb_handle_setup_dev_vnd(struct spkt * s) { -#if 0 - /* if we're in OTG mode, and the Host is currently using the port, - * stop now and don't rip the controller out from under the - * ehci driver - */ - if (udc->gadget.is_otg) { - if (!(UDC_OTGSC & OTGSC_STS_USB_ID)) { - logf("Leaving early"); - return; - } - } -#endif + int ret, error = 0; + unsigned int val = 0; - /* disable all INTR */ - UDC_USBINTR = 0; -#if 0 - /* Set stopped bit */ - udc->stopped = 1; -#endif - /* Set controller to Stop */ - UDC_USBCMD &= ~USB_CMD_RUN_STOP; + ret = 0; + + if (ret < 0) { + error = ret; + } + + /* ACK the transfer */ + + usb_ack(s, error); + + return 0; } + +int +usb_handle_setup_dev(struct spkt * s) +{ + switch ((s->bmRequestType >> 5) & 3) { + case 0x00 : + return usb_handle_setup_dev_std(s); + case 0x02 : + return usb_handle_setup_dev_vnd(s); + } + + return 0; +} + +int +usb_handle_setup_if_std(struct spkt * s) +{ + int error; + + switch (s->bRequest) { + case 0x0b : /* set interface */ + error = 0; + break; + default : + error = ERROR_UNKNOWN; + break; + } + + usb_ack(s, error); + + return 0; +} + +int +usb_handle_setup_if(struct spkt * s) +{ + switch ((s->bmRequestType >> 5) & 3) { + case 0x00 : + return usb_handle_setup_if_std(s); + } + + return usb_ack(s, ERROR_UNKNOWN); +} + +int +usb_handle_setup_ep(struct spkt * s) +{ + return usb_ack(s, ERROR_UNKNOWN); +} + +int +usb_handle_setup(struct spkt * s) +{ + switch (s->bmRequestType & 0x1f) { + case 0x00 : + return usb_handle_setup_dev(s); + case 0x01 : + return usb_handle_setup_if(s); + case 0x02 : + return usb_handle_setup_ep(s); + } + + logf("should never happen"); + return -1; +} + +void +usb_handle_reset(void) +{ + unsigned int timeout = RESET_TIMER; + UOG_ENDPTSETUPSTAT = UOG_ENDPTSETUPSTAT; + UOG_ENDPTCOMPLETE = UOG_ENDPTCOMPLETE; + + while (UOG_ENDPTPRIME) { /* prime and flush pending transfers */ + if ((timeout--) <= 0) { + logf("TIMEOUT->p&f"); + } + } + + UOG_ENDPTFLUSH = ~0; + + if ((UOG_PORTSC0 & (1 << 8)) == 0) { + logf("TIMEOUT->port"); + } + + UOG_USBSTS = (1 << 6); + + while ((UOG_USBSTS & (1 << 2)) == 0) { /* wait for port change */ + if ((timeout--) <= 0) { + logf("TIMEOUT->portchange"); + } + } + + UOG_USBSTS = (1 << 2); +} + +void usb_int() { + struct spkt spkt; + + if (USB_BUS_RESET) { + usb_handle_reset(); + } + + if ((UOG_ENDPTSETUPSTAT & 0x1) != 0) { + memcpy(&spkt, dev_qh[0].setup_buf, sizeof(spkt)); + logf("invalidate icache"); + /* invalidate cache */ + invalidate_icache(); + + UOG_ENDPTSETUPSTAT = UOG_ENDPTSETUPSTAT; + logf("recived packet"); + usb_handle_setup(&spkt); + } +} + +void arcotg_init() { + + unsigned int timeout = RESET_TIMER; + UOG_USBCMD &= ~(1 << 0); /* stop */ + + sleep(HZ/2); /* is this equal to usleep(50000)? */ + + UOG_USBCMD |= (1 << 1); /* reset */ + + while ((UOG_USBCMD & (1 << 1)) || (timeout--) > 0) { + } + + if (timeout <= 0) { + logf("TIMEOUT->init"); + } + + /* Configure the controller */ + + UOG_USBMODE = 2; /* device mode */ + + logf("1) 0x%x", UOG_CONTROL); + UOG_CONTROL |= (1 << 4) | (1 << 5); + logf("2) 0x%x", UOG_CONTROL); + + /* Init queue heads */ + + dqh_init(HOST2DEV); + dqh_init(DEV2HOST); + + UOG_ENDPOINTLISTADDR = (unsigned int)dev_qh; +} + +void dr_controller_run() { + /* Start the device */ + UOG_USBCMD |= (1 << 0); /* run */ +} + +void dr_controller_stop() { +}