-
Notifications
You must be signed in to change notification settings - Fork 1.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Adding support for a generic SOF callback #2213
Changes from all commits
0161955
a98b219
427ecbb
997c29b
288f24b
46977a0
c87fba1
337d03d
6c286e3
c8beaad
11b5b2a
ca479d6
16cd92f
376b439
eea7d7b
36ba42c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -56,6 +56,10 @@ TU_ATTR_WEAK void tud_event_hook_cb(uint8_t rhport, uint32_t eventid, bool in_is | |
(void)in_isr; | ||
} | ||
|
||
TU_ATTR_WEAK void tud_sof_cb(uint32_t frame_count) { | ||
(void)frame_count; | ||
} | ||
|
||
//--------------------------------------------------------------------+ | ||
// Device Data | ||
//--------------------------------------------------------------------+ | ||
|
@@ -76,6 +80,7 @@ typedef struct { | |
volatile uint8_t cfg_num; // current active configuration (0x00 is not configured) | ||
uint8_t speed; | ||
volatile uint8_t setup_count; | ||
volatile uint8_t sof_consumer; | ||
|
||
uint8_t itf2drv[CFG_TUD_INTERFACE_MAX]; // map interface number to driver (0xff is invalid) | ||
uint8_t ep2drv[CFG_TUD_ENDPPOINT_MAX][2]; // map endpoint to driver ( 0xff is invalid ), can use only 4-bit each | ||
|
@@ -275,6 +280,7 @@ TU_ATTR_ALWAYS_INLINE static inline usbd_class_driver_t const * get_driver(uint8 | |
return driver; | ||
} | ||
|
||
|
||
//--------------------------------------------------------------------+ | ||
// DCD Event | ||
//--------------------------------------------------------------------+ | ||
|
@@ -382,6 +388,12 @@ bool tud_connect(void) { | |
return true; | ||
} | ||
|
||
bool tud_sof_cb_enable(bool en) | ||
{ | ||
usbd_sof_enable(_usbd_rhport, SOF_CONSUMER_USER, en); | ||
return true; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. A return value makes no sense here. While also true for my original PR that wasn't as obvious. I wasn't sure if every driver has implemented It would make sense if there is a check if an implementation of a weak declared There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You are right, forgot to change. |
||
} | ||
|
||
//--------------------------------------------------------------------+ | ||
// USBD Task | ||
//--------------------------------------------------------------------+ | ||
|
@@ -612,6 +624,12 @@ void tud_task_ext(uint32_t timeout_ms, bool in_isr) { | |
break; | ||
|
||
case DCD_EVENT_SOF: | ||
if (tu_bit_test(_usbd_dev.sof_consumer, SOF_CONSUMER_USER)) { | ||
TU_LOG_USBD("\r\n"); | ||
tud_sof_cb(event.sof.frame_count); | ||
} | ||
break; | ||
|
||
default: | ||
TU_BREAKPOINT(); | ||
break; | ||
|
@@ -702,6 +720,9 @@ static bool process_control_request(uint8_t rhport, tusb_control_request_t const | |
// already configured: need to clear all endpoints and driver first | ||
TU_LOG_USBD(" Clear current Configuration (%u) before switching\r\n", _usbd_dev.cfg_num); | ||
|
||
// disable SOF | ||
dcd_sof_enable(rhport, false); | ||
|
||
// close all non-control endpoints, cancel all pending transfers if any | ||
dcd_edpt_close_all(rhport); | ||
|
||
|
@@ -1101,6 +1122,14 @@ TU_ATTR_FAST_FUNC void dcd_event_handler(dcd_event_t const* event, bool in_isr) | |
break; | ||
|
||
case DCD_EVENT_SOF: | ||
// 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) { | ||
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) { | ||
|
@@ -1110,15 +1139,10 @@ TU_ATTR_FAST_FUNC void dcd_event_handler(dcd_event_t const* event, bool in_isr) | |
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) { | ||
driver->sof(event->rhport, event->sof.frame_count); | ||
} | ||
if (tu_bit_test(_usbd_dev.sof_consumer, SOF_CONSUMER_USER)) { | ||
dcd_event_t const event_sof = {.rhport = event->rhport, .event_id = DCD_EVENT_SOF}; | ||
queue_event(&event_sof, in_isr); | ||
} | ||
|
||
// skip osal queue for SOF in usbd task | ||
break; | ||
|
||
case DCD_EVENT_SETUP_RECEIVED: | ||
|
@@ -1355,12 +1379,21 @@ void usbd_edpt_close(uint8_t rhport, uint8_t ep_addr) { | |
return; | ||
} | ||
|
||
void usbd_sof_enable(uint8_t rhport, bool en) { | ||
void usbd_sof_enable(uint8_t rhport, sof_consumer_t consumer, bool en) { | ||
rhport = _usbd_rhport; | ||
|
||
// TODO: Check needed if all drivers including the user sof_cb does not need an active SOF ISR any more. | ||
// Only if all drivers switched off SOF calls the SOF interrupt may be disabled | ||
dcd_sof_enable(rhport, en); | ||
uint8_t consumer_old = _usbd_dev.sof_consumer; | ||
// Keep track how many class instances need the SOF interrupt | ||
if (en) { | ||
_usbd_dev.sof_consumer |= (uint8_t)(1 << consumer); | ||
} else { | ||
_usbd_dev.sof_consumer &= (uint8_t)(~(1 << consumer)); | ||
} | ||
|
||
// Test logically unequal | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Seems like a typo, should be: But I don't get why to mention the specific implementation instead of the goal. While a hint that this is a logical XOR is indeed nice I think a comment should primary explain the meaning and not the implementation detail. Like: There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not a typo, it could be other consumers later, should be only called when whole value change to true or false.
This comment was marked as off-topic.
Sorry, something went wrong. |
||
if(!_usbd_dev.sof_consumer != !consumer_old) { | ||
dcd_sof_enable(rhport, _usbd_dev.sof_consumer); | ||
} | ||
} | ||
|
||
bool usbd_edpt_iso_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t largest_packet_size) { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not have a weak declaration in the header file? After all it's used only once at #L629 anyway. So a check there for a definition similar how it's done for other things should be more inline.
Edit:
In that case there can be a sanity check. Like to return false at #L394 if there is no function definition.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We are converting to weak default implementation for keil and clang compatibility.