| M480 BSP V3.05.001 The Board Support Package for M480 Series

ehci.c
Go to the documentation of this file.
1 /**************************************************************************/
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13
14 #include "NuMicro.h"
15
16 #include "usb.h"
17 #include "hub.h"
18
19
21
22 static QH_T *_H_qh; /* head of reclamation list */
23 static qTD_T *_ghost_qtd; /* used as a terminator qTD */
24 static QH_T *qh_remove_list;
25
26 extern ISO_EP_T *iso_ep_list; /* list of activated isochronous pipes */
27 extern int ehci_iso_xfer(UTR_T *utr); /* EHCI isochronous transfer function */
28 extern int ehci_quit_iso_xfer(UTR_T *utr, EP_INFO_T *ep);
29
30 #ifdef __ICCARM__
31 #pragma data_alignment=4096
32 uint32_t _PFList[FL_SIZE]; /* Periodic frame list (IAR) */
33 #else
34 uint32_t _PFList[FL_SIZE] __attribute__((aligned(4096))); /* Periodic frame list */
35 #endif
36
37 QH_T * _Iqh[NUM_IQH];
38
39
40 #ifdef ENABLE_ERROR_MSG
41 void dump_ehci_regs()
42 {
43 USB_debug("Dump HSUSBH(EHCI) registers:\n");
44 USB_debug(" UCMDR = 0x%x\n", _ehci->UCMDR);
45 USB_debug(" USTSR = 0x%x\n", _ehci->USTSR);
46 USB_debug(" UIENR = 0x%x\n", _ehci->UIENR);
47 USB_debug(" UFINDR = 0x%x\n", _ehci->UFINDR);
48 USB_debug(" UPFLBAR = 0x%x\n", _ehci->UPFLBAR);
49 USB_debug(" UCALAR = 0x%x\n", _ehci->UCALAR);
50 USB_debug(" UASSTR = 0x%x\n", _ehci->UASSTR);
51 USB_debug(" UCFGR = 0x%x\n", _ehci->UCFGR);
52 USB_debug(" UPSCR = 0x%x\n", _ehci->UPSCR[0]);
53 USB_debug(" PHYCTL0 = 0x%x\n", _ehci->USBPCR0);
54 USB_debug(" PHYCTL1 = 0x%x\n", _ehci->USBPCR1);
55 }
56
57 void dump_ehci_ports()
58 {
59 USB_debug("_ehci port0=0x%x, port1=0x%x\n", _ehci->UPSCR[0], _ehci->UPSCR[1]);
60 }
61
62 void dump_ehci_qtd(qTD_T *qtd)
63 {
64 USB_debug(" [qTD] - 0x%08x\n", (int)qtd);
65 USB_debug(" 0x%08x (Next qtd Pointer)\n", qtd->Next_qTD);
66 USB_debug(" 0x%08x (Alternate Next qtd Pointer)\n", qtd->Alt_Next_qTD);
67 USB_debug(" 0x%08x (qtd Token) PID: %s, Bytes: %d, IOC: %d\n", qtd->Token, (((qtd->Token>>8)&0x3)==0) ? "OUT" : ((((qtd->Token>>8)&0x3)==1) ? "IN" : "SETUP"), (qtd->Token>>16)&0x7FFF, (qtd->Token>>15)&0x1);
68 USB_debug(" 0x%08x (Buffer Pointer (page 0))\n", qtd->Bptr[0]);
69 //USB_debug(" 0x%08x (Buffer Pointer (page 1))\n", qtd->Bptr[1]);
70 //USB_debug(" 0x%08x (Buffer Pointer (page 2))\n", qtd->Bptr[2]);
71 //USB_debug(" 0x%08x (Buffer Pointer (page 3))\n", qtd->Bptr[3]);
72 //USB_debug(" 0x%08x (Buffer Pointer (page 4))\n", qtd->Bptr[4]);
73 USB_debug("\n");
74 }
75
76 void dump_ehci_asynclist(void)
77 {
78 QH_T *qh = _H_qh;
79 qTD_T *qtd;
80
81 USB_debug(">>> Dump EHCI Asynchronous List <<<\n");
82 do
83 {
84 USB_debug("[QH] - 0x%08x\n", (int)qh);
85 USB_debug(" 0x%08x (Queue Head Horizontal Link Pointer, Queue Head DWord 0)\n", qh->HLink);
86 USB_debug(" 0x%08x (Endpoint Characteristics) DevAddr: %d, EP: 0x%x, PktSz: %d, Speed: %s\n", qh->Chrst, qh->Chrst&0x7F, (qh->Chrst>>8)&0xF, (qh->Chrst>>16)&0x7FF, ((qh->Chrst>>12)&0x3 == 0) ? "Full" : (((qh->Chrst>>12)&0x3 == 1) ? "Low" : "High"));
87 USB_debug(" 0x%08x (Endpoint Capabilities: Queue Head DWord 2)\n", qh->Cap);
88 USB_debug(" 0x%08x (Current qtd Pointer)\n", qh->Curr_qTD);
89 USB_debug(" --- Overlay Area ---\n");
90 USB_debug(" 0x%08x (Next qtd Pointer)\n", qh->OL_Next_qTD);
91 USB_debug(" 0x%08x (Alternate Next qtd Pointer)\n", qh->OL_Alt_Next_qTD);
92 USB_debug(" 0x%08x (qtd Token)\n", qh->OL_Token);
93 USB_debug(" 0x%08x (Buffer Pointer (page 0))\n", qh->OL_Bptr[0]);
94 USB_debug("\n");
95
96 qtd = QTD_PTR(qh->Curr_qTD);
97 while (qtd != NULL)
98 {
99 dump_ehci_qtd(qtd);
100 qtd = QTD_PTR(qtd->Next_qTD);
101 }
102 qh = QH_PTR(qh->HLink);
103 }
104 while (qh != _H_qh);
105 }
106
107 void dump_ehci_asynclist_simple(void)
108 {
109 QH_T *qh = _H_qh;
110
111 USB_debug(">>> EHCI Asynchronous List <<<\n");
112 USB_debug("[QH] => ");
113 do
114 {
115 USB_debug("0x%08x ", (int)qh);
116 qh = QH_PTR(qh->HLink);
117 }
118 while (qh != _H_qh);
119 USB_debug("\n");
120 }
121
122 void dump_ehci_period_frame_list_simple(void)
123 {
124 QH_T *qh = _Iqh[NUM_IQH-1];
125
126 USB_debug(">>> EHCI period frame list simple <<<\n");
127 USB_debug("[FList] => ");
128 do
129 {
130 USB_debug("0x%08x ", (int)qh);
131 qh = QH_PTR(qh->HLink);
132 }
133 while (qh != NULL);
134 USB_debug("\n");
135 }
136
137 void dump_ehci_period_frame_list()
138 {
139 int i;
140 QH_T *qh;
141
142 for (i = 0; i < FL_SIZE; i++)
143 {
144 USB_debug("!%02d: ", i);
145 qh = QH_PTR(_PFList[i]);;
146 while (qh != NULL)
147 {
148 // USB_debug("0x%x (0x%x) => ", (int)qh, qh->HLink);
149 USB_debug("0x%x => ", (int)qh);
150 qh = QH_PTR(qh->HLink);
151 }
152 USB_debug("0\n");
153 }
154 }
155
156 #endif /* ENABLE_ERROR_MSG */
157
158 static void init_periodic_frame_list()
159 {
160 QH_T *qh_p;
161 int i, idx, interval;
162
163 memset(_PFList, 0, sizeof(_PFList));
164
165 iso_ep_list = NULL;
166
167 for (i = NUM_IQH-1; i >= 0; i--) /* interval = i^2 */
168 {
169 _Iqh[i] = alloc_ehci_QH();
170
171 _Iqh[i]->HLink = QH_HLNK_END;
172 _Iqh[i]->Curr_qTD = (uint32_t)_ghost_qtd;
173 _Iqh[i]->OL_Next_qTD = QTD_LIST_END;
174 _Iqh[i]->OL_Alt_Next_qTD = (uint32_t)_ghost_qtd;
175 _Iqh[i]->OL_Token = QTD_STS_HALT;
176
177 interval = 0x1 << i;
178
179 for (idx = interval - 1; idx < FL_SIZE; idx += interval)
180 {
181 if (_PFList[idx] == 0) /* is empty list, insert directly */
182 {
183 _PFList[idx] = QH_HLNK_QH(_Iqh[i]);
184 }
185 else
186 {
187 qh_p = QH_PTR(_PFList[idx]);
188
189 while (1)
190 {
191 if (qh_p == _Iqh[i])
192 break; /* already chained by previous visit */
193
194 if (qh_p->HLink == QH_HLNK_END) /* reach end of list? */
195 {
196 qh_p->HLink = QH_HLNK_QH(_Iqh[i]);
197 break;
198 }
199 qh_p = QH_PTR(qh_p->HLink);
200 }
201 }
202 }
203 }
204 }
205
206 static QH_T * get_int_tree_head_node(int interval)
207 {
208 int i;
209
210 interval /= 8; /* each frame list entry for 8 micro-frame */
211
212 for (i = 0; i < NUM_IQH-1; i++)
213 {
214 interval >>= 1;
215 if (interval == 0)
216 return _Iqh[i];
217 }
218 return _Iqh[NUM_IQH-1];
219 }
220
221 static int make_int_s_mask(int bInterval)
222 {
223 int order, interval;
224
225 interval = 1;
226 while (bInterval > 1)
227 {
228 interval *= 2;
229 bInterval--;
230 }
231
232 if (interval < 2)
233 return 0xFF; /* interval 1 */
234 if (interval < 4)
235 return 0x55; /* interval 2 */
236 if (interval < 8)
237 return 0x22; /* interval 4 */
238 for (order = 0; (interval > 1); order++)
239 {
240 interval >>= 1;
241 }
242 return (0x1 << (order % 8));
243 }
244
245 static int ehci_init(void)
246 {
247 int timeout = 250*1000; /* EHCI reset time-out 250 ms */
248
249 /*------------------------------------------------------------------------------------*/
250 /* Reset EHCI host controller */
251 /*------------------------------------------------------------------------------------*/
252 _ehci->UCMDR = HSUSBH_UCMDR_HCRST_Msk;
253 while ((_ehci->UCMDR & HSUSBH_UCMDR_HCRST_Msk) && (timeout > 0))
254 {
255 delay_us(1000);
256 timeout -= 1000;
257 }
258 if (_ehci->UCMDR & HSUSBH_UCMDR_HCRST_Msk)
259 return USBH_ERR_EHCI_INIT;
260
261 _ehci->UCMDR = UCMDR_INT_THR_CTRL | HSUSBH_UCMDR_RUN_Msk;
262
263 _ghost_qtd = alloc_ehci_qTD(NULL);
264 _ghost_qtd->Token = 0x11197B3F; //QTD_STS_HALT; visit_qtd() will not remove a qTD with this mark. It represents a qhost qTD.
265
266 /*------------------------------------------------------------------------------------*/
267 /* Initialize asynchronous list */
268 /*------------------------------------------------------------------------------------*/
269 qh_remove_list = NULL;
270
271 /* Create the QH list head with H-bit 1 */
272 _H_qh = alloc_ehci_QH();
273 _H_qh->HLink = QH_HLNK_QH(_H_qh); /* circular link to itself, the only one QH */
274 _H_qh->Chrst = QH_RCLM_LIST_HEAD; /* it's the head of reclamation list */
275 _H_qh->Curr_qTD = (uint32_t)_ghost_qtd;
276 _H_qh->OL_Next_qTD = QTD_LIST_END;
277 _H_qh->OL_Alt_Next_qTD = (uint32_t)_ghost_qtd;
278 _H_qh->OL_Token = QTD_STS_HALT;
279 _ehci->UCALAR = (uint32_t)_H_qh;
280
281 /*------------------------------------------------------------------------------------*/
282 /* Initialize periodic list */
283 /*------------------------------------------------------------------------------------*/
284 if (FL_SIZE == 256)
285 _ehci->UCMDR |= (0x2<<HSUSBH_UCMDR_FLSZ_Pos);
286 else if (FL_SIZE == 512)
287 _ehci->UCMDR |= (0x1<<HSUSBH_UCMDR_FLSZ_Pos);
288 else if (FL_SIZE == 1024)
289 _ehci->UCMDR |= (0x0<<HSUSBH_UCMDR_FLSZ_Pos);
290 else
291 return USBH_ERR_EHCI_INIT; /* Invalid FL_SIZE setting! */
292
293 _ehci->UPFLBAR = (uint32_t)_PFList;
294
295 /*------------------------------------------------------------------------------------*/
296 /* start run */
297 /*------------------------------------------------------------------------------------*/
298
299 _ehci->UCFGR = 0x1; /* enable port routing to EHCI */
300 _ehci->UIENR = HSUSBH_UIENR_USBIEN_Msk | HSUSBH_UIENR_UERRIEN_Msk | HSUSBH_UIENR_HSERREN_Msk | HSUSBH_UIENR_IAAEN_Msk;
301
302 delay_us(1000); /* delay 1 ms */
303
304 _ehci->UPSCR[0] = HSUSBH_UPSCR_PP_Msk; /* enable port 1 port power */
305 _ehci->UPSCR[1] = HSUSBH_UPSCR_PP_Msk | HSUSBH_UPSCR_PO_Msk; /* set port 2 owner to OHCI */
306
307 init_periodic_frame_list();
308
309 delay_us(10*1000); /* delay 10 ms */
310
311 return 0;
312 }
313
314 static void ehci_suspend(void)
315 {
316 if (_ehci->UPSCR[0] & 0x1)
317 _ehci->UPSCR[0] |= HSUSBH_UPSCR_SUSPEND_Msk;
318 }
319
320 static void ehci_resume(void)
321 {
322 if (_ehci->UPSCR[0] & 0x1)
323 _ehci->UPSCR[0] = (HSUSBH->UPSCR[0] & ~HSUSBH_UPSCR_SUSPEND_Msk) | HSUSBH_UPSCR_FPR_Msk;
324 }
325
326 static void ehci_shutdown(void)
327 {
328 ehci_suspend();
329 }
330
331 static void move_qh_to_remove_list(QH_T *qh)
332 {
333 QH_T *q;
334
335 // USB_debug("move_qh_to_remove_list - 0x%x (0x%x)\n", (int)qh, qh->Chrst);
336
337 /* check if this ED found in ed_remove_list */
338 q = qh_remove_list;
339 while (q)
340 {
341 if (q == qh) /* This QH found in qh_remove_list. */
342 {
343 return; /* Do nothing, return... */
344 }
345 q = q->next;
346 }
347
348 DISABLE_EHCI_IRQ();
349
350 /*------------------------------------------------------------------------------------*/
351 /* Search asynchronous frame list and remove qh if found in list. */
352 /*------------------------------------------------------------------------------------*/
353 q = _H_qh; /* find and remove it from asynchronous list */
354 while (QH_PTR(q->HLink) != _H_qh)
355 {
356 if (QH_PTR(q->HLink) == qh)
357 {
358 /* q's next QH is qh, found... */
359 q->HLink = qh->HLink; /* remove qh from list */
360
361 qh->next = qh_remove_list; /* add qh to qh_remove_list */
362 qh_remove_list = qh;
363 _ehci->UCMDR |= HSUSBH_UCMDR_IAAD_Msk; /* trigger IAA interrupt */
364 ENABLE_EHCI_IRQ();
365 return; /* done */
366 }
367 q = QH_PTR(q->HLink); /* advance to next QH in asynchronous list */
368 }
369
370 /*------------------------------------------------------------------------------------*/
371 /* Search periodic frame list and remove qh if found in list. */
372 /*------------------------------------------------------------------------------------*/
373 q = _Iqh[NUM_IQH-1];
374 while (q->HLink != QH_HLNK_END)
375 {
376 if (QH_PTR(q->HLink) == qh)
377 {
378 /* q's next QH is qh, found... */
379 q->HLink = qh->HLink; /* remove qh from list */
380
381 qh->next = qh_remove_list; /* add qh to qh_remove_list */
382 qh_remove_list = qh;
383 _ehci->UCMDR |= HSUSBH_UCMDR_IAAD_Msk; /* trigger IAA interrupt */
384 ENABLE_EHCI_IRQ();
385 return; /* done */
386 }
387 q = QH_PTR(q->HLink); /* advance to next QH in asynchronous list */
388 }
389 ENABLE_EHCI_IRQ();
390 }
391
392 static void append_to_qtd_list_of_QH(QH_T *qh, qTD_T *qtd)
393 {
394 qTD_T *q;
395
396 if (qh->qtd_list == NULL)
397 {
398 qh->qtd_list = qtd;
399 }
400 else
401 {
402 q = qh->qtd_list;
403 while (q->next != NULL)
404 {
405 q = q->next;
406 }
407 q->next = qtd;
408 }
409 }
410
411 /*
412 * If ep==NULL, it's a control endpoint QH.
413 */
414 static void write_qh(UDEV_T *udev, EP_INFO_T *ep, QH_T *qh)
415 {
416 uint32_t chrst, cap;
417
418 /*------------------------------------------------------------------------------------*/
419 /* Write QH DWord 1 - Endpoint Characteristics */
420 /*------------------------------------------------------------------------------------*/
421 if (ep == NULL) /* is control endpoint? */
422 {
423 if (udev->descriptor.bMaxPacketSize0 == 0)
424 {
425 if (udev->speed == SPEED_LOW) /* give a default maximum packet size */
426 udev->descriptor.bMaxPacketSize0 = 8;
427 else
428 udev->descriptor.bMaxPacketSize0 = 64;
429 }
430 chrst = QH_DTC | QH_NAK_RL | (udev->descriptor.bMaxPacketSize0 << 16);
431 if (udev->speed != SPEED_HIGH)
432 chrst |= QH_CTRL_EP_FLAG; /* non-high-speed control endpoint */
433 }
434 else /* not a control endpoint */
435 {
436 chrst = QH_NAK_RL | (ep->wMaxPacketSize << 16);
437 chrst |= ((ep->bEndpointAddress & 0xf) << 8); /* Endpoint Address */
438 }
439
440 if (udev->speed == SPEED_LOW)
441 chrst |= QH_EPS_LOW;
442 else if (udev->speed == SPEED_FULL)
443 chrst |= QH_EPS_FULL;
444 else
445 chrst |= QH_EPS_HIGH;
446
447 chrst |= udev->dev_num;
448
449 qh->Chrst = chrst;
450
451 /*------------------------------------------------------------------------------------*/
452 /* Write QH DWord 2 - Endpoint Capabilities */
453 /*------------------------------------------------------------------------------------*/
454 if (udev->speed == SPEED_HIGH)
455 {
456 cap = 0;
457 }
458 else
459 {
460 /*
461 * Backtrace device tree until the USB 2.0 hub found
462 */
463 HUB_DEV_T *hub;
464 int port_num;
465
466 port_num = udev->port_num;
467 hub = udev->parent;
468
469 while ((hub != NULL) && (hub->iface->udev->speed != SPEED_HIGH))
470 {
471 port_num = hub->iface->udev->port_num;
472 hub = hub->iface->udev->parent;
473 }
474
475 cap = (port_num << QH_HUB_PORT_Pos) |
476 (hub->iface->udev->dev_num << QH_HUB_ADDR_Pos);
477 }
478
479 qh->Cap = cap;
480 }
481
482 static void write_qtd_bptr(qTD_T *qtd, uint32_t buff_addr, int xfer_len)
483 {
484 int i;
485
486 qtd->xfer_len = xfer_len;
487 qtd->Bptr[0] = buff_addr;
488
489 buff_addr = (buff_addr + 0x1000) & ~0xFFF;
490
491 for (i = 1; i < 5; i++)
492 {
493 qtd->Bptr[i] = buff_addr;
494 buff_addr += 0x1000;
495 }
496 }
497
498 static int ehci_ctrl_xfer(UTR_T *utr)
499 {
500 UDEV_T *udev;
501 QH_T *qh;
502 qTD_T *qtd_setup, *qtd_data, *qtd_status;
503 uint32_t token;
504 int is_new_qh = 0;
505
506 udev = utr->udev;
507
508 if (utr->data_len > 0)
509 {
510 if (((uint32_t)utr->buff + utr->data_len) > (((uint32_t)utr->buff & ~0xFFF)+0x5000))
511 return USBH_ERR_BUFF_OVERRUN;
512 }
513
514 /*------------------------------------------------------------------------------------*/
515 /* Allocate and link QH */
516 /*------------------------------------------------------------------------------------*/
517 if (udev->ep0.hw_pipe != NULL)
518 {
519 qh = (QH_T *)udev->ep0.hw_pipe;
520 if (qh->qtd_list)
521 return USBH_ERR_EHCI_QH_BUSY;
522 }
523 else
524 {
525 qh = alloc_ehci_QH();
526 if (qh == NULL)
527 return USBH_ERR_MEMORY_OUT;
528
529 udev->ep0.hw_pipe = (void *)qh; /* driver can find QH from EP */
530 is_new_qh = 1;
531 }
532 write_qh(udev, NULL, qh);
533 utr->ep = &udev->ep0; /* driver can find EP from UTR */
534
535 /*------------------------------------------------------------------------------------*/
536 /* Allocate qTDs */
537 /*------------------------------------------------------------------------------------*/
538 qtd_setup = alloc_ehci_qTD(utr); /* allocate qTD for SETUP */
539
540 if (utr->data_len > 0)
541 qtd_data = alloc_ehci_qTD(utr); /* allocate qTD for DATA */
542 else
543 qtd_data = NULL;
544
545 qtd_status = alloc_ehci_qTD(utr); /* allocate qTD for USTSR */
546
547 if (qtd_status == NULL) /* out of memory? */
548 {
549 if (qtd_setup)
550 free_ehci_qTD(qtd_setup); /* free memory */
551 if (qtd_data)
552 free_ehci_qTD(qtd_data); /* free memory */
553 return USBH_ERR_MEMORY_OUT; /* out of memory */
554 }
555
556 // USB_debug("qh=0x%x, qtd_setup=0x%x, qtd_data=0x%x, qtd_status=0x%x\n", (int)qh, (int)qtd_setup, (int)qtd_data, (int)qtd_status);
557
558 /*------------------------------------------------------------------------------------*/
559 /* prepare SETUP stage qTD */
560 /*------------------------------------------------------------------------------------*/
561 qtd_setup->qh = qh;
562 //qtd_setup->utr = utr;
563 write_qtd_bptr(qtd_setup, (uint32_t)&utr->setup, 8);
564 append_to_qtd_list_of_QH(qh, qtd_setup);
565 qtd_setup->Token = (8 << 16) | QTD_ERR_COUNTER | QTD_PID_SETUP | QTD_STS_ACTIVE;
566
567 /*------------------------------------------------------------------------------------*/
568 /* prepare DATA stage qTD */
569 /*------------------------------------------------------------------------------------*/
570 if (utr->data_len > 0)
571 {
572 qtd_setup->Next_qTD = (uint32_t)qtd_data;
573 qtd_data->Next_qTD = (uint32_t)qtd_status;
574
575 if ((utr->setup.bmRequestType & 0x80) == REQ_TYPE_OUT)
576 token = QTD_ERR_COUNTER | QTD_PID_OUT | QTD_STS_ACTIVE;
577 else
578 token = QTD_ERR_COUNTER | QTD_PID_IN | QTD_STS_ACTIVE;
579
580 qtd_data->qh = qh;
581 //qtd_data->utr = utr;
582 write_qtd_bptr(qtd_data, (uint32_t)utr->buff, utr->data_len);
583 append_to_qtd_list_of_QH(qh, qtd_data);
584 qtd_data->Token = QTD_DT | (utr->data_len << 16) | token;
585 }
586 else
587 {
588 qtd_setup->Next_qTD = (uint32_t)qtd_status;
589 }
590
591 /*------------------------------------------------------------------------------------*/
592 /* prepare USTSR stage qTD */
593 /*------------------------------------------------------------------------------------*/
594 qtd_status->Next_qTD = (uint32_t)_ghost_qtd;
595 qtd_status->Alt_Next_qTD = QTD_LIST_END;
596
597 if ((utr->setup.bmRequestType & 0x80) == REQ_TYPE_OUT)
598 token = QTD_ERR_COUNTER | QTD_PID_IN | QTD_STS_ACTIVE;
599 else
600 token = QTD_ERR_COUNTER | QTD_PID_OUT | QTD_STS_ACTIVE;
601
602 qtd_status->qh = qh;
603 //qtd_status->utr = utr;
604 append_to_qtd_list_of_QH(qh, qtd_status);
605 qtd_status->Token = QTD_DT | QTD_IOC | token;
606
607 /*------------------------------------------------------------------------------------*/
608 /* Update QH overlay */
609 /*------------------------------------------------------------------------------------*/
610 qh->Curr_qTD = 0;
611 qh->OL_Next_qTD = (uint32_t)qtd_setup;
612 qh->OL_Alt_Next_qTD = QTD_LIST_END;
613 qh->OL_Token = 0;
614
615 /*------------------------------------------------------------------------------------*/
616 /* Link QH and start asynchronous transfer */
617 /*------------------------------------------------------------------------------------*/
618 if (is_new_qh)
619 {
620 qh->HLink = _H_qh->HLink;
621 _H_qh->HLink = QH_HLNK_QH(qh);
622 }
623
624 /* Start transfer */
625 _ehci->UCMDR |= HSUSBH_UCMDR_ASEN_Msk; /* start asynchronous transfer */
626 return 0;
627 }
628
629 static int ehci_bulk_xfer(UTR_T *utr)
630 {
631 UDEV_T *udev;
632 EP_INFO_T *ep = utr->ep;
633 QH_T *qh;
634 qTD_T *qtd, *qtd_pre;
635 uint32_t data_len, xfer_len;
636 uint8_t *buff;
637 uint32_t token;
638 int is_new_qh = 0;
639
640 //USB_debug("Bulk XFER =>\n");
641 // dump_ehci_asynclist_simple();
642
643 udev = utr->udev;
644
645 if (ep->hw_pipe != NULL)
646 {
647 qh = (QH_T *)ep->hw_pipe ;
648 if (qh->qtd_list)
649 {
650 return USBH_ERR_EHCI_QH_BUSY;
651 }
652 }
653 else
654 {
655 qh = alloc_ehci_QH();
656 if (qh == NULL)
657 return USBH_ERR_MEMORY_OUT;
658 is_new_qh = 1;
659 write_qh(udev, ep, qh);
660 ep->hw_pipe = (void *)qh; /* associate QH with endpoint */
661 }
662
663 /*------------------------------------------------------------------------------------*/
664 /* Prepare qTDs */
665 /*------------------------------------------------------------------------------------*/
666 data_len = utr->data_len;
667 buff = utr->buff;
668 qtd_pre = NULL;
669
670 while (data_len > 0)
671 {
672 qtd = alloc_ehci_qTD(utr);
673 if (qtd == NULL) /* failed to allocate a qTD */
674 {
675 qtd = qh->qtd_list;
676 while (qtd != NULL)
677 {
678 qtd_pre = qtd;
679 qtd = qtd->next;
680 free_ehci_qTD(qtd_pre);
681 }
682 if (is_new_qh)
683 {
684 free_ehci_QH(qh);
685 ep->hw_pipe = NULL;
686 }
687 return USBH_ERR_MEMORY_OUT;
688 }
689
690 if ((ep->bEndpointAddress & EP_ADDR_DIR_MASK) == EP_ADDR_DIR_OUT)
691 token = QTD_ERR_COUNTER | QTD_PID_OUT | QTD_STS_ACTIVE;
692 else
693 token = QTD_ERR_COUNTER | QTD_PID_IN | QTD_STS_ACTIVE;
694
695 if (data_len > 0x4000) /* force maximum x'fer length 16K per qTD */
696 xfer_len = 0x4000;
697 else
698 xfer_len = data_len; /* remaining data length < 4K */
699
700 qtd->qh = qh;
701 qtd->Next_qTD = (uint32_t)_ghost_qtd;
702 qtd->Alt_Next_qTD = QTD_LIST_END; //(uint32_t)_ghost_qtd;
703 write_qtd_bptr(qtd, (uint32_t)buff, xfer_len);
704 append_to_qtd_list_of_QH(qh, qtd);
705 qtd->Token = (xfer_len << 16) | token;
706
707 buff += xfer_len; /* advanced buffer pointer */
708 data_len -= xfer_len;
709
710 if (data_len == 0) /* is this the latest qTD? */
711 {
712 qtd->Token |= QTD_IOC; /* ask to raise an interrupt on the last qTD */
713 qtd->Next_qTD = (uint32_t)_ghost_qtd; /* qTD list end */
714 }
715
716 if (qtd_pre != NULL)
717 qtd_pre->Next_qTD = (uint32_t)qtd;
718 qtd_pre = qtd;
719 }
720
721 //USB_debug("utr=0x%x, qh=0x%x, qtd=0x%x\n", (int)utr, (int)qh, (int)qh->qtd_list);
722
723 qtd = qh->qtd_list;
724
725 // qh->Curr_qTD = 0; //(uint32_t)qtd;
726 qh->OL_Next_qTD = (uint32_t)qtd;
727 // qh->OL_Alt_Next_qTD = QTD_LIST_END;
728
729 /*------------------------------------------------------------------------------------*/
730 /* Link QH and start asynchronous transfer */
731 /*------------------------------------------------------------------------------------*/
732 if (is_new_qh)
733 {
734 memcpy(&(qh->OL_Bptr[0]), &(qtd->Bptr[0]), 20);
735 qh->Curr_qTD = (uint32_t)qtd;
736
737 qh->OL_Token = 0; //qtd->Token;
738
739 if (utr->ep->bToggle)
740 qh->OL_Token |= QTD_DT;
741
742 qh->HLink = _H_qh->HLink;
743 _H_qh->HLink = QH_HLNK_QH(qh);
744 }
745
746 /* Start transfer */
747 _ehci->UCMDR |= HSUSBH_UCMDR_ASEN_Msk; /* start asynchronous transfer */
748
749 return 0;
750 }
751
752 static int ehci_int_xfer(UTR_T *utr)
753 {
754 UDEV_T *udev = utr->udev;
755 EP_INFO_T *ep = utr->ep;
756 QH_T *qh, *iqh;
757 qTD_T *qtd, *dummy_qtd;
758 uint32_t token;
759
760 dummy_qtd = alloc_ehci_qTD(NULL); /* allocate a new dummy qTD */
761 if (dummy_qtd == NULL)
762 return USBH_ERR_MEMORY_OUT;
763 dummy_qtd->Token &= ~(QTD_STS_ACTIVE | QTD_STS_HALT);
764
765 if (ep->hw_pipe != NULL)
766 {
767 qh = (QH_T *)ep->hw_pipe ;
768 }
769 else
770 {
771 qh = alloc_ehci_QH();
772 if (qh == NULL)
773 {
774 free_ehci_qTD(dummy_qtd);
775 return USBH_ERR_MEMORY_OUT;
776 }
777 write_qh(udev, ep, qh);
778 qh->Chrst &= ~0xF0000000;
779
780 if (udev->speed == SPEED_HIGH)
781 {
782 qh->Cap = (0x1 << QH_MULT_Pos) | (qh->Cap & 0xff) | make_int_s_mask(ep->bInterval);
783 }
784 else
785 {
786 qh->Cap = (0x1 << QH_MULT_Pos) | (qh->Cap & ~(QH_C_MASK_Msk | QH_S_MASK_Msk)) | 0x7802;
787 }
788 ep->hw_pipe = (void *)qh; /* associate QH with endpoint */
789
790 /*
791 * Allocate another dummy qTD
792 */
793 qtd = alloc_ehci_qTD(NULL); /* allocate a new dummy qTD */
794 if (qtd == NULL)
795 {
796 free_ehci_qTD(dummy_qtd);
797 free_ehci_QH(qh);
798 return USBH_ERR_MEMORY_OUT;
799 }
800 qtd->Token &= ~(QTD_STS_ACTIVE | QTD_STS_HALT);
801
802 qh->dummy = dummy_qtd;
803 qh->OL_Next_qTD = (uint32_t)dummy_qtd;
804 qh->OL_Token = 0; /* !Active & !Halted */
805
806 /*
807 * link QH
808 */
809 if (udev->speed == SPEED_HIGH) /* get head node of this interval */
810 iqh = get_int_tree_head_node(ep->bInterval);
811 else
812 iqh = get_int_tree_head_node(ep->bInterval * 8);
813 qh->HLink = iqh->HLink; /* Add to list of the same interval */
814 iqh->HLink = QH_HLNK_QH(qh);
815
816 dummy_qtd = qtd;
817 }
818
819 qtd = qh->dummy; /* use the current dummy qTD */
820 qtd->Next_qTD = (uint32_t)dummy_qtd;
821 qtd->utr = utr;
822 qh->dummy = dummy_qtd; /* give the new dummy qTD */
823
824 /*------------------------------------------------------------------------------------*/
825 /* Prepare qTD */
826 /*------------------------------------------------------------------------------------*/
827
828 if ((ep->bEndpointAddress & EP_ADDR_DIR_MASK) == EP_ADDR_DIR_OUT)
829 token = QTD_ERR_COUNTER | QTD_PID_OUT;
830 else
831 token = QTD_ERR_COUNTER | QTD_PID_IN;
832
833 qtd->qh = qh;
834 qtd->Alt_Next_qTD = QTD_LIST_END;
835 write_qtd_bptr(qtd, (uint32_t)utr->buff, utr->data_len);
836 append_to_qtd_list_of_QH(qh, qtd);
837 qtd->Token = QTD_IOC | (utr->data_len << 16) | token | QTD_STS_ACTIVE;
838
839 // printf("ehci_int_xfer - qh: 0x%x, 0x%x, 0x%x\n", (int)qh, (int)qh->Chrst, (int)qh->Cap);
840
841 _ehci->UCMDR |= HSUSBH_UCMDR_PSEN_Msk; /* periodic list enable */
842 return 0;
843 }
844
845 /*
846 * Quit current trasnfer via UTR or hardware EP.
847 */
848 static int ehci_quit_xfer(UTR_T *utr, EP_INFO_T *ep)
849 {
850 QH_T *qh;
851
852 // USB_debug("ehci_quit_xfer - utr: 0x%x, ep: 0x%x\n", (int)utr, (int)ep);
853
854 DISABLE_EHCI_IRQ();
855 if (ehci_quit_iso_xfer(utr, ep) == 0)
856 {
857 ENABLE_EHCI_IRQ();
858 return 0;
859 }
860 ENABLE_EHCI_IRQ();
861
862 if (utr != NULL)
863 {
864 if (utr->ep == NULL)
865 return USBH_ERR_NOT_FOUND;
866
867 qh = (QH_T *)(utr->ep->hw_pipe);
868
869 if (!qh)
870 return USBH_ERR_NOT_FOUND;
871
872 /* add the QH to remove list, it will be removed on the next IAAD interrupt */
873 move_qh_to_remove_list(qh);
874 utr->ep->hw_pipe = NULL;
875 }
876
877 if ((ep != NULL) && (ep->hw_pipe != NULL))
878 {
879 qh = (QH_T *)(ep->hw_pipe);
880 /* add the QH to remove list, it will be removed on the next IAAD interrupt */
881 move_qh_to_remove_list(qh);
882 ep->hw_pipe = NULL;
883 }
884 delay_us(2000);
885
886 return 0;
887 }
888
889 static int visit_qtd(qTD_T *qtd)
890 {
891 if ((qtd->Token == 0x11197B3F) || (qtd->Token == 0x1197B3F))
892 return 0; /* A Dummy qTD or qTD on writing, don't touch it. */
893
894 // USB_debug("Visit qtd 0x%x - 0x%x\n", (int)qtd, qtd->Token);
895
896 if ((qtd->Token & QTD_STS_ACTIVE) == 0)
897 {
898 if (qtd->Token & (QTD_STS_HALT | QTD_STS_DATA_BUFF_ERR | QTD_STS_BABBLE | QTD_STS_XactErr | QTD_STS_MISS_MF))
899 {
900 USB_error("qTD error token=0x%x! 0x%x\n", qtd->Token, qtd->Bptr[0]);
901 if (qtd->utr->status == 0)
902 qtd->utr->status = USBH_ERR_TRANSACTION;
903 }
904 else
905 {
906 if ((qtd->Token & QTD_PID_Msk) != QTD_PID_SETUP)
907 {
908 qtd->utr->xfer_len += qtd->xfer_len - QTD_TODO_LEN(qtd->Token);
909 // USB_debug("0x%x utr->xfer_len += %d\n", qtd->Token, qtd->xfer_len - QTD_TODO_LEN(qtd->Token));
910 }
911 }
912 return 1;
913 }
914 return 0;
915 }
916
917 static void scan_asynchronous_list()
918 {
919 QH_T *qh, *qh_tmp;
920 qTD_T *q_pre, *qtd, *qtd_tmp;
921 UTR_T *utr;
922
923 qh = QH_PTR(_H_qh->HLink);
924 while (qh != _H_qh)
925 {
926 // USB_debug("Scan qh=0x%x, 0x%x\n", (int)qh, qh->OL_Token);
927
928 utr = NULL;
929 qtd = qh->qtd_list;
930 while (qtd != NULL)
931 {
932 if (visit_qtd(qtd)) /* if TRUE, reclaim this qtd */
933 {
934 /* qTD is completed, will remove it */
935 utr = qtd->utr;
936 if (qtd == qh->qtd_list)
937 qh->qtd_list = qtd->next; /* unlink the qTD from qtd_list */
938 else
939 q_pre->next = qtd->next; /* unlink the qTD from qtd_list */
940
941 qtd_tmp = qtd; /* remember this qTD for freeing later */
942 qtd = qtd->next; /* advance to the next qTD */
943
944 qtd_tmp->next = qh->done_list; /* push this qTD to QH's done list */
945 qh->done_list = qtd_tmp;
946 }
947 else
948 {
949 q_pre = qtd; /* remember this qTD as a preceder */
950 qtd = qtd->next; /* advance to next qTD */
951 }
952 }
953
954 qh_tmp = qh;
955 qh = QH_PTR(qh->HLink); /* advance to the next QH */
956
957 /* If all TDs are done, call-back to requester and then remove this QH. */
958 if ((qh_tmp->qtd_list == NULL) && utr)
959 {
960 // printf("T %d [%d]\n", (qh_tmp->Chrst>>8)&0xf, (qh_tmp->OL_Token&QTD_DT) ? 1 : 0);
961 if (qh_tmp->OL_Token & QTD_DT)
962 utr->ep->bToggle = 1;
963 else
964 utr->ep->bToggle = 0;
965
966 utr->bIsTransferDone = 1;
967 if (utr->func)
968 utr->func(utr);
969
970 _ehci->UCMDR |= HSUSBH_UCMDR_IAAD_Msk; /* trigger IAA to reclaim done_list */
971 }
972 }
973 }
974
975 static void scan_periodic_frame_list()
976 {
977 QH_T *qh;
978 qTD_T *qtd, *qNext;
979 UTR_T *utr;
980
981 /*------------------------------------------------------------------------------------*/
982 /* Scan interrupt frame list */
983 /*------------------------------------------------------------------------------------*/
984 qh = _Iqh[NUM_IQH-1];
985 while (qh != NULL)
986 {
987 qtd = qh->qtd_list;
988
989 if (qtd == NULL)
990 {
991 /* empty QH */
992 qh = QH_PTR(qh->HLink); /* advance to the next QH */
993 continue;
994 }
995
996 while (qtd != NULL)
997 {
998 qNext = qtd->next;
999
1000 if (visit_qtd(qtd)) /* if TRUE, reclaim this qtd */
1001 {
1002 qh->qtd_list = qtd->next; /* proceed to next qTD or NULL */
1003 qtd->next = qh->done_list; /* push qTD into the done list */
1004 qh->done_list = qtd; /* move qTD to done list */
1005 }
1006 qtd = qNext;
1007 }
1008
1009 qtd = qh->done_list;
1010
1011 while (qtd != NULL)
1012 {
1013 utr = qtd->utr;
1014
1015 if (qh->OL_Token & QTD_DT)
1016 utr->ep->bToggle = 1;
1017 else
1018 utr->ep->bToggle = 0;
1019
1020 utr->bIsTransferDone = 1;
1021 if (utr->func)
1022 utr->func(utr);
1023
1024 _ehci->UCMDR |= HSUSBH_UCMDR_IAAD_Msk; /* trigger IAA to reclaim done_list */
1025
1026 qtd = qtd->next;
1027 }
1028
1029 qh = QH_PTR(qh->HLink); /* advance to the next QH */
1030 }
1031
1032 /*------------------------------------------------------------------------------------*/
1033 /* Scan isochronous frame list */
1034 /*------------------------------------------------------------------------------------*/
1035
1036 scan_isochronous_list();
1037 }
1038
1039 void iaad_remove_qh()
1040 {
1041 QH_T *qh;
1042 qTD_T *qtd;
1043 UTR_T *utr;
1044
1045 /*------------------------------------------------------------------------------------*/
1046 /* Remove all QHs in qh_remove_list... */
1047 /*------------------------------------------------------------------------------------*/
1048 while (qh_remove_list != NULL)
1049 {
1050 qh = qh_remove_list;
1051 qh_remove_list = qh->next;
1052
1053 // USB_debug("iaad_remove_qh - remove QH 0x%x\n", (int)qh);
1054
1055 while (qh->done_list) /* we can free the qTDs now */
1056 {
1057 qtd = qh->done_list;
1058 qh->done_list = qtd->next;
1059 free_ehci_qTD(qtd);
1060 }
1061
1062 if (qh->qtd_list != NULL) /* still have incomplete qTDs? */
1063 {
1064 utr = qh->qtd_list->utr;
1065 while (qh->qtd_list)
1066 {
1067 qtd = qh->qtd_list;
1068 qh->qtd_list = qtd->next;
1069 free_ehci_qTD(qtd);
1070 }
1071 utr->status = USBH_ERR_ABORT;
1072 utr->bIsTransferDone = 1;
1073 if (utr->func)
1074 utr->func(utr); /* call back */
1075 }
1076 free_ehci_QH(qh); /* free the QH */
1077 }
1078
1079 /*------------------------------------------------------------------------------------*/
1080 /* Free all qTD in done_list of each asynchronous QH */
1081 /*------------------------------------------------------------------------------------*/
1082 qh = QH_PTR(_H_qh->HLink);
1083 while (qh != _H_qh)
1084 {
1085 while (qh->done_list) /* we can free the qTDs now */
1086 {
1087 qtd = qh->done_list;
1088 qh->done_list = qtd->next;
1089 free_ehci_qTD(qtd);
1090 }
1091 qh = QH_PTR(qh->HLink); /* advance to the next QH */
1092 }
1093
1094 /*------------------------------------------------------------------------------------*/
1095 /* Free all qTD in done_list of each QH of periodic frame list */
1096 /*------------------------------------------------------------------------------------*/
1097 qh = _Iqh[NUM_IQH-1];
1098 while (qh != NULL)
1099 {
1100 while (qh->done_list) /* we can free the qTDs now */
1101 {
1102 qtd = qh->done_list;
1103 qh->done_list = qtd->next;
1104 free_ehci_qTD(qtd);
1105 }
1106 qh = QH_PTR(qh->HLink); /* advance to the next QH */
1107 }
1108 }
1109
1110 //static irqreturn_t ehci_irq (struct usb_hcd *hcd)
1111 void EHCI_IRQHandler(void)
1112 {
1113 uint32_t intsts;
1114
1115 intsts = _ehci->USTSR;
1116 _ehci->USTSR = intsts; /* clear interrupt status */
1117
1118 // USB_debug("Eirq USTSR=0x%x\n", intsts);
1119
1120 if (intsts & HSUSBH_USTSR_UERRINT_Msk)
1121 {
1122 // USB_error("Transfer error!\n");
1123 }
1124
1125 if (intsts & HSUSBH_USTSR_USBINT_Msk)
1126 {
1127 /* some transfers completed, travel asynchronous */
1128 /* and periodic lists to find and reclaim them. */
1129 scan_asynchronous_list();
1130
1131 scan_periodic_frame_list();
1132 }
1133
1134 if (intsts & HSUSBH_USTSR_IAA_Msk)
1135 {
1136 iaad_remove_qh();
1137 }
1138 }
1139
1140 static UDEV_T * ehci_find_device_by_port(int port)
1141 {
1142 UDEV_T *udev;
1143
1144 udev = g_udev_list;
1145 while (udev != NULL)
1146 {
1147 if ((udev->parent == NULL) && (udev->port_num == port) && (udev->speed == SPEED_HIGH))
1148 return udev;
1149 udev = udev->next;
1150 }
1151 return NULL;
1152 }
1153
1154 static int ehci_rh_port_reset(int port)
1155 {
1156 int retry;
1157 int reset_time;
1158 uint32_t t0;
1159
1160 reset_time = PORT_RESET_TIME_MS;
1161
1162 for (retry = 0; retry < PORT_RESET_RETRY; retry++)
1163 {
1164 _ehci->UPSCR[port] = (_ehci->UPSCR[port] | HSUSBH_UPSCR_PRST_Msk) & ~HSUSBH_UPSCR_PE_Msk;
1165
1166 t0 = get_ticks();
1167 while (get_ticks() - t0 < (reset_time/10)+1) ; /* wait at least 50 ms */
1168
1169 _ehci->UPSCR[port] &= ~HSUSBH_UPSCR_PRST_Msk;
1170
1171 t0 = get_ticks();
1172 while (get_ticks() - t0 < (reset_time/10)+1)
1173 {
1174 if (!(_ehci->UPSCR[port] & HSUSBH_UPSCR_CCS_Msk) ||
1175 ((_ehci->UPSCR[port] & (HSUSBH_UPSCR_CCS_Msk | HSUSBH_UPSCR_PE_Msk)) == (HSUSBH_UPSCR_CCS_Msk | HSUSBH_UPSCR_PE_Msk)))
1176 goto port_reset_done;
1177 }
1178 reset_time += PORT_RESET_RETRY_INC_MS;
1179 }
1180
1181 USB_debug("EHCI port %d - port reset failed!\n", port+1);
1182 return USBH_ERR_PORT_RESET;
1183
1184 port_reset_done:
1185 if ((_ehci->UPSCR[port] & HSUSBH_UPSCR_CCS_Msk) == 0) /* check again if device disconnected */
1186 {
1187 _ehci->UPSCR[port] |= HSUSBH_UPSCR_CSC_Msk; /* clear CSC */
1188 return USBH_ERR_DISCONNECTED;
1189 }
1190 _ehci->UPSCR[port] |= HSUSBH_UPSCR_PEC_Msk; /* clear port enable change status */
1191 return USBH_OK; /* port reset success */
1192 }
1193
1194 static int ehci_rh_polling(void)
1195 {
1196 UDEV_T *udev;
1197 int ret;
1198 int connect_status, t0;
1199
1200 if (!(_ehci->UPSCR[0] & HSUSBH_UPSCR_CSC_Msk))
1201 return 0;
1202
1203 /*------------------------------------------------------------------------------------*/
1204 /* connect status change */
1205 /*------------------------------------------------------------------------------------*/
1206
1207 USB_debug("EHCI port1 status change: 0x%x\n", _ehci->UPSCR[0]);
1208
1209 /*--------------------------------------------------------------------------------*/
1210 /* Disconnect the devices attached to this port. */
1211 /*--------------------------------------------------------------------------------*/
1212 while (1)
1213 {
1214 udev = ehci_find_device_by_port(1);
1215 if (udev == NULL)
1216 break;
1217 disconnect_device(udev);
1218 }
1219
1220 /*--------------------------------------------------------------------------------*/
1221 /* Port de-bounce */
1222 /*--------------------------------------------------------------------------------*/
1223 t0 = get_ticks();
1224 connect_status = _ehci->UPSCR[0] & HSUSBH_UPSCR_CCS_Msk;
1225 while (get_ticks() - t0 < HUB_DEBOUNCE_TIME/10)
1226 {
1227 if (connect_status != (_ehci->UPSCR[0] & HSUSBH_UPSCR_CCS_Msk))
1228 {
1229 /* reset stable time counting */
1230 t0 = get_ticks();
1231 connect_status = _ehci->UPSCR[0] & HSUSBH_UPSCR_CCS_Msk;
1232 }
1233 }
1234
1235 _ehci->UPSCR[0] |= HSUSBH_UPSCR_CSC_Msk; /* clear connect status change bit */
1236
1237 if (connect_status == HSUSBH_UPSCR_CCS_Msk)
1238 {
1239 /*--------------------------------------------------------------------------------*/
1240 /* A new device connected. */
1241 /*--------------------------------------------------------------------------------*/
1242 if (ehci_rh_port_reset(0) != USBH_OK)
1243 {
1244 /* port reset failed, maybe an USB 1.1 device */
1245 _ehci->UPSCR[0] |= HSUSBH_UPSCR_PO_Msk; /* change port owner to OHCI */
1246 _ehci->UPSCR[0] |= HSUSBH_UPSCR_CSC_Msk; /* clear all status change bits */
1247 return 0;
1248 }
1249
1250 /*
1251 * Port reset success. Start to enumerate this new device.
1252 */
1253 udev = alloc_device();
1254 if (udev == NULL)
1255 return 0; /* out-of-memory, do nothing... */
1256
1257 udev->parent = NULL;
1258 udev->port_num = 1;
1259 udev->speed = SPEED_HIGH;
1260 udev->hc_driver = &ehci_driver;
1261
1262 ret = connect_device(udev);
1263 if (ret < 0)
1264 {
1265 USB_error("connect_device error! [%d]\n", ret);
1266 free_device(udev);
1267 }
1268 }
1269 else
1270 {
1271 /*
1272 * Device disconnected
1273 */
1274 while (1)
1275 {
1276 udev = ehci_find_device_by_port(1);
1277 if (udev == NULL)
1278 break;
1279 disconnect_device(udev);
1280 }
1281 }
1282 return 1;
1283 }
1284
1285
1286 HC_DRV_T ehci_driver =
1287 {
1288 ehci_init, /* init */
1289 ehci_shutdown, /* shutdown */
1290 ehci_suspend, /* suspend */
1291 ehci_resume, /* resume */
1292 ehci_ctrl_xfer, /* ctrl_xfer */
1293 ehci_bulk_xfer, /* bulk_xfer */
1294 ehci_int_xfer, /* int_xfer */
1295 ehci_iso_xfer, /* iso_xfer */
1296 ehci_quit_xfer, /* quit_xfer */
1297 ehci_rh_port_reset, /* rthub_port_reset */
1298 ehci_rh_polling /* rthub_polling */
1299 };
1300
1301
1303
1304 /*** (C) COPYRIGHT 2017 Nuvoton Technology Corp. ***/
USBH_ERR_TRANSACTION
#define USBH_ERR_TRANSACTION
Definition: usbh_lib.h:52
USBH_ERR_NOT_FOUND
#define USBH_ERR_NOT_FOUND
Definition: usbh_lib.h:39
HSUSBH_UPSCR_PO_Msk
#define HSUSBH_UPSCR_PO_Msk
Definition: hsusbh_reg.h:1143
HSUSBH
#define HSUSBH
Definition: M480.h:389
HSUSBH_UPSCR_PRST_Msk
#define HSUSBH_UPSCR_PRST_Msk
Definition: hsusbh_reg.h:1134
HSUSBH_UPSCR_SUSPEND_Msk
#define HSUSBH_UPSCR_SUSPEND_Msk
Definition: hsusbh_reg.h:1131
HSUSBH_USTSR_USBINT_Msk
#define HSUSBH_USTSR_USBINT_Msk
Definition: hsusbh_reg.h:1047
HSUSBH_UCMDR_HCRST_Msk
#define HSUSBH_UCMDR_HCRST_Msk
Definition: hsusbh_reg.h:1029
HSUSBH_UCMDR_IAAD_Msk
#define HSUSBH_UCMDR_IAAD_Msk
Definition: hsusbh_reg.h:1041
HSUSBH_UPSCR_CCS_Msk
#define HSUSBH_UPSCR_CCS_Msk
Definition: hsusbh_reg.h:1110
HSUSBH_UPSCR_PEC_Msk
#define HSUSBH_UPSCR_PEC_Msk
Definition: hsusbh_reg.h:1119
NuMicro.h
NuMicro peripheral access layer header file.
hub.h
USB Host hub class driver header file.
HSUSBH_USTSR_UERRINT_Msk
#define HSUSBH_USTSR_UERRINT_Msk
Definition: hsusbh_reg.h:1050
HSUSBH_UCMDR_FLSZ_Pos
#define HSUSBH_UCMDR_FLSZ_Pos
Definition: hsusbh_reg.h:1031
HSUSBH_UCMDR_ASEN_Msk
#define HSUSBH_UCMDR_ASEN_Msk
Definition: hsusbh_reg.h:1038
__attribute__
void *__dso_handle __attribute__((weak))
Definition: _syscalls.c:35
HSUSBH_UIENR_HSERREN_Msk
#define HSUSBH_UIENR_HSERREN_Msk
Definition: hsusbh_reg.h:1089
HSUSBH_UCMDR_PSEN_Msk
#define HSUSBH_UCMDR_PSEN_Msk
Definition: hsusbh_reg.h:1035
HSUSBH_UCMDR_RUN_Msk
#define HSUSBH_UCMDR_RUN_Msk
Definition: hsusbh_reg.h:1026
HSUSBH_UIENR_USBIEN_Msk
#define HSUSBH_UIENR_USBIEN_Msk
Definition: hsusbh_reg.h:1077
HSUSBH_UPSCR_FPR_Msk
#define HSUSBH_UPSCR_FPR_Msk
Definition: hsusbh_reg.h:1128
USBH_ERR_ABORT
#define USBH_ERR_ABORT
Definition: usbh_lib.h:47
USBH_ERR_PORT_RESET
#define USBH_ERR_PORT_RESET
Definition: usbh_lib.h:48
get_ticks
uint32_t get_ticks(void)
A function return current tick count.
HSUSBH_UIENR_IAAEN_Msk
#define HSUSBH_UIENR_IAAEN_Msk
Definition: hsusbh_reg.h:1092
USBH_ERR_EHCI_QH_BUSY
#define USBH_ERR_EHCI_QH_BUSY
Definition: usbh_lib.h:75
USBH_ERR_MEMORY_OUT
#define USBH_ERR_MEMORY_OUT
Definition: usbh_lib.h:32
USBH_ERR_DISCONNECTED
#define USBH_ERR_DISCONNECTED
Definition: usbh_lib.h:50
HSUSBH_UPSCR_PE_Msk
#define HSUSBH_UPSCR_PE_Msk
Definition: hsusbh_reg.h:1116
uac_dev_t::udev
UDEV_T * udev
Definition: usbh_uac.h:111
HSUSBH_UPSCR_PP_Msk
#define HSUSBH_UPSCR_PP_Msk
Definition: hsusbh_reg.h:1140
usb.h
USB Host library header file.
HSUSBH_UPSCR_CSC_Msk
#define HSUSBH_UPSCR_CSC_Msk
Definition: hsusbh_reg.h:1113
NULL
#define NULL
NULL pointer.
Definition: M480.h:604
HSUSBH_USTSR_IAA_Msk
#define HSUSBH_USTSR_IAA_Msk
Definition: hsusbh_reg.h:1062
USBH_OK
#define USBH_OK
Definition: usbh_lib.h:31
USBH_ERR_BUFF_OVERRUN
#define USBH_ERR_BUFF_OVERRUN
Definition: usbh_lib.h:66
USBH_ERR_EHCI_INIT
#define USBH_ERR_EHCI_INIT
Definition: usbh_lib.h:74
HSUSBH_UIENR_UERRIEN_Msk
#define HSUSBH_UIENR_UERRIEN_Msk
Definition: hsusbh_reg.h:1080