29#if CFG_TUH_ENABLED && defined(TUP_USBIP_OHCI)
31#ifndef TUP_OHCI_RHPORTS
32#error OHCI is enabled, but TUP_OHCI_RHPORTS is not defined.
49#define OHCI_REG ((ohci_registers_t *) LPC_USB_BASE)
168TU_ATTR_ALWAYS_INLINE
static inline void *
_phys_addr(
void *virtual_address)
171 return virtual_address;
174TU_ATTR_ALWAYS_INLINE
static inline void *
_virt_addr(
void *physical_address)
177 return physical_address;
187 for(uint8_t i=0; i<32; i++)
189 ohci_data.hcca.interrupt_table[i] = (uint32_t)
_phys_addr(&ohci_data.period_head_ed);
192 ohci_data.control[0].ed.skip = 1;
193 ohci_data.bulk_head_ed.skip = 1;
194 ohci_data.period_head_ed.skip = 1;
197 if (OHCI_REG->control_bit.interrupt_routing == 1)
199 OHCI_REG->command_status_bit.ownership_change_request = 1;
200 while (OHCI_REG->control_bit.interrupt_routing == 1) {}
210#if CFG_TUSB_OS != OPT_OS_NONE
219 OHCI_REG->command_status_bit.controller_reset = 1;
220 while( OHCI_REG->command_status_bit.controller_reset ) {}
223 OHCI_REG->control_head_ed = (uint32_t)
_phys_addr(&ohci_data.control[0].ed);
224 OHCI_REG->bulk_head_ed = (uint32_t)
_phys_addr(&ohci_data.bulk_head_ed);
225 OHCI_REG->hcca = (uint32_t)
_phys_addr(&ohci_data.hcca);
227 OHCI_REG->interrupt_disable = OHCI_REG->interrupt_enable;
228 OHCI_REG->interrupt_status = OHCI_REG->interrupt_status;
237 OHCI_REG->frame_interval ^= (1 << 31);
241 OHCI_REG->rh_status_bit.local_power_status_change = 1;
243#if CFG_TUSB_OS != OPT_OS_NONE
245 osal_task_delay(OHCI_REG->rh_descriptorA_bit.power_on_to_good_time * 2);
254 return (ohci_data.frame_number_hi << 16) | OHCI_REG->frame_number;
273 return OHCI_REG->rhport_status_bit[hostid].current_connect_status;
291 ohci_data.control[0].ed.skip = 1;
335 p_ed->ep_number = ep_addr & 0x0F;
337 p_ed->speed = devtree_info.
speed;
339 p_ed->max_packet_size = ep_size;
351 p_td->buffer_rounding = 1;
357 p_td->current_buffer_pointer = cbp;
361 p_td->buffer_end = cbp;
371 for(uint32_t i=0; i<ED_MAX; i++)
387 for(uint8_t i = 0; i < ED_MAX; i++)
389 if ( !ed_pool[i].used )
return &ed_pool[i];
397 p_ed->next = p_pre->next;
405 while( p_prev->next )
415 p_prev->next = ed->next;
430 for(uint8_t i=0; i < GTD_MAX; i++)
432 if ( !ohci_data.gtd_pool[i].used )
return &ohci_data.gtd_pool[i];
443 p_ed->td_head.address |= (uint32_t)
_phys_addr(p_gtd);
467 p_ed = &ohci_data.control[
dev_addr].ed;
496 gtd_init(qtd, (uint8_t*)(uintptr_t) setup_packet, 8);
503 ed->td_head.address = (uint32_t)
_phys_addr(qtd);
505 OHCI_REG->command_status_bit.control_list_filled = 1;
529 ed->td_head.address = (uint32_t)
_phys_addr(gtd);
531 OHCI_REG->command_status_bit.control_list_filled = 1;
540 gtd->index = ed-ohci_data.ed_pool;
546 if (
TUSB_XFER_BULK == xfer_type) OHCI_REG->command_status_bit.bulk_list_filled = 1;
564 p_ed->is_stalled = 0;
565 p_ed->td_tail &= 0x0Ful;
567 p_ed->td_head.toggle = 0;
568 p_ed->td_head.halted = 0;
583 while(td_head != NULL)
586 uint32_t next = td_head->next;
589 td_head->next = (uint32_t) td_reverse_head;
600 return ((uint32_t) p_qtd) < ((uint32_t) ohci_data.gtd_pool);
607 return &ohci_data.control[p_qtd->index].ed;
610 return &ohci_data.ed_pool[p_qtd->index];
616 uint8_t idx = ((uintptr_t)gtd - (uintptr_t)&ohci_data.control->gtd) /
sizeof(ohci_data.control[0]);
617 return &ohci_data.gtd_extra_control[idx];
619 return &ohci_data.gtd_extra[gtd - ohci_data.gtd_pool];
628 if (current_buffer == 0)
return 0;
630 return (
tu_align4k(buffer_end ^ current_buffer) ? 0x1000 : 0) +
640 ohci_data.hcca.done_head = 0;
642 while( td_head != NULL )
665 ed->td_tail &= 0x0Ful;
666 ed->td_tail |=
tu_align16(ed->td_head.address);
670 uint8_t dir = (ed->ep_number == 0) ? (qtd->pid ==
PID_IN) : (ed->pid ==
PID_IN);
682 uint32_t
const int_en = OHCI_REG->interrupt_enable;
683 uint32_t
const int_status = OHCI_REG->interrupt_status & int_en;
685 if (int_status == 0)
return;
693 ohci_data.frame_number_hi++;
699 for (
int i = 0; i < TUP_OHCI_RHPORTS; i++)
705 if ( OHCI_REG->rhport_status_bit[i].current_connect_status )
721 OHCI_REG->rhport_status[i] = rhport_status;
731 OHCI_REG->interrupt_status = int_status;
static TU_ATTR_ALWAYS_INLINE void hcd_event_device_remove(uint8_t rhport, bool in_isr)
static TU_ATTR_ALWAYS_INLINE void hcd_event_xfer_complete(uint8_t dev_addr, uint8_t ep_addr, uint32_t xferred_bytes, xfer_result_t result, bool in_isr)
static TU_ATTR_ALWAYS_INLINE void hcd_event_device_attach(uint8_t rhport, bool in_isr)
void hcd_devtree_get_info(uint8_t dev_addr, hcd_devtree_info_t *devtree_info)
static TU_ATTR_ALWAYS_INLINE void * _phys_addr(void *virtual_address)
bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, uint8_t const setup_packet[8])
static ohci_gtd_t * gtd_find_free(void)
static gtd_extra_data_t * gtd_get_extra_data(ohci_gtd_t const *const gtd)
static tusb_xfer_type_t ed_get_xfer_type(ohci_ed_t const *const p_ed)
void hcd_int_handler(uint8_t hostid, bool in_isr)
static void done_queue_isr(uint8_t hostid)
@ OHCI_CCODE_DEVICE_NOT_RESPONDING
@ OHCI_CCODE_BIT_STUFFING
@ OHCI_CCODE_BUFFER_OVERRUN
@ OHCI_CCODE_PID_CHECK_FAILURE
@ OHCI_CCODE_NOT_ACCESSED
@ OHCI_CCODE_DATA_OVERRUN
@ OHCI_CCODE_BUFFER_UNDERRUN
@ OHCI_CCODE_DATA_TOGGLE_MISMATCH
@ OHCI_CCODE_UNEXPECTED_PID
@ OHCI_CCODE_DATA_UNDERRUN
bool hcd_edpt_clear_stall(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr)
bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t *buffer, uint16_t buflen)
static uint32_t gtd_xfer_byte_left(uint32_t buffer_end, uint32_t current_buffer)
void hcd_device_close(uint8_t rhport, uint8_t dev_addr)
bool hcd_edpt_abort_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr)
void hcd_port_reset_end(uint8_t rhport)
static void ed_init(ohci_ed_t *p_ed, uint8_t dev_addr, uint16_t ep_size, uint8_t ep_addr, uint8_t xfer_type, uint8_t interval)
static ohci_ed_t * ed_from_addr(uint8_t dev_addr, uint8_t ep_addr)
static TU_ATTR_ALWAYS_INLINE void * _virt_addr(void *physical_address)
CFG_TUH_MEM_SECTION TU_ATTR_ALIGNED(256)
@ OHCI_CONTROL_FUNCSTATE_RESET
@ OHCI_CONTROL_FUNCSTATE_OPERATIONAL
@ OHCI_CONTROL_FUNCSTATE_SUSPEND
@ OHCI_CONTROL_FUNCSTATE_RESUME
static void td_insert_to_ed(ohci_ed_t *p_ed, ohci_gtd_t *p_gtd)
static void gtd_init(ohci_gtd_t *p_td, uint8_t *data_ptr, uint16_t total_bytes)
uint32_t hcd_frame_number(uint8_t rhport)
@ OHCI_INT_SCHEDULING_OVERUN_MASK
@ OHCI_INT_OWNERSHIP_CHANGE_MASK
@ OHCI_INT_UNRECOVERABLE_ERROR_MASK
@ OHCI_INT_RHPORT_STATUS_CHANGE_MASK
@ OHCI_INT_MASTER_ENABLE_MASK
@ OHCI_INT_RESUME_DETECTED_MASK
@ OHCI_INT_FRAME_OVERFLOW_MASK
@ OHCI_INT_WRITEBACK_DONEHEAD_MASK
@ RHPORT_CURRENT_CONNECT_STATUS_MASK
@ RHPORT_LOW_SPEED_DEVICE_ATTACHED_MASK
@ RHPORT_CONNECT_STATUS_CHANGE_MASK
@ RHPORT_PORT_POWER_STATUS_MASK
@ RHPORT_PORT_OVER_CURRENT_INDICATOR_MASK
@ RHPORT_PORT_SUSPEND_STATUS_MASK
@ RHPORT_PORT_SUSPEND_CHANGE_MASK
@ RHPORT_PORT_RESET_CHANGE_MASK
@ RHPORT_PORT_RESET_STATUS_MASK
write '1' to reset port
@ RHPORT_OVER_CURRENT_CHANGE_MASK
@ RHPORT_PORT_ENABLE_CHANGE_MASK
@ RHPORT_PORT_ENABLE_STATUS_MASK
tusb_speed_t hcd_port_speed_get(uint8_t hostid)
static bool gtd_is_control(ohci_gtd_t const *const p_qtd)
bool hcd_init(uint8_t rhport, const tusb_rhport_init_t *rh_init)
bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const *ep_desc)
static ohci_ed_t * ed_find_free(void)
static ohci_ed_t * gtd_get_ed(ohci_gtd_t const *const p_qtd)
static void ed_list_remove_by_addr(ohci_ed_t *p_head, uint8_t dev_addr)
static ohci_td_item_t * list_reverse(ohci_td_item_t *td_head)
bool hcd_port_connect_status(uint8_t hostid)
void hcd_port_reset(uint8_t hostid)
static void ed_list_insert(ohci_ed_t *p_pre, ohci_ed_t *p_ed)
@ OHCI_CONTROL_CONTROL_BULK_RATIO
This specifies the service ratio between Control and Bulk EDs. 0 = 1:1, 3 = 4:1.
@ OHCI_CONTROL_LIST_ISOCHRONOUS_ENABLE_MASK
@ OHCI_CONTROL_LIST_CONTROL_ENABLE_MASK
@ OHCI_CONTROL_LIST_PERIODIC_ENABLE_MASK
@ OHCI_CONTROL_LIST_BULK_ENABLE_MASK
@ OHCI_INT_ON_COMPLETE_NO
@ OHCI_INT_ON_COMPLETE_YES
TU_ATTR_WEAK void osal_task_delay(uint32_t msec)
AUDIO Channel Cluster Descriptor (4.1)
uint8_t bmAttributes
See: audio_clock_source_attribute_t.
TU_ATTR_WEAK void * tusb_app_phys_to_virt(void *phys_addr)
static TU_ATTR_ALWAYS_INLINE uint32_t tu_align4k(uint32_t value)
TU_ATTR_WEAK void * tusb_app_virt_to_phys(void *virt_addr)
static TU_ATTR_ALWAYS_INLINE uint32_t tu_align16(uint32_t value)
static TU_ATTR_ALWAYS_INLINE uint32_t tu_offset4k(uint32_t value)
tusb_speed_t
defined base on EHCI specs value for Endpoint Speed
static TU_ATTR_ALWAYS_INLINE uint8_t tu_edpt_number(uint8_t addr)
static TU_ATTR_ALWAYS_INLINE uint16_t tu_edpt_packet_size(tusb_desc_endpoint_t const *desc_ep)
tusb_xfer_type_t
defined base on USB Specs Endpoint's bmAttributes
TU_ATTR_PACKED_END TU_ATTR_BIT_FIELD_ORDER_END static TU_ATTR_ALWAYS_INLINE tusb_dir_t tu_edpt_dir(uint8_t addr)
static TU_ATTR_ALWAYS_INLINE uint8_t tu_edpt_addr(uint8_t num, uint8_t dir)