From 34ae21319e2e5c34d1e210e36231f695581ae05a Mon Sep 17 00:00:00 2001 From: tobozo Date: Wed, 2 Mar 2022 15:00:07 +0100 Subject: added Absolute Mouse report struct --- src/class/hid/hid.h | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'src/class') diff --git a/src/class/hid/hid.h b/src/class/hid/hid.h index 940454bd9..667ee79aa 100644 --- a/src/class/hid/hid.h +++ b/src/class/hid/hid.h @@ -300,6 +300,20 @@ typedef struct TU_ATTR_PACKED int8_t pan; // using AC Pan } hid_mouse_report_t; + +// Absolute Mouse: same as the Standard (relative) Mouse Report but +// with int16_t instead of int8_t for X and Y coordinates. +typedef struct TU_ATTR_PACKED +{ + uint8_t buttons; /**< buttons mask for currently pressed buttons in the mouse. */ + int16_t x; /**< Current x position of the mouse. */ + int16_t y; /**< Current y position of the mouse. */ + int8_t wheel; /**< Current delta wheel movement on the mouse. */ + int8_t pan; // using AC Pan +} abs_mouse_report_t; + + + /// Standard Mouse Buttons Bitmap typedef enum { -- cgit v1.3.1 From 8c79b8924eabf441f40a8ce3cab8828688575b6d Mon Sep 17 00:00:00 2001 From: tobozo Date: Wed, 2 Mar 2022 15:01:18 +0100 Subject: added Absolute Mouse descriptor template --- src/class/hid/hid_device.h | 49 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) (limited to 'src/class') diff --git a/src/class/hid/hid_device.h b/src/class/hid/hid_device.h index 078b67349..547a78f4f 100644 --- a/src/class/hid/hid_device.h +++ b/src/class/hid/hid_device.h @@ -266,6 +266,55 @@ static inline bool tud_hid_gamepad_report(uint8_t report_id, int8_t x, int8_t y HID_COLLECTION_END , \ HID_COLLECTION_END \ +// Absolute Mouse Report Descriptor Template +#define TUD_HID_REPORT_DESC_ABSMOUSE(...) \ + HID_USAGE_PAGE ( HID_USAGE_PAGE_DESKTOP ) ,\ + HID_USAGE ( HID_USAGE_DESKTOP_MOUSE ) ,\ + HID_COLLECTION ( HID_COLLECTION_APPLICATION ) ,\ + /* Report ID if any */\ + __VA_ARGS__ \ + HID_USAGE ( HID_USAGE_DESKTOP_POINTER ) ,\ + HID_COLLECTION ( HID_COLLECTION_PHYSICAL ) ,\ + HID_USAGE_PAGE ( HID_USAGE_PAGE_BUTTON ) ,\ + HID_USAGE_MIN ( 1 ) ,\ + HID_USAGE_MAX ( 5 ) ,\ + HID_LOGICAL_MIN ( 0 ) ,\ + HID_LOGICAL_MAX ( 1 ) ,\ + /* Left, Right, Middle, Backward, Forward buttons */ \ + HID_REPORT_COUNT( 5 ) ,\ + HID_REPORT_SIZE ( 1 ) ,\ + HID_INPUT ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE ) ,\ + /* 3 bit padding */ \ + HID_REPORT_COUNT( 1 ) ,\ + HID_REPORT_SIZE ( 3 ) ,\ + HID_INPUT ( HID_CONSTANT ) ,\ + HID_USAGE_PAGE ( HID_USAGE_PAGE_DESKTOP ) ,\ + /* X, Y absolute position [0, 32767] */ \ + HID_USAGE ( HID_USAGE_DESKTOP_X ) ,\ + HID_USAGE ( HID_USAGE_DESKTOP_Y ) ,\ + HID_LOGICAL_MIN ( 0x00 ) ,\ + HID_LOGICAL_MAX_N( 0x7FFF, 2 ) ,\ + HID_REPORT_SIZE ( 16 ) ,\ + HID_REPORT_COUNT ( 2 ) ,\ + HID_INPUT ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE ) ,\ + /* Vertical wheel scroll [-127, 127] */ \ + HID_USAGE ( HID_USAGE_DESKTOP_WHEEL ) ,\ + HID_LOGICAL_MIN ( 0x81 ) ,\ + HID_LOGICAL_MAX ( 0x7f ) ,\ + HID_REPORT_COUNT( 1 ) ,\ + HID_REPORT_SIZE ( 8 ) ,\ + HID_INPUT ( HID_DATA | HID_VARIABLE | HID_RELATIVE ) ,\ + HID_USAGE_PAGE ( HID_USAGE_PAGE_CONSUMER ), \ + /* Horizontal wheel scroll [-127, 127] */ \ + HID_USAGE_N ( HID_USAGE_CONSUMER_AC_PAN, 2 ), \ + HID_LOGICAL_MIN ( 0x81 ), \ + HID_LOGICAL_MAX ( 0x7f ), \ + HID_REPORT_COUNT( 1 ), \ + HID_REPORT_SIZE ( 8 ), \ + HID_INPUT ( HID_DATA | HID_VARIABLE | HID_RELATIVE ), \ + HID_COLLECTION_END , \ + HID_COLLECTION_END \ + // Consumer Control Report Descriptor Template #define TUD_HID_REPORT_DESC_CONSUMER(...) \ HID_USAGE_PAGE ( HID_USAGE_PAGE_CONSUMER ) ,\ -- cgit v1.3.1 From 9526a0ff736ccc4c8a9791a8467d6a6de82c0c45 Mon Sep 17 00:00:00 2001 From: tobozo Date: Wed, 2 Mar 2022 16:56:59 +0100 Subject: stick to struct naming convention --- src/class/hid/hid.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/class') diff --git a/src/class/hid/hid.h b/src/class/hid/hid.h index 667ee79aa..98c2ee0de 100644 --- a/src/class/hid/hid.h +++ b/src/class/hid/hid.h @@ -310,7 +310,7 @@ typedef struct TU_ATTR_PACKED int16_t y; /**< Current y position of the mouse. */ int8_t wheel; /**< Current delta wheel movement on the mouse. */ int8_t pan; // using AC Pan -} abs_mouse_report_t; +} hid_abs_mouse_report_t; -- cgit v1.3.1 From f931983469bf375eec9503b99e021b9b633bf23f Mon Sep 17 00:00:00 2001 From: Mark K Cowan Date: Sun, 23 Oct 2022 02:55:28 +0300 Subject: UAC2 supports interrupt-endpoint for providing control-change notifications to the host --- src/class/audio/audio_device.c | 58 +++++++++++++++++++++++++++++++++++++++--- src/class/audio/audio_device.h | 46 +++++++++++++++++++++++++++++---- 2 files changed, 96 insertions(+), 8 deletions(-) (limited to 'src/class') diff --git a/src/class/audio/audio_device.c b/src/class/audio/audio_device.c index a65d605b7..05339f9ce 100644 --- a/src/class/audio/audio_device.c +++ b/src/class/audio/audio_device.c @@ -341,7 +341,7 @@ typedef struct // 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_SECTION CFG_TUSB_MEM_ALIGN uint8_t ep_int_ctr_buf[CFG_TUD_AUDIO_INT_CTR_EP_IN_SW_BUFFER_SIZE]; + CFG_TUSB_MEM_ALIGN uint8_t ep_int_ctr_buf[CFG_TUD_AUDIO_INT_CTR_EP_IN_SW_BUFFER_SIZE]; #endif // Decoding parameters - parameters are set when alternate AS interface is set by host @@ -464,7 +464,7 @@ bool tud_audio_n_mounted(uint8_t func_id) if (audio->ep_in == 0) return false; #endif -#if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN +#if CFG_TUD_AUDIO_ENABLE_INTERRUPT_EP if (audio->ep_int_ctr == 0) return false; #endif @@ -813,11 +813,13 @@ 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 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_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) { + TU_VERIFY(_audiod_fct[func_id].ep_int_ctr != 0); + 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 @@ -1079,6 +1081,52 @@ static inline bool audiod_fb_send(uint8_t rhport, audiod_function_t *audio) } #endif +#if CFG_TUD_AUDIO_ENABLE_INTERRUPT_EP +static bool set_int_ctr_number(audiod_function_t *audio) +{ + + uint8_t const *p_desc = audio->p_desc; + // Get pointer at end + uint8_t const *p_desc_end = audio->p_desc + audio->desc_length - TUD_AUDIO_DESC_IAD_LEN; + + + // p_desc starts at required interface with alternate setting zero + while (p_desc < p_desc_end) + { + // Find correct interface + if (tu_desc_type(p_desc) == TUSB_DESC_INTERFACE && ((tusb_desc_interface_t const * )p_desc)->bInterfaceNumber == 0 && ((tusb_desc_interface_t const * )p_desc)->bAlternateSetting == 0) + { + + uint8_t foundEPs = 0, nEps = ((tusb_desc_interface_t const * )p_desc)->bNumEndpoints; + while (foundEPs < nEps && p_desc < p_desc_end) + { + // found :n 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 (tu_edpt_dir(ep_addr) == TUSB_DIR_IN && desc_ep->bmAttributes.xfer == 0x03) // Check if usage is interrupt EP + { + audio->ep_int_ctr = ep_addr; + TU_ASSERT(usbd_edpt_open(audio->rhport, desc_ep)); + } + + foundEPs += 1; + } + p_desc = tu_desc_next(p_desc); + } + break; + } + p_desc = tu_desc_next(p_desc); + } + + return true; + +} +#endif + //--------------------------------------------------------------------+ // USBD Driver API //--------------------------------------------------------------------+ @@ -1484,6 +1532,10 @@ uint16_t audiod_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uin // This is all we need so far - the EPs are setup by a later set_interface request (as per UAC2 specification) uint16_t drv_len = _audiod_fct[i].desc_length - TUD_AUDIO_DESC_IAD_LEN; // - TUD_AUDIO_DESC_IAD_LEN since tinyUSB already handles the IAD descriptor +#if CFG_TUD_AUDIO_ENABLE_INTERRUPT_EP + TU_ASSERT(set_int_ctr_number(&_audiod_fct[i])); +#endif + return drv_len; } diff --git a/src/class/audio/audio_device.h b/src/class/audio/audio_device.h index 0ef100fa4..0c394d235 100644 --- a/src/class/audio/audio_device.h +++ b/src/class/audio/audio_device.h @@ -191,9 +191,19 @@ #define CFG_TUD_AUDIO_ENABLE_FEEDBACK_FORMAT_CORRECTION 0 // 0 or 1 #endif +// 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 + // 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) +// Audio interrupt control - if required - 6 Bytes according to UAC 2 specification (p. 74) +#if CFG_TUD_AUDIO_ENABLE_INTERRUPT_EP +#define CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN 6 +#else +#define CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN 0 +#endif #endif #ifndef CFG_TUD_AUDIO_INT_CTR_EP_IN_SW_BUFFER_SIZE @@ -388,7 +398,7 @@ 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 +#if CFG_TUD_AUDIO_ENABLE_INTERRUPT_EP uint16_t tud_audio_int_ctr_n_write (uint8_t func_id, uint8_t const* buffer, uint16_t len); #endif @@ -431,7 +441,7 @@ 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 +#if CFG_TUD_AUDIO_ENABLE_INTERRUPT_EP static inline uint16_t tud_audio_int_ctr_write (uint8_t const* buffer, uint16_t len); #endif @@ -531,7 +541,33 @@ 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 +#if CFG_TUD_AUDIO_ENABLE_INTERRUPT_EP +// UAC2 §9.6 +// Structure of "interrupt data message" +typedef struct TU_ATTR_PACKED +{ + uint8_t bInfo; + uint8_t bAttribute; + union TU_ATTR_PACKED + { + uint16_t wValue; + struct TU_ATTR_PACKED + { + uint8_t wValue_cn_or_mcn; + uint8_t wValue_cs; + }; + }; + union TU_ATTR_PACKED + { + uint16_t wIndex; + struct TU_ATTR_PACKED + { + uint8_t wIndex_ep_or_int; + uint8_t wIndex_entity_id; + }; + }; +} audio_status_update_t; + TU_ATTR_WEAK bool tud_audio_int_ctr_done_cb(uint8_t rhport, uint16_t n_bytes_copied); #endif @@ -663,7 +699,7 @@ static inline tu_fifo_t* tud_audio_get_tx_support_ff(uint8_t ff_idx) #endif -#if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN +#if CFG_TUD_AUDIO_ENABLE_INTERRUPT_EP static inline uint16_t tud_audio_int_ctr_write(uint8_t const* buffer, uint16_t len) { return tud_audio_int_ctr_n_write(0, buffer, len); -- cgit v1.3.1 From 025d3477e81e07ddc2db78193e8957cdb1050516 Mon Sep 17 00:00:00 2001 From: Mark K Cowan Date: Mon, 24 Oct 2022 20:41:09 +0300 Subject: fixed spec reference --- src/class/audio/audio_device.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'src/class') diff --git a/src/class/audio/audio_device.h b/src/class/audio/audio_device.h index 0c394d235..92a1e6585 100644 --- a/src/class/audio/audio_device.h +++ b/src/class/audio/audio_device.h @@ -542,8 +542,7 @@ 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_ENABLE_INTERRUPT_EP -// UAC2 §9.6 -// Structure of "interrupt data message" +// UAC2 §6.1 "interrupt data message" typedef struct TU_ATTR_PACKED { uint8_t bInfo; -- cgit v1.3.1 From 15ed45e1a33210c5e949801a77aabd544fa170ed Mon Sep 17 00:00:00 2001 From: Mark K Cowan Date: Wed, 26 Oct 2022 21:40:30 +0300 Subject: clean up descriptor search for interrupt endpoint --- src/class/audio/audio_device.c | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) (limited to 'src/class') diff --git a/src/class/audio/audio_device.c b/src/class/audio/audio_device.c index 05339f9ce..efa06cf70 100644 --- a/src/class/audio/audio_device.c +++ b/src/class/audio/audio_device.c @@ -1090,40 +1090,36 @@ static bool set_int_ctr_number(audiod_function_t *audio) uint8_t const *p_desc_end = audio->p_desc + audio->desc_length - TUD_AUDIO_DESC_IAD_LEN; - // p_desc starts at required interface with alternate setting zero - while (p_desc < p_desc_end) + bool found = false; + while (!found && p_desc < p_desc_end) { - // Find correct interface - if (tu_desc_type(p_desc) == TUSB_DESC_INTERFACE && ((tusb_desc_interface_t const * )p_desc)->bInterfaceNumber == 0 && ((tusb_desc_interface_t const * )p_desc)->bAlternateSetting == 0) + // For each interface/alternate + if (tu_desc_type(p_desc) == TUSB_DESC_INTERFACE) { - uint8_t foundEPs = 0, nEps = ((tusb_desc_interface_t const * )p_desc)->bNumEndpoints; - while (foundEPs < nEps && p_desc < p_desc_end) + while (!found && foundEPs < nEps && p_desc < p_desc_end) { - // found :n endpoint + // 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 == 0x03) // Check if usage is interrupt EP { + // Store endpoint number and open endpoint audio->ep_int_ctr = ep_addr; TU_ASSERT(usbd_edpt_open(audio->rhport, desc_ep)); + found = true; } - foundEPs += 1; } p_desc = tu_desc_next(p_desc); } - break; } p_desc = tu_desc_next(p_desc); } - - return true; - + return found; } #endif -- cgit v1.3.1 From 9673d20901dd5419c82ccc14dd2fd300ca0fa8c4 Mon Sep 17 00:00:00 2001 From: Mark K Cowan Date: Wed, 26 Oct 2022 21:43:27 +0300 Subject: PanRe refactor applied: s{_int_ctr_}{_int_}g; s{_INT_CTR_}{_INT_}g; --- src/class/audio/audio_device.c | 38 +++++++++++++++++++------------------- src/class/audio/audio_device.h | 20 ++++++++++---------- 2 files changed, 29 insertions(+), 29 deletions(-) (limited to 'src/class') diff --git a/src/class/audio/audio_device.c b/src/class/audio/audio_device.c index efa06cf70..4681e1ddb 100644 --- a/src/class/audio/audio_device.c +++ b/src/class/audio/audio_device.c @@ -283,8 +283,8 @@ typedef struct #endif -#if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN - uint8_t ep_int_ctr; // Audio control interrupt EP. +#if CFG_TUD_AUDIO_INT_EPSIZE_IN + uint8_t ep_int; // Audio control interrupt EP. #endif /*------------- From this point, data is not cleared by bus reset -------------*/ @@ -340,8 +340,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_INT_EPSIZE_IN + CFG_TUSB_MEM_ALIGN uint8_t ep_int_buf[CFG_TUD_AUDIO_INT_EP_IN_SW_BUFFER_SIZE]; #endif // Decoding parameters - parameters are set when alternate AS interface is set by host @@ -465,7 +465,7 @@ bool tud_audio_n_mounted(uint8_t func_id) #endif #if CFG_TUD_AUDIO_ENABLE_INTERRUPT_EP - if (audio->ep_int_ctr == 0) return false; + if (audio->ep_int == 0) return false; #endif #if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP @@ -815,23 +815,23 @@ tu_fifo_t* tud_audio_n_get_tx_support_ff(uint8_t func_id, uint8_t ff_idx) #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_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 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 +uint16_t tud_audio_int_n_write(uint8_t func_id, uint8_t const* buffer, uint16_t len) { - TU_VERIFY(_audiod_fct[func_id].ep_int_ctr != 0); + TU_VERIFY(_audiod_fct[func_id].ep_int != 0); 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(!usbd_edpt_busy(_audiod_fct[func_id].rhport, _audiod_fct[func_id].ep_int)); // Check length - TU_VERIFY(len <= CFG_TUD_AUDIO_INT_CTR_EP_IN_SW_BUFFER_SIZE); + TU_VERIFY(len <= CFG_TUD_AUDIO_INT_EP_IN_SW_BUFFER_SIZE); - memcpy(_audiod_fct[func_id].ep_int_ctr_buf, buffer, len); + memcpy(_audiod_fct[func_id].ep_int_buf, buffer, len); // 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)); + TU_VERIFY(usbd_edpt_xfer(_audiod_fct[func_id].rhport, _audiod_fct[func_id].ep_int, _audiod_fct[func_id].ep_int_buf, len)); return true; } @@ -1082,7 +1082,7 @@ static inline bool audiod_fb_send(uint8_t rhport, audiod_function_t *audio) #endif #if CFG_TUD_AUDIO_ENABLE_INTERRUPT_EP -static bool set_int_ctr_number(audiod_function_t *audio) +static bool set_int_number(audiod_function_t *audio) { uint8_t const *p_desc = audio->p_desc; @@ -1108,7 +1108,7 @@ static bool set_int_ctr_number(audiod_function_t *audio) if (tu_edpt_dir(ep_addr) == TUSB_DIR_IN && desc_ep->bmAttributes.xfer == 0x03) // Check if usage is interrupt EP { // Store endpoint number and open endpoint - audio->ep_int_ctr = ep_addr; + audio->ep_int = ep_addr; TU_ASSERT(usbd_edpt_open(audio->rhport, desc_ep)); found = true; } @@ -1485,7 +1485,7 @@ uint16_t audiod_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uin // 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 { - TU_VERIFY(CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN > 0); + TU_VERIFY(CFG_TUD_AUDIO_INT_EPSIZE_IN > 0); } // Alternate setting MUST be zero - this check can be omitted @@ -1529,7 +1529,7 @@ uint16_t audiod_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uin uint16_t drv_len = _audiod_fct[i].desc_length - TUD_AUDIO_DESC_IAD_LEN; // - TUD_AUDIO_DESC_IAD_LEN since tinyUSB already handles the IAD descriptor #if CFG_TUD_AUDIO_ENABLE_INTERRUPT_EP - TU_ASSERT(set_int_ctr_number(&_audiod_fct[i])); + TU_ASSERT(set_int_number(&_audiod_fct[i])); #endif return drv_len; @@ -2030,10 +2030,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_INT_EPSIZE_IN // 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 ??? @@ -2042,7 +2042,7 @@ 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) TU_VERIFY(tud_audio_int_done_cb(rhport, (uint16_t) xferred_bytes)); } #endif diff --git a/src/class/audio/audio_device.h b/src/class/audio/audio_device.h index 92a1e6585..2e39e6049 100644 --- a/src/class/audio/audio_device.h +++ b/src/class/audio/audio_device.h @@ -197,17 +197,17 @@ #endif // Audio interrupt control EP size - disabled if 0 -#ifndef CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN +#ifndef CFG_TUD_AUDIO_INT_EPSIZE_IN // Audio interrupt control - if required - 6 Bytes according to UAC 2 specification (p. 74) #if CFG_TUD_AUDIO_ENABLE_INTERRUPT_EP -#define CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN 6 +#define CFG_TUD_AUDIO_INT_EPSIZE_IN 6 #else -#define CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN 0 +#define CFG_TUD_AUDIO_INT_EPSIZE_IN 0 #endif #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) +#ifndef CFG_TUD_AUDIO_INT_EP_IN_SW_BUFFER_SIZE +#define CFG_TUD_AUDIO_INT_EP_IN_SW_BUFFER_SIZE 6 // Buffer size of audio control interrupt EP - 6 Bytes according to UAC 2 specification (p. 74) #endif // Use software encoding/decoding @@ -399,7 +399,7 @@ tu_fifo_t* tud_audio_n_get_tx_support_ff (uint8_t func_id, uint8_t ff_i #endif #if CFG_TUD_AUDIO_ENABLE_INTERRUPT_EP -uint16_t tud_audio_int_ctr_n_write (uint8_t func_id, uint8_t const* buffer, uint16_t len); +uint16_t tud_audio_int_n_write (uint8_t func_id, uint8_t const* buffer, uint16_t len); #endif //--------------------------------------------------------------------+ @@ -442,7 +442,7 @@ static inline tu_fifo_t* tud_audio_get_tx_support_ff (uint8_t ff_idx); // INT CTR API #if CFG_TUD_AUDIO_ENABLE_INTERRUPT_EP -static inline uint16_t tud_audio_int_ctr_write (uint8_t const* buffer, uint16_t len); +static inline uint16_t tud_audio_int_write (uint8_t const* buffer, uint16_t len); #endif // Buffer control EP data and schedule a transmit @@ -567,7 +567,7 @@ typedef struct TU_ATTR_PACKED }; } audio_status_update_t; -TU_ATTR_WEAK bool tud_audio_int_ctr_done_cb(uint8_t rhport, uint16_t n_bytes_copied); +TU_ATTR_WEAK bool tud_audio_int_done_cb(uint8_t rhport, uint16_t n_bytes_copied); #endif // Invoked when audio set interface request received @@ -699,9 +699,9 @@ static inline tu_fifo_t* tud_audio_get_tx_support_ff(uint8_t ff_idx) #endif #if CFG_TUD_AUDIO_ENABLE_INTERRUPT_EP -static inline uint16_t tud_audio_int_ctr_write(uint8_t const* buffer, uint16_t len) +static inline uint16_t tud_audio_int_write(uint8_t const* buffer, uint16_t len) { - return tud_audio_int_ctr_n_write(0, buffer, len); + return tud_audio_int_n_write(0, buffer, len); } #endif -- cgit v1.3.1 From a77aaf7f9e8a86c904d0bf6e8994288f45b3b410 Mon Sep 17 00:00:00 2001 From: tobozo Date: Thu, 30 Mar 2023 21:57:06 +0200 Subject: Added helpers for abs_mouse_report --- src/class/hid/hid_device.c | 13 +++++++++++++ src/class/hid/hid_device.h | 12 +++++++++++- 2 files changed, 24 insertions(+), 1 deletion(-) (limited to 'src/class') diff --git a/src/class/hid/hid_device.c b/src/class/hid/hid_device.c index 9240fe2ca..7e28b2c94 100644 --- a/src/class/hid/hid_device.c +++ b/src/class/hid/hid_device.c @@ -146,6 +146,19 @@ bool tud_hid_n_mouse_report(uint8_t instance, uint8_t report_id, return tud_hid_n_report(instance, report_id, &report, sizeof(report)); } +bool tud_hid_n_abs_mouse_report(uint8_t instance, uint8_t report_id, uint8_t buttons, int16_t x, int16_t y, int8_t vertical, int8_t horizontal) +{ + hid_abs_mouse_report_t report = + { + .buttons = buttons, + .x = x, + .y = y, + .wheel = vertical, + .pan = horizontal + }; + return tud_hid_n_report(instance, report_id, &report, sizeof(report)); +} + bool tud_hid_n_gamepad_report(uint8_t instance, uint8_t report_id, int8_t x, int8_t y, int8_t z, int8_t rz, int8_t rx, int8_t ry, uint8_t hat, uint32_t buttons) { hid_gamepad_report_t report = diff --git a/src/class/hid/hid_device.h b/src/class/hid/hid_device.h index cb794e964..40755afed 100644 --- a/src/class/hid/hid_device.h +++ b/src/class/hid/hid_device.h @@ -72,6 +72,16 @@ bool tud_hid_n_keyboard_report(uint8_t instance, uint8_t report_id, uint8_t modi // use template layout report as defined by hid_mouse_report_t bool tud_hid_n_mouse_report(uint8_t instance, uint8_t report_id, uint8_t buttons, int8_t x, int8_t y, int8_t vertical, int8_t horizontal); +// ABSOLUTE MOUSE: convenient helper to send absolute mouse report if application +// use template layout report as defined by hid_abs_mouse_report_t +bool tud_hid_n_abs_mouse_report(uint8_t instance, uint8_t report_id, uint8_t buttons, int16_t x, int16_t y, int8_t vertical, int8_t horizontal); + + +static inline bool tud_hid_abs_mouse_report(uint8_t report_id, uint8_t buttons, int16_t x, int16_t y, int8_t vertical, int8_t horizontal) +{ + return tud_hid_n_abs_mouse_report(0, report_id, buttons, x, y, vertical, horizontal); +} + // Gamepad: convenient helper to send gamepad report if application // use template layout report TUD_HID_REPORT_DESC_GAMEPAD bool tud_hid_n_gamepad_report(uint8_t instance, uint8_t report_id, int8_t x, int8_t y, int8_t z, int8_t rz, int8_t rx, int8_t ry, uint8_t hat, uint32_t buttons); @@ -314,7 +324,7 @@ static inline bool tud_hid_gamepad_report(uint8_t report_id, int8_t x, int8_t y HID_INPUT ( HID_DATA | HID_VARIABLE | HID_RELATIVE ), \ HID_COLLECTION_END , \ HID_COLLECTION_END \ - + // Consumer Control Report Descriptor Template #define TUD_HID_REPORT_DESC_CONSUMER(...) \ HID_USAGE_PAGE ( HID_USAGE_PAGE_CONSUMER ) ,\ -- cgit v1.3.1 From 805ebb39249a7b96092a9c59d244152bc343d898 Mon Sep 17 00:00:00 2001 From: tobozo Date: Thu, 30 Mar 2023 22:01:36 +0200 Subject: remove trailing space (satisfy pre-commit flow) --- src/class/hid/hid.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'src/class') diff --git a/src/class/hid/hid.h b/src/class/hid/hid.h index 3e238966f..fcaab7a50 100644 --- a/src/class/hid/hid.h +++ b/src/class/hid/hid.h @@ -312,8 +312,7 @@ typedef struct TU_ATTR_PACKED int8_t pan; // using AC Pan } hid_abs_mouse_report_t; - - + /// Standard Mouse Buttons Bitmap typedef enum { -- cgit v1.3.1 From 0693462ebad20338de78aeb93d60d6c3c73a6ca7 Mon Sep 17 00:00:00 2001 From: Lars Pötter Date: Sun, 2 Jul 2023 09:02:24 +0200 Subject: made line ends consistent. --- src/class/cdc/cdc_host.c | 4 ++-- src/class/video/video_device.c | 16 +++++++------- src/common/tusb_fifo.c | 2 +- src/portable/dialog/da146xx/dcd_da146xx.c | 2 +- src/portable/mentor/musb/dcd_musb.c | 30 +++++++++++++------------- src/portable/mentor/musb/hcd_musb.c | 8 +++---- src/portable/nxp/khci/hcd_khci.c | 16 +++++++------- src/portable/raspberrypi/rp2040/hcd_rp2040.c | 4 ++-- src/portable/raspberrypi/rp2040/rp2040_usb.c | 4 ++-- src/portable/renesas/rusb2/hcd_rusb2.c | 8 +++---- src/portable/st/typec/typec_stm32.c | 18 ++++++++-------- src/portable/sunxi/dcd_sunxi_musb.c | 32 ++++++++++++++-------------- 12 files changed, 72 insertions(+), 72 deletions(-) (limited to 'src/class') diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index ce9f27c33..e1af8d801 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -973,7 +973,7 @@ static uint32_t ftdi_232bm_baud_to_divisor(uint32_t baud) static bool ftdi_sio_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { uint16_t const divisor = (uint16_t) ftdi_232bm_baud_to_divisor(baudrate); - TU_LOG_DRV("CDC FTDI Set BaudRate = %lu, divisor = 0x%04x\n", baudrate, divisor); + TU_LOG_DRV("CDC FTDI Set BaudRate = %lu, divisor = 0x%04x\r\n", baudrate, divisor); p_cdc->user_control_cb = complete_cb; _ftdi_requested_baud = baudrate; @@ -1108,7 +1108,7 @@ static bool cp210x_ifc_enable(cdch_interface_t* p_cdc, uint16_t enabled, tuh_xfe } static bool cp210x_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - TU_LOG_DRV("CDC CP210x Set BaudRate = %lu\n", baudrate); + TU_LOG_DRV("CDC CP210x Set BaudRate = %lu\r\n", baudrate); uint32_t baud_le = tu_htole32(baudrate); p_cdc->user_control_cb = complete_cb; return cp210x_set_request(p_cdc, CP210X_SET_BAUDRATE, 0, (uint8_t *) &baud_le, 4, diff --git a/src/class/video/video_device.c b/src/class/video/video_device.c index 91f452afc..16eae0ced 100644 --- a/src/class/video/video_device.c +++ b/src/class/video/video_device.c @@ -609,17 +609,17 @@ static bool _close_vc_itf(uint8_t rhport, videod_interface_t *self) * @param[in] altnum The target alternate setting number. */ static bool _open_vc_itf(uint8_t rhport, videod_interface_t *self, uint_fast8_t altnum) { - TU_LOG2(" open VC %d\n", altnum); + TU_LOG2(" open VC %d\r\n", altnum); uint8_t const *beg = self->beg; uint8_t const *end = beg + self->len; /* The first descriptor is a video control interface descriptor. */ uint8_t const *cur = _find_desc_itf(beg, end, _desc_itfnum(beg), altnum); - TU_LOG2(" cur %d\n", cur - beg); + TU_LOG2(" cur %d\r\n", cur - beg); TU_VERIFY(cur < end); tusb_desc_vc_itf_t const *vc = (tusb_desc_vc_itf_t const *)cur; - TU_LOG2(" bInCollection %d\n", vc->ctl.bInCollection); + TU_LOG2(" bInCollection %d\r\n", vc->ctl.bInCollection); /* Support for up to 2 streaming interfaces only. */ TU_ASSERT(vc->ctl.bInCollection <= CFG_TUD_VIDEO_STREAMING); @@ -628,7 +628,7 @@ static bool _open_vc_itf(uint8_t rhport, videod_interface_t *self, uint_fast8_t /* Advance to the next descriptor after the class-specific VC interface header descriptor. */ cur += vc->std.bLength + vc->ctl.bLength; - TU_LOG2(" bNumEndpoints %d\n", vc->std.bNumEndpoints); + TU_LOG2(" bNumEndpoints %d\r\n", vc->std.bNumEndpoints); /* Open the notification endpoint if it exist. */ if (vc->std.bNumEndpoints) { /* Support for 1 endpoint only. */ @@ -662,7 +662,7 @@ static bool _init_vs_configuration(videod_streaming_interface_t *stm) static bool _open_vs_itf(uint8_t rhport, videod_streaming_interface_t *stm, uint_fast8_t altnum) { uint_fast8_t i; - TU_LOG2(" reopen VS %d\n", altnum); + TU_LOG2(" reopen VS %d\r\n", altnum); uint8_t const *desc = _videod_itf[stm->index_vc].beg; /* Close endpoints of previous settings. */ @@ -672,7 +672,7 @@ static bool _open_vs_itf(uint8_t rhport, videod_streaming_interface_t *stm, uint uint8_t ep_adr = _desc_ep_addr(desc + ofs_ep); usbd_edpt_close(rhport, ep_adr); stm->desc.ep[i] = 0; - TU_LOG2(" close EP%02x\n", ep_adr); + TU_LOG2(" close EP%02x\r\n", ep_adr); } /* clear transfer management information */ @@ -709,12 +709,12 @@ static bool _open_vs_itf(uint8_t rhport, videod_streaming_interface_t *stm, uint } TU_ASSERT(usbd_edpt_open(rhport, ep)); stm->desc.ep[i] = (uint16_t) (cur - desc); - TU_LOG2(" open EP%02x\n", _desc_ep_addr(cur)); + TU_LOG2(" open EP%02x\r\n", _desc_ep_addr(cur)); } if (altnum) { stm->state = VS_STATE_STREAMING; } - TU_LOG2(" done\n"); + TU_LOG2(" done\r\n"); return true; } diff --git a/src/common/tusb_fifo.c b/src/common/tusb_fifo.c index a52c92267..d6c3db4ce 100644 --- a/src/common/tusb_fifo.c +++ b/src/common/tusb_fifo.c @@ -539,7 +539,7 @@ static uint16_t _tu_fifo_write_n(tu_fifo_t* f, const void * data, uint16_t n, tu // Advance index f->wr_idx = advance_index(f->depth, wr_idx, n); - TU_LOG(TU_FIFO_DBG, "\tnew_wr = %u\n", f->wr_idx); + TU_LOG(TU_FIFO_DBG, "\tnew_wr = %u\r\n", f->wr_idx); } _ff_unlock(f->mutex_wr); diff --git a/src/portable/dialog/da146xx/dcd_da146xx.c b/src/portable/dialog/da146xx/dcd_da146xx.c index 961da81d6..d1e85c2df 100644 --- a/src/portable/dialog/da146xx/dcd_da146xx.c +++ b/src/portable/dialog/da146xx/dcd_da146xx.c @@ -651,7 +651,7 @@ static void handle_epx_tx_ev(xfer_ctl_t *xfer) } if (txs & USB_USB_TXS1_REG_USB_TX_URUN_Msk) { - TU_LOG1("EP %d FIFO underrun\n", epnum); + TU_LOG1("EP %d FIFO underrun\r\n", epnum); } // Start next or repeated packet. start_tx_packet(xfer); diff --git a/src/portable/mentor/musb/dcd_musb.c b/src/portable/mentor/musb/dcd_musb.c index 487761847..3c0114e41 100644 --- a/src/portable/mentor/musb/dcd_musb.c +++ b/src/portable/mentor/musb/dcd_musb.c @@ -317,7 +317,7 @@ static bool handle_xfer_in(uint_fast8_t ep_addr) const unsigned mps = regs->TXMAXP; const unsigned len = TU_MIN(mps, rem); void *buf = pipe->buf; - // TU_LOG1(" %p mps %d len %d rem %d\n", buf, mps, len, rem); + // TU_LOG1(" %p mps %d len %d rem %d\r\n", buf, mps, len, rem); if (len) { if (_dcd.pipe_buf_is_fifo[TUSB_DIR_IN] & TU_BIT(epnum_minus1)) { pipe_read_write_packet_ff(buf, &USB0->FIFO1_WORD + epnum_minus1, len, TUSB_DIR_IN); @@ -328,7 +328,7 @@ static bool handle_xfer_in(uint_fast8_t ep_addr) pipe->remaining = rem - len; } regs->TXCSRL = USB_TXCSRL1_TXRDY; - // TU_LOG1(" TXCSRL%d = %x %d\n", epnum_minus1 + 1, regs->TXCSRL, rem - len); + // TU_LOG1(" TXCSRL%d = %x %d\r\n", epnum_minus1 + 1, regs->TXCSRL, rem - len); return false; } @@ -337,7 +337,7 @@ static bool handle_xfer_out(uint_fast8_t ep_addr) unsigned epnum_minus1 = tu_edpt_number(ep_addr) - 1; pipe_state_t *pipe = &_dcd.pipe[tu_edpt_dir(ep_addr)][epnum_minus1]; volatile hw_endpoint_t *regs = edpt_regs(epnum_minus1); - // TU_LOG1(" RXCSRL%d = %x\n", epnum_minus1 + 1, regs->RXCSRL); + // TU_LOG1(" RXCSRL%d = %x\r\n", epnum_minus1 + 1, regs->RXCSRL); TU_ASSERT(regs->RXCSRL & USB_RXCSRL1_RXRDY); @@ -399,14 +399,14 @@ static bool edpt0_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_ * may have already finished and received the next setup packet * without calling this function, so we have no choice but to * invoke the callback function of status packet here. */ - // TU_LOG1(" STATUS OUT USB0->CSRL0 = %x\n", USB0->CSRL0); + // TU_LOG1(" STATUS OUT USB0->CSRL0 = %x\r\n", USB0->CSRL0); _dcd.status_out = 0; if (req == REQUEST_TYPE_INVALID) { dcd_event_xfer_complete(rhport, ep_addr, total_bytes, XFER_RESULT_SUCCESS, false); } else { /* The next setup packet has already been received, it aborts * invoking callback function to avoid confusing TUSB stack. */ - TU_LOG1("Drop CONTROL_STAGE_ACK\n"); + TU_LOG1("Drop CONTROL_STAGE_ACK\r\n"); } return true; } @@ -431,16 +431,16 @@ static bool edpt0_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_ } else { USB0->CSRL0 = USB_CSRL0_TXRDY; /* Flush TX FIFO to return ACK. */ } - // TU_LOG1(" IN USB0->CSRL0 = %x\n", USB0->CSRL0); + // TU_LOG1(" IN USB0->CSRL0 = %x\r\n", USB0->CSRL0); } else { - // TU_LOG1(" OUT USB0->CSRL0 = %x\n", USB0->CSRL0); + // TU_LOG1(" OUT USB0->CSRL0 = %x\r\n", USB0->CSRL0); _dcd.pipe0.buf = buffer; _dcd.pipe0.length = len; _dcd.pipe0.remaining = len; USB0->CSRL0 = USB_CSRL0_RXRDYC; /* Clear RX FIFO to return ACK. */ } } else if (dir_in) { - // TU_LOG1(" STATUS IN USB0->CSRL0 = %x\n", USB0->CSRL0); + // TU_LOG1(" STATUS IN USB0->CSRL0 = %x\r\n", USB0->CSRL0); _dcd.pipe0.buf = NULL; _dcd.pipe0.length = 0; _dcd.pipe0.remaining = 0; @@ -454,7 +454,7 @@ static void process_ep0(uint8_t rhport) { uint_fast8_t csrl = USB0->CSRL0; - // TU_LOG1(" EP0 USB0->CSRL0 = %x\n", csrl); + // TU_LOG1(" EP0 USB0->CSRL0 = %x\r\n", csrl); if (csrl & USB_CSRL0_STALLED) { /* Returned STALL packet to HOST. */ @@ -464,7 +464,7 @@ static void process_ep0(uint8_t rhport) unsigned req = _dcd.setup_packet.bmRequestType; if (csrl & USB_CSRL0_SETEND) { - TU_LOG1(" ABORT by the next packets\n"); + TU_LOG1(" ABORT by the next packets\r\n"); USB0->CSRL0 = USB_CSRL0_SETENDC; if (req != REQUEST_TYPE_INVALID && _dcd.pipe0.buf) { /* DATA stage was aborted by receiving STATUS or SETUP packet. */ @@ -539,14 +539,14 @@ static void process_edpt_n(uint8_t rhport, uint_fast8_t ep_addr) volatile hw_endpoint_t *regs = edpt_regs(epn_minus1); if (dir_in) { - // TU_LOG1(" TXCSRL%d = %x\n", epn_minus1 + 1, regs->TXCSRL); + // TU_LOG1(" TXCSRL%d = %x\r\n", epn_minus1 + 1, regs->TXCSRL); if (regs->TXCSRL & USB_TXCSRL1_STALLED) { regs->TXCSRL &= ~(USB_TXCSRL1_STALLED | USB_TXCSRL1_UNDRN); return; } completed = handle_xfer_in(ep_addr); } else { - // TU_LOG1(" RXCSRL%d = %x\n", epn_minus1 + 1, regs->RXCSRL); + // TU_LOG1(" RXCSRL%d = %x\r\n", epn_minus1 + 1, regs->RXCSRL); if (regs->RXCSRL & USB_RXCSRL1_STALLED) { regs->RXCSRL &= ~(USB_RXCSRL1_STALLED | USB_RXCSRL1_OVER); return; @@ -789,7 +789,7 @@ bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t t { (void)rhport; bool ret; - // TU_LOG1("X %x %d\n", ep_addr, total_bytes); + // TU_LOG1("X %x %d\r\n", ep_addr, total_bytes); unsigned const epnum = tu_edpt_number(ep_addr); unsigned const ie = NVIC_GetEnableIRQ(USB0_IRQn); NVIC_DisableIRQ(USB0_IRQn); @@ -807,7 +807,7 @@ bool dcd_edpt_xfer_fifo(uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_ { (void)rhport; bool ret; - // TU_LOG1("X %x %d\n", ep_addr, total_bytes); + // TU_LOG1("X %x %d\r\n", ep_addr, total_bytes); unsigned const epnum = tu_edpt_number(ep_addr); TU_ASSERT(epnum); unsigned const ie = NVIC_GetEnableIRQ(USB0_IRQn); @@ -869,7 +869,7 @@ void dcd_int_handler(uint8_t rhport) is = USB0->IS; /* read and clear interrupt status */ txis = USB0->TXIS; /* read and clear interrupt status */ rxis = USB0->RXIS; /* read and clear interrupt status */ - // TU_LOG1("D%2x T%2x R%2x\n", is, txis, rxis); + // TU_LOG1("D%2x T%2x R%2x\r\n", is, txis, rxis); is &= USB0->IE; /* Clear disabled interrupts */ if (is & USB_IS_DISCON) { diff --git a/src/portable/mentor/musb/hcd_musb.c b/src/portable/mentor/musb/hcd_musb.c index 9eb2e005e..7e67b8291 100644 --- a/src/portable/mentor/musb/hcd_musb.c +++ b/src/portable/mentor/musb/hcd_musb.c @@ -418,7 +418,7 @@ static void process_ep0(uint8_t rhport) (void)rhport; uint_fast8_t csrl = USB0->CSRL0; - // TU_LOG1(" EP0 CSRL = %x\n", csrl); + // TU_LOG1(" EP0 CSRL = %x\r\n", csrl); unsigned const dev_addr = USB0->TXFUNCADDR0; unsigned const req = _hcd.bmRequestType; @@ -508,7 +508,7 @@ static void process_pipe_tx(uint8_t rhport, uint_fast8_t pipenum) volatile hw_endpoint_t *regs = edpt_regs(pipenum - 1); unsigned const csrl = regs->TXCSRL; - // TU_LOG1(" TXCSRL%d = %x\n", pipenum, csrl); + // TU_LOG1(" TXCSRL%d = %x\r\n", pipenum, csrl); if (csrl & (USB_TXCSRL1_STALLED | USB_TXCSRL1_ERROR)) { if (csrl & USB_TXCSRL1_TXRDY) regs->TXCSRL = (csrl & ~(USB_TXCSRL1_STALLED | USB_TXCSRL1_ERROR)) | USB_TXCSRL1_FLUSH; @@ -537,7 +537,7 @@ static void process_pipe_rx(uint8_t rhport, uint_fast8_t pipenum) volatile hw_endpoint_t *regs = edpt_regs(pipenum - 1); unsigned const csrl = regs->RXCSRL; - // TU_LOG1(" RXCSRL%d = %x\n", pipenum, csrl); + // TU_LOG1(" RXCSRL%d = %x\r\n", pipenum, csrl); if (csrl & (USB_RXCSRL1_STALLED | USB_RXCSRL1_ERROR)) { if (csrl & USB_RXCSRL1_RXRDY) regs->RXCSRL = (csrl & ~(USB_RXCSRL1_STALLED | USB_RXCSRL1_ERROR)) | USB_RXCSRL1_FLUSH; @@ -846,7 +846,7 @@ void hcd_int_handler(uint8_t rhport) is = USB0->IS; /* read and clear interrupt status */ txis = USB0->TXIS; /* read and clear interrupt status */ rxis = USB0->RXIS; /* read and clear interrupt status */ - // TU_LOG1("D%2x T%2x R%2x\n", is, txis, rxis); + // TU_LOG1("D%2x T%2x R%2x\r\n", is, txis, rxis); is &= USB0->IE; /* Clear disabled interrupts */ if (is & USB_IS_RESUME) { diff --git a/src/portable/nxp/khci/hcd_khci.c b/src/portable/nxp/khci/hcd_khci.c index f6029ee0d..fb978cac8 100644 --- a/src/portable/nxp/khci/hcd_khci.c +++ b/src/portable/nxp/khci/hcd_khci.c @@ -161,7 +161,7 @@ static int prepare_packets(int pipenum) buffer_descriptor_t *bd = _hcd.bdt[dir_tx]; TU_ASSERT(0 == bd[odd].own, -1); - // TU_LOG1(" %p dir %d odd %d data %d\n", &bd[odd], dir_tx, odd, pipe->data); + // TU_LOG1(" %p dir %d odd %d data %d\r\n", &bd[odd], dir_tx, odd, pipe->data); ep->pipenum = pipenum; @@ -251,7 +251,7 @@ static bool resume_transfer(int pipenum) flags |= USB_ENDPT_EPHSHK_MASK | USB_ENDPT_EPCTLDIS_MASK | USB_ENDPT_RETRYDIS_MASK; break; } - // TU_LOG1(" resume pipenum %d flags %x\n", pipenum, flags); + // TU_LOG1(" resume pipenum %d flags %x\r\n", pipenum, flags); KHCI->ENDPOINT[0].ENDPT = flags; KHCI->ADDR = (KHCI->ADDR & USB_ADDR_LSEN_MASK) | pipe->dev_addr; @@ -302,7 +302,7 @@ static void process_tokdne(uint8_t rhport) int pipenum = ep->pipenum; int next_pipenum; - // TU_LOG1("TOKDNE %x PID %x pipe %d\n", s, pid, pipenum); + // TU_LOG1("TOKDNE %x PID %x pipe %d\r\n", s, pid, pipenum); xfer_result_t result; switch (pid) { @@ -479,7 +479,7 @@ void hcd_device_close(uint8_t rhport, uint8_t dev_addr) bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, uint8_t const setup_packet[8]) { (void)rhport; - // TU_LOG1("SETUP %u\n", dev_addr); + // TU_LOG1("SETUP %u\r\n", dev_addr); TU_ASSERT(0 == (_hcd.in_progress & TU_BIT(0))); int pipenum = find_pipe(dev_addr, 0); @@ -510,7 +510,7 @@ bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const { (void)rhport; uint8_t const ep_addr = ep_desc->bEndpointAddress; - // TU_LOG1("O %u %x\n", dev_addr, ep_addr); + // TU_LOG1("O %u %x\r\n", dev_addr, ep_addr); /* Find a free pipe */ pipe_state_t *p = &_hcd.pipe[0]; pipe_state_t *end = &_hcd.pipe[CFG_TUH_ENDPOINT_MAX * 2]; @@ -543,7 +543,7 @@ bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t * buffer, uint16_t buflen) { (void)rhport; - // TU_LOG1("X %u %x %x %d\n", dev_addr, ep_addr, (uintptr_t)buffer, buflen); + // TU_LOG1("X %u %x %x %d\r\n", dev_addr, ep_addr, (uintptr_t)buffer, buflen); int pipenum = find_pipe(dev_addr, ep_addr); TU_ASSERT(0 <= pipenum); @@ -580,7 +580,7 @@ void hcd_int_handler(uint8_t rhport) uint32_t is = KHCI->ISTAT; uint32_t msk = KHCI->INTEN; - // TU_LOG1("S %lx\n", is); + // TU_LOG1("S %lx\r\n", is); /* clear disabled interrupts */ KHCI->ISTAT = (is & ~msk & ~USB_ISTAT_TOKDNE_MASK) | USB_ISTAT_SOFTOK_MASK; @@ -589,7 +589,7 @@ void hcd_int_handler(uint8_t rhport) if (is & USB_ISTAT_ERROR_MASK) { unsigned err = KHCI->ERRSTAT; if (err) { - TU_LOG1(" ERR %x\n", err); + TU_LOG1(" ERR %x\r\n", err); KHCI->ERRSTAT = err; } else { KHCI->INTEN &= ~USB_ISTAT_ERROR_MASK; diff --git a/src/portable/raspberrypi/rp2040/hcd_rp2040.c b/src/portable/raspberrypi/rp2040/hcd_rp2040.c index 02f9968a7..51b8bf72d 100644 --- a/src/portable/raspberrypi/rp2040/hcd_rp2040.c +++ b/src/portable/raspberrypi/rp2040/hcd_rp2040.c @@ -219,7 +219,7 @@ static void __tusb_irq_path_func(hcd_rp2040_irq)(void) if ( status & USB_INTS_BUFF_STATUS_BITS ) { handled |= USB_INTS_BUFF_STATUS_BITS; - TU_LOG(2, "Buffer complete\n"); + TU_LOG(2, "Buffer complete\r\n"); hw_handle_buff_status(); } @@ -227,7 +227,7 @@ static void __tusb_irq_path_func(hcd_rp2040_irq)(void) { handled |= USB_INTS_TRANS_COMPLETE_BITS; usb_hw_clear->sie_status = USB_SIE_STATUS_TRANS_COMPLETE_BITS; - TU_LOG(2, "Transfer complete\n"); + TU_LOG(2, "Transfer complete\r\n"); hw_trans_complete(); } diff --git a/src/portable/raspberrypi/rp2040/rp2040_usb.c b/src/portable/raspberrypi/rp2040/rp2040_usb.c index 1f49665ff..53486a586 100644 --- a/src/portable/raspberrypi/rp2040/rp2040_usb.c +++ b/src/portable/raspberrypi/rp2040/rp2040_usb.c @@ -219,7 +219,7 @@ void hw_endpoint_xfer_start(struct hw_endpoint *ep, uint8_t *buffer, uint16_t to if ( ep->active ) { // TODO: Is this acceptable for interrupt packets? - TU_LOG(1, "WARN: starting new transfer on already active ep %d %s\n", tu_edpt_number(ep->ep_addr), + TU_LOG(1, "WARN: starting new transfer on already active ep %d %s\r\n", tu_edpt_number(ep->ep_addr), ep_dir_string[tu_edpt_dir(ep->ep_addr)]); hw_endpoint_reset_transfer(ep); @@ -419,7 +419,7 @@ static bool __tusb_irq_path_func(e15_is_critical_frame_period) (struct hw_endpoi if (delta < 800 || delta > 998) { return false; } - TU_LOG(3, "Avoiding sof %lu now %lu last %lu\n", (usb_hw->sof_rd + 1) & USB_SOF_RD_BITS, time_us_32(), e15_last_sof); + TU_LOG(3, "Avoiding sof %lu now %lu last %lu\r\n", (usb_hw->sof_rd + 1) & USB_SOF_RD_BITS, time_us_32(), e15_last_sof); return true; } diff --git a/src/portable/renesas/rusb2/hcd_rusb2.c b/src/portable/renesas/rusb2/hcd_rusb2.c index 0e6fa1618..886a6f6b8 100644 --- a/src/portable/renesas/rusb2/hcd_rusb2.c +++ b/src/portable/renesas/rusb2/hcd_rusb2.c @@ -409,7 +409,7 @@ static void process_pipe_nrdy(uint8_t rhport, unsigned num) (void)rhport; xfer_result_t result; uint16_t volatile *ctr = get_pipectr(num); - // TU_LOG1("NRDY %d %x\n", num, *ctr); + // TU_LOG1("NRDY %d %x\r\n", num, *ctr); switch (*ctr & RUSB2_PIPE_CTR_PID_Msk) { default: return; case RUSB2_PIPE_CTR_PID_STALL: result = XFER_RESULT_STALLED; break; @@ -608,7 +608,7 @@ void hcd_device_close(uint8_t rhport, uint8_t dev_addr) bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, uint8_t const setup_packet[8]) { (void)rhport; - // TU_LOG1("S %d %x\n", dev_addr, RUSB2->DCPCTR); + // TU_LOG1("S %d %x\r\n", dev_addr, RUSB2->DCPCTR); TU_ASSERT(dev_addr < 6); /* USBa can only handle addresses from 0 to 5. */ TU_ASSERT(0 == RUSB2->DCPCTR_b.SUREQ); @@ -701,7 +701,7 @@ bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t *b { bool r; hcd_int_disable(rhport); - // TU_LOG1("X %d %x %u\n", dev_addr, ep_addr, buflen); + // TU_LOG1("X %d %x %u\r\n", dev_addr, ep_addr, buflen); r = process_edpt_xfer(dev_addr, ep_addr, buffer, buflen); hcd_int_enable(rhport); return r; @@ -745,7 +745,7 @@ void hcd_int_handler(uint8_t rhport) /* clear active bits except VALID (don't write 0 to already cleared bits according to the HW manual) */ RUSB2->INTSTS1 = ~((RUSB2_INTSTS1_SACK_Msk | RUSB2_INTSTS1_SIGN_Msk | RUSB2_INTSTS1_ATTCH_Msk | RUSB2_INTSTS1_DTCH_Msk) & is1); RUSB2->INTSTS0 = ~((RUSB2_INTSTS0_BRDY_Msk | RUSB2_INTSTS0_NRDY_Msk | RUSB2_INTSTS0_BEMP_Msk) & is0); - // TU_LOG1("IS %04x %04x\n", is0, is1); + // TU_LOG1("IS %04x %04x\r\n", is0, is1); is1 &= RUSB2->INTENB1; is0 &= RUSB2->INTENB0; diff --git a/src/portable/st/typec/typec_stm32.c b/src/portable/st/typec/typec_stm32.c index bf8b660f0..8da2e39ba 100644 --- a/src/portable/st/typec/typec_stm32.c +++ b/src/portable/st/typec/typec_stm32.c @@ -246,7 +246,7 @@ void tcd_int_handler(uint8_t rhport) { v_cc[0] = (UCPD1->SR >> UCPD_SR_TYPEC_VSTATE_CC1_Pos) & 0x03; v_cc[1] = (UCPD1->SR >> UCPD_SR_TYPEC_VSTATE_CC2_Pos) & 0x03; - TU_LOG3("VState CC1 = %lu, CC2 = %lu\n", v_cc[0], v_cc[1]); + TU_LOG3("VState CC1 = %lu, CC2 = %lu\r\n", v_cc[0], v_cc[1]); uint32_t cr = UCPD1->CR; @@ -255,15 +255,15 @@ void tcd_int_handler(uint8_t rhport) { // FIXME somehow CC2 is vstate is not correct, always 1 even not attached. // on DPOW1 board, it is connected to PA10 (USBPD_DBCC2), we probably miss something. if ((sr & UCPD_SR_TYPECEVT1) && (v_cc[0] == 3)) { - TU_LOG3("Attach CC1\n"); + TU_LOG3("Attach CC1\r\n"); cr &= ~(UCPD_CR_PHYCCSEL | UCPD_CR_CCENABLE); cr |= UCPD_CR_PHYRXEN | UCPD_CR_CCENABLE_0; } else if ((sr & UCPD_SR_TYPECEVT2) && (v_cc[1] == 3)) { - TU_LOG3("Attach CC2\n"); + TU_LOG3("Attach CC2\r\n"); cr &= ~UCPD_CR_CCENABLE; cr |= (UCPD_CR_PHYCCSEL | UCPD_CR_PHYRXEN | UCPD_CR_CCENABLE_1); } else { - TU_LOG3("Detach\n"); + TU_LOG3("Detach\r\n"); cr &= ~UCPD_CR_PHYRXEN; cr |= UCPD_CR_CCENABLE_0 | UCPD_CR_CCENABLE_1; } @@ -290,7 +290,7 @@ void tcd_int_handler(uint8_t rhport) { //------------- RX -------------// if (sr & UCPD_SR_RXORDDET) { // SOP: Start of Packet. - TU_LOG3("SOP\n"); + TU_LOG3("SOP\r\n"); // UCPD1->RX_ORDSET & UCPD_RX_ORDSET_RXORDSET_Msk; // ack @@ -299,7 +299,7 @@ void tcd_int_handler(uint8_t rhport) { // Received full message if (sr & UCPD_SR_RXMSGEND) { - TU_LOG3("RX MSG END\n"); + TU_LOG3("RX MSG END\r\n"); // stop TX dma_stop(rhport, true); @@ -328,7 +328,7 @@ void tcd_int_handler(uint8_t rhport) { } if (sr & UCPD_SR_RXOVR) { - TU_LOG3("RXOVR\n"); + TU_LOG3("RXOVR\r\n"); // ack UCPD1->ICR = UCPD_ICR_RXOVRCF; } @@ -343,12 +343,12 @@ void tcd_int_handler(uint8_t rhport) { uint8_t result; if ( sr & UCPD_SR_TXMSGSENT ) { - TU_LOG3("TX MSG SENT\n"); + TU_LOG3("TX MSG SENT\r\n"); result = XFER_RESULT_SUCCESS; // ack UCPD1->ICR = UCPD_ICR_TXMSGSENTCF; }else { - TU_LOG3("TX Error\n"); + TU_LOG3("TX Error\r\n"); result = XFER_RESULT_FAILED; // ack UCPD1->ICR = UCPD_SR_TXMSGDISC | UCPD_SR_TXMSGABT | UCPD_SR_TXUND; diff --git a/src/portable/sunxi/dcd_sunxi_musb.c b/src/portable/sunxi/dcd_sunxi_musb.c index e26be775d..6cc1975a8 100644 --- a/src/portable/sunxi/dcd_sunxi_musb.c +++ b/src/portable/sunxi/dcd_sunxi_musb.c @@ -408,9 +408,9 @@ static inline unsigned free_block_size(free_block_t const *blk) #if 0 static inline void print_block_list(free_block_t const *blk, unsigned num) { - TU_LOG1("*************\n"); + TU_LOG1("*************\r\n"); for (unsigned i = 0; i < num; ++i) { - TU_LOG1(" Blk%u %u %u\n", i, blk->beg, blk->end); + TU_LOG1(" Blk%u %u %u\r\n", i, blk->beg, blk->end); ++blk; } } @@ -590,7 +590,7 @@ static bool handle_xfer_in(uint_fast8_t ep_addr) const unsigned mps = USBC_Readw(USBC_REG_TXMAXP(USBC0_BASE)); const unsigned len = TU_MIN(mps, rem); uint8_t *buf = pipe->buf; - // TU_LOG1(" %p mps %d len %d rem %d\n", buf, mps, len, rem); + // TU_LOG1(" %p mps %d len %d rem %d\r\n", buf, mps, len, rem); if (len) { volatile void* addr = (volatile void*)(USBC_REG_EPFIFO1(USBC0_BASE) + (epnum_minus1 << 2)); if (_dcd.pipe_buf_is_fifo[TUSB_DIR_IN] & TU_BIT(epnum_minus1)) { @@ -602,7 +602,7 @@ static bool handle_xfer_in(uint_fast8_t ep_addr) pipe->remaining = rem - len; } __USBC_Dev_Tx_WriteDataComplete(); - // TU_LOG1(" TXCSRL%d = %x %d\n", epnum_minus1 + 1, regs->TXCSRL, rem - len); + // TU_LOG1(" TXCSRL%d = %x %d\r\n", epnum_minus1 + 1, regs->TXCSRL, rem - len); return false; } @@ -610,7 +610,7 @@ static bool handle_xfer_out(uint_fast8_t ep_addr) { unsigned epnum_minus1 = tu_edpt_number(ep_addr) - 1; pipe_state_t *pipe = &_dcd.pipe[tu_edpt_dir(ep_addr)][epnum_minus1]; - // TU_LOG1(" RXCSRL%d = %x\n", epnum_minus1 + 1, regs->RXCSRL); + // TU_LOG1(" RXCSRL%d = %x\r\n", epnum_minus1 + 1, regs->RXCSRL); TU_ASSERT(__USBC_Dev_Rx_IsReadDataReady()); @@ -677,14 +677,14 @@ static bool edpt0_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_ * may have already finished and received the next setup packet * without calling this function, so we have no choice but to * invoke the callback function of status packet here. */ - // TU_LOG1(" STATUS OUT CSRL0 = %x\n", CSRL0); + // TU_LOG1(" STATUS OUT CSRL0 = %x\r\n", CSRL0); _dcd.status_out = 0; if (req == REQUEST_TYPE_INVALID) { dcd_event_xfer_complete(rhport, ep_addr, total_bytes, XFER_RESULT_SUCCESS, false); } else { /* The next setup packet has already been received, it aborts * invoking callback function to avoid confusing TUSB stack. */ - TU_LOG1("Drop CONTROL_STAGE_ACK\n"); + TU_LOG1("Drop CONTROL_STAGE_ACK\r\n"); } return true; } @@ -709,16 +709,16 @@ static bool edpt0_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_ } else { __USBC_Dev_ep0_WriteDataHalf(); } - // TU_LOG1(" IN CSRL0 = %x\n", CSRL0); + // TU_LOG1(" IN CSRL0 = %x\r\n", CSRL0); } else { - // TU_LOG1(" OUT CSRL0 = %x\n", CSRL0); + // TU_LOG1(" OUT CSRL0 = %x\r\n", CSRL0); _dcd.pipe0.buf = buffer; _dcd.pipe0.length = len; _dcd.pipe0.remaining = len; __USBC_Dev_ep0_ReadDataHalf(); } } else if (dir_in) { - // TU_LOG1(" STATUS IN CSRL0 = %x\n", CSRL0); + // TU_LOG1(" STATUS IN CSRL0 = %x\r\n", CSRL0); _dcd.pipe0.buf = NULL; _dcd.pipe0.length = 0; _dcd.pipe0.remaining = 0; @@ -733,7 +733,7 @@ static void process_ep0(uint8_t rhport) USBC_SelectActiveEp(0); uint_fast8_t csrl = USBC_Readw(USBC_REG_CSR0(USBC0_BASE)); - // TU_LOG1(" EP0 CSRL0 = %x\n", csrl); + // TU_LOG1(" EP0 CSRL0 = %x\r\n", csrl); if (csrl & USB_CSRL0_STALLED) { /* Returned STALL packet to HOST. */ @@ -743,7 +743,7 @@ static void process_ep0(uint8_t rhport) unsigned req = _dcd.setup_packet.bmRequestType; if (csrl & USB_CSRL0_SETEND) { - // TU_LOG1(" ABORT by the next packets\n"); + // TU_LOG1(" ABORT by the next packets\r\n"); USBC_Dev_Ctrl_ClearSetupEnd(); if (req != REQUEST_TYPE_INVALID && _dcd.pipe0.buf) { /* DATA stage was aborted by receiving STATUS or SETUP packet. */ @@ -819,14 +819,14 @@ static void process_edpt_n(uint8_t rhport, uint_fast8_t ep_addr) USBC_SelectActiveEp(epn); if (dir_in) { - // TU_LOG1(" TXCSRL%d = %x\n", epn_minus1 + 1, regs->TXCSRL); + // TU_LOG1(" TXCSRL%d = %x\r\n", epn_minus1 + 1, regs->TXCSRL); if (__USBC_Dev_Tx_IsEpStall()) { __USBC_Dev_Tx_ClearStall(); return; } completed = handle_xfer_in(ep_addr); } else { - // TU_LOG1(" RXCSRL%d = %x\n", epn_minus1 + 1, regs->RXCSRL); + // TU_LOG1(" RXCSRL%d = %x\r\n", epn_minus1 + 1, regs->RXCSRL); if (__USBC_Dev_Rx_IsEpStall()) { __USBC_Dev_Rx_ClearStall(); return; @@ -1092,7 +1092,7 @@ bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t t { (void)rhport; bool ret; - // TU_LOG1("X %x %d\n", ep_addr, total_bytes); + // TU_LOG1("X %x %d\r\n", ep_addr, total_bytes); unsigned const epnum = tu_edpt_number(ep_addr); musb_int_mask(); @@ -1111,7 +1111,7 @@ bool dcd_edpt_xfer_fifo(uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_ { (void)rhport; bool ret; - // TU_LOG1("X %x %d\n", ep_addr, total_bytes); + // TU_LOG1("X %x %d\r\n", ep_addr, total_bytes); unsigned const epnum = tu_edpt_number(ep_addr); TU_ASSERT(epnum); -- cgit v1.3.1 From 979bf32266d379ec493ad31001b815d6a597b91e Mon Sep 17 00:00:00 2001 From: hathach Date: Wed, 2 Aug 2023 15:34:18 +0700 Subject: default class driver log level to CFG_TUH/TUD_LOG_LEVEL allow application to selectively disable usbd/usbh or driver log --- src/class/cdc/cdc_device.c | 15 +++++++++++---- src/class/cdc/cdc_host.c | 9 ++++++--- src/class/dfu/dfu_device.c | 11 +++++++++-- src/class/dfu/dfu_rt_device.c | 13 ++++++++++--- src/class/hid/hid_host.c | 8 +++++--- src/class/msc/msc_device.c | 2 +- src/class/msc/msc_host.c | 19 +++++++++++-------- src/class/net/ncm_device.c | 11 +++++++++-- src/class/video/video_device.c | 23 +++++++++++++++-------- src/host/usbh.c | 7 ------- src/host/usbh_classdriver.h | 7 +++++++ 11 files changed, 84 insertions(+), 41 deletions(-) (limited to 'src/class') diff --git a/src/class/cdc/cdc_device.c b/src/class/cdc/cdc_device.c index f658df4d0..70d9c2e24 100644 --- a/src/class/cdc/cdc_device.c +++ b/src/class/cdc/cdc_device.c @@ -33,6 +33,13 @@ #include "cdc_device.h" +// Level where CFG_TUSB_DEBUG must be at least for this driver is logged +#ifndef CFG_TUD_CDC_LOG_LEVEL + #define CFG_TUD_CDC_LOG_LEVEL CFG_TUD_LOG_LEVEL +#endif + +#define TU_LOG_DRV(...) TU_LOG(CFG_TUD_CDC_LOG_LEVEL, __VA_ARGS__) + //--------------------------------------------------------------------+ // MACRO CONSTANT TYPEDEF //--------------------------------------------------------------------+ @@ -353,7 +360,7 @@ bool cdcd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t case CDC_REQUEST_SET_LINE_CODING: if (stage == CONTROL_STAGE_SETUP) { - TU_LOG2(" Set Line Coding\r\n"); + TU_LOG_DRV(" Set Line Coding\r\n"); tud_control_xfer(rhport, request, &p_cdc->line_coding, sizeof(cdc_line_coding_t)); } else if ( stage == CONTROL_STAGE_ACK) @@ -365,7 +372,7 @@ bool cdcd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t case CDC_REQUEST_GET_LINE_CODING: if (stage == CONTROL_STAGE_SETUP) { - TU_LOG2(" Get Line Coding\r\n"); + TU_LOG_DRV(" Get Line Coding\r\n"); tud_control_xfer(rhport, request, &p_cdc->line_coding, sizeof(cdc_line_coding_t)); } break; @@ -390,7 +397,7 @@ bool cdcd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t // Disable fifo overwriting if DTR bit is set tu_fifo_set_overwritable(&p_cdc->tx_ff, !dtr); - TU_LOG2(" Set Control Line State: DTR = %d, RTS = %d\r\n", dtr, rts); + TU_LOG_DRV(" Set Control Line State: DTR = %d, RTS = %d\r\n", dtr, rts); // Invoke callback if ( tud_cdc_line_state_cb ) tud_cdc_line_state_cb(itf, dtr, rts); @@ -403,7 +410,7 @@ bool cdcd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t } else if (stage == CONTROL_STAGE_ACK) { - TU_LOG2(" Send Break\r\n"); + TU_LOG_DRV(" Send Break\r\n"); if ( tud_cdc_send_break_cb ) tud_cdc_send_break_cb(itf, request->wValue); } break; diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index ce9f27c33..7f9ed18b3 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -33,9 +33,12 @@ #include "cdc_host.h" -// Debug level, TUSB_CFG_DEBUG must be at least this level for debug message -#define CDCH_DEBUG 2 -#define TU_LOG_DRV(...) TU_LOG(CDCH_DEBUG, __VA_ARGS__) +// Level where CFG_TUSB_DEBUG must be at least for this driver is logged +#ifndef CFG_TUH_CDC_LOG_LEVEL + #define CFG_TUH_CDC_LOG_LEVEL CFG_TUH_LOG_LEVEL +#endif + +#define TU_LOG_DRV(...) TU_LOG(CFG_TUH_CDC_LOG_LEVEL, __VA_ARGS__) //--------------------------------------------------------------------+ // Host CDC Interface diff --git a/src/class/dfu/dfu_device.c b/src/class/dfu/dfu_device.c index bffdb8376..3e7c13dea 100644 --- a/src/class/dfu/dfu_device.c +++ b/src/class/dfu/dfu_device.c @@ -37,6 +37,13 @@ // MACRO CONSTANT TYPEDEF //--------------------------------------------------------------------+ +// Level where CFG_TUSB_DEBUG must be at least for this driver is logged +#ifndef CFG_TUD_DFU_LOG_LEVEL + #define CFG_TUD_DFU_LOG_LEVEL CFG_TUD_LOG_LEVEL +#endif + +#define TU_LOG_DRV(...) TU_LOG(CFG_TUD_DFU_LOG_LEVEL, __VA_ARGS__) + //--------------------------------------------------------------------+ // INTERNAL OBJECT & FUNCTION DECLARATION //--------------------------------------------------------------------+ @@ -205,7 +212,7 @@ bool dfu_moded_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_reque { TU_VERIFY(request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_INTERFACE); - TU_LOG2(" DFU State : %s, Status: %s\r\n", tu_lookup_find(&_dfu_state_table, _dfu_ctx.state), tu_lookup_find(&_dfu_status_table, _dfu_ctx.status)); + TU_LOG_DRV(" DFU State : %s, Status: %s\r\n", tu_lookup_find(&_dfu_state_table, _dfu_ctx.state), tu_lookup_find(&_dfu_status_table, _dfu_ctx.status)); if ( request->bmRequestType_bit.type == TUSB_REQ_TYPE_STANDARD ) { @@ -235,7 +242,7 @@ bool dfu_moded_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_reque } else if ( request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS ) { - TU_LOG2(" DFU Request: %s\r\n", tu_lookup_find(&_dfu_request_table, request->bRequest)); + TU_LOG_DRV(" DFU Request: %s\r\n", tu_lookup_find(&_dfu_request_table, request->bRequest)); // Class request switch ( request->bRequest ) diff --git a/src/class/dfu/dfu_rt_device.c b/src/class/dfu/dfu_rt_device.c index 7b77b3f8f..a940d8d62 100644 --- a/src/class/dfu/dfu_rt_device.c +++ b/src/class/dfu/dfu_rt_device.c @@ -37,6 +37,13 @@ // MACRO CONSTANT TYPEDEF //--------------------------------------------------------------------+ +// Level where CFG_TUSB_DEBUG must be at least for this driver is logged +#ifndef CFG_TUD_DFU_RUNTIME_LOG_LEVEL + #define CFG_TUD_DFU_RUNTIME_LOG_LEVEL CFG_TUD_LOG_LEVEL +#endif + +#define TU_LOG_DRV(...) TU_LOG(CFG_TUD_DFU_RUNTIME_LOG_LEVEL, __VA_ARGS__) + //--------------------------------------------------------------------+ // INTERNAL OBJECT & FUNCTION DECLARATION //--------------------------------------------------------------------+ @@ -99,7 +106,7 @@ bool dfu_rtd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request { case DFU_REQUEST_DETACH: { - TU_LOG2(" DFU RT Request: DETACH\r\n"); + TU_LOG_DRV(" DFU RT Request: DETACH\r\n"); tud_control_status(rhport, request); tud_dfu_runtime_reboot_to_dfu_cb(); } @@ -107,7 +114,7 @@ bool dfu_rtd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request case DFU_REQUEST_GETSTATUS: { - TU_LOG2(" DFU RT Request: GETSTATUS\r\n"); + TU_LOG_DRV(" DFU RT Request: GETSTATUS\r\n"); dfu_status_response_t resp; // Status = OK, Poll timeout is ignored during RT, State = APP_IDLE, IString = 0 TU_VERIFY(tu_memset_s(&resp, sizeof(resp), 0x00, sizeof(resp))==0); @@ -117,7 +124,7 @@ bool dfu_rtd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request default: { - TU_LOG2(" DFU RT Unexpected Request: %d\r\n", request->bRequest); + TU_LOG_DRV(" DFU RT Unexpected Request: %d\r\n", request->bRequest); return false; // stall unsupported request } } diff --git a/src/class/hid/hid_host.c b/src/class/hid/hid_host.c index 6abe298e5..4253170d4 100644 --- a/src/class/hid/hid_host.c +++ b/src/class/hid/hid_host.c @@ -33,10 +33,12 @@ #include "hid_host.h" -// Debug level, TUSB_CFG_DEBUG must be at least this level for debug message -#define HIDH_DEBUG 2 -#define TU_LOG_DRV(...) TU_LOG(HIDH_DEBUG, __VA_ARGS__) +// Level where CFG_TUSB_DEBUG must be at least for this driver is logged +#ifndef CFG_TUH_HID_LOG_LEVEL + #define CFG_TUH_HID_LOG_LEVEL CFG_TUH_LOG_LEVEL +#endif +#define TU_LOG_DRV(...) TU_LOG(CFG_TUH_HID_LOG_LEVEL, __VA_ARGS__) //--------------------------------------------------------------------+ // MACRO CONSTANT TYPEDEF //--------------------------------------------------------------------+ diff --git a/src/class/msc/msc_device.c b/src/class/msc/msc_device.c index a602e9672..2589dcd2c 100644 --- a/src/class/msc/msc_device.c +++ b/src/class/msc/msc_device.c @@ -36,7 +36,7 @@ // Level where CFG_TUSB_DEBUG must be at least for this driver is logged #ifndef CFG_TUD_MSC_LOG_LEVEL - #define CFG_TUD_MSC_LOG_LEVEL 2 + #define CFG_TUD_MSC_LOG_LEVEL CFG_TUD_LOG_LEVEL #endif #define TU_LOG_DRV(...) TU_LOG(CFG_TUD_MSC_LOG_LEVEL, __VA_ARGS__) diff --git a/src/class/msc/msc_host.c b/src/class/msc/msc_host.c index d32c0adb0..a65208d69 100644 --- a/src/class/msc/msc_host.c +++ b/src/class/msc/msc_host.c @@ -33,9 +33,12 @@ #include "msc_host.h" -// Debug level, TUSB_CFG_DEBUG must be at least this level for debug message -#define MSCH_DEBUG 2 -#define TU_LOG_MSCH(...) TU_LOG(MSCH_DEBUG, __VA_ARGS__) +// Level where CFG_TUSB_DEBUG must be at least for this driver is logged +#ifndef CFG_TUH_MSC_LOG_LEVEL + #define CFG_TUH_MSC_LOG_LEVEL CFG_TUH_LOG_LEVEL +#endif + +#define TU_LOG_DRV(...) TU_LOG(CFG_TUH_MSC_LOG_LEVEL, __VA_ARGS__) //--------------------------------------------------------------------+ // MACRO CONSTANT TYPEDEF @@ -308,7 +311,7 @@ void msch_close(uint8_t dev_addr) msch_interface_t* p_msc = get_itf(dev_addr); TU_VERIFY(p_msc->configured, ); - TU_LOG_MSCH(" MSCh close addr = %d\r\n", dev_addr); + TU_LOG_DRV(" MSCh close addr = %d\r\n", dev_addr); // invoke Application Callback if (p_msc->mounted) { @@ -426,7 +429,7 @@ bool msch_set_config(uint8_t dev_addr, uint8_t itf_num) p_msc->configured = true; //------------- Get Max Lun -------------// - TU_LOG_MSCH("MSC Get Max Lun\r\n"); + TU_LOG_DRV("MSC Get Max Lun\r\n"); tusb_control_request_t const request = { .bmRequestType_bit = @@ -465,7 +468,7 @@ static void config_get_maxlun_complete (tuh_xfer_t* xfer) p_msc->max_lun++; // MAX LUN is minus 1 by specs // TODO multiple LUN support - TU_LOG_MSCH("SCSI Test Unit Ready\r\n"); + TU_LOG_DRV("SCSI Test Unit Ready\r\n"); uint8_t const lun = 0; tuh_msc_test_unit_ready(daddr, lun, config_test_unit_ready_complete, 0); } @@ -478,14 +481,14 @@ static bool config_test_unit_ready_complete(uint8_t dev_addr, tuh_msc_complete_d if (csw->status == 0) { // Unit is ready, read its capacity - TU_LOG_MSCH("SCSI Read Capacity\r\n"); + TU_LOG_DRV("SCSI Read Capacity\r\n"); tuh_msc_read_capacity(dev_addr, cbw->lun, (scsi_read_capacity10_resp_t*) ((void*) _msch_buffer), config_read_capacity_complete, 0); }else { // Note: During enumeration, some device fails Test Unit Ready and require a few retries // with Request Sense to start working !! // TODO limit number of retries - TU_LOG_MSCH("SCSI Request Sense\r\n"); + TU_LOG_DRV("SCSI Request Sense\r\n"); TU_ASSERT(tuh_msc_request_sense(dev_addr, cbw->lun, _msch_buffer, config_request_sense_complete, 0)); } diff --git a/src/class/net/ncm_device.c b/src/class/net/ncm_device.c index 611dc3348..226c42c4e 100644 --- a/src/class/net/ncm_device.c +++ b/src/class/net/ncm_device.c @@ -34,6 +34,13 @@ #include "device/usbd_pvt.h" #include "net_device.h" +// Level where CFG_TUSB_DEBUG must be at least for this driver is logged +#ifndef CFG_TUD_NCM_LOG_LEVEL + #define CFG_TUD_NCM_LOG_LEVEL CFG_TUD_LOG_LEVEL +#endif + +#define TU_LOG_DRV(...) TU_LOG(CFG_TUD_NCM_LOG_LEVEL, __VA_ARGS__) + //--------------------------------------------------------------------+ // MACRO CONSTANT TYPEDEF //--------------------------------------------------------------------+ @@ -473,13 +480,13 @@ bool tud_network_can_xmit(uint16_t size) TU_VERIFY(ncm_interface.itf_data_alt == 1); if (ncm_interface.datagram_count >= ncm_interface.max_datagrams_per_ntb) { - TU_LOG2("NTB full [by count]\r\n"); + TU_LOG_DRV("NTB full [by count]\r\n"); return false; } size_t next_datagram_offset = ncm_interface.next_datagram_offset; if (next_datagram_offset + size > ncm_interface.ntb_in_size) { - TU_LOG2("ntb full [by size]\r\n"); + TU_LOG_DRV("ntb full [by size]\r\n"); return false; } diff --git a/src/class/video/video_device.c b/src/class/video/video_device.c index e6fadf41b..abc43ccff 100644 --- a/src/class/video/video_device.c +++ b/src/class/video/video_device.c @@ -34,6 +34,13 @@ #include "video_device.h" +// Level where CFG_TUSB_DEBUG must be at least for this driver is logged +#ifndef CFG_TUD_VIDEO_LOG_LEVEL + #define CFG_TUD_VIDEO_LOG_LEVEL CFG_TUD_LOG_LEVEL +#endif + +#define TU_LOG_DRV(...) TU_LOG(CFG_TUD_VIDEO_LOG_LEVEL, __VA_ARGS__) + //--------------------------------------------------------------------+ // MACRO CONSTANT TYPEDEF //--------------------------------------------------------------------+ @@ -609,17 +616,17 @@ static bool _close_vc_itf(uint8_t rhport, videod_interface_t *self) * @param[in] altnum The target alternate setting number. */ static bool _open_vc_itf(uint8_t rhport, videod_interface_t *self, uint_fast8_t altnum) { - TU_LOG2(" open VC %d\n", altnum); + TU_LOG_DRV(" open VC %d\n", altnum); uint8_t const *beg = self->beg; uint8_t const *end = beg + self->len; /* The first descriptor is a video control interface descriptor. */ uint8_t const *cur = _find_desc_itf(beg, end, _desc_itfnum(beg), altnum); - TU_LOG2(" cur %d\n", cur - beg); + TU_LOG_DRV(" cur %d\n", cur - beg); TU_VERIFY(cur < end); tusb_desc_vc_itf_t const *vc = (tusb_desc_vc_itf_t const *)cur; - TU_LOG2(" bInCollection %d\n", vc->ctl.bInCollection); + TU_LOG_DRV(" bInCollection %d\n", vc->ctl.bInCollection); /* Support for up to 2 streaming interfaces only. */ TU_ASSERT(vc->ctl.bInCollection <= CFG_TUD_VIDEO_STREAMING); @@ -628,7 +635,7 @@ static bool _open_vc_itf(uint8_t rhport, videod_interface_t *self, uint_fast8_t /* Advance to the next descriptor after the class-specific VC interface header descriptor. */ cur += vc->std.bLength + vc->ctl.bLength; - TU_LOG2(" bNumEndpoints %d\n", vc->std.bNumEndpoints); + TU_LOG_DRV(" bNumEndpoints %d\n", vc->std.bNumEndpoints); /* Open the notification endpoint if it exist. */ if (vc->std.bNumEndpoints) { /* Support for 1 endpoint only. */ @@ -662,7 +669,7 @@ static bool _init_vs_configuration(videod_streaming_interface_t *stm) static bool _open_vs_itf(uint8_t rhport, videod_streaming_interface_t *stm, uint_fast8_t altnum) { uint_fast8_t i; - TU_LOG2(" reopen VS %d\n", altnum); + TU_LOG_DRV(" reopen VS %d\n", altnum); uint8_t const *desc = _videod_itf[stm->index_vc].beg; /* Close endpoints of previous settings. */ @@ -672,7 +679,7 @@ static bool _open_vs_itf(uint8_t rhport, videod_streaming_interface_t *stm, uint uint8_t ep_adr = _desc_ep_addr(desc + ofs_ep); usbd_edpt_close(rhport, ep_adr); stm->desc.ep[i] = 0; - TU_LOG2(" close EP%02x\n", ep_adr); + TU_LOG_DRV(" close EP%02x\n", ep_adr); } /* clear transfer management information */ @@ -709,12 +716,12 @@ static bool _open_vs_itf(uint8_t rhport, videod_streaming_interface_t *stm, uint } TU_ASSERT(usbd_edpt_open(rhport, ep)); stm->desc.ep[i] = (uint16_t) (cur - desc); - TU_LOG2(" open EP%02x\n", _desc_ep_addr(cur)); + TU_LOG_DRV(" open EP%02x\n", _desc_ep_addr(cur)); } if (altnum) { stm->state = VS_STATE_STREAMING; } - TU_LOG2(" done\n"); + TU_LOG_DRV(" done\n"); return true; } diff --git a/src/host/usbh.c b/src/host/usbh.c index c8eb91be3..49f8c78f1 100644 --- a/src/host/usbh.c +++ b/src/host/usbh.c @@ -45,13 +45,6 @@ #define CFG_TUH_INTERFACE_MAX 8 #endif -// Level where CFG_TUSB_DEBUG must be at least for USBH is logged -#ifndef CFG_TUH_LOG_LEVEL - #define CFG_TUH_LOG_LEVEL 2 -#endif - -#define TU_LOG_USBH(...) TU_LOG(CFG_TUH_LOG_LEVEL, __VA_ARGS__) - //--------------------------------------------------------------------+ // USBH-HCD common data structure //--------------------------------------------------------------------+ diff --git a/src/host/usbh_classdriver.h b/src/host/usbh_classdriver.h index be9811641..308b4418a 100644 --- a/src/host/usbh_classdriver.h +++ b/src/host/usbh_classdriver.h @@ -35,6 +35,13 @@ extern "C" { #endif +// Level where CFG_TUSB_DEBUG must be at least for USBH is logged +#ifndef CFG_TUH_LOG_LEVEL + #define CFG_TUH_LOG_LEVEL 2 +#endif + +#define TU_LOG_USBH(...) TU_LOG(CFG_TUH_LOG_LEVEL, __VA_ARGS__) + enum { USBH_EPSIZE_BULK_MAX = (TUH_OPT_HIGH_SPEED ? TUSB_EPSIZE_BULK_HS : TUSB_EPSIZE_BULK_FS) }; -- cgit v1.3.1 From 18646179d0c784660ca261fb675e21787451655b Mon Sep 17 00:00:00 2001 From: hathach Date: Mon, 7 Aug 2023 18:23:16 +0700 Subject: fix host msc get maxlun not using aligned section memory --- src/class/msc/msc_host.c | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) (limited to 'src/class') diff --git a/src/class/msc/msc_host.c b/src/class/msc/msc_host.c index a65208d69..90a58d3d0 100644 --- a/src/class/msc/msc_host.c +++ b/src/class/msc/msc_host.c @@ -421,8 +421,7 @@ bool msch_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *de return true; } -bool msch_set_config(uint8_t dev_addr, uint8_t itf_num) -{ +bool msch_set_config(uint8_t dev_addr, uint8_t itf_num) { msch_interface_t* p_msc = get_itf(dev_addr); TU_ASSERT(p_msc->itf_num == itf_num); @@ -430,10 +429,8 @@ bool msch_set_config(uint8_t dev_addr, uint8_t itf_num) //------------- Get Max Lun -------------// TU_LOG_DRV("MSC Get Max Lun\r\n"); - tusb_control_request_t const request = - { - .bmRequestType_bit = - { + tusb_control_request_t const request = { + .bmRequestType_bit = { .recipient = TUSB_REQ_RCPT_INTERFACE, .type = TUSB_REQ_TYPE_CLASS, .direction = TUSB_DIR_IN @@ -444,12 +441,11 @@ bool msch_set_config(uint8_t dev_addr, uint8_t itf_num) .wLength = 1 }; - tuh_xfer_t xfer = - { + tuh_xfer_t xfer = { .daddr = dev_addr, .ep_addr = 0, .setup = &request, - .buffer = &p_msc->max_lun, + .buffer = _msch_buffer, .complete_cb = config_get_maxlun_complete, .user_data = 0 }; @@ -467,6 +463,8 @@ static void config_get_maxlun_complete (tuh_xfer_t* xfer) p_msc->max_lun = (XFER_RESULT_SUCCESS == xfer->result) ? _msch_buffer[0] : 0; p_msc->max_lun++; // MAX LUN is minus 1 by specs + TU_LOG_DRV(" Max LUN = %u\r\n", p_msc->max_lun); + // TODO multiple LUN support TU_LOG_DRV("SCSI Test Unit Ready\r\n"); uint8_t const lun = 0; -- cgit v1.3.1 From 798ff807b3361a5859945cb23c3d0fd7d1a5679f Mon Sep 17 00:00:00 2001 From: Hardy Griech Date: Fri, 11 Aug 2023 18:04:34 +0200 Subject: removed obsolete tud_network_link_state_cb() --- src/class/net/ncm_device.c | 7 ------- src/class/net/net_device.h | 5 ----- test/fuzz/net_fuzz.cc | 10 +--------- 3 files changed, 1 insertion(+), 21 deletions(-) (limited to 'src/class') diff --git a/src/class/net/ncm_device.c b/src/class/net/ncm_device.c index 226c42c4e..dc086cf5c 100644 --- a/src/class/net/ncm_device.c +++ b/src/class/net/ncm_device.c @@ -337,11 +337,6 @@ static void ncm_report(void) } } -TU_ATTR_WEAK void tud_network_link_state_cb(bool state) -{ - (void)state; -} - // Handle class control request // return false to stall control endpoint (e.g unsupported request) bool netd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request) @@ -381,8 +376,6 @@ bool netd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t ncm_report(); } } - - tud_network_link_state_cb(ncm_interface.itf_data_alt); } tud_control_status(rhport, request); diff --git a/src/class/net/net_device.h b/src/class/net/net_device.h index 399916355..454fde861 100644 --- a/src/class/net/net_device.h +++ b/src/class/net/net_device.h @@ -96,11 +96,6 @@ void tud_network_init_cb(void); // TODO removed later since it is not part of tinyusb stack extern uint8_t tud_network_mac_address[6]; -//------------- NCM -------------// - -// callback to client providing optional indication of internal state of network driver -void tud_network_link_state_cb(bool state); - //--------------------------------------------------------------------+ // INTERNAL USBD-CLASS DRIVER API //--------------------------------------------------------------------+ diff --git a/test/fuzz/net_fuzz.cc b/test/fuzz/net_fuzz.cc index 63cd1ac98..468437b0c 100644 --- a/test/fuzz/net_fuzz.cc +++ b/test/fuzz/net_fuzz.cc @@ -69,14 +69,6 @@ void tud_network_init_cb(void) { // TODO removed later since it is not part of tinyusb stack uint8_t tud_network_mac_address[6] = {0}; -//------------- NCM -------------// - -// callback to client providing optional indication of internal state of network -// driver -void tud_network_link_state_cb(bool state) { - (void)state; - // NoOp. -} -} +} // extern "C" #endif -- cgit v1.3.1 From bd51afb091f29cdab6520479a1a504409d95aac8 Mon Sep 17 00:00:00 2001 From: tswan-quasi Date: Mon, 14 Aug 2023 08:49:52 -0400 Subject: min on cdc r/w --- src/class/cdc/cdc_device.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/class') diff --git a/src/class/cdc/cdc_device.c b/src/class/cdc/cdc_device.c index 70d9c2e24..2c1fda4ff 100644 --- a/src/class/cdc/cdc_device.c +++ b/src/class/cdc/cdc_device.c @@ -150,7 +150,7 @@ uint32_t tud_cdc_n_available(uint8_t itf) uint32_t tud_cdc_n_read(uint8_t itf, void* buffer, uint32_t bufsize) { cdcd_interface_t* p_cdc = &_cdcd_itf[itf]; - uint32_t num_read = tu_fifo_read_n(&p_cdc->rx_ff, buffer, (uint16_t) bufsize); + uint32_t num_read = tu_fifo_read_n(&p_cdc->rx_ff, buffer, (uint16_t) TU_MIN(bufsize, 65535)); _prep_out_transaction(p_cdc); return num_read; } @@ -173,7 +173,7 @@ void tud_cdc_n_read_flush (uint8_t itf) uint32_t tud_cdc_n_write(uint8_t itf, void const* buffer, uint32_t bufsize) { cdcd_interface_t* p_cdc = &_cdcd_itf[itf]; - uint16_t ret = tu_fifo_write_n(&p_cdc->tx_ff, buffer, (uint16_t) bufsize); + uint16_t ret = tu_fifo_write_n(&p_cdc->tx_ff, buffer, (uint16_t) TU_MIN(bufsize, 65535)); // flush if queue more than packet size // may need to suppress -Wunreachable-code since most of the time CFG_TUD_CDC_TX_BUFSIZE < BULK_PACKET_SIZE -- cgit v1.3.1 From b5ba12119dccb123aa6e8798dc86d639af6703b9 Mon Sep 17 00:00:00 2001 From: tswan-quasi Date: Mon, 14 Aug 2023 09:01:30 -0400 Subject: UINT16_MAX stdint macro usage --- src/class/cdc/cdc_device.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/class') diff --git a/src/class/cdc/cdc_device.c b/src/class/cdc/cdc_device.c index 2c1fda4ff..c26264e60 100644 --- a/src/class/cdc/cdc_device.c +++ b/src/class/cdc/cdc_device.c @@ -150,7 +150,7 @@ uint32_t tud_cdc_n_available(uint8_t itf) uint32_t tud_cdc_n_read(uint8_t itf, void* buffer, uint32_t bufsize) { cdcd_interface_t* p_cdc = &_cdcd_itf[itf]; - uint32_t num_read = tu_fifo_read_n(&p_cdc->rx_ff, buffer, (uint16_t) TU_MIN(bufsize, 65535)); + uint32_t num_read = tu_fifo_read_n(&p_cdc->rx_ff, buffer, (uint16_t) TU_MIN(bufsize, UINT16_MAX)); _prep_out_transaction(p_cdc); return num_read; } @@ -173,7 +173,7 @@ void tud_cdc_n_read_flush (uint8_t itf) uint32_t tud_cdc_n_write(uint8_t itf, void const* buffer, uint32_t bufsize) { cdcd_interface_t* p_cdc = &_cdcd_itf[itf]; - uint16_t ret = tu_fifo_write_n(&p_cdc->tx_ff, buffer, (uint16_t) TU_MIN(bufsize, 65535)); + uint16_t ret = tu_fifo_write_n(&p_cdc->tx_ff, buffer, (uint16_t) TU_MIN(bufsize, UINT16_MAX)); // flush if queue more than packet size // may need to suppress -Wunreachable-code since most of the time CFG_TUD_CDC_TX_BUFSIZE < BULK_PACKET_SIZE -- cgit v1.3.1 From 1b33a315365184a74a8b5bbce5fdbdfc4dfe6f69 Mon Sep 17 00:00:00 2001 From: hathach Date: Tue, 15 Aug 2023 22:51:21 +0700 Subject: more minor clean up - also rename usbh_classdriver.h to usbh_pvt.h to consitent with usbd --- src/class/cdc/cdc_host.c | 2 +- src/class/hid/hid_host.c | 2 +- src/class/msc/msc_host.c | 2 +- src/device/usbd.c | 31 +++++-------- src/device/usbd_pvt.h | 2 +- src/host/hub.c | 2 +- src/host/usbh.c | 84 ++++++++++++++++----------------- src/host/usbh_classdriver.h | 111 -------------------------------------------- src/host/usbh_pvt.h | 108 ++++++++++++++++++++++++++++++++++++++++++ src/tusb.c | 2 +- 10 files changed, 164 insertions(+), 182 deletions(-) delete mode 100644 src/host/usbh_classdriver.h create mode 100644 src/host/usbh_pvt.h (limited to 'src/class') diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index 40ebd331d..53e15710e 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -29,7 +29,7 @@ #if (CFG_TUH_ENABLED && CFG_TUH_CDC) #include "host/usbh.h" -#include "host/usbh_classdriver.h" +#include "host/usbh_pvt.h" #include "cdc_host.h" diff --git a/src/class/hid/hid_host.c b/src/class/hid/hid_host.c index 4253170d4..a3551c85a 100644 --- a/src/class/hid/hid_host.c +++ b/src/class/hid/hid_host.c @@ -29,7 +29,7 @@ #if (CFG_TUH_ENABLED && CFG_TUH_HID) #include "host/usbh.h" -#include "host/usbh_classdriver.h" +#include "host/usbh_pvt.h" #include "hid_host.h" diff --git a/src/class/msc/msc_host.c b/src/class/msc/msc_host.c index 90a58d3d0..da264142c 100644 --- a/src/class/msc/msc_host.c +++ b/src/class/msc/msc_host.c @@ -29,7 +29,7 @@ #if CFG_TUH_ENABLED && CFG_TUH_MSC #include "host/usbh.h" -#include "host/usbh_classdriver.h" +#include "host/usbh_pvt.h" #include "msc_host.h" diff --git a/src/device/usbd.c b/src/device/usbd.c index 156b92ce1..f0d9fba52 100644 --- a/src/device/usbd.c +++ b/src/device/usbd.c @@ -238,34 +238,25 @@ enum { BUILTIN_DRIVER_COUNT = TU_ARRAY_SIZE(_usbd_driver) }; tu_static usbd_class_driver_t const * _app_driver = NULL; tu_static uint8_t _app_driver_count = 0; +#define TOTAL_DRIVER_COUNT (_app_driver_count + BUILTIN_DRIVER_COUNT) + // virtually joins built-in and application drivers together. // Application is positioned first to allow overwriting built-in ones. static inline usbd_class_driver_t const * get_driver(uint8_t drvid) { - // Application drivers - if ( usbd_app_driver_get_cb ) - { - if ( drvid < _app_driver_count ) return &_app_driver[drvid]; - drvid -= _app_driver_count; - } - - // when there is no built-in drivers BUILTIN_DRIVER_COUNT = 0 will cause -Wtype-limits warning -#ifdef __GNUC__ -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wtype-limits" -#endif - - // Built-in drivers - if (drvid < BUILTIN_DRIVER_COUNT) return &_usbd_driver[drvid]; + usbd_class_driver_t const * driver = NULL; -#ifdef __GNUC__ -#pragma GCC diagnostic pop -#endif + if ( drvid < _app_driver_count ) { + // Application drivers + driver = &_app_driver[drvid]; + } else if ( drvid < TOTAL_DRIVER_COUNT && BUILTIN_DRIVER_COUNT > 0 ){ + driver = &_usbd_driver[drvid - _app_driver_count]; + } - return NULL; + return driver; } -#define TOTAL_DRIVER_COUNT (_app_driver_count + BUILTIN_DRIVER_COUNT) + //--------------------------------------------------------------------+ // DCD Event diff --git a/src/device/usbd_pvt.h b/src/device/usbd_pvt.h index 940b2858b..16585167f 100644 --- a/src/device/usbd_pvt.h +++ b/src/device/usbd_pvt.h @@ -59,7 +59,7 @@ typedef struct } usbd_class_driver_t; // Invoked when initializing device stack to get additional class drivers. -// Can optionally implemented by application to extend/overwrite class driver support. +// Can be implemented by application to extend/overwrite class driver support. // Note: The drivers array must be accessible at all time when stack is active usbd_class_driver_t const* usbd_app_driver_get_cb(uint8_t* driver_count) TU_ATTR_WEAK; diff --git a/src/host/hub.c b/src/host/hub.c index ec30eb96a..32f5e0ac7 100644 --- a/src/host/hub.c +++ b/src/host/hub.c @@ -30,7 +30,7 @@ #include "hcd.h" #include "usbh.h" -#include "usbh_classdriver.h" +#include "usbh_pvt.h" #include "hub.h" // Debug level, TUSB_CFG_DEBUG must be at least this level for debug message diff --git a/src/host/usbh.c b/src/host/usbh.c index af8142be3..739157b56 100644 --- a/src/host/usbh.c +++ b/src/host/usbh.c @@ -30,7 +30,7 @@ #include "host/hcd.h" #include "tusb.h" -#include "host/usbh_classdriver.h" +#include "host/usbh_pvt.h" #include "hub.h" //--------------------------------------------------------------------+ @@ -183,6 +183,23 @@ static usbh_class_driver_t const usbh_class_drivers[] = enum { USBH_BUILTIN_DRIVER_COUNT = TU_ARRAY_SIZE(usbh_class_drivers) }; enum { CONFIG_NUM = 1 }; // default to use configuration 1 +// Additional class drivers implemented by application +tu_static usbh_class_driver_t const * _app_driver = NULL; +tu_static uint8_t _app_driver_count = 0; + +#define TOTAL_DRIVER_COUNT (_app_driver_count + USBH_BUILTIN_DRIVER_COUNT) + +static inline usbh_class_driver_t const *get_driver(uint8_t drv_id) { + usbh_class_driver_t const *driver = NULL; + + if ( drv_id < _app_driver_count ) { + driver = &_app_driver[drv_id]; + } else if ( drv_id < TOTAL_DRIVER_COUNT && USBH_BUILTIN_DRIVER_COUNT > 0) { + driver = &usbh_class_drivers[drv_id - _app_driver_count]; + } + + return driver; +} //--------------------------------------------------------------------+ // INTERNAL OBJECT & FUNCTION DECLARATION @@ -246,21 +263,6 @@ static void process_removing_device(uint8_t rhport, uint8_t hub_addr, uint8_t hu static bool usbh_edpt_control_open(uint8_t dev_addr, uint8_t max_packet_size); static bool usbh_control_xfer_cb (uint8_t daddr, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes); -// Additional class drivers implemented by application -tu_static usbh_class_driver_t const * _app_driver = NULL; -tu_static uint8_t _app_driver_count = 0; -tu_static uint8_t _total_driver_count = USBH_BUILTIN_DRIVER_COUNT; - -static usbh_class_driver_t const * usbh_get_driver(uint8_t drv_id) -{ - usbh_class_driver_t const * driver = NULL; - if ( drv_id < _app_driver_count ) - driver = &_app_driver[drv_id]; - else if ( drv_id < _total_driver_count ) - driver = &usbh_class_drivers[drv_id - _app_driver_count]; - return driver; -} - #if CFG_TUSB_OS == OPT_OS_NONE // TODO rework time-related function later // weak and overridable @@ -354,11 +356,10 @@ bool tuh_init(uint8_t controller_id) { _usbh_mutex = osal_mutex_create(&_usbh_mutexdef); TU_ASSERT(_usbh_mutex); #endif + // Get application driver if available - if ( usbh_app_driver_get_cb ) - { + if ( usbh_app_driver_get_cb ) { _app_driver = usbh_app_driver_get_cb(&_app_driver_count); - _total_driver_count = USBH_BUILTIN_DRIVER_COUNT + _app_driver_count; } // Device @@ -372,9 +373,9 @@ bool tuh_init(uint8_t controller_id) { } // Class drivers - for (uint8_t drv_id = 0; drv_id < _total_driver_count; drv_id++) + for (uint8_t drv_id = 0; drv_id < TOTAL_DRIVER_COUNT; drv_id++) { - usbh_class_driver_t const * driver = usbh_get_driver(drv_id); + usbh_class_driver_t const * driver = get_driver(drv_id); if ( driver ) { TU_LOG_USBH("%s init\r\n", driver->name); @@ -508,12 +509,12 @@ void tuh_task_ext(uint32_t timeout_ms, bool in_isr) { #endif { uint8_t drv_id = dev->ep2drv[epnum][ep_dir]; - usbh_class_driver_t const * driver = usbh_get_driver(drv_id); + usbh_class_driver_t const * driver = get_driver(drv_id); if ( driver ) { TU_LOG_USBH("%s xfer callback\r\n", driver->name); driver->xfer_cb(event.dev_addr, ep_addr, (xfer_result_t) event.xfer_complete.result, - event.xfer_complete.len); + event.xfer_complete.len); } else { @@ -1220,12 +1221,10 @@ static void process_removing_device(uint8_t rhport, uint8_t hub_addr, uint8_t hu // 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)) - { + (hub_port == 0 || dev->hub_port == hub_port)) { TU_LOG_USBH("Device unplugged address = %u\r\n", daddr); - if (is_hub_addr(daddr)) - { + if (is_hub_addr(daddr)) { TU_LOG(CFG_TUH_LOG_LEVEL, " is a HUB device %u\r\n", daddr); // Submit removed event If the device itself is a hub (un-rolled recursive) @@ -1243,14 +1242,11 @@ static void process_removing_device(uint8_t rhport, uint8_t hub_addr, uint8_t hu } // Close class driver - for (uint8_t drv_id = 0; drv_id < _total_driver_count; drv_id++) - { - usbh_class_driver_t const * driver = usbh_get_driver(drv_id); - if ( driver ) - { - driver->close(daddr); - } + 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); } + hcd_device_close(rhport, daddr); clear_device(dev); // abort on-going control xfer if any @@ -1679,10 +1675,9 @@ static bool _parse_configuration_descriptor(uint8_t dev_addr, tusb_desc_configur TU_ASSERT(drv_len >= sizeof(tusb_desc_interface_t)); // Find driver for this interface - uint8_t drv_id = 0; - for (; drv_id < _total_driver_count; drv_id++) + for (uint8_t drv_id = 0; drv_id < TOTAL_DRIVER_COUNT; drv_id++) { - usbh_class_driver_t const * driver = usbh_get_driver(drv_id); + usbh_class_driver_t const * driver = get_driver(drv_id); if (driver && driver->open(dev->rhport, dev_addr, desc_itf, drv_len) ) { @@ -1705,12 +1700,11 @@ static bool _parse_configuration_descriptor(uint8_t dev_addr, tusb_desc_configur break; // exit driver find loop } - } - - if( drv_id >= _total_driver_count ) - { - TU_LOG(CFG_TUH_LOG_LEVEL, "Interface %u: class = %u subclass = %u protocol = %u is not supported\r\n", - desc_itf->bInterfaceNumber, desc_itf->bInterfaceClass, desc_itf->bInterfaceSubClass, desc_itf->bInterfaceProtocol); + if ( drv_id == TOTAL_DRIVER_COUNT - 1 ) + { + TU_LOG(CFG_TUH_LOG_LEVEL, "[%u:%u] Interface %u: class = %u subclass = %u protocol = %u is not supported\r\n", + dev->rhport, dev_addr, desc_itf->bInterfaceNumber, desc_itf->bInterfaceClass, desc_itf->bInterfaceSubClass, desc_itf->bInterfaceProtocol); + } } // next Interface or IAD descriptor @@ -1730,9 +1724,9 @@ void usbh_driver_set_config_complete(uint8_t dev_addr, uint8_t itf_num) // IAD binding interface such as CDCs should return itf_num + 1 when complete // with usbh_driver_set_config_complete() uint8_t const drv_id = dev->itf2drv[itf_num]; - if (drv_id != TUSB_INDEX_INVALID_8) + usbh_class_driver_t const * driver = get_driver(drv_id); + if (driver) { - usbh_class_driver_t const * driver = usbh_get_driver(drv_id); TU_LOG_USBH("%s set config: itf = %u\r\n", driver->name, itf_num); driver->set_config(dev_addr, itf_num); break; diff --git a/src/host/usbh_classdriver.h b/src/host/usbh_classdriver.h deleted file mode 100644 index 7443b2d90..000000000 --- a/src/host/usbh_classdriver.h +++ /dev/null @@ -1,111 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2021, Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * This file is part of the TinyUSB stack. - */ - -#ifndef _TUSB_USBH_CLASSDRIVER_H_ -#define _TUSB_USBH_CLASSDRIVER_H_ - -#include "osal/osal.h" -#include "common/tusb_fifo.h" -#include "common/tusb_private.h" - -#ifdef __cplusplus - extern "C" { -#endif - -// Level where CFG_TUSB_DEBUG must be at least for USBH is logged -#ifndef CFG_TUH_LOG_LEVEL - #define CFG_TUH_LOG_LEVEL 2 -#endif - -#define TU_LOG_USBH(...) TU_LOG(CFG_TUH_LOG_LEVEL, __VA_ARGS__) - -enum { - USBH_EPSIZE_BULK_MAX = (TUH_OPT_HIGH_SPEED ? TUSB_EPSIZE_BULK_HS : TUSB_EPSIZE_BULK_FS) -}; - -//--------------------------------------------------------------------+ -// Class Driver API -//--------------------------------------------------------------------+ - -typedef struct { - #if CFG_TUSB_DEBUG >= 2 - char const* name; - #endif - - void (* const init )(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); - void (* const close )(uint8_t dev_addr); -} usbh_class_driver_t; - -// Call by class driver to tell USBH that it has complete the enumeration -void usbh_driver_set_config_complete(uint8_t dev_addr, uint8_t itf_num); - -uint8_t usbh_get_rhport(uint8_t dev_addr); - -uint8_t* usbh_get_enum_buf(void); - -void usbh_int_set(bool enabled); - -//--------------------------------------------------------------------+ -// USBH Endpoint API -//--------------------------------------------------------------------+ - -// Submit a usb transfer with callback support, require CFG_TUH_API_EDPT_XFER -bool usbh_edpt_xfer_with_callback(uint8_t dev_addr, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes, - tuh_xfer_cb_t complete_cb, uintptr_t user_data); - -TU_ATTR_ALWAYS_INLINE -static inline bool usbh_edpt_xfer(uint8_t dev_addr, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes) -{ - return usbh_edpt_xfer_with_callback(dev_addr, ep_addr, buffer, total_bytes, NULL, 0); -} - - -// Claim an endpoint before submitting a transfer. -// If caller does not make any transfer, it must release endpoint for others. -bool usbh_edpt_claim(uint8_t dev_addr, uint8_t ep_addr); - -// Release claimed endpoint without submitting a transfer -bool usbh_edpt_release(uint8_t dev_addr, uint8_t ep_addr); - -// Check if endpoint transferring is complete -bool usbh_edpt_busy(uint8_t dev_addr, uint8_t ep_addr); - -//--------------------------------------------------------------------+ -// USBH application additional driver API -//--------------------------------------------------------------------+ -// Invoked when initializing host stack to get additional class drivers. -// Can optionally implemented by application to extend/overwrite class driver support. -// Note: The drivers array must be accessible at all time when stack is active -usbh_class_driver_t const* usbh_app_driver_get_cb(uint8_t* driver_count) TU_ATTR_WEAK; - -#ifdef __cplusplus - } -#endif - -#endif diff --git a/src/host/usbh_pvt.h b/src/host/usbh_pvt.h new file mode 100644 index 000000000..0b58a91bc --- /dev/null +++ b/src/host/usbh_pvt.h @@ -0,0 +1,108 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2021, Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#ifndef _TUSB_USBH_CLASSDRIVER_H_ +#define _TUSB_USBH_CLASSDRIVER_H_ + +#include "osal/osal.h" +#include "common/tusb_fifo.h" +#include "common/tusb_private.h" + +#ifdef __cplusplus + extern "C" { +#endif + +// Level where CFG_TUSB_DEBUG must be at least for USBH is logged +#ifndef CFG_TUH_LOG_LEVEL + #define CFG_TUH_LOG_LEVEL 2 +#endif + +#define TU_LOG_USBH(...) TU_LOG(CFG_TUH_LOG_LEVEL, __VA_ARGS__) + +enum { + USBH_EPSIZE_BULK_MAX = (TUH_OPT_HIGH_SPEED ? TUSB_EPSIZE_BULK_HS : TUSB_EPSIZE_BULK_FS) +}; + +//--------------------------------------------------------------------+ +// Class Driver API +//--------------------------------------------------------------------+ + +typedef struct { + #if CFG_TUSB_DEBUG >= 2 + char const* name; + #endif + + void (* const init )(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); + void (* const close )(uint8_t dev_addr); +} usbh_class_driver_t; + +// Invoked when initializing host stack to get additional class drivers. +// Can be implemented by application to extend/overwrite class driver support. +// Note: The drivers array must be accessible at all time when stack is active +usbh_class_driver_t const* usbh_app_driver_get_cb(uint8_t* driver_count) TU_ATTR_WEAK; + +// Call by class driver to tell USBH that it has complete the enumeration +void usbh_driver_set_config_complete(uint8_t dev_addr, uint8_t itf_num); + +uint8_t usbh_get_rhport(uint8_t dev_addr); + +uint8_t* usbh_get_enum_buf(void); + +void usbh_int_set(bool enabled); + +//--------------------------------------------------------------------+ +// USBH Endpoint API +//--------------------------------------------------------------------+ + +// Submit a usb transfer with callback support, require CFG_TUH_API_EDPT_XFER +bool usbh_edpt_xfer_with_callback(uint8_t dev_addr, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes, + tuh_xfer_cb_t complete_cb, uintptr_t user_data); + +TU_ATTR_ALWAYS_INLINE +static inline bool usbh_edpt_xfer(uint8_t dev_addr, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes) +{ + return usbh_edpt_xfer_with_callback(dev_addr, ep_addr, buffer, total_bytes, NULL, 0); +} + + +// Claim an endpoint before submitting a transfer. +// If caller does not make any transfer, it must release endpoint for others. +bool usbh_edpt_claim(uint8_t dev_addr, uint8_t ep_addr); + +// Release claimed endpoint without submitting a transfer +bool usbh_edpt_release(uint8_t dev_addr, uint8_t ep_addr); + +// Check if endpoint transferring is complete +bool usbh_edpt_busy(uint8_t dev_addr, uint8_t ep_addr); + +#ifdef __cplusplus + } +#endif + +#endif diff --git a/src/tusb.c b/src/tusb.c index 465b608b0..7b0a669a0 100644 --- a/src/tusb.c +++ b/src/tusb.c @@ -36,7 +36,7 @@ #endif #if CFG_TUH_ENABLED -#include "host/usbh_classdriver.h" +#include "host/usbh_pvt.h" #endif //--------------------------------------------------------------------+ -- cgit v1.3.1 From fca08c939c0d04b9485413166b69f8abac6fb083 Mon Sep 17 00:00:00 2001 From: Hardy Griech Date: Sun, 20 Aug 2023 18:22:07 +0200 Subject: files taken from yapicoprobe --- src/class/net/ncm.h | 106 +++- src/class/net/ncm_device.c | 1281 +++++++++++++++++++++++++++++++------------- src/class/net/net_device.h | 24 +- 3 files changed, 997 insertions(+), 414 deletions(-) (limited to 'src/class') diff --git a/src/class/net/ncm.h b/src/class/net/ncm.h index 96ba11fbc..313237747 100644 --- a/src/class/net/ncm.h +++ b/src/class/net/ncm.h @@ -30,10 +30,47 @@ #include "common/tusb_common.h" -#ifdef __cplusplus - extern "C" { + +#ifndef CFG_TUD_NCM_IN_NTB_MAX_SIZE + /// must be >> MTU + #define CFG_TUD_NCM_IN_NTB_MAX_SIZE 3200 +#endif +#ifndef CFG_TUD_NCM_OUT_NTB_MAX_SIZE + /// must be >> MTU + #define CFG_TUD_NCM_OUT_NTB_MAX_SIZE 3200 +#endif + +#ifndef CFG_TUD_NCM_OUT_NTB_N + /// number of ntb buffers for reception side + /// 1 - good performance + /// 2 - up to 30% more performance with iperf with small packets + /// >2 - no performance gain + #define CFG_TUD_NCM_OUT_NTB_N 2 +#endif + +#ifndef CFG_TUD_NCM_IN_NTB_N + /// number of ntb buffers for transmission side + /// 1 - good performance but SystemView shows lost events (on load test) + /// 2 - up to 50% more performance with iperf with small packets, "tud_network_can_xmit: request blocked" + /// happens from time to time with SystemView + /// 3 - "tud_network_can_xmit: request blocked" never happens + /// >2 - no performance gain + #define CFG_TUD_NCM_IN_NTB_N 3 +#endif + +#ifndef CFG_TUD_NCM_MAX_DATAGRAMS_PER_NTB + /// this is for the transmission size for allocation of \a ndp16_datagram_t + #define CFG_TUD_NCM_MAX_DATAGRAMS_PER_NTB 8 +#endif + +#ifndef CFG_TUD_NCM_ALIGNMENT + #define CFG_TUD_NCM_ALIGNMENT 4 +#endif +#if (CFG_TUD_NCM_ALIGNMENT != 4) + #error "CFG_TUD_NCM_ALIGNMENT must be 4, otherwise the headers and start of datagrams have to be aligned (which they are currently not)" #endif + // Table 4.3 Data Class Interface Protocol Codes typedef enum { @@ -62,8 +99,67 @@ typedef enum NCM_SET_CRC_MODE = 0x8A, } ncm_request_code_t; -#ifdef __cplusplus - } -#endif + +#define NTH16_SIGNATURE 0x484D434E +#define NDP16_SIGNATURE_NCM0 0x304D434E +#define NDP16_SIGNATURE_NCM1 0x314D434E + +typedef struct TU_ATTR_PACKED { + uint16_t wLength; + uint16_t bmNtbFormatsSupported; + uint32_t dwNtbInMaxSize; + uint16_t wNdbInDivisor; + uint16_t wNdbInPayloadRemainder; + uint16_t wNdbInAlignment; + uint16_t wReserved; + uint32_t dwNtbOutMaxSize; + uint16_t wNdbOutDivisor; + uint16_t wNdbOutPayloadRemainder; + uint16_t wNdbOutAlignment; + uint16_t wNtbOutMaxDatagrams; +} ntb_parameters_t; + +typedef struct TU_ATTR_PACKED { + uint32_t dwSignature; + uint16_t wHeaderLength; + uint16_t wSequence; + uint16_t wBlockLength; + uint16_t wNdpIndex; +} nth16_t; + +typedef struct TU_ATTR_PACKED { + uint16_t wDatagramIndex; + uint16_t wDatagramLength; +} ndp16_datagram_t; + +typedef struct TU_ATTR_PACKED { + uint32_t dwSignature; + uint16_t wLength; + uint16_t wNextNdpIndex; + //ndp16_datagram_t datagram[]; +} ndp16_t; + +typedef union TU_ATTR_PACKED { + struct { + nth16_t nth; + ndp16_t ndp; + ndp16_datagram_t ndp_datagram[CFG_TUD_NCM_MAX_DATAGRAMS_PER_NTB + 1]; + }; + uint8_t data[CFG_TUD_NCM_IN_NTB_MAX_SIZE]; +} xmit_ntb_t; + +typedef union TU_ATTR_PACKED { + struct { + nth16_t nth; + // only the header is at a guaranteed position + }; + uint8_t data[CFG_TUD_NCM_OUT_NTB_MAX_SIZE]; +} recv_ntb_t; + +struct ncm_notify_t { + tusb_control_request_t header; + uint32_t downlink, uplink; +}; + #endif diff --git a/src/class/net/ncm_device.c b/src/class/net/ncm_device.c index 226c42c4e..f7a236e69 100644 --- a/src/class/net/ncm_device.c +++ b/src/class/net/ncm_device.c @@ -1,9 +1,7 @@ /* * The MIT License (MIT) * - * Copyright (c) 2020 Jacob Berg Potter - * Copyright (c) 2020 Peter Lawrence - * Copyright (c) 2019 Ha Thach (tinyusb.org) + * Copyright (c) 2023 Hardy Griech * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -26,493 +24,1004 @@ * This file is part of the TinyUSB stack. */ +/** + * Small Glossary (from the spec) + * -------------- + * Datagram - A collection of bytes forming a single item of information, passed as a unit from source to destination. + * NCM - Network Control Model + * NDP - NCM Datagram Pointer: NTB structure that delineates Datagrams (typically Ethernet frames) within an NTB + * NTB - NCM Transfer Block: a data structure for efficient USB encapsulation of one or more datagrams + * Each NTB is designed to be a single USB transfer + * NTH - NTB Header: a data structure at the front of each NTB, which provides the information needed to validate + * the NTB and begin decoding + * + * Some explanations + * ----------------- + * - rhport is the USB port of the device, in most cases "0" + * - itf_data_alt if != 0 -> data xmit/recv are allowed (see spec) + * - ep_in IN endpoints take data from the device intended to go in to the host (the device transmits) + * - ep_out OUT endpoints send data out of the host to the device (the device receives) + */ + #include "tusb_option.h" -#if ( CFG_TUD_ENABLED && CFG_TUD_NCM ) +#if ECLIPSE_GUI || ( CFG_TUD_ENABLED && CFG_TUD_NCM ) + +#include +#include +#include #include "device/usbd.h" #include "device/usbd_pvt.h" + #include "net_device.h" +#include "ncm.h" + + +#if !defined(tu_static) || ECLIPSE_GUI + // TinyUSB <=0.15.0 does not know "tu_static" + #define tu_static static +#endif -// Level where CFG_TUSB_DEBUG must be at least for this driver is logged -#ifndef CFG_TUD_NCM_LOG_LEVEL - #define CFG_TUD_NCM_LOG_LEVEL CFG_TUD_LOG_LEVEL +#if 0 + #define DEBUG_OUT(...) printf(__VA_ARGS__) + #define DEBUG_OUT_ENABLED +#else + #define DEBUG_OUT(...) #endif -#define TU_LOG_DRV(...) TU_LOG(CFG_TUD_NCM_LOG_LEVEL, __VA_ARGS__) +#if 0 + #define INFO_OUT(...) printf(__VA_ARGS__) +#else + #define INFO_OUT(...) +#endif + +#if 1 + #define ERROR_OUT(...) printf(__VA_ARGS__) +#else + #define ERROR_OUT(...) +#endif + +// calculate alignment of xmit datagrams within an NTB +#define XMIT_ALIGN_OFFSET(x) ((CFG_TUD_NCM_ALIGNMENT - ((x) & (CFG_TUD_NCM_ALIGNMENT - 1))) & (CFG_TUD_NCM_ALIGNMENT - 1)) + +//----------------------------------------------------------------------------- +// +// Module global things +// +#define XMIT_NTB_N CFG_TUD_NCM_IN_NTB_N +#define RECV_NTB_N CFG_TUD_NCM_OUT_NTB_N + +typedef struct { + // general + uint8_t ep_in; //!< endpoint for outgoing datagrams (naming is a little bit confusing) + uint8_t ep_out; //!< endpoint for incoming datagrams (naming is a little bit confusing) + uint8_t ep_notif; //!< endpoint for notifications + uint8_t itf_num; //!< interface number + uint8_t itf_data_alt; //!< ==0 -> no endpoints, i.e. no network traffic, ==1 -> normal operation with two endpoints (spec, chapter 5.3) + uint8_t rhport; //!< storage of \a rhport because some callbacks are done without it + + // recv handling + recv_ntb_t recv_ntb[RECV_NTB_N]; //!< actual recv NTBs + recv_ntb_t *recv_free_ntb[RECV_NTB_N]; //!< free list of recv NTBs + recv_ntb_t *recv_ready_ntb[RECV_NTB_N]; //!< NTBs waiting for transmission to glue logic + recv_ntb_t *recv_tinyusb_ntb; //!< buffer for the running transfer TinyUSB -> driver + recv_ntb_t *recv_glue_ntb; //!< buffer for the running transfer driver -> glue logic + uint16_t recv_glue_ntb_datagram_ndx; //!< index into \a recv_glue_ntb_datagram + + // xmit handling + xmit_ntb_t xmit_ntb[XMIT_NTB_N]; //!< actual xmit NTBs + xmit_ntb_t *xmit_free_ntb[XMIT_NTB_N]; //!< free list of xmit NTBs + xmit_ntb_t *xmit_ready_ntb[XMIT_NTB_N]; //!< NTBs waiting for transmission to TinyUSB + xmit_ntb_t *xmit_tinyusb_ntb; //!< buffer for the running transfer driver -> TinyUSB + xmit_ntb_t *xmit_glue_ntb; //!< buffer for the running transfer glue logic -> driver + uint16_t xmit_sequence; //!< NTB sequence counter + uint16_t xmit_glue_ntb_datagram_ndx; //!< index into \a xmit_glue_ntb_datagram + + // notification handling + enum { + NOTIFICATION_SPEED, + NOTIFICATION_CONNECTED, + NOTIFICATION_DONE + } notification_xmit_state; //!< state of notification transmission + bool notification_xmit_is_running; //!< notification is currently transmitted +} ncm_interface_t; + -//--------------------------------------------------------------------+ -// MACRO CONSTANT TYPEDEF -//--------------------------------------------------------------------+ +CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN tu_static ncm_interface_t ncm_interface; -#define NTH16_SIGNATURE 0x484D434E -#define NDP16_SIGNATURE_NCM0 0x304D434E -#define NDP16_SIGNATURE_NCM1 0x314D434E -typedef struct TU_ATTR_PACKED +/** + * This is the NTB parameter structure + * + * \attention + * We are lucky, that byte order is correct + */ +CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN tu_static const ntb_parameters_t ntb_parameters = { + .wLength = sizeof(ntb_parameters_t), + .bmNtbFormatsSupported = 0x01, // 16-bit NTB supported + .dwNtbInMaxSize = CFG_TUD_NCM_IN_NTB_MAX_SIZE, + .wNdbInDivisor = 4, + .wNdbInPayloadRemainder = 0, + .wNdbInAlignment = CFG_TUD_NCM_ALIGNMENT, + .wReserved = 0, + .dwNtbOutMaxSize = CFG_TUD_NCM_OUT_NTB_MAX_SIZE, + .wNdbOutDivisor = 4, + .wNdbOutPayloadRemainder = 0, + .wNdbOutAlignment = CFG_TUD_NCM_ALIGNMENT, + .wNtbOutMaxDatagrams = 6 // 0=no limit +}; + +// Some confusing remarks about wNtbOutMaxDatagrams... +// ==1 -> SystemView packets/s goes up to 2000 and events are lost during startup +// ==0 -> SystemView runs fine, iperf shows in wireshark a lot of error +// ==6 -> SystemView runs fine, iperf also +// >6 -> iperf starts to show errors +// -> 6 seems to be the best value. Why? Don't know, perhaps only on my system? +// switch \a INFO_OUT on to see interesting values for this. +// +// iperf: for MSS in 100 200 400 800 1200 1450 1500; do iperf -c 192.168.14.1 -e -i 1 -M $MSS -l 8192 -P 1; sleep 2; done +// sysview: SYSTICKS_PER_SEC=35000, IDLE_US=1000, PRINT_MOD=1000 +// + +//----------------------------------------------------------------------------- +// +// everything about notifications +// +tu_static struct ncm_notify_t ncm_notify_connected = { + .header = { + .bmRequestType_bit = { + .recipient = TUSB_REQ_RCPT_INTERFACE, + .type = TUSB_REQ_TYPE_CLASS, + .direction = TUSB_DIR_IN + }, + .bRequest = CDC_NOTIF_NETWORK_CONNECTION, + .wValue = 1 /* Connected */, + .wLength = 0, + }, +}; + +tu_static struct ncm_notify_t ncm_notify_speed_change = { + .header = { + .bmRequestType_bit = { + .recipient = TUSB_REQ_RCPT_INTERFACE, + .type = TUSB_REQ_TYPE_CLASS, + .direction = TUSB_DIR_IN + }, + .bRequest = CDC_NOTIF_CONNECTION_SPEED_CHANGE, + .wLength = 8, + }, + .downlink = 1000000, + .uplink = 1000000, +}; + + + +static void notification_xmit(uint8_t rhport, bool force_next) +/** + * Transmit next notification to the host (if appropriate). + * Notifications are transferred to the host once during connection setup. + */ { - uint16_t wLength; - uint16_t bmNtbFormatsSupported; - uint32_t dwNtbInMaxSize; - uint16_t wNdbInDivisor; - uint16_t wNdbInPayloadRemainder; - uint16_t wNdbInAlignment; - uint16_t wReserved; - uint32_t dwNtbOutMaxSize; - uint16_t wNdbOutDivisor; - uint16_t wNdbOutPayloadRemainder; - uint16_t wNdbOutAlignment; - uint16_t wNtbOutMaxDatagrams; -} ntb_parameters_t; - -typedef struct TU_ATTR_PACKED + DEBUG_OUT("notification_xmit(%d, %d) - %d %d\n", force_next, rhport, ncm_interface.notification_xmit_state, ncm_interface.notification_xmit_is_running); + + if ( !force_next && ncm_interface.notification_xmit_is_running) { + return; + } + + if (ncm_interface.notification_xmit_state == NOTIFICATION_SPEED) { + DEBUG_OUT(" NOTIFICATION_SPEED\n"); + ncm_notify_speed_change.header.wIndex = ncm_interface.itf_num; + usbd_edpt_xfer(rhport, ncm_interface.ep_notif, (uint8_t*) &ncm_notify_speed_change, sizeof(ncm_notify_speed_change)); + ncm_interface.notification_xmit_state = NOTIFICATION_CONNECTED; + ncm_interface.notification_xmit_is_running = true; + } + else if (ncm_interface.notification_xmit_state == NOTIFICATION_CONNECTED) { + DEBUG_OUT(" NOTIFICATION_CONNECTED\n"); + ncm_notify_connected.header.wIndex = ncm_interface.itf_num; + usbd_edpt_xfer(rhport, ncm_interface.ep_notif, (uint8_t*) &ncm_notify_connected, sizeof(ncm_notify_connected)); + ncm_interface.notification_xmit_state = NOTIFICATION_DONE; + ncm_interface.notification_xmit_is_running = true; + } + else { + DEBUG_OUT(" NOTIFICATION_FINISHED\n"); + } +} // notification_xmit + + +//----------------------------------------------------------------------------- +// +// everything about packet transmission (driver -> TinyUSB) +// + + +static void xmit_put_ntb_into_free_list(xmit_ntb_t *free_ntb) +/** + * Put NTB into the transmitter free list. + */ { - uint32_t dwSignature; - uint16_t wHeaderLength; - uint16_t wSequence; - uint16_t wBlockLength; - uint16_t wNdpIndex; -} nth16_t; - -typedef struct TU_ATTR_PACKED + DEBUG_OUT("xmit_put_ntb_into_free_list() - %p\n", ncm_interface.xmit_tinyusb_ntb); + + if (free_ntb == NULL) { + // can happen due to ZLPs + return; + } + + for (int i = 0; i < XMIT_NTB_N; ++i) { + if (ncm_interface.xmit_free_ntb[i] == NULL) { + ncm_interface.xmit_free_ntb[i] = free_ntb; + return; + } + } + ERROR_OUT("xmit_put_ntb_into_free_list - no entry in free list\n"); // this should not happen +} // xmit_put_ntb_into_free_list + + + +static xmit_ntb_t *xmit_get_free_ntb(void) +/** + * Get an NTB from the free list + */ { - uint16_t wDatagramIndex; - uint16_t wDatagramLength; -} ndp16_datagram_t; + DEBUG_OUT("xmit_get_free_ntb()\n"); + + for (int i = 0; i < XMIT_NTB_N; ++i) { + if (ncm_interface.xmit_free_ntb[i] != NULL) { + xmit_ntb_t *free = ncm_interface.xmit_free_ntb[i]; + ncm_interface.xmit_free_ntb[i] = NULL; + return free; + } + } + return NULL; +} // xmit_get_free_ntb -typedef struct TU_ATTR_PACKED + + +static void xmit_put_ntb_into_ready_list(xmit_ntb_t *ready_ntb) +/** + * Put a filled NTB into the ready list + */ { - uint32_t dwSignature; - uint16_t wLength; - uint16_t wNextNdpIndex; - ndp16_datagram_t datagram[]; -} ndp16_t; - -typedef union TU_ATTR_PACKED { - struct { - nth16_t nth; - ndp16_t ndp; - }; - uint8_t data[CFG_TUD_NCM_IN_NTB_MAX_SIZE]; -} transmit_ntb_t; - -struct ecm_notify_struct + INFO_OUT("xmit_put_ntb_into_ready_list(%p) %d\n", ready_ntb, ready_ntb->len); + + for (int i = 0; i < XMIT_NTB_N; ++i) { + if (ncm_interface.xmit_ready_ntb[i] == NULL) { + ncm_interface.xmit_ready_ntb[i] = ready_ntb; + return; + } + } + ERROR_OUT("xmit_put_ntb_into_ready_list: ready list full\n"); // this should not happen +} // xmit_put_ntb_into_ready_list + + + +static xmit_ntb_t *xmit_get_next_ready_ntb(void) +/** + * Get the next NTB from the ready list (and remove it from the list). + * If the ready list is empty, return NULL. + */ { - tusb_control_request_t header; - uint32_t downlink, uplink; -}; + xmit_ntb_t *r = NULL; -typedef struct + r = ncm_interface.xmit_ready_ntb[0]; + memmove(ncm_interface.xmit_ready_ntb + 0, ncm_interface.xmit_ready_ntb + 1, sizeof(ncm_interface.xmit_ready_ntb) - sizeof(ncm_interface.xmit_ready_ntb[0])); + + DEBUG_OUT("recv_get_next_ready_ntb: %p\n", r); + return r; +} // xmit_get_next_ready_ntb + + + +static bool xmit_insert_required_zlp(uint8_t rhport, uint16_t xferred_bytes) +/** + * Transmit a ZLP if required + * + * \note + * Insertion of the ZLPs is a little bit different then described in the spec. + * But the below implementation actually works. Don't know if this is a spec + * or TinyUSB issue. + * + * \pre + * This must be called from netd_xfer_cb() so that ep_in is ready + */ { - uint8_t itf_num; // Index number of Management Interface, +1 for Data Interface - uint8_t itf_data_alt; // Alternate setting of Data Interface. 0 : inactive, 1 : active + DEBUG_OUT("xmit_insert_required_zlp(%d,%d)\n", rhport, xferred_bytes); - uint8_t ep_notif; - uint8_t ep_in; - uint8_t ep_out; + if (xferred_bytes == 0 || xferred_bytes % CFG_TUD_NET_ENDPOINT_SIZE != 0) { + return false; + } - const ndp16_t *ndp; - uint8_t num_datagrams, current_datagram_index; + TU_ASSERT(ncm_interface.itf_data_alt == 1, false); + TU_ASSERT( !usbd_edpt_busy(rhport, ncm_interface.ep_in), false); - enum { - REPORT_SPEED, - REPORT_CONNECTED, - REPORT_DONE - } report_state; - bool report_pending; + INFO_OUT("xmit_insert_required_zlp! (%u)\n", (unsigned)xferred_bytes); - uint8_t current_ntb; // Index in transmit_ntb[] that is currently being filled with datagrams - uint8_t datagram_count; // Number of datagrams in transmit_ntb[current_ntb] - uint16_t next_datagram_offset; // Offset in transmit_ntb[current_ntb].data to place the next datagram - uint16_t ntb_in_size; // Maximum size of transmitted (IN to host) NTBs; initially CFG_TUD_NCM_IN_NTB_MAX_SIZE - uint8_t max_datagrams_per_ntb; // Maximum number of datagrams per NTB; initially CFG_TUD_NCM_MAX_DATAGRAMS_PER_NTB + // start transmission of the ZLP + usbd_edpt_xfer(rhport, ncm_interface.ep_in, NULL, 0); - uint16_t nth_sequence; // Sequence number counter for transmitted NTBs + return true; +} // xmit_insert_required_zlp - bool transferring; -} ncm_interface_t; -//--------------------------------------------------------------------+ -// INTERNAL OBJECT & FUNCTION DECLARATION -//--------------------------------------------------------------------+ - -CFG_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN tu_static const ntb_parameters_t ntb_parameters = { - .wLength = sizeof(ntb_parameters_t), - .bmNtbFormatsSupported = 0x01, - .dwNtbInMaxSize = CFG_TUD_NCM_IN_NTB_MAX_SIZE, - .wNdbInDivisor = 4, - .wNdbInPayloadRemainder = 0, - .wNdbInAlignment = CFG_TUD_NCM_ALIGNMENT, - .wReserved = 0, - .dwNtbOutMaxSize = CFG_TUD_NCM_OUT_NTB_MAX_SIZE, - .wNdbOutDivisor = 4, - .wNdbOutPayloadRemainder = 0, - .wNdbOutAlignment = CFG_TUD_NCM_ALIGNMENT, - .wNtbOutMaxDatagrams = 0 -}; +static void xmit_start_if_possible(uint8_t rhport) +/** + * Start transmission if it there is a waiting packet and if can be done from interface side. + */ +{ + DEBUG_OUT("xmit_start_if_possible()\n"); -CFG_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN tu_static transmit_ntb_t transmit_ntb[2]; + if (ncm_interface.xmit_tinyusb_ntb != NULL) { + DEBUG_OUT(" !xmit_start_if_possible 1\n"); + return; + } + if (ncm_interface.itf_data_alt != 1) { + ERROR_OUT(" !xmit_start_if_possible 2\n"); + return; + } + if (usbd_edpt_busy(rhport, ncm_interface.ep_in)) { + INFO_OUT(" !xmit_start_if_possible 3\n"); + return; + } -CFG_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN tu_static uint8_t receive_ntb[CFG_TUD_NCM_OUT_NTB_MAX_SIZE]; + ncm_interface.xmit_tinyusb_ntb = xmit_get_next_ready_ntb(); + if (ncm_interface.xmit_tinyusb_ntb == NULL) { + if (ncm_interface.xmit_glue_ntb == NULL || ncm_interface.xmit_glue_ntb_datagram_ndx == 0) { + // -> really nothing is waiting + return; + } + ncm_interface.xmit_tinyusb_ntb = ncm_interface.xmit_glue_ntb; + ncm_interface.xmit_glue_ntb = NULL; + } + +#if DEBUG_OUT_ENABLED + { + uint16_t len = ncm_interface.xmit_tinyusb_ntb->ntb.nth.wBlockLength; + DEBUG_OUT(" %d\n", len); + for (int i = 0; i < len; ++i) { + DEBUG_OUT(" %02x", ncm_interface.xmit_tinyusb_ntb->data[i]); + } + DEBUG_OUT("\n"); + } +#endif + + if (ncm_interface.xmit_glue_ntb_datagram_ndx != 1) { + DEBUG_OUT(">> %d %d\n", ncm_interface.xmit_tinyusb_ntb->len, ncm_interface.xmit_glue_ntb_datagram_ndx); + } -tu_static ncm_interface_t ncm_interface; + // Kick off an endpoint transfer + usbd_edpt_xfer(0, ncm_interface.ep_in, ncm_interface.xmit_tinyusb_ntb->data, ncm_interface.xmit_tinyusb_ntb->nth.wBlockLength); +} // xmit_start_if_possible -/* - * Set up the NTB state in ncm_interface to be ready to add datagrams. + + +static bool xmit_requested_datagram_fits_into_current_ntb(uint16_t datagram_size) +/** + * check if a new datagram fits into the current NTB */ -static void ncm_prepare_for_tx(void) { - ncm_interface.datagram_count = 0; - // datagrams start after all the headers - ncm_interface.next_datagram_offset = sizeof(nth16_t) + sizeof(ndp16_t) - + ((CFG_TUD_NCM_MAX_DATAGRAMS_PER_NTB + 1) * sizeof(ndp16_datagram_t)); -} +{ + DEBUG_OUT("xmit_requested_datagram_fits_into_current_ntb(%d) - %p %p\n", datagram_size, ncm_interface.xmit_tinyusb_ntb, ncm_interface.xmit_glue_ntb); -/* - * If not already transmitting, start sending the current NTB to the host and swap buffers - * to start filling the other one with datagrams. + if (ncm_interface.xmit_glue_ntb == NULL) { + return false; + } + if (ncm_interface.xmit_glue_ntb_datagram_ndx >= CFG_TUD_NCM_MAX_DATAGRAMS_PER_NTB) { + return false; + } + if (ncm_interface.xmit_glue_ntb->nth.wBlockLength + datagram_size + XMIT_ALIGN_OFFSET(datagram_size) > CFG_TUD_NCM_OUT_NTB_MAX_SIZE) { + return false; + } + return true; +} // xmit_requested_datagram_fits_into_current_ntb + + + +static bool xmit_setup_next_glue_ntb(void) +/** + * Setup an NTB for the glue logic */ -static void ncm_start_tx(void) { - if (ncm_interface.transferring) { - return; - } - - transmit_ntb_t *ntb = &transmit_ntb[ncm_interface.current_ntb]; - size_t ntb_length = ncm_interface.next_datagram_offset; - - // Fill in NTB header - ntb->nth.dwSignature = NTH16_SIGNATURE; - ntb->nth.wHeaderLength = sizeof(nth16_t); - ntb->nth.wSequence = ncm_interface.nth_sequence++; - ntb->nth.wBlockLength = ntb_length; - ntb->nth.wNdpIndex = sizeof(nth16_t); - - // Fill in NDP16 header and terminator - ntb->ndp.dwSignature = NDP16_SIGNATURE_NCM0; - ntb->ndp.wLength = sizeof(ndp16_t) + (ncm_interface.datagram_count + 1) * sizeof(ndp16_datagram_t); - ntb->ndp.wNextNdpIndex = 0; - ntb->ndp.datagram[ncm_interface.datagram_count].wDatagramIndex = 0; - ntb->ndp.datagram[ncm_interface.datagram_count].wDatagramLength = 0; - - // Kick off an endpoint transfer - usbd_edpt_xfer(0, ncm_interface.ep_in, ntb->data, ntb_length); - ncm_interface.transferring = true; - - // Swap to the other NTB and clear it out - ncm_interface.current_ntb = 1 - ncm_interface.current_ntb; - ncm_prepare_for_tx(); -} - -tu_static struct ecm_notify_struct ncm_notify_connected = { - .header = { - .bmRequestType_bit = { - .recipient = TUSB_REQ_RCPT_INTERFACE, - .type = TUSB_REQ_TYPE_CLASS, - .direction = TUSB_DIR_IN - }, - .bRequest = CDC_NOTIF_NETWORK_CONNECTION, - .wValue = 1 /* Connected */, - .wLength = 0, - }, -}; + DEBUG_OUT("xmit_setup_next_glue_ntb - %p\n", ncm_interface.xmit_glue_ntb); + + if (ncm_interface.xmit_glue_ntb != NULL) { + // put NTB into waiting list (the new datagram did not fit in) + xmit_put_ntb_into_ready_list(ncm_interface.xmit_glue_ntb); + } + + ncm_interface.xmit_glue_ntb = xmit_get_free_ntb(); // get next buffer (if any) + if (ncm_interface.xmit_glue_ntb == NULL) { + DEBUG_OUT(" xmit_setup_next_glue_ntb - nothing free\n"); // should happen rarely + return false; + } + + ncm_interface.xmit_glue_ntb_datagram_ndx = 0; + + xmit_ntb_t *ntb = ncm_interface.xmit_glue_ntb; + + // Fill in NTB header + ntb->nth.dwSignature = NTH16_SIGNATURE; + ntb->nth.wHeaderLength = sizeof(ntb->nth); + ntb->nth.wSequence = ncm_interface.xmit_sequence++; + ntb->nth.wBlockLength = sizeof(ntb->nth) + sizeof(ntb->ndp) + sizeof(ntb->ndp_datagram); + ntb->nth.wNdpIndex = sizeof(ntb->nth); + + // Fill in NDP16 header and terminator + ntb->ndp.dwSignature = NDP16_SIGNATURE_NCM0; + ntb->ndp.wLength = sizeof(ntb->ndp) + sizeof(ntb->ndp_datagram); + ntb->ndp.wNextNdpIndex = 0; + + memset(ntb->ndp_datagram, 0, sizeof(ntb->ndp_datagram)); + return true; +} // xmit_setup_next_glue_ntb + -tu_static struct ecm_notify_struct ncm_notify_speed_change = +//----------------------------------------------------------------------------- +// +// all the recv_*() stuff (TinyUSB -> driver -> glue logic) +// + + +static recv_ntb_t *recv_get_free_ntb(void) +/** + * Return pointer to an available receive buffer or NULL. + * Returned buffer (if any) has the size \a CFG_TUD_NCM_OUT_NTB_MAX_SIZE. + */ { - .header = { - .bmRequestType_bit = { - .recipient = TUSB_REQ_RCPT_INTERFACE, - .type = TUSB_REQ_TYPE_CLASS, - .direction = TUSB_DIR_IN - }, - .bRequest = CDC_NOTIF_CONNECTION_SPEED_CHANGE, - .wLength = 8, - }, - .downlink = 10000000, - .uplink = 10000000, -}; + DEBUG_OUT("recv_get_free_ntb()\n"); -void tud_network_recv_renew(void) + for (int i = 0; i < RECV_NTB_N; ++i) { + if (ncm_interface.recv_free_ntb[i] != NULL) { + recv_ntb_t *free = ncm_interface.recv_free_ntb[i]; + ncm_interface.recv_free_ntb[i] = NULL; + return free; + } + } + return NULL; +} // recv_get_free_ntb + + + +static recv_ntb_t *recv_get_next_ready_ntb(void) +/** + * Get the next NTB from the ready list (and remove it from the list). + * If the ready list is empty, return NULL. + */ { - if (!ncm_interface.num_datagrams) - { - usbd_edpt_xfer(0, ncm_interface.ep_out, receive_ntb, sizeof(receive_ntb)); - return; - } + recv_ntb_t *r = NULL; - const ndp16_t *ndp = ncm_interface.ndp; - const int i = ncm_interface.current_datagram_index; - ncm_interface.current_datagram_index++; - ncm_interface.num_datagrams--; + r = ncm_interface.recv_ready_ntb[0]; + memmove(ncm_interface.recv_ready_ntb + 0, ncm_interface.recv_ready_ntb + 1, sizeof(ncm_interface.recv_ready_ntb) - sizeof(ncm_interface.recv_ready_ntb[0])); - tud_network_recv_cb(receive_ntb + ndp->datagram[i].wDatagramIndex, ndp->datagram[i].wDatagramLength); -} + DEBUG_OUT("recv_get_next_ready_ntb: %p\n", r); + return r; +} // recv_get_next_ready_ntb -//--------------------------------------------------------------------+ -// USBD Driver API -//--------------------------------------------------------------------+ -void netd_init(void) + +static void recv_put_ntb_into_free_list(recv_ntb_t *free_ntb) +/** + * + */ { - tu_memclr(&ncm_interface, sizeof(ncm_interface)); - ncm_interface.ntb_in_size = CFG_TUD_NCM_IN_NTB_MAX_SIZE; - ncm_interface.max_datagrams_per_ntb = CFG_TUD_NCM_MAX_DATAGRAMS_PER_NTB; - ncm_prepare_for_tx(); -} + DEBUG_OUT("recv_put_ntb_into_free_list(%p)\n", free_ntb); -void netd_reset(uint8_t rhport) + for (int i = 0; i < RECV_NTB_N; ++i) { + if (ncm_interface.recv_free_ntb[i] == NULL) { + ncm_interface.recv_free_ntb[i] = free_ntb; + return; + } + } + ERROR_OUT("recv_put_ntb_into_free_list - no entry in free list\n"); // this should not happen +} // recv_put_ntb_into_free_list + + + +static void recv_put_ntb_into_ready_list(recv_ntb_t *ready_ntb) +/** + * The \a ncm_interface.recv_tinyusb_ntb is filled, + * put this buffer into the waiting list and free the receive logic. + */ { - (void) rhport; + DEBUG_OUT("recv_put_ntb_into_ready_list(%p) %d\n", ready_ntb, ready_ntb->len); + + for (int i = 0; i < RECV_NTB_N; ++i) { + if (ncm_interface.recv_ready_ntb[i] == NULL) { + ncm_interface.recv_ready_ntb[i] = ready_ntb; + return; + } + } + ERROR_OUT("recv_put_ntb_into_ready_list: ready list full\n"); // this should not happen +} // recv_put_ntb_into_ready_list + - netd_init(); -} -uint16_t netd_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len) +static void recv_try_to_start_new_reception(uint8_t rhport) +/** + * If possible, start a new reception TinyUSB -> driver. + * Return value is actually not of interest. + */ { - // confirm interface hasn't already been allocated - TU_ASSERT(0 == ncm_interface.ep_notif, 0); + DEBUG_OUT("recv_try_to_start_new_reception(%d)\n", rhport); - //------------- Management Interface -------------// - ncm_interface.itf_num = itf_desc->bInterfaceNumber; + if (ncm_interface.itf_data_alt != 1) { + return; + } + if (ncm_interface.recv_tinyusb_ntb != NULL) { + return; + } + if (usbd_edpt_busy(ncm_interface.rhport, ncm_interface.ep_out)) { + return; + } - uint16_t drv_len = sizeof(tusb_desc_interface_t); - uint8_t const * p_desc = tu_desc_next( itf_desc ); + ncm_interface.recv_tinyusb_ntb = recv_get_free_ntb(); + if (ncm_interface.recv_tinyusb_ntb == NULL) { + return; + } - // Communication Functional Descriptors - while ( TUSB_DESC_CS_INTERFACE == tu_desc_type(p_desc) && drv_len <= max_len ) - { - drv_len += tu_desc_len(p_desc); - p_desc = tu_desc_next(p_desc); - } + // initiate transfer + DEBUG_OUT(" start reception\n"); + bool r = usbd_edpt_xfer(0, ncm_interface.ep_out, ncm_interface.recv_tinyusb_ntb->data, CFG_TUD_NCM_OUT_NTB_MAX_SIZE); + if ( !r) { + recv_put_ntb_into_free_list(ncm_interface.recv_tinyusb_ntb); + ncm_interface.recv_tinyusb_ntb = NULL; + } +} // recv_try_to_start_new_reception - // notification endpoint (if any) - if ( TUSB_DESC_ENDPOINT == tu_desc_type(p_desc) ) - { - TU_ASSERT( usbd_edpt_open(rhport, (tusb_desc_endpoint_t const *) p_desc), 0 ); - ncm_interface.ep_notif = ((tusb_desc_endpoint_t const *) p_desc)->bEndpointAddress; - drv_len += tu_desc_len(p_desc); - p_desc = tu_desc_next(p_desc); - } +static bool recv_validate_datagram(const recv_ntb_t *ntb, uint16_t len) +/** + * Validate incoming datagram. + * \return true if valid + * + * \note + * \a ndp16->wNextNdpIndex != 0 is not supported + */ +{ + const nth16_t *nth16 = &(ntb->nth); - //------------- Data Interface -------------// - // - CDC-NCM data interface has 2 alternate settings - // - 0 : zero endpoints for inactive (default) - // - 1 : IN & OUT endpoints for transfer of NTBs - TU_ASSERT(TUSB_DESC_INTERFACE == tu_desc_type(p_desc), 0); + DEBUG_OUT("recv_validate_datagram(%p)\n", ntb); - do - { - tusb_desc_interface_t const * data_itf_desc = (tusb_desc_interface_t const *) p_desc; - TU_ASSERT(TUSB_CLASS_CDC_DATA == data_itf_desc->bInterfaceClass, 0); + // + // check header + // + if (nth16->wHeaderLength != sizeof(nth16_t)) + { + ERROR_OUT(" ill nth16 length: %d\n", nth16->wHeaderLength); + return false; + } + if (nth16->dwSignature != NTH16_SIGNATURE) { + ERROR_OUT(" ill signature: 0x%08x\n", (unsigned)nth16->dwSignature); + return false; + } + if (len < sizeof(nth16_t) + sizeof(ndp16_t) + 2*sizeof(ndp16_datagram_t)) { + ERROR_OUT(" ill min len: %d\n", len); + return false; + } + if (nth16->wBlockLength > len) { + ERROR_OUT(" ill block length: %d > %d\n", nth16->wBlockLength, len); + return false; + } + if (nth16->wBlockLength > CFG_TUD_NCM_OUT_NTB_MAX_SIZE) { + ERROR_OUT(" ill block length2: %d > %d\n", nth16->wBlockLength, CFG_TUD_NCM_OUT_NTB_MAX_SIZE); + return false; + } + if (nth16->wNdpIndex < sizeof(nth16) || nth16->wNdpIndex > len - (sizeof(ndp16_t) + 2*sizeof(ndp16_datagram_t))) { + ERROR_OUT(" ill position of first ndp: %d (%d)\n", nth16->wNdpIndex, len); + return false; + } - drv_len += tu_desc_len(p_desc); - p_desc = tu_desc_next(p_desc); - } while((TUSB_DESC_INTERFACE == tu_desc_type(p_desc)) && (drv_len <= max_len)); + // + // check (first) NDP(16) + // + const ndp16_t *ndp16 = (ndp16_t *)(ntb->data + nth16->wNdpIndex); - // Pair of endpoints - TU_ASSERT(TUSB_DESC_ENDPOINT == tu_desc_type(p_desc), 0); + if (ndp16->wLength < sizeof(ndp16_t) + 2*sizeof(ndp16_datagram_t)) { + ERROR_OUT(" ill ndp16 length: %d\n", ndp16->wLength); + return false; + } + if (ndp16->dwSignature != NDP16_SIGNATURE_NCM0 && ndp16->dwSignature != NDP16_SIGNATURE_NCM1) { + ERROR_OUT(" ill signature: 0x%08x\n", (unsigned)ndp16->dwSignature); + return false; + } + if (ndp16->wNextNdpIndex != 0) { + ERROR_OUT(" cannot handle wNextNdpIndex!=0 (%d)\n", ndp16->wNextNdpIndex); + return false; + } - TU_ASSERT(usbd_open_edpt_pair(rhport, p_desc, 2, TUSB_XFER_BULK, &ncm_interface.ep_out, &ncm_interface.ep_in) ); + const ndp16_datagram_t *ndp16_datagram = (ndp16_datagram_t *)(ntb->data + nth16->wNdpIndex + sizeof(ndp16_t)); + int ndx = 0; + int max_ndx = (ndp16->wLength - sizeof(ndp16_t)) / sizeof(ndp16_datagram_t); - drv_len += 2*sizeof(tusb_desc_endpoint_t); + if (max_ndx > 2) { + // number of datagrams in NTB > 1 + INFO_OUT("<< %d (%d)\n", max_ndx - 1, ntb->len); + } + if (ndp16_datagram[max_ndx-1].wDatagramIndex != 0 || ndp16_datagram[max_ndx-1].wDatagramLength != 0) { + INFO_OUT(" max_ndx != 0\n"); + return false; + } + while (ndp16_datagram[ndx].wDatagramIndex != 0 && ndp16_datagram[ndx].wDatagramLength != 0) { + DEBUG_OUT(" << %d %d\n", ndp16_datagram[ndx].wDatagramIndex, ndp16_datagram[ndx].wDatagramLength); + if (ndp16_datagram[ndx].wDatagramIndex > len) { + ERROR_OUT(" ill start of datagram[%d]: %d (%d)\n", ndx, ndp16_datagram[ndx].wDatagramIndex, len); + return false; + } + if (ndp16_datagram[ndx].wDatagramIndex + ndp16_datagram[ndx].wDatagramLength > len) { + ERROR_OUT(" ill end of datagram[%d]: %d (%d)\n", ndx, ndp16_datagram[ndx].wDatagramIndex + ndp16_datagram[ndx].wDatagramLength, len); + return false; + } + ++ndx; + } + + for (int i = 0; i < len; ++i) { + DEBUG_OUT(" %02x", ntb->data[i]); + } + DEBUG_OUT("\n"); + + // -> ntb contains a valid packet structure + // ok... I did not check for garbage within the datagram indices... + return true; +} // recv_validate_datagram - return drv_len; -} -static void ncm_report(void) -{ - uint8_t const rhport = 0; - if (ncm_interface.report_state == REPORT_SPEED) { - ncm_notify_speed_change.header.wIndex = ncm_interface.itf_num; - usbd_edpt_xfer(rhport, ncm_interface.ep_notif, (uint8_t *) &ncm_notify_speed_change, sizeof(ncm_notify_speed_change)); - ncm_interface.report_state = REPORT_CONNECTED; - ncm_interface.report_pending = true; - } else if (ncm_interface.report_state == REPORT_CONNECTED) { - ncm_notify_connected.header.wIndex = ncm_interface.itf_num; - usbd_edpt_xfer(rhport, ncm_interface.ep_notif, (uint8_t *) &ncm_notify_connected, sizeof(ncm_notify_connected)); - ncm_interface.report_state = REPORT_DONE; - ncm_interface.report_pending = true; - } -} - -TU_ATTR_WEAK void tud_network_link_state_cb(bool state) -{ - (void)state; -} -// Handle class control request -// return false to stall control endpoint (e.g unsupported request) -bool netd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request) +static void recv_transfer_datagram_to_glue_logic(void) +/** + * Transfer the next (pending) datagram to the glue logic and return receive buffer if empty. + */ { - if ( stage != CONTROL_STAGE_SETUP ) return true; - - switch ( request->bmRequestType_bit.type ) - { - case TUSB_REQ_TYPE_STANDARD: - switch ( request->bRequest ) - { - case TUSB_REQ_GET_INTERFACE: - { - uint8_t const req_itfnum = (uint8_t) request->wIndex; - TU_VERIFY(ncm_interface.itf_num + 1 == req_itfnum); - - tud_control_xfer(rhport, request, &ncm_interface.itf_data_alt, 1); + DEBUG_OUT("recv_transfer_datagram_to_glue_logic()\n"); + + if (ncm_interface.recv_glue_ntb == NULL) { + ncm_interface.recv_glue_ntb = recv_get_next_ready_ntb(); + DEBUG_OUT(" new buffer for glue logic: %p\n", ncm_interface.recv_glue_ntb); + ncm_interface.recv_glue_ntb_datagram_ndx = 0; + } + + if (ncm_interface.recv_glue_ntb != NULL) { + const ndp16_datagram_t *ndp16_datagram = (ndp16_datagram_t *)(ncm_interface.recv_glue_ntb->data + + ncm_interface.recv_glue_ntb->nth.wNdpIndex + + sizeof(ndp16_t)); + + if (ndp16_datagram[ncm_interface.recv_glue_ntb_datagram_ndx].wDatagramIndex == 0) { + ERROR_OUT(" SOMETHING WENT WRONG 1\n"); } - break; - - case TUSB_REQ_SET_INTERFACE: - { - uint8_t const req_itfnum = (uint8_t) request->wIndex; - uint8_t const req_alt = (uint8_t) request->wValue; - - // Only valid for Data Interface with Alternate is either 0 or 1 - TU_VERIFY(ncm_interface.itf_num + 1 == req_itfnum && req_alt < 2); - - if (req_alt != ncm_interface.itf_data_alt) { - ncm_interface.itf_data_alt = req_alt; - - if (ncm_interface.itf_data_alt) { - if (!usbd_edpt_busy(rhport, ncm_interface.ep_out)) { - tud_network_recv_renew(); // prepare for incoming datagrams - } - if (!ncm_interface.report_pending) { - ncm_report(); - } + else if (ndp16_datagram[ncm_interface.recv_glue_ntb_datagram_ndx].wDatagramLength == 0) { + ERROR_OUT(" SOMETHING WENT WRONG 2\n"); + } + else { + uint16_t datagramIndex = ndp16_datagram[ncm_interface.recv_glue_ntb_datagram_ndx].wDatagramIndex; + uint16_t datagramLength = ndp16_datagram[ncm_interface.recv_glue_ntb_datagram_ndx].wDatagramLength; + + DEBUG_OUT(" recv[%d] - %d %d\n", ncm_interface.recv_glue_ntb_datagram_ndx, datagramIndex, datagramLength); + if (tud_network_recv_cb(ncm_interface.recv_glue_ntb->data + datagramIndex, datagramLength)) { + // + // send datagram successfully to glue logic + // + DEBUG_OUT(" OK\n"); + datagramIndex = ndp16_datagram[ncm_interface.recv_glue_ntb_datagram_ndx + 1].wDatagramIndex; + datagramLength = ndp16_datagram[ncm_interface.recv_glue_ntb_datagram_ndx + 1].wDatagramLength; + + if (datagramIndex != 0 && datagramLength != 0) { + // -> next datagram + ++ncm_interface.recv_glue_ntb_datagram_ndx; + } + else { + // end of datagrams reached + recv_put_ntb_into_free_list(ncm_interface.recv_glue_ntb); + ncm_interface.recv_glue_ntb = NULL; + } } + } + } +} // recv_transfer_datagram_to_glue_logic - tud_network_link_state_cb(ncm_interface.itf_data_alt); - } - tud_control_status(rhport, request); - } - break; +//----------------------------------------------------------------------------- +// +// all the tud_network_*() stuff (glue logic -> driver) +// + + +bool tud_network_can_xmit(uint16_t size) +/** + * Check if the glue logic is allowed to call tud_network_xmit(). + * This function also fetches a next buffer if required, so that tud_network_xmit() is ready for copy + * and transmission operation. + */ +{ + DEBUG_OUT("tud_network_can_xmit(%d)\n", size); + + TU_ASSERT(size <= CFG_TUD_NCM_OUT_NTB_MAX_SIZE - (sizeof(nth16_t) + sizeof(ndp16_t) + 2*sizeof(ndp16_datagram_t)), false); + + if (xmit_requested_datagram_fits_into_current_ntb(size) || xmit_setup_next_glue_ntb()) { + // -> everything is fine + return true; + } + xmit_start_if_possible(ncm_interface.rhport); + ERROR_OUT(" tud_network_can_xmit: request blocked\n"); // could happen if all xmit buffers are full (but should happen rarely) + return false; +} // tud_network_can_xmit - // unsupported request - default: return false; - } - break; - case TUSB_REQ_TYPE_CLASS: - TU_VERIFY (ncm_interface.itf_num == request->wIndex); - if (NCM_GET_NTB_PARAMETERS == request->bRequest) - { - tud_control_xfer(rhport, request, (void*)(uintptr_t) &ntb_parameters, sizeof(ntb_parameters)); - } +void tud_network_xmit(void *ref, uint16_t arg) +/** + * Put a datagram into a waiting NTB. + * If currently no transmission is started, then initiate transmission. + */ +{ + DEBUG_OUT("tud_network_xmit(%p, %d)\n", ref, arg); + + if (ncm_interface.xmit_glue_ntb == NULL) { + ERROR_OUT("tud_network_xmit: no buffer\n"); // must not happen (really) + return; + } + + xmit_ntb_t *ntb = ncm_interface.xmit_glue_ntb; + + // copy new datagram to the end of the current NTB + uint16_t size = tud_network_xmit_cb(ntb->data + ntb->nth.wBlockLength, ref, arg); + + // correct NTB internals + ntb->ndp_datagram[ncm_interface.xmit_glue_ntb_datagram_ndx].wDatagramIndex = ntb->nth.wBlockLength; + ntb->ndp_datagram[ncm_interface.xmit_glue_ntb_datagram_ndx].wDatagramLength = size; + ncm_interface.xmit_glue_ntb_datagram_ndx += 1; - break; + ntb->nth.wBlockLength += size + XMIT_ALIGN_OFFSET(size); - // unsupported request - default: return false; - } + if (ntb->nth.wBlockLength > CFG_TUD_NCM_OUT_NTB_MAX_SIZE) { + ERROR_OUT("tud_network_xmit: buffer overflow\n"); // must not happen (really) + return; + } + + xmit_start_if_possible(ncm_interface.rhport); +} // tud_network_xmit - return true; -} -static void handle_incoming_datagram(uint32_t len) + +void tud_network_recv_renew(void) +/** + * Keep the receive logic busy and transfer pending packets to the glue logic. + */ { - uint32_t size = len; + DEBUG_OUT("tud_network_recv_renew()\n"); - if (len == 0) { - return; - } + recv_transfer_datagram_to_glue_logic(); + recv_try_to_start_new_reception(ncm_interface.rhport); +} // tud_network_recv_renew - TU_ASSERT(size >= sizeof(nth16_t), ); - const nth16_t *hdr = (const nth16_t *)receive_ntb; - TU_ASSERT(hdr->dwSignature == NTH16_SIGNATURE, ); - TU_ASSERT(hdr->wNdpIndex >= sizeof(nth16_t) && (hdr->wNdpIndex + sizeof(ndp16_t)) <= len, ); - const ndp16_t *ndp = (const ndp16_t *)(receive_ntb + hdr->wNdpIndex); - TU_ASSERT(ndp->dwSignature == NDP16_SIGNATURE_NCM0 || ndp->dwSignature == NDP16_SIGNATURE_NCM1, ); - TU_ASSERT(hdr->wNdpIndex + ndp->wLength <= len, ); +void tud_network_recv_renew_r(uint8_t rhport) +/** + * Same as tud_network_recv_renew() but knows \a rhport + */ +{ + DEBUG_OUT("tud_network_recv_renew_r(%d)\n", rhport); - int num_datagrams = (ndp->wLength - 12) / 4; - ncm_interface.current_datagram_index = 0; - ncm_interface.num_datagrams = 0; - ncm_interface.ndp = ndp; - for (int i = 0; i < num_datagrams && ndp->datagram[i].wDatagramIndex && ndp->datagram[i].wDatagramLength; i++) - { - ncm_interface.num_datagrams++; - } + ncm_interface.rhport = rhport; + tud_network_recv_renew(); +} // tud_network_recv_renew - tud_network_recv_renew(); -} -bool netd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) +//----------------------------------------------------------------------------- +// +// all the netd_*() stuff (interface TinyUSB -> driver) +// +void netd_init(void) +/** + * Initialize the driver data structures. + * Might be called several times. + */ { - (void) rhport; - (void) result; + DEBUG_OUT("netd_init()\n"); - /* new datagram receive_ntb */ - if (ep_addr == ncm_interface.ep_out ) - { - handle_incoming_datagram(xferred_bytes); - } + memset( &ncm_interface, 0, sizeof(ncm_interface)); - /* data transmission finished */ - if (ep_addr == ncm_interface.ep_in ) - { - if (ncm_interface.transferring) { - ncm_interface.transferring = false; + for (int i = 0; i < XMIT_NTB_N; ++i) { + ncm_interface.xmit_free_ntb[i] = ncm_interface.xmit_ntb + i; } + for (int i = 0; i < RECV_NTB_N; ++i) { + ncm_interface.recv_free_ntb[i] = ncm_interface.recv_ntb + i; + } +} // netd_init + - // If there are datagrams queued up that we tried to send while this NTB was being emitted, send them now - if (ncm_interface.datagram_count && ncm_interface.itf_data_alt == 1) { - ncm_start_tx(); + +void netd_reset(uint8_t rhport) +/** + * Resets the port. + * In this driver this is the same as netd_init() + */ +{ + DEBUG_OUT("netd_reset(%d)\n", rhport); + + netd_init(); +} // netd_reset + + + +uint16_t netd_open(uint8_t rhport, tusb_desc_interface_t const *itf_desc, uint16_t max_len) +/** + * Open the USB interface. + * - parse the USB descriptor \a TUD_CDC_NCM_DESCRIPTOR for itfnum and endpoints + * - a specific order of elements in the descriptor is tested. + * + * \note + * Actually all of the information could be read directly from \a itf_desc, because the + * structure and the values are well known. But we do it this way. + * + * \post + * - \a itf_num set + * - \a ep_notif, \a ep_in and \a ep_out are set + * - USB interface is open + */ +{ + DEBUG_OUT("netd_open(%d,%p,%d)\n", rhport, itf_desc, max_len); + + TU_ASSERT(ncm_interface.ep_notif == 0, 0); // assure that the interface is only opened once + + ncm_interface.itf_num = itf_desc->bInterfaceNumber; // management interface + + // + // skip the two first entries and the following TUSB_DESC_CS_INTERFACE entries + // + uint16_t drv_len = sizeof(tusb_desc_interface_t); + uint8_t const *p_desc = tu_desc_next(itf_desc); + while (tu_desc_type(p_desc) == TUSB_DESC_CS_INTERFACE && drv_len <= max_len) { + drv_len += tu_desc_len(p_desc); + p_desc = tu_desc_next(p_desc); } - } - if (ep_addr == ncm_interface.ep_notif ) - { - ncm_interface.report_pending = false; - ncm_report(); - } + // + // get notification endpoint + // + TU_ASSERT(tu_desc_type(p_desc) == TUSB_DESC_ENDPOINT, 0); + TU_ASSERT(usbd_edpt_open(rhport, (tusb_desc_endpoint_t const* ) p_desc), 0); + ncm_interface.ep_notif = ((tusb_desc_endpoint_t const*) p_desc)->bEndpointAddress; + drv_len += tu_desc_len(p_desc); + p_desc = tu_desc_next(p_desc); - return true; -} + // + // skip the following TUSB_DESC_INTERFACE entries (which must be TUSB_CLASS_CDC_DATA) + // + while (tu_desc_type(p_desc) == TUSB_DESC_INTERFACE && drv_len <= max_len) { + tusb_desc_interface_t const *data_itf_desc = (tusb_desc_interface_t const*)p_desc; + TU_ASSERT(data_itf_desc->bInterfaceClass == TUSB_CLASS_CDC_DATA, 0); -// poll network driver for its ability to accept another packet to transmit -bool tud_network_can_xmit(uint16_t size) + drv_len += tu_desc_len(p_desc); + p_desc = tu_desc_next(p_desc); + } + + // + // a TUSB_DESC_ENDPOINT (actually two) must follow, open these endpoints + // + TU_ASSERT(tu_desc_type(p_desc) == TUSB_DESC_ENDPOINT, 0); + TU_ASSERT(usbd_open_edpt_pair(rhport, p_desc, 2, TUSB_XFER_BULK, &ncm_interface.ep_out, &ncm_interface.ep_in)); + drv_len += 2 * sizeof(tusb_desc_endpoint_t); + + return drv_len; +} // netd_open + + + +bool netd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) +/** + * Handle TinyUSB requests to process transfer events. + */ { - TU_VERIFY(ncm_interface.itf_data_alt == 1); + DEBUG_OUT("netd_xfer_cb(%d,%d,%d,%u)\n", rhport, ep_addr, result, (unsigned)xferred_bytes); + + if (ep_addr == ncm_interface.ep_out) { + // + // new NTB received + // - make the NTB valid + // - if ready transfer datagrams to the glue logic for further processing + // - if there is a free receive buffer, initiate reception + // + DEBUG_OUT(" EP_OUT %d %d %d %u\n", rhport, ep_addr, result, (unsigned)xferred_bytes); + if ( !recv_validate_datagram( ncm_interface.recv_tinyusb_ntb, xferred_bytes)) { + // verification failed: ignore NTB and return it to free + ERROR_OUT(" VALIDATION FAILED. WHAT CAN WE DO IN THIS CASE?\n"); + } + else { + // packet ok -> put it into ready list + recv_put_ntb_into_ready_list(ncm_interface.recv_tinyusb_ntb); + } + ncm_interface.recv_tinyusb_ntb = NULL; + tud_network_recv_renew_r(rhport); + } + else if (ep_addr == ncm_interface.ep_in) { + // + // transmission of an NTB finished + // - free the transmitted NTB buffer + // - insert ZLPs when necessary + // - if there is another transmit NTB waiting, try to start transmission + // + DEBUG_OUT(" EP_IN %d %u\n", ncm_interface.itf_data_alt, (unsigned)xferred_bytes); + xmit_put_ntb_into_free_list(ncm_interface.xmit_tinyusb_ntb); + ncm_interface.xmit_tinyusb_ntb = NULL; + if ( !xmit_insert_required_zlp(rhport, xferred_bytes)) { + xmit_start_if_possible(rhport); + } + } + else if (ep_addr == ncm_interface.ep_notif) { + // + // next transfer on notification channel + // + DEBUG_OUT(" EP_NOTIF\n"); + notification_xmit(rhport, true); + } - if (ncm_interface.datagram_count >= ncm_interface.max_datagrams_per_ntb) { - TU_LOG_DRV("NTB full [by count]\r\n"); - return false; - } + return true; +} // netd_xfer_cb - size_t next_datagram_offset = ncm_interface.next_datagram_offset; - if (next_datagram_offset + size > ncm_interface.ntb_in_size) { - TU_LOG_DRV("ntb full [by size]\r\n"); - return false; - } - return true; -} -void tud_network_xmit(void *ref, uint16_t arg) +bool netd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request) +/** + * Respond to TinyUSB control requests. + * At startup transmission of notification packets are done here. + */ { - transmit_ntb_t *ntb = &transmit_ntb[ncm_interface.current_ntb]; - size_t next_datagram_offset = ncm_interface.next_datagram_offset; + DEBUG_OUT("netd_control_xfer_cb(%d, %d, %p)\n", rhport, stage, request); - uint16_t size = tud_network_xmit_cb(ntb->data + next_datagram_offset, ref, arg); + if (stage != CONTROL_STAGE_SETUP) { + return true; + } - ntb->ndp.datagram[ncm_interface.datagram_count].wDatagramIndex = ncm_interface.next_datagram_offset; - ntb->ndp.datagram[ncm_interface.datagram_count].wDatagramLength = size; + switch (request->bmRequestType_bit.type) { + case TUSB_REQ_TYPE_STANDARD: + switch (request->bRequest) { + case TUSB_REQ_GET_INTERFACE: { + TU_VERIFY(ncm_interface.itf_num + 1 == request->wIndex, false); + + DEBUG_OUT(" TUSB_REQ_GET_INTERFACE - %d\n", ncm_interface.itf_data_alt); + tud_control_xfer(rhport, request, &ncm_interface.itf_data_alt, 1); + } + break; + + case TUSB_REQ_SET_INTERFACE: { + TU_VERIFY(ncm_interface.itf_num + 1 == request->wIndex && request->wValue < 2, false); + + ncm_interface.itf_data_alt = request->wValue; + DEBUG_OUT(" TUSB_REQ_SET_INTERFACE - %d %d %d\n", ncm_interface.itf_data_alt, request->wIndex, ncm_interface.itf_num); + + if (ncm_interface.itf_data_alt == 1) { + tud_network_recv_renew_r(rhport); + notification_xmit(rhport, false); + } + tud_control_status(rhport, request); + } + break; + + // unsupported request + default: + return false; + } + break; - ncm_interface.datagram_count++; - next_datagram_offset += size; + case TUSB_REQ_TYPE_CLASS: + TU_VERIFY(ncm_interface.itf_num == request->wIndex, false); - // round up so the next datagram is aligned correctly - next_datagram_offset += (CFG_TUD_NCM_ALIGNMENT - 1); - next_datagram_offset -= (next_datagram_offset % CFG_TUD_NCM_ALIGNMENT); + DEBUG_OUT(" TUSB_REQ_TYPE_CLASS: %d\n", request->bRequest); - ncm_interface.next_datagram_offset = next_datagram_offset; + if (request->bRequest == NCM_GET_NTB_PARAMETERS) { + // transfer NTB parameters to host. + // TODO can one assume, that tud_control_xfer() succeeds? + DEBUG_OUT(" NCM_GET_NTB_PARAMETERS\n"); + tud_control_xfer(rhport, request, (void*) (uintptr_t) &ntb_parameters, sizeof(ntb_parameters)); + } + break; - ncm_start_tx(); -} + // unsupported request + default: + return false ; + } -#endif + return true; +} // netd_control_xfer_cb + +#endif // ECLIPSE_GUI || ( CFG_TUD_ENABLED && CFG_TUD_NCM ) diff --git a/src/class/net/net_device.h b/src/class/net/net_device.h index 399916355..111c822fb 100644 --- a/src/class/net/net_device.h +++ b/src/class/net/net_device.h @@ -28,14 +28,13 @@ #ifndef _TUSB_NET_DEVICE_H_ #define _TUSB_NET_DEVICE_H_ +#include #include "class/cdc/cdc.h" #if CFG_TUD_ECM_RNDIS && CFG_TUD_NCM #error "Cannot enable both ECM_RNDIS and NCM network drivers" #endif -#include "ncm.h" - /* declared here, NOT in usb_descriptors.c, so that the driver can intelligently ZLP as needed */ #define CFG_TUD_NET_ENDPOINT_SIZE (TUD_OPT_HIGH_SPEED ? 512 : 64) @@ -44,21 +43,6 @@ #define CFG_TUD_NET_MTU 1514 #endif -#ifndef CFG_TUD_NCM_IN_NTB_MAX_SIZE -#define CFG_TUD_NCM_IN_NTB_MAX_SIZE 3200 -#endif - -#ifndef CFG_TUD_NCM_OUT_NTB_MAX_SIZE -#define CFG_TUD_NCM_OUT_NTB_MAX_SIZE 3200 -#endif - -#ifndef CFG_TUD_NCM_MAX_DATAGRAMS_PER_NTB -#define CFG_TUD_NCM_MAX_DATAGRAMS_PER_NTB 8 -#endif - -#ifndef CFG_TUD_NCM_ALIGNMENT -#define CFG_TUD_NCM_ALIGNMENT 4 -#endif #ifdef __cplusplus extern "C" { @@ -92,12 +76,6 @@ uint16_t tud_network_xmit_cb(uint8_t *dst, void *ref, uint16_t arg); // client must provide this: initialize any network state back to the beginning void tud_network_init_cb(void); -// client must provide this: 48-bit MAC address -// TODO removed later since it is not part of tinyusb stack -extern uint8_t tud_network_mac_address[6]; - -//------------- NCM -------------// - // callback to client providing optional indication of internal state of network driver void tud_network_link_state_cb(bool state); -- cgit v1.3.1 From d5da303f450ce0e1004121af4a40a512371e9353 Mon Sep 17 00:00:00 2001 From: Hardy Griech Date: Sun, 20 Aug 2023 18:22:07 +0200 Subject: moved some declarations --- src/class/net/ncm.h | 7 ------- src/class/net/net_device.h | 11 +++++++++++ 2 files changed, 11 insertions(+), 7 deletions(-) (limited to 'src/class') diff --git a/src/class/net/ncm.h b/src/class/net/ncm.h index 313237747..c768192a5 100644 --- a/src/class/net/ncm.h +++ b/src/class/net/ncm.h @@ -71,13 +71,6 @@ #endif -// Table 4.3 Data Class Interface Protocol Codes -typedef enum -{ - NCM_DATA_PROTOCOL_NETWORK_TRANSFER_BLOCK = 0x01 -} ncm_data_interface_protocol_code_t; - - // Table 6.2 Class-Specific Request Codes for Network Control Model subclass typedef enum { diff --git a/src/class/net/net_device.h b/src/class/net/net_device.h index 111c822fb..3342dac3d 100644 --- a/src/class/net/net_device.h +++ b/src/class/net/net_device.h @@ -44,6 +44,13 @@ #endif +// Table 4.3 Data Class Interface Protocol Codes +typedef enum +{ + NCM_DATA_PROTOCOL_NETWORK_TRANSFER_BLOCK = 0x01 +} ncm_data_interface_protocol_code_t; + + #ifdef __cplusplus extern "C" { #endif @@ -76,6 +83,10 @@ uint16_t tud_network_xmit_cb(uint8_t *dst, void *ref, uint16_t arg); // client must provide this: initialize any network state back to the beginning void tud_network_init_cb(void); +// client must provide this: 48-bit MAC address +// TODO removed later since it is not part of tinyusb stack +extern uint8_t tud_network_mac_address[6]; + // callback to client providing optional indication of internal state of network driver void tud_network_link_state_cb(bool state); -- cgit v1.3.1 From e4c18c101cf5dc78f6bd1034aae7f0f7e22b7e47 Mon Sep 17 00:00:00 2001 From: Hardy Griech Date: Sun, 20 Aug 2023 18:22:07 +0200 Subject: Copyright --- src/class/net/ncm_device.c | 1 + 1 file changed, 1 insertion(+) (limited to 'src/class') diff --git a/src/class/net/ncm_device.c b/src/class/net/ncm_device.c index f7a236e69..28066b6af 100644 --- a/src/class/net/ncm_device.c +++ b/src/class/net/ncm_device.c @@ -2,6 +2,7 @@ * The MIT License (MIT) * * Copyright (c) 2023 Hardy Griech + * Copyright (c) 2019 Ha Thach (tinyusb.org) * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal -- cgit v1.3.1 From 28107326da6cbc462bf6644f1f6edd5d0bcb43b8 Mon Sep 17 00:00:00 2001 From: Hardy Griech Date: Sun, 20 Aug 2023 18:22:07 +0200 Subject: bug fix recv/xmit_get_next_ready_ntb() --- src/class/net/ncm_device.c | 58 ++++++++++++++++++++++++---------------------- 1 file changed, 30 insertions(+), 28 deletions(-) (limited to 'src/class') diff --git a/src/class/net/ncm_device.c b/src/class/net/ncm_device.c index 28066b6af..65543fcab 100644 --- a/src/class/net/ncm_device.c +++ b/src/class/net/ncm_device.c @@ -254,7 +254,7 @@ static void xmit_put_ntb_into_free_list(xmit_ntb_t *free_ntb) return; } } - ERROR_OUT("xmit_put_ntb_into_free_list - no entry in free list\n"); // this should not happen + ERROR_OUT("(EE) xmit_put_ntb_into_free_list - no entry in free list\n"); // this should not happen } // xmit_put_ntb_into_free_list @@ -283,7 +283,7 @@ static void xmit_put_ntb_into_ready_list(xmit_ntb_t *ready_ntb) * Put a filled NTB into the ready list */ { - INFO_OUT("xmit_put_ntb_into_ready_list(%p) %d\n", ready_ntb, ready_ntb->len); + INFO_OUT("xmit_put_ntb_into_ready_list(%p) %d\n", ready_ntb, ready_ntb->nth.wBlockLength); for (int i = 0; i < XMIT_NTB_N; ++i) { if (ncm_interface.xmit_ready_ntb[i] == NULL) { @@ -291,7 +291,7 @@ static void xmit_put_ntb_into_ready_list(xmit_ntb_t *ready_ntb) return; } } - ERROR_OUT("xmit_put_ntb_into_ready_list: ready list full\n"); // this should not happen + ERROR_OUT("(EE) xmit_put_ntb_into_ready_list: ready list full\n"); // this should not happen } // xmit_put_ntb_into_ready_list @@ -306,6 +306,7 @@ static xmit_ntb_t *xmit_get_next_ready_ntb(void) r = ncm_interface.xmit_ready_ntb[0]; memmove(ncm_interface.xmit_ready_ntb + 0, ncm_interface.xmit_ready_ntb + 1, sizeof(ncm_interface.xmit_ready_ntb) - sizeof(ncm_interface.xmit_ready_ntb[0])); + ncm_interface.xmit_ready_ntb[XMIT_NTB_N - 1] = NULL; DEBUG_OUT("recv_get_next_ready_ntb: %p\n", r); return r; @@ -357,7 +358,7 @@ static void xmit_start_if_possible(uint8_t rhport) return; } if (ncm_interface.itf_data_alt != 1) { - ERROR_OUT(" !xmit_start_if_possible 2\n"); + ERROR_OUT("(II) !xmit_start_if_possible 2\n"); return; } if (usbd_edpt_busy(rhport, ncm_interface.ep_in)) { @@ -375,9 +376,9 @@ static void xmit_start_if_possible(uint8_t rhport) ncm_interface.xmit_glue_ntb = NULL; } -#if DEBUG_OUT_ENABLED +#ifdef DEBUG_OUT_ENABLED { - uint16_t len = ncm_interface.xmit_tinyusb_ntb->ntb.nth.wBlockLength; + uint16_t len = ncm_interface.xmit_tinyusb_ntb->nth.wBlockLength; DEBUG_OUT(" %d\n", len); for (int i = 0; i < len; ++i) { DEBUG_OUT(" %02x", ncm_interface.xmit_tinyusb_ntb->data[i]); @@ -387,7 +388,7 @@ static void xmit_start_if_possible(uint8_t rhport) #endif if (ncm_interface.xmit_glue_ntb_datagram_ndx != 1) { - DEBUG_OUT(">> %d %d\n", ncm_interface.xmit_tinyusb_ntb->len, ncm_interface.xmit_glue_ntb_datagram_ndx); + DEBUG_OUT(">> %d %d\n", ncm_interface.xmit_tinyusb_ntb->nth.wBlockLength, ncm_interface.xmit_glue_ntb_datagram_ndx); } // Kick off an endpoint transfer @@ -492,6 +493,7 @@ static recv_ntb_t *recv_get_next_ready_ntb(void) r = ncm_interface.recv_ready_ntb[0]; memmove(ncm_interface.recv_ready_ntb + 0, ncm_interface.recv_ready_ntb + 1, sizeof(ncm_interface.recv_ready_ntb) - sizeof(ncm_interface.recv_ready_ntb[0])); + ncm_interface.recv_ready_ntb[RECV_NTB_N - 1] = NULL; DEBUG_OUT("recv_get_next_ready_ntb: %p\n", r); return r; @@ -512,7 +514,7 @@ static void recv_put_ntb_into_free_list(recv_ntb_t *free_ntb) return; } } - ERROR_OUT("recv_put_ntb_into_free_list - no entry in free list\n"); // this should not happen + ERROR_OUT("(EE) recv_put_ntb_into_free_list - no entry in free list\n"); // this should not happen } // recv_put_ntb_into_free_list @@ -523,7 +525,7 @@ static void recv_put_ntb_into_ready_list(recv_ntb_t *ready_ntb) * put this buffer into the waiting list and free the receive logic. */ { - DEBUG_OUT("recv_put_ntb_into_ready_list(%p) %d\n", ready_ntb, ready_ntb->len); + DEBUG_OUT("recv_put_ntb_into_ready_list(%p) %d\n", ready_ntb, ready_ntb->nth.wBlockLength); for (int i = 0; i < RECV_NTB_N; ++i) { if (ncm_interface.recv_ready_ntb[i] == NULL) { @@ -531,7 +533,7 @@ static void recv_put_ntb_into_ready_list(recv_ntb_t *ready_ntb) return; } } - ERROR_OUT("recv_put_ntb_into_ready_list: ready list full\n"); // this should not happen + ERROR_OUT("(EE) recv_put_ntb_into_ready_list: ready list full\n"); // this should not happen } // recv_put_ntb_into_ready_list @@ -588,27 +590,27 @@ static bool recv_validate_datagram(const recv_ntb_t *ntb, uint16_t len) // if (nth16->wHeaderLength != sizeof(nth16_t)) { - ERROR_OUT(" ill nth16 length: %d\n", nth16->wHeaderLength); + ERROR_OUT("(EE) ill nth16 length: %d\n", nth16->wHeaderLength); return false; } if (nth16->dwSignature != NTH16_SIGNATURE) { - ERROR_OUT(" ill signature: 0x%08x\n", (unsigned)nth16->dwSignature); + ERROR_OUT("(EE) ill signature: 0x%08x\n", (unsigned)nth16->dwSignature); return false; } if (len < sizeof(nth16_t) + sizeof(ndp16_t) + 2*sizeof(ndp16_datagram_t)) { - ERROR_OUT(" ill min len: %d\n", len); + ERROR_OUT("(EE) ill min len: %d\n", len); return false; } if (nth16->wBlockLength > len) { - ERROR_OUT(" ill block length: %d > %d\n", nth16->wBlockLength, len); + ERROR_OUT("(EE) ill block length: %d > %d\n", nth16->wBlockLength, len); return false; } if (nth16->wBlockLength > CFG_TUD_NCM_OUT_NTB_MAX_SIZE) { - ERROR_OUT(" ill block length2: %d > %d\n", nth16->wBlockLength, CFG_TUD_NCM_OUT_NTB_MAX_SIZE); + ERROR_OUT("(EE) ill block length2: %d > %d\n", nth16->wBlockLength, CFG_TUD_NCM_OUT_NTB_MAX_SIZE); return false; } if (nth16->wNdpIndex < sizeof(nth16) || nth16->wNdpIndex > len - (sizeof(ndp16_t) + 2*sizeof(ndp16_datagram_t))) { - ERROR_OUT(" ill position of first ndp: %d (%d)\n", nth16->wNdpIndex, len); + ERROR_OUT("(EE) ill position of first ndp: %d (%d)\n", nth16->wNdpIndex, len); return false; } @@ -618,15 +620,15 @@ static bool recv_validate_datagram(const recv_ntb_t *ntb, uint16_t len) const ndp16_t *ndp16 = (ndp16_t *)(ntb->data + nth16->wNdpIndex); if (ndp16->wLength < sizeof(ndp16_t) + 2*sizeof(ndp16_datagram_t)) { - ERROR_OUT(" ill ndp16 length: %d\n", ndp16->wLength); + ERROR_OUT("(EE) ill ndp16 length: %d\n", ndp16->wLength); return false; } if (ndp16->dwSignature != NDP16_SIGNATURE_NCM0 && ndp16->dwSignature != NDP16_SIGNATURE_NCM1) { - ERROR_OUT(" ill signature: 0x%08x\n", (unsigned)ndp16->dwSignature); + ERROR_OUT("(EE) ill signature: 0x%08x\n", (unsigned)ndp16->dwSignature); return false; } if (ndp16->wNextNdpIndex != 0) { - ERROR_OUT(" cannot handle wNextNdpIndex!=0 (%d)\n", ndp16->wNextNdpIndex); + ERROR_OUT("(EE) cannot handle wNextNdpIndex!=0 (%d)\n", ndp16->wNextNdpIndex); return false; } @@ -636,7 +638,7 @@ static bool recv_validate_datagram(const recv_ntb_t *ntb, uint16_t len) if (max_ndx > 2) { // number of datagrams in NTB > 1 - INFO_OUT("<< %d (%d)\n", max_ndx - 1, ntb->len); + INFO_OUT("<< %d (%d)\n", max_ndx - 1, ntb->nth.wBlockLength); } if (ndp16_datagram[max_ndx-1].wDatagramIndex != 0 || ndp16_datagram[max_ndx-1].wDatagramLength != 0) { INFO_OUT(" max_ndx != 0\n"); @@ -645,11 +647,11 @@ static bool recv_validate_datagram(const recv_ntb_t *ntb, uint16_t len) while (ndp16_datagram[ndx].wDatagramIndex != 0 && ndp16_datagram[ndx].wDatagramLength != 0) { DEBUG_OUT(" << %d %d\n", ndp16_datagram[ndx].wDatagramIndex, ndp16_datagram[ndx].wDatagramLength); if (ndp16_datagram[ndx].wDatagramIndex > len) { - ERROR_OUT(" ill start of datagram[%d]: %d (%d)\n", ndx, ndp16_datagram[ndx].wDatagramIndex, len); + ERROR_OUT("(EE) ill start of datagram[%d]: %d (%d)\n", ndx, ndp16_datagram[ndx].wDatagramIndex, len); return false; } if (ndp16_datagram[ndx].wDatagramIndex + ndp16_datagram[ndx].wDatagramLength > len) { - ERROR_OUT(" ill end of datagram[%d]: %d (%d)\n", ndx, ndp16_datagram[ndx].wDatagramIndex + ndp16_datagram[ndx].wDatagramLength, len); + ERROR_OUT("(EE) ill end of datagram[%d]: %d (%d)\n", ndx, ndp16_datagram[ndx].wDatagramIndex + ndp16_datagram[ndx].wDatagramLength, len); return false; } ++ndx; @@ -686,10 +688,10 @@ static void recv_transfer_datagram_to_glue_logic(void) + sizeof(ndp16_t)); if (ndp16_datagram[ncm_interface.recv_glue_ntb_datagram_ndx].wDatagramIndex == 0) { - ERROR_OUT(" SOMETHING WENT WRONG 1\n"); + ERROR_OUT("(EE) SOMETHING WENT WRONG 1\n"); } else if (ndp16_datagram[ncm_interface.recv_glue_ntb_datagram_ndx].wDatagramLength == 0) { - ERROR_OUT(" SOMETHING WENT WRONG 2\n"); + ERROR_OUT("(EE) SOMETHING WENT WRONG 2\n"); } else { uint16_t datagramIndex = ndp16_datagram[ncm_interface.recv_glue_ntb_datagram_ndx].wDatagramIndex; @@ -741,7 +743,7 @@ bool tud_network_can_xmit(uint16_t size) return true; } xmit_start_if_possible(ncm_interface.rhport); - ERROR_OUT(" tud_network_can_xmit: request blocked\n"); // could happen if all xmit buffers are full (but should happen rarely) + ERROR_OUT("(II) tud_network_can_xmit: request blocked\n"); // could happen if all xmit buffers are full (but should happen rarely) return false; } // tud_network_can_xmit @@ -756,7 +758,7 @@ void tud_network_xmit(void *ref, uint16_t arg) DEBUG_OUT("tud_network_xmit(%p, %d)\n", ref, arg); if (ncm_interface.xmit_glue_ntb == NULL) { - ERROR_OUT("tud_network_xmit: no buffer\n"); // must not happen (really) + ERROR_OUT("(EE) tud_network_xmit: no buffer\n"); // must not happen (really) return; } @@ -773,7 +775,7 @@ void tud_network_xmit(void *ref, uint16_t arg) ntb->nth.wBlockLength += size + XMIT_ALIGN_OFFSET(size); if (ntb->nth.wBlockLength > CFG_TUD_NCM_OUT_NTB_MAX_SIZE) { - ERROR_OUT("tud_network_xmit: buffer overflow\n"); // must not happen (really) + ERROR_OUT("(II) tud_network_xmit: buffer overflow\n"); // must not happen (really) return; } @@ -925,7 +927,7 @@ bool netd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_ DEBUG_OUT(" EP_OUT %d %d %d %u\n", rhport, ep_addr, result, (unsigned)xferred_bytes); if ( !recv_validate_datagram( ncm_interface.recv_tinyusb_ntb, xferred_bytes)) { // verification failed: ignore NTB and return it to free - ERROR_OUT(" VALIDATION FAILED. WHAT CAN WE DO IN THIS CASE?\n"); + ERROR_OUT("(EE) VALIDATION FAILED. WHAT CAN WE DO IN THIS CASE?\n"); } else { // packet ok -> put it into ready list -- cgit v1.3.1 From 2c1addff4f853586c8d9590e3f93d79fc7c6e250 Mon Sep 17 00:00:00 2001 From: Hardy Griech Date: Sun, 20 Aug 2023 18:27:06 +0200 Subject: defined(ECLIPSE_GUI) --- src/class/net/ncm_device.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/class') diff --git a/src/class/net/ncm_device.c b/src/class/net/ncm_device.c index 65543fcab..1c6f888cd 100644 --- a/src/class/net/ncm_device.c +++ b/src/class/net/ncm_device.c @@ -46,7 +46,7 @@ #include "tusb_option.h" -#if ECLIPSE_GUI || ( CFG_TUD_ENABLED && CFG_TUD_NCM ) +#if defined(ECLIPSE_GUI) || ( CFG_TUD_ENABLED && CFG_TUD_NCM ) #include #include -- cgit v1.3.1 From 1dd9fa3f307e6f3a847619d587529ea17608c1a3 Mon Sep 17 00:00:00 2001 From: Hardy Griech Date: Thu, 31 Aug 2023 20:24:56 +0200 Subject: code review: changed to TinyUSB log system --- src/class/net/ncm_device.c | 205 +++++++++++++++++++++------------------------ 1 file changed, 96 insertions(+), 109 deletions(-) (limited to 'src/class') diff --git a/src/class/net/ncm_device.c b/src/class/net/ncm_device.c index 1c6f888cd..d0832cf73 100644 --- a/src/class/net/ncm_device.c +++ b/src/class/net/ncm_device.c @@ -59,30 +59,11 @@ #include "ncm.h" -#if !defined(tu_static) || ECLIPSE_GUI +#if !defined(tu_static) || defined(ECLIPSE_GUI) // TinyUSB <=0.15.0 does not know "tu_static" #define tu_static static #endif -#if 0 - #define DEBUG_OUT(...) printf(__VA_ARGS__) - #define DEBUG_OUT_ENABLED -#else - #define DEBUG_OUT(...) -#endif - -#if 0 - #define INFO_OUT(...) printf(__VA_ARGS__) -#else - #define INFO_OUT(...) -#endif - -#if 1 - #define ERROR_OUT(...) printf(__VA_ARGS__) -#else - #define ERROR_OUT(...) -#endif - // calculate alignment of xmit datagrams within an NTB #define XMIT_ALIGN_OFFSET(x) ((CFG_TUD_NCM_ALIGNMENT - ((x) & (CFG_TUD_NCM_ALIGNMENT - 1))) & (CFG_TUD_NCM_ALIGNMENT - 1)) @@ -103,7 +84,7 @@ typedef struct { uint8_t rhport; //!< storage of \a rhport because some callbacks are done without it // recv handling - recv_ntb_t recv_ntb[RECV_NTB_N]; //!< actual recv NTBs + CFG_TUSB_MEM_ALIGN recv_ntb_t recv_ntb[RECV_NTB_N]; //!< actual recv NTBs recv_ntb_t *recv_free_ntb[RECV_NTB_N]; //!< free list of recv NTBs recv_ntb_t *recv_ready_ntb[RECV_NTB_N]; //!< NTBs waiting for transmission to glue logic recv_ntb_t *recv_tinyusb_ntb; //!< buffer for the running transfer TinyUSB -> driver @@ -111,7 +92,7 @@ typedef struct { uint16_t recv_glue_ntb_datagram_ndx; //!< index into \a recv_glue_ntb_datagram // xmit handling - xmit_ntb_t xmit_ntb[XMIT_NTB_N]; //!< actual xmit NTBs + CFG_TUSB_MEM_ALIGN xmit_ntb_t xmit_ntb[XMIT_NTB_N]; //!< actual xmit NTBs xmit_ntb_t *xmit_free_ntb[XMIT_NTB_N]; //!< free list of xmit NTBs xmit_ntb_t *xmit_ready_ntb[XMIT_NTB_N]; //!< NTBs waiting for transmission to TinyUSB xmit_ntb_t *xmit_tinyusb_ntb; //!< buffer for the running transfer driver -> TinyUSB @@ -159,7 +140,7 @@ CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN tu_static const ntb_parameters_t ntb_par // ==6 -> SystemView runs fine, iperf also // >6 -> iperf starts to show errors // -> 6 seems to be the best value. Why? Don't know, perhaps only on my system? -// switch \a INFO_OUT on to see interesting values for this. +// switch \a TU_LOG2 on to see interesting values for this. // // iperf: for MSS in 100 200 400 800 1200 1450 1500; do iperf -c 192.168.14.1 -e -i 1 -M $MSS -l 8192 -P 1; sleep 2; done // sysview: SYSTICKS_PER_SEC=35000, IDLE_US=1000, PRINT_MOD=1000 @@ -192,8 +173,8 @@ tu_static struct ncm_notify_t ncm_notify_speed_change = { .bRequest = CDC_NOTIF_CONNECTION_SPEED_CHANGE, .wLength = 8, }, - .downlink = 1000000, - .uplink = 1000000, + .downlink = 12000000, + .uplink = 12000000, }; @@ -204,28 +185,28 @@ static void notification_xmit(uint8_t rhport, bool force_next) * Notifications are transferred to the host once during connection setup. */ { - DEBUG_OUT("notification_xmit(%d, %d) - %d %d\n", force_next, rhport, ncm_interface.notification_xmit_state, ncm_interface.notification_xmit_is_running); + TU_LOG3("notification_xmit(%d, %d) - %d %d\n", force_next, rhport, ncm_interface.notification_xmit_state, ncm_interface.notification_xmit_is_running); if ( !force_next && ncm_interface.notification_xmit_is_running) { return; } if (ncm_interface.notification_xmit_state == NOTIFICATION_SPEED) { - DEBUG_OUT(" NOTIFICATION_SPEED\n"); + TU_LOG3(" NOTIFICATION_SPEED\n"); ncm_notify_speed_change.header.wIndex = ncm_interface.itf_num; usbd_edpt_xfer(rhport, ncm_interface.ep_notif, (uint8_t*) &ncm_notify_speed_change, sizeof(ncm_notify_speed_change)); ncm_interface.notification_xmit_state = NOTIFICATION_CONNECTED; ncm_interface.notification_xmit_is_running = true; } else if (ncm_interface.notification_xmit_state == NOTIFICATION_CONNECTED) { - DEBUG_OUT(" NOTIFICATION_CONNECTED\n"); + TU_LOG3(" NOTIFICATION_CONNECTED\n"); ncm_notify_connected.header.wIndex = ncm_interface.itf_num; usbd_edpt_xfer(rhport, ncm_interface.ep_notif, (uint8_t*) &ncm_notify_connected, sizeof(ncm_notify_connected)); ncm_interface.notification_xmit_state = NOTIFICATION_DONE; ncm_interface.notification_xmit_is_running = true; } else { - DEBUG_OUT(" NOTIFICATION_FINISHED\n"); + TU_LOG3(" NOTIFICATION_FINISHED\n"); } } // notification_xmit @@ -241,7 +222,7 @@ static void xmit_put_ntb_into_free_list(xmit_ntb_t *free_ntb) * Put NTB into the transmitter free list. */ { - DEBUG_OUT("xmit_put_ntb_into_free_list() - %p\n", ncm_interface.xmit_tinyusb_ntb); + TU_LOG3("xmit_put_ntb_into_free_list() - %p\n", ncm_interface.xmit_tinyusb_ntb); if (free_ntb == NULL) { // can happen due to ZLPs @@ -254,7 +235,7 @@ static void xmit_put_ntb_into_free_list(xmit_ntb_t *free_ntb) return; } } - ERROR_OUT("(EE) xmit_put_ntb_into_free_list - no entry in free list\n"); // this should not happen + TU_LOG1("(EE) xmit_put_ntb_into_free_list - no entry in free list\n"); // this should not happen } // xmit_put_ntb_into_free_list @@ -264,7 +245,7 @@ static xmit_ntb_t *xmit_get_free_ntb(void) * Get an NTB from the free list */ { - DEBUG_OUT("xmit_get_free_ntb()\n"); + TU_LOG3("xmit_get_free_ntb()\n"); for (int i = 0; i < XMIT_NTB_N; ++i) { if (ncm_interface.xmit_free_ntb[i] != NULL) { @@ -283,7 +264,7 @@ static void xmit_put_ntb_into_ready_list(xmit_ntb_t *ready_ntb) * Put a filled NTB into the ready list */ { - INFO_OUT("xmit_put_ntb_into_ready_list(%p) %d\n", ready_ntb, ready_ntb->nth.wBlockLength); + TU_LOG2("xmit_put_ntb_into_ready_list(%p) %d\n", ready_ntb, ready_ntb->nth.wBlockLength); for (int i = 0; i < XMIT_NTB_N; ++i) { if (ncm_interface.xmit_ready_ntb[i] == NULL) { @@ -291,7 +272,7 @@ static void xmit_put_ntb_into_ready_list(xmit_ntb_t *ready_ntb) return; } } - ERROR_OUT("(EE) xmit_put_ntb_into_ready_list: ready list full\n"); // this should not happen + TU_LOG1("(EE) xmit_put_ntb_into_ready_list: ready list full\n"); // this should not happen } // xmit_put_ntb_into_ready_list @@ -308,13 +289,13 @@ static xmit_ntb_t *xmit_get_next_ready_ntb(void) memmove(ncm_interface.xmit_ready_ntb + 0, ncm_interface.xmit_ready_ntb + 1, sizeof(ncm_interface.xmit_ready_ntb) - sizeof(ncm_interface.xmit_ready_ntb[0])); ncm_interface.xmit_ready_ntb[XMIT_NTB_N - 1] = NULL; - DEBUG_OUT("recv_get_next_ready_ntb: %p\n", r); + TU_LOG3("recv_get_next_ready_ntb: %p\n", r); return r; } // xmit_get_next_ready_ntb -static bool xmit_insert_required_zlp(uint8_t rhport, uint16_t xferred_bytes) +static bool xmit_insert_required_zlp(uint8_t rhport, uint32_t xferred_bytes) /** * Transmit a ZLP if required * @@ -327,7 +308,7 @@ static bool xmit_insert_required_zlp(uint8_t rhport, uint16_t xferred_bytes) * This must be called from netd_xfer_cb() so that ep_in is ready */ { - DEBUG_OUT("xmit_insert_required_zlp(%d,%d)\n", rhport, xferred_bytes); + TU_LOG3("xmit_insert_required_zlp(%d,%d)\n", rhport, xferred_bytes); if (xferred_bytes == 0 || xferred_bytes % CFG_TUD_NET_ENDPOINT_SIZE != 0) { return false; @@ -336,7 +317,7 @@ static bool xmit_insert_required_zlp(uint8_t rhport, uint16_t xferred_bytes) TU_ASSERT(ncm_interface.itf_data_alt == 1, false); TU_ASSERT( !usbd_edpt_busy(rhport, ncm_interface.ep_in), false); - INFO_OUT("xmit_insert_required_zlp! (%u)\n", (unsigned)xferred_bytes); + TU_LOG2("xmit_insert_required_zlp! (%u)\n", (unsigned)xferred_bytes); // start transmission of the ZLP usbd_edpt_xfer(rhport, ncm_interface.ep_in, NULL, 0); @@ -351,18 +332,18 @@ static void xmit_start_if_possible(uint8_t rhport) * Start transmission if it there is a waiting packet and if can be done from interface side. */ { - DEBUG_OUT("xmit_start_if_possible()\n"); + TU_LOG3("xmit_start_if_possible()\n"); if (ncm_interface.xmit_tinyusb_ntb != NULL) { - DEBUG_OUT(" !xmit_start_if_possible 1\n"); + TU_LOG3(" !xmit_start_if_possible 1\n"); return; } if (ncm_interface.itf_data_alt != 1) { - ERROR_OUT("(II) !xmit_start_if_possible 2\n"); + TU_LOG1("(II) !xmit_start_if_possible 2\n"); return; } if (usbd_edpt_busy(rhport, ncm_interface.ep_in)) { - INFO_OUT(" !xmit_start_if_possible 3\n"); + TU_LOG2(" !xmit_start_if_possible 3\n"); return; } @@ -379,16 +360,16 @@ static void xmit_start_if_possible(uint8_t rhport) #ifdef DEBUG_OUT_ENABLED { uint16_t len = ncm_interface.xmit_tinyusb_ntb->nth.wBlockLength; - DEBUG_OUT(" %d\n", len); + TU_LOG3(" %d\n", len); for (int i = 0; i < len; ++i) { - DEBUG_OUT(" %02x", ncm_interface.xmit_tinyusb_ntb->data[i]); + TU_LOG3(" %02x", ncm_interface.xmit_tinyusb_ntb->data[i]); } - DEBUG_OUT("\n"); + TU_LOG3("\n"); } #endif if (ncm_interface.xmit_glue_ntb_datagram_ndx != 1) { - DEBUG_OUT(">> %d %d\n", ncm_interface.xmit_tinyusb_ntb->nth.wBlockLength, ncm_interface.xmit_glue_ntb_datagram_ndx); + TU_LOG3(">> %d %d\n", ncm_interface.xmit_tinyusb_ntb->nth.wBlockLength, ncm_interface.xmit_glue_ntb_datagram_ndx); } // Kick off an endpoint transfer @@ -402,7 +383,7 @@ static bool xmit_requested_datagram_fits_into_current_ntb(uint16_t datagram_size * check if a new datagram fits into the current NTB */ { - DEBUG_OUT("xmit_requested_datagram_fits_into_current_ntb(%d) - %p %p\n", datagram_size, ncm_interface.xmit_tinyusb_ntb, ncm_interface.xmit_glue_ntb); + TU_LOG3("xmit_requested_datagram_fits_into_current_ntb(%d) - %p %p\n", datagram_size, ncm_interface.xmit_tinyusb_ntb, ncm_interface.xmit_glue_ntb); if (ncm_interface.xmit_glue_ntb == NULL) { return false; @@ -423,7 +404,7 @@ static bool xmit_setup_next_glue_ntb(void) * Setup an NTB for the glue logic */ { - DEBUG_OUT("xmit_setup_next_glue_ntb - %p\n", ncm_interface.xmit_glue_ntb); + TU_LOG3("xmit_setup_next_glue_ntb - %p\n", ncm_interface.xmit_glue_ntb); if (ncm_interface.xmit_glue_ntb != NULL) { // put NTB into waiting list (the new datagram did not fit in) @@ -432,7 +413,7 @@ static bool xmit_setup_next_glue_ntb(void) ncm_interface.xmit_glue_ntb = xmit_get_free_ntb(); // get next buffer (if any) if (ncm_interface.xmit_glue_ntb == NULL) { - DEBUG_OUT(" xmit_setup_next_glue_ntb - nothing free\n"); // should happen rarely + TU_LOG3(" xmit_setup_next_glue_ntb - nothing free\n"); // should happen rarely return false; } @@ -469,7 +450,7 @@ static recv_ntb_t *recv_get_free_ntb(void) * Returned buffer (if any) has the size \a CFG_TUD_NCM_OUT_NTB_MAX_SIZE. */ { - DEBUG_OUT("recv_get_free_ntb()\n"); + TU_LOG3("recv_get_free_ntb()\n"); for (int i = 0; i < RECV_NTB_N; ++i) { if (ncm_interface.recv_free_ntb[i] != NULL) { @@ -495,7 +476,7 @@ static recv_ntb_t *recv_get_next_ready_ntb(void) memmove(ncm_interface.recv_ready_ntb + 0, ncm_interface.recv_ready_ntb + 1, sizeof(ncm_interface.recv_ready_ntb) - sizeof(ncm_interface.recv_ready_ntb[0])); ncm_interface.recv_ready_ntb[RECV_NTB_N - 1] = NULL; - DEBUG_OUT("recv_get_next_ready_ntb: %p\n", r); + TU_LOG3("recv_get_next_ready_ntb: %p\n", r); return r; } // recv_get_next_ready_ntb @@ -506,7 +487,7 @@ static void recv_put_ntb_into_free_list(recv_ntb_t *free_ntb) * */ { - DEBUG_OUT("recv_put_ntb_into_free_list(%p)\n", free_ntb); + TU_LOG3("recv_put_ntb_into_free_list(%p)\n", free_ntb); for (int i = 0; i < RECV_NTB_N; ++i) { if (ncm_interface.recv_free_ntb[i] == NULL) { @@ -514,7 +495,7 @@ static void recv_put_ntb_into_free_list(recv_ntb_t *free_ntb) return; } } - ERROR_OUT("(EE) recv_put_ntb_into_free_list - no entry in free list\n"); // this should not happen + TU_LOG1("(EE) recv_put_ntb_into_free_list - no entry in free list\n"); // this should not happen } // recv_put_ntb_into_free_list @@ -525,7 +506,7 @@ static void recv_put_ntb_into_ready_list(recv_ntb_t *ready_ntb) * put this buffer into the waiting list and free the receive logic. */ { - DEBUG_OUT("recv_put_ntb_into_ready_list(%p) %d\n", ready_ntb, ready_ntb->nth.wBlockLength); + TU_LOG3("recv_put_ntb_into_ready_list(%p) %d\n", ready_ntb, ready_ntb->nth.wBlockLength); for (int i = 0; i < RECV_NTB_N; ++i) { if (ncm_interface.recv_ready_ntb[i] == NULL) { @@ -533,7 +514,7 @@ static void recv_put_ntb_into_ready_list(recv_ntb_t *ready_ntb) return; } } - ERROR_OUT("(EE) recv_put_ntb_into_ready_list: ready list full\n"); // this should not happen + TU_LOG1("(EE) recv_put_ntb_into_ready_list: ready list full\n"); // this should not happen } // recv_put_ntb_into_ready_list @@ -544,7 +525,7 @@ static void recv_try_to_start_new_reception(uint8_t rhport) * Return value is actually not of interest. */ { - DEBUG_OUT("recv_try_to_start_new_reception(%d)\n", rhport); + TU_LOG3("recv_try_to_start_new_reception(%d)\n", rhport); if (ncm_interface.itf_data_alt != 1) { return; @@ -552,7 +533,7 @@ static void recv_try_to_start_new_reception(uint8_t rhport) if (ncm_interface.recv_tinyusb_ntb != NULL) { return; } - if (usbd_edpt_busy(ncm_interface.rhport, ncm_interface.ep_out)) { + if (usbd_edpt_busy(rhport, ncm_interface.ep_out)) { return; } @@ -562,8 +543,8 @@ static void recv_try_to_start_new_reception(uint8_t rhport) } // initiate transfer - DEBUG_OUT(" start reception\n"); - bool r = usbd_edpt_xfer(0, ncm_interface.ep_out, ncm_interface.recv_tinyusb_ntb->data, CFG_TUD_NCM_OUT_NTB_MAX_SIZE); + TU_LOG3(" start reception\n"); + bool r = usbd_edpt_xfer(rhport, ncm_interface.ep_out, ncm_interface.recv_tinyusb_ntb->data, CFG_TUD_NCM_OUT_NTB_MAX_SIZE); if ( !r) { recv_put_ntb_into_free_list(ncm_interface.recv_tinyusb_ntb); ncm_interface.recv_tinyusb_ntb = NULL; @@ -572,7 +553,7 @@ static void recv_try_to_start_new_reception(uint8_t rhport) -static bool recv_validate_datagram(const recv_ntb_t *ntb, uint16_t len) +static bool recv_validate_datagram(const recv_ntb_t *ntb, uint32_t len) /** * Validate incoming datagram. * \return true if valid @@ -583,84 +564,86 @@ static bool recv_validate_datagram(const recv_ntb_t *ntb, uint16_t len) { const nth16_t *nth16 = &(ntb->nth); - DEBUG_OUT("recv_validate_datagram(%p)\n", ntb); + TU_LOG3("recv_validate_datagram(%p)\n", ntb); // // check header // if (nth16->wHeaderLength != sizeof(nth16_t)) { - ERROR_OUT("(EE) ill nth16 length: %d\n", nth16->wHeaderLength); + TU_LOG1("(EE) ill nth16 length: %d\n", nth16->wHeaderLength); return false; } if (nth16->dwSignature != NTH16_SIGNATURE) { - ERROR_OUT("(EE) ill signature: 0x%08x\n", (unsigned)nth16->dwSignature); + TU_LOG1("(EE) ill signature: 0x%08x\n", (unsigned)nth16->dwSignature); return false; } if (len < sizeof(nth16_t) + sizeof(ndp16_t) + 2*sizeof(ndp16_datagram_t)) { - ERROR_OUT("(EE) ill min len: %d\n", len); + TU_LOG1("(EE) ill min len: %d\n", len); return false; } if (nth16->wBlockLength > len) { - ERROR_OUT("(EE) ill block length: %d > %d\n", nth16->wBlockLength, len); + TU_LOG1("(EE) ill block length: %d > %d\n", nth16->wBlockLength, len); return false; } if (nth16->wBlockLength > CFG_TUD_NCM_OUT_NTB_MAX_SIZE) { - ERROR_OUT("(EE) ill block length2: %d > %d\n", nth16->wBlockLength, CFG_TUD_NCM_OUT_NTB_MAX_SIZE); + TU_LOG1("(EE) ill block length2: %d > %d\n", nth16->wBlockLength, CFG_TUD_NCM_OUT_NTB_MAX_SIZE); return false; } if (nth16->wNdpIndex < sizeof(nth16) || nth16->wNdpIndex > len - (sizeof(ndp16_t) + 2*sizeof(ndp16_datagram_t))) { - ERROR_OUT("(EE) ill position of first ndp: %d (%d)\n", nth16->wNdpIndex, len); + TU_LOG1("(EE) ill position of first ndp: %d (%d)\n", nth16->wNdpIndex, len); return false; } // // check (first) NDP(16) // - const ndp16_t *ndp16 = (ndp16_t *)(ntb->data + nth16->wNdpIndex); + const ndp16_t *ndp16 = (const ndp16_t *)(ntb->data + nth16->wNdpIndex); if (ndp16->wLength < sizeof(ndp16_t) + 2*sizeof(ndp16_datagram_t)) { - ERROR_OUT("(EE) ill ndp16 length: %d\n", ndp16->wLength); + TU_LOG1("(EE) ill ndp16 length: %d\n", ndp16->wLength); return false; } if (ndp16->dwSignature != NDP16_SIGNATURE_NCM0 && ndp16->dwSignature != NDP16_SIGNATURE_NCM1) { - ERROR_OUT("(EE) ill signature: 0x%08x\n", (unsigned)ndp16->dwSignature); + TU_LOG1("(EE) ill signature: 0x%08x\n", (unsigned)ndp16->dwSignature); return false; } if (ndp16->wNextNdpIndex != 0) { - ERROR_OUT("(EE) cannot handle wNextNdpIndex!=0 (%d)\n", ndp16->wNextNdpIndex); + TU_LOG1("(EE) cannot handle wNextNdpIndex!=0 (%d)\n", ndp16->wNextNdpIndex); return false; } - const ndp16_datagram_t *ndp16_datagram = (ndp16_datagram_t *)(ntb->data + nth16->wNdpIndex + sizeof(ndp16_t)); + const ndp16_datagram_t *ndp16_datagram = (const ndp16_datagram_t *)(ntb->data + nth16->wNdpIndex + sizeof(ndp16_t)); int ndx = 0; - int max_ndx = (ndp16->wLength - sizeof(ndp16_t)) / sizeof(ndp16_datagram_t); + uint16_t max_ndx = (uint16_t)((ndp16->wLength - sizeof(ndp16_t)) / sizeof(ndp16_datagram_t)); if (max_ndx > 2) { // number of datagrams in NTB > 1 - INFO_OUT("<< %d (%d)\n", max_ndx - 1, ntb->nth.wBlockLength); + TU_LOG2("<< %d (%d)\n", max_ndx - 1, ntb->nth.wBlockLength); } if (ndp16_datagram[max_ndx-1].wDatagramIndex != 0 || ndp16_datagram[max_ndx-1].wDatagramLength != 0) { - INFO_OUT(" max_ndx != 0\n"); + TU_LOG2(" max_ndx != 0\n"); return false; } while (ndp16_datagram[ndx].wDatagramIndex != 0 && ndp16_datagram[ndx].wDatagramLength != 0) { - DEBUG_OUT(" << %d %d\n", ndp16_datagram[ndx].wDatagramIndex, ndp16_datagram[ndx].wDatagramLength); + TU_LOG3(" << %d %d\n", ndp16_datagram[ndx].wDatagramIndex, ndp16_datagram[ndx].wDatagramLength); if (ndp16_datagram[ndx].wDatagramIndex > len) { - ERROR_OUT("(EE) ill start of datagram[%d]: %d (%d)\n", ndx, ndp16_datagram[ndx].wDatagramIndex, len); + TU_LOG1("(EE) ill start of datagram[%d]: %d (%d)\n", ndx, ndp16_datagram[ndx].wDatagramIndex, len); return false; } if (ndp16_datagram[ndx].wDatagramIndex + ndp16_datagram[ndx].wDatagramLength > len) { - ERROR_OUT("(EE) ill end of datagram[%d]: %d (%d)\n", ndx, ndp16_datagram[ndx].wDatagramIndex + ndp16_datagram[ndx].wDatagramLength, len); + TU_LOG1("(EE) ill end of datagram[%d]: %d (%d)\n", ndx, ndp16_datagram[ndx].wDatagramIndex + ndp16_datagram[ndx].wDatagramLength, len); return false; } ++ndx; } - for (int i = 0; i < len; ++i) { - DEBUG_OUT(" %02x", ntb->data[i]); +#if CFG_TUSB_DEBUG >= 3 + for (uint32_t i = 0; i < len; ++i) { + TU_LOG3(" %02x", ntb->data[i]); } - DEBUG_OUT("\n"); + TU_LOG3("\n"); +#endif // -> ntb contains a valid packet structure // ok... I did not check for garbage within the datagram indices... @@ -674,11 +657,11 @@ static void recv_transfer_datagram_to_glue_logic(void) * Transfer the next (pending) datagram to the glue logic and return receive buffer if empty. */ { - DEBUG_OUT("recv_transfer_datagram_to_glue_logic()\n"); + TU_LOG3("recv_transfer_datagram_to_glue_logic()\n"); if (ncm_interface.recv_glue_ntb == NULL) { ncm_interface.recv_glue_ntb = recv_get_next_ready_ntb(); - DEBUG_OUT(" new buffer for glue logic: %p\n", ncm_interface.recv_glue_ntb); + TU_LOG3(" new buffer for glue logic: %p\n", ncm_interface.recv_glue_ntb); ncm_interface.recv_glue_ntb_datagram_ndx = 0; } @@ -688,21 +671,21 @@ static void recv_transfer_datagram_to_glue_logic(void) + sizeof(ndp16_t)); if (ndp16_datagram[ncm_interface.recv_glue_ntb_datagram_ndx].wDatagramIndex == 0) { - ERROR_OUT("(EE) SOMETHING WENT WRONG 1\n"); + TU_LOG1("(EE) SOMETHING WENT WRONG 1\n"); } else if (ndp16_datagram[ncm_interface.recv_glue_ntb_datagram_ndx].wDatagramLength == 0) { - ERROR_OUT("(EE) SOMETHING WENT WRONG 2\n"); + TU_LOG1("(EE) SOMETHING WENT WRONG 2\n"); } else { uint16_t datagramIndex = ndp16_datagram[ncm_interface.recv_glue_ntb_datagram_ndx].wDatagramIndex; uint16_t datagramLength = ndp16_datagram[ncm_interface.recv_glue_ntb_datagram_ndx].wDatagramLength; - DEBUG_OUT(" recv[%d] - %d %d\n", ncm_interface.recv_glue_ntb_datagram_ndx, datagramIndex, datagramLength); + TU_LOG3(" recv[%d] - %d %d\n", ncm_interface.recv_glue_ntb_datagram_ndx, datagramIndex, datagramLength); if (tud_network_recv_cb(ncm_interface.recv_glue_ntb->data + datagramIndex, datagramLength)) { // // send datagram successfully to glue logic // - DEBUG_OUT(" OK\n"); + TU_LOG3(" OK\n"); datagramIndex = ndp16_datagram[ncm_interface.recv_glue_ntb_datagram_ndx + 1].wDatagramIndex; datagramLength = ndp16_datagram[ncm_interface.recv_glue_ntb_datagram_ndx + 1].wDatagramLength; @@ -734,7 +717,7 @@ bool tud_network_can_xmit(uint16_t size) * and transmission operation. */ { - DEBUG_OUT("tud_network_can_xmit(%d)\n", size); + TU_LOG3("tud_network_can_xmit(%d)\n", size); TU_ASSERT(size <= CFG_TUD_NCM_OUT_NTB_MAX_SIZE - (sizeof(nth16_t) + sizeof(ndp16_t) + 2*sizeof(ndp16_datagram_t)), false); @@ -743,7 +726,7 @@ bool tud_network_can_xmit(uint16_t size) return true; } xmit_start_if_possible(ncm_interface.rhport); - ERROR_OUT("(II) tud_network_can_xmit: request blocked\n"); // could happen if all xmit buffers are full (but should happen rarely) + TU_LOG1("(II) tud_network_can_xmit: request blocked\n"); // could happen if all xmit buffers are full (but should happen rarely) return false; } // tud_network_can_xmit @@ -755,10 +738,10 @@ void tud_network_xmit(void *ref, uint16_t arg) * If currently no transmission is started, then initiate transmission. */ { - DEBUG_OUT("tud_network_xmit(%p, %d)\n", ref, arg); + TU_LOG3("tud_network_xmit(%p, %d)\n", ref, arg); if (ncm_interface.xmit_glue_ntb == NULL) { - ERROR_OUT("(EE) tud_network_xmit: no buffer\n"); // must not happen (really) + TU_LOG1("(EE) tud_network_xmit: no buffer\n"); // must not happen (really) return; } @@ -772,10 +755,10 @@ void tud_network_xmit(void *ref, uint16_t arg) ntb->ndp_datagram[ncm_interface.xmit_glue_ntb_datagram_ndx].wDatagramLength = size; ncm_interface.xmit_glue_ntb_datagram_ndx += 1; - ntb->nth.wBlockLength += size + XMIT_ALIGN_OFFSET(size); + ntb->nth.wBlockLength += (uint16_t)(size + XMIT_ALIGN_OFFSET(size)); if (ntb->nth.wBlockLength > CFG_TUD_NCM_OUT_NTB_MAX_SIZE) { - ERROR_OUT("(II) tud_network_xmit: buffer overflow\n"); // must not happen (really) + TU_LOG1("(II) tud_network_xmit: buffer overflow\n"); // must not happen (really) return; } @@ -789,7 +772,7 @@ void tud_network_recv_renew(void) * Keep the receive logic busy and transfer pending packets to the glue logic. */ { - DEBUG_OUT("tud_network_recv_renew()\n"); + TU_LOG3("tud_network_recv_renew()\n"); recv_transfer_datagram_to_glue_logic(); recv_try_to_start_new_reception(ncm_interface.rhport); @@ -802,7 +785,7 @@ void tud_network_recv_renew_r(uint8_t rhport) * Same as tud_network_recv_renew() but knows \a rhport */ { - DEBUG_OUT("tud_network_recv_renew_r(%d)\n", rhport); + TU_LOG3("tud_network_recv_renew_r(%d)\n", rhport); ncm_interface.rhport = rhport; tud_network_recv_renew(); @@ -819,7 +802,7 @@ void netd_init(void) * Might be called several times. */ { - DEBUG_OUT("netd_init()\n"); + TU_LOG3("netd_init()\n"); memset( &ncm_interface, 0, sizeof(ncm_interface)); @@ -839,7 +822,9 @@ void netd_reset(uint8_t rhport) * In this driver this is the same as netd_init() */ { - DEBUG_OUT("netd_reset(%d)\n", rhport); + (void)rhport; + + TU_LOG3("netd_reset(%d)\n", rhport); netd_init(); } // netd_reset @@ -862,7 +847,7 @@ uint16_t netd_open(uint8_t rhport, tusb_desc_interface_t const *itf_desc, uint16 * - USB interface is open */ { - DEBUG_OUT("netd_open(%d,%p,%d)\n", rhport, itf_desc, max_len); + TU_LOG3("netd_open(%d,%p,%d)\n", rhport, itf_desc, max_len); TU_ASSERT(ncm_interface.ep_notif == 0, 0); // assure that the interface is only opened once @@ -915,7 +900,9 @@ bool netd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_ * Handle TinyUSB requests to process transfer events. */ { - DEBUG_OUT("netd_xfer_cb(%d,%d,%d,%u)\n", rhport, ep_addr, result, (unsigned)xferred_bytes); + (void)result; + + TU_LOG3("netd_xfer_cb(%d,%d,%d,%u)\n", rhport, ep_addr, result, (unsigned)xferred_bytes); if (ep_addr == ncm_interface.ep_out) { // @@ -924,10 +911,10 @@ bool netd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_ // - if ready transfer datagrams to the glue logic for further processing // - if there is a free receive buffer, initiate reception // - DEBUG_OUT(" EP_OUT %d %d %d %u\n", rhport, ep_addr, result, (unsigned)xferred_bytes); + TU_LOG3(" EP_OUT %d %d %d %u\n", rhport, ep_addr, result, (unsigned)xferred_bytes); if ( !recv_validate_datagram( ncm_interface.recv_tinyusb_ntb, xferred_bytes)) { // verification failed: ignore NTB and return it to free - ERROR_OUT("(EE) VALIDATION FAILED. WHAT CAN WE DO IN THIS CASE?\n"); + TU_LOG1("(EE) VALIDATION FAILED. WHAT CAN WE DO IN THIS CASE?\n"); } else { // packet ok -> put it into ready list @@ -943,7 +930,7 @@ bool netd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_ // - insert ZLPs when necessary // - if there is another transmit NTB waiting, try to start transmission // - DEBUG_OUT(" EP_IN %d %u\n", ncm_interface.itf_data_alt, (unsigned)xferred_bytes); + TU_LOG3(" EP_IN %d %u\n", ncm_interface.itf_data_alt, (unsigned)xferred_bytes); xmit_put_ntb_into_free_list(ncm_interface.xmit_tinyusb_ntb); ncm_interface.xmit_tinyusb_ntb = NULL; if ( !xmit_insert_required_zlp(rhport, xferred_bytes)) { @@ -954,7 +941,7 @@ bool netd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_ // // next transfer on notification channel // - DEBUG_OUT(" EP_NOTIF\n"); + TU_LOG3(" EP_NOTIF\n"); notification_xmit(rhport, true); } @@ -969,7 +956,7 @@ bool netd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t * At startup transmission of notification packets are done here. */ { - DEBUG_OUT("netd_control_xfer_cb(%d, %d, %p)\n", rhport, stage, request); + TU_LOG3("netd_control_xfer_cb(%d, %d, %p)\n", rhport, stage, request); if (stage != CONTROL_STAGE_SETUP) { return true; @@ -981,7 +968,7 @@ bool netd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t case TUSB_REQ_GET_INTERFACE: { TU_VERIFY(ncm_interface.itf_num + 1 == request->wIndex, false); - DEBUG_OUT(" TUSB_REQ_GET_INTERFACE - %d\n", ncm_interface.itf_data_alt); + TU_LOG3(" TUSB_REQ_GET_INTERFACE - %d\n", ncm_interface.itf_data_alt); tud_control_xfer(rhport, request, &ncm_interface.itf_data_alt, 1); } break; @@ -989,8 +976,8 @@ bool netd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t case TUSB_REQ_SET_INTERFACE: { TU_VERIFY(ncm_interface.itf_num + 1 == request->wIndex && request->wValue < 2, false); - ncm_interface.itf_data_alt = request->wValue; - DEBUG_OUT(" TUSB_REQ_SET_INTERFACE - %d %d %d\n", ncm_interface.itf_data_alt, request->wIndex, ncm_interface.itf_num); + ncm_interface.itf_data_alt = (uint8_t)request->wValue; + TU_LOG3(" TUSB_REQ_SET_INTERFACE - %d %d %d\n", ncm_interface.itf_data_alt, request->wIndex, ncm_interface.itf_num); if (ncm_interface.itf_data_alt == 1) { tud_network_recv_renew_r(rhport); @@ -1009,12 +996,12 @@ bool netd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t case TUSB_REQ_TYPE_CLASS: TU_VERIFY(ncm_interface.itf_num == request->wIndex, false); - DEBUG_OUT(" TUSB_REQ_TYPE_CLASS: %d\n", request->bRequest); + TU_LOG3(" TUSB_REQ_TYPE_CLASS: %d\n", request->bRequest); if (request->bRequest == NCM_GET_NTB_PARAMETERS) { // transfer NTB parameters to host. // TODO can one assume, that tud_control_xfer() succeeds? - DEBUG_OUT(" NCM_GET_NTB_PARAMETERS\n"); + TU_LOG3(" NCM_GET_NTB_PARAMETERS\n"); tud_control_xfer(rhport, request, (void*) (uintptr_t) &ntb_parameters, sizeof(ntb_parameters)); } break; -- cgit v1.3.1 From 51ea467350f84b92439d0890a4b12bd55e2eff91 Mon Sep 17 00:00:00 2001 From: Hardy Griech Date: Thu, 31 Aug 2023 20:34:12 +0200 Subject: removed debug comment --- src/class/net/ncm_device.c | 12 ------------ 1 file changed, 12 deletions(-) (limited to 'src/class') diff --git a/src/class/net/ncm_device.c b/src/class/net/ncm_device.c index d0832cf73..9adb3df0d 100644 --- a/src/class/net/ncm_device.c +++ b/src/class/net/ncm_device.c @@ -134,18 +134,6 @@ CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN tu_static const ntb_parameters_t ntb_par .wNtbOutMaxDatagrams = 6 // 0=no limit }; -// Some confusing remarks about wNtbOutMaxDatagrams... -// ==1 -> SystemView packets/s goes up to 2000 and events are lost during startup -// ==0 -> SystemView runs fine, iperf shows in wireshark a lot of error -// ==6 -> SystemView runs fine, iperf also -// >6 -> iperf starts to show errors -// -> 6 seems to be the best value. Why? Don't know, perhaps only on my system? -// switch \a TU_LOG2 on to see interesting values for this. -// -// iperf: for MSS in 100 200 400 800 1200 1450 1500; do iperf -c 192.168.14.1 -e -i 1 -M $MSS -l 8192 -P 1; sleep 2; done -// sysview: SYSTICKS_PER_SEC=35000, IDLE_US=1000, PRINT_MOD=1000 -// - //----------------------------------------------------------------------------- // // everything about notifications -- cgit v1.3.1 From f1d3663d24f04dbb68732f8287c516abd0b7ecfb Mon Sep 17 00:00:00 2001 From: Hardy Griech Date: Fri, 8 Sep 2023 07:01:13 +0200 Subject: minor changes to comments and debug output --- src/class/net/ncm_device.c | 24 +++++++++--------------- 1 file changed, 9 insertions(+), 15 deletions(-) (limited to 'src/class') diff --git a/src/class/net/ncm_device.c b/src/class/net/ncm_device.c index 9adb3df0d..d803d6429 100644 --- a/src/class/net/ncm_device.c +++ b/src/class/net/ncm_device.c @@ -59,11 +59,6 @@ #include "ncm.h" -#if !defined(tu_static) || defined(ECLIPSE_GUI) - // TinyUSB <=0.15.0 does not know "tu_static" - #define tu_static static -#endif - // calculate alignment of xmit datagrams within an NTB #define XMIT_ALIGN_OFFSET(x) ((CFG_TUD_NCM_ALIGNMENT - ((x) & (CFG_TUD_NCM_ALIGNMENT - 1))) & (CFG_TUD_NCM_ALIGNMENT - 1)) @@ -84,7 +79,7 @@ typedef struct { uint8_t rhport; //!< storage of \a rhport because some callbacks are done without it // recv handling - CFG_TUSB_MEM_ALIGN recv_ntb_t recv_ntb[RECV_NTB_N]; //!< actual recv NTBs + CFG_TUSB_MEM_ALIGN recv_ntb_t recv_ntb[RECV_NTB_N]; //!< actual recv NTBs recv_ntb_t *recv_free_ntb[RECV_NTB_N]; //!< free list of recv NTBs recv_ntb_t *recv_ready_ntb[RECV_NTB_N]; //!< NTBs waiting for transmission to glue logic recv_ntb_t *recv_tinyusb_ntb; //!< buffer for the running transfer TinyUSB -> driver @@ -92,7 +87,7 @@ typedef struct { uint16_t recv_glue_ntb_datagram_ndx; //!< index into \a recv_glue_ntb_datagram // xmit handling - CFG_TUSB_MEM_ALIGN xmit_ntb_t xmit_ntb[XMIT_NTB_N]; //!< actual xmit NTBs + CFG_TUSB_MEM_ALIGN xmit_ntb_t xmit_ntb[XMIT_NTB_N]; //!< actual xmit NTBs xmit_ntb_t *xmit_free_ntb[XMIT_NTB_N]; //!< free list of xmit NTBs xmit_ntb_t *xmit_ready_ntb[XMIT_NTB_N]; //!< NTBs waiting for transmission to TinyUSB xmit_ntb_t *xmit_tinyusb_ntb; //!< buffer for the running transfer driver -> TinyUSB @@ -327,7 +322,7 @@ static void xmit_start_if_possible(uint8_t rhport) return; } if (ncm_interface.itf_data_alt != 1) { - TU_LOG1("(II) !xmit_start_if_possible 2\n"); + TU_LOG1("(EE) !xmit_start_if_possible 2\n"); return; } if (usbd_edpt_busy(rhport, ncm_interface.ep_in)) { @@ -472,7 +467,7 @@ static recv_ntb_t *recv_get_next_ready_ntb(void) static void recv_put_ntb_into_free_list(recv_ntb_t *free_ntb) /** - * + * Put NTB into the receiver free list. */ { TU_LOG3("recv_put_ntb_into_free_list(%p)\n", free_ntb); @@ -490,8 +485,8 @@ static void recv_put_ntb_into_free_list(recv_ntb_t *free_ntb) static void recv_put_ntb_into_ready_list(recv_ntb_t *ready_ntb) /** - * The \a ncm_interface.recv_tinyusb_ntb is filled, - * put this buffer into the waiting list and free the receive logic. + * \a ready_ntb holds a validated NTB, + * put this buffer into the waiting list. */ { TU_LOG3("recv_put_ntb_into_ready_list(%p) %d\n", ready_ntb, ready_ntb->nth.wBlockLength); @@ -510,7 +505,6 @@ static void recv_put_ntb_into_ready_list(recv_ntb_t *ready_ntb) static void recv_try_to_start_new_reception(uint8_t rhport) /** * If possible, start a new reception TinyUSB -> driver. - * Return value is actually not of interest. */ { TU_LOG3("recv_try_to_start_new_reception(%d)\n", rhport); @@ -552,7 +546,7 @@ static bool recv_validate_datagram(const recv_ntb_t *ntb, uint32_t len) { const nth16_t *nth16 = &(ntb->nth); - TU_LOG3("recv_validate_datagram(%p)\n", ntb); + TU_LOG3("recv_validate_datagram(%p, %d)\n", ntb, (int)len); // // check header @@ -714,7 +708,7 @@ bool tud_network_can_xmit(uint16_t size) return true; } xmit_start_if_possible(ncm_interface.rhport); - TU_LOG1("(II) tud_network_can_xmit: request blocked\n"); // could happen if all xmit buffers are full (but should happen rarely) + TU_LOG2("tud_network_can_xmit: request blocked\n"); // could happen if all xmit buffers are full (but should happen rarely) return false; } // tud_network_can_xmit @@ -746,7 +740,7 @@ void tud_network_xmit(void *ref, uint16_t arg) ntb->nth.wBlockLength += (uint16_t)(size + XMIT_ALIGN_OFFSET(size)); if (ntb->nth.wBlockLength > CFG_TUD_NCM_OUT_NTB_MAX_SIZE) { - TU_LOG1("(II) tud_network_xmit: buffer overflow\n"); // must not happen (really) + TU_LOG1("(EE) tud_network_xmit: buffer overflow\n"); // must not happen (really) return; } -- cgit v1.3.1 From 11fba8433474a0653047823a25a749183a7d1ac2 Mon Sep 17 00:00:00 2001 From: Rocky04 Date: Wed, 13 Sep 2023 21:29:04 +0000 Subject: Error handling on transfer --- src/class/hid/hid_device.c | 25 +++++++++++++++++++++---- src/class/hid/hid_device.h | 4 ++++ 2 files changed, 25 insertions(+), 4 deletions(-) (limited to 'src/class') diff --git a/src/class/hid/hid_device.c b/src/class/hid/hid_device.c index 5637ea6b4..8bedb6395 100644 --- a/src/class/hid/hid_device.c +++ b/src/class/hid/hid_device.c @@ -381,8 +381,6 @@ bool hidd_control_xfer_cb (uint8_t rhport, uint8_t stage, tusb_control_request_t bool hidd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) { - (void) result; - uint8_t instance = 0; hidd_interface_t * p_hid = _hidd_itf; @@ -394,6 +392,25 @@ bool hidd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_ } TU_ASSERT(instance < CFG_TUD_HID); + // Check if there was a problem + if (XFER_RESULT_SUCCESS != result) + { + // Inform application about the issue + if (tud_hid_report_issue_cb) + { + tud_hid_report_issue_cb(instance, ep_addr, result, xferred_bytes); + } + + // Allow a new transfer to be received if issue happened on an OUT endpoint + if (ep_addr == p_hid->ep_out) + { + // Prepare the OUT endpoint to be able to receive a new transfer + TU_ASSERT(usbd_edpt_xfer(rhport, p_hid->ep_out, p_hid->epout_buf, sizeof(p_hid->epout_buf))); + } + + return true; + } + // Sent report successfully if (ep_addr == p_hid->ep_in) { @@ -402,10 +419,10 @@ bool hidd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_ tud_hid_report_complete_cb(instance, p_hid->epin_buf, (uint16_t) xferred_bytes); } } - // Received report + // Received report successfully else if (ep_addr == p_hid->ep_out) { - tud_hid_set_report_cb(instance, 0, HID_REPORT_TYPE_INVALID, p_hid->epout_buf, (uint16_t) xferred_bytes); + tud_hid_set_report_cb(instance, 0, HID_REPORT_TYPE_OUTPUT, p_hid->epout_buf, (uint16_t) xferred_bytes); TU_ASSERT(usbd_edpt_xfer(rhport, p_hid->ep_out, p_hid->epout_buf, sizeof(p_hid->epout_buf))); } diff --git a/src/class/hid/hid_device.h b/src/class/hid/hid_device.h index 17b24def1..056727378 100644 --- a/src/class/hid/hid_device.h +++ b/src/class/hid/hid_device.h @@ -118,6 +118,8 @@ TU_ATTR_WEAK bool tud_hid_set_idle_cb(uint8_t instance, uint8_t idle_rate); // Note: For composite reports, report[0] is report ID TU_ATTR_WEAK void tud_hid_report_complete_cb(uint8_t instance, uint8_t const* report, uint16_t len); +// Invoked when a transfer wasn't successful +TU_ATTR_WEAK void tud_hid_report_issue_cb(uint8_t instance, uint8_t ep_addr, xfer_result_t result, uint16_t xferred_bytes); //--------------------------------------------------------------------+ // Inline Functions @@ -411,6 +413,8 @@ uint16_t hidd_open (uint8_t rhport, tusb_desc_interface_t const * itf bool hidd_control_xfer_cb (uint8_t rhport, uint8_t stage, tusb_control_request_t const * request); bool hidd_xfer_cb (uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes); +void test(void); + #ifdef __cplusplus } #endif -- cgit v1.3.1 From 81e63ed6d865d43b634ed6bf2d3df3ae29135913 Mon Sep 17 00:00:00 2001 From: Rocky04 Date: Wed, 13 Sep 2023 22:03:44 +0000 Subject: Fixing warning --- src/class/hid/hid_device.c | 2 +- src/class/hid/hid_device.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'src/class') diff --git a/src/class/hid/hid_device.c b/src/class/hid/hid_device.c index 8bedb6395..564ad12f6 100644 --- a/src/class/hid/hid_device.c +++ b/src/class/hid/hid_device.c @@ -398,7 +398,7 @@ bool hidd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_ // Inform application about the issue if (tud_hid_report_issue_cb) { - tud_hid_report_issue_cb(instance, ep_addr, result, xferred_bytes); + tud_hid_report_issue_cb(instance, ep_addr, result, (uint16_t) xferred_bytes); } // Allow a new transfer to be received if issue happened on an OUT endpoint diff --git a/src/class/hid/hid_device.h b/src/class/hid/hid_device.h index 056727378..a934753eb 100644 --- a/src/class/hid/hid_device.h +++ b/src/class/hid/hid_device.h @@ -119,7 +119,7 @@ TU_ATTR_WEAK bool tud_hid_set_idle_cb(uint8_t instance, uint8_t idle_rate); TU_ATTR_WEAK void tud_hid_report_complete_cb(uint8_t instance, uint8_t const* report, uint16_t len); // Invoked when a transfer wasn't successful -TU_ATTR_WEAK void tud_hid_report_issue_cb(uint8_t instance, uint8_t ep_addr, xfer_result_t result, uint16_t xferred_bytes); +TU_ATTR_WEAK void tud_hid_report_issue_cb(uint8_t instance, uint8_t ep_addr, xfer_result_t result, uint16_t len); //--------------------------------------------------------------------+ // Inline Functions -- cgit v1.3.1 From 9d0251f7a6751a0d998da4fad81a35a043608275 Mon Sep 17 00:00:00 2001 From: HiFiPhile Date: Tue, 19 Sep 2023 15:42:52 +0200 Subject: Fix UAC interleaved copy. --- src/class/audio/audio_device.c | 113 +++++++++++++++++++---------------------- 1 file changed, 51 insertions(+), 62 deletions(-) (limited to 'src/class') diff --git a/src/class/audio/audio_device.c b/src/class/audio/audio_device.c index 1a7ce7870..0e4220f4f 100644 --- a/src/class/audio/audio_device.c +++ b/src/class/audio/audio_device.c @@ -631,68 +631,59 @@ static bool audiod_rx_done_cb(uint8_t rhport, audiod_function_t* audio, uint16_t // Decoding according to 2.3.1.5 Audio Streams // Helper function -static inline uint8_t * audiod_interleaved_copy_bytes_fast_decode(uint16_t const nBytesToCopy, void * dst, uint8_t * dst_end, uint8_t * src, uint8_t const n_ff_used) +static inline uint8_t * audiod_interleaved_copy_bytes_fast_decode(uint16_t const nBytesToCopy, uint8_t * dst, uint8_t * dst_end, uint8_t * src, uint8_t const n_ff_used) { - // This function is an optimized version of - // while((uint8_t *)dst < dst_end) - // { - // memcpy(dst, src, nBytesToCopy); - // dst = (uint8_t *)dst + nBytesToCopy; - // src += nBytesToCopy * n_ff_used; - // } - - // Optimize for fast half word copies - typedef struct{ - uint16_t val; - } __attribute((__packed__)) unaligned_uint16_t; - - // Optimize for fast word copies - typedef struct{ - uint32_t val; - } __attribute((__packed__)) unaligned_uint32_t; + // Due to one FIFO contains 2 channels, data always aligned to (nBytesToCopy * 2) switch (nBytesToCopy) { case 1: while((uint8_t *)dst < dst_end) { - *(uint8_t *)dst++ = *src; - src += n_ff_used; + *(uint16_t*)dst = *(uint16_t*)src; + src += 2; + dst += 2; + src += 2 * (n_ff_used - 1); } break; case 2: while((uint8_t *)dst < dst_end) { - *(unaligned_uint16_t*)dst = *(unaligned_uint16_t*)src; - dst += 2; - src += 2 * n_ff_used; + *(uint32_t*)dst = *(uint32_t*)src; + src += 4; + dst += 4; + src += 4 * (n_ff_used - 1); } break; case 3: while((uint8_t *)dst < dst_end) { - // memcpy(dst, src, 3); - // dst = (uint8_t *)dst + 3; - // src += 3 * n_ff_used; - - // TODO: Is there a faster way to copy 3 bytes? - *(uint8_t *)dst++ = *src++; - *(uint8_t *)dst++ = *src++; - *(uint8_t *)dst++ = *src++; - - src += 3 * (n_ff_used - 1); + *(uint16_t*)dst = *(uint16_t*)src; + src += 2; + dst += 2; + *(uint16_t*)dst = *(uint16_t*)src; + src += 2; + dst += 2; + *(uint16_t*)dst = *(uint16_t*)src; + src += 2; + dst += 2; + src += 6 * (n_ff_used - 1); } break; case 4: while((uint8_t *)dst < dst_end) { - *(unaligned_uint32_t*)dst = *(unaligned_uint32_t*)src; + *(uint32_t*)dst++ = *(uint32_t*)src++; + src += 4; + dst += 4; + *(uint32_t*)dst++ = *(uint32_t*)src++; + src += 4; dst += 4; - src += 4 * n_ff_used; + src += 8 * (n_ff_used - 1); } break; } @@ -946,57 +937,55 @@ range [-1, +1) // Helper function static inline uint8_t * audiod_interleaved_copy_bytes_fast_encode(uint16_t const nBytesToCopy, uint8_t * src, uint8_t * src_end, uint8_t * dst, uint8_t const n_ff_used) { - // Optimize for fast half word copies - typedef struct{ - uint16_t val; - } __attribute((__packed__)) unaligned_uint16_t; - - // Optimize for fast word copies - typedef struct{ - uint32_t val; - } __attribute((__packed__)) unaligned_uint32_t; - + // Due to one FIFO contains 2 channels, data always aligned to (nBytesToCopy * 2) switch (nBytesToCopy) { case 1: while(src < src_end) { - *dst = *src++; - dst += n_ff_used; + *(uint16_t*)dst = *(uint16_t*)src; + src += 2; + dst += 2; + dst += 2 * (n_ff_used - 1); } break; case 2: while(src < src_end) { - *(unaligned_uint16_t*)dst = *(unaligned_uint16_t*)src; - src += 2; - dst += 2 * n_ff_used; + *(uint32_t*)dst = *(uint32_t*)src; + src += 4; + dst += 4; + dst += 4 * (n_ff_used - 1); } break; case 3: while(src < src_end) { - // memcpy(dst, src, 3); - // src = (uint8_t *)src + 3; - // dst += 3 * n_ff_used; - - // TODO: Is there a faster way to copy 3 bytes? - *dst++ = *src++; - *dst++ = *src++; - *dst++ = *src++; - - dst += 3 * (n_ff_used - 1); + *(uint16_t*)dst = *(uint16_t*)src; + src += 2; + dst += 2; + *(uint16_t*)dst = *(uint16_t*)src; + src += 2; + dst += 2; + *(uint16_t*)dst = *(uint16_t*)src; + src += 2; + dst += 2; + dst += 6 * (n_ff_used - 1); } break; case 4: while(src < src_end) { - *(unaligned_uint32_t*)dst = *(unaligned_uint32_t*)src; + *(uint32_t*)dst++ = *(uint32_t*)src++; + src += 4; + dst += 4; + *(uint32_t*)dst++ = *(uint32_t*)src++; src += 4; - dst += 4 * n_ff_used; + dst += 4; + dst += 8 * (n_ff_used - 1); } break; } -- cgit v1.3.1 From 6be7f354c26e09a87d1b856b0e237ff82be5963f Mon Sep 17 00:00:00 2001 From: HiFiPhile Date: Tue, 19 Sep 2023 16:32:49 +0200 Subject: Fix cast-align. --- src/class/audio/audio_device.c | 196 +++++++++++++++++++---------------------- 1 file changed, 90 insertions(+), 106 deletions(-) (limited to 'src/class') diff --git a/src/class/audio/audio_device.c b/src/class/audio/audio_device.c index 0e4220f4f..46fd6dfa9 100644 --- a/src/class/audio/audio_device.c +++ b/src/class/audio/audio_device.c @@ -631,64 +631,55 @@ static bool audiod_rx_done_cb(uint8_t rhport, audiod_function_t* audio, uint16_t // Decoding according to 2.3.1.5 Audio Streams // Helper function -static inline uint8_t * audiod_interleaved_copy_bytes_fast_decode(uint16_t const nBytesToCopy, uint8_t * dst, uint8_t * dst_end, uint8_t * src, uint8_t const n_ff_used) +static inline void * audiod_interleaved_copy_bytes_fast_decode(uint16_t const nBytesToCopy, void * dst, const void * dst_end, void * src, uint8_t const n_ff_used) { - // Due to one FIFO contains 2 channels, data always aligned to (nBytesToCopy * 2) - - switch (nBytesToCopy) + uint16_t * dst16 = dst; + uint16_t * src16 = src; + const uint16_t * dst_end16 = dst_end; + uint32_t * dst32 = dst; + uint32_t * src32 = src; + const uint32_t * dst_end32 = dst_end; + + if (nBytesToCopy == 1) { - case 1: - while((uint8_t *)dst < dst_end) - { - *(uint16_t*)dst = *(uint16_t*)src; - src += 2; - dst += 2; - src += 2 * (n_ff_used - 1); - } - break; - - case 2: - while((uint8_t *)dst < dst_end) - { - *(uint32_t*)dst = *(uint32_t*)src; - src += 4; - dst += 4; - src += 4 * (n_ff_used - 1); - } - break; - - case 3: - while((uint8_t *)dst < dst_end) - { - *(uint16_t*)dst = *(uint16_t*)src; - src += 2; - dst += 2; - *(uint16_t*)dst = *(uint16_t*)src; - src += 2; - dst += 2; - *(uint16_t*)dst = *(uint16_t*)src; - src += 2; - dst += 2; - src += 6 * (n_ff_used - 1); - } - break; - - case 4: - while((uint8_t *)dst < dst_end) - { - *(uint32_t*)dst++ = *(uint32_t*)src++; - src += 4; - dst += 4; - *(uint32_t*)dst++ = *(uint32_t*)src++; - src += 4; - dst += 4; - src += 8 * (n_ff_used - 1); - } - break; + while(dst16 < dst_end16) + { + *dst16++ = *src16++; + src16 += n_ff_used - 1; + } + return src16; + } + else if (nBytesToCopy == 2) + { + while(dst32 < dst_end32) + { + *dst32++ = *src32++; + src32 += n_ff_used - 1; + } + return src32; + } + else if (nBytesToCopy == 3) + { + while(dst16 < dst_end16) + { + *dst16++ = *src16++; + *dst16++ = *src16++; + *dst16++ = *src16++; + src16 += 3 * (n_ff_used - 1); + } + return src16; + } + else // nBytesToCopy == 4 + { + while(dst32 < dst_end32) + { + *dst32++ = *src32++; + *dst32++ = *src32++; + src32 += 2 * (n_ff_used - 1); + } + return src32; } - - return src; } static bool audiod_decode_type_I_pcm(uint8_t rhport, audiod_function_t* audio, uint16_t n_bytes_received) @@ -935,62 +926,55 @@ range [-1, +1) * */ // Helper function -static inline uint8_t * audiod_interleaved_copy_bytes_fast_encode(uint16_t const nBytesToCopy, uint8_t * src, uint8_t * src_end, uint8_t * dst, uint8_t const n_ff_used) +static inline void * audiod_interleaved_copy_bytes_fast_encode(uint16_t const nBytesToCopy, void * src, const void * src_end, void * dst, uint8_t const n_ff_used) { // Due to one FIFO contains 2 channels, data always aligned to (nBytesToCopy * 2) - switch (nBytesToCopy) + uint16_t * dst16 = dst; + uint16_t * src16 = src; + const uint16_t * src_end16 = src_end; + uint32_t * dst32 = dst; + uint32_t * src32 = src; + const uint32_t * src_end32 = src_end; + + if (nBytesToCopy == 1) { - case 1: - while(src < src_end) - { - *(uint16_t*)dst = *(uint16_t*)src; - src += 2; - dst += 2; - dst += 2 * (n_ff_used - 1); - } - break; - - case 2: - while(src < src_end) - { - *(uint32_t*)dst = *(uint32_t*)src; - src += 4; - dst += 4; - dst += 4 * (n_ff_used - 1); - } - break; - - case 3: - while(src < src_end) - { - *(uint16_t*)dst = *(uint16_t*)src; - src += 2; - dst += 2; - *(uint16_t*)dst = *(uint16_t*)src; - src += 2; - dst += 2; - *(uint16_t*)dst = *(uint16_t*)src; - src += 2; - dst += 2; - dst += 6 * (n_ff_used - 1); - } - break; - - case 4: - while(src < src_end) - { - *(uint32_t*)dst++ = *(uint32_t*)src++; - src += 4; - dst += 4; - *(uint32_t*)dst++ = *(uint32_t*)src++; - src += 4; - dst += 4; - dst += 8 * (n_ff_used - 1); - } - break; + while(src16 < src_end16) + { + *dst16++ = *src16++; + dst16 += n_ff_used - 1; + } + return dst16; + } + else if (nBytesToCopy == 2) + { + while(src32 < src_end32) + { + *dst32++ = *src32++; + dst32 += n_ff_used - 1; + } + return dst32; + } + else if (nBytesToCopy == 3) + { + while(src16 < src_end16) + { + *dst16++ = *src16++; + *dst16++ = *src16++; + *dst16++ = *src16++; + dst16 += 3 * (n_ff_used - 1); + } + return dst16; + } + else // nBytesToCopy == 4 + { + while(src32 < src_end32) + { + *dst32++ = *src32++; + *dst32++ = *src32++; + dst32 += 2 * (n_ff_used - 1); + } + return dst32; } - - return dst; } static uint16_t audiod_encode_type_I_pcm(uint8_t rhport, audiod_function_t* audio) -- cgit v1.3.1 From 277852afc1798f2acdb61917984e76b4bafa699e Mon Sep 17 00:00:00 2001 From: hathach Date: Thu, 28 Sep 2023 10:56:38 +0700 Subject: fix esp32 msc example --- examples/host/cdc_msc_hid_freertos/src/cdc_app.c | 8 +- examples/host/cdc_msc_hid_freertos/src/hid_app.c | 4 + examples/host/cdc_msc_hid_freertos/src/main.c | 12 +- examples/host/cdc_msc_hid_freertos/src/msc_app.c | 8 +- src/class/msc/msc_host.c | 265 ++++++++++------------- src/class/msc/msc_host.h | 8 +- src/host/usbh.c | 22 +- 7 files changed, 151 insertions(+), 176 deletions(-) (limited to 'src/class') diff --git a/examples/host/cdc_msc_hid_freertos/src/cdc_app.c b/examples/host/cdc_msc_hid_freertos/src/cdc_app.c index 943e534d8..91dcc2e1a 100644 --- a/examples/host/cdc_msc_hid_freertos/src/cdc_app.c +++ b/examples/host/cdc_msc_hid_freertos/src/cdc_app.c @@ -31,9 +31,7 @@ // MACRO TYPEDEF CONSTANT ENUM DECLARATION //--------------------------------------------------------------------+ - -//------------- IMPLEMENTATION -------------// - +// helper size_t get_console_inputs(uint8_t *buf, size_t bufsize) { size_t count = 0; while (count < bufsize) { @@ -47,6 +45,10 @@ size_t get_console_inputs(uint8_t *buf, size_t bufsize) { return count; } +void cdc_app_init(void) { + // nothing to do +} + void cdc_app_task(void* param) { (void) param; diff --git a/examples/host/cdc_msc_hid_freertos/src/hid_app.c b/examples/host/cdc_msc_hid_freertos/src/hid_app.c index a2df3b909..9ea5c1be0 100644 --- a/examples/host/cdc_msc_hid_freertos/src/hid_app.c +++ b/examples/host/cdc_msc_hid_freertos/src/hid_app.c @@ -48,6 +48,10 @@ static void process_kbd_report(hid_keyboard_report_t const *report); static void process_mouse_report(hid_mouse_report_t const *report); static void process_generic_report(uint8_t dev_addr, uint8_t instance, uint8_t const *report, uint16_t len); +void hid_app_init(void) { + // nothing to do +} + //--------------------------------------------------------------------+ // TinyUSB Callbacks //--------------------------------------------------------------------+ diff --git a/examples/host/cdc_msc_hid_freertos/src/main.c b/examples/host/cdc_msc_hid_freertos/src/main.c index 88e742ee2..b60be015b 100644 --- a/examples/host/cdc_msc_hid_freertos/src/main.c +++ b/examples/host/cdc_msc_hid_freertos/src/main.c @@ -82,10 +82,15 @@ StaticTask_t cdc_taskdef; TimerHandle_t blinky_tm; static void led_blinky_cb(TimerHandle_t xTimer); -static void usb_host_task(void* param); +extern void cdc_app_init(void); +extern void hid_app_init(void); +extern void msc_app_init(void); +static void usb_host_task(void* param); extern void cdc_app_task(void* param); + + /*------------- MAIN -------------*/ int main(void) { board_init(); @@ -131,6 +136,10 @@ static void usb_host_task(void *param) { board_init_after_tusb(); } + cdc_app_init(); + hid_app_init(); + msc_app_init(); + // RTOS forever loop while (1) { // put this thread to waiting state until there is new events @@ -154,7 +163,6 @@ void tuh_umount_cb(uint8_t dev_addr) { printf("A device with address %d is unmounted \r\n", dev_addr); } - //--------------------------------------------------------------------+ // BLINKING TASK //--------------------------------------------------------------------+ diff --git a/examples/host/cdc_msc_hid_freertos/src/msc_app.c b/examples/host/cdc_msc_hid_freertos/src/msc_app.c index a8d6fbfaa..ee02ba917 100644 --- a/examples/host/cdc_msc_hid_freertos/src/msc_app.c +++ b/examples/host/cdc_msc_hid_freertos/src/msc_app.c @@ -25,10 +25,12 @@ #include "tusb.h" -#if CFG_TUH_MSC - static scsi_inquiry_resp_t inquiry_resp; +void msc_app_init(void) { + // nothing to do +} + bool inquiry_complete_cb(uint8_t dev_addr, tuh_msc_complete_data_t const *cb_data) { msc_cbw_t const *cbw = cb_data->cbw; msc_csw_t const *csw = cb_data->csw; @@ -63,5 +65,3 @@ void tuh_msc_umount_cb(uint8_t dev_addr) { (void) dev_addr; printf("A MassStorage device is unmounted\r\n"); } - -#endif diff --git a/src/class/msc/msc_host.c b/src/class/msc/msc_host.c index da264142c..39f2d9f1c 100644 --- a/src/class/msc/msc_host.c +++ b/src/class/msc/msc_host.c @@ -43,16 +43,14 @@ //--------------------------------------------------------------------+ // MACRO CONSTANT TYPEDEF //--------------------------------------------------------------------+ -enum -{ +enum { MSC_STAGE_IDLE = 0, MSC_STAGE_CMD, MSC_STAGE_DATA, MSC_STAGE_STATUS, }; -typedef struct -{ +typedef struct { uint8_t itf_num; uint8_t ep_in; uint8_t ep_out; @@ -69,13 +67,13 @@ typedef struct //------------- SCSI -------------// uint8_t stage; - void* buffer; + void* buffer; tuh_msc_complete_cb_t complete_cb; uintptr_t complete_arg; CFG_TUH_MEM_ALIGN msc_cbw_t cbw; CFG_TUH_MEM_ALIGN msc_csw_t csw; -}msch_interface_t; +} msch_interface_t; CFG_TUH_MEM_SECTION static msch_interface_t _msch_itf[CFG_TUH_DEVICE_MAX]; @@ -86,40 +84,34 @@ static uint8_t _msch_buffer[sizeof(scsi_inquiry_resp_t)]; // FIXME potential nul reference TU_ATTR_ALWAYS_INLINE -static inline msch_interface_t* get_itf(uint8_t dev_addr) -{ - return &_msch_itf[dev_addr-1]; +static inline msch_interface_t* get_itf(uint8_t dev_addr) { + return &_msch_itf[dev_addr - 1]; } //--------------------------------------------------------------------+ // PUBLIC API //--------------------------------------------------------------------+ -uint8_t tuh_msc_get_maxlun(uint8_t dev_addr) -{ +uint8_t tuh_msc_get_maxlun(uint8_t dev_addr) { msch_interface_t* p_msc = get_itf(dev_addr); return p_msc->max_lun; } -uint32_t tuh_msc_get_block_count(uint8_t dev_addr, uint8_t lun) -{ +uint32_t tuh_msc_get_block_count(uint8_t dev_addr, uint8_t lun) { msch_interface_t* p_msc = get_itf(dev_addr); return p_msc->capacity[lun].block_count; } -uint32_t tuh_msc_get_block_size(uint8_t dev_addr, uint8_t lun) -{ +uint32_t tuh_msc_get_block_size(uint8_t dev_addr, uint8_t lun) { msch_interface_t* p_msc = get_itf(dev_addr); return p_msc->capacity[lun].block_size; } -bool tuh_msc_mounted(uint8_t dev_addr) -{ +bool tuh_msc_mounted(uint8_t dev_addr) { msch_interface_t* p_msc = get_itf(dev_addr); return p_msc->mounted; } -bool tuh_msc_ready(uint8_t dev_addr) -{ +bool tuh_msc_ready(uint8_t dev_addr) { msch_interface_t* p_msc = get_itf(dev_addr); return p_msc->mounted && !usbh_edpt_busy(dev_addr, p_msc->ep_in) && !usbh_edpt_busy(dev_addr, p_msc->ep_out); } @@ -127,20 +119,20 @@ bool tuh_msc_ready(uint8_t dev_addr) //--------------------------------------------------------------------+ // PUBLIC API: SCSI COMMAND //--------------------------------------------------------------------+ -static inline void cbw_init(msc_cbw_t *cbw, uint8_t lun) -{ +static inline void cbw_init(msc_cbw_t* cbw, uint8_t lun) { tu_memclr(cbw, sizeof(msc_cbw_t)); cbw->signature = MSC_CBW_SIGNATURE; cbw->tag = 0x54555342; // TUSB cbw->lun = lun; } -bool tuh_msc_scsi_command(uint8_t dev_addr, msc_cbw_t const* cbw, void* data, tuh_msc_complete_cb_t complete_cb, uintptr_t arg) -{ - msch_interface_t* p_msc = get_itf(dev_addr); +bool tuh_msc_scsi_command(uint8_t daddr, msc_cbw_t const* cbw, void* data, + tuh_msc_complete_cb_t complete_cb, uintptr_t arg) { + msch_interface_t* p_msc = get_itf(daddr); TU_VERIFY(p_msc->configured); - // TODO claim endpoint + // claim endpoint + TU_VERIFY(usbh_edpt_claim(daddr, p_msc->ep_out)); p_msc->cbw = *cbw; p_msc->stage = MSC_STAGE_CMD; @@ -148,15 +140,18 @@ bool tuh_msc_scsi_command(uint8_t dev_addr, msc_cbw_t const* cbw, void* data, tu p_msc->complete_cb = complete_cb; p_msc->complete_arg = arg; - TU_ASSERT(usbh_edpt_xfer(dev_addr, p_msc->ep_out, (uint8_t*) &p_msc->cbw, sizeof(msc_cbw_t))); + if (!usbh_edpt_xfer(daddr, p_msc->ep_out, (uint8_t*) &p_msc->cbw, sizeof(msc_cbw_t))) { + usbh_edpt_release(daddr, p_msc->ep_out); + return false; + } return true; } -bool tuh_msc_read_capacity(uint8_t dev_addr, uint8_t lun, scsi_read_capacity10_resp_t* response, tuh_msc_complete_cb_t complete_cb, uintptr_t arg) -{ - msch_interface_t* p_msc = get_itf(dev_addr); - TU_VERIFY(p_msc->configured); +bool tuh_msc_read_capacity(uint8_t dev_addr, uint8_t lun, scsi_read_capacity10_resp_t* response, + tuh_msc_complete_cb_t complete_cb, uintptr_t arg) { + msch_interface_t* p_msc = get_itf(dev_addr); + TU_VERIFY(p_msc->configured); msc_cbw_t cbw; cbw_init(&cbw, lun); @@ -169,8 +164,8 @@ bool tuh_msc_read_capacity(uint8_t dev_addr, uint8_t lun, scsi_read_capacity10_r return tuh_msc_scsi_command(dev_addr, &cbw, response, complete_cb, arg); } -bool tuh_msc_inquiry(uint8_t dev_addr, uint8_t lun, scsi_inquiry_resp_t* response, tuh_msc_complete_cb_t complete_cb, uintptr_t arg) -{ +bool tuh_msc_inquiry(uint8_t dev_addr, uint8_t lun, scsi_inquiry_resp_t* response, + tuh_msc_complete_cb_t complete_cb, uintptr_t arg) { msch_interface_t* p_msc = get_itf(dev_addr); TU_VERIFY(p_msc->mounted); @@ -181,18 +176,16 @@ bool tuh_msc_inquiry(uint8_t dev_addr, uint8_t lun, scsi_inquiry_resp_t* respons cbw.dir = TUSB_DIR_IN_MASK; cbw.cmd_len = sizeof(scsi_inquiry_t); - scsi_inquiry_t const cmd_inquiry = - { - .cmd_code = SCSI_CMD_INQUIRY, - .alloc_length = sizeof(scsi_inquiry_resp_t) + scsi_inquiry_t const cmd_inquiry = { + .cmd_code = SCSI_CMD_INQUIRY, + .alloc_length = sizeof(scsi_inquiry_resp_t) }; memcpy(cbw.command, &cmd_inquiry, cbw.cmd_len); return tuh_msc_scsi_command(dev_addr, &cbw, response, complete_cb, arg); } -bool tuh_msc_test_unit_ready(uint8_t dev_addr, uint8_t lun, tuh_msc_complete_cb_t complete_cb, uintptr_t arg) -{ +bool tuh_msc_test_unit_ready(uint8_t dev_addr, uint8_t lun, tuh_msc_complete_cb_t complete_cb, uintptr_t arg) { msch_interface_t* p_msc = get_itf(dev_addr); TU_VERIFY(p_msc->configured); @@ -200,16 +193,16 @@ bool tuh_msc_test_unit_ready(uint8_t dev_addr, uint8_t lun, tuh_msc_complete_cb_ cbw_init(&cbw, lun); cbw.total_bytes = 0; - cbw.dir = TUSB_DIR_OUT; - cbw.cmd_len = sizeof(scsi_test_unit_ready_t); - cbw.command[0] = SCSI_CMD_TEST_UNIT_READY; - cbw.command[1] = lun; // according to wiki TODO need verification + cbw.dir = TUSB_DIR_OUT; + cbw.cmd_len = sizeof(scsi_test_unit_ready_t); + cbw.command[0] = SCSI_CMD_TEST_UNIT_READY; + cbw.command[1] = lun; // according to wiki TODO need verification return tuh_msc_scsi_command(dev_addr, &cbw, NULL, complete_cb, arg); } -bool tuh_msc_request_sense(uint8_t dev_addr, uint8_t lun, void *response, tuh_msc_complete_cb_t complete_cb, uintptr_t arg) -{ +bool tuh_msc_request_sense(uint8_t dev_addr, uint8_t lun, void* response, + tuh_msc_complete_cb_t complete_cb, uintptr_t arg) { msc_cbw_t cbw; cbw_init(&cbw, lun); @@ -217,73 +210,64 @@ bool tuh_msc_request_sense(uint8_t dev_addr, uint8_t lun, void *response, tuh_ms cbw.dir = TUSB_DIR_IN_MASK; cbw.cmd_len = sizeof(scsi_request_sense_t); - scsi_request_sense_t const cmd_request_sense = - { - .cmd_code = SCSI_CMD_REQUEST_SENSE, - .alloc_length = 18 + scsi_request_sense_t const cmd_request_sense = { + .cmd_code = SCSI_CMD_REQUEST_SENSE, + .alloc_length = 18 }; - memcpy(cbw.command, &cmd_request_sense, cbw.cmd_len); return tuh_msc_scsi_command(dev_addr, &cbw, response, complete_cb, arg); } -bool tuh_msc_read10(uint8_t dev_addr, uint8_t lun, void * buffer, uint32_t lba, uint16_t block_count, tuh_msc_complete_cb_t complete_cb, uintptr_t arg) -{ +bool tuh_msc_read10(uint8_t dev_addr, uint8_t lun, void* buffer, uint32_t lba, uint16_t block_count, + tuh_msc_complete_cb_t complete_cb, uintptr_t arg) { msch_interface_t* p_msc = get_itf(dev_addr); TU_VERIFY(p_msc->mounted); msc_cbw_t cbw; cbw_init(&cbw, lun); - cbw.total_bytes = block_count*p_msc->capacity[lun].block_size; - cbw.dir = TUSB_DIR_IN_MASK; - cbw.cmd_len = sizeof(scsi_read10_t); + cbw.total_bytes = block_count * p_msc->capacity[lun].block_size; + cbw.dir = TUSB_DIR_IN_MASK; + cbw.cmd_len = sizeof(scsi_read10_t); - scsi_read10_t const cmd_read10 = - { - .cmd_code = SCSI_CMD_READ_10, - .lba = tu_htonl(lba), - .block_count = tu_htons(block_count) + scsi_read10_t const cmd_read10 = { + .cmd_code = SCSI_CMD_READ_10, + .lba = tu_htonl(lba), + .block_count = tu_htons(block_count) }; - memcpy(cbw.command, &cmd_read10, cbw.cmd_len); return tuh_msc_scsi_command(dev_addr, &cbw, buffer, complete_cb, arg); } -bool tuh_msc_write10(uint8_t dev_addr, uint8_t lun, void const * buffer, uint32_t lba, uint16_t block_count, tuh_msc_complete_cb_t complete_cb, uintptr_t arg) -{ +bool tuh_msc_write10(uint8_t dev_addr, uint8_t lun, void const* buffer, uint32_t lba, uint16_t block_count, + tuh_msc_complete_cb_t complete_cb, uintptr_t arg) { msch_interface_t* p_msc = get_itf(dev_addr); TU_VERIFY(p_msc->mounted); msc_cbw_t cbw; cbw_init(&cbw, lun); - cbw.total_bytes = block_count*p_msc->capacity[lun].block_size; + cbw.total_bytes = block_count * p_msc->capacity[lun].block_size; cbw.dir = TUSB_DIR_OUT; cbw.cmd_len = sizeof(scsi_write10_t); - scsi_write10_t const cmd_write10 = - { - .cmd_code = SCSI_CMD_WRITE_10, - .lba = tu_htonl(lba), - .block_count = tu_htons(block_count) + scsi_write10_t const cmd_write10 = { + .cmd_code = SCSI_CMD_WRITE_10, + .lba = tu_htonl(lba), + .block_count = tu_htons(block_count) }; - memcpy(cbw.command, &cmd_write10, cbw.cmd_len); - return tuh_msc_scsi_command(dev_addr, &cbw, (void*)(uintptr_t) buffer, complete_cb, arg); + return tuh_msc_scsi_command(dev_addr, &cbw, (void*) (uintptr_t) buffer, complete_cb, arg); } #if 0 // MSC interface Reset (not used now) -bool tuh_msc_reset(uint8_t dev_addr) -{ - tusb_control_request_t const new_request = - { - .bmRequestType_bit = - { +bool tuh_msc_reset(uint8_t dev_addr) { + tusb_control_request_t const new_request = { + .bmRequestType_bit = { .recipient = TUSB_REQ_RCPT_INTERFACE, .type = TUSB_REQ_TYPE_CLASS, .direction = TUSB_DIR_OUT @@ -300,79 +284,71 @@ bool tuh_msc_reset(uint8_t dev_addr) //--------------------------------------------------------------------+ // CLASS-USBH API //--------------------------------------------------------------------+ -void msch_init(void) -{ +void msch_init(void) { tu_memclr(_msch_itf, sizeof(_msch_itf)); } -void msch_close(uint8_t dev_addr) -{ - TU_VERIFY(dev_addr <= CFG_TUH_DEVICE_MAX, ); +void msch_close(uint8_t dev_addr) { + TU_VERIFY(dev_addr <= CFG_TUH_DEVICE_MAX,); msch_interface_t* p_msc = get_itf(dev_addr); - TU_VERIFY(p_msc->configured, ); + TU_VERIFY(p_msc->configured,); TU_LOG_DRV(" MSCh close addr = %d\r\n", dev_addr); // invoke Application Callback if (p_msc->mounted) { - if(tuh_msc_umount_cb) tuh_msc_umount_cb(dev_addr); + if (tuh_msc_umount_cb) tuh_msc_umount_cb(dev_addr); } tu_memclr(p_msc, sizeof(msch_interface_t)); } -bool msch_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes) -{ +bool msch_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes) { msch_interface_t* p_msc = get_itf(dev_addr); msc_cbw_t const * cbw = &p_msc->cbw; msc_csw_t * csw = &p_msc->csw; - switch (p_msc->stage) - { + switch (p_msc->stage) { case MSC_STAGE_CMD: // Must be Command Block - TU_ASSERT(ep_addr == p_msc->ep_out && event == XFER_RESULT_SUCCESS && xferred_bytes == sizeof(msc_cbw_t)); + TU_ASSERT(ep_addr == p_msc->ep_out && event == XFER_RESULT_SUCCESS && xferred_bytes == sizeof(msc_cbw_t)); - if ( cbw->total_bytes && p_msc->buffer ) - { + if (cbw->total_bytes && p_msc->buffer) { // Data stage if any p_msc->stage = MSC_STAGE_DATA; - uint8_t const ep_data = (cbw->dir & TUSB_DIR_IN_MASK) ? p_msc->ep_in : p_msc->ep_out; TU_ASSERT(usbh_edpt_xfer(dev_addr, ep_data, p_msc->buffer, (uint16_t) cbw->total_bytes)); - }else - { + } else { // Status stage p_msc->stage = MSC_STAGE_STATUS; TU_ASSERT(usbh_edpt_xfer(dev_addr, p_msc->ep_in, (uint8_t*) &p_msc->csw, (uint16_t) sizeof(msc_csw_t))); } - break; + break; case MSC_STAGE_DATA: // Status stage p_msc->stage = MSC_STAGE_STATUS; TU_ASSERT(usbh_edpt_xfer(dev_addr, p_msc->ep_in, (uint8_t*) &p_msc->csw, (uint16_t) sizeof(msc_csw_t))); - break; + break; case MSC_STAGE_STATUS: // SCSI op is complete p_msc->stage = MSC_STAGE_IDLE; - if (p_msc->complete_cb) - { - tuh_msc_complete_data_t const cb_data = - { - .cbw = cbw, - .csw = csw, - .scsi_data = p_msc->buffer, - .user_arg = p_msc->complete_arg + if (p_msc->complete_cb) { + tuh_msc_complete_data_t const cb_data = { + .cbw = cbw, + .csw = csw, + .scsi_data = p_msc->buffer, + .user_arg = p_msc->complete_arg }; p_msc->complete_cb(dev_addr, &cb_data); } - break; + break; - // unknown state - default: break; + // unknown state + default: + break; } return true; @@ -381,39 +357,35 @@ bool msch_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, uint32 //--------------------------------------------------------------------+ // MSC Enumeration //--------------------------------------------------------------------+ - -static void config_get_maxlun_complete (tuh_xfer_t* xfer); -static bool config_test_unit_ready_complete(uint8_t dev_addr, tuh_msc_complete_data_t const * cb_data); +static void config_get_maxlun_complete(tuh_xfer_t* xfer); +static bool config_test_unit_ready_complete(uint8_t dev_addr, tuh_msc_complete_data_t const* cb_data); static bool config_request_sense_complete(uint8_t dev_addr, tuh_msc_complete_data_t const* cb_data); static bool config_read_capacity_complete(uint8_t dev_addr, tuh_msc_complete_data_t const* cb_data); -bool msch_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *desc_itf, uint16_t max_len) -{ +bool msch_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const* desc_itf, uint16_t max_len) { (void) rhport; TU_VERIFY (MSC_SUBCLASS_SCSI == desc_itf->bInterfaceSubClass && - MSC_PROTOCOL_BOT == desc_itf->bInterfaceProtocol); + MSC_PROTOCOL_BOT == desc_itf->bInterfaceProtocol); // msc driver length is fixed - uint16_t const drv_len = (uint16_t) (sizeof(tusb_desc_interface_t) + desc_itf->bNumEndpoints * sizeof(tusb_desc_endpoint_t)); + uint16_t const drv_len = (uint16_t) (sizeof(tusb_desc_interface_t) + + desc_itf->bNumEndpoints * sizeof(tusb_desc_endpoint_t)); TU_ASSERT(drv_len <= max_len); msch_interface_t* p_msc = get_itf(dev_addr); - tusb_desc_endpoint_t const * ep_desc = (tusb_desc_endpoint_t const *) tu_desc_next(desc_itf); + tusb_desc_endpoint_t const* ep_desc = (tusb_desc_endpoint_t const*) tu_desc_next(desc_itf); - for(uint32_t i=0; i<2; i++) - { + for (uint32_t i = 0; i < 2; i++) { TU_ASSERT(TUSB_DESC_ENDPOINT == ep_desc->bDescriptorType && TUSB_XFER_BULK == ep_desc->bmAttributes.xfer); TU_ASSERT(tuh_edpt_open(dev_addr, ep_desc)); - if ( tu_edpt_dir(ep_desc->bEndpointAddress) == TUSB_DIR_IN ) - { + if (TUSB_DIR_IN == tu_edpt_dir(ep_desc->bEndpointAddress)) { p_msc->ep_in = ep_desc->bEndpointAddress; - }else - { + } else { p_msc->ep_out = ep_desc->bEndpointAddress; } - ep_desc = (tusb_desc_endpoint_t const *) tu_desc_next(ep_desc); + ep_desc = (tusb_desc_endpoint_t const*) tu_desc_next(ep_desc); } p_msc->itf_num = desc_itf->bInterfaceNumber; @@ -430,32 +402,31 @@ bool msch_set_config(uint8_t dev_addr, uint8_t itf_num) { //------------- Get Max Lun -------------// TU_LOG_DRV("MSC Get Max Lun\r\n"); tusb_control_request_t const request = { - .bmRequestType_bit = { - .recipient = TUSB_REQ_RCPT_INTERFACE, - .type = TUSB_REQ_TYPE_CLASS, - .direction = TUSB_DIR_IN - }, - .bRequest = MSC_REQ_GET_MAX_LUN, - .wValue = 0, - .wIndex = itf_num, - .wLength = 1 + .bmRequestType_bit = { + .recipient = TUSB_REQ_RCPT_INTERFACE, + .type = TUSB_REQ_TYPE_CLASS, + .direction = TUSB_DIR_IN + }, + .bRequest = MSC_REQ_GET_MAX_LUN, + .wValue = 0, + .wIndex = itf_num, + .wLength = 1 }; tuh_xfer_t xfer = { - .daddr = dev_addr, - .ep_addr = 0, - .setup = &request, - .buffer = _msch_buffer, - .complete_cb = config_get_maxlun_complete, - .user_data = 0 + .daddr = dev_addr, + .ep_addr = 0, + .setup = &request, + .buffer = _msch_buffer, + .complete_cb = config_get_maxlun_complete, + .user_data = 0 }; TU_ASSERT(tuh_control_xfer(&xfer)); return true; } -static void config_get_maxlun_complete (tuh_xfer_t* xfer) -{ +static void config_get_maxlun_complete(tuh_xfer_t* xfer) { uint8_t const daddr = xfer->daddr; msch_interface_t* p_msc = get_itf(daddr); @@ -471,18 +442,16 @@ static void config_get_maxlun_complete (tuh_xfer_t* xfer) tuh_msc_test_unit_ready(daddr, lun, config_test_unit_ready_complete, 0); } -static bool config_test_unit_ready_complete(uint8_t dev_addr, tuh_msc_complete_data_t const * cb_data) -{ +static bool config_test_unit_ready_complete(uint8_t dev_addr, tuh_msc_complete_data_t const* cb_data) { msc_cbw_t const* cbw = cb_data->cbw; msc_csw_t const* csw = cb_data->csw; - if (csw->status == 0) - { + if (csw->status == 0) { // Unit is ready, read its capacity TU_LOG_DRV("SCSI Read Capacity\r\n"); - tuh_msc_read_capacity(dev_addr, cbw->lun, (scsi_read_capacity10_resp_t*) ((void*) _msch_buffer), config_read_capacity_complete, 0); - }else - { + tuh_msc_read_capacity(dev_addr, cbw->lun, (scsi_read_capacity10_resp_t*) ((void*) _msch_buffer), + config_read_capacity_complete, 0); + } else { // Note: During enumeration, some device fails Test Unit Ready and require a few retries // with Request Sense to start working !! // TODO limit number of retries @@ -493,8 +462,7 @@ static bool config_test_unit_ready_complete(uint8_t dev_addr, tuh_msc_complete_d return true; } -static bool config_request_sense_complete(uint8_t dev_addr, tuh_msc_complete_data_t const * cb_data) -{ +static bool config_request_sense_complete(uint8_t dev_addr, tuh_msc_complete_data_t const* cb_data) { msc_cbw_t const* cbw = cb_data->cbw; msc_csw_t const* csw = cb_data->csw; @@ -503,8 +471,7 @@ static bool config_request_sense_complete(uint8_t dev_addr, tuh_msc_complete_dat return true; } -static bool config_read_capacity_complete(uint8_t dev_addr, tuh_msc_complete_data_t const * cb_data) -{ +static bool config_read_capacity_complete(uint8_t dev_addr, tuh_msc_complete_data_t const* cb_data) { msc_cbw_t const* cbw = cb_data->cbw; msc_csw_t const* csw = cb_data->csw; diff --git a/src/class/msc/msc_host.h b/src/class/msc/msc_host.h index 6c0e5c9dd..9ca1b4703 100644 --- a/src/class/msc/msc_host.h +++ b/src/class/msc/msc_host.h @@ -24,8 +24,8 @@ * This file is part of the TinyUSB stack. */ -#ifndef _TUSB_MSC_HOST_H_ -#define _TUSB_MSC_HOST_H_ +#ifndef TUSB_MSC_HOST_H_ +#define TUSB_MSC_HOST_H_ #include "msc.h" @@ -73,7 +73,7 @@ uint32_t tuh_msc_get_block_size(uint8_t dev_addr, uint8_t lun); // Perform a full SCSI command (cbw, data, csw) in non-blocking manner. // Complete callback is invoked when SCSI op is complete. // return true if success, false if there is already pending operation. -bool tuh_msc_scsi_command(uint8_t dev_addr, msc_cbw_t const* cbw, void* data, tuh_msc_complete_cb_t complete_cb, uintptr_t arg); +bool tuh_msc_scsi_command(uint8_t daddr, msc_cbw_t const* cbw, void* data, tuh_msc_complete_cb_t complete_cb, uintptr_t arg); // Perform SCSI Inquiry command // Complete callback is invoked when SCSI op is complete. @@ -123,4 +123,4 @@ bool msch_xfer_cb (uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, ui } #endif -#endif /* _TUSB_MSC_HOST_H_ */ +#endif diff --git a/src/host/usbh.c b/src/host/usbh.c index e332f35cc..8d75c9726 100644 --- a/src/host/usbh.c +++ b/src/host/usbh.c @@ -817,6 +817,7 @@ bool usbh_edpt_release(uint8_t dev_addr, uint8_t ep_addr) } // Submit an transfer +// TODO call usbh_edpt_release if failed bool usbh_edpt_xfer_with_callback(uint8_t dev_addr, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { @@ -1713,19 +1714,16 @@ static bool _parse_configuration_descriptor(uint8_t dev_addr, tusb_desc_configur return true; } -void usbh_driver_set_config_complete(uint8_t dev_addr, uint8_t itf_num) -{ +void usbh_driver_set_config_complete(uint8_t dev_addr, uint8_t itf_num) { usbh_device_t* dev = get_device(dev_addr); - for(itf_num++; itf_num < CFG_TUH_INTERFACE_MAX; itf_num++) - { + for(itf_num++; itf_num < CFG_TUH_INTERFACE_MAX; itf_num++) { // continue with next valid interface // IAD binding interface such as CDCs should return itf_num + 1 when complete // with usbh_driver_set_config_complete() uint8_t const drv_id = dev->itf2drv[itf_num]; usbh_class_driver_t const * driver = get_driver(drv_id); - if (driver) - { + if (driver) { TU_LOG_USBH("%s set config: itf = %u\r\n", driver->name, itf_num); driver->set_config(dev_addr, itf_num); break; @@ -1733,23 +1731,19 @@ void usbh_driver_set_config_complete(uint8_t dev_addr, uint8_t itf_num) } // all interface are configured - if (itf_num == CFG_TUH_INTERFACE_MAX) - { + if (itf_num == CFG_TUH_INTERFACE_MAX) { enum_full_complete(); - if (is_hub_addr(dev_addr)) - { + if (is_hub_addr(dev_addr)) { TU_LOG(CFG_TUH_LOG_LEVEL, "HUB address = %u is mounted\r\n", dev_addr); - }else - { + }else { // Invoke callback if available if (tuh_mount_cb) tuh_mount_cb(dev_addr); } } } -static void enum_full_complete(void) -{ +static void enum_full_complete(void) { // mark enumeration as complete _dev0.enumerating = 0; -- cgit v1.3.1 From 8b2cb63da88c0f790fee8d514971153569993b05 Mon Sep 17 00:00:00 2001 From: HiFiPhile Date: Tue, 10 Oct 2023 18:22:20 +0200 Subject: Fix naming nBytesPerSample. --- src/class/audio/audio_device.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) (limited to 'src/class') diff --git a/src/class/audio/audio_device.c b/src/class/audio/audio_device.c index 46fd6dfa9..5d3772a9d 100644 --- a/src/class/audio/audio_device.c +++ b/src/class/audio/audio_device.c @@ -631,9 +631,9 @@ static bool audiod_rx_done_cb(uint8_t rhport, audiod_function_t* audio, uint16_t // Decoding according to 2.3.1.5 Audio Streams // Helper function -static inline void * audiod_interleaved_copy_bytes_fast_decode(uint16_t const nBytesToCopy, void * dst, const void * dst_end, void * src, uint8_t const n_ff_used) +static inline void * audiod_interleaved_copy_bytes_fast_decode(uint16_t const nBytesPerSample, void * dst, const void * dst_end, void * src, uint8_t const n_ff_used) { - // Due to one FIFO contains 2 channels, data always aligned to (nBytesToCopy * 2) + // Due to one FIFO contains 2 channels, data always aligned to (nBytesPerSample * 2) uint16_t * dst16 = dst; uint16_t * src16 = src; const uint16_t * dst_end16 = dst_end; @@ -641,7 +641,7 @@ static inline void * audiod_interleaved_copy_bytes_fast_decode(uint16_t const nB uint32_t * src32 = src; const uint32_t * dst_end32 = dst_end; - if (nBytesToCopy == 1) + if (nBytesPerSample == 1) { while(dst16 < dst_end16) { @@ -650,7 +650,7 @@ static inline void * audiod_interleaved_copy_bytes_fast_decode(uint16_t const nB } return src16; } - else if (nBytesToCopy == 2) + else if (nBytesPerSample == 2) { while(dst32 < dst_end32) { @@ -659,7 +659,7 @@ static inline void * audiod_interleaved_copy_bytes_fast_decode(uint16_t const nB } return src32; } - else if (nBytesToCopy == 3) + else if (nBytesPerSample == 3) { while(dst16 < dst_end16) { @@ -670,7 +670,7 @@ static inline void * audiod_interleaved_copy_bytes_fast_decode(uint16_t const nB } return src16; } - else // nBytesToCopy == 4 + else // nBytesPerSample == 4 { while(dst32 < dst_end32) { @@ -926,9 +926,9 @@ range [-1, +1) * */ // Helper function -static inline void * audiod_interleaved_copy_bytes_fast_encode(uint16_t const nBytesToCopy, void * src, const void * src_end, void * dst, uint8_t const n_ff_used) +static inline void * audiod_interleaved_copy_bytes_fast_encode(uint16_t const nBytesPerSample, void * src, const void * src_end, void * dst, uint8_t const n_ff_used) { - // Due to one FIFO contains 2 channels, data always aligned to (nBytesToCopy * 2) + // Due to one FIFO contains 2 channels, data always aligned to (nBytesPerSample * 2) uint16_t * dst16 = dst; uint16_t * src16 = src; const uint16_t * src_end16 = src_end; @@ -936,7 +936,7 @@ static inline void * audiod_interleaved_copy_bytes_fast_encode(uint16_t const nB uint32_t * src32 = src; const uint32_t * src_end32 = src_end; - if (nBytesToCopy == 1) + if (nBytesPerSample == 1) { while(src16 < src_end16) { @@ -945,7 +945,7 @@ static inline void * audiod_interleaved_copy_bytes_fast_encode(uint16_t const nB } return dst16; } - else if (nBytesToCopy == 2) + else if (nBytesPerSample == 2) { while(src32 < src_end32) { @@ -954,7 +954,7 @@ static inline void * audiod_interleaved_copy_bytes_fast_encode(uint16_t const nB } return dst32; } - else if (nBytesToCopy == 3) + else if (nBytesPerSample == 3) { while(src16 < src_end16) { @@ -965,7 +965,7 @@ static inline void * audiod_interleaved_copy_bytes_fast_encode(uint16_t const nB } return dst16; } - else // nBytesToCopy == 4 + else // nBytesPerSample == 4 { while(src32 < src_end32) { -- cgit v1.3.1 From 656e1e416aa9dbd7ba4c18e777f7294a101f0667 Mon Sep 17 00:00:00 2001 From: HiFiPhile Date: Tue, 17 Oct 2023 09:46:01 +0200 Subject: Add flow control for IN transfer. --- examples/device/audio_4_channel_mic/src/main.c | 30 ++++- .../audio_4_channel_mic/src/plot_audio_samples.py | 7 +- .../device/audio_4_channel_mic/src/tusb_config.h | 15 ++- src/class/audio/audio_device.c | 140 ++++++++++++++++++--- src/class/audio/audio_device.h | 16 +++ 5 files changed, 187 insertions(+), 21 deletions(-) (limited to 'src/class') diff --git a/examples/device/audio_4_channel_mic/src/main.c b/examples/device/audio_4_channel_mic/src/main.c index 4bcbdb692..52e6d71f7 100644 --- a/examples/device/audio_4_channel_mic/src/main.c +++ b/examples/device/audio_4_channel_mic/src/main.c @@ -69,8 +69,13 @@ uint8_t clkValid; audio_control_range_2_n_t(1) volumeRng[CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX+1]; // Volume range state audio_control_range_4_n_t(1) sampleFreqRng; // Sample frequency range state +#if CFG_TUD_AUDIO_ENABLE_ENCODING // Audio test data, each buffer contains 2 channels, buffer[0] for CH0-1, buffer[1] for CH1-2 uint16_t i2s_dummy_buffer[CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_1_TX_SUPP_SW_FIFO_SZ/2]; // Ensure half word aligned +#else +// Audio test data, 4 channels muxed together, buffer[0] for CH0, buffer[1] for CH1, buffer[2] for CH2, buffer[3] for CH3 +uint16_t i2s_dummy_buffer[CFG_TUD_AUDIO_EP_SZ_IN]; // Ensure half word aligned +#endif void led_blinking_task(void); void audio_task(void); @@ -97,6 +102,7 @@ int main(void) sampleFreqRng.subrange[0].bRes = 0; // Generate dummy data +#if CFG_TUD_AUDIO_ENABLE_ENCODING uint16_t * p_buff = i2s_dummy_buffer[0]; uint16_t dataVal = 1; for (uint16_t cnt = 0; cnt < AUDIO_SAMPLE_RATE/1000; cnt++) @@ -116,6 +122,23 @@ int main(void) float t = 2*3.1415f * cnt / (AUDIO_SAMPLE_RATE/1000); *p_buff++ = (uint16_t)(sinf(t) * 25) + 200; } +#else + uint16_t * p_buff = i2s_dummy_buffer; + uint16_t dataVal = 1; + for (uint16_t cnt = 0; cnt < AUDIO_SAMPLE_RATE/1000; cnt++) + { + // CH0 saw wave + *p_buff++ = dataVal; + // CH1 inverted saw wave + *p_buff++ = 60 + AUDIO_SAMPLE_RATE/1000 - dataVal; + dataVal++; + // CH3 square wave + *p_buff++ = cnt < (AUDIO_SAMPLE_RATE/1000/2) ? 120:170; + // CH4 sinus wave + float t = 2*3.1415f * cnt / (AUDIO_SAMPLE_RATE/1000); + *p_buff++ = (uint16_t)(sinf(t) * 25) + 200; + } +#endif while (1) { @@ -384,6 +407,8 @@ bool tud_audio_get_req_entity_cb(uint8_t rhport, tusb_control_request_t const * { case AUDIO_CS_REQ_CUR: TU_LOG2(" Get Sample Freq.\r\n"); + // Set sample rate for flow control + tud_audio_set_tx_flow_control(sampFreq); return tud_control_xfer(rhport, p_request, &sampFreq, sizeof(sampFreq)); case AUDIO_CS_REQ_RANGE: @@ -429,12 +454,15 @@ bool tud_audio_tx_done_pre_load_cb(uint8_t rhport, uint8_t itf, uint8_t ep_in, u // tud_audio_write_support_ff(channel, data, samples * N_BYTES_PER_SAMPLE * N_CHANNEL_PER_FIFO); // } +#if CFG_TUD_AUDIO_ENABLE_ENCODING // Write I2S buffer into FIFO for (uint8_t cnt=0; cnt < 2; cnt++) { tud_audio_write_support_ff(cnt, i2s_dummy_buffer[cnt], AUDIO_SAMPLE_RATE/1000 * CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_TX * CFG_TUD_AUDIO_FUNC_1_CHANNEL_PER_FIFO_TX); } - +#else + tud_audio_write(i2s_dummy_buffer, AUDIO_SAMPLE_RATE/1000 * CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_TX * CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX); +#endif return true; } diff --git a/examples/device/audio_4_channel_mic/src/plot_audio_samples.py b/examples/device/audio_4_channel_mic/src/plot_audio_samples.py index a3a2b2fd4..d17a908b6 100644 --- a/examples/device/audio_4_channel_mic/src/plot_audio_samples.py +++ b/examples/device/audio_4_channel_mic/src/plot_audio_samples.py @@ -10,11 +10,11 @@ if __name__ == '__main__': # print(sd.query_devices()) fs = 48000 # Sample rate - duration = 20e-3 # Duration of recording + duration = 1 # Duration of recording if platform.system() == 'Windows': # WDM-KS is needed since there are more than one MicNode device APIs (at least in Windows) - device = 'Microphone (MicNode_4_Ch), Windows WDM-KS' + device = 'Microphone (MicNode_4_Ch), Windows WASAPI' elif platform.system() == 'Darwin': device = 'MicNode_4_Ch' else: @@ -28,8 +28,7 @@ if __name__ == '__main__': time = np.arange(0, duration, 1 / fs) # time vector # strip starting zero - myrecording = myrecording[100:] - time = time[100:] + plt.plot(time, myrecording) plt.xlabel('Time [s]') plt.ylabel('Amplitude') diff --git a/examples/device/audio_4_channel_mic/src/tusb_config.h b/examples/device/audio_4_channel_mic/src/tusb_config.h index 291ac4f79..d1e19c5a1 100644 --- a/examples/device/audio_4_channel_mic/src/tusb_config.h +++ b/examples/device/audio_4_channel_mic/src/tusb_config.h @@ -114,14 +114,25 @@ extern "C" { #define CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_TX 2 // This value is not required by the driver, it parses this information from the descriptor once the alternate interface is set by the host - we use it for the setup #define CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX 4 // This value is not required by the driver, it parses this information from the descriptor once the alternate interface is set by the host - we use it for the setup #define CFG_TUD_AUDIO_EP_SZ_IN TUD_AUDIO_EP_SIZE(CFG_TUD_AUDIO_FUNC_1_SAMPLE_RATE, CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_TX, CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX) + +#define CFG_TUD_AUDIO_ENABLE_ENCODING 0 + +#if CFG_TUD_AUDIO_ENABLE_ENCODING + #define CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX CFG_TUD_AUDIO_EP_SZ_IN #define CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ CFG_TUD_AUDIO_EP_SZ_IN -#define CFG_TUD_AUDIO_ENABLE_ENCODING 1 #define CFG_TUD_AUDIO_ENABLE_TYPE_I_ENCODING 1 #define CFG_TUD_AUDIO_FUNC_1_CHANNEL_PER_FIFO_TX 2 // One I2S stream contains two channels, each stream is saved within one support FIFO - this value is currently fixed, the driver does not support a changing value #define CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO (CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX / CFG_TUD_AUDIO_FUNC_1_CHANNEL_PER_FIFO_TX) -#define CFG_TUD_AUDIO_FUNC_1_TX_SUPP_SW_FIFO_SZ (CFG_TUD_AUDIO_EP_SZ_IN / CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO) +#define CFG_TUD_AUDIO_FUNC_1_TX_SUPP_SW_FIFO_SZ 4 * (CFG_TUD_AUDIO_EP_SZ_IN / CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO) + +#else + +#define CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX 4 * CFG_TUD_AUDIO_EP_SZ_IN +#define CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ 4 * CFG_TUD_AUDIO_EP_SZ_IN + +#endif #ifdef __cplusplus } diff --git a/src/class/audio/audio_device.c b/src/class/audio/audio_device.c index 5d3772a9d..9299440c9 100644 --- a/src/class/audio/audio_device.c +++ b/src/class/audio/audio_device.c @@ -364,14 +364,21 @@ typedef struct #endif #endif +#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_EP_IN_FLOW_CONTROL + uint32_t sample_rate_tx; + uint16_t packet_sz_tx[3]; + uint8_t bclock_id_tx; + uint8_t interval_tx; +#endif + // Encoding parameters - parameters are set when alternate AS interface is set by host -#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_ENCODING +#if CFG_TUD_AUDIO_ENABLE_EP_IN && (CFG_TUD_AUDIO_ENABLE_ENCODING || CFG_TUD_AUDIO_EP_IN_FLOW_CONTROL) audio_format_type_t format_type_tx; uint8_t n_channels_tx; + uint8_t n_bytes_per_sampe_tx; #if CFG_TUD_AUDIO_ENABLE_TYPE_I_ENCODING audio_data_format_type_I_t format_type_I_tx; - uint8_t n_bytes_per_sampe_tx; uint8_t n_channels_per_ff_tx; uint8_t n_ff_used_tx; #endif @@ -444,7 +451,7 @@ static bool audiod_verify_itf_exists(uint8_t itf, uint8_t *func_id); static bool audiod_verify_ep_exists(uint8_t ep, uint8_t *func_id); static uint8_t audiod_get_audio_fct_idx(audiod_function_t * audio); -#if CFG_TUD_AUDIO_ENABLE_ENCODING || CFG_TUD_AUDIO_ENABLE_DECODING +#if (CFG_TUD_AUDIO_ENABLE_EP_IN && (CFG_TUD_AUDIO_EP_IN_FLOW_CONTROL || CFG_TUD_AUDIO_ENABLE_ENCODING)) || (CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_DECODING) static void audiod_parse_for_AS_params(audiod_function_t* audio, uint8_t const * p_desc, uint8_t const * p_desc_end, uint8_t const as_itf); static inline uint8_t tu_desc_subtype(void const* desc) @@ -453,6 +460,10 @@ static inline uint8_t tu_desc_subtype(void const* desc) } #endif +#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_EP_IN_FLOW_CONTROL +static bool audiod_tx_calc_packet_size(const uint16_t* norminal_size, uint16_t data_size, uint16_t fifo_size, uint16_t* packet_size); +#endif + #if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP static bool set_fb_params_freq(audiod_function_t* audio, uint32_t sample_freq, uint32_t mclk_freq); #endif @@ -821,6 +832,57 @@ uint16_t tud_audio_int_ctr_n_write(uint8_t func_id, uint8_t const* buffer, uint1 #endif +#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_EP_IN_FLOW_CONTROL + +bool tud_audio_n_set_tx_flow_control(uint8_t func_id, uint32_t sample_rate) +{ + TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL); + audiod_function_t* audio = &_audiod_fct[func_id]; + + TU_VERIFY(audio->format_type_tx == AUDIO_FORMAT_TYPE_I); + TU_VERIFY(audio->n_channels_tx); + TU_VERIFY(audio->n_bytes_per_sampe_tx); + TU_VERIFY(audio->interval_tx); + + if (sample_rate == 0) + { + audio->packet_sz_tx[0] = 0; + audio->packet_sz_tx[1] = 0; + audio->packet_sz_tx[2] = 0; + return false; + } + + const uint8_t interval = (tud_speed_get() == TUSB_SPEED_FULL) ? audio->interval_tx : 1 << (audio->interval_tx - 1); + + const uint32_t sample_normimal = sample_rate * interval / ((tud_speed_get() == TUSB_SPEED_FULL) ? 1000 : 8000); + const uint32_t sample_reminder = sample_rate * interval % ((tud_speed_get() == TUSB_SPEED_FULL) ? 1000 : 8000); + + const uint16_t packet_sz_tx_min = (sample_normimal - 1) * audio->n_channels_tx * audio->n_bytes_per_sampe_tx; + const uint16_t packet_sz_tx_norm = sample_normimal * audio->n_channels_tx * audio->n_bytes_per_sampe_tx; + const uint16_t packet_sz_tx_max = (sample_normimal + 1) * audio->n_channels_tx * audio->n_bytes_per_sampe_tx; + + TU_ASSERT(packet_sz_tx_max <= audio->ep_in_sz); + + // Frmt20.pdf 2.3.1.1 USB Packets + if (sample_reminder) + { + // All virtual frame packets must either contain INT(nav) audio slots (small VFP) or INT(nav)+1 (large VFP) audio slots + audio->packet_sz_tx[0] = packet_sz_tx_norm; + audio->packet_sz_tx[1] = packet_sz_tx_norm; + audio->packet_sz_tx[2] = packet_sz_tx_max; + } else + { + // In the case where nav = INT(nav), ni may vary between INT(nav)-1 (small VFP), INT(nav) + // (medium VFP) and INT(nav)+1 (large VFP). + audio->packet_sz_tx[0] = packet_sz_tx_min; + audio->packet_sz_tx[1] = packet_sz_tx_norm; + audio->packet_sz_tx[2] = packet_sz_tx_max; + } + + 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. // If you prefer your own (more efficient) implementation suiting your purpose set CFG_TUD_AUDIO_ENABLE_ENCODING = 0 and use tud_audio_n_write. @@ -886,9 +948,16 @@ static bool audiod_tx_done_cb(uint8_t rhport, audiod_function_t * audio) #else // No support FIFOs, if no linear buffer required schedule transmit, else put data into linear buffer and schedule - +#if CFG_TUD_AUDIO_EP_IN_FLOW_CONTROL + uint16_t tgt_packet_sz; + // packet_sz_tx is based on total packet size, here we want size for each support buffer. + if (audiod_tx_calc_packet_size(audio->packet_sz_tx, tu_fifo_count(&audio->ep_in_ff), audio->ep_in_ff.depth, &tgt_packet_sz)) + n_bytes_tx = tgt_packet_sz; + else + n_bytes_tx = tu_min16(tu_fifo_count(&audio->ep_in_ff), audio->ep_in_sz); +#else n_bytes_tx = tu_min16(tu_fifo_count(&audio->ep_in_ff), audio->ep_in_sz); // Limit up to max packet size, more can not be done for ISO - +#endif #if USE_LINEAR_BUFFER_TX tu_fifo_read_n(&audio->ep_in_ff, audio->lin_buf_in, n_bytes_tx); TU_VERIFY(usbd_edpt_xfer(rhport, audio->ep_in, audio->lin_buf_in, n_bytes_tx)); @@ -987,7 +1056,6 @@ static uint16_t audiod_encode_type_I_pcm(uint8_t rhport, audiod_function_t* audi // Determine amount of samples uint8_t const n_ff_used = audio->n_ff_used_tx; - uint16_t const nBytesToCopy = audio->n_channels_per_ff_tx * audio->n_bytes_per_sampe_tx; uint16_t const capPerFF = audio->ep_in_sz / n_ff_used; // Sample capacity per FIFO in bytes uint16_t nBytesPerFFToSend = tu_fifo_count(&audio->tx_supp_ff[0]); uint8_t cnt_ff; @@ -1001,14 +1069,24 @@ static uint16_t audiod_encode_type_I_pcm(uint8_t rhport, audiod_function_t* audi } } - // Check if there is enough +#if CFG_TUD_AUDIO_EP_IN_FLOW_CONTROL + uint16_t tgt_packet_sz; + // packet_sz_tx is based on total packet size, here we want size for each support buffer. + if (audiod_tx_calc_packet_size(audio->packet_sz_tx, nBytesPerFFToSend * n_ff_used, audio->tx_supp_ff[0].depth * n_ff_used, &tgt_packet_sz)) + nBytesPerFFToSend = tgt_packet_sz / n_ff_used; +#endif + + // Check if there is enough data if (nBytesPerFFToSend == 0) return 0; // Limit to maximum sample number - THIS IS A POSSIBLE ERROR SOURCE IF TOO MANY SAMPLE WOULD NEED TO BE SENT BUT CAN NOT! nBytesPerFFToSend = tu_min16(nBytesPerFFToSend, capPerFF); +#if !CFG_TUD_AUDIO_EP_IN_FLOW_CONTROL // Round to full number of samples (flooring) - nBytesPerFFToSend = (nBytesPerFFToSend / nBytesToCopy) * nBytesToCopy; + uint16_t const nSlotSize = audio->n_channels_per_ff_tx * audio->n_bytes_per_sampe_tx; + nBytesPerFFToSend = (nBytesPerFFToSend / nSlotSize) * nSlotSize; +#endif // Encode uint8_t * dst; @@ -1489,6 +1567,9 @@ uint16_t audiod_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uin #if CFG_TUD_AUDIO_ENABLE_EP_IN ep_in = desc_ep->bEndpointAddress; ep_in_size = TU_MAX(tu_edpt_packet_size(desc_ep), ep_in_size); + #if CFG_TUD_AUDIO_EP_IN_FLOW_CONTROL + _audiod_fct[i].interval_tx = desc_ep->bInterval; + #endif #endif } else { @@ -1607,6 +1688,11 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const * audio->ep_in = 0; // Necessary? + #if CFG_TUD_AUDIO_EP_IN_FLOW_CONTROL + audio->packet_sz_tx[0] = 0; + audio->packet_sz_tx[1] = 0; + audio->packet_sz_tx[2] = 0; + #endif } #endif // CFG_TUD_AUDIO_ENABLE_EP_IN @@ -1657,7 +1743,7 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const * // Find correct interface if (tu_desc_type(p_desc) == TUSB_DESC_INTERFACE && ((tusb_desc_interface_t const * )p_desc)->bInterfaceNumber == itf && ((tusb_desc_interface_t const * )p_desc)->bAlternateSetting == alt) { -#if CFG_TUD_AUDIO_ENABLE_ENCODING || CFG_TUD_AUDIO_ENABLE_DECODING +#if CFG_TUD_AUDIO_ENABLE_ENCODING || CFG_TUD_AUDIO_ENABLE_DECODING || CFG_TUD_AUDIO_EP_IN_FLOW_CONTROL uint8_t const * p_desc_parse_for_params = p_desc; #endif // From this point forward follow the EP descriptors associated to the current alternate setting interface - Open EPs if necessary @@ -1686,12 +1772,13 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const * audio->ep_in_sz = tu_edpt_packet_size(desc_ep); // If software encoding is enabled, parse for the corresponding parameters - doing this here means only AS interfaces with EPs get scanned for parameters - #if CFG_TUD_AUDIO_ENABLE_ENCODING + #if CFG_TUD_AUDIO_ENABLE_ENCODING || CFG_TUD_AUDIO_EP_IN_FLOW_CONTROL audiod_parse_for_AS_params(audio, p_desc_parse_for_params, p_desc_end, itf); // Reconfigure size of support FIFOs - this is necessary to avoid samples to get split in case of a wrap - #if CFG_TUD_AUDIO_ENABLE_TYPE_I_ENCODING - const uint16_t active_fifo_depth = (uint16_t) ((audio->tx_supp_ff_sz_max / audio->n_bytes_per_sampe_tx) * audio->n_bytes_per_sampe_tx); + #if CFG_TUD_AUDIO_ENABLE_ENCODING && CFG_TUD_AUDIO_ENABLE_TYPE_I_ENCODING + const uint16_t active_fifo_depth = (uint16_t) ((audio->tx_supp_ff_sz_max / (audio->n_channels_per_ff_tx * audio->n_bytes_per_sampe_tx)) + * (audio->n_channels_per_ff_tx * audio->n_bytes_per_sampe_tx)); for (uint8_t cnt = 0; cnt < audio->n_tx_supp_ff; cnt++) { tu_fifo_config(&audio->tx_supp_ff[cnt], audio->tx_supp_ff[cnt].buffer, active_fifo_depth, 1, true); @@ -2404,7 +2491,7 @@ static bool audiod_verify_ep_exists(uint8_t ep, uint8_t *func_id) return false; } -#if CFG_TUD_AUDIO_ENABLE_ENCODING || CFG_TUD_AUDIO_ENABLE_DECODING +#if (CFG_TUD_AUDIO_ENABLE_EP_IN && (CFG_TUD_AUDIO_EP_IN_FLOW_CONTROL || CFG_TUD_AUDIO_ENABLE_ENCODING)) || (CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_DECODING) // p_desc points to the AS interface of alternate setting zero // itf is the interface number of the corresponding interface - we check if the interface belongs to EP in or EP out to see if it is a TX or RX parameter // Currently, only AS interfaces with an EP (in or out) are supposed to be parsed for! @@ -2455,7 +2542,7 @@ static void audiod_parse_for_AS_params(audiod_function_t* audio, uint8_t const * } // Look for a Type I Format Type Descriptor(2.3.1.6 - Audio Formats) -#if CFG_TUD_AUDIO_ENABLE_TYPE_I_ENCODING || CFG_TUD_AUDIO_ENABLE_TYPE_I_DECODING +#if CFG_TUD_AUDIO_ENABLE_TYPE_I_ENCODING || CFG_TUD_AUDIO_EP_IN_FLOW_CONTROL || CFG_TUD_AUDIO_ENABLE_TYPE_I_DECODING if (tu_desc_type(p_desc) == TUSB_DESC_CS_INTERFACE && tu_desc_subtype(p_desc) == AUDIO_CS_AS_INTERFACE_FORMAT_TYPE && ((audio_desc_type_I_format_t const * )p_desc)->bFormatType == AUDIO_FORMAT_TYPE_I) { #if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_EP_OUT @@ -2491,6 +2578,31 @@ static void audiod_parse_for_AS_params(audiod_function_t* audio, uint8_t const * } #endif +#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_EP_IN_FLOW_CONTROL +static bool audiod_tx_calc_packet_size(const uint16_t* norminal_size, uint16_t data_size, uint16_t fifo_size, uint16_t* packet_size) +{ + TU_VERIFY(norminal_size[1]); + + // This flow control method need a FIFO size of 4*Navg + TU_VERIFY(norminal_size[1] <= fifo_size * 4); + + if (data_size < norminal_size[0]) + *packet_size = 0; + else + { + uint16_t slot_size = norminal_size[2] - norminal_size[1]; + if (data_size < fifo_size / 2 - slot_size) + *packet_size = norminal_size[0]; + else if (data_size > fifo_size / 2 + slot_size) + *packet_size = norminal_size[2]; + else + *packet_size = norminal_size[1]; + } + + return true; +} +#endif + #if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP bool tud_audio_n_fb_set(uint8_t func_id, uint32_t feedback) diff --git a/src/class/audio/audio_device.h b/src/class/audio/audio_device.h index 7c88b99fc..4cb3ca84c 100644 --- a/src/class/audio/audio_device.h +++ b/src/class/audio/audio_device.h @@ -181,6 +181,11 @@ #endif #endif +// (For TYPE-I format only) Flow control is necessary to allow IN ep send correct amount of data, unless it's a virtual device where data is perfectly synchronized to USB clock. +#ifndef CFG_TUD_AUDIO_EP_IN_FLOW_CONTROL +#define CFG_TUD_AUDIO_EP_IN_FLOW_CONTROL 1 +#endif + // Enable/disable feedback EP (required for asynchronous RX applications) #ifndef CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP #define CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP 0 // Feedback - 0 or 1 @@ -392,6 +397,10 @@ tu_fifo_t* tud_audio_n_get_tx_support_ff (uint8_t func_id, uint8_t ff_i uint16_t tud_audio_int_ctr_n_write (uint8_t func_id, uint8_t const* buffer, uint16_t len); #endif +#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_EP_IN_FLOW_CONTROL +bool tud_audio_n_set_tx_flow_control (uint8_t func_id, uint32_t sample_rate); +#endif + //--------------------------------------------------------------------+ // Application API (Interface0) //--------------------------------------------------------------------+ @@ -670,6 +679,13 @@ static inline uint16_t tud_audio_int_ctr_write(uint8_t const* buffer, uint16_t l } #endif +#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_EP_IN_FLOW_CONTROL +static inline bool tud_audio_set_tx_flow_control(uint32_t sample_rate) +{ + return tud_audio_n_set_tx_flow_control(0, sample_rate); +} +#endif + #if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP static inline bool tud_audio_fb_set(uint32_t feedback) -- cgit v1.3.1 From 0a1d6cf4d028bce2248da01b8cc13aa4673e61b5 Mon Sep 17 00:00:00 2001 From: HiFiPhile Date: Tue, 17 Oct 2023 13:06:55 +0200 Subject: Read sample rate directly from control transfer to eliminate callback. --- examples/device/audio_4_channel_mic/src/main.c | 5 +- src/class/audio/audio_device.c | 301 ++++++++++++++----------- src/class/audio/audio_device.h | 10 - 3 files changed, 173 insertions(+), 143 deletions(-) (limited to 'src/class') diff --git a/examples/device/audio_4_channel_mic/src/main.c b/examples/device/audio_4_channel_mic/src/main.c index 52e6d71f7..9c37315c8 100644 --- a/examples/device/audio_4_channel_mic/src/main.c +++ b/examples/device/audio_4_channel_mic/src/main.c @@ -407,9 +407,8 @@ bool tud_audio_get_req_entity_cb(uint8_t rhport, tusb_control_request_t const * { case AUDIO_CS_REQ_CUR: TU_LOG2(" Get Sample Freq.\r\n"); - // Set sample rate for flow control - tud_audio_set_tx_flow_control(sampFreq); - return tud_control_xfer(rhport, p_request, &sampFreq, sizeof(sampFreq)); + // Buffered control transfer is needed for IN flow control to work + return tud_audio_buffer_and_schedule_control_xfer(rhport, p_request, &sampFreq, sizeof(sampFreq)); case AUDIO_CS_REQ_RANGE: TU_LOG2(" Get Sample Freq. range\r\n"); diff --git a/src/class/audio/audio_device.c b/src/class/audio/audio_device.c index 9299440c9..e246281be 100644 --- a/src/class/audio/audio_device.c +++ b/src/class/audio/audio_device.c @@ -461,7 +461,8 @@ static inline uint8_t tu_desc_subtype(void const* desc) #endif #if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_EP_IN_FLOW_CONTROL -static bool audiod_tx_calc_packet_size(const uint16_t* norminal_size, uint16_t data_size, uint16_t fifo_size, uint16_t* packet_size); +static bool audiod_calc_tx_packet_sz(audiod_function_t* audio); +static uint16_t audiod_tx_packet_size(const uint16_t* norminal_size, uint16_t data_count, uint16_t fifo_depth, uint16_t max_size); #endif #if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP @@ -832,58 +833,6 @@ uint16_t tud_audio_int_ctr_n_write(uint8_t func_id, uint8_t const* buffer, uint1 #endif -#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_EP_IN_FLOW_CONTROL - -bool tud_audio_n_set_tx_flow_control(uint8_t func_id, uint32_t sample_rate) -{ - TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL); - audiod_function_t* audio = &_audiod_fct[func_id]; - - TU_VERIFY(audio->format_type_tx == AUDIO_FORMAT_TYPE_I); - TU_VERIFY(audio->n_channels_tx); - TU_VERIFY(audio->n_bytes_per_sampe_tx); - TU_VERIFY(audio->interval_tx); - - if (sample_rate == 0) - { - audio->packet_sz_tx[0] = 0; - audio->packet_sz_tx[1] = 0; - audio->packet_sz_tx[2] = 0; - return false; - } - - const uint8_t interval = (tud_speed_get() == TUSB_SPEED_FULL) ? audio->interval_tx : 1 << (audio->interval_tx - 1); - - const uint32_t sample_normimal = sample_rate * interval / ((tud_speed_get() == TUSB_SPEED_FULL) ? 1000 : 8000); - const uint32_t sample_reminder = sample_rate * interval % ((tud_speed_get() == TUSB_SPEED_FULL) ? 1000 : 8000); - - const uint16_t packet_sz_tx_min = (sample_normimal - 1) * audio->n_channels_tx * audio->n_bytes_per_sampe_tx; - const uint16_t packet_sz_tx_norm = sample_normimal * audio->n_channels_tx * audio->n_bytes_per_sampe_tx; - const uint16_t packet_sz_tx_max = (sample_normimal + 1) * audio->n_channels_tx * audio->n_bytes_per_sampe_tx; - - TU_ASSERT(packet_sz_tx_max <= audio->ep_in_sz); - - // Frmt20.pdf 2.3.1.1 USB Packets - if (sample_reminder) - { - // All virtual frame packets must either contain INT(nav) audio slots (small VFP) or INT(nav)+1 (large VFP) audio slots - audio->packet_sz_tx[0] = packet_sz_tx_norm; - audio->packet_sz_tx[1] = packet_sz_tx_norm; - audio->packet_sz_tx[2] = packet_sz_tx_max; - } else - { - // In the case where nav = INT(nav), ni may vary between INT(nav)-1 (small VFP), INT(nav) - // (medium VFP) and INT(nav)+1 (large VFP). - audio->packet_sz_tx[0] = packet_sz_tx_min; - audio->packet_sz_tx[1] = packet_sz_tx_norm; - audio->packet_sz_tx[2] = packet_sz_tx_max; - } - - 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. // If you prefer your own (more efficient) implementation suiting your purpose set CFG_TUD_AUDIO_ENABLE_ENCODING = 0 and use tud_audio_n_write. @@ -949,12 +898,8 @@ static bool audiod_tx_done_cb(uint8_t rhport, audiod_function_t * audio) #else // No support FIFOs, if no linear buffer required schedule transmit, else put data into linear buffer and schedule #if CFG_TUD_AUDIO_EP_IN_FLOW_CONTROL - uint16_t tgt_packet_sz; // packet_sz_tx is based on total packet size, here we want size for each support buffer. - if (audiod_tx_calc_packet_size(audio->packet_sz_tx, tu_fifo_count(&audio->ep_in_ff), audio->ep_in_ff.depth, &tgt_packet_sz)) - n_bytes_tx = tgt_packet_sz; - else - n_bytes_tx = tu_min16(tu_fifo_count(&audio->ep_in_ff), audio->ep_in_sz); + n_bytes_tx = audiod_tx_packet_size(audio->packet_sz_tx, tu_fifo_count(&audio->ep_in_ff), audio->ep_in_ff.depth, audio->ep_in_sz); #else n_bytes_tx = tu_min16(tu_fifo_count(&audio->ep_in_ff), audio->ep_in_sz); // Limit up to max packet size, more can not be done for ISO #endif @@ -1056,7 +1001,6 @@ static uint16_t audiod_encode_type_I_pcm(uint8_t rhport, audiod_function_t* audi // Determine amount of samples uint8_t const n_ff_used = audio->n_ff_used_tx; - uint16_t const capPerFF = audio->ep_in_sz / n_ff_used; // Sample capacity per FIFO in bytes uint16_t nBytesPerFFToSend = tu_fifo_count(&audio->tx_supp_ff[0]); uint8_t cnt_ff; @@ -1070,19 +1014,18 @@ static uint16_t audiod_encode_type_I_pcm(uint8_t rhport, audiod_function_t* audi } #if CFG_TUD_AUDIO_EP_IN_FLOW_CONTROL - uint16_t tgt_packet_sz; + const uint16_t norm_packet_sz_tx[3] = {audio->packet_sz_tx[0] / n_ff_used, + audio->packet_sz_tx[1] / n_ff_used, + audio->packet_sz_tx[2] / n_ff_used}; // packet_sz_tx is based on total packet size, here we want size for each support buffer. - if (audiod_tx_calc_packet_size(audio->packet_sz_tx, nBytesPerFFToSend * n_ff_used, audio->tx_supp_ff[0].depth * n_ff_used, &tgt_packet_sz)) - nBytesPerFFToSend = tgt_packet_sz / n_ff_used; -#endif - + nBytesPerFFToSend = audiod_tx_packet_size(norm_packet_sz_tx, nBytesPerFFToSend, audio->tx_supp_ff[0].depth, audio->ep_in_sz / n_ff_used); + // Check if there is enough data + if (nBytesPerFFToSend == 0) return 0; +#else // Check if there is enough data if (nBytesPerFFToSend == 0) return 0; - // Limit to maximum sample number - THIS IS A POSSIBLE ERROR SOURCE IF TOO MANY SAMPLE WOULD NEED TO BE SENT BUT CAN NOT! - nBytesPerFFToSend = tu_min16(nBytesPerFFToSend, capPerFF); - -#if !CFG_TUD_AUDIO_EP_IN_FLOW_CONTROL + nBytesPerFFToSend = tu_min16(nBytesPerFFToSend, audio->ep_in_sz / n_ff_used); // Round to full number of samples (flooring) uint16_t const nSlotSize = audio->n_channels_per_ff_tx * audio->n_bytes_per_sampe_tx; nBytesPerFFToSend = (nBytesPerFFToSend / nSlotSize) * nSlotSize; @@ -1349,7 +1292,7 @@ void audiod_init(void) #endif // CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_ENCODING // Set encoding parameters for Type_I formats -#if CFG_TUD_AUDIO_ENABLE_TYPE_I_ENCODING +#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_TYPE_I_ENCODING switch (i) { #if CFG_TUD_AUDIO_FUNC_1_TX_SUPP_SW_FIFO_SZ > 0 @@ -1529,85 +1472,115 @@ uint16_t audiod_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uin } #if USE_ISO_EP_ALLOCATION + { #if CFG_TUD_AUDIO_ENABLE_EP_IN - uint8_t ep_in = 0; - uint16_t ep_in_size = 0; + uint8_t ep_in = 0; + uint16_t ep_in_size = 0; #endif #if CFG_TUD_AUDIO_ENABLE_EP_OUT - uint8_t ep_out = 0; - uint16_t ep_out_size = 0; + uint8_t ep_out = 0; + uint16_t ep_out_size = 0; #endif #if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP - uint8_t ep_fb = 0; + uint8_t ep_fb = 0; #endif - - 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; - while (p_desc < p_desc_end) - { - if (tu_desc_type(p_desc) == TUSB_DESC_ENDPOINT) + 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; + while (p_desc < p_desc_end) { - tusb_desc_endpoint_t const *desc_ep = (tusb_desc_endpoint_t const *) p_desc; - if (desc_ep->bmAttributes.xfer == TUSB_XFER_ISOCHRONOUS) + if (tu_desc_type(p_desc) == TUSB_DESC_ENDPOINT) { - #if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP - // Explicit feedback EP - if (desc_ep->bmAttributes.usage == 1) + tusb_desc_endpoint_t const *desc_ep = (tusb_desc_endpoint_t const *) p_desc; + if (desc_ep->bmAttributes.xfer == TUSB_XFER_ISOCHRONOUS) { - ep_fb = desc_ep->bEndpointAddress; - } + #if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP + // Explicit feedback EP + if (desc_ep->bmAttributes.usage == 1) + { + ep_fb = desc_ep->bEndpointAddress; + } #endif - // Data EP - if (desc_ep->bmAttributes.usage == 0) - { - if (tu_edpt_dir(desc_ep->bEndpointAddress) == TUSB_DIR_IN) + // Data EP + if (desc_ep->bmAttributes.usage == 0) { + if (tu_edpt_dir(desc_ep->bEndpointAddress) == TUSB_DIR_IN) + { #if CFG_TUD_AUDIO_ENABLE_EP_IN - ep_in = desc_ep->bEndpointAddress; - ep_in_size = TU_MAX(tu_edpt_packet_size(desc_ep), ep_in_size); - #if CFG_TUD_AUDIO_EP_IN_FLOW_CONTROL - _audiod_fct[i].interval_tx = desc_ep->bInterval; - #endif + ep_in = desc_ep->bEndpointAddress; + ep_in_size = TU_MAX(tu_edpt_packet_size(desc_ep), ep_in_size); #endif - } else - { + } else + { #if CFG_TUD_AUDIO_ENABLE_EP_OUT - ep_out = desc_ep->bEndpointAddress; - ep_out_size = TU_MAX(tu_edpt_packet_size(desc_ep), ep_out_size); + ep_out = desc_ep->bEndpointAddress; + ep_out_size = TU_MAX(tu_edpt_packet_size(desc_ep), ep_out_size); #endif + } } - } + } } + + p_desc = tu_desc_next(p_desc); } - p_desc = tu_desc_next(p_desc); - } #if CFG_TUD_AUDIO_ENABLE_EP_IN - if (ep_in) - { - usbd_edpt_iso_alloc(rhport, ep_in, ep_in_size); - } + if (ep_in) + { + usbd_edpt_iso_alloc(rhport, ep_in, ep_in_size); + } #endif #if CFG_TUD_AUDIO_ENABLE_EP_OUT - if (ep_out) - { - usbd_edpt_iso_alloc(rhport, ep_out, ep_out_size); - } + if (ep_out) + { + usbd_edpt_iso_alloc(rhport, ep_out, ep_out_size); + } #endif #if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP - if (ep_fb) - { - usbd_edpt_iso_alloc(rhport, ep_fb, 4); - } + if (ep_fb) + { + usbd_edpt_iso_alloc(rhport, ep_fb, 4); + } #endif - + } #endif // USE_ISO_EP_ALLOCATION +#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_EP_IN_FLOW_CONTROL + { + 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; + while (p_desc < p_desc_end) + { + if (tu_desc_type(p_desc) == TUSB_DESC_ENDPOINT) + { + tusb_desc_endpoint_t const *desc_ep = (tusb_desc_endpoint_t const *) p_desc; + if (desc_ep->bmAttributes.xfer == TUSB_XFER_ISOCHRONOUS) + { + if (desc_ep->bmAttributes.usage == 0) + { + if (tu_edpt_dir(desc_ep->bEndpointAddress) == TUSB_DIR_IN) + { + _audiod_fct[i].interval_tx = desc_ep->bInterval; + } + } + } + } else + if (tu_desc_type(p_desc) == TUSB_DESC_CS_INTERFACE && tu_desc_subtype(p_desc) == AUDIO_CS_AC_INTERFACE_OUTPUT_TERMINAL) + { + if(tu_unaligned_read16(p_desc + 4) == AUDIO_TERM_TYPE_USB_STREAMING) + { + _audiod_fct[i].bclock_id_tx = p_desc[8]; + } + } + p_desc = tu_desc_next(p_desc); + } + } +#endif // CFG_TUD_AUDIO_EP_IN_FLOW_CONTROL + break; } } @@ -1910,6 +1883,10 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const * if (disable) usbd_sof_enable(rhport, false); #endif +#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_EP_IN_FLOW_CONTROL + audiod_calc_tx_packet_sz(audio); +#endif + tud_control_status(rhport, p_request); return true; @@ -2352,6 +2329,19 @@ bool tud_audio_buffer_and_schedule_control_xfer(uint8_t rhport, tusb_control_req // Copy into buffer TU_VERIFY(0 == tu_memcpy_s(_audiod_fct[func_id].ctrl_buf, _audiod_fct[func_id].ctrl_buf_sz, data, (size_t)len)); +#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_EP_IN_FLOW_CONTROL + // Find data for sampling_frequency_control + if (p_request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS && p_request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_INTERFACE) + { + uint8_t entityID = TU_U16_HIGH(p_request->wIndex); + uint8_t ctrlSel = TU_U16_HIGH(p_request->wValue); + if (_audiod_fct[func_id].bclock_id_tx == entityID && ctrlSel == AUDIO_CS_CTRL_SAM_FREQ && p_request->bRequest == AUDIO_CS_REQ_CUR) + { + _audiod_fct[func_id].sample_rate_tx = tu_unaligned_read32(_audiod_fct[func_id].ctrl_buf); + } + } +#endif + // Schedule transmit return tud_control_xfer(rhport, p_request, (void*)_audiod_fct[func_id].ctrl_buf, len); } @@ -2579,28 +2569,79 @@ static void audiod_parse_for_AS_params(audiod_function_t* audio, uint8_t const * #endif #if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_EP_IN_FLOW_CONTROL -static bool audiod_tx_calc_packet_size(const uint16_t* norminal_size, uint16_t data_size, uint16_t fifo_size, uint16_t* packet_size) + +static bool audiod_calc_tx_packet_sz(audiod_function_t* audio) { - TU_VERIFY(norminal_size[1]); + TU_VERIFY(audio->format_type_tx == AUDIO_FORMAT_TYPE_I); + TU_VERIFY(audio->n_channels_tx); + TU_VERIFY(audio->n_bytes_per_sampe_tx); + TU_VERIFY(audio->interval_tx); + TU_VERIFY(audio->sample_rate_tx); - // This flow control method need a FIFO size of 4*Navg - TU_VERIFY(norminal_size[1] <= fifo_size * 4); + const uint8_t interval = (tud_speed_get() == TUSB_SPEED_FULL) ? audio->interval_tx : 1 << (audio->interval_tx - 1); - if (data_size < norminal_size[0]) - *packet_size = 0; - else + const uint32_t sample_normimal = audio->sample_rate_tx * interval / ((tud_speed_get() == TUSB_SPEED_FULL) ? 1000 : 8000); + const uint32_t sample_reminder = audio->sample_rate_tx * interval % ((tud_speed_get() == TUSB_SPEED_FULL) ? 1000 : 8000); + + const uint16_t packet_sz_tx_min = (sample_normimal - 1) * audio->n_channels_tx * audio->n_bytes_per_sampe_tx; + const uint16_t packet_sz_tx_norm = sample_normimal * audio->n_channels_tx * audio->n_bytes_per_sampe_tx; + const uint16_t packet_sz_tx_max = (sample_normimal + 1) * audio->n_channels_tx * audio->n_bytes_per_sampe_tx; + + // Endpoint size must larger than packet size + TU_ASSERT(packet_sz_tx_max <= audio->ep_in_sz); + + // Frmt20.pdf 2.3.1.1 USB Packets + if (sample_reminder) { - uint16_t slot_size = norminal_size[2] - norminal_size[1]; - if (data_size < fifo_size / 2 - slot_size) - *packet_size = norminal_size[0]; - else if (data_size > fifo_size / 2 + slot_size) - *packet_size = norminal_size[2]; - else - *packet_size = norminal_size[1]; + // All virtual frame packets must either contain INT(nav) audio slots (small VFP) or INT(nav)+1 (large VFP) audio slots + audio->packet_sz_tx[0] = packet_sz_tx_norm; + audio->packet_sz_tx[1] = packet_sz_tx_norm; + audio->packet_sz_tx[2] = packet_sz_tx_max; + } else + { + // In the case where nav = INT(nav), ni may vary between INT(nav)-1 (small VFP), INT(nav) + // (medium VFP) and INT(nav)+1 (large VFP). + audio->packet_sz_tx[0] = packet_sz_tx_min; + audio->packet_sz_tx[1] = packet_sz_tx_norm; + audio->packet_sz_tx[2] = packet_sz_tx_max; } return true; } + +static uint16_t audiod_tx_packet_size(const uint16_t* norminal_size, uint16_t data_count, uint16_t fifo_depth, uint16_t max_depth) +{ + // Flow control need a FIFO size of at least 4*Navg + if(norminal_size[1] && norminal_size[1] <= fifo_depth * 4) + { + uint16_t packet_size; + uint16_t slot_size = norminal_size[2] - norminal_size[1]; + if (data_count < fifo_depth / 2 - slot_size) + { + if (data_count < norminal_size[0]) + { + // If you get here frequently, then your I2S clock deviation is too big ! + packet_size = 0; + } else + { + packet_size = norminal_size[0]; + } + } + else if (data_count > fifo_depth / 2 + slot_size) + { + packet_size = norminal_size[2]; + } else + { + packet_size = norminal_size[1]; + } + // Normally this cap is not necessary + return tu_min16(packet_size, max_depth); + } else + { + return tu_min16(data_count, max_depth); + } +} + #endif #if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP diff --git a/src/class/audio/audio_device.h b/src/class/audio/audio_device.h index 4cb3ca84c..ef3e12a06 100644 --- a/src/class/audio/audio_device.h +++ b/src/class/audio/audio_device.h @@ -397,9 +397,6 @@ tu_fifo_t* tud_audio_n_get_tx_support_ff (uint8_t func_id, uint8_t ff_i uint16_t tud_audio_int_ctr_n_write (uint8_t func_id, uint8_t const* buffer, uint16_t len); #endif -#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_EP_IN_FLOW_CONTROL -bool tud_audio_n_set_tx_flow_control (uint8_t func_id, uint32_t sample_rate); -#endif //--------------------------------------------------------------------+ // Application API (Interface0) @@ -679,13 +676,6 @@ static inline uint16_t tud_audio_int_ctr_write(uint8_t const* buffer, uint16_t l } #endif -#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_EP_IN_FLOW_CONTROL -static inline bool tud_audio_set_tx_flow_control(uint32_t sample_rate) -{ - return tud_audio_n_set_tx_flow_control(0, sample_rate); -} -#endif - #if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP static inline bool tud_audio_fb_set(uint32_t feedback) -- cgit v1.3.1 From d83a2107883c8a6224ab99f248a59b216a8d2a82 Mon Sep 17 00:00:00 2001 From: HiFiPhile Date: Tue, 17 Oct 2023 15:18:05 +0200 Subject: Add blackout time. --- src/class/audio/audio_device.c | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-) (limited to 'src/class') diff --git a/src/class/audio/audio_device.c b/src/class/audio/audio_device.c index e246281be..d32ed56b2 100644 --- a/src/class/audio/audio_device.c +++ b/src/class/audio/audio_device.c @@ -2614,25 +2614,39 @@ static uint16_t audiod_tx_packet_size(const uint16_t* norminal_size, uint16_t da // Flow control need a FIFO size of at least 4*Navg if(norminal_size[1] && norminal_size[1] <= fifo_depth * 4) { + // Use blackout to prioritize normal size packet + static int ctrl_blackout = 0; uint16_t packet_size; uint16_t slot_size = norminal_size[2] - norminal_size[1]; - if (data_count < fifo_depth / 2 - slot_size) + if (data_count < norminal_size[0]) { - if (data_count < norminal_size[0]) - { // If you get here frequently, then your I2S clock deviation is too big ! packet_size = 0; + } else + if (data_count < fifo_depth / 2 - slot_size && !ctrl_blackout) + { + packet_size = norminal_size[0]; + ctrl_blackout = 10; + } else + if (data_count > fifo_depth / 2 + slot_size && !ctrl_blackout) + { + packet_size = norminal_size[2]; + if(norminal_size[0] == norminal_size[1]) + { + // nav = INT(nav) + 1 + ctrl_blackout = 2; } else { - packet_size = norminal_size[0]; + // nav = INT(nav) + ctrl_blackout = 10; } - } - else if (data_count > fifo_depth / 2 + slot_size) - { - packet_size = norminal_size[2]; } else { packet_size = norminal_size[1]; + if (ctrl_blackout) + { + ctrl_blackout--; + } } // Normally this cap is not necessary return tu_min16(packet_size, max_depth); -- cgit v1.3.1 From e9d894fe6620d623bc393698a971d08d43516e01 Mon Sep 17 00:00:00 2001 From: HiFiPhile Date: Tue, 17 Oct 2023 15:23:05 +0200 Subject: Fix compile. --- .../device/audio_4_channel_mic/src/tusb_config.h | 5 +++-- src/class/audio/audio_device.c | 26 +++++++++++----------- 2 files changed, 16 insertions(+), 15 deletions(-) (limited to 'src/class') diff --git a/examples/device/audio_4_channel_mic/src/tusb_config.h b/examples/device/audio_4_channel_mic/src/tusb_config.h index d1e19c5a1..f86b63528 100644 --- a/examples/device/audio_4_channel_mic/src/tusb_config.h +++ b/examples/device/audio_4_channel_mic/src/tusb_config.h @@ -115,7 +115,8 @@ extern "C" { #define CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX 4 // This value is not required by the driver, it parses this information from the descriptor once the alternate interface is set by the host - we use it for the setup #define CFG_TUD_AUDIO_EP_SZ_IN TUD_AUDIO_EP_SIZE(CFG_TUD_AUDIO_FUNC_1_SAMPLE_RATE, CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_TX, CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX) -#define CFG_TUD_AUDIO_ENABLE_ENCODING 0 +#define CFG_TUD_AUDIO_ENABLE_ENCODING 1 +#define CFG_TUD_AUDIO_EP_IN_FLOW_CONTROL 1 #if CFG_TUD_AUDIO_ENABLE_ENCODING @@ -129,7 +130,7 @@ extern "C" { #else -#define CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX 4 * CFG_TUD_AUDIO_EP_SZ_IN +#define CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX CFG_TUD_AUDIO_EP_SZ_IN #define CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ 4 * CFG_TUD_AUDIO_EP_SZ_IN #endif diff --git a/src/class/audio/audio_device.c b/src/class/audio/audio_device.c index d32ed56b2..220771aec 100644 --- a/src/class/audio/audio_device.c +++ b/src/class/audio/audio_device.c @@ -217,7 +217,7 @@ uint8_t alt_setting_3[CFG_TUD_AUDIO_FUNC_3_N_AS_INT]; // Software encoding/decoding support FIFOs #if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_ENCODING #if CFG_TUD_AUDIO_FUNC_1_TX_SUPP_SW_FIFO_SZ > 0 - CFG_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t tx_supp_ff_buf_1[CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_1_TX_SUPP_SW_FIFO_SZ]; + CFG_TUSB_MEM_ALIGN uint8_t tx_supp_ff_buf_1[CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_1_TX_SUPP_SW_FIFO_SZ]; tu_fifo_t tx_supp_ff_1[CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO]; #if CFG_FIFO_MUTEX osal_mutex_def_t tx_supp_ff_mutex_wr_1[CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO]; // No need for read mutex as only USB driver reads from FIFO @@ -225,7 +225,7 @@ uint8_t alt_setting_3[CFG_TUD_AUDIO_FUNC_3_N_AS_INT]; #endif #if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_TX_SUPP_SW_FIFO_SZ > 0 - CFG_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t tx_supp_ff_buf_2[CFG_TUD_AUDIO_FUNC_2_N_TX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_2_TX_SUPP_SW_FIFO_SZ]; + CFG_TUSB_MEM_ALIGN uint8_t tx_supp_ff_buf_2[CFG_TUD_AUDIO_FUNC_2_N_TX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_2_TX_SUPP_SW_FIFO_SZ]; tu_fifo_t tx_supp_ff_2[CFG_TUD_AUDIO_FUNC_2_N_TX_SUPP_SW_FIFO]; #if CFG_FIFO_MUTEX osal_mutex_def_t tx_supp_ff_mutex_wr_2[CFG_TUD_AUDIO_FUNC_2_N_TX_SUPP_SW_FIFO]; // No need for read mutex as only USB driver reads from FIFO @@ -233,7 +233,7 @@ uint8_t alt_setting_3[CFG_TUD_AUDIO_FUNC_3_N_AS_INT]; #endif #if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_TX_SUPP_SW_FIFO_SZ > 0 - CFG_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t tx_supp_ff_buf_3[CFG_TUD_AUDIO_FUNC_3_N_TX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_3_TX_SUPP_SW_FIFO_SZ]; + CFG_TUSB_MEM_ALIGN uint8_t tx_supp_ff_buf_3[CFG_TUD_AUDIO_FUNC_3_N_TX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_3_TX_SUPP_SW_FIFO_SZ]; tu_fifo_t tx_supp_ff_3[CFG_TUD_AUDIO_FUNC_3_N_TX_SUPP_SW_FIFO]; #if CFG_FIFO_MUTEX osal_mutex_def_t tx_supp_ff_mutex_wr_3[CFG_TUD_AUDIO_FUNC_3_N_TX_SUPP_SW_FIFO]; // No need for read mutex as only USB driver reads from FIFO @@ -243,7 +243,7 @@ uint8_t alt_setting_3[CFG_TUD_AUDIO_FUNC_3_N_AS_INT]; #if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_DECODING #if CFG_TUD_AUDIO_FUNC_1_RX_SUPP_SW_FIFO_SZ > 0 - CFG_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t rx_supp_ff_buf_1[CFG_TUD_AUDIO_FUNC_1_N_RX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_1_RX_SUPP_SW_FIFO_SZ]; + CFG_TUSB_MEM_ALIGN uint8_t rx_supp_ff_buf_1[CFG_TUD_AUDIO_FUNC_1_N_RX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_1_RX_SUPP_SW_FIFO_SZ]; tu_fifo_t rx_supp_ff_1[CFG_TUD_AUDIO_FUNC_1_N_RX_SUPP_SW_FIFO]; #if CFG_FIFO_MUTEX osal_mutex_def_t rx_supp_ff_mutex_rd_1[CFG_TUD_AUDIO_FUNC_1_N_RX_SUPP_SW_FIFO]; // No need for write mutex as only USB driver writes into FIFO @@ -251,7 +251,7 @@ uint8_t alt_setting_3[CFG_TUD_AUDIO_FUNC_3_N_AS_INT]; #endif #if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_RX_SUPP_SW_FIFO_SZ > 0 - CFG_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t rx_supp_ff_buf_2[CFG_TUD_AUDIO_FUNC_2_N_RX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_2_RX_SUPP_SW_FIFO_SZ]; + CFG_TUSB_MEM_ALIGN uint8_t rx_supp_ff_buf_2[CFG_TUD_AUDIO_FUNC_2_N_RX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_2_RX_SUPP_SW_FIFO_SZ]; tu_fifo_t rx_supp_ff_2[CFG_TUD_AUDIO_FUNC_2_N_RX_SUPP_SW_FIFO]; #if CFG_FIFO_MUTEX osal_mutex_def_t rx_supp_ff_mutex_rd_2[CFG_TUD_AUDIO_FUNC_2_N_RX_SUPP_SW_FIFO]; // No need for write mutex as only USB driver writes into FIFO @@ -259,7 +259,7 @@ uint8_t alt_setting_3[CFG_TUD_AUDIO_FUNC_3_N_AS_INT]; #endif #if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_RX_SUPP_SW_FIFO_SZ > 0 - CFG_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t rx_supp_ff_buf_3[CFG_TUD_AUDIO_FUNC_3_N_RX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_3_RX_SUPP_SW_FIFO_SZ]; + CFG_TUSB_MEM_ALIGN uint8_t rx_supp_ff_buf_3[CFG_TUD_AUDIO_FUNC_3_N_RX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_3_RX_SUPP_SW_FIFO_SZ]; tu_fifo_t rx_supp_ff_3[CFG_TUD_AUDIO_FUNC_3_N_RX_SUPP_SW_FIFO]; #if CFG_FIFO_MUTEX osal_mutex_def_t rx_supp_ff_mutex_rd_3[CFG_TUD_AUDIO_FUNC_3_N_RX_SUPP_SW_FIFO]; // No need for write mutex as only USB driver writes into FIFO @@ -2519,7 +2519,7 @@ static void audiod_parse_for_AS_params(audiod_function_t* audio, uint8_t const * } #endif -#if CFG_TUD_AUDIO_ENABLE_EP_OUT +#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_DECODING if (as_itf == audio->ep_out_as_intf_num) { audio->n_channels_rx = ((audio_desc_cs_as_interface_t const * )p_desc)->bNrChannels; @@ -2552,7 +2552,7 @@ static void audiod_parse_for_AS_params(audiod_function_t* audio, uint8_t const * } #endif -#if CFG_TUD_AUDIO_ENABLE_EP_OUT +#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_DECODING if (as_itf == audio->ep_out_as_intf_num) { audio->n_bytes_per_sampe_rx = ((audio_desc_type_I_format_t const * )p_desc)->bSubslotSize; @@ -2580,12 +2580,12 @@ static bool audiod_calc_tx_packet_sz(audiod_function_t* audio) const uint8_t interval = (tud_speed_get() == TUSB_SPEED_FULL) ? audio->interval_tx : 1 << (audio->interval_tx - 1); - const uint32_t sample_normimal = audio->sample_rate_tx * interval / ((tud_speed_get() == TUSB_SPEED_FULL) ? 1000 : 8000); - const uint32_t sample_reminder = audio->sample_rate_tx * interval % ((tud_speed_get() == TUSB_SPEED_FULL) ? 1000 : 8000); + const uint16_t sample_normimal = (uint16_t)(audio->sample_rate_tx * interval / ((tud_speed_get() == TUSB_SPEED_FULL) ? 1000 : 8000)); + const uint16_t sample_reminder = (uint16_t)(audio->sample_rate_tx * interval % ((tud_speed_get() == TUSB_SPEED_FULL) ? 1000 : 8000)); - const uint16_t packet_sz_tx_min = (sample_normimal - 1) * audio->n_channels_tx * audio->n_bytes_per_sampe_tx; - const uint16_t packet_sz_tx_norm = sample_normimal * audio->n_channels_tx * audio->n_bytes_per_sampe_tx; - const uint16_t packet_sz_tx_max = (sample_normimal + 1) * audio->n_channels_tx * audio->n_bytes_per_sampe_tx; + const uint16_t packet_sz_tx_min = (uint16_t)((sample_normimal - 1) * audio->n_channels_tx * audio->n_bytes_per_sampe_tx); + const uint16_t packet_sz_tx_norm = (uint16_t)(sample_normimal * audio->n_channels_tx * audio->n_bytes_per_sampe_tx); + const uint16_t packet_sz_tx_max = (uint16_t)((sample_normimal + 1) * audio->n_channels_tx * audio->n_bytes_per_sampe_tx); // Endpoint size must larger than packet size TU_ASSERT(packet_sz_tx_max <= audio->ep_in_sz); -- cgit v1.3.1 From ade8a19aefa91e4aba0bbb0ddeafbcd041c6a4c3 Mon Sep 17 00:00:00 2001 From: HiFiPhile Date: Tue, 17 Oct 2023 21:21:52 +0200 Subject: Put sw_buf in USB section only if necessary. --- src/class/audio/audio_device.c | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) (limited to 'src/class') diff --git a/src/class/audio/audio_device.c b/src/class/audio/audio_device.c index 220771aec..9712afde9 100644 --- a/src/class/audio/audio_device.c +++ b/src/class/audio/audio_device.c @@ -110,24 +110,36 @@ #error Maximum number of audio functions restricted to three! #endif +// Put sw_buf in USB section only if necessary +#if USE_LINEAR_BUFFER || CFG_TUD_AUDIO_ENABLE_ENCODING +#define IN_SW_BUF_MEM_SECTION +#else +#define IN_SW_BUF_MEM_SECTION CFG_TUD_MEM_SECTION +#endif +#if USE_LINEAR_BUFFER || CFG_TUD_AUDIO_ENABLE_DECODING +#define OUT_SW_BUF_MEM_SECTION +#else +#define OUT_SW_BUF_MEM_SECTION CFG_TUD_MEM_SECTION +#endif + // EP IN software buffers and mutexes #if CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_ENCODING #if CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ > 0 - CFG_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t audio_ep_in_sw_buf_1[CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ]; + IN_SW_BUF_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t audio_ep_in_sw_buf_1[CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ]; #if CFG_FIFO_MUTEX osal_mutex_def_t ep_in_ff_mutex_wr_1; // No need for read mutex as only USB driver reads from FIFO #endif #endif // CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ > 0 #if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_IN_SW_BUF_SZ > 0 - CFG_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t audio_ep_in_sw_buf_2[CFG_TUD_AUDIO_FUNC_2_EP_IN_SW_BUF_SZ]; + IN_SW_BUF_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t audio_ep_in_sw_buf_2[CFG_TUD_AUDIO_FUNC_2_EP_IN_SW_BUF_SZ]; #if CFG_FIFO_MUTEX osal_mutex_def_t ep_in_ff_mutex_wr_2; // No need for read mutex as only USB driver reads from FIFO #endif #endif // CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_IN_SW_BUF_SZ > 0 #if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_IN_SW_BUF_SZ > 0 - CFG_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t audio_ep_in_sw_buf_3[CFG_TUD_AUDIO_FUNC_3_EP_IN_SW_BUF_SZ]; + IN_SW_BUF_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t audio_ep_in_sw_buf_3[CFG_TUD_AUDIO_FUNC_3_EP_IN_SW_BUF_SZ]; #if CFG_FIFO_MUTEX osal_mutex_def_t ep_in_ff_mutex_wr_3; // No need for read mutex as only USB driver reads from FIFO #endif @@ -154,21 +166,21 @@ // EP OUT software buffers and mutexes #if CFG_TUD_AUDIO_ENABLE_EP_OUT && !CFG_TUD_AUDIO_ENABLE_DECODING #if CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ > 0 - CFG_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t audio_ep_out_sw_buf_1[CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ]; + OUT_SW_BUF_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t audio_ep_out_sw_buf_1[CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ]; #if CFG_FIFO_MUTEX osal_mutex_def_t ep_out_ff_mutex_rd_1; // No need for write mutex as only USB driver writes into FIFO #endif #endif // CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ > 0 #if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_OUT_SW_BUF_SZ > 0 - CFG_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t audio_ep_out_sw_buf_2[CFG_TUD_AUDIO_FUNC_2_EP_OUT_SW_BUF_SZ]; + OUT_SW_BUF_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t audio_ep_out_sw_buf_2[CFG_TUD_AUDIO_FUNC_2_EP_OUT_SW_BUF_SZ]; #if CFG_FIFO_MUTEX osal_mutex_def_t ep_out_ff_mutex_rd_2; // No need for write mutex as only USB driver writes into FIFO #endif #endif // CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_OUT_SW_BUF_SZ > 0 #if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_OUT_SW_BUF_SZ > 0 - CFG_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t audio_ep_out_sw_buf_3[CFG_TUD_AUDIO_FUNC_3_EP_OUT_SW_BUF_SZ]; + OUT_SW_BUF_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t audio_ep_out_sw_buf_3[CFG_TUD_AUDIO_FUNC_3_EP_OUT_SW_BUF_SZ]; #if CFG_FIFO_MUTEX osal_mutex_def_t ep_out_ff_mutex_rd_3; // No need for write mutex as only USB driver writes into FIFO #endif -- cgit v1.3.1 From f88a5bb03b2504df272d2cd285b17e66f11dfc64 Mon Sep 17 00:00:00 2001 From: Shawn Hoffman Date: Tue, 17 Oct 2023 19:26:11 -0700 Subject: hid_device: use separate buffer for SET_REPORT instead of epout --- src/class/hid/hid_device.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'src/class') diff --git a/src/class/hid/hid_device.c b/src/class/hid/hid_device.c index 2d46d760f..c939c0117 100644 --- a/src/class/hid/hid_device.c +++ b/src/class/hid/hid_device.c @@ -52,6 +52,7 @@ typedef struct CFG_TUSB_MEM_ALIGN uint8_t epin_buf[CFG_TUD_HID_EP_BUFSIZE]; CFG_TUSB_MEM_ALIGN uint8_t epout_buf[CFG_TUD_HID_EP_BUFSIZE]; + CFG_TUSB_MEM_ALIGN uint8_t set_report_buf[CFG_TUD_HID_EP_BUFSIZE]; // TODO save hid descriptor since host can specifically request this after enumeration // Note: HID descriptor may be not available from application after enumeration @@ -307,15 +308,15 @@ bool hidd_control_xfer_cb (uint8_t rhport, uint8_t stage, tusb_control_request_t case HID_REQ_CONTROL_SET_REPORT: if ( stage == CONTROL_STAGE_SETUP ) { - TU_VERIFY(request->wLength <= sizeof(p_hid->epout_buf)); - tud_control_xfer(rhport, request, p_hid->epout_buf, request->wLength); + TU_VERIFY(request->wLength <= sizeof(p_hid->set_report_buf)); + tud_control_xfer(rhport, request, p_hid->set_report_buf, request->wLength); } else if ( stage == CONTROL_STAGE_ACK ) { uint8_t const report_type = tu_u16_high(request->wValue); uint8_t const report_id = tu_u16_low(request->wValue); - uint8_t const* report_buf = p_hid->epout_buf; + uint8_t const* report_buf = p_hid->set_report_buf; uint16_t report_len = tu_min16(request->wLength, CFG_TUD_HID_EP_BUFSIZE); // If host request a specific Report ID, extract report ID in buffer before invoking callback -- cgit v1.3.1 From d3fa3cdf487be5929240bc23f9d109c5e3e947bc Mon Sep 17 00:00:00 2001 From: Mengsk Date: Wed, 18 Oct 2023 17:05:35 +0200 Subject: Adjsut blackout time. --- examples/device/audio_4_channel_mic/src/tusb_config.h | 4 ++-- src/class/audio/audio_device.c | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'src/class') diff --git a/examples/device/audio_4_channel_mic/src/tusb_config.h b/examples/device/audio_4_channel_mic/src/tusb_config.h index f86b63528..cf44918e2 100644 --- a/examples/device/audio_4_channel_mic/src/tusb_config.h +++ b/examples/device/audio_4_channel_mic/src/tusb_config.h @@ -126,12 +126,12 @@ extern "C" { #define CFG_TUD_AUDIO_ENABLE_TYPE_I_ENCODING 1 #define CFG_TUD_AUDIO_FUNC_1_CHANNEL_PER_FIFO_TX 2 // One I2S stream contains two channels, each stream is saved within one support FIFO - this value is currently fixed, the driver does not support a changing value #define CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO (CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX / CFG_TUD_AUDIO_FUNC_1_CHANNEL_PER_FIFO_TX) -#define CFG_TUD_AUDIO_FUNC_1_TX_SUPP_SW_FIFO_SZ 4 * (CFG_TUD_AUDIO_EP_SZ_IN / CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO) +#define CFG_TUD_AUDIO_FUNC_1_TX_SUPP_SW_FIFO_SZ 4 * (CFG_TUD_AUDIO_EP_SZ_IN / CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO) // Minimum 4*EP size is needed for flow control #else #define CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX CFG_TUD_AUDIO_EP_SZ_IN -#define CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ 4 * CFG_TUD_AUDIO_EP_SZ_IN +#define CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ 4 * CFG_TUD_AUDIO_EP_SZ_IN // Minimum 4*EP size is needed for flow control #endif diff --git a/src/class/audio/audio_device.c b/src/class/audio/audio_device.c index 9712afde9..9af999992 100644 --- a/src/class/audio/audio_device.c +++ b/src/class/audio/audio_device.c @@ -2645,11 +2645,11 @@ static uint16_t audiod_tx_packet_size(const uint16_t* norminal_size, uint16_t da packet_size = norminal_size[2]; if(norminal_size[0] == norminal_size[1]) { - // nav = INT(nav) + 1 - ctrl_blackout = 2; + // nav > INT(nav), eg. 44.1k, 88.2k + ctrl_blackout = 0; } else { - // nav = INT(nav) + // nav = INT(nav), eg. 48k, 96k ctrl_blackout = 10; } } else -- cgit v1.3.1 From 8bac68db84ccbf4f9fbd0d6075b6a1b0253c081a Mon Sep 17 00:00:00 2001 From: Antonio Vázquez Blanco Date: Wed, 11 Oct 2023 10:15:52 +0200 Subject: Add historical EP compatibility to bth class --- src/class/bth/bth_device.c | 2 +- src/class/bth/bth_device.h | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) (limited to 'src/class') diff --git a/src/class/bth/bth_device.c b/src/class/bth/bth_device.c index c5c74d26a..be36e8c11 100755 --- a/src/class/bth/bth_device.c +++ b/src/class/bth/bth_device.c @@ -204,7 +204,7 @@ bool btd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t c request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_DEVICE) { // HCI command packet addressing for single function Primary Controllers - TU_VERIFY(request->bRequest == 0 && request->wValue == 0 && request->wIndex == 0); + TU_VERIFY((CFG_TUD_BTH_HISTORICAL_COMPAT && request->bRequest == 0xe0) || (request->bRequest == 0 && request->wValue == 0 && request->wIndex == 0)); } else if (request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_INTERFACE) { diff --git a/src/class/bth/bth_device.h b/src/class/bth/bth_device.h index 921bd7a1a..c23e74bfb 100755 --- a/src/class/bth/bth_device.h +++ b/src/class/bth/bth_device.h @@ -39,6 +39,13 @@ #ifndef CFG_TUD_BTH_DATA_EPSIZE #define CFG_TUD_BTH_DATA_EPSIZE 64 #endif +#ifndef CFG_TUD_BTH_HISTORICAL_COMPAT +#define CFG_TUD_BTH_HISTORICAL_COMPAT 0 +#endif +#ifndef CFG_TUD_BTH_ISO_ALT_COUNT +// See Bluetooth Core v5.3, Vol. 4, Part B, Section 2.1 +#error You must tell the driver the number of ISO endpoints to use +#endif typedef struct TU_ATTR_PACKED { -- cgit v1.3.1 From aedc92f2d31af6209b00e8a5d7abbfec02ed979b Mon Sep 17 00:00:00 2001 From: hathach Date: Wed, 22 Nov 2023 11:25:55 +0700 Subject: fix typo in cdc line coding enum --- examples/host/cdc_msc_hid/src/tusb_config.h | 2 +- examples/host/cdc_msc_hid_freertos/src/tusb_config.h | 2 +- src/class/cdc/cdc.h | 20 +++++++++++--------- src/class/cdc/cdc_host.h | 2 +- 4 files changed, 14 insertions(+), 12 deletions(-) (limited to 'src/class') diff --git a/examples/host/cdc_msc_hid/src/tusb_config.h b/examples/host/cdc_msc_hid/src/tusb_config.h index c8e9138e3..a53000a11 100644 --- a/examples/host/cdc_msc_hid/src/tusb_config.h +++ b/examples/host/cdc_msc_hid/src/tusb_config.h @@ -118,7 +118,7 @@ // Set Line Coding on enumeration/mounted, value for cdc_line_coding_t // bit rate = 115200, 1 stop bit, no parity, 8 bit data width -#define CFG_TUH_CDC_LINE_CODING_ON_ENUM { 115200, CDC_LINE_CONDING_STOP_BITS_1, CDC_LINE_CODING_PARITY_NONE, 8 } +#define CFG_TUH_CDC_LINE_CODING_ON_ENUM { 115200, CDC_LINE_CODING_STOP_BITS_1, CDC_LINE_CODING_PARITY_NONE, 8 } #ifdef __cplusplus diff --git a/examples/host/cdc_msc_hid_freertos/src/tusb_config.h b/examples/host/cdc_msc_hid_freertos/src/tusb_config.h index 1bed9a9b3..ba23301ed 100644 --- a/examples/host/cdc_msc_hid_freertos/src/tusb_config.h +++ b/examples/host/cdc_msc_hid_freertos/src/tusb_config.h @@ -123,7 +123,7 @@ // Set Line Coding on enumeration/mounted, value for cdc_line_coding_t // bit rate = 115200, 1 stop bit, no parity, 8 bit data width -#define CFG_TUH_CDC_LINE_CODING_ON_ENUM { 115200, CDC_LINE_CONDING_STOP_BITS_1, CDC_LINE_CODING_PARITY_NONE, 8 } +#define CFG_TUH_CDC_LINE_CODING_ON_ENUM { 115200, CDC_LINE_CODING_STOP_BITS_1, CDC_LINE_CODING_PARITY_NONE, 8 } #ifdef __cplusplus diff --git a/src/class/cdc/cdc.h b/src/class/cdc/cdc.h index 4658e43af..deec32ae4 100644 --- a/src/class/cdc/cdc.h +++ b/src/class/cdc/cdc.h @@ -182,21 +182,23 @@ typedef enum CDC_REQUEST_MDLM_SEMANTIC_MODEL = 0x60, }cdc_management_request_t; -enum -{ +enum { CDC_CONTROL_LINE_STATE_DTR = 0x01, CDC_CONTROL_LINE_STATE_RTS = 0x02, }; -enum -{ - CDC_LINE_CONDING_STOP_BITS_1 = 0, // 1 bit - CDC_LINE_CONDING_STOP_BITS_1_5 = 1, // 1.5 bits - CDC_LINE_CONDING_STOP_BITS_2 = 2, // 2 bits +enum { + CDC_LINE_CODING_STOP_BITS_1 = 0, // 1 bit + CDC_LINE_CODING_STOP_BITS_1_5 = 1, // 1.5 bits + CDC_LINE_CODING_STOP_BITS_2 = 2, // 2 bits }; -enum -{ +// TODO Backward compatible for typos. Maybe removed in the future release +#define CDC_LINE_CONDING_STOP_BITS_1 CDC_LINE_CODING_STOP_BITS_1 +#define CDC_LINE_CONDING_STOP_BITS_1_5 CDC_LINE_CODING_STOP_BITS_1_5 +#define CDC_LINE_CONDING_STOP_BITS_2 CDC_LINE_CODING_STOP_BITS_2 + +enum { CDC_LINE_CODING_PARITY_NONE = 0, CDC_LINE_CODING_PARITY_ODD = 1, CDC_LINE_CODING_PARITY_EVEN = 2, diff --git a/src/class/cdc/cdc_host.h b/src/class/cdc/cdc_host.h index 19552f1ee..9e5edd94e 100644 --- a/src/class/cdc/cdc_host.h +++ b/src/class/cdc/cdc_host.h @@ -44,7 +44,7 @@ // Set Line Coding on enumeration/mounted, value for cdc_line_coding_t //#ifndef CFG_TUH_CDC_LINE_CODING_ON_ENUM -//#define CFG_TUH_CDC_LINE_CODING_ON_ENUM { 115200, CDC_LINE_CONDING_STOP_BITS_1, CDC_LINE_CODING_PARITY_NONE, 8 } +//#define CFG_TUH_CDC_LINE_CODING_ON_ENUM { 115200, CDC_LINE_CODING_STOP_BITS_1, CDC_LINE_CODING_PARITY_NONE, 8 } //#endif // RX FIFO size -- cgit v1.3.1 From 6e5c7f43906bac8ab47642e56c153297b83f3679 Mon Sep 17 00:00:00 2001 From: hathach Date: Fri, 24 Nov 2023 16:08:06 +0700 Subject: rename to CFG_TUD_BTH_HISTORICAL_COMPATIBLE, move CFG_TUD_BTH_ISO_ALT_COUNT to tusb_option.h and mandatory for BTH driver --- src/class/bth/bth_device.c | 4 +++- src/class/bth/bth_device.h | 12 ++++++------ src/device/usbd.h | 4 ---- src/tusb_option.h | 13 +++++++++---- 4 files changed, 18 insertions(+), 15 deletions(-) (limited to 'src/class') diff --git a/src/class/bth/bth_device.c b/src/class/bth/bth_device.c index be36e8c11..f145e2ead 100755 --- a/src/class/bth/bth_device.c +++ b/src/class/bth/bth_device.c @@ -204,7 +204,9 @@ bool btd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t c request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_DEVICE) { // HCI command packet addressing for single function Primary Controllers - TU_VERIFY((CFG_TUD_BTH_HISTORICAL_COMPAT && request->bRequest == 0xe0) || (request->bRequest == 0 && request->wValue == 0 && request->wIndex == 0)); + // also compatible with historical mode if enabled + TU_VERIFY((request->bRequest == 0 && request->wValue == 0 && request->wIndex == 0) || + (CFG_TUD_BTH_HISTORICAL_COMPATIBLE && request->bRequest == 0xe0)); } else if (request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_INTERFACE) { diff --git a/src/class/bth/bth_device.h b/src/class/bth/bth_device.h index c23e74bfb..e782c532b 100755 --- a/src/class/bth/bth_device.h +++ b/src/class/bth/bth_device.h @@ -36,15 +36,15 @@ #ifndef CFG_TUD_BTH_EVENT_EPSIZE #define CFG_TUD_BTH_EVENT_EPSIZE 16 #endif + #ifndef CFG_TUD_BTH_DATA_EPSIZE #define CFG_TUD_BTH_DATA_EPSIZE 64 #endif -#ifndef CFG_TUD_BTH_HISTORICAL_COMPAT -#define CFG_TUD_BTH_HISTORICAL_COMPAT 0 -#endif -#ifndef CFG_TUD_BTH_ISO_ALT_COUNT -// See Bluetooth Core v5.3, Vol. 4, Part B, Section 2.1 -#error You must tell the driver the number of ISO endpoints to use + +// Allow BTH class to work in historically compatibility mode where the bRequest is always 0xe0. +// See Bluetooth Core v5.3, Vol. 4, Part B, Section 2.2 +#ifndef CFG_TUD_BTH_HISTORICAL_COMPATIBLE +#define CFG_TUD_BTH_HISTORICAL_COMPATIBLE 0 #endif typedef struct TU_ATTR_PACKED diff --git a/src/device/usbd.h b/src/device/usbd.h index 93a2033c4..e14e3d6de 100644 --- a/src/device/usbd.h +++ b/src/device/usbd.h @@ -771,10 +771,6 @@ TU_ATTR_WEAK bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb #define TUD_BT_PROTOCOL_PRIMARY_CONTROLLER 0x01 #define TUD_BT_PROTOCOL_AMP_CONTROLLER 0x02 -#ifndef CFG_TUD_BTH_ISO_ALT_COUNT -#define CFG_TUD_BTH_ISO_ALT_COUNT 0 -#endif - // Length of template descriptor: 38 bytes + number of ISO alternatives * 23 #define TUD_BTH_DESC_LEN (8 + 9 + 7 + 7 + 7 + (CFG_TUD_BTH_ISO_ALT_COUNT) * (9 + 7 + 7)) diff --git a/src/tusb_option.h b/src/tusb_option.h index b8509a069..7920fbf35 100644 --- a/src/tusb_option.h +++ b/src/tusb_option.h @@ -342,6 +342,15 @@ #define CFG_TUD_INTERFACE_MAX 16 #endif +//------------- Device Class Driver -------------// +#ifndef CFG_TUD_BTH + #define CFG_TUD_BTH 0 +#endif + +#if CFG_TUD_BTH && !defined(CFG_TUD_BTH_ISO_ALT_COUNT) +#error CFG_TUD_BTH_ISO_ALT_COUNT must be defined to tell Bluetooth driver the number of ISO endpoints to use +#endif + #ifndef CFG_TUD_CDC #define CFG_TUD_CDC 0 #endif @@ -382,10 +391,6 @@ #define CFG_TUD_DFU 0 #endif -#ifndef CFG_TUD_BTH - #define CFG_TUD_BTH 0 -#endif - #ifndef CFG_TUD_ECM_RNDIS #ifdef CFG_TUD_NET #warning "CFG_TUD_NET is renamed to CFG_TUD_ECM_RNDIS" -- cgit v1.3.1 From 2fed722b0004e64667df526043f3bfcb131d3ee3 Mon Sep 17 00:00:00 2001 From: Xudong Zheng <7pkvm5aw@slicealias.com> Date: Sun, 27 Aug 2023 15:21:15 -0400 Subject: add tuh_hid_set_default_protocol() to set default USB host HID protocol --- src/class/hid/hid_host.c | 11 +++++++++-- src/class/hid/hid_host.h | 5 +++++ 2 files changed, 14 insertions(+), 2 deletions(-) (limited to 'src/class') diff --git a/src/class/hid/hid_host.c b/src/class/hid/hid_host.c index a3551c85a..80312676a 100644 --- a/src/class/hid/hid_host.c +++ b/src/class/hid/hid_host.c @@ -211,6 +211,13 @@ static void set_protocol_complete(tuh_xfer_t* xfer) } } +CFG_TUH_MEM_SECTION +tu_static uint8_t _hidh_default_protocol = HID_PROTOCOL_BOOT; + +void tuh_hid_set_default_protocol(uint8_t protocol) { + _hidh_default_protocol = protocol; +} + static bool _hidh_set_protocol(uint8_t daddr, uint8_t itf_num, uint8_t protocol, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { TU_LOG_DRV("HID Set Protocol = %d\r\n", protocol); @@ -521,7 +528,7 @@ bool hidh_open(uint8_t rhport, uint8_t daddr, tusb_desc_interface_t const *desc_ p_hid->report_desc_len = tu_unaligned_read16(&desc_hid->wReportLength); // Per HID Specs: default is Report protocol, though we will force Boot protocol when set_config - p_hid->protocol_mode = HID_PROTOCOL_BOOT; + p_hid->protocol_mode = _hidh_default_protocol; if ( HID_SUBCLASS_BOOT == desc_itf->bInterfaceSubClass ) { p_hid->itf_protocol = desc_itf->bInterfaceProtocol; @@ -591,7 +598,7 @@ static void process_set_config(tuh_xfer_t* xfer) break; case CONFIG_SET_PROTOCOL: - _hidh_set_protocol(daddr, p_hid->itf_num, HID_PROTOCOL_BOOT, process_set_config, CONFIG_GET_REPORT_DESC); + _hidh_set_protocol(daddr, p_hid->itf_num, _hidh_default_protocol, process_set_config, CONFIG_GET_REPORT_DESC); break; case CONFIG_GET_REPORT_DESC: diff --git a/src/class/hid/hid_host.h b/src/class/hid/hid_host.h index 08ad421d2..3c59e301d 100644 --- a/src/class/hid/hid_host.h +++ b/src/class/hid/hid_host.h @@ -97,6 +97,11 @@ uint8_t tuh_hid_parse_report_descriptor(tuh_hid_report_info_t* reports_info_arr, // Application can use set_protocol() to switch back to Report protocol. uint8_t tuh_hid_get_protocol(uint8_t dev_addr, uint8_t idx); +// Device by default is initialized in Boot protocol for simplicity. Application +// can use this to modify the default protocol before calling tuh_init(), or use +// set_protocol() to change the protocol after initialization. +void tuh_hid_set_default_protocol(uint8_t protocol); + // Set protocol to HID_PROTOCOL_BOOT (0) or HID_PROTOCOL_REPORT (1) // This function is only supported by Boot interface (tuh_n_hid_interface_protocol() != NONE) bool tuh_hid_set_protocol(uint8_t dev_addr, uint8_t idx, uint8_t protocol); -- cgit v1.3.1 From f469250fa34929b1890500b1d7abfb2a7bb7dcc5 Mon Sep 17 00:00:00 2001 From: hathach Date: Fri, 24 Nov 2023 18:35:00 +0700 Subject: minor update --- src/class/hid/hid_host.c | 5 ++--- src/class/hid/hid_host.h | 5 ++--- 2 files changed, 4 insertions(+), 6 deletions(-) (limited to 'src/class') diff --git a/src/class/hid/hid_host.c b/src/class/hid/hid_host.c index 80312676a..db52b503f 100644 --- a/src/class/hid/hid_host.c +++ b/src/class/hid/hid_host.c @@ -67,6 +67,8 @@ typedef struct CFG_TUH_MEM_SECTION tu_static hidh_interface_t _hidh_itf[CFG_TUH_HID]; +tu_static uint8_t _hidh_default_protocol = HID_PROTOCOL_BOOT; + //--------------------------------------------------------------------+ // Helper //--------------------------------------------------------------------+ @@ -211,9 +213,6 @@ static void set_protocol_complete(tuh_xfer_t* xfer) } } -CFG_TUH_MEM_SECTION -tu_static uint8_t _hidh_default_protocol = HID_PROTOCOL_BOOT; - void tuh_hid_set_default_protocol(uint8_t protocol) { _hidh_default_protocol = protocol; } diff --git a/src/class/hid/hid_host.h b/src/class/hid/hid_host.h index 3c59e301d..238b7c627 100644 --- a/src/class/hid/hid_host.h +++ b/src/class/hid/hid_host.h @@ -97,9 +97,8 @@ uint8_t tuh_hid_parse_report_descriptor(tuh_hid_report_info_t* reports_info_arr, // Application can use set_protocol() to switch back to Report protocol. uint8_t tuh_hid_get_protocol(uint8_t dev_addr, uint8_t idx); -// Device by default is initialized in Boot protocol for simplicity. Application -// can use this to modify the default protocol before calling tuh_init(), or use -// set_protocol() to change the protocol after initialization. +// Device by default is enumerated in Boot protocol for simplicity. Application +// can use this to modify the default protocol for next enumeration. void tuh_hid_set_default_protocol(uint8_t protocol); // Set protocol to HID_PROTOCOL_BOOT (0) or HID_PROTOCOL_REPORT (1) -- cgit v1.3.1 From c4e04d3db4f8f33e906afbae4739d64e53fa9987 Mon Sep 17 00:00:00 2001 From: Oliver Larsson Date: Sun, 29 Oct 2023 16:53:10 +0100 Subject: Add configuration option CFG_TUH_CDC_CP210X_PID_LIST to tusb_option.h --- src/class/cdc/cdc_host.c | 2 +- src/class/cdc/serial/cp210x.h | 2 -- src/tusb_option.h | 6 ++++++ 3 files changed, 7 insertions(+), 3 deletions(-) (limited to 'src/class') diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index 53e15710e..a6af9b84d 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -109,7 +109,7 @@ static bool ftdi_sio_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, tu #if CFG_TUH_CDC_CP210X #include "serial/cp210x.h" -static uint16_t const cp210x_pids[] = { TU_CP210X_PID_LIST }; +static uint16_t const cp210x_pids[] = { CFG_TUH_CDC_CP210X_PID_LIST }; enum { CP210X_PID_COUNT = sizeof(cp210x_pids) / sizeof(cp210x_pids[0]) }; diff --git a/src/class/cdc/serial/cp210x.h b/src/class/cdc/serial/cp210x.h index b01417092..2c749f522 100644 --- a/src/class/cdc/serial/cp210x.h +++ b/src/class/cdc/serial/cp210x.h @@ -29,8 +29,6 @@ // https://www.silabs.com/documents/public/application-notes/AN571.pdf #define TU_CP210X_VID 0x10C4 -#define TU_CP210X_PID_LIST \ - 0xEA60, 0xEA70 /* Config request codes */ #define CP210X_IFC_ENABLE 0x00 diff --git a/src/tusb_option.h b/src/tusb_option.h index a41f5a07e..3d290ae66 100644 --- a/src/tusb_option.h +++ b/src/tusb_option.h @@ -441,6 +441,12 @@ #define CFG_TUH_CDC_CP210X 0 #endif +#ifndef CFG_TUH_CDC_CP210X_PID_LIST + // List of product IDs that can use the CP210X CDC driver + #define CFG_TUH_CDC_CP210X_PID_LIST \ + 0xEA60, 0xEA70 +#endif + #ifndef CFG_TUH_HID #define CFG_TUH_HID 0 #endif -- cgit v1.3.1 From ac418f4d25400c12864b242f94215664dc5d9229 Mon Sep 17 00:00:00 2001 From: Angel Molina Date: Sat, 9 Dec 2023 23:13:53 +0100 Subject: Fix strict-overflow warning when compiling with gcc >= 12 --- src/class/audio/audio_device.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/class') diff --git a/src/class/audio/audio_device.c b/src/class/audio/audio_device.c index 9af999992..731c39b54 100644 --- a/src/class/audio/audio_device.c +++ b/src/class/audio/audio_device.c @@ -1565,7 +1565,7 @@ uint16_t audiod_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uin { 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; - while (p_desc < p_desc_end) + while (p_desc_end - p_desc > 0) { if (tu_desc_type(p_desc) == TUSB_DESC_ENDPOINT) { -- cgit v1.3.1 From 506617d4b39ba9118a24477a4be6db9733e2e2f1 Mon Sep 17 00:00:00 2001 From: Ángel Molina Núñez Date: Sun, 10 Dec 2023 17:04:46 +0100 Subject: Add comment to explain why the condition changes --- src/class/audio/audio_device.c | 1 + 1 file changed, 1 insertion(+) (limited to 'src/class') diff --git a/src/class/audio/audio_device.c b/src/class/audio/audio_device.c index 731c39b54..d438d0715 100644 --- a/src/class/audio/audio_device.c +++ b/src/class/audio/audio_device.c @@ -1565,6 +1565,7 @@ uint16_t audiod_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uin { 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) { if (tu_desc_type(p_desc) == TUSB_DESC_ENDPOINT) -- cgit v1.3.1 From 9a7e23379ccd4fe572af824c09d6113401412522 Mon Sep 17 00:00:00 2001 From: Oliver Larsson Date: Mon, 11 Dec 2023 09:36:10 +0100 Subject: Add configuration option CFG_TUH_CDC_FTDI_PID_LIST to tusb_option.h --- src/class/cdc/cdc_host.c | 2 +- src/class/cdc/serial/ftdi_sio.h | 5 +---- src/tusb_option.h | 6 ++++++ 3 files changed, 8 insertions(+), 5 deletions(-) (limited to 'src/class') diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index a6af9b84d..a6dfb45ae 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -90,7 +90,7 @@ static bool acm_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfe #if CFG_TUH_CDC_FTDI #include "serial/ftdi_sio.h" -static uint16_t const ftdi_pids[] = { TU_FTDI_PID_LIST }; +static uint16_t const ftdi_pids[] = { CFG_TUH_CDC_FTDI_PID_LIST }; enum { FTDI_PID_COUNT = sizeof(ftdi_pids) / sizeof(ftdi_pids[0]) }; diff --git a/src/class/cdc/serial/ftdi_sio.h b/src/class/cdc/serial/ftdi_sio.h index 6916e4031..0825f0719 100644 --- a/src/class/cdc/serial/ftdi_sio.h +++ b/src/class/cdc/serial/ftdi_sio.h @@ -25,11 +25,8 @@ #ifndef TUSB_FTDI_SIO_H #define TUSB_FTDI_SIO_H -// VID/PID for matching FTDI devices +// VID for matching FTDI devices #define TU_FTDI_VID 0x0403 -#define TU_FTDI_PID_LIST \ - 0x6001, 0x6006, 0x6010, 0x6011, 0x6014, 0x6015, 0x8372, 0xFBFA, \ - 0xcd18 // Commands #define FTDI_SIO_RESET 0 /* Reset the port */ diff --git a/src/tusb_option.h b/src/tusb_option.h index 900784388..7597392d6 100644 --- a/src/tusb_option.h +++ b/src/tusb_option.h @@ -442,6 +442,12 @@ #define CFG_TUH_CDC_FTDI 0 #endif +#ifndef CFG_TUH_CDC_FTDI_PID_LIST + // List of product IDs that can use the FTDI CDC driver + #define CFG_TUH_CDC_FTDI_PID_LIST \ + 0x6001, 0x6006, 0x6010, 0x6011, 0x6014, 0x6015, 0x8372, 0xFBFA, 0xCD18 +#endif + #ifndef CFG_TUH_CDC_CP210X // CP210X is not part of CDC class, only to re-use CDC driver API #define CFG_TUH_CDC_CP210X 0 -- cgit v1.3.1 From c2bbcc9f60a2b7293fad4e24468d3f045fde28ee Mon Sep 17 00:00:00 2001 From: IngHK Date: Tue, 26 Dec 2023 20:14:03 +0100 Subject: initial support of CH34x CDC device --- examples/host/cdc_msc_hid/src/tusb_config.h | 1 + .../host/cdc_msc_hid_freertos/src/tusb_config.h | 1 + src/class/cdc/cdc_host.c | 466 ++++++++++++++++++++- src/class/cdc/serial/ch34x.h | 113 +++++ src/tusb_option.h | 17 + 5 files changed, 595 insertions(+), 3 deletions(-) create mode 100644 src/class/cdc/serial/ch34x.h (limited to 'src/class') diff --git a/examples/host/cdc_msc_hid/src/tusb_config.h b/examples/host/cdc_msc_hid/src/tusb_config.h index 61abb85eb..76d59c316 100644 --- a/examples/host/cdc_msc_hid/src/tusb_config.h +++ b/examples/host/cdc_msc_hid/src/tusb_config.h @@ -105,6 +105,7 @@ #define CFG_TUH_CDC 1 // CDC ACM #define CFG_TUH_CDC_FTDI 1 // FTDI Serial. FTDI is not part of CDC class, only to re-use CDC driver API #define CFG_TUH_CDC_CP210X 1 // CP210x Serial. CP210X is not part of CDC class, only to re-use CDC driver API +#define CFG_TUH_CDC_CH34X 1 // CH340 or CH341 Serial. CH34X is not part of CDC class, only to re-use CDC driver API #define CFG_TUH_HID (3*CFG_TUH_DEVICE_MAX) // typical keyboard + mouse device can have 3-4 HID interfaces #define CFG_TUH_MSC 1 #define CFG_TUH_VENDOR 0 diff --git a/examples/host/cdc_msc_hid_freertos/src/tusb_config.h b/examples/host/cdc_msc_hid_freertos/src/tusb_config.h index c661f47be..bb7c3388d 100644 --- a/examples/host/cdc_msc_hid_freertos/src/tusb_config.h +++ b/examples/host/cdc_msc_hid_freertos/src/tusb_config.h @@ -110,6 +110,7 @@ #define CFG_TUH_CDC 1 // CDC ACM #define CFG_TUH_CDC_FTDI 1 // FTDI Serial. FTDI is not part of CDC class, only to re-use CDC driver API #define CFG_TUH_CDC_CP210X 1 // CP210x Serial. CP210X is not part of CDC class, only to re-use CDC driver API +#define CFG_TUH_CDC_CH34X 1 // CH340 or CH341 Serial. CH34X is not part of CDC class, only to re-use CDC driver API #define CFG_TUH_HID (3*CFG_TUH_DEVICE_MAX) // typical keyboard + mouse device can have 3-4 HID interfaces #define CFG_TUH_MSC 1 #define CFG_TUH_VENDOR 0 diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index a6dfb45ae..9b5186e0c 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -2,6 +2,7 @@ * The MIT License (MIT) * * Copyright (c) 2019 Ha Thach (tinyusb.org) + * Copyright (c) 2023 Heiko Kuester (CH34x support) * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -69,7 +70,16 @@ typedef struct { uint8_t rx_ff_buf[CFG_TUH_CDC_TX_BUFSIZE]; CFG_TUH_MEM_ALIGN uint8_t rx_ep_buf[CFG_TUH_CDC_TX_EPSIZE]; } stream; - + #if CFG_TUH_CDC_CH34X + struct { + uint32_t baud_rate; + uint8_t mcr; + uint8_t msr; + uint8_t lcr; + uint32_t quirks; + uint8_t version; + } ch34x; + #endif } cdch_interface_t; CFG_TUH_MEM_SECTION @@ -121,6 +131,23 @@ static bool cp210x_set_modem_ctrl(cdch_interface_t* p_cdc, uint16_t line_state, static bool cp210x_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data); #endif +//------------- CH34x prototypes -------------// +#if CFG_TUH_CDC_CH34X +#include "serial/ch34x.h" + +static uint16_t const ch34x_vids_pids[][2] = { CFG_TUH_CDC_CH34X_VID_PID_LIST }; +enum { + CH34X_VID_PID_COUNT = sizeof ( ch34x_vids_pids ) / sizeof ( ch34x_vids_pids[0] ) +}; + +static bool ch34x_open ( uint8_t daddr, tusb_desc_interface_t const *itf_desc, uint16_t max_len ); +static void ch34x_process_config ( tuh_xfer_t* xfer ); + +static bool ch34x_set_modem_ctrl ( cdch_interface_t* p_cdc, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data ); +static bool ch34x_set_baudrate ( cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data ); +#endif + + enum { SERIAL_DRIVER_ACM = 0, @@ -131,6 +158,10 @@ enum { #if CFG_TUH_CDC_CP210X SERIAL_DRIVER_CP210X, #endif + +#if CFG_TUH_CDC_CH34X + SERIAL_DRIVER_CH34X, +#endif }; typedef struct { @@ -159,6 +190,13 @@ static const cdch_serial_driver_t serial_drivers[] = { .set_baudrate = cp210x_set_baudrate }, #endif + + #if CFG_TUH_CDC_CH34X + { .process_set_config = ch34x_process_config, + .set_control_line_state = ch34x_set_modem_ctrl, + .set_baudrate = ch34x_set_baudrate + }, +#endif }; enum { @@ -426,6 +464,12 @@ static void cdch_internal_control_complete(tuh_xfer_t* xfer) break; #endif + #if CFG_TUH_CDC_CH34X + case SERIAL_DRIVER_CH34X: + TU_ASSERT(false, ); // see special ch34x_control_complete function + break; + #endif + default: break; } } @@ -641,7 +685,7 @@ bool cdch_open(uint8_t rhport, uint8_t daddr, tusb_desc_interface_t const *itf_d { return acm_open(daddr, itf_desc, max_len); } - #if CFG_TUH_CDC_FTDI || CFG_TUH_CDC_CP210X + #if CFG_TUH_CDC_FTDI || CFG_TUH_CDC_CP210X || CFG_TUH_CDC_CH34X else if ( 0xff == itf_desc->bInterfaceClass ) { uint16_t vid, pid; @@ -666,8 +710,16 @@ bool cdch_open(uint8_t rhport, uint8_t daddr, tusb_desc_interface_t const *itf_d } } #endif + + #if CFG_TUH_CDC_CH34X + for (size_t i = 0; i < CH34X_VID_PID_COUNT; i++) { + if ( ch34x_vids_pids[i][0] == vid && ch34x_vids_pids[i][1] == pid ) { + return ch34x_open(daddr, itf_desc, max_len); + } + } + #endif } - #endif + #endif // CFG_TUH_CDC_FTDI || CFG_TUH_CDC_CP210X || CFG_TUH_CDC_CH34X return false; } @@ -1176,4 +1228,412 @@ static void cp210x_process_config(tuh_xfer_t* xfer) { #endif +//--------------------------------------------------------------------+ +// CH34x +//--------------------------------------------------------------------+ + +#if CFG_TUH_CDC_CH34X + +enum { + CONFIG_CH34X_STEP1 = 0, + CONFIG_CH34X_STEP2, + CONFIG_CH34X_STEP3, + CONFIG_CH34X_STEP4, + CONFIG_CH34X_STEP5, + CONFIG_CH34X_STEP6, + CONFIG_CH34X_STEP7, + CONFIG_CH34X_STEP8, + CONFIG_CH34X_COMPLETE +}; + +static bool ch34x_open ( uint8_t daddr, tusb_desc_interface_t const *itf_desc, uint16_t max_len ) +{ + // CH34x Interface includes 1 vendor interface + 3 bulk endpoints + TU_VERIFY ( itf_desc->bNumEndpoints == 3 ); + TU_VERIFY ( sizeof ( tusb_desc_interface_t ) + 2 * sizeof ( tusb_desc_endpoint_t ) <= max_len ); + + cdch_interface_t *p_cdc = make_new_itf ( daddr, itf_desc ); + TU_VERIFY ( p_cdc ); + + TU_LOG_DRV ( "CH34x opened\r\n" ); + p_cdc->serial_drid = SERIAL_DRIVER_CH34X; + + // endpoint pair + tusb_desc_endpoint_t const * desc_ep = (tusb_desc_endpoint_t const *) tu_desc_next ( itf_desc ); + + // data endpoints expected to be in pairs + return open_ep_stream_pair ( p_cdc, desc_ep ); +} + +static bool ch34x_set_request ( cdch_interface_t* p_cdc, uint8_t direction, uint8_t request, uint16_t value, uint16_t index, uint8_t* buffer, uint16_t length, tuh_xfer_cb_t complete_cb, uintptr_t user_data ) +{ + tusb_control_request_t const request_setup = { + .bmRequestType_bit = { + .recipient = TUSB_REQ_RCPT_DEVICE, + .type = TUSB_REQ_TYPE_VENDOR, + .direction = direction + }, + .bRequest = request, + .wValue = tu_htole16 ( value ), + .wIndex = tu_htole16 ( index ), + .wLength = tu_htole16 ( length ) + }; + + // use usbh enum buf since application variable does not live long enough + uint8_t* enum_buf = NULL; + + if ( buffer && length > 0 ) { + enum_buf = usbh_get_enum_buf(); + tu_memcpy_s ( enum_buf, CFG_TUH_ENUMERATION_BUFSIZE, buffer, length ); + } + + tuh_xfer_t xfer = { + .daddr = p_cdc->daddr, + .ep_addr = 0, + .setup = &request_setup, + .buffer = enum_buf, + .complete_cb = complete_cb, + // CH34x needs a special handling of bInterfaceNumber, because wIndex is used for other purposes and not for bInterfaceNumber + .user_data = (uintptr_t)( ( p_cdc->bInterfaceNumber & 0xff ) << 8 ) | ( user_data & 0xff ) + }; + + return tuh_control_xfer ( &xfer ); + return false; +} + +static bool ch341_control_out ( cdch_interface_t* p_cdc, uint8_t request, uint16_t value, uint16_t index, tuh_xfer_cb_t complete_cb, uintptr_t user_data ) +{ + return ch34x_set_request ( p_cdc, TUSB_DIR_OUT, request, value, index, /* buffer */ NULL, /* length */ 0, complete_cb, user_data ); +} + +static bool ch341_control_in ( cdch_interface_t* p_cdc, uint8_t request, uint16_t value, uint16_t index, uint8_t *buffer, uint16_t buffersize, tuh_xfer_cb_t complete_cb, uintptr_t user_data ) +{ + return ch34x_set_request ( p_cdc, TUSB_DIR_IN, request, value, index, buffer, buffersize, complete_cb, user_data ); +} + +static int32_t ch341_write_reg ( cdch_interface_t* p_cdc, uint16_t reg, uint16_t value, tuh_xfer_cb_t complete_cb, uintptr_t user_data ) +{ + return ch341_control_out ( p_cdc, CH341_REQ_WRITE_REG, /* value */ reg, /* index */ value, complete_cb, user_data ); +} + +static int32_t ch341_read_reg_request ( cdch_interface_t* p_cdc, uint16_t reg, uint8_t *buffer, uint16_t buffersize, tuh_xfer_cb_t complete_cb, uintptr_t user_data ) +{ + return ch341_control_in ( p_cdc, CH341_REQ_READ_REG, reg, /* index */ 0, buffer, buffersize, complete_cb, user_data ); +} + +/* + * The device line speed is given by the following equation: + * + * baudrate = 48000000 / (2^(12 - 3 * ps - fact) * div), where + * + * 0 <= ps <= 3, + * 0 <= fact <= 1, + * 2 <= div <= 256 if fact = 0, or + * 9 <= div <= 256 if fact = 1 + */ +// calculate baudrate devisors +// Parts of this functions have been taken over from Linux driver /drivers/usb/serial/ch341.c +static int32_t ch341_get_divisor ( cdch_interface_t* p_cdc, uint32_t speed ) +{ + uint32_t fact, div, clk_div; + bool force_fact0 = false; + int32_t ps; + static const uint32_t ch341_min_rates[] = { + CH341_MIN_RATE(0), + CH341_MIN_RATE(1), + CH341_MIN_RATE(2), + CH341_MIN_RATE(3), + }; + + /* + * Clamp to supported range, this makes the (ps < 0) and (div < 2) + * sanity checks below redundant. + */ + inline uint32_t max ( uint32_t val, uint32_t maxval ) { return val > maxval ? val : maxval; } + inline uint32_t min ( uint32_t val, uint32_t minval ) { return val < minval ? val : minval; } + inline uint32_t clamp_val ( uint32_t val, uint32_t minval, uint32_t maxval ) { return min ( max ( val, minval ), maxval ); } + speed = clamp_val(speed, CH341_MIN_BPS, CH341_MAX_BPS); + + /* + * Start with highest possible base clock (fact = 1) that will give a + * divisor strictly less than 512. + */ + fact = 1; + for (ps = 3; ps >= 0; ps--) { + if (speed > ch341_min_rates[ps]) + break; + } + + if (ps < 0) + return -EINVAL; + + /* Determine corresponding divisor, rounding down. */ + clk_div = CH341_CLK_DIV(ps, fact); + div = CH341_CLKRATE / (clk_div * speed); + + /* Some devices require a lower base clock if ps < 3. */ + if (ps < 3 && (p_cdc->ch34x.quirks & CH341_QUIRK_LIMITED_PRESCALER)) + force_fact0 = true; + + /* Halve base clock (fact = 0) if required. */ + if (div < 9 || div > 255 || force_fact0) { + div /= 2; + clk_div *= 2; + fact = 0; + } + + if (div < 2) + return -EINVAL; + + /* + * Pick next divisor if resulting rate is closer to the requested one, + * scale up to avoid rounding errors on low rates. + */ + if (16 * CH341_CLKRATE / (clk_div * div) - 16 * speed >= + 16 * speed - 16 * CH341_CLKRATE / (clk_div * (div + 1))) + div++; + + /* + * Prefer lower base clock (fact = 0) if even divisor. + * + * Note that this makes the receiver more tolerant to errors. + */ + if (fact == 1 && div % 2 == 0) { + div /= 2; + fact = 0; + } + + return (0x100 - div) << 8 | fact << 2 | ps; +} + +// set baudrate (low level) +// do not confuse with ch34x_set_baudrate +// Parts of this functions have been taken over from Linux driver /drivers/usb/serial/ch341.c +static int32_t ch341_set_baudrate ( cdch_interface_t* p_cdc, uint32_t baud_rate, tuh_xfer_cb_t complete_cb, uintptr_t user_data ) +{ + int val; + + if (!baud_rate) + return -EINVAL; + + val = ch341_get_divisor(p_cdc, baud_rate); + if (val < 0) + return -EINVAL; + + /* + * CH341A buffers data until a full endpoint-size packet (32 bytes) + * has been received unless bit 7 is set. + * + * At least one device with version 0x27 appears to have this bit + * inverted. + */ + if ( p_cdc->ch34x.version > 0x27 ) + val |= BIT(7); + + return ch341_write_reg ( p_cdc, CH341_REG_DIVISOR << 8 | CH341_REG_PRESCALER, val, complete_cb, user_data ); +} + +// set lcr register +// Parts of this functions have been taken over from Linux driver /drivers/usb/serial/ch341.c +static int32_t ch341_set_lcr ( cdch_interface_t* p_cdc, uint8_t lcr, tuh_xfer_cb_t complete_cb, uintptr_t user_data ) +{ + /* + * Chip versions before version 0x30 as read using + * CH341_REQ_READ_VERSION used separate registers for line control + * (stop bits, parity and word length). Version 0x30 and above use + * CH341_REG_LCR only and CH341_REG_LCR2 is always set to zero. + */ + if ( p_cdc->ch34x.version < 0x30 ) + return 0; + + return ch341_write_reg ( p_cdc, CH341_REG_LCR2 << 8 | CH341_REG_LCR, lcr, complete_cb, user_data ); +} + +// set handshake (modem controls) +// Parts of this functions have been taken over from Linux driver /drivers/usb/serial/ch341.c +static int32_t ch341_set_handshake ( cdch_interface_t* p_cdc, uint8_t control, tuh_xfer_cb_t complete_cb, uintptr_t user_data ) +{ + return ch341_control_out ( p_cdc, CH341_REQ_MODEM_CTRL, /* value */ ~control, /* index */ 0, complete_cb, user_data ); +} + +// detect quirks (special versions of CH34x) +// Parts of this functions have been taken over from Linux driver /drivers/usb/serial/ch341.c +static int32_t ch341_detect_quirks ( tuh_xfer_t* xfer, cdch_interface_t* p_cdc, uint8_t step, uint8_t *buffer, uint16_t buffersize, tuh_xfer_cb_t complete_cb, uintptr_t user_data ) +{ + /* + * A subset of CH34x devices does not support all features. The + * prescaler is limited and there is no support for sending a RS232 + * break condition. A read failure when trying to set up the latter is + * used to detect these devices. + */ + switch ( step ) + { + case 1: + p_cdc->ch34x.quirks = 0; + return ch341_read_reg_request ( p_cdc, CH341_REG_BREAK, buffer, buffersize, complete_cb, user_data ); + break; + case 2: + if ( xfer->result != XFER_RESULT_SUCCESS ) + p_cdc->ch34x.quirks |= CH341_QUIRK_LIMITED_PRESCALER | CH341_QUIRK_SIMULATE_BREAK; + return true; + break; + default: + TU_ASSERT ( false ); // suspicious step + break; + } +} + +// internal control complete to update state such as line state, encoding +// CH34x needs a special interface recovery due to abnormal wIndex usage +static void ch34x_control_complete(tuh_xfer_t* xfer) +{ + uint8_t const itf_num = (uint8_t)( ( xfer->user_data & 0xff00 ) >> 8 ); + uint8_t const idx = tuh_cdc_itf_get_index ( xfer->daddr, itf_num ); + cdch_interface_t *p_cdc = get_itf ( idx ); + TU_ASSERT ( p_cdc, ); + TU_ASSERT ( p_cdc->serial_drid == SERIAL_DRIVER_CH34X, ); // ch34x_control_complete is only used for CH34x + + if (xfer->result == XFER_RESULT_SUCCESS) { + switch (xfer->setup->bRequest) { + case CH341_REQ_WRITE_REG: { // register write request + switch ( tu_le16toh ( xfer->setup->wValue ) ) { + case ( CH341_REG_DIVISOR << 8 | CH341_REG_PRESCALER ): { // baudrate write + p_cdc->line_coding.bit_rate = p_cdc->ch34x.baud_rate; + break; + } + default: { + TU_ASSERT(false, ); // unexpected register write + break; + } + } + break; + } + default: { + TU_ASSERT(false, ); // unexpected request + break; + } + } + xfer->complete_cb = p_cdc->user_control_cb; + if (xfer->complete_cb) + xfer->complete_cb(xfer); + } +} + +static bool ch34x_set_baudrate ( cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data ) // do not confuse with ch341_set_baudrate +{ + TU_LOG_DRV("CDC CH34x Set BaudRate = %lu\r\n", baudrate); + uint32_t baud_le = tu_htole32(baudrate); + p_cdc->ch34x.baud_rate = baudrate; + p_cdc->user_control_cb = complete_cb; + return ch341_set_baudrate ( p_cdc, baud_le, complete_cb ? ch34x_control_complete : NULL, user_data ); +} + +static bool ch34x_set_modem_ctrl ( cdch_interface_t* p_cdc, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data ) +{ + TU_LOG_DRV("CDC CH34x Set Control Line State\r\n"); + // todo later + return false; +} + +static void ch34x_process_config ( tuh_xfer_t* xfer ) +{ + uintptr_t const state = xfer->user_data & 0xff; + // CH34x needs a special handling of bInterfaceNumber, because wIndex is used for other purposes and not for bInterfaceNumber + uint8_t const itf_num = (uint8_t)( ( xfer->user_data & 0xff00 ) >> 8 ); + uint8_t const idx = tuh_cdc_itf_get_index ( xfer->daddr, itf_num ); + cdch_interface_t *p_cdc = get_itf ( idx ); + uint8_t buffer [ CH34X_BUFFER_SIZE ]; + cdc_line_coding_t line_coding = CFG_TUH_CDC_LINE_CODING_ON_ENUM; + TU_ASSERT ( p_cdc, ); + + if ( state == 0 ) { + // defaults + p_cdc->ch34x.baud_rate = DEFAULT_BAUD_RATE; + p_cdc->ch34x.mcr = 0; + p_cdc->ch34x.msr = 0; + p_cdc->ch34x.quirks = 0; + p_cdc->ch34x.version = 0; + /* + * Some CH340 devices appear unable to change the initial LCR + * settings, so set a sane 8N1 default. + */ + p_cdc->ch34x.lcr = CH341_LCR_ENABLE_RX | CH341_LCR_ENABLE_TX | CH341_LCR_CS8; + } + // This process flow has been taken over from Linux driver /drivers/usb/serial/ch341.c + switch ( state ) { + case CONFIG_CH34X_STEP1: // request version read + TU_ASSERT ( ch341_control_in ( p_cdc, /* request */ CH341_REQ_READ_VERSION, /* value */ 0, /* index */ 0, buffer, CH34X_BUFFER_SIZE, ch34x_process_config, CONFIG_CH34X_STEP2 ), ); + break; + case CONFIG_CH34X_STEP2: // handle version read data, request to init CH34x + p_cdc->ch34x.version = xfer->buffer[0]; + TU_LOG_DRV ( "Chip version=%02x\r\n", p_cdc->ch34x.version ); + TU_ASSERT ( ch341_control_out ( p_cdc, /* request */ CH341_REQ_SERIAL_INIT, /* value */ 0, /* index */ 0, ch34x_process_config, CONFIG_CH34X_STEP3 ), ); + break; + case CONFIG_CH34X_STEP3: // set baudrate with default values (see above) + TU_ASSERT ( ch341_set_baudrate ( p_cdc, p_cdc->ch34x.baud_rate, ch34x_process_config, CONFIG_CH34X_STEP4 ) > 0, ); + break; + case CONFIG_CH34X_STEP4: // set line controls with default values (see above) + TU_ASSERT ( ch341_set_lcr ( p_cdc, p_cdc->ch34x.lcr, ch34x_process_config, CONFIG_CH34X_STEP5 ) > 0, ); + break; + case CONFIG_CH34X_STEP5: // set handshake RTS/DTR + TU_ASSERT ( ch341_set_handshake ( p_cdc, p_cdc->ch34x.mcr, ch34x_process_config, CONFIG_CH34X_STEP6 ) > 0, ); + break; + case CONFIG_CH34X_STEP6: // detect quirks step 1 + TU_ASSERT ( ch341_detect_quirks ( xfer, p_cdc, /* step */ 1, buffer, CH34X_BUFFER_SIZE, ch34x_process_config, CONFIG_CH34X_STEP7 ) > 0, ); + break; + case CONFIG_CH34X_STEP7: // detect quirks step 2 and set baudrate with configured values + TU_ASSERT ( ch341_detect_quirks ( xfer, p_cdc, /* step */ 2, NULL, 0, NULL, 0 ) > 0, ); +#ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM + TU_ASSERT ( ch34x_set_baudrate ( p_cdc, line_coding.bit_rate, ch34x_process_config, CONFIG_CH34X_STEP8 ), ); +#else + TU_ATTR_FALLTHROUGH; #endif + break; + case CONFIG_CH34X_STEP8: // set data/stop bit quantities, parity +#ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM + p_cdc->ch34x.lcr = CH341_LCR_ENABLE_RX | CH341_LCR_ENABLE_TX; + switch ( line_coding.data_bits ) { + case 5: + p_cdc->ch34x.lcr |= CH341_LCR_CS5; + break; + case 6: + p_cdc->ch34x.lcr |= CH341_LCR_CS6; + break; + case 7: + p_cdc->ch34x.lcr |= CH341_LCR_CS7; + break; + case 8: + p_cdc->ch34x.lcr |= CH341_LCR_CS8; + break; + default: + TU_ASSERT ( false, ); // not supported data_bits + p_cdc->ch34x.lcr |= CH341_LCR_CS8; + break; + } + if ( line_coding.parity != CDC_LINE_CODING_PARITY_NONE ) { + p_cdc->ch34x.lcr |= CH341_LCR_ENABLE_PAR; + if ( line_coding.parity == CDC_LINE_CODING_PARITY_EVEN || line_coding.parity == CDC_LINE_CODING_PARITY_SPACE ) + p_cdc->ch34x.lcr |= CH341_LCR_PAR_EVEN; + if ( line_coding.parity == CDC_LINE_CODING_PARITY_MARK || line_coding.parity == CDC_LINE_CODING_PARITY_SPACE ) + p_cdc->ch34x.lcr |= CH341_LCR_MARK_SPACE; + } + TU_ASSERT ( line_coding.stop_bits == CDC_LINE_CODING_STOP_BITS_1 || line_coding.stop_bits == CDC_LINE_CODING_STOP_BITS_2, ); // not supported 1.5 stop bits + if ( line_coding.stop_bits == CDC_LINE_CODING_STOP_BITS_2 ) + p_cdc->ch34x.lcr |= CH341_LCR_STOP_BITS_2; + TU_ASSERT ( ch341_set_lcr ( p_cdc, p_cdc->ch34x.lcr, ch34x_process_config, CONFIG_CH34X_COMPLETE ) > 0, ); +#else + TU_ATTR_FALLTHROUGH; +#endif + break; + case CONFIG_CH34X_COMPLETE: + set_config_complete ( p_cdc, idx, itf_num ); + break; + default: + TU_ASSERT ( false, ); + break; + } +} + +#endif // CFG_TUH_CDC_CH34X + +#endif // (CFG_TUH_ENABLED && CFG_TUH_CDC) diff --git a/src/class/cdc/serial/ch34x.h b/src/class/cdc/serial/ch34x.h new file mode 100644 index 000000000..94e18b252 --- /dev/null +++ b/src/class/cdc/serial/ch34x.h @@ -0,0 +1,113 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2023 Heiko Kuester (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#ifndef _CH34X_H_ +#define _CH34X_H_ + +#include + +#define BIT(nr) ( (uint32_t)1 << (nr) ) + +#define CH34X_BUFFER_SIZE 2 + +// The following defines have been taken over from Linux driver /drivers/usb/serial/ch341.c + +#define DEFAULT_BAUD_RATE 9600 + +/* flags for IO-Bits */ +#define CH341_BIT_RTS (1 << 6) +#define CH341_BIT_DTR (1 << 5) + +/******************************/ +/* interrupt pipe definitions */ +/******************************/ +/* always 4 interrupt bytes */ +/* first irq byte normally 0x08 */ +/* second irq byte base 0x7d + below */ +/* third irq byte base 0x94 + below */ +/* fourth irq byte normally 0xee */ + +/* second interrupt byte */ +#define CH341_MULT_STAT 0x04 /* multiple status since last interrupt event */ + +/* status returned in third interrupt answer byte, inverted in data + from irq */ +#define CH341_BIT_CTS 0x01 +#define CH341_BIT_DSR 0x02 +#define CH341_BIT_RI 0x04 +#define CH341_BIT_DCD 0x08 +#define CH341_BITS_MODEM_STAT 0x0f /* all bits */ + +/* Break support - the information used to implement this was gleaned from + * the Net/FreeBSD uchcom.c driver by Takanori Watanabe. Domo arigato. + */ + +// USB requests +#define CH341_REQ_READ_VERSION 0x5F // dec 95 +#define CH341_REQ_WRITE_REG 0x9A +#define CH341_REQ_READ_REG 0x95 +#define CH341_REQ_SERIAL_INIT 0xA1 +#define CH341_REQ_MODEM_CTRL 0xA4 + +// CH34x registers +#define CH341_REG_BREAK 0x05 +#define CH341_REG_PRESCALER 0x12 +#define CH341_REG_DIVISOR 0x13 +#define CH341_REG_LCR 0x18 +#define CH341_REG_LCR2 0x25 + +#define CH341_NBREAK_BITS 0x01 + +// line control bits +#define CH341_LCR_ENABLE_RX 0x80 +#define CH341_LCR_ENABLE_TX 0x40 +#define CH341_LCR_MARK_SPACE 0x20 +#define CH341_LCR_PAR_EVEN 0x10 +#define CH341_LCR_ENABLE_PAR 0x08 +#define CH341_LCR_STOP_BITS_2 0x04 +#define CH341_LCR_CS8 0x03 +#define CH341_LCR_CS7 0x02 +#define CH341_LCR_CS6 0x01 +#define CH341_LCR_CS5 0x00 + +#define CH341_QUIRK_LIMITED_PRESCALER BIT(0) +#define CH341_QUIRK_SIMULATE_BREAK BIT(1) + +#define CH341_CLKRATE 48000000 +#define CH341_CLK_DIV(ps, fact) (1 << (12 - 3 * (ps) - (fact))) +#define CH341_MIN_RATE(ps) (CH341_CLKRATE / (CH341_CLK_DIV((ps), 1) * 512)) + +/* Supported range is 46 to 3000000 bps. */ +#define CH341_MIN_BPS DIV_ROUND_UP(CH341_CLKRATE, CH341_CLK_DIV(0, 0) * 256) +#define CH341_MAX_BPS (CH341_CLKRATE / (CH341_CLK_DIV(3, 0) * 2)) + +#define DIV_ROUND_UP __KERNEL_DIV_ROUND_UP +#define __KERNEL_DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d)) + +// error codes +#define EINVAL 22 /* Invalid argument */ + +#endif /* _CH34X_H_ */ diff --git a/src/tusb_option.h b/src/tusb_option.h index a76281c0c..13151a07b 100644 --- a/src/tusb_option.h +++ b/src/tusb_option.h @@ -470,6 +470,23 @@ 0xEA60, 0xEA70 #endif +#ifndef CFG_TUH_CDC_CH34X + // CH34X is not part of CDC class, only to re-use CDC driver API + #define CFG_TUH_CDC_CH34X 0 +#endif + +#ifndef CFG_TUH_CDC_CH34X_VID_PID_LIST + // List of product IDs that can use the CH34X CDC driver + #define CFG_TUH_CDC_CH34X_VID_PID_LIST \ + { 0x1a86, 0x7523 }, /* ch340 chip */ \ + { 0x1a86, 0x7522 }, /* ch340k chip */ \ + { 0x1a86, 0x5523 }, /* ch341 chip */ \ + { 0x1a86, 0xe523 }, /* ch330 chip */ \ + { 0x4348, 0x5523 }, /* ch340 custom chip */ \ + { 0x2184, 0x0057 }, /* overtaken from Linux driver /drivers/usb/serial/ch341.c */ \ + { 0x9986, 0x7523 } /* overtaken from Linux driver /drivers/usb/serial/ch341.c */ +#endif + #ifndef CFG_TUH_HID #define CFG_TUH_HID 0 #endif -- cgit v1.3.1 From 91f65a36bfb1d4516c39306e77fb15d4e1c2fc0b Mon Sep 17 00:00:00 2001 From: IngHK Date: Tue, 9 Jan 2024 09:53:54 +0100 Subject: [CDC] host: moved acm_open to other acm prototypes --- src/class/cdc/cdc_host.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'src/class') diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index a6dfb45ae..b20da3723 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -80,6 +80,7 @@ static cdch_interface_t cdch_data[CFG_TUH_CDC]; //--------------------------------------------------------------------+ //------------- ACM prototypes -------------// +static bool acm_open(uint8_t daddr, tusb_desc_interface_t const *itf_desc, uint16_t max_len); static void acm_process_config(tuh_xfer_t* xfer); static bool acm_set_line_coding(cdch_interface_t* p_cdc, cdc_line_coding_t const* line_coding, tuh_xfer_cb_t complete_cb, uintptr_t user_data); @@ -605,8 +606,6 @@ bool cdch_xfer_cb(uint8_t daddr, uint8_t ep_addr, xfer_result_t event, uint32_t // Enumeration //--------------------------------------------------------------------+ -static bool acm_open(uint8_t daddr, tusb_desc_interface_t const *itf_desc, uint16_t max_len); - static bool open_ep_stream_pair(cdch_interface_t* p_cdc, tusb_desc_endpoint_t const *desc_ep) { for(size_t i=0; i<2; i++) -- cgit v1.3.1 From c619a861414d2edeb34c5f59b74ed0fe28b39172 Mon Sep 17 00:00:00 2001 From: IngHK Date: Thu, 11 Jan 2024 08:53:47 +0100 Subject: bInterfaceClass number replaced by define --- src/class/cdc/cdc_host.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/class') diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index b20da3723..79477ef53 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -641,7 +641,7 @@ bool cdch_open(uint8_t rhport, uint8_t daddr, tusb_desc_interface_t const *itf_d return acm_open(daddr, itf_desc, max_len); } #if CFG_TUH_CDC_FTDI || CFG_TUH_CDC_CP210X - else if ( 0xff == itf_desc->bInterfaceClass ) + else if ( TUSB_CLASS_VENDOR_SPECIFIC == itf_desc->bInterfaceClass ) { uint16_t vid, pid; TU_VERIFY(tuh_vid_pid_get(daddr, &vid, &pid)); -- cgit v1.3.1 From d92eb38c211899ed963250272d882fcac8dbaf9c Mon Sep 17 00:00:00 2001 From: hathach Date: Mon, 15 Jan 2024 16:56:18 +0700 Subject: change code style --- src/class/cdc/cdc_host.c | 526 +++++++++++++++++++++-------------------------- 1 file changed, 235 insertions(+), 291 deletions(-) (limited to 'src/class') diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index 4f36f7517..05a061487 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -106,7 +106,7 @@ static bool acm_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfe static uint16_t const ftdi_pids[] = { CFG_TUH_CDC_FTDI_PID_LIST }; enum { - FTDI_PID_COUNT = sizeof(ftdi_pids) / sizeof(ftdi_pids[0]) + FTDI_PID_COUNT = TU_ARRAY_SIZE(ftdi_pids) }; // Store last request baudrate since divisor to baudrate is not easy @@ -114,7 +114,6 @@ static uint32_t _ftdi_requested_baud; static bool ftdi_open(uint8_t daddr, const tusb_desc_interface_t *itf_desc, uint16_t max_len); static void ftdi_process_config(tuh_xfer_t* xfer); - static bool ftdi_sio_set_modem_ctrl(cdch_interface_t* p_cdc, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data); static bool ftdi_sio_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data); #endif @@ -125,12 +124,11 @@ static bool ftdi_sio_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, tu static uint16_t const cp210x_pids[] = { CFG_TUH_CDC_CP210X_PID_LIST }; enum { - CP210X_PID_COUNT = sizeof(cp210x_pids) / sizeof(cp210x_pids[0]) + CP210X_PID_COUNT = TU_ARRAY_SIZE(cp210x_pids) }; static bool cp210x_open(uint8_t daddr, tusb_desc_interface_t const *itf_desc, uint16_t max_len); static void cp210x_process_config(tuh_xfer_t* xfer); - static bool cp210x_set_modem_ctrl(cdch_interface_t* p_cdc, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data); static bool cp210x_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data); #endif @@ -141,16 +139,16 @@ static bool cp210x_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, tuh_ static uint16_t const ch34x_vids_pids[][2] = { CFG_TUH_CDC_CH34X_VID_PID_LIST }; enum { - CH34X_VID_PID_COUNT = sizeof ( ch34x_vids_pids ) / sizeof ( ch34x_vids_pids[0] ) + CH34X_VID_PID_COUNT = TU_ARRAY_SIZE(ch34x_vids_pids) }; static bool ch34x_open ( uint8_t daddr, tusb_desc_interface_t const *itf_desc, uint16_t max_len ); static void ch34x_process_config ( tuh_xfer_t* xfer ); - static bool ch34x_set_modem_ctrl ( cdch_interface_t* p_cdc, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data ); static bool ch34x_set_baudrate ( cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data ); #endif +//------------- Common -------------// enum { SERIAL_DRIVER_ACM = 0, @@ -204,29 +202,25 @@ static const cdch_serial_driver_t serial_drivers[] = { }; enum { - SERIAL_DRIVER_COUNT = sizeof(serial_drivers) / sizeof(serial_drivers[0]) + SERIAL_DRIVER_COUNT = TU_ARRAY_SIZE(serial_drivers) }; //--------------------------------------------------------------------+ // INTERNAL OBJECT & FUNCTION DECLARATION //--------------------------------------------------------------------+ -static inline cdch_interface_t* get_itf(uint8_t idx) -{ +static inline cdch_interface_t* get_itf(uint8_t idx) { TU_ASSERT(idx < CFG_TUH_CDC, NULL); cdch_interface_t* p_cdc = &cdch_data[idx]; return (p_cdc->daddr != 0) ? p_cdc : NULL; } -static inline uint8_t get_idx_by_ep_addr(uint8_t daddr, uint8_t ep_addr) -{ - for(uint8_t i=0; idaddr == daddr) && - (ep_addr == p_cdc->ep_notif || ep_addr == p_cdc->stream.rx.ep_addr || ep_addr == p_cdc->stream.tx.ep_addr)) - { + (ep_addr == p_cdc->ep_notif || ep_addr == p_cdc->stream.rx.ep_addr || ep_addr == p_cdc->stream.tx.ep_addr)) { return i; } } @@ -234,14 +228,10 @@ static inline uint8_t get_idx_by_ep_addr(uint8_t daddr, uint8_t ep_addr) return TUSB_INDEX_INVALID_8; } - -static cdch_interface_t* make_new_itf(uint8_t daddr, tusb_desc_interface_t const *itf_desc) -{ - for(uint8_t i=0; idaddr = daddr; p_cdc->bInterfaceNumber = itf_desc->bInterfaceNumber; p_cdc->bInterfaceSubClass = itf_desc->bInterfaceSubClass; @@ -262,20 +252,16 @@ static void cdch_internal_control_complete(tuh_xfer_t* xfer); // APPLICATION API //--------------------------------------------------------------------+ -uint8_t tuh_cdc_itf_get_index(uint8_t daddr, uint8_t itf_num) -{ - for(uint8_t i=0; idaddr == daddr && p_cdc->bInterfaceNumber == itf_num) return i; } return TUSB_INDEX_INVALID_8; } -bool tuh_cdc_itf_get_info(uint8_t idx, tuh_itf_info_t* info) -{ +bool tuh_cdc_itf_get_info(uint8_t idx, tuh_itf_info_t* info) { cdch_interface_t* p_cdc = get_itf(idx); TU_VERIFY(p_cdc && info); @@ -297,30 +283,26 @@ bool tuh_cdc_itf_get_info(uint8_t idx, tuh_itf_info_t* info) return true; } -bool tuh_cdc_mounted(uint8_t idx) -{ +bool tuh_cdc_mounted(uint8_t idx) { cdch_interface_t* p_cdc = get_itf(idx); return p_cdc != NULL; } -bool tuh_cdc_get_dtr(uint8_t idx) -{ +bool tuh_cdc_get_dtr(uint8_t idx) { cdch_interface_t* p_cdc = get_itf(idx); TU_VERIFY(p_cdc); return (p_cdc->line_state & CDC_CONTROL_LINE_STATE_DTR) ? true : false; } -bool tuh_cdc_get_rts(uint8_t idx) -{ +bool tuh_cdc_get_rts(uint8_t idx) { cdch_interface_t* p_cdc = get_itf(idx); TU_VERIFY(p_cdc); return (p_cdc->line_state & CDC_CONTROL_LINE_STATE_RTS) ? true : false; } -bool tuh_cdc_get_local_line_coding(uint8_t idx, cdc_line_coding_t* line_coding) -{ +bool tuh_cdc_get_local_line_coding(uint8_t idx, cdc_line_coding_t* line_coding) { cdch_interface_t* p_cdc = get_itf(idx); TU_VERIFY(p_cdc); @@ -333,32 +315,28 @@ bool tuh_cdc_get_local_line_coding(uint8_t idx, cdc_line_coding_t* line_coding) // Write //--------------------------------------------------------------------+ -uint32_t tuh_cdc_write(uint8_t idx, void const* buffer, uint32_t bufsize) -{ +uint32_t tuh_cdc_write(uint8_t idx, void const* buffer, uint32_t bufsize) { cdch_interface_t* p_cdc = get_itf(idx); TU_VERIFY(p_cdc); return tu_edpt_stream_write(&p_cdc->stream.tx, buffer, bufsize); } -uint32_t tuh_cdc_write_flush(uint8_t idx) -{ +uint32_t tuh_cdc_write_flush(uint8_t idx) { cdch_interface_t* p_cdc = get_itf(idx); TU_VERIFY(p_cdc); return tu_edpt_stream_write_xfer(&p_cdc->stream.tx); } -bool tuh_cdc_write_clear(uint8_t idx) -{ +bool tuh_cdc_write_clear(uint8_t idx) { cdch_interface_t* p_cdc = get_itf(idx); TU_VERIFY(p_cdc); return tu_edpt_stream_clear(&p_cdc->stream.tx); } -uint32_t tuh_cdc_write_available(uint8_t idx) -{ +uint32_t tuh_cdc_write_available(uint8_t idx) { cdch_interface_t* p_cdc = get_itf(idx); TU_VERIFY(p_cdc); @@ -369,32 +347,28 @@ uint32_t tuh_cdc_write_available(uint8_t idx) // Read //--------------------------------------------------------------------+ -uint32_t tuh_cdc_read (uint8_t idx, void* buffer, uint32_t bufsize) -{ +uint32_t tuh_cdc_read (uint8_t idx, void* buffer, uint32_t bufsize) { cdch_interface_t* p_cdc = get_itf(idx); TU_VERIFY(p_cdc); return tu_edpt_stream_read(&p_cdc->stream.rx, buffer, bufsize); } -uint32_t tuh_cdc_read_available(uint8_t idx) -{ +uint32_t tuh_cdc_read_available(uint8_t idx) { cdch_interface_t* p_cdc = get_itf(idx); TU_VERIFY(p_cdc); return tu_edpt_stream_read_available(&p_cdc->stream.rx); } -bool tuh_cdc_peek(uint8_t idx, uint8_t* ch) -{ +bool tuh_cdc_peek(uint8_t idx, uint8_t* ch) { cdch_interface_t* p_cdc = get_itf(idx); TU_VERIFY(p_cdc); return tu_edpt_stream_peek(&p_cdc->stream.rx, ch); } -bool tuh_cdc_read_clear (uint8_t idx) -{ +bool tuh_cdc_read_clear (uint8_t idx) { cdch_interface_t* p_cdc = get_itf(idx); TU_VERIFY(p_cdc); @@ -408,15 +382,13 @@ bool tuh_cdc_read_clear (uint8_t idx) //--------------------------------------------------------------------+ // internal control complete to update state such as line state, encoding -static void cdch_internal_control_complete(tuh_xfer_t* xfer) -{ +static void cdch_internal_control_complete(tuh_xfer_t* xfer) { uint8_t const itf_num = (uint8_t) tu_le16toh(xfer->setup->wIndex); uint8_t idx = tuh_cdc_itf_get_index(xfer->daddr, itf_num); cdch_interface_t* p_cdc = get_itf(idx); TU_ASSERT(p_cdc, ); - if (xfer->result == XFER_RESULT_SUCCESS) - { + if (xfer->result == XFER_RESULT_SUCCESS) { switch (p_cdc->serial_drid) { case SERIAL_DRIVER_ACM: switch (xfer->setup->bRequest) { @@ -502,7 +474,6 @@ bool tuh_cdc_set_control_line_state(uint8_t idx, uint16_t line_state, tuh_xfer_c } TU_VERIFY(ret && result == XFER_RESULT_SUCCESS); - p_cdc->line_state = (uint8_t) line_state; return true; } @@ -526,7 +497,6 @@ bool tuh_cdc_set_baudrate(uint8_t idx, uint32_t baudrate, tuh_xfer_cb_t complete } TU_VERIFY(ret && result == XFER_RESULT_SUCCESS); - p_cdc->line_coding.bit_rate = baudrate; return true; } @@ -552,7 +522,6 @@ bool tuh_cdc_set_line_coding(uint8_t idx, cdc_line_coding_t const* line_coding, } TU_VERIFY(ret && result == XFER_RESULT_SUCCESS); - p_cdc->line_coding = *line_coding; return true; } @@ -562,31 +531,26 @@ bool tuh_cdc_set_line_coding(uint8_t idx, cdc_line_coding_t const* line_coding, // CLASS-USBH API //--------------------------------------------------------------------+ -void cdch_init(void) -{ +void cdch_init(void) { tu_memclr(cdch_data, sizeof(cdch_data)); - for(size_t i=0; istream.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); + p_cdc->stream.tx_ff_buf, CFG_TUH_CDC_TX_BUFSIZE, + p_cdc->stream.tx_ep_buf, CFG_TUH_CDC_TX_EPSIZE); tu_edpt_stream_init(&p_cdc->stream.rx, true, false, false, - p_cdc->stream.rx_ff_buf, CFG_TUH_CDC_RX_BUFSIZE, - p_cdc->stream.rx_ep_buf, CFG_TUH_CDC_RX_EPSIZE); + p_cdc->stream.rx_ff_buf, CFG_TUH_CDC_RX_BUFSIZE, + p_cdc->stream.rx_ep_buf, CFG_TUH_CDC_RX_EPSIZE); } } -void cdch_close(uint8_t daddr) -{ - for(uint8_t idx=0; idxdaddr == daddr) - { + if (p_cdc->daddr == daddr) { TU_LOG_DRV(" CDCh close addr = %u index = %u\r\n", daddr, idx); // Invoke application callback @@ -618,16 +582,11 @@ bool cdch_xfer_cb(uint8_t daddr, uint8_t ep_addr, xfer_result_t event, uint32_t // - xferred_bytes is multiple of EP Packet size and not zero tu_edpt_stream_write_zlp_if_needed(&p_cdc->stream.tx, xferred_bytes); } - } - else if ( ep_addr == p_cdc->stream.rx.ep_addr ) { + } else if ( ep_addr == p_cdc->stream.rx.ep_addr ) { #if CFG_TUH_CDC_FTDI if (p_cdc->serial_drid == SERIAL_DRIVER_FTDI) { // FTDI reserve 2 bytes for status - // FTDI status -// uint8_t status[2] = { -// p_cdc->stream.rx.ep_buf[0], -// p_cdc->stream.rx.ep_buf[1] -// }; + // uint8_t status[2] = {p_cdc->stream.rx.ep_buf[0], p_cdc->stream.rx.ep_buf[1]}; tu_edpt_stream_read_xfer_complete_offset(&p_cdc->stream.rx, xferred_bytes, 2); }else #endif @@ -653,20 +612,15 @@ bool cdch_xfer_cb(uint8_t daddr, uint8_t ep_addr, xfer_result_t event, uint32_t // Enumeration //--------------------------------------------------------------------+ -static bool open_ep_stream_pair(cdch_interface_t* p_cdc, tusb_desc_endpoint_t const *desc_ep) -{ - for(size_t i=0; i<2; i++) - { +static bool open_ep_stream_pair(cdch_interface_t* p_cdc, tusb_desc_endpoint_t const* desc_ep) { + for (size_t i = 0; i < 2; i++) { TU_ASSERT(TUSB_DESC_ENDPOINT == desc_ep->bDescriptorType && - TUSB_XFER_BULK == desc_ep->bmAttributes.xfer); - + TUSB_XFER_BULK == desc_ep->bmAttributes.xfer); TU_ASSERT(tuh_edpt_open(p_cdc->daddr, desc_ep)); - if ( tu_edpt_dir(desc_ep->bEndpointAddress) == TUSB_DIR_IN ) - { + if (tu_edpt_dir(desc_ep->bEndpointAddress) == TUSB_DIR_IN) { tu_edpt_stream_open(&p_cdc->stream.rx, p_cdc->daddr, desc_ep); - }else - { + } else { tu_edpt_stream_open(&p_cdc->stream.tx, p_cdc->daddr, desc_ep); } @@ -676,20 +630,17 @@ static bool open_ep_stream_pair(cdch_interface_t* p_cdc, tusb_desc_endpoint_t co return true; } -bool cdch_open(uint8_t rhport, uint8_t daddr, tusb_desc_interface_t const *itf_desc, uint16_t max_len) -{ +bool cdch_open(uint8_t rhport, uint8_t daddr, tusb_desc_interface_t const *itf_desc, uint16_t max_len) { (void) rhport; - // Only support ACM subclass + // For CDC: only support ACM subclass // Note: Protocol 0xFF can be RNDIS device - if ( TUSB_CLASS_CDC == itf_desc->bInterfaceClass && - CDC_COMM_SUBCLASS_ABSTRACT_CONTROL_MODEL == itf_desc->bInterfaceSubClass) - { + if (TUSB_CLASS_CDC == itf_desc->bInterfaceClass && + CDC_COMM_SUBCLASS_ABSTRACT_CONTROL_MODEL == itf_desc->bInterfaceSubClass) { return acm_open(daddr, itf_desc, max_len); } #if CFG_TUH_CDC_FTDI || CFG_TUH_CDC_CP210X || CFG_TUH_CDC_CH34X - else if ( TUSB_CLASS_VENDOR_SPECIFIC == itf_desc->bInterfaceClass ) - { + else if (TUSB_CLASS_VENDOR_SPECIFIC == itf_desc->bInterfaceClass) { uint16_t vid, pid; TU_VERIFY(tuh_vid_pid_get(daddr, &vid, &pid)); @@ -721,7 +672,7 @@ bool cdch_open(uint8_t rhport, uint8_t daddr, tusb_desc_interface_t const *itf_d } #endif } - #endif // CFG_TUH_CDC_FTDI || CFG_TUH_CDC_CP210X || CFG_TUH_CDC_CH34X + #endif return false; } @@ -767,94 +718,85 @@ enum { CONFIG_ACM_COMPLETE, }; -static bool acm_open(uint8_t daddr, tusb_desc_interface_t const *itf_desc, uint16_t max_len) -{ - uint8_t const * p_desc_end = ((uint8_t const*) itf_desc) + max_len; +static bool acm_open(uint8_t daddr, tusb_desc_interface_t const* itf_desc, uint16_t max_len) { + uint8_t const* p_desc_end = ((uint8_t const*) itf_desc) + max_len; - cdch_interface_t * p_cdc = make_new_itf(daddr, itf_desc); + cdch_interface_t* p_cdc = make_new_itf(daddr, itf_desc); TU_VERIFY(p_cdc); p_cdc->serial_drid = SERIAL_DRIVER_ACM; //------------- Control Interface -------------// - uint8_t const * p_desc = tu_desc_next(itf_desc); + uint8_t const* p_desc = tu_desc_next(itf_desc); // Communication Functional Descriptors - while( (p_desc < p_desc_end) && (TUSB_DESC_CS_INTERFACE == tu_desc_type(p_desc)) ) - { - if ( CDC_FUNC_DESC_ABSTRACT_CONTROL_MANAGEMENT == cdc_functional_desc_typeof(p_desc) ) - { + while ((p_desc < p_desc_end) && (TUSB_DESC_CS_INTERFACE == tu_desc_type(p_desc))) { + if (CDC_FUNC_DESC_ABSTRACT_CONTROL_MANAGEMENT == cdc_functional_desc_typeof(p_desc)) { // save ACM bmCapabilities - p_cdc->acm_capability = ((cdc_desc_func_acm_t const *) p_desc)->bmCapabilities; + p_cdc->acm_capability = ((cdc_desc_func_acm_t const*) p_desc)->bmCapabilities; } p_desc = tu_desc_next(p_desc); } // Open notification endpoint of control interface if any - if (itf_desc->bNumEndpoints == 1) - { + if (itf_desc->bNumEndpoints == 1) { TU_ASSERT(TUSB_DESC_ENDPOINT == tu_desc_type(p_desc)); - tusb_desc_endpoint_t const * desc_ep = (tusb_desc_endpoint_t const *) p_desc; + tusb_desc_endpoint_t const* desc_ep = (tusb_desc_endpoint_t const*) p_desc; - TU_ASSERT( tuh_edpt_open(daddr, desc_ep) ); + TU_ASSERT(tuh_edpt_open(daddr, desc_ep)); p_cdc->ep_notif = desc_ep->bEndpointAddress; p_desc = tu_desc_next(p_desc); } //------------- Data Interface (if any) -------------// - if ( (TUSB_DESC_INTERFACE == tu_desc_type(p_desc)) && - (TUSB_CLASS_CDC_DATA == ((tusb_desc_interface_t const *) p_desc)->bInterfaceClass) ) - { + if ((TUSB_DESC_INTERFACE == tu_desc_type(p_desc)) && + (TUSB_CLASS_CDC_DATA == ((tusb_desc_interface_t const*) p_desc)->bInterfaceClass)) { // next to endpoint descriptor p_desc = tu_desc_next(p_desc); // data endpoints expected to be in pairs - TU_ASSERT(open_ep_stream_pair(p_cdc, (tusb_desc_endpoint_t const *) p_desc)); + TU_ASSERT(open_ep_stream_pair(p_cdc, (tusb_desc_endpoint_t const*) p_desc)); } return true; } -static void acm_process_config(tuh_xfer_t* xfer) -{ +static void acm_process_config(tuh_xfer_t* xfer) { uintptr_t const state = xfer->user_data; uint8_t const itf_num = (uint8_t) tu_le16toh(xfer->setup->wIndex); uint8_t const idx = tuh_cdc_itf_get_index(xfer->daddr, itf_num); - cdch_interface_t * p_cdc = get_itf(idx); - TU_ASSERT(p_cdc, ); + cdch_interface_t* p_cdc = get_itf(idx); + TU_ASSERT(p_cdc,); - switch(state) - { + switch (state) { case CONFIG_ACM_SET_CONTROL_LINE_STATE: #if CFG_TUH_CDC_LINE_CONTROL_ON_ENUM - if (p_cdc->acm_capability.support_line_request) - { - TU_ASSERT(acm_set_control_line_state(p_cdc, CFG_TUH_CDC_LINE_CONTROL_ON_ENUM, acm_process_config, - CONFIG_ACM_SET_LINE_CODING), ); + if (p_cdc->acm_capability.support_line_request) { + TU_ASSERT(acm_set_control_line_state(p_cdc, CFG_TUH_CDC_LINE_CONTROL_ON_ENUM, acm_process_config, CONFIG_ACM_SET_LINE_CODING),); break; } - #endif + #endif TU_ATTR_FALLTHROUGH; case CONFIG_ACM_SET_LINE_CODING: - #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM - if (p_cdc->acm_capability.support_line_request) - { + #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM + if (p_cdc->acm_capability.support_line_request) { cdc_line_coding_t line_coding = CFG_TUH_CDC_LINE_CODING_ON_ENUM; - TU_ASSERT(acm_set_line_coding(p_cdc, &line_coding, acm_process_config, CONFIG_ACM_COMPLETE), ); + TU_ASSERT(acm_set_line_coding(p_cdc, &line_coding, acm_process_config, CONFIG_ACM_COMPLETE),); break; } - #endif + #endif TU_ATTR_FALLTHROUGH; case CONFIG_ACM_COMPLETE: // itf_num+1 to account for data interface as well - set_config_complete(p_cdc, idx, itf_num+1); + set_config_complete(p_cdc, idx, itf_num + 1); break; - default: break; + default: + break; } } @@ -987,13 +929,12 @@ static bool ftdi_sio_set_request(cdch_interface_t* p_cdc, uint8_t command, uint1 return tuh_control_xfer(&xfer); } -static bool ftdi_sio_reset(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) -{ +static bool ftdi_sio_reset(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { return ftdi_sio_set_request(p_cdc, FTDI_SIO_RESET, FTDI_SIO_RESET_SIO, complete_cb, user_data); } -static bool ftdi_sio_set_modem_ctrl(cdch_interface_t* p_cdc, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data) -{ +static bool +ftdi_sio_set_modem_ctrl(cdch_interface_t* p_cdc, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { TU_LOG_DRV("CDC FTDI Set Control Line State\r\n"); p_cdc->user_control_cb = complete_cb; TU_ASSERT(ftdi_sio_set_request(p_cdc, FTDI_SIO_MODEM_CTRL, 0x0300 | line_state, @@ -1001,8 +942,7 @@ static bool ftdi_sio_set_modem_ctrl(cdch_interface_t* p_cdc, uint16_t line_state return true; } -static uint32_t ftdi_232bm_baud_base_to_divisor(uint32_t baud, uint32_t base) -{ +static uint32_t ftdi_232bm_baud_base_to_divisor(uint32_t baud, uint32_t base) { const uint8_t divfrac[8] = { 0, 3, 2, 4, 1, 5, 6, 7 }; uint32_t divisor; @@ -1022,13 +962,11 @@ static uint32_t ftdi_232bm_baud_base_to_divisor(uint32_t baud, uint32_t base) return divisor; } -static uint32_t ftdi_232bm_baud_to_divisor(uint32_t baud) -{ +static uint32_t ftdi_232bm_baud_to_divisor(uint32_t baud) { return ftdi_232bm_baud_base_to_divisor(baud, 48000000u); } -static bool ftdi_sio_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data) -{ +static bool ftdi_sio_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { uint16_t const divisor = (uint16_t) ftdi_232bm_baud_to_divisor(baudrate); TU_LOG_DRV("CDC FTDI Set BaudRate = %lu, divisor = 0x%04x\r\n", baudrate, divisor); @@ -1055,8 +993,7 @@ static void ftdi_process_config(tuh_xfer_t* xfer) { case CONFIG_FTDI_MODEM_CTRL: #if CFG_TUH_CDC_LINE_CONTROL_ON_ENUM - TU_ASSERT( - ftdi_sio_set_modem_ctrl(p_cdc, CFG_TUH_CDC_LINE_CONTROL_ON_ENUM, ftdi_process_config, CONFIG_FTDI_SET_BAUDRATE),); + TU_ASSERT(ftdi_sio_set_modem_ctrl(p_cdc, CFG_TUH_CDC_LINE_CONTROL_ON_ENUM, ftdi_process_config, CONFIG_FTDI_SET_BAUDRATE),); break; #else TU_ATTR_FALLTHROUGH; @@ -1172,8 +1109,7 @@ static bool cp210x_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, tuh_ complete_cb ? cdch_internal_control_complete : NULL, user_data); } -static bool cp210x_set_modem_ctrl(cdch_interface_t* p_cdc, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data) -{ +static bool cp210x_set_modem_ctrl(cdch_interface_t* p_cdc, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { TU_LOG_DRV("CDC CP210x Set Control Line State\r\n"); p_cdc->user_control_cb = complete_cb; return cp210x_set_request(p_cdc, CP210X_SET_MHS, 0x0300 | line_state, NULL, 0, @@ -1213,8 +1149,7 @@ static void cp210x_process_config(tuh_xfer_t* xfer) { case CONFIG_CP210X_SET_DTR_RTS: #if CFG_TUH_CDC_LINE_CONTROL_ON_ENUM - TU_ASSERT( - cp210x_set_modem_ctrl(p_cdc, CFG_TUH_CDC_LINE_CONTROL_ON_ENUM, cp210x_process_config, CONFIG_CP210X_COMPLETE),); + TU_ASSERT(cp210x_set_modem_ctrl(p_cdc, CFG_TUH_CDC_LINE_CONTROL_ON_ENUM, cp210x_process_config, CONFIG_CP210X_COMPLETE),); break; #else TU_ATTR_FALLTHROUGH; @@ -1248,8 +1183,7 @@ enum { CONFIG_CH34X_COMPLETE }; -static bool ch34x_open ( uint8_t daddr, tusb_desc_interface_t const *itf_desc, uint16_t max_len ) -{ +static bool ch34x_open ( uint8_t daddr, tusb_desc_interface_t const *itf_desc, uint16_t max_len ) { // CH34x Interface includes 1 vendor interface + 3 bulk endpoints TU_VERIFY ( itf_desc->bNumEndpoints == 3 ); TU_VERIFY ( sizeof ( tusb_desc_interface_t ) + 2 * sizeof ( tusb_desc_endpoint_t ) <= max_len ); @@ -1303,23 +1237,19 @@ static bool ch34x_set_request ( cdch_interface_t* p_cdc, uint8_t direction, uint return false; } -static bool ch341_control_out ( cdch_interface_t* p_cdc, uint8_t request, uint16_t value, uint16_t index, tuh_xfer_cb_t complete_cb, uintptr_t user_data ) -{ +static bool ch341_control_out ( cdch_interface_t* p_cdc, uint8_t request, uint16_t value, uint16_t index, tuh_xfer_cb_t complete_cb, uintptr_t user_data ) { return ch34x_set_request ( p_cdc, TUSB_DIR_OUT, request, value, index, /* buffer */ NULL, /* length */ 0, complete_cb, user_data ); } -static bool ch341_control_in ( cdch_interface_t* p_cdc, uint8_t request, uint16_t value, uint16_t index, uint8_t *buffer, uint16_t buffersize, tuh_xfer_cb_t complete_cb, uintptr_t user_data ) -{ +static bool ch341_control_in ( cdch_interface_t* p_cdc, uint8_t request, uint16_t value, uint16_t index, uint8_t *buffer, uint16_t buffersize, tuh_xfer_cb_t complete_cb, uintptr_t user_data ) { return ch34x_set_request ( p_cdc, TUSB_DIR_IN, request, value, index, buffer, buffersize, complete_cb, user_data ); } -static int32_t ch341_write_reg ( cdch_interface_t* p_cdc, uint16_t reg, uint16_t value, tuh_xfer_cb_t complete_cb, uintptr_t user_data ) -{ +static int32_t ch341_write_reg ( cdch_interface_t* p_cdc, uint16_t reg, uint16_t value, tuh_xfer_cb_t complete_cb, uintptr_t user_data ) { return ch341_control_out ( p_cdc, CH341_REQ_WRITE_REG, /* value */ reg, /* index */ value, complete_cb, user_data ); } -static int32_t ch341_read_reg_request ( cdch_interface_t* p_cdc, uint16_t reg, uint8_t *buffer, uint16_t buffersize, tuh_xfer_cb_t complete_cb, uintptr_t user_data ) -{ +static int32_t ch341_read_reg_request ( cdch_interface_t* p_cdc, uint16_t reg, uint8_t *buffer, uint16_t buffersize, tuh_xfer_cb_t complete_cb, uintptr_t user_data ) { return ch341_control_in ( p_cdc, CH341_REQ_READ_REG, reg, /* index */ 0, buffer, buffersize, complete_cb, user_data ); } @@ -1335,8 +1265,7 @@ static int32_t ch341_read_reg_request ( cdch_interface_t* p_cdc, uint16_t reg, u */ // calculate baudrate devisors // Parts of this functions have been taken over from Linux driver /drivers/usb/serial/ch341.c -static int32_t ch341_get_divisor ( cdch_interface_t* p_cdc, uint32_t speed ) -{ +static int32_t ch341_get_divisor ( cdch_interface_t* p_cdc, uint32_t speed ) { uint32_t fact, div, clk_div; bool force_fact0 = false; int32_t ps; @@ -1362,20 +1291,19 @@ static int32_t ch341_get_divisor ( cdch_interface_t* p_cdc, uint32_t speed ) */ fact = 1; for (ps = 3; ps >= 0; ps--) { - if (speed > ch341_min_rates[ps]) - break; + if (speed > ch341_min_rates[ps]) break; } - if (ps < 0) - return -EINVAL; + if (ps < 0) return -EINVAL; /* Determine corresponding divisor, rounding down. */ clk_div = CH341_CLK_DIV(ps, fact); div = CH341_CLKRATE / (clk_div * speed); /* Some devices require a lower base clock if ps < 3. */ - if (ps < 3 && (p_cdc->ch34x.quirks & CH341_QUIRK_LIMITED_PRESCALER)) + if (ps < 3 && (p_cdc->ch34x.quirks & CH341_QUIRK_LIMITED_PRESCALER)) { force_fact0 = true; + } /* Halve base clock (fact = 0) if required. */ if (div < 9 || div > 255 || force_fact0) { @@ -1384,16 +1312,16 @@ static int32_t ch341_get_divisor ( cdch_interface_t* p_cdc, uint32_t speed ) fact = 0; } - if (div < 2) - return -EINVAL; + if (div < 2) return -EINVAL; /* * Pick next divisor if resulting rate is closer to the requested one, * scale up to avoid rounding errors on low rates. */ if (16 * CH341_CLKRATE / (clk_div * div) - 16 * speed >= - 16 * speed - 16 * CH341_CLKRATE / (clk_div * (div + 1))) + 16 * speed - 16 * CH341_CLKRATE / (clk_div * (div + 1))) { div++; + } /* * Prefer lower base clock (fact = 0) if even divisor. @@ -1411,16 +1339,13 @@ static int32_t ch341_get_divisor ( cdch_interface_t* p_cdc, uint32_t speed ) // set baudrate (low level) // do not confuse with ch34x_set_baudrate // Parts of this functions have been taken over from Linux driver /drivers/usb/serial/ch341.c -static int32_t ch341_set_baudrate ( cdch_interface_t* p_cdc, uint32_t baud_rate, tuh_xfer_cb_t complete_cb, uintptr_t user_data ) -{ +static int32_t ch341_set_baudrate ( cdch_interface_t* p_cdc, uint32_t baud_rate, tuh_xfer_cb_t complete_cb, uintptr_t user_data ) { int val; - if (!baud_rate) - return -EINVAL; + if (!baud_rate) return -EINVAL; val = ch341_get_divisor(p_cdc, baud_rate); - if (val < 0) - return -EINVAL; + if (val < 0) return -EINVAL; /* * CH341A buffers data until a full endpoint-size packet (32 bytes) @@ -1429,100 +1354,94 @@ static int32_t ch341_set_baudrate ( cdch_interface_t* p_cdc, uint32_t baud_rate, * At least one device with version 0x27 appears to have this bit * inverted. */ - if ( p_cdc->ch34x.version > 0x27 ) + if ( p_cdc->ch34x.version > 0x27 ) { val |= BIT(7); + } return ch341_write_reg ( p_cdc, CH341_REG_DIVISOR << 8 | CH341_REG_PRESCALER, val, complete_cb, user_data ); } // set lcr register // Parts of this functions have been taken over from Linux driver /drivers/usb/serial/ch341.c -static int32_t ch341_set_lcr ( cdch_interface_t* p_cdc, uint8_t lcr, tuh_xfer_cb_t complete_cb, uintptr_t user_data ) -{ +static int32_t ch341_set_lcr ( cdch_interface_t* p_cdc, uint8_t lcr, tuh_xfer_cb_t complete_cb, uintptr_t user_data ) { /* * Chip versions before version 0x30 as read using * CH341_REQ_READ_VERSION used separate registers for line control * (stop bits, parity and word length). Version 0x30 and above use * CH341_REG_LCR only and CH341_REG_LCR2 is always set to zero. */ - if ( p_cdc->ch34x.version < 0x30 ) - return 0; + if ( p_cdc->ch34x.version < 0x30 ) return 0; return ch341_write_reg ( p_cdc, CH341_REG_LCR2 << 8 | CH341_REG_LCR, lcr, complete_cb, user_data ); } // set handshake (modem controls) // Parts of this functions have been taken over from Linux driver /drivers/usb/serial/ch341.c -static int32_t ch341_set_handshake ( cdch_interface_t* p_cdc, uint8_t control, tuh_xfer_cb_t complete_cb, uintptr_t user_data ) -{ +static int32_t ch341_set_handshake ( cdch_interface_t* p_cdc, uint8_t control, tuh_xfer_cb_t complete_cb, uintptr_t user_data ) { return ch341_control_out ( p_cdc, CH341_REQ_MODEM_CTRL, /* value */ ~control, /* index */ 0, complete_cb, user_data ); } // detect quirks (special versions of CH34x) // Parts of this functions have been taken over from Linux driver /drivers/usb/serial/ch341.c -static int32_t ch341_detect_quirks ( tuh_xfer_t* xfer, cdch_interface_t* p_cdc, uint8_t step, uint8_t *buffer, uint16_t buffersize, tuh_xfer_cb_t complete_cb, uintptr_t user_data ) -{ +static int32_t ch341_detect_quirks ( tuh_xfer_t* xfer, cdch_interface_t* p_cdc, uint8_t step, uint8_t *buffer, uint16_t buffersize, tuh_xfer_cb_t complete_cb, uintptr_t user_data ) { /* * A subset of CH34x devices does not support all features. The * prescaler is limited and there is no support for sending a RS232 * break condition. A read failure when trying to set up the latter is * used to detect these devices. */ - switch ( step ) - { - case 1: - p_cdc->ch34x.quirks = 0; - return ch341_read_reg_request ( p_cdc, CH341_REG_BREAK, buffer, buffersize, complete_cb, user_data ); - break; - case 2: - if ( xfer->result != XFER_RESULT_SUCCESS ) - p_cdc->ch34x.quirks |= CH341_QUIRK_LIMITED_PRESCALER | CH341_QUIRK_SIMULATE_BREAK; - return true; - break; - default: - TU_ASSERT ( false ); // suspicious step - break; + switch (step) { + case 1: + p_cdc->ch34x.quirks = 0; + return ch341_read_reg_request(p_cdc, CH341_REG_BREAK, buffer, buffersize, complete_cb, user_data); + break; + + case 2: + if (xfer->result != XFER_RESULT_SUCCESS) { + p_cdc->ch34x.quirks |= CH341_QUIRK_LIMITED_PRESCALER | CH341_QUIRK_SIMULATE_BREAK; + } + return true; + break; + + default: + TU_ASSERT (false); // suspicious step + break; } } // internal control complete to update state such as line state, encoding // CH34x needs a special interface recovery due to abnormal wIndex usage -static void ch34x_control_complete(tuh_xfer_t* xfer) -{ - uint8_t const itf_num = (uint8_t)( ( xfer->user_data & 0xff00 ) >> 8 ); - uint8_t const idx = tuh_cdc_itf_get_index ( xfer->daddr, itf_num ); - cdch_interface_t *p_cdc = get_itf ( idx ); - TU_ASSERT ( p_cdc, ); - TU_ASSERT ( p_cdc->serial_drid == SERIAL_DRIVER_CH34X, ); // ch34x_control_complete is only used for CH34x +static void ch34x_control_complete(tuh_xfer_t* xfer) { + uint8_t const itf_num = (uint8_t) ((xfer->user_data & 0xff00) >> 8); + uint8_t const idx = tuh_cdc_itf_get_index(xfer->daddr, itf_num); + cdch_interface_t* p_cdc = get_itf(idx); + TU_ASSERT (p_cdc,); + TU_ASSERT (p_cdc->serial_drid == SERIAL_DRIVER_CH34X,); // ch34x_control_complete is only used for CH34x if (xfer->result == XFER_RESULT_SUCCESS) { switch (xfer->setup->bRequest) { - case CH341_REQ_WRITE_REG: { // register write request - switch ( tu_le16toh ( xfer->setup->wValue ) ) { - case ( CH341_REG_DIVISOR << 8 | CH341_REG_PRESCALER ): { // baudrate write - p_cdc->line_coding.bit_rate = p_cdc->ch34x.baud_rate; + case CH341_REQ_WRITE_REG: // register write request + switch (tu_le16toh (xfer->setup->wValue)) { + case (CH341_REG_DIVISOR << 8 | CH341_REG_PRESCALER): // baudrate write + p_cdc->line_coding.bit_rate = p_cdc->ch34x.baud_rate; + break; + + default: + TU_ASSERT(false,); // unexpected register write + break; + } break; - } - default: { - TU_ASSERT(false, ); // unexpected register write + + default: + TU_ASSERT(false,); // unexpected request break; - } - } - break; - } - default: { - TU_ASSERT(false, ); // unexpected request - break; - } } xfer->complete_cb = p_cdc->user_control_cb; - if (xfer->complete_cb) - xfer->complete_cb(xfer); + if (xfer->complete_cb) xfer->complete_cb(xfer); } } -static bool ch34x_set_baudrate ( cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data ) // do not confuse with ch341_set_baudrate -{ +static bool ch34x_set_baudrate ( cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data ) /* do not confuse with ch341_set_baudrate */ { TU_LOG_DRV("CDC CH34x Set BaudRate = %lu\r\n", baudrate); uint32_t baud_le = tu_htole32(baudrate); p_cdc->ch34x.baud_rate = baudrate; @@ -1530,15 +1449,13 @@ static bool ch34x_set_baudrate ( cdch_interface_t* p_cdc, uint32_t baudrate, tuh return ch341_set_baudrate ( p_cdc, baud_le, complete_cb ? ch34x_control_complete : NULL, user_data ); } -static bool ch34x_set_modem_ctrl ( cdch_interface_t* p_cdc, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data ) -{ +static bool ch34x_set_modem_ctrl ( cdch_interface_t* p_cdc, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data ) { TU_LOG_DRV("CDC CH34x Set Control Line State\r\n"); // todo later return false; } -static void ch34x_process_config ( tuh_xfer_t* xfer ) -{ +static void ch34x_process_config ( tuh_xfer_t* xfer ) { uintptr_t const state = xfer->user_data & 0xff; // CH34x needs a special handling of bInterfaceNumber, because wIndex is used for other purposes and not for bInterfaceNumber uint8_t const itf_num = (uint8_t)( ( xfer->user_data & 0xff00 ) >> 8 ); @@ -1561,81 +1478,108 @@ static void ch34x_process_config ( tuh_xfer_t* xfer ) */ p_cdc->ch34x.lcr = CH341_LCR_ENABLE_RX | CH341_LCR_ENABLE_TX | CH341_LCR_CS8; } + // This process flow has been taken over from Linux driver /drivers/usb/serial/ch341.c - switch ( state ) { - case CONFIG_CH34X_STEP1: // request version read - TU_ASSERT ( ch341_control_in ( p_cdc, /* request */ CH341_REQ_READ_VERSION, /* value */ 0, /* index */ 0, buffer, CH34X_BUFFER_SIZE, ch34x_process_config, CONFIG_CH34X_STEP2 ), ); - break; - case CONFIG_CH34X_STEP2: // handle version read data, request to init CH34x - p_cdc->ch34x.version = xfer->buffer[0]; - TU_LOG_DRV ( "Chip version=%02x\r\n", p_cdc->ch34x.version ); - TU_ASSERT ( ch341_control_out ( p_cdc, /* request */ CH341_REQ_SERIAL_INIT, /* value */ 0, /* index */ 0, ch34x_process_config, CONFIG_CH34X_STEP3 ), ); - break; - case CONFIG_CH34X_STEP3: // set baudrate with default values (see above) - TU_ASSERT ( ch341_set_baudrate ( p_cdc, p_cdc->ch34x.baud_rate, ch34x_process_config, CONFIG_CH34X_STEP4 ) > 0, ); - break; - case CONFIG_CH34X_STEP4: // set line controls with default values (see above) - TU_ASSERT ( ch341_set_lcr ( p_cdc, p_cdc->ch34x.lcr, ch34x_process_config, CONFIG_CH34X_STEP5 ) > 0, ); - break; - case CONFIG_CH34X_STEP5: // set handshake RTS/DTR - TU_ASSERT ( ch341_set_handshake ( p_cdc, p_cdc->ch34x.mcr, ch34x_process_config, CONFIG_CH34X_STEP6 ) > 0, ); - break; - case CONFIG_CH34X_STEP6: // detect quirks step 1 - TU_ASSERT ( ch341_detect_quirks ( xfer, p_cdc, /* step */ 1, buffer, CH34X_BUFFER_SIZE, ch34x_process_config, CONFIG_CH34X_STEP7 ) > 0, ); - break; - case CONFIG_CH34X_STEP7: // detect quirks step 2 and set baudrate with configured values - TU_ASSERT ( ch341_detect_quirks ( xfer, p_cdc, /* step */ 2, NULL, 0, NULL, 0 ) > 0, ); -#ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM - TU_ASSERT ( ch34x_set_baudrate ( p_cdc, line_coding.bit_rate, ch34x_process_config, CONFIG_CH34X_STEP8 ), ); -#else - TU_ATTR_FALLTHROUGH; -#endif - break; - case CONFIG_CH34X_STEP8: // set data/stop bit quantities, parity -#ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM - p_cdc->ch34x.lcr = CH341_LCR_ENABLE_RX | CH341_LCR_ENABLE_TX; - switch ( line_coding.data_bits ) { - case 5: - p_cdc->ch34x.lcr |= CH341_LCR_CS5; + switch (state) { + case CONFIG_CH34X_STEP1: // request version read + TU_ASSERT (ch341_control_in(p_cdc, /* request */ CH341_REQ_READ_VERSION, /* value */ 0, /* index */0, + buffer, CH34X_BUFFER_SIZE, ch34x_process_config, CONFIG_CH34X_STEP2),); break; - case 6: - p_cdc->ch34x.lcr |= CH341_LCR_CS6; + + case CONFIG_CH34X_STEP2: // handle version read data, request to init CH34x + p_cdc->ch34x.version = xfer->buffer[0]; + TU_LOG_DRV ("Chip version=%02x\r\n", p_cdc->ch34x.version); + TU_ASSERT (ch341_control_out(p_cdc, /* request */ CH341_REQ_SERIAL_INIT, /* value */ 0, /* index */0, + ch34x_process_config, CONFIG_CH34X_STEP3),); break; - case 7: - p_cdc->ch34x.lcr |= CH341_LCR_CS7; + + case CONFIG_CH34X_STEP3: // set baudrate with default values (see above) + TU_ASSERT (ch341_set_baudrate(p_cdc, p_cdc->ch34x.baud_rate, ch34x_process_config, + CONFIG_CH34X_STEP4) > 0,); break; - case 8: - p_cdc->ch34x.lcr |= CH341_LCR_CS8; + + case CONFIG_CH34X_STEP4: // set line controls with default values (see above) + TU_ASSERT (ch341_set_lcr(p_cdc, p_cdc->ch34x.lcr, ch34x_process_config, CONFIG_CH34X_STEP5) > 0,); break; - default: - TU_ASSERT ( false, ); // not supported data_bits - p_cdc->ch34x.lcr |= CH341_LCR_CS8; + + case CONFIG_CH34X_STEP5: // set handshake RTS/DTR + TU_ASSERT (ch341_set_handshake(p_cdc, p_cdc->ch34x.mcr, ch34x_process_config, CONFIG_CH34X_STEP6) > 0,); break; - } - if ( line_coding.parity != CDC_LINE_CODING_PARITY_NONE ) { - p_cdc->ch34x.lcr |= CH341_LCR_ENABLE_PAR; - if ( line_coding.parity == CDC_LINE_CODING_PARITY_EVEN || line_coding.parity == CDC_LINE_CODING_PARITY_SPACE ) - p_cdc->ch34x.lcr |= CH341_LCR_PAR_EVEN; - if ( line_coding.parity == CDC_LINE_CODING_PARITY_MARK || line_coding.parity == CDC_LINE_CODING_PARITY_SPACE ) - p_cdc->ch34x.lcr |= CH341_LCR_MARK_SPACE; - } - TU_ASSERT ( line_coding.stop_bits == CDC_LINE_CODING_STOP_BITS_1 || line_coding.stop_bits == CDC_LINE_CODING_STOP_BITS_2, ); // not supported 1.5 stop bits - if ( line_coding.stop_bits == CDC_LINE_CODING_STOP_BITS_2 ) - p_cdc->ch34x.lcr |= CH341_LCR_STOP_BITS_2; - TU_ASSERT ( ch341_set_lcr ( p_cdc, p_cdc->ch34x.lcr, ch34x_process_config, CONFIG_CH34X_COMPLETE ) > 0, ); + + case CONFIG_CH34X_STEP6: // detect quirks step 1 + TU_ASSERT (ch341_detect_quirks(xfer, p_cdc, /* step */ 1, buffer, CH34X_BUFFER_SIZE, + ch34x_process_config, CONFIG_CH34X_STEP7) > 0,); + break; + + case CONFIG_CH34X_STEP7: // detect quirks step 2 and set baudrate with configured values + TU_ASSERT (ch341_detect_quirks(xfer, p_cdc, /* step */ 2, NULL, 0, NULL, 0) > 0,); +#ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM + TU_ASSERT (ch34x_set_baudrate(p_cdc, line_coding.bit_rate, ch34x_process_config, CONFIG_CH34X_STEP8),); #else - TU_ATTR_FALLTHROUGH; + TU_ATTR_FALLTHROUGH; #endif - break; + break; + + case CONFIG_CH34X_STEP8: // set data/stop bit quantities, parity +#ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM + p_cdc->ch34x.lcr = CH341_LCR_ENABLE_RX | CH341_LCR_ENABLE_TX; + switch (line_coding.data_bits) { + case 5: + p_cdc->ch34x.lcr |= CH341_LCR_CS5; + break; + + case 6: + p_cdc->ch34x.lcr |= CH341_LCR_CS6; + break; + + case 7: + p_cdc->ch34x.lcr |= CH341_LCR_CS7; + break; + + case 8: + p_cdc->ch34x.lcr |= CH341_LCR_CS8; + break; + + default: + TU_ASSERT (false,); // not supported data_bits + p_cdc->ch34x.lcr |= CH341_LCR_CS8; + break; + } + + if (line_coding.parity != CDC_LINE_CODING_PARITY_NONE) { + p_cdc->ch34x.lcr |= CH341_LCR_ENABLE_PAR; + + if (line_coding.parity == CDC_LINE_CODING_PARITY_EVEN || + line_coding.parity == CDC_LINE_CODING_PARITY_SPACE) { + p_cdc->ch34x.lcr |= CH341_LCR_PAR_EVEN; + } + + if (line_coding.parity == CDC_LINE_CODING_PARITY_MARK || + line_coding.parity == CDC_LINE_CODING_PARITY_SPACE) { + p_cdc->ch34x.lcr |= CH341_LCR_MARK_SPACE; + } + } + TU_ASSERT (line_coding.stop_bits == CDC_LINE_CODING_STOP_BITS_1 || line_coding.stop_bits == + CDC_LINE_CODING_STOP_BITS_2,); // not supported 1.5 stop bits + if (line_coding.stop_bits == CDC_LINE_CODING_STOP_BITS_2) { + p_cdc->ch34x.lcr |= CH341_LCR_STOP_BITS_2; + } + TU_ASSERT (ch341_set_lcr(p_cdc, p_cdc->ch34x.lcr, ch34x_process_config, CONFIG_CH34X_COMPLETE) > 0,); +#else + TU_ATTR_FALLTHROUGH; +#endif + break; + case CONFIG_CH34X_COMPLETE: - set_config_complete ( p_cdc, idx, itf_num ); + set_config_complete(p_cdc, idx, itf_num); break; + default: - TU_ASSERT ( false, ); + TU_ASSERT (false,); break; } } #endif // CFG_TUH_CDC_CH34X -#endif // (CFG_TUH_ENABLED && CFG_TUH_CDC) +#endif -- cgit v1.3.1 From d192868d62b56ef2eab9300bf0698a77e4e01cd3 Mon Sep 17 00:00:00 2001 From: hathach Date: Mon, 15 Jan 2024 18:25:15 +0700 Subject: fix sign-conversion warning --- src/class/cdc/cdc_host.c | 34 +++++++++++++++++++++------------- 1 file changed, 21 insertions(+), 13 deletions(-) (limited to 'src/class') diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index 05a061487..0cc35da52 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -1207,7 +1207,7 @@ static bool ch34x_set_request ( cdch_interface_t* p_cdc, uint8_t direction, uint .bmRequestType_bit = { .recipient = TUSB_REQ_RCPT_DEVICE, .type = TUSB_REQ_TYPE_VENDOR, - .direction = direction + .direction = direction & 0x01u }, .bRequest = request, .wValue = tu_htole16 ( value ), @@ -1265,6 +1265,11 @@ static int32_t ch341_read_reg_request ( cdch_interface_t* p_cdc, uint16_t reg, u */ // calculate baudrate devisors // Parts of this functions have been taken over from Linux driver /drivers/usb/serial/ch341.c + +static inline uint32_t clamp_val(uint32_t val, uint32_t minval, uint32_t maxval) { + return tu_min32(tu_max32(val, minval), maxval); +} + static int32_t ch341_get_divisor ( cdch_interface_t* p_cdc, uint32_t speed ) { uint32_t fact, div, clk_div; bool force_fact0 = false; @@ -1280,9 +1285,6 @@ static int32_t ch341_get_divisor ( cdch_interface_t* p_cdc, uint32_t speed ) { * Clamp to supported range, this makes the (ps < 0) and (div < 2) * sanity checks below redundant. */ - inline uint32_t max ( uint32_t val, uint32_t maxval ) { return val > maxval ? val : maxval; } - inline uint32_t min ( uint32_t val, uint32_t minval ) { return val < minval ? val : minval; } - inline uint32_t clamp_val ( uint32_t val, uint32_t minval, uint32_t maxval ) { return min ( max ( val, minval ), maxval ); } speed = clamp_val(speed, CH341_MIN_BPS, CH341_MAX_BPS); /* @@ -1297,7 +1299,7 @@ static int32_t ch341_get_divisor ( cdch_interface_t* p_cdc, uint32_t speed ) { if (ps < 0) return -EINVAL; /* Determine corresponding divisor, rounding down. */ - clk_div = CH341_CLK_DIV(ps, fact); + clk_div = CH341_CLK_DIV((uint32_t) ps, fact); div = CH341_CLKRATE / (clk_div * speed); /* Some devices require a lower base clock if ps < 3. */ @@ -1333,19 +1335,20 @@ static int32_t ch341_get_divisor ( cdch_interface_t* p_cdc, uint32_t speed ) { fact = 0; } - return (0x100 - div) << 8 | fact << 2 | ps; + return (int32_t) ((0x100 - div) << 8 | fact << 2 | (uint32_t) ps); } // set baudrate (low level) // do not confuse with ch34x_set_baudrate // Parts of this functions have been taken over from Linux driver /drivers/usb/serial/ch341.c -static int32_t ch341_set_baudrate ( cdch_interface_t* p_cdc, uint32_t baud_rate, tuh_xfer_cb_t complete_cb, uintptr_t user_data ) { - int val; - +static int32_t ch341_set_baudrate (cdch_interface_t* p_cdc, uint32_t baud_rate, tuh_xfer_cb_t complete_cb, uintptr_t user_data ) { if (!baud_rate) return -EINVAL; - val = ch341_get_divisor(p_cdc, baud_rate); - if (val < 0) return -EINVAL; + int ret; + ret = ch341_get_divisor(p_cdc, baud_rate); + if (ret < 0) return -EINVAL; + + uint16_t val = (uint16_t) ret; /* * CH341A buffers data until a full endpoint-size packet (32 bytes) @@ -1355,7 +1358,7 @@ static int32_t ch341_set_baudrate ( cdch_interface_t* p_cdc, uint32_t baud_rate, * inverted. */ if ( p_cdc->ch34x.version > 0x27 ) { - val |= BIT(7); + val = (val | BIT(7)); } return ch341_write_reg ( p_cdc, CH341_REG_DIVISOR << 8 | CH341_REG_PRESCALER, val, complete_cb, user_data ); @@ -1449,8 +1452,13 @@ static bool ch34x_set_baudrate ( cdch_interface_t* p_cdc, uint32_t baudrate, tuh return ch341_set_baudrate ( p_cdc, baud_le, complete_cb ? ch34x_control_complete : NULL, user_data ); } -static bool ch34x_set_modem_ctrl ( cdch_interface_t* p_cdc, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data ) { +static bool ch34x_set_modem_ctrl(cdch_interface_t* p_cdc, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { TU_LOG_DRV("CDC CH34x Set Control Line State\r\n"); + (void) p_cdc; + (void) line_state; + (void) complete_cb; + (void) user_data; + // todo later return false; } -- cgit v1.3.1 From 1f2901e8b12258c953e3c338897f188c98b5eaed Mon Sep 17 00:00:00 2001 From: hathach Date: Mon, 15 Jan 2024 18:42:39 +0700 Subject: fix conflict of BIT() macro --- src/class/cdc/cdc_host.c | 2 +- src/class/cdc/serial/ch34x.h | 11 ++++------- src/common/tusb_common.h | 1 + 3 files changed, 6 insertions(+), 8 deletions(-) (limited to 'src/class') diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index 0cc35da52..ca5bfff04 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -1358,7 +1358,7 @@ static int32_t ch341_set_baudrate (cdch_interface_t* p_cdc, uint32_t baud_rate, * inverted. */ if ( p_cdc->ch34x.version > 0x27 ) { - val = (val | BIT(7)); + val = (val | TU_BIT(7)); } return ch341_write_reg ( p_cdc, CH341_REG_DIVISOR << 8 | CH341_REG_PRESCALER, val, complete_cb, user_data ); diff --git a/src/class/cdc/serial/ch34x.h b/src/class/cdc/serial/ch34x.h index 94e18b252..4a5e61bbd 100644 --- a/src/class/cdc/serial/ch34x.h +++ b/src/class/cdc/serial/ch34x.h @@ -29,7 +29,7 @@ #include -#define BIT(nr) ( (uint32_t)1 << (nr) ) +//#define BIT(nr) ( (uint32_t)1 << (nr) ) #define CH34X_BUFFER_SIZE 2 @@ -93,20 +93,17 @@ #define CH341_LCR_CS6 0x01 #define CH341_LCR_CS5 0x00 -#define CH341_QUIRK_LIMITED_PRESCALER BIT(0) -#define CH341_QUIRK_SIMULATE_BREAK BIT(1) +#define CH341_QUIRK_LIMITED_PRESCALER TU_BIT(0) +#define CH341_QUIRK_SIMULATE_BREAK TU_BIT(1) #define CH341_CLKRATE 48000000 #define CH341_CLK_DIV(ps, fact) (1 << (12 - 3 * (ps) - (fact))) #define CH341_MIN_RATE(ps) (CH341_CLKRATE / (CH341_CLK_DIV((ps), 1) * 512)) /* Supported range is 46 to 3000000 bps. */ -#define CH341_MIN_BPS DIV_ROUND_UP(CH341_CLKRATE, CH341_CLK_DIV(0, 0) * 256) +#define CH341_MIN_BPS TU_DIV_CEIL(CH341_CLKRATE, CH341_CLK_DIV(0, 0) * 256) #define CH341_MAX_BPS (CH341_CLKRATE / (CH341_CLK_DIV(3, 0) * 2)) -#define DIV_ROUND_UP __KERNEL_DIV_ROUND_UP -#define __KERNEL_DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d)) - // error codes #define EINVAL 22 /* Invalid argument */ diff --git a/src/common/tusb_common.h b/src/common/tusb_common.h index caeb5f2ef..1f08ce4ed 100644 --- a/src/common/tusb_common.h +++ b/src/common/tusb_common.h @@ -37,6 +37,7 @@ #define TU_ARRAY_SIZE(_arr) ( sizeof(_arr) / sizeof(_arr[0]) ) #define TU_MIN(_x, _y) ( ( (_x) < (_y) ) ? (_x) : (_y) ) #define TU_MAX(_x, _y) ( ( (_x) > (_y) ) ? (_x) : (_y) ) +#define TU_DIV_CEIL(n, d) (((n) + (d) - 1) / (d)) #define TU_U16(_high, _low) ((uint16_t) (((_high) << 8) | (_low))) #define TU_U16_HIGH(_u16) ((uint8_t) (((_u16) >> 8) & 0x00ff)) -- cgit v1.3.1 From aa58cdcfa6a35cf5d903eaffd304db4834ce56ec Mon Sep 17 00:00:00 2001 From: hathach Date: Tue, 16 Jan 2024 01:28:29 +0700 Subject: change CFG_TUH_CDC_FTDI/CP210X_PID_LIST to CFG_TUH_CDC_FTDI/CP210X_VID_PID_LIST which contains both vid and pid. --- .idea/cmake.xml | 2 +- src/class/cdc/cdc_host.c | 24 ++++++++++-------------- src/tusb_option.h | 18 ++++++++++-------- 3 files changed, 21 insertions(+), 23 deletions(-) (limited to 'src/class') diff --git a/.idea/cmake.xml b/.idea/cmake.xml index 432e44172..3cb883e62 100644 --- a/.idea/cmake.xml +++ b/.idea/cmake.xml @@ -80,7 +80,7 @@ - + \ No newline at end of file diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index 79477ef53..2463671c6 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -91,9 +91,9 @@ static bool acm_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfe #if CFG_TUH_CDC_FTDI #include "serial/ftdi_sio.h" -static uint16_t const ftdi_pids[] = { CFG_TUH_CDC_FTDI_PID_LIST }; +static uint16_t const ftdi_vid_pid_list[][2] = {CFG_TUH_CDC_FTDI_VID_PID_LIST }; enum { - FTDI_PID_COUNT = sizeof(ftdi_pids) / sizeof(ftdi_pids[0]) + FTDI_PID_COUNT = sizeof(ftdi_vid_pid_list) / sizeof(ftdi_vid_pid_list[0]) }; // Store last request baudrate since divisor to baudrate is not easy @@ -110,9 +110,9 @@ static bool ftdi_sio_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, tu #if CFG_TUH_CDC_CP210X #include "serial/cp210x.h" -static uint16_t const cp210x_pids[] = { CFG_TUH_CDC_CP210X_PID_LIST }; +static uint16_t const cp210x_vid_pid_list[][2] = {CFG_TUH_CDC_CP210X_VID_PID_LIST }; enum { - CP210X_PID_COUNT = sizeof(cp210x_pids) / sizeof(cp210x_pids[0]) + CP210X_PID_COUNT = sizeof(cp210x_vid_pid_list) / sizeof(cp210x_vid_pid_list[0]) }; static bool cp210x_open(uint8_t daddr, tusb_desc_interface_t const *itf_desc, uint16_t max_len); @@ -647,21 +647,17 @@ bool cdch_open(uint8_t rhport, uint8_t daddr, tusb_desc_interface_t const *itf_d TU_VERIFY(tuh_vid_pid_get(daddr, &vid, &pid)); #if CFG_TUH_CDC_FTDI - if (TU_FTDI_VID == vid) { - for (size_t i = 0; i < FTDI_PID_COUNT; i++) { - if (ftdi_pids[i] == pid) { - return ftdi_open(daddr, itf_desc, max_len); - } + for (size_t i = 0; i < FTDI_PID_COUNT; i++) { + if (ftdi_vid_pid_list[i][0] == vid && ftdi_vid_pid_list[i][1] == pid) { + return ftdi_open(daddr, itf_desc, max_len); } } #endif #if CFG_TUH_CDC_CP210X - if (TU_CP210X_VID == vid) { - for (size_t i = 0; i < CP210X_PID_COUNT; i++) { - if (cp210x_pids[i] == pid) { - return cp210x_open(daddr, itf_desc, max_len); - } + for (size_t i = 0; i < CP210X_PID_COUNT; i++) { + if (cp210x_vid_pid_list[i][0] == vid && cp210x_vid_pid_list[i][1] == pid) { + return cp210x_open(daddr, itf_desc, max_len); } } #endif diff --git a/src/tusb_option.h b/src/tusb_option.h index a76281c0c..57f026312 100644 --- a/src/tusb_option.h +++ b/src/tusb_option.h @@ -453,10 +453,12 @@ #define CFG_TUH_CDC_FTDI 0 #endif -#ifndef CFG_TUH_CDC_FTDI_PID_LIST - // List of product IDs that can use the FTDI CDC driver - #define CFG_TUH_CDC_FTDI_PID_LIST \ - 0x6001, 0x6006, 0x6010, 0x6011, 0x6014, 0x6015, 0x8372, 0xFBFA, 0xCD18 +#ifndef CFG_TUH_CDC_FTDI_VID_PID_LIST + // List of product IDs that can use the FTDI CDC driver. 0x0403 is FTDI's VID + #define CFG_TUH_CDC_FTDI_VID_PID_LIST \ + {0x0403, 0x6001}, {0x0403, 0x6006}, {0x0403, 0x6010}, {0x0403, 0x6011}, \ + {0x0403, 0x6014}, {0x0403, 0x6015}, {0x0403, 0x8372}, {0x0403, 0xFBFA}, \ + {0x0403, 0xCD18} #endif #ifndef CFG_TUH_CDC_CP210X @@ -464,10 +466,10 @@ #define CFG_TUH_CDC_CP210X 0 #endif -#ifndef CFG_TUH_CDC_CP210X_PID_LIST - // List of product IDs that can use the CP210X CDC driver - #define CFG_TUH_CDC_CP210X_PID_LIST \ - 0xEA60, 0xEA70 +#ifndef CFG_TUH_CDC_CP210X_VID_PID_LIST + // List of product IDs that can use the CP210X CDC driver. 0x10C4 is Silicon Labs' VID + #define CFG_TUH_CDC_CP210X_VID_PID_LIST \ + {0x10C4, 0xEA60}, {0x10C4, 0xEA70} #endif #ifndef CFG_TUH_HID -- cgit v1.3.1 From e2aa671346103d3ed80c2849350488d5ddf2e0dc Mon Sep 17 00:00:00 2001 From: hathach Date: Tue, 16 Jan 2024 12:54:39 +0700 Subject: move open() ad vid_pid_list into serial driver struct --- src/class/cdc/cdc_host.c | 102 ++++++++++++++++++++++------------------------- 1 file changed, 47 insertions(+), 55 deletions(-) (limited to 'src/class') diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index c018cf057..91e35ec8c 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -104,10 +104,7 @@ static bool acm_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfe #if CFG_TUH_CDC_FTDI #include "serial/ftdi_sio.h" -static uint16_t const ftdi_vid_pid_list[][2] = {CFG_TUH_CDC_FTDI_VID_PID_LIST }; -enum { - FTDI_PID_COUNT = TU_ARRAY_SIZE(ftdi_vid_pid_list) -}; +static uint16_t const ftdi_vid_pid_list[][2] = {CFG_TUH_CDC_FTDI_VID_PID_LIST}; // Store last request baudrate since divisor to baudrate is not easy static uint32_t _ftdi_requested_baud; @@ -122,10 +119,7 @@ static bool ftdi_sio_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, tu #if CFG_TUH_CDC_CP210X #include "serial/cp210x.h" -static uint16_t const cp210x_vid_pid_list[][2] = {CFG_TUH_CDC_CP210X_VID_PID_LIST }; -enum { - CP210X_PID_COUNT = TU_ARRAY_SIZE(cp210x_vid_pid_list) -}; +static uint16_t const cp210x_vid_pid_list[][2] = {CFG_TUH_CDC_CP210X_VID_PID_LIST}; static bool cp210x_open(uint8_t daddr, tusb_desc_interface_t const *itf_desc, uint16_t max_len); static void cp210x_process_config(tuh_xfer_t* xfer); @@ -137,10 +131,7 @@ static bool cp210x_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, tuh_ #if CFG_TUH_CDC_CH34X #include "serial/ch34x.h" -static uint16_t const ch34x_vids_pids[][2] = { CFG_TUH_CDC_CH34X_VID_PID_LIST }; -enum { - CH34X_VID_PID_COUNT = TU_ARRAY_SIZE(ch34x_vids_pids) -}; +static uint16_t const ch34x_vid_pid_list[][2] = {CFG_TUH_CDC_CH34X_VID_PID_LIST}; static bool ch34x_open ( uint8_t daddr, tusb_desc_interface_t const *itf_desc, uint16_t max_len ); static void ch34x_process_config ( tuh_xfer_t* xfer ); @@ -164,9 +155,14 @@ enum { #if CFG_TUH_CDC_CH34X SERIAL_DRIVER_CH34X, #endif + + SERIAL_DRIVER_COUNT }; typedef struct { + uint16_t const (*vid_pid_list)[2]; + uint16_t const vid_pid_count; + bool (*const open)(uint8_t daddr, const tusb_desc_interface_t *itf_desc, uint16_t max_len); void (*const process_set_config)(tuh_xfer_t* xfer); bool (*const set_control_line_state)(cdch_interface_t* p_cdc, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data); bool (*const set_baudrate)(cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data); @@ -174,36 +170,50 @@ typedef struct { // Note driver list must be in the same order as SERIAL_DRIVER enum static const cdch_serial_driver_t serial_drivers[] = { - { .process_set_config = acm_process_config, - .set_control_line_state = acm_set_control_line_state, - .set_baudrate = acm_set_baudrate + { + .vid_pid_list = NULL, + .vid_pid_count = 0, + .open = acm_open, + .process_set_config = acm_process_config, + .set_control_line_state = acm_set_control_line_state, + .set_baudrate = acm_set_baudrate }, #if CFG_TUH_CDC_FTDI - { .process_set_config = ftdi_process_config, - .set_control_line_state = ftdi_sio_set_modem_ctrl, - .set_baudrate = ftdi_sio_set_baudrate + { + .vid_pid_list = ftdi_vid_pid_list, + .vid_pid_count = TU_ARRAY_SIZE(ftdi_vid_pid_list), + .open = ftdi_open, + .process_set_config = ftdi_process_config, + .set_control_line_state = ftdi_sio_set_modem_ctrl, + .set_baudrate = ftdi_sio_set_baudrate }, #endif #if CFG_TUH_CDC_CP210X - { .process_set_config = cp210x_process_config, - .set_control_line_state = cp210x_set_modem_ctrl, - .set_baudrate = cp210x_set_baudrate + { + .vid_pid_list = cp210x_vid_pid_list, + .vid_pid_count = TU_ARRAY_SIZE(cp210x_vid_pid_list), + .open = cp210x_open, + .process_set_config = cp210x_process_config, + .set_control_line_state = cp210x_set_modem_ctrl, + .set_baudrate = cp210x_set_baudrate }, #endif #if CFG_TUH_CDC_CH34X - { .process_set_config = ch34x_process_config, - .set_control_line_state = ch34x_set_modem_ctrl, - .set_baudrate = ch34x_set_baudrate + { + .vid_pid_list = ch34x_vid_pid_list, + .vid_pid_count = TU_ARRAY_SIZE(ch34x_vid_pid_list), + .open = ch34x_open, + .process_set_config = ch34x_process_config, + .set_control_line_state = ch34x_set_modem_ctrl, + .set_baudrate = ch34x_set_baudrate }, -#endif + #endif }; -enum { - SERIAL_DRIVER_COUNT = TU_ARRAY_SIZE(serial_drivers) -}; +TU_VERIFY_STATIC(TU_ARRAY_SIZE(serial_drivers) == SERIAL_DRIVER_COUNT, "Serial driver count mismatch"); //--------------------------------------------------------------------+ // INTERNAL OBJECT & FUNCTION DECLARATION @@ -639,36 +649,20 @@ bool cdch_open(uint8_t rhport, uint8_t daddr, tusb_desc_interface_t const *itf_d CDC_COMM_SUBCLASS_ABSTRACT_CONTROL_MODEL == itf_desc->bInterfaceSubClass) { return acm_open(daddr, itf_desc, max_len); } - #if CFG_TUH_CDC_FTDI || CFG_TUH_CDC_CP210X || CFG_TUH_CDC_CH34X - else if (TUSB_CLASS_VENDOR_SPECIFIC == itf_desc->bInterfaceClass) { + else if (SERIAL_DRIVER_COUNT > 1 && + TUSB_CLASS_VENDOR_SPECIFIC == itf_desc->bInterfaceClass) { uint16_t vid, pid; TU_VERIFY(tuh_vid_pid_get(daddr, &vid, &pid)); - #if CFG_TUH_CDC_FTDI - for (size_t i = 0; i < FTDI_PID_COUNT; i++) { - if (ftdi_vid_pid_list[i][0] == vid && ftdi_vid_pid_list[i][1] == pid) { - return ftdi_open(daddr, itf_desc, max_len); - } - } - #endif - - #if CFG_TUH_CDC_CP210X - for (size_t i = 0; i < CP210X_PID_COUNT; i++) { - if (cp210x_vid_pid_list[i][0] == vid && cp210x_vid_pid_list[i][1] == pid) { - return cp210x_open(daddr, itf_desc, max_len); - } - } - #endif - - #if CFG_TUH_CDC_CH34X - for (size_t i = 0; i < CH34X_VID_PID_COUNT; i++) { - if ( ch34x_vids_pids[i][0] == vid && ch34x_vids_pids[i][1] == pid ) { - return ch34x_open(daddr, itf_desc, max_len); + for (size_t dr = 1; dr < SERIAL_DRIVER_COUNT; dr++) { + cdch_serial_driver_t const* driver = &serial_drivers[dr]; + for (size_t i = 0; i < driver->vid_pid_count; i++) { + if (driver->vid_pid_list[i][0] == vid && driver->vid_pid_list[i][1] == pid) { + return driver->open(daddr, itf_desc, max_len); + } } } - #endif } - #endif return false; } @@ -683,9 +677,7 @@ static void set_config_complete(cdch_interface_t * p_cdc, uint8_t idx, uint8_t i usbh_driver_set_config_complete(p_cdc->daddr, itf_num); } - -bool cdch_set_config(uint8_t daddr, uint8_t itf_num) -{ +bool cdch_set_config(uint8_t daddr, uint8_t itf_num) { tusb_control_request_t request; request.wIndex = tu_htole16((uint16_t) itf_num); -- cgit v1.3.1 From 4e6408ea4940085f66c676772d77e3951e82ea11 Mon Sep 17 00:00:00 2001 From: IngHK Date: Tue, 16 Jan 2024 08:07:22 +0100 Subject: CDCh host: further work on CH340/CH341 support --- examples/host/cdc_msc_hid/src/tusb_config.h | 3 +- .../host/cdc_msc_hid_freertos/src/tusb_config.h | 3 +- src/class/cdc/cdc_debug.h | 65 +++ src/class/cdc/cdc_device.c | 21 +- src/class/cdc/cdc_host.c | 568 ++++++++++----------- src/class/cdc/cdc_host.h | 4 +- src/class/cdc/serial/ch34x.h | 103 +--- 7 files changed, 369 insertions(+), 398 deletions(-) create mode 100644 src/class/cdc/cdc_debug.h (limited to 'src/class') diff --git a/examples/host/cdc_msc_hid/src/tusb_config.h b/examples/host/cdc_msc_hid/src/tusb_config.h index 76d59c316..ac14ef97e 100644 --- a/examples/host/cdc_msc_hid/src/tusb_config.h +++ b/examples/host/cdc_msc_hid/src/tusb_config.h @@ -120,8 +120,7 @@ //------------- CDC -------------// // Set Line Control state on enumeration/mounted: -// DTR ( bit 0), RTS (bit 1) -#define CFG_TUH_CDC_LINE_CONTROL_ON_ENUM 0x03 +#define CFG_TUH_CDC_LINE_CONTROL_ON_ENUM ( CDC_CONTROL_LINE_STATE_RTS | CDC_CONTROL_LINE_STATE_DTR ) // Set Line Coding on enumeration/mounted, value for cdc_line_coding_t // bit rate = 115200, 1 stop bit, no parity, 8 bit data width diff --git a/examples/host/cdc_msc_hid_freertos/src/tusb_config.h b/examples/host/cdc_msc_hid_freertos/src/tusb_config.h index bb7c3388d..1b68dd2d8 100644 --- a/examples/host/cdc_msc_hid_freertos/src/tusb_config.h +++ b/examples/host/cdc_msc_hid_freertos/src/tusb_config.h @@ -125,8 +125,7 @@ //------------- CDC -------------// // Set Line Control state on enumeration/mounted: -// DTR ( bit 0), RTS (bit 1) -#define CFG_TUH_CDC_LINE_CONTROL_ON_ENUM 0x03 +#define CFG_TUH_CDC_LINE_CONTROL_ON_ENUM ( CDC_CONTROL_LINE_STATE_RTS | CDC_CONTROL_LINE_STATE_DTR ) // Set Line Coding on enumeration/mounted, value for cdc_line_coding_t // bit rate = 115200, 1 stop bit, no parity, 8 bit data width diff --git a/src/class/cdc/cdc_debug.h b/src/class/cdc/cdc_debug.h new file mode 100644 index 000000000..879e49a50 --- /dev/null +++ b/src/class/cdc/cdc_debug.h @@ -0,0 +1,65 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2023 Ha Thach (tinyusb.org) + * Copyright (c) 2023 IngHK Heiko Kuester + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#ifndef _TUSB_CDC_DEBUG_H_ +#define _TUSB_CDC_DEBUG_H_ + +#include "cdc.h" + +#ifdef __cplusplus + extern "C" { +#endif + +// logging of line coding +#define TU_LOG_LINE_CODING(PRE_TEXT,LINE_CODING) \ + TU_LOG_DRV(PRE_TEXT "Line Coding %lu Bd, %u%c%s\r\n", \ + LINE_CODING.bit_rate, \ + LINE_CODING.data_bits, \ + LINE_CODING.parity == CDC_LINE_CODING_PARITY_NONE ? 'N' : \ + LINE_CODING.parity == CDC_LINE_CODING_PARITY_ODD ? 'O' : \ + LINE_CODING.parity == CDC_LINE_CODING_PARITY_EVEN ? 'E' : \ + LINE_CODING.parity == CDC_LINE_CODING_PARITY_MARK ? 'M' : \ + LINE_CODING.parity == CDC_LINE_CODING_PARITY_SPACE ? 'S' : '?', \ + LINE_CODING.stop_bits == CDC_LINE_CODING_STOP_BITS_1 ? "1" : \ + LINE_CODING.stop_bits == CDC_LINE_CODING_STOP_BITS_1_5 ? "1.5" : \ + LINE_CODING.stop_bits == CDC_LINE_CODING_STOP_BITS_2 ? "2" : "?") + +// logging of baudrate +#define TU_LOG_BAUDRATE(PRE_TEXT,BAUDRATE) \ + TU_LOG_DRV(PRE_TEXT "Baudrate %lu Bd\r\n", BAUDRATE) + + // logging of control line state +#define TU_LOG_CONTROL_LINE_STATE(PRE_TEXT,LINE_STATE) \ + TU_LOG_DRV(PRE_TEXT "Control Line State RTS%c DTR%c\r\n", \ + LINE_STATE & CDC_CONTROL_LINE_STATE_RTS ? '+' : '-', \ + LINE_STATE & CDC_CONTROL_LINE_STATE_DTR ? '+' : '-' ) + +#ifdef __cplusplus + } +#endif + +#endif /* _TUSB_CDC_DEBUG_H_ */ diff --git a/src/class/cdc/cdc_device.c b/src/class/cdc/cdc_device.c index c26264e60..b763419e7 100644 --- a/src/class/cdc/cdc_device.c +++ b/src/class/cdc/cdc_device.c @@ -32,6 +32,9 @@ #include "device/usbd_pvt.h" #include "cdc_device.h" +#if 0 // TODO activate and test +#include "cdc_debug.h" +#endif // Level where CFG_TUSB_DEBUG must be at least for this driver is logged #ifndef CFG_TUD_CDC_LOG_LEVEL @@ -360,7 +363,11 @@ bool cdcd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t case CDC_REQUEST_SET_LINE_CODING: if (stage == CONTROL_STAGE_SETUP) { - TU_LOG_DRV(" Set Line Coding\r\n"); + #if 0 // TODO activate, test and remove else + TU_LOG_LINE_CODING(" Set ", p_cdc->line_coding); + #else + TU_LOG_DRV(" Set Line Coding\r\n"); + #endif tud_control_xfer(rhport, request, &p_cdc->line_coding, sizeof(cdc_line_coding_t)); } else if ( stage == CONTROL_STAGE_ACK) @@ -372,7 +379,11 @@ bool cdcd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t case CDC_REQUEST_GET_LINE_CODING: if (stage == CONTROL_STAGE_SETUP) { - TU_LOG_DRV(" Get Line Coding\r\n"); + #if 0 // TODO activate, test and remove else + TU_LOG_LINE_CODING(" Get ", p_cdc->line_coding); + #else + TU_LOG_DRV(" Get Line Coding\r\n"); + #endif tud_control_xfer(rhport, request, &p_cdc->line_coding, sizeof(cdc_line_coding_t)); } break; @@ -397,7 +408,11 @@ bool cdcd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t // Disable fifo overwriting if DTR bit is set tu_fifo_set_overwritable(&p_cdc->tx_ff, !dtr); - TU_LOG_DRV(" Set Control Line State: DTR = %d, RTS = %d\r\n", dtr, rts); + #if 0 // TODO activate, test and remove else + TU_LOG_CONTROL_LINE_STATE(" Set ", p_cdc->line_state); + #else + TU_LOG_DRV(" Set Control Line State: DTR = %d, RTS = %d\r\n", dtr, rts); + #endif // Invoke callback if ( tud_cdc_line_state_cb ) tud_cdc_line_state_cb(itf, dtr, rts); diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index f6a6773e0..d46bfecb4 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -2,7 +2,7 @@ * The MIT License (MIT) * * Copyright (c) 2019 Ha Thach (tinyusb.org) - * Copyright (c) 2023 Heiko Kuester (CH34x support) + * Copyright (c) 2023 IngHK Heiko Kuester * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -33,6 +33,7 @@ #include "host/usbh_pvt.h" #include "cdc_host.h" +#include "cdc_debug.h" // Level where CFG_TUSB_DEBUG must be at least for this driver is logged #ifndef CFG_TUH_CDC_LOG_LEVEL @@ -55,7 +56,7 @@ typedef struct { cdc_acm_capability_t acm_capability; uint8_t ep_notif; - uint8_t line_state; // DTR (bit0), RTS (bit1) + uint8_t line_state; // RTS, DTR (refer enums CDC_CONTROL_LINE_STATE_RTS, CDC_CONTROL_LINE_STATE_DTR) TU_ATTR_ALIGNED(4) cdc_line_coding_t line_coding; // Baudrate, stop bits, parity, data width tuh_xfer_cb_t user_control_cb; @@ -70,16 +71,9 @@ typedef struct { uint8_t rx_ff_buf[CFG_TUH_CDC_TX_BUFSIZE]; CFG_TUH_MEM_ALIGN uint8_t rx_ep_buf[CFG_TUH_CDC_TX_EPSIZE]; } stream; - #if CFG_TUH_CDC_CH34X - struct { - uint32_t baud_rate; - uint8_t mcr; - uint8_t msr; - uint8_t lcr; - uint32_t quirks; - uint8_t version; - } ch34x; - #endif +#if CFG_TUH_CDC_FTDI || CFG_TUH_CDC_CH34X + uint32_t baudrate_requested; +#endif } cdch_interface_t; CFG_TUH_MEM_SECTION @@ -106,12 +100,10 @@ enum { FTDI_PID_COUNT = sizeof(ftdi_pids) / sizeof(ftdi_pids[0]) }; -// Store last request baudrate since divisor to baudrate is not easy -static uint32_t _ftdi_requested_baud; - static bool ftdi_open(uint8_t daddr, const tusb_desc_interface_t *itf_desc, uint16_t max_len); static void ftdi_process_config(tuh_xfer_t* xfer); +static bool ftdi_set_line_coding(cdch_interface_t* p_cdc, cdc_line_coding_t const* line_coding, tuh_xfer_cb_t complete_cb, uintptr_t user_data); static bool ftdi_sio_set_modem_ctrl(cdch_interface_t* p_cdc, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data); static bool ftdi_sio_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data); #endif @@ -128,6 +120,7 @@ enum { static bool cp210x_open(uint8_t daddr, tusb_desc_interface_t const *itf_desc, uint16_t max_len); static void cp210x_process_config(tuh_xfer_t* xfer); +static bool cp210x_set_line_coding(cdch_interface_t* p_cdc, cdc_line_coding_t const* line_coding, tuh_xfer_cb_t complete_cb, uintptr_t user_data); static bool cp210x_set_modem_ctrl(cdch_interface_t* p_cdc, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data); static bool cp210x_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data); #endif @@ -144,6 +137,7 @@ enum { static bool ch34x_open ( uint8_t daddr, tusb_desc_interface_t const *itf_desc, uint16_t max_len ); static void ch34x_process_config ( tuh_xfer_t* xfer ); +static bool ch34x_set_line_coding(cdch_interface_t* p_cdc, cdc_line_coding_t const* line_coding, tuh_xfer_cb_t complete_cb, uintptr_t user_data); static bool ch34x_set_modem_ctrl ( cdch_interface_t* p_cdc, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data ); static bool ch34x_set_baudrate ( cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data ); #endif @@ -169,35 +163,40 @@ typedef struct { void (*const process_set_config)(tuh_xfer_t* xfer); bool (*const set_control_line_state)(cdch_interface_t* p_cdc, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data); bool (*const set_baudrate)(cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data); + bool (*const set_line_coding)(cdch_interface_t* p_cdc, cdc_line_coding_t const* line_coding, tuh_xfer_cb_t complete_cb, uintptr_t user_data); } cdch_serial_driver_t; // Note driver list must be in the same order as SERIAL_DRIVER enum static const cdch_serial_driver_t serial_drivers[] = { { .process_set_config = acm_process_config, .set_control_line_state = acm_set_control_line_state, - .set_baudrate = acm_set_baudrate + .set_baudrate = acm_set_baudrate, + .set_line_coding = acm_set_line_coding }, #if CFG_TUH_CDC_FTDI { .process_set_config = ftdi_process_config, .set_control_line_state = ftdi_sio_set_modem_ctrl, - .set_baudrate = ftdi_sio_set_baudrate + .set_baudrate = ftdi_sio_set_baudrate, + .set_line_coding = ftdi_set_line_coding }, #endif #if CFG_TUH_CDC_CP210X { .process_set_config = cp210x_process_config, .set_control_line_state = cp210x_set_modem_ctrl, - .set_baudrate = cp210x_set_baudrate + .set_baudrate = cp210x_set_baudrate, + .set_line_coding = cp210x_set_line_coding }, #endif #if CFG_TUH_CDC_CH34X { .process_set_config = ch34x_process_config, .set_control_line_state = ch34x_set_modem_ctrl, - .set_baudrate = ch34x_set_baudrate + .set_baudrate = ch34x_set_baudrate, + .set_line_coding = ch34x_set_line_coding }, -#endif + #endif }; enum { @@ -304,6 +303,7 @@ bool tuh_cdc_get_dtr(uint8_t idx) { cdch_interface_t* p_cdc = get_itf(idx); TU_VERIFY(p_cdc); + TU_LOG_CONTROL_LINE_STATE("CDCh Local ", p_cdc->line_state); return (p_cdc->line_state & CDC_CONTROL_LINE_STATE_DTR) ? true : false; } @@ -312,6 +312,7 @@ bool tuh_cdc_get_rts(uint8_t idx) { cdch_interface_t* p_cdc = get_itf(idx); TU_VERIFY(p_cdc); + TU_LOG_CONTROL_LINE_STATE("CDCh Local ", p_cdc->line_state); return (p_cdc->line_state & CDC_CONTROL_LINE_STATE_RTS) ? true : false; } @@ -322,6 +323,7 @@ bool tuh_cdc_get_local_line_coding(uint8_t idx, cdc_line_coding_t* line_coding) TU_VERIFY(p_cdc); *line_coding = p_cdc->line_coding; + TU_LOG_LINE_CODING("CDCh Get ", p_cdc->line_coding); return true; } @@ -440,7 +442,7 @@ static void cdch_internal_control_complete(tuh_xfer_t* xfer) case FTDI_SIO_SET_BAUD_RATE: // convert from divisor to baudrate is not supported - p_cdc->line_coding.bit_rate = _ftdi_requested_baud; + p_cdc->line_coding.bit_rate = p_cdc->baudrate_requested; break; default: break; @@ -465,12 +467,6 @@ static void cdch_internal_control_complete(tuh_xfer_t* xfer) break; #endif - #if CFG_TUH_CDC_CH34X - case SERIAL_DRIVER_CH34X: - TU_ASSERT(false, ); // see special ch34x_control_complete function - break; - #endif - default: break; } } @@ -487,7 +483,7 @@ bool tuh_cdc_set_control_line_state(uint8_t idx, uint16_t line_state, tuh_xfer_c cdch_serial_driver_t const* driver = &serial_drivers[p_cdc->serial_drid]; if ( complete_cb ) { - return driver->set_control_line_state(p_cdc, line_state, complete_cb, user_data); + TU_VERIFY(driver->set_control_line_state(p_cdc, line_state, complete_cb, user_data)); }else { // blocking xfer_result_t result = XFER_RESULT_INVALID; @@ -501,8 +497,10 @@ bool tuh_cdc_set_control_line_state(uint8_t idx, uint16_t line_state, tuh_xfer_c TU_VERIFY(ret && result == XFER_RESULT_SUCCESS); p_cdc->line_state = (uint8_t) line_state; - return true; } + TU_LOG_CONTROL_LINE_STATE("CDCh Set ", p_cdc->line_state); + + return true; } bool tuh_cdc_set_baudrate(uint8_t idx, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { @@ -511,7 +509,7 @@ bool tuh_cdc_set_baudrate(uint8_t idx, uint32_t baudrate, tuh_xfer_cb_t complete cdch_serial_driver_t const* driver = &serial_drivers[p_cdc->serial_drid]; if ( complete_cb ) { - return driver->set_baudrate(p_cdc, baudrate, complete_cb, user_data); + TU_VERIFY(driver->set_baudrate(p_cdc, baudrate, complete_cb, user_data)); }else { // blocking xfer_result_t result = XFER_RESULT_INVALID; @@ -525,23 +523,24 @@ bool tuh_cdc_set_baudrate(uint8_t idx, uint32_t baudrate, tuh_xfer_cb_t complete TU_VERIFY(ret && result == XFER_RESULT_SUCCESS); p_cdc->line_coding.bit_rate = baudrate; - return true; } + TU_LOG_BAUDRATE("CDCh Set ", p_cdc->line_coding.bit_rate); + + return true; } bool tuh_cdc_set_line_coding(uint8_t idx, cdc_line_coding_t const* line_coding, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { cdch_interface_t* p_cdc = get_itf(idx); - // only ACM support this set line coding request - TU_VERIFY(p_cdc && p_cdc->serial_drid == SERIAL_DRIVER_ACM); - TU_VERIFY(p_cdc->acm_capability.support_line_request); + TU_VERIFY(p_cdc && p_cdc->serial_drid < SERIAL_DRIVER_COUNT); + cdch_serial_driver_t const* driver = &serial_drivers[p_cdc->serial_drid]; if ( complete_cb ) { - return acm_set_line_coding(p_cdc, line_coding, complete_cb, user_data); - }else { + TU_VERIFY(driver->set_line_coding(p_cdc, line_coding, complete_cb, user_data)); + } else { // blocking xfer_result_t result = XFER_RESULT_INVALID; - bool ret = acm_set_line_coding(p_cdc, line_coding, complete_cb, (uintptr_t) &result); + bool ret = driver->set_line_coding(p_cdc, line_coding, complete_cb, (uintptr_t) &result); if (user_data) { // user_data is not NULL, return result via user_data @@ -551,8 +550,10 @@ bool tuh_cdc_set_line_coding(uint8_t idx, cdc_line_coding_t const* line_coding, TU_VERIFY(ret && result == XFER_RESULT_SUCCESS); p_cdc->line_coding = *line_coding; - return true; } + TU_LOG_LINE_CODING("CDCh Set ", p_cdc->line_coding); + + return true; } //--------------------------------------------------------------------+ @@ -684,13 +685,8 @@ bool cdch_open(uint8_t rhport, uint8_t daddr, tusb_desc_interface_t const *itf_d { return acm_open(daddr, itf_desc, max_len); } -<<<<<<< HEAD #if CFG_TUH_CDC_FTDI || CFG_TUH_CDC_CP210X || CFG_TUH_CDC_CH34X - else if ( 0xff == itf_desc->bInterfaceClass ) -======= - #if CFG_TUH_CDC_FTDI || CFG_TUH_CDC_CP210X else if ( TUSB_CLASS_VENDOR_SPECIFIC == itf_desc->bInterfaceClass ) ->>>>>>> remotes/hathach/master { uint16_t vid, pid; TU_VERIFY(tuh_vid_pid_get(daddr, &vid, &pid)); @@ -816,6 +812,8 @@ static bool acm_open(uint8_t daddr, tusb_desc_interface_t const *itf_desc, uint1 TU_ASSERT(open_ep_stream_pair(p_cdc, (tusb_desc_endpoint_t const *) p_desc)); } + TU_LOG_DRV("[%u] CDCh ACM opened\r\n", daddr); + return true; } @@ -852,6 +850,12 @@ static void acm_process_config(tuh_xfer_t* xfer) TU_ATTR_FALLTHROUGH; case CONFIG_ACM_COMPLETE: + #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM + TU_LOG_LINE_CODING("CDCh ACM Init ", p_cdc->line_coding); + #endif + #if CFG_TUH_CDC_LINE_CONTROL_ON_ENUM + TU_LOG_CONTROL_LINE_STATE("CDCh ACM Init", p_cdc->line_state); + #endif // itf_num+1 to account for data interface as well set_config_complete(p_cdc, idx, itf_num+1); break; @@ -893,6 +897,7 @@ static bool acm_set_control_line_state(cdch_interface_t* p_cdc, uint16_t line_st static bool acm_set_line_coding(cdch_interface_t* p_cdc, cdc_line_coding_t const* line_coding, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { TU_LOG_DRV("CDC ACM Set Line Conding\r\n"); + TU_VERIFY(p_cdc->acm_capability.support_line_request); tusb_control_request_t const request = { .bmRequestType_bit = { @@ -994,6 +999,12 @@ static bool ftdi_sio_reset(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, u return ftdi_sio_set_request(p_cdc, FTDI_SIO_RESET, FTDI_SIO_RESET_SIO, complete_cb, user_data); } +static bool ftdi_set_line_coding(cdch_interface_t* p_cdc, cdc_line_coding_t const* line_coding, tuh_xfer_cb_t complete_cb, uintptr_t user_data) +{ + TU_ASSERT(false, false); // TODO + return false; +} + static bool ftdi_sio_set_modem_ctrl(cdch_interface_t* p_cdc, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { TU_LOG_DRV("CDC FTDI Set Control Line State\r\n"); @@ -1035,7 +1046,7 @@ static bool ftdi_sio_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, tu TU_LOG_DRV("CDC FTDI Set BaudRate = %lu, divisor = 0x%04x\r\n", baudrate, divisor); p_cdc->user_control_cb = complete_cb; - _ftdi_requested_baud = baudrate; + p_cdc->baudrate_requested = baudrate; TU_ASSERT(ftdi_sio_set_request(p_cdc, FTDI_SIO_SET_BAUD_RATE, divisor, complete_cb ? cdch_internal_control_complete : NULL, user_data)); @@ -1088,6 +1099,14 @@ static void ftdi_process_config(tuh_xfer_t* xfer) { case CONFIG_FTDI_COMPLETE: set_config_complete(p_cdc, idx, itf_num); + #if 0 // TODO set data format + #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM + TU_LOG_LINE_CODING("CDCh FTDI Init ", p_cdc->line_coding); + #endif + #endif + #if CFG_TUH_CDC_LINE_CONTROL_ON_ENUM + TU_LOG_CONTROL_LINE_STATE("CDCh FTDI Init ", p_cdc->line_state); + #endif break; default: @@ -1166,6 +1185,12 @@ static bool cp210x_ifc_enable(cdch_interface_t* p_cdc, uint16_t enabled, tuh_xfe return cp210x_set_request(p_cdc, CP210X_IFC_ENABLE, enabled, NULL, 0, complete_cb, user_data); } +static bool cp210x_set_line_coding(cdch_interface_t* p_cdc, cdc_line_coding_t const* line_coding, tuh_xfer_cb_t complete_cb, uintptr_t user_data) +{ + TU_ASSERT(false, false); // TODO + return false; +} + static bool cp210x_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { TU_LOG_DRV("CDC CP210x Set BaudRate = %lu\r\n", baudrate); uint32_t baud_le = tu_htole32(baudrate); @@ -1224,6 +1249,12 @@ static void cp210x_process_config(tuh_xfer_t* xfer) { case CONFIG_CP210X_COMPLETE: set_config_complete(p_cdc, idx, itf_num); + #if defined(CFG_TUH_CDC_LINE_CODING_ON_ENUM) && 0 // skip for now + TU_LOG_LINE_CODING("CDCh CP210x Init ", p_cdc->line_coding); + #endif + #if CFG_TUH_CDC_LINE_CONTROL_ON_ENUM + TU_LOG_CONTROL_LINE_STATE("CDCh CP210x Init ", p_cdc->line_state); + #endif break; default: break; @@ -1233,20 +1264,19 @@ static void cp210x_process_config(tuh_xfer_t* xfer) { #endif //--------------------------------------------------------------------+ -// CH34x +// CH34x (CH340 & CH341) //--------------------------------------------------------------------+ #if CFG_TUH_CDC_CH34X +#define CH34X_LOGS false + enum { - CONFIG_CH34X_STEP1 = 0, - CONFIG_CH34X_STEP2, - CONFIG_CH34X_STEP3, - CONFIG_CH34X_STEP4, - CONFIG_CH34X_STEP5, - CONFIG_CH34X_STEP6, - CONFIG_CH34X_STEP7, - CONFIG_CH34X_STEP8, + CONFIG_CH34X_READ_VERSION = 0, + CONFIG_CH34X_SERIAL_INIT, + CONFIG_CH34X_SPECIAL_REG_WRITE, + CONFIG_CH34X_FLOW_CONTROL, + CONFIG_CH34X_MODEM_CONTROL, CONFIG_CH34X_COMPLETE }; @@ -1259,17 +1289,22 @@ static bool ch34x_open ( uint8_t daddr, tusb_desc_interface_t const *itf_desc, u cdch_interface_t *p_cdc = make_new_itf ( daddr, itf_desc ); TU_VERIFY ( p_cdc ); - TU_LOG_DRV ( "CH34x opened\r\n" ); + p_cdc->serial_drid = SERIAL_DRIVER_CH34X; // endpoint pair tusb_desc_endpoint_t const * desc_ep = (tusb_desc_endpoint_t const *) tu_desc_next ( itf_desc ); // data endpoints expected to be in pairs - return open_ep_stream_pair ( p_cdc, desc_ep ); + TU_ASSERT(open_ep_stream_pair(p_cdc, desc_ep), false); + + TU_LOG_DRV("[%u] CDCh CH34x opened\r\n", daddr); + + return true; } -static bool ch34x_set_request ( cdch_interface_t* p_cdc, uint8_t direction, uint8_t request, uint16_t value, uint16_t index, uint8_t* buffer, uint16_t length, tuh_xfer_cb_t complete_cb, uintptr_t user_data ) +static bool ch34x_set_request ( cdch_interface_t* p_cdc, uint8_t direction, uint8_t request, uint16_t value, uint16_t index, + uint8_t* buffer, uint16_t length, tuh_xfer_cb_t complete_cb, uintptr_t user_data ) { tusb_control_request_t const request_setup = { .bmRequestType_bit = { @@ -1297,212 +1332,66 @@ static bool ch34x_set_request ( cdch_interface_t* p_cdc, uint8_t direction, uint .setup = &request_setup, .buffer = enum_buf, .complete_cb = complete_cb, - // CH34x needs a special handling of bInterfaceNumber, because wIndex is used for other purposes and not for bInterfaceNumber - .user_data = (uintptr_t)( ( p_cdc->bInterfaceNumber & 0xff ) << 8 ) | ( user_data & 0xff ) + .user_data = user_data }; return tuh_control_xfer ( &xfer ); - return false; } -static bool ch341_control_out ( cdch_interface_t* p_cdc, uint8_t request, uint16_t value, uint16_t index, tuh_xfer_cb_t complete_cb, uintptr_t user_data ) +static bool ch34x_control_out ( cdch_interface_t* p_cdc, uint8_t request, uint16_t value, uint16_t index, tuh_xfer_cb_t complete_cb, uintptr_t user_data ) { return ch34x_set_request ( p_cdc, TUSB_DIR_OUT, request, value, index, /* buffer */ NULL, /* length */ 0, complete_cb, user_data ); } -static bool ch341_control_in ( cdch_interface_t* p_cdc, uint8_t request, uint16_t value, uint16_t index, uint8_t *buffer, uint16_t buffersize, tuh_xfer_cb_t complete_cb, uintptr_t user_data ) +static bool ch34x_control_in ( cdch_interface_t* p_cdc, uint8_t request, uint16_t value, uint16_t index, + uint8_t *buffer, uint16_t buffersize, tuh_xfer_cb_t complete_cb, uintptr_t user_data ) { return ch34x_set_request ( p_cdc, TUSB_DIR_IN, request, value, index, buffer, buffersize, complete_cb, user_data ); } -static int32_t ch341_write_reg ( cdch_interface_t* p_cdc, uint16_t reg, uint16_t value, tuh_xfer_cb_t complete_cb, uintptr_t user_data ) +static bool ch34x_write_reg ( cdch_interface_t* p_cdc, uint16_t reg, uint16_t value, tuh_xfer_cb_t complete_cb, uintptr_t user_data ) { - return ch341_control_out ( p_cdc, CH341_REQ_WRITE_REG, /* value */ reg, /* index */ value, complete_cb, user_data ); + return ch34x_control_out ( p_cdc, CH34X_REQ_WRITE_REG, /* value */ reg, /* index */ value, complete_cb, user_data ); } -static int32_t ch341_read_reg_request ( cdch_interface_t* p_cdc, uint16_t reg, uint8_t *buffer, uint16_t buffersize, tuh_xfer_cb_t complete_cb, uintptr_t user_data ) -{ - return ch341_control_in ( p_cdc, CH341_REQ_READ_REG, reg, /* index */ 0, buffer, buffersize, complete_cb, user_data ); -} +//static bool ch34x_read_reg_request ( cdch_interface_t* p_cdc, uint16_t reg, +// uint8_t *buffer, uint16_t buffersize, tuh_xfer_cb_t complete_cb, uintptr_t user_data ) +//{ +// return ch34x_control_in ( p_cdc, CH34X_REQ_READ_REG, reg, /* index */ 0, buffer, buffersize, complete_cb, user_data ); +//} -/* - * The device line speed is given by the following equation: - * - * baudrate = 48000000 / (2^(12 - 3 * ps - fact) * div), where - * - * 0 <= ps <= 3, - * 0 <= fact <= 1, - * 2 <= div <= 256 if fact = 0, or - * 9 <= div <= 256 if fact = 1 - */ -// calculate baudrate devisors -// Parts of this functions have been taken over from Linux driver /drivers/usb/serial/ch341.c -static int32_t ch341_get_divisor ( cdch_interface_t* p_cdc, uint32_t speed ) +uint8_t ch34x_xfer_get_itf_num ( tuh_xfer_t* xfer ) +// CH34x needs a special handling to get bInterfaceNumber, because wIndex is used for other purposes and not for bInterfaceNumber +// CH340 and CH341 derivates have always only one interface, so it's OK to check only daddr { - uint32_t fact, div, clk_div; - bool force_fact0 = false; - int32_t ps; - static const uint32_t ch341_min_rates[] = { - CH341_MIN_RATE(0), - CH341_MIN_RATE(1), - CH341_MIN_RATE(2), - CH341_MIN_RATE(3), - }; - - /* - * Clamp to supported range, this makes the (ps < 0) and (div < 2) - * sanity checks below redundant. - */ - inline uint32_t max ( uint32_t val, uint32_t maxval ) { return val > maxval ? val : maxval; } - inline uint32_t min ( uint32_t val, uint32_t minval ) { return val < minval ? val : minval; } - inline uint32_t clamp_val ( uint32_t val, uint32_t minval, uint32_t maxval ) { return min ( max ( val, minval ), maxval ); } - speed = clamp_val(speed, CH341_MIN_BPS, CH341_MAX_BPS); - - /* - * Start with highest possible base clock (fact = 1) that will give a - * divisor strictly less than 512. - */ - fact = 1; - for (ps = 3; ps >= 0; ps--) { - if (speed > ch341_min_rates[ps]) - break; - } - - if (ps < 0) - return -EINVAL; - - /* Determine corresponding divisor, rounding down. */ - clk_div = CH341_CLK_DIV(ps, fact); - div = CH341_CLKRATE / (clk_div * speed); - - /* Some devices require a lower base clock if ps < 3. */ - if (ps < 3 && (p_cdc->ch34x.quirks & CH341_QUIRK_LIMITED_PRESCALER)) - force_fact0 = true; - - /* Halve base clock (fact = 0) if required. */ - if (div < 9 || div > 255 || force_fact0) { - div /= 2; - clk_div *= 2; - fact = 0; - } - - if (div < 2) - return -EINVAL; - - /* - * Pick next divisor if resulting rate is closer to the requested one, - * scale up to avoid rounding errors on low rates. - */ - if (16 * CH341_CLKRATE / (clk_div * div) - 16 * speed >= - 16 * speed - 16 * CH341_CLKRATE / (clk_div * (div + 1))) - div++; - - /* - * Prefer lower base clock (fact = 0) if even divisor. - * - * Note that this makes the receiver more tolerant to errors. - */ - if (fact == 1 && div % 2 == 0) { - div /= 2; - fact = 0; - } - - return (0x100 - div) << 8 | fact << 2 | ps; -} - -// set baudrate (low level) -// do not confuse with ch34x_set_baudrate -// Parts of this functions have been taken over from Linux driver /drivers/usb/serial/ch341.c -static int32_t ch341_set_baudrate ( cdch_interface_t* p_cdc, uint32_t baud_rate, tuh_xfer_cb_t complete_cb, uintptr_t user_data ) -{ - int val; - - if (!baud_rate) - return -EINVAL; - - val = ch341_get_divisor(p_cdc, baud_rate); - if (val < 0) - return -EINVAL; - - /* - * CH341A buffers data until a full endpoint-size packet (32 bytes) - * has been received unless bit 7 is set. - * - * At least one device with version 0x27 appears to have this bit - * inverted. - */ - if ( p_cdc->ch34x.version > 0x27 ) - val |= BIT(7); - - return ch341_write_reg ( p_cdc, CH341_REG_DIVISOR << 8 | CH341_REG_PRESCALER, val, complete_cb, user_data ); -} - -// set lcr register -// Parts of this functions have been taken over from Linux driver /drivers/usb/serial/ch341.c -static int32_t ch341_set_lcr ( cdch_interface_t* p_cdc, uint8_t lcr, tuh_xfer_cb_t complete_cb, uintptr_t user_data ) -{ - /* - * Chip versions before version 0x30 as read using - * CH341_REQ_READ_VERSION used separate registers for line control - * (stop bits, parity and word length). Version 0x30 and above use - * CH341_REG_LCR only and CH341_REG_LCR2 is always set to zero. - */ - if ( p_cdc->ch34x.version < 0x30 ) - return 0; - - return ch341_write_reg ( p_cdc, CH341_REG_LCR2 << 8 | CH341_REG_LCR, lcr, complete_cb, user_data ); -} - -// set handshake (modem controls) -// Parts of this functions have been taken over from Linux driver /drivers/usb/serial/ch341.c -static int32_t ch341_set_handshake ( cdch_interface_t* p_cdc, uint8_t control, tuh_xfer_cb_t complete_cb, uintptr_t user_data ) -{ - return ch341_control_out ( p_cdc, CH341_REQ_MODEM_CTRL, /* value */ ~control, /* index */ 0, complete_cb, user_data ); -} - -// detect quirks (special versions of CH34x) -// Parts of this functions have been taken over from Linux driver /drivers/usb/serial/ch341.c -static int32_t ch341_detect_quirks ( tuh_xfer_t* xfer, cdch_interface_t* p_cdc, uint8_t step, uint8_t *buffer, uint16_t buffersize, tuh_xfer_cb_t complete_cb, uintptr_t user_data ) -{ - /* - * A subset of CH34x devices does not support all features. The - * prescaler is limited and there is no support for sending a RS232 - * break condition. A read failure when trying to set up the latter is - * used to detect these devices. - */ - switch ( step ) + for ( uint8_t i=0; ich34x.quirks = 0; - return ch341_read_reg_request ( p_cdc, CH341_REG_BREAK, buffer, buffersize, complete_cb, user_data ); - break; - case 2: - if ( xfer->result != XFER_RESULT_SUCCESS ) - p_cdc->ch34x.quirks |= CH341_QUIRK_LIMITED_PRESCALER | CH341_QUIRK_SIMULATE_BREAK; - return true; - break; - default: - TU_ASSERT ( false ); // suspicious step - break; + const cdch_interface_t* p_cdc = &cdch_data[i]; + if ( p_cdc->daddr == xfer->daddr ) return p_cdc->bInterfaceNumber; } + + return INTERFACE_INVALID_NUMBER; } // internal control complete to update state such as line state, encoding -// CH34x needs a special interface recovery due to abnormal wIndex usage -static void ch34x_control_complete(tuh_xfer_t* xfer) +static void ch34x_control_complete ( tuh_xfer_t* xfer ) { - uint8_t const itf_num = (uint8_t)( ( xfer->user_data & 0xff00 ) >> 8 ); + uint8_t const itf_num = ch34x_xfer_get_itf_num ( xfer ); uint8_t const idx = tuh_cdc_itf_get_index ( xfer->daddr, itf_num ); cdch_interface_t *p_cdc = get_itf ( idx ); + uint16_t value = tu_le16toh ( xfer->setup->wValue ); TU_ASSERT ( p_cdc, ); TU_ASSERT ( p_cdc->serial_drid == SERIAL_DRIVER_CH34X, ); // ch34x_control_complete is only used for CH34x - if (xfer->result == XFER_RESULT_SUCCESS) { - switch (xfer->setup->bRequest) { - case CH341_REQ_WRITE_REG: { // register write request - switch ( tu_le16toh ( xfer->setup->wValue ) ) { - case ( CH341_REG_DIVISOR << 8 | CH341_REG_PRESCALER ): { // baudrate write - p_cdc->line_coding.bit_rate = p_cdc->ch34x.baud_rate; + if ( xfer->result == XFER_RESULT_SUCCESS ) { + switch ( xfer->setup->bRequest ) { + case CH34X_REQ_WRITE_REG: { // register write request + switch ( value ) { + case ( 0x1312 ): { // baudrate write + p_cdc->line_coding.bit_rate = p_cdc->baudrate_requested; + #if CH34X_LOGS + TU_LOG_BAUDRATE("CDCh CH34x Control Complete ", p_cdc->line_coding.bit_rate); + #endif break; } default: { @@ -1512,6 +1401,20 @@ static void ch34x_control_complete(tuh_xfer_t* xfer) } break; } + case CH34X_REQ_MODEM_CTRL: { // set modem controls RTS/DTR request + if ( ~value & CH34X_BIT_RTS ) + p_cdc->line_state |= CDC_CONTROL_LINE_STATE_RTS; + else + p_cdc->line_state &= ~CDC_CONTROL_LINE_STATE_RTS; + if ( ~value & CH34X_BIT_DTR ) + p_cdc->line_state |= CDC_CONTROL_LINE_STATE_DTR; + else + p_cdc->line_state &= ~CDC_CONTROL_LINE_STATE_DTR; + #if CH34X_LOGS + TU_LOG_CONTROL_LINE_STATE("CDCh CH34x Control Complete ", p_cdc->line_state); + #endif + break; + } default: { TU_ASSERT(false, ); // unexpected request break; @@ -1523,118 +1426,161 @@ static void ch34x_control_complete(tuh_xfer_t* xfer) } } -static bool ch34x_set_baudrate ( cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data ) // do not confuse with ch341_set_baudrate +static bool ch34x_get_factor_divisor ( uint32_t baval, uint8_t *factor, uint8_t *divisor ) +{ // calc baudrate factor and divisor + uint8_t a; + uint8_t b; + uint32_t c; + + switch (baval) { + case 921600: + a = 0xf3; + b = 7; + break; + case 307200: + a = 0xd9; + b = 7; + break; + default: + if (baval > 6000000 / 255) { + b = 3; + c = 6000000; + } else if (baval > 750000 / 255) { + b = 2; + c = 750000; + } else if (baval > 93750 / 255) { + b = 1; + c = 93750; + } else { + b = 0; + c = 11719; + } + a = (unsigned char)(c / baval); + if (a == 0 || a == 0xFF) + return false; + if ((c / a - baval) > (baval - c / (a + 1))) + a++; + a = 256 - a; + break; + } + *factor = a; + *divisor = b; + + return true; +} + +static bool ch34x_set_line_coding(cdch_interface_t* p_cdc, cdc_line_coding_t const* line_coding, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - TU_LOG_DRV("CDC CH34x Set BaudRate = %lu\r\n", baudrate); - uint32_t baud_le = tu_htole32(baudrate); - p_cdc->ch34x.baud_rate = baudrate; + TU_ASSERT(false, false); // TODO + return false; +} + +static bool ch34x_set_baudrate ( cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data ) +{ + p_cdc->baudrate_requested = baudrate; p_cdc->user_control_cb = complete_cb; - return ch341_set_baudrate ( p_cdc, baud_le, complete_cb ? ch34x_control_complete : NULL, user_data ); + uint8_t factor, divisor; + TU_ASSERT ( ch34x_get_factor_divisor ( baudrate, &factor, &divisor ), false ); + TU_ASSERT ( ch34x_write_reg ( p_cdc, /* reg */ 0x1312, /* value */ (uint16_t)factor << 8 | 0x80 | divisor, + complete_cb ? ch34x_control_complete : NULL, user_data ), false ); + + return true; } static bool ch34x_set_modem_ctrl ( cdch_interface_t* p_cdc, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data ) { - TU_LOG_DRV("CDC CH34x Set Control Line State\r\n"); - // todo later - return false; + p_cdc->user_control_cb = complete_cb; + uint16_t control = 0; + if ( line_state & CDC_CONTROL_LINE_STATE_RTS ) + control |= CH34X_BIT_RTS; + if ( line_state & CDC_CONTROL_LINE_STATE_DTR ) + control |= CH34X_BIT_DTR; + TU_ASSERT ( ch34x_control_out ( p_cdc, /* request */ CH34X_REQ_MODEM_CTRL, /* value */ (uint8_t)~control, + /* index */ 0, complete_cb ? ch34x_control_complete : NULL, user_data ), false ); + return true; } static void ch34x_process_config ( tuh_xfer_t* xfer ) { - uintptr_t const state = xfer->user_data & 0xff; - // CH34x needs a special handling of bInterfaceNumber, because wIndex is used for other purposes and not for bInterfaceNumber - uint8_t const itf_num = (uint8_t)( ( xfer->user_data & 0xff00 ) >> 8 ); - uint8_t const idx = tuh_cdc_itf_get_index ( xfer->daddr, itf_num ); - cdch_interface_t *p_cdc = get_itf ( idx ); - uint8_t buffer [ CH34X_BUFFER_SIZE ]; - cdc_line_coding_t line_coding = CFG_TUH_CDC_LINE_CODING_ON_ENUM; + uint8_t const itf_num = ch34x_xfer_get_itf_num ( xfer ); + uintptr_t const state = xfer->user_data; + uint8_t const idx = tuh_cdc_itf_get_index ( xfer->daddr, itf_num ); + cdch_interface_t *p_cdc = get_itf ( idx ); + cdc_line_coding_t const line_coding = CFG_TUH_CDC_LINE_CODING_ON_ENUM_CH34X; + uint8_t buffer[2]; TU_ASSERT ( p_cdc, ); - if ( state == 0 ) { - // defaults - p_cdc->ch34x.baud_rate = DEFAULT_BAUD_RATE; - p_cdc->ch34x.mcr = 0; - p_cdc->ch34x.msr = 0; - p_cdc->ch34x.quirks = 0; - p_cdc->ch34x.version = 0; - /* - * Some CH340 devices appear unable to change the initial LCR - * settings, so set a sane 8N1 default. - */ - p_cdc->ch34x.lcr = CH341_LCR_ENABLE_RX | CH341_LCR_ENABLE_TX | CH341_LCR_CS8; - } - // This process flow has been taken over from Linux driver /drivers/usb/serial/ch341.c switch ( state ) { - case CONFIG_CH34X_STEP1: // request version read - TU_ASSERT ( ch341_control_in ( p_cdc, /* request */ CH341_REQ_READ_VERSION, /* value */ 0, /* index */ 0, buffer, CH34X_BUFFER_SIZE, ch34x_process_config, CONFIG_CH34X_STEP2 ), ); - break; - case CONFIG_CH34X_STEP2: // handle version read data, request to init CH34x - p_cdc->ch34x.version = xfer->buffer[0]; - TU_LOG_DRV ( "Chip version=%02x\r\n", p_cdc->ch34x.version ); - TU_ASSERT ( ch341_control_out ( p_cdc, /* request */ CH341_REQ_SERIAL_INIT, /* value */ 0, /* index */ 0, ch34x_process_config, CONFIG_CH34X_STEP3 ), ); - break; - case CONFIG_CH34X_STEP3: // set baudrate with default values (see above) - TU_ASSERT ( ch341_set_baudrate ( p_cdc, p_cdc->ch34x.baud_rate, ch34x_process_config, CONFIG_CH34X_STEP4 ) > 0, ); - break; - case CONFIG_CH34X_STEP4: // set line controls with default values (see above) - TU_ASSERT ( ch341_set_lcr ( p_cdc, p_cdc->ch34x.lcr, ch34x_process_config, CONFIG_CH34X_STEP5 ) > 0, ); - break; - case CONFIG_CH34X_STEP5: // set handshake RTS/DTR - TU_ASSERT ( ch341_set_handshake ( p_cdc, p_cdc->ch34x.mcr, ch34x_process_config, CONFIG_CH34X_STEP6 ) > 0, ); - break; - case CONFIG_CH34X_STEP6: // detect quirks step 1 - TU_ASSERT ( ch341_detect_quirks ( xfer, p_cdc, /* step */ 1, buffer, CH34X_BUFFER_SIZE, ch34x_process_config, CONFIG_CH34X_STEP7 ) > 0, ); - break; - case CONFIG_CH34X_STEP7: // detect quirks step 2 and set baudrate with configured values - TU_ASSERT ( ch341_detect_quirks ( xfer, p_cdc, /* step */ 2, NULL, 0, NULL, 0 ) > 0, ); -#ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM - TU_ASSERT ( ch34x_set_baudrate ( p_cdc, line_coding.bit_rate, ch34x_process_config, CONFIG_CH34X_STEP8 ), ); -#else - TU_ATTR_FALLTHROUGH; -#endif + case CONFIG_CH34X_READ_VERSION: // request version read + #if CH34X_LOGS + TU_LOG_DRV ( "[%u] CDCh CH34x Process Config started\r\n", p_cdc->daddr ); + #endif + TU_ASSERT ( ch34x_control_in ( p_cdc, /* request */ CH34X_REQ_READ_VERSION, /* value */ 0, + /* index */ 0, buffer, 2, ch34x_process_config, CONFIG_CH34X_SERIAL_INIT ), ); break; - case CONFIG_CH34X_STEP8: // set data/stop bit quantities, parity -#ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM - p_cdc->ch34x.lcr = CH341_LCR_ENABLE_RX | CH341_LCR_ENABLE_TX; + case CONFIG_CH34X_SERIAL_INIT: { // handle version read data, request to init CH34x with line_coding and baudrate + uint8_t version = xfer->buffer[0]; + #if CH34X_LOGS + TU_LOG_DRV ( "[%u] CDCh CH34x Chip version=%02x\r\n", p_cdc->daddr, version ); + #endif + // only versions >= 0x30 are tested, below 0x30 seems having other programming, see WCH vendor, linux kernel and FreeBSD drivers + TU_ASSERT ( version >= 0x30, ); + uint8_t factor, divisor; + TU_ASSERT ( ch34x_get_factor_divisor ( line_coding.bit_rate, &factor, &divisor ), ); + uint8_t lcr = CH34X_LCR_ENABLE_RX | CH34X_LCR_ENABLE_TX; switch ( line_coding.data_bits ) { case 5: - p_cdc->ch34x.lcr |= CH341_LCR_CS5; + lcr |= CH34X_LCR_CS5; break; case 6: - p_cdc->ch34x.lcr |= CH341_LCR_CS6; + lcr |= CH34X_LCR_CS6; break; case 7: - p_cdc->ch34x.lcr |= CH341_LCR_CS7; + lcr |= CH34X_LCR_CS7; break; case 8: - p_cdc->ch34x.lcr |= CH341_LCR_CS8; + lcr |= CH34X_LCR_CS8; break; default: TU_ASSERT ( false, ); // not supported data_bits - p_cdc->ch34x.lcr |= CH341_LCR_CS8; + lcr |= CH34X_LCR_CS8; break; } if ( line_coding.parity != CDC_LINE_CODING_PARITY_NONE ) { - p_cdc->ch34x.lcr |= CH341_LCR_ENABLE_PAR; + lcr |= CH34X_LCR_ENABLE_PAR; if ( line_coding.parity == CDC_LINE_CODING_PARITY_EVEN || line_coding.parity == CDC_LINE_CODING_PARITY_SPACE ) - p_cdc->ch34x.lcr |= CH341_LCR_PAR_EVEN; + lcr |= CH34X_LCR_PAR_EVEN; if ( line_coding.parity == CDC_LINE_CODING_PARITY_MARK || line_coding.parity == CDC_LINE_CODING_PARITY_SPACE ) - p_cdc->ch34x.lcr |= CH341_LCR_MARK_SPACE; + lcr |= CH34X_LCR_MARK_SPACE; } TU_ASSERT ( line_coding.stop_bits == CDC_LINE_CODING_STOP_BITS_1 || line_coding.stop_bits == CDC_LINE_CODING_STOP_BITS_2, ); // not supported 1.5 stop bits if ( line_coding.stop_bits == CDC_LINE_CODING_STOP_BITS_2 ) - p_cdc->ch34x.lcr |= CH341_LCR_STOP_BITS_2; - TU_ASSERT ( ch341_set_lcr ( p_cdc, p_cdc->ch34x.lcr, ch34x_process_config, CONFIG_CH34X_COMPLETE ) > 0, ); -#else - TU_ATTR_FALLTHROUGH; -#endif + lcr |= CH34X_LCR_STOP_BITS_2; + TU_ASSERT ( ch34x_control_out ( p_cdc, /* request */ CH34X_REQ_SERIAL_INIT, /* value */ (uint16_t)lcr << 8 | 0x9c, + /* index */ (uint16_t)factor << 8 | 0x80 | divisor, ch34x_process_config, CONFIG_CH34X_SPECIAL_REG_WRITE ), ); + break; + } + case CONFIG_CH34X_SPECIAL_REG_WRITE: // do special reg write, purpose unknown, overtaken from WCH driver + TU_ASSERT ( ch34x_write_reg ( p_cdc, /* reg */ 0x0f2c, /* value */ 0x0007, ch34x_process_config, CONFIG_CH34X_FLOW_CONTROL ), ); + break; + case CONFIG_CH34X_FLOW_CONTROL: // no hardware flow control + TU_ASSERT ( ch34x_write_reg ( p_cdc, /* reg */ 0x2727, /* value */ 0x0000, ch34x_process_config, CONFIG_CH34X_MODEM_CONTROL ), ); + break; + case CONFIG_CH34X_MODEM_CONTROL: // !always! set modem controls RTS/DTR (CH34x has no reset state after CH34X_REQ_SERIAL_INIT) + TU_ASSERT ( ch34x_set_modem_ctrl ( p_cdc, CFG_TUH_CDC_LINE_CONTROL_ON_ENUM, ch34x_process_config, CONFIG_CH34X_COMPLETE ), ); + break; + case CONFIG_CH34X_COMPLETE: + p_cdc->line_coding = line_coding; // CONFIG_CH34X_SERIAL_INIT not handled by ch34x_control_complete + #if CH34X_LOGS + TU_LOG_DRV("CDCh CH34x Process Config Complete\r\n"); + TU_LOG_LINE_CODING(" ", p_cdc->line_coding); + TU_LOG_CONTROL_LINE_STATE(" ", p_cdc->line_state); + #endif + set_config_complete ( p_cdc, idx, itf_num ); + break; + default: + TU_ASSERT ( false, ); break; - case CONFIG_CH34X_COMPLETE: - set_config_complete ( p_cdc, idx, itf_num ); - break; - default: - TU_ASSERT ( false, ); - break; } } diff --git a/src/class/cdc/cdc_host.h b/src/class/cdc/cdc_host.h index 9e5edd94e..8e3a2352a 100644 --- a/src/class/cdc/cdc_host.h +++ b/src/class/cdc/cdc_host.h @@ -37,7 +37,7 @@ // Class Driver Configuration //--------------------------------------------------------------------+ -// Set Line Control state on enumeration/mounted: DTR ( bit 0), RTS (bit 1) +// Set Line Control state on enumeration/mounted, refer enums CDC_CONTROL_LINE_STATE_RTS, CDC_CONTROL_LINE_STATE_DTR #ifndef CFG_TUH_CDC_LINE_CONTROL_ON_ENUM #define CFG_TUH_CDC_LINE_CONTROL_ON_ENUM 0 #endif @@ -142,7 +142,7 @@ bool tuh_cdc_read_clear (uint8_t idx); // - The function will return true if transfer is successful, false otherwise. //--------------------------------------------------------------------+ -// Request to Set Control Line State: DTR (bit 0), RTS (bit 1) +// Request to Set Control Line State, refer enums CDC_CONTROL_LINE_STATE_RTS, CDC_CONTROL_LINE_STATE_DTR bool tuh_cdc_set_control_line_state(uint8_t idx, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data); // Request to set baudrate diff --git a/src/class/cdc/serial/ch34x.h b/src/class/cdc/serial/ch34x.h index 94e18b252..262e012fd 100644 --- a/src/class/cdc/serial/ch34x.h +++ b/src/class/cdc/serial/ch34x.h @@ -1,7 +1,7 @@ /* * The MIT License (MIT) * - * Copyright (c) 2023 Heiko Kuester (tinyusb.org) + * Copyright (c) 2023 IngHK Heiko Kuester (tinyusb.org) * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -27,87 +27,34 @@ #ifndef _CH34X_H_ #define _CH34X_H_ -#include - -#define BIT(nr) ( (uint32_t)1 << (nr) ) - -#define CH34X_BUFFER_SIZE 2 - -// The following defines have been taken over from Linux driver /drivers/usb/serial/ch341.c - -#define DEFAULT_BAUD_RATE 9600 - -/* flags for IO-Bits */ -#define CH341_BIT_RTS (1 << 6) -#define CH341_BIT_DTR (1 << 5) - -/******************************/ -/* interrupt pipe definitions */ -/******************************/ -/* always 4 interrupt bytes */ -/* first irq byte normally 0x08 */ -/* second irq byte base 0x7d + below */ -/* third irq byte base 0x94 + below */ -/* fourth irq byte normally 0xee */ - -/* second interrupt byte */ -#define CH341_MULT_STAT 0x04 /* multiple status since last interrupt event */ - -/* status returned in third interrupt answer byte, inverted in data - from irq */ -#define CH341_BIT_CTS 0x01 -#define CH341_BIT_DSR 0x02 -#define CH341_BIT_RI 0x04 -#define CH341_BIT_DCD 0x08 -#define CH341_BITS_MODEM_STAT 0x0f /* all bits */ - -/* Break support - the information used to implement this was gleaned from - * the Net/FreeBSD uchcom.c driver by Takanori Watanabe. Domo arigato. - */ +// set line_coding @ enumeration +#ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM +#define CFG_TUH_CDC_LINE_CODING_ON_ENUM_CH34X CFG_TUH_CDC_LINE_CODING_ON_ENUM +#else // this default is necessary to work properly +#define CFG_TUH_CDC_LINE_CODING_ON_ENUM_CH34X { 9600, CDC_LINE_CONDING_STOP_BITS_1, CDC_LINE_CODING_PARITY_NONE, 8 } +#endif // USB requests -#define CH341_REQ_READ_VERSION 0x5F // dec 95 -#define CH341_REQ_WRITE_REG 0x9A -#define CH341_REQ_READ_REG 0x95 -#define CH341_REQ_SERIAL_INIT 0xA1 -#define CH341_REQ_MODEM_CTRL 0xA4 +#define CH34X_REQ_READ_VERSION 0x5F // dec 95 +#define CH34X_REQ_WRITE_REG 0x9A // dec 154 +#define CH34X_REQ_READ_REG 0x95 // dec 149 +#define CH34X_REQ_SERIAL_INIT 0xA1 // dec 161 +#define CH34X_REQ_MODEM_CTRL 0xA4 // dev 164 -// CH34x registers -#define CH341_REG_BREAK 0x05 -#define CH341_REG_PRESCALER 0x12 -#define CH341_REG_DIVISOR 0x13 -#define CH341_REG_LCR 0x18 -#define CH341_REG_LCR2 0x25 - -#define CH341_NBREAK_BITS 0x01 +// modem control bits +#define CH34X_BIT_RTS ( 1 << 6 ) +#define CH34X_BIT_DTR ( 1 << 5 ) // line control bits -#define CH341_LCR_ENABLE_RX 0x80 -#define CH341_LCR_ENABLE_TX 0x40 -#define CH341_LCR_MARK_SPACE 0x20 -#define CH341_LCR_PAR_EVEN 0x10 -#define CH341_LCR_ENABLE_PAR 0x08 -#define CH341_LCR_STOP_BITS_2 0x04 -#define CH341_LCR_CS8 0x03 -#define CH341_LCR_CS7 0x02 -#define CH341_LCR_CS6 0x01 -#define CH341_LCR_CS5 0x00 - -#define CH341_QUIRK_LIMITED_PRESCALER BIT(0) -#define CH341_QUIRK_SIMULATE_BREAK BIT(1) - -#define CH341_CLKRATE 48000000 -#define CH341_CLK_DIV(ps, fact) (1 << (12 - 3 * (ps) - (fact))) -#define CH341_MIN_RATE(ps) (CH341_CLKRATE / (CH341_CLK_DIV((ps), 1) * 512)) - -/* Supported range is 46 to 3000000 bps. */ -#define CH341_MIN_BPS DIV_ROUND_UP(CH341_CLKRATE, CH341_CLK_DIV(0, 0) * 256) -#define CH341_MAX_BPS (CH341_CLKRATE / (CH341_CLK_DIV(3, 0) * 2)) - -#define DIV_ROUND_UP __KERNEL_DIV_ROUND_UP -#define __KERNEL_DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d)) - -// error codes -#define EINVAL 22 /* Invalid argument */ +#define CH34X_LCR_ENABLE_RX 0x80 +#define CH34X_LCR_ENABLE_TX 0x40 +#define CH34X_LCR_MARK_SPACE 0x20 +#define CH34X_LCR_PAR_EVEN 0x10 +#define CH34X_LCR_ENABLE_PAR 0x08 +#define CH34X_LCR_STOP_BITS_2 0x04 +#define CH34X_LCR_CS8 0x03 +#define CH34X_LCR_CS7 0x02 +#define CH34X_LCR_CS6 0x01 +#define CH34X_LCR_CS5 0x00 #endif /* _CH34X_H_ */ -- cgit v1.3.1 From 07e3d5c69192b1c45d52fc9760ab0ee65d8b0f0c Mon Sep 17 00:00:00 2001 From: hathach Date: Tue, 16 Jan 2024 13:16:53 +0700 Subject: fix number of endpoint for ch340x, also open notification even not used for now --- src/class/cdc/cdc_host.c | 67 +++++++++++++++++++++++--------------------- src/class/cdc/serial/ch34x.h | 6 ++-- 2 files changed, 38 insertions(+), 35 deletions(-) (limited to 'src/class') diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index 91e35ec8c..f7213d558 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -471,9 +471,9 @@ bool tuh_cdc_set_control_line_state(uint8_t idx, uint16_t line_state, tuh_xfer_c TU_VERIFY(p_cdc && p_cdc->serial_drid < SERIAL_DRIVER_COUNT); cdch_serial_driver_t const* driver = &serial_drivers[p_cdc->serial_drid]; - if ( complete_cb ) { + if (complete_cb) { return driver->set_control_line_state(p_cdc, line_state, complete_cb, user_data); - }else { + } else { // blocking xfer_result_t result = XFER_RESULT_INVALID; bool ret = driver->set_control_line_state(p_cdc, line_state, complete_cb, (uintptr_t) &result); @@ -494,9 +494,9 @@ bool tuh_cdc_set_baudrate(uint8_t idx, uint32_t baudrate, tuh_xfer_cb_t complete TU_VERIFY(p_cdc && p_cdc->serial_drid < SERIAL_DRIVER_COUNT); cdch_serial_driver_t const* driver = &serial_drivers[p_cdc->serial_drid]; - if ( complete_cb ) { + if (complete_cb) { return driver->set_baudrate(p_cdc, baudrate, complete_cb, user_data); - }else { + } else { // blocking xfer_result_t result = XFER_RESULT_INVALID; bool ret = driver->set_baudrate(p_cdc, baudrate, complete_cb, (uintptr_t) &result); @@ -512,16 +512,15 @@ bool tuh_cdc_set_baudrate(uint8_t idx, uint32_t baudrate, tuh_xfer_cb_t complete } } -bool tuh_cdc_set_line_coding(uint8_t idx, cdc_line_coding_t const* line_coding, tuh_xfer_cb_t complete_cb, uintptr_t user_data) -{ +bool tuh_cdc_set_line_coding(uint8_t idx, cdc_line_coding_t const* line_coding, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { cdch_interface_t* p_cdc = get_itf(idx); // only ACM support this set line coding request TU_VERIFY(p_cdc && p_cdc->serial_drid == SERIAL_DRIVER_ACM); TU_VERIFY(p_cdc->acm_capability.support_line_request); - if ( complete_cb ) { + if (complete_cb) { return acm_set_line_coding(p_cdc, line_coding, complete_cb, user_data); - }else { + } else { // blocking xfer_result_t result = XFER_RESULT_INVALID; bool ret = acm_set_line_coding(p_cdc, line_coding, complete_cb, (uintptr_t) &result); @@ -711,7 +710,6 @@ static bool acm_open(uint8_t daddr, tusb_desc_interface_t const* itf_desc, uint1 cdch_interface_t* p_cdc = make_new_itf(daddr, itf_desc); TU_VERIFY(p_cdc); - p_cdc->serial_drid = SERIAL_DRIVER_ACM; //------------- Control Interface -------------// @@ -881,7 +879,6 @@ static bool ftdi_open(uint8_t daddr, const tusb_desc_interface_t *itf_desc, uint TU_VERIFY(p_cdc); TU_LOG_DRV("FTDI opened\r\n"); - p_cdc->serial_drid = SERIAL_DRIVER_FTDI; // endpoint pair @@ -921,8 +918,7 @@ static bool ftdi_sio_reset(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, u return ftdi_sio_set_request(p_cdc, FTDI_SIO_RESET, FTDI_SIO_RESET_SIO, complete_cb, user_data); } -static bool -ftdi_sio_set_modem_ctrl(cdch_interface_t* p_cdc, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { +static bool ftdi_sio_set_modem_ctrl(cdch_interface_t* p_cdc, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { TU_LOG_DRV("CDC FTDI Set Control Line State\r\n"); p_cdc->user_control_cb = complete_cb; TU_ASSERT(ftdi_sio_set_request(p_cdc, FTDI_SIO_MODEM_CTRL, 0x0300 | line_state, @@ -1171,26 +1167,34 @@ enum { CONFIG_CH34X_COMPLETE }; -static bool ch34x_open ( uint8_t daddr, tusb_desc_interface_t const *itf_desc, uint16_t max_len ) { - // CH34x Interface includes 1 vendor interface + 3 bulk endpoints - TU_VERIFY ( itf_desc->bNumEndpoints == 3 ); - TU_VERIFY ( sizeof ( tusb_desc_interface_t ) + 2 * sizeof ( tusb_desc_endpoint_t ) <= max_len ); +static bool ch34x_open(uint8_t daddr, tusb_desc_interface_t const* itf_desc, uint16_t max_len) { + // CH34x Interface includes 1 vendor interface + 2 bulk + 1 interrupt endpoints + TU_VERIFY (itf_desc->bNumEndpoints == 3); + TU_VERIFY (sizeof(tusb_desc_interface_t) + 3 * sizeof(tusb_desc_endpoint_t) <= max_len); - cdch_interface_t *p_cdc = make_new_itf ( daddr, itf_desc ); - TU_VERIFY ( p_cdc ); + cdch_interface_t* p_cdc = make_new_itf(daddr, itf_desc); + TU_VERIFY (p_cdc); - TU_LOG_DRV ( "CH34x opened\r\n" ); + TU_LOG_DRV ("CH34x opened\r\n"); p_cdc->serial_drid = SERIAL_DRIVER_CH34X; - // endpoint pair - tusb_desc_endpoint_t const * desc_ep = (tusb_desc_endpoint_t const *) tu_desc_next ( itf_desc ); + tusb_desc_endpoint_t const* desc_ep = (tusb_desc_endpoint_t const*) tu_desc_next(itf_desc); // data endpoints expected to be in pairs - return open_ep_stream_pair ( p_cdc, desc_ep ); + TU_ASSERT(open_ep_stream_pair(p_cdc, desc_ep)); + desc_ep += 2; + + // Interrupt endpoint: not used for now + TU_ASSERT(TUSB_DESC_ENDPOINT == tu_desc_type(desc_ep) && + TUSB_XFER_INTERRUPT == desc_ep->bmAttributes.xfer); + TU_ASSERT(tuh_edpt_open(daddr, desc_ep)); + p_cdc->ep_notif = desc_ep->bEndpointAddress; + + return true; } -static bool ch34x_set_request ( cdch_interface_t* p_cdc, uint8_t direction, uint8_t request, uint16_t value, uint16_t index, uint8_t* buffer, uint16_t length, tuh_xfer_cb_t complete_cb, uintptr_t user_data ) -{ +static bool ch34x_set_request(cdch_interface_t* p_cdc, uint8_t direction, uint8_t request, uint16_t value, + uint16_t index, uint8_t* buffer, uint16_t length, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { tusb_control_request_t const request_setup = { .bmRequestType_bit = { .recipient = TUSB_REQ_RCPT_DEVICE, @@ -1198,17 +1202,17 @@ static bool ch34x_set_request ( cdch_interface_t* p_cdc, uint8_t direction, uint .direction = direction & 0x01u }, .bRequest = request, - .wValue = tu_htole16 ( value ), - .wIndex = tu_htole16 ( index ), - .wLength = tu_htole16 ( length ) + .wValue = tu_htole16 (value), + .wIndex = tu_htole16 (index), + .wLength = tu_htole16 (length) }; // use usbh enum buf since application variable does not live long enough uint8_t* enum_buf = NULL; - if ( buffer && length > 0 ) { + if (buffer && length > 0) { enum_buf = usbh_get_enum_buf(); - tu_memcpy_s ( enum_buf, CFG_TUH_ENUMERATION_BUFSIZE, buffer, length ); + tu_memcpy_s(enum_buf, CFG_TUH_ENUMERATION_BUFSIZE, buffer, length); } tuh_xfer_t xfer = { @@ -1218,11 +1222,10 @@ static bool ch34x_set_request ( cdch_interface_t* p_cdc, uint8_t direction, uint .buffer = enum_buf, .complete_cb = complete_cb, // CH34x needs a special handling of bInterfaceNumber, because wIndex is used for other purposes and not for bInterfaceNumber - .user_data = (uintptr_t)( ( p_cdc->bInterfaceNumber & 0xff ) << 8 ) | ( user_data & 0xff ) + .user_data = (uintptr_t) ((p_cdc->bInterfaceNumber & 0xff) << 8) | (user_data & 0xff) }; - return tuh_control_xfer ( &xfer ); - return false; + return tuh_control_xfer(&xfer); } static bool ch341_control_out ( cdch_interface_t* p_cdc, uint8_t request, uint16_t value, uint16_t index, tuh_xfer_cb_t complete_cb, uintptr_t user_data ) { diff --git a/src/class/cdc/serial/ch34x.h b/src/class/cdc/serial/ch34x.h index 4a5e61bbd..cc3ac99fe 100644 --- a/src/class/cdc/serial/ch34x.h +++ b/src/class/cdc/serial/ch34x.h @@ -1,7 +1,7 @@ /* * The MIT License (MIT) * - * Copyright (c) 2023 Heiko Kuester (tinyusb.org) + * Copyright (c) 2023 Heiko Kuester * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -34,6 +34,7 @@ #define CH34X_BUFFER_SIZE 2 // The following defines have been taken over from Linux driver /drivers/usb/serial/ch341.c +// Note: updated driver can also be found in https://github.com/WCHSoftGroup/ch341ser_linux/tree/main/driver #define DEFAULT_BAUD_RATE 9600 @@ -53,8 +54,7 @@ /* second interrupt byte */ #define CH341_MULT_STAT 0x04 /* multiple status since last interrupt event */ -/* status returned in third interrupt answer byte, inverted in data - from irq */ +/* status returned in third interrupt answer byte, inverted in data from irq */ #define CH341_BIT_CTS 0x01 #define CH341_BIT_DSR 0x02 #define CH341_BIT_RI 0x04 -- cgit v1.3.1 From 46ac03ba8537a32ae2bf1f7d864879657b696f81 Mon Sep 17 00:00:00 2001 From: hathach Date: Tue, 16 Jan 2024 17:45:16 +0700 Subject: change code style --- src/class/cdc/cdc_host.c | 97 +++++++++++++++++++++++------------------------- 1 file changed, 46 insertions(+), 51 deletions(-) (limited to 'src/class') diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index 8ef26a7d9..5541b5dee 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -1291,25 +1291,22 @@ static void ch34x_control_complete(tuh_xfer_t* xfer) { if (xfer->result == XFER_RESULT_SUCCESS) { switch (xfer->setup->bRequest) { - case CH34X_REQ_WRITE_REG: { // register write request + case CH34X_REQ_WRITE_REG: + // register write request switch (value) { - case (0x1312): { // baudrate write + case (0x1312): + // baudrate write p_cdc->line_coding.bit_rate = p_cdc->baudrate_requested; - #if CH34X_LOGS - TU_LOG_BAUDRATE("CDCh CH34x Control Complete ", p_cdc->line_coding.bit_rate); - #endif break; - } - default: { + default: TU_ASSERT(false,); // unexpected register write break; - } } break; - } - case CH34X_REQ_MODEM_CTRL: { // set modem controls RTS/DTR request + case CH34X_REQ_MODEM_CTRL: + // set modem controls RTS/DTR request if (~value & CH34X_BIT_RTS) { p_cdc->line_state |= CDC_CONTROL_LINE_STATE_RTS; } else { @@ -1322,16 +1319,11 @@ static void ch34x_control_complete(tuh_xfer_t* xfer) { p_cdc->line_state &= (uint8_t ) ~CDC_CONTROL_LINE_STATE_DTR; } - #if CH34X_LOGS - TU_LOG_CONTROL_LINE_STATE("CDCh CH34x Control Complete ", p_cdc->line_state); - #endif break; - } - default: { + default: TU_ASSERT(false,); // unexpected request break; - } } xfer->complete_cb = p_cdc->user_control_cb; @@ -1393,33 +1385,31 @@ static bool ch34x_set_line_coding(cdch_interface_t* p_cdc, cdc_line_coding_t con return false; } -static bool -ch34x_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfer_cb_t complete_cb, - uintptr_t user_data) { +static bool ch34x_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, + tuh_xfer_cb_t complete_cb, uintptr_t user_data) { p_cdc->baudrate_requested = baudrate; p_cdc->user_control_cb = complete_cb; uint8_t factor, divisor; - TU_ASSERT (ch34x_get_factor_divisor(baudrate, &factor, &divisor), false); + TU_ASSERT (ch34x_get_factor_divisor(baudrate, &factor, &divisor)); uint16_t const value = (uint16_t ) (factor << 8 | 0x80 | divisor); - TU_ASSERT ( - ch34x_write_reg(p_cdc, /* reg */ 0x1312, /* value */ value, - complete_cb ? ch34x_control_complete : NULL, user_data), false); + TU_ASSERT (ch34x_write_reg(p_cdc, 0x1312, value, + complete_cb ? ch34x_control_complete : NULL, user_data)); return true; } -static bool -ch34x_set_modem_ctrl(cdch_interface_t* p_cdc, uint16_t line_state, tuh_xfer_cb_t complete_cb, - uintptr_t user_data) { +static bool ch34x_set_modem_ctrl(cdch_interface_t* p_cdc, uint16_t line_state, + tuh_xfer_cb_t complete_cb, uintptr_t user_data) { p_cdc->user_control_cb = complete_cb; uint16_t control = 0; - if (line_state & CDC_CONTROL_LINE_STATE_RTS) + if (line_state & CDC_CONTROL_LINE_STATE_RTS) { control |= CH34X_BIT_RTS; - if (line_state & CDC_CONTROL_LINE_STATE_DTR) + } + if (line_state & CDC_CONTROL_LINE_STATE_DTR) { control |= CH34X_BIT_DTR; - TU_ASSERT ( - ch34x_control_out(p_cdc, /* request */ CH34X_REQ_MODEM_CTRL, /* value */ (uint8_t) ~control, - /* index */ 0, complete_cb ? ch34x_control_complete : NULL, user_data), false); + } + TU_ASSERT (ch34x_control_out(p_cdc, CH34X_REQ_MODEM_CTRL, (uint8_t) ~control, 0, + complete_cb ? ch34x_control_complete : NULL, user_data)); return true; } @@ -1437,9 +1427,9 @@ static void ch34x_process_config(tuh_xfer_t* xfer) { #if CH34X_LOGS TU_LOG_DRV ( "[%u] CDCh CH34x Process Config started\r\n", p_cdc->daddr ); #endif - TU_ASSERT (ch34x_control_in(p_cdc, /* request */ CH34X_REQ_READ_VERSION, /* value */ 0, - /* index */ 0, buffer, 2, ch34x_process_config, CONFIG_CH34X_SERIAL_INIT),); + TU_ASSERT (ch34x_control_in(p_cdc, CH34X_REQ_READ_VERSION, 0, 0, buffer, 2, ch34x_process_config, CONFIG_CH34X_SERIAL_INIT),); break; + case CONFIG_CH34X_SERIAL_INIT: { // handle version read data, request to init CH34x with line_coding and baudrate uint8_t version = xfer->buffer[0]; #if CH34X_LOGS @@ -1468,46 +1458,51 @@ static void ch34x_process_config(tuh_xfer_t* xfer) { lcr |= CH34X_LCR_CS8; break; } + if (line_coding.parity != CDC_LINE_CODING_PARITY_NONE) { lcr |= CH34X_LCR_ENABLE_PAR; if (line_coding.parity == CDC_LINE_CODING_PARITY_EVEN || - line_coding.parity == CDC_LINE_CODING_PARITY_SPACE) + line_coding.parity == CDC_LINE_CODING_PARITY_SPACE) { lcr |= CH34X_LCR_PAR_EVEN; + } if (line_coding.parity == CDC_LINE_CODING_PARITY_MARK || - line_coding.parity == CDC_LINE_CODING_PARITY_SPACE) + line_coding.parity == CDC_LINE_CODING_PARITY_SPACE) { lcr |= CH34X_LCR_MARK_SPACE; + } } TU_ASSERT (line_coding.stop_bits == CDC_LINE_CODING_STOP_BITS_1 || line_coding.stop_bits == CDC_LINE_CODING_STOP_BITS_2,); // not supported 1.5 stop bits - if (line_coding.stop_bits == CDC_LINE_CODING_STOP_BITS_2) + if (line_coding.stop_bits == CDC_LINE_CODING_STOP_BITS_2) { lcr |= CH34X_LCR_STOP_BITS_2; - TU_ASSERT (ch34x_control_out(p_cdc, /* request */ CH34X_REQ_SERIAL_INIT, /* value */ - (uint16_t) (lcr << 8 | 0x9c), - /* index */ (uint16_t) (factor << 8 | 0x80 | divisor), ch34x_process_config, - CONFIG_CH34X_SPECIAL_REG_WRITE),); + } + TU_ASSERT (ch34x_control_out(p_cdc, CH34X_REQ_SERIAL_INIT, (uint16_t) (lcr << 8 | 0x9c), (uint16_t) (factor << 8 | 0x80 | divisor), + ch34x_process_config, CONFIG_CH34X_SPECIAL_REG_WRITE),); break; } - case CONFIG_CH34X_SPECIAL_REG_WRITE: // do special reg write, purpose unknown, overtaken from WCH driver - TU_ASSERT (ch34x_write_reg(p_cdc, /* reg */ 0x0f2c, /* value */ 0x0007, ch34x_process_config, - CONFIG_CH34X_FLOW_CONTROL),); + + case CONFIG_CH34X_SPECIAL_REG_WRITE: + // do special reg write, purpose unknown, overtaken from WCH driver + TU_ASSERT (ch34x_write_reg(p_cdc, 0x0f2c, 0x0007, ch34x_process_config, CONFIG_CH34X_FLOW_CONTROL),); break; - case CONFIG_CH34X_FLOW_CONTROL: // no hardware flow control - TU_ASSERT (ch34x_write_reg(p_cdc, /* reg */ 0x2727, /* value */ 0x0000, ch34x_process_config, - CONFIG_CH34X_MODEM_CONTROL),); + + case CONFIG_CH34X_FLOW_CONTROL: + // no hardware flow control + TU_ASSERT (ch34x_write_reg(p_cdc, 0x2727, 0x0000, ch34x_process_config, CONFIG_CH34X_MODEM_CONTROL),); break; - case CONFIG_CH34X_MODEM_CONTROL: // !always! set modem controls RTS/DTR (CH34x has no reset state after CH34X_REQ_SERIAL_INIT) - TU_ASSERT (ch34x_set_modem_ctrl(p_cdc, CFG_TUH_CDC_LINE_CONTROL_ON_ENUM, ch34x_process_config, - CONFIG_CH34X_COMPLETE),); + + case CONFIG_CH34X_MODEM_CONTROL: + // !always! set modem controls RTS/DTR (CH34x has no reset state after CH34X_REQ_SERIAL_INIT) + TU_ASSERT (ch34x_set_modem_ctrl(p_cdc, CFG_TUH_CDC_LINE_CONTROL_ON_ENUM, ch34x_process_config, CONFIG_CH34X_COMPLETE),); break; + case CONFIG_CH34X_COMPLETE: p_cdc->line_coding = line_coding; // CONFIG_CH34X_SERIAL_INIT not handled by ch34x_control_complete #if CH34X_LOGS TU_LOG_DRV("CDCh CH34x Process Config Complete\r\n"); - TU_LOG_LINE_CODING(" ", p_cdc->line_coding); - TU_LOG_CONTROL_LINE_STATE(" ", p_cdc->line_state); #endif set_config_complete(p_cdc, idx, itf_num); break; + default: TU_ASSERT (false,); break; -- cgit v1.3.1 From 482a8068a51025ee8c31ccdb4355801c185172cc Mon Sep 17 00:00:00 2001 From: IngHK Date: Tue, 16 Jan 2024 14:51:04 +0100 Subject: change code style and code cleanup --- src/class/cdc/cdc_host.c | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) (limited to 'src/class') diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index 5541b5dee..4cecc79a1 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -1260,13 +1260,13 @@ static bool ch34x_control_in(cdch_interface_t* p_cdc, uint8_t request, uint16_t } static bool ch34x_write_reg(cdch_interface_t* p_cdc, uint16_t reg, uint16_t value, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - return ch34x_control_out(p_cdc, CH34X_REQ_WRITE_REG, /* value */ reg, /* index */ value, complete_cb, user_data); + return ch34x_control_out(p_cdc, CH34X_REQ_WRITE_REG, reg, value, complete_cb, user_data); } //static bool ch34x_read_reg_request ( cdch_interface_t* p_cdc, uint16_t reg, // uint8_t *buffer, uint16_t buffersize, tuh_xfer_cb_t complete_cb, uintptr_t user_data ) //{ -// return ch34x_control_in ( p_cdc, CH34X_REQ_READ_REG, reg, /* index */ 0, buffer, buffersize, complete_cb, user_data ); +// return ch34x_control_in ( p_cdc, CH34X_REQ_READ_REG, reg, 0, buffer, buffersize, complete_cb, user_data ); //} uint8_t ch34x_xfer_get_itf_num(tuh_xfer_t* xfer) { @@ -1327,7 +1327,9 @@ static void ch34x_control_complete(tuh_xfer_t* xfer) { } xfer->complete_cb = p_cdc->user_control_cb; - if (xfer->complete_cb)xfer->complete_cb(xfer); + if (xfer->complete_cb) { + xfer->complete_cb(xfer); + } } } @@ -1363,8 +1365,12 @@ static bool ch34x_get_factor_divisor(uint32_t baval, uint8_t* factor, uint8_t* d c = 11719; } a = (unsigned char) (c / baval); - if (a == 0 || a == 0xFF) return false; - if ((c / a - baval) > (baval - c / (a + 1))) a++; + if (a == 0 || a == 0xFF) { + return false; + } + if ((c / a - baval) > (baval - c / (a + 1))) { + a++; + } a = (uint8_t) (256 - a); break; } @@ -1425,7 +1431,7 @@ static void ch34x_process_config(tuh_xfer_t* xfer) { switch (state) { case CONFIG_CH34X_READ_VERSION: // request version read #if CH34X_LOGS - TU_LOG_DRV ( "[%u] CDCh CH34x Process Config started\r\n", p_cdc->daddr ); + TU_LOG_DRV ( "[%u] CDCh CH34x Process Config started\r\n", p_cdc->daddr ); #endif TU_ASSERT (ch34x_control_in(p_cdc, CH34X_REQ_READ_VERSION, 0, 0, buffer, 2, ch34x_process_config, CONFIG_CH34X_SERIAL_INIT),); break; @@ -1433,7 +1439,7 @@ static void ch34x_process_config(tuh_xfer_t* xfer) { case CONFIG_CH34X_SERIAL_INIT: { // handle version read data, request to init CH34x with line_coding and baudrate uint8_t version = xfer->buffer[0]; #if CH34X_LOGS - TU_LOG_DRV ( "[%u] CDCh CH34x Chip version=%02x\r\n", p_cdc->daddr, version ); + TU_LOG_DRV("[%u] CDCh CH34x Chip version=%02x\r\n", p_cdc->daddr, version); #endif // only versions >= 0x30 are tested, below 0x30 seems having other programming, see WCH vendor, linux kernel and FreeBSD drivers TU_ASSERT (version >= 0x30,); @@ -1470,8 +1476,8 @@ static void ch34x_process_config(tuh_xfer_t* xfer) { lcr |= CH34X_LCR_MARK_SPACE; } } - TU_ASSERT (line_coding.stop_bits == CDC_LINE_CODING_STOP_BITS_1 || line_coding.stop_bits == - CDC_LINE_CODING_STOP_BITS_2,); // not supported 1.5 stop bits + TU_ASSERT (line_coding.stop_bits == CDC_LINE_CODING_STOP_BITS_1 || + line_coding.stop_bits == CDC_LINE_CODING_STOP_BITS_2,); // 1.5 stop bits not supported if (line_coding.stop_bits == CDC_LINE_CODING_STOP_BITS_2) { lcr |= CH34X_LCR_STOP_BITS_2; } @@ -1498,7 +1504,7 @@ static void ch34x_process_config(tuh_xfer_t* xfer) { case CONFIG_CH34X_COMPLETE: p_cdc->line_coding = line_coding; // CONFIG_CH34X_SERIAL_INIT not handled by ch34x_control_complete #if CH34X_LOGS - TU_LOG_DRV("CDCh CH34x Process Config Complete\r\n"); + TU_LOG_DRV("CDCh CH34x Process Config Complete\r\n"); #endif set_config_complete(p_cdc, idx, itf_num); break; -- cgit v1.3.1 From f221c0fb6683fc552febbb9a52300d66f031d275 Mon Sep 17 00:00:00 2001 From: hathach Date: Wed, 17 Jan 2024 14:45:09 +0700 Subject: more clean up --- src/class/cdc/cdc_host.c | 28 ++++++++++------------------ src/class/cdc/serial/ch34x.h | 13 +++++++++++++ 2 files changed, 23 insertions(+), 18 deletions(-) (limited to 'src/class') diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index 4cecc79a1..faee062cf 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -670,6 +670,7 @@ bool cdch_open(uint8_t rhport, uint8_t daddr, tusb_desc_interface_t const *itf_d } static void set_config_complete(cdch_interface_t * p_cdc, uint8_t idx, uint8_t itf_num) { + TU_LOG_DRV("CDCh Set Configure complete\r\n"); if (tuh_cdc_mount_cb) tuh_cdc_mount_cb(idx); // Prepare for incoming data @@ -1176,8 +1177,6 @@ static void cp210x_process_config(tuh_xfer_t* xfer) { #if CFG_TUH_CDC_CH34X -#define CH34X_LOGS false - enum { CONFIG_CH34X_READ_VERSION = 0, CONFIG_CH34X_SERIAL_INIT, @@ -1247,14 +1246,13 @@ static bool ch34x_set_request(cdch_interface_t* p_cdc, uint8_t direction, uint8_ return tuh_control_xfer(&xfer); } -static bool ch34x_control_out(cdch_interface_t* p_cdc, uint8_t request, uint16_t value, uint16_t index, - tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - return ch34x_set_request(p_cdc, TUSB_DIR_OUT, request, value, index, /* buffer */ NULL, /* length */ 0, complete_cb, user_data); +static inline bool ch34x_control_out(cdch_interface_t* p_cdc, uint8_t request, uint16_t value, uint16_t index, + tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + return ch34x_set_request(p_cdc, TUSB_DIR_OUT, request, value, index, NULL, 0, complete_cb, user_data); } -static bool ch34x_control_in(cdch_interface_t* p_cdc, uint8_t request, uint16_t value, uint16_t index, - uint8_t* buffer, uint16_t buffersize, tuh_xfer_cb_t complete_cb, - uintptr_t user_data) { +static inline bool ch34x_control_in(cdch_interface_t* p_cdc, uint8_t request, uint16_t value, uint16_t index, + uint8_t* buffer, uint16_t buffersize, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { return ch34x_set_request(p_cdc, TUSB_DIR_IN, request, value, index, buffer, buffersize, complete_cb, user_data); } @@ -1425,27 +1423,24 @@ static void ch34x_process_config(tuh_xfer_t* xfer) { uint8_t const idx = tuh_cdc_itf_get_index(xfer->daddr, itf_num); cdch_interface_t* p_cdc = get_itf(idx); cdc_line_coding_t const line_coding = CFG_TUH_CDC_LINE_CODING_ON_ENUM_CH34X; - uint8_t buffer[2]; + uint8_t buffer[2]; // TODO remove TU_ASSERT (p_cdc,); switch (state) { case CONFIG_CH34X_READ_VERSION: // request version read - #if CH34X_LOGS - TU_LOG_DRV ( "[%u] CDCh CH34x Process Config started\r\n", p_cdc->daddr ); - #endif + TU_LOG_DRV("[%u] CDCh CH34x attempt to read version\r\n", p_cdc->daddr); TU_ASSERT (ch34x_control_in(p_cdc, CH34X_REQ_READ_VERSION, 0, 0, buffer, 2, ch34x_process_config, CONFIG_CH34X_SERIAL_INIT),); break; case CONFIG_CH34X_SERIAL_INIT: { // handle version read data, request to init CH34x with line_coding and baudrate uint8_t version = xfer->buffer[0]; - #if CH34X_LOGS - TU_LOG_DRV("[%u] CDCh CH34x Chip version=%02x\r\n", p_cdc->daddr, version); - #endif + TU_LOG_DRV("[%u] CDCh CH34x Chip version = %02x\r\n", p_cdc->daddr, version); // only versions >= 0x30 are tested, below 0x30 seems having other programming, see WCH vendor, linux kernel and FreeBSD drivers TU_ASSERT (version >= 0x30,); uint8_t factor, divisor; TU_ASSERT (ch34x_get_factor_divisor(line_coding.bit_rate, &factor, &divisor),); uint8_t lcr = CH34X_LCR_ENABLE_RX | CH34X_LCR_ENABLE_TX; + switch (line_coding.data_bits) { case 5: lcr |= CH34X_LCR_CS5; @@ -1503,9 +1498,6 @@ static void ch34x_process_config(tuh_xfer_t* xfer) { case CONFIG_CH34X_COMPLETE: p_cdc->line_coding = line_coding; // CONFIG_CH34X_SERIAL_INIT not handled by ch34x_control_complete - #if CH34X_LOGS - TU_LOG_DRV("CDCh CH34x Process Config Complete\r\n"); - #endif set_config_complete(p_cdc, idx, itf_num); break; diff --git a/src/class/cdc/serial/ch34x.h b/src/class/cdc/serial/ch34x.h index 557e093a9..54b5b3560 100644 --- a/src/class/cdc/serial/ch34x.h +++ b/src/class/cdc/serial/ch34x.h @@ -27,6 +27,10 @@ #ifndef _CH34X_H_ #define _CH34X_H_ +// There is no official documentation for the CH34x chips. Reference can be found +// - https://github.com/WCHSoftGroup/ch341ser_linux +// - https://github.com/torvalds/linux/blob/master/drivers/usb/serial/ch341.c + // set line_coding @ enumeration #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM #define CFG_TUH_CDC_LINE_CODING_ON_ENUM_CH34X CFG_TUH_CDC_LINE_CODING_ON_ENUM @@ -41,6 +45,15 @@ #define CH34X_REQ_SERIAL_INIT 0xA1 // dec 161 #define CH34X_REQ_MODEM_CTRL 0xA4 // dev 164 +#define CH34X_REG_BREAK 0x05 +#define CH34X_REG_PRESCALER 0x12 +#define CH34X_REG_DIVISOR 0x13 +#define CH34X_REG_LCR 0x18 +#define CH34X_REG_LCR2 0x25 +#define CH34X_REG_MCR_MSR 0x06 +#define CH34X_REG_MCR_MSR2 0x07 +#define CH34X_NBREAK_BITS 0x01 + // modem control bits #define CH34X_BIT_RTS ( 1 << 6 ) #define CH34X_BIT_DTR ( 1 << 5 ) -- cgit v1.3.1 From 3968a0fff87c794266284af7901e334d122e894c Mon Sep 17 00:00:00 2001 From: IngHK Date: Wed, 17 Jan 2024 16:04:31 +0100 Subject: implemented ch34x_set_line_coding() and some code cleanup --- src/class/cdc/cdc_host.c | 177 ++++++++++++++++++++++++++----------------- src/class/cdc/serial/ch34x.h | 7 ++ 2 files changed, 116 insertions(+), 68 deletions(-) (limited to 'src/class') diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index faee062cf..45a03a31d 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -1179,7 +1179,7 @@ static void cp210x_process_config(tuh_xfer_t* xfer) { enum { CONFIG_CH34X_READ_VERSION = 0, - CONFIG_CH34X_SERIAL_INIT, + CONFIG_CH34X_SET_LINE_CODING, CONFIG_CH34X_SPECIAL_REG_WRITE, CONFIG_CH34X_FLOW_CONTROL, CONFIG_CH34X_MODEM_CONTROL, @@ -1292,11 +1292,10 @@ static void ch34x_control_complete(tuh_xfer_t* xfer) { case CH34X_REQ_WRITE_REG: // register write request switch (value) { - case (0x1312): + case 0x1312: // baudrate write p_cdc->line_coding.bit_rate = p_cdc->baudrate_requested; break; - default: TU_ASSERT(false,); // unexpected register write break; @@ -1310,13 +1309,60 @@ static void ch34x_control_complete(tuh_xfer_t* xfer) { } else { p_cdc->line_state &= (uint8_t ) ~CDC_CONTROL_LINE_STATE_RTS; } - if (~value & CH34X_BIT_DTR) { p_cdc->line_state |= CDC_CONTROL_LINE_STATE_DTR; } else { p_cdc->line_state &= (uint8_t ) ~CDC_CONTROL_LINE_STATE_DTR; } + break; + case CH34X_REQ_SERIAL_INIT: + // serial init request (set line coding incl. baudrate) + p_cdc->line_coding.bit_rate = p_cdc->baudrate_requested; + uint8_t lcr = (uint8_t) (value >> 8); + TU_ASSERT (lcr & CH34X_LCR_ENABLE_RX && lcr & CH34X_LCR_ENABLE_TX,); // both have to be enabled + switch (lcr & CH34X_LCR_CS_MASK) { + case CH34X_LCR_CS5: + p_cdc->line_coding.data_bits = 5; + break; + case CH34X_LCR_CS6: + p_cdc->line_coding.data_bits = 6; + break; + case CH34X_LCR_CS7: + p_cdc->line_coding.data_bits = 7; + break; + case CH34X_LCR_CS8: + p_cdc->line_coding.data_bits = 8; + break; + default: + TU_ASSERT (false,); // unexpected data_bits lcr + break; + } + if (lcr & CH34X_LCR_STOP_BITS_2) { + p_cdc->line_coding.stop_bits = CDC_LINE_CODING_STOP_BITS_2; + } else { + p_cdc->line_coding.stop_bits = CDC_LINE_CODING_STOP_BITS_1; + } + switch (lcr & CH34X_LCR_PAR_MASK) { + case 0: + p_cdc->line_coding.parity = CDC_LINE_CODING_PARITY_NONE; + break; + case CH34X_LCR_ENABLE_PAR: + p_cdc->line_coding.parity = CDC_LINE_CODING_PARITY_ODD; + break; + case CH34X_LCR_ENABLE_PAR | CH34X_LCR_PAR_EVEN: + p_cdc->line_coding.parity = CDC_LINE_CODING_PARITY_EVEN; + break; + case CH34X_LCR_ENABLE_PAR | CH34X_LCR_MARK_SPACE: + p_cdc->line_coding.parity = CDC_LINE_CODING_PARITY_MARK; + break; + case CH34X_LCR_ENABLE_PAR | CH34X_LCR_MARK_SPACE | CH34X_LCR_PAR_EVEN: + p_cdc->line_coding.parity = CDC_LINE_CODING_PARITY_SPACE; + break; + default: + TU_ASSERT (false,); // unexpected parity lcr + break; + } break; default: @@ -1378,15 +1424,57 @@ static bool ch34x_get_factor_divisor(uint32_t baval, uint8_t* factor, uint8_t* d return true; } +// calc lcr register value (data bits, parity, stop bits) +static bool ch34x_get_lcr(cdc_line_coding_t const* line_coding, uint8_t *lcr) { + *lcr = CH34X_LCR_ENABLE_RX | CH34X_LCR_ENABLE_TX; + switch (line_coding->data_bits) { + case 5: + *lcr |= CH34X_LCR_CS5; + break; + case 6: + *lcr |= CH34X_LCR_CS6; + break; + case 7: + *lcr |= CH34X_LCR_CS7; + break; + case 8: + *lcr |= CH34X_LCR_CS8; + break; + default: + TU_ASSERT (false); // data_bits not supported + break; + } + TU_ASSERT (line_coding->parity == CDC_LINE_CODING_PARITY_NONE || // supported parities + line_coding->parity == CDC_LINE_CODING_PARITY_ODD || line_coding->parity == CDC_LINE_CODING_PARITY_EVEN || + line_coding->parity == CDC_LINE_CODING_PARITY_MARK || line_coding->parity == CDC_LINE_CODING_PARITY_SPACE); + if (line_coding->parity != CDC_LINE_CODING_PARITY_NONE) { + *lcr |= CH34X_LCR_ENABLE_PAR; + if (line_coding->parity == CDC_LINE_CODING_PARITY_EVEN || line_coding->parity == CDC_LINE_CODING_PARITY_SPACE) { + *lcr |= CH34X_LCR_PAR_EVEN; + } + if (line_coding->parity == CDC_LINE_CODING_PARITY_MARK || line_coding->parity == CDC_LINE_CODING_PARITY_SPACE) { + *lcr |= CH34X_LCR_MARK_SPACE; + } + } + TU_ASSERT (line_coding->stop_bits == CDC_LINE_CODING_STOP_BITS_1 || + line_coding->stop_bits == CDC_LINE_CODING_STOP_BITS_2); // not supported 1.5 stop bits + if (line_coding->stop_bits == CDC_LINE_CODING_STOP_BITS_2) { + *lcr |= CH34X_LCR_STOP_BITS_2; + } + + return true; +} + static bool ch34x_set_line_coding(cdch_interface_t* p_cdc, cdc_line_coding_t const* line_coding, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - // TODO implement later - (void) p_cdc; - (void) line_coding; - (void) complete_cb; - (void) user_data; - - return false; + p_cdc->baudrate_requested = line_coding->bit_rate; + p_cdc->user_control_cb = complete_cb; + uint8_t factor, divisor, lcr; + TU_ASSERT (ch34x_get_factor_divisor(line_coding->bit_rate, &factor, &divisor)); + TU_ASSERT (ch34x_get_lcr(line_coding, &lcr)); + TU_ASSERT (ch34x_control_out(p_cdc, CH34X_REQ_SERIAL_INIT, (uint16_t) (lcr << 8 | 0x9c), (uint16_t) (factor << 8 | 0x80 | divisor), + complete_cb ? ch34x_control_complete : NULL, user_data)); + return true; } static bool ch34x_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, @@ -1398,7 +1486,6 @@ static bool ch34x_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, uint16_t const value = (uint16_t ) (factor << 8 | 0x80 | divisor); TU_ASSERT (ch34x_write_reg(p_cdc, 0x1312, value, complete_cb ? ch34x_control_complete : NULL, user_data)); - return true; } @@ -1427,82 +1514,36 @@ static void ch34x_process_config(tuh_xfer_t* xfer) { TU_ASSERT (p_cdc,); switch (state) { - case CONFIG_CH34X_READ_VERSION: // request version read - TU_LOG_DRV("[%u] CDCh CH34x attempt to read version\r\n", p_cdc->daddr); - TU_ASSERT (ch34x_control_in(p_cdc, CH34X_REQ_READ_VERSION, 0, 0, buffer, 2, ch34x_process_config, CONFIG_CH34X_SERIAL_INIT),); + case CONFIG_CH34X_READ_VERSION: + // version read request + TU_LOG_DRV("[%u] CDCh CH34x attempt to read Chip Version\r\n", p_cdc->daddr); + TU_ASSERT (ch34x_control_in(p_cdc, CH34X_REQ_READ_VERSION, 0, 0, buffer, 2, ch34x_process_config, CONFIG_CH34X_SET_LINE_CODING),); break; - - case CONFIG_CH34X_SERIAL_INIT: { // handle version read data, request to init CH34x with line_coding and baudrate + case CONFIG_CH34X_SET_LINE_CODING: + // handle version read data, set CH34x line coding (incl. baudrate) uint8_t version = xfer->buffer[0]; - TU_LOG_DRV("[%u] CDCh CH34x Chip version = %02x\r\n", p_cdc->daddr, version); - // only versions >= 0x30 are tested, below 0x30 seems having other programming, see WCH vendor, linux kernel and FreeBSD drivers + TU_LOG_DRV("[%u] CDCh CH34x Chip Version = %02x\r\n", p_cdc->daddr, version); + // only versions >= 0x30 are tested, below 0x30 seems having other programming, see drivers from WCH vendor, Linux kernel and FreeBSD TU_ASSERT (version >= 0x30,); - uint8_t factor, divisor; - TU_ASSERT (ch34x_get_factor_divisor(line_coding.bit_rate, &factor, &divisor),); - uint8_t lcr = CH34X_LCR_ENABLE_RX | CH34X_LCR_ENABLE_TX; - - switch (line_coding.data_bits) { - case 5: - lcr |= CH34X_LCR_CS5; - break; - case 6: - lcr |= CH34X_LCR_CS6; - break; - case 7: - lcr |= CH34X_LCR_CS7; - break; - case 8: - lcr |= CH34X_LCR_CS8; - break; - default: - TU_ASSERT (false,); // not supported data_bits - lcr |= CH34X_LCR_CS8; - break; - } - - if (line_coding.parity != CDC_LINE_CODING_PARITY_NONE) { - lcr |= CH34X_LCR_ENABLE_PAR; - if (line_coding.parity == CDC_LINE_CODING_PARITY_EVEN || - line_coding.parity == CDC_LINE_CODING_PARITY_SPACE) { - lcr |= CH34X_LCR_PAR_EVEN; - } - if (line_coding.parity == CDC_LINE_CODING_PARITY_MARK || - line_coding.parity == CDC_LINE_CODING_PARITY_SPACE) { - lcr |= CH34X_LCR_MARK_SPACE; - } - } - TU_ASSERT (line_coding.stop_bits == CDC_LINE_CODING_STOP_BITS_1 || - line_coding.stop_bits == CDC_LINE_CODING_STOP_BITS_2,); // 1.5 stop bits not supported - if (line_coding.stop_bits == CDC_LINE_CODING_STOP_BITS_2) { - lcr |= CH34X_LCR_STOP_BITS_2; - } - TU_ASSERT (ch34x_control_out(p_cdc, CH34X_REQ_SERIAL_INIT, (uint16_t) (lcr << 8 | 0x9c), (uint16_t) (factor << 8 | 0x80 | divisor), - ch34x_process_config, CONFIG_CH34X_SPECIAL_REG_WRITE),); + TU_ASSERT (ch34x_set_line_coding(p_cdc, &line_coding, ch34x_process_config, CONFIG_CH34X_SPECIAL_REG_WRITE),); break; - } - case CONFIG_CH34X_SPECIAL_REG_WRITE: // do special reg write, purpose unknown, overtaken from WCH driver TU_ASSERT (ch34x_write_reg(p_cdc, 0x0f2c, 0x0007, ch34x_process_config, CONFIG_CH34X_FLOW_CONTROL),); break; - case CONFIG_CH34X_FLOW_CONTROL: // no hardware flow control TU_ASSERT (ch34x_write_reg(p_cdc, 0x2727, 0x0000, ch34x_process_config, CONFIG_CH34X_MODEM_CONTROL),); break; - case CONFIG_CH34X_MODEM_CONTROL: // !always! set modem controls RTS/DTR (CH34x has no reset state after CH34X_REQ_SERIAL_INIT) TU_ASSERT (ch34x_set_modem_ctrl(p_cdc, CFG_TUH_CDC_LINE_CONTROL_ON_ENUM, ch34x_process_config, CONFIG_CH34X_COMPLETE),); break; - case CONFIG_CH34X_COMPLETE: - p_cdc->line_coding = line_coding; // CONFIG_CH34X_SERIAL_INIT not handled by ch34x_control_complete set_config_complete(p_cdc, idx, itf_num); break; - default: - TU_ASSERT (false,); + TU_ASSERT (false,); // something gone wrong, should never reached break; } } diff --git a/src/class/cdc/serial/ch34x.h b/src/class/cdc/serial/ch34x.h index 54b5b3560..b4ed7420c 100644 --- a/src/class/cdc/serial/ch34x.h +++ b/src/class/cdc/serial/ch34x.h @@ -27,9 +27,13 @@ #ifndef _CH34X_H_ #define _CH34X_H_ +// For simplicity, only the name CH34X is used here, +// but specifically only CH340 and CH341 are supported. + // There is no official documentation for the CH34x chips. Reference can be found // - https://github.com/WCHSoftGroup/ch341ser_linux // - https://github.com/torvalds/linux/blob/master/drivers/usb/serial/ch341.c +// - https://github.com/freebsd/freebsd-src/blob/main/sys/dev/usb/serial/uchcom.c // set line_coding @ enumeration #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM @@ -45,6 +49,7 @@ #define CH34X_REQ_SERIAL_INIT 0xA1 // dec 161 #define CH34X_REQ_MODEM_CTRL 0xA4 // dev 164 +// registers #define CH34X_REG_BREAK 0x05 #define CH34X_REG_PRESCALER 0x12 #define CH34X_REG_DIVISOR 0x13 @@ -64,10 +69,12 @@ #define CH34X_LCR_MARK_SPACE 0x20 #define CH34X_LCR_PAR_EVEN 0x10 #define CH34X_LCR_ENABLE_PAR 0x08 +#define CH34X_LCR_PAR_MASK 0x38 // all parity bits #define CH34X_LCR_STOP_BITS_2 0x04 #define CH34X_LCR_CS8 0x03 #define CH34X_LCR_CS7 0x02 #define CH34X_LCR_CS6 0x01 #define CH34X_LCR_CS5 0x00 +#define CH34X_LCR_CS_MASK 0x03 // all CSx bits #endif /* _CH34X_H_ */ -- cgit v1.3.1 From 30eb35f17f1baa4698da0cd45dbc3dff8906d7c0 Mon Sep 17 00:00:00 2001 From: hathach Date: Fri, 19 Jan 2024 01:06:24 +0700 Subject: - revert the use of serial init for set line coding - update ch34x_get_lcr and ch34x_get_factor_divisor --- src/class/cdc/cdc_host.c | 146 ++++++++++++++++++++++++------------------- src/class/cdc/serial/ch34x.h | 6 ++ 2 files changed, 87 insertions(+), 65 deletions(-) (limited to 'src/class') diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index 45a03a31d..150ac21f2 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -1179,7 +1179,7 @@ static void cp210x_process_config(tuh_xfer_t* xfer) { enum { CONFIG_CH34X_READ_VERSION = 0, - CONFIG_CH34X_SET_LINE_CODING, + CONFIG_CH34X_SERIAL_INIT, CONFIG_CH34X_SPECIAL_REG_WRITE, CONFIG_CH34X_FLOW_CONTROL, CONFIG_CH34X_MODEM_CONTROL, @@ -1231,7 +1231,9 @@ static bool ch34x_set_request(cdch_interface_t* p_cdc, uint8_t direction, uint8_ if (buffer && length > 0) { enum_buf = usbh_get_enum_buf(); - tu_memcpy_s(enum_buf, CFG_TUH_ENUMERATION_BUFSIZE, buffer, length); + if (direction == TUSB_DIR_OUT) { + tu_memcpy_s(enum_buf, CFG_TUH_ENUMERATION_BUFSIZE, buffer, length); + } } tuh_xfer_t xfer = { @@ -1257,8 +1259,8 @@ static inline bool ch34x_control_in(cdch_interface_t* p_cdc, uint8_t request, ui complete_cb, user_data); } -static bool ch34x_write_reg(cdch_interface_t* p_cdc, uint16_t reg, uint16_t value, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - return ch34x_control_out(p_cdc, CH34X_REQ_WRITE_REG, reg, value, complete_cb, user_data); +static bool ch34x_write_reg(cdch_interface_t* p_cdc, uint16_t reg, uint16_t reg_value, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + return ch34x_control_out(p_cdc, CH34X_REQ_WRITE_REG, reg, reg_value, complete_cb, user_data); } //static bool ch34x_read_reg_request ( cdch_interface_t* p_cdc, uint16_t reg, @@ -1292,10 +1294,11 @@ static void ch34x_control_complete(tuh_xfer_t* xfer) { case CH34X_REQ_WRITE_REG: // register write request switch (value) { - case 0x1312: + case CH34X_REG16_DIVISOR_PRESCALER: // baudrate write p_cdc->line_coding.bit_rate = p_cdc->baudrate_requested; break; + default: TU_ASSERT(false,); // unexpected register write break; @@ -1309,6 +1312,7 @@ static void ch34x_control_complete(tuh_xfer_t* xfer) { } else { p_cdc->line_state &= (uint8_t ) ~CDC_CONTROL_LINE_STATE_RTS; } + if (~value & CH34X_BIT_DTR) { p_cdc->line_state |= CDC_CONTROL_LINE_STATE_DTR; } else { @@ -1377,8 +1381,8 @@ static void ch34x_control_complete(tuh_xfer_t* xfer) { } } -// calc baudrate factor and divisor -static bool ch34x_get_factor_divisor(uint32_t baval, uint8_t* factor, uint8_t* divisor) { +// calculate divisor and prescaler for baudrate, return it as 16-bit combined value +static uint16_t ch34x_get_divisor_prescaler(uint32_t baval) { uint8_t a; uint8_t b; uint32_t c; @@ -1410,7 +1414,7 @@ static bool ch34x_get_factor_divisor(uint32_t baval, uint8_t* factor, uint8_t* d } a = (unsigned char) (c / baval); if (a == 0 || a == 0xFF) { - return false; + return 0; } if ((c / a - baval) > (baval - c / (a + 1))) { a++; @@ -1418,74 +1422,75 @@ static bool ch34x_get_factor_divisor(uint32_t baval, uint8_t* factor, uint8_t* d a = (uint8_t) (256 - a); break; } - *factor = a; - *divisor = b; - return true; + // reg divisor = a, reg prescaler = b + // According to linux code we need to set bit 7 of UCHCOM_REG_BPS_PRE, + // otherwise the chip will buffer data. + return (uint16_t) (a << 8 | 0x80 | b); } -// calc lcr register value (data bits, parity, stop bits) -static bool ch34x_get_lcr(cdc_line_coding_t const* line_coding, uint8_t *lcr) { - *lcr = CH34X_LCR_ENABLE_RX | CH34X_LCR_ENABLE_TX; - switch (line_coding->data_bits) { - case 5: - *lcr |= CH34X_LCR_CS5; - break; - case 6: - *lcr |= CH34X_LCR_CS6; - break; - case 7: - *lcr |= CH34X_LCR_CS7; +static inline uint8_t ch34x_get_lcr(uint8_t stop_bits, uint8_t parity, uint8_t data_bits) { + uint8_t lcr = CH34X_LCR_ENABLE_RX | CH34X_LCR_ENABLE_TX; + TU_VERIFY(data_bits >= 5, 0); + lcr |= (uint8_t) (data_bits - 5); + + if (parity) { + lcr |= CH34X_LCR_ENABLE_PAR; + } + switch(parity) { + case CDC_LINE_CODING_PARITY_EVEN: + lcr |= CH34X_LCR_PAR_EVEN; break; - case 8: - *lcr |= CH34X_LCR_CS8; + + case CDC_LINE_CODING_PARITY_MARK: + lcr |= CH34X_LCR_MARK_SPACE; break; - default: - TU_ASSERT (false); // data_bits not supported + + case CDC_LINE_CODING_PARITY_SPACE: + lcr |= CH34X_LCR_MARK_SPACE | CH34X_LCR_PAR_EVEN; break; + + default: break; } - TU_ASSERT (line_coding->parity == CDC_LINE_CODING_PARITY_NONE || // supported parities - line_coding->parity == CDC_LINE_CODING_PARITY_ODD || line_coding->parity == CDC_LINE_CODING_PARITY_EVEN || - line_coding->parity == CDC_LINE_CODING_PARITY_MARK || line_coding->parity == CDC_LINE_CODING_PARITY_SPACE); - if (line_coding->parity != CDC_LINE_CODING_PARITY_NONE) { - *lcr |= CH34X_LCR_ENABLE_PAR; - if (line_coding->parity == CDC_LINE_CODING_PARITY_EVEN || line_coding->parity == CDC_LINE_CODING_PARITY_SPACE) { - *lcr |= CH34X_LCR_PAR_EVEN; - } - if (line_coding->parity == CDC_LINE_CODING_PARITY_MARK || line_coding->parity == CDC_LINE_CODING_PARITY_SPACE) { - *lcr |= CH34X_LCR_MARK_SPACE; - } - } - TU_ASSERT (line_coding->stop_bits == CDC_LINE_CODING_STOP_BITS_1 || - line_coding->stop_bits == CDC_LINE_CODING_STOP_BITS_2); // not supported 1.5 stop bits - if (line_coding->stop_bits == CDC_LINE_CODING_STOP_BITS_2) { - *lcr |= CH34X_LCR_STOP_BITS_2; + + // 1.5 stop bits not supported + TU_VERIFY(stop_bits != CDC_LINE_CODING_STOP_BITS_1_5, 0); + if (stop_bits == CDC_LINE_CODING_STOP_BITS_2) { + lcr |= CH34X_LCR_STOP_BITS_2; } - return true; + return lcr; } -static bool ch34x_set_line_coding(cdch_interface_t* p_cdc, cdc_line_coding_t const* line_coding, - tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - p_cdc->baudrate_requested = line_coding->bit_rate; - p_cdc->user_control_cb = complete_cb; - uint8_t factor, divisor, lcr; - TU_ASSERT (ch34x_get_factor_divisor(line_coding->bit_rate, &factor, &divisor)); - TU_ASSERT (ch34x_get_lcr(line_coding, &lcr)); - TU_ASSERT (ch34x_control_out(p_cdc, CH34X_REQ_SERIAL_INIT, (uint16_t) (lcr << 8 | 0x9c), (uint16_t) (factor << 8 | 0x80 | divisor), - complete_cb ? ch34x_control_complete : NULL, user_data)); - return true; -} +//static bool ch34x_set_line_data(cdch_interface_t* p_cdc, uint8_t stop_bits, uint8_t parity, uint8_t data_bits, +// tuh_xfer_cb_t complete_cb, uintptr_t user_data) { static bool ch34x_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { p_cdc->baudrate_requested = baudrate; p_cdc->user_control_cb = complete_cb; - uint8_t factor, divisor; - TU_ASSERT (ch34x_get_factor_divisor(baudrate, &factor, &divisor)); - uint16_t const value = (uint16_t ) (factor << 8 | 0x80 | divisor); - TU_ASSERT (ch34x_write_reg(p_cdc, 0x1312, value, - complete_cb ? ch34x_control_complete : NULL, user_data)); + uint16_t const div_ps = ch34x_get_divisor_prescaler(baudrate); + TU_VERIFY(div_ps != 0); + TU_ASSERT(ch34x_write_reg(p_cdc, CH34X_REG16_DIVISOR_PRESCALER, div_ps, + complete_cb ? ch34x_control_complete : NULL, user_data)); + + return true; +} + +static bool ch34x_set_line_coding(cdch_interface_t* p_cdc, cdc_line_coding_t const* line_coding, + tuh_xfer_cb_t complete_cb, uintptr_t user_data) { +// p_cdc->baudrate_requested = line_coding->bit_rate; +// p_cdc->user_control_cb = complete_cb; +// uint8_t factor, divisor, lcr; +// TU_ASSERT (ch34x_get_factor_divisor(line_coding->bit_rate, &factor, &divisor)); +// TU_ASSERT (ch34x_get_lcr(line_coding, &lcr)); +// TU_ASSERT (ch34x_control_out(p_cdc, CH34X_REQ_SERIAL_INIT, (uint16_t) (lcr << 8 | 0x9c), (uint16_t) (factor << 8 | 0x80 | divisor), +// complete_cb ? ch34x_control_complete : NULL, user_data)); + (void) p_cdc; + (void) line_coding; + (void) complete_cb; + (void) user_data; + return true; } @@ -1515,35 +1520,46 @@ static void ch34x_process_config(tuh_xfer_t* xfer) { switch (state) { case CONFIG_CH34X_READ_VERSION: - // version read request TU_LOG_DRV("[%u] CDCh CH34x attempt to read Chip Version\r\n", p_cdc->daddr); - TU_ASSERT (ch34x_control_in(p_cdc, CH34X_REQ_READ_VERSION, 0, 0, buffer, 2, ch34x_process_config, CONFIG_CH34X_SET_LINE_CODING),); + TU_ASSERT (ch34x_control_in(p_cdc, CH34X_REQ_READ_VERSION, 0, 0, buffer, 2, ch34x_process_config, CONFIG_CH34X_SERIAL_INIT),); break; - case CONFIG_CH34X_SET_LINE_CODING: + + case CONFIG_CH34X_SERIAL_INIT: { // handle version read data, set CH34x line coding (incl. baudrate) uint8_t version = xfer->buffer[0]; TU_LOG_DRV("[%u] CDCh CH34x Chip Version = %02x\r\n", p_cdc->daddr, version); // only versions >= 0x30 are tested, below 0x30 seems having other programming, see drivers from WCH vendor, Linux kernel and FreeBSD TU_ASSERT (version >= 0x30,); - TU_ASSERT (ch34x_set_line_coding(p_cdc, &line_coding, ch34x_process_config, CONFIG_CH34X_SPECIAL_REG_WRITE),); + uint16_t const div_ps = ch34x_get_divisor_prescaler(line_coding.bit_rate); + TU_ASSERT(div_ps != 0, ); + + uint8_t const lcr = ch34x_get_lcr(line_coding.stop_bits, line_coding.parity, line_coding.data_bits); + TU_ASSERT (ch34x_control_out(p_cdc, CH34X_REQ_SERIAL_INIT, tu_u16(lcr, 0x9c), div_ps, + ch34x_process_config, CONFIG_CH34X_SPECIAL_REG_WRITE),); break; + } + case CONFIG_CH34X_SPECIAL_REG_WRITE: // do special reg write, purpose unknown, overtaken from WCH driver TU_ASSERT (ch34x_write_reg(p_cdc, 0x0f2c, 0x0007, ch34x_process_config, CONFIG_CH34X_FLOW_CONTROL),); break; + case CONFIG_CH34X_FLOW_CONTROL: // no hardware flow control TU_ASSERT (ch34x_write_reg(p_cdc, 0x2727, 0x0000, ch34x_process_config, CONFIG_CH34X_MODEM_CONTROL),); break; + case CONFIG_CH34X_MODEM_CONTROL: // !always! set modem controls RTS/DTR (CH34x has no reset state after CH34X_REQ_SERIAL_INIT) TU_ASSERT (ch34x_set_modem_ctrl(p_cdc, CFG_TUH_CDC_LINE_CONTROL_ON_ENUM, ch34x_process_config, CONFIG_CH34X_COMPLETE),); break; + case CONFIG_CH34X_COMPLETE: set_config_complete(p_cdc, idx, itf_num); break; + default: - TU_ASSERT (false,); // something gone wrong, should never reached + TU_ASSERT (false,); break; } } diff --git a/src/class/cdc/serial/ch34x.h b/src/class/cdc/serial/ch34x.h index b4ed7420c..3f78a3007 100644 --- a/src/class/cdc/serial/ch34x.h +++ b/src/class/cdc/serial/ch34x.h @@ -59,6 +59,12 @@ #define CH34X_REG_MCR_MSR2 0x07 #define CH34X_NBREAK_BITS 0x01 +#define CH341_REG_0x0F 0x0F // undocumented register +#define CH341_REG_0x2C 0x2C // undocumented register +#define CH341_REG_0x27 0x27 // hardware flow control (cts/rts) + +#define CH34X_REG16_DIVISOR_PRESCALER TU_U16(CH34X_REG_DIVISOR, CH34X_REG_PRESCALER) + // modem control bits #define CH34X_BIT_RTS ( 1 << 6 ) #define CH34X_BIT_DTR ( 1 << 5 ) -- cgit v1.3.1 From c568a6793e99dde311802d4b4cb0633d2d6f5830 Mon Sep 17 00:00:00 2001 From: hathach Date: Fri, 19 Jan 2024 12:14:45 +0700 Subject: - add requested line coding to make update data format easier - change ch34x_xfer_get_itf_num() to simply 0 --- src/class/cdc/cdc_host.c | 295 ++++++++++++++++++++++------------------------- 1 file changed, 136 insertions(+), 159 deletions(-) (limited to 'src/class') diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index 150ac21f2..3843a8edc 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -60,6 +60,11 @@ typedef struct { uint8_t line_state; // DTR (bit0), RTS (bit1) TU_ATTR_ALIGNED(4) cdc_line_coding_t line_coding; // Baudrate, stop bits, parity, data width + #if CFG_TUH_CDC_FTDI || CFG_TUH_CDC_CP210X || CFG_TUH_CDC_CH34X + cdc_line_coding_t requested_line_coding; + // 1 byte padding + #endif + tuh_xfer_cb_t user_control_cb; struct { @@ -72,10 +77,6 @@ typedef struct { uint8_t rx_ff_buf[CFG_TUH_CDC_TX_BUFSIZE]; CFG_TUH_MEM_ALIGN uint8_t rx_ep_buf[CFG_TUH_CDC_TX_EPSIZE]; } stream; - -#if CFG_TUH_CDC_FTDI || CFG_TUH_CDC_CH34X - uint32_t baudrate_requested; -#endif } cdch_interface_t; CFG_TUH_MEM_SECTION @@ -429,7 +430,7 @@ static void cdch_internal_control_complete(tuh_xfer_t* xfer) { case FTDI_SIO_SET_BAUD_RATE: // convert from divisor to baudrate is not supported - p_cdc->line_coding.bit_rate = p_cdc->baudrate_requested; + p_cdc->line_coding.bit_rate = p_cdc->requested_line_coding.bit_rate; break; default: break; @@ -968,7 +969,7 @@ static bool ftdi_sio_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, tu TU_LOG_DRV("CDC FTDI Set BaudRate = %lu, divisor = 0x%04x\r\n", baudrate, divisor); p_cdc->user_control_cb = complete_cb; - p_cdc->baudrate_requested = baudrate; + p_cdc->requested_line_coding.bit_rate = baudrate; TU_ASSERT(ftdi_sio_set_request(p_cdc, FTDI_SIO_SET_BAUD_RATE, divisor, complete_cb ? cdch_internal_control_complete : NULL, user_data)); @@ -1186,6 +1187,9 @@ enum { CONFIG_CH34X_COMPLETE }; +static uint8_t ch34x_get_lcr(uint8_t stop_bits, uint8_t parity, uint8_t data_bits); +static uint16_t ch34x_get_divisor_prescaler(uint32_t baval); + static bool ch34x_open(uint8_t daddr, tusb_desc_interface_t const* itf_desc, uint16_t max_len) { // CH34x Interface includes 1 vendor interface + 2 bulk + 1 interrupt endpoints TU_VERIFY (itf_desc->bNumEndpoints == 3); @@ -1269,20 +1273,10 @@ static bool ch34x_write_reg(cdch_interface_t* p_cdc, uint16_t reg, uint16_t reg_ // return ch34x_control_in ( p_cdc, CH34X_REQ_READ_REG, reg, 0, buffer, buffersize, complete_cb, user_data ); //} -uint8_t ch34x_xfer_get_itf_num(tuh_xfer_t* xfer) { -// CH34x needs a special handling to get bInterfaceNumber, because wIndex is used for other purposes and not for bInterfaceNumber -// CH340 and CH341 derivates have always only one interface, so it's OK to check only daddr - for (uint8_t i = 0; i < CFG_TUH_CDC; i++) { - const cdch_interface_t* p_cdc = &cdch_data[i]; - if (p_cdc->daddr == xfer->daddr) return p_cdc->bInterfaceNumber; - } - - return INTERFACE_INVALID_NUMBER; -} - // internal control complete to update state such as line state, encoding static void ch34x_control_complete(tuh_xfer_t* xfer) { - uint8_t const itf_num = ch34x_xfer_get_itf_num(xfer); + // CH34x only has 1 interface and use wIndex as payload and not for bInterfaceNumber + uint8_t const itf_num = 0; uint8_t const idx = tuh_cdc_itf_get_index(xfer->daddr, itf_num); cdch_interface_t* p_cdc = get_itf(idx); uint16_t value = tu_le16toh (xfer->setup->wValue); @@ -1296,7 +1290,14 @@ static void ch34x_control_complete(tuh_xfer_t* xfer) { switch (value) { case CH34X_REG16_DIVISOR_PRESCALER: // baudrate write - p_cdc->line_coding.bit_rate = p_cdc->baudrate_requested; + p_cdc->line_coding.bit_rate = p_cdc->requested_line_coding.bit_rate; + break; + + case CH32X_REG16_LCR2_LCR: + // data format write + p_cdc->line_coding.stop_bits = p_cdc->requested_line_coding.stop_bits; + p_cdc->line_coding.parity = p_cdc->requested_line_coding.parity; + p_cdc->line_coding.data_bits = p_cdc->requested_line_coding.data_bits; break; default: @@ -1305,68 +1306,26 @@ static void ch34x_control_complete(tuh_xfer_t* xfer) { } break; - case CH34X_REQ_MODEM_CTRL: - // set modem controls RTS/DTR request - if (~value & CH34X_BIT_RTS) { + case CH34X_REQ_MODEM_CTRL: { + // set modem controls RTS/DTR request. Note: signals are inverted + uint16_t const modem_signal = ~value; + if (modem_signal & CH34X_BIT_RTS) { p_cdc->line_state |= CDC_CONTROL_LINE_STATE_RTS; } else { - p_cdc->line_state &= (uint8_t ) ~CDC_CONTROL_LINE_STATE_RTS; + p_cdc->line_state &= (uint8_t) ~CDC_CONTROL_LINE_STATE_RTS; } - if (~value & CH34X_BIT_DTR) { + if (modem_signal & CH34X_BIT_DTR) { p_cdc->line_state |= CDC_CONTROL_LINE_STATE_DTR; } else { - p_cdc->line_state &= (uint8_t ) ~CDC_CONTROL_LINE_STATE_DTR; + p_cdc->line_state &= (uint8_t) ~CDC_CONTROL_LINE_STATE_DTR; } break; + } case CH34X_REQ_SERIAL_INIT: // serial init request (set line coding incl. baudrate) - p_cdc->line_coding.bit_rate = p_cdc->baudrate_requested; - uint8_t lcr = (uint8_t) (value >> 8); - TU_ASSERT (lcr & CH34X_LCR_ENABLE_RX && lcr & CH34X_LCR_ENABLE_TX,); // both have to be enabled - switch (lcr & CH34X_LCR_CS_MASK) { - case CH34X_LCR_CS5: - p_cdc->line_coding.data_bits = 5; - break; - case CH34X_LCR_CS6: - p_cdc->line_coding.data_bits = 6; - break; - case CH34X_LCR_CS7: - p_cdc->line_coding.data_bits = 7; - break; - case CH34X_LCR_CS8: - p_cdc->line_coding.data_bits = 8; - break; - default: - TU_ASSERT (false,); // unexpected data_bits lcr - break; - } - if (lcr & CH34X_LCR_STOP_BITS_2) { - p_cdc->line_coding.stop_bits = CDC_LINE_CODING_STOP_BITS_2; - } else { - p_cdc->line_coding.stop_bits = CDC_LINE_CODING_STOP_BITS_1; - } - switch (lcr & CH34X_LCR_PAR_MASK) { - case 0: - p_cdc->line_coding.parity = CDC_LINE_CODING_PARITY_NONE; - break; - case CH34X_LCR_ENABLE_PAR: - p_cdc->line_coding.parity = CDC_LINE_CODING_PARITY_ODD; - break; - case CH34X_LCR_ENABLE_PAR | CH34X_LCR_PAR_EVEN: - p_cdc->line_coding.parity = CDC_LINE_CODING_PARITY_EVEN; - break; - case CH34X_LCR_ENABLE_PAR | CH34X_LCR_MARK_SPACE: - p_cdc->line_coding.parity = CDC_LINE_CODING_PARITY_MARK; - break; - case CH34X_LCR_ENABLE_PAR | CH34X_LCR_MARK_SPACE | CH34X_LCR_PAR_EVEN: - p_cdc->line_coding.parity = CDC_LINE_CODING_PARITY_SPACE; - break; - default: - TU_ASSERT (false,); // unexpected parity lcr - break; - } + p_cdc->line_coding = p_cdc->requested_line_coding; break; default: @@ -1381,93 +1340,17 @@ static void ch34x_control_complete(tuh_xfer_t* xfer) { } } -// calculate divisor and prescaler for baudrate, return it as 16-bit combined value -static uint16_t ch34x_get_divisor_prescaler(uint32_t baval) { - uint8_t a; - uint8_t b; - uint32_t c; - - switch (baval) { - case 921600: - a = 0xf3; - b = 7; - break; - - case 307200: - a = 0xd9; - b = 7; - break; - - default: - if (baval > 6000000 / 255) { - b = 3; - c = 6000000; - } else if (baval > 750000 / 255) { - b = 2; - c = 750000; - } else if (baval > 93750 / 255) { - b = 1; - c = 93750; - } else { - b = 0; - c = 11719; - } - a = (unsigned char) (c / baval); - if (a == 0 || a == 0xFF) { - return 0; - } - if ((c / a - baval) > (baval - c / (a + 1))) { - a++; - } - a = (uint8_t) (256 - a); - break; - } - - // reg divisor = a, reg prescaler = b - // According to linux code we need to set bit 7 of UCHCOM_REG_BPS_PRE, - // otherwise the chip will buffer data. - return (uint16_t) (a << 8 | 0x80 | b); -} - -static inline uint8_t ch34x_get_lcr(uint8_t stop_bits, uint8_t parity, uint8_t data_bits) { - uint8_t lcr = CH34X_LCR_ENABLE_RX | CH34X_LCR_ENABLE_TX; - TU_VERIFY(data_bits >= 5, 0); - lcr |= (uint8_t) (data_bits - 5); - - if (parity) { - lcr |= CH34X_LCR_ENABLE_PAR; - } - switch(parity) { - case CDC_LINE_CODING_PARITY_EVEN: - lcr |= CH34X_LCR_PAR_EVEN; - break; - - case CDC_LINE_CODING_PARITY_MARK: - lcr |= CH34X_LCR_MARK_SPACE; - break; - - case CDC_LINE_CODING_PARITY_SPACE: - lcr |= CH34X_LCR_MARK_SPACE | CH34X_LCR_PAR_EVEN; - break; - - default: break; - } - - // 1.5 stop bits not supported - TU_VERIFY(stop_bits != CDC_LINE_CODING_STOP_BITS_1_5, 0); - if (stop_bits == CDC_LINE_CODING_STOP_BITS_2) { - lcr |= CH34X_LCR_STOP_BITS_2; - } - - return lcr; -} - -//static bool ch34x_set_line_data(cdch_interface_t* p_cdc, uint8_t stop_bits, uint8_t parity, uint8_t data_bits, +//static bool ch34x_set_data_format(cdch_interface_t* p_cdc, uint8_t stop_bits, uint8_t parity, uint8_t data_bits, // tuh_xfer_cb_t complete_cb, uintptr_t user_data) { +// uint8_t const lcr = ch34x_get_lcr(stop_bits, parity, data_bits); +// TU_ASSERT (ch34x_control_out(p_cdc, CH34X_REQ_WRITE_REG, CH32X_REG16_LCR2_LCR, lcr, +// complete_cb ? ch34x_control_complete : NULL, user_data)); +// return false; +//} static bool ch34x_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - p_cdc->baudrate_requested = baudrate; + p_cdc->requested_line_coding.bit_rate = baudrate; p_cdc->user_control_cb = complete_cb; uint16_t const div_ps = ch34x_get_divisor_prescaler(baudrate); TU_VERIFY(div_ps != 0); @@ -1496,24 +1379,29 @@ static bool ch34x_set_line_coding(cdch_interface_t* p_cdc, cdc_line_coding_t con static bool ch34x_set_modem_ctrl(cdch_interface_t* p_cdc, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - p_cdc->user_control_cb = complete_cb; - uint16_t control = 0; + uint8_t control = 0; if (line_state & CDC_CONTROL_LINE_STATE_RTS) { control |= CH34X_BIT_RTS; } if (line_state & CDC_CONTROL_LINE_STATE_DTR) { control |= CH34X_BIT_DTR; } - TU_ASSERT (ch34x_control_out(p_cdc, CH34X_REQ_MODEM_CTRL, (uint8_t) ~control, 0, + + // CH34x signals are inverted + control = ~control; + + p_cdc->user_control_cb = complete_cb; + TU_ASSERT (ch34x_control_out(p_cdc, CH34X_REQ_MODEM_CTRL, control, 0, complete_cb ? ch34x_control_complete : NULL, user_data)); return true; } static void ch34x_process_config(tuh_xfer_t* xfer) { - uint8_t const itf_num = ch34x_xfer_get_itf_num(xfer); - uintptr_t const state = xfer->user_data; + // CH34x only has 1 interface and use wIndex as payload and not for bInterfaceNumber + uint8_t const itf_num = 0; uint8_t const idx = tuh_cdc_itf_get_index(xfer->daddr, itf_num); cdch_interface_t* p_cdc = get_itf(idx); + uintptr_t const state = xfer->user_data; cdc_line_coding_t const line_coding = CFG_TUH_CDC_LINE_CODING_ON_ENUM_CH34X; uint8_t buffer[2]; // TODO remove TU_ASSERT (p_cdc,); @@ -1526,14 +1414,17 @@ static void ch34x_process_config(tuh_xfer_t* xfer) { case CONFIG_CH34X_SERIAL_INIT: { // handle version read data, set CH34x line coding (incl. baudrate) - uint8_t version = xfer->buffer[0]; + uint8_t const version = xfer->buffer[0]; TU_LOG_DRV("[%u] CDCh CH34x Chip Version = %02x\r\n", p_cdc->daddr, version); // only versions >= 0x30 are tested, below 0x30 seems having other programming, see drivers from WCH vendor, Linux kernel and FreeBSD TU_ASSERT (version >= 0x30,); + uint16_t const div_ps = ch34x_get_divisor_prescaler(line_coding.bit_rate); TU_ASSERT(div_ps != 0, ); uint8_t const lcr = ch34x_get_lcr(line_coding.stop_bits, line_coding.parity, line_coding.data_bits); + + // Init CH34x with line coding TU_ASSERT (ch34x_control_out(p_cdc, CH34X_REQ_SERIAL_INIT, tu_u16(lcr, 0x9c), div_ps, ch34x_process_config, CONFIG_CH34X_SPECIAL_REG_WRITE),); break; @@ -1541,6 +1432,7 @@ static void ch34x_process_config(tuh_xfer_t* xfer) { case CONFIG_CH34X_SPECIAL_REG_WRITE: // do special reg write, purpose unknown, overtaken from WCH driver + p_cdc->line_coding = line_coding; TU_ASSERT (ch34x_write_reg(p_cdc, 0x0f2c, 0x0007, ch34x_process_config, CONFIG_CH34X_FLOW_CONTROL),); break; @@ -1564,6 +1456,91 @@ static void ch34x_process_config(tuh_xfer_t* xfer) { } } +//------------- CH34x helper -------------// + +// calculate divisor and prescaler for baudrate, return it as 16-bit combined value +static uint16_t ch34x_get_divisor_prescaler(uint32_t baval) { + uint8_t a; + uint8_t b; + uint32_t c; + + switch (baval) { + case 921600: + a = 0xf3; + b = 7; + break; + + case 307200: + a = 0xd9; + b = 7; + break; + + default: + if (baval > 6000000 / 255) { + b = 3; + c = 6000000; + } else if (baval > 750000 / 255) { + b = 2; + c = 750000; + } else if (baval > 93750 / 255) { + b = 1; + c = 93750; + } else { + b = 0; + c = 11719; + } + a = (unsigned char) (c / baval); + if (a == 0 || a == 0xFF) { + return 0; + } + if ((c / a - baval) > (baval - c / (a + 1))) { + a++; + } + a = (uint8_t) (256 - a); + break; + } + + // reg divisor = a, reg prescaler = b + // According to linux code we need to set bit 7 of UCHCOM_REG_BPS_PRE, + // otherwise the chip will buffer data. + return (uint16_t) (a << 8 | 0x80 | b); +} + +// calculate lcr value from data coding +static uint8_t ch34x_get_lcr(uint8_t stop_bits, uint8_t parity, uint8_t data_bits) { + uint8_t lcr = CH34X_LCR_ENABLE_RX | CH34X_LCR_ENABLE_TX; + TU_VERIFY(data_bits >= 5, 0); + lcr |= (uint8_t) (data_bits - 5); + + if (parity) { + lcr |= CH34X_LCR_ENABLE_PAR; + } + switch(parity) { + case CDC_LINE_CODING_PARITY_EVEN: + lcr |= CH34X_LCR_PAR_EVEN; + break; + + case CDC_LINE_CODING_PARITY_MARK: + lcr |= CH34X_LCR_MARK_SPACE; + break; + + case CDC_LINE_CODING_PARITY_SPACE: + lcr |= CH34X_LCR_MARK_SPACE | CH34X_LCR_PAR_EVEN; + break; + + default: break; + } + + // 1.5 stop bits not supported + TU_VERIFY(stop_bits != CDC_LINE_CODING_STOP_BITS_1_5, 0); + if (stop_bits == CDC_LINE_CODING_STOP_BITS_2) { + lcr |= CH34X_LCR_STOP_BITS_2; + } + + return lcr; +} + + #endif // CFG_TUH_CDC_CH34X #endif -- cgit v1.3.1 From 23c2d929a1bae39578b195c7c7b068fb718212bd Mon Sep 17 00:00:00 2001 From: hathach Date: Fri, 19 Jan 2024 12:40:37 +0700 Subject: refactor process_internal_control_complete() --- src/class/cdc/cdc_host.c | 142 +++++++++++++++++++++++------------------------ 1 file changed, 69 insertions(+), 73 deletions(-) (limited to 'src/class') diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index 3843a8edc..bfaa64a77 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -396,26 +396,23 @@ bool tuh_cdc_read_clear (uint8_t idx) { // Control Endpoint API //--------------------------------------------------------------------+ -// internal control complete to update state such as line state, encoding -static void cdch_internal_control_complete(tuh_xfer_t* xfer) { - uint8_t const itf_num = (uint8_t) tu_le16toh(xfer->setup->wIndex); - uint8_t idx = tuh_cdc_itf_get_index(xfer->daddr, itf_num); - cdch_interface_t* p_cdc = get_itf(idx); +static void process_internal_control_complete(cdch_interface_t* p_cdc, tuh_xfer_t* xfer) { TU_ASSERT(p_cdc, ); + uint16_t const value = tu_le16toh(xfer->setup->wValue); if (xfer->result == XFER_RESULT_SUCCESS) { switch (p_cdc->serial_drid) { case SERIAL_DRIVER_ACM: switch (xfer->setup->bRequest) { case CDC_REQUEST_SET_CONTROL_LINE_STATE: - p_cdc->line_state = (uint8_t) tu_le16toh(xfer->setup->wValue); + p_cdc->line_state = (uint8_t) value; break; case CDC_REQUEST_SET_LINE_CODING: { uint16_t const len = tu_min16(sizeof(cdc_line_coding_t), tu_le16toh(xfer->setup->wLength)); memcpy(&p_cdc->line_coding, xfer->buffer, len); - } break; + } default: break; } @@ -425,11 +422,10 @@ static void cdch_internal_control_complete(tuh_xfer_t* xfer) { case SERIAL_DRIVER_FTDI: switch (xfer->setup->bRequest) { case FTDI_SIO_MODEM_CTRL: - p_cdc->line_state = (uint8_t) (tu_le16toh(xfer->setup->wValue) & 0x00ff); + p_cdc->line_state = (uint8_t) value; break; case FTDI_SIO_SET_BAUD_RATE: - // convert from divisor to baudrate is not supported p_cdc->line_coding.bit_rate = p_cdc->requested_line_coding.bit_rate; break; @@ -442,22 +438,62 @@ static void cdch_internal_control_complete(tuh_xfer_t* xfer) { case SERIAL_DRIVER_CP210X: switch(xfer->setup->bRequest) { case CP210X_SET_MHS: - p_cdc->line_state = (uint8_t) (tu_le16toh(xfer->setup->wValue) & 0x00ff); + p_cdc->line_state = (uint8_t) value; break; case CP210X_SET_BAUDRATE: { uint32_t baudrate; memcpy(&baudrate, xfer->buffer, sizeof(uint32_t)); p_cdc->line_coding.bit_rate = tu_le32toh(baudrate); - } break; + } + + default: break; } break; #endif #if CFG_TUH_CDC_CH34X case SERIAL_DRIVER_CH34X: - TU_ASSERT(false, ); // see special ch34x_control_complete function + switch (xfer->setup->bRequest) { + case CH34X_REQ_WRITE_REG: + // register write request + switch (value) { + case CH34X_REG16_DIVISOR_PRESCALER: + // baudrate + p_cdc->line_coding.bit_rate = p_cdc->requested_line_coding.bit_rate; + break; + + case CH32X_REG16_LCR2_LCR: + // data format + p_cdc->line_coding.stop_bits = p_cdc->requested_line_coding.stop_bits; + p_cdc->line_coding.parity = p_cdc->requested_line_coding.parity; + p_cdc->line_coding.data_bits = p_cdc->requested_line_coding.data_bits; + break; + + default: break; + } + break; + + case CH34X_REQ_MODEM_CTRL: { + // set modem controls RTS/DTR request. Note: signals are inverted + uint16_t const modem_signal = ~value; + if (modem_signal & CH34X_BIT_RTS) { + p_cdc->line_state |= CDC_CONTROL_LINE_STATE_RTS; + } else { + p_cdc->line_state &= (uint8_t) ~CDC_CONTROL_LINE_STATE_RTS; + } + + if (modem_signal & CH34X_BIT_DTR) { + p_cdc->line_state |= CDC_CONTROL_LINE_STATE_DTR; + } else { + p_cdc->line_state &= (uint8_t) ~CDC_CONTROL_LINE_STATE_DTR; + } + break; + } + + default: break; + } break; #endif @@ -471,6 +507,15 @@ static void cdch_internal_control_complete(tuh_xfer_t* xfer) { } } +// internal control complete to update state such as line state, encoding +static void cdch_internal_control_complete(tuh_xfer_t* xfer) { + uint8_t const itf_num = (uint8_t) tu_le16toh(xfer->setup->wIndex); + uint8_t idx = tuh_cdc_itf_get_index(xfer->daddr, itf_num); + cdch_interface_t* p_cdc = get_itf(idx); + + process_internal_control_complete(p_cdc, xfer); +} + bool tuh_cdc_set_control_line_state(uint8_t idx, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { cdch_interface_t* p_cdc = get_itf(idx); TU_VERIFY(p_cdc && p_cdc->serial_drid < SERIAL_DRIVER_COUNT); @@ -1279,70 +1324,16 @@ static void ch34x_control_complete(tuh_xfer_t* xfer) { uint8_t const itf_num = 0; uint8_t const idx = tuh_cdc_itf_get_index(xfer->daddr, itf_num); cdch_interface_t* p_cdc = get_itf(idx); - uint16_t value = tu_le16toh (xfer->setup->wValue); - TU_ASSERT (p_cdc,); - TU_ASSERT (p_cdc->serial_drid == SERIAL_DRIVER_CH34X,); - - if (xfer->result == XFER_RESULT_SUCCESS) { - switch (xfer->setup->bRequest) { - case CH34X_REQ_WRITE_REG: - // register write request - switch (value) { - case CH34X_REG16_DIVISOR_PRESCALER: - // baudrate write - p_cdc->line_coding.bit_rate = p_cdc->requested_line_coding.bit_rate; - break; - - case CH32X_REG16_LCR2_LCR: - // data format write - p_cdc->line_coding.stop_bits = p_cdc->requested_line_coding.stop_bits; - p_cdc->line_coding.parity = p_cdc->requested_line_coding.parity; - p_cdc->line_coding.data_bits = p_cdc->requested_line_coding.data_bits; - break; - - default: - TU_ASSERT(false,); // unexpected register write - break; - } - break; - - case CH34X_REQ_MODEM_CTRL: { - // set modem controls RTS/DTR request. Note: signals are inverted - uint16_t const modem_signal = ~value; - if (modem_signal & CH34X_BIT_RTS) { - p_cdc->line_state |= CDC_CONTROL_LINE_STATE_RTS; - } else { - p_cdc->line_state &= (uint8_t) ~CDC_CONTROL_LINE_STATE_RTS; - } - - if (modem_signal & CH34X_BIT_DTR) { - p_cdc->line_state |= CDC_CONTROL_LINE_STATE_DTR; - } else { - p_cdc->line_state &= (uint8_t) ~CDC_CONTROL_LINE_STATE_DTR; - } - break; - } - - case CH34X_REQ_SERIAL_INIT: - // serial init request (set line coding incl. baudrate) - p_cdc->line_coding = p_cdc->requested_line_coding; - break; - - default: - TU_ASSERT(false,); // unexpected request - break; - } - - xfer->complete_cb = p_cdc->user_control_cb; - if (xfer->complete_cb) { - xfer->complete_cb(xfer); - } - } + process_internal_control_complete(p_cdc, xfer); } //static bool ch34x_set_data_format(cdch_interface_t* p_cdc, uint8_t stop_bits, uint8_t parity, uint8_t data_bits, // tuh_xfer_cb_t complete_cb, uintptr_t user_data) { // uint8_t const lcr = ch34x_get_lcr(stop_bits, parity, data_bits); +// p_cdc->requested_line_coding.stop_bits = stop_bits; +// p_cdc->requested_line_coding.parity = parity; +// p_cdc->requested_line_coding.data_bits = data_bits; +// // TU_ASSERT (ch34x_control_out(p_cdc, CH34X_REQ_WRITE_REG, CH32X_REG16_LCR2_LCR, lcr, // complete_cb ? ch34x_control_complete : NULL, user_data)); // return false; @@ -1350,16 +1341,21 @@ static void ch34x_control_complete(tuh_xfer_t* xfer) { static bool ch34x_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - p_cdc->requested_line_coding.bit_rate = baudrate; - p_cdc->user_control_cb = complete_cb; uint16_t const div_ps = ch34x_get_divisor_prescaler(baudrate); TU_VERIFY(div_ps != 0); + + p_cdc->requested_line_coding.bit_rate = baudrate; + p_cdc->user_control_cb = complete_cb; TU_ASSERT(ch34x_write_reg(p_cdc, CH34X_REG16_DIVISOR_PRESCALER, div_ps, complete_cb ? ch34x_control_complete : NULL, user_data)); return true; } +//static void ch34x_set_line_coding_stage1(tuh_xfer_t* xfer) { +// +//} + static bool ch34x_set_line_coding(cdch_interface_t* p_cdc, cdc_line_coding_t const* line_coding, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { // p_cdc->baudrate_requested = line_coding->bit_rate; -- cgit v1.3.1 From 98781bb903d94190d57ad4b9436a85a31d67404c Mon Sep 17 00:00:00 2001 From: hathach Date: Fri, 19 Jan 2024 15:58:05 +0700 Subject: - add ch34x_set_data_format() - add ch34x_set_line_coding() --- examples/host/cdc_msc_hid/src/cdc_app.c | 68 ++++++++++------------ src/class/cdc/cdc_host.c | 100 ++++++++++++++++++++++---------- src/class/cdc/serial/ch34x.h | 3 +- 3 files changed, 102 insertions(+), 69 deletions(-) (limited to 'src/class') diff --git a/examples/host/cdc_msc_hid/src/cdc_app.c b/examples/host/cdc_msc_hid/src/cdc_app.c index a1b26e49c..81052047c 100644 --- a/examples/host/cdc_msc_hid/src/cdc_app.c +++ b/examples/host/cdc_msc_hid/src/cdc_app.c @@ -27,20 +27,11 @@ #include "tusb.h" #include "bsp/board_api.h" -//--------------------------------------------------------------------+ -// MACRO TYPEDEF CONSTANT ENUM DECLARATION -//--------------------------------------------------------------------+ - - -//------------- IMPLEMENTATION -------------// - -size_t get_console_inputs(uint8_t* buf, size_t bufsize) -{ +size_t get_console_inputs(uint8_t* buf, size_t bufsize) { size_t count = 0; - while (count < bufsize) - { + while (count < bufsize) { int ch = board_getchar(); - if ( ch <= 0 ) break; + if (ch <= 0) break; buf[count] = (uint8_t) ch; count++; @@ -49,22 +40,18 @@ size_t get_console_inputs(uint8_t* buf, size_t bufsize) return count; } -void cdc_app_task(void) -{ - uint8_t buf[64+1]; // +1 for extra null character - uint32_t const bufsize = sizeof(buf)-1; +void cdc_app_task(void) { + uint8_t buf[64 + 1]; // +1 for extra null character + uint32_t const bufsize = sizeof(buf) - 1; uint32_t count = get_console_inputs(buf, bufsize); buf[count] = 0; // loop over all mounted interfaces - for(uint8_t idx=0; idx cdc interfaces - if (count) - { + if (count) { tuh_cdc_write(idx, buf, count); tuh_cdc_write_flush(idx); } @@ -72,11 +59,14 @@ void cdc_app_task(void) } } +//--------------------------------------------------------------------+ +// TinyUSB callbacks +//--------------------------------------------------------------------+ + // Invoked when received new data -void tuh_cdc_rx_cb(uint8_t idx) -{ - uint8_t buf[64+1]; // +1 for extra null character - uint32_t const bufsize = sizeof(buf)-1; +void tuh_cdc_rx_cb(uint8_t idx) { + uint8_t buf[64 + 1]; // +1 for extra null character + uint32_t const bufsize = sizeof(buf) - 1; // forward cdc interfaces -> console uint32_t count = tuh_cdc_read(idx, buf, bufsize); @@ -85,29 +75,31 @@ void tuh_cdc_rx_cb(uint8_t idx) printf((char*) buf); } -void tuh_cdc_mount_cb(uint8_t idx) -{ - tuh_itf_info_t itf_info = { 0 }; +// Invoked when a device with CDC interface is mounted +// idx is index of cdc interface in the internal pool. +void tuh_cdc_mount_cb(uint8_t idx) { + tuh_itf_info_t itf_info = {0}; tuh_cdc_itf_get_info(idx, &itf_info); - printf("CDC Interface is mounted: address = %u, itf_num = %u\r\n", itf_info.daddr, itf_info.desc.bInterfaceNumber); + printf("CDC Interface is mounted: address = %u, itf_num = %u\r\n", itf_info.daddr, + itf_info.desc.bInterfaceNumber); #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM // CFG_TUH_CDC_LINE_CODING_ON_ENUM must be defined for line coding is set by tinyusb in enumeration // otherwise you need to call tuh_cdc_set_line_coding() first - cdc_line_coding_t line_coding = { 0 }; - if ( tuh_cdc_get_local_line_coding(idx, &line_coding) ) - { + cdc_line_coding_t line_coding = {0}; + if (tuh_cdc_get_local_line_coding(idx, &line_coding)) { printf(" Baudrate: %lu, Stop Bits : %u\r\n", line_coding.bit_rate, line_coding.stop_bits); - printf(" Parity : %u, Data Width: %u\r\n", line_coding.parity , line_coding.data_bits); + printf(" Parity : %u, Data Width: %u\r\n", line_coding.parity, line_coding.data_bits); } #endif } -void tuh_cdc_umount_cb(uint8_t idx) -{ - tuh_itf_info_t itf_info = { 0 }; +// Invoked when a device with CDC interface is unmounted +void tuh_cdc_umount_cb(uint8_t idx) { + tuh_itf_info_t itf_info = {0}; tuh_cdc_itf_get_info(idx, &itf_info); - printf("CDC Interface is unmounted: address = %u, itf_num = %u\r\n", itf_info.daddr, itf_info.desc.bInterfaceNumber); + printf("CDC Interface is unmounted: address = %u, itf_num = %u\r\n", itf_info.daddr, + itf_info.desc.bInterfaceNumber); } diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index bfaa64a77..37fa30982 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -1327,48 +1327,88 @@ static void ch34x_control_complete(tuh_xfer_t* xfer) { process_internal_control_complete(p_cdc, xfer); } -//static bool ch34x_set_data_format(cdch_interface_t* p_cdc, uint8_t stop_bits, uint8_t parity, uint8_t data_bits, -// tuh_xfer_cb_t complete_cb, uintptr_t user_data) { -// uint8_t const lcr = ch34x_get_lcr(stop_bits, parity, data_bits); -// p_cdc->requested_line_coding.stop_bits = stop_bits; -// p_cdc->requested_line_coding.parity = parity; -// p_cdc->requested_line_coding.data_bits = data_bits; -// -// TU_ASSERT (ch34x_control_out(p_cdc, CH34X_REQ_WRITE_REG, CH32X_REG16_LCR2_LCR, lcr, -// complete_cb ? ch34x_control_complete : NULL, user_data)); -// return false; -//} +static bool ch34x_set_data_format(cdch_interface_t* p_cdc, uint8_t stop_bits, uint8_t parity, uint8_t data_bits, + tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + p_cdc->requested_line_coding.stop_bits = stop_bits; + p_cdc->requested_line_coding.parity = parity; + p_cdc->requested_line_coding.data_bits = data_bits; + + uint8_t const lcr = ch34x_get_lcr(stop_bits, parity, data_bits); + TU_ASSERT (ch34x_control_out(p_cdc, CH34X_REQ_WRITE_REG, CH32X_REG16_LCR2_LCR, lcr, + complete_cb ? ch34x_control_complete : NULL, user_data)); + return true; +} -static bool ch34x_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, - tuh_xfer_cb_t complete_cb, uintptr_t user_data) { +static bool ch34x_write_reg_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, + tuh_xfer_cb_t complete_cb, uintptr_t user_data) { uint16_t const div_ps = ch34x_get_divisor_prescaler(baudrate); TU_VERIFY(div_ps != 0); + TU_ASSERT(ch34x_write_reg(p_cdc, CH34X_REG16_DIVISOR_PRESCALER, div_ps, + complete_cb, user_data)); + return true; +} +static bool ch34x_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, + tuh_xfer_cb_t complete_cb, uintptr_t user_data) { p_cdc->requested_line_coding.bit_rate = baudrate; p_cdc->user_control_cb = complete_cb; - TU_ASSERT(ch34x_write_reg(p_cdc, CH34X_REG16_DIVISOR_PRESCALER, div_ps, - complete_cb ? ch34x_control_complete : NULL, user_data)); - + TU_ASSERT(ch34x_write_reg_baudrate(p_cdc, baudrate, + complete_cb ? ch34x_control_complete : NULL, user_data)); return true; } -//static void ch34x_set_line_coding_stage1(tuh_xfer_t* xfer) { -// -//} +static void ch34x_set_line_coding_stage1_complete(tuh_xfer_t* xfer) { + uint8_t const itf_num = 0; + uint8_t const idx = tuh_cdc_itf_get_index(xfer->daddr, itf_num); + cdch_interface_t* p_cdc = get_itf(idx); + TU_ASSERT(p_cdc, ); + if (xfer->result == XFER_RESULT_SUCCESS) { + // stage 1 success, continue to stage 2 + p_cdc->line_coding.bit_rate = p_cdc->requested_line_coding.bit_rate; + TU_ASSERT(ch34x_set_data_format(p_cdc, p_cdc->requested_line_coding.stop_bits, p_cdc->requested_line_coding.parity, + p_cdc->requested_line_coding.data_bits, ch34x_control_complete, xfer->user_data), ); + } else { + // stage 1 failed, notify user + xfer->complete_cb = p_cdc->user_control_cb; + if (xfer->complete_cb) { + xfer->complete_cb(xfer); + } + } +} + +// 2 stages: set baudrate (stage1) + set data format (stage2) static bool ch34x_set_line_coding(cdch_interface_t* p_cdc, cdc_line_coding_t const* line_coding, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { -// p_cdc->baudrate_requested = line_coding->bit_rate; -// p_cdc->user_control_cb = complete_cb; -// uint8_t factor, divisor, lcr; -// TU_ASSERT (ch34x_get_factor_divisor(line_coding->bit_rate, &factor, &divisor)); -// TU_ASSERT (ch34x_get_lcr(line_coding, &lcr)); -// TU_ASSERT (ch34x_control_out(p_cdc, CH34X_REQ_SERIAL_INIT, (uint16_t) (lcr << 8 | 0x9c), (uint16_t) (factor << 8 | 0x80 | divisor), -// complete_cb ? ch34x_control_complete : NULL, user_data)); - (void) p_cdc; - (void) line_coding; - (void) complete_cb; - (void) user_data; + p_cdc->requested_line_coding = *line_coding; + p_cdc->user_control_cb = complete_cb; + + if (complete_cb) { + // stage 1 set baudrate + TU_ASSERT(ch34x_write_reg_baudrate(p_cdc, line_coding->bit_rate, + ch34x_set_line_coding_stage1_complete, user_data)); + } else { + // sync call + xfer_result_t result; + + // stage 1 set baudrate + TU_ASSERT(ch34x_write_reg_baudrate(p_cdc, line_coding->bit_rate, NULL, (uintptr_t) &result)); + TU_VERIFY(result == XFER_RESULT_SUCCESS); + p_cdc->line_coding.bit_rate = line_coding->bit_rate; + + // stage 2 set data format + TU_ASSERT(ch34x_set_data_format(p_cdc, line_coding->stop_bits, line_coding->parity, line_coding->data_bits, + NULL, (uintptr_t) &result)); + TU_VERIFY(result == XFER_RESULT_SUCCESS); + p_cdc->line_coding.stop_bits = line_coding->stop_bits; + p_cdc->line_coding.parity = line_coding->parity; + p_cdc->line_coding.data_bits = line_coding->data_bits; + + // update transfer result, user_data is expected to point to xfer_result_t + if (user_data) { + user_data = result; + } + } return true; } diff --git a/src/class/cdc/serial/ch34x.h b/src/class/cdc/serial/ch34x.h index 3f78a3007..5def8d212 100644 --- a/src/class/cdc/serial/ch34x.h +++ b/src/class/cdc/serial/ch34x.h @@ -63,7 +63,8 @@ #define CH341_REG_0x2C 0x2C // undocumented register #define CH341_REG_0x27 0x27 // hardware flow control (cts/rts) -#define CH34X_REG16_DIVISOR_PRESCALER TU_U16(CH34X_REG_DIVISOR, CH34X_REG_PRESCALER) +#define CH34X_REG16_DIVISOR_PRESCALER TU_U16(CH34X_REG_DIVISOR, CH34X_REG_PRESCALER) +#define CH32X_REG16_LCR2_LCR TU_U16(CH34X_REG_LCR2, CH34X_REG_LCR) // modem control bits #define CH34X_BIT_RTS ( 1 << 6 ) -- cgit v1.3.1 From c196a2ed9cbd27188472d76ec428fdb24931d0b6 Mon Sep 17 00:00:00 2001 From: hathach Date: Fri, 19 Jan 2024 16:04:30 +0700 Subject: move code around --- src/class/cdc/cdc_host.c | 94 +++++++++++++++++++++++++----------------------- 1 file changed, 49 insertions(+), 45 deletions(-) (limited to 'src/class') diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index 37fa30982..8965ee261 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -1223,46 +1223,12 @@ static void cp210x_process_config(tuh_xfer_t* xfer) { #if CFG_TUH_CDC_CH34X -enum { - CONFIG_CH34X_READ_VERSION = 0, - CONFIG_CH34X_SERIAL_INIT, - CONFIG_CH34X_SPECIAL_REG_WRITE, - CONFIG_CH34X_FLOW_CONTROL, - CONFIG_CH34X_MODEM_CONTROL, - CONFIG_CH34X_COMPLETE -}; - static uint8_t ch34x_get_lcr(uint8_t stop_bits, uint8_t parity, uint8_t data_bits); static uint16_t ch34x_get_divisor_prescaler(uint32_t baval); -static bool ch34x_open(uint8_t daddr, tusb_desc_interface_t const* itf_desc, uint16_t max_len) { - // CH34x Interface includes 1 vendor interface + 2 bulk + 1 interrupt endpoints - TU_VERIFY (itf_desc->bNumEndpoints == 3); - TU_VERIFY (sizeof(tusb_desc_interface_t) + 3 * sizeof(tusb_desc_endpoint_t) <= max_len); - - cdch_interface_t* p_cdc = make_new_itf(daddr, itf_desc); - TU_VERIFY (p_cdc); - - TU_LOG_DRV ("CH34x opened\r\n"); - p_cdc->serial_drid = SERIAL_DRIVER_CH34X; - - tusb_desc_endpoint_t const* desc_ep = (tusb_desc_endpoint_t const*) tu_desc_next(itf_desc); - - // data endpoints expected to be in pairs - TU_ASSERT(open_ep_stream_pair(p_cdc, desc_ep)); - desc_ep += 2; - - // Interrupt endpoint: not used for now - TU_ASSERT(TUSB_DESC_ENDPOINT == tu_desc_type(desc_ep) && - TUSB_XFER_INTERRUPT == desc_ep->bmAttributes.xfer); - TU_ASSERT(tuh_edpt_open(daddr, desc_ep)); - p_cdc->ep_notif = desc_ep->bEndpointAddress; - - return true; -} - +//------------- control requestt -------------// static bool ch34x_set_request(cdch_interface_t* p_cdc, uint8_t direction, uint8_t request, uint16_t value, - uint16_t index, uint8_t* buffer, uint16_t length, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + uint16_t index, uint8_t* buffer, uint16_t length, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { tusb_control_request_t const request_setup = { .bmRequestType_bit = { .recipient = TUSB_REQ_RCPT_DEVICE, @@ -1318,6 +1284,17 @@ static bool ch34x_write_reg(cdch_interface_t* p_cdc, uint16_t reg, uint16_t reg_ // return ch34x_control_in ( p_cdc, CH34X_REQ_READ_REG, reg, 0, buffer, buffersize, complete_cb, user_data ); //} +static bool ch34x_write_reg_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, + tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + uint16_t const div_ps = ch34x_get_divisor_prescaler(baudrate); + TU_VERIFY(div_ps != 0); + TU_ASSERT(ch34x_write_reg(p_cdc, CH34X_REG16_DIVISOR_PRESCALER, div_ps, + complete_cb, user_data)); + return true; +} + +//------------- Driver API -------------// + // internal control complete to update state such as line state, encoding static void ch34x_control_complete(tuh_xfer_t* xfer) { // CH34x only has 1 interface and use wIndex as payload and not for bInterfaceNumber @@ -1339,15 +1316,6 @@ static bool ch34x_set_data_format(cdch_interface_t* p_cdc, uint8_t stop_bits, ui return true; } -static bool ch34x_write_reg_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, - tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - uint16_t const div_ps = ch34x_get_divisor_prescaler(baudrate); - TU_VERIFY(div_ps != 0); - TU_ASSERT(ch34x_write_reg(p_cdc, CH34X_REG16_DIVISOR_PRESCALER, div_ps, - complete_cb, user_data)); - return true; -} - static bool ch34x_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { p_cdc->requested_line_coding.bit_rate = baudrate; @@ -1432,6 +1400,42 @@ static bool ch34x_set_modem_ctrl(cdch_interface_t* p_cdc, uint16_t line_state, return true; } +//------------- Enumeration -------------// +enum { + CONFIG_CH34X_READ_VERSION = 0, + CONFIG_CH34X_SERIAL_INIT, + CONFIG_CH34X_SPECIAL_REG_WRITE, + CONFIG_CH34X_FLOW_CONTROL, + CONFIG_CH34X_MODEM_CONTROL, + CONFIG_CH34X_COMPLETE +}; + +static bool ch34x_open(uint8_t daddr, tusb_desc_interface_t const* itf_desc, uint16_t max_len) { + // CH34x Interface includes 1 vendor interface + 2 bulk + 1 interrupt endpoints + TU_VERIFY (itf_desc->bNumEndpoints == 3); + TU_VERIFY (sizeof(tusb_desc_interface_t) + 3 * sizeof(tusb_desc_endpoint_t) <= max_len); + + cdch_interface_t* p_cdc = make_new_itf(daddr, itf_desc); + TU_VERIFY (p_cdc); + + TU_LOG_DRV ("CH34x opened\r\n"); + p_cdc->serial_drid = SERIAL_DRIVER_CH34X; + + tusb_desc_endpoint_t const* desc_ep = (tusb_desc_endpoint_t const*) tu_desc_next(itf_desc); + + // data endpoints expected to be in pairs + TU_ASSERT(open_ep_stream_pair(p_cdc, desc_ep)); + desc_ep += 2; + + // Interrupt endpoint: not used for now + TU_ASSERT(TUSB_DESC_ENDPOINT == tu_desc_type(desc_ep) && + TUSB_XFER_INTERRUPT == desc_ep->bmAttributes.xfer); + TU_ASSERT(tuh_edpt_open(daddr, desc_ep)); + p_cdc->ep_notif = desc_ep->bEndpointAddress; + + return true; +} + static void ch34x_process_config(tuh_xfer_t* xfer) { // CH34x only has 1 interface and use wIndex as payload and not for bInterfaceNumber uint8_t const itf_num = 0; -- cgit v1.3.1 From 55cb713264a1fe531b548a05290ee8fe1289828f Mon Sep 17 00:00:00 2001 From: hathach Date: Fri, 19 Jan 2024 16:56:32 +0700 Subject: - add new API tuh_cdc_set_data_format() - add typedef for cdc enum --- src/class/cdc/cdc.h | 20 +++++------ src/class/cdc/cdc_host.c | 90 ++++++++++++++++++++++++++++++++++++++++++------ src/class/cdc/cdc_host.h | 13 +++---- 3 files changed, 95 insertions(+), 28 deletions(-) (limited to 'src/class') diff --git a/src/class/cdc/cdc.h b/src/class/cdc/cdc.h index deec32ae4..5cbd658fe 100644 --- a/src/class/cdc/cdc.h +++ b/src/class/cdc/cdc.h @@ -136,8 +136,7 @@ typedef enum{ //--------------------------------------------------------------------+ /// Communication Interface Management Element Request Codes -typedef enum -{ +typedef enum { CDC_REQUEST_SEND_ENCAPSULATED_COMMAND = 0x00, ///< is used to issue a command in the format of the supported control protocol of the Communications Class interface CDC_REQUEST_GET_ENCAPSULATED_RESPONSE = 0x01, ///< is used to request a response in the format of the supported control protocol of the Communications Class interface. CDC_REQUEST_SET_COMM_FEATURE = 0x02, @@ -180,39 +179,38 @@ typedef enum CDC_REQUEST_GET_ATM_VC_STATISTICS = 0x53, CDC_REQUEST_MDLM_SEMANTIC_MODEL = 0x60, -}cdc_management_request_t; +} cdc_management_request_t; -enum { +typedef enum { CDC_CONTROL_LINE_STATE_DTR = 0x01, CDC_CONTROL_LINE_STATE_RTS = 0x02, -}; +} cdc_control_line_state_t; -enum { +typedef enum { CDC_LINE_CODING_STOP_BITS_1 = 0, // 1 bit CDC_LINE_CODING_STOP_BITS_1_5 = 1, // 1.5 bits CDC_LINE_CODING_STOP_BITS_2 = 2, // 2 bits -}; +} cdc_line_coding_stopbits_t; // TODO Backward compatible for typos. Maybe removed in the future release #define CDC_LINE_CONDING_STOP_BITS_1 CDC_LINE_CODING_STOP_BITS_1 #define CDC_LINE_CONDING_STOP_BITS_1_5 CDC_LINE_CODING_STOP_BITS_1_5 #define CDC_LINE_CONDING_STOP_BITS_2 CDC_LINE_CODING_STOP_BITS_2 -enum { +typedef enum { CDC_LINE_CODING_PARITY_NONE = 0, CDC_LINE_CODING_PARITY_ODD = 1, CDC_LINE_CODING_PARITY_EVEN = 2, CDC_LINE_CODING_PARITY_MARK = 3, CDC_LINE_CODING_PARITY_SPACE = 4, -}; +} cdc_line_coding_parity_t; //--------------------------------------------------------------------+ // Management Element Notification (Notification Endpoint) //--------------------------------------------------------------------+ /// 6.3 Notification Codes -typedef enum -{ +typedef enum { CDC_NOTIF_NETWORK_CONNECTION = 0x00, ///< This notification allows the device to notify the host about network connection status. CDC_NOTIF_RESPONSE_AVAILABLE = 0x01, ///< This notification allows the device to notify the hostthat a response is available. This response can be retrieved with a subsequent \ref CDC_REQUEST_GET_ENCAPSULATED_RESPONSE request. CDC_NOTIF_AUX_JACK_HOOK_STATE = 0x08, diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index 8965ee261..f5182efc2 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -90,9 +90,10 @@ static cdch_interface_t cdch_data[CFG_TUH_CDC]; static bool acm_open(uint8_t daddr, tusb_desc_interface_t const *itf_desc, uint16_t max_len); static void acm_process_config(tuh_xfer_t* xfer); +static bool acm_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data); +static bool acm_set_data_format(cdch_interface_t* p_cdc, uint8_t stop_bits, uint8_t parity, uint8_t data_bits, tuh_xfer_cb_t complete_cb, uintptr_t user_data); static bool acm_set_line_coding(cdch_interface_t* p_cdc, cdc_line_coding_t const* line_coding, tuh_xfer_cb_t complete_cb, uintptr_t user_data); static bool acm_set_control_line_state(cdch_interface_t* p_cdc, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data); -static bool acm_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data); //------------- FTDI prototypes -------------// #if CFG_TUH_CDC_FTDI @@ -100,15 +101,13 @@ static bool acm_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfe static uint16_t const ftdi_vid_pid_list[][2] = {CFG_TUH_CDC_FTDI_VID_PID_LIST}; -// Store last request baudrate since divisor to baudrate is not easy -// static uint32_t _ftdi_requested_baud; - static bool ftdi_open(uint8_t daddr, const tusb_desc_interface_t *itf_desc, uint16_t max_len); static void ftdi_process_config(tuh_xfer_t* xfer); +static bool ftdi_sio_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data); +static bool ftdi_set_data_format(cdch_interface_t* p_cdc, uint8_t stop_bits, uint8_t parity, uint8_t data_bits, tuh_xfer_cb_t complete_cb, uintptr_t user_data); static bool ftdi_set_line_coding(cdch_interface_t* p_cdc, cdc_line_coding_t const* line_coding, tuh_xfer_cb_t complete_cb, uintptr_t user_data); static bool ftdi_sio_set_modem_ctrl(cdch_interface_t* p_cdc, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data); -static bool ftdi_sio_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data); #endif //------------- CP210X prototypes -------------// @@ -120,9 +119,10 @@ static uint16_t const cp210x_vid_pid_list[][2] = {CFG_TUH_CDC_CP210X_VID_PID_LIS static bool cp210x_open(uint8_t daddr, tusb_desc_interface_t const *itf_desc, uint16_t max_len); static void cp210x_process_config(tuh_xfer_t* xfer); +static bool cp210x_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data); +static bool cp210x_set_data_format(cdch_interface_t* p_cdc, uint8_t stop_bits, uint8_t parity, uint8_t data_bits, tuh_xfer_cb_t complete_cb, uintptr_t user_data); static bool cp210x_set_line_coding(cdch_interface_t* p_cdc, cdc_line_coding_t const* line_coding, tuh_xfer_cb_t complete_cb, uintptr_t user_data); static bool cp210x_set_modem_ctrl(cdch_interface_t* p_cdc, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data); -static bool cp210x_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data); #endif //------------- CH34x prototypes -------------// @@ -131,16 +131,16 @@ static bool cp210x_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, tuh_ static uint16_t const ch34x_vid_pid_list[][2] = {CFG_TUH_CDC_CH34X_VID_PID_LIST}; -static bool ch34x_open ( uint8_t daddr, tusb_desc_interface_t const *itf_desc, uint16_t max_len ); -static void ch34x_process_config ( tuh_xfer_t* xfer ); +static bool ch34x_open(uint8_t daddr, tusb_desc_interface_t const* itf_desc, uint16_t max_len); +static void ch34x_process_config(tuh_xfer_t* xfer); +static bool ch34x_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data); +static bool ch34x_set_data_format(cdch_interface_t* p_cdc, uint8_t stop_bits, uint8_t parity, uint8_t data_bits, tuh_xfer_cb_t complete_cb, uintptr_t user_data); static bool ch34x_set_line_coding(cdch_interface_t* p_cdc, cdc_line_coding_t const* line_coding, tuh_xfer_cb_t complete_cb, uintptr_t user_data); -static bool ch34x_set_modem_ctrl ( cdch_interface_t* p_cdc, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data ); -static bool ch34x_set_baudrate ( cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data ); +static bool ch34x_set_modem_ctrl(cdch_interface_t* p_cdc, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data); #endif //------------- Common -------------// - enum { SERIAL_DRIVER_ACM = 0, @@ -166,6 +166,7 @@ typedef struct { void (*const process_set_config)(tuh_xfer_t* xfer); bool (*const set_control_line_state)(cdch_interface_t* p_cdc, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data); bool (*const set_baudrate)(cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data); + bool (*const set_data_format)(cdch_interface_t* p_cdc, uint8_t stop_bits, uint8_t parity, uint8_t data_bits, tuh_xfer_cb_t complete_cb, uintptr_t user_data); bool (*const set_line_coding)(cdch_interface_t* p_cdc, cdc_line_coding_t const* line_coding, tuh_xfer_cb_t complete_cb, uintptr_t user_data); } cdch_serial_driver_t; @@ -178,6 +179,7 @@ static const cdch_serial_driver_t serial_drivers[] = { .process_set_config = acm_process_config, .set_control_line_state = acm_set_control_line_state, .set_baudrate = acm_set_baudrate, + .set_data_format = acm_set_data_format, .set_line_coding = acm_set_line_coding }, @@ -189,6 +191,7 @@ static const cdch_serial_driver_t serial_drivers[] = { .process_set_config = ftdi_process_config, .set_control_line_state = ftdi_sio_set_modem_ctrl, .set_baudrate = ftdi_sio_set_baudrate, + .set_data_format = ftdi_set_data_format, .set_line_coding = ftdi_set_line_coding }, #endif @@ -201,6 +204,7 @@ static const cdch_serial_driver_t serial_drivers[] = { .process_set_config = cp210x_process_config, .set_control_line_state = cp210x_set_modem_ctrl, .set_baudrate = cp210x_set_baudrate, + .set_data_format = cp210x_set_data_format, .set_line_coding = cp210x_set_line_coding }, #endif @@ -213,6 +217,7 @@ static const cdch_serial_driver_t serial_drivers[] = { .process_set_config = ch34x_process_config, .set_control_line_state = ch34x_set_modem_ctrl, .set_baudrate = ch34x_set_baudrate, + .set_data_format = ch34x_set_data_format, .set_line_coding = ch34x_set_line_coding }, #endif @@ -562,6 +567,32 @@ bool tuh_cdc_set_baudrate(uint8_t idx, uint32_t baudrate, tuh_xfer_cb_t complete } } +bool tuh_cdc_set_data_format(uint8_t idx, uint8_t stop_bits, uint8_t parity, uint8_t data_bits, + tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + cdch_interface_t* p_cdc = get_itf(idx); + TU_VERIFY(p_cdc && p_cdc->serial_drid < SERIAL_DRIVER_COUNT); + cdch_serial_driver_t const* driver = &serial_drivers[p_cdc->serial_drid]; + + if (complete_cb) { + return driver->set_data_format(p_cdc, stop_bits, parity, data_bits, complete_cb, user_data); + } else { + // blocking + xfer_result_t result = XFER_RESULT_INVALID; + bool ret = driver->set_data_format(p_cdc, stop_bits, parity, data_bits, complete_cb, (uintptr_t) &result); + + if (user_data) { + // user_data is not NULL, return result via user_data + *((xfer_result_t*) user_data) = result; + } + + TU_VERIFY(ret && result == XFER_RESULT_SUCCESS); + p_cdc->line_coding.stop_bits = stop_bits; + p_cdc->line_coding.parity = parity; + p_cdc->line_coding.data_bits = data_bits; + return true; + } +} + bool tuh_cdc_set_line_coding(uint8_t idx, cdc_line_coding_t const* line_coding, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { cdch_interface_t* p_cdc = get_itf(idx); TU_VERIFY(p_cdc && p_cdc->serial_drid < SERIAL_DRIVER_COUNT); @@ -900,6 +931,19 @@ static bool acm_set_line_coding(cdch_interface_t* p_cdc, cdc_line_coding_t const return true; } +static bool acm_set_data_format(cdch_interface_t* p_cdc, uint8_t stop_bits, uint8_t parity, uint8_t data_bits, + tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + TU_LOG_DRV("CDC ACM Set Data Format\r\n"); + + cdc_line_coding_t line_coding; + line_coding.bit_rate = p_cdc->line_coding.bit_rate; + line_coding.stop_bits = stop_bits; + line_coding.parity = parity; + line_coding.data_bits = data_bits; + + return acm_set_line_coding(p_cdc, &line_coding, complete_cb, user_data); +} + static bool acm_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { TU_VERIFY(p_cdc->acm_capability.support_line_request); cdc_line_coding_t line_coding = p_cdc->line_coding; @@ -968,6 +1012,18 @@ static bool ftdi_sio_reset(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, u return ftdi_sio_set_request(p_cdc, FTDI_SIO_RESET, FTDI_SIO_RESET_SIO, complete_cb, user_data); } +static bool ftdi_set_data_format(cdch_interface_t* p_cdc, uint8_t stop_bits, uint8_t parity, uint8_t data_bits, + tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + (void) p_cdc; + (void) stop_bits; + (void) parity; + (void) data_bits; + (void) complete_cb; + (void) user_data; + // TODO not implemented yet + return false; +} + static bool ftdi_set_line_coding(cdch_interface_t* p_cdc, cdc_line_coding_t const* line_coding, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { (void) p_cdc; (void) line_coding; @@ -1161,6 +1217,18 @@ static bool cp210x_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, tuh_ complete_cb ? cdch_internal_control_complete : NULL, user_data); } +static bool cp210x_set_data_format(cdch_interface_t* p_cdc, uint8_t stop_bits, uint8_t parity, uint8_t data_bits, + tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + (void) p_cdc; + (void) stop_bits; + (void) parity; + (void) data_bits; + (void) complete_cb; + (void) user_data; + // TODO not implemented yet + return false; +} + static bool cp210x_set_modem_ctrl(cdch_interface_t* p_cdc, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { TU_LOG_DRV("CDC CP210x Set Control Line State\r\n"); p_cdc->user_control_cb = complete_cb; diff --git a/src/class/cdc/cdc_host.h b/src/class/cdc/cdc_host.h index 9e5edd94e..d512a23a5 100644 --- a/src/class/cdc/cdc_host.h +++ b/src/class/cdc/cdc_host.h @@ -148,8 +148,11 @@ bool tuh_cdc_set_control_line_state(uint8_t idx, uint16_t line_state, tuh_xfer_c // Request to set baudrate bool tuh_cdc_set_baudrate(uint8_t idx, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data); -// Request to Set Line Coding (ACM only) -// Should only use if you don't work with serial devices such as FTDI/CP210x +// Request to set data format +bool tuh_cdc_set_data_format(uint8_t idx, uint8_t stop_bits, uint8_t parity, uint8_t data_bits, tuh_xfer_cb_t complete_cb, uintptr_t user_data); + +// Request to Set Line Coding = baudrate + data format +// Note: only implemented by ACM and CH34x, not supported by FTDI and CP210x yet bool tuh_cdc_set_line_coding(uint8_t idx, cdc_line_coding_t const* line_coding, tuh_xfer_cb_t complete_cb, uintptr_t user_data); // Request to Get Line Coding (ACM only) @@ -159,15 +162,13 @@ bool tuh_cdc_set_line_coding(uint8_t idx, cdc_line_coding_t const* line_coding, // Connect by set both DTR, RTS TU_ATTR_ALWAYS_INLINE static inline -bool tuh_cdc_connect(uint8_t idx, tuh_xfer_cb_t complete_cb, uintptr_t user_data) -{ +bool tuh_cdc_connect(uint8_t idx, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { return tuh_cdc_set_control_line_state(idx, CDC_CONTROL_LINE_STATE_DTR | CDC_CONTROL_LINE_STATE_RTS, complete_cb, user_data); } // Disconnect by clear both DTR, RTS TU_ATTR_ALWAYS_INLINE static inline -bool tuh_cdc_disconnect(uint8_t idx, tuh_xfer_cb_t complete_cb, uintptr_t user_data) -{ +bool tuh_cdc_disconnect(uint8_t idx, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { return tuh_cdc_set_control_line_state(idx, 0x00, complete_cb, user_data); } -- cgit v1.3.1 From 87d509d416ea7c250f4256f897f6cc9a7b7d2121 Mon Sep 17 00:00:00 2001 From: hathach Date: Sat, 20 Jan 2024 01:42:31 +0700 Subject: make CFG_TUH_CDC_LINE_CODING_ON_ENUM optional for ch34x --- examples/host/cdc_msc_hid/src/cdc_app.c | 8 ++++++-- src/class/cdc/cdc_host.c | 19 ++++++++++++++----- src/class/cdc/serial/ch34x.h | 12 +----------- 3 files changed, 21 insertions(+), 18 deletions(-) (limited to 'src/class') diff --git a/examples/host/cdc_msc_hid/src/cdc_app.c b/examples/host/cdc_msc_hid/src/cdc_app.c index 81052047c..e275e7943 100644 --- a/examples/host/cdc_msc_hid/src/cdc_app.c +++ b/examples/host/cdc_msc_hid/src/cdc_app.c @@ -85,13 +85,17 @@ void tuh_cdc_mount_cb(uint8_t idx) { itf_info.desc.bInterfaceNumber); #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM - // CFG_TUH_CDC_LINE_CODING_ON_ENUM must be defined for line coding is set by tinyusb in enumeration - // otherwise you need to call tuh_cdc_set_line_coding() first + // If CFG_TUH_CDC_LINE_CODING_ON_ENUM is defined, line coding will be set by tinyusb stack + // while eneumerating new cdc device cdc_line_coding_t line_coding = {0}; if (tuh_cdc_get_local_line_coding(idx, &line_coding)) { printf(" Baudrate: %lu, Stop Bits : %u\r\n", line_coding.bit_rate, line_coding.stop_bits); printf(" Parity : %u, Data Width: %u\r\n", line_coding.parity, line_coding.data_bits); } +#else + // Set Line Coding upon mounted + cdc_line_coding_t new_line_coding = { 115200, CDC_LINE_CODING_STOP_BITS_1, CDC_LINE_CODING_PARITY_NONE, 8 }; + tuh_cdc_set_line_coding(idx, &new_line_coding, NULL, 0); #endif } diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index f5182efc2..cd948243d 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -1510,10 +1510,11 @@ static void ch34x_process_config(tuh_xfer_t* xfer) { uint8_t const idx = tuh_cdc_itf_get_index(xfer->daddr, itf_num); cdch_interface_t* p_cdc = get_itf(idx); uintptr_t const state = xfer->user_data; - cdc_line_coding_t const line_coding = CFG_TUH_CDC_LINE_CODING_ON_ENUM_CH34X; uint8_t buffer[2]; // TODO remove TU_ASSERT (p_cdc,); + // TODO check xfer->result + switch (state) { case CONFIG_CH34X_READ_VERSION: TU_LOG_DRV("[%u] CDCh CH34x attempt to read Chip Version\r\n", p_cdc->daddr); @@ -1527,20 +1528,28 @@ static void ch34x_process_config(tuh_xfer_t* xfer) { // only versions >= 0x30 are tested, below 0x30 seems having other programming, see drivers from WCH vendor, Linux kernel and FreeBSD TU_ASSERT (version >= 0x30,); + #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM + cdc_line_coding_t const line_coding = CFG_TUH_CDC_LINE_CODING_ON_ENUM; + uint8_t const lcr = ch34x_get_lcr(line_coding.stop_bits, line_coding.parity, line_coding.data_bits); + uint16_t const first_arg = tu_u16(lcr, 0x9c); uint16_t const div_ps = ch34x_get_divisor_prescaler(line_coding.bit_rate); TU_ASSERT(div_ps != 0, ); - - uint8_t const lcr = ch34x_get_lcr(line_coding.stop_bits, line_coding.parity, line_coding.data_bits); + #else + uint16_t const first_arg = 0; + uint16_t const div_ps = 0; + #endif // Init CH34x with line coding - TU_ASSERT (ch34x_control_out(p_cdc, CH34X_REQ_SERIAL_INIT, tu_u16(lcr, 0x9c), div_ps, + TU_ASSERT (ch34x_control_out(p_cdc, CH34X_REQ_SERIAL_INIT, first_arg, div_ps, ch34x_process_config, CONFIG_CH34X_SPECIAL_REG_WRITE),); break; } case CONFIG_CH34X_SPECIAL_REG_WRITE: // do special reg write, purpose unknown, overtaken from WCH driver - p_cdc->line_coding = line_coding; + #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM + p_cdc->line_coding = ((cdc_line_coding_t) CFG_TUH_CDC_LINE_CODING_ON_ENUM); + #endif TU_ASSERT (ch34x_write_reg(p_cdc, 0x0f2c, 0x0007, ch34x_process_config, CONFIG_CH34X_FLOW_CONTROL),); break; diff --git a/src/class/cdc/serial/ch34x.h b/src/class/cdc/serial/ch34x.h index 5def8d212..b9121afb3 100644 --- a/src/class/cdc/serial/ch34x.h +++ b/src/class/cdc/serial/ch34x.h @@ -27,21 +27,11 @@ #ifndef _CH34X_H_ #define _CH34X_H_ -// For simplicity, only the name CH34X is used here, -// but specifically only CH340 and CH341 are supported. - -// There is no official documentation for the CH34x chips. Reference can be found +// There is no official documentation for the CH34x (CH340, CH341) chips. Reference can be found // - https://github.com/WCHSoftGroup/ch341ser_linux // - https://github.com/torvalds/linux/blob/master/drivers/usb/serial/ch341.c // - https://github.com/freebsd/freebsd-src/blob/main/sys/dev/usb/serial/uchcom.c -// set line_coding @ enumeration -#ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM -#define CFG_TUH_CDC_LINE_CODING_ON_ENUM_CH34X CFG_TUH_CDC_LINE_CODING_ON_ENUM -#else // this default is necessary to work properly -#define CFG_TUH_CDC_LINE_CODING_ON_ENUM_CH34X { 9600, CDC_LINE_CONDING_STOP_BITS_1, CDC_LINE_CODING_PARITY_NONE, 8 } -#endif - // USB requests #define CH34X_REQ_READ_VERSION 0x5F // dec 95 #define CH34X_REQ_WRITE_REG 0x9A // dec 154 -- cgit v1.3.1 From 769a237b19bbe5254e1c83869b463c79afb1af34 Mon Sep 17 00:00:00 2001 From: IngHK Date: Sat, 20 Jan 2024 20:34:50 +0100 Subject: accumulated review changes --- src/class/cdc/cdc_host.c | 68 ++++++++++++++++++++------------------------ src/class/cdc/serial/ch34x.h | 7 +++++ 2 files changed, 38 insertions(+), 37 deletions(-) (limited to 'src/class') diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index cd948243d..7adaa0c8c 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -401,7 +401,9 @@ bool tuh_cdc_read_clear (uint8_t idx) { // Control Endpoint API //--------------------------------------------------------------------+ -static void process_internal_control_complete(cdch_interface_t* p_cdc, tuh_xfer_t* xfer) { +static void process_internal_control_complete(tuh_xfer_t* xfer, uint8_t itf_num) { + uint8_t idx = tuh_cdc_itf_get_index(xfer->daddr, itf_num); + cdch_interface_t* p_cdc = get_itf(idx); TU_ASSERT(p_cdc, ); uint16_t const value = tu_le16toh(xfer->setup->wValue); @@ -515,10 +517,7 @@ static void process_internal_control_complete(cdch_interface_t* p_cdc, tuh_xfer_ // internal control complete to update state such as line state, encoding static void cdch_internal_control_complete(tuh_xfer_t* xfer) { uint8_t const itf_num = (uint8_t) tu_le16toh(xfer->setup->wIndex); - uint8_t idx = tuh_cdc_itf_get_index(xfer->daddr, itf_num); - cdch_interface_t* p_cdc = get_itf(idx); - - process_internal_control_complete(p_cdc, xfer); + process_internal_control_complete(xfer, itf_num); } bool tuh_cdc_set_control_line_state(uint8_t idx, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { @@ -1294,7 +1293,8 @@ static void cp210x_process_config(tuh_xfer_t* xfer) { static uint8_t ch34x_get_lcr(uint8_t stop_bits, uint8_t parity, uint8_t data_bits); static uint16_t ch34x_get_divisor_prescaler(uint32_t baval); -//------------- control requestt -------------// +//------------- control request -------------// + static bool ch34x_set_request(cdch_interface_t* p_cdc, uint8_t direction, uint8_t request, uint16_t value, uint16_t index, uint8_t* buffer, uint16_t length, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { tusb_control_request_t const request_setup = { @@ -1366,10 +1366,7 @@ static bool ch34x_write_reg_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, // internal control complete to update state such as line state, encoding static void ch34x_control_complete(tuh_xfer_t* xfer) { // CH34x only has 1 interface and use wIndex as payload and not for bInterfaceNumber - uint8_t const itf_num = 0; - uint8_t const idx = tuh_cdc_itf_get_index(xfer->daddr, itf_num); - cdch_interface_t* p_cdc = get_itf(idx); - process_internal_control_complete(p_cdc, xfer); + process_internal_control_complete(xfer, 0); } static bool ch34x_set_data_format(cdch_interface_t* p_cdc, uint8_t stop_bits, uint8_t parity, uint8_t data_bits, @@ -1379,6 +1376,7 @@ static bool ch34x_set_data_format(cdch_interface_t* p_cdc, uint8_t stop_bits, ui p_cdc->requested_line_coding.data_bits = data_bits; uint8_t const lcr = ch34x_get_lcr(stop_bits, parity, data_bits); + TU_VERIFY(lcr != 0); TU_ASSERT (ch34x_control_out(p_cdc, CH34X_REQ_WRITE_REG, CH32X_REG16_LCR2_LCR, lcr, complete_cb ? ch34x_control_complete : NULL, user_data)); return true; @@ -1527,35 +1525,26 @@ static void ch34x_process_config(tuh_xfer_t* xfer) { TU_LOG_DRV("[%u] CDCh CH34x Chip Version = %02x\r\n", p_cdc->daddr, version); // only versions >= 0x30 are tested, below 0x30 seems having other programming, see drivers from WCH vendor, Linux kernel and FreeBSD TU_ASSERT (version >= 0x30,); - - #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM - cdc_line_coding_t const line_coding = CFG_TUH_CDC_LINE_CODING_ON_ENUM; - uint8_t const lcr = ch34x_get_lcr(line_coding.stop_bits, line_coding.parity, line_coding.data_bits); - uint16_t const first_arg = tu_u16(lcr, 0x9c); + // init CH34x with line coding + cdc_line_coding_t const line_coding = CFG_TUH_CDC_LINE_CODING_ON_ENUM_CH34X; uint16_t const div_ps = ch34x_get_divisor_prescaler(line_coding.bit_rate); TU_ASSERT(div_ps != 0, ); - #else - uint16_t const first_arg = 0; - uint16_t const div_ps = 0; - #endif - - // Init CH34x with line coding - TU_ASSERT (ch34x_control_out(p_cdc, CH34X_REQ_SERIAL_INIT, first_arg, div_ps, + uint8_t const lcr = ch34x_get_lcr(line_coding.stop_bits, line_coding.parity, line_coding.data_bits); + TU_ASSERT(lcr != 0, ); + TU_ASSERT (ch34x_control_out(p_cdc, CH34X_REQ_SERIAL_INIT, tu_u16(lcr, 0x9c), div_ps, ch34x_process_config, CONFIG_CH34X_SPECIAL_REG_WRITE),); break; } case CONFIG_CH34X_SPECIAL_REG_WRITE: - // do special reg write, purpose unknown, overtaken from WCH driver - #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM - p_cdc->line_coding = ((cdc_line_coding_t) CFG_TUH_CDC_LINE_CODING_ON_ENUM); - #endif - TU_ASSERT (ch34x_write_reg(p_cdc, 0x0f2c, 0x0007, ch34x_process_config, CONFIG_CH34X_FLOW_CONTROL),); + // overtake line coding and do special reg write, purpose unknown, overtaken from WCH driver + p_cdc->line_coding = ((cdc_line_coding_t) CFG_TUH_CDC_LINE_CODING_ON_ENUM_CH34X); + TU_ASSERT (ch34x_write_reg(p_cdc, TU_U16(CH341_REG_0x0F, CH341_REG_0x2C), 0x0007, ch34x_process_config, CONFIG_CH34X_FLOW_CONTROL),); break; case CONFIG_CH34X_FLOW_CONTROL: // no hardware flow control - TU_ASSERT (ch34x_write_reg(p_cdc, 0x2727, 0x0000, ch34x_process_config, CONFIG_CH34X_MODEM_CONTROL),); + TU_ASSERT (ch34x_write_reg(p_cdc, TU_U16(CH341_REG_0x27, CH341_REG_0x27), 0x0000, ch34x_process_config, CONFIG_CH34X_MODEM_CONTROL),); break; case CONFIG_CH34X_MODEM_CONTROL: @@ -1581,6 +1570,7 @@ static uint16_t ch34x_get_divisor_prescaler(uint32_t baval) { uint8_t b; uint32_t c; + TU_VERIFY(baval != 0, 0); switch (baval) { case 921600: a = 0xf3; @@ -1606,7 +1596,7 @@ static uint16_t ch34x_get_divisor_prescaler(uint32_t baval) { b = 0; c = 11719; } - a = (unsigned char) (c / baval); + a = (uint8_t) (c / baval); if (a == 0 || a == 0xFF) { return 0; } @@ -1620,29 +1610,33 @@ static uint16_t ch34x_get_divisor_prescaler(uint32_t baval) { // reg divisor = a, reg prescaler = b // According to linux code we need to set bit 7 of UCHCOM_REG_BPS_PRE, // otherwise the chip will buffer data. - return (uint16_t) (a << 8 | 0x80 | b); + return (uint16_t) ((uint16_t)a << 8 | 0x80 | b); } // calculate lcr value from data coding static uint8_t ch34x_get_lcr(uint8_t stop_bits, uint8_t parity, uint8_t data_bits) { uint8_t lcr = CH34X_LCR_ENABLE_RX | CH34X_LCR_ENABLE_TX; - TU_VERIFY(data_bits >= 5, 0); + TU_VERIFY(data_bits >= 5 && data_bits <= 8, 0); lcr |= (uint8_t) (data_bits - 5); - if (parity) { - lcr |= CH34X_LCR_ENABLE_PAR; - } switch(parity) { + case CDC_LINE_CODING_PARITY_NONE: + break; + + case CDC_LINE_CODING_PARITY_ODD: + lcr |= CH34X_LCR_ENABLE_PAR; + break; + case CDC_LINE_CODING_PARITY_EVEN: - lcr |= CH34X_LCR_PAR_EVEN; + lcr |= CH34X_LCR_ENABLE_PAR | CH34X_LCR_PAR_EVEN; break; case CDC_LINE_CODING_PARITY_MARK: - lcr |= CH34X_LCR_MARK_SPACE; + lcr |= CH34X_LCR_ENABLE_PAR | CH34X_LCR_MARK_SPACE; break; case CDC_LINE_CODING_PARITY_SPACE: - lcr |= CH34X_LCR_MARK_SPACE | CH34X_LCR_PAR_EVEN; + lcr |= CH34X_LCR_ENABLE_PAR | CH34X_LCR_MARK_SPACE | CH34X_LCR_PAR_EVEN; break; default: break; diff --git a/src/class/cdc/serial/ch34x.h b/src/class/cdc/serial/ch34x.h index b9121afb3..c18066f57 100644 --- a/src/class/cdc/serial/ch34x.h +++ b/src/class/cdc/serial/ch34x.h @@ -32,6 +32,13 @@ // - https://github.com/torvalds/linux/blob/master/drivers/usb/serial/ch341.c // - https://github.com/freebsd/freebsd-src/blob/main/sys/dev/usb/serial/uchcom.c +// set line_coding @ enumeration +#ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM +#define CFG_TUH_CDC_LINE_CODING_ON_ENUM_CH34X CFG_TUH_CDC_LINE_CODING_ON_ENUM +#else // this default is necessary to work properly +#define CFG_TUH_CDC_LINE_CODING_ON_ENUM_CH34X { 9600, CDC_LINE_CONDING_STOP_BITS_1, CDC_LINE_CODING_PARITY_NONE, 8 } +#endif + // USB requests #define CH34X_REQ_READ_VERSION 0x5F // dec 95 #define CH34X_REQ_WRITE_REG 0x9A // dec 154 -- cgit v1.3.1 From af3c6be79fe9a9829f30831bd7525d2a22cb5529 Mon Sep 17 00:00:00 2001 From: Jonathan Zentgraf Date: Sat, 20 Jan 2024 20:16:54 -0500 Subject: msc_device: Fix check for including MSC lookup tables The _msc_scsi_cmd_lookup and _msc_scsi_cmd_table variables are needed when logging is enabled for the MSC device via CFG_TUD_MSC_LOG_LEVEL. Update the preprocessor check around them to use that definition when deciding whether to define those variables. Closes #2419 --- src/class/msc/msc_device.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/class') diff --git a/src/class/msc/msc_device.c b/src/class/msc/msc_device.c index 2589dcd2c..c145d86a6 100644 --- a/src/class/msc/msc_device.c +++ b/src/class/msc/msc_device.c @@ -203,7 +203,7 @@ uint8_t rdwr10_validate_cmd(msc_cbw_t const* cbw) //--------------------------------------------------------------------+ // Debug //--------------------------------------------------------------------+ -#if CFG_TUSB_DEBUG >= 2 +#if CFG_TUSB_DEBUG >= CFG_TUD_MSC_LOG_LEVEL TU_ATTR_UNUSED tu_static tu_lookup_entry_t const _msc_scsi_cmd_lookup[] = { -- cgit v1.3.1 From 1c9a839401cb7323f93202f600c6f3148100e10a Mon Sep 17 00:00:00 2001 From: Jerzy Kasenberg Date: Tue, 23 Jan 2024 13:48:09 +0100 Subject: audio_device: Fix unused variable warning In some configurations local variable p_desc_parse_for_params is declared and never used resulting in warning that can be escalated to build error (for mynewt) Now variable is surrounded with same preprocessor condition as function that uses it audiod_parse_for_AS_params() --- src/class/audio/audio_device.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/class') diff --git a/src/class/audio/audio_device.c b/src/class/audio/audio_device.c index d438d0715..4adc558a6 100644 --- a/src/class/audio/audio_device.c +++ b/src/class/audio/audio_device.c @@ -1729,7 +1729,7 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const * // Find correct interface if (tu_desc_type(p_desc) == TUSB_DESC_INTERFACE && ((tusb_desc_interface_t const * )p_desc)->bInterfaceNumber == itf && ((tusb_desc_interface_t const * )p_desc)->bAlternateSetting == alt) { -#if CFG_TUD_AUDIO_ENABLE_ENCODING || CFG_TUD_AUDIO_ENABLE_DECODING || CFG_TUD_AUDIO_EP_IN_FLOW_CONTROL +#if (CFG_TUD_AUDIO_ENABLE_EP_IN && (CFG_TUD_AUDIO_EP_IN_FLOW_CONTROL || CFG_TUD_AUDIO_ENABLE_ENCODING)) || (CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_DECODING) uint8_t const * p_desc_parse_for_params = p_desc; #endif // From this point forward follow the EP descriptors associated to the current alternate setting interface - Open EPs if necessary -- cgit v1.3.1 From 0b8b8af83dfac97caa7c41f9d5c8c1a3af1b9ac1 Mon Sep 17 00:00:00 2001 From: hathach Date: Thu, 25 Jan 2024 17:25:48 +0700 Subject: minor update to video capture example --- examples/device/video_capture/src/main.c | 15 +- examples/device/video_capture/src/tusb_config.h | 2 +- .../device/video_capture/src/usb_descriptors.h | 69 +++------ src/class/video/video_device.c | 6 +- src/common/tusb_types.h | 154 ++++++++------------- 5 files changed, 92 insertions(+), 154 deletions(-) (limited to 'src/class') diff --git a/examples/device/video_capture/src/main.c b/examples/device/video_capture/src/main.c index 7b180dd6b..e63335e67 100644 --- a/examples/device/video_capture/src/main.c +++ b/examples/device/video_capture/src/main.c @@ -131,8 +131,7 @@ static struct { static uint8_t frame_buffer[FRAME_WIDTH * FRAME_HEIGHT * 16 / 8]; static void fill_color_bar(uint8_t* buffer, unsigned start_position) { - /* EBU color bars - * See also https://stackoverflow.com/questions/6939422 */ + /* EBU color bars: https://stackoverflow.com/questions/6939422 */ static uint8_t const bar_color[8][4] = { /* Y, U, Y, V */ { 235, 128, 235, 128}, /* 100% White */ @@ -184,12 +183,12 @@ void video_task(void) { already_sent = 1; start_ms = board_millis(); #ifdef CFG_EXAMPLE_VIDEO_READONLY -# if defined(CFG_EXAMPLE_VIDEO_DISABLE_MJPEG) + #if defined(CFG_EXAMPLE_VIDEO_DISABLE_MJPEG) tud_video_n_frame_xfer(0, 0, (void*)(uintptr_t)&frame_buffer[(frame_num % (FRAME_WIDTH / 2)) * 4], FRAME_WIDTH * FRAME_HEIGHT * 16/8); -# else + #else tud_video_n_frame_xfer(0, 0, (void*)(uintptr_t)frames[frame_num % 8].buffer, frames[frame_num % 8].size); -# endif + #endif #else fill_color_bar(frame_buffer, frame_num); tud_video_n_frame_xfer(0, 0, (void*) frame_buffer, FRAME_WIDTH * FRAME_HEIGHT * 16 / 8); @@ -202,12 +201,12 @@ void video_task(void) { start_ms += interval_ms; #ifdef CFG_EXAMPLE_VIDEO_READONLY -# if defined(CFG_EXAMPLE_VIDEO_DISABLE_MJPEG) + #if defined(CFG_EXAMPLE_VIDEO_DISABLE_MJPEG) tud_video_n_frame_xfer(0, 0, (void*)(uintptr_t)&frame_buffer[(frame_num % (FRAME_WIDTH / 2)) * 4], FRAME_WIDTH * FRAME_HEIGHT * 16/8); -# else + #else tud_video_n_frame_xfer(0, 0, (void*)(uintptr_t)frames[frame_num % 8].buffer, frames[frame_num % 8].size); -# endif + #endif #else fill_color_bar(frame_buffer, frame_num); tud_video_n_frame_xfer(0, 0, (void*) frame_buffer, FRAME_WIDTH * FRAME_HEIGHT * 16 / 8); diff --git a/examples/device/video_capture/src/tusb_config.h b/examples/device/video_capture/src/tusb_config.h index 8440b47ef..d563c6f5c 100644 --- a/examples/device/video_capture/src/tusb_config.h +++ b/examples/device/video_capture/src/tusb_config.h @@ -97,7 +97,7 @@ // The number of video streaming interfaces #define CFG_TUD_VIDEO_STREAMING 1 -// video streaming endpoint size +// video streaming endpoint buffer size #define CFG_TUD_VIDEO_STREAMING_EP_BUFSIZE 256 // use bulk endpoint for streaming interface diff --git a/examples/device/video_capture/src/usb_descriptors.h b/examples/device/video_capture/src/usb_descriptors.h index b924c8dbe..fa3c1fbd2 100644 --- a/examples/device/video_capture/src/usb_descriptors.h +++ b/examples/device/video_capture/src/usb_descriptors.h @@ -126,23 +126,17 @@ enum { #define TUD_VIDEO_CAPTURE_DESCRIPTOR_UNCOMPR(_stridx, _epin, _width, _height, _fps, _epsize) \ TUD_VIDEO_DESC_IAD(ITF_NUM_VIDEO_CONTROL, /* 2 Interfaces */ 0x02, _stridx), \ /* Video control 0 */ \ - TUD_VIDEO_DESC_STD_VC(ITF_NUM_VIDEO_CONTROL, 0, _stridx), \ - TUD_VIDEO_DESC_CS_VC( /* UVC 1.5*/ 0x0150, \ - /* wTotalLength - bLength */ \ - TUD_VIDEO_DESC_CAMERA_TERM_LEN + TUD_VIDEO_DESC_OUTPUT_TERM_LEN, \ - UVC_CLOCK_FREQUENCY, ITF_NUM_VIDEO_STREAMING), \ - TUD_VIDEO_DESC_CAMERA_TERM(UVC_ENTITY_CAP_INPUT_TERMINAL, 0, 0,\ - /*wObjectiveFocalLengthMin*/0, /*wObjectiveFocalLengthMax*/0,\ - /*wObjectiveFocalLength*/0, /*bmControls*/0), \ + TUD_VIDEO_DESC_STD_VC(ITF_NUM_VIDEO_CONTROL, 0, _stridx), \ + /* Header: UVC 1.5, length of followed descs, clock (deprecated), streaming interfaces */ \ + TUD_VIDEO_DESC_CS_VC(0x0150, TUD_VIDEO_DESC_CAMERA_TERM_LEN + TUD_VIDEO_DESC_OUTPUT_TERM_LEN, UVC_CLOCK_FREQUENCY, ITF_NUM_VIDEO_STREAMING), \ + /* Camera Terminal: ID, bAssocTerminal, iTerminal, focal min, max, length, bmControl */ \ + TUD_VIDEO_DESC_CAMERA_TERM(UVC_ENTITY_CAP_INPUT_TERMINAL, 0, 0, 0, 0, 0, 0), \ TUD_VIDEO_DESC_OUTPUT_TERM(UVC_ENTITY_CAP_OUTPUT_TERMINAL, VIDEO_TT_STREAMING, 0, 1, 0), \ /* Video stream alt. 0 */ \ TUD_VIDEO_DESC_STD_VS(ITF_NUM_VIDEO_STREAMING, 0, 0, _stridx), \ /* Video stream header for without still image capture */ \ TUD_VIDEO_DESC_CS_VS_INPUT( /*bNumFormats*/1, \ - /*wTotalLength - bLength */\ - TUD_VIDEO_DESC_CS_VS_FMT_UNCOMPR_LEN\ - + TUD_VIDEO_DESC_CS_VS_FRM_UNCOMPR_CONT_LEN\ - + TUD_VIDEO_DESC_CS_VS_COLOR_MATCHING_LEN,\ + /*wTotalLength - bLength */ TUD_VIDEO_DESC_CS_VS_FMT_UNCOMPR_LEN + TUD_VIDEO_DESC_CS_VS_FRM_UNCOMPR_CONT_LEN + TUD_VIDEO_DESC_CS_VS_COLOR_MATCHING_LEN,\ _epin, /*bmInfo*/0, /*bTerminalLink*/UVC_ENTITY_CAP_OUTPUT_TERMINAL, \ /*bStillCaptureMethod*/0, /*bTriggerSupport*/0, /*bTriggerUsage*/0, \ /*bmaControls(1)*/0), \ @@ -163,23 +157,17 @@ enum { #define TUD_VIDEO_CAPTURE_DESCRIPTOR_MJPEG(_stridx, _epin, _width, _height, _fps, _epsize) \ TUD_VIDEO_DESC_IAD(ITF_NUM_VIDEO_CONTROL, /* 2 Interfaces */ 0x02, _stridx), \ /* Video control 0 */ \ - TUD_VIDEO_DESC_STD_VC(ITF_NUM_VIDEO_CONTROL, 0, _stridx), \ - TUD_VIDEO_DESC_CS_VC( /* UVC 1.5*/ 0x0150, \ - /* wTotalLength - bLength */ \ - TUD_VIDEO_DESC_CAMERA_TERM_LEN + TUD_VIDEO_DESC_OUTPUT_TERM_LEN, \ - UVC_CLOCK_FREQUENCY, ITF_NUM_VIDEO_STREAMING), \ - TUD_VIDEO_DESC_CAMERA_TERM(UVC_ENTITY_CAP_INPUT_TERMINAL, 0, 0,\ - /*wObjectiveFocalLengthMin*/0, /*wObjectiveFocalLengthMax*/0,\ - /*wObjectiveFocalLength*/0, /*bmControls*/0), \ + TUD_VIDEO_DESC_STD_VC(ITF_NUM_VIDEO_CONTROL, 0, _stridx), \ + /* Header: UVC 1.5, length of followed descs, clock (deprecated), streaming interfaces */ \ + TUD_VIDEO_DESC_CS_VC(0x0150, TUD_VIDEO_DESC_CAMERA_TERM_LEN + TUD_VIDEO_DESC_OUTPUT_TERM_LEN, UVC_CLOCK_FREQUENCY, ITF_NUM_VIDEO_STREAMING), \ + /* Camera Terminal: ID, bAssocTerminal, iTerminal, focal min, max, length, bmControl */ \ + TUD_VIDEO_DESC_CAMERA_TERM(UVC_ENTITY_CAP_INPUT_TERMINAL, 0, 0, 0, 0, 0, 0), \ TUD_VIDEO_DESC_OUTPUT_TERM(UVC_ENTITY_CAP_OUTPUT_TERMINAL, VIDEO_TT_STREAMING, 0, 1, 0), \ /* Video stream alt. 0 */ \ TUD_VIDEO_DESC_STD_VS(ITF_NUM_VIDEO_STREAMING, 0, 0, _stridx), \ /* Video stream header for without still image capture */ \ TUD_VIDEO_DESC_CS_VS_INPUT( /*bNumFormats*/1, \ - /*wTotalLength - bLength */\ - TUD_VIDEO_DESC_CS_VS_FMT_MJPEG_LEN\ - + TUD_VIDEO_DESC_CS_VS_FRM_MJPEG_CONT_LEN\ - + TUD_VIDEO_DESC_CS_VS_COLOR_MATCHING_LEN,\ + /*wTotalLength - bLength */ TUD_VIDEO_DESC_CS_VS_FMT_MJPEG_LEN + TUD_VIDEO_DESC_CS_VS_FRM_MJPEG_CONT_LEN + TUD_VIDEO_DESC_CS_VS_COLOR_MATCHING_LEN,\ _epin, /*bmInfo*/0, /*bTerminalLink*/UVC_ENTITY_CAP_OUTPUT_TERMINAL, \ /*bStillCaptureMethod*/0, /*bTriggerSupport*/0, /*bTriggerUsage*/0, \ /*bmaControls(1)*/0), \ @@ -202,22 +190,17 @@ enum { TUD_VIDEO_DESC_IAD(ITF_NUM_VIDEO_CONTROL, /* 2 Interfaces */ 0x02, _stridx), \ /* Video control 0 */ \ TUD_VIDEO_DESC_STD_VC(ITF_NUM_VIDEO_CONTROL, 0, _stridx), \ - TUD_VIDEO_DESC_CS_VC( /* UVC 1.5*/ 0x0150, \ - /* wTotalLength - bLength */ \ - TUD_VIDEO_DESC_CAMERA_TERM_LEN + TUD_VIDEO_DESC_OUTPUT_TERM_LEN, \ - UVC_CLOCK_FREQUENCY, ITF_NUM_VIDEO_STREAMING), \ - TUD_VIDEO_DESC_CAMERA_TERM(UVC_ENTITY_CAP_INPUT_TERMINAL, 0, 0,\ - /*wObjectiveFocalLengthMin*/0, /*wObjectiveFocalLengthMax*/0,\ - /*wObjectiveFocalLength*/0, /*bmControls*/0), \ + /* Header: UVC 1.5, length of followed descs, clock (deprecated), streaming interfaces */ \ + TUD_VIDEO_DESC_CS_VC(0x0150, TUD_VIDEO_DESC_CAMERA_TERM_LEN + TUD_VIDEO_DESC_OUTPUT_TERM_LEN, UVC_CLOCK_FREQUENCY, ITF_NUM_VIDEO_STREAMING), \ + /* Camera Terminal: ID, bAssocTerminal, iTerminal, focal min, max, length, bmControl */ \ + TUD_VIDEO_DESC_CAMERA_TERM(UVC_ENTITY_CAP_INPUT_TERMINAL, 0, 0, 0, 0, 0, 0), \ TUD_VIDEO_DESC_OUTPUT_TERM(UVC_ENTITY_CAP_OUTPUT_TERMINAL, VIDEO_TT_STREAMING, 0, 1, 0), \ /* Video stream alt. 0 */ \ TUD_VIDEO_DESC_STD_VS(ITF_NUM_VIDEO_STREAMING, 0, 1, _stridx), \ /* Video stream header for without still image capture */ \ TUD_VIDEO_DESC_CS_VS_INPUT( /*bNumFormats*/1, \ /*wTotalLength - bLength */\ - TUD_VIDEO_DESC_CS_VS_FMT_UNCOMPR_LEN\ - + TUD_VIDEO_DESC_CS_VS_FRM_UNCOMPR_CONT_LEN\ - + TUD_VIDEO_DESC_CS_VS_COLOR_MATCHING_LEN,\ + TUD_VIDEO_DESC_CS_VS_FMT_UNCOMPR_LEN + TUD_VIDEO_DESC_CS_VS_FRM_UNCOMPR_CONT_LEN + TUD_VIDEO_DESC_CS_VS_COLOR_MATCHING_LEN,\ _epin, /*bmInfo*/0, /*bTerminalLink*/UVC_ENTITY_CAP_OUTPUT_TERMINAL, \ /*bStillCaptureMethod*/0, /*bTriggerSupport*/0, /*bTriggerUsage*/0, \ /*bmaControls(1)*/0), \ @@ -235,23 +218,17 @@ enum { #define TUD_VIDEO_CAPTURE_DESCRIPTOR_MJPEG_BULK(_stridx, _epin, _width, _height, _fps, _epsize) \ TUD_VIDEO_DESC_IAD(ITF_NUM_VIDEO_CONTROL, /* 2 Interfaces */ 0x02, _stridx), \ /* Video control 0 */ \ - TUD_VIDEO_DESC_STD_VC(ITF_NUM_VIDEO_CONTROL, 0, _stridx), \ - TUD_VIDEO_DESC_CS_VC( /* UVC 1.5*/ 0x0150, \ - /* wTotalLength - bLength */ \ - TUD_VIDEO_DESC_CAMERA_TERM_LEN + TUD_VIDEO_DESC_OUTPUT_TERM_LEN, \ - UVC_CLOCK_FREQUENCY, ITF_NUM_VIDEO_STREAMING), \ - TUD_VIDEO_DESC_CAMERA_TERM(UVC_ENTITY_CAP_INPUT_TERMINAL, 0, 0,\ - /*wObjectiveFocalLengthMin*/0, /*wObjectiveFocalLengthMax*/0,\ - /*wObjectiveFocalLength*/0, /*bmControls*/0), \ + TUD_VIDEO_DESC_STD_VC(ITF_NUM_VIDEO_CONTROL, 0, _stridx), \ + /* Header: UVC 1.5, length of followed descs, clock (deprecated), streaming interfaces */ \ + TUD_VIDEO_DESC_CS_VC(0x0150, TUD_VIDEO_DESC_CAMERA_TERM_LEN + TUD_VIDEO_DESC_OUTPUT_TERM_LEN, UVC_CLOCK_FREQUENCY, ITF_NUM_VIDEO_STREAMING), \ + /* Camera Terminal: ID, bAssocTerminal, iTerminal, focal min, max, length, bmControl */ \ + TUD_VIDEO_DESC_CAMERA_TERM(UVC_ENTITY_CAP_INPUT_TERMINAL, 0, 0, 0, 0, 0, 0), \ TUD_VIDEO_DESC_OUTPUT_TERM(UVC_ENTITY_CAP_OUTPUT_TERMINAL, VIDEO_TT_STREAMING, 0, 1, 0), \ /* Video stream alt. 0 */ \ TUD_VIDEO_DESC_STD_VS(ITF_NUM_VIDEO_STREAMING, 0, 1, _stridx), \ /* Video stream header for without still image capture */ \ TUD_VIDEO_DESC_CS_VS_INPUT( /*bNumFormats*/1, \ - /*wTotalLength - bLength */\ - TUD_VIDEO_DESC_CS_VS_FMT_MJPEG_LEN\ - + TUD_VIDEO_DESC_CS_VS_FRM_MJPEG_CONT_LEN\ - + TUD_VIDEO_DESC_CS_VS_COLOR_MATCHING_LEN,\ + /*wTotalLength - bLength */ TUD_VIDEO_DESC_CS_VS_FMT_MJPEG_LEN + TUD_VIDEO_DESC_CS_VS_FRM_MJPEG_CONT_LEN + TUD_VIDEO_DESC_CS_VS_COLOR_MATCHING_LEN,\ _epin, /*bmInfo*/0, /*bTerminalLink*/UVC_ENTITY_CAP_OUTPUT_TERMINAL, \ /*bStillCaptureMethod*/0, /*bTriggerSupport*/0, /*bTriggerUsage*/0, \ /*bmaControls(1)*/0), \ diff --git a/src/class/video/video_device.c b/src/class/video/video_device.c index 3b29454a3..c16a45fcd 100644 --- a/src/class/video/video_device.c +++ b/src/class/video/video_device.c @@ -434,8 +434,9 @@ static bool _update_streaming_parameters(videod_streaming_interface_t const *stm uint_fast32_t interval_ms = interval / 10000; TU_ASSERT(interval_ms); uint_fast32_t payload_size = (frame_size + interval_ms - 1) / interval_ms + 2; - if (CFG_TUD_VIDEO_STREAMING_EP_BUFSIZE < payload_size) + if (CFG_TUD_VIDEO_STREAMING_EP_BUFSIZE < payload_size) { payload_size = CFG_TUD_VIDEO_STREAMING_EP_BUFSIZE; + } param->dwMaxPayloadTransferSize = payload_size; return true; } @@ -577,8 +578,9 @@ static bool _negotiate_streaming_parameters(videod_streaming_interface_t const * } else { payload_size = (frame_size + interval_ms - 1) / interval_ms + 2; } - if (CFG_TUD_VIDEO_STREAMING_EP_BUFSIZE < payload_size) + if (CFG_TUD_VIDEO_STREAMING_EP_BUFSIZE < payload_size) { payload_size = CFG_TUD_VIDEO_STREAMING_EP_BUFSIZE; + } param->dwMaxPayloadTransferSize = payload_size; } return true; diff --git a/src/common/tusb_types.h b/src/common/tusb_types.h index fab680989..d4ef1fd09 100644 --- a/src/common/tusb_types.h +++ b/src/common/tusb_types.h @@ -44,43 +44,38 @@ *------------------------------------------------------------------*/ /// defined base on EHCI specs value for Endpoint Speed -typedef enum -{ +typedef enum { TUSB_SPEED_FULL = 0, TUSB_SPEED_LOW = 1, TUSB_SPEED_HIGH = 2, TUSB_SPEED_INVALID = 0xff, -}tusb_speed_t; +} tusb_speed_t; /// defined base on USB Specs Endpoint's bmAttributes -typedef enum -{ +typedef enum { TUSB_XFER_CONTROL = 0 , TUSB_XFER_ISOCHRONOUS , TUSB_XFER_BULK , TUSB_XFER_INTERRUPT -}tusb_xfer_type_t; +} tusb_xfer_type_t; -typedef enum -{ +typedef enum { TUSB_DIR_OUT = 0, TUSB_DIR_IN = 1, TUSB_DIR_IN_MASK = 0x80 -}tusb_dir_t; +} tusb_dir_t; -enum -{ +enum { TUSB_EPSIZE_BULK_FS = 64, - TUSB_EPSIZE_BULK_HS= 512, + TUSB_EPSIZE_BULK_HS = 512, TUSB_EPSIZE_ISO_FS_MAX = 1023, TUSB_EPSIZE_ISO_HS_MAX = 1024, }; -/// Isochronous End Point Attributes -typedef enum -{ +/// Isochronous Endpoint Attributes +typedef enum { TUSB_ISO_EP_ATT_NO_SYNC = 0x00, TUSB_ISO_EP_ATT_ASYNCHRONOUS = 0x04, TUSB_ISO_EP_ATT_ADAPTIVE = 0x08, @@ -88,11 +83,10 @@ typedef enum TUSB_ISO_EP_ATT_DATA = 0x00, ///< Data End Point TUSB_ISO_EP_ATT_EXPLICIT_FB = 0x10, ///< Feedback End Point TUSB_ISO_EP_ATT_IMPLICIT_FB = 0x20, ///< Data endpoint that also serves as an implicit feedback -}tusb_iso_ep_attribute_t; +} tusb_iso_ep_attribute_t; /// USB Descriptor Types -typedef enum -{ +typedef enum { TUSB_DESC_DEVICE = 0x01, TUSB_DESC_CONFIGURATION = 0x02, TUSB_DESC_STRING = 0x03, @@ -119,10 +113,9 @@ typedef enum TUSB_DESC_SUPERSPEED_ENDPOINT_COMPANION = 0x30, TUSB_DESC_SUPERSPEED_ISO_ENDPOINT_COMPANION = 0x31 -}tusb_desc_type_t; +} tusb_desc_type_t; -typedef enum -{ +typedef enum { TUSB_REQ_GET_STATUS = 0 , TUSB_REQ_CLEAR_FEATURE = 1 , TUSB_REQ_RESERVED = 2 , @@ -136,25 +129,22 @@ typedef enum TUSB_REQ_GET_INTERFACE = 10 , TUSB_REQ_SET_INTERFACE = 11 , TUSB_REQ_SYNCH_FRAME = 12 -}tusb_request_code_t; +} tusb_request_code_t; -typedef enum -{ +typedef enum { TUSB_REQ_FEATURE_EDPT_HALT = 0, TUSB_REQ_FEATURE_REMOTE_WAKEUP = 1, TUSB_REQ_FEATURE_TEST_MODE = 2 -}tusb_request_feature_selector_t; +} tusb_request_feature_selector_t; -typedef enum -{ +typedef enum { TUSB_REQ_TYPE_STANDARD = 0, TUSB_REQ_TYPE_CLASS, TUSB_REQ_TYPE_VENDOR, TUSB_REQ_TYPE_INVALID } tusb_request_type_t; -typedef enum -{ +typedef enum { TUSB_REQ_RCPT_DEVICE =0, TUSB_REQ_RCPT_INTERFACE, TUSB_REQ_RCPT_ENDPOINT, @@ -162,8 +152,7 @@ typedef enum } tusb_request_recipient_t; // https://www.usb.org/defined-class-codes -typedef enum -{ +typedef enum { TUSB_CLASS_UNSPECIFIED = 0 , TUSB_CLASS_AUDIO = 1 , TUSB_CLASS_CDC = 2 , @@ -187,26 +176,23 @@ typedef enum TUSB_CLASS_MISC = 0xEF , TUSB_CLASS_APPLICATION_SPECIFIC = 0xFE , TUSB_CLASS_VENDOR_SPECIFIC = 0xFF -}tusb_class_code_t; +} tusb_class_code_t; typedef enum { MISC_SUBCLASS_COMMON = 2 }misc_subclass_type_t; -typedef enum -{ +typedef enum { MISC_PROTOCOL_IAD = 1 -}misc_protocol_type_t; +} misc_protocol_type_t; -typedef enum -{ +typedef enum { APP_SUBCLASS_USBTMC = 0x03, APP_SUBCLASS_DFU_RUNTIME = 0x01 } app_subclass_type_t; -typedef enum -{ +typedef enum { DEVICE_CAPABILITY_WIRELESS_USB = 0x01, DEVICE_CAPABILITY_USB20_EXTENSION = 0x02, DEVICE_CAPABILITY_SUPERSPEED_USB = 0x03, @@ -223,7 +209,7 @@ typedef enum DEVICE_CAPABILITY_AUTHENTICATION = 0x0E, DEVICE_CAPABILITY_BILLBOARD_EX = 0x0F, DEVICE_CAPABILITY_CONFIGURATION_SUMMARY = 0x10 -}device_capability_type_t; +} device_capability_type_t; enum { TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP = TU_BIT(5), @@ -235,28 +221,25 @@ enum { //--------------------------------------------------------------------+ // //--------------------------------------------------------------------+ -typedef enum -{ +typedef enum { XFER_RESULT_SUCCESS = 0, XFER_RESULT_FAILED, XFER_RESULT_STALLED, XFER_RESULT_TIMEOUT, XFER_RESULT_INVALID -}xfer_result_t; +} xfer_result_t; -enum // TODO remove -{ +// TODO remove +enum { DESC_OFFSET_LEN = 0, DESC_OFFSET_TYPE = 1 }; -enum -{ +enum { INTERFACE_INVALID_NUMBER = 0xff }; -typedef enum -{ +typedef enum { MS_OS_20_SET_HEADER_DESCRIPTOR = 0x00, MS_OS_20_SUBSET_HEADER_CONFIGURATION = 0x01, MS_OS_20_SUBSET_HEADER_FUNCTION = 0x02, @@ -268,16 +251,14 @@ typedef enum MS_OS_20_FEATURE_VENDOR_REVISION = 0x08 } microsoft_os_20_type_t; -enum -{ +enum { CONTROL_STAGE_IDLE, CONTROL_STAGE_SETUP, CONTROL_STAGE_DATA, CONTROL_STAGE_ACK }; -enum -{ +enum { TUSB_INDEX_INVALID_8 = 0xFFu }; @@ -290,8 +271,7 @@ TU_ATTR_PACKED_BEGIN TU_ATTR_BIT_FIELD_ORDER_BEGIN /// USB Device Descriptor -typedef struct TU_ATTR_PACKED -{ +typedef struct TU_ATTR_PACKED { uint8_t bLength ; ///< Size of this descriptor in bytes. uint8_t bDescriptorType ; ///< DEVICE Descriptor Type. uint16_t bcdUSB ; ///< BUSB Specification Release Number in Binary-Coded Decimal (i.e., 2.10 is 210H). This field identifies the release of the USB Specification with which the device and its descriptors are compliant. @@ -314,8 +294,7 @@ typedef struct TU_ATTR_PACKED TU_VERIFY_STATIC( sizeof(tusb_desc_device_t) == 18, "size is not correct"); // USB Binary Device Object Store (BOS) Descriptor -typedef struct TU_ATTR_PACKED -{ +typedef struct TU_ATTR_PACKED { uint8_t bLength ; ///< Size of this descriptor in bytes uint8_t bDescriptorType ; ///< CONFIGURATION Descriptor Type uint16_t wTotalLength ; ///< Total length of data returned for this descriptor @@ -325,8 +304,7 @@ typedef struct TU_ATTR_PACKED TU_VERIFY_STATIC( sizeof(tusb_desc_bos_t) == 5, "size is not correct"); /// USB Configuration Descriptor -typedef struct TU_ATTR_PACKED -{ +typedef struct TU_ATTR_PACKED { uint8_t bLength ; ///< Size of this descriptor in bytes uint8_t bDescriptorType ; ///< CONFIGURATION Descriptor Type uint16_t wTotalLength ; ///< Total length of data returned for this configuration. Includes the combined length of all descriptors (configuration, interface, endpoint, and class- or vendor-specific) returned for this configuration. @@ -341,8 +319,7 @@ typedef struct TU_ATTR_PACKED TU_VERIFY_STATIC( sizeof(tusb_desc_configuration_t) == 9, "size is not correct"); /// USB Interface Descriptor -typedef struct TU_ATTR_PACKED -{ +typedef struct TU_ATTR_PACKED { uint8_t bLength ; ///< Size of this descriptor in bytes uint8_t bDescriptorType ; ///< INTERFACE Descriptor Type @@ -358,8 +335,7 @@ typedef struct TU_ATTR_PACKED TU_VERIFY_STATIC( sizeof(tusb_desc_interface_t) == 9, "size is not correct"); /// USB Endpoint Descriptor -typedef struct TU_ATTR_PACKED -{ +typedef struct TU_ATTR_PACKED { uint8_t bLength ; // Size of this descriptor in bytes uint8_t bDescriptorType ; // ENDPOINT Descriptor Type @@ -379,8 +355,7 @@ typedef struct TU_ATTR_PACKED TU_VERIFY_STATIC( sizeof(tusb_desc_endpoint_t) == 7, "size is not correct"); /// USB Other Speed Configuration Descriptor -typedef struct TU_ATTR_PACKED -{ +typedef struct TU_ATTR_PACKED { uint8_t bLength ; ///< Size of descriptor uint8_t bDescriptorType ; ///< Other_speed_Configuration Type uint16_t wTotalLength ; ///< Total length of data returned @@ -393,8 +368,7 @@ typedef struct TU_ATTR_PACKED } tusb_desc_other_speed_t; /// USB Device Qualifier Descriptor -typedef struct TU_ATTR_PACKED -{ +typedef struct TU_ATTR_PACKED { uint8_t bLength ; ///< Size of descriptor uint8_t bDescriptorType ; ///< Device Qualifier Type uint16_t bcdUSB ; ///< USB specification version number (e.g., 0200H for V2.00) @@ -411,8 +385,7 @@ typedef struct TU_ATTR_PACKED TU_VERIFY_STATIC( sizeof(tusb_desc_device_qualifier_t) == 10, "size is not correct"); /// USB Interface Association Descriptor (IAD ECN) -typedef struct TU_ATTR_PACKED -{ +typedef struct TU_ATTR_PACKED { uint8_t bLength ; ///< Size of descriptor uint8_t bDescriptorType ; ///< Other_speed_Configuration Type @@ -427,16 +400,14 @@ typedef struct TU_ATTR_PACKED } tusb_desc_interface_assoc_t; // USB String Descriptor -typedef struct TU_ATTR_PACKED -{ +typedef struct TU_ATTR_PACKED { uint8_t bLength ; ///< Size of this descriptor in bytes uint8_t bDescriptorType ; ///< Descriptor Type uint16_t unicode_string[]; } tusb_desc_string_t; // USB Binary Device Object Store (BOS) -typedef struct TU_ATTR_PACKED -{ +typedef struct TU_ATTR_PACKED { uint8_t bLength; uint8_t bDescriptorType ; uint8_t bDevCapabilityType; @@ -445,9 +416,8 @@ typedef struct TU_ATTR_PACKED uint8_t CapabilityData[]; } tusb_desc_bos_platform_t; -// USB WebuSB URL Descriptor -typedef struct TU_ATTR_PACKED -{ +// USB WebUSB URL Descriptor +typedef struct TU_ATTR_PACKED { uint8_t bLength; uint8_t bDescriptorType; uint8_t bScheme; @@ -455,8 +425,7 @@ typedef struct TU_ATTR_PACKED } tusb_desc_webusb_url_t; // DFU Functional Descriptor -typedef struct TU_ATTR_PACKED -{ +typedef struct TU_ATTR_PACKED { uint8_t bLength; uint8_t bDescriptorType; @@ -481,7 +450,7 @@ typedef struct TU_ATTR_PACKED // //--------------------------------------------------------------------+ -typedef struct TU_ATTR_PACKED{ +typedef struct TU_ATTR_PACKED { union { struct TU_ATTR_PACKED { uint8_t recipient : 5; ///< Recipient type tusb_request_recipient_t. @@ -509,36 +478,30 @@ TU_ATTR_BIT_FIELD_ORDER_END //--------------------------------------------------------------------+ // Get direction from Endpoint address -TU_ATTR_ALWAYS_INLINE static inline tusb_dir_t tu_edpt_dir(uint8_t addr) -{ +TU_ATTR_ALWAYS_INLINE static inline tusb_dir_t tu_edpt_dir(uint8_t addr) { return (addr & TUSB_DIR_IN_MASK) ? TUSB_DIR_IN : TUSB_DIR_OUT; } // Get Endpoint number from address -TU_ATTR_ALWAYS_INLINE static inline uint8_t tu_edpt_number(uint8_t addr) -{ +TU_ATTR_ALWAYS_INLINE static inline uint8_t tu_edpt_number(uint8_t addr) { return (uint8_t)(addr & (~TUSB_DIR_IN_MASK)); } -TU_ATTR_ALWAYS_INLINE static inline uint8_t tu_edpt_addr(uint8_t num, uint8_t dir) -{ +TU_ATTR_ALWAYS_INLINE static inline uint8_t tu_edpt_addr(uint8_t num, uint8_t dir) { return (uint8_t)(num | (dir ? TUSB_DIR_IN_MASK : 0)); } -TU_ATTR_ALWAYS_INLINE static inline uint16_t tu_edpt_packet_size(tusb_desc_endpoint_t const* desc_ep) -{ +TU_ATTR_ALWAYS_INLINE static inline uint16_t tu_edpt_packet_size(tusb_desc_endpoint_t const* desc_ep) { return tu_le16toh(desc_ep->wMaxPacketSize) & TU_GENMASK(10, 0); } #if CFG_TUSB_DEBUG -TU_ATTR_ALWAYS_INLINE static inline const char *tu_edpt_dir_str(tusb_dir_t dir) -{ +TU_ATTR_ALWAYS_INLINE static inline const char *tu_edpt_dir_str(tusb_dir_t dir) { tu_static const char *str[] = {"out", "in"}; return str[dir]; } -TU_ATTR_ALWAYS_INLINE static inline const char *tu_edpt_type_str(tusb_xfer_type_t t) -{ +TU_ATTR_ALWAYS_INLINE static inline const char *tu_edpt_type_str(tusb_xfer_type_t t) { tu_static const char *str[] = {"control", "isochronous", "bulk", "interrupt"}; return str[t]; } @@ -549,21 +512,18 @@ TU_ATTR_ALWAYS_INLINE static inline const char *tu_edpt_type_str(tusb_xfer_type_ //--------------------------------------------------------------------+ // return next descriptor -TU_ATTR_ALWAYS_INLINE static inline uint8_t const * tu_desc_next(void const* desc) -{ +TU_ATTR_ALWAYS_INLINE static inline uint8_t const * tu_desc_next(void const* desc) { uint8_t const* desc8 = (uint8_t const*) desc; return desc8 + desc8[DESC_OFFSET_LEN]; } // get descriptor type -TU_ATTR_ALWAYS_INLINE static inline uint8_t tu_desc_type(void const* desc) -{ +TU_ATTR_ALWAYS_INLINE static inline uint8_t tu_desc_type(void const* desc) { return ((uint8_t const*) desc)[DESC_OFFSET_TYPE]; } // get descriptor length -TU_ATTR_ALWAYS_INLINE static inline uint8_t tu_desc_len(void const* desc) -{ +TU_ATTR_ALWAYS_INLINE static inline uint8_t tu_desc_len(void const* desc) { return ((uint8_t const*) desc)[DESC_OFFSET_LEN]; } -- cgit v1.3.1 From a7de4ac9b7a2dfb1fa44921fb0f41f249c8cdd5e Mon Sep 17 00:00:00 2001 From: YixingShen Date: Fri, 26 Jan 2024 02:37:15 +0800 Subject: Correct VIDEO_CS_VS_INTERFACE_FRAME_MJPEG to VIDEO_CS_ITF_VS_FRAME_MJPEG for #define TUD_VIDEO_DESC_CS_VS_FRM_MJPEG_DISC --- src/class/video/video.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/class') diff --git a/src/class/video/video.h b/src/class/video/video.h index d9880c291..268e219e2 100644 --- a/src/class/video/video.h +++ b/src/class/video/video.h @@ -537,7 +537,7 @@ TU_VERIFY_STATIC( sizeof(video_probe_and_commit_control_t) == 48, "size is not c /* Motion-JPEG 3.1.1 Table 3-2 and 3-4 */ #define TUD_VIDEO_DESC_CS_VS_FRM_MJPEG_DISC(_frmidx, _cap, _width, _height, _minbr, _maxbr, _maxfrmbufsz, _frminterval, ...) \ TUD_VIDEO_DESC_CS_VS_FRM_MJPEG_DISC_LEN + (TU_ARGS_NUM(__VA_ARGS__)) * 4, \ - TUSB_DESC_CS_INTERFACE, VIDEO_CS_VS_INTERFACE_FRAME_MJPEG, \ + TUSB_DESC_CS_INTERFACE, VIDEO_CS_ITF_VS_FRAME_MJPEG, \ _frmidx, _cap, U16_TO_U8S_LE(_width), U16_TO_U8S_LE(_height), U32_TO_U8S_LE(_minbr), U32_TO_U8S_LE(_maxbr), \ U32_TO_U8S_LE(_maxfrmbufsz), U32_TO_U8S_LE(_frminterval), (TU_ARGS_NUM(__VA_ARGS__)), __VA_ARGS__ -- cgit v1.3.1 From b5cd673330fc87f2981ecf139b24940df5cb3cfe Mon Sep 17 00:00:00 2001 From: hathach Date: Fri, 26 Jan 2024 22:55:55 +0700 Subject: rename and add more video descriptors use struct to define uvc descriptor for video_capture since uvc is rather too complicated to use macro templates --- .../device/video_capture/src/usb_descriptors.c | 233 +++++++++++++++++++-- .../device/video_capture/src/usb_descriptors.h | 4 +- src/class/video/video.h | 224 ++++++++++++++------ src/class/video/video_device.c | 20 +- src/common/tusb_types.h | 3 +- 5 files changed, 389 insertions(+), 95 deletions(-) (limited to 'src/class') diff --git a/examples/device/video_capture/src/usb_descriptors.c b/examples/device/video_capture/src/usb_descriptors.c index d38f158c8..8e54d3afd 100644 --- a/examples/device/video_capture/src/usb_descriptors.c +++ b/examples/device/video_capture/src/usb_descriptors.c @@ -40,6 +40,26 @@ #define USB_VID 0xCafe #define USB_BCD 0x0200 +// String Descriptor Index +enum { + STRID_LANGID = 0, + STRID_MANUFACTURER, + STRID_PRODUCT, + STRID_SERIAL, + STRID_UVC_CONTROL, + STRID_UVC_STREAMING, +}; + +// array of pointer to string descriptors +char const* string_desc_arr[] = { + (const char[]) {0x09, 0x04}, // 0: is supported language is English (0x0409) + "TinyUSB", // 1: Manufacturer + "TinyUSB Device", // 2: Product + NULL, // 3: Serials will use unique ID if possible + "TinyUSB UVC Control", // 4: UVC Interface + "TinyUSB UVC Streaming", // 5: UVC Interface +}; + //--------------------------------------------------------------------+ // Device Descriptors //--------------------------------------------------------------------+ @@ -60,9 +80,9 @@ tusb_desc_device_t const desc_device = { .idProduct = USB_PID, .bcdDevice = 0x0100, - .iManufacturer = 0x01, - .iProduct = 0x02, - .iSerialNumber = 0x03, + .iManufacturer = STRID_MANUFACTURER, + .iProduct = STRID_PRODUCT, + .iSerialNumber = STRID_SERIAL, .bNumConfigurations = 0x01 }; @@ -164,6 +184,193 @@ uint8_t const* tud_descriptor_other_speed_configuration_cb(uint8_t index) { } #endif // highspeed +typedef struct TU_ATTR_PACKED { + tusb_desc_interface_t itf; + tusb_desc_video_control_header_1itf_t header; + tusb_desc_video_control_camera_terminal_t camera_terminal; + tusb_desc_video_control_output_terminal_t output_terminal; +} uvc_control_desc_t; + +/* Windows support YUY2 and NV12 + * https://docs.microsoft.com/en-us/windows-hardware/drivers/stream/usb-video-class-driver-overview */ + +typedef struct TU_ATTR_PACKED { + tusb_desc_interface_t itf; + tusb_desc_video_streaming_input_header_1byte_t header; + tusb_desc_video_format_uncompressed_t format; + tusb_desc_video_frame_uncompressed_continuous_t frame; + tusb_desc_video_streaming_color_matching_t color; + tusb_desc_endpoint_t ep; +} uvc_streaming_desc_t; + +typedef struct TU_ATTR_PACKED { + tusb_desc_configuration_t config; + tusb_desc_interface_assoc_t iad; + uvc_control_desc_t video_control; + uvc_streaming_desc_t video_streaming; +} uvc_cfg_desc_t; + +const uvc_cfg_desc_t config_desc = { + .config = { + .bLength = sizeof(tusb_desc_configuration_t), + .bDescriptorType = TUSB_DESC_CONFIGURATION, + + .wTotalLength = sizeof(uvc_cfg_desc_t), + .bNumInterfaces = ITF_NUM_TOTAL, + .bConfigurationValue = 1, + .iConfiguration = 0, + .bmAttributes = TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, + .bMaxPower = 100 / 2 + }, + .iad = { + .bLength = sizeof(tusb_desc_interface_assoc_t), + .bDescriptorType = TUSB_DESC_INTERFACE_ASSOCIATION, + + .bFirstInterface = ITF_NUM_VIDEO_CONTROL, + .bInterfaceCount = 2, + .bFunctionClass = TUSB_CLASS_VIDEO, + .bFunctionSubClass = VIDEO_SUBCLASS_INTERFACE_COLLECTION, + .bFunctionProtocol = VIDEO_ITF_PROTOCOL_UNDEFINED, + .iFunction = 0 + }, + + .video_control = { + .itf = { + .bLength = sizeof(tusb_desc_interface_t), + .bDescriptorType = TUSB_DESC_INTERFACE, + + .bInterfaceNumber = ITF_NUM_VIDEO_CONTROL, + .bAlternateSetting = 0, + .bNumEndpoints = 0, + .bInterfaceClass = TUSB_CLASS_VIDEO, + .bInterfaceSubClass = VIDEO_SUBCLASS_CONTROL, + .bInterfaceProtocol = VIDEO_ITF_PROTOCOL_15, + .iInterface = STRID_UVC_CONTROL + }, + .header = { + .bLength = sizeof(tusb_desc_video_control_header_1itf_t), + .bDescriptorType = TUSB_DESC_CS_INTERFACE, + .bDescriptorSubType = VIDEO_CS_ITF_VC_HEADER, + + .bcdUVC = VIDEO_BCD_1_50, + .wTotalLength = sizeof(uvc_control_desc_t) - sizeof(tusb_desc_interface_t), // CS VC descriptors only + .dwClockFrequency = UVC_CLOCK_FREQUENCY, + .bInCollection = 1, + .baInterfaceNr = { ITF_NUM_VIDEO_STREAMING } + }, + .camera_terminal = { + .bLength = sizeof(tusb_desc_video_control_camera_terminal_t), + .bDescriptorType = TUSB_DESC_CS_INTERFACE, + .bDescriptorSubType = VIDEO_CS_ITF_VC_INPUT_TERMINAL, + + .bTerminalID = UVC_ENTITY_CAP_INPUT_TERMINAL, + .wTerminalType = VIDEO_ITT_CAMERA, + .bAssocTerminal = 0, + .iTerminal = 0, + .wObjectiveFocalLengthMin = 0, + .wObjectiveFocalLengthMax = 0, + .wOcularFocalLength = 0, + .bControlSize = 3, + .bmControls = { 0, 0, 0 } + }, + .output_terminal = { + .bLength = sizeof(tusb_desc_video_control_output_terminal_t), + .bDescriptorType = TUSB_DESC_CS_INTERFACE, + .bDescriptorSubType = VIDEO_CS_ITF_VC_OUTPUT_TERMINAL, + + .bTerminalID = UVC_ENTITY_CAP_OUTPUT_TERMINAL, + .wTerminalType = VIDEO_TT_STREAMING, + .bAssocTerminal = 0, + .bSourceID = UVC_ENTITY_CAP_INPUT_TERMINAL, + .iTerminal = 0 + } + }, + + .video_streaming = { + .itf = { + .bLength = sizeof(tusb_desc_interface_t), + .bDescriptorType = TUSB_DESC_INTERFACE, + + .bInterfaceNumber = ITF_NUM_VIDEO_STREAMING, + .bAlternateSetting = 0, + .bNumEndpoints = 1, + .bInterfaceClass = TUSB_CLASS_VIDEO, + .bInterfaceSubClass = VIDEO_SUBCLASS_STREAMING, + .bInterfaceProtocol = VIDEO_ITF_PROTOCOL_15, + .iInterface = STRID_UVC_STREAMING + }, + .header = { + .bLength = sizeof(tusb_desc_video_streaming_input_header_1byte_t), + .bDescriptorType = TUSB_DESC_CS_INTERFACE, + .bDescriptorSubType = VIDEO_CS_ITF_VS_INPUT_HEADER, + + .bNumFormats = 1, + .wTotalLength = sizeof(uvc_streaming_desc_t) - sizeof(tusb_desc_interface_t) - sizeof(tusb_desc_endpoint_t), // CS VS descriptors only + .bEndpointAddress = EPNUM_VIDEO_IN, + .bmInfo = 0, + .bTerminalLink = UVC_ENTITY_CAP_OUTPUT_TERMINAL, + .bStillCaptureMethod = 0, + .bTriggerSupport = 0, + .bTriggerUsage = 0, + .bControlSize = 1, + .bmaControls = { 0 } + }, + .format = { + .bLength = sizeof(tusb_desc_video_format_uncompressed_t), + .bDescriptorType = TUSB_DESC_CS_INTERFACE, + .bDescriptorSubType = VIDEO_CS_ITF_VS_FORMAT_UNCOMPRESSED, + + .bFormatIndex = 1, // 1-based index + .bNumFrameDescriptors = 1, + .guidFormat = { TUD_VIDEO_GUID_YUY2 }, + .bBitsPerPixel = 16, + .bDefaultFrameIndex = 1, + .bAspectRatioX = 0, + .bAspectRatioY = 0, + .bmInterlaceFlags = 0, + .bCopyProtect = 0 + }, + .frame = { + .bLength = sizeof(tusb_desc_video_frame_uncompressed_continuous_t), + .bDescriptorType = TUSB_DESC_CS_INTERFACE, + .bDescriptorSubType = VIDEO_CS_ITF_VS_FRAME_UNCOMPRESSED, + + .bFrameIndex = 1, // 1-based index + .bmCapabilities = 0, + .wWidth = FRAME_WIDTH, + .wHeight = FRAME_HEIGHT, + .dwMinBitRate = FRAME_WIDTH * FRAME_HEIGHT * 16 * 1, + .dwMaxBitRate = FRAME_WIDTH * FRAME_HEIGHT * 16 * FRAME_RATE, + .dwMaxVideoFrameBufferSize = FRAME_WIDTH * FRAME_HEIGHT * 16 / 8, + .dwDefaultFrameInterval = 10000000 / FRAME_RATE, + .bFrameIntervalType = 0, // continuous + .dwFrameInterval = { + 10000000 / FRAME_RATE, // min + 10000000, // max + 10000000 / FRAME_RATE // step + } + }, + .color = { + .bLength = sizeof(tusb_desc_video_streaming_color_matching_t), + .bDescriptorType = TUSB_DESC_CS_INTERFACE, + .bDescriptorSubType = VIDEO_CS_ITF_VS_COLORFORMAT, + + .bColorPrimaries = VIDEO_COLOR_PRIMARIES_BT709, + .bTransferCharacteristics = VIDEO_COLOR_XFER_CH_BT709, + .bMatrixCoefficients = VIDEO_COLOR_COEF_SMPTE170M + }, + .ep = { + .bLength = sizeof(tusb_desc_endpoint_t), + .bDescriptorType = TUSB_DESC_ENDPOINT, + + .bEndpointAddress = EPNUM_VIDEO_IN, + .bmAttributes = { .xfer = TUSB_XFER_BULK }, + .wMaxPacketSize = CFG_TUD_VIDEO_STREAMING_BULK ? 64 : CFG_TUD_VIDEO_STREAMING_EP_BUFSIZE, + .bInterval = 1 + } + } +}; + // Invoked when received GET CONFIGURATION DESCRIPTOR // Application return pointer to descriptor // Descriptor contents must exist long enough for transfer to complete @@ -174,7 +381,8 @@ uint8_t const* tud_descriptor_configuration_cb(uint8_t index) { // Although we are highspeed, host may be fullspeed. return (tud_speed_get() == TUSB_SPEED_HIGH) ? desc_hs_configuration : desc_fs_configuration; #else - return desc_fs_configuration; +// return desc_fs_configuration; + return (uint8_t const*) &config_desc; #endif } @@ -182,23 +390,6 @@ uint8_t const* tud_descriptor_configuration_cb(uint8_t index) { // String Descriptors //--------------------------------------------------------------------+ -// String Descriptor Index -enum { - STRID_LANGID = 0, - STRID_MANUFACTURER, - STRID_PRODUCT, - STRID_SERIAL, -}; - -// array of pointer to string descriptors -char const* string_desc_arr[] = { - (const char[]) {0x09, 0x04}, // 0: is supported language is English (0x0409) - "TinyUSB", // 1: Manufacturer - "TinyUSB Device", // 2: Product - NULL, // 3: Serials will use unique ID if possible - "TinyUSB UVC", // 4: UVC Interface -}; - static uint16_t _desc_str[32 + 1]; // Invoked when received GET STRING DESCRIPTOR request diff --git a/examples/device/video_capture/src/usb_descriptors.h b/examples/device/video_capture/src/usb_descriptors.h index fa3c1fbd2..fd908c9c2 100644 --- a/examples/device/video_capture/src/usb_descriptors.h +++ b/examples/device/video_capture/src/usb_descriptors.h @@ -210,7 +210,7 @@ enum { /* Video stream frame format */ \ TUD_VIDEO_DESC_CS_VS_FRM_UNCOMPR_CONT(/*bFrameIndex */1, 0, _width, _height, \ _width * _height * 16, _width * _height * 16 * _fps, \ - _width * _height * 16, \ + _width * _height * 16 / 8, \ (10000000/_fps), (10000000/_fps), (10000000/_fps)*_fps, (10000000/_fps)), \ TUD_VIDEO_DESC_CS_VS_COLOR_MATCHING(VIDEO_COLOR_PRIMARIES_BT709, VIDEO_COLOR_XFER_CH_BT709, VIDEO_COLOR_COEF_SMPTE170M), \ TUD_VIDEO_DESC_EP_BULK(_epin, _epsize, 1) @@ -223,7 +223,7 @@ enum { TUD_VIDEO_DESC_CS_VC(0x0150, TUD_VIDEO_DESC_CAMERA_TERM_LEN + TUD_VIDEO_DESC_OUTPUT_TERM_LEN, UVC_CLOCK_FREQUENCY, ITF_NUM_VIDEO_STREAMING), \ /* Camera Terminal: ID, bAssocTerminal, iTerminal, focal min, max, length, bmControl */ \ TUD_VIDEO_DESC_CAMERA_TERM(UVC_ENTITY_CAP_INPUT_TERMINAL, 0, 0, 0, 0, 0, 0), \ - TUD_VIDEO_DESC_OUTPUT_TERM(UVC_ENTITY_CAP_OUTPUT_TERMINAL, VIDEO_TT_STREAMING, 0, 1, 0), \ + TUD_VIDEO_DESC_OUTPUT_TERM(UVC_ENTITY_CAP_OUTPUT_TERMINAL, VIDEO_TT_STREAMING, 0, UVC_ENTITY_CAP_INPUT_TERMINAL, 0), \ /* Video stream alt. 0 */ \ TUD_VIDEO_DESC_STD_VS(ITF_NUM_VIDEO_STREAMING, 0, 1, _stridx), \ /* Video stream header for without still image capture */ \ diff --git a/src/class/video/video.h b/src/class/video/video.h index d9880c291..162d4e4c4 100644 --- a/src/class/video/video.h +++ b/src/class/video/video.h @@ -29,6 +29,10 @@ #include "common/tusb_common.h" +enum { + VIDEO_BCD_1_50 = 0x0150, +}; + // Table 3-19 Color Matching Descriptor typedef enum { VIDEO_COLOR_PRIMARIES_UNDEFINED = 0x00, @@ -198,55 +202,98 @@ typedef enum { } video_terminal_type_t; //--------------------------------------------------------------------+ -// Descriptors +// Video Control (VC) Descriptors //--------------------------------------------------------------------+ /* 2.3.4.2 */ +#define tusb_desc_video_control_header_nitf_t(_nitf) \ + struct TU_ATTR_PACKED { \ + uint8_t bLength; \ + uint8_t bDescriptorType; \ + uint8_t bDescriptorSubType; \ + uint16_t bcdUVC; \ + uint16_t wTotalLength; \ + uint32_t dwClockFrequency; /* deprecated */ \ + uint8_t bInCollection; \ + uint8_t baInterfaceNr[_nitf]; \ + } + +typedef tusb_desc_video_control_header_nitf_t() tusb_desc_video_control_header_t; +typedef tusb_desc_video_control_header_nitf_t(1) tusb_desc_video_control_header_1itf_t; +typedef tusb_desc_video_control_header_nitf_t(2) tusb_desc_video_control_header_2itf_t; +typedef tusb_desc_video_control_header_nitf_t(3) tusb_desc_video_control_header_3itf_t; +typedef tusb_desc_video_control_header_nitf_t(4) tusb_desc_video_control_header_4itf_t; + typedef struct TU_ATTR_PACKED { uint8_t bLength; uint8_t bDescriptorType; uint8_t bDescriptorSubType; - uint16_t bcdUVC; - uint16_t wTotalLength; - uint32_t dwClockFrequency; - uint8_t bInCollection; - uint8_t baInterfaceNr[]; -} tusb_desc_cs_video_ctl_itf_hdr_t; + uint8_t bTerminalID; + uint16_t wTerminalType; + uint8_t bAssocTerminal; + uint8_t iTerminal; +} tusb_desc_video_control_input_terminal_t; + +TU_VERIFY_STATIC(sizeof(tusb_desc_video_control_input_terminal_t) == 8, "size is not correct"); -/* 2.4.3.3 */ typedef struct TU_ATTR_PACKED { - uint8_t bHeaderLength; - union { - uint8_t bmHeaderInfo; - struct { - uint8_t FrameID: 1; - uint8_t EndOfFrame: 1; - uint8_t PresentationTime: 1; - uint8_t SourceClockReference: 1; - uint8_t PayloadSpecific: 1; - uint8_t StillImage: 1; - uint8_t Error: 1; - uint8_t EndOfHeader: 1; - }; - }; -} tusb_video_payload_header_t; + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bDescriptorSubType; + uint8_t bTerminalID; + uint16_t wTerminalType; + uint8_t bAssocTerminal; + uint8_t bSourceID; + uint8_t iTerminal; +} tusb_desc_video_control_output_terminal_t; + +TU_VERIFY_STATIC(sizeof(tusb_desc_video_control_output_terminal_t) == 9, "size is not correct"); -/* 3.9.2.1 */ typedef struct TU_ATTR_PACKED { uint8_t bLength; uint8_t bDescriptorType; uint8_t bDescriptorSubType; - uint8_t bNumFormats; - uint16_t wTotalLength; - uint8_t bEndpointAddress; - uint8_t bmInfo; - uint8_t bTerminalLink; - uint8_t bStillCaptureMethod; - uint8_t bTriggerSupport; - uint8_t bTriggerUsage; + uint8_t bTerminalID; + uint16_t wTerminalType; + uint8_t bAssocTerminal; + uint8_t iTerminal; + + uint16_t wObjectiveFocalLengthMin; + uint16_t wObjectiveFocalLengthMax; + uint16_t wOcularFocalLength; uint8_t bControlSize; - uint8_t bmaControls[]; -} tusb_desc_cs_video_stm_itf_in_hdr_t; + uint8_t bmControls[3]; +} tusb_desc_video_control_camera_terminal_t; + +TU_VERIFY_STATIC(sizeof(tusb_desc_video_control_camera_terminal_t) == 18, "size is not correct"); + +//--------------------------------------------------------------------+ +// Video Streaming (VS) Descriptors +//--------------------------------------------------------------------+ + +/* 3.9.2.1 */ +#define tusb_desc_video_streaming_input_header_nbyte_t(_nb) \ + struct TU_ATTR_PACKED { \ + uint8_t bLength; \ + uint8_t bDescriptorType; \ + uint8_t bDescriptorSubType; \ + uint8_t bNumFormats; /* Number of video payload Format descriptors for this interface */ \ + uint16_t wTotalLength; \ + uint8_t bEndpointAddress; \ + uint8_t bmInfo; /* Bit 0: dynamic format change supported */ \ + uint8_t bTerminalLink; \ + uint8_t bStillCaptureMethod; \ + uint8_t bTriggerSupport; /* Hardware trigger supported */ \ + uint8_t bTriggerUsage; \ + uint8_t bControlSize; /* sizeof of each control item */ \ + uint8_t bmaControls[_nb]; \ + } + +typedef tusb_desc_video_streaming_input_header_nbyte_t() tusb_desc_video_streaming_input_header_t; +typedef tusb_desc_video_streaming_input_header_nbyte_t(1) tusb_desc_video_streaming_input_header_1byte_t; +typedef tusb_desc_video_streaming_input_header_nbyte_t(2) tusb_desc_video_streaming_input_header_2byte_t; +typedef tusb_desc_video_streaming_input_header_nbyte_t(3) tusb_desc_video_streaming_input_header_3byte_t; +typedef tusb_desc_video_streaming_input_header_nbyte_t(4) tusb_desc_video_streaming_input_header_4byte_t; /* 3.9.2.2 */ typedef struct TU_ATTR_PACKED { @@ -259,7 +306,7 @@ typedef struct TU_ATTR_PACKED { uint8_t bTerminalLink; uint8_t bControlSize; uint8_t bmaControls[]; -} tusb_desc_cs_video_stm_itf_out_hdr_t; +} tusb_desc_video_streaming_output_header_t; typedef struct TU_ATTR_PACKED { uint8_t bLength; @@ -285,14 +332,33 @@ typedef struct TU_ATTR_PACKED { uint8_t bmaControls[]; } output; }; -} tusb_desc_cs_video_stm_itf_hdr_t; +} tusb_desc_video_streaming_inout_header_t; +// 3.9.2.6 Color Matching Descriptor +typedef struct TU_ATTR_PACKED { + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bDescriptorSubType; + uint8_t bColorPrimaries; + uint8_t bTransferCharacteristics; + uint8_t bMatrixCoefficients; +} tusb_desc_video_streaming_color_matching_t; + +TU_VERIFY_STATIC(sizeof(tusb_desc_video_streaming_color_matching_t) == 6, "size is not correct"); + +//--------------------------------------------------------------------+ +// Format and Frame Descriptor +// Note: bFormatIndex & bFrameIndex are 1-based index +//--------------------------------------------------------------------+ + +//------------- Uncompressed -------------// +// Uncompressed payload specs: 3.1.1 format descriptor typedef struct TU_ATTR_PACKED { uint8_t bLength; uint8_t bDescriptorType; uint8_t bDescriptorSubType; uint8_t bFormatIndex; - uint8_t bNumFrameDescriptors; + uint8_t bNumFrameDescriptors; // Number of frame descriptors for this format uint8_t guidFormat[16]; uint8_t bBitsPerPixel; uint8_t bDefaultFrameIndex; @@ -300,8 +366,39 @@ typedef struct TU_ATTR_PACKED { uint8_t bAspectRatioY; uint8_t bmInterlaceFlags; uint8_t bCopyProtect; -} tusb_desc_cs_video_fmt_uncompressed_t; - +} tusb_desc_video_format_uncompressed_t; + +// Uncompressed payload specs: 3.1.2 frame descriptor +#define tusb_desc_video_frame_uncompressed_nint_t(_nint) \ + struct TU_ATTR_PACKED { \ + uint8_t bLength; \ + uint8_t bDescriptorType; \ + uint8_t bDescriptorSubType; \ + uint8_t bFrameIndex; \ + uint8_t bmCapabilities; \ + uint16_t wWidth; \ + uint16_t wHeight; \ + uint32_t dwMinBitRate; \ + uint32_t dwMaxBitRate; \ + uint32_t dwMaxVideoFrameBufferSize; /* deprecated in 1.5 */ \ + uint32_t dwDefaultFrameInterval; \ + uint8_t bFrameIntervalType; \ + uint32_t dwFrameInterval[_nint]; \ + } + +typedef tusb_desc_video_frame_uncompressed_nint_t() tusb_desc_video_frame_uncompressed_t; +typedef tusb_desc_video_frame_uncompressed_nint_t(1) tusb_desc_video_frame_uncompressed_1int_t; +typedef tusb_desc_video_frame_uncompressed_nint_t(2) tusb_desc_video_frame_uncompressed_2int_t; +typedef tusb_desc_video_frame_uncompressed_nint_t(3) tusb_desc_video_frame_uncompressed_3int_t; +typedef tusb_desc_video_frame_uncompressed_nint_t(4) tusb_desc_video_frame_uncompressed_4int_t; + +// continuous = 3 intervals: min, max, step +typedef tusb_desc_video_frame_uncompressed_3int_t tusb_desc_video_frame_uncompressed_continuous_t; + +TU_VERIFY_STATIC(sizeof(tusb_desc_video_frame_uncompressed_continuous_t) == 38, "size is not correct"); + +//------------- MJPEG -------------// +// MJPEG payload specs: 3.1.1 formatt descriptor typedef struct TU_ATTR_PACKED { uint8_t bLength; uint8_t bDescriptorType; @@ -314,8 +411,12 @@ typedef struct TU_ATTR_PACKED { uint8_t bAspectRatioY; uint8_t bmInterlaceFlags; uint8_t bCopyProtect; -} tusb_desc_cs_video_fmt_mjpeg_t; +} tusb_desc_video_format_mjpeg_t; +// MJPEG payload specs: 3.1.2 frame descriptor (same as uncompressed) +typedef tusb_desc_video_frame_uncompressed_t tusb_desc_video_frame_mjpeg_t; + +// DV payload specs: 3.1.1 typedef struct TU_ATTR_PACKED { uint8_t bLength; uint8_t bDescriptorType; @@ -323,8 +424,9 @@ typedef struct TU_ATTR_PACKED { uint8_t bFormatIndex; uint32_t dwMaxVideoFrameBufferSize; /* deprecated */ uint8_t bFormatType; -} tusb_desc_cs_video_fmt_dv_t; +} tusb_desc_video_format_dv_t; +// Frame Based payload specs: 3.1.1 typedef struct TU_ATTR_PACKED { uint8_t bLength; uint8_t bDescriptorType; @@ -339,25 +441,7 @@ typedef struct TU_ATTR_PACKED { uint8_t bmInterlaceFlags; uint8_t bCopyProtect; uint8_t bVaribaleSize; -} tusb_desc_cs_video_fmt_frame_based_t; - -typedef struct TU_ATTR_PACKED { - uint8_t bLength; - uint8_t bDescriptorType; - uint8_t bDescriptorSubType; - uint8_t bFrameIndex; - uint8_t bmCapabilities; - uint16_t wWidth; - uint16_t wHeight; - uint32_t dwMinBitRate; - uint32_t dwMaxBitRate; - uint32_t dwMaxVideoFrameBufferSize; /* deprecated */ - uint32_t dwDefaultFrameInterval; - uint8_t bFrameIntervalType; - uint32_t dwFrameInterval[]; -} tusb_desc_cs_video_frm_uncompressed_t; - -typedef tusb_desc_cs_video_frm_uncompressed_t tusb_desc_cs_video_frm_mjpeg_t; +} tusb_desc_video_format_framebased_t; typedef struct TU_ATTR_PACKED { uint8_t bLength; @@ -373,12 +457,30 @@ typedef struct TU_ATTR_PACKED { uint8_t bFrameIntervalType; uint32_t dwBytesPerLine; uint32_t dwFrameInterval[]; -} tusb_desc_cs_video_frm_frame_based_t; +} tusb_desc_video_frame_framebased_t; //--------------------------------------------------------------------+ // Requests //--------------------------------------------------------------------+ +/* 2.4.3.3 */ +typedef struct TU_ATTR_PACKED { + uint8_t bHeaderLength; + union { + uint8_t bmHeaderInfo; + struct { + uint8_t FrameID: 1; + uint8_t EndOfFrame: 1; + uint8_t PresentationTime: 1; + uint8_t SourceClockReference: 1; + uint8_t PayloadSpecific: 1; + uint8_t StillImage: 1; + uint8_t Error: 1; + uint8_t EndOfHeader: 1; + }; + }; +} tusb_video_payload_header_t; + /* 4.3.1.1 */ typedef struct TU_ATTR_PACKED { union { diff --git a/src/class/video/video_device.c b/src/class/video/video_device.c index c16a45fcd..1affd615e 100644 --- a/src/class/video/video_device.c +++ b/src/class/video/video_device.c @@ -50,17 +50,17 @@ typedef struct { tusb_desc_interface_t std; - tusb_desc_cs_video_ctl_itf_hdr_t ctl; + tusb_desc_video_control_header_t ctl; } tusb_desc_vc_itf_t; typedef struct { tusb_desc_interface_t std; - tusb_desc_cs_video_stm_itf_hdr_t stm; + tusb_desc_video_streaming_inout_header_t stm; } tusb_desc_vs_itf_t; typedef union { - tusb_desc_cs_video_ctl_itf_hdr_t ctl; - tusb_desc_cs_video_stm_itf_hdr_t stm; + tusb_desc_video_control_header_t ctl; + tusb_desc_video_streaming_inout_header_t stm; } tusb_desc_video_itf_hdr_t; typedef struct TU_ATTR_PACKED { @@ -78,9 +78,9 @@ typedef union { uint8_t bFormatIndex; uint8_t bNumFrameDescriptors; }; - tusb_desc_cs_video_fmt_uncompressed_t uncompressed; - tusb_desc_cs_video_fmt_mjpeg_t mjpeg; - tusb_desc_cs_video_fmt_frame_based_t frame_based; + tusb_desc_video_format_uncompressed_t uncompressed; + tusb_desc_video_format_mjpeg_t mjpeg; + tusb_desc_video_format_framebased_t frame_based; } tusb_desc_cs_video_fmt_t; typedef union { @@ -93,9 +93,9 @@ typedef union { uint16_t wWidth; uint16_t wHeight; }; - tusb_desc_cs_video_frm_uncompressed_t uncompressed; - tusb_desc_cs_video_frm_mjpeg_t mjpeg; - tusb_desc_cs_video_frm_frame_based_t frame_based; + tusb_desc_video_frame_uncompressed_t uncompressed; + tusb_desc_video_frame_mjpeg_t mjpeg; + tusb_desc_video_frame_framebased_t frame_based; } tusb_desc_cs_video_frm_t; /* video streaming interface */ diff --git a/src/common/tusb_types.h b/src/common/tusb_types.h index d4ef1fd09..2c5dce723 100644 --- a/src/common/tusb_types.h +++ b/src/common/tusb_types.h @@ -399,6 +399,8 @@ typedef struct TU_ATTR_PACKED { uint8_t iFunction ; ///< Index of the string descriptor describing the interface association. } tusb_desc_interface_assoc_t; +TU_VERIFY_STATIC( sizeof(tusb_desc_interface_assoc_t) == 8, "size is not correct"); + // USB String Descriptor typedef struct TU_ATTR_PACKED { uint8_t bLength ; ///< Size of this descriptor in bytes @@ -469,7 +471,6 @@ typedef struct TU_ATTR_PACKED { TU_VERIFY_STATIC( sizeof(tusb_control_request_t) == 8, "size is not correct"); - TU_ATTR_PACKED_END // End of all packed definitions TU_ATTR_BIT_FIELD_ORDER_END -- cgit v1.3.1 From 0daf8ec51b9513fbab9601fedb2150dda3927b05 Mon Sep 17 00:00:00 2001 From: hathach Date: Fri, 26 Jan 2024 23:23:38 +0700 Subject: update example to work bulk mjpeg --- .../device/video_capture/src/usb_descriptors.c | 27 +++++++++++++++++++++- src/class/video/video.h | 10 +++++++- 2 files changed, 35 insertions(+), 2 deletions(-) (limited to 'src/class') diff --git a/examples/device/video_capture/src/usb_descriptors.c b/examples/device/video_capture/src/usb_descriptors.c index 8e54d3afd..90a6b27a2 100644 --- a/examples/device/video_capture/src/usb_descriptors.c +++ b/examples/device/video_capture/src/usb_descriptors.c @@ -109,6 +109,10 @@ uint8_t const* tud_descriptor_device_cb(void) { #define EPNUM_VIDEO_IN 0x81 #endif +#if defined(CFG_EXAMPLE_VIDEO_READONLY) && !defined(CFG_EXAMPLE_VIDEO_DISABLE_MJPEG) + #define USE_MJPEG +#endif + // For mcus that does not have enough SRAM for frame buffer, we use fixed frame data. // To further reduce the size, we use MJPEG format instead of YUY2. // Select interface descriptor and length accordingly. @@ -197,8 +201,15 @@ typedef struct TU_ATTR_PACKED { typedef struct TU_ATTR_PACKED { tusb_desc_interface_t itf; tusb_desc_video_streaming_input_header_1byte_t header; + +#ifdef USE_MJPEG + tusb_desc_video_format_mjpeg_t format; + tusb_desc_video_frame_mjpeg_continuous_t frame; +#else tusb_desc_video_format_uncompressed_t format; tusb_desc_video_frame_uncompressed_continuous_t frame; +#endif + tusb_desc_video_streaming_color_matching_t color; tusb_desc_endpoint_t ep; } uvc_streaming_desc_t; @@ -316,14 +327,22 @@ const uvc_cfg_desc_t config_desc = { .bmaControls = { 0 } }, .format = { +#ifdef USE_MJPEG + .bLength = sizeof(tusb_desc_video_format_mjpeg_t), + .bDescriptorType = TUSB_DESC_CS_INTERFACE, + .bDescriptorSubType = VIDEO_CS_ITF_VS_FORMAT_MJPEG, + .bFormatIndex = 1, // 1-based index + .bNumFrameDescriptors = 1, + .bmFlags = 0, +#else .bLength = sizeof(tusb_desc_video_format_uncompressed_t), .bDescriptorType = TUSB_DESC_CS_INTERFACE, .bDescriptorSubType = VIDEO_CS_ITF_VS_FORMAT_UNCOMPRESSED, - .bFormatIndex = 1, // 1-based index .bNumFrameDescriptors = 1, .guidFormat = { TUD_VIDEO_GUID_YUY2 }, .bBitsPerPixel = 16, +#endif .bDefaultFrameIndex = 1, .bAspectRatioX = 0, .bAspectRatioY = 0, @@ -331,9 +350,15 @@ const uvc_cfg_desc_t config_desc = { .bCopyProtect = 0 }, .frame = { +#ifdef USE_MJPEG + .bLength = sizeof(tusb_desc_video_frame_mjpeg_continuous_t), + .bDescriptorType = TUSB_DESC_CS_INTERFACE, + .bDescriptorSubType = VIDEO_CS_ITF_VS_FRAME_MJPEG, +#else .bLength = sizeof(tusb_desc_video_frame_uncompressed_continuous_t), .bDescriptorType = TUSB_DESC_CS_INTERFACE, .bDescriptorSubType = VIDEO_CS_ITF_VS_FRAME_UNCOMPRESSED, +#endif .bFrameIndex = 1, // 1-based index .bmCapabilities = 0, diff --git a/src/class/video/video.h b/src/class/video/video.h index 162d4e4c4..bed8eeecf 100644 --- a/src/class/video/video.h +++ b/src/class/video/video.h @@ -405,7 +405,7 @@ typedef struct TU_ATTR_PACKED { uint8_t bDescriptorSubType; uint8_t bFormatIndex; uint8_t bNumFrameDescriptors; - uint8_t bmFlags; + uint8_t bmFlags; // Bit 0: fixed size samples (1 = yes) uint8_t bDefaultFrameIndex; uint8_t bAspectRatioX; uint8_t bAspectRatioY; @@ -415,7 +415,15 @@ typedef struct TU_ATTR_PACKED { // MJPEG payload specs: 3.1.2 frame descriptor (same as uncompressed) typedef tusb_desc_video_frame_uncompressed_t tusb_desc_video_frame_mjpeg_t; +typedef tusb_desc_video_frame_uncompressed_1int_t tusb_desc_video_frame_mjpeg_1int_t; +typedef tusb_desc_video_frame_uncompressed_2int_t tusb_desc_video_frame_mjpeg_2int_t; +typedef tusb_desc_video_frame_uncompressed_3int_t tusb_desc_video_frame_mjpeg_3int_t; +typedef tusb_desc_video_frame_uncompressed_4int_t tusb_desc_video_frame_mjpeg_4int_t; +// continuous = 3 intervals: min, max, step +typedef tusb_desc_video_frame_mjpeg_3int_t tusb_desc_video_frame_mjpeg_continuous_t; + +//------------- DV -------------// // DV payload specs: 3.1.1 typedef struct TU_ATTR_PACKED { uint8_t bLength; -- cgit v1.3.1 From 82be2477e8201fe6ea61324b8995b79d1b4cab46 Mon Sep 17 00:00:00 2001 From: IngHK Date: Mon, 29 Jan 2024 12:04:00 +0100 Subject: fixed #2437 --- src/class/cdc/cdc_host.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'src/class') diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index 7adaa0c8c..36b5d4234 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -77,6 +77,8 @@ typedef struct { uint8_t rx_ff_buf[CFG_TUH_CDC_TX_BUFSIZE]; CFG_TUH_MEM_ALIGN uint8_t rx_ep_buf[CFG_TUH_CDC_TX_EPSIZE]; } stream; + + bool configured; } cdch_interface_t; CFG_TUH_MEM_SECTION @@ -257,6 +259,7 @@ static cdch_interface_t* make_new_itf(uint8_t daddr, tusb_desc_interface_t const p_cdc->bInterfaceSubClass = itf_desc->bInterfaceSubClass; p_cdc->bInterfaceProtocol = itf_desc->bInterfaceProtocol; p_cdc->line_state = 0; + p_cdc->configured = false; return p_cdc; } } @@ -305,7 +308,8 @@ bool tuh_cdc_itf_get_info(uint8_t idx, tuh_itf_info_t* info) { bool tuh_cdc_mounted(uint8_t idx) { cdch_interface_t* p_cdc = get_itf(idx); - return p_cdc != NULL; + TU_VERIFY(p_cdc); + return p_cdc->configured; } bool tuh_cdc_get_dtr(uint8_t idx) { @@ -747,6 +751,7 @@ bool cdch_open(uint8_t rhport, uint8_t daddr, tusb_desc_interface_t const *itf_d static void set_config_complete(cdch_interface_t * p_cdc, uint8_t idx, uint8_t itf_num) { TU_LOG_DRV("CDCh Set Configure complete\r\n"); + p_cdc->configured = true; if (tuh_cdc_mount_cb) tuh_cdc_mount_cb(idx); // Prepare for incoming data -- cgit v1.3.1 From 55950656cbee915662a9a33477ddd549489ffcf0 Mon Sep 17 00:00:00 2001 From: hathach Date: Mon, 29 Jan 2024 23:23:06 +0700 Subject: add freertos build support for video_capture example --- examples/device/video_capture/src/CMakeLists.txt | 4 + examples/device/video_capture/src/main.c | 131 ++++++++++++++++++--- examples/device/video_capture/src/tusb_config.h | 8 ++ .../device/video_capture/src/usb_descriptors.c | 29 +++-- hw/bsp/board_api.h | 19 ++- src/class/video/video.h | 2 +- 6 files changed, 170 insertions(+), 23 deletions(-) create mode 100644 examples/device/video_capture/src/CMakeLists.txt (limited to 'src/class') diff --git a/examples/device/video_capture/src/CMakeLists.txt b/examples/device/video_capture/src/CMakeLists.txt new file mode 100644 index 000000000..cef2b46ee --- /dev/null +++ b/examples/device/video_capture/src/CMakeLists.txt @@ -0,0 +1,4 @@ +# This file is for ESP-IDF only +idf_component_register(SRCS "main.c" "usb_descriptors.c" + INCLUDE_DIRS "." + REQUIRES boards tinyusb_src) diff --git a/examples/device/video_capture/src/main.c b/examples/device/video_capture/src/main.c index e63335e67..091eb8d0c 100644 --- a/examples/device/video_capture/src/main.c +++ b/examples/device/video_capture/src/main.c @@ -48,13 +48,25 @@ enum { static uint32_t blink_interval_ms = BLINK_NOT_MOUNTED; -void led_blinking_task(void); -void video_task(void); +void led_blinking_task(void* param); +void usb_device_task(void *param); +void video_task(void* param); -/*------------- MAIN -------------*/ +#if CFG_TUSB_OS == OPT_OS_FREERTOS +void freertos_init_task(void); +#endif + + +//--------------------------------------------------------------------+ +// Main +//--------------------------------------------------------------------+ int main(void) { board_init(); + // If using FreeRTOS: create blinky, tinyusb device, video task +#if CFG_TUSB_OS == OPT_OS_FREERTOS + freertos_init_task(); +#else // init device stack on configured roothub port tud_init(BOARD_TUD_RHPORT); @@ -64,10 +76,10 @@ int main(void) { while (1) { tud_task(); // tinyusb device task - led_blinking_task(); - - video_task(); + led_blinking_task(NULL); + video_task(NULL); } +#endif } //--------------------------------------------------------------------+ @@ -169,7 +181,7 @@ static void fill_color_bar(uint8_t* buffer, unsigned start_position) { #endif -void video_task(void) { +void video_send_frame(void) { static unsigned start_ms = 0; static unsigned already_sent = 0; @@ -213,6 +225,21 @@ void video_task(void) { #endif } + +void video_task(void* param) { + (void) param; + + while(1) { + video_send_frame(); + + #if CFG_TUSB_OS == OPT_OS_FREERTOS + vTaskDelay(interval_ms / portTICK_PERIOD_MS); + #else + return; + #endif + } +} + void tud_video_frame_xfer_complete_cb(uint_fast8_t ctl_idx, uint_fast8_t stm_idx) { (void) ctl_idx; (void) stm_idx; @@ -231,16 +258,92 @@ int tud_video_commit_cb(uint_fast8_t ctl_idx, uint_fast8_t stm_idx, } //--------------------------------------------------------------------+ -// BLINKING TASK +// Blinking Task //--------------------------------------------------------------------+ -void led_blinking_task(void) { +void led_blinking_task(void* param) { + (void) param; static uint32_t start_ms = 0; static bool led_state = false; - // Blink every interval ms - if (board_millis() - start_ms < blink_interval_ms) return; // not enough time - start_ms += blink_interval_ms; + while (1) { + #if CFG_TUSB_OS == OPT_OS_FREERTOS + vTaskDelay(blink_interval_ms / portTICK_PERIOD_MS); + #else + if (board_millis() - start_ms < blink_interval_ms) return; // not enough time + #endif + + start_ms += blink_interval_ms; + board_led_write(led_state); + led_state = 1 - led_state; // toggle + } +} + +//--------------------------------------------------------------------+ +// FreeRTOS +//--------------------------------------------------------------------+ +#if CFG_TUSB_OS == OPT_OS_FREERTOS + +#define BLINKY_STACK_SIZE configMINIMAL_STACK_SIZE +#define VIDEO_STACK_SIZE (configMINIMAL_STACK_SIZE*4) + +#if TU_CHECK_MCU(OPT_MCU_ESP32S2, OPT_MCU_ESP32S3) + #define USBD_STACK_SIZE 4096 + int main(void); + void app_main(void) { + main(); + } +#else + // Increase stack size when debug log is enabled + #define USBD_STACK_SIZE (3*configMINIMAL_STACK_SIZE/2) * (CFG_TUSB_DEBUG ? 2 : 1) +#endif + +// static task +#if configSUPPORT_STATIC_ALLOCATION +StackType_t blinky_stack[BLINKY_STACK_SIZE]; +StaticTask_t blinky_taskdef; + +StackType_t usb_device_stack[USBD_STACK_SIZE]; +StaticTask_t usb_device_taskdef; + +StackType_t video_stack[VIDEO_STACK_SIZE]; +StaticTask_t video_taskdef; +#endif + +// USB Device Driver task +// This top level thread process all usb events and invoke callbacks +void usb_device_task(void *param) { + (void) param; + + // init device stack on configured roothub port + // This should be called after scheduler/kernel is started. + // Otherwise, it could cause kernel issue since USB IRQ handler does use RTOS queue API. + tud_init(BOARD_TUD_RHPORT); + + if (board_init_after_tusb) { + board_init_after_tusb(); + } - board_led_write(led_state); - led_state = 1 - led_state; // toggle + // RTOS forever loop + while (1) { + // put this thread to waiting state until there is new events + tud_task(); + } } + +void freertos_init_task(void) { + #if configSUPPORT_STATIC_ALLOCATION + xTaskCreateStatic(led_blinking_task, "blinky", BLINKY_STACK_SIZE, NULL, 1, blinky_stack, &blinky_taskdef); + xTaskCreateStatic(usb_device_task, "usbd", USBD_STACK_SIZE, NULL, configMAX_PRIORITIES-1, usb_device_stack, &usb_device_taskdef); + xTaskCreateStatic(video_task, "cdc", VIDEO_STACK_SIZE, NULL, configMAX_PRIORITIES - 2, video_stack, &video_taskdef); + #else + xTaskCreate(led_blinking_task, "blinky", BLINKY_STACK_SIZE, NULL, 1, NULL); + xTaskCreate(usb_device_task, "usbd", USBD_STACK_SIZE, NULL, configMAX_PRIORITIES - 1, NULL); + xTaskCreate(video_task, "video", VIDEO_STACK_SZIE, NULL, configMAX_PRIORITIES - 2, NULL); + #endif + + // skip starting scheduler (and return) for ESP32-S2 or ESP32-S3 + #if !TU_CHECK_MCU(OPT_MCU_ESP32S2, OPT_MCU_ESP32S3) + vTaskStartScheduler(); + #endif +} +#endif diff --git a/examples/device/video_capture/src/tusb_config.h b/examples/device/video_capture/src/tusb_config.h index d563c6f5c..bdfc37d87 100644 --- a/examples/device/video_capture/src/tusb_config.h +++ b/examples/device/video_capture/src/tusb_config.h @@ -57,6 +57,11 @@ #define CFG_TUSB_OS OPT_OS_NONE #endif +// Espressif IDF requires "freertos/" prefix in include path +#if TU_CHECK_MCU(OPT_MCU_ESP32S2, OPT_MCU_ESP32S3) +#define CFG_TUSB_OS_INC_PATH freertos/ +#endif + #ifndef CFG_TUSB_DEBUG #define CFG_TUSB_DEBUG 0 #endif @@ -103,6 +108,9 @@ // use bulk endpoint for streaming interface #define CFG_TUD_VIDEO_STREAMING_BULK 1 +//#define CFG_EXAMPLE_VIDEO_READONLY +//#define CFG_EXAMPLE_VIDEO_DISABLE_MJPEG + #ifdef __cplusplus } #endif diff --git a/examples/device/video_capture/src/usb_descriptors.c b/examples/device/video_capture/src/usb_descriptors.c index 17e11229d..f308c75a7 100644 --- a/examples/device/video_capture/src/usb_descriptors.c +++ b/examples/device/video_capture/src/usb_descriptors.c @@ -364,7 +364,22 @@ const uvc_cfg_desc_t desc_fs_configuration = { }; #if TUD_OPT_HIGH_SPEED -uvc_cfg_desc_t desc_hs_configuration = desc_fs_configuration; +uvc_cfg_desc_t desc_hs_configuration; + +static uint8_t * get_hs_configuration_desc(void) { + static bool init = false; + + if (!init) { + desc_hs_configuration = desc_fs_configuration; + // change endpoint bulk size to 512 if bulk streaming + if (CFG_TUD_VIDEO_STREAMING_BULK) { + desc_hs_configuration.video_streaming.ep.wMaxPacketSize = 512; + } + } + init = true; + + return (uint8_t *) &desc_hs_configuration; +} // device qualifier is mostly similar to device descriptor since we don't change configuration based on speed tusb_desc_device_qualifier_t const desc_device_qualifier = { @@ -395,7 +410,11 @@ uint8_t const* tud_descriptor_device_qualifier_cb(void) { uint8_t const* tud_descriptor_other_speed_configuration_cb(uint8_t index) { (void) index; // for multiple configurations // if link speed is high return fullspeed config, and vice versa - return (uint8_t const*) ((tud_speed_get() == TUSB_SPEED_HIGH) ? &desc_fs_configuration : &desc_hs_configuration); + if (tud_speed_get() == TUSB_SPEED_HIGH) { + return (uint8_t const*) &desc_fs_configuration; + } else { + return get_hs_configuration_desc(); + } } #endif // highspeed @@ -408,11 +427,7 @@ uint8_t const* tud_descriptor_configuration_cb(uint8_t index) { #if TUD_OPT_HIGH_SPEED // Although we are highspeed, host may be fullspeed. if (tud_speed_get() == TUSB_SPEED_HIGH) { - // change endpoint bulk size to 512 if bulk streaming - if (CFG_TUD_VIDEO_STREAMING_BULK) { - desc_hs_configuration.video_streaming.ep.wMaxPacketSize = 512; - } - return (uint8_t const*) &desc_hs_configuration; + return get_hs_configuration_desc(); } else #endif { diff --git a/hw/bsp/board_api.h b/hw/bsp/board_api.h index 404509a28..0c8a35924 100644 --- a/hw/bsp/board_api.h +++ b/hw/bsp/board_api.h @@ -33,9 +33,26 @@ extern "C" { #include #include - #include "tusb.h" +#if CFG_TUSB_OS == OPT_OS_FREERTOS +#if TU_CHECK_MCU(OPT_MCU_ESP32S2, OPT_MCU_ESP32S3) + // ESP-IDF need "freertos/" prefix in include path. + // CFG_TUSB_OS_INC_PATH should be defined accordingly. + #include "freertos/FreeRTOS.h" + #include "freertos/semphr.h" + #include "freertos/queue.h" + #include "freertos/task.h" + #include "freertos/timers.h" +#else + #include "FreeRTOS.h" + #include "semphr.h" + #include "queue.h" + #include "task.h" + #include "timers.h" +#endif +#endif + // Define the default baudrate #ifndef CFG_BOARD_UART_BAUDRATE #define CFG_BOARD_UART_BAUDRATE 115200 ///< Default baud rate diff --git a/src/class/video/video.h b/src/class/video/video.h index bed8eeecf..fb0d0af1d 100644 --- a/src/class/video/video.h +++ b/src/class/video/video.h @@ -398,7 +398,7 @@ typedef tusb_desc_video_frame_uncompressed_3int_t tusb_desc_video_frame_uncompre TU_VERIFY_STATIC(sizeof(tusb_desc_video_frame_uncompressed_continuous_t) == 38, "size is not correct"); //------------- MJPEG -------------// -// MJPEG payload specs: 3.1.1 formatt descriptor +// MJPEG payload specs: 3.1.1 format descriptor typedef struct TU_ATTR_PACKED { uint8_t bLength; uint8_t bDescriptorType; -- cgit v1.3.1 From 00ba4e95acec64da4446fa89a40c3a2e38beed3c Mon Sep 17 00:00:00 2001 From: hathach Date: Tue, 30 Jan 2024 10:59:12 +0700 Subject: cdch: de-configure when closing, rename configured to mounted --- src/class/cdc/cdc_host.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) (limited to 'src/class') diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index 36b5d4234..4e0a9499f 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -53,12 +53,13 @@ typedef struct { uint8_t bInterfaceSubClass; uint8_t bInterfaceProtocol; + uint8_t ep_notif; uint8_t serial_drid; // Serial Driver ID + bool mounted; // Enumeration is complete cdc_acm_capability_t acm_capability; - uint8_t ep_notif; - uint8_t line_state; // DTR (bit0), RTS (bit1) TU_ATTR_ALIGNED(4) cdc_line_coding_t line_coding; // Baudrate, stop bits, parity, data width + uint8_t line_state; // DTR (bit0), RTS (bit1) #if CFG_TUH_CDC_FTDI || CFG_TUH_CDC_CP210X || CFG_TUH_CDC_CH34X cdc_line_coding_t requested_line_coding; @@ -77,8 +78,6 @@ typedef struct { uint8_t rx_ff_buf[CFG_TUH_CDC_TX_BUFSIZE]; CFG_TUH_MEM_ALIGN uint8_t rx_ep_buf[CFG_TUH_CDC_TX_EPSIZE]; } stream; - - bool configured; } cdch_interface_t; CFG_TUH_MEM_SECTION @@ -259,7 +258,6 @@ static cdch_interface_t* make_new_itf(uint8_t daddr, tusb_desc_interface_t const p_cdc->bInterfaceSubClass = itf_desc->bInterfaceSubClass; p_cdc->bInterfaceProtocol = itf_desc->bInterfaceProtocol; p_cdc->line_state = 0; - p_cdc->configured = false; return p_cdc; } } @@ -309,7 +307,7 @@ bool tuh_cdc_itf_get_info(uint8_t idx, tuh_itf_info_t* info) { bool tuh_cdc_mounted(uint8_t idx) { cdch_interface_t* p_cdc = get_itf(idx); TU_VERIFY(p_cdc); - return p_cdc->configured; + return p_cdc->mounted; } bool tuh_cdc_get_dtr(uint8_t idx) { @@ -648,9 +646,9 @@ void cdch_close(uint8_t daddr) { // Invoke application callback if (tuh_cdc_umount_cb) tuh_cdc_umount_cb(idx); - //tu_memclr(p_cdc, sizeof(cdch_interface_t)); p_cdc->daddr = 0; p_cdc->bInterfaceNumber = 0; + p_cdc->mounted = false; tu_edpt_stream_close(&p_cdc->stream.tx); tu_edpt_stream_close(&p_cdc->stream.rx); } @@ -751,7 +749,7 @@ bool cdch_open(uint8_t rhport, uint8_t daddr, tusb_desc_interface_t const *itf_d static void set_config_complete(cdch_interface_t * p_cdc, uint8_t idx, uint8_t itf_num) { TU_LOG_DRV("CDCh Set Configure complete\r\n"); - p_cdc->configured = true; + p_cdc->mounted = true; if (tuh_cdc_mount_cb) tuh_cdc_mount_cb(idx); // Prepare for incoming data -- cgit v1.3.1 From f600a8a0fc263b764ea018f0d0912f8001dd3160 Mon Sep 17 00:00:00 2001 From: IngHK Date: Tue, 30 Jan 2024 10:33:55 +0100 Subject: fix tuh_hid_mounted() similar to #2437 --- src/class/hid/hid_host.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'src/class') diff --git a/src/class/hid/hid_host.c b/src/class/hid/hid_host.c index db52b503f..709fa3dd8 100644 --- a/src/class/hid/hid_host.c +++ b/src/class/hid/hid_host.c @@ -50,6 +50,7 @@ typedef struct uint8_t itf_num; uint8_t ep_in; uint8_t ep_out; + bool mounted; // Enumeration is complete uint8_t itf_protocol; // None, Keyboard, Mouse uint8_t protocol_mode; // Boot (0) or Report protocol (1) @@ -139,7 +140,8 @@ uint8_t tuh_hid_itf_get_total_count(void) bool tuh_hid_mounted(uint8_t daddr, uint8_t idx) { hidh_interface_t* p_hid = get_hid_itf(daddr, idx); - return p_hid != NULL; + TU_VERIFY(p_hid); + return p_hid->mounted; } bool tuh_hid_itf_get_info(uint8_t daddr, uint8_t idx, tuh_itf_info_t* info) @@ -463,6 +465,7 @@ void hidh_close(uint8_t 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; } } } @@ -632,6 +635,7 @@ static void config_driver_mount_complete(uint8_t daddr, uint8_t idx, uint8_t con { hidh_interface_t* p_hid = get_hid_itf(daddr, idx); TU_VERIFY(p_hid, ); + p_hid->mounted = true; // enumeration is complete if (tuh_hid_mount_cb) tuh_hid_mount_cb(daddr, idx, desc_report, desc_len); -- cgit v1.3.1 From 82776aaca9f7a8ae1b627c42cd69a021b1b50fe3 Mon Sep 17 00:00:00 2001 From: mamiral Date: Wed, 31 Jan 2024 10:48:15 +0100 Subject: Update vendor_device.c fifo mutex config similar to cdc_device.c. --- src/class/vendor/vendor_device.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) (limited to 'src/class') diff --git a/src/class/vendor/vendor_device.c b/src/class/vendor/vendor_device.c index 389a29696..a68cb2156 100644 --- a/src/class/vendor/vendor_device.c +++ b/src/class/vendor/vendor_device.c @@ -49,10 +49,8 @@ typedef struct uint8_t rx_ff_buf[CFG_TUD_VENDOR_RX_BUFSIZE]; uint8_t tx_ff_buf[CFG_TUD_VENDOR_TX_BUFSIZE]; -#if CFG_FIFO_MUTEX - osal_mutex_def_t rx_ff_mutex; - osal_mutex_def_t tx_ff_mutex; -#endif + OSAL_MUTEX_DEF(rx_ff_mutex); + OSAL_MUTEX_DEF(tx_ff_mutex); // Endpoint Transfer buffer CFG_TUSB_MEM_ALIGN uint8_t epout_buf[CFG_TUD_VENDOR_EPSIZE]; @@ -183,10 +181,8 @@ void vendord_init(void) tu_fifo_config(&p_itf->rx_ff, p_itf->rx_ff_buf, CFG_TUD_VENDOR_RX_BUFSIZE, 1, false); tu_fifo_config(&p_itf->tx_ff, p_itf->tx_ff_buf, CFG_TUD_VENDOR_TX_BUFSIZE, 1, false); -#if CFG_FIFO_MUTEX tu_fifo_config_mutex(&p_itf->rx_ff, NULL, osal_mutex_create(&p_itf->rx_ff_mutex)); tu_fifo_config_mutex(&p_itf->tx_ff, osal_mutex_create(&p_itf->tx_ff_mutex), NULL); -#endif } } -- cgit v1.3.1 From e63a2f5c58b111a5f990ad1b6a0260f09a248c53 Mon Sep 17 00:00:00 2001 From: IngHK Date: Wed, 31 Jan 2024 18:00:25 +0100 Subject: fix #2444 and other small things --- src/class/cdc/cdc_host.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'src/class') diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index 4e0a9499f..2fb37d835 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -1345,7 +1345,7 @@ static inline bool ch34x_control_in(cdch_interface_t* p_cdc, uint8_t request, ui complete_cb, user_data); } -static bool ch34x_write_reg(cdch_interface_t* p_cdc, uint16_t reg, uint16_t reg_value, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { +static inline bool ch34x_write_reg(cdch_interface_t* p_cdc, uint16_t reg, uint16_t reg_value, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { return ch34x_control_out(p_cdc, CH34X_REQ_WRITE_REG, reg, reg_value, complete_cb, user_data); } @@ -1358,7 +1358,7 @@ static bool ch34x_write_reg(cdch_interface_t* p_cdc, uint16_t reg, uint16_t reg_ static bool ch34x_write_reg_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { uint16_t const div_ps = ch34x_get_divisor_prescaler(baudrate); - TU_VERIFY(div_ps != 0); + TU_VERIFY(div_ps); TU_ASSERT(ch34x_write_reg(p_cdc, CH34X_REG16_DIVISOR_PRESCALER, div_ps, complete_cb, user_data)); return true; @@ -1379,7 +1379,7 @@ static bool ch34x_set_data_format(cdch_interface_t* p_cdc, uint8_t stop_bits, ui p_cdc->requested_line_coding.data_bits = data_bits; uint8_t const lcr = ch34x_get_lcr(stop_bits, parity, data_bits); - TU_VERIFY(lcr != 0); + TU_VERIFY(lcr); TU_ASSERT (ch34x_control_out(p_cdc, CH34X_REQ_WRITE_REG, CH32X_REG16_LCR2_LCR, lcr, complete_cb ? ch34x_control_complete : NULL, user_data)); return true; @@ -1395,6 +1395,7 @@ static bool ch34x_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, } static void ch34x_set_line_coding_stage1_complete(tuh_xfer_t* xfer) { + // CH34x only has 1 interface and use wIndex as payload and not for bInterfaceNumber uint8_t const itf_num = 0; uint8_t const idx = tuh_cdc_itf_get_index(xfer->daddr, itf_num); cdch_interface_t* p_cdc = get_itf(idx); @@ -1443,7 +1444,7 @@ static bool ch34x_set_line_coding(cdch_interface_t* p_cdc, cdc_line_coding_t con // update transfer result, user_data is expected to point to xfer_result_t if (user_data) { - user_data = result; + *((xfer_result_t*) user_data) = result; } } @@ -1513,8 +1514,7 @@ static void ch34x_process_config(tuh_xfer_t* xfer) { uintptr_t const state = xfer->user_data; uint8_t buffer[2]; // TODO remove TU_ASSERT (p_cdc,); - - // TODO check xfer->result + TU_ASSERT (xfer->result == XFER_RESULT_SUCCESS,); switch (state) { case CONFIG_CH34X_READ_VERSION: @@ -1531,9 +1531,9 @@ static void ch34x_process_config(tuh_xfer_t* xfer) { // init CH34x with line coding cdc_line_coding_t const line_coding = CFG_TUH_CDC_LINE_CODING_ON_ENUM_CH34X; uint16_t const div_ps = ch34x_get_divisor_prescaler(line_coding.bit_rate); - TU_ASSERT(div_ps != 0, ); + TU_ASSERT(div_ps, ); uint8_t const lcr = ch34x_get_lcr(line_coding.stop_bits, line_coding.parity, line_coding.data_bits); - TU_ASSERT(lcr != 0, ); + TU_ASSERT(lcr, ); TU_ASSERT (ch34x_control_out(p_cdc, CH34X_REQ_SERIAL_INIT, tu_u16(lcr, 0x9c), div_ps, ch34x_process_config, CONFIG_CH34X_SPECIAL_REG_WRITE),); break; @@ -1573,7 +1573,7 @@ static uint16_t ch34x_get_divisor_prescaler(uint32_t baval) { uint8_t b; uint32_t c; - TU_VERIFY(baval != 0, 0); + TU_VERIFY(baval != 0 && baval <= 2000000, 0); switch (baval) { case 921600: a = 0xf3; @@ -1627,7 +1627,7 @@ static uint8_t ch34x_get_lcr(uint8_t stop_bits, uint8_t parity, uint8_t data_bit break; case CDC_LINE_CODING_PARITY_ODD: - lcr |= CH34X_LCR_ENABLE_PAR; + lcr |= CH34X_LCR_ENABLE_PAR; break; case CDC_LINE_CODING_PARITY_EVEN: -- cgit v1.3.1 From 3f2df94457e917dda2fed05c7ee17deefe55199e Mon Sep 17 00:00:00 2001 From: Bob Abeles Date: Tue, 20 Feb 2024 08:16:39 -0800 Subject: video_device: fix uninitialized warning --- src/class/video/video_device.c | 1 + 1 file changed, 1 insertion(+) (limited to 'src/class') diff --git a/src/class/video/video_device.c b/src/class/video/video_device.c index 1affd615e..c33dfa0b0 100644 --- a/src/class/video/video_device.c +++ b/src/class/video/video_device.c @@ -559,6 +559,7 @@ static bool _negotiate_streaming_parameters(videod_streaming_interface_t const * 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; -- cgit v1.3.1 From 13d26d216613792e814dda4742ef7ab4fb9b0d37 Mon Sep 17 00:00:00 2001 From: hathach Date: Thu, 22 Feb 2024 19:20:28 +0700 Subject: slightly change cdc_msc_freertos example --- examples/device/cdc_msc_freertos/src/main.c | 51 +++++++++++++++-------------- src/class/video/video.h | 6 +++- 2 files changed, 32 insertions(+), 25 deletions(-) (limited to 'src/class') diff --git a/examples/device/cdc_msc_freertos/src/main.c b/examples/device/cdc_msc_freertos/src/main.c index 1dadc4513..e94e8eaec 100644 --- a/examples/device/cdc_msc_freertos/src/main.c +++ b/examples/device/cdc_msc_freertos/src/main.c @@ -52,7 +52,8 @@ #define USBD_STACK_SIZE (3*configMINIMAL_STACK_SIZE/2) * (CFG_TUSB_DEBUG ? 2 : 1) #endif -#define CDC_STACK_SZIE configMINIMAL_STACK_SIZE +#define CDC_STACK_SIZE configMINIMAL_STACK_SIZE +#define BLINKY_STACK_SIZE configMINIMAL_STACK_SIZE //--------------------------------------------------------------------+ // MACRO CONSTANT TYPEDEF PROTOTYPES @@ -69,21 +70,22 @@ enum { BLINK_SUSPENDED = 2500, }; -// static timer & task +// static task #if configSUPPORT_STATIC_ALLOCATION -StaticTimer_t blinky_tmdef; +StackType_t blinky_stack[BLINKY_STACK_SIZE]; +StaticTask_t blinky_taskdef; StackType_t usb_device_stack[USBD_STACK_SIZE]; StaticTask_t usb_device_taskdef; -StackType_t cdc_stack[CDC_STACK_SZIE]; +StackType_t cdc_stack[CDC_STACK_SIZE]; StaticTask_t cdc_taskdef; #endif -TimerHandle_t blinky_tm; +static uint32_t blink_interval_ms = BLINK_NOT_MOUNTED; -static void led_blinky_cb(TimerHandle_t xTimer); static void usb_device_task(void *param); +void led_blinking_task(void* param); void cdc_task(void *params); //--------------------------------------------------------------------+ @@ -94,22 +96,20 @@ int main(void) { board_init(); #if configSUPPORT_STATIC_ALLOCATION - // soft timer for blinky - blinky_tm = xTimerCreateStatic(NULL, pdMS_TO_TICKS(BLINK_NOT_MOUNTED), true, NULL, led_blinky_cb, &blinky_tmdef); + // blinky task + xTaskCreateStatic(led_blinking_task, "blinky", BLINKY_STACK_SIZE, NULL, 1, blinky_stack, &blinky_taskdef); // Create a task for tinyusb device stack xTaskCreateStatic(usb_device_task, "usbd", USBD_STACK_SIZE, NULL, configMAX_PRIORITIES-1, usb_device_stack, &usb_device_taskdef); // Create CDC task - xTaskCreateStatic(cdc_task, "cdc", CDC_STACK_SZIE, NULL, configMAX_PRIORITIES-2, cdc_stack, &cdc_taskdef); + xTaskCreateStatic(cdc_task, "cdc", CDC_STACK_SIZE, NULL, configMAX_PRIORITIES - 2, cdc_stack, &cdc_taskdef); #else - blinky_tm = xTimerCreate(NULL, pdMS_TO_TICKS(BLINK_NOT_MOUNTED), true, NULL, led_blinky_cb); + xTaskCreate(led_blinking_task, "blinky", BLINKY_STACK_SIZE, NULL, 1, NULL); xTaskCreate(usb_device_task, "usbd", USBD_STACK_SIZE, NULL, configMAX_PRIORITIES - 1, NULL); xTaskCreate(cdc_task, "cdc", CDC_STACK_SZIE, NULL, configMAX_PRIORITIES - 2, NULL); #endif - xTimerStart(blinky_tm, 0); - // skip starting scheduler (and return) for ESP32-S2 or ESP32-S3 #if !TU_CHECK_MCU(OPT_MCU_ESP32S2, OPT_MCU_ESP32S3) vTaskStartScheduler(); @@ -154,12 +154,12 @@ static void usb_device_task(void *param) { // Invoked when device is mounted void tud_mount_cb(void) { - xTimerChangePeriod(blinky_tm, pdMS_TO_TICKS(BLINK_MOUNTED), 0); + blink_interval_ms = BLINK_MOUNTED; } // Invoked when device is unmounted void tud_umount_cb(void) { - xTimerChangePeriod(blinky_tm, pdMS_TO_TICKS(BLINK_NOT_MOUNTED), 0); + blink_interval_ms = BLINK_NOT_MOUNTED; } // Invoked when usb bus is suspended @@ -167,16 +167,12 @@ void tud_umount_cb(void) { // Within 7ms, device must draw an average of current less than 2.5 mA from bus void tud_suspend_cb(bool remote_wakeup_en) { (void) remote_wakeup_en; - xTimerChangePeriod(blinky_tm, pdMS_TO_TICKS(BLINK_SUSPENDED), 0); + blink_interval_ms = BLINK_SUSPENDED; } // Invoked when usb bus is resumed void tud_resume_cb(void) { - if (tud_mounted()) { - xTimerChangePeriod(blinky_tm, pdMS_TO_TICKS(BLINK_MOUNTED), 0); - } else { - xTimerChangePeriod(blinky_tm, pdMS_TO_TICKS(BLINK_NOT_MOUNTED), 0); - } + blink_interval_ms = tud_mounted() ? BLINK_MOUNTED : BLINK_NOT_MOUNTED; } //--------------------------------------------------------------------+ @@ -235,10 +231,17 @@ void tud_cdc_rx_cb(uint8_t itf) { //--------------------------------------------------------------------+ // BLINKING TASK //--------------------------------------------------------------------+ -static void led_blinky_cb(TimerHandle_t xTimer) { - (void) xTimer; +void led_blinking_task(void* param) { + (void) param; + static uint32_t start_ms = 0; static bool led_state = false; - board_led_write(led_state); - led_state = 1 - led_state; // toggle + while (1) { + // Blink every interval ms + vTaskDelay(blink_interval_ms / portTICK_PERIOD_MS); + start_ms += blink_interval_ms; + + board_led_write(led_state); + led_state = 1 - led_state; // toggle + } } diff --git a/src/class/video/video.h b/src/class/video/video.h index 6319c6536..abf1e34b9 100644 --- a/src/class/video/video.h +++ b/src/class/video/video.h @@ -368,6 +368,8 @@ typedef struct TU_ATTR_PACKED { uint8_t bCopyProtect; } tusb_desc_video_format_uncompressed_t; +TU_VERIFY_STATIC(sizeof(tusb_desc_video_format_uncompressed_t) == 27, "size is not correct"); + // Uncompressed payload specs: 3.1.2 frame descriptor #define tusb_desc_video_frame_uncompressed_nint_t(_nint) \ struct TU_ATTR_PACKED { \ @@ -381,7 +383,7 @@ typedef struct TU_ATTR_PACKED { uint32_t dwMinBitRate; \ uint32_t dwMaxBitRate; \ uint32_t dwMaxVideoFrameBufferSize; /* deprecated in 1.5 */ \ - uint32_t dwDefaultFrameInterval; \ + uint32_t dwDefaultFrameInterval; /* 100ns unit */\ uint8_t bFrameIntervalType; \ uint32_t dwFrameInterval[_nint]; \ } @@ -413,6 +415,8 @@ typedef struct TU_ATTR_PACKED { uint8_t bCopyProtect; } tusb_desc_video_format_mjpeg_t; +TU_VERIFY_STATIC(sizeof(tusb_desc_video_format_mjpeg_t) == 11, "size is not correct"); + // MJPEG payload specs: 3.1.2 frame descriptor (same as uncompressed) typedef tusb_desc_video_frame_uncompressed_t tusb_desc_video_frame_mjpeg_t; typedef tusb_desc_video_frame_uncompressed_1int_t tusb_desc_video_frame_mjpeg_1int_t; -- cgit v1.3.1 From 5ce7b147117826dd75c2d7b347df80b0177e7252 Mon Sep 17 00:00:00 2001 From: Tommie Gannert Date: Mon, 26 Feb 2024 11:41:50 +0100 Subject: add notification support for device class USBTMC. The ep_int_in is already used for responding to USB488 READ_STATUS_BYTE requests, but that EP is defined for all of USBTMC. This extends the functionality to let callers send notifications and receive ACKs. --- src/class/usbtmc/usbtmc.h | 25 +++++++++++++++++++++++++ src/class/usbtmc/usbtmc_device.c | 16 +++++++++++++++- src/class/usbtmc/usbtmc_device.h | 20 +++++++++++++++----- 3 files changed, 55 insertions(+), 6 deletions(-) (limited to 'src/class') diff --git a/src/class/usbtmc/usbtmc.h b/src/class/usbtmc/usbtmc.h index 090ab3c4a..327de087c 100644 --- a/src/class/usbtmc/usbtmc.h +++ b/src/class/usbtmc/usbtmc.h @@ -183,6 +183,23 @@ typedef enum { } usmtmc_request_type_enum; +typedef enum { + // The last and first valid bNotify1 for use by the USBTMC class specification. + USBTMC_bNOTIFY1_USBTMC_FIRST = 0x00, + USBTMC_bNOTIFY1_USBTMC_LAST = 0x3F, + + // The last and first valid bNotify1 for use by vendors. + USBTMC_bNOTIFY1_VENDOR_SPECIFIC_FIRST = 0x40, + USBTMC_bNOTIFY1_VENDOR_SPECIFIC_LAST = 0x7F, + + // The last and first valid bNotify1 for use by USBTMC subclass specifications. + USBTMC_bNOTIFY1_SUBCLASS_FIRST = 0x80, + USBTMC_bNOTIFY1_SUBCLASS_LAST = 0xFF, + + // From the USB488 Subclass Specification, Section 3.4. + USB488_bNOTIFY1_SRQ = 0x81, +} usbtmc_int_in_payload_format; + typedef enum { USBTMC_STATUS_SUCCESS = 0x01, USBTMC_STATUS_PENDING = 0x02, @@ -303,6 +320,14 @@ typedef struct TU_ATTR_PACKED TU_VERIFY_STATIC(sizeof(usbtmc_read_stb_rsp_488_t) == 3u, "struct wrong length"); +typedef struct TU_ATTR_PACKED +{ + uint8_t bNotify1; // Must be USB488_bNOTIFY1_SRQ + uint8_t StatusByte; +} usbtmc_srq_interrupt_488_t; + +TU_VERIFY_STATIC(sizeof(usbtmc_srq_interrupt_488_t) == 2u, "struct wrong length"); + typedef struct TU_ATTR_PACKED { struct TU_ATTR_PACKED diff --git a/src/class/usbtmc/usbtmc_device.c b/src/class/usbtmc/usbtmc_device.c index 573654d58..debe445fd 100644 --- a/src/class/usbtmc/usbtmc_device.c +++ b/src/class/usbtmc/usbtmc_device.c @@ -240,6 +240,18 @@ bool tud_usbtmc_transmit_dev_msg_data( return true; } +bool tud_usbtmc_transmit_notification_data(const void * data, size_t len) +{ +#ifndef NDEBUG + TU_ASSERT(len >= 1); + TU_ASSERT(usbtmc_state.ep_int_in != 0); +#endif + if (usbd_edpt_busy(usbtmc_state.rhport, usbtmc_state.ep_int_in)) return false; + + TU_VERIFY(usbd_edpt_xfer(usbtmc_state.rhport, usbtmc_state.ep_int_in, (void *)data, len)); + return true; +} + void usbtmcd_init_cb(void) { usbtmc_state.capabilities = tud_usbtmc_get_capabilities_cb(); @@ -578,7 +590,9 @@ bool usbtmcd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint } } else if (ep_addr == usbtmc_state.ep_int_in) { - // Good? + if (tud_usbtmc_notification_complete_cb) { + TU_VERIFY(tud_usbtmc_notification_complete_cb()); + } return true; } return false; diff --git a/src/class/usbtmc/usbtmc_device.h b/src/class/usbtmc/usbtmc_device.h index c1298ddb8..2f3c91dbd 100644 --- a/src/class/usbtmc/usbtmc_device.h +++ b/src/class/usbtmc/usbtmc_device.h @@ -73,6 +73,10 @@ bool tud_usbtmc_check_abort_bulk_in_cb(usbtmc_check_abort_bulk_rsp_t *rsp); bool tud_usbtmc_check_abort_bulk_out_cb(usbtmc_check_abort_bulk_rsp_t *rsp); bool tud_usbtmc_check_clear_cb(usbtmc_get_clear_status_rsp_t *rsp); +// The interrupt-IN endpoint buffer was transmitted to the host. Use +// tud_usbtmc_transmit_notification_data to send another notification. +TU_ATTR_WEAK bool tud_usbtmc_notification_complete_cb(void); + // Indicator pulse should be 0.5 to 1.0 seconds long TU_ATTR_WEAK bool tud_usbtmc_indicator_pulse_cb(tusb_control_request_t const * msg, uint8_t *tmcResult); @@ -93,6 +97,17 @@ bool tud_usbtmc_transmit_dev_msg_data( const void * data, size_t len, bool endOfMessage, bool usingTermChar); +// Buffers a notification to be sent to the host. The buffer must be +// valid until the tud_usbtmc_notification_complete_cb callback. The +// data starts with the bNotify1 field, see the USBTMC Specification, +// Table 13. +// +// If the previous notification data has not yet been sent, this +// returns false. +// +// Requires an interrupt endpoint in the interface. +bool tud_usbtmc_transmit_notification_data(const void * data, size_t len); + bool tud_usbtmc_start_bus_read(void); @@ -104,9 +119,4 @@ bool usbtmcd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, bool usbtmcd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request); void usbtmcd_init_cb(void); -/************************************************************ - * USBTMC Descriptor Templates - *************************************************************/ - - #endif /* CLASS_USBTMC_USBTMC_DEVICE_H_ */ -- cgit v1.3.1 From 4ed02ae5f97b57bd442521234b81a381c507d3a1 Mon Sep 17 00:00:00 2001 From: hathach Date: Fri, 1 Mar 2024 17:34:14 +0700 Subject: reformat code hid_host.c - fix ceedling with ruby 3.1 - allow overwrite CMAKE_C_COMPILER/CMAKE_CXX_COMPILER from command line --- .../build_system/cmake/toolchain/arm_gcc.cmake | 12 +- src/class/hid/hid_host.c | 519 +++++++++------------ test/unit-test/project.yml | 13 +- 3 files changed, 231 insertions(+), 313 deletions(-) (limited to 'src/class') diff --git a/examples/build_system/cmake/toolchain/arm_gcc.cmake b/examples/build_system/cmake/toolchain/arm_gcc.cmake index 7680d75ab..d3fd5b557 100644 --- a/examples/build_system/cmake/toolchain/arm_gcc.cmake +++ b/examples/build_system/cmake/toolchain/arm_gcc.cmake @@ -1,8 +1,14 @@ set(CMAKE_SYSTEM_NAME Generic) -set(CMAKE_C_COMPILER "arm-none-eabi-gcc") -set(CMAKE_CXX_COMPILER "arm-none-eabi-g++") -set(CMAKE_ASM_COMPILER "arm-none-eabi-gcc") +if (NOT DEFINED CMAKE_C_COMPILER) + set(CMAKE_C_COMPILER "arm-none-eabi-gcc") +endif () + +if (NOT DEFINED CMAKE_CXX_COMPILER) + set(CMAKE_CXX_COMPILER "arm-none-eabi-g++") +endif () + +set(CMAKE_ASM_COMPILER ${CMAKE_C_COMPILER}) set(CMAKE_SIZE "arm-none-eabi-size" CACHE FILEPATH "") set(CMAKE_OBJCOPY "arm-none-eabi-objcopy" CACHE FILEPATH "") diff --git a/src/class/hid/hid_host.c b/src/class/hid/hid_host.c index 709fa3dd8..21aee531a 100644 --- a/src/class/hid/hid_host.c +++ b/src/class/hid/hid_host.c @@ -39,12 +39,11 @@ #endif #define TU_LOG_DRV(...) TU_LOG(CFG_TUH_HID_LOG_LEVEL, __VA_ARGS__) + //--------------------------------------------------------------------+ // MACRO CONSTANT TYPEDEF //--------------------------------------------------------------------+ - -typedef struct -{ +typedef struct { uint8_t daddr; uint8_t itf_num; @@ -55,7 +54,7 @@ typedef struct uint8_t itf_protocol; // None, Keyboard, Mouse uint8_t protocol_mode; // Boot (0) or Report protocol (1) - uint8_t report_desc_type; + uint8_t report_desc_type; uint16_t report_desc_len; uint16_t epin_size; @@ -73,79 +72,57 @@ tu_static uint8_t _hidh_default_protocol = HID_PROTOCOL_BOOT; //--------------------------------------------------------------------+ // Helper //--------------------------------------------------------------------+ - -TU_ATTR_ALWAYS_INLINE static inline -hidh_interface_t* get_hid_itf(uint8_t daddr, uint8_t idx) -{ +TU_ATTR_ALWAYS_INLINE static inline hidh_interface_t* get_hid_itf(uint8_t daddr, uint8_t idx) { TU_ASSERT(daddr > 0 && idx < CFG_TUH_HID, NULL); hidh_interface_t* p_hid = &_hidh_itf[idx]; return (p_hid->daddr == daddr) ? p_hid : NULL; } // Get instance ID by endpoint address -static uint8_t get_idx_by_epaddr(uint8_t daddr, uint8_t ep_addr) -{ - for ( uint8_t idx = 0; idx < CFG_TUH_HID; idx++ ) - { - hidh_interface_t const * p_hid = &_hidh_itf[idx]; - - if ( p_hid->daddr == daddr && - (p_hid->ep_in == ep_addr || p_hid->ep_out == ep_addr) ) - { +static uint8_t get_idx_by_epaddr(uint8_t daddr, uint8_t ep_addr) { + for (uint8_t idx = 0; idx < CFG_TUH_HID; idx++) { + hidh_interface_t const* p_hid = &_hidh_itf[idx]; + if (p_hid->daddr == daddr && + (p_hid->ep_in == ep_addr || p_hid->ep_out == ep_addr)) { return idx; } } - return TUSB_INDEX_INVALID_8; } -static hidh_interface_t* find_new_itf(void) -{ - for(uint8_t i=0; imounted; } -bool tuh_hid_itf_get_info(uint8_t daddr, uint8_t idx, tuh_itf_info_t* info) -{ +bool tuh_hid_itf_get_info(uint8_t daddr, uint8_t idx, tuh_itf_info_t* info) { hidh_interface_t* p_hid = get_hid_itf(daddr, idx); TU_VERIFY(p_hid && info); @@ -153,34 +130,30 @@ bool tuh_hid_itf_get_info(uint8_t daddr, uint8_t idx, tuh_itf_info_t* info) // re-construct descriptor tusb_desc_interface_t* desc = &info->desc; - desc->bLength = sizeof(tusb_desc_interface_t); - desc->bDescriptorType = TUSB_DESC_INTERFACE; + desc->bLength = sizeof(tusb_desc_interface_t); + desc->bDescriptorType = TUSB_DESC_INTERFACE; - desc->bInterfaceNumber = p_hid->itf_num; - desc->bAlternateSetting = 0; - desc->bNumEndpoints = (uint8_t) ((p_hid->ep_in ? 1u : 0u) + (p_hid->ep_out ? 1u : 0u)); - desc->bInterfaceClass = TUSB_CLASS_HID; + desc->bInterfaceNumber = p_hid->itf_num; + desc->bAlternateSetting = 0; + desc->bNumEndpoints = (uint8_t) ((p_hid->ep_in ? 1u : 0u) + (p_hid->ep_out ? 1u : 0u)); + desc->bInterfaceClass = TUSB_CLASS_HID; desc->bInterfaceSubClass = (p_hid->itf_protocol ? HID_SUBCLASS_BOOT : HID_SUBCLASS_NONE); desc->bInterfaceProtocol = p_hid->itf_protocol; - desc->iInterface = 0; // not used yet + desc->iInterface = 0; // not used yet return true; } -uint8_t tuh_hid_itf_get_index(uint8_t daddr, uint8_t itf_num) -{ - for ( uint8_t idx = 0; idx < CFG_TUH_HID; idx++ ) - { - hidh_interface_t const * p_hid = &_hidh_itf[idx]; - - if ( p_hid->daddr == daddr && p_hid->itf_num == itf_num) return idx; +uint8_t tuh_hid_itf_get_index(uint8_t daddr, uint8_t itf_num) { + for (uint8_t idx = 0; idx < CFG_TUH_HID; idx++) { + hidh_interface_t const* p_hid = &_hidh_itf[idx]; + if (p_hid->daddr == daddr && p_hid->itf_num == itf_num) return idx; } return TUSB_INDEX_INVALID_8; } -uint8_t tuh_hid_interface_protocol(uint8_t daddr, uint8_t idx) -{ +uint8_t tuh_hid_interface_protocol(uint8_t daddr, uint8_t idx) { hidh_interface_t* p_hid = get_hid_itf(daddr, idx); return p_hid ? p_hid->itf_protocol : 0; } @@ -188,29 +161,24 @@ uint8_t tuh_hid_interface_protocol(uint8_t daddr, uint8_t idx) //--------------------------------------------------------------------+ // Control Endpoint API //--------------------------------------------------------------------+ - -uint8_t tuh_hid_get_protocol(uint8_t daddr, uint8_t idx) -{ +uint8_t tuh_hid_get_protocol(uint8_t daddr, uint8_t idx) { hidh_interface_t* p_hid = get_hid_itf(daddr, idx); return p_hid ? p_hid->protocol_mode : 0; } -static void set_protocol_complete(tuh_xfer_t* xfer) -{ +static void set_protocol_complete(tuh_xfer_t* xfer) { uint8_t const itf_num = (uint8_t) tu_le16toh(xfer->setup->wIndex); - uint8_t const daddr = xfer->daddr; - uint8_t const idx = tuh_hid_itf_get_index(daddr, itf_num); + uint8_t const daddr = xfer->daddr; + uint8_t const idx = tuh_hid_itf_get_index(daddr, itf_num); hidh_interface_t* p_hid = get_hid_itf(daddr, idx); - TU_VERIFY(p_hid, ); + TU_VERIFY(p_hid,); - if (XFER_RESULT_SUCCESS == xfer->result) - { + if (XFER_RESULT_SUCCESS == xfer->result) { p_hid->protocol_mode = (uint8_t) tu_le16toh(xfer->setup->wValue); } - if (tuh_hid_set_protocol_complete_cb) - { + if (tuh_hid_set_protocol_complete_cb) { tuh_hid_set_protocol_complete_cb(daddr, idx, p_hid->protocol_mode); } } @@ -219,123 +187,109 @@ void tuh_hid_set_default_protocol(uint8_t protocol) { _hidh_default_protocol = protocol; } -static bool _hidh_set_protocol(uint8_t daddr, uint8_t itf_num, uint8_t protocol, tuh_xfer_cb_t complete_cb, uintptr_t user_data) -{ +static bool _hidh_set_protocol(uint8_t daddr, uint8_t itf_num, uint8_t protocol, + tuh_xfer_cb_t complete_cb, uintptr_t user_data) { TU_LOG_DRV("HID Set Protocol = %d\r\n", protocol); - tusb_control_request_t const request = - { - .bmRequestType_bit = - { - .recipient = TUSB_REQ_RCPT_INTERFACE, - .type = TUSB_REQ_TYPE_CLASS, - .direction = TUSB_DIR_OUT - }, - .bRequest = HID_REQ_CONTROL_SET_PROTOCOL, - .wValue = protocol, - .wIndex = itf_num, - .wLength = 0 + tusb_control_request_t const request = { + .bmRequestType_bit = { + .recipient = TUSB_REQ_RCPT_INTERFACE, + .type = TUSB_REQ_TYPE_CLASS, + .direction = TUSB_DIR_OUT + }, + .bRequest = HID_REQ_CONTROL_SET_PROTOCOL, + .wValue = protocol, + .wIndex = itf_num, + .wLength = 0 }; - tuh_xfer_t xfer = - { - .daddr = daddr, - .ep_addr = 0, - .setup = &request, - .buffer = NULL, - .complete_cb = complete_cb, - .user_data = user_data + tuh_xfer_t xfer = { + .daddr = daddr, + .ep_addr = 0, + .setup = &request, + .buffer = NULL, + .complete_cb = complete_cb, + .user_data = user_data }; return tuh_control_xfer(&xfer); } -bool tuh_hid_set_protocol(uint8_t daddr, uint8_t idx, uint8_t protocol) -{ +bool tuh_hid_set_protocol(uint8_t daddr, uint8_t idx, uint8_t protocol) { hidh_interface_t* p_hid = get_hid_itf(daddr, idx); TU_VERIFY(p_hid && p_hid->itf_protocol != HID_ITF_PROTOCOL_NONE); return _hidh_set_protocol(daddr, p_hid->itf_num, protocol, set_protocol_complete, 0); } -static void set_report_complete(tuh_xfer_t* xfer) -{ +static void set_report_complete(tuh_xfer_t* xfer) { TU_LOG_DRV("HID Set Report complete\r\n"); - if (tuh_hid_set_report_complete_cb) - { + if (tuh_hid_set_report_complete_cb) { uint8_t const itf_num = (uint8_t) tu_le16toh(xfer->setup->wIndex); - uint8_t const idx = tuh_hid_itf_get_index(xfer->daddr, itf_num); + uint8_t const idx = tuh_hid_itf_get_index(xfer->daddr, itf_num); uint8_t const report_type = tu_u16_high(xfer->setup->wValue); - uint8_t const report_id = tu_u16_low(xfer->setup->wValue); + uint8_t const report_id = tu_u16_low(xfer->setup->wValue); tuh_hid_set_report_complete_cb(xfer->daddr, idx, report_id, report_type, (xfer->result == XFER_RESULT_SUCCESS) ? xfer->setup->wLength : 0); } } -bool tuh_hid_set_report(uint8_t daddr, uint8_t idx, uint8_t report_id, uint8_t report_type, void* report, uint16_t len) -{ +bool tuh_hid_set_report(uint8_t daddr, uint8_t idx, uint8_t report_id, uint8_t report_type, void* report, uint16_t len) { hidh_interface_t* p_hid = get_hid_itf(daddr, idx); TU_VERIFY(p_hid); - TU_LOG_DRV("HID Set Report: id = %u, type = %u, len = %u\r\n", report_id, report_type, len); - tusb_control_request_t const request = - { - .bmRequestType_bit = - { - .recipient = TUSB_REQ_RCPT_INTERFACE, - .type = TUSB_REQ_TYPE_CLASS, - .direction = TUSB_DIR_OUT - }, - .bRequest = HID_REQ_CONTROL_SET_REPORT, - .wValue = tu_htole16(tu_u16(report_type, report_id)), - .wIndex = tu_htole16((uint16_t)p_hid->itf_num), - .wLength = len + tusb_control_request_t const request = { + .bmRequestType_bit = { + .recipient = TUSB_REQ_RCPT_INTERFACE, + .type = TUSB_REQ_TYPE_CLASS, + .direction = TUSB_DIR_OUT + }, + .bRequest = HID_REQ_CONTROL_SET_REPORT, + .wValue = tu_htole16(tu_u16(report_type, report_id)), + .wIndex = tu_htole16((uint16_t) p_hid->itf_num), + .wLength = len }; - tuh_xfer_t xfer = - { - .daddr = daddr, - .ep_addr = 0, - .setup = &request, - .buffer = report, - .complete_cb = set_report_complete, - .user_data = 0 + tuh_xfer_t xfer = { + .daddr = daddr, + .ep_addr = 0, + .setup = &request, + .buffer = report, + .complete_cb = set_report_complete, + .user_data = 0 }; return tuh_control_xfer(&xfer); } -static bool _hidh_set_idle(uint8_t daddr, uint8_t itf_num, uint16_t idle_rate, tuh_xfer_cb_t complete_cb, uintptr_t user_data) -{ +static bool _hidh_set_idle(uint8_t daddr, uint8_t itf_num, uint16_t idle_rate, + tuh_xfer_cb_t complete_cb, uintptr_t user_data) { // SET IDLE request, device can stall if not support this request TU_LOG_DRV("HID Set Idle \r\n"); - tusb_control_request_t const request = - { - .bmRequestType_bit = - { - .recipient = TUSB_REQ_RCPT_INTERFACE, - .type = TUSB_REQ_TYPE_CLASS, - .direction = TUSB_DIR_OUT - }, - .bRequest = HID_REQ_CONTROL_SET_IDLE, - .wValue = tu_htole16(idle_rate), - .wIndex = tu_htole16((uint16_t)itf_num), - .wLength = 0 + tusb_control_request_t const request = { + .bmRequestType_bit = { + .recipient = TUSB_REQ_RCPT_INTERFACE, + .type = TUSB_REQ_TYPE_CLASS, + .direction = TUSB_DIR_OUT + }, + .bRequest = HID_REQ_CONTROL_SET_IDLE, + .wValue = tu_htole16(idle_rate), + .wIndex = tu_htole16((uint16_t) itf_num), + .wLength = 0 }; - tuh_xfer_t xfer = - { - .daddr = daddr, - .ep_addr = 0, - .setup = &request, - .buffer = NULL, - .complete_cb = complete_cb, - .user_data = user_data + tuh_xfer_t xfer = { + .daddr = daddr, + .ep_addr = 0, + .setup = &request, + .buffer = NULL, + .complete_cb = complete_cb, + .user_data = user_data }; return tuh_control_xfer(&xfer); @@ -346,24 +300,20 @@ static bool _hidh_set_idle(uint8_t daddr, uint8_t itf_num, uint16_t idle_rate, t //--------------------------------------------------------------------+ // Check if HID interface is ready to receive report -bool tuh_hid_receive_ready(uint8_t dev_addr, uint8_t idx) -{ +bool tuh_hid_receive_ready(uint8_t dev_addr, uint8_t idx) { hidh_interface_t* p_hid = get_hid_itf(dev_addr, idx); TU_VERIFY(p_hid); - return !usbh_edpt_busy(dev_addr, p_hid->ep_in); } -bool tuh_hid_receive_report(uint8_t daddr, uint8_t idx) -{ +bool tuh_hid_receive_report(uint8_t daddr, uint8_t idx) { hidh_interface_t* p_hid = get_hid_itf(daddr, idx); TU_VERIFY(p_hid); // claim endpoint - TU_VERIFY( usbh_edpt_claim(daddr, p_hid->ep_in) ); + TU_VERIFY(usbh_edpt_claim(daddr, p_hid->ep_in)); - if ( !usbh_edpt_xfer(daddr, p_hid->ep_in, p_hid->epin_buf, p_hid->epin_size) ) - { + if (!usbh_edpt_xfer(daddr, p_hid->ep_in, p_hid->epin_buf, p_hid->epin_size)) { usbh_edpt_release(daddr, p_hid->ep_in); return false; } @@ -371,43 +321,34 @@ bool tuh_hid_receive_report(uint8_t daddr, uint8_t idx) return true; } -bool tuh_hid_send_ready(uint8_t dev_addr, uint8_t idx) -{ +bool tuh_hid_send_ready(uint8_t dev_addr, uint8_t idx) { hidh_interface_t* p_hid = get_hid_itf(dev_addr, idx); TU_VERIFY(p_hid); - return !usbh_edpt_busy(dev_addr, p_hid->ep_out); } -bool tuh_hid_send_report(uint8_t daddr, uint8_t idx, uint8_t report_id, const void* report, uint16_t len) -{ +bool tuh_hid_send_report(uint8_t daddr, uint8_t idx, uint8_t report_id, const void* report, uint16_t len) { TU_LOG_DRV("HID Send Report %d\r\n", report_id); hidh_interface_t* p_hid = get_hid_itf(daddr, idx); TU_VERIFY(p_hid); - if (p_hid->ep_out == 0) - { + if (p_hid->ep_out == 0) { // This HID does not have an out endpoint (other than control) return false; - } - else if (len > CFG_TUH_HID_EPOUT_BUFSIZE || - (report_id != 0 && len > (CFG_TUH_HID_EPOUT_BUFSIZE - 1))) - { + } else if (len > CFG_TUH_HID_EPOUT_BUFSIZE || + (report_id != 0 && len > (CFG_TUH_HID_EPOUT_BUFSIZE - 1))) { // ep_out buffer is not large enough to hold contents return false; } // claim endpoint - TU_VERIFY( usbh_edpt_claim(daddr, p_hid->ep_out) ); + TU_VERIFY(usbh_edpt_claim(daddr, p_hid->ep_out)); - if (report_id == 0) - { + if (report_id == 0) { // No report ID in transmission memcpy(&p_hid->epout_buf[0], report, len); - } - else - { + } else { p_hid->epout_buf[0] = report_id; memcpy(&p_hid->epout_buf[1], report, len); ++len; // 1 more byte for report_id @@ -415,8 +356,7 @@ bool tuh_hid_send_report(uint8_t daddr, uint8_t idx, uint8_t report_id, const vo TU_LOG3_MEM(p_hid->epout_buf, len, 2); - if ( !usbh_edpt_xfer(daddr, p_hid->ep_out, p_hid->epout_buf, len) ) - { + if (!usbh_edpt_xfer(daddr, p_hid->ep_out, p_hid->epout_buf, len)) { usbh_edpt_release(daddr, p_hid->ep_out); return false; } @@ -427,13 +367,11 @@ bool tuh_hid_send_report(uint8_t daddr, uint8_t idx, uint8_t report_id, const vo //--------------------------------------------------------------------+ // USBH API //--------------------------------------------------------------------+ -void hidh_init(void) -{ +void hidh_init(void) { tu_memclr(_hidh_itf, sizeof(_hidh_itf)); } -bool hidh_xfer_cb(uint8_t daddr, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) -{ +bool hidh_xfer_cb(uint8_t daddr, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) { (void) result; uint8_t const dir = tu_edpt_dir(ep_addr); @@ -442,28 +380,25 @@ bool hidh_xfer_cb(uint8_t daddr, uint8_t ep_addr, xfer_result_t result, uint32_t hidh_interface_t* p_hid = get_hid_itf(daddr, idx); TU_VERIFY(p_hid); - if ( dir == TUSB_DIR_IN ) - { + if (dir == TUSB_DIR_IN) { TU_LOG_DRV(" Get Report callback (%u, %u)\r\n", daddr, idx); TU_LOG3_MEM(p_hid->epin_buf, xferred_bytes, 2); tuh_hid_report_received_cb(daddr, idx, p_hid->epin_buf, (uint16_t) xferred_bytes); - }else - { - if (tuh_hid_report_sent_cb) tuh_hid_report_sent_cb(daddr, idx, p_hid->epout_buf, (uint16_t) xferred_bytes); + } else { + if (tuh_hid_report_sent_cb) { + tuh_hid_report_sent_cb(daddr, idx, p_hid->epout_buf, (uint16_t) xferred_bytes); + } } return true; } -void hidh_close(uint8_t daddr) -{ - for(uint8_t i=0; idaddr == 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); + if (tuh_hid_umount_cb) tuh_hid_umount_cb(daddr, i); p_hid->daddr = 0; p_hid->mounted = false; } @@ -474,25 +409,22 @@ void hidh_close(uint8_t daddr) // Enumeration //--------------------------------------------------------------------+ -bool hidh_open(uint8_t rhport, uint8_t daddr, tusb_desc_interface_t const *desc_itf, uint16_t max_len) -{ +bool hidh_open(uint8_t rhport, uint8_t daddr, tusb_desc_interface_t const* desc_itf, uint16_t max_len) { (void) rhport; (void) max_len; TU_VERIFY(TUSB_CLASS_HID == desc_itf->bInterfaceClass); - TU_LOG_DRV("[%u] HID opening Interface %u\r\n", daddr, desc_itf->bInterfaceNumber); // len = interface + hid + n*endpoints uint16_t const drv_len = (uint16_t) (sizeof(tusb_desc_interface_t) + sizeof(tusb_hid_descriptor_hid_t) + desc_itf->bNumEndpoints * sizeof(tusb_desc_endpoint_t)); TU_ASSERT(max_len >= drv_len); - - uint8_t const *p_desc = (uint8_t const *) desc_itf; + uint8_t const* p_desc = (uint8_t const*) desc_itf; //------------- HID descriptor -------------// p_desc = tu_desc_next(p_desc); - tusb_hid_descriptor_hid_t const *desc_hid = (tusb_hid_descriptor_hid_t const *) p_desc; + tusb_hid_descriptor_hid_t const* desc_hid = (tusb_hid_descriptor_hid_t const*) p_desc; TU_ASSERT(HID_DESC_TYPE_HID == desc_hid->bDescriptorType); hidh_interface_t* p_hid = find_new_itf(); @@ -501,38 +433,33 @@ bool hidh_open(uint8_t rhport, uint8_t daddr, tusb_desc_interface_t const *desc_ //------------- Endpoint Descriptors -------------// p_desc = tu_desc_next(p_desc); - tusb_desc_endpoint_t const * desc_ep = (tusb_desc_endpoint_t const *) p_desc; + tusb_desc_endpoint_t const* desc_ep = (tusb_desc_endpoint_t const*) p_desc; - for(int i = 0; i < desc_itf->bNumEndpoints; i++) - { + for (int i = 0; i < desc_itf->bNumEndpoints; i++) { TU_ASSERT(TUSB_DESC_ENDPOINT == desc_ep->bDescriptorType); - TU_ASSERT( tuh_edpt_open(daddr, desc_ep) ); + TU_ASSERT(tuh_edpt_open(daddr, desc_ep)); - if(tu_edpt_dir(desc_ep->bEndpointAddress) == TUSB_DIR_IN) - { - p_hid->ep_in = desc_ep->bEndpointAddress; + if (tu_edpt_dir(desc_ep->bEndpointAddress) == TUSB_DIR_IN) { + p_hid->ep_in = desc_ep->bEndpointAddress; p_hid->epin_size = tu_edpt_packet_size(desc_ep); - } - else - { - p_hid->ep_out = desc_ep->bEndpointAddress; + } else { + p_hid->ep_out = desc_ep->bEndpointAddress; p_hid->epout_size = tu_edpt_packet_size(desc_ep); } p_desc = tu_desc_next(p_desc); - desc_ep = (tusb_desc_endpoint_t const *) p_desc; + desc_ep = (tusb_desc_endpoint_t const*) p_desc; } - p_hid->itf_num = desc_itf->bInterfaceNumber; + p_hid->itf_num = desc_itf->bInterfaceNumber; // Assume bNumDescriptors = 1 p_hid->report_desc_type = desc_hid->bReportType; - p_hid->report_desc_len = tu_unaligned_read16(&desc_hid->wReportLength); + p_hid->report_desc_len = tu_unaligned_read16(&desc_hid->wReportLength); // Per HID Specs: default is Report protocol, though we will force Boot protocol when set_config p_hid->protocol_mode = _hidh_default_protocol; - if ( HID_SUBCLASS_BOOT == desc_itf->bInterfaceSubClass ) - { + if (HID_SUBCLASS_BOOT == desc_itf->bInterfaceSubClass) { p_hid->itf_protocol = desc_itf->bInterfaceProtocol; } @@ -553,15 +480,14 @@ enum { static void config_driver_mount_complete(uint8_t daddr, uint8_t idx, uint8_t const* desc_report, uint16_t desc_len); static void process_set_config(tuh_xfer_t* xfer); -bool hidh_set_config(uint8_t daddr, uint8_t itf_num) -{ +bool hidh_set_config(uint8_t daddr, uint8_t itf_num) { tusb_control_request_t request; request.wIndex = tu_htole16((uint16_t) itf_num); tuh_xfer_t xfer; - xfer.daddr = daddr; - xfer.result = XFER_RESULT_SUCCESS; - xfer.setup = &request; + xfer.daddr = daddr; + xfer.result = XFER_RESULT_SUCCESS; + xfer.setup = &request; xfer.user_data = CONFG_SET_IDLE; // fake request to kick-off the set config process @@ -570,71 +496,67 @@ bool hidh_set_config(uint8_t daddr, uint8_t itf_num) return true; } -static void process_set_config(tuh_xfer_t* xfer) -{ +static void process_set_config(tuh_xfer_t* xfer) { // Stall is a valid response for SET_IDLE, sometime SET_PROTOCOL as well // therefore we could ignore its result - if ( !(xfer->setup->bRequest == HID_REQ_CONTROL_SET_IDLE || - xfer->setup->bRequest == HID_REQ_CONTROL_SET_PROTOCOL) ) - { - TU_ASSERT(xfer->result == XFER_RESULT_SUCCESS, ); + if (!(xfer->setup->bRequest == HID_REQ_CONTROL_SET_IDLE || + xfer->setup->bRequest == HID_REQ_CONTROL_SET_PROTOCOL)) { + TU_ASSERT(xfer->result == XFER_RESULT_SUCCESS,); } uintptr_t const state = xfer->user_data; uint8_t const itf_num = (uint8_t) tu_le16toh(xfer->setup->wIndex); - uint8_t const daddr = xfer->daddr; + uint8_t const daddr = xfer->daddr; - uint8_t const idx = tuh_hid_itf_get_index(daddr, itf_num); + uint8_t const idx = tuh_hid_itf_get_index(daddr, itf_num); hidh_interface_t* p_hid = get_hid_itf(daddr, idx); - TU_VERIFY(p_hid, ); + TU_VERIFY(p_hid,); - switch(state) - { - case CONFG_SET_IDLE: - { + switch (state) { + case CONFG_SET_IDLE: { // Idle rate = 0 mean only report when there is changes const uint16_t idle_rate = 0; - const uintptr_t next_state = (p_hid->itf_protocol != HID_ITF_PROTOCOL_NONE) ? CONFIG_SET_PROTOCOL : CONFIG_GET_REPORT_DESC; + const uintptr_t next_state = (p_hid->itf_protocol != HID_ITF_PROTOCOL_NONE) + ? CONFIG_SET_PROTOCOL : CONFIG_GET_REPORT_DESC; _hidh_set_idle(daddr, itf_num, idle_rate, process_set_config, next_state); + break; } - break; case CONFIG_SET_PROTOCOL: _hidh_set_protocol(daddr, p_hid->itf_num, _hidh_default_protocol, process_set_config, CONFIG_GET_REPORT_DESC); - break; + break; case CONFIG_GET_REPORT_DESC: // Get Report Descriptor if possible // using usbh enumeration buffer since report descriptor can be very long - if( p_hid->report_desc_len > CFG_TUH_ENUMERATION_BUFSIZE ) - { + if (p_hid->report_desc_len > CFG_TUH_ENUMERATION_BUFSIZE) { TU_LOG_DRV("HID Skip Report Descriptor since it is too large %u bytes\r\n", p_hid->report_desc_len); // Driver is mounted without report descriptor config_driver_mount_complete(daddr, idx, NULL, 0); - }else - { - tuh_descriptor_get_hid_report(daddr, itf_num, p_hid->report_desc_type, 0, usbh_get_enum_buf(), p_hid->report_desc_len, process_set_config, CONFIG_COMPLETE); + } else { + tuh_descriptor_get_hid_report(daddr, itf_num, p_hid->report_desc_type, 0, + usbh_get_enum_buf(), p_hid->report_desc_len, + process_set_config, CONFIG_COMPLETE); } break; - case CONFIG_COMPLETE: - { + case CONFIG_COMPLETE: { uint8_t const* desc_report = usbh_get_enum_buf(); - uint16_t const desc_len = tu_le16toh(xfer->setup->wLength); + uint16_t const desc_len = tu_le16toh(xfer->setup->wLength); config_driver_mount_complete(daddr, idx, desc_report, desc_len); + break; } - break; - default: break; + default: + break; } } -static void config_driver_mount_complete(uint8_t daddr, uint8_t idx, uint8_t const* desc_report, uint16_t desc_len) -{ +static void config_driver_mount_complete(uint8_t daddr, uint8_t idx, uint8_t const* desc_report, uint16_t desc_len) { hidh_interface_t* p_hid = get_hid_itf(daddr, idx); - TU_VERIFY(p_hid, ); + TU_VERIFY(p_hid,); p_hid->mounted = true; // enumeration is complete @@ -648,21 +570,19 @@ static void config_driver_mount_complete(uint8_t daddr, uint8_t idx, uint8_t con // Report Descriptor Parser //--------------------------------------------------------------------+ -uint8_t tuh_hid_parse_report_descriptor(tuh_hid_report_info_t* report_info_arr, uint8_t arr_count, uint8_t const* desc_report, uint16_t desc_len) -{ +uint8_t tuh_hid_parse_report_descriptor(tuh_hid_report_info_t* report_info_arr, uint8_t arr_count, + uint8_t const* desc_report, uint16_t desc_len) { // Report Item 6.2.2.2 USB HID 1.11 - union TU_ATTR_PACKED - { + union TU_ATTR_PACKED { uint8_t byte; - struct TU_ATTR_PACKED - { - uint8_t size : 2; - uint8_t type : 2; - uint8_t tag : 4; + struct TU_ATTR_PACKED { + uint8_t size : 2; + uint8_t type : 2; + uint8_t tag : 4; }; } header; - tu_memclr(report_info_arr, arr_count*sizeof(tuh_hid_report_info_t)); + tu_memclr(report_info_arr, arr_count * sizeof(tuh_hid_report_info_t)); uint8_t report_num = 0; tuh_hid_report_info_t* info = report_info_arr; @@ -672,114 +592,105 @@ uint8_t tuh_hid_parse_report_descriptor(tuh_hid_report_info_t* report_info_arr, // uint8_t ri_report_size = 0; uint8_t ri_collection_depth = 0; - - while(desc_len && report_num < arr_count) - { + while (desc_len && report_num < arr_count) { header.byte = *desc_report++; desc_len--; - uint8_t const tag = header.tag; + uint8_t const tag = header.tag; uint8_t const type = header.type; uint8_t const size = header.size; uint8_t const data8 = desc_report[0]; TU_LOG(3, "tag = %d, type = %d, size = %d, data = ", tag, type, size); - for(uint32_t i=0; iusage_page, desc_report, size); - break; + if (ri_collection_depth == 0) memcpy(&info->usage_page, desc_report, size); + break; - case RI_GLOBAL_LOGICAL_MIN : break; - case RI_GLOBAL_LOGICAL_MAX : break; - case RI_GLOBAL_PHYSICAL_MIN : break; - case RI_GLOBAL_PHYSICAL_MAX : break; + case RI_GLOBAL_LOGICAL_MIN: break; + case RI_GLOBAL_LOGICAL_MAX: break; + case RI_GLOBAL_PHYSICAL_MIN: break; + case RI_GLOBAL_PHYSICAL_MAX: break; case RI_GLOBAL_REPORT_ID: info->report_id = data8; - break; + break; case RI_GLOBAL_REPORT_SIZE: // ri_report_size = data8; - break; + break; case RI_GLOBAL_REPORT_COUNT: // ri_report_count = data8; - break; + break; - case RI_GLOBAL_UNIT_EXPONENT : break; - case RI_GLOBAL_UNIT : break; - case RI_GLOBAL_PUSH : break; - case RI_GLOBAL_POP : break; + case RI_GLOBAL_UNIT_EXPONENT: break; + case RI_GLOBAL_UNIT: break; + case RI_GLOBAL_PUSH: break; + case RI_GLOBAL_POP: break; default: break; } - break; + break; case RI_TYPE_LOCAL: - switch(tag) - { + switch (tag) { case RI_LOCAL_USAGE: // only take in account the "usage" before starting REPORT ID - if ( ri_collection_depth == 0 ) info->usage = data8; - break; - - case RI_LOCAL_USAGE_MIN : break; - case RI_LOCAL_USAGE_MAX : break; - case RI_LOCAL_DESIGNATOR_INDEX : break; - case RI_LOCAL_DESIGNATOR_MIN : break; - case RI_LOCAL_DESIGNATOR_MAX : break; - case RI_LOCAL_STRING_INDEX : break; - case RI_LOCAL_STRING_MIN : break; - case RI_LOCAL_STRING_MAX : break; - case RI_LOCAL_DELIMITER : break; + if (ri_collection_depth == 0) info->usage = data8; + break; + + case RI_LOCAL_USAGE_MIN: break; + case RI_LOCAL_USAGE_MAX: break; + case RI_LOCAL_DESIGNATOR_INDEX: break; + case RI_LOCAL_DESIGNATOR_MIN: break; + case RI_LOCAL_DESIGNATOR_MAX: break; + case RI_LOCAL_STRING_INDEX: break; + case RI_LOCAL_STRING_MIN: break; + case RI_LOCAL_STRING_MAX: break; + case RI_LOCAL_DELIMITER: break; default: break; } - break; + break; - // error + // error default: break; } desc_report += size; - desc_len -= size; + desc_len -= size; } - for ( uint8_t i = 0; i < report_num; i++ ) - { - info = report_info_arr+i; + for (uint8_t i = 0; i < report_num; i++) { + info = report_info_arr + i; TU_LOG_DRV("%u: id = %u, usage_page = %u, usage = %u\r\n", i, info->report_id, info->usage_page, info->usage); } diff --git a/test/unit-test/project.yml b/test/unit-test/project.yml index 562dbca09..82528f68c 100644 --- a/test/unit-test/project.yml +++ b/test/unit-test/project.yml @@ -44,12 +44,13 @@ # in order to add common defines: # 1) remove the trailing [] from the :common: section # 2) add entries to the :common: section (e.g. :test: has TEST defined) - :common: &common_defines - - _UNITY_TEST_ + :common: &common_defines [] :test: - - *common_defines + - _UNITY_TEST_ + #- *common_defines :test_preprocess: - - *common_defines + - _UNITY_TEST_ + #- *common_defines :cmock: :mock_prefix: mock_ @@ -106,9 +107,9 @@ :flag: "${1}" # or "-L ${1}" for example :common: &common_libraries [] :test: - - *common_libraries + #- *common_libraries :release: - - *common_libraries + #- *common_libraries :plugins: :load_paths: -- cgit v1.3.1 From 4f5d80d3976fb0dc5cd190b1768225aacf34211b Mon Sep 17 00:00:00 2001 From: hathach Date: Fri, 1 Mar 2024 17:40:38 +0700 Subject: add tuh_hid_receive_abort() API --- src/class/hid/hid_host.c | 5 +++++ src/class/hid/hid_host.h | 28 ++++++++++++++++------------ 2 files changed, 21 insertions(+), 12 deletions(-) (limited to 'src/class') diff --git a/src/class/hid/hid_host.c b/src/class/hid/hid_host.c index 21aee531a..7330fa237 100644 --- a/src/class/hid/hid_host.c +++ b/src/class/hid/hid_host.c @@ -320,6 +320,11 @@ bool tuh_hid_receive_report(uint8_t daddr, uint8_t idx) { return true; } +bool tuh_hid_receive_abort(uint8_t dev_addr, uint8_t idx) { + hidh_interface_t* p_hid = get_hid_itf(dev_addr, idx); + TU_VERIFY(p_hid); + return tuh_edpt_abort_xfer(dev_addr, p_hid->ep_in); +} bool tuh_hid_send_ready(uint8_t dev_addr, uint8_t idx) { hidh_interface_t* p_hid = get_hid_itf(dev_addr, idx); diff --git a/src/class/hid/hid_host.h b/src/class/hid/hid_host.h index 238b7c627..17f4e27c0 100644 --- a/src/class/hid/hid_host.h +++ b/src/class/hid/hid_host.h @@ -30,7 +30,7 @@ #include "hid.h" #ifdef __cplusplus - extern "C" { +extern "C" { #endif //--------------------------------------------------------------------+ @@ -47,10 +47,9 @@ #endif -typedef struct -{ - uint8_t report_id; - uint8_t usage; +typedef struct { + uint8_t report_id; + uint8_t usage; uint16_t usage_page; // TODO still use the endpoint size for now @@ -86,7 +85,8 @@ bool tuh_hid_mounted(uint8_t dev_addr, uint8_t idx); // Parse report descriptor into array of report_info struct and return number of reports. // For complicated report, application should write its own parser. -uint8_t tuh_hid_parse_report_descriptor(tuh_hid_report_info_t* reports_info_arr, uint8_t arr_count, uint8_t const* desc_report, uint16_t desc_len) TU_ATTR_UNUSED; +TU_ATTR_UNUSED uint8_t tuh_hid_parse_report_descriptor(tuh_hid_report_info_t* reports_info_arr, uint8_t arr_count, + uint8_t const* desc_report, uint16_t desc_len); //--------------------------------------------------------------------+ // Control Endpoint API @@ -107,7 +107,8 @@ bool tuh_hid_set_protocol(uint8_t dev_addr, uint8_t idx, uint8_t protocol); // Set Report using control endpoint // report_type is either Input, Output or Feature, (value from hid_report_type_t) -bool tuh_hid_set_report(uint8_t dev_addr, uint8_t idx, uint8_t report_id, uint8_t report_type, void* report, uint16_t len); +bool tuh_hid_set_report(uint8_t dev_addr, uint8_t idx, uint8_t report_id, uint8_t report_type, + void* report, uint16_t len); //--------------------------------------------------------------------+ // Interrupt Endpoint API @@ -121,6 +122,9 @@ bool tuh_hid_receive_ready(uint8_t dev_addr, uint8_t idx); // - false if failed to queue the transfer e.g endpoint is busy bool tuh_hid_receive_report(uint8_t dev_addr, uint8_t idx); +// Abort receiving report on Interrupt Endpoint +bool tuh_hid_receive_abort(uint8_t dev_addr, uint8_t idx); + // Check if HID interface is ready to send report bool tuh_hid_send_ready(uint8_t dev_addr, uint8_t idx); @@ -159,11 +163,11 @@ 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_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); -void hidh_close (uint8_t dev_addr); +void hidh_init(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); +void hidh_close(uint8_t dev_addr); #ifdef __cplusplus } -- cgit v1.3.1 From 9e674fa109348d97fb4280ac534be665f619a4d8 Mon Sep 17 00:00:00 2001 From: Tommie Gannert Date: Fri, 15 Mar 2024 15:02:13 +0100 Subject: [usbtmc] cast to uintptr_t to get rid of const for usbd_edpt_xfer. --- src/class/usbtmc/usbtmc_device.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/class') diff --git a/src/class/usbtmc/usbtmc_device.c b/src/class/usbtmc/usbtmc_device.c index debe445fd..4092c37ea 100644 --- a/src/class/usbtmc/usbtmc_device.c +++ b/src/class/usbtmc/usbtmc_device.c @@ -248,7 +248,7 @@ bool tud_usbtmc_transmit_notification_data(const void * data, size_t len) #endif if (usbd_edpt_busy(usbtmc_state.rhport, usbtmc_state.ep_int_in)) return false; - TU_VERIFY(usbd_edpt_xfer(usbtmc_state.rhport, usbtmc_state.ep_int_in, (void *)data, len)); + TU_VERIFY(usbd_edpt_xfer(usbtmc_state.rhport, usbtmc_state.ep_int_in, (void *)(uintptr_t) data, len)); return true; } -- cgit v1.3.1 From 5d1f6934fbbeee3238267b0444172d47033a2fd9 Mon Sep 17 00:00:00 2001 From: Li Junru Date: Thu, 14 Mar 2024 20:55:05 +0800 Subject: fix: uvc multiple interface support 1. fix next interface may have IAD_DESC 2. fix vs_itf can't be open on bulk mode. --- src/class/video/video_device.c | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) (limited to 'src/class') diff --git a/src/class/video/video_device.c b/src/class/video/video_device.c index c33dfa0b0..249ced83d 100644 --- a/src/class/video/video_device.c +++ b/src/class/video/video_device.c @@ -207,6 +207,24 @@ static void const* _find_desc(void const *beg, void const *end, uint_fast8_t des return cur; } +/** Find the first descriptor of two given types + * + * @param[in] beg The head of descriptor byte array. + * @param[in] end The tail of descriptor byte array. + * @param[in] desc_type_0 The first target descriptor type. + * @param[in] desc_type_1 The second target descriptor type. + * + * @return The pointer for interface descriptor. + * @retval end did not found interface descriptor */ +static void const* _find_desc_2_type(void const *beg, void const *end, uint_fast8_t desc_type_0, uint_fast8_t desc_type_1) +{ + void const *cur = beg; + while ((cur < end) && (desc_type_0 != tu_desc_type(cur)) && (desc_type_1 != tu_desc_type(cur))) { + cur = tu_desc_next(cur); + } + return cur; +} + /** Find the first descriptor specified by the arguments * * @param[in] beg The head of descriptor byte array. @@ -233,6 +251,10 @@ static void const* _find_desc_3(void const *beg, void const *end, } /** Return the next interface descriptor which has another interface number. + * If there are multiple VC interfaces, there will be an IAD descriptor before + * the next interface descriptor. Check both the IAD descriptor and the interface + * descriptor. + * 3.1 Descriptor Layout Overview * * @param[in] beg The head of descriptor byte array. * @param[in] end The tail of descriptor byte array. @@ -245,7 +267,7 @@ static void const* _next_desc_itf(void const *beg, void const *end) uint_fast8_t itfnum = ((tusb_desc_interface_t const*)cur)->bInterfaceNumber; while ((cur < end) && (itfnum == ((tusb_desc_interface_t const*)cur)->bInterfaceNumber)) { - cur = _find_desc(tu_desc_next(cur), end, TUSB_DESC_INTERFACE); + cur = _find_desc_2_type(tu_desc_next(cur), end, TUSB_DESC_INTERFACE, TUSB_DESC_INTERFACE_ASSOCIATION); } return cur; } @@ -1216,7 +1238,7 @@ uint16_t videod_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uin * host may not issue set_interface so open the streaming interface here. */ uint8_t const *sbeg = (uint8_t const*)itf_desc + stm->desc.beg; uint8_t const *send = (uint8_t const*)itf_desc + stm->desc.end; - if (end == _find_desc_itf(sbeg, send, _desc_itfnum(sbeg), 1)) { + if (send == _find_desc_itf(sbeg, send, _desc_itfnum(sbeg), 1)) { TU_VERIFY(_open_vs_itf(rhport, stm, 0), 0); } } -- cgit v1.3.1 From 5630030a22cc850672c62bfe3a12c0054a7f84a2 Mon Sep 17 00:00:00 2001 From: hathach Date: Fri, 15 Mar 2024 20:39:45 +0700 Subject: improve uvc debug message --- src/class/video/video.h | 23 ++-- src/class/video/video_device.c | 223 ++++++++++++++++++++++------------ src/device/usbd.c | 2 +- src/portable/nordic/nrf5x/dcd_nrf5x.c | 4 +- 4 files changed, 157 insertions(+), 95 deletions(-) (limited to 'src/class') 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..dc3f8d897 100644 --- a/src/class/video/video_device.c +++ b/src/class/video/video_device.c @@ -143,13 +143,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 +210,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 +220,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 +228,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 +246,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 +285,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 +307,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 +458,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 +482,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 +527,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 +561,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 +589,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 +609,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; @@ -681,8 +739,7 @@ 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 = (video_probe_and_commit_control_t *)&stm->ep_buf; tu_memclr(param, sizeof(*param)); return _update_streaming_parameters(stm, param); } @@ -760,6 +817,10 @@ static uint_fast16_t _prepare_in_payload(videod_streaming_interface_t *stm) pkt_len = hdr_len + remaining; } uint_fast16_t data_len = pkt_len - hdr_len; + TU_LOG2(" prepare remain = %u, hdr_len = %u, pkt_len = %u, offset = %lu, data_len = %u\r\n", remaining, hdr_len, pkt_len, stm->offset, data_len); + if ( data_len > sizeof(stm->ep_buf) ) { + TU_BREAKPOINT(); + } memcpy(&stm->ep_buf[hdr_len], stm->buffer + stm->offset, data_len); stm->offset += data_len; remaining -= data_len; @@ -775,6 +836,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 +874,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 +941,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 +964,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 +980,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 +994,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; @@ -962,6 +1027,7 @@ static int handle_video_stm_cs_req(uint8_t rhport, uint8_t stage, self->state = VS_STATE_PROBING; _init_vs_configuration(self); } + switch (request->bRequest) { case VIDEO_REQUEST_SET_CUR: if (stage == CONTROL_STAGE_SETUP) { @@ -975,8 +1041,7 @@ 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); } @@ -986,8 +1051,7 @@ 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; @@ -997,8 +1061,7 @@ static int handle_video_stm_cs_req(uint8_t rhport, uint8_t stage, 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 +1069,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); } @@ -1046,16 +1108,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); } 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 +1123,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); } @@ -1264,6 +1323,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 +1339,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; 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/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; -- cgit v1.3.1 From ff12544c9ac1f61c5d25d58608f16f5991e9f776 Mon Sep 17 00:00:00 2001 From: hathach Date: Wed, 20 Mar 2024 22:45:46 +0700 Subject: added dedicate buffer for probe commit payload --- src/class/video/video_device.c | 45 ++++++++++++++++-------------------------- 1 file changed, 17 insertions(+), 28 deletions(-) (limited to 'src/class') diff --git a/src/class/video/video_device.c b/src/class/video/video_device.c index dc3f8d897..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; @@ -734,12 +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); } @@ -816,11 +817,8 @@ 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; - TU_LOG2(" prepare remain = %u, hdr_len = %u, pkt_len = %u, offset = %lu, data_len = %u\r\n", remaining, hdr_len, pkt_len, stm->offset, data_len); - if ( data_len > sizeof(stm->ep_buf) ) { - TU_BREAKPOINT(); - } memcpy(&stm->ep_buf[hdr_len], stm->buffer + stm->offset, data_len); stm->offset += data_len; remaining -= data_len; @@ -1025,17 +1023,15 @@ 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; @@ -1043,7 +1039,7 @@ static int handle_video_stm_cs_req(uint8_t rhport, uint8_t stage, case VIDEO_REQUEST_GET_CUR: 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; @@ -1053,8 +1049,7 @@ static int handle_video_stm_cs_req(uint8_t rhport, uint8_t stage, case VIDEO_REQUEST_GET_DEF: 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); } @@ -1083,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; @@ -1110,7 +1104,7 @@ static int handle_video_stm_cs_req(uint8_t rhport, uint8_t stage, case VIDEO_REQUEST_GET_CUR: 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; @@ -1224,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)); @@ -1236,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]; @@ -1249,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); @@ -1309,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); @@ -1348,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 */ -- cgit v1.3.1 From 74bd2647589790b3bee49146774133c2061a34fe Mon Sep 17 00:00:00 2001 From: hathach Date: Fri, 22 Mar 2024 11:42:33 +0700 Subject: adding deinit() stub for usbh/hcd class driver add TUSB_VERSION_BUILD, also add TUSB_VERSION_NUMBER --- src/class/cdc/cdc_host.c | 4 ++++ src/class/cdc/cdc_host.h | 1 + src/class/hid/hid_host.c | 4 ++++ src/class/hid/hid_host.h | 1 + src/class/msc/msc_host.c | 5 +++++ src/class/msc/msc_host.h | 1 + src/host/hcd.h | 3 +++ src/host/hub.c | 7 ++++-- src/host/hub.h | 1 + src/host/usbh.c | 55 ++++++++++++++++++++++++++++++++++++------------ src/host/usbh.h | 4 ++++ src/host/usbh_pvt.h | 4 +--- src/tusb_option.h | 5 +++++ 13 files changed, 76 insertions(+), 19 deletions(-) (limited to 'src/class') diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index 2fb37d835..14f380b40 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -637,6 +637,10 @@ void cdch_init(void) { } } +bool cdch_deinit(void) { + return true; +} + void cdch_close(uint8_t daddr) { for (uint8_t idx = 0; idx < CFG_TUH_CDC; idx++) { cdch_interface_t* p_cdc = &cdch_data[idx]; diff --git a/src/class/cdc/cdc_host.h b/src/class/cdc/cdc_host.h index d512a23a5..7530b1e9d 100644 --- a/src/class/cdc/cdc_host.h +++ b/src/class/cdc/cdc_host.h @@ -193,6 +193,7 @@ TU_ATTR_WEAK extern void tuh_cdc_tx_complete_cb(uint8_t idx); // Internal Class Driver API //--------------------------------------------------------------------+ void 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..16e2d3c2c 100644 --- a/src/class/hid/hid_host.c +++ b/src/class/hid/hid_host.c @@ -376,6 +376,10 @@ void hidh_init(void) { tu_memclr(_hidh_itf, sizeof(_hidh_itf)); } +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) { (void) result; diff --git a/src/class/hid/hid_host.h b/src/class/hid/hid_host.h index 17f4e27c0..9ea222b3d 100644 --- a/src/class/hid/hid_host.h +++ b/src/class/hid/hid_host.h @@ -164,6 +164,7 @@ 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_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..61ecb8e4e 100644 --- a/src/class/msc/msc_host.c +++ b/src/class/msc/msc_host.c @@ -288,6 +288,11 @@ void msch_init(void) { tu_memclr(_msch_itf, sizeof(_msch_itf)); } +bool msch_deinit(void) { + return true; +} + + void msch_close(uint8_t dev_addr) { TU_VERIFY(dev_addr <= CFG_TUH_DEVICE_MAX,); msch_interface_t* p_msc = get_itf(dev_addr); diff --git a/src/class/msc/msc_host.h b/src/class/msc/msc_host.h index 9ca1b4703..5bf2e62e3 100644 --- a/src/class/msc/msc_host.h +++ b/src/class/msc/msc_host.h @@ -114,6 +114,7 @@ TU_ATTR_WEAK void tuh_msc_umount_cb(uint8_t dev_addr); //--------------------------------------------------------------------+ void 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/host/hcd.h b/src/host/hcd.h index 2bde289df..d5804c608 100644 --- a/src/host/hcd.h +++ b/src/host/hcd.h @@ -130,6 +130,9 @@ bool hcd_configure(uint8_t rhport, uint32_t cfg_id, const void* cfg_param) TU_AT // 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..0853ff27a 100644 --- a/src/host/hub.c +++ b/src/host/hub.c @@ -182,11 +182,14 @@ 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) -{ +void hub_init(void) { tu_memclr(hub_data, sizeof(hub_data)); } +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) { (void) rhport; diff --git a/src/host/hub.h b/src/host/hub.h index 390740e1f..c3f4a3612 100644 --- a/src/host/hub.h +++ b/src/host/hub.h @@ -205,6 +205,7 @@ 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_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..cf348bbb2 100644 --- a/src/host/usbh.c +++ b/src/host/usbh.c @@ -45,8 +45,13 @@ #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 void tuh_event_hook_cb(uint8_t rhport, uint32_t eventid, bool in_isr) { (void) rhport; (void) eventid; @@ -119,16 +124,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 +144,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 +156,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 +168,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 +180,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 } @@ -338,11 +349,11 @@ 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; - TU_LOG_USBH("USBH init on controller %u\r\n", controller_id); + TU_LOG_USBH("USBH init on controller %u\r\n", rhport); TU_LOG_INT_USBH(sizeof(usbh_device_t)); TU_LOG_INT_USBH(sizeof(hcd_event_t)); TU_LOG_INT_USBH(sizeof(_ctrl_xfer)); @@ -383,10 +394,26 @@ bool tuh_init(uint8_t controller_id) { } } - _usbh_controller = controller_id;; + _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; + + hcd_int_disable(rhport); + hcd_deinit(rhport); - TU_ASSERT(hcd_init(controller_id)); - hcd_int_enable(controller_id); + _usbh_controller = TUSB_INDEX_INVALID_8; + + // no other controller is active, deinit the stack + if (!tuh_inited()) { + + } return true; } diff --git a/src/host/usbh.h b/src/host/usbh.h index 9ff118543..0e31e80a7 100644 --- a/src/host/usbh.h +++ b/src/host/usbh.h @@ -109,7 +109,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..204315175 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 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/tusb_option.h b/src/tusb_option.h index 96378cb80..22f27e9e1 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 1 + +#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) //--------------------------------------------------------------------+ -- cgit v1.3.1 From e84c9f3e221092687808f175e1e19732a10fea72 Mon Sep 17 00:00:00 2001 From: hathach Date: Fri, 22 Mar 2024 16:12:57 +0700 Subject: implement tuh_init() change usbh driver init() return type from void to bool --- src/class/cdc/cdc_host.c | 12 +++++-- src/class/cdc/cdc_host.h | 2 +- src/class/hid/hid_host.c | 4 ++- src/class/hid/hid_host.h | 2 +- src/class/msc/msc_host.c | 5 +-- src/class/msc/msc_host.h | 2 +- src/host/hub.c | 3 +- src/host/hub.h | 12 +++---- src/host/usbh.c | 85 ++++++++++++++++++++++++++++++------------------ src/host/usbh_pvt.h | 2 +- 10 files changed, 79 insertions(+), 50 deletions(-) (limited to 'src/class') diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index 14f380b40..5bdd41f1f 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -621,12 +621,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]; - 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); @@ -635,9 +634,16 @@ 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; } diff --git a/src/class/cdc/cdc_host.h b/src/class/cdc/cdc_host.h index 7530b1e9d..b63dd1530 100644 --- a/src/class/cdc/cdc_host.h +++ b/src/class/cdc/cdc_host.h @@ -192,7 +192,7 @@ 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); diff --git a/src/class/hid/hid_host.c b/src/class/hid/hid_host.c index 16e2d3c2c..efc54656e 100644 --- a/src/class/hid/hid_host.c +++ b/src/class/hid/hid_host.c @@ -372,8 +372,10 @@ 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) { diff --git a/src/class/hid/hid_host.h b/src/class/hid/hid_host.h index 9ea222b3d..0902bf1af 100644 --- a/src/class/hid/hid_host.h +++ b/src/class/hid/hid_host.h @@ -163,7 +163,7 @@ 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); diff --git a/src/class/msc/msc_host.c b/src/class/msc/msc_host.c index 61ecb8e4e..ce6e7fb2d 100644 --- a/src/class/msc/msc_host.c +++ b/src/class/msc/msc_host.c @@ -284,15 +284,16 @@ 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) { TU_VERIFY(dev_addr <= CFG_TUH_DEVICE_MAX,); msch_interface_t* p_msc = get_itf(dev_addr); diff --git a/src/class/msc/msc_host.h b/src/class/msc/msc_host.h index 5bf2e62e3..9fda566d8 100644 --- a/src/class/msc/msc_host.h +++ b/src/class/msc/msc_host.h @@ -113,7 +113,7 @@ 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); diff --git a/src/host/hub.c b/src/host/hub.c index 0853ff27a..e97014443 100644 --- a/src/host/hub.c +++ b/src/host/hub.c @@ -182,8 +182,9 @@ 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) { diff --git a/src/host/hub.h b/src/host/hub.h index c3f4a3612..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,7 @@ 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); diff --git a/src/host/usbh.c b/src/host/usbh.c index cf348bbb2..1edc43fd6 100644 --- a/src/host/usbh.c +++ b/src/host/usbh.c @@ -351,51 +351,55 @@ bool tuh_inited(void) { 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_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); + // 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); #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; iname); - 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(); + } } } + // Init host controller _usbh_controller = rhport;; - TU_ASSERT(hcd_init(rhport)); hcd_int_enable(rhport); @@ -405,14 +409,31 @@ bool tuh_init(uint8_t rhport) { 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; - // no other controller is active, deinit the stack + // 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; + #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; diff --git a/src/host/usbh_pvt.h b/src/host/usbh_pvt.h index 204315175..95de915e9 100644 --- a/src/host/usbh_pvt.h +++ b/src/host/usbh_pvt.h @@ -51,7 +51,7 @@ enum { typedef struct { char const* name; - 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); -- cgit v1.3.1 From cab11064160deab42af654cd766bbfaca7f688cd Mon Sep 17 00:00:00 2001 From: HiFiPhile Date: Tue, 21 Nov 2023 18:06:57 +0100 Subject: dwc2: add endpoint allocation support. --- src/class/audio/audio_device.c | 4 +- src/portable/synopsys/dwc2/dcd_dwc2.c | 102 ++++++++++++++++++++++++++++++++++ 2 files changed, 104 insertions(+), 2 deletions(-) (limited to 'src/class') diff --git a/src/class/audio/audio_device.c b/src/class/audio/audio_device.c index 4adc558a6..293defd96 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 diff --git a/src/portable/synopsys/dwc2/dcd_dwc2.c b/src/portable/synopsys/dwc2/dcd_dwc2.c index 3f00243e5..b0149a9a9 100644 --- a/src/portable/synopsys/dwc2/dcd_dwc2.c +++ b/src/portable/synopsys/dwc2/dcd_dwc2.c @@ -648,6 +648,108 @@ 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) +{ + (void)rhport; + + TU_ASSERT(largest_packet_size <= 1024); + + 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(largest_packet_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; + } + + } 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); + } + + return true; +} + +bool dcd_edpt_iso_activate(uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc) +{ + (void)rhport; + + 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; + + if (dir == TUSB_DIR_OUT) { + dwc2->epout[epnum].doepctl |= (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); + + dwc2->daintmsk |= TU_BIT(DAINTMSK_OEPM_Pos + epnum); + } else + { + dwc2->epin[epnum].diepctl |= (1 << DIEPCTL_USBAEP_Pos) | + (epnum << DIEPCTL_TXFNUM_Pos) | + (p_endpoint_desc->bmAttributes.xfer << DIEPCTL_EPTYP_Pos) | + (p_endpoint_desc->bmAttributes.xfer != TUSB_XFER_ISOCHRONOUS ? DIEPCTL_SD0PID_SEVNFRM : 0) | + (xfer->max_size << DIEPCTL_MPSIZ_Pos); + + dwc2->daintmsk |= (1 << (DAINTMSK_IEPM_Pos + epnum)); + } + + 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); -- cgit v1.3.1 From 2012a0d369badbc671ac061184ddc3f5961e985e Mon Sep 17 00:00:00 2001 From: hathach Date: Sun, 31 Mar 2024 15:48:26 +0700 Subject: fix hid close not clear data --- src/class/hid/hid_host.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'src/class') diff --git a/src/class/hid/hid_host.c b/src/class/hid/hid_host.c index efc54656e..621fb2a55 100644 --- a/src/class/hid/hid_host.c +++ b/src/class/hid/hid_host.c @@ -410,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)); } } } -- cgit v1.3.1 From 05f9cab1916195ceb55d73efa56d226b2451f5d1 Mon Sep 17 00:00:00 2001 From: HiFiPhile Date: Mon, 1 Apr 2024 19:48:45 +0200 Subject: UAC2: refactor interrupt endpoint support. --- src/class/audio/audio.h | 25 +++++++++ src/class/audio/audio_device.c | 114 ++++++++++++++++++----------------------- src/class/audio/audio_device.h | 51 +++--------------- src/device/usbd.h | 11 ++-- 4 files changed, 88 insertions(+), 113 deletions(-) (limited to 'src/class') 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 f4e7de0c8..93e995c56 100644 --- a/src/class/audio/audio_device.c +++ b/src/class/audio/audio_device.c @@ -301,8 +301,8 @@ typedef struct #endif -#if CFG_TUD_AUDIO_INT_EPSIZE_IN - uint8_t ep_int; // Audio control interrupt EP. +#if CFG_TUD_AUDIO_ENABLE_INTERRUPT_EP + uint8_t ep_int; // Audio control interrupt EP. #endif /*------------- From this point, data is not cleared by bus reset -------------*/ @@ -358,8 +358,8 @@ typedef struct #endif // Audio control interrupt buffer - no FIFO - 6 Bytes according to UAC 2 specification (p. 74) -#if CFG_TUD_AUDIO_INT_EPSIZE_IN - CFG_TUSB_MEM_ALIGN uint8_t ep_int_buf[CFG_TUD_AUDIO_INT_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 @@ -826,26 +826,29 @@ tu_fifo_t* tud_audio_n_get_tx_support_ff(uint8_t func_id, uint8_t ff_idx) #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 -uint16_t tud_audio_int_n_write(uint8_t func_id, uint8_t const* buffer, uint16_t len) +bool tud_audio_int_n_write(uint8_t func_id, const audio_interrupt_data_t * data) { - TU_VERIFY(_audiod_fct[func_id].ep_int != 0); - TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL); + TU_VERIFY(_audiod_fct[func_id].ep_int != 0); + // 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)); + TU_VERIFY(usbd_edpt_claim(_audiod_fct[func_id].rhport, _audiod_fct[func_id].ep_int)); // Check length - TU_VERIFY(tu_memcpy_s(_audiod_fct[func_id].ep_int_buf, CFG_TUD_AUDIO_INT_EP_IN_SW_BUFFER_SIZE, buffer, len)==0); - - // Schedule transmit - TU_VERIFY(usbd_edpt_xfer(_audiod_fct[func_id].rhport, _audiod_fct[func_id].ep_int, _audiod_fct[func_id].ep_int_buf, len)); + 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. @@ -1091,48 +1094,6 @@ static inline bool audiod_fb_send(uint8_t rhport, audiod_function_t *audio) } #endif -#if CFG_TUD_AUDIO_ENABLE_INTERRUPT_EP -static bool set_int_number(audiod_function_t *audio) -{ - - uint8_t const *p_desc = audio->p_desc; - // Get pointer at end - uint8_t const *p_desc_end = audio->p_desc + audio->desc_length - TUD_AUDIO_DESC_IAD_LEN; - - - bool found = false; - while (!found && p_desc < p_desc_end) - { - // For each interface/alternate - if (tu_desc_type(p_desc) == TUSB_DESC_INTERFACE) - { - uint8_t foundEPs = 0, nEps = ((tusb_desc_interface_t const * )p_desc)->bNumEndpoints; - while (!found && foundEPs < nEps && p_desc < p_desc_end) - { - // 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 == 0x03) // Check if usage is interrupt EP - { - // Store endpoint number and open endpoint - audio->ep_int = ep_addr; - TU_ASSERT(usbd_edpt_open(audio->rhport, desc_ep)); - found = true; - } - foundEPs += 1; - } - p_desc = tu_desc_next(p_desc); - } - } - p_desc = tu_desc_next(p_desc); - } - return found; -} -#endif - //--------------------------------------------------------------------+ // USBD Driver API //--------------------------------------------------------------------+ @@ -1492,10 +1453,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_EPSIZE_IN > 0); + TU_ASSERT(CFG_TUD_AUDIO_ENABLE_INTERRUPT_EP); } // Alternate setting MUST be zero - this check can be omitted @@ -1639,6 +1601,31 @@ 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 + break; } } @@ -1649,10 +1636,6 @@ uint16_t audiod_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uin // This is all we need so far - the EPs are setup by a later set_interface request (as per UAC2 specification) uint16_t drv_len = _audiod_fct[i].desc_length - TUD_AUDIO_DESC_IAD_LEN; // - TUD_AUDIO_DESC_IAD_LEN since tinyUSB already handles the IAD descriptor -#if CFG_TUD_AUDIO_ENABLE_INTERRUPT_EP - TU_ASSERT(set_int_number(&_audiod_fct[i])); -#endif - return drv_len; } @@ -2169,7 +2152,7 @@ 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_EPSIZE_IN +#if CFG_TUD_AUDIO_ENABLE_INTERRUPT_EP // Data transmission of control interrupt finished if (audio->ep_int == ep_addr) @@ -2181,7 +2164,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_done_cb) TU_VERIFY(tud_audio_int_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 70bbd7ff6..040a760d6 100644 --- a/src/class/audio/audio_device.h +++ b/src/class/audio/audio_device.h @@ -198,21 +198,7 @@ // 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 - -// Audio interrupt control EP size - disabled if 0 -#ifndef CFG_TUD_AUDIO_INT_EPSIZE_IN -// Audio interrupt control - if required - 6 Bytes according to UAC 2 specification (p. 74) -#if CFG_TUD_AUDIO_ENABLE_INTERRUPT_EP -#define CFG_TUD_AUDIO_INT_EPSIZE_IN 6 -#else -#define CFG_TUD_AUDIO_INT_EPSIZE_IN 0 -#endif -#endif - -#ifndef CFG_TUD_AUDIO_INT_EP_IN_SW_BUFFER_SIZE -#define CFG_TUD_AUDIO_INT_EP_IN_SW_BUFFER_SIZE 6 // Buffer size of audio control interrupt EP - 6 Bytes according to UAC 2 specification (p. 74) +#define CFG_TUD_AUDIO_ENABLE_INTERRUPT_EP 0 // Feedback - 0 or 1 #endif // Use software encoding/decoding @@ -404,7 +390,7 @@ tu_fifo_t* tud_audio_n_get_tx_support_ff (uint8_t func_id, uint8_t ff_i #endif #if CFG_TUD_AUDIO_ENABLE_INTERRUPT_EP -uint16_t tud_audio_int_n_write (uint8_t func_id, uint8_t const* buffer, uint16_t len); +bool tud_audio_int_n_write (uint8_t func_id, const audio_interrupt_data_t * data); #endif @@ -448,7 +434,7 @@ static inline tu_fifo_t* tud_audio_get_tx_support_ff (uint8_t ff_idx); // INT CTR API #if CFG_TUD_AUDIO_ENABLE_INTERRUPT_EP -static inline uint16_t tud_audio_int_write (uint8_t const* buffer, uint16_t len); +static inline bool tud_audio_int_write (const audio_interrupt_data_t * data); #endif // Buffer control EP data and schedule a transmit @@ -548,32 +534,7 @@ 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_ENABLE_INTERRUPT_EP -// UAC2 §6.1 "interrupt data message" -typedef struct TU_ATTR_PACKED -{ - uint8_t bInfo; - uint8_t bAttribute; - union TU_ATTR_PACKED - { - uint16_t wValue; - struct TU_ATTR_PACKED - { - uint8_t wValue_cn_or_mcn; - uint8_t wValue_cs; - }; - }; - union TU_ATTR_PACKED - { - uint16_t wIndex; - struct TU_ATTR_PACKED - { - uint8_t wIndex_ep_or_int; - uint8_t wIndex_entity_id; - }; - }; -} audio_status_update_t; - -TU_ATTR_WEAK bool tud_audio_int_done_cb(uint8_t rhport, uint16_t n_bytes_copied); +TU_ATTR_WEAK void tud_audio_int_done_cb(uint8_t rhport); #endif // Invoked when audio set interface request received @@ -705,9 +666,9 @@ static inline tu_fifo_t* tud_audio_get_tx_support_ff(uint8_t ff_idx) #endif #if CFG_TUD_AUDIO_ENABLE_INTERRUPT_EP -static inline uint16_t tud_audio_int_write(uint8_t const* buffer, uint16_t len) +static inline bool tud_audio_int_write(const audio_interrupt_data_t * data) { - return tud_audio_int_n_write(0, buffer, len); + return tud_audio_int_n_write(0, data); } #endif diff --git a/src/device/usbd.h b/src/device/usbd.h index cf500143a..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) \ @@ -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) */\ -- cgit v1.3.1 From 7ca988018ee057a66ab7d5635069fbc695182d2d Mon Sep 17 00:00:00 2001 From: HiFiPhile Date: Mon, 1 Apr 2024 19:50:52 +0200 Subject: UAC2: fix mounted condition. --- src/class/audio/audio_device.c | 21 ++++----------------- 1 file changed, 4 insertions(+), 17 deletions(-) (limited to 'src/class') diff --git a/src/class/audio/audio_device.c b/src/class/audio/audio_device.c index 93e995c56..9a361419b 100644 --- a/src/class/audio/audio_device.c +++ b/src/class/audio/audio_device.c @@ -305,6 +305,8 @@ typedef struct 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 @@ -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_ENABLE_INTERRUPT_EP - if (audio->ep_int == 0) return false; -#endif - -#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP - if (audio->ep_fb == 0) return false; -#endif - - return true; + return audio->mounted; } //--------------------------------------------------------------------+ @@ -1626,6 +1612,7 @@ uint16_t audiod_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uin } #endif + _audiod_fct[i].mounted = true; break; } } -- cgit v1.3.1 From db28437218244ae9a1e16d87964edd51f78f54bd Mon Sep 17 00:00:00 2001 From: HiFiPhile Date: Tue, 2 Apr 2024 14:17:24 +0200 Subject: Move endpoint alloc define to tusb_mcu.h --- src/class/audio/audio_device.c | 19 ++++++------------- src/common/tusb_mcu.h | 4 ++++ 2 files changed, 10 insertions(+), 13 deletions(-) (limited to 'src/class') diff --git a/src/class/audio/audio_device.c b/src/class/audio/audio_device.c index 9a361419b..2af3da324 100644 --- a/src/class/audio/audio_device.c +++ b/src/class/audio/audio_device.c @@ -96,13 +96,6 @@ #define USE_LINEAR_BUFFER 1 #endif -// 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 -#endif - // Declaration of buffers // Check for maximum supported numbers @@ -1476,7 +1469,7 @@ uint16_t audiod_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uin #endif } -#if USE_ISO_EP_ALLOCATION +#ifdef TUP_DCD_EDPT_ISO_ALLOC { #if CFG_TUD_AUDIO_ENABLE_EP_IN uint8_t ep_in = 0; @@ -1552,7 +1545,7 @@ uint16_t audiod_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uin } #endif } -#endif // USE_ISO_EP_ALLOCATION +#endif // TUP_DCD_EDPT_ISO_ALLOC #if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_EP_IN_FLOW_CONTROL { @@ -1674,7 +1667,7 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const * if (audio->ep_in_as_intf_num == itf) { audio->ep_in_as_intf_num = 0; - #if !USE_ISO_EP_ALLOCATION + #ifndef TUP_DCD_EDPT_ISO_ALLOC usbd_edpt_close(rhport, audio->ep_in); #endif @@ -1705,7 +1698,7 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const * if (audio->ep_out_as_intf_num == itf) { audio->ep_out_as_intf_num = 0; - #if !USE_ISO_EP_ALLOCATION + #ifndef TUP_DCD_EDPT_ISO_ALLOC usbd_edpt_close(rhport, audio->ep_out); #endif @@ -1726,7 +1719,7 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const * // Close corresponding feedback EP #if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP - #if !USE_ISO_EP_ALLOCATION + #ifndef TUP_DCD_EDPT_ISO_ALLOC usbd_edpt_close(rhport, audio->ep_fb); #endif audio->ep_fb = 0; @@ -1758,7 +1751,7 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const * if (tu_desc_type(p_desc) == TUSB_DESC_ENDPOINT) { tusb_desc_endpoint_t const* desc_ep = (tusb_desc_endpoint_t const *) p_desc; -#if USE_ISO_EP_ALLOCATION +#ifdef TUP_DCD_EDPT_ISO_ALLOC TU_ASSERT(usbd_edpt_iso_activate(rhport, desc_ep)); #else TU_ASSERT(usbd_edpt_open(rhport, desc_ep)); diff --git a/src/common/tusb_mcu.h b/src/common/tusb_mcu.h index 308ee713c..1ee20ba07 100644 --- a/src/common/tusb_mcu.h +++ b/src/common/tusb_mcu.h @@ -434,4 +434,8 @@ #define TU_ATTR_FAST_FUNC #endif +#if defined(TUP_USBIP_DWC2) || defined(TUP_USBIP_FSDEV) + #define TUP_DCD_EDPT_ISO_ALLOC +#endif + #endif -- cgit v1.3.1 From 2e4d4e4a017202e4aef2a8f3027a29da0f47cd32 Mon Sep 17 00:00:00 2001 From: HiFiPhile Date: Tue, 2 Apr 2024 15:29:16 +0200 Subject: Add endpoint ISO allocation to video class. --- src/class/video/video_device.c | 47 ++++++++++++++++++++++++++++++++---------- 1 file changed, 36 insertions(+), 11 deletions(-) (limited to 'src/class') diff --git a/src/class/video/video_device.c b/src/class/video/video_device.c index 5306356ba..648c8c3c8 100644 --- a/src/class/video/video_device.c +++ b/src/class/video/video_device.c @@ -759,10 +759,15 @@ static bool _open_vs_itf(uint8_t rhport, videod_streaming_interface_t *stm, uint for (i = 0; i < TU_ARRAY_SIZE(stm->desc.ep); ++i) { uint_fast16_t ofs_ep = stm->desc.ep[i]; if (!ofs_ep) break; - uint8_t ep_adr = _desc_ep_addr(desc + ofs_ep); - usbd_edpt_close(rhport, ep_adr); - stm->desc.ep[i] = 0; - TU_LOG_DRV(" close EP%02x\r\n", ep_adr); + tusb_desc_endpoint_t const *ep = (tusb_desc_endpoint_t const*)(desc + ofs_ep); + /* Only ISO endpoints needs to be closed */ + if(ep->bmAttributes.xfer == TUSB_XFER_ISOCHRONOUS) { +#ifndef TUP_DCD_EDPT_ISO_ALLOC + usbd_edpt_close(rhport, ep->bEndpointAddress); +#endif + stm->desc.ep[i] = 0; + TU_LOG_DRV(" close EP%02x\r\n", ep->bEndpointAddress); + } } /* clear transfer management information */ @@ -788,16 +793,18 @@ static bool _open_vs_itf(uint8_t rhport, videod_streaming_interface_t *stm, uint TU_ASSERT(cur < end); tusb_desc_endpoint_t const *ep = (tusb_desc_endpoint_t const*)cur; uint_fast32_t max_size = stm->max_payload_transfer_size; - if (altnum) { - if ((TUSB_XFER_ISOCHRONOUS == ep->bmAttributes.xfer) && - (tu_edpt_packet_size(ep) < max_size)) { - /* FS must be less than or equal to max packet size */ - return false; - } + if (altnum && (TUSB_XFER_ISOCHRONOUS == ep->bmAttributes.xfer)) { + /* FS must be less than or equal to max packet size */ + TU_VERIFY (tu_edpt_packet_size(ep) >= max_size); +#ifdef TUP_DCD_EDPT_ISO_ALLOC + usbd_edpt_iso_activate(rhport, ep); +#else + TU_ASSERT(usbd_edpt_open(rhport, ep)); +#endif } else { TU_VERIFY(TUSB_XFER_BULK == ep->bmAttributes.xfer); + TU_ASSERT(usbd_edpt_open(rhport, ep)); } - TU_ASSERT(usbd_edpt_open(rhport, ep)); stm->desc.ep[i] = (uint16_t) (cur - desc); TU_LOG_DRV(" open EP%02x\r\n", _desc_ep_addr(cur)); } @@ -1283,6 +1290,24 @@ uint16_t videod_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uin cur = _next_desc_itf(cur, end); stm->desc.end = (uint16_t) ((uintptr_t)cur - (uintptr_t)itf_desc); stm->state = VS_STATE_PROBING; +#ifdef TUP_DCD_EDPT_ISO_ALLOC + /* Allocate ISO endpoints */ + uint16_t ep_size = 0; + uint16_t ep_addr = 0; + uint8_t const *p_desc = (uint8_t const*)itf_desc + stm->desc.beg; + uint8_t const *p_desc_end = (uint8_t const*)itf_desc + stm->desc.end; + while (p_desc < p_desc_end) { + if (tu_desc_type(p_desc) == TUSB_DESC_ENDPOINT) { + tusb_desc_endpoint_t const *desc_ep = (tusb_desc_endpoint_t const *) p_desc; + if (desc_ep->bmAttributes.xfer == TUSB_XFER_ISOCHRONOUS) { + ep_addr = desc_ep->bEndpointAddress; + ep_size = TU_MAX(tu_edpt_packet_size(desc_ep), ep_size); + } + } + p_desc = tu_desc_next(p_desc); + } + if(ep_addr > 0 && ep_size > 0) usbd_edpt_iso_alloc(rhport, ep_addr, ep_size); +#endif if (0 == stm_idx && 1 == bInCollection) { /* If there is only one streaming interface and no alternate settings, * host may not issue set_interface so open the streaming interface here. */ -- cgit v1.3.1 From e642066562f96e7e4790b709635d32d4c8450861 Mon Sep 17 00:00:00 2001 From: HiFiPhile Date: Sat, 6 Apr 2024 19:02:50 +0200 Subject: Move TUP_DCD_EDPT_ISO_ALLOC outside usbd_edpt_close() loop. --- src/class/video/video_device.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/class') diff --git a/src/class/video/video_device.c b/src/class/video/video_device.c index 648c8c3c8..891ece721 100644 --- a/src/class/video/video_device.c +++ b/src/class/video/video_device.c @@ -755,6 +755,7 @@ static bool _open_vs_itf(uint8_t rhport, videod_streaming_interface_t *stm, uint TU_LOG_DRV(" reopen VS %d\r\n", altnum); uint8_t const *desc = _videod_itf[stm->index_vc].beg; +#ifndef TUP_DCD_EDPT_ISO_ALLOC /* Close endpoints of previous settings. */ for (i = 0; i < TU_ARRAY_SIZE(stm->desc.ep); ++i) { uint_fast16_t ofs_ep = stm->desc.ep[i]; @@ -762,13 +763,12 @@ static bool _open_vs_itf(uint8_t rhport, videod_streaming_interface_t *stm, uint tusb_desc_endpoint_t const *ep = (tusb_desc_endpoint_t const*)(desc + ofs_ep); /* Only ISO endpoints needs to be closed */ if(ep->bmAttributes.xfer == TUSB_XFER_ISOCHRONOUS) { -#ifndef TUP_DCD_EDPT_ISO_ALLOC usbd_edpt_close(rhport, ep->bEndpointAddress); -#endif stm->desc.ep[i] = 0; TU_LOG_DRV(" close EP%02x\r\n", ep->bEndpointAddress); } } +#endif /* clear transfer management information */ stm->buffer = NULL; -- cgit v1.3.1 From c3c06484560d0102366a3a1b1101c35301009f97 Mon Sep 17 00:00:00 2001 From: hathach Date: Mon, 8 Apr 2024 22:07:56 +0700 Subject: add class driver deinit --- src/class/audio/audio_device.c | 4 + src/class/audio/audio_device.h | 1 + src/class/bth/bth_device.c | 7 +- src/class/bth/bth_device.h | 1 + src/class/cdc/cdc_device.c | 32 ++++- src/class/cdc/cdc_device.h | 1 + src/class/dfu/dfu_device.c | 7 +- src/class/dfu/dfu_device.h | 1 + src/class/dfu/dfu_rt_device.c | 7 +- src/class/dfu/dfu_rt_device.h | 1 + src/class/hid/hid_device.c | 7 +- src/class/hid/hid_device.h | 1 + src/class/midi/midi_device.c | 36 ++++- src/class/midi/midi_device.h | 1 + src/class/msc/msc_device.c | 8 +- src/class/msc/msc_device.h | 1 + src/class/net/ecm_rndis_device.c | 7 +- src/class/net/ncm_device.c | 4 + src/class/net/net_device.h | 1 + src/class/usbtmc/usbtmc_device.c | 5 + src/class/usbtmc/usbtmc_device.h | 3 +- src/class/vendor/vendor_device.c | 38 ++++- src/class/vendor/vendor_device.h | 1 + src/class/video/video_device.c | 4 + src/class/video/video_device.h | 1 + src/device/dcd.h | 2 +- src/device/usbd.c | 204 +++++++++++++++++---------- src/device/usbd.h | 2 +- src/device/usbd_pvt.h | 4 +- src/host/usbh.c | 2 +- src/portable/raspberrypi/rp2040/dcd_rp2040.c | 5 +- src/portable/raspberrypi/rp2040/hcd_rp2040.c | 4 +- src/tusb_option.h | 2 +- 33 files changed, 292 insertions(+), 113 deletions(-) (limited to 'src/class') diff --git a/src/class/audio/audio_device.c b/src/class/audio/audio_device.c index 9a361419b..7077d66f8 100644 --- a/src/class/audio/audio_device.c +++ b/src/class/audio/audio_device.c @@ -1396,6 +1396,10 @@ void audiod_init(void) } } +bool audiod_deinit(void) { + return false; // TODO not implemented yet +} + void audiod_reset(uint8_t rhport) { (void) rhport; diff --git a/src/class/audio/audio_device.h b/src/class/audio/audio_device.h index 040a760d6..b16514fd4 100644 --- a/src/class/audio/audio_device.h +++ b/src/class/audio/audio_device.h @@ -685,6 +685,7 @@ static inline bool tud_audio_fb_set(uint32_t feedback) // Internal Class Driver API //--------------------------------------------------------------------+ void audiod_init (void); +bool audiod_deinit (void); void audiod_reset (uint8_t rhport); uint16_t audiod_open (uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len); bool audiod_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request); diff --git a/src/class/bth/bth_device.c b/src/class/bth/bth_device.c index f145e2ead..cbf6e1332 100755 --- a/src/class/bth/bth_device.c +++ b/src/class/bth/bth_device.c @@ -91,11 +91,14 @@ bool tud_bt_acl_data_send(void *event, uint16_t event_len) //--------------------------------------------------------------------+ // USBD Driver API //--------------------------------------------------------------------+ -void btd_init(void) -{ +void btd_init(void) { tu_memclr(&_btd_itf, sizeof(_btd_itf)); } +bool btd_deinit(void) { + return true; +} + void btd_reset(uint8_t rhport) { (void)rhport; diff --git a/src/class/bth/bth_device.h b/src/class/bth/bth_device.h index e782c532b..4f6350839 100755 --- a/src/class/bth/bth_device.h +++ b/src/class/bth/bth_device.h @@ -104,6 +104,7 @@ bool tud_bt_acl_data_send(void *acl_data, uint16_t data_len); // Internal Class Driver API //--------------------------------------------------------------------+ void btd_init (void); +bool btd_deinit (void); void btd_reset (uint8_t rhport); uint16_t btd_open (uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len); bool btd_control_xfer_cb (uint8_t rhport, uint8_t stage, tusb_control_request_t const *request); diff --git a/src/class/cdc/cdc_device.c b/src/class/cdc/cdc_device.c index c26264e60..7ef0530ec 100644 --- a/src/class/cdc/cdc_device.c +++ b/src/class/cdc/cdc_device.c @@ -253,11 +253,39 @@ void cdcd_init(void) // In this way, the most current data is prioritized. tu_fifo_config(&p_cdc->tx_ff, p_cdc->tx_ff_buf, TU_ARRAY_SIZE(p_cdc->tx_ff_buf), 1, true); - tu_fifo_config_mutex(&p_cdc->rx_ff, NULL, osal_mutex_create(&p_cdc->rx_ff_mutex)); - tu_fifo_config_mutex(&p_cdc->tx_ff, osal_mutex_create(&p_cdc->tx_ff_mutex), NULL); + #if OSAL_MUTEX_REQUIRED + osal_mutex_t mutex_rd = osal_mutex_create(&p_cdc->rx_ff_mutex); + osal_mutex_t mutex_wr = osal_mutex_create(&p_cdc->tx_ff_mutex); + TU_ASSERT(mutex_rd != NULL && mutex_wr != NULL, ); + + tu_fifo_config_mutex(&p_cdc->rx_ff, NULL, mutex_rd); + tu_fifo_config_mutex(&p_cdc->tx_ff, mutex_wr, NULL); + #endif } } +bool cdcd_deinit(void) { + #if OSAL_MUTEX_REQUIRED + for(uint8_t i=0; irx_ff.mutex_rd; + osal_mutex_t mutex_wr = p_cdc->tx_ff.mutex_wr; + + if (mutex_rd) { + osal_mutex_delete(mutex_rd); + tu_fifo_config_mutex(&p_cdc->rx_ff, NULL, NULL); + } + + if (mutex_wr) { + osal_mutex_delete(mutex_wr); + tu_fifo_config_mutex(&p_cdc->tx_ff, NULL, NULL); + } + } + #endif + + return true; +} + void cdcd_reset(uint8_t rhport) { (void) rhport; diff --git a/src/class/cdc/cdc_device.h b/src/class/cdc/cdc_device.h index a6e07aa5c..20e908451 100644 --- a/src/class/cdc/cdc_device.h +++ b/src/class/cdc/cdc_device.h @@ -247,6 +247,7 @@ static inline bool tud_cdc_write_clear(void) // INTERNAL USBD-CLASS DRIVER API //--------------------------------------------------------------------+ void cdcd_init (void); +bool cdcd_deinit (void); void cdcd_reset (uint8_t rhport); uint16_t cdcd_open (uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len); bool cdcd_control_xfer_cb (uint8_t rhport, uint8_t stage, tusb_control_request_t const * request); diff --git a/src/class/dfu/dfu_device.c b/src/class/dfu/dfu_device.c index 3e7c13dea..71e7ac2b3 100644 --- a/src/class/dfu/dfu_device.c +++ b/src/class/dfu/dfu_device.c @@ -160,11 +160,14 @@ void dfu_moded_reset(uint8_t rhport) reset_state(); } -void dfu_moded_init(void) -{ +void dfu_moded_init(void) { dfu_moded_reset(0); } +bool dfu_moded_deinit(void) { + return true; +} + uint16_t dfu_moded_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len) { (void) rhport; diff --git a/src/class/dfu/dfu_device.h b/src/class/dfu/dfu_device.h index fecf8596f..00c22ea8b 100644 --- a/src/class/dfu/dfu_device.h +++ b/src/class/dfu/dfu_device.h @@ -86,6 +86,7 @@ TU_ATTR_WEAK void tud_dfu_abort_cb(uint8_t alt); // Internal Class Driver API //--------------------------------------------------------------------+ void dfu_moded_init(void); +bool dfu_moded_deinit(void); void dfu_moded_reset(uint8_t rhport); uint16_t dfu_moded_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len); bool dfu_moded_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request); diff --git a/src/class/dfu/dfu_rt_device.c b/src/class/dfu/dfu_rt_device.c index a940d8d62..3b801b787 100644 --- a/src/class/dfu/dfu_rt_device.c +++ b/src/class/dfu/dfu_rt_device.c @@ -51,8 +51,11 @@ //--------------------------------------------------------------------+ // USBD Driver API //--------------------------------------------------------------------+ -void dfu_rtd_init(void) -{ +void dfu_rtd_init(void) { +} + +bool dfu_rtd_deinit(void) { + return true; } void dfu_rtd_reset(uint8_t rhport) diff --git a/src/class/dfu/dfu_rt_device.h b/src/class/dfu/dfu_rt_device.h index babaa8214..67eb26d95 100644 --- a/src/class/dfu/dfu_rt_device.h +++ b/src/class/dfu/dfu_rt_device.h @@ -43,6 +43,7 @@ void tud_dfu_runtime_reboot_to_dfu_cb(void); // Internal Class Driver API //--------------------------------------------------------------------+ void dfu_rtd_init(void); +bool dfu_rtd_deinit(void); void dfu_rtd_reset(uint8_t rhport); uint16_t dfu_rtd_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len); bool dfu_rtd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request); diff --git a/src/class/hid/hid_device.c b/src/class/hid/hid_device.c index 5637ea6b4..e8eda1400 100644 --- a/src/class/hid/hid_device.c +++ b/src/class/hid/hid_device.c @@ -166,11 +166,14 @@ bool tud_hid_n_gamepad_report(uint8_t instance, uint8_t report_id, //--------------------------------------------------------------------+ // USBD-CLASS API //--------------------------------------------------------------------+ -void hidd_init(void) -{ +void hidd_init(void) { hidd_reset(0); } +bool hidd_deinit(void) { + return true; +} + void hidd_reset(uint8_t rhport) { (void) rhport; diff --git a/src/class/hid/hid_device.h b/src/class/hid/hid_device.h index 17b24def1..53ecf9c06 100644 --- a/src/class/hid/hid_device.h +++ b/src/class/hid/hid_device.h @@ -406,6 +406,7 @@ static inline bool tud_hid_gamepad_report(uint8_t report_id, int8_t x, int8_t y // Internal Class Driver API //--------------------------------------------------------------------+ void hidd_init (void); +bool hidd_deinit (void); void hidd_reset (uint8_t rhport); uint16_t hidd_open (uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len); bool hidd_control_xfer_cb (uint8_t rhport, uint8_t stage, tusb_control_request_t const * request); diff --git a/src/class/midi/midi_device.c b/src/class/midi/midi_device.c index 052372a93..42905ab0d 100644 --- a/src/class/midi/midi_device.c +++ b/src/class/midi/midi_device.c @@ -373,12 +373,10 @@ bool tud_midi_n_packet_write (uint8_t itf, uint8_t const packet[4]) //--------------------------------------------------------------------+ // USBD Driver API //--------------------------------------------------------------------+ -void midid_init(void) -{ +void midid_init(void) { tu_memclr(_midid_itf, sizeof(_midid_itf)); - for(uint8_t i=0; itx_ff, midi->tx_ff_buf, CFG_TUD_MIDI_TX_BUFSIZE, 1, false); // OBVS. #if CFG_FIFO_MUTEX - tu_fifo_config_mutex(&midi->rx_ff, NULL, osal_mutex_create(&midi->rx_ff_mutex)); - tu_fifo_config_mutex(&midi->tx_ff, osal_mutex_create(&midi->tx_ff_mutex), NULL); + osal_mutex_t mutex_rd = osal_mutex_create(&midi->rx_ff_mutex); + osal_mutex_t mutex_wr = osal_mutex_create(&midi->tx_ff_mutex); + TU_ASSERT(mutex_wr != NULL && mutex_wr != NULL, ); + + tu_fifo_config_mutex(&midi->rx_ff, NULL, mutex_rd); + tu_fifo_config_mutex(&midi->tx_ff, mutex_wr, NULL); #endif } } +bool midid_deinit(void) { + #if CFG_FIFO_MUTEX + for(uint8_t i=0; irx_ff.mutex_rd; + osal_mutex_t mutex_wr = midi->tx_ff.mutex_wr; + + if (mutex_rd) { + osal_mutex_delete(mutex_rd); + tu_fifo_config_mutex(&midi->rx_ff, NULL, NULL); + } + + if (mutex_wr) { + osal_mutex_delete(mutex_wr); + tu_fifo_config_mutex(&midi->tx_ff, NULL, NULL); + } + } + #endif + + return true; +} + void midid_reset(uint8_t rhport) { (void) rhport; diff --git a/src/class/midi/midi_device.h b/src/class/midi/midi_device.h index 1c6f996be..3e89cc0a3 100644 --- a/src/class/midi/midi_device.h +++ b/src/class/midi/midi_device.h @@ -158,6 +158,7 @@ static inline bool tud_midi_packet_write (uint8_t const packet[4]) // Internal Class Driver API //--------------------------------------------------------------------+ void midid_init (void); +bool midid_deinit (void); void midid_reset (uint8_t rhport); uint16_t midid_open (uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len); bool midid_control_xfer_cb (uint8_t rhport, uint8_t stage, tusb_control_request_t const * request); diff --git a/src/class/msc/msc_device.c b/src/class/msc/msc_device.c index c145d86a6..588fcaaca 100644 --- a/src/class/msc/msc_device.c +++ b/src/class/msc/msc_device.c @@ -251,11 +251,15 @@ static inline void set_sense_medium_not_present(uint8_t lun) //--------------------------------------------------------------------+ // USBD Driver API //--------------------------------------------------------------------+ -void mscd_init(void) -{ +void mscd_init(void) { tu_memclr(&_mscd_itf, sizeof(mscd_interface_t)); } +bool mscd_deinit(void) { + // nothing to do + return true; +} + void mscd_reset(uint8_t rhport) { (void) rhport; diff --git a/src/class/msc/msc_device.h b/src/class/msc/msc_device.h index 72f95be06..4247a40bd 100644 --- a/src/class/msc/msc_device.h +++ b/src/class/msc/msc_device.h @@ -150,6 +150,7 @@ TU_ATTR_WEAK bool tud_msc_is_writable_cb(uint8_t lun); // Internal Class Driver API //--------------------------------------------------------------------+ void mscd_init (void); +bool mscd_deinit (void); void mscd_reset (uint8_t rhport); uint16_t mscd_open (uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len); bool mscd_control_xfer_cb (uint8_t rhport, uint8_t stage, tusb_control_request_t const * p_request); diff --git a/src/class/net/ecm_rndis_device.c b/src/class/net/ecm_rndis_device.c index 762425732..f7a5fd225 100644 --- a/src/class/net/ecm_rndis_device.c +++ b/src/class/net/ecm_rndis_device.c @@ -132,11 +132,14 @@ void netd_report(uint8_t *buf, uint16_t len) //--------------------------------------------------------------------+ // USBD Driver API //--------------------------------------------------------------------+ -void netd_init(void) -{ +void netd_init(void) { tu_memclr(&_netd_itf, sizeof(_netd_itf)); } +bool netd_deinit(void) { + return true; +} + void netd_reset(uint8_t rhport) { (void) rhport; diff --git a/src/class/net/ncm_device.c b/src/class/net/ncm_device.c index 226c42c4e..f84bd9f73 100644 --- a/src/class/net/ncm_device.c +++ b/src/class/net/ncm_device.c @@ -260,6 +260,10 @@ void netd_init(void) ncm_prepare_for_tx(); } +bool netd_deinit(void) { + return true; +} + void netd_reset(uint8_t rhport) { (void) rhport; diff --git a/src/class/net/net_device.h b/src/class/net/net_device.h index 399916355..da1a7b1e8 100644 --- a/src/class/net/net_device.h +++ b/src/class/net/net_device.h @@ -105,6 +105,7 @@ void tud_network_link_state_cb(bool state); // INTERNAL USBD-CLASS DRIVER API //--------------------------------------------------------------------+ void netd_init (void); +bool netd_deinit (void); void netd_reset (uint8_t rhport); uint16_t netd_open (uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len); bool netd_control_xfer_cb (uint8_t rhport, uint8_t stage, tusb_control_request_t const * request); diff --git a/src/class/usbtmc/usbtmc_device.c b/src/class/usbtmc/usbtmc_device.c index 573654d58..972a450e6 100644 --- a/src/class/usbtmc/usbtmc_device.c +++ b/src/class/usbtmc/usbtmc_device.c @@ -260,6 +260,11 @@ void usbtmcd_init_cb(void) usbtmcLock = osal_mutex_create(&usbtmcLockBuffer); } +bool usbtmcd_deinit(void) { + osal_mutex_delete(usbtmcLock); + return true; +} + uint16_t usbtmcd_open_cb(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len) { (void)rhport; diff --git a/src/class/usbtmc/usbtmc_device.h b/src/class/usbtmc/usbtmc_device.h index c1298ddb8..3299a36eb 100644 --- a/src/class/usbtmc/usbtmc_device.h +++ b/src/class/usbtmc/usbtmc_device.h @@ -98,11 +98,12 @@ bool tud_usbtmc_start_bus_read(void); /* "callbacks" from USB device core */ +void usbtmcd_init_cb(void); +bool usbtmcd_deinit(void); uint16_t usbtmcd_open_cb(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len); void usbtmcd_reset_cb(uint8_t rhport); bool usbtmcd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes); bool usbtmcd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request); -void usbtmcd_init_cb(void); /************************************************************ * USBTMC Descriptor Templates diff --git a/src/class/vendor/vendor_device.c b/src/class/vendor/vendor_device.c index a68cb2156..e87ce3997 100644 --- a/src/class/vendor/vendor_device.c +++ b/src/class/vendor/vendor_device.c @@ -169,21 +169,47 @@ uint32_t tud_vendor_n_write_available (uint8_t itf) //--------------------------------------------------------------------+ // USBD Driver API //--------------------------------------------------------------------+ -void vendord_init(void) -{ +void vendord_init(void) { tu_memclr(_vendord_itf, sizeof(_vendord_itf)); - for(uint8_t i=0; irx_ff, p_itf->rx_ff_buf, CFG_TUD_VENDOR_RX_BUFSIZE, 1, false); tu_fifo_config(&p_itf->tx_ff, p_itf->tx_ff_buf, CFG_TUD_VENDOR_TX_BUFSIZE, 1, false); - tu_fifo_config_mutex(&p_itf->rx_ff, NULL, osal_mutex_create(&p_itf->rx_ff_mutex)); - tu_fifo_config_mutex(&p_itf->tx_ff, osal_mutex_create(&p_itf->tx_ff_mutex), NULL); + #if OSAL_MUTEX_REQUIRED + osal_mutex_t mutex_rd = osal_mutex_create(&p_itf->rx_ff_mutex); + osal_mutex_t mutex_wr = osal_mutex_create(&p_itf->tx_ff_mutex); + TU_ASSERT(mutex_rd && mutex_wr,); + + tu_fifo_config_mutex(&p_itf->rx_ff, NULL, mutex_rd); + tu_fifo_config_mutex(&p_itf->tx_ff, mutex_wr, NULL); + #endif + } +} + +bool vendord_deinit(void) { + #if OSAL_MUTEX_REQUIRED + for(uint8_t i=0; irx_ff.mutex_rd; + osal_mutex_t mutex_wr = p_itf->tx_ff.mutex_wr; + + if (mutex_rd) { + osal_mutex_delete(mutex_rd); + tu_fifo_config_mutex(&p_itf->rx_ff, NULL, NULL); + } + + if (mutex_wr) { + osal_mutex_delete(mutex_wr); + tu_fifo_config_mutex(&p_itf->tx_ff, NULL, NULL); + } } + #endif + + return true; } void vendord_reset(uint8_t rhport) diff --git a/src/class/vendor/vendor_device.h b/src/class/vendor/vendor_device.h index d239406b4..cd69ec7c6 100644 --- a/src/class/vendor/vendor_device.h +++ b/src/class/vendor/vendor_device.h @@ -139,6 +139,7 @@ static inline uint32_t tud_vendor_write_available (void) // Internal Class Driver API //--------------------------------------------------------------------+ void vendord_init(void); +bool vendord_deinit(void); void vendord_reset(uint8_t rhport); uint16_t vendord_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len); bool vendord_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes); diff --git a/src/class/video/video_device.c b/src/class/video/video_device.c index 5306356ba..c30690232 100644 --- a/src/class/video/video_device.c +++ b/src/class/video/video_device.c @@ -1229,6 +1229,10 @@ void videod_init(void) { } } +bool videod_deinit(void) { + return true; +} + void videod_reset(uint8_t rhport) { (void) rhport; for (uint_fast8_t i = 0; i < CFG_TUD_VIDEO; ++i) { diff --git a/src/class/video/video_device.h b/src/class/video/video_device.h index ee2fcb9d5..92930c013 100644 --- a/src/class/video/video_device.h +++ b/src/class/video/video_device.h @@ -85,6 +85,7 @@ TU_ATTR_WEAK int tud_video_commit_cb(uint_fast8_t ctl_idx, uint_fast8_t stm_idx, // INTERNAL USBD-CLASS DRIVER API //--------------------------------------------------------------------+ void videod_init (void); +bool videod_deinit (void); void videod_reset (uint8_t rhport); uint16_t videod_open (uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len); bool videod_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request); diff --git a/src/device/dcd.h b/src/device/dcd.h index 21f404e4f..d4f105aa3 100644 --- a/src/device/dcd.h +++ b/src/device/dcd.h @@ -123,7 +123,7 @@ void dcd_dcache_clean_invalidate(void const* addr, uint32_t data_size) TU_ATTR_W void dcd_init(uint8_t rhport); // Deinitialize controller, unset device mode. -void dcd_deinit(uint8_t rhport); +bool dcd_deinit(uint8_t rhport); // Interrupt Handler void dcd_int_handler(uint8_t rhport); diff --git a/src/device/usbd.c b/src/device/usbd.c index 8f98862c6..439e071ff 100644 --- a/src/device/usbd.c +++ b/src/device/usbd.c @@ -43,8 +43,13 @@ #endif //--------------------------------------------------------------------+ -// Callback weak stubs (called if application does not provide) +// Weak stubs: invoked if no strong implementation is available //--------------------------------------------------------------------+ +TU_ATTR_WEAK bool dcd_deinit(uint8_t rhport) { + (void) rhport; + return false; +} + TU_ATTR_WEAK void tud_event_hook_cb(uint8_t rhport, uint32_t eventid, bool in_isr) { (void)rhport; (void)eventid; @@ -85,17 +90,18 @@ tu_static usbd_device_t _usbd_dev; // Class Driver //--------------------------------------------------------------------+ #if CFG_TUSB_DEBUG >= CFG_TUD_LOG_LEVEL - #define DRIVER_NAME(_name) .name = _name, + #define DRIVER_NAME(_name) _name #else - #define DRIVER_NAME(_name) + #define DRIVER_NAME(_name) NULL #endif // Built-in class drivers tu_static usbd_class_driver_t const _usbd_driver[] = { #if CFG_TUD_CDC { - DRIVER_NAME("CDC") + .name = DRIVER_NAME("CDC"), .init = cdcd_init, + .deinit = cdcd_deinit, .reset = cdcd_reset, .open = cdcd_open, .control_xfer_cb = cdcd_control_xfer_cb, @@ -106,8 +112,9 @@ tu_static usbd_class_driver_t const _usbd_driver[] = { #if CFG_TUD_MSC { - DRIVER_NAME("MSC") + .name = DRIVER_NAME("MSC"), .init = mscd_init, + .deinit = NULL, .reset = mscd_reset, .open = mscd_open, .control_xfer_cb = mscd_control_xfer_cb, @@ -118,121 +125,131 @@ tu_static usbd_class_driver_t const _usbd_driver[] = { #if CFG_TUD_HID { - DRIVER_NAME("HID") - .init = hidd_init, - .reset = hidd_reset, - .open = hidd_open, - .control_xfer_cb = hidd_control_xfer_cb, - .xfer_cb = hidd_xfer_cb, - .sof = NULL + .name = DRIVER_NAME("HID"), + .init = hidd_init, + .deinit = hidd_deinit, + .reset = hidd_reset, + .open = hidd_open, + .control_xfer_cb = hidd_control_xfer_cb, + .xfer_cb = hidd_xfer_cb, + .sof = NULL }, #endif #if CFG_TUD_AUDIO { - DRIVER_NAME("AUDIO") - .init = audiod_init, - .reset = audiod_reset, - .open = audiod_open, - .control_xfer_cb = audiod_control_xfer_cb, - .xfer_cb = audiod_xfer_cb, - .sof = audiod_sof_isr + .name = DRIVER_NAME("AUDIO"), + .init = audiod_init, + .deinit = audiod_deinit, + .reset = audiod_reset, + .open = audiod_open, + .control_xfer_cb = audiod_control_xfer_cb, + .xfer_cb = audiod_xfer_cb, + .sof = audiod_sof_isr }, #endif #if CFG_TUD_VIDEO { - DRIVER_NAME("VIDEO") - .init = videod_init, - .reset = videod_reset, - .open = videod_open, - .control_xfer_cb = videod_control_xfer_cb, - .xfer_cb = videod_xfer_cb, - .sof = NULL + .name = DRIVER_NAME("VIDEO"), + .init = videod_init, + .deinit = videod_deinit, + .reset = videod_reset, + .open = videod_open, + .control_xfer_cb = videod_control_xfer_cb, + .xfer_cb = videod_xfer_cb, + .sof = NULL }, #endif #if CFG_TUD_MIDI { - DRIVER_NAME("MIDI") - .init = midid_init, - .open = midid_open, - .reset = midid_reset, - .control_xfer_cb = midid_control_xfer_cb, - .xfer_cb = midid_xfer_cb, - .sof = NULL + .name = DRIVER_NAME("MIDI"), + .init = midid_init, + .deinit = midid_deinit, + .open = midid_open, + .reset = midid_reset, + .control_xfer_cb = midid_control_xfer_cb, + .xfer_cb = midid_xfer_cb, + .sof = NULL }, #endif #if CFG_TUD_VENDOR { - DRIVER_NAME("VENDOR") - .init = vendord_init, - .reset = vendord_reset, - .open = vendord_open, - .control_xfer_cb = tud_vendor_control_xfer_cb, - .xfer_cb = vendord_xfer_cb, - .sof = NULL + .name = DRIVER_NAME("VENDOR"), + .init = vendord_init, + .deinit = vendord_deinit, + .reset = vendord_reset, + .open = vendord_open, + .control_xfer_cb = tud_vendor_control_xfer_cb, + .xfer_cb = vendord_xfer_cb, + .sof = NULL }, #endif #if CFG_TUD_USBTMC { - DRIVER_NAME("TMC") - .init = usbtmcd_init_cb, - .reset = usbtmcd_reset_cb, - .open = usbtmcd_open_cb, - .control_xfer_cb = usbtmcd_control_xfer_cb, - .xfer_cb = usbtmcd_xfer_cb, - .sof = NULL + .name = DRIVER_NAME("TMC"), + .init = usbtmcd_init_cb, + .deinit = usbtmcd_deinit, + .reset = usbtmcd_reset_cb, + .open = usbtmcd_open_cb, + .control_xfer_cb = usbtmcd_control_xfer_cb, + .xfer_cb = usbtmcd_xfer_cb, + .sof = NULL }, #endif #if CFG_TUD_DFU_RUNTIME { - DRIVER_NAME("DFU-RUNTIME") - .init = dfu_rtd_init, - .reset = dfu_rtd_reset, - .open = dfu_rtd_open, - .control_xfer_cb = dfu_rtd_control_xfer_cb, - .xfer_cb = NULL, - .sof = NULL + .name = DRIVER_NAME("DFU-RUNTIME"), + .init = dfu_rtd_init, + .deinit = dfu_rtd_deinit, + .reset = dfu_rtd_reset, + .open = dfu_rtd_open, + .control_xfer_cb = dfu_rtd_control_xfer_cb, + .xfer_cb = NULL, + .sof = NULL }, #endif #if CFG_TUD_DFU { - DRIVER_NAME("DFU") - .init = dfu_moded_init, - .reset = dfu_moded_reset, - .open = dfu_moded_open, - .control_xfer_cb = dfu_moded_control_xfer_cb, - .xfer_cb = NULL, - .sof = NULL + .name = DRIVER_NAME("DFU"), + .init = dfu_moded_init, + .deinit = dfu_moded_deinit, + .reset = dfu_moded_reset, + .open = dfu_moded_open, + .control_xfer_cb = dfu_moded_control_xfer_cb, + .xfer_cb = NULL, + .sof = NULL }, #endif #if CFG_TUD_ECM_RNDIS || CFG_TUD_NCM { - DRIVER_NAME("NET") - .init = netd_init, - .reset = netd_reset, - .open = netd_open, - .control_xfer_cb = netd_control_xfer_cb, - .xfer_cb = netd_xfer_cb, - .sof = NULL, + .name = DRIVER_NAME("NET"), + .init = netd_init, + .deinit = netd_deinit, + .reset = netd_reset, + .open = netd_open, + .control_xfer_cb = netd_control_xfer_cb, + .xfer_cb = netd_xfer_cb, + .sof = NULL, }, #endif #if CFG_TUD_BTH { - DRIVER_NAME("BTH") - .init = btd_init, - .reset = btd_reset, - .open = btd_open, - .control_xfer_cb = btd_control_xfer_cb, - .xfer_cb = btd_xfer_cb, - .sof = NULL + .name = DRIVER_NAME("BTH"), + .init = btd_init, + .deinit = btd_deinit, + .reset = btd_reset, + .open = btd_open, + .control_xfer_cb = btd_control_xfer_cb, + .xfer_cb = btd_xfer_cb, + .sof = NULL }, #endif }; @@ -402,7 +419,7 @@ bool tud_init(uint8_t rhport) { // Init class drivers for (uint8_t i = 0; i < TOTAL_DRIVER_COUNT; i++) { usbd_class_driver_t const* driver = get_driver(i); - TU_ASSERT(driver); + TU_ASSERT(driver && driver->init); TU_LOG_USBD("%s init\r\n", driver->name); driver->init(); } @@ -416,6 +433,41 @@ bool tud_init(uint8_t rhport) { return true; } +bool tud_deinit(uint8_t rhport) { + // skip if not initialized + if (!tud_inited()) return true; + + TU_LOG_USBD("USBD deinit on controller %u\r\n", rhport); + + // Deinit device controller driver + dcd_int_disable(rhport); + dcd_disconnect(rhport); + dcd_deinit(rhport); + + // Deinit class drivers + for (uint8_t i = 0; i < TOTAL_DRIVER_COUNT; i++) { + usbd_class_driver_t const* driver = get_driver(i); + if(driver && driver->deinit) { + TU_LOG_USBD("%s deinit\r\n", driver->name); + driver->deinit(); + } + } + + // Deinit device queue & task + osal_queue_delete(_usbd_q); + _usbd_q = NULL; + +#if OSAL_MUTEX_REQUIRED + // TODO make sure there is no task waiting on this mutex + osal_mutex_delete(_usbd_mutex); + _usbd_mutex = NULL; +#endif + + _usbd_rhport = RHPORT_INVALID; + + return true; +} + static void configuration_reset(uint8_t rhport) { for (uint8_t i = 0; i < TOTAL_DRIVER_COUNT; i++) { usbd_class_driver_t const* driver = get_driver(i); diff --git a/src/device/usbd.h b/src/device/usbd.h index a9350192b..0197628e2 100644 --- a/src/device/usbd.h +++ b/src/device/usbd.h @@ -41,7 +41,7 @@ extern "C" { bool tud_init (uint8_t rhport); // Deinit device stack on roothub port -void tud_deinit(uint8_t rhport); +bool tud_deinit(uint8_t rhport); // Check if device stack is already initialized bool tud_inited(void); diff --git a/src/device/usbd_pvt.h b/src/device/usbd_pvt.h index 9039bc9d6..5ae96e589 100644 --- a/src/device/usbd_pvt.h +++ b/src/device/usbd_pvt.h @@ -40,11 +40,9 @@ //--------------------------------------------------------------------+ typedef struct { - #if CFG_TUSB_DEBUG >= CFG_TUD_LOG_LEVEL char const* name; - #endif - void (* init ) (void); + bool (* deinit ) (void); void (* reset ) (uint8_t rhport); uint16_t (* open ) (uint8_t rhport, tusb_desc_interface_t const * desc_intf, uint16_t max_len); bool (* control_xfer_cb ) (uint8_t rhport, uint8_t stage, tusb_control_request_t const * request); diff --git a/src/host/usbh.c b/src/host/usbh.c index aa0603d47..6a5491998 100644 --- a/src/host/usbh.c +++ b/src/host/usbh.c @@ -425,7 +425,7 @@ bool tuh_deinit(uint8_t rhport) { // 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) { + if (driver && driver->deinit) { TU_LOG_USBH("%s deinit\r\n", driver->name); driver->deinit(); } diff --git a/src/portable/raspberrypi/rp2040/dcd_rp2040.c b/src/portable/raspberrypi/rp2040/dcd_rp2040.c index ccc7ee102..a2b3375a3 100644 --- a/src/portable/raspberrypi/rp2040/dcd_rp2040.c +++ b/src/portable/raspberrypi/rp2040/dcd_rp2040.c @@ -407,16 +407,17 @@ void dcd_init(uint8_t rhport) { dcd_connect(rhport); } -void dcd_deinit(uint8_t rhport) { +bool dcd_deinit(uint8_t rhport) { assert(rhport == 0); - dcd_disconnect(rhport); reset_non_control_endpoints(); irq_remove_handler(USBCTRL_IRQ, dcd_rp2040_irq); // reset usb hardware into initial state reset_block(RESETS_RESET_USBCTRL_BITS); unreset_block_wait(RESETS_RESET_USBCTRL_BITS); + + return true; } void dcd_int_enable(__unused uint8_t rhport) { diff --git a/src/portable/raspberrypi/rp2040/hcd_rp2040.c b/src/portable/raspberrypi/rp2040/hcd_rp2040.c index 762753a25..222dbbbf0 100644 --- a/src/portable/raspberrypi/rp2040/hcd_rp2040.c +++ b/src/portable/raspberrypi/rp2040/hcd_rp2040.c @@ -409,12 +409,14 @@ bool hcd_init(uint8_t rhport) return true; } -void hcd_deinit(uint8_t rhport) { +bool hcd_deinit(uint8_t rhport) { (void) rhport; irq_remove_handler(USBCTRL_IRQ, hcd_rp2040_irq); reset_block(RESETS_RESET_USBCTRL_BITS); unreset_block_wait(RESETS_RESET_USBCTRL_BITS); + + return true; } void hcd_port_reset(uint8_t rhport) diff --git a/src/tusb_option.h b/src/tusb_option.h index 2921d3ae0..cbcb69edd 100644 --- a/src/tusb_option.h +++ b/src/tusb_option.h @@ -34,7 +34,7 @@ #define TUSB_VERSION_MAJOR 0 #define TUSB_VERSION_MINOR 16 #define TUSB_VERSION_REVISION 0 -#define TUSB_VERSION_BUILD 2 +#define TUSB_VERSION_BUILD 3 #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) -- cgit v1.3.1 From 366564e952b974a49a5b8da7f1d4c729bd37219d Mon Sep 17 00:00:00 2001 From: hathach Date: Mon, 8 Apr 2024 22:13:05 +0700 Subject: fix missing if mutex required --- src/class/usbtmc/usbtmc_device.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/class') diff --git a/src/class/usbtmc/usbtmc_device.c b/src/class/usbtmc/usbtmc_device.c index 972a450e6..286cbe108 100644 --- a/src/class/usbtmc/usbtmc_device.c +++ b/src/class/usbtmc/usbtmc_device.c @@ -261,7 +261,9 @@ void usbtmcd_init_cb(void) } bool usbtmcd_deinit(void) { + #if OSAL_MUTEX_REQUIRED osal_mutex_delete(usbtmcLock); + #endif return true; } -- cgit v1.3.1 From b0568e32a5d3ad427d296e0d3bcb1020d54d25a3 Mon Sep 17 00:00:00 2001 From: HiFiPhile Date: Tue, 9 Apr 2024 10:47:06 +0200 Subject: Fix tud_video_n_streaming check --- src/class/video/video_device.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'src/class') diff --git a/src/class/video/video_device.c b/src/class/video/video_device.c index d0a88eb17..4218835aa 100644 --- a/src/class/video/video_device.c +++ b/src/class/video/video_device.c @@ -763,8 +763,8 @@ static bool _open_vs_itf(uint8_t rhport, videod_streaming_interface_t *stm, uint tusb_desc_endpoint_t const *ep = (tusb_desc_endpoint_t const*)(desc + ofs_ep); /* Only ISO endpoints needs to be closed */ if(ep->bmAttributes.xfer == TUSB_XFER_ISOCHRONOUS) { - usbd_edpt_close(rhport, ep->bEndpointAddress); stm->desc.ep[i] = 0; + usbd_edpt_close(rhport, ep->bEndpointAddress); TU_LOG_DRV(" close EP%02x\r\n", ep->bEndpointAddress); } } @@ -1186,6 +1186,16 @@ bool tud_video_n_streaming(uint_fast8_t ctl_idx, uint_fast8_t stm_idx) videod_streaming_interface_t *stm = _get_instance_streaming(ctl_idx, stm_idx); if (!stm || !stm->desc.ep[0]) return false; if (stm->state == VS_STATE_PROBING) return false; + +#ifdef TUP_DCD_EDPT_ISO_ALLOC + uint8_t const *desc = _videod_itf[stm->index_vc].beg; + uint_fast16_t ofs_ep = stm->desc.ep[0]; + tusb_desc_endpoint_t const *ep = (tusb_desc_endpoint_t const*)(desc + ofs_ep); + if (ep->bmAttributes.xfer == TUSB_XFER_ISOCHRONOUS) { + if (stm->state == VS_STATE_COMMITTED) return false; + } +#endif + return true; } -- cgit v1.3.1 From 804a73a454f382ef7dd5377e6a564f516196fa5d Mon Sep 17 00:00:00 2001 From: Luke A Date: Mon, 14 Aug 2023 21:58:20 -0400 Subject: Adding tuh_hid_get_report(...) to hid_host.h This allows USB host functionality to call HID_REQ_CONTROL_GET_REPORT on the IN Endpoint, and read the report buffer in the callback. --- src/class/hid/hid_host.c | 44 ++++++++++++++++++++++++++++++++++++++++++++ src/class/hid/hid_host.h | 8 ++++++++ 2 files changed, 52 insertions(+) (limited to 'src/class') diff --git a/src/class/hid/hid_host.c b/src/class/hid/hid_host.c index 621fb2a55..115a8a4df 100644 --- a/src/class/hid/hid_host.c +++ b/src/class/hid/hid_host.c @@ -222,6 +222,50 @@ bool tuh_hid_set_protocol(uint8_t daddr, uint8_t idx, uint8_t protocol) { return _hidh_set_protocol(daddr, p_hid->itf_num, protocol, set_protocol_complete, 0); } +static void get_report_complete(tuh_xfer_t* xfer) { + TU_LOG_DRV("HID Get Report complete\r\n"); + + if (tuh_hid_get_report_complete_cb) { + uint8_t const itf_num = (uint8_t) tu_le16toh(xfer->setup->wIndex); + uint8_t const idx = tuh_hid_itf_get_index(xfer->daddr, itf_num); + + uint8_t const report_type = tu_u16_high(xfer->setup->wValue); + uint8_t const report_id = tu_u16_low(xfer->setup->wValue); + + tuh_hid_get_report_complete_cb(xfer->daddr, idx, report_id, report_type, + (xfer->result == XFER_RESULT_SUCCESS) ? xfer->setup->wLength : 0); + } +} + +bool tuh_hid_get_report(uint8_t daddr, uint8_t idx, uint8_t report_id, uint8_t report_type, void* report, uint16_t len) { + hidh_interface_t* p_hid = get_hid_itf(daddr, idx); + TU_VERIFY(p_hid); + TU_LOG_DRV("HID Get Report: id = %u, type = %u, len = %u\r\n", report_id, report_type, len); + + tusb_control_request_t const request = { + .bmRequestType_bit = { + .recipient = TUSB_REQ_RCPT_INTERFACE, + .type = TUSB_REQ_TYPE_CLASS, + .direction = TUSB_DIR_IN + }, + .bRequest = HID_REQ_CONTROL_GET_REPORT, + .wValue = tu_htole16(tu_u16(report_type, report_id)), + .wIndex = tu_htole16((uint16_t) p_hid->itf_num), + .wLength = len + }; + + tuh_xfer_t xfer = { + .daddr = daddr, + .ep_addr = 0, + .setup = &request, + .buffer = report, + .complete_cb = get_report_complete, + .user_data = 0 + }; + + return tuh_control_xfer(&xfer); +} + static void set_report_complete(tuh_xfer_t* xfer) { TU_LOG_DRV("HID Set Report complete\r\n"); diff --git a/src/class/hid/hid_host.h b/src/class/hid/hid_host.h index 0902bf1af..9681c704b 100644 --- a/src/class/hid/hid_host.h +++ b/src/class/hid/hid_host.h @@ -105,6 +105,10 @@ void tuh_hid_set_default_protocol(uint8_t protocol); // This function is only supported by Boot interface (tuh_n_hid_interface_protocol() != NONE) bool tuh_hid_set_protocol(uint8_t dev_addr, uint8_t idx, uint8_t protocol); +// Get Report using control endpoint +// report_type is either Input, Output or Feature, (value from hid_report_type_t) +bool tuh_hid_get_report(uint8_t dev_addr, uint8_t idx, uint8_t report_id, uint8_t report_type, void* report, uint16_t len); + // Set Report using control endpoint // report_type is either Input, Output or Feature, (value from hid_report_type_t) bool tuh_hid_set_report(uint8_t dev_addr, uint8_t idx, uint8_t report_id, uint8_t report_type, @@ -153,6 +157,10 @@ void tuh_hid_report_received_cb(uint8_t dev_addr, uint8_t idx, uint8_t const* re // Invoked when sent report to device successfully via interrupt endpoint TU_ATTR_WEAK void tuh_hid_report_sent_cb(uint8_t dev_addr, uint8_t idx, uint8_t const* report, uint16_t len); +// Invoked when Get Report to device via either control endpoint +// len = 0 indicate there is error in the transfer e.g stalled response +TU_ATTR_WEAK void tuh_hid_get_report_complete_cb(uint8_t dev_addr, uint8_t idx, uint8_t report_id, uint8_t report_type, uint16_t len); + // Invoked when Sent Report to device via either control endpoint // len = 0 indicate there is error in the transfer e.g stalled response TU_ATTR_WEAK void tuh_hid_set_report_complete_cb(uint8_t dev_addr, uint8_t idx, uint8_t report_id, uint8_t report_type, uint16_t len); -- cgit v1.3.1 From 62331f02070bdb1bec2890885008e9f88b06bdb6 Mon Sep 17 00:00:00 2001 From: hathach Date: Mon, 22 Apr 2024 15:55:50 +0700 Subject: fix nrfx v3 spim freq when init fix clang build with nrf --- examples/host/cdc_msc_hid/src/msc_app.c | 4 ++-- hw/bsp/nrf/boards/pca10059/pca10059.ld | 8 +++++++- hw/bsp/nrf/boards/pca10095/board.cmake | 1 - hw/bsp/nrf/boards/pca10100/board.cmake | 1 - hw/bsp/nrf/boards/raytac_mdbt50q_rx/board.cmake | 1 - hw/bsp/nrf/family.c | 6 ++++-- hw/bsp/nrf/family.cmake | 18 +++++++++--------- hw/bsp/nrf/linker/nrf52833_xxaa.ld | 20 ++++++++++++++++++++ hw/bsp/nrf/linker/nrf5340_xxaa_application.ld | 21 +++++++++++++++++++++ src/class/cdc/cdc_host.c | 4 ++-- src/host/usbh.c | 2 +- 11 files changed, 66 insertions(+), 20 deletions(-) create mode 100644 hw/bsp/nrf/linker/nrf52833_xxaa.ld create mode 100644 hw/bsp/nrf/linker/nrf5340_xxaa_application.ld (limited to 'src/class') diff --git a/examples/host/cdc_msc_hid/src/msc_app.c b/examples/host/cdc_msc_hid/src/msc_app.c index e9c9676b8..1d7e18e6e 100644 --- a/examples/host/cdc_msc_hid/src/msc_app.c +++ b/examples/host/cdc_msc_hid/src/msc_app.c @@ -48,8 +48,8 @@ bool inquiry_complete_cb(uint8_t dev_addr, tuh_msc_complete_data_t const * cb_da uint32_t const block_count = tuh_msc_get_block_count(dev_addr, cbw->lun); uint32_t const block_size = tuh_msc_get_block_size(dev_addr, cbw->lun); - printf("Disk Size: %lu MB\r\n", block_count / ((1024*1024)/block_size)); - printf("Block Count = %lu, Block Size: %lu\r\n", block_count, block_size); + printf("Disk Size: %" PRIu32 " MB\r\n", block_count / ((1024*1024)/block_size)); + printf("Block Count = %" PRIu32 ", Block Size: %" PRIu32 "\r\n", block_count, block_size); return true; } diff --git a/hw/bsp/nrf/boards/pca10059/pca10059.ld b/hw/bsp/nrf/boards/pca10059/pca10059.ld index 510bfdd8c..adc80f3c4 100644 --- a/hw/bsp/nrf/boards/pca10059/pca10059.ld +++ b/hw/bsp/nrf/boards/pca10059/pca10059.ld @@ -1,7 +1,7 @@ /* Linker script to configure memory regions. */ SEARCH_DIR(.) -GROUP(-lgcc -lc -lnosys) +/*GROUP(-lgcc -lc -lnosys) not compatible with clang*/ MEMORY { @@ -11,3 +11,9 @@ MEMORY INCLUDE "nrf_common.ld" + +/* nrfx v2 linker does not define __tbss_start/end__ __sbss_start/end__*/ +__tbss_start__ = __tbss_start; +__tbss_end__ = __tbss_end; +__sbss_start__ = __sbss_start; +__sbss_end__ = __sbss_end; diff --git a/hw/bsp/nrf/boards/pca10095/board.cmake b/hw/bsp/nrf/boards/pca10095/board.cmake index ca5399a3a..95dd30969 100644 --- a/hw/bsp/nrf/boards/pca10095/board.cmake +++ b/hw/bsp/nrf/boards/pca10095/board.cmake @@ -1,5 +1,4 @@ set(MCU_VARIANT nrf5340_application) -set(LD_FILE_GNU ${NRFX_DIR}/mdk/nrf5340_xxaa_application.ld) function(update_board TARGET) target_sources(${TARGET} PRIVATE diff --git a/hw/bsp/nrf/boards/pca10100/board.cmake b/hw/bsp/nrf/boards/pca10100/board.cmake index c30026815..a925dae80 100644 --- a/hw/bsp/nrf/boards/pca10100/board.cmake +++ b/hw/bsp/nrf/boards/pca10100/board.cmake @@ -1,5 +1,4 @@ set(MCU_VARIANT nrf52833) -set(LD_FILE_GNU ${NRFX_DIR}/mdk/nrf52833_xxaa.ld) function(update_board TARGET) endfunction() diff --git a/hw/bsp/nrf/boards/raytac_mdbt50q_rx/board.cmake b/hw/bsp/nrf/boards/raytac_mdbt50q_rx/board.cmake index 693d7beed..cc370aac8 100644 --- a/hw/bsp/nrf/boards/raytac_mdbt50q_rx/board.cmake +++ b/hw/bsp/nrf/boards/raytac_mdbt50q_rx/board.cmake @@ -1,5 +1,4 @@ set(MCU_VARIANT nrf52840) -set(LD_FILE_GNU ${NRFX_DIR}/mdk/nrf52840_xxaa.ld) function(update_board TARGET) endfunction() diff --git a/hw/bsp/nrf/family.c b/hw/bsp/nrf/family.c index deae64f05..aff851ddc 100644 --- a/hw/bsp/nrf/family.c +++ b/hw/bsp/nrf/family.c @@ -356,20 +356,22 @@ static void max3421_init(void) { .miso_pin = MAX3421_MISO_PIN, #if NRFX_VER <= 2 .ss_pin = NRFX_SPIM_PIN_NOT_USED, + .frequency = NRF_SPIM_FREQ_4M, #else .ss_pin = NRF_SPIM_PIN_NOT_CONNECTED, + .frequency = 4000000u, #endif .ss_active_high = false, .irq_priority = 3, .orc = 0xFF, // default setting 4 Mhz, Mode 0, MSB first - .frequency = NRF_SPIM_FREQ_4M, .mode = NRF_SPIM_MODE_0, .bit_order = NRF_SPIM_BIT_ORDER_MSB_FIRST, + .miso_pull = NRF_GPIO_PIN_NOPULL, }; // no handler --> blocking - nrfx_spim_init(&_spi, &cfg, NULL, NULL); + TU_ASSERT(NRFX_SUCCESS == nrfx_spim_init(&_spi, &cfg, NULL, NULL), ); // max3421e interrupt pin #if NRFX_VER <= 2 diff --git a/hw/bsp/nrf/family.cmake b/hw/bsp/nrf/family.cmake index 52a6fc196..56ff62bc4 100644 --- a/hw/bsp/nrf/family.cmake +++ b/hw/bsp/nrf/family.cmake @@ -30,8 +30,14 @@ set(FAMILY_MCUS NRF5X CACHE INTERNAL "") # only need to be built ONCE for all examples function(add_board_target BOARD_TARGET) if (NOT TARGET ${BOARD_TARGET}) + if (MCU_VARIANT STREQUAL "nrf5340_application") + set(MCU_VARIANT_XXAA "nrf5340_xxaa_application") + else () + set(MCU_VARIANT_XXAA "${MCU_VARIANT}_xxaa") + endif () + if (NOT DEFINED LD_FILE_GNU) - set(LD_FILE_GNU ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/linker/${MCU_VARIANT}_xxaa.ld) + set(LD_FILE_GNU ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/linker/${MCU_VARIANT_XXAA}.ld) endif () set(LD_FILE_Clang ${LD_FILE_GNU}) @@ -50,19 +56,13 @@ function(add_board_target BOARD_TARGET) ${NRFX_DIR}/soc/nrfx_atomic.c ${STARTUP_FILE_${CMAKE_C_COMPILER_ID}} ) + string(TOUPPER "${MCU_VARIANT_XXAA}" MCU_VARIANT_XXAA_UPPER) target_compile_definitions(${BOARD_TARGET} PUBLIC __STARTUP_CLEAR_BSS CONFIG_GPIO_AS_PINRESET + ${MCU_VARIANT_XXAA_UPPER} ) - if (MCU_VARIANT STREQUAL "nrf52840") - target_compile_definitions(${BOARD_TARGET} PUBLIC NRF52840_XXAA) - elseif (MCU_VARIANT STREQUAL "nrf52833") - target_compile_definitions(${BOARD_TARGET} PUBLIC NRF52833_XXAA) - elseif (MCU_VARIANT STREQUAL "nrf5340_application") - target_compile_definitions(${BOARD_TARGET} PUBLIC NRF5340_XXAA NRF5340_XXAA_APPLICATION) - endif () - if (TRACE_ETM STREQUAL "1") # ENABLE_TRACE will cause system_nrf5x.c to set up ETM trace target_compile_definitions(${BOARD_TARGET} PUBLIC ENABLE_TRACE) diff --git a/hw/bsp/nrf/linker/nrf52833_xxaa.ld b/hw/bsp/nrf/linker/nrf52833_xxaa.ld new file mode 100644 index 000000000..ae4d0e5b3 --- /dev/null +++ b/hw/bsp/nrf/linker/nrf52833_xxaa.ld @@ -0,0 +1,20 @@ +/* Linker script to configure memory regions. */ + +SEARCH_DIR(.) +/*GROUP(-lgcc -lc -lnosys) not compatible with clang*/ + +MEMORY +{ + FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 0x80000 + RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 0x20000 + CODE_RAM (rwx) : ORIGIN = 0x800000, LENGTH = 0x20000 +} + + +INCLUDE "nrf_common.ld" + +/* nrfx v2 linker does not define __tbss_start/end__ __sbss_start/end__*/ +__tbss_start__ = __tbss_start; +__tbss_end__ = __tbss_end; +__sbss_start__ = __sbss_start; +__sbss_end__ = __sbss_end; diff --git a/hw/bsp/nrf/linker/nrf5340_xxaa_application.ld b/hw/bsp/nrf/linker/nrf5340_xxaa_application.ld new file mode 100644 index 000000000..31762d0b2 --- /dev/null +++ b/hw/bsp/nrf/linker/nrf5340_xxaa_application.ld @@ -0,0 +1,21 @@ +/* Linker script to configure memory regions. */ + +SEARCH_DIR(.) +/*GROUP(-lgcc -lc) not compatible with clang*/ + +MEMORY +{ + FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 0x100000 + EXTFLASH (rx) : ORIGIN = 0x10000000, LENGTH = 0x8000000 + RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 0x40000 + RAM1 (rwx) : ORIGIN = 0x20040000, LENGTH = 0x3F000 +} + + +INCLUDE "nrf_common.ld" + +/* nrfx v2 linker does not define __tbss_start/end__ __sbss_start/end__*/ +__tbss_start__ = __tbss_start; +__tbss_end__ = __tbss_end; +__sbss_start__ = __sbss_start; +__sbss_end__ = __sbss_end; diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index 5bdd41f1f..133a10f6e 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -1079,7 +1079,7 @@ static uint32_t ftdi_232bm_baud_to_divisor(uint32_t baud) { static bool ftdi_sio_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { uint16_t const divisor = (uint16_t) ftdi_232bm_baud_to_divisor(baudrate); - TU_LOG_DRV("CDC FTDI Set BaudRate = %lu, divisor = 0x%04x\r\n", baudrate, divisor); + TU_LOG_DRV("CDC FTDI Set BaudRate = %" PRIu32 ", divisor = 0x%04x\r\n", baudrate, divisor); p_cdc->user_control_cb = complete_cb; p_cdc->requested_line_coding.bit_rate = baudrate; @@ -1222,7 +1222,7 @@ static bool cp210x_set_line_coding(cdch_interface_t* p_cdc, cdc_line_coding_t co } static bool cp210x_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - TU_LOG_DRV("CDC CP210x Set BaudRate = %lu\r\n", baudrate); + TU_LOG_DRV("CDC CP210x Set BaudRate = %" PRIu32 "\r\n", baudrate); uint32_t baud_le = tu_htole32(baudrate); p_cdc->user_control_cb = complete_cb; return cp210x_set_request(p_cdc, CP210X_SET_BAUDRATE, 0, (uint8_t *) &baud_le, 4, diff --git a/src/host/usbh.c b/src/host/usbh.c index f8fddf394..7a47f5056 100644 --- a/src/host/usbh.c +++ b/src/host/usbh.c @@ -704,7 +704,7 @@ static bool usbh_control_xfer_cb (uint8_t daddr, uint8_t ep_addr, xfer_result_t tusb_control_request_t const * request = &_ctrl_xfer.request; if (XFER_RESULT_SUCCESS != result) { - TU_LOG_USBH("[%u:%u] Control %s, xferred_bytes = %lu\r\n", rhport, daddr, result == XFER_RESULT_STALLED ? "STALLED" : "FAILED", xferred_bytes); + TU_LOG_USBH("[%u:%u] Control %s, xferred_bytes = %" PRIu32 "\r\n", rhport, daddr, result == XFER_RESULT_STALLED ? "STALLED" : "FAILED", xferred_bytes); TU_LOG_BUF_USBH(request, 8); // terminate transfer if any stage failed -- cgit v1.3.1 From c097c85dcf8e0ef3ea052c146c5f514101827251 Mon Sep 17 00:00:00 2001 From: hathach Date: Mon, 22 Apr 2024 16:17:22 +0700 Subject: fix print lu format warnings with clang --- examples/device/audio_test_multi_rate/src/main.c | 2 +- examples/device/cdc_uac2/src/uac2_app.c | 4 ++-- examples/device/uac2_headset/src/main.c | 4 ++-- examples/host/bare_api/src/main.c | 2 +- examples/host/cdc_msc_hid_freertos/src/cdc_app.c | 4 ++-- examples/host/cdc_msc_hid_freertos/src/msc_app.c | 4 ++-- examples/host/msc_file_explorer/src/msc_app.c | 6 +++--- src/CMakeLists.txt | 2 +- src/class/cdc/cdc_device.c | 13 ++++++------- src/class/usbtmc/usbtmc_device.c | 2 +- src/portable/nordic/nrf5x/dcd_nrf5x.c | 2 +- tools/get_deps.py | 3 ++- 12 files changed, 24 insertions(+), 24 deletions(-) (limited to 'src/class') diff --git a/examples/device/audio_test_multi_rate/src/main.c b/examples/device/audio_test_multi_rate/src/main.c index 3e7f40dac..2ff7f10bd 100644 --- a/examples/device/audio_test_multi_rate/src/main.c +++ b/examples/device/audio_test_multi_rate/src/main.c @@ -272,7 +272,7 @@ bool tud_audio_set_req_entity_cb(uint8_t rhport, tusb_control_request_t const * sampFreq = (uint32_t)((audio_control_cur_4_t *)pBuff)->bCur; - TU_LOG2("Clock set current freq: %lu\r\n", sampFreq); + TU_LOG2("Clock set current freq: %" PRIu32 "\r\n", sampFreq); return true; break; diff --git a/examples/device/cdc_uac2/src/uac2_app.c b/examples/device/cdc_uac2/src/uac2_app.c index 98659ea68..c57d98a1a 100644 --- a/examples/device/cdc_uac2/src/uac2_app.c +++ b/examples/device/cdc_uac2/src/uac2_app.c @@ -69,7 +69,7 @@ static bool tud_audio_clock_get_request(uint8_t rhport, audio_control_request_t { if (request->bRequest == AUDIO_CS_REQ_CUR) { - TU_LOG1("Clock get current freq %lu\r\n", current_sample_rate); + TU_LOG1("Clock get current freq %" PRIu32 "\r\n", current_sample_rate); audio_control_cur_4_t curf = { (int32_t) tu_htole32(current_sample_rate) }; return tud_audio_buffer_and_schedule_control_xfer(rhport, (tusb_control_request_t const *)request, &curf, sizeof(curf)); @@ -118,7 +118,7 @@ static bool tud_audio_clock_set_request(uint8_t rhport, audio_control_request_t current_sample_rate = (uint32_t) ((audio_control_cur_4_t const *)buf)->bCur; - TU_LOG1("Clock set current freq: %ld\r\n", current_sample_rate); + TU_LOG1("Clock set current freq: %" PRIu32 "\r\n", current_sample_rate); return true; } diff --git a/examples/device/uac2_headset/src/main.c b/examples/device/uac2_headset/src/main.c index fbd7ffe22..0ea6e7025 100644 --- a/examples/device/uac2_headset/src/main.c +++ b/examples/device/uac2_headset/src/main.c @@ -157,7 +157,7 @@ static bool tud_audio_clock_get_request(uint8_t rhport, audio_control_request_t { if (request->bRequest == AUDIO_CS_REQ_CUR) { - TU_LOG1("Clock get current freq %lu\r\n", current_sample_rate); + TU_LOG1("Clock get current freq %" PRIu32 "\r\n", current_sample_rate); audio_control_cur_4_t curf = { (int32_t) tu_htole32(current_sample_rate) }; return tud_audio_buffer_and_schedule_control_xfer(rhport, (tusb_control_request_t const *)request, &curf, sizeof(curf)); @@ -206,7 +206,7 @@ static bool tud_audio_clock_set_request(uint8_t rhport, audio_control_request_t current_sample_rate = (uint32_t) ((audio_control_cur_4_t const *)buf)->bCur; - TU_LOG1("Clock set current freq: %ld\r\n", current_sample_rate); + TU_LOG1("Clock set current freq: %" PRIu32 "\r\n", current_sample_rate); return true; } diff --git a/examples/host/bare_api/src/main.c b/examples/host/bare_api/src/main.c index 14725996d..940840a30 100644 --- a/examples/host/bare_api/src/main.c +++ b/examples/host/bare_api/src/main.c @@ -420,5 +420,5 @@ static void print_utf16(uint16_t *temp_buf, size_t buf_len) { _convert_utf16le_to_utf8(temp_buf + 1, utf16_len, (uint8_t *) temp_buf, sizeof(uint16_t) * buf_len); ((uint8_t*) temp_buf)[utf8_len] = '\0'; - printf((char*)temp_buf); + printf("%s", (char*)temp_buf); } diff --git a/examples/host/cdc_msc_hid_freertos/src/cdc_app.c b/examples/host/cdc_msc_hid_freertos/src/cdc_app.c index 6ff513be1..7d246af67 100644 --- a/examples/host/cdc_msc_hid_freertos/src/cdc_app.c +++ b/examples/host/cdc_msc_hid_freertos/src/cdc_app.c @@ -117,7 +117,7 @@ void tuh_cdc_rx_cb(uint8_t idx) { uint32_t count = tuh_cdc_read(idx, buf, bufsize); buf[count] = 0; - printf((char *) buf); + printf("%s", (char *) buf); } void tuh_cdc_mount_cb(uint8_t idx) { @@ -131,7 +131,7 @@ void tuh_cdc_mount_cb(uint8_t idx) { // otherwise you need to call tuh_cdc_set_line_coding() first cdc_line_coding_t line_coding = { 0 }; if (tuh_cdc_get_local_line_coding(idx, &line_coding)) { - printf(" Baudrate: %lu, Stop Bits : %u\r\n", line_coding.bit_rate, line_coding.stop_bits); + printf(" Baudrate: %" PRIu32 ", Stop Bits : %u\r\n", line_coding.bit_rate, line_coding.stop_bits); printf(" Parity : %u, Data Width: %u\r\n", line_coding.parity, line_coding.data_bits); } #endif diff --git a/examples/host/cdc_msc_hid_freertos/src/msc_app.c b/examples/host/cdc_msc_hid_freertos/src/msc_app.c index ee02ba917..9ffd5d965 100644 --- a/examples/host/cdc_msc_hid_freertos/src/msc_app.c +++ b/examples/host/cdc_msc_hid_freertos/src/msc_app.c @@ -47,8 +47,8 @@ bool inquiry_complete_cb(uint8_t dev_addr, tuh_msc_complete_data_t const *cb_dat uint32_t const block_count = tuh_msc_get_block_count(dev_addr, cbw->lun); uint32_t const block_size = tuh_msc_get_block_size(dev_addr, cbw->lun); - printf("Disk Size: %lu MB\r\n", block_count / ((1024 * 1024) / block_size)); - printf("Block Count = %lu, Block Size: %lu\r\n", block_count, block_size); + printf("Disk Size: %" PRIu32 " MB\r\n", block_count / ((1024 * 1024) / block_size)); + printf("Block Count = %" PRIu32 ", Block Size: %" PRIu32 "\r\n", block_count, block_size); return true; } diff --git a/examples/host/msc_file_explorer/src/msc_app.c b/examples/host/msc_file_explorer/src/msc_app.c index ecea614a2..f323e30f0 100644 --- a/examples/host/msc_file_explorer/src/msc_app.c +++ b/examples/host/msc_file_explorer/src/msc_app.c @@ -114,7 +114,7 @@ bool inquiry_complete_cb(uint8_t dev_addr, tuh_msc_complete_data_t const * cb_da uint32_t const block_count = tuh_msc_get_block_count(dev_addr, cbw->lun); uint32_t const block_size = tuh_msc_get_block_size(dev_addr, cbw->lun); - printf("Disk Size: %lu MB\r\n", block_count / ((1024*1024)/block_size)); + printf("Disk Size: %" PRIu32 " MB\r\n", block_count / ((1024*1024)/block_size)); // printf("Block Count = %lu, Block Size: %lu\r\n", block_count, block_size); // For simplicity: we only mount 1 LUN per device @@ -541,10 +541,10 @@ void cli_cmd_ls(EmbeddedCli *cli, char *args, void *context) printf("%-40s", fno.fname); if (fno.fsize < 1024) { - printf("%lu B\r\n", fno.fsize); + printf("%" PRIu32 " B\r\n", fno.fsize); }else { - printf("%lu KB\r\n", fno.fsize / 1024); + printf("%" PRIu32 " KB\r\n", fno.fsize / 1024); } } } diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 076e1e1eb..272962332 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -41,7 +41,7 @@ function(add_tinyusb TARGET) ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/../lib/networking ) - if (CMAKE_C_COMPILER_ID STREQUAL "GNU") + if (CMAKE_C_COMPILER_ID STREQUAL "GNU" OR CMAKE_C_COMPILER_ID STREQUAL "Clang") target_compile_options(${TARGET} PRIVATE -Wall -Wextra diff --git a/src/class/cdc/cdc_device.c b/src/class/cdc/cdc_device.c index 7ef0530ec..2e0a0c30d 100644 --- a/src/class/cdc/cdc_device.c +++ b/src/class/cdc/cdc_device.c @@ -43,10 +43,7 @@ //--------------------------------------------------------------------+ // MACRO CONSTANT TYPEDEF //--------------------------------------------------------------------+ -enum -{ - BULK_PACKET_SIZE = (TUD_OPT_HIGH_SPEED ? 512 : 64) -}; +#define BULK_PACKET_SIZE (TUD_OPT_HIGH_SPEED ? 512 : 64) typedef struct { @@ -176,9 +173,11 @@ uint32_t tud_cdc_n_write(uint8_t itf, void const* buffer, uint32_t bufsize) uint16_t ret = tu_fifo_write_n(&p_cdc->tx_ff, buffer, (uint16_t) TU_MIN(bufsize, UINT16_MAX)); // flush if queue more than packet size - // may need to suppress -Wunreachable-code since most of the time CFG_TUD_CDC_TX_BUFSIZE < BULK_PACKET_SIZE - if ( (tu_fifo_count(&p_cdc->tx_ff) >= BULK_PACKET_SIZE) || ((CFG_TUD_CDC_TX_BUFSIZE < BULK_PACKET_SIZE) && tu_fifo_full(&p_cdc->tx_ff)) ) - { + if ( tu_fifo_count(&p_cdc->tx_ff) >= BULK_PACKET_SIZE + #if CFG_TUD_CDC_TX_BUFSIZE < BULK_PACKET_SIZE + || tu_fifo_full(&p_cdc->tx_ff) // check full if fifo size is less than packet size + #endif + ) { tud_cdc_n_write_flush(itf); } diff --git a/src/class/usbtmc/usbtmc_device.c b/src/class/usbtmc/usbtmc_device.c index 286cbe108..f6cddfbd7 100644 --- a/src/class/usbtmc/usbtmc_device.c +++ b/src/class/usbtmc/usbtmc_device.c @@ -360,7 +360,7 @@ uint16_t usbtmcd_open_cb(uint8_t rhport, tusb_desc_interface_t const * itf_desc, // processing a command (such as a clear). Returns true if it was // in the NAK state and successfully transitioned to the ACK wait // state. -bool tud_usbtmc_start_bus_read() +bool tud_usbtmc_start_bus_read(void) { usbtmcd_state_enum oldState = usbtmc_state.state; switch(oldState) diff --git a/src/portable/nordic/nrf5x/dcd_nrf5x.c b/src/portable/nordic/nrf5x/dcd_nrf5x.c index 56e7f39a0..2fe721d6b 100644 --- a/src/portable/nordic/nrf5x/dcd_nrf5x.c +++ b/src/portable/nordic/nrf5x/dcd_nrf5x.c @@ -147,7 +147,7 @@ static void start_dma(volatile uint32_t* reg_startep) { static void edpt_dma_start(volatile uint32_t* reg_startep) { if (atomic_flag_test_and_set(&_dcd.dma_running)) { - usbd_defer_func((osal_task_func_t) edpt_dma_start, (void*) (uintptr_t) reg_startep, true); + usbd_defer_func((osal_task_func_t)(uintptr_t ) edpt_dma_start, (void*) (uintptr_t) reg_startep, true); } else { start_dma(reg_startep); } diff --git a/tools/get_deps.py b/tools/get_deps.py index cfa60002a..e08246178 100644 --- a/tools/get_deps.py +++ b/tools/get_deps.py @@ -177,7 +177,8 @@ deps_optional = { '20285262657d1b482d132d20d755c8c330d55c1f', 'imxrt kinetis_k32l2 kinetis_kl lpc51 lpc54 lpc55 mcx mm32 msp432e4 nrf ra saml2x' 'stm32f0 stm32f1 stm32f2 stm32f3 stm32f4 stm32f7 stm32g0 stm32g4 stm32h5' - 'stm32h7 stm32l0 stm32l1 stm32l4 stm32l5 stm32u5 stm32wb'], + 'stm32h7 stm32l0 stm32l1 stm32l4 stm32l5 stm32u5 stm32wb' + 'sam3x samd11 samd21 samd51 same5x same7x saml2x samg'], 'lib/sct_neopixel': ['https://github.com/gsteiert/sct_neopixel.git', 'e73e04ca63495672d955f9268e003cffe168fcd8', 'lpc55'], -- cgit v1.3.1 From 13bde7af403c4f6f3ff6381e23202fc433bffdb2 Mon Sep 17 00:00:00 2001 From: HiFiPhile Date: Tue, 23 Apr 2024 21:36:05 +0200 Subject: uac2: return on clear_feature. --- src/class/audio/audio_device.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'src/class') diff --git a/src/class/audio/audio_device.c b/src/class/audio/audio_device.c index 9050b462a..9ba38a20c 100644 --- a/src/class/audio/audio_device.c +++ b/src/class/audio/audio_device.c @@ -2015,7 +2015,10 @@ static bool audiod_control_request(uint8_t rhport, tusb_control_request_t const case TUSB_REQ_SET_INTERFACE: return audiod_set_interface(rhport, p_request); - // Unknown/Unsupported request + case TUSB_REQ_CLEAR_FEATURE: + return true; + + // Unknown/Unsupported request default: TU_BREAKPOINT(); return false; } } -- cgit v1.3.1 From 7fb8d3341ce2feb46b0bce0bef069d31cf080168 Mon Sep 17 00:00:00 2001 From: HiFiPhile Date: Fri, 26 Apr 2024 13:40:13 +0200 Subject: use separate buffer for ctrl transfer. --- src/class/hid/hid_device.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'src/class') diff --git a/src/class/hid/hid_device.c b/src/class/hid/hid_device.c index ba77d3c5f..a5c709d4c 100644 --- a/src/class/hid/hid_device.c +++ b/src/class/hid/hid_device.c @@ -52,7 +52,7 @@ typedef struct CFG_TUSB_MEM_ALIGN uint8_t epin_buf[CFG_TUD_HID_EP_BUFSIZE]; CFG_TUSB_MEM_ALIGN uint8_t epout_buf[CFG_TUD_HID_EP_BUFSIZE]; - CFG_TUSB_MEM_ALIGN uint8_t set_report_buf[CFG_TUD_HID_EP_BUFSIZE]; + CFG_TUSB_MEM_ALIGN uint8_t ctrl_buf[CFG_TUD_HID_EP_BUFSIZE]; // TODO save hid descriptor since host can specifically request this after enumeration // Note: HID descriptor may be not available from application after enumeration @@ -296,7 +296,7 @@ bool hidd_control_xfer_cb (uint8_t rhport, uint8_t stage, tusb_control_request_t uint8_t const report_type = tu_u16_high(request->wValue); uint8_t const report_id = tu_u16_low(request->wValue); - uint8_t* report_buf = p_hid->epin_buf; + uint8_t* report_buf = p_hid->ctrl_buf; uint16_t req_len = tu_min16(request->wLength, CFG_TUD_HID_EP_BUFSIZE); uint16_t xferlen = 0; @@ -313,22 +313,22 @@ bool hidd_control_xfer_cb (uint8_t rhport, uint8_t stage, tusb_control_request_t xferlen += tud_hid_get_report_cb(hid_itf, report_id, (hid_report_type_t) report_type, report_buf, req_len); TU_ASSERT( xferlen > 0 ); - tud_control_xfer(rhport, request, p_hid->epin_buf, xferlen); + tud_control_xfer(rhport, request, p_hid->ctrl_buf, xferlen); } break; case HID_REQ_CONTROL_SET_REPORT: if ( stage == CONTROL_STAGE_SETUP ) { - TU_VERIFY(request->wLength <= sizeof(p_hid->set_report_buf)); - tud_control_xfer(rhport, request, p_hid->set_report_buf, request->wLength); + TU_VERIFY(request->wLength <= sizeof(p_hid->ctrl_buf)); + tud_control_xfer(rhport, request, p_hid->ctrl_buf, request->wLength); } else if ( stage == CONTROL_STAGE_ACK ) { uint8_t const report_type = tu_u16_high(request->wValue); uint8_t const report_id = tu_u16_low(request->wValue); - uint8_t const* report_buf = p_hid->set_report_buf; + uint8_t const* report_buf = p_hid->ctrl_buf; uint16_t report_len = tu_min16(request->wLength, CFG_TUD_HID_EP_BUFSIZE); // If host request a specific Report ID, extract report ID in buffer before invoking callback -- cgit v1.3.1 From 1661acf82f8e01392de0c18c3472d016679c707d Mon Sep 17 00:00:00 2001 From: HiFiPhile Date: Fri, 26 Apr 2024 13:42:20 +0200 Subject: Add missing alignment. --- src/class/hid/hid_device.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/class') diff --git a/src/class/hid/hid_device.c b/src/class/hid/hid_device.c index a5c709d4c..c66a4597e 100644 --- a/src/class/hid/hid_device.c +++ b/src/class/hid/hid_device.c @@ -46,9 +46,9 @@ typedef struct uint8_t ep_out; // optional Out endpoint uint8_t itf_protocol; // Boot mouse or keyboard - uint8_t protocol_mode; // Boot (0) or Report protocol (1) - uint8_t idle_rate; // up to application to handle idle rate uint16_t report_desc_len; + CFG_TUSB_MEM_ALIGN uint8_t protocol_mode; // Boot (0) or Report protocol (1) + CFG_TUSB_MEM_ALIGN uint8_t idle_rate; // up to application to handle idle rate CFG_TUSB_MEM_ALIGN uint8_t epin_buf[CFG_TUD_HID_EP_BUFSIZE]; CFG_TUSB_MEM_ALIGN uint8_t epout_buf[CFG_TUD_HID_EP_BUFSIZE]; -- cgit v1.3.1 From 4af67dd0078009c1378612440afd5806e84a81c7 Mon Sep 17 00:00:00 2001 From: HiFiPhile Date: Fri, 26 Apr 2024 17:45:14 +0200 Subject: Simplify transfer failure cb. --- .clang-format | 6 ++++++ src/class/hid/hid_device.c | 6 ++++-- src/class/hid/hid_device.h | 3 +-- 3 files changed, 11 insertions(+), 4 deletions(-) create mode 100644 .clang-format (limited to 'src/class') diff --git a/.clang-format b/.clang-format new file mode 100644 index 000000000..4369c29fe --- /dev/null +++ b/.clang-format @@ -0,0 +1,6 @@ +--- +BreakBeforeBraces: Linux +ColumnLimit: '200' +ReflowComments: 'true' + +... diff --git a/src/class/hid/hid_device.c b/src/class/hid/hid_device.c index 564ad12f6..637bc7f61 100644 --- a/src/class/hid/hid_device.c +++ b/src/class/hid/hid_device.c @@ -381,6 +381,8 @@ bool hidd_control_xfer_cb (uint8_t rhport, uint8_t stage, tusb_control_request_t bool hidd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) { + (void) result; + uint8_t instance = 0; hidd_interface_t * p_hid = _hidd_itf; @@ -396,9 +398,9 @@ bool hidd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_ if (XFER_RESULT_SUCCESS != result) { // Inform application about the issue - if (tud_hid_report_issue_cb) + if (tud_hid_report_fail_cb) { - tud_hid_report_issue_cb(instance, ep_addr, result, (uint16_t) xferred_bytes); + tud_hid_report_fail_cb(instance, ep_addr, (uint16_t) xferred_bytes); } // Allow a new transfer to be received if issue happened on an OUT endpoint diff --git a/src/class/hid/hid_device.h b/src/class/hid/hid_device.h index a934753eb..9206d67f8 100644 --- a/src/class/hid/hid_device.h +++ b/src/class/hid/hid_device.h @@ -119,7 +119,7 @@ TU_ATTR_WEAK bool tud_hid_set_idle_cb(uint8_t instance, uint8_t idle_rate); TU_ATTR_WEAK void tud_hid_report_complete_cb(uint8_t instance, uint8_t const* report, uint16_t len); // Invoked when a transfer wasn't successful -TU_ATTR_WEAK void tud_hid_report_issue_cb(uint8_t instance, uint8_t ep_addr, xfer_result_t result, uint16_t len); +TU_ATTR_WEAK void tud_hid_report_fail_cb(uint8_t instance, uint8_t ep_addr, uint16_t len); //--------------------------------------------------------------------+ // Inline Functions @@ -413,7 +413,6 @@ uint16_t hidd_open (uint8_t rhport, tusb_desc_interface_t const * itf bool hidd_control_xfer_cb (uint8_t rhport, uint8_t stage, tusb_control_request_t const * request); bool hidd_xfer_cb (uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes); -void test(void); #ifdef __cplusplus } -- cgit v1.3.1 From 24339dbcce5c5374e0abedf605471753484e4a56 Mon Sep 17 00:00:00 2001 From: HiFiPhile Date: Fri, 26 Apr 2024 18:01:02 +0200 Subject: Code format. --- src/class/hid/hid_device.c | 355 +++++++++++++++++++-------------------------- 1 file changed, 153 insertions(+), 202 deletions(-) (limited to 'src/class') diff --git a/src/class/hid/hid_device.c b/src/class/hid/hid_device.c index 45c10862b..ada01582e 100644 --- a/src/class/hid/hid_device.c +++ b/src/class/hid/hid_device.c @@ -39,12 +39,11 @@ //--------------------------------------------------------------------+ // MACRO CONSTANT TYPEDEF //--------------------------------------------------------------------+ -typedef struct -{ +typedef struct { uint8_t itf_num; uint8_t ep_in; - uint8_t ep_out; // optional Out endpoint - uint8_t itf_protocol; // Boot mouse or keyboard + uint8_t ep_out; // optional Out endpoint + uint8_t itf_protocol; // Boot mouse or keyboard uint16_t report_desc_len; CFG_TUSB_MEM_ALIGN uint8_t protocol_mode; // Boot (0) or Report protocol (1) @@ -56,7 +55,7 @@ typedef struct // TODO save hid descriptor since host can specifically request this after enumeration // Note: HID descriptor may be not available from application after enumeration - tusb_hid_descriptor_hid_t const * hid_descriptor; + tusb_hid_descriptor_hid_t const *hid_descriptor; } hidd_interface_t; CFG_TUD_MEM_SECTION tu_static hidd_interface_t _hidd_itf[CFG_TUD_HID]; @@ -64,12 +63,12 @@ CFG_TUD_MEM_SECTION tu_static hidd_interface_t _hidd_itf[CFG_TUD_HID]; /*------------- Helpers -------------*/ static inline uint8_t get_index_by_itfnum(uint8_t itf_num) { - for (uint8_t i=0; i < CFG_TUD_HID; i++ ) - { - if ( itf_num == _hidd_itf[i].itf_num ) return i; - } + for (uint8_t i = 0; i < CFG_TUD_HID; i++) { + if (itf_num == _hidd_itf[i].itf_num) + return i; + } - return 0xFF; + return 0xFF; } //--------------------------------------------------------------------+ @@ -82,37 +81,29 @@ bool tud_hid_n_ready(uint8_t instance) return tud_ready() && (ep_in != 0) && !usbd_edpt_busy(rhport, ep_in); } -bool tud_hid_n_report(uint8_t instance, uint8_t report_id, void const* report, uint16_t len) +bool tud_hid_n_report(uint8_t instance, uint8_t report_id, void const *report, uint16_t len) { uint8_t const rhport = 0; - hidd_interface_t * p_hid = &_hidd_itf[instance]; + hidd_interface_t *p_hid = &_hidd_itf[instance]; // claim endpoint - TU_VERIFY( usbd_edpt_claim(rhport, p_hid->ep_in) ); + TU_VERIFY(usbd_edpt_claim(rhport, p_hid->ep_in)); // prepare data - if (report_id) - { + if (report_id) { p_hid->epin_buf[0] = report_id; - TU_VERIFY(0 == tu_memcpy_s(p_hid->epin_buf+1, CFG_TUD_HID_EP_BUFSIZE-1, report, len)); + TU_VERIFY(0 == tu_memcpy_s(p_hid->epin_buf + 1, CFG_TUD_HID_EP_BUFSIZE - 1, report, len)); len++; - }else - { + } else { TU_VERIFY(0 == tu_memcpy_s(p_hid->epin_buf, CFG_TUD_HID_EP_BUFSIZE, report, len)); } return usbd_edpt_xfer(rhport, p_hid->ep_in, p_hid->epin_buf, len); } -uint8_t tud_hid_n_interface_protocol(uint8_t instance) -{ - return _hidd_itf[instance].itf_protocol; -} +uint8_t tud_hid_n_interface_protocol(uint8_t instance) { return _hidd_itf[instance].itf_protocol; } -uint8_t tud_hid_n_get_protocol(uint8_t instance) -{ - return _hidd_itf[instance].protocol_mode; -} +uint8_t tud_hid_n_get_protocol(uint8_t instance) { return _hidd_itf[instance].protocol_mode; } bool tud_hid_n_keyboard_report(uint8_t instance, uint8_t report_id, uint8_t modifier, uint8_t keycode[6]) { @@ -121,27 +112,23 @@ bool tud_hid_n_keyboard_report(uint8_t instance, uint8_t report_id, uint8_t modi report.modifier = modifier; report.reserved = 0; - if ( keycode ) - { + if (keycode) { memcpy(report.keycode, keycode, sizeof(report.keycode)); - }else - { + } else { tu_memclr(report.keycode, 6); } return tud_hid_n_report(instance, report_id, &report, sizeof(report)); } -bool tud_hid_n_mouse_report(uint8_t instance, uint8_t report_id, - uint8_t buttons, int8_t x, int8_t y, int8_t vertical, int8_t horizontal) +bool tud_hid_n_mouse_report(uint8_t instance, uint8_t report_id, uint8_t buttons, int8_t x, int8_t y, int8_t vertical, int8_t horizontal) { - hid_mouse_report_t report = - { + hid_mouse_report_t report = { .buttons = buttons, - .x = x, - .y = y, - .wheel = vertical, - .pan = horizontal + .x = x, + .y = y, + .wheel = vertical, + .pan = horizontal }; return tud_hid_n_report(instance, report_id, &report, sizeof(report)); @@ -149,29 +136,27 @@ bool tud_hid_n_mouse_report(uint8_t instance, uint8_t report_id, bool tud_hid_n_abs_mouse_report(uint8_t instance, uint8_t report_id, uint8_t buttons, int16_t x, int16_t y, int8_t vertical, int8_t horizontal) { - hid_abs_mouse_report_t report = - { + hid_abs_mouse_report_t report = { .buttons = buttons, - .x = x, - .y = y, - .wheel = vertical, - .pan = horizontal + .x = x, + .y = y, + .wheel = vertical, + .pan = horizontal }; return tud_hid_n_report(instance, report_id, &report, sizeof(report)); } -bool tud_hid_n_gamepad_report(uint8_t instance, uint8_t report_id, - int8_t x, int8_t y, int8_t z, int8_t rz, int8_t rx, int8_t ry, uint8_t hat, uint32_t buttons) { - hid_gamepad_report_t report = - { - .x = x, - .y = y, - .z = z, - .rz = rz, - .rx = rx, - .ry = ry, - .hat = hat, - .buttons = buttons, +bool tud_hid_n_gamepad_report(uint8_t instance, uint8_t report_id, int8_t x, int8_t y, int8_t z, int8_t rz, int8_t rx, int8_t ry, uint8_t hat, uint32_t buttons) +{ + hid_gamepad_report_t report = { + .x = x, + .y = y, + .z = z, + .rz = rz, + .rx = rx, + .ry = ry, + .hat = hat, + .buttons = buttons, }; return tud_hid_n_report(instance, report_id, &report, sizeof(report)); @@ -180,67 +165,64 @@ bool tud_hid_n_gamepad_report(uint8_t instance, uint8_t report_id, //--------------------------------------------------------------------+ // USBD-CLASS API //--------------------------------------------------------------------+ -void hidd_init(void) { +void hidd_init(void) +{ hidd_reset(0); } -bool hidd_deinit(void) { +bool hidd_deinit(void) +{ return true; } void hidd_reset(uint8_t rhport) { - (void) rhport; + (void)rhport; tu_memclr(_hidd_itf, sizeof(_hidd_itf)); } -uint16_t hidd_open(uint8_t rhport, tusb_desc_interface_t const * desc_itf, uint16_t max_len) - { +uint16_t hidd_open(uint8_t rhport, tusb_desc_interface_t const *desc_itf, uint16_t max_len) +{ TU_VERIFY(TUSB_CLASS_HID == desc_itf->bInterfaceClass, 0); // len = interface + hid + n*endpoints - uint16_t const drv_len = - (uint16_t) (sizeof(tusb_desc_interface_t) + sizeof(tusb_hid_descriptor_hid_t) + - desc_itf->bNumEndpoints * sizeof(tusb_desc_endpoint_t)); + uint16_t const drv_len = (uint16_t)(sizeof(tusb_desc_interface_t) + sizeof(tusb_hid_descriptor_hid_t) + desc_itf->bNumEndpoints * sizeof(tusb_desc_endpoint_t)); TU_ASSERT(max_len >= drv_len, 0); // Find available interface - hidd_interface_t * p_hid = NULL; + hidd_interface_t *p_hid = NULL; uint8_t hid_id; - for(hid_id=0; hid_idhid_descriptor = (tusb_hid_descriptor_hid_t const *) p_desc; + p_hid->hid_descriptor = (tusb_hid_descriptor_hid_t const *)p_desc; //------------- Endpoint Descriptor -------------// p_desc = tu_desc_next(p_desc); TU_ASSERT(usbd_open_edpt_pair(rhport, p_desc, desc_itf->bNumEndpoints, TUSB_XFER_INTERRUPT, &p_hid->ep_out, &p_hid->ep_in), 0); - if ( desc_itf->bInterfaceSubClass == HID_SUBCLASS_BOOT ) p_hid->itf_protocol = desc_itf->bInterfaceProtocol; + if (desc_itf->bInterfaceSubClass == HID_SUBCLASS_BOOT) + p_hid->itf_protocol = desc_itf->bInterfaceProtocol; p_hid->protocol_mode = HID_PROTOCOL_REPORT; // Per Specs: default is report mode - p_hid->itf_num = desc_itf->bInterfaceNumber; + p_hid->itf_num = desc_itf->bInterfaceNumber; // Use offsetof to avoid pointer to the odd/misaligned address - p_hid->report_desc_len = tu_unaligned_read16((uint8_t const*) p_hid->hid_descriptor + offsetof(tusb_hid_descriptor_hid_t, wReportLength)); + p_hid->report_desc_len = tu_unaligned_read16((uint8_t const *)p_hid->hid_descriptor + offsetof(tusb_hid_descriptor_hid_t, wReportLength)); // Prepare for output endpoint - if (p_hid->ep_out) - { - if ( !usbd_edpt_xfer(rhport, p_hid->ep_out, p_hid->epout_buf, sizeof(p_hid->epout_buf)) ) - { + if (p_hid->ep_out) { + if (!usbd_edpt_xfer(rhport, p_hid->ep_out, p_hid->epout_buf, sizeof(p_hid->epout_buf))) { TU_LOG_FAILED(); TU_BREAKPOINT(); } @@ -252,144 +234,120 @@ uint16_t hidd_open(uint8_t rhport, tusb_desc_interface_t const * desc_itf, uint1 // 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 hidd_control_xfer_cb (uint8_t rhport, uint8_t stage, tusb_control_request_t const * request) +bool hidd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request) { TU_VERIFY(request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_INTERFACE); - uint8_t const hid_itf = get_index_by_itfnum((uint8_t) request->wIndex); + uint8_t const hid_itf = get_index_by_itfnum((uint8_t)request->wIndex); TU_VERIFY(hid_itf < CFG_TUD_HID); - hidd_interface_t* p_hid = &_hidd_itf[hid_itf]; + hidd_interface_t *p_hid = &_hidd_itf[hid_itf]; - if (request->bmRequestType_bit.type == TUSB_REQ_TYPE_STANDARD) - { + if (request->bmRequestType_bit.type == TUSB_REQ_TYPE_STANDARD) { //------------- STD Request -------------// - if ( stage == CONTROL_STAGE_SETUP ) - { - uint8_t const desc_type = tu_u16_high(request->wValue); - //uint8_t const desc_index = tu_u16_low (request->wValue); + if (stage == CONTROL_STAGE_SETUP) { + uint8_t const desc_type = tu_u16_high(request->wValue); + // uint8_t const desc_index = tu_u16_low (request->wValue); - if (request->bRequest == TUSB_REQ_GET_DESCRIPTOR && desc_type == HID_DESC_TYPE_HID) - { + if (request->bRequest == TUSB_REQ_GET_DESCRIPTOR && desc_type == HID_DESC_TYPE_HID) { TU_VERIFY(p_hid->hid_descriptor); - TU_VERIFY(tud_control_xfer(rhport, request, (void*)(uintptr_t) p_hid->hid_descriptor, p_hid->hid_descriptor->bLength)); - } - else if (request->bRequest == TUSB_REQ_GET_DESCRIPTOR && desc_type == HID_DESC_TYPE_REPORT) - { - uint8_t const * desc_report = tud_hid_descriptor_report_cb(hid_itf); - tud_control_xfer(rhport, request, (void*)(uintptr_t) desc_report, p_hid->report_desc_len); - } - else - { + TU_VERIFY(tud_control_xfer(rhport, request, (void *)(uintptr_t)p_hid->hid_descriptor, p_hid->hid_descriptor->bLength)); + } else if (request->bRequest == TUSB_REQ_GET_DESCRIPTOR && desc_type == HID_DESC_TYPE_REPORT) { + uint8_t const *desc_report = tud_hid_descriptor_report_cb(hid_itf); + tud_control_xfer(rhport, request, (void *)(uintptr_t)desc_report, p_hid->report_desc_len); + } else { return false; // stall unsupported request } } - } - else if (request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS) - { + } else if (request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS) { //------------- Class Specific Request -------------// - switch( request->bRequest ) - { - case HID_REQ_CONTROL_GET_REPORT: - if ( stage == CONTROL_STAGE_SETUP ) - { - uint8_t const report_type = tu_u16_high(request->wValue); - uint8_t const report_id = tu_u16_low(request->wValue); + switch (request->bRequest) { + case HID_REQ_CONTROL_GET_REPORT: + if (stage == CONTROL_STAGE_SETUP) { + uint8_t const report_type = tu_u16_high(request->wValue); + uint8_t const report_id = tu_u16_low(request->wValue); - uint8_t* report_buf = p_hid->ctrl_buf; - uint16_t req_len = tu_min16(request->wLength, CFG_TUD_HID_EP_BUFSIZE); + uint8_t *report_buf = p_hid->ctrl_buf; + uint16_t req_len = tu_min16(request->wLength, CFG_TUD_HID_EP_BUFSIZE); - uint16_t xferlen = 0; + uint16_t xferlen = 0; - // If host request a specific Report ID, add ID to as 1 byte of response - if ( (report_id != HID_REPORT_TYPE_INVALID) && (req_len > 1) ) - { - *report_buf++ = report_id; - req_len--; + // If host request a specific Report ID, add ID to as 1 byte of response + if ((report_id != HID_REPORT_TYPE_INVALID) && (req_len > 1)) { + *report_buf++ = report_id; + req_len--; - xferlen++; - } + xferlen++; + } - xferlen += tud_hid_get_report_cb(hid_itf, report_id, (hid_report_type_t) report_type, report_buf, req_len); - TU_ASSERT( xferlen > 0 ); + xferlen += tud_hid_get_report_cb(hid_itf, report_id, (hid_report_type_t)report_type, report_buf, req_len); + TU_ASSERT(xferlen > 0); - tud_control_xfer(rhport, request, p_hid->ctrl_buf, xferlen); - } + tud_control_xfer(rhport, request, p_hid->ctrl_buf, xferlen); + } break; - case HID_REQ_CONTROL_SET_REPORT: - if ( stage == CONTROL_STAGE_SETUP ) - { - TU_VERIFY(request->wLength <= sizeof(p_hid->ctrl_buf)); - tud_control_xfer(rhport, request, p_hid->ctrl_buf, request->wLength); - } - else if ( stage == CONTROL_STAGE_ACK ) - { - uint8_t const report_type = tu_u16_high(request->wValue); - uint8_t const report_id = tu_u16_low(request->wValue); - - uint8_t const* report_buf = p_hid->ctrl_buf; - uint16_t report_len = tu_min16(request->wLength, CFG_TUD_HID_EP_BUFSIZE); - - // If host request a specific Report ID, extract report ID in buffer before invoking callback - if ( (report_id != HID_REPORT_TYPE_INVALID) && (report_len > 1) && (report_id == report_buf[0]) ) - { - report_buf++; - report_len--; - } - - tud_hid_set_report_cb(hid_itf, report_id, (hid_report_type_t) report_type, report_buf, report_len); + case HID_REQ_CONTROL_SET_REPORT: + if (stage == CONTROL_STAGE_SETUP) { + TU_VERIFY(request->wLength <= sizeof(p_hid->ctrl_buf)); + tud_control_xfer(rhport, request, p_hid->ctrl_buf, request->wLength); + } else if (stage == CONTROL_STAGE_ACK) { + uint8_t const report_type = tu_u16_high(request->wValue); + uint8_t const report_id = tu_u16_low(request->wValue); + + uint8_t const *report_buf = p_hid->ctrl_buf; + uint16_t report_len = tu_min16(request->wLength, CFG_TUD_HID_EP_BUFSIZE); + + // If host request a specific Report ID, extract report ID in buffer before invoking callback + if ((report_id != HID_REPORT_TYPE_INVALID) && (report_len > 1) && (report_id == report_buf[0])) { + report_buf++; + report_len--; } + + tud_hid_set_report_cb(hid_itf, report_id, (hid_report_type_t)report_type, report_buf, report_len); + } break; - case HID_REQ_CONTROL_SET_IDLE: - if ( stage == CONTROL_STAGE_SETUP ) - { - p_hid->idle_rate = tu_u16_high(request->wValue); - if ( tud_hid_set_idle_cb ) - { - // stall request if callback return false - TU_VERIFY( tud_hid_set_idle_cb( hid_itf, p_hid->idle_rate) ); - } - - tud_control_status(rhport, request); + case HID_REQ_CONTROL_SET_IDLE: + if (stage == CONTROL_STAGE_SETUP) { + p_hid->idle_rate = tu_u16_high(request->wValue); + if (tud_hid_set_idle_cb) { + // stall request if callback return false + TU_VERIFY(tud_hid_set_idle_cb(hid_itf, p_hid->idle_rate)); } + + tud_control_status(rhport, request); + } break; - case HID_REQ_CONTROL_GET_IDLE: - if ( stage == CONTROL_STAGE_SETUP ) - { - // TODO idle rate of report - tud_control_xfer(rhport, request, &p_hid->idle_rate, 1); - } + case HID_REQ_CONTROL_GET_IDLE: + if (stage == CONTROL_STAGE_SETUP) { + // TODO idle rate of report + tud_control_xfer(rhport, request, &p_hid->idle_rate, 1); + } break; - case HID_REQ_CONTROL_GET_PROTOCOL: - if ( stage == CONTROL_STAGE_SETUP ) - { - tud_control_xfer(rhport, request, &p_hid->protocol_mode, 1); - } + case HID_REQ_CONTROL_GET_PROTOCOL: + if (stage == CONTROL_STAGE_SETUP) { + tud_control_xfer(rhport, request, &p_hid->protocol_mode, 1); + } break; - case HID_REQ_CONTROL_SET_PROTOCOL: - if ( stage == CONTROL_STAGE_SETUP ) - { - tud_control_status(rhport, request); - } - else if ( stage == CONTROL_STAGE_ACK ) - { - p_hid->protocol_mode = (uint8_t) request->wValue; - if (tud_hid_set_protocol_cb) - { - tud_hid_set_protocol_cb(hid_itf, p_hid->protocol_mode); - } + case HID_REQ_CONTROL_SET_PROTOCOL: + if (stage == CONTROL_STAGE_SETUP) { + tud_control_status(rhport, request); + } else if (stage == CONTROL_STAGE_ACK) { + p_hid->protocol_mode = (uint8_t)request->wValue; + if (tud_hid_set_protocol_cb) { + tud_hid_set_protocol_cb(hid_itf, p_hid->protocol_mode); } + } break; - default: return false; // stall unsupported request + default: + return false; // stall unsupported request } - }else - { + } else { return false; // stall unsupported request } @@ -398,31 +356,27 @@ bool hidd_control_xfer_cb (uint8_t rhport, uint8_t stage, tusb_control_request_t bool hidd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) { - (void) result; + (void)result; uint8_t instance = 0; - hidd_interface_t * p_hid = _hidd_itf; + hidd_interface_t *p_hid = _hidd_itf; // Identify which interface to use - for (instance = 0; instance < CFG_TUD_HID; instance++) - { + for (instance = 0; instance < CFG_TUD_HID; instance++) { p_hid = &_hidd_itf[instance]; - if ( (ep_addr == p_hid->ep_out) || (ep_addr == p_hid->ep_in) ) break; + if ((ep_addr == p_hid->ep_out) || (ep_addr == p_hid->ep_in)) + break; } TU_ASSERT(instance < CFG_TUD_HID); // Check if there was a problem - if (XFER_RESULT_SUCCESS != result) - { - // Inform application about the issue - if (tud_hid_report_fail_cb) - { - tud_hid_report_fail_cb(instance, ep_addr, (uint16_t) xferred_bytes); + if (XFER_RESULT_SUCCESS != result) { // Inform application about the issue + if (tud_hid_report_fail_cb) { + tud_hid_report_fail_cb(instance, ep_addr, (uint16_t)xferred_bytes); } // Allow a new transfer to be received if issue happened on an OUT endpoint - if (ep_addr == p_hid->ep_out) - { + if (ep_addr == p_hid->ep_out) { // Prepare the OUT endpoint to be able to receive a new transfer TU_ASSERT(usbd_edpt_xfer(rhport, p_hid->ep_out, p_hid->epout_buf, sizeof(p_hid->epout_buf))); } @@ -431,17 +385,14 @@ bool hidd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_ } // Sent report successfully - if (ep_addr == p_hid->ep_in) - { - if (tud_hid_report_complete_cb) - { - tud_hid_report_complete_cb(instance, p_hid->epin_buf, (uint16_t) xferred_bytes); + if (ep_addr == p_hid->ep_in) { + if (tud_hid_report_complete_cb) { + tud_hid_report_complete_cb(instance, p_hid->epin_buf, (uint16_t)xferred_bytes); } } // Received report successfully - else if (ep_addr == p_hid->ep_out) - { - tud_hid_set_report_cb(instance, 0, HID_REPORT_TYPE_OUTPUT, p_hid->epout_buf, (uint16_t) xferred_bytes); + else if (ep_addr == p_hid->ep_out) { + tud_hid_set_report_cb(instance, 0, HID_REPORT_TYPE_OUTPUT, p_hid->epout_buf, (uint16_t)xferred_bytes); TU_ASSERT(usbd_edpt_xfer(rhport, p_hid->ep_out, p_hid->epout_buf, sizeof(p_hid->epout_buf))); } -- cgit v1.3.1 From 98e85a296deb89dbcc05033bda26e3c9581d535b Mon Sep 17 00:00:00 2001 From: HiFiPhile Date: Sat, 27 Apr 2024 17:09:05 +0200 Subject: bulk_in: copy buffer to ensure alignment correctness. --- src/class/usbtmc/usbtmc_device.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'src/class') diff --git a/src/class/usbtmc/usbtmc_device.c b/src/class/usbtmc/usbtmc_device.c index 4092c37ea..81e969732 100644 --- a/src/class/usbtmc/usbtmc_device.c +++ b/src/class/usbtmc/usbtmc_device.c @@ -552,9 +552,10 @@ bool usbtmcd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint case STATE_TX_INITIATED: if(usbtmc_state.transfer_size_remaining >= sizeof(usbtmc_state.ep_bulk_in_buf)) { - // FIXME! This removes const below! + // Copy buffer to ensure alignment correctness + memcpy(usbtmc_state.ep_bulk_in_buf, usbtmc_state.devInBuffer, sizeof(usbtmc_state.ep_bulk_in_buf)); TU_VERIFY( usbd_edpt_xfer(rhport, usbtmc_state.ep_bulk_in, - (void*)(uintptr_t) usbtmc_state.devInBuffer, sizeof(usbtmc_state.ep_bulk_in_buf))); + usbtmc_state.ep_bulk_in_buf, sizeof(usbtmc_state.ep_bulk_in_buf))); usbtmc_state.devInBuffer += sizeof(usbtmc_state.ep_bulk_in_buf); usbtmc_state.transfer_size_remaining -= sizeof(usbtmc_state.ep_bulk_in_buf); usbtmc_state.transfer_size_sent += sizeof(usbtmc_state.ep_bulk_in_buf); -- cgit v1.3.1 From fdb431b5c70ff605eebda8988e1728e7118b4ab4 Mon Sep 17 00:00:00 2001 From: HiFiPhile Date: Sat, 27 Apr 2024 17:12:00 +0200 Subject: Buffer int msg to ensure alignment and placement correctness. --- src/class/usbtmc/usbtmc_device.c | 18 +++++++++++++----- src/class/usbtmc/usbtmc_device.h | 17 ++++++----------- 2 files changed, 19 insertions(+), 16 deletions(-) (limited to 'src/class') diff --git a/src/class/usbtmc/usbtmc_device.c b/src/class/usbtmc/usbtmc_device.c index 81e969732..59d9b184e 100644 --- a/src/class/usbtmc/usbtmc_device.c +++ b/src/class/usbtmc/usbtmc_device.c @@ -86,6 +86,11 @@ tu_static char logMsg[150]; // imposes a minimum buffer size of 32 bytes. #define USBTMCD_BUFFER_SIZE (TUD_OPT_HIGH_SPEED ? 512 : 64) +// Interrupt endpoint buffer size, default to 2 bytes as USB488 specification. +#ifndef CFG_TUD_USBTMC_INT_EP_SIZE +#define CFG_TUD_USBTMC_INT_EP_SIZE 2 +#endif + /* * The state machine does not allow simultaneous reading and writing. This is * consistent with USBTMC. @@ -124,13 +129,15 @@ typedef struct uint8_t ep_bulk_in; uint8_t ep_bulk_out; uint8_t ep_int_in; + uint32_t ep_bulk_in_wMaxPacketSize; + uint32_t ep_bulk_out_wMaxPacketSize; // IN buffer is only used for first packet, not the remainder // in order to deal with prepending header CFG_TUSB_MEM_ALIGN uint8_t ep_bulk_in_buf[USBTMCD_BUFFER_SIZE]; - uint32_t ep_bulk_in_wMaxPacketSize; // OUT buffer receives one packet at a time CFG_TUSB_MEM_ALIGN uint8_t ep_bulk_out_buf[USBTMCD_BUFFER_SIZE]; - uint32_t ep_bulk_out_wMaxPacketSize; + // Buffer int msg to ensure alignment and placement correctness + CFG_TUSB_MEM_ALIGN uint8_t ep_int_in_buf[CFG_TUD_USBTMC_INT_EP_SIZE]; uint32_t transfer_size_remaining; // also used for requested length for bulk IN. uint32_t transfer_size_sent; // To keep track of data bytes that have been queued in FIFO (not header bytes) @@ -243,12 +250,13 @@ bool tud_usbtmc_transmit_dev_msg_data( bool tud_usbtmc_transmit_notification_data(const void * data, size_t len) { #ifndef NDEBUG - TU_ASSERT(len >= 1); + TU_ASSERT(len > 0); TU_ASSERT(usbtmc_state.ep_int_in != 0); #endif - if (usbd_edpt_busy(usbtmc_state.rhport, usbtmc_state.ep_int_in)) return false; + TU_VERIFY(usbd_edpt_busy(usbtmc_state.rhport, usbtmc_state.ep_int_in)); - TU_VERIFY(usbd_edpt_xfer(usbtmc_state.rhport, usbtmc_state.ep_int_in, (void *)(uintptr_t) data, len)); + TU_VERIFY(tu_memcpy_s(usbtmc_state.ep_int_in_buf, sizeof(usbtmc_state.ep_int_in_buf), data, len) == 0); + TU_VERIFY(usbd_edpt_xfer(usbtmc_state.rhport, usbtmc_state.ep_int_in, usbtmc_state.ep_int_in_buf, len)); return true; } diff --git a/src/class/usbtmc/usbtmc_device.h b/src/class/usbtmc/usbtmc_device.h index 2f3c91dbd..af7ea6ec9 100644 --- a/src/class/usbtmc/usbtmc_device.h +++ b/src/class/usbtmc/usbtmc_device.h @@ -86,21 +86,16 @@ TU_ATTR_WEAK bool tud_usbtmc_msg_trigger_cb(usbtmc_msg_generic_t* msg); //TU_ATTR_WEAK bool tud_usbtmc_app_go_to_local_cb(); #endif -/******************************************* - * Called from app - * - * We keep a reference to the buffer, so it MUST not change until the app is - * notified that the transfer is complete. - ******************************************/ - +// Called from app +// +// We keep a reference to the buffer, so it MUST not change until the app is +// notified that the transfer is complete. bool tud_usbtmc_transmit_dev_msg_data( const void * data, size_t len, bool endOfMessage, bool usingTermChar); -// Buffers a notification to be sent to the host. The buffer must be -// valid until the tud_usbtmc_notification_complete_cb callback. The -// data starts with the bNotify1 field, see the USBTMC Specification, -// Table 13. +// Buffers a notification to be sent to the host. The data starts +// with the bNotify1 field, see the USBTMC Specification, Table 13. // // If the previous notification data has not yet been sent, this // returns false. -- cgit v1.3.1 From bd033a2d531d09478ddd947121e12aa6ece86d56 Mon Sep 17 00:00:00 2001 From: HiFiPhile Date: Sat, 27 Apr 2024 17:24:19 +0200 Subject: Fix CI. --- src/class/usbtmc/usbtmc_device.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/class') diff --git a/src/class/usbtmc/usbtmc_device.c b/src/class/usbtmc/usbtmc_device.c index 59d9b184e..f80abdaf3 100644 --- a/src/class/usbtmc/usbtmc_device.c +++ b/src/class/usbtmc/usbtmc_device.c @@ -256,7 +256,7 @@ bool tud_usbtmc_transmit_notification_data(const void * data, size_t len) TU_VERIFY(usbd_edpt_busy(usbtmc_state.rhport, usbtmc_state.ep_int_in)); TU_VERIFY(tu_memcpy_s(usbtmc_state.ep_int_in_buf, sizeof(usbtmc_state.ep_int_in_buf), data, len) == 0); - TU_VERIFY(usbd_edpt_xfer(usbtmc_state.rhport, usbtmc_state.ep_int_in, usbtmc_state.ep_int_in_buf, len)); + TU_VERIFY(usbd_edpt_xfer(usbtmc_state.rhport, usbtmc_state.ep_int_in, usbtmc_state.ep_int_in_buf, (uint16_t)len)); return true; } -- cgit v1.3.1 From 327e3ec4bd1908e57e2ecd90738f01fc04a17ba1 Mon Sep 17 00:00:00 2001 From: HiFiPhile Date: Sun, 28 Apr 2024 21:59:54 +0200 Subject: Stall unsupported class request. --- src/class/net/ncm_device.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) (limited to 'src/class') diff --git a/src/class/net/ncm_device.c b/src/class/net/ncm_device.c index 14ace9d8e..829161865 100644 --- a/src/class/net/ncm_device.c +++ b/src/class/net/ncm_device.c @@ -947,7 +947,7 @@ bool netd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t } switch (request->bmRequestType_bit.type) { - case TUSB_REQ_TYPE_STANDARD: + case TUSB_REQ_TYPE_STANDARD: { switch (request->bRequest) { case TUSB_REQ_GET_INTERFACE: { TU_VERIFY(ncm_interface.itf_num + 1 == request->wIndex, false); @@ -975,14 +975,15 @@ bool netd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t default: return false; } - break; + } + break; - case TUSB_REQ_TYPE_CLASS: + case TUSB_REQ_TYPE_CLASS: { TU_VERIFY(ncm_interface.itf_num == request->wIndex, false); - + switch (request->bRequest) { TU_LOG3(" TUSB_REQ_TYPE_CLASS: %d\n", request->bRequest); - if (request->bRequest == NCM_GET_NTB_PARAMETERS) { + case NCM_GET_NTB_PARAMETERS: { // transfer NTB parameters to host. // TODO can one assume, that tud_control_xfer() succeeds? TU_LOG3(" NCM_GET_NTB_PARAMETERS\n"); @@ -990,6 +991,13 @@ bool netd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t } break; + // unsupported request + default: + return false ; + + } + } + break; // unsupported request default: return false ; -- cgit v1.3.1 From ea55537fb2a42e112c8d4f714c71c51b2faa88d6 Mon Sep 17 00:00:00 2001 From: Hardy Griech Date: Sun, 5 May 2024 20:33:01 +0200 Subject: minor changes due to CR with HiFiPhile --- src/class/net/ncm.h | 50 ++++++++++++++++++++++++++-------------------- src/class/net/ncm_device.c | 6 +++--- 2 files changed, 31 insertions(+), 25 deletions(-) (limited to 'src/class') diff --git a/src/class/net/ncm.h b/src/class/net/ncm.h index c768192a5..cf4daf96c 100644 --- a/src/class/net/ncm.h +++ b/src/class/net/ncm.h @@ -2,6 +2,7 @@ * The MIT License (MIT) * * Copyright (c) 2021, Ha Thach (tinyusb.org) + * Copyright (c) 2024, Hardy Griech * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -29,42 +30,47 @@ #define _TUSB_NCM_H_ #include "common/tusb_common.h" - +#include "lwipopts.h" #ifndef CFG_TUD_NCM_IN_NTB_MAX_SIZE - /// must be >> MTU - #define CFG_TUD_NCM_IN_NTB_MAX_SIZE 3200 + #define CFG_TUD_NCM_IN_NTB_MAX_SIZE (2 * TCP_MSS + 100) #endif #ifndef CFG_TUD_NCM_OUT_NTB_MAX_SIZE - /// must be >> MTU - #define CFG_TUD_NCM_OUT_NTB_MAX_SIZE 3200 + #define CFG_TUD_NCM_OUT_NTB_MAX_SIZE (2 * TCP_MSS + 100) #endif #ifndef CFG_TUD_NCM_OUT_NTB_N - /// number of ntb buffers for reception side - /// 1 - good performance - /// 2 - up to 30% more performance with iperf with small packets - /// >2 - no performance gain - #define CFG_TUD_NCM_OUT_NTB_N 2 + /// number of NTB buffers for reception side + /// 1 - good performance + /// 2 - up to 30% more performance with iperf with small packets + /// >2 - no performance gain + /// -> for performance optimizations this parameter could be increased with the cost of additional RAM requirements + #define CFG_TUD_NCM_OUT_NTB_N 1 #endif #ifndef CFG_TUD_NCM_IN_NTB_N - /// number of ntb buffers for transmission side - /// 1 - good performance but SystemView shows lost events (on load test) - /// 2 - up to 50% more performance with iperf with small packets, "tud_network_can_xmit: request blocked" - /// happens from time to time with SystemView - /// 3 - "tud_network_can_xmit: request blocked" never happens - /// >2 - no performance gain - #define CFG_TUD_NCM_IN_NTB_N 3 + /// number of NTB buffers for transmission side + /// 1 - good performance but SystemView shows lost events (on load test) + /// 2 - up to 50% more performance with iperf with small packets, "tud_network_can_xmit: request blocked" + /// happens from time to time with SystemView + /// 3 - "tud_network_can_xmit: request blocked" never happens + /// >2 - no performance gain + /// -> for performance optimizations this parameter could be increased with the cost of additional RAM requirements + #define CFG_TUD_NCM_IN_NTB_N 1 +#endif + +#ifndef CFG_TUD_NCM_IN_MAX_DATAGRAMS_PER_NTB + /// this is for the transmission side for allocation of \a ndp16_datagram_t + #define CFG_TUD_NCM_IN_MAX_DATAGRAMS_PER_NTB 8 #endif -#ifndef CFG_TUD_NCM_MAX_DATAGRAMS_PER_NTB - /// this is for the transmission size for allocation of \a ndp16_datagram_t - #define CFG_TUD_NCM_MAX_DATAGRAMS_PER_NTB 8 +#ifndef CFG_TUD_NCM_OUT_MAX_DATAGRAMS_PER_NTB + /// this tells the host how many datagrams it is allowed to put into an NTB + #define CFG_TUD_NCM_OUT_MAX_DATAGRAMS_PER_NTB 6 #endif #ifndef CFG_TUD_NCM_ALIGNMENT - #define CFG_TUD_NCM_ALIGNMENT 4 + #define CFG_TUD_NCM_ALIGNMENT 4 #endif #if (CFG_TUD_NCM_ALIGNMENT != 4) #error "CFG_TUD_NCM_ALIGNMENT must be 4, otherwise the headers and start of datagrams have to be aligned (which they are currently not)" @@ -136,7 +142,7 @@ typedef union TU_ATTR_PACKED { struct { nth16_t nth; ndp16_t ndp; - ndp16_datagram_t ndp_datagram[CFG_TUD_NCM_MAX_DATAGRAMS_PER_NTB + 1]; + ndp16_datagram_t ndp_datagram[CFG_TUD_NCM_IN_MAX_DATAGRAMS_PER_NTB + 1]; }; uint8_t data[CFG_TUD_NCM_IN_NTB_MAX_SIZE]; } xmit_ntb_t; diff --git a/src/class/net/ncm_device.c b/src/class/net/ncm_device.c index 829161865..40f70dc3f 100644 --- a/src/class/net/ncm_device.c +++ b/src/class/net/ncm_device.c @@ -1,8 +1,8 @@ /* * The MIT License (MIT) * - * Copyright (c) 2023 Hardy Griech * Copyright (c) 2019 Ha Thach (tinyusb.org) + * Copyright (c) 2024 Hardy Griech * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -126,7 +126,7 @@ CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN tu_static const ntb_parameters_t ntb_par .wNdbOutDivisor = 4, .wNdbOutPayloadRemainder = 0, .wNdbOutAlignment = CFG_TUD_NCM_ALIGNMENT, - .wNtbOutMaxDatagrams = 6 // 0=no limit + .wNtbOutMaxDatagrams = CFG_TUD_NCM_OUT_MAX_DATAGRAMS_PER_NTB, }; //----------------------------------------------------------------------------- @@ -371,7 +371,7 @@ static bool xmit_requested_datagram_fits_into_current_ntb(uint16_t datagram_size if (ncm_interface.xmit_glue_ntb == NULL) { return false; } - if (ncm_interface.xmit_glue_ntb_datagram_ndx >= CFG_TUD_NCM_MAX_DATAGRAMS_PER_NTB) { + if (ncm_interface.xmit_glue_ntb_datagram_ndx >= CFG_TUD_NCM_IN_MAX_DATAGRAMS_PER_NTB) { return false; } if (ncm_interface.xmit_glue_ntb->nth.wBlockLength + datagram_size + XMIT_ALIGN_OFFSET(datagram_size) > CFG_TUD_NCM_OUT_NTB_MAX_SIZE) { -- cgit v1.3.1 From cc70958c16f4b88c0e48590d32189c870091547e Mon Sep 17 00:00:00 2001 From: Hardy Griech Date: Sun, 5 May 2024 21:18:57 +0200 Subject: mostly comments --- src/class/net/ncm_device.c | 56 +++++++++++++++++++++++++++++----------------- 1 file changed, 35 insertions(+), 21 deletions(-) (limited to 'src/class') diff --git a/src/class/net/ncm_device.c b/src/class/net/ncm_device.c index 40f70dc3f..05cebf94e 100644 --- a/src/class/net/ncm_device.c +++ b/src/class/net/ncm_device.c @@ -79,7 +79,7 @@ typedef struct { uint8_t rhport; //!< storage of \a rhport because some callbacks are done without it // recv handling - CFG_TUSB_MEM_ALIGN recv_ntb_t recv_ntb[RECV_NTB_N]; //!< actual recv NTBs + CFG_TUSB_MEM_ALIGN recv_ntb_t recv_ntb[RECV_NTB_N]; //!< actual recv NTBs recv_ntb_t *recv_free_ntb[RECV_NTB_N]; //!< free list of recv NTBs recv_ntb_t *recv_ready_ntb[RECV_NTB_N]; //!< NTBs waiting for transmission to glue logic recv_ntb_t *recv_tinyusb_ntb; //!< buffer for the running transfer TinyUSB -> driver @@ -87,7 +87,7 @@ typedef struct { uint16_t recv_glue_ntb_datagram_ndx; //!< index into \a recv_glue_ntb_datagram // xmit handling - CFG_TUSB_MEM_ALIGN xmit_ntb_t xmit_ntb[XMIT_NTB_N]; //!< actual xmit NTBs + CFG_TUSB_MEM_ALIGN xmit_ntb_t xmit_ntb[XMIT_NTB_N]; //!< actual xmit NTBs xmit_ntb_t *xmit_free_ntb[XMIT_NTB_N]; //!< free list of xmit NTBs xmit_ntb_t *xmit_ready_ntb[XMIT_NTB_N]; //!< NTBs waiting for transmission to TinyUSB xmit_ntb_t *xmit_tinyusb_ntb; //!< buffer for the running transfer driver -> TinyUSB @@ -129,6 +129,18 @@ CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN tu_static const ntb_parameters_t ntb_par .wNtbOutMaxDatagrams = CFG_TUD_NCM_OUT_MAX_DATAGRAMS_PER_NTB, }; +// Some confusing remarks about wNtbOutMaxDatagrams... +// ==1 -> SystemView packets/s goes up to 2000 and events are lost during startup +// ==0 -> SystemView runs fine, iperf shows in wireshark a lot of error +// ==6 -> SystemView runs fine, iperf also +// >6 -> iperf starts to show errors +// -> 6 seems to be the best value. Why? Don't know, perhaps only on my system? +// switch \a TU_LOG2 on to see interesting values for this. +// +// iperf: for MSS in 100 200 400 800 1200 1450 1500; do iperf -c 192.168.14.1 -e -i 1 -M $MSS -l 8192 -P 1; sleep 2; done +// sysview: SYSTICKS_PER_SEC=35000, IDLE_US=1000, PRINT_MOD=1000 +// + //----------------------------------------------------------------------------- // // everything about notifications @@ -340,7 +352,7 @@ static void xmit_start_if_possible(uint8_t rhport) ncm_interface.xmit_glue_ntb = NULL; } -#ifdef DEBUG_OUT_ENABLED +#if CFG_TUSB_DEBUG >= 3 { uint16_t len = ncm_interface.xmit_tinyusb_ntb->nth.wBlockLength; TU_LOG3(" %d\n", len); @@ -708,7 +720,7 @@ bool tud_network_can_xmit(uint16_t size) return true; } xmit_start_if_possible(ncm_interface.rhport); - TU_LOG2("tud_network_can_xmit: request blocked\n"); // could happen if all xmit buffers are full (but should happen rarely) + TU_LOG2("(II) tud_network_can_xmit: request blocked\n"); // could happen if all xmit buffers are full (but should happen rarely) return false; } // tud_network_can_xmit @@ -796,10 +808,18 @@ void netd_init(void) } } // netd_init -bool netd_deinit(void) { - return true; + + +bool netd_deinit(void) +/** + * Deinit driver + */ +{ + return true; } + + void netd_reset(uint8_t rhport) /** * Resets the port. @@ -947,12 +967,14 @@ bool netd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t } switch (request->bmRequestType_bit.type) { - case TUSB_REQ_TYPE_STANDARD: { + case TUSB_REQ_TYPE_STANDARD: + TU_LOG3(" TUSB_REQ_TYPE_STANDARD: %d\n", request->bRequest); + switch (request->bRequest) { case TUSB_REQ_GET_INTERFACE: { TU_VERIFY(ncm_interface.itf_num + 1 == request->wIndex, false); - TU_LOG3(" TUSB_REQ_GET_INTERFACE - %d\n", ncm_interface.itf_data_alt); + TU_LOG3(" TUSB_REQ_GET_INTERFACE - %d\n", ncm_interface.itf_data_alt); tud_control_xfer(rhport, request, &ncm_interface.itf_data_alt, 1); } break; @@ -961,7 +983,7 @@ bool netd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t TU_VERIFY(ncm_interface.itf_num + 1 == request->wIndex && request->wValue < 2, false); ncm_interface.itf_data_alt = (uint8_t)request->wValue; - TU_LOG3(" TUSB_REQ_SET_INTERFACE - %d %d %d\n", ncm_interface.itf_data_alt, request->wIndex, ncm_interface.itf_num); + TU_LOG3(" TUSB_REQ_SET_INTERFACE - %d %d %d\n", ncm_interface.itf_data_alt, request->wIndex, ncm_interface.itf_num); if (ncm_interface.itf_data_alt == 1) { tud_network_recv_renew_r(rhport); @@ -975,15 +997,14 @@ bool netd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t default: return false; } - } - break; + break; - case TUSB_REQ_TYPE_CLASS: { + case TUSB_REQ_TYPE_CLASS: TU_VERIFY(ncm_interface.itf_num == request->wIndex, false); - switch (request->bRequest) { + TU_LOG3(" TUSB_REQ_TYPE_CLASS: %d\n", request->bRequest); - case NCM_GET_NTB_PARAMETERS: { + if (request->bRequest == NCM_GET_NTB_PARAMETERS) { // transfer NTB parameters to host. // TODO can one assume, that tud_control_xfer() succeeds? TU_LOG3(" NCM_GET_NTB_PARAMETERS\n"); @@ -991,13 +1012,6 @@ bool netd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t } break; - // unsupported request - default: - return false ; - - } - } - break; // unsupported request default: return false ; -- cgit v1.3.1 From 91d69fa942c8a450c9816595f0d19138964533ef Mon Sep 17 00:00:00 2001 From: HiFiPhile Date: Tue, 7 May 2024 00:10:26 +0200 Subject: Reformat NCM class. --- src/class/net/ncm.h | 141 +++-- src/class/net/ncm_device.c | 1270 ++++++++++++++++++++------------------------ 2 files changed, 640 insertions(+), 771 deletions(-) (limited to 'src/class') diff --git a/src/class/net/ncm.h b/src/class/net/ncm.h index cf4daf96c..1b987fca0 100644 --- a/src/class/net/ncm.h +++ b/src/class/net/ncm.h @@ -25,58 +25,59 @@ * This file is part of the TinyUSB stack. */ - #ifndef _TUSB_NCM_H_ #define _TUSB_NCM_H_ #include "common/tusb_common.h" -#include "lwipopts.h" -#ifndef CFG_TUD_NCM_IN_NTB_MAX_SIZE - #define CFG_TUD_NCM_IN_NTB_MAX_SIZE (2 * TCP_MSS + 100) -#endif +// NTB buffers size for reception side, must be >> MTU to avoid TCP retransmission (driver issue ?) +// Linux use 2048 as minimal size #ifndef CFG_TUD_NCM_OUT_NTB_MAX_SIZE - #define CFG_TUD_NCM_OUT_NTB_MAX_SIZE (2 * TCP_MSS + 100) + #define CFG_TUD_NCM_OUT_NTB_MAX_SIZE 3200 +#endif + +// NTB buffers size for reception side, must be > MTU +// Linux use 2048 as minimal size +#ifndef CFG_TUD_NCM_IN_NTB_MAX_SIZE + #define CFG_TUD_NCM_IN_NTB_MAX_SIZE 3200 #endif +// Number of NTB buffers for reception side +// Depending on the configuration, this parameter could be increased with the cost of additional RAM requirements +// On Full-Speed (RP2040) : +// 1 - good performance +// 2 - up to 30% more performance with iperf with small packets +// >2 - no performance gain +// On High-Speed (STM32F7) : +// No performance gain #ifndef CFG_TUD_NCM_OUT_NTB_N - /// number of NTB buffers for reception side - /// 1 - good performance - /// 2 - up to 30% more performance with iperf with small packets - /// >2 - no performance gain - /// -> for performance optimizations this parameter could be increased with the cost of additional RAM requirements - #define CFG_TUD_NCM_OUT_NTB_N 1 + #define CFG_TUD_NCM_OUT_NTB_N 1 #endif +// Number of NTB buffers for transmission side +// Depending on the configuration, this parameter could be increased with the cost of additional RAM requirements +// On Full-Speed (RP2040) : +// 1 - good performance but SystemView shows lost events (on load test) +// 2 - up to 50% more performance with iperf with small packets, "tud_network_can_xmit: request blocked" +// happens from time to time with SystemView +// 3 - "tud_network_can_xmit: request blocked" never happens +// >3 - no performance gain +// On High-Speed (STM32F7) : +// No performance gain #ifndef CFG_TUD_NCM_IN_NTB_N - /// number of NTB buffers for transmission side - /// 1 - good performance but SystemView shows lost events (on load test) - /// 2 - up to 50% more performance with iperf with small packets, "tud_network_can_xmit: request blocked" - /// happens from time to time with SystemView - /// 3 - "tud_network_can_xmit: request blocked" never happens - /// >2 - no performance gain - /// -> for performance optimizations this parameter could be increased with the cost of additional RAM requirements - #define CFG_TUD_NCM_IN_NTB_N 1 + #define CFG_TUD_NCM_IN_NTB_N 1 #endif +// How many datagrams it is allowed to put into an NTB for transmission side #ifndef CFG_TUD_NCM_IN_MAX_DATAGRAMS_PER_NTB - /// this is for the transmission side for allocation of \a ndp16_datagram_t - #define CFG_TUD_NCM_IN_MAX_DATAGRAMS_PER_NTB 8 + #define CFG_TUD_NCM_IN_MAX_DATAGRAMS_PER_NTB 8 #endif +// This tells the host how many datagrams it is allowed to put into an NTB #ifndef CFG_TUD_NCM_OUT_MAX_DATAGRAMS_PER_NTB - /// this tells the host how many datagrams it is allowed to put into an NTB - #define CFG_TUD_NCM_OUT_MAX_DATAGRAMS_PER_NTB 6 + #define CFG_TUD_NCM_OUT_MAX_DATAGRAMS_PER_NTB 6 #endif -#ifndef CFG_TUD_NCM_ALIGNMENT - #define CFG_TUD_NCM_ALIGNMENT 4 -#endif -#if (CFG_TUD_NCM_ALIGNMENT != 4) - #error "CFG_TUD_NCM_ALIGNMENT must be 4, otherwise the headers and start of datagrams have to be aligned (which they are currently not)" -#endif - - // Table 6.2 Class-Specific Request Codes for Network Control Model subclass typedef enum { @@ -98,67 +99,65 @@ typedef enum NCM_SET_CRC_MODE = 0x8A, } ncm_request_code_t; - -#define NTH16_SIGNATURE 0x484D434E +#define NTH16_SIGNATURE 0x484D434E #define NDP16_SIGNATURE_NCM0 0x304D434E #define NDP16_SIGNATURE_NCM1 0x314D434E typedef struct TU_ATTR_PACKED { - uint16_t wLength; - uint16_t bmNtbFormatsSupported; - uint32_t dwNtbInMaxSize; - uint16_t wNdbInDivisor; - uint16_t wNdbInPayloadRemainder; - uint16_t wNdbInAlignment; - uint16_t wReserved; - uint32_t dwNtbOutMaxSize; - uint16_t wNdbOutDivisor; - uint16_t wNdbOutPayloadRemainder; - uint16_t wNdbOutAlignment; - uint16_t wNtbOutMaxDatagrams; + uint16_t wLength; + uint16_t bmNtbFormatsSupported; + uint32_t dwNtbInMaxSize; + uint16_t wNdbInDivisor; + uint16_t wNdbInPayloadRemainder; + uint16_t wNdbInAlignment; + uint16_t wReserved; + uint32_t dwNtbOutMaxSize; + uint16_t wNdbOutDivisor; + uint16_t wNdbOutPayloadRemainder; + uint16_t wNdbOutAlignment; + uint16_t wNtbOutMaxDatagrams; } ntb_parameters_t; typedef struct TU_ATTR_PACKED { - uint32_t dwSignature; - uint16_t wHeaderLength; - uint16_t wSequence; - uint16_t wBlockLength; - uint16_t wNdpIndex; + uint32_t dwSignature; + uint16_t wHeaderLength; + uint16_t wSequence; + uint16_t wBlockLength; + uint16_t wNdpIndex; } nth16_t; typedef struct TU_ATTR_PACKED { - uint16_t wDatagramIndex; - uint16_t wDatagramLength; + uint16_t wDatagramIndex; + uint16_t wDatagramLength; } ndp16_datagram_t; typedef struct TU_ATTR_PACKED { - uint32_t dwSignature; - uint16_t wLength; - uint16_t wNextNdpIndex; - //ndp16_datagram_t datagram[]; + uint32_t dwSignature; + uint16_t wLength; + uint16_t wNextNdpIndex; + //ndp16_datagram_t datagram[]; } ndp16_t; typedef union TU_ATTR_PACKED { - struct { - nth16_t nth; - ndp16_t ndp; - ndp16_datagram_t ndp_datagram[CFG_TUD_NCM_IN_MAX_DATAGRAMS_PER_NTB + 1]; - }; - uint8_t data[CFG_TUD_NCM_IN_NTB_MAX_SIZE]; + struct { + nth16_t nth; + ndp16_t ndp; + ndp16_datagram_t ndp_datagram[CFG_TUD_NCM_IN_MAX_DATAGRAMS_PER_NTB + 1]; + }; + uint8_t data[CFG_TUD_NCM_IN_NTB_MAX_SIZE]; } xmit_ntb_t; typedef union TU_ATTR_PACKED { - struct { - nth16_t nth; - // only the header is at a guaranteed position - }; - uint8_t data[CFG_TUD_NCM_OUT_NTB_MAX_SIZE]; + struct { + nth16_t nth; + // only the header is at a guaranteed position + }; + uint8_t data[CFG_TUD_NCM_OUT_NTB_MAX_SIZE]; } recv_ntb_t; struct ncm_notify_t { - tusb_control_request_t header; - uint32_t downlink, uplink; + tusb_control_request_t header; + uint32_t downlink, uplink; }; - #endif diff --git a/src/class/net/ncm_device.c b/src/class/net/ncm_device.c index 05cebf94e..4b237e4cf 100644 --- a/src/class/net/ncm_device.c +++ b/src/class/net/ncm_device.c @@ -46,7 +46,7 @@ #include "tusb_option.h" -#if defined(ECLIPSE_GUI) || ( CFG_TUD_ENABLED && CFG_TUD_NCM ) +#if (CFG_TUD_ENABLED && CFG_TUD_NCM) #include #include @@ -55,59 +55,65 @@ #include "device/usbd.h" #include "device/usbd_pvt.h" -#include "net_device.h" #include "ncm.h" +#include "net_device.h" + +// Level where CFG_TUSB_DEBUG must be at least for this driver is logged +#ifndef CFG_TUD_NCM_LOG_LEVEL + #define CFG_TUD_NCM_LOG_LEVEL CFG_TUD_LOG_LEVEL +#endif +#define TU_LOG_DRV(...) TU_LOG(CFG_TUD_NCM_LOG_LEVEL, __VA_ARGS__) +// Alignment must be 4 +#define TUD_NCM_ALIGNMENT 4 // calculate alignment of xmit datagrams within an NTB -#define XMIT_ALIGN_OFFSET(x) ((CFG_TUD_NCM_ALIGNMENT - ((x) & (CFG_TUD_NCM_ALIGNMENT - 1))) & (CFG_TUD_NCM_ALIGNMENT - 1)) +#define XMIT_ALIGN_OFFSET(x) ((TUD_NCM_ALIGNMENT - ((x) & (TUD_NCM_ALIGNMENT - 1))) & (TUD_NCM_ALIGNMENT - 1)) //----------------------------------------------------------------------------- // // Module global things // -#define XMIT_NTB_N CFG_TUD_NCM_IN_NTB_N -#define RECV_NTB_N CFG_TUD_NCM_OUT_NTB_N +#define XMIT_NTB_N CFG_TUD_NCM_IN_NTB_N +#define RECV_NTB_N CFG_TUD_NCM_OUT_NTB_N typedef struct { - // general - uint8_t ep_in; //!< endpoint for outgoing datagrams (naming is a little bit confusing) - uint8_t ep_out; //!< endpoint for incoming datagrams (naming is a little bit confusing) - uint8_t ep_notif; //!< endpoint for notifications - uint8_t itf_num; //!< interface number - uint8_t itf_data_alt; //!< ==0 -> no endpoints, i.e. no network traffic, ==1 -> normal operation with two endpoints (spec, chapter 5.3) - uint8_t rhport; //!< storage of \a rhport because some callbacks are done without it - - // recv handling - CFG_TUSB_MEM_ALIGN recv_ntb_t recv_ntb[RECV_NTB_N]; //!< actual recv NTBs - recv_ntb_t *recv_free_ntb[RECV_NTB_N]; //!< free list of recv NTBs - recv_ntb_t *recv_ready_ntb[RECV_NTB_N]; //!< NTBs waiting for transmission to glue logic - recv_ntb_t *recv_tinyusb_ntb; //!< buffer for the running transfer TinyUSB -> driver - recv_ntb_t *recv_glue_ntb; //!< buffer for the running transfer driver -> glue logic - uint16_t recv_glue_ntb_datagram_ndx; //!< index into \a recv_glue_ntb_datagram - - // xmit handling - CFG_TUSB_MEM_ALIGN xmit_ntb_t xmit_ntb[XMIT_NTB_N]; //!< actual xmit NTBs - xmit_ntb_t *xmit_free_ntb[XMIT_NTB_N]; //!< free list of xmit NTBs - xmit_ntb_t *xmit_ready_ntb[XMIT_NTB_N]; //!< NTBs waiting for transmission to TinyUSB - xmit_ntb_t *xmit_tinyusb_ntb; //!< buffer for the running transfer driver -> TinyUSB - xmit_ntb_t *xmit_glue_ntb; //!< buffer for the running transfer glue logic -> driver - uint16_t xmit_sequence; //!< NTB sequence counter - uint16_t xmit_glue_ntb_datagram_ndx; //!< index into \a xmit_glue_ntb_datagram - - // notification handling - enum { - NOTIFICATION_SPEED, - NOTIFICATION_CONNECTED, - NOTIFICATION_DONE - } notification_xmit_state; //!< state of notification transmission - bool notification_xmit_is_running; //!< notification is currently transmitted + // general + uint8_t ep_in; // endpoint for outgoing datagrams (naming is a little bit confusing) + uint8_t ep_out; // endpoint for incoming datagrams (naming is a little bit confusing) + uint8_t ep_notif; // endpoint for notifications + uint8_t itf_num; // interface number + uint8_t itf_data_alt; // ==0 -> no endpoints, i.e. no network traffic, ==1 -> normal operation with two endpoints (spec, chapter 5.3) + uint8_t rhport; // storage of \a rhport because some callbacks are done without it + + // recv handling + CFG_TUSB_MEM_ALIGN recv_ntb_t recv_ntb[RECV_NTB_N]; // actual recv NTBs + recv_ntb_t *recv_free_ntb[RECV_NTB_N]; // free list of recv NTBs + recv_ntb_t *recv_ready_ntb[RECV_NTB_N]; // NTBs waiting for transmission to glue logic + recv_ntb_t *recv_tinyusb_ntb; // buffer for the running transfer TinyUSB -> driver + recv_ntb_t *recv_glue_ntb; // buffer for the running transfer driver -> glue logic + uint16_t recv_glue_ntb_datagram_ndx; // index into \a recv_glue_ntb_datagram + + // xmit handling + CFG_TUSB_MEM_ALIGN xmit_ntb_t xmit_ntb[XMIT_NTB_N]; // actual xmit NTBs + xmit_ntb_t *xmit_free_ntb[XMIT_NTB_N]; // free list of xmit NTBs + xmit_ntb_t *xmit_ready_ntb[XMIT_NTB_N]; // NTBs waiting for transmission to TinyUSB + xmit_ntb_t *xmit_tinyusb_ntb; // buffer for the running transfer driver -> TinyUSB + xmit_ntb_t *xmit_glue_ntb; // buffer for the running transfer glue logic -> driver + uint16_t xmit_sequence; // NTB sequence counter + uint16_t xmit_glue_ntb_datagram_ndx; // index into \a xmit_glue_ntb_datagram + + // notification handling + enum { + NOTIFICATION_SPEED, + NOTIFICATION_CONNECTED, + NOTIFICATION_DONE + } notification_xmit_state; // state of notification transmission + bool notification_xmit_is_running; // notification is currently transmitted } ncm_interface_t; - CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN tu_static ncm_interface_t ncm_interface; - /** * This is the NTB parameter structure * @@ -115,18 +121,18 @@ CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN tu_static ncm_interface_t ncm_interface; * We are lucky, that byte order is correct */ CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN tu_static const ntb_parameters_t ntb_parameters = { - .wLength = sizeof(ntb_parameters_t), - .bmNtbFormatsSupported = 0x01, // 16-bit NTB supported - .dwNtbInMaxSize = CFG_TUD_NCM_IN_NTB_MAX_SIZE, - .wNdbInDivisor = 4, - .wNdbInPayloadRemainder = 0, - .wNdbInAlignment = CFG_TUD_NCM_ALIGNMENT, - .wReserved = 0, - .dwNtbOutMaxSize = CFG_TUD_NCM_OUT_NTB_MAX_SIZE, - .wNdbOutDivisor = 4, - .wNdbOutPayloadRemainder = 0, - .wNdbOutAlignment = CFG_TUD_NCM_ALIGNMENT, - .wNtbOutMaxDatagrams = CFG_TUD_NCM_OUT_MAX_DATAGRAMS_PER_NTB, + .wLength = sizeof(ntb_parameters_t), + .bmNtbFormatsSupported = 0x01,// 16-bit NTB supported + .dwNtbInMaxSize = CFG_TUD_NCM_IN_NTB_MAX_SIZE, + .wNdbInDivisor = 1, + .wNdbInPayloadRemainder = 0, + .wNdbInAlignment = TUD_NCM_ALIGNMENT, + .wReserved = 0, + .dwNtbOutMaxSize = CFG_TUD_NCM_OUT_NTB_MAX_SIZE, + .wNdbOutDivisor = 1, + .wNdbOutPayloadRemainder = 0, + .wNdbOutAlignment = TUD_NCM_ALIGNMENT, + .wNtbOutMaxDatagrams = CFG_TUD_NCM_OUT_MAX_DATAGRAMS_PER_NTB, }; // Some confusing remarks about wNtbOutMaxDatagrams... @@ -135,7 +141,6 @@ CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN tu_static const ntb_parameters_t ntb_par // ==6 -> SystemView runs fine, iperf also // >6 -> iperf starts to show errors // -> 6 seems to be the best value. Why? Don't know, perhaps only on my system? -// switch \a TU_LOG2 on to see interesting values for this. // // iperf: for MSS in 100 200 400 800 1200 1450 1500; do iperf -c 192.168.14.1 -e -i 1 -M $MSS -l 8192 -P 1; sleep 2; done // sysview: SYSTICKS_PER_SEC=35000, IDLE_US=1000, PRINT_MOD=1000 @@ -146,151 +151,128 @@ CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN tu_static const ntb_parameters_t ntb_par // everything about notifications // tu_static struct ncm_notify_t ncm_notify_connected = { - .header = { - .bmRequestType_bit = { - .recipient = TUSB_REQ_RCPT_INTERFACE, - .type = TUSB_REQ_TYPE_CLASS, - .direction = TUSB_DIR_IN - }, - .bRequest = CDC_NOTIF_NETWORK_CONNECTION, - .wValue = 1 /* Connected */, - .wLength = 0, - }, + .header = { + .bmRequestType_bit = { + .recipient = TUSB_REQ_RCPT_INTERFACE, + .type = TUSB_REQ_TYPE_CLASS, + .direction = TUSB_DIR_IN}, + .bRequest = CDC_NOTIF_NETWORK_CONNECTION, + .wValue = 1 /* Connected */, + .wLength = 0, + }, }; tu_static struct ncm_notify_t ncm_notify_speed_change = { - .header = { - .bmRequestType_bit = { - .recipient = TUSB_REQ_RCPT_INTERFACE, - .type = TUSB_REQ_TYPE_CLASS, - .direction = TUSB_DIR_IN - }, - .bRequest = CDC_NOTIF_CONNECTION_SPEED_CHANGE, - .wLength = 8, - }, - .downlink = 12000000, - .uplink = 12000000, + .header = { + .bmRequestType_bit = { + .recipient = TUSB_REQ_RCPT_INTERFACE, + .type = TUSB_REQ_TYPE_CLASS, + .direction = TUSB_DIR_IN}, + .bRequest = CDC_NOTIF_CONNECTION_SPEED_CHANGE, + .wLength = 8, + }, + .downlink = TUD_OPT_HIGH_SPEED ? 480000000 : 12000000, + .uplink = TUD_OPT_HIGH_SPEED ? 480000000 : 12000000, }; - - -static void notification_xmit(uint8_t rhport, bool force_next) /** * Transmit next notification to the host (if appropriate). * Notifications are transferred to the host once during connection setup. */ -{ - TU_LOG3("notification_xmit(%d, %d) - %d %d\n", force_next, rhport, ncm_interface.notification_xmit_state, ncm_interface.notification_xmit_is_running); - - if ( !force_next && ncm_interface.notification_xmit_is_running) { - return; - } - - if (ncm_interface.notification_xmit_state == NOTIFICATION_SPEED) { - TU_LOG3(" NOTIFICATION_SPEED\n"); - ncm_notify_speed_change.header.wIndex = ncm_interface.itf_num; - usbd_edpt_xfer(rhport, ncm_interface.ep_notif, (uint8_t*) &ncm_notify_speed_change, sizeof(ncm_notify_speed_change)); - ncm_interface.notification_xmit_state = NOTIFICATION_CONNECTED; - ncm_interface.notification_xmit_is_running = true; - } - else if (ncm_interface.notification_xmit_state == NOTIFICATION_CONNECTED) { - TU_LOG3(" NOTIFICATION_CONNECTED\n"); - ncm_notify_connected.header.wIndex = ncm_interface.itf_num; - usbd_edpt_xfer(rhport, ncm_interface.ep_notif, (uint8_t*) &ncm_notify_connected, sizeof(ncm_notify_connected)); - ncm_interface.notification_xmit_state = NOTIFICATION_DONE; - ncm_interface.notification_xmit_is_running = true; - } - else { - TU_LOG3(" NOTIFICATION_FINISHED\n"); - } -} // notification_xmit - +static void notification_xmit(uint8_t rhport, bool force_next) { + TU_LOG_DRV("notification_xmit(%d, %d) - %d %d\n", force_next, rhport, ncm_interface.notification_xmit_state, ncm_interface.notification_xmit_is_running); + + if (!force_next && ncm_interface.notification_xmit_is_running) { + return; + } + + if (ncm_interface.notification_xmit_state == NOTIFICATION_SPEED) { + TU_LOG_DRV(" NOTIFICATION_SPEED\n"); + ncm_notify_speed_change.header.wIndex = ncm_interface.itf_num; + usbd_edpt_xfer(rhport, ncm_interface.ep_notif, (uint8_t *) &ncm_notify_speed_change, sizeof(ncm_notify_speed_change)); + ncm_interface.notification_xmit_state = NOTIFICATION_CONNECTED; + ncm_interface.notification_xmit_is_running = true; + } else if (ncm_interface.notification_xmit_state == NOTIFICATION_CONNECTED) { + TU_LOG_DRV(" NOTIFICATION_CONNECTED\n"); + ncm_notify_connected.header.wIndex = ncm_interface.itf_num; + usbd_edpt_xfer(rhport, ncm_interface.ep_notif, (uint8_t *) &ncm_notify_connected, sizeof(ncm_notify_connected)); + ncm_interface.notification_xmit_state = NOTIFICATION_DONE; + ncm_interface.notification_xmit_is_running = true; + } else { + TU_LOG_DRV(" NOTIFICATION_FINISHED\n"); + } +} // notification_xmit //----------------------------------------------------------------------------- // // everything about packet transmission (driver -> TinyUSB) // - -static void xmit_put_ntb_into_free_list(xmit_ntb_t *free_ntb) /** * Put NTB into the transmitter free list. */ -{ - TU_LOG3("xmit_put_ntb_into_free_list() - %p\n", ncm_interface.xmit_tinyusb_ntb); +static void xmit_put_ntb_into_free_list(xmit_ntb_t *free_ntb) { + TU_LOG_DRV("xmit_put_ntb_into_free_list() - %p\n", ncm_interface.xmit_tinyusb_ntb); - if (free_ntb == NULL) { - // can happen due to ZLPs - return; - } + if (free_ntb == NULL) { // can happen due to ZLPs + return; + } - for (int i = 0; i < XMIT_NTB_N; ++i) { - if (ncm_interface.xmit_free_ntb[i] == NULL) { - ncm_interface.xmit_free_ntb[i] = free_ntb; - return; - } + for (int i = 0; i < XMIT_NTB_N; ++i) { + if (ncm_interface.xmit_free_ntb[i] == NULL) { + ncm_interface.xmit_free_ntb[i] = free_ntb; + return; } - TU_LOG1("(EE) xmit_put_ntb_into_free_list - no entry in free list\n"); // this should not happen -} // xmit_put_ntb_into_free_list - - + } + TU_LOG_DRV("(EE) xmit_put_ntb_into_free_list - no entry in free list\n");// this should not happen +} // xmit_put_ntb_into_free_list -static xmit_ntb_t *xmit_get_free_ntb(void) /** * Get an NTB from the free list */ -{ - TU_LOG3("xmit_get_free_ntb()\n"); - - for (int i = 0; i < XMIT_NTB_N; ++i) { - if (ncm_interface.xmit_free_ntb[i] != NULL) { - xmit_ntb_t *free = ncm_interface.xmit_free_ntb[i]; - ncm_interface.xmit_free_ntb[i] = NULL; - return free; - } - } - return NULL; -} // xmit_get_free_ntb - +static xmit_ntb_t *xmit_get_free_ntb(void) { + TU_LOG_DRV("xmit_get_free_ntb()\n"); + for (int i = 0; i < XMIT_NTB_N; ++i) { + if (ncm_interface.xmit_free_ntb[i] != NULL) { + xmit_ntb_t *free = ncm_interface.xmit_free_ntb[i]; + ncm_interface.xmit_free_ntb[i] = NULL; + return free; + } + } + return NULL; +} // xmit_get_free_ntb -static void xmit_put_ntb_into_ready_list(xmit_ntb_t *ready_ntb) /** * Put a filled NTB into the ready list */ -{ - TU_LOG2("xmit_put_ntb_into_ready_list(%p) %d\n", ready_ntb, ready_ntb->nth.wBlockLength); +static void xmit_put_ntb_into_ready_list(xmit_ntb_t *ready_ntb) { + TU_LOG_DRV("xmit_put_ntb_into_ready_list(%p) %d\n", ready_ntb, ready_ntb->nth.wBlockLength); - for (int i = 0; i < XMIT_NTB_N; ++i) { - if (ncm_interface.xmit_ready_ntb[i] == NULL) { - ncm_interface.xmit_ready_ntb[i] = ready_ntb; - return; - } + for (int i = 0; i < XMIT_NTB_N; ++i) { + if (ncm_interface.xmit_ready_ntb[i] == NULL) { + ncm_interface.xmit_ready_ntb[i] = ready_ntb; + return; } - TU_LOG1("(EE) xmit_put_ntb_into_ready_list: ready list full\n"); // this should not happen -} // xmit_put_ntb_into_ready_list + } + TU_LOG_DRV("(EE) xmit_put_ntb_into_ready_list: ready list full\n");// this should not happen +} // xmit_put_ntb_into_ready_list - - -static xmit_ntb_t *xmit_get_next_ready_ntb(void) /** * Get the next NTB from the ready list (and remove it from the list). * If the ready list is empty, return NULL. */ -{ - xmit_ntb_t *r = NULL; - - r = ncm_interface.xmit_ready_ntb[0]; - memmove(ncm_interface.xmit_ready_ntb + 0, ncm_interface.xmit_ready_ntb + 1, sizeof(ncm_interface.xmit_ready_ntb) - sizeof(ncm_interface.xmit_ready_ntb[0])); - ncm_interface.xmit_ready_ntb[XMIT_NTB_N - 1] = NULL; +static xmit_ntb_t *xmit_get_next_ready_ntb(void) { + xmit_ntb_t *r = NULL; - TU_LOG3("recv_get_next_ready_ntb: %p\n", r); - return r; -} // xmit_get_next_ready_ntb + r = ncm_interface.xmit_ready_ntb[0]; + memmove(ncm_interface.xmit_ready_ntb + 0, ncm_interface.xmit_ready_ntb + 1, sizeof(ncm_interface.xmit_ready_ntb) - sizeof(ncm_interface.xmit_ready_ntb[0])); + ncm_interface.xmit_ready_ntb[XMIT_NTB_N - 1] = NULL; + TU_LOG_DRV("recv_get_next_ready_ntb: %p\n", r); + return r; +} // xmit_get_next_ready_ntb - -static bool xmit_insert_required_zlp(uint8_t rhport, uint32_t xferred_bytes) /** * Transmit a ZLP if required * @@ -302,252 +284,221 @@ static bool xmit_insert_required_zlp(uint8_t rhport, uint32_t xferred_bytes) * \pre * This must be called from netd_xfer_cb() so that ep_in is ready */ -{ - TU_LOG3("xmit_insert_required_zlp(%d,%d)\n", rhport, xferred_bytes); - - if (xferred_bytes == 0 || xferred_bytes % CFG_TUD_NET_ENDPOINT_SIZE != 0) { - return false; - } +static bool xmit_insert_required_zlp(uint8_t rhport, uint32_t xferred_bytes) { + TU_LOG_DRV("xmit_insert_required_zlp(%d,%d)\n", rhport, xferred_bytes); - TU_ASSERT(ncm_interface.itf_data_alt == 1, false); - TU_ASSERT( !usbd_edpt_busy(rhport, ncm_interface.ep_in), false); - - TU_LOG2("xmit_insert_required_zlp! (%u)\n", (unsigned)xferred_bytes); + if (xferred_bytes == 0 || xferred_bytes % CFG_TUD_NET_ENDPOINT_SIZE != 0) { + return false; + } - // start transmission of the ZLP - usbd_edpt_xfer(rhport, ncm_interface.ep_in, NULL, 0); + TU_ASSERT(ncm_interface.itf_data_alt == 1, false); + TU_ASSERT(!usbd_edpt_busy(rhport, ncm_interface.ep_in), false); - return true; -} // xmit_insert_required_zlp + TU_LOG_DRV("xmit_insert_required_zlp! (%u)\n", (unsigned) xferred_bytes); + // start transmission of the ZLP + usbd_edpt_xfer(rhport, ncm_interface.ep_in, NULL, 0); + return true; +} // xmit_insert_required_zlp -static void xmit_start_if_possible(uint8_t rhport) /** * Start transmission if it there is a waiting packet and if can be done from interface side. */ -{ - TU_LOG3("xmit_start_if_possible()\n"); - - if (ncm_interface.xmit_tinyusb_ntb != NULL) { - TU_LOG3(" !xmit_start_if_possible 1\n"); - return; - } - if (ncm_interface.itf_data_alt != 1) { - TU_LOG1("(EE) !xmit_start_if_possible 2\n"); - return; - } - if (usbd_edpt_busy(rhport, ncm_interface.ep_in)) { - TU_LOG2(" !xmit_start_if_possible 3\n"); - return; - } +static void xmit_start_if_possible(uint8_t rhport) { + TU_LOG_DRV("xmit_start_if_possible()\n"); + + if (ncm_interface.xmit_tinyusb_ntb != NULL) { + TU_LOG_DRV(" !xmit_start_if_possible 1\n"); + return; + } + if (ncm_interface.itf_data_alt != 1) { + TU_LOG_DRV("(EE) !xmit_start_if_possible 2\n"); + return; + } + if (usbd_edpt_busy(rhport, ncm_interface.ep_in)) { + TU_LOG_DRV(" !xmit_start_if_possible 3\n"); + return; + } + + ncm_interface.xmit_tinyusb_ntb = xmit_get_next_ready_ntb(); + if (ncm_interface.xmit_tinyusb_ntb == NULL) { + if (ncm_interface.xmit_glue_ntb == NULL || ncm_interface.xmit_glue_ntb_datagram_ndx == 0) { + // -> really nothing is waiting + return; + } + ncm_interface.xmit_tinyusb_ntb = ncm_interface.xmit_glue_ntb; + ncm_interface.xmit_glue_ntb = NULL; + } + + #if CFG_TUD_NCM_LOG_LEVEL >= 3 + { + uint16_t len = ncm_interface.xmit_tinyusb_ntb->nth.wBlockLength; + TU_LOG_BUF(3, ncm_interface.xmit_tinyusb_ntb->data[i], len); + } + #endif + + if (ncm_interface.xmit_glue_ntb_datagram_ndx != 1) { + TU_LOG_DRV(">> %d %d\n", ncm_interface.xmit_tinyusb_ntb->nth.wBlockLength, ncm_interface.xmit_glue_ntb_datagram_ndx); + } + + // Kick off an endpoint transfer + usbd_edpt_xfer(0, ncm_interface.ep_in, ncm_interface.xmit_tinyusb_ntb->data, ncm_interface.xmit_tinyusb_ntb->nth.wBlockLength); +} // xmit_start_if_possible - ncm_interface.xmit_tinyusb_ntb = xmit_get_next_ready_ntb(); - if (ncm_interface.xmit_tinyusb_ntb == NULL) { - if (ncm_interface.xmit_glue_ntb == NULL || ncm_interface.xmit_glue_ntb_datagram_ndx == 0) { - // -> really nothing is waiting - return; - } - ncm_interface.xmit_tinyusb_ntb = ncm_interface.xmit_glue_ntb; - ncm_interface.xmit_glue_ntb = NULL; - } - -#if CFG_TUSB_DEBUG >= 3 - { - uint16_t len = ncm_interface.xmit_tinyusb_ntb->nth.wBlockLength; - TU_LOG3(" %d\n", len); - for (int i = 0; i < len; ++i) { - TU_LOG3(" %02x", ncm_interface.xmit_tinyusb_ntb->data[i]); - } - TU_LOG3("\n"); - } -#endif - - if (ncm_interface.xmit_glue_ntb_datagram_ndx != 1) { - TU_LOG3(">> %d %d\n", ncm_interface.xmit_tinyusb_ntb->nth.wBlockLength, ncm_interface.xmit_glue_ntb_datagram_ndx); - } - - // Kick off an endpoint transfer - usbd_edpt_xfer(0, ncm_interface.ep_in, ncm_interface.xmit_tinyusb_ntb->data, ncm_interface.xmit_tinyusb_ntb->nth.wBlockLength); -} // xmit_start_if_possible - - - -static bool xmit_requested_datagram_fits_into_current_ntb(uint16_t datagram_size) /** * check if a new datagram fits into the current NTB */ -{ - TU_LOG3("xmit_requested_datagram_fits_into_current_ntb(%d) - %p %p\n", datagram_size, ncm_interface.xmit_tinyusb_ntb, ncm_interface.xmit_glue_ntb); - - if (ncm_interface.xmit_glue_ntb == NULL) { - return false; - } - if (ncm_interface.xmit_glue_ntb_datagram_ndx >= CFG_TUD_NCM_IN_MAX_DATAGRAMS_PER_NTB) { - return false; - } - if (ncm_interface.xmit_glue_ntb->nth.wBlockLength + datagram_size + XMIT_ALIGN_OFFSET(datagram_size) > CFG_TUD_NCM_OUT_NTB_MAX_SIZE) { - return false; - } - return true; -} // xmit_requested_datagram_fits_into_current_ntb - +static bool xmit_requested_datagram_fits_into_current_ntb(uint16_t datagram_size) { + TU_LOG_DRV("xmit_requested_datagram_fits_into_current_ntb(%d) - %p %p\n", datagram_size, ncm_interface.xmit_tinyusb_ntb, ncm_interface.xmit_glue_ntb); + if (ncm_interface.xmit_glue_ntb == NULL) { + return false; + } + if (ncm_interface.xmit_glue_ntb_datagram_ndx >= CFG_TUD_NCM_IN_MAX_DATAGRAMS_PER_NTB) { + return false; + } + if (ncm_interface.xmit_glue_ntb->nth.wBlockLength + datagram_size + XMIT_ALIGN_OFFSET(datagram_size) > CFG_TUD_NCM_OUT_NTB_MAX_SIZE) { + return false; + } + return true; +} // xmit_requested_datagram_fits_into_current_ntb -static bool xmit_setup_next_glue_ntb(void) /** * Setup an NTB for the glue logic */ -{ - TU_LOG3("xmit_setup_next_glue_ntb - %p\n", ncm_interface.xmit_glue_ntb); +static bool xmit_setup_next_glue_ntb(void) { + TU_LOG_DRV("xmit_setup_next_glue_ntb - %p\n", ncm_interface.xmit_glue_ntb); - if (ncm_interface.xmit_glue_ntb != NULL) { - // put NTB into waiting list (the new datagram did not fit in) - xmit_put_ntb_into_ready_list(ncm_interface.xmit_glue_ntb); - } + if (ncm_interface.xmit_glue_ntb != NULL) { + // put NTB into waiting list (the new datagram did not fit in) + xmit_put_ntb_into_ready_list(ncm_interface.xmit_glue_ntb); + } - ncm_interface.xmit_glue_ntb = xmit_get_free_ntb(); // get next buffer (if any) - if (ncm_interface.xmit_glue_ntb == NULL) { - TU_LOG3(" xmit_setup_next_glue_ntb - nothing free\n"); // should happen rarely - return false; - } - - ncm_interface.xmit_glue_ntb_datagram_ndx = 0; + ncm_interface.xmit_glue_ntb = xmit_get_free_ntb();// get next buffer (if any) + if (ncm_interface.xmit_glue_ntb == NULL) { + TU_LOG_DRV(" xmit_setup_next_glue_ntb - nothing free\n");// should happen rarely + return false; + } - xmit_ntb_t *ntb = ncm_interface.xmit_glue_ntb; + ncm_interface.xmit_glue_ntb_datagram_ndx = 0; - // Fill in NTB header - ntb->nth.dwSignature = NTH16_SIGNATURE; - ntb->nth.wHeaderLength = sizeof(ntb->nth); - ntb->nth.wSequence = ncm_interface.xmit_sequence++; - ntb->nth.wBlockLength = sizeof(ntb->nth) + sizeof(ntb->ndp) + sizeof(ntb->ndp_datagram); - ntb->nth.wNdpIndex = sizeof(ntb->nth); + xmit_ntb_t *ntb = ncm_interface.xmit_glue_ntb; - // Fill in NDP16 header and terminator - ntb->ndp.dwSignature = NDP16_SIGNATURE_NCM0; - ntb->ndp.wLength = sizeof(ntb->ndp) + sizeof(ntb->ndp_datagram); - ntb->ndp.wNextNdpIndex = 0; + // Fill in NTB header + ntb->nth.dwSignature = NTH16_SIGNATURE; + ntb->nth.wHeaderLength = sizeof(ntb->nth); + ntb->nth.wSequence = ncm_interface.xmit_sequence++; + ntb->nth.wBlockLength = sizeof(ntb->nth) + sizeof(ntb->ndp) + sizeof(ntb->ndp_datagram); + ntb->nth.wNdpIndex = sizeof(ntb->nth); - memset(ntb->ndp_datagram, 0, sizeof(ntb->ndp_datagram)); - return true; -} // xmit_setup_next_glue_ntb + // Fill in NDP16 header and terminator + ntb->ndp.dwSignature = NDP16_SIGNATURE_NCM0; + ntb->ndp.wLength = sizeof(ntb->ndp) + sizeof(ntb->ndp_datagram); + ntb->ndp.wNextNdpIndex = 0; + memset(ntb->ndp_datagram, 0, sizeof(ntb->ndp_datagram)); + return true; +} // xmit_setup_next_glue_ntb //----------------------------------------------------------------------------- // // all the recv_*() stuff (TinyUSB -> driver -> glue logic) // - -static recv_ntb_t *recv_get_free_ntb(void) /** * Return pointer to an available receive buffer or NULL. * Returned buffer (if any) has the size \a CFG_TUD_NCM_OUT_NTB_MAX_SIZE. */ -{ - TU_LOG3("recv_get_free_ntb()\n"); - - for (int i = 0; i < RECV_NTB_N; ++i) { - if (ncm_interface.recv_free_ntb[i] != NULL) { - recv_ntb_t *free = ncm_interface.recv_free_ntb[i]; - ncm_interface.recv_free_ntb[i] = NULL; - return free; - } - } - return NULL; -} // recv_get_free_ntb - +static recv_ntb_t *recv_get_free_ntb(void) { + TU_LOG_DRV("recv_get_free_ntb()\n"); + for (int i = 0; i < RECV_NTB_N; ++i) { + if (ncm_interface.recv_free_ntb[i] != NULL) { + recv_ntb_t *free = ncm_interface.recv_free_ntb[i]; + ncm_interface.recv_free_ntb[i] = NULL; + return free; + } + } + return NULL; +} // recv_get_free_ntb -static recv_ntb_t *recv_get_next_ready_ntb(void) /** * Get the next NTB from the ready list (and remove it from the list). * If the ready list is empty, return NULL. */ -{ - recv_ntb_t *r = NULL; +static recv_ntb_t *recv_get_next_ready_ntb(void) { + recv_ntb_t *r = NULL; - r = ncm_interface.recv_ready_ntb[0]; - memmove(ncm_interface.recv_ready_ntb + 0, ncm_interface.recv_ready_ntb + 1, sizeof(ncm_interface.recv_ready_ntb) - sizeof(ncm_interface.recv_ready_ntb[0])); - ncm_interface.recv_ready_ntb[RECV_NTB_N - 1] = NULL; + r = ncm_interface.recv_ready_ntb[0]; + memmove(ncm_interface.recv_ready_ntb + 0, ncm_interface.recv_ready_ntb + 1, sizeof(ncm_interface.recv_ready_ntb) - sizeof(ncm_interface.recv_ready_ntb[0])); + ncm_interface.recv_ready_ntb[RECV_NTB_N - 1] = NULL; - TU_LOG3("recv_get_next_ready_ntb: %p\n", r); - return r; -} // recv_get_next_ready_ntb + TU_LOG_DRV("recv_get_next_ready_ntb: %p\n", r); + return r; +} // recv_get_next_ready_ntb - - -static void recv_put_ntb_into_free_list(recv_ntb_t *free_ntb) /** * Put NTB into the receiver free list. */ -{ - TU_LOG3("recv_put_ntb_into_free_list(%p)\n", free_ntb); +static void recv_put_ntb_into_free_list(recv_ntb_t *free_ntb) { + TU_LOG_DRV("recv_put_ntb_into_free_list(%p)\n", free_ntb); - for (int i = 0; i < RECV_NTB_N; ++i) { - if (ncm_interface.recv_free_ntb[i] == NULL) { - ncm_interface.recv_free_ntb[i] = free_ntb; - return; - } + for (int i = 0; i < RECV_NTB_N; ++i) { + if (ncm_interface.recv_free_ntb[i] == NULL) { + ncm_interface.recv_free_ntb[i] = free_ntb; + return; } - TU_LOG1("(EE) recv_put_ntb_into_free_list - no entry in free list\n"); // this should not happen -} // recv_put_ntb_into_free_list + } + TU_LOG_DRV("(EE) recv_put_ntb_into_free_list - no entry in free list\n");// this should not happen +} // recv_put_ntb_into_free_list - - -static void recv_put_ntb_into_ready_list(recv_ntb_t *ready_ntb) /** * \a ready_ntb holds a validated NTB, * put this buffer into the waiting list. */ -{ - TU_LOG3("recv_put_ntb_into_ready_list(%p) %d\n", ready_ntb, ready_ntb->nth.wBlockLength); +static void recv_put_ntb_into_ready_list(recv_ntb_t *ready_ntb) { + TU_LOG_DRV("recv_put_ntb_into_ready_list(%p) %d\n", ready_ntb, ready_ntb->nth.wBlockLength); - for (int i = 0; i < RECV_NTB_N; ++i) { - if (ncm_interface.recv_ready_ntb[i] == NULL) { - ncm_interface.recv_ready_ntb[i] = ready_ntb; - return; - } + for (int i = 0; i < RECV_NTB_N; ++i) { + if (ncm_interface.recv_ready_ntb[i] == NULL) { + ncm_interface.recv_ready_ntb[i] = ready_ntb; + return; } - TU_LOG1("(EE) recv_put_ntb_into_ready_list: ready list full\n"); // this should not happen -} // recv_put_ntb_into_ready_list - - + } + TU_LOG_DRV("(EE) recv_put_ntb_into_ready_list: ready list full\n");// this should not happen +} // recv_put_ntb_into_ready_list -static void recv_try_to_start_new_reception(uint8_t rhport) /** * If possible, start a new reception TinyUSB -> driver. */ -{ - TU_LOG3("recv_try_to_start_new_reception(%d)\n", rhport); - - if (ncm_interface.itf_data_alt != 1) { - return; - } - if (ncm_interface.recv_tinyusb_ntb != NULL) { - return; - } - if (usbd_edpt_busy(rhport, ncm_interface.ep_out)) { - return; - } - - ncm_interface.recv_tinyusb_ntb = recv_get_free_ntb(); - if (ncm_interface.recv_tinyusb_ntb == NULL) { - return; - } - - // initiate transfer - TU_LOG3(" start reception\n"); - bool r = usbd_edpt_xfer(rhport, ncm_interface.ep_out, ncm_interface.recv_tinyusb_ntb->data, CFG_TUD_NCM_OUT_NTB_MAX_SIZE); - if ( !r) { - recv_put_ntb_into_free_list(ncm_interface.recv_tinyusb_ntb); - ncm_interface.recv_tinyusb_ntb = NULL; - } -} // recv_try_to_start_new_reception - - +static void recv_try_to_start_new_reception(uint8_t rhport) { + TU_LOG_DRV("recv_try_to_start_new_reception(%d)\n", rhport); + + if (ncm_interface.itf_data_alt != 1) { + return; + } + if (ncm_interface.recv_tinyusb_ntb != NULL) { + return; + } + if (usbd_edpt_busy(rhport, ncm_interface.ep_out)) { + return; + } + + ncm_interface.recv_tinyusb_ntb = recv_get_free_ntb(); + if (ncm_interface.recv_tinyusb_ntb == NULL) { + return; + } + + // initiate transfer + TU_LOG_DRV(" start reception\n"); + bool r = usbd_edpt_xfer(rhport, ncm_interface.ep_out, ncm_interface.recv_tinyusb_ntb->data, CFG_TUD_NCM_OUT_NTB_MAX_SIZE); + if (!r) { + recv_put_ntb_into_free_list(ncm_interface.recv_tinyusb_ntb); + ncm_interface.recv_tinyusb_ntb = NULL; + } +} // recv_try_to_start_new_reception -static bool recv_validate_datagram(const recv_ntb_t *ntb, uint32_t len) /** * Validate incoming datagram. * \return true if valid @@ -555,287 +506,243 @@ static bool recv_validate_datagram(const recv_ntb_t *ntb, uint32_t len) * \note * \a ndp16->wNextNdpIndex != 0 is not supported */ -{ - const nth16_t *nth16 = &(ntb->nth); - - TU_LOG3("recv_validate_datagram(%p, %d)\n", ntb, (int)len); - - // - // check header - // - if (nth16->wHeaderLength != sizeof(nth16_t)) - { - TU_LOG1("(EE) ill nth16 length: %d\n", nth16->wHeaderLength); - return false; - } - if (nth16->dwSignature != NTH16_SIGNATURE) { - TU_LOG1("(EE) ill signature: 0x%08x\n", (unsigned)nth16->dwSignature); - return false; - } - if (len < sizeof(nth16_t) + sizeof(ndp16_t) + 2*sizeof(ndp16_datagram_t)) { - TU_LOG1("(EE) ill min len: %d\n", len); - return false; - } - if (nth16->wBlockLength > len) { - TU_LOG1("(EE) ill block length: %d > %d\n", nth16->wBlockLength, len); - return false; - } - if (nth16->wBlockLength > CFG_TUD_NCM_OUT_NTB_MAX_SIZE) { - TU_LOG1("(EE) ill block length2: %d > %d\n", nth16->wBlockLength, CFG_TUD_NCM_OUT_NTB_MAX_SIZE); - return false; - } - if (nth16->wNdpIndex < sizeof(nth16) || nth16->wNdpIndex > len - (sizeof(ndp16_t) + 2*sizeof(ndp16_datagram_t))) { - TU_LOG1("(EE) ill position of first ndp: %d (%d)\n", nth16->wNdpIndex, len); - return false; - } +static bool recv_validate_datagram(const recv_ntb_t *ntb, uint32_t len) { + const nth16_t *nth16 = &(ntb->nth); - // - // check (first) NDP(16) - // - const ndp16_t *ndp16 = (const ndp16_t *)(ntb->data + nth16->wNdpIndex); + TU_LOG_DRV("recv_validate_datagram(%p, %d)\n", ntb, (int) len); - if (ndp16->wLength < sizeof(ndp16_t) + 2*sizeof(ndp16_datagram_t)) { - TU_LOG1("(EE) ill ndp16 length: %d\n", ndp16->wLength); - return false; - } - if (ndp16->dwSignature != NDP16_SIGNATURE_NCM0 && ndp16->dwSignature != NDP16_SIGNATURE_NCM1) { - TU_LOG1("(EE) ill signature: 0x%08x\n", (unsigned)ndp16->dwSignature); - return false; - } - if (ndp16->wNextNdpIndex != 0) { - TU_LOG1("(EE) cannot handle wNextNdpIndex!=0 (%d)\n", ndp16->wNextNdpIndex); - return false; - } + // check header + if (nth16->wHeaderLength != sizeof(nth16_t)) { + TU_LOG_DRV("(EE) ill nth16 length: %d\n", nth16->wHeaderLength); + return false; + } + if (nth16->dwSignature != NTH16_SIGNATURE) { + TU_LOG_DRV("(EE) ill signature: 0x%08x\n", (unsigned) nth16->dwSignature); + return false; + } + if (len < sizeof(nth16_t) + sizeof(ndp16_t) + 2 * sizeof(ndp16_datagram_t)) { + TU_LOG_DRV("(EE) ill min len: %d\n", len); + return false; + } + if (nth16->wBlockLength > len) { + TU_LOG_DRV("(EE) ill block length: %d > %d\n", nth16->wBlockLength, len); + return false; + } + if (nth16->wBlockLength > CFG_TUD_NCM_OUT_NTB_MAX_SIZE) { + TU_LOG_DRV("(EE) ill block length2: %d > %d\n", nth16->wBlockLength, CFG_TUD_NCM_OUT_NTB_MAX_SIZE); + return false; + } + if (nth16->wNdpIndex < sizeof(nth16) || nth16->wNdpIndex > len - (sizeof(ndp16_t) + 2 * sizeof(ndp16_datagram_t))) { + TU_LOG_DRV("(EE) ill position of first ndp: %d (%d)\n", nth16->wNdpIndex, len); + return false; + } - const ndp16_datagram_t *ndp16_datagram = (const ndp16_datagram_t *)(ntb->data + nth16->wNdpIndex + sizeof(ndp16_t)); - int ndx = 0; - uint16_t max_ndx = (uint16_t)((ndp16->wLength - sizeof(ndp16_t)) / sizeof(ndp16_datagram_t)); + // check (first) NDP(16) + const ndp16_t *ndp16 = (const ndp16_t *) (ntb->data + nth16->wNdpIndex); - if (max_ndx > 2) { - // number of datagrams in NTB > 1 - TU_LOG2("<< %d (%d)\n", max_ndx - 1, ntb->nth.wBlockLength); - } - if (ndp16_datagram[max_ndx-1].wDatagramIndex != 0 || ndp16_datagram[max_ndx-1].wDatagramLength != 0) { - TU_LOG2(" max_ndx != 0\n"); - return false; - } - while (ndp16_datagram[ndx].wDatagramIndex != 0 && ndp16_datagram[ndx].wDatagramLength != 0) { - TU_LOG3(" << %d %d\n", ndp16_datagram[ndx].wDatagramIndex, ndp16_datagram[ndx].wDatagramLength); - if (ndp16_datagram[ndx].wDatagramIndex > len) { - TU_LOG1("(EE) ill start of datagram[%d]: %d (%d)\n", ndx, ndp16_datagram[ndx].wDatagramIndex, len); - return false; - } - if (ndp16_datagram[ndx].wDatagramIndex + ndp16_datagram[ndx].wDatagramLength > len) { - TU_LOG1("(EE) ill end of datagram[%d]: %d (%d)\n", ndx, ndp16_datagram[ndx].wDatagramIndex + ndp16_datagram[ndx].wDatagramLength, len); - return false; - } - ++ndx; - } + if (ndp16->wLength < sizeof(ndp16_t) + 2 * sizeof(ndp16_datagram_t)) { + TU_LOG_DRV("(EE) ill ndp16 length: %d\n", ndp16->wLength); + return false; + } + if (ndp16->dwSignature != NDP16_SIGNATURE_NCM0 && ndp16->dwSignature != NDP16_SIGNATURE_NCM1) { + TU_LOG_DRV("(EE) ill signature: 0x%08x\n", (unsigned) ndp16->dwSignature); + return false; + } + if (ndp16->wNextNdpIndex != 0) { + TU_LOG_DRV("(EE) cannot handle wNextNdpIndex!=0 (%d)\n", ndp16->wNextNdpIndex); + return false; + } -#if CFG_TUSB_DEBUG >= 3 - for (uint32_t i = 0; i < len; ++i) { - TU_LOG3(" %02x", ntb->data[i]); - } - TU_LOG3("\n"); -#endif + const ndp16_datagram_t *ndp16_datagram = (const ndp16_datagram_t *) (ntb->data + nth16->wNdpIndex + sizeof(ndp16_t)); + int ndx = 0; + uint16_t max_ndx = (uint16_t) ((ndp16->wLength - sizeof(ndp16_t)) / sizeof(ndp16_datagram_t)); - // -> ntb contains a valid packet structure - // ok... I did not check for garbage within the datagram indices... - return true; -} // recv_validate_datagram + if (max_ndx > 2) { // number of datagrams in NTB > 1 + TU_LOG_DRV("<< %d (%d)\n", max_ndx - 1, ntb->nth.wBlockLength); + } + if (ndp16_datagram[max_ndx - 1].wDatagramIndex != 0 || ndp16_datagram[max_ndx - 1].wDatagramLength != 0) { + TU_LOG_DRV(" max_ndx != 0\n"); + return false; + } + while (ndp16_datagram[ndx].wDatagramIndex != 0 && ndp16_datagram[ndx].wDatagramLength != 0) { + TU_LOG_DRV(" << %d %d\n", ndp16_datagram[ndx].wDatagramIndex, ndp16_datagram[ndx].wDatagramLength); + if (ndp16_datagram[ndx].wDatagramIndex > len) { + TU_LOG_DRV("(EE) ill start of datagram[%d]: %d (%d)\n", ndx, ndp16_datagram[ndx].wDatagramIndex, len); + return false; + } + if (ndp16_datagram[ndx].wDatagramIndex + ndp16_datagram[ndx].wDatagramLength > len) { + TU_LOG_DRV("(EE) ill end of datagram[%d]: %d (%d)\n", ndx, ndp16_datagram[ndx].wDatagramIndex + ndp16_datagram[ndx].wDatagramLength, len); + return false; + } + ++ndx; + } + #if CFG_TUD_NCM_LOG_LEVEL >= 3 + TU_LOG_BUF(3, ntb->data[i], len); + #endif + // -> ntb contains a valid packet structure + // ok... I did not check for garbage within the datagram indices... + return true; +} // recv_validate_datagram -static void recv_transfer_datagram_to_glue_logic(void) /** * Transfer the next (pending) datagram to the glue logic and return receive buffer if empty. */ -{ - TU_LOG3("recv_transfer_datagram_to_glue_logic()\n"); - - if (ncm_interface.recv_glue_ntb == NULL) { - ncm_interface.recv_glue_ntb = recv_get_next_ready_ntb(); - TU_LOG3(" new buffer for glue logic: %p\n", ncm_interface.recv_glue_ntb); - ncm_interface.recv_glue_ntb_datagram_ndx = 0; - } - - if (ncm_interface.recv_glue_ntb != NULL) { - const ndp16_datagram_t *ndp16_datagram = (ndp16_datagram_t *)(ncm_interface.recv_glue_ntb->data - + ncm_interface.recv_glue_ntb->nth.wNdpIndex - + sizeof(ndp16_t)); - - if (ndp16_datagram[ncm_interface.recv_glue_ntb_datagram_ndx].wDatagramIndex == 0) { - TU_LOG1("(EE) SOMETHING WENT WRONG 1\n"); - } - else if (ndp16_datagram[ncm_interface.recv_glue_ntb_datagram_ndx].wDatagramLength == 0) { - TU_LOG1("(EE) SOMETHING WENT WRONG 2\n"); - } - else { - uint16_t datagramIndex = ndp16_datagram[ncm_interface.recv_glue_ntb_datagram_ndx].wDatagramIndex; - uint16_t datagramLength = ndp16_datagram[ncm_interface.recv_glue_ntb_datagram_ndx].wDatagramLength; - - TU_LOG3(" recv[%d] - %d %d\n", ncm_interface.recv_glue_ntb_datagram_ndx, datagramIndex, datagramLength); - if (tud_network_recv_cb(ncm_interface.recv_glue_ntb->data + datagramIndex, datagramLength)) { - // - // send datagram successfully to glue logic - // - TU_LOG3(" OK\n"); - datagramIndex = ndp16_datagram[ncm_interface.recv_glue_ntb_datagram_ndx + 1].wDatagramIndex; - datagramLength = ndp16_datagram[ncm_interface.recv_glue_ntb_datagram_ndx + 1].wDatagramLength; - - if (datagramIndex != 0 && datagramLength != 0) { - // -> next datagram - ++ncm_interface.recv_glue_ntb_datagram_ndx; - } - else { - // end of datagrams reached - recv_put_ntb_into_free_list(ncm_interface.recv_glue_ntb); - ncm_interface.recv_glue_ntb = NULL; - } - } +static void recv_transfer_datagram_to_glue_logic(void) { + TU_LOG_DRV("recv_transfer_datagram_to_glue_logic()\n"); + + if (ncm_interface.recv_glue_ntb == NULL) { + ncm_interface.recv_glue_ntb = recv_get_next_ready_ntb(); + TU_LOG_DRV(" new buffer for glue logic: %p\n", ncm_interface.recv_glue_ntb); + ncm_interface.recv_glue_ntb_datagram_ndx = 0; + } + + if (ncm_interface.recv_glue_ntb != NULL) { + const ndp16_datagram_t *ndp16_datagram = (ndp16_datagram_t *) (ncm_interface.recv_glue_ntb->data + ncm_interface.recv_glue_ntb->nth.wNdpIndex + sizeof(ndp16_t)); + + if (ndp16_datagram[ncm_interface.recv_glue_ntb_datagram_ndx].wDatagramIndex == 0) { + TU_LOG_DRV("(EE) SOMETHING WENT WRONG 1\n"); + } else if (ndp16_datagram[ncm_interface.recv_glue_ntb_datagram_ndx].wDatagramLength == 0) { + TU_LOG_DRV("(EE) SOMETHING WENT WRONG 2\n"); + } else { + uint16_t datagramIndex = ndp16_datagram[ncm_interface.recv_glue_ntb_datagram_ndx].wDatagramIndex; + uint16_t datagramLength = ndp16_datagram[ncm_interface.recv_glue_ntb_datagram_ndx].wDatagramLength; + + TU_LOG_DRV(" recv[%d] - %d %d\n", ncm_interface.recv_glue_ntb_datagram_ndx, datagramIndex, datagramLength); + if (tud_network_recv_cb(ncm_interface.recv_glue_ntb->data + datagramIndex, datagramLength)) { + // send datagram successfully to glue logic + TU_LOG_DRV(" OK\n"); + datagramIndex = ndp16_datagram[ncm_interface.recv_glue_ntb_datagram_ndx + 1].wDatagramIndex; + datagramLength = ndp16_datagram[ncm_interface.recv_glue_ntb_datagram_ndx + 1].wDatagramLength; + + if (datagramIndex != 0 && datagramLength != 0) { + // -> next datagram + ++ncm_interface.recv_glue_ntb_datagram_ndx; + } else { + // end of datagrams reached + recv_put_ntb_into_free_list(ncm_interface.recv_glue_ntb); + ncm_interface.recv_glue_ntb = NULL; } + } } -} // recv_transfer_datagram_to_glue_logic - + } +} // recv_transfer_datagram_to_glue_logic //----------------------------------------------------------------------------- // // all the tud_network_*() stuff (glue logic -> driver) // - -bool tud_network_can_xmit(uint16_t size) /** * Check if the glue logic is allowed to call tud_network_xmit(). * This function also fetches a next buffer if required, so that tud_network_xmit() is ready for copy * and transmission operation. */ -{ - TU_LOG3("tud_network_can_xmit(%d)\n", size); - - TU_ASSERT(size <= CFG_TUD_NCM_OUT_NTB_MAX_SIZE - (sizeof(nth16_t) + sizeof(ndp16_t) + 2*sizeof(ndp16_datagram_t)), false); - - if (xmit_requested_datagram_fits_into_current_ntb(size) || xmit_setup_next_glue_ntb()) { - // -> everything is fine - return true; - } - xmit_start_if_possible(ncm_interface.rhport); - TU_LOG2("(II) tud_network_can_xmit: request blocked\n"); // could happen if all xmit buffers are full (but should happen rarely) - return false; -} // tud_network_can_xmit +bool tud_network_can_xmit(uint16_t size) { + TU_LOG_DRV("tud_network_can_xmit(%d)\n", size); + TU_ASSERT(size <= CFG_TUD_NCM_OUT_NTB_MAX_SIZE - (sizeof(nth16_t) + sizeof(ndp16_t) + 2 * sizeof(ndp16_datagram_t)), false); + if (xmit_requested_datagram_fits_into_current_ntb(size) || xmit_setup_next_glue_ntb()) { + // -> everything is fine + return true; + } + xmit_start_if_possible(ncm_interface.rhport); + TU_LOG_DRV("(II) tud_network_can_xmit: request blocked\n");// could happen if all xmit buffers are full (but should happen rarely) + return false; +} // tud_network_can_xmit -void tud_network_xmit(void *ref, uint16_t arg) /** * Put a datagram into a waiting NTB. * If currently no transmission is started, then initiate transmission. */ -{ - TU_LOG3("tud_network_xmit(%p, %d)\n", ref, arg); - - if (ncm_interface.xmit_glue_ntb == NULL) { - TU_LOG1("(EE) tud_network_xmit: no buffer\n"); // must not happen (really) - return; - } - - xmit_ntb_t *ntb = ncm_interface.xmit_glue_ntb; +void tud_network_xmit(void *ref, uint16_t arg) { + TU_LOG_DRV("tud_network_xmit(%p, %d)\n", ref, arg); - // copy new datagram to the end of the current NTB - uint16_t size = tud_network_xmit_cb(ntb->data + ntb->nth.wBlockLength, ref, arg); + if (ncm_interface.xmit_glue_ntb == NULL) { + TU_LOG_DRV("(EE) tud_network_xmit: no buffer\n");// must not happen (really) + return; + } - // correct NTB internals - ntb->ndp_datagram[ncm_interface.xmit_glue_ntb_datagram_ndx].wDatagramIndex = ntb->nth.wBlockLength; - ntb->ndp_datagram[ncm_interface.xmit_glue_ntb_datagram_ndx].wDatagramLength = size; - ncm_interface.xmit_glue_ntb_datagram_ndx += 1; + xmit_ntb_t *ntb = ncm_interface.xmit_glue_ntb; - ntb->nth.wBlockLength += (uint16_t)(size + XMIT_ALIGN_OFFSET(size)); + // copy new datagram to the end of the current NTB + uint16_t size = tud_network_xmit_cb(ntb->data + ntb->nth.wBlockLength, ref, arg); - if (ntb->nth.wBlockLength > CFG_TUD_NCM_OUT_NTB_MAX_SIZE) { - TU_LOG1("(EE) tud_network_xmit: buffer overflow\n"); // must not happen (really) - return; - } + // correct NTB internals + ntb->ndp_datagram[ncm_interface.xmit_glue_ntb_datagram_ndx].wDatagramIndex = ntb->nth.wBlockLength; + ntb->ndp_datagram[ncm_interface.xmit_glue_ntb_datagram_ndx].wDatagramLength = size; + ncm_interface.xmit_glue_ntb_datagram_ndx += 1; - xmit_start_if_possible(ncm_interface.rhport); -} // tud_network_xmit + ntb->nth.wBlockLength += (uint16_t) (size + XMIT_ALIGN_OFFSET(size)); + if (ntb->nth.wBlockLength > CFG_TUD_NCM_OUT_NTB_MAX_SIZE) { + TU_LOG_DRV("(EE) tud_network_xmit: buffer overflow\n"); // must not happen (really) + return; + } + xmit_start_if_possible(ncm_interface.rhport); +} // tud_network_xmit -void tud_network_recv_renew(void) /** * Keep the receive logic busy and transfer pending packets to the glue logic. */ -{ - TU_LOG3("tud_network_recv_renew()\n"); +void tud_network_recv_renew(void) { + TU_LOG_DRV("tud_network_recv_renew()\n"); - recv_transfer_datagram_to_glue_logic(); - recv_try_to_start_new_reception(ncm_interface.rhport); -} // tud_network_recv_renew + recv_transfer_datagram_to_glue_logic(); + recv_try_to_start_new_reception(ncm_interface.rhport); +} // tud_network_recv_renew - - -void tud_network_recv_renew_r(uint8_t rhport) /** * Same as tud_network_recv_renew() but knows \a rhport */ -{ - TU_LOG3("tud_network_recv_renew_r(%d)\n", rhport); - - ncm_interface.rhport = rhport; - tud_network_recv_renew(); -} // tud_network_recv_renew +void tud_network_recv_renew_r(uint8_t rhport) { + TU_LOG_DRV("tud_network_recv_renew_r(%d)\n", rhport); + ncm_interface.rhport = rhport; + tud_network_recv_renew(); +} // tud_network_recv_renew //----------------------------------------------------------------------------- // // all the netd_*() stuff (interface TinyUSB -> driver) // -void netd_init(void) /** * Initialize the driver data structures. * Might be called several times. */ -{ - TU_LOG3("netd_init()\n"); +void netd_init(void) { + TU_LOG_DRV("netd_init()\n"); - memset( &ncm_interface, 0, sizeof(ncm_interface)); - - for (int i = 0; i < XMIT_NTB_N; ++i) { - ncm_interface.xmit_free_ntb[i] = ncm_interface.xmit_ntb + i; - } - for (int i = 0; i < RECV_NTB_N; ++i) { - ncm_interface.recv_free_ntb[i] = ncm_interface.recv_ntb + i; - } -} // netd_init + memset(&ncm_interface, 0, sizeof(ncm_interface)); + for (int i = 0; i < XMIT_NTB_N; ++i) { + ncm_interface.xmit_free_ntb[i] = ncm_interface.xmit_ntb + i; + } + for (int i = 0; i < RECV_NTB_N; ++i) { + ncm_interface.recv_free_ntb[i] = ncm_interface.recv_ntb + i; + } +} // netd_init - -bool netd_deinit(void) /** * Deinit driver */ -{ - return true; +bool netd_deinit(void) { + return true; } - - -void netd_reset(uint8_t rhport) /** * Resets the port. * In this driver this is the same as netd_init() */ -{ - (void)rhport; - - TU_LOG3("netd_reset(%d)\n", rhport); +void netd_reset(uint8_t rhport) { + (void) rhport; - netd_init(); -} // netd_reset + netd_init(); +} // netd_reset - - -uint16_t netd_open(uint8_t rhport, tusb_desc_interface_t const *itf_desc, uint16_t max_len) /** * Open the USB interface. * - parse the USB descriptor \a TUD_CDC_NCM_DESCRIPTOR for itfnum and endpoints @@ -850,174 +757,137 @@ uint16_t netd_open(uint8_t rhport, tusb_desc_interface_t const *itf_desc, uint16 * - \a ep_notif, \a ep_in and \a ep_out are set * - USB interface is open */ -{ - TU_LOG3("netd_open(%d,%p,%d)\n", rhport, itf_desc, max_len); - - TU_ASSERT(ncm_interface.ep_notif == 0, 0); // assure that the interface is only opened once +uint16_t netd_open(uint8_t rhport, tusb_desc_interface_t const *itf_desc, uint16_t max_len) { + TU_ASSERT(ncm_interface.ep_notif == 0, 0);// assure that the interface is only opened once - ncm_interface.itf_num = itf_desc->bInterfaceNumber; // management interface + ncm_interface.itf_num = itf_desc->bInterfaceNumber;// management interface - // - // skip the two first entries and the following TUSB_DESC_CS_INTERFACE entries - // - uint16_t drv_len = sizeof(tusb_desc_interface_t); - uint8_t const *p_desc = tu_desc_next(itf_desc); - while (tu_desc_type(p_desc) == TUSB_DESC_CS_INTERFACE && drv_len <= max_len) { - drv_len += tu_desc_len(p_desc); - p_desc = tu_desc_next(p_desc); - } - - // - // get notification endpoint - // - TU_ASSERT(tu_desc_type(p_desc) == TUSB_DESC_ENDPOINT, 0); - TU_ASSERT(usbd_edpt_open(rhport, (tusb_desc_endpoint_t const* ) p_desc), 0); - ncm_interface.ep_notif = ((tusb_desc_endpoint_t const*) p_desc)->bEndpointAddress; + // skip the two first entries and the following TUSB_DESC_CS_INTERFACE entries + uint16_t drv_len = sizeof(tusb_desc_interface_t); + uint8_t const *p_desc = tu_desc_next(itf_desc); + while (tu_desc_type(p_desc) == TUSB_DESC_CS_INTERFACE && drv_len <= max_len) { drv_len += tu_desc_len(p_desc); p_desc = tu_desc_next(p_desc); + } - // - // skip the following TUSB_DESC_INTERFACE entries (which must be TUSB_CLASS_CDC_DATA) - // - while (tu_desc_type(p_desc) == TUSB_DESC_INTERFACE && drv_len <= max_len) { - tusb_desc_interface_t const *data_itf_desc = (tusb_desc_interface_t const*)p_desc; - TU_ASSERT(data_itf_desc->bInterfaceClass == TUSB_CLASS_CDC_DATA, 0); + // get notification endpoint + TU_ASSERT(tu_desc_type(p_desc) == TUSB_DESC_ENDPOINT, 0); + TU_ASSERT(usbd_edpt_open(rhport, (tusb_desc_endpoint_t const *) p_desc), 0); + ncm_interface.ep_notif = ((tusb_desc_endpoint_t const *) p_desc)->bEndpointAddress; + drv_len += tu_desc_len(p_desc); + p_desc = tu_desc_next(p_desc); - drv_len += tu_desc_len(p_desc); - p_desc = tu_desc_next(p_desc); - } + // skip the following TUSB_DESC_INTERFACE entries (which must be TUSB_CLASS_CDC_DATA) + while (tu_desc_type(p_desc) == TUSB_DESC_INTERFACE && drv_len <= max_len) { + tusb_desc_interface_t const *data_itf_desc = (tusb_desc_interface_t const *) p_desc; + TU_ASSERT(data_itf_desc->bInterfaceClass == TUSB_CLASS_CDC_DATA, 0); - // - // a TUSB_DESC_ENDPOINT (actually two) must follow, open these endpoints - // - TU_ASSERT(tu_desc_type(p_desc) == TUSB_DESC_ENDPOINT, 0); - TU_ASSERT(usbd_open_edpt_pair(rhport, p_desc, 2, TUSB_XFER_BULK, &ncm_interface.ep_out, &ncm_interface.ep_in)); - drv_len += 2 * sizeof(tusb_desc_endpoint_t); - - return drv_len; -} // netd_open + drv_len += tu_desc_len(p_desc); + p_desc = tu_desc_next(p_desc); + } + // a TUSB_DESC_ENDPOINT (actually two) must follow, open these endpoints + TU_ASSERT(tu_desc_type(p_desc) == TUSB_DESC_ENDPOINT, 0); + TU_ASSERT(usbd_open_edpt_pair(rhport, p_desc, 2, TUSB_XFER_BULK, &ncm_interface.ep_out, &ncm_interface.ep_in)); + drv_len += 2 * sizeof(tusb_desc_endpoint_t); + return drv_len; +} // netd_open -bool netd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) /** * Handle TinyUSB requests to process transfer events. */ -{ - (void)result; - - TU_LOG3("netd_xfer_cb(%d,%d,%d,%u)\n", rhport, ep_addr, result, (unsigned)xferred_bytes); - - if (ep_addr == ncm_interface.ep_out) { - // - // new NTB received - // - make the NTB valid - // - if ready transfer datagrams to the glue logic for further processing - // - if there is a free receive buffer, initiate reception - // - TU_LOG3(" EP_OUT %d %d %d %u\n", rhport, ep_addr, result, (unsigned)xferred_bytes); - if ( !recv_validate_datagram( ncm_interface.recv_tinyusb_ntb, xferred_bytes)) { - // verification failed: ignore NTB and return it to free - TU_LOG1("(EE) VALIDATION FAILED. WHAT CAN WE DO IN THIS CASE?\n"); - } - else { - // packet ok -> put it into ready list - recv_put_ntb_into_ready_list(ncm_interface.recv_tinyusb_ntb); - } - ncm_interface.recv_tinyusb_ntb = NULL; - tud_network_recv_renew_r(rhport); - } - else if (ep_addr == ncm_interface.ep_in) { - // - // transmission of an NTB finished - // - free the transmitted NTB buffer - // - insert ZLPs when necessary - // - if there is another transmit NTB waiting, try to start transmission - // - TU_LOG3(" EP_IN %d %u\n", ncm_interface.itf_data_alt, (unsigned)xferred_bytes); - xmit_put_ntb_into_free_list(ncm_interface.xmit_tinyusb_ntb); - ncm_interface.xmit_tinyusb_ntb = NULL; - if ( !xmit_insert_required_zlp(rhport, xferred_bytes)) { - xmit_start_if_possible(rhport); - } - } - else if (ep_addr == ncm_interface.ep_notif) { - // - // next transfer on notification channel - // - TU_LOG3(" EP_NOTIF\n"); - notification_xmit(rhport, true); - } - - return true; -} // netd_xfer_cb - - +bool netd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) { + (void) result; + + if (ep_addr == ncm_interface.ep_out) { + // new NTB received + // - make the NTB valid + // - if ready transfer datagrams to the glue logic for further processing + // - if there is a free receive buffer, initiate reception + if (!recv_validate_datagram(ncm_interface.recv_tinyusb_ntb, xferred_bytes)) { + // verification failed: ignore NTB and return it to free + TU_LOG_DRV("(EE) VALIDATION FAILED. WHAT CAN WE DO IN THIS CASE?\n"); + } else { + // packet ok -> put it into ready list + recv_put_ntb_into_ready_list(ncm_interface.recv_tinyusb_ntb); + } + ncm_interface.recv_tinyusb_ntb = NULL; + tud_network_recv_renew_r(rhport); + } else if (ep_addr == ncm_interface.ep_in) { + // transmission of an NTB finished + // - free the transmitted NTB buffer + // - insert ZLPs when necessary + // - if there is another transmit NTB waiting, try to start transmission + xmit_put_ntb_into_free_list(ncm_interface.xmit_tinyusb_ntb); + ncm_interface.xmit_tinyusb_ntb = NULL; + if (!xmit_insert_required_zlp(rhport, xferred_bytes)) { + xmit_start_if_possible(rhport); + } + } else if (ep_addr == ncm_interface.ep_notif) { + // next transfer on notification channel + notification_xmit(rhport, true); + } + + return true; +} // netd_xfer_cb -bool netd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request) /** * Respond to TinyUSB control requests. * At startup transmission of notification packets are done here. */ -{ - TU_LOG3("netd_control_xfer_cb(%d, %d, %p)\n", rhport, stage, request); +bool netd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request) { + if (stage != CONTROL_STAGE_SETUP) { + return true; + } - if (stage != CONTROL_STAGE_SETUP) { - return true; - } + switch (request->bmRequestType_bit.type) { + case TUSB_REQ_TYPE_STANDARD: - switch (request->bmRequestType_bit.type) { - case TUSB_REQ_TYPE_STANDARD: - TU_LOG3(" TUSB_REQ_TYPE_STANDARD: %d\n", request->bRequest); - - switch (request->bRequest) { - case TUSB_REQ_GET_INTERFACE: { - TU_VERIFY(ncm_interface.itf_num + 1 == request->wIndex, false); - - TU_LOG3(" TUSB_REQ_GET_INTERFACE - %d\n", ncm_interface.itf_data_alt); - tud_control_xfer(rhport, request, &ncm_interface.itf_data_alt, 1); - } - break; - - case TUSB_REQ_SET_INTERFACE: { - TU_VERIFY(ncm_interface.itf_num + 1 == request->wIndex && request->wValue < 2, false); - - ncm_interface.itf_data_alt = (uint8_t)request->wValue; - TU_LOG3(" TUSB_REQ_SET_INTERFACE - %d %d %d\n", ncm_interface.itf_data_alt, request->wIndex, ncm_interface.itf_num); - - if (ncm_interface.itf_data_alt == 1) { - tud_network_recv_renew_r(rhport); - notification_xmit(rhport, false); - } - tud_control_status(rhport, request); - } - break; - - // unsupported request - default: - return false; - } - break; - - case TUSB_REQ_TYPE_CLASS: - TU_VERIFY(ncm_interface.itf_num == request->wIndex, false); - - TU_LOG3(" TUSB_REQ_TYPE_CLASS: %d\n", request->bRequest); - - if (request->bRequest == NCM_GET_NTB_PARAMETERS) { - // transfer NTB parameters to host. - // TODO can one assume, that tud_control_xfer() succeeds? - TU_LOG3(" NCM_GET_NTB_PARAMETERS\n"); - tud_control_xfer(rhport, request, (void*) (uintptr_t) &ntb_parameters, sizeof(ntb_parameters)); - } - break; - - // unsupported request - default: - return false ; - } + switch (request->bRequest) { + case TUSB_REQ_GET_INTERFACE: { + TU_VERIFY(ncm_interface.itf_num + 1 == request->wIndex, false); - return true; -} // netd_control_xfer_cb + tud_control_xfer(rhport, request, &ncm_interface.itf_data_alt, 1); + } break; -#endif // ECLIPSE_GUI || ( CFG_TUD_ENABLED && CFG_TUD_NCM ) + case TUSB_REQ_SET_INTERFACE: { + TU_VERIFY(ncm_interface.itf_num + 1 == request->wIndex && request->wValue < 2, false); + + ncm_interface.itf_data_alt = (uint8_t) request->wValue; + + if (ncm_interface.itf_data_alt == 1) { + tud_network_recv_renew_r(rhport); + notification_xmit(rhport, false); + } + tud_control_status(rhport, request); + } break; + + // unsupported request + default: + return false; + } + break; + + case TUSB_REQ_TYPE_CLASS: + TU_VERIFY(ncm_interface.itf_num == request->wIndex, false); + switch (request->bRequest) { + case NCM_GET_NTB_PARAMETERS: { + // transfer NTB parameters to host. + tud_control_xfer(rhport, request, (void *) (uintptr_t) &ntb_parameters, sizeof(ntb_parameters)); + } break; + + // unsupported request + default: + return false; + } + break; + // unsupported request + default: + return false; + } + + return true; +} // netd_control_xfer_cb + +#endif // ( CFG_TUD_ENABLED && CFG_TUD_NCM ) -- cgit v1.3.1