From 72d1d19ae7f84c30cf73469d4de73e92d9fbc9ad Mon Sep 17 00:00:00 2001 From: Marcin Bukat Date: Sun, 15 Jun 2014 11:06:29 +0200 Subject: hwstub: fix usb driver for rk27xx Change-Id: I299e76837715c320987177eaea8459f8f199cb96 --- utils/hwstub/stub/rk27xx/usb_drv_rk27xx.c | 78 ++++++++++++++++++++----------- 1 file changed, 50 insertions(+), 28 deletions(-) diff --git a/utils/hwstub/stub/rk27xx/usb_drv_rk27xx.c b/utils/hwstub/stub/rk27xx/usb_drv_rk27xx.c index 6a9293334a..3706e76b35 100644 --- a/utils/hwstub/stub/rk27xx/usb_drv_rk27xx.c +++ b/utils/hwstub/stub/rk27xx/usb_drv_rk27xx.c @@ -52,6 +52,7 @@ volatile bool setup_data_valid = false; static volatile uint32_t setup_data[2]; static volatile bool usb_drv_send_done = false; +static volatile bool usb_drv_rcv_done = false; void usb_drv_configure_endpoint(int ep_num, int type) { @@ -81,7 +82,7 @@ static void setup_irq_handler(void) } /* service ep0 IN transaction */ -static void ctr_write(void) +static void ep0_in_dma_setup(void) { int xfer_size = MIN(ctrlep[DIR_IN].cnt, CTL_MAX_SIZE); @@ -91,31 +92,20 @@ static void ctr_write(void) TX0STAT = xfer_size; /* size of the transfer */ TX0DMALM_IADDR = (uint32_t)ctrlep[DIR_IN].buf; /* local buffer address */ TX0DMAINCTL = DMA_START; /* start DMA */ - TX0CON &= ~TXNAK; /* 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. - */ ctrlep[DIR_IN].cnt -= CTL_MAX_SIZE; ctrlep[DIR_IN].buf += xfer_size; + + TX0CON &= ~TXNAK; /* clear NAK */ } -static void ctr_read(void) +static void ep0_out_dma_setup(void) { - int xfer_size = RX0STAT & 0xffff; + RX0DMAOUTLMADDR = (uint32_t)ctrlep[DIR_OUT].buf; /* buffer address */ + RX0DMACTLO = DMA_START; /* start DMA */ /* clear NAK bit */ RX0CON &= ~RXNAK; - - ctrlep[DIR_OUT].cnt -= xfer_size; - ctrlep[DIR_OUT].buf += xfer_size; - - RX0DMAOUTLMADDR = (uint32_t)ctrlep[DIR_OUT].buf; /* buffer address */ - RX0DMACTLO = DMA_START; /* start DMA */ } static void udc_phy_reset(void) @@ -158,7 +148,7 @@ int usb_drv_send(int endpoint, void *ptr, int length) ep->buf = ptr; ep->len = ep->cnt = length; - ctr_write(); + ep0_in_dma_setup(); /* wait for transfer to end */ while(!usb_drv_send_done) @@ -169,7 +159,7 @@ int usb_drv_send(int endpoint, void *ptr, int length) return 0; } -/* Setup a receive transfer. (non blocking) */ +/* Setup a receive transfer. (blocking) */ int usb_drv_recv(int endpoint, void* ptr, int length) { (void)endpoint; @@ -178,12 +168,23 @@ int usb_drv_recv(int endpoint, void* ptr, int length) ep->buf = ptr; ep->len = ep->cnt = length; - /* clear NAK bit */ - RX0CON &= ~RXNAK; - RX0DMAOUTLMADDR = (uint32_t)ptr; /* buffer address */ - RX0DMACTLO = DMA_START; /* start DMA */ + if (length) + { + usb_drv_rcv_done = false; - return 0; + ep0_out_dma_setup(); + + /* block here until the transfer is finished */ + while (!usb_drv_rcv_done) + ; + } + else + { + /* ZLP, clear NAK bit */ + RX0CON &= ~RXNAK; + } + + return (length - ep->cnt); } /* Stall the endpoint. Usually set a flag in the controller */ @@ -260,6 +261,8 @@ void INT_UDC(void) * endpoint does not respond to an SETUP * or OUT token */ RXNAK; /* Set as one to response NAK handshake */ + + usb_drv_rcv_done = true; } if (intsrc & SETUP_INTR) /* setup interrupt */ @@ -274,15 +277,25 @@ void INT_UDC(void) /* TODO handle errors */ if (txstat & TXACK) /* check TxACK flag */ { + /* 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. + */ if (ctrlep[DIR_IN].cnt > 0) { /* we still have data to send */ - ctr_write(); + ep0_in_dma_setup(); + } else { if (ctrlep[DIR_IN].cnt == 0) - ctr_write(); + { + ep0_in_dma_setup(); + } /* final ack received */ usb_drv_send_done = true; @@ -297,8 +310,17 @@ void INT_UDC(void) /* TODO handle errors */ if (rxstat & RXACK) /* RxACK */ { - if (ctrlep[DIR_OUT].cnt > 0) - ctr_read(); + int xfer_size = RX0STAT & 0xffff; + ctrlep[DIR_OUT].cnt -= xfer_size; + + if (ctrlep[DIR_OUT].cnt > 0 && xfer_size == 64) + { + /* advance the buffer */ + ctrlep[DIR_OUT].buf += xfer_size; + ep0_out_dma_setup(); + } + else + usb_drv_rcv_done = true; } } -- cgit