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 */
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) ||
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. ***/
#define USBH_ERR_TRANSACTION
Definition: usbh_lib.h:52
#define USBH_ERR_NOT_FOUND
Definition: usbh_lib.h:39
#define HSUSBH_UPSCR_PO_Msk
Definition: hsusbh_reg.h:1143
#define HSUSBH
Definition: M480.h:389
#define HSUSBH_UPSCR_PRST_Msk
Definition: hsusbh_reg.h:1134
#define HSUSBH_UPSCR_SUSPEND_Msk
Definition: hsusbh_reg.h:1131
#define HSUSBH_USTSR_USBINT_Msk
Definition: hsusbh_reg.h:1047
#define HSUSBH_UCMDR_HCRST_Msk
Definition: hsusbh_reg.h:1029
#define HSUSBH_UCMDR_IAAD_Msk
Definition: hsusbh_reg.h:1041
#define HSUSBH_UPSCR_CCS_Msk
Definition: hsusbh_reg.h:1110
#define HSUSBH_UPSCR_PEC_Msk
Definition: hsusbh_reg.h:1119
NuMicro peripheral access layer header file.
USB Host hub class driver header file.
#define HSUSBH_USTSR_UERRINT_Msk
Definition: hsusbh_reg.h:1050
#define HSUSBH_UCMDR_FLSZ_Pos
Definition: hsusbh_reg.h:1031
#define HSUSBH_UCMDR_ASEN_Msk
Definition: hsusbh_reg.h:1038
void *__dso_handle __attribute__((weak))
Definition: _syscalls.c:35
#define HSUSBH_UIENR_HSERREN_Msk
Definition: hsusbh_reg.h:1089
#define HSUSBH_UCMDR_PSEN_Msk
Definition: hsusbh_reg.h:1035
#define HSUSBH_UCMDR_RUN_Msk
Definition: hsusbh_reg.h:1026
#define HSUSBH_UIENR_USBIEN_Msk
Definition: hsusbh_reg.h:1077
#define HSUSBH_UPSCR_FPR_Msk
Definition: hsusbh_reg.h:1128
#define USBH_ERR_ABORT
Definition: usbh_lib.h:47
#define USBH_ERR_PORT_RESET
Definition: usbh_lib.h:48
uint32_t get_ticks(void)
A function return current tick count.
#define HSUSBH_UIENR_IAAEN_Msk
Definition: hsusbh_reg.h:1092
#define USBH_ERR_EHCI_QH_BUSY
Definition: usbh_lib.h:75
#define USBH_ERR_MEMORY_OUT
Definition: usbh_lib.h:32
#define USBH_ERR_DISCONNECTED
Definition: usbh_lib.h:50
#define HSUSBH_UPSCR_PE_Msk
Definition: hsusbh_reg.h:1116
UDEV_T * udev
Definition: usbh_uac.h:111
#define HSUSBH_UPSCR_PP_Msk
Definition: hsusbh_reg.h:1140
USB Host library header file.
#define HSUSBH_UPSCR_CSC_Msk
Definition: hsusbh_reg.h:1113
#define NULL
NULL pointer.
Definition: M480.h:604
#define HSUSBH_USTSR_IAA_Msk
Definition: hsusbh_reg.h:1062
#define USBH_OK
Definition: usbh_lib.h:31
#define USBH_ERR_BUFF_OVERRUN
Definition: usbh_lib.h:66
#define USBH_ERR_EHCI_INIT
Definition: usbh_lib.h:74
#define HSUSBH_UIENR_UERRIEN_Msk
Definition: hsusbh_reg.h:1080