summaryrefslogtreecommitdiff
path: root/src/host/ohci/ohci.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/host/ohci/ohci.c')
-rw-r--r--src/host/ohci/ohci.c448
1 files changed, 201 insertions, 247 deletions
diff --git a/src/host/ohci/ohci.c b/src/host/ohci/ohci.c
index 91d9b6243..887b3e561 100644
--- a/src/host/ohci/ohci.c
+++ b/src/host/ohci/ohci.c
@@ -38,17 +38,19 @@
#include <common/tusb_common.h>
-#if MODE_HOST_SUPPORTED && (CFG_TUSB_MCU == OPT_MCU_LPC175X_6X)
+#if TUSB_OPT_HOST_ENABLED && (CFG_TUSB_MCU == OPT_MCU_LPC175X_6X || CFG_TUSB_MCU == OPT_MCU_LPC40XX)
//--------------------------------------------------------------------+
// INCLUDE
//--------------------------------------------------------------------+
-#include "hal/hal.h"
#include "osal/osal.h"
#include "../hcd.h"
#include "../usbh_hcd.h"
#include "ohci.h"
+// TODO remove
+#include "chip.h"
+
//--------------------------------------------------------------------+
// MACRO CONSTANT TYPEDEF
//--------------------------------------------------------------------+
@@ -63,10 +65,10 @@ enum {
enum {
OHCI_CONTROL_CONTROL_BULK_RATIO = 3, ///< This specifies the service ratio between Control and Bulk EDs. 0 = 1:1, 3 = 4:1
- OHCI_CONTROL_LIST_PERIODIC_ENABLE_MASK = BIT_(2),
- OHCI_CONTROL_LIST_ISOCHRONOUS_ENABLE_MASK = BIT_(3),
- OHCI_CONTROL_LIST_CONTROL_ENABLE_MASK = BIT_(4),
- OHCI_CONTROL_LIST_BULK_ENABLE_MASK = BIT_(5),
+ OHCI_CONTROL_LIST_PERIODIC_ENABLE_MASK = TU_BIT(2),
+ OHCI_CONTROL_LIST_ISOCHRONOUS_ENABLE_MASK = TU_BIT(3),
+ OHCI_CONTROL_LIST_CONTROL_ENABLE_MASK = TU_BIT(4),
+ OHCI_CONTROL_LIST_BULK_ENABLE_MASK = TU_BIT(5),
};
enum {
@@ -78,42 +80,34 @@ enum {
OHCI_PERIODIC_START = 0x3E67
};
-#ifdef __CC_ARM
-#pragma diag_suppress 66 // Suppress Keil warnings #66-D: enumeration value is out of "int" range
-#endif
-
enum {
- OHCI_INT_SCHEDULING_OVERUN_MASK = BIT_(0),
- OHCI_INT_WRITEBACK_DONEHEAD_MASK = BIT_(1),
- OHCI_INT_SOF_MASK = BIT_(2),
- OHCI_INT_RESUME_DETECTED_MASK = BIT_(3),
- OHCI_INT_UNRECOVERABLE_ERROR_MASK = BIT_(4),
- OHCI_INT_FRAME_OVERFLOW_MASK = BIT_(5),
- OHCI_INT_RHPORT_STATUS_CHANGE_MASK = BIT_(6),
+ OHCI_INT_SCHEDULING_OVERUN_MASK = TU_BIT(0),
+ OHCI_INT_WRITEBACK_DONEHEAD_MASK = TU_BIT(1),
+ OHCI_INT_SOF_MASK = TU_BIT(2),
+ OHCI_INT_RESUME_DETECTED_MASK = TU_BIT(3),
+ OHCI_INT_UNRECOVERABLE_ERROR_MASK = TU_BIT(4),
+ OHCI_INT_FRAME_OVERFLOW_MASK = TU_BIT(5),
+ OHCI_INT_RHPORT_STATUS_CHANGE_MASK = TU_BIT(6),
- OHCI_INT_OWNERSHIP_CHANGE_MASK = BIT_(30),
- OHCI_INT_MASTER_ENABLE_MASK = BIT_(31),
+ OHCI_INT_OWNERSHIP_CHANGE_MASK = TU_BIT(30),
+ OHCI_INT_MASTER_ENABLE_MASK = TU_BIT(31),
};
-#ifdef __CC_ARM
-#pragma diag_default 66 // return Keil 66 to normal severity
-#endif
-
enum {
- OHCI_RHPORT_CURRENT_CONNECT_STATUS_MASK = BIT_(0),
- OHCI_RHPORT_PORT_ENABLE_STATUS_MASK = BIT_(1),
- OHCI_RHPORT_PORT_SUSPEND_STATUS_MASK = BIT_(2),
- OHCI_RHPORT_PORT_OVER_CURRENT_INDICATOR_MASK = BIT_(3),
- OHCI_RHPORT_PORT_RESET_STATUS_MASK = BIT_(4), ///< write '1' to reset port
+ OHCI_RHPORT_CURRENT_CONNECT_STATUS_MASK = TU_BIT(0),
+ OHCI_RHPORT_PORT_ENABLE_STATUS_MASK = TU_BIT(1),
+ OHCI_RHPORT_PORT_SUSPEND_STATUS_MASK = TU_BIT(2),
+ OHCI_RHPORT_PORT_OVER_CURRENT_INDICATOR_MASK = TU_BIT(3),
+ OHCI_RHPORT_PORT_RESET_STATUS_MASK = TU_BIT(4), ///< write '1' to reset port
- OHCI_RHPORT_PORT_POWER_STATUS_MASK = BIT_(8),
- OHCI_RHPORT_LOW_SPEED_DEVICE_ATTACHED_MASK = BIT_(9),
+ OHCI_RHPORT_PORT_POWER_STATUS_MASK = TU_BIT(8),
+ OHCI_RHPORT_LOW_SPEED_DEVICE_ATTACHED_MASK = TU_BIT(9),
- OHCI_RHPORT_CONNECT_STATUS_CHANGE_MASK = BIT_(16),
- OHCI_RHPORT_PORT_ENABLE_CHANGE_MASK = BIT_(17),
- OHCI_RHPORT_PORT_SUSPEND_CHANGE_MASK = BIT_(18),
- OHCI_RHPORT_OVER_CURRENT_CHANGE_MASK = BIT_(19),
- OHCI_RHPORT_PORT_RESET_CHANGE_MASK = BIT_(20),
+ OHCI_RHPORT_CONNECT_STATUS_CHANGE_MASK = TU_BIT(16),
+ OHCI_RHPORT_PORT_ENABLE_CHANGE_MASK = TU_BIT(17),
+ OHCI_RHPORT_PORT_SUSPEND_CHANGE_MASK = TU_BIT(18),
+ OHCI_RHPORT_OVER_CURRENT_CHANGE_MASK = TU_BIT(19),
+ OHCI_RHPORT_PORT_RESET_CHANGE_MASK = TU_BIT(20),
OHCI_RHPORT_ALL_CHANGE_MASK = OHCI_RHPORT_CONNECT_STATUS_CHANGE_MASK | OHCI_RHPORT_PORT_ENABLE_CHANGE_MASK |
OHCI_RHPORT_PORT_SUSPEND_CHANGE_MASK | OHCI_RHPORT_OVER_CURRENT_CHANGE_MASK | OHCI_RHPORT_PORT_RESET_CHANGE_MASK
@@ -137,12 +131,12 @@ enum {
enum {
OHCI_INT_ON_COMPLETE_YES = 0,
- OHCI_INT_ON_COMPLETE_NO = BIN8(111)
+ OHCI_INT_ON_COMPLETE_NO = TU_BIN8(111)
};
//--------------------------------------------------------------------+
// INTERNAL OBJECT & FUNCTION DECLARATION
//--------------------------------------------------------------------+
-CFG_TUSB_MEM_SECTION ATTR_ALIGNED(256) STATIC_VAR ohci_data_t ohci_data;
+CFG_TUSB_MEM_SECTION ATTR_ALIGNED(256) static ohci_data_t ohci_data;
static ohci_ed_t * const p_ed_head[] =
{
@@ -153,15 +147,13 @@ static ohci_ed_t * const p_ed_head[] =
};
static void ed_list_insert(ohci_ed_t * p_pre, ohci_ed_t * p_ed);
-static void ed_list_remove(ohci_ed_t * p_head, ohci_ed_t * p_ed);
-
-static ohci_ed_t * ed_list_find_previous(ohci_ed_t const * p_head, ohci_ed_t const * p_ed);
+static void ed_list_remove_by_addr(ohci_ed_t * p_head, uint8_t dev_addr);
//--------------------------------------------------------------------+
// USBH-HCD API
//--------------------------------------------------------------------+
// Initialization according to 5.1.1.4
-tusb_error_t hcd_init(void)
+bool hcd_init(void)
{
//------------- Data Structure init -------------//
tu_memclr(&ohci_data, sizeof(ohci_data_t));
@@ -198,7 +190,7 @@ tusb_error_t hcd_init(void)
OHCI_REG->control_bit.hc_functional_state = OHCI_CONTROL_FUNCSTATE_OPERATIONAL; // make HC's state to operational state TODO use this to suspend (save power)
OHCI_REG->rh_status_bit.local_power_status_change = 1; // set global power for ports
- return TUSB_ERROR_NONE;
+ return true;
}
//--------------------------------------------------------------------+
@@ -206,23 +198,46 @@ tusb_error_t hcd_init(void)
//--------------------------------------------------------------------+
void hcd_port_reset(uint8_t hostid)
{
+ (void) hostid;
OHCI_REG->rhport_status[0] = OHCI_RHPORT_PORT_RESET_STATUS_MASK;
}
bool hcd_port_connect_status(uint8_t hostid)
{
+ (void) hostid;
return OHCI_REG->rhport_status_bit[0].current_connect_status;
}
tusb_speed_t hcd_port_speed_get(uint8_t hostid)
{
+ (void) hostid;
return OHCI_REG->rhport_status_bit[0].low_speed_device_attached ? TUSB_SPEED_LOW : TUSB_SPEED_FULL;
}
-// TODO refractor abtract later
-void hcd_port_unplug(uint8_t hostid)
+// endpoints are tied to an address, which only reclaim after a long delay when enumerating
+// thus there is no need to make sure ED is not in HC's cahed as it will not for sure
+void hcd_device_close(uint8_t rhport, uint8_t dev_addr)
{
// TODO OHCI
+ (void) rhport;
+
+ // addr0 serves as static head --> only set skip bit
+ if ( dev_addr == 0 )
+ {
+ ohci_data.control[0].ed.skip = 1;
+ }else
+ {
+ // remove control
+ ed_list_remove_by_addr( p_ed_head[TUSB_XFER_CONTROL], dev_addr);
+
+ // remove bulk
+ ed_list_remove_by_addr(p_ed_head[TUSB_XFER_BULK], dev_addr);
+
+ // remove interrupt
+ ed_list_remove_by_addr(p_ed_head[TUSB_XFER_INTERRUPT], dev_addr);
+
+ // TODO remove ISO
+ }
}
//--------------------------------------------------------------------+
@@ -232,28 +247,29 @@ void hcd_port_unplug(uint8_t hostid)
//--------------------------------------------------------------------+
// CONTROL PIPE API
//--------------------------------------------------------------------+
-static inline tusb_xfer_type_t ed_get_xfer_type(ohci_ed_t const * const p_ed) ATTR_PURE ATTR_ALWAYS_INLINE;
static inline tusb_xfer_type_t ed_get_xfer_type(ohci_ed_t const * const p_ed)
{
- return (p_ed->endpoint_number == 0 ) ? TUSB_XFER_CONTROL :
+ return (p_ed->ep_number == 0 ) ? TUSB_XFER_CONTROL :
(p_ed->is_iso ) ? TUSB_XFER_ISOCHRONOUS :
(p_ed->is_interrupt_xfer ) ? TUSB_XFER_INTERRUPT : TUSB_XFER_BULK;
}
static void ed_init(ohci_ed_t *p_ed, uint8_t dev_addr, uint16_t max_packet_size, uint8_t endpoint_addr, uint8_t xfer_type, uint8_t interval)
{
+ (void) interval;
+
// address 0 is used as async head, which always on the list --> cannot be cleared
if (dev_addr != 0)
{
tu_memclr(p_ed, sizeof(ohci_ed_t));
}
- p_ed->device_address = dev_addr;
- p_ed->endpoint_number = endpoint_addr & 0x0F;
- p_ed->direction = (xfer_type == TUSB_XFER_CONTROL) ? OHCI_PID_SETUP : ( (endpoint_addr & TUSB_DIR_IN_MASK) ? OHCI_PID_IN : OHCI_PID_OUT );
- p_ed->speed = usbh_devices[dev_addr].speed;
+ p_ed->dev_addr = dev_addr;
+ p_ed->ep_number = endpoint_addr & 0x0F;
+ p_ed->pid = (xfer_type == TUSB_XFER_CONTROL) ? OHCI_PID_SETUP : ( (endpoint_addr & TUSB_DIR_IN_MASK) ? OHCI_PID_IN : OHCI_PID_OUT );
+ p_ed->speed = _usbh_devices[dev_addr].speed;
p_ed->is_iso = (xfer_type == TUSB_XFER_ISOCHRONOUS) ? 1 : 0;
- p_ed->max_package_size = max_packet_size;
+ p_ed->max_packet_size = max_packet_size;
p_ed->used = 1;
p_ed->is_interrupt_xfer = (xfer_type == TUSB_XFER_INTERRUPT ? 1 : 0);
@@ -274,181 +290,156 @@ static void gtd_init(ohci_gtd_t* p_td, void* data_ptr, uint16_t total_bytes)
p_td->buffer_end = total_bytes ? (((uint8_t*) data_ptr) + total_bytes-1) : NULL;
}
-tusb_error_t hcd_pipe_control_open(uint8_t dev_addr, uint8_t max_packet_size)
+bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, uint8_t const setup_packet[8])
{
- ohci_ed_t* const p_ed = &ohci_data.control[dev_addr].ed;
+ (void) rhport;
- ed_init(p_ed, dev_addr, max_packet_size, 0, TUSB_XFER_CONTROL, 0); // TODO binterval of control is ignored
+ ohci_ed_t* p_ed = &ohci_data.control[dev_addr].ed;
+ ohci_gtd_t *p_setup = &ohci_data.control[dev_addr].gtd;
- if ( dev_addr != 0 )
- { // insert to control head
- ed_list_insert( p_ed_head[TUSB_XFER_CONTROL], p_ed);
- }else
- {
- p_ed->skip = 0; // addr0 is used as static control head --> only need to clear skip bit
- }
-
- return TUSB_ERROR_NONE;
-}
-
-tusb_error_t hcd_pipe_control_xfer(uint8_t dev_addr, tusb_control_request_t const * p_request, uint8_t data[])
-{
- ohci_ed_t* const p_ed = &ohci_data.control[dev_addr].ed;
-
- ohci_gtd_t *p_setup = &ohci_data.control[dev_addr].gtd[0];
- ohci_gtd_t *p_data = p_setup + 1;
- ohci_gtd_t *p_status = p_setup + 2;
-
- //------------- SETUP Phase -------------//
- gtd_init(p_setup, (void*) p_request, 8);
+ gtd_init(p_setup, (void*) setup_packet, 8);
p_setup->index = dev_addr;
p_setup->pid = OHCI_PID_SETUP;
- p_setup->data_toggle = BIN8(10); // DATA0
- p_setup->next_td = (uint32_t) p_data;
-
- //------------- DATA Phase -------------//
- if (p_request->wLength > 0)
- {
- gtd_init(p_data, data, p_request->wLength);
- p_data->index = dev_addr;
- p_data->pid = p_request->bmRequestType_bit.direction ? OHCI_PID_IN : OHCI_PID_OUT;
- p_data->data_toggle = BIN8(11); // DATA1
- }else
- {
- p_data = p_setup;
- }
- p_data->next_td = (uint32_t) p_status;
-
- //------------- STATUS Phase -------------//
- gtd_init(p_status, NULL, 0); // zero-length data
- p_status->index = dev_addr;
- p_status->pid = p_request->bmRequestType_bit.direction ? OHCI_PID_OUT : OHCI_PID_IN; // reverse direction of data phase
- p_status->data_toggle = BIN8(11); // DATA1
- p_status->delay_interrupt = OHCI_INT_ON_COMPLETE_YES;
+ p_setup->data_toggle = TU_BIN8(10); // DATA0
+ p_setup->delay_interrupt = OHCI_INT_ON_COMPLETE_YES;
//------------- Attach TDs list to Control Endpoint -------------//
p_ed->td_head.address = (uint32_t) p_setup;
OHCI_REG->command_status_bit.control_list_filled = 1;
- return TUSB_ERROR_NONE;
+ return true;
}
-tusb_error_t hcd_pipe_control_close(uint8_t dev_addr)
+bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t * buffer, uint16_t buflen)
{
- ohci_ed_t* const p_ed = &ohci_data.control[dev_addr].ed;
+ (void) rhport;
- if ( dev_addr == 0 )
- { // addr0 serves as static head --> only set skip bitx
- p_ed->skip = 1;
- }else
+ uint8_t const epnum = tu_edpt_number(ep_addr);
+ uint8_t const dir = tu_edpt_dir(ep_addr);
+
+ // FIXME control only for now
+ if ( epnum == 0 )
{
- ed_list_remove( p_ed_head[ ed_get_xfer_type(p_ed)], p_ed );
+ ohci_ed_t* const p_ed = &ohci_data.control[dev_addr].ed;
+ ohci_gtd_t *p_data = &ohci_data.control[dev_addr].gtd;
+
+ gtd_init(p_data, buffer, buflen);
+
+ p_data->index = dev_addr;
+ p_data->pid = dir ? OHCI_PID_IN : OHCI_PID_OUT;
+ p_data->data_toggle = TU_BIN8(11); // DATA1
+ p_data->delay_interrupt = OHCI_INT_ON_COMPLETE_YES;
- // TODO refractor to be USBH
- usbh_devices[dev_addr].state = TUSB_DEVICE_STATE_UNPLUG;
+ p_ed->td_head.address = (uint32_t) p_data;
+
+ OHCI_REG->command_status_bit.control_list_filled = 1;
}
- return TUSB_ERROR_NONE;
+ return true;
}
//--------------------------------------------------------------------+
// BULK/INT/ISO PIPE API
//--------------------------------------------------------------------+
-static inline uint8_t ed_get_index(ohci_ed_t const * const p_ed) ATTR_PURE ATTR_ALWAYS_INLINE;
-static inline uint8_t ed_get_index(ohci_ed_t const * const p_ed)
+static inline ohci_ed_t * ed_from_addr(uint8_t dev_addr, uint8_t ep_addr)
{
- return p_ed - ohci_data.device[p_ed->device_address-1].ed;
-}
+ if ( tu_edpt_number(ep_addr) == 0 ) return &ohci_data.control[dev_addr].ed;
-static inline ohci_ed_t * ed_from_pipe_handle(pipe_handle_t pipe_hdl) ATTR_PURE ATTR_ALWAYS_INLINE;
-static inline ohci_ed_t * ed_from_pipe_handle(pipe_handle_t pipe_hdl)
-{
- return &ohci_data.device[pipe_hdl.dev_addr-1].ed[pipe_hdl.index];
-}
+ ohci_ed_t* ed_pool = ohci_data.ed_pool;
-static inline ohci_ed_t * ed_find_free(uint8_t dev_addr) ATTR_PURE ATTR_ALWAYS_INLINE;
-static inline ohci_ed_t * ed_find_free(uint8_t dev_addr)
-{
- for(uint8_t i = 0; i < HCD_MAX_ENDPOINT; i++)
+ for(uint32_t i=0; i<HCD_MAX_ENDPOINT; i++)
{
- if ( !ohci_data.device[dev_addr-1].ed[i].used )
+ if ( (ed_pool[i].dev_addr == dev_addr) &&
+ ep_addr == tu_edpt_addr(ed_pool[i].ep_number, ed_pool[i].pid == OHCI_PID_IN) )
{
- return &ohci_data.device[dev_addr-1].ed[i];
+ return &ed_pool[i];
}
}
return NULL;
}
-static ohci_ed_t * ed_list_find_previous(ohci_ed_t const * p_head, ohci_ed_t const * p_ed)
+static inline ohci_ed_t * ed_find_free(void)
{
- uint32_t max_loop = HCD_MAX_ENDPOINT*CFG_TUSB_HOST_DEVICE_MAX;
-
- ohci_ed_t const * p_prev = p_head;
-
- TU_ASSERT(p_prev, NULL);
+ ohci_ed_t* ed_pool = ohci_data.ed_pool;
- while ( tu_align16(p_prev->next_ed) != 0 && /* not reach null */
- tu_align16(p_prev->next_ed) != (uint32_t) p_ed && /* not found yet */
- max_loop > 0)
+ for(uint8_t i = 0; i < HCD_MAX_ENDPOINT; i++)
{
- p_prev = (ohci_ed_t const *) tu_align16(p_prev->next_ed);
- max_loop--;
+ if ( !ed_pool[i].used ) return &ed_pool[i];
}
- return ( tu_align16(p_prev->next_ed) == (uint32_t) p_ed ) ? (ohci_ed_t*) p_prev : NULL;
+ return NULL;
}
static void ed_list_insert(ohci_ed_t * p_pre, ohci_ed_t * p_ed)
{
- p_ed->next_ed |= p_pre->next_ed; // to reserve 4 lsb bits
- p_pre->next_ed = (p_pre->next_ed & 0x0FUL) | ((uint32_t) p_ed);
+ p_ed->next = p_pre->next;
+ p_pre->next = (uint32_t) p_ed;
}
-static void ed_list_remove(ohci_ed_t * p_head, ohci_ed_t * p_ed)
+static void ed_list_remove_by_addr(ohci_ed_t * p_head, uint8_t dev_addr)
{
- ohci_ed_t * const p_prev = ed_list_find_previous(p_head, p_ed);
+ ohci_ed_t* p_prev = p_head;
+
+ while( p_prev->next )
+ {
+ ohci_ed_t* ed = (ohci_ed_t*) p_prev->next;
+
+ if (ed->dev_addr == dev_addr)
+ {
+ // unlink ed
+ p_prev->next = ed->next;
- p_prev->next_ed = (p_prev->next_ed & 0x0fUL) | tu_align16(p_ed->next_ed);
- // point the removed ED's next pointer to list head to make sure HC can always safely move away from this ED
- p_ed->next_ed = (uint32_t) p_head;
- p_ed->used = 0; // free ED
+ // point the removed ED's next pointer to list head to make sure HC can always safely move away from this ED
+ ed->next = (uint32_t) p_head;
+ ed->used = 0;
+ }
+
+ // check next valid since we could remove it
+ if (p_prev->next) p_prev = (ohci_ed_t*) p_prev->next;
+ }
}
-pipe_handle_t hcd_pipe_open(uint8_t dev_addr, tusb_desc_endpoint_t const * p_endpoint_desc, uint8_t class_code)
+bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const * ep_desc)
{
- pipe_handle_t const null_handle = { .dev_addr = 0, .xfer_type = 0, .index = 0 };
+ (void) rhport;
// TODO iso support
- TU_ASSERT(p_endpoint_desc->bmAttributes.xfer != TUSB_XFER_ISOCHRONOUS, null_handle );
+ TU_ASSERT(ep_desc->bmAttributes.xfer != TUSB_XFER_ISOCHRONOUS);
//------------- Prepare Queue Head -------------//
- ohci_ed_t * const p_ed = ed_find_free(dev_addr);
- TU_ASSERT(p_ed, null_handle);
+ ohci_ed_t * p_ed;
- ed_init( p_ed, dev_addr, p_endpoint_desc->wMaxPacketSize.size, p_endpoint_desc->bEndpointAddress,
- p_endpoint_desc->bmAttributes.xfer, p_endpoint_desc->bInterval );
- p_ed->td_tail.class_code = class_code;
+ if ( ep_desc->bEndpointAddress == 0 )
+ {
+ p_ed = &ohci_data.control[dev_addr].ed;
+ }else
+ {
+ p_ed = ed_find_free();
+ }
+ TU_ASSERT(p_ed);
- ed_list_insert( p_ed_head[p_endpoint_desc->bmAttributes.xfer], p_ed );
+ ed_init( p_ed, dev_addr, ep_desc->wMaxPacketSize.size, ep_desc->bEndpointAddress,
+ ep_desc->bmAttributes.xfer, ep_desc->bInterval );
- return (pipe_handle_t)
+ // control of dev0 is used as static async head
+ if ( dev_addr == 0 )
{
- .dev_addr = dev_addr,
- .xfer_type = p_endpoint_desc->bmAttributes.xfer,
- .index = ed_get_index(p_ed)
- };
+ p_ed->skip = 0; // only need to clear skip bit
+ return true;
+ }
+
+ ed_list_insert( p_ed_head[ep_desc->bmAttributes.xfer], p_ed );
+
+ return true;
}
-static ohci_gtd_t * gtd_find_free(uint8_t dev_addr)
+static ohci_gtd_t * gtd_find_free(void)
{
for(uint8_t i=0; i < HCD_MAX_XFER; i++)
{
- if (!ohci_data.device[dev_addr-1].gtd[i].used)
- {
- return &ohci_data.device[dev_addr-1].gtd[i];
- }
+ if ( !ohci_data.gtd_pool[i].used ) return &ohci_data.gtd_pool[i];
}
return NULL;
@@ -463,97 +454,72 @@ static void td_insert_to_ed(ohci_ed_t* p_ed, ohci_gtd_t * p_gtd)
}
else
{ // TODO currently only support queue up to 2 TD each endpoint at a time
- ((ohci_gtd_t*) tu_align16(p_ed->td_head.address))->next_td = (uint32_t) p_gtd;
+ ((ohci_gtd_t*) tu_align16(p_ed->td_head.address))->next = (uint32_t) p_gtd;
}
}
-static tusb_error_t pipe_queue_xfer(pipe_handle_t pipe_hdl, uint8_t buffer[], uint16_t total_bytes, bool int_on_complete)
+static bool pipe_queue_xfer(uint8_t dev_addr, uint8_t ep_addr, uint8_t buffer[], uint16_t total_bytes, bool int_on_complete)
{
- ohci_ed_t* const p_ed = ed_from_pipe_handle(pipe_hdl);
+ ohci_ed_t* const p_ed = ed_from_addr(dev_addr, ep_addr);
- if ( !p_ed->is_iso )
- {
- ohci_gtd_t * const p_gtd = gtd_find_free(pipe_hdl.dev_addr);
- TU_ASSERT(p_gtd, TUSB_ERROR_EHCI_NOT_ENOUGH_QTD); // TODO refractor error code
+ // not support ISO yet
+ TU_VERIFY ( !p_ed->is_iso );
- gtd_init(p_gtd, buffer, total_bytes);
- p_gtd->index = pipe_hdl.index;
- if ( int_on_complete ) p_gtd->delay_interrupt = OHCI_INT_ON_COMPLETE_YES;
+ ohci_gtd_t * const p_gtd = gtd_find_free();
+ TU_ASSERT(p_gtd); // not enough gtd
- td_insert_to_ed(p_ed, p_gtd);
- }else
- {
- TU_ASSERT_ERR(TUSB_ERROR_NOT_SUPPORTED_YET);
- }
+ gtd_init(p_gtd, buffer, total_bytes);
+ p_gtd->index = p_ed-ohci_data.ed_pool;
- return TUSB_ERROR_NONE;
-}
+ if ( int_on_complete ) p_gtd->delay_interrupt = OHCI_INT_ON_COMPLETE_YES;
-tusb_error_t hcd_pipe_queue_xfer(pipe_handle_t pipe_hdl, uint8_t buffer[], uint16_t total_bytes)
-{
- return pipe_queue_xfer(pipe_hdl, buffer, total_bytes, false);
+ td_insert_to_ed(p_ed, p_gtd);
+
+ return true;
}
-tusb_error_t hcd_pipe_xfer(pipe_handle_t pipe_hdl, uint8_t buffer[], uint16_t total_bytes, bool int_on_complete)
+bool hcd_pipe_queue_xfer(uint8_t dev_addr, uint8_t ep_addr, uint8_t buffer[], uint16_t total_bytes)
{
- TU_ASSERT_ERR( pipe_queue_xfer(pipe_hdl, buffer, total_bytes, true) );
-
- tusb_xfer_type_t xfer_type = ed_get_xfer_type( ed_from_pipe_handle(pipe_hdl) );
-
- if (TUSB_XFER_BULK == xfer_type) OHCI_REG->command_status_bit.bulk_list_filled = 1;
-
- return TUSB_ERROR_NONE;
+ return pipe_queue_xfer(dev_addr, ep_addr, buffer, total_bytes, false);
}
-/// pipe_close should only be called as a part of unmount/safe-remove process
-// endpoints are tied to an address, which only reclaim after a long delay when enumerating
-// thus there is no need to make sure ED is not in HC's cahed as it will not for sure
-tusb_error_t hcd_pipe_close(pipe_handle_t pipe_hdl)
+bool hcd_pipe_xfer(uint8_t dev_addr, uint8_t ep_addr, uint8_t buffer[], uint16_t total_bytes, bool int_on_complete)
{
- ohci_ed_t * const p_ed = ed_from_pipe_handle(pipe_hdl);
+ (void) int_on_complete;
+ TU_ASSERT( pipe_queue_xfer(dev_addr, ep_addr, buffer, total_bytes, true) );
- ed_list_remove( p_ed_head[ ed_get_xfer_type(p_ed)], p_ed );
+ tusb_xfer_type_t xfer_type = ed_get_xfer_type( ed_from_addr(dev_addr, ep_addr) );
- return TUSB_ERROR_FAILED;
-}
+ if (TUSB_XFER_BULK == xfer_type) OHCI_REG->command_status_bit.bulk_list_filled = 1;
-bool hcd_pipe_is_busy(pipe_handle_t pipe_hdl)
-{
- ohci_ed_t const * const p_ed = ed_from_pipe_handle(pipe_hdl);
- return tu_align16(p_ed->td_head.address) != tu_align16(p_ed->td_tail.address);
+ return true;
}
-bool hcd_pipe_is_error(pipe_handle_t pipe_hdl)
+bool hcd_edpt_busy(uint8_t dev_addr, uint8_t ep_addr)
{
- ohci_ed_t const * const p_ed = ed_from_pipe_handle(pipe_hdl);
- return p_ed->td_head.halted;
+ ohci_ed_t const * const p_ed = ed_from_addr(dev_addr, ep_addr);
+ return tu_align16(p_ed->td_head.address) != tu_align16(p_ed->td_tail);
}
-bool hcd_pipe_is_stalled(pipe_handle_t pipe_hdl)
+bool hcd_edpt_stalled(uint8_t dev_addr, uint8_t ep_addr)
{
- ohci_ed_t const * const p_ed = ed_from_pipe_handle(pipe_hdl);
+ ohci_ed_t const * const p_ed = ed_from_addr(dev_addr, ep_addr);
return p_ed->td_head.halted && p_ed->is_stalled;
}
-uint8_t hcd_pipe_get_endpoint_addr(pipe_handle_t pipe_hdl)
+bool hcd_edpt_clear_stall(uint8_t dev_addr, uint8_t ep_addr)
{
- ohci_ed_t const * const p_ed = ed_from_pipe_handle(pipe_hdl);
- return p_ed->endpoint_number | (p_ed->direction == OHCI_PID_IN ? TUSB_DIR_IN_MASK : 0 );
-}
+ ohci_ed_t * const p_ed = ed_from_addr(dev_addr, ep_addr);
-tusb_error_t hcd_pipe_clear_stall(pipe_handle_t pipe_hdl)
-{
- ohci_ed_t * const p_ed = ed_from_pipe_handle(pipe_hdl);
+ p_ed->is_stalled = 0;
+ p_ed->td_tail &= 0x0Ful; // set tail pointer back to NULL
- p_ed->is_stalled = 0;
- p_ed->td_tail.address &= 0x0Ful; // set tail pointer back to NULL
-
- p_ed->td_head.toggle = 0; // reset data toggle
- p_ed->td_head.halted = 0;
+ p_ed->td_head.toggle = 0; // reset data toggle
+ p_ed->td_head.halted = 0;
if ( TUSB_XFER_BULK == ed_get_xfer_type(p_ed) ) OHCI_REG->command_status_bit.bulk_list_filled = 1;
- return TUSB_ERROR_NONE;
+ return true;
}
@@ -566,10 +532,10 @@ static ohci_td_item_t* list_reverse(ohci_td_item_t* td_head)
while(td_head != NULL)
{
- uint32_t next = td_head->next_td;
+ uint32_t next = td_head->next;
// make current's item become reverse's first item
- td_head->next_td = (uint32_t) td_reverse_head;
+ td_head->next = (uint32_t) td_reverse_head;
td_reverse_head = td_head;
td_head = (ohci_td_item_t*) next; // advance to next item
@@ -578,13 +544,11 @@ static ohci_td_item_t* list_reverse(ohci_td_item_t* td_head)
return td_reverse_head;
}
-static inline bool gtd_is_control(ohci_gtd_t const * const p_qtd) ATTR_CONST ATTR_ALWAYS_INLINE;
static inline bool gtd_is_control(ohci_gtd_t const * const p_qtd)
{
- return ((uint32_t) p_qtd) < ((uint32_t) ohci_data.device); // check ohci_data_t for memory layout
+ return ((uint32_t) p_qtd) < ((uint32_t) ohci_data.gtd_pool); // check ohci_data_t for memory layout
}
-static inline ohci_ed_t* gtd_get_ed(ohci_gtd_t const * const p_qtd) ATTR_PURE ATTR_ALWAYS_INLINE;
static inline ohci_ed_t* gtd_get_ed(ohci_gtd_t const * const p_qtd)
{
if ( gtd_is_control(p_qtd) )
@@ -592,13 +556,10 @@ static inline ohci_ed_t* gtd_get_ed(ohci_gtd_t const * const p_qtd)
return &ohci_data.control[p_qtd->index].ed;
}else
{
- uint8_t dev_addr_idx = (((uint32_t)p_qtd) - ((uint32_t)ohci_data.device)) / sizeof(ohci_data.device[0]);
-
- return &ohci_data.device[dev_addr_idx].ed[p_qtd->index];
+ return &ohci_data.ed_pool[p_qtd->index];
}
}
-static inline uint32_t gtd_xfer_byte_left(uint32_t buffer_end, uint32_t current_buffer) ATTR_CONST ATTR_ALWAYS_INLINE;
static inline uint32_t gtd_xfer_byte_left(uint32_t buffer_end, uint32_t current_buffer)
{ // 5.2.9 OHCI sample code
return (tu_align4k(buffer_end ^ current_buffer) ? 0x1000 : 0) +
@@ -607,18 +568,18 @@ static inline uint32_t gtd_xfer_byte_left(uint32_t buffer_end, uint32_t current_
static void done_queue_isr(uint8_t hostid)
{
- uint8_t max_loop = (CFG_TUSB_HOST_DEVICE_MAX+1)*(HCD_MAX_XFER+OHCI_MAX_ITD);
+ (void) hostid;
// done head is written in reversed order of completion --> need to reverse the done queue first
ohci_td_item_t* td_head = list_reverse ( (ohci_td_item_t*) tu_align16(ohci_data.hcca.done_head) );
- while( td_head != NULL && max_loop > 0)
+ while( td_head != NULL )
{
// TODO check if td_head is iso td
//------------- Non ISO transfer -------------//
ohci_gtd_t * const p_qtd = (ohci_gtd_t *) td_head;
xfer_result_t const event = (p_qtd->condition_code == OHCI_CCODE_NO_ERROR) ? XFER_RESULT_SUCCESS :
- (p_qtd->condition_code == OHCI_CCODE_STALL) ? XFER_RESULT_STALLED : XFER_RESULT_FAILED;
+ (p_qtd->condition_code == OHCI_CCODE_STALL) ? XFER_RESULT_STALLED : XFER_RESULT_FAILED;
p_qtd->used = 0; // free TD
if ( (p_qtd->delay_interrupt == OHCI_INT_ON_COMPLETE_YES) || (event != XFER_RESULT_SUCCESS) )
@@ -636,24 +597,17 @@ static void done_queue_isr(uint8_t hostid)
// the TailP must be set back to NULL for processing remaining TDs
if ((event != XFER_RESULT_SUCCESS))
{
- p_ed->td_tail.address &= 0x0Ful;
- p_ed->td_tail.address |= tu_align16(p_ed->td_head.address); // mark halted EP as empty queue
+ p_ed->td_tail &= 0x0Ful;
+ p_ed->td_tail |= tu_align16(p_ed->td_head.address); // mark halted EP as empty queue
if ( event == XFER_RESULT_STALLED ) p_ed->is_stalled = 1;
}
- pipe_handle_t pipe_hdl =
- {
- .dev_addr = p_ed->device_address,
- .xfer_type = ed_get_xfer_type(p_ed),
- };
-
- if ( pipe_hdl.xfer_type != TUSB_XFER_CONTROL) pipe_hdl.index = ed_get_index(p_ed);
-
- usbh_xfer_isr(pipe_hdl, p_ed->td_tail.class_code, event, xferred_bytes);
+ hcd_event_xfer_complete(p_ed->dev_addr,
+ tu_edpt_addr(p_ed->ep_number, p_ed->pid == OHCI_PID_IN),
+ event, xferred_bytes);
}
- td_head = (ohci_td_item_t*) td_head->next_td;
- max_loop--;
+ td_head = (ohci_td_item_t*) td_head->next;
}
}
@@ -677,10 +631,10 @@ void hal_hcd_isr(uint8_t hostid)
{
// TODO reset port immediately, without this controller will got 2-3 (debouncing connection status change)
OHCI_REG->rhport_status[0] = OHCI_RHPORT_PORT_RESET_STATUS_MASK;
- usbh_hcd_rhport_plugged_isr(0);
+ hcd_event_device_attach(0);
}else
{
- usbh_hcd_rhport_unplugged_isr(0);
+ hcd_event_device_remove(0);
}
}