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