summaryrefslogtreecommitdiff
path: root/utils
diff options
context:
space:
mode:
authorMarcin Bukat <marcin.bukat@gmail.com>2014-06-15 11:06:29 +0200
committerMarcin Bukat <marcin.bukat@gmail.com>2014-06-15 12:49:56 +0200
commit72d1d19ae7f84c30cf73469d4de73e92d9fbc9ad (patch)
treeb9357cce6ae1caa009dddc56317a1f1238c63551 /utils
parentbc376654d41432751a07f4999334155c7bc276aa (diff)
downloadrockbox-72d1d19ae7f84c30cf73469d4de73e92d9fbc9ad.tar.gz
rockbox-72d1d19ae7f84c30cf73469d4de73e92d9fbc9ad.zip
hwstub: fix usb driver for rk27xx
Change-Id: I299e76837715c320987177eaea8459f8f199cb96
Diffstat (limited to 'utils')
-rw-r--r--utils/hwstub/stub/rk27xx/usb_drv_rk27xx.c78
1 files 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;
52static volatile uint32_t setup_data[2]; 52static volatile uint32_t setup_data[2];
53 53
54static volatile bool usb_drv_send_done = false; 54static volatile bool usb_drv_send_done = false;
55static volatile bool usb_drv_rcv_done = false;
55 56
56void usb_drv_configure_endpoint(int ep_num, int type) 57void usb_drv_configure_endpoint(int ep_num, int type)
57{ 58{
@@ -81,7 +82,7 @@ static void setup_irq_handler(void)
81} 82}
82 83
83/* service ep0 IN transaction */ 84/* service ep0 IN transaction */
84static void ctr_write(void) 85static void ep0_in_dma_setup(void)
85{ 86{
86 int xfer_size = MIN(ctrlep[DIR_IN].cnt, CTL_MAX_SIZE); 87 int xfer_size = MIN(ctrlep[DIR_IN].cnt, CTL_MAX_SIZE);
87 88
@@ -91,31 +92,20 @@ static void ctr_write(void)
91 TX0STAT = xfer_size; /* size of the transfer */ 92 TX0STAT = xfer_size; /* size of the transfer */
92 TX0DMALM_IADDR = (uint32_t)ctrlep[DIR_IN].buf; /* local buffer address */ 93 TX0DMALM_IADDR = (uint32_t)ctrlep[DIR_IN].buf; /* local buffer address */
93 TX0DMAINCTL = DMA_START; /* start DMA */ 94 TX0DMAINCTL = DMA_START; /* start DMA */
94 TX0CON &= ~TXNAK; /* clear NAK */
95 95
96 /* Decrement by max packet size is intentional.
97 * This way if we have final packet short one we will get negative len
98 * after transfer, which in turn indicates we *don't* need to send
99 * zero length packet. If the final packet is max sized packet we will
100 * get zero len after transfer which indicates we need to send
101 * zero length packet to signal host end of the transfer.
102 */
103 ctrlep[DIR_IN].cnt -= CTL_MAX_SIZE; 96 ctrlep[DIR_IN].cnt -= CTL_MAX_SIZE;
104 ctrlep[DIR_IN].buf += xfer_size; 97 ctrlep[DIR_IN].buf += xfer_size;
98
99 TX0CON &= ~TXNAK; /* clear NAK */
105} 100}
106 101
107static void ctr_read(void) 102static void ep0_out_dma_setup(void)
108{ 103{
109 int xfer_size = RX0STAT & 0xffff; 104 RX0DMAOUTLMADDR = (uint32_t)ctrlep[DIR_OUT].buf; /* buffer address */
105 RX0DMACTLO = DMA_START; /* start DMA */
110 106
111 /* clear NAK bit */ 107 /* clear NAK bit */
112 RX0CON &= ~RXNAK; 108 RX0CON &= ~RXNAK;
113
114 ctrlep[DIR_OUT].cnt -= xfer_size;
115 ctrlep[DIR_OUT].buf += xfer_size;
116
117 RX0DMAOUTLMADDR = (uint32_t)ctrlep[DIR_OUT].buf; /* buffer address */
118 RX0DMACTLO = DMA_START; /* start DMA */
119} 109}
120 110
121static void udc_phy_reset(void) 111static void udc_phy_reset(void)
@@ -158,7 +148,7 @@ int usb_drv_send(int endpoint, void *ptr, int length)
158 ep->buf = ptr; 148 ep->buf = ptr;
159 ep->len = ep->cnt = length; 149 ep->len = ep->cnt = length;
160 150
161 ctr_write(); 151 ep0_in_dma_setup();
162 152
163 /* wait for transfer to end */ 153 /* wait for transfer to end */
164 while(!usb_drv_send_done) 154 while(!usb_drv_send_done)
@@ -169,7 +159,7 @@ int usb_drv_send(int endpoint, void *ptr, int length)
169 return 0; 159 return 0;
170} 160}
171 161
172/* Setup a receive transfer. (non blocking) */ 162/* Setup a receive transfer. (blocking) */
173int usb_drv_recv(int endpoint, void* ptr, int length) 163int usb_drv_recv(int endpoint, void* ptr, int length)
174{ 164{
175 (void)endpoint; 165 (void)endpoint;
@@ -178,12 +168,23 @@ int usb_drv_recv(int endpoint, void* ptr, int length)
178 ep->buf = ptr; 168 ep->buf = ptr;
179 ep->len = ep->cnt = length; 169 ep->len = ep->cnt = length;
180 170
181 /* clear NAK bit */ 171 if (length)
182 RX0CON &= ~RXNAK; 172 {
183 RX0DMAOUTLMADDR = (uint32_t)ptr; /* buffer address */ 173 usb_drv_rcv_done = false;
184 RX0DMACTLO = DMA_START; /* start DMA */
185 174
186 return 0; 175 ep0_out_dma_setup();
176
177 /* block here until the transfer is finished */
178 while (!usb_drv_rcv_done)
179 ;
180 }
181 else
182 {
183 /* ZLP, clear NAK bit */
184 RX0CON &= ~RXNAK;
185 }
186
187 return (length - ep->cnt);
187} 188}
188 189
189/* Stall the endpoint. Usually set a flag in the controller */ 190/* Stall the endpoint. Usually set a flag in the controller */
@@ -260,6 +261,8 @@ void INT_UDC(void)
260 * endpoint does not respond to an SETUP 261 * endpoint does not respond to an SETUP
261 * or OUT token */ 262 * or OUT token */
262 RXNAK; /* Set as one to response NAK handshake */ 263 RXNAK; /* Set as one to response NAK handshake */
264
265 usb_drv_rcv_done = true;
263 } 266 }
264 267
265 if (intsrc & SETUP_INTR) /* setup interrupt */ 268 if (intsrc & SETUP_INTR) /* setup interrupt */
@@ -274,15 +277,25 @@ void INT_UDC(void)
274 /* TODO handle errors */ 277 /* TODO handle errors */
275 if (txstat & TXACK) /* check TxACK flag */ 278 if (txstat & TXACK) /* check TxACK flag */
276 { 279 {
280 /* Decrement by max packet size is intentional.
281 * This way if we have final packet short one we will get negative len
282 * after transfer, which in turn indicates we *don't* need to send
283 * zero length packet. If the final packet is max sized packet we will
284 * get zero len after transfer which indicates we need to send
285 * zero length packet to signal host end of the transfer.
286 */
277 if (ctrlep[DIR_IN].cnt > 0) 287 if (ctrlep[DIR_IN].cnt > 0)
278 { 288 {
279 /* we still have data to send */ 289 /* we still have data to send */
280 ctr_write(); 290 ep0_in_dma_setup();
291
281 } 292 }
282 else 293 else
283 { 294 {
284 if (ctrlep[DIR_IN].cnt == 0) 295 if (ctrlep[DIR_IN].cnt == 0)
285 ctr_write(); 296 {
297 ep0_in_dma_setup();
298 }
286 299
287 /* final ack received */ 300 /* final ack received */
288 usb_drv_send_done = true; 301 usb_drv_send_done = true;
@@ -297,8 +310,17 @@ void INT_UDC(void)
297 /* TODO handle errors */ 310 /* TODO handle errors */
298 if (rxstat & RXACK) /* RxACK */ 311 if (rxstat & RXACK) /* RxACK */
299 { 312 {
300 if (ctrlep[DIR_OUT].cnt > 0) 313 int xfer_size = RX0STAT & 0xffff;
301 ctr_read(); 314 ctrlep[DIR_OUT].cnt -= xfer_size;
315
316 if (ctrlep[DIR_OUT].cnt > 0 && xfer_size == 64)
317 {
318 /* advance the buffer */
319 ctrlep[DIR_OUT].buf += xfer_size;
320 ep0_out_dma_setup();
321 }
322 else
323 usb_drv_rcv_done = true;
302 } 324 }
303 } 325 }
304 326