28#pragma data_alignment=256
37static ED_T *ed_remove_list;
39static void add_to_ED_remove_list(ED_T *ed)
43 ED_debug(
"add_to_ED_remove_list - 0x%x (0x%x)\n", (
int)ed, ed->Info);
59 ed->next = ed_remove_list;
67static int ohci_reset(
void)
83 USB_error(
"Error! - USB OHCI reset timed out!\n");
89 _ohci->HcControl = HCFS_RESET;
96 USB_error(
"Error! - USB HC reset timed out!\n");
102static void init_hcca_int_table()
105 int i, idx, interval;
107 memset(_hcca.int_table, 0,
sizeof(_hcca.int_table));
109 for(i = 5; i >= 0; i--)
111 _Ied[i] = alloc_ohci_ED();
112 _Ied[i]->Info = ED_SKIP;
116 for(idx = interval - 1; idx < 32; idx += interval)
118 if(_hcca.int_table[idx] == 0)
120 _hcca.int_table[idx] = (uint32_t)_Ied[i];
124 ed_p = (ED_T *)_hcca.int_table[idx];
131 if(ed_p->NextED == 0)
133 ed_p->NextED = (uint32_t)_Ied[i];
136 ed_p = (ED_T *)ed_p->NextED;
143static ED_T * get_int_tree_head_node(
int interval)
147 for(i = 0; i < 5; i++)
156static int get_ohci_interval(
int interval)
158 int i, bInterval = 1;
160 for(i = 0; i < 5; i++)
171static int ohci_init(
void)
179 ed_remove_list =
NULL;
181 init_hcca_int_table();
185 _ohci->HcControlHeadED = 0;
186 _ohci->HcBulkHeadED = 0;
188 _ohci->HcHCCA = (uint32_t)&_hcca;
192 _ohci->HcPeriodicStart = (fminterval * 9) / 10;
195 fminterval |= ((((fminterval - 210) * 6) / 7) << 16);
196 _ohci->HcFmInterval = fminterval;
198 _ohci->HcLSThreshold = 0x628;
213static void ohci_suspend(
void)
216 if(_ohci->HcRhPortStatus[0] & 0x1)
217 _ohci->HcRhPortStatus[0] = 0x4;
219 if(_ohci->HcRhPortStatus[1] & 0x1)
220 _ohci->HcRhPortStatus[1] = 0x4;
232static void ohci_resume(
void)
237 if(_ohci->HcRhPortStatus[0] & 0x4)
238 _ohci->HcRhPortStatus[0] = 0x8;
239 if(_ohci->HcRhPortStatus[1] & 0x4)
240 _ohci->HcRhPortStatus[1] = 0x8;
243static void ohci_shutdown(
void)
254static int ohci_quit_xfer(UTR_T *utr, EP_INFO_T *ep)
263 ed = (ED_T *)(utr->ep->hw_pipe);
269 add_to_ED_remove_list(ed);
270 utr->ep->hw_pipe =
NULL;
273 if((ep !=
NULL) && (ep->hw_pipe !=
NULL))
275 ed = (ED_T *)(ep->hw_pipe);
277 add_to_ED_remove_list(ed);
284uint32_t ed_make_info(UDEV_T *udev, EP_INFO_T *ep)
291 if(udev->descriptor.bMaxPacketSize0 == 0)
293 if(udev->speed == SPEED_LOW)
294 udev->descriptor.bMaxPacketSize0 = 8;
296 udev->descriptor.bMaxPacketSize0 = 64;
298 info = (udev->descriptor.bMaxPacketSize0 << 16)
301 | (0 << ED_CTRL_EN_Pos);
305 info = (ep->wMaxPacketSize << 16);
307 info |= ((ep->bEndpointAddress & 0xf) << ED_CTRL_EN_Pos);
309 if((ep->bEndpointAddress & EP_ADDR_DIR_MASK) == EP_ADDR_DIR_IN)
314 if((ep->bmAttributes & EP_ATTR_TT_MASK) == EP_ATTR_TT_ISO)
315 info |= ED_FORMAT_ISO;
317 info |= ED_FORMAT_GENERAL;
320 info |= ((udev->speed == SPEED_LOW) ? ED_SPEED_LOW : ED_SPEED_FULL);
321 info |= (udev->dev_num);
326static void write_td(TD_T *td, uint32_t info, uint8_t *buff, uint32_t data_len)
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;
335static int ohci_ctrl_xfer(UTR_T *utr)
339 TD_T *td_setup, *td_data, *td_status;
347 td_setup = alloc_ohci_TD(utr);
349 if(utr->data_len > 0)
350 td_data = alloc_ohci_TD(utr);
354 td_status = alloc_ohci_TD(utr);
356 if(td_status ==
NULL)
358 free_ohci_TD(td_setup);
359 if(utr->data_len > 0)
360 free_ohci_TD(td_data);
365 if(udev->ep0.hw_pipe ==
NULL)
367 ed = alloc_ohci_ED();
370 free_ohci_TD(td_setup);
371 free_ohci_TD(td_status);
372 if(utr->data_len > 0)
373 free_ohci_TD(td_data);
378 ed = (ED_T *)udev->ep0.hw_pipe;
383 info = TD_CC | TD_T_DATA0 | TD_TYPE_CTRL;
384 write_td(td_setup, info, (uint8_t *)&utr->setup, 8);
390 if(utr->data_len > 0)
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);
395 info = (TD_CC | TD_R | TD_DP_IN | TD_T_DATA1 | TD_TYPE_CTRL | TD_CTRL_DATA);
397 write_td(td_data, info, utr->buff, utr->data_len);
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;
406 td_setup->NextTD = (uint32_t)td_status;
407 td_setup->next = td_status;
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);
417 info = (TD_CC | TD_DP_OUT | TD_T_DATA1 | TD_TYPE_CTRL);
419 write_td(td_status, info,
NULL, 0);
421 td_status->NextTD = 0;
428 ed->HeadP = (uint32_t)td_setup;
429 ed->Info = ed_make_info(udev,
NULL);
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);
438 if(utr->data_len > 0)
443 utr->ep = &udev->ep0;
444 udev->ep0.hw_pipe = (
void *)ed;
450 _ohci->HcControlHeadED = (uint32_t)ed;
458static int ohci_bulk_xfer(UTR_T *utr)
460 UDEV_T *udev = utr->udev;
461 EP_INFO_T *ep = utr->ep;
463 TD_T *td, *td_p, *td_list =
NULL;
465 uint32_t data_len, xfer_len;
473 info = ed_make_info(udev, ep);
476 ed = (ED_T *)_ohci->HcBulkHeadED;
481 if((ed->HeadP & 0xFFFFFFF0) != (ed->TailP & 0xFFFFFFF0))
486 ed = (ED_T *)ed->NextED;
492 ed = alloc_ohci_ED();
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);
500 ep->hw_pipe = (
void *)ed;
506 data_len = utr->data_len;
511 if((ep->bEndpointAddress & EP_ADDR_DIR_MASK) == EP_ADDR_DIR_OUT)
512 info = (TD_CC | TD_R | TD_DP_OUT | TD_TYPE_BULK);
514 info = (TD_CC | TD_R | TD_DP_IN | TD_TYPE_BULK);
523 td = alloc_ohci_TD(utr);
527 write_td(td, info, buff, xfer_len);
533 data_len -= xfer_len;
543 while(td_p->NextTD != 0)
544 td_p = (TD_T *)td_p->NextTD;
545 td_p->NextTD = (uint32_t)td;
556 ed->HeadP = (ed->HeadP & 0x2) | (uint32_t)td_list;
559 ed->HeadP = (uint32_t)td_list;
561 ed->NextED = _ohci->HcBulkHeadED;
562 _ohci->HcBulkHeadED = (uint32_t)ed;
571 while(td_list !=
NULL)
574 td_list = (TD_T *)td_list->NextTD;
581static int ohci_int_xfer(UTR_T *utr)
583 UDEV_T *udev = utr->udev;
584 EP_INFO_T *ep = utr->ep;
590 if(utr->data_len > 64)
593 td_new = alloc_ohci_TD(utr);
597 ied = get_int_tree_head_node(ep->bInterval);
602 info = ed_make_info(udev, ep);
608 ed = (ED_T *)ed->NextED;
614 ed = alloc_ohci_ED();
619 ed->bInterval = ep->bInterval;
621 td = alloc_ohci_TD(
NULL);
625 free_ohci_TD(td_new);
628 ed->HeadP = (uint32_t)td;
629 ed->TailP = ed->HeadP;
633 td = (TD_T *)(ed->TailP & ~0xf);
635 ep->hw_pipe = (
void *)ed;
640 if((ep->bEndpointAddress & EP_ADDR_DIR_MASK) == EP_ADDR_DIR_OUT)
641 info = (TD_CC | TD_R | TD_DP_OUT | TD_TYPE_INT);
643 info = (TD_CC | TD_R | TD_DP_IN | TD_TYPE_INT);
646 info = (info & ~(1 << 25)) | (td->Info & (1 << 25));
649 write_td(td, info, utr->buff, utr->data_len);
651 td->NextTD = (uint32_t)td_new;
661 ed->TailP = (uint32_t)td_new;
665 ed->NextED = ied->NextED;
666 ied->NextED = (uint32_t)ed;
677static int ohci_iso_xfer(UTR_T *utr)
679 UDEV_T *udev = utr->udev;
680 EP_INFO_T *ep = utr->ep;
682 TD_T *td, *td_list, *last_td;
688 ied = get_int_tree_head_node(ep->bInterval);
693 info = ed_make_info(udev, ep);
699 ed = (ED_T *)ed->NextED;
705 ed = alloc_ohci_ED();
710 ed->bInterval = ep->bInterval;
714 ep->hw_pipe = (
void *)ed;
719 if(utr->bIsoNewSched)
720 ed->next_sf = _hcca.frame_no + OHCI_ISO_DELAY;
723 utr->iso_sf = ed->next_sf;
728 for(i = 0; i < IF_PER_UTR; i++)
732 td = alloc_ohci_TD(utr);
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);
750 last_td->NextTD = (uint32_t)td;
761 if((ed->HeadP & ~0x3) == 0)
762 ed->HeadP = (ed->HeadP & 0x2) | (uint32_t)td_list;
766 td = (TD_T *)(ed->HeadP & ~0x3);
767 while(td->NextTD != 0)
769 td = (TD_T *)td->NextTD;
771 td->NextTD = (uint32_t)td_list;
777 ed->NextED = ied->NextED;
778 ied->NextED = (uint32_t)ed;
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);
788 while(td_list !=
NULL)
791 td_list = (TD_T *)td_list->NextTD;
798static UDEV_T * ohci_find_device_by_port(
int port)
805 if((udev->parent ==
NULL) && (udev->port_num == port) &&
806 ((udev->speed == SPEED_LOW) || (udev->speed == SPEED_FULL)))
813static int ohci_rh_port_reset(
int port)
819 reset_time = PORT_RESET_TIME_MS;
821 for(retry = 0; retry < PORT_RESET_RETRY; retry++)
826 while(
get_ticks() - t0 < (reset_time / 10) + 1)
833 goto port_reset_done;
835 reset_time += PORT_RESET_RETRY_INC_MS;
838 USB_debug(
"OHCI port %d - port reset failed!\n", port + 1);
850static int ohci_rh_polling(
void)
856 for(i = 0; i < 2; i++)
878 udev = ohci_find_device_by_port(i + 1);
881 disconnect_device(udev);
884 if(ohci_rh_port_reset(i) !=
USBH_OK)
890 udev = alloc_device();
895 udev->port_num = i + 1;
897 udev->speed = SPEED_LOW;
899 udev->speed = SPEED_FULL;
900 udev->hc_driver = &ohci_driver;
902 ret = connect_device(udev);
905 USB_error(
"connect_device error! [%d]\n", ret);
918 udev = ohci_find_device_by_port(i + 1);
921 disconnect_device(udev);
929void td_done(TD_T *td)
931 UTR_T *utr = td->utr;
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);
940 if((info & TD_TYPE_Msk) == TD_TYPE_ISO)
946 idx = ((sf + 0x10000 - utr->iso_sf) & 0xFFFF) / get_ohci_interval(td->ed->bInterval);
947 if(idx >= IF_PER_UTR)
949 USB_error(
"ISO invalid index!! %d, %d\n", sf, utr->iso_sf);
953 cc = (td->PSW[0] >> 12) & 0xF;
956 USB_debug(
"ISO F %d N/A!\n", sf);
960 if((cc != 0) && (cc != CC_DATA_UNDERRUN))
965 utr->iso_status[idx] = 0;
966 utr->iso_xlen[idx] = td->PSW[0] & 0x7FF;
970 cc = TD_CC_GET(info);
973 if((cc != CC_NOERROR) && (cc != CC_DATA_UNDERRUN))
975 USB_error(
"TD error, CC = 0x%x\n", cc);
979 switch(info & TD_TYPE_Msk)
982 if(info & TD_CTRL_DATA)
985 utr->xfer_len += td->BE - td->buff_start + 1;
987 utr->xfer_len += td->CBP - td->buff_start;
994 utr->xfer_len += td->BE - td->buff_start + 1;
996 utr->xfer_len += td->CBP - td->buff_start;
1006 if(utr->td_cnt == 0)
1008 utr->bIsTransferDone = 1;
1015static void remove_ed()
1017 ED_T *ed, *ed_p, *ied;
1022 while(ed_remove_list !=
NULL)
1024 ED_debug(
"Remove ED: 0x%x, %d\n", (
int)ed_remove_list, ed_remove_list->bInterval);
1025 ed_p = ed_remove_list;
1031 if((ed_p->Info & ED_EP_ADDR_Msk) == 0)
1033 if(_ohci->HcControlHeadED == (uint32_t)ed_p)
1035 _ohci->HcControlHeadED = (uint32_t)ed_p->NextED;
1040 ed = (ED_T *)_ohci->HcControlHeadED;
1043 if(ed->NextED == (uint32_t)ed_p)
1045 ed->NextED = ed_p->NextED;
1048 ed = (ED_T *)ed->NextED;
1056 else if(ed_p->bInterval > 0)
1058 ied = get_int_tree_head_node(ed_p->bInterval);
1063 if(ed->NextED == (uint32_t)ed_p)
1065 ed->NextED = ed_p->NextED;
1069 ed = (ED_T *)ed->NextED;
1078 if(_ohci->HcBulkHeadED == (uint32_t)ed_p)
1081 _ohci->HcBulkHeadED = ed_p->NextED;
1086 ed = (ED_T *)_ohci->HcBulkHeadED;
1089 if(ed->NextED == (uint32_t)ed_p)
1091 ed->NextED = ed_p->NextED;
1094 ed = (ED_T *)ed->NextED;
1104 td = (TD_T *)(ed_p->HeadP & ~0x3);
1110 td_next = (TD_T *)td->NextTD;
1115 if(utr->td_cnt == 0)
1118 utr->bIsTransferDone = 1;
1129 ed_remove_list = ed_p->next;
1136void USBH_IRQHandler(
void)
1138 TD_T *td, *td_prev, *td_next;
1141 int_sts = _ohci->HcInterruptStatus;
1148 int_sts &= ~USBH_HcInterruptStatus_SF_Msk;
1157 int_sts &= ~USBH_HcInterruptStatus_WDH_Msk;
1161 td = (TD_T *)(_hcca.done_head & TD_ADDR_MASK);
1162 _hcca.done_head = 0;
1169 td_next = (TD_T *)(td->NextTD & TD_ADDR_MASK);
1170 td->NextTD = (uint32_t)td_prev;
1181 TD_debug(
"Reclaim TD 0x%x, next 0x%x\n", (
int)td, td->NextTD);
1182 td_next = (TD_T *)td->NextTD;
1194 _ohci->HcInterruptStatus = int_sts;
1197#ifdef ENABLE_DEBUG_MSG
1199void dump_ohci_int_table()
1205 for(i = 0; i < 1; i++)
1208 USB_debug(
"%02d: ", i);
1210 ed = (ED_T *)_hcca.int_table[i];
1214 USB_debug(
"0x%x (0x%x) => ", (
int)ed, ed->HeadP);
1215 ed = (ED_T *)ed->NextED;
1221void dump_ohci_regs()
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);
1251void dump_ohci_ports()
1253 USB_debug(
"_ohci port0=0x%x, port1=0x%x\n", _ohci->HcRhPortStatus[0], _ohci->HcRhPortStatus[1]);
1258HC_DRV_T ohci_driver =
void *__dso_handle __attribute__((weak))
#define USBH_HcControl_CBSR_Pos
#define USBH_HcRhDescriptorA_OCPM_Msk
#define USBH_HcInterruptEnable_WDH_Msk
#define USBH_HcCommandStatus_CLF_Msk
#define USBH_HcRhPortStatus_PESC_Msk
#define USBH_HcInterruptDisable_SF_Msk
#define USBH_HcInterruptDisable_MIE_Msk
#define USBH_HcInterruptDisable_RHSC_Msk
#define USBH_HcRhStatus_DRWE_Msk
#define USBH_HcCommandStatus_HCR_Msk
#define USBH_HcRhStatus_LPSC_Msk
#define USBH_HcRhPortStatus_CSC_Msk
#define USBH_HcRhPortStatus_PRSC_Msk
#define USBH_HcInterruptStatus_RHSC_Msk
#define USBH_HcRhDescriptorA_PSM_Msk
#define USBH_HcCommandStatus_BLF_Msk
#define USBH_HcInterruptEnable_RD_Msk
#define USBH_HcRhPortStatus_LSDA_Msk
#define USBH_HcControl_PLE_Msk
#define USBH_HcControl_BLE_Msk
#define USBH_HcRhPortStatus_PSSC_Msk
#define USBH_HcRhStatus_LPS_Msk
#define USBH_HcRhPortStatus_PRS_Msk
#define USBH_HcRhStatus_OCI_Msk
#define USBH_HcControl_CLE_Msk
#define USBH_HcInterruptEnable_RHSC_Msk
#define USBH_HcControl_HCFS_Pos
#define USBH_HcRhPortStatus_PES_Msk
#define USBH_HcRhPortStatus_OCIC_Msk
#define USBH_HcInterruptEnable_MIE_Msk
#define USBH_HcControl_IE_Msk
#define USBH_HcInterruptEnable_SF_Msk
#define USBH_HcRhPortStatus_CCS_Msk
#define USBH_HcInterruptStatus_WDH_Msk
#define USBH_HcInterruptStatus_SF_Msk
NuMicro peripheral access layer header file.
#define USBH_ERR_SCH_OVERRUN
#define USBH_ERR_TRANSFER
#define USBH_ERR_INVALID_PARAM
#define USBH_ERR_PORT_RESET
#define USBH_ERR_OHCI_EP_BUSY
#define USBH_ERR_CC_NO_ERR
#define USBH_ERR_NOT_FOUND
#define USBH_ERR_NOT_ACCESS1
#define USBH_ERR_MEMORY_OUT
#define USBH_ERR_DISCONNECTED
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.