as3525v2-usb: rework ep listing&xfers cancelling, implement speed reporting, first...
[kugel-rb.git] / firmware / target / arm / as3525 / usb-drv-as3525v2.c
blob24487c0981aef0cb3edcbf97d9edc22c3f810768
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright © 2010 Amaury Pouly
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
22 #include "usb.h"
23 #include "usb_drv.h"
24 #include "as3525v2.h"
25 #include "clock-target.h"
26 #include "ascodec.h"
27 #include "as3514.h"
28 #include "stdbool.h"
29 #include "string.h"
30 #include "stdio.h"
31 #include "panic.h"
32 #include "mmu-arm.h"
33 #include "system.h"
34 #define LOGF_ENABLE
35 #include "logf.h"
36 #include "usb-drv-as3525v2.h"
37 #include "usb_core.h"
39 static int __in_ep_list[NUM_IN_EP] = {IN_EP_LIST};
40 static int __out_ep_list[NUM_OUT_EP] = {OUT_EP_LIST};
41 static int __in_ep_list_ep0[NUM_IN_EP + 1] = {0, IN_EP_LIST};
42 static int __out_ep_list_ep0[NUM_OUT_EP + 1] = {0, OUT_EP_LIST};
44 /* iterate through each in/out ep except EP0
45 * 'counter' is the counter, 'ep' is the actual value */
46 #define FOR_EACH_EP(list, size, counter, ep) \
47 for(counter = 0, ep = (list)[0]; \
48 counter < (size); \
49 counter++, ep = (list)[counter])
51 #define FOR_EACH_IN_EP_EX(include_ep0, counter, ep) \
52 FOR_EACH_EP(include_ep0 ? __in_ep_list_ep0 : __in_ep_list, \
53 include_ep0 ? NUM_IN_EP : NUM_IN_EP + 1, counter, ep)
55 #define FOR_EACH_OUT_EP_EX(include_ep0, counter, ep) \
56 FOR_EACH_EP(include_ep0 ? __out_ep_list_ep0 : __out_ep_list, \
57 include_ep0 ? NUM_OUT_EP : NUM_OUT_EP + 1, counter, ep)
59 #define FOR_EACH_IN_EP(counter, ep) \
60 FOR_EACH_IN_EP_EX(false, counter, ep)
62 #define FOR_EACH_IN_EP_AND_EP0(counter, ep) \
63 FOR_EACH_IN_EP_EX(true, counter, ep)
65 #define FOR_EACH_OUT_EP(counter, ep) \
66 FOR_EACH_OUT_EP_EX(false, counter, ep)
68 #define FOR_EACH_OUT_EP_AND_EP0(counter, ep) \
69 FOR_EACH_OUT_EP_EX(true, counter, ep)
71 struct usb_endpoint
73 bool active;
74 unsigned int len;
75 bool wait;
76 bool busy;
77 int status;
78 struct wakeup complete;
81 // 0:out, 1:in
82 static struct usb_endpoint endpoints[USB_NUM_ENDPOINTS][2];
83 static struct usb_ctrlrequest ep0_setup_pkt USB_DEVBSS_ATTR;
85 void usb_attach(void)
87 logf("usb-drv: attach");
88 usb_enable(true);
91 static void usb_delay(void)
93 int i = 0;
94 while(i < 0x300)
96 asm volatile("nop");
97 i++;
101 static void as3525v2_connect(void)
103 logf("usb-drv: init as3525v2");
104 /* 1) enable usb core clock */
105 CGU_PERI |= CGU_USB_CLOCK_ENABLE;
106 usb_delay();
107 /* 2) enable usb phy clock */
108 /* PHY clock */
109 CGU_USB = 1<<5 /* enable */
110 | (CLK_DIV(AS3525_PLLA_FREQ, 60000000)) << 2
111 | 1; /* source = PLLA */
112 usb_delay();
113 /* 3) clear "stop pclk" */
114 PCGCCTL &= ~0x1;
115 usb_delay();
116 /* 4) clear "power clamp" */
117 PCGCCTL &= ~0x4;
118 usb_delay();
119 /* 5) clear "reset power down module" */
120 PCGCCTL &= ~0x8;
121 usb_delay();
122 /* 6) set "power on program done" */
123 DCTL |= DCTL_pwronprgdone;
124 usb_delay();
125 /* 7) core soft reset */
126 GRSTCTL |= GRSTCTL_csftrst;
127 usb_delay();
128 /* 8) hclk soft reset */
129 GRSTCTL |= GRSTCTL_hsftrst;
130 usb_delay();
131 /* 9) flush and reset everything */
132 GRSTCTL |= 0x3f;
133 usb_delay();
134 /* 10) force device mode*/
135 GUSBCFG &= ~GUSBCFG_force_host_mode;
136 GUSBCFG |= GUSBCFG_force_device_mode;
137 usb_delay();
138 /* 11) Do something that is probably CCU related but undocumented*/
139 CCU_USB_THINGY &= ~0x1000;
140 usb_delay();
141 CCU_USB_THINGY &= ~0x300000;
142 usb_delay();
143 /* 12) reset usb core parameters (dev addr, speed, ...) */
144 DCFG = 0;
145 usb_delay();
148 static void as3525v2_disconnect(void)
152 static void enable_device_interrupts(void)
154 /* Clear any pending interrupt */
155 GINTSTS = 0xffffffff;
156 /* Clear any pending otg interrupt */
157 GOTGINT = 0xffffffff;
158 /* Enable interrupts */
159 GINTMSK = GINTMSK_usbreset
160 | GINTMSK_enumdone
161 | GINTMSK_inepintr
162 | GINTMSK_outepintr
163 | GINTMSK_disconnect;
166 static void flush_tx_fifos(int nums)
168 unsigned int i = 0;
170 GRSTCTL = (nums << GRSTCTL_txfnum_bitp)
171 | GRSTCTL_txfflsh_flush;
172 while(GRSTCTL & GRSTCTL_txfflsh_flush && i < 0x300)
173 i++;
174 if(GRSTCTL & GRSTCTL_txfflsh_flush)
175 panicf("usb-drv: hang of flush tx fifos (%x)", nums);
176 /* wait 3 phy clocks */
177 udelay(1);
180 static void flush_rx_fifos(void)
182 unsigned int i = 0;
184 GRSTCTL = GRSTCTL_rxfflsh_flush;
185 while(GRSTCTL & GRSTCTL_rxfflsh_flush && i < 0x300)
186 i++;
187 if(GRSTCTL & GRSTCTL_rxfflsh_flush)
188 panicf("usb-drv: hang of flush rx fifos");
189 /* wait 3 phy clocks */
190 udelay(1);
193 static void prepare_setup_ep0(void)
195 /* setup DMA */
196 clean_dcache_range((void*)&ep0_setup_pkt, sizeof ep0_setup_pkt); /* force write back */
197 DOEPDMA(0) = (unsigned long)&ep0_setup_pkt; /* virtual address=physical address */
199 /* Setup EP0 OUT with the following parameters:
200 * packet count = 1
201 * setup packet count = 1
202 * transfer size = 8 (setup packet)
204 DOEPTSIZ(0) = (1 << DEPTSIZ0_supcnt_bitp)
205 | (1 << DEPTSIZ0_pkcnt_bitp)
206 | 8;
208 /* Enable endpoint, clear nak */
209 DOEPCTL(0) |= DEPCTL_epena | DEPCTL_cnak;
211 if(!(DOEPCTL(0) & DEPCTL_epena))
212 panicf("usb-drv: failed to enable EP0 !");
215 static void reset_endpoints(void)
217 int i, ep;
218 /* disable all endpoints except EP0 */
219 FOR_EACH_IN_EP(i, ep)
220 if(DIEPCTL(ep) & DEPCTL_epena)
221 DIEPCTL(ep) = DEPCTL_epdis | DEPCTL_snak;
222 else
223 DIEPCTL(ep) = 0;
225 FOR_EACH_OUT_EP(i, ep)
226 if(DOEPCTL(ep) & DEPCTL_epena)
227 DOEPCTL(ep) = DEPCTL_epdis | DEPCTL_snak;
228 else
229 DOEPCTL(ep) = 0;
231 /* 64 bytes packet size, active endpoint */
232 DOEPCTL(0) = (DEPCTL_MPS_64 << DEPCTL_mps_bitp) | DEPCTL_usbactep;
233 DIEPCTL(0) = (DEPCTL_MPS_64 << DEPCTL_mps_bitp) | DEPCTL_usbactep;
235 prepare_setup_ep0();
238 static void cancel_all_transfers(bool cancel_ep0)
240 logf("usb-drv: cancel all transfers");
241 int flags = disable_irq_save();
242 unsigned i, ep;
243 FOR_EACH_IN_EP_EX(cancel_ep0, i, ep)
245 endpoints[ep][DIR_IN].status = 1;
246 endpoints[ep][DIR_IN].wait = false;
247 endpoints[ep][DIR_IN].busy = false;
248 wakeup_signal(&endpoints[ep][DIR_IN].complete);
249 DIEPCTL(ep) = (DIEPCTL(ep) & ~DEPCTL_usbactep) | DEPCTL_epdis;
251 FOR_EACH_OUT_EP_EX(cancel_ep0, i, ep)
253 endpoints[ep][DIR_OUT].status = 1;
254 endpoints[ep][DIR_OUT].wait = false;
255 endpoints[ep][DIR_OUT].busy = false;
256 wakeup_signal(&endpoints[ep][DIR_OUT].complete);
257 DOEPCTL(ep) = (DOEPCTL(ep) & ~DEPCTL_usbactep) | DEPCTL_epdis;
260 restore_irq(flags);
263 static void core_dev_init(void)
265 unsigned int i, ep;
266 /* Restart the phy clock */
267 PCGCCTL = 0;
268 /* Set phy speed : high speed */
269 DCFG = (DCFG & ~bitm(DCFG, devspd)) | DCFG_devspd_hs_phy_hs;
271 /* Check hardware capabilities */
272 if(extract(GHWCFG2, arch) != GHWCFG2_ARCH_INTERNAL_DMA)
273 panicf("usb-drv: wrong architecture (%ld)", extract(GHWCFG2, arch));
274 if(extract(GHWCFG2, hs_phy_type) != GHWCFG2_PHY_TYPE_UTMI)
275 panicf("usb-drv: wrong HS phy type (%ld)", extract(GHWCFG2, hs_phy_type));
276 if(extract(GHWCFG2, fs_phy_type) != GHWCFG2_PHY_TYPE_UNSUPPORTED)
277 panicf("usb-drv: wrong FS phy type (%ld)", extract(GHWCFG2, fs_phy_type));
278 if(extract(GHWCFG4, utmi_phy_data_width) != 0x2)
279 panicf("usb-drv: wrong utmi data width (%ld)", extract(GHWCFG4, utmi_phy_data_width));
280 if(!(GHWCFG4 & GHWCFG4_ded_fifo_en)) /* it seems to be multiple tx fifo support */
281 panicf("usb-drv: no multiple tx fifo");
283 #ifdef USE_CUSTOM_FIFO_LAYOUT
284 if(!(GHWCFG2 & GHWCFG2_dyn_fifo))
285 panicf("usb-drv: no dynamic fifo");
286 if(GRXFSIZ != DATA_FIFO_DEPTH)
287 panicf("usb-drv: wrong data fifo size");
288 #endif /* USE_CUSTOM_FIFO_LAYOUT */
290 /* do some logging */
292 logf("hwcfg1: %08lx", GHWCFG1);
293 logf("hwcfg2: %08lx", GHWCFG2);
294 logf("hwcfg3: %08lx", GHWCFG3);
295 logf("hwcfg4: %08lx", GHWCFG4);
298 if(USB_NUM_ENDPOINTS != extract(GHWCFG2, num_ep))
299 panicf("usb-drv: wrong endpoint number");
301 FOR_EACH_IN_EP_AND_EP0(i, ep)
303 int type = (GHWCFG1 >> GHWCFG1_epdir_bitp(ep)) & GHWCFG1_epdir_bits;
304 if(type != GHWCFG1_EPDIR_BIDIR && type != GHWCFG1_EPDIR_IN)
305 panicf("usb-drv: EP%d is no IN or BIDIR", ep);
307 FOR_EACH_OUT_EP_AND_EP0(i, ep)
309 int type = (GHWCFG1 >> GHWCFG1_epdir_bitp(ep)) & GHWCFG1_epdir_bits;
310 if(type != GHWCFG1_EPDIR_BIDIR && type != GHWCFG1_EPDIR_OUT)
311 panicf("usb-drv: EP%d is no OUT or BIDIR", ep);
314 /* Setup interrupt masks for endpoints */
315 /* Setup interrupt masks */
316 DOEPMSK = DOEPINT_setup | DOEPINT_xfercompl | DOEPINT_ahberr;
317 DIEPMSK = DIEPINT_xfercompl | DIEPINT_timeout | DIEPINT_ahberr;
318 DAINTMSK = 0xffffffff;
320 reset_endpoints();
322 /* fixme: threshold tweaking only takes place if we use multiple tx fifos it seems */
323 /* only dump them for now, leave threshold disabled */
325 logf("threshold control:");
326 logf(" non_iso_thr_en: %d", (DTHRCTL & DTHRCTL_non_iso_thr_en) ? 1 : 0);
327 logf(" iso_thr_en: %d", (DTHRCTL & DTHRCTL_iso_thr_en) ? 1 : 0);
328 logf(" tx_thr_len: %lu", extract(DTHRCTL, tx_thr_len));
329 logf(" rx_thr_en: %d", (DTHRCTL & DTHRCTL_rx_thr_en) ? 1 : 0);
330 logf(" rx_thr_len: %lu", extract(DTHRCTL, rx_thr_len));
333 /* enable USB interrupts */
334 enable_device_interrupts();
337 static void core_init(void)
339 /* Disconnect */
340 DCTL |= DCTL_sftdiscon;
341 /* Select UTMI+ 16 */
342 GUSBCFG |= GUSBCFG_phy_if;
344 /* fixme: the current code is for internal DMA only, the clip+ architecture
345 * define the internal DMA model */
346 /* Set burstlen and enable DMA*/
347 GAHBCFG = (GAHBCFG_INT_DMA_BURST_INCR4 << GAHBCFG_hburstlen_bitp)
348 | GAHBCFG_dma_enable;
349 /* Disable HNP and SRP, not sure it's useful because we already forced dev mode */
350 GUSBCFG &= ~(GUSBCFG_srpcap | GUSBCFG_hnpcapp);
352 /* perform device model specific init */
353 core_dev_init();
355 /* Reconnect */
356 DCTL &= ~DCTL_sftdiscon;
359 static void enable_global_interrupts(void)
361 VIC_INT_ENABLE = INTERRUPT_USB;
362 GAHBCFG |= GAHBCFG_glblintrmsk;
365 static void disable_global_interrupts(void)
367 GAHBCFG &= ~GAHBCFG_glblintrmsk;
368 VIC_INT_EN_CLEAR = INTERRUPT_USB;
371 void usb_drv_init(void)
373 unsigned i, ep;
374 logf("usb_drv_init");
375 /* Boost cpu */
376 cpu_boost(1);
377 /* Enable PHY and clocks (but leave pullups disabled) */
378 as3525v2_connect();
379 logf("usb-drv: synopsis id: %lx", GSNPSID);
380 /* Core init */
381 core_init();
382 FOR_EACH_IN_EP_AND_EP0(i, ep)
383 wakeup_init(&endpoints[ep][DIR_IN].complete);
384 FOR_EACH_OUT_EP_AND_EP0(i, ep)
385 wakeup_init(&endpoints[ep][DIR_OUT].complete);
386 /* Enable global interrupts */
387 enable_global_interrupts();
390 void usb_drv_exit(void)
392 logf("usb_drv_exit");
394 disable_global_interrupts();
395 as3525v2_disconnect();
396 cpu_boost(0);
399 static void handle_ep_int(int ep, bool dir_in)
401 struct usb_endpoint *endpoint = &endpoints[ep][dir_in];
402 if(dir_in)
404 if(DIEPINT(ep) & DIEPINT_ahberr)
405 panicf("usb-drv: ahb error on EP%d IN", ep);
406 if(DIEPINT(ep) & DIEPINT_xfercompl)
408 logf("usb-drv: xfer complete on EP%d IN", ep);
409 if(endpoint->busy)
411 endpoint->busy = false;
412 endpoint->status = 0;
413 /* works even for PE0 */
414 int transfered = endpoint->len - (DIEPTSIZ(ep) & DEPTSIZ_xfersize_bits);
415 logf("len=%d reg=%ld xfer=%d", endpoint->len,
416 (DIEPTSIZ(ep) & DEPTSIZ_xfersize_bits),
417 transfered);
418 invalidate_dcache_range((void *)DIEPDMA(ep), transfered);
419 DIEPCTL(ep) |= DEPCTL_snak;
420 /* if the transfer length is 0 on EP0, this is a ack
421 * so we setup EP0 to receive next setup */
422 if(ep == 0 && endpoint->len == 0)
423 prepare_setup_ep0();
424 usb_core_transfer_complete(ep, USB_DIR_IN, 0, transfered);
425 wakeup_signal(&endpoint->complete);
428 if(DIEPINT(ep) & DIEPINT_timeout)
430 logf("usb-drv: timeout on EP%d IN", ep);
431 if(endpoint->busy)
433 endpoint->busy = false;
434 endpoint->status = 1;
435 /* for safety, act as if no bytes as been transfered */
436 endpoint->len = 0;
437 DIEPCTL(ep) |= DEPCTL_snak;
438 usb_core_transfer_complete(ep, USB_DIR_IN, 1, 0);
439 wakeup_signal(&endpoint->complete);
442 /* clear interrupts */
443 DIEPINT(ep) = DIEPINT(ep);
445 else
447 if(DOEPINT(ep) & DOEPINT_ahberr)
448 panicf("usb-drv: ahb error on EP%d OUT", ep);
449 if(DOEPINT(ep) & DOEPINT_xfercompl)
451 logf("usb-drv: xfer complete on EP%d OUT", ep);
452 if(endpoint->busy)
454 endpoint->busy = false;
455 endpoint->status = 0;
456 /* works even for EP0 */
457 int transfered = endpoint->len - (DOEPTSIZ(ep) & DEPTSIZ_xfersize_bits);
458 logf("len=%d reg=%ld xfer=%d", endpoint->len,
459 (DOEPTSIZ(ep) & DEPTSIZ_xfersize_bits),
460 transfered);
461 invalidate_dcache_range((void *)DOEPDMA(ep), transfered);
462 /* if the transfer length is 0 on EP0, this is a ack
463 * so we setup EP0 to receive next setup */
464 if(ep == 0 && endpoint->len == 0)
465 prepare_setup_ep0();
466 else
467 DOEPCTL(ep) |= DEPCTL_snak;
468 usb_core_transfer_complete(ep, USB_DIR_OUT, 0, transfered);
469 wakeup_signal(&endpoint->complete);
472 if(DOEPINT(ep) & DOEPINT_setup)
474 logf("usb-drv: setup on EP%d OUT", ep);
475 if(ep != 0)
476 panicf("usb-drv: setup not on EP0, this is impossible");
477 DOEPCTL(ep) |= DEPCTL_snak;
478 /* handle the set address here because of a bug in the usb core */
479 invalidate_dcache_range((void*)&ep0_setup_pkt, sizeof ep0_setup_pkt); /* force write back */
480 logf(" rt=%x r=%x", ep0_setup_pkt.bRequestType, ep0_setup_pkt.bRequest);
481 if(ep0_setup_pkt.bRequestType == USB_TYPE_STANDARD &&
482 ep0_setup_pkt.bRequest == USB_REQ_SET_ADDRESS)
483 usb_drv_set_address(ep0_setup_pkt.wValue);
484 usb_core_control_request(&ep0_setup_pkt);
486 /* clear interrupts */
487 DOEPINT(ep) = DOEPINT(ep);
491 static void handle_ep_ints(void)
493 logf("usb-drv: ep int");
494 /* we must read it */
495 unsigned long daint = DAINT;
496 unsigned i, ep;
498 FOR_EACH_IN_EP_AND_EP0(i, ep)
499 if(daint & DAINT_IN_EP(ep))
500 handle_ep_int(ep, true);
501 FOR_EACH_OUT_EP_AND_EP0(i, ep)
502 if(daint & DAINT_OUT_EP(ep))
503 handle_ep_int(ep, false);
505 /* write back to clear status */
506 DAINT = daint;
509 /* interrupt service routine */
510 void INT_USB(void)
512 /* some bits in GINTSTS can be set even though we didn't enable the interrupt source
513 * so AND it with the actual mask */
514 unsigned long sts = GINTSTS & GINTMSK;
516 /* device part */
517 if(sts & GINTMSK_usbreset)
519 logf("usb-drv: bus reset");
521 /* Clear the Remote Wakeup Signalling */
522 //DCTL &= ~DCTL_rmtwkupsig;
524 cancel_all_transfers(true);
525 /* Flush FIFOs */
526 flush_tx_fifos(0x10);
527 flush_rx_fifos();
529 reset_endpoints();
531 /* Reset Device Address */
532 DCFG &= ~bitm(DCFG, devadr);
534 usb_core_bus_reset();
537 if(sts & GINTMSK_enumdone)
539 logf("usb-drv: enum done");
541 /* read speed */
542 if(usb_drv_port_speed())
543 logf("usb-drv: HS");
544 else
545 logf("usb-drv: FS");
547 /* fixme: change EP0 mps here */
550 if(sts & (GINTMSK_outepintr | GINTMSK_inepintr))
552 handle_ep_ints();
555 if(sts & GINTMSK_disconnect)
557 panicf("usb-drv: disconnect");
558 cancel_all_transfers(true);
559 usb_enable(false);
562 GINTSTS = GINTSTS;
565 int usb_drv_port_speed(void)
567 switch(extract(DSTS, enumspd))
569 case DSTS_ENUMSPD_HS_PHY_30MHZ_OR_60MHZ:
570 return 1;
571 case DSTS_ENUMSPD_FS_PHY_30MHZ_OR_60MHZ:
572 case DSTS_ENUMSPD_FS_PHY_48MHZ:
573 return 0;
574 break;
575 case DSTS_ENUMSPD_LS_PHY_6MHZ:
576 panicf("usb-drv: LS is not supported");
577 return 0;
578 default:
579 panicf("usb-drv: wtf is this speed ?");
580 return 0;
584 int usb_drv_request_endpoint(int type, int dir)
586 (void) type;
587 (void) dir;
588 logf("usb-drv: request endpoint (type=%d,dir=%s)", type, dir == USB_DIR_IN ? "IN" : "OUT");
589 return -1;
592 void usb_drv_release_endpoint(int ep)
594 //logf("usb-drv: release EP%d %s", EP_NUM(ep), EP_DIR(ep) == DIR_IN ? "IN" : "OUT");
595 endpoints[EP_NUM(ep)][EP_DIR(ep)].active = false;
598 void usb_drv_cancel_all_transfers()
600 cancel_all_transfers(false);
603 static int usb_drv_transfer(int ep, void *ptr, int len, bool dir_in, bool blocking)
605 ep = EP_NUM(ep);
606 logf("usb-drv: xfer EP%d, len=%d, dir_in=%d, blocking=%d", ep,
607 len, dir_in, blocking);
609 volatile unsigned long *epctl = dir_in ? &DIEPCTL(ep) : &DOEPCTL(ep);
610 volatile unsigned long *eptsiz = dir_in ? &DIEPTSIZ(ep) : &DOEPTSIZ(ep);
611 volatile unsigned long *epdma = dir_in ? &DIEPDMA(ep) : &DOEPDMA(ep);
612 struct usb_endpoint *endpoint = &endpoints[ep][dir_in];
613 #define DEPCTL *epctl
614 #define DEPTSIZ *eptsiz
615 #define DEPDMA *epdma
617 if(DEPCTL & DEPCTL_stall)
619 logf("usb-drv: cannot receive/send on a stalled endpoint");
620 return -1;
623 if(endpoint->busy)
624 logf("usb-drv: EP%d %s is already busy", ep, dir_in ? "IN" : "OUT");
626 endpoint->busy = true;
627 endpoint->len = len;
628 endpoint->wait = blocking;
629 DEPCTL |= DEPCTL_usbactep;
631 int mps = 64;
632 int nb_packets = (len + mps - 1) / mps;
634 if(len == 0)
635 DEPTSIZ = 1 << DEPTSIZ_pkcnt_bitp;
636 else
637 DEPTSIZ = (nb_packets << DEPTSIZ_pkcnt_bitp) | len;
638 clean_dcache_range(ptr, len);
639 DEPDMA = (unsigned long)ptr;
640 DEPCTL |= DEPCTL_epena | DEPCTL_cnak;
642 /* fixme: check if endpoint was really enabled ? */
644 if(blocking)
645 wakeup_wait(&endpoint->complete, TIMEOUT_BLOCK);
646 if(endpoint->status != 0)
647 return -1;
648 return 0;
650 #undef DEPCTL
651 #undef DEPTSIZ
652 #undef DEPDMA
655 int usb_drv_recv(int ep, void *ptr, int len)
657 return usb_drv_transfer(ep, ptr, len, false, false);
660 int usb_drv_send(int ep, void *ptr, int len)
662 return usb_drv_transfer(ep, ptr, len, true, true);
665 int usb_drv_send_nonblocking(int ep, void *ptr, int len)
667 return usb_drv_transfer(ep, ptr, len, true, false);
671 void usb_drv_set_test_mode(int mode)
673 (void) mode;
676 void usb_drv_set_address(int address)
678 /* ignore it if addres is already set */
679 if(extract(DCFG, devadr) == 0)
681 logf("usb-drv: set address %x", address);
682 DCFG = (DCFG & ~bitm(DCFG, devadr)) | (address << DCFG_devadr_bitp);
686 void usb_drv_stall(int ep, bool stall, bool in)
688 (void) ep;
689 (void) stall;
690 (void) in;
691 logf("usb-drv: %sstall EP%d %s", stall ? "" : "un", ep, in ? "IN" : "OUT");
694 bool usb_drv_stalled(int ep, bool in)
696 (void) ep;
697 (void) in;
698 return true;