summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorIngHK <[email protected]>2024-04-04 14:07:32 +0200
committerIngHK <[email protected]>2024-04-04 14:07:32 +0200
commite2a56308110c1b3948441bec7ea71e397dfc1b49 (patch)
tree904e3c19c3c5e0027f243e8aa3d247b72051e886 /src
parent1bbd658352f5ecbfea13343df20cd02597dc31fd (diff)
parent66cdf6d097d76f8d21ed4314651ac730d4023f99 (diff)
Merge remote-tracking branch 'remotes/hathach/master' into cdch_upgrade
Diffstat (limited to 'src')
-rw-r--r--src/class/audio/audio.h25
-rw-r--r--src/class/audio/audio_device.c98
-rw-r--r--src/class/audio/audio_device.h28
-rw-r--r--src/class/cdc/cdc_host.c18
-rw-r--r--src/class/cdc/cdc_host.h3
-rw-r--r--src/class/hid/hid_host.c11
-rw-r--r--src/class/hid/hid_host.h3
-rw-r--r--src/class/msc/msc_host.c8
-rw-r--r--src/class/msc/msc_host.h3
-rw-r--r--src/class/video/video.h23
-rw-r--r--src/class/video/video_device.c258
-rw-r--r--src/common/tusb_fifo.h31
-rw-r--r--src/common/tusb_private.h19
-rw-r--r--src/device/usbd.c2
-rw-r--r--src/device/usbd.h13
-rw-r--r--src/host/hcd.h5
-rw-r--r--src/host/hub.c8
-rw-r--r--src/host/hub.h13
-rw-r--r--src/host/usbh.c267
-rw-r--r--src/host/usbh.h18
-rw-r--r--src/host/usbh_pvt.h6
-rw-r--r--src/osal/osal.h3
-rw-r--r--src/osal/osal_freertos.h19
-rw-r--r--src/osal/osal_mynewt.h61
-rw-r--r--src/osal/osal_none.h16
-rw-r--r--src/osal/osal_pico.h105
-rw-r--r--src/osal/osal_rtthread.h60
-rw-r--r--src/osal/osal_rtx4.h61
-rw-r--r--src/portable/analog/max3421/hcd_max3421.c269
-rw-r--r--src/portable/nordic/nrf5x/dcd_nrf5x.c4
-rw-r--r--src/portable/raspberrypi/rp2040/hcd_rp2040.c10
-rw-r--r--src/portable/sony/cxd56/dcd_cxd56.c30
-rw-r--r--src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c53
-rw-r--r--src/portable/st/stm32_fsdev/dcd_stm32_fsdev.h (renamed from src/portable/st/stm32_fsdev/dcd_stm32_fsdev_pvt_st.h)181
-rw-r--r--src/portable/synopsys/dwc2/dcd_dwc2.c313
-rw-r--r--src/tusb.c292
-rw-r--r--src/tusb_option.h6
37 files changed, 1290 insertions, 1053 deletions
diff --git a/src/class/audio/audio.h b/src/class/audio/audio.h
index 70d431282..d6f3e22e2 100644
--- a/src/class/audio/audio.h
+++ b/src/class/audio/audio.h
@@ -924,6 +924,31 @@ typedef struct TU_ATTR_PACKED {
} subrange[numSubRanges]; \
}
+// 6.1 Interrupt Data Message Format
+typedef struct TU_ATTR_PACKED
+{
+ uint8_t bInfo;
+ uint8_t bAttribute;
+ union
+ {
+ uint16_t wValue;
+ struct
+ {
+ uint8_t wValue_cn_or_mcn;
+ uint8_t wValue_cs;
+ };
+ };
+ union
+ {
+ uint16_t wIndex;
+ struct
+ {
+ uint8_t wIndex_ep_or_int;
+ uint8_t wIndex_entity_id;
+ };
+ };
+} audio_interrupt_data_t;
+
/** @} */
#ifdef __cplusplus
diff --git a/src/class/audio/audio_device.c b/src/class/audio/audio_device.c
index 4adc558a6..9a361419b 100644
--- a/src/class/audio/audio_device.c
+++ b/src/class/audio/audio_device.c
@@ -96,8 +96,8 @@
#define USE_LINEAR_BUFFER 1
#endif
-// Temporarily put the check here for stm32_fsdev
-#ifdef TUP_USBIP_FSDEV
+// Temporarily put the check here
+#if defined(TUP_USBIP_FSDEV) || defined(TUP_USBIP_DWC2)
#define USE_ISO_EP_ALLOCATION 1
#else
#define USE_ISO_EP_ALLOCATION 0
@@ -301,10 +301,12 @@ typedef struct
#endif
-#if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN
- uint8_t ep_int_ctr; // Audio control interrupt EP.
+#if CFG_TUD_AUDIO_ENABLE_INTERRUPT_EP
+ uint8_t ep_int; // Audio control interrupt EP.
#endif
+ bool mounted; // Device opened
+
/*------------- From this point, data is not cleared by bus reset -------------*/
uint16_t desc_length; // Length of audio function descriptor
@@ -358,8 +360,8 @@ typedef struct
#endif
// Audio control interrupt buffer - no FIFO - 6 Bytes according to UAC 2 specification (p. 74)
-#if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN
- CFG_TUSB_MEM_ALIGN uint8_t ep_int_ctr_buf[CFG_TUD_AUDIO_INT_CTR_EP_IN_SW_BUFFER_SIZE];
+#if CFG_TUD_AUDIO_ENABLE_INTERRUPT_EP
+ CFG_TUSB_MEM_ALIGN uint8_t ep_int_buf[6];
#endif
// Decoding parameters - parameters are set when alternate AS interface is set by host
@@ -486,23 +488,7 @@ bool tud_audio_n_mounted(uint8_t func_id)
TU_VERIFY(func_id < CFG_TUD_AUDIO);
audiod_function_t* audio = &_audiod_fct[func_id];
-#if CFG_TUD_AUDIO_ENABLE_EP_OUT
- if (audio->ep_out == 0) return false;
-#endif
-
-#if CFG_TUD_AUDIO_ENABLE_EP_IN
- if (audio->ep_in == 0) return false;
-#endif
-
-#if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN
- if (audio->ep_int_ctr == 0) return false;
-#endif
-
-#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
- if (audio->ep_fb == 0) return false;
-#endif
-
- return true;
+ return audio->mounted;
}
//--------------------------------------------------------------------+
@@ -825,24 +811,30 @@ tu_fifo_t* tud_audio_n_get_tx_support_ff(uint8_t func_id, uint8_t ff_idx)
#endif
-#if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN
-
-// If no interrupt transmit is pending bytes get written into buffer and a transmit is scheduled - once transmit completed tud_audio_int_ctr_done_cb() is called in inform user
-uint16_t tud_audio_int_ctr_n_write(uint8_t func_id, uint8_t const* buffer, uint16_t len)
+#if CFG_TUD_AUDIO_ENABLE_INTERRUPT_EP
+// If no interrupt transmit is pending bytes get written into buffer and a transmit is scheduled - once transmit completed tud_audio_int_done_cb() is called in inform user
+bool tud_audio_int_n_write(uint8_t func_id, const audio_interrupt_data_t * data)
{
TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL);
- // We write directly into the EP's buffer - abort if previous transfer not complete
- TU_VERIFY(!usbd_edpt_busy(_audiod_fct[func_id].rhport, _audiod_fct[func_id].ep_int_ctr));
+ TU_VERIFY(_audiod_fct[func_id].ep_int != 0);
- TU_VERIFY(tu_memcpy_s(_audiod_fct[func_id].ep_int_ctr_buf, CFG_TUD_AUDIO_INT_CTR_EP_IN_SW_BUFFER_SIZE, buffer, len)==0);
+ // We write directly into the EP's buffer - abort if previous transfer not complete
+ TU_VERIFY(usbd_edpt_claim(_audiod_fct[func_id].rhport, _audiod_fct[func_id].ep_int));
- // Schedule transmit
- TU_VERIFY(usbd_edpt_xfer(_audiod_fct[func_id].rhport, _audiod_fct[func_id].ep_int_ctr, _audiod_fct[func_id].ep_int_ctr_buf, len));
+ // Check length
+ if (tu_memcpy_s(_audiod_fct[func_id].ep_int_buf, sizeof(_audiod_fct[func_id].ep_int_buf), data, sizeof(audio_interrupt_data_t)) == 0)
+ {
+ // Schedule transmit
+ TU_ASSERT(usbd_edpt_xfer(_audiod_fct[func_id].rhport, _audiod_fct[func_id].ep_int, _audiod_fct[func_id].ep_int_buf, sizeof(_audiod_fct[func_id].ep_int_buf)), 0);
+ } else
+ {
+ // Release endpoint since we don't make any transfer
+ usbd_edpt_release(_audiod_fct[func_id].rhport, _audiod_fct[func_id].ep_int);
+ }
return true;
}
-
#endif
// This function is called once a transmit of an audio packet was successfully completed. Here, we encode samples and place it in IN EP's buffer for next transmission.
@@ -1447,10 +1439,11 @@ uint16_t audiod_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uin
// Verify version is correct - this check can be omitted
TU_VERIFY(itf_desc->bInterfaceProtocol == AUDIO_INT_PROTOCOL_CODE_V2);
- // Verify interrupt control EP is enabled if demanded by descriptor - this should be best some static check however - this check can be omitted
- if (itf_desc->bNumEndpoints == 1) // 0 or 1 EPs are allowed
+ // Verify interrupt control EP is enabled if demanded by descriptor
+ TU_ASSERT(itf_desc->bNumEndpoints <= 1); // 0 or 1 EPs are allowed
+ if (itf_desc->bNumEndpoints == 1)
{
- TU_VERIFY(CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN > 0);
+ TU_ASSERT(CFG_TUD_AUDIO_ENABLE_INTERRUPT_EP);
}
// Alternate setting MUST be zero - this check can be omitted
@@ -1594,6 +1587,32 @@ uint16_t audiod_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uin
}
#endif // CFG_TUD_AUDIO_EP_IN_FLOW_CONTROL
+#if CFG_TUD_AUDIO_ENABLE_INTERRUPT_EP
+ {
+ uint8_t const *p_desc = _audiod_fct[i].p_desc;
+ uint8_t const *p_desc_end = p_desc + _audiod_fct[i].desc_length - TUD_AUDIO_DESC_IAD_LEN;
+ // Condition modified from p_desc < p_desc_end to prevent gcc>=12 strict-overflow warning
+ while (p_desc_end - p_desc > 0)
+ {
+ // For each endpoint
+ if (tu_desc_type(p_desc) == TUSB_DESC_ENDPOINT)
+ {
+ tusb_desc_endpoint_t const* desc_ep = (tusb_desc_endpoint_t const *) p_desc;
+ uint8_t const ep_addr = desc_ep->bEndpointAddress;
+ // If endpoint is input-direction and interrupt-type
+ if (tu_edpt_dir(ep_addr) == TUSB_DIR_IN && desc_ep->bmAttributes.xfer == TUSB_XFER_INTERRUPT)
+ {
+ // Store endpoint number and open endpoint
+ _audiod_fct[i].ep_int = ep_addr;
+ TU_ASSERT(usbd_edpt_open(_audiod_fct[i].rhport, desc_ep));
+ }
+ }
+ p_desc = tu_desc_next(p_desc);
+ }
+ }
+#endif
+
+ _audiod_fct[i].mounted = true;
break;
}
}
@@ -2120,10 +2139,10 @@ bool audiod_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint3
{
audiod_function_t* audio = &_audiod_fct[func_id];
-#if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN
+#if CFG_TUD_AUDIO_ENABLE_INTERRUPT_EP
// Data transmission of control interrupt finished
- if (audio->ep_int_ctr == ep_addr)
+ if (audio->ep_int == ep_addr)
{
// According to USB2 specification, maximum payload of interrupt EP is 8 bytes on low speed, 64 bytes on full speed, and 1024 bytes on high speed (but only if an alternate interface other than 0 is used - see specification p. 49)
// In case there is nothing to send we have to return a NAK - this is taken care of by PHY ???
@@ -2132,7 +2151,8 @@ bool audiod_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint3
// I assume here, that things above are handled by PHY
// All transmission is done - what remains to do is to inform job was completed
- if (tud_audio_int_ctr_done_cb) TU_VERIFY(tud_audio_int_ctr_done_cb(rhport, (uint16_t) xferred_bytes));
+ if (tud_audio_int_done_cb) tud_audio_int_done_cb(rhport);
+ return true;
}
#endif
diff --git a/src/class/audio/audio_device.h b/src/class/audio/audio_device.h
index ef3e12a06..040a760d6 100644
--- a/src/class/audio/audio_device.h
+++ b/src/class/audio/audio_device.h
@@ -196,13 +196,9 @@
#define CFG_TUD_AUDIO_ENABLE_FEEDBACK_FORMAT_CORRECTION 0 // 0 or 1
#endif
-// Audio interrupt control EP size - disabled if 0
-#ifndef CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN
-#define CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN 0 // Audio interrupt control - if required - 6 Bytes according to UAC 2 specification (p. 74)
-#endif
-
-#ifndef CFG_TUD_AUDIO_INT_CTR_EP_IN_SW_BUFFER_SIZE
-#define CFG_TUD_AUDIO_INT_CTR_EP_IN_SW_BUFFER_SIZE 6 // Buffer size of audio control interrupt EP - 6 Bytes according to UAC 2 specification (p. 74)
+// Enable/disable interrupt EP (required for notifying host of control changes)
+#ifndef CFG_TUD_AUDIO_ENABLE_INTERRUPT_EP
+#define CFG_TUD_AUDIO_ENABLE_INTERRUPT_EP 0 // Feedback - 0 or 1
#endif
// Use software encoding/decoding
@@ -393,8 +389,8 @@ uint16_t tud_audio_n_write_support_ff (uint8_t func_id, uint8_t ff_i
tu_fifo_t* tud_audio_n_get_tx_support_ff (uint8_t func_id, uint8_t ff_idx);
#endif
-#if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN
-uint16_t tud_audio_int_ctr_n_write (uint8_t func_id, uint8_t const* buffer, uint16_t len);
+#if CFG_TUD_AUDIO_ENABLE_INTERRUPT_EP
+bool tud_audio_int_n_write (uint8_t func_id, const audio_interrupt_data_t * data);
#endif
@@ -437,8 +433,8 @@ static inline tu_fifo_t* tud_audio_get_tx_support_ff (uint8_t ff_idx);
// INT CTR API
-#if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN
-static inline uint16_t tud_audio_int_ctr_write (uint8_t const* buffer, uint16_t len);
+#if CFG_TUD_AUDIO_ENABLE_INTERRUPT_EP
+static inline bool tud_audio_int_write (const audio_interrupt_data_t * data);
#endif
// Buffer control EP data and schedule a transmit
@@ -537,8 +533,8 @@ TU_ATTR_WEAK TU_ATTR_FAST_FUNC void tud_audio_feedback_interval_isr(uint8_t func
#endif // CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
-#if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN
-TU_ATTR_WEAK bool tud_audio_int_ctr_done_cb(uint8_t rhport, uint16_t n_bytes_copied);
+#if CFG_TUD_AUDIO_ENABLE_INTERRUPT_EP
+TU_ATTR_WEAK void tud_audio_int_done_cb(uint8_t rhport);
#endif
// Invoked when audio set interface request received
@@ -669,10 +665,10 @@ static inline tu_fifo_t* tud_audio_get_tx_support_ff(uint8_t ff_idx)
#endif
-#if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN
-static inline uint16_t tud_audio_int_ctr_write(uint8_t const* buffer, uint16_t len)
+#if CFG_TUD_AUDIO_ENABLE_INTERRUPT_EP
+static inline bool tud_audio_int_write(const audio_interrupt_data_t * data)
{
- return tud_audio_int_ctr_n_write(0, buffer, len);
+ return tud_audio_int_n_write(0, data);
}
#endif
diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c
index 6121e59f0..e6579ad82 100644
--- a/src/class/cdc/cdc_host.c
+++ b/src/class/cdc/cdc_host.c
@@ -717,12 +717,11 @@ bool tuh_cdc_set_line_coding(uint8_t idx, cdc_line_coding_t const * line_coding,
// CLASS-USBH API
//--------------------------------------------------------------------+
-void cdch_init(void) {
+bool cdch_init(void) {
+ TU_LOG_DRV("sizeof(cdch_interface_t) = %u\r\n", sizeof(cdch_interface_t));
tu_memclr(cdch_data, sizeof(cdch_data));
-
for (size_t i = 0; i < CFG_TUH_CDC; i++) {
- cdch_interface_t * p_cdc = &cdch_data[i];
-
+ cdch_interface_t* p_cdc = &cdch_data[i];
tu_edpt_stream_init(&p_cdc->stream.tx, true, true, false,
p_cdc->stream.tx_ff_buf, CFG_TUH_CDC_TX_BUFSIZE,
p_cdc->stream.tx_ep_buf, CFG_TUH_CDC_TX_EPSIZE);
@@ -731,6 +730,17 @@ void cdch_init(void) {
p_cdc->stream.rx_ff_buf, CFG_TUH_CDC_RX_BUFSIZE,
p_cdc->stream.rx_ep_buf, CFG_TUH_CDC_RX_EPSIZE);
}
+
+ return true;
+}
+
+bool cdch_deinit(void) {
+ for (size_t i = 0; i < CFG_TUH_CDC; i++) {
+ cdch_interface_t* p_cdc = &cdch_data[i];
+ tu_edpt_stream_deinit(&p_cdc->stream.tx);
+ tu_edpt_stream_deinit(&p_cdc->stream.rx);
+ }
+ return true;
}
void cdch_close(uint8_t daddr) {
diff --git a/src/class/cdc/cdc_host.h b/src/class/cdc/cdc_host.h
index 77081d3b0..27f9170a8 100644
--- a/src/class/cdc/cdc_host.h
+++ b/src/class/cdc/cdc_host.h
@@ -188,7 +188,8 @@ TU_ATTR_WEAK extern void tuh_cdc_tx_complete_cb(uint8_t idx);
//--------------------------------------------------------------------+
// Internal Class Driver API
//--------------------------------------------------------------------+
-void cdch_init (void);
+bool cdch_init (void);
+bool cdch_deinit (void);
bool cdch_open (uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *itf_desc, uint16_t max_len);
bool cdch_set_config (uint8_t dev_addr, uint8_t itf_num);
bool cdch_xfer_cb (uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes);
diff --git a/src/class/hid/hid_host.c b/src/class/hid/hid_host.c
index 7330fa237..621fb2a55 100644
--- a/src/class/hid/hid_host.c
+++ b/src/class/hid/hid_host.c
@@ -372,8 +372,14 @@ bool tuh_hid_send_report(uint8_t daddr, uint8_t idx, uint8_t report_id, const vo
//--------------------------------------------------------------------+
// USBH API
//--------------------------------------------------------------------+
-void hidh_init(void) {
+bool hidh_init(void) {
+ TU_LOG_DRV("sizeof(hidh_interface_t) = %u\r\n", sizeof(hidh_interface_t));
tu_memclr(_hidh_itf, sizeof(_hidh_itf));
+ return true;
+}
+
+bool hidh_deinit(void) {
+ return true;
}
bool hidh_xfer_cb(uint8_t daddr, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) {
@@ -404,8 +410,7 @@ void hidh_close(uint8_t daddr) {
if (p_hid->daddr == daddr) {
TU_LOG_DRV(" HIDh close addr = %u index = %u\r\n", daddr, i);
if (tuh_hid_umount_cb) tuh_hid_umount_cb(daddr, i);
- p_hid->daddr = 0;
- p_hid->mounted = false;
+ tu_memclr(p_hid, sizeof(hidh_interface_t));
}
}
}
diff --git a/src/class/hid/hid_host.h b/src/class/hid/hid_host.h
index 17f4e27c0..0902bf1af 100644
--- a/src/class/hid/hid_host.h
+++ b/src/class/hid/hid_host.h
@@ -163,7 +163,8 @@ TU_ATTR_WEAK void tuh_hid_set_protocol_complete_cb(uint8_t dev_addr, uint8_t idx
//--------------------------------------------------------------------+
// Internal Class Driver API
//--------------------------------------------------------------------+
-void hidh_init(void);
+bool hidh_init(void);
+bool hidh_deinit(void);
bool hidh_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const* desc_itf, uint16_t max_len);
bool hidh_set_config(uint8_t dev_addr, uint8_t itf_num);
bool hidh_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes);
diff --git a/src/class/msc/msc_host.c b/src/class/msc/msc_host.c
index 39f2d9f1c..ce6e7fb2d 100644
--- a/src/class/msc/msc_host.c
+++ b/src/class/msc/msc_host.c
@@ -284,8 +284,14 @@ bool tuh_msc_reset(uint8_t dev_addr) {
//--------------------------------------------------------------------+
// CLASS-USBH API
//--------------------------------------------------------------------+
-void msch_init(void) {
+bool msch_init(void) {
+ TU_LOG_DRV("sizeof(msch_interface_t) = %u\r\n", sizeof(msch_interface_t));
tu_memclr(_msch_itf, sizeof(_msch_itf));
+ return true;
+}
+
+bool msch_deinit(void) {
+ return true;
}
void msch_close(uint8_t dev_addr) {
diff --git a/src/class/msc/msc_host.h b/src/class/msc/msc_host.h
index 9ca1b4703..9fda566d8 100644
--- a/src/class/msc/msc_host.h
+++ b/src/class/msc/msc_host.h
@@ -113,7 +113,8 @@ TU_ATTR_WEAK void tuh_msc_umount_cb(uint8_t dev_addr);
// Internal Class Driver API
//--------------------------------------------------------------------+
-void msch_init (void);
+bool msch_init (void);
+bool msch_deinit (void);
bool msch_open (uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *desc_itf, uint16_t max_len);
bool msch_set_config (uint8_t dev_addr, uint8_t itf_num);
void msch_close (uint8_t dev_addr);
diff --git a/src/class/video/video.h b/src/class/video/video.h
index abf1e34b9..b8a9b6369 100644
--- a/src/class/video/video.h
+++ b/src/class/video/video.h
@@ -160,22 +160,23 @@ typedef enum {
/* A.9.1 VideoControl Interface Control Selectors */
typedef enum {
VIDEO_VC_CTL_UNDEFINED = 0x00,
- VIDEO_VC_CTL_VIDEO_POWER_MODE,
- VIDEO_VC_CTL_REQUEST_ERROR_CODE,
+ VIDEO_VC_CTL_VIDEO_POWER_MODE, // 0x01
+ VIDEO_VC_CTL_REQUEST_ERROR_CODE, // 0x02
} video_interface_control_selector_t;
/* A.9.8 VideoStreaming Interface Control Selectors */
typedef enum {
VIDEO_VS_CTL_UNDEFINED = 0x00,
- VIDEO_VS_CTL_PROBE,
- VIDEO_VS_CTL_COMMIT,
- VIDEO_VS_CTL_STILL_PROBE,
- VIDEO_VS_CTL_STILL_COMMIT,
- VIDEO_VS_CTL_STILL_IMAGE_TRIGGER,
- VIDEO_VS_CTL_STREAM_ERROR_CODE,
- VIDEO_VS_CTL_GENERATE_KEY_FRAME,
- VIDEO_VS_CTL_UPDATE_FRAME_SEGMENT,
- VIDEO_VS_CTL_SYNCH_DELAY_CONTROL,
+ VIDEO_VS_CTL_PROBE, // 0x01
+ VIDEO_VS_CTL_COMMIT, // 0x02
+ VIDEO_VS_CTL_STILL_PROBE, // 0x03
+ VIDEO_VS_CTL_STILL_COMMIT, // 0x04
+ VIDEO_VS_CTL_STILL_IMAGE_TRIGGER, // 0x05
+ VIDEO_VS_CTL_STREAM_ERROR_CODE, // 0x06
+ VIDEO_VS_CTL_GENERATE_KEY_FRAME, // 0x07
+ VIDEO_VS_CTL_UPDATE_FRAME_SEGMENT, // 0x08
+ VIDEO_VS_CTL_SYNCH_DELAY_CONTROL, // 0x09
+
} video_interface_streaming_selector_t;
/* B. Terminal Types */
diff --git a/src/class/video/video_device.c b/src/class/video/video_device.c
index 249ced83d..5306356ba 100644
--- a/src/class/video/video_device.c
+++ b/src/class/video/video_device.c
@@ -114,6 +114,8 @@ typedef struct TU_ATTR_PACKED {
uint32_t max_payload_transfer_size;
uint8_t error_code;/* error code */
uint8_t state; /* 0:probing 1:committed 2:streaming */
+
+ video_probe_and_commit_control_t probe_commit_payload; /* Probe and Commit control */
/*------------- From this point, data is not cleared by bus reset -------------*/
CFG_TUSB_MEM_ALIGN uint8_t ep_buf[CFG_TUD_VIDEO_STREAMING_EP_BUFSIZE]; /* EP transfer buffer for streaming */
} videod_streaming_interface_t;
@@ -143,13 +145,65 @@ CFG_TUD_MEM_SECTION tu_static videod_streaming_interface_t _videod_streaming_itf
tu_static uint8_t const _cap_get = 0x1u; /* support for GET */
tu_static uint8_t const _cap_get_set = 0x3u; /* support for GET and SET */
+//--------------------------------------------------------------------+
+// Debug
+//--------------------------------------------------------------------+
+#if CFG_TUSB_DEBUG >= CFG_TUD_VIDEO_LOG_LEVEL
+
+static tu_lookup_entry_t const tu_lookup_video_request[] = {
+ {.key = VIDEO_REQUEST_UNDEFINED, .data = "Undefined"},
+ {.key = VIDEO_REQUEST_SET_CUR, .data = "SetCur"},
+ {.key = VIDEO_REQUEST_SET_CUR_ALL, .data = "SetCurAll"},
+ {.key = VIDEO_REQUEST_GET_CUR, .data = "GetCur"},
+ {.key = VIDEO_REQUEST_GET_MIN, .data = "GetMin"},
+ {.key = VIDEO_REQUEST_GET_MAX, .data = "GetMax"},
+ {.key = VIDEO_REQUEST_GET_RES, .data = "GetRes"},
+ {.key = VIDEO_REQUEST_GET_LEN, .data = "GetLen"},
+ {.key = VIDEO_REQUEST_GET_INFO, .data = "GetInfo"},
+ {.key = VIDEO_REQUEST_GET_DEF, .data = "GetDef"},
+ {.key = VIDEO_REQUEST_GET_CUR_ALL, .data = "GetCurAll"},
+ {.key = VIDEO_REQUEST_GET_MIN_ALL, .data = "GetMinAll"},
+ {.key = VIDEO_REQUEST_GET_MAX_ALL, .data = "GetMaxAll"},
+ {.key = VIDEO_REQUEST_GET_RES_ALL, .data = "GetResAll"},
+ {.key = VIDEO_REQUEST_GET_DEF_ALL, .data = "GetDefAll"},
+};
+
+static tu_lookup_table_t const tu_table_video_request = {
+ .count = TU_ARRAY_SIZE(tu_lookup_video_request),
+ .items = tu_lookup_video_request
+};
+
+static char const* const tu_str_video_vc_control_selector[] = {
+ "Undefined",
+ "Video Power Mode",
+ "Request Error Code",
+};
+
+static char const* const tu_str_video_vs_control_selector[] = {
+ "Undefined",
+ "Probe",
+ "Commit",
+ "Still Probe",
+ "Still Commit",
+ "Still Image Trigger",
+ "Stream Error Code",
+ "Generate Key Frame",
+ "Update Frame Segment",
+ "Sync Delay",
+};
+
+#endif
+
+//--------------------------------------------------------------------+
+//
+//--------------------------------------------------------------------+
+
/** Get interface number from the interface descriptor
*
* @param[in] desc interface descriptor
*
* @return bInterfaceNumber */
-static inline uint8_t _desc_itfnum(void const *desc)
-{
+static inline uint8_t _desc_itfnum(void const *desc) {
return ((uint8_t const*)desc)[2];
}
@@ -158,8 +212,7 @@ static inline uint8_t _desc_itfnum(void const *desc)
* @param[in] desc endpoint descriptor
*
* @return bEndpointAddress */
-static inline uint8_t _desc_ep_addr(void const *desc)
-{
+static inline uint8_t _desc_ep_addr(void const *desc) {
return ((uint8_t const*)desc)[2];
}
@@ -169,8 +222,7 @@ static inline uint8_t _desc_ep_addr(void const *desc)
* @param[in] stm_idx index number of streaming interface
*
* @return instance */
-static videod_streaming_interface_t* _get_instance_streaming(uint_fast8_t ctl_idx, uint_fast8_t stm_idx)
-{
+static videod_streaming_interface_t* _get_instance_streaming(uint_fast8_t ctl_idx, uint_fast8_t stm_idx) {
videod_interface_t *ctl = &_videod_itf[ctl_idx];
if (!ctl->beg) return NULL;
videod_streaming_interface_t *stm = &_videod_streaming_itf[ctl->stm[stm_idx]];
@@ -178,13 +230,11 @@ static videod_streaming_interface_t* _get_instance_streaming(uint_fast8_t ctl_id
return stm;
}
-static tusb_desc_vc_itf_t const* _get_desc_vc(videod_interface_t const *self)
-{
+static tusb_desc_vc_itf_t const* _get_desc_vc(videod_interface_t const *self) {
return (tusb_desc_vc_itf_t const *)(self->beg + self->cur);
}
-static tusb_desc_vs_itf_t const* _get_desc_vs(videod_streaming_interface_t const *self)
-{
+static tusb_desc_vs_itf_t const* _get_desc_vs(videod_streaming_interface_t const *self) {
if (!self->desc.cur) return NULL;
uint8_t const *desc = _videod_itf[self->index_vc].beg;
return (tusb_desc_vs_itf_t const*)(desc + self->desc.cur);
@@ -198,8 +248,7 @@ static tusb_desc_vs_itf_t const* _get_desc_vs(videod_streaming_interface_t const
*
* @return The pointer for interface descriptor.
* @retval end did not found interface descriptor */
-static void const* _find_desc(void const *beg, void const *end, uint_fast8_t desc_type)
-{
+static void const* _find_desc(void const *beg, void const *end, uint_fast8_t desc_type) {
void const *cur = beg;
while ((cur < end) && (desc_type != tu_desc_type(cur))) {
cur = tu_desc_next(cur);
@@ -238,8 +287,7 @@ static void const* _find_desc_2_type(void const *beg, void const *end, uint_fast
static void const* _find_desc_3(void const *beg, void const *end,
uint_fast8_t desc_type,
uint_fast8_t element_0,
- uint_fast8_t element_1)
-{
+ uint_fast8_t element_1) {
for (void const *cur = beg; cur < end; cur = _find_desc(cur, end, desc_type)) {
uint8_t const *p = (uint8_t const *)cur;
if ((p[2] == element_0) && (p[3] == element_1)) {
@@ -261,8 +309,7 @@ static void const* _find_desc_3(void const *beg, void const *end,
*
* @return The pointer for interface descriptor.
* @retval end did not found interface descriptor */
-static void const* _next_desc_itf(void const *beg, void const *end)
-{
+static void const* _next_desc_itf(void const *beg, void const *end) {
void const *cur = beg;
uint_fast8_t itfnum = ((tusb_desc_interface_t const*)cur)->bInterfaceNumber;
while ((cur < end) &&
@@ -413,8 +460,10 @@ static bool _update_streaming_parameters(videod_streaming_interface_t const *stm
case VIDEO_CS_ITF_VS_FORMAT_UNCOMPRESSED:
param->wCompQuality = 1; /* 1 to 10000 */
break;
- case VIDEO_CS_ITF_VS_FORMAT_MJPEG:
+
+ case VIDEO_CS_ITF_VS_FORMAT_MJPEG:
break;
+
default: return false;
}
@@ -435,9 +484,11 @@ static bool _update_streaming_parameters(videod_streaming_interface_t const *stm
case VIDEO_CS_ITF_VS_FORMAT_UNCOMPRESSED:
frame_size = (uint_fast32_t)frm->wWidth * frm->wHeight * fmt->uncompressed.bBitsPerPixel / 8;
break;
+
case VIDEO_CS_ITF_VS_FORMAT_MJPEG:
frame_size = (uint_fast32_t)frm->wWidth * frm->wHeight * 16 / 8; /* YUV422 */
break;
+
default: break;
}
param->dwMaxVideoFrameSize = frame_size;
@@ -478,10 +529,12 @@ static bool _negotiate_streaming_parameters(videod_streaming_interface_t const *
if (_get_desc_vs(stm))
param->bFormatIndex = _get_desc_vs(stm)->stm.bNumFormats;
break;
+
case VIDEO_REQUEST_GET_MIN:
case VIDEO_REQUEST_GET_DEF:
param->bFormatIndex = 1;
break;
+
default: return false;
}
/* Set the parameters determined by the format */
@@ -510,18 +563,22 @@ static bool _negotiate_streaming_parameters(videod_streaming_interface_t const *
case VIDEO_REQUEST_GET_MAX:
frmnum = fmt->bNumFrameDescriptors;
break;
+
case VIDEO_REQUEST_GET_MIN:
frmnum = 1;
break;
+
case VIDEO_REQUEST_GET_DEF:
switch (fmt->bDescriptorSubType) {
- case VIDEO_CS_ITF_VS_FORMAT_UNCOMPRESSED:
- frmnum = fmt->uncompressed.bDefaultFrameIndex;
- break;
- case VIDEO_CS_ITF_VS_FORMAT_MJPEG:
- frmnum = fmt->mjpeg.bDefaultFrameIndex;
- break;
- default: return false;
+ case VIDEO_CS_ITF_VS_FORMAT_UNCOMPRESSED:
+ frmnum = fmt->uncompressed.bDefaultFrameIndex;
+ break;
+
+ case VIDEO_CS_ITF_VS_FORMAT_MJPEG:
+ frmnum = fmt->mjpeg.bDefaultFrameIndex;
+ break;
+
+ default: return false;
}
break;
default: return false;
@@ -534,9 +591,11 @@ static bool _negotiate_streaming_parameters(videod_streaming_interface_t const *
case VIDEO_CS_ITF_VS_FORMAT_UNCOMPRESSED:
frame_size = (uint_fast32_t)frm->wWidth * frm->wHeight * fmt->uncompressed.bBitsPerPixel / 8;
break;
+
case VIDEO_CS_ITF_VS_FORMAT_MJPEG:
frame_size = (uint_fast32_t)frm->wWidth * frm->wHeight * 16 / 8; /* YUV422 */
break;
+
default: return false;
}
param->dwMaxVideoFrameSize = frame_size;
@@ -552,42 +611,43 @@ static bool _negotiate_streaming_parameters(videod_streaming_interface_t const *
uint_fast32_t interval, interval_ms;
switch (request) {
- case VIDEO_REQUEST_GET_MAX:
- {
- uint_fast32_t min_interval, max_interval;
- uint_fast8_t num_intervals = frm->uncompressed.bFrameIntervalType;
- max_interval = num_intervals ? frm->uncompressed.dwFrameInterval[num_intervals - 1]: frm->uncompressed.dwFrameInterval[1];
- min_interval = frm->uncompressed.dwFrameInterval[0];
- interval = max_interval;
- interval_ms = min_interval / 10000;
- }
+ case VIDEO_REQUEST_GET_MAX: {
+ uint_fast32_t min_interval, max_interval;
+ uint_fast8_t num_intervals = frm->uncompressed.bFrameIntervalType;
+ max_interval = num_intervals ? frm->uncompressed.dwFrameInterval[num_intervals - 1]: frm->uncompressed.dwFrameInterval[1];
+ min_interval = frm->uncompressed.dwFrameInterval[0];
+ interval = max_interval;
+ interval_ms = min_interval / 10000;
break;
- case VIDEO_REQUEST_GET_MIN:
- {
- uint_fast32_t min_interval, max_interval;
- uint_fast8_t num_intervals = frm->uncompressed.bFrameIntervalType;
- max_interval = num_intervals ? frm->uncompressed.dwFrameInterval[num_intervals - 1]: frm->uncompressed.dwFrameInterval[1];
- min_interval = frm->uncompressed.dwFrameInterval[0];
- interval = min_interval;
- interval_ms = max_interval / 10000;
- }
+ }
+
+ case VIDEO_REQUEST_GET_MIN: {
+ uint_fast32_t min_interval, max_interval;
+ uint_fast8_t num_intervals = frm->uncompressed.bFrameIntervalType;
+ max_interval = num_intervals ? frm->uncompressed.dwFrameInterval[num_intervals - 1]: frm->uncompressed.dwFrameInterval[1];
+ min_interval = frm->uncompressed.dwFrameInterval[0];
+ interval = min_interval;
+ interval_ms = max_interval / 10000;
break;
+ }
+
case VIDEO_REQUEST_GET_DEF:
interval = frm->uncompressed.dwDefaultFrameInterval;
interval_ms = interval / 10000;
break;
- case VIDEO_REQUEST_GET_RES:
- {
- uint_fast8_t num_intervals = frm->uncompressed.bFrameIntervalType;
- if (num_intervals) {
- interval = 0;
- interval_ms = 0;
- } else {
- interval = frm->uncompressed.dwFrameInterval[2];
- interval_ms = interval / 10000;
- }
+
+ case VIDEO_REQUEST_GET_RES: {
+ uint_fast8_t num_intervals = frm->uncompressed.bFrameIntervalType;
+ if (num_intervals) {
+ interval = 0;
+ interval_ms = 0;
+ } else {
+ interval = frm->uncompressed.dwFrameInterval[2];
+ interval_ms = interval / 10000;
}
break;
+ }
+
default: return false;
}
param->dwFrameInterval = interval;
@@ -676,13 +736,11 @@ static bool _open_vc_itf(uint8_t rhport, videod_interface_t *self, uint_fast8_t
return true;
}
-static bool _init_vs_configuration(videod_streaming_interface_t *stm)
-{
+static bool _init_vs_configuration(videod_streaming_interface_t *stm) {
/* initialize streaming settings */
stm->state = VS_STATE_PROBING;
stm->max_payload_transfer_size = 0;
- video_probe_and_commit_control_t *param =
- (video_probe_and_commit_control_t *)&stm->ep_buf;
+ video_probe_and_commit_control_t *param = &stm->probe_commit_payload;
tu_memclr(param, sizeof(*param));
return _update_streaming_parameters(stm, param);
}
@@ -759,6 +817,7 @@ static uint_fast16_t _prepare_in_payload(videod_streaming_interface_t *stm)
if (hdr_len + remaining < pkt_len) {
pkt_len = hdr_len + remaining;
}
+ TU_ASSERT(pkt_len >= hdr_len);
uint_fast16_t data_len = pkt_len - hdr_len;
memcpy(&stm->ep_buf[hdr_len], stm->buffer + stm->offset, data_len);
stm->offset += data_len;
@@ -775,6 +834,7 @@ static int handle_video_ctl_std_req(uint8_t rhport, uint8_t stage,
tusb_control_request_t const *request,
uint_fast8_t ctl_idx)
{
+ TU_LOG_DRV("\r\n");
switch (request->bRequest) {
case TUSB_REQ_GET_INTERFACE:
if (stage == CONTROL_STAGE_SETUP)
@@ -812,7 +872,10 @@ static int handle_video_ctl_cs_req(uint8_t rhport, uint8_t stage,
videod_interface_t *self = &_videod_itf[ctl_idx];
/* 4.2.1 Interface Control Request */
- switch (TU_U16_HIGH(request->wValue)) {
+ uint8_t const ctrl_sel = TU_U16_HIGH(request->wValue);
+ TU_LOG_DRV("%s_Control(%s)\r\n", tu_str_video_vc_control_selector[ctrl_sel], tu_lookup_find(&tu_table_video_request, request->bRequest));
+
+ switch (ctrl_sel) {
case VIDEO_VC_CTL_VIDEO_POWER_MODE:
switch (request->bRequest) {
case VIDEO_REQUEST_SET_CUR:
@@ -876,19 +939,19 @@ static int handle_video_ctl_req(uint8_t rhport, uint8_t stage,
tusb_control_request_t const *request,
uint_fast8_t ctl_idx)
{
- uint_fast8_t entity_id;
switch (request->bmRequestType_bit.type) {
case TUSB_REQ_TYPE_STANDARD:
return handle_video_ctl_std_req(rhport, stage, request, ctl_idx);
- case TUSB_REQ_TYPE_CLASS:
- entity_id = TU_U16_HIGH(request->wIndex);
+ case TUSB_REQ_TYPE_CLASS: {
+ uint_fast8_t entity_id = TU_U16_HIGH(request->wIndex);
if (!entity_id) {
return handle_video_ctl_cs_req(rhport, stage, request, ctl_idx);
} else {
TU_VERIFY(_find_desc_entity(_get_desc_vc(&_videod_itf[ctl_idx]), entity_id), VIDEO_ERROR_INVALID_REQUEST);
return VIDEO_ERROR_NONE;
}
+ }
default:
return VIDEO_ERROR_INVALID_REQUEST;
@@ -899,6 +962,7 @@ static int handle_video_stm_std_req(uint8_t rhport, uint8_t stage,
tusb_control_request_t const *request,
uint_fast8_t stm_idx)
{
+ TU_LOG_DRV("\r\n");
videod_streaming_interface_t *self = &_videod_streaming_itf[stm_idx];
switch (request->bRequest) {
case TUSB_REQ_GET_INTERFACE:
@@ -914,8 +978,7 @@ static int handle_video_stm_std_req(uint8_t rhport, uint8_t stage,
return VIDEO_ERROR_NONE;
case TUSB_REQ_SET_INTERFACE:
- if (stage == CONTROL_STAGE_SETUP)
- {
+ if (stage == CONTROL_STAGE_SETUP) {
TU_VERIFY(_open_vs_itf(rhport, self, request->wValue), VIDEO_ERROR_UNKNOWN);
tud_control_status(rhport, request);
}
@@ -929,26 +992,26 @@ static int handle_video_stm_std_req(uint8_t rhport, uint8_t stage,
static int handle_video_stm_cs_req(uint8_t rhport, uint8_t stage,
tusb_control_request_t const *request,
- uint_fast8_t stm_idx)
-{
+ uint_fast8_t stm_idx) {
(void)rhport;
videod_streaming_interface_t *self = &_videod_streaming_itf[stm_idx];
+ uint8_t const ctrl_sel = TU_U16_HIGH(request->wValue);
+ TU_LOG_DRV("%s_Control(%s)\r\n", tu_str_video_vs_control_selector[ctrl_sel], tu_lookup_find(&tu_table_video_request, request->bRequest));
+
/* 4.2.1 Interface Control Request */
- switch (TU_U16_HIGH(request->wValue)) {
+ switch (ctrl_sel) {
case VIDEO_VS_CTL_STREAM_ERROR_CODE:
switch (request->bRequest) {
case VIDEO_REQUEST_GET_CUR:
- if (stage == CONTROL_STAGE_SETUP)
- {
+ if (stage == CONTROL_STAGE_SETUP) {
/* TODO */
TU_VERIFY(tud_control_xfer(rhport, request, &self->error_code, sizeof(uint8_t)), VIDEO_ERROR_UNKNOWN);
}
return VIDEO_ERROR_NONE;
case VIDEO_REQUEST_GET_INFO:
- if (stage == CONTROL_STAGE_SETUP)
- {
+ if (stage == CONTROL_STAGE_SETUP) {
TU_VERIFY(tud_control_xfer(rhport, request, (uint8_t*)(uintptr_t) &_cap_get, sizeof(_cap_get)), VIDEO_ERROR_UNKNOWN);
}
return VIDEO_ERROR_NONE;
@@ -960,25 +1023,23 @@ static int handle_video_stm_cs_req(uint8_t rhport, uint8_t stage,
case VIDEO_VS_CTL_PROBE:
if (self->state != VS_STATE_PROBING) {
self->state = VS_STATE_PROBING;
- _init_vs_configuration(self);
}
+
switch (request->bRequest) {
case VIDEO_REQUEST_SET_CUR:
if (stage == CONTROL_STAGE_SETUP) {
- TU_VERIFY(sizeof(video_probe_and_commit_control_t) >= request->wLength, VIDEO_ERROR_UNKNOWN);
- TU_VERIFY(tud_control_xfer(rhport, request, self->ep_buf, sizeof(video_probe_and_commit_control_t)),
+ TU_VERIFY(tud_control_xfer(rhport, request, &self->probe_commit_payload, sizeof(video_probe_and_commit_control_t)),
VIDEO_ERROR_UNKNOWN);
} else if (stage == CONTROL_STAGE_DATA) {
- TU_VERIFY(_update_streaming_parameters(self, (video_probe_and_commit_control_t*)self->ep_buf),
+ TU_VERIFY(_update_streaming_parameters(self, &self->probe_commit_payload),
VIDEO_ERROR_INVALID_VALUE_WITHIN_RANGE);
}
return VIDEO_ERROR_NONE;
case VIDEO_REQUEST_GET_CUR:
- if (stage == CONTROL_STAGE_SETUP)
- {
+ if (stage == CONTROL_STAGE_SETUP) {
TU_VERIFY(request->wLength, VIDEO_ERROR_UNKNOWN);
- TU_VERIFY(tud_control_xfer(rhport, request, self->ep_buf, sizeof(video_probe_and_commit_control_t)), VIDEO_ERROR_UNKNOWN);
+ TU_VERIFY(tud_control_xfer(rhport, request, &self->probe_commit_payload, sizeof(video_probe_and_commit_control_t)), VIDEO_ERROR_UNKNOWN);
}
return VIDEO_ERROR_NONE;
@@ -986,19 +1047,16 @@ static int handle_video_stm_cs_req(uint8_t rhport, uint8_t stage,
case VIDEO_REQUEST_GET_MAX:
case VIDEO_REQUEST_GET_RES:
case VIDEO_REQUEST_GET_DEF:
- if (stage == CONTROL_STAGE_SETUP)
- {
+ if (stage == CONTROL_STAGE_SETUP) {
TU_VERIFY(request->wLength, VIDEO_ERROR_UNKNOWN);
- video_probe_and_commit_control_t tmp;
- tmp = *(video_probe_and_commit_control_t*)&self->ep_buf;
+ video_probe_and_commit_control_t tmp = self->probe_commit_payload;
TU_VERIFY(_negotiate_streaming_parameters(self, request->bRequest, &tmp), VIDEO_ERROR_INVALID_VALUE_WITHIN_RANGE);
TU_VERIFY(tud_control_xfer(rhport, request, &tmp, sizeof(tmp)), VIDEO_ERROR_UNKNOWN);
}
return VIDEO_ERROR_NONE;
case VIDEO_REQUEST_GET_LEN:
- if (stage == CONTROL_STAGE_SETUP)
- {
+ if (stage == CONTROL_STAGE_SETUP) {
TU_VERIFY(2 == request->wLength, VIDEO_ERROR_UNKNOWN);
uint16_t len = sizeof(video_probe_and_commit_control_t);
TU_VERIFY(tud_control_xfer(rhport, request, (uint8_t*)&len, sizeof(len)), VIDEO_ERROR_UNKNOWN);
@@ -1006,8 +1064,7 @@ static int handle_video_stm_cs_req(uint8_t rhport, uint8_t stage,
return VIDEO_ERROR_NONE;
case VIDEO_REQUEST_GET_INFO:
- if (stage == CONTROL_STAGE_SETUP)
- {
+ if (stage == CONTROL_STAGE_SETUP) {
TU_VERIFY(1 == request->wLength, VIDEO_ERROR_UNKNOWN);
TU_VERIFY(tud_control_xfer(rhport, request, (uint8_t*)(uintptr_t)&_cap_get_set, sizeof(_cap_get_set)), VIDEO_ERROR_UNKNOWN);
}
@@ -1021,10 +1078,9 @@ static int handle_video_stm_cs_req(uint8_t rhport, uint8_t stage,
switch (request->bRequest) {
case VIDEO_REQUEST_SET_CUR:
if (stage == CONTROL_STAGE_SETUP) {
- TU_VERIFY(sizeof(video_probe_and_commit_control_t) >= request->wLength, VIDEO_ERROR_UNKNOWN);
- TU_VERIFY(tud_control_xfer(rhport, request, self->ep_buf, sizeof(video_probe_and_commit_control_t)), VIDEO_ERROR_UNKNOWN);
+ TU_VERIFY(tud_control_xfer(rhport, request, &self->probe_commit_payload, sizeof(video_probe_and_commit_control_t)), VIDEO_ERROR_UNKNOWN);
} else if (stage == CONTROL_STAGE_DATA) {
- video_probe_and_commit_control_t *param = (video_probe_and_commit_control_t*)self->ep_buf;
+ video_probe_and_commit_control_t *param = &self->probe_commit_payload;
TU_VERIFY(_update_streaming_parameters(self, param), VIDEO_ERROR_INVALID_VALUE_WITHIN_RANGE);
/* Set the negotiated value */
self->max_payload_transfer_size = param->dwMaxPayloadTransferSize;
@@ -1046,16 +1102,14 @@ static int handle_video_stm_cs_req(uint8_t rhport, uint8_t stage,
return VIDEO_ERROR_NONE;
case VIDEO_REQUEST_GET_CUR:
- if (stage == CONTROL_STAGE_SETUP)
- {
+ if (stage == CONTROL_STAGE_SETUP) {
TU_VERIFY(request->wLength, VIDEO_ERROR_UNKNOWN);
- TU_VERIFY(tud_control_xfer(rhport, request, self->ep_buf, sizeof(video_probe_and_commit_control_t)), VIDEO_ERROR_UNKNOWN);
+ TU_VERIFY(tud_control_xfer(rhport, request, &self->probe_commit_payload, sizeof(video_probe_and_commit_control_t)), VIDEO_ERROR_UNKNOWN);
}
return VIDEO_ERROR_NONE;
case VIDEO_REQUEST_GET_LEN:
- if (stage == CONTROL_STAGE_SETUP)
- {
+ if (stage == CONTROL_STAGE_SETUP) {
TU_VERIFY(2 == request->wLength, VIDEO_ERROR_UNKNOWN);
uint16_t len = sizeof(video_probe_and_commit_control_t);
TU_VERIFY(tud_control_xfer(rhport, request, (uint8_t*)&len, sizeof(len)), VIDEO_ERROR_UNKNOWN);
@@ -1063,8 +1117,7 @@ static int handle_video_stm_cs_req(uint8_t rhport, uint8_t stage,
return VIDEO_ERROR_NONE;
case VIDEO_REQUEST_GET_INFO:
- if (stage == CONTROL_STAGE_SETUP)
- {
+ if (stage == CONTROL_STAGE_SETUP) {
TU_VERIFY(1 == request->wLength, VIDEO_ERROR_UNKNOWN);
TU_VERIFY(tud_control_xfer(rhport, request, (uint8_t*)(uintptr_t) &_cap_get_set, sizeof(_cap_get_set)), VIDEO_ERROR_UNKNOWN);
}
@@ -1165,8 +1218,7 @@ bool tud_video_n_frame_xfer(uint_fast8_t ctl_idx, uint_fast8_t stm_idx, void *bu
//--------------------------------------------------------------------+
// USBD Driver API
//--------------------------------------------------------------------+
-void videod_init(void)
-{
+void videod_init(void) {
for (uint_fast8_t i = 0; i < CFG_TUD_VIDEO; ++i) {
videod_interface_t* ctl = &_videod_itf[i];
tu_memclr(ctl, sizeof(*ctl));
@@ -1177,8 +1229,7 @@ void videod_init(void)
}
}
-void videod_reset(uint8_t rhport)
-{
+void videod_reset(uint8_t rhport) {
(void) rhport;
for (uint_fast8_t i = 0; i < CFG_TUD_VIDEO; ++i) {
videod_interface_t* ctl = &_videod_itf[i];
@@ -1190,8 +1241,7 @@ void videod_reset(uint8_t rhport)
}
}
-uint16_t videod_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len)
-{
+uint16_t videod_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len) {
TU_VERIFY((TUSB_CLASS_VIDEO == itf_desc->bInterfaceClass) &&
(VIDEO_SUBCLASS_CONTROL == itf_desc->bInterfaceSubClass) &&
(VIDEO_ITF_PROTOCOL_15 == itf_desc->bInterfaceProtocol), 0);
@@ -1250,8 +1300,7 @@ uint16_t videod_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uin
// Invoked when a control transfer occurred on an interface of this class
// Driver response accordingly to the request and the transfer stage (setup/data/ack)
// return false to stall control endpoint (e.g unsupported request)
-bool videod_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request)
-{
+bool videod_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request) {
int err;
TU_VERIFY(request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_INTERFACE);
uint_fast8_t itfnum = tu_u16_low(request->wIndex);
@@ -1264,6 +1313,7 @@ bool videod_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_
}
if (itf < CFG_TUD_VIDEO) {
+ TU_LOG_DRV(" VC[%d]: ", itf);
err = handle_video_ctl_req(rhport, stage, request, itf);
_videod_itf[itf].error_code = (uint8_t)err;
if (err) return false;
@@ -1279,6 +1329,7 @@ bool videod_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_
}
if (itf < CFG_TUD_VIDEO_STREAMING) {
+ TU_LOG_DRV(" VS[%d]: ", itf);
err = handle_video_stm_req(rhport, stage, request, itf);
_videod_streaming_itf[itf].error_code = (uint8_t)err;
if (err) return false;
@@ -1287,8 +1338,7 @@ bool videod_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_
return false;
}
-bool videod_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes)
-{
+bool videod_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) {
(void)result; (void)xferred_bytes;
/* find streaming handle */
diff --git a/src/common/tusb_fifo.h b/src/common/tusb_fifo.h
index 2f60ec2f4..2d9f5e667 100644
--- a/src/common/tusb_fifo.h
+++ b/src/common/tusb_fifo.h
@@ -102,10 +102,8 @@ extern "C" {
* |
* -------------------------
* | R | 1 | 2 | W | 4 | 5 |
-
*/
-typedef struct
-{
+typedef struct {
uint8_t* buffer ; // buffer pointer
uint16_t depth ; // max items
@@ -124,16 +122,14 @@ typedef struct
} tu_fifo_t;
-typedef struct
-{
+typedef struct {
uint16_t len_lin ; ///< linear length in item size
uint16_t len_wrap ; ///< wrapped length in item size
void * ptr_lin ; ///< linear part start pointer
void * ptr_wrap ; ///< wrapped part start pointer
} tu_fifo_buffer_info_t;
-#define TU_FIFO_INIT(_buffer, _depth, _type, _overwritable) \
-{ \
+#define TU_FIFO_INIT(_buffer, _depth, _type, _overwritable){\
.buffer = _buffer, \
.depth = _depth, \
.item_size = sizeof(_type), \
@@ -144,23 +140,18 @@ typedef struct
uint8_t _name##_buf[_depth*sizeof(_type)]; \
tu_fifo_t _name = TU_FIFO_INIT(_name##_buf, _depth, _type, _overwritable)
-
bool tu_fifo_set_overwritable(tu_fifo_t *f, bool overwritable);
bool tu_fifo_clear(tu_fifo_t *f);
bool tu_fifo_config(tu_fifo_t *f, void* buffer, uint16_t depth, uint16_t item_size, bool overwritable);
#if OSAL_MUTEX_REQUIRED
-TU_ATTR_ALWAYS_INLINE static inline
-void tu_fifo_config_mutex(tu_fifo_t *f, osal_mutex_t wr_mutex, osal_mutex_t rd_mutex)
-{
- f->mutex_wr = wr_mutex;
- f->mutex_rd = rd_mutex;
-}
-
+ TU_ATTR_ALWAYS_INLINE static inline
+ void tu_fifo_config_mutex(tu_fifo_t *f, osal_mutex_t wr_mutex, osal_mutex_t rd_mutex) {
+ f->mutex_wr = wr_mutex;
+ f->mutex_rd = rd_mutex;
+ }
#else
-
-#define tu_fifo_config_mutex(_f, _wr_mutex, _rd_mutex)
-
+ #define tu_fifo_config_mutex(_f, _wr_mutex, _rd_mutex)
#endif
bool tu_fifo_write (tu_fifo_t* f, void const * p_data);
@@ -182,8 +173,7 @@ bool tu_fifo_overflowed (tu_fifo_t* f);
void tu_fifo_correct_read_pointer (tu_fifo_t* f);
TU_ATTR_ALWAYS_INLINE static inline
-uint16_t tu_fifo_depth(tu_fifo_t* f)
-{
+uint16_t tu_fifo_depth(tu_fifo_t* f) {
return f->depth;
}
@@ -198,7 +188,6 @@ void tu_fifo_advance_read_pointer (tu_fifo_t *f, uint16_t n);
void tu_fifo_get_read_info (tu_fifo_t *f, tu_fifo_buffer_info_t *info);
void tu_fifo_get_write_info(tu_fifo_t *f, tu_fifo_buffer_info_t *info);
-
#ifdef __cplusplus
}
#endif
diff --git a/src/common/tusb_private.h b/src/common/tusb_private.h
index db1ba974d..373a50256 100644
--- a/src/common/tusb_private.h
+++ b/src/common/tusb_private.h
@@ -60,7 +60,7 @@ typedef struct {
tu_fifo_t ff;
// mutex: read if ep rx, write if e tx
- OSAL_MUTEX_DEF(ff_mutex);
+ OSAL_MUTEX_DEF(ff_mutexdef);
}tu_edpt_stream_t;
@@ -87,15 +87,17 @@ bool tu_edpt_release(tu_edpt_state_t* ep_state, osal_mutex_t mutex);
// Endpoint Stream
//--------------------------------------------------------------------+
-// Init an stream, should only be called once
+// Init an endpoint stream
bool tu_edpt_stream_init(tu_edpt_stream_t* s, bool is_host, bool is_tx, bool overwritable,
void* ff_buf, uint16_t ff_bufsize, uint8_t* ep_buf, uint16_t ep_bufsize);
+// Deinit an endpoint stream
+bool tu_edpt_stream_deinit(tu_edpt_stream_t* s);
+
// Open an stream for an endpoint
// hwid is either device address (host mode) or rhport (device mode)
TU_ATTR_ALWAYS_INLINE static inline
-void tu_edpt_stream_open(tu_edpt_stream_t* s, uint8_t hwid, tusb_desc_endpoint_t const *desc_ep)
-{
+void tu_edpt_stream_open(tu_edpt_stream_t* s, uint8_t hwid, tusb_desc_endpoint_t const *desc_ep) {
tu_fifo_clear(&s->ff);
s->hwid = hwid;
s->ep_addr = desc_ep->bEndpointAddress;
@@ -103,16 +105,14 @@ void tu_edpt_stream_open(tu_edpt_stream_t* s, uint8_t hwid, tusb_desc_endpoint_t
}
TU_ATTR_ALWAYS_INLINE static inline
-void tu_edpt_stream_close(tu_edpt_stream_t* s)
-{
+void tu_edpt_stream_close(tu_edpt_stream_t* s) {
s->hwid = 0;
s->ep_addr = 0;
}
// Clear fifo
TU_ATTR_ALWAYS_INLINE static inline
-bool tu_edpt_stream_clear(tu_edpt_stream_t* s)
-{
+bool tu_edpt_stream_clear(tu_edpt_stream_t* s) {
return tu_fifo_clear(&s->ff);
}
@@ -131,8 +131,7 @@ bool tu_edpt_stream_write_zlp_if_needed(tu_edpt_stream_t* s, uint32_t last_xferr
// Get the number of bytes available for writing
TU_ATTR_ALWAYS_INLINE static inline
-uint32_t tu_edpt_stream_write_available(tu_edpt_stream_t* s)
-{
+uint32_t tu_edpt_stream_write_available(tu_edpt_stream_t* s) {
return (uint32_t) tu_fifo_remaining(&s->ff);
}
diff --git a/src/device/usbd.c b/src/device/usbd.c
index ab572e095..96d0b698b 100644
--- a/src/device/usbd.c
+++ b/src/device/usbd.c
@@ -319,7 +319,7 @@ void usbd_driver_print_control_complete_name(usbd_control_xfer_cb_t callback) {
for (uint8_t i = 0; i < TOTAL_DRIVER_COUNT; i++) {
usbd_class_driver_t const* driver = get_driver(i);
if (driver && driver->control_xfer_cb == callback) {
- TU_LOG_USBD(" %s control complete\r\n", driver->name);
+ TU_LOG_USBD("%s control complete\r\n", driver->name);
return;
}
}
diff --git a/src/device/usbd.h b/src/device/usbd.h
index 3ab6c813f..2e3987b99 100644
--- a/src/device/usbd.h
+++ b/src/device/usbd.h
@@ -393,6 +393,11 @@ TU_ATTR_WEAK bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb
// For more channels, add definitions here
+/* Standard AC Interrupt Endpoint Descriptor(4.8.2.1) */
+#define TUD_AUDIO_DESC_STD_AC_INT_EP_LEN 7
+#define TUD_AUDIO_DESC_STD_AC_INT_EP(_ep, _interval) \
+ TUD_AUDIO_DESC_STD_AC_INT_EP_LEN, TUSB_DESC_ENDPOINT, _ep, TUSB_XFER_INTERRUPT, U16_TO_U8S_LE(6), _interval
+
/* Standard AS Interface Descriptor(4.9.1) */
#define TUD_AUDIO_DESC_STD_AS_INT_LEN 9
#define TUD_AUDIO_DESC_STD_AS_INT(_itfnum, _altset, _nEPs, _stridx) \
@@ -421,7 +426,7 @@ TU_ATTR_WEAK bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb
/* Standard AS Isochronous Feedback Endpoint Descriptor(4.10.2.1) */
#define TUD_AUDIO_DESC_STD_AS_ISO_FB_EP_LEN 7
#define TUD_AUDIO_DESC_STD_AS_ISO_FB_EP(_ep, _interval) \
- TUD_AUDIO_DESC_STD_AS_ISO_FB_EP_LEN, TUSB_DESC_ENDPOINT, _ep, (uint8_t) (TUSB_XFER_ISOCHRONOUS | TUSB_ISO_EP_ATT_NO_SYNC | TUSB_ISO_EP_ATT_EXPLICIT_FB), U16_TO_U8S_LE(4), _interval
+ TUD_AUDIO_DESC_STD_AS_ISO_FB_EP_LEN, TUSB_DESC_ENDPOINT, _ep, (uint8_t) ((uint8_t)TUSB_XFER_ISOCHRONOUS | (uint8_t)TUSB_ISO_EP_ATT_NO_SYNC | (uint8_t)TUSB_ISO_EP_ATT_EXPLICIT_FB), U16_TO_U8S_LE(4), _interval
// AUDIO simple descriptor (UAC2) for 1 microphone input
// - 1 Input Terminal, 1 Feature Unit (Mute and Volume Control), 1 Output Terminal, 1 Clock Source
@@ -468,7 +473,7 @@ TU_ATTR_WEAK bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb
/* Type I Format Type Descriptor(2.3.1.6 - Audio Formats) */\
TUD_AUDIO_DESC_TYPE_I_FORMAT(_nBytesPerSample, _nBitsUsedPerSample),\
/* Standard AS Isochronous Audio Data Endpoint Descriptor(4.10.1.1) */\
- TUD_AUDIO_DESC_STD_AS_ISO_EP(/*_ep*/ _epin, /*_attr*/ (uint8_t) (TUSB_XFER_ISOCHRONOUS | TUSB_ISO_EP_ATT_ASYNCHRONOUS | TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ _epsize, /*_interval*/ 0x01),\
+ TUD_AUDIO_DESC_STD_AS_ISO_EP(/*_ep*/ _epin, /*_attr*/ (uint8_t) ((uint8_t)TUSB_XFER_ISOCHRONOUS | (uint8_t)TUSB_ISO_EP_ATT_ASYNCHRONOUS | (uint8_t)TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ _epsize, /*_interval*/ 0x01),\
/* Class-Specific AS Isochronous Audio Data Endpoint Descriptor(4.10.1.2) */\
TUD_AUDIO_DESC_CS_AS_ISO_EP(/*_attr*/ AUDIO_CS_AS_ISO_DATA_EP_ATT_NON_MAX_PACKETS_OK, /*_ctrl*/ AUDIO_CTRL_NONE, /*_lockdelayunit*/ AUDIO_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_UNDEFINED, /*_lockdelay*/ 0x0000)
@@ -517,7 +522,7 @@ TU_ATTR_WEAK bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb
/* Type I Format Type Descriptor(2.3.1.6 - Audio Formats) */\
TUD_AUDIO_DESC_TYPE_I_FORMAT(_nBytesPerSample, _nBitsUsedPerSample),\
/* Standard AS Isochronous Audio Data Endpoint Descriptor(4.10.1.1) */\
- TUD_AUDIO_DESC_STD_AS_ISO_EP(/*_ep*/ _epin, /*_attr*/ (uint8_t) (TUSB_XFER_ISOCHRONOUS | TUSB_ISO_EP_ATT_ASYNCHRONOUS | TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ _epsize, /*_interval*/ 0x01),\
+ TUD_AUDIO_DESC_STD_AS_ISO_EP(/*_ep*/ _epin, /*_attr*/ (uint8_t) ((uint8_t)TUSB_XFER_ISOCHRONOUS | (uint8_t)TUSB_ISO_EP_ATT_ASYNCHRONOUS | (uint8_t)TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ _epsize, /*_interval*/ 0x01),\
/* Class-Specific AS Isochronous Audio Data Endpoint Descriptor(4.10.1.2) */\
TUD_AUDIO_DESC_CS_AS_ISO_EP(/*_attr*/ AUDIO_CS_AS_ISO_DATA_EP_ATT_NON_MAX_PACKETS_OK, /*_ctrl*/ AUDIO_CTRL_NONE, /*_lockdelayunit*/ AUDIO_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_UNDEFINED, /*_lockdelay*/ 0x0000)
@@ -565,7 +570,7 @@ TU_ATTR_WEAK bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb
/* Type I Format Type Descriptor(2.3.1.6 - Audio Formats) */\
TUD_AUDIO_DESC_TYPE_I_FORMAT(_nBytesPerSample, _nBitsUsedPerSample),\
/* Standard AS Isochronous Audio Data Endpoint Descriptor(4.10.1.1) */\
- TUD_AUDIO_DESC_STD_AS_ISO_EP(/*_ep*/ _epout, /*_attr*/ (uint8_t) (TUSB_XFER_ISOCHRONOUS | TUSB_ISO_EP_ATT_ASYNCHRONOUS | TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ _epsize, /*_interval*/ 0x01),\
+ TUD_AUDIO_DESC_STD_AS_ISO_EP(/*_ep*/ _epout, /*_attr*/ (uint8_t) ((uint8_t)TUSB_XFER_ISOCHRONOUS | (uint8_t)TUSB_ISO_EP_ATT_ASYNCHRONOUS | (uint8_t)TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ _epsize, /*_interval*/ 0x01),\
/* Class-Specific AS Isochronous Audio Data Endpoint Descriptor(4.10.1.2) */\
TUD_AUDIO_DESC_CS_AS_ISO_EP(/*_attr*/ AUDIO_CS_AS_ISO_DATA_EP_ATT_NON_MAX_PACKETS_OK, /*_ctrl*/ AUDIO_CTRL_NONE, /*_lockdelayunit*/ AUDIO_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_UNDEFINED, /*_lockdelay*/ 0x0000),\
/* Standard AS Isochronous Feedback Endpoint Descriptor(4.10.2.1) */\
diff --git a/src/host/hcd.h b/src/host/hcd.h
index 2bde289df..5547c7cc5 100644
--- a/src/host/hcd.h
+++ b/src/host/hcd.h
@@ -125,11 +125,14 @@ bool hcd_dcache_clean_invalidate(void const* addr, uint32_t data_size) TU_ATTR_W
//--------------------------------------------------------------------+
// optional hcd configuration, called by tuh_configure()
-bool hcd_configure(uint8_t rhport, uint32_t cfg_id, const void* cfg_param) TU_ATTR_WEAK;
+bool hcd_configure(uint8_t rhport, uint32_t cfg_id, const void* cfg_param);
// Initialize controller to host mode
bool hcd_init(uint8_t rhport);
+// De-initialize controller
+bool hcd_deinit(uint8_t rhport);
+
// Interrupt Handler
void hcd_int_handler(uint8_t rhport, bool in_isr);
diff --git a/src/host/hub.c b/src/host/hub.c
index 3bac18698..e97014443 100644
--- a/src/host/hub.c
+++ b/src/host/hub.c
@@ -182,9 +182,13 @@ bool hub_port_get_status(uint8_t hub_addr, uint8_t hub_port, void* resp,
//--------------------------------------------------------------------+
// CLASS-USBH API (don't require to verify parameters)
//--------------------------------------------------------------------+
-void hub_init(void)
-{
+bool hub_init(void) {
tu_memclr(hub_data, sizeof(hub_data));
+ return true;
+}
+
+bool hub_deinit(void) {
+ return true;
}
bool hub_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *itf_desc, uint16_t max_len)
diff --git a/src/host/hub.h b/src/host/hub.h
index 390740e1f..385efe6b2 100644
--- a/src/host/hub.h
+++ b/src/host/hub.h
@@ -187,16 +187,14 @@ bool hub_port_get_status (uint8_t hub_addr, uint8_t hub_port, void* resp,
bool hub_edpt_status_xfer(uint8_t dev_addr);
// Reset a port
-static inline bool hub_port_reset(uint8_t hub_addr, uint8_t hub_port,
- tuh_xfer_cb_t complete_cb, uintptr_t user_data)
-{
+TU_ATTR_ALWAYS_INLINE static inline
+bool hub_port_reset(uint8_t hub_addr, uint8_t hub_port, tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
return hub_port_set_feature(hub_addr, hub_port, HUB_FEATURE_PORT_RESET, complete_cb, user_data);
}
// Clear Reset Change
-static inline bool hub_port_clear_reset_change(uint8_t hub_addr, uint8_t hub_port,
- tuh_xfer_cb_t complete_cb, uintptr_t user_data)
-{
+TU_ATTR_ALWAYS_INLINE static inline
+bool hub_port_clear_reset_change(uint8_t hub_addr, uint8_t hub_port, tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
return hub_port_clear_feature(hub_addr, hub_port, HUB_FEATURE_PORT_RESET_CHANGE, complete_cb, user_data);
}
@@ -204,7 +202,8 @@ static inline bool hub_port_clear_reset_change(uint8_t hub_addr, uint8_t hub_por
//--------------------------------------------------------------------+
// Internal Class Driver API
//--------------------------------------------------------------------+
-void hub_init (void);
+bool hub_init (void);
+bool hub_deinit (void);
bool hub_open (uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *itf_desc, uint16_t max_len);
bool hub_set_config (uint8_t dev_addr, uint8_t itf_num);
bool hub_xfer_cb (uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes);
diff --git a/src/host/usbh.c b/src/host/usbh.c
index 625857683..aa0603d47 100644
--- a/src/host/usbh.c
+++ b/src/host/usbh.c
@@ -45,8 +45,20 @@
#endif
//--------------------------------------------------------------------+
-// Callback weak stubs (called if application does not provide)
+// Weak stubs: invoked if no strong implementation is available
//--------------------------------------------------------------------+
+TU_ATTR_WEAK bool hcd_deinit(uint8_t rhport) {
+ (void) rhport;
+ return false;
+}
+
+TU_ATTR_WEAK bool hcd_configure(uint8_t rhport, uint32_t cfg_id, const void* cfg_param) {
+ (void) rhport;
+ (void) cfg_id;
+ (void) cfg_param;
+ return false;
+}
+
TU_ATTR_WEAK void tuh_event_hook_cb(uint8_t rhport, uint32_t eventid, bool in_isr) {
(void) rhport;
(void) eventid;
@@ -119,16 +131,17 @@ typedef struct {
// MACRO CONSTANT TYPEDEF
//--------------------------------------------------------------------+
#if CFG_TUSB_DEBUG >= CFG_TUH_LOG_LEVEL
- #define DRIVER_NAME(_name) .name = _name,
+ #define DRIVER_NAME(_name) _name
#else
- #define DRIVER_NAME(_name)
+ #define DRIVER_NAME(_name) NULL
#endif
static usbh_class_driver_t const usbh_class_drivers[] = {
#if CFG_TUH_CDC
{
- DRIVER_NAME("CDC")
+ .name = DRIVER_NAME("CDC"),
.init = cdch_init,
+ .deinit = cdch_deinit,
.open = cdch_open,
.set_config = cdch_set_config,
.xfer_cb = cdch_xfer_cb,
@@ -138,8 +151,9 @@ static usbh_class_driver_t const usbh_class_drivers[] = {
#if CFG_TUH_MSC
{
- DRIVER_NAME("MSC")
+ .name = DRIVER_NAME("MSC"),
.init = msch_init,
+ .deinit = msch_deinit,
.open = msch_open,
.set_config = msch_set_config,
.xfer_cb = msch_xfer_cb,
@@ -149,8 +163,9 @@ static usbh_class_driver_t const usbh_class_drivers[] = {
#if CFG_TUH_HID
{
- DRIVER_NAME("HID")
+ .name = DRIVER_NAME("HID"),
.init = hidh_init,
+ .deinit = hidh_deinit,
.open = hidh_open,
.set_config = hidh_set_config,
.xfer_cb = hidh_xfer_cb,
@@ -160,8 +175,9 @@ static usbh_class_driver_t const usbh_class_drivers[] = {
#if CFG_TUH_HUB
{
- DRIVER_NAME("HUB")
+ .name = DRIVER_NAME("HUB"),
.init = hub_init,
+ .deinit = hub_deinit,
.open = hub_open,
.set_config = hub_set_config,
.xfer_cb = hub_xfer_cb,
@@ -171,9 +187,11 @@ static usbh_class_driver_t const usbh_class_drivers[] = {
#if CFG_TUH_VENDOR
{
- DRIVER_NAME("VENDOR")
+ .name = DRIVER_NAME("VENDOR"),
.init = cush_init,
- .open = cush_open_subtask,
+ .deinit = cush_deinit,
+ .open = cush_open,
+ .set_config = cush_set_config,
.xfer_cb = cush_isr,
.close = cush_close
}
@@ -321,11 +339,7 @@ bool tuh_rhport_reset_bus(uint8_t rhport, bool active) {
//--------------------------------------------------------------------+
bool tuh_configure(uint8_t rhport, uint32_t cfg_id, const void *cfg_param) {
- if ( hcd_configure ) {
- return hcd_configure(rhport, cfg_id, cfg_param);
- } else {
- return false;
- }
+ return hcd_configure(rhport, cfg_id, cfg_param);
}
static void clear_device(usbh_device_t* dev) {
@@ -338,55 +352,94 @@ bool tuh_inited(void) {
return _usbh_controller != TUSB_INDEX_INVALID_8;
}
-bool tuh_init(uint8_t controller_id) {
+bool tuh_init(uint8_t rhport) {
// skip if already initialized
- if ( tuh_inited() ) return true;
+ if (tuh_rhport_is_active(rhport)) return true;
+
+ TU_LOG_USBH("USBH init on controller %u\r\n", rhport);
- TU_LOG_USBH("USBH init on controller %u\r\n", controller_id);
- TU_LOG_INT_USBH(sizeof(usbh_device_t));
- TU_LOG_INT_USBH(sizeof(hcd_event_t));
- TU_LOG_INT_USBH(sizeof(_ctrl_xfer));
- TU_LOG_INT_USBH(sizeof(tuh_xfer_t));
- TU_LOG_INT_USBH(sizeof(tu_fifo_t));
- TU_LOG_INT_USBH(sizeof(tu_edpt_stream_t));
+ // Init host stack if not already
+ if (!tuh_inited()) {
+ TU_LOG_INT_USBH(sizeof(usbh_device_t));
+ TU_LOG_INT_USBH(sizeof(hcd_event_t));
+ TU_LOG_INT_USBH(sizeof(_ctrl_xfer));
+ TU_LOG_INT_USBH(sizeof(tuh_xfer_t));
+ TU_LOG_INT_USBH(sizeof(tu_fifo_t));
+ TU_LOG_INT_USBH(sizeof(tu_edpt_stream_t));
- // Event queue
- _usbh_q = osal_queue_create( &_usbh_qdef );
- TU_ASSERT(_usbh_q != NULL);
+ // Event queue
+ _usbh_q = osal_queue_create(&_usbh_qdef);
+ TU_ASSERT(_usbh_q != NULL);
#if OSAL_MUTEX_REQUIRED
- // Init mutex
- _usbh_mutex = osal_mutex_create(&_usbh_mutexdef);
- TU_ASSERT(_usbh_mutex);
+ // Init mutex
+ _usbh_mutex = osal_mutex_create(&_usbh_mutexdef);
+ TU_ASSERT(_usbh_mutex);
#endif
- // Get application driver if available
- if ( usbh_app_driver_get_cb ) {
- _app_driver = usbh_app_driver_get_cb(&_app_driver_count);
- }
+ // Get application driver if available
+ if (usbh_app_driver_get_cb) {
+ _app_driver = usbh_app_driver_get_cb(&_app_driver_count);
+ }
- // Device
- tu_memclr(&_dev0, sizeof(_dev0));
- tu_memclr(_usbh_devices, sizeof(_usbh_devices));
- tu_memclr(&_ctrl_xfer, sizeof(_ctrl_xfer));
+ // Device
+ tu_memclr(&_dev0, sizeof(_dev0));
+ tu_memclr(_usbh_devices, sizeof(_usbh_devices));
+ tu_memclr(&_ctrl_xfer, sizeof(_ctrl_xfer));
- for(uint8_t i=0; i<TOTAL_DEVICES; i++) {
- clear_device(&_usbh_devices[i]);
- }
+ for (uint8_t i = 0; i < TOTAL_DEVICES; i++) {
+ clear_device(&_usbh_devices[i]);
+ }
- // Class drivers
- for (uint8_t drv_id = 0; drv_id < TOTAL_DRIVER_COUNT; drv_id++) {
- usbh_class_driver_t const* driver = get_driver(drv_id);
- if (driver) {
- TU_LOG_USBH("%s init\r\n", driver->name);
- driver->init();
+ // Class drivers
+ for (uint8_t drv_id = 0; drv_id < TOTAL_DRIVER_COUNT; drv_id++) {
+ usbh_class_driver_t const* driver = get_driver(drv_id);
+ if (driver) {
+ TU_LOG_USBH("%s init\r\n", driver->name);
+ driver->init();
+ }
}
}
- _usbh_controller = controller_id;;
+ // Init host controller
+ _usbh_controller = rhport;;
+ TU_ASSERT(hcd_init(rhport));
+ hcd_int_enable(rhport);
+
+ return true;
+}
+
+bool tuh_deinit(uint8_t rhport) {
+ if (!tuh_rhport_is_active(rhport)) return true;
+
+ // deinit host controller
+ hcd_int_disable(rhport);
+ hcd_deinit(rhport);
+ _usbh_controller = TUSB_INDEX_INVALID_8;
+
+ // "unplug" all devices on this rhport (hub_addr = 0, hub_port = 0)
+ process_removing_device(rhport, 0, 0);
+
+ // deinit host stack if no controller is active
+ if (!tuh_inited()) {
+ // Class drivers
+ for (uint8_t drv_id = 0; drv_id < TOTAL_DRIVER_COUNT; drv_id++) {
+ usbh_class_driver_t const* driver = get_driver(drv_id);
+ if (driver) {
+ TU_LOG_USBH("%s deinit\r\n", driver->name);
+ driver->deinit();
+ }
+ }
+
+ osal_queue_delete(_usbh_q);
+ _usbh_q = NULL;
- TU_ASSERT(hcd_init(controller_id));
- hcd_int_enable(controller_id);
+ #if OSAL_MUTEX_REQUIRED
+ // TODO make sure there is no task waiting on this mutex
+ osal_mutex_delete(_usbh_mutex);
+ _usbh_mutex = NULL;
+ #endif
+ }
return true;
}
@@ -1090,43 +1143,42 @@ bool tuh_interface_set(uint8_t daddr, uint8_t itf_num, uint8_t itf_alt,
TU_VERIFY(_async_func(__VA_ARGS__, NULL, (uintptr_t) &result), XFER_RESULT_TIMEOUT); \
return (uint8_t) result
-uint8_t tuh_descriptor_get_sync(uint8_t daddr, uint8_t type, uint8_t index, void* buffer, uint16_t len)
-{
+uint8_t tuh_descriptor_get_sync(uint8_t daddr, uint8_t type, uint8_t index,
+ void* buffer, uint16_t len) {
_CONTROL_SYNC_API(tuh_descriptor_get, daddr, type, index, buffer, len);
}
-uint8_t tuh_descriptor_get_device_sync(uint8_t daddr, void* buffer, uint16_t len)
-{
+uint8_t tuh_descriptor_get_device_sync(uint8_t daddr, void* buffer, uint16_t len) {
_CONTROL_SYNC_API(tuh_descriptor_get_device, daddr, buffer, len);
}
-uint8_t tuh_descriptor_get_configuration_sync(uint8_t daddr, uint8_t index, void* buffer, uint16_t len)
-{
+uint8_t tuh_descriptor_get_configuration_sync(uint8_t daddr, uint8_t index,
+ void* buffer, uint16_t len) {
_CONTROL_SYNC_API(tuh_descriptor_get_configuration, daddr, index, buffer, len);
}
-uint8_t tuh_descriptor_get_hid_report_sync(uint8_t daddr, uint8_t itf_num, uint8_t desc_type, uint8_t index, void* buffer, uint16_t len)
-{
+uint8_t tuh_descriptor_get_hid_report_sync(uint8_t daddr, uint8_t itf_num, uint8_t desc_type, uint8_t index,
+ void* buffer, uint16_t len) {
_CONTROL_SYNC_API(tuh_descriptor_get_hid_report, daddr, itf_num, desc_type, index, buffer, len);
}
-uint8_t tuh_descriptor_get_string_sync(uint8_t daddr, uint8_t index, uint16_t language_id, void* buffer, uint16_t len)
-{
+uint8_t tuh_descriptor_get_string_sync(uint8_t daddr, uint8_t index, uint16_t language_id,
+ void* buffer, uint16_t len) {
_CONTROL_SYNC_API(tuh_descriptor_get_string, daddr, index, language_id, buffer, len);
}
-uint8_t tuh_descriptor_get_manufacturer_string_sync(uint8_t daddr, uint16_t language_id, void* buffer, uint16_t len)
-{
+uint8_t tuh_descriptor_get_manufacturer_string_sync(uint8_t daddr, uint16_t language_id,
+ void* buffer, uint16_t len) {
_CONTROL_SYNC_API(tuh_descriptor_get_manufacturer_string, daddr, language_id, buffer, len);
}
-uint8_t tuh_descriptor_get_product_string_sync(uint8_t daddr, uint16_t language_id, void* buffer, uint16_t len)
-{
+uint8_t tuh_descriptor_get_product_string_sync(uint8_t daddr, uint16_t language_id,
+ void* buffer, uint16_t len) {
_CONTROL_SYNC_API(tuh_descriptor_get_product_string, daddr, language_id, buffer, len);
}
-uint8_t tuh_descriptor_get_serial_string_sync(uint8_t daddr, uint16_t language_id, void* buffer, uint16_t len)
-{
+uint8_t tuh_descriptor_get_serial_string_sync(uint8_t daddr, uint16_t language_id,
+ void* buffer, uint16_t len) {
_CONTROL_SYNC_API(tuh_descriptor_get_serial_string, daddr, language_id, buffer, len);
}
@@ -1162,57 +1214,60 @@ TU_ATTR_ALWAYS_INLINE static inline bool is_hub_addr(uint8_t daddr) {
static void process_removing_device(uint8_t rhport, uint8_t hub_addr, uint8_t hub_port) {
//------------- find the all devices (star-network) under port that is unplugged -------------//
// TODO mark as disconnected in ISR, also handle dev0
+ uint32_t removing_hubs = 0;
+ do {
+ for (uint8_t dev_id = 0; dev_id < TOTAL_DEVICES; dev_id++) {
+ usbh_device_t* dev = &_usbh_devices[dev_id];
+ uint8_t const daddr = dev_id + 1;
-#if 0
- // index as hub addr, value is hub port (0xFF for invalid)
- uint8_t removing_hubs[CFG_TUH_HUB];
- memset(removing_hubs, TUSB_INDEX_INVALID_8, sizeof(removing_hubs));
-
- removing_hubs[hub_addr-CFG_TUH_DEVICE_MAX] = hub_port;
+ // hub_addr = 0 means roothub, hub_port = 0 means all devices of downstream hub
+ if (dev->rhport == rhport && dev->connected &&
+ (hub_addr == 0 || dev->hub_addr == hub_addr) &&
+ (hub_port == 0 || dev->hub_port == hub_port)) {
+ TU_LOG_USBH("[%u:%u:%u] unplugged address = %u\r\n", rhport, hub_addr, hub_port, daddr);
- // consecutive non-removing hub
- uint8_t nop_count = 0;
-#endif
+ if (is_hub_addr(daddr)) {
+ TU_LOG_USBH(" is a HUB device %u\r\n", daddr);
+ removing_hubs |= TU_BIT(dev_id - CFG_TUH_DEVICE_MAX);
+ } else {
+ // Invoke callback before closing driver (maybe call it later ?)
+ if (tuh_umount_cb) tuh_umount_cb(daddr);
+ }
- for (uint8_t dev_id = 0; dev_id < TOTAL_DEVICES; dev_id++) {
- usbh_device_t *dev = &_usbh_devices[dev_id];
- uint8_t const daddr = dev_id + 1;
+ // Close class driver
+ for (uint8_t drv_id = 0; drv_id < TOTAL_DRIVER_COUNT; drv_id++) {
+ usbh_class_driver_t const* driver = get_driver(drv_id);
+ if (driver) driver->close(daddr);
+ }
- // hub_addr = 0 means roothub, hub_port = 0 means all devices of downstream hub
- if (dev->rhport == rhport && dev->connected &&
- (hub_addr == 0 || dev->hub_addr == hub_addr) &&
- (hub_port == 0 || dev->hub_port == hub_port)) {
- TU_LOG_USBH("Device unplugged address = %u\r\n", daddr);
+ hcd_device_close(rhport, daddr);
+ clear_device(dev);
- if (is_hub_addr(daddr)) {
- TU_LOG_USBH(" is a HUB device %u\r\n", daddr);
+ // abort on-going control xfer on this device if any
+ if (_ctrl_xfer.daddr == daddr) _set_control_xfer_stage(CONTROL_STAGE_IDLE);
+ }
+ }
- // Submit removed event If the device itself is a hub (un-rolled recursive)
- // TODO a better to unroll recursrive is using array of removing_hubs and mark it here
- hcd_event_t event;
- event.rhport = rhport;
- event.event_id = HCD_EVENT_DEVICE_REMOVE;
- event.connection.hub_addr = daddr;
- event.connection.hub_port = 0;
+ // if removing a hub, we need to remove its downstream devices
+ #if CFG_TUH_HUB
+ if (removing_hubs == 0) break;
- hcd_event_handler(&event, false);
- } else {
- // Invoke callback before closing driver (maybe call it later ?)
- if (tuh_umount_cb) tuh_umount_cb(daddr);
- }
+ // find a marked hub to process
+ for (uint8_t h_id = 0; h_id < CFG_TUH_HUB; h_id++) {
+ if (tu_bit_test(removing_hubs, h_id)) {
+ removing_hubs &= ~TU_BIT(h_id);
- // Close class driver
- for (uint8_t drv_id = 0; drv_id < TOTAL_DRIVER_COUNT; drv_id++) {
- usbh_class_driver_t const * driver = get_driver(drv_id);
- if ( driver ) driver->close(daddr);
+ // update hub_addr and hub_port for next loop
+ hub_addr = h_id + 1 + CFG_TUH_DEVICE_MAX;
+ hub_port = 0;
+ break;
}
-
- hcd_device_close(rhport, daddr);
- clear_device(dev);
- // abort on-going control xfer if any
- if (_ctrl_xfer.daddr == daddr) _set_control_xfer_stage(CONTROL_STAGE_IDLE);
}
- }
+ #else
+ (void) removing_hubs;
+ break;
+ #endif
+ } while(1);
}
//--------------------------------------------------------------------+
diff --git a/src/host/usbh.h b/src/host/usbh.h
index 9ff118543..57362c778 100644
--- a/src/host/usbh.h
+++ b/src/host/usbh.h
@@ -73,11 +73,21 @@ typedef struct {
tusb_desc_interface_t desc;
} tuh_itf_info_t;
-// ConfigID for tuh_config()
+// ConfigID for tuh_configure()
enum {
- TUH_CFGID_RPI_PIO_USB_CONFIGURATION = OPT_MCU_RP2040 << 8 // cfg_param: pio_usb_configuration_t
+ TUH_CFGID_INVALID = 0,
+ TUH_CFGID_RPI_PIO_USB_CONFIGURATION = 100, // cfg_param: pio_usb_configuration_t
+ TUH_CFGID_MAX3421 = 200,
};
+typedef union {
+ // For TUH_CFGID_RPI_PIO_USB_CONFIGURATION use pio_usb_configuration_t
+
+ struct {
+ uint8_t max_nak;
+ } max3421;
+} tuh_configure_param_t;
+
//--------------------------------------------------------------------+
// APPLICATION CALLBACK
//--------------------------------------------------------------------+
@@ -109,7 +119,11 @@ bool tuh_configure(uint8_t rhport, uint32_t cfg_id, const void* cfg_param);
// Init host stack
bool tuh_init(uint8_t rhport);
+// Deinit host stack on rhport
+bool tuh_deinit(uint8_t rhport);
+
// Check if host stack is already initialized with any roothub ports
+// To check if an rhport is initialized, use tuh_rhport_is_active()
bool tuh_inited(void);
// Task function should be called in main/rtos loop, extended version of tuh_task()
diff --git a/src/host/usbh_pvt.h b/src/host/usbh_pvt.h
index 4ed2a72b5..95de915e9 100644
--- a/src/host/usbh_pvt.h
+++ b/src/host/usbh_pvt.h
@@ -50,11 +50,9 @@ enum {
//--------------------------------------------------------------------+
typedef struct {
- #if CFG_TUSB_DEBUG >= CFG_TUH_LOG_LEVEL
char const* name;
- #endif
-
- void (* const init )(void);
+ bool (* const init )(void);
+ bool (* const deinit )(void);
bool (* const open )(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const * itf_desc, uint16_t max_len);
bool (* const set_config )(uint8_t dev_addr, uint8_t itf_num);
bool (* const xfer_cb )(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes);
diff --git a/src/osal/osal.h b/src/osal/osal.h
index f092e8ffb..8f45ea5c1 100644
--- a/src/osal/osal.h
+++ b/src/osal/osal.h
@@ -74,15 +74,18 @@ typedef void (*osal_task_func_t)( void * );
// Should be implemented as static inline function in osal_port.h header
/*
osal_semaphore_t osal_semaphore_create(osal_semaphore_def_t* semdef);
+ bool osal_semaphore_delete(osal_semaphore_t semd_hdl);
bool osal_semaphore_post(osal_semaphore_t sem_hdl, bool in_isr);
bool osal_semaphore_wait(osal_semaphore_t sem_hdl, uint32_t msec);
void osal_semaphore_reset(osal_semaphore_t sem_hdl); // TODO removed
osal_mutex_t osal_mutex_create(osal_mutex_def_t* mdef);
+ bool osal_mutex_delete(osal_mutex_t mutex_hdl)
bool osal_mutex_lock (osal_mutex_t sem_hdl, uint32_t msec);
bool osal_mutex_unlock(osal_mutex_t mutex_hdl);
osal_queue_t osal_queue_create(osal_queue_def_t* qdef);
+ bool osal_queue_delete(osal_queue_t qhdl);
bool osal_queue_receive(osal_queue_t qhdl, void* data, uint32_t msec);
bool osal_queue_send(osal_queue_t qhdl, void const * data, bool in_isr);
bool osal_queue_empty(osal_queue_t qhdl);
diff --git a/src/osal/osal_freertos.h b/src/osal/osal_freertos.h
index 501e0bddd..f1f05f353 100644
--- a/src/osal/osal_freertos.h
+++ b/src/osal/osal_freertos.h
@@ -24,8 +24,8 @@
* This file is part of the TinyUSB stack.
*/
-#ifndef _TUSB_OSAL_FREERTOS_H_
-#define _TUSB_OSAL_FREERTOS_H_
+#ifndef TUSB_OSAL_FREERTOS_H_
+#define TUSB_OSAL_FREERTOS_H_
// FreeRTOS Headers
#include TU_INCLUDE_PATH(CFG_TUSB_OS_INC_PATH,FreeRTOS.h)
@@ -114,6 +114,11 @@ TU_ATTR_ALWAYS_INLINE static inline osal_semaphore_t osal_semaphore_create(osal_
#endif
}
+TU_ATTR_ALWAYS_INLINE static inline bool osal_semaphore_delete(osal_semaphore_t semd_hdl) {
+ vSemaphoreDelete(semd_hdl);
+ return true;
+}
+
TU_ATTR_ALWAYS_INLINE static inline bool osal_semaphore_post(osal_semaphore_t sem_hdl, bool in_isr) {
if ( !in_isr ) {
return xSemaphoreGive(sem_hdl) != 0;
@@ -153,6 +158,11 @@ TU_ATTR_ALWAYS_INLINE static inline osal_mutex_t osal_mutex_create(osal_mutex_de
#endif
}
+TU_ATTR_ALWAYS_INLINE static inline bool osal_mutex_delete(osal_mutex_t mutex_hdl) {
+ vSemaphoreDelete(mutex_hdl);
+ return true;
+}
+
TU_ATTR_ALWAYS_INLINE static inline bool osal_mutex_lock(osal_mutex_t mutex_hdl, uint32_t msec) {
return osal_semaphore_wait(mutex_hdl, msec);
}
@@ -181,6 +191,11 @@ TU_ATTR_ALWAYS_INLINE static inline osal_queue_t osal_queue_create(osal_queue_de
return q;
}
+TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_delete(osal_queue_t qhdl) {
+ vQueueDelete(qhdl);
+ return true;
+}
+
TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_receive(osal_queue_t qhdl, void* data, uint32_t msec) {
return xQueueReceive(qhdl, data, _osal_ms2tick(msec));
}
diff --git a/src/osal/osal_mynewt.h b/src/osal/osal_mynewt.h
index b8ea2087c..16def0d2a 100644
--- a/src/osal/osal_mynewt.h
+++ b/src/osal/osal_mynewt.h
@@ -36,8 +36,7 @@
//--------------------------------------------------------------------+
// TASK API
//--------------------------------------------------------------------+
-TU_ATTR_ALWAYS_INLINE static inline void osal_task_delay(uint32_t msec)
-{
+TU_ATTR_ALWAYS_INLINE static inline void osal_task_delay(uint32_t msec) {
os_time_delay( os_time_ms_to_ticks32(msec) );
}
@@ -47,25 +46,26 @@ TU_ATTR_ALWAYS_INLINE static inline void osal_task_delay(uint32_t msec)
typedef struct os_sem osal_semaphore_def_t;
typedef struct os_sem* osal_semaphore_t;
-TU_ATTR_ALWAYS_INLINE static inline osal_semaphore_t osal_semaphore_create(osal_semaphore_def_t* semdef)
-{
+TU_ATTR_ALWAYS_INLINE static inline osal_semaphore_t osal_semaphore_create(osal_semaphore_def_t* semdef) {
return (os_sem_init(semdef, 0) == OS_OK) ? (osal_semaphore_t) semdef : NULL;
}
-TU_ATTR_ALWAYS_INLINE static inline bool osal_semaphore_post(osal_semaphore_t sem_hdl, bool in_isr)
-{
+TU_ATTR_ALWAYS_INLINE static inline bool osal_semaphore_delete(osal_semaphore_t semd_hdl) {
+ (void) semd_hdl;
+ return true; // nothing to do
+}
+
+TU_ATTR_ALWAYS_INLINE static inline bool osal_semaphore_post(osal_semaphore_t sem_hdl, bool in_isr) {
(void) in_isr;
return os_sem_release(sem_hdl) == OS_OK;
}
-TU_ATTR_ALWAYS_INLINE static inline bool osal_semaphore_wait(osal_semaphore_t sem_hdl, uint32_t msec)
-{
+TU_ATTR_ALWAYS_INLINE static inline bool osal_semaphore_wait(osal_semaphore_t sem_hdl, uint32_t msec) {
uint32_t const ticks = (msec == OSAL_TIMEOUT_WAIT_FOREVER) ? OS_TIMEOUT_NEVER : os_time_ms_to_ticks32(msec);
return os_sem_pend(sem_hdl, ticks) == OS_OK;
}
-static inline void osal_semaphore_reset(osal_semaphore_t sem_hdl)
-{
+static inline void osal_semaphore_reset(osal_semaphore_t sem_hdl) {
// TODO implement later
}
@@ -75,19 +75,21 @@ static inline void osal_semaphore_reset(osal_semaphore_t sem_hdl)
typedef struct os_mutex osal_mutex_def_t;
typedef struct os_mutex* osal_mutex_t;
-TU_ATTR_ALWAYS_INLINE static inline osal_mutex_t osal_mutex_create(osal_mutex_def_t* mdef)
-{
+TU_ATTR_ALWAYS_INLINE static inline osal_mutex_t osal_mutex_create(osal_mutex_def_t* mdef) {
return (os_mutex_init(mdef) == OS_OK) ? (osal_mutex_t) mdef : NULL;
}
-TU_ATTR_ALWAYS_INLINE static inline bool osal_mutex_lock(osal_mutex_t mutex_hdl, uint32_t msec)
-{
+TU_ATTR_ALWAYS_INLINE static inline bool osal_mutex_delete(osal_mutex_t mutex_hdl) {
+ (void) mutex_hdl;
+ return true; // nothing to do
+}
+
+TU_ATTR_ALWAYS_INLINE static inline bool osal_mutex_lock(osal_mutex_t mutex_hdl, uint32_t msec) {
uint32_t const ticks = (msec == OSAL_TIMEOUT_WAIT_FOREVER) ? OS_TIMEOUT_NEVER : os_time_ms_to_ticks32(msec);
return os_mutex_pend(mutex_hdl, ticks) == OS_OK;
}
-TU_ATTR_ALWAYS_INLINE static inline bool osal_mutex_unlock(osal_mutex_t mutex_hdl)
-{
+TU_ATTR_ALWAYS_INLINE static inline bool osal_mutex_unlock(osal_mutex_t mutex_hdl) {
return os_mutex_release(mutex_hdl) == OS_OK;
}
@@ -101,8 +103,7 @@ TU_ATTR_ALWAYS_INLINE static inline bool osal_mutex_unlock(osal_mutex_t mutex_hd
static struct os_event _name##_##evbuf[_depth];\
osal_queue_def_t _name = { .depth = _depth, .item_sz = sizeof(_type), .buf = _name##_##buf, .evbuf = _name##_##evbuf};\
-typedef struct
-{
+typedef struct {
uint16_t depth;
uint16_t item_sz;
void* buf;
@@ -116,17 +117,20 @@ typedef struct
typedef osal_queue_def_t* osal_queue_t;
-TU_ATTR_ALWAYS_INLINE static inline osal_queue_t osal_queue_create(osal_queue_def_t* qdef)
-{
- if ( OS_OK != os_mempool_init(&qdef->mpool, qdef->depth, qdef->item_sz, qdef->buf, "usbd queue") ) return NULL;
- if ( OS_OK != os_mempool_init(&qdef->epool, qdef->depth, sizeof(struct os_event), qdef->evbuf, "usbd evqueue") ) return NULL;
+TU_ATTR_ALWAYS_INLINE static inline osal_queue_t osal_queue_create(osal_queue_def_t* qdef) {
+ if ( OS_OK != os_mempool_init(&qdef->mpool, qdef->depth, qdef->item_sz, qdef->buf, "usb queue") ) return NULL;
+ if ( OS_OK != os_mempool_init(&qdef->epool, qdef->depth, sizeof(struct os_event), qdef->evbuf, "usb evqueue") ) return NULL;
os_eventq_init(&qdef->evq);
return (osal_queue_t) qdef;
}
-TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_receive(osal_queue_t qhdl, void* data, uint32_t msec)
-{
+TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_delete(osal_queue_t qhdl) {
+ (void) qhdl;
+ return true; // nothing to do
+}
+
+TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_receive(osal_queue_t qhdl, void* data, uint32_t msec) {
(void) msec; // os_eventq_get() does not take timeout, always behave as msec = WAIT_FOREVER
struct os_event* ev;
@@ -139,8 +143,7 @@ TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_receive(osal_queue_t qhdl, v
return true;
}
-static inline bool osal_queue_send(osal_queue_t qhdl, void const * data, bool in_isr)
-{
+static inline bool osal_queue_send(osal_queue_t qhdl, void const * data, bool in_isr) {
(void) in_isr;
// get a block from mem pool for data
@@ -150,8 +153,7 @@ static inline bool osal_queue_send(osal_queue_t qhdl, void const * data, bool in
// get a block from event pool to put into queue
struct os_event* ev = (struct os_event*) os_memblock_get(&qhdl->epool);
- if (!ev)
- {
+ if (!ev) {
os_memblock_put(&qhdl->mpool, ptr);
return false;
}
@@ -163,8 +165,7 @@ static inline bool osal_queue_send(osal_queue_t qhdl, void const * data, bool in
return true;
}
-TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_empty(osal_queue_t qhdl)
-{
+TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_empty(osal_queue_t qhdl) {
return STAILQ_EMPTY(&qhdl->evq.evq_list);
}
diff --git a/src/osal/osal_none.h b/src/osal/osal_none.h
index a07d39828..c954fcfe8 100644
--- a/src/osal/osal_none.h
+++ b/src/osal/osal_none.h
@@ -54,6 +54,12 @@ TU_ATTR_ALWAYS_INLINE static inline osal_semaphore_t osal_semaphore_create(osal_
return semdef;
}
+TU_ATTR_ALWAYS_INLINE static inline bool osal_semaphore_delete(osal_semaphore_t semd_hdl) {
+ (void) semd_hdl;
+ return true; // nothing to do
+}
+
+
TU_ATTR_ALWAYS_INLINE static inline bool osal_semaphore_post(osal_semaphore_t sem_hdl, bool in_isr) {
(void) in_isr;
sem_hdl->count++;
@@ -90,6 +96,11 @@ TU_ATTR_ALWAYS_INLINE static inline osal_mutex_t osal_mutex_create(osal_mutex_de
return mdef;
}
+TU_ATTR_ALWAYS_INLINE static inline bool osal_mutex_delete(osal_mutex_t mutex_hdl) {
+ (void) mutex_hdl;
+ return true; // nothing to do
+}
+
TU_ATTR_ALWAYS_INLINE static inline bool osal_mutex_lock (osal_mutex_t mutex_hdl, uint32_t msec) {
return osal_semaphore_wait(mutex_hdl, msec);
}
@@ -143,6 +154,11 @@ TU_ATTR_ALWAYS_INLINE static inline osal_queue_t osal_queue_create(osal_queue_de
return (osal_queue_t) qdef;
}
+TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_delete(osal_queue_t qhdl) {
+ (void) qhdl;
+ return true; // nothing to do
+}
+
TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_receive(osal_queue_t qhdl, void* data, uint32_t msec) {
(void) msec; // not used, always behave as msec = 0
diff --git a/src/osal/osal_pico.h b/src/osal/osal_pico.h
index e6efa0968..00c589ef9 100644
--- a/src/osal/osal_pico.h
+++ b/src/osal/osal_pico.h
@@ -24,8 +24,8 @@
* This file is part of the TinyUSB stack.
*/
-#ifndef _TUSB_OSAL_PICO_H_
-#define _TUSB_OSAL_PICO_H_
+#ifndef TUSB_OSAL_PICO_H_
+#define TUSB_OSAL_PICO_H_
#include "pico/time.h"
#include "pico/sem.h"
@@ -33,42 +33,42 @@
#include "pico/critical_section.h"
#ifdef __cplusplus
- extern "C" {
+extern "C" {
#endif
//--------------------------------------------------------------------+
// TASK API
//--------------------------------------------------------------------+
-TU_ATTR_ALWAYS_INLINE static inline void osal_task_delay(uint32_t msec)
-{
+TU_ATTR_ALWAYS_INLINE static inline void osal_task_delay(uint32_t msec) {
sleep_ms(msec);
}
//--------------------------------------------------------------------+
// Binary Semaphore API
//--------------------------------------------------------------------+
-typedef struct semaphore osal_semaphore_def_t, *osal_semaphore_t;
+typedef struct semaphore osal_semaphore_def_t, * osal_semaphore_t;
-TU_ATTR_ALWAYS_INLINE static inline osal_semaphore_t osal_semaphore_create(osal_semaphore_def_t* semdef)
-{
+TU_ATTR_ALWAYS_INLINE static inline osal_semaphore_t osal_semaphore_create(osal_semaphore_def_t* semdef) {
sem_init(semdef, 0, 255);
return semdef;
}
-TU_ATTR_ALWAYS_INLINE static inline bool osal_semaphore_post(osal_semaphore_t sem_hdl, bool in_isr)
-{
+TU_ATTR_ALWAYS_INLINE static inline bool osal_semaphore_delete(osal_semaphore_t semd_hdl) {
+ (void) semd_hdl;
+ return true; // nothing to do
+}
+
+TU_ATTR_ALWAYS_INLINE static inline bool osal_semaphore_post(osal_semaphore_t sem_hdl, bool in_isr) {
(void) in_isr;
sem_release(sem_hdl);
return true;
}
-TU_ATTR_ALWAYS_INLINE static inline bool osal_semaphore_wait (osal_semaphore_t sem_hdl, uint32_t msec)
-{
+TU_ATTR_ALWAYS_INLINE static inline bool osal_semaphore_wait(osal_semaphore_t sem_hdl, uint32_t msec) {
return sem_acquire_timeout_ms(sem_hdl, msec);
}
-TU_ATTR_ALWAYS_INLINE static inline void osal_semaphore_reset(osal_semaphore_t sem_hdl)
-{
+TU_ATTR_ALWAYS_INLINE static inline void osal_semaphore_reset(osal_semaphore_t sem_hdl) {
sem_reset(sem_hdl, 0);
}
@@ -76,21 +76,23 @@ TU_ATTR_ALWAYS_INLINE static inline void osal_semaphore_reset(osal_semaphore_t s
// MUTEX API
// Within tinyusb, mutex is never used in ISR context
//--------------------------------------------------------------------+
-typedef struct mutex osal_mutex_def_t, *osal_mutex_t;
+typedef struct mutex osal_mutex_def_t, * osal_mutex_t;
-TU_ATTR_ALWAYS_INLINE static inline osal_mutex_t osal_mutex_create(osal_mutex_def_t* mdef)
-{
+TU_ATTR_ALWAYS_INLINE static inline osal_mutex_t osal_mutex_create(osal_mutex_def_t* mdef) {
mutex_init(mdef);
return mdef;
}
-TU_ATTR_ALWAYS_INLINE static inline bool osal_mutex_lock (osal_mutex_t mutex_hdl, uint32_t msec)
-{
+TU_ATTR_ALWAYS_INLINE static inline bool osal_mutex_delete(osal_mutex_t mutex_hdl) {
+ (void) mutex_hdl;
+ return true; // nothing to do
+}
+
+TU_ATTR_ALWAYS_INLINE static inline bool osal_mutex_lock(osal_mutex_t mutex_hdl, uint32_t msec) {
return mutex_enter_timeout_ms(mutex_hdl, msec);
}
-TU_ATTR_ALWAYS_INLINE static inline bool osal_mutex_unlock(osal_mutex_t mutex_hdl)
-{
+TU_ATTR_ALWAYS_INLINE static inline bool osal_mutex_unlock(osal_mutex_t mutex_hdl) {
mutex_exit(mutex_hdl);
return true;
}
@@ -100,75 +102,54 @@ TU_ATTR_ALWAYS_INLINE static inline bool osal_mutex_unlock(osal_mutex_t mutex_hd
//--------------------------------------------------------------------+
#include "common/tusb_fifo.h"
-typedef struct
-{
- tu_fifo_t ff;
- struct critical_section critsec; // osal_queue may be used in IRQs, so need critical section
+typedef struct {
+ tu_fifo_t ff;
+ struct critical_section critsec; // osal_queue may be used in IRQs, so need critical section
} osal_queue_def_t;
typedef osal_queue_def_t* osal_queue_t;
// role device/host is used by OS NONE for mutex (disable usb isr) only
-#define OSAL_QUEUE_DEF(_int_set, _name, _depth, _type) \
+#define OSAL_QUEUE_DEF(_int_set, _name, _depth, _type) \
uint8_t _name##_buf[_depth*sizeof(_type)]; \
osal_queue_def_t _name = { \
.ff = TU_FIFO_INIT(_name##_buf, _depth, _type, false) \
}
-// lock queue by disable USB interrupt
-TU_ATTR_ALWAYS_INLINE static inline void _osal_q_lock(osal_queue_t qhdl)
-{
- critical_section_enter_blocking(&qhdl->critsec);
-}
-
-// unlock queue
-TU_ATTR_ALWAYS_INLINE static inline void _osal_q_unlock(osal_queue_t qhdl)
-{
- critical_section_exit(&qhdl->critsec);
-}
-
-TU_ATTR_ALWAYS_INLINE static inline osal_queue_t osal_queue_create(osal_queue_def_t* qdef)
-{
+TU_ATTR_ALWAYS_INLINE static inline osal_queue_t osal_queue_create(osal_queue_def_t* qdef) {
critical_section_init(&qdef->critsec);
tu_fifo_clear(&qdef->ff);
return (osal_queue_t) qdef;
}
-TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_receive(osal_queue_t qhdl, void* data, uint32_t msec)
-{
- (void) msec; // not used, always behave as msec = 0
+TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_delete(osal_queue_t qhdl) {
+ osal_queue_def_t* qdef = (osal_queue_def_t*) qhdl;
+ critical_section_deinit(&qdef->critsec);
+ return true;
+}
- // TODO: revisit... docs say that mutexes are never used from IRQ context,
- // however osal_queue_recieve may be. therefore my assumption is that
- // the fifo mutex is not populated for queues used from an IRQ context
- //assert(!qhdl->ff.mutex);
+TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_receive(osal_queue_t qhdl, void* data, uint32_t msec) {
+ (void) msec; // not used, always behave as msec = 0
- _osal_q_lock(qhdl);
+ critical_section_enter_blocking(&qhdl->critsec);
bool success = tu_fifo_read(&qhdl->ff, data);
- _osal_q_unlock(qhdl);
+ critical_section_exit(&qhdl->critsec);
return success;
}
-TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_send(osal_queue_t qhdl, void const * data, bool in_isr)
-{
- // TODO: revisit... docs say that mutexes are never used from IRQ context,
- // however osal_queue_recieve may be. therefore my assumption is that
- // the fifo mutex is not populated for queues used from an IRQ context
- //assert(!qhdl->ff.mutex);
+TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_send(osal_queue_t qhdl, void const* data, bool in_isr) {
(void) in_isr;
- _osal_q_lock(qhdl);
+ critical_section_enter_blocking(&qhdl->critsec);
bool success = tu_fifo_write(&qhdl->ff, data);
- _osal_q_unlock(qhdl);
+ critical_section_exit(&qhdl->critsec);
TU_ASSERT(success);
-
return success;
}
-TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_empty(osal_queue_t qhdl)
-{
+TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_empty(osal_queue_t qhdl) {
// TODO: revisit; whether this is true or not currently, tu_fifo_empty is a single
// volatile read.
@@ -178,7 +159,7 @@ TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_empty(osal_queue_t qhdl)
}
#ifdef __cplusplus
- }
+}
#endif
-#endif /* _TUSB_OSAL_PICO_H_ */
+#endif
diff --git a/src/osal/osal_rtthread.h b/src/osal/osal_rtthread.h
index d03b53bee..c27814835 100644
--- a/src/osal/osal_rtthread.h
+++ b/src/osal/osal_rtthread.h
@@ -25,8 +25,8 @@
* This file is part of the TinyUSB stack.
*/
-#ifndef _TUSB_OSAL_RTTHREAD_H_
-#define _TUSB_OSAL_RTTHREAD_H_
+#ifndef TUSB_OSAL_RTTHREAD_H_
+#define TUSB_OSAL_RTTHREAD_H_
// RT-Thread Headers
#include "rtthread.h"
@@ -48,23 +48,27 @@ TU_ATTR_ALWAYS_INLINE static inline void osal_task_delay(uint32_t msec) {
typedef struct rt_semaphore osal_semaphore_def_t;
typedef rt_sem_t osal_semaphore_t;
-TU_ATTR_ALWAYS_INLINE static inline osal_semaphore_t
-osal_semaphore_create(osal_semaphore_def_t *semdef) {
- rt_sem_init(semdef, "tusb", 0, RT_IPC_FLAG_PRIO);
- return semdef;
+TU_ATTR_ALWAYS_INLINE static inline
+osal_semaphore_t osal_semaphore_create(osal_semaphore_def_t *semdef) {
+ rt_sem_init(semdef, "tusb", 0, RT_IPC_FLAG_PRIO);
+ return semdef;
+}
+
+TU_ATTR_ALWAYS_INLINE static inline bool osal_semaphore_delete(osal_semaphore_t semd_hdl) {
+ return RT_EOK == rt_sem_detach(semd_hdl);
}
TU_ATTR_ALWAYS_INLINE static inline bool osal_semaphore_post(osal_semaphore_t sem_hdl, bool in_isr) {
- (void) in_isr;
- return rt_sem_release(sem_hdl) == RT_EOK;
+ (void) in_isr;
+ return rt_sem_release(sem_hdl) == RT_EOK;
}
TU_ATTR_ALWAYS_INLINE static inline bool osal_semaphore_wait(osal_semaphore_t sem_hdl, uint32_t msec) {
- return rt_sem_take(sem_hdl, rt_tick_from_millisecond((rt_int32_t) msec)) == RT_EOK;
+ return rt_sem_take(sem_hdl, rt_tick_from_millisecond((rt_int32_t) msec)) == RT_EOK;
}
TU_ATTR_ALWAYS_INLINE static inline void osal_semaphore_reset(osal_semaphore_t const sem_hdl) {
- rt_sem_control(sem_hdl, RT_IPC_CMD_RESET, 0);
+ rt_sem_control(sem_hdl, RT_IPC_CMD_RESET, 0);
}
//--------------------------------------------------------------------+
@@ -74,16 +78,20 @@ typedef struct rt_mutex osal_mutex_def_t;
typedef rt_mutex_t osal_mutex_t;
TU_ATTR_ALWAYS_INLINE static inline osal_mutex_t osal_mutex_create(osal_mutex_def_t *mdef) {
- rt_mutex_init(mdef, "tusb", RT_IPC_FLAG_PRIO);
- return mdef;
+ rt_mutex_init(mdef, "tusb", RT_IPC_FLAG_PRIO);
+ return mdef;
+}
+
+TU_ATTR_ALWAYS_INLINE static inline bool osal_mutex_delete(osal_mutex_t mutex_hdl) {
+ return RT_EOK == rt_mutex_detach(mutex_hdl);
}
TU_ATTR_ALWAYS_INLINE static inline bool osal_mutex_lock(osal_mutex_t mutex_hdl, uint32_t msec) {
- return rt_mutex_take(mutex_hdl, rt_tick_from_millisecond((rt_int32_t) msec)) == RT_EOK;
+ return rt_mutex_take(mutex_hdl, rt_tick_from_millisecond((rt_int32_t) msec)) == RT_EOK;
}
TU_ATTR_ALWAYS_INLINE static inline bool osal_mutex_unlock(osal_mutex_t mutex_hdl) {
- return rt_mutex_release(mutex_hdl) == RT_EOK;
+ return rt_mutex_release(mutex_hdl) == RT_EOK;
}
//--------------------------------------------------------------------+
@@ -106,31 +114,35 @@ typedef struct {
typedef rt_mq_t osal_queue_t;
TU_ATTR_ALWAYS_INLINE static inline osal_queue_t osal_queue_create(osal_queue_def_t *qdef) {
- rt_mq_init(&(qdef->sq), "tusb", qdef->buf, qdef->item_sz,
- qdef->item_sz * qdef->depth, RT_IPC_FLAG_PRIO);
- return &(qdef->sq);
+ rt_mq_init(&(qdef->sq), "tusb", qdef->buf, qdef->item_sz,
+ qdef->item_sz * qdef->depth, RT_IPC_FLAG_PRIO);
+ return &(qdef->sq);
+}
+
+TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_delete(osal_queue_t qhdl) {
+ return RT_EOK == rt_mq_detach(qhdl);
}
TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_receive(osal_queue_t qhdl, void *data, uint32_t msec) {
- rt_tick_t tick = rt_tick_from_millisecond((rt_int32_t) msec);
+ rt_tick_t tick = rt_tick_from_millisecond((rt_int32_t) msec);
#if RT_VERSION_MAJOR >= 5
- return rt_mq_recv(qhdl, data, qhdl->msg_size, tick) > 0;
+ return rt_mq_recv(qhdl, data, qhdl->msg_size, tick) > 0;
#else
- return rt_mq_recv(qhdl, data, qhdl->msg_size, tick) == RT_EOK;
+ return rt_mq_recv(qhdl, data, qhdl->msg_size, tick) == RT_EOK;
#endif /* RT_VERSION_MAJOR >= 5 */
}
TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_send(osal_queue_t qhdl, void const *data, bool in_isr) {
- (void) in_isr;
- return rt_mq_send(qhdl, (void *)data, qhdl->msg_size) == RT_EOK;
+ (void) in_isr;
+ return rt_mq_send(qhdl, (void *)data, qhdl->msg_size) == RT_EOK;
}
TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_empty(osal_queue_t qhdl) {
- return (qhdl->entry) == 0;
+ return (qhdl->entry) == 0;
}
#ifdef __cplusplus
}
#endif
-#endif /* _TUSB_OSAL_RTTHREAD_H_ */
+#endif
diff --git a/src/osal/osal_rtx4.h b/src/osal/osal_rtx4.h
index e443135e0..35909e4d6 100644
--- a/src/osal/osal_rtx4.h
+++ b/src/osal/osal_rtx4.h
@@ -25,8 +25,8 @@
* This file is part of the TinyUSB stack.
*/
-#ifndef _TUSB_OSAL_RTX4_H_
-#define _TUSB_OSAL_RTX4_H_
+#ifndef TUSB_OSAL_RTX4_H_
+#define TUSB_OSAL_RTX4_H_
#include <rtl.h>
@@ -37,8 +37,7 @@ extern "C" {
//--------------------------------------------------------------------+
// TASK API
//--------------------------------------------------------------------+
-TU_ATTR_ALWAYS_INLINE static inline void osal_task_delay(uint32_t msec)
-{
+TU_ATTR_ALWAYS_INLINE static inline void osal_task_delay(uint32_t msec) {
uint16_t hi = msec >> 16;
uint16_t lo = msec;
while (hi--) {
@@ -48,12 +47,13 @@ TU_ATTR_ALWAYS_INLINE static inline void osal_task_delay(uint32_t msec)
}
TU_ATTR_ALWAYS_INLINE static inline uint16_t msec2wait(uint32_t msec) {
- if (msec == OSAL_TIMEOUT_WAIT_FOREVER)
+ if (msec == OSAL_TIMEOUT_WAIT_FOREVER) {
return 0xFFFF;
- else if (msec >= 0xFFFE)
+ } else if (msec >= 0xFFFE) {
return 0xFFFE;
- else
+ } else {
return msec;
+ }
}
//--------------------------------------------------------------------+
@@ -67,6 +67,11 @@ TU_ATTR_ALWAYS_INLINE static inline OS_ID osal_semaphore_create(osal_semaphore_d
return semdef;
}
+TU_ATTR_ALWAYS_INLINE static inline bool osal_semaphore_delete(osal_semaphore_t semd_hdl) {
+ (void) semd_hdl;
+ return true; // nothing to do
+}
+
TU_ATTR_ALWAYS_INLINE static inline bool osal_semaphore_post(osal_semaphore_t sem_hdl, bool in_isr) {
if ( !in_isr ) {
os_sem_send(sem_hdl);
@@ -90,19 +95,21 @@ TU_ATTR_ALWAYS_INLINE static inline void osal_semaphore_reset(osal_semaphore_t c
typedef OS_MUT osal_mutex_def_t;
typedef OS_ID osal_mutex_t;
-TU_ATTR_ALWAYS_INLINE static inline osal_mutex_t osal_mutex_create(osal_mutex_def_t* mdef)
-{
+TU_ATTR_ALWAYS_INLINE static inline osal_mutex_t osal_mutex_create(osal_mutex_def_t* mdef) {
os_mut_init(mdef);
return mdef;
}
-TU_ATTR_ALWAYS_INLINE static inline bool osal_mutex_lock (osal_mutex_t mutex_hdl, uint32_t msec)
-{
+TU_ATTR_ALWAYS_INLINE static inline bool osal_mutex_delete(osal_mutex_t mutex_hdl) {
+ (void) mutex_hdl;
+ return true; // nothing to do
+}
+
+TU_ATTR_ALWAYS_INLINE static inline bool osal_mutex_lock (osal_mutex_t mutex_hdl, uint32_t msec) {
return os_mut_wait(mutex_hdl, msec2wait(msec)) != OS_R_TMO;
}
-TU_ATTR_ALWAYS_INLINE static inline bool osal_mutex_unlock(osal_mutex_t mutex_hdl)
-{
+TU_ATTR_ALWAYS_INLINE static inline bool osal_mutex_unlock(osal_mutex_t mutex_hdl) {
return os_mut_release(mutex_hdl) == OS_R_OK;
}
@@ -116,9 +123,7 @@ TU_ATTR_ALWAYS_INLINE static inline bool osal_mutex_unlock(osal_mutex_t mutex_hd
_declare_box(_name##__pool, sizeof(_type), _depth); \
osal_queue_def_t _name = { .depth = _depth, .item_sz = sizeof(_type), .pool = _name##__pool, .mbox = _name##__mbox };
-
-typedef struct
-{
+typedef struct {
uint16_t depth;
uint16_t item_sz;
U32* pool;
@@ -127,15 +132,13 @@ typedef struct
typedef osal_queue_def_t* osal_queue_t;
-TU_ATTR_ALWAYS_INLINE static inline osal_queue_t osal_queue_create(osal_queue_def_t* qdef)
-{
+TU_ATTR_ALWAYS_INLINE static inline osal_queue_t osal_queue_create(osal_queue_def_t* qdef) {
os_mbx_init(qdef->mbox, (qdef->depth + 4) * 4);
_init_box(qdef->pool, ((qdef->item_sz+3)/4)*(qdef->depth) + 3, qdef->item_sz);
return qdef;
}
-TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_receive(osal_queue_t qhdl, void* data, uint32_t msec)
-{
+TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_receive(osal_queue_t qhdl, void* data, uint32_t msec) {
void* buf;
os_mbx_wait(qhdl->mbox, &buf, msec2wait(msec));
memcpy(data, buf, qhdl->item_sz);
@@ -143,23 +146,23 @@ TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_receive(osal_queue_t qhdl, v
return true;
}
-TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_send(osal_queue_t qhdl, void const * data, bool in_isr)
-{
+TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_delete(osal_queue_t qhdl) {
+ (void) qhdl;
+ return true; // nothing to do ?
+}
+
+TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_send(osal_queue_t qhdl, void const * data, bool in_isr) {
void* buf = _alloc_box(qhdl->pool);
memcpy(buf, data, qhdl->item_sz);
- if ( !in_isr )
- {
+ if ( !in_isr ) {
os_mbx_send(qhdl->mbox, buf, 0xFFFF);
- }
- else
- {
+ } else {
isr_mbx_send(qhdl->mbox, buf);
}
return true;
}
-TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_empty(osal_queue_t qhdl)
-{
+TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_empty(osal_queue_t qhdl) {
return os_mbx_check(qhdl->mbox) == qhdl->depth;
}
diff --git a/src/portable/analog/max3421/hcd_max3421.c b/src/portable/analog/max3421/hcd_max3421.c
index cc4799dd6..242c65501 100644
--- a/src/portable/analog/max3421/hcd_max3421.c
+++ b/src/portable/analog/max3421/hcd_max3421.c
@@ -30,6 +30,7 @@
#include <stdatomic.h>
#include "host/hcd.h"
+#include "host/usbh.h"
//--------------------------------------------------------------------+
//
@@ -166,6 +167,17 @@ enum {
DEFAULT_HIEN = HIRQ_CONDET_IRQ | HIRQ_FRAME_IRQ | HIRQ_HXFRDN_IRQ | HIRQ_RCVDAV_IRQ
};
+enum {
+ MAX_NAK_DEFAULT = 1 // Number of NAK per endpoint per usb frame
+};
+
+enum {
+ EP_STATE_IDLE = 0,
+ EP_STATE_COMPLETE = 1,
+ EP_STATE_ATTEMPT_1 = 2, // pending 1st attempt
+ EP_STATE_ATTEMPT_MAX = 15
+};
+
//--------------------------------------------------------------------+
//
//--------------------------------------------------------------------+
@@ -173,18 +185,21 @@ enum {
typedef struct {
uint8_t daddr;
- struct TU_ATTR_PACKED {
- uint8_t ep_dir : 1;
- uint8_t is_iso : 1;
- uint8_t is_setup : 1;
- uint8_t data_toggle : 1;
- uint8_t xfer_pending : 1;
- uint8_t xfer_complete : 1;
+ union { ;
+ struct TU_ATTR_PACKED {
+ uint8_t ep_num : 4;
+ uint8_t is_setup : 1;
+ uint8_t is_out : 1;
+ uint8_t is_iso : 1;
+ }hxfr_bm;
+
+ uint8_t hxfr;
};
struct TU_ATTR_PACKED {
- uint8_t ep_num : 4;
- uint16_t packet_size : 12;
+ uint8_t state : 4;
+ uint8_t data_toggle : 1;
+ uint16_t packet_size : 11;
};
uint16_t total_len;
@@ -195,6 +210,8 @@ typedef struct {
TU_VERIFY_STATIC(sizeof(max3421_ep_t) == 12, "size is not correct");
typedef struct {
+ volatile uint16_t frame_count;
+
// cached register
uint8_t sndbc;
uint8_t hirq;
@@ -204,18 +221,20 @@ typedef struct {
uint8_t hxfr;
atomic_flag busy; // busy transferring
- volatile uint16_t frame_count;
- max3421_ep_t ep[CFG_TUH_MAX3421_ENDPOINT_TOTAL]; // [0] is reserved for addr0
-
- OSAL_MUTEX_DEF(spi_mutexdef);
#if OSAL_MUTEX_REQUIRED
+ OSAL_MUTEX_DEF(spi_mutexdef);
osal_mutex_t spi_mutex;
#endif
+
+ max3421_ep_t ep[CFG_TUH_MAX3421_ENDPOINT_TOTAL]; // [0] is reserved for addr0
} max3421_data_t;
static max3421_data_t _hcd_data;
+// max NAK before giving up in a frame. 0 means infinite NAKs
+static uint8_t _max_nak = MAX_NAK_DEFAULT;
+
//--------------------------------------------------------------------+
// API: SPI transfer with MAX3421E
// - spi_cs_api(), spi_xfer_api(), int_api(): must be implemented by application
@@ -304,7 +323,6 @@ static void fifo_write(uint8_t rhport, uint8_t reg, uint8_t const * buffer, uint
tuh_max3421_spi_xfer_api(rhport, buffer, NULL, len);
max3421_spi_unlock(rhport, in_isr);
-
}
static void fifo_read(uint8_t rhport, uint8_t * buffer, uint16_t len, bool in_isr) {
@@ -321,35 +339,35 @@ static void fifo_read(uint8_t rhport, uint8_t * buffer, uint16_t len, bool in_is
}
//------------- register write helper -------------//
-static inline void hirq_write(uint8_t rhport, uint8_t data, bool in_isr) {
+TU_ATTR_ALWAYS_INLINE static inline void hirq_write(uint8_t rhport, uint8_t data, bool in_isr) {
reg_write(rhport, HIRQ_ADDR, data, in_isr);
// HIRQ write 1 is clear
_hcd_data.hirq &= (uint8_t) ~data;
}
-static inline void hien_write(uint8_t rhport, uint8_t data, bool in_isr) {
+TU_ATTR_ALWAYS_INLINE static inline void hien_write(uint8_t rhport, uint8_t data, bool in_isr) {
_hcd_data.hien = data;
reg_write(rhport, HIEN_ADDR, data, in_isr);
}
-static inline void mode_write(uint8_t rhport, uint8_t data, bool in_isr) {
+TU_ATTR_ALWAYS_INLINE static inline void mode_write(uint8_t rhport, uint8_t data, bool in_isr) {
_hcd_data.mode = data;
reg_write(rhport, MODE_ADDR, data, in_isr);
}
-static inline void peraddr_write(uint8_t rhport, uint8_t data, bool in_isr) {
+TU_ATTR_ALWAYS_INLINE static inline void peraddr_write(uint8_t rhport, uint8_t data, bool in_isr) {
if ( _hcd_data.peraddr == data ) return; // no need to change address
_hcd_data.peraddr = data;
reg_write(rhport, PERADDR_ADDR, data, in_isr);
}
-static inline void hxfr_write(uint8_t rhport, uint8_t data, bool in_isr) {
+TU_ATTR_ALWAYS_INLINE static inline void hxfr_write(uint8_t rhport, uint8_t data, bool in_isr) {
_hcd_data.hxfr = data;
reg_write(rhport, HXFR_ADDR, data, in_isr);
}
-static inline void sndbc_write(uint8_t rhport, uint8_t data, bool in_isr) {
+TU_ATTR_ALWAYS_INLINE static inline void sndbc_write(uint8_t rhport, uint8_t data, bool in_isr) {
_hcd_data.sndbc = data;
reg_write(rhport, SNDBC_ADDR, data, in_isr);
}
@@ -359,10 +377,11 @@ static inline void sndbc_write(uint8_t rhport, uint8_t data, bool in_isr) {
//--------------------------------------------------------------------+
static max3421_ep_t* find_ep_not_addr0(uint8_t daddr, uint8_t ep_num, uint8_t ep_dir) {
+ uint8_t const is_out = 1-ep_dir;
for(size_t i=1; i<CFG_TUH_MAX3421_ENDPOINT_TOTAL; i++) {
max3421_ep_t* ep = &_hcd_data.ep[i];
- // for control endpoint, skip direction check
- if (daddr == ep->daddr && ep_num == ep->ep_num && (ep_dir == ep->ep_dir || ep_num == 0)) {
+ // control endpoint is bi-direction (skip check)
+ if (daddr == ep->daddr && ep_num == ep->hxfr_bm.ep_num && (ep_num == 0 || is_out == ep->hxfr_bm.is_out)) {
return ep;
}
}
@@ -393,14 +412,23 @@ static void free_ep(uint8_t daddr) {
}
}
+// Check if endpoint has an queued transfer and not reach max NAK
+TU_ATTR_ALWAYS_INLINE static inline bool is_ep_pending(max3421_ep_t const * ep) {
+ uint8_t const state = ep->state;
+ return ep->packet_size && (state >= EP_STATE_ATTEMPT_1) &&
+ (_max_nak == 0 || state < EP_STATE_ATTEMPT_1 + _max_nak);
+}
+
+// Find the next pending endpoint using round-robin scheduling, starting from next endpoint.
+// return NULL if not found
+// TODO respect interrupt endpoint's interval
static max3421_ep_t * find_next_pending_ep(max3421_ep_t * cur_ep) {
size_t const idx = (size_t) (cur_ep - _hcd_data.ep);
// starting from next endpoint
for (size_t i = idx + 1; i < CFG_TUH_MAX3421_ENDPOINT_TOTAL; i++) {
max3421_ep_t* ep = &_hcd_data.ep[i];
- if (ep->xfer_pending && ep->packet_size) {
-// TU_LOG3("next pending i = %u\r\n", i);
+ if (is_ep_pending(ep)) {
return ep;
}
}
@@ -408,8 +436,7 @@ static max3421_ep_t * find_next_pending_ep(max3421_ep_t * cur_ep) {
// wrap around including current endpoint
for (size_t i = 0; i <= idx; i++) {
max3421_ep_t* ep = &_hcd_data.ep[i];
- if (ep->xfer_pending && ep->packet_size) {
-// TU_LOG3("next pending i = %u\r\n", i);
+ if (is_ep_pending(ep)) {
return ep;
}
}
@@ -424,10 +451,11 @@ static max3421_ep_t * find_next_pending_ep(max3421_ep_t * cur_ep) {
// optional hcd configuration, called by tuh_configure()
bool hcd_configure(uint8_t rhport, uint32_t cfg_id, const void* cfg_param) {
(void) rhport;
- (void) cfg_id;
- (void) cfg_param;
+ TU_VERIFY(cfg_id == TUH_CFGID_MAX3421 && cfg_param != NULL);
- return false;
+ tuh_configure_param_t const* cfg = (tuh_configure_param_t const*) cfg_param;
+ _max_nak = tu_min8(cfg->max3421.max_nak, EP_STATE_ATTEMPT_MAX-EP_STATE_ATTEMPT_1);
+ return true;
}
// Initialize controller to host mode
@@ -438,6 +466,7 @@ bool hcd_init(uint8_t rhport) {
TU_LOG2_INT(sizeof(max3421_ep_t));
TU_LOG2_INT(sizeof(max3421_data_t));
+ TU_LOG2_INT(offsetof(max3421_data_t, ep));
tu_memclr(&_hcd_data, sizeof(_hcd_data));
_hcd_data.peraddr = 0xff; // invalid
@@ -449,7 +478,7 @@ bool hcd_init(uint8_t rhport) {
// full duplex, interrupt negative edge
reg_write(rhport, PINCTL_ADDR, PINCTL_FDUPSPI, false);
- // V1 is 0x01, V2 is 0x12, V3 is 0x13
+ // v1 is 0x01, v2 is 0x12, v3 is 0x13
uint8_t const revision = reg_read(rhport, REVISION_ADDR, false);
TU_ASSERT(revision == 0x01 || revision == 0x12 || revision == 0x13, false);
TU_LOG2_HEX(revision);
@@ -481,6 +510,24 @@ bool hcd_init(uint8_t rhport) {
return true;
}
+bool hcd_deinit(uint8_t rhport) {
+ (void) rhport;
+
+ // disable interrupt
+ tuh_max3421_int_api(rhport, false);
+
+ // reset max3421
+ reg_write(rhport, USBCTL_ADDR, USBCTL_CHIPRES, false);
+ reg_write(rhport, USBCTL_ADDR, 0, false);
+
+ #if OSAL_MUTEX_REQUIRED
+ osal_mutex_delete(_hcd_data.spi_mutex);
+ _hcd_data.spi_mutex = NULL;
+ #endif
+
+ return true;
+}
+
// Enable USB interrupt
// Not actually enable GPIO interrupt, just set variable to prevent handler to process
void hcd_int_enable (uint8_t rhport) {
@@ -539,7 +586,6 @@ void hcd_device_close(uint8_t rhport, uint8_t dev_addr) {
// Open an endpoint
bool hcd_edpt_open(uint8_t rhport, uint8_t daddr, tusb_desc_endpoint_t const * ep_desc) {
(void) rhport;
- (void) daddr;
uint8_t const ep_num = tu_edpt_number(ep_desc->bEndpointAddress);
tusb_dir_t const ep_dir = tu_edpt_dir(ep_desc->bEndpointAddress);
@@ -551,12 +597,9 @@ bool hcd_edpt_open(uint8_t rhport, uint8_t daddr, tusb_desc_endpoint_t const * e
ep = allocate_ep();
TU_ASSERT(ep);
ep->daddr = daddr;
- ep->ep_num = (uint8_t) (ep_num & 0x0f);
- ep->ep_dir = (ep_dir == TUSB_DIR_IN) ? 1 : 0;
- }
-
- if ( TUSB_XFER_ISOCHRONOUS == ep_desc->bmAttributes.xfer ) {
- ep->is_iso = 1;
+ ep->hxfr_bm.ep_num = (uint8_t) (ep_num & 0x0f);
+ ep->hxfr_bm.is_out = (ep_dir == TUSB_DIR_OUT) ? 1 : 0;
+ ep->hxfr_bm.is_iso = (TUSB_XFER_ISOCHRONOUS == ep_desc->bmAttributes.xfer) ? 1 : 0;
}
ep->packet_size = (uint16_t) (tu_edpt_packet_size(ep_desc) & 0x7ff);
@@ -564,7 +607,7 @@ bool hcd_edpt_open(uint8_t rhport, uint8_t daddr, tusb_desc_endpoint_t const * e
return true;
}
-void xact_out(uint8_t rhport, max3421_ep_t *ep, bool switch_ep, bool in_isr) {
+static void xact_out(uint8_t rhport, max3421_ep_t *ep, bool switch_ep, bool in_isr) {
// Page 12: Programming BULK-OUT Transfers
// TODO double buffered
if (switch_ep) {
@@ -580,12 +623,10 @@ void xact_out(uint8_t rhport, max3421_ep_t *ep, bool switch_ep, bool in_isr) {
fifo_write(rhport, SNDFIFO_ADDR, ep->buf, xact_len, in_isr);
}
sndbc_write(rhport, xact_len, in_isr);
-
- uint8_t const hxfr = (uint8_t ) (ep->ep_num | HXFR_OUT_NIN | (ep->is_iso ? HXFR_ISO : 0));
- hxfr_write(rhport, hxfr, in_isr);
+ hxfr_write(rhport, ep->hxfr, in_isr);
}
-void xact_in(uint8_t rhport, max3421_ep_t *ep, bool switch_ep, bool in_isr) {
+static void xact_in(uint8_t rhport, max3421_ep_t *ep, bool switch_ep, bool in_isr) {
// Page 13: Programming BULK-IN Transfers
if (switch_ep) {
peraddr_write(rhport, ep->daddr, in_isr);
@@ -594,33 +635,36 @@ void xact_in(uint8_t rhport, max3421_ep_t *ep, bool switch_ep, bool in_isr) {
reg_write(rhport, HCTL_ADDR, hctl, in_isr);
}
- uint8_t const hxfr = (uint8_t) (ep->ep_num | (ep->is_iso ? HXFR_ISO : 0));
- hxfr_write(rhport, hxfr, in_isr);
+ hxfr_write(rhport, ep->hxfr, in_isr);
+}
+
+static void xact_setup(uint8_t rhport, max3421_ep_t *ep, bool in_isr) {
+ peraddr_write(rhport, ep->daddr, in_isr);
+ fifo_write(rhport, SUDFIFO_ADDR, ep->buf, 8, in_isr);
+ hxfr_write(rhport, HXFR_SETUP, in_isr);
}
-TU_ATTR_ALWAYS_INLINE static inline void xact_inout(uint8_t rhport, max3421_ep_t *ep, bool switch_ep, bool in_isr) {
- if (ep->ep_num == 0 ) {
+static void xact_generic(uint8_t rhport, max3421_ep_t *ep, bool switch_ep, bool in_isr) {
+ if (ep->hxfr_bm.ep_num == 0 ) {
// setup
- if (ep->is_setup) {
- peraddr_write(rhport, ep->daddr, in_isr);
- fifo_write(rhport, SUDFIFO_ADDR, ep->buf, 8, in_isr);
- hxfr_write(rhport, HXFR_SETUP, in_isr);
+ if (ep->hxfr_bm.is_setup) {
+ xact_setup(rhport, ep, in_isr);
return;
}
// status
if (ep->buf == NULL || ep->total_len == 0) {
- uint8_t const hxfr = HXFR_HS | (ep->ep_dir ? 0 : HXFR_OUT_NIN);
+ uint8_t const hxfr = HXFR_HS | (ep->hxfr_bm.is_out ? HXFR_OUT_NIN : 0);
peraddr_write(rhport, ep->daddr, in_isr);
hxfr_write(rhport, hxfr, in_isr);
return;
}
}
- if (ep->ep_dir) {
- xact_in(rhport, ep, switch_ep, in_isr);
- }else {
+ if (ep->hxfr_bm.is_out) {
xact_out(rhport, ep, switch_ep, in_isr);
+ }else {
+ xact_in(rhport, ep, switch_ep, in_isr);
}
}
@@ -633,24 +677,21 @@ bool hcd_edpt_xfer(uint8_t rhport, uint8_t daddr, uint8_t ep_addr, uint8_t * buf
TU_VERIFY(ep);
// control transfer can switch direction
- ep->ep_dir = ep_dir ? 1u : 0u;
+ ep->hxfr_bm.is_out = ep_dir ? 0u : 1u;
ep->buf = buffer;
ep->total_len = buflen;
ep->xferred_len = 0;
- ep->xfer_complete = 0;
- ep->xfer_pending = 1;
+ ep->state = EP_STATE_ATTEMPT_1;
- if ( ep_num == 0 ) {
- ep->is_setup = 0;
+ if (ep_num == 0) {
+ ep->hxfr_bm.is_setup = 0;
ep->data_toggle = 1;
}
// carry out transfer if not busy
- if ( !atomic_flag_test_and_set(&_hcd_data.busy) ) {
- xact_inout(rhport, ep, true, false);
- } else {
- return true;
+ if (!atomic_flag_test_and_set(&_hcd_data.busy)) {
+ xact_generic(rhport, ep, true, false);
}
return true;
@@ -673,17 +714,16 @@ bool hcd_setup_send(uint8_t rhport, uint8_t daddr, uint8_t const setup_packet[8]
max3421_ep_t* ep = find_opened_ep(daddr, 0, 0);
TU_ASSERT(ep);
- ep->ep_dir = 0;
- ep->is_setup = 1;
+ ep->hxfr_bm.is_out = 1;
+ ep->hxfr_bm.is_setup = 1;
ep->buf = (uint8_t*)(uintptr_t) setup_packet;
ep->total_len = 8;
ep->xferred_len = 0;
- ep->xfer_complete = 0;
- ep->xfer_pending = 1;
+ ep->state = EP_STATE_ATTEMPT_1;
// carry out transfer if not busy
- if ( !atomic_flag_test_and_set(&_hcd_data.busy) ) {
- xact_inout(rhport, ep, true, false);
+ if (!atomic_flag_test_and_set(&_hcd_data.busy)) {
+ xact_setup(rhport, ep, false);
}
return true;
@@ -748,22 +788,23 @@ static void handle_connect_irq(uint8_t rhport, bool in_isr) {
}
static void xfer_complete_isr(uint8_t rhport, max3421_ep_t *ep, xfer_result_t result, uint8_t hrsl, bool in_isr) {
- uint8_t const ep_addr = tu_edpt_addr(ep->ep_num, ep->ep_dir);
+ uint8_t const ep_dir = 1-ep->hxfr_bm.is_out;
+ uint8_t const ep_addr = tu_edpt_addr(ep->hxfr_bm.ep_num, ep_dir);
// save data toggle
- if (ep->ep_dir) {
+ if (ep_dir) {
ep->data_toggle = (hrsl & HRSL_RCVTOGRD) ? 1u : 0u;
}else {
ep->data_toggle = (hrsl & HRSL_SNDTOGRD) ? 1u : 0u;
}
- ep->xfer_pending = 0;
+ ep->state = EP_STATE_IDLE;
hcd_event_xfer_complete(ep->daddr, ep_addr, ep->xferred_len, result, in_isr);
// Find next pending endpoint
- max3421_ep_t *next_ep = find_next_pending_ep(ep);
+ max3421_ep_t * next_ep = find_next_pending_ep(ep);
if (next_ep) {
- xact_inout(rhport, next_ep, true, in_isr);
+ xact_generic(rhport, next_ep, true, in_isr);
}else {
// no more pending
atomic_flag_clear(&_hcd_data.busy);
@@ -793,20 +834,23 @@ static void handle_xfer_done(uint8_t rhport, bool in_isr) {
case HRSL_NAK:
if (ep_num == 0) {
- // NAK on control, retry immediately
+ // control endpoint -> retry immediately
hxfr_write(rhport, _hcd_data.hxfr, in_isr);
- }else {
- // NAK on non-control, find next pending to switch
- max3421_ep_t *next_ep = find_next_pending_ep(ep);
+ } else {
+ if (ep->state < EP_STATE_ATTEMPT_MAX) {
+ ep->state++;
+ }
+ max3421_ep_t * next_ep = find_next_pending_ep(ep);
if (ep == next_ep) {
- // this endpoint is only one pending, retry immediately
+ // this endpoint is only one pending -> retry immediately
hxfr_write(rhport, _hcd_data.hxfr, in_isr);
- }else if (next_ep) {
- // switch to next pending TODO could have issue with double buffered if not clear previously out data
- xact_inout(rhport, next_ep, true, in_isr);
- }else {
- TU_ASSERT(false,);
+ } else if (next_ep) {
+ // switch to next pending endpoint TODO could have issue with double buffered if not clear previously out data
+ xact_generic(rhport, next_ep, true, in_isr);
+ } else {
+ // no more pending in this frame -> clear busy
+ atomic_flag_clear(&_hcd_data.busy);
}
}
return;
@@ -828,12 +872,14 @@ static void handle_xfer_done(uint8_t rhport, bool in_isr) {
if (ep_dir) {
// IN transfer: fifo data is already received in RCVDAV IRQ
- if ( hxfr_type & HXFR_HS ) {
- ep->xfer_complete = 1;
+
+ // mark control handshake as complete
+ if (hxfr_type & HXFR_HS) {
+ ep->state = EP_STATE_COMPLETE;
}
// short packet or all bytes transferred
- if ( ep->xfer_complete ) {
+ if (ep->state == EP_STATE_COMPLETE) {
xfer_complete_isr(rhport, ep, xfer_result, hrsl, in_isr);
}else {
// more to transfer
@@ -867,13 +913,13 @@ static void handle_xfer_done(uint8_t rhport, bool in_isr) {
void print_hirq(uint8_t hirq) {
TU_LOG3_HEX(hirq);
- if (hirq & HIRQ_HXFRDN_IRQ) TU_LOG3(" HXFRDN");
- if (hirq & HIRQ_FRAME_IRQ) TU_LOG3(" FRAME");
- if (hirq & HIRQ_CONDET_IRQ) TU_LOG3(" CONDET");
- if (hirq & HIRQ_SUSDN_IRQ) TU_LOG3(" SUSDN");
- if (hirq & HIRQ_SNDBAV_IRQ) TU_LOG3(" SNDBAV");
- if (hirq & HIRQ_RCVDAV_IRQ) TU_LOG3(" RCVDAV");
- if (hirq & HIRQ_RWU_IRQ) TU_LOG3(" RWU");
+ if (hirq & HIRQ_HXFRDN_IRQ) TU_LOG3(" HXFRDN");
+ if (hirq & HIRQ_FRAME_IRQ) TU_LOG3(" FRAME");
+ if (hirq & HIRQ_CONDET_IRQ) TU_LOG3(" CONDET");
+ if (hirq & HIRQ_SUSDN_IRQ) TU_LOG3(" SUSDN");
+ if (hirq & HIRQ_SNDBAV_IRQ) TU_LOG3(" SNDBAV");
+ if (hirq & HIRQ_RCVDAV_IRQ) TU_LOG3(" RCVDAV");
+ if (hirq & HIRQ_RWU_IRQ) TU_LOG3(" RWU");
if (hirq & HIRQ_BUSEVENT_IRQ) TU_LOG3(" BUSEVENT");
TU_LOG3("\r\n");
@@ -890,6 +936,25 @@ void hcd_int_handler(uint8_t rhport, bool in_isr) {
if (hirq & HIRQ_FRAME_IRQ) {
_hcd_data.frame_count++;
+
+ max3421_ep_t* ep_retry = NULL;
+
+ // reset all endpoints attempt counter
+ for (size_t i = 0; i < CFG_TUH_MAX3421_ENDPOINT_TOTAL; i++) {
+ max3421_ep_t* ep = &_hcd_data.ep[i];
+ if (ep->packet_size && ep->state > EP_STATE_ATTEMPT_1) {
+ ep->state = EP_STATE_ATTEMPT_1;
+
+ if (ep_retry == NULL) {
+ ep_retry = ep;
+ }
+ }
+ }
+
+ // start usb transfer if not busy
+ if (ep_retry != NULL && !atomic_flag_test_and_set(&_hcd_data.busy)) {
+ xact_generic(rhport, ep_retry, true, in_isr);
+ }
}
if (hirq & HIRQ_CONDET_IRQ) {
@@ -898,17 +963,17 @@ void hcd_int_handler(uint8_t rhport, bool in_isr) {
// queue more transfer in handle_xfer_done() can cause hirq to be set again while external IRQ may not catch and/or
// not call this handler again. So we need to loop until all IRQ are cleared
- while ( hirq & (HIRQ_RCVDAV_IRQ | HIRQ_HXFRDN_IRQ) ) {
- if ( hirq & HIRQ_RCVDAV_IRQ ) {
+ while (hirq & (HIRQ_RCVDAV_IRQ | HIRQ_HXFRDN_IRQ)) {
+ if (hirq & HIRQ_RCVDAV_IRQ) {
uint8_t const ep_num = _hcd_data.hxfr & HXFR_EPNUM_MASK;
- max3421_ep_t *ep = find_opened_ep(_hcd_data.peraddr, ep_num, 1);
+ max3421_ep_t* ep = find_opened_ep(_hcd_data.peraddr, ep_num, 1);
uint8_t xact_len = 0;
// RCVDAV_IRQ can trigger 2 times (dual buffered)
- while ( hirq & HIRQ_RCVDAV_IRQ ) {
+ while (hirq & HIRQ_RCVDAV_IRQ) {
uint8_t rcvbc = reg_read(rhport, RCVBC_ADDR, in_isr);
xact_len = (uint8_t) tu_min16(rcvbc, ep->total_len - ep->xferred_len);
- if ( xact_len ) {
+ if (xact_len) {
fifo_read(rhport, ep->buf, xact_len, in_isr);
ep->buf += xact_len;
ep->xferred_len += xact_len;
@@ -919,12 +984,12 @@ void hcd_int_handler(uint8_t rhport, bool in_isr) {
hirq = reg_read(rhport, HIRQ_ADDR, in_isr);
}
- if ( xact_len < ep->packet_size || ep->xferred_len >= ep->total_len ) {
- ep->xfer_complete = 1;
+ if (xact_len < ep->packet_size || ep->xferred_len >= ep->total_len) {
+ ep->state = EP_STATE_COMPLETE;
}
}
- if ( hirq & HIRQ_HXFRDN_IRQ ) {
+ if (hirq & HIRQ_HXFRDN_IRQ) {
hirq_write(rhport, HIRQ_HXFRDN_IRQ, in_isr);
handle_xfer_done(rhport, in_isr);
}
diff --git a/src/portable/nordic/nrf5x/dcd_nrf5x.c b/src/portable/nordic/nrf5x/dcd_nrf5x.c
index 841cda752..80a285ef0 100644
--- a/src/portable/nordic/nrf5x/dcd_nrf5x.c
+++ b/src/portable/nordic/nrf5x/dcd_nrf5x.c
@@ -246,7 +246,7 @@ static void xact_in_dma(uint8_t epnum)
//--------------------------------------------------------------------+
void dcd_init (uint8_t rhport)
{
- TU_LOG1("dcd init\r\n");
+ TU_LOG2("dcd init\r\n");
(void) rhport;
}
@@ -685,7 +685,7 @@ void dcd_int_handler(uint8_t rhport)
if ( int_status & USBD_INTEN_USBEVENT_Msk )
{
- TU_LOG(2, "EVENTCAUSE = 0x%04lX\r\n", NRF_USBD->EVENTCAUSE);
+ TU_LOG(3, "EVENTCAUSE = 0x%04lX\r\n", NRF_USBD->EVENTCAUSE);
enum { EVT_CAUSE_MASK = USBD_EVENTCAUSE_SUSPEND_Msk | USBD_EVENTCAUSE_RESUME_Msk | USBD_EVENTCAUSE_USBWUALLOWED_Msk | USBD_EVENTCAUSE_ISOOUTCRC_Msk };
uint32_t const evt_cause = NRF_USBD->EVENTCAUSE & EVT_CAUSE_MASK;
diff --git a/src/portable/raspberrypi/rp2040/hcd_rp2040.c b/src/portable/raspberrypi/rp2040/hcd_rp2040.c
index 08aef9314..b351a9a07 100644
--- a/src/portable/raspberrypi/rp2040/hcd_rp2040.c
+++ b/src/portable/raspberrypi/rp2040/hcd_rp2040.c
@@ -113,7 +113,7 @@ static void __tusb_irq_path_func(_handle_buff_status_bit)(uint bit, struct hw_en
static void __tusb_irq_path_func(hw_handle_buff_status)(void)
{
uint32_t remaining_buffers = usb_hw->buf_status;
- pico_trace("buf_status 0x%08x\n", remaining_buffers);
+ pico_trace("buf_status 0x%08lx\n", remaining_buffers);
// Check EPX first
uint bit = 0b1;
@@ -325,10 +325,8 @@ static void _hw_endpoint_init(struct hw_endpoint *ep, uint8_t dev_addr, uint8_t
ep->wMaxPacketSize = wMaxPacketSize;
ep->transfer_type = transfer_type;
- pico_trace("hw_endpoint_init dev %d ep %d %s xfer %d\n", ep->dev_addr, tu_edpt_number(ep->ep_addr),
- ep_dir_string[tu_edpt_dir(ep->ep_addr)], ep->transfer_type);
- pico_trace("dev %d ep %d %s setup buffer @ 0x%p\n", ep->dev_addr, tu_edpt_number(ep->ep_addr),
- ep_dir_string[tu_edpt_dir(ep->ep_addr)], ep->hw_data_buf);
+ pico_trace("hw_endpoint_init dev %d ep %02X xfer %d\n", ep->dev_addr, ep->ep_addr, ep->transfer_type);
+ pico_trace("dev %d ep %02X setup buffer @ 0x%p\n", ep->dev_addr, ep->ep_addr, ep->hw_data_buf);
uint dpram_offset = hw_data_offset(ep->hw_data_buf);
// Bits 0-5 should be 0
assert(!(dpram_offset & 0b111111));
@@ -343,7 +341,7 @@ static void _hw_endpoint_init(struct hw_endpoint *ep, uint8_t dev_addr, uint8_t
ep_reg |= (uint32_t) ((bmInterval - 1) << EP_CTRL_HOST_INTERRUPT_INTERVAL_LSB);
}
*ep->endpoint_control = ep_reg;
- pico_trace("endpoint control (0x%p) <- 0x%x\n", ep->endpoint_control, ep_reg);
+ pico_trace("endpoint control (0x%p) <- 0x%lx\n", ep->endpoint_control, ep_reg);
ep->configured = true;
if ( ep != &epx )
diff --git a/src/portable/sony/cxd56/dcd_cxd56.c b/src/portable/sony/cxd56/dcd_cxd56.c
index 6677891a5..41814370e 100644
--- a/src/portable/sony/cxd56/dcd_cxd56.c
+++ b/src/portable/sony/cxd56/dcd_cxd56.c
@@ -102,17 +102,25 @@ static int _dcd_bind(FAR struct usbdevclass_driver_s *driver, FAR struct usbdev_
usbdev = dev;
usbdcd_driver.ep[0] = dev->ep0;
+ #ifdef EP_ALLOCREQ
+ // SDK v2
usbdcd_driver.req[0] = EP_ALLOCREQ(usbdcd_driver.ep[0]);
- if (usbdcd_driver.req[0] != NULL)
- {
+ if (usbdcd_driver.req[0] != NULL) {
usbdcd_driver.req[0]->len = 64;
usbdcd_driver.req[0]->buf = EP_ALLOCBUFFER(usbdcd_driver.ep[0], 64);
- if (!usbdcd_driver.req[0]->buf)
- {
+ if (!usbdcd_driver.req[0]->buf) {
EP_FREEREQ(usbdcd_driver.ep[0], usbdcd_driver.req[0]);
usbdcd_driver.req[0] = NULL;
+ return ENOMEM;
}
}
+ #else
+ // SDK v3
+ usbdcd_driver.req[0] = usbdev_allocreq(usbdcd_driver.ep[0], 64);
+ if (usbdcd_driver.req[0] == NULL) {
+ return ENOMEM;
+ }
+ #endif
usbdcd_driver.req[0]->callback = usbdcd_ep0incomplete;
@@ -295,13 +303,19 @@ bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const *p_endpoint_desc)
}
usbdcd_driver.req[epnum] = NULL;
+
+ #ifdef EP_ALLOCREQ
+ // sdk v2
usbdcd_driver.req[epnum] = EP_ALLOCREQ(usbdcd_driver.ep[epnum]);
- if (usbdcd_driver.req[epnum] != NULL)
- {
+ if (usbdcd_driver.req[epnum] != NULL) {
usbdcd_driver.req[epnum]->len = ep_mps;
}
- else
- {
+ #else
+ // sdk v3
+ usbdcd_driver.req[epnum] = usbdev_allocreq(usbdcd_driver.ep[epnum], ep_mps);
+ #endif
+
+ if(usbdcd_driver.req[epnum] == NULL) {
return false;
}
diff --git a/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c b/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c
index 9c37f1f98..7bf726f3f 100644
--- a/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c
+++ b/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c
@@ -109,7 +109,7 @@
#ifdef TUP_USBIP_FSDEV_STM32
// Undefine to reduce the dependence on HAL
#undef USE_HAL_DRIVER
- #include "portable/st/stm32_fsdev/dcd_stm32_fsdev_pvt_st.h"
+ #include "portable/st/stm32_fsdev/dcd_stm32_fsdev.h"
#endif
/*****************************************************
@@ -200,8 +200,7 @@ static bool dcd_read_packet_memory_ff(tu_fifo_t * ff, uint16_t src, uint16_t wNB
// Inline helper
//--------------------------------------------------------------------+
-TU_ATTR_ALWAYS_INLINE static inline xfer_ctl_t* xfer_ctl_ptr(uint32_t ep_addr)
-{
+TU_ATTR_ALWAYS_INLINE static inline xfer_ctl_t* xfer_ctl_ptr(uint32_t ep_addr) {
uint8_t epnum = tu_edpt_number(ep_addr);
uint8_t dir = tu_edpt_dir(ep_addr);
// Fix -Werror=null-dereference
@@ -524,7 +523,7 @@ static void dcd_ep_ctr_tx_handler(uint32_t wIstr)
xfer_ctl_t * xfer = xfer_ctl_ptr(ep_addr);
if((xfer->total_len != xfer->queued_len)) /* TX not complete */
{
- dcd_transmit_packet(xfer, EPindex);
+ dcd_transmit_packet(xfer, EPindex);
}
else /* TX Complete */
{
@@ -533,10 +532,29 @@ static void dcd_ep_ctr_tx_handler(uint32_t wIstr)
}
// Handle CTR interrupt for the RX/OUT direction
-//
// Upon call, (wIstr & USB_ISTR_DIR) == 0U
-static void dcd_ep_ctr_rx_handler(uint32_t wIstr)
-{
+static void dcd_ep_ctr_rx_handler(uint32_t wIstr) {
+ #ifdef FSDEV_BUS_32BIT
+ /* https://www.st.com/resource/en/errata_sheet/es0561-stm32h503cbebkbrb-device-errata-stmicroelectronics.pdf
+ * From STM32H503 errata 2.15.1: Buffer description table update completes after CTR interrupt triggers
+ * Description:
+ * - During OUT transfers, the correct transfer interrupt (CTR) is triggered a little before the last USB SRAM accesses
+ * have completed. If the software responds quickly to the interrupt, the full buffer contents may not be correct.
+ * Workaround:
+ * - Software should ensure that a small delay is included before accessing the SRAM contents. This delay
+ * should be 800 ns in Full Speed mode and 6.4 μs in Low Speed mode
+ * - Since H5 can run up to 250Mhz -> 1 cycle = 4ns. Per errata, we need to wait 200 cycles. Though executing code
+ * also takes time, so we'll wait 40 cycles (count = 20).
+ * - Since Low Speed mode is not supported/popular, we will ignore it for now.
+ *
+ * Note: this errata also seems to apply to G0, U5, H5 etc.
+ */
+ volatile uint32_t cycle_count = 20; // defined as PCD_RX_PMA_CNT in stm32 hal_driver
+ while (cycle_count > 0U) {
+ cycle_count--; // each count take 2 cycle (1 cycle for sub, 1 cycle for compare/jump)
+ }
+ #endif
+
uint32_t EPindex = wIstr & USB_ISTR_EP_ID;
uint32_t wEPRegVal = pcd_get_endpoint(USB, EPindex);
uint8_t ep_addr = wEPRegVal & USB_EPADDR_FIELD;
@@ -545,8 +563,7 @@ static void dcd_ep_ctr_rx_handler(uint32_t wIstr)
// Verify the CTR_RX bit is set. This was in the ST Micro code,
// but I'm not sure it's actually necessary?
- if((wEPRegVal & USB_EP_CTR_RX) == 0U)
- {
+ if((wEPRegVal & USB_EP_CTR_RX) == 0U) {
return;
}
@@ -633,26 +650,22 @@ static void dcd_ep_ctr_rx_handler(uint32_t wIstr)
// (Based on the docs, it seems SETUP will always be accepted after CTR is cleared)
if(ep_addr == 0u)
{
- // Always be prepared for a status packet...
+ // Always be prepared for a status packet...
pcd_set_ep_rx_bufsize(USB, EPindex, CFG_TUD_ENDPOINT0_SIZE);
pcd_clear_rx_ep_ctr(USB, EPindex);
}
}
-static void dcd_ep_ctr_handler(void)
-{
+static void dcd_ep_ctr_handler(void) {
uint32_t wIstr;
/* stay in loop while pending interrupts */
- while (((wIstr = USB->ISTR) & USB_ISTR_CTR) != 0U)
- {
-
- if ((wIstr & USB_ISTR_DIR) == 0U) /* TX/IN */
- {
+ while (((wIstr = USB->ISTR) & USB_ISTR_CTR) != 0U) {
+ if ((wIstr & USB_ISTR_DIR) == 0U) {
+ /* TX/IN */
dcd_ep_ctr_tx_handler(wIstr);
- }
- else /* RX/OUT*/
- {
+ } else {
+ /* RX/OUT*/
dcd_ep_ctr_rx_handler(wIstr);
}
}
diff --git a/src/portable/st/stm32_fsdev/dcd_stm32_fsdev_pvt_st.h b/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.h
index 3f4db985d..946ad2c7c 100644
--- a/src/portable/st/stm32_fsdev/dcd_stm32_fsdev_pvt_st.h
+++ b/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.h
@@ -1,30 +1,32 @@
-/**
- * Copyright(c) 2016 STMicroelectronics
- * Copyright(c) N Conrad
- *
- * Redistribution and use in source and binary forms, with or without modification,
- * are permitted provided that the following conditions are met:
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- * 3. Neither the name of STMicroelectronics nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
+/*
+ * Copyright(c) 2016 STMicroelectronics
+ * Copyright(c) N Conrad
+ * Copyright (c) 2019 Ha Thach (tinyusb.org)
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of STMicroelectronics nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * This file is part of the TinyUSB stack.
+ */
// This file contains source copied from ST's HAL, and thus should have their copyright statement.
@@ -113,6 +115,11 @@
#elif CFG_TUSB_MCU == OPT_MCU_STM32H5
#include "stm32h5xx.h"
#define FSDEV_BUS_32BIT
+
+ #if !defined(USB_DRD_BASE) && defined(USB_DRD_FS_BASE)
+ #define USB_DRD_BASE USB_DRD_FS_BASE
+ #endif
+
#define FSDEV_PMA_SIZE (2048u)
#undef USB_PMAADDR
#define USB_PMAADDR USB_DRD_PMAADDR
@@ -138,7 +145,6 @@
#define USB_CNTR_LPMODE USB_CNTR_SUSPRDY
#define USB_CNTR_FSUSP USB_CNTR_SUSPEN
-
#elif CFG_TUSB_MCU == OPT_MCU_STM32WB
#include "stm32wbxx.h"
#define FSDEV_PMA_SIZE (1024u)
@@ -182,27 +188,23 @@ typedef uint16_t fsdev_bus_t;
// Volatile is also needed to prevent the optimizer from changing access to 32-bit (as 32-bit access is forbidden)
static __IO uint16_t * const pma = (__IO uint16_t*)USB_PMAADDR;
-TU_ATTR_ALWAYS_INLINE static inline __IO uint16_t * pcd_btable_word_ptr(USB_TypeDef * USBx, size_t x)
-{
+TU_ATTR_ALWAYS_INLINE static inline __IO uint16_t * pcd_btable_word_ptr(USB_TypeDef * USBx, size_t x) {
size_t total_word_offset = (((USBx)->BTABLE)>>1) + x;
total_word_offset *= FSDEV_PMA_STRIDE;
return &(pma[total_word_offset]);
}
-TU_ATTR_ALWAYS_INLINE static inline __IO uint16_t* pcd_ep_tx_cnt_ptr(USB_TypeDef * USBx, uint32_t bEpIdx)
-{
+TU_ATTR_ALWAYS_INLINE static inline __IO uint16_t* pcd_ep_tx_cnt_ptr(USB_TypeDef * USBx, uint32_t bEpIdx) {
return pcd_btable_word_ptr(USBx,(bEpIdx)*4u + 1u);
}
-TU_ATTR_ALWAYS_INLINE static inline __IO uint16_t* pcd_ep_rx_cnt_ptr(USB_TypeDef * USBx, uint32_t bEpIdx)
-{
+TU_ATTR_ALWAYS_INLINE static inline __IO uint16_t* pcd_ep_rx_cnt_ptr(USB_TypeDef * USBx, uint32_t bEpIdx) {
return pcd_btable_word_ptr(USBx,(bEpIdx)*4u + 3u);
}
#endif
/* Aligned buffer size according to hardware */
-TU_ATTR_ALWAYS_INLINE static inline uint16_t pcd_aligned_buffer_size(uint16_t size)
-{
+TU_ATTR_ALWAYS_INLINE static inline uint16_t pcd_aligned_buffer_size(uint16_t size) {
/* The STM32 full speed USB peripheral supports only a limited set of
* buffer sizes given by the RX buffer entry format in the USB_BTABLE. */
uint16_t blocksize = (size > 62) ? 32 : 2;
@@ -213,9 +215,7 @@ TU_ATTR_ALWAYS_INLINE static inline uint16_t pcd_aligned_buffer_size(uint16_t si
return numblocks * blocksize;
}
-/* SetENDPOINT */
-TU_ATTR_ALWAYS_INLINE static inline void pcd_set_endpoint(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t wRegValue)
-{
+TU_ATTR_ALWAYS_INLINE static inline void pcd_set_endpoint(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t wRegValue) {
#ifdef FSDEV_BUS_32BIT
(void) USBx;
__O uint32_t *reg = (__O uint32_t *)(USB_DRD_BASE + bEpIdx*4);
@@ -226,7 +226,6 @@ TU_ATTR_ALWAYS_INLINE static inline void pcd_set_endpoint(USB_TypeDef * USBx, ui
#endif
}
-/* GetENDPOINT */
TU_ATTR_ALWAYS_INLINE static inline uint32_t pcd_get_endpoint(USB_TypeDef * USBx, uint32_t bEpIdx) {
#ifdef FSDEV_BUS_32BIT
(void) USBx;
@@ -237,8 +236,7 @@ TU_ATTR_ALWAYS_INLINE static inline uint32_t pcd_get_endpoint(USB_TypeDef * USBx
return *reg;
}
-TU_ATTR_ALWAYS_INLINE static inline void pcd_set_eptype(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t wType)
-{
+TU_ATTR_ALWAYS_INLINE static inline void pcd_set_eptype(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t wType) {
uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx);
regVal &= (uint32_t)USB_EP_T_MASK;
regVal |= wType;
@@ -246,20 +244,19 @@ TU_ATTR_ALWAYS_INLINE static inline void pcd_set_eptype(USB_TypeDef * USBx, uint
pcd_set_endpoint(USBx, bEpIdx, regVal);
}
-TU_ATTR_ALWAYS_INLINE static inline uint32_t pcd_get_eptype(USB_TypeDef * USBx, uint32_t bEpIdx)
-{
+TU_ATTR_ALWAYS_INLINE static inline uint32_t pcd_get_eptype(USB_TypeDef * USBx, uint32_t bEpIdx) {
uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx);
regVal &= USB_EP_T_FIELD;
return regVal;
}
+
/**
* @brief Clears bit CTR_RX / CTR_TX in the endpoint register.
* @param USBx USB peripheral instance register address.
* @param bEpIdx Endpoint Number.
* @retval None
*/
-TU_ATTR_ALWAYS_INLINE static inline void pcd_clear_rx_ep_ctr(USB_TypeDef * USBx, uint32_t bEpIdx)
-{
+TU_ATTR_ALWAYS_INLINE static inline void pcd_clear_rx_ep_ctr(USB_TypeDef * USBx, uint32_t bEpIdx) {
uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx);
regVal &= USB_EPREG_MASK;
regVal &= ~USB_EP_CTR_RX;
@@ -267,22 +264,21 @@ TU_ATTR_ALWAYS_INLINE static inline void pcd_clear_rx_ep_ctr(USB_TypeDef * USBx,
pcd_set_endpoint(USBx, bEpIdx, regVal);
}
-TU_ATTR_ALWAYS_INLINE static inline void pcd_clear_tx_ep_ctr(USB_TypeDef * USBx, uint32_t bEpIdx)
-{
+TU_ATTR_ALWAYS_INLINE static inline void pcd_clear_tx_ep_ctr(USB_TypeDef * USBx, uint32_t bEpIdx) {
uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx);
regVal &= USB_EPREG_MASK;
regVal &= ~USB_EP_CTR_TX;
regVal |= USB_EP_CTR_RX; // preserve CTR_RX (clears on writing 0)
pcd_set_endpoint(USBx, bEpIdx,regVal);
}
+
/**
* @brief gets counter of the tx buffer.
* @param USBx USB peripheral instance register address.
* @param bEpIdx Endpoint Number.
* @retval Counter value
*/
-TU_ATTR_ALWAYS_INLINE static inline uint32_t pcd_get_ep_tx_cnt(USB_TypeDef * USBx, uint32_t bEpIdx)
-{
+TU_ATTR_ALWAYS_INLINE static inline uint32_t pcd_get_ep_tx_cnt(USB_TypeDef * USBx, uint32_t bEpIdx) {
#ifdef FSDEV_BUS_32BIT
(void) USBx;
return (pma32[2*bEpIdx] & 0x03FF0000) >> 16;
@@ -292,8 +288,7 @@ TU_ATTR_ALWAYS_INLINE static inline uint32_t pcd_get_ep_tx_cnt(USB_TypeDef * USB
#endif
}
-TU_ATTR_ALWAYS_INLINE static inline uint32_t pcd_get_ep_rx_cnt(USB_TypeDef * USBx, uint32_t bEpIdx)
-{
+TU_ATTR_ALWAYS_INLINE static inline uint32_t pcd_get_ep_rx_cnt(USB_TypeDef * USBx, uint32_t bEpIdx) {
#ifdef FSDEV_BUS_32BIT
(void) USBx;
return (pma32[2*bEpIdx + 1] & 0x03FF0000) >> 16;
@@ -310,8 +305,7 @@ TU_ATTR_ALWAYS_INLINE static inline uint32_t pcd_get_ep_rx_cnt(USB_TypeDef * USB
* @param bAddr Address.
* @retval None
*/
-TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_address(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t bAddr)
-{
+TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_address(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t bAddr) {
uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx);
regVal &= USB_EPREG_MASK;
regVal |= bAddr;
@@ -319,8 +313,7 @@ TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_address(USB_TypeDef * USBx,
pcd_set_endpoint(USBx, bEpIdx,regVal);
}
-TU_ATTR_ALWAYS_INLINE static inline uint32_t pcd_get_ep_tx_address(USB_TypeDef * USBx, uint32_t bEpIdx)
-{
+TU_ATTR_ALWAYS_INLINE static inline uint32_t pcd_get_ep_tx_address(USB_TypeDef * USBx, uint32_t bEpIdx) {
#ifdef FSDEV_BUS_32BIT
(void) USBx;
return pma32[2*bEpIdx] & 0x0000FFFFu ;
@@ -329,8 +322,7 @@ TU_ATTR_ALWAYS_INLINE static inline uint32_t pcd_get_ep_tx_address(USB_TypeDef *
#endif
}
-TU_ATTR_ALWAYS_INLINE static inline uint32_t pcd_get_ep_rx_address(USB_TypeDef * USBx, uint32_t bEpIdx)
-{
+TU_ATTR_ALWAYS_INLINE static inline uint32_t pcd_get_ep_rx_address(USB_TypeDef * USBx, uint32_t bEpIdx) {
#ifdef FSDEV_BUS_32BIT
(void) USBx;
return pma32[2*bEpIdx + 1] & 0x0000FFFFu;
@@ -339,8 +331,7 @@ TU_ATTR_ALWAYS_INLINE static inline uint32_t pcd_get_ep_rx_address(USB_TypeDef *
#endif
}
-TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_tx_address(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t addr)
-{
+TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_tx_address(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t addr) {
#ifdef FSDEV_BUS_32BIT
(void) USBx;
pma32[2*bEpIdx] = (pma32[2*bEpIdx] & 0xFFFF0000u) | (addr & 0x0000FFFCu);
@@ -349,8 +340,7 @@ TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_tx_address(USB_TypeDef * USB
#endif
}
-TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_rx_address(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t addr)
-{
+TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_rx_address(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t addr) {
#ifdef FSDEV_BUS_32BIT
(void) USBx;
pma32[2*bEpIdx + 1] = (pma32[2*bEpIdx + 1] & 0xFFFF0000u) | (addr & 0x0000FFFCu);
@@ -359,8 +349,7 @@ TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_rx_address(USB_TypeDef * USB
#endif
}
-TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_tx_cnt(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t wCount)
-{
+TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_tx_cnt(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t wCount) {
#ifdef FSDEV_BUS_32BIT
(void) USBx;
pma32[2*bEpIdx] = (pma32[2*bEpIdx] & ~0x03FF0000u) | ((wCount & 0x3FFu) << 16);
@@ -370,8 +359,7 @@ TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_tx_cnt(USB_TypeDef * USBx, u
#endif
}
-TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_rx_cnt(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t wCount)
-{
+TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_rx_cnt(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t wCount) {
#ifdef FSDEV_BUS_32BIT
(void) USBx;
pma32[2*bEpIdx + 1] = (pma32[2*bEpIdx + 1] & ~0x03FF0000u) | ((wCount & 0x3FFu) << 16);
@@ -381,8 +369,8 @@ TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_rx_cnt(USB_TypeDef * USBx, u
#endif
}
-TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_blsize_num_blocks(USB_TypeDef * USBx, uint32_t rxtx_idx, uint32_t blocksize, uint32_t numblocks)
-{
+TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_blsize_num_blocks(USB_TypeDef * USBx, uint32_t rxtx_idx,
+ uint32_t blocksize, uint32_t numblocks) {
/* Encode into register. When BLSIZE==1, we need to subtract 1 block count */
#ifdef FSDEV_BUS_32BIT
(void) USBx;
@@ -393,8 +381,7 @@ TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_blsize_num_blocks(USB_TypeDe
#endif
}
-TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_bufsize(USB_TypeDef * USBx, uint32_t rxtx_idx, uint32_t wCount)
-{
+TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_bufsize(USB_TypeDef * USBx, uint32_t rxtx_idx, uint32_t wCount) {
wCount = pcd_aligned_buffer_size(wCount);
/* We assume that the buffer size is already aligned to hardware requirements. */
@@ -408,13 +395,11 @@ TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_bufsize(USB_TypeDef * USBx,
pcd_set_ep_blsize_num_blocks(USBx, rxtx_idx, blocksize, numblocks);
}
-TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_tx_bufsize(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t wCount)
-{
+TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_tx_bufsize(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t wCount) {
pcd_set_ep_bufsize(USBx, 2*bEpIdx, wCount);
}
-TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_rx_bufsize(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t wCount)
-{
+TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_rx_bufsize(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t wCount) {
pcd_set_ep_bufsize(USBx, 2*bEpIdx + 1, wCount);
}
@@ -425,8 +410,7 @@ TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_rx_bufsize(USB_TypeDef * USB
* @param wState new state
* @retval None
*/
-TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_tx_status(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t wState)
-{
+TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_tx_status(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t wState) {
uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx);
regVal &= USB_EPTX_DTOGMASK;
@@ -443,7 +427,7 @@ TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_tx_status(USB_TypeDef * USBx
regVal |= USB_EP_CTR_RX|USB_EP_CTR_TX;
pcd_set_endpoint(USBx, bEpIdx, regVal);
-} /* pcd_set_ep_tx_status */
+}
/**
* @brief sets the status for rx transfer (bits STAT_TX[1:0])
@@ -453,31 +437,27 @@ TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_tx_status(USB_TypeDef * USBx
* @retval None
*/
-TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_rx_status(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t wState)
-{
+TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_rx_status(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t wState) {
uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx);
regVal &= USB_EPRX_DTOGMASK;
/* toggle first bit ? */
- if((USB_EPRX_DTOG1 & wState)!= 0U)
- {
+ if((USB_EPRX_DTOG1 & wState)!= 0U) {
regVal ^= USB_EPRX_DTOG1;
}
/* toggle second bit ? */
- if((USB_EPRX_DTOG2 & wState)!= 0U)
- {
+ if((USB_EPRX_DTOG2 & wState)!= 0U) {
regVal ^= USB_EPRX_DTOG2;
}
regVal |= USB_EP_CTR_RX|USB_EP_CTR_TX;
pcd_set_endpoint(USBx, bEpIdx, regVal);
-} /* pcd_set_ep_rx_status */
+}
-TU_ATTR_ALWAYS_INLINE static inline uint32_t pcd_get_ep_rx_status(USB_TypeDef * USBx, uint32_t bEpIdx)
-{
+TU_ATTR_ALWAYS_INLINE static inline uint32_t pcd_get_ep_rx_status(USB_TypeDef * USBx, uint32_t bEpIdx) {
uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx);
return (regVal & USB_EPRX_STAT) >> (12u);
-} /* pcd_get_ep_rx_status */
+}
/**
@@ -486,16 +466,14 @@ TU_ATTR_ALWAYS_INLINE static inline uint32_t pcd_get_ep_rx_status(USB_TypeDef *
* @param bEpIdx Endpoint Number.
* @retval None
*/
-TU_ATTR_ALWAYS_INLINE static inline void pcd_rx_dtog(USB_TypeDef * USBx, uint32_t bEpIdx)
-{
+TU_ATTR_ALWAYS_INLINE static inline void pcd_rx_dtog(USB_TypeDef * USBx, uint32_t bEpIdx) {
uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx);
regVal &= USB_EPREG_MASK;
regVal |= USB_EP_CTR_RX|USB_EP_CTR_TX|USB_EP_DTOG_RX;
pcd_set_endpoint(USBx, bEpIdx, regVal);
}
-TU_ATTR_ALWAYS_INLINE static inline void pcd_tx_dtog(USB_TypeDef * USBx, uint32_t bEpIdx)
-{
+TU_ATTR_ALWAYS_INLINE static inline void pcd_tx_dtog(USB_TypeDef * USBx, uint32_t bEpIdx) {
uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx);
regVal &= USB_EPREG_MASK;
regVal |= USB_EP_CTR_RX|USB_EP_CTR_TX|USB_EP_DTOG_TX;
@@ -508,21 +486,16 @@ TU_ATTR_ALWAYS_INLINE static inline void pcd_tx_dtog(USB_TypeDef * USBx, uint32
* @param bEpIdx Endpoint Number.
* @retval None
*/
-
-TU_ATTR_ALWAYS_INLINE static inline void pcd_clear_rx_dtog(USB_TypeDef * USBx, uint32_t bEpIdx)
-{
+TU_ATTR_ALWAYS_INLINE static inline void pcd_clear_rx_dtog(USB_TypeDef * USBx, uint32_t bEpIdx) {
uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx);
- if((regVal & USB_EP_DTOG_RX) != 0)
- {
+ if((regVal & USB_EP_DTOG_RX) != 0) {
pcd_rx_dtog(USBx,bEpIdx);
}
}
-TU_ATTR_ALWAYS_INLINE static inline void pcd_clear_tx_dtog(USB_TypeDef * USBx, uint32_t bEpIdx)
-{
+TU_ATTR_ALWAYS_INLINE static inline void pcd_clear_tx_dtog(USB_TypeDef * USBx, uint32_t bEpIdx) {
uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx);
- if((regVal & USB_EP_DTOG_TX) != 0)
- {
+ if((regVal & USB_EP_DTOG_TX) != 0) {
pcd_tx_dtog(USBx,bEpIdx);
}
}
@@ -533,17 +506,15 @@ TU_ATTR_ALWAYS_INLINE static inline void pcd_clear_tx_dtog(USB_TypeDef * USBx,
* @param bEpIdx Endpoint Number.
* @retval None
*/
-
-TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_kind(USB_TypeDef * USBx, uint32_t bEpIdx)
-{
+TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_kind(USB_TypeDef * USBx, uint32_t bEpIdx) {
uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx);
regVal |= USB_EP_KIND;
regVal &= USB_EPREG_MASK;
regVal |= USB_EP_CTR_RX|USB_EP_CTR_TX;
pcd_set_endpoint(USBx, bEpIdx, regVal);
}
-TU_ATTR_ALWAYS_INLINE static inline void pcd_clear_ep_kind(USB_TypeDef * USBx, uint32_t bEpIdx)
-{
+
+TU_ATTR_ALWAYS_INLINE static inline void pcd_clear_ep_kind(USB_TypeDef * USBx, uint32_t bEpIdx) {
uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx);
regVal &= USB_EPKIND_MASK;
regVal |= USB_EP_CTR_RX|USB_EP_CTR_TX;
diff --git a/src/portable/synopsys/dwc2/dcd_dwc2.c b/src/portable/synopsys/dwc2/dcd_dwc2.c
index 3e15d51c6..cf8f3be50 100644
--- a/src/portable/synopsys/dwc2/dcd_dwc2.c
+++ b/src/portable/synopsys/dwc2/dcd_dwc2.c
@@ -102,7 +102,13 @@ static bool _out_ep_closed; // Flag to check if RX FIFO size n
// SOF enabling flag - required for SOF to not get disabled in ISR when SOF was enabled by
static bool _sof_en;
-// Calculate the RX FIFO size according to recommendations from reference manual
+// Calculate the RX FIFO size according to minimum recommendations from reference manual
+// RxFIFO = (5 * number of control endpoints + 8) +
+// ((largest USB packet used / 4) + 1 for status information) +
+// (2 * number of OUT endpoints) + 1 for Global NAK
+// with number of control endpoints = 1 we have
+// RxFIFO = 15 + (largest USB packet used / 4) + 2 * number of OUT endpoints
+// we double the largest USB packet size to be able to hold up to 2 packets
static inline uint16_t calc_grxfsiz(uint16_t max_ep_size, uint8_t ep_count) {
return 15 + 2 * (max_ep_size / 4) + 2 * ep_count;
}
@@ -121,6 +127,141 @@ static void update_grxfsiz(uint8_t rhport) {
dwc2->grxfsiz = calc_grxfsiz(max_epsize, ep_count);
}
+static bool fifo_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t packet_size) {
+ dwc2_regs_t* dwc2 = DWC2_REG(rhport);
+ uint8_t const ep_count = _dwc2_controller[rhport].ep_count;
+ uint8_t const epnum = tu_edpt_number(ep_addr);
+ uint8_t const dir = tu_edpt_dir(ep_addr);
+
+ TU_ASSERT(epnum < ep_count);
+
+ uint16_t const fifo_size = tu_div_ceil(packet_size, 4);
+
+ // "USB Data FIFOs" section in reference manual
+ // Peripheral FIFO architecture
+ //
+ // --------------- 320 or 1024 ( 1280 or 4096 bytes )
+ // | IN FIFO 0 |
+ // --------------- (320 or 1024) - 16
+ // | IN FIFO 1 |
+ // --------------- (320 or 1024) - 16 - x
+ // | . . . . |
+ // --------------- (320 or 1024) - 16 - x - y - ... - z
+ // | IN FIFO MAX |
+ // ---------------
+ // | FREE |
+ // --------------- GRXFSIZ
+ // | OUT FIFO |
+ // | ( Shared ) |
+ // --------------- 0
+ //
+ // In FIFO is allocated by following rules:
+ // - IN EP 1 gets FIFO 1, IN EP "n" gets FIFO "n".
+ if (dir == TUSB_DIR_OUT) {
+ // Calculate required size of RX FIFO
+ uint16_t const sz = calc_grxfsiz(4 * fifo_size, ep_count);
+
+ // If size_rx needs to be extended check if possible and if so enlarge it
+ if (dwc2->grxfsiz < sz) {
+ TU_ASSERT(sz + _allocated_fifo_words_tx <= _dwc2_controller[rhport].ep_fifo_size / 4);
+
+ // Enlarge RX FIFO
+ dwc2->grxfsiz = sz;
+ }
+ } else {
+ // Check if free space is available
+ TU_ASSERT(_allocated_fifo_words_tx + fifo_size + dwc2->grxfsiz <= _dwc2_controller[rhport].ep_fifo_size / 4);
+ _allocated_fifo_words_tx += fifo_size;
+ TU_LOG(DWC2_DEBUG, " Allocated %u bytes at offset %lu", fifo_size * 4,
+ _dwc2_controller[rhport].ep_fifo_size - _allocated_fifo_words_tx * 4);
+
+ // DIEPTXF starts at FIFO #1.
+ // Both TXFD and TXSA are in unit of 32-bit words.
+ dwc2->dieptxf[epnum - 1] = (fifo_size << DIEPTXF_INEPTXFD_Pos) |
+ (_dwc2_controller[rhport].ep_fifo_size / 4 - _allocated_fifo_words_tx);
+ }
+
+ return true;
+}
+
+static void edpt_activate(uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc) {
+ dwc2_regs_t* dwc2 = DWC2_REG(rhport);
+ uint8_t const epnum = tu_edpt_number(p_endpoint_desc->bEndpointAddress);
+ uint8_t const dir = tu_edpt_dir(p_endpoint_desc->bEndpointAddress);
+
+ xfer_ctl_t* xfer = XFER_CTL_BASE(epnum, dir);
+ xfer->max_size = tu_edpt_packet_size(p_endpoint_desc);
+ xfer->interval = p_endpoint_desc->bInterval;
+
+ // USBAEP, EPTYP, SD0PID_SEVNFRM, MPSIZ are the same for IN and OUT endpoints.
+ uint32_t const dxepctl = (1 << DOEPCTL_USBAEP_Pos) |
+ (p_endpoint_desc->bmAttributes.xfer << DOEPCTL_EPTYP_Pos) |
+ (p_endpoint_desc->bmAttributes.xfer != TUSB_XFER_ISOCHRONOUS ? DOEPCTL_SD0PID_SEVNFRM : 0) |
+ (xfer->max_size << DOEPCTL_MPSIZ_Pos);
+
+ if (dir == TUSB_DIR_OUT) {
+ dwc2->epout[epnum].doepctl |= dxepctl;
+ dwc2->daintmsk |= TU_BIT(DAINTMSK_OEPM_Pos + epnum);
+ } else {
+ dwc2->epin[epnum].diepctl |= dxepctl | (epnum << DIEPCTL_TXFNUM_Pos);
+ dwc2->daintmsk |= (1 << (DAINTMSK_IEPM_Pos + epnum));
+ }
+}
+
+static void edpt_disable(uint8_t rhport, uint8_t ep_addr, bool stall) {
+ (void) rhport;
+
+ dwc2_regs_t* dwc2 = DWC2_REG(rhport);
+ uint8_t const epnum = tu_edpt_number(ep_addr);
+ uint8_t const dir = tu_edpt_dir(ep_addr);
+
+ if (dir == TUSB_DIR_IN) {
+ dwc2_epin_t* epin = dwc2->epin;
+
+ // Only disable currently enabled non-control endpoint
+ if ((epnum == 0) || !(epin[epnum].diepctl & DIEPCTL_EPENA)) {
+ epin[epnum].diepctl |= DIEPCTL_SNAK | (stall ? DIEPCTL_STALL : 0);
+ } else {
+ // Stop transmitting packets and NAK IN xfers.
+ epin[epnum].diepctl |= DIEPCTL_SNAK;
+ while ((epin[epnum].diepint & DIEPINT_INEPNE) == 0) {}
+
+ // Disable the endpoint.
+ epin[epnum].diepctl |= DIEPCTL_EPDIS | (stall ? DIEPCTL_STALL : 0);
+ while ((epin[epnum].diepint & DIEPINT_EPDISD_Msk) == 0) {}
+
+ epin[epnum].diepint = DIEPINT_EPDISD;
+ }
+
+ // Flush the FIFO, and wait until we have confirmed it cleared.
+ dwc2->grstctl = ((epnum << GRSTCTL_TXFNUM_Pos) | GRSTCTL_TXFFLSH);
+ while ((dwc2->grstctl & GRSTCTL_TXFFLSH_Msk) != 0) {}
+ } else {
+ dwc2_epout_t* epout = dwc2->epout;
+
+ // Only disable currently enabled non-control endpoint
+ if ((epnum == 0) || !(epout[epnum].doepctl & DOEPCTL_EPENA)) {
+ epout[epnum].doepctl |= stall ? DOEPCTL_STALL : 0;
+ } else {
+ // Asserting GONAK is required to STALL an OUT endpoint.
+ // Simpler to use polling here, we don't use the "B"OUTNAKEFF interrupt
+ // anyway, and it can't be cleared by user code. If this while loop never
+ // finishes, we have bigger problems than just the stack.
+ dwc2->dctl |= DCTL_SGONAK;
+ while ((dwc2->gintsts & GINTSTS_BOUTNAKEFF_Msk) == 0) {}
+
+ // Ditto here- disable the endpoint.
+ epout[epnum].doepctl |= DOEPCTL_EPDIS | (stall ? DOEPCTL_STALL : 0);
+ while ((epout[epnum].doepint & DOEPINT_EPDISD_Msk) == 0) {}
+
+ epout[epnum].doepint = DOEPINT_EPDISD;
+
+ // Allow other OUT endpoints to keep receiving.
+ dwc2->dctl |= DCTL_CGONAK;
+ }
+ }
+}
+
// Start of Bus Reset
static void bus_reset(uint8_t rhport) {
dwc2_regs_t* dwc2 = DWC2_REG(rhport);
@@ -139,6 +280,14 @@ static void bus_reset(uint8_t rhport) {
dwc2->epout[n].doepctl |= DOEPCTL_SNAK;
}
+ // flush all TX fifo and wait for it cleared
+ dwc2->grstctl = GRSTCTL_TXFFLSH | (0x10u << GRSTCTL_TXFNUM_Pos);
+ while (dwc2->grstctl & GRSTCTL_TXFFLSH_Msk) {}
+
+ // flush RX fifo and wait for it cleared
+ dwc2->grstctl = GRSTCTL_RXFFLSH;
+ while (dwc2->grstctl & GRSTCTL_RXFFLSH_Msk) {}
+
// 2. Set up interrupt mask
dwc2->daintmsk = TU_BIT(DAINTMSK_OEPM_Pos) | TU_BIT(DAINTMSK_IEPM_Pos);
dwc2->doepmsk = DOEPMSK_STUPM | DOEPMSK_XFRCM;
@@ -269,7 +418,6 @@ static void edpt_schedule_packets(uint8_t rhport, uint8_t const epnum, uint8_t c
/* Controller API
*------------------------------------------------------------------*/
#if CFG_TUSB_DEBUG >= DWC2_DEBUG
-
void print_dwc2_info(dwc2_regs_t* dwc2) {
// print guid, gsnpsid, ghwcfg1, ghwcfg2, ghwcfg3, ghwcfg4
// use dwc2_info.py/md for bit-field value and comparison with other ports
@@ -280,7 +428,6 @@ void print_dwc2_info(dwc2_regs_t* dwc2) {
}
TU_LOG(DWC2_DEBUG, "0x%08lX\r\n", p[5]);
}
-
#endif
static void reset_core(dwc2_regs_t* dwc2) {
@@ -462,9 +609,7 @@ void dcd_init(uint8_t rhport) {
dwc2->gotgint |= int_mask;
// Required as part of core initialization.
- // TODO: How should mode mismatch be handled? It will cause
- // the core to stop working/require reset.
- dwc2->gintmsk = GINTMSK_OTGINT | GINTMSK_MMISM | GINTMSK_RXFLVLM |
+ dwc2->gintmsk = GINTMSK_OTGINT | GINTMSK_RXFLVLM |
GINTMSK_USBSUSPM | GINTMSK_USBRST | GINTMSK_ENUMDNEM | GINTMSK_WUIM;
// Enable global interrupt
@@ -547,84 +692,8 @@ void dcd_sof_enable(uint8_t rhport, bool en) {
*------------------------------------------------------------------*/
bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const* desc_edpt) {
- (void) rhport;
-
- dwc2_regs_t* dwc2 = DWC2_REG(rhport);
- uint8_t const ep_count = _dwc2_controller[rhport].ep_count;
-
- uint8_t const epnum = tu_edpt_number(desc_edpt->bEndpointAddress);
- uint8_t const dir = tu_edpt_dir(desc_edpt->bEndpointAddress);
-
- TU_ASSERT(epnum < ep_count);
-
- xfer_ctl_t* xfer = XFER_CTL_BASE(epnum, dir);
- xfer->max_size = tu_edpt_packet_size(desc_edpt);
- xfer->interval = desc_edpt->bInterval;
-
- uint16_t const fifo_size = tu_div_ceil(xfer->max_size, 4);
-
- if (dir == TUSB_DIR_OUT) {
- // Calculate required size of RX FIFO
- uint16_t const sz = calc_grxfsiz(4 * fifo_size, ep_count);
-
- // If size_rx needs to be extended check if possible and if so enlarge it
- if (dwc2->grxfsiz < sz) {
- TU_ASSERT(sz + _allocated_fifo_words_tx <= _dwc2_controller[rhport].ep_fifo_size / 4);
-
- // Enlarge RX FIFO
- dwc2->grxfsiz = sz;
- }
-
- dwc2->epout[epnum].doepctl |= (1 << DOEPCTL_USBAEP_Pos) |
- (desc_edpt->bmAttributes.xfer << DOEPCTL_EPTYP_Pos) |
- (desc_edpt->bmAttributes.xfer != TUSB_XFER_ISOCHRONOUS ? DOEPCTL_SD0PID_SEVNFRM : 0) |
- (xfer->max_size << DOEPCTL_MPSIZ_Pos);
-
- dwc2->daintmsk |= TU_BIT(DAINTMSK_OEPM_Pos + epnum);
- } else {
- // "USB Data FIFOs" section in reference manual
- // Peripheral FIFO architecture
- //
- // --------------- 320 or 1024 ( 1280 or 4096 bytes )
- // | IN FIFO 0 |
- // --------------- (320 or 1024) - 16
- // | IN FIFO 1 |
- // --------------- (320 or 1024) - 16 - x
- // | . . . . |
- // --------------- (320 or 1024) - 16 - x - y - ... - z
- // | IN FIFO MAX |
- // ---------------
- // | FREE |
- // --------------- GRXFSIZ
- // | OUT FIFO |
- // | ( Shared ) |
- // --------------- 0
- //
- // In FIFO is allocated by following rules:
- // - IN EP 1 gets FIFO 1, IN EP "n" gets FIFO "n".
-
- // Check if free space is available
- TU_ASSERT(_allocated_fifo_words_tx + fifo_size + dwc2->grxfsiz <= _dwc2_controller[rhport].ep_fifo_size / 4);
-
- _allocated_fifo_words_tx += fifo_size;
-
- TU_LOG(DWC2_DEBUG, " Allocated %u bytes at offset %lu", fifo_size * 4,
- _dwc2_controller[rhport].ep_fifo_size - _allocated_fifo_words_tx * 4);
-
- // DIEPTXF starts at FIFO #1.
- // Both TXFD and TXSA are in unit of 32-bit words.
- dwc2->dieptxf[epnum - 1] = (fifo_size << DIEPTXF_INEPTXFD_Pos) |
- (_dwc2_controller[rhport].ep_fifo_size / 4 - _allocated_fifo_words_tx);
-
- dwc2->epin[epnum].diepctl |= (1 << DIEPCTL_USBAEP_Pos) |
- (epnum << DIEPCTL_TXFNUM_Pos) |
- (desc_edpt->bmAttributes.xfer << DIEPCTL_EPTYP_Pos) |
- (desc_edpt->bmAttributes.xfer != TUSB_XFER_ISOCHRONOUS ? DIEPCTL_SD0PID_SEVNFRM : 0) |
- (xfer->max_size << DIEPCTL_MPSIZ_Pos);
-
- dwc2->daintmsk |= (1 << (DAINTMSK_IEPM_Pos + epnum));
- }
-
+ TU_ASSERT(fifo_alloc(rhport, desc_edpt->bEndpointAddress, tu_edpt_packet_size(desc_edpt)));
+ edpt_activate(rhport, desc_edpt);
return true;
}
@@ -650,6 +719,20 @@ void dcd_edpt_close_all(uint8_t rhport) {
_allocated_fifo_words_tx = 16;
}
+bool dcd_edpt_iso_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t largest_packet_size) {
+ TU_ASSERT(fifo_alloc(rhport, ep_addr, largest_packet_size));
+ return true;
+}
+
+bool dcd_edpt_iso_activate(uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc) {
+ // Disable EP to clear potential incomplete transfers
+ edpt_disable(rhport, p_endpoint_desc->bEndpointAddress, false);
+
+ edpt_activate(rhport, p_endpoint_desc);
+
+ return true;
+}
+
bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, uint16_t total_bytes) {
uint8_t const epnum = tu_edpt_number(ep_addr);
uint8_t const dir = tu_edpt_dir(ep_addr);
@@ -707,71 +790,13 @@ bool dcd_edpt_xfer_fifo(uint8_t rhport, uint8_t ep_addr, tu_fifo_t* ff, uint16_t
return true;
}
-static void dcd_edpt_disable(uint8_t rhport, uint8_t ep_addr, bool stall) {
- (void) rhport;
-
- dwc2_regs_t* dwc2 = DWC2_REG(rhport);
-
- uint8_t const epnum = tu_edpt_number(ep_addr);
- uint8_t const dir = tu_edpt_dir(ep_addr);
-
- if (dir == TUSB_DIR_IN) {
- dwc2_epin_t* epin = dwc2->epin;
-
- // Only disable currently enabled non-control endpoint
- if ((epnum == 0) || !(epin[epnum].diepctl & DIEPCTL_EPENA)) {
- epin[epnum].diepctl |= DIEPCTL_SNAK | (stall ? DIEPCTL_STALL : 0);
- } else {
- // Stop transmitting packets and NAK IN xfers.
- epin[epnum].diepctl |= DIEPCTL_SNAK;
- while ((epin[epnum].diepint & DIEPINT_INEPNE) == 0) {}
-
- // Disable the endpoint.
- epin[epnum].diepctl |= DIEPCTL_EPDIS | (stall ? DIEPCTL_STALL : 0);
- while ((epin[epnum].diepint & DIEPINT_EPDISD_Msk) == 0) {}
-
- epin[epnum].diepint = DIEPINT_EPDISD;
- }
-
- // Flush the FIFO, and wait until we have confirmed it cleared.
- dwc2->grstctl = ((epnum << GRSTCTL_TXFNUM_Pos) | GRSTCTL_TXFFLSH);
- while ((dwc2->grstctl & GRSTCTL_TXFFLSH_Msk) != 0) {}
- } else {
- dwc2_epout_t* epout = dwc2->epout;
-
- // Only disable currently enabled non-control endpoint
- if ((epnum == 0) || !(epout[epnum].doepctl & DOEPCTL_EPENA)) {
- epout[epnum].doepctl |= stall ? DOEPCTL_STALL : 0;
- } else {
- // Asserting GONAK is required to STALL an OUT endpoint.
- // Simpler to use polling here, we don't use the "B"OUTNAKEFF interrupt
- // anyway, and it can't be cleared by user code. If this while loop never
- // finishes, we have bigger problems than just the stack.
- dwc2->dctl |= DCTL_SGONAK;
- while ((dwc2->gintsts & GINTSTS_BOUTNAKEFF_Msk) == 0) {}
-
- // Ditto here- disable the endpoint.
- epout[epnum].doepctl |= DOEPCTL_EPDIS | (stall ? DOEPCTL_STALL : 0);
- while ((epout[epnum].doepint & DOEPINT_EPDISD_Msk) == 0) {}
-
- epout[epnum].doepint = DOEPINT_EPDISD;
-
- // Allow other OUT endpoints to keep receiving.
- dwc2->dctl |= DCTL_CGONAK;
- }
- }
-}
-
-/**
- * Close an endpoint.
- */
void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr) {
dwc2_regs_t* dwc2 = DWC2_REG(rhport);
uint8_t const epnum = tu_edpt_number(ep_addr);
uint8_t const dir = tu_edpt_dir(ep_addr);
- dcd_edpt_disable(rhport, ep_addr, false);
+ edpt_disable(rhport, ep_addr, false);
// Update max_size
xfer_status[epnum][dir].max_size = 0; // max_size = 0 marks a disabled EP - required for changing FIFO allocation
@@ -789,7 +814,7 @@ void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr) {
}
void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr) {
- dcd_edpt_disable(rhport, ep_addr, true);
+ edpt_disable(rhport, ep_addr, true);
}
void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr) {
diff --git a/src/tusb.c b/src/tusb.c
index 7c86f1ca5..0092267a1 100644
--- a/src/tusb.c
+++ b/src/tusb.c
@@ -43,32 +43,30 @@
// Public API
//--------------------------------------------------------------------+
-bool tusb_init(void)
-{
-#if CFG_TUD_ENABLED && defined(TUD_OPT_RHPORT)
+bool tusb_init(void) {
+ #if CFG_TUD_ENABLED && defined(TUD_OPT_RHPORT)
// init device stack CFG_TUSB_RHPORTx_MODE must be defined
TU_ASSERT ( tud_init(TUD_OPT_RHPORT) );
-#endif
+ #endif
-#if CFG_TUH_ENABLED && defined(TUH_OPT_RHPORT)
+ #if CFG_TUH_ENABLED && defined(TUH_OPT_RHPORT)
// init host stack CFG_TUSB_RHPORTx_MODE must be defined
TU_ASSERT( tuh_init(TUH_OPT_RHPORT) );
-#endif
+ #endif
return true;
}
-bool tusb_inited(void)
-{
+bool tusb_inited(void) {
bool ret = false;
-#if CFG_TUD_ENABLED
+ #if CFG_TUD_ENABLED
ret = ret || tud_inited();
-#endif
+ #endif
-#if CFG_TUH_ENABLED
+ #if CFG_TUH_ENABLED
ret = ret || tuh_inited();
-#endif
+ #endif
return ret;
}
@@ -77,37 +75,30 @@ bool tusb_inited(void)
// Descriptor helper
//--------------------------------------------------------------------+
-uint8_t const * tu_desc_find(uint8_t const* desc, uint8_t const* end, uint8_t byte1)
-{
- while(desc+1 < end)
- {
- if ( desc[1] == byte1 ) return desc;
+uint8_t const* tu_desc_find(uint8_t const* desc, uint8_t const* end, uint8_t byte1) {
+ while (desc + 1 < end) {
+ if (desc[1] == byte1) return desc;
desc += desc[DESC_OFFSET_LEN];
}
return NULL;
}
-uint8_t const * tu_desc_find2(uint8_t const* desc, uint8_t const* end, uint8_t byte1, uint8_t byte2)
-{
- while(desc+2 < end)
- {
- if ( desc[1] == byte1 && desc[2] == byte2) return desc;
+uint8_t const* tu_desc_find2(uint8_t const* desc, uint8_t const* end, uint8_t byte1, uint8_t byte2) {
+ while (desc + 2 < end) {
+ if (desc[1] == byte1 && desc[2] == byte2) return desc;
desc += desc[DESC_OFFSET_LEN];
}
return NULL;
}
-uint8_t const * tu_desc_find3(uint8_t const* desc, uint8_t const* end, uint8_t byte1, uint8_t byte2, uint8_t byte3)
-{
- while(desc+3 < end)
- {
+uint8_t const* tu_desc_find3(uint8_t const* desc, uint8_t const* end, uint8_t byte1, uint8_t byte2, uint8_t byte3) {
+ while (desc + 3 < end) {
if (desc[1] == byte1 && desc[2] == byte2 && desc[3] == byte3) return desc;
desc += desc[DESC_OFFSET_LEN];
}
return NULL;
}
-
//--------------------------------------------------------------------+
// Endpoint Helper for both Host and Device stack
//--------------------------------------------------------------------+
@@ -126,13 +117,11 @@ bool tu_edpt_claim(tu_edpt_state_t* ep_state, osal_mutex_t mutex) {
}
(void) osal_mutex_unlock(mutex);
-
return available;
}
bool tu_edpt_release(tu_edpt_state_t* ep_state, osal_mutex_t mutex) {
(void) mutex;
-
(void) osal_mutex_lock(mutex, OSAL_TIMEOUT_WAIT_FOREVER);
// can only release the endpoint if it is claimed and not busy
@@ -142,87 +131,74 @@ bool tu_edpt_release(tu_edpt_state_t* ep_state, osal_mutex_t mutex) {
}
(void) osal_mutex_unlock(mutex);
-
return ret;
}
-bool tu_edpt_validate(tusb_desc_endpoint_t const * desc_ep, tusb_speed_t speed)
-{
+bool tu_edpt_validate(tusb_desc_endpoint_t const* desc_ep, tusb_speed_t speed) {
uint16_t const max_packet_size = tu_edpt_packet_size(desc_ep);
TU_LOG2(" Open EP %02X with Size = %u\r\n", desc_ep->bEndpointAddress, max_packet_size);
- switch (desc_ep->bmAttributes.xfer)
- {
- case TUSB_XFER_ISOCHRONOUS:
- {
+ switch (desc_ep->bmAttributes.xfer) {
+ case TUSB_XFER_ISOCHRONOUS: {
uint16_t const spec_size = (speed == TUSB_SPEED_HIGH ? 1024 : 1023);
TU_ASSERT(max_packet_size <= spec_size);
+ break;
}
- break;
case TUSB_XFER_BULK:
- if (speed == TUSB_SPEED_HIGH)
- {
+ if (speed == TUSB_SPEED_HIGH) {
// Bulk highspeed must be EXACTLY 512
TU_ASSERT(max_packet_size == 512);
- }else
- {
+ } else {
// TODO Bulk fullspeed can only be 8, 16, 32, 64
TU_ASSERT(max_packet_size <= 64);
}
- break;
+ break;
- case TUSB_XFER_INTERRUPT:
- {
+ case TUSB_XFER_INTERRUPT: {
uint16_t const spec_size = (speed == TUSB_SPEED_HIGH ? 1024 : 64);
TU_ASSERT(max_packet_size <= spec_size);
+ break;
}
- break;
- default: return false;
+ default:
+ return false;
}
return true;
}
-void tu_edpt_bind_driver(uint8_t ep2drv[][2], tusb_desc_interface_t const* desc_itf, uint16_t desc_len, uint8_t driver_id)
-{
+void tu_edpt_bind_driver(uint8_t ep2drv[][2], tusb_desc_interface_t const* desc_itf, uint16_t desc_len,
+ uint8_t driver_id) {
uint8_t const* p_desc = (uint8_t const*) desc_itf;
uint8_t const* desc_end = p_desc + desc_len;
- while( p_desc < desc_end )
- {
- if ( TUSB_DESC_ENDPOINT == tu_desc_type(p_desc) )
- {
+ while (p_desc < desc_end) {
+ if (TUSB_DESC_ENDPOINT == tu_desc_type(p_desc)) {
uint8_t const ep_addr = ((tusb_desc_endpoint_t const*) p_desc)->bEndpointAddress;
-
TU_LOG(2, " Bind EP %02x to driver id %u\r\n", ep_addr, driver_id);
ep2drv[tu_edpt_number(ep_addr)][tu_edpt_dir(ep_addr)] = driver_id;
}
-
p_desc = tu_desc_next(p_desc);
}
}
-uint16_t tu_desc_get_interface_total_len(tusb_desc_interface_t const* desc_itf, uint8_t itf_count, uint16_t max_len)
-{
+uint16_t tu_desc_get_interface_total_len(tusb_desc_interface_t const* desc_itf, uint8_t itf_count, uint16_t max_len) {
uint8_t const* p_desc = (uint8_t const*) desc_itf;
uint16_t len = 0;
- while (itf_count--)
- {
+ while (itf_count--) {
// Next on interface desc
len += tu_desc_len(desc_itf);
p_desc = tu_desc_next(p_desc);
- while (len < max_len)
- {
+ while (len < max_len) {
// return on IAD regardless of itf count
- if ( tu_desc_type(p_desc) == TUSB_DESC_INTERFACE_ASSOCIATION ) return len;
-
- if ( (tu_desc_type(p_desc) == TUSB_DESC_INTERFACE) &&
- ((tusb_desc_interface_t const*) p_desc)->bAlternateSetting == 0 )
- {
+ if (tu_desc_type(p_desc) == TUSB_DESC_INTERFACE_ASSOCIATION) {
+ return len;
+ }
+ if ((tu_desc_type(p_desc) == TUSB_DESC_INTERFACE) &&
+ ((tusb_desc_interface_t const*) p_desc)->bAlternateSetting == 0) {
break;
}
@@ -239,9 +215,8 @@ uint16_t tu_desc_get_interface_total_len(tusb_desc_interface_t const* desc_itf,
//--------------------------------------------------------------------+
bool tu_edpt_stream_init(tu_edpt_stream_t* s, bool is_host, bool is_tx, bool overwritable,
- void* ff_buf, uint16_t ff_bufsize, uint8_t* ep_buf, uint16_t ep_bufsize)
-{
- osal_mutex_t new_mutex = osal_mutex_create(&s->ff_mutex);
+ void* ff_buf, uint16_t ff_bufsize, uint8_t* ep_buf, uint16_t ep_bufsize) {
+ osal_mutex_t new_mutex = osal_mutex_create(&s->ff_mutexdef);
(void) new_mutex;
(void) is_tx;
@@ -255,92 +230,82 @@ bool tu_edpt_stream_init(tu_edpt_stream_t* s, bool is_host, bool is_tx, bool ove
return true;
}
+bool tu_edpt_stream_deinit(tu_edpt_stream_t* s) {
+ (void) s;
+ #if OSAL_MUTEX_REQUIRED
+ if (s->ff.mutex_wr) osal_mutex_delete(s->ff.mutex_wr);
+ if (s->ff.mutex_rd) osal_mutex_delete(s->ff.mutex_rd);
+ #endif
+ return true;
+}
+
TU_ATTR_ALWAYS_INLINE static inline
-bool stream_claim(tu_edpt_stream_t* s)
-{
- if (s->is_host)
- {
+bool stream_claim(tu_edpt_stream_t* s) {
+ if (s->is_host) {
#if CFG_TUH_ENABLED
return usbh_edpt_claim(s->daddr, s->ep_addr);
#endif
- }else
- {
+ } else {
#if CFG_TUD_ENABLED
return usbd_edpt_claim(s->rhport, s->ep_addr);
#endif
}
-
return false;
}
TU_ATTR_ALWAYS_INLINE static inline
-bool stream_xfer(tu_edpt_stream_t* s, uint16_t count)
-{
- if (s->is_host)
- {
+bool stream_xfer(tu_edpt_stream_t* s, uint16_t count) {
+ if (s->is_host) {
#if CFG_TUH_ENABLED
return usbh_edpt_xfer(s->daddr, s->ep_addr, count ? s->ep_buf : NULL, count);
#endif
- }else
- {
+ } else {
#if CFG_TUD_ENABLED
return usbd_edpt_xfer(s->rhport, s->ep_addr, count ? s->ep_buf : NULL, count);
#endif
}
-
return false;
}
TU_ATTR_ALWAYS_INLINE static inline
-bool stream_release(tu_edpt_stream_t* s)
-{
- if (s->is_host)
- {
+bool stream_release(tu_edpt_stream_t* s) {
+ if (s->is_host) {
#if CFG_TUH_ENABLED
return usbh_edpt_release(s->daddr, s->ep_addr);
#endif
- }else
- {
+ } else {
#if CFG_TUD_ENABLED
return usbd_edpt_release(s->rhport, s->ep_addr);
#endif
}
-
return false;
}
//--------------------------------------------------------------------+
// Stream Write
//--------------------------------------------------------------------+
-
-bool tu_edpt_stream_write_zlp_if_needed(tu_edpt_stream_t* s, uint32_t last_xferred_bytes)
-{
+bool tu_edpt_stream_write_zlp_if_needed(tu_edpt_stream_t* s, uint32_t last_xferred_bytes) {
// ZLP condition: no pending data, last transferred bytes is multiple of packet size
- TU_VERIFY( !tu_fifo_count(&s->ff) && last_xferred_bytes && (0 == (last_xferred_bytes & (s->ep_packetsize-1))) );
-
- TU_VERIFY( stream_claim(s) );
- TU_ASSERT( stream_xfer(s, 0) );
-
+ TU_VERIFY(!tu_fifo_count(&s->ff) && last_xferred_bytes && (0 == (last_xferred_bytes & (s->ep_packetsize - 1))));
+ TU_VERIFY(stream_claim(s));
+ TU_ASSERT(stream_xfer(s, 0));
return true;
}
-uint32_t tu_edpt_stream_write_xfer(tu_edpt_stream_t* s)
-{
+uint32_t tu_edpt_stream_write_xfer(tu_edpt_stream_t* s) {
// skip if no data
- TU_VERIFY( tu_fifo_count(&s->ff), 0 );
+ TU_VERIFY(tu_fifo_count(&s->ff), 0);
// Claim the endpoint
- TU_VERIFY( stream_claim(s), 0 );
+ TU_VERIFY(stream_claim(s), 0);
// Pull data from FIFO -> EP buf
uint16_t const count = tu_fifo_read_n(&s->ff, s->ep_buf, s->ep_bufsize);
- if ( count )
- {
- TU_ASSERT( stream_xfer(s, count), 0 );
+ if (count) {
+ TU_ASSERT(stream_xfer(s, count), 0);
return count;
- }else
- {
+ } else {
// Release endpoint since we don't make any transfer
// Note: data is dropped if terminal is not connected
stream_release(s);
@@ -348,16 +313,13 @@ uint32_t tu_edpt_stream_write_xfer(tu_edpt_stream_t* s)
}
}
-uint32_t tu_edpt_stream_write(tu_edpt_stream_t* s, void const *buffer, uint32_t bufsize)
-{
+uint32_t tu_edpt_stream_write(tu_edpt_stream_t* s, void const* buffer, uint32_t bufsize) {
TU_VERIFY(bufsize); // TODO support ZLP
-
uint16_t ret = tu_fifo_write_n(&s->ff, buffer, (uint16_t) bufsize);
// flush if fifo has more than packet size or
// in rare case: fifo depth is configured too small (which never reach packet size)
- if ( (tu_fifo_count(&s->ff) >= s->ep_packetsize) || (tu_fifo_depth(&s->ff) < s->ep_packetsize) )
- {
+ if ((tu_fifo_count(&s->ff) >= s->ep_packetsize) || (tu_fifo_depth(&s->ff) < s->ep_packetsize)) {
tu_edpt_stream_write_xfer(s);
}
@@ -367,9 +329,7 @@ uint32_t tu_edpt_stream_write(tu_edpt_stream_t* s, void const *buffer, uint32_t
//--------------------------------------------------------------------+
// Stream Read
//--------------------------------------------------------------------+
-
-uint32_t tu_edpt_stream_read_xfer(tu_edpt_stream_t* s)
-{
+uint32_t tu_edpt_stream_read_xfer(tu_edpt_stream_t* s) {
uint16_t available = tu_fifo_remaining(&s->ff);
// Prepare for incoming data but only allow what we can store in the ring buffer.
@@ -384,25 +344,21 @@ uint32_t tu_edpt_stream_read_xfer(tu_edpt_stream_t* s)
// get available again since fifo can be changed before endpoint is claimed
available = tu_fifo_remaining(&s->ff);
- if ( available >= s->ep_packetsize )
- {
+ if (available >= s->ep_packetsize) {
// multiple of packet size limit by ep bufsize
- uint16_t count = (uint16_t) (available & ~(s->ep_packetsize -1));
+ uint16_t count = (uint16_t) (available & ~(s->ep_packetsize - 1));
count = tu_min16(count, s->ep_bufsize);
- TU_ASSERT( stream_xfer(s, count), 0 );
-
+ TU_ASSERT(stream_xfer(s, count), 0);
return count;
- }else
- {
+ } else {
// Release endpoint since we don't make any transfer
stream_release(s);
return 0;
}
}
-uint32_t tu_edpt_stream_read(tu_edpt_stream_t* s, void* buffer, uint32_t bufsize)
-{
+uint32_t tu_edpt_stream_read(tu_edpt_stream_t* s, void* buffer, uint32_t bufsize) {
uint32_t num_read = tu_fifo_read_n(&s->ff, buffer, (uint16_t) bufsize);
tu_edpt_stream_read_xfer(s);
return num_read;
@@ -416,42 +372,35 @@ uint32_t tu_edpt_stream_read(tu_edpt_stream_t* s, void* buffer, uint32_t bufsize
#include <ctype.h>
#if CFG_TUSB_DEBUG >= CFG_TUH_LOG_LEVEL || CFG_TUSB_DEBUG >= CFG_TUD_LOG_LEVEL
-
-char const* const tu_str_speed[] = { "Full", "Low", "High" };
-char const* const tu_str_std_request[] =
-{
- "Get Status" ,
- "Clear Feature" ,
- "Reserved" ,
- "Set Feature" ,
- "Reserved" ,
- "Set Address" ,
- "Get Descriptor" ,
- "Set Descriptor" ,
- "Get Configuration" ,
- "Set Configuration" ,
- "Get Interface" ,
- "Set Interface" ,
- "Synch Frame"
+char const* const tu_str_speed[] = {"Full", "Low", "High"};
+char const* const tu_str_std_request[] = {
+ "Get Status",
+ "Clear Feature",
+ "Reserved",
+ "Set Feature",
+ "Reserved",
+ "Set Address",
+ "Get Descriptor",
+ "Set Descriptor",
+ "Get Configuration",
+ "Set Configuration",
+ "Get Interface",
+ "Set Interface",
+ "Synch Frame"
};
char const* const tu_str_xfer_result[] = {
"OK", "FAILED", "STALLED", "TIMEOUT"
};
-
#endif
-static void dump_str_line(uint8_t const* buf, uint16_t count)
-{
+static void dump_str_line(uint8_t const* buf, uint16_t count) {
tu_printf(" |");
-
// each line is 16 bytes
- for(uint16_t i=0; i<count; i++)
- {
+ for (uint16_t i = 0; i < count; i++) {
const char ch = buf[i];
tu_printf("%c", isprint(ch) ? ch : '.');
}
-
tu_printf("|\r\n");
}
@@ -460,39 +409,27 @@ static void dump_str_line(uint8_t const* buf, uint16_t count)
* - count : number of item
* - indent: prefix spaces on every line
*/
-void tu_print_mem(void const *buf, uint32_t count, uint8_t indent)
-{
+void tu_print_mem(void const* buf, uint32_t count, uint8_t indent) {
uint8_t const size = 1; // fixed 1 byte for now
-
- if ( !buf || !count )
- {
+ if (!buf || !count) {
tu_printf("NULL\r\n");
return;
}
- uint8_t const *buf8 = (uint8_t const *) buf;
-
+ uint8_t const* buf8 = (uint8_t const*) buf;
char format[] = "%00X";
- format[2] += (uint8_t) (2*size); // 1 byte = 2 hex digits
-
- const uint8_t item_per_line = 16 / size;
+ format[2] += (uint8_t) (2 * size); // 1 byte = 2 hex digits
+ const uint8_t item_per_line = 16 / size;
- for(unsigned int i=0; i<count; i++)
- {
- unsigned int value=0;
+ for (unsigned int i = 0; i < count; i++) {
+ unsigned int value = 0;
- if ( i%item_per_line == 0 )
- {
+ if (i % item_per_line == 0) {
// Print Ascii
- if ( i != 0 )
- {
- dump_str_line(buf8-16, 16);
- }
-
- for(uint8_t s=0; s < indent; s++) tu_printf(" ");
-
+ if (i != 0) dump_str_line(buf8 - 16, 16);
+ for (uint8_t s = 0; s < indent; s++) tu_printf(" ");
// print offset or absolute address
- tu_printf("%04X: ", 16*i/item_per_line);
+ tu_printf("%04X: ", 16 * i / item_per_line);
}
tu_memcpy_s(&value, sizeof(value), buf8, size);
@@ -503,19 +440,16 @@ void tu_print_mem(void const *buf, uint32_t count, uint8_t indent)
}
// fill up last row to 16 for printing ascii
- const uint32_t remain = count%16;
- uint8_t nback = (uint8_t)(remain ? remain : 16);
-
- if ( remain )
- {
- for(uint32_t i=0; i< 16-remain; i++)
- {
+ const uint32_t remain = count % 16;
+ uint8_t nback = (uint8_t) (remain ? remain : 16);
+ if (remain) {
+ for (uint32_t i = 0; i < 16 - remain; i++) {
tu_printf(" ");
- for(int j=0; j<2*size; j++) tu_printf(" ");
+ for (int j = 0; j < 2 * size; j++) tu_printf(" ");
}
}
- dump_str_line(buf8-nback, nback);
+ dump_str_line(buf8 - nback, nback);
}
#endif
diff --git a/src/tusb_option.h b/src/tusb_option.h
index 723c3bb5a..19e4cdf4b 100644
--- a/src/tusb_option.h
+++ b/src/tusb_option.h
@@ -29,9 +29,14 @@
#include "common/tusb_compiler.h"
+// Version is release as major.minor.revision eg 1.0.0. though there could be notable APIs before a new release.
+// For notable API changes within a release, we increase the build number.
#define TUSB_VERSION_MAJOR 0
#define TUSB_VERSION_MINOR 16
#define TUSB_VERSION_REVISION 0
+#define TUSB_VERSION_BUILD 2
+
+#define TUSB_VERSION_NUMBER (TUSB_VERSION_MAJOR << 24 | TUSB_VERSION_MINOR << 16 | TUSB_VERSION_REVISION << 8 | TUSB_VERSION_BUILD)
#define TUSB_VERSION_STRING TU_STRING(TUSB_VERSION_MAJOR) "." TU_STRING(TUSB_VERSION_MINOR) "." TU_STRING(TUSB_VERSION_REVISION)
//--------------------------------------------------------------------+
@@ -139,7 +144,6 @@
#define OPT_MCU_RX72N 1402 ///< Renesas RX72N
#define OPT_MCU_RAXXX 1403 ///< Renesas RAxxx families
-
// Mind Motion
#define OPT_MCU_MM32F327X 1500 ///< Mind Motion MM32F327