M471M/R1/S BSP V3.01.000
The Board Support Package for M4521
ohci.c
Go to the documentation of this file.
1/**************************************************************************/
9#include <stdio.h>
10#include <stdlib.h>
11#include <string.h>
12
13#include "NuMicro.h"
14
15#include "usb.h"
16#include "hub.h"
17#include "ohci.h"
18
20
21//#define TD_debug printf
22#define TD_debug(...)
23
24//#define ED_debug printf
25#define ED_debug(...)
26
27#ifdef __ICCARM__
28#pragma data_alignment=256
29HCCA_T _hcca;
30#else
31HCCA_T _hcca __attribute__((aligned(256)));
32#endif
33
34ED_T * _Ied[6];
35
36
37static ED_T *ed_remove_list;
38
39static void add_to_ED_remove_list(ED_T *ed)
40{
41 ED_T *p;
42
43 ED_debug("add_to_ED_remove_list - 0x%x (0x%x)\n", (int)ed, ed->Info);
44 DISABLE_OHCI_IRQ();
45
46 /* check if this ED found in ed_remove_list */
47 p = ed_remove_list;
48 while(p)
49 {
50 if(p == ed)
51 {
52 ENABLE_OHCI_IRQ(); /* This ED found in ed_remove_list */
53 return; /* do nothing */
54 }
55 p = p->next;
56 }
57
58 ed->Info |= ED_SKIP; /* ask OHCI controller skip this ED */
59 ed->next = ed_remove_list;
60 ed_remove_list = ed; /* insert to the head of ed_remove_list */
61 ENABLE_OHCI_IRQ();
62 _ohci->HcInterruptStatus = USBH_HcInterruptStatus_SF_Msk;
63 _ohci->HcInterruptEnable |= USBH_HcInterruptEnable_SF_Msk;
64 delay_us(2000); /* Full speed wait 2 ms is enough */
65}
66
67static int ohci_reset(void)
68{
69 volatile int t0;
70
71 /* Disable HC interrupts */
72 _ohci->HcInterruptDisable = USBH_HcInterruptDisable_MIE_Msk;
73
74 /* HC Reset requires max 10 ms delay */
75 _ohci->HcControl = 0;
76 _ohci->HcCommandStatus = USBH_HcCommandStatus_HCR_Msk;
77
78 delay_us(10000);
79
80 /* Check if OHCI reset completed? */
81 if((_ohci->HcCommandStatus & USBH_HcCommandStatus_HCR_Msk) != 0)
82 {
83 USB_error("Error! - USB OHCI reset timed out!\n");
84 return -1;
85 }
86
88
89 _ohci->HcControl = HCFS_RESET;
90
91 delay_us(10000);
92
93 /* Check if OHCI reset completed? */
94 if((_ohci->HcCommandStatus & USBH_HcCommandStatus_HCR_Msk) != 0)
95 {
96 USB_error("Error! - USB HC reset timed out!\n");
97 return -1;
98 }
99 return 0;
100}
101
102static void init_hcca_int_table()
103{
104 ED_T *ed_p;
105 int i, idx, interval;
106
107 memset(_hcca.int_table, 0, sizeof(_hcca.int_table));
108
109 for(i = 5; i >= 0; i--) /* interval = i^2 */
110 {
111 _Ied[i] = alloc_ohci_ED();
112 _Ied[i]->Info = ED_SKIP;
113
114 interval = 0x1 << i;
115
116 for(idx = interval - 1; idx < 32; idx += interval)
117 {
118 if(_hcca.int_table[idx] == 0) /* is empty list, insert directly */
119 {
120 _hcca.int_table[idx] = (uint32_t)_Ied[i];
121 }
122 else
123 {
124 ed_p = (ED_T *)_hcca.int_table[idx];
125
126 while(1)
127 {
128 if(ed_p == _Ied[i])
129 break; /* already chained by previous visit */
130
131 if(ed_p->NextED == 0) /* reach end of list? */
132 {
133 ed_p->NextED = (uint32_t)_Ied[i];
134 break;
135 }
136 ed_p = (ED_T *)ed_p->NextED;
137 }
138 }
139 }
140 }
141}
142
143static ED_T * get_int_tree_head_node(int interval)
144{
145 int i;
146
147 for(i = 0; i < 5; i++)
148 {
149 interval >>= 1;
150 if(interval == 0)
151 return _Ied[i];
152 }
153 return _Ied[5]; /* for interval >= 32 */
154}
155
156static int get_ohci_interval(int interval)
157{
158 int i, bInterval = 1;
159
160 for(i = 0; i < 5; i++)
161 {
162 interval >>= 1;
163 if(interval == 0)
164 return bInterval;
165 bInterval *= 2;
166 }
167 return 32; /* for interval >= 32 */
168}
169
170
171static int ohci_init(void)
172{
173 uint32_t fminterval;
174 volatile int i;
175
176 if(ohci_reset() < 0)
177 return -1;
178
179 ed_remove_list = NULL;
180
181 init_hcca_int_table();
182
183 /* Tell the controller where the control and bulk lists are
184 * The lists are empty now. */
185 _ohci->HcControlHeadED = 0; /* control ED list head */
186 _ohci->HcBulkHeadED = 0; /* bulk ED list head */
187
188 _ohci->HcHCCA = (uint32_t)&_hcca; /* HCCA area */
189
190 /* periodic start 90% of frame interval */
191 fminterval = 0x2edf; /* 11,999 */
192 _ohci->HcPeriodicStart = (fminterval * 9) / 10;
193
194 /* set FSLargestDataPacket, 10,104 for 0x2edf frame interval */
195 fminterval |= ((((fminterval - 210) * 6) / 7) << 16);
196 _ohci->HcFmInterval = fminterval;
197
198 _ohci->HcLSThreshold = 0x628;
199
200 /* start controller operations */
201 _ohci->HcControl = HCFS_OPER | (0x3 << USBH_HcControl_CBSR_Pos);
202
203 _ohci->HcRhDescriptorA = (_ohci->HcRhDescriptorA | (1 << 9)) & ~(USBH_HcRhDescriptorA_PSM_Msk | USBH_HcRhDescriptorA_OCPM_Msk);
204 _ohci->HcRhStatus = USBH_HcRhStatus_LPSC_Msk;
205
207
208 /* POTPGT delay is bits 24-31, in 20 ms units. */
209 delay_us(20000);
210 return 0;
211}
212
213static void ohci_suspend(void)
214{
215 /* set port suspend if connected */
216 if(_ohci->HcRhPortStatus[0] & 0x1)
217 _ohci->HcRhPortStatus[0] = 0x4;
218
219 if(_ohci->HcRhPortStatus[1] & 0x1)
220 _ohci->HcRhPortStatus[1] = 0x4;
221
222 /* enable Device Remote Wakeup */
223 _ohci->HcRhStatus |= USBH_HcRhStatus_DRWE_Msk;
224
225 /* enable USBH RHSC interrupt for system wakeup */
227
228 /* set Host Controller enter suspend state */
229 _ohci->HcControl = (_ohci->HcControl & ~USBH_HcControl_HCFS_Msk) | (3 << USBH_HcControl_HCFS_Pos);
230}
231
232static void ohci_resume(void)
233{
234 _ohci->HcControl = (_ohci->HcControl & ~USBH_HcControl_HCFS_Msk) | (1 << USBH_HcControl_HCFS_Pos);
235 _ohci->HcControl = (_ohci->HcControl & ~USBH_HcControl_HCFS_Msk) | (2 << USBH_HcControl_HCFS_Pos);
236
237 if(_ohci->HcRhPortStatus[0] & 0x4)
238 _ohci->HcRhPortStatus[0] = 0x8;
239 if(_ohci->HcRhPortStatus[1] & 0x4)
240 _ohci->HcRhPortStatus[1] = 0x8;
241}
242
243static void ohci_shutdown(void)
244{
245 ohci_suspend();
246 DISABLE_OHCI_IRQ();
247 _ohci->HcRhStatus = USBH_HcRhStatus_LPS_Msk;
248}
249
250
251/*
252 * Quit current trasnfer via UTR or hardware EP.
253 */
254static int ohci_quit_xfer(UTR_T *utr, EP_INFO_T *ep)
255{
256 ED_T *ed;
257
258 if(utr != NULL)
259 {
260 if(utr->ep == NULL)
261 return USBH_ERR_NOT_FOUND;
262
263 ed = (ED_T *)(utr->ep->hw_pipe);
264
265 if(!ed)
266 return USBH_ERR_NOT_FOUND;
267
268 /* add the endpoint to remove list, it will be removed on the next start of frame */
269 add_to_ED_remove_list(ed);
270 utr->ep->hw_pipe = NULL;
271 }
272
273 if((ep != NULL) && (ep->hw_pipe != NULL))
274 {
275 ed = (ED_T *)(ep->hw_pipe);
276 /* add the endpoint to remove list, it will be removed on the next start of frame */
277 add_to_ED_remove_list(ed);
278 ep->hw_pipe = NULL;
279 }
280
281 return 0;
282}
283
284uint32_t ed_make_info(UDEV_T *udev, EP_INFO_T *ep)
285{
286 uint32_t info;
287
288 if(ep == NULL) /* is a control endpoint */
289 {
290 /* control endpoint direction is from TD */
291 if(udev->descriptor.bMaxPacketSize0 == 0) /* is 0 if device descriptor still not obtained. */
292 {
293 if(udev->speed == SPEED_LOW) /* give a default maximum packet size */
294 udev->descriptor.bMaxPacketSize0 = 8;
295 else
296 udev->descriptor.bMaxPacketSize0 = 64;
297 }
298 info = (udev->descriptor.bMaxPacketSize0 << 16) /* Control endpoint Maximum Packet Size from device descriptor */
299 | ED_DIR_BY_TD /* Direction (Get direction From TD) */
300 | ED_FORMAT_GENERAL /* General format */
301 | (0 << ED_CTRL_EN_Pos); /* Endpoint address 0 */
302 }
303 else /* Other endpoint direction is from endpoint descriptor */
304 {
305 info = (ep->wMaxPacketSize << 16); /* Maximum Packet Size from endpoint */
306
307 info |= ((ep->bEndpointAddress & 0xf) << ED_CTRL_EN_Pos); /* Endpoint Number */
308
309 if((ep->bEndpointAddress & EP_ADDR_DIR_MASK) == EP_ADDR_DIR_IN)
310 info |= ED_DIR_IN;
311 else
312 info |= ED_DIR_OUT;
313
314 if((ep->bmAttributes & EP_ATTR_TT_MASK) == EP_ATTR_TT_ISO)
315 info |= ED_FORMAT_ISO;
316 else
317 info |= ED_FORMAT_GENERAL;
318 }
319
320 info |= ((udev->speed == SPEED_LOW) ? ED_SPEED_LOW : ED_SPEED_FULL); /* Speed */
321 info |= (udev->dev_num); /* Function Address */
322
323 return info;
324}
325
326static void write_td(TD_T *td, uint32_t info, uint8_t *buff, uint32_t data_len)
327{
328 td->Info = info;
329 td->CBP = (uint32_t)((!buff || !data_len) ? 0 : buff);
330 td->BE = (uint32_t)((!buff || !data_len) ? 0 : (uint32_t)buff + data_len - 1);
331 td->buff_start = td->CBP;
332 // TD_debug("TD [0x%x]: 0x%x, 0x%x, 0x%x\n", (int)td, td->Info, td->CBP, td->BE);
333}
334
335static int ohci_ctrl_xfer(UTR_T *utr)
336{
337 UDEV_T *udev;
338 ED_T *ed;
339 TD_T *td_setup, *td_data, *td_status;
340 uint32_t info;
341
342 udev = utr->udev;
343
344 /*------------------------------------------------------------------------------------*/
345 /* Allocate ED and TDs */
346 /*------------------------------------------------------------------------------------*/
347 td_setup = alloc_ohci_TD(utr);
348
349 if(utr->data_len > 0)
350 td_data = alloc_ohci_TD(utr);
351 else
352 td_data = NULL;
353
354 td_status = alloc_ohci_TD(utr);
355
356 if(td_status == NULL)
357 {
358 free_ohci_TD(td_setup);
359 if(utr->data_len > 0)
360 free_ohci_TD(td_data);
361 return USBH_ERR_MEMORY_OUT;
362 }
363
364 /* Check if there's any transfer pending on this endpoint... */
365 if(udev->ep0.hw_pipe == NULL)
366 {
367 ed = alloc_ohci_ED();
368 if(ed == NULL)
369 {
370 free_ohci_TD(td_setup);
371 free_ohci_TD(td_status);
372 if(utr->data_len > 0)
373 free_ohci_TD(td_data);
374 return USBH_ERR_MEMORY_OUT;
375 }
376 }
377 else
378 ed = (ED_T *)udev->ep0.hw_pipe;
379
380 /*------------------------------------------------------------------------------------*/
381 /* prepare SETUP stage TD */
382 /*------------------------------------------------------------------------------------*/
383 info = TD_CC | TD_T_DATA0 | TD_TYPE_CTRL;
384 write_td(td_setup, info, (uint8_t *)&utr->setup, 8);
385 td_setup->ed = ed;
386
387 /*------------------------------------------------------------------------------------*/
388 /* prepare DATA stage TD */
389 /*------------------------------------------------------------------------------------*/
390 if(utr->data_len > 0)
391 {
392 if((utr->setup.bmRequestType & 0x80) == REQ_TYPE_OUT)
393 info = (TD_CC | TD_R | TD_DP_OUT | TD_T_DATA1 | TD_TYPE_CTRL | TD_CTRL_DATA);
394 else
395 info = (TD_CC | TD_R | TD_DP_IN | TD_T_DATA1 | TD_TYPE_CTRL | TD_CTRL_DATA);
396
397 write_td(td_data, info, utr->buff, utr->data_len);
398 td_data->ed = ed;
399 td_setup->NextTD = (uint32_t)td_data;
400 td_setup->next = td_data;
401 td_data->NextTD = (uint32_t)td_status;
402 td_data->next = td_status;
403 }
404 else
405 {
406 td_setup->NextTD = (uint32_t)td_status;
407 td_setup->next = td_status;
408 }
409
410 /*------------------------------------------------------------------------------------*/
411 /* prepare STATUS stage TD */
412 /*------------------------------------------------------------------------------------*/
413 ed->Info = ed_make_info(udev, NULL);
414 if((utr->setup.bmRequestType & 0x80) == REQ_TYPE_OUT)
415 info = (TD_CC | TD_DP_IN | TD_T_DATA1 | TD_TYPE_CTRL);
416 else
417 info = (TD_CC | TD_DP_OUT | TD_T_DATA1 | TD_TYPE_CTRL);
418
419 write_td(td_status, info, NULL, 0);
420 td_status->ed = ed;
421 td_status->NextTD = 0;
422 td_status->next = 0;
423
424 /*------------------------------------------------------------------------------------*/
425 /* prepare ED */
426 /*------------------------------------------------------------------------------------*/
427 ed->TailP = 0;
428 ed->HeadP = (uint32_t)td_setup;
429 ed->Info = ed_make_info(udev, NULL);
430 ed->NextED = 0;
431
432 //TD_debug("TD SETUP [0x%x]: 0x%x, 0x%x, 0x%x, 0x%x\n", (int)td_setup, td_setup->Info, td_setup->CBP, td_setup->BE, td_setup->NextTD);
433 //if (td_data)
434 // TD_debug("TD DATA [0x%x]: 0x%x, 0x%x, 0x%x, 0x%x\n", (int)td_data, td_data->Info, td_data->CBP, td_data->BE, td_data->NextTD);
435 //TD_debug("TD STATUS [0x%x]: 0x%x, 0x%x, 0x%x, 0x%x\n", (int)td_status, td_status->Info, td_status->CBP, td_status->BE, td_status->NextTD);
436 ED_debug("Xfer ED 0x%x: 0x%x 0x%x 0x%x 0x%x\n", (int)ed, ed->Info, ed->TailP, ed->HeadP, ed->NextED);
437
438 if(utr->data_len > 0)
439 utr->td_cnt = 3;
440 else
441 utr->td_cnt = 2;
442
443 utr->ep = &udev->ep0; /* driver can find EP from UTR */
444 udev->ep0.hw_pipe = (void *)ed; /* driver can find ED from EP */
445
446 /*------------------------------------------------------------------------------------*/
447 /* Start transfer */
448 /*------------------------------------------------------------------------------------*/
449 DISABLE_OHCI_IRQ();
450 _ohci->HcControlHeadED = (uint32_t)ed; /* Link ED to OHCI */
451 _ohci->HcControl |= USBH_HcControl_CLE_Msk; /* enable control list */
452 ENABLE_OHCI_IRQ();
453 _ohci->HcCommandStatus = USBH_HcCommandStatus_CLF_Msk; /* start Control list */
454
455 return 0;
456}
457
458static int ohci_bulk_xfer(UTR_T *utr)
459{
460 UDEV_T *udev = utr->udev;
461 EP_INFO_T *ep = utr->ep;
462 ED_T *ed;
463 TD_T *td, *td_p, *td_list = NULL;
464 uint32_t info;
465 uint32_t data_len, xfer_len;
466 int8_t bIsNewED = 0;
467 uint8_t *buff;
468
469 /*------------------------------------------------------------------------------------*/
470 /* Check if there's uncompleted transfer on this endpoint... */
471 /* Prepare ED */
472 /*------------------------------------------------------------------------------------*/
473 info = ed_make_info(udev, ep);
474
475 /* Check if there's any transfer pending on this endpoint... */
476 ed = (ED_T *)_ohci->HcBulkHeadED; /* get the head of bulk endpoint list */
477 while(ed != NULL)
478 {
479 if(ed->Info == info) /* have transfer of this EP not completed? */
480 {
481 if((ed->HeadP & 0xFFFFFFF0) != (ed->TailP & 0xFFFFFFF0))
482 return USBH_ERR_OHCI_EP_BUSY; /* endpoint is busy */
483 else
484 break; /* ED already there... */
485 }
486 ed = (ED_T *)ed->NextED;
487 }
488
489 if(ed == NULL)
490 {
491 bIsNewED = 1;
492 ed = alloc_ohci_ED(); /* allocate an Endpoint Descriptor */
493 if(ed == NULL)
494 return USBH_ERR_MEMORY_OUT;
495 ed->Info = info;
496 ed->HeadP = 0;
497 ED_debug("Link BULK ED 0x%x: 0x%x 0x%x 0x%x 0x%x\n", (int)ed, ed->Info, ed->TailP, ed->HeadP, ed->NextED);
498 }
499
500 ep->hw_pipe = (void *)ed;
501
502 /*------------------------------------------------------------------------------------*/
503 /* Prepare TDs */
504 /*------------------------------------------------------------------------------------*/
505 utr->td_cnt = 0;
506 data_len = utr->data_len;
507 buff = utr->buff;
508
509 do
510 {
511 if((ep->bEndpointAddress & EP_ADDR_DIR_MASK) == EP_ADDR_DIR_OUT)
512 info = (TD_CC | TD_R | TD_DP_OUT | TD_TYPE_BULK);
513 else
514 info = (TD_CC | TD_R | TD_DP_IN | TD_TYPE_BULK);
515
516 info &= ~(1 << 25); /* Data toggle from ED toggleCarry bit */
517
518 if(data_len > 4096) /* maximum transfer length is 4K for each TD */
519 xfer_len = 4096;
520 else
521 xfer_len = data_len; /* remaining data length < 4K */
522
523 td = alloc_ohci_TD(utr); /* allocate a TD */
524 if(td == NULL)
525 goto mem_out;
526 /* fill this TD */
527 write_td(td, info, buff, xfer_len);
528 td->ed = ed;
529
530 utr->td_cnt++; /* increase TD count, for recalim counter */
531
532 buff += xfer_len; /* advanced buffer pointer */
533 data_len -= xfer_len;
534
535 /* chain to end of TD list */
536 if(td_list == NULL)
537 {
538 td_list = td;
539 }
540 else
541 {
542 td_p = td_list;
543 while(td_p->NextTD != 0)
544 td_p = (TD_T *)td_p->NextTD;
545 td_p->NextTD = (uint32_t)td;
546 }
547
548 }
549 while(data_len > 0);
550
551 /*------------------------------------------------------------------------------------*/
552 /* Start transfer */
553 /*------------------------------------------------------------------------------------*/
554 utr->status = 0;
555 DISABLE_OHCI_IRQ();
556 ed->HeadP = (ed->HeadP & 0x2) | (uint32_t)td_list; /* keep toggleCarry bit */
557 if(bIsNewED)
558 {
559 ed->HeadP = (uint32_t)td_list;
560 /* Link ED to OHCI Bulk List */
561 ed->NextED = _ohci->HcBulkHeadED;
562 _ohci->HcBulkHeadED = (uint32_t)ed;
563 }
564 ENABLE_OHCI_IRQ();
565 _ohci->HcControl |= USBH_HcControl_BLE_Msk; /* enable bulk list */
566 _ohci->HcCommandStatus = USBH_HcCommandStatus_BLF_Msk; /* start bulk list */
567
568 return 0;
569
570mem_out:
571 while(td_list != NULL)
572 {
573 td = td_list;
574 td_list = (TD_T *)td_list->NextTD;
575 free_ohci_TD(td);
576 }
577 free_ohci_ED(ed);
578 return USBH_ERR_MEMORY_OUT;
579}
580
581static int ohci_int_xfer(UTR_T *utr)
582{
583 UDEV_T *udev = utr->udev;
584 EP_INFO_T *ep = utr->ep;
585 ED_T *ed, *ied;
586 TD_T *td, *td_new;
587 uint32_t info;
588 int8_t bIsNewED = 0;
589
590 if(utr->data_len > 64) /* USB 1.1 interrupt transfer maximum packet size is 64 */
592
593 td_new = alloc_ohci_TD(utr); /* allocate a TD for dummy TD */
594 if(td_new == NULL)
595 return USBH_ERR_MEMORY_OUT;
596
597 ied = get_int_tree_head_node(ep->bInterval); /* get head node of this interval */
598
599 /*------------------------------------------------------------------------------------*/
600 /* Find if this ED was already in the list */
601 /*------------------------------------------------------------------------------------*/
602 info = ed_make_info(udev, ep);
603 ed = ied;
604 while(ed != NULL)
605 {
606 if(ed->Info == info)
607 break; /* Endpoint found */
608 ed = (ED_T *)ed->NextED;
609 }
610
611 if(ed == NULL) /* ED not found, create it */
612 {
613 bIsNewED = 1;
614 ed = alloc_ohci_ED(); /* allocate an Endpoint Descriptor */
615 if(ed == NULL)
616 return USBH_ERR_MEMORY_OUT;
617 ed->Info = info;
618 ed->HeadP = 0;
619 ed->bInterval = ep->bInterval;
620
621 td = alloc_ohci_TD(NULL); /* allocate the initial dummy TD for ED */
622 if(td == NULL)
623 {
624 free_ohci_ED(ed);
625 free_ohci_TD(td_new);
626 return USBH_ERR_MEMORY_OUT;
627 }
628 ed->HeadP = (uint32_t)td; /* Let both HeadP and TailP point to dummy TD */
629 ed->TailP = ed->HeadP;
630 }
631 else
632 {
633 td = (TD_T *)(ed->TailP & ~0xf); /* TailP always point to the dummy TD */
634 }
635 ep->hw_pipe = (void *)ed;
636
637 /*------------------------------------------------------------------------------------*/
638 /* Prepare TD */
639 /*------------------------------------------------------------------------------------*/
640 if((ep->bEndpointAddress & EP_ADDR_DIR_MASK) == EP_ADDR_DIR_OUT)
641 info = (TD_CC | TD_R | TD_DP_OUT | TD_TYPE_INT);
642 else
643 info = (TD_CC | TD_R | TD_DP_IN | TD_TYPE_INT);
644
645 /* Keep data toggle */
646 info = (info & ~(1 << 25)) | (td->Info & (1 << 25));
647
648 /* fill this TD */
649 write_td(td, info, utr->buff, utr->data_len);
650 td->ed = ed;
651 td->NextTD = (uint32_t)td_new;
652 td->utr = utr;
653 utr->td_cnt = 1; /* increase TD count, for recalim counter */
654 utr->status = 0;
655
656 /*------------------------------------------------------------------------------------*/
657 /* Hook ED and TD list to HCCA interrupt table */
658 /*------------------------------------------------------------------------------------*/
659 DISABLE_OHCI_IRQ();
660
661 ed->TailP = (uint32_t)td_new;
662 if(bIsNewED)
663 {
664 /* Add to list of the same interval */
665 ed->NextED = ied->NextED;
666 ied->NextED = (uint32_t)ed;
667 }
668
669 ENABLE_OHCI_IRQ();
670
671 //printf("Link INT ED 0x%x: 0x%x 0x%x 0x%x 0x%x\n", (int)ed, ed->Info, ed->TailP, ed->HeadP, ed->NextED);
672
673 _ohci->HcControl |= USBH_HcControl_PLE_Msk; /* periodic list enable */
674 return 0;
675}
676
677static int ohci_iso_xfer(UTR_T *utr)
678{
679 UDEV_T *udev = utr->udev;
680 EP_INFO_T *ep = utr->ep;
681 ED_T *ed, *ied;
682 TD_T *td, *td_list, *last_td;
683 int i;
684 uint32_t info;
685 uint32_t buff_addr;
686 int8_t bIsNewED = 0;
687
688 ied = get_int_tree_head_node(ep->bInterval); /* get head node of this interval */
689
690 /*------------------------------------------------------------------------------------*/
691 /* Find if this ED was already in the list */
692 /*------------------------------------------------------------------------------------*/
693 info = ed_make_info(udev, ep);
694 ed = ied;
695 while(ed != NULL)
696 {
697 if(ed->Info == info)
698 break; /* Endpoint found */
699 ed = (ED_T *)ed->NextED;
700 }
701
702 if(ed == NULL) /* ED not found, create it */
703 {
704 bIsNewED = 1;
705 ed = alloc_ohci_ED(); /* allocate an Endpoint Descriptor */
706 if(ed == NULL)
707 return USBH_ERR_MEMORY_OUT;
708 ed->Info = info;
709 ed->HeadP = 0;
710 ed->bInterval = ep->bInterval;
711 }
712 else
713
714 ep->hw_pipe = (void *)ed;
715
716 /*------------------------------------------------------------------------------------*/
717 /* Prepare TDs */
718 /*------------------------------------------------------------------------------------*/
719 if(utr->bIsoNewSched) /* Is the starting of isochronous streaming? */
720 ed->next_sf = _hcca.frame_no + OHCI_ISO_DELAY;
721
722 utr->td_cnt = 0;
723 utr->iso_sf = ed->next_sf;
724
725 last_td = NULL;
726 td_list = NULL;
727
728 for(i = 0; i < IF_PER_UTR; i++)
729 {
730 utr->iso_status[i] = USBH_ERR_NOT_ACCESS1;
731
732 td = alloc_ohci_TD(utr); /* allocate a TD */
733 if(td == NULL)
734 goto mem_out;
735 /* fill this TD */
736 buff_addr = (uint32_t)(utr->iso_buff[i]);
737 td->Info = (TD_CC | TD_TYPE_ISO) | ed->next_sf;
738 ed->next_sf += get_ohci_interval(ed->bInterval);
739 td->CBP = buff_addr & ~0xFFF;
740 td->BE = buff_addr + utr->iso_xlen[i] - 1;
741 td->PSW[0] = 0xE000 | (buff_addr & 0xFFF);
742
743 td->ed = ed;
744 utr->td_cnt++; /* increase TD count, for reclaim counter */
745
746 /* chain to end of TD list */
747 if(td_list == NULL)
748 td_list = td;
749 else
750 last_td->NextTD = (uint32_t)td;
751
752 last_td = td;
753 };
754
755 /*------------------------------------------------------------------------------------*/
756 /* Hook ED and TD list to HCCA interrupt table */
757 /*------------------------------------------------------------------------------------*/
758 utr->status = 0;
759 DISABLE_OHCI_IRQ();
760
761 if((ed->HeadP & ~0x3) == 0)
762 ed->HeadP = (ed->HeadP & 0x2) | (uint32_t)td_list; /* keep toggleCarry bit */
763 else
764 {
765 /* find the tail of TDs under this ED */
766 td = (TD_T *)(ed->HeadP & ~0x3);
767 while(td->NextTD != 0)
768 {
769 td = (TD_T *)td->NextTD;
770 }
771 td->NextTD = (uint32_t)td_list;
772 }
773
774 if(bIsNewED)
775 {
776 /* Add to list of the same interval */
777 ed->NextED = ied->NextED;
778 ied->NextED = (uint32_t)ed;
779 }
780
781 ENABLE_OHCI_IRQ();
782 ED_debug("Link ISO ED 0x%x: 0x%x 0x%x 0x%x 0x%x\n", (int)ed, ed->Info, ed->TailP, ed->HeadP, ed->NextED);
783 _ohci->HcControl |= USBH_HcControl_PLE_Msk | USBH_HcControl_IE_Msk; /* enable periodic list and isochronous transfer */
784
785 return 0;
786
787mem_out:
788 while(td_list != NULL)
789 {
790 td = td_list;
791 td_list = (TD_T *)td_list->NextTD;
792 free_ohci_TD(td);
793 }
794 free_ohci_ED(ed);
795 return USBH_ERR_MEMORY_OUT;
796}
797
798static UDEV_T * ohci_find_device_by_port(int port)
799{
800 UDEV_T *udev;
801
802 udev = g_udev_list;
803 while(udev != NULL)
804 {
805 if((udev->parent == NULL) && (udev->port_num == port) &&
806 ((udev->speed == SPEED_LOW) || (udev->speed == SPEED_FULL)))
807 return udev;
808 udev = udev->next;
809 }
810 return NULL;
811}
812
813static int ohci_rh_port_reset(int port)
814{
815 int retry;
816 int reset_time;
817 uint32_t t0;
818
819 reset_time = PORT_RESET_TIME_MS;
820
821 for(retry = 0; retry < PORT_RESET_RETRY; retry++)
822 {
823 _ohci->HcRhPortStatus[port] = USBH_HcRhPortStatus_PRS_Msk;
824
825 t0 = get_ticks();
826 while(get_ticks() - t0 < (reset_time / 10) + 1)
827 {
828 /*
829 * If device is disconnected or port enabled, we can stop port reset.
830 */
831 if(((_ohci->HcRhPortStatus[port] & USBH_HcRhPortStatus_CCS_Msk) == 0) ||
833 goto port_reset_done;
834 }
835 reset_time += PORT_RESET_RETRY_INC_MS;
836 }
837
838 USB_debug("OHCI port %d - port reset failed!\n", port + 1);
839 return USBH_ERR_PORT_RESET;
840
841port_reset_done:
842 if((_ohci->HcRhPortStatus[port] & USBH_HcRhPortStatus_CCS_Msk) == 0) /* check again if device disconnected */
843 {
844 _ohci->HcRhPortStatus[port] = USBH_HcRhPortStatus_CSC_Msk; /* clear CSC */
846 }
847 return USBH_OK; /* port reset success */
848}
849
850static int ohci_rh_polling(void)
851{
852 int i, change = 0;
853 UDEV_T *udev;
854 int ret;
855
856 for(i = 0; i < 2; i++)
857 {
858 /* clear unwanted port change status */
861
862 if((_ohci->HcRhPortStatus[i] & USBH_HcRhPortStatus_CSC_Msk) == 0)
863 continue;
864
865 /*--------------------------------------------------------------------------------*/
866 /* connect status change */
867 /*--------------------------------------------------------------------------------*/
868
869 _ohci->HcRhPortStatus[i] = USBH_HcRhPortStatus_CSC_Msk; /* clear CSC */
870
871 if(_ohci->HcRhPortStatus[i] & USBH_HcRhPortStatus_CCS_Msk)
872 {
873 /*----------------------------------------------------------------------------*/
874 /* First of all, check if there's any previously connected device. */
875 /*----------------------------------------------------------------------------*/
876 while(1)
877 {
878 udev = ohci_find_device_by_port(i + 1);
879 if(udev == NULL)
880 break;
881 disconnect_device(udev);
882 }
883
884 if(ohci_rh_port_reset(i) != USBH_OK)
885 continue;
886
887 /*
888 * Port reset success...
889 */
890 udev = alloc_device();
891 if(udev == NULL)
892 continue;
893
894 udev->parent = NULL;
895 udev->port_num = i + 1;
896 if(_ohci->HcRhPortStatus[i] & USBH_HcRhPortStatus_LSDA_Msk)
897 udev->speed = SPEED_LOW;
898 else
899 udev->speed = SPEED_FULL;
900 udev->hc_driver = &ohci_driver;
901
902 ret = connect_device(udev);
903 if(ret < 0)
904 {
905 USB_error("connect_device error! [%d]\n", ret);
906 free_device(udev);
907 }
908
909 change = 1;
910 }
911 else
912 {
913 /*
914 * Device disconnected
915 */
916 while(1)
917 {
918 udev = ohci_find_device_by_port(i + 1);
919 if(udev == NULL)
920 break;
921 disconnect_device(udev);
922 }
923 change = 1;
924 }
925 }
926 return change;
927}
928
929void td_done(TD_T *td)
930{
931 UTR_T *utr = td->utr;
932 uint32_t info;
933 int cc;
934
935 info = td->Info;
936
937 TD_debug("td_done: 0x%x, 0x%x, 0x%x, 0x%x, 0x%x\n", (int)td, td->Info, td->CBP, td->NextTD, td->BE);
938
939 /* ISO ... drivers see per-TD length/status */
940 if((info & TD_TYPE_Msk) == TD_TYPE_ISO)
941 {
942 uint16_t sf;
943 int idx;
944
945 sf = info & 0xFFFF;
946 idx = ((sf + 0x10000 - utr->iso_sf) & 0xFFFF) / get_ohci_interval(td->ed->bInterval);
947 if(idx >= IF_PER_UTR)
948 {
949 USB_error("ISO invalid index!! %d, %d\n", sf, utr->iso_sf);
950 goto td_out;
951 }
952
953 cc = (td->PSW[0] >> 12) & 0xF;
954 if(cc == 0xF) /* this frame was not transferred */
955 {
956 USB_debug("ISO F %d N/A!\n", sf);
957 utr->iso_status[idx] = USBH_ERR_SCH_OVERRUN;
958 goto td_out;
959 }
960 if((cc != 0) && (cc != CC_DATA_UNDERRUN))
961 {
962 utr->iso_status[idx] = USBH_ERR_CC_NO_ERR - cc;
963 goto td_out;
964 }
965 utr->iso_status[idx] = 0;
966 utr->iso_xlen[idx] = td->PSW[0] & 0x7FF;
967 }
968 else
969 {
970 cc = TD_CC_GET(info);
971
972 /* short packet is fine */
973 if((cc != CC_NOERROR) && (cc != CC_DATA_UNDERRUN))
974 {
975 USB_error("TD error, CC = 0x%x\n", cc);
976 utr->status = USBH_ERR_TRANSFER;
977 }
978
979 switch(info & TD_TYPE_Msk)
980 {
981 case TD_TYPE_CTRL:
982 if(info & TD_CTRL_DATA)
983 {
984 if(td->CBP == 0)
985 utr->xfer_len += td->BE - td->buff_start + 1;
986 else
987 utr->xfer_len += td->CBP - td->buff_start;
988 }
989 break;
990
991 case TD_TYPE_BULK:
992 case TD_TYPE_INT:
993 if(td->CBP == 0)
994 utr->xfer_len += td->BE - td->buff_start + 1;
995 else
996 utr->xfer_len += td->CBP - td->buff_start;
997 break;
998 }
999 }
1000
1001td_out:
1002
1003 utr->td_cnt--;
1004
1005 /* If all TDs are done, call-back to requester. */
1006 if(utr->td_cnt == 0)
1007 {
1008 utr->bIsTransferDone = 1;
1009 if(utr->func)
1010 utr->func(utr);
1011 }
1012}
1013
1014/* in IRQ context */
1015static void remove_ed()
1016{
1017 ED_T *ed, *ed_p, *ied;
1018 TD_T *td, *td_next;
1019 UTR_T *utr;
1020 int found;
1021
1022 while(ed_remove_list != NULL)
1023 {
1024 ED_debug("Remove ED: 0x%x, %d\n", (int)ed_remove_list, ed_remove_list->bInterval);
1025 ed_p = ed_remove_list;
1026 found = 0;
1027
1028 /*--------------------------------------------------------------------------------*/
1029 /* Remove endpoint from Control List if found */
1030 /*--------------------------------------------------------------------------------*/
1031 if((ed_p->Info & ED_EP_ADDR_Msk) == 0)
1032 {
1033 if(_ohci->HcControlHeadED == (uint32_t)ed_p)
1034 {
1035 _ohci->HcControlHeadED = (uint32_t)ed_p->NextED;
1036 found = 1;
1037 }
1038 else
1039 {
1040 ed = (ED_T *)_ohci->HcControlHeadED;
1041 while(ed != NULL)
1042 {
1043 if(ed->NextED == (uint32_t)ed_p)
1044 {
1045 ed->NextED = ed_p->NextED;
1046 found = 1;
1047 }
1048 ed = (ED_T *)ed->NextED;
1049 }
1050 }
1051 }
1052
1053 /*--------------------------------------------------------------------------------*/
1054 /* Remove INT or ISO endpoint from HCCA interrupt table */
1055 /*--------------------------------------------------------------------------------*/
1056 else if(ed_p->bInterval > 0)
1057 {
1058 ied = get_int_tree_head_node(ed_p->bInterval);
1059
1060 ed = ied;
1061 while(ed != NULL)
1062 {
1063 if(ed->NextED == (uint32_t)ed_p)
1064 {
1065 ed->NextED = ed_p->NextED;
1066 found = 1;
1067 break;
1068 }
1069 ed = (ED_T *)ed->NextED;
1070 }
1071 }
1072
1073 /*--------------------------------------------------------------------------------*/
1074 /* Remove endpoint from Bulk List if found */
1075 /*--------------------------------------------------------------------------------*/
1076 else
1077 {
1078 if(_ohci->HcBulkHeadED == (uint32_t)ed_p)
1079 {
1080 ed = (ED_T *)ed_p;
1081 _ohci->HcBulkHeadED = ed_p->NextED;
1082 found = 1;
1083 }
1084 else
1085 {
1086 ed = (ED_T *)_ohci->HcBulkHeadED;
1087 while(ed != NULL)
1088 {
1089 if(ed->NextED == (uint32_t)ed_p)
1090 {
1091 ed->NextED = ed_p->NextED;
1092 found = 1;
1093 }
1094 ed = (ED_T *)ed->NextED;
1095 }
1096 }
1097 }
1098
1099 /*--------------------------------------------------------------------------------*/
1100 /* Remove and free all TDs under this endpoint */
1101 /*--------------------------------------------------------------------------------*/
1102 if(found)
1103 {
1104 td = (TD_T *)(ed_p->HeadP & ~0x3);
1105 if(td != NULL)
1106 {
1107 while(td != NULL)
1108 {
1109 utr = td->utr;
1110 td_next = (TD_T *)td->NextTD;
1111 free_ohci_TD(td);
1112 td = td_next;
1113
1114 utr->td_cnt--;
1115 if(utr->td_cnt == 0)
1116 {
1117 utr->status = USBH_ERR_ABORT;
1118 utr->bIsTransferDone = 1;
1119 if(utr->func)
1120 utr->func(utr);
1121 }
1122 }
1123 }
1124 }
1125
1126 /*
1127 * Done. Remove this ED from [ed_remove_list] and free it.
1128 */
1129 ed_remove_list = ed_p->next;
1130 free_ohci_ED(ed_p);
1131 }
1132}
1133
1134
1135//static irqreturn_t usbh_irq (struct usb_hcd *hcd)
1136void USBH_IRQHandler(void)
1137{
1138 TD_T *td, *td_prev, *td_next;
1139 uint32_t int_sts;
1140
1141 int_sts = _ohci->HcInterruptStatus;
1142
1143 //USB_debug("ohci int_sts = 0x%x\n", int_sts);
1144
1145 if((_ohci->HcInterruptEnable & USBH_HcInterruptEnable_SF_Msk) &&
1147 {
1148 int_sts &= ~USBH_HcInterruptStatus_SF_Msk;
1149
1150 _ohci->HcInterruptDisable = USBH_HcInterruptDisable_SF_Msk;
1151 remove_ed();
1152 _ohci->HcInterruptStatus = USBH_HcInterruptStatus_SF_Msk;
1153 }
1154
1155 if(int_sts & USBH_HcInterruptStatus_WDH_Msk)
1156 {
1157 int_sts &= ~USBH_HcInterruptStatus_WDH_Msk;
1158 /*
1159 * reverse done list
1160 */
1161 td = (TD_T *)(_hcca.done_head & TD_ADDR_MASK);
1162 _hcca.done_head = 0;
1163 td_prev = NULL;
1164 _ohci->HcInterruptStatus = USBH_HcInterruptStatus_WDH_Msk;
1165
1166 while(td != NULL)
1167 {
1168 //TD_debug("Done list TD 0x%x => 0x%x\n", (int)td, (int)td->NextTD);
1169 td_next = (TD_T *)(td->NextTD & TD_ADDR_MASK);
1170 td->NextTD = (uint32_t)td_prev;
1171 td_prev = td;
1172 td = td_next;
1173 }
1174 td = td_prev; /* first TD of the reversed done list */
1175
1176 /*
1177 * reclaim TDs
1178 */
1179 while(td != NULL)
1180 {
1181 TD_debug("Reclaim TD 0x%x, next 0x%x\n", (int)td, td->NextTD);
1182 td_next = (TD_T *)td->NextTD;
1183 td_done(td);
1184 free_ohci_TD(td);
1185 td = td_next;
1186 }
1187 }
1188
1190 {
1191 _ohci->HcInterruptDisable = USBH_HcInterruptDisable_RHSC_Msk;
1192 }
1193
1194 _ohci->HcInterruptStatus = int_sts;
1195}
1196
1197#ifdef ENABLE_DEBUG_MSG
1198
1199void dump_ohci_int_table()
1200{
1201 int i;
1202 ED_T *ed;
1203
1204// for (i = 0; i < 32; i++)
1205 for(i = 0; i < 1; i++)
1206
1207 {
1208 USB_debug("%02d: ", i);
1209
1210 ed = (ED_T *)_hcca.int_table[i];
1211
1212 while(ed != NULL)
1213 {
1214 USB_debug("0x%x (0x%x) => ", (int)ed, ed->HeadP);
1215 ed = (ED_T *)ed->NextED;
1216 }
1217 printf("0\n");
1218 }
1219}
1220
1221void dump_ohci_regs()
1222{
1223 USB_debug("Dump OCHI registers:\n");
1224 USB_debug(" HcRevision = 0x%x\n", _ohci->HcRevision);
1225 USB_debug(" HcControl = 0x%x\n", _ohci->HcControl);
1226 USB_debug(" HcCommandStatus = 0x%x\n", _ohci->HcCommandStatus);
1227 USB_debug(" HcInterruptStatus = 0x%x\n", _ohci->HcInterruptStatus);
1228 USB_debug(" HcInterruptEnable = 0x%x\n", _ohci->HcInterruptEnable);
1229 USB_debug(" HcInterruptDisable = 0x%x\n", _ohci->HcInterruptDisable);
1230 USB_debug(" HcHCCA = 0x%x\n", _ohci->HcHCCA);
1231 USB_debug(" HcPeriodCurrentED = 0x%x\n", _ohci->HcPeriodCurrentED);
1232 USB_debug(" HcControlHeadED = 0x%x\n", _ohci->HcControlHeadED);
1233 USB_debug(" HcControlCurrentED = 0x%x\n", _ohci->HcControlCurrentED);
1234 USB_debug(" HcBulkHeadED = 0x%x\n", _ohci->HcBulkHeadED);
1235 USB_debug(" HcBulkCurrentED = 0x%x\n", _ohci->HcBulkCurrentED);
1236 USB_debug(" HcDoneHead = 0x%x\n", _ohci->HcDoneHead);
1237 USB_debug(" HcFmInterval = 0x%x\n", _ohci->HcFmInterval);
1238 USB_debug(" HcFmRemaining = 0x%x\n", _ohci->HcFmRemaining);
1239 USB_debug(" HcFmNumber = 0x%x\n", _ohci->HcFmNumber);
1240 USB_debug(" HcPeriodicStart = 0x%x\n", _ohci->HcPeriodicStart);
1241 USB_debug(" HcLSThreshold = 0x%x\n", _ohci->HcLSThreshold);
1242 USB_debug(" HcRhDescriptorA = 0x%x\n", _ohci->HcRhDescriptorA);
1243 USB_debug(" HcRhDescriptorB = 0x%x\n", _ohci->HcRhDescriptorB);
1244 USB_debug(" HcRhStatus = 0x%x\n", _ohci->HcRhStatus);
1245 USB_debug(" HcRhPortStatus0 = 0x%x\n", _ohci->HcRhPortStatus[0]);
1246 USB_debug(" HcRhPortStatus1 = 0x%x\n", _ohci->HcRhPortStatus[1]);
1247 USB_debug(" HcPhyControl = 0x%x\n", _ohci->HcPhyControl);
1248 USB_debug(" HcMiscControl = 0x%x\n", _ohci->HcMiscControl);
1249}
1250
1251void dump_ohci_ports()
1252{
1253 USB_debug("_ohci port0=0x%x, port1=0x%x\n", _ohci->HcRhPortStatus[0], _ohci->HcRhPortStatus[1]);
1254}
1255
1256#endif // ENABLE_DEBUG_MSG
1257
1258HC_DRV_T ohci_driver =
1259{
1260 ohci_init, /* init */
1261 ohci_shutdown, /* shutdown */
1262 ohci_suspend, /* suspend */
1263 ohci_resume, /* resume */
1264 ohci_ctrl_xfer, /* ctrl_xfer */
1265 ohci_bulk_xfer, /* bulk_xfer */
1266 ohci_int_xfer, /* int_xfer */
1267 ohci_iso_xfer, /* iso_xfer */
1268 ohci_quit_xfer, /* quit_xfer */
1269 ohci_rh_port_reset, /* rthub_port_reset */
1270 ohci_rh_polling /* rthub_polling */
1271};
1272
1274
1275/*** (C) COPYRIGHT 2020 Nuvoton Technology Corp. ***/
void *__dso_handle __attribute__((weak))
Definition: _syscalls.c:35
#define USBH_HcControl_CBSR_Pos
Definition: M471M_R1_S.h:13251
#define USBH_HcRhDescriptorA_OCPM_Msk
Definition: M471M_R1_S.h:13393
#define USBH_HcInterruptEnable_WDH_Msk
Definition: M471M_R1_S.h:13303
#define USBH_HcCommandStatus_CLF_Msk
Definition: M471M_R1_S.h:13273
#define USBH_HcRhPortStatus_PESC_Msk
Definition: M471M_R1_S.h:13444
#define USBH_HcInterruptDisable_SF_Msk
Definition: M471M_R1_S.h:13327
#define USBH_HcInterruptDisable_MIE_Msk
Definition: M471M_R1_S.h:13339
#define USBH_HcInterruptDisable_RHSC_Msk
Definition: M471M_R1_S.h:13336
#define USBH_HcRhStatus_DRWE_Msk
Definition: M471M_R1_S.h:13408
#define USBH_HcCommandStatus_HCR_Msk
Definition: M471M_R1_S.h:13270
#define USBH_HcRhStatus_LPSC_Msk
Definition: M471M_R1_S.h:13411
#define USBH_HcRhPortStatus_CSC_Msk
Definition: M471M_R1_S.h:13441
#define USBH_HcRhPortStatus_PRSC_Msk
Definition: M471M_R1_S.h:13453
#define USBH_HcInterruptStatus_RHSC_Msk
Definition: M471M_R1_S.h:13297
#define USBH_HcRhDescriptorA_PSM_Msk
Definition: M471M_R1_S.h:13390
#define USBH_HcCommandStatus_BLF_Msk
Definition: M471M_R1_S.h:13276
#define USBH_HcInterruptEnable_RD_Msk
Definition: M471M_R1_S.h:13309
#define USBH_HcRhPortStatus_LSDA_Msk
Definition: M471M_R1_S.h:13438
#define USBH_HcControl_PLE_Msk
Definition: M471M_R1_S.h:13255
#define USBH_HcControl_BLE_Msk
Definition: M471M_R1_S.h:13264
#define USBH_HcRhPortStatus_PSSC_Msk
Definition: M471M_R1_S.h:13447
#define USBH_HcRhStatus_LPS_Msk
Definition: M471M_R1_S.h:13402
#define USBH_HcRhPortStatus_PRS_Msk
Definition: M471M_R1_S.h:13432
#define USBH_HcRhStatus_OCI_Msk
Definition: M471M_R1_S.h:13405
#define USBH_HcControl_CLE_Msk
Definition: M471M_R1_S.h:13261
#define USBH_HcInterruptEnable_RHSC_Msk
Definition: M471M_R1_S.h:13315
#define USBH_HcControl_HCFS_Pos
Definition: M471M_R1_S.h:13266
#define USBH_HcRhPortStatus_PES_Msk
Definition: M471M_R1_S.h:13423
#define USBH_HcRhPortStatus_OCIC_Msk
Definition: M471M_R1_S.h:13450
#define USBH_HcInterruptEnable_MIE_Msk
Definition: M471M_R1_S.h:13318
#define USBH_HcControl_IE_Msk
Definition: M471M_R1_S.h:13258
#define USBH_HcInterruptEnable_SF_Msk
Definition: M471M_R1_S.h:13306
#define USBH_HcRhPortStatus_CCS_Msk
Definition: M471M_R1_S.h:13420
#define USBH_HcInterruptStatus_WDH_Msk
Definition: M471M_R1_S.h:13285
#define USBH_HcInterruptStatus_SF_Msk
Definition: M471M_R1_S.h:13288
NuMicro peripheral access layer header file.
#define NULL
Definition: M471M_R1_S.h:13908
#define USBH_ERR_SCH_OVERRUN
Definition: usbh_lib.h:48
#define USBH_ERR_TRANSFER
Definition: usbh_lib.h:44
#define USBH_OK
Definition: usbh_lib.h:30
#define USBH_ERR_INVALID_PARAM
Definition: usbh_lib.h:37
#define USBH_ERR_ABORT
Definition: usbh_lib.h:46
#define USBH_ERR_PORT_RESET
Definition: usbh_lib.h:47
#define USBH_ERR_OHCI_EP_BUSY
Definition: usbh_lib.h:71
#define USBH_ERR_CC_NO_ERR
Definition: usbh_lib.h:55
#define USBH_ERR_NOT_FOUND
Definition: usbh_lib.h:38
#define USBH_ERR_NOT_ACCESS1
Definition: usbh_lib.h:68
#define USBH_ERR_MEMORY_OUT
Definition: usbh_lib.h:31
#define USBH_ERR_DISCONNECTED
Definition: usbh_lib.h:49
uint32_t get_ticks(void)
A function return current tick count.
USB Host hub class driver header file.
USB OHCI host controller driver header file.
USB Host library header file.