add ep addr to host cdc

This commit is contained in:
hathach 2018-12-10 19:01:28 +07:00
parent 0ae8a1aa89
commit 9c4c797502
No known key found for this signature in database
GPG Key ID: 2FA891220FBFD581
8 changed files with 104 additions and 171 deletions

View File

@ -41,9 +41,7 @@
#if (TUSB_OPT_DEVICE_ENABLED && CFG_TUD_CDC)
#define _TINY_USB_SOURCE_FILE_
//--------------------------------------------------------------------+
// INCLUDE
//--------------------------------------------------------------------+
#include "cdc_device.h"
#include "device/usbd_pvt.h"
@ -236,8 +234,7 @@ tusb_error_t cdcd_open(uint8_t rhport, tusb_desc_interface_t const * p_interface
if ( CDC_COMM_SUBCLASS_ABSTRACT_CONTROL_MODEL != p_interface_desc->bInterfaceSubClass) return TUSB_ERROR_CDC_UNSUPPORTED_SUBCLASS;
// Only support AT commands, no protocol and vendor specific commands.
if ( !(tu_within(CDC_COMM_PROTOCOL_ATCOMMAND, p_interface_desc->bInterfaceProtocol, CDC_COMM_PROTOCOL_ATCOMMAND_CDMA) ||
p_interface_desc->bInterfaceProtocol == CDC_COMM_PROTOCOL_NONE ||
if ( !(tu_within(CDC_COMM_PROTOCOL_NONE, p_interface_desc->bInterfaceProtocol, CDC_COMM_PROTOCOL_ATCOMMAND_CDMA) ||
p_interface_desc->bInterfaceProtocol == 0xff ) )
{
return TUSB_ERROR_CDC_UNSUPPORTED_PROTOCOL;

View File

@ -42,24 +42,35 @@
#define _TINY_USB_SOURCE_FILE_
//--------------------------------------------------------------------+
// INCLUDE
//--------------------------------------------------------------------+
#include "common/tusb_common.h"
#include "cdc_host.h"
//--------------------------------------------------------------------+
// MACRO CONSTANT TYPEDEF
//--------------------------------------------------------------------+
typedef struct {
uint8_t itf_num;
uint8_t itf_protocol;
cdc_acm_capability_t acm_capability;
pipe_handle_t pipe_notification, pipe_out, pipe_in;
uint8_t ep_notif;
uint8_t ep_in;
uint8_t ep_out;
} cdch_data_t;
//--------------------------------------------------------------------+
// INTERNAL OBJECT & FUNCTION DECLARATION
//--------------------------------------------------------------------+
static cdch_data_t cdch_data[CFG_TUSB_HOST_DEVICE_MAX]; // TODO to be static
static cdch_data_t cdch_data[CFG_TUSB_HOST_DEVICE_MAX];
static inline bool tuh_cdc_mounted(uint8_t dev_addr)
bool tuh_cdc_mounted(uint8_t dev_addr)
{
return pipehandle_is_valid(cdch_data[dev_addr-1].pipe_in) && pipehandle_is_valid(cdch_data[dev_addr-1].pipe_out);
cdch_data_t* cdc = &cdch_data[dev_addr-1];
return cdc->ep_in && cdc->ep_out;
}
bool tuh_cdc_is_busy(uint8_t dev_addr, cdc_pipeid_t pipeid)
@ -91,8 +102,8 @@ bool tuh_cdc_serial_is_mounted(uint8_t dev_addr)
{
// TODO consider all AT Command as serial candidate
return tuh_cdc_mounted(dev_addr) &&
(CDC_COMM_PROTOCOL_ATCOMMAND <= cdch_data[dev_addr-1].interface_protocol) &&
(cdch_data[dev_addr-1].interface_protocol <= CDC_COMM_PROTOCOL_ATCOMMAND_CDMA);
(CDC_COMM_PROTOCOL_ATCOMMAND <= cdch_data[dev_addr-1].itf_protocol) &&
(cdch_data[dev_addr-1].itf_protocol <= CDC_COMM_PROTOCOL_ATCOMMAND_CDMA);
}
tusb_error_t tuh_cdc_send(uint8_t dev_addr, void const * p_data, uint32_t length, bool is_notify)
@ -125,33 +136,33 @@ void cdch_init(void)
tu_memclr(cdch_data, sizeof(cdch_data_t)*CFG_TUSB_HOST_DEVICE_MAX);
}
bool cdch_open_subtask(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *p_interface_desc, uint16_t *p_length)
bool cdch_open_subtask(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *itf_desc, uint16_t *p_length)
{
// TODO change following assert to subtask_assert
if ( CDC_COMM_SUBCLASS_ABSTRACT_CONTROL_MODEL != p_interface_desc->bInterfaceSubClass) return TUSB_ERROR_CDC_UNSUPPORTED_SUBCLASS;
// Only support ACM
TU_VERIFY( CDC_COMM_SUBCLASS_ABSTRACT_CONTROL_MODEL == itf_desc->bInterfaceSubClass);
if ( !(tu_within(CDC_COMM_PROTOCOL_ATCOMMAND, p_interface_desc->bInterfaceProtocol, CDC_COMM_PROTOCOL_ATCOMMAND_CDMA) ||
0xff == p_interface_desc->bInterfaceProtocol) )
{
return TUSB_ERROR_CDC_UNSUPPORTED_PROTOCOL;
}
// Only support AT commands, no protocol and vendor specific commands.
TU_VERIFY(tu_within(CDC_COMM_PROTOCOL_NONE, itf_desc->bInterfaceProtocol, CDC_COMM_PROTOCOL_ATCOMMAND_CDMA) ||
0xff == itf_desc->bInterfaceProtocol);
uint8_t const * p_desc;
cdch_data_t * p_cdc;
p_desc = descriptor_next ( (uint8_t const *) p_interface_desc );
p_cdc = &cdch_data[dev_addr-1]; // non-static variable cannot be used after OS service call
p_desc = descriptor_next ( (uint8_t const *) itf_desc );
p_cdc = &cdch_data[dev_addr-1];
p_cdc->interface_number = p_interface_desc->bInterfaceNumber;
p_cdc->interface_protocol = p_interface_desc->bInterfaceProtocol; // TODO 0xff is consider as rndis candidate, other is virtual Com
p_cdc->itf_num = itf_desc->bInterfaceNumber;
p_cdc->itf_protocol = itf_desc->bInterfaceProtocol; // TODO 0xff is consider as rndis candidate, other is virtual Com
//------------- Communication Interface -------------//
(*p_length) = sizeof(tusb_desc_interface_t);
// Communication Functional Descriptors
while( TUSB_DESC_CLASS_SPECIFIC == p_desc[DESC_OFFSET_TYPE] )
{ // Communication Functional Descriptors
{
if ( CDC_FUNC_DESC_ABSTRACT_CONTROL_MANAGEMENT == cdc_functional_desc_typeof(p_desc) )
{ // save ACM bmCapabilities
{
// save ACM bmCapabilities
p_cdc->acm_capability = ((cdc_desc_func_acm_t const *) p_desc)->bmCapabilities;
}
@ -160,8 +171,12 @@ bool cdch_open_subtask(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t c
}
if ( TUSB_DESC_ENDPOINT == p_desc[DESC_OFFSET_TYPE])
{ // notification endpoint if any
p_cdc->pipe_notification = hcd_pipe_open(rhport, dev_addr, (tusb_desc_endpoint_t const *) p_desc, TUSB_CLASS_CDC);
{
// notification endpoint if any
tusb_desc_endpoint_t const * ep_desc = (tusb_desc_endpoint_t const *) p_desc;
p_cdc->pipe_notification = hcd_pipe_open(rhport, dev_addr, ep_desc, TUSB_CLASS_CDC);
p_cdc->ep_notif = ep_desc->bEndpointAddress;
(*p_length) += p_desc[DESC_OFFSET_LEN];
p_desc = descriptor_next(p_desc);
@ -179,16 +194,24 @@ bool cdch_open_subtask(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t c
// data endpoints expected to be in pairs
for(uint32_t i=0; i<2; i++)
{
tusb_desc_endpoint_t const *p_endpoint = (tusb_desc_endpoint_t const *) p_desc;
TU_ASSERT(TUSB_DESC_ENDPOINT == p_endpoint->bDescriptorType);
TU_ASSERT(TUSB_XFER_BULK == p_endpoint->bmAttributes.xfer);
tusb_desc_endpoint_t const *ep_desc = (tusb_desc_endpoint_t const *) p_desc;
TU_ASSERT(TUSB_DESC_ENDPOINT == ep_desc->bDescriptorType);
TU_ASSERT(TUSB_XFER_BULK == ep_desc->bmAttributes.xfer);
pipe_handle_t * p_pipe_hdl = ( p_endpoint->bEndpointAddress & TUSB_DIR_IN_MASK ) ?
pipe_handle_t * p_pipe_hdl = ( ep_desc->bEndpointAddress & TUSB_DIR_IN_MASK ) ?
&p_cdc->pipe_in : &p_cdc->pipe_out;
(*p_pipe_hdl) = hcd_pipe_open(rhport, dev_addr, p_endpoint, TUSB_CLASS_CDC);
(*p_pipe_hdl) = hcd_pipe_open(rhport, dev_addr, ep_desc, TUSB_CLASS_CDC);
TU_ASSERT ( pipehandle_is_valid(*p_pipe_hdl) );
if ( edpt_dir(ep_desc->bEndpointAddress) == TUSB_DIR_IN )
{
p_cdc->ep_in = ep_desc->bEndpointAddress;
}else
{
p_cdc->ep_out = ep_desc->bEndpointAddress;
}
(*p_length) += p_desc[DESC_OFFSET_LEN];
p_desc = descriptor_next( p_desc );
}
@ -203,7 +226,7 @@ bool cdch_open_subtask(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t c
.bmRequestType_bit = { .recipient = TUSB_REQ_RCPT_INTERFACE, .type = TUSB_REQ_TYPE_CLASS, .direction = TUSB_DIR_OUT },
.bRequest = CDC_REQUEST_SET_CONTROL_LINE_STATE,
.wValue = 0x03, // dtr on, cst on
.wIndex = p_cdc->interface_number,
.wIndex = p_cdc->itf_num,
.wLength = 0
};

View File

@ -137,18 +137,8 @@ void tuh_cdc_xfer_isr(uint8_t dev_addr, xfer_result_t event, cdc_pipeid_t pipe_i
//--------------------------------------------------------------------+
#ifdef _TINY_USB_SOURCE_FILE_
typedef struct {
uint8_t interface_number;
uint8_t interface_protocol;
cdc_acm_capability_t acm_capability;
pipe_handle_t pipe_notification, pipe_out, pipe_in;
} cdch_data_t;
void cdch_init(void);
bool cdch_open_subtask(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *p_interface_desc, uint16_t *p_length) ATTR_WARN_UNUSED_RESULT;
bool cdch_open_subtask(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *p_interface_desc, uint16_t *p_length);
void cdch_isr(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes);
void cdch_close(uint8_t dev_addr);

View File

@ -73,6 +73,8 @@
// MACROS
//--------------------------------------------------------------------+
#define TU_ARRAY_SZIE(_arr) ( sizeof(_arr) / sizeof(_arr[0]) )
#define TU_MIN(_x, _y) ( (_x) < (_y) ) ? (_x) : (_y) )
#define TU_MAX(_x, _y) ( (_x) > (_y) ) ? (_x) : (_y) )
#define U16_HIGH_U8(u16) ((uint8_t) (((u16) >> 8) & 0x00ff))
#define U16_LOW_U8(u16) ((uint8_t) ((u16) & 0x00ff))
@ -167,53 +169,23 @@ static inline uint16_t tu_u16_le2be(uint16_t u16)
return ((uint16_t)(tu_u16_low(u16) << 8)) | tu_u16_high(u16);
}
//------------- Min -------------//
static inline uint8_t tu_min8(uint8_t x, uint8_t y)
{
return (x < y) ? x : y;
}
// Min
static inline uint8_t tu_min8(uint8_t x, uint8_t y) { return (x < y) ? x : y; }
static inline uint16_t tu_min16(uint16_t x, uint16_t y) { return (x < y) ? x : y; }
static inline uint32_t tu_min32(uint32_t x, uint32_t y) { return (x < y) ? x : y; }
static inline uint16_t tu_min16(uint16_t x, uint16_t y)
{
return (x < y) ? x : y;
}
// Max
static inline uint8_t tu_max8(uint8_t x, uint8_t y) { return (x > y) ? x : y; }
static inline uint16_t tu_max16(uint16_t x, uint16_t y) { return (x > y) ? x : y; }
static inline uint32_t tu_max32(uint32_t x, uint32_t y) { return (x > y) ? x : y; }
static inline uint32_t tu_min32(uint32_t x, uint32_t y)
{
return (x < y) ? x : y;
}
// Align
static inline uint32_t tu_align32 (uint32_t value) { return (value & 0xFFFFFFE0UL); }
static inline uint32_t tu_align16 (uint32_t value) { return (value & 0xFFFFFFF0UL); }
static inline uint32_t tu_align_n (uint32_t alignment, uint32_t value) { return value & ((uint32_t) ~(alignment-1)); }
static inline uint32_t tu_align4k (uint32_t value) { return (value & 0xFFFFF000UL); }
//------------- Max -------------//
static inline uint32_t tu_max32(uint32_t x, uint32_t y)
{
return (x > y) ? x : y;
}
//------------- Align -------------//
static inline uint32_t tu_align32 (uint32_t value)
{
return (value & 0xFFFFFFE0UL);
}
static inline uint32_t tu_align16 (uint32_t value)
{
return (value & 0xFFFFFFF0UL);
}
static inline uint32_t tu_align_n (uint32_t alignment, uint32_t value)
{
return value & ((uint32_t) ~(alignment-1));
}
static inline uint32_t tu_align4k (uint32_t value)
{
return (value & 0xFFFFF000UL);
}
static inline uint32_t tu_offset4k(uint32_t value)
{
return (value & 0xFFFUL);
}
static inline uint32_t tu_offset4k(uint32_t value) { return (value & 0xFFFUL); }
//------------- Mathematics -------------//
static inline uint32_t tu_abs(int32_t value)
@ -221,7 +193,6 @@ static inline uint32_t tu_abs(int32_t value)
return (value < 0) ? (-value) : value;
}
/// inclusive range checking
static inline bool tu_within(uint32_t lower, uint32_t value, uint32_t upper)
{

View File

@ -623,24 +623,24 @@ void dcd_event_xfer_complete (uint8_t rhport, uint8_t ep_addr, uint32_t xferred_
//--------------------------------------------------------------------+
// Helper to parse an pair of endpoint descriptors (IN & OUT)
tusb_error_t usbd_open_edpt_pair(uint8_t rhport, tusb_desc_endpoint_t const* p_desc_ep, uint8_t xfer_type, uint8_t* ep_out, uint8_t* ep_in)
tusb_error_t usbd_open_edpt_pair(uint8_t rhport, tusb_desc_endpoint_t const* ep_desc, uint8_t xfer_type, uint8_t* ep_out, uint8_t* ep_in)
{
for(int i=0; i<2; i++)
{
TU_ASSERT(TUSB_DESC_ENDPOINT == p_desc_ep->bDescriptorType &&
xfer_type == p_desc_ep->bmAttributes.xfer, TUSB_ERROR_DESCRIPTOR_CORRUPTED);
TU_ASSERT(TUSB_DESC_ENDPOINT == ep_desc->bDescriptorType &&
xfer_type == ep_desc->bmAttributes.xfer, TUSB_ERROR_DESCRIPTOR_CORRUPTED);
TU_ASSERT( dcd_edpt_open(rhport, p_desc_ep), TUSB_ERROR_DCD_OPEN_PIPE_FAILED );
TU_ASSERT( dcd_edpt_open(rhport, ep_desc), TUSB_ERROR_DCD_OPEN_PIPE_FAILED );
if ( edpt_dir(p_desc_ep->bEndpointAddress) == TUSB_DIR_IN )
if ( edpt_dir(ep_desc->bEndpointAddress) == TUSB_DIR_IN )
{
(*ep_in) = p_desc_ep->bEndpointAddress;
(*ep_in) = ep_desc->bEndpointAddress;
}else
{
(*ep_out) = p_desc_ep->bEndpointAddress;
(*ep_out) = ep_desc->bEndpointAddress;
}
p_desc_ep = (tusb_desc_endpoint_t const *) descriptor_next( (uint8_t const*) p_desc_ep );
ep_desc = (tusb_desc_endpoint_t const *) descriptor_next( (uint8_t const*) ep_desc );
}
return TUSB_ERROR_NONE;

View File

@ -58,26 +58,8 @@
//--------------------------------------------------------------------+
// INTERNAL OBJECT & FUNCTION DECLARATION
//--------------------------------------------------------------------+
CFG_TUSB_MEM_SECTION static ehci_data_t ehci_data;
#if EHCI_PERIODIC_LIST
#if (CFG_TUSB_RHPORT0_MODE & OPT_MODE_HOST)
CFG_TUSB_MEM_SECTION ATTR_ALIGNED(4096) static ehci_link_t period_frame_list0[EHCI_FRAMELIST_SIZE];
#ifndef __ICCARM__ // IAR cannot able to determine the alignment with datalignment pragma
TU_VERIFY_STATIC( ALIGN_OF(period_frame_list0) == 4096, "Period Framelist must be 4k alginment"); // validation
#endif
#endif
#if (CFG_TUSB_RHPORT1_MODE & OPT_MODE_HOST)
CFG_TUSB_MEM_SECTION ATTR_ALIGNED(4096) STATIC_VAR ehci_link_t period_frame_list1[EHCI_FRAMELIST_SIZE];
#ifndef __ICCARM__ // IAR cannot able to determine the alignment with datalignment pragma
TU_VERIFY_STATIC( ALIGN_OF(period_frame_list1) == 4096, "Period Framelist must be 4k alginment"); // validation
#endif
#endif
#endif
// Periodic frame list must be 4K alignment
CFG_TUSB_MEM_SECTION ATTR_ALIGNED(4096) static ehci_data_t ehci_data;
//------------- Validation -------------//
// TODO static assert for memory placement on some known MCU such as lpc43xx
@ -86,7 +68,6 @@ CFG_TUSB_MEM_SECTION static ehci_data_t ehci_data;
// PROTOTYPE
//--------------------------------------------------------------------+
static inline ehci_registers_t* get_operational_register(uint8_t hostid) ATTR_PURE ATTR_ALWAYS_INLINE ATTR_WARN_UNUSED_RESULT;
static inline ehci_link_t* get_period_frame_list(uint8_t hostid) ATTR_PURE ATTR_ALWAYS_INLINE ATTR_WARN_UNUSED_RESULT;
static inline ehci_qhd_t* get_async_head(uint8_t hostid) ATTR_ALWAYS_INLINE ATTR_PURE ATTR_WARN_UNUSED_RESULT;
static inline ehci_link_t* get_period_head(uint8_t hostid, uint8_t interval_ms) ATTR_ALWAYS_INLINE ATTR_PURE ATTR_WARN_UNUSED_RESULT;
@ -112,9 +93,9 @@ static void qhd_init(ehci_qhd_t *p_qhd, uint8_t dev_addr, tusb_desc_endpoint_t c
static inline ehci_qtd_t* qtd_find_free(uint8_t dev_addr) ATTR_PURE ATTR_ALWAYS_INLINE;
static inline ehci_qtd_t* qtd_next(ehci_qtd_t const * p_qtd ) ATTR_PURE ATTR_ALWAYS_INLINE;
static inline void qtd_insert_to_qhd(ehci_qhd_t *p_qhd, ehci_qtd_t *p_qtd_new) ATTR_ALWAYS_INLINE;
static inline void qtd_remove_1st_from_qhd(ehci_qhd_t *p_qhd) ATTR_ALWAYS_INLINE;
static inline ehci_qtd_t* qtd_next(ehci_qtd_t const * p_qtd ) ATTR_PURE ATTR_ALWAYS_INLINE;
static inline void qtd_insert_to_qhd(ehci_qhd_t *p_qhd, ehci_qtd_t *p_qtd_new) ATTR_ALWAYS_INLINE;
static inline void qtd_remove_1st_from_qhd(ehci_qhd_t *p_qhd) ATTR_ALWAYS_INLINE;
static void qtd_init(ehci_qtd_t* p_qtd, uint32_t data_ptr, uint16_t total_bytes);
static inline void list_insert(ehci_link_t *current, ehci_link_t *new, uint8_t new_type) ATTR_ALWAYS_INLINE;
@ -129,18 +110,8 @@ static bool ehci_init(uint8_t hostid);
//--------------------------------------------------------------------+
bool hcd_init(void)
{
//------------- Data Structure init -------------//
tu_memclr(&ehci_data, sizeof(ehci_data_t));
#if (CFG_TUSB_RHPORT0_MODE & OPT_MODE_HOST)
TU_VERIFY(ehci_init(0));
#endif
#if (CFG_TUSB_RHPORT1_MODE & OPT_MODE_HOST)
TU_VERIFY(ehci_init(1));
#endif
return true;
return ehci_init(TUH_OPT_RHPORT);
}
//--------------------------------------------------------------------+
@ -148,7 +119,7 @@ bool hcd_init(void)
//--------------------------------------------------------------------+
void hcd_port_reset(uint8_t hostid)
{
ehci_registers_t* const regs = get_operational_register(hostid);
ehci_registers_t* regs = ehci_data.regs;
regs->portsc_bit.port_enable = 0; // disable port before reset
regs->portsc_bit.port_reset = 1;
@ -156,19 +127,18 @@ void hcd_port_reset(uint8_t hostid)
bool hcd_port_connect_status(uint8_t hostid)
{
return get_operational_register(hostid)->portsc_bit.current_connect_status;
return ehci_data.regs->portsc_bit.current_connect_status;
}
tusb_speed_t hcd_port_speed_get(uint8_t hostid)
{
return (tusb_speed_t) get_operational_register(hostid)->portsc_bit.nxp_port_speed; // NXP specific port speed
return (tusb_speed_t) ehci_data.regs->portsc_bit.nxp_port_speed; // NXP specific port speed
}
// TODO refractor abtract later
void hcd_port_unplug(uint8_t hostid)
{
ehci_registers_t* const regs = get_operational_register(hostid);
regs->usb_cmd_bit.advacne_async = 1; // Async doorbell check EHCI 4.8.2 for operational details
ehci_data.regs->usb_cmd_bit.advance_async = 1; // Async doorbell check EHCI 4.8.2 for operational details
}
//--------------------------------------------------------------------+
@ -176,7 +146,9 @@ void hcd_port_unplug(uint8_t hostid)
//--------------------------------------------------------------------+
static bool ehci_init(uint8_t hostid)
{
ehci_registers_t* const regs = get_operational_register(hostid);
ehci_data.regs = get_operational_register(hostid);
ehci_registers_t* regs = ehci_data.regs;
//------------- CTRLDSSEGMENT Register (skip) -------------//
//------------- USB INT Register -------------//
@ -211,7 +183,7 @@ static bool ehci_init(uint8_t hostid)
ehci_data.period_head_arr[i].qtd_overlay.halted = 1; // dummy node, always inactive
}
ehci_link_t * const framelist = get_period_frame_list(hostid);
ehci_link_t * const framelist = ehci_data.period_framelist;
ehci_link_t * const period_1ms = get_period_head(hostid, 1);
// all links --> period_head_arr[0] (1ms)
// 0, 2, 4, 6 etc --> period_head_arr[1] (2ms)
@ -264,11 +236,11 @@ static bool ehci_init(uint8_t hostid)
static tusb_error_t hcd_controller_stop(uint8_t hostid)
{
ehci_registers_t* const regs = get_operational_register(hostid);
tu_timeout_t timeout;
ehci_registers_t* regs = ehci_data.regs;
regs->usb_cmd_bit.run_stop = 0;
tu_timeout_t timeout;
tu_timeout_set(&timeout, 2); // USB Spec: controller has to stop within 16 uframe = 2 frames
while( regs->usb_sts_bit.hc_halted == 0 && !tu_timeout_expired(&timeout)) {}
@ -613,10 +585,8 @@ static void async_advance_isr(ehci_qhd_t * const async_head)
static void port_connect_status_change_isr(uint8_t hostid)
{
ehci_registers_t* const regs = get_operational_register(hostid);
// NOTE There is an sequence plug->unplug->…..-> plug if device is powering with pre-plugged device
if (regs->portsc_bit.current_connect_status)
if (ehci_data.regs->portsc_bit.current_connect_status)
{
hcd_port_reset(hostid);
hcd_event_device_attach(hostid);
@ -797,7 +767,7 @@ static void xfer_error_isr(uint8_t hostid)
//------------- Host Controller Driver's Interrupt Handler -------------//
void hal_hcd_isr(uint8_t hostid)
{
ehci_registers_t* const regs = get_operational_register(hostid);
ehci_registers_t* regs = ehci_data.regs;
uint32_t int_status = regs->usb_sts;
int_status &= regs->usb_int_enable;
@ -854,26 +824,6 @@ static inline ehci_registers_t* get_operational_register(uint8_t hostid)
return (ehci_registers_t*) (hostid ? (&LPC_USB1->USBCMD_H) : (&LPC_USB0->USBCMD_H) );
}
#if EHCI_PERIODIC_LIST // TODO refractor/group this together
static inline ehci_link_t* get_period_frame_list(uint8_t hostid)
{
switch(hostid)
{
#if (CFG_TUSB_RHPORT0_MODE & OPT_MODE_HOST)
case 0:
return period_frame_list0;
#endif
#if (CFG_TUSB_RHPORT1_MODE & OPT_MODE_HOST)
case 1:
return period_frame_list1;
#endif
default: return NULL;
}
}
#endif
//------------- queue head helper -------------//
static inline ehci_qhd_t* get_async_head(uint8_t hostid)
{

View File

@ -352,7 +352,7 @@ typedef volatile struct {
uint32_t framelist_size : 2 ; ///< This field is R/W only if Programmable Frame List Flagin the HCCPARAMS registers is set to a one. This field specifies the size of the frame list.00b 1024 elements (4096 bytes) Default value 01b 512 elements (2048 bytes) 10b 256 elements (1024 bytes)
uint32_t periodic_enable : 1 ; ///< This bit controls whether the host controller skips processing the Periodic Schedule. Values mean: 0b Do not process the Periodic Schedule 1b Use the PERIODICLISTBASE register to access the Periodic Schedule.
uint32_t async_enable : 1 ; ///< This bit controls whether the host controller skips processing the Asynchronous Schedule. Values mean: 0b Do not process the Asynchronous Schedule 1b Use the ASYNCLISTADDR register to access the Asynchronous Schedule.
uint32_t advacne_async : 1 ; ///< This bit is used as a doorbell by software to tell the host controller to issue an interrupt the next time it advances asynchronous schedule. Software must write a 1 to this bit to ringthe doorbell. When the host controller has evicted all appropriate cached schedule state, it sets the Interrupt on Async Advancestatus bit in the USBSTS register. If the Interrupt on Async Advance Enablebit in the USBINTR register is a one then the host controller will assert an interrupt at the next interrupt threshold. See Section 4.8.2 for operational details. The host controller sets this bit to a zero after it has set the Interrupt on Async Advance status bit in the USBSTS register to a one. Software should not write a one to this bit when the asynchronous schedule is disabled. Doing so will yield undefined results.
uint32_t advance_async : 1 ; ///< This bit is used as a doorbell by software to tell the host controller to issue an interrupt the next time it advances asynchronous schedule. Software must write a 1 to this bit to ringthe doorbell. When the host controller has evicted all appropriate cached schedule state, it sets the Interrupt on Async Advancestatus bit in the USBSTS register. If the Interrupt on Async Advance Enablebit in the USBINTR register is a one then the host controller will assert an interrupt at the next interrupt threshold. See Section 4.8.2 for operational details. The host controller sets this bit to a zero after it has set the Interrupt on Async Advance status bit in the USBSTS register to a one. Software should not write a one to this bit when the asynchronous schedule is disabled. Doing so will yield undefined results.
uint32_t light_reset : 1 ; ///< This control bit is not required. If implemented, it allows the driver to reset the EHCI controller without affecting the state of the ports or the relationship to the companion host controllers. For example, the PORSTC registers should not be reset to their default values and the CF bit setting should not go to zero (retaining port ownership relationships). A host software read of this bit as zero indicates the Light Host Controller Reset has completed and it is safe for host software to re-initialize the host controller. A host software read of this bit as a one indicates the Light Host Controller Reset has not yet completed.
uint32_t async_park : 2 ; ///< It contains a count of the number of successive transactions the host controller is allowed to execute from a high-speed queue head on the Asynchronous schedule before continuing traversal of the Asynchronous schedule. See Section 4.10.3.2 for full operational details. Valid values are 1h to 3h. Software must not write a zero to this bit when Park Mode Enableis a one as this will result in undefined behavior.
uint32_t : 1 ; ///< reserved
@ -450,11 +450,11 @@ typedef volatile struct {
//--------------------------------------------------------------------+
typedef struct
{
#if EHCI_PERIODIC_LIST
ehci_link_t period_framelist[EHCI_FRAMELIST_SIZE];
// for NXP ECHI, only implement 1 ms & 2 ms & 4 ms, 8 ms (framelist)
// [0] : 1ms, [1] : 2ms, [2] : 4ms, [3] : 8 ms
ehci_qhd_t period_head_arr[4];
#endif
struct {
ehci_qhd_t qhd; // also used as head of async list (each for 1 controller), always exists
@ -472,6 +472,8 @@ typedef struct
// ehci_itd_t itd[EHCI_MAX_ITD] ; ///< Iso Transfer Pool
// ehci_sitd_t sitd[EHCI_MAX_SITD] ; ///< Split (FS) Isochronous Transfer Pool
}device[CFG_TUSB_HOST_DEVICE_MAX];
ehci_registers_t* regs;
}ehci_data_t;
#ifdef __cplusplus

View File

@ -225,7 +225,7 @@ void test_register_usbcmd(void)
TEST_ASSERT_EQUAL( 2 , BITFIELD_OFFSET_OF_MEMBER(ehci_registers_t, usb_cmd_bit, framelist_size) );
TEST_ASSERT_EQUAL( 4 , BITFIELD_OFFSET_OF_MEMBER(ehci_registers_t, usb_cmd_bit, periodic_enable) );
TEST_ASSERT_EQUAL( 5 , BITFIELD_OFFSET_OF_MEMBER(ehci_registers_t, usb_cmd_bit, async_enable) );
TEST_ASSERT_EQUAL( 6 , BITFIELD_OFFSET_OF_MEMBER(ehci_registers_t, usb_cmd_bit, advacne_async) );
TEST_ASSERT_EQUAL( 6 , BITFIELD_OFFSET_OF_MEMBER(ehci_registers_t, usb_cmd_bit, advance_async) );
TEST_ASSERT_EQUAL( 7 , BITFIELD_OFFSET_OF_MEMBER(ehci_registers_t, usb_cmd_bit, light_reset) );
TEST_ASSERT_EQUAL( 8 , BITFIELD_OFFSET_OF_MEMBER(ehci_registers_t, usb_cmd_bit, async_park) );
TEST_ASSERT_EQUAL( 11 , BITFIELD_OFFSET_OF_MEMBER(ehci_registers_t, usb_cmd_bit, async_park_enable) );