mirror of
https://github.com/hathach/tinyusb.git
synced 2025-03-28 05:37:15 +00:00
add cdc host driver close cdch_close
refractor - add helper function in ehci qhd_next & qtd_next - extract function qhd_create_pipe_handle rename tusb_transfer_type_t to tusb_xfer_type_t add some handling for stall
This commit is contained in:
parent
d8bd749c75
commit
3f9f3f08d2
@ -32,7 +32,10 @@
|
||||
<tool id="cdt.managedbuild.tool.gnu.archiver.mingw.base.1485867060" name="GCC Archiver" superClass="cdt.managedbuild.tool.gnu.archiver.mingw.base"/>
|
||||
<tool id="cdt.managedbuild.tool.gnu.cpp.compiler.mingw.base.694786126" name="GCC C++ Compiler" superClass="cdt.managedbuild.tool.gnu.cpp.compiler.mingw.base"/>
|
||||
<tool errorParsers="org.eclipse.cdt.core.GCCErrorParser" id="cdt.managedbuild.tool.gnu.c.compiler.mingw.base.1588045403" name="GCC C Compiler" superClass="cdt.managedbuild.tool.gnu.c.compiler.mingw.base">
|
||||
<option id="gnu.c.compiler.option.preprocessor.def.symbols.1484610767" name="Defined symbols (-D)" superClass="gnu.c.compiler.option.preprocessor.def.symbols"/>
|
||||
<option id="gnu.c.compiler.option.preprocessor.def.symbols.1484610767" name="Defined symbols (-D)" superClass="gnu.c.compiler.option.preprocessor.def.symbols" valueType="definedSymbols">
|
||||
<listOptionValue builtIn="false" value="MCU=MCU_LPC43XX"/>
|
||||
</option>
|
||||
<option id="gnu.c.compiler.option.preprocessor.undef.symbol.1508960620" superClass="gnu.c.compiler.option.preprocessor.undef.symbol" valueType="undefDefinedSymbols"/>
|
||||
<inputType id="cdt.managedbuild.tool.gnu.c.compiler.input.451457393" superClass="cdt.managedbuild.tool.gnu.c.compiler.input"/>
|
||||
</tool>
|
||||
<tool errorParsers="org.eclipse.cdt.core.GLDErrorParser" id="cdt.managedbuild.tool.gnu.c.linker.mingw.base.1896871485" name="MinGW C Linker" superClass="cdt.managedbuild.tool.gnu.c.linker.mingw.base">
|
||||
|
@ -142,7 +142,30 @@ void cdch_isr(pipe_handle_t pipe_hdl, tusb_event_t event)
|
||||
|
||||
void cdch_close(uint8_t dev_addr)
|
||||
{
|
||||
tusb_error_t err1, err2, err3;
|
||||
cdch_data_t * p_cdc = &cdch_data[dev_addr-1];
|
||||
|
||||
|
||||
if ( pipehandle_is_valid(p_cdc->pipe_notification) )
|
||||
{
|
||||
err1 = hcd_pipe_close(p_cdc->pipe_notification);
|
||||
}
|
||||
|
||||
if ( pipehandle_is_valid(p_cdc->pipe_in) )
|
||||
{
|
||||
err2 = hcd_pipe_close(p_cdc->pipe_in);
|
||||
}
|
||||
|
||||
if ( pipehandle_is_valid(p_cdc->pipe_out) )
|
||||
{
|
||||
err3 = hcd_pipe_close(p_cdc->pipe_out);
|
||||
}
|
||||
|
||||
memclr_(p_cdc, sizeof(cdch_data_t));
|
||||
|
||||
ASSERT(err1 == TUSB_ERROR_NONE &&
|
||||
err2 == TUSB_ERROR_NONE &&
|
||||
err3 == TUSB_ERROR_NONE, (void) 0 );
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -67,7 +67,7 @@ typedef enum {
|
||||
TUSB_XFER_ISOCHRONOUS ,
|
||||
TUSB_XFER_BULK ,
|
||||
TUSB_XFER_INTERRUPT
|
||||
}tusb_transfer_type_t;
|
||||
}tusb_xfer_type_t;
|
||||
|
||||
typedef enum {
|
||||
TUSB_DIR_HOST_TO_DEV = 0,
|
||||
@ -198,6 +198,8 @@ typedef enum tusb_device_state_{
|
||||
typedef enum {
|
||||
TUSB_EVENT_XFER_COMPLETE,
|
||||
TUSB_EVENT_XFER_ERROR,
|
||||
TUSB_EVENT_XFER_STALLED,
|
||||
|
||||
TUSB_EVENT_INTERFACE_OPEN,
|
||||
TUSB_EVENT_INTERFACE_CLOSE,
|
||||
|
||||
|
@ -88,12 +88,17 @@ STATIC_ INLINE_ ehci_link_t* get_period_head(uint8_t hostid, uint8_t interval_ms
|
||||
STATIC_ INLINE_ ehci_qhd_t* get_control_qhd(uint8_t dev_addr) ATTR_ALWAYS_INLINE ATTR_PURE ATTR_WARN_UNUSED_RESULT;
|
||||
STATIC_ INLINE_ ehci_qtd_t* get_control_qtds(uint8_t dev_addr) ATTR_ALWAYS_INLINE ATTR_PURE ATTR_WARN_UNUSED_RESULT;
|
||||
|
||||
static inline uint8_t qhd_get_index(ehci_qhd_t * p_qhd) ATTR_ALWAYS_INLINE ATTR_PURE;
|
||||
static inline uint8_t qhd_get_index(ehci_qhd_t const * p_qhd) ATTR_ALWAYS_INLINE ATTR_PURE;
|
||||
static inline ehci_qhd_t* qhd_next(ehci_qhd_t const * p_qhd) ATTR_ALWAYS_INLINE ATTR_PURE;
|
||||
static inline ehci_qhd_t* qhd_find_free (uint8_t dev_addr) ATTR_PURE ATTR_ALWAYS_INLINE;
|
||||
STATIC_ INLINE_ ehci_qhd_t* qhd_get_from_pipe_handle(pipe_handle_t pipe_hdl) ATTR_PURE ATTR_ALWAYS_INLINE;
|
||||
static inline pipe_handle_t qhd_create_pipe_handle(ehci_qhd_t const * p_qhd, tusb_xfer_type_t xfer_type) ATTR_PURE ATTR_ALWAYS_INLINE;
|
||||
|
||||
static void qhd_init(ehci_qhd_t *p_qhd, uint8_t dev_addr, uint16_t max_packet_size, uint8_t endpoint_addr, uint8_t xfer_type, uint8_t interval);
|
||||
|
||||
|
||||
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 void qtd_init(ehci_qtd_t* p_qtd, uint32_t data_ptr, uint16_t total_bytes);
|
||||
@ -424,7 +429,7 @@ tusb_error_t hcd_pipe_close(pipe_handle_t pipe_hdl)
|
||||
|
||||
// async list needs async advance handshake to make sure host controller has released cached data
|
||||
// period list queue element is guarantee to be free in the next frame (1 ms)
|
||||
p_qhd->is_removing = 1;
|
||||
p_qhd->is_removing = 1; // TODO redundant, only apply to control queue head
|
||||
|
||||
if ( pipe_hdl.xfer_type == TUSB_XFER_BULK )
|
||||
{
|
||||
@ -453,6 +458,9 @@ bool hcd_pipe_is_idle(pipe_handle_t pipe_hdl)
|
||||
//--------------------------------------------------------------------+
|
||||
// EHCI Interrupt Handler
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
// async_advance is handshake between sw stack & ehci controller where ehci free all memory from an deleted queue head.
|
||||
// In tinyusb, queue head is only removed when device is unplugged. So only control queue head is checked if removing
|
||||
void async_advance_isr(ehci_qhd_t * const async_head)
|
||||
{
|
||||
// TODO do we need to close addr0
|
||||
@ -506,7 +514,8 @@ void port_connect_status_change_isr(uint8_t hostid)
|
||||
}
|
||||
}
|
||||
|
||||
void qhd_xfer_complete_isr(ehci_qhd_t * p_qhd, tusb_transfer_type_t xfer_type)
|
||||
//void qtd_xfer_process_isr(ehci_qtd_t * p_qtd, )
|
||||
void qhd_xfer_complete_isr(ehci_qhd_t * p_qhd, tusb_xfer_type_t xfer_type)
|
||||
{
|
||||
// free all TDs from the head td to the first active TD
|
||||
while(p_qhd->p_qtd_list_head != NULL && !p_qhd->p_qtd_list_head->active)
|
||||
@ -520,16 +529,8 @@ void qhd_xfer_complete_isr(ehci_qhd_t * p_qhd, tusb_transfer_type_t xfer_type)
|
||||
|
||||
if (is_ioc) // end of request
|
||||
{
|
||||
pipe_handle_t pipe_hdl = {
|
||||
.dev_addr = p_qhd->device_address,
|
||||
.xfer_type = xfer_type
|
||||
};
|
||||
if (TUSB_XFER_CONTROL != xfer_type) // qhd index for control is meaningless
|
||||
{
|
||||
pipe_hdl.index = qhd_get_index(p_qhd);
|
||||
}
|
||||
|
||||
usbh_xfer_isr( pipe_hdl, p_qhd->class_code, TUSB_EVENT_XFER_COMPLETE); // call USBH callback
|
||||
usbh_xfer_isr( qhd_create_pipe_handle(p_qhd, xfer_type),
|
||||
p_qhd->class_code, TUSB_EVENT_XFER_COMPLETE); // call USBH callback
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -545,7 +546,7 @@ void async_list_xfer_complete_isr(ehci_qhd_t * const async_head)
|
||||
qhd_xfer_complete_isr(p_qhd,
|
||||
p_qhd->endpoint_number != 0 ? TUSB_XFER_BULK : TUSB_XFER_CONTROL);
|
||||
}
|
||||
p_qhd = (ehci_qhd_t*) align32(p_qhd->next.address);
|
||||
p_qhd = qhd_next(p_qhd);
|
||||
max_loop++;
|
||||
}while(p_qhd != async_head && max_loop < EHCI_MAX_QHD); // async list traversal, stop if loop around
|
||||
// TODO abstract max loop guard for async
|
||||
@ -591,15 +592,23 @@ void period_list_xfer_complete_isr(uint8_t hostid, uint8_t interval_ms)
|
||||
void xfer_error_isr(uint8_t hostid)
|
||||
{
|
||||
//------------- async list -------------//
|
||||
uint8_t max_loop = 0;
|
||||
ehci_qhd_t * const async_head = get_async_head(hostid);
|
||||
ehci_qhd_t *p_qhd = async_head;
|
||||
do
|
||||
{
|
||||
// current qhd has error in transaction
|
||||
if (p_qhd->qtd_overlay.buffer_err || p_qhd->qtd_overlay.babble_err || p_qhd->qtd_overlay.xact_err ||
|
||||
if ( (p_qhd->device_address != 0 && p_qhd->qtd_overlay.halted) || // addr0 cannot be protocol STALL
|
||||
p_qhd->qtd_overlay.buffer_err ||p_qhd->qtd_overlay.babble_err || p_qhd->qtd_overlay.xact_err
|
||||
//p_qhd->qtd_overlay.non_hs_period_missed_uframe || p_qhd->qtd_overlay.pingstate_err TODO split transaction error
|
||||
(p_qhd->device_address != 0 && p_qhd->qtd_overlay.halted) ) // addr0 cannot be protocol STALL
|
||||
)
|
||||
{
|
||||
|
||||
if ( !p_qhd->qtd_overlay.buffer_err && !p_qhd->qtd_overlay.babble_err && !p_qhd->qtd_overlay.xact_err)
|
||||
{ // no error bits are set, endpoint is halted due to STALL handshake
|
||||
|
||||
}
|
||||
|
||||
hal_debugger_breakpoint();
|
||||
|
||||
p_qhd->p_qtd_list_head->used = 0; // free QTD
|
||||
@ -618,8 +627,9 @@ void xfer_error_isr(uint8_t hostid)
|
||||
usbh_xfer_isr( pipe_hdl, p_qhd->class_code, TUSB_EVENT_XFER_ERROR); // call USBH callback
|
||||
}
|
||||
|
||||
p_qhd = (ehci_qhd_t*) align32(p_qhd->next.address);
|
||||
}while(p_qhd != async_head); // async list traversal, stop if loop around
|
||||
p_qhd = qhd_next(p_qhd);
|
||||
max_loop++;
|
||||
}while(p_qhd != async_head && max_loop < EHCI_MAX_QHD); // async list traversal, stop if loop around
|
||||
|
||||
//------------- TODO period list -------------//
|
||||
}
|
||||
@ -753,16 +763,36 @@ static inline ehci_qhd_t* qhd_find_free (uint8_t dev_addr)
|
||||
return (index < EHCI_MAX_QHD) ? &ehci_data.device[relative_address].qhd[index] : NULL;
|
||||
}
|
||||
|
||||
static inline uint8_t qhd_get_index(ehci_qhd_t * p_qhd)
|
||||
static inline uint8_t qhd_get_index(ehci_qhd_t const * p_qhd)
|
||||
{
|
||||
return p_qhd - ehci_data.device[p_qhd->device_address-1].qhd;
|
||||
}
|
||||
|
||||
static inline ehci_qhd_t* qhd_next(ehci_qhd_t const * p_qhd)
|
||||
{
|
||||
return (ehci_qhd_t*) align32(p_qhd->next.address);
|
||||
}
|
||||
|
||||
STATIC_ INLINE_ ehci_qhd_t* qhd_get_from_pipe_handle(pipe_handle_t pipe_hdl)
|
||||
{
|
||||
return &ehci_data.device[ pipe_hdl.dev_addr-1 ].qhd[ pipe_hdl.index ];
|
||||
}
|
||||
|
||||
static inline pipe_handle_t qhd_create_pipe_handle(ehci_qhd_t const * p_qhd, tusb_xfer_type_t xfer_type)
|
||||
{
|
||||
pipe_handle_t pipe_hdl = {
|
||||
.dev_addr = p_qhd->device_address,
|
||||
.xfer_type = xfer_type
|
||||
};
|
||||
|
||||
// TODO Isochronous transfer support
|
||||
if (TUSB_XFER_CONTROL != xfer_type) // qhd index for control is meaningless
|
||||
{
|
||||
pipe_hdl.index = qhd_get_index(p_qhd);
|
||||
}
|
||||
|
||||
return pipe_hdl;
|
||||
}
|
||||
|
||||
//------------- TD helper -------------//
|
||||
STATIC_ INLINE_ ehci_qtd_t* qtd_find_free(uint8_t dev_addr)
|
||||
@ -776,6 +806,11 @@ STATIC_ INLINE_ ehci_qtd_t* qtd_find_free(uint8_t dev_addr)
|
||||
return (index < EHCI_MAX_QTD) ? &ehci_data.device[dev_addr-1].qtd[index] : NULL;
|
||||
}
|
||||
|
||||
static inline ehci_qtd_t* qtd_next(ehci_qtd_t const * p_qtd )
|
||||
{
|
||||
return (ehci_qtd_t*) align32(p_qtd->next.address);
|
||||
}
|
||||
|
||||
static inline void qtd_remove_1st_from_qhd(ehci_qhd_t *p_qhd)
|
||||
{
|
||||
if (p_qhd->p_qtd_list_head == p_qhd->p_qtd_list_tail) // last TD --> make it NULL
|
||||
@ -783,7 +818,7 @@ static inline void qtd_remove_1st_from_qhd(ehci_qhd_t *p_qhd)
|
||||
p_qhd->p_qtd_list_head = p_qhd->p_qtd_list_tail = NULL;
|
||||
}else
|
||||
{
|
||||
p_qhd->p_qtd_list_head = (ehci_qtd_t*) align32(p_qhd->p_qtd_list_head->next.address);
|
||||
p_qhd->p_qtd_list_head = qtd_next( p_qhd->p_qtd_list_head );
|
||||
}
|
||||
}
|
||||
|
||||
@ -896,9 +931,9 @@ static ehci_link_t* list_find_previous_item(ehci_link_t* p_head, ehci_link_t* p_
|
||||
{
|
||||
ehci_link_t *p_prev = p_head;
|
||||
uint32_t max_loop = 0;
|
||||
while( (align32(p_prev->address) != (uint32_t) p_head) &&
|
||||
(align32(p_prev->address) != (uint32_t) p_current) &&
|
||||
!p_prev->terminate &&
|
||||
while( (align32(p_prev->address) != (uint32_t) p_head) &&
|
||||
(align32(p_prev->address) != (uint32_t) p_current) &&
|
||||
!p_prev->terminate &&
|
||||
max_loop < EHCI_MAX_QHD)
|
||||
{
|
||||
p_prev = (ehci_link_t*) align32(p_prev->address);
|
||||
|
Loading…
x
Reference in New Issue
Block a user