29#pragma data_alignment=256
38static ED_T *ed_remove_list;
40static void add_to_ED_remove_list(ED_T *ed)
44 ED_debug(
"add_to_ED_remove_list - 0x%x (0x%x)\n", (
int)ed, ed->Info);
60 ed->next = ed_remove_list;
68static int ohci_reset(
void)
84 USB_error(
"Error! - USB OHCI reset timed out!\n");
90 USBH->HcControl = HCFS_RESET;
97 USB_error(
"Error! - USB HC reset timed out!\n");
103static void init_hcca_int_table()
106 int i, idx, interval;
108 memset(_hcca.int_table, 0,
sizeof(_hcca.int_table));
110 for (i = 5; i >= 0; i--)
112 _Ied[i] = alloc_ohci_ED();
113 _Ied[i]->Info = ED_SKIP;
117 for (idx = interval - 1; idx < 32; idx += interval)
119 if (_hcca.int_table[idx] == 0)
121 _hcca.int_table[idx] = (uint32_t)_Ied[i];
125 ed_p = (ED_T *)_hcca.int_table[idx];
132 if (ed_p->NextED == 0)
134 ed_p->NextED = (uint32_t)_Ied[i];
137 ed_p = (ED_T *)ed_p->NextED;
144static ED_T * get_int_tree_head_node(
int interval)
148 for (i = 0; i < 5; i++)
157static int get_ohci_interval(
int interval)
159 int i, bInterval = 1;
161 for (i = 0; i < 5; i++)
172static int ohci_init(
void)
177 if (ohci_reset() < 0)
180 ed_remove_list =
NULL;
182 init_hcca_int_table();
186 _ohci->HcControlHeadED = 0;
187 _ohci->HcBulkHeadED = 0;
189 _ohci->HcHCCA = (uint32_t)&_hcca;
193 _ohci->HcPeriodicStart = (fminterval*9)/10;
196 fminterval |= ((((fminterval - 210) * 6) / 7) << 16);
197 _ohci->HcFmInterval = fminterval;
199 _ohci->HcLSThreshold = 0x628;
204#ifdef OHCI_PER_PORT_POWER
205 _ohci->HcRhDescriptorB = 0x60000;
209 _ohci->HcRhDescriptorA = (
USBH->HcRhDescriptorA | (1<<9)) & ~USBH_HcRhDescriptorA_PSM_Msk;
220static void ohci_suspend(
void)
223 if (_ohci->HcRhPortStatus[0] & 0x1)
224 _ohci->HcRhPortStatus[0] = 0x4;
226 if (_ohci->HcRhPortStatus[1] & 0x1)
227 _ohci->HcRhPortStatus[1] = 0x4;
239static void ohci_resume(
void)
244 if (_ohci->HcRhPortStatus[0] & 0x4)
245 _ohci->HcRhPortStatus[0] = 0x8;
246 if (_ohci->HcRhPortStatus[1] & 0x4)
247 _ohci->HcRhPortStatus[1] = 0x8;
250static void ohci_shutdown(
void)
254#ifndef OHCI_PER_PORT_POWER
263static int ohci_quit_xfer(UTR_T *utr, EP_INFO_T *ep)
272 ed = (ED_T *)(utr->ep->hw_pipe);
278 add_to_ED_remove_list(ed);
279 utr->ep->hw_pipe =
NULL;
282 if ((ep !=
NULL) && (ep->hw_pipe !=
NULL))
284 ed = (ED_T *)(ep->hw_pipe);
286 add_to_ED_remove_list(ed);
293uint32_t ed_make_info(UDEV_T *udev, EP_INFO_T *ep)
300 if (udev->descriptor.bMaxPacketSize0 == 0)
302 if (udev->speed == SPEED_LOW)
303 udev->descriptor.bMaxPacketSize0 = 8;
305 udev->descriptor.bMaxPacketSize0 = 64;
307 info = (udev->descriptor.bMaxPacketSize0 << 16)
310 | (0 << ED_CTRL_EN_Pos);
314 info = (ep->wMaxPacketSize << 16);
316 info |= ((ep->bEndpointAddress & 0xf) << ED_CTRL_EN_Pos);
318 if ((ep->bEndpointAddress & EP_ADDR_DIR_MASK) == EP_ADDR_DIR_IN)
323 if ((ep->bmAttributes & EP_ATTR_TT_MASK) == EP_ATTR_TT_ISO)
324 info |= ED_FORMAT_ISO;
326 info |= ED_FORMAT_GENERAL;
329 info |= ((udev->speed == SPEED_LOW) ? ED_SPEED_LOW : ED_SPEED_FULL);
330 info |= (udev->dev_num);
335static void write_td(TD_T *td, uint32_t info, uint8_t *buff, uint32_t data_len)
338 td->CBP = (uint32_t)((!buff || !data_len) ? 0 : buff);
339 td->BE = (uint32_t)((!buff || !data_len ) ? 0 : (uint32_t)buff + data_len - 1);
340 td->buff_start = td->CBP;
344static int ohci_ctrl_xfer(UTR_T *utr)
348 TD_T *td_setup, *td_data, *td_status;
356 td_setup = alloc_ohci_TD(utr);
358 if (utr->data_len > 0)
359 td_data = alloc_ohci_TD(utr);
363 td_status = alloc_ohci_TD(utr);
365 if (td_status ==
NULL)
367 free_ohci_TD(td_setup);
368 if (utr->data_len > 0)
369 free_ohci_TD(td_data);
374 if (udev->ep0.hw_pipe ==
NULL)
376 ed = alloc_ohci_ED();
379 free_ohci_TD(td_setup);
380 free_ohci_TD(td_status);
381 if (utr->data_len > 0)
382 free_ohci_TD(td_data);
387 ed = (ED_T *)udev->ep0.hw_pipe;
392 info = TD_CC | TD_T_DATA0 | TD_TYPE_CTRL;
393 write_td(td_setup, info, (uint8_t *)&utr->setup, 8);
399 if (utr->data_len > 0)
401 if ((utr->setup.bmRequestType & 0x80) == REQ_TYPE_OUT)
402 info = (TD_CC | TD_R | TD_DP_OUT | TD_T_DATA1 | TD_TYPE_CTRL | TD_CTRL_DATA);
404 info = (TD_CC | TD_R | TD_DP_IN | TD_T_DATA1 | TD_TYPE_CTRL | TD_CTRL_DATA);
406 write_td(td_data, info, utr->buff, utr->data_len);
408 td_setup->NextTD = (uint32_t)td_data;
409 td_setup->next = td_data;
410 td_data->NextTD = (uint32_t)td_status;
411 td_data->next = td_status;
415 td_setup->NextTD = (uint32_t)td_status;
416 td_setup->next = td_status;
422 ed->Info = ed_make_info(udev,
NULL);
423 if ((utr->setup.bmRequestType & 0x80) == REQ_TYPE_OUT)
424 info = (TD_CC | TD_DP_IN | TD_T_DATA1 | TD_TYPE_CTRL);
426 info = (TD_CC | TD_DP_OUT | TD_T_DATA1 | TD_TYPE_CTRL);
428 write_td(td_status, info,
NULL, 0);
430 td_status->NextTD = 0;
437 ed->HeadP = (uint32_t)td_setup;
438 ed->Info = ed_make_info(udev,
NULL);
445 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);
447 if (utr->data_len > 0)
452 utr->ep = &udev->ep0;
453 udev->ep0.hw_pipe = (
void *)ed;
459 _ohci->HcControlHeadED = (uint32_t)ed;
467static int ohci_bulk_xfer(UTR_T *utr)
469 UDEV_T *udev = utr->udev;
470 EP_INFO_T *ep = utr->ep;
472 TD_T *td, *td_p, *td_list =
NULL;
474 uint32_t data_len, xfer_len;
482 info = ed_make_info(udev, ep);
485 ed = (ED_T *)_ohci->HcBulkHeadED;
488 if (ed->Info == info)
490 if ((ed->HeadP & 0xFFFFFFF0) != (ed->TailP & 0xFFFFFFF0))
495 ed = (ED_T *)ed->NextED;
501 ed = alloc_ohci_ED();
506 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);
509 ep->hw_pipe = (
void *)ed;
515 data_len = utr->data_len;
520 if ((ep->bEndpointAddress & EP_ADDR_DIR_MASK) == EP_ADDR_DIR_OUT)
521 info = (TD_CC | TD_R | TD_DP_OUT | TD_TYPE_BULK);
523 info = (TD_CC | TD_R | TD_DP_IN | TD_TYPE_BULK);
532 td = alloc_ohci_TD(utr);
536 write_td(td, info, buff, xfer_len);
542 data_len -= xfer_len;
552 while (td_p->NextTD != 0)
553 td_p = (TD_T *)td_p->NextTD;
554 td_p->NextTD = (uint32_t)td;
558 while (data_len > 0);
565 ed->HeadP = (ed->HeadP & 0x2) | (uint32_t)td_list;
568 ed->HeadP = (uint32_t)td_list;
570 ed->NextED = _ohci->HcBulkHeadED;
571 _ohci->HcBulkHeadED = (uint32_t)ed;
580 while (td_list !=
NULL)
583 td_list = (TD_T *)td_list->NextTD;
590static int ohci_int_xfer(UTR_T *utr)
592 UDEV_T *udev = utr->udev;
593 EP_INFO_T *ep = utr->ep;
599 if (utr->data_len > 64)
602 td_new = alloc_ohci_TD(utr);
606 ied = get_int_tree_head_node(ep->bInterval);
611 info = ed_make_info(udev, ep);
615 if (ed->Info == info)
617 ed = (ED_T *)ed->NextED;
623 ed = alloc_ohci_ED();
628 ed->bInterval = ep->bInterval;
630 td = alloc_ohci_TD(
NULL);
634 free_ohci_TD(td_new);
637 ed->HeadP = (uint32_t)td;
638 ed->TailP = ed->HeadP;
642 td = (TD_T *)(ed->TailP & ~0xf);
644 ep->hw_pipe = (
void *)ed;
649 if ((ep->bEndpointAddress & EP_ADDR_DIR_MASK) == EP_ADDR_DIR_OUT)
650 info = (TD_CC | TD_R | TD_DP_OUT | TD_TYPE_INT);
652 info = (TD_CC | TD_R | TD_DP_IN | TD_TYPE_INT);
655 info = (info & ~(1<<25)) | (td->Info & (1<<25));
658 write_td(td, info, utr->buff, utr->data_len);
660 td->NextTD = (uint32_t)td_new;
670 ed->TailP = (uint32_t)td_new;
674 ed->NextED = ied->NextED;
675 ied->NextED = (uint32_t)ed;
686static int ohci_iso_xfer(UTR_T *utr)
688 UDEV_T *udev = utr->udev;
689 EP_INFO_T *ep = utr->ep;
691 TD_T *td, *td_list, *last_td;
697 ied = get_int_tree_head_node(ep->bInterval);
702 info = ed_make_info(udev, ep);
706 if (ed->Info == info)
708 ed = (ED_T *)ed->NextED;
714 ed = alloc_ohci_ED();
719 ed->bInterval = ep->bInterval;
723 ep->hw_pipe = (
void *)ed;
728 if (utr->bIsoNewSched)
729 ed->next_sf = _hcca.frame_no + OHCI_ISO_DELAY;
732 utr->iso_sf = ed->next_sf;
737 for (i = 0; i < IF_PER_UTR; i++)
741 td = alloc_ohci_TD(utr);
745 buff_addr = (uint32_t)(utr->iso_buff[i]);
746 td->Info = (TD_CC | TD_TYPE_ISO) | ed->next_sf;
747 ed->next_sf += get_ohci_interval(ed->bInterval);
748 td->CBP = buff_addr & ~0xFFF;
749 td->BE = buff_addr + utr->iso_xlen[i] - 1;
750 td->PSW[0] = 0xE000 | (buff_addr & 0xFFF);
759 last_td->NextTD = (uint32_t)td;
770 if ((ed->HeadP & ~0x3) == 0)
771 ed->HeadP = (ed->HeadP & 0x2) | (uint32_t)td_list;
775 td = (TD_T *)(ed->HeadP & ~0x3);
776 while (td->NextTD != 0)
778 td = (TD_T *)td->NextTD;
780 td->NextTD = (uint32_t)td_list;
786 ed->NextED = ied->NextED;
787 ied->NextED = (uint32_t)ed;
791 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);
797 while (td_list !=
NULL)
800 td_list = (TD_T *)td_list->NextTD;
807static UDEV_T * ohci_find_device_by_port(
int port)
814 if ((udev->parent ==
NULL) && (udev->port_num == port) &&
815 ((udev->speed == SPEED_LOW) || (udev->speed == SPEED_FULL)))
822static int ohci_rh_port_reset(
int port)
828 reset_time = PORT_RESET_TIME_MS;
830 for (retry = 0; retry < PORT_RESET_RETRY; retry++)
835 while (
get_ticks() - t0 < (reset_time/10)+1)
842 goto port_reset_done;
844 reset_time += PORT_RESET_RETRY_INC_MS;
847 USB_debug(
"OHCI port %d - port reset failed!\n", port+1);
859static int ohci_rh_polling(
void)
865 for (i = 0; i < 2; i++)
890 udev = ohci_find_device_by_port(i+1);
893 disconnect_device(udev);
896 if (ohci_rh_port_reset(i) !=
USBH_OK)
902 udev = alloc_device();
907 udev->port_num = i+1;
909 udev->speed = SPEED_LOW;
911 udev->speed = SPEED_FULL;
912 udev->hc_driver = &ohci_driver;
914 ret = connect_device(udev);
917 USB_error(
"connect_device error! [%d]\n", ret);
930 udev = ohci_find_device_by_port(i+1);
933 disconnect_device(udev);
941void td_done(TD_T *td)
943 UTR_T *utr = td->utr;
949 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);
952 if ((info & TD_TYPE_Msk) == TD_TYPE_ISO)
958 idx = ((sf + 0x10000 - utr->iso_sf) & 0xFFFF) / get_ohci_interval(td->ed->bInterval);
959 if (idx >= IF_PER_UTR)
961 USB_error(
"ISO invalid index!! %d, %d\n", sf, utr->iso_sf);
965 cc = (td->PSW[0] >> 12) & 0xF;
968 USB_debug(
"ISO F %d N/A!\n", sf);
972 if ((cc != 0) && (cc != CC_DATA_UNDERRUN))
977 utr->iso_status[idx] = 0;
978 utr->iso_xlen[idx] = td->PSW[0] & 0x7FF;
982 cc = TD_CC_GET(info);
985 if ((cc != CC_NOERROR) && (cc != CC_DATA_UNDERRUN))
987 USB_error(
"TD error, CC = 0x%x\n", cc);
994 switch (info & TD_TYPE_Msk)
997 if (info & TD_CTRL_DATA)
1000 utr->xfer_len += td->BE - td->buff_start + 1;
1002 utr->xfer_len += td->CBP - td->buff_start;
1009 utr->xfer_len += td->BE - td->buff_start + 1;
1011 utr->xfer_len += td->CBP - td->buff_start;
1021 if (utr->td_cnt == 0)
1023 utr->bIsTransferDone = 1;
1030static void remove_ed()
1032 ED_T *ed, *ed_p, *ied;
1037 while (ed_remove_list !=
NULL)
1039 ED_debug(
"Remove ED: 0x%x, %d\n", (
int)ed_remove_list, ed_remove_list->bInterval);
1040 ed_p = ed_remove_list;
1046 if ((ed_p->Info & ED_EP_ADDR_Msk) == 0)
1048 if (_ohci->HcControlHeadED == (uint32_t)ed_p)
1050 _ohci->HcControlHeadED = (uint32_t)ed_p->NextED;
1055 ed = (ED_T *)_ohci->HcControlHeadED;
1058 if (ed->NextED == (uint32_t)ed_p)
1060 ed->NextED = ed_p->NextED;
1063 ed = (ED_T *)ed->NextED;
1071 else if (ed_p->bInterval > 0)
1073 ied = get_int_tree_head_node(ed_p->bInterval);
1078 if (ed->NextED == (uint32_t)ed_p)
1080 ed->NextED = ed_p->NextED;
1084 ed = (ED_T *)ed->NextED;
1093 if (_ohci->HcBulkHeadED == (uint32_t)ed_p)
1096 _ohci->HcBulkHeadED = ed_p->NextED;
1101 ed = (ED_T *)_ohci->HcBulkHeadED;
1104 if (ed->NextED == (uint32_t)ed_p)
1106 ed->NextED = ed_p->NextED;
1109 ed = (ED_T *)ed->NextED;
1119 td = (TD_T *)(ed_p->HeadP & ~0x3);
1125 td_next = (TD_T *)td->NextTD;
1130 if (utr->td_cnt == 0)
1133 utr->bIsTransferDone = 1;
1144 ed_remove_list = ed_p->next;
1151void OHCI_IRQHandler(
void)
1153 TD_T *td, *td_prev, *td_next;
1156 int_sts = _ohci->HcInterruptStatus;
1163 int_sts &= ~USBH_HcInterruptStatus_SF_Msk;
1173 int_sts &= ~USBH_HcInterruptStatus_WDH_Msk;
1177 td = (TD_T *)(_hcca.done_head & TD_ADDR_MASK);
1178 _hcca.done_head = 0;
1185 td_next = (TD_T *)(td->NextTD & TD_ADDR_MASK);
1186 td->NextTD = (uint32_t)td_prev;
1197 TD_debug(
"Reclaim TD 0x%x, next 0x%x\n", (
int)td, td->NextTD);
1198 td_next = (TD_T *)td->NextTD;
1210 _ohci->HcInterruptStatus = int_sts;
1213#ifdef ENABLE_DEBUG_MSG
1215void dump_ohci_int_table()
1220 for (i = 0; i < 32; i++)
1224 USB_debug(
"%02d: ", i);
1226 ed = (ED_T *)_hcca.int_table[i];
1230 USB_debug(
"0x%x (0x%x) => ", (
int)ed, ed->HeadP);
1231 ed = (ED_T *)ed->NextED;
1237void dump_ohci_regs()
1239 USB_debug(
"Dump OCHI registers:\n");
1240 USB_debug(
" HcRevision = 0x%x\n", _ohci->HcRevision);
1241 USB_debug(
" HcControl = 0x%x\n", _ohci->HcControl);
1242 USB_debug(
" HcCommandStatus = 0x%x\n", _ohci->HcCommandStatus);
1243 USB_debug(
" HcInterruptStatus = 0x%x\n", _ohci->HcInterruptStatus);
1244 USB_debug(
" HcInterruptEnable = 0x%x\n", _ohci->HcInterruptEnable);
1245 USB_debug(
" HcInterruptDisable = 0x%x\n", _ohci->HcInterruptDisable);
1246 USB_debug(
" HcHCCA = 0x%x\n", _ohci->HcHCCA);
1247 USB_debug(
" HcPeriodCurrentED = 0x%x\n", _ohci->HcPeriodCurrentED);
1248 USB_debug(
" HcControlHeadED = 0x%x\n", _ohci->HcControlHeadED);
1249 USB_debug(
" HcControlCurrentED = 0x%x\n", _ohci->HcControlCurrentED);
1250 USB_debug(
" HcBulkHeadED = 0x%x\n", _ohci->HcBulkHeadED);
1251 USB_debug(
" HcBulkCurrentED = 0x%x\n", _ohci->HcBulkCurrentED);
1252 USB_debug(
" HcDoneHead = 0x%x\n", _ohci->HcDoneHead);
1253 USB_debug(
" HcFmInterval = 0x%x\n", _ohci->HcFmInterval);
1254 USB_debug(
" HcFmRemaining = 0x%x\n", _ohci->HcFmRemaining);
1255 USB_debug(
" HcFmNumber = 0x%x\n", _ohci->HcFmNumber);
1256 USB_debug(
" HcPeriodicStart = 0x%x\n", _ohci->HcPeriodicStart);
1257 USB_debug(
" HcLSThreshold = 0x%x\n", _ohci->HcLSThreshold);
1258 USB_debug(
" HcRhDescriptorA = 0x%x\n", _ohci->HcRhDescriptorA);
1259 USB_debug(
" HcRhDescriptorB = 0x%x\n", _ohci->HcRhDescriptorB);
1260 USB_debug(
" HcRhStatus = 0x%x\n", _ohci->HcRhStatus);
1261 USB_debug(
" HcRhPortStatus0 = 0x%x\n", _ohci->HcRhPortStatus[0]);
1262 USB_debug(
" HcRhPortStatus1 = 0x%x\n", _ohci->HcRhPortStatus[1]);
1263 USB_debug(
" HcPhyControl = 0x%x\n", _ohci->HcPhyControl);
1264 USB_debug(
" HcMiscControl = 0x%x\n", _ohci->HcMiscControl);
1267void dump_ohci_ports()
1269 USB_debug(
"_ohci port0=0x%x, port1=0x%x\n", _ohci->HcRhPortStatus[0], _ohci->HcRhPortStatus[1]);
1274HC_DRV_T ohci_driver =
void *__dso_handle __attribute__((weak))
NuMicro peripheral access layer header file.
#define NULL
NULL pointer.
#define SYS_CSERVER_VERSION_Msk
#define USBH_HcControl_CBSR_Pos
#define USBH_HcInterruptEnable_WDH_Msk
#define USBH_HcCommandStatus_CLF_Msk
#define USBH_HcRhPortStatus_PESC_Msk
#define USBH_HcInterruptDisable_SF_Msk
#define USBH_HcRhPortStatus_PPS_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_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
#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.