mirror of
https://github.com/hathach/tinyusb.git
synced 2025-01-17 05:32:55 +08:00
Merge pull request #2303 from projectgus/feature/isr_event_hook
Add optional hooks for DCD and HCD events
This commit is contained in:
commit
02017a81e9
@ -242,22 +242,17 @@ tu_static uint8_t _app_driver_count = 0;
|
||||
|
||||
// virtually joins built-in and application drivers together.
|
||||
// Application is positioned first to allow overwriting built-in ones.
|
||||
static inline usbd_class_driver_t const * get_driver(uint8_t drvid)
|
||||
{
|
||||
TU_ATTR_ALWAYS_INLINE static inline usbd_class_driver_t const * get_driver(uint8_t drvid) {
|
||||
usbd_class_driver_t const * driver = NULL;
|
||||
|
||||
if ( drvid < _app_driver_count ) {
|
||||
// Application drivers
|
||||
driver = &_app_driver[drvid];
|
||||
} else if ( drvid < TOTAL_DRIVER_COUNT && BUILTIN_DRIVER_COUNT > 0 ){
|
||||
driver = &_usbd_driver[drvid - _app_driver_count];
|
||||
}
|
||||
|
||||
return driver;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// DCD Event
|
||||
//--------------------------------------------------------------------+
|
||||
@ -278,6 +273,11 @@ tu_static osal_queue_t _usbd_q;
|
||||
#define _usbd_mutex NULL
|
||||
#endif
|
||||
|
||||
TU_ATTR_ALWAYS_INLINE static inline bool queue_event(dcd_event_t const * event, bool in_isr) {
|
||||
bool ret = osal_queue_send(_usbd_q, event, in_isr);
|
||||
if (tud_event_hook_cb) tud_event_hook_cb(event->rhport, event->event_id, in_isr);
|
||||
return ret;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Prototypes
|
||||
@ -374,8 +374,7 @@ bool tud_connect(void)
|
||||
//--------------------------------------------------------------------+
|
||||
// USBD Task
|
||||
//--------------------------------------------------------------------+
|
||||
bool tud_inited(void)
|
||||
{
|
||||
bool tud_inited(void) {
|
||||
return _usbd_rhport != RHPORT_INVALID;
|
||||
}
|
||||
|
||||
@ -1077,66 +1076,64 @@ static bool process_get_descriptor(uint8_t rhport, tusb_control_request_t const
|
||||
//--------------------------------------------------------------------+
|
||||
// DCD Event Handler
|
||||
//--------------------------------------------------------------------+
|
||||
TU_ATTR_FAST_FUNC void dcd_event_handler(dcd_event_t const * event, bool in_isr)
|
||||
{
|
||||
switch (event->event_id)
|
||||
{
|
||||
TU_ATTR_FAST_FUNC void dcd_event_handler(dcd_event_t const* event, bool in_isr) {
|
||||
bool send = false;
|
||||
switch (event->event_id) {
|
||||
case DCD_EVENT_UNPLUGGED:
|
||||
_usbd_dev.connected = 0;
|
||||
_usbd_dev.addressed = 0;
|
||||
_usbd_dev.cfg_num = 0;
|
||||
_usbd_dev.suspended = 0;
|
||||
osal_queue_send(_usbd_q, event, in_isr);
|
||||
break;
|
||||
_usbd_dev.connected = 0;
|
||||
_usbd_dev.addressed = 0;
|
||||
_usbd_dev.cfg_num = 0;
|
||||
_usbd_dev.suspended = 0;
|
||||
send = true;
|
||||
break;
|
||||
|
||||
case DCD_EVENT_SUSPEND:
|
||||
// NOTE: When plugging/unplugging device, the D+/D- state are unstable and
|
||||
// can accidentally meet the SUSPEND condition ( Bus Idle for 3ms ).
|
||||
// In addition, some MCUs such as SAMD or boards that haven no VBUS detection cannot distinguish
|
||||
// suspended vs disconnected. We will skip handling SUSPEND/RESUME event if not currently connected
|
||||
if ( _usbd_dev.connected )
|
||||
{
|
||||
if (_usbd_dev.connected) {
|
||||
_usbd_dev.suspended = 1;
|
||||
osal_queue_send(_usbd_q, event, in_isr);
|
||||
send = true;
|
||||
}
|
||||
break;
|
||||
break;
|
||||
|
||||
case DCD_EVENT_RESUME:
|
||||
// skip event if not connected (especially required for SAMD)
|
||||
if ( _usbd_dev.connected )
|
||||
{
|
||||
if (_usbd_dev.connected) {
|
||||
_usbd_dev.suspended = 0;
|
||||
osal_queue_send(_usbd_q, event, in_isr);
|
||||
send = true;
|
||||
}
|
||||
break;
|
||||
break;
|
||||
|
||||
case DCD_EVENT_SOF:
|
||||
// Some MCUs after running dcd_remote_wakeup() does not have way to detect the end of remote wakeup
|
||||
// which last 1-15 ms. DCD can use SOF as a clear indicator that bus is back to operational
|
||||
if (_usbd_dev.suspended) {
|
||||
_usbd_dev.suspended = 0;
|
||||
|
||||
dcd_event_t const event_resume = {.rhport = event->rhport, .event_id = DCD_EVENT_RESUME};
|
||||
queue_event(&event_resume, in_isr);
|
||||
}
|
||||
|
||||
// SOF driver handler in ISR context
|
||||
for (uint8_t i = 0; i < TOTAL_DRIVER_COUNT; i++)
|
||||
{
|
||||
usbd_class_driver_t const * driver = get_driver(i);
|
||||
if (driver && driver->sof)
|
||||
{
|
||||
for (uint8_t i = 0; i < TOTAL_DRIVER_COUNT; i++) {
|
||||
usbd_class_driver_t const* driver = get_driver(i);
|
||||
if (driver && driver->sof) {
|
||||
driver->sof(event->rhport, event->sof.frame_count);
|
||||
}
|
||||
}
|
||||
|
||||
// Some MCUs after running dcd_remote_wakeup() does not have way to detect the end of remote wakeup
|
||||
// which last 1-15 ms. DCD can use SOF as a clear indicator that bus is back to operational
|
||||
if ( _usbd_dev.suspended )
|
||||
{
|
||||
_usbd_dev.suspended = 0;
|
||||
|
||||
dcd_event_t const event_resume = { .rhport = event->rhport, .event_id = DCD_EVENT_RESUME };
|
||||
osal_queue_send(_usbd_q, &event_resume, in_isr);
|
||||
}
|
||||
|
||||
// skip osal queue for SOF in usbd task
|
||||
break;
|
||||
break;
|
||||
|
||||
default:
|
||||
osal_queue_send(_usbd_q, event, in_isr);
|
||||
break;
|
||||
send = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (send) {
|
||||
queue_event(event, in_isr);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1180,18 +1177,15 @@ bool usbd_open_edpt_pair(uint8_t rhport, uint8_t const* p_desc, uint8_t ep_count
|
||||
}
|
||||
|
||||
// Helper to defer an isr function
|
||||
void usbd_defer_func(osal_task_func_t func, void* param, bool in_isr)
|
||||
{
|
||||
dcd_event_t event =
|
||||
{
|
||||
void usbd_defer_func(osal_task_func_t func, void* param, bool in_isr) {
|
||||
dcd_event_t event = {
|
||||
.rhport = 0,
|
||||
.event_id = USBD_EVENT_FUNC_CALL,
|
||||
};
|
||||
|
||||
event.func_call.func = func;
|
||||
event.func_call.param = param;
|
||||
|
||||
dcd_event_handler(&event, in_isr);
|
||||
queue_event(&event, in_isr);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
|
@ -146,6 +146,9 @@ TU_ATTR_WEAK void tud_suspend_cb(bool remote_wakeup_en);
|
||||
// Invoked when usb bus is resumed
|
||||
TU_ATTR_WEAK void tud_resume_cb(void);
|
||||
|
||||
// Invoked when there is a new usb event, which need to be processed by tud_task()/tud_task_ext()
|
||||
TU_ATTR_WEAK void tud_event_hook_cb(uint8_t rhport, uint32_t eventid, bool in_isr);
|
||||
|
||||
// Invoked when received control request with VENDOR TYPE
|
||||
TU_ATTR_WEAK bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request);
|
||||
|
||||
|
@ -247,9 +247,7 @@ CFG_TUH_MEM_SECTION struct
|
||||
|
||||
//------------- Helper Function -------------//
|
||||
|
||||
TU_ATTR_ALWAYS_INLINE
|
||||
static inline usbh_device_t* get_device(uint8_t dev_addr)
|
||||
{
|
||||
TU_ATTR_ALWAYS_INLINE static inline usbh_device_t* get_device(uint8_t dev_addr) {
|
||||
TU_VERIFY(dev_addr > 0 && dev_addr <= TOTAL_DEVICES, NULL);
|
||||
return &_usbh_devices[dev_addr-1];
|
||||
}
|
||||
@ -268,6 +266,12 @@ TU_ATTR_WEAK void osal_task_delay(uint32_t msec) {
|
||||
}
|
||||
#endif
|
||||
|
||||
TU_ATTR_ALWAYS_INLINE static inline bool queue_event(hcd_event_t const * event, bool in_isr) {
|
||||
bool ret = osal_queue_send(_usbh_q, event, in_isr);
|
||||
if (tuh_event_hook_cb) tuh_event_hook_cb(event->rhport, event->event_id, in_isr);
|
||||
return ret;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Device API
|
||||
//--------------------------------------------------------------------+
|
||||
@ -433,7 +437,7 @@ void tuh_task_ext(uint32_t timeout_ms, bool in_isr) {
|
||||
TU_LOG_USBH("[%u:] USBH Defer Attach until current enumeration complete\r\n", event.rhport);
|
||||
|
||||
bool is_empty = osal_queue_empty(_usbh_q);
|
||||
osal_queue_send(_usbh_q, &event, in_isr);
|
||||
queue_event(&event, in_isr);
|
||||
|
||||
if (is_empty) {
|
||||
// Exit if this is the only event in the queue, otherwise we may loop forever
|
||||
@ -779,7 +783,7 @@ void usbh_defer_func(osal_task_func_t func, void *param, bool in_isr) {
|
||||
event.func_call.func = func;
|
||||
event.func_call.param = param;
|
||||
|
||||
osal_queue_send(_usbh_q, &event, in_isr);
|
||||
queue_event(&event, in_isr);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
@ -935,7 +939,7 @@ TU_ATTR_FAST_FUNC void hcd_event_handler(hcd_event_t const* event, bool in_isr)
|
||||
default: break;
|
||||
}
|
||||
|
||||
osal_queue_send(_usbh_q, event, in_isr);
|
||||
queue_event(event, in_isr);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
|
@ -90,9 +90,12 @@ TU_ATTR_WEAK void tuh_mount_cb (uint8_t daddr);
|
||||
// Invoked when a device failed to mount during enumeration process
|
||||
// TU_ATTR_WEAK void tuh_mount_failed_cb (uint8_t daddr);
|
||||
|
||||
/// Invoked when a device is unmounted (detached)
|
||||
// Invoked when a device is unmounted (detached)
|
||||
TU_ATTR_WEAK void tuh_umount_cb(uint8_t daddr);
|
||||
|
||||
// Invoked when there is a new usb event, which need to be processed by tuh_task()/tuh_task_ext()
|
||||
TU_ATTR_WEAK void tuh_event_hook_cb(uint8_t rhport, uint32_t eventid, bool in_isr);
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// APPLICATION API
|
||||
//--------------------------------------------------------------------+
|
||||
|
Loading…
x
Reference in New Issue
Block a user