diff options
Diffstat (limited to 'utils/hwstub/stub/rk27xx/usb_drv_rk27xx.c')
-rw-r--r-- | utils/hwstub/stub/rk27xx/usb_drv_rk27xx.c | 78 |
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; | |||
52 | static volatile uint32_t setup_data[2]; | 52 | static volatile uint32_t setup_data[2]; |
53 | 53 | ||
54 | static volatile bool usb_drv_send_done = false; | 54 | static volatile bool usb_drv_send_done = false; |
55 | static volatile bool usb_drv_rcv_done = false; | ||
55 | 56 | ||
56 | void usb_drv_configure_endpoint(int ep_num, int type) | 57 | void 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 */ |
84 | static void ctr_write(void) | 85 | static 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 | ||
107 | static void ctr_read(void) | 102 | static 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 | ||
121 | static void udc_phy_reset(void) | 111 | static 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) */ |
173 | int usb_drv_recv(int endpoint, void* ptr, int length) | 163 | int 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 | ||