summaryrefslogtreecommitdiffstats
path: root/utils
diff options
context:
space:
mode:
Diffstat (limited to 'utils')
-rw-r--r--utils/hwstub/stub/atj213x/usb_drv_atj213x.c246
1 files changed, 142 insertions, 104 deletions
diff --git a/utils/hwstub/stub/atj213x/usb_drv_atj213x.c b/utils/hwstub/stub/atj213x/usb_drv_atj213x.c
index ef66766527..0017378473 100644
--- a/utils/hwstub/stub/atj213x/usb_drv_atj213x.c
+++ b/utils/hwstub/stub/atj213x/usb_drv_atj213x.c
@@ -31,6 +31,17 @@
volatile bool setup_data_valid = false;
volatile int udc_speed = USB_FULL_SPEED;
+struct endpoint_t
+{
+ void *buf;
+ int length;
+ bool zlp;
+ bool finished;
+};
+
+static volatile struct endpoint_t ep0in = {NULL,0,false,false};
+static volatile struct endpoint_t ep0out = {NULL,0,false,false};
+
static void usb_copy_from(void *ptr, volatile void *reg, size_t sz)
{
uint32_t *p = ptr;
@@ -67,65 +78,6 @@ static void usb_copy_to(volatile void *reg, void *ptr, size_t sz)
*rp++ = *p++;
}
-void INT_UDC(void)
-{
- /* get possible sources */
- unsigned int usbirq = OTG_USBIRQ;
- unsigned int otgirq = OTG_OTGIRQ;
-#if 0
- unsigned int usbeirq = OTG_USBEIRQ;
- unsigned int epinirq = OTG_IN04IRQ;
- unsigned int epoutirq = OTG_OUT04IRQ;
-#endif
-
- /* HS, Reset, Setup */
- if (usbirq)
- {
-
- if (usbirq & (1<<5))
- {
- /* HS irq */
- udc_speed = USB_HIGH_SPEED;
- }
- else if (usbirq & (1<<4))
- {
- /* Reset */
- udc_speed = USB_FULL_SPEED;
-
- /* clear all pending irqs */
- OTG_OUT04IRQ = 0xff;
- OTG_IN04IRQ = 0xff;
- }
- else if (usbirq & (1<<0))
- {
- /* Setup data valid */
- setup_data_valid = true;
- }
-
- /* clear irq flags */
- OTG_USBIRQ = usbirq;
- }
-
-#if 0
- if (epoutirq)
- {
- OTG_OUT04IRQ = epoutirq;
- }
-
- if (epinirq)
- {
- OTG_IN04IRQ = epinirq;
- }
-#endif
-
- if (otgirq)
- {
- OTG_OTGIRQ = otgirq;
- }
-
- OTG_USBEIRQ = 0x50;
-}
-
void usb_drv_init(void)
{
OTG_USBCS |= 0x40; /* soft disconnect */
@@ -144,9 +96,9 @@ void usb_drv_init(void)
OTG_USBIEN = (1<<5) | (1<<4) | (1<<0); /* HS, Reset, Setup_data */
OTG_OTGIEN = 0;
- /* disable interrupts from ep0 */
- OTG_IN04IEN = 0;
- OTG_OUT04IEN = 0;
+ /* enable interrupts from ep0 */
+ OTG_IN04IEN = 1;
+ OTG_OUT04IEN = 1;
/* unmask UDC interrupt in interrupt controller */
INTC_MSK = (1<<4);
@@ -183,71 +135,75 @@ void usb_drv_set_address(int address)
/* UDC sets this automaticaly */
}
+static void ep0_write(void)
+{
+ int xfer_size = MIN(ep0in.length, 64);
+
+ /* copy data to UDC buffer */
+ usb_copy_to(&OTG_EP0INDAT, ep0in.buf, xfer_size);
+ ep0in.buf += xfer_size;
+ ep0in.length -= xfer_size;
+
+ /* this marks data as ready to send */
+ OTG_IN0BC = xfer_size;
+}
+
/* TODO: Maybe adapt to irq scheme */
int usb_drv_send(int endpoint, void *ptr, int length)
{
(void)endpoint;
- int xfer_size, cnt = length;
-
- while (cnt)
+ if (length)
{
- xfer_size = MIN(cnt, 64);
+ ep0in.length = length;
+ ep0in.buf = ptr;
+ ep0in.zlp = (length % 64 == 0) ? true : false;
+ ep0in.finished = false;
- /* copy data to ep0in buffer */
- usb_copy_to(&OTG_EP0INDAT, ptr, xfer_size);
+ ep0_write();
- /* this marks data as ready to send */
- OTG_IN0BC = xfer_size;
-
- /* wait for the transfer end */
- while(OTG_EP0CS & 0x04)
+ while(!ep0in.finished)
;
-
- cnt -= xfer_size;
- ptr += xfer_size;
}
-
- /* ZLP stage */
- if((length % 64) == 0)
+ else
+ {
OTG_EP0CS = 2;
+ }
return 0;
}
+static int ep0_read(void)
+{
+ int xfer_size = OTG_OUT0BC;
+ usb_copy_from(ep0out.buf, &OTG_EP0OUTDAT, xfer_size);
+ ep0out.buf += xfer_size;
+ ep0out.length -= xfer_size;
+
+ return xfer_size;
+}
+
/* TODO: Maybe adapt to irq scheme */
int usb_drv_recv(int endpoint, void* ptr, int length)
{
(void)endpoint;
- int xfer_size, cnt = 0;
- while (cnt < length)
- {
- /* Arm receiving buffer by writing
- * any value to OUT0BC. This sets
- * OUT_BUSY bit in EP0CS until the data
- * are correctly received and ACK'd
- */
- OTG_OUT0BC = 0;
-
- while (OTG_EP0CS & 0x08)
- ;
+ ep0out.length = length;
+ ep0out.buf = ptr;
+ ep0out.zlp = (length == 0) ? true : false;
+ ep0out.finished = false;
- xfer_size = OTG_OUT0BC;
+ /* Arm receiving buffer by writing
+ * any value to OUT0BC. This sets
+ * OUT_BUSY bit in EP0CS until the data
+ * are correctly received and ACK'd
+ */
+ OTG_OUT0BC = 0;
- usb_copy_from(ptr, &OTG_EP0OUTDAT, xfer_size);
- cnt += xfer_size;
- ptr += xfer_size;
-
- if (xfer_size < 64)
- break;
- }
+ while (!ep0out.finished)
+ ;
- /* ZLP stage */
- if (length == 0)
- OTG_EP0CS = 2;
-
- return cnt;
+ return (length - ep0out.length);
}
void usb_drv_stall(int endpoint, bool stall, bool in)
@@ -265,3 +221,85 @@ void usb_drv_stall(int endpoint, bool stall, bool in)
void usb_drv_exit(void)
{
}
+
+void INT_UDC(void)
+{
+ /* get possible sources */
+ unsigned int usbirq = OTG_USBIRQ;
+ unsigned int otgirq = OTG_OTGIRQ;
+ unsigned int epinirq = OTG_IN04IRQ;
+ unsigned int epoutirq = OTG_OUT04IRQ;
+
+ /* HS, Reset, Setup */
+ if (usbirq)
+ {
+
+ if (usbirq & (1<<5))
+ {
+ /* HS irq */
+ udc_speed = USB_HIGH_SPEED;
+ }
+ else if (usbirq & (1<<4))
+ {
+ /* Reset */
+ udc_speed = USB_FULL_SPEED;
+
+ /* clear all pending irqs */
+ OTG_OUT04IRQ = 0xff;
+ OTG_IN04IRQ = 0xff;
+ }
+ else if (usbirq & (1<<0))
+ {
+ /* Setup data valid */
+ setup_data_valid = true;
+ }
+
+ /* clear irq flags */
+ OTG_USBIRQ = usbirq;
+ }
+
+ if (epoutirq)
+ {
+ if (ep0_read() == 64)
+ {
+ /* rearm receive buffer */
+ OTG_OUT0BC = 0;
+ }
+ else
+ {
+ if (ep0out.length == 0 && ep0out.zlp)
+ {
+ OTG_EP0CS = 2;
+ }
+ ep0out.finished = true;
+ }
+ OTG_OUT04IRQ = epoutirq;
+ }
+
+ if (epinirq)
+ {
+ if (ep0in.length)
+ {
+ ep0_write();
+ }
+ else
+ {
+ if (ep0in.zlp)
+ {
+ OTG_EP0CS = 2;
+ }
+
+ ep0in.finished = true;
+ }
+
+ /* ack interrupt */
+ OTG_IN04IRQ = epinirq;
+ }
+
+ if (otgirq)
+ {
+ OTG_OTGIRQ = otgirq;
+ }
+
+ OTG_USBEIRQ = 0x50;
+}