/** * \brief Add a transfer descriptor to non-control endpoint. * * \param ep_number endpoint number. * \param buf Point to the data buffer. * \param buf_size Length of the data buffer. * * \return true for success. */ bool ohci_add_td_non_control(uint8_t ep_number, uint8_t *buf, uint32_t buf_size, struct ohci_td_general **td_general_header) { struct ohci_ed *ed_header; uint32_t i; uint8_t ep_dir; if (ep_number & 0x80) { ep_dir = 2; } else { ep_dir = 1; } ep_number = ep_number & 0xF; /* Bulk endpoints. */ i = 0; ed_header = (struct ohci_ed *)OHCI->HcBulkHeadED; while (ed_header != NULL) { if ((ed_header->ed_info.ed_info_s.bEndpointNumber == ep_number) && (ed_header->ed_info.ed_info_s.bDirection == ep_dir)) { /* Wait for transfer done. */ do { p_td_head = ((uint32_t)(ed_header->p_td_head)) & 0xFFFFFFF0; p_td_tail = ((uint32_t)(ed_header->p_td_tail)) & 0xFFFFFFF0; } while(p_td_head != p_td_tail); memset((void *)&bulk_td_head[i], 0, sizeof(bulk_td_head[i])); memset((void *)&bulk_td_tail[i], 0, sizeof(bulk_td_tail[i])); bulk_td_head[i].td_info.bBufferRounding = 1; bulk_td_head[i].td_info.bDirectionPID = 3; bulk_td_head[i].td_info.bDelayInterrupt = 0; bulk_td_head[i].td_info.bDataToggle = 0; bulk_td_head[i].td_info.bErrorCount = 0; bulk_td_head[i].td_info.bConditionCode = 0; bulk_td_head[i].pCurrentBufferPointer= buf; bulk_td_head[i].p_next_td = NULL; bulk_td_head[i].pBufferEnd = buf + buf_size - 1; /* Check the halt status. */ if ((uint32_t)ed_header->p_td_head & 0x01) { return false; } p_td_head = (uint32_t)(&bulk_td_head[i]); p_td_head &= 0xFFFFFFF0; *td_general_header = (struct ohci_td_general *)p_td_head; p_td_tail = (uint32_t)(ed_header->p_td_head); p_td_tail &= 0x0000000F; p_td_head |= p_td_tail; ed_header->p_td_head = (void *)p_td_head; ed_header->p_td_tail = NULL; OHCI->HcCommandStatus = HC_COMMANDSTATUS_BLF; OHCI->HcControl |= HC_CONTROL_BLE; return true; } else { ed_header = ed_header->p_next_ed; i++; } } /* Int/ISO endpoints. */ for (i = 0; i < 8; i++) { ed_header = (struct ohci_ed *)hcca.InterruptTable[i]; if ((ed_header->ed_info.ed_info_s.bEndpointNumber == ep_number) && (ed_header->ed_info.ed_info_s.bDirection == ep_dir)) { if (ed_header->ed_info.ed_info_s.bFormat == 0) { /* Wait for transfer done. */ do { p_td_head = ((uint32_t)(ed_header->p_td_head)) & 0xFFFFFFF0; p_td_tail = ((uint32_t)(ed_header->p_td_tail)) & 0xFFFFFFF0; } while(p_td_head != p_td_tail); OHCI->HcControl &= ~HC_CONTROL_PLE; OHCI->HcControl &= ~HC_CONTROL_IE; memset((void *)&interrupt_td_head[i], 0, sizeof(interrupt_td_head[i])); memset((void *)&interrupt_td_tail[i], 0, sizeof(interrupt_td_tail[i])); interrupt_td_head[i].td_info.bBufferRounding = 1; interrupt_td_head[i].td_info.bDirectionPID = 3; interrupt_td_head[i].td_info.bDelayInterrupt = 0; interrupt_td_head[i].td_info.bDataToggle = 0; interrupt_td_head[i].td_info.bErrorCount = 0; interrupt_td_head[i].td_info.bConditionCode = 0; interrupt_td_head[i].pCurrentBufferPointer= buf; interrupt_td_head[i].p_next_td = NULL; interrupt_td_head[i].pBufferEnd = buf + buf_size - 1; /* Check the halt status. */ if ((uint32_t)ed_header->p_td_head & 0x01) { return false; } p_td_head = (uint32_t)(&interrupt_td_head[i]); p_td_head &= 0xFFFFFFF0; *td_general_header = (struct ohci_td_general *)p_td_head; p_td_tail = (uint32_t)(ed_header->p_td_head); p_td_tail &= 0x0000000F; p_td_head |= p_td_tail; ed_header->p_td_head = (void *)p_td_head; ed_header->p_td_tail = NULL; OHCI->HcControl |= HC_CONTROL_PLE; OHCI->HcControl |= HC_CONTROL_IE; return true; } else { /* Wait for transfer done. */ do { p_td_head = ((uint32_t)(ed_header->p_td_head)) & 0xFFFFFFF0; p_td_tail = ((uint32_t)(ed_header->p_td_tail)) & 0xFFFFFFF0; } while(p_td_head != p_td_tail); OHCI->HcControl &= ~HC_CONTROL_PLE; OHCI->HcControl &= ~HC_CONTROL_IE; memset((void *)&isochronous_td_head[i], 0, sizeof(isochronous_td_head[i])); memset((void *)&isochronous_td_tail[i], 0, sizeof(isochronous_td_tail[i])); /* Start after 3 frame. */ isochronous_td_head[i].td_info.bStartingFrame = ohci_get_frame_number() + 3; isochronous_td_head[i].td_info.bDelayInterrupt = 0; isochronous_td_head[i].td_info.FrameCount = 0; // one frame transaction isochronous_td_head[i].td_info.bConditionCode = 0; isochronous_td_head[i].pBufferPage0= buf; isochronous_td_head[i].p_next_td = NULL; isochronous_td_head[i].pBufferEnd = buf + buf_size - 1; isochronous_td_head[i].offset_psw[0] = 0; /* Check the halt status. */ // if ((uint32_t)ed_header->p_td_head & 0x01) { // return false; // } // set the skip // ed_header->ed_info.ed_info_s.bSkip = 1; ed_header->p_td_head = (void *)&isochronous_td_head[i]; ed_header->p_td_tail = NULL; // clear the skip // ed_header->ed_info.ed_info_s.bSkip = 0; OHCI->HcControl |= HC_CONTROL_PLE; OHCI->HcControl |= HC_CONTROL_IE; return true; } } } return false; }
uint16_t uhd_get_frame_number(void) { return ohci_get_frame_number(); }