From 2ddd74fada9b2f272923fce9c3b1926a6e9f5c80 Mon Sep 17 00:00:00 2001 From: rppicomidi Date: Fri, 12 Aug 2022 11:06:36 -0700 Subject: Add MIDI host support to tinyusb --- src/class/midi/README_midi_host.md | 111 +++++ src/class/midi/midi.h | 19 +- src/class/midi/midi_host.c | 944 +++++++++++++++++++++++++++++++++++++ src/class/midi/midi_host.h | 137 ++++++ 4 files changed, 1209 insertions(+), 2 deletions(-) create mode 100644 src/class/midi/README_midi_host.md create mode 100644 src/class/midi/midi_host.c create mode 100644 src/class/midi/midi_host.h (limited to 'src/class') diff --git a/src/class/midi/README_midi_host.md b/src/class/midi/README_midi_host.md new file mode 100644 index 000000000..9df2249b3 --- /dev/null +++ b/src/class/midi/README_midi_host.md @@ -0,0 +1,111 @@ +# MIDI HOST DRIVER +This README file contains the design notes and limitations of the +MIDI host driver. + +# MAXIMUM NUMBER OF MIDI DEVICES ATTACHED TO HOST +In this version of the driver, only one MIDI device is supported. This +constraint may change in the future. + +# MAXIMUM NUMBER OF ENDPOINTS +Although the USB MIDI 1.0 Class specification allows an arbitrary number +of endpoints, this driver supports at most one USB BULK DATA IN endpoint +and one USB BULK DATA OUT endpoint. Each endpoint can support up to 16 +virtual cables. If a device has multiple IN endpoints or multiple OUT +endpoints, it will fail to enumerate. + +Most USB MIDI devices contain both an IN endpoint and an OUT endpoint, +but not all do. For example, some USB pedals only support an OUT endpoint. +This driver allows that. + +# PUBLIC API +Applications interact with this driver via 8-bit buffers of MIDI messages +formed using the rules for sending bytes on a 5-pin DIN cable per the +original MIDI 1.0 specification. + +To send a message to a device, the Host application composes a sequence +of status and data bytes in a byte array and calls the API function. +The arguments of the function are a pointer to the byte array, the number +of bytes in the array, and the target virtual cable number 0-15. + +When the host driver receives a message from the device, the host driver +will call a callback function that the host application registers. This +callback function contains a pointer to a message buffer, a message length, +and the virtual cable number of the message buffer. One complete bulk IN +endpoint transfer might contain multiple messages targeted to different +virtual cables. + +# SUBCLASS AUDIO CONTROL +A MIDI device does not absolutely need to have an Audio Control Interface, +unless it adheres to the USB Audio Class 2 spec, but many devices +have them even if the devices do not have an audio streaming interface. +Because this driver does not support audio streaming, the descriptor parser +will skip past any audio control interface and audio streaming interface +and open only the MIDI interface. + +An audio streaming host driver can use this driver by passing a pointer +to the MIDI interface descriptor that is found after the audio streaming +interface to the midih_open() function. That is, an audio streaming host +driver would parse the audio control interface descriptor and then the +audio streaming interface and endpoint descriptors. When the next descriptor +pointer points to a MIDI interface descriptor, call midih_open() with that +descriptor pointer. + +# CLASS SPECIFIC INTERFACE AND REQUESTS +The host driver does not make use of the informaton in the class specific +interface descriptors. In the future, a public API could be created to +retrieve the string descriptors for the names of each ELEMENT, +IN JACK and OUT JACK, and how the device describes the connections. + +This driver also does not support class specific requests to control +ELEMENT items, nor does it support non-MIDI Streaming bulk endpoints. + +# MIDI CLASS SPECIFIC DESCRIPTOR TOTAL LENGTH FIELD IGNORED +I have observed at least one keyboard by a leading manufacturer that +sets the wTotalLength field of the Class-Specific MS Interface Header +Descriptor to include the length of the MIDIStreaming Endpoint +Descriptors. This is wrong per my reading of the specification. + +# MESSAGE BUFFER DETAILS +Messages buffers composed from USB data received on the IN endpoint will never contain +running status because USB MIDI 1.0 class does not support that. Messages +buffers to be sent to the device on the OUT endpont may contain running status +(the message might come from a UART data stream from a 5-pin DIN MIDI IN +cable on the host, for example). The driver may in the future correctly compose +4-byte USB MIDI Class packets using the running status if need be. However, +it does not currently do that. Also, use of running status is not a good idea +overall because a single byte error can really mess up the data stream with no +way to recover until the next non-real time status byte is in the message buffer. + +Message buffers to be sent to the device may contain Real time messages +such as MIDI clock. Real time messages may be inserted in the message +byte stream between status and data bytes of another message without disrupting +the running status. However, because MIDI 1.0 class messages are sent +as four byte packets, a real-time message so inserted will be re-ordered +to be sent to the device in a new 4-byte packet immediately before the +interrupted data stream. + +Real time messages the device sends to the host can only appear between +the status byte and data bytes of the message in System Exclusive messages +that are longer than 3 bytes. + +# POORLY FORMED USB MIDI DATA PACKETS FROM THE DEVICE +Some devices do not properly encode the code index number (CIN) for the +MIDI message status byte even though the 3-byte data payload correctly encodes +the MIDI message. This driver looks to the byte after the CIN byte to decide +how many bytes to place in the message buffer. + +Some devices do not properly encode the virtual cable number. If the virtual +cable number in the CIN data byte of the packet is not less than bNumEmbMIDIJack +for that endpoint, then the host driver assumes virtual cable 0 and does not +report an error. + +Some MIDI devices will always send back exactly wMaxPacketSize bytes on +every endpoint even if only one 4-byte packet is required (e.g., NOTE ON). +These devices send packets with 4 packet bytes 0. This driver ignores all +zero packets without reporting an error. + +# ENUMERATION FAILURES +The host may fail to enumerate a device if it has too many endpoints, if it has +if it has a Standard MS Transfer Bulk Data Endpoint Descriptor (not supported), +if it has a poorly formed descriptor, or if the descriptor is too long for +the host to read the whole thing. diff --git a/src/class/midi/midi.h b/src/class/midi/midi.h index 74dc41749..ea2cfec75 100644 --- a/src/class/midi/midi.h +++ b/src/class/midi/midi.h @@ -71,8 +71,8 @@ typedef enum MIDI_CIN_SYSEX_END_1BYTE = 5, // SysEx ends with 1 data, or 1 byte system common message MIDI_CIN_SYSEX_END_2BYTE = 6, // SysEx ends with 2 data MIDI_CIN_SYSEX_END_3BYTE = 7, // SysEx ends with 3 data - MIDI_CIN_NOTE_ON = 8, - MIDI_CIN_NOTE_OFF = 9, + MIDI_CIN_NOTE_ON = 9, + MIDI_CIN_NOTE_OFF = 8, MIDI_CIN_POLY_KEYPRESS = 10, MIDI_CIN_CONTROL_CHANGE = 11, MIDI_CIN_PROGRAM_CHANGE = 12, @@ -106,6 +106,11 @@ enum MIDI_STATUS_SYSREAL_SYSTEM_RESET = 0xFF, }; +enum +{ + MIDI_MAX_DATA_VAL = 0x7F, +}; + /// MIDI Interface Header Descriptor typedef struct TU_ATTR_PACKED { @@ -201,6 +206,16 @@ typedef struct TU_ATTR_PACKED uint8_t iElement; \ } +// This descriptor follows the standard bulk data endpoint descriptor +typedef struct +{ + uint8_t bLength ; ///< Size of this descriptor in bytes (4+bNumEmbMIDIJack) + uint8_t bDescriptorType ; ///< Descriptor Type, must be CS_ENDPOINT + uint8_t bDescriptorSubType ; ///< Descriptor SubType, must be MS_GENERAL + uint8_t bNumEmbMIDIJack; ; ///< Number of embedded MIDI jacks associated with this endpoint + uint8_t baAssocJackID[]; ; ///< A list of associated jacks +} midi_cs_desc_endpoint_t; + /** @} */ #ifdef __cplusplus diff --git a/src/class/midi/midi_host.c b/src/class/midi/midi_host.c new file mode 100644 index 000000000..e482f5265 --- /dev/null +++ b/src/class/midi/midi_host.c @@ -0,0 +1,944 @@ +/* + * The MIT License (MIT) + * + * 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 + * 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. + */ + +#include "tusb_option.h" + +#if (TUSB_OPT_HOST_ENABLED && CFG_TUH_MIDI) + +#include "host/usbh.h" +#include "host/usbh_classdriver.h" + +#include "midi_host.h" + +//--------------------------------------------------------------------+ +// MACRO CONSTANT TYPEDEF +//--------------------------------------------------------------------+ +#ifndef CFG_TUH_MAX_CABLES + #define CFG_TUH_MAX_CABLES 16 +#endif +#define CFG_TUH_MIDI_RX_BUFSIZE 64 +#define CFG_TUH_MIDI_TX_BUFSIZE 64 +#ifndef CFG_TUH_MIDI_EP_BUFSIZE + #define CFG_TUH_MIDI_EP_BUFSIZE 64 +#endif + +// TODO: refactor to share code with the MIDI Device driver +typedef struct +{ + uint8_t buffer[4]; + uint8_t index; + uint8_t total; +}midi_stream_t; + +typedef struct +{ + uint8_t dev_addr; + uint8_t itf_num; + + uint8_t ep_in; // IN endpoint address + uint8_t ep_out; // OUT endpoint address + uint16_t ep_in_max; // min( CFG_TUH_MIDI_RX_BUFSIZE, wMaxPacketSize of the IN endpoint) + uint16_t ep_out_max; // min( CFG_TUH_MIDI_TX_BUFSIZE, wMaxPacketSize of the OUT endpoint) + + uint8_t num_cables_rx; // IN endpoint CS descriptor bNumEmbMIDIJack value + uint8_t num_cables_tx; // OUT endpoint CS descriptor bNumEmbMIDIJack value + + // For Stream read()/write() API + // Messages are always 4 bytes long, queue them for reading and writing so the + // callers can use the Stream interface with single-byte read/write calls. + midi_stream_t stream_write; + midi_stream_t stream_read; + + /*------------- From this point, data is not cleared by bus reset -------------*/ + // Endpoint FIFOs + tu_fifo_t rx_ff; + tu_fifo_t tx_ff; + + + uint8_t rx_ff_buf[CFG_TUH_MIDI_RX_BUFSIZE]; + uint8_t tx_ff_buf[CFG_TUH_MIDI_TX_BUFSIZE]; + + #if CFG_FIFO_MUTEX + osal_mutex_def_t rx_ff_mutex; + osal_mutex_def_t tx_ff_mutex; + #endif + + // Endpoint Transfer buffer + CFG_TUSB_MEM_ALIGN uint8_t epout_buf[CFG_TUH_MIDI_EP_BUFSIZE]; + CFG_TUSB_MEM_ALIGN uint8_t epin_buf[CFG_TUH_MIDI_EP_BUFSIZE]; + + bool configured; + +#if CFG_MIDI_HOST_DEVSTRINGS +#define MAX_STRING_INDICES 32 + uint8_t all_string_indices[MAX_STRING_INDICES]; + uint8_t num_string_indices; +#define MAX_IN_JACKS 8 +#define MAX_OUT_JACKS 8 + struct { + uint8_t jack_id; + int8_t jack_type; + uint8_t string_index; + } in_jack_info[MAX_IN_JACKS]; + uint8_t next_in_jack; + struct { + uint8_t jack_id; + uint8_t jack_type; + uint8_t num_source_ids; + uint8_t source_ids[MAX_IN_JACKS/4]; + uint8_t string_index; + } out_jack_info[MAX_OUT_JACKS]; + uint8_t next_out_jack; + uint8_t ep_in_associated_jacks[MAX_OUT_JACKS/2]; + uint8_t ep_out_associated_jacks[MAX_IN_JACKS/2]; +#endif +}midih_interface_t; + +static midih_interface_t _midi_host[CFG_TUH_DEVICE_MAX]; + +static midih_interface_t *get_midi_host(uint8_t dev_addr) +{ + TU_VERIFY(dev_addr >0 && dev_addr <= CFG_TUH_DEVICE_MAX); + return (_midi_host + dev_addr - 1); +} + +//------------- Internal prototypes -------------// +static uint32_t write_flush(uint8_t dev_addr, midih_interface_t* midi); + +//--------------------------------------------------------------------+ +// USBH API +//--------------------------------------------------------------------+ +void midih_init(void) +{ + tu_memclr(&_midi_host, sizeof(_midi_host)); + // config fifos + for (int inst = 0; inst < CFG_TUH_DEVICE_MAX; inst++) + { + midih_interface_t *p_midi_host = &_midi_host[inst]; + tu_fifo_config(&p_midi_host->rx_ff, p_midi_host->rx_ff_buf, CFG_TUH_MIDI_RX_BUFSIZE, 1, false); // true, true + tu_fifo_config(&p_midi_host->tx_ff, p_midi_host->tx_ff_buf, CFG_TUH_MIDI_TX_BUFSIZE, 1, false); // OBVS. + + #if CFG_FIFO_MUTEX + tu_fifo_config_mutex(&p_midi_host->rx_ff, NULL, osal_mutex_create(&p_midi_host->rx_ff_mutex)); + tu_fifo_config_mutex(&p_midi_host->tx_ff, osal_mutex_create(&p_midi_host->tx_ff_mutex), NULL); + #endif + } +} + +bool midih_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) +{ + (void)result; + midih_interface_t *p_midi_host = get_midi_host(dev_addr); + TU_VERIFY(p_midi_host != NULL); + if ( ep_addr == p_midi_host->ep_in) + { + if (0 == xferred_bytes) + { + return true; // No data to handle + } + + // receive new data if available + uint32_t packets_queued = 0; + if (xferred_bytes) + { + // put in the RX FIFO only non-zero MIDI IN 4-byte packets + uint8_t* buf = p_midi_host->epin_buf; + uint32_t npackets = xferred_bytes / 4; + uint32_t packet_num; + for (packet_num = 0; packet_num < npackets; packet_num++) + { + // some devices send back all zero packets even if there is no data ready + uint32_t packet = (uint32_t)((*buf)<<24) | ((uint32_t)(*(buf+1))<<16) | ((uint32_t)(*(buf+2))<<8) | ((uint32_t)(*(buf+3))); + if (packet != 0) + { + tu_fifo_write_n(&p_midi_host->rx_ff, buf, 4); + ++packets_queued; + TU_LOG3("MIDI RX=%08x\r\n", packet); + } + buf += 4; + } + } + // invoke receive callback if available + if (tuh_midi_rx_cb) + { + tuh_midi_rx_cb(dev_addr, packets_queued); + } + } + else if ( ep_addr == p_midi_host->ep_out ) + { + if (0 == write_flush(dev_addr, p_midi_host)) + { + // If there is no data left, a ZLP should be sent if + // xferred_bytes is multiple of EP size and not zero + if ( !tu_fifo_count(&p_midi_host->tx_ff) && xferred_bytes && (0 == (xferred_bytes % p_midi_host->ep_out_max)) ) + { + if ( usbh_edpt_claim(dev_addr, p_midi_host->ep_out) ) + { + TU_ASSERT(usbh_edpt_xfer(dev_addr, p_midi_host->ep_out, XFER_RESULT_SUCCESS, 0)); + } + } + } + if (tuh_midi_tx_cb) + { + tuh_midi_tx_cb(dev_addr); + } + } + + return true; +} + +void midih_close(uint8_t dev_addr) +{ + midih_interface_t *p_midi_host = get_midi_host(dev_addr); + if (p_midi_host == NULL) + return; + if (tuh_midi_umount_cb) + tuh_midi_umount_cb(dev_addr, 0); + tu_fifo_clear(&p_midi_host->rx_ff); + tu_fifo_clear(&p_midi_host->tx_ff); + p_midi_host->ep_in = 0; + p_midi_host->ep_in_max = 0; + p_midi_host->ep_out = 0; + p_midi_host->ep_out_max = 0; + p_midi_host->itf_num = 0; + p_midi_host->num_cables_rx = 0; + p_midi_host->num_cables_tx = 0; + p_midi_host->dev_addr = 255; // invalid + p_midi_host->configured = false; + tu_memclr(&p_midi_host->stream_read, sizeof(p_midi_host->stream_read)); + tu_memclr(&p_midi_host->stream_write, sizeof(p_midi_host->stream_write)); +} + +//--------------------------------------------------------------------+ +// Enumeration +//--------------------------------------------------------------------+ +bool midih_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *desc_itf, uint16_t max_len) +{ + (void) rhport; + + midih_interface_t *p_midi_host = get_midi_host(dev_addr); + + TU_VERIFY(p_midi_host != NULL); + p_midi_host->num_string_indices = 0; + TU_VERIFY(TUSB_CLASS_AUDIO == desc_itf->bInterfaceClass); + // There can be just a MIDI interface or an audio and a MIDI interface. Only open the MIDI interface + uint8_t const *p_desc = (uint8_t const *) desc_itf; + uint16_t len_parsed = 0; + if (AUDIO_SUBCLASS_CONTROL == desc_itf->bInterfaceSubClass) + { + // Keep track of any string descriptor that might be here + if (desc_itf->iInterface != 0) + p_midi_host->all_string_indices[p_midi_host->num_string_indices++] = desc_itf->iInterface; + // This driver does not support audio streaming. However, if this is the audio control interface + // there might be a MIDI interface following it. Search through every descriptor until a MIDI + // interface is found or the end of the descriptor is found + while (len_parsed < max_len && (desc_itf->bInterfaceClass != TUSB_CLASS_AUDIO || desc_itf->bInterfaceSubClass != AUDIO_SUBCLASS_MIDI_STREAMING)) + { + len_parsed += desc_itf->bLength; + p_desc = tu_desc_next(p_desc); + desc_itf = (tusb_desc_interface_t const *)p_desc; + } + + TU_VERIFY(TUSB_CLASS_AUDIO == desc_itf->bInterfaceClass); + } + TU_VERIFY(AUDIO_SUBCLASS_MIDI_STREAMING == desc_itf->bInterfaceSubClass); + len_parsed += desc_itf->bLength; + + // Keep track of any string descriptor that might be here + if (desc_itf->iInterface != 0) + p_midi_host->all_string_indices[p_midi_host->num_string_indices++] = desc_itf->iInterface; + + p_desc = tu_desc_next(p_desc); + TU_LOG1("MIDI opening Interface %u (addr = %u)\r\n", desc_itf->bInterfaceNumber, dev_addr); + // Find out if getting the MIDI class specific interface header or an endpoint descriptor + // or a class-specific endpoint descriptor + // Jack descriptors or element descriptors must follow the cs interface header, + // but this driver does not support devices that contain element descriptors + + // assume it is an interface header + midi_desc_header_t const *p_mdh = (midi_desc_header_t const *)p_desc; + TU_VERIFY((p_mdh->bDescriptorType == TUSB_DESC_CS_INTERFACE && p_mdh->bDescriptorSubType == MIDI_CS_INTERFACE_HEADER) || + (p_mdh->bDescriptorType == TUSB_DESC_CS_ENDPOINT && p_mdh->bDescriptorSubType == MIDI_CS_ENDPOINT_GENERAL) || + p_mdh->bDescriptorType == TUSB_DESC_ENDPOINT); + + uint8_t prev_ep_addr = 0; // the CS endpoint descriptor is associated with the previous endpoint descrptor + p_midi_host->itf_num = desc_itf->bInterfaceNumber; + tusb_desc_endpoint_t const* in_desc = NULL; + tusb_desc_endpoint_t const* out_desc = NULL; + while (len_parsed < max_len) + { + TU_VERIFY((p_mdh->bDescriptorType == TUSB_DESC_CS_INTERFACE) || + (p_mdh->bDescriptorType == TUSB_DESC_CS_ENDPOINT && p_mdh->bDescriptorSubType == MIDI_CS_ENDPOINT_GENERAL) || + p_mdh->bDescriptorType == TUSB_DESC_ENDPOINT); + + if (p_mdh->bDescriptorType == TUSB_DESC_CS_INTERFACE) { + // The USB host doesn't really need this information unless it uses + // the string descriptor for a jack or Element + + // assume it is an input jack + midi_desc_in_jack_t const *p_mdij = (midi_desc_in_jack_t const *)p_desc; + if (p_mdij->bDescriptorSubType == MIDI_CS_INTERFACE_HEADER) + { + TU_LOG2("Found MIDI Interface Header\r\b"); + } + else if (p_mdij->bDescriptorSubType == MIDI_CS_INTERFACE_IN_JACK) + { + // Then it is an in jack. + TU_LOG2("Found in jack\r\n"); +#if CFG_MIDI_HOST_DEVSTRINGS + if (p_midi_host->next_in_jack < MAX_IN_JACKS) + { + p_midi_host->in_jack_info[p_midi_host->next_in_jack].jack_id = p_mdij->bJackID; + p_midi_host->in_jack_info[p_midi_host->next_in_jack].jack_type = p_mdij->bJackType; + p_midi_host->in_jack_info[p_midi_host->next_in_jack].string_index = p_mdij->iJack; + ++p_midi_host->next_in_jack; + // Keep track of any string descriptor that might be here + if (p_mdij->iJack != 0) + p_midi_host->all_string_indices[p_midi_host->num_string_indices++] = p_mdij->iJack; + + } +#endif + } + else if (p_mdij->bDescriptorSubType == MIDI_CS_INTERFACE_OUT_JACK) + { + // then it is an out jack + TU_LOG2("Found out jack\r\n"); +#if CFG_MIDI_HOST_DEVSTRINGS + if (p_midi_host->next_out_jack < MAX_OUT_JACKS) + { + midi_desc_out_jack_t const *p_mdoj = (midi_desc_out_jack_t const *)p_desc; + p_midi_host->out_jack_info[p_midi_host->next_out_jack].jack_id = p_mdoj->bJackID; + p_midi_host->out_jack_info[p_midi_host->next_out_jack].jack_type = p_mdoj->bJackType; + p_midi_host->out_jack_info[p_midi_host->next_out_jack].num_source_ids = p_mdoj->bNrInputPins; + struct associated_jack_s { + uint8_t id; + uint8_t pin; + } *associated_jack = (struct associated_jack_s *)(p_desc+6); + int jack; + for (jack = 0; jack < p_mdoj->bNrInputPins; jack++) + { + p_midi_host->out_jack_info[p_midi_host->next_out_jack].source_ids[jack] = associated_jack->id; + } + p_midi_host->out_jack_info[p_midi_host->next_out_jack].string_index = *(p_desc+6+p_mdoj->bNrInputPins*2); + ++p_midi_host->next_out_jack; + if (p_mdoj->iJack != 0) + p_midi_host->all_string_indices[p_midi_host->num_string_indices++] = p_mdoj->iJack; + } +#endif + } + else if (p_mdij->bDescriptorSubType == MIDI_CS_INTERFACE_ELEMENT) + { + // the it is an element; + #if CFG_MIDI_HOST_DEVSTRINGS + TU_LOG1("Found element; strings not supported\r\n"); + #else + TU_LOG2("Found element\r\n"); + #endif + } + else + { + TU_LOG2("Unknown CS Interface sub-type %u\r\n", p_mdij->bDescriptorSubType); + TU_VERIFY(false); // unknown CS Interface sub-type + } + len_parsed += p_mdij->bLength; + } + else if (p_mdh->bDescriptorType == TUSB_DESC_CS_ENDPOINT) + { + TU_LOG2("found CS_ENDPOINT Descriptor for %u\r\n", prev_ep_addr); + TU_VERIFY(prev_ep_addr != 0); + // parse out the mapping between the device's embedded jacks and the endpoints + // Each embedded IN jack is assocated with an OUT endpoint + midi_cs_desc_endpoint_t const* p_csep = (midi_cs_desc_endpoint_t const*)p_mdh; + if (tu_edpt_dir(prev_ep_addr) == TUSB_DIR_OUT) + { + TU_VERIFY(p_midi_host->ep_out == prev_ep_addr); + TU_VERIFY(p_midi_host->num_cables_tx == 0); + p_midi_host->num_cables_tx = p_csep->bNumEmbMIDIJack; +#if CFG_MIDI_HOST_DEVSTRINGS + uint8_t jack; + uint8_t max_jack = p_midi_host->num_cables_tx; + if (max_jack > sizeof(p_midi_host->ep_out_associated_jacks)) + { + max_jack = sizeof(p_midi_host->ep_out_associated_jacks); + } + for (jack = 0; jack < max_jack; jack++) + { + p_midi_host->ep_out_associated_jacks[jack] = p_csep->baAssocJackID[jack]; + } +#endif + } + else + { + TU_VERIFY(p_midi_host->ep_in == prev_ep_addr); + TU_VERIFY(p_midi_host->num_cables_rx == 0); + p_midi_host->num_cables_rx = p_csep->bNumEmbMIDIJack; +#if CFG_MIDI_HOST_DEVSTRINGS + uint8_t jack; + uint8_t max_jack = p_midi_host->num_cables_rx; + if (max_jack > sizeof(p_midi_host->ep_in_associated_jacks)) + { + max_jack = sizeof(p_midi_host->ep_in_associated_jacks); + } + for (jack = 0; jack < max_jack; jack++) + { + p_midi_host->ep_in_associated_jacks[jack] = p_csep->baAssocJackID[jack]; + } +#endif + } + len_parsed += p_csep->bLength; + prev_ep_addr = 0; + } + else if (p_mdh->bDescriptorType == TUSB_DESC_ENDPOINT) { + // parse out the bulk endpoint info + tusb_desc_endpoint_t const *p_ep = (tusb_desc_endpoint_t const *)p_mdh; + TU_LOG2("found ENDPOINT Descriptor for %u\r\n", p_ep->bEndpointAddress); + if (tu_edpt_dir(p_ep->bEndpointAddress) == TUSB_DIR_OUT) + { + TU_VERIFY(p_midi_host->ep_out == 0); + TU_VERIFY(p_midi_host->num_cables_tx == 0); + p_midi_host->ep_out = p_ep->bEndpointAddress; + p_midi_host->ep_out_max = p_ep->wMaxPacketSize; + if (p_midi_host->ep_out_max > CFG_TUH_MIDI_TX_BUFSIZE) + p_midi_host->ep_out_max = CFG_TUH_MIDI_TX_BUFSIZE; + prev_ep_addr = p_midi_host->ep_out; + out_desc = p_ep; + } + else + { + TU_VERIFY(p_midi_host->ep_in == 0); + TU_VERIFY(p_midi_host->num_cables_rx == 0); + p_midi_host->ep_in = p_ep->bEndpointAddress; + p_midi_host->ep_in_max = p_ep->wMaxPacketSize; + if (p_midi_host->ep_in_max > CFG_TUH_MIDI_RX_BUFSIZE) + p_midi_host->ep_in_max = CFG_TUH_MIDI_RX_BUFSIZE; + prev_ep_addr = p_midi_host->ep_in; + in_desc = p_ep; + } + len_parsed += p_mdh->bLength; + } + p_desc = tu_desc_next(p_desc); + p_mdh = (midi_desc_header_t const *)p_desc; + } + TU_VERIFY((p_midi_host->ep_out != 0 && p_midi_host->num_cables_tx != 0) || + (p_midi_host->ep_in != 0 && p_midi_host->num_cables_rx != 0)); + TU_LOG1("MIDI descriptor parsed successfully\r\n"); + // remove duplicate string indices + for (int idx=0; idx < p_midi_host->num_string_indices; idx++) { + for (int jdx = idx+1; jdx < p_midi_host->num_string_indices; jdx++) { + while (jdx < p_midi_host->num_string_indices && p_midi_host->all_string_indices[idx] == p_midi_host->all_string_indices[jdx]) { + // delete the duplicate by overwriting it with the last entry and reducing the number of entries by 1 + p_midi_host->all_string_indices[jdx] = p_midi_host->all_string_indices[p_midi_host->num_string_indices-1]; + --p_midi_host->num_string_indices; + } + } + } + if (in_desc) + { + TU_ASSERT(tuh_edpt_open(dev_addr, in_desc)); + // Some devices always return exactly the request length so transfers won't complete + // unless you assume every transfer is the last one. + // TODO usbh_edpt_force_last_buffer(dev_addr, p_midi_host->ep_in, true); + } + if (out_desc) + { + TU_ASSERT(tuh_edpt_open(dev_addr, out_desc)); + } + p_midi_host->dev_addr = dev_addr; + + if (tuh_midi_mount_cb) + { + tuh_midi_mount_cb(dev_addr, p_midi_host->ep_in, p_midi_host->ep_out, p_midi_host->num_cables_rx, p_midi_host->num_cables_tx); + } + return true; +} + +bool tuh_midi_configured(uint8_t dev_addr) +{ + midih_interface_t *p_midi_host = get_midi_host(dev_addr); + TU_VERIFY(p_midi_host != NULL); + return p_midi_host->configured; +} + +bool midih_set_config(uint8_t dev_addr, uint8_t itf_num) +{ + (void) itf_num; + midih_interface_t *p_midi_host = get_midi_host(dev_addr); + TU_VERIFY(p_midi_host != NULL); + p_midi_host->configured = true; + + // TODO I don't think there are any special config things to do for MIDI + + return true; +} + +//--------------------------------------------------------------------+ +// Stream API +//--------------------------------------------------------------------+ +static uint32_t write_flush(uint8_t dev_addr, midih_interface_t* midi) +{ + // No data to send + if ( !tu_fifo_count(&midi->tx_ff) ) return 0; + + // skip if previous transfer not complete + TU_VERIFY( usbh_edpt_claim(dev_addr, midi->ep_out) ); + + uint16_t count = tu_fifo_read_n(&midi->tx_ff, midi->epout_buf, midi->ep_out_max); + + if (count) + { + TU_ASSERT( usbh_edpt_xfer(dev_addr, midi->ep_out, midi->epout_buf, count), 0 ); + return count; + }else + { + // Release endpoint since we don't make any transfer + usbh_edpt_release(dev_addr, midi->ep_out); + return 0; + } +} + +bool tuh_midi_read_poll( uint8_t dev_addr ) +{ + midih_interface_t *p_midi_host = get_midi_host(dev_addr); + TU_VERIFY(p_midi_host != NULL); + bool result = false; + + bool in_edpt_not_busy = !usbh_edpt_busy(dev_addr, p_midi_host->ep_in); + if (in_edpt_not_busy) + { + TU_LOG2("Requesting poll IN endpoint %d\r\n", p_midi_host->ep_in); + TU_ASSERT(usbh_edpt_xfer(p_midi_host->dev_addr, p_midi_host->ep_in, _midi_host->epin_buf, _midi_host->ep_in_max), 0); + result = true; + } + else + { + // Maybe the IN endpoint is only busy because the RP2040 host hardware + // is retrying a NAK'd IN transfer forever. Try aborting the NAK'd + // transfer to allow other transfers to happen on the one shared + // epx endpoint. + // TODO for RP2040 USB shared endpoint: usbh_edpt_clear_in_on_nak(p_midi_host->dev_addr, p_midi_host->ep_in); + } + return result; +} + +uint32_t tuh_midi_stream_write (uint8_t dev_addr, uint8_t cable_num, uint8_t const* buffer, uint32_t bufsize) +{ + midih_interface_t *p_midi_host = get_midi_host(dev_addr); + TU_VERIFY(p_midi_host != NULL); + TU_VERIFY(cable_num < p_midi_host->num_cables_tx); + midi_stream_t *stream = &p_midi_host->stream_write; + + uint32_t i = 0; + while ( (i < bufsize) && (tu_fifo_remaining(&p_midi_host->tx_ff) >= 4) ) + { + uint8_t const data = buffer[i]; + i++; + if (data >= MIDI_STATUS_SYSREAL_TIMING_CLOCK) + { + // real-time messages need to be sent right away + midi_stream_t streamrt; + streamrt.buffer[0] = MIDI_CIN_SYSEX_END_1BYTE; + streamrt.buffer[1] = data; + streamrt.index = 2; + streamrt.total = 2; + uint16_t const count = tu_fifo_write_n(&p_midi_host->tx_ff, streamrt.buffer, 4); + // FIFO overflown, since we already check fifo remaining. It is probably race condition + TU_ASSERT(count == 4, i); + } + else if ( stream->index == 0 ) + { + //------------- New event packet -------------// + + uint8_t const msg = data >> 4; + + stream->index = 2; + stream->buffer[1] = data; + + // Check to see if we're still in a SysEx transmit. + if ( stream->buffer[0] == MIDI_CIN_SYSEX_START ) + { + if ( data == MIDI_STATUS_SYSEX_END ) + { + stream->buffer[0] = MIDI_CIN_SYSEX_END_1BYTE; + stream->total = 2; + } + else + { + stream->total = 4; + } + } + else if ( (msg >= 0x8 && msg <= 0xB) || msg == 0xE ) + { + // Channel Voice Messages + stream->buffer[0] = (cable_num << 4) | msg; + stream->total = 4; + } + else if ( msg == 0xC || msg == 0xD) + { + // Channel Voice Messages, two-byte variants (Program Change and Channel Pressure) + stream->buffer[0] = (cable_num << 4) | msg; + stream->total = 3; + } + else if ( msg == 0xf ) + { + // System message + if ( data == MIDI_STATUS_SYSEX_START ) + { + stream->buffer[0] = MIDI_CIN_SYSEX_START; + stream->total = 4; + } + else if ( data == MIDI_STATUS_SYSCOM_TIME_CODE_QUARTER_FRAME || data == MIDI_STATUS_SYSCOM_SONG_SELECT ) + { + stream->buffer[0] = MIDI_CIN_SYSCOM_2BYTE; + stream->total = 3; + } + else if ( data == MIDI_STATUS_SYSCOM_SONG_POSITION_POINTER ) + { + stream->buffer[0] = MIDI_CIN_SYSCOM_3BYTE; + stream->total = 4; + } + else + { + stream->buffer[0] = MIDI_CIN_SYSEX_END_1BYTE; + stream->total = 2; + } + } + else + { + // Pack individual bytes if we don't support packing them into words. + stream->buffer[0] = cable_num << 4 | 0xf; + stream->buffer[2] = 0; + stream->buffer[3] = 0; + stream->index = 2; + stream->total = 2; + } + } + else + { + //------------- On-going (buffering) packet -------------// + + TU_ASSERT(stream->index < 4, i); + stream->buffer[stream->index] = data; + stream->index++; + // See if this byte ends a SysEx. + if ( stream->buffer[0] == MIDI_CIN_SYSEX_START && data == MIDI_STATUS_SYSEX_END ) + { + stream->buffer[0] = MIDI_CIN_SYSEX_START + (stream->index - 1); + stream->total = stream->index; + } + } + + // Send out packet + if ( stream->index >= 2 && stream->index == stream->total ) + { + // zeroes unused bytes + for(uint8_t idx = stream->total; idx < 4; idx++) stream->buffer[idx] = 0; + TU_LOG3_MEM(stream->buffer, 4, 2); + + uint16_t const count = tu_fifo_write_n(&p_midi_host->tx_ff, stream->buffer, 4); + + // complete current event packet, reset stream + stream->index = 0; + stream->total = 0; + + // FIFO overflown, since we already check fifo remaining. It is probably race condition + TU_ASSERT(count == 4, i); + } + } + return i; +} + +bool tuh_midi_packet_write (uint8_t dev_addr, uint8_t const packet[4]) +{ + midih_interface_t *p_midi_host = get_midi_host(dev_addr); + TU_VERIFY(p_midi_host != NULL); + + if (tu_fifo_remaining(&p_midi_host->tx_ff) < 4) + { + return false; + } + + tu_fifo_write_n(&p_midi_host->tx_ff, packet, 4); + + return true; +} + +uint32_t tuh_midi_stream_flush( uint8_t dev_addr ) +{ + midih_interface_t *p_midi_host = get_midi_host(dev_addr); + TU_VERIFY(p_midi_host != NULL); + + uint32_t bytes_flushed = 0; + if (!usbh_edpt_busy(p_midi_host->dev_addr, p_midi_host->ep_out)) + { + bytes_flushed = write_flush(dev_addr, p_midi_host); + } + return bytes_flushed; +} +//--------------------------------------------------------------------+ +// Helper +//--------------------------------------------------------------------+ +uint8_t tuh_midih_get_num_tx_cables (uint8_t dev_addr) +{ + midih_interface_t *p_midi_host = get_midi_host(dev_addr); + TU_VERIFY(p_midi_host != NULL); + TU_VERIFY(p_midi_host->ep_out != 0); // returns 0 if fails + return p_midi_host->num_cables_tx; +} + +uint8_t tuh_midih_get_num_rx_cables (uint8_t dev_addr) +{ + midih_interface_t *p_midi_host = get_midi_host(dev_addr); + TU_VERIFY(p_midi_host != NULL); + TU_VERIFY(p_midi_host->ep_in != 0); // returns 0 if fails + return p_midi_host->num_cables_rx; +} + +bool tuh_midi_packet_read (uint8_t dev_addr, uint8_t packet[4]) +{ + midih_interface_t *p_midi_host = get_midi_host(dev_addr); + TU_VERIFY(p_midi_host != NULL); + TU_VERIFY(tu_fifo_count(&p_midi_host->rx_ff) >= 4); + return tu_fifo_read_n(&p_midi_host->rx_ff, packet, 4) == 4; +} + +uint32_t tuh_midi_stream_read (uint8_t dev_addr, uint8_t *p_cable_num, uint8_t *p_buffer, uint16_t bufsize) +{ + midih_interface_t *p_midi_host = get_midi_host(dev_addr); + TU_VERIFY(p_midi_host != NULL); + uint32_t bytes_buffered = 0; + TU_ASSERT(p_cable_num); + TU_ASSERT(p_buffer); + TU_ASSERT(bufsize); + uint8_t one_byte; + if (!tu_fifo_peek(&p_midi_host->rx_ff, &one_byte)) + { + return 0; + } + *p_cable_num = (one_byte >> 4) & 0xf; + uint32_t nread = tu_fifo_read_n(&p_midi_host->rx_ff, p_midi_host->stream_read.buffer, 4); + static uint16_t cable_sysex_in_progress; // bit i is set if received MIDI_STATUS_SYSEX_START but not MIDI_STATUS_SYSEX_END + while (nread == 4 && bytes_buffered < bufsize) + { + *p_cable_num=(p_midi_host->stream_read.buffer[0] >> 4) & 0x0f; + uint8_t bytes_to_add_to_stream = 0; + if (*p_cable_num < p_midi_host->num_cables_rx) + { + // ignore the CIN field; too many devices out there encode this wrong + uint8_t status = p_midi_host->stream_read.buffer[1]; + uint16_t cable_mask = 1 << *p_cable_num; + if (status <= MIDI_MAX_DATA_VAL || status == MIDI_STATUS_SYSEX_START) + { + if (status == MIDI_STATUS_SYSEX_START) + { + cable_sysex_in_progress |= cable_mask; + } + // only add the packet if a sysex message is in progress + if (cable_sysex_in_progress & cable_mask) + { + ++bytes_to_add_to_stream; + uint8_t idx; + for (idx = 2; idx < 4; idx++) + { + if (p_midi_host->stream_read.buffer[idx] <= MIDI_MAX_DATA_VAL) + { + ++bytes_to_add_to_stream; + } + else if (p_midi_host->stream_read.buffer[idx] == MIDI_STATUS_SYSEX_END) + { + ++bytes_to_add_to_stream; + cable_sysex_in_progress &= ~cable_mask; + idx = 4; // force the loop to exit; I hate break statements in loops + } + } + } + } + else if (status < MIDI_STATUS_SYSEX_START) + { + // then it is a channel message either three bytes or two + uint8_t fake_cin = (status & 0xf0) >> 4; + switch (fake_cin) + { + case MIDI_CIN_NOTE_OFF: + case MIDI_CIN_NOTE_ON: + case MIDI_CIN_POLY_KEYPRESS: + case MIDI_CIN_CONTROL_CHANGE: + case MIDI_CIN_PITCH_BEND_CHANGE: + bytes_to_add_to_stream = 3; + break; + case MIDI_CIN_PROGRAM_CHANGE: + case MIDI_CIN_CHANNEL_PRESSURE: + bytes_to_add_to_stream = 2; + break; + default: + break; // Should not get this + } + cable_sysex_in_progress &= ~cable_mask; + } + else if (status < MIDI_STATUS_SYSREAL_TIMING_CLOCK) + { + switch (status) + { + case MIDI_STATUS_SYSCOM_TIME_CODE_QUARTER_FRAME: + case MIDI_STATUS_SYSCOM_SONG_SELECT: + bytes_to_add_to_stream = 2; + break; + case MIDI_STATUS_SYSCOM_SONG_POSITION_POINTER: + bytes_to_add_to_stream = 3; + break; + case MIDI_STATUS_SYSCOM_TUNE_REQUEST: + case MIDI_STATUS_SYSEX_END: + bytes_to_add_to_stream = 1; + break; + default: + break; + cable_sysex_in_progress &= ~cable_mask; + } + } + else + { + // Real-time message: can be inserted into a sysex message, + // so do don't clear cable_sysex_in_progress bit + bytes_to_add_to_stream = 1; + } + } + uint8_t idx; + for (idx = 1; idx <= bytes_to_add_to_stream; idx++) + { + *p_buffer++ = p_midi_host->stream_read.buffer[idx]; + } + bytes_buffered += bytes_to_add_to_stream; + nread = 0; + if (tu_fifo_peek(&p_midi_host->rx_ff, &one_byte)) + { + uint8_t new_cable = (one_byte >> 4) & 0xf; + if (new_cable == *p_cable_num) + { + // still on the same cable. Continue reading the stream + nread = tu_fifo_read_n(&p_midi_host->rx_ff, p_midi_host->stream_read.buffer, 4); + } + } + } + + return bytes_buffered; +} + +uint8_t tuh_midi_get_num_rx_cables(uint8_t dev_addr) +{ + midih_interface_t *p_midi_host = get_midi_host(dev_addr); + TU_VERIFY(p_midi_host != NULL); + uint8_t num_cables = 0; + if (p_midi_host) + { + num_cables = p_midi_host->num_cables_rx; + } + return num_cables; +} + +uint8_t tuh_midi_get_num_tx_cables(uint8_t dev_addr) +{ + midih_interface_t *p_midi_host = get_midi_host(dev_addr); + TU_VERIFY(p_midi_host != NULL); + uint8_t num_cables = 0; + if (p_midi_host) + { + num_cables = p_midi_host->num_cables_tx; + } + return num_cables; +} + +#if CFG_MIDI_HOST_DEVSTRINGS +static uint8_t find_string_index(midih_interface_t *ptr, uint8_t jack_id) +{ + uint8_t index = 0; + uint8_t assoc; + for (assoc = 0; index == 0 && assoc < ptr->next_in_jack; assoc++) + { + if (jack_id == ptr->in_jack_info[assoc].jack_id) + { + index = ptr->in_jack_info[assoc].string_index; + } + } + for (assoc = 0; index == 0 && assoc < ptr->next_out_jack; assoc++) + { + if (jack_id == ptr->out_jack_info[assoc].jack_id) + { + index = ptr->out_jack_info[assoc].string_index; + } + } + return index; +} +#endif + +#if CFG_MIDI_HOST_DEVSTRINGS +uint8_t tuh_midi_get_rx_cable_istrings(uint8_t dev_addr, uint8_t* istrings, uint8_t max_istrings) +{ + uint8_t nstrings = 0; + midih_interface_t *p_midi_host = get_midi_host(dev_addr); + TU_VERIFY(p_midi_host != NULL); + nstrings = p_midi_host->num_cables_rx; + if (nstrings > max_istrings) + { + nstrings = max_istrings; + } + uint8_t jack; + for (jack=0; jackep_in_associated_jacks[jack]; + istrings[jack] = find_string_index(p_midi_host, jack_id); + } + return nstrings; +} + +uint8_t tuh_midi_get_tx_cable_istrings(uint8_t dev_addr, uint8_t* istrings, uint8_t max_istrings) +{ + uint8_t nstrings = 0; + midih_interface_t *p_midi_host = get_midi_host(dev_addr); + TU_VERIFY(p_midi_host != NULL); + nstrings = p_midi_host->num_cables_tx; + if (nstrings > max_istrings) + { + nstrings = max_istrings; + } + uint8_t jack; + for (jack=0; jackep_out_associated_jacks[jack]; + istrings[jack] = find_string_index(p_midi_host, jack_id); + } + return nstrings; +} +#endif + +uint8_t tuh_midi_get_all_istrings(uint8_t dev_addr, const uint8_t** istrings) +{ + midih_interface_t *p_midi_host = get_midi_host(dev_addr); + TU_VERIFY(p_midi_host != NULL); + uint8_t nstrings = p_midi_host->num_string_indices; + if (nstrings) + *istrings = p_midi_host->all_string_indices; + return nstrings; +} +#endif diff --git a/src/class/midi/midi_host.h b/src/class/midi/midi_host.h new file mode 100644 index 000000000..fc661939a --- /dev/null +++ b/src/class/midi/midi_host.h @@ -0,0 +1,137 @@ +/* + * The MIT License (MIT) + * + * 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 + * 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_MIDI_HOST_H_ +#define _TUSB_MIDI_HOST_H_ + +#include "class/audio/audio.h" +#include "midi.h" + +#ifdef __cplusplus + extern "C" { +#endif + +//--------------------------------------------------------------------+ +// Class Driver Configuration +//--------------------------------------------------------------------+ + +// TODO Highspeed bulk transfer can be up to 512 bytes +#ifndef CFG_TUH_HID_EPIN_BUFSIZE +#define CFG_TUH_HID_EPIN_BUFSIZE 64 +#endif + +#ifndef CFG_TUH_HID_EPOUT_BUFSIZE +#define CFG_TUH_HID_EPOUT_BUFSIZE 64 +#endif + + +//--------------------------------------------------------------------+ +// Application API (Single Interface) +//--------------------------------------------------------------------+ +bool tuh_midi_configured (uint8_t dev_addr); +uint32_t tuh_midi_available (uint8_t dev_addr); + +// return the number of virtual midi cables on the device's OUT endpoint +uint8_t tuh_midih_get_num_tx_cables (uint8_t dev_addr); + +// return the number of virtual midi cables on the device's IN endpoint +uint8_t tuh_midih_get_num_rx_cables (uint8_t dev_addr); + +// request available data from the device. tuh_midi_message_received_cb() will +// be called if the device has any data to send. Otherwise, the device will +// respond NAK. This function blocks until the transfer completes or the +// devices sends NAK. +// This function will return false if the hardware is busy. +bool tuh_midi_read_poll( uint8_t dev_addr ); + +// Queue a packet to the device. The application +// must call tuh_midi_stream_flush to actually have the +// data go out. It is up to the application to properly +// format this packet; this function does not check. +// Returns true if the packet was successfully queued. +bool tuh_midi_packet_write (uint8_t dev_addr, uint8_t const packet[4]); + +// Queue a message to the device. The application +// must call tuh_midi_stream_flush to actually have the +// data go out. +uint32_t tuh_midi_stream_write (uint8_t dev_addr, uint8_t cable_num, uint8_t const* p_buffer, uint32_t bufsize); + +// Send any queued packets to the device if the host hardware is able to do it +// Returns the number of bytes flushed to the host hardware or 0 if +// the host hardware is busy or there is nothing in queue to send. +uint32_t tuh_midi_stream_flush( uint8_t dev_addr); + +// Get the MIDI stream from the device. Set the value pointed +// to by p_cable_num to the MIDI cable number intended to receive it. +// The MIDI stream will be stored in the buffer pointed to by p_buffer. +// Return the number of bytes added to the buffer. +// Note that this function ignores the CIN field of the MIDI packet +// because a number of commercial devices out there do not encode +// it properly. +uint32_t tuh_midi_stream_read (uint8_t dev_addr, uint8_t *p_cable_num, uint8_t *p_buffer, uint16_t bufsize); + +// Read a raw MIDI packet from the connected device +// This function does not parse the packet format +// Return true if a packet was returned +bool tuh_midi_packet_read (uint8_t dev_addr, uint8_t packet[4]); + +uint8_t tuh_midi_get_num_rx_cables(uint8_t dev_addr); +uint8_t tuh_midi_get_num_tx_cables(uint8_t dev_addr); +#if CFG_MIDI_HOST_DEVSTRINGS +uint8_t tuh_midi_get_rx_cable_istrings(uint8_t dev_addr, uint8_t* istrings, uint8_t max_istrings); +uint8_t tuh_midi_get_tx_cable_istrings(uint8_t dev_addr, uint8_t* istrings, uint8_t max_istrings); +uint8_t tuh_midi_get_all_istrings(uint8_t dev_addr, const uint8_t** istrings); +#endif +//--------------------------------------------------------------------+ +// Internal Class Driver API +//--------------------------------------------------------------------+ +void midih_init (void); +bool midih_open (uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *desc_itf, uint16_t max_len); +bool midih_set_config (uint8_t dev_addr, uint8_t itf_num); +bool midih_xfer_cb (uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes); +void midih_close (uint8_t dev_addr); + +//--------------------------------------------------------------------+ +// Callbacks (Weak is optional) +//--------------------------------------------------------------------+ + +// Invoked when device with MIDI interface is mounted. +// If the MIDI host application requires MIDI IN, it should requst an +// IN transfer here. The device will likely NAK this transfer. How the driver +// handles the NAK is hardware dependent. +TU_ATTR_WEAK void tuh_midi_mount_cb(uint8_t dev_addr, uint8_t in_ep, uint8_t out_ep, uint8_t num_cables_rx, uint16_t num_cables_tx); + +// Invoked when device with MIDI interface is un-mounted +// For now, the instance parameter is always 0 and can be ignored +TU_ATTR_WEAK void tuh_midi_umount_cb(uint8_t dev_addr, uint8_t instance); + +TU_ATTR_WEAK void tuh_midi_rx_cb(uint8_t dev_addr, uint32_t num_packets); +TU_ATTR_WEAK void tuh_midi_tx_cb(uint8_t dev_addr); +#ifdef __cplusplus +} +#endif + +#endif /* _TUSB_MIDI_HOST_H_ */ -- cgit v1.3.1 From 3325e2613d4bc68ac2443445e62520baa4bbe6cb Mon Sep 17 00:00:00 2001 From: rppicomidi Date: Thu, 25 Aug 2022 15:09:27 -0700 Subject: Make USB MIDI device code allow a device with no Audio Control interface --- src/class/midi/midi_device.c | 26 ++++++++++++++++---------- src/device/usbd.c | 10 +++++++++- 2 files changed, 25 insertions(+), 11 deletions(-) (limited to 'src/class') diff --git a/src/class/midi/midi_device.c b/src/class/midi/midi_device.c index de41706e8..c6c99db29 100644 --- a/src/class/midi/midi_device.c +++ b/src/class/midi/midi_device.c @@ -406,19 +406,25 @@ void midid_reset(uint8_t rhport) uint16_t midid_open(uint8_t rhport, tusb_desc_interface_t const * desc_itf, uint16_t max_len) { + uint16_t drv_len = 0; + uint8_t const * p_desc = (uint8_t const *)desc_itf; // 1st Interface is Audio Control v1 - TU_VERIFY(TUSB_CLASS_AUDIO == desc_itf->bInterfaceClass && + if (TUSB_CLASS_AUDIO == desc_itf->bInterfaceClass && AUDIO_SUBCLASS_CONTROL == desc_itf->bInterfaceSubClass && - AUDIO_FUNC_PROTOCOL_CODE_UNDEF == desc_itf->bInterfaceProtocol, 0); - - uint16_t drv_len = tu_desc_len(desc_itf); - uint8_t const * p_desc = tu_desc_next(desc_itf); - - // Skip Class Specific descriptors - while ( TUSB_DESC_CS_INTERFACE == tu_desc_type(p_desc) && drv_len <= max_len ) + AUDIO_FUNC_PROTOCOL_CODE_UNDEF == desc_itf->bInterfaceProtocol) { - drv_len += tu_desc_len(p_desc); - p_desc = tu_desc_next(p_desc); + drv_len = tu_desc_len(desc_itf); + p_desc = tu_desc_next(desc_itf); + // Skip Class Specific 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); + } + } + else + { + TU_LOG1("Warning: MIDI Device has no Audio Control Interface"); } // 2nd Interface is MIDI Streaming diff --git a/src/device/usbd.c b/src/device/usbd.c index c199e647e..1cede1289 100644 --- a/src/device/usbd.c +++ b/src/device/usbd.c @@ -920,7 +920,15 @@ static bool process_set_config(uint8_t rhport, uint8_t cfg_num) #endif #if CFG_TUD_MIDI - if ( driver->open == midid_open ) assoc_itf_count = 2; + if ( driver->open == midid_open ) + { + // If there is a class-compliant Audio Control Class, then 2 interfaces + // Otherwise, only one + if (TUSB_CLASS_AUDIO == desc_itf->bInterfaceClass && + AUDIO_SUBCLASS_CONTROL == desc_itf->bInterfaceSubClass && + AUDIO_FUNC_PROTOCOL_CODE_UNDEF == desc_itf->bInterfaceProtocol) + assoc_itf_count = 2; + } #endif #if CFG_TUD_BTH && CFG_TUD_BTH_ISO_ALT_COUNT -- cgit v1.3.1 From 4fbf99621d5a5b8b5de698a792578a2066c667f3 Mon Sep 17 00:00:00 2001 From: atok Date: Thu, 8 Sep 2022 17:51:01 +0200 Subject: Get rid of implicit uint conversions --- src/class/midi/midi_host.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/class') diff --git a/src/class/midi/midi_host.c b/src/class/midi/midi_host.c index e482f5265..a6ad1303a 100644 --- a/src/class/midi/midi_host.c +++ b/src/class/midi/midi_host.c @@ -100,7 +100,7 @@ typedef struct #define MAX_OUT_JACKS 8 struct { uint8_t jack_id; - int8_t jack_type; + uint8_t jack_type; uint8_t string_index; } in_jack_info[MAX_IN_JACKS]; uint8_t next_in_jack; -- cgit v1.3.1 From 19563b441463aed9b3d622f2d57d61082199fbdd Mon Sep 17 00:00:00 2001 From: atok Date: Thu, 8 Sep 2022 21:13:55 +0200 Subject: Simple MIDI rx example --- examples/host/CMakeLists.txt | 1 + examples/host/midi_rx/CMakeLists.txt | 27 ++++++ examples/host/midi_rx/only.txt | 1 + examples/host/midi_rx/src/main.c | 152 ++++++++++++++++++++++++++++++++ examples/host/midi_rx/src/tusb_config.h | 96 ++++++++++++++++++++ src/class/midi/midi_host.c | 4 +- 6 files changed, 279 insertions(+), 2 deletions(-) create mode 100644 examples/host/midi_rx/CMakeLists.txt create mode 100644 examples/host/midi_rx/only.txt create mode 100644 examples/host/midi_rx/src/main.c create mode 100644 examples/host/midi_rx/src/tusb_config.h (limited to 'src/class') diff --git a/examples/host/CMakeLists.txt b/examples/host/CMakeLists.txt index 5c63ec0c0..39a41c4ae 100644 --- a/examples/host/CMakeLists.txt +++ b/examples/host/CMakeLists.txt @@ -8,3 +8,4 @@ family_initialize_project(tinyusb_host_examples ${CMAKE_CURRENT_LIST_DIR}) # family_add_subdirectory will filter what to actually add based on selected FAMILY family_add_subdirectory(cdc_msc_hid) family_add_subdirectory(hid_controller) +family_add_subdirectory(midi_rx) \ No newline at end of file diff --git a/examples/host/midi_rx/CMakeLists.txt b/examples/host/midi_rx/CMakeLists.txt new file mode 100644 index 000000000..4856e0a47 --- /dev/null +++ b/examples/host/midi_rx/CMakeLists.txt @@ -0,0 +1,27 @@ +cmake_minimum_required(VERSION 3.5) + +include(${CMAKE_CURRENT_SOURCE_DIR}/../../../hw/bsp/family_support.cmake) + +# gets PROJECT name for the example (e.g. -) +family_get_project_name(PROJECT ${CMAKE_CURRENT_LIST_DIR}) + +project(${PROJECT}) + +# Checks this example is valid for the family and initializes the project +family_initialize_project(${PROJECT} ${CMAKE_CURRENT_LIST_DIR}) + +add_executable(${PROJECT}) + +# Example source +target_sources(${PROJECT} PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR}/src/main.c + ) + +# Example include +target_include_directories(${PROJECT} PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR}/src + ) + +# Configure compilation flags and libraries for the example... see the corresponding function +# in hw/bsp/FAMILY/family.cmake for details. +family_configure_host_example(${PROJECT}) \ No newline at end of file diff --git a/examples/host/midi_rx/only.txt b/examples/host/midi_rx/only.txt new file mode 100644 index 000000000..2ba4438fd --- /dev/null +++ b/examples/host/midi_rx/only.txt @@ -0,0 +1 @@ +mcu:RP2040 diff --git a/examples/host/midi_rx/src/main.c b/examples/host/midi_rx/src/main.c new file mode 100644 index 000000000..64428932f --- /dev/null +++ b/examples/host/midi_rx/src/main.c @@ -0,0 +1,152 @@ +/* + * The MIT License (MIT) + * + * 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 + * 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. + * + */ + +#include +#include +#include + +#include "bsp/board.h" +#include "tusb.h" +#include "class/midi/midi_host.h" + + +#if CFG_TUH_MIDI + +//--------------------------------------------------------------------+ +// STATIC GLOBALS DECLARATION +//--------------------------------------------------------------------+ +static uint8_t midi_dev_addr = 0; + +//--------------------------------------------------------------------+ +// MACRO CONSTANT TYPEDEF PROTYPES +//--------------------------------------------------------------------+ +void led_blinking_task(void); +void midi_host_rx_task(void); + +/*------------- MAIN -------------*/ +int main(void) +{ + board_init(); + + printf("TinyUSB Host MIDI Example\r\n"); + + tusb_init(); + + while (1) + { + tuh_task(); + led_blinking_task(); + midi_host_rx_task(); + } + + return 0; +} + +#endif + +//--------------------------------------------------------------------+ +// Blinking Task +//--------------------------------------------------------------------+ +void led_blinking_task(void) +{ + const uint32_t interval_ms = 1000; + static uint32_t start_ms = 0; + + static bool led_state = false; + + // Blink every interval ms + if ( board_millis() - start_ms < interval_ms) return; // not enough time + start_ms += interval_ms; + + board_led_write(led_state); + led_state = 1 - led_state; // toggle +} + +//--------------------------------------------------------------------+ +// MIDI host receive task +//--------------------------------------------------------------------+ +void midi_host_rx_task(void) +{ + // device must be attached and have at least one endpoint ready to receive a message + if (!midi_dev_addr || !tuh_midi_configured(midi_dev_addr)) + { + return; + } + if (tuh_midih_get_num_rx_cables(midi_dev_addr) < 1) + { + return; + } + tuh_midi_read_poll(midi_dev_addr); +} + +//--------------------------------------------------------------------+ +// TinyUSB Callbacks +//--------------------------------------------------------------------+ + +// Invoked when device with hid interface is mounted +// Report descriptor is also available for use. tuh_hid_parse_report_descriptor() +// can be used to parse common/simple enough descriptor. +// Note: if report descriptor length > CFG_TUH_ENUMERATION_BUFSIZE, it will be skipped +// therefore report_desc = NULL, desc_len = 0 +void tuh_midi_mount_cb(uint8_t dev_addr, uint8_t in_ep, uint8_t out_ep, uint8_t num_cables_rx, uint16_t num_cables_tx) +{ + TU_LOG1("MIDI device address = %u, IN endpoint %u has %u cables, OUT endpoint %u has %u cables\r\n", + dev_addr, in_ep & 0xf, num_cables_rx, out_ep & 0xf, num_cables_tx); + + midi_dev_addr = dev_addr; +} + +// Invoked when device with hid interface is un-mounted +void tuh_midi_umount_cb(uint8_t dev_addr, uint8_t instance) +{ + TU_LOG1("MIDI device address = %d, instance = %d is unmounted\r\n", dev_addr, instance); + + midi_dev_addr = 0; +} + +void tuh_midi_rx_cb(uint8_t dev_addr, uint32_t num_packets) +{ + if (midi_dev_addr != dev_addr) + { + return; + } + + if(num_packets == 0) + { + return; + } + + uint8_t cable_num; + uint8_t buffer[48]; + uint32_t bytes_read = tuh_midi_stream_read(dev_addr, &cable_num, buffer, sizeof(buffer)); + + TU_LOG1("Read bytes %u cable %u", bytes_read, cable_num); + TU_LOG1_MEM(buffer, bytes_read, 2); +} + +void tuh_midi_tx_cb(uint8_t dev_addr) +{ + (void ) dev_addr; +} \ No newline at end of file diff --git a/examples/host/midi_rx/src/tusb_config.h b/examples/host/midi_rx/src/tusb_config.h new file mode 100644 index 000000000..5cc354ea9 --- /dev/null +++ b/examples/host/midi_rx/src/tusb_config.h @@ -0,0 +1,96 @@ +/* + * The MIT License (MIT) + * + * 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 + * 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. + * + */ + +#ifndef _TUSB_CONFIG_H_ +#define _TUSB_CONFIG_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +//-------------------------------------------------------------------- +// COMMON CONFIGURATION +//-------------------------------------------------------------------- + +// defined by compiler flags for flexibility +#ifndef CFG_TUSB_MCU +#error CFG_TUSB_MCU must be defined +#endif + +#if CFG_TUSB_MCU == OPT_MCU_LPC43XX || CFG_TUSB_MCU == OPT_MCU_LPC18XX || CFG_TUSB_MCU == OPT_MCU_MIMXRT10XX +#define CFG_TUSB_RHPORT0_MODE (OPT_MODE_HOST | OPT_MODE_HIGH_SPEED) +#else +#define CFG_TUSB_RHPORT0_MODE OPT_MODE_HOST +#endif + +#ifndef CFG_TUSB_OS +#define CFG_TUSB_OS OPT_OS_NONE +#endif + +// CFG_TUSB_DEBUG is defined by compiler in DEBUG build +// #define CFG_TUSB_DEBUG 0 + +/* USB DMA on some MCUs can only access a specific SRAM region with restriction on alignment. + * Tinyusb use follows macros to declare transferring memory so that they can be put + * into those specific section. + * e.g + * - CFG_TUSB_MEM SECTION : __attribute__ (( section(".usb_ram") )) + * - CFG_TUSB_MEM_ALIGN : __attribute__ ((aligned(4))) + */ +#ifndef CFG_TUSB_MEM_SECTION +#define CFG_TUSB_MEM_SECTION +#endif + +#ifndef CFG_TUSB_MEM_ALIGN +#define CFG_TUSB_MEM_ALIGN __attribute__ ((aligned(4))) +#endif + +//-------------------------------------------------------------------- +// CONFIGURATION +//-------------------------------------------------------------------- + +// Size of buffer to hold descriptors and other data used for enumeration +#define CFG_TUH_ENUMERATION_BUFSIZE 256 + +#define CFG_TUH_HUB 1 +#define CFG_TUH_CDC 0 +#define CFG_TUH_HID 0 // typical keyboard + mouse device can have 3-4 HID interfaces +#define CFG_TUH_MIDI 1 // there will be at most one MIDIStreaming Interface descriptor +#define CFG_TUH_MSC 0 +#define CFG_TUH_VENDOR 0 + +// max device support (excluding hub device) +#define CFG_TUH_DEVICE_MAX (CFG_TUH_HUB ? 4 : 1) // hub typically has 4 ports +#define CFG_MIDI_HOST_DEVSTRINGS 1 + +//------------- HID -------------// +#define CFG_TUH_HID_EPIN_BUFSIZE 64 +#define CFG_TUH_HID_EPOUT_BUFSIZE 64 + +#ifdef __cplusplus +} +#endif + +#endif /* _TUSB_CONFIG_H_ */ diff --git a/src/class/midi/midi_host.c b/src/class/midi/midi_host.c index a6ad1303a..aafa340cd 100644 --- a/src/class/midi/midi_host.c +++ b/src/class/midi/midi_host.c @@ -333,10 +333,10 @@ bool midih_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *d p_midi_host->out_jack_info[p_midi_host->next_out_jack].jack_id = p_mdoj->bJackID; p_midi_host->out_jack_info[p_midi_host->next_out_jack].jack_type = p_mdoj->bJackType; p_midi_host->out_jack_info[p_midi_host->next_out_jack].num_source_ids = p_mdoj->bNrInputPins; - struct associated_jack_s { + const struct associated_jack_s { uint8_t id; uint8_t pin; - } *associated_jack = (struct associated_jack_s *)(p_desc+6); + } *associated_jack = (const struct associated_jack_s *)(p_desc+6); int jack; for (jack = 0; jack < p_mdoj->bNrInputPins; jack++) { -- cgit v1.3.1 From a6d4b64beccc586d1bfb6e4c171d560762221645 Mon Sep 17 00:00:00 2001 From: atok Date: Sun, 2 Oct 2022 09:53:37 +0200 Subject: Removed unused function prototype --- src/class/midi/midi_host.h | 1 - 1 file changed, 1 deletion(-) (limited to 'src/class') diff --git a/src/class/midi/midi_host.h b/src/class/midi/midi_host.h index fc661939a..8180e3309 100644 --- a/src/class/midi/midi_host.h +++ b/src/class/midi/midi_host.h @@ -52,7 +52,6 @@ // Application API (Single Interface) //--------------------------------------------------------------------+ bool tuh_midi_configured (uint8_t dev_addr); -uint32_t tuh_midi_available (uint8_t dev_addr); // return the number of virtual midi cables on the device's OUT endpoint uint8_t tuh_midih_get_num_tx_cables (uint8_t dev_addr); -- cgit v1.3.1 From 21e003af2234b3211fb9b4da42202c79949e4caa Mon Sep 17 00:00:00 2001 From: atoktoto Date: Sun, 13 Nov 2022 14:38:33 +0100 Subject: Added explicit conversions --- src/class/midi/midi_host.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src/class') diff --git a/src/class/midi/midi_host.c b/src/class/midi/midi_host.c index aafa340cd..d242d33c5 100644 --- a/src/class/midi/midi_host.c +++ b/src/class/midi/midi_host.c @@ -592,13 +592,13 @@ uint32_t tuh_midi_stream_write (uint8_t dev_addr, uint8_t cable_num, uint8_t con else if ( (msg >= 0x8 && msg <= 0xB) || msg == 0xE ) { // Channel Voice Messages - stream->buffer[0] = (cable_num << 4) | msg; + stream->buffer[0] = (uint8_t) ((cable_num << 4) | msg); stream->total = 4; } else if ( msg == 0xC || msg == 0xD) { // Channel Voice Messages, two-byte variants (Program Change and Channel Pressure) - stream->buffer[0] = (cable_num << 4) | msg; + stream->buffer[0] = (uint8_t) ((cable_num << 4) | msg); stream->total = 3; } else if ( msg == 0xf ) @@ -628,7 +628,7 @@ uint32_t tuh_midi_stream_write (uint8_t dev_addr, uint8_t cable_num, uint8_t con else { // Pack individual bytes if we don't support packing them into words. - stream->buffer[0] = cable_num << 4 | 0xf; + stream->buffer[0] = (uint8_t) (cable_num << 4 | 0xf); stream->buffer[2] = 0; stream->buffer[3] = 0; stream->index = 2; @@ -748,7 +748,7 @@ uint32_t tuh_midi_stream_read (uint8_t dev_addr, uint8_t *p_cable_num, uint8_t * { // ignore the CIN field; too many devices out there encode this wrong uint8_t status = p_midi_host->stream_read.buffer[1]; - uint16_t cable_mask = 1 << *p_cable_num; + uint16_t cable_mask = (uint16_t) (1 << *p_cable_num); if (status <= MIDI_MAX_DATA_VAL || status == MIDI_STATUS_SYSEX_START) { if (status == MIDI_STATUS_SYSEX_START) -- cgit v1.3.1 From 0a844f2a3019df04a346232b0e54a9fc89e4c551 Mon Sep 17 00:00:00 2001 From: atoktoto Date: Sat, 19 Nov 2022 18:08:31 +0100 Subject: Fix usb hubs --- src/class/midi/midi_host.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/class') diff --git a/src/class/midi/midi_host.c b/src/class/midi/midi_host.c index d242d33c5..bc87898cc 100644 --- a/src/class/midi/midi_host.c +++ b/src/class/midi/midi_host.c @@ -490,7 +490,7 @@ bool midih_set_config(uint8_t dev_addr, uint8_t itf_num) p_midi_host->configured = true; // TODO I don't think there are any special config things to do for MIDI - + usbh_driver_set_config_complete(dev_addr, p_midi_host->itf_num); return true; } -- cgit v1.3.1 From 34729b1dc46ef9cee3446e22c88e8484395f1fa7 Mon Sep 17 00:00:00 2001 From: atoktoto Date: Mon, 21 Nov 2022 10:29:26 +0100 Subject: Fix usb-hub data transfer problems by AndrewCapon --- src/class/midi/midi_host.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/class') diff --git a/src/class/midi/midi_host.c b/src/class/midi/midi_host.c index bc87898cc..8df1b2005 100644 --- a/src/class/midi/midi_host.c +++ b/src/class/midi/midi_host.c @@ -529,7 +529,7 @@ bool tuh_midi_read_poll( uint8_t dev_addr ) if (in_edpt_not_busy) { TU_LOG2("Requesting poll IN endpoint %d\r\n", p_midi_host->ep_in); - TU_ASSERT(usbh_edpt_xfer(p_midi_host->dev_addr, p_midi_host->ep_in, _midi_host->epin_buf, _midi_host->ep_in_max), 0); + TU_ASSERT(usbh_edpt_xfer(p_midi_host->dev_addr, p_midi_host->ep_in, p_midi_host->epin_buf, p_midi_host->ep_in_max), 0); result = true; } else -- cgit v1.3.1 From 3ba03110782747dead880f334f4fd65c03cbca9d Mon Sep 17 00:00:00 2001 From: atoktoto Date: Mon, 21 Nov 2022 12:36:50 +0100 Subject: Explicit type conversion --- src/class/midi/midi_host.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/class') diff --git a/src/class/midi/midi_host.c b/src/class/midi/midi_host.c index 8df1b2005..308120ea2 100644 --- a/src/class/midi/midi_host.c +++ b/src/class/midi/midi_host.c @@ -769,7 +769,7 @@ uint32_t tuh_midi_stream_read (uint8_t dev_addr, uint8_t *p_cable_num, uint8_t * else if (p_midi_host->stream_read.buffer[idx] == MIDI_STATUS_SYSEX_END) { ++bytes_to_add_to_stream; - cable_sysex_in_progress &= ~cable_mask; + cable_sysex_in_progress &= (uint16_t) ~cable_mask; idx = 4; // force the loop to exit; I hate break statements in loops } } -- cgit v1.3.1 From 89eac75085134d570dc26dffaf3d8f204aef5359 Mon Sep 17 00:00:00 2001 From: atoktoto Date: Mon, 21 Nov 2022 13:49:43 +0100 Subject: Explicit type conversion --- src/class/midi/midi_host.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/class') diff --git a/src/class/midi/midi_host.c b/src/class/midi/midi_host.c index 308120ea2..32311556e 100644 --- a/src/class/midi/midi_host.c +++ b/src/class/midi/midi_host.c @@ -795,7 +795,7 @@ uint32_t tuh_midi_stream_read (uint8_t dev_addr, uint8_t *p_cable_num, uint8_t * default: break; // Should not get this } - cable_sysex_in_progress &= ~cable_mask; + cable_sysex_in_progress &= (uint16_t)~cable_mask; } else if (status < MIDI_STATUS_SYSREAL_TIMING_CLOCK) { @@ -814,7 +814,7 @@ uint32_t tuh_midi_stream_read (uint8_t dev_addr, uint8_t *p_cable_num, uint8_t * break; default: break; - cable_sysex_in_progress &= ~cable_mask; + cable_sysex_in_progress &= (uint16_t)~cable_mask; } } else -- cgit v1.3.1 From 069c68ad04bd6210fc50dbc2aeb2c62448c1731d Mon Sep 17 00:00:00 2001 From: IngHK Date: Fri, 23 Feb 2024 23:27:38 +0100 Subject: sorted driver functions into Control Request, Driver API, Enumeration and Helper. no functional changes --- src/class/cdc/cdc_host.c | 359 +++++++++++++++++++++++++---------------------- 1 file changed, 189 insertions(+), 170 deletions(-) (limited to 'src/class') diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index 2fb37d835..26eb70c9b 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -782,92 +782,7 @@ bool cdch_set_config(uint8_t daddr, uint8_t itf_num) { // ACM //--------------------------------------------------------------------+ -enum { - CONFIG_ACM_SET_CONTROL_LINE_STATE = 0, - CONFIG_ACM_SET_LINE_CODING, - 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; - - 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); - - // 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)) { - // save ACM 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) { - TU_ASSERT(TUSB_DESC_ENDPOINT == tu_desc_type(p_desc)); - tusb_desc_endpoint_t const* desc_ep = (tusb_desc_endpoint_t const*) p_desc; - - 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)) { - // 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)); - } - - return true; -} - -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,); - - 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),); - break; - } - #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) { - 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),); - break; - } - #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); - break; - - default: - break; - } -} +//------------- Driver API -------------// 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) { TU_VERIFY(p_cdc->acm_capability.support_line_request); @@ -953,37 +868,104 @@ static bool acm_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfe return acm_set_line_coding(p_cdc, &line_coding, complete_cb, user_data); } -//--------------------------------------------------------------------+ -// FTDI -//--------------------------------------------------------------------+ -#if CFG_TUH_CDC_FTDI +//------------- Enumeration -------------// enum { - CONFIG_FTDI_RESET = 0, - CONFIG_FTDI_MODEM_CTRL, - CONFIG_FTDI_SET_BAUDRATE, - CONFIG_FTDI_SET_DATA, - CONFIG_FTDI_COMPLETE + CONFIG_ACM_SET_CONTROL_LINE_STATE = 0, + CONFIG_ACM_SET_LINE_CODING, + CONFIG_ACM_COMPLETE, }; -static bool ftdi_open(uint8_t daddr, const tusb_desc_interface_t *itf_desc, uint16_t max_len) { - // FTDI Interface includes 1 vendor interface + 2 bulk endpoints - TU_VERIFY(itf_desc->bInterfaceSubClass == 0xff && itf_desc->bInterfaceProtocol == 0xff && itf_desc->bNumEndpoints == 2); - TU_VERIFY(sizeof(tusb_desc_interface_t) + 2*sizeof(tusb_desc_endpoint_t) <= 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; - TU_LOG_DRV("FTDI opened\r\n"); - p_cdc->serial_drid = SERIAL_DRIVER_FTDI; + //------------- Control Interface -------------// + uint8_t const* p_desc = tu_desc_next(itf_desc); - // endpoint pair - tusb_desc_endpoint_t const * desc_ep = (tusb_desc_endpoint_t const *) 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)) { + // save ACM bmCapabilities + p_cdc->acm_capability = ((cdc_desc_func_acm_t const*) p_desc)->bmCapabilities; + } - // data endpoints expected to be in pairs - return open_ep_stream_pair(p_cdc, desc_ep); + p_desc = tu_desc_next(p_desc); + } + + // Open notification endpoint of control interface if any + 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; + + 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)) { + // 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)); + } + + return true; } +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,); + + 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),); + break; + } + #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) { + 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),); + break; + } + #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); + break; + + default: + break; + } +} + +//--------------------------------------------------------------------+ +// FTDI +//--------------------------------------------------------------------+ +#if CFG_TUH_CDC_FTDI + +static uint32_t ftdi_232bm_baud_to_divisor(uint32_t baud); + +//------------- Control Request -------------// + // set request without data static bool ftdi_sio_set_request(cdch_interface_t* p_cdc, uint8_t command, uint16_t value, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { tusb_control_request_t const request = { @@ -1014,6 +996,20 @@ 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); } +//------------- Driver API -------------// + +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); + + p_cdc->user_control_cb = complete_cb; + 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)); + + return true; +} + 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; @@ -1043,40 +1039,32 @@ 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) { - const uint8_t divfrac[8] = { 0, 3, 2, 4, 1, 5, 6, 7 }; - uint32_t divisor; - - /* divisor shifted 3 bits to the left */ - uint32_t divisor3 = base / (2 * baud); - divisor = (divisor3 >> 3); - divisor |= (uint32_t) divfrac[divisor3 & 0x7] << 14; +//------------- Enumeration -------------// - /* Deal with special cases for highest baud rates. */ - if (divisor == 1) { /* 1.0 */ - divisor = 0; - } - else if (divisor == 0x4001) { /* 1.5 */ - divisor = 1; - } +enum { + CONFIG_FTDI_RESET = 0, + CONFIG_FTDI_MODEM_CTRL, + CONFIG_FTDI_SET_BAUDRATE, + CONFIG_FTDI_SET_DATA, + CONFIG_FTDI_COMPLETE +}; - return divisor; -} +static bool ftdi_open(uint8_t daddr, const tusb_desc_interface_t *itf_desc, uint16_t max_len) { + // FTDI Interface includes 1 vendor interface + 2 bulk endpoints + TU_VERIFY(itf_desc->bInterfaceSubClass == 0xff && itf_desc->bInterfaceProtocol == 0xff && itf_desc->bNumEndpoints == 2); + TU_VERIFY(sizeof(tusb_desc_interface_t) + 2*sizeof(tusb_desc_endpoint_t) <= max_len); -static uint32_t ftdi_232bm_baud_to_divisor(uint32_t baud) { - return ftdi_232bm_baud_base_to_divisor(baud, 48000000u); -} + cdch_interface_t * p_cdc = make_new_itf(daddr, itf_desc); + TU_VERIFY(p_cdc); -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("FTDI opened\r\n"); + p_cdc->serial_drid = SERIAL_DRIVER_FTDI; - p_cdc->user_control_cb = complete_cb; - 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)); + // endpoint pair + tusb_desc_endpoint_t const * desc_ep = (tusb_desc_endpoint_t const *) tu_desc_next(itf_desc); - return true; + // data endpoints expected to be in pairs + return open_ep_stream_pair(p_cdc, desc_ep); } static void ftdi_process_config(tuh_xfer_t* xfer) { @@ -1131,39 +1119,40 @@ static void ftdi_process_config(tuh_xfer_t* xfer) { } } -#endif +//------------- Helper -------------// -//--------------------------------------------------------------------+ -// CP210x -//--------------------------------------------------------------------+ +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; -#if CFG_TUH_CDC_CP210X + /* divisor shifted 3 bits to the left */ + uint32_t divisor3 = base / (2 * baud); + divisor = (divisor3 >> 3); + divisor |= (uint32_t) divfrac[divisor3 & 0x7] << 14; -enum { - CONFIG_CP210X_IFC_ENABLE = 0, - CONFIG_CP210X_SET_BAUDRATE, - CONFIG_CP210X_SET_LINE_CTL, - CONFIG_CP210X_SET_DTR_RTS, - CONFIG_CP210X_COMPLETE -}; + /* Deal with special cases for highest baud rates. */ + if (divisor == 1) { /* 1.0 */ + divisor = 0; + } + else if (divisor == 0x4001) { /* 1.5 */ + divisor = 1; + } -static bool cp210x_open(uint8_t daddr, tusb_desc_interface_t const *itf_desc, uint16_t max_len) { - // CP210x Interface includes 1 vendor interface + 2 bulk endpoints - TU_VERIFY(itf_desc->bInterfaceSubClass == 0 && itf_desc->bInterfaceProtocol == 0 && itf_desc->bNumEndpoints == 2); - TU_VERIFY(sizeof(tusb_desc_interface_t) + 2*sizeof(tusb_desc_endpoint_t) <= max_len); + return divisor; +} - cdch_interface_t * p_cdc = make_new_itf(daddr, itf_desc); - TU_VERIFY(p_cdc); +static uint32_t ftdi_232bm_baud_to_divisor(uint32_t baud) { + return ftdi_232bm_baud_base_to_divisor(baud, 48000000u); +} - TU_LOG_DRV("CP210x opened\r\n"); - p_cdc->serial_drid = SERIAL_DRIVER_CP210X; +#endif - // endpoint pair - tusb_desc_endpoint_t const * desc_ep = (tusb_desc_endpoint_t const *) tu_desc_next(itf_desc); +//--------------------------------------------------------------------+ +// CP210x +//--------------------------------------------------------------------+ +#if CFG_TUH_CDC_CP210X - // data endpoints expected to be in pairs - return open_ep_stream_pair(p_cdc, desc_ep); -} +//------------- Control Request -------------// static bool cp210x_set_request(cdch_interface_t* p_cdc, uint8_t command, uint16_t value, uint8_t* buffer, uint16_t length, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { tusb_control_request_t const request = { @@ -1202,14 +1191,7 @@ 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) { - // TODO implement later - (void) p_cdc; - (void) line_coding; - (void) complete_cb; - (void) user_data; - return false; -} +//------------- Driver API -------------// 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); @@ -1231,6 +1213,15 @@ static bool cp210x_set_data_format(cdch_interface_t* p_cdc, uint8_t stop_bits, u return false; } +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) { + // TODO implement later + (void) p_cdc; + (void) line_coding; + (void) complete_cb; + (void) user_data; + 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; @@ -1238,6 +1229,34 @@ static bool cp210x_set_modem_ctrl(cdch_interface_t* p_cdc, uint16_t line_state, complete_cb ? cdch_internal_control_complete : NULL, user_data); } +//------------- Enumeration -------------// + +enum { + CONFIG_CP210X_IFC_ENABLE = 0, + CONFIG_CP210X_SET_BAUDRATE, + CONFIG_CP210X_SET_LINE_CTL, + CONFIG_CP210X_SET_DTR_RTS, + CONFIG_CP210X_COMPLETE +}; + +static bool cp210x_open(uint8_t daddr, tusb_desc_interface_t const *itf_desc, uint16_t max_len) { + // CP210x Interface includes 1 vendor interface + 2 bulk endpoints + TU_VERIFY(itf_desc->bInterfaceSubClass == 0 && itf_desc->bInterfaceProtocol == 0 && itf_desc->bNumEndpoints == 2); + 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("CP210x opened\r\n"); + p_cdc->serial_drid = SERIAL_DRIVER_CP210X; + + // 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 void cp210x_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); @@ -1296,7 +1315,7 @@ 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 request -------------// +//------------- 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) { @@ -1471,6 +1490,7 @@ static bool ch34x_set_modem_ctrl(cdch_interface_t* p_cdc, uint16_t line_state, } //------------- Enumeration -------------// + enum { CONFIG_CH34X_READ_VERSION = 0, CONFIG_CH34X_SERIAL_INIT, @@ -1565,7 +1585,7 @@ static void ch34x_process_config(tuh_xfer_t* xfer) { } } -//------------- CH34x helper -------------// +//------------- Helper -------------// // calculate divisor and prescaler for baudrate, return it as 16-bit combined value static uint16_t ch34x_get_divisor_prescaler(uint32_t baval) { @@ -1654,7 +1674,6 @@ static uint8_t ch34x_get_lcr(uint8_t stop_bits, uint8_t parity, uint8_t data_bit return lcr; } - #endif // CFG_TUH_CDC_CH34X #endif -- cgit v1.3.1 From 47777a63050f9438d79364436c25d0f6a80dfd55 Mon Sep 17 00:00:00 2001 From: IngHK Date: Tue, 20 Feb 2024 22:08:51 +0100 Subject: improved TU_LOGs --- src/class/cdc/cdc_host.c | 86 +++++++++++++++++++++++++++++++----------------- 1 file changed, 55 insertions(+), 31 deletions(-) (limited to 'src/class') diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index 26eb70c9b..856db32ff 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -41,7 +41,11 @@ #define CFG_TUH_CDC_LOG_LEVEL CFG_TUH_LOG_LEVEL #endif -#define TU_LOG_DRV(...) TU_LOG(CFG_TUH_CDC_LOG_LEVEL, __VA_ARGS__) +#define TU_LOG_DRV(...) TU_LOG(CFG_TUH_CDC_LOG_LEVEL, __VA_ARGS__) +#define TU_LOG_CDC(TXT,DADDR,ITF_NUM,NAME,...) TU_LOG_DRV("[:%u:%u] CDCh %s " TXT "\r\n", \ + DADDR, ITF_NUM, NAME, ##__VA_ARGS__) +#define TU_LOG_P_CDC(TXT,...) TU_LOG_CDC(TXT, p_cdc->daddr, p_cdc->bInterfaceNumber, \ + serial_drivers[p_cdc->serial_drid].name, ##__VA_ARGS__) //--------------------------------------------------------------------+ // Host CDC Interface @@ -169,6 +173,9 @@ typedef struct { 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); + #if CFG_TUSB_DEBUG && CFG_TUSB_DEBUG >= CFG_TUH_CDC_LOG_LEVEL + uint8_t const * name; + #endif } cdch_serial_driver_t; // Note driver list must be in the same order as SERIAL_DRIVER enum @@ -181,7 +188,10 @@ static const cdch_serial_driver_t serial_drivers[] = { .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 + .set_line_coding = acm_set_line_coding, + #if CFG_TUSB_DEBUG && CFG_TUSB_DEBUG >= CFG_TUH_CDC_LOG_LEVEL + .name = (uint8_t const *) "ACM" + #endif }, #if CFG_TUH_CDC_FTDI @@ -193,7 +203,10 @@ static const cdch_serial_driver_t serial_drivers[] = { .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 + .set_line_coding = ftdi_set_line_coding, + #if CFG_TUSB_DEBUG && CFG_TUSB_DEBUG >= CFG_TUH_CDC_LOG_LEVEL + .name = (uint8_t const *) "FTDI" + #endif }, #endif @@ -206,7 +219,10 @@ static const cdch_serial_driver_t serial_drivers[] = { .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 + .set_line_coding = cp210x_set_line_coding, + #if CFG_TUSB_DEBUG && CFG_TUSB_DEBUG >= CFG_TUH_CDC_LOG_LEVEL + .name = (uint8_t const *) "CP210x" + #endif }, #endif @@ -219,7 +235,10 @@ static const cdch_serial_driver_t serial_drivers[] = { .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 + .set_line_coding = ch34x_set_line_coding, + #if CFG_TUSB_DEBUG && CFG_TUSB_DEBUG >= CFG_TUH_CDC_LOG_LEVEL + .name = (uint8_t const *) "CH34x" + #endif }, #endif }; @@ -408,8 +427,10 @@ static void process_internal_control_complete(tuh_xfer_t* xfer, uint8_t itf_num) cdch_interface_t* p_cdc = get_itf(idx); TU_ASSERT(p_cdc, ); uint16_t const value = tu_le16toh(xfer->setup->wValue); + bool const success = (xfer->result == XFER_RESULT_SUCCESS); + TU_LOG_P_CDC("control complete success = %u", success); - if (xfer->result == XFER_RESULT_SUCCESS) { + if (success) { switch (p_cdc->serial_drid) { case SERIAL_DRIVER_ACM: switch (xfer->setup->bRequest) { @@ -525,6 +546,7 @@ static void cdch_internal_control_complete(tuh_xfer_t* 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); + TU_LOG_P_CDC("set control line state line_state = %u", line_state); cdch_serial_driver_t const* driver = &serial_drivers[p_cdc->serial_drid]; if (complete_cb) { @@ -548,6 +570,7 @@ bool tuh_cdc_set_control_line_state(uint8_t idx, uint16_t line_state, tuh_xfer_c bool tuh_cdc_set_baudrate(uint8_t idx, uint32_t baudrate, 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); + TU_LOG_P_CDC("set baudrate = %lu", baudrate); cdch_serial_driver_t const* driver = &serial_drivers[p_cdc->serial_drid]; if (complete_cb) { @@ -572,6 +595,8 @@ bool tuh_cdc_set_data_format(uint8_t idx, uint8_t stop_bits, uint8_t parity, uin 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); + TU_LOG_P_CDC("set data format data_bits = %u parity = %u stop_bits = %u (indexes!)", + data_bits, parity, stop_bits); cdch_serial_driver_t const* driver = &serial_drivers[p_cdc->serial_drid]; if (complete_cb) { @@ -597,6 +622,8 @@ bool tuh_cdc_set_data_format(uint8_t idx, uint8_t stop_bits, uint8_t parity, uin 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); + TU_LOG_P_CDC("set line coding baudrate = %lu data_bits = %u parity = %u stop_bits = %u (indexes!)", + line_coding->bit_rate, line_coding->data_bits, line_coding->parity, line_coding->stop_bits); cdch_serial_driver_t const* driver = &serial_drivers[p_cdc->serial_drid]; if ( complete_cb ) { @@ -641,7 +668,7 @@ void cdch_close(uint8_t daddr) { for (uint8_t idx = 0; idx < CFG_TUH_CDC; idx++) { cdch_interface_t* p_cdc = &cdch_data[idx]; if (p_cdc->daddr == daddr) { - TU_LOG_DRV(" CDCh close addr = %u index = %u\r\n", daddr, idx); + TU_LOG_P_CDC("close"); // Invoke application callback if (tuh_cdc_umount_cb) tuh_cdc_umount_cb(idx); @@ -722,33 +749,42 @@ static bool open_ep_stream_pair(cdch_interface_t* p_cdc, tusb_desc_endpoint_t co bool cdch_open(uint8_t rhport, uint8_t daddr, tusb_desc_interface_t const *itf_desc, uint16_t max_len) { (void) rhport; + cdch_serial_driver_t const * driver_detected = NULL; // 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) { - return acm_open(daddr, itf_desc, max_len); - } - else if (SERIAL_DRIVER_COUNT > 1 && - TUSB_CLASS_VENDOR_SPECIFIC == itf_desc->bInterfaceClass) { + driver_detected = &serial_drivers[0]; + } 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)); for (size_t dr = 1; dr < SERIAL_DRIVER_COUNT; dr++) { - cdch_serial_driver_t const* driver = &serial_drivers[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); + driver_detected = driver; + break; } } + if (driver_detected) { + break; + } } } + if (driver_detected) { + TU_LOG_CDC("open", daddr, itf_desc->bInterfaceNumber, driver_detected->name); + bool ret = driver_detected->open(daddr, itf_desc, max_len); + return ret; + } + return false; } 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"); + TU_LOG_P_CDC("set config complete"); p_cdc->mounted = true; if (tuh_cdc_mount_cb) tuh_cdc_mount_cb(idx); @@ -762,6 +798,10 @@ static void set_config_complete(cdch_interface_t * p_cdc, uint8_t idx, uint8_t i bool cdch_set_config(uint8_t daddr, uint8_t itf_num) { tusb_control_request_t request; request.wIndex = tu_htole16((uint16_t) itf_num); + uint8_t const idx = tuh_cdc_itf_get_index(daddr, itf_num); + cdch_interface_t * p_cdc = get_itf(idx); + TU_ASSERT(p_cdc && p_cdc->serial_drid < SERIAL_DRIVER_COUNT); + TU_LOG_P_CDC("set config"); // fake transfer to kick-off process tuh_xfer_t xfer; @@ -770,10 +810,6 @@ bool cdch_set_config(uint8_t daddr, uint8_t itf_num) { xfer.setup = &request; xfer.user_data = 0; // initial state - uint8_t const idx = tuh_cdc_itf_get_index(daddr, itf_num); - cdch_interface_t * p_cdc = get_itf(idx); - TU_ASSERT(p_cdc && p_cdc->serial_drid < SERIAL_DRIVER_COUNT); - serial_drivers[p_cdc->serial_drid].process_set_config(&xfer); return true; } @@ -786,7 +822,6 @@ bool cdch_set_config(uint8_t daddr, uint8_t itf_num) { 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) { TU_VERIFY(p_cdc->acm_capability.support_line_request); - TU_LOG_DRV("CDC ACM Set Control Line State\r\n"); tusb_control_request_t const request = { .bmRequestType_bit = { @@ -816,8 +851,6 @@ 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"); - tusb_control_request_t const request = { .bmRequestType_bit = { .recipient = TUSB_REQ_RCPT_INTERFACE, @@ -850,7 +883,6 @@ static bool acm_set_line_coding(cdch_interface_t* p_cdc, cdc_line_coding_t const 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; @@ -1000,7 +1032,6 @@ static bool ftdi_sio_reset(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, u 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); p_cdc->user_control_cb = complete_cb; p_cdc->requested_line_coding.bit_rate = baudrate; @@ -1032,7 +1063,6 @@ static bool ftdi_set_line_coding(cdch_interface_t* p_cdc, cdc_line_coding_t cons } 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, complete_cb ? cdch_internal_control_complete : NULL, user_data)); @@ -1057,7 +1087,6 @@ static bool ftdi_open(uint8_t daddr, const tusb_desc_interface_t *itf_desc, uint cdch_interface_t * p_cdc = make_new_itf(daddr, itf_desc); TU_VERIFY(p_cdc); - TU_LOG_DRV("FTDI opened\r\n"); p_cdc->serial_drid = SERIAL_DRIVER_FTDI; // endpoint pair @@ -1194,7 +1223,6 @@ static bool cp210x_ifc_enable(cdch_interface_t* p_cdc, uint16_t enabled, tuh_xfe //------------- Driver API -------------// 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); p_cdc->user_control_cb = complete_cb; return cp210x_set_request(p_cdc, CP210X_SET_BAUDRATE, 0, (uint8_t *) &baud_le, 4, @@ -1223,7 +1251,6 @@ static bool cp210x_set_line_coding(cdch_interface_t* p_cdc, cdc_line_coding_t co } 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, complete_cb ? cdch_internal_control_complete : NULL, user_data); @@ -1247,7 +1274,6 @@ static bool cp210x_open(uint8_t daddr, tusb_desc_interface_t const *itf_desc, ui cdch_interface_t * p_cdc = make_new_itf(daddr, itf_desc); TU_VERIFY(p_cdc); - TU_LOG_DRV("CP210x opened\r\n"); p_cdc->serial_drid = SERIAL_DRIVER_CP210X; // endpoint pair @@ -1508,7 +1534,6 @@ static bool ch34x_open(uint8_t daddr, tusb_desc_interface_t const* itf_desc, uin 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); @@ -1538,14 +1563,13 @@ static void ch34x_process_config(tuh_xfer_t* xfer) { switch (state) { case CONFIG_CH34X_READ_VERSION: - 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_SERIAL_INIT),); break; case CONFIG_CH34X_SERIAL_INIT: { // handle version read data, set CH34x line coding (incl. baudrate) uint8_t const version = xfer->buffer[0]; - TU_LOG_DRV("[%u] CDCh CH34x Chip Version = %02x\r\n", p_cdc->daddr, version); + TU_LOG_P_CDC("Chip Version = %02x", 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,); // init CH34x with line coding -- cgit v1.3.1 From 829ea52873387f6fe269c44089c339cfd6d7c64e Mon Sep 17 00:00:00 2001 From: IngHK Date: Thu, 22 Feb 2024 08:56:15 +0100 Subject: splitted cdch_internal_control_complete() into driver's _internal_control_complete() and moved them into driver's sections. no functional change --- src/class/cdc/cdc_host.c | 289 +++++++++++++++++++++++++---------------------- 1 file changed, 154 insertions(+), 135 deletions(-) (limited to 'src/class') diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index 856db32ff..e39122e8f 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -286,7 +286,6 @@ static cdch_interface_t* make_new_itf(uint8_t daddr, tusb_desc_interface_t const static bool open_ep_stream_pair(cdch_interface_t* p_cdc , tusb_desc_endpoint_t const *desc_ep); static void set_config_complete(cdch_interface_t * p_cdc, uint8_t idx, uint8_t itf_num); -static void cdch_internal_control_complete(tuh_xfer_t* xfer); //--------------------------------------------------------------------+ // APPLICATION API @@ -422,127 +421,6 @@ bool tuh_cdc_read_clear (uint8_t idx) { // Control Endpoint API //--------------------------------------------------------------------+ -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); - bool const success = (xfer->result == XFER_RESULT_SUCCESS); - TU_LOG_P_CDC("control complete success = %u", success); - - if (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) 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; - } - break; - - #if CFG_TUH_CDC_FTDI - case SERIAL_DRIVER_FTDI: - switch (xfer->setup->bRequest) { - case FTDI_SIO_MODEM_CTRL: - p_cdc->line_state = (uint8_t) value; - break; - - case FTDI_SIO_SET_BAUD_RATE: - p_cdc->line_coding.bit_rate = p_cdc->requested_line_coding.bit_rate; - break; - - default: break; - } - break; - #endif - - #if CFG_TUH_CDC_CP210X - case SERIAL_DRIVER_CP210X: - switch(xfer->setup->bRequest) { - case CP210X_SET_MHS: - 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: - 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 - - default: break; - } - } - - xfer->complete_cb = p_cdc->user_control_cb; - if (xfer->complete_cb) { - xfer->complete_cb(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); - 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) { cdch_interface_t* p_cdc = get_itf(idx); TU_VERIFY(p_cdc && p_cdc->serial_drid < SERIAL_DRIVER_COUNT); @@ -820,6 +698,36 @@ bool cdch_set_config(uint8_t daddr, uint8_t itf_num) { //------------- Driver API -------------// +// internal control complete to update state such as line state, encoding +static void acm_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,); + bool const success = (xfer->result == XFER_RESULT_SUCCESS); + TU_LOG_P_CDC("control complete success = %u", success); + + if (success) { + switch (xfer->setup->bRequest) { + case CDC_REQUEST_SET_CONTROL_LINE_STATE: + p_cdc->line_state = (uint8_t) tu_le16toh(xfer->setup->wValue); + 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; + } + } + + xfer->complete_cb = p_cdc->user_control_cb; + if (xfer->complete_cb) { + xfer->complete_cb(xfer); + } +} + 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) { TU_VERIFY(p_cdc->acm_capability.support_line_request); @@ -842,7 +750,7 @@ static bool acm_set_control_line_state(cdch_interface_t* p_cdc, uint16_t line_st .ep_addr = 0, .setup = &request, .buffer = NULL, - .complete_cb = complete_cb ? cdch_internal_control_complete : NULL, // complete_cb is NULL for sync call + .complete_cb = complete_cb ? acm_internal_control_complete : NULL, // complete_cb is NULL for sync call .user_data = user_data }; @@ -873,7 +781,7 @@ static bool acm_set_line_coding(cdch_interface_t* p_cdc, cdc_line_coding_t const .ep_addr = 0, .setup = &request, .buffer = enum_buf, - .complete_cb = complete_cb ? cdch_internal_control_complete : NULL, // complete_cb is NULL for sync call + .complete_cb = complete_cb ? acm_internal_control_complete : NULL, // complete_cb is NULL for sync call .user_data = user_data }; @@ -1030,13 +938,42 @@ static bool ftdi_sio_reset(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, u //------------- Driver API -------------// +// internal control complete to update state such as line state, line_coding +static void ftdi_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,); + bool const success = (xfer->result == XFER_RESULT_SUCCESS); + TU_LOG_P_CDC("control complete success = %u", success); + + if (success) { + switch (xfer->setup->bRequest) { + case FTDI_SIO_MODEM_CTRL: + p_cdc->line_state = (uint8_t) tu_le16toh(xfer->setup->wValue); + break; + + case FTDI_SIO_SET_BAUD_RATE: + p_cdc->line_coding.bit_rate = p_cdc->requested_line_coding.bit_rate; + break; + + default: break; + } + } + + xfer->complete_cb = p_cdc->user_control_cb; + if (xfer->complete_cb) { + xfer->complete_cb(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) { uint16_t const divisor = (uint16_t) ftdi_232bm_baud_to_divisor(baudrate); p_cdc->user_control_cb = complete_cb; 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)); + complete_cb ? ftdi_internal_control_complete : NULL, user_data)); return true; } @@ -1065,7 +1002,7 @@ static bool ftdi_set_line_coding(cdch_interface_t* p_cdc, cdc_line_coding_t cons 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) { p_cdc->user_control_cb = complete_cb; TU_ASSERT(ftdi_sio_set_request(p_cdc, FTDI_SIO_MODEM_CTRL, 0x0300 | line_state, - complete_cb ? cdch_internal_control_complete : NULL, user_data)); + complete_cb ? ftdi_internal_control_complete : NULL, user_data)); return true; } @@ -1222,11 +1159,42 @@ static bool cp210x_ifc_enable(cdch_interface_t* p_cdc, uint16_t enabled, tuh_xfe //------------- Driver API -------------// +// internal control complete to update state such as line state, encoding +static void cp210x_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,); + bool const success = (xfer->result == XFER_RESULT_SUCCESS); + TU_LOG_P_CDC("control complete success = %u", success); + + if (success) { + switch(xfer->setup->bRequest) { + case CP210X_SET_MHS: + p_cdc->line_state = (uint8_t) tu_le16toh(xfer->setup->wValue); + 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; + } + } + + xfer->complete_cb = p_cdc->user_control_cb; + if (xfer->complete_cb) { + xfer->complete_cb(xfer); + } +} + static bool cp210x_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { 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, - complete_cb ? cdch_internal_control_complete : NULL, user_data); + complete_cb ? cp210x_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, @@ -1253,7 +1221,7 @@ static bool cp210x_set_line_coding(cdch_interface_t* p_cdc, cdc_line_coding_t co 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) { p_cdc->user_control_cb = complete_cb; return cp210x_set_request(p_cdc, CP210X_SET_MHS, 0x0300 | line_state, NULL, 0, - complete_cb ? cdch_internal_control_complete : NULL, user_data); + complete_cb ? cp210x_internal_control_complete : NULL, user_data); } //------------- Enumeration -------------// @@ -1412,9 +1380,60 @@ static bool ch34x_write_reg_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, //------------- 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 - process_internal_control_complete(xfer, 0); +static void ch34x_internal_control_complete(tuh_xfer_t * xfer) { + // CH34x has only interface 0, because wIndex is used as payload and not for bInterfaceNumber + uint8_t const itf_num = 0; + uint8_t idx = tuh_cdc_itf_get_index(xfer->daddr, itf_num); + cdch_interface_t * p_cdc = get_itf(idx); + TU_ASSERT(p_cdc,); + bool const success = (xfer->result == XFER_RESULT_SUCCESS); + TU_LOG_P_CDC("control complete success = %u", success); + + if (success) { + switch (xfer->setup->bRequest) { + case CH34X_REQ_WRITE_REG: + // register write request + switch (tu_le16toh(xfer->setup->wValue)) { + 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 = ~tu_le16toh(xfer->setup->wValue); + 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; + } + } + + xfer->complete_cb = p_cdc->user_control_cb; + if (xfer->complete_cb) { + xfer->complete_cb(xfer); + } } static bool ch34x_set_data_format(cdch_interface_t* p_cdc, uint8_t stop_bits, uint8_t parity, uint8_t data_bits, @@ -1426,7 +1445,7 @@ static bool ch34x_set_data_format(cdch_interface_t* p_cdc, uint8_t stop_bits, ui uint8_t const lcr = ch34x_get_lcr(stop_bits, parity, data_bits); 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)); + complete_cb ? ch34x_internal_control_complete : NULL, user_data)); return true; } @@ -1435,7 +1454,7 @@ static bool ch34x_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, p_cdc->requested_line_coding.bit_rate = baudrate; p_cdc->user_control_cb = complete_cb; TU_ASSERT(ch34x_write_reg_baudrate(p_cdc, baudrate, - complete_cb ? ch34x_control_complete : NULL, user_data)); + complete_cb ? ch34x_internal_control_complete : NULL, user_data)); return true; } @@ -1450,7 +1469,7 @@ static void ch34x_set_line_coding_stage1_complete(tuh_xfer_t* xfer) { // 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), ); + p_cdc->requested_line_coding.data_bits, ch34x_internal_control_complete, xfer->user_data), ); } else { // stage 1 failed, notify user xfer->complete_cb = p_cdc->user_control_cb; @@ -1511,7 +1530,7 @@ static bool ch34x_set_modem_ctrl(cdch_interface_t* p_cdc, uint16_t line_state, 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)); + complete_cb ? ch34x_internal_control_complete : NULL, user_data)); return true; } -- cgit v1.3.1 From 2f50f5a4263dc3d65f3bf96b593edac5ac271a5a Mon Sep 17 00:00:00 2001 From: IngHK Date: Thu, 22 Feb 2024 14:59:16 +0100 Subject: changed to use of p_cdc->requested_line_coding --- src/class/cdc/cdc_host.c | 215 +++++++++++++++++++++-------------------------- 1 file changed, 96 insertions(+), 119 deletions(-) (limited to 'src/class') diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index e39122e8f..b2ba7c9ea 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -63,12 +63,10 @@ typedef struct { cdc_acm_capability_t acm_capability; 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; + TU_ATTR_ALIGNED(4) cdc_line_coding_t requested_line_coding; // 1 byte padding - #endif + + uint8_t line_state; // DTR (bit0), RTS (bit1) tuh_xfer_cb_t user_control_cb; @@ -95,9 +93,9 @@ 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_baudrate(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); +static bool acm_set_data_format(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); +static bool acm_set_line_coding(cdch_interface_t* p_cdc, 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); //------------- FTDI prototypes -------------// @@ -109,9 +107,9 @@ static uint16_t const ftdi_vid_pid_list[][2] = {CFG_TUH_CDC_FTDI_VID_PID_LIST}; 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_baudrate(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); +static bool ftdi_set_data_format(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); +static bool ftdi_set_line_coding(cdch_interface_t* p_cdc, 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); #endif @@ -124,9 +122,9 @@ 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_baudrate(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); +static bool cp210x_set_data_format(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); +static bool cp210x_set_line_coding(cdch_interface_t* p_cdc, 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); #endif @@ -139,9 +137,9 @@ 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_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_baudrate(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); +static bool ch34x_set_data_format(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); +static bool ch34x_set_line_coding(cdch_interface_t* p_cdc, 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 @@ -170,9 +168,9 @@ typedef struct { 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); - 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); + bool (*const set_baudrate)(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); + bool (*const set_data_format)(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); + bool (*const set_line_coding)(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); #if CFG_TUSB_DEBUG && CFG_TUSB_DEBUG >= CFG_TUH_CDC_LOG_LEVEL uint8_t const * name; #endif @@ -276,6 +274,7 @@ static cdch_interface_t* make_new_itf(uint8_t daddr, tusb_desc_interface_t const p_cdc->bInterfaceNumber = itf_desc->bInterfaceNumber; p_cdc->bInterfaceSubClass = itf_desc->bInterfaceSubClass; p_cdc->bInterfaceProtocol = itf_desc->bInterfaceProtocol; + p_cdc->line_coding = (cdc_line_coding_t) { 0, 0, 0, 0 }; p_cdc->line_state = 0; return p_cdc; } @@ -451,12 +450,14 @@ bool tuh_cdc_set_baudrate(uint8_t idx, uint32_t baudrate, tuh_xfer_cb_t complete TU_LOG_P_CDC("set baudrate = %lu", baudrate); cdch_serial_driver_t const* driver = &serial_drivers[p_cdc->serial_drid]; + p_cdc->requested_line_coding.bit_rate = baudrate; + if (complete_cb) { - return driver->set_baudrate(p_cdc, baudrate, complete_cb, user_data); + return driver->set_baudrate(p_cdc, complete_cb, user_data); } else { // blocking xfer_result_t result = XFER_RESULT_INVALID; - bool ret = driver->set_baudrate(p_cdc, baudrate, complete_cb, (uintptr_t) &result); + bool ret = driver->set_baudrate(p_cdc, complete_cb, (uintptr_t) &result); if (user_data) { // user_data is not NULL, return result via user_data @@ -477,12 +478,16 @@ bool tuh_cdc_set_data_format(uint8_t idx, uint8_t stop_bits, uint8_t parity, uin data_bits, parity, stop_bits); cdch_serial_driver_t const* driver = &serial_drivers[p_cdc->serial_drid]; + 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; + if (complete_cb) { - return driver->set_data_format(p_cdc, stop_bits, parity, data_bits, complete_cb, user_data); + return driver->set_data_format(p_cdc, 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); + bool ret = driver->set_data_format(p_cdc, complete_cb, (uintptr_t) &result); if (user_data) { // user_data is not NULL, return result via user_data @@ -491,7 +496,7 @@ bool tuh_cdc_set_data_format(uint8_t idx, uint8_t stop_bits, uint8_t parity, uin 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.parity = parity; p_cdc->line_coding.data_bits = data_bits; return true; } @@ -504,12 +509,14 @@ bool tuh_cdc_set_line_coding(uint8_t idx, cdc_line_coding_t const* line_coding, line_coding->bit_rate, line_coding->data_bits, line_coding->parity, line_coding->stop_bits); cdch_serial_driver_t const* driver = &serial_drivers[p_cdc->serial_drid]; + p_cdc->requested_line_coding = *line_coding; + if ( complete_cb ) { - return driver->set_line_coding(p_cdc, line_coding, complete_cb, user_data); + return driver->set_line_coding(p_cdc, complete_cb, user_data); } else { // blocking xfer_result_t result = XFER_RESULT_INVALID; - bool ret = driver->set_line_coding(p_cdc, line_coding, complete_cb, (uintptr_t) &result); + bool ret = driver->set_line_coding(p_cdc, complete_cb, (uintptr_t) &result); if (user_data) { // user_data is not NULL, return result via user_data @@ -714,8 +721,7 @@ static void acm_internal_control_complete(tuh_xfer_t * xfer) { 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); + p_cdc->line_coding = p_cdc->requested_line_coding; break; default: break; @@ -758,7 +764,7 @@ static bool acm_set_control_line_state(cdch_interface_t* p_cdc, uint16_t line_st return true; } -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_line_coding(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { tusb_control_request_t const request = { .bmRequestType_bit = { .recipient = TUSB_REQ_RCPT_INTERFACE, @@ -773,7 +779,7 @@ static bool acm_set_line_coding(cdch_interface_t* p_cdc, cdc_line_coding_t const // use usbh enum buf to hold line coding since user line_coding variable does not live long enough uint8_t* enum_buf = usbh_get_enum_buf(); - memcpy(enum_buf, line_coding, sizeof(cdc_line_coding_t)); + memcpy(enum_buf, &p_cdc->requested_line_coding, sizeof(cdc_line_coding_t)); p_cdc->user_control_cb = complete_cb; tuh_xfer_t xfer = { @@ -789,23 +795,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) { - - 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; +static bool acm_set_data_format(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + p_cdc->requested_line_coding.bit_rate = p_cdc->line_coding.bit_rate; - return acm_set_line_coding(p_cdc, &line_coding, complete_cb, user_data); + return acm_set_line_coding(p_cdc, 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) { +static bool acm_set_baudrate(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + p_cdc->requested_line_coding.stop_bits = p_cdc->line_coding.stop_bits; + p_cdc->requested_line_coding.parity = p_cdc->line_coding.parity; + p_cdc->requested_line_coding.data_bits = p_cdc->line_coding.data_bits; TU_VERIFY(p_cdc->acm_capability.support_line_request); - cdc_line_coding_t line_coding = p_cdc->line_coding; - line_coding.bit_rate = baudrate; - return acm_set_line_coding(p_cdc, &line_coding, complete_cb, user_data); + + return acm_set_line_coding(p_cdc, complete_cb, user_data); } //------------- Enumeration -------------// @@ -879,11 +881,11 @@ static void acm_process_config(tuh_xfer_t* xfer) { case CONFIG_ACM_SET_LINE_CODING: #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),); - break; - } + if (p_cdc->acm_capability.support_line_request) { + p_cdc->requested_line_coding = (cdc_line_coding_t) CFG_TUH_CDC_LINE_CODING_ON_ENUM; + TU_ASSERT(acm_set_line_coding(p_cdc, acm_process_config, CONFIG_ACM_COMPLETE),); + break; + } #endif TU_ATTR_FALLTHROUGH; @@ -902,7 +904,7 @@ static void acm_process_config(tuh_xfer_t* xfer) { //--------------------------------------------------------------------+ #if CFG_TUH_CDC_FTDI -static uint32_t ftdi_232bm_baud_to_divisor(uint32_t baud); +static uint32_t ftdi_232bm_baud_to_divisor(cdch_interface_t* p_cdc); //------------- Control Request -------------// @@ -967,32 +969,26 @@ static void ftdi_internal_control_complete(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) { - uint16_t const divisor = (uint16_t) ftdi_232bm_baud_to_divisor(baudrate); +static bool ftdi_sio_set_baudrate(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + uint16_t const divisor = (uint16_t) ftdi_232bm_baud_to_divisor(p_cdc); p_cdc->user_control_cb = complete_cb; - p_cdc->requested_line_coding.bit_rate = baudrate; TU_ASSERT(ftdi_sio_set_request(p_cdc, FTDI_SIO_SET_BAUD_RATE, divisor, complete_cb ? ftdi_internal_control_complete : NULL, user_data)); return true; } -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_data_format(cdch_interface_t* p_cdc, 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) { +static bool ftdi_set_line_coding(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { (void) p_cdc; - (void) line_coding; (void) complete_cb; (void) user_data; // TODO not implemented yet @@ -1056,11 +1052,11 @@ static void ftdi_process_config(tuh_xfer_t* xfer) { case CONFIG_FTDI_SET_BAUDRATE: { #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM - cdc_line_coding_t line_coding = CFG_TUH_CDC_LINE_CODING_ON_ENUM; - TU_ASSERT(ftdi_sio_set_baudrate(p_cdc, line_coding.bit_rate, ftdi_process_config, CONFIG_FTDI_SET_DATA),); - break; + p_cdc->requested_line_coding.bit_rate = ((cdc_line_coding_t) CFG_TUH_CDC_LINE_CODING_ON_ENUM).bit_rate; + TU_ASSERT(ftdi_sio_set_baudrate(p_cdc, ftdi_process_config, CONFIG_FTDI_SET_DATA),); + break; #else - TU_ATTR_FALLTHROUGH; + TU_ATTR_FALLTHROUGH; #endif } @@ -1107,8 +1103,8 @@ 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) { - return ftdi_232bm_baud_base_to_divisor(baud, 48000000u); +static uint32_t ftdi_232bm_baud_to_divisor(cdch_interface_t* p_cdc) { + return ftdi_232bm_baud_base_to_divisor(p_cdc->requested_line_coding.bit_rate, 48000000u); } #endif @@ -1175,9 +1171,7 @@ static void cp210x_internal_control_complete(tuh_xfer_t * xfer) { break; case CP210X_SET_BAUDRATE: - uint32_t baudrate; - memcpy(&baudrate, xfer->buffer, sizeof(uint32_t)); - p_cdc->line_coding.bit_rate = tu_le32toh(baudrate); + p_cdc->line_coding.bit_rate = p_cdc->requested_line_coding.bit_rate; break; default: break; @@ -1190,29 +1184,24 @@ static void cp210x_internal_control_complete(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) { - uint32_t baud_le = tu_htole32(baudrate); +static bool cp210x_set_baudrate(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + uint32_t baud_le = tu_htole32(p_cdc->requested_line_coding.bit_rate); p_cdc->user_control_cb = complete_cb; return cp210x_set_request(p_cdc, CP210X_SET_BAUDRATE, 0, (uint8_t *) &baud_le, 4, complete_cb ? cp210x_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) { +static bool cp210x_set_data_format(cdch_interface_t* p_cdc, 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_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_line_coding(cdch_interface_t* p_cdc, 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; @@ -1265,11 +1254,11 @@ static void cp210x_process_config(tuh_xfer_t* xfer) { case CONFIG_CP210X_SET_BAUDRATE: { #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM - cdc_line_coding_t line_coding = CFG_TUH_CDC_LINE_CODING_ON_ENUM; - TU_ASSERT(cp210x_set_baudrate(p_cdc, line_coding.bit_rate, cp210x_process_config, CONFIG_CP210X_SET_LINE_CTL),); - break; + p_cdc->requested_line_coding.bit_rate = ((cdc_line_coding_t) CFG_TUH_CDC_LINE_CODING_ON_ENUM).bit_rate; + TU_ASSERT(cp210x_set_baudrate(p_cdc, cp210x_process_config, CONFIG_CP210X_SET_LINE_CTL),); + break; #else - TU_ATTR_FALLTHROUGH; + TU_ATTR_FALLTHROUGH; #endif } @@ -1306,8 +1295,8 @@ static void cp210x_process_config(tuh_xfer_t* xfer) { #if CFG_TUH_CDC_CH34X -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 uint8_t ch34x_get_lcr(cdch_interface_t * p_cdc); +static uint16_t ch34x_get_divisor_prescaler(cdch_interface_t * p_cdc); //------------- Control Request -------------// @@ -1368,9 +1357,8 @@ static inline bool ch34x_write_reg(cdch_interface_t* p_cdc, uint16_t reg, uint16 // 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); +static bool ch34x_write_reg_baudrate(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + uint16_t const div_ps = ch34x_get_divisor_prescaler(p_cdc); TU_VERIFY(div_ps); TU_ASSERT(ch34x_write_reg(p_cdc, CH34X_REG16_DIVISOR_PRESCALER, div_ps, complete_cb, user_data)); @@ -1436,25 +1424,17 @@ static void ch34x_internal_control_complete(tuh_xfer_t * 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) { - 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); +static bool ch34x_set_data_format(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + uint8_t const lcr = ch34x_get_lcr(p_cdc); TU_VERIFY(lcr); TU_ASSERT (ch34x_control_out(p_cdc, CH34X_REQ_WRITE_REG, CH32X_REG16_LCR2_LCR, lcr, complete_cb ? ch34x_internal_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) { - p_cdc->requested_line_coding.bit_rate = baudrate; +static bool ch34x_set_baudrate(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { p_cdc->user_control_cb = complete_cb; - TU_ASSERT(ch34x_write_reg_baudrate(p_cdc, baudrate, - complete_cb ? ch34x_internal_control_complete : NULL, user_data)); + TU_ASSERT(ch34x_write_reg_baudrate(p_cdc, complete_cb ? ch34x_internal_control_complete : NULL, user_data)); return true; } @@ -1468,8 +1448,7 @@ static void ch34x_set_line_coding_stage1_complete(tuh_xfer_t* xfer) { 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_internal_control_complete, xfer->user_data), ); + TU_ASSERT(ch34x_set_data_format(p_cdc, ch34x_internal_control_complete, xfer->user_data), ); } else { // stage 1 failed, notify user xfer->complete_cb = p_cdc->user_control_cb; @@ -1480,31 +1459,24 @@ static void ch34x_set_line_coding_stage1_complete(tuh_xfer_t* 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->requested_line_coding = *line_coding; +static bool ch34x_set_line_coding(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { 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)); + TU_ASSERT(ch34x_write_reg_baudrate(p_cdc, 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_ASSERT(ch34x_write_reg_baudrate(p_cdc, NULL, (uintptr_t) &result)); TU_VERIFY(result == XFER_RESULT_SUCCESS); - p_cdc->line_coding.bit_rate = line_coding->bit_rate; + p_cdc->line_coding.bit_rate = p_cdc->requested_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_ASSERT(ch34x_set_data_format(p_cdc, 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) { @@ -1592,10 +1564,10 @@ 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,); // 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); + p_cdc->requested_line_coding = (cdc_line_coding_t) CFG_TUH_CDC_LINE_CODING_ON_ENUM_CH34X; + uint16_t const div_ps = ch34x_get_divisor_prescaler(p_cdc); TU_ASSERT(div_ps, ); - uint8_t const lcr = ch34x_get_lcr(line_coding.stop_bits, line_coding.parity, line_coding.data_bits); + uint8_t const lcr = ch34x_get_lcr(p_cdc); 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),); @@ -1604,7 +1576,7 @@ static void ch34x_process_config(tuh_xfer_t* xfer) { case CONFIG_CH34X_SPECIAL_REG_WRITE: // 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); + 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; @@ -1631,7 +1603,8 @@ static void ch34x_process_config(tuh_xfer_t* xfer) { //------------- Helper -------------// // calculate divisor and prescaler for baudrate, return it as 16-bit combined value -static uint16_t ch34x_get_divisor_prescaler(uint32_t baval) { +static uint16_t ch34x_get_divisor_prescaler(cdch_interface_t * p_cdc) { + uint32_t const baval = p_cdc->requested_line_coding.bit_rate; uint8_t a; uint8_t b; uint32_t c; @@ -1680,7 +1653,11 @@ static uint16_t ch34x_get_divisor_prescaler(uint32_t baval) { } // calculate lcr value from data coding -static uint8_t ch34x_get_lcr(uint8_t stop_bits, uint8_t parity, uint8_t data_bits) { +static uint8_t ch34x_get_lcr(cdch_interface_t * p_cdc) { + uint8_t const stop_bits = p_cdc->requested_line_coding.stop_bits; + uint8_t const parity = p_cdc->requested_line_coding.parity; + uint8_t const data_bits = p_cdc->requested_line_coding.data_bits; + uint8_t lcr = CH34X_LCR_ENABLE_RX | CH34X_LCR_ENABLE_TX; TU_VERIFY(data_bits >= 5 && data_bits <= 8, 0); lcr |= (uint8_t) (data_bits - 5); -- cgit v1.3.1 From 7dd435cb877f5d3e0b9576dfcdb8c40e9a03c399 Mon Sep 17 00:00:00 2001 From: IngHK Date: Tue, 20 Feb 2024 20:45:50 +0100 Subject: changed to use of p_cdc->requested_line_state --- src/class/cdc/cdc_host.c | 82 ++++++++++++++++++++++-------------------------- 1 file changed, 38 insertions(+), 44 deletions(-) (limited to 'src/class') diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index b2ba7c9ea..0af429e4b 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -67,6 +67,7 @@ typedef struct { // 1 byte padding uint8_t line_state; // DTR (bit0), RTS (bit1) + uint8_t requested_line_state; tuh_xfer_cb_t user_control_cb; @@ -96,7 +97,7 @@ static void acm_process_config(tuh_xfer_t* xfer); static bool acm_set_baudrate(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); static bool acm_set_data_format(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); static bool acm_set_line_coding(cdch_interface_t* p_cdc, 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_control_line_state(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); //------------- FTDI prototypes -------------// #if CFG_TUH_CDC_FTDI @@ -110,7 +111,7 @@ static void ftdi_process_config(tuh_xfer_t* xfer); static bool ftdi_sio_set_baudrate(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); static bool ftdi_set_data_format(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); static bool ftdi_set_line_coding(cdch_interface_t* p_cdc, 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_modem_ctrl(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); #endif //------------- CP210X prototypes -------------// @@ -125,7 +126,7 @@ static void cp210x_process_config(tuh_xfer_t* xfer); static bool cp210x_set_baudrate(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); static bool cp210x_set_data_format(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); static bool cp210x_set_line_coding(cdch_interface_t* p_cdc, 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_modem_ctrl(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); #endif //------------- CH34x prototypes -------------// @@ -140,7 +141,7 @@ static void ch34x_process_config(tuh_xfer_t* xfer); static bool ch34x_set_baudrate(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); static bool ch34x_set_data_format(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); static bool ch34x_set_line_coding(cdch_interface_t* p_cdc, 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_modem_ctrl(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); #endif //------------- Common -------------// @@ -167,7 +168,7 @@ typedef struct { 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_control_line_state)(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); bool (*const set_baudrate)(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); bool (*const set_data_format)(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); bool (*const set_line_coding)(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); @@ -426,12 +427,14 @@ bool tuh_cdc_set_control_line_state(uint8_t idx, uint16_t line_state, tuh_xfer_c TU_LOG_P_CDC("set control line state line_state = %u", line_state); cdch_serial_driver_t const* driver = &serial_drivers[p_cdc->serial_drid]; + p_cdc->requested_line_state = (uint8_t) line_state; + if (complete_cb) { - return driver->set_control_line_state(p_cdc, line_state, complete_cb, user_data); + return driver->set_control_line_state(p_cdc, complete_cb, user_data); } 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); + bool ret = driver->set_control_line_state(p_cdc, complete_cb, (uintptr_t) &result); if (user_data) { // user_data is not NULL, return result via user_data @@ -717,7 +720,7 @@ static void acm_internal_control_complete(tuh_xfer_t * xfer) { if (success) { 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 = p_cdc->requested_line_state; break; case CDC_REQUEST_SET_LINE_CODING: @@ -734,7 +737,7 @@ static void acm_internal_control_complete(tuh_xfer_t * xfer) { } } -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_control_line_state(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { TU_VERIFY(p_cdc->acm_capability.support_line_request); tusb_control_request_t const request = { @@ -744,7 +747,7 @@ static bool acm_set_control_line_state(cdch_interface_t* p_cdc, uint16_t line_st .direction = TUSB_DIR_OUT }, .bRequest = CDC_REQUEST_SET_CONTROL_LINE_STATE, - .wValue = tu_htole16(line_state), + .wValue = tu_htole16(p_cdc->requested_line_state), .wIndex = tu_htole16((uint16_t) p_cdc->bInterfaceNumber), .wLength = 0 }; @@ -872,10 +875,11 @@ static void acm_process_config(tuh_xfer_t* xfer) { 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),); - break; - } + if (p_cdc->acm_capability.support_line_request) { + p_cdc->requested_line_state = CFG_TUH_CDC_LINE_CONTROL_ON_ENUM; + TU_ASSERT(acm_set_control_line_state(p_cdc, acm_process_config, CONFIG_ACM_SET_LINE_CODING),); + break; + } #endif TU_ATTR_FALLTHROUGH; @@ -952,7 +956,7 @@ static void ftdi_internal_control_complete(tuh_xfer_t * xfer) { if (success) { switch (xfer->setup->bRequest) { case FTDI_SIO_MODEM_CTRL: - p_cdc->line_state = (uint8_t) tu_le16toh(xfer->setup->wValue); + p_cdc->line_state = p_cdc->requested_line_state; break; case FTDI_SIO_SET_BAUD_RATE: @@ -995,9 +999,9 @@ static bool ftdi_set_line_coding(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete 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) { +static bool ftdi_sio_set_modem_ctrl(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { p_cdc->user_control_cb = complete_cb; - TU_ASSERT(ftdi_sio_set_request(p_cdc, FTDI_SIO_MODEM_CTRL, 0x0300 | line_state, + TU_ASSERT(ftdi_sio_set_request(p_cdc, FTDI_SIO_MODEM_CTRL, 0x0300 | p_cdc->requested_line_state, complete_cb ? ftdi_internal_control_complete : NULL, user_data)); return true; } @@ -1044,10 +1048,11 @@ 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),); - break; + p_cdc->requested_line_state = CFG_TUH_CDC_LINE_CONTROL_ON_ENUM; + TU_ASSERT(ftdi_sio_set_modem_ctrl(p_cdc, ftdi_process_config, CONFIG_FTDI_SET_BAUDRATE),); + break; #else - TU_ATTR_FALLTHROUGH; + TU_ATTR_FALLTHROUGH; #endif case CONFIG_FTDI_SET_BAUDRATE: { @@ -1167,7 +1172,7 @@ static void cp210x_internal_control_complete(tuh_xfer_t * xfer) { if (success) { switch(xfer->setup->bRequest) { case CP210X_SET_MHS: - p_cdc->line_state = (uint8_t) tu_le16toh(xfer->setup->wValue); + p_cdc->line_state = p_cdc->requested_line_state; break; case CP210X_SET_BAUDRATE: @@ -1207,9 +1212,9 @@ static bool cp210x_set_line_coding(cdch_interface_t* p_cdc, tuh_xfer_cb_t comple 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) { +static bool cp210x_set_modem_ctrl(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { p_cdc->user_control_cb = complete_cb; - return cp210x_set_request(p_cdc, CP210X_SET_MHS, 0x0300 | line_state, NULL, 0, + return cp210x_set_request(p_cdc, CP210X_SET_MHS, 0x0300 | p_cdc->requested_line_state, NULL, 0, complete_cb ? cp210x_internal_control_complete : NULL, user_data); } @@ -1273,10 +1278,11 @@ 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),); - break; + p_cdc->requested_line_state = CFG_TUH_CDC_LINE_CONTROL_ON_ENUM; + TU_ASSERT(cp210x_set_modem_ctrl(p_cdc, cp210x_process_config, CONFIG_CP210X_COMPLETE),); + break; #else - TU_ATTR_FALLTHROUGH; + TU_ATTR_FALLTHROUGH; #endif case CONFIG_CP210X_COMPLETE: @@ -1399,19 +1405,7 @@ static void ch34x_internal_control_complete(tuh_xfer_t * xfer) { break; case CH34X_REQ_MODEM_CTRL: - // set modem controls RTS/DTR request. Note: signals are inverted - uint16_t const modem_signal = ~tu_le16toh(xfer->setup->wValue); - 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; - } + p_cdc->line_state = p_cdc->requested_line_state; break; default: break; @@ -1487,13 +1481,12 @@ static bool ch34x_set_line_coding(cdch_interface_t* p_cdc, tuh_xfer_cb_t complet 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, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { uint8_t control = 0; - if (line_state & CDC_CONTROL_LINE_STATE_RTS) { + if (p_cdc->requested_line_state & CDC_CONTROL_LINE_STATE_RTS) { control |= CH34X_BIT_RTS; } - if (line_state & CDC_CONTROL_LINE_STATE_DTR) { + if (p_cdc->requested_line_state & CDC_CONTROL_LINE_STATE_DTR) { control |= CH34X_BIT_DTR; } @@ -1587,7 +1580,8 @@ static void ch34x_process_config(tuh_xfer_t* xfer) { 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),); + p_cdc->requested_line_state = CFG_TUH_CDC_LINE_CONTROL_ON_ENUM; + TU_ASSERT (ch34x_set_modem_ctrl(p_cdc, ch34x_process_config, CONFIG_CH34X_COMPLETE),); break; case CONFIG_CH34X_COMPLETE: -- cgit v1.3.1 From dcadf8c2a2a79b838cfccf32612fadcb15216c77 Mon Sep 17 00:00:00 2001 From: IngHK Date: Thu, 22 Feb 2024 15:04:24 +0100 Subject: created set_function_call() --- src/class/cdc/cdc_host.c | 108 +++++++++++++++++++++-------------------------- 1 file changed, 47 insertions(+), 61 deletions(-) (limited to 'src/class') diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index 0af429e4b..6a650071d 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -421,115 +421,101 @@ bool tuh_cdc_read_clear (uint8_t idx) { // Control Endpoint API //--------------------------------------------------------------------+ -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); - TU_LOG_P_CDC("set control line state line_state = %u", line_state); - cdch_serial_driver_t const* driver = &serial_drivers[p_cdc->serial_drid]; - - p_cdc->requested_line_state = (uint8_t) line_state; - +// call of (non-)blocking set-functions (to set line state, baudrate, ...) +static bool set_function_call ( + cdch_interface_t * p_cdc, + bool (*set_function)(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data), + tuh_xfer_cb_t complete_cb, uintptr_t user_data) { if (complete_cb) { - return driver->set_control_line_state(p_cdc, complete_cb, user_data); + // non-blocking with call back + return set_function(p_cdc, complete_cb, user_data); } else { // blocking - xfer_result_t result = XFER_RESULT_INVALID; - bool ret = driver->set_control_line_state(p_cdc, complete_cb, (uintptr_t) &result); + xfer_result_t result = XFER_RESULT_INVALID; // use local result, because user_data ptr may be NULL + bool ret = set_function(p_cdc, NULL, (uintptr_t) &result); if (user_data) { - // user_data is not NULL, return result via user_data - *((xfer_result_t*) user_data) = result; + *((xfer_result_t *) user_data) = result; } - TU_VERIFY(ret && result == XFER_RESULT_SUCCESS); + return (ret && result == XFER_RESULT_SUCCESS); + } +} + +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); + TU_LOG_P_CDC("set control line state line_state = %u", line_state); + cdch_serial_driver_t const * driver = &serial_drivers[p_cdc->serial_drid]; + + p_cdc->requested_line_state = (uint8_t) line_state; + + bool ret = set_function_call(p_cdc, driver->set_control_line_state, complete_cb, user_data); + + if (ret && !complete_cb) { p_cdc->line_state = (uint8_t) line_state; - return true; } + + return ret; } bool tuh_cdc_set_baudrate(uint8_t idx, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - cdch_interface_t* p_cdc = get_itf(idx); + cdch_interface_t * p_cdc = get_itf(idx); TU_VERIFY(p_cdc && p_cdc->serial_drid < SERIAL_DRIVER_COUNT); TU_LOG_P_CDC("set baudrate = %lu", baudrate); - cdch_serial_driver_t const* driver = &serial_drivers[p_cdc->serial_drid]; + cdch_serial_driver_t const * driver = &serial_drivers[p_cdc->serial_drid]; p_cdc->requested_line_coding.bit_rate = baudrate; - if (complete_cb) { - return driver->set_baudrate(p_cdc, complete_cb, user_data); - } else { - // blocking - xfer_result_t result = XFER_RESULT_INVALID; - bool ret = driver->set_baudrate(p_cdc, complete_cb, (uintptr_t) &result); - - if (user_data) { - // user_data is not NULL, return result via user_data - *((xfer_result_t*) user_data) = result; - } + bool ret = set_function_call(p_cdc, driver->set_baudrate, complete_cb, user_data); - TU_VERIFY(ret && result == XFER_RESULT_SUCCESS); + if (ret && !complete_cb) { p_cdc->line_coding.bit_rate = baudrate; - return true; } + + return ret; } 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); + cdch_interface_t * p_cdc = get_itf(idx); TU_VERIFY(p_cdc && p_cdc->serial_drid < SERIAL_DRIVER_COUNT); TU_LOG_P_CDC("set data format data_bits = %u parity = %u stop_bits = %u (indexes!)", data_bits, parity, stop_bits); - cdch_serial_driver_t const* driver = &serial_drivers[p_cdc->serial_drid]; + cdch_serial_driver_t const * driver = &serial_drivers[p_cdc->serial_drid]; 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; - if (complete_cb) { - return driver->set_data_format(p_cdc, complete_cb, user_data); - } else { - // blocking - xfer_result_t result = XFER_RESULT_INVALID; - bool ret = driver->set_data_format(p_cdc, complete_cb, (uintptr_t) &result); - - if (user_data) { - // user_data is not NULL, return result via user_data - *((xfer_result_t*) user_data) = result; - } + bool ret = set_function_call(p_cdc, driver->set_data_format, complete_cb, user_data); - TU_VERIFY(ret && result == XFER_RESULT_SUCCESS); + if (ret && !complete_cb) { p_cdc->line_coding.stop_bits = stop_bits; p_cdc->line_coding.parity = parity; p_cdc->line_coding.data_bits = data_bits; - return true; } + + return ret; } -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); +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); TU_LOG_P_CDC("set line coding baudrate = %lu data_bits = %u parity = %u stop_bits = %u (indexes!)", line_coding->bit_rate, line_coding->data_bits, line_coding->parity, line_coding->stop_bits); - cdch_serial_driver_t const* driver = &serial_drivers[p_cdc->serial_drid]; + cdch_serial_driver_t const * driver = &serial_drivers[p_cdc->serial_drid]; p_cdc->requested_line_coding = *line_coding; - if ( complete_cb ) { - return driver->set_line_coding(p_cdc, complete_cb, user_data); - } else { - // blocking - xfer_result_t result = XFER_RESULT_INVALID; - bool ret = driver->set_line_coding(p_cdc, complete_cb, (uintptr_t) &result); + bool ret = set_function_call(p_cdc, driver->set_line_coding, complete_cb, user_data); - 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); + if (ret && !complete_cb) { p_cdc->line_coding = *line_coding; - return true; } + + return ret; } //--------------------------------------------------------------------+ -- cgit v1.3.1 From ea86bbe5f742344b307e52945c0977143522810b Mon Sep 17 00:00:00 2001 From: IngHK Date: Wed, 21 Feb 2024 16:30:02 +0100 Subject: added continue enum after config fail --- src/class/cdc/cdc_host.c | 109 +++++++++++++++++++++++++++++------------------ 1 file changed, 67 insertions(+), 42 deletions(-) (limited to 'src/class') diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index 6a650071d..226f389e3 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -47,6 +47,16 @@ #define TU_LOG_P_CDC(TXT,...) TU_LOG_CDC(TXT, p_cdc->daddr, p_cdc->bInterfaceNumber, \ serial_drivers[p_cdc->serial_drid].name, ##__VA_ARGS__) +#define TU_ASSERT_COMPLETE_DEFINE(_cond, _itf_offset) \ + do { \ + if (!(_cond)) { _MESS_FAILED(); TU_BREAKPOINT(); set_config_complete(idx, _itf_offset, false); } \ + } while(0) + +#define TU_ASSERT_COMPLETE_1ARGS(_cond) TU_ASSERT_COMPLETE_DEFINE(_cond, 0) +#define TU_ASSERT_COMPLETE_2ARGS(_cond, _itf_offset) TU_ASSERT_COMPLETE_DEFINE(_cond, _itf_offset) + +#define TU_ASSERT_COMPLETE(...) _GET_3RD_ARG(__VA_ARGS__, TU_ASSERT_COMPLETE_2ARGS, TU_ASSERT_COMPLETE_1ARGS, _dummy)(__VA_ARGS__) + //--------------------------------------------------------------------+ // Host CDC Interface //--------------------------------------------------------------------+ @@ -285,7 +295,6 @@ static cdch_interface_t* make_new_itf(uint8_t daddr, tusb_desc_interface_t const } static bool open_ep_stream_pair(cdch_interface_t* p_cdc , tusb_desc_endpoint_t const *desc_ep); -static void set_config_complete(cdch_interface_t * p_cdc, uint8_t idx, uint8_t itf_num); //--------------------------------------------------------------------+ // APPLICATION API @@ -657,16 +666,26 @@ bool cdch_open(uint8_t rhport, uint8_t daddr, tusb_desc_interface_t const *itf_d return false; } -static void set_config_complete(cdch_interface_t * p_cdc, uint8_t idx, uint8_t itf_num) { - TU_LOG_P_CDC("set config complete"); - p_cdc->mounted = true; - if (tuh_cdc_mount_cb) tuh_cdc_mount_cb(idx); +static void set_config_complete(uint8_t idx, uint8_t itf_offset, bool success) { + cdch_interface_t * p_cdc = get_itf(idx); + TU_ASSERT(p_cdc,); + TU_LOG_P_CDC("set config complete success = %u", success); - // Prepare for incoming data - tu_edpt_stream_read_xfer(&p_cdc->stream.rx); + if (success) { + p_cdc->mounted = true; + if (tuh_cdc_mount_cb) { + tuh_cdc_mount_cb(idx); + } + // Prepare for incoming data + tu_edpt_stream_read_xfer(&p_cdc->stream.rx); + } else { + // clear the interface entry + p_cdc->daddr = 0; + p_cdc->bInterfaceNumber = 0; + } // notify usbh that driver enumeration is complete - usbh_driver_set_config_complete(p_cdc->daddr, itf_num); + usbh_driver_set_config_complete(p_cdc->daddr, p_cdc->bInterfaceNumber + itf_offset); } bool cdch_set_config(uint8_t daddr, uint8_t itf_num) { @@ -856,14 +875,14 @@ static void acm_process_config(tuh_xfer_t* xfer) { 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,); + TU_ASSERT_COMPLETE(p_cdc && xfer->result == XFER_RESULT_SUCCESS, 1); 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) { p_cdc->requested_line_state = CFG_TUH_CDC_LINE_CONTROL_ON_ENUM; - TU_ASSERT(acm_set_control_line_state(p_cdc, acm_process_config, CONFIG_ACM_SET_LINE_CODING),); + TU_ASSERT_COMPLETE(acm_set_control_line_state(p_cdc, acm_process_config, CONFIG_ACM_SET_LINE_CODING), 1); break; } #endif @@ -873,7 +892,7 @@ static void acm_process_config(tuh_xfer_t* xfer) { #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM if (p_cdc->acm_capability.support_line_request) { p_cdc->requested_line_coding = (cdc_line_coding_t) CFG_TUH_CDC_LINE_CODING_ON_ENUM; - TU_ASSERT(acm_set_line_coding(p_cdc, acm_process_config, CONFIG_ACM_COMPLETE),); + TU_ASSERT_COMPLETE(acm_set_line_coding(p_cdc, acm_process_config, CONFIG_ACM_COMPLETE), 1); break; } #endif @@ -881,10 +900,11 @@ static void acm_process_config(tuh_xfer_t* xfer) { 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(idx, 1, true); break; default: + set_config_complete(idx, 1, false); break; } } @@ -1024,18 +1044,18 @@ static void ftdi_process_config(tuh_xfer_t* xfer) { 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, ); + TU_ASSERT_COMPLETE(p_cdc && xfer->result == XFER_RESULT_SUCCESS); switch(state) { // Note may need to read FTDI eeprom case CONFIG_FTDI_RESET: - TU_ASSERT(ftdi_sio_reset(p_cdc, ftdi_process_config, CONFIG_FTDI_MODEM_CTRL),); + TU_ASSERT_COMPLETE(ftdi_sio_reset(p_cdc, ftdi_process_config, CONFIG_FTDI_MODEM_CTRL)); break; case CONFIG_FTDI_MODEM_CTRL: #if CFG_TUH_CDC_LINE_CONTROL_ON_ENUM p_cdc->requested_line_state = CFG_TUH_CDC_LINE_CONTROL_ON_ENUM; - TU_ASSERT(ftdi_sio_set_modem_ctrl(p_cdc, ftdi_process_config, CONFIG_FTDI_SET_BAUDRATE),); + TU_ASSERT_COMPLETE(ftdi_sio_set_modem_ctrl(p_cdc, ftdi_process_config, CONFIG_FTDI_SET_BAUDRATE)); break; #else TU_ATTR_FALLTHROUGH; @@ -1044,7 +1064,7 @@ static void ftdi_process_config(tuh_xfer_t* xfer) { case CONFIG_FTDI_SET_BAUDRATE: { #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM p_cdc->requested_line_coding.bit_rate = ((cdc_line_coding_t) CFG_TUH_CDC_LINE_CODING_ON_ENUM).bit_rate; - TU_ASSERT(ftdi_sio_set_baudrate(p_cdc, ftdi_process_config, CONFIG_FTDI_SET_DATA),); + TU_ASSERT_COMPLETE(ftdi_sio_set_baudrate(p_cdc, ftdi_process_config, CONFIG_FTDI_SET_DATA)); break; #else TU_ATTR_FALLTHROUGH; @@ -1055,7 +1075,7 @@ static void ftdi_process_config(tuh_xfer_t* xfer) { #if 0 // TODO set data format #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM cdc_line_coding_t line_coding = CFG_TUH_CDC_LINE_CODING_ON_ENUM; - TU_ASSERT(ftdi_sio_set_data(p_cdc, process_ftdi_config, CONFIG_FTDI_COMPLETE),); + TU_ASSERT_COMPLETE(ftdi_sio_set_data(p_cdc, process_ftdi_config, CONFIG_FTDI_COMPLETE)); break; #endif #endif @@ -1064,10 +1084,11 @@ static void ftdi_process_config(tuh_xfer_t* xfer) { } case CONFIG_FTDI_COMPLETE: - set_config_complete(p_cdc, idx, itf_num); + set_config_complete(idx, 0, true); break; default: + set_config_complete(idx, 0, false); break; } } @@ -1150,8 +1171,8 @@ static bool cp210x_ifc_enable(cdch_interface_t* p_cdc, uint16_t enabled, tuh_xfe static void cp210x_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,); + cdch_interface_t* p_cdc = get_itf(idx); + TU_ASSERT(p_cdc, ); bool const success = (xfer->result == XFER_RESULT_SUCCESS); TU_LOG_P_CDC("control complete success = %u", success); @@ -1236,17 +1257,17 @@ static void cp210x_process_config(tuh_xfer_t* xfer) { 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,); + TU_ASSERT_COMPLETE(p_cdc && xfer->result == XFER_RESULT_SUCCESS); switch (state) { case CONFIG_CP210X_IFC_ENABLE: - TU_ASSERT(cp210x_ifc_enable(p_cdc, 1, cp210x_process_config, CONFIG_CP210X_SET_BAUDRATE),); + TU_ASSERT_COMPLETE(cp210x_ifc_enable(p_cdc, 1, cp210x_process_config, CONFIG_CP210X_SET_BAUDRATE)); break; case CONFIG_CP210X_SET_BAUDRATE: { #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM p_cdc->requested_line_coding.bit_rate = ((cdc_line_coding_t) CFG_TUH_CDC_LINE_CODING_ON_ENUM).bit_rate; - TU_ASSERT(cp210x_set_baudrate(p_cdc, cp210x_process_config, CONFIG_CP210X_SET_LINE_CTL),); + TU_ASSERT_COMPLETE(cp210x_set_baudrate(p_cdc, cp210x_process_config, CONFIG_CP210X_SET_LINE_CTL)); break; #else TU_ATTR_FALLTHROUGH; @@ -1265,17 +1286,19 @@ static void cp210x_process_config(tuh_xfer_t* xfer) { case CONFIG_CP210X_SET_DTR_RTS: #if CFG_TUH_CDC_LINE_CONTROL_ON_ENUM p_cdc->requested_line_state = CFG_TUH_CDC_LINE_CONTROL_ON_ENUM; - TU_ASSERT(cp210x_set_modem_ctrl(p_cdc, cp210x_process_config, CONFIG_CP210X_COMPLETE),); + TU_ASSERT_COMPLETE(cp210x_set_modem_ctrl(p_cdc, cp210x_process_config, CONFIG_CP210X_COMPLETE)); break; #else TU_ATTR_FALLTHROUGH; #endif case CONFIG_CP210X_COMPLETE: - set_config_complete(p_cdc, idx, itf_num); + set_config_complete(idx, 0, true); break; - default: break; + default: + set_config_complete(idx, 0, false); + break; } } @@ -1361,11 +1384,11 @@ static bool ch34x_write_reg_baudrate(cdch_interface_t* p_cdc, tuh_xfer_cb_t comp // internal control complete to update state such as line state, encoding static void ch34x_internal_control_complete(tuh_xfer_t * xfer) { - // CH34x has only interface 0, because wIndex is used as payload and not for bInterfaceNumber + // CH34x only has 1 interface and wIndex used as payload and not for bInterfaceNumber uint8_t const itf_num = 0; uint8_t 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, ); bool const success = (xfer->result == XFER_RESULT_SUCCESS); TU_LOG_P_CDC("control complete success = %u", success); @@ -1526,14 +1549,14 @@ static void ch34x_process_config(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_COMPLETE(p_cdc && xfer->result == XFER_RESULT_SUCCESS); uintptr_t const state = xfer->user_data; uint8_t buffer[2]; // TODO remove - TU_ASSERT (p_cdc,); - TU_ASSERT (xfer->result == XFER_RESULT_SUCCESS,); switch (state) { case CONFIG_CH34X_READ_VERSION: - TU_ASSERT (ch34x_control_in(p_cdc, CH34X_REQ_READ_VERSION, 0, 0, buffer, 2, ch34x_process_config, CONFIG_CH34X_SERIAL_INIT),); + TU_ASSERT_COMPLETE(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: { @@ -1541,41 +1564,43 @@ static void ch34x_process_config(tuh_xfer_t* xfer) { uint8_t const version = xfer->buffer[0]; TU_LOG_P_CDC("Chip Version = %02x", 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_COMPLETE(version >= 0x30); // init CH34x with line coding p_cdc->requested_line_coding = (cdc_line_coding_t) CFG_TUH_CDC_LINE_CODING_ON_ENUM_CH34X; uint16_t const div_ps = ch34x_get_divisor_prescaler(p_cdc); - TU_ASSERT(div_ps, ); + TU_ASSERT_COMPLETE(div_ps); uint8_t const lcr = ch34x_get_lcr(p_cdc); - 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),); + TU_ASSERT_COMPLETE(lcr); + TU_ASSERT_COMPLETE(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: // 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),); + TU_ASSERT_COMPLETE(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, TU_U16(CH341_REG_0x27, CH341_REG_0x27), 0x0000, ch34x_process_config, CONFIG_CH34X_MODEM_CONTROL),); + TU_ASSERT_COMPLETE(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: // !always! set modem controls RTS/DTR (CH34x has no reset state after CH34X_REQ_SERIAL_INIT) p_cdc->requested_line_state = CFG_TUH_CDC_LINE_CONTROL_ON_ENUM; - TU_ASSERT (ch34x_set_modem_ctrl(p_cdc, ch34x_process_config, CONFIG_CH34X_COMPLETE),); + TU_ASSERT_COMPLETE(ch34x_set_modem_ctrl(p_cdc, ch34x_process_config, CONFIG_CH34X_COMPLETE)); break; case CONFIG_CH34X_COMPLETE: - set_config_complete(p_cdc, idx, itf_num); + set_config_complete(idx, 0, true); break; default: - TU_ASSERT (false,); + set_config_complete(idx, 0, false); break; } } -- cgit v1.3.1 From 22a12c76689399bd1a67e52531171876e5d88a28 Mon Sep 17 00:00:00 2001 From: IngHK Date: Thu, 22 Feb 2024 09:28:06 +0100 Subject: improved ACM checks --- src/class/cdc/cdc_host.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'src/class') diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index 226f389e3..ae8245b0e 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -773,6 +773,11 @@ static bool acm_set_control_line_state(cdch_interface_t* p_cdc, tuh_xfer_cb_t co } static bool acm_set_line_coding(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + TU_VERIFY(p_cdc->acm_capability.support_line_request); + TU_VERIFY(p_cdc->requested_line_coding.data_bits && p_cdc->requested_line_coding.bit_rate); + TU_VERIFY((p_cdc->requested_line_coding.data_bits >= 5 && p_cdc->requested_line_coding.data_bits <= 8) || + p_cdc->requested_line_coding.data_bits == 16); + tusb_control_request_t const request = { .bmRequestType_bit = { .recipient = TUSB_REQ_RCPT_INTERFACE, @@ -813,7 +818,6 @@ static bool acm_set_baudrate(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, p_cdc->requested_line_coding.stop_bits = p_cdc->line_coding.stop_bits; p_cdc->requested_line_coding.parity = p_cdc->line_coding.parity; p_cdc->requested_line_coding.data_bits = p_cdc->line_coding.data_bits; - TU_VERIFY(p_cdc->acm_capability.support_line_request); return acm_set_line_coding(p_cdc, complete_cb, user_data); } -- cgit v1.3.1 From 138567af3e39e08742b3d1edf5b83d27d8526a4a Mon Sep 17 00:00:00 2001 From: IngHK Date: Sun, 18 Feb 2024 20:33:54 +0100 Subject: fixed #2448 CH34x ch34x_set_line_coding() callback bug --- src/class/cdc/cdc_host.c | 127 ++++++++++++++++++++++++++++------------------- 1 file changed, 75 insertions(+), 52 deletions(-) (limited to 'src/class') diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index ae8245b0e..f6804ca2b 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -80,6 +80,9 @@ typedef struct { uint8_t requested_line_state; tuh_xfer_cb_t user_control_cb; + #if CFG_TUH_CDC_CH34X + tuh_xfer_cb_t requested_complete_cb; + #endif struct { tu_edpt_stream_t tx; @@ -1376,12 +1379,33 @@ static inline bool ch34x_write_reg(cdch_interface_t* p_cdc, uint16_t reg, uint16 // 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, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { +static bool ch34x_write_reg_data_format(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + uint8_t const lcr = ch34x_get_lcr(p_cdc); + TU_VERIFY(lcr); + + return ch34x_write_reg(p_cdc, CH32X_REG16_LCR2_LCR, lcr, complete_cb, user_data); +} + +static bool ch34x_write_reg_baudrate(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { uint16_t const div_ps = ch34x_get_divisor_prescaler(p_cdc); TU_VERIFY(div_ps); - TU_ASSERT(ch34x_write_reg(p_cdc, CH34X_REG16_DIVISOR_PRESCALER, div_ps, - complete_cb, user_data)); - return true; + + return ch34x_write_reg(p_cdc, CH34X_REG16_DIVISOR_PRESCALER, div_ps, complete_cb, user_data); +} + +static bool ch34x_modem_ctrl_request(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + uint8_t control = 0; + if (p_cdc->requested_line_state & CDC_CONTROL_LINE_STATE_RTS) { + control |= CH34X_BIT_RTS; + } + if (p_cdc->requested_line_state & CDC_CONTROL_LINE_STATE_DTR) { + control |= CH34X_BIT_DTR; + } + + // CH34x signals are inverted + control = ~control; + + return ch34x_control_out(p_cdc, CH34X_REQ_MODEM_CTRL, control, 0, complete_cb, user_data); } //------------- Driver API -------------// @@ -1431,34 +1455,34 @@ static void ch34x_internal_control_complete(tuh_xfer_t * xfer) { } } -static bool ch34x_set_data_format(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - uint8_t const lcr = ch34x_get_lcr(p_cdc); - TU_VERIFY(lcr); - TU_ASSERT (ch34x_control_out(p_cdc, CH34X_REQ_WRITE_REG, CH32X_REG16_LCR2_LCR, lcr, - complete_cb ? ch34x_internal_control_complete : NULL, user_data)); +static bool ch34x_set_data_format(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + p_cdc->user_control_cb = complete_cb; + TU_ASSERT(ch34x_write_reg_data_format(p_cdc, complete_cb ? ch34x_internal_control_complete : NULL, user_data)); + return true; } -static bool ch34x_set_baudrate(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { +static bool ch34x_set_baudrate(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { p_cdc->user_control_cb = complete_cb; TU_ASSERT(ch34x_write_reg_baudrate(p_cdc, complete_cb ? ch34x_internal_control_complete : NULL, user_data)); + return true; } -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 +static void ch34x_set_line_coding_stage1_complete(tuh_xfer_t * xfer) { + // CH34x only has 1 interface and wIndex used 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); 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, ch34x_internal_control_complete, xfer->user_data), ); + // stage 1 success, continue with stage 2 + p_cdc->user_control_cb = p_cdc->requested_complete_cb; + ch34x_write_reg_data_format(p_cdc, ch34x_internal_control_complete, xfer->user_data); } else { // stage 1 failed, notify user - xfer->complete_cb = p_cdc->user_control_cb; + xfer->complete_cb = p_cdc->requested_complete_cb; if (xfer->complete_cb) { xfer->complete_cb(xfer); } @@ -1466,49 +1490,46 @@ static void ch34x_set_line_coding_stage1_complete(tuh_xfer_t* xfer) { } // 2 stages: set baudrate (stage1) + set data format (stage2) -static bool ch34x_set_line_coding(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - p_cdc->user_control_cb = complete_cb; - +static bool ch34x_set_line_coding(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { if (complete_cb) { // stage 1 set baudrate - TU_ASSERT(ch34x_write_reg_baudrate(p_cdc, ch34x_set_line_coding_stage1_complete, user_data)); + p_cdc->requested_complete_cb = complete_cb; + p_cdc->user_control_cb = ch34x_set_line_coding_stage1_complete; + return ch34x_write_reg_baudrate(p_cdc, ch34x_internal_control_complete, user_data); } else { - // sync call - xfer_result_t result; - + // blocking sequence // stage 1 set baudrate - TU_ASSERT(ch34x_write_reg_baudrate(p_cdc, NULL, (uintptr_t) &result)); + xfer_result_t result = XFER_RESULT_INVALID; // use local result, because user_data ptr may be NULL + bool ret = ch34x_write_reg_baudrate(p_cdc, NULL, (uintptr_t) &result); + + // store/check results + if (user_data) { + *((xfer_result_t*) user_data) = result; + } + TU_ASSERT(ret); TU_VERIFY(result == XFER_RESULT_SUCCESS); + + // overtake baudrate p_cdc->line_coding.bit_rate = p_cdc->requested_line_coding.bit_rate; // stage 2 set data format - TU_ASSERT(ch34x_set_data_format(p_cdc, NULL, (uintptr_t) &result)); - TU_VERIFY(result == XFER_RESULT_SUCCESS); + result = XFER_RESULT_INVALID; + ret = ch34x_write_reg_data_format(p_cdc, NULL, (uintptr_t) &result); - // update transfer result, user_data is expected to point to xfer_result_t + // store/check results if (user_data) { *((xfer_result_t*) user_data) = result; } + TU_ASSERT(ret); + return (result == XFER_RESULT_SUCCESS); + // the overtaking of remaining requested_line_coding will be done in tuh_cdc_set_line_coding() } - - return true; } -static bool ch34x_set_modem_ctrl(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - uint8_t control = 0; - if (p_cdc->requested_line_state & CDC_CONTROL_LINE_STATE_RTS) { - control |= CH34X_BIT_RTS; - } - if (p_cdc->requested_line_state & CDC_CONTROL_LINE_STATE_DTR) { - control |= CH34X_BIT_DTR; - } - - // CH34x signals are inverted - control = ~control; - +static bool ch34x_set_modem_ctrl(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { p_cdc->user_control_cb = complete_cb; - TU_ASSERT (ch34x_control_out(p_cdc, CH34X_REQ_MODEM_CTRL, control, 0, - complete_cb ? ch34x_internal_control_complete : NULL, user_data)); + TU_ASSERT(ch34x_modem_ctrl_request(p_cdc, complete_cb ? ch34x_internal_control_complete : NULL, user_data)); + return true; } @@ -1549,25 +1570,27 @@ static bool ch34x_open(uint8_t daddr, tusb_desc_interface_t const* itf_desc, uin } static void ch34x_process_config(tuh_xfer_t* xfer) { - // CH34x only has 1 interface and use wIndex as payload and not for bInterfaceNumber + // CH34x only has 1 interface and wIndex used as payload and not for bInterfaceNumber + uintptr_t const state = xfer->user_data; 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_COMPLETE(p_cdc && xfer->result == XFER_RESULT_SUCCESS); - uintptr_t const state = xfer->user_data; uint8_t buffer[2]; // TODO remove switch (state) { case CONFIG_CH34X_READ_VERSION: + p_cdc->user_control_cb = ch34x_process_config; // set once for whole process config TU_ASSERT_COMPLETE(ch34x_control_in(p_cdc, CH34X_REQ_READ_VERSION, 0, 0, buffer, 2, - ch34x_process_config, CONFIG_CH34X_SERIAL_INIT)); + ch34x_process_config, CONFIG_CH34X_SERIAL_INIT)); break; case CONFIG_CH34X_SERIAL_INIT: { // handle version read data, set CH34x line coding (incl. baudrate) uint8_t const version = xfer->buffer[0]; TU_LOG_P_CDC("Chip Version = %02x", version); - // only versions >= 0x30 are tested, below 0x30 seems having other programming, see drivers from WCH vendor, Linux kernel and FreeBSD + // only versions >= 0x30 are tested, below 0x30 seems having other programming + // see drivers from WCH vendor, Linux kernel and FreeBSD TU_ASSERT_COMPLETE(version >= 0x30); // init CH34x with line coding p_cdc->requested_line_coding = (cdc_line_coding_t) CFG_TUH_CDC_LINE_CODING_ON_ENUM_CH34X; @@ -1584,19 +1607,19 @@ static void ch34x_process_config(tuh_xfer_t* xfer) { // 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_COMPLETE(ch34x_write_reg(p_cdc, TU_U16(CH341_REG_0x0F, CH341_REG_0x2C), 0x0007, - ch34x_process_config, CONFIG_CH34X_FLOW_CONTROL)); + ch34x_process_config, CONFIG_CH34X_FLOW_CONTROL)); break; case CONFIG_CH34X_FLOW_CONTROL: // no hardware flow control TU_ASSERT_COMPLETE(ch34x_write_reg(p_cdc, TU_U16(CH341_REG_0x27, CH341_REG_0x27), 0x0000, - ch34x_process_config, CONFIG_CH34X_MODEM_CONTROL)); + 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) p_cdc->requested_line_state = CFG_TUH_CDC_LINE_CONTROL_ON_ENUM; - TU_ASSERT_COMPLETE(ch34x_set_modem_ctrl(p_cdc, ch34x_process_config, CONFIG_CH34X_COMPLETE)); + TU_ASSERT_COMPLETE(ch34x_modem_ctrl_request(p_cdc, ch34x_internal_control_complete, CONFIG_CH34X_COMPLETE)); break; case CONFIG_CH34X_COMPLETE: @@ -1668,7 +1691,7 @@ static uint8_t ch34x_get_lcr(cdch_interface_t * p_cdc) { uint8_t const data_bits = p_cdc->requested_line_coding.data_bits; uint8_t lcr = CH34X_LCR_ENABLE_RX | CH34X_LCR_ENABLE_TX; - TU_VERIFY(data_bits >= 5 && data_bits <= 8, 0); + TU_VERIFY(data_bits >= 5 && data_bits <= 8); lcr |= (uint8_t) (data_bits - 5); switch(parity) { @@ -1695,7 +1718,7 @@ static uint8_t ch34x_get_lcr(cdch_interface_t * p_cdc) { } // 1.5 stop bits not supported - TU_VERIFY(stop_bits != CDC_LINE_CODING_STOP_BITS_1_5, 0); + TU_VERIFY(stop_bits != CDC_LINE_CODING_STOP_BITS_1_5); if (stop_bits == CDC_LINE_CODING_STOP_BITS_2) { lcr |= CH34X_LCR_STOP_BITS_2; } -- cgit v1.3.1 From db511fb2f3df190f538d84d08b6be83746adae0e Mon Sep 17 00:00:00 2001 From: IngHK Date: Mon, 19 Feb 2024 08:05:16 +0100 Subject: fixed CFG_TUH_CDC_LINE_CONTROL_ON_ENUM handling. only set if defined. value 0 is also valid --- src/class/cdc/cdc_host.c | 17 ++++++++++------- src/class/cdc/cdc_host.h | 10 ---------- 2 files changed, 10 insertions(+), 17 deletions(-) (limited to 'src/class') diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index f6804ca2b..850c1fceb 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -886,7 +886,7 @@ static void acm_process_config(tuh_xfer_t* xfer) { switch (state) { case CONFIG_ACM_SET_CONTROL_LINE_STATE: - #if CFG_TUH_CDC_LINE_CONTROL_ON_ENUM + #ifdef CFG_TUH_CDC_LINE_CONTROL_ON_ENUM if (p_cdc->acm_capability.support_line_request) { p_cdc->requested_line_state = CFG_TUH_CDC_LINE_CONTROL_ON_ENUM; TU_ASSERT_COMPLETE(acm_set_control_line_state(p_cdc, acm_process_config, CONFIG_ACM_SET_LINE_CODING), 1); @@ -1060,7 +1060,7 @@ static void ftdi_process_config(tuh_xfer_t* xfer) { break; case CONFIG_FTDI_MODEM_CTRL: - #if CFG_TUH_CDC_LINE_CONTROL_ON_ENUM + #ifdef CFG_TUH_CDC_LINE_CONTROL_ON_ENUM p_cdc->requested_line_state = CFG_TUH_CDC_LINE_CONTROL_ON_ENUM; TU_ASSERT_COMPLETE(ftdi_sio_set_modem_ctrl(p_cdc, ftdi_process_config, CONFIG_FTDI_SET_BAUDRATE)); break; @@ -1291,7 +1291,7 @@ static void cp210x_process_config(tuh_xfer_t* xfer) { } case CONFIG_CP210X_SET_DTR_RTS: - #if CFG_TUH_CDC_LINE_CONTROL_ON_ENUM + #ifdef CFG_TUH_CDC_LINE_CONTROL_ON_ENUM p_cdc->requested_line_state = CFG_TUH_CDC_LINE_CONTROL_ON_ENUM; TU_ASSERT_COMPLETE(cp210x_set_modem_ctrl(p_cdc, cp210x_process_config, CONFIG_CP210X_COMPLETE)); break; @@ -1617,10 +1617,13 @@ static void ch34x_process_config(tuh_xfer_t* xfer) { break; case CONFIG_CH34X_MODEM_CONTROL: - // !always! set modem controls RTS/DTR (CH34x has no reset state after CH34X_REQ_SERIAL_INIT) - p_cdc->requested_line_state = CFG_TUH_CDC_LINE_CONTROL_ON_ENUM; - TU_ASSERT_COMPLETE(ch34x_modem_ctrl_request(p_cdc, ch34x_internal_control_complete, CONFIG_CH34X_COMPLETE)); - break; + #ifdef CFG_TUH_CDC_LINE_CONTROL_ON_ENUM + p_cdc->requested_line_state = CFG_TUH_CDC_LINE_CONTROL_ON_ENUM; + TU_ASSERT_COMPLETE(ch34x_modem_ctrl_request(p_cdc, ch34x_internal_control_complete, CONFIG_CH34X_COMPLETE)); + break; + #else + TU_ATTR_FALLTHROUGH; + #endif case CONFIG_CH34X_COMPLETE: set_config_complete(idx, 0, true); diff --git a/src/class/cdc/cdc_host.h b/src/class/cdc/cdc_host.h index d512a23a5..ca6567453 100644 --- a/src/class/cdc/cdc_host.h +++ b/src/class/cdc/cdc_host.h @@ -37,16 +37,6 @@ // Class Driver Configuration //--------------------------------------------------------------------+ -// Set Line Control state on enumeration/mounted: DTR ( bit 0), RTS (bit 1) -#ifndef CFG_TUH_CDC_LINE_CONTROL_ON_ENUM -#define CFG_TUH_CDC_LINE_CONTROL_ON_ENUM 0 -#endif - -// 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_CODING_STOP_BITS_1, CDC_LINE_CODING_PARITY_NONE, 8 } -//#endif - // RX FIFO size #ifndef CFG_TUH_CDC_RX_BUFSIZE #define CFG_TUH_CDC_RX_BUFSIZE USBH_EPSIZE_BULK_MAX -- cgit v1.3.1 From 0b5f85eee0f34a80dd8debe2f764607070293119 Mon Sep 17 00:00:00 2001 From: IngHK Date: Wed, 21 Feb 2024 17:25:13 +0100 Subject: created set_line_coding_sequence() and void set_line_coding_stage1_complete() to be reused by FTDI & CP210x --- src/class/cdc/cdc_host.c | 131 +++++++++++++++++++++++++++++------------------ 1 file changed, 81 insertions(+), 50 deletions(-) (limited to 'src/class') diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index 850c1fceb..8deeffc37 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -433,6 +433,77 @@ bool tuh_cdc_read_clear (uint8_t idx) { // Control Endpoint API //--------------------------------------------------------------------+ +// set line coding using sequence with 2 stages: set baudrate (stage1) + set data format (stage2) +static bool set_line_coding_sequence( + cdch_interface_t * p_cdc, + // control request function to set baudrate + bool (*set_baudrate_request)(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data), + // control request function to set data format + bool (*set_data_format_request)(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data), + // function to be called after stage 1 completed + void (*set_line_coding_stage1_complete)(tuh_xfer_t * xfer), + // control complete function to be called after request + void (*internal_control_complete)(tuh_xfer_t * xfer), + tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + if (complete_cb) { + // non-blocking + // stage 1 set baudrate + p_cdc->requested_complete_cb = complete_cb; // store complete_cb to be used in set_line_coding_stage1_complete() + p_cdc->user_control_cb = set_line_coding_stage1_complete; + return set_baudrate_request(p_cdc, internal_control_complete, user_data); + } else { + // blocking sequence + // stage 1 set baudrate + xfer_result_t result = XFER_RESULT_INVALID; // use local result, because user_data ptr may be NULL + bool ret = set_baudrate_request(p_cdc, NULL, (uintptr_t) &result); + + if (user_data) { + *((xfer_result_t *) user_data) = result; + } + + TU_ASSERT(ret); + TU_VERIFY(result == XFER_RESULT_SUCCESS); + + // overtake baudrate after successful request + p_cdc->line_coding.bit_rate = p_cdc->requested_line_coding.bit_rate; + + // stage 2 set data format + result = XFER_RESULT_INVALID; + ret = set_data_format_request(p_cdc, NULL, (uintptr_t) &result); + + if (user_data) { + *((xfer_result_t *) user_data) = result; + } + + TU_ASSERT(ret); + return (result == XFER_RESULT_SUCCESS); + // the overtaking of remaining requested_line_coding will be done in tuh_cdc_set_line_coding() + } +} + +static void set_line_coding_stage1_complete( + tuh_xfer_t * xfer, uint8_t const itf_num, + // control request function to set data format + bool (*set_data_format_request)(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data), + // control complete function to be called after request + void (*internal_control_complete)(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); + TU_ASSERT(p_cdc,); + + if (xfer->result == XFER_RESULT_SUCCESS) { + // stage 1 success, continue with stage 2 + p_cdc->user_control_cb = p_cdc->requested_complete_cb; + set_data_format_request(p_cdc, internal_control_complete, xfer->user_data); + } else { + // stage 1 failed, notify user + xfer->complete_cb = p_cdc->requested_complete_cb; + if (xfer->complete_cb) { + xfer->complete_cb(xfer); + } + } +} + // call of (non-)blocking set-functions (to set line state, baudrate, ...) static bool set_function_call ( cdch_interface_t * p_cdc, @@ -1470,60 +1541,20 @@ static bool ch34x_set_baudrate(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_ } static void ch34x_set_line_coding_stage1_complete(tuh_xfer_t * xfer) { - // CH34x only has 1 interface and wIndex used 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); - TU_ASSERT(p_cdc, ); - - if (xfer->result == XFER_RESULT_SUCCESS) { - // stage 1 success, continue with stage 2 - p_cdc->user_control_cb = p_cdc->requested_complete_cb; - ch34x_write_reg_data_format(p_cdc, ch34x_internal_control_complete, xfer->user_data); - } else { - // stage 1 failed, notify user - xfer->complete_cb = p_cdc->requested_complete_cb; - if (xfer->complete_cb) { - xfer->complete_cb(xfer); - } - } + uint8_t const itf_num = 0; // CH34x has only interface 0, because wIndex is used as payload and not for bInterfaceNumber + set_line_coding_stage1_complete(xfer, itf_num, + ch34x_write_reg_data_format, // control request function to set data format + ch34x_internal_control_complete); // control complete function to be called after request } // 2 stages: set baudrate (stage1) + set data format (stage2) static bool ch34x_set_line_coding(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - if (complete_cb) { - // stage 1 set baudrate - p_cdc->requested_complete_cb = complete_cb; - p_cdc->user_control_cb = ch34x_set_line_coding_stage1_complete; - return ch34x_write_reg_baudrate(p_cdc, ch34x_internal_control_complete, user_data); - } else { - // blocking sequence - // stage 1 set baudrate - xfer_result_t result = XFER_RESULT_INVALID; // use local result, because user_data ptr may be NULL - bool ret = ch34x_write_reg_baudrate(p_cdc, NULL, (uintptr_t) &result); - - // store/check results - if (user_data) { - *((xfer_result_t*) user_data) = result; - } - TU_ASSERT(ret); - TU_VERIFY(result == XFER_RESULT_SUCCESS); - - // overtake baudrate - p_cdc->line_coding.bit_rate = p_cdc->requested_line_coding.bit_rate; - - // stage 2 set data format - result = XFER_RESULT_INVALID; - ret = ch34x_write_reg_data_format(p_cdc, NULL, (uintptr_t) &result); - - // store/check results - if (user_data) { - *((xfer_result_t*) user_data) = result; - } - TU_ASSERT(ret); - return (result == XFER_RESULT_SUCCESS); - // the overtaking of remaining requested_line_coding will be done in tuh_cdc_set_line_coding() - } + return set_line_coding_sequence(p_cdc, + ch34x_write_reg_baudrate, // control request function to set baudrate + ch34x_write_reg_data_format, // control request function to set data format + ch34x_set_line_coding_stage1_complete, // function to be called after stage 1 completed + ch34x_internal_control_complete, // control complete function to be called after request + complete_cb, user_data); } static bool ch34x_set_modem_ctrl(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { -- cgit v1.3.1 From 7fef5943eff0d7f1b7122e878cf2caa78bea06aa Mon Sep 17 00:00:00 2001 From: IngHK Date: Sat, 24 Feb 2024 12:58:45 +0100 Subject: improved FTDI support --- src/class/cdc/cdc_host.c | 503 +++++++++++++++++++++++++++++++++------- src/class/cdc/serial/ftdi_sio.h | 385 +++++++++++++++--------------- src/tusb_option.h | 19 +- 3 files changed, 616 insertions(+), 291 deletions(-) (limited to 'src/class') diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index 8deeffc37..f9540efbe 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -35,6 +35,9 @@ #include "host/usbh_pvt.h" #include "cdc_host.h" +#include "serial/ftdi_sio.h" +#include "serial/cp210x.h" +#include "serial/ch34x.h" // Level where CFG_TUSB_DEBUG must be at least for this driver is logged #ifndef CFG_TUH_CDC_LOG_LEVEL @@ -80,10 +83,14 @@ typedef struct { uint8_t requested_line_state; tuh_xfer_cb_t user_control_cb; - #if CFG_TUH_CDC_CH34X + #if CFG_TUH_CDC_FTDI || CFG_TUH_CDC_CH34X tuh_xfer_cb_t requested_complete_cb; #endif + #if CFG_TUH_CDC_FTDI + ftdi_private_t ftdi; + #endif + struct { tu_edpt_stream_t tx; tu_edpt_stream_t rx; @@ -98,6 +105,9 @@ typedef struct { CFG_TUH_MEM_SECTION static cdch_interface_t cdch_data[CFG_TUH_CDC]; +#if CFG_TUH_CDC_FTDI + static tusb_desc_device_t desc_dev[CFG_TUH_CDC][CFG_TUH_ENUMERATION_BUFSIZE]; +#endif //--------------------------------------------------------------------+ // Serial Driver @@ -114,23 +124,22 @@ static bool acm_set_control_line_state(cdch_interface_t* p_cdc, tuh_xfer_cb_t co //------------- FTDI prototypes -------------// #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}; +#if CFG_TUSB_DEBUG && CFG_TUSB_DEBUG >= CFG_TUH_CDC_LOG_LEVEL +static uint8_t const * ftdi_chip_name[] = { FTDI_CHIP_NAMES }; +#endif 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, tuh_xfer_cb_t complete_cb, uintptr_t user_data); +static bool ftdi_set_baudrate(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); static bool ftdi_set_data_format(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); static bool ftdi_set_line_coding(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); -static bool ftdi_sio_set_modem_ctrl(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); +static bool ftdi_set_modem_ctrl(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); #endif //------------- CP210X prototypes -------------// #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}; static bool cp210x_open(uint8_t daddr, tusb_desc_interface_t const *itf_desc, uint16_t max_len); @@ -144,8 +153,6 @@ static bool cp210x_set_modem_ctrl(cdch_interface_t* p_cdc, tuh_xfer_cb_t complet //------------- CH34x prototypes -------------// #if CFG_TUH_CDC_CH34X -#include "serial/ch34x.h" - 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); @@ -212,8 +219,8 @@ static const cdch_serial_driver_t serial_drivers[] = { .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, + .set_control_line_state = ftdi_set_modem_ctrl, + .set_baudrate = ftdi_set_baudrate, .set_data_format = ftdi_set_data_format, .set_line_coding = ftdi_set_line_coding, #if CFG_TUSB_DEBUG && CFG_TUSB_DEBUG >= CFG_TUH_CDC_LOG_LEVEL @@ -992,28 +999,27 @@ static void acm_process_config(tuh_xfer_t* xfer) { //--------------------------------------------------------------------+ #if CFG_TUH_CDC_FTDI -static uint32_t ftdi_232bm_baud_to_divisor(cdch_interface_t* p_cdc); +static bool ftdi_determine_type(cdch_interface_t * p_cdc, uint8_t const idx); +static uint32_t ftdi_get_divisor(cdch_interface_t * p_cdc); +static uint8_t ftdi_get_idx(tuh_xfer_t * xfer); //------------- Control Request -------------// // set request without data -static bool ftdi_sio_set_request(cdch_interface_t* p_cdc, uint8_t command, uint16_t value, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - tusb_control_request_t const request = { - .bmRequestType_bit = { - .recipient = TUSB_REQ_RCPT_DEVICE, - .type = TUSB_REQ_TYPE_VENDOR, - .direction = TUSB_DIR_OUT - }, - .bRequest = command, - .wValue = tu_htole16(value), - .wIndex = 0, - .wLength = 0 +static bool ftdi_set_request(cdch_interface_t * p_cdc, uint8_t request, uint8_t requesttype, + uint16_t value, uint16_t index, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + tusb_control_request_t const request_setup = { + .bmRequestType = requesttype, + .bRequest = request, + .wValue = tu_htole16(value), + .wIndex = tu_htole16(index), + .wLength = 0 }; tuh_xfer_t xfer = { .daddr = p_cdc->daddr, .ep_addr = 0, - .setup = &request, + .setup = &request_setup, .buffer = NULL, .complete_cb = complete_cb, .user_data = user_data @@ -1022,16 +1028,57 @@ 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) { - return ftdi_sio_set_request(p_cdc, FTDI_SIO_RESET, FTDI_SIO_RESET_SIO, complete_cb, user_data); +#ifdef CFG_TUH_CDC_FTDI_LATENCY +static int8_t ftdi_write_latency_timer(cdch_interface_t * p_cdc, uint16_t latency, + tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + if (p_cdc->ftdi.chip_type == SIO /* || p_cdc->ftdi.chip_type == FT232A */ ) + return FTDI_NOT_POSSIBLE; + return ftdi_set_request(p_cdc, FTDI_SIO_SET_LATENCY_TIMER_REQUEST, FTDI_SIO_SET_LATENCY_TIMER_REQUEST_TYPE, + latency, p_cdc->ftdi.channel, complete_cb, user_data) ? FTDI_REQUESTED : FTDI_FAIL; +} +#endif + +static inline bool ftdi_sio_reset(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + return ftdi_set_request(p_cdc, FTDI_SIO_RESET_REQUEST, FTDI_SIO_RESET_REQUEST_TYPE, FTDI_SIO_RESET_SIO, + p_cdc->ftdi.channel, complete_cb, user_data); +} + +static bool ftdi_change_speed(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + uint32_t index_value = ftdi_get_divisor(p_cdc); + TU_VERIFY(index_value); + uint16_t value = (uint16_t) index_value; + uint16_t index = (uint16_t) (index_value >> 16); + if (p_cdc->ftdi.channel) { + index = (uint16_t)((index << 8) | p_cdc->ftdi.channel); + } + + return ftdi_set_request(p_cdc, FTDI_SIO_SET_BAUDRATE_REQUEST, FTDI_SIO_SET_BAUDRATE_REQUEST_TYPE, + value, index, complete_cb, user_data); +} + +static bool ftdi_set_data_request(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + TU_VERIFY(p_cdc->requested_line_coding.data_bits >= 7 && p_cdc->requested_line_coding.data_bits <= 8, 0); + uint16_t value = (uint16_t) ( + ((uint32_t) p_cdc->requested_line_coding.data_bits & 0xf) | // data bit quantity is stored in bits 0-3 + ((uint32_t) p_cdc->requested_line_coding.parity & 0x7) << 8 | // parity is stored in bits 8-10, same coding + ((uint32_t) p_cdc->requested_line_coding.stop_bits & 0x3) << 11 ); // stop bits quantity is stored in bits 11-12, same coding + // not each FTDI supports 1.5 stop bits + + return ftdi_set_request(p_cdc, FTDI_SIO_SET_DATA_REQUEST, FTDI_SIO_SET_DATA_REQUEST_TYPE, + value, p_cdc->ftdi.channel, complete_cb, user_data); +} + +static inline bool ftdi_update_mctrl(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + // FTDI has the same bit coding + return ftdi_set_request(p_cdc, FTDI_SIO_SET_MODEM_CTRL_REQUEST, FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE, + p_cdc->requested_line_state, p_cdc->ftdi.channel, complete_cb, user_data); } //------------- Driver API -------------// // internal control complete to update state such as line state, line_coding static void ftdi_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); + uint8_t const idx = ftdi_get_idx(xfer); cdch_interface_t * p_cdc = get_itf(idx); TU_ASSERT(p_cdc,); bool const success = (xfer->result == XFER_RESULT_SUCCESS); @@ -1039,11 +1086,17 @@ static void ftdi_internal_control_complete(tuh_xfer_t * xfer) { if (success) { switch (xfer->setup->bRequest) { - case FTDI_SIO_MODEM_CTRL: + case FTDI_SIO_SET_MODEM_CTRL_REQUEST: p_cdc->line_state = p_cdc->requested_line_state; break; - case FTDI_SIO_SET_BAUD_RATE: + case FTDI_SIO_SET_DATA_REQUEST: + 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; + + case FTDI_SIO_SET_BAUDRATE_REQUEST: p_cdc->line_coding.bit_rate = p_cdc->requested_line_coding.bit_rate; break; @@ -1057,52 +1110,62 @@ static void ftdi_internal_control_complete(tuh_xfer_t * xfer) { } } -static bool ftdi_sio_set_baudrate(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - uint16_t const divisor = (uint16_t) ftdi_232bm_baud_to_divisor(p_cdc); +static bool ftdi_set_data_format(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + p_cdc->user_control_cb = complete_cb; + TU_ASSERT(ftdi_set_data_request(p_cdc, complete_cb ? ftdi_internal_control_complete : NULL, user_data)); + + return true; +} +static bool ftdi_set_baudrate(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { p_cdc->user_control_cb = complete_cb; - TU_ASSERT(ftdi_sio_set_request(p_cdc, FTDI_SIO_SET_BAUD_RATE, divisor, - complete_cb ? ftdi_internal_control_complete : NULL, user_data)); + TU_ASSERT(ftdi_change_speed(p_cdc, complete_cb ? ftdi_internal_control_complete : NULL, user_data)); return true; } -static bool ftdi_set_data_format(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - (void) p_cdc; - (void) complete_cb; - (void) user_data; - // TODO not implemented yet - return false; +static void ftdi_set_line_coding_stage1_complete(tuh_xfer_t * xfer) { + uint8_t const itf_num = (uint8_t) tu_le16toh(xfer->setup->wIndex); + set_line_coding_stage1_complete(xfer, itf_num, + ftdi_set_data_request, // control request function to set data format + ftdi_internal_control_complete); // control complete function to be called after request } -static bool ftdi_set_line_coding(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - (void) p_cdc; - (void) complete_cb; - (void) user_data; - // TODO not implemented yet - return false; +// 2 stages: set baudrate (stage1) + set data format (stage2) +static bool ftdi_set_line_coding(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + return set_line_coding_sequence(p_cdc, + ftdi_change_speed, // control request function to set baudrate + ftdi_set_data_request, // control request function to set data format + ftdi_set_line_coding_stage1_complete, // function to be called after stage 1 completed + ftdi_internal_control_complete, // control complete function to be called after request + complete_cb, user_data); } -static bool ftdi_sio_set_modem_ctrl(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { +static bool ftdi_set_modem_ctrl(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { p_cdc->user_control_cb = complete_cb; - TU_ASSERT(ftdi_sio_set_request(p_cdc, FTDI_SIO_MODEM_CTRL, 0x0300 | p_cdc->requested_line_state, - complete_cb ? ftdi_internal_control_complete : NULL, user_data)); + TU_ASSERT(ftdi_update_mctrl(p_cdc, complete_cb ? ftdi_internal_control_complete : NULL, user_data)); + return true; } //------------- Enumeration -------------// enum { - CONFIG_FTDI_RESET = 0, - CONFIG_FTDI_MODEM_CTRL, - CONFIG_FTDI_SET_BAUDRATE, + CONFIG_FTDI_GET_DESC = 0, + CONFIG_FTDI_DETERMINE_TYPE, + CONFIG_FTDI_WRITE_LATENCY, + CONFIG_FTDI_SIO_RESET, CONFIG_FTDI_SET_DATA, + CONFIG_FTDI_SET_BAUDRATE, + CONFIG_FTDI_FLOW_CONTROL, + CONFIG_FTDI_MODEM_CTRL, CONFIG_FTDI_COMPLETE }; -static bool ftdi_open(uint8_t daddr, const tusb_desc_interface_t *itf_desc, uint16_t max_len) { +static bool ftdi_open(uint8_t daddr, const tusb_desc_interface_t * itf_desc, uint16_t max_len) { // FTDI Interface includes 1 vendor interface + 2 bulk endpoints - TU_VERIFY(itf_desc->bInterfaceSubClass == 0xff && itf_desc->bInterfaceProtocol == 0xff && itf_desc->bNumEndpoints == 2); + TU_VERIFY(itf_desc->bInterfaceSubClass == 0xff && itf_desc->bInterfaceProtocol == 0xff && + itf_desc->bNumEndpoints == 2); 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); @@ -1113,53 +1176,96 @@ static bool ftdi_open(uint8_t daddr, const tusb_desc_interface_t *itf_desc, uint // endpoint pair tusb_desc_endpoint_t const * desc_ep = (tusb_desc_endpoint_t const *) tu_desc_next(itf_desc); + /* + * NOTE: Some customers have programmed FT232R/FT245R devices + * with an endpoint size of 0 - not good. + */ + TU_ASSERT(desc_ep->wMaxPacketSize != 0); + // data endpoints expected to be in pairs return open_ep_stream_pair(p_cdc, desc_ep); } -static void ftdi_process_config(tuh_xfer_t* xfer) { +static void ftdi_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); + uint8_t const idx = ftdi_get_idx(xfer); cdch_interface_t * p_cdc = get_itf(idx); TU_ASSERT_COMPLETE(p_cdc && xfer->result == XFER_RESULT_SUCCESS); + uint8_t const itf_num = p_cdc->bInterfaceNumber; switch(state) { - // Note may need to read FTDI eeprom - case CONFIG_FTDI_RESET: - TU_ASSERT_COMPLETE(ftdi_sio_reset(p_cdc, ftdi_process_config, CONFIG_FTDI_MODEM_CTRL)); + + // from here sequence overtaken from Linux Kernel function ftdi_port_probe() + case CONFIG_FTDI_GET_DESC: + // get device descriptor + p_cdc->user_control_cb = ftdi_process_config; // set once for whole process config + if (itf_num == 0) { // only necessary for 1st interface. other interface overtake type from interface 0 + TU_ASSERT_COMPLETE(tuh_descriptor_get_device(xfer->daddr, desc_dev[idx], sizeof(tusb_desc_device_t), + ftdi_process_config, CONFIG_FTDI_DETERMINE_TYPE)); + break; + } + TU_ATTR_FALLTHROUGH; + + case CONFIG_FTDI_DETERMINE_TYPE: + // determine type + if (itf_num == 0) { + TU_ASSERT_COMPLETE(ftdi_determine_type(p_cdc, idx)); + } else { + // other interfaces have same type as interface 0 + uint8_t const idx_itf0 = tuh_cdc_itf_get_index(xfer->daddr, 0); + cdch_interface_t const * p_cdc_itf0 = get_itf(idx_itf0); + p_cdc->ftdi.chip_type = p_cdc_itf0->ftdi.chip_type; + } + TU_ATTR_FALLTHROUGH; + + case CONFIG_FTDI_WRITE_LATENCY: + #ifdef CFG_TUH_CDC_FTDI_LATENCY + int8_t result = ftdi_write_latency_timer(p_cdc, CFG_TUH_CDC_FTDI_LATENCY, ftdi_process_config, + CONFIG_FTDI_SIO_RESET); + TU_ASSERT_COMPLETE(result != FTDI_FAIL); + if(result == FTDI_REQUESTED) { + break; + } // else FTDI_NOT_POSSIBLE => continue directly with next state + #endif + TU_ATTR_FALLTHROUGH; + + // from here sequence overtaken from Linux Kernel function ftdi_open() + case CONFIG_FTDI_SIO_RESET: + TU_ASSERT_COMPLETE(ftdi_sio_reset(p_cdc, ftdi_process_config, CONFIG_FTDI_SET_DATA)); break; - case CONFIG_FTDI_MODEM_CTRL: - #ifdef CFG_TUH_CDC_LINE_CONTROL_ON_ENUM - p_cdc->requested_line_state = CFG_TUH_CDC_LINE_CONTROL_ON_ENUM; - TU_ASSERT_COMPLETE(ftdi_sio_set_modem_ctrl(p_cdc, ftdi_process_config, CONFIG_FTDI_SET_BAUDRATE)); + // from here sequence overtaken from Linux Kernel function ftdi_set_termios() + case CONFIG_FTDI_SET_DATA: + #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM + p_cdc->requested_line_coding = (cdc_line_coding_t) CFG_TUH_CDC_LINE_CODING_ON_ENUM; + TU_ASSERT_COMPLETE(ftdi_set_data_request(p_cdc, ftdi_internal_control_complete, CONFIG_FTDI_SET_BAUDRATE)); break; #else TU_ATTR_FALLTHROUGH; #endif - case CONFIG_FTDI_SET_BAUDRATE: { + case CONFIG_FTDI_SET_BAUDRATE: #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM - p_cdc->requested_line_coding.bit_rate = ((cdc_line_coding_t) CFG_TUH_CDC_LINE_CODING_ON_ENUM).bit_rate; - TU_ASSERT_COMPLETE(ftdi_sio_set_baudrate(p_cdc, ftdi_process_config, CONFIG_FTDI_SET_DATA)); + TU_ASSERT_COMPLETE(ftdi_change_speed(p_cdc, ftdi_internal_control_complete, CONFIG_FTDI_FLOW_CONTROL)); break; #else TU_ATTR_FALLTHROUGH; #endif - } - case CONFIG_FTDI_SET_DATA: { - #if 0 // TODO set data format - #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM - cdc_line_coding_t line_coding = CFG_TUH_CDC_LINE_CODING_ON_ENUM; - TU_ASSERT_COMPLETE(ftdi_sio_set_data(p_cdc, process_ftdi_config, CONFIG_FTDI_COMPLETE)); + case CONFIG_FTDI_FLOW_CONTROL: + // disable flow control + TU_ASSERT_COMPLETE(ftdi_set_request(p_cdc, FTDI_SIO_SET_FLOW_CTRL_REQUEST, FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE, + 0, FTDI_SIO_DISABLE_FLOW_CTRL, ftdi_process_config, CONFIG_FTDI_MODEM_CTRL)); break; - #endif - #endif - TU_ATTR_FALLTHROUGH; - } + case CONFIG_FTDI_MODEM_CTRL: + #ifdef CFG_TUH_CDC_LINE_CONTROL_ON_ENUM + p_cdc->requested_line_state = CFG_TUH_CDC_LINE_CONTROL_ON_ENUM; + TU_ASSERT_COMPLETE(ftdi_update_mctrl(p_cdc, ftdi_internal_control_complete, CONFIG_FTDI_COMPLETE)); + break; + #else + TU_ATTR_FALLTHROUGH; + #endif case CONFIG_FTDI_COMPLETE: set_config_complete(idx, 0, true); @@ -1173,28 +1279,249 @@ static void ftdi_process_config(tuh_xfer_t* xfer) { //------------- Helper -------------// +static bool ftdi_determine_type(cdch_interface_t * p_cdc, uint8_t const idx) +{ + uint16_t const version = desc_dev[idx]->bcdDevice; + uint8_t const itf_num = p_cdc->bInterfaceNumber; + + p_cdc->ftdi.chip_type = UNKNOWN; + + /* Assume Hi-Speed type */ + p_cdc->ftdi.channel = CHANNEL_A + itf_num; + + switch (version) { + case 0x200: + // FT232A not supported to keep it simple (no extra _read_latency_timer()) + // not testable + // p_cdc->ftdi.chip_type = FT232A; + // p_cdc->ftdi.baud_base = 48000000 / 2; + // p_cdc->ftdi.channel = 0; + // /* + // * FT232B devices have a bug where bcdDevice gets set to 0x200 + // * when iSerialNumber is 0. Assume it is an FT232B in case the + // * latency timer is readable. + // */ + // if (desc->iSerialNumber == 0 && + // _read_latency_timer(port) >= 0) { + // p_cdc->ftdi.chip_type = FT232B; + // } + break; + case 0x400: + p_cdc->ftdi.chip_type = FT232B; + p_cdc->ftdi.channel = 0; + break; + case 0x500: + p_cdc->ftdi.chip_type = FT2232C; + break; + case 0x600: + p_cdc->ftdi.chip_type = FT232R; + p_cdc->ftdi.channel = 0; + break; + case 0x700: + p_cdc->ftdi.chip_type = FT2232H; + break; + case 0x800: + p_cdc->ftdi.chip_type = FT4232H; + break; + case 0x900: + p_cdc->ftdi.chip_type = FT232H; + break; + case 0x1000: + p_cdc->ftdi.chip_type = FTX; + break; + case 0x2800: + p_cdc->ftdi.chip_type = FT2233HP; + break; + case 0x2900: + p_cdc->ftdi.chip_type = FT4233HP; + break; + case 0x3000: + p_cdc->ftdi.chip_type = FT2232HP; + break; + case 0x3100: + p_cdc->ftdi.chip_type = FT4232HP; + break; + case 0x3200: + p_cdc->ftdi.chip_type = FT233HP; + break; + case 0x3300: + p_cdc->ftdi.chip_type = FT232HP; + break; + case 0x3600: + p_cdc->ftdi.chip_type = FT4232HA; + break; + default: + if (version < 0x200) { + p_cdc->ftdi.chip_type = SIO; + p_cdc->ftdi.channel = 0; + } + break; + } + + TU_LOG_P_CDC("%s detected", ftdi_chip_name[p_cdc->ftdi.chip_type]); + + return (p_cdc->ftdi.chip_type != UNKNOWN); +} + +// FT232A not supported +//static uint32_t ftdi_232am_baud_base_to_divisor(uint32_t baud, uint32_t base) +//{ +// uint32_t divisor; +// /* divisor shifted 3 bits to the left */ +// uint32_t divisor3 = DIV_ROUND_CLOSEST(base, 2 * baud); +// if ((divisor3 & 0x7) == 7) +// divisor3++; /* round x.7/8 up to x+1 */ +// divisor = divisor3 >> 3; +// divisor3 &= 0x7; +// if (divisor3 == 1) +// divisor |= 0xc000; /* +0.125 */ +// else if (divisor3 >= 4) +// divisor |= 0x4000; /* +0.5 */ +// else if (divisor3 != 0) +// divisor |= 0x8000; /* +0.25 */ +// else if (divisor == 1) +// divisor = 0; /* special case for maximum baud rate */ +// return divisor; +//} + +// FT232A not supported +//static inline uint32_t ftdi_232am_baud_to_divisor(uint32_t baud) +//{ +// return ftdi_232am_baud_base_to_divisor(baud, (uint32_t) 48000000); +//} + 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 }; + uint8_t divfrac[8] = { 0, 3, 2, 4, 1, 5, 6, 7 }; uint32_t divisor; - /* divisor shifted 3 bits to the left */ - uint32_t divisor3 = base / (2 * baud); - divisor = (divisor3 >> 3); - divisor |= (uint32_t) divfrac[divisor3 & 0x7] << 14; + uint32_t divisor3 = DIV_ROUND_CLOSEST(base, 2 * baud); + divisor = divisor3 >> 3; + divisor |= (uint32_t)divfrac[divisor3 & 0x7] << 14; + /* Deal with special cases for highest baud rates. */ + if (divisor == 1) /* 1.0 */ + divisor = 0; + else if (divisor == 0x4001) /* 1.5 */ + divisor = 1; + return divisor; +} + +static inline uint32_t ftdi_232bm_baud_to_divisor(uint32_t baud) +{ + return ftdi_232bm_baud_base_to_divisor(baud, 48000000); +} + +static uint32_t ftdi_2232h_baud_base_to_divisor(uint32_t baud, uint32_t base) +{ + static const unsigned char divfrac[8] = { 0, 3, 2, 4, 1, 5, 6, 7 }; + uint32_t divisor; + uint32_t divisor3; + + /* hi-speed baud rate is 10-bit sampling instead of 16-bit */ + divisor3 = DIV_ROUND_CLOSEST(8 * base, 10 * baud); + divisor = divisor3 >> 3; + divisor |= (uint32_t)divfrac[divisor3 & 0x7] << 14; /* Deal with special cases for highest baud rates. */ - if (divisor == 1) { /* 1.0 */ + if (divisor == 1) /* 1.0 */ divisor = 0; - } - else if (divisor == 0x4001) { /* 1.5 */ + else if (divisor == 0x4001) /* 1.5 */ divisor = 1; + /* + * Set this bit to turn off a divide by 2.5 on baud rate generator + * This enables baud rates up to 12Mbaud but cannot reach below 1200 + * baud with this bit set + */ + divisor |= 0x00020000; + return divisor; +} + +static inline uint32_t ftdi_2232h_baud_to_divisor(uint32_t baud) +{ + return ftdi_2232h_baud_base_to_divisor(baud, (uint32_t) 120000000); +} + +static inline uint32_t ftdi_get_divisor(cdch_interface_t * p_cdc) +{ + uint32_t baud = p_cdc->requested_line_coding.bit_rate; + uint32_t div_value = 0; + TU_VERIFY(baud); + + switch (p_cdc->ftdi.chip_type) { + case UNKNOWN: + return 0; + case SIO: + switch (baud) { + case 300: div_value = ftdi_sio_b300; break; + case 600: div_value = ftdi_sio_b600; break; + case 1200: div_value = ftdi_sio_b1200; break; + case 2400: div_value = ftdi_sio_b2400; break; + case 4800: div_value = ftdi_sio_b4800; break; + case 9600: div_value = ftdi_sio_b9600; break; + case 19200: div_value = ftdi_sio_b19200; break; + case 38400: div_value = ftdi_sio_b38400; break; + case 57600: div_value = ftdi_sio_b57600; break; + case 115200: div_value = ftdi_sio_b115200; break; + default: + // Baudrate not supported + return 0; + break; + } + break; + // FT232A not supported + // case FT232A: + // if (baud <= 3000000) { + // div_value = ftdi_232am_baud_to_divisor(baud); + // } else { + // // Baud rate too high! + // baud = 9600; + // div_value = ftdi_232am_baud_to_divisor(9600); + // div_okay = false; + // } + // break; + case FT232B: + case FT2232C: + case FT232R: + case FTX: + TU_VERIFY(baud <= 3000000); // else Baud rate too high! + div_value = ftdi_232bm_baud_to_divisor(baud); + break; + case FT232H: + case FT2232H: + case FT4232H: + case FT4232HA: + case FT232HP: + case FT233HP: + case FT2232HP: + case FT2233HP: + case FT4232HP: + case FT4233HP: + default: + TU_VERIFY(baud <= 12000000); // else Baud rate too high! + if (baud >= 1200) { + div_value = ftdi_2232h_baud_to_divisor(baud); + } else { + div_value = ftdi_232bm_baud_to_divisor(baud); + } + break; } - return divisor; + TU_LOG_P_CDC("Baudrate divisor 0x%lu", div_value); + + return div_value; } -static uint32_t ftdi_232bm_baud_to_divisor(cdch_interface_t* p_cdc) { - return ftdi_232bm_baud_base_to_divisor(p_cdc->requested_line_coding.bit_rate, 48000000u); +static uint8_t ftdi_get_idx(tuh_xfer_t * xfer) { + uint8_t const channel = (uint8_t) tu_le16toh(xfer->setup->wIndex); // channel index, or 0 for legacy types + 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 && + (!p_cdc->ftdi.channel || // 0 for legacy types (only interface 0) + channel == p_cdc->ftdi.channel)) { // or multi-channel types (interfaces 0..n) + return i; + } + } + + return TUSB_INDEX_INVALID_8; } #endif diff --git a/src/class/cdc/serial/ftdi_sio.h b/src/class/cdc/serial/ftdi_sio.h index 0825f0719..42716f73e 100644 --- a/src/class/cdc/serial/ftdi_sio.h +++ b/src/class/cdc/serial/ftdi_sio.h @@ -25,222 +25,207 @@ #ifndef TUSB_FTDI_SIO_H #define TUSB_FTDI_SIO_H -// VID for matching FTDI devices -#define TU_FTDI_VID 0x0403 +#include // Commands -#define FTDI_SIO_RESET 0 /* Reset the port */ -#define FTDI_SIO_MODEM_CTRL 1 /* Set the modem control register */ -#define FTDI_SIO_SET_FLOW_CTRL 2 /* Set flow control register */ -#define FTDI_SIO_SET_BAUD_RATE 3 /* Set baud rate */ -#define FTDI_SIO_SET_DATA 4 /* Set the data characteristics of the port */ -#define FTDI_SIO_GET_MODEM_STATUS 5 /* Retrieve current value of modem status register */ -#define FTDI_SIO_SET_EVENT_CHAR 6 /* Set the event character */ -#define FTDI_SIO_SET_ERROR_CHAR 7 /* Set the error character */ -#define FTDI_SIO_SET_LATENCY_TIMER 9 /* Set the latency timer */ -#define FTDI_SIO_GET_LATENCY_TIMER 0x0a /* Get the latency timer */ -#define FTDI_SIO_SET_BITMODE 0x0b /* Set bitbang mode */ -#define FTDI_SIO_READ_PINS 0x0c /* Read immediate value of pins */ -#define FTDI_SIO_READ_EEPROM 0x90 /* Read EEPROM */ - -/* FTDI_SIO_RESET */ +#define FTDI_SIO_RESET 0 // Reset the port +#define FTDI_SIO_MODEM_CTRL 1 // Set the modem control register +#define FTDI_SIO_SET_FLOW_CTRL 2 // Set flow control register +#define FTDI_SIO_SET_BAUD_RATE 3 // Set baud rate +#define FTDI_SIO_SET_DATA 4 // Set the data characteristics of the port +#define FTDI_SIO_GET_MODEM_STATUS 5 // Retrieve current value of modem status register +#define FTDI_SIO_SET_EVENT_CHAR 6 // Set the event character +#define FTDI_SIO_SET_ERROR_CHAR 7 // Set the error character +#define FTDI_SIO_SET_LATENCY_TIMER 9 // Set the latency timer +#define FTDI_SIO_GET_LATENCY_TIMER 10 // Get the latency timer +#define FTDI_SIO_SET_BITMODE 11 // Set bitbang mode +#define FTDI_SIO_READ_PINS 12 // Read immediate value of pins +#define FTDI_SIO_READ_EEPROM 0x90 // Read EEPROM + +// Channel indices for FT2232, FT2232H and FT4232H devices +#define CHANNEL_A 1 +#define CHANNEL_B 2 +#define CHANNEL_C 3 +#define CHANNEL_D 4 + +// Port Identifier Table +#define PIT_DEFAULT 0 // SIOA +#define PIT_SIOA 1 // SIOA +// The device this driver is tested with one has only one port +#define PIT_SIOB 2 // SIOB +#define PIT_PARALLEL 3 // Parallel + +// FTDI_SIO_RESET +#define FTDI_SIO_RESET_REQUEST FTDI_SIO_RESET +#define FTDI_SIO_RESET_REQUEST_TYPE 0x40 #define FTDI_SIO_RESET_SIO 0 #define FTDI_SIO_RESET_PURGE_RX 1 #define FTDI_SIO_RESET_PURGE_TX 2 -/* - * BmRequestType: 0100 0000B - * bRequest: FTDI_SIO_RESET - * wValue: Control Value - * 0 = Reset SIO - * 1 = Purge RX buffer - * 2 = Purge TX buffer - * wIndex: Port - * wLength: 0 - * Data: None - * - * The Reset SIO command has this effect: - * - * Sets flow control set to 'none' - * Event char = $0D - * Event trigger = disabled - * Purge RX buffer - * Purge TX buffer - * Clear DTR - * Clear RTS - * baud and data format not reset - * - * The Purge RX and TX buffer commands affect nothing except the buffers - * - */ - -/* FTDI_SIO_MODEM_CTRL */ -/* - * BmRequestType: 0100 0000B - * bRequest: FTDI_SIO_MODEM_CTRL - * wValue: ControlValue (see below) - * wIndex: Port - * wLength: 0 - * Data: None - * - * NOTE: If the device is in RTS/CTS flow control, the RTS set by this - * command will be IGNORED without an error being returned - * Also - you can not set DTR and RTS with one control message - */ +// FTDI_SIO_SET_BAUDRATE +#define FTDI_SIO_SET_BAUDRATE_REQUEST_TYPE 0x40 +#define FTDI_SIO_SET_BAUDRATE_REQUEST 3 + +enum ftdi_sio_baudrate { + ftdi_sio_b300 = 0, + ftdi_sio_b600 = 1, + ftdi_sio_b1200 = 2, + ftdi_sio_b2400 = 3, + ftdi_sio_b4800 = 4, + ftdi_sio_b9600 = 5, + ftdi_sio_b19200 = 6, + ftdi_sio_b38400 = 7, + ftdi_sio_b57600 = 8, + ftdi_sio_b115200 = 9 +}; + +// FTDI_SIO_SET_DATA +#define FTDI_SIO_SET_DATA_REQUEST FTDI_SIO_SET_DATA +#define FTDI_SIO_SET_DATA_REQUEST_TYPE 0x40 +#define FTDI_SIO_SET_DATA_PARITY_NONE (0x0 << 8) +#define FTDI_SIO_SET_DATA_PARITY_ODD (0x1 << 8) +#define FTDI_SIO_SET_DATA_PARITY_EVEN (0x2 << 8) +#define FTDI_SIO_SET_DATA_PARITY_MARK (0x3 << 8) +#define FTDI_SIO_SET_DATA_PARITY_SPACE (0x4 << 8) +#define FTDI_SIO_SET_DATA_STOP_BITS_1 (0x0 << 11) +#define FTDI_SIO_SET_DATA_STOP_BITS_15 (0x1 << 11) +#define FTDI_SIO_SET_DATA_STOP_BITS_2 (0x2 << 11) +#define FTDI_SIO_SET_BREAK (0x1 << 14) + +// FTDI_SIO_MODEM_CTRL +#define FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE 0x40 +#define FTDI_SIO_SET_MODEM_CTRL_REQUEST FTDI_SIO_MODEM_CTRL #define FTDI_SIO_SET_DTR_MASK 0x1 -#define FTDI_SIO_SET_DTR_HIGH ((FTDI_SIO_SET_DTR_MASK << 8) | 1) -#define FTDI_SIO_SET_DTR_LOW ((FTDI_SIO_SET_DTR_MASK << 8) | 0) +#define FTDI_SIO_SET_DTR_HIGH ((FTDI_SIO_SET_DTR_MASK << 8) | 1) +#define FTDI_SIO_SET_DTR_LOW ((FTDI_SIO_SET_DTR_MASK << 8) | 0) #define FTDI_SIO_SET_RTS_MASK 0x2 #define FTDI_SIO_SET_RTS_HIGH ((FTDI_SIO_SET_RTS_MASK << 8) | 2) #define FTDI_SIO_SET_RTS_LOW ((FTDI_SIO_SET_RTS_MASK << 8) | 0) -/* - * ControlValue - * B0 DTR state - * 0 = reset - * 1 = set - * B1 RTS state - * 0 = reset - * 1 = set - * B2..7 Reserved - * B8 DTR state enable - * 0 = ignore - * 1 = use DTR state - * B9 RTS state enable - * 0 = ignore - * 1 = use RTS state - * B10..15 Reserved - */ - -/* FTDI_SIO_SET_FLOW_CTRL */ +// FTDI_SIO_SET_FLOW_CTRL +#define FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE 0x40 +#define FTDI_SIO_SET_FLOW_CTRL_REQUEST FTDI_SIO_SET_FLOW_CTRL #define FTDI_SIO_DISABLE_FLOW_CTRL 0x0 #define FTDI_SIO_RTS_CTS_HS (0x1 << 8) #define FTDI_SIO_DTR_DSR_HS (0x2 << 8) #define FTDI_SIO_XON_XOFF_HS (0x4 << 8) -/* - * BmRequestType: 0100 0000b - * bRequest: FTDI_SIO_SET_FLOW_CTRL - * wValue: Xoff/Xon - * wIndex: Protocol/Port - hIndex is protocol / lIndex is port - * wLength: 0 - * Data: None - * - * hIndex protocol is: - * B0 Output handshaking using RTS/CTS - * 0 = disabled - * 1 = enabled - * B1 Output handshaking using DTR/DSR - * 0 = disabled - * 1 = enabled - * B2 Xon/Xoff handshaking - * 0 = disabled - * 1 = enabled - * - * A value of zero in the hIndex field disables handshaking - * - * If Xon/Xoff handshaking is specified, the hValue field should contain the - * XOFF character and the lValue field contains the XON character. - */ - -/* FTDI_SIO_SET_BAUD_RATE */ -/* - * BmRequestType: 0100 0000B - * bRequest: FTDI_SIO_SET_BAUDRATE - * wValue: BaudDivisor value - see below - * wIndex: Port - * wLength: 0 - * Data: None - * The BaudDivisor values are calculated as follows (too complicated): - */ - -/* FTDI_SIO_SET_DATA */ -#define FTDI_SIO_SET_DATA_PARITY_NONE (0x0 << 8) -#define FTDI_SIO_SET_DATA_PARITY_ODD (0x1 << 8) -#define FTDI_SIO_SET_DATA_PARITY_EVEN (0x2 << 8) -#define FTDI_SIO_SET_DATA_PARITY_MARK (0x3 << 8) -#define FTDI_SIO_SET_DATA_PARITY_SPACE (0x4 << 8) -#define FTDI_SIO_SET_DATA_STOP_BITS_1 (0x0 << 11) -#define FTDI_SIO_SET_DATA_STOP_BITS_15 (0x1 << 11) -#define FTDI_SIO_SET_DATA_STOP_BITS_2 (0x2 << 11) -#define FTDI_SIO_SET_BREAK (0x1 << 14) - -/* - * BmRequestType: 0100 0000B - * bRequest: FTDI_SIO_SET_DATA - * wValue: Data characteristics (see below) - * wIndex: Port - * wLength: 0 - * Data: No - * - * Data characteristics - * - * B0..7 Number of data bits - * B8..10 Parity - * 0 = None - * 1 = Odd - * 2 = Even - * 3 = Mark - * 4 = Space - * B11..13 Stop Bits - * 0 = 1 - * 1 = 1.5 - * 2 = 2 - * B14 - * 1 = TX ON (break) - * 0 = TX OFF (normal state) - * B15 Reserved - * - */ - -/* -* DATA FORMAT -* -* IN Endpoint -* -* The device reserves the first two bytes of data on this endpoint to contain -* the current values of the modem and line status registers. In the absence of -* data, the device generates a message consisting of these two status bytes - * every 40 ms - * - * Byte 0: Modem Status -* -* Offset Description -* B0 Reserved - must be 1 -* B1 Reserved - must be 0 -* B2 Reserved - must be 0 -* B3 Reserved - must be 0 -* B4 Clear to Send (CTS) -* B5 Data Set Ready (DSR) -* B6 Ring Indicator (RI) -* B7 Receive Line Signal Detect (RLSD) -* -* Byte 1: Line Status -* -* Offset Description -* B0 Data Ready (DR) -* B1 Overrun Error (OE) -* B2 Parity Error (PE) -* B3 Framing Error (FE) -* B4 Break Interrupt (BI) -* B5 Transmitter Holding Register (THRE) -* B6 Transmitter Empty (TEMT) -* B7 Error in RCVR FIFO -* -*/ -#define FTDI_RS0_CTS (1 << 4) -#define FTDI_RS0_DSR (1 << 5) -#define FTDI_RS0_RI (1 << 6) -#define FTDI_RS0_RLSD (1 << 7) - -#define FTDI_RS_DR 1 -#define FTDI_RS_OE (1<<1) -#define FTDI_RS_PE (1<<2) -#define FTDI_RS_FE (1<<3) -#define FTDI_RS_BI (1<<4) -#define FTDI_RS_THRE (1<<5) -#define FTDI_RS_TEMT (1<<6) -#define FTDI_RS_FIFO (1<<7) +// FTDI_SIO_GET_LATENCY_TIMER +#define FTDI_SIO_GET_LATENCY_TIMER_REQUEST FTDI_SIO_GET_LATENCY_TIMER +#define FTDI_SIO_GET_LATENCY_TIMER_REQUEST_TYPE 0xC0 + +// FTDI_SIO_SET_LATENCY_TIMER +#define FTDI_SIO_SET_LATENCY_TIMER_REQUEST FTDI_SIO_SET_LATENCY_TIMER +#define FTDI_SIO_SET_LATENCY_TIMER_REQUEST_TYPE 0x40 + +// FTDI_SIO_SET_EVENT_CHAR +#define FTDI_SIO_SET_EVENT_CHAR_REQUEST FTDI_SIO_SET_EVENT_CHAR +#define FTDI_SIO_SET_EVENT_CHAR_REQUEST_TYPE 0x40 + +// FTDI_SIO_GET_MODEM_STATUS +#define FTDI_SIO_GET_MODEM_STATUS_REQUEST_TYPE 0xc0 +#define FTDI_SIO_GET_MODEM_STATUS_REQUEST FTDI_SIO_GET_MODEM_STATUS +#define FTDI_SIO_CTS_MASK 0x10 +#define FTDI_SIO_DSR_MASK 0x20 +#define FTDI_SIO_RI_MASK 0x40 +#define FTDI_SIO_RLSD_MASK 0x80 + +// FTDI_SIO_SET_BITMODE +#define FTDI_SIO_SET_BITMODE_REQUEST_TYPE 0x40 +#define FTDI_SIO_SET_BITMODE_REQUEST FTDI_SIO_SET_BITMODE + +// Possible bitmodes for FTDI_SIO_SET_BITMODE_REQUEST +#define FTDI_SIO_BITMODE_RESET 0x00 +#define FTDI_SIO_BITMODE_CBUS 0x20 + +// FTDI_SIO_READ_PINS +#define FTDI_SIO_READ_PINS_REQUEST_TYPE 0xc0 +#define FTDI_SIO_READ_PINS_REQUEST FTDI_SIO_READ_PINS + +// FTDI_SIO_READ_EEPROM +#define FTDI_SIO_READ_EEPROM_REQUEST_TYPE 0xc0 +#define FTDI_SIO_READ_EEPROM_REQUEST FTDI_SIO_READ_EEPROM + +#define FTDI_FTX_CBUS_MUX_GPIO 0x8 +#define FTDI_FT232R_CBUS_MUX_GPIO 0xa + +#define FTDI_RS0_CTS (1 << 4) +#define FTDI_RS0_DSR (1 << 5) +#define FTDI_RS0_RI (1 << 6) +#define FTDI_RS0_RLSD (1 << 7) + +#define FTDI_RS_DR 1 +#define FTDI_RS_OE (1<<1) +#define FTDI_RS_PE (1<<2) +#define FTDI_RS_FE (1<<3) +#define FTDI_RS_BI (1<<4) +#define FTDI_RS_THRE (1<<5) +#define FTDI_RS_TEMT (1<<6) +#define FTDI_RS_FIFO (1<<7) + +// chip types and names +enum ftdi_chip_type { + SIO = 0, +// FT232A, + FT232B, + FT2232C, + FT232R, + FT232H, + FT2232H, + FT4232H, + FT4232HA, + FT232HP, + FT233HP, + FT2232HP, + FT2233HP, + FT4232HP, + FT4233HP, + FTX, + UNKNOWN +}; + +#define FTDI_CHIP_NAMES \ + [SIO] = (uint8_t const*) "SIO", /* the serial part of FT8U100AX */ \ +/* [FT232A] = (uint8_t const*) "FT232A", */ \ + [FT232B] = (uint8_t const*) "FT232B", \ + [FT2232C] = (uint8_t const*) "FT2232C/D", \ + [FT232R] = (uint8_t const*) "FT232R", \ + [FT232H] = (uint8_t const*) "FT232H", \ + [FT2232H] = (uint8_t const*) "FT2232H", \ + [FT4232H] = (uint8_t const*) "FT4232H", \ + [FT4232HA] = (uint8_t const*) "FT4232HA", \ + [FT232HP] = (uint8_t const*) "FT232HP", \ + [FT233HP] = (uint8_t const*) "FT233HP", \ + [FT2232HP] = (uint8_t const*) "FT2232HP", \ + [FT2233HP] = (uint8_t const*) "FT2233HP", \ + [FT4232HP] = (uint8_t const*) "FT4232HP", \ + [FT4233HP] = (uint8_t const*) "FT4233HP", \ + [FTX] = (uint8_t const*) "FT-X", \ + [UNKNOWN] = (uint8_t const*) "UNKNOWN" + +// private interface data +typedef struct ftdi_private { + enum ftdi_chip_type chip_type; + uint8_t channel; // channel index, or 0 for legacy types +} ftdi_private_t; + +#define FTDI_OK true +#define FTDI_FAIL false +#define FTDI_NOT_POSSIBLE -1 +#define FTDI_REQUESTED -2 + +// division and round function overtaken from math.h +#define DIV_ROUND_CLOSEST(x, divisor)( \ +{ \ + typeof(x) __x = x; \ + typeof(divisor) __d = divisor; \ + (((typeof(x))-1) > 0 || \ + ((typeof(divisor))-1) > 0 || \ + (((__x) > 0) == ((__d) > 0))) ? \ + (((__x) + ((__d) / 2)) / (__d)) : \ + (((__x) - ((__d) / 2)) / (__d)); \ +} \ +) #endif //TUSB_FTDI_SIO_H diff --git a/src/tusb_option.h b/src/tusb_option.h index 767323bdd..ebf9a4d4d 100644 --- a/src/tusb_option.h +++ b/src/tusb_option.h @@ -456,9 +456,22 @@ #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} + {0x0403, 0x6001}, /* Similar device to SIO above */ \ + {0x0403, 0x6006}, /* FTDI's alternate PID for above */ \ + {0x0403, 0x6010}, /* Dual channel device */ \ + {0x0403, 0x6011}, /* Quad channel hi-speed device */ \ + {0x0403, 0x6014}, /* Single channel hi-speed device */ \ + {0x0403, 0x6015}, /* FT-X series (FT201X, FT230X, FT231X, etc) */ \ + {0x0403, 0x6040}, /* Dual channel hi-speed device with PD */ \ + {0x0403, 0x6041}, /* Quad channel hi-speed device with PD */ \ + {0x0403, 0x6042}, /* Dual channel hi-speed device with PD */ \ + {0x0403, 0x6043}, /* Quad channel hi-speed device with PD */ \ + {0x0403, 0x6044}, /* Dual channel hi-speed device with PD */ \ + {0x0403, 0x6045}, /* Dual channel hi-speed device with PD */ \ + {0x0403, 0x6048}, /* Quad channel automotive grade hi-speed device */ \ + {0x0403, 0x8372}, /* Product Id SIO application of 8U100AX */ \ + {0x0403, 0xFBFA}, /* Product ID for FT232RL */ \ + {0x0403, 0xCD18}, /* ??? */ #endif #ifndef CFG_TUH_CDC_CP210X -- cgit v1.3.1 From 4547737833de0368354cb4823d908c6b250f92df Mon Sep 17 00:00:00 2001 From: IngHK Date: Thu, 22 Feb 2024 15:42:33 +0100 Subject: improved CP210x support --- src/class/cdc/cdc_host.c | 135 +++++++++++++++++++++++++++++------------- src/class/cdc/serial/cp210x.h | 63 +++++++++++++++++++- src/tusb_option.h | 4 +- 3 files changed, 159 insertions(+), 43 deletions(-) (limited to 'src/class') diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index f9540efbe..86c010fa7 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -83,7 +83,7 @@ typedef struct { uint8_t requested_line_state; tuh_xfer_cb_t user_control_cb; - #if CFG_TUH_CDC_FTDI || CFG_TUH_CDC_CH34X + #if CFG_TUH_CDC_FTDI || CFG_TUH_CDC_CP210X || CFG_TUH_CDC_CH34X tuh_xfer_cb_t requested_complete_cb; #endif @@ -1533,7 +1533,8 @@ static uint8_t ftdi_get_idx(tuh_xfer_t * xfer) { //------------- Control Request -------------// -static bool cp210x_set_request(cdch_interface_t* p_cdc, uint8_t command, uint16_t value, uint8_t* buffer, uint16_t length, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { +static bool cp210x_set_request(cdch_interface_t * p_cdc, uint8_t command, uint16_t value, + uint8_t * buffer, uint16_t length, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { tusb_control_request_t const request = { .bmRequestType_bit = { .recipient = TUSB_REQ_RCPT_INTERFACE, @@ -1542,12 +1543,12 @@ static bool cp210x_set_request(cdch_interface_t* p_cdc, uint8_t command, uint16_ }, .bRequest = command, .wValue = tu_htole16(value), - .wIndex = p_cdc->bInterfaceNumber, + .wIndex = tu_htole16(p_cdc->bInterfaceNumber), .wLength = tu_htole16(length) }; // use usbh enum buf since application variable does not live long enough - uint8_t* enum_buf = NULL; + uint8_t * enum_buf = NULL; if (buffer && length > 0) { enum_buf = usbh_get_enum_buf(); @@ -1566,18 +1567,52 @@ static bool cp210x_set_request(cdch_interface_t* p_cdc, uint8_t command, uint16_ return tuh_control_xfer(&xfer); } -static bool cp210x_ifc_enable(cdch_interface_t* p_cdc, uint16_t enabled, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { +static inline bool cp210x_ifc_enable(cdch_interface_t * p_cdc, uint16_t enabled, + tuh_xfer_cb_t complete_cb, uintptr_t user_data) { return cp210x_set_request(p_cdc, CP210X_IFC_ENABLE, enabled, NULL, 0, complete_cb, user_data); } +static bool cp210x_set_baudrate_request(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + // Check baudrate is supported. It's only a specific list. reference: datasheets and AN205 "CP210x Baud Rate Support" + uint32_t const supported_baudrates_list[] = CP210X_SUPPORTED_BAUDRATES_LIST; + uint8_t i; + for ( i=0; supported_baudrates_list[i]; i++ ){ + if (p_cdc->requested_line_coding.bit_rate == supported_baudrates_list[i]) { + break; + } + } + TU_VERIFY(supported_baudrates_list[i]); + uint32_t baud_le = tu_htole32(p_cdc->requested_line_coding.bit_rate); + + return cp210x_set_request(p_cdc, CP210X_SET_BAUDRATE, 0, (uint8_t *) &baud_le, 4, complete_cb, user_data); +} + +static bool cp210x_set_line_ctl(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + TU_VERIFY(p_cdc->requested_line_coding.data_bits >= 5 && p_cdc->requested_line_coding.data_bits <= 9, 0); + uint16_t lcr = (uint16_t) ( + ((uint32_t) p_cdc->requested_line_coding.data_bits & 0xf) << 8 | // data bit quantity is stored in bits 8-11 + ((uint32_t) p_cdc->requested_line_coding.parity & 0xf) << 4 | // parity is stored in bits 4-7, same coding + ((uint32_t) p_cdc->requested_line_coding.stop_bits & 0xf)); // parity is stored in bits 0-3, same coding + + return cp210x_set_request(p_cdc, CP210X_SET_LINE_CTL, lcr, NULL, 0, complete_cb, user_data); +} + +static inline bool cp210x_set_mhs(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + // CP210x has the same bit coding + return cp210x_set_request(p_cdc, CP210X_SET_MHS, + (uint16_t) ((uint32_t) CP210X_CONTROL_WRITE_DTR | + (uint32_t) CP210X_CONTROL_WRITE_RTS | p_cdc->requested_line_state), + NULL, 0, complete_cb, user_data); +} + //------------- Driver API -------------// // internal control complete to update state such as line state, encoding static void cp210x_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, ); + cdch_interface_t * p_cdc = get_itf(idx); + TU_ASSERT(p_cdc,); bool const success = (xfer->result == XFER_RESULT_SUCCESS); TU_LOG_P_CDC("control complete success = %u", success); @@ -1587,6 +1622,12 @@ static void cp210x_internal_control_complete(tuh_xfer_t * xfer) { p_cdc->line_state = p_cdc->requested_line_state; break; + case CP210X_SET_LINE_CTL: + 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; + case CP210X_SET_BAUDRATE: p_cdc->line_coding.bit_rate = p_cdc->requested_line_coding.bit_rate; break; @@ -1601,46 +1642,55 @@ static void cp210x_internal_control_complete(tuh_xfer_t * xfer) { } } -static bool cp210x_set_baudrate(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - uint32_t baud_le = tu_htole32(p_cdc->requested_line_coding.bit_rate); +static bool cp210x_set_baudrate(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { p_cdc->user_control_cb = complete_cb; - return cp210x_set_request(p_cdc, CP210X_SET_BAUDRATE, 0, (uint8_t *) &baud_le, 4, - complete_cb ? cp210x_internal_control_complete : NULL, user_data); + TU_ASSERT(cp210x_set_baudrate_request(p_cdc, complete_cb ? cp210x_internal_control_complete : NULL, user_data)); + + return true; } -static bool cp210x_set_data_format(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - (void) p_cdc; - (void) complete_cb; - (void) user_data; - // TODO not implemented yet - return false; +static bool cp210x_set_data_format(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + p_cdc->user_control_cb = complete_cb; + TU_ASSERT(cp210x_set_line_ctl(p_cdc, complete_cb ? cp210x_internal_control_complete : NULL, user_data)); + + return true; } -static bool cp210x_set_line_coding(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - // TODO implement later - (void) p_cdc; - (void) complete_cb; - (void) user_data; - return false; +static void cp210x_set_line_coding_stage1_complete(tuh_xfer_t * xfer) { + uint8_t const itf_num = (uint8_t) tu_le16toh(xfer->setup->wIndex); + set_line_coding_stage1_complete(xfer, itf_num, + cp210x_set_line_ctl, // control request function to set data format + cp210x_internal_control_complete); // control complete function to be called after request +} + +// 2 stages: set baudrate (stage1) + set data format (stage2) +static bool cp210x_set_line_coding(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + return set_line_coding_sequence(p_cdc, + cp210x_set_baudrate_request, // control request function to set baudrate + cp210x_set_line_ctl, // control request function to set data format + cp210x_set_line_coding_stage1_complete, // function to be called after stage 1 completed + cp210x_internal_control_complete, // control complete function to be called after request + complete_cb, user_data); } -static bool cp210x_set_modem_ctrl(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { +static bool cp210x_set_modem_ctrl(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { p_cdc->user_control_cb = complete_cb; - return cp210x_set_request(p_cdc, CP210X_SET_MHS, 0x0300 | p_cdc->requested_line_state, NULL, 0, - complete_cb ? cp210x_internal_control_complete : NULL, user_data); + TU_ASSERT(cp210x_set_mhs(p_cdc, complete_cb ? cp210x_internal_control_complete : NULL, user_data)); + + return true; } //------------- Enumeration -------------// enum { CONFIG_CP210X_IFC_ENABLE = 0, - CONFIG_CP210X_SET_BAUDRATE, + CONFIG_CP210X_SET_BAUDRATE_REQUEST, CONFIG_CP210X_SET_LINE_CTL, CONFIG_CP210X_SET_DTR_RTS, CONFIG_CP210X_COMPLETE }; -static bool cp210x_open(uint8_t daddr, tusb_desc_interface_t const *itf_desc, uint16_t max_len) { +static bool cp210x_open(uint8_t daddr, tusb_desc_interface_t const * itf_desc, uint16_t max_len) { // CP210x Interface includes 1 vendor interface + 2 bulk endpoints TU_VERIFY(itf_desc->bInterfaceSubClass == 0 && itf_desc->bInterfaceProtocol == 0 && itf_desc->bNumEndpoints == 2); TU_VERIFY(sizeof(tusb_desc_interface_t) + 2*sizeof(tusb_desc_endpoint_t) <= max_len); @@ -1657,7 +1707,7 @@ static bool cp210x_open(uint8_t daddr, tusb_desc_interface_t const *itf_desc, ui return open_ep_stream_pair(p_cdc, desc_ep); } -static void cp210x_process_config(tuh_xfer_t* xfer) { +static void cp210x_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); @@ -1666,32 +1716,35 @@ static void cp210x_process_config(tuh_xfer_t* xfer) { switch (state) { case CONFIG_CP210X_IFC_ENABLE: - TU_ASSERT_COMPLETE(cp210x_ifc_enable(p_cdc, 1, cp210x_process_config, CONFIG_CP210X_SET_BAUDRATE)); + p_cdc->user_control_cb = cp210x_process_config; // set once for whole process config + TU_ASSERT_COMPLETE(cp210x_ifc_enable(p_cdc, CP210X_UART_ENABLE, cp210x_process_config, + CONFIG_CP210X_SET_BAUDRATE_REQUEST)); break; - case CONFIG_CP210X_SET_BAUDRATE: { + case CONFIG_CP210X_SET_BAUDRATE_REQUEST: #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM - p_cdc->requested_line_coding.bit_rate = ((cdc_line_coding_t) CFG_TUH_CDC_LINE_CODING_ON_ENUM).bit_rate; - TU_ASSERT_COMPLETE(cp210x_set_baudrate(p_cdc, cp210x_process_config, CONFIG_CP210X_SET_LINE_CTL)); + p_cdc->requested_line_coding = (cdc_line_coding_t) CFG_TUH_CDC_LINE_CODING_ON_ENUM; + TU_ASSERT_COMPLETE(cp210x_set_baudrate_request(p_cdc, cp210x_internal_control_complete, + CONFIG_CP210X_SET_LINE_CTL)); break; #else TU_ATTR_FALLTHROUGH; #endif - } - case CONFIG_CP210X_SET_LINE_CTL: { - #if defined(CFG_TUH_CDC_LINE_CODING_ON_ENUM) && 0 // skip for now - cdc_line_coding_t line_coding = CFG_TUH_CDC_LINE_CODING_ON_ENUM; - break; + case CONFIG_CP210X_SET_LINE_CTL: + #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM + TU_ASSERT_COMPLETE(cp210x_set_line_ctl(p_cdc, cp210x_internal_control_complete, + CONFIG_CP210X_SET_DTR_RTS)); + break; #else - TU_ATTR_FALLTHROUGH; + TU_ATTR_FALLTHROUGH; #endif - } case CONFIG_CP210X_SET_DTR_RTS: #ifdef CFG_TUH_CDC_LINE_CONTROL_ON_ENUM p_cdc->requested_line_state = CFG_TUH_CDC_LINE_CONTROL_ON_ENUM; - TU_ASSERT_COMPLETE(cp210x_set_modem_ctrl(p_cdc, cp210x_process_config, CONFIG_CP210X_COMPLETE)); + TU_ASSERT_COMPLETE(cp210x_set_mhs(p_cdc, cp210x_internal_control_complete, + CONFIG_CP210X_COMPLETE)); break; #else TU_ATTR_FALLTHROUGH; diff --git a/src/class/cdc/serial/cp210x.h b/src/class/cdc/serial/cp210x.h index 2c749f522..e18da7d51 100644 --- a/src/class/cdc/serial/cp210x.h +++ b/src/class/cdc/serial/cp210x.h @@ -28,7 +28,8 @@ // Protocol details can be found at AN571: CP210x Virtual COM Port Interface // https://www.silabs.com/documents/public/application-notes/AN571.pdf -#define TU_CP210X_VID 0x10C4 +// parts are overtaken from vendors driver +// https://www.silabs.com/documents/public/software/cp210x-3.1.0.tar.gz /* Config request codes */ #define CP210X_IFC_ENABLE 0x00 @@ -59,4 +60,64 @@ #define CP210X_SET_BAUDRATE 0x1E #define CP210X_VENDOR_SPECIFIC 0xFF // GPIO, Recipient must be Device +/* SILABSER_IFC_ENABLE_REQUEST_CODE */ +#define CP210X_UART_ENABLE 0x0001 +#define CP210X_UART_DISABLE 0x0000 + +/* SILABSER_SET_BAUDDIV_REQUEST_CODE */ +#define CP210X_BAUD_RATE_GEN_FREQ 0x384000 + +/*SILABSER_SET_LINE_CTL_REQUEST_CODE */ +#define CP210X_BITS_DATA_MASK 0x0f00 +#define CP210X_BITS_DATA_5 0x0500 +#define CP210X_BITS_DATA_6 0x0600 +#define CP210X_BITS_DATA_7 0x0700 +#define CP210X_BITS_DATA_8 0x0800 +#define CP210X_BITS_DATA_9 0x0900 + +#define CP210X_BITS_PARITY_MASK 0x00f0 +#define CP210X_BITS_PARITY_NONE 0x0000 +#define CP210X_BITS_PARITY_ODD 0x0010 +#define CP210X_BITS_PARITY_EVEN 0x0020 +#define CP210X_BITS_PARITY_MARK 0x0030 +#define CP210X_BITS_PARITY_SPACE 0x0040 + +#define CP210X_BITS_STOP_MASK 0x000f +#define CP210X_BITS_STOP_1 0x0000 +#define CP210X_BITS_STOP_1_5 0x0001 +#define CP210X_BITS_STOP_2 0x0002 + +/* SILABSER_SET_BREAK_REQUEST_CODE */ +#define CP210X_BREAK_ON 0x0001 +#define CP210X_BREAK_OFF 0x0000 + +/* SILABSER_SET_MHS_REQUEST_CODE */ +#define CP210X_MCR_DTR 0x0001 +#define CP210X_MCR_RTS 0x0002 +#define CP210X_MCR_ALL 0x0003 +#define CP210X_MSR_CTS 0x0010 +#define CP210X_MSR_DSR 0x0020 +#define CP210X_MSR_RING 0x0040 +#define CP210X_MSR_DCD 0x0080 +#define CP210X_MSR_ALL 0x00F0 + +#define CP210X_CONTROL_WRITE_DTR 0x0100 +#define CP210X_CONTROL_WRITE_RTS 0x0200 + +#define CP210X_LSR_BREAK 0x0001 +#define CP210X_LSR_FRAMING_ERROR 0x0002 +#define CP210X_LSR_HW_OVERRUN 0x0004 +#define CP210X_LSR_QUEUE_OVERRUN 0x0008 +#define CP210X_LSR_PARITY_ERROR 0x0010 +#define CP210X_LSR_ALL 0x001F + +// supported baudrates +// reference: datasheets and AN205 "CP210x Baud Rate Support" +#define CP210X_SUPPORTED_BAUDRATES_LIST { \ + 300, 600, \ + 1200, 1800, 2400, 4000, 4800, 7200, 9600, \ + 14400, 16000, 19200, 28800, 38400, 51200, 56000, 57600, 64000, 76800, \ + 115200, 128000, 153600, 230400, 250000, 256000, 460800, 500000, 576000, 921600, \ + 0 } + #endif //TUSB_CP210X_H diff --git a/src/tusb_option.h b/src/tusb_option.h index ebf9a4d4d..281341685 100644 --- a/src/tusb_option.h +++ b/src/tusb_option.h @@ -482,7 +482,9 @@ #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} + { 0x10C4, 0xEA60 }, /* Silicon Labs factory default */ \ + { 0x10C4, 0xEA61 }, /* Silicon Labs factory default */ \ + { 0x10C4, 0xEA70 } /* Silicon Labs Dual Port factory default */ #endif #ifndef CFG_TUH_CDC_CH34X -- cgit v1.3.1 From aabee25e189d2a05cb52e5c54329ab1ec875f084 Mon Sep 17 00:00:00 2001 From: IngHK Date: Thu, 22 Feb 2024 11:45:38 +0100 Subject: added PL2303 support --- 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 | 754 ++++++++++++++++++++- src/class/cdc/serial/pl2303.h | 172 +++++ src/tusb_option.h | 18 + 5 files changed, 942 insertions(+), 4 deletions(-) create mode 100644 src/class/cdc/serial/pl2303.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 e4d74077f..fc956c6d3 100644 --- a/examples/host/cdc_msc_hid/src/tusb_config.h +++ b/examples/host/cdc_msc_hid/src/tusb_config.h @@ -106,6 +106,7 @@ #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_CDC_PL2303 1 // PL2303 Serial. PL2303 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 9dc89dc55..dd732c700 100644 --- a/examples/host/cdc_msc_hid_freertos/src/tusb_config.h +++ b/examples/host/cdc_msc_hid_freertos/src/tusb_config.h @@ -111,6 +111,7 @@ #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_CDC_PL2303 1 // PL2303 Serial. PL2303 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 86c010fa7..429d0a113 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -38,6 +38,7 @@ #include "serial/ftdi_sio.h" #include "serial/cp210x.h" #include "serial/ch34x.h" +#include "serial/pl2303.h" // Level where CFG_TUSB_DEBUG must be at least for this driver is logged #ifndef CFG_TUH_CDC_LOG_LEVEL @@ -91,6 +92,10 @@ typedef struct { ftdi_private_t ftdi; #endif + #if CFG_TUH_CDC_PL2303 + pl2303_private_t pl2303; + #endif + struct { tu_edpt_stream_t tx; tu_edpt_stream_t rx; @@ -105,7 +110,7 @@ typedef struct { CFG_TUH_MEM_SECTION static cdch_interface_t cdch_data[CFG_TUH_CDC]; -#if CFG_TUH_CDC_FTDI +#if CFG_TUH_CDC_FTDI || CFG_TUH_CDC_PL2303 static tusb_desc_device_t desc_dev[CFG_TUH_CDC][CFG_TUH_ENUMERATION_BUFSIZE]; #endif @@ -164,6 +169,22 @@ static bool ch34x_set_line_coding(cdch_interface_t* p_cdc, tuh_xfer_cb_t complet static bool ch34x_set_modem_ctrl(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); #endif +//------------- PL2303 prototypes -------------// +#if CFG_TUH_CDC_PL2303 +static uint16_t const pl2303_vid_pid_list[][2] = {CFG_TUH_CDC_PL2303_VID_PID_LIST}; +static const struct pl2303_type_data pl2303_type_data[TYPE_COUNT] = {PL2303_TYPE_DATA}; + +CFG_TUH_MEM_SECTION CFG_TUH_MEM_ALIGN + +static bool pl2303_open(uint8_t daddr, tusb_desc_interface_t const * itf_desc, uint16_t max_len); +static void pl2303_process_config(tuh_xfer_t * xfer); + +static bool pl2303_set_baudrate(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); +static bool pl2303_set_data_format(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); +static bool pl2303_set_line_coding(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); +static bool pl2303_set_modem_ctrl(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); +#endif + //------------- Common -------------// enum { SERIAL_DRIVER_ACM = 0, @@ -180,6 +201,10 @@ enum { SERIAL_DRIVER_CH34X, #endif +#if CFG_TUH_CDC_PL2303 + SERIAL_DRIVER_PL2303, +#endif + SERIAL_DRIVER_COUNT }; @@ -260,6 +285,22 @@ static const cdch_serial_driver_t serial_drivers[] = { #endif }, #endif + + #if CFG_TUH_CDC_PL2303 + { + .vid_pid_list = pl2303_vid_pid_list, + .vid_pid_count = TU_ARRAY_SIZE(pl2303_vid_pid_list), + .open = pl2303_open, + .process_set_config = pl2303_process_config, + .set_control_line_state = pl2303_set_modem_ctrl, + .set_baudrate = pl2303_set_baudrate, + .set_data_format = pl2303_set_data_format, + .set_line_coding = pl2303_set_line_coding, + #if CFG_TUSB_DEBUG && CFG_TUSB_DEBUG >= CFG_TUH_CDC_LOG_LEVEL + .name = (uint8_t const *) "PL2303" + #endif + } + #endif }; TU_VERIFY_STATIC(TU_ARRAY_SIZE(serial_drivers) == SERIAL_DRIVER_COUNT, "Serial driver count mismatch"); @@ -1863,7 +1904,7 @@ static bool ch34x_modem_ctrl_request(cdch_interface_t * p_cdc, tuh_xfer_cb_t com // internal control complete to update state such as line state, encoding static void ch34x_internal_control_complete(tuh_xfer_t * xfer) { - // CH34x only has 1 interface and wIndex used as payload and not for bInterfaceNumber + // CH34x has only interface 0, because wIndex is used as payload and not for bInterfaceNumber uint8_t const itf_num = 0; uint8_t idx = tuh_cdc_itf_get_index(xfer->daddr, itf_num); cdch_interface_t* p_cdc = get_itf(idx); @@ -1921,7 +1962,8 @@ static bool ch34x_set_baudrate(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_ } static void ch34x_set_line_coding_stage1_complete(tuh_xfer_t * xfer) { - uint8_t const itf_num = 0; // CH34x has only interface 0, because wIndex is used as payload and not for bInterfaceNumber + // CH34x has only interface 0, because wIndex is used as payload and not for bInterfaceNumber + uint8_t const itf_num = 0; set_line_coding_stage1_complete(xfer, itf_num, ch34x_write_reg_data_format, // control request function to set data format ch34x_internal_control_complete); // control complete function to be called after request @@ -1981,7 +2023,7 @@ static bool ch34x_open(uint8_t daddr, tusb_desc_interface_t const* itf_desc, uin } static void ch34x_process_config(tuh_xfer_t* xfer) { - // CH34x only has 1 interface and wIndex used as payload and not for bInterfaceNumber + // CH34x has only interface 0, because wIndex is used as payload and not for bInterfaceNumber uintptr_t const state = xfer->user_data; uint8_t const itf_num = 0; uint8_t const idx = tuh_cdc_itf_get_index(xfer->daddr, itf_num); @@ -2142,4 +2184,708 @@ static uint8_t ch34x_get_lcr(cdch_interface_t * p_cdc) { #endif // CFG_TUH_CDC_CH34X +//--------------------------------------------------------------------+ +// PL2303 +//--------------------------------------------------------------------+ +#if CFG_TUH_CDC_PL2303 + +static int8_t pl2303_detect_type(cdch_interface_t * p_cdc, uint8_t const idx, uint8_t step, + tuh_xfer_cb_t complete_cb, uintptr_t user_data); +static bool pl2303_encode_baud_rate(cdch_interface_t * p_cdc, uint8_t buf[PL2303_LINE_CODING_BAUDRATE_BUFSIZE]); + +//------------- Control Request -------------// + +static bool pl2303_set_request(cdch_interface_t * p_cdc, uint8_t request, uint8_t requesttype, + 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 = requesttype, + .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(); + if (request_setup.bmRequestType_bit.direction == TUSB_DIR_OUT) { + 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, + .user_data = user_data + }; + + return tuh_control_xfer(&xfer); +} + +static bool pl2303_vendor_read(cdch_interface_t * p_cdc, uint16_t value, uint8_t * buf, + tuh_xfer_cb_t complete_cb, uintptr_t user_data) +{ + uint8_t request = p_cdc->pl2303.serial_private.type == &pl2303_type_data[TYPE_HXN] ? + PL2303_VENDOR_READ_NREQUEST : PL2303_VENDOR_READ_REQUEST; + + return pl2303_set_request(p_cdc, request, PL2303_VENDOR_READ_REQUEST_TYPE, value, 0, buf, 1, complete_cb, user_data); +} + +static bool pl2303_vendor_write(cdch_interface_t * p_cdc, uint16_t value, uint16_t index, + tuh_xfer_cb_t complete_cb, uintptr_t user_data) +{ + uint8_t request = p_cdc->pl2303.serial_private.type == &pl2303_type_data[TYPE_HXN] ? + PL2303_VENDOR_WRITE_NREQUEST : PL2303_VENDOR_WRITE_REQUEST; + + return pl2303_set_request(p_cdc, request, PL2303_VENDOR_WRITE_REQUEST_TYPE, value, index, NULL, 0, complete_cb, user_data); +} + +static inline bool pl2303_supports_hx_status(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) +{ + uint8_t buf; + + return pl2303_set_request(p_cdc, PL2303_VENDOR_READ_REQUEST, PL2303_VENDOR_READ_REQUEST_TYPE, PL2303_READ_TYPE_HX_STATUS, 0, + &buf, 1, complete_cb, user_data); +} + +static inline bool pl2303_set_control_lines(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) +{ + return pl2303_set_request(p_cdc, PL2303_SET_CONTROL_REQUEST, PL2303_SET_CONTROL_REQUEST_TYPE, + p_cdc->requested_line_state, 0, NULL, 0, complete_cb, user_data); +} + +//static bool pl2303_get_line_request(cdch_interface_t * p_cdc, uint8_t buf[PL2303_LINE_CODING_BUFSIZE]) +//{ +// return pl2303_set_request(p_cdc, PL2303_GET_LINE_REQUEST, PL2303_GET_LINE_REQUEST_TYPE, 0, 0, buf, PL2303_LINE_CODING_BUFSIZE); +//} + +static bool pl2303_set_line_request(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + // the caller has to precheck, that the new line coding different than the current, else false returned + uint8_t buf[PL2303_LINE_CODING_BUFSIZE]; + /* + * Some PL2303 are known to lose bytes if you change serial settings + * even to the same values as before. Thus we actually need to filter + * in this specific case. + */ + // TODO really necessary to check? what to do in this case when no transfer will happen? + // callback is not called... + TU_VERIFY(memcmp(&p_cdc->requested_line_coding, &p_cdc->line_coding, sizeof(cdc_line_coding_t) ) != 0); + + /* For reference buf[6] data bits value */ + TU_VERIFY(p_cdc->requested_line_coding.data_bits >= 5 && p_cdc->requested_line_coding.data_bits <= 8, 0); + buf[6] = p_cdc->requested_line_coding.data_bits; + + /* For reference buf[0]:buf[3] baud rate value */ + TU_VERIFY(pl2303_encode_baud_rate(p_cdc, &buf[0])); + + /* For reference buf[4]=0 is 1 stop bits */ + /* For reference buf[4]=1 is 1.5 stop bits */ + /* For reference buf[4]=2 is 2 stop bits */ + buf[4] = p_cdc->requested_line_coding.stop_bits; // PL2303 has the same coding + + /* For reference buf[5]=0 is none parity */ + /* For reference buf[5]=1 is odd parity */ + /* For reference buf[5]=2 is even parity */ + /* For reference buf[5]=3 is mark parity */ + /* For reference buf[5]=4 is space parity */ + buf[5] = p_cdc->requested_line_coding.parity; // PL2303 has the same coding + + return pl2303_set_request(p_cdc, PL2303_SET_LINE_REQUEST, PL2303_SET_LINE_REQUEST_TYPE, 0, 0, + buf, PL2303_LINE_CODING_BUFSIZE, complete_cb, user_data); +} + +//static bool pl2303_set_break(cdch_interface_t * p_cdc, bool enable) +//{ +// uint16_t state = enable ? PL2303_BREAK_ON : PL2303_BREAK_OFF; +// return pl2303_set_request(p_cdc, PL2303_BREAK_REQUEST, PL2303_BREAK_REQUEST_TYPE, state, 0, NULL, 0); +//} + +static inline int pl2303_clear_halt(cdch_interface_t * p_cdc, uint8_t endp, tuh_xfer_cb_t complete_cb, uintptr_t user_data) +{ + /* we don't care if it wasn't halted first. in fact some devices + * (like some ibmcam model 1 units) seem to expect hosts to make + * this request for iso endpoints, which can't halt! + */ + return pl2303_set_request(p_cdc, TUSB_REQ_CLEAR_FEATURE, PL2303_CLEAR_HALT_REQUEST_TYPE, TUSB_REQ_FEATURE_EDPT_HALT, endp, + NULL, 0, complete_cb, user_data); +} + +//------------- Driver API -------------// + +// internal control complete to update state such as line state, encoding +static void pl2303_internal_control_complete(tuh_xfer_t * xfer) { + // PL2303 has only interface 0, because wIndex is used as payload and not for bInterfaceNumber + uint8_t const itf_num = 0; + uint8_t idx = tuh_cdc_itf_get_index(xfer->daddr, itf_num); + cdch_interface_t * p_cdc = get_itf(idx); + TU_ASSERT(p_cdc,); + bool const success = (xfer->result == XFER_RESULT_SUCCESS); + TU_LOG_P_CDC("control complete success = %u", success); + + if (success) { + if (xfer->setup->bRequest == PL2303_SET_LINE_REQUEST && + xfer->setup->bmRequestType == PL2303_SET_LINE_REQUEST_TYPE) { + p_cdc->line_coding = p_cdc->requested_line_coding; + } + if (xfer->setup->bRequest == PL2303_SET_CONTROL_REQUEST && + xfer->setup->bmRequestType == PL2303_SET_CONTROL_REQUEST_TYPE) { + p_cdc->line_state = p_cdc->requested_line_state; + } + } + + xfer->complete_cb = p_cdc->user_control_cb; + if (xfer->complete_cb) { + xfer->complete_cb(xfer); + } +} + +static bool pl2303_set_line_coding(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + p_cdc->user_control_cb = complete_cb; + TU_ASSERT(pl2303_set_line_request(p_cdc, complete_cb ? pl2303_internal_control_complete : NULL, user_data)); + + return true; +} + +static bool pl2303_set_data_format(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + p_cdc->requested_line_coding.bit_rate = p_cdc->line_coding.bit_rate; + p_cdc->user_control_cb = complete_cb; + TU_ASSERT(pl2303_set_line_request(p_cdc, complete_cb ? pl2303_internal_control_complete : NULL, user_data)); + + return true; +} + +static bool pl2303_set_baudrate(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + p_cdc->requested_line_coding.stop_bits = p_cdc->line_coding.stop_bits; + p_cdc->requested_line_coding.parity = p_cdc->line_coding.parity; + p_cdc->requested_line_coding.data_bits = p_cdc->line_coding.data_bits; + p_cdc->user_control_cb = complete_cb; + TU_ASSERT(pl2303_set_line_request(p_cdc, complete_cb ? pl2303_internal_control_complete : NULL, user_data)); + + return true; +} + +static bool pl2303_set_modem_ctrl(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + // PL2303 has the same bit coding + p_cdc->user_control_cb = complete_cb; + TU_ASSERT(pl2303_set_control_lines(p_cdc, complete_cb ? pl2303_internal_control_complete : NULL, user_data)); + + return true; +} + +//------------- Enumeration -------------// + +enum { + CONFIG_PL2303_GET_DESC = 0, + CONFIG_PL2303_DETECT_TYPE, + CONFIG_PL2303_READ1, + CONFIG_PL2303_WRITE1, + CONFIG_PL2303_READ2, + CONFIG_PL2303_READ3, + CONFIG_PL2303_READ4, + CONFIG_PL2303_WRITE2, + CONFIG_PL2303_READ5, + CONFIG_PL2303_READ6, + CONFIG_PL2303_WRITE3, + CONFIG_PL2303_WRITE4, + CONFIG_PL2303_WRITE5, + CONFIG_PL2303_RESET_ENDP1, + CONFIG_PL2303_RESET_ENDP2, + CONFIG_PL2303_LINE_CODING, + CONFIG_PL2303_MODEM_CONTROL, + CONFIG_PL2303_FLOW_CTRL_READ, + CONFIG_PL2303_FLOW_CTRL_WRITE, + CONFIG_PL2303_COMPLETE +}; + +static bool pl2303_open(uint8_t daddr, tusb_desc_interface_t const * itf_desc, uint16_t max_len) { + // PL2303 Interface includes 1 vendor interface + 1 interrupt endpoints + 2 bulk + 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); + + p_cdc->serial_drid = SERIAL_DRIVER_PL2303; + p_cdc->pl2303.serial_private.quirks = 0; + p_cdc->pl2303.supports_hx_status = false; + + tusb_desc_endpoint_t const * desc_ep = (tusb_desc_endpoint_t const * ) tu_desc_next(itf_desc); + + // 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; + desc_ep += 1; + + // data endpoints expected to be in pairs + TU_ASSERT(open_ep_stream_pair(p_cdc, desc_ep)); + + return true; +} + +static void pl2303_process_config(tuh_xfer_t * xfer) { + // PL2303 has only interface 0, because wIndex is used 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); + // state CONFIG_PL2303_READ1 may have no success due to expected stall by pl2303_supports_hx_status() + TU_ASSERT_COMPLETE(p_cdc && (xfer->result == XFER_RESULT_SUCCESS || xfer->user_data == CONFIG_PL2303_READ1)); + uint8_t buf; + int8_t type; + + switch (xfer->user_data) { + + // from here sequence overtaken from Linux Kernel function pl2303_startup() + case CONFIG_PL2303_GET_DESC: + p_cdc->user_control_cb = pl2303_process_config; // set once for whole process config + // get device descriptor + TU_ASSERT_COMPLETE(tuh_descriptor_get_device(xfer->daddr, desc_dev[idx], sizeof(tusb_desc_device_t), + pl2303_process_config, CONFIG_PL2303_DETECT_TYPE)); + break; + + case CONFIG_PL2303_DETECT_TYPE: + // get type and quirks (step 1) + type = pl2303_detect_type (p_cdc, idx, 1, pl2303_process_config, CONFIG_PL2303_READ1); // step 1 + TU_ASSERT_COMPLETE(type!=PL2303_DETECT_TYPE_FAILED); + if (type == PL2303_SUPPORTS_HX_STATUS_TRIGGERED) { + break; + } // else: no transfer triggered and continue with CONFIG_PL2303_READ1 + TU_ATTR_FALLTHROUGH; + + case CONFIG_PL2303_READ1: + // get supports_hx_status, type and quirks (step 2), do special read + p_cdc->pl2303.supports_hx_status = ( // will not be true, if coming directly from previous case + xfer->user_data == CONFIG_PL2303_READ1 && xfer->result == XFER_RESULT_SUCCESS ); + type = pl2303_detect_type (p_cdc, idx, 2, NULL, 0); // step 2 now with supports_hx_status + TU_ASSERT_COMPLETE(type!=PL2303_DETECT_TYPE_FAILED); + p_cdc->pl2303.serial_private.type = &pl2303_type_data[type]; + p_cdc->pl2303.serial_private.quirks |= p_cdc->pl2303.serial_private.type->quirks; + #if CFG_TUSB_DEBUG >= CFG_TUH_CDC_LOG_LEVEL && 0 // can be activated if necessary + TU_LOG(CFG_TUH_CDC_LOG_LEVEL, "PL2303 bDeviceClass = 0x%02x bMaxPacketSize0 = %u bcdUSB = 0x%04x bcdDevice = 0x%04x", + desc_dev[idx]->bDeviceClass, desc_dev[idx]->bMaxPacketSize0, desc_dev[idx]->bcdUSB, desc_dev[idx]->bcdDevice ); + uint16_t vid, pid; + TU_ASSERT_COMPLETE(tuh_vid_pid_get(p_cdc->daddr, &vid, &pid)); + TU_LOG(CFG_TUH_CDC_LOG_LEVEL, " vid = 0x%04x pid = 0x%04x supports_hx_status = %u type = %s quirks = %u", + vid, pid, p_cdc->pl2303.supports_hx_status, + p_cdc->pl2303.serial_private.type->name, p_cdc->pl2303.serial_private.quirks); + #endif + // purpose unknown, overtaken from Linux Kernel driver + if (p_cdc->pl2303.serial_private.type != &pl2303_type_data[TYPE_HXN]) { + TU_ASSERT_COMPLETE(pl2303_vendor_read(p_cdc, 0x8484, &buf, pl2303_process_config, CONFIG_PL2303_WRITE1)); + break; + } // else: continue with next step + TU_ATTR_FALLTHROUGH; + + case CONFIG_PL2303_WRITE1: + // purpose unknown, overtaken from Linux Kernel driver + if (p_cdc->pl2303.serial_private.type != &pl2303_type_data[TYPE_HXN]) { + TU_ASSERT_COMPLETE(pl2303_vendor_write(p_cdc, 0x0404, 0, pl2303_process_config, CONFIG_PL2303_READ2)); + break; + } // else: continue with next step + TU_ATTR_FALLTHROUGH; + + case CONFIG_PL2303_READ2: + // purpose unknown, overtaken from Linux Kernel driver + if (p_cdc->pl2303.serial_private.type != &pl2303_type_data[TYPE_HXN]) { + TU_ASSERT_COMPLETE(pl2303_vendor_read(p_cdc, 0x8484, &buf, pl2303_process_config, CONFIG_PL2303_READ3)); + break; + } // else: continue with next step + TU_ATTR_FALLTHROUGH; + + case CONFIG_PL2303_READ3: + // purpose unknown, overtaken from Linux Kernel driver + if (p_cdc->pl2303.serial_private.type != &pl2303_type_data[TYPE_HXN]) { + TU_ASSERT_COMPLETE(pl2303_vendor_read(p_cdc, 0x8383, &buf, pl2303_process_config, CONFIG_PL2303_READ4)); + break; + } // else: continue with next step + TU_ATTR_FALLTHROUGH; + + case CONFIG_PL2303_READ4: + // purpose unknown, overtaken from Linux Kernel driver + if (p_cdc->pl2303.serial_private.type != &pl2303_type_data[TYPE_HXN]) { + TU_ASSERT_COMPLETE(pl2303_vendor_read(p_cdc, 0x8484, &buf, pl2303_process_config, CONFIG_PL2303_WRITE2)); + break; + } // else: continue with next step + TU_ATTR_FALLTHROUGH; + + case CONFIG_PL2303_WRITE2: + // purpose unknown, overtaken from Linux Kernel driver + if (p_cdc->pl2303.serial_private.type != &pl2303_type_data[TYPE_HXN]) { + TU_ASSERT_COMPLETE(pl2303_vendor_write(p_cdc, 0x0404, 1, pl2303_process_config, CONFIG_PL2303_READ5)); + break; + } // else: continue with next step + TU_ATTR_FALLTHROUGH; + + case CONFIG_PL2303_READ5: + // purpose unknown, overtaken from Linux Kernel driver + if (p_cdc->pl2303.serial_private.type != &pl2303_type_data[TYPE_HXN]) { + TU_ASSERT_COMPLETE(pl2303_vendor_read(p_cdc, 0x8484, &buf, pl2303_process_config, CONFIG_PL2303_READ6)); + break; + } // else: continue with next step + TU_ATTR_FALLTHROUGH; + + case CONFIG_PL2303_READ6: + // purpose unknown, overtaken from Linux Kernel driver + if (p_cdc->pl2303.serial_private.type != &pl2303_type_data[TYPE_HXN]) { + TU_ASSERT_COMPLETE(pl2303_vendor_read(p_cdc, 0x8383, &buf, pl2303_process_config, CONFIG_PL2303_WRITE3)); + break; + } // else: continue with next step + TU_ATTR_FALLTHROUGH; + + case CONFIG_PL2303_WRITE3: + // purpose unknown, overtaken from Linux Kernel driver + if (p_cdc->pl2303.serial_private.type != &pl2303_type_data[TYPE_HXN]) { + TU_ASSERT_COMPLETE(pl2303_vendor_write(p_cdc, 0, 1, pl2303_process_config, CONFIG_PL2303_WRITE4)); + break; + } // else: continue with next step + TU_ATTR_FALLTHROUGH; + + case CONFIG_PL2303_WRITE4: + // purpose unknown, overtaken from Linux Kernel driver + if (p_cdc->pl2303.serial_private.type != &pl2303_type_data[TYPE_HXN]) { + TU_ASSERT_COMPLETE(pl2303_vendor_write(p_cdc, 1, 0, pl2303_process_config, CONFIG_PL2303_WRITE5)); + break; + } // else: continue with next step + TU_ATTR_FALLTHROUGH; + + case CONFIG_PL2303_WRITE5: + // purpose unknown, overtaken from Linux Kernel driver + if (p_cdc->pl2303.serial_private.type != &pl2303_type_data[TYPE_HXN]) { + if (p_cdc->pl2303.serial_private.quirks & PL2303_QUIRK_LEGACY) { + TU_ASSERT_COMPLETE(pl2303_vendor_write(p_cdc, 2, 0x24, pl2303_process_config, CONFIG_PL2303_RESET_ENDP1)); + } else { + TU_ASSERT_COMPLETE(pl2303_vendor_write(p_cdc, 2, 0x44, pl2303_process_config, CONFIG_PL2303_RESET_ENDP1)); + } + break; + } // else: continue with next step + TU_ATTR_FALLTHROUGH; + + // from here sequence overtaken from Linux Kernel function pl2303_open() + case CONFIG_PL2303_RESET_ENDP1: + // step 1 + if (p_cdc->pl2303.serial_private.quirks & PL2303_QUIRK_LEGACY) { + TU_ASSERT_COMPLETE(pl2303_clear_halt(p_cdc, PL2303_OUT_EP, pl2303_process_config, CONFIG_PL2303_RESET_ENDP2)); + } else { + /* reset upstream data pipes */ + if (p_cdc->pl2303.serial_private.type == &pl2303_type_data[TYPE_HXN]) { + TU_ASSERT_COMPLETE(pl2303_vendor_write(p_cdc, PL2303_HXN_RESET_REG, // skip CONFIG_PL2303_RESET_ENDP2, no 2nd step + PL2303_HXN_RESET_UPSTREAM_PIPE | PL2303_HXN_RESET_DOWNSTREAM_PIPE, + pl2303_process_config, CONFIG_PL2303_LINE_CODING)); + } else { + pl2303_vendor_write(p_cdc, 8, 0, pl2303_process_config, CONFIG_PL2303_RESET_ENDP2); + } + } + break; + + case CONFIG_PL2303_RESET_ENDP2: + // step 2 + if (p_cdc->pl2303.serial_private.quirks & PL2303_QUIRK_LEGACY) { + TU_ASSERT_COMPLETE(pl2303_clear_halt(p_cdc, PL2303_IN_EP, pl2303_process_config, CONFIG_PL2303_LINE_CODING)); + } else { + /* reset upstream data pipes */ + if (p_cdc->pl2303.serial_private.type == &pl2303_type_data[TYPE_HXN]) { + // here nothing to do, only structure of previous step overtaken for better reading and comparison + } else { + TU_ASSERT_COMPLETE(pl2303_vendor_write(p_cdc, 9, 0, pl2303_process_config, CONFIG_PL2303_LINE_CODING)); + } + } + break; + + // from here sequence overtaken from Linux Kernel function pl2303_set_termios() + // unnecessary pl2303_get_line_request() is skipped due to a stall + case CONFIG_PL2303_LINE_CODING: + #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM + p_cdc->requested_line_coding = (cdc_line_coding_t) CFG_TUH_CDC_LINE_CODING_ON_ENUM; + TU_ASSERT_COMPLETE( pl2303_set_line_request(p_cdc, pl2303_internal_control_complete, CONFIG_PL2303_MODEM_CONTROL)); + break; + #else + TU_ATTR_FALLTHROUGH; + #endif + + case CONFIG_PL2303_MODEM_CONTROL: + #ifdef CFG_TUH_CDC_LINE_CONTROL_ON_ENUM + p_cdc->requested_line_state = CFG_TUH_CDC_LINE_CONTROL_ON_ENUM; + TU_ASSERT_COMPLETE(pl2303_set_control_lines(p_cdc, pl2303_internal_control_complete, CONFIG_PL2303_FLOW_CTRL_READ)); + break; + #else + TU_ATTR_FALLTHROUGH; + #endif + + case CONFIG_PL2303_FLOW_CTRL_READ: + // read flow control register for modify & write back in next step + if (p_cdc->pl2303.serial_private.type == &pl2303_type_data[TYPE_HXN]) { + TU_ASSERT_COMPLETE(pl2303_vendor_read(p_cdc, PL2303_HXN_FLOWCTRL_REG, &buf, pl2303_process_config, + CONFIG_PL2303_FLOW_CTRL_WRITE)); + } else { + TU_ASSERT_COMPLETE(pl2303_vendor_read(p_cdc, 0, &buf, pl2303_process_config, CONFIG_PL2303_FLOW_CTRL_WRITE)); + } + break; + + case CONFIG_PL2303_FLOW_CTRL_WRITE: + // no flow control + buf = xfer->buffer[0]; + if (p_cdc->pl2303.serial_private.type == &pl2303_type_data[TYPE_HXN]) { + buf &= (uint8_t) ~PL2303_HXN_FLOWCTRL_MASK; + buf |= PL2303_HXN_FLOWCTRL_NONE; + TU_ASSERT_COMPLETE(pl2303_vendor_write(p_cdc, PL2303_HXN_FLOWCTRL_REG, buf, pl2303_process_config, + CONFIG_PL2303_COMPLETE)); + } else { + buf &= (uint8_t) ~PL2303_FLOWCTRL_MASK; + TU_ASSERT_COMPLETE(pl2303_vendor_write(p_cdc, 0, buf, pl2303_process_config, CONFIG_PL2303_COMPLETE)); + } + break; + + case CONFIG_PL2303_COMPLETE: + set_config_complete(idx, 0, true); + break; + + default: + set_config_complete(idx, 0, false); + break; + } +} + +//------------- Helper -------------// + +static int8_t pl2303_detect_type(cdch_interface_t * p_cdc, uint8_t const idx, uint8_t step, + tuh_xfer_cb_t complete_cb, uintptr_t user_data ) +{ + /* + * Legacy PL2303H, variants 0 and 1 (difference unknown). + */ + if (desc_dev[idx]->bDeviceClass == 0x02) { + return TYPE_H; /* variant 0 */ + } + + if (desc_dev[idx]->bMaxPacketSize0 != 0x40) { + if (desc_dev[idx]->bDeviceClass == 0x00 || desc_dev[idx]->bDeviceClass == 0xff) { + return TYPE_H; /* variant 1 */ + } + return TYPE_H; /* variant 0 */ + } + + switch (desc_dev[idx]->bcdUSB) { + case 0x101: + /* USB 1.0.1? Let's assume they meant 1.1... */ + TU_ATTR_FALLTHROUGH; + case 0x110: + switch (desc_dev[idx]->bcdDevice) { + case 0x300: + return TYPE_HX; + case 0x400: + return TYPE_HXD; + default: + return TYPE_HX; + } + break; + case 0x200: + switch (desc_dev[idx]->bcdDevice) { + case 0x100: /* GC */ + case 0x105: + return TYPE_HXN; + case 0x300: /* GT / TA */ + if (step == 1) { + // step 1 trigger pl2303_supports_hx_status() request + TU_ASSERT(pl2303_supports_hx_status (p_cdc, complete_cb, user_data), PL2303_DETECT_TYPE_FAILED); + return PL2303_SUPPORTS_HX_STATUS_TRIGGERED; + } else { + // step 2 use supports_hx_status + if (p_cdc->pl2303.supports_hx_status) { + return TYPE_TA; + } + } + TU_ATTR_FALLTHROUGH; + case 0x305: + case 0x400: /* GL */ + case 0x405: + return TYPE_HXN; + case 0x500: /* GE / TB */ + if (step == 1) { + // step 1 trigger pl2303_supports_hx_status() request + TU_ASSERT(pl2303_supports_hx_status (p_cdc, complete_cb, user_data), PL2303_DETECT_TYPE_FAILED); + return PL2303_SUPPORTS_HX_STATUS_TRIGGERED; + } else { + // step 2 use supports_hx_status + if (p_cdc->pl2303.supports_hx_status) { + return TYPE_TB; + } + } + TU_ATTR_FALLTHROUGH; + case 0x505: + case 0x600: /* GS */ + case 0x605: + case 0x700: /* GR */ + case 0x705: + return TYPE_HXN; + default: + break; + } + break; + default: break; + } + + TU_LOG_P_CDC("unknown device type bcdUSB = 0x%04x", desc_dev[idx]->bcdUSB); + + return PL2303_DETECT_TYPE_FAILED; +} + +/* + * Returns the nearest supported baud rate that can be set directly without + * using divisors. + */ +static uint32_t pl2303_get_supported_baud_rate(uint32_t baud) +{ + static const uint32_t baud_sup[] = { + 75, 150, 300, 600, 1200, 1800, 2400, 3600, 4800, 7200, 9600, + 14400, 19200, 28800, 38400, 57600, 115200, 230400, 460800, + 614400, 921600, 1228800, 2457600, 3000000, 6000000 + }; + + uint8_t i; + for (i = 0; i < TU_ARRAY_SIZE(baud_sup); ++i) { + if (baud_sup[i] > baud) { + break; + } + } + + if (i == TU_ARRAY_SIZE(baud_sup)) { + baud = baud_sup[i - 1]; + } else if (i > 0 && (baud_sup[i] - baud) > (baud - baud_sup[i - 1])) { + baud = baud_sup[i - 1]; + } else { + baud = baud_sup[i]; + } + + return baud; +} + +/* + * NOTE: If unsupported baud rates are set directly, the PL2303 seems to + * use 9600 baud. + */ +static uint32_t pl2303_encode_baud_rate_direct(uint8_t buf[PL2303_LINE_CODING_BAUDRATE_BUFSIZE], uint32_t baud) +{ + uint32_t baud_le = tu_htole32(baud); + buf[0] = (uint8_t) ( baud_le & 0xff); + buf[1] = (uint8_t) ((baud_le >> 8) & 0xff); + buf[2] = (uint8_t) ((baud_le >> 16) & 0xff); + buf[3] = (uint8_t) ((baud_le >> 24) & 0xff); + + return baud; +} + +static uint32_t pl2303_encode_baud_rate_divisor(uint8_t buf[PL2303_LINE_CODING_BAUDRATE_BUFSIZE], uint32_t baud) +{ + uint32_t baseline, mantissa, exponent; + + /* + * Apparently the formula is: + * baudrate = 12M * 32 / (mantissa * 4^exponent) + * where + * mantissa = buf[8:0] + * exponent = buf[11:9] + */ + baseline = 12000000 * 32; + mantissa = baseline / baud; + if (mantissa == 0) + mantissa = 1; /* Avoid dividing by zero if baud > 32 * 12M. */ + exponent = 0; + while (mantissa >= 512) { + if (exponent < 7) { + mantissa >>= 2; /* divide by 4 */ + exponent++; + } else { + /* Exponent is maxed. Trim mantissa and leave. */ + mantissa = 511; + break; + } + } + + buf[3] = 0x80; + buf[2] = 0; + buf[1] = (uint8_t) ((exponent << 1 | mantissa >> 8) & 0xff); + buf[0] = (uint8_t) (mantissa & 0xff); + + /* Calculate and return the exact baud rate. */ + baud = (baseline / mantissa) >> (exponent << 1); + + return baud; +} + +static uint32_t pl2303_encode_baud_rate_divisor_alt(uint8_t buf[PL2303_LINE_CODING_BAUDRATE_BUFSIZE], uint32_t baud) +{ + uint32_t baseline, mantissa, exponent; + + /* + * Apparently, for the TA version the formula is: + * baudrate = 12M * 32 / (mantissa * 2^exponent) + * where + * mantissa = buf[10:0] + * exponent = buf[15:13 16] + */ + baseline = 12000000 * 32; + mantissa = baseline / baud; + if (mantissa == 0) { + mantissa = 1; /* Avoid dividing by zero if baud > 32 * 12M. */ + } + exponent = 0; + while (mantissa >= 2048) { + if (exponent < 15) { + mantissa >>= 1; /* divide by 2 */ + exponent++; + } else { + /* Exponent is maxed. Trim mantissa and leave. */ + mantissa = 2047; + break; + } + } + + buf[3] = 0x80; + buf[2] = (uint8_t) (exponent & 0x01); + buf[1] = (uint8_t) (((exponent & (uint32_t) ~0x01) << 4 | mantissa >> 8 ) & 0xff); + buf[0] = (uint8_t) (mantissa & 0xff); + + /* Calculate and return the exact baud rate. */ + baud = (baseline / mantissa) >> exponent; + + return baud; +} + +static bool pl2303_encode_baud_rate(cdch_interface_t * p_cdc, uint8_t buf[PL2303_LINE_CODING_BAUDRATE_BUFSIZE]) +{ + uint32_t baud = p_cdc->requested_line_coding.bit_rate; + uint32_t baud_sup; + + TU_VERIFY(baud && baud <= p_cdc->pl2303.serial_private.type->max_baud_rate); + /* + * Use direct method for supported baud rates, otherwise use divisors. + * Newer chip types do not support divisor encoding. + */ + if (p_cdc->pl2303.serial_private.type->no_divisors) { + baud_sup = baud; + } else { + baud_sup = pl2303_get_supported_baud_rate(baud); + } + + if (baud == baud_sup) { + baud = pl2303_encode_baud_rate_direct(buf, baud); + } else if (p_cdc->pl2303.serial_private.type->alt_divisors) { + baud = pl2303_encode_baud_rate_divisor_alt(buf, baud); + } else { + baud = pl2303_encode_baud_rate_divisor(buf, baud); + } + TU_LOG_P_CDC("real baudrate = %lu", baud); + + return true; +} + +#endif // CFG_TUH_CDC_PL2303 + #endif diff --git a/src/class/cdc/serial/pl2303.h b/src/class/cdc/serial/pl2303.h new file mode 100644 index 000000000..bf264191b --- /dev/null +++ b/src/class/cdc/serial/pl2303.h @@ -0,0 +1,172 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2024 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 _PL2303_H_ +#define _PL2303_H_ + +#include +#include + +// There is no official documentation for the PL2303 chips. +// Reference can be found +// - https://github.com/torvalds/linux/blob/master/drivers/usb/serial/pl2303.h and +// https://github.com/torvalds/linux/blob/master/drivers/usb/serial/pl2303.c +// - https://github.com/freebsd/freebsd-src/blob/main/sys/dev/usb/serial/uplcom.c + +/* quirks */ +#define PL2303_QUIRK_UART_STATE_IDX0 1 +#define PL2303_QUIRK_LEGACY 2 +#define PL2303_QUIRK_ENDPOINT_HACK 4 + +/* requests and bits */ +#define PL2303_SET_LINE_REQUEST_TYPE 0x21 // class request host to device interface +#define PL2303_SET_LINE_REQUEST 0x20 // dec 32 + +#define PL2303_SET_CONTROL_REQUEST_TYPE 0x21 // class request host to device interface +#define PL2303_SET_CONTROL_REQUEST 0x22 // dec 34 +#define PL2303_CONTROL_DTR 0x01 // dec 1 +#define PL2303_CONTROL_RTS 0x02 // dec 2 + +#define PL2303_BREAK_REQUEST_TYPE 0x21 // class request host to device interface +#define PL2303_BREAK_REQUEST 0x23 // dec 35 +#define PL2303_BREAK_ON 0xffff +#define PL2303_BREAK_OFF 0x0000 + +#define PL2303_GET_LINE_REQUEST_TYPE 0xa1 // class request device to host interface +#define PL2303_GET_LINE_REQUEST 0x21 // dec 33 + +#define PL2303_VENDOR_WRITE_REQUEST_TYPE 0x40 // vendor request host to device interface +#define PL2303_VENDOR_WRITE_REQUEST 0x01 // dec 1 +#define PL2303_VENDOR_WRITE_NREQUEST 0x80 // dec 128 + +#define PL2303_VENDOR_READ_REQUEST_TYPE 0xc0 // vendor request device to host interface +#define PL2303_VENDOR_READ_REQUEST 0x01 // dec 1 +#define PL2303_VENDOR_READ_NREQUEST 0x81 // dec 129 + +#define PL2303_UART_STATE_INDEX 8 +#define PL2303_UART_STATE_MSR_MASK 0x8b +#define PL2303_UART_STATE_TRANSIENT_MASK 0x74 +#define PL2303_UART_DCD 0x01 +#define PL2303_UART_DSR 0x02 +#define PL2303_UART_BREAK_ERROR 0x04 +#define PL2303_UART_RING 0x08 +#define PL2303_UART_FRAME_ERROR 0x10 +#define PL2303_UART_PARITY_ERROR 0x20 +#define PL2303_UART_OVERRUN_ERROR 0x40 +#define PL2303_UART_CTS 0x80 + +#define PL2303_FLOWCTRL_MASK 0xf0 + +#define PL2303_CLEAR_HALT_REQUEST_TYPE 0x02 // standard request host to device endpoint + +/* registers via vendor read/write requests */ +#define PL2303_READ_TYPE_HX_STATUS 0x8080 + +#define PL2303_HXN_RESET_REG 0x07 +#define PL2303_HXN_RESET_UPSTREAM_PIPE 0x02 +#define PL2303_HXN_RESET_DOWNSTREAM_PIPE 0x01 + +#define PL2303_HXN_FLOWCTRL_REG 0x0a +#define PL2303_HXN_FLOWCTRL_MASK 0x1c +#define PL2303_HXN_FLOWCTRL_NONE 0x1c +#define PL2303_HXN_FLOWCTRL_RTS_CTS 0x18 +#define PL2303_HXN_FLOWCTRL_XON_XOFF 0x0c + +/* type data */ +enum pl2303_type { + TYPE_H, + TYPE_HX, + TYPE_TA, + TYPE_TB, + TYPE_HXD, + TYPE_HXN, + TYPE_COUNT +}; + +struct pl2303_type_data { + uint8_t const *name; + uint32_t const max_baud_rate; + uint8_t const quirks; + uint16_t const no_autoxonxoff:1; + uint16_t const no_divisors:1; + uint16_t const alt_divisors:1; +}; + +#define PL2303_TYPE_DATA \ + [TYPE_H] = { \ + .name = (uint8_t const*)"H", \ + .max_baud_rate = 1228800, \ + .quirks = PL2303_QUIRK_LEGACY, \ + .no_autoxonxoff = true, \ + }, \ + [TYPE_HX] = { \ + .name = (uint8_t const*)"HX", \ + .max_baud_rate = 6000000, \ + }, \ + [TYPE_TA] = { \ + .name = (uint8_t const*)"TA", \ + .max_baud_rate = 6000000, \ + .alt_divisors = true, \ + }, \ + [TYPE_TB] = { \ + .name = (uint8_t const*)"TB", \ + .max_baud_rate = 12000000, \ + .alt_divisors = true, \ + }, \ + [TYPE_HXD] = { \ + .name = (uint8_t const*)"HXD", \ + .max_baud_rate = 12000000, \ + }, \ + [TYPE_HXN] = { \ + .name = (uint8_t const*)"G (HXN)", \ + .max_baud_rate = 12000000, \ + .no_divisors = true, \ + } + +/* private data types */ +struct pl2303_serial_private { + const struct pl2303_type_data* type; + uint8_t quirks; +}; + +typedef struct TU_ATTR_PACKED { + struct pl2303_serial_private serial_private; + bool supports_hx_status; +} pl2303_private_t; + +/* buffer sizes for line coding data */ +#define PL2303_LINE_CODING_BUFSIZE 7 +#define PL2303_LINE_CODING_BAUDRATE_BUFSIZE 4 + +/* bulk endpoints */ +#define PL2303_OUT_EP 0x02 +#define PL2303_IN_EP 0x83 + +/* return values of pl2303_detect_type() */ +#define PL2303_SUPPORTS_HX_STATUS_TRIGGERED -1 +#define PL2303_DETECT_TYPE_FAILED -2 + +#endif /* _PL2303_H_ */ diff --git a/src/tusb_option.h b/src/tusb_option.h index 281341685..f023b490a 100644 --- a/src/tusb_option.h +++ b/src/tusb_option.h @@ -504,6 +504,24 @@ { 0x9986, 0x7523 } /* overtaken from Linux Kernel driver /drivers/usb/serial/ch341.c */ #endif +#ifndef CFG_TUH_CDC_PL2303 + // PL2303 is not part of CDC class, only to re-use CDC driver API + #define CFG_TUH_CDC_PL2303 0 +#endif + +#ifndef CFG_TUH_CDC_PL2303_VID_PID_QUIRKS_LIST + // List of product IDs that can use the PL2303 CDC driver + #define CFG_TUH_CDC_PL2303_VID_PID_LIST \ + { 0x067b, 0x2303 }, /* initial 2303 */ \ + { 0x067b, 0x2304 }, /* TB */ \ + { 0x067b, 0x23a3 }, /* GC */ \ + { 0x067b, 0x23b3 }, /* GB */ \ + { 0x067b, 0x23c3 }, /* GT */ \ + { 0x067b, 0x23d3 }, /* GL */ \ + { 0x067b, 0x23e3 }, /* GE */ \ + { 0x067b, 0x23f3 } /* GS */ +#endif + #ifndef CFG_TUH_HID #define CFG_TUH_HID 0 #endif -- cgit v1.3.1 From ea175a78aad5bd258954aa61550aae0162bc884b Mon Sep 17 00:00:00 2001 From: IngHK Date: Sat, 24 Feb 2024 13:00:46 +0100 Subject: updated contribution, readme and some comments --- CONTRIBUTORS.rst | 7 +++++++ README.rst | 2 +- src/class/cdc/cdc_host.c | 6 +++--- 3 files changed, 11 insertions(+), 4 deletions(-) (limited to 'src/class') diff --git a/CONTRIBUTORS.rst b/CONTRIBUTORS.rst index 085f8082a..451ac0783 100644 --- a/CONTRIBUTORS.rst +++ b/CONTRIBUTORS.rst @@ -31,6 +31,13 @@ Notable contributors - Most features development +`Heiko Kuester `__ +-------------------------------------------- + +- Add CH34x and PL2303 support (CDC host) +- Improve FTDI and CP210x support (CDC host) + + `Hristo Gochkov `__ ------------------------------------------------- diff --git a/README.rst b/README.rst index fe2417451..6922c231e 100644 --- a/README.rst +++ b/README.rst @@ -77,7 +77,7 @@ Host Stack - Human Interface Device (HID): Keyboard, Mouse, Generic - Mass Storage Class (MSC) - Communication Device Class: CDC-ACM -- Vendor serial over USB: FTDI, CP210x +- Vendor serial over USB: FTDI, CP210x, CH34x, PL2303 - Hub with multiple-level support Similar to the Device Stack, if you have a special requirement, `usbh_app_driver_get_cb()` can be used to write your own class driver without modifying the stack. diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index 429d0a113..b35a8fd93 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -24,7 +24,7 @@ * This file is part of the TinyUSB stack. * * Contribution - * - Heiko Kuester: CH34x support + * - Heiko Kuester: add support of CH34x & PL2303, improve support of FTDI & CP210x */ #include "tusb_option.h" @@ -818,12 +818,12 @@ bool cdch_set_config(uint8_t daddr, uint8_t itf_num) { TU_ASSERT(p_cdc && p_cdc->serial_drid < SERIAL_DRIVER_COUNT); TU_LOG_P_CDC("set config"); - // fake transfer to kick-off process + // fake transfer to kick-off process_set_config() tuh_xfer_t xfer; xfer.daddr = daddr; xfer.result = XFER_RESULT_SUCCESS; xfer.setup = &request; - xfer.user_data = 0; // initial state + xfer.user_data = 0; // initial state 0 serial_drivers[p_cdc->serial_drid].process_set_config(&xfer); return true; -- cgit v1.3.1 From 2b507dba4d9901d1208c4166bbc6026bb6062c9b Mon Sep 17 00:00:00 2001 From: IngHK Date: Sat, 24 Feb 2024 13:01:38 +0100 Subject: small changes & code style --- src/class/cdc/cdc_host.c | 236 +++++++++++++++++++++++++---------------------- 1 file changed, 124 insertions(+), 112 deletions(-) (limited to 'src/class') diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index b35a8fd93..50aa4b6f0 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -85,7 +85,7 @@ typedef struct { tuh_xfer_cb_t user_control_cb; #if CFG_TUH_CDC_FTDI || CFG_TUH_CDC_CP210X || CFG_TUH_CDC_CH34X - tuh_xfer_cb_t requested_complete_cb; + tuh_xfer_cb_t requested_complete_cb; #endif #if CFG_TUH_CDC_FTDI @@ -119,54 +119,54 @@ 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_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, tuh_xfer_cb_t complete_cb, uintptr_t user_data); -static bool acm_set_data_format(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); -static bool acm_set_line_coding(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); -static bool acm_set_control_line_state(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); +static bool acm_set_baudrate(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); +static bool acm_set_data_format(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); +static bool acm_set_line_coding(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); +static bool acm_set_control_line_state(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); //------------- FTDI prototypes -------------// #if CFG_TUH_CDC_FTDI static uint16_t const ftdi_vid_pid_list[][2] = {CFG_TUH_CDC_FTDI_VID_PID_LIST}; #if CFG_TUSB_DEBUG && CFG_TUSB_DEBUG >= CFG_TUH_CDC_LOG_LEVEL -static uint8_t const * ftdi_chip_name[] = { FTDI_CHIP_NAMES }; + static uint8_t const * ftdi_chip_name[] = { FTDI_CHIP_NAMES }; #endif -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_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_baudrate(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); -static bool ftdi_set_data_format(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); -static bool ftdi_set_line_coding(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); -static bool ftdi_set_modem_ctrl(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); +static bool ftdi_set_baudrate(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); +static bool ftdi_set_data_format(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); +static bool ftdi_set_line_coding(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); +static bool ftdi_set_modem_ctrl(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); #endif //------------- CP210X prototypes -------------// #if CFG_TUH_CDC_CP210X 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); +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, tuh_xfer_cb_t complete_cb, uintptr_t user_data); -static bool cp210x_set_data_format(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); -static bool cp210x_set_line_coding(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); -static bool cp210x_set_modem_ctrl(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); +static bool cp210x_set_baudrate(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); +static bool cp210x_set_data_format(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); +static bool cp210x_set_line_coding(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); +static bool cp210x_set_modem_ctrl(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); #endif //------------- CH34x prototypes -------------// #if CFG_TUH_CDC_CH34X 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, tuh_xfer_cb_t complete_cb, uintptr_t user_data); -static bool ch34x_set_data_format(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); -static bool ch34x_set_line_coding(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); -static bool ch34x_set_modem_ctrl(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); +static bool ch34x_set_baudrate(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); +static bool ch34x_set_data_format(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); +static bool ch34x_set_line_coding(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); +static bool ch34x_set_modem_ctrl(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); #endif //------------- PL2303 prototypes -------------// @@ -211,14 +211,14 @@ enum { 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, tuh_xfer_cb_t complete_cb, uintptr_t user_data); - bool (*const set_baudrate)(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); - bool (*const set_data_format)(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); - bool (*const set_line_coding)(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); + 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, tuh_xfer_cb_t complete_cb, uintptr_t user_data); + bool (*const set_baudrate)(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); + bool (*const set_data_format)(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); + bool (*const set_line_coding)(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); #if CFG_TUSB_DEBUG && CFG_TUSB_DEBUG >= CFG_TUH_CDC_LOG_LEVEL - uint8_t const * name; + uint8_t const * name; #endif } cdch_serial_driver_t; @@ -309,17 +309,17 @@ TU_VERIFY_STATIC(TU_ARRAY_SIZE(serial_drivers) == SERIAL_DRIVER_COUNT, "Serial d // 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]; + 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) && + cdch_interface_t * p_cdc = &cdch_data[i]; + if ((p_cdc->daddr == daddr) && (ep_addr == p_cdc->ep_notif || ep_addr == p_cdc->stream.rx.ep_addr || ep_addr == p_cdc->stream.tx.ep_addr)) { return i; } @@ -328,10 +328,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) { +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; @@ -345,7 +345,7 @@ static cdch_interface_t* make_new_itf(uint8_t daddr, tusb_desc_interface_t const return NULL; } -static bool open_ep_stream_pair(cdch_interface_t* p_cdc , tusb_desc_endpoint_t const *desc_ep); +static bool open_ep_stream_pair(cdch_interface_t * p_cdc , tusb_desc_endpoint_t const *desc_ep); //--------------------------------------------------------------------+ // APPLICATION API @@ -353,21 +353,21 @@ static bool open_ep_stream_pair(cdch_interface_t* p_cdc , tusb_desc_endpoint_t c uint8_t tuh_cdc_itf_get_index(uint8_t daddr, uint8_t itf_num) { for (uint8_t i = 0; i < CFG_TUH_CDC; i++) { - const cdch_interface_t* p_cdc = &cdch_data[i]; + const cdch_interface_t * p_cdc = &cdch_data[i]; if (p_cdc->daddr == 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) { - cdch_interface_t* p_cdc = get_itf(idx); +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); info->daddr = p_cdc->daddr; // re-construct descriptor - tusb_desc_interface_t* desc = &info->desc; + tusb_desc_interface_t * desc = &info->desc; desc->bLength = sizeof(tusb_desc_interface_t); desc->bDescriptorType = TUSB_DESC_INTERFACE; @@ -383,27 +383,27 @@ 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); + cdch_interface_t * p_cdc = get_itf(idx); TU_VERIFY(p_cdc); return p_cdc->mounted; } bool tuh_cdc_get_dtr(uint8_t idx) { - cdch_interface_t* p_cdc = get_itf(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) { - cdch_interface_t* p_cdc = get_itf(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) { - cdch_interface_t* p_cdc = get_itf(idx); +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); *line_coding = p_cdc->line_coding; @@ -415,29 +415,29 @@ 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) { - cdch_interface_t* p_cdc = get_itf(idx); +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) { - cdch_interface_t* p_cdc = get_itf(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) { - cdch_interface_t* p_cdc = get_itf(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) { - cdch_interface_t* p_cdc = get_itf(idx); + cdch_interface_t * p_cdc = get_itf(idx); TU_VERIFY(p_cdc); return tu_edpt_stream_write_available(&p_cdc->stream.tx); @@ -447,33 +447,34 @@ uint32_t tuh_cdc_write_available(uint8_t idx) { // Read //--------------------------------------------------------------------+ -uint32_t tuh_cdc_read (uint8_t idx, void* buffer, uint32_t bufsize) { - cdch_interface_t* p_cdc = get_itf(idx); +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) { - cdch_interface_t* p_cdc = get_itf(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) { - cdch_interface_t* p_cdc = get_itf(idx); +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) { - cdch_interface_t* p_cdc = get_itf(idx); + cdch_interface_t * p_cdc = get_itf(idx); TU_VERIFY(p_cdc); bool ret = tu_edpt_stream_clear(&p_cdc->stream.rx); tu_edpt_stream_read_xfer(&p_cdc->stream.rx); + return ret; } @@ -657,7 +658,7 @@ void cdch_init(void) { tu_memclr(cdch_data, sizeof(cdch_data)); for (size_t i = 0; i < CFG_TUH_CDC; i++) { - cdch_interface_t* p_cdc = &cdch_data[i]; + cdch_interface_t * p_cdc = &cdch_data[i]; tu_edpt_stream_init(&p_cdc->stream.tx, true, true, false, p_cdc->stream.tx_ff_buf, CFG_TUH_CDC_TX_BUFSIZE, @@ -671,7 +672,7 @@ void cdch_init(void) { void cdch_close(uint8_t daddr) { for (uint8_t idx = 0; idx < CFG_TUH_CDC; idx++) { - cdch_interface_t* p_cdc = &cdch_data[idx]; + cdch_interface_t * p_cdc = &cdch_data[idx]; if (p_cdc->daddr == daddr) { TU_LOG_P_CDC("close"); @@ -695,35 +696,37 @@ bool cdch_xfer_cb(uint8_t daddr, uint8_t ep_addr, xfer_result_t event, uint32_t cdch_interface_t * p_cdc = get_itf(idx); TU_ASSERT(p_cdc); - if ( ep_addr == p_cdc->stream.tx.ep_addr ) { + if (ep_addr == p_cdc->stream.tx.ep_addr) { // invoke tx complete callback to possibly refill tx fifo if (tuh_cdc_tx_complete_cb) tuh_cdc_tx_complete_cb(idx); - if ( 0 == tu_edpt_stream_write_xfer(&p_cdc->stream.tx) ) { + if (0 == tu_edpt_stream_write_xfer(&p_cdc->stream.tx)) { // If there is no data left, a ZLP should be sent if: // - 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 // 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 + } else #endif { tu_edpt_stream_read_xfer_complete(&p_cdc->stream.rx, xferred_bytes); } // invoke receive callback - if (tuh_cdc_rx_cb) tuh_cdc_rx_cb(idx); + if (tuh_cdc_rx_cb) { + tuh_cdc_rx_cb(idx); + } // prepare for next transfer if needed tu_edpt_stream_read_xfer(&p_cdc->stream.rx); - }else if ( ep_addr == p_cdc->ep_notif ) { + } else if (ep_addr == p_cdc->ep_notif) { // TODO handle notification endpoint - }else { + } else { TU_ASSERT(false); } @@ -734,7 +737,7 @@ 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) { +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); @@ -746,13 +749,13 @@ static bool open_ep_stream_pair(cdch_interface_t* p_cdc, tusb_desc_endpoint_t co tu_edpt_stream_open(&p_cdc->stream.tx, p_cdc->daddr, desc_ep); } - desc_ep = (tusb_desc_endpoint_t const*) tu_desc_next(desc_ep); + desc_ep = (tusb_desc_endpoint_t const *) tu_desc_next(desc_ep); } 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; cdch_serial_driver_t const * driver_detected = NULL; @@ -826,6 +829,7 @@ bool cdch_set_config(uint8_t daddr, uint8_t itf_num) { xfer.user_data = 0; // initial state 0 serial_drivers[p_cdc->serial_drid].process_set_config(&xfer); + return true; } @@ -864,7 +868,7 @@ static void acm_internal_control_complete(tuh_xfer_t * xfer) { } } -static bool acm_set_control_line_state(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { +static bool acm_set_control_line_state(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { TU_VERIFY(p_cdc->acm_capability.support_line_request); tusb_control_request_t const request = { @@ -886,15 +890,16 @@ static bool acm_set_control_line_state(cdch_interface_t* p_cdc, tuh_xfer_cb_t co .ep_addr = 0, .setup = &request, .buffer = NULL, - .complete_cb = complete_cb ? acm_internal_control_complete : NULL, // complete_cb is NULL for sync call + .complete_cb = complete_cb ? acm_internal_control_complete : NULL, .user_data = user_data }; TU_ASSERT(tuh_control_xfer(&xfer)); + return true; } -static bool acm_set_line_coding(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { +static bool acm_set_line_coding(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { TU_VERIFY(p_cdc->acm_capability.support_line_request); TU_VERIFY(p_cdc->requested_line_coding.data_bits && p_cdc->requested_line_coding.bit_rate); TU_VERIFY((p_cdc->requested_line_coding.data_bits >= 5 && p_cdc->requested_line_coding.data_bits <= 8) || @@ -913,30 +918,32 @@ static bool acm_set_line_coding(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_ }; // use usbh enum buf to hold line coding since user line_coding variable does not live long enough - uint8_t* enum_buf = usbh_get_enum_buf(); + uint8_t * enum_buf = usbh_get_enum_buf(); memcpy(enum_buf, &p_cdc->requested_line_coding, sizeof(cdc_line_coding_t)); p_cdc->user_control_cb = complete_cb; + tuh_xfer_t xfer = { .daddr = p_cdc->daddr, .ep_addr = 0, .setup = &request, .buffer = enum_buf, - .complete_cb = complete_cb ? acm_internal_control_complete : NULL, // complete_cb is NULL for sync call + .complete_cb = complete_cb ? acm_internal_control_complete : NULL, .user_data = user_data }; TU_ASSERT(tuh_control_xfer(&xfer)); + return true; } -static bool acm_set_data_format(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { +static bool acm_set_data_format(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { p_cdc->requested_line_coding.bit_rate = p_cdc->line_coding.bit_rate; return acm_set_line_coding(p_cdc, complete_cb, user_data); } -static bool acm_set_baudrate(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { +static bool acm_set_baudrate(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { p_cdc->requested_line_coding.stop_bits = p_cdc->line_coding.stop_bits; p_cdc->requested_line_coding.parity = p_cdc->line_coding.parity; p_cdc->requested_line_coding.data_bits = p_cdc->line_coding.data_bits; @@ -952,21 +959,22 @@ 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)) { // 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); @@ -975,7 +983,7 @@ static bool acm_open(uint8_t daddr, tusb_desc_interface_t const* itf_desc, uint1 // Open notification endpoint of control interface if any 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)); p_cdc->ep_notif = desc_ep->bEndpointAddress; @@ -985,22 +993,22 @@ static bool acm_open(uint8_t daddr, tusb_desc_interface_t const* itf_desc, uint1 //------------- 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)) { + (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); + cdch_interface_t * p_cdc = get_itf(idx); TU_ASSERT_COMPLETE(p_cdc && xfer->result == XFER_RESULT_SUCCESS, 1); switch (state) { @@ -1814,8 +1822,9 @@ static uint16_t ch34x_get_divisor_prescaler(cdch_interface_t * p_cdc); //------------- 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) { +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, @@ -1829,7 +1838,7 @@ static bool ch34x_set_request(cdch_interface_t* p_cdc, uint8_t direction, uint8_ }; // use usbh enum buf since application variable does not live long enough - uint8_t* enum_buf = NULL; + uint8_t * enum_buf = NULL; if (buffer && length > 0) { enum_buf = usbh_get_enum_buf(); @@ -1850,22 +1859,23 @@ static bool ch34x_set_request(cdch_interface_t* p_cdc, uint8_t direction, uint8_ return tuh_control_xfer(&xfer); } -static inline bool ch34x_control_out(cdch_interface_t* p_cdc, uint8_t request, uint16_t value, uint16_t index, +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 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) { +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); } -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) { +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); } -//static bool ch34x_read_reg_request ( cdch_interface_t* p_cdc, uint16_t reg, +//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, 0, buffer, buffersize, complete_cb, user_data ); @@ -1907,8 +1917,8 @@ static void ch34x_internal_control_complete(tuh_xfer_t * xfer) { // CH34x has only interface 0, because wIndex is used as payload and not for bInterfaceNumber uint8_t const itf_num = 0; uint8_t 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,); bool const success = (xfer->result == XFER_RESULT_SUCCESS); TU_LOG_P_CDC("control complete success = %u", success); @@ -1997,17 +2007,17 @@ 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 + 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); + 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); p_cdc->serial_drid = SERIAL_DRIVER_CH34X; - 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 TU_ASSERT(open_ep_stream_pair(p_cdc, desc_ep)); @@ -2023,11 +2033,11 @@ static bool ch34x_open(uint8_t daddr, tusb_desc_interface_t const* itf_desc, uin } static void ch34x_process_config(tuh_xfer_t* xfer) { - // CH34x has only interface 0, because wIndex is used as payload and not for bInterfaceNumber uintptr_t const state = xfer->user_data; + // CH34x has only interface 0, because wIndex is used 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); + cdch_interface_t * p_cdc = get_itf(idx); TU_ASSERT_COMPLETE(p_cdc && xfer->result == XFER_RESULT_SUCCESS); uint8_t buffer[2]; // TODO remove @@ -2035,7 +2045,7 @@ static void ch34x_process_config(tuh_xfer_t* xfer) { case CONFIG_CH34X_READ_VERSION: p_cdc->user_control_cb = ch34x_process_config; // set once for whole process config TU_ASSERT_COMPLETE(ch34x_control_in(p_cdc, CH34X_REQ_READ_VERSION, 0, 0, buffer, 2, - ch34x_process_config, CONFIG_CH34X_SERIAL_INIT)); + ch34x_process_config, CONFIG_CH34X_SERIAL_INIT)); break; case CONFIG_CH34X_SERIAL_INIT: { @@ -2060,19 +2070,20 @@ static void ch34x_process_config(tuh_xfer_t* xfer) { // 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_COMPLETE(ch34x_write_reg(p_cdc, TU_U16(CH341_REG_0x0F, CH341_REG_0x2C), 0x0007, - ch34x_process_config, CONFIG_CH34X_FLOW_CONTROL)); + ch34x_process_config, CONFIG_CH34X_FLOW_CONTROL)); break; case CONFIG_CH34X_FLOW_CONTROL: // no hardware flow control TU_ASSERT_COMPLETE(ch34x_write_reg(p_cdc, TU_U16(CH341_REG_0x27, CH341_REG_0x27), 0x0000, - ch34x_process_config, CONFIG_CH34X_MODEM_CONTROL)); + ch34x_process_config, CONFIG_CH34X_MODEM_CONTROL)); break; case CONFIG_CH34X_MODEM_CONTROL: #ifdef CFG_TUH_CDC_LINE_CONTROL_ON_ENUM p_cdc->requested_line_state = CFG_TUH_CDC_LINE_CONTROL_ON_ENUM; - TU_ASSERT_COMPLETE(ch34x_modem_ctrl_request(p_cdc, ch34x_internal_control_complete, CONFIG_CH34X_COMPLETE)); + TU_ASSERT_COMPLETE(ch34x_modem_ctrl_request(p_cdc, ch34x_internal_control_complete, + CONFIG_CH34X_COMPLETE)); break; #else TU_ATTR_FALLTHROUGH; @@ -2431,6 +2442,7 @@ static bool pl2303_open(uint8_t daddr, tusb_desc_interface_t const * itf_desc, u } static void pl2303_process_config(tuh_xfer_t * xfer) { + uintptr_t const state = xfer->user_data; // PL2303 has only interface 0, because wIndex is used 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); @@ -2440,7 +2452,7 @@ static void pl2303_process_config(tuh_xfer_t * xfer) { uint8_t buf; int8_t type; - switch (xfer->user_data) { + switch (state) { // from here sequence overtaken from Linux Kernel function pl2303_startup() case CONFIG_PL2303_GET_DESC: -- cgit v1.3.1 From da93fcfc6dbe51ceb73e990aefea9c8d55d3fc94 Mon Sep 17 00:00:00 2001 From: IngHK Date: Thu, 22 Feb 2024 15:09:25 +0100 Subject: improved TU_LOGs --- src/class/cdc/cdc_host.c | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) (limited to 'src/class') diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index 50aa4b6f0..f3fbe88ea 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -50,6 +50,7 @@ DADDR, ITF_NUM, NAME, ##__VA_ARGS__) #define TU_LOG_P_CDC(TXT,...) TU_LOG_CDC(TXT, p_cdc->daddr, p_cdc->bInterfaceNumber, \ serial_drivers[p_cdc->serial_drid].name, ##__VA_ARGS__) +#define TU_LOG_RESULT(TXT,RESULT) TU_LOG_P_CDC(TXT " " #RESULT " = %s", RESULT ? "true" : "FALSE" ) #define TU_ASSERT_COMPLETE_DEFINE(_cond, _itf_offset) \ do { \ @@ -587,6 +588,7 @@ bool tuh_cdc_set_control_line_state(uint8_t idx, uint16_t line_state, tuh_xfer_c if (ret && !complete_cb) { p_cdc->line_state = (uint8_t) line_state; } + TU_LOG_RESULT("set control line state", ret); return ret; } @@ -604,6 +606,7 @@ bool tuh_cdc_set_baudrate(uint8_t idx, uint32_t baudrate, tuh_xfer_cb_t complete if (ret && !complete_cb) { p_cdc->line_coding.bit_rate = baudrate; } + TU_LOG_RESULT("set baudrate", ret); return ret; } @@ -627,6 +630,7 @@ bool tuh_cdc_set_data_format(uint8_t idx, uint8_t stop_bits, uint8_t parity, uin p_cdc->line_coding.parity = parity; p_cdc->line_coding.data_bits = data_bits; } + TU_LOG_RESULT("set data format", ret); return ret; } @@ -646,6 +650,7 @@ bool tuh_cdc_set_line_coding(uint8_t idx, cdc_line_coding_t const * line_coding, if (ret && !complete_cb) { p_cdc->line_coding = *line_coding; } + TU_LOG_RESULT("set line coding", ret); return ret; } @@ -785,6 +790,7 @@ bool cdch_open(uint8_t rhport, uint8_t daddr, tusb_desc_interface_t const * itf_ if (driver_detected) { TU_LOG_CDC("open", daddr, itf_desc->bInterfaceNumber, driver_detected->name); bool ret = driver_detected->open(daddr, itf_desc, max_len); + TU_LOG_CDC("opened ret = %s", daddr, itf_desc->bInterfaceNumber, driver_detected->name, ret ? "true" : "FALSE" ); return ret; } @@ -794,7 +800,7 @@ bool cdch_open(uint8_t rhport, uint8_t daddr, tusb_desc_interface_t const * itf_ static void set_config_complete(uint8_t idx, uint8_t itf_offset, bool success) { cdch_interface_t * p_cdc = get_itf(idx); TU_ASSERT(p_cdc,); - TU_LOG_P_CDC("set config complete success = %u", success); + TU_LOG_RESULT("set config complete", success); if (success) { p_cdc->mounted = true; @@ -846,7 +852,7 @@ static void acm_internal_control_complete(tuh_xfer_t * xfer) { cdch_interface_t * p_cdc = get_itf(idx); TU_ASSERT(p_cdc,); bool const success = (xfer->result == XFER_RESULT_SUCCESS); - TU_LOG_P_CDC("control complete success = %u", success); + TU_LOG_RESULT(" control complete", success); if (success) { switch (xfer->setup->bRequest) { @@ -1131,7 +1137,7 @@ static void ftdi_internal_control_complete(tuh_xfer_t * xfer) { cdch_interface_t * p_cdc = get_itf(idx); TU_ASSERT(p_cdc,); bool const success = (xfer->result == XFER_RESULT_SUCCESS); - TU_LOG_P_CDC("control complete success = %u", success); + TU_LOG_RESULT(" control complete", success); if (success) { switch (xfer->setup->bRequest) { @@ -1407,7 +1413,7 @@ static bool ftdi_determine_type(cdch_interface_t * p_cdc, uint8_t const idx) break; } - TU_LOG_P_CDC("%s detected", ftdi_chip_name[p_cdc->ftdi.chip_type]); + TU_LOG_P_CDC(" %s detected", ftdi_chip_name[p_cdc->ftdi.chip_type]); return (p_cdc->ftdi.chip_type != UNKNOWN); } @@ -1554,7 +1560,7 @@ static inline uint32_t ftdi_get_divisor(cdch_interface_t * p_cdc) break; } - TU_LOG_P_CDC("Baudrate divisor 0x%lu", div_value); + TU_LOG_P_CDC(" Baudrate divisor 0x%lu", div_value); return div_value; } @@ -1663,7 +1669,7 @@ static void cp210x_internal_control_complete(tuh_xfer_t * xfer) { cdch_interface_t * p_cdc = get_itf(idx); TU_ASSERT(p_cdc,); bool const success = (xfer->result == XFER_RESULT_SUCCESS); - TU_LOG_P_CDC("control complete success = %u", success); + TU_LOG_RESULT(" control complete", success); if (success) { switch(xfer->setup->bRequest) { @@ -1920,7 +1926,7 @@ static void ch34x_internal_control_complete(tuh_xfer_t * xfer) { cdch_interface_t * p_cdc = get_itf(idx); TU_ASSERT(p_cdc,); bool const success = (xfer->result == XFER_RESULT_SUCCESS); - TU_LOG_P_CDC("control complete success = %u", success); + TU_LOG_RESULT(" control complete", success); if (success) { switch (xfer->setup->bRequest) { @@ -2051,7 +2057,7 @@ 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 const version = xfer->buffer[0]; - TU_LOG_P_CDC("Chip Version = %02x", version); + TU_LOG_P_CDC(" Chip Version = %02x", version); // only versions >= 0x30 are tested, below 0x30 seems having other programming // see drivers from WCH vendor, Linux kernel and FreeBSD TU_ASSERT_COMPLETE(version >= 0x30); @@ -2337,7 +2343,7 @@ static void pl2303_internal_control_complete(tuh_xfer_t * xfer) { cdch_interface_t * p_cdc = get_itf(idx); TU_ASSERT(p_cdc,); bool const success = (xfer->result == XFER_RESULT_SUCCESS); - TU_LOG_P_CDC("control complete success = %u", success); + TU_LOG_RESULT(" control complete", success); if (success) { if (xfer->setup->bRequest == PL2303_SET_LINE_REQUEST && @@ -2743,7 +2749,7 @@ static int8_t pl2303_detect_type(cdch_interface_t * p_cdc, uint8_t const idx, ui default: break; } - TU_LOG_P_CDC("unknown device type bcdUSB = 0x%04x", desc_dev[idx]->bcdUSB); + TU_LOG_P_CDC(" unknown device type bcdUSB = 0x%04x", desc_dev[idx]->bcdUSB); return PL2303_DETECT_TYPE_FAILED; } @@ -2893,7 +2899,7 @@ static bool pl2303_encode_baud_rate(cdch_interface_t * p_cdc, uint8_t buf[PL2303 } else { baud = pl2303_encode_baud_rate_divisor(buf, baud); } - TU_LOG_P_CDC("real baudrate = %lu", baud); + TU_LOG_P_CDC(" real baudrate = %lu", baud); return true; } -- cgit v1.3.1 From 46a861b0e31a7382d620986079abd0c373dfe6da Mon Sep 17 00:00:00 2001 From: IngHK Date: Fri, 23 Feb 2024 08:30:50 +0100 Subject: improved PL2303 TU_LOGs --- src/class/cdc/cdc_host.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'src/class') diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index f3fbe88ea..9d27b1e79 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -2486,13 +2486,14 @@ static void pl2303_process_config(tuh_xfer_t * xfer) { p_cdc->pl2303.serial_private.type = &pl2303_type_data[type]; p_cdc->pl2303.serial_private.quirks |= p_cdc->pl2303.serial_private.type->quirks; #if CFG_TUSB_DEBUG >= CFG_TUH_CDC_LOG_LEVEL && 0 // can be activated if necessary - TU_LOG(CFG_TUH_CDC_LOG_LEVEL, "PL2303 bDeviceClass = 0x%02x bMaxPacketSize0 = %u bcdUSB = 0x%04x bcdDevice = 0x%04x", - desc_dev[idx]->bDeviceClass, desc_dev[idx]->bMaxPacketSize0, desc_dev[idx]->bcdUSB, desc_dev[idx]->bcdDevice ); + TU_LOG_P_CDC(" bDeviceClass = 0x%02x bMaxPacketSize0 = %u bcdUSB = 0x%04x bcdDevice = 0x%04x", + desc_dev[idx]->bDeviceClass, desc_dev[idx]->bMaxPacketSize0, + desc_dev[idx]->bcdUSB, desc_dev[idx]->bcdDevice ); uint16_t vid, pid; TU_ASSERT_COMPLETE(tuh_vid_pid_get(p_cdc->daddr, &vid, &pid)); - TU_LOG(CFG_TUH_CDC_LOG_LEVEL, " vid = 0x%04x pid = 0x%04x supports_hx_status = %u type = %s quirks = %u", - vid, pid, p_cdc->pl2303.supports_hx_status, - p_cdc->pl2303.serial_private.type->name, p_cdc->pl2303.serial_private.quirks); + TU_LOG_P_CDC(" vid = 0x%04x pid = 0x%04x supports_hx_status = %u type = %s quirks = %u", + vid, pid, p_cdc->pl2303.supports_hx_status, + p_cdc->pl2303.serial_private.type->name, p_cdc->pl2303.serial_private.quirks); #endif // purpose unknown, overtaken from Linux Kernel driver if (p_cdc->pl2303.serial_private.type != &pl2303_type_data[TYPE_HXN]) { -- cgit v1.3.1 From f97e31226a959944785122d4c0c10d4b3304704c Mon Sep 17 00:00:00 2001 From: IngHK Date: Wed, 28 Feb 2024 13:07:40 +0100 Subject: FTDI fixed itf_num and some improvement --- src/class/cdc/cdc_host.c | 37 +++++++++++++++++++------------------ 1 file changed, 19 insertions(+), 18 deletions(-) (limited to 'src/class') diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index 9d27b1e79..33d201c07 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -1140,22 +1140,19 @@ static void ftdi_internal_control_complete(tuh_xfer_t * xfer) { TU_LOG_RESULT(" control complete", success); if (success) { - switch (xfer->setup->bRequest) { - case FTDI_SIO_SET_MODEM_CTRL_REQUEST: - p_cdc->line_state = p_cdc->requested_line_state; - break; - - case FTDI_SIO_SET_DATA_REQUEST: - 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; - - case FTDI_SIO_SET_BAUDRATE_REQUEST: - p_cdc->line_coding.bit_rate = p_cdc->requested_line_coding.bit_rate; - break; - - default: break; + if (xfer->setup->bRequest == FTDI_SIO_SET_MODEM_CTRL_REQUEST && + xfer->setup->bmRequestType == FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE ) { + p_cdc->line_state = p_cdc->requested_line_state; + } + if (xfer->setup->bRequest == FTDI_SIO_SET_DATA_REQUEST && + xfer->setup->bmRequestType == FTDI_SIO_SET_DATA_REQUEST_TYPE ) { + 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; + } + if (xfer->setup->bRequest == FTDI_SIO_SET_BAUDRATE_REQUEST && + xfer->setup->bmRequestType == FTDI_SIO_SET_BAUDRATE_REQUEST_TYPE ) { + p_cdc->line_coding.bit_rate = p_cdc->requested_line_coding.bit_rate; } } @@ -1180,7 +1177,10 @@ static bool ftdi_set_baudrate(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_c } static void ftdi_set_line_coding_stage1_complete(tuh_xfer_t * xfer) { - uint8_t const itf_num = (uint8_t) tu_le16toh(xfer->setup->wIndex); + uint8_t const idx = ftdi_get_idx(xfer); + cdch_interface_t * p_cdc = get_itf(idx); + TU_ASSERT(p_cdc,); + uint8_t const itf_num = p_cdc->bInterfaceNumber; set_line_coding_stage1_complete(xfer, itf_num, ftdi_set_data_request, // control request function to set data format ftdi_internal_control_complete); // control complete function to be called after request @@ -1413,7 +1413,8 @@ static bool ftdi_determine_type(cdch_interface_t * p_cdc, uint8_t const idx) break; } - TU_LOG_P_CDC(" %s detected", ftdi_chip_name[p_cdc->ftdi.chip_type]); + TU_LOG_P_CDC(" %s detected (bcdDevice = 0x%04x)", + ftdi_chip_name[p_cdc->ftdi.chip_type], desc_dev[idx]->bcdDevice); return (p_cdc->ftdi.chip_type != UNKNOWN); } -- cgit v1.3.1 From d3d61da0384d066b9930e8e5b658717983f02efb Mon Sep 17 00:00:00 2001 From: IngHK Date: Sun, 25 Feb 2024 17:20:02 +0100 Subject: improved & fixed compiler warnings device descriptor handling --- src/class/cdc/cdc_host.c | 44 +++++++++++++++++++++++--------------------- 1 file changed, 23 insertions(+), 21 deletions(-) (limited to 'src/class') diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index 33d201c07..c222e11db 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -111,8 +111,10 @@ typedef struct { CFG_TUH_MEM_SECTION static cdch_interface_t cdch_data[CFG_TUH_CDC]; + #if CFG_TUH_CDC_FTDI || CFG_TUH_CDC_PL2303 - static tusb_desc_device_t desc_dev[CFG_TUH_CDC][CFG_TUH_ENUMERATION_BUFSIZE]; + CFG_TUH_MEM_SECTION CFG_TUH_MEM_ALIGN + static tusb_desc_device_t desc_dev[CFG_TUH_ENUMERATION_BUFSIZE]; #endif //--------------------------------------------------------------------+ @@ -1054,7 +1056,7 @@ static void acm_process_config(tuh_xfer_t * xfer) { //--------------------------------------------------------------------+ #if CFG_TUH_CDC_FTDI -static bool ftdi_determine_type(cdch_interface_t * p_cdc, uint8_t const idx); +static bool ftdi_determine_type(cdch_interface_t * p_cdc); static uint32_t ftdi_get_divisor(cdch_interface_t * p_cdc); static uint8_t ftdi_get_idx(tuh_xfer_t * xfer); @@ -1255,7 +1257,7 @@ static void ftdi_process_config(tuh_xfer_t * xfer) { // get device descriptor p_cdc->user_control_cb = ftdi_process_config; // set once for whole process config if (itf_num == 0) { // only necessary for 1st interface. other interface overtake type from interface 0 - TU_ASSERT_COMPLETE(tuh_descriptor_get_device(xfer->daddr, desc_dev[idx], sizeof(tusb_desc_device_t), + TU_ASSERT_COMPLETE(tuh_descriptor_get_device(xfer->daddr, &desc_dev, sizeof(tusb_desc_device_t), ftdi_process_config, CONFIG_FTDI_DETERMINE_TYPE)); break; } @@ -1264,7 +1266,7 @@ static void ftdi_process_config(tuh_xfer_t * xfer) { case CONFIG_FTDI_DETERMINE_TYPE: // determine type if (itf_num == 0) { - TU_ASSERT_COMPLETE(ftdi_determine_type(p_cdc, idx)); + TU_ASSERT_COMPLETE(ftdi_determine_type(p_cdc)); } else { // other interfaces have same type as interface 0 uint8_t const idx_itf0 = tuh_cdc_itf_get_index(xfer->daddr, 0); @@ -1334,9 +1336,9 @@ static void ftdi_process_config(tuh_xfer_t * xfer) { //------------- Helper -------------// -static bool ftdi_determine_type(cdch_interface_t * p_cdc, uint8_t const idx) +static bool ftdi_determine_type(cdch_interface_t * p_cdc) { - uint16_t const version = desc_dev[idx]->bcdDevice; + uint16_t const version = desc_dev->bcdDevice; uint8_t const itf_num = p_cdc->bInterfaceNumber; p_cdc->ftdi.chip_type = UNKNOWN; @@ -1414,7 +1416,7 @@ static bool ftdi_determine_type(cdch_interface_t * p_cdc, uint8_t const idx) } TU_LOG_P_CDC(" %s detected (bcdDevice = 0x%04x)", - ftdi_chip_name[p_cdc->ftdi.chip_type], desc_dev[idx]->bcdDevice); + ftdi_chip_name[p_cdc->ftdi.chip_type], desc_dev->bcdDevice); return (p_cdc->ftdi.chip_type != UNKNOWN); } @@ -2207,7 +2209,7 @@ static uint8_t ch34x_get_lcr(cdch_interface_t * p_cdc) { //--------------------------------------------------------------------+ #if CFG_TUH_CDC_PL2303 -static int8_t pl2303_detect_type(cdch_interface_t * p_cdc, uint8_t const idx, uint8_t step, +static int8_t pl2303_detect_type(cdch_interface_t * p_cdc, uint8_t step, tuh_xfer_cb_t complete_cb, uintptr_t user_data); static bool pl2303_encode_baud_rate(cdch_interface_t * p_cdc, uint8_t buf[PL2303_LINE_CODING_BAUDRATE_BUFSIZE]); @@ -2465,13 +2467,13 @@ static void pl2303_process_config(tuh_xfer_t * xfer) { case CONFIG_PL2303_GET_DESC: p_cdc->user_control_cb = pl2303_process_config; // set once for whole process config // get device descriptor - TU_ASSERT_COMPLETE(tuh_descriptor_get_device(xfer->daddr, desc_dev[idx], sizeof(tusb_desc_device_t), + TU_ASSERT_COMPLETE(tuh_descriptor_get_device(xfer->daddr, &desc_dev, sizeof(tusb_desc_device_t), pl2303_process_config, CONFIG_PL2303_DETECT_TYPE)); break; case CONFIG_PL2303_DETECT_TYPE: // get type and quirks (step 1) - type = pl2303_detect_type (p_cdc, idx, 1, pl2303_process_config, CONFIG_PL2303_READ1); // step 1 + type = pl2303_detect_type (p_cdc, 1, pl2303_process_config, CONFIG_PL2303_READ1); // step 1 TU_ASSERT_COMPLETE(type!=PL2303_DETECT_TYPE_FAILED); if (type == PL2303_SUPPORTS_HX_STATUS_TRIGGERED) { break; @@ -2482,14 +2484,14 @@ static void pl2303_process_config(tuh_xfer_t * xfer) { // get supports_hx_status, type and quirks (step 2), do special read p_cdc->pl2303.supports_hx_status = ( // will not be true, if coming directly from previous case xfer->user_data == CONFIG_PL2303_READ1 && xfer->result == XFER_RESULT_SUCCESS ); - type = pl2303_detect_type (p_cdc, idx, 2, NULL, 0); // step 2 now with supports_hx_status + type = pl2303_detect_type (p_cdc, 2, NULL, 0); // step 2 now with supports_hx_status TU_ASSERT_COMPLETE(type!=PL2303_DETECT_TYPE_FAILED); p_cdc->pl2303.serial_private.type = &pl2303_type_data[type]; p_cdc->pl2303.serial_private.quirks |= p_cdc->pl2303.serial_private.type->quirks; #if CFG_TUSB_DEBUG >= CFG_TUH_CDC_LOG_LEVEL && 0 // can be activated if necessary TU_LOG_P_CDC(" bDeviceClass = 0x%02x bMaxPacketSize0 = %u bcdUSB = 0x%04x bcdDevice = 0x%04x", - desc_dev[idx]->bDeviceClass, desc_dev[idx]->bMaxPacketSize0, - desc_dev[idx]->bcdUSB, desc_dev[idx]->bcdDevice ); + desc_dev->bDeviceClass, desc_dev->bMaxPacketSize0, + desc_dev->bcdUSB, desc_dev->bcdDevice ); uint16_t vid, pid; TU_ASSERT_COMPLETE(tuh_vid_pid_get(p_cdc->daddr, &vid, &pid)); TU_LOG_P_CDC(" vid = 0x%04x pid = 0x%04x supports_hx_status = %u type = %s quirks = %u", @@ -2674,29 +2676,29 @@ static void pl2303_process_config(tuh_xfer_t * xfer) { //------------- Helper -------------// -static int8_t pl2303_detect_type(cdch_interface_t * p_cdc, uint8_t const idx, uint8_t step, +static int8_t pl2303_detect_type(cdch_interface_t * p_cdc, uint8_t step, tuh_xfer_cb_t complete_cb, uintptr_t user_data ) { /* * Legacy PL2303H, variants 0 and 1 (difference unknown). */ - if (desc_dev[idx]->bDeviceClass == 0x02) { + if (desc_dev->bDeviceClass == 0x02) { return TYPE_H; /* variant 0 */ } - if (desc_dev[idx]->bMaxPacketSize0 != 0x40) { - if (desc_dev[idx]->bDeviceClass == 0x00 || desc_dev[idx]->bDeviceClass == 0xff) { + if (desc_dev->bMaxPacketSize0 != 0x40) { + if (desc_dev->bDeviceClass == 0x00 || desc_dev->bDeviceClass == 0xff) { return TYPE_H; /* variant 1 */ } return TYPE_H; /* variant 0 */ } - switch (desc_dev[idx]->bcdUSB) { + switch (desc_dev->bcdUSB) { case 0x101: /* USB 1.0.1? Let's assume they meant 1.1... */ TU_ATTR_FALLTHROUGH; case 0x110: - switch (desc_dev[idx]->bcdDevice) { + switch (desc_dev->bcdDevice) { case 0x300: return TYPE_HX; case 0x400: @@ -2706,7 +2708,7 @@ static int8_t pl2303_detect_type(cdch_interface_t * p_cdc, uint8_t const idx, ui } break; case 0x200: - switch (desc_dev[idx]->bcdDevice) { + switch (desc_dev->bcdDevice) { case 0x100: /* GC */ case 0x105: return TYPE_HXN; @@ -2751,7 +2753,7 @@ static int8_t pl2303_detect_type(cdch_interface_t * p_cdc, uint8_t const idx, ui default: break; } - TU_LOG_P_CDC(" unknown device type bcdUSB = 0x%04x", desc_dev[idx]->bcdUSB); + TU_LOG_P_CDC(" unknown device type bcdUSB = 0x%04x", desc_dev->bcdUSB); return PL2303_DETECT_TYPE_FAILED; } -- cgit v1.3.1 From edf13203916931962a53af50abc548dd3eded278 Mon Sep 17 00:00:00 2001 From: IngHK Date: Wed, 28 Feb 2024 13:13:18 +0100 Subject: removed expendable ACM check --- src/class/cdc/cdc_host.c | 1 - 1 file changed, 1 deletion(-) (limited to 'src/class') diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index c222e11db..4d2134f9d 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -909,7 +909,6 @@ static bool acm_set_control_line_state(cdch_interface_t * p_cdc, tuh_xfer_cb_t c static bool acm_set_line_coding(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { TU_VERIFY(p_cdc->acm_capability.support_line_request); - TU_VERIFY(p_cdc->requested_line_coding.data_bits && p_cdc->requested_line_coding.bit_rate); TU_VERIFY((p_cdc->requested_line_coding.data_bits >= 5 && p_cdc->requested_line_coding.data_bits <= 8) || p_cdc->requested_line_coding.data_bits == 16); -- cgit v1.3.1 From 3cf9cb98e630a0cb26bc28a2e4c67fb6df19a884 Mon Sep 17 00:00:00 2001 From: IngHK Date: Wed, 28 Feb 2024 13:15:37 +0100 Subject: small PL2303 improvements --- src/class/cdc/cdc_host.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'src/class') diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index 4d2134f9d..130993547 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -2292,9 +2292,10 @@ static bool pl2303_set_line_request(cdch_interface_t * p_cdc, tuh_xfer_cb_t comp * even to the same values as before. Thus we actually need to filter * in this specific case. */ - // TODO really necessary to check? what to do in this case when no transfer will happen? - // callback is not called... - TU_VERIFY(memcmp(&p_cdc->requested_line_coding, &p_cdc->line_coding, sizeof(cdc_line_coding_t) ) != 0); + TU_VERIFY(p_cdc->requested_line_coding.data_bits != p_cdc->line_coding.data_bits || + p_cdc->requested_line_coding.stop_bits != p_cdc->line_coding.stop_bits || + p_cdc->requested_line_coding.parity != p_cdc->line_coding.parity || + p_cdc->requested_line_coding.bit_rate != p_cdc->line_coding.bit_rate ); /* For reference buf[6] data bits value */ TU_VERIFY(p_cdc->requested_line_coding.data_bits >= 5 && p_cdc->requested_line_coding.data_bits <= 8, 0); -- cgit v1.3.1 From e7308e313a1fb5482dbbb34cdfc6b7b11a54fd6b Mon Sep 17 00:00:00 2001 From: IngHK Date: Wed, 28 Feb 2024 13:28:38 +0100 Subject: improved TU_LOGs --- src/class/cdc/cdc.h | 12 +++++++++ src/class/cdc/cdc_host.c | 65 +++++++++++++++++++++++++++++------------------- 2 files changed, 51 insertions(+), 26 deletions(-) (limited to 'src/class') diff --git a/src/class/cdc/cdc.h b/src/class/cdc/cdc.h index 5cbd658fe..b1dca1ad8 100644 --- a/src/class/cdc/cdc.h +++ b/src/class/cdc/cdc.h @@ -192,6 +192,11 @@ typedef enum { CDC_LINE_CODING_STOP_BITS_2 = 2, // 2 bits } cdc_line_coding_stopbits_t; +#define CDC_LINE_CODING_STOP_BITS_TEXT(STOP_BITS) ( \ + STOP_BITS == CDC_LINE_CODING_STOP_BITS_1 ? "1" : \ + STOP_BITS == CDC_LINE_CODING_STOP_BITS_1_5 ? "1.5" : \ + STOP_BITS == CDC_LINE_CODING_STOP_BITS_2 ? "2" : "?" ) + // 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 @@ -205,6 +210,13 @@ typedef enum { CDC_LINE_CODING_PARITY_SPACE = 4, } cdc_line_coding_parity_t; +#define CDC_LINE_CODING_PARITY_CHAR(PARITY) ( \ + PARITY == CDC_LINE_CODING_PARITY_NONE ? 'N' : \ + PARITY == CDC_LINE_CODING_PARITY_ODD ? 'O' : \ + PARITY == CDC_LINE_CODING_PARITY_EVEN ? 'E' : \ + PARITY == CDC_LINE_CODING_PARITY_MARK ? 'M' : \ + PARITY == CDC_LINE_CODING_PARITY_SPACE ? 'S' : '?' ) + //--------------------------------------------------------------------+ // Management Element Notification (Notification Endpoint) //--------------------------------------------------------------------+ diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index 130993547..d2bc63d64 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -50,7 +50,7 @@ DADDR, ITF_NUM, NAME, ##__VA_ARGS__) #define TU_LOG_P_CDC(TXT,...) TU_LOG_CDC(TXT, p_cdc->daddr, p_cdc->bInterfaceNumber, \ serial_drivers[p_cdc->serial_drid].name, ##__VA_ARGS__) -#define TU_LOG_RESULT(TXT,RESULT) TU_LOG_P_CDC(TXT " " #RESULT " = %s", RESULT ? "true" : "FALSE" ) +#define TU_LOG_P_CDC_BOOL(TXT,VAL) TU_LOG_P_CDC(TXT " " #VAL " = %s", VAL ? "true" : "false" ) #define TU_ASSERT_COMPLETE_DEFINE(_cond, _itf_offset) \ do { \ @@ -395,14 +395,20 @@ 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 ret = (p_cdc->line_state & CDC_CONTROL_LINE_STATE_DTR); +// TU_LOG_P_CDC_BOOL("get DTR", ret); + + return ret; } 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 ret = (p_cdc->line_state & CDC_CONTROL_LINE_STATE_RTS); +// TU_LOG_P_CDC_BOOL("get RTS", ret); + + return ret; } bool tuh_cdc_get_local_line_coding(uint8_t idx, cdc_line_coding_t * line_coding) { @@ -410,6 +416,10 @@ 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_P_CDC("get line coding %lu %u%c%s", + p_cdc->line_coding.bit_rate, p_cdc->line_coding.data_bits, + CDC_LINE_CODING_PARITY_CHAR(p_cdc->line_coding.parity), + CDC_LINE_CODING_STOP_BITS_TEXT(line_coding->stop_bits)); return true; } @@ -590,7 +600,7 @@ bool tuh_cdc_set_control_line_state(uint8_t idx, uint16_t line_state, tuh_xfer_c if (ret && !complete_cb) { p_cdc->line_state = (uint8_t) line_state; } - TU_LOG_RESULT("set control line state", ret); +// TU_LOG_P_CDC_BOOL("set control line state", ret); return ret; } @@ -598,7 +608,7 @@ bool tuh_cdc_set_control_line_state(uint8_t idx, uint16_t line_state, tuh_xfer_c bool tuh_cdc_set_baudrate(uint8_t idx, uint32_t baudrate, 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); - TU_LOG_P_CDC("set baudrate = %lu", baudrate); + TU_LOG_P_CDC("set baudrate %lu", baudrate); cdch_serial_driver_t const * driver = &serial_drivers[p_cdc->serial_drid]; p_cdc->requested_line_coding.bit_rate = baudrate; @@ -608,7 +618,7 @@ bool tuh_cdc_set_baudrate(uint8_t idx, uint32_t baudrate, tuh_xfer_cb_t complete if (ret && !complete_cb) { p_cdc->line_coding.bit_rate = baudrate; } - TU_LOG_RESULT("set baudrate", ret); +// TU_LOG_P_CDC_BOOL("set baudrate", ret); return ret; } @@ -617,8 +627,9 @@ bool tuh_cdc_set_data_format(uint8_t idx, uint8_t stop_bits, uint8_t parity, uin 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); - TU_LOG_P_CDC("set data format data_bits = %u parity = %u stop_bits = %u (indexes!)", - data_bits, parity, stop_bits); + TU_LOG_P_CDC("set data format %u%c%s", + data_bits, CDC_LINE_CODING_PARITY_CHAR(parity), + CDC_LINE_CODING_STOP_BITS_TEXT(stop_bits)); cdch_serial_driver_t const * driver = &serial_drivers[p_cdc->serial_drid]; p_cdc->requested_line_coding.stop_bits = stop_bits; @@ -632,7 +643,7 @@ bool tuh_cdc_set_data_format(uint8_t idx, uint8_t stop_bits, uint8_t parity, uin p_cdc->line_coding.parity = parity; p_cdc->line_coding.data_bits = data_bits; } - TU_LOG_RESULT("set data format", ret); +// TU_LOG_P_CDC_BOOL("set data format", ret); return ret; } @@ -641,8 +652,10 @@ 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); - TU_LOG_P_CDC("set line coding baudrate = %lu data_bits = %u parity = %u stop_bits = %u (indexes!)", - line_coding->bit_rate, line_coding->data_bits, line_coding->parity, line_coding->stop_bits); + TU_LOG_P_CDC("set line coding %lu %u%c%s", + line_coding->bit_rate, line_coding->data_bits, + CDC_LINE_CODING_PARITY_CHAR(line_coding->parity), + CDC_LINE_CODING_STOP_BITS_TEXT(line_coding->stop_bits)); cdch_serial_driver_t const * driver = &serial_drivers[p_cdc->serial_drid]; p_cdc->requested_line_coding = *line_coding; @@ -652,7 +665,7 @@ bool tuh_cdc_set_line_coding(uint8_t idx, cdc_line_coding_t const * line_coding, if (ret && !complete_cb) { p_cdc->line_coding = *line_coding; } - TU_LOG_RESULT("set line coding", ret); +// TU_LOG_P_CDC_BOOL("set line coding", ret); return ret; } @@ -792,7 +805,7 @@ bool cdch_open(uint8_t rhport, uint8_t daddr, tusb_desc_interface_t const * itf_ if (driver_detected) { TU_LOG_CDC("open", daddr, itf_desc->bInterfaceNumber, driver_detected->name); bool ret = driver_detected->open(daddr, itf_desc, max_len); - TU_LOG_CDC("opened ret = %s", daddr, itf_desc->bInterfaceNumber, driver_detected->name, ret ? "true" : "FALSE" ); +// TU_LOG_CDC("opened ret = %s", daddr, itf_desc->bInterfaceNumber, driver_detected->name, ret ? "true" : "FALSE" ); return ret; } @@ -802,7 +815,7 @@ bool cdch_open(uint8_t rhport, uint8_t daddr, tusb_desc_interface_t const * itf_ static void set_config_complete(uint8_t idx, uint8_t itf_offset, bool success) { cdch_interface_t * p_cdc = get_itf(idx); TU_ASSERT(p_cdc,); - TU_LOG_RESULT("set config complete", success); + TU_LOG_P_CDC_BOOL("set config complete", success); if (success) { p_cdc->mounted = true; @@ -854,7 +867,7 @@ static void acm_internal_control_complete(tuh_xfer_t * xfer) { cdch_interface_t * p_cdc = get_itf(idx); TU_ASSERT(p_cdc,); bool const success = (xfer->result == XFER_RESULT_SUCCESS); - TU_LOG_RESULT(" control complete", success); + TU_LOG_P_CDC_BOOL("control complete", success); if (success) { switch (xfer->setup->bRequest) { @@ -1138,7 +1151,7 @@ static void ftdi_internal_control_complete(tuh_xfer_t * xfer) { cdch_interface_t * p_cdc = get_itf(idx); TU_ASSERT(p_cdc,); bool const success = (xfer->result == XFER_RESULT_SUCCESS); - TU_LOG_RESULT(" control complete", success); + TU_LOG_P_CDC_BOOL("control complete", success); if (success) { if (xfer->setup->bRequest == FTDI_SIO_SET_MODEM_CTRL_REQUEST && @@ -1414,7 +1427,7 @@ static bool ftdi_determine_type(cdch_interface_t * p_cdc) break; } - TU_LOG_P_CDC(" %s detected (bcdDevice = 0x%04x)", + TU_LOG_P_CDC("%s detected (bcdDevice = 0x%04x)", ftdi_chip_name[p_cdc->ftdi.chip_type], desc_dev->bcdDevice); return (p_cdc->ftdi.chip_type != UNKNOWN); @@ -1562,7 +1575,7 @@ static inline uint32_t ftdi_get_divisor(cdch_interface_t * p_cdc) break; } - TU_LOG_P_CDC(" Baudrate divisor 0x%lu", div_value); + TU_LOG_P_CDC("Baudrate divisor = 0x%lu", div_value); return div_value; } @@ -1671,7 +1684,7 @@ static void cp210x_internal_control_complete(tuh_xfer_t * xfer) { cdch_interface_t * p_cdc = get_itf(idx); TU_ASSERT(p_cdc,); bool const success = (xfer->result == XFER_RESULT_SUCCESS); - TU_LOG_RESULT(" control complete", success); + TU_LOG_P_CDC_BOOL("control complete", success); if (success) { switch(xfer->setup->bRequest) { @@ -1928,7 +1941,7 @@ static void ch34x_internal_control_complete(tuh_xfer_t * xfer) { cdch_interface_t * p_cdc = get_itf(idx); TU_ASSERT(p_cdc,); bool const success = (xfer->result == XFER_RESULT_SUCCESS); - TU_LOG_RESULT(" control complete", success); + TU_LOG_P_CDC_BOOL("control complete", success); if (success) { switch (xfer->setup->bRequest) { @@ -2059,7 +2072,7 @@ 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 const version = xfer->buffer[0]; - TU_LOG_P_CDC(" Chip Version = %02x", version); + TU_LOG_P_CDC("Chip Version = 0x%02x", version); // only versions >= 0x30 are tested, below 0x30 seems having other programming // see drivers from WCH vendor, Linux kernel and FreeBSD TU_ASSERT_COMPLETE(version >= 0x30); @@ -2346,7 +2359,7 @@ static void pl2303_internal_control_complete(tuh_xfer_t * xfer) { cdch_interface_t * p_cdc = get_itf(idx); TU_ASSERT(p_cdc,); bool const success = (xfer->result == XFER_RESULT_SUCCESS); - TU_LOG_RESULT(" control complete", success); + TU_LOG_P_CDC_BOOL("control complete", success); if (success) { if (xfer->setup->bRequest == PL2303_SET_LINE_REQUEST && @@ -2489,12 +2502,12 @@ static void pl2303_process_config(tuh_xfer_t * xfer) { p_cdc->pl2303.serial_private.type = &pl2303_type_data[type]; p_cdc->pl2303.serial_private.quirks |= p_cdc->pl2303.serial_private.type->quirks; #if CFG_TUSB_DEBUG >= CFG_TUH_CDC_LOG_LEVEL && 0 // can be activated if necessary - TU_LOG_P_CDC(" bDeviceClass = 0x%02x bMaxPacketSize0 = %u bcdUSB = 0x%04x bcdDevice = 0x%04x", + TU_LOG_P_CDC("bDeviceClass = 0x%02x bMaxPacketSize0 = %u bcdUSB = 0x%04x bcdDevice = 0x%04x", desc_dev->bDeviceClass, desc_dev->bMaxPacketSize0, desc_dev->bcdUSB, desc_dev->bcdDevice ); uint16_t vid, pid; TU_ASSERT_COMPLETE(tuh_vid_pid_get(p_cdc->daddr, &vid, &pid)); - TU_LOG_P_CDC(" vid = 0x%04x pid = 0x%04x supports_hx_status = %u type = %s quirks = %u", + TU_LOG_P_CDC("vid = 0x%04x pid = 0x%04x supports_hx_status = %u type = %s quirks = %u", vid, pid, p_cdc->pl2303.supports_hx_status, p_cdc->pl2303.serial_private.type->name, p_cdc->pl2303.serial_private.quirks); #endif @@ -2753,7 +2766,7 @@ static int8_t pl2303_detect_type(cdch_interface_t * p_cdc, uint8_t step, default: break; } - TU_LOG_P_CDC(" unknown device type bcdUSB = 0x%04x", desc_dev->bcdUSB); + TU_LOG_P_CDC("unknown device type bcdUSB = 0x%04x", desc_dev->bcdUSB); return PL2303_DETECT_TYPE_FAILED; } @@ -2903,7 +2916,7 @@ static bool pl2303_encode_baud_rate(cdch_interface_t * p_cdc, uint8_t buf[PL2303 } else { baud = pl2303_encode_baud_rate_divisor(buf, baud); } - TU_LOG_P_CDC(" real baudrate = %lu", baud); + TU_LOG_P_CDC("real baudrate %lu", baud); return true; } -- cgit v1.3.1 From e6d27b6d3e8fc928cc00ab08898243c7e037ba35 Mon Sep 17 00:00:00 2001 From: IngHK Date: Thu, 29 Feb 2024 20:19:35 +0100 Subject: fixed IAR compile error --- src/class/cdc/cdc_host.c | 1 - 1 file changed, 1 deletion(-) (limited to 'src/class') diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index d2bc63d64..dfe078de4 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -113,7 +113,6 @@ CFG_TUH_MEM_SECTION static cdch_interface_t cdch_data[CFG_TUH_CDC]; #if CFG_TUH_CDC_FTDI || CFG_TUH_CDC_PL2303 - CFG_TUH_MEM_SECTION CFG_TUH_MEM_ALIGN static tusb_desc_device_t desc_dev[CFG_TUH_ENUMERATION_BUFSIZE]; #endif -- cgit v1.3.1 From dea27d28bceeaaa23d3daa6468373cb536390108 Mon Sep 17 00:00:00 2001 From: IngHK Date: Thu, 29 Feb 2024 20:24:13 +0100 Subject: added explicite (uint16_t) casts inside tu_htole16() --- src/class/cdc/cdc_host.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'src/class') diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index dfe078de4..d71cda124 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -932,8 +932,8 @@ static bool acm_set_line_coding(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete }, .bRequest = CDC_REQUEST_SET_LINE_CODING, .wValue = 0, - .wIndex = tu_htole16(p_cdc->bInterfaceNumber), - .wLength = tu_htole16(sizeof(cdc_line_coding_t)) + .wIndex = tu_htole16((uint16_t) p_cdc->bInterfaceNumber), + .wLength = tu_htole16((uint16_t) sizeof(cdc_line_coding_t)) }; // use usbh enum buf to hold line coding since user line_coding variable does not live long enough @@ -1612,7 +1612,7 @@ static bool cp210x_set_request(cdch_interface_t * p_cdc, uint8_t command, uint16 }, .bRequest = command, .wValue = tu_htole16(value), - .wIndex = tu_htole16(p_cdc->bInterfaceNumber), + .wIndex = tu_htole16((uint16_t) p_cdc->bInterfaceNumber), .wLength = tu_htole16(length) }; @@ -1852,9 +1852,9 @@ static bool ch34x_set_request(cdch_interface_t * p_cdc, uint8_t direction, uint8 .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 @@ -2232,9 +2232,9 @@ static bool pl2303_set_request(cdch_interface_t * p_cdc, uint8_t request, uint8_ tusb_control_request_t const request_setup = { .bmRequestType = requesttype, .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 -- cgit v1.3.1 From e0551043ca8a6b3be92fed57f5e34d6d8014406b Mon Sep 17 00:00:00 2001 From: IngHK Date: Sun, 3 Mar 2024 13:02:58 +0100 Subject: added use of cdc_line_control_state_t type in CDCh --- src/class/cdc/cdc.h | 14 ++++++++------ src/class/cdc/cdc_device.c | 2 ++ src/class/cdc/cdc_host.c | 45 +++++++++++++++++++-------------------------- 3 files changed, 29 insertions(+), 32 deletions(-) (limited to 'src/class') diff --git a/src/class/cdc/cdc.h b/src/class/cdc/cdc.h index b1dca1ad8..10aed79ab 100644 --- a/src/class/cdc/cdc.h +++ b/src/class/cdc/cdc.h @@ -414,15 +414,17 @@ typedef struct TU_ATTR_PACKED TU_VERIFY_STATIC(sizeof(cdc_line_coding_t) == 7, "size is not correct"); -typedef struct TU_ATTR_PACKED +typedef union TU_ATTR_PACKED { - uint16_t dtr : 1; - uint16_t rts : 1; - uint16_t : 6; - uint16_t : 8; + struct { + uint8_t dtr : 1; + uint8_t rts : 1; + uint8_t : 6; + }; + uint8_t all; } cdc_line_control_state_t; -TU_VERIFY_STATIC(sizeof(cdc_line_control_state_t) == 2, "size is not correct"); +TU_VERIFY_STATIC(sizeof(cdc_line_control_state_t) == 1, "size is not correct"); TU_ATTR_PACKED_END // End of all packed definitions TU_ATTR_BIT_FIELD_ORDER_END diff --git a/src/class/cdc/cdc_device.c b/src/class/cdc/cdc_device.c index c26264e60..9f51a6d4b 100644 --- a/src/class/cdc/cdc_device.c +++ b/src/class/cdc/cdc_device.c @@ -56,6 +56,7 @@ typedef struct uint8_t ep_out; // Bit 0: DTR (Data Terminal Ready), Bit 1: RTS (Request to Send) + // TODO use cdc_line_control_state_t instead of uint8_t uint8_t line_state; /*------------- From this point, data is not cleared by bus reset -------------*/ @@ -124,6 +125,7 @@ bool tud_cdc_n_connected(uint8_t itf) } uint8_t tud_cdc_n_get_line_state (uint8_t itf) +// TODO use cdc_line_control_state_t instead of uint8_t { return _cdcd_itf[itf].line_state; } diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index d71cda124..a3407a5f9 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -81,8 +81,8 @@ typedef struct { TU_ATTR_ALIGNED(4) cdc_line_coding_t requested_line_coding; // 1 byte padding - uint8_t line_state; // DTR (bit0), RTS (bit1) - uint8_t requested_line_state; + cdc_line_control_state_t line_state; + cdc_line_control_state_t requested_line_state; tuh_xfer_cb_t user_control_cb; #if CFG_TUH_CDC_FTDI || CFG_TUH_CDC_CP210X || CFG_TUH_CDC_CH34X @@ -339,7 +339,7 @@ static cdch_interface_t * make_new_itf(uint8_t daddr, tusb_desc_interface_t cons p_cdc->bInterfaceSubClass = itf_desc->bInterfaceSubClass; p_cdc->bInterfaceProtocol = itf_desc->bInterfaceProtocol; p_cdc->line_coding = (cdc_line_coding_t) { 0, 0, 0, 0 }; - p_cdc->line_state = 0; + p_cdc->line_state.all = 0; return p_cdc; } } @@ -394,7 +394,7 @@ bool tuh_cdc_get_dtr(uint8_t idx) { cdch_interface_t * p_cdc = get_itf(idx); TU_VERIFY(p_cdc); - bool ret = (p_cdc->line_state & CDC_CONTROL_LINE_STATE_DTR); + bool ret = p_cdc->line_state.dtr; // TU_LOG_P_CDC_BOOL("get DTR", ret); return ret; @@ -404,7 +404,7 @@ bool tuh_cdc_get_rts(uint8_t idx) { cdch_interface_t * p_cdc = get_itf(idx); TU_VERIFY(p_cdc); - bool ret = (p_cdc->line_state & CDC_CONTROL_LINE_STATE_RTS); + bool ret = p_cdc->line_state.rts; // TU_LOG_P_CDC_BOOL("get RTS", ret); return ret; @@ -592,12 +592,12 @@ bool tuh_cdc_set_control_line_state(uint8_t idx, uint16_t line_state, tuh_xfer_c TU_LOG_P_CDC("set control line state line_state = %u", line_state); cdch_serial_driver_t const * driver = &serial_drivers[p_cdc->serial_drid]; - p_cdc->requested_line_state = (uint8_t) line_state; + p_cdc->requested_line_state.all = (uint8_t) line_state; bool ret = set_function_call(p_cdc, driver->set_control_line_state, complete_cb, user_data); if (ret && !complete_cb) { - p_cdc->line_state = (uint8_t) line_state; + p_cdc->line_state.all = (uint8_t) line_state; } // TU_LOG_P_CDC_BOOL("set control line state", ret); @@ -898,7 +898,7 @@ static bool acm_set_control_line_state(cdch_interface_t * p_cdc, tuh_xfer_cb_t c .direction = TUSB_DIR_OUT }, .bRequest = CDC_REQUEST_SET_CONTROL_LINE_STATE, - .wValue = tu_htole16(p_cdc->requested_line_state), + .wValue = tu_htole16((uint16_t) p_cdc->requested_line_state.all), .wIndex = tu_htole16((uint16_t) p_cdc->bInterfaceNumber), .wLength = 0 }; @@ -1034,7 +1034,7 @@ static void acm_process_config(tuh_xfer_t * xfer) { case CONFIG_ACM_SET_CONTROL_LINE_STATE: #ifdef CFG_TUH_CDC_LINE_CONTROL_ON_ENUM if (p_cdc->acm_capability.support_line_request) { - p_cdc->requested_line_state = CFG_TUH_CDC_LINE_CONTROL_ON_ENUM; + p_cdc->requested_line_state.all = CFG_TUH_CDC_LINE_CONTROL_ON_ENUM; TU_ASSERT_COMPLETE(acm_set_control_line_state(p_cdc, acm_process_config, CONFIG_ACM_SET_LINE_CODING), 1); break; } @@ -1139,7 +1139,7 @@ static bool ftdi_set_data_request(cdch_interface_t * p_cdc, tuh_xfer_cb_t comple static inline bool ftdi_update_mctrl(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { // FTDI has the same bit coding return ftdi_set_request(p_cdc, FTDI_SIO_SET_MODEM_CTRL_REQUEST, FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE, - p_cdc->requested_line_state, p_cdc->ftdi.channel, complete_cb, user_data); + p_cdc->requested_line_state.all, p_cdc->ftdi.channel, complete_cb, user_data); } //------------- Driver API -------------// @@ -1328,7 +1328,7 @@ static void ftdi_process_config(tuh_xfer_t * xfer) { case CONFIG_FTDI_MODEM_CTRL: #ifdef CFG_TUH_CDC_LINE_CONTROL_ON_ENUM - p_cdc->requested_line_state = CFG_TUH_CDC_LINE_CONTROL_ON_ENUM; + p_cdc->requested_line_state.all = CFG_TUH_CDC_LINE_CONTROL_ON_ENUM; TU_ASSERT_COMPLETE(ftdi_update_mctrl(p_cdc, ftdi_internal_control_complete, CONFIG_FTDI_COMPLETE)); break; #else @@ -1670,7 +1670,7 @@ static inline bool cp210x_set_mhs(cdch_interface_t * p_cdc, tuh_xfer_cb_t comple // CP210x has the same bit coding return cp210x_set_request(p_cdc, CP210X_SET_MHS, (uint16_t) ((uint32_t) CP210X_CONTROL_WRITE_DTR | - (uint32_t) CP210X_CONTROL_WRITE_RTS | p_cdc->requested_line_state), + (uint32_t) CP210X_CONTROL_WRITE_RTS | p_cdc->requested_line_state.all), NULL, 0, complete_cb, user_data); } @@ -1811,7 +1811,7 @@ static void cp210x_process_config(tuh_xfer_t * xfer) { case CONFIG_CP210X_SET_DTR_RTS: #ifdef CFG_TUH_CDC_LINE_CONTROL_ON_ENUM - p_cdc->requested_line_state = CFG_TUH_CDC_LINE_CONTROL_ON_ENUM; + p_cdc->requested_line_state.all = CFG_TUH_CDC_LINE_CONTROL_ON_ENUM; TU_ASSERT_COMPLETE(cp210x_set_mhs(p_cdc, cp210x_internal_control_complete, CONFIG_CP210X_COMPLETE)); break; @@ -1916,16 +1916,8 @@ static bool ch34x_write_reg_baudrate(cdch_interface_t * p_cdc, tuh_xfer_cb_t com } static bool ch34x_modem_ctrl_request(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - uint8_t control = 0; - if (p_cdc->requested_line_state & CDC_CONTROL_LINE_STATE_RTS) { - control |= CH34X_BIT_RTS; - } - if (p_cdc->requested_line_state & CDC_CONTROL_LINE_STATE_DTR) { - control |= CH34X_BIT_DTR; - } - - // CH34x signals are inverted - control = ~control; + uint8_t control = ~((p_cdc->requested_line_state.rts ? CH34X_BIT_RTS : 0) | // CH34x signals are inverted + (p_cdc->requested_line_state.dtr ? CH34X_BIT_DTR : 0)); return ch34x_control_out(p_cdc, CH34X_REQ_MODEM_CTRL, control, 0, complete_cb, user_data); } @@ -2101,7 +2093,7 @@ static void ch34x_process_config(tuh_xfer_t* xfer) { case CONFIG_CH34X_MODEM_CONTROL: #ifdef CFG_TUH_CDC_LINE_CONTROL_ON_ENUM - p_cdc->requested_line_state = CFG_TUH_CDC_LINE_CONTROL_ON_ENUM; + p_cdc->requested_line_state.all = CFG_TUH_CDC_LINE_CONTROL_ON_ENUM; TU_ASSERT_COMPLETE(ch34x_modem_ctrl_request(p_cdc, ch34x_internal_control_complete, CONFIG_CH34X_COMPLETE)); break; @@ -2287,8 +2279,9 @@ static inline bool pl2303_supports_hx_status(cdch_interface_t * p_cdc, tuh_xfer_ static inline bool pl2303_set_control_lines(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + // PL2303 has the same bit coding return pl2303_set_request(p_cdc, PL2303_SET_CONTROL_REQUEST, PL2303_SET_CONTROL_REQUEST_TYPE, - p_cdc->requested_line_state, 0, NULL, 0, complete_cb, user_data); + p_cdc->requested_line_state.all, 0, NULL, 0, complete_cb, user_data); } //static bool pl2303_get_line_request(cdch_interface_t * p_cdc, uint8_t buf[PL2303_LINE_CODING_BUFSIZE]) @@ -2645,7 +2638,7 @@ static void pl2303_process_config(tuh_xfer_t * xfer) { case CONFIG_PL2303_MODEM_CONTROL: #ifdef CFG_TUH_CDC_LINE_CONTROL_ON_ENUM - p_cdc->requested_line_state = CFG_TUH_CDC_LINE_CONTROL_ON_ENUM; + p_cdc->requested_line_state.all = CFG_TUH_CDC_LINE_CONTROL_ON_ENUM; TU_ASSERT_COMPLETE(pl2303_set_control_lines(p_cdc, pl2303_internal_control_complete, CONFIG_PL2303_FLOW_CTRL_READ)); break; #else -- cgit v1.3.1 From a9cc07fc83599fab4d9576e6f5b793bc1bf2bf35 Mon Sep 17 00:00:00 2001 From: IngHK Date: Sun, 10 Mar 2024 08:20:12 +0100 Subject: added line control function using cdc_line_control_state_t --- src/class/cdc/cdc_host.c | 35 ++++++++++++++++++++++++++++++----- src/class/cdc/cdc_host.h | 10 ++++++++-- 2 files changed, 38 insertions(+), 7 deletions(-) (limited to 'src/class') diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index a3407a5f9..86b874b1e 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -50,8 +50,9 @@ DADDR, ITF_NUM, NAME, ##__VA_ARGS__) #define TU_LOG_P_CDC(TXT,...) TU_LOG_CDC(TXT, p_cdc->daddr, p_cdc->bInterfaceNumber, \ serial_drivers[p_cdc->serial_drid].name, ##__VA_ARGS__) -#define TU_LOG_P_CDC_BOOL(TXT,VAL) TU_LOG_P_CDC(TXT " " #VAL " = %s", VAL ? "true" : "false" ) +#define TU_LOG_P_CDC_BOOL(TXT,VAL) TU_LOG_P_CDC(TXT " " #VAL " = %d", VAL) +// assert and set config complete #define TU_ASSERT_COMPLETE_DEFINE(_cond, _itf_offset) \ do { \ if (!(_cond)) { _MESS_FAILED(); TU_BREAKPOINT(); set_config_complete(idx, _itf_offset, false); } \ @@ -586,24 +587,48 @@ static bool set_function_call ( } } -bool tuh_cdc_set_control_line_state(uint8_t idx, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { +bool tuh_cdc_set_control_line_state_u(uint8_t idx, cdc_line_control_state_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + // uses cdc_line_control_state_t union for line_state cdch_interface_t * p_cdc = get_itf(idx); TU_VERIFY(p_cdc && p_cdc->serial_drid < SERIAL_DRIVER_COUNT); - TU_LOG_P_CDC("set control line state line_state = %u", line_state); + TU_LOG_P_CDC("set control line state dtr = %u rts = %u", line_state.dtr, line_state.rts ); cdch_serial_driver_t const * driver = &serial_drivers[p_cdc->serial_drid]; - p_cdc->requested_line_state.all = (uint8_t) line_state; + p_cdc->requested_line_state = line_state; bool ret = set_function_call(p_cdc, driver->set_control_line_state, complete_cb, user_data); if (ret && !complete_cb) { - p_cdc->line_state.all = (uint8_t) line_state; + p_cdc->line_state = line_state; } // TU_LOG_P_CDC_BOOL("set control line state", ret); return ret; } +bool tuh_cdc_set_control_line_state(uint8_t idx, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + // uses uint16_t for line_state => DTR (bit 0), RTS (bit 1) + + return tuh_cdc_set_control_line_state_u(idx, (cdc_line_control_state_t) { .all = (uint8_t) line_state }, + complete_cb, user_data); +} + +bool tuh_cdc_set_dtr(uint8_t idx, bool dtr_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); + cdc_line_control_state_t const line_state = { .dtr = dtr_state, .rts = p_cdc->line_state.rts }; + + return tuh_cdc_set_control_line_state_u(idx, line_state, complete_cb, user_data); +} + +bool tuh_cdc_set_rts(uint8_t idx, bool rts_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); + cdc_line_control_state_t const line_state = { .rts = rts_state, .dtr = p_cdc->line_state.dtr }; + + return tuh_cdc_set_control_line_state_u(idx, line_state, complete_cb, user_data); +} + bool tuh_cdc_set_baudrate(uint8_t idx, uint32_t baudrate, 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); diff --git a/src/class/cdc/cdc_host.h b/src/class/cdc/cdc_host.h index ca6567453..77081d3b0 100644 --- a/src/class/cdc/cdc_host.h +++ b/src/class/cdc/cdc_host.h @@ -132,8 +132,14 @@ 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) -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 Control Line State +bool tuh_cdc_set_control_line_state_u(uint8_t idx, cdc_line_control_state_t line_state, // uses cdc_line_control_state_t union for line_state + tuh_xfer_cb_t complete_cb, uintptr_t user_data); +bool tuh_cdc_set_control_line_state(uint8_t idx, uint16_t line_state, // uses uint16_t for line_state (legacy function) + tuh_xfer_cb_t complete_cb, uintptr_t user_data); // DTR (bit 0), RTS (bit 1) + +bool tuh_cdc_set_dtr(uint8_t idx, bool dtr_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data); // Request to Set DTR +bool tuh_cdc_set_rts(uint8_t idx, bool rts_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data); // Request to Set RTS // 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); -- cgit v1.3.1 From ee92e582b38e36df53381f8c98a0be54c2caef3e Mon Sep 17 00:00:00 2001 From: IngHK Date: Sun, 3 Mar 2024 13:12:10 +0100 Subject: added defines CFG_TUH_CDC_DTR_CONTROL_ON_ENUM & CFG_TUH_CDC_RTS_CONTROL_ON_ENUM --- examples/host/cdc_msc_hid/src/tusb_config.h | 4 +-- .../host/cdc_msc_hid_freertos/src/tusb_config.h | 4 +-- src/class/cdc/cdc_host.c | 40 ++++++++++++++++------ 3 files changed, 34 insertions(+), 14 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 fc956c6d3..32a29bd4f 100644 --- a/examples/host/cdc_msc_hid/src/tusb_config.h +++ b/examples/host/cdc_msc_hid/src/tusb_config.h @@ -121,8 +121,8 @@ //------------- 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_DTR_CONTROL_ON_ENUM true +#define CFG_TUH_CDC_RTS_CONTROL_ON_ENUM true // 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 dd732c700..88b341e95 100644 --- a/examples/host/cdc_msc_hid_freertos/src/tusb_config.h +++ b/examples/host/cdc_msc_hid_freertos/src/tusb_config.h @@ -126,8 +126,8 @@ //------------- 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_DTR_CONTROL_ON_ENUM true +#define CFG_TUH_CDC_RTS_CONTROL_ON_ENUM true // 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_host.c b/src/class/cdc/cdc_host.c index 86b874b1e..5b74d031d 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -63,6 +63,26 @@ #define TU_ASSERT_COMPLETE(...) _GET_3RD_ARG(__VA_ARGS__, TU_ASSERT_COMPLETE_2ARGS, TU_ASSERT_COMPLETE_1ARGS, _dummy)(__VA_ARGS__) +// handle line control defines +#if defined(CFG_TUH_CDC_LINE_CONTROL_ON_ENUM) && \ + (defined(CFG_TUH_CDC_DTR_CONTROL_ON_ENUM) || defined(CFG_TUH_CDC_RTS_CONTROL_ON_ENUM)) + TU_VERIFY_STATIC(false, "Contradictory line control defines"); +#endif + +#ifdef CFG_TUH_CDC_LINE_CONTROL_ON_ENUM + #define LINE_CONTROL_ON_ENUM CFG_TUH_CDC_LINE_CONTROL_ON_ENUM +#elif defined(CFG_TUH_CDC_DTR_CONTROL_ON_ENUM) || defined(CFG_TUH_CDC_RTS_CONTROL_ON_ENUM) + #ifndef CFG_TUH_CDC_DTR_CONTROL_ON_ENUM + #define CFG_TUH_CDC_DTR_CONTROL_ON_ENUM 0 + #endif + #ifndef CFG_TUH_CDC_RTS_CONTROL_ON_ENUM + #define CFG_TUH_CDC_RTS_CONTROL_ON_ENUM 0 + #endif + #define LINE_CONTROL_ON_ENUM ( ( CFG_TUH_CDC_DTR_CONTROL_ON_ENUM ? CDC_CONTROL_LINE_STATE_DTR : 0 ) | \ + ( CFG_TUH_CDC_RTS_CONTROL_ON_ENUM ? CDC_CONTROL_LINE_STATE_RTS : 0 ) ) +#endif + + //--------------------------------------------------------------------+ // Host CDC Interface //--------------------------------------------------------------------+ @@ -1057,9 +1077,9 @@ static void acm_process_config(tuh_xfer_t * xfer) { switch (state) { case CONFIG_ACM_SET_CONTROL_LINE_STATE: - #ifdef CFG_TUH_CDC_LINE_CONTROL_ON_ENUM + #ifdef LINE_CONTROL_ON_ENUM if (p_cdc->acm_capability.support_line_request) { - p_cdc->requested_line_state.all = CFG_TUH_CDC_LINE_CONTROL_ON_ENUM; + p_cdc->requested_line_state.all = LINE_CONTROL_ON_ENUM; TU_ASSERT_COMPLETE(acm_set_control_line_state(p_cdc, acm_process_config, CONFIG_ACM_SET_LINE_CODING), 1); break; } @@ -1352,8 +1372,8 @@ static void ftdi_process_config(tuh_xfer_t * xfer) { break; case CONFIG_FTDI_MODEM_CTRL: - #ifdef CFG_TUH_CDC_LINE_CONTROL_ON_ENUM - p_cdc->requested_line_state.all = CFG_TUH_CDC_LINE_CONTROL_ON_ENUM; + #ifdef LINE_CONTROL_ON_ENUM + p_cdc->requested_line_state.all = LINE_CONTROL_ON_ENUM; TU_ASSERT_COMPLETE(ftdi_update_mctrl(p_cdc, ftdi_internal_control_complete, CONFIG_FTDI_COMPLETE)); break; #else @@ -1835,8 +1855,8 @@ static void cp210x_process_config(tuh_xfer_t * xfer) { #endif case CONFIG_CP210X_SET_DTR_RTS: - #ifdef CFG_TUH_CDC_LINE_CONTROL_ON_ENUM - p_cdc->requested_line_state.all = CFG_TUH_CDC_LINE_CONTROL_ON_ENUM; + #ifdef LINE_CONTROL_ON_ENUM + p_cdc->requested_line_state.all = LINE_CONTROL_ON_ENUM; TU_ASSERT_COMPLETE(cp210x_set_mhs(p_cdc, cp210x_internal_control_complete, CONFIG_CP210X_COMPLETE)); break; @@ -2117,8 +2137,8 @@ static void ch34x_process_config(tuh_xfer_t* xfer) { break; case CONFIG_CH34X_MODEM_CONTROL: - #ifdef CFG_TUH_CDC_LINE_CONTROL_ON_ENUM - p_cdc->requested_line_state.all = CFG_TUH_CDC_LINE_CONTROL_ON_ENUM; + #ifdef LINE_CONTROL_ON_ENUM + p_cdc->requested_line_state.all = LINE_CONTROL_ON_ENUM; TU_ASSERT_COMPLETE(ch34x_modem_ctrl_request(p_cdc, ch34x_internal_control_complete, CONFIG_CH34X_COMPLETE)); break; @@ -2662,8 +2682,8 @@ static void pl2303_process_config(tuh_xfer_t * xfer) { #endif case CONFIG_PL2303_MODEM_CONTROL: - #ifdef CFG_TUH_CDC_LINE_CONTROL_ON_ENUM - p_cdc->requested_line_state.all = CFG_TUH_CDC_LINE_CONTROL_ON_ENUM; + #ifdef LINE_CONTROL_ON_ENUM + p_cdc->requested_line_state.all = LINE_CONTROL_ON_ENUM; TU_ASSERT_COMPLETE(pl2303_set_control_lines(p_cdc, pl2303_internal_control_complete, CONFIG_PL2303_FLOW_CTRL_READ)); break; #else -- cgit v1.3.1 From 2786a61e8b9811b1065cf1f36502eb4744e9d772 Mon Sep 17 00:00:00 2001 From: IngHK Date: Sun, 3 Mar 2024 13:25:04 +0100 Subject: fixed FTDI set control line --- src/class/cdc/cdc_host.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) (limited to 'src/class') diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index 5b74d031d..6121e59f0 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -82,7 +82,6 @@ ( CFG_TUH_CDC_RTS_CONTROL_ON_ENUM ? CDC_CONTROL_LINE_STATE_RTS : 0 ) ) #endif - //--------------------------------------------------------------------+ // Host CDC Interface //--------------------------------------------------------------------+ @@ -1172,19 +1171,21 @@ static bool ftdi_change_speed(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_c static bool ftdi_set_data_request(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { TU_VERIFY(p_cdc->requested_line_coding.data_bits >= 7 && p_cdc->requested_line_coding.data_bits <= 8, 0); uint16_t value = (uint16_t) ( - ((uint32_t) p_cdc->requested_line_coding.data_bits & 0xf) | // data bit quantity is stored in bits 0-3 - ((uint32_t) p_cdc->requested_line_coding.parity & 0x7) << 8 | // parity is stored in bits 8-10, same coding - ((uint32_t) p_cdc->requested_line_coding.stop_bits & 0x3) << 11 ); // stop bits quantity is stored in bits 11-12, same coding - // not each FTDI supports 1.5 stop bits + ((uint32_t) p_cdc->requested_line_coding.data_bits & 0xfu) | // data bit quantity is stored in bits 0-3 + ((uint32_t) p_cdc->requested_line_coding.parity & 0x7u) << 8 | // parity is stored in bits 8-10, same coding + ((uint32_t) p_cdc->requested_line_coding.stop_bits & 0x3u) << 11 ); // stop bits quantity is stored in bits 11-12, same coding + // not each FTDI supports 1.5 stop bits return ftdi_set_request(p_cdc, FTDI_SIO_SET_DATA_REQUEST, FTDI_SIO_SET_DATA_REQUEST_TYPE, value, p_cdc->ftdi.channel, complete_cb, user_data); } static inline bool ftdi_update_mctrl(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - // FTDI has the same bit coding + uint16_t value = (uint16_t) ((p_cdc->requested_line_state.dtr ? (uint32_t) FTDI_SIO_SET_DTR_HIGH : (uint32_t) FTDI_SIO_SET_DTR_LOW) | + (p_cdc->requested_line_state.rts ? (uint32_t) FTDI_SIO_SET_RTS_HIGH : (uint32_t) FTDI_SIO_SET_RTS_LOW)); + return ftdi_set_request(p_cdc, FTDI_SIO_SET_MODEM_CTRL_REQUEST, FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE, - p_cdc->requested_line_state.all, p_cdc->ftdi.channel, complete_cb, user_data); + value, p_cdc->ftdi.channel, complete_cb, user_data); } //------------- Driver API -------------// @@ -1704,9 +1705,9 @@ static bool cp210x_set_baudrate_request(cdch_interface_t * p_cdc, tuh_xfer_cb_t static bool cp210x_set_line_ctl(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { TU_VERIFY(p_cdc->requested_line_coding.data_bits >= 5 && p_cdc->requested_line_coding.data_bits <= 9, 0); uint16_t lcr = (uint16_t) ( - ((uint32_t) p_cdc->requested_line_coding.data_bits & 0xf) << 8 | // data bit quantity is stored in bits 8-11 - ((uint32_t) p_cdc->requested_line_coding.parity & 0xf) << 4 | // parity is stored in bits 4-7, same coding - ((uint32_t) p_cdc->requested_line_coding.stop_bits & 0xf)); // parity is stored in bits 0-3, same coding + ((uint32_t) p_cdc->requested_line_coding.data_bits & 0xfu) << 8 | // data bit quantity is stored in bits 8-11 + ((uint32_t) p_cdc->requested_line_coding.parity & 0xfu) << 4 | // parity is stored in bits 4-7, same coding + ((uint32_t) p_cdc->requested_line_coding.stop_bits & 0xfu)); // parity is stored in bits 0-3, same coding return cp210x_set_request(p_cdc, CP210X_SET_LINE_CTL, lcr, NULL, 0, complete_cb, user_data); } -- cgit v1.3.1 From cb69ed0d0423b8e09ae77307fcc01165ae4c9386 Mon Sep 17 00:00:00 2001 From: IngHK Date: Thu, 21 Mar 2024 08:29:28 +0100 Subject: code style and clean up CDC serial header files --- src/class/cdc/serial/ch34x.h | 70 ++++++++-------- src/class/cdc/serial/cp210x.h | 86 ++++++++++---------- src/class/cdc/serial/ftdi_sio.h | 172 ++++++++++++++++++++-------------------- src/class/cdc/serial/pl2303.h | 146 +++++++++++++++++----------------- 4 files changed, 237 insertions(+), 237 deletions(-) (limited to 'src/class') diff --git a/src/class/cdc/serial/ch34x.h b/src/class/cdc/serial/ch34x.h index c18066f57..7d91f01fe 100644 --- a/src/class/cdc/serial/ch34x.h +++ b/src/class/cdc/serial/ch34x.h @@ -24,8 +24,8 @@ * This file is part of the TinyUSB stack. */ -#ifndef _CH34X_H_ -#define _CH34X_H_ +#ifndef TUSB_CH34X_H +#define TUSB_CH34X_H // There is no official documentation for the CH34x (CH340, CH341) chips. Reference can be found // - https://github.com/WCHSoftGroup/ch341ser_linux @@ -40,45 +40,45 @@ #endif // USB requests -#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 +#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 // registers -#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 +#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 -#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 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) -#define CH32X_REG16_LCR2_LCR TU_U16(CH34X_REG_LCR2, CH34X_REG_LCR) +#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 ) -#define CH34X_BIT_DTR ( 1 << 5 ) +#define CH34X_BIT_RTS (1 << 6) +#define CH34X_BIT_DTR (1 << 5) // line control bits -#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_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 +#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_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_ */ +#endif // TUSB_CH34X_H diff --git a/src/class/cdc/serial/cp210x.h b/src/class/cdc/serial/cp210x.h index e18da7d51..a553a54da 100644 --- a/src/class/cdc/serial/cp210x.h +++ b/src/class/cdc/serial/cp210x.h @@ -31,7 +31,7 @@ // parts are overtaken from vendors driver // https://www.silabs.com/documents/public/software/cp210x-3.1.0.tar.gz -/* Config request codes */ +// Config request codes #define CP210X_IFC_ENABLE 0x00 #define CP210X_SET_BAUDDIV 0x01 #define CP210X_GET_BAUDDIV 0x02 @@ -60,56 +60,56 @@ #define CP210X_SET_BAUDRATE 0x1E #define CP210X_VENDOR_SPECIFIC 0xFF // GPIO, Recipient must be Device -/* SILABSER_IFC_ENABLE_REQUEST_CODE */ -#define CP210X_UART_ENABLE 0x0001 -#define CP210X_UART_DISABLE 0x0000 +// SILABSER_IFC_ENABLE_REQUEST_CODE +#define CP210X_UART_ENABLE 0x0001 +#define CP210X_UART_DISABLE 0x0000 -/* SILABSER_SET_BAUDDIV_REQUEST_CODE */ -#define CP210X_BAUD_RATE_GEN_FREQ 0x384000 +// SILABSER_SET_BAUDDIV_REQUEST_CODE +#define CP210X_BAUD_RATE_GEN_FREQ 0x384000 -/*SILABSER_SET_LINE_CTL_REQUEST_CODE */ -#define CP210X_BITS_DATA_MASK 0x0f00 -#define CP210X_BITS_DATA_5 0x0500 -#define CP210X_BITS_DATA_6 0x0600 -#define CP210X_BITS_DATA_7 0x0700 -#define CP210X_BITS_DATA_8 0x0800 -#define CP210X_BITS_DATA_9 0x0900 +// SILABSER_SET_LINE_CTL_REQUEST_CODE +#define CP210X_BITS_DATA_MASK 0x0f00 +#define CP210X_BITS_DATA_5 0x0500 +#define CP210X_BITS_DATA_6 0x0600 +#define CP210X_BITS_DATA_7 0x0700 +#define CP210X_BITS_DATA_8 0x0800 +#define CP210X_BITS_DATA_9 0x0900 -#define CP210X_BITS_PARITY_MASK 0x00f0 -#define CP210X_BITS_PARITY_NONE 0x0000 -#define CP210X_BITS_PARITY_ODD 0x0010 -#define CP210X_BITS_PARITY_EVEN 0x0020 -#define CP210X_BITS_PARITY_MARK 0x0030 -#define CP210X_BITS_PARITY_SPACE 0x0040 +#define CP210X_BITS_PARITY_MASK 0x00f0 +#define CP210X_BITS_PARITY_NONE 0x0000 +#define CP210X_BITS_PARITY_ODD 0x0010 +#define CP210X_BITS_PARITY_EVEN 0x0020 +#define CP210X_BITS_PARITY_MARK 0x0030 +#define CP210X_BITS_PARITY_SPACE 0x0040 -#define CP210X_BITS_STOP_MASK 0x000f -#define CP210X_BITS_STOP_1 0x0000 -#define CP210X_BITS_STOP_1_5 0x0001 -#define CP210X_BITS_STOP_2 0x0002 +#define CP210X_BITS_STOP_MASK 0x000f +#define CP210X_BITS_STOP_1 0x0000 +#define CP210X_BITS_STOP_1_5 0x0001 +#define CP210X_BITS_STOP_2 0x0002 -/* SILABSER_SET_BREAK_REQUEST_CODE */ -#define CP210X_BREAK_ON 0x0001 -#define CP210X_BREAK_OFF 0x0000 +// SILABSER_SET_BREAK_REQUEST_CODE +#define CP210X_BREAK_ON 0x0001 +#define CP210X_BREAK_OFF 0x0000 -/* SILABSER_SET_MHS_REQUEST_CODE */ -#define CP210X_MCR_DTR 0x0001 -#define CP210X_MCR_RTS 0x0002 -#define CP210X_MCR_ALL 0x0003 -#define CP210X_MSR_CTS 0x0010 -#define CP210X_MSR_DSR 0x0020 -#define CP210X_MSR_RING 0x0040 -#define CP210X_MSR_DCD 0x0080 -#define CP210X_MSR_ALL 0x00F0 +// SILABSER_SET_MHS_REQUEST_CODE +#define CP210X_MCR_DTR 0x0001 +#define CP210X_MCR_RTS 0x0002 +#define CP210X_MCR_ALL 0x0003 +#define CP210X_MSR_CTS 0x0010 +#define CP210X_MSR_DSR 0x0020 +#define CP210X_MSR_RING 0x0040 +#define CP210X_MSR_DCD 0x0080 +#define CP210X_MSR_ALL 0x00F0 -#define CP210X_CONTROL_WRITE_DTR 0x0100 -#define CP210X_CONTROL_WRITE_RTS 0x0200 +#define CP210X_CONTROL_WRITE_DTR 0x0100 +#define CP210X_CONTROL_WRITE_RTS 0x0200 -#define CP210X_LSR_BREAK 0x0001 -#define CP210X_LSR_FRAMING_ERROR 0x0002 -#define CP210X_LSR_HW_OVERRUN 0x0004 -#define CP210X_LSR_QUEUE_OVERRUN 0x0008 -#define CP210X_LSR_PARITY_ERROR 0x0010 -#define CP210X_LSR_ALL 0x001F +#define CP210X_LSR_BREAK 0x0001 +#define CP210X_LSR_FRAMING_ERROR 0x0002 +#define CP210X_LSR_HW_OVERRUN 0x0004 +#define CP210X_LSR_QUEUE_OVERRUN 0x0008 +#define CP210X_LSR_PARITY_ERROR 0x0010 +#define CP210X_LSR_ALL 0x001F // supported baudrates // reference: datasheets and AN205 "CP210x Baud Rate Support" diff --git a/src/class/cdc/serial/ftdi_sio.h b/src/class/cdc/serial/ftdi_sio.h index 42716f73e..4afedec9b 100644 --- a/src/class/cdc/serial/ftdi_sio.h +++ b/src/class/cdc/serial/ftdi_sio.h @@ -28,43 +28,43 @@ #include // Commands -#define FTDI_SIO_RESET 0 // Reset the port -#define FTDI_SIO_MODEM_CTRL 1 // Set the modem control register -#define FTDI_SIO_SET_FLOW_CTRL 2 // Set flow control register -#define FTDI_SIO_SET_BAUD_RATE 3 // Set baud rate -#define FTDI_SIO_SET_DATA 4 // Set the data characteristics of the port -#define FTDI_SIO_GET_MODEM_STATUS 5 // Retrieve current value of modem status register -#define FTDI_SIO_SET_EVENT_CHAR 6 // Set the event character -#define FTDI_SIO_SET_ERROR_CHAR 7 // Set the error character -#define FTDI_SIO_SET_LATENCY_TIMER 9 // Set the latency timer -#define FTDI_SIO_GET_LATENCY_TIMER 10 // Get the latency timer -#define FTDI_SIO_SET_BITMODE 11 // Set bitbang mode -#define FTDI_SIO_READ_PINS 12 // Read immediate value of pins -#define FTDI_SIO_READ_EEPROM 0x90 // Read EEPROM +#define FTDI_SIO_RESET 0 // Reset the port +#define FTDI_SIO_MODEM_CTRL 1 // Set the modem control register +#define FTDI_SIO_SET_FLOW_CTRL 2 // Set flow control register +#define FTDI_SIO_SET_BAUD_RATE 3 // Set baud rate +#define FTDI_SIO_SET_DATA 4 // Set the data characteristics of the port +#define FTDI_SIO_GET_MODEM_STATUS 5 // Retrieve current value of modem status register +#define FTDI_SIO_SET_EVENT_CHAR 6 // Set the event character +#define FTDI_SIO_SET_ERROR_CHAR 7 // Set the error character +#define FTDI_SIO_SET_LATENCY_TIMER 9 // Set the latency timer +#define FTDI_SIO_GET_LATENCY_TIMER 10 // Get the latency timer +#define FTDI_SIO_SET_BITMODE 11 // Set bitbang mode +#define FTDI_SIO_READ_PINS 12 // Read immediate value of pins +#define FTDI_SIO_READ_EEPROM 0x90 // Read EEPROM // Channel indices for FT2232, FT2232H and FT4232H devices -#define CHANNEL_A 1 -#define CHANNEL_B 2 -#define CHANNEL_C 3 -#define CHANNEL_D 4 +#define CHANNEL_A 1 +#define CHANNEL_B 2 +#define CHANNEL_C 3 +#define CHANNEL_D 4 // Port Identifier Table -#define PIT_DEFAULT 0 // SIOA -#define PIT_SIOA 1 // SIOA +#define PIT_DEFAULT 0 // SIOA +#define PIT_SIOA 1 // SIOA // The device this driver is tested with one has only one port -#define PIT_SIOB 2 // SIOB -#define PIT_PARALLEL 3 // Parallel +#define PIT_SIOB 2 // SIOB +#define PIT_PARALLEL 3 // Parallel // FTDI_SIO_RESET -#define FTDI_SIO_RESET_REQUEST FTDI_SIO_RESET -#define FTDI_SIO_RESET_REQUEST_TYPE 0x40 -#define FTDI_SIO_RESET_SIO 0 -#define FTDI_SIO_RESET_PURGE_RX 1 -#define FTDI_SIO_RESET_PURGE_TX 2 +#define FTDI_SIO_RESET_REQUEST FTDI_SIO_RESET +#define FTDI_SIO_RESET_REQUEST_TYPE 0x40 +#define FTDI_SIO_RESET_SIO 0 +#define FTDI_SIO_RESET_PURGE_RX 1 +#define FTDI_SIO_RESET_PURGE_TX 2 // FTDI_SIO_SET_BAUDRATE -#define FTDI_SIO_SET_BAUDRATE_REQUEST_TYPE 0x40 -#define FTDI_SIO_SET_BAUDRATE_REQUEST 3 +#define FTDI_SIO_SET_BAUDRATE_REQUEST_TYPE 0x40 +#define FTDI_SIO_SET_BAUDRATE_REQUEST 3 enum ftdi_sio_baudrate { ftdi_sio_b300 = 0, @@ -80,89 +80,89 @@ enum ftdi_sio_baudrate { }; // FTDI_SIO_SET_DATA -#define FTDI_SIO_SET_DATA_REQUEST FTDI_SIO_SET_DATA -#define FTDI_SIO_SET_DATA_REQUEST_TYPE 0x40 -#define FTDI_SIO_SET_DATA_PARITY_NONE (0x0 << 8) -#define FTDI_SIO_SET_DATA_PARITY_ODD (0x1 << 8) -#define FTDI_SIO_SET_DATA_PARITY_EVEN (0x2 << 8) -#define FTDI_SIO_SET_DATA_PARITY_MARK (0x3 << 8) -#define FTDI_SIO_SET_DATA_PARITY_SPACE (0x4 << 8) -#define FTDI_SIO_SET_DATA_STOP_BITS_1 (0x0 << 11) -#define FTDI_SIO_SET_DATA_STOP_BITS_15 (0x1 << 11) -#define FTDI_SIO_SET_DATA_STOP_BITS_2 (0x2 << 11) -#define FTDI_SIO_SET_BREAK (0x1 << 14) +#define FTDI_SIO_SET_DATA_REQUEST FTDI_SIO_SET_DATA +#define FTDI_SIO_SET_DATA_REQUEST_TYPE 0x40 +#define FTDI_SIO_SET_DATA_PARITY_NONE (0x0 << 8) +#define FTDI_SIO_SET_DATA_PARITY_ODD (0x1 << 8) +#define FTDI_SIO_SET_DATA_PARITY_EVEN (0x2 << 8) +#define FTDI_SIO_SET_DATA_PARITY_MARK (0x3 << 8) +#define FTDI_SIO_SET_DATA_PARITY_SPACE (0x4 << 8) +#define FTDI_SIO_SET_DATA_STOP_BITS_1 (0x0 << 11) // same coding as ACM +#define FTDI_SIO_SET_DATA_STOP_BITS_15 (0x1 << 11) // 1.5 not supported, for future use? +#define FTDI_SIO_SET_DATA_STOP_BITS_2 (0x2 << 11) +#define FTDI_SIO_SET_BREAK (0x1 << 14) // FTDI_SIO_MODEM_CTRL -#define FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE 0x40 -#define FTDI_SIO_SET_MODEM_CTRL_REQUEST FTDI_SIO_MODEM_CTRL +#define FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE 0x40 +#define FTDI_SIO_SET_MODEM_CTRL_REQUEST FTDI_SIO_MODEM_CTRL -#define FTDI_SIO_SET_DTR_MASK 0x1 -#define FTDI_SIO_SET_DTR_HIGH ((FTDI_SIO_SET_DTR_MASK << 8) | 1) -#define FTDI_SIO_SET_DTR_LOW ((FTDI_SIO_SET_DTR_MASK << 8) | 0) -#define FTDI_SIO_SET_RTS_MASK 0x2 -#define FTDI_SIO_SET_RTS_HIGH ((FTDI_SIO_SET_RTS_MASK << 8) | 2) -#define FTDI_SIO_SET_RTS_LOW ((FTDI_SIO_SET_RTS_MASK << 8) | 0) +#define FTDI_SIO_SET_DTR_MASK 0x1 +#define FTDI_SIO_SET_DTR_HIGH ((FTDI_SIO_SET_DTR_MASK << 8) | 1) +#define FTDI_SIO_SET_DTR_LOW ((FTDI_SIO_SET_DTR_MASK << 8) | 0) +#define FTDI_SIO_SET_RTS_MASK 0x2 +#define FTDI_SIO_SET_RTS_HIGH ((FTDI_SIO_SET_RTS_MASK << 8) | 2) +#define FTDI_SIO_SET_RTS_LOW ((FTDI_SIO_SET_RTS_MASK << 8) | 0) // FTDI_SIO_SET_FLOW_CTRL -#define FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE 0x40 -#define FTDI_SIO_SET_FLOW_CTRL_REQUEST FTDI_SIO_SET_FLOW_CTRL +#define FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE 0x40 +#define FTDI_SIO_SET_FLOW_CTRL_REQUEST FTDI_SIO_SET_FLOW_CTRL #define FTDI_SIO_DISABLE_FLOW_CTRL 0x0 -#define FTDI_SIO_RTS_CTS_HS (0x1 << 8) -#define FTDI_SIO_DTR_DSR_HS (0x2 << 8) -#define FTDI_SIO_XON_XOFF_HS (0x4 << 8) +#define FTDI_SIO_RTS_CTS_HS (0x1 << 8) +#define FTDI_SIO_DTR_DSR_HS (0x2 << 8) +#define FTDI_SIO_XON_XOFF_HS (0x4 << 8) // FTDI_SIO_GET_LATENCY_TIMER -#define FTDI_SIO_GET_LATENCY_TIMER_REQUEST FTDI_SIO_GET_LATENCY_TIMER -#define FTDI_SIO_GET_LATENCY_TIMER_REQUEST_TYPE 0xC0 +#define FTDI_SIO_GET_LATENCY_TIMER_REQUEST FTDI_SIO_GET_LATENCY_TIMER +#define FTDI_SIO_GET_LATENCY_TIMER_REQUEST_TYPE 0xC0 // FTDI_SIO_SET_LATENCY_TIMER -#define FTDI_SIO_SET_LATENCY_TIMER_REQUEST FTDI_SIO_SET_LATENCY_TIMER -#define FTDI_SIO_SET_LATENCY_TIMER_REQUEST_TYPE 0x40 +#define FTDI_SIO_SET_LATENCY_TIMER_REQUEST FTDI_SIO_SET_LATENCY_TIMER +#define FTDI_SIO_SET_LATENCY_TIMER_REQUEST_TYPE 0x40 // FTDI_SIO_SET_EVENT_CHAR -#define FTDI_SIO_SET_EVENT_CHAR_REQUEST FTDI_SIO_SET_EVENT_CHAR -#define FTDI_SIO_SET_EVENT_CHAR_REQUEST_TYPE 0x40 +#define FTDI_SIO_SET_EVENT_CHAR_REQUEST FTDI_SIO_SET_EVENT_CHAR +#define FTDI_SIO_SET_EVENT_CHAR_REQUEST_TYPE 0x40 // FTDI_SIO_GET_MODEM_STATUS -#define FTDI_SIO_GET_MODEM_STATUS_REQUEST_TYPE 0xc0 -#define FTDI_SIO_GET_MODEM_STATUS_REQUEST FTDI_SIO_GET_MODEM_STATUS -#define FTDI_SIO_CTS_MASK 0x10 -#define FTDI_SIO_DSR_MASK 0x20 -#define FTDI_SIO_RI_MASK 0x40 -#define FTDI_SIO_RLSD_MASK 0x80 +#define FTDI_SIO_GET_MODEM_STATUS_REQUEST_TYPE 0xc0 +#define FTDI_SIO_GET_MODEM_STATUS_REQUEST FTDI_SIO_GET_MODEM_STATUS +#define FTDI_SIO_CTS_MASK 0x10 +#define FTDI_SIO_DSR_MASK 0x20 +#define FTDI_SIO_RI_MASK 0x40 +#define FTDI_SIO_RLSD_MASK 0x80 // FTDI_SIO_SET_BITMODE -#define FTDI_SIO_SET_BITMODE_REQUEST_TYPE 0x40 -#define FTDI_SIO_SET_BITMODE_REQUEST FTDI_SIO_SET_BITMODE +#define FTDI_SIO_SET_BITMODE_REQUEST_TYPE 0x40 +#define FTDI_SIO_SET_BITMODE_REQUEST FTDI_SIO_SET_BITMODE // Possible bitmodes for FTDI_SIO_SET_BITMODE_REQUEST -#define FTDI_SIO_BITMODE_RESET 0x00 -#define FTDI_SIO_BITMODE_CBUS 0x20 +#define FTDI_SIO_BITMODE_RESET 0x00 +#define FTDI_SIO_BITMODE_CBUS 0x20 // FTDI_SIO_READ_PINS -#define FTDI_SIO_READ_PINS_REQUEST_TYPE 0xc0 -#define FTDI_SIO_READ_PINS_REQUEST FTDI_SIO_READ_PINS +#define FTDI_SIO_READ_PINS_REQUEST_TYPE 0xc0 +#define FTDI_SIO_READ_PINS_REQUEST FTDI_SIO_READ_PINS // FTDI_SIO_READ_EEPROM -#define FTDI_SIO_READ_EEPROM_REQUEST_TYPE 0xc0 -#define FTDI_SIO_READ_EEPROM_REQUEST FTDI_SIO_READ_EEPROM +#define FTDI_SIO_READ_EEPROM_REQUEST_TYPE 0xc0 +#define FTDI_SIO_READ_EEPROM_REQUEST FTDI_SIO_READ_EEPROM #define FTDI_FTX_CBUS_MUX_GPIO 0x8 #define FTDI_FT232R_CBUS_MUX_GPIO 0xa #define FTDI_RS0_CTS (1 << 4) #define FTDI_RS0_DSR (1 << 5) -#define FTDI_RS0_RI (1 << 6) +#define FTDI_RS0_RI (1 << 6) #define FTDI_RS0_RLSD (1 << 7) -#define FTDI_RS_DR 1 -#define FTDI_RS_OE (1<<1) -#define FTDI_RS_PE (1<<2) -#define FTDI_RS_FE (1<<3) -#define FTDI_RS_BI (1<<4) -#define FTDI_RS_THRE (1<<5) -#define FTDI_RS_TEMT (1<<6) -#define FTDI_RS_FIFO (1<<7) +#define FTDI_RS_DR 1 +#define FTDI_RS_OE (1 << 1) +#define FTDI_RS_PE (1 << 2) +#define FTDI_RS_FE (1 << 3) +#define FTDI_RS_BI (1 << 4) +#define FTDI_RS_THRE (1 << 5) +#define FTDI_RS_TEMT (1 << 6) +#define FTDI_RS_FIFO (1 << 7) // chip types and names enum ftdi_chip_type { @@ -206,14 +206,14 @@ enum ftdi_chip_type { // private interface data typedef struct ftdi_private { - enum ftdi_chip_type chip_type; - uint8_t channel; // channel index, or 0 for legacy types + enum ftdi_chip_type chip_type; + uint8_t channel; // channel index, or 0 for legacy types } ftdi_private_t; -#define FTDI_OK true -#define FTDI_FAIL false +#define FTDI_OK true +#define FTDI_FAIL false #define FTDI_NOT_POSSIBLE -1 -#define FTDI_REQUESTED -2 +#define FTDI_REQUESTED -2 // division and round function overtaken from math.h #define DIV_ROUND_CLOSEST(x, divisor)( \ diff --git a/src/class/cdc/serial/pl2303.h b/src/class/cdc/serial/pl2303.h index bf264191b..d69bdbfae 100644 --- a/src/class/cdc/serial/pl2303.h +++ b/src/class/cdc/serial/pl2303.h @@ -24,8 +24,8 @@ * This file is part of the TinyUSB stack. */ -#ifndef _PL2303_H_ -#define _PL2303_H_ +#ifndef TUSB_PL2303_H +#define TUSB_PL2303_H #include #include @@ -36,66 +36,66 @@ // https://github.com/torvalds/linux/blob/master/drivers/usb/serial/pl2303.c // - https://github.com/freebsd/freebsd-src/blob/main/sys/dev/usb/serial/uplcom.c -/* quirks */ -#define PL2303_QUIRK_UART_STATE_IDX0 1 -#define PL2303_QUIRK_LEGACY 2 -#define PL2303_QUIRK_ENDPOINT_HACK 4 - -/* requests and bits */ -#define PL2303_SET_LINE_REQUEST_TYPE 0x21 // class request host to device interface -#define PL2303_SET_LINE_REQUEST 0x20 // dec 32 - -#define PL2303_SET_CONTROL_REQUEST_TYPE 0x21 // class request host to device interface -#define PL2303_SET_CONTROL_REQUEST 0x22 // dec 34 -#define PL2303_CONTROL_DTR 0x01 // dec 1 -#define PL2303_CONTROL_RTS 0x02 // dec 2 - -#define PL2303_BREAK_REQUEST_TYPE 0x21 // class request host to device interface -#define PL2303_BREAK_REQUEST 0x23 // dec 35 -#define PL2303_BREAK_ON 0xffff -#define PL2303_BREAK_OFF 0x0000 - -#define PL2303_GET_LINE_REQUEST_TYPE 0xa1 // class request device to host interface -#define PL2303_GET_LINE_REQUEST 0x21 // dec 33 - -#define PL2303_VENDOR_WRITE_REQUEST_TYPE 0x40 // vendor request host to device interface -#define PL2303_VENDOR_WRITE_REQUEST 0x01 // dec 1 -#define PL2303_VENDOR_WRITE_NREQUEST 0x80 // dec 128 - -#define PL2303_VENDOR_READ_REQUEST_TYPE 0xc0 // vendor request device to host interface -#define PL2303_VENDOR_READ_REQUEST 0x01 // dec 1 -#define PL2303_VENDOR_READ_NREQUEST 0x81 // dec 129 - -#define PL2303_UART_STATE_INDEX 8 -#define PL2303_UART_STATE_MSR_MASK 0x8b -#define PL2303_UART_STATE_TRANSIENT_MASK 0x74 -#define PL2303_UART_DCD 0x01 -#define PL2303_UART_DSR 0x02 -#define PL2303_UART_BREAK_ERROR 0x04 -#define PL2303_UART_RING 0x08 -#define PL2303_UART_FRAME_ERROR 0x10 -#define PL2303_UART_PARITY_ERROR 0x20 -#define PL2303_UART_OVERRUN_ERROR 0x40 -#define PL2303_UART_CTS 0x80 - -#define PL2303_FLOWCTRL_MASK 0xf0 - -#define PL2303_CLEAR_HALT_REQUEST_TYPE 0x02 // standard request host to device endpoint - -/* registers via vendor read/write requests */ -#define PL2303_READ_TYPE_HX_STATUS 0x8080 - -#define PL2303_HXN_RESET_REG 0x07 -#define PL2303_HXN_RESET_UPSTREAM_PIPE 0x02 -#define PL2303_HXN_RESET_DOWNSTREAM_PIPE 0x01 - -#define PL2303_HXN_FLOWCTRL_REG 0x0a -#define PL2303_HXN_FLOWCTRL_MASK 0x1c -#define PL2303_HXN_FLOWCTRL_NONE 0x1c -#define PL2303_HXN_FLOWCTRL_RTS_CTS 0x18 -#define PL2303_HXN_FLOWCTRL_XON_XOFF 0x0c - -/* type data */ +// quirks +#define PL2303_QUIRK_UART_STATE_IDX0 1 +#define PL2303_QUIRK_LEGACY 2 +#define PL2303_QUIRK_ENDPOINT_HACK 4 + +// requests and bits +#define PL2303_SET_LINE_REQUEST_TYPE 0x21 // class request host to device interface +#define PL2303_SET_LINE_REQUEST 0x20 // dec 32 + +#define PL2303_SET_CONTROL_REQUEST_TYPE 0x21 // class request host to device interface +#define PL2303_SET_CONTROL_REQUEST 0x22 // dec 34 +#define PL2303_CONTROL_DTR 0x01 // dec 1 +#define PL2303_CONTROL_RTS 0x02 // dec 2 + +#define PL2303_BREAK_REQUEST_TYPE 0x21 // class request host to device interface +#define PL2303_BREAK_REQUEST 0x23 // dec 35 +#define PL2303_BREAK_ON 0xffff +#define PL2303_BREAK_OFF 0x0000 + +#define PL2303_GET_LINE_REQUEST_TYPE 0xa1 // class request device to host interface +#define PL2303_GET_LINE_REQUEST 0x21 // dec 33 + +#define PL2303_VENDOR_WRITE_REQUEST_TYPE 0x40 // vendor request host to device interface +#define PL2303_VENDOR_WRITE_REQUEST 0x01 // dec 1 +#define PL2303_VENDOR_WRITE_NREQUEST 0x80 // dec 128 + +#define PL2303_VENDOR_READ_REQUEST_TYPE 0xc0 // vendor request device to host interface +#define PL2303_VENDOR_READ_REQUEST 0x01 // dec 1 +#define PL2303_VENDOR_READ_NREQUEST 0x81 // dec 129 + +#define PL2303_UART_STATE_INDEX 8 +#define PL2303_UART_STATE_MSR_MASK 0x8b +#define PL2303_UART_STATE_TRANSIENT_MASK 0x74 +#define PL2303_UART_DCD 0x01 +#define PL2303_UART_DSR 0x02 +#define PL2303_UART_BREAK_ERROR 0x04 +#define PL2303_UART_RING 0x08 +#define PL2303_UART_FRAME_ERROR 0x10 +#define PL2303_UART_PARITY_ERROR 0x20 +#define PL2303_UART_OVERRUN_ERROR 0x40 +#define PL2303_UART_CTS 0x80 + +#define PL2303_FLOWCTRL_MASK 0xf0 + +#define PL2303_CLEAR_HALT_REQUEST_TYPE 0x02 // standard request host to device endpoint + +// registers via vendor read/write requests +#define PL2303_READ_TYPE_HX_STATUS 0x8080 + +#define PL2303_HXN_RESET_REG 0x07 +#define PL2303_HXN_RESET_UPSTREAM_PIPE 0x02 +#define PL2303_HXN_RESET_DOWNSTREAM_PIPE 0x01 + +#define PL2303_HXN_FLOWCTRL_REG 0x0a +#define PL2303_HXN_FLOWCTRL_MASK 0x1c +#define PL2303_HXN_FLOWCTRL_NONE 0x1c +#define PL2303_HXN_FLOWCTRL_RTS_CTS 0x18 +#define PL2303_HXN_FLOWCTRL_XON_XOFF 0x0c + +// type data enum pl2303_type { TYPE_H, TYPE_HX, @@ -107,9 +107,9 @@ enum pl2303_type { }; struct pl2303_type_data { - uint8_t const *name; + uint8_t const *name; uint32_t const max_baud_rate; - uint8_t const quirks; + uint8_t const quirks; uint16_t const no_autoxonxoff:1; uint16_t const no_divisors:1; uint16_t const alt_divisors:1; @@ -146,7 +146,7 @@ struct pl2303_type_data { .no_divisors = true, \ } -/* private data types */ +// private data types struct pl2303_serial_private { const struct pl2303_type_data* type; uint8_t quirks; @@ -157,16 +157,16 @@ typedef struct TU_ATTR_PACKED { bool supports_hx_status; } pl2303_private_t; -/* buffer sizes for line coding data */ -#define PL2303_LINE_CODING_BUFSIZE 7 +// buffer sizes for line coding data +#define PL2303_LINE_CODING_BUFSIZE 7 #define PL2303_LINE_CODING_BAUDRATE_BUFSIZE 4 -/* bulk endpoints */ -#define PL2303_OUT_EP 0x02 -#define PL2303_IN_EP 0x83 +// bulk endpoints +#define PL2303_OUT_EP 0x02 +#define PL2303_IN_EP 0x83 -/* return values of pl2303_detect_type() */ +// return values of pl2303_detect_type() #define PL2303_SUPPORTS_HX_STATUS_TRIGGERED -1 -#define PL2303_DETECT_TYPE_FAILED -2 +#define PL2303_DETECT_TYPE_FAILED -2 -#endif /* _PL2303_H_ */ +#endif // TUSB_PL2303_H -- cgit v1.3.1 From 5e67b92b8c398d6fee92010ecd63cf50b51f8f9a Mon Sep 17 00:00:00 2001 From: IngHK Date: Thu, 4 Apr 2024 14:10:31 +0200 Subject: fixed compile warnings --- src/class/cdc/cdc_host.c | 29 ++++++++++++++++------------- src/class/cdc/serial/cp210x.h | 4 ++-- src/class/cdc/serial/ftdi_sio.h | 14 +++++++------- 3 files changed, 25 insertions(+), 22 deletions(-) (limited to 'src/class') diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index e6579ad82..2d900a753 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -1181,9 +1181,9 @@ static bool ftdi_change_speed(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_c static bool ftdi_set_data_request(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { TU_VERIFY(p_cdc->requested_line_coding.data_bits >= 7 && p_cdc->requested_line_coding.data_bits <= 8, 0); uint16_t value = (uint16_t) ( - ((uint32_t) p_cdc->requested_line_coding.data_bits & 0xfu) | // data bit quantity is stored in bits 0-3 - ((uint32_t) p_cdc->requested_line_coding.parity & 0x7u) << 8 | // parity is stored in bits 8-10, same coding - ((uint32_t) p_cdc->requested_line_coding.stop_bits & 0x3u) << 11 ); // stop bits quantity is stored in bits 11-12, same coding + (p_cdc->requested_line_coding.data_bits & 0xfUL) | // data bit quantity is stored in bits 0-3 + (p_cdc->requested_line_coding.parity & 0x7UL) << 8 | // parity is stored in bits 8-10, same coding + (p_cdc->requested_line_coding.stop_bits & 0x3UL) << 11 ); // stop bits quantity is stored in bits 11-12, same coding // not each FTDI supports 1.5 stop bits return ftdi_set_request(p_cdc, FTDI_SIO_SET_DATA_REQUEST, FTDI_SIO_SET_DATA_REQUEST_TYPE, @@ -1191,8 +1191,8 @@ static bool ftdi_set_data_request(cdch_interface_t * p_cdc, tuh_xfer_cb_t comple } static inline bool ftdi_update_mctrl(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - uint16_t value = (uint16_t) ((p_cdc->requested_line_state.dtr ? (uint32_t) FTDI_SIO_SET_DTR_HIGH : (uint32_t) FTDI_SIO_SET_DTR_LOW) | - (p_cdc->requested_line_state.rts ? (uint32_t) FTDI_SIO_SET_RTS_HIGH : (uint32_t) FTDI_SIO_SET_RTS_LOW)); + uint16_t value = (uint16_t) ((p_cdc->requested_line_state.dtr ? FTDI_SIO_SET_DTR_HIGH : FTDI_SIO_SET_DTR_LOW) | + (p_cdc->requested_line_state.rts ? FTDI_SIO_SET_RTS_HIGH : FTDI_SIO_SET_RTS_LOW)); return ftdi_set_request(p_cdc, FTDI_SIO_SET_MODEM_CTRL_REQUEST, FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE, value, p_cdc->ftdi.channel, complete_cb, user_data); @@ -1338,7 +1338,10 @@ static void ftdi_process_config(tuh_xfer_t * xfer) { // other interfaces have same type as interface 0 uint8_t const idx_itf0 = tuh_cdc_itf_get_index(xfer->daddr, 0); cdch_interface_t const * p_cdc_itf0 = get_itf(idx_itf0); - p_cdc->ftdi.chip_type = p_cdc_itf0->ftdi.chip_type; + TU_ASSERT_COMPLETE(p_cdc_itf0); + if (p_cdc_itf0) { + p_cdc->ftdi.chip_type = p_cdc_itf0->ftdi.chip_type; + } } TU_ATTR_FALLTHROUGH; @@ -1715,9 +1718,9 @@ static bool cp210x_set_baudrate_request(cdch_interface_t * p_cdc, tuh_xfer_cb_t static bool cp210x_set_line_ctl(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { TU_VERIFY(p_cdc->requested_line_coding.data_bits >= 5 && p_cdc->requested_line_coding.data_bits <= 9, 0); uint16_t lcr = (uint16_t) ( - ((uint32_t) p_cdc->requested_line_coding.data_bits & 0xfu) << 8 | // data bit quantity is stored in bits 8-11 - ((uint32_t) p_cdc->requested_line_coding.parity & 0xfu) << 4 | // parity is stored in bits 4-7, same coding - ((uint32_t) p_cdc->requested_line_coding.stop_bits & 0xfu)); // parity is stored in bits 0-3, same coding + (p_cdc->requested_line_coding.data_bits & 0xfUL) << 8 | // data bit quantity is stored in bits 8-11 + (p_cdc->requested_line_coding.parity & 0xfUL) << 4 | // parity is stored in bits 4-7, same coding + (p_cdc->requested_line_coding.stop_bits & 0xfUL)); // parity is stored in bits 0-3, same coding return cp210x_set_request(p_cdc, CP210X_SET_LINE_CTL, lcr, NULL, 0, complete_cb, user_data); } @@ -1725,8 +1728,8 @@ static bool cp210x_set_line_ctl(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete static inline bool cp210x_set_mhs(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { // CP210x has the same bit coding return cp210x_set_request(p_cdc, CP210X_SET_MHS, - (uint16_t) ((uint32_t) CP210X_CONTROL_WRITE_DTR | - (uint32_t) CP210X_CONTROL_WRITE_RTS | p_cdc->requested_line_state.all), + (uint16_t) (CP210X_CONTROL_WRITE_DTR | CP210X_CONTROL_WRITE_RTS | + p_cdc->requested_line_state.all), NULL, 0, complete_cb, user_data); } @@ -2327,7 +2330,7 @@ static bool pl2303_vendor_write(cdch_interface_t * p_cdc, uint16_t value, uint16 static inline bool pl2303_supports_hx_status(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - uint8_t buf; + uint8_t buf = 0; return pl2303_set_request(p_cdc, PL2303_VENDOR_READ_REQUEST, PL2303_VENDOR_READ_REQUEST_TYPE, PL2303_READ_TYPE_HX_STATUS, 0, &buf, 1, complete_cb, user_data); @@ -2519,7 +2522,7 @@ static void pl2303_process_config(tuh_xfer_t * xfer) { cdch_interface_t * p_cdc = get_itf(idx); // state CONFIG_PL2303_READ1 may have no success due to expected stall by pl2303_supports_hx_status() TU_ASSERT_COMPLETE(p_cdc && (xfer->result == XFER_RESULT_SUCCESS || xfer->user_data == CONFIG_PL2303_READ1)); - uint8_t buf; + uint8_t buf = 0; int8_t type; switch (state) { diff --git a/src/class/cdc/serial/cp210x.h b/src/class/cdc/serial/cp210x.h index a553a54da..ac9c27330 100644 --- a/src/class/cdc/serial/cp210x.h +++ b/src/class/cdc/serial/cp210x.h @@ -101,8 +101,8 @@ #define CP210X_MSR_DCD 0x0080 #define CP210X_MSR_ALL 0x00F0 -#define CP210X_CONTROL_WRITE_DTR 0x0100 -#define CP210X_CONTROL_WRITE_RTS 0x0200 +#define CP210X_CONTROL_WRITE_DTR 0x0100UL +#define CP210X_CONTROL_WRITE_RTS 0x0200UL #define CP210X_LSR_BREAK 0x0001 #define CP210X_LSR_FRAMING_ERROR 0x0002 diff --git a/src/class/cdc/serial/ftdi_sio.h b/src/class/cdc/serial/ftdi_sio.h index 4afedec9b..f621b3912 100644 --- a/src/class/cdc/serial/ftdi_sio.h +++ b/src/class/cdc/serial/ftdi_sio.h @@ -96,17 +96,17 @@ enum ftdi_sio_baudrate { #define FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE 0x40 #define FTDI_SIO_SET_MODEM_CTRL_REQUEST FTDI_SIO_MODEM_CTRL -#define FTDI_SIO_SET_DTR_MASK 0x1 -#define FTDI_SIO_SET_DTR_HIGH ((FTDI_SIO_SET_DTR_MASK << 8) | 1) -#define FTDI_SIO_SET_DTR_LOW ((FTDI_SIO_SET_DTR_MASK << 8) | 0) -#define FTDI_SIO_SET_RTS_MASK 0x2 -#define FTDI_SIO_SET_RTS_HIGH ((FTDI_SIO_SET_RTS_MASK << 8) | 2) -#define FTDI_SIO_SET_RTS_LOW ((FTDI_SIO_SET_RTS_MASK << 8) | 0) +#define FTDI_SIO_SET_DTR_MASK 0x1UL +#define FTDI_SIO_SET_DTR_HIGH ((FTDI_SIO_SET_DTR_MASK << 8) | 1UL) +#define FTDI_SIO_SET_DTR_LOW ((FTDI_SIO_SET_DTR_MASK << 8) | 0UL) +#define FTDI_SIO_SET_RTS_MASK 0x2UL +#define FTDI_SIO_SET_RTS_HIGH ((FTDI_SIO_SET_RTS_MASK << 8) | 2UL) +#define FTDI_SIO_SET_RTS_LOW ((FTDI_SIO_SET_RTS_MASK << 8) | 0UL) // FTDI_SIO_SET_FLOW_CTRL #define FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE 0x40 #define FTDI_SIO_SET_FLOW_CTRL_REQUEST FTDI_SIO_SET_FLOW_CTRL -#define FTDI_SIO_DISABLE_FLOW_CTRL 0x0 +#define FTDI_SIO_DISABLE_FLOW_CTRL 0x0 #define FTDI_SIO_RTS_CTS_HS (0x1 << 8) #define FTDI_SIO_DTR_DSR_HS (0x2 << 8) #define FTDI_SIO_XON_XOFF_HS (0x4 << 8) -- cgit v1.3.1 From e07ee4a7b1f7c7d18f385d605dd41e08962ddba4 Mon Sep 17 00:00:00 2001 From: IngHK Date: Thu, 4 Apr 2024 14:12:14 +0200 Subject: CP210x removed baudrate check, fixed data bits check --- src/class/cdc/cdc_host.c | 12 ++---------- src/class/cdc/serial/cp210x.h | 9 --------- 2 files changed, 2 insertions(+), 19 deletions(-) (limited to 'src/class') diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index 2d900a753..73d800469 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -1701,22 +1701,14 @@ static inline bool cp210x_ifc_enable(cdch_interface_t * p_cdc, uint16_t enabled, } static bool cp210x_set_baudrate_request(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - // Check baudrate is supported. It's only a specific list. reference: datasheets and AN205 "CP210x Baud Rate Support" - uint32_t const supported_baudrates_list[] = CP210X_SUPPORTED_BAUDRATES_LIST; - uint8_t i; - for ( i=0; supported_baudrates_list[i]; i++ ){ - if (p_cdc->requested_line_coding.bit_rate == supported_baudrates_list[i]) { - break; - } - } - TU_VERIFY(supported_baudrates_list[i]); + // Not every baud rate is supported. See datasheets and AN205 "CP210x Baud Rate Support" uint32_t baud_le = tu_htole32(p_cdc->requested_line_coding.bit_rate); return cp210x_set_request(p_cdc, CP210X_SET_BAUDRATE, 0, (uint8_t *) &baud_le, 4, complete_cb, user_data); } static bool cp210x_set_line_ctl(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - TU_VERIFY(p_cdc->requested_line_coding.data_bits >= 5 && p_cdc->requested_line_coding.data_bits <= 9, 0); + TU_VERIFY(p_cdc->requested_line_coding.data_bits >= 5 && p_cdc->requested_line_coding.data_bits <= 8, 0); uint16_t lcr = (uint16_t) ( (p_cdc->requested_line_coding.data_bits & 0xfUL) << 8 | // data bit quantity is stored in bits 8-11 (p_cdc->requested_line_coding.parity & 0xfUL) << 4 | // parity is stored in bits 4-7, same coding diff --git a/src/class/cdc/serial/cp210x.h b/src/class/cdc/serial/cp210x.h index ac9c27330..a0eff9e40 100644 --- a/src/class/cdc/serial/cp210x.h +++ b/src/class/cdc/serial/cp210x.h @@ -111,13 +111,4 @@ #define CP210X_LSR_PARITY_ERROR 0x0010 #define CP210X_LSR_ALL 0x001F -// supported baudrates -// reference: datasheets and AN205 "CP210x Baud Rate Support" -#define CP210X_SUPPORTED_BAUDRATES_LIST { \ - 300, 600, \ - 1200, 1800, 2400, 4000, 4800, 7200, 9600, \ - 14400, 16000, 19200, 28800, 38400, 51200, 56000, 57600, 64000, 76800, \ - 115200, 128000, 153600, 230400, 250000, 256000, 460800, 500000, 576000, 921600, \ - 0 } - #endif //TUSB_CP210X_H -- cgit v1.3.1 From a1b1c1f552d944da1bf309ce002b7c07f5a270a0 Mon Sep 17 00:00:00 2001 From: IngHK Date: Thu, 4 Apr 2024 14:13:24 +0200 Subject: foxed FTDI flow control config --- src/class/cdc/cdc_host.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/class') diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index 73d800469..6006730b7 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -1382,7 +1382,8 @@ static void ftdi_process_config(tuh_xfer_t * xfer) { case CONFIG_FTDI_FLOW_CONTROL: // disable flow control TU_ASSERT_COMPLETE(ftdi_set_request(p_cdc, FTDI_SIO_SET_FLOW_CTRL_REQUEST, FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE, - 0, FTDI_SIO_DISABLE_FLOW_CTRL, ftdi_process_config, CONFIG_FTDI_MODEM_CTRL)); + FTDI_SIO_DISABLE_FLOW_CTRL, p_cdc->ftdi.channel, + ftdi_process_config, CONFIG_FTDI_MODEM_CTRL)); break; case CONFIG_FTDI_MODEM_CTRL: -- cgit v1.3.1 From e02a309f1dc09377fe5123c21ecfe36eb6a032c7 Mon Sep 17 00:00:00 2001 From: IngHK Date: Thu, 4 Apr 2024 14:14:41 +0200 Subject: disable PL2303 flow control config --- src/class/cdc/cdc_host.c | 55 +++++++++++++++++++++++++----------------------- 1 file changed, 29 insertions(+), 26 deletions(-) (limited to 'src/class') diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index 6006730b7..b9915f583 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -2475,8 +2475,8 @@ enum { CONFIG_PL2303_RESET_ENDP2, CONFIG_PL2303_LINE_CODING, CONFIG_PL2303_MODEM_CONTROL, - CONFIG_PL2303_FLOW_CTRL_READ, - CONFIG_PL2303_FLOW_CTRL_WRITE, +// CONFIG_PL2303_FLOW_CTRL_READ, +// CONFIG_PL2303_FLOW_CTRL_WRITE, CONFIG_PL2303_COMPLETE }; @@ -2691,35 +2691,38 @@ static void pl2303_process_config(tuh_xfer_t * xfer) { case CONFIG_PL2303_MODEM_CONTROL: #ifdef LINE_CONTROL_ON_ENUM p_cdc->requested_line_state.all = LINE_CONTROL_ON_ENUM; - TU_ASSERT_COMPLETE(pl2303_set_control_lines(p_cdc, pl2303_internal_control_complete, CONFIG_PL2303_FLOW_CTRL_READ)); + TU_ASSERT_COMPLETE(pl2303_set_control_lines(p_cdc, pl2303_internal_control_complete, CONFIG_PL2303_COMPLETE)); break; #else TU_ATTR_FALLTHROUGH; #endif - case CONFIG_PL2303_FLOW_CTRL_READ: - // read flow control register for modify & write back in next step - if (p_cdc->pl2303.serial_private.type == &pl2303_type_data[TYPE_HXN]) { - TU_ASSERT_COMPLETE(pl2303_vendor_read(p_cdc, PL2303_HXN_FLOWCTRL_REG, &buf, pl2303_process_config, - CONFIG_PL2303_FLOW_CTRL_WRITE)); - } else { - TU_ASSERT_COMPLETE(pl2303_vendor_read(p_cdc, 0, &buf, pl2303_process_config, CONFIG_PL2303_FLOW_CTRL_WRITE)); - } - break; - - case CONFIG_PL2303_FLOW_CTRL_WRITE: - // no flow control - buf = xfer->buffer[0]; - if (p_cdc->pl2303.serial_private.type == &pl2303_type_data[TYPE_HXN]) { - buf &= (uint8_t) ~PL2303_HXN_FLOWCTRL_MASK; - buf |= PL2303_HXN_FLOWCTRL_NONE; - TU_ASSERT_COMPLETE(pl2303_vendor_write(p_cdc, PL2303_HXN_FLOWCTRL_REG, buf, pl2303_process_config, - CONFIG_PL2303_COMPLETE)); - } else { - buf &= (uint8_t) ~PL2303_FLOWCTRL_MASK; - TU_ASSERT_COMPLETE(pl2303_vendor_write(p_cdc, 0, buf, pl2303_process_config, CONFIG_PL2303_COMPLETE)); - } - break; +// skipped, because it's not working with each PL230x. flow control can be also set by PL2303 EEPROM Writer Program +// case CONFIG_PL2303_FLOW_CTRL_READ: +// // read flow control register for modify & write back in next step +// if (p_cdc->pl2303.serial_private.type == &pl2303_type_data[TYPE_HXN]) { +// TU_LOG_P_CDC ( "1\r\n" ); +// TU_ASSERT_COMPLETE(pl2303_vendor_read(p_cdc, PL2303_HXN_FLOWCTRL_REG, &buf, pl2303_process_config, +// CONFIG_PL2303_FLOW_CTRL_WRITE)); +// } else { +// TU_LOG_P_CDC ( "2\r\n" ); +// TU_ASSERT_COMPLETE(pl2303_vendor_read(p_cdc, 0, &buf, pl2303_process_config, CONFIG_PL2303_FLOW_CTRL_WRITE)); +// } +// break; +// +// case CONFIG_PL2303_FLOW_CTRL_WRITE: +// // no flow control +// buf = xfer->buffer[0]; +// if (p_cdc->pl2303.serial_private.type == &pl2303_type_data[TYPE_HXN]) { +// buf &= (uint8_t) ~PL2303_HXN_FLOWCTRL_MASK; +// buf |= PL2303_HXN_FLOWCTRL_NONE; +// TU_ASSERT_COMPLETE(pl2303_vendor_write(p_cdc, PL2303_HXN_FLOWCTRL_REG, buf, pl2303_process_config, +// CONFIG_PL2303_COMPLETE)); +// } else { +// buf &= (uint8_t) ~PL2303_FLOWCTRL_MASK; +// TU_ASSERT_COMPLETE(pl2303_vendor_write(p_cdc, 0, buf, pl2303_process_config, CONFIG_PL2303_COMPLETE)); +// } +// break; case CONFIG_PL2303_COMPLETE: set_config_complete(idx, 0, true); -- cgit v1.3.1 From 68602e4adda941ab11826afbd7b82e44134a97ae Mon Sep 17 00:00:00 2001 From: IngHK Date: Thu, 4 Apr 2024 14:16:02 +0200 Subject: small change process config complete --- src/class/cdc/cdc_host.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src/class') diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index b9915f583..fbe0cc9ca 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -1400,7 +1400,7 @@ static void ftdi_process_config(tuh_xfer_t * xfer) { break; default: - set_config_complete(idx, 0, false); + TU_ASSERT_COMPLETE(false); break; } } @@ -1876,7 +1876,7 @@ static void cp210x_process_config(tuh_xfer_t * xfer) { break; default: - set_config_complete(idx, 0, false); + TU_ASSERT_COMPLETE(false); break; } } @@ -2158,7 +2158,7 @@ static void ch34x_process_config(tuh_xfer_t* xfer) { break; default: - set_config_complete(idx, 0, false); + TU_ASSERT_COMPLETE(false); break; } } @@ -2729,7 +2729,7 @@ static void pl2303_process_config(tuh_xfer_t * xfer) { break; default: - set_config_complete(idx, 0, false); + TU_ASSERT_COMPLETE(false); break; } } -- cgit v1.3.1 From 61eee535c16701acd577b253bc17a7716ae60c7c Mon Sep 17 00:00:00 2001 From: Li Junru Date: Wed, 22 May 2024 20:57:23 +0800 Subject: feat(uvc): support format frame based --- src/class/video/video.h | 55 ++++++++++++++++++++++++++++++------------ src/class/video/video_device.c | 17 ++++++++++++- 2 files changed, 55 insertions(+), 17 deletions(-) (limited to 'src/class') diff --git a/src/class/video/video.h b/src/class/video/video.h index b8a9b6369..f348e187b 100644 --- a/src/class/video/video.h +++ b/src/class/video/video.h @@ -540,28 +540,32 @@ typedef struct TU_ATTR_PACKED { TU_VERIFY_STATIC( sizeof(video_probe_and_commit_control_t) == 48, "size is not correct"); -#define TUD_VIDEO_DESC_IAD_LEN 8 -#define TUD_VIDEO_DESC_STD_VC_LEN 9 -#define TUD_VIDEO_DESC_CS_VC_LEN 12 -#define TUD_VIDEO_DESC_INPUT_TERM_LEN 8 -#define TUD_VIDEO_DESC_OUTPUT_TERM_LEN 9 -#define TUD_VIDEO_DESC_CAMERA_TERM_LEN 18 -#define TUD_VIDEO_DESC_STD_VS_LEN 9 -#define TUD_VIDEO_DESC_CS_VS_IN_LEN 13 -#define TUD_VIDEO_DESC_CS_VS_OUT_LEN 9 -#define TUD_VIDEO_DESC_CS_VS_FMT_UNCOMPR_LEN 27 -#define TUD_VIDEO_DESC_CS_VS_FMT_MJPEG_LEN 11 -#define TUD_VIDEO_DESC_CS_VS_FRM_UNCOMPR_CONT_LEN 38 -#define TUD_VIDEO_DESC_CS_VS_FRM_UNCOMPR_DISC_LEN 26 -#define TUD_VIDEO_DESC_CS_VS_FRM_MJPEG_CONT_LEN 38 -#define TUD_VIDEO_DESC_CS_VS_FRM_MJPEG_DISC_LEN 26 -#define TUD_VIDEO_DESC_CS_VS_COLOR_MATCHING_LEN 6 +#define TUD_VIDEO_DESC_IAD_LEN 8 +#define TUD_VIDEO_DESC_STD_VC_LEN 9 +#define TUD_VIDEO_DESC_CS_VC_LEN 12 +#define TUD_VIDEO_DESC_INPUT_TERM_LEN 8 +#define TUD_VIDEO_DESC_OUTPUT_TERM_LEN 9 +#define TUD_VIDEO_DESC_CAMERA_TERM_LEN 18 +#define TUD_VIDEO_DESC_STD_VS_LEN 9 +#define TUD_VIDEO_DESC_CS_VS_IN_LEN 13 +#define TUD_VIDEO_DESC_CS_VS_OUT_LEN 9 +#define TUD_VIDEO_DESC_CS_VS_FMT_UNCOMPR_LEN 27 +#define TUD_VIDEO_DESC_CS_VS_FMT_MJPEG_LEN 11 +#define TUD_VIDEO_DESC_CS_VS_FMT_FRAME_BASED_LEN 28 +#define TUD_VIDEO_DESC_CS_VS_FRM_UNCOMPR_CONT_LEN 38 +#define TUD_VIDEO_DESC_CS_VS_FRM_UNCOMPR_DISC_LEN 26 +#define TUD_VIDEO_DESC_CS_VS_FRM_MJPEG_CONT_LEN 38 +#define TUD_VIDEO_DESC_CS_VS_FRM_MJPEG_DISC_LEN 26 +#define TUD_VIDEO_DESC_CS_VS_FRM_FRAME_BASED_CONT_LEN 38 +#define TUD_VIDEO_DESC_CS_VS_FRM_FRAME_BASED_DISC_LEN 26 +#define TUD_VIDEO_DESC_CS_VS_COLOR_MATCHING_LEN 6 /* 2.2 compression formats */ #define TUD_VIDEO_GUID_YUY2 0x59,0x55,0x59,0x32,0x00,0x00,0x10,0x00,0x80,0x00,0x00,0xAA,0x00,0x38,0x9B,0x71 #define TUD_VIDEO_GUID_NV12 0x4E,0x56,0x31,0x32,0x00,0x00,0x10,0x00,0x80,0x00,0x00,0xAA,0x00,0x38,0x9B,0x71 #define TUD_VIDEO_GUID_M420 0x4D,0x34,0x32,0x30,0x00,0x00,0x10,0x00,0x80,0x00,0x00,0xAA,0x00,0x38,0x9B,0x71 #define TUD_VIDEO_GUID_I420 0x49,0x34,0x32,0x30,0x00,0x00,0x10,0x00,0x80,0x00,0x00,0xAA,0x00,0x38,0x9B,0x71 +#define TUD_VIDEO_GUID_H264 0x48,0x32,0x36,0x34,0x00,0x00,0x10,0x00,0x80,0x00,0x00,0xAA,0x00,0x38,0x9B,0x71 #define TUD_VIDEO_DESC_IAD(_firstitf, _nitfs, _stridx) \ TUD_VIDEO_DESC_IAD_LEN, TUSB_DESC_INTERFACE_ASSOCIATION, \ @@ -656,6 +660,25 @@ TU_VERIFY_STATIC( sizeof(video_probe_and_commit_control_t) == 48, "size is not c _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__ +/* Motion-Frame-Based 3.1.1 Table 3-1 */ +#define TUD_VIDEO_DESC_CS_VS_FMT_FRAME_BASED(_fmtidx, _numfrmdesc, _guid, _bitsperpix, _frmidx, _asrx, _asry, _interlace, _cp, _variablesize) \ + TUD_VIDEO_DESC_CS_VS_FMT_FRAME_BASED_LEN, TUSB_DESC_CS_INTERFACE, VIDEO_CS_ITF_VS_FORMAT_FRAME_BASED, \ + _fmtidx, _numfrmdesc, TUD_VIDEO_GUID(_guid), _bitsperpix, _frmidx, _asrx, _asry, _interlace, _cp, _variablesize + +/* Motion-Frame-Based 3.1.1 Table 3-2 and 3-3 */ +#define TUD_VIDEO_DESC_CS_VS_FRM_FRAME_BASED_CONT(_frmidx, _cap, _width, _height, _minbr, _maxbr, _frminterval, _bytesperline, _minfrminterval, _maxfrminterval, _frmintervalstep) \ + TUD_VIDEO_DESC_CS_VS_FRM_FRAME_BASED_CONT_LEN, TUSB_DESC_CS_INTERFACE, VIDEO_CS_ITF_VS_FRAME_FRAME_BASED, \ + _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(_frminterval), 0, U32_TO_U8S_LE(_bytesperline), \ + U32_TO_U8S_LE(_minfrminterval), U32_TO_U8S_LE(_maxfrminterval), U32_TO_U8S_LE(_frmintervalstep) + +/* Motion-Frame-Based 3.1.1 Table 3-2 and 3-4 */ +#define TUD_VIDEO_DESC_CS_VS_FRM_FRAME_BASED_DISC(_frmidx, _cap, _width, _height, _minbr, _maxbr, _frminterval, _bytesperline, ...) \ + TUD_VIDEO_DESC_CS_VS_FRM_FRAME_BASED_DISC_LEN + (TU_ARGS_NUM(__VA_ARGS__)) * 4, \ + TUSB_DESC_CS_INTERFACE, VIDEO_CS_ITF_VS_FRAME_FRAME_BASED, \ + _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(_frminterval), U32_TO_U8S_LE(_bytesperline), (TU_ARGS_NUM(__VA_ARGS__)), __VA_ARGS__ + /* 3.9.2.6 */ #define TUD_VIDEO_DESC_CS_VS_COLOR_MATCHING(_color, _trns, _mat) \ TUD_VIDEO_DESC_CS_VS_COLOR_MATCHING_LEN, \ diff --git a/src/class/video/video_device.c b/src/class/video/video_device.c index 4218835aa..5310a393b 100644 --- a/src/class/video/video_device.c +++ b/src/class/video/video_device.c @@ -398,7 +398,7 @@ static inline void const *_find_desc_format(void const *beg, void const *end, ui if ((fmt == VIDEO_CS_ITF_VS_FORMAT_UNCOMPRESSED || fmt == VIDEO_CS_ITF_VS_FORMAT_MJPEG || fmt == VIDEO_CS_ITF_VS_FORMAT_DV || - fmt == VIDEO_CS_ITF_VS_FRAME_FRAME_BASED) && + fmt == VIDEO_CS_ITF_VS_FORMAT_FRAME_BASED) && fmtnum == p[3]) { return cur; } @@ -464,6 +464,9 @@ static bool _update_streaming_parameters(videod_streaming_interface_t const *stm case VIDEO_CS_ITF_VS_FORMAT_MJPEG: break; + case VIDEO_CS_ITF_VS_FORMAT_FRAME_BASED: + break; + default: return false; } @@ -489,6 +492,10 @@ static bool _update_streaming_parameters(videod_streaming_interface_t const *stm frame_size = (uint_fast32_t)frm->wWidth * frm->wHeight * 16 / 8; /* YUV422 */ break; + case VIDEO_CS_ITF_VS_FORMAT_FRAME_BASED: + frame_size = (uint_fast32_t)frm->wWidth * frm->wHeight * 16 / 8; /* YUV422 */ + break; + default: break; } param->dwMaxVideoFrameSize = frame_size; @@ -578,6 +585,10 @@ static bool _negotiate_streaming_parameters(videod_streaming_interface_t const * frmnum = fmt->mjpeg.bDefaultFrameIndex; break; + case VIDEO_CS_ITF_VS_FORMAT_FRAME_BASED: + frmnum = fmt->frame_based.bDefaultFrameIndex; + break; + default: return false; } break; @@ -596,6 +607,10 @@ static bool _negotiate_streaming_parameters(videod_streaming_interface_t const * frame_size = (uint_fast32_t)frm->wWidth * frm->wHeight * 16 / 8; /* YUV422 */ break; + case VIDEO_CS_ITF_VS_FORMAT_FRAME_BASED: + frame_size = (uint_fast32_t)frm->wWidth * frm->wHeight * 16 / 8; /* YUV422 */ + break; + default: return false; } param->dwMaxVideoFrameSize = frame_size; -- cgit v1.3.1 From f2ed60e9fc562bc5fd2016aea61695b708c2bd53 Mon Sep 17 00:00:00 2001 From: HiFiPhile Date: Sat, 30 Nov 2024 21:49:33 +0100 Subject: Update audio class with dcache support. Signed-off-by: HiFiPhile --- examples/device/audio_test_multi_rate/src/main.c | 2 +- src/class/audio/audio_device.c | 212 ++++++++++++++--------- src/class/audio/audio_device.h | 3 + 3 files changed, 133 insertions(+), 84 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 f9dcd1b8a..8fa902a04 100644 --- a/examples/device/audio_test_multi_rate/src/main.c +++ b/examples/device/audio_test_multi_rate/src/main.c @@ -85,7 +85,7 @@ audio_control_range_2_n_t(1) volumeRng[CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX+1]; // Audio test data -CFG_TUSB_MEM_ALIGN uint8_t test_buffer_audio[CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX]; +CFG_TUD_MEM_ALIGN uint8_t test_buffer_audio[CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX]; uint16_t startVal = 0; void led_blinking_task(void); diff --git a/src/class/audio/audio_device.c b/src/class/audio/audio_device.c index cd4183cc3..2add741a8 100644 --- a/src/class/audio/audio_device.c +++ b/src/class/audio/audio_device.c @@ -81,6 +81,7 @@ // Only STM32 and dcd_transdimension use non-linear buffer for now // dwc2 except esp32sx (since it may use dcd_esp32sx) +// Ring buffer is imcompatible with dcache, since neither address nor size is aligned to cache line #if (defined(TUP_USBIP_DWC2) && !TU_CHECK_MCU(OPT_MCU_ESP32S2, OPT_MCU_ESP32S3)) || \ defined(TUP_USBIP_FSDEV) || \ CFG_TUSB_MCU == OPT_MCU_RX63X || \ @@ -90,7 +91,7 @@ CFG_TUSB_MCU == OPT_MCU_LPC43XX || \ CFG_TUSB_MCU == OPT_MCU_MIMXRT1XXX || \ CFG_TUSB_MCU == OPT_MCU_MSP432E4 - #if TUD_AUDIO_PREFER_RING_BUFFER + #if TUD_AUDIO_PREFER_RING_BUFFER && !CFG_TUD_MEM_DCACHE_ENABLE #define USE_LINEAR_BUFFER 0 #else #define USE_LINEAR_BUFFER 1 @@ -106,109 +107,115 @@ #error Maximum number of audio functions restricted to three! #endif -// Put sw_buf in USB section only if necessary +// Put swap buffer in USB section only if necessary #if USE_LINEAR_BUFFER || CFG_TUD_AUDIO_ENABLE_ENCODING -#define IN_SW_BUF_MEM_SECTION +#define IN_SW_BUF_MEM_ATTR TU_ATTR_ALIGNED(4) #else -#define IN_SW_BUF_MEM_SECTION CFG_TUD_MEM_SECTION +#define IN_SW_BUF_MEM_ATTR CFG_TUD_MEM_SECTION CFG_TUD_MEM_ALIGN #endif #if USE_LINEAR_BUFFER || CFG_TUD_AUDIO_ENABLE_DECODING -#define OUT_SW_BUF_MEM_SECTION +#define OUT_SW_BUF_MEM_ATTR TU_ATTR_ALIGNED(4) #else -#define OUT_SW_BUF_MEM_SECTION CFG_TUD_MEM_SECTION +#define OUT_SW_BUF_MEM_ATTR CFG_TUD_MEM_SECTION CFG_TUD_MEM_ALIGN #endif // EP IN software buffers and mutexes #if CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_ENCODING +tu_static IN_SW_BUF_MEM_ATTR struct { #if CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ > 0 - tu_static 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 - tu_static 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 - + TUD_EPBUF_DEF(buf_1, CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ); + #endif #if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_IN_SW_BUF_SZ > 0 - tu_static 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 - tu_static 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 - + TUD_EPBUF_DEF(buf_2, CFG_TUD_AUDIO_FUNC_2_EP_IN_SW_BUF_SZ); + #endif #if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_IN_SW_BUF_SZ > 0 - tu_static 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 - tu_static osal_mutex_def_t ep_in_ff_mutex_wr_3; // No need for read mutex as only USB driver reads from FIFO + TUD_EPBUF_DEF(buf_3, CFG_TUD_AUDIO_FUNC_3_EP_IN_SW_BUF_SZ); + #endif +} ep_in_sw_buf; + + #if CFG_FIFO_MUTEX + #if CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ > 0 + tu_static osal_mutex_def_t ep_in_ff_mutex_wr_1; + #endif + #if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_IN_SW_BUF_SZ > 0 + tu_static osal_mutex_def_t ep_in_ff_mutex_wr_2; + #endif + #if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_IN_SW_BUF_SZ > 0 + tu_static osal_mutex_def_t ep_in_ff_mutex_wr_3; #endif - #endif // CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_IN_SW_BUF_SZ > 0 + #endif #endif // CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_ENCODING // Linear buffer TX in case: // - target MCU is not capable of handling a ring buffer FIFO e.g. no hardware buffer is available or driver is would need to be changed dramatically OR // - the software encoding is used - in this case the linear buffers serve as a target memory where logical channels are encoded into #if CFG_TUD_AUDIO_ENABLE_EP_IN && (USE_LINEAR_BUFFER || CFG_TUD_AUDIO_ENABLE_ENCODING) +tu_static CFG_TUD_MEM_SECTION struct { #if CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX > 0 - tu_static CFG_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t lin_buf_in_1[CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX]; + TUD_EPBUF_DEF(buf_1, CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX); #endif - #if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_IN_SZ_MAX > 0 - tu_static CFG_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t lin_buf_in_2[CFG_TUD_AUDIO_FUNC_2_EP_IN_SZ_MAX]; + TUD_EPBUF_DEF(buf_2, CFG_TUD_AUDIO_FUNC_2_EP_IN_SZ_MAX); #endif - #if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_IN_SZ_MAX > 0 - tu_static CFG_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t lin_buf_in_3[CFG_TUD_AUDIO_FUNC_3_EP_IN_SZ_MAX]; + TUD_EPBUF_DEF(buf_3, CFG_TUD_AUDIO_FUNC_3_EP_IN_SZ_MAX); #endif +} lin_buf_in; #endif // CFG_TUD_AUDIO_ENABLE_EP_IN && (USE_LINEAR_BUFFER || CFG_TUD_AUDIO_ENABLE_DECODING) // EP OUT software buffers and mutexes #if CFG_TUD_AUDIO_ENABLE_EP_OUT && !CFG_TUD_AUDIO_ENABLE_DECODING +tu_static OUT_SW_BUF_MEM_ATTR struct { #if CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ > 0 - tu_static 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 - tu_static 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 - + TUD_EPBUF_DEF(buf_1, CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ); + #endif #if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_OUT_SW_BUF_SZ > 0 - tu_static 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 - tu_static 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 - + TUD_EPBUF_DEF(buf_2, CFG_TUD_AUDIO_FUNC_2_EP_OUT_SW_BUF_SZ); + #endif #if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_OUT_SW_BUF_SZ > 0 - tu_static 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 - tu_static osal_mutex_def_t ep_out_ff_mutex_rd_3; // No need for write mutex as only USB driver writes into FIFO + TUD_EPBUF_DEF(buf_3, CFG_TUD_AUDIO_FUNC_3_EP_OUT_SW_BUF_SZ); + #endif +} ep_out_sw_buf; + + #if CFG_FIFO_MUTEX + #if CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ > 0 + tu_static osal_mutex_def_t ep_out_ff_mutex_wr_1; + #endif + #if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_OUT_SW_BUF_SZ > 0 + tu_static osal_mutex_def_t ep_out_ff_mutex_wr_2; #endif - #endif // CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_OUT_SW_BUF_SZ > 0 + #if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_OUT_SW_BUF_SZ > 0 + tu_static osal_mutex_def_t ep_out_ff_mutex_wr_3; + #endif + #endif #endif // CFG_TUD_AUDIO_ENABLE_EP_OUT && !CFG_TUD_AUDIO_ENABLE_DECODING // Linear buffer RX in case: // - target MCU is not capable of handling a ring buffer FIFO e.g. no hardware buffer is available or driver is would need to be changed dramatically OR // - the software encoding is used - in this case the linear buffers serve as a target memory where logical channels are encoded into #if CFG_TUD_AUDIO_ENABLE_EP_OUT && (USE_LINEAR_BUFFER || CFG_TUD_AUDIO_ENABLE_DECODING) +tu_static CFG_TUD_MEM_SECTION struct { #if CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX > 0 - tu_static CFG_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t lin_buf_out_1[CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX]; + TUD_EPBUF_DEF(buf_1, CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX); #endif - #if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_OUT_SZ_MAX > 0 - tu_static CFG_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t lin_buf_out_2[CFG_TUD_AUDIO_FUNC_2_EP_OUT_SZ_MAX]; + TUD_EPBUF_DEF(buf_2, CFG_TUD_AUDIO_FUNC_2_EP_OUT_SZ_MAX); #endif - #if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_OUT_SZ_MAX > 0 - tu_static CFG_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t lin_buf_out_3[CFG_TUD_AUDIO_FUNC_3_EP_OUT_SZ_MAX]; + TUD_EPBUF_DEF(buf_3, CFG_TUD_AUDIO_FUNC_3_EP_OUT_SZ_MAX); #endif +} lin_buf_out; #endif // CFG_TUD_AUDIO_ENABLE_EP_OUT && (USE_LINEAR_BUFFER || CFG_TUD_AUDIO_ENABLE_DECODING) // Control buffers -tu_static CFG_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t ctrl_buf_1[CFG_TUD_AUDIO_FUNC_1_CTRL_BUF_SZ]; +tu_static uint8_t ctrl_buf_1[CFG_TUD_AUDIO_FUNC_1_CTRL_BUF_SZ]; #if CFG_TUD_AUDIO > 1 -tu_static CFG_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t ctrl_buf_2[CFG_TUD_AUDIO_FUNC_2_CTRL_BUF_SZ]; +tu_static uint8_t ctrl_buf_2[CFG_TUD_AUDIO_FUNC_2_CTRL_BUF_SZ]; #endif #if CFG_TUD_AUDIO > 2 -tu_static CFG_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t ctrl_buf_3[CFG_TUD_AUDIO_FUNC_3_CTRL_BUF_SZ]; +tu_static uint8_t ctrl_buf_3[CFG_TUD_AUDIO_FUNC_3_CTRL_BUF_SZ]; #endif // Active alternate setting of interfaces @@ -225,7 +232,7 @@ tu_static 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 - tu_static 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_static TU_ATTR_ALIGNED(4) 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_static tu_fifo_t tx_supp_ff_1[CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO]; #if CFG_FIFO_MUTEX tu_static 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 @@ -233,7 +240,7 @@ tu_static 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 - tu_static 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_static TU_ATTR_ALIGNED(4) 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_static tu_fifo_t tx_supp_ff_2[CFG_TUD_AUDIO_FUNC_2_N_TX_SUPP_SW_FIFO]; #if CFG_FIFO_MUTEX tu_static 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 @@ -241,7 +248,7 @@ tu_static 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 - tu_static 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_static TU_ATTR_ALIGNED(4) 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_static tu_fifo_t tx_supp_ff_3[CFG_TUD_AUDIO_FUNC_3_N_TX_SUPP_SW_FIFO]; #if CFG_FIFO_MUTEX tu_static 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 @@ -251,7 +258,7 @@ tu_static 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 - tu_static 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_static TU_ATTR_ALIGNED(4) 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_static tu_fifo_t rx_supp_ff_1[CFG_TUD_AUDIO_FUNC_1_N_RX_SUPP_SW_FIFO]; #if CFG_FIFO_MUTEX tu_static 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 @@ -259,7 +266,7 @@ tu_static 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 - tu_static 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_static TU_ATTR_ALIGNED(4) 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_static tu_fifo_t rx_supp_ff_2[CFG_TUD_AUDIO_FUNC_2_N_RX_SUPP_SW_FIFO]; #if CFG_FIFO_MUTEX tu_static 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 @@ -267,7 +274,7 @@ tu_static 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 - tu_static 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_static TU_ATTR_ALIGNED(4) 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_static tu_fifo_t rx_supp_ff_3[CFG_TUD_AUDIO_FUNC_3_N_RX_SUPP_SW_FIFO]; #if CFG_FIFO_MUTEX tu_static 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 @@ -275,6 +282,28 @@ tu_static uint8_t alt_setting_3[CFG_TUD_AUDIO_FUNC_3_N_AS_INT]; #endif #endif +// Aligned buffer for feedback EP +#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP +tu_static CFG_TUD_MEM_SECTION struct { + #if CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX > 0 + TUD_EPBUF_TYPE_DEF(uint32_t, buf_1); + #endif + #if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_OUT_SZ_MAX > 0 + TUD_EPBUF_TYPE_DEF(uint32_t, buf_2); + #endif + #if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_OUT_SZ_MAX > 0 + TUD_EPBUF_TYPE_DEF(uint32_t, buf_3); + #endif +} fb_ep_buf; +#endif + +// Aligned buffer for interrupt EP +#if CFG_TUD_AUDIO_ENABLE_INTERRUPT_EP +tu_static CFG_TUD_MEM_SECTION struct { + TUD_EPBUF_DEF(buf, CFG_TUD_AUDIO_INTERRUPT_EP_SZ); +} int_ep_buf[CFG_TUD_AUDIO]; +#endif + typedef struct { uint8_t rhport; @@ -307,7 +336,6 @@ typedef struct #if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP struct { - CFG_TUSB_MEM_ALIGN uint32_t send_buf; uint32_t value; // Feedback value for asynchronous mode (in 16.16 format). uint32_t min_value; // min value according to UAC2 FMT-2.0 section 2.3.1.1. uint32_t max_value; // max value according to UAC2 FMT-2.0 section 2.3.1.1. @@ -385,11 +413,6 @@ typedef struct tu_fifo_t ep_in_ff; #endif - // Audio control interrupt buffer - no FIFO - 6 Bytes according to UAC 2 specification (p. 74) -#if CFG_TUD_AUDIO_ENABLE_INTERRUPT_EP - CFG_TUSB_MEM_ALIGN uint8_t ep_int_buf[6]; -#endif - // Support FIFOs for software encoding and decoding #if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_DECODING tu_fifo_t * rx_supp_ff; @@ -420,6 +443,9 @@ typedef struct #define USE_LINEAR_BUFFER_TX 1 #endif +#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP + uint32_t * fb_buf; +#endif } audiod_function_t; #ifndef USE_LINEAR_BUFFER_TX @@ -964,10 +990,10 @@ bool tud_audio_int_n_write(uint8_t func_id, const audio_interrupt_data_t * data) TU_VERIFY(usbd_edpt_claim(_audiod_fct[func_id].rhport, _audiod_fct[func_id].ep_int)); // Check length - if (tu_memcpy_s(_audiod_fct[func_id].ep_int_buf, sizeof(_audiod_fct[func_id].ep_int_buf), data, sizeof(audio_interrupt_data_t)) == 0) + if (tu_memcpy_s(int_ep_buf[func_id].buf, sizeof(int_ep_buf[func_id].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); + TU_ASSERT(usbd_edpt_xfer(_audiod_fct[func_id].rhport, _audiod_fct[func_id].ep_int, int_ep_buf[func_id].buf, sizeof(int_ep_buf[func_id].buf)), 0); } else { // Release endpoint since we don't make any transfer @@ -1221,7 +1247,7 @@ static inline bool audiod_fb_send(audiod_function_t *audio) // Format the feedback value if (apply_correction) { - uint8_t * fb = (uint8_t *) &audio->feedback.send_buf; + uint8_t * fb = (uint8_t *) audio->fb_buf; // For FS format is 10.14 *(fb++) = (audio->feedback.value >> 2) & 0xFF; @@ -1230,7 +1256,7 @@ static inline bool audiod_fb_send(audiod_function_t *audio) *fb = 0; } else { - audio->feedback.send_buf = audio->feedback.value; + *audio->fb_buf = audio->feedback.value; } // About feedback format on FS @@ -1246,7 +1272,7 @@ static inline bool audiod_fb_send(audiod_function_t *audio) // 10.14 3 3 Linux, OSX // // We send 3 bytes since sending packet larger than wMaxPacketSize is pretty ugly - return usbd_edpt_xfer(audio->rhport, audio->ep_fb, (uint8_t *) &audio->feedback.send_buf, apply_correction ? 3 : 4); + return usbd_edpt_xfer(audio->rhport, audio->ep_fb, (uint8_t *) audio->fb_buf, apply_correction ? 3 : 4); } #endif @@ -1309,7 +1335,7 @@ void audiod_init(void) { #if CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ > 0 case 0: - tu_fifo_config(&audio->ep_in_ff, audio_ep_in_sw_buf_1, CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ, 1, true); + tu_fifo_config(&audio->ep_in_ff, ep_in_sw_buf.buf_1, CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ, 1, true); #if CFG_FIFO_MUTEX tu_fifo_config_mutex(&audio->ep_in_ff, osal_mutex_create(&ep_in_ff_mutex_wr_1), NULL); #endif @@ -1317,7 +1343,7 @@ void audiod_init(void) #endif #if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_IN_SW_BUF_SZ > 0 case 1: - tu_fifo_config(&audio->ep_in_ff, audio_ep_in_sw_buf_2, CFG_TUD_AUDIO_FUNC_2_EP_IN_SW_BUF_SZ, 1, true); + tu_fifo_config(&audio->ep_in_ff, ep_in_sw_buf.buf_2, CFG_TUD_AUDIO_FUNC_2_EP_IN_SW_BUF_SZ, 1, true); #if CFG_FIFO_MUTEX tu_fifo_config_mutex(&audio->ep_in_ff, osal_mutex_create(&ep_in_ff_mutex_wr_2), NULL); #endif @@ -1325,7 +1351,7 @@ void audiod_init(void) #endif #if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_IN_SW_BUF_SZ > 0 case 2: - tu_fifo_config(&audio->ep_in_ff, audio_ep_in_sw_buf_3, CFG_TUD_AUDIO_FUNC_3_EP_IN_SW_BUF_SZ, 1, true); + tu_fifo_config(&audio->ep_in_ff, ep_in_sw_buf.buf_3, CFG_TUD_AUDIO_FUNC_3_EP_IN_SW_BUF_SZ, 1, true); #if CFG_FIFO_MUTEX tu_fifo_config_mutex(&audio->ep_in_ff, osal_mutex_create(&ep_in_ff_mutex_wr_3), NULL); #endif @@ -1340,17 +1366,17 @@ void audiod_init(void) { #if CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX > 0 case 0: - audio->lin_buf_in = lin_buf_in_1; + audio->lin_buf_in = lin_buf_in.buf_1; break; #endif #if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_IN_SZ_MAX > 0 case 1: - audio->lin_buf_in = lin_buf_in_2; + audio->lin_buf_in = lin_buf_in.buf_2; break; #endif #if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_IN_SZ_MAX > 0 case 2: - audio->lin_buf_in = lin_buf_in_3; + audio->lin_buf_in = lin_buf_in.buf_3; break; #endif } @@ -1363,7 +1389,7 @@ void audiod_init(void) { #if CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ > 0 case 0: - tu_fifo_config(&audio->ep_out_ff, audio_ep_out_sw_buf_1, CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ, 1, true); + tu_fifo_config(&audio->ep_out_ff, ep_out_sw_buf.buf_1, CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ, 1, true); #if CFG_FIFO_MUTEX tu_fifo_config_mutex(&audio->ep_out_ff, NULL, osal_mutex_create(&ep_out_ff_mutex_rd_1)); #endif @@ -1371,7 +1397,7 @@ void audiod_init(void) #endif #if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_OUT_SW_BUF_SZ > 0 case 1: - tu_fifo_config(&audio->ep_out_ff, audio_ep_out_sw_buf_2, CFG_TUD_AUDIO_FUNC_2_EP_OUT_SW_BUF_SZ, 1, true); + tu_fifo_config(&audio->ep_out_ff, ep_out_sw_buf.buf_2, CFG_TUD_AUDIO_FUNC_2_EP_OUT_SW_BUF_SZ, 1, true); #if CFG_FIFO_MUTEX tu_fifo_config_mutex(&audio->ep_out_ff, NULL, osal_mutex_create(&ep_out_ff_mutex_rd_2)); #endif @@ -1379,7 +1405,7 @@ void audiod_init(void) #endif #if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_OUT_SW_BUF_SZ > 0 case 2: - tu_fifo_config(&audio->ep_out_ff, audio_ep_out_sw_buf_3, CFG_TUD_AUDIO_FUNC_3_EP_OUT_SW_BUF_SZ, 1, true); + tu_fifo_config(&audio->ep_out_ff, ep_out_sw_buf.buf_3, CFG_TUD_AUDIO_FUNC_3_EP_OUT_SW_BUF_SZ, 1, true); #if CFG_FIFO_MUTEX tu_fifo_config_mutex(&audio->ep_out_ff, NULL, osal_mutex_create(&ep_out_ff_mutex_rd_3)); #endif @@ -1394,21 +1420,42 @@ void audiod_init(void) { #if CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX > 0 case 0: - audio->lin_buf_out = lin_buf_out_1; + audio->lin_buf_out = lin_buf_out.buf_1; break; #endif #if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_OUT_SZ_MAX > 0 case 1: - audio->lin_buf_out = lin_buf_out_2; + audio->lin_buf_out = lin_buf_out.buf_2; break; #endif #if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_OUT_SZ_MAX > 0 case 2: - audio->lin_buf_out = lin_buf_out_3; + audio->lin_buf_out = lin_buf_out.buf_3; break; #endif } -#endif // USE_LINEAR_BUFFER_TX +#endif // USE_LINEAR_BUFFER_RX + +#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP + switch (i) + { +#if CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX > 0 + case 0: + audio->fb_buf = &fb_ep_buf.buf_1; + break; +#endif +#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_OUT_SZ_MAX > 0 + case 1: + audio->fb_buf = &fb_ep_buf.buf_2; + break; +#endif +#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_OUT_SZ_MAX > 0 + case 2: + audio->fb_buf = &fb_ep_buf.buf_3; + break; +#endif + } +#endif // CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP // Initialize TX support FIFOs if required #if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_ENCODING @@ -1810,8 +1857,7 @@ static bool audiod_get_interface(uint8_t rhport, tusb_control_request_t const * uint8_t const *dummy; TU_VERIFY(audiod_get_AS_interface_index_global(itf, &func_id, &idxItf, &dummy)); - _audiod_fct[func_id].ctrl_buf[0] = _audiod_fct[func_id].alt_setting[idxItf]; - TU_VERIFY(tud_control_xfer(rhport, p_request, _audiod_fct[func_id].ctrl_buf, 1)); + TU_VERIFY(tud_control_xfer(rhport, p_request, &_audiod_fct[func_id].alt_setting[idxItf], 1)); TU_LOG2(" Get itf: %u - current alt: %u\r\n", itf, _audiod_fct[func_id].alt_setting[idxItf]); diff --git a/src/class/audio/audio_device.h b/src/class/audio/audio_device.h index ae253f49d..0a7bff212 100644 --- a/src/class/audio/audio_device.h +++ b/src/class/audio/audio_device.h @@ -203,6 +203,9 @@ #define CFG_TUD_AUDIO_ENABLE_INTERRUPT_EP 0 // Feedback - 0 or 1 #endif +// Audio control interrupt EP - 6 Bytes according to UAC 2 specification (p. 74) +#define CFG_TUD_AUDIO_INTERRUPT_EP_SZ 6 + // Use software encoding/decoding // The software coding feature of the driver is not mandatory. It is useful if, for instance, you have two I2S streams which need to be interleaved -- cgit v1.3.1 From 0bca377d5210833ac259db6ed9d7d96c724f3e6e Mon Sep 17 00:00:00 2001 From: HiFiPhile Date: Sat, 30 Nov 2024 21:57:47 +0100 Subject: Fix typo. Signed-off-by: HiFiPhile --- src/class/audio/audio_device.c | 8 ++++---- src/portable/chipidea/ci_hs/dcd_ci_hs.c | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'src/class') diff --git a/src/class/audio/audio_device.c b/src/class/audio/audio_device.c index 2add741a8..425da4483 100644 --- a/src/class/audio/audio_device.c +++ b/src/class/audio/audio_device.c @@ -81,7 +81,7 @@ // Only STM32 and dcd_transdimension use non-linear buffer for now // dwc2 except esp32sx (since it may use dcd_esp32sx) -// Ring buffer is imcompatible with dcache, since neither address nor size is aligned to cache line +// Ring buffer is incompatible with dcache, since neither address nor size is aligned to cache line #if (defined(TUP_USBIP_DWC2) && !TU_CHECK_MCU(OPT_MCU_ESP32S2, OPT_MCU_ESP32S3)) || \ defined(TUP_USBIP_FSDEV) || \ CFG_TUSB_MCU == OPT_MCU_RX63X || \ @@ -179,13 +179,13 @@ tu_static OUT_SW_BUF_MEM_ATTR struct { #if CFG_FIFO_MUTEX #if CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ > 0 - tu_static osal_mutex_def_t ep_out_ff_mutex_wr_1; + tu_static osal_mutex_def_t ep_out_ff_mutex_rd_1; #endif #if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_OUT_SW_BUF_SZ > 0 - tu_static osal_mutex_def_t ep_out_ff_mutex_wr_2; + tu_static osal_mutex_def_t ep_out_ff_mutex_rd_2; #endif #if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_OUT_SW_BUF_SZ > 0 - tu_static osal_mutex_def_t ep_out_ff_mutex_wr_3; + tu_static osal_mutex_def_t ep_out_ff_mutex_rd_3; #endif #endif #endif // CFG_TUD_AUDIO_ENABLE_EP_OUT && !CFG_TUD_AUDIO_ENABLE_DECODING diff --git a/src/portable/chipidea/ci_hs/dcd_ci_hs.c b/src/portable/chipidea/ci_hs/dcd_ci_hs.c index bacc1b99d..331fbfe80 100644 --- a/src/portable/chipidea/ci_hs/dcd_ci_hs.c +++ b/src/portable/chipidea/ci_hs/dcd_ci_hs.c @@ -467,7 +467,7 @@ bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t t #if !CFG_TUD_MEM_DCACHE_ENABLE // fifo has to be aligned to 4k boundary -// It's imcompatible with dcache enabled transfer, since neither address nor size is aligned to cache line +// It's incompatible with dcache enabled transfer, since neither address nor size is aligned to cache line bool dcd_edpt_xfer_fifo (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes) { uint8_t const epnum = tu_edpt_number(ep_addr); -- cgit v1.3.1 From df91c12ab29a117edee504b876dfaf78a5615da9 Mon Sep 17 00:00:00 2001 From: HiFiPhile Date: Sat, 30 Nov 2024 23:31:28 +0100 Subject: Reformat audio class. Signed-off-by: HiFiPhile --- src/class/audio/audio_device.c | 1571 +++++++++++++++++----------------------- 1 file changed, 670 insertions(+), 901 deletions(-) (limited to 'src/class') diff --git a/src/class/audio/audio_device.c b/src/class/audio/audio_device.c index 425da4483..8a130b7e2 100644 --- a/src/class/audio/audio_device.c +++ b/src/class/audio/audio_device.c @@ -83,68 +83,68 @@ // dwc2 except esp32sx (since it may use dcd_esp32sx) // Ring buffer is incompatible with dcache, since neither address nor size is aligned to cache line #if (defined(TUP_USBIP_DWC2) && !TU_CHECK_MCU(OPT_MCU_ESP32S2, OPT_MCU_ESP32S3)) || \ - defined(TUP_USBIP_FSDEV) || \ - CFG_TUSB_MCU == OPT_MCU_RX63X || \ - CFG_TUSB_MCU == OPT_MCU_RX65X || \ - CFG_TUSB_MCU == OPT_MCU_RX72N || \ - CFG_TUSB_MCU == OPT_MCU_LPC18XX || \ - CFG_TUSB_MCU == OPT_MCU_LPC43XX || \ - CFG_TUSB_MCU == OPT_MCU_MIMXRT1XXX || \ + defined(TUP_USBIP_FSDEV) || \ + CFG_TUSB_MCU == OPT_MCU_RX63X || \ + CFG_TUSB_MCU == OPT_MCU_RX65X || \ + CFG_TUSB_MCU == OPT_MCU_RX72N || \ + CFG_TUSB_MCU == OPT_MCU_LPC18XX || \ + CFG_TUSB_MCU == OPT_MCU_LPC43XX || \ + CFG_TUSB_MCU == OPT_MCU_MIMXRT1XXX || \ CFG_TUSB_MCU == OPT_MCU_MSP432E4 #if TUD_AUDIO_PREFER_RING_BUFFER && !CFG_TUD_MEM_DCACHE_ENABLE - #define USE_LINEAR_BUFFER 0 + #define USE_LINEAR_BUFFER 0 #else - #define USE_LINEAR_BUFFER 1 + #define USE_LINEAR_BUFFER 1 #endif #else - #define USE_LINEAR_BUFFER 1 + #define USE_LINEAR_BUFFER 1 #endif // Declaration of buffers // Check for maximum supported numbers #if CFG_TUD_AUDIO > 3 -#error Maximum number of audio functions restricted to three! + #error Maximum number of audio functions restricted to three! #endif // Put swap buffer in USB section only if necessary #if USE_LINEAR_BUFFER || CFG_TUD_AUDIO_ENABLE_ENCODING -#define IN_SW_BUF_MEM_ATTR TU_ATTR_ALIGNED(4) + #define IN_SW_BUF_MEM_ATTR TU_ATTR_ALIGNED(4) #else -#define IN_SW_BUF_MEM_ATTR CFG_TUD_MEM_SECTION CFG_TUD_MEM_ALIGN + #define IN_SW_BUF_MEM_ATTR CFG_TUD_MEM_SECTION CFG_TUD_MEM_ALIGN #endif #if USE_LINEAR_BUFFER || CFG_TUD_AUDIO_ENABLE_DECODING -#define OUT_SW_BUF_MEM_ATTR TU_ATTR_ALIGNED(4) + #define OUT_SW_BUF_MEM_ATTR TU_ATTR_ALIGNED(4) #else -#define OUT_SW_BUF_MEM_ATTR CFG_TUD_MEM_SECTION CFG_TUD_MEM_ALIGN + #define OUT_SW_BUF_MEM_ATTR CFG_TUD_MEM_SECTION CFG_TUD_MEM_ALIGN #endif // EP IN software buffers and mutexes #if CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_ENCODING tu_static IN_SW_BUF_MEM_ATTR struct { #if CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ > 0 - TUD_EPBUF_DEF(buf_1, CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ); + TUD_EPBUF_DEF(buf_1, CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ); #endif #if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_IN_SW_BUF_SZ > 0 - TUD_EPBUF_DEF(buf_2, CFG_TUD_AUDIO_FUNC_2_EP_IN_SW_BUF_SZ); + TUD_EPBUF_DEF(buf_2, CFG_TUD_AUDIO_FUNC_2_EP_IN_SW_BUF_SZ); #endif #if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_IN_SW_BUF_SZ > 0 - TUD_EPBUF_DEF(buf_3, CFG_TUD_AUDIO_FUNC_3_EP_IN_SW_BUF_SZ); + TUD_EPBUF_DEF(buf_3, CFG_TUD_AUDIO_FUNC_3_EP_IN_SW_BUF_SZ); #endif } ep_in_sw_buf; #if CFG_FIFO_MUTEX #if CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ > 0 - tu_static osal_mutex_def_t ep_in_ff_mutex_wr_1; + tu_static osal_mutex_def_t ep_in_ff_mutex_wr_1; #endif #if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_IN_SW_BUF_SZ > 0 - tu_static osal_mutex_def_t ep_in_ff_mutex_wr_2; + tu_static osal_mutex_def_t ep_in_ff_mutex_wr_2; #endif #if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_IN_SW_BUF_SZ > 0 - tu_static osal_mutex_def_t ep_in_ff_mutex_wr_3; + tu_static osal_mutex_def_t ep_in_ff_mutex_wr_3; #endif #endif -#endif // CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_ENCODING +#endif// CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_ENCODING // Linear buffer TX in case: // - target MCU is not capable of handling a ring buffer FIFO e.g. no hardware buffer is available or driver is would need to be changed dramatically OR @@ -152,43 +152,43 @@ tu_static IN_SW_BUF_MEM_ATTR struct { #if CFG_TUD_AUDIO_ENABLE_EP_IN && (USE_LINEAR_BUFFER || CFG_TUD_AUDIO_ENABLE_ENCODING) tu_static CFG_TUD_MEM_SECTION struct { #if CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX > 0 - TUD_EPBUF_DEF(buf_1, CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX); + TUD_EPBUF_DEF(buf_1, CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX); #endif #if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_IN_SZ_MAX > 0 - TUD_EPBUF_DEF(buf_2, CFG_TUD_AUDIO_FUNC_2_EP_IN_SZ_MAX); + TUD_EPBUF_DEF(buf_2, CFG_TUD_AUDIO_FUNC_2_EP_IN_SZ_MAX); #endif #if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_IN_SZ_MAX > 0 - TUD_EPBUF_DEF(buf_3, CFG_TUD_AUDIO_FUNC_3_EP_IN_SZ_MAX); + TUD_EPBUF_DEF(buf_3, CFG_TUD_AUDIO_FUNC_3_EP_IN_SZ_MAX); #endif } lin_buf_in; -#endif // CFG_TUD_AUDIO_ENABLE_EP_IN && (USE_LINEAR_BUFFER || CFG_TUD_AUDIO_ENABLE_DECODING) +#endif// CFG_TUD_AUDIO_ENABLE_EP_IN && (USE_LINEAR_BUFFER || CFG_TUD_AUDIO_ENABLE_DECODING) // EP OUT software buffers and mutexes #if CFG_TUD_AUDIO_ENABLE_EP_OUT && !CFG_TUD_AUDIO_ENABLE_DECODING tu_static OUT_SW_BUF_MEM_ATTR struct { #if CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ > 0 - TUD_EPBUF_DEF(buf_1, CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ); + TUD_EPBUF_DEF(buf_1, CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ); #endif #if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_OUT_SW_BUF_SZ > 0 - TUD_EPBUF_DEF(buf_2, CFG_TUD_AUDIO_FUNC_2_EP_OUT_SW_BUF_SZ); + TUD_EPBUF_DEF(buf_2, CFG_TUD_AUDIO_FUNC_2_EP_OUT_SW_BUF_SZ); #endif #if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_OUT_SW_BUF_SZ > 0 - TUD_EPBUF_DEF(buf_3, CFG_TUD_AUDIO_FUNC_3_EP_OUT_SW_BUF_SZ); + TUD_EPBUF_DEF(buf_3, CFG_TUD_AUDIO_FUNC_3_EP_OUT_SW_BUF_SZ); #endif } ep_out_sw_buf; #if CFG_FIFO_MUTEX #if CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ > 0 - tu_static osal_mutex_def_t ep_out_ff_mutex_rd_1; + tu_static osal_mutex_def_t ep_out_ff_mutex_rd_1; #endif #if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_OUT_SW_BUF_SZ > 0 - tu_static osal_mutex_def_t ep_out_ff_mutex_rd_2; + tu_static osal_mutex_def_t ep_out_ff_mutex_rd_2; #endif #if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_OUT_SW_BUF_SZ > 0 - tu_static osal_mutex_def_t ep_out_ff_mutex_rd_3; + tu_static osal_mutex_def_t ep_out_ff_mutex_rd_3; #endif #endif -#endif // CFG_TUD_AUDIO_ENABLE_EP_OUT && !CFG_TUD_AUDIO_ENABLE_DECODING +#endif// CFG_TUD_AUDIO_ENABLE_EP_OUT && !CFG_TUD_AUDIO_ENABLE_DECODING // Linear buffer RX in case: // - target MCU is not capable of handling a ring buffer FIFO e.g. no hardware buffer is available or driver is would need to be changed dramatically OR @@ -196,16 +196,16 @@ tu_static OUT_SW_BUF_MEM_ATTR struct { #if CFG_TUD_AUDIO_ENABLE_EP_OUT && (USE_LINEAR_BUFFER || CFG_TUD_AUDIO_ENABLE_DECODING) tu_static CFG_TUD_MEM_SECTION struct { #if CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX > 0 - TUD_EPBUF_DEF(buf_1, CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX); + TUD_EPBUF_DEF(buf_1, CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX); #endif #if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_OUT_SZ_MAX > 0 - TUD_EPBUF_DEF(buf_2, CFG_TUD_AUDIO_FUNC_2_EP_OUT_SZ_MAX); + TUD_EPBUF_DEF(buf_2, CFG_TUD_AUDIO_FUNC_2_EP_OUT_SZ_MAX); #endif #if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_OUT_SZ_MAX > 0 - TUD_EPBUF_DEF(buf_3, CFG_TUD_AUDIO_FUNC_3_EP_OUT_SZ_MAX); + TUD_EPBUF_DEF(buf_3, CFG_TUD_AUDIO_FUNC_3_EP_OUT_SZ_MAX); #endif } lin_buf_out; -#endif // CFG_TUD_AUDIO_ENABLE_EP_OUT && (USE_LINEAR_BUFFER || CFG_TUD_AUDIO_ENABLE_DECODING) +#endif// CFG_TUD_AUDIO_ENABLE_EP_OUT && (USE_LINEAR_BUFFER || CFG_TUD_AUDIO_ENABLE_DECODING) // Control buffers tu_static uint8_t ctrl_buf_1[CFG_TUD_AUDIO_FUNC_1_CTRL_BUF_SZ]; @@ -235,7 +235,7 @@ tu_static uint8_t alt_setting_3[CFG_TUD_AUDIO_FUNC_3_N_AS_INT]; tu_static TU_ATTR_ALIGNED(4) 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_static tu_fifo_t tx_supp_ff_1[CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO]; #if CFG_FIFO_MUTEX - tu_static 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 + tu_static 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 #endif #endif @@ -243,7 +243,7 @@ tu_static uint8_t alt_setting_3[CFG_TUD_AUDIO_FUNC_3_N_AS_INT]; tu_static TU_ATTR_ALIGNED(4) 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_static tu_fifo_t tx_supp_ff_2[CFG_TUD_AUDIO_FUNC_2_N_TX_SUPP_SW_FIFO]; #if CFG_FIFO_MUTEX - tu_static 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 + tu_static 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 #endif #endif @@ -251,7 +251,7 @@ tu_static uint8_t alt_setting_3[CFG_TUD_AUDIO_FUNC_3_N_AS_INT]; tu_static TU_ATTR_ALIGNED(4) 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_static tu_fifo_t tx_supp_ff_3[CFG_TUD_AUDIO_FUNC_3_N_TX_SUPP_SW_FIFO]; #if CFG_FIFO_MUTEX - tu_static 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 + tu_static 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 #endif #endif #endif @@ -261,7 +261,7 @@ tu_static uint8_t alt_setting_3[CFG_TUD_AUDIO_FUNC_3_N_AS_INT]; tu_static TU_ATTR_ALIGNED(4) 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_static tu_fifo_t rx_supp_ff_1[CFG_TUD_AUDIO_FUNC_1_N_RX_SUPP_SW_FIFO]; #if CFG_FIFO_MUTEX - tu_static 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 + tu_static 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 #endif #endif @@ -269,7 +269,7 @@ tu_static uint8_t alt_setting_3[CFG_TUD_AUDIO_FUNC_3_N_AS_INT]; tu_static TU_ATTR_ALIGNED(4) 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_static tu_fifo_t rx_supp_ff_2[CFG_TUD_AUDIO_FUNC_2_N_RX_SUPP_SW_FIFO]; #if CFG_FIFO_MUTEX - tu_static 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 + tu_static 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 #endif #endif @@ -277,7 +277,7 @@ tu_static uint8_t alt_setting_3[CFG_TUD_AUDIO_FUNC_3_N_AS_INT]; tu_static TU_ATTR_ALIGNED(4) 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_static tu_fifo_t rx_supp_ff_3[CFG_TUD_AUDIO_FUNC_3_N_RX_SUPP_SW_FIFO]; #if CFG_FIFO_MUTEX - tu_static 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 + tu_static 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 #endif #endif #endif @@ -286,13 +286,13 @@ tu_static uint8_t alt_setting_3[CFG_TUD_AUDIO_FUNC_3_N_AS_INT]; #if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP tu_static CFG_TUD_MEM_SECTION struct { #if CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX > 0 - TUD_EPBUF_TYPE_DEF(uint32_t, buf_1); + TUD_EPBUF_TYPE_DEF(uint32_t, buf_1); #endif #if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_OUT_SZ_MAX > 0 - TUD_EPBUF_TYPE_DEF(uint32_t, buf_2); + TUD_EPBUF_TYPE_DEF(uint32_t, buf_2); #endif #if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_OUT_SZ_MAX > 0 - TUD_EPBUF_TYPE_DEF(uint32_t, buf_3); + TUD_EPBUF_TYPE_DEF(uint32_t, buf_3); #endif } fb_ep_buf; #endif @@ -300,80 +300,80 @@ tu_static CFG_TUD_MEM_SECTION struct { // Aligned buffer for interrupt EP #if CFG_TUD_AUDIO_ENABLE_INTERRUPT_EP tu_static CFG_TUD_MEM_SECTION struct { - TUD_EPBUF_DEF(buf, CFG_TUD_AUDIO_INTERRUPT_EP_SZ); + TUD_EPBUF_DEF(buf, CFG_TUD_AUDIO_INTERRUPT_EP_SZ); } int_ep_buf[CFG_TUD_AUDIO]; #endif typedef struct { uint8_t rhport; - uint8_t const * p_desc; // Pointer pointing to Standard AC Interface Descriptor(4.7.1) - Audio Control descriptor defining audio function + uint8_t const *p_desc;// Pointer pointing to Standard AC Interface Descriptor(4.7.1) - Audio Control descriptor defining audio function #if CFG_TUD_AUDIO_ENABLE_EP_IN - uint8_t ep_in; // TX audio data EP. - uint16_t ep_in_sz; // Current size of TX EP - uint8_t ep_in_as_intf_num; // Corresponding Standard AS Interface Descriptor (4.9.1) belonging to output terminal to which this EP belongs - 0 is invalid (this fits to UAC2 specification since AS interfaces can not have interface number equal to zero) + uint8_t ep_in; // TX audio data EP. + uint16_t ep_in_sz; // Current size of TX EP + uint8_t ep_in_as_intf_num;// Corresponding Standard AS Interface Descriptor (4.9.1) belonging to output terminal to which this EP belongs - 0 is invalid (this fits to UAC2 specification since AS interfaces can not have interface number equal to zero) #endif #if CFG_TUD_AUDIO_ENABLE_EP_OUT - uint8_t ep_out; // Incoming (into uC) audio data EP. - uint16_t ep_out_sz; // Current size of RX EP - uint8_t ep_out_as_intf_num; // Corresponding Standard AS Interface Descriptor (4.9.1) belonging to input terminal to which this EP belongs - 0 is invalid (this fits to UAC2 specification since AS interfaces can not have interface number equal to zero) + uint8_t ep_out; // Incoming (into uC) audio data EP. + uint16_t ep_out_sz; // Current size of RX EP + uint8_t ep_out_as_intf_num;// Corresponding Standard AS Interface Descriptor (4.9.1) belonging to input terminal to which this EP belongs - 0 is invalid (this fits to UAC2 specification since AS interfaces can not have interface number equal to zero) -#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP - uint8_t ep_fb; // Feedback EP. -#endif + #if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP + uint8_t ep_fb;// Feedback EP. + #endif #endif #if CFG_TUD_AUDIO_ENABLE_INTERRUPT_EP - uint8_t ep_int; // Audio control interrupt EP. + uint8_t ep_int;// Audio control interrupt EP. #endif - bool mounted; // Device opened + bool mounted;// Device opened - uint16_t desc_length; // Length of audio function descriptor + uint16_t desc_length;// Length of audio function descriptor #if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP struct { - uint32_t value; // Feedback value for asynchronous mode (in 16.16 format). - uint32_t min_value; // min value according to UAC2 FMT-2.0 section 2.3.1.1. - uint32_t max_value; // max value according to UAC2 FMT-2.0 section 2.3.1.1. + uint32_t value; // Feedback value for asynchronous mode (in 16.16 format). + uint32_t min_value;// min value according to UAC2 FMT-2.0 section 2.3.1.1. + uint32_t max_value;// max value according to UAC2 FMT-2.0 section 2.3.1.1. - uint8_t frame_shift; // bInterval-1 in unit of frame (FS), micro-frame (HS) + uint8_t frame_shift;// bInterval-1 in unit of frame (FS), micro-frame (HS) uint8_t compute_method; bool format_correction; union { - uint8_t power_of_2; // pre-computed power of 2 shift - float float_const; // pre-computed float constant + uint8_t power_of_2;// pre-computed power of 2 shift + float float_const; // pre-computed float constant struct { uint32_t sample_freq; uint32_t mclk_freq; - }fixed; + } fixed; struct { - uint32_t nom_value; // In 16.16 format - uint32_t fifo_lvl_avg; // In 16.16 format - uint16_t fifo_lvl_thr; // fifo level threshold - uint16_t rate_const[2]; // pre-computed feedback/fifo_depth rate - }fifo_count; - }compute; + uint32_t nom_value; // In 16.16 format + uint32_t fifo_lvl_avg; // In 16.16 format + uint16_t fifo_lvl_thr; // fifo level threshold + uint16_t rate_const[2];// pre-computed feedback/fifo_depth rate + } fifo_count; + } compute; } feedback; -#endif // CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP +#endif// CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP - // Decoding parameters - parameters are set when alternate AS interface is set by host - // Coding is currently only supported for EP. Software coding corresponding to AS interfaces without EPs are not supported currently. +// Decoding parameters - parameters are set when alternate AS interface is set by host +// Coding is currently only supported for EP. Software coding corresponding to AS interfaces without EPs are not supported currently. #if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_DECODING audio_format_type_t format_type_rx; uint8_t n_channels_rx; -#if CFG_TUD_AUDIO_ENABLE_TYPE_I_DECODING + #if CFG_TUD_AUDIO_ENABLE_TYPE_I_DECODING audio_data_format_type_I_t format_type_I_rx; uint8_t n_bytes_per_sample_rx; uint8_t n_ff_used_rx; -#endif + #endif #endif #if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_EP_IN_FLOW_CONTROL @@ -383,28 +383,28 @@ typedef struct uint8_t interval_tx; #endif - // Encoding parameters - parameters are set when alternate AS interface is set by host +// 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 || CFG_TUD_AUDIO_EP_IN_FLOW_CONTROL) audio_format_type_t format_type_tx; uint8_t n_channels_tx; uint8_t n_bytes_per_sample_tx; -#if CFG_TUD_AUDIO_ENABLE_TYPE_I_ENCODING + #if CFG_TUD_AUDIO_ENABLE_TYPE_I_ENCODING audio_data_format_type_I_t format_type_I_tx; uint8_t n_ff_used_tx; -#endif + #endif #endif /*------------- From this point, data is not cleared by bus reset -------------*/ // Buffer for control requests - uint8_t * ctrl_buf; + uint8_t *ctrl_buf; uint8_t ctrl_buf_sz; // Current active alternate settings - uint8_t * alt_setting; // We need to save the current alternate setting this way, because it is possible that there are AS interfaces which do not have an EP! + uint8_t *alt_setting;// We need to save the current alternate setting this way, because it is possible that there are AS interfaces which do not have an EP! - // EP Transfer buffers and FIFOs +// EP Transfer buffers and FIFOs #if CFG_TUD_AUDIO_ENABLE_EP_OUT && !CFG_TUD_AUDIO_ENABLE_DECODING tu_fifo_t ep_out_ff; #endif @@ -413,50 +413,50 @@ typedef struct tu_fifo_t ep_in_ff; #endif - // Support FIFOs for software encoding and decoding +// Support FIFOs for software encoding and decoding #if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_DECODING - tu_fifo_t * rx_supp_ff; + tu_fifo_t *rx_supp_ff; uint8_t n_rx_supp_ff; uint16_t rx_supp_ff_sz_max; -#if CFG_TUD_AUDIO_ENABLE_TYPE_I_DECODING + #if CFG_TUD_AUDIO_ENABLE_TYPE_I_DECODING uint8_t n_channels_per_ff_rx; -#endif + #endif #endif #if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_ENCODING - tu_fifo_t * tx_supp_ff; + tu_fifo_t *tx_supp_ff; uint8_t n_tx_supp_ff; uint16_t tx_supp_ff_sz_max; -#if CFG_TUD_AUDIO_ENABLE_TYPE_I_ENCODING + #if CFG_TUD_AUDIO_ENABLE_TYPE_I_ENCODING uint8_t n_channels_per_ff_tx; -#endif + #endif #endif - // Linear buffer in case target MCU is not capable of handling a ring buffer FIFO e.g. no hardware buffer is available or driver is would need to be changed dramatically OR the support FIFOs are used +// Linear buffer in case target MCU is not capable of handling a ring buffer FIFO e.g. no hardware buffer is available or driver is would need to be changed dramatically OR the support FIFOs are used #if CFG_TUD_AUDIO_ENABLE_EP_OUT && (USE_LINEAR_BUFFER || CFG_TUD_AUDIO_ENABLE_DECODING) - uint8_t * lin_buf_out; -#define USE_LINEAR_BUFFER_RX 1 + uint8_t *lin_buf_out; + #define USE_LINEAR_BUFFER_RX 1 #endif #if CFG_TUD_AUDIO_ENABLE_EP_IN && (USE_LINEAR_BUFFER || CFG_TUD_AUDIO_ENABLE_ENCODING) - uint8_t * lin_buf_in; -#define USE_LINEAR_BUFFER_TX 1 + uint8_t *lin_buf_in; + #define USE_LINEAR_BUFFER_TX 1 #endif #if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP - uint32_t * fb_buf; + uint32_t *fb_buf; #endif } audiod_function_t; #ifndef USE_LINEAR_BUFFER_TX -#define USE_LINEAR_BUFFER_TX 0 + #define USE_LINEAR_BUFFER_TX 0 #endif #ifndef USE_LINEAR_BUFFER_RX -#define USE_LINEAR_BUFFER_RX 0 + #define USE_LINEAR_BUFFER_RX 0 #endif -#define ITF_MEM_RESET_SIZE offsetof(audiod_function_t, ctrl_buf) +#define ITF_MEM_RESET_SIZE offsetof(audiod_function_t, ctrl_buf) //--------------------------------------------------------------------+ // WEAK FUNCTION STUBS @@ -506,7 +506,7 @@ TU_ATTR_WEAK void tud_audio_fb_done_cb(uint8_t func_id) { (void) func_id; } -TU_ATTR_WEAK void tud_audio_feedback_params_cb(uint8_t func_id, uint8_t alt_itf, audio_feedback_params_t* feedback_param) { +TU_ATTR_WEAK void tud_audio_feedback_params_cb(uint8_t func_id, uint8_t alt_itf, audio_feedback_params_t *feedback_param) { (void) func_id; (void) alt_itf; feedback_param->method = AUDIO_FEEDBACK_METHOD_DISABLED; @@ -531,68 +531,68 @@ TU_ATTR_WEAK void tud_audio_int_done_cb(uint8_t rhport) { #endif // Invoked when audio set interface request received -TU_ATTR_WEAK bool tud_audio_set_itf_cb(uint8_t rhport, tusb_control_request_t const * p_request) { +TU_ATTR_WEAK bool tud_audio_set_itf_cb(uint8_t rhport, tusb_control_request_t const *p_request) { (void) rhport; (void) p_request; return true; } // Invoked when audio set interface request received which closes an EP -TU_ATTR_WEAK bool tud_audio_set_itf_close_EP_cb(uint8_t rhport, tusb_control_request_t const * p_request) { +TU_ATTR_WEAK bool tud_audio_set_itf_close_EP_cb(uint8_t rhport, tusb_control_request_t const *p_request) { (void) rhport; (void) p_request; return true; } // Invoked when audio class specific set request received for an EP -TU_ATTR_WEAK bool tud_audio_set_req_ep_cb(uint8_t rhport, tusb_control_request_t const * p_request, uint8_t *pBuff) { +TU_ATTR_WEAK bool tud_audio_set_req_ep_cb(uint8_t rhport, tusb_control_request_t const *p_request, uint8_t *pBuff) { (void) rhport; (void) p_request; (void) pBuff; TU_LOG2(" No EP set request callback available!\r\n"); - return false; // In case no callback function is present or request can not be conducted we stall it + return false;// In case no callback function is present or request can not be conducted we stall it } // Invoked when audio class specific set request received for an interface -TU_ATTR_WEAK bool tud_audio_set_req_itf_cb(uint8_t rhport, tusb_control_request_t const * p_request, uint8_t *pBuff) { +TU_ATTR_WEAK bool tud_audio_set_req_itf_cb(uint8_t rhport, tusb_control_request_t const *p_request, uint8_t *pBuff) { (void) rhport; (void) p_request; (void) pBuff; TU_LOG2(" No interface set request callback available!\r\n"); - return false; // In case no callback function is present or request can not be conducted we stall it + return false;// In case no callback function is present or request can not be conducted we stall it } // Invoked when audio class specific set request received for an entity -TU_ATTR_WEAK bool tud_audio_set_req_entity_cb(uint8_t rhport, tusb_control_request_t const * p_request, uint8_t *pBuff) { +TU_ATTR_WEAK bool tud_audio_set_req_entity_cb(uint8_t rhport, tusb_control_request_t const *p_request, uint8_t *pBuff) { (void) rhport; (void) p_request; (void) pBuff; TU_LOG2(" No entity set request callback available!\r\n"); - return false; // In case no callback function is present or request can not be conducted we stall it + return false;// In case no callback function is present or request can not be conducted we stall it } // Invoked when audio class specific get request received for an EP -TU_ATTR_WEAK bool tud_audio_get_req_ep_cb(uint8_t rhport, tusb_control_request_t const * p_request) { +TU_ATTR_WEAK bool tud_audio_get_req_ep_cb(uint8_t rhport, tusb_control_request_t const *p_request) { (void) rhport; (void) p_request; TU_LOG2(" No EP get request callback available!\r\n"); - return false; // Stall + return false;// Stall } // Invoked when audio class specific get request received for an interface -TU_ATTR_WEAK bool tud_audio_get_req_itf_cb(uint8_t rhport, tusb_control_request_t const * p_request) { +TU_ATTR_WEAK bool tud_audio_get_req_itf_cb(uint8_t rhport, tusb_control_request_t const *p_request) { (void) rhport; (void) p_request; TU_LOG2(" No interface get request callback available!\r\n"); - return false; // Stall + return false;// Stall } // Invoked when audio class specific get request received for an entity -TU_ATTR_WEAK bool tud_audio_get_req_entity_cb(uint8_t rhport, tusb_control_request_t const * p_request) { +TU_ATTR_WEAK bool tud_audio_get_req_entity_cb(uint8_t rhport, tusb_control_request_t const *p_request) { (void) rhport; (void) p_request; TU_LOG2(" No entity get request callback available!\r\n"); - return false; // Stall + return false;// Stall } //--------------------------------------------------------------------+ @@ -601,54 +601,52 @@ TU_ATTR_WEAK bool tud_audio_get_req_entity_cb(uint8_t rhport, tusb_control_reque tu_static CFG_TUD_MEM_SECTION audiod_function_t _audiod_fct[CFG_TUD_AUDIO]; #if CFG_TUD_AUDIO_ENABLE_EP_OUT -static bool audiod_rx_done_cb(uint8_t rhport, audiod_function_t* audio, uint16_t n_bytes_received); +static bool audiod_rx_done_cb(uint8_t rhport, audiod_function_t *audio, uint16_t n_bytes_received); #endif #if CFG_TUD_AUDIO_ENABLE_DECODING && CFG_TUD_AUDIO_ENABLE_EP_OUT -static bool audiod_decode_type_I_pcm(uint8_t rhport, audiod_function_t* audio, uint16_t n_bytes_received); +static bool audiod_decode_type_I_pcm(uint8_t rhport, audiod_function_t *audio, uint16_t n_bytes_received); #endif #if CFG_TUD_AUDIO_ENABLE_EP_IN -static bool audiod_tx_done_cb(uint8_t rhport, audiod_function_t* audio); +static bool audiod_tx_done_cb(uint8_t rhport, audiod_function_t *audio); #endif #if CFG_TUD_AUDIO_ENABLE_ENCODING && CFG_TUD_AUDIO_ENABLE_EP_IN -static uint16_t audiod_encode_type_I_pcm(uint8_t rhport, audiod_function_t* audio); +static uint16_t audiod_encode_type_I_pcm(uint8_t rhport, audiod_function_t *audio); #endif -static bool audiod_get_interface(uint8_t rhport, tusb_control_request_t const * p_request); -static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const * p_request); +static bool audiod_get_interface(uint8_t rhport, tusb_control_request_t const *p_request); +static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const *p_request); static bool audiod_get_AS_interface_index_global(uint8_t itf, uint8_t *func_id, uint8_t *idxItf, uint8_t const **pp_desc_int); -static bool audiod_get_AS_interface_index(uint8_t itf, audiod_function_t * audio, uint8_t *idxItf, uint8_t const **pp_desc_int); +static bool audiod_get_AS_interface_index(uint8_t itf, audiod_function_t *audio, uint8_t *idxItf, uint8_t const **pp_desc_int); static bool audiod_verify_entity_exists(uint8_t itf, uint8_t entityID, uint8_t *func_id); 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); +static uint8_t audiod_get_audio_fct_idx(audiod_function_t *audio); #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 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) -{ - return ((uint8_t const*) desc)[2]; +static inline uint8_t tu_desc_subtype(void const *desc) { + return ((uint8_t const *) desc)[2]; } #endif #if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_EP_IN_FLOW_CONTROL -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); +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 -static bool audiod_set_fb_params_freq(audiod_function_t* audio, uint32_t sample_freq, uint32_t mclk_freq); -static void audiod_fb_fifo_count_update(audiod_function_t* audio, uint16_t lvl_new); +static bool audiod_set_fb_params_freq(audiod_function_t *audio, uint32_t sample_freq, uint32_t mclk_freq); +static void audiod_fb_fifo_count_update(audiod_function_t *audio, uint16_t lvl_new); #endif -bool tud_audio_n_mounted(uint8_t func_id) -{ +bool tud_audio_n_mounted(uint8_t func_id) { TU_VERIFY(func_id < CFG_TUD_AUDIO); - audiod_function_t* audio = &_audiod_fct[func_id]; + audiod_function_t *audio = &_audiod_fct[func_id]; return audio->mounted; } @@ -659,27 +657,23 @@ bool tud_audio_n_mounted(uint8_t func_id) #if CFG_TUD_AUDIO_ENABLE_EP_OUT && !CFG_TUD_AUDIO_ENABLE_DECODING -uint16_t tud_audio_n_available(uint8_t func_id) -{ +uint16_t tud_audio_n_available(uint8_t func_id) { TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL); return tu_fifo_count(&_audiod_fct[func_id].ep_out_ff); } -uint16_t tud_audio_n_read(uint8_t func_id, void* buffer, uint16_t bufsize) -{ +uint16_t tud_audio_n_read(uint8_t func_id, void *buffer, uint16_t bufsize) { TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL); return tu_fifo_read_n(&_audiod_fct[func_id].ep_out_ff, buffer, bufsize); } -bool tud_audio_n_clear_ep_out_ff(uint8_t func_id) -{ +bool tud_audio_n_clear_ep_out_ff(uint8_t func_id) { TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL); return tu_fifo_clear(&_audiod_fct[func_id].ep_out_ff); } -tu_fifo_t* tud_audio_n_get_ep_out_ff(uint8_t func_id) -{ - if(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL) return &_audiod_fct[func_id].ep_out_ff; +tu_fifo_t *tud_audio_n_get_ep_out_ff(uint8_t func_id) { + if (func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL) return &_audiod_fct[func_id].ep_out_ff; return NULL; } @@ -687,27 +681,23 @@ tu_fifo_t* tud_audio_n_get_ep_out_ff(uint8_t func_id) #if CFG_TUD_AUDIO_ENABLE_DECODING && CFG_TUD_AUDIO_ENABLE_EP_OUT // Delete all content in the support RX FIFOs -bool tud_audio_n_clear_rx_support_ff(uint8_t func_id, uint8_t ff_idx) -{ +bool tud_audio_n_clear_rx_support_ff(uint8_t func_id, uint8_t ff_idx) { TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL && ff_idx < _audiod_fct[func_id].n_rx_supp_ff); return tu_fifo_clear(&_audiod_fct[func_id].rx_supp_ff[ff_idx]); } -uint16_t tud_audio_n_available_support_ff(uint8_t func_id, uint8_t ff_idx) -{ +uint16_t tud_audio_n_available_support_ff(uint8_t func_id, uint8_t ff_idx) { TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL && ff_idx < _audiod_fct[func_id].n_rx_supp_ff); return tu_fifo_count(&_audiod_fct[func_id].rx_supp_ff[ff_idx]); } -uint16_t tud_audio_n_read_support_ff(uint8_t func_id, uint8_t ff_idx, void* buffer, uint16_t bufsize) -{ +uint16_t tud_audio_n_read_support_ff(uint8_t func_id, uint8_t ff_idx, void *buffer, uint16_t bufsize) { TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL && ff_idx < _audiod_fct[func_id].n_rx_supp_ff); return tu_fifo_read_n(&_audiod_fct[func_id].rx_supp_ff[ff_idx], buffer, bufsize); } -tu_fifo_t* tud_audio_n_get_rx_support_ff(uint8_t func_id, uint8_t ff_idx) -{ - if(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL && ff_idx < _audiod_fct[func_id].n_rx_supp_ff) return &_audiod_fct[func_id].rx_supp_ff[ff_idx]; +tu_fifo_t *tud_audio_n_get_rx_support_ff(uint8_t func_id, uint8_t ff_idx) { + if (func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL && ff_idx < _audiod_fct[func_id].n_rx_supp_ff) return &_audiod_fct[func_id].rx_supp_ff[ff_idx]; return NULL; } #endif @@ -717,8 +707,7 @@ tu_fifo_t* tud_audio_n_get_rx_support_ff(uint8_t func_id, uint8_t ff_idx) #if CFG_TUD_AUDIO_ENABLE_EP_OUT -static bool audiod_rx_done_cb(uint8_t rhport, audiod_function_t* audio, uint16_t n_bytes_received) -{ +static bool audiod_rx_done_cb(uint8_t rhport, audiod_function_t *audio, uint16_t n_bytes_received) { uint8_t idxItf = 0; uint8_t const *dummy2; uint8_t idx_audio_fct = 0; @@ -729,10 +718,9 @@ static bool audiod_rx_done_cb(uint8_t rhport, audiod_function_t* audio, uint16_t // Call a weak callback here - a possibility for user to get informed an audio packet was received and data gets now loaded into EP FIFO (or decoded into support RX software FIFO) TU_VERIFY(tud_audio_rx_done_pre_read_cb(rhport, n_bytes_received, idx_audio_fct, audio->ep_out, audio->alt_setting[idxItf])); -#if CFG_TUD_AUDIO_ENABLE_DECODING + #if CFG_TUD_AUDIO_ENABLE_DECODING - switch (audio->format_type_rx) - { + switch (audio->format_type_rx) { case AUDIO_FORMAT_TYPE_UNDEFINED: // INDIVIDUAL DECODING PROCEDURE REQUIRED HERE! TU_LOG2(" Desired CFG_TUD_AUDIO_FORMAT encoding not implemented!\r\n"); @@ -741,8 +729,7 @@ static bool audiod_rx_done_cb(uint8_t rhport, audiod_function_t* audio, uint16_t case AUDIO_FORMAT_TYPE_I: - switch (audio->format_type_I_rx) - { + switch (audio->format_type_I_rx) { case AUDIO_DATA_FORMAT_TYPE_I_PCM: TU_VERIFY(audiod_decode_type_I_pcm(rhport, audio, n_bytes_received)); break; @@ -755,37 +742,36 @@ static bool audiod_rx_done_cb(uint8_t rhport, audiod_function_t* audio, uint16_t } break; - default: - // Desired CFG_TUD_AUDIO_FORMAT_TYPE_RX not implemented! - TU_LOG2(" Desired CFG_TUD_AUDIO_FORMAT_TYPE_RX not implemented!\r\n"); - TU_BREAKPOINT(); - break; + default: + // Desired CFG_TUD_AUDIO_FORMAT_TYPE_RX not implemented! + TU_LOG2(" Desired CFG_TUD_AUDIO_FORMAT_TYPE_RX not implemented!\r\n"); + TU_BREAKPOINT(); + break; } // Prepare for next transmission TU_VERIFY(usbd_edpt_xfer(rhport, audio->ep_out, audio->lin_buf_out, audio->ep_out_sz), false); -#else + #else -#if USE_LINEAR_BUFFER_RX + #if USE_LINEAR_BUFFER_RX // Data currently is in linear buffer, copy into EP OUT FIFO TU_VERIFY(tu_fifo_write_n(&audio->ep_out_ff, audio->lin_buf_out, n_bytes_received)); // Schedule for next receive TU_VERIFY(usbd_edpt_xfer(rhport, audio->ep_out, audio->lin_buf_out, audio->ep_out_sz), false); -#else + #else // Data is already placed in EP FIFO, schedule for next receive TU_VERIFY(usbd_edpt_xfer_fifo(rhport, audio->ep_out, &audio->ep_out_ff, audio->ep_out_sz), false); -#endif + #endif -#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP - if(audio->feedback.compute_method == AUDIO_FEEDBACK_METHOD_FIFO_COUNT) - { + #if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP + if (audio->feedback.compute_method == AUDIO_FEEDBACK_METHOD_FIFO_COUNT) { audiod_fb_fifo_count_update(audio, tu_fifo_count(&audio->ep_out_ff)); } -#endif + #endif -#endif + #endif // Call a weak callback here - a possibility for user to get informed decoding was completed TU_VERIFY(tud_audio_rx_done_post_read_cb(rhport, n_bytes_received, idx_audio_fct, audio->ep_out, audio->alt_setting[idxItf])); @@ -793,7 +779,7 @@ static bool audiod_rx_done_cb(uint8_t rhport, audiod_function_t* audio, uint16_t return true; } -#endif //CFG_TUD_AUDIO_ENABLE_EP_OUT +#endif//CFG_TUD_AUDIO_ENABLE_EP_OUT // The following functions are used in case CFG_TUD_AUDIO_ENABLE_DECODING != 0 #if CFG_TUD_AUDIO_ENABLE_DECODING && CFG_TUD_AUDIO_ENABLE_EP_OUT @@ -801,49 +787,38 @@ 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 nBytesPerSample, 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 (nBytesPerSample * 2) - 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 (nBytesPerSample == 1) - { - while(dst16 < dst_end16) - { + 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 (nBytesPerSample == 1) { + while (dst16 < dst_end16) { *dst16++ = *src16++; src16 += n_ff_used - 1; } return src16; - } - else if (nBytesPerSample == 2) - { - while(dst32 < dst_end32) - { + } else if (nBytesPerSample == 2) { + while (dst32 < dst_end32) { *dst32++ = *src32++; src32 += n_ff_used - 1; } return src32; - } - else if (nBytesPerSample == 3) - { - while(dst16 < dst_end16) - { + } else if (nBytesPerSample == 3) { + while (dst16 < dst_end16) { *dst16++ = *src16++; *dst16++ = *src16++; *dst16++ = *src16++; src16 += 3 * (n_ff_used - 1); } return src16; - } - else // nBytesPerSample == 4 + } else// nBytesPerSample == 4 { - while(dst32 < dst_end32) - { + while (dst32 < dst_end32) { *dst32++ = *src32++; *dst32++ = *src32++; src32 += 2 * (n_ff_used - 1); @@ -852,36 +827,32 @@ static inline void * audiod_interleaved_copy_bytes_fast_decode(uint16_t const nB } } -static bool audiod_decode_type_I_pcm(uint8_t rhport, audiod_function_t* audio, uint16_t n_bytes_received) -{ +static bool audiod_decode_type_I_pcm(uint8_t rhport, audiod_function_t *audio, uint16_t n_bytes_received) { (void) rhport; // Determine amount of samples - uint8_t const n_ff_used = audio->n_ff_used_rx; - uint16_t const nBytesPerFFToRead = n_bytes_received / n_ff_used; + uint8_t const n_ff_used = audio->n_ff_used_rx; + uint16_t const nBytesPerFFToRead = n_bytes_received / n_ff_used; uint8_t cnt_ff; // Decode - uint8_t * src; - uint8_t * dst_end; + uint8_t *src; + uint8_t *dst_end; tu_fifo_buffer_info_t info; - for (cnt_ff = 0; cnt_ff < n_ff_used; cnt_ff++) - { + for (cnt_ff = 0; cnt_ff < n_ff_used; cnt_ff++) { tu_fifo_get_write_info(&audio->rx_supp_ff[cnt_ff], &info); - if (info.len_lin != 0) - { + if (info.len_lin != 0) { info.len_lin = tu_min16(nBytesPerFFToRead, info.len_lin); - src = &audio->lin_buf_out[cnt_ff*audio->n_channels_per_ff_rx * audio->n_bytes_per_sample_rx]; + src = &audio->lin_buf_out[cnt_ff * audio->n_channels_per_ff_rx * audio->n_bytes_per_sample_rx]; dst_end = info.ptr_lin + info.len_lin; src = audiod_interleaved_copy_bytes_fast_decode(audio->n_bytes_per_sample_rx, info.ptr_lin, dst_end, src, n_ff_used); // Handle wrapped part of FIFO info.len_wrap = tu_min16(nBytesPerFFToRead - info.len_lin, info.len_wrap); - if (info.len_wrap != 0) - { + if (info.len_wrap != 0) { dst_end = info.ptr_wrap + info.len_wrap; audiod_interleaved_copy_bytes_fast_decode(audio->n_bytes_per_sample_rx, info.ptr_wrap, dst_end, src, n_ff_used); } @@ -892,16 +863,15 @@ static bool audiod_decode_type_I_pcm(uint8_t rhport, audiod_function_t* audio, u // Number of bytes should be a multiple of CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX * CFG_TUD_AUDIO_N_CHANNELS_RX but checking makes no sense - no way to correct it // TU_VERIFY(cnt != n_bytes); -#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP - if(audio->feedback.compute_method == AUDIO_FEEDBACK_METHOD_FIFO_COUNT) - { + #if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP + if (audio->feedback.compute_method == AUDIO_FEEDBACK_METHOD_FIFO_COUNT) { audiod_fb_fifo_count_update(audio, tu_fifo_count(&audio->rx_supp_ff[0])); } -#endif + #endif return true; } -#endif //CFG_TUD_AUDIO_ENABLE_DECODING +#endif//CFG_TUD_AUDIO_ENABLE_DECODING //--------------------------------------------------------------------+ // WRITE API @@ -920,21 +890,19 @@ static bool audiod_decode_type_I_pcm(uint8_t rhport, audiod_function_t* audio, u * \param[in] len: # of array elements to copy * \return Number of bytes actually written */ -uint16_t tud_audio_n_write(uint8_t func_id, const void * data, uint16_t len) -{ +uint16_t tud_audio_n_write(uint8_t func_id, const void *data, uint16_t len) { TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL); return tu_fifo_write_n(&_audiod_fct[func_id].ep_in_ff, data, len); } -bool tud_audio_n_clear_ep_in_ff(uint8_t func_id) // Delete all content in the EP IN FIFO +bool tud_audio_n_clear_ep_in_ff(uint8_t func_id)// Delete all content in the EP IN FIFO { TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL); return tu_fifo_clear(&_audiod_fct[func_id].ep_in_ff); } -tu_fifo_t* tud_audio_n_get_ep_in_ff(uint8_t func_id) -{ - if(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL) return &_audiod_fct[func_id].ep_in_ff; +tu_fifo_t *tud_audio_n_get_ep_in_ff(uint8_t func_id) { + if (func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL) return &_audiod_fct[func_id].ep_in_ff; return NULL; } @@ -942,36 +910,33 @@ tu_fifo_t* tud_audio_n_get_ep_in_ff(uint8_t func_id) #if CFG_TUD_AUDIO_ENABLE_ENCODING && CFG_TUD_AUDIO_ENABLE_EP_IN -uint16_t tud_audio_n_flush_tx_support_ff(uint8_t func_id) // Force all content in the support TX FIFOs to be written into linear buffer and schedule a transmit +uint16_t tud_audio_n_flush_tx_support_ff(uint8_t func_id)// Force all content in the support TX FIFOs to be written into linear buffer and schedule a transmit { TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL); - audiod_function_t* audio = &_audiod_fct[func_id]; + audiod_function_t *audio = &_audiod_fct[func_id]; uint16_t n_bytes_copied = tu_fifo_count(&audio->tx_supp_ff[0]); TU_VERIFY(audiod_tx_done_cb(audio->rhport, audio)); n_bytes_copied -= tu_fifo_count(&audio->tx_supp_ff[0]); - n_bytes_copied = n_bytes_copied*audio->tx_supp_ff[0].item_size; + n_bytes_copied = n_bytes_copied * audio->tx_supp_ff[0].item_size; return n_bytes_copied; } -bool tud_audio_n_clear_tx_support_ff(uint8_t func_id, uint8_t ff_idx) -{ +bool tud_audio_n_clear_tx_support_ff(uint8_t func_id, uint8_t ff_idx) { TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL && ff_idx < _audiod_fct[func_id].n_tx_supp_ff); return tu_fifo_clear(&_audiod_fct[func_id].tx_supp_ff[ff_idx]); } -uint16_t tud_audio_n_write_support_ff(uint8_t func_id, uint8_t ff_idx, const void * data, uint16_t len) -{ +uint16_t tud_audio_n_write_support_ff(uint8_t func_id, uint8_t ff_idx, const void *data, uint16_t len) { TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL && ff_idx < _audiod_fct[func_id].n_tx_supp_ff); return tu_fifo_write_n(&_audiod_fct[func_id].tx_supp_ff[ff_idx], data, len); } -tu_fifo_t* tud_audio_n_get_tx_support_ff(uint8_t func_id, uint8_t ff_idx) -{ - if(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL && ff_idx < _audiod_fct[func_id].n_tx_supp_ff) return &_audiod_fct[func_id].tx_supp_ff[ff_idx]; +tu_fifo_t *tud_audio_n_get_tx_support_ff(uint8_t func_id, uint8_t ff_idx) { + if (func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL && ff_idx < _audiod_fct[func_id].n_tx_supp_ff) return &_audiod_fct[func_id].tx_supp_ff[ff_idx]; return NULL; } @@ -980,8 +945,7 @@ 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 -bool tud_audio_int_n_write(uint8_t func_id, const audio_interrupt_data_t * data) -{ +bool tud_audio_int_n_write(uint8_t func_id, const audio_interrupt_data_t *data) { TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL); TU_VERIFY(_audiod_fct[func_id].ep_int != 0); @@ -990,12 +954,10 @@ bool tud_audio_int_n_write(uint8_t func_id, const audio_interrupt_data_t * data) TU_VERIFY(usbd_edpt_claim(_audiod_fct[func_id].rhport, _audiod_fct[func_id].ep_int)); // Check length - if (tu_memcpy_s(int_ep_buf[func_id].buf, sizeof(int_ep_buf[func_id].buf), data, sizeof(audio_interrupt_data_t)) == 0) - { + if (tu_memcpy_s(int_ep_buf[func_id].buf, sizeof(int_ep_buf[func_id].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, int_ep_buf[func_id].buf, sizeof(int_ep_buf[func_id].buf)), 0); - } else - { + } else { // Release endpoint since we don't make any transfer usbd_edpt_release(_audiod_fct[func_id].rhport, _audiod_fct[func_id].ep_int); } @@ -1009,8 +971,7 @@ bool tud_audio_int_n_write(uint8_t func_id, const audio_interrupt_data_t * data) // n_bytes_copied - Informs caller how many bytes were loaded. In case n_bytes_copied = 0, a ZLP is scheduled to inform host no data is available for current frame. #if CFG_TUD_AUDIO_ENABLE_EP_IN -static bool audiod_tx_done_cb(uint8_t rhport, audiod_function_t * audio) -{ +static bool audiod_tx_done_cb(uint8_t rhport, audiod_function_t *audio) { uint8_t idxItf; uint8_t const *dummy2; @@ -1028,9 +989,8 @@ static bool audiod_tx_done_cb(uint8_t rhport, audiod_function_t * audio) uint16_t n_bytes_tx; // If support FIFOs are used, encode and schedule transmit -#if CFG_TUD_AUDIO_ENABLE_ENCODING && CFG_TUD_AUDIO_ENABLE_EP_IN - switch (audio->format_type_tx) - { + #if CFG_TUD_AUDIO_ENABLE_ENCODING && CFG_TUD_AUDIO_ENABLE_EP_IN + switch (audio->format_type_tx) { case AUDIO_FORMAT_TYPE_UNDEFINED: // INDIVIDUAL ENCODING PROCEDURE REQUIRED HERE! TU_LOG2(" Desired CFG_TUD_AUDIO_FORMAT encoding not implemented!\r\n"); @@ -1040,8 +1000,7 @@ static bool audiod_tx_done_cb(uint8_t rhport, audiod_function_t * audio) case AUDIO_FORMAT_TYPE_I: - switch (audio->format_type_I_tx) - { + switch (audio->format_type_I_tx) { case AUDIO_DATA_FORMAT_TYPE_I_PCM: n_bytes_tx = audiod_encode_type_I_pcm(rhport, audio); @@ -1056,33 +1015,33 @@ static bool audiod_tx_done_cb(uint8_t rhport, audiod_function_t * audio) } break; - default: - // Desired CFG_TUD_AUDIO_FORMAT_TYPE_TX not implemented! - TU_LOG2(" Desired CFG_TUD_AUDIO_FORMAT_TYPE_TX not implemented!\r\n"); - TU_BREAKPOINT(); - n_bytes_tx = 0; - break; + default: + // Desired CFG_TUD_AUDIO_FORMAT_TYPE_TX not implemented! + TU_LOG2(" Desired CFG_TUD_AUDIO_FORMAT_TYPE_TX not implemented!\r\n"); + TU_BREAKPOINT(); + n_bytes_tx = 0; + break; } TU_VERIFY(usbd_edpt_xfer(rhport, audio->ep_in, audio->lin_buf_in, n_bytes_tx)); -#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 + #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 // packet_sz_tx is based on total packet size, here we want size for each support buffer. 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 -#if USE_LINEAR_BUFFER_TX + #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)); -#else + #else // Send everything in ISO EP FIFO TU_VERIFY(usbd_edpt_xfer_fifo(rhport, audio->ep_in, &audio->ep_in_ff, n_bytes_tx)); -#endif + #endif -#endif + #endif // Call a weak callback here - a possibility for user to get informed former TX was completed and how many bytes were loaded for the next frame TU_VERIFY(tud_audio_tx_done_post_load_cb(rhport, n_bytes_tx, idx_audio_fct, audio->ep_in, audio->alt_setting[idxItf])); @@ -1090,7 +1049,7 @@ static bool audiod_tx_done_cb(uint8_t rhport, audiod_function_t * audio) return true; } -#endif //CFG_TUD_AUDIO_ENABLE_EP_IN +#endif//CFG_TUD_AUDIO_ENABLE_EP_IN #if CFG_TUD_AUDIO_ENABLE_ENCODING && CFG_TUD_AUDIO_ENABLE_EP_IN // Take samples from the support buffer and encode them into the IN EP software FIFO @@ -1111,49 +1070,38 @@ range [-1, +1) * */ // Helper function -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) -{ +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 (nBytesPerSample * 2) - 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 (nBytesPerSample == 1) - { - while(src16 < src_end16) - { + 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 (nBytesPerSample == 1) { + while (src16 < src_end16) { *dst16++ = *src16++; dst16 += n_ff_used - 1; } return dst16; - } - else if (nBytesPerSample == 2) - { - while(src32 < src_end32) - { + } else if (nBytesPerSample == 2) { + while (src32 < src_end32) { *dst32++ = *src32++; dst32 += n_ff_used - 1; } return dst32; - } - else if (nBytesPerSample == 3) - { - while(src16 < src_end16) - { + } else if (nBytesPerSample == 3) { + while (src16 < src_end16) { *dst16++ = *src16++; *dst16++ = *src16++; *dst16++ = *src16++; dst16 += 3 * (n_ff_used - 1); } return dst16; - } - else // nBytesPerSample == 4 + } else// nBytesPerSample == 4 { - while(src32 < src_end32) - { + while (src32 < src_end32) { *dst32++ = *src32++; *dst32++ = *src32++; dst32 += 2 * (n_ff_used - 1); @@ -1162,8 +1110,7 @@ static inline void * audiod_interleaved_copy_bytes_fast_encode(uint16_t const nB } } -static uint16_t audiod_encode_type_I_pcm(uint8_t rhport, audiod_function_t* audio) -{ +static uint16_t audiod_encode_type_I_pcm(uint8_t rhport, audiod_function_t *audio) { // This function relies on the fact that the length of the support FIFOs was configured to be a multiple of the active sample size in bytes s.t. no sample is split within a wrap // This is ensured within set_interface, where the FIFOs are reconfigured according to this size @@ -1171,62 +1118,57 @@ static uint16_t audiod_encode_type_I_pcm(uint8_t rhport, audiod_function_t* audi TU_VERIFY(!usbd_edpt_busy(rhport, audio->ep_in)); // Determine amount of samples - uint8_t const n_ff_used = audio->n_ff_used_tx; - uint16_t nBytesPerFFToSend = tu_fifo_count(&audio->tx_supp_ff[0]); + uint8_t const n_ff_used = audio->n_ff_used_tx; + uint16_t nBytesPerFFToSend = tu_fifo_count(&audio->tx_supp_ff[0]); uint8_t cnt_ff; - for (cnt_ff = 1; cnt_ff < n_ff_used; cnt_ff++) - { + for (cnt_ff = 1; cnt_ff < n_ff_used; cnt_ff++) { uint16_t const count = tu_fifo_count(&audio->tx_supp_ff[cnt_ff]); - if (count < nBytesPerFFToSend) - { + if (count < nBytesPerFFToSend) { nBytesPerFFToSend = count; } } -#if CFG_TUD_AUDIO_EP_IN_FLOW_CONTROL + #if CFG_TUD_AUDIO_EP_IN_FLOW_CONTROL 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. 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 + if (nBytesPerFFToSend == 0) return 0; + #else // Check if there is enough data - if (nBytesPerFFToSend == 0) return 0; + 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, 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_sample_tx; nBytesPerFFToSend = (nBytesPerFFToSend / nSlotSize) * nSlotSize; -#endif + #endif // Encode - uint8_t * dst; - uint8_t * src_end; + uint8_t *dst; + uint8_t *src_end; tu_fifo_buffer_info_t info; - for (cnt_ff = 0; cnt_ff < n_ff_used; cnt_ff++) - { - dst = &audio->lin_buf_in[cnt_ff*audio->n_channels_per_ff_tx*audio->n_bytes_per_sample_tx]; + for (cnt_ff = 0; cnt_ff < n_ff_used; cnt_ff++) { + dst = &audio->lin_buf_in[cnt_ff * audio->n_channels_per_ff_tx * audio->n_bytes_per_sample_tx]; tu_fifo_get_read_info(&audio->tx_supp_ff[cnt_ff], &info); - if (info.len_lin != 0) - { - info.len_lin = tu_min16(nBytesPerFFToSend, info.len_lin); // Limit up to desired length - src_end = (uint8_t *)info.ptr_lin + info.len_lin; + if (info.len_lin != 0) { + info.len_lin = tu_min16(nBytesPerFFToSend, info.len_lin);// Limit up to desired length + src_end = (uint8_t *) info.ptr_lin + info.len_lin; dst = audiod_interleaved_copy_bytes_fast_encode(audio->n_bytes_per_sample_tx, info.ptr_lin, src_end, dst, n_ff_used); // Limit up to desired length info.len_wrap = tu_min16(nBytesPerFFToSend - info.len_lin, info.len_wrap); // Handle wrapped part of FIFO - if (info.len_wrap != 0) - { - src_end = (uint8_t *)info.ptr_wrap + info.len_wrap; + if (info.len_wrap != 0) { + src_end = (uint8_t *) info.ptr_wrap + info.len_wrap; audiod_interleaved_copy_bytes_fast_encode(audio->n_bytes_per_sample_tx, info.ptr_wrap, src_end, dst, n_ff_used); } @@ -1236,26 +1178,23 @@ static uint16_t audiod_encode_type_I_pcm(uint8_t rhport, audiod_function_t* audi return nBytesPerFFToSend * n_ff_used; } -#endif //CFG_TUD_AUDIO_ENABLE_ENCODING +#endif//CFG_TUD_AUDIO_ENABLE_ENCODING // This function is called once a transmit of a feedback packet was successfully completed. Here, we get the next feedback value to be sent #if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP -static inline bool audiod_fb_send(audiod_function_t *audio) -{ +static inline bool audiod_fb_send(audiod_function_t *audio) { bool apply_correction = (TUSB_SPEED_FULL == tud_speed_get()) && audio->feedback.format_correction; // Format the feedback value - if (apply_correction) - { - uint8_t * fb = (uint8_t *) audio->fb_buf; + if (apply_correction) { + uint8_t *fb = (uint8_t *) audio->fb_buf; // For FS format is 10.14 *(fb++) = (audio->feedback.value >> 2) & 0xFF; *(fb++) = (audio->feedback.value >> 10) & 0xFF; *(fb++) = (audio->feedback.value >> 18) & 0xFF; *fb = 0; - } else - { + } else { *audio->fb_buf = audio->feedback.value; } @@ -1279,17 +1218,14 @@ static inline bool audiod_fb_send(audiod_function_t *audio) //--------------------------------------------------------------------+ // USBD Driver API //--------------------------------------------------------------------+ -void audiod_init(void) -{ +void audiod_init(void) { tu_memclr(_audiod_fct, sizeof(_audiod_fct)); - for(uint8_t i=0; ictrl_buf = ctrl_buf_1; audio->ctrl_buf_sz = CFG_TUD_AUDIO_FUNC_1_CTRL_BUF_SZ; @@ -1309,8 +1245,7 @@ void audiod_init(void) } // Initialize active alternate interface buffers - switch (i) - { + switch (i) { #if CFG_TUD_AUDIO_FUNC_1_N_AS_INT > 0 case 0: audio->alt_setting = alt_setting_1; @@ -1328,302 +1263,285 @@ void audiod_init(void) #endif } - // Initialize IN EP FIFO if required + // Initialize IN EP FIFO if required #if CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_ENCODING - switch (i) - { -#if CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ > 0 + switch (i) { + #if CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ > 0 case 0: tu_fifo_config(&audio->ep_in_ff, ep_in_sw_buf.buf_1, CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ, 1, true); -#if CFG_FIFO_MUTEX + #if CFG_FIFO_MUTEX tu_fifo_config_mutex(&audio->ep_in_ff, osal_mutex_create(&ep_in_ff_mutex_wr_1), NULL); -#endif + #endif break; -#endif -#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_IN_SW_BUF_SZ > 0 + #endif + #if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_IN_SW_BUF_SZ > 0 case 1: tu_fifo_config(&audio->ep_in_ff, ep_in_sw_buf.buf_2, CFG_TUD_AUDIO_FUNC_2_EP_IN_SW_BUF_SZ, 1, true); -#if CFG_FIFO_MUTEX + #if CFG_FIFO_MUTEX tu_fifo_config_mutex(&audio->ep_in_ff, osal_mutex_create(&ep_in_ff_mutex_wr_2), NULL); -#endif + #endif break; -#endif -#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_IN_SW_BUF_SZ > 0 + #endif + #if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_IN_SW_BUF_SZ > 0 case 2: tu_fifo_config(&audio->ep_in_ff, ep_in_sw_buf.buf_3, CFG_TUD_AUDIO_FUNC_3_EP_IN_SW_BUF_SZ, 1, true); -#if CFG_FIFO_MUTEX + #if CFG_FIFO_MUTEX tu_fifo_config_mutex(&audio->ep_in_ff, osal_mutex_create(&ep_in_ff_mutex_wr_3), NULL); -#endif + #endif break; -#endif + #endif } -#endif // CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_ENCODING +#endif// CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_ENCODING - // Initialize linear buffers + // Initialize linear buffers #if USE_LINEAR_BUFFER_TX - switch (i) - { -#if CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX > 0 + switch (i) { + #if CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX > 0 case 0: audio->lin_buf_in = lin_buf_in.buf_1; break; -#endif -#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_IN_SZ_MAX > 0 + #endif + #if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_IN_SZ_MAX > 0 case 1: audio->lin_buf_in = lin_buf_in.buf_2; break; -#endif -#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_IN_SZ_MAX > 0 + #endif + #if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_IN_SZ_MAX > 0 case 2: audio->lin_buf_in = lin_buf_in.buf_3; break; -#endif + #endif } -#endif // USE_LINEAR_BUFFER_TX +#endif// USE_LINEAR_BUFFER_TX - // Initialize OUT EP FIFO if required + // Initialize OUT EP FIFO if required #if CFG_TUD_AUDIO_ENABLE_EP_OUT && !CFG_TUD_AUDIO_ENABLE_DECODING - switch (i) - { -#if CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ > 0 + switch (i) { + #if CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ > 0 case 0: tu_fifo_config(&audio->ep_out_ff, ep_out_sw_buf.buf_1, CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ, 1, true); -#if CFG_FIFO_MUTEX + #if CFG_FIFO_MUTEX tu_fifo_config_mutex(&audio->ep_out_ff, NULL, osal_mutex_create(&ep_out_ff_mutex_rd_1)); -#endif + #endif break; -#endif -#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_OUT_SW_BUF_SZ > 0 + #endif + #if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_OUT_SW_BUF_SZ > 0 case 1: tu_fifo_config(&audio->ep_out_ff, ep_out_sw_buf.buf_2, CFG_TUD_AUDIO_FUNC_2_EP_OUT_SW_BUF_SZ, 1, true); -#if CFG_FIFO_MUTEX + #if CFG_FIFO_MUTEX tu_fifo_config_mutex(&audio->ep_out_ff, NULL, osal_mutex_create(&ep_out_ff_mutex_rd_2)); -#endif + #endif break; -#endif -#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_OUT_SW_BUF_SZ > 0 + #endif + #if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_OUT_SW_BUF_SZ > 0 case 2: tu_fifo_config(&audio->ep_out_ff, ep_out_sw_buf.buf_3, CFG_TUD_AUDIO_FUNC_3_EP_OUT_SW_BUF_SZ, 1, true); -#if CFG_FIFO_MUTEX + #if CFG_FIFO_MUTEX tu_fifo_config_mutex(&audio->ep_out_ff, NULL, osal_mutex_create(&ep_out_ff_mutex_rd_3)); -#endif + #endif break; -#endif + #endif } -#endif // CFG_TUD_AUDIO_ENABLE_EP_OUT && !CFG_TUD_AUDIO_ENABLE_DECODING +#endif// CFG_TUD_AUDIO_ENABLE_EP_OUT && !CFG_TUD_AUDIO_ENABLE_DECODING - // Initialize linear buffers + // Initialize linear buffers #if USE_LINEAR_BUFFER_RX - switch (i) - { -#if CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX > 0 + switch (i) { + #if CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX > 0 case 0: audio->lin_buf_out = lin_buf_out.buf_1; break; -#endif -#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_OUT_SZ_MAX > 0 + #endif + #if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_OUT_SZ_MAX > 0 case 1: audio->lin_buf_out = lin_buf_out.buf_2; break; -#endif -#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_OUT_SZ_MAX > 0 + #endif + #if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_OUT_SZ_MAX > 0 case 2: audio->lin_buf_out = lin_buf_out.buf_3; break; -#endif + #endif } -#endif // USE_LINEAR_BUFFER_RX +#endif// USE_LINEAR_BUFFER_RX #if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP - switch (i) - { -#if CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX > 0 + switch (i) { + #if CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX > 0 case 0: audio->fb_buf = &fb_ep_buf.buf_1; break; -#endif -#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_OUT_SZ_MAX > 0 + #endif + #if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_OUT_SZ_MAX > 0 case 1: audio->fb_buf = &fb_ep_buf.buf_2; break; -#endif -#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_OUT_SZ_MAX > 0 + #endif + #if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_OUT_SZ_MAX > 0 case 2: audio->fb_buf = &fb_ep_buf.buf_3; break; -#endif + #endif } -#endif // CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP +#endif// CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP - // Initialize TX support FIFOs if required + // Initialize TX support FIFOs if required #if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_ENCODING - switch (i) - { -#if CFG_TUD_AUDIO_FUNC_1_TX_SUPP_SW_FIFO_SZ > 0 + switch (i) { + #if CFG_TUD_AUDIO_FUNC_1_TX_SUPP_SW_FIFO_SZ > 0 case 0: audio->tx_supp_ff = tx_supp_ff_1; audio->n_tx_supp_ff = CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO; audio->tx_supp_ff_sz_max = CFG_TUD_AUDIO_FUNC_1_TX_SUPP_SW_FIFO_SZ; - for (uint8_t cnt = 0; cnt < CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO; cnt++) - { + for (uint8_t cnt = 0; cnt < CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO; cnt++) { tu_fifo_config(&tx_supp_ff_1[cnt], tx_supp_ff_buf_1[cnt], CFG_TUD_AUDIO_FUNC_1_TX_SUPP_SW_FIFO_SZ, 1, true); -#if CFG_FIFO_MUTEX + #if CFG_FIFO_MUTEX tu_fifo_config_mutex(&tx_supp_ff_1[cnt], osal_mutex_create(&tx_supp_ff_mutex_wr_1[cnt]), NULL); -#endif + #endif } break; -#endif // CFG_TUD_AUDIO_FUNC_1_TX_SUPP_SW_FIFO_SZ > 0 + #endif// CFG_TUD_AUDIO_FUNC_1_TX_SUPP_SW_FIFO_SZ > 0 -#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_TX_SUPP_SW_FIFO_SZ > 0 + #if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_TX_SUPP_SW_FIFO_SZ > 0 case 1: audio->tx_supp_ff = tx_supp_ff_2; audio->n_tx_supp_ff = CFG_TUD_AUDIO_FUNC_2_N_TX_SUPP_SW_FIFO; audio->tx_supp_ff_sz_max = CFG_TUD_AUDIO_FUNC_2_TX_SUPP_SW_FIFO_SZ; - for (uint8_t cnt = 0; cnt < CFG_TUD_AUDIO_FUNC_2_N_TX_SUPP_SW_FIFO; cnt++) - { + for (uint8_t cnt = 0; cnt < CFG_TUD_AUDIO_FUNC_2_N_TX_SUPP_SW_FIFO; cnt++) { tu_fifo_config(&tx_supp_ff_2[cnt], tx_supp_ff_buf_2[cnt], CFG_TUD_AUDIO_FUNC_2_TX_SUPP_SW_FIFO_SZ, 1, true); -#if CFG_FIFO_MUTEX + #if CFG_FIFO_MUTEX tu_fifo_config_mutex(&tx_supp_ff_2[cnt], osal_mutex_create(&tx_supp_ff_mutex_wr_2[cnt]), NULL); -#endif + #endif } break; -#endif // CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_TX_SUPP_SW_FIFO_SZ > 0 + #endif// CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_TX_SUPP_SW_FIFO_SZ > 0 -#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_TX_SUPP_SW_FIFO_SZ > 0 + #if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_TX_SUPP_SW_FIFO_SZ > 0 case 2: audio->tx_supp_ff = tx_supp_ff_3; audio->n_tx_supp_ff = CFG_TUD_AUDIO_FUNC_3_N_TX_SUPP_SW_FIFO; audio->tx_supp_ff_sz_max = CFG_TUD_AUDIO_FUNC_3_TX_SUPP_SW_FIFO_SZ; - for (uint8_t cnt = 0; cnt < CFG_TUD_AUDIO_FUNC_3_N_TX_SUPP_SW_FIFO; cnt++) - { + for (uint8_t cnt = 0; cnt < CFG_TUD_AUDIO_FUNC_3_N_TX_SUPP_SW_FIFO; cnt++) { tu_fifo_config(&tx_supp_ff_3[cnt], tx_supp_ff_buf_3[cnt], CFG_TUD_AUDIO_FUNC_3_TX_SUPP_SW_FIFO_SZ, 1, true); -#if CFG_FIFO_MUTEX + #if CFG_FIFO_MUTEX tu_fifo_config_mutex(&tx_supp_ff_3[cnt], osal_mutex_create(&tx_supp_ff_mutex_wr_3[cnt]), NULL); -#endif + #endif } break; -#endif // CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_TX_SUPP_SW_FIFO_SZ > 0 + #endif// CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_TX_SUPP_SW_FIFO_SZ > 0 } -#endif // CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_ENCODING +#endif// CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_ENCODING - // Set encoding parameters for Type_I formats + // Set encoding parameters for Type_I formats #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 + switch (i) { + #if CFG_TUD_AUDIO_FUNC_1_TX_SUPP_SW_FIFO_SZ > 0 case 0: audio->n_channels_per_ff_tx = CFG_TUD_AUDIO_FUNC_1_CHANNEL_PER_FIFO_TX; break; -#endif -#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_TX_SUPP_SW_FIFO_SZ > 0 + #endif + #if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_TX_SUPP_SW_FIFO_SZ > 0 case 1: audio->n_channels_per_ff_tx = CFG_TUD_AUDIO_FUNC_2_CHANNEL_PER_FIFO_TX; break; -#endif -#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_TX_SUPP_SW_FIFO_SZ > 0 + #endif + #if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_TX_SUPP_SW_FIFO_SZ > 0 case 2: audio->n_channels_per_ff_tx = CFG_TUD_AUDIO_FUNC_3_CHANNEL_PER_FIFO_TX; break; -#endif + #endif } -#endif // CFG_TUD_AUDIO_ENABLE_TYPE_I_ENCODING +#endif// CFG_TUD_AUDIO_ENABLE_TYPE_I_ENCODING - // Initialize RX support FIFOs if required + // Initialize RX support FIFOs if required #if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_DECODING - switch (i) - { -#if CFG_TUD_AUDIO_FUNC_1_RX_SUPP_SW_FIFO_SZ > 0 + switch (i) { + #if CFG_TUD_AUDIO_FUNC_1_RX_SUPP_SW_FIFO_SZ > 0 case 0: audio->rx_supp_ff = rx_supp_ff_1; audio->n_rx_supp_ff = CFG_TUD_AUDIO_FUNC_1_N_RX_SUPP_SW_FIFO; audio->rx_supp_ff_sz_max = CFG_TUD_AUDIO_FUNC_1_RX_SUPP_SW_FIFO_SZ; - for (uint8_t cnt = 0; cnt < CFG_TUD_AUDIO_FUNC_1_N_RX_SUPP_SW_FIFO; cnt++) - { + for (uint8_t cnt = 0; cnt < CFG_TUD_AUDIO_FUNC_1_N_RX_SUPP_SW_FIFO; cnt++) { tu_fifo_config(&rx_supp_ff_1[cnt], rx_supp_ff_buf_1[cnt], CFG_TUD_AUDIO_FUNC_1_RX_SUPP_SW_FIFO_SZ, 1, true); -#if CFG_FIFO_MUTEX + #if CFG_FIFO_MUTEX tu_fifo_config_mutex(&rx_supp_ff_1[cnt], osal_mutex_create(&rx_supp_ff_mutex_rd_1[cnt]), NULL); -#endif + #endif } break; -#endif // CFG_TUD_AUDIO_FUNC_1_RX_SUPP_SW_FIFO_SZ > 0 + #endif// CFG_TUD_AUDIO_FUNC_1_RX_SUPP_SW_FIFO_SZ > 0 -#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_RX_SUPP_SW_FIFO_SZ > 0 + #if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_RX_SUPP_SW_FIFO_SZ > 0 case 1: audio->rx_supp_ff = rx_supp_ff_2; audio->n_rx_supp_ff = CFG_TUD_AUDIO_FUNC_2_N_RX_SUPP_SW_FIFO; audio->rx_supp_ff_sz_max = CFG_TUD_AUDIO_FUNC_2_RX_SUPP_SW_FIFO_SZ; - for (uint8_t cnt = 0; cnt < CFG_TUD_AUDIO_FUNC_2_N_RX_SUPP_SW_FIFO; cnt++) - { + for (uint8_t cnt = 0; cnt < CFG_TUD_AUDIO_FUNC_2_N_RX_SUPP_SW_FIFO; cnt++) { tu_fifo_config(&rx_supp_ff_2[cnt], rx_supp_ff_buf_2[cnt], CFG_TUD_AUDIO_FUNC_2_RX_SUPP_SW_FIFO_SZ, 1, true); -#if CFG_FIFO_MUTEX + #if CFG_FIFO_MUTEX tu_fifo_config_mutex(&rx_supp_ff_2[cnt], osal_mutex_create(&rx_supp_ff_mutex_rd_2[cnt]), NULL); -#endif + #endif } break; -#endif // CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_RX_SUPP_SW_FIFO_SZ > 0 + #endif// CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_RX_SUPP_SW_FIFO_SZ > 0 -#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_RX_SUPP_SW_FIFO_SZ > 0 + #if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_RX_SUPP_SW_FIFO_SZ > 0 case 2: audio->rx_supp_ff = rx_supp_ff_3; audio->n_rx_supp_ff = CFG_TUD_AUDIO_FUNC_3_N_RX_SUPP_SW_FIFO; audio->rx_supp_ff_sz_max = CFG_TUD_AUDIO_FUNC_3_RX_SUPP_SW_FIFO_SZ; - for (uint8_t cnt = 0; cnt < CFG_TUD_AUDIO_FUNC_3_N_RX_SUPP_SW_FIFO; cnt++) - { + for (uint8_t cnt = 0; cnt < CFG_TUD_AUDIO_FUNC_3_N_RX_SUPP_SW_FIFO; cnt++) { tu_fifo_config(&rx_supp_ff_3[cnt], rx_supp_ff_buf_3[cnt], CFG_TUD_AUDIO_FUNC_3_RX_SUPP_SW_FIFO_SZ, 1, true); -#if CFG_FIFO_MUTEX + #if CFG_FIFO_MUTEX tu_fifo_config_mutex(&rx_supp_ff_3[cnt], osal_mutex_create(&rx_supp_ff_mutex_rd_3[cnt]), NULL); -#endif + #endif } break; -#endif // CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_RX_SUPP_SW_FIFO_SZ > 0 + #endif// CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_RX_SUPP_SW_FIFO_SZ > 0 } -#endif // CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_ENCODING +#endif// CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_ENCODING - // Set encoding parameters for Type_I formats + // Set encoding parameters for Type_I formats #if CFG_TUD_AUDIO_ENABLE_TYPE_I_DECODING - switch (i) - { -#if CFG_TUD_AUDIO_FUNC_1_RX_SUPP_SW_FIFO_SZ > 0 + switch (i) { + #if CFG_TUD_AUDIO_FUNC_1_RX_SUPP_SW_FIFO_SZ > 0 case 0: audio->n_channels_per_ff_rx = CFG_TUD_AUDIO_FUNC_1_CHANNEL_PER_FIFO_RX; break; -#endif -#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_RX_SUPP_SW_FIFO_SZ > 0 + #endif + #if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_RX_SUPP_SW_FIFO_SZ > 0 case 1: audio->n_channels_per_ff_rx = CFG_TUD_AUDIO_FUNC_2_CHANNEL_PER_FIFO_RX; break; -#endif -#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_RX_SUPP_SW_FIFO_SZ > 0 + #endif + #if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_RX_SUPP_SW_FIFO_SZ > 0 case 2: audio->n_channels_per_ff_rx = CFG_TUD_AUDIO_FUNC_3_CHANNEL_PER_FIFO_RX; break; -#endif + #endif } -#endif // CFG_TUD_AUDIO_ENABLE_TYPE_I_DECODING +#endif// CFG_TUD_AUDIO_ENABLE_TYPE_I_DECODING } } bool audiod_deinit(void) { - return false; // TODO not implemented yet + return false;// TODO not implemented yet } -void audiod_reset(uint8_t rhport) -{ +void audiod_reset(uint8_t rhport) { (void) rhport; - for(uint8_t i=0; in_tx_supp_ff; cnt++) - { + for (uint8_t cnt = 0; cnt < audio->n_tx_supp_ff; cnt++) { tu_fifo_clear(&audio->tx_supp_ff[cnt]); } #endif #if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_DECODING - for (uint8_t cnt = 0; cnt < audio->n_rx_supp_ff; cnt++) - { + for (uint8_t cnt = 0; cnt < audio->n_rx_supp_ff; cnt++) { tu_fifo_clear(&audio->rx_supp_ff[cnt]); } #endif } } -uint16_t audiod_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len) -{ +uint16_t audiod_open(uint8_t rhport, tusb_desc_interface_t const *itf_desc, uint16_t max_len) { (void) max_len; - TU_VERIFY ( TUSB_CLASS_AUDIO == itf_desc->bInterfaceClass && - AUDIO_SUBCLASS_CONTROL == itf_desc->bInterfaceSubClass); + TU_VERIFY(TUSB_CLASS_AUDIO == itf_desc->bInterfaceClass && + AUDIO_SUBCLASS_CONTROL == itf_desc->bInterfaceSubClass); // 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 - TU_ASSERT(itf_desc->bNumEndpoints <= 1); // 0 or 1 EPs are allowed - if (itf_desc->bNumEndpoints == 1) - { + TU_ASSERT(itf_desc->bNumEndpoints <= 1);// 0 or 1 EPs are allowed + if (itf_desc->bNumEndpoints == 1) { TU_ASSERT(CFG_TUD_AUDIO_ENABLE_INTERRUPT_EP); } @@ -1672,16 +1586,13 @@ uint16_t audiod_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uin // Find available audio driver interface uint8_t i; - for (i = 0; i < CFG_TUD_AUDIO; i++) - { - if (!_audiod_fct[i].p_desc) - { - _audiod_fct[i].p_desc = (uint8_t const *)itf_desc; // Save pointer to AC descriptor which is by specification always the first one + for (i = 0; i < CFG_TUD_AUDIO; i++) { + if (!_audiod_fct[i].p_desc) { + _audiod_fct[i].p_desc = (uint8_t const *) itf_desc;// Save pointer to AC descriptor which is by specification always the first one _audiod_fct[i].rhport = rhport; // Setup descriptor lengths - switch (i) - { + switch (i) { case 0: _audiod_fct[i].desc_length = CFG_TUD_AUDIO_FUNC_1_DESC_LEN; break; @@ -1700,12 +1611,12 @@ uint16_t audiod_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uin #ifdef TUP_DCD_EDPT_ISO_ALLOC { #if CFG_TUD_AUDIO_ENABLE_EP_IN - uint8_t ep_in = 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; + uint8_t ep_out = 0; uint16_t ep_out_size = 0; #endif @@ -1715,38 +1626,30 @@ 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) - { + while (p_desc_end - p_desc > 0) { + 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.xfer == TUSB_XFER_ISOCHRONOUS) { #if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP // Explicit feedback EP - if (desc_ep->bmAttributes.usage == 1) - { + 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) - { + 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); #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); #endif } } - } } @@ -1754,76 +1657,62 @@ uint16_t audiod_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uin } #if CFG_TUD_AUDIO_ENABLE_EP_IN - if (ep_in) - { + if (ep_in) { usbd_edpt_iso_alloc(rhport, ep_in, ep_in_size); } #endif #if CFG_TUD_AUDIO_ENABLE_EP_OUT - if (ep_out) - { + if (ep_out) { usbd_edpt_iso_alloc(rhport, ep_out, ep_out_size); } #endif #if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP - if (ep_fb) - { + if (ep_fb) { usbd_edpt_iso_alloc(rhport, ep_fb, 4); } #endif } -#endif // TUP_DCD_EDPT_ISO_ALLOC +#endif// TUP_DCD_EDPT_ISO_ALLOC #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; // 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) - { + while (p_desc_end - p_desc > 0) { + 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) - { + 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]; + } 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 +#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) - { + 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; + 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) - { + 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)); @@ -1840,16 +1729,15 @@ uint16_t audiod_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uin } // Verify we found a free one - TU_ASSERT( i < CFG_TUD_AUDIO ); + TU_ASSERT(i < CFG_TUD_AUDIO); // 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 + 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 return drv_len; } -static bool audiod_get_interface(uint8_t rhport, tusb_control_request_t const * p_request) -{ +static bool audiod_get_interface(uint8_t rhport, tusb_control_request_t const *p_request) { uint8_t const itf = tu_u16_low(p_request->wIndex); // Find index of audio streaming interface @@ -1864,8 +1752,7 @@ static bool audiod_get_interface(uint8_t rhport, tusb_control_request_t const * return true; } -static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const * p_request) -{ +static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const *p_request) { (void) rhport; // Here we need to do the following: @@ -1889,12 +1776,11 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const * uint8_t const *p_desc; TU_VERIFY(audiod_get_AS_interface_index_global(itf, &func_id, &idxItf, &p_desc)); - audiod_function_t* audio = &_audiod_fct[func_id]; + audiod_function_t *audio = &_audiod_fct[func_id]; - // Look if there is an EP to be closed - for this driver, there are only 3 possible EPs which may be closed (only AS related EPs can be closed, AC EP (if present) is always open) +// Look if there is an EP to be closed - for this driver, there are only 3 possible EPs which may be closed (only AS related EPs can be closed, AC EP (if present) is always open) #if CFG_TUD_AUDIO_ENABLE_EP_IN - if (audio->ep_in_as_intf_num == itf) - { + if (audio->ep_in_as_intf_num == itf) { audio->ep_in_as_intf_num = 0; #ifndef TUP_DCD_EDPT_ISO_ALLOC usbd_edpt_close(rhport, audio->ep_in); @@ -1904,8 +1790,7 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const * #if !CFG_TUD_AUDIO_ENABLE_ENCODING tu_fifo_clear(&audio->ep_in_ff); #else - for (uint8_t cnt = 0; cnt < audio->n_tx_supp_ff; cnt++) - { + for (uint8_t cnt = 0; cnt < audio->n_tx_supp_ff; cnt++) { tu_fifo_clear(&audio->tx_supp_ff[cnt]); } #endif @@ -1913,7 +1798,7 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const * // Invoke callback - can be used to stop data sampling TU_VERIFY(tud_audio_set_itf_close_EP_cb(rhport, p_request)); - audio->ep_in = 0; // Necessary? + audio->ep_in = 0;// Necessary? #if CFG_TUD_AUDIO_EP_IN_FLOW_CONTROL audio->packet_sz_tx[0] = 0; @@ -1921,11 +1806,10 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const * audio->packet_sz_tx[2] = 0; #endif } -#endif // CFG_TUD_AUDIO_ENABLE_EP_IN +#endif// CFG_TUD_AUDIO_ENABLE_EP_IN #if CFG_TUD_AUDIO_ENABLE_EP_OUT - if (audio->ep_out_as_intf_num == itf) - { + if (audio->ep_out_as_intf_num == itf) { audio->ep_out_as_intf_num = 0; #ifndef TUP_DCD_EDPT_ISO_ALLOC usbd_edpt_close(rhport, audio->ep_out); @@ -1935,8 +1819,7 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const * #if !CFG_TUD_AUDIO_ENABLE_DECODING tu_fifo_clear(&audio->ep_out_ff); #else - for (uint8_t cnt = 0; cnt < audio->n_rx_supp_ff; cnt++) - { + for (uint8_t cnt = 0; cnt < audio->n_rx_supp_ff; cnt++) { tu_fifo_clear(&audio->rx_supp_ff[cnt]); } #endif @@ -1944,7 +1827,7 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const * // Invoke callback - can be used to stop data sampling TU_VERIFY(tud_audio_set_itf_close_EP_cb(rhport, p_request)); - audio->ep_out = 0; // Necessary? + audio->ep_out = 0;// Necessary? // Close corresponding feedback EP #if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP @@ -1955,7 +1838,7 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const * tu_memclr(&audio->feedback, sizeof(audio->feedback)); #endif } -#endif // CFG_TUD_AUDIO_ENABLE_EP_OUT +#endif// CFG_TUD_AUDIO_ENABLE_EP_OUT // Save current alternative interface setting audio->alt_setting[idxItf] = alt; @@ -1966,22 +1849,18 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const * // p_desc starts at required interface with alternate setting zero // Condition modified from p_desc < p_desc_end to prevent gcc>=12 strict-overflow warning - while (p_desc_end - p_desc > 0) - { + while (p_desc_end - p_desc > 0) { // 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 (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_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; + 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 - uint8_t foundEPs = 0, nEps = ((tusb_desc_interface_t const * )p_desc)->bNumEndpoints; + uint8_t foundEPs = 0, nEps = ((tusb_desc_interface_t const *) p_desc)->bNumEndpoints; // Condition modified from p_desc < p_desc_end to prevent gcc>=12 strict-overflow warning - while (foundEPs < nEps && (p_desc_end - p_desc > 0)) - { - if (tu_desc_type(p_desc) == TUSB_DESC_ENDPOINT) - { - tusb_desc_endpoint_t const* desc_ep = (tusb_desc_endpoint_t const *) p_desc; + while (foundEPs < nEps && (p_desc_end - p_desc > 0)) { + if (tu_desc_type(p_desc) == TUSB_DESC_ENDPOINT) { + tusb_desc_endpoint_t const *desc_ep = (tusb_desc_endpoint_t const *) p_desc; #ifdef TUP_DCD_EDPT_ISO_ALLOC TU_ASSERT(usbd_edpt_iso_activate(rhport, desc_ep)); #else @@ -1993,7 +1872,7 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const * usbd_edpt_clear_stall(rhport, ep_addr); #if CFG_TUD_AUDIO_ENABLE_EP_IN - if (tu_edpt_dir(ep_addr) == TUSB_DIR_IN && desc_ep->bmAttributes.usage == 0x00) // Check if usage is data EP + if (tu_edpt_dir(ep_addr) == TUSB_DIR_IN && desc_ep->bmAttributes.usage == 0x00)// Check if usage is data EP { // Save address audio->ep_in = ep_addr; @@ -2004,16 +1883,14 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const * #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 + // Reconfigure size of support FIFOs - this is necessary to avoid samples to get split in case of a wrap #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_sample_tx)) - * (audio->n_channels_per_ff_tx * audio->n_bytes_per_sample_tx)); - for (uint8_t cnt = 0; cnt < audio->n_tx_supp_ff; cnt++) - { + const uint16_t active_fifo_depth = (uint16_t) ((audio->tx_supp_ff_sz_max / (audio->n_channels_per_ff_tx * audio->n_bytes_per_sample_tx)) * (audio->n_channels_per_ff_tx * audio->n_bytes_per_sample_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); } audio->n_ff_used_tx = audio->n_channels_tx / audio->n_channels_per_ff_tx; - TU_ASSERT( audio->n_ff_used_tx <= audio->n_tx_supp_ff ); + TU_ASSERT(audio->n_ff_used_tx <= audio->n_tx_supp_ff); #endif #endif @@ -2021,11 +1898,11 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const * // It is necessary to trigger this here since the refill is done with an RX FIFO empty interrupt which can only trigger if something was in there TU_VERIFY(audiod_tx_done_cb(rhport, &_audiod_fct[func_id])); } -#endif // CFG_TUD_AUDIO_ENABLE_EP_IN +#endif// CFG_TUD_AUDIO_ENABLE_EP_IN #if CFG_TUD_AUDIO_ENABLE_EP_OUT - if (tu_edpt_dir(ep_addr) == TUSB_DIR_OUT) // Checking usage not necessary + if (tu_edpt_dir(ep_addr) == TUSB_DIR_OUT)// Checking usage not necessary { // Save address audio->ep_out = ep_addr; @@ -2035,15 +1912,14 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const * #if CFG_TUD_AUDIO_ENABLE_DECODING 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 + // 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_DECODING const uint16_t active_fifo_depth = (audio->rx_supp_ff_sz_max / audio->n_bytes_per_sample_rx) * audio->n_bytes_per_sample_rx; - for (uint8_t cnt = 0; cnt < audio->n_rx_supp_ff; cnt++) - { + for (uint8_t cnt = 0; cnt < audio->n_rx_supp_ff; cnt++) { tu_fifo_config(&audio->rx_supp_ff[cnt], audio->rx_supp_ff[cnt].buffer, active_fifo_depth, 1, true); } audio->n_ff_used_rx = audio->n_channels_rx / audio->n_channels_per_ff_rx; - TU_ASSERT( audio->n_ff_used_rx <= audio->n_rx_supp_ff ); + TU_ASSERT(audio->n_ff_used_rx <= audio->n_rx_supp_ff); #endif #endif @@ -2056,13 +1932,13 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const * } #if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP - if (tu_edpt_dir(ep_addr) == TUSB_DIR_IN && desc_ep->bmAttributes.usage == 1) // Check if usage is explicit data feedback + if (tu_edpt_dir(ep_addr) == TUSB_DIR_IN && desc_ep->bmAttributes.usage == 1)// Check if usage is explicit data feedback { audio->ep_fb = ep_addr; - audio->feedback.frame_shift = desc_ep->bInterval -1; + audio->feedback.frame_shift = desc_ep->bInterval - 1; } #endif -#endif // CFG_TUD_AUDIO_ENABLE_EP_OUT +#endif// CFG_TUD_AUDIO_ENABLE_EP_OUT foundEPs += 1; } @@ -2076,58 +1952,55 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const * #if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP // Prepare feedback computation if endpoint is available - if(audio->ep_fb != 0) - { + if (audio->ep_fb != 0) { audio_feedback_params_t fb_param; tud_audio_feedback_params_cb(func_id, alt, &fb_param); audio->feedback.compute_method = fb_param.method; - if(TUSB_SPEED_FULL == tud_speed_get()) + if (TUSB_SPEED_FULL == tud_speed_get()) audio->feedback.format_correction = tud_audio_feedback_format_correction_cb(func_id); // Minimal/Maximum value in 16.16 format for full speed (1ms per frame) or high speed (125 us per frame) - uint32_t const frame_div = (TUSB_SPEED_FULL == tud_speed_get()) ? 1000 : 8000; - audio->feedback.min_value = ((fb_param.sample_freq - 1)/frame_div) << 16; - audio->feedback.max_value = (fb_param.sample_freq/frame_div + 1) << 16; + uint32_t const frame_div = (TUSB_SPEED_FULL == tud_speed_get()) ? 1000 : 8000; + audio->feedback.min_value = ((fb_param.sample_freq - 1) / frame_div) << 16; + audio->feedback.max_value = (fb_param.sample_freq / frame_div + 1) << 16; - switch(fb_param.method) - { + switch (fb_param.method) { case AUDIO_FEEDBACK_METHOD_FREQUENCY_FIXED: case AUDIO_FEEDBACK_METHOD_FREQUENCY_FLOAT: case AUDIO_FEEDBACK_METHOD_FREQUENCY_POWER_OF_2: audiod_set_fb_params_freq(audio, fb_param.sample_freq, fb_param.frequency.mclk_freq); - break; + break; - case AUDIO_FEEDBACK_METHOD_FIFO_COUNT: - { + case AUDIO_FEEDBACK_METHOD_FIFO_COUNT: { // Initialize the threshold level to half filled uint16_t fifo_lvl_thr; -#if CFG_TUD_AUDIO_ENABLE_DECODING + #if CFG_TUD_AUDIO_ENABLE_DECODING fifo_lvl_thr = tu_fifo_depth(&audio->rx_supp_ff[0]) / 2; -#else + #else fifo_lvl_thr = tu_fifo_depth(&audio->ep_out_ff) / 2; -#endif + #endif audio->feedback.compute.fifo_count.fifo_lvl_thr = fifo_lvl_thr; - audio->feedback.compute.fifo_count.fifo_lvl_avg = ((uint32_t)fifo_lvl_thr) << 16; + audio->feedback.compute.fifo_count.fifo_lvl_avg = ((uint32_t) fifo_lvl_thr) << 16; // Avoid 64bit division uint32_t nominal = ((fb_param.sample_freq / 100) << 16) / (frame_div / 100); audio->feedback.compute.fifo_count.nom_value = nominal; audio->feedback.compute.fifo_count.rate_const[0] = (uint16_t) ((audio->feedback.max_value - nominal) / fifo_lvl_thr); audio->feedback.compute.fifo_count.rate_const[1] = (uint16_t) ((nominal - audio->feedback.min_value) / fifo_lvl_thr); // On HS feedback is more sensitive since packet size can vary every MSOF, could cause instability - if(tud_speed_get() == TUSB_SPEED_HIGH) { + if (tud_speed_get() == TUSB_SPEED_HIGH) { audio->feedback.compute.fifo_count.rate_const[0] /= 8; audio->feedback.compute.fifo_count.rate_const[1] /= 8; } - } - break; + } break; // nothing to do - default: break; + default: + break; } } -#endif // CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP +#endif// CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP // We are done - abort loop break; @@ -2140,13 +2013,11 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const * #if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP // Disable SOF interrupt if no driver has any enabled feedback EP bool enable_sof = false; - for(uint8_t i=0; i < CFG_TUD_AUDIO; i++) - { + for (uint8_t i = 0; i < CFG_TUD_AUDIO; i++) { if (_audiod_fct[i].ep_fb != 0 && - (_audiod_fct[i].feedback.compute_method == AUDIO_FEEDBACK_METHOD_FREQUENCY_FIXED || - _audiod_fct[i].feedback.compute_method == AUDIO_FEEDBACK_METHOD_FREQUENCY_FLOAT || - _audiod_fct[i].feedback.compute_method == AUDIO_FEEDBACK_METHOD_FREQUENCY_POWER_OF_2 )) - { + (_audiod_fct[i].feedback.compute_method == AUDIO_FEEDBACK_METHOD_FREQUENCY_FIXED || + _audiod_fct[i].feedback.compute_method == AUDIO_FEEDBACK_METHOD_FREQUENCY_FLOAT || + _audiod_fct[i].feedback.compute_method == AUDIO_FEEDBACK_METHOD_FREQUENCY_POWER_OF_2)) { enable_sof = true; break; } @@ -2165,22 +2036,17 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const * // Invoked when class request DATA stage is finished. // return false to stall control EP (e.g Host send non-sense DATA) -static bool audiod_control_complete(uint8_t rhport, tusb_control_request_t const * p_request) -{ +static bool audiod_control_complete(uint8_t rhport, tusb_control_request_t const *p_request) { // Handle audio class specific set requests - if(p_request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS && p_request->bmRequestType_bit.direction == TUSB_DIR_OUT) - { + if (p_request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS && p_request->bmRequestType_bit.direction == TUSB_DIR_OUT) { uint8_t func_id; - switch (p_request->bmRequestType_bit.recipient) - { - case TUSB_REQ_RCPT_INTERFACE: - { + switch (p_request->bmRequestType_bit.recipient) { + case TUSB_REQ_RCPT_INTERFACE: { uint8_t itf = TU_U16_LOW(p_request->wIndex); uint8_t entityID = TU_U16_HIGH(p_request->wIndex); - if (entityID != 0) - { + if (entityID != 0) { // Check if entity is present and get corresponding driver index TU_VERIFY(audiod_verify_entity_exists(itf, entityID, &func_id)); @@ -2193,20 +2059,16 @@ static bool audiod_control_complete(uint8_t rhport, tusb_control_request_t const // Invoke callback return tud_audio_set_req_entity_cb(rhport, p_request, _audiod_fct[func_id].ctrl_buf); - } - else - { + } else { // Find index of audio driver structure and verify interface really exists TU_VERIFY(audiod_verify_itf_exists(itf, &func_id)); // Invoke callback return tud_audio_set_req_itf_cb(rhport, p_request, _audiod_fct[func_id].ctrl_buf); } - } - break; + } break; - case TUSB_REQ_RCPT_ENDPOINT: - { + case TUSB_REQ_RCPT_ENDPOINT: { uint8_t ep = TU_U16_LOW(p_request->wIndex); // Check if entity is present and get corresponding driver index @@ -2214,10 +2076,11 @@ static bool audiod_control_complete(uint8_t rhport, tusb_control_request_t const // Invoke callback return tud_audio_set_req_ep_cb(rhport, p_request, _audiod_fct[func_id].ctrl_buf); - } - break; + } break; // Unknown/Unsupported recipient - default: TU_BREAKPOINT(); return false; + default: + TU_BREAKPOINT(); + return false; } } return true; @@ -2225,15 +2088,12 @@ static bool audiod_control_complete(uint8_t rhport, tusb_control_request_t const // Handle class control request // return false to stall control endpoint (e.g unsupported request) -static bool audiod_control_request(uint8_t rhport, tusb_control_request_t const * p_request) -{ +static bool audiod_control_request(uint8_t rhport, tusb_control_request_t const *p_request) { (void) rhport; // Handle standard requests - standard set requests usually have no data stage so we also handle set requests here - if (p_request->bmRequestType_bit.type == TUSB_REQ_TYPE_STANDARD) - { - switch (p_request->bRequest) - { + if (p_request->bmRequestType_bit.type == TUSB_REQ_TYPE_STANDARD) { + switch (p_request->bRequest) { case TUSB_REQ_GET_INTERFACE: return audiod_get_interface(rhport, p_request); @@ -2244,66 +2104,59 @@ static bool audiod_control_request(uint8_t rhport, tusb_control_request_t const return true; // Unknown/Unsupported request - default: TU_BREAKPOINT(); return false; + default: + TU_BREAKPOINT(); + return false; } } // Handle class requests - if (p_request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS) - { + if (p_request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS) { uint8_t itf = TU_U16_LOW(p_request->wIndex); uint8_t func_id; // Conduct checks which depend on the recipient - switch (p_request->bmRequestType_bit.recipient) - { - case TUSB_REQ_RCPT_INTERFACE: - { + switch (p_request->bmRequestType_bit.recipient) { + case TUSB_REQ_RCPT_INTERFACE: { uint8_t entityID = TU_U16_HIGH(p_request->wIndex); // Verify if entity is present - if (entityID != 0) - { + if (entityID != 0) { // Find index of audio driver structure and verify entity really exists TU_VERIFY(audiod_verify_entity_exists(itf, entityID, &func_id)); // In case we got a get request invoke callback - callback needs to answer as defined in UAC2 specification page 89 - 5. Requests - if (p_request->bmRequestType_bit.direction == TUSB_DIR_IN) - { + if (p_request->bmRequestType_bit.direction == TUSB_DIR_IN) { return tud_audio_get_req_entity_cb(rhport, p_request); } - } - else - { + } else { // Find index of audio driver structure and verify interface really exists TU_VERIFY(audiod_verify_itf_exists(itf, &func_id)); // In case we got a get request invoke callback - callback needs to answer as defined in UAC2 specification page 89 - 5. Requests - if (p_request->bmRequestType_bit.direction == TUSB_DIR_IN) - { + if (p_request->bmRequestType_bit.direction == TUSB_DIR_IN) { return tud_audio_get_req_itf_cb(rhport, p_request); } } - } - break; + } break; - case TUSB_REQ_RCPT_ENDPOINT: - { + case TUSB_REQ_RCPT_ENDPOINT: { uint8_t ep = TU_U16_LOW(p_request->wIndex); // Find index of audio driver structure and verify EP really exists TU_VERIFY(audiod_verify_ep_exists(ep, &func_id)); // In case we got a get request invoke callback - callback needs to answer as defined in UAC2 specification page 89 - 5. Requests - if (p_request->bmRequestType_bit.direction == TUSB_DIR_IN) - { + if (p_request->bmRequestType_bit.direction == TUSB_DIR_IN) { return tud_audio_get_req_ep_cb(rhport, p_request); } - } - break; + } break; // Unknown/Unsupported recipient - default: TU_LOG2(" Unsupported recipient: %d\r\n", p_request->bmRequestType_bit.recipient); TU_BREAKPOINT(); return false; + default: + TU_LOG2(" Unsupported recipient: %d\r\n", p_request->bmRequestType_bit.recipient); + TU_BREAKPOINT(); + return false; } // If we end here, the received request is a set request - we schedule a receive for the data stage and return true here. We handle the rest later in audiod_control_complete() once the data stage was finished @@ -2316,35 +2169,28 @@ static bool audiod_control_request(uint8_t rhport, tusb_control_request_t const return false; } -bool audiod_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request) -{ - if ( stage == CONTROL_STAGE_SETUP ) - { +bool audiod_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request) { + if (stage == CONTROL_STAGE_SETUP) { return audiod_control_request(rhport, request); - } - else if ( stage == CONTROL_STAGE_DATA ) - { + } else if (stage == CONTROL_STAGE_DATA) { return audiod_control_complete(rhport, request); } return true; } -bool audiod_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) -{ +bool audiod_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) { (void) result; (void) xferred_bytes; // Search for interface belonging to given end point address and proceed as required - for (uint8_t func_id = 0; func_id < CFG_TUD_AUDIO; func_id++) - { - audiod_function_t* audio = &_audiod_fct[func_id]; + for (uint8_t func_id = 0; func_id < CFG_TUD_AUDIO; func_id++) { + audiod_function_t *audio = &_audiod_fct[func_id]; #if CFG_TUD_AUDIO_ENABLE_INTERRUPT_EP // Data transmission of control interrupt finished - if (audio->ep_int == 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 ??? // In case of an erroneous transmission a retransmission is conducted - this is taken care of by PHY ??? @@ -2361,8 +2207,7 @@ bool audiod_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint3 #if CFG_TUD_AUDIO_ENABLE_EP_IN // Data transmission of audio packet finished - if (audio->ep_in == ep_addr && audio->alt_setting != 0) - { + if (audio->ep_in == ep_addr && audio->alt_setting != 0) { // USB 2.0, section 5.6.4, third paragraph, states "An isochronous endpoint must specify its required bus access period. However, an isochronous endpoint must be prepared to handle poll rates faster than the one specified." // That paragraph goes on to say "An isochronous IN endpoint must return a zero-length packet whenever data is requested at a faster interval than the specified interval and data is not available." // This can only be solved reliably if we load a ZLP after every IN transmission since we can not say if the host requests samples earlier than we declared! Once all samples are collected we overwrite the loaded ZLP. @@ -2382,27 +2227,24 @@ bool audiod_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint3 #if CFG_TUD_AUDIO_ENABLE_EP_OUT // New audio packet received - if (audio->ep_out == ep_addr) - { + if (audio->ep_out == ep_addr) { TU_VERIFY(audiod_rx_done_cb(rhport, audio, (uint16_t) xferred_bytes)); return true; } -#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP + #if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP // Transmission of feedback EP finished - if (audio->ep_fb == ep_addr) - { + if (audio->ep_fb == ep_addr) { tud_audio_fb_done_cb(func_id); // Schedule a transmit with the new value if EP is not busy - if (usbd_edpt_claim(rhport, audio->ep_fb)) - { + if (usbd_edpt_claim(rhport, audio->ep_fb)) { // Schedule next transmission - value is changed bytud_audio_n_fb_set() in the meantime or the old value gets sent return audiod_fb_send(audio); } } -#endif + #endif #endif } @@ -2411,8 +2253,7 @@ bool audiod_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint3 #if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP -static bool audiod_set_fb_params_freq(audiod_function_t* audio, uint32_t sample_freq, uint32_t mclk_freq) -{ +static bool audiod_set_fb_params_freq(audiod_function_t *audio, uint32_t sample_freq, uint32_t mclk_freq) { // Check if frame interval is within sane limits // The interval value n_frames was taken from the descriptors within audiod_set_interface() @@ -2421,23 +2262,19 @@ static bool audiod_set_fb_params_freq(audiod_function_t* audio, uint32_t sample_ uint32_t const k = (TUSB_SPEED_FULL == tud_speed_get()) ? 10 : 13; uint32_t const n_frame = (1UL << audio->feedback.frame_shift); - if ( (((1UL << k) * sample_freq / mclk_freq) + 1) > n_frame ) - { - TU_LOG1(" UAC2 feedback interval too small\r\n"); TU_BREAKPOINT(); return false; + if ((((1UL << k) * sample_freq / mclk_freq) + 1) > n_frame) { + TU_LOG1(" UAC2 feedback interval too small\r\n"); + TU_BREAKPOINT(); + return false; } // Check if parameters really allow for a power of two division - if ((mclk_freq % sample_freq) == 0 && tu_is_power_of_two(mclk_freq / sample_freq)) - { - audio->feedback.compute_method = AUDIO_FEEDBACK_METHOD_FREQUENCY_POWER_OF_2; + if ((mclk_freq % sample_freq) == 0 && tu_is_power_of_two(mclk_freq / sample_freq)) { + audio->feedback.compute_method = AUDIO_FEEDBACK_METHOD_FREQUENCY_POWER_OF_2; audio->feedback.compute.power_of_2 = (uint8_t) (16 - (audio->feedback.frame_shift - 1) - tu_log2(mclk_freq / sample_freq)); - } - else if ( audio->feedback.compute_method == AUDIO_FEEDBACK_METHOD_FREQUENCY_FLOAT) - { - audio->feedback.compute.float_const = (float)sample_freq / (float) mclk_freq * (1UL << (16 - (audio->feedback.frame_shift - 1))); - } - else - { + } else if (audio->feedback.compute_method == AUDIO_FEEDBACK_METHOD_FREQUENCY_FLOAT) { + audio->feedback.compute.float_const = (float) sample_freq / (float) mclk_freq * (1UL << (16 - (audio->feedback.frame_shift - 1))); + } else { audio->feedback.compute.fixed.sample_freq = sample_freq; audio->feedback.compute.fixed.mclk_freq = mclk_freq; } @@ -2445,84 +2282,75 @@ static bool audiod_set_fb_params_freq(audiod_function_t* audio, uint32_t sample_ return true; } -static void audiod_fb_fifo_count_update(audiod_function_t* audio, uint16_t lvl_new) -{ +static void audiod_fb_fifo_count_update(audiod_function_t *audio, uint16_t lvl_new) { /* Low-pass (averaging) filter */ uint32_t lvl = audio->feedback.compute.fifo_count.fifo_lvl_avg; - lvl = (uint32_t)(((uint64_t)lvl * 63 + ((uint32_t)lvl_new << 16)) >> 6); + lvl = (uint32_t) (((uint64_t) lvl * 63 + ((uint32_t) lvl_new << 16)) >> 6); audio->feedback.compute.fifo_count.fifo_lvl_avg = lvl; uint32_t const ff_lvl = lvl >> 16; uint16_t const ff_thr = audio->feedback.compute.fifo_count.fifo_lvl_thr; - uint16_t const *rate = audio->feedback.compute.fifo_count.rate_const; + uint16_t const *rate = audio->feedback.compute.fifo_count.rate_const; uint32_t feedback; - if(ff_lvl < ff_thr) - { + if (ff_lvl < ff_thr) { feedback = audio->feedback.compute.fifo_count.nom_value + (ff_thr - ff_lvl) * rate[0]; - } else - { + } else { feedback = audio->feedback.compute.fifo_count.nom_value - (ff_lvl - ff_thr) * rate[1]; } - if ( feedback > audio->feedback.max_value ) feedback = audio->feedback.max_value; - if ( feedback < audio->feedback.min_value ) feedback = audio->feedback.min_value; + if (feedback > audio->feedback.max_value) feedback = audio->feedback.max_value; + if (feedback < audio->feedback.min_value) feedback = audio->feedback.min_value; audio->feedback.value = feedback; // Schedule a transmit with the new value if EP is not busy - this triggers repetitive scheduling of the feedback value - if (usbd_edpt_claim(audio->rhport, audio->ep_fb)) - { + if (usbd_edpt_claim(audio->rhport, audio->ep_fb)) { audiod_fb_send(audio); } } -uint32_t tud_audio_feedback_update(uint8_t func_id, uint32_t cycles) -{ - audiod_function_t* audio = &_audiod_fct[func_id]; +uint32_t tud_audio_feedback_update(uint8_t func_id, uint32_t cycles) { + audiod_function_t *audio = &_audiod_fct[func_id]; uint32_t feedback; - switch (audio->feedback.compute_method) - { + switch (audio->feedback.compute_method) { case AUDIO_FEEDBACK_METHOD_FREQUENCY_POWER_OF_2: feedback = (cycles << audio->feedback.compute.power_of_2); - break; + break; case AUDIO_FEEDBACK_METHOD_FREQUENCY_FLOAT: feedback = (uint32_t) ((float) cycles * audio->feedback.compute.float_const); - break; + break; - case AUDIO_FEEDBACK_METHOD_FREQUENCY_FIXED: - { + case AUDIO_FEEDBACK_METHOD_FREQUENCY_FIXED: { uint64_t fb64 = (((uint64_t) cycles) * audio->feedback.compute.fixed.sample_freq) << (16 - (audio->feedback.frame_shift - 1)); feedback = (uint32_t) (fb64 / audio->feedback.compute.fixed.mclk_freq); - } - break; + } break; - default: return 0; + default: + return 0; } // For Windows: https://docs.microsoft.com/en-us/windows-hardware/drivers/audio/usb-2-0-audio-drivers // The size of isochronous packets created by the device must be within the limits specified in FMT-2.0 section 2.3.1.1. // This means that the deviation of actual packet size from nominal size must not exceed +/- one audio slot // (audio slot = channel count samples). - if ( feedback > audio->feedback.max_value ) feedback = audio->feedback.max_value; - if ( feedback < audio->feedback.min_value ) feedback = audio->feedback.min_value; + if (feedback > audio->feedback.max_value) feedback = audio->feedback.max_value; + if (feedback < audio->feedback.min_value) feedback = audio->feedback.min_value; tud_audio_n_fb_set(func_id, feedback); return feedback; } -bool tud_audio_n_fb_set(uint8_t func_id, uint32_t feedback) -{ +bool tud_audio_n_fb_set(uint8_t func_id, uint32_t feedback) { TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL); _audiod_fct[func_id].feedback.value = feedback; // Schedule a transmit with the new value if EP is not busy - this triggers repetitive scheduling of the feedback value - if (usbd_edpt_claim(_audiod_fct[func_id].rhport, _audiod_fct[func_id].ep_fb)) - { + if (usbd_edpt_claim(_audiod_fct[func_id].rhport, _audiod_fct[func_id].ep_fb)) { return audiod_fb_send(&_audiod_fct[func_id]); } @@ -2530,8 +2358,7 @@ bool tud_audio_n_fb_set(uint8_t func_id, uint32_t feedback) } #endif -TU_ATTR_FAST_FUNC void audiod_sof_isr (uint8_t rhport, uint32_t frame_count) -{ +TU_ATTR_FAST_FUNC void audiod_sof_isr(uint8_t rhport, uint32_t frame_count) { (void) rhport; (void) frame_count; @@ -2543,26 +2370,22 @@ TU_ATTR_FAST_FUNC void audiod_sof_isr (uint8_t rhport, uint32_t frame_count) // feedback = n_cycles / n_frames * f_s / f_m in 16.16 format, where n_cycles are the number of main clock cycles within fb_n_frames // Iterate over audio functions and set feedback value - for(uint8_t i=0; i < CFG_TUD_AUDIO; i++) - { - audiod_function_t* audio = &_audiod_fct[i]; + for (uint8_t i = 0; i < CFG_TUD_AUDIO; i++) { + audiod_function_t *audio = &_audiod_fct[i]; - if (audio->ep_fb != 0) - { + if (audio->ep_fb != 0) { // HS shift need to be adjusted since SOF event is generated for frame only uint8_t const hs_adjust = (TUSB_SPEED_HIGH == tud_speed_get()) ? 3 : 0; uint32_t const interval = 1UL << (audio->feedback.frame_shift - hs_adjust); - if ( 0 == (frame_count & (interval-1)) ) - { + if (0 == (frame_count & (interval - 1))) { tud_audio_feedback_interval_isr(i, frame_count, audio->feedback.frame_shift); } } } -#endif // CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP +#endif// CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP } -bool tud_audio_buffer_and_schedule_control_xfer(uint8_t rhport, tusb_control_request_t const * p_request, void* data, uint16_t len) -{ +bool tud_audio_buffer_and_schedule_control_xfer(uint8_t rhport, tusb_control_request_t const *p_request, void *data, uint16_t len) { // Handles only sending of data not receiving if (p_request->bmRequestType_bit.direction == TUSB_DIR_OUT) return false; @@ -2571,85 +2394,73 @@ bool tud_audio_buffer_and_schedule_control_xfer(uint8_t rhport, tusb_control_req uint8_t itf = TU_U16_LOW(p_request->wIndex); // Conduct checks which depend on the recipient - switch (p_request->bmRequestType_bit.recipient) - { - case TUSB_REQ_RCPT_INTERFACE: - { + switch (p_request->bmRequestType_bit.recipient) { + case TUSB_REQ_RCPT_INTERFACE: { uint8_t entityID = TU_U16_HIGH(p_request->wIndex); // Verify if entity is present - if (entityID != 0) - { + if (entityID != 0) { // Find index of audio driver structure and verify entity really exists TU_VERIFY(audiod_verify_entity_exists(itf, entityID, &func_id)); - } - else - { + } else { // Find index of audio driver structure and verify interface really exists TU_VERIFY(audiod_verify_itf_exists(itf, &func_id)); } - } - break; + } break; - case TUSB_REQ_RCPT_ENDPOINT: - { + case TUSB_REQ_RCPT_ENDPOINT: { uint8_t ep = TU_U16_LOW(p_request->wIndex); // Find index of audio driver structure and verify EP really exists TU_VERIFY(audiod_verify_ep_exists(ep, &func_id)); - } - break; + } break; // Unknown/Unsupported recipient - default: TU_LOG2(" Unsupported recipient: %d\r\n", p_request->bmRequestType_bit.recipient); TU_BREAKPOINT(); return false; + default: + TU_LOG2(" Unsupported recipient: %d\r\n", p_request->bmRequestType_bit.recipient); + TU_BREAKPOINT(); + return false; } // Crop length if (len > _audiod_fct[func_id].ctrl_buf_sz) len = _audiod_fct[func_id].ctrl_buf_sz; // 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)); + 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) - { + 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) - { + 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); + return tud_control_xfer(rhport, p_request, (void *) _audiod_fct[func_id].ctrl_buf, len); } // This helper function finds for a given audio function and AS interface number the index of the attached driver structure, the index of the interface in the audio function // (e.g. the std. AS interface with interface number 15 is the first AS interface for the given audio function and thus gets index zero), and // finally a pointer to the std. AS interface, where the pointer always points to the first alternate setting i.e. alternate interface zero. -static bool audiod_get_AS_interface_index(uint8_t itf, audiod_function_t * audio, uint8_t *idxItf, uint8_t const **pp_desc_int) -{ - if (audio->p_desc) - { +static bool audiod_get_AS_interface_index(uint8_t itf, audiod_function_t *audio, uint8_t *idxItf, uint8_t const **pp_desc_int) { + if (audio->p_desc) { // Get pointer at end uint8_t const *p_desc_end = audio->p_desc + audio->desc_length - TUD_AUDIO_DESC_IAD_LEN; // Advance past AC descriptors uint8_t const *p_desc = tu_desc_next(audio->p_desc); - p_desc += ((audio_desc_cs_ac_interface_t const *)p_desc)->wTotalLength; + p_desc += ((audio_desc_cs_ac_interface_t const *) p_desc)->wTotalLength; uint8_t tmp = 0; // Condition modified from p_desc < p_desc_end to prevent gcc>=12 strict-overflow warning - while (p_desc_end - p_desc > 0) - { + while (p_desc_end - p_desc > 0) { // We assume the number of alternate settings is increasing thus we return the index of alternate setting zero! - if (tu_desc_type(p_desc) == TUSB_DESC_INTERFACE && ((tusb_desc_interface_t const * )p_desc)->bAlternateSetting == 0) - { - if (((tusb_desc_interface_t const * )p_desc)->bInterfaceNumber == itf) - { + if (tu_desc_type(p_desc) == TUSB_DESC_INTERFACE && ((tusb_desc_interface_t const *) p_desc)->bAlternateSetting == 0) { + if (((tusb_desc_interface_t const *) p_desc)->bInterfaceNumber == itf) { *idxItf = tmp; *pp_desc_int = p_desc; return true; @@ -2666,14 +2477,11 @@ static bool audiod_get_AS_interface_index(uint8_t itf, audiod_function_t * audio // This helper function finds for a given AS interface number the index of the attached driver structure, the index of the interface in the audio function // (e.g. the std. AS interface with interface number 15 is the first AS interface for the given audio function and thus gets index zero), and // finally a pointer to the std. AS interface, where the pointer always points to the first alternate setting i.e. alternate interface zero. -static bool audiod_get_AS_interface_index_global(uint8_t itf, uint8_t *func_id, uint8_t *idxItf, uint8_t const **pp_desc_int) -{ +static bool audiod_get_AS_interface_index_global(uint8_t itf, uint8_t *func_id, uint8_t *idxItf, uint8_t const **pp_desc_int) { // Loop over audio driver interfaces uint8_t i; - for (i = 0; i < CFG_TUD_AUDIO; i++) - { - if (audiod_get_AS_interface_index(itf, &_audiod_fct[i], idxItf, pp_desc_int)) - { + for (i = 0; i < CFG_TUD_AUDIO; i++) { + if (audiod_get_AS_interface_index(itf, &_audiod_fct[i], idxItf, pp_desc_int)) { *func_id = i; return true; } @@ -2683,23 +2491,19 @@ static bool audiod_get_AS_interface_index_global(uint8_t itf, uint8_t *func_id, } // Verify an entity with the given ID exists and returns also the corresponding driver index -static bool audiod_verify_entity_exists(uint8_t itf, uint8_t entityID, uint8_t *func_id) -{ +static bool audiod_verify_entity_exists(uint8_t itf, uint8_t entityID, uint8_t *func_id) { uint8_t i; - for (i = 0; i < CFG_TUD_AUDIO; i++) - { + for (i = 0; i < CFG_TUD_AUDIO; i++) { // Look for the correct driver by checking if the unique standard AC interface number fits - if (_audiod_fct[i].p_desc && ((tusb_desc_interface_t const *)_audiod_fct[i].p_desc)->bInterfaceNumber == itf) - { + if (_audiod_fct[i].p_desc && ((tusb_desc_interface_t const *) _audiod_fct[i].p_desc)->bInterfaceNumber == itf) { // Get pointers after class specific AC descriptors and end of AC descriptors - entities are defined in between - uint8_t const *p_desc = tu_desc_next(_audiod_fct[i].p_desc); // Points to CS AC descriptor - uint8_t const *p_desc_end = ((audio_desc_cs_ac_interface_t const *)p_desc)->wTotalLength + p_desc; - p_desc = tu_desc_next(p_desc); // Get past CS AC descriptor + uint8_t const *p_desc = tu_desc_next(_audiod_fct[i].p_desc);// Points to CS AC descriptor + uint8_t const *p_desc_end = ((audio_desc_cs_ac_interface_t const *) p_desc)->wTotalLength + p_desc; + p_desc = tu_desc_next(p_desc);// Get past CS AC descriptor // Condition modified from p_desc < p_desc_end to prevent gcc>=12 strict-overflow warning - while (p_desc_end - p_desc > 0) - { - if (p_desc[3] == entityID) // Entity IDs are always at offset 3 + while (p_desc_end - p_desc > 0) { + if (p_desc[3] == entityID)// Entity IDs are always at offset 3 { *func_id = i; return true; @@ -2711,21 +2515,16 @@ static bool audiod_verify_entity_exists(uint8_t itf, uint8_t entityID, uint8_t * return false; } -static bool audiod_verify_itf_exists(uint8_t itf, uint8_t *func_id) -{ +static bool audiod_verify_itf_exists(uint8_t itf, uint8_t *func_id) { uint8_t i; - for (i = 0; i < CFG_TUD_AUDIO; i++) - { - if (_audiod_fct[i].p_desc) - { + for (i = 0; i < CFG_TUD_AUDIO; i++) { + if (_audiod_fct[i].p_desc) { // Get pointer at beginning and end uint8_t const *p_desc = _audiod_fct[i].p_desc; uint8_t const *p_desc_end = _audiod_fct[i].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_INTERFACE && ((tusb_desc_interface_t const *)_audiod_fct[i].p_desc)->bInterfaceNumber == itf) - { + while (p_desc_end - p_desc > 0) { + if (tu_desc_type(p_desc) == TUSB_DESC_INTERFACE && ((tusb_desc_interface_t const *) _audiod_fct[i].p_desc)->bInterfaceNumber == itf) { *func_id = i; return true; } @@ -2736,25 +2535,20 @@ static bool audiod_verify_itf_exists(uint8_t itf, uint8_t *func_id) return false; } -static bool audiod_verify_ep_exists(uint8_t ep, uint8_t *func_id) -{ +static bool audiod_verify_ep_exists(uint8_t ep, uint8_t *func_id) { uint8_t i; - for (i = 0; i < CFG_TUD_AUDIO; i++) - { - if (_audiod_fct[i].p_desc) - { + for (i = 0; i < CFG_TUD_AUDIO; i++) { + if (_audiod_fct[i].p_desc) { // Get pointer at end uint8_t const *p_desc_end = _audiod_fct[i].p_desc + _audiod_fct[i].desc_length; // Advance past AC descriptors - EP we look for are streaming EPs uint8_t const *p_desc = tu_desc_next(_audiod_fct[i].p_desc); - p_desc += ((audio_desc_cs_ac_interface_t const *)p_desc)->wTotalLength; + p_desc += ((audio_desc_cs_ac_interface_t const *) p_desc)->wTotalLength; // 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 && ((tusb_desc_endpoint_t const * )p_desc)->bEndpointAddress == ep) - { + while (p_desc_end - p_desc > 0) { + if (tu_desc_type(p_desc) == TUSB_DESC_ENDPOINT && ((tusb_desc_endpoint_t const *) p_desc)->bEndpointAddress == ep) { *func_id = i; return true; } @@ -2769,81 +2563,73 @@ static bool audiod_verify_ep_exists(uint8_t ep, uint8_t *func_id) // 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! -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) -{ -#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_EP_OUT - if (as_itf != audio->ep_in_as_intf_num && as_itf != audio->ep_out_as_intf_num) return; // Abort, this interface has no EP, this driver does not support this currently -#endif -#if CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_EP_OUT +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) { + #if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_EP_OUT + if (as_itf != audio->ep_in_as_intf_num && as_itf != audio->ep_out_as_intf_num) return;// Abort, this interface has no EP, this driver does not support this currently + #endif + #if CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_EP_OUT if (as_itf != audio->ep_in_as_intf_num) return; -#endif -#if !CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_EP_OUT + #endif + #if !CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_EP_OUT if (as_itf != audio->ep_out_as_intf_num) return; -#endif + #endif - p_desc = tu_desc_next(p_desc); // Exclude standard AS interface descriptor of current alternate interface descriptor + p_desc = tu_desc_next(p_desc);// Exclude standard AS interface descriptor of current alternate interface descriptor // Condition modified from p_desc < p_desc_end to prevent gcc>=12 strict-overflow warning - while (p_desc_end - p_desc > 0) - { + while (p_desc_end - p_desc > 0) { // Abort if follow up descriptor is a new standard interface descriptor - indicates the last AS descriptor was already finished if (tu_desc_type(p_desc) == TUSB_DESC_INTERFACE) break; // Look for a Class-Specific AS Interface Descriptor(4.9.2) to verify format type and format and also to get number of physical channels - if (tu_desc_type(p_desc) == TUSB_DESC_CS_INTERFACE && tu_desc_subtype(p_desc) == AUDIO_CS_AS_INTERFACE_AS_GENERAL) - { -#if CFG_TUD_AUDIO_ENABLE_EP_IN - if (as_itf == audio->ep_in_as_intf_num) - { - audio->n_channels_tx = ((audio_desc_cs_as_interface_t const * )p_desc)->bNrChannels; - audio->format_type_tx = (audio_format_type_t)(((audio_desc_cs_as_interface_t const * )p_desc)->bFormatType); + if (tu_desc_type(p_desc) == TUSB_DESC_CS_INTERFACE && tu_desc_subtype(p_desc) == AUDIO_CS_AS_INTERFACE_AS_GENERAL) { + #if CFG_TUD_AUDIO_ENABLE_EP_IN + if (as_itf == audio->ep_in_as_intf_num) { + audio->n_channels_tx = ((audio_desc_cs_as_interface_t const *) p_desc)->bNrChannels; + audio->format_type_tx = (audio_format_type_t) (((audio_desc_cs_as_interface_t const *) p_desc)->bFormatType); -#if CFG_TUD_AUDIO_ENABLE_TYPE_I_ENCODING - audio->format_type_I_tx = (audio_data_format_type_I_t)(((audio_desc_cs_as_interface_t const * )p_desc)->bmFormats); -#endif + #if CFG_TUD_AUDIO_ENABLE_TYPE_I_ENCODING + audio->format_type_I_tx = (audio_data_format_type_I_t) (((audio_desc_cs_as_interface_t const *) p_desc)->bmFormats); + #endif } -#endif + #endif -#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; - audio->format_type_rx = ((audio_desc_cs_as_interface_t const * )p_desc)->bFormatType; -#if CFG_TUD_AUDIO_ENABLE_TYPE_I_DECODING - audio->format_type_I_rx = ((audio_desc_cs_as_interface_t const * )p_desc)->bmFormats; -#endif + #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; + audio->format_type_rx = ((audio_desc_cs_as_interface_t const *) p_desc)->bFormatType; + #if CFG_TUD_AUDIO_ENABLE_TYPE_I_DECODING + audio->format_type_I_rx = ((audio_desc_cs_as_interface_t const *) p_desc)->bmFormats; + #endif } -#endif + #endif } // 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_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 - if (as_itf != audio->ep_in_as_intf_num && as_itf != audio->ep_out_as_intf_num) break; // Abort loop, this interface has no EP, this driver does not support this currently -#endif -#if CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_EP_OUT + #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 + if (as_itf != audio->ep_in_as_intf_num && as_itf != audio->ep_out_as_intf_num) break;// Abort loop, this interface has no EP, this driver does not support this currently + #endif + #if CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_EP_OUT if (as_itf != audio->ep_in_as_intf_num) break; -#endif -#if !CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_EP_OUT + #endif + #if !CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_EP_OUT if (as_itf != audio->ep_out_as_intf_num) break; -#endif + #endif -#if CFG_TUD_AUDIO_ENABLE_EP_IN - if (as_itf == audio->ep_in_as_intf_num) - { - audio->n_bytes_per_sample_tx = ((audio_desc_type_I_format_t const * )p_desc)->bSubslotSize; + #if CFG_TUD_AUDIO_ENABLE_EP_IN + if (as_itf == audio->ep_in_as_intf_num) { + audio->n_bytes_per_sample_tx = ((audio_desc_type_I_format_t const *) p_desc)->bSubslotSize; } -#endif + #endif -#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_sample_rx = ((audio_desc_type_I_format_t const * )p_desc)->bSubslotSize; + #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_sample_rx = ((audio_desc_type_I_format_t const *) p_desc)->bSubslotSize; } -#endif + #endif } -#endif + #endif // Other format types are not supported yet @@ -2854,8 +2640,7 @@ static void audiod_parse_for_AS_params(audiod_function_t* audio, uint8_t const * #if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_EP_IN_FLOW_CONTROL -static bool audiod_calc_tx_packet_sz(audiod_function_t* audio) -{ +static bool audiod_calc_tx_packet_sz(audiod_function_t *audio) { TU_VERIFY(audio->format_type_tx == AUDIO_FORMAT_TYPE_I); TU_VERIFY(audio->n_channels_tx); TU_VERIFY(audio->n_bytes_per_sample_tx); @@ -2864,25 +2649,23 @@ 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 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 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 = (uint16_t)((sample_normimal - 1) * audio->n_channels_tx * audio->n_bytes_per_sample_tx); - const uint16_t packet_sz_tx_norm = (uint16_t)(sample_normimal * audio->n_channels_tx * audio->n_bytes_per_sample_tx); - const uint16_t packet_sz_tx_max = (uint16_t)((sample_normimal + 1) * audio->n_channels_tx * audio->n_bytes_per_sample_tx); + const uint16_t packet_sz_tx_min = (uint16_t) ((sample_normimal - 1) * audio->n_channels_tx * audio->n_bytes_per_sample_tx); + const uint16_t packet_sz_tx_norm = (uint16_t) (sample_normimal * audio->n_channels_tx * audio->n_bytes_per_sample_tx); + const uint16_t packet_sz_tx_max = (uint16_t) ((sample_normimal + 1) * audio->n_channels_tx * audio->n_bytes_per_sample_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) - { + 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 - { + } 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; @@ -2893,49 +2676,37 @@ static bool audiod_calc_tx_packet_sz(audiod_function_t* audio) 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) -{ +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) - { + 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 < 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) - { + 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) - { + } else if (data_count > fifo_depth / 2 + slot_size && !ctrl_blackout) { packet_size = norminal_size[2]; - if(norminal_size[0] == norminal_size[1]) - { + if (norminal_size[0] == norminal_size[1]) { // nav > INT(nav), eg. 44.1k, 88.2k ctrl_blackout = 0; - } else - { + } else { // nav = INT(nav), eg. 48k, 96k ctrl_blackout = 10; } - } else - { + } else { packet_size = norminal_size[1]; - if (ctrl_blackout) - { + if (ctrl_blackout) { ctrl_blackout--; } } // Normally this cap is not necessary return tu_min16(packet_size, max_depth); - } else - { + } else { return tu_min16(data_count, max_depth); } } @@ -2943,13 +2714,11 @@ static uint16_t audiod_tx_packet_size(const uint16_t* norminal_size, uint16_t da #endif // No security checks here - internal function only which should always succeed -static uint8_t audiod_get_audio_fct_idx(audiod_function_t * audio) -{ - for (uint8_t cnt=0; cnt < CFG_TUD_AUDIO; cnt++) - { +static uint8_t audiod_get_audio_fct_idx(audiod_function_t *audio) { + for (uint8_t cnt = 0; cnt < CFG_TUD_AUDIO; cnt++) { if (&_audiod_fct[cnt] == audio) return cnt; } return 0; } -#endif //CFG_TUD_ENABLED && CFG_TUD_AUDIO +#endif // (CFG_TUD_ENABLED && CFG_TUD_AUDIO) -- cgit v1.3.1 From 3f335df508870a8497cbd52ec2a3032e8dab324e Mon Sep 17 00:00:00 2001 From: shdeb <34346784+shdeb@users.noreply.github.com> Date: Fri, 6 Dec 2024 11:43:54 +0530 Subject: Adding HID Usage Table Physical Input Device Page (0x0F) --- src/class/hid/hid.h | 110 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 110 insertions(+) (limited to 'src/class') diff --git a/src/class/hid/hid.h b/src/class/hid/hid.h index c2b5a8a48..db9a500ee 100644 --- a/src/class/hid/hid.h +++ b/src/class/hid/hid.h @@ -949,6 +949,116 @@ enum { HID_USAGE_FIDO_DATA_OUT = 0x21 // Raw OUT data report }; +/// HID Usage Table: Physical Input Device Page (0x0F) +enum { + HID_USAGE_PID_UNDEFINED = 0x00, + HID_USAGE_PID_PHYSICAL_INPUT_DEVICE = 0x01, + HID_USAGE_PID_NORMAL = 0x20, + HID_USAGE_PID_SET_EFFECT_REPORT = 0x21, + HID_USAGE_PID_EFFECT_PARAMETER_BLOCK_INDEX = 0x22, + HID_USAGE_PID_PARAMETER_BLOCK_OFFSET = 0x23, + HID_USAGE_PID_ROM_FLAG = 0x24, + HID_USAGE_PID_EFFECT_TYPE = 0x25, + HID_USAGE_PID_ET_CONSTANTFORCE = 0x26, + HID_USAGE_PID_ET_RAMP = 0x27, + HID_USAGE_PID_ET_CUSTOMFORCE = 0x28, + HID_USAGE_PID_ET_SQUARE = 0x30, + HID_USAGE_PID_ET_SINE = 0x31, + HID_USAGE_PID_ET_TRIANGLE = 0x32, + HID_USAGE_PID_ET_SAWTOOTH_UP = 0x33, + HID_USAGE_PID_ET_SAWTOOTH_DOWN = 0x34, + HID_USAGE_PID_ET_SPRING = 0x40, + HID_USAGE_PID_ET_DAMPER = 0x41, + HID_USAGE_PID_ET_INERTIA = 0x42, + HID_USAGE_PID_ET_FRICTION = 0x43, + HID_USAGE_PID_DURATION = 0x50, + HID_USAGE_PID_SAMPLE_PERIOD = 0x51, + HID_USAGE_PID_GAIN = 0x52, + HID_USAGE_PID_TRIGGER_BUTTON = 0x53, + HID_USAGE_PID_TRIGGER_REPEAT_INTERVAL = 0x54, + HID_USAGE_PID_AXES_ENABLE = 0x55, + HID_USAGE_PID_DIRECTION_ENABLE = 0x56, + HID_USAGE_PID_DIRECTION = 0x57, + HID_USAGE_PID_TYPE_SPECIFIC_BLOCK_OFFSET = 0x58, + HID_USAGE_PID_BLOCK_TYPE = 0x59, + HID_USAGE_PID_SET_ENVELOPE_REPORT = 0x5a, + HID_USAGE_PID_ATTACK_LEVEL = 0x5b, + HID_USAGE_PID_ATTACK_TIME = 0x5c, + HID_USAGE_PID_FADE_LEVEL = 0x5d, + HID_USAGE_PID_FADE_TIME = 0x5e, + HID_USAGE_PID_SET_CONDITION_REPORT = 0x5f, + HID_USAGE_PID_CENTERPOINT_OFFSET = 0x60, + HID_USAGE_PID_POSITIVE_COEFFICIENT = 0x61, + HID_USAGE_PID_NEGATIVE_COEFFICIENT = 0x62, + HID_USAGE_PID_POSITIVE_SATURATION = 0x63, + HID_USAGE_PID_NEGATIVE_SATURATION = 0x64, + HID_USAGE_PID_DEAD_BAND = 0x65, + HID_USAGE_PID_DOWNLOAD_FORCE_SAMPLE = 0x66, + HID_USAGE_PID_ISOCH_CUSTOMFORCE_ENABLE = 0x67, + HID_USAGE_PID_CUSTOMFORCE_DATA_REPORT = 0x68, + HID_USAGE_PID_CUSTOMFORCE_DATA = 0x69, + HID_USAGE_PID_CUSTOMFORCE_VENDOR_DEFINED_DATA = 0x6a, + HID_USAGE_PID_SET_CUSTOMFORCE_REPORT = 0x6b, + HID_USAGE_PID_CUSTOMFORCE_DATA_OFFSET = 0x6c, + HID_USAGE_PID_SAMPLE_COUNT = 0x6d, + HID_USAGE_PID_SET_PERIODIC_REPORT = 0x6e, + HID_USAGE_PID_OFFSET = 0x6f, + HID_USAGE_PID_MAGNITUDE = 0x70, + HID_USAGE_PID_PHASE = 0x71, + HID_USAGE_PID_PERIOD = 0x72, + HID_USAGE_PID_SET_CONSTANTFORCE_REPORT = 0x73, + HID_USAGE_PID_SET_RAMPFORCE_REPORT = 0x74, + HID_USAGE_PID_RAMP_START = 0x75, + HID_USAGE_PID_RAMP_END = 0x76, + HID_USAGE_PID_EFFECT_OPERATION_REPORT = 0x77, + HID_USAGE_PID_EFFECT_OPERATION = 0x78, + HID_USAGE_PID_OP_EFFECT_START = 0x79, + HID_USAGE_PID_OP_EFFECT_START_SOLO = 0x7a, + HID_USAGE_PID_OP_EFFECT_STOP = 0x7b, + HID_USAGE_PID_LOOP_COUNT = 0x7c, + HID_USAGE_PID_DEVICE_GAIN_REPORT = 0x7d, + HID_USAGE_PID_DEVICE_GAIN = 0x7e, + HID_USAGE_PID_PARAMETER_BLOCK_POOLS_REPORT = 0x7f, + HID_USAGE_PID_RAM_POOL_SIZE = 0x80, + HID_USAGE_PID_ROM_POOL_SIZE = 0x81, + HID_USAGE_PID_ROM_EFFECT_BLOCK_COUNT = 0x82, + HID_USAGE_PID_SIMULTANEOUS_EFFECTS_MAX = 0x83, + HID_USAGE_PID_POOL_ALIGNMENT = 0x84, + HID_USAGE_PID_PARAMETER_BLOCK_MOVE_REPORT = 0x85, + HID_USAGE_PID_MOVE_SOURCE = 0x86, + HID_USAGE_PID_MOVE_DESTINATION = 0x87, + HID_USAGE_PID_MOVE_LENGTH = 0x88, + HID_USAGE_PID_EFFECT_PARAMETER_BLOCK_LOAD_REPORT = 0x89, + HID_USAGE_PID_EFFECT_PARAMETER_BLOCK_LOAD_STATUS = 0x8b, + HID_USAGE_PID_BLOCK_LOAD_SUCCESS = 0x8c, + HID_USAGE_PID_BLOCK_LOAD_FULL = 0x8d, + HID_USAGE_PID_BLOCK_LOAD_ERROR = 0x8e, + HID_USAGE_PID_BLOCK_HANDLE = 0x8f, + HID_USAGE_PID_EFFECT_PARAMETER_BLOCK_FREE_REPORT = 0x90, + HID_USAGE_PID_TYPE_SPECIFIC_BLOCK_HANDLE = 0x91, + HID_USAGE_PID_PID_STATE_REPORT = 0x92, + HID_USAGE_PID_EFFECT_PLAYING = 0x94, + HID_USAGE_PID_PID_DEVICE_CONTROL_REPORT = 0x95, + HID_USAGE_PID_PID_DEVICE_CONTROL = 0x96, + HID_USAGE_PID_DC_ENABLE_ACTUATORS = 0x97, + HID_USAGE_PID_DC_DISABLE_ACTUATORS = 0x98, + HID_USAGE_PID_DC_STOP_ALL_EFFECTS = 0x99, + HID_USAGE_PID_DC_RESET = 0x9a, + HID_USAGE_PID_DC_PAUSE = 0x9b, + HID_USAGE_PID_DC_CONTINUE = 0x9c, + HID_USAGE_PID_DEVICE_PAUSED = 0x9f, + HID_USAGE_PID_ACTUATORS_ENABLED = 0xa0, + HID_USAGE_PID_SAFETY_SWITCH = 0xa4, + HID_USAGE_PID_ACTUATOR_OVERRIDE_SWITCH = 0xa5, + HID_USAGE_PID_ACTUATOR_POWER = 0xa6, + HID_USAGE_PID_START_DELAY = 0xa7, + HID_USAGE_PID_PARAMETER_BLOCK_SIZE = 0xa8, + HID_USAGE_PID_DEVICEMANAGED_POOL = 0xa9, + HID_USAGE_PID_SHARED_PARAMETER_BLOCKS = 0xaa, + HID_USAGE_PID_CREATE_NEW_EFFECT_PARAMETER_BLOCK_REPORT = 0xab, + HID_USAGE_PID_RAM_POOL_AVAILABLE = 0xac, +}; + /*-------------------------------------------------------------------- * ASCII to KEYCODE Conversion * Expand to array of [128][2] (shift, keycode) -- cgit v1.3.1 From 15b1623aa3b677100cb7e81bf05f0c3b481d355b Mon Sep 17 00:00:00 2001 From: Jay <33371449+jay94ks@users.noreply.github.com> Date: Mon, 23 Dec 2024 22:03:37 +0900 Subject: add hid stylus pen device. this works with android, for bypassing that absmouse does not support android. note that, to hide cursor on android for every touch signal, find cursor option in android settings menu. references: 1. https://stackoverflow.com/questions/28536602/hid-digitizer-descriptor-doesnt-perform-well-with-landscape-orientation 2. https://github.com/jonathanedgecombe/absmouse/blob/master/src/AbsMouse.cpp --- examples/device/hid_composite/src/main.c | 34 +++++++++++++++++- .../device/hid_composite/src/usb_descriptors.c | 1 + .../device/hid_composite/src/usb_descriptors.h | 1 + src/class/hid/hid.h | 34 ++++++++++++++++++ src/class/hid/hid_device.c | 10 ++++++ src/class/hid/hid_device.h | 42 ++++++++++++++++++++++ 6 files changed, 121 insertions(+), 1 deletion(-) (limited to 'src/class') diff --git a/examples/device/hid_composite/src/main.c b/examples/device/hid_composite/src/main.c index 5302af3b8..958d8f4af 100644 --- a/examples/device/hid_composite/src/main.c +++ b/examples/device/hid_composite/src/main.c @@ -197,11 +197,43 @@ static void send_hid_report(uint8_t report_id, uint32_t btn) } } break; - default: break; } } +/* use this to send stylus touch signal through USB. */ +static void send_stylus_touch(uint16_t x, uint16_t y, bool state) +{ + // skip if hid is not ready yet + if ( !tud_hid_ready() ) return; + + static bool has_stylus_pen = false; + + hid_stylus_report_t report = + { + .attr = 0, + .x = 0, + .y = 0 + }; + + report.x = x; + report.y = y; + + if (state) + { + report.attr = STYLUS_ATTR_TIP_SWITCH | STYLUS_ATTR_IN_RANGE; + tud_hid_report(REPORT_ID_STYLUS_PEN, &report, sizeof(report)); + + has_stylus_pen = true; + }else + { + report.attr = 0; + if (has_stylus_pen) tud_hid_report(REPORT_ID_STYLUS_PEN, &report, sizeof(report)); + has_stylus_pen = false; + } + +} + // Every 10ms, we will sent 1 report for each HID profile (keyboard, mouse etc ..) // tud_hid_report_complete_cb() is used to send the next report after previous one is complete void hid_task(void) diff --git a/examples/device/hid_composite/src/usb_descriptors.c b/examples/device/hid_composite/src/usb_descriptors.c index e174db46d..15c6e1f73 100644 --- a/examples/device/hid_composite/src/usb_descriptors.c +++ b/examples/device/hid_composite/src/usb_descriptors.c @@ -79,6 +79,7 @@ uint8_t const desc_hid_report[] = { TUD_HID_REPORT_DESC_KEYBOARD( HID_REPORT_ID(REPORT_ID_KEYBOARD )), TUD_HID_REPORT_DESC_MOUSE ( HID_REPORT_ID(REPORT_ID_MOUSE )), + TUD_HID_REPORT_DESC_STYLUS_PEN( HID_REPORT_ID(REPORT_ID_STYLUS_PEN )), TUD_HID_REPORT_DESC_CONSUMER( HID_REPORT_ID(REPORT_ID_CONSUMER_CONTROL )), TUD_HID_REPORT_DESC_GAMEPAD ( HID_REPORT_ID(REPORT_ID_GAMEPAD )) }; diff --git a/examples/device/hid_composite/src/usb_descriptors.h b/examples/device/hid_composite/src/usb_descriptors.h index e733d31dd..18d31172b 100644 --- a/examples/device/hid_composite/src/usb_descriptors.h +++ b/examples/device/hid_composite/src/usb_descriptors.h @@ -29,6 +29,7 @@ enum { REPORT_ID_KEYBOARD = 1, REPORT_ID_MOUSE, + REPORT_ID_STYLUS_PEN, REPORT_ID_CONSUMER_CONTROL, REPORT_ID_GAMEPAD, REPORT_ID_COUNT diff --git a/src/class/hid/hid.h b/src/class/hid/hid.h index db9a500ee..fb27c0d0e 100644 --- a/src/class/hid/hid.h +++ b/src/class/hid/hid.h @@ -325,6 +325,29 @@ typedef enum /// @} +//--------------------------------------------------------------------+ +// Digitizer Stylus Pen +//--------------------------------------------------------------------+ +/** \addtogroup ClassDriver_HID_Stylus Stylus + * @{ */ + +// Standard Stylus Pen Report. +typedef struct TU_ATTR_PACKED +{ + uint8_t attr; /**< Attribute mask for describing current status of the stylus pen. */ + uint16_t x; /**< Current x position of the mouse. */ + uint16_t y; /**< Current y position of the mouse. */ +} hid_stylus_report_t; + +// Standard Stylus Pen Attributes Bitmap. +typedef enum +{ + STYLUS_ATTR_TIP_SWITCH = TU_BIT(0), ///< Tip switch + STYLUS_ATTR_IN_RANGE = TU_BIT(1), ///< In-range bit. +} hid_stylus_attr_bm_t; + +/// @} + //--------------------------------------------------------------------+ // Keyboard //--------------------------------------------------------------------+ @@ -760,7 +783,9 @@ enum { HID_USAGE_PAGE_PID = 0x0f, HID_USAGE_PAGE_UNICODE = 0x10, HID_USAGE_PAGE_ALPHA_DISPLAY = 0x14, + HID_USAGE_PAGE_IN_RANGE = 0x32, HID_USAGE_PAGE_MEDICAL = 0x40, + HID_USAGE_PAGE_TIP_SWITCH = 0x42, HID_USAGE_PAGE_LIGHTING_AND_ILLUMINATION = 0x59, HID_USAGE_PAGE_MONITOR = 0x80, // 0x80 - 0x83 HID_USAGE_PAGE_POWER = 0x84, // 0x084 - 0x87 @@ -846,6 +871,15 @@ enum { HID_USAGE_DESKTOP_SYSTEM_DISPLAY_LCD_AUTOSCALE = 0xB7 }; +/// HID Usage Table: Digitizer Page (0x0D) +enum { + // Touch Screen. + HID_USAGE_DIGITIZER_TOUCH_SCREEN = 0x04, + + // Stylus Pen. + HID_USAGE_DIGITIZER_STYLUS = 0x20, +}; + /// HID Usage Table: Consumer Page (0x0C) /// Only contains controls that supported by Windows (whole list is too long) diff --git a/src/class/hid/hid_device.c b/src/class/hid/hid_device.c index eedcba984..b4f24902b 100644 --- a/src/class/hid/hid_device.c +++ b/src/class/hid/hid_device.c @@ -194,6 +194,16 @@ bool tud_hid_n_gamepad_report(uint8_t instance, uint8_t report_id, return tud_hid_n_report(instance, report_id, &report, sizeof(report)); } +bool tud_hid_n_stylus_report(uint8_t instance, uint8_t report_id, uint8_t attrs, uint16_t x, uint16_t y) { + hid_stylus_report_t report = { + .attr = attrs, + .x = x, + .y = y, + }; + + return tud_hid_n_report(instance, report_id, &report, sizeof(report)); +} + //--------------------------------------------------------------------+ // USBD-CLASS API //--------------------------------------------------------------------+ diff --git a/src/class/hid/hid_device.h b/src/class/hid/hid_device.h index ab2e27373..513d6e996 100644 --- a/src/class/hid/hid_device.h +++ b/src/class/hid/hid_device.h @@ -79,6 +79,9 @@ bool tud_hid_n_abs_mouse_report(uint8_t instance, uint8_t report_id, uint8_t but // 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); +// STYLUS PEN: convenient helper to send absolute stylus pen report if application +bool tud_hid_n_stylus_report(uint8_t instance, uint8_t report_id, uint8_t attrs, uint16_t x, uint16_t y); + //--------------------------------------------------------------------+ // Application API (Single Port) //--------------------------------------------------------------------+ @@ -114,6 +117,10 @@ TU_ATTR_ALWAYS_INLINE static inline bool tud_hid_gamepad_report(uint8_t report_i return tud_hid_n_gamepad_report(0, report_id, x, y, z, rz, rx, ry, hat, buttons); } +TU_ATTR_ALWAYS_INLINE static inline bool tud_hid_stylus_report(uint8_t report_id, uint8_t attrs, uint16_t x, uint16_t y) { + return tud_hid_n_stylus_report(0, report_id, attrs, x, y); +} + //--------------------------------------------------------------------+ // Application Callbacks //--------------------------------------------------------------------+ @@ -257,6 +264,41 @@ void tud_hid_report_failed_cb(uint8_t instance, hid_report_type_t report_type, u HID_COLLECTION_END , \ HID_COLLECTION_END \ +// Stylus Pen Report Descriptor Template +#define TUD_HID_REPORT_DESC_STYLUS_PEN(...) \ + HID_USAGE_PAGE ( HID_USAGE_PAGE_DIGITIZER ) , \ + HID_USAGE ( HID_USAGE_DIGITIZER_TOUCH_SCREEN ) , \ + HID_COLLECTION ( HID_COLLECTION_APPLICATION ) , \ + /* Report ID if any */\ + __VA_ARGS__ \ + HID_USAGE ( HID_USAGE_DIGITIZER_STYLUS ) , \ + HID_COLLECTION ( HID_COLLECTION_PHYSICAL ) , \ + HID_USAGE_PAGE ( HID_USAGE_PAGE_TIP_SWITCH ) , \ + HID_USAGE_PAGE ( HID_USAGE_PAGE_IN_RANGE ) , \ + HID_LOGICAL_MIN ( 0 ), \ + HID_LOGICAL_MAX ( 1 ), \ + HID_REPORT_SIZE ( 1 ), \ + HID_REPORT_COUNT( 2 ), \ + HID_INPUT ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE ), \ + HID_REPORT_SIZE ( 1 ), \ + HID_REPORT_COUNT( 6 ), \ + HID_INPUT ( HID_CONSTANT | HID_ARRAY | HID_ABSOLUTE), \ + HID_USAGE_PAGE ( HID_USAGE_PAGE_DESKTOP ), \ + HID_PHYSICAL_MAX( 0x7fff ), \ + HID_LOGICAL_MAX ( 0x7fff ), \ + HID_REPORT_SIZE ( 16 ), \ + HID_REPORT_COUNT( 1 ), \ + HID_UNIT_EXPONENT( -1 ), \ + HID_UNIT ( HID_VARIABLE | HID_NONLINEAR ), \ + HID_PHYSICAL_MIN( 0 ), \ + HID_PHYSICAL_MAX( 0 ), \ + HID_USAGE ( HID_USAGE_DESKTOP_X ), \ + HID_INPUT ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE ), \ + HID_USAGE ( HID_USAGE_DESKTOP_Y ), \ + HID_INPUT ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE ), \ + HID_COLLECTION_END , \ + HID_COLLECTION_END \ + // Absolute Mouse Report Descriptor Template #define TUD_HID_REPORT_DESC_ABSMOUSE(...) \ HID_USAGE_PAGE ( HID_USAGE_PAGE_DESKTOP ) ,\ -- cgit v1.3.1 From 7e59b595f43c906e4bf207861762bf93e772d4f8 Mon Sep 17 00:00:00 2001 From: Jay <33371449+jay94ks@users.noreply.github.com> Date: Mon, 23 Dec 2024 22:09:59 +0900 Subject: Update hid_device.h --- src/class/hid/hid_device.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/class') diff --git a/src/class/hid/hid_device.h b/src/class/hid/hid_device.h index 513d6e996..79b8a695e 100644 --- a/src/class/hid/hid_device.h +++ b/src/class/hid/hid_device.h @@ -284,8 +284,8 @@ void tud_hid_report_failed_cb(uint8_t instance, hid_report_type_t report_type, u HID_REPORT_COUNT( 6 ), \ HID_INPUT ( HID_CONSTANT | HID_ARRAY | HID_ABSOLUTE), \ HID_USAGE_PAGE ( HID_USAGE_PAGE_DESKTOP ), \ - HID_PHYSICAL_MAX( 0x7fff ), \ - HID_LOGICAL_MAX ( 0x7fff ), \ + HID_PHYSICAL_MAX_N( 0x7fff, 2 ), \ + HID_LOGICAL_MAX_N ( 0x7fff, 2 ), \ HID_REPORT_SIZE ( 16 ), \ HID_REPORT_COUNT( 1 ), \ HID_UNIT_EXPONENT( -1 ), \ -- cgit v1.3.1 From eb1c2b83ef09e87964d1d801c3b78caf924af63b Mon Sep 17 00:00:00 2001 From: Jay <33371449+jay94ks@users.noreply.github.com> Date: Mon, 23 Dec 2024 22:19:35 +0900 Subject: trimed trailing whitespaces. --- examples/device/hid_composite/src/main.c | 2 +- src/class/hid/hid.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'src/class') diff --git a/examples/device/hid_composite/src/main.c b/examples/device/hid_composite/src/main.c index bc12d2a93..a58107b6f 100644 --- a/examples/device/hid_composite/src/main.c +++ b/examples/device/hid_composite/src/main.c @@ -209,7 +209,7 @@ static void send_stylus_touch(uint16_t x, uint16_t y, bool state) static bool has_stylus_pen = false; - hid_stylus_report_t report = + hid_stylus_report_t report = { .attr = 0, .x = 0, diff --git a/src/class/hid/hid.h b/src/class/hid/hid.h index fb27c0d0e..b179fc72a 100644 --- a/src/class/hid/hid.h +++ b/src/class/hid/hid.h @@ -340,7 +340,7 @@ typedef struct TU_ATTR_PACKED } hid_stylus_report_t; // Standard Stylus Pen Attributes Bitmap. -typedef enum +typedef enum { STYLUS_ATTR_TIP_SWITCH = TU_BIT(0), ///< Tip switch STYLUS_ATTR_IN_RANGE = TU_BIT(1), ///< In-range bit. -- cgit v1.3.1 From 5c4e4b1bc273b771411660e1b6fbe81c2e8fd90b Mon Sep 17 00:00:00 2001 From: Jay <33371449+jay94ks@users.noreply.github.com> Date: Mon, 23 Dec 2024 22:26:08 +0900 Subject: modified invalid marked unit exponent. --- src/class/hid/hid_device.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/class') diff --git a/src/class/hid/hid_device.h b/src/class/hid/hid_device.h index 79b8a695e..f6704c51a 100644 --- a/src/class/hid/hid_device.h +++ b/src/class/hid/hid_device.h @@ -288,7 +288,7 @@ void tud_hid_report_failed_cb(uint8_t instance, hid_report_type_t report_type, u HID_LOGICAL_MAX_N ( 0x7fff, 2 ), \ HID_REPORT_SIZE ( 16 ), \ HID_REPORT_COUNT( 1 ), \ - HID_UNIT_EXPONENT( -1 ), \ + HID_UNIT_EXPONENT( 0x0f ), \ HID_UNIT ( HID_VARIABLE | HID_NONLINEAR ), \ HID_PHYSICAL_MIN( 0 ), \ HID_PHYSICAL_MAX( 0 ), \ -- cgit v1.3.1 From 679065c3d6ce7e219f1d45db0ad9f132f8ab93dd Mon Sep 17 00:00:00 2001 From: Tomas Rezucha Date: Tue, 14 Jan 2025 16:56:24 +0100 Subject: fix(ncm): Use IN buffer for transmit checks --- src/class/net/ncm_device.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/class') diff --git a/src/class/net/ncm_device.c b/src/class/net/ncm_device.c index 4e6088340..aac11a058 100644 --- a/src/class/net/ncm_device.c +++ b/src/class/net/ncm_device.c @@ -390,7 +390,7 @@ static bool xmit_requested_datagram_fits_into_current_ntb(uint16_t datagram_size 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) { + if (ncm_interface.xmit_glue_ntb->nth.wBlockLength + datagram_size + XMIT_ALIGN_OFFSET(datagram_size) > CFG_TUD_NCM_IN_NTB_MAX_SIZE) { return false; } return true; @@ -674,7 +674,7 @@ static void recv_transfer_datagram_to_glue_logic(void) { 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); + TU_ASSERT(size <= CFG_TUD_NCM_IN_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 @@ -709,7 +709,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) { + if (ntb->nth.wBlockLength > CFG_TUD_NCM_IN_NTB_MAX_SIZE) { TU_LOG_DRV("(EE) tud_network_xmit: buffer overflow\n"); // must not happen (really) return; } -- cgit v1.3.1 From 76fe0393edbc1b1ff80e3a333c233c81f1fc5d67 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Tue, 14 Jan 2025 17:01:43 -0500 Subject: src/class/hid/hid_host.c: fix logging calls for epbuf --- src/class/hid/hid_host.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/class') diff --git a/src/class/hid/hid_host.c b/src/class/hid/hid_host.c index eef584d74..a3cc7d6d7 100644 --- a/src/class/hid/hid_host.c +++ b/src/class/hid/hid_host.c @@ -410,7 +410,7 @@ bool tuh_hid_send_report(uint8_t daddr, uint8_t idx, uint8_t report_id, const vo ++len; // 1 more byte for report_id } - TU_LOG3_MEM(p_hid->epout_buf, len, 2); + TU_LOG3_MEM(epbuf->epout, len, 2); if (!usbh_edpt_xfer(daddr, p_hid->ep_out, epbuf->epout, len)) { usbh_edpt_release(daddr, p_hid->ep_out); @@ -445,7 +445,7 @@ bool hidh_xfer_cb(uint8_t daddr, uint8_t ep_addr, xfer_result_t result, uint32_t 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); + TU_LOG3_MEM(epbuf->epin, xferred_bytes, 2); tuh_hid_report_received_cb(daddr, idx, epbuf->epin, (uint16_t) xferred_bytes); } else { if (tuh_hid_report_sent_cb) { -- cgit v1.3.1 From 6476ff12417be6df834333410f4fb2e64049fe7a Mon Sep 17 00:00:00 2001 From: Tomas Rezucha Date: Wed, 15 Jan 2025 19:16:58 +0100 Subject: fix(ncm): Return invalid NTBs to free list In case we received invalid datagram, we silently fail a the buffer was not returned to empty list -> it was lost. If this happened more than CFG_TUD_NCM_OUT_NTB_N times, we run out of NTBs and all OUT transfers are NACKed. Closes https://github.com/espressif/esp-usb/issues/107 --- src/class/net/ncm_device.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/class') diff --git a/src/class/net/ncm_device.c b/src/class/net/ncm_device.c index aac11a058..f9fda0698 100644 --- a/src/class/net/ncm_device.c +++ b/src/class/net/ncm_device.c @@ -857,7 +857,8 @@ bool netd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_ // - 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"); + TU_LOG_DRV("Invalid datatagram. Ignoring NTB\n"); + recv_put_ntb_into_free_list(ncm_interface.recv_tinyusb_ntb); } else { // packet ok -> put it into ready list recv_put_ntb_into_ready_list(ncm_interface.recv_tinyusb_ntb); -- cgit v1.3.1 From cc626f35d212aef86b0aa7275eea016ae69b5de4 Mon Sep 17 00:00:00 2001 From: HiFiPhile Date: Wed, 29 Jan 2025 15:16:02 +0100 Subject: msc_device: add async IO support. Signed-off-by: HiFiPhile --- src/class/msc/msc_device.c | 180 ++++++++++++++++++++++++++++++++------------- src/class/msc/msc_device.h | 16 ++++ 2 files changed, 145 insertions(+), 51 deletions(-) (limited to 'src/class') diff --git a/src/class/msc/msc_device.c b/src/class/msc/msc_device.c index dd66bfb6f..c7c926f4e 100644 --- a/src/class/msc/msc_device.c +++ b/src/class/msc/msc_device.c @@ -52,10 +52,18 @@ enum { MSC_STAGE_NEED_RESET, }; +enum { + MSC_NEXT_OP_NONE = 0, + MSC_NEXT_OP_READ10, + MSC_NEXT_OP_WRITE10, + MSC_NEXT_OP_STATUS +}; + typedef struct { TU_ATTR_ALIGNED(4) msc_cbw_t cbw; TU_ATTR_ALIGNED(4) msc_csw_t csw; + uint8_t rhport; uint8_t itf_num; uint8_t ep_in; uint8_t ep_out; @@ -70,6 +78,10 @@ typedef struct { uint8_t sense_key; uint8_t add_sense_code; uint8_t add_sense_qualifier; +#if CFG_TUD_MSC_ASYNC_IO + uint8_t next_op; + uint32_t xferred_bytes; +#endif }mscd_interface_t; static mscd_interface_t _mscd_itf; @@ -82,31 +94,39 @@ CFG_TUD_MEM_SECTION static struct { // INTERNAL OBJECT & FUNCTION DECLARATION //--------------------------------------------------------------------+ static int32_t proc_builtin_scsi(uint8_t lun, uint8_t const scsi_cmd[16], uint8_t* buffer, uint32_t bufsize); -static void proc_read10_cmd(uint8_t rhport, mscd_interface_t* p_msc); - -static void proc_write10_cmd(uint8_t rhport, mscd_interface_t* p_msc); -static void proc_write10_new_data(uint8_t rhport, mscd_interface_t* p_msc, uint32_t xferred_bytes); +static void proc_read10_cmd(mscd_interface_t* p_msc); +static void proc_read10_next(mscd_interface_t* p_msc, int32_t nbytes); +static void proc_write10_cmd(mscd_interface_t* p_msc); +static void proc_write10_new_data(mscd_interface_t* p_msc, uint32_t xferred_bytes); +static void proc_write10_next(mscd_interface_t* p_msc, uint32_t xferred_bytes, int32_t nbytes); +static bool proc_stage_status(mscd_interface_t* p_msc); +#if CFG_TUD_MSC_ASYNC_IO +static void tud_msc_async_io_done_cb(void* bytes_processed); +#endif TU_ATTR_ALWAYS_INLINE static inline bool is_data_in(uint8_t dir) { return tu_bit_test(dir, 7); } -static inline bool send_csw(uint8_t rhport, mscd_interface_t* p_msc) { +static inline bool send_csw(mscd_interface_t* p_msc) { // Data residue is always = host expect - actual transferred + uint8_t rhport = p_msc->rhport; p_msc->csw.data_residue = p_msc->cbw.total_bytes - p_msc->xferred_len; p_msc->stage = MSC_STAGE_STATUS_SENT; memcpy(_mscd_epbuf.buf, &p_msc->csw, sizeof(msc_csw_t)); return usbd_edpt_xfer(rhport, p_msc->ep_in , _mscd_epbuf.buf, sizeof(msc_csw_t)); } -static inline bool prepare_cbw(uint8_t rhport, mscd_interface_t* p_msc) { +static inline bool prepare_cbw(mscd_interface_t* p_msc) { + uint8_t rhport = p_msc->rhport; p_msc->stage = MSC_STAGE_CMD; return usbd_edpt_xfer(rhport, p_msc->ep_out, _mscd_epbuf.buf, sizeof(msc_cbw_t)); } -static void fail_scsi_op(uint8_t rhport, mscd_interface_t* p_msc, uint8_t status) { +static void fail_scsi_op(mscd_interface_t* p_msc, uint8_t status) { msc_cbw_t const * p_cbw = &p_msc->cbw; msc_csw_t * p_csw = &p_msc->csw; + uint8_t rhport = p_msc->rhport; p_csw->status = status; p_csw->data_residue = p_msc->cbw.total_bytes - p_msc->xferred_len; @@ -177,6 +197,32 @@ static uint8_t rdwr10_validate_cmd(msc_cbw_t const* cbw) { return status; } +static bool proc_stage_status(mscd_interface_t* p_msc) { + uint8_t rhport = p_msc->rhport; + msc_cbw_t const* p_cbw = &p_msc->cbw; + // skip status if epin is currently stalled, will do it when received Clear Stall request + if (!usbd_edpt_stalled(rhport, p_msc->ep_in)) { + if ((p_cbw->total_bytes > p_msc->xferred_len) && is_data_in(p_cbw->dir)) { + // 6.7 The 13 Cases: case 5 (Hi > Di): STALL before status + // TU_LOG(MSC_DEBUG, " SCSI case 5 (Hi > Di): %lu > %lu\r\n", p_cbw->total_bytes, p_msc->xferred_len); + usbd_edpt_stall(rhport, p_msc->ep_in); + } else { + TU_ASSERT(send_csw(p_msc)); + } + } + + #if TU_CHECK_MCU(OPT_MCU_CXD56) + // WORKAROUND: cxd56 has its own nuttx usb stack which does not forward Set/ClearFeature(Endpoint) to DCD. + // There is no way for us to know when EP is un-stall, therefore we will unconditionally un-stall here and + // hope everything will work + if ( usbd_edpt_stalled(rhport, p_msc->ep_in) ) { + usbd_edpt_clear_stall(rhport, p_msc->ep_in); + send_csw(p_msc); + } + #endif + return true; +} + //--------------------------------------------------------------------+ // Debug //--------------------------------------------------------------------+ @@ -219,6 +265,32 @@ static inline void set_sense_medium_not_present(uint8_t lun) { tud_msc_set_sense(lun, SCSI_SENSE_NOT_READY, 0x3A, 0x00); } +#if CFG_TUD_MSC_ASYNC_IO +void tud_msc_async_io_done(int32_t bytes_processed) { + // Precheck to avoid queueing multiple RW done callback + TU_VERIFY(_mscd_itf.next_op != MSC_NEXT_OP_NONE,); + // Call usbd_edpt_xfer() in tud_task() to avoid racing condition + usbd_defer_func(tud_msc_async_io_done_cb, (void*) bytes_processed, false); +} + +static void tud_msc_async_io_done_cb(void* bytes_processed) { + TU_VERIFY(_mscd_itf.next_op != MSC_NEXT_OP_NONE,); + uint8_t next_op = _mscd_itf.next_op; + _mscd_itf.next_op = MSC_NEXT_OP_NONE; + int32_t nbytes = (int32_t)bytes_processed; + // READ10 + if (next_op == MSC_NEXT_OP_READ10) { + proc_read10_next(&_mscd_itf, nbytes); + } else if (next_op == MSC_NEXT_OP_WRITE10) { + proc_write10_next(&_mscd_itf, _mscd_itf.xferred_bytes, nbytes); + // Need to manually invoke CSW transfer + if (_mscd_itf.stage == MSC_STAGE_STATUS) { + proc_stage_status(&_mscd_itf); + } + } +} +#endif + //--------------------------------------------------------------------+ // USBD Driver API //--------------------------------------------------------------------+ @@ -245,12 +317,13 @@ uint16_t mscd_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint1 mscd_interface_t * p_msc = &_mscd_itf; p_msc->itf_num = itf_desc->bInterfaceNumber; + p_msc->rhport = rhport; // Open endpoint pair TU_ASSERT(usbd_open_edpt_pair(rhport, tu_desc_next(itf_desc), 2, TUSB_XFER_BULK, &p_msc->ep_out, &p_msc->ep_in), 0); // Prepare for Command Block Wrapper - TU_ASSERT(prepare_cbw(rhport, p_msc), drv_len); + TU_ASSERT(prepare_cbw(p_msc), drv_len); return drv_len; } @@ -289,14 +362,14 @@ bool mscd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t if (ep_addr == p_msc->ep_in) { if (p_msc->stage == MSC_STAGE_STATUS) { // resume sending SCSI status if we are in this stage previously before stalled - TU_ASSERT(send_csw(rhport, p_msc)); + TU_ASSERT(send_csw(p_msc)); } } else if (ep_addr == p_msc->ep_out) { if (p_msc->stage == MSC_STAGE_CMD) { // part of reset recovery (probably due to invalid CBW) -> prepare for new command // Note: skip if already queued previously if (usbd_edpt_ready(rhport, p_msc->ep_out)) { - TU_ASSERT(prepare_cbw(rhport, p_msc)); + TU_ASSERT(prepare_cbw(p_msc)); } } } @@ -344,7 +417,7 @@ bool mscd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t msc_csw_t * p_csw = &p_msc->csw; switch (p_msc->stage) { - case MSC_STAGE_CMD: + case MSC_STAGE_CMD: { //------------- new CBW received -------------// // Complete IN while waiting for CMD is usually Status of previous SCSI op, ignore it if (ep_addr != p_msc->ep_out) { @@ -382,12 +455,12 @@ bool mscd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t uint8_t const status = rdwr10_validate_cmd(p_cbw); if (status != MSC_CSW_STATUS_PASSED) { - fail_scsi_op(rhport, p_msc, status); + fail_scsi_op(p_msc, status); } else if (p_cbw->total_bytes) { if (SCSI_CMD_READ_10 == p_cbw->command[0]) { - proc_read10_cmd(rhport, p_msc); + proc_read10_cmd(p_msc); } else { - proc_write10_cmd(rhport, p_msc); + proc_write10_cmd(p_msc); } } else { // no data transfer, only exist in complaint test suite @@ -400,7 +473,7 @@ bool mscd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t if ((p_cbw->total_bytes > 0) && !is_data_in(p_cbw->dir)) { if (p_cbw->total_bytes > CFG_TUD_MSC_EP_BUFSIZE) { TU_LOG_DRV(" SCSI reject non READ10/WRITE10 with large data\r\n"); - fail_scsi_op(rhport, p_msc, MSC_CSW_STATUS_FAILED); + fail_scsi_op(p_msc, MSC_CSW_STATUS_FAILED); } else { // Didn't check for case 9 (Ho > Dn), which requires examining scsi command first // but it is OK to just receive data then responded with failed status @@ -418,12 +491,12 @@ bool mscd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t if (resplen < 0) { // unsupported command TU_LOG_DRV(" SCSI unsupported or failed command\r\n"); - fail_scsi_op(rhport, p_msc, MSC_CSW_STATUS_FAILED); + fail_scsi_op(p_msc, MSC_CSW_STATUS_FAILED); } else if (resplen == 0) { if (p_cbw->total_bytes) { // 6.7 The 13 Cases: case 4 (Hi > Dn) // TU_LOG(MSC_DEBUG, " SCSI case 4 (Hi > Dn): %lu\r\n", p_cbw->total_bytes); - fail_scsi_op(rhport, p_msc, MSC_CSW_STATUS_FAILED); + fail_scsi_op(p_msc, MSC_CSW_STATUS_FAILED); } else { // case 1 Hn = Dn: all good p_msc->stage = MSC_STAGE_STATUS; @@ -432,7 +505,7 @@ bool mscd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t if (p_cbw->total_bytes == 0) { // 6.7 The 13 Cases: case 2 (Hn < Di) // TU_LOG(MSC_DEBUG, " SCSI case 2 (Hn < Di): %lu\r\n", p_cbw->total_bytes); - fail_scsi_op(rhport, p_msc, MSC_CSW_STATUS_FAILED); + fail_scsi_op(p_msc, MSC_CSW_STATUS_FAILED); } else { // cannot return more than host expect p_msc->total_len = tu_min32((uint32_t)resplen, p_cbw->total_bytes); @@ -441,6 +514,7 @@ bool mscd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t } } } + } break; case MSC_STAGE_DATA: @@ -454,10 +528,10 @@ bool mscd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t // Data Stage is complete p_msc->stage = MSC_STAGE_STATUS; }else { - proc_read10_cmd(rhport, p_msc); + proc_read10_cmd(p_msc); } } else if (SCSI_CMD_WRITE_10 == p_cbw->command[0]) { - proc_write10_new_data(rhport, p_msc, xferred_bytes); + proc_write10_new_data(p_msc, xferred_bytes); } else { p_msc->xferred_len += xferred_bytes; @@ -468,7 +542,7 @@ bool mscd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t if ( cb_result < 0 ) { // unsupported command TU_LOG_DRV(" SCSI unsupported command\r\n"); - fail_scsi_op(rhport, p_msc, MSC_CSW_STATUS_FAILED); + fail_scsi_op(p_msc, MSC_CSW_STATUS_FAILED); }else { // TODO haven't implement this scenario any further yet } @@ -517,7 +591,7 @@ bool mscd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t break; } - TU_ASSERT(prepare_cbw(rhport, p_msc)); + TU_ASSERT(prepare_cbw(p_msc)); } else { // Any xfer ended here is consider unknown error, ignore it TU_LOG1(" Warning expect SCSI Status but received unknown data\r\n"); @@ -528,26 +602,7 @@ bool mscd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t } if (p_msc->stage == MSC_STAGE_STATUS) { - // skip status if epin is currently stalled, will do it when received Clear Stall request - if (!usbd_edpt_stalled(rhport, p_msc->ep_in)) { - if ((p_cbw->total_bytes > p_msc->xferred_len) && is_data_in(p_cbw->dir)) { - // 6.7 The 13 Cases: case 5 (Hi > Di): STALL before status - // TU_LOG(MSC_DEBUG, " SCSI case 5 (Hi > Di): %lu > %lu\r\n", p_cbw->total_bytes, p_msc->xferred_len); - usbd_edpt_stall(rhport, p_msc->ep_in); - } else { - TU_ASSERT(send_csw(rhport, p_msc)); - } - } - - #if TU_CHECK_MCU(OPT_MCU_CXD56) - // WORKAROUND: cxd56 has its own nuttx usb stack which does not forward Set/ClearFeature(Endpoint) to DCD. - // There is no way for us to know when EP is un-stall, therefore we will unconditionally un-stall here and - // hope everything will work - if ( usbd_edpt_stalled(rhport, p_msc->ep_in) ) { - usbd_edpt_clear_stall(rhport, p_msc->ep_in); - send_csw(rhport, p_msc); - } - #endif + TU_ASSERT(proc_stage_status(p_msc)); } return true; @@ -751,7 +806,7 @@ static int32_t proc_builtin_scsi(uint8_t lun, uint8_t const scsi_cmd[16], uint8_ return resplen; } -static void proc_read10_cmd(uint8_t rhport, mscd_interface_t* p_msc) { +static void proc_read10_cmd(mscd_interface_t* p_msc) { msc_cbw_t const* p_cbw = &p_msc->cbw; // block size already verified not zero @@ -765,16 +820,27 @@ static void proc_read10_cmd(uint8_t rhport, mscd_interface_t* p_msc) { // Application can consume smaller bytes uint32_t const offset = p_msc->xferred_len % block_sz; + +#if CFG_TUD_MSC_ASYNC_IO + p_msc->next_op = MSC_NEXT_OP_READ10; + tud_msc_read10_cb(p_cbw->lun, lba, offset, _mscd_epbuf.buf, (uint32_t)nbytes); +#else nbytes = tud_msc_read10_cb(p_cbw->lun, lba, offset, _mscd_epbuf.buf, (uint32_t)nbytes); + proc_read10_next(p_msc, nbytes); +#endif +} +static void proc_read10_next(mscd_interface_t* p_msc, int32_t nbytes) { + uint8_t rhport = p_msc->rhport; if (nbytes < 0) { // negative means error -> endpoint is stalled & status in CSW set to failed TU_LOG_DRV(" tud_msc_read10_cb() return -1\r\n"); // set sense + msc_cbw_t const* p_cbw = &p_msc->cbw; set_sense_medium_not_present(p_cbw->lun); - fail_scsi_op(rhport, p_msc, MSC_CSW_STATUS_FAILED); + fail_scsi_op(p_msc, MSC_CSW_STATUS_FAILED); } else if (nbytes == 0) { // zero means not ready -> simulate an transfer complete so that this driver callback will fired again dcd_event_xfer_complete(rhport, p_msc->ep_in, 0, XFER_RESULT_SUCCESS, false); @@ -783,7 +849,7 @@ static void proc_read10_cmd(uint8_t rhport, mscd_interface_t* p_msc) { } } -static void proc_write10_cmd(uint8_t rhport, mscd_interface_t* p_msc) { +static void proc_write10_cmd(mscd_interface_t* p_msc) { msc_cbw_t const* p_cbw = &p_msc->cbw; bool writable = true; @@ -795,19 +861,19 @@ static void proc_write10_cmd(uint8_t rhport, mscd_interface_t* p_msc) { // Not writable, complete this SCSI op with error // Sense = Write protected tud_msc_set_sense(p_cbw->lun, SCSI_SENSE_DATA_PROTECT, 0x27, 0x00); - fail_scsi_op(rhport, p_msc, MSC_CSW_STATUS_FAILED); + fail_scsi_op(p_msc, MSC_CSW_STATUS_FAILED); return; } // remaining bytes capped at class buffer uint16_t nbytes = (uint16_t)tu_min32(CFG_TUD_MSC_EP_BUFSIZE, p_cbw->total_bytes - p_msc->xferred_len); - // Write10 callback will be called later when usb transfer complete + uint8_t rhport = p_msc->rhport; TU_ASSERT(usbd_edpt_xfer(rhport, p_msc->ep_out, _mscd_epbuf.buf, nbytes),); } // process new data arrived from WRITE10 -static void proc_write10_new_data(uint8_t rhport, mscd_interface_t* p_msc, uint32_t xferred_bytes) { +static void proc_write10_new_data(mscd_interface_t* p_msc, uint32_t xferred_bytes) { msc_cbw_t const* p_cbw = &p_msc->cbw; // block size already verified not zero @@ -818,8 +884,18 @@ static void proc_write10_new_data(uint8_t rhport, mscd_interface_t* p_msc, uint3 // Invoke callback to consume new data uint32_t const offset = p_msc->xferred_len % block_sz; - int32_t nbytes = tud_msc_write10_cb(p_cbw->lun, lba, offset, _mscd_epbuf.buf, xferred_bytes); +#if CFG_TUD_MSC_ASYNC_IO + p_msc->next_op = MSC_NEXT_OP_WRITE10; + p_msc->xferred_bytes = xferred_bytes; + tud_msc_write10_cb(p_cbw->lun, lba, offset, _mscd_epbuf.buf, xferred_bytes); +#else + int32_t nbytes = tud_msc_write10_cb(p_cbw->lun, lba, offset, _mscd_epbuf.buf, xferred_bytes); + proc_write10_next(p_msc, xferred_bytes, nbytes); +#endif +} + +static void proc_write10_next(mscd_interface_t* p_msc, uint32_t xferred_bytes, int32_t nbytes) { if (nbytes < 0) { // negative means error -> failed this scsi op TU_LOG_DRV(" tud_msc_write10_cb() return -1\r\n"); @@ -828,9 +904,10 @@ static void proc_write10_new_data(uint8_t rhport, mscd_interface_t* p_msc, uint3 p_msc->xferred_len += xferred_bytes; // Set sense + msc_cbw_t const* p_cbw = &p_msc->cbw; set_sense_medium_not_present(p_cbw->lun); - fail_scsi_op(rhport, p_msc, MSC_CSW_STATUS_FAILED); + fail_scsi_op(p_msc, MSC_CSW_STATUS_FAILED); } else { // Application consume less than what we got (including zero) if ((uint32_t)nbytes < xferred_bytes) { @@ -841,6 +918,7 @@ static void proc_write10_new_data(uint8_t rhport, mscd_interface_t* p_msc, uint3 } // simulate an transfer complete with adjusted parameters --> callback will be invoked with adjusted parameter + uint8_t rhport = p_msc->rhport; dcd_event_xfer_complete(rhport, p_msc->ep_out, left_over, XFER_RESULT_SUCCESS, false); } else { // Application consume all bytes in our buffer @@ -851,7 +929,7 @@ static void proc_write10_new_data(uint8_t rhport, mscd_interface_t* p_msc, uint3 p_msc->stage = MSC_STAGE_STATUS; } else { // prepare to receive more data from host - proc_write10_cmd(rhport, p_msc); + proc_write10_cmd(p_msc); } } } diff --git a/src/class/msc/msc_device.h b/src/class/msc/msc_device.h index 29acd280a..407fe241c 100644 --- a/src/class/msc/msc_device.h +++ b/src/class/msc/msc_device.h @@ -48,6 +48,11 @@ #error CFG_TUD_MSC_EP_BUFSIZE must be defined, value of a block size should work well, the more the better #endif +// Enable asynchronous read/write, once operation is finished tud_msc_async_io_done() must be called +#ifndef CFG_TUD_MSC_ASYNC_IO +#define CFG_TUD_MSC_ASYNC_IO 0 +#endif + TU_VERIFY_STATIC(CFG_TUD_MSC_EP_BUFSIZE < UINT16_MAX, "Size is not correct"); //--------------------------------------------------------------------+ @@ -73,6 +78,9 @@ bool tud_msc_set_sense(uint8_t lun, uint8_t sense_key, uint8_t add_sense_code, u // // - read < 0 : Indicate application error e.g invalid address. This request will be STALLed // and return failed status in command status wrapper phase. +// +// - In case of asynchronous IO enabled, application should passing reading parameters to background IO +// task and return immediately. Once reading is done, tud_msc_async_io_done() must be called. int32_t tud_msc_read10_cb (uint8_t lun, uint32_t lba, uint32_t offset, void* buffer, uint32_t bufsize); // Invoked when received SCSI WRITE10 command @@ -88,6 +96,8 @@ int32_t tud_msc_read10_cb (uint8_t lun, uint32_t lba, uint32_t offset, void* buf // - write < 0 : Indicate application error e.g invalid address. This request will be STALLed // and return failed status in command status wrapper phase. // +// - In case of asynchronous IO enabled, application should passing writing parameters to background IO +// task and return immediately. Once writing is done, tud_msc_async_io_done() must be called. // TODO change buffer to const uint8_t* int32_t tud_msc_write10_cb (uint8_t lun, uint32_t lba, uint32_t offset, uint8_t* buffer, uint32_t bufsize); @@ -121,6 +131,12 @@ void tud_msc_capacity_cb(uint8_t lun, uint32_t* block_count, uint16_t* block_siz */ int32_t tud_msc_scsi_cb (uint8_t lun, uint8_t const scsi_cmd[16], void* buffer, uint16_t bufsize); +#if CFG_TUD_MSC_ASYNC_IO +// Called once asynchronous read/write operation is done +// bytes_processed has the same meaning of tud_msc_read10_cb() / +// tud_msc_write10_cb() return value +void tud_msc_async_io_done(int32_t bytes_processed); +#endif /*------------- Optional callbacks -------------*/ // Invoked when received GET_MAX_LUN request, required for multiple LUNs implementation -- cgit v1.3.1 From 84f8876c7c3639ef4ac707956831311791aefd76 Mon Sep 17 00:00:00 2001 From: HiFiPhile Date: Fri, 31 Jan 2025 16:26:10 +0100 Subject: Use return code to choose async io. Signed-off-by: HiFiPhile --- src/class/msc/msc_device.c | 26 +++++++++------------ src/class/msc/msc_device.h | 56 +++++++++++++++++++++++++--------------------- 2 files changed, 41 insertions(+), 41 deletions(-) (limited to 'src/class') diff --git a/src/class/msc/msc_device.c b/src/class/msc/msc_device.c index c7c926f4e..e3fe5a078 100644 --- a/src/class/msc/msc_device.c +++ b/src/class/msc/msc_device.c @@ -78,10 +78,10 @@ typedef struct { uint8_t sense_key; uint8_t add_sense_code; uint8_t add_sense_qualifier; -#if CFG_TUD_MSC_ASYNC_IO + + // Async IO uint8_t next_op; uint32_t xferred_bytes; -#endif }mscd_interface_t; static mscd_interface_t _mscd_itf; @@ -100,9 +100,7 @@ static void proc_write10_cmd(mscd_interface_t* p_msc); static void proc_write10_new_data(mscd_interface_t* p_msc, uint32_t xferred_bytes); static void proc_write10_next(mscd_interface_t* p_msc, uint32_t xferred_bytes, int32_t nbytes); static bool proc_stage_status(mscd_interface_t* p_msc); -#if CFG_TUD_MSC_ASYNC_IO static void tud_msc_async_io_done_cb(void* bytes_processed); -#endif TU_ATTR_ALWAYS_INLINE static inline bool is_data_in(uint8_t dir) { return tu_bit_test(dir, 7); @@ -265,7 +263,6 @@ static inline void set_sense_medium_not_present(uint8_t lun) { tud_msc_set_sense(lun, SCSI_SENSE_NOT_READY, 0x3A, 0x00); } -#if CFG_TUD_MSC_ASYNC_IO void tud_msc_async_io_done(int32_t bytes_processed) { // Precheck to avoid queueing multiple RW done callback TU_VERIFY(_mscd_itf.next_op != MSC_NEXT_OP_NONE,); @@ -289,7 +286,6 @@ static void tud_msc_async_io_done_cb(void* bytes_processed) { } } } -#endif //--------------------------------------------------------------------+ // USBD Driver API @@ -821,13 +817,12 @@ static void proc_read10_cmd(mscd_interface_t* p_msc) { // Application can consume smaller bytes uint32_t const offset = p_msc->xferred_len % block_sz; -#if CFG_TUD_MSC_ASYNC_IO p_msc->next_op = MSC_NEXT_OP_READ10; - tud_msc_read10_cb(p_cbw->lun, lba, offset, _mscd_epbuf.buf, (uint32_t)nbytes); -#else nbytes = tud_msc_read10_cb(p_cbw->lun, lba, offset, _mscd_epbuf.buf, (uint32_t)nbytes); - proc_read10_next(p_msc, nbytes); -#endif + if (nbytes != TUD_MSC_RET_ASYNC) { + p_msc->next_op = MSC_NEXT_OP_NONE; + proc_read10_next(p_msc, nbytes); + } } static void proc_read10_next(mscd_interface_t* p_msc, int32_t nbytes) { @@ -885,14 +880,13 @@ static void proc_write10_new_data(mscd_interface_t* p_msc, uint32_t xferred_byte // Invoke callback to consume new data uint32_t const offset = p_msc->xferred_len % block_sz; -#if CFG_TUD_MSC_ASYNC_IO p_msc->next_op = MSC_NEXT_OP_WRITE10; p_msc->xferred_bytes = xferred_bytes; - tud_msc_write10_cb(p_cbw->lun, lba, offset, _mscd_epbuf.buf, xferred_bytes); -#else int32_t nbytes = tud_msc_write10_cb(p_cbw->lun, lba, offset, _mscd_epbuf.buf, xferred_bytes); - proc_write10_next(p_msc, xferred_bytes, nbytes); -#endif + if (nbytes != TUD_MSC_RET_ASYNC) { + p_msc->next_op = MSC_NEXT_OP_NONE; + proc_write10_next(p_msc, xferred_bytes, nbytes); + } } static void proc_write10_next(mscd_interface_t* p_msc, uint32_t xferred_bytes, int32_t nbytes) { diff --git a/src/class/msc/msc_device.h b/src/class/msc/msc_device.h index 407fe241c..7162b11e4 100644 --- a/src/class/msc/msc_device.h +++ b/src/class/msc/msc_device.h @@ -48,10 +48,11 @@ #error CFG_TUD_MSC_EP_BUFSIZE must be defined, value of a block size should work well, the more the better #endif -// Enable asynchronous read/write, once operation is finished tud_msc_async_io_done() must be called -#ifndef CFG_TUD_MSC_ASYNC_IO -#define CFG_TUD_MSC_ASYNC_IO 0 -#endif +// Return value of callback functions +// Error +#define TUD_MSC_RET_ERROR -1 +// Asynchronous IO +#define TUD_MSC_RET_ASYNC -16 TU_VERIFY_STATIC(CFG_TUD_MSC_EP_BUFSIZE < UINT16_MAX, "Size is not correct"); @@ -62,6 +63,11 @@ TU_VERIFY_STATIC(CFG_TUD_MSC_EP_BUFSIZE < UINT16_MAX, "Size is not correct"); // Set SCSI sense response bool tud_msc_set_sense(uint8_t lun, uint8_t sense_key, uint8_t add_sense_code, uint8_t add_sense_qualifier); +// Called once asynchronous read/write operation is done +// bytes_processed has the same meaning of tud_msc_read10_cb() / +// tud_msc_write10_cb() return value +void tud_msc_async_io_done(int32_t bytes_processed); + //--------------------------------------------------------------------+ // Application Callbacks (WEAK is optional) //--------------------------------------------------------------------+ @@ -70,34 +76,40 @@ bool tud_msc_set_sense(uint8_t lun, uint8_t sense_key, uint8_t add_sense_code, u // - Address = lba * BLOCK_SIZE + offset // - offset is only needed if CFG_TUD_MSC_EP_BUFSIZE is smaller than BLOCK_SIZE. // -// - Application fill the buffer (up to bufsize) with address contents and return number of read byte. If -// - read < bufsize : These bytes are transferred first and callback invoked again for remaining data. +// - Application fill the buffer (up to bufsize) with address contents and return number of bytes read or status. +// +// - ret < bufsize : These bytes are transferred first and callback will be invoked again for remaining data. // -// - read == 0 : Indicate application is not ready yet e.g disk I/O busy. -// Callback invoked again with the same parameters later on. +// - ret == 0 : Indicate application is not ready yet e.g disk I/O busy. +// Callback will be invoked again with the same parameters later on. // -// - read < 0 : Indicate application error e.g invalid address. This request will be STALLed +// - ret == TUD_MSC_RET_ERROR (-1) +// : Indicate application error e.g invalid address. This request will be STALLed // and return failed status in command status wrapper phase. // -// - In case of asynchronous IO enabled, application should passing reading parameters to background IO -// task and return immediately. Once reading is done, tud_msc_async_io_done() must be called. +// - ret == TUD_MSC_RET_ASYNC (-16) +// : Data reading will be done asynchronously in a background task. Application should return immediately. +// tud_msc_async_io_done() must be called once reading is done to signal completion. int32_t tud_msc_read10_cb (uint8_t lun, uint32_t lba, uint32_t offset, void* buffer, uint32_t bufsize); // Invoked when received SCSI WRITE10 command // - Address = lba * BLOCK_SIZE + offset // - offset is only needed if CFG_TUD_MSC_EP_BUFSIZE is smaller than BLOCK_SIZE. // -// - Application write data from buffer to address contents (up to bufsize) and return number of written byte. If -// - write < bufsize : callback invoked again with remaining data later on. +// - Application writes data from buffer to address contents (up to bufsize) and returns the number of bytes written or status. // -// - write == 0 : Indicate application is not ready yet e.g disk I/O busy. -// Callback invoked again with the same parameters later on. +// - ret < bufsize : Callback will be invoked again with remaining data later on. // -// - write < 0 : Indicate application error e.g invalid address. This request will be STALLed -// and return failed status in command status wrapper phase. +// - ret == 0 : Indicate application is not ready yet e.g disk I/O busy. +// Callback will be invoked again with the same parameters later on. // -// - In case of asynchronous IO enabled, application should passing writing parameters to background IO -// task and return immediately. Once writing is done, tud_msc_async_io_done() must be called. +// - ret == TUD_MSC_RET_ERROR (-1) +// : Indicate application error e.g invalid address. This request will be STALLed +// and return failed status in command status wrapper phase. +// +// - ret == TUD_MSC_RET_ASYNC (-16) +// : Data writing will be done asynchronously in a background task. Application should return immediately. +// tud_msc_async_io_done() must be called once writing is done to signal completion. // TODO change buffer to const uint8_t* int32_t tud_msc_write10_cb (uint8_t lun, uint32_t lba, uint32_t offset, uint8_t* buffer, uint32_t bufsize); @@ -131,12 +143,6 @@ void tud_msc_capacity_cb(uint8_t lun, uint32_t* block_count, uint16_t* block_siz */ int32_t tud_msc_scsi_cb (uint8_t lun, uint8_t const scsi_cmd[16], void* buffer, uint16_t bufsize); -#if CFG_TUD_MSC_ASYNC_IO -// Called once asynchronous read/write operation is done -// bytes_processed has the same meaning of tud_msc_read10_cb() / -// tud_msc_write10_cb() return value -void tud_msc_async_io_done(int32_t bytes_processed); -#endif /*------------- Optional callbacks -------------*/ // Invoked when received GET_MAX_LUN request, required for multiple LUNs implementation -- cgit v1.3.1 From 8d2310247c47160bf8de6e5f754284360ad7e937 Mon Sep 17 00:00:00 2001 From: HiFiPhile Date: Fri, 31 Jan 2025 16:31:47 +0100 Subject: Fix CI. Signed-off-by: HiFiPhile --- examples/device/cdc_msc_freertos/src/msc_disk.c | 2 ++ src/class/msc/msc_device.c | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) (limited to 'src/class') diff --git a/examples/device/cdc_msc_freertos/src/msc_disk.c b/examples/device/cdc_msc_freertos/src/msc_disk.c index c75b9ae34..c2aaca847 100644 --- a/examples/device/cdc_msc_freertos/src/msc_disk.c +++ b/examples/device/cdc_msc_freertos/src/msc_disk.c @@ -166,8 +166,10 @@ static void io_task(void *params) { uint8_t const* addr = msc_disk[io_ops.lba] + io_ops.offset; memcpy(io_ops.buffer, addr, io_ops.bufsize); } else { +#ifndef CFG_EXAMPLE_MSC_READONLY uint8_t* addr = msc_disk[io_ops.lba] + io_ops.offset; memcpy(addr, io_ops.buffer, io_ops.bufsize); +#endif } tusb_time_delay_ms_api(CFG_EXAMPLE_MSC_IO_DELAY_MS); diff --git a/src/class/msc/msc_device.c b/src/class/msc/msc_device.c index e3fe5a078..72c3747fc 100644 --- a/src/class/msc/msc_device.c +++ b/src/class/msc/msc_device.c @@ -267,14 +267,14 @@ void tud_msc_async_io_done(int32_t bytes_processed) { // Precheck to avoid queueing multiple RW done callback TU_VERIFY(_mscd_itf.next_op != MSC_NEXT_OP_NONE,); // Call usbd_edpt_xfer() in tud_task() to avoid racing condition - usbd_defer_func(tud_msc_async_io_done_cb, (void*) bytes_processed, false); + usbd_defer_func(tud_msc_async_io_done_cb, (void*) (intptr_t)bytes_processed, false); } static void tud_msc_async_io_done_cb(void* bytes_processed) { TU_VERIFY(_mscd_itf.next_op != MSC_NEXT_OP_NONE,); uint8_t next_op = _mscd_itf.next_op; _mscd_itf.next_op = MSC_NEXT_OP_NONE; - int32_t nbytes = (int32_t)bytes_processed; + int32_t nbytes = (int32_t)(intptr_t)bytes_processed; // READ10 if (next_op == MSC_NEXT_OP_READ10) { proc_read10_next(&_mscd_itf, nbytes); -- cgit v1.3.1 From 3ffe8dbfee001e9591025f9dcc121fa2f5ef550c Mon Sep 17 00:00:00 2001 From: hathach Date: Fri, 7 Feb 2025 12:33:22 +0700 Subject: fix stringop-overread warning for msc device with memmove --- src/class/msc/msc_device.c | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) (limited to 'src/class') diff --git a/src/class/msc/msc_device.c b/src/class/msc/msc_device.c index dd66bfb6f..6670045aa 100644 --- a/src/class/msc/msc_device.c +++ b/src/class/msc/msc_device.c @@ -365,7 +365,7 @@ bool mscd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t memcpy(p_cbw, _mscd_epbuf.buf, sizeof(msc_cbw_t)); TU_LOG_DRV(" SCSI Command [Lun%u]: %s\r\n", p_cbw->lun, tu_lookup_find(&_msc_scsi_cmd_table, p_cbw->command[0])); - //TU_LOG_MEM(MSC_DEBUG, p_cbw, xferred_bytes, 2); + // TU_LOG_MEM(CFG_TUD_MSC_LOG_LEVEL, p_cbw, xferred_bytes, 2); p_csw->signature = MSC_CSW_SIGNATURE; p_csw->tag = p_cbw->tag; @@ -422,7 +422,7 @@ bool mscd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t } else if (resplen == 0) { if (p_cbw->total_bytes) { // 6.7 The 13 Cases: case 4 (Hi > Dn) - // TU_LOG(MSC_DEBUG, " SCSI case 4 (Hi > Dn): %lu\r\n", p_cbw->total_bytes); + // TU_LOG_DRV(" SCSI case 4 (Hi > Dn): %lu\r\n", p_cbw->total_bytes); fail_scsi_op(rhport, p_msc, MSC_CSW_STATUS_FAILED); } else { // case 1 Hn = Dn: all good @@ -431,7 +431,7 @@ bool mscd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t } else { if (p_cbw->total_bytes == 0) { // 6.7 The 13 Cases: case 2 (Hn < Di) - // TU_LOG(MSC_DEBUG, " SCSI case 2 (Hn < Di): %lu\r\n", p_cbw->total_bytes); + // TU_LOG_DRV(" SCSI case 2 (Hn < Di): %lu\r\n", p_cbw->total_bytes); fail_scsi_op(rhport, p_msc, MSC_CSW_STATUS_FAILED); } else { // cannot return more than host expect @@ -445,7 +445,8 @@ bool mscd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t case MSC_STAGE_DATA: TU_LOG_DRV(" SCSI Data [Lun%u]\r\n", p_cbw->lun); - //TU_LOG_MEM(MSC_DEBUG, _mscd_epbuf.buf, xferred_bytes, 2); + TU_ASSERT(xferred_bytes <= CFG_TUD_MSC_EP_BUFSIZE); // sanity check to avoid buffer overflow + // TU_LOG_MEM(CFG_TUD_MSC_LOG_LEVEL, _mscd_epbuf.buf, xferred_bytes, 2); if (SCSI_CMD_READ_10 == p_cbw->command[0]) { p_msc->xferred_len += xferred_bytes; @@ -492,7 +493,7 @@ bool mscd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t // Wait for the Status phase to complete if ((ep_addr == p_msc->ep_in) && (xferred_bytes == sizeof(msc_csw_t))) { TU_LOG_DRV(" SCSI Status [Lun%u] = %u\r\n", p_cbw->lun, p_csw->status); - // TU_LOG_MEM(MSC_DEBUG, p_csw, xferred_bytes, 2); + // TU_LOG_MEM(CFG_TUD_MSC_LOG_LEVEL, p_csw, xferred_bytes, 2); // Invoke complete callback if defined // Note: There is racing issue with samd51 + qspi flash testing with arduino @@ -532,7 +533,7 @@ bool mscd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t if (!usbd_edpt_stalled(rhport, p_msc->ep_in)) { if ((p_cbw->total_bytes > p_msc->xferred_len) && is_data_in(p_cbw->dir)) { // 6.7 The 13 Cases: case 5 (Hi > Di): STALL before status - // TU_LOG(MSC_DEBUG, " SCSI case 5 (Hi > Di): %lu > %lu\r\n", p_cbw->total_bytes, p_msc->xferred_len); + // TU_LOG_DRV(" SCSI case 5 (Hi > Di): %lu > %lu\r\n", p_cbw->total_bytes, p_msc->xferred_len); usbd_edpt_stall(rhport, p_msc->ep_in); } else { TU_ASSERT(send_csw(rhport, p_msc)); @@ -827,20 +828,18 @@ static void proc_write10_new_data(uint8_t rhport, mscd_interface_t* p_msc, uint3 // update actual byte before failed p_msc->xferred_len += xferred_bytes; - // Set sense set_sense_medium_not_present(p_cbw->lun); - fail_scsi_op(rhport, p_msc, MSC_CSW_STATUS_FAILED); } else { - // Application consume less than what we got (including zero) if ((uint32_t)nbytes < xferred_bytes) { - uint32_t const left_over = xferred_bytes - (uint32_t)nbytes; + // Application consume less than what we got (including zero) + const uint32_t left_over = xferred_bytes - (uint32_t)nbytes; if (nbytes > 0) { p_msc->xferred_len += (uint16_t)nbytes; memmove(_mscd_epbuf.buf, _mscd_epbuf.buf + nbytes, left_over); } - // simulate an transfer complete with adjusted parameters --> callback will be invoked with adjusted parameter + // simulate a transfer complete with adjusted parameters --> callback will be invoked with adjusted parameter dcd_event_xfer_complete(rhport, p_msc->ep_out, left_over, XFER_RESULT_SUCCESS, false); } else { // Application consume all bytes in our buffer -- cgit v1.3.1 From a232644cbd62db681ba8b285290c9b1d00a1fdb7 Mon Sep 17 00:00:00 2001 From: hathach Date: Fri, 7 Feb 2025 16:38:14 +0700 Subject: add full hid usage for Digitizer Page (0x0D), move thing around a bit. --- src/class/hid/hid.h | 240 ++++++++++++++++++++++++++++++++++----------- src/class/hid/hid_device.h | 4 +- 2 files changed, 187 insertions(+), 57 deletions(-) (limited to 'src/class') diff --git a/src/class/hid/hid.h b/src/class/hid/hid.h index b179fc72a..c2434c20d 100644 --- a/src/class/hid/hid.h +++ b/src/class/hid/hid.h @@ -763,6 +763,21 @@ enum { //--------------------------------------------------------------------+ // Usage Table +/* Usage Types Data + Sel Selector Array + SV Static Value Constant, Variable, Absolute + SF Static Flag Constant, Variable, Absolute + DV Dynamic Value Constant, Variable, Absolute + DF Dynamic Flag Constant, Variable, Absolute +*/ +/* Usage Types Collection + NAry Named Array Logical + CA Collection Application Application + CL Collection Logical Logical + CP Collection Physical Physical + US Usage Switch Logical + UM Usage Modifier Logical +*/ //--------------------------------------------------------------------+ /// HID Usage Table - Table 1: Usage Page Summary @@ -782,10 +797,14 @@ enum { HID_USAGE_PAGE_DIGITIZER = 0x0d, HID_USAGE_PAGE_PID = 0x0f, HID_USAGE_PAGE_UNICODE = 0x10, - HID_USAGE_PAGE_ALPHA_DISPLAY = 0x14, - HID_USAGE_PAGE_IN_RANGE = 0x32, - HID_USAGE_PAGE_MEDICAL = 0x40, - HID_USAGE_PAGE_TIP_SWITCH = 0x42, + HID_USAGE_PAGE_SOC = 0x11, + HID_USAGE_PAGE_EYE_AND_HEAD_TRACKERS = 0x12, + // 0x13 is reserved + HID_USAGE_PAGE_AUXILIARY_DISPLAY = 0x14, + // 0x15 - 0x1f is reserved + HID_USAGE_PAGE_SENSORS = 0x20, + // 0x21 - 0x3f is reserved + HID_USAGE_PAGE_MEDICAL_INSTRUMENT = 0x40, HID_USAGE_PAGE_LIGHTING_AND_ILLUMINATION = 0x59, HID_USAGE_PAGE_MONITOR = 0x80, // 0x80 - 0x83 HID_USAGE_PAGE_POWER = 0x84, // 0x084 - 0x87 @@ -871,16 +890,6 @@ enum { HID_USAGE_DESKTOP_SYSTEM_DISPLAY_LCD_AUTOSCALE = 0xB7 }; -/// HID Usage Table: Digitizer Page (0x0D) -enum { - // Touch Screen. - HID_USAGE_DIGITIZER_TOUCH_SCREEN = 0x04, - - // Stylus Pen. - HID_USAGE_DIGITIZER_STYLUS = 0x20, -}; - - /// HID Usage Table: Consumer Page (0x0C) /// Only contains controls that supported by Windows (whole list is too long) enum { @@ -939,48 +948,125 @@ enum { HID_USAGE_CONSUMER_AC_PAN = 0x0238, }; -/// HID Usage Table - Lighting And Illumination Page (0x59) -enum { - HID_USAGE_LIGHTING_LAMP_ARRAY = 0x01, - HID_USAGE_LIGHTING_LAMP_ARRAY_ATTRIBUTES_REPORT = 0x02, - HID_USAGE_LIGHTING_LAMP_COUNT = 0x03, - HID_USAGE_LIGHTING_BOUNDING_BOX_WIDTH_IN_MICROMETERS = 0x04, - HID_USAGE_LIGHTING_BOUNDING_BOX_HEIGHT_IN_MICROMETERS = 0x05, - HID_USAGE_LIGHTING_BOUNDING_BOX_DEPTH_IN_MICROMETERS = 0x06, - HID_USAGE_LIGHTING_LAMP_ARRAY_KIND = 0x07, - HID_USAGE_LIGHTING_MIN_UPDATE_INTERVAL_IN_MICROSECONDS = 0x08, - HID_USAGE_LIGHTING_LAMP_ATTRIBUTES_REQUEST_REPORT = 0x20, - HID_USAGE_LIGHTING_LAMP_ID = 0x21, - HID_USAGE_LIGHTING_LAMP_ATTRIBUTES_RESPONSE_REPORT = 0x22, - HID_USAGE_LIGHTING_POSITION_X_IN_MICROMETERS = 0x23, - HID_USAGE_LIGHTING_POSITION_Y_IN_MICROMETERS = 0x24, - HID_USAGE_LIGHTING_POSITION_Z_IN_MICROMETERS = 0x25, - HID_USAGE_LIGHTING_LAMP_PURPOSES = 0x26, - HID_USAGE_LIGHTING_UPDATE_LATENCY_IN_MICROSECONDS = 0x27, - HID_USAGE_LIGHTING_RED_LEVEL_COUNT = 0x28, - HID_USAGE_LIGHTING_GREEN_LEVEL_COUNT = 0x29, - HID_USAGE_LIGHTING_BLUE_LEVEL_COUNT = 0x2A, - HID_USAGE_LIGHTING_INTENSITY_LEVEL_COUNT = 0x2B, - HID_USAGE_LIGHTING_IS_PROGRAMMABLE = 0x2C, - HID_USAGE_LIGHTING_INPUT_BINDING = 0x2D, - HID_USAGE_LIGHTING_LAMP_MULTI_UPDATE_REPORT = 0x50, - HID_USAGE_LIGHTING_RED_UPDATE_CHANNEL = 0x51, - HID_USAGE_LIGHTING_GREEN_UPDATE_CHANNEL = 0x52, - HID_USAGE_LIGHTING_BLUE_UPDATE_CHANNEL = 0x53, - HID_USAGE_LIGHTING_INTENSITY_UPDATE_CHANNEL = 0x54, - HID_USAGE_LIGHTING_LAMP_UPDATE_FLAGS = 0x55, - HID_USAGE_LIGHTING_LAMP_RANGE_UPDATE_REPORT = 0x60, - HID_USAGE_LIGHTING_LAMP_ID_START = 0x61, - HID_USAGE_LIGHTING_LAMP_ID_END = 0x62, - HID_USAGE_LIGHTING_LAMP_ARRAY_CONTROL_REPORT = 0x70, - HID_USAGE_LIGHTING_AUTONOMOUS_MODE = 0x71, -}; - -/// HID Usage Table: FIDO Alliance Page (0xF1D0) +/// HID Usage Table: Digitizer Page (0x0D) enum { - HID_USAGE_FIDO_U2FHID = 0x01, // U2FHID usage for top-level collection - HID_USAGE_FIDO_DATA_IN = 0x20, // Raw IN data report - HID_USAGE_FIDO_DATA_OUT = 0x21 // Raw OUT data report + HID_USAGE_DIGITIZER_UNDEFINED = 0x00, + HID_USAGE_DIGITIZER_DIGITIZER = 0x01, // CA + HID_USAGE_DIGITIZER_PEN = 0x02, // CA + HID_USAGE_DIGITIZER_LIGHT_PEN = 0x03, // CA + HID_USAGE_DIGITIZER_TOUCH_SCREEN = 0x04, // CA + HID_USAGE_DIGITIZER_TOUCH_PAD = 0x05, // CA + HID_USAGE_DIGITIZER_WHITEBOARD = 0x06, // CA + HID_USAGE_DIGITIZER_COORDINATE_MEASURING_MACHINE = 0x07, // CA + HID_USAGE_DIGITIZER_3D_DIGITIZER = 0x08, // CA + HID_USAGE_DIGITIZER_STEREO_PLOTTER = 0x09, // CA + HID_USAGE_DIGITIZER_ARTICULATED_ARM = 0x0A, // CA + HID_USAGE_DIGITIZER_ARMATURE = 0x0B, // CA + HID_USAGE_DIGITIZER_MULTIPLE_POINT_DIGITIZER = 0x0C, // CA + HID_USAGE_DIGITIZER_FREE_SPACE_WAND = 0x0D, // CA + HID_USAGE_DIGITIZER_DEVICE_CONFIGURATION = 0x0E, // CA + HID_USAGE_DIGITIZER_CAPACITIVE_HEAT_MAP_DIGITIZER = 0x0F, // CA + // Reserved (0x10 - 0x1F) + HID_USAGE_DIGITIZER_STYLUS = 0x20, // CA/CL + HID_USAGE_DIGITIZER_PUCK = 0x21, // CL + HID_USAGE_DIGITIZER_FINGER = 0x22, // CL + HID_USAGE_DIGITIZER_DEVICE_SETTINGS = 0x23, // CL + HID_USAGE_DIGITIZER_CHARACTER_GESTURE = 0x24, // CL + // Reserved (0x25 - 0x2F) + HID_USAGE_DIGITIZER_TIP_PRESSURE = 0x30, // DV + HID_USAGE_DIGITIZER_BARREL_PRESSURE = 0x31, // DV + HID_USAGE_DIGITIZER_IN_RANGE = 0x32, // MC + HID_USAGE_DIGITIZER_TOUCH = 0x33, // MC + HID_USAGE_DIGITIZER_UNTOUCH = 0x34, // OSC + HID_USAGE_DIGITIZER_TAP = 0x35, // OSC + HID_USAGE_DIGITIZER_QUALITY = 0x36, // DV + HID_USAGE_DIGITIZER_DATA_VALID = 0x37, // MC + HID_USAGE_DIGITIZER_TRANSDUCER_INDEX = 0x38, // DV + HID_USAGE_DIGITIZER_TABLET_FUNCTION_KEYS = 0x39, // CL + HID_USAGE_DIGITIZER_PROGRAM_CHANGE_KEYS = 0x3A, // CL + HID_USAGE_DIGITIZER_BATTERY_STRENGTH = 0x3B, // DV + HID_USAGE_DIGITIZER_INVERT = 0x3C, // MC + HID_USAGE_DIGITIZER_X_TILT = 0x3D, // DV + HID_USAGE_DIGITIZER_Y_TILT = 0x3E, // DV + HID_USAGE_DIGITIZER_AZIMUTH = 0x3F, // DV + HID_USAGE_DIGITIZER_ALTITUDE = 0x40, // DV + HID_USAGE_DIGITIZER_TWIST = 0x41, // DV + HID_USAGE_DIGITIZER_TIP_SWITCH = 0x42, // MC + HID_USAGE_DIGITIZER_SECONDARY_TIP_SWITCH = 0x43, // MC + HID_USAGE_DIGITIZER_BARREL_SWITCH = 0x44, // MC + HID_USAGE_DIGITIZER_ERASER = 0x45, // MC + HID_USAGE_DIGITIZER_TABLET_PICK = 0x46, // MC + HID_USAGE_DIGITIZER_TOUCH_VALID = 0x47, // MC + HID_USAGE_DIGITIZER_WIDTH = 0x48, // DV + HID_USAGE_DIGITIZER_HEIGHT = 0x49, // DV + // Reserved (0x4A - 0x50) + HID_USAGE_DIGITIZER_CONTACT_IDENTIFIER = 0x51, // DV + HID_USAGE_DIGITIZER_DEVICE_MODE = 0x52, // DV + HID_USAGE_DIGITIZER_DEVICE_IDENTIFIER = 0x53, // DV/SV + HID_USAGE_DIGITIZER_CONTACT_COUNT = 0x54, // DV + HID_USAGE_DIGITIZER_CONTACT_COUNT_MAXIMUM = 0x55, // SV + HID_USAGE_DIGITIZER_SCAN_TIME = 0x56, // DV + HID_USAGE_DIGITIZER_SURFACE_SWITCH = 0x57, // DF + HID_USAGE_DIGITIZER_BUTTON_SWITCH = 0x58, // DF + HID_USAGE_DIGITIZER_PAD_TYPE = 0x59, // SF + HID_USAGE_DIGITIZER_TRANSDUCER_SERIAL_NUMBER = 0x5B, // SV + HID_USAGE_DIGITIZER_PREFERRED_COLOR = 0x5C, // DV + HID_USAGE_DIGITIZER_PREFERRED_COLOR_LOCKED = 0x5D, // MC + HID_USAGE_DIGITIZER_PREFERRED_LINE_WIDTH = 0x5E, // DV + HID_USAGE_DIGITIZER_PREFERRED_LINE_WIDTH_LOCKED = 0x5F, // MC + HID_USAGE_DIGITIZER_LATENCY_MODE = 0x60, // DF + HID_USAGE_DIGITIZER_GESTURE_CHARACTER_QUALITY = 0x61, // DV + HID_USAGE_DIGITIZER_CHARACTER_GESTURE_DATA_LENGTH = 0x62, // DV + HID_USAGE_DIGITIZER_CHARACTER_GESTURE_DATA = 0x63, // DV + HID_USAGE_DIGITIZER_GESTURE_CHARACTER_ENCODING = 0x64, // NAry + HID_USAGE_DIGITIZER_UTF8_CHARACTER_GESTURE_ENCODING = 0x65, // Sel + HID_USAGE_DIGITIZER_UTF16_LE_CHARACTER_GESTURE_ENCODING = 0x66, // Sel + HID_USAGE_DIGITIZER_UTF16_BE_CHARACTER_GESTURE_ENCODING = 0x67, // Sel + HID_USAGE_DIGITIZER_UTF32_LE_CHARACTER_GESTURE_ENCODING = 0x68, // Sel + HID_USAGE_DIGITIZER_UTF32_BE_CHARACTER_GESTURE_ENCODING = 0x69, // Sel + HID_USAGE_DIGITIZER_CAPACITIVE_HEAT_MAP_VENDOR_ID = 0x6A, // SV + HID_USAGE_DIGITIZER_CAPACITIVE_HEAT_MAP_VERSION = 0x6B, // SV + HID_USAGE_DIGITIZER_CAPACITIVE_HEAT_MAP_FRAME_DATA = 0x6C, // DV + HID_USAGE_DIGITIZER_GESTURE_CHARACTER_ENABLE = 0x6D, // DF + HID_USAGE_DIGITIZER_TRANSDUCER_SERIAL_NUMBER_PART2 = 0x6E, // SV + HID_USAGE_DIGITIZER_NO_PREFERRED_COLOR = 0x6F, // DF + HID_USAGE_DIGITIZER_PREFERRED_LINE_STYLE = 0x70, // NAry + HID_USAGE_DIGITIZER_PREFERRED_LINE_STYLE_LOCKED = 0x71, // MC + HID_USAGE_DIGITIZER_INK = 0x72, // Sel + HID_USAGE_DIGITIZER_PENCIL = 0x73, // Sel + HID_USAGE_DIGITIZER_HIGHLIGHTER = 0x74, // Sel + HID_USAGE_DIGITIZER_CHISEL_MARKER = 0x75, // Sel + HID_USAGE_DIGITIZER_BRUSH = 0x76, // Sel + HID_USAGE_DIGITIZER_NO_PREFERENCE = 0x77, // Sel + // Reserved (0x78 - 0x7F) + HID_USAGE_DIGITIZER_DIGITIZER_DIAGNOSTIC = 0x80, // CL + HID_USAGE_DIGITIZER_DIGITIZER_ERROR = 0x81, // NAry + HID_USAGE_DIGITIZER_ERR_NORMAL_STATUS = 0x82, // Sel + HID_USAGE_DIGITIZER_ERR_TRANSDUCERS_EXCEEDED = 0x83, // Sel + HID_USAGE_DIGITIZER_ERR_FULL_TRANS_FEATURES_UNAVAILABLE = 0x84, // Sel + HID_USAGE_DIGITIZER_ERR_CHARGE_LOW = 0x85, // Sel + // Reserved (0x86 - 0x8F) + HID_USAGE_DIGITIZER_TRANSDUCER_SOFTWARE_INFO = 0x90, // CL + HID_USAGE_DIGITIZER_TRANSDUCER_VENDOR_ID = 0x91, // SV + HID_USAGE_DIGITIZER_TRANSDUCER_PRODUCT_ID = 0x92, // SV + HID_USAGE_DIGITIZER_DEVICE_SUPPORTED_PROTOCOLS = 0x93, // NAry/CL + HID_USAGE_DIGITIZER_TRANSDUCER_SUPPORTED_PROTOCOLS = 0x94, // NAry/CL + HID_USAGE_DIGITIZER_NO_PROTOCOL = 0x95, // Sel + HID_USAGE_DIGITIZER_WACOM_AES_PROTOCOL = 0x96, // Sel + HID_USAGE_DIGITIZER_USI_PROTOCOL = 0x97, // Sel + HID_USAGE_DIGITIZER_MICROSOFT_PEN_PROTOCOL = 0x98, // Sel + // Reserved (0x99 - 0x9F) + HID_USAGE_DIGITIZER_SUPPORTED_REPORT_RATES = 0xA0, // SV/CL + HID_USAGE_DIGITIZER_REPORT_RATE = 0xA1, // DV + HID_USAGE_DIGITIZER_TRANSDUCER_CONNECTED = 0xA2, // SF + HID_USAGE_DIGITIZER_SWITCH_DISABLED = 0xA3, // Sel + HID_USAGE_DIGITIZER_SWITCH_UNIMPLEMENTED = 0xA4, // Sel + HID_USAGE_DIGITIZER_TRANSDUCER_SWITCHES = 0xA5, // CL + HID_USAGE_DIGITIZER_TRANSDUCER_INDEX_SELECTOR = 0xA6, // DV + // Reserved (0xA7 - 0xAF) + HID_USAGE_DIGITIZER_BUTTON_PRESS_THRESHOLD = 0xB0, // DV + + // Reserved (0xB1 - 0xFFFF) }; /// HID Usage Table: Physical Input Device Page (0x0F) @@ -1093,6 +1179,50 @@ enum { HID_USAGE_PID_RAM_POOL_AVAILABLE = 0xac, }; +/// HID Usage Table - Lighting And Illumination Page (0x59) +enum { + HID_USAGE_LIGHTING_LAMP_ARRAY = 0x01, + HID_USAGE_LIGHTING_LAMP_ARRAY_ATTRIBUTES_REPORT = 0x02, + HID_USAGE_LIGHTING_LAMP_COUNT = 0x03, + HID_USAGE_LIGHTING_BOUNDING_BOX_WIDTH_IN_MICROMETERS = 0x04, + HID_USAGE_LIGHTING_BOUNDING_BOX_HEIGHT_IN_MICROMETERS = 0x05, + HID_USAGE_LIGHTING_BOUNDING_BOX_DEPTH_IN_MICROMETERS = 0x06, + HID_USAGE_LIGHTING_LAMP_ARRAY_KIND = 0x07, + HID_USAGE_LIGHTING_MIN_UPDATE_INTERVAL_IN_MICROSECONDS = 0x08, + HID_USAGE_LIGHTING_LAMP_ATTRIBUTES_REQUEST_REPORT = 0x20, + HID_USAGE_LIGHTING_LAMP_ID = 0x21, + HID_USAGE_LIGHTING_LAMP_ATTRIBUTES_RESPONSE_REPORT = 0x22, + HID_USAGE_LIGHTING_POSITION_X_IN_MICROMETERS = 0x23, + HID_USAGE_LIGHTING_POSITION_Y_IN_MICROMETERS = 0x24, + HID_USAGE_LIGHTING_POSITION_Z_IN_MICROMETERS = 0x25, + HID_USAGE_LIGHTING_LAMP_PURPOSES = 0x26, + HID_USAGE_LIGHTING_UPDATE_LATENCY_IN_MICROSECONDS = 0x27, + HID_USAGE_LIGHTING_RED_LEVEL_COUNT = 0x28, + HID_USAGE_LIGHTING_GREEN_LEVEL_COUNT = 0x29, + HID_USAGE_LIGHTING_BLUE_LEVEL_COUNT = 0x2A, + HID_USAGE_LIGHTING_INTENSITY_LEVEL_COUNT = 0x2B, + HID_USAGE_LIGHTING_IS_PROGRAMMABLE = 0x2C, + HID_USAGE_LIGHTING_INPUT_BINDING = 0x2D, + HID_USAGE_LIGHTING_LAMP_MULTI_UPDATE_REPORT = 0x50, + HID_USAGE_LIGHTING_RED_UPDATE_CHANNEL = 0x51, + HID_USAGE_LIGHTING_GREEN_UPDATE_CHANNEL = 0x52, + HID_USAGE_LIGHTING_BLUE_UPDATE_CHANNEL = 0x53, + HID_USAGE_LIGHTING_INTENSITY_UPDATE_CHANNEL = 0x54, + HID_USAGE_LIGHTING_LAMP_UPDATE_FLAGS = 0x55, + HID_USAGE_LIGHTING_LAMP_RANGE_UPDATE_REPORT = 0x60, + HID_USAGE_LIGHTING_LAMP_ID_START = 0x61, + HID_USAGE_LIGHTING_LAMP_ID_END = 0x62, + HID_USAGE_LIGHTING_LAMP_ARRAY_CONTROL_REPORT = 0x70, + HID_USAGE_LIGHTING_AUTONOMOUS_MODE = 0x71, +}; + +/// HID Usage Table: FIDO Alliance Page (0xF1D0) +enum { + HID_USAGE_FIDO_U2FHID = 0x01, // U2FHID usage for top-level collection + HID_USAGE_FIDO_DATA_IN = 0x20, // Raw IN data report + HID_USAGE_FIDO_DATA_OUT = 0x21 // Raw OUT data report +}; + /*-------------------------------------------------------------------- * ASCII to KEYCODE Conversion * Expand to array of [128][2] (shift, keycode) diff --git a/src/class/hid/hid_device.h b/src/class/hid/hid_device.h index f6704c51a..fc1dbcbd8 100644 --- a/src/class/hid/hid_device.h +++ b/src/class/hid/hid_device.h @@ -273,8 +273,8 @@ void tud_hid_report_failed_cb(uint8_t instance, hid_report_type_t report_type, u __VA_ARGS__ \ HID_USAGE ( HID_USAGE_DIGITIZER_STYLUS ) , \ HID_COLLECTION ( HID_COLLECTION_PHYSICAL ) , \ - HID_USAGE_PAGE ( HID_USAGE_PAGE_TIP_SWITCH ) , \ - HID_USAGE_PAGE ( HID_USAGE_PAGE_IN_RANGE ) , \ + HID_USAGE_PAGE ( HID_USAGE_DIGITIZER_TIP_SWITCH ) , \ + HID_USAGE_PAGE ( HID_USAGE_DIGITIZER_IN_RANGE ) , \ HID_LOGICAL_MIN ( 0 ), \ HID_LOGICAL_MAX ( 1 ), \ HID_REPORT_SIZE ( 1 ), \ -- cgit v1.3.1 From 85247e50ddc17347fca1f6c9b9fedb1227eda25f Mon Sep 17 00:00:00 2001 From: hathach Date: Wed, 12 Feb 2025 11:34:32 +0700 Subject: clean up --- hw/bsp/rp2040/family.cmake | 30 +++++++++++++++--------------- src/class/midi/midi_device.c | 2 +- src/device/usbd.c | 13 ++++++------- src/host/usbh.c | 8 ++++++-- src/tusb_option.h | 6 +++--- 5 files changed, 31 insertions(+), 28 deletions(-) (limited to 'src/class') diff --git a/hw/bsp/rp2040/family.cmake b/hw/bsp/rp2040/family.cmake index cf5295f22..1cbc0742c 100644 --- a/hw/bsp/rp2040/family.cmake +++ b/hw/bsp/rp2040/family.cmake @@ -100,21 +100,21 @@ target_sources(tinyusb_device_base INTERFACE ${TOP}/src/class/video/video_device.c ) - #------------------------------------ - # Base config for host mode; wrapped by SDK's tinyusb_host - #------------------------------------ - add_library(tinyusb_host_base INTERFACE) - target_sources(tinyusb_host_base INTERFACE - ${TOP}/src/portable/raspberrypi/rp2040/hcd_rp2040.c - ${TOP}/src/portable/raspberrypi/rp2040/rp2040_usb.c - ${TOP}/src/host/usbh.c - ${TOP}/src/host/hub.c - ${TOP}/src/class/cdc/cdc_host.c - ${TOP}/src/class/hid/hid_host.c - ${TOP}/src/class/midi/midi_host.c - ${TOP}/src/class/msc/msc_host.c - ${TOP}/src/class/vendor/vendor_host.c - ) +#------------------------------------ +# Base config for host mode; wrapped by SDK's tinyusb_host +#------------------------------------ +add_library(tinyusb_host_base INTERFACE) +target_sources(tinyusb_host_base INTERFACE + ${TOP}/src/portable/raspberrypi/rp2040/hcd_rp2040.c + ${TOP}/src/portable/raspberrypi/rp2040/rp2040_usb.c + ${TOP}/src/host/usbh.c + ${TOP}/src/host/hub.c + ${TOP}/src/class/cdc/cdc_host.c + ${TOP}/src/class/hid/hid_host.c + ${TOP}/src/class/midi/midi_host.c + ${TOP}/src/class/msc/msc_host.c + ${TOP}/src/class/vendor/vendor_host.c + ) # Sometimes have to do host specific actions in mostly common functions target_compile_definitions(tinyusb_host_base INTERFACE diff --git a/src/class/midi/midi_device.c b/src/class/midi/midi_device.c index 4ae8ea8fa..dd1883e37 100644 --- a/src/class/midi/midi_device.c +++ b/src/class/midi/midi_device.c @@ -440,7 +440,7 @@ uint16_t midid_open(uint8_t rhport, const tusb_desc_interface_t* desc_itf, uint1 drv_len = tu_desc_len(desc_itf); p_desc = tu_desc_next(desc_itf); // Skip Class Specific descriptors - while ( TUSB_DESC_CS_INTERFACE == tu_desc_type(p_desc) && drv_len <= max_len ) { + 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); } diff --git a/src/device/usbd.c b/src/device/usbd.c index 20f803563..faf926855 100644 --- a/src/device/usbd.c +++ b/src/device/usbd.c @@ -1032,14 +1032,13 @@ static bool process_set_config(uint8_t rhport, uint8_t cfg_num) #endif #if CFG_TUD_MIDI - if ( driver->open == midid_open ) - { - // If there is a class-compliant Audio Control Class, then 2 interfaces - // Otherwise, only one + if (driver->open == midid_open) { + // If there is a class-compliant Audio Control Class, then 2 interfaces. Otherwise, only one if (TUSB_CLASS_AUDIO == desc_itf->bInterfaceClass && - AUDIO_SUBCLASS_CONTROL == desc_itf->bInterfaceSubClass && - AUDIO_FUNC_PROTOCOL_CODE_UNDEF == desc_itf->bInterfaceProtocol) - assoc_itf_count = 2; + AUDIO_SUBCLASS_CONTROL == desc_itf->bInterfaceSubClass && + AUDIO_FUNC_PROTOCOL_CODE_UNDEF == desc_itf->bInterfaceProtocol) { + assoc_itf_count = 2; + } } #endif diff --git a/src/host/usbh.c b/src/host/usbh.c index 6f7a8b8bf..30a4f5f63 100644 --- a/src/host/usbh.c +++ b/src/host/usbh.c @@ -1488,7 +1488,9 @@ static void process_enumeration(tuh_xfer_t* xfer) { dev->i_product = desc_device->iProduct; dev->i_serial = desc_device->iSerialNumber; - if (tuh_desc_device_cb) tuh_desc_device_cb(daddr, (tusb_desc_device_t const*) _usbh_ctrl_buf); + if (tuh_desc_device_cb) { + tuh_desc_device_cb(daddr, (tusb_desc_device_t const*) _usbh_ctrl_buf); + } // Get 9-byte for total length uint8_t const config_idx = CONFIG_NUM - 1; @@ -1517,7 +1519,9 @@ static void process_enumeration(tuh_xfer_t* xfer) { } case ENUM_SET_CONFIG: - if (tuh_desc_config_cb) tuh_desc_config_cb(daddr, (const tusb_desc_configuration_t*) _usbh_ctrl_buf); + if (tuh_desc_config_cb) { + tuh_desc_config_cb(daddr, (const tusb_desc_configuration_t*) _usbh_ctrl_buf); + } TU_ASSERT(tuh_configuration_set(daddr, CONFIG_NUM, process_enumeration, ENUM_CONFIG_DRIVER),); break; diff --git a/src/tusb_option.h b/src/tusb_option.h index 84319939a..29fdcb0d6 100644 --- a/src/tusb_option.h +++ b/src/tusb_option.h @@ -657,9 +657,9 @@ //------------------------------------------------------------------ // Configuration Validation //------------------------------------------------------------------ -//#if CFG_TUD_ENDPOINT0_SIZE > 64 -// #error Control Endpoint Max Packet Size cannot be larger than 64 -//#endif +#if CFG_TUD_ENDPOINT0_SIZE > 64 + #error Control Endpoint Max Packet Size cannot be larger than 64 +#endif // To avoid GCC compiler warnings when -pedantic option is used (strict ISO C) typedef int make_iso_compilers_happy; -- cgit v1.3.1 From 294fb268d7bf36d163363fa669f3984fc95bfd32 Mon Sep 17 00:00:00 2001 From: hathach Date: Wed, 12 Feb 2025 11:39:26 +0700 Subject: pre-commit fix --- examples/host/midi_rx/CMakeLists.txt | 2 +- examples/host/midi_rx/Makefile | 2 +- examples/host/midi_rx/src/main.c | 2 +- src/class/midi/README_midi_host.md | 14 +++++++------- src/class/midi/midi_host.c | 14 +++++++------- src/class/midi/midi_host.h | 4 ++-- 6 files changed, 19 insertions(+), 19 deletions(-) (limited to 'src/class') diff --git a/examples/host/midi_rx/CMakeLists.txt b/examples/host/midi_rx/CMakeLists.txt index 4856e0a47..b5e5f6bc8 100644 --- a/examples/host/midi_rx/CMakeLists.txt +++ b/examples/host/midi_rx/CMakeLists.txt @@ -24,4 +24,4 @@ target_include_directories(${PROJECT} PUBLIC # Configure compilation flags and libraries for the example... see the corresponding function # in hw/bsp/FAMILY/family.cmake for details. -family_configure_host_example(${PROJECT}) \ No newline at end of file +family_configure_host_example(${PROJECT}) diff --git a/examples/host/midi_rx/Makefile b/examples/host/midi_rx/Makefile index f830617ac..af8ef4275 100644 --- a/examples/host/midi_rx/Makefile +++ b/examples/host/midi_rx/Makefile @@ -6,4 +6,4 @@ INC += \ # Example source EXAMPLE_SOURCE += $(wildcard src/*.c) SRC_C += $(addprefix $(CURRENT_PATH)/, $(EXAMPLE_SOURCE)) -include ../../rules.mk \ No newline at end of file +include ../../rules.mk diff --git a/examples/host/midi_rx/src/main.c b/examples/host/midi_rx/src/main.c index 6fe17255a..6c3311043 100644 --- a/examples/host/midi_rx/src/main.c +++ b/examples/host/midi_rx/src/main.c @@ -157,4 +157,4 @@ void tuh_midi_rx_cb(uint8_t dev_addr, uint32_t num_packets) void tuh_midi_tx_cb(uint8_t dev_addr) { (void ) dev_addr; -} \ No newline at end of file +} diff --git a/src/class/midi/README_midi_host.md b/src/class/midi/README_midi_host.md index 9df2249b3..efaf7a13d 100644 --- a/src/class/midi/README_midi_host.md +++ b/src/class/midi/README_midi_host.md @@ -9,7 +9,7 @@ constraint may change in the future. # MAXIMUM NUMBER OF ENDPOINTS Although the USB MIDI 1.0 Class specification allows an arbitrary number of endpoints, this driver supports at most one USB BULK DATA IN endpoint -and one USB BULK DATA OUT endpoint. Each endpoint can support up to 16 +and one USB BULK DATA OUT endpoint. Each endpoint can support up to 16 virtual cables. If a device has multiple IN endpoints or multiple OUT endpoints, it will fail to enumerate. @@ -51,9 +51,9 @@ pointer points to a MIDI interface descriptor, call midih_open() with that descriptor pointer. # CLASS SPECIFIC INTERFACE AND REQUESTS -The host driver does not make use of the informaton in the class specific +The host driver does not make use of the information in the class specific interface descriptors. In the future, a public API could be created to -retrieve the string descriptors for the names of each ELEMENT, +retrieve the string descriptors for the names of each ELEMENT, IN JACK and OUT JACK, and how the device describes the connections. This driver also does not support class specific requests to control @@ -68,18 +68,18 @@ Descriptors. This is wrong per my reading of the specification. # MESSAGE BUFFER DETAILS Messages buffers composed from USB data received on the IN endpoint will never contain running status because USB MIDI 1.0 class does not support that. Messages -buffers to be sent to the device on the OUT endpont may contain running status +buffers to be sent to the device on the OUT endpoint may contain running status (the message might come from a UART data stream from a 5-pin DIN MIDI IN -cable on the host, for example). The driver may in the future correctly compose +cable on the host, for example). The driver may in the future correctly compose 4-byte USB MIDI Class packets using the running status if need be. However, it does not currently do that. Also, use of running status is not a good idea overall because a single byte error can really mess up the data stream with no way to recover until the next non-real time status byte is in the message buffer. Message buffers to be sent to the device may contain Real time messages -such as MIDI clock. Real time messages may be inserted in the message +such as MIDI clock. Real time messages may be inserted in the message byte stream between status and data bytes of another message without disrupting -the running status. However, because MIDI 1.0 class messages are sent +the running status. However, because MIDI 1.0 class messages are sent as four byte packets, a real-time message so inserted will be re-ordered to be sent to the device in a new 4-byte packet immediately before the interrupted data stream. diff --git a/src/class/midi/midi_host.c b/src/class/midi/midi_host.c index 32311556e..061e17fee 100644 --- a/src/class/midi/midi_host.c +++ b/src/class/midi/midi_host.c @@ -1,4 +1,4 @@ -/* +/* * The MIT License (MIT) * * Copyright (c) 2019 Ha Thach (tinyusb.org) @@ -76,7 +76,7 @@ typedef struct // Endpoint FIFOs tu_fifo_t rx_ff; tu_fifo_t tx_ff; - + uint8_t rx_ff_buf[CFG_TUH_MIDI_RX_BUFSIZE]; uint8_t tx_ff_buf[CFG_TUH_MIDI_TX_BUFSIZE]; @@ -280,17 +280,17 @@ bool midih_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *d // assume it is an interface header midi_desc_header_t const *p_mdh = (midi_desc_header_t const *)p_desc; - TU_VERIFY((p_mdh->bDescriptorType == TUSB_DESC_CS_INTERFACE && p_mdh->bDescriptorSubType == MIDI_CS_INTERFACE_HEADER) || + TU_VERIFY((p_mdh->bDescriptorType == TUSB_DESC_CS_INTERFACE && p_mdh->bDescriptorSubType == MIDI_CS_INTERFACE_HEADER) || (p_mdh->bDescriptorType == TUSB_DESC_CS_ENDPOINT && p_mdh->bDescriptorSubType == MIDI_CS_ENDPOINT_GENERAL) || p_mdh->bDescriptorType == TUSB_DESC_ENDPOINT); - uint8_t prev_ep_addr = 0; // the CS endpoint descriptor is associated with the previous endpoint descrptor + uint8_t prev_ep_addr = 0; // the CS endpoint descriptor is associated with the previous endpoint descriptor p_midi_host->itf_num = desc_itf->bInterfaceNumber; tusb_desc_endpoint_t const* in_desc = NULL; tusb_desc_endpoint_t const* out_desc = NULL; while (len_parsed < max_len) { - TU_VERIFY((p_mdh->bDescriptorType == TUSB_DESC_CS_INTERFACE) || + TU_VERIFY((p_mdh->bDescriptorType == TUSB_DESC_CS_INTERFACE) || (p_mdh->bDescriptorType == TUSB_DESC_CS_ENDPOINT && p_mdh->bDescriptorSubType == MIDI_CS_ENDPOINT_GENERAL) || p_mdh->bDescriptorType == TUSB_DESC_ENDPOINT); @@ -306,7 +306,7 @@ bool midih_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *d } else if (p_mdij->bDescriptorSubType == MIDI_CS_INTERFACE_IN_JACK) { - // Then it is an in jack. + // Then it is an in jack. TU_LOG2("Found in jack\r\n"); #if CFG_MIDI_HOST_DEVSTRINGS if (p_midi_host->next_in_jack < MAX_IN_JACKS) @@ -370,7 +370,7 @@ bool midih_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *d TU_LOG2("found CS_ENDPOINT Descriptor for %u\r\n", prev_ep_addr); TU_VERIFY(prev_ep_addr != 0); // parse out the mapping between the device's embedded jacks and the endpoints - // Each embedded IN jack is assocated with an OUT endpoint + // Each embedded IN jack is associated with an OUT endpoint midi_cs_desc_endpoint_t const* p_csep = (midi_cs_desc_endpoint_t const*)p_mdh; if (tu_edpt_dir(prev_ep_addr) == TUSB_DIR_OUT) { diff --git a/src/class/midi/midi_host.h b/src/class/midi/midi_host.h index 8180e3309..292c596e4 100644 --- a/src/class/midi/midi_host.h +++ b/src/class/midi/midi_host.h @@ -1,4 +1,4 @@ -/* +/* * The MIT License (MIT) * * Copyright (c) 2019 Ha Thach (tinyusb.org) @@ -118,7 +118,7 @@ void midih_close (uint8_t dev_addr); //--------------------------------------------------------------------+ // Invoked when device with MIDI interface is mounted. -// If the MIDI host application requires MIDI IN, it should requst an +// If the MIDI host application requires MIDI IN, it should request an // IN transfer here. The device will likely NAK this transfer. How the driver // handles the NAK is hardware dependent. TU_ATTR_WEAK void tuh_midi_mount_cb(uint8_t dev_addr, uint8_t in_ep, uint8_t out_ep, uint8_t num_cables_rx, uint16_t num_cables_tx); -- cgit v1.3.1 From 7c405236cfcf0850032ec0190eea1f01fb631ef9 Mon Sep 17 00:00:00 2001 From: hathach Date: Wed, 12 Feb 2025 11:50:57 +0700 Subject: fix host midi build --- examples/host/midi_rx/CMakeLists.txt | 25 +++++++++++++++---------- examples/host/midi_rx/Makefile | 12 ++++++++---- examples/host/midi_rx/only.txt | 19 +++++++++++++++++++ examples/host/midi_rx/src/main.c | 4 +--- src/CMakeLists.txt | 1 + src/class/midi/midi_host.c | 5 +++-- src/class/midi/midi_host.h | 2 +- src/host/usbh.c | 4 ++-- src/tinyusb.mk | 1 + 9 files changed, 51 insertions(+), 22 deletions(-) (limited to 'src/class') diff --git a/examples/host/midi_rx/CMakeLists.txt b/examples/host/midi_rx/CMakeLists.txt index b5e5f6bc8..33953233d 100644 --- a/examples/host/midi_rx/CMakeLists.txt +++ b/examples/host/midi_rx/CMakeLists.txt @@ -1,27 +1,32 @@ -cmake_minimum_required(VERSION 3.5) +cmake_minimum_required(VERSION 3.20) include(${CMAKE_CURRENT_SOURCE_DIR}/../../../hw/bsp/family_support.cmake) -# gets PROJECT name for the example (e.g. -) +# gets PROJECT name for the example family_get_project_name(PROJECT ${CMAKE_CURRENT_LIST_DIR}) -project(${PROJECT}) +project(${PROJECT} C CXX ASM) # Checks this example is valid for the family and initializes the project family_initialize_project(${PROJECT} ${CMAKE_CURRENT_LIST_DIR}) +# Espressif has its own cmake build system +if(FAMILY STREQUAL "espressif") + return() +endif() + add_executable(${PROJECT}) # Example source target_sources(${PROJECT} PUBLIC - ${CMAKE_CURRENT_SOURCE_DIR}/src/main.c - ) + ${CMAKE_CURRENT_SOURCE_DIR}/src/main.c + ) # Example include target_include_directories(${PROJECT} PUBLIC - ${CMAKE_CURRENT_SOURCE_DIR}/src - ) + ${CMAKE_CURRENT_SOURCE_DIR}/src + ) -# Configure compilation flags and libraries for the example... see the corresponding function -# in hw/bsp/FAMILY/family.cmake for details. -family_configure_host_example(${PROJECT}) +# Configure compilation flags and libraries for the example without RTOS. +# See the corresponding function in hw/bsp/FAMILY/family.cmake for details. +family_configure_host_example(${PROJECT} noos) diff --git a/examples/host/midi_rx/Makefile b/examples/host/midi_rx/Makefile index af8ef4275..0235e08c3 100644 --- a/examples/host/midi_rx/Makefile +++ b/examples/host/midi_rx/Makefile @@ -1,9 +1,13 @@ -include ../../../tools/top.mk -include ../../make.mk +include ../../build_system/make/make.mk + INC += \ src \ $(TOP)/hw \ + # Example source -EXAMPLE_SOURCE += $(wildcard src/*.c) +EXAMPLE_SOURCE += \ + src/main.c + SRC_C += $(addprefix $(CURRENT_PATH)/, $(EXAMPLE_SOURCE)) -include ../../rules.mk + +include ../../build_system/make/rules.mk diff --git a/examples/host/midi_rx/only.txt b/examples/host/midi_rx/only.txt index 2ba4438fd..b6f87f423 100644 --- a/examples/host/midi_rx/only.txt +++ b/examples/host/midi_rx/only.txt @@ -1 +1,20 @@ +mcu:ESP32S2 +mcu:ESP32S3 +mcu:ESP32P4 +mcu:KINETIS_KL +mcu:LPC175X_6X +mcu:LPC177X_8X +mcu:LPC18XX +mcu:LPC40XX +mcu:LPC43XX +mcu:MAX3421 +mcu:MIMXRT1XXX +mcu:MIMXRT10XX +mcu:MIMXRT11XX +mcu:MSP432E4 mcu:RP2040 +mcu:RX65X +mcu:RAXXX +mcu:STM32F4 +mcu:STM32F7 +mcu:STM32H7 diff --git a/examples/host/midi_rx/src/main.c b/examples/host/midi_rx/src/main.c index 6c3311043..8b83977e2 100644 --- a/examples/host/midi_rx/src/main.c +++ b/examples/host/midi_rx/src/main.c @@ -27,10 +27,8 @@ #include #include -#include "bsp/board.h" +#include "bsp/board_api.h" #include "tusb.h" -#include "class/midi/midi_host.h" - #if CFG_TUH_MIDI diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 7b3ab4d42..55c52033c 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -29,6 +29,7 @@ function(tinyusb_target_add TARGET) ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/host/hub.c ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/class/cdc/cdc_host.c ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/class/hid/hid_host.c + ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/class/midi/midi_host.c ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/class/msc/msc_host.c ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/class/vendor/vendor_host.c # typec diff --git a/src/class/midi/midi_host.c b/src/class/midi/midi_host.c index 061e17fee..fbb994ade 100644 --- a/src/class/midi/midi_host.c +++ b/src/class/midi/midi_host.c @@ -29,7 +29,7 @@ #if (TUSB_OPT_HOST_ENABLED && CFG_TUH_MIDI) #include "host/usbh.h" -#include "host/usbh_classdriver.h" +#include "host/usbh_pvt.h" #include "midi_host.h" @@ -131,7 +131,7 @@ static uint32_t write_flush(uint8_t dev_addr, midih_interface_t* midi); //--------------------------------------------------------------------+ // USBH API //--------------------------------------------------------------------+ -void midih_init(void) +bool midih_init(void) { tu_memclr(&_midi_host, sizeof(_midi_host)); // config fifos @@ -146,6 +146,7 @@ void midih_init(void) tu_fifo_config_mutex(&p_midi_host->tx_ff, osal_mutex_create(&p_midi_host->tx_ff_mutex), NULL); #endif } + return true; } bool midih_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) diff --git a/src/class/midi/midi_host.h b/src/class/midi/midi_host.h index 292c596e4..edf57bfcb 100644 --- a/src/class/midi/midi_host.h +++ b/src/class/midi/midi_host.h @@ -107,7 +107,7 @@ uint8_t tuh_midi_get_all_istrings(uint8_t dev_addr, const uint8_t** istrings); //--------------------------------------------------------------------+ // Internal Class Driver API //--------------------------------------------------------------------+ -void midih_init (void); +bool midih_init (void); bool midih_open (uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *desc_itf, uint16_t max_len); bool midih_set_config (uint8_t dev_addr, uint8_t itf_num); bool midih_xfer_cb (uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes); diff --git a/src/host/usbh.c b/src/host/usbh.c index 30a4f5f63..e38ee3187 100644 --- a/src/host/usbh.c +++ b/src/host/usbh.c @@ -1489,7 +1489,7 @@ static void process_enumeration(tuh_xfer_t* xfer) { dev->i_serial = desc_device->iSerialNumber; if (tuh_desc_device_cb) { - tuh_desc_device_cb(daddr, (tusb_desc_device_t const*) _usbh_ctrl_buf); + tuh_desc_device_cb(daddr, (tusb_desc_device_t const*) _usbh_epbuf.ctrl); } // Get 9-byte for total length @@ -1520,7 +1520,7 @@ static void process_enumeration(tuh_xfer_t* xfer) { case ENUM_SET_CONFIG: if (tuh_desc_config_cb) { - tuh_desc_config_cb(daddr, (const tusb_desc_configuration_t*) _usbh_ctrl_buf); + tuh_desc_config_cb(daddr, (const tusb_desc_configuration_t*) _usbh_epbuf.ctrl); } TU_ASSERT(tuh_configuration_set(daddr, CONFIG_NUM, process_enumeration, ENUM_CONFIG_DRIVER),); diff --git a/src/tinyusb.mk b/src/tinyusb.mk index 89ea0212c..a9f623c24 100644 --- a/src/tinyusb.mk +++ b/src/tinyusb.mk @@ -21,6 +21,7 @@ TINYUSB_SRC_C += \ src/host/hub.c \ src/class/cdc/cdc_host.c \ src/class/hid/hid_host.c \ + src/class/midi/midi_host.c \ src/class/msc/msc_host.c \ src/class/vendor/vendor_host.c \ src/typec/usbc.c \ -- cgit v1.3.1 From e0b192b633e70338ef5ac88c7f5a49f37867b289 Mon Sep 17 00:00:00 2001 From: hathach Date: Wed, 12 Feb 2025 22:16:08 +0700 Subject: - use CFG_TUH_MIDI as number of midi host instance - comment out tuh_descriptor_device_cb/tuh_desc_configuration_cb since it is unrelated to this PR --- examples/host/midi_rx/src/tusb_config.h | 3 +- src/class/midi/midi_host.c | 289 ++++++++++++++------------------ src/class/midi/midi_host.h | 19 ++- src/host/usbh.c | 8 +- src/host/usbh.h | 8 +- 5 files changed, 151 insertions(+), 176 deletions(-) (limited to 'src/class') diff --git a/examples/host/midi_rx/src/tusb_config.h b/examples/host/midi_rx/src/tusb_config.h index 1afcbbd63..24b3b3ae6 100644 --- a/examples/host/midi_rx/src/tusb_config.h +++ b/examples/host/midi_rx/src/tusb_config.h @@ -107,10 +107,9 @@ extern "C" { #define CFG_TUH_ENUMERATION_BUFSIZE 256 #define CFG_TUH_HUB 1 -#define CFG_TUH_MIDI 1 // there will be at most one MIDIStreaming Interface descriptor - // max device support (excluding hub device): 1 hub typically has 4 ports #define CFG_TUH_DEVICE_MAX (3*CFG_TUH_HUB + 1) +#define CFG_TUH_MIDI CFG_TUH_DEVICE_MAX #define CFG_MIDI_HOST_DEVSTRINGS 1 diff --git a/src/class/midi/midi_host.c b/src/class/midi/midi_host.c index fbb994ade..21fe09143 100644 --- a/src/class/midi/midi_host.c +++ b/src/class/midi/midi_host.c @@ -36,14 +36,6 @@ //--------------------------------------------------------------------+ // MACRO CONSTANT TYPEDEF //--------------------------------------------------------------------+ -#ifndef CFG_TUH_MAX_CABLES - #define CFG_TUH_MAX_CABLES 16 -#endif -#define CFG_TUH_MIDI_RX_BUFSIZE 64 -#define CFG_TUH_MIDI_TX_BUFSIZE 64 -#ifndef CFG_TUH_MIDI_EP_BUFSIZE - #define CFG_TUH_MIDI_EP_BUFSIZE 64 -#endif // TODO: refactor to share code with the MIDI Device driver typedef struct @@ -117,34 +109,44 @@ typedef struct #endif }midih_interface_t; -static midih_interface_t _midi_host[CFG_TUH_DEVICE_MAX]; - -static midih_interface_t *get_midi_host(uint8_t dev_addr) -{ - TU_VERIFY(dev_addr >0 && dev_addr <= CFG_TUH_DEVICE_MAX); - return (_midi_host + dev_addr - 1); -} +static midih_interface_t _midi_host[CFG_TUH_MIDI]; //------------- Internal prototypes -------------// static uint32_t write_flush(uint8_t dev_addr, midih_interface_t* midi); +//--------------------------------------------------------------------+ +// Helper +//--------------------------------------------------------------------+ + +TU_ATTR_ALWAYS_INLINE static inline midih_interface_t* find_midi_by_daddr(uint8_t dev_addr) { + for (uint8_t i = 0; i < CFG_TUH_MIDI; i++) { + if (_midi_host[i].dev_addr == dev_addr) { + return &_midi_host[i]; + } + } + return NULL; +} + +TU_ATTR_ALWAYS_INLINE static inline midih_interface_t* find_new_midi(void) { + return find_midi_by_daddr(0); +} + + //--------------------------------------------------------------------+ // USBH API //--------------------------------------------------------------------+ -bool midih_init(void) -{ +bool midih_init(void) { tu_memclr(&_midi_host, sizeof(_midi_host)); // config fifos - for (int inst = 0; inst < CFG_TUH_DEVICE_MAX; inst++) - { + for (int inst = 0; inst < CFG_TUH_MIDI; inst++) { midih_interface_t *p_midi_host = &_midi_host[inst]; - tu_fifo_config(&p_midi_host->rx_ff, p_midi_host->rx_ff_buf, CFG_TUH_MIDI_RX_BUFSIZE, 1, false); // true, true - tu_fifo_config(&p_midi_host->tx_ff, p_midi_host->tx_ff_buf, CFG_TUH_MIDI_TX_BUFSIZE, 1, false); // OBVS. + tu_fifo_config(&p_midi_host->rx_ff, p_midi_host->rx_ff_buf, CFG_TUH_MIDI_RX_BUFSIZE, 1, false);// true, true + tu_fifo_config(&p_midi_host->tx_ff, p_midi_host->tx_ff_buf, CFG_TUH_MIDI_TX_BUFSIZE, 1, false);// OBVS. - #if CFG_FIFO_MUTEX + #if CFG_FIFO_MUTEX tu_fifo_config_mutex(&p_midi_host->rx_ff, NULL, osal_mutex_create(&p_midi_host->rx_ff_mutex)); tu_fifo_config_mutex(&p_midi_host->tx_ff, osal_mutex_create(&p_midi_host->tx_ff_mutex), NULL); - #endif + #endif } return true; } @@ -152,7 +154,7 @@ bool midih_init(void) bool midih_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) { (void)result; - midih_interface_t *p_midi_host = get_midi_host(dev_addr); + midih_interface_t *p_midi_host = find_midi_by_daddr(dev_addr); TU_VERIFY(p_midi_host != NULL); if ( ep_addr == p_midi_host->ep_in) { @@ -211,13 +213,14 @@ bool midih_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, uint return true; } -void midih_close(uint8_t dev_addr) -{ - midih_interface_t *p_midi_host = get_midi_host(dev_addr); - if (p_midi_host == NULL) +void midih_close(uint8_t dev_addr) { + midih_interface_t *p_midi_host = find_midi_by_daddr(dev_addr); + if (p_midi_host == NULL) { return; - if (tuh_midi_umount_cb) + } + if (tuh_midi_umount_cb) { tuh_midi_umount_cb(dev_addr, 0); + } tu_fifo_clear(&p_midi_host->rx_ff); tu_fifo_clear(&p_midi_host->tx_ff); p_midi_host->ep_in = 0; @@ -240,24 +243,24 @@ bool midih_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *d { (void) rhport; - midih_interface_t *p_midi_host = get_midi_host(dev_addr); - + midih_interface_t *p_midi_host = find_new_midi(); TU_VERIFY(p_midi_host != NULL); + p_midi_host->num_string_indices = 0; TU_VERIFY(TUSB_CLASS_AUDIO == desc_itf->bInterfaceClass); // There can be just a MIDI interface or an audio and a MIDI interface. Only open the MIDI interface uint8_t const *p_desc = (uint8_t const *) desc_itf; uint16_t len_parsed = 0; - if (AUDIO_SUBCLASS_CONTROL == desc_itf->bInterfaceSubClass) - { + if (AUDIO_SUBCLASS_CONTROL == desc_itf->bInterfaceSubClass) { // Keep track of any string descriptor that might be here - if (desc_itf->iInterface != 0) - p_midi_host->all_string_indices[p_midi_host->num_string_indices++] = desc_itf->iInterface; + if (desc_itf->iInterface != 0) { + p_midi_host->all_string_indices[p_midi_host->num_string_indices++] = desc_itf->iInterface; + } // This driver does not support audio streaming. However, if this is the audio control interface // there might be a MIDI interface following it. Search through every descriptor until a MIDI // interface is found or the end of the descriptor is found - while (len_parsed < max_len && (desc_itf->bInterfaceClass != TUSB_CLASS_AUDIO || desc_itf->bInterfaceSubClass != AUDIO_SUBCLASS_MIDI_STREAMING)) - { + while (len_parsed < max_len && + (desc_itf->bInterfaceClass != TUSB_CLASS_AUDIO || desc_itf->bInterfaceSubClass != AUDIO_SUBCLASS_MIDI_STREAMING)) { len_parsed += desc_itf->bLength; p_desc = tu_desc_next(p_desc); desc_itf = (tusb_desc_interface_t const *)p_desc; @@ -269,8 +272,9 @@ bool midih_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *d len_parsed += desc_itf->bLength; // Keep track of any string descriptor that might be here - if (desc_itf->iInterface != 0) - p_midi_host->all_string_indices[p_midi_host->num_string_indices++] = desc_itf->iInterface; + if (desc_itf->iInterface != 0) { + p_midi_host->all_string_indices[p_midi_host->num_string_indices++] = desc_itf->iInterface; + } p_desc = tu_desc_next(p_desc); TU_LOG1("MIDI opening Interface %u (addr = %u)\r\n", desc_itf->bInterfaceNumber, dev_addr); @@ -282,195 +286,169 @@ bool midih_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *d // assume it is an interface header midi_desc_header_t const *p_mdh = (midi_desc_header_t const *)p_desc; TU_VERIFY((p_mdh->bDescriptorType == TUSB_DESC_CS_INTERFACE && p_mdh->bDescriptorSubType == MIDI_CS_INTERFACE_HEADER) || - (p_mdh->bDescriptorType == TUSB_DESC_CS_ENDPOINT && p_mdh->bDescriptorSubType == MIDI_CS_ENDPOINT_GENERAL) || - p_mdh->bDescriptorType == TUSB_DESC_ENDPOINT); + (p_mdh->bDescriptorType == TUSB_DESC_CS_ENDPOINT && p_mdh->bDescriptorSubType == MIDI_CS_ENDPOINT_GENERAL) || + p_mdh->bDescriptorType == TUSB_DESC_ENDPOINT); uint8_t prev_ep_addr = 0; // the CS endpoint descriptor is associated with the previous endpoint descriptor p_midi_host->itf_num = desc_itf->bInterfaceNumber; tusb_desc_endpoint_t const* in_desc = NULL; tusb_desc_endpoint_t const* out_desc = NULL; - while (len_parsed < max_len) - { + while (len_parsed < max_len) { TU_VERIFY((p_mdh->bDescriptorType == TUSB_DESC_CS_INTERFACE) || - (p_mdh->bDescriptorType == TUSB_DESC_CS_ENDPOINT && p_mdh->bDescriptorSubType == MIDI_CS_ENDPOINT_GENERAL) || - p_mdh->bDescriptorType == TUSB_DESC_ENDPOINT); + (p_mdh->bDescriptorType == TUSB_DESC_CS_ENDPOINT && p_mdh->bDescriptorSubType == MIDI_CS_ENDPOINT_GENERAL) || + p_mdh->bDescriptorType == TUSB_DESC_ENDPOINT); if (p_mdh->bDescriptorType == TUSB_DESC_CS_INTERFACE) { // The USB host doesn't really need this information unless it uses // the string descriptor for a jack or Element // assume it is an input jack - midi_desc_in_jack_t const *p_mdij = (midi_desc_in_jack_t const *)p_desc; - if (p_mdij->bDescriptorSubType == MIDI_CS_INTERFACE_HEADER) - { + midi_desc_in_jack_t const *p_mdij = (midi_desc_in_jack_t const *) p_desc; + if (p_mdij->bDescriptorSubType == MIDI_CS_INTERFACE_HEADER) { TU_LOG2("Found MIDI Interface Header\r\b"); - } - else if (p_mdij->bDescriptorSubType == MIDI_CS_INTERFACE_IN_JACK) - { + } else if (p_mdij->bDescriptorSubType == MIDI_CS_INTERFACE_IN_JACK) { // Then it is an in jack. TU_LOG2("Found in jack\r\n"); -#if CFG_MIDI_HOST_DEVSTRINGS - if (p_midi_host->next_in_jack < MAX_IN_JACKS) - { + #if CFG_MIDI_HOST_DEVSTRINGS + if (p_midi_host->next_in_jack < MAX_IN_JACKS) { p_midi_host->in_jack_info[p_midi_host->next_in_jack].jack_id = p_mdij->bJackID; p_midi_host->in_jack_info[p_midi_host->next_in_jack].jack_type = p_mdij->bJackType; p_midi_host->in_jack_info[p_midi_host->next_in_jack].string_index = p_mdij->iJack; ++p_midi_host->next_in_jack; // Keep track of any string descriptor that might be here - if (p_mdij->iJack != 0) + if (p_mdij->iJack != 0) { p_midi_host->all_string_indices[p_midi_host->num_string_indices++] = p_mdij->iJack; - + } } -#endif - } - else if (p_mdij->bDescriptorSubType == MIDI_CS_INTERFACE_OUT_JACK) - { + #endif + } else if (p_mdij->bDescriptorSubType == MIDI_CS_INTERFACE_OUT_JACK) { // then it is an out jack TU_LOG2("Found out jack\r\n"); -#if CFG_MIDI_HOST_DEVSTRINGS - if (p_midi_host->next_out_jack < MAX_OUT_JACKS) - { - midi_desc_out_jack_t const *p_mdoj = (midi_desc_out_jack_t const *)p_desc; + #if CFG_MIDI_HOST_DEVSTRINGS + if (p_midi_host->next_out_jack < MAX_OUT_JACKS) { + midi_desc_out_jack_t const *p_mdoj = (midi_desc_out_jack_t const *) p_desc; p_midi_host->out_jack_info[p_midi_host->next_out_jack].jack_id = p_mdoj->bJackID; p_midi_host->out_jack_info[p_midi_host->next_out_jack].jack_type = p_mdoj->bJackType; p_midi_host->out_jack_info[p_midi_host->next_out_jack].num_source_ids = p_mdoj->bNrInputPins; const struct associated_jack_s { - uint8_t id; - uint8_t pin; - } *associated_jack = (const struct associated_jack_s *)(p_desc+6); + uint8_t id; + uint8_t pin; + } *associated_jack = (const struct associated_jack_s *) (p_desc + 6); int jack; - for (jack = 0; jack < p_mdoj->bNrInputPins; jack++) - { + for (jack = 0; jack < p_mdoj->bNrInputPins; jack++) { p_midi_host->out_jack_info[p_midi_host->next_out_jack].source_ids[jack] = associated_jack->id; } - p_midi_host->out_jack_info[p_midi_host->next_out_jack].string_index = *(p_desc+6+p_mdoj->bNrInputPins*2); + p_midi_host->out_jack_info[p_midi_host->next_out_jack].string_index = *(p_desc + 6 + p_mdoj->bNrInputPins * 2); ++p_midi_host->next_out_jack; - if (p_mdoj->iJack != 0) + if (p_mdoj->iJack != 0) { p_midi_host->all_string_indices[p_midi_host->num_string_indices++] = p_mdoj->iJack; + } } -#endif - } - else if (p_mdij->bDescriptorSubType == MIDI_CS_INTERFACE_ELEMENT) - { + #endif + } else if (p_mdij->bDescriptorSubType == MIDI_CS_INTERFACE_ELEMENT) { // the it is an element; - #if CFG_MIDI_HOST_DEVSTRINGS + #if CFG_MIDI_HOST_DEVSTRINGS TU_LOG1("Found element; strings not supported\r\n"); - #else + #else TU_LOG2("Found element\r\n"); - #endif - } - else - { + #endif + } else { TU_LOG2("Unknown CS Interface sub-type %u\r\n", p_mdij->bDescriptorSubType); - TU_VERIFY(false); // unknown CS Interface sub-type + TU_VERIFY(false);// unknown CS Interface sub-type } len_parsed += p_mdij->bLength; - } - else if (p_mdh->bDescriptorType == TUSB_DESC_CS_ENDPOINT) - { + } else if (p_mdh->bDescriptorType == TUSB_DESC_CS_ENDPOINT) { TU_LOG2("found CS_ENDPOINT Descriptor for %u\r\n", prev_ep_addr); TU_VERIFY(prev_ep_addr != 0); // parse out the mapping between the device's embedded jacks and the endpoints // Each embedded IN jack is associated with an OUT endpoint - midi_cs_desc_endpoint_t const* p_csep = (midi_cs_desc_endpoint_t const*)p_mdh; - if (tu_edpt_dir(prev_ep_addr) == TUSB_DIR_OUT) - { + midi_cs_desc_endpoint_t const *p_csep = (midi_cs_desc_endpoint_t const *) p_mdh; + if (tu_edpt_dir(prev_ep_addr) == TUSB_DIR_OUT) { TU_VERIFY(p_midi_host->ep_out == prev_ep_addr); TU_VERIFY(p_midi_host->num_cables_tx == 0); p_midi_host->num_cables_tx = p_csep->bNumEmbMIDIJack; -#if CFG_MIDI_HOST_DEVSTRINGS + #if CFG_MIDI_HOST_DEVSTRINGS uint8_t jack; uint8_t max_jack = p_midi_host->num_cables_tx; - if (max_jack > sizeof(p_midi_host->ep_out_associated_jacks)) - { - max_jack = sizeof(p_midi_host->ep_out_associated_jacks); + if (max_jack > sizeof(p_midi_host->ep_out_associated_jacks)) { + max_jack = sizeof(p_midi_host->ep_out_associated_jacks); } - for (jack = 0; jack < max_jack; jack++) - { + for (jack = 0; jack < max_jack; jack++) { p_midi_host->ep_out_associated_jacks[jack] = p_csep->baAssocJackID[jack]; } -#endif - } - else - { + #endif + } else { TU_VERIFY(p_midi_host->ep_in == prev_ep_addr); TU_VERIFY(p_midi_host->num_cables_rx == 0); p_midi_host->num_cables_rx = p_csep->bNumEmbMIDIJack; -#if CFG_MIDI_HOST_DEVSTRINGS + #if CFG_MIDI_HOST_DEVSTRINGS uint8_t jack; uint8_t max_jack = p_midi_host->num_cables_rx; - if (max_jack > sizeof(p_midi_host->ep_in_associated_jacks)) - { - max_jack = sizeof(p_midi_host->ep_in_associated_jacks); + if (max_jack > sizeof(p_midi_host->ep_in_associated_jacks)) { + max_jack = sizeof(p_midi_host->ep_in_associated_jacks); } - for (jack = 0; jack < max_jack; jack++) - { + for (jack = 0; jack < max_jack; jack++) { p_midi_host->ep_in_associated_jacks[jack] = p_csep->baAssocJackID[jack]; } -#endif + #endif } len_parsed += p_csep->bLength; prev_ep_addr = 0; - } - else if (p_mdh->bDescriptorType == TUSB_DESC_ENDPOINT) { + } else if (p_mdh->bDescriptorType == TUSB_DESC_ENDPOINT) { // parse out the bulk endpoint info - tusb_desc_endpoint_t const *p_ep = (tusb_desc_endpoint_t const *)p_mdh; + tusb_desc_endpoint_t const *p_ep = (tusb_desc_endpoint_t const *) p_mdh; TU_LOG2("found ENDPOINT Descriptor for %u\r\n", p_ep->bEndpointAddress); - if (tu_edpt_dir(p_ep->bEndpointAddress) == TUSB_DIR_OUT) - { + if (tu_edpt_dir(p_ep->bEndpointAddress) == TUSB_DIR_OUT) { TU_VERIFY(p_midi_host->ep_out == 0); TU_VERIFY(p_midi_host->num_cables_tx == 0); p_midi_host->ep_out = p_ep->bEndpointAddress; p_midi_host->ep_out_max = p_ep->wMaxPacketSize; - if (p_midi_host->ep_out_max > CFG_TUH_MIDI_TX_BUFSIZE) + if (p_midi_host->ep_out_max > CFG_TUH_MIDI_TX_BUFSIZE) { p_midi_host->ep_out_max = CFG_TUH_MIDI_TX_BUFSIZE; + } prev_ep_addr = p_midi_host->ep_out; out_desc = p_ep; - } - else - { + } else { TU_VERIFY(p_midi_host->ep_in == 0); TU_VERIFY(p_midi_host->num_cables_rx == 0); p_midi_host->ep_in = p_ep->bEndpointAddress; p_midi_host->ep_in_max = p_ep->wMaxPacketSize; - if (p_midi_host->ep_in_max > CFG_TUH_MIDI_RX_BUFSIZE) + if (p_midi_host->ep_in_max > CFG_TUH_MIDI_RX_BUFSIZE) { p_midi_host->ep_in_max = CFG_TUH_MIDI_RX_BUFSIZE; + } prev_ep_addr = p_midi_host->ep_in; in_desc = p_ep; } len_parsed += p_mdh->bLength; } p_desc = tu_desc_next(p_desc); - p_mdh = (midi_desc_header_t const *)p_desc; + p_mdh = (midi_desc_header_t const *) p_desc; } TU_VERIFY((p_midi_host->ep_out != 0 && p_midi_host->num_cables_tx != 0) || (p_midi_host->ep_in != 0 && p_midi_host->num_cables_rx != 0)); TU_LOG1("MIDI descriptor parsed successfully\r\n"); // remove duplicate string indices - for (int idx=0; idx < p_midi_host->num_string_indices; idx++) { - for (int jdx = idx+1; jdx < p_midi_host->num_string_indices; jdx++) { - while (jdx < p_midi_host->num_string_indices && p_midi_host->all_string_indices[idx] == p_midi_host->all_string_indices[jdx]) { - // delete the duplicate by overwriting it with the last entry and reducing the number of entries by 1 - p_midi_host->all_string_indices[jdx] = p_midi_host->all_string_indices[p_midi_host->num_string_indices-1]; - --p_midi_host->num_string_indices; - } + for (int idx = 0; idx < p_midi_host->num_string_indices; idx++) { + for (int jdx = idx + 1; jdx < p_midi_host->num_string_indices; jdx++) { + while (jdx < p_midi_host->num_string_indices && p_midi_host->all_string_indices[idx] == p_midi_host->all_string_indices[jdx]) { + // delete the duplicate by overwriting it with the last entry and reducing the number of entries by 1 + p_midi_host->all_string_indices[jdx] = p_midi_host->all_string_indices[p_midi_host->num_string_indices - 1]; + --p_midi_host->num_string_indices; } + } } - if (in_desc) - { + if (in_desc) { TU_ASSERT(tuh_edpt_open(dev_addr, in_desc)); // Some devices always return exactly the request length so transfers won't complete // unless you assume every transfer is the last one. // TODO usbh_edpt_force_last_buffer(dev_addr, p_midi_host->ep_in, true); } - if (out_desc) - { + if (out_desc) { TU_ASSERT(tuh_edpt_open(dev_addr, out_desc)); } p_midi_host->dev_addr = dev_addr; - if (tuh_midi_mount_cb) - { + if (tuh_midi_mount_cb) { tuh_midi_mount_cb(dev_addr, p_midi_host->ep_in, p_midi_host->ep_out, p_midi_host->num_cables_rx, p_midi_host->num_cables_tx); } return true; @@ -478,7 +456,7 @@ bool midih_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *d bool tuh_midi_configured(uint8_t dev_addr) { - midih_interface_t *p_midi_host = get_midi_host(dev_addr); + midih_interface_t *p_midi_host = find_midi_by_daddr(dev_addr); TU_VERIFY(p_midi_host != NULL); return p_midi_host->configured; } @@ -486,7 +464,7 @@ bool tuh_midi_configured(uint8_t dev_addr) bool midih_set_config(uint8_t dev_addr, uint8_t itf_num) { (void) itf_num; - midih_interface_t *p_midi_host = get_midi_host(dev_addr); + midih_interface_t *p_midi_host = find_midi_by_daddr(dev_addr); TU_VERIFY(p_midi_host != NULL); p_midi_host->configured = true; @@ -498,43 +476,36 @@ bool midih_set_config(uint8_t dev_addr, uint8_t itf_num) //--------------------------------------------------------------------+ // Stream API //--------------------------------------------------------------------+ -static uint32_t write_flush(uint8_t dev_addr, midih_interface_t* midi) -{ +static uint32_t write_flush(uint8_t dev_addr, midih_interface_t* midi) { // No data to send - if ( !tu_fifo_count(&midi->tx_ff) ) return 0; + if ( !tu_fifo_count(&midi->tx_ff) ) { return 0; } // skip if previous transfer not complete TU_VERIFY( usbh_edpt_claim(dev_addr, midi->ep_out) ); uint16_t count = tu_fifo_read_n(&midi->tx_ff, midi->epout_buf, midi->ep_out_max); - if (count) - { - TU_ASSERT( usbh_edpt_xfer(dev_addr, midi->ep_out, midi->epout_buf, count), 0 ); + if (count) { + TU_ASSERT(usbh_edpt_xfer(dev_addr, midi->ep_out, midi->epout_buf, count), 0); return count; - }else - { + } else { // Release endpoint since we don't make any transfer usbh_edpt_release(dev_addr, midi->ep_out); return 0; } } -bool tuh_midi_read_poll( uint8_t dev_addr ) -{ - midih_interface_t *p_midi_host = get_midi_host(dev_addr); +bool tuh_midi_read_poll(uint8_t dev_addr) { + midih_interface_t *p_midi_host = find_midi_by_daddr(dev_addr); TU_VERIFY(p_midi_host != NULL); bool result = false; bool in_edpt_not_busy = !usbh_edpt_busy(dev_addr, p_midi_host->ep_in); - if (in_edpt_not_busy) - { + if (in_edpt_not_busy) { TU_LOG2("Requesting poll IN endpoint %d\r\n", p_midi_host->ep_in); TU_ASSERT(usbh_edpt_xfer(p_midi_host->dev_addr, p_midi_host->ep_in, p_midi_host->epin_buf, p_midi_host->ep_in_max), 0); result = true; - } - else - { + } else { // Maybe the IN endpoint is only busy because the RP2040 host hardware // is retrying a NAK'd IN transfer forever. Try aborting the NAK'd // transfer to allow other transfers to happen on the one shared @@ -546,7 +517,7 @@ bool tuh_midi_read_poll( uint8_t dev_addr ) uint32_t tuh_midi_stream_write (uint8_t dev_addr, uint8_t cable_num, uint8_t const* buffer, uint32_t bufsize) { - midih_interface_t *p_midi_host = get_midi_host(dev_addr); + midih_interface_t *p_midi_host = find_midi_by_daddr(dev_addr); TU_VERIFY(p_midi_host != NULL); TU_VERIFY(cable_num < p_midi_host->num_cables_tx); midi_stream_t *stream = &p_midi_host->stream_write; @@ -673,7 +644,7 @@ uint32_t tuh_midi_stream_write (uint8_t dev_addr, uint8_t cable_num, uint8_t con bool tuh_midi_packet_write (uint8_t dev_addr, uint8_t const packet[4]) { - midih_interface_t *p_midi_host = get_midi_host(dev_addr); + midih_interface_t *p_midi_host = find_midi_by_daddr(dev_addr); TU_VERIFY(p_midi_host != NULL); if (tu_fifo_remaining(&p_midi_host->tx_ff) < 4) @@ -688,7 +659,7 @@ bool tuh_midi_packet_write (uint8_t dev_addr, uint8_t const packet[4]) uint32_t tuh_midi_stream_flush( uint8_t dev_addr ) { - midih_interface_t *p_midi_host = get_midi_host(dev_addr); + midih_interface_t *p_midi_host = find_midi_by_daddr(dev_addr); TU_VERIFY(p_midi_host != NULL); uint32_t bytes_flushed = 0; @@ -703,7 +674,7 @@ uint32_t tuh_midi_stream_flush( uint8_t dev_addr ) //--------------------------------------------------------------------+ uint8_t tuh_midih_get_num_tx_cables (uint8_t dev_addr) { - midih_interface_t *p_midi_host = get_midi_host(dev_addr); + midih_interface_t *p_midi_host = find_midi_by_daddr(dev_addr); TU_VERIFY(p_midi_host != NULL); TU_VERIFY(p_midi_host->ep_out != 0); // returns 0 if fails return p_midi_host->num_cables_tx; @@ -711,7 +682,7 @@ uint8_t tuh_midih_get_num_tx_cables (uint8_t dev_addr) uint8_t tuh_midih_get_num_rx_cables (uint8_t dev_addr) { - midih_interface_t *p_midi_host = get_midi_host(dev_addr); + midih_interface_t *p_midi_host = find_midi_by_daddr(dev_addr); TU_VERIFY(p_midi_host != NULL); TU_VERIFY(p_midi_host->ep_in != 0); // returns 0 if fails return p_midi_host->num_cables_rx; @@ -719,7 +690,7 @@ uint8_t tuh_midih_get_num_rx_cables (uint8_t dev_addr) bool tuh_midi_packet_read (uint8_t dev_addr, uint8_t packet[4]) { - midih_interface_t *p_midi_host = get_midi_host(dev_addr); + midih_interface_t *p_midi_host = find_midi_by_daddr(dev_addr); TU_VERIFY(p_midi_host != NULL); TU_VERIFY(tu_fifo_count(&p_midi_host->rx_ff) >= 4); return tu_fifo_read_n(&p_midi_host->rx_ff, packet, 4) == 4; @@ -727,7 +698,7 @@ bool tuh_midi_packet_read (uint8_t dev_addr, uint8_t packet[4]) uint32_t tuh_midi_stream_read (uint8_t dev_addr, uint8_t *p_cable_num, uint8_t *p_buffer, uint16_t bufsize) { - midih_interface_t *p_midi_host = get_midi_host(dev_addr); + midih_interface_t *p_midi_host = find_midi_by_daddr(dev_addr); TU_VERIFY(p_midi_host != NULL); uint32_t bytes_buffered = 0; TU_ASSERT(p_cable_num); @@ -848,7 +819,7 @@ uint32_t tuh_midi_stream_read (uint8_t dev_addr, uint8_t *p_cable_num, uint8_t * uint8_t tuh_midi_get_num_rx_cables(uint8_t dev_addr) { - midih_interface_t *p_midi_host = get_midi_host(dev_addr); + midih_interface_t *p_midi_host = find_midi_by_daddr(dev_addr); TU_VERIFY(p_midi_host != NULL); uint8_t num_cables = 0; if (p_midi_host) @@ -860,7 +831,7 @@ uint8_t tuh_midi_get_num_rx_cables(uint8_t dev_addr) uint8_t tuh_midi_get_num_tx_cables(uint8_t dev_addr) { - midih_interface_t *p_midi_host = get_midi_host(dev_addr); + midih_interface_t *p_midi_host = find_midi_by_daddr(dev_addr); TU_VERIFY(p_midi_host != NULL); uint8_t num_cables = 0; if (p_midi_host) @@ -897,7 +868,7 @@ static uint8_t find_string_index(midih_interface_t *ptr, uint8_t jack_id) uint8_t tuh_midi_get_rx_cable_istrings(uint8_t dev_addr, uint8_t* istrings, uint8_t max_istrings) { uint8_t nstrings = 0; - midih_interface_t *p_midi_host = get_midi_host(dev_addr); + midih_interface_t *p_midi_host = find_midi_by_daddr(dev_addr); TU_VERIFY(p_midi_host != NULL); nstrings = p_midi_host->num_cables_rx; if (nstrings > max_istrings) @@ -916,7 +887,7 @@ uint8_t tuh_midi_get_rx_cable_istrings(uint8_t dev_addr, uint8_t* istrings, uint uint8_t tuh_midi_get_tx_cable_istrings(uint8_t dev_addr, uint8_t* istrings, uint8_t max_istrings) { uint8_t nstrings = 0; - midih_interface_t *p_midi_host = get_midi_host(dev_addr); + midih_interface_t *p_midi_host = find_midi_by_daddr(dev_addr); TU_VERIFY(p_midi_host != NULL); nstrings = p_midi_host->num_cables_tx; if (nstrings > max_istrings) @@ -935,7 +906,7 @@ uint8_t tuh_midi_get_tx_cable_istrings(uint8_t dev_addr, uint8_t* istrings, uint uint8_t tuh_midi_get_all_istrings(uint8_t dev_addr, const uint8_t** istrings) { - midih_interface_t *p_midi_host = get_midi_host(dev_addr); + midih_interface_t *p_midi_host = find_midi_by_daddr(dev_addr); TU_VERIFY(p_midi_host != NULL); uint8_t nstrings = p_midi_host->num_string_indices; if (nstrings) diff --git a/src/class/midi/midi_host.h b/src/class/midi/midi_host.h index edf57bfcb..bf2378168 100644 --- a/src/class/midi/midi_host.h +++ b/src/class/midi/midi_host.h @@ -37,16 +37,25 @@ //--------------------------------------------------------------------+ // Class Driver Configuration //--------------------------------------------------------------------+ +#ifndef CFG_TUH_MAX_CABLES +#define CFG_TUH_MAX_CABLES 16 +#endif + +#ifndef CFG_TUH_MIDI_RX_BUFSIZE +#define CFG_TUH_MIDI_RX_BUFSIZE 64 +#endif -// TODO Highspeed bulk transfer can be up to 512 bytes -#ifndef CFG_TUH_HID_EPIN_BUFSIZE -#define CFG_TUH_HID_EPIN_BUFSIZE 64 +#ifndef CFG_TUH_MIDI_TX_BUFSIZE +#define CFG_TUH_MIDI_TX_BUFSIZE 64 #endif -#ifndef CFG_TUH_HID_EPOUT_BUFSIZE -#define CFG_TUH_HID_EPOUT_BUFSIZE 64 +#ifndef CFG_TUH_MIDI_EP_BUFSIZE +#define CFG_TUH_MIDI_EP_BUFSIZE 64 #endif +#ifndef CFG_MIDI_HOST_DEVSTRINGS +#define CFG_MIDI_HOST_DEVSTRINGS 0 +#endif //--------------------------------------------------------------------+ // Application API (Single Interface) diff --git a/src/host/usbh.c b/src/host/usbh.c index e38ee3187..f874121a3 100644 --- a/src/host/usbh.c +++ b/src/host/usbh.c @@ -1488,9 +1488,7 @@ static void process_enumeration(tuh_xfer_t* xfer) { dev->i_product = desc_device->iProduct; dev->i_serial = desc_device->iSerialNumber; - if (tuh_desc_device_cb) { - tuh_desc_device_cb(daddr, (tusb_desc_device_t const*) _usbh_epbuf.ctrl); - } + // tuh_descriptor_device_cb(daddr, (tusb_desc_device_t const*) _usbh_epbuf.ctrl); // Get 9-byte for total length uint8_t const config_idx = CONFIG_NUM - 1; @@ -1519,9 +1517,7 @@ static void process_enumeration(tuh_xfer_t* xfer) { } case ENUM_SET_CONFIG: - if (tuh_desc_config_cb) { - tuh_desc_config_cb(daddr, (const tusb_desc_configuration_t*) _usbh_epbuf.ctrl); - } + // tuh_desc_configuration_cb(daddr, CONFIG_NUM-1, (const tusb_desc_configuration_t*) _usbh_epbuf.ctrl); TU_ASSERT(tuh_configuration_set(daddr, CONFIG_NUM, process_enumeration, ENUM_CONFIG_DRIVER),); break; diff --git a/src/host/usbh.h b/src/host/usbh.h index 500b044f8..3bcdd3657 100644 --- a/src/host/usbh.h +++ b/src/host/usbh.h @@ -96,11 +96,11 @@ typedef union { // APPLICATION CALLBACK //--------------------------------------------------------------------+ -// Give the application an opportunity to grab the device descriptor -TU_ATTR_WEAK void tuh_desc_device_cb(uint8_t daddr, const tusb_desc_device_t *desc_device); +// Invoked when enumeration get device descriptor +// TU_ATTR_WEAK void tuh_descriptor_device_cb(uint8_t daddr, const tusb_desc_device_t *desc_device); -// Give the application an opportunity to grab the configuration descriptor -TU_ATTR_WEAK void tuh_desc_config_cb(uint8_t daddr, const tusb_desc_configuration_t *desc_config); +// Invoked when enumeration get configuration descriptor +// TU_ATTR_WEAK void tuh_desc_configuration_cb(uint8_t daddr, uint8_t cfg_index, const tusb_desc_configuration_t *desc_config); // Invoked when a device is mounted (configured) TU_ATTR_WEAK void tuh_mount_cb (uint8_t daddr); -- cgit v1.3.1 From bad6cbe48930c0c5250b8a717a46cc1f6d83de56 Mon Sep 17 00:00:00 2001 From: hathach Date: Thu, 13 Feb 2025 15:52:30 +0700 Subject: update midi host to use endpoint stream API --- src/class/cdc/cdc_host.c | 4 +- src/class/midi/midi_host.c | 445 +++++++++++++++------------------------------ src/class/midi/midi_host.h | 25 +-- src/common/tusb_private.h | 10 +- src/host/usbh.c | 3 +- src/host/usbh.h | 3 + 6 files changed, 174 insertions(+), 316 deletions(-) (limited to 'src/class') diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index e817ebc7e..4058857c5 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -691,10 +691,10 @@ bool cdch_xfer_cb(uint8_t daddr, uint8_t ep_addr, xfer_result_t event, uint32_t } } else if ( ep_addr == p_cdc->stream.rx.ep_addr ) { #if CFG_TUH_CDC_FTDI - if (p_cdc->serial_drid == SERIAL_DRIVER_FTDI) { + if (p_cdc->serial_drid == SERIAL_DRIVER_FTDI && xferred_bytes > 2) { // FTDI reserve 2 bytes for status // 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); + tu_edpt_stream_read_xfer_complete_with_buf(&p_cdc->stream.rx, p_cdc->stream.rx.ep_buf+2, xferred_bytes-2); }else #endif { diff --git a/src/class/midi/midi_host.c b/src/class/midi/midi_host.c index 21fe09143..eb3f0b070 100644 --- a/src/class/midi/midi_host.c +++ b/src/class/midi/midi_host.c @@ -45,15 +45,12 @@ typedef struct uint8_t total; }midi_stream_t; -typedef struct -{ +typedef struct { uint8_t dev_addr; uint8_t itf_num; uint8_t ep_in; // IN endpoint address uint8_t ep_out; // OUT endpoint address - uint16_t ep_in_max; // min( CFG_TUH_MIDI_RX_BUFSIZE, wMaxPacketSize of the IN endpoint) - uint16_t ep_out_max; // min( CFG_TUH_MIDI_TX_BUFSIZE, wMaxPacketSize of the OUT endpoint) uint8_t num_cables_rx; // IN endpoint CS descriptor bNumEmbMIDIJack value uint8_t num_cables_tx; // OUT endpoint CS descriptor bNumEmbMIDIJack value @@ -65,22 +62,14 @@ typedef struct midi_stream_t stream_read; /*------------- From this point, data is not cleared by bus reset -------------*/ - // Endpoint FIFOs - tu_fifo_t rx_ff; - tu_fifo_t tx_ff; - - - uint8_t rx_ff_buf[CFG_TUH_MIDI_RX_BUFSIZE]; - uint8_t tx_ff_buf[CFG_TUH_MIDI_TX_BUFSIZE]; - - #if CFG_FIFO_MUTEX - osal_mutex_def_t rx_ff_mutex; - osal_mutex_def_t tx_ff_mutex; - #endif + // Endpoint stream + struct { + tu_edpt_stream_t tx; + tu_edpt_stream_t rx; - // Endpoint Transfer buffer - CFG_TUSB_MEM_ALIGN uint8_t epout_buf[CFG_TUH_MIDI_EP_BUFSIZE]; - CFG_TUSB_MEM_ALIGN uint8_t epin_buf[CFG_TUH_MIDI_EP_BUFSIZE]; + uint8_t rx_ff_buf[CFG_TUH_MIDI_RX_BUFSIZE]; + uint8_t tx_ff_buf[CFG_TUH_MIDI_TX_BUFSIZE]; + } ep_stream; bool configured; @@ -109,15 +98,17 @@ typedef struct #endif }midih_interface_t; -static midih_interface_t _midi_host[CFG_TUH_MIDI]; +typedef struct { + TUH_EPBUF_DEF(tx, TUH_EPSIZE_BULK_MPS); + TUH_EPBUF_DEF(rx, TUH_EPSIZE_BULK_MPS); +} midih_epbuf_t; -//------------- Internal prototypes -------------// -static uint32_t write_flush(uint8_t dev_addr, midih_interface_t* midi); +static midih_interface_t _midi_host[CFG_TUH_MIDI]; +CFG_TUH_MEM_SECTION static midih_epbuf_t _midi_epbuf[CFG_TUH_MIDI]; //--------------------------------------------------------------------+ // Helper //--------------------------------------------------------------------+ - TU_ATTR_ALWAYS_INLINE static inline midih_interface_t* find_midi_by_daddr(uint8_t dev_addr) { for (uint8_t i = 0; i < CFG_TUH_MIDI; i++) { if (_midi_host[i].dev_addr == dev_addr) { @@ -131,85 +122,27 @@ TU_ATTR_ALWAYS_INLINE static inline midih_interface_t* find_new_midi(void) { return find_midi_by_daddr(0); } - //--------------------------------------------------------------------+ // USBH API //--------------------------------------------------------------------+ bool midih_init(void) { tu_memclr(&_midi_host, sizeof(_midi_host)); - // config fifos for (int inst = 0; inst < CFG_TUH_MIDI; inst++) { midih_interface_t *p_midi_host = &_midi_host[inst]; - tu_fifo_config(&p_midi_host->rx_ff, p_midi_host->rx_ff_buf, CFG_TUH_MIDI_RX_BUFSIZE, 1, false);// true, true - tu_fifo_config(&p_midi_host->tx_ff, p_midi_host->tx_ff_buf, CFG_TUH_MIDI_TX_BUFSIZE, 1, false);// OBVS. - - #if CFG_FIFO_MUTEX - tu_fifo_config_mutex(&p_midi_host->rx_ff, NULL, osal_mutex_create(&p_midi_host->rx_ff_mutex)); - tu_fifo_config_mutex(&p_midi_host->tx_ff, osal_mutex_create(&p_midi_host->tx_ff_mutex), NULL); - #endif + tu_edpt_stream_init(&p_midi_host->ep_stream.rx, true, false, false, + p_midi_host->ep_stream.rx_ff_buf, CFG_TUH_MIDI_RX_BUFSIZE, _midi_epbuf->rx, TUH_EPSIZE_BULK_MPS); + tu_edpt_stream_init(&p_midi_host->ep_stream.tx, true, true, false, + p_midi_host->ep_stream.tx_ff_buf, CFG_TUH_MIDI_TX_BUFSIZE, _midi_epbuf->tx, TUH_EPSIZE_BULK_MPS); } return true; } -bool midih_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) -{ - (void)result; - midih_interface_t *p_midi_host = find_midi_by_daddr(dev_addr); - TU_VERIFY(p_midi_host != NULL); - if ( ep_addr == p_midi_host->ep_in) - { - if (0 == xferred_bytes) - { - return true; // No data to handle - } - - // receive new data if available - uint32_t packets_queued = 0; - if (xferred_bytes) - { - // put in the RX FIFO only non-zero MIDI IN 4-byte packets - uint8_t* buf = p_midi_host->epin_buf; - uint32_t npackets = xferred_bytes / 4; - uint32_t packet_num; - for (packet_num = 0; packet_num < npackets; packet_num++) - { - // some devices send back all zero packets even if there is no data ready - uint32_t packet = (uint32_t)((*buf)<<24) | ((uint32_t)(*(buf+1))<<16) | ((uint32_t)(*(buf+2))<<8) | ((uint32_t)(*(buf+3))); - if (packet != 0) - { - tu_fifo_write_n(&p_midi_host->rx_ff, buf, 4); - ++packets_queued; - TU_LOG3("MIDI RX=%08x\r\n", packet); - } - buf += 4; - } - } - // invoke receive callback if available - if (tuh_midi_rx_cb) - { - tuh_midi_rx_cb(dev_addr, packets_queued); - } - } - else if ( ep_addr == p_midi_host->ep_out ) - { - if (0 == write_flush(dev_addr, p_midi_host)) - { - // If there is no data left, a ZLP should be sent if - // xferred_bytes is multiple of EP size and not zero - if ( !tu_fifo_count(&p_midi_host->tx_ff) && xferred_bytes && (0 == (xferred_bytes % p_midi_host->ep_out_max)) ) - { - if ( usbh_edpt_claim(dev_addr, p_midi_host->ep_out) ) - { - TU_ASSERT(usbh_edpt_xfer(dev_addr, p_midi_host->ep_out, XFER_RESULT_SUCCESS, 0)); - } - } - } - if (tuh_midi_tx_cb) - { - tuh_midi_tx_cb(dev_addr); - } +bool midih_deinit(void) { + for (size_t i = 0; i < CFG_TUH_MIDI; i++) { + midih_interface_t* p_midi = &_midi_host[i]; + tu_edpt_stream_deinit(&p_midi->ep_stream.rx); + tu_edpt_stream_deinit(&p_midi->ep_stream.tx); } - return true; } @@ -221,26 +154,67 @@ void midih_close(uint8_t dev_addr) { if (tuh_midi_umount_cb) { tuh_midi_umount_cb(dev_addr, 0); } - tu_fifo_clear(&p_midi_host->rx_ff); - tu_fifo_clear(&p_midi_host->tx_ff); p_midi_host->ep_in = 0; - p_midi_host->ep_in_max = 0; p_midi_host->ep_out = 0; - p_midi_host->ep_out_max = 0; p_midi_host->itf_num = 0; p_midi_host->num_cables_rx = 0; p_midi_host->num_cables_tx = 0; - p_midi_host->dev_addr = 255; // invalid + p_midi_host->dev_addr = 0; p_midi_host->configured = false; tu_memclr(&p_midi_host->stream_read, sizeof(p_midi_host->stream_read)); tu_memclr(&p_midi_host->stream_write, sizeof(p_midi_host->stream_write)); + + tu_edpt_stream_close(&p_midi_host->ep_stream.rx); + tu_edpt_stream_close(&p_midi_host->ep_stream.tx); +} + +bool midih_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) { + (void) result; + midih_interface_t *p_midi_host = find_midi_by_daddr(dev_addr); + TU_VERIFY(p_midi_host != NULL); + if (ep_addr == p_midi_host->ep_stream.rx.ep_addr) { + // receive new data if available + if (xferred_bytes) { + // put in the RX FIFO only non-zero MIDI IN 4-byte packets + uint32_t packets_queued = 0; + uint8_t *buf = _midi_epbuf->rx; + const uint32_t npackets = xferred_bytes / 4; + for (uint32_t p = 0; p < npackets; p++) { + // some devices send back all zero packets even if there is no data ready + const uint32_t packet = tu_unaligned_read32(buf); + if (packet != 0) { + tu_edpt_stream_read_xfer_complete_with_buf(&p_midi_host->ep_stream.rx, buf, 4); + ++packets_queued; + TU_LOG3("MIDI RX=%08x\r\n", packet); + } + buf += 4; + } + + if (tuh_midi_rx_cb) { + tuh_midi_rx_cb(dev_addr, packets_queued); // invoke receive callback + } + } + + // prepare for next transfer if needed + tu_edpt_stream_read_xfer(dev_addr, &p_midi_host->ep_stream.rx); + } else if (ep_addr == p_midi_host->ep_stream.tx.ep_addr) { + if (tuh_midi_tx_cb) { + tuh_midi_tx_cb(dev_addr); + } + if (0 == tu_edpt_stream_write_xfer(dev_addr, &p_midi_host->ep_stream.tx)) { + // If there is no data left, a ZLP should be sent if + // xferred_bytes is multiple of EP size and not zero + tu_edpt_stream_write_zlp_if_needed(dev_addr, &p_midi_host->ep_stream.tx, xferred_bytes); + } + } + + return true; } //--------------------------------------------------------------------+ // Enumeration //--------------------------------------------------------------------+ -bool midih_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *desc_itf, uint16_t max_len) -{ +bool midih_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *desc_itf, uint16_t max_len) { (void) rhport; midih_interface_t *p_midi_host = find_new_midi(); @@ -402,20 +376,12 @@ bool midih_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *d TU_VERIFY(p_midi_host->ep_out == 0); TU_VERIFY(p_midi_host->num_cables_tx == 0); p_midi_host->ep_out = p_ep->bEndpointAddress; - p_midi_host->ep_out_max = p_ep->wMaxPacketSize; - if (p_midi_host->ep_out_max > CFG_TUH_MIDI_TX_BUFSIZE) { - p_midi_host->ep_out_max = CFG_TUH_MIDI_TX_BUFSIZE; - } prev_ep_addr = p_midi_host->ep_out; out_desc = p_ep; } else { TU_VERIFY(p_midi_host->ep_in == 0); TU_VERIFY(p_midi_host->num_cables_rx == 0); p_midi_host->ep_in = p_ep->bEndpointAddress; - p_midi_host->ep_in_max = p_ep->wMaxPacketSize; - if (p_midi_host->ep_in_max > CFG_TUH_MIDI_RX_BUFSIZE) { - p_midi_host->ep_in_max = CFG_TUH_MIDI_RX_BUFSIZE; - } prev_ep_addr = p_midi_host->ep_in; in_desc = p_ep; } @@ -439,36 +405,34 @@ bool midih_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *d } if (in_desc) { TU_ASSERT(tuh_edpt_open(dev_addr, in_desc)); - // Some devices always return exactly the request length so transfers won't complete - // unless you assume every transfer is the last one. - // TODO usbh_edpt_force_last_buffer(dev_addr, p_midi_host->ep_in, true); + tu_edpt_stream_open(&p_midi_host->ep_stream.rx, in_desc); } if (out_desc) { TU_ASSERT(tuh_edpt_open(dev_addr, out_desc)); + tu_edpt_stream_open(&p_midi_host->ep_stream.tx, out_desc); } p_midi_host->dev_addr = dev_addr; - if (tuh_midi_mount_cb) { - tuh_midi_mount_cb(dev_addr, p_midi_host->ep_in, p_midi_host->ep_out, p_midi_host->num_cables_rx, p_midi_host->num_cables_tx); - } return true; } -bool tuh_midi_configured(uint8_t dev_addr) -{ +bool tuh_midi_configured(uint8_t dev_addr) { midih_interface_t *p_midi_host = find_midi_by_daddr(dev_addr); TU_VERIFY(p_midi_host != NULL); return p_midi_host->configured; } -bool midih_set_config(uint8_t dev_addr, uint8_t itf_num) -{ +bool midih_set_config(uint8_t dev_addr, uint8_t itf_num) { (void) itf_num; midih_interface_t *p_midi_host = find_midi_by_daddr(dev_addr); TU_VERIFY(p_midi_host != NULL); p_midi_host->configured = true; - // TODO I don't think there are any special config things to do for MIDI + if (tuh_midi_mount_cb) { + tuh_midi_mount_cb(dev_addr, p_midi_host->ep_in, p_midi_host->ep_out, p_midi_host->num_cables_rx, p_midi_host->num_cables_tx); + } + + // No special config things to do for MIDI usbh_driver_set_config_complete(dev_addr, p_midi_host->itf_num); return true; } @@ -476,71 +440,32 @@ bool midih_set_config(uint8_t dev_addr, uint8_t itf_num) //--------------------------------------------------------------------+ // Stream API //--------------------------------------------------------------------+ -static uint32_t write_flush(uint8_t dev_addr, midih_interface_t* midi) { - // No data to send - if ( !tu_fifo_count(&midi->tx_ff) ) { return 0; } - - // skip if previous transfer not complete - TU_VERIFY( usbh_edpt_claim(dev_addr, midi->ep_out) ); - - uint16_t count = tu_fifo_read_n(&midi->tx_ff, midi->epout_buf, midi->ep_out_max); - - if (count) { - TU_ASSERT(usbh_edpt_xfer(dev_addr, midi->ep_out, midi->epout_buf, count), 0); - return count; - } else { - // Release endpoint since we don't make any transfer - usbh_edpt_release(dev_addr, midi->ep_out); - return 0; - } -} - bool tuh_midi_read_poll(uint8_t dev_addr) { midih_interface_t *p_midi_host = find_midi_by_daddr(dev_addr); TU_VERIFY(p_midi_host != NULL); - bool result = false; - - bool in_edpt_not_busy = !usbh_edpt_busy(dev_addr, p_midi_host->ep_in); - if (in_edpt_not_busy) { - TU_LOG2("Requesting poll IN endpoint %d\r\n", p_midi_host->ep_in); - TU_ASSERT(usbh_edpt_xfer(p_midi_host->dev_addr, p_midi_host->ep_in, p_midi_host->epin_buf, p_midi_host->ep_in_max), 0); - result = true; - } else { - // Maybe the IN endpoint is only busy because the RP2040 host hardware - // is retrying a NAK'd IN transfer forever. Try aborting the NAK'd - // transfer to allow other transfers to happen on the one shared - // epx endpoint. - // TODO for RP2040 USB shared endpoint: usbh_edpt_clear_in_on_nak(p_midi_host->dev_addr, p_midi_host->ep_in); - } - return result; + return tu_edpt_stream_read_xfer(dev_addr, &p_midi_host->ep_stream.rx) > 0; } -uint32_t tuh_midi_stream_write (uint8_t dev_addr, uint8_t cable_num, uint8_t const* buffer, uint32_t bufsize) -{ +uint32_t tuh_midi_stream_write(uint8_t dev_addr, uint8_t cable_num, uint8_t const *buffer, uint32_t bufsize) { midih_interface_t *p_midi_host = find_midi_by_daddr(dev_addr); TU_VERIFY(p_midi_host != NULL); TU_VERIFY(cable_num < p_midi_host->num_cables_tx); midi_stream_t *stream = &p_midi_host->stream_write; uint32_t i = 0; - while ( (i < bufsize) && (tu_fifo_remaining(&p_midi_host->tx_ff) >= 4) ) - { + while ((i < bufsize) && (tu_edpt_stream_write_available(dev_addr, &p_midi_host->ep_stream.tx) >= 4)) { uint8_t const data = buffer[i]; i++; - if (data >= MIDI_STATUS_SYSREAL_TIMING_CLOCK) - { + if (data >= MIDI_STATUS_SYSREAL_TIMING_CLOCK) { // real-time messages need to be sent right away midi_stream_t streamrt; streamrt.buffer[0] = MIDI_CIN_SYSEX_END_1BYTE; streamrt.buffer[1] = data; streamrt.index = 2; streamrt.total = 2; - uint16_t const count = tu_fifo_write_n(&p_midi_host->tx_ff, streamrt.buffer, 4); - // FIFO overflown, since we already check fifo remaining. It is probably race condition - TU_ASSERT(count == 4, i); - } - else if ( stream->index == 0 ) - { + uint32_t const count = tu_edpt_stream_write(dev_addr, &p_midi_host->ep_stream.tx, streamrt.buffer, 4); + TU_ASSERT(count == 4, i); // Check FIFO overflown, since we already check fifo remaining. It is probably race condition + } else if (stream->index == 0) { //------------- New event packet -------------// uint8_t const msg = data >> 4; @@ -549,56 +474,37 @@ uint32_t tuh_midi_stream_write (uint8_t dev_addr, uint8_t cable_num, uint8_t con stream->buffer[1] = data; // Check to see if we're still in a SysEx transmit. - if ( stream->buffer[0] == MIDI_CIN_SYSEX_START ) - { - if ( data == MIDI_STATUS_SYSEX_END ) - { + if (stream->buffer[0] == MIDI_CIN_SYSEX_START) { + if (data == MIDI_STATUS_SYSEX_END) { stream->buffer[0] = MIDI_CIN_SYSEX_END_1BYTE; stream->total = 2; - } - else - { + } else { stream->total = 4; } - } - else if ( (msg >= 0x8 && msg <= 0xB) || msg == 0xE ) - { + } else if ((msg >= 0x8 && msg <= 0xB) || msg == 0xE) { // Channel Voice Messages stream->buffer[0] = (uint8_t) ((cable_num << 4) | msg); stream->total = 4; - } - else if ( msg == 0xC || msg == 0xD) - { + } else if (msg == 0xC || msg == 0xD) { // Channel Voice Messages, two-byte variants (Program Change and Channel Pressure) stream->buffer[0] = (uint8_t) ((cable_num << 4) | msg); stream->total = 3; - } - else if ( msg == 0xf ) - { + } else if (msg == 0xf) { // System message - if ( data == MIDI_STATUS_SYSEX_START ) - { + if (data == MIDI_STATUS_SYSEX_START) { stream->buffer[0] = MIDI_CIN_SYSEX_START; stream->total = 4; - } - else if ( data == MIDI_STATUS_SYSCOM_TIME_CODE_QUARTER_FRAME || data == MIDI_STATUS_SYSCOM_SONG_SELECT ) - { + } else if (data == MIDI_STATUS_SYSCOM_TIME_CODE_QUARTER_FRAME || data == MIDI_STATUS_SYSCOM_SONG_SELECT) { stream->buffer[0] = MIDI_CIN_SYSCOM_2BYTE; stream->total = 3; - } - else if ( data == MIDI_STATUS_SYSCOM_SONG_POSITION_POINTER ) - { + } else if (data == MIDI_STATUS_SYSCOM_SONG_POSITION_POINTER) { stream->buffer[0] = MIDI_CIN_SYSCOM_3BYTE; stream->total = 4; - } - else - { + } else { stream->buffer[0] = MIDI_CIN_SYSEX_END_1BYTE; stream->total = 2; } - } - else - { + } else { // Pack individual bytes if we don't support packing them into words. stream->buffer[0] = (uint8_t) (cable_num << 4 | 0xf); stream->buffer[2] = 0; @@ -606,30 +512,25 @@ uint32_t tuh_midi_stream_write (uint8_t dev_addr, uint8_t cable_num, uint8_t con stream->index = 2; stream->total = 2; } - } - else - { + } else { //------------- On-going (buffering) packet -------------// - TU_ASSERT(stream->index < 4, i); stream->buffer[stream->index] = data; stream->index++; // See if this byte ends a SysEx. - if ( stream->buffer[0] == MIDI_CIN_SYSEX_START && data == MIDI_STATUS_SYSEX_END ) - { + if (stream->buffer[0] == MIDI_CIN_SYSEX_START && data == MIDI_STATUS_SYSEX_END) { stream->buffer[0] = MIDI_CIN_SYSEX_START + (stream->index - 1); stream->total = stream->index; } } // Send out packet - if ( stream->index >= 2 && stream->index == stream->total ) - { + if (stream->index >= 2 && stream->index == stream->total) { // zeroes unused bytes - for(uint8_t idx = stream->total; idx < 4; idx++) stream->buffer[idx] = 0; + for (uint8_t idx = stream->total; idx < 4; idx++) { stream->buffer[idx] = 0; } TU_LOG3_MEM(stream->buffer, 4, 2); - uint16_t const count = tu_fifo_write_n(&p_midi_host->tx_ff, stream->buffer, 4); + uint32_t const count = tu_edpt_stream_write(dev_addr, &p_midi_host->ep_stream.tx, stream->buffer, 4); // complete current event packet, reset stream stream->index = 0; @@ -642,32 +543,16 @@ uint32_t tuh_midi_stream_write (uint8_t dev_addr, uint8_t cable_num, uint8_t con return i; } -bool tuh_midi_packet_write (uint8_t dev_addr, uint8_t const packet[4]) -{ +bool tuh_midi_packet_write (uint8_t dev_addr, uint8_t const packet[4]) { midih_interface_t *p_midi_host = find_midi_by_daddr(dev_addr); TU_VERIFY(p_midi_host != NULL); - - if (tu_fifo_remaining(&p_midi_host->tx_ff) < 4) - { - return false; - } - - tu_fifo_write_n(&p_midi_host->tx_ff, packet, 4); - - return true; + return 4 == tu_edpt_stream_write(dev_addr, &p_midi_host->ep_stream.tx, packet, 4); } -uint32_t tuh_midi_stream_flush( uint8_t dev_addr ) -{ - midih_interface_t *p_midi_host = find_midi_by_daddr(dev_addr); - TU_VERIFY(p_midi_host != NULL); - - uint32_t bytes_flushed = 0; - if (!usbh_edpt_busy(p_midi_host->dev_addr, p_midi_host->ep_out)) - { - bytes_flushed = write_flush(dev_addr, p_midi_host); - } - return bytes_flushed; +uint32_t tuh_midi_stream_flush(uint8_t dev_addr) { + midih_interface_t *p_midi = find_midi_by_daddr(dev_addr); + TU_VERIFY(p_midi != NULL); + return tu_edpt_stream_write_xfer(p_midi->dev_addr, &p_midi->ep_stream.tx); } //--------------------------------------------------------------------+ // Helper @@ -692,12 +577,11 @@ bool tuh_midi_packet_read (uint8_t dev_addr, uint8_t packet[4]) { midih_interface_t *p_midi_host = find_midi_by_daddr(dev_addr); TU_VERIFY(p_midi_host != NULL); - TU_VERIFY(tu_fifo_count(&p_midi_host->rx_ff) >= 4); - return tu_fifo_read_n(&p_midi_host->rx_ff, packet, 4) == 4; + TU_VERIFY(tu_edpt_stream_read_available(&p_midi_host->ep_stream.rx) >= 4); + return 4 == tu_edpt_stream_read(dev_addr, &p_midi_host->ep_stream.rx, packet, 4); } -uint32_t tuh_midi_stream_read (uint8_t dev_addr, uint8_t *p_cable_num, uint8_t *p_buffer, uint16_t bufsize) -{ +uint32_t tuh_midi_stream_read(uint8_t dev_addr, uint8_t *p_cable_num, uint8_t *p_buffer, uint16_t bufsize) { midih_interface_t *p_midi_host = find_midi_by_daddr(dev_addr); TU_VERIFY(p_midi_host != NULL); uint32_t bytes_buffered = 0; @@ -705,54 +589,40 @@ uint32_t tuh_midi_stream_read (uint8_t dev_addr, uint8_t *p_cable_num, uint8_t * TU_ASSERT(p_buffer); TU_ASSERT(bufsize); uint8_t one_byte; - if (!tu_fifo_peek(&p_midi_host->rx_ff, &one_byte)) - { + if (!tu_edpt_stream_peek(&p_midi_host->ep_stream.rx, &one_byte)) { return 0; } *p_cable_num = (one_byte >> 4) & 0xf; - uint32_t nread = tu_fifo_read_n(&p_midi_host->rx_ff, p_midi_host->stream_read.buffer, 4); + uint32_t nread = tu_edpt_stream_read(dev_addr, &p_midi_host->ep_stream.rx, p_midi_host->stream_read.buffer, 4); static uint16_t cable_sysex_in_progress; // bit i is set if received MIDI_STATUS_SYSEX_START but not MIDI_STATUS_SYSEX_END - while (nread == 4 && bytes_buffered < bufsize) - { - *p_cable_num=(p_midi_host->stream_read.buffer[0] >> 4) & 0x0f; + while (nread == 4 && bytes_buffered < bufsize) { + *p_cable_num = (p_midi_host->stream_read.buffer[0] >> 4) & 0x0f; uint8_t bytes_to_add_to_stream = 0; - if (*p_cable_num < p_midi_host->num_cables_rx) - { + if (*p_cable_num < p_midi_host->num_cables_rx) { // ignore the CIN field; too many devices out there encode this wrong uint8_t status = p_midi_host->stream_read.buffer[1]; uint16_t cable_mask = (uint16_t) (1 << *p_cable_num); - if (status <= MIDI_MAX_DATA_VAL || status == MIDI_STATUS_SYSEX_START) - { - if (status == MIDI_STATUS_SYSEX_START) - { + if (status <= MIDI_MAX_DATA_VAL || status == MIDI_STATUS_SYSEX_START) { + if (status == MIDI_STATUS_SYSEX_START) { cable_sysex_in_progress |= cable_mask; } // only add the packet if a sysex message is in progress - if (cable_sysex_in_progress & cable_mask) - { + if (cable_sysex_in_progress & cable_mask) { ++bytes_to_add_to_stream; - uint8_t idx; - for (idx = 2; idx < 4; idx++) - { - if (p_midi_host->stream_read.buffer[idx] <= MIDI_MAX_DATA_VAL) - { + for (uint8_t idx = 2; idx < 4; idx++) { + if (p_midi_host->stream_read.buffer[idx] <= MIDI_MAX_DATA_VAL) { ++bytes_to_add_to_stream; - } - else if (p_midi_host->stream_read.buffer[idx] == MIDI_STATUS_SYSEX_END) - { + } else if (p_midi_host->stream_read.buffer[idx] == MIDI_STATUS_SYSEX_END) { ++bytes_to_add_to_stream; cable_sysex_in_progress &= (uint16_t) ~cable_mask; - idx = 4; // force the loop to exit; I hate break statements in loops + idx = 4;// force the loop to exit; I hate break statements in loops } } } - } - else if (status < MIDI_STATUS_SYSEX_START) - { + } else if (status < MIDI_STATUS_SYSEX_START) { // then it is a channel message either three bytes or two uint8_t fake_cin = (status & 0xf0) >> 4; - switch (fake_cin) - { + switch (fake_cin) { case MIDI_CIN_NOTE_OFF: case MIDI_CIN_NOTE_ON: case MIDI_CIN_POLY_KEYPRESS: @@ -765,14 +635,11 @@ uint32_t tuh_midi_stream_read (uint8_t dev_addr, uint8_t *p_cable_num, uint8_t * bytes_to_add_to_stream = 2; break; default: - break; // Should not get this + break;// Should not get this } - cable_sysex_in_progress &= (uint16_t)~cable_mask; - } - else if (status < MIDI_STATUS_SYSREAL_TIMING_CLOCK) - { - switch (status) - { + cable_sysex_in_progress &= (uint16_t) ~cable_mask; + } else if (status < MIDI_STATUS_SYSREAL_TIMING_CLOCK) { + switch (status) { case MIDI_STATUS_SYSCOM_TIME_CODE_QUARTER_FRAME: case MIDI_STATUS_SYSCOM_SONG_SELECT: bytes_to_add_to_stream = 2; @@ -786,30 +653,24 @@ uint32_t tuh_midi_stream_read (uint8_t dev_addr, uint8_t *p_cable_num, uint8_t * break; default: break; - cable_sysex_in_progress &= (uint16_t)~cable_mask; + cable_sysex_in_progress &= (uint16_t) ~cable_mask; } - } - else - { + } else { // Real-time message: can be inserted into a sysex message, // so do don't clear cable_sysex_in_progress bit bytes_to_add_to_stream = 1; } } - uint8_t idx; - for (idx = 1; idx <= bytes_to_add_to_stream; idx++) - { + for (uint8_t idx = 1; idx <= bytes_to_add_to_stream; idx++) { *p_buffer++ = p_midi_host->stream_read.buffer[idx]; } bytes_buffered += bytes_to_add_to_stream; nread = 0; - if (tu_fifo_peek(&p_midi_host->rx_ff, &one_byte)) - { + if (tu_edpt_stream_peek(&p_midi_host->ep_stream.rx, &one_byte)) { uint8_t new_cable = (one_byte >> 4) & 0xf; - if (new_cable == *p_cable_num) - { + if (new_cable == *p_cable_num) { // still on the same cable. Continue reading the stream - nread = tu_fifo_read_n(&p_midi_host->rx_ff, p_midi_host->stream_read.buffer, 4); + nread = tu_edpt_stream_read(dev_addr, &p_midi_host->ep_stream.rx, p_midi_host->stream_read.buffer, 4); } } } @@ -865,19 +726,14 @@ static uint8_t find_string_index(midih_interface_t *ptr, uint8_t jack_id) #endif #if CFG_MIDI_HOST_DEVSTRINGS -uint8_t tuh_midi_get_rx_cable_istrings(uint8_t dev_addr, uint8_t* istrings, uint8_t max_istrings) -{ - uint8_t nstrings = 0; +uint8_t tuh_midi_get_rx_cable_istrings(uint8_t dev_addr, uint8_t* istrings, uint8_t max_istrings) { midih_interface_t *p_midi_host = find_midi_by_daddr(dev_addr); - TU_VERIFY(p_midi_host != NULL); - nstrings = p_midi_host->num_cables_rx; - if (nstrings > max_istrings) - { - nstrings = max_istrings; + TU_VERIFY(p_midi_host != NULL, 0); + uint8_t nstrings = p_midi_host->num_cables_rx; + if (nstrings > max_istrings) { + nstrings = max_istrings; } - uint8_t jack; - for (jack=0; jackep_in_associated_jacks[jack]; istrings[jack] = find_string_index(p_midi_host, jack_id); } @@ -886,17 +742,13 @@ uint8_t tuh_midi_get_rx_cable_istrings(uint8_t dev_addr, uint8_t* istrings, uint uint8_t tuh_midi_get_tx_cable_istrings(uint8_t dev_addr, uint8_t* istrings, uint8_t max_istrings) { - uint8_t nstrings = 0; midih_interface_t *p_midi_host = find_midi_by_daddr(dev_addr); - TU_VERIFY(p_midi_host != NULL); - nstrings = p_midi_host->num_cables_tx; - if (nstrings > max_istrings) - { - nstrings = max_istrings; + TU_VERIFY(p_midi_host != NULL, 0); + uint8_t nstrings = p_midi_host->num_cables_tx; + if (nstrings > max_istrings) { + nstrings = max_istrings; } - uint8_t jack; - for (jack=0; jackep_out_associated_jacks[jack]; istrings[jack] = find_string_index(p_midi_host, jack_id); } @@ -909,8 +761,7 @@ uint8_t tuh_midi_get_all_istrings(uint8_t dev_addr, const uint8_t** istrings) midih_interface_t *p_midi_host = find_midi_by_daddr(dev_addr); TU_VERIFY(p_midi_host != NULL); uint8_t nstrings = p_midi_host->num_string_indices; - if (nstrings) - *istrings = p_midi_host->all_string_indices; + if (nstrings) { *istrings = p_midi_host->all_string_indices; } return nstrings; } #endif diff --git a/src/class/midi/midi_host.h b/src/class/midi/midi_host.h index bf2378168..6401eb0c3 100644 --- a/src/class/midi/midi_host.h +++ b/src/class/midi/midi_host.h @@ -42,15 +42,15 @@ #endif #ifndef CFG_TUH_MIDI_RX_BUFSIZE -#define CFG_TUH_MIDI_RX_BUFSIZE 64 +#define CFG_TUH_MIDI_RX_BUFSIZE TUH_EPSIZE_BULK_MPS #endif #ifndef CFG_TUH_MIDI_TX_BUFSIZE -#define CFG_TUH_MIDI_TX_BUFSIZE 64 +#define CFG_TUH_MIDI_TX_BUFSIZE TUH_EPSIZE_BULK_MPS #endif #ifndef CFG_TUH_MIDI_EP_BUFSIZE -#define CFG_TUH_MIDI_EP_BUFSIZE 64 +#define CFG_TUH_MIDI_EP_BUFSIZE TUH_EPSIZE_BULK_MPS #endif #ifndef CFG_MIDI_HOST_DEVSTRINGS @@ -113,14 +113,6 @@ uint8_t tuh_midi_get_rx_cable_istrings(uint8_t dev_addr, uint8_t* istrings, uint uint8_t tuh_midi_get_tx_cable_istrings(uint8_t dev_addr, uint8_t* istrings, uint8_t max_istrings); uint8_t tuh_midi_get_all_istrings(uint8_t dev_addr, const uint8_t** istrings); #endif -//--------------------------------------------------------------------+ -// Internal Class Driver API -//--------------------------------------------------------------------+ -bool midih_init (void); -bool midih_open (uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *desc_itf, uint16_t max_len); -bool midih_set_config (uint8_t dev_addr, uint8_t itf_num); -bool midih_xfer_cb (uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes); -void midih_close (uint8_t dev_addr); //--------------------------------------------------------------------+ // Callbacks (Weak is optional) @@ -138,6 +130,17 @@ TU_ATTR_WEAK void tuh_midi_umount_cb(uint8_t dev_addr, uint8_t instance); TU_ATTR_WEAK void tuh_midi_rx_cb(uint8_t dev_addr, uint32_t num_packets); TU_ATTR_WEAK void tuh_midi_tx_cb(uint8_t dev_addr); + +//--------------------------------------------------------------------+ +// Internal Class Driver API +//--------------------------------------------------------------------+ +bool midih_init (void); +bool midih_deinit (void); +bool midih_open (uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *desc_itf, uint16_t max_len); +bool midih_set_config (uint8_t dev_addr, uint8_t itf_num); +bool midih_xfer_cb (uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes); +void midih_close (uint8_t dev_addr); + #ifdef __cplusplus } #endif diff --git a/src/common/tusb_private.h b/src/common/tusb_private.h index c71775abb..445882243 100644 --- a/src/common/tusb_private.h +++ b/src/common/tusb_private.h @@ -138,7 +138,7 @@ uint32_t tu_edpt_stream_read(uint8_t hwid, tu_edpt_stream_t* s, void* buffer, ui // Start an usb transfer if endpoint is not busy uint32_t tu_edpt_stream_read_xfer(uint8_t hwid, tu_edpt_stream_t* s); -// Must be called in the transfer complete callback +// Complete read transfer by writing EP -> FIFO. Must be called in the transfer complete callback TU_ATTR_ALWAYS_INLINE static inline void tu_edpt_stream_read_xfer_complete(tu_edpt_stream_t* s, uint32_t xferred_bytes) { if (tu_fifo_depth(&s->ff)) { @@ -146,11 +146,11 @@ void tu_edpt_stream_read_xfer_complete(tu_edpt_stream_t* s, uint32_t xferred_byt } } -// Same as tu_edpt_stream_read_xfer_complete but skip the first n bytes +// Complete read transfer with provided buffer TU_ATTR_ALWAYS_INLINE static inline -void tu_edpt_stream_read_xfer_complete_offset(tu_edpt_stream_t* s, uint32_t xferred_bytes, uint32_t skip_offset) { - if (tu_fifo_depth(&s->ff) && (skip_offset < xferred_bytes)) { - tu_fifo_write_n(&s->ff, s->ep_buf + skip_offset, (uint16_t) (xferred_bytes - skip_offset)); +void tu_edpt_stream_read_xfer_complete_with_buf(tu_edpt_stream_t* s, const void * buf, uint32_t xferred_bytes) { + if (tu_fifo_depth(&s->ff)) { + tu_fifo_write_n(&s->ff, buf, (uint16_t) xferred_bytes); } } diff --git a/src/host/usbh.c b/src/host/usbh.c index f874121a3..e6b6cd91c 100644 --- a/src/host/usbh.c +++ b/src/host/usbh.c @@ -192,6 +192,7 @@ static usbh_class_driver_t const usbh_class_drivers[] = { { .name = DRIVER_NAME("MIDI"), .init = midih_init, + .deinit = midih_deinit, .open = midih_open, .set_config = midih_set_config, .xfer_cb = midih_xfer_cb, @@ -1672,7 +1673,7 @@ static bool _parse_configuration_descriptor(uint8_t dev_addr, tusb_desc_configur if ( 0 == tu_desc_len(p_desc) ) { // A zero length descriptor indicates that the device is off spec (e.g. wrong wTotalLength). // Parsed interfaces should still be usable - TU_LOG_USBH("Encountered a zero-length descriptor after %u bytes\r\n", (uint32_t)p_desc - (uint32_t)desc_cfg); + TU_LOG_USBH("Encountered a zero-length descriptor after %" PRIu32 " bytes\r\n", (uint32_t)p_desc - (uint32_t)desc_cfg); break; } diff --git a/src/host/usbh.h b/src/host/usbh.h index 3bcdd3657..7fc8ea826 100644 --- a/src/host/usbh.h +++ b/src/host/usbh.h @@ -37,6 +37,9 @@ // MACRO CONSTANT TYPEDEF //--------------------------------------------------------------------+ +// Endpoint Bulk size depending on host mx speed +#define TUH_EPSIZE_BULK_MPS (TUD_OPT_HIGH_SPEED ? TUSB_EPSIZE_BULK_HS : TUSB_EPSIZE_BULK_FS) + // forward declaration struct tuh_xfer_s; typedef struct tuh_xfer_s tuh_xfer_t; -- cgit v1.3.1 From ed88fc983fcc8bd0bcc27b9982b21223a580f59d Mon Sep 17 00:00:00 2001 From: hathach Date: Fri, 14 Feb 2025 10:41:05 +0700 Subject: - remove tuh_midi_read_poll(), auto schedule EP in when set_config() and xfer_cb as well as ep read() - de-dup tuh_midi_get_num_rx/tx_cables - add tuh_midi_read_available() --- examples/host/midi_rx/src/main.c | 5 ++- src/class/midi/midi_host.c | 67 +++++++++++++--------------------------- src/class/midi/midi_host.h | 49 +++++++++++++++-------------- 3 files changed, 49 insertions(+), 72 deletions(-) (limited to 'src/class') diff --git a/examples/host/midi_rx/src/main.c b/examples/host/midi_rx/src/main.c index a03fd588f..0b07ba6e7 100644 --- a/examples/host/midi_rx/src/main.c +++ b/examples/host/midi_rx/src/main.c @@ -38,7 +38,7 @@ static uint8_t midi_dev_addr = 0; //--------------------------------------------------------------------+ -// MACRO CONSTANT TYPEDEF PROTYPES +// MACRO CONSTANT TYPEDEF PROTOTYPES //--------------------------------------------------------------------+ void led_blinking_task(void); void midi_host_rx_task(void); @@ -92,10 +92,9 @@ void midi_host_rx_task(void) { if (!midi_dev_addr || !tuh_midi_configured(midi_dev_addr)) { return; } - if (tuh_midih_get_num_rx_cables(midi_dev_addr) < 1) { + if (tuh_midi_get_num_rx_cables(midi_dev_addr) < 1) { return; } - tuh_midi_read_poll(midi_dev_addr); } //--------------------------------------------------------------------+ diff --git a/src/class/midi/midi_host.c b/src/class/midi/midi_host.c index eb3f0b070..7d6eb35fa 100644 --- a/src/class/midi/midi_host.c +++ b/src/class/midi/midi_host.c @@ -26,7 +26,7 @@ #include "tusb_option.h" -#if (TUSB_OPT_HOST_ENABLED && CFG_TUH_MIDI) +#if (CFG_TUH_ENABLED && CFG_TUH_MIDI) #include "host/usbh.h" #include "host/usbh_pvt.h" @@ -195,8 +195,7 @@ bool midih_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, uint } } - // prepare for next transfer if needed - tu_edpt_stream_read_xfer(dev_addr, &p_midi_host->ep_stream.rx); + tu_edpt_stream_read_xfer(dev_addr, &p_midi_host->ep_stream.rx); // prepare for next transfer } else if (ep_addr == p_midi_host->ep_stream.tx.ep_addr) { if (tuh_midi_tx_cb) { tuh_midi_tx_cb(dev_addr); @@ -416,12 +415,6 @@ bool midih_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *d return true; } -bool tuh_midi_configured(uint8_t dev_addr) { - midih_interface_t *p_midi_host = find_midi_by_daddr(dev_addr); - TU_VERIFY(p_midi_host != NULL); - return p_midi_host->configured; -} - bool midih_set_config(uint8_t dev_addr, uint8_t itf_num) { (void) itf_num; midih_interface_t *p_midi_host = find_midi_by_daddr(dev_addr); @@ -432,18 +425,20 @@ bool midih_set_config(uint8_t dev_addr, uint8_t itf_num) { tuh_midi_mount_cb(dev_addr, p_midi_host->ep_in, p_midi_host->ep_out, p_midi_host->num_cables_rx, p_midi_host->num_cables_tx); } + tu_edpt_stream_read_xfer(dev_addr, &p_midi_host->ep_stream.rx); // prepare for incoming data + // No special config things to do for MIDI usbh_driver_set_config_complete(dev_addr, p_midi_host->itf_num); return true; } //--------------------------------------------------------------------+ -// Stream API +// API //--------------------------------------------------------------------+ -bool tuh_midi_read_poll(uint8_t dev_addr) { +bool tuh_midi_configured(uint8_t dev_addr) { midih_interface_t *p_midi_host = find_midi_by_daddr(dev_addr); TU_VERIFY(p_midi_host != NULL); - return tu_edpt_stream_read_xfer(dev_addr, &p_midi_host->ep_stream.rx) > 0; + return p_midi_host->configured; } uint32_t tuh_midi_stream_write(uint8_t dev_addr, uint8_t cable_num, uint8_t const *buffer, uint32_t bufsize) { @@ -557,24 +552,27 @@ uint32_t tuh_midi_stream_flush(uint8_t dev_addr) { //--------------------------------------------------------------------+ // Helper //--------------------------------------------------------------------+ -uint8_t tuh_midih_get_num_tx_cables (uint8_t dev_addr) -{ +uint8_t tuh_midi_get_num_tx_cables (uint8_t dev_addr) { midih_interface_t *p_midi_host = find_midi_by_daddr(dev_addr); - TU_VERIFY(p_midi_host != NULL); - TU_VERIFY(p_midi_host->ep_out != 0); // returns 0 if fails + TU_VERIFY(p_midi_host != NULL, 0); + TU_VERIFY(p_midi_host->ep_out != 0, 0); return p_midi_host->num_cables_tx; } -uint8_t tuh_midih_get_num_rx_cables (uint8_t dev_addr) -{ +uint8_t tuh_midi_get_num_rx_cables (uint8_t dev_addr) { midih_interface_t *p_midi_host = find_midi_by_daddr(dev_addr); - TU_VERIFY(p_midi_host != NULL); - TU_VERIFY(p_midi_host->ep_in != 0); // returns 0 if fails + TU_VERIFY(p_midi_host != NULL, 0); + TU_VERIFY(p_midi_host->ep_in != 0, 0); return p_midi_host->num_cables_rx; } -bool tuh_midi_packet_read (uint8_t dev_addr, uint8_t packet[4]) -{ +uint32_t tuh_midi_read_available(uint8_t dev_addr) { + midih_interface_t *p_midi_host = find_midi_by_daddr(dev_addr); + TU_VERIFY(p_midi_host != NULL); + return tu_edpt_stream_read_available(&p_midi_host->ep_stream.rx); +} + +bool tuh_midi_packet_read (uint8_t dev_addr, uint8_t packet[4]) { midih_interface_t *p_midi_host = find_midi_by_daddr(dev_addr); TU_VERIFY(p_midi_host != NULL); TU_VERIFY(tu_edpt_stream_read_available(&p_midi_host->ep_stream.rx) >= 4); @@ -661,6 +659,7 @@ uint32_t tuh_midi_stream_read(uint8_t dev_addr, uint8_t *p_cable_num, uint8_t *p bytes_to_add_to_stream = 1; } } + for (uint8_t idx = 1; idx <= bytes_to_add_to_stream; idx++) { *p_buffer++ = p_midi_host->stream_read.buffer[idx]; } @@ -678,30 +677,6 @@ uint32_t tuh_midi_stream_read(uint8_t dev_addr, uint8_t *p_cable_num, uint8_t *p return bytes_buffered; } -uint8_t tuh_midi_get_num_rx_cables(uint8_t dev_addr) -{ - midih_interface_t *p_midi_host = find_midi_by_daddr(dev_addr); - TU_VERIFY(p_midi_host != NULL); - uint8_t num_cables = 0; - if (p_midi_host) - { - num_cables = p_midi_host->num_cables_rx; - } - return num_cables; -} - -uint8_t tuh_midi_get_num_tx_cables(uint8_t dev_addr) -{ - midih_interface_t *p_midi_host = find_midi_by_daddr(dev_addr); - TU_VERIFY(p_midi_host != NULL); - uint8_t num_cables = 0; - if (p_midi_host) - { - num_cables = p_midi_host->num_cables_tx; - } - return num_cables; -} - #if CFG_MIDI_HOST_DEVSTRINGS static uint8_t find_string_index(midih_interface_t *ptr, uint8_t jack_id) { diff --git a/src/class/midi/midi_host.h b/src/class/midi/midi_host.h index 6401eb0c3..6529f2bbc 100644 --- a/src/class/midi/midi_host.h +++ b/src/class/midi/midi_host.h @@ -58,22 +58,34 @@ #endif //--------------------------------------------------------------------+ -// Application API (Single Interface) +// Application API //--------------------------------------------------------------------+ bool tuh_midi_configured (uint8_t dev_addr); +// return the number of virtual midi cables on the device's IN endpoint +uint8_t tuh_midi_get_num_rx_cables(uint8_t dev_addr); + // return the number of virtual midi cables on the device's OUT endpoint -uint8_t tuh_midih_get_num_tx_cables (uint8_t dev_addr); +uint8_t tuh_midi_get_num_tx_cables(uint8_t dev_addr); -// return the number of virtual midi cables on the device's IN endpoint -uint8_t tuh_midih_get_num_rx_cables (uint8_t dev_addr); +#if CFG_MIDI_HOST_DEVSTRINGS +uint8_t tuh_midi_get_rx_cable_istrings(uint8_t dev_addr, uint8_t* istrings, uint8_t max_istrings); +uint8_t tuh_midi_get_tx_cable_istrings(uint8_t dev_addr, uint8_t* istrings, uint8_t max_istrings); +uint8_t tuh_midi_get_all_istrings(uint8_t dev_addr, const uint8_t** istrings); +#endif + +// return the raw number of bytes available from device endpoint. +// Note: this is related but not the same as number of stream bytes available. +uint32_t tuh_midi_read_available(uint8_t dev_addr); + +//--------------------------------------------------------------------+ +// Packet API +//--------------------------------------------------------------------+ -// request available data from the device. tuh_midi_message_received_cb() will -// be called if the device has any data to send. Otherwise, the device will -// respond NAK. This function blocks until the transfer completes or the -// devices sends NAK. -// This function will return false if the hardware is busy. -bool tuh_midi_read_poll( uint8_t dev_addr ); +// Read a raw MIDI packet from the connected device +// This function does not parse the packet format +// Return true if a packet was returned +bool tuh_midi_packet_read (uint8_t dev_addr, uint8_t packet[4]); // Queue a packet to the device. The application // must call tuh_midi_stream_flush to actually have the @@ -82,6 +94,10 @@ bool tuh_midi_read_poll( uint8_t dev_addr ); // Returns true if the packet was successfully queued. bool tuh_midi_packet_write (uint8_t dev_addr, uint8_t const packet[4]); +//--------------------------------------------------------------------+ +// Stream API +//--------------------------------------------------------------------+ + // Queue a message to the device. The application // must call tuh_midi_stream_flush to actually have the // data go out. @@ -101,19 +117,6 @@ uint32_t tuh_midi_stream_flush( uint8_t dev_addr); // it properly. uint32_t tuh_midi_stream_read (uint8_t dev_addr, uint8_t *p_cable_num, uint8_t *p_buffer, uint16_t bufsize); -// Read a raw MIDI packet from the connected device -// This function does not parse the packet format -// Return true if a packet was returned -bool tuh_midi_packet_read (uint8_t dev_addr, uint8_t packet[4]); - -uint8_t tuh_midi_get_num_rx_cables(uint8_t dev_addr); -uint8_t tuh_midi_get_num_tx_cables(uint8_t dev_addr); -#if CFG_MIDI_HOST_DEVSTRINGS -uint8_t tuh_midi_get_rx_cable_istrings(uint8_t dev_addr, uint8_t* istrings, uint8_t max_istrings); -uint8_t tuh_midi_get_tx_cable_istrings(uint8_t dev_addr, uint8_t* istrings, uint8_t max_istrings); -uint8_t tuh_midi_get_all_istrings(uint8_t dev_addr, const uint8_t** istrings); -#endif - //--------------------------------------------------------------------+ // Callbacks (Weak is optional) //--------------------------------------------------------------------+ -- cgit v1.3.1 From 31a2696de77d4642d28086ccbe476f40b1bdea7d Mon Sep 17 00:00:00 2001 From: hathach Date: Fri, 14 Feb 2025 11:09:50 +0700 Subject: - change signature of tuh_midi_mount/umount_cb() - rename midi_stream_t to midi_driver_stream_t and move to midi.h (common for device and host) --- examples/host/midi_rx/src/main.c | 22 ++++++---------------- src/class/midi/midi.h | 26 +++++++++++++++----------- src/class/midi/midi_device.c | 16 ++++++---------- src/class/midi/midi_host.c | 24 ++++++++---------------- src/class/midi/midi_host.h | 8 ++------ 5 files changed, 37 insertions(+), 59 deletions(-) (limited to 'src/class') diff --git a/examples/host/midi_rx/src/main.c b/examples/host/midi_rx/src/main.c index 0b07ba6e7..fed782947 100644 --- a/examples/host/midi_rx/src/main.c +++ b/examples/host/midi_rx/src/main.c @@ -101,30 +101,20 @@ void midi_host_rx_task(void) { // TinyUSB Callbacks //--------------------------------------------------------------------+ -// Invoked when device with hid interface is mounted -// Report descriptor is also available for use. tuh_hid_parse_report_descriptor() -// can be used to parse common/simple enough descriptor. -// Note: if report descriptor length > CFG_TUH_ENUMERATION_BUFSIZE, it will be skipped -// therefore report_desc = NULL, desc_len = 0 -void tuh_midi_mount_cb(uint8_t dev_addr, uint8_t in_ep, uint8_t out_ep, uint8_t num_cables_rx, uint16_t num_cables_tx) { - (void) in_ep; - (void) out_ep; +// Invoked when device with MIDI interface is mounted. +void tuh_midi_mount_cb(uint8_t dev_addr, uint8_t num_cables_rx, uint16_t num_cables_tx) { (void) num_cables_rx; (void) num_cables_tx; - - TU_LOG1("MIDI device address = %u, IN endpoint %u has %u cables, OUT endpoint %u has %u cables\r\n", - dev_addr, in_ep & 0xf, num_cables_rx, out_ep & 0xf, num_cables_tx); - midi_dev_addr = dev_addr; + TU_LOG1("MIDI device address = %u, Number of RX cables = %u, Number of TX cables = %u\r\n", + dev_addr, num_cables_rx, num_cables_tx); } // Invoked when device with hid interface is un-mounted -void tuh_midi_umount_cb(uint8_t dev_addr, uint8_t instance) { +void tuh_midi_umount_cb(uint8_t dev_addr) { (void) dev_addr; - (void) instance; - - TU_LOG1("MIDI device address = %d, instance = %d is unmounted\r\n", dev_addr, instance); midi_dev_addr = 0; + TU_LOG1("MIDI device address = %d is unmounted\r\n", dev_addr); } void tuh_midi_rx_cb(uint8_t dev_addr, uint32_t num_packets) { diff --git a/src/class/midi/midi.h b/src/class/midi/midi.h index 68a784c60..9591f13c4 100644 --- a/src/class/midi/midi.h +++ b/src/class/midi/midi.h @@ -24,13 +24,8 @@ * This file is part of the TinyUSB stack. */ -/** \ingroup group_class - * \defgroup ClassDriver_CDC Communication Device Class (CDC) - * Currently only Abstract Control Model subclass is supported - * @{ */ - -#ifndef _TUSB_MIDI_H__ -#define _TUSB_MIDI_H__ +#ifndef TUSB_MIDI_H_ +#define TUSB_MIDI_H_ #include "common/tusb_common.h" @@ -39,7 +34,7 @@ #endif //--------------------------------------------------------------------+ -// Class Specific Descriptor +// Constants //--------------------------------------------------------------------+ typedef enum @@ -111,6 +106,10 @@ enum MIDI_MAX_DATA_VAL = 0x7F, }; +//--------------------------------------------------------------------+ +// Class Specific Descriptor +//--------------------------------------------------------------------+ + /// MIDI Interface Header Descriptor typedef struct TU_ATTR_PACKED { @@ -216,12 +215,17 @@ typedef struct uint8_t baAssocJackID[]; ; ///< A list of associated jacks } midi_cs_desc_endpoint_t; -/** @} */ +//--------------------------------------------------------------------+ +// For Internal Driver Use +//--------------------------------------------------------------------+ +typedef struct { + uint8_t buffer[4]; + uint8_t index; + uint8_t total; +} midi_driver_stream_t; #ifdef __cplusplus } #endif #endif - -/** @} */ diff --git a/src/class/midi/midi_device.c b/src/class/midi/midi_device.c index dd1883e37..7b6705640 100644 --- a/src/class/midi/midi_device.c +++ b/src/class/midi/midi_device.c @@ -40,11 +40,7 @@ // MACRO CONSTANT TYPEDEF //--------------------------------------------------------------------+ -typedef struct { - uint8_t buffer[4]; - uint8_t index; - uint8_t total; -} midid_stream_t; + typedef struct { uint8_t itf_num; @@ -54,8 +50,8 @@ typedef struct { // For Stream read()/write() API // Messages are always 4 bytes long, queue them for reading and writing so the // callers can use the Stream interface with single-byte read/write calls. - midid_stream_t stream_write; - midid_stream_t stream_read; + midi_driver_stream_t stream_write; + midi_driver_stream_t stream_read; /*------------- From this point, data is not cleared by bus reset -------------*/ // FIFO @@ -122,7 +118,7 @@ uint32_t tud_midi_n_available(uint8_t itf, uint8_t cable_num) (void) cable_num; midid_interface_t* midi = &_midid_itf[itf]; - const midid_stream_t* stream = &midi->stream_read; + const midi_driver_stream_t* stream = &midi->stream_read; // when using with packet API stream total & index are both zero return tu_fifo_count(&midi->rx_ff) + (uint8_t) (stream->total - stream->index); @@ -136,7 +132,7 @@ uint32_t tud_midi_n_stream_read(uint8_t itf, uint8_t cable_num, void* buffer, ui uint8_t* buf8 = (uint8_t*) buffer; midid_interface_t* midi = &_midid_itf[itf]; - midid_stream_t* stream = &midi->stream_read; + midi_driver_stream_t* stream = &midi->stream_read; uint32_t total_read = 0; while( bufsize ) @@ -241,7 +237,7 @@ uint32_t tud_midi_n_stream_write(uint8_t itf, uint8_t cable_num, const uint8_t* midid_interface_t* midi = &_midid_itf[itf]; TU_VERIFY(midi->ep_in, 0); - midid_stream_t* stream = &midi->stream_write; + midi_driver_stream_t* stream = &midi->stream_write; uint32_t i = 0; while ( (i < bufsize) && (tu_fifo_remaining(&midi->tx_ff) >= 4) ) diff --git a/src/class/midi/midi_host.c b/src/class/midi/midi_host.c index 7d6eb35fa..b6ebaa7a9 100644 --- a/src/class/midi/midi_host.c +++ b/src/class/midi/midi_host.c @@ -37,14 +37,6 @@ // MACRO CONSTANT TYPEDEF //--------------------------------------------------------------------+ -// TODO: refactor to share code with the MIDI Device driver -typedef struct -{ - uint8_t buffer[4]; - uint8_t index; - uint8_t total; -}midi_stream_t; - typedef struct { uint8_t dev_addr; uint8_t itf_num; @@ -58,8 +50,8 @@ typedef struct { // For Stream read()/write() API // Messages are always 4 bytes long, queue them for reading and writing so the // callers can use the Stream interface with single-byte read/write calls. - midi_stream_t stream_write; - midi_stream_t stream_read; + midi_driver_stream_t stream_write; + midi_driver_stream_t stream_read; /*------------- From this point, data is not cleared by bus reset -------------*/ // Endpoint stream @@ -152,7 +144,7 @@ void midih_close(uint8_t dev_addr) { return; } if (tuh_midi_umount_cb) { - tuh_midi_umount_cb(dev_addr, 0); + tuh_midi_umount_cb(dev_addr); } p_midi_host->ep_in = 0; p_midi_host->ep_out = 0; @@ -422,7 +414,7 @@ bool midih_set_config(uint8_t dev_addr, uint8_t itf_num) { p_midi_host->configured = true; if (tuh_midi_mount_cb) { - tuh_midi_mount_cb(dev_addr, p_midi_host->ep_in, p_midi_host->ep_out, p_midi_host->num_cables_rx, p_midi_host->num_cables_tx); + tuh_midi_mount_cb(dev_addr, p_midi_host->num_cables_rx, p_midi_host->num_cables_tx); } tu_edpt_stream_read_xfer(dev_addr, &p_midi_host->ep_stream.rx); // prepare for incoming data @@ -445,7 +437,7 @@ uint32_t tuh_midi_stream_write(uint8_t dev_addr, uint8_t cable_num, uint8_t cons midih_interface_t *p_midi_host = find_midi_by_daddr(dev_addr); TU_VERIFY(p_midi_host != NULL); TU_VERIFY(cable_num < p_midi_host->num_cables_tx); - midi_stream_t *stream = &p_midi_host->stream_write; + midi_driver_stream_t *stream = &p_midi_host->stream_write; uint32_t i = 0; while ((i < bufsize) && (tu_edpt_stream_write_available(dev_addr, &p_midi_host->ep_stream.tx) >= 4)) { @@ -453,7 +445,7 @@ uint32_t tuh_midi_stream_write(uint8_t dev_addr, uint8_t cable_num, uint8_t cons i++; if (data >= MIDI_STATUS_SYSREAL_TIMING_CLOCK) { // real-time messages need to be sent right away - midi_stream_t streamrt; + midi_driver_stream_t streamrt; streamrt.buffer[0] = MIDI_CIN_SYSEX_END_1BYTE; streamrt.buffer[1] = data; streamrt.index = 2; @@ -555,14 +547,14 @@ uint32_t tuh_midi_stream_flush(uint8_t dev_addr) { uint8_t tuh_midi_get_num_tx_cables (uint8_t dev_addr) { midih_interface_t *p_midi_host = find_midi_by_daddr(dev_addr); TU_VERIFY(p_midi_host != NULL, 0); - TU_VERIFY(p_midi_host->ep_out != 0, 0); + TU_VERIFY(p_midi_host->ep_stream.tx.ep_addr != 0, 0); return p_midi_host->num_cables_tx; } uint8_t tuh_midi_get_num_rx_cables (uint8_t dev_addr) { midih_interface_t *p_midi_host = find_midi_by_daddr(dev_addr); TU_VERIFY(p_midi_host != NULL, 0); - TU_VERIFY(p_midi_host->ep_in != 0, 0); + TU_VERIFY(p_midi_host->ep_stream.rx.ep_addr != 0, 0); return p_midi_host->num_cables_rx; } diff --git a/src/class/midi/midi_host.h b/src/class/midi/midi_host.h index 6529f2bbc..ab6c43908 100644 --- a/src/class/midi/midi_host.h +++ b/src/class/midi/midi_host.h @@ -122,14 +122,10 @@ uint32_t tuh_midi_stream_read (uint8_t dev_addr, uint8_t *p_cable_num, uint8_t * //--------------------------------------------------------------------+ // Invoked when device with MIDI interface is mounted. -// If the MIDI host application requires MIDI IN, it should request an -// IN transfer here. The device will likely NAK this transfer. How the driver -// handles the NAK is hardware dependent. -TU_ATTR_WEAK void tuh_midi_mount_cb(uint8_t dev_addr, uint8_t in_ep, uint8_t out_ep, uint8_t num_cables_rx, uint16_t num_cables_tx); +TU_ATTR_WEAK void tuh_midi_mount_cb(uint8_t dev_addr, uint8_t num_cables_rx, uint16_t num_cables_tx); // Invoked when device with MIDI interface is un-mounted -// For now, the instance parameter is always 0 and can be ignored -TU_ATTR_WEAK void tuh_midi_umount_cb(uint8_t dev_addr, uint8_t instance); +TU_ATTR_WEAK void tuh_midi_umount_cb(uint8_t dev_addr); TU_ATTR_WEAK void tuh_midi_rx_cb(uint8_t dev_addr, uint32_t num_packets); TU_ATTR_WEAK void tuh_midi_tx_cb(uint8_t dev_addr); -- cgit v1.3.1 From 997771fdbaddd4943515e8cdade00c1252b351de Mon Sep 17 00:00:00 2001 From: hathach Date: Fri, 14 Feb 2025 16:21:48 +0700 Subject: - rename tuh_midi_stream_flush() to tuh_midi_write_flush() - add tuh_midi_packet_read_n() and tuh_midi_packet_write_n() - add CFG_TUH_MIDI_STREAM_API to opt out stream API --- src/class/midi/midi_host.c | 102 ++++++++++++++++++++++++++------------------- src/class/midi/midi_host.h | 59 +++++++++++++++++--------- 2 files changed, 97 insertions(+), 64 deletions(-) (limited to 'src/class') diff --git a/src/class/midi/midi_host.c b/src/class/midi/midi_host.c index b6ebaa7a9..55146accb 100644 --- a/src/class/midi/midi_host.c +++ b/src/class/midi/midi_host.c @@ -47,13 +47,14 @@ typedef struct { uint8_t num_cables_rx; // IN endpoint CS descriptor bNumEmbMIDIJack value uint8_t num_cables_tx; // OUT endpoint CS descriptor bNumEmbMIDIJack value + #if CFG_TUH_MIDI_STREAM_API // For Stream read()/write() API // Messages are always 4 bytes long, queue them for reading and writing so the // callers can use the Stream interface with single-byte read/write calls. midi_driver_stream_t stream_write; midi_driver_stream_t stream_read; + #endif - /*------------- From this point, data is not cleared by bus reset -------------*/ // Endpoint stream struct { tu_edpt_stream_t tx; @@ -433,6 +434,57 @@ bool tuh_midi_configured(uint8_t dev_addr) { return p_midi_host->configured; } +uint8_t tuh_midi_get_num_tx_cables (uint8_t dev_addr) { + midih_interface_t *p_midi_host = find_midi_by_daddr(dev_addr); + TU_VERIFY(p_midi_host != NULL, 0); + TU_VERIFY(p_midi_host->ep_stream.tx.ep_addr != 0, 0); + return p_midi_host->num_cables_tx; +} + +uint8_t tuh_midi_get_num_rx_cables (uint8_t dev_addr) { + midih_interface_t *p_midi_host = find_midi_by_daddr(dev_addr); + TU_VERIFY(p_midi_host != NULL, 0); + TU_VERIFY(p_midi_host->ep_stream.rx.ep_addr != 0, 0); + return p_midi_host->num_cables_rx; +} + +uint32_t tuh_midi_read_available(uint8_t dev_addr) { + midih_interface_t *p_midi_host = find_midi_by_daddr(dev_addr); + TU_VERIFY(p_midi_host != NULL); + return tu_edpt_stream_read_available(&p_midi_host->ep_stream.rx); +} + +uint32_t tuh_midi_write_flush(uint8_t dev_addr) { + midih_interface_t *p_midi = find_midi_by_daddr(dev_addr); + TU_VERIFY(p_midi != NULL); + return tu_edpt_stream_write_xfer(p_midi->dev_addr, &p_midi->ep_stream.tx); +} + +//--------------------------------------------------------------------+ +// Packet API +//--------------------------------------------------------------------+ + +uint32_t tuh_midi_packet_read_n(uint8_t dev_addr, uint8_t* buffer, uint32_t bufsize) { + midih_interface_t *p_midi_host = find_midi_by_daddr(dev_addr); + TU_VERIFY(p_midi_host != NULL); + + uint32_t count4 = tu_min32(bufsize, tu_edpt_stream_read_available(&p_midi_host->ep_stream.rx)); + count4 = tu_align4(count4); // round down to multiple of 4 + TU_VERIFY(count4 > 0, 0); + return tu_edpt_stream_read(dev_addr, &p_midi_host->ep_stream.rx, buffer, count4); +} + +uint32_t tuh_midi_packet_write_n(uint8_t dev_addr, const uint8_t* buffer, uint32_t bufsize) { + midih_interface_t *p_midi_host = find_midi_by_daddr(dev_addr); + TU_VERIFY(p_midi_host != NULL, 0); + uint32_t bufsize4 = tu_align4(bufsize); + return tu_edpt_stream_write(dev_addr, &p_midi_host->ep_stream.tx, buffer, bufsize4); +} + +//--------------------------------------------------------------------+ +// Stream API +//--------------------------------------------------------------------+ +#if CFG_TUH_MIDI_STREAM_API uint32_t tuh_midi_stream_write(uint8_t dev_addr, uint8_t cable_num, uint8_t const *buffer, uint32_t bufsize) { midih_interface_t *p_midi_host = find_midi_by_daddr(dev_addr); TU_VERIFY(p_midi_host != NULL); @@ -530,47 +582,6 @@ uint32_t tuh_midi_stream_write(uint8_t dev_addr, uint8_t cable_num, uint8_t cons return i; } -bool tuh_midi_packet_write (uint8_t dev_addr, uint8_t const packet[4]) { - midih_interface_t *p_midi_host = find_midi_by_daddr(dev_addr); - TU_VERIFY(p_midi_host != NULL); - return 4 == tu_edpt_stream_write(dev_addr, &p_midi_host->ep_stream.tx, packet, 4); -} - -uint32_t tuh_midi_stream_flush(uint8_t dev_addr) { - midih_interface_t *p_midi = find_midi_by_daddr(dev_addr); - TU_VERIFY(p_midi != NULL); - return tu_edpt_stream_write_xfer(p_midi->dev_addr, &p_midi->ep_stream.tx); -} -//--------------------------------------------------------------------+ -// Helper -//--------------------------------------------------------------------+ -uint8_t tuh_midi_get_num_tx_cables (uint8_t dev_addr) { - midih_interface_t *p_midi_host = find_midi_by_daddr(dev_addr); - TU_VERIFY(p_midi_host != NULL, 0); - TU_VERIFY(p_midi_host->ep_stream.tx.ep_addr != 0, 0); - return p_midi_host->num_cables_tx; -} - -uint8_t tuh_midi_get_num_rx_cables (uint8_t dev_addr) { - midih_interface_t *p_midi_host = find_midi_by_daddr(dev_addr); - TU_VERIFY(p_midi_host != NULL, 0); - TU_VERIFY(p_midi_host->ep_stream.rx.ep_addr != 0, 0); - return p_midi_host->num_cables_rx; -} - -uint32_t tuh_midi_read_available(uint8_t dev_addr) { - midih_interface_t *p_midi_host = find_midi_by_daddr(dev_addr); - TU_VERIFY(p_midi_host != NULL); - return tu_edpt_stream_read_available(&p_midi_host->ep_stream.rx); -} - -bool tuh_midi_packet_read (uint8_t dev_addr, uint8_t packet[4]) { - midih_interface_t *p_midi_host = find_midi_by_daddr(dev_addr); - TU_VERIFY(p_midi_host != NULL); - TU_VERIFY(tu_edpt_stream_read_available(&p_midi_host->ep_stream.rx) >= 4); - return 4 == tu_edpt_stream_read(dev_addr, &p_midi_host->ep_stream.rx, packet, 4); -} - uint32_t tuh_midi_stream_read(uint8_t dev_addr, uint8_t *p_cable_num, uint8_t *p_buffer, uint16_t bufsize) { midih_interface_t *p_midi_host = find_midi_by_daddr(dev_addr); TU_VERIFY(p_midi_host != NULL); @@ -669,6 +680,9 @@ uint32_t tuh_midi_stream_read(uint8_t dev_addr, uint8_t *p_cable_num, uint8_t *p return bytes_buffered; } +//--------------------------------------------------------------------+ +// String API +//--------------------------------------------------------------------+ #if CFG_MIDI_HOST_DEVSTRINGS static uint8_t find_string_index(midih_interface_t *ptr, uint8_t jack_id) { @@ -690,9 +704,7 @@ static uint8_t find_string_index(midih_interface_t *ptr, uint8_t jack_id) } return index; } -#endif -#if CFG_MIDI_HOST_DEVSTRINGS uint8_t tuh_midi_get_rx_cable_istrings(uint8_t dev_addr, uint8_t* istrings, uint8_t max_istrings) { midih_interface_t *p_midi_host = find_midi_by_daddr(dev_addr); TU_VERIFY(p_midi_host != NULL, 0); @@ -732,3 +744,5 @@ uint8_t tuh_midi_get_all_istrings(uint8_t dev_addr, const uint8_t** istrings) return nstrings; } #endif + +#endif diff --git a/src/class/midi/midi_host.h b/src/class/midi/midi_host.h index ab6c43908..6e2595e44 100644 --- a/src/class/midi/midi_host.h +++ b/src/class/midi/midi_host.h @@ -24,8 +24,8 @@ * This file is part of the TinyUSB stack. */ -#ifndef _TUSB_MIDI_HOST_H_ -#define _TUSB_MIDI_HOST_H_ +#ifndef TUSB_MIDI_HOST_H_ +#define TUSB_MIDI_HOST_H_ #include "class/audio/audio.h" #include "midi.h" @@ -53,6 +53,12 @@ #define CFG_TUH_MIDI_EP_BUFSIZE TUH_EPSIZE_BULK_MPS #endif +// Enable the MIDI stream read/write API. Some library can work with raw USB MIDI packet +// Disable this can save driver footprint. +#ifndef CFG_TUH_MIDI_STREAM_API +#define CFG_TUH_MIDI_STREAM_API 1 +#endif + #ifndef CFG_MIDI_HOST_DEVSTRINGS #define CFG_MIDI_HOST_DEVSTRINGS 0 #endif @@ -60,7 +66,7 @@ //--------------------------------------------------------------------+ // Application API //--------------------------------------------------------------------+ -bool tuh_midi_configured (uint8_t dev_addr); +bool tuh_midi_configured (uint8_t dev_addr); // return the number of virtual midi cables on the device's IN endpoint uint8_t tuh_midi_get_num_rx_cables(uint8_t dev_addr); @@ -74,40 +80,51 @@ uint8_t tuh_midi_get_tx_cable_istrings(uint8_t dev_addr, uint8_t* istrings, uint uint8_t tuh_midi_get_all_istrings(uint8_t dev_addr, const uint8_t** istrings); #endif -// return the raw number of bytes available from device endpoint. +// return the raw number of bytes available. // Note: this is related but not the same as number of stream bytes available. uint32_t tuh_midi_read_available(uint8_t dev_addr); +// Send any queued packets to the device if the host hardware is able to do it +// Returns the number of bytes flushed to the host hardware or 0 if +// the host hardware is busy or there is nothing in queue to send. +uint32_t tuh_midi_write_flush( uint8_t dev_addr); + //--------------------------------------------------------------------+ // Packet API //--------------------------------------------------------------------+ +// Read all available MIDI packets from the connected device +// Return number of bytes read (always multiple of 4) +uint32_t tuh_midi_packet_read_n(uint8_t dev_addr, uint8_t* buffer, uint32_t bufsize); + // Read a raw MIDI packet from the connected device -// This function does not parse the packet format // Return true if a packet was returned -bool tuh_midi_packet_read (uint8_t dev_addr, uint8_t packet[4]); +TU_ATTR_ALWAYS_INLINE static inline +bool tuh_midi_packet_read (uint8_t dev_addr, uint8_t packet[4]) { + return 4 == tuh_midi_packet_read_n(dev_addr, packet, 4); +} + +// Write all 4-byte packets, data is locally buffered and only transferred when buffered bytes +// reach the endpoint packet size or tuh_midi_write_flush() is called +uint32_t tuh_midi_packet_write_n(uint8_t dev_addr, const uint8_t* buffer, uint32_t bufsize); -// Queue a packet to the device. The application -// must call tuh_midi_stream_flush to actually have the -// data go out. It is up to the application to properly -// format this packet; this function does not check. +// Write a 4-bytes packet to the device. // Returns true if the packet was successfully queued. -bool tuh_midi_packet_write (uint8_t dev_addr, uint8_t const packet[4]); +TU_ATTR_ALWAYS_INLINE static inline +bool tuh_midi_packet_write (uint8_t dev_addr, uint8_t const packet[4]) { + return 4 == tuh_midi_packet_write_n(dev_addr, packet, 4); +} //--------------------------------------------------------------------+ // Stream API //--------------------------------------------------------------------+ +#if CFG_TUH_MIDI_STREAM_API -// Queue a message to the device. The application -// must call tuh_midi_stream_flush to actually have the -// data go out. +// Queue a message to the device using stream API. data is locally buffered and only transferred when buffered bytes +// reach the endpoint packet size or tuh_midi_write_flush() is called +// Returns number of bytes was successfully queued. uint32_t tuh_midi_stream_write (uint8_t dev_addr, uint8_t cable_num, uint8_t const* p_buffer, uint32_t bufsize); -// Send any queued packets to the device if the host hardware is able to do it -// Returns the number of bytes flushed to the host hardware or 0 if -// the host hardware is busy or there is nothing in queue to send. -uint32_t tuh_midi_stream_flush( uint8_t dev_addr); - // Get the MIDI stream from the device. Set the value pointed // to by p_cable_num to the MIDI cable number intended to receive it. // The MIDI stream will be stored in the buffer pointed to by p_buffer. @@ -117,6 +134,8 @@ uint32_t tuh_midi_stream_flush( uint8_t dev_addr); // it properly. uint32_t tuh_midi_stream_read (uint8_t dev_addr, uint8_t *p_cable_num, uint8_t *p_buffer, uint16_t bufsize); +#endif + //--------------------------------------------------------------------+ // Callbacks (Weak is optional) //--------------------------------------------------------------------+ @@ -144,4 +163,4 @@ void midih_close (uint8_t dev_addr); } #endif -#endif /* _TUSB_MIDI_HOST_H_ */ +#endif -- cgit v1.3.1 From b12c8a90125b99b71ab3409c10424d3f8ad0736b Mon Sep 17 00:00:00 2001 From: hathach Date: Fri, 21 Feb 2025 17:31:13 +0700 Subject: remove CFG_MIDI_HOST_DEVSTRINGS support, we will leave that for application to parse/extract this information if needed rename tuh_midi_configure() to mounted() for consistency --- examples/host/midi_rx/src/main.c | 2 +- src/class/midi/midi.h | 127 +++++++++---------- src/class/midi/midi_host.c | 256 ++++++++------------------------------- src/class/midi/midi_host.h | 18 ++- 4 files changed, 117 insertions(+), 286 deletions(-) (limited to 'src/class') diff --git a/examples/host/midi_rx/src/main.c b/examples/host/midi_rx/src/main.c index fed782947..57e9df29e 100644 --- a/examples/host/midi_rx/src/main.c +++ b/examples/host/midi_rx/src/main.c @@ -89,7 +89,7 @@ void led_blinking_task(void) { //--------------------------------------------------------------------+ void midi_host_rx_task(void) { // device must be attached and have at least one endpoint ready to receive a message - if (!midi_dev_addr || !tuh_midi_configured(midi_dev_addr)) { + if (!midi_dev_addr || !tuh_midi_mounted(midi_dev_addr)) { return; } if (tuh_midi_get_num_rx_cables(midi_dev_addr) < 1) { diff --git a/src/class/midi/midi.h b/src/class/midi/midi.h index 9591f13c4..a7da98831 100644 --- a/src/class/midi/midi.h +++ b/src/class/midi/midi.h @@ -36,28 +36,29 @@ //--------------------------------------------------------------------+ // Constants //--------------------------------------------------------------------+ +enum { + MIDI_VERSION_1_0 = 0x0100, + MIDI_VERSION_2_0 = 0x0200, +}; -typedef enum -{ +typedef enum { MIDI_CS_INTERFACE_HEADER = 0x01, MIDI_CS_INTERFACE_IN_JACK = 0x02, MIDI_CS_INTERFACE_OUT_JACK = 0x03, MIDI_CS_INTERFACE_ELEMENT = 0x04, } midi_cs_interface_subtype_t; -typedef enum -{ - MIDI_CS_ENDPOINT_GENERAL = 0x01 +typedef enum { + MIDI_CS_ENDPOINT_GENERAL = 0x01, + MIDI_CS_ENDPOINT_GENERAL_2_0 = 0x02, } midi_cs_endpoint_subtype_t; -typedef enum -{ +typedef enum { MIDI_JACK_EMBEDDED = 0x01, MIDI_JACK_EXTERNAL = 0x02 } midi_jack_type_t; -typedef enum -{ +typedef enum { MIDI_CIN_MISC = 0, MIDI_CIN_CABLE_EVENT = 1, MIDI_CIN_SYSCOM_2BYTE = 2, // 2 byte system common message e.g MTC, SongSelect @@ -77,8 +78,7 @@ typedef enum } midi_code_index_number_t; // MIDI 1.0 status byte -enum -{ +enum { //------------- System Exclusive -------------// MIDI_STATUS_SYSEX_START = 0xF0, MIDI_STATUS_SYSEX_END = 0xF7, @@ -101,8 +101,7 @@ enum MIDI_STATUS_SYSREAL_SYSTEM_RESET = 0xFF, }; -enum -{ +enum { MIDI_MAX_DATA_VAL = 0x7F, }; @@ -111,62 +110,48 @@ enum //--------------------------------------------------------------------+ /// MIDI Interface Header Descriptor -typedef struct TU_ATTR_PACKED -{ - uint8_t bLength ; ///< Size of this descriptor in bytes. - uint8_t bDescriptorType ; ///< Descriptor Type, must be Class-Specific - uint8_t bDescriptorSubType ; ///< Descriptor SubType - uint16_t bcdMSC ; ///< MidiStreaming SubClass release number in Binary-Coded Decimal - uint16_t wTotalLength ; +typedef struct TU_ATTR_PACKED { + uint8_t bLength; ///< Size of this descriptor in bytes. + uint8_t bDescriptorType; ///< must be TUSB_DESC_CS_INTERFACE + uint8_t bDescriptorSubType;///< Descriptor SubType + uint16_t bcdMSC; ///< MidiStreaming SubClass release number in Binary-Coded Decimal + uint16_t wTotalLength; } midi_desc_header_t; +TU_VERIFY_STATIC(sizeof(midi_desc_header_t) == 7, "size is not correct"); /// MIDI In Jack Descriptor -typedef struct TU_ATTR_PACKED -{ - uint8_t bLength ; ///< Size of this descriptor in bytes. - uint8_t bDescriptorType ; ///< Descriptor Type, must be Class-Specific - uint8_t bDescriptorSubType ; ///< Descriptor SubType - uint8_t bJackType ; ///< Embedded or External - uint8_t bJackID ; ///< Unique ID for MIDI IN Jack - uint8_t iJack ; ///< string descriptor +typedef struct TU_ATTR_PACKED { + uint8_t bLength; ///< Size of this descriptor in bytes. + uint8_t bDescriptorType; ///< Descriptor Type, must be Class-Specific + uint8_t bDescriptorSubType;///< Descriptor SubType + uint8_t bJackType; ///< Embedded or External + uint8_t bJackID; ///< Unique ID for MIDI IN Jack + uint8_t iJack; ///< string descriptor } midi_desc_in_jack_t; +TU_VERIFY_STATIC(sizeof(midi_desc_in_jack_t) == 6, "size is not correct"); - -/// MIDI Out Jack Descriptor with single pin -typedef struct TU_ATTR_PACKED -{ - uint8_t bLength ; ///< Size of this descriptor in bytes. - uint8_t bDescriptorType ; ///< Descriptor Type, must be Class-Specific - uint8_t bDescriptorSubType ; ///< Descriptor SubType - uint8_t bJackType ; ///< Embedded or External - uint8_t bJackID ; ///< Unique ID for MIDI IN Jack - uint8_t bNrInputPins; - - uint8_t baSourceID; - uint8_t baSourcePin; - - uint8_t iJack ; ///< string descriptor -} midi_desc_out_jack_t ; - -/// MIDI Out Jack Descriptor with multiple pins +/// MIDI Out Jack Descriptor with multiple input pins #define midi_desc_out_jack_n_t(input_num) \ - struct TU_ATTR_PACKED { \ - uint8_t bLength ; \ - uint8_t bDescriptorType ; \ - uint8_t bDescriptorSubType ; \ - uint8_t bJackType ; \ - uint8_t bJackID ; \ - uint8_t bNrInputPins ; \ - struct TU_ATTR_PACKED { \ - uint8_t baSourceID; \ - uint8_t baSourcePin; \ - } pins[input_num]; \ - uint8_t iJack ; \ + struct TU_ATTR_PACKED { \ + uint8_t bLength; \ + uint8_t bDescriptorType; \ + uint8_t bDescriptorSubType; \ + uint8_t bJackType; \ + uint8_t bJackID; \ + uint8_t bNrInputPins; \ + struct TU_ATTR_PACKED { \ + uint8_t baSourceID; \ + uint8_t baSourcePin; \ + } input[input_num]; \ + uint8_t iJack; \ } +typedef midi_desc_out_jack_n_t(1) midi_desc_out_jack_1in_t; // 1 input +typedef midi_desc_out_jack_1in_t midi_desc_out_jack_t; // backward compatible +TU_VERIFY_STATIC(sizeof(midi_desc_out_jack_1in_t) == 7 + 2 * 1, "size is not correct"); + /// MIDI Element 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, must be Class-Specific uint8_t bDescriptorSubType ; ///< Descriptor SubType @@ -184,6 +169,7 @@ typedef struct TU_ATTR_PACKED uint16_t bmElementCaps; uint8_t iElement; } midi_desc_element_t; +TU_VERIFY_STATIC(sizeof(midi_desc_element_t) == 14, "size is not correct"); /// MIDI Element Descriptor with multiple pins #define midi_desc_element_n_t(input_num) \ @@ -206,14 +192,19 @@ typedef struct TU_ATTR_PACKED } // This descriptor follows the standard bulk data endpoint descriptor -typedef struct -{ - uint8_t bLength ; ///< Size of this descriptor in bytes (4+bNumEmbMIDIJack) - uint8_t bDescriptorType ; ///< Descriptor Type, must be CS_ENDPOINT - uint8_t bDescriptorSubType ; ///< Descriptor SubType, must be MS_GENERAL - uint8_t bNumEmbMIDIJack; ; ///< Number of embedded MIDI jacks associated with this endpoint - uint8_t baAssocJackID[]; ; ///< A list of associated jacks -} midi_cs_desc_endpoint_t; +#define midi_desc_cs_endpoint_n_t(jack_num) \ + struct TU_ATTR_PACKED { \ + uint8_t bLength; \ + uint8_t bDescriptorType; \ + uint8_t bDescriptorSubType; \ + uint8_t bNumEmbMIDIJack; \ + uint8_t baAssocJackID[jack_num]; \ + } + +typedef midi_desc_cs_endpoint_n_t() midi_desc_cs_endpoint_t; // empty/flexible jack list +typedef midi_desc_cs_endpoint_n_t(1) midi_desc_cs_endpoint_1jack_t; + +TU_VERIFY_STATIC(sizeof(midi_desc_cs_endpoint_1jack_t) == 4+1, "size is not correct"); //--------------------------------------------------------------------+ // For Internal Driver Use diff --git a/src/class/midi/midi_host.c b/src/class/midi/midi_host.c index 55146accb..810c413e3 100644 --- a/src/class/midi/midi_host.c +++ b/src/class/midi/midi_host.c @@ -33,6 +33,13 @@ #include "midi_host.h" +// Level where CFG_TUSB_DEBUG must be at least for this driver is logged +#ifndef CFG_TUH_MIDI_LOG_LEVEL + #define CFG_TUH_MIDI_LOG_LEVEL CFG_TUH_LOG_LEVEL +#endif + +#define TU_LOG_DRV(...) TU_LOG(CFG_TUH_MIDI_LOG_LEVEL, __VA_ARGS__) + //--------------------------------------------------------------------+ // MACRO CONSTANT TYPEDEF //--------------------------------------------------------------------+ @@ -65,30 +72,6 @@ typedef struct { } ep_stream; bool configured; - -#if CFG_MIDI_HOST_DEVSTRINGS -#define MAX_STRING_INDICES 32 - uint8_t all_string_indices[MAX_STRING_INDICES]; - uint8_t num_string_indices; -#define MAX_IN_JACKS 8 -#define MAX_OUT_JACKS 8 - struct { - uint8_t jack_id; - uint8_t jack_type; - uint8_t string_index; - } in_jack_info[MAX_IN_JACKS]; - uint8_t next_in_jack; - struct { - uint8_t jack_id; - uint8_t jack_type; - uint8_t num_source_ids; - uint8_t source_ids[MAX_IN_JACKS/4]; - uint8_t string_index; - } out_jack_info[MAX_OUT_JACKS]; - uint8_t next_out_jack; - uint8_t ep_in_associated_jacks[MAX_OUT_JACKS/2]; - uint8_t ep_out_associated_jacks[MAX_IN_JACKS/2]; -#endif }midih_interface_t; typedef struct { @@ -209,19 +192,14 @@ bool midih_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, uint bool midih_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *desc_itf, uint16_t max_len) { (void) rhport; - midih_interface_t *p_midi_host = find_new_midi(); - TU_VERIFY(p_midi_host != NULL); + midih_interface_t *p_midi = find_new_midi(); + TU_VERIFY(p_midi != NULL); - p_midi_host->num_string_indices = 0; TU_VERIFY(TUSB_CLASS_AUDIO == desc_itf->bInterfaceClass); // There can be just a MIDI interface or an audio and a MIDI interface. Only open the MIDI interface uint8_t const *p_desc = (uint8_t const *) desc_itf; uint16_t len_parsed = 0; if (AUDIO_SUBCLASS_CONTROL == desc_itf->bInterfaceSubClass) { - // Keep track of any string descriptor that might be here - if (desc_itf->iInterface != 0) { - p_midi_host->all_string_indices[p_midi_host->num_string_indices++] = desc_itf->iInterface; - } // This driver does not support audio streaming. However, if this is the audio control interface // there might be a MIDI interface following it. Search through every descriptor until a MIDI // interface is found or the end of the descriptor is found @@ -237,26 +215,18 @@ bool midih_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *d TU_VERIFY(AUDIO_SUBCLASS_MIDI_STREAMING == desc_itf->bInterfaceSubClass); len_parsed += desc_itf->bLength; - // Keep track of any string descriptor that might be here - if (desc_itf->iInterface != 0) { - p_midi_host->all_string_indices[p_midi_host->num_string_indices++] = desc_itf->iInterface; - } + TU_LOG_DRV("MIDI opening Interface %u (addr = %u)\r\n", desc_itf->bInterfaceNumber, dev_addr); + p_midi->itf_num = desc_itf->bInterfaceNumber; + // CS Header descriptor p_desc = tu_desc_next(p_desc); - TU_LOG1("MIDI opening Interface %u (addr = %u)\r\n", desc_itf->bInterfaceNumber, dev_addr); - // Find out if getting the MIDI class specific interface header or an endpoint descriptor - // or a class-specific endpoint descriptor - // Jack descriptors or element descriptors must follow the cs interface header, - // but this driver does not support devices that contain element descriptors - - // assume it is an interface header - midi_desc_header_t const *p_mdh = (midi_desc_header_t const *)p_desc; - TU_VERIFY((p_mdh->bDescriptorType == TUSB_DESC_CS_INTERFACE && p_mdh->bDescriptorSubType == MIDI_CS_INTERFACE_HEADER) || - (p_mdh->bDescriptorType == TUSB_DESC_CS_ENDPOINT && p_mdh->bDescriptorSubType == MIDI_CS_ENDPOINT_GENERAL) || - p_mdh->bDescriptorType == TUSB_DESC_ENDPOINT); + midi_desc_header_t const *p_mdh = (midi_desc_header_t const *) p_desc; + TU_VERIFY(p_mdh->bDescriptorType == TUSB_DESC_CS_INTERFACE && + p_mdh->bDescriptorSubType == MIDI_CS_INTERFACE_HEADER); + TU_LOG_DRV(" Interface Header descriptor\r\n"); + // p_desc = tu_desc_next(p_desc); uint8_t prev_ep_addr = 0; // the CS endpoint descriptor is associated with the previous endpoint descriptor - p_midi_host->itf_num = desc_itf->bInterfaceNumber; tusb_desc_endpoint_t const* in_desc = NULL; tusb_desc_endpoint_t const* out_desc = NULL; while (len_parsed < max_len) { @@ -271,110 +241,53 @@ bool midih_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *d // assume it is an input jack midi_desc_in_jack_t const *p_mdij = (midi_desc_in_jack_t const *) p_desc; if (p_mdij->bDescriptorSubType == MIDI_CS_INTERFACE_HEADER) { - TU_LOG2("Found MIDI Interface Header\r\b"); + TU_LOG_DRV(" Interface Header descriptor\r\n"); } else if (p_mdij->bDescriptorSubType == MIDI_CS_INTERFACE_IN_JACK) { // Then it is an in jack. - TU_LOG2("Found in jack\r\n"); - #if CFG_MIDI_HOST_DEVSTRINGS - if (p_midi_host->next_in_jack < MAX_IN_JACKS) { - p_midi_host->in_jack_info[p_midi_host->next_in_jack].jack_id = p_mdij->bJackID; - p_midi_host->in_jack_info[p_midi_host->next_in_jack].jack_type = p_mdij->bJackType; - p_midi_host->in_jack_info[p_midi_host->next_in_jack].string_index = p_mdij->iJack; - ++p_midi_host->next_in_jack; - // Keep track of any string descriptor that might be here - if (p_mdij->iJack != 0) { - p_midi_host->all_string_indices[p_midi_host->num_string_indices++] = p_mdij->iJack; - } - } - #endif + TU_LOG_DRV(" IN Jack %s descriptor \r\n", p_mdij->bJackType == MIDI_JACK_EXTERNAL ? "External" : "Embedded"); } else if (p_mdij->bDescriptorSubType == MIDI_CS_INTERFACE_OUT_JACK) { // then it is an out jack - TU_LOG2("Found out jack\r\n"); - #if CFG_MIDI_HOST_DEVSTRINGS - if (p_midi_host->next_out_jack < MAX_OUT_JACKS) { - midi_desc_out_jack_t const *p_mdoj = (midi_desc_out_jack_t const *) p_desc; - p_midi_host->out_jack_info[p_midi_host->next_out_jack].jack_id = p_mdoj->bJackID; - p_midi_host->out_jack_info[p_midi_host->next_out_jack].jack_type = p_mdoj->bJackType; - p_midi_host->out_jack_info[p_midi_host->next_out_jack].num_source_ids = p_mdoj->bNrInputPins; - const struct associated_jack_s { - uint8_t id; - uint8_t pin; - } *associated_jack = (const struct associated_jack_s *) (p_desc + 6); - int jack; - for (jack = 0; jack < p_mdoj->bNrInputPins; jack++) { - p_midi_host->out_jack_info[p_midi_host->next_out_jack].source_ids[jack] = associated_jack->id; - } - p_midi_host->out_jack_info[p_midi_host->next_out_jack].string_index = *(p_desc + 6 + p_mdoj->bNrInputPins * 2); - ++p_midi_host->next_out_jack; - if (p_mdoj->iJack != 0) { - p_midi_host->all_string_indices[p_midi_host->num_string_indices++] = p_mdoj->iJack; - } - } - #endif + TU_LOG_DRV(" OUT Jack %s descriptor\r\n", p_mdij->bJackType == MIDI_JACK_EXTERNAL ? "External" : "Embedded"); } else if (p_mdij->bDescriptorSubType == MIDI_CS_INTERFACE_ELEMENT) { // the it is an element; - #if CFG_MIDI_HOST_DEVSTRINGS - TU_LOG1("Found element; strings not supported\r\n"); - #else - TU_LOG2("Found element\r\n"); - #endif + TU_LOG_DRV("Found element\r\n"); } else { - TU_LOG2("Unknown CS Interface sub-type %u\r\n", p_mdij->bDescriptorSubType); + TU_LOG_DRV(" Unknown CS Interface sub-type %u\r\n", p_mdij->bDescriptorSubType); TU_VERIFY(false);// unknown CS Interface sub-type } len_parsed += p_mdij->bLength; } else if (p_mdh->bDescriptorType == TUSB_DESC_CS_ENDPOINT) { - TU_LOG2("found CS_ENDPOINT Descriptor for %u\r\n", prev_ep_addr); + TU_LOG_DRV(" CS_ENDPOINT descriptor\r\n"); TU_VERIFY(prev_ep_addr != 0); // parse out the mapping between the device's embedded jacks and the endpoints // Each embedded IN jack is associated with an OUT endpoint - midi_cs_desc_endpoint_t const *p_csep = (midi_cs_desc_endpoint_t const *) p_mdh; + midi_desc_cs_endpoint_t const *p_csep = (midi_desc_cs_endpoint_t const *) p_mdh; if (tu_edpt_dir(prev_ep_addr) == TUSB_DIR_OUT) { - TU_VERIFY(p_midi_host->ep_out == prev_ep_addr); - TU_VERIFY(p_midi_host->num_cables_tx == 0); - p_midi_host->num_cables_tx = p_csep->bNumEmbMIDIJack; - #if CFG_MIDI_HOST_DEVSTRINGS - uint8_t jack; - uint8_t max_jack = p_midi_host->num_cables_tx; - if (max_jack > sizeof(p_midi_host->ep_out_associated_jacks)) { - max_jack = sizeof(p_midi_host->ep_out_associated_jacks); - } - for (jack = 0; jack < max_jack; jack++) { - p_midi_host->ep_out_associated_jacks[jack] = p_csep->baAssocJackID[jack]; - } - #endif + TU_VERIFY(p_midi->ep_out == prev_ep_addr); + TU_VERIFY(p_midi->num_cables_tx == 0); + p_midi->num_cables_tx = p_csep->bNumEmbMIDIJack; } else { - TU_VERIFY(p_midi_host->ep_in == prev_ep_addr); - TU_VERIFY(p_midi_host->num_cables_rx == 0); - p_midi_host->num_cables_rx = p_csep->bNumEmbMIDIJack; - #if CFG_MIDI_HOST_DEVSTRINGS - uint8_t jack; - uint8_t max_jack = p_midi_host->num_cables_rx; - if (max_jack > sizeof(p_midi_host->ep_in_associated_jacks)) { - max_jack = sizeof(p_midi_host->ep_in_associated_jacks); - } - for (jack = 0; jack < max_jack; jack++) { - p_midi_host->ep_in_associated_jacks[jack] = p_csep->baAssocJackID[jack]; - } - #endif + TU_VERIFY(p_midi->ep_in == prev_ep_addr); + TU_VERIFY(p_midi->num_cables_rx == 0); + p_midi->num_cables_rx = p_csep->bNumEmbMIDIJack; } len_parsed += p_csep->bLength; prev_ep_addr = 0; } else if (p_mdh->bDescriptorType == TUSB_DESC_ENDPOINT) { // parse out the bulk endpoint info tusb_desc_endpoint_t const *p_ep = (tusb_desc_endpoint_t const *) p_mdh; - TU_LOG2("found ENDPOINT Descriptor for %u\r\n", p_ep->bEndpointAddress); + TU_LOG_DRV(" Endpoint descriptor %02x\r\n", p_ep->bEndpointAddress); if (tu_edpt_dir(p_ep->bEndpointAddress) == TUSB_DIR_OUT) { - TU_VERIFY(p_midi_host->ep_out == 0); - TU_VERIFY(p_midi_host->num_cables_tx == 0); - p_midi_host->ep_out = p_ep->bEndpointAddress; - prev_ep_addr = p_midi_host->ep_out; + TU_VERIFY(p_midi->ep_out == 0); + TU_VERIFY(p_midi->num_cables_tx == 0); + p_midi->ep_out = p_ep->bEndpointAddress; + prev_ep_addr = p_midi->ep_out; out_desc = p_ep; } else { - TU_VERIFY(p_midi_host->ep_in == 0); - TU_VERIFY(p_midi_host->num_cables_rx == 0); - p_midi_host->ep_in = p_ep->bEndpointAddress; - prev_ep_addr = p_midi_host->ep_in; + TU_VERIFY(p_midi->ep_in == 0); + TU_VERIFY(p_midi->num_cables_rx == 0); + p_midi->ep_in = p_ep->bEndpointAddress; + prev_ep_addr = p_midi->ep_in; in_desc = p_ep; } len_parsed += p_mdh->bLength; @@ -382,28 +295,22 @@ bool midih_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *d p_desc = tu_desc_next(p_desc); p_mdh = (midi_desc_header_t const *) p_desc; } - TU_VERIFY((p_midi_host->ep_out != 0 && p_midi_host->num_cables_tx != 0) || - (p_midi_host->ep_in != 0 && p_midi_host->num_cables_rx != 0)); - TU_LOG1("MIDI descriptor parsed successfully\r\n"); - // remove duplicate string indices - for (int idx = 0; idx < p_midi_host->num_string_indices; idx++) { - for (int jdx = idx + 1; jdx < p_midi_host->num_string_indices; jdx++) { - while (jdx < p_midi_host->num_string_indices && p_midi_host->all_string_indices[idx] == p_midi_host->all_string_indices[jdx]) { - // delete the duplicate by overwriting it with the last entry and reducing the number of entries by 1 - p_midi_host->all_string_indices[jdx] = p_midi_host->all_string_indices[p_midi_host->num_string_indices - 1]; - --p_midi_host->num_string_indices; - } - } - } + TU_VERIFY((p_midi->ep_out != 0 && p_midi->num_cables_tx != 0) || + (p_midi->ep_in != 0 && p_midi->num_cables_rx != 0)); + if (in_desc) { TU_ASSERT(tuh_edpt_open(dev_addr, in_desc)); - tu_edpt_stream_open(&p_midi_host->ep_stream.rx, in_desc); + tu_edpt_stream_open(&p_midi->ep_stream.rx, in_desc); } if (out_desc) { TU_ASSERT(tuh_edpt_open(dev_addr, out_desc)); - tu_edpt_stream_open(&p_midi_host->ep_stream.tx, out_desc); + tu_edpt_stream_open(&p_midi->ep_stream.tx, out_desc); } - p_midi_host->dev_addr = dev_addr; + p_midi->dev_addr = dev_addr; + + // if (tuh_midi_interface_descriptor_cb) { + // tuh_midi_interface_descriptor_cb(dev_addr, desc_itf, ); + // } return true; } @@ -428,7 +335,7 @@ bool midih_set_config(uint8_t dev_addr, uint8_t itf_num) { //--------------------------------------------------------------------+ // API //--------------------------------------------------------------------+ -bool tuh_midi_configured(uint8_t dev_addr) { +bool tuh_midi_mounted(uint8_t dev_addr) { midih_interface_t *p_midi_host = find_midi_by_daddr(dev_addr); TU_VERIFY(p_midi_host != NULL); return p_midi_host->configured; @@ -680,69 +587,6 @@ uint32_t tuh_midi_stream_read(uint8_t dev_addr, uint8_t *p_cable_num, uint8_t *p return bytes_buffered; } -//--------------------------------------------------------------------+ -// String API -//--------------------------------------------------------------------+ -#if CFG_MIDI_HOST_DEVSTRINGS -static uint8_t find_string_index(midih_interface_t *ptr, uint8_t jack_id) -{ - uint8_t index = 0; - uint8_t assoc; - for (assoc = 0; index == 0 && assoc < ptr->next_in_jack; assoc++) - { - if (jack_id == ptr->in_jack_info[assoc].jack_id) - { - index = ptr->in_jack_info[assoc].string_index; - } - } - for (assoc = 0; index == 0 && assoc < ptr->next_out_jack; assoc++) - { - if (jack_id == ptr->out_jack_info[assoc].jack_id) - { - index = ptr->out_jack_info[assoc].string_index; - } - } - return index; -} - -uint8_t tuh_midi_get_rx_cable_istrings(uint8_t dev_addr, uint8_t* istrings, uint8_t max_istrings) { - midih_interface_t *p_midi_host = find_midi_by_daddr(dev_addr); - TU_VERIFY(p_midi_host != NULL, 0); - uint8_t nstrings = p_midi_host->num_cables_rx; - if (nstrings > max_istrings) { - nstrings = max_istrings; - } - for (uint8_t jack = 0; jackep_in_associated_jacks[jack]; - istrings[jack] = find_string_index(p_midi_host, jack_id); - } - return nstrings; -} - -uint8_t tuh_midi_get_tx_cable_istrings(uint8_t dev_addr, uint8_t* istrings, uint8_t max_istrings) -{ - midih_interface_t *p_midi_host = find_midi_by_daddr(dev_addr); - TU_VERIFY(p_midi_host != NULL, 0); - uint8_t nstrings = p_midi_host->num_cables_tx; - if (nstrings > max_istrings) { - nstrings = max_istrings; - } - for (uint8_t jack = 0; jackep_out_associated_jacks[jack]; - istrings[jack] = find_string_index(p_midi_host, jack_id); - } - return nstrings; -} -#endif - -uint8_t tuh_midi_get_all_istrings(uint8_t dev_addr, const uint8_t** istrings) -{ - midih_interface_t *p_midi_host = find_midi_by_daddr(dev_addr); - TU_VERIFY(p_midi_host != NULL); - uint8_t nstrings = p_midi_host->num_string_indices; - if (nstrings) { *istrings = p_midi_host->all_string_indices; } - return nstrings; -} #endif #endif diff --git a/src/class/midi/midi_host.h b/src/class/midi/midi_host.h index 6e2595e44..adf41d205 100644 --- a/src/class/midi/midi_host.h +++ b/src/class/midi/midi_host.h @@ -59,14 +59,12 @@ #define CFG_TUH_MIDI_STREAM_API 1 #endif -#ifndef CFG_MIDI_HOST_DEVSTRINGS -#define CFG_MIDI_HOST_DEVSTRINGS 0 -#endif - //--------------------------------------------------------------------+ // Application API //--------------------------------------------------------------------+ -bool tuh_midi_configured (uint8_t dev_addr); + +// Check if MIDI interface is mounted +bool tuh_midi_mounted(uint8_t dev_addr); // return the number of virtual midi cables on the device's IN endpoint uint8_t tuh_midi_get_num_rx_cables(uint8_t dev_addr); @@ -74,12 +72,6 @@ uint8_t tuh_midi_get_num_rx_cables(uint8_t dev_addr); // return the number of virtual midi cables on the device's OUT endpoint uint8_t tuh_midi_get_num_tx_cables(uint8_t dev_addr); -#if CFG_MIDI_HOST_DEVSTRINGS -uint8_t tuh_midi_get_rx_cable_istrings(uint8_t dev_addr, uint8_t* istrings, uint8_t max_istrings); -uint8_t tuh_midi_get_tx_cable_istrings(uint8_t dev_addr, uint8_t* istrings, uint8_t max_istrings); -uint8_t tuh_midi_get_all_istrings(uint8_t dev_addr, const uint8_t** istrings); -#endif - // return the raw number of bytes available. // Note: this is related but not the same as number of stream bytes available. uint32_t tuh_midi_read_available(uint8_t dev_addr); @@ -140,6 +132,10 @@ uint32_t tuh_midi_stream_read (uint8_t dev_addr, uint8_t *p_cable_num, uint8_t * // Callbacks (Weak is optional) //--------------------------------------------------------------------+ +// Invoked when MIDI interface is detected in enumeration. Application can copy/parse descriptor if needed. +// Note: may be fired before tuh_midi_mount_cb(), therefore midi interface is not mounted/ready. +// TU_ATTR_WEAK void tuh_midi_interface_descriptor_cb(uint8_t dev_addr, const uint8_t* desc_itf, uint16_t desc_len); + // Invoked when device with MIDI interface is mounted. TU_ATTR_WEAK void tuh_midi_mount_cb(uint8_t dev_addr, uint8_t num_cables_rx, uint16_t num_cables_tx); -- cgit v1.3.1 From 71e046d9ffb6e388052b02f8230de51bfeb5b0ed Mon Sep 17 00:00:00 2001 From: hathach Date: Sun, 23 Feb 2025 22:21:55 +0700 Subject: add tuh_midi_descriptor_cb() --- src/class/audio/audio.h | 1 + src/class/audio/audio_device.c | 4 - src/class/midi/midi.h | 21 ----- src/class/midi/midi_host.c | 179 +++++++++++++++++++---------------------- src/class/midi/midi_host.h | 14 +++- src/common/tusb_types.h | 14 +++- src/tusb.c | 12 ++- 7 files changed, 115 insertions(+), 130 deletions(-) (limited to 'src/class') diff --git a/src/class/audio/audio.h b/src/class/audio/audio.h index 2f97c0f23..0d1acadcc 100644 --- a/src/class/audio/audio.h +++ b/src/class/audio/audio.h @@ -661,6 +661,7 @@ typedef struct TU_ATTR_PACKED uint16_t wTotalLength ; ///< Total number of bytes returned for the class-specific AudioControl interface descriptor. Includes the combined length of this descriptor header and all Clock Source, Unit and Terminal descriptors. uint8_t bmControls ; ///< See: audio_cs_ac_interface_control_pos_t. } audio_desc_cs_ac_interface_t; +TU_VERIFY_STATIC(sizeof(audio_desc_cs_ac_interface_t) == 9, "size is not correct"); /// AUDIO Clock Source Descriptor (4.7.2.1) typedef struct TU_ATTR_PACKED diff --git a/src/class/audio/audio_device.c b/src/class/audio/audio_device.c index 8a130b7e2..388168424 100644 --- a/src/class/audio/audio_device.c +++ b/src/class/audio/audio_device.c @@ -628,10 +628,6 @@ static uint8_t audiod_get_audio_fct_idx(audiod_function_t *audio); #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) { - return ((uint8_t const *) desc)[2]; -} #endif #if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_EP_IN_FLOW_CONTROL diff --git a/src/class/midi/midi.h b/src/class/midi/midi.h index a7da98831..cd67640e4 100644 --- a/src/class/midi/midi.h +++ b/src/class/midi/midi.h @@ -150,27 +150,6 @@ typedef midi_desc_out_jack_n_t(1) midi_desc_out_jack_1in_t; // 1 input typedef midi_desc_out_jack_1in_t midi_desc_out_jack_t; // backward compatible TU_VERIFY_STATIC(sizeof(midi_desc_out_jack_1in_t) == 7 + 2 * 1, "size is not correct"); -/// MIDI Element Descriptor -typedef struct TU_ATTR_PACKED { - uint8_t bLength ; ///< Size of this descriptor in bytes. - uint8_t bDescriptorType ; ///< Descriptor Type, must be Class-Specific - uint8_t bDescriptorSubType ; ///< Descriptor SubType - uint8_t bElementID; - - uint8_t bNrInputPins; - uint8_t baSourceID; - uint8_t baSourcePin; - - uint8_t bNrOutputPins; - uint8_t bInTerminalLink; - uint8_t bOutTerminalLink; - uint8_t bElCapsSize; - - uint16_t bmElementCaps; - uint8_t iElement; -} midi_desc_element_t; -TU_VERIFY_STATIC(sizeof(midi_desc_element_t) == 14, "size is not correct"); - /// MIDI Element Descriptor with multiple pins #define midi_desc_element_n_t(input_num) \ struct TU_ATTR_PACKED { \ diff --git a/src/class/midi/midi_host.c b/src/class/midi/midi_host.c index 810c413e3..2fdf41b9d 100644 --- a/src/class/midi/midi_host.c +++ b/src/class/midi/midi_host.c @@ -194,123 +194,108 @@ bool midih_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *d midih_interface_t *p_midi = find_new_midi(); TU_VERIFY(p_midi != NULL); - TU_VERIFY(TUSB_CLASS_AUDIO == desc_itf->bInterfaceClass); - // There can be just a MIDI interface or an audio and a MIDI interface. Only open the MIDI interface + + // There can be just a MIDI or an Audio + MIDI interface + // const uint8_t* p_start = ((uint8_t const*) desc_itf); + const uint8_t* p_end = ((uint8_t const*) desc_itf) + max_len; uint8_t const *p_desc = (uint8_t const *) desc_itf; uint16_t len_parsed = 0; + + tuh_midi_descriptor_cb_t desc_cb = { 0 }; + desc_cb.jack_num = 0; + + // If there is Audio Control Interface + Audio Header descriptor, skip it if (AUDIO_SUBCLASS_CONTROL == desc_itf->bInterfaceSubClass) { - // This driver does not support audio streaming. However, if this is the audio control interface - // there might be a MIDI interface following it. Search through every descriptor until a MIDI - // interface is found or the end of the descriptor is found - while (len_parsed < max_len && - (desc_itf->bInterfaceClass != TUSB_CLASS_AUDIO || desc_itf->bInterfaceSubClass != AUDIO_SUBCLASS_MIDI_STREAMING)) { - len_parsed += desc_itf->bLength; - p_desc = tu_desc_next(p_desc); - desc_itf = (tusb_desc_interface_t const *)p_desc; - } + TU_VERIFY(max_len > 2*sizeof(tusb_desc_interface_t) + sizeof(audio_desc_cs_ac_interface_t)); + p_desc = tu_desc_next(p_desc); + TU_VERIFY(tu_desc_type(p_desc) == TUSB_DESC_CS_INTERFACE && + tu_desc_subtype(p_desc) == AUDIO_CS_AC_INTERFACE_HEADER); + + p_desc = tu_desc_next(p_desc); + desc_itf = (tusb_desc_interface_t const *)p_desc; TU_VERIFY(TUSB_CLASS_AUDIO == desc_itf->bInterfaceClass); } TU_VERIFY(AUDIO_SUBCLASS_MIDI_STREAMING == desc_itf->bInterfaceSubClass); + desc_cb.desc_interface = desc_itf; + len_parsed += desc_itf->bLength; TU_LOG_DRV("MIDI opening Interface %u (addr = %u)\r\n", desc_itf->bInterfaceNumber, dev_addr); p_midi->itf_num = desc_itf->bInterfaceNumber; - - // CS Header descriptor p_desc = tu_desc_next(p_desc); - midi_desc_header_t const *p_mdh = (midi_desc_header_t const *) p_desc; - TU_VERIFY(p_mdh->bDescriptorType == TUSB_DESC_CS_INTERFACE && - p_mdh->bDescriptorSubType == MIDI_CS_INTERFACE_HEADER); - TU_LOG_DRV(" Interface Header descriptor\r\n"); - - // p_desc = tu_desc_next(p_desc); - uint8_t prev_ep_addr = 0; // the CS endpoint descriptor is associated with the previous endpoint descriptor - tusb_desc_endpoint_t const* in_desc = NULL; - tusb_desc_endpoint_t const* out_desc = NULL; - while (len_parsed < max_len) { - TU_VERIFY((p_mdh->bDescriptorType == TUSB_DESC_CS_INTERFACE) || - (p_mdh->bDescriptorType == TUSB_DESC_CS_ENDPOINT && p_mdh->bDescriptorSubType == MIDI_CS_ENDPOINT_GENERAL) || - p_mdh->bDescriptorType == TUSB_DESC_ENDPOINT); - - if (p_mdh->bDescriptorType == TUSB_DESC_CS_INTERFACE) { - // The USB host doesn't really need this information unless it uses - // the string descriptor for a jack or Element - - // assume it is an input jack - midi_desc_in_jack_t const *p_mdij = (midi_desc_in_jack_t const *) p_desc; - if (p_mdij->bDescriptorSubType == MIDI_CS_INTERFACE_HEADER) { - TU_LOG_DRV(" Interface Header descriptor\r\n"); - } else if (p_mdij->bDescriptorSubType == MIDI_CS_INTERFACE_IN_JACK) { - // Then it is an in jack. - TU_LOG_DRV(" IN Jack %s descriptor \r\n", p_mdij->bJackType == MIDI_JACK_EXTERNAL ? "External" : "Embedded"); - } else if (p_mdij->bDescriptorSubType == MIDI_CS_INTERFACE_OUT_JACK) { - // then it is an out jack - TU_LOG_DRV(" OUT Jack %s descriptor\r\n", p_mdij->bJackType == MIDI_JACK_EXTERNAL ? "External" : "Embedded"); - } else if (p_mdij->bDescriptorSubType == MIDI_CS_INTERFACE_ELEMENT) { - // the it is an element; - TU_LOG_DRV("Found element\r\n"); - } else { - TU_LOG_DRV(" Unknown CS Interface sub-type %u\r\n", p_mdij->bDescriptorSubType); - TU_VERIFY(false);// unknown CS Interface sub-type - } - len_parsed += p_mdij->bLength; - } else if (p_mdh->bDescriptorType == TUSB_DESC_CS_ENDPOINT) { - TU_LOG_DRV(" CS_ENDPOINT descriptor\r\n"); - TU_VERIFY(prev_ep_addr != 0); - // parse out the mapping between the device's embedded jacks and the endpoints - // Each embedded IN jack is associated with an OUT endpoint - midi_desc_cs_endpoint_t const *p_csep = (midi_desc_cs_endpoint_t const *) p_mdh; - if (tu_edpt_dir(prev_ep_addr) == TUSB_DIR_OUT) { - TU_VERIFY(p_midi->ep_out == prev_ep_addr); - TU_VERIFY(p_midi->num_cables_tx == 0); - p_midi->num_cables_tx = p_csep->bNumEmbMIDIJack; - } else { - TU_VERIFY(p_midi->ep_in == prev_ep_addr); - TU_VERIFY(p_midi->num_cables_rx == 0); - p_midi->num_cables_rx = p_csep->bNumEmbMIDIJack; - } - len_parsed += p_csep->bLength; - prev_ep_addr = 0; - } else if (p_mdh->bDescriptorType == TUSB_DESC_ENDPOINT) { - // parse out the bulk endpoint info - tusb_desc_endpoint_t const *p_ep = (tusb_desc_endpoint_t const *) p_mdh; - TU_LOG_DRV(" Endpoint descriptor %02x\r\n", p_ep->bEndpointAddress); - if (tu_edpt_dir(p_ep->bEndpointAddress) == TUSB_DIR_OUT) { - TU_VERIFY(p_midi->ep_out == 0); - TU_VERIFY(p_midi->num_cables_tx == 0); - p_midi->ep_out = p_ep->bEndpointAddress; - prev_ep_addr = p_midi->ep_out; - out_desc = p_ep; - } else { - TU_VERIFY(p_midi->ep_in == 0); - TU_VERIFY(p_midi->num_cables_rx == 0); - p_midi->ep_in = p_ep->bEndpointAddress; - prev_ep_addr = p_midi->ep_in; - in_desc = p_ep; + + bool found_new_interface = false; + while ((p_desc < p_end) && (tu_desc_next(p_desc) <= p_end) && !found_new_interface) { + switch (tu_desc_type(p_desc)) { + case TUSB_DESC_INTERFACE: + found_new_interface = true; + break; + + case TUSB_DESC_CS_INTERFACE: + switch (tu_desc_subtype(p_desc)) { + case MIDI_CS_INTERFACE_HEADER: + TU_LOG_DRV(" Interface Header descriptor\r\n"); + desc_cb.desc_header = p_desc; + break; + + case MIDI_CS_INTERFACE_IN_JACK: + case MIDI_CS_INTERFACE_OUT_JACK: { + TU_LOG_DRV(" Jack %s %s descriptor \r\n", + tu_desc_subtype(p_desc) == MIDI_CS_INTERFACE_IN_JACK ? "IN" : "OUT", + p_desc[3] == MIDI_JACK_EXTERNAL ? "External" : "Embedded"); + desc_cb.desc_jack[desc_cb.jack_num++] = p_desc; + break; + } + + case MIDI_CS_INTERFACE_ELEMENT: + TU_LOG_DRV(" Element descriptor\r\n"); + desc_cb.desc_element = p_desc; + break; + + default: + TU_LOG_DRV(" Unknown CS Interface sub-type %u\r\n", tu_desc_subtype(p_desc)); + break; + } + break; + + case TUSB_DESC_ENDPOINT: { + tusb_desc_endpoint_t const *p_ep = (tusb_desc_endpoint_t const *) p_desc; + p_desc = tu_desc_next(p_desc); // next to CS endpoint + TU_VERIFY(p_desc < p_end && tu_desc_next(p_desc) <= p_end); + midi_desc_cs_endpoint_t const *p_csep = (midi_desc_cs_endpoint_t const *) p_desc; + + TU_LOG_DRV(" Endpoint and CS_Endpoint descriptor %02x\r\n", p_ep->bEndpointAddress); + if (tu_edpt_dir(p_ep->bEndpointAddress) == TUSB_DIR_OUT) { + p_midi->ep_out = p_ep->bEndpointAddress; + p_midi->num_cables_tx = p_csep->bNumEmbMIDIJack; + desc_cb.desc_epout = p_ep; + + TU_ASSERT(tuh_edpt_open(dev_addr, p_ep)); + tu_edpt_stream_open(&p_midi->ep_stream.tx, p_ep); + } else { + p_midi->ep_in = p_ep->bEndpointAddress; + p_midi->num_cables_rx = p_csep->bNumEmbMIDIJack; + desc_cb.desc_epin = p_ep; + + TU_ASSERT(tuh_edpt_open(dev_addr, p_ep)); + tu_edpt_stream_open(&p_midi->ep_stream.rx, p_ep); + } + break; } - len_parsed += p_mdh->bLength; + + default: break; // skip unknown descriptor } p_desc = tu_desc_next(p_desc); - p_mdh = (midi_desc_header_t const *) p_desc; } - TU_VERIFY((p_midi->ep_out != 0 && p_midi->num_cables_tx != 0) || - (p_midi->ep_in != 0 && p_midi->num_cables_rx != 0)); + desc_cb.desc_interface_len = (uint16_t) ((uintptr_t)p_desc - (uintptr_t) desc_itf); - if (in_desc) { - TU_ASSERT(tuh_edpt_open(dev_addr, in_desc)); - tu_edpt_stream_open(&p_midi->ep_stream.rx, in_desc); - } - if (out_desc) { - TU_ASSERT(tuh_edpt_open(dev_addr, out_desc)); - tu_edpt_stream_open(&p_midi->ep_stream.tx, out_desc); - } p_midi->dev_addr = dev_addr; - // if (tuh_midi_interface_descriptor_cb) { - // tuh_midi_interface_descriptor_cb(dev_addr, desc_itf, ); - // } + if (tuh_midi_descriptor_cb) { + tuh_midi_descriptor_cb(dev_addr, &desc_cb); + } return true; } diff --git a/src/class/midi/midi_host.h b/src/class/midi/midi_host.h index adf41d205..286e034f1 100644 --- a/src/class/midi/midi_host.h +++ b/src/class/midi/midi_host.h @@ -62,6 +62,18 @@ //--------------------------------------------------------------------+ // Application API //--------------------------------------------------------------------+ +typedef struct { + const tusb_desc_interface_t* desc_interface; // start of whole midi interface descriptor + uint16_t desc_interface_len; + + const uint8_t* desc_header; + const uint8_t* desc_element; + const tusb_desc_endpoint_t* desc_epin; // endpoint IN descriptor, CS_ENDPOINT is right after + const tusb_desc_endpoint_t* desc_epout; // endpoint OUT descriptor, CS_ENDPOINT is right after + + uint8_t jack_num; + const uint8_t* desc_jack[16]; // list of jack descriptors (embedded + external) +} tuh_midi_descriptor_cb_t; // Check if MIDI interface is mounted bool tuh_midi_mounted(uint8_t dev_addr); @@ -134,7 +146,7 @@ uint32_t tuh_midi_stream_read (uint8_t dev_addr, uint8_t *p_cable_num, uint8_t * // Invoked when MIDI interface is detected in enumeration. Application can copy/parse descriptor if needed. // Note: may be fired before tuh_midi_mount_cb(), therefore midi interface is not mounted/ready. -// TU_ATTR_WEAK void tuh_midi_interface_descriptor_cb(uint8_t dev_addr, const uint8_t* desc_itf, uint16_t desc_len); +TU_ATTR_WEAK void tuh_midi_descriptor_cb(uint8_t dev_addr, tuh_midi_descriptor_cb_t const* desc_cb); // Invoked when device with MIDI interface is mounted. TU_ATTR_WEAK void tuh_midi_mount_cb(uint8_t dev_addr, uint8_t num_cables_rx, uint16_t num_cables_tx); diff --git a/src/common/tusb_types.h b/src/common/tusb_types.h index 42ce5fc12..95ee489a6 100644 --- a/src/common/tusb_types.h +++ b/src/common/tusb_types.h @@ -281,7 +281,8 @@ typedef enum { // TODO remove enum { DESC_OFFSET_LEN = 0, - DESC_OFFSET_TYPE = 1 + DESC_OFFSET_TYPE = 1, + DESC_OFFSET_SUBTYPE = 2 }; enum { @@ -570,14 +571,19 @@ TU_ATTR_ALWAYS_INLINE static inline uint8_t const * tu_desc_next(void const* des return desc8 + desc8[DESC_OFFSET_LEN]; } +// get descriptor length +TU_ATTR_ALWAYS_INLINE static inline uint8_t tu_desc_len(void const* desc) { + return ((uint8_t const*) desc)[DESC_OFFSET_LEN]; +} + // get descriptor type 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) { - return ((uint8_t const*) desc)[DESC_OFFSET_LEN]; +// get descriptor subtype +TU_ATTR_ALWAYS_INLINE static inline uint8_t tu_desc_subtype(void const* desc) { + return ((uint8_t const*) desc)[DESC_OFFSET_SUBTYPE]; } // find descriptor that match byte1 (type) diff --git a/src/tusb.c b/src/tusb.c index 85ab1d6ae..9303e9bc4 100644 --- a/src/tusb.c +++ b/src/tusb.c @@ -142,7 +142,9 @@ void tusb_int_handler(uint8_t rhport, bool in_isr) { uint8_t const* tu_desc_find(uint8_t const* desc, uint8_t const* end, uint8_t byte1) { while (desc + 1 < end) { - if (desc[1] == byte1) return desc; + if (desc[1] == byte1) { + return desc; + } desc += desc[DESC_OFFSET_LEN]; } return NULL; @@ -150,7 +152,9 @@ uint8_t const* tu_desc_find(uint8_t const* desc, uint8_t const* end, uint8_t byt uint8_t const* tu_desc_find2(uint8_t const* desc, uint8_t const* end, uint8_t byte1, uint8_t byte2) { while (desc + 2 < end) { - if (desc[1] == byte1 && desc[2] == byte2) return desc; + if (desc[1] == byte1 && desc[2] == byte2) { + return desc; + } desc += desc[DESC_OFFSET_LEN]; } return NULL; @@ -158,7 +162,9 @@ uint8_t const* tu_desc_find2(uint8_t const* desc, uint8_t const* end, uint8_t by uint8_t const* tu_desc_find3(uint8_t const* desc, uint8_t const* end, uint8_t byte1, uint8_t byte2, uint8_t byte3) { while (desc + 3 < end) { - if (desc[1] == byte1 && desc[2] == byte2 && desc[3] == byte3) return desc; + if (desc[1] == byte1 && desc[2] == byte2 && desc[3] == byte3) { + return desc; + } desc += desc[DESC_OFFSET_LEN]; } return NULL; -- cgit v1.3.1 From 8c70475c23233e70652c5852088fc539bfb337ad Mon Sep 17 00:00:00 2001 From: hathach Date: Mon, 24 Feb 2025 12:39:02 +0700 Subject: change API to take index instead of dev address, this allow to support more than 1 midi per device. --- examples/host/midi_rx/src/main.c | 48 +++---- src/class/midi/midi_host.c | 277 +++++++++++++++++++++------------------ src/class/midi/midi_host.h | 42 +++--- 3 files changed, 190 insertions(+), 177 deletions(-) (limited to 'src/class') diff --git a/examples/host/midi_rx/src/main.c b/examples/host/midi_rx/src/main.c index 57e9df29e..a8a5b40ca 100644 --- a/examples/host/midi_rx/src/main.c +++ b/examples/host/midi_rx/src/main.c @@ -30,12 +30,9 @@ #include "bsp/board_api.h" #include "tusb.h" -#if CFG_TUH_MIDI - //--------------------------------------------------------------------+ // STATIC GLOBALS DECLARATION //--------------------------------------------------------------------+ -static uint8_t midi_dev_addr = 0; //--------------------------------------------------------------------+ // MACRO CONSTANT TYPEDEF PROTOTYPES @@ -65,8 +62,6 @@ int main(void) { return 0; } -#endif - //--------------------------------------------------------------------+ // Blinking Task //--------------------------------------------------------------------+ @@ -88,13 +83,7 @@ void led_blinking_task(void) { // MIDI host receive task //--------------------------------------------------------------------+ void midi_host_rx_task(void) { - // device must be attached and have at least one endpoint ready to receive a message - if (!midi_dev_addr || !tuh_midi_mounted(midi_dev_addr)) { - return; - } - if (tuh_midi_get_num_rx_cables(midi_dev_addr) < 1) { - return; - } + // nothing to do, we just print out received data in callback } //--------------------------------------------------------------------+ @@ -102,39 +91,32 @@ void midi_host_rx_task(void) { //--------------------------------------------------------------------+ // Invoked when device with MIDI interface is mounted. -void tuh_midi_mount_cb(uint8_t dev_addr, uint8_t num_cables_rx, uint16_t num_cables_tx) { - (void) num_cables_rx; - (void) num_cables_tx; - midi_dev_addr = dev_addr; - TU_LOG1("MIDI device address = %u, Number of RX cables = %u, Number of TX cables = %u\r\n", - dev_addr, num_cables_rx, num_cables_tx); +void tuh_midi_mount_cb(uint8_t idx, uint8_t num_cables_rx, uint16_t num_cables_tx) { + printf("MIDI Interface Index = %u, Number of RX cables = %u, Number of TX cables = %u\r\n", + idx, num_cables_rx, num_cables_tx); } // Invoked when device with hid interface is un-mounted -void tuh_midi_umount_cb(uint8_t dev_addr) { - (void) dev_addr; - midi_dev_addr = 0; - TU_LOG1("MIDI device address = %d is unmounted\r\n", dev_addr); +void tuh_midi_umount_cb(uint8_t idx) { + printf("MIDI Interface Index = %u is unmounted\r\n", idx); } -void tuh_midi_rx_cb(uint8_t dev_addr, uint32_t num_packets) { - if (midi_dev_addr != dev_addr) { - return; - } - +void tuh_midi_rx_cb(uint8_t idx, uint32_t num_packets) { if (num_packets == 0) { return; } uint8_t cable_num; uint8_t buffer[48]; - uint32_t bytes_read = tuh_midi_stream_read(dev_addr, &cable_num, buffer, sizeof(buffer)); - (void) bytes_read; + uint32_t bytes_read = tuh_midi_stream_read(idx, &cable_num, buffer, sizeof(buffer)); - TU_LOG1("Read bytes %lu cable %u", bytes_read, cable_num); - TU_LOG1_MEM(buffer, bytes_read, 2); + printf("Cable %u rx %lu bytes: ", cable_num, bytes_read); + for (uint32_t i = 0; i < bytes_read; i++) { + printf("%02X ", buffer[i]); + } + printf("\r\n"); } -void tuh_midi_tx_cb(uint8_t dev_addr) { - (void) dev_addr; +void tuh_midi_tx_cb(uint8_t idx) { + (void) idx; } diff --git a/src/class/midi/midi_host.c b/src/class/midi/midi_host.c index 2fdf41b9d..8fb325c2b 100644 --- a/src/class/midi/midi_host.c +++ b/src/class/midi/midi_host.c @@ -45,8 +45,9 @@ //--------------------------------------------------------------------+ typedef struct { - uint8_t dev_addr; - uint8_t itf_num; + uint8_t daddr; + uint8_t bInterfaceNumber; // interface number of MIDI streaming + uint8_t itf_count; // number of interface including Audio Control + MIDI streaming uint8_t ep_in; // IN endpoint address uint8_t ep_out; // OUT endpoint address @@ -71,7 +72,7 @@ typedef struct { uint8_t tx_ff_buf[CFG_TUH_MIDI_TX_BUFSIZE]; } ep_stream; - bool configured; + bool mounted; }midih_interface_t; typedef struct { @@ -85,17 +86,24 @@ CFG_TUH_MEM_SECTION static midih_epbuf_t _midi_epbuf[CFG_TUH_MIDI]; //--------------------------------------------------------------------+ // Helper //--------------------------------------------------------------------+ -TU_ATTR_ALWAYS_INLINE static inline midih_interface_t* find_midi_by_daddr(uint8_t dev_addr) { - for (uint8_t i = 0; i < CFG_TUH_MIDI; i++) { - if (_midi_host[i].dev_addr == dev_addr) { - return &_midi_host[i]; +TU_ATTR_ALWAYS_INLINE static inline uint8_t find_new_midi_index(void) { + for (uint8_t idx = 0; idx < CFG_TUH_MIDI; idx++) { + if (_midi_host[idx].daddr == 0) { + return idx; } } - return NULL; + return TUSB_INDEX_INVALID_8; } -TU_ATTR_ALWAYS_INLINE static inline midih_interface_t* find_new_midi(void) { - return find_midi_by_daddr(0); +static inline uint8_t get_idx_by_ep_addr(uint8_t daddr, uint8_t ep_addr) { + for (uint8_t idx = 0; idx < CFG_TUH_MIDI; idx++) { + const midih_interface_t *p_midi = &_midi_host[idx]; + if ((p_midi->daddr == daddr) && + (ep_addr == p_midi->ep_stream.rx.ep_addr || ep_addr == p_midi->ep_stream.tx.ep_addr)) { + return idx; + } + } + return TUSB_INDEX_INVALID_8; } //--------------------------------------------------------------------+ @@ -122,32 +130,38 @@ bool midih_deinit(void) { return true; } -void midih_close(uint8_t dev_addr) { - midih_interface_t *p_midi_host = find_midi_by_daddr(dev_addr); - if (p_midi_host == NULL) { - return; - } - if (tuh_midi_umount_cb) { - tuh_midi_umount_cb(dev_addr); +void midih_close(uint8_t daddr) { + for (uint8_t idx = 0; idx < CFG_TUH_MIDI; idx++) { + midih_interface_t* p_midi = &_midi_host[idx]; + if (p_midi->daddr == daddr) { + TU_LOG_DRV(" MIDI close addr = %u index = %u\r\n", daddr, idx); + + if (tuh_midi_umount_cb) { + tuh_midi_umount_cb(idx); + } + + p_midi->ep_in = 0; + p_midi->ep_out = 0; + p_midi->bInterfaceNumber = 0; + p_midi->num_cables_rx = 0; + p_midi->num_cables_tx = 0; + p_midi->daddr = 0; + p_midi->mounted = false; + tu_memclr(&p_midi->stream_read, sizeof(p_midi->stream_read)); + tu_memclr(&p_midi->stream_write, sizeof(p_midi->stream_write)); + + tu_edpt_stream_close(&p_midi->ep_stream.rx); + tu_edpt_stream_close(&p_midi->ep_stream.tx); + } } - p_midi_host->ep_in = 0; - p_midi_host->ep_out = 0; - p_midi_host->itf_num = 0; - p_midi_host->num_cables_rx = 0; - p_midi_host->num_cables_tx = 0; - p_midi_host->dev_addr = 0; - p_midi_host->configured = false; - tu_memclr(&p_midi_host->stream_read, sizeof(p_midi_host->stream_read)); - tu_memclr(&p_midi_host->stream_write, sizeof(p_midi_host->stream_write)); - - tu_edpt_stream_close(&p_midi_host->ep_stream.rx); - tu_edpt_stream_close(&p_midi_host->ep_stream.tx); } bool midih_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) { (void) result; - midih_interface_t *p_midi_host = find_midi_by_daddr(dev_addr); - TU_VERIFY(p_midi_host != NULL); + const uint8_t idx = get_idx_by_ep_addr(dev_addr, ep_addr); + TU_VERIFY(idx < CFG_TUH_MIDI); + midih_interface_t *p_midi_host = &_midi_host[idx]; + if (ep_addr == p_midi_host->ep_stream.rx.ep_addr) { // receive new data if available if (xferred_bytes) { @@ -167,14 +181,14 @@ bool midih_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, uint } if (tuh_midi_rx_cb) { - tuh_midi_rx_cb(dev_addr, packets_queued); // invoke receive callback + tuh_midi_rx_cb(idx, packets_queued); } } tu_edpt_stream_read_xfer(dev_addr, &p_midi_host->ep_stream.rx); // prepare for next transfer } else if (ep_addr == p_midi_host->ep_stream.tx.ep_addr) { if (tuh_midi_tx_cb) { - tuh_midi_tx_cb(dev_addr); + tuh_midi_tx_cb(idx); } if (0 == tu_edpt_stream_write_xfer(dev_addr, &p_midi_host->ep_stream.tx)) { // If there is no data left, a ZLP should be sent if @@ -192,19 +206,20 @@ bool midih_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, uint bool midih_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *desc_itf, uint16_t max_len) { (void) rhport; - midih_interface_t *p_midi = find_new_midi(); - TU_VERIFY(p_midi != NULL); TU_VERIFY(TUSB_CLASS_AUDIO == desc_itf->bInterfaceClass); - - // There can be just a MIDI or an Audio + MIDI interface // const uint8_t* p_start = ((uint8_t const*) desc_itf); - const uint8_t* p_end = ((uint8_t const*) desc_itf) + max_len; - uint8_t const *p_desc = (uint8_t const *) desc_itf; - uint16_t len_parsed = 0; + const uint8_t *p_end = ((const uint8_t *) desc_itf) + max_len; + const uint8_t *p_desc = (const uint8_t *) desc_itf; + + const uint8_t idx = find_new_midi_index(); + TU_VERIFY(idx < CFG_TUH_MIDI); + midih_interface_t *p_midi = &_midi_host[idx]; + p_midi->itf_count = 0; tuh_midi_descriptor_cb_t desc_cb = { 0 }; desc_cb.jack_num = 0; + // There can be just a MIDI or an Audio + MIDI interface // If there is Audio Control Interface + Audio Header descriptor, skip it if (AUDIO_SUBCLASS_CONTROL == desc_itf->bInterfaceSubClass) { TU_VERIFY(max_len > 2*sizeof(tusb_desc_interface_t) + sizeof(audio_desc_cs_ac_interface_t)); @@ -216,15 +231,16 @@ bool midih_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *d p_desc = tu_desc_next(p_desc); desc_itf = (tusb_desc_interface_t const *)p_desc; TU_VERIFY(TUSB_CLASS_AUDIO == desc_itf->bInterfaceClass); + p_midi->itf_count = 1; } TU_VERIFY(AUDIO_SUBCLASS_MIDI_STREAMING == desc_itf->bInterfaceSubClass); - desc_cb.desc_interface = desc_itf; - - len_parsed += desc_itf->bLength; TU_LOG_DRV("MIDI opening Interface %u (addr = %u)\r\n", desc_itf->bInterfaceNumber, dev_addr); - p_midi->itf_num = desc_itf->bInterfaceNumber; - p_desc = tu_desc_next(p_desc); + p_midi->bInterfaceNumber = desc_itf->bInterfaceNumber; + p_midi->itf_count++; + desc_cb.desc_interface = desc_itf; + + p_desc = tu_desc_next(p_desc); // next to CS Header bool found_new_interface = false; while ((p_desc < p_end) && (tu_desc_next(p_desc) <= p_end) && !found_new_interface) { @@ -291,102 +307,115 @@ bool midih_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *d } desc_cb.desc_interface_len = (uint16_t) ((uintptr_t)p_desc - (uintptr_t) desc_itf); - p_midi->dev_addr = dev_addr; + p_midi->daddr = dev_addr; if (tuh_midi_descriptor_cb) { - tuh_midi_descriptor_cb(dev_addr, &desc_cb); + tuh_midi_descriptor_cb(idx, &desc_cb); } return true; } bool midih_set_config(uint8_t dev_addr, uint8_t itf_num) { - (void) itf_num; - midih_interface_t *p_midi_host = find_midi_by_daddr(dev_addr); - TU_VERIFY(p_midi_host != NULL); - p_midi_host->configured = true; + uint8_t idx = tuh_midi_itf_get_index(dev_addr, itf_num); + TU_ASSERT(idx < CFG_TUH_MIDI); + midih_interface_t *p_midi = &_midi_host[idx]; + p_midi->mounted = true; if (tuh_midi_mount_cb) { - tuh_midi_mount_cb(dev_addr, p_midi_host->num_cables_rx, p_midi_host->num_cables_tx); + tuh_midi_mount_cb(idx, p_midi->num_cables_rx, p_midi->num_cables_tx); } - tu_edpt_stream_read_xfer(dev_addr, &p_midi_host->ep_stream.rx); // prepare for incoming data + tu_edpt_stream_read_xfer(dev_addr, &p_midi->ep_stream.rx); // prepare for incoming data // No special config things to do for MIDI - usbh_driver_set_config_complete(dev_addr, p_midi_host->itf_num); + usbh_driver_set_config_complete(dev_addr, p_midi->bInterfaceNumber); return true; } //--------------------------------------------------------------------+ // API //--------------------------------------------------------------------+ -bool tuh_midi_mounted(uint8_t dev_addr) { - midih_interface_t *p_midi_host = find_midi_by_daddr(dev_addr); - TU_VERIFY(p_midi_host != NULL); - return p_midi_host->configured; +bool tuh_midi_mounted(uint8_t idx) { + TU_VERIFY(idx < CFG_TUH_MIDI); + midih_interface_t *p_midi = &_midi_host[idx]; + return p_midi->mounted; +} + +uint8_t tuh_midi_itf_get_index(uint8_t daddr, uint8_t itf_num) { + for (uint8_t idx = 0; idx < CFG_TUH_MIDI; idx++) { + const midih_interface_t *p_midi = &_midi_host[idx]; + if (p_midi->daddr == daddr && + (p_midi->bInterfaceNumber == itf_num || + p_midi->bInterfaceNumber == (uint8_t) (itf_num + p_midi->itf_count - 1))) { + return idx; + } + } + return TUSB_INDEX_INVALID_8; } -uint8_t tuh_midi_get_num_tx_cables (uint8_t dev_addr) { - midih_interface_t *p_midi_host = find_midi_by_daddr(dev_addr); - TU_VERIFY(p_midi_host != NULL, 0); - TU_VERIFY(p_midi_host->ep_stream.tx.ep_addr != 0, 0); - return p_midi_host->num_cables_tx; +uint8_t tuh_midi_get_num_tx_cables (uint8_t idx) { + TU_VERIFY(idx < CFG_TUH_MIDI); + midih_interface_t *p_midi = &_midi_host[idx]; + TU_VERIFY(p_midi->ep_stream.tx.ep_addr != 0, 0); + return p_midi->num_cables_tx; } -uint8_t tuh_midi_get_num_rx_cables (uint8_t dev_addr) { - midih_interface_t *p_midi_host = find_midi_by_daddr(dev_addr); - TU_VERIFY(p_midi_host != NULL, 0); - TU_VERIFY(p_midi_host->ep_stream.rx.ep_addr != 0, 0); - return p_midi_host->num_cables_rx; +uint8_t tuh_midi_get_num_rx_cables (uint8_t idx) { + TU_VERIFY(idx < CFG_TUH_MIDI); + midih_interface_t *p_midi = &_midi_host[idx]; + TU_VERIFY(p_midi->ep_stream.rx.ep_addr != 0, 0); + return p_midi->num_cables_rx; } -uint32_t tuh_midi_read_available(uint8_t dev_addr) { - midih_interface_t *p_midi_host = find_midi_by_daddr(dev_addr); - TU_VERIFY(p_midi_host != NULL); - return tu_edpt_stream_read_available(&p_midi_host->ep_stream.rx); +uint32_t tuh_midi_read_available(uint8_t idx) { + TU_VERIFY(idx < CFG_TUH_MIDI); + midih_interface_t *p_midi = &_midi_host[idx]; + return tu_edpt_stream_read_available(&p_midi->ep_stream.rx); } -uint32_t tuh_midi_write_flush(uint8_t dev_addr) { - midih_interface_t *p_midi = find_midi_by_daddr(dev_addr); - TU_VERIFY(p_midi != NULL); - return tu_edpt_stream_write_xfer(p_midi->dev_addr, &p_midi->ep_stream.tx); +uint32_t tuh_midi_write_flush(uint8_t idx) { + TU_VERIFY(idx < CFG_TUH_MIDI); + midih_interface_t *p_midi = &_midi_host[idx]; + return tu_edpt_stream_write_xfer(p_midi->daddr, &p_midi->ep_stream.tx); } //--------------------------------------------------------------------+ // Packet API //--------------------------------------------------------------------+ +uint32_t tuh_midi_packet_read_n(uint8_t idx, uint8_t* buffer, uint32_t bufsize) { + TU_VERIFY(idx < CFG_TUH_MIDI && buffer && bufsize > 0, 0); + midih_interface_t *p_midi = &_midi_host[idx]; -uint32_t tuh_midi_packet_read_n(uint8_t dev_addr, uint8_t* buffer, uint32_t bufsize) { - midih_interface_t *p_midi_host = find_midi_by_daddr(dev_addr); - TU_VERIFY(p_midi_host != NULL); - - uint32_t count4 = tu_min32(bufsize, tu_edpt_stream_read_available(&p_midi_host->ep_stream.rx)); + uint32_t count4 = tu_min32(bufsize, tu_edpt_stream_read_available(&p_midi->ep_stream.rx)); count4 = tu_align4(count4); // round down to multiple of 4 TU_VERIFY(count4 > 0, 0); - return tu_edpt_stream_read(dev_addr, &p_midi_host->ep_stream.rx, buffer, count4); + return tu_edpt_stream_read(p_midi->daddr, &p_midi->ep_stream.rx, buffer, count4); } -uint32_t tuh_midi_packet_write_n(uint8_t dev_addr, const uint8_t* buffer, uint32_t bufsize) { - midih_interface_t *p_midi_host = find_midi_by_daddr(dev_addr); - TU_VERIFY(p_midi_host != NULL, 0); - uint32_t bufsize4 = tu_align4(bufsize); - return tu_edpt_stream_write(dev_addr, &p_midi_host->ep_stream.tx, buffer, bufsize4); +uint32_t tuh_midi_packet_write_n(uint8_t idx, const uint8_t* buffer, uint32_t bufsize) { + TU_VERIFY(idx < CFG_TUH_MIDI && buffer && bufsize > 0, 0); + midih_interface_t *p_midi = &_midi_host[idx]; + + const uint32_t bufsize4 = tu_align4(bufsize); + TU_VERIFY(bufsize4 > 0, 0); + return tu_edpt_stream_write(p_midi->daddr, &p_midi->ep_stream.tx, buffer, bufsize4); } //--------------------------------------------------------------------+ // Stream API //--------------------------------------------------------------------+ #if CFG_TUH_MIDI_STREAM_API -uint32_t tuh_midi_stream_write(uint8_t dev_addr, uint8_t cable_num, uint8_t const *buffer, uint32_t bufsize) { - midih_interface_t *p_midi_host = find_midi_by_daddr(dev_addr); - TU_VERIFY(p_midi_host != NULL); - TU_VERIFY(cable_num < p_midi_host->num_cables_tx); - midi_driver_stream_t *stream = &p_midi_host->stream_write; - - uint32_t i = 0; - while ((i < bufsize) && (tu_edpt_stream_write_available(dev_addr, &p_midi_host->ep_stream.tx) >= 4)) { - uint8_t const data = buffer[i]; - i++; +uint32_t tuh_midi_stream_write(uint8_t idx, uint8_t cable_num, uint8_t const *buffer, uint32_t bufsize) { + TU_VERIFY(idx < CFG_TUH_MIDI && buffer && bufsize > 0); + midih_interface_t *p_midi = &_midi_host[idx]; + TU_VERIFY(cable_num < p_midi->num_cables_tx); + midi_driver_stream_t *stream = &p_midi->stream_write; + + uint32_t byte_count = 0; + while ((byte_count < bufsize) && (tu_edpt_stream_write_available(p_midi->daddr, &p_midi->ep_stream.tx) >= 4)) { + uint8_t const data = buffer[byte_count]; + byte_count++; if (data >= MIDI_STATUS_SYSREAL_TIMING_CLOCK) { // real-time messages need to be sent right away midi_driver_stream_t streamrt; @@ -394,8 +423,8 @@ uint32_t tuh_midi_stream_write(uint8_t dev_addr, uint8_t cable_num, uint8_t cons streamrt.buffer[1] = data; streamrt.index = 2; streamrt.total = 2; - uint32_t const count = tu_edpt_stream_write(dev_addr, &p_midi_host->ep_stream.tx, streamrt.buffer, 4); - TU_ASSERT(count == 4, i); // Check FIFO overflown, since we already check fifo remaining. It is probably race condition + uint32_t const count = tu_edpt_stream_write(p_midi->daddr, &p_midi->ep_stream.tx, streamrt.buffer, 4); + TU_ASSERT(count == 4, byte_count); // Check FIFO overflown, since we already check fifo remaining. It is probably race condition } else if (stream->index == 0) { //------------- New event packet -------------// @@ -445,7 +474,7 @@ uint32_t tuh_midi_stream_write(uint8_t dev_addr, uint8_t cable_num, uint8_t cons } } else { //------------- On-going (buffering) packet -------------// - TU_ASSERT(stream->index < 4, i); + TU_ASSERT(stream->index < 4, byte_count); stream->buffer[stream->index] = data; stream->index++; // See if this byte ends a SysEx. @@ -458,42 +487,41 @@ uint32_t tuh_midi_stream_write(uint8_t dev_addr, uint8_t cable_num, uint8_t cons // Send out packet if (stream->index >= 2 && stream->index == stream->total) { // zeroes unused bytes - for (uint8_t idx = stream->total; idx < 4; idx++) { stream->buffer[idx] = 0; } + for (uint8_t i = stream->total; i < 4; i++) { + stream->buffer[i] = 0; + } TU_LOG3_MEM(stream->buffer, 4, 2); - uint32_t const count = tu_edpt_stream_write(dev_addr, &p_midi_host->ep_stream.tx, stream->buffer, 4); + const uint32_t count = tu_edpt_stream_write(p_midi->daddr, &p_midi->ep_stream.tx, stream->buffer, 4); // complete current event packet, reset stream stream->index = 0; stream->total = 0; // FIFO overflown, since we already check fifo remaining. It is probably race condition - TU_ASSERT(count == 4, i); + TU_ASSERT(count == 4, byte_count); } } - return i; + return byte_count; } -uint32_t tuh_midi_stream_read(uint8_t dev_addr, uint8_t *p_cable_num, uint8_t *p_buffer, uint16_t bufsize) { - midih_interface_t *p_midi_host = find_midi_by_daddr(dev_addr); - TU_VERIFY(p_midi_host != NULL); +uint32_t tuh_midi_stream_read(uint8_t idx, uint8_t *p_cable_num, uint8_t *p_buffer, uint16_t bufsize) { + TU_VERIFY(idx < CFG_TUH_MIDI && p_cable_num && p_buffer && bufsize > 0); + midih_interface_t *p_midi = &_midi_host[idx]; uint32_t bytes_buffered = 0; - TU_ASSERT(p_cable_num); - TU_ASSERT(p_buffer); - TU_ASSERT(bufsize); uint8_t one_byte; - if (!tu_edpt_stream_peek(&p_midi_host->ep_stream.rx, &one_byte)) { + if (!tu_edpt_stream_peek(&p_midi->ep_stream.rx, &one_byte)) { return 0; } *p_cable_num = (one_byte >> 4) & 0xf; - uint32_t nread = tu_edpt_stream_read(dev_addr, &p_midi_host->ep_stream.rx, p_midi_host->stream_read.buffer, 4); - static uint16_t cable_sysex_in_progress; // bit i is set if received MIDI_STATUS_SYSEX_START but not MIDI_STATUS_SYSEX_END + uint32_t nread = tu_edpt_stream_read(p_midi->daddr, &p_midi->ep_stream.rx, p_midi->stream_read.buffer, 4); + static uint16_t cable_sysex_in_progress;// bit i is set if received MIDI_STATUS_SYSEX_START but not MIDI_STATUS_SYSEX_END while (nread == 4 && bytes_buffered < bufsize) { - *p_cable_num = (p_midi_host->stream_read.buffer[0] >> 4) & 0x0f; + *p_cable_num = (p_midi->stream_read.buffer[0] >> 4) & 0x0f; uint8_t bytes_to_add_to_stream = 0; - if (*p_cable_num < p_midi_host->num_cables_rx) { + if (*p_cable_num < p_midi->num_cables_rx) { // ignore the CIN field; too many devices out there encode this wrong - uint8_t status = p_midi_host->stream_read.buffer[1]; + uint8_t status = p_midi->stream_read.buffer[1]; uint16_t cable_mask = (uint16_t) (1 << *p_cable_num); if (status <= MIDI_MAX_DATA_VAL || status == MIDI_STATUS_SYSEX_START) { if (status == MIDI_STATUS_SYSEX_START) { @@ -502,13 +530,13 @@ uint32_t tuh_midi_stream_read(uint8_t dev_addr, uint8_t *p_cable_num, uint8_t *p // only add the packet if a sysex message is in progress if (cable_sysex_in_progress & cable_mask) { ++bytes_to_add_to_stream; - for (uint8_t idx = 2; idx < 4; idx++) { - if (p_midi_host->stream_read.buffer[idx] <= MIDI_MAX_DATA_VAL) { + for (uint8_t i = 2; i < 4; i++) { + if (p_midi->stream_read.buffer[i] <= MIDI_MAX_DATA_VAL) { ++bytes_to_add_to_stream; - } else if (p_midi_host->stream_read.buffer[idx] == MIDI_STATUS_SYSEX_END) { + } else if (p_midi->stream_read.buffer[i] == MIDI_STATUS_SYSEX_END) { ++bytes_to_add_to_stream; cable_sysex_in_progress &= (uint16_t) ~cable_mask; - idx = 4;// force the loop to exit; I hate break statements in loops + i = 4;// force the loop to exit; I hate break statements in loops } } } @@ -555,23 +583,22 @@ uint32_t tuh_midi_stream_read(uint8_t dev_addr, uint8_t *p_cable_num, uint8_t *p } } - for (uint8_t idx = 1; idx <= bytes_to_add_to_stream; idx++) { - *p_buffer++ = p_midi_host->stream_read.buffer[idx]; + for (uint8_t i = 1; i <= bytes_to_add_to_stream; i++) { + *p_buffer++ = p_midi->stream_read.buffer[i]; } bytes_buffered += bytes_to_add_to_stream; nread = 0; - if (tu_edpt_stream_peek(&p_midi_host->ep_stream.rx, &one_byte)) { + if (tu_edpt_stream_peek(&p_midi->ep_stream.rx, &one_byte)) { uint8_t new_cable = (one_byte >> 4) & 0xf; if (new_cable == *p_cable_num) { // still on the same cable. Continue reading the stream - nread = tu_edpt_stream_read(dev_addr, &p_midi_host->ep_stream.rx, p_midi_host->stream_read.buffer, 4); + nread = tu_edpt_stream_read(p_midi->daddr, &p_midi->ep_stream.rx, p_midi->stream_read.buffer, 4); } } } return bytes_buffered; } - #endif #endif diff --git a/src/class/midi/midi_host.h b/src/class/midi/midi_host.h index 286e034f1..c9780a9e4 100644 --- a/src/class/midi/midi_host.h +++ b/src/class/midi/midi_host.h @@ -76,22 +76,26 @@ typedef struct { } tuh_midi_descriptor_cb_t; // Check if MIDI interface is mounted -bool tuh_midi_mounted(uint8_t dev_addr); +bool tuh_midi_mounted(uint8_t idx); + +// Get Interface index from device address + interface number +// return TUSB_INDEX_INVALID_8 (0xFF) if not found +uint8_t tuh_midi_itf_get_index(uint8_t daddr, uint8_t itf_num); // return the number of virtual midi cables on the device's IN endpoint -uint8_t tuh_midi_get_num_rx_cables(uint8_t dev_addr); +uint8_t tuh_midi_get_num_rx_cables(uint8_t idx); // return the number of virtual midi cables on the device's OUT endpoint -uint8_t tuh_midi_get_num_tx_cables(uint8_t dev_addr); +uint8_t tuh_midi_get_num_tx_cables(uint8_t idx); // return the raw number of bytes available. // Note: this is related but not the same as number of stream bytes available. -uint32_t tuh_midi_read_available(uint8_t dev_addr); +uint32_t tuh_midi_read_available(uint8_t idx); // Send any queued packets to the device if the host hardware is able to do it // Returns the number of bytes flushed to the host hardware or 0 if // the host hardware is busy or there is nothing in queue to send. -uint32_t tuh_midi_write_flush( uint8_t dev_addr); +uint32_t tuh_midi_write_flush(uint8_t idx); //--------------------------------------------------------------------+ // Packet API @@ -99,24 +103,24 @@ uint32_t tuh_midi_write_flush( uint8_t dev_addr); // Read all available MIDI packets from the connected device // Return number of bytes read (always multiple of 4) -uint32_t tuh_midi_packet_read_n(uint8_t dev_addr, uint8_t* buffer, uint32_t bufsize); +uint32_t tuh_midi_packet_read_n(uint8_t idx, uint8_t* buffer, uint32_t bufsize); // Read a raw MIDI packet from the connected device // Return true if a packet was returned TU_ATTR_ALWAYS_INLINE static inline -bool tuh_midi_packet_read (uint8_t dev_addr, uint8_t packet[4]) { - return 4 == tuh_midi_packet_read_n(dev_addr, packet, 4); +bool tuh_midi_packet_read (uint8_t idx, uint8_t packet[4]) { + return 4 == tuh_midi_packet_read_n(idx, packet, 4); } // Write all 4-byte packets, data is locally buffered and only transferred when buffered bytes // reach the endpoint packet size or tuh_midi_write_flush() is called -uint32_t tuh_midi_packet_write_n(uint8_t dev_addr, const uint8_t* buffer, uint32_t bufsize); +uint32_t tuh_midi_packet_write_n(uint8_t idx, const uint8_t* buffer, uint32_t bufsize); // Write a 4-bytes packet to the device. // Returns true if the packet was successfully queued. TU_ATTR_ALWAYS_INLINE static inline -bool tuh_midi_packet_write (uint8_t dev_addr, uint8_t const packet[4]) { - return 4 == tuh_midi_packet_write_n(dev_addr, packet, 4); +bool tuh_midi_packet_write (uint8_t idx, uint8_t const packet[4]) { + return 4 == tuh_midi_packet_write_n(idx, packet, 4); } //--------------------------------------------------------------------+ @@ -127,7 +131,7 @@ bool tuh_midi_packet_write (uint8_t dev_addr, uint8_t const packet[4]) { // Queue a message to the device using stream API. data is locally buffered and only transferred when buffered bytes // reach the endpoint packet size or tuh_midi_write_flush() is called // Returns number of bytes was successfully queued. -uint32_t tuh_midi_stream_write (uint8_t dev_addr, uint8_t cable_num, uint8_t const* p_buffer, uint32_t bufsize); +uint32_t tuh_midi_stream_write(uint8_t idx, uint8_t cable_num, uint8_t const *p_buffer, uint32_t bufsize); // Get the MIDI stream from the device. Set the value pointed // to by p_cable_num to the MIDI cable number intended to receive it. @@ -136,7 +140,7 @@ uint32_t tuh_midi_stream_write (uint8_t dev_addr, uint8_t cable_num, uint8_t con // Note that this function ignores the CIN field of the MIDI packet // because a number of commercial devices out there do not encode // it properly. -uint32_t tuh_midi_stream_read (uint8_t dev_addr, uint8_t *p_cable_num, uint8_t *p_buffer, uint16_t bufsize); +uint32_t tuh_midi_stream_read(uint8_t idx, uint8_t *p_cable_num, uint8_t *p_buffer, uint16_t bufsize); #endif @@ -146,16 +150,16 @@ uint32_t tuh_midi_stream_read (uint8_t dev_addr, uint8_t *p_cable_num, uint8_t * // Invoked when MIDI interface is detected in enumeration. Application can copy/parse descriptor if needed. // Note: may be fired before tuh_midi_mount_cb(), therefore midi interface is not mounted/ready. -TU_ATTR_WEAK void tuh_midi_descriptor_cb(uint8_t dev_addr, tuh_midi_descriptor_cb_t const* desc_cb); +TU_ATTR_WEAK void tuh_midi_descriptor_cb(uint8_t idx, const tuh_midi_descriptor_cb_t * desc_cb); // Invoked when device with MIDI interface is mounted. -TU_ATTR_WEAK void tuh_midi_mount_cb(uint8_t dev_addr, uint8_t num_cables_rx, uint16_t num_cables_tx); +TU_ATTR_WEAK void tuh_midi_mount_cb(uint8_t idx, uint8_t num_cables_rx, uint16_t num_cables_tx); // Invoked when device with MIDI interface is un-mounted -TU_ATTR_WEAK void tuh_midi_umount_cb(uint8_t dev_addr); +TU_ATTR_WEAK void tuh_midi_umount_cb(uint8_t idx); -TU_ATTR_WEAK void tuh_midi_rx_cb(uint8_t dev_addr, uint32_t num_packets); -TU_ATTR_WEAK void tuh_midi_tx_cb(uint8_t dev_addr); +TU_ATTR_WEAK void tuh_midi_rx_cb(uint8_t idx, uint32_t num_packets); +TU_ATTR_WEAK void tuh_midi_tx_cb(uint8_t idx); //--------------------------------------------------------------------+ // Internal Class Driver API @@ -165,7 +169,7 @@ bool midih_deinit (void); bool midih_open (uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *desc_itf, uint16_t max_len); bool midih_set_config (uint8_t dev_addr, uint8_t itf_num); bool midih_xfer_cb (uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes); -void midih_close (uint8_t dev_addr); +void midih_close (uint8_t daddr); #ifdef __cplusplus } -- cgit v1.3.1 From 56e84bd1a605e3835f29e2e7fd17f65e0f3b5431 Mon Sep 17 00:00:00 2001 From: hathach Date: Mon, 24 Feb 2025 12:42:45 +0700 Subject: add desc_audio_control to midi descriptor callback --- examples/host/midi_rx/src/main.c | 2 +- examples/host/midi_rx/src/tusb_config.h | 2 -- src/class/midi/midi_host.c | 7 ++++--- src/class/midi/midi_host.h | 5 +++-- 4 files changed, 8 insertions(+), 8 deletions(-) (limited to 'src/class') diff --git a/examples/host/midi_rx/src/main.c b/examples/host/midi_rx/src/main.c index a8a5b40ca..6db329ab5 100644 --- a/examples/host/midi_rx/src/main.c +++ b/examples/host/midi_rx/src/main.c @@ -106,8 +106,8 @@ void tuh_midi_rx_cb(uint8_t idx, uint32_t num_packets) { return; } - uint8_t cable_num; uint8_t buffer[48]; + uint8_t cable_num = 0; uint32_t bytes_read = tuh_midi_stream_read(idx, &cable_num, buffer, sizeof(buffer)); printf("Cable %u rx %lu bytes: ", cable_num, bytes_read); diff --git a/examples/host/midi_rx/src/tusb_config.h b/examples/host/midi_rx/src/tusb_config.h index 24b3b3ae6..c9b430388 100644 --- a/examples/host/midi_rx/src/tusb_config.h +++ b/examples/host/midi_rx/src/tusb_config.h @@ -111,8 +111,6 @@ extern "C" { #define CFG_TUH_DEVICE_MAX (3*CFG_TUH_HUB + 1) #define CFG_TUH_MIDI CFG_TUH_DEVICE_MAX -#define CFG_MIDI_HOST_DEVSTRINGS 1 - #ifdef __cplusplus } #endif diff --git a/src/class/midi/midi_host.c b/src/class/midi/midi_host.c index 8fb325c2b..770a39a8d 100644 --- a/src/class/midi/midi_host.c +++ b/src/class/midi/midi_host.c @@ -227,9 +227,10 @@ bool midih_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *d p_desc = tu_desc_next(p_desc); TU_VERIFY(tu_desc_type(p_desc) == TUSB_DESC_CS_INTERFACE && tu_desc_subtype(p_desc) == AUDIO_CS_AC_INTERFACE_HEADER); + desc_cb.desc_audio_control = desc_itf; p_desc = tu_desc_next(p_desc); - desc_itf = (tusb_desc_interface_t const *)p_desc; + desc_itf = (const tusb_desc_interface_t *)p_desc; TU_VERIFY(TUSB_CLASS_AUDIO == desc_itf->bInterfaceClass); p_midi->itf_count = 1; } @@ -238,7 +239,7 @@ bool midih_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *d TU_LOG_DRV("MIDI opening Interface %u (addr = %u)\r\n", desc_itf->bInterfaceNumber, dev_addr); p_midi->bInterfaceNumber = desc_itf->bInterfaceNumber; p_midi->itf_count++; - desc_cb.desc_interface = desc_itf; + desc_cb.desc_midi = desc_itf; p_desc = tu_desc_next(p_desc); // next to CS Header @@ -305,7 +306,7 @@ bool midih_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *d } p_desc = tu_desc_next(p_desc); } - desc_cb.desc_interface_len = (uint16_t) ((uintptr_t)p_desc - (uintptr_t) desc_itf); + desc_cb.desc_midi_total_len = (uint16_t) ((uintptr_t)p_desc - (uintptr_t) desc_itf); p_midi->daddr = dev_addr; diff --git a/src/class/midi/midi_host.h b/src/class/midi/midi_host.h index c9780a9e4..717e6ba67 100644 --- a/src/class/midi/midi_host.h +++ b/src/class/midi/midi_host.h @@ -63,8 +63,9 @@ // Application API //--------------------------------------------------------------------+ typedef struct { - const tusb_desc_interface_t* desc_interface; // start of whole midi interface descriptor - uint16_t desc_interface_len; + const tusb_desc_interface_t* desc_audio_control; + const tusb_desc_interface_t* desc_midi; // start of whole midi interface descriptor + uint16_t desc_midi_total_len; const uint8_t* desc_header; const uint8_t* desc_element; -- cgit v1.3.1 From d132044b7587f7e846bbec6e7b897d0842a21d13 Mon Sep 17 00:00:00 2001 From: hathach Date: Mon, 24 Feb 2025 15:40:48 +0700 Subject: add tuh_midi_mount_cb_t struct for tuh_midi_mount_cb() change tuh_midi_rx/tx_cb() to have xferred_bytes rename tuh_midi_get_num_rx/tx_cables() to tuh_midi_get_rx/tx_cable_count() use default empty callback instead of weak null to be compatible with keil compiler --- examples/host/cdc_msc_hid/src/main.c | 4 +- examples/host/midi_rx/src/main.c | 13 +++--- src/class/cdc/cdc_host.h | 8 ++-- src/class/midi/midi_device.c | 5 --- src/class/midi/midi_host.c | 81 ++++++++++++++++-------------------- src/class/midi/midi_host.h | 34 +++++++++------ src/host/usbh_pvt.h | 4 -- 7 files changed, 70 insertions(+), 79 deletions(-) (limited to 'src/class') diff --git a/examples/host/cdc_msc_hid/src/main.c b/examples/host/cdc_msc_hid/src/main.c index 71257c0fe..2d5df23f9 100644 --- a/examples/host/cdc_msc_hid/src/main.c +++ b/examples/host/cdc_msc_hid/src/main.c @@ -82,12 +82,12 @@ int main(void) { void tuh_mount_cb(uint8_t dev_addr) { // application set-up - printf("A device with address %d is mounted\r\n", dev_addr); + printf("A device with address %u is mounted\r\n", dev_addr); } void tuh_umount_cb(uint8_t dev_addr) { // application tear-down - printf("A device with address %d is unmounted \r\n", dev_addr); + printf("A device with address %u is unmounted \r\n", dev_addr); } diff --git a/examples/host/midi_rx/src/main.c b/examples/host/midi_rx/src/main.c index 6db329ab5..d26321e5d 100644 --- a/examples/host/midi_rx/src/main.c +++ b/examples/host/midi_rx/src/main.c @@ -91,9 +91,9 @@ void midi_host_rx_task(void) { //--------------------------------------------------------------------+ // Invoked when device with MIDI interface is mounted. -void tuh_midi_mount_cb(uint8_t idx, uint8_t num_cables_rx, uint16_t num_cables_tx) { - printf("MIDI Interface Index = %u, Number of RX cables = %u, Number of TX cables = %u\r\n", - idx, num_cables_rx, num_cables_tx); +void tuh_midi_mount_cb(uint8_t idx, const tuh_midi_mount_cb_t* mount_cb_data) { + printf("MIDI Interface Index = %u, Address = %u, Number of RX cables = %u, Number of TX cables = %u\r\n", + idx, mount_cb_data->daddr, mount_cb_data->rx_cable_count, mount_cb_data->tx_cable_count); } // Invoked when device with hid interface is un-mounted @@ -101,8 +101,8 @@ void tuh_midi_umount_cb(uint8_t idx) { printf("MIDI Interface Index = %u is unmounted\r\n", idx); } -void tuh_midi_rx_cb(uint8_t idx, uint32_t num_packets) { - if (num_packets == 0) { +void tuh_midi_rx_cb(uint8_t idx, uint32_t xferred_bytes) { + if (xferred_bytes == 0) { return; } @@ -117,6 +117,7 @@ void tuh_midi_rx_cb(uint8_t idx, uint32_t num_packets) { printf("\r\n"); } -void tuh_midi_tx_cb(uint8_t idx) { +void tuh_midi_tx_cb(uint8_t idx, uint32_t xferred_bytes) { (void) idx; + (void) xferred_bytes; } diff --git a/src/class/cdc/cdc_host.h b/src/class/cdc/cdc_host.h index df975b2f0..8c5399534 100644 --- a/src/class/cdc/cdc_host.h +++ b/src/class/cdc/cdc_host.h @@ -49,22 +49,22 @@ // RX FIFO size #ifndef CFG_TUH_CDC_RX_BUFSIZE -#define CFG_TUH_CDC_RX_BUFSIZE USBH_EPSIZE_BULK_MAX +#define CFG_TUH_CDC_RX_BUFSIZE TUH_EPSIZE_BULK_MPS #endif // RX Endpoint size #ifndef CFG_TUH_CDC_RX_EPSIZE -#define CFG_TUH_CDC_RX_EPSIZE USBH_EPSIZE_BULK_MAX +#define CFG_TUH_CDC_RX_EPSIZE TUH_EPSIZE_BULK_MPS #endif // TX FIFO size #ifndef CFG_TUH_CDC_TX_BUFSIZE -#define CFG_TUH_CDC_TX_BUFSIZE USBH_EPSIZE_BULK_MAX +#define CFG_TUH_CDC_TX_BUFSIZE TUH_EPSIZE_BULK_MPS #endif // TX Endpoint size #ifndef CFG_TUH_CDC_TX_EPSIZE -#define CFG_TUH_CDC_TX_EPSIZE USBH_EPSIZE_BULK_MAX +#define CFG_TUH_CDC_TX_EPSIZE TUH_EPSIZE_BULK_MPS #endif //--------------------------------------------------------------------+ diff --git a/src/class/midi/midi_device.c b/src/class/midi/midi_device.c index 7b6705640..0bbb3caf4 100644 --- a/src/class/midi/midi_device.c +++ b/src/class/midi/midi_device.c @@ -39,9 +39,6 @@ //--------------------------------------------------------------------+ // MACRO CONSTANT TYPEDEF //--------------------------------------------------------------------+ - - - typedef struct { uint8_t itf_num; uint8_t ep_in; @@ -440,8 +437,6 @@ uint16_t midid_open(uint8_t rhport, const tusb_desc_interface_t* desc_itf, uint1 drv_len += tu_desc_len(p_desc); p_desc = tu_desc_next(p_desc); } - } else { - TU_LOG2("Warning: MIDI Device has no Audio Control Interface"); } // 2nd Interface is MIDI Streaming diff --git a/src/class/midi/midi_host.c b/src/class/midi/midi_host.c index 770a39a8d..a4b1ebd2e 100644 --- a/src/class/midi/midi_host.c +++ b/src/class/midi/midi_host.c @@ -40,6 +40,15 @@ #define TU_LOG_DRV(...) TU_LOG(CFG_TUH_MIDI_LOG_LEVEL, __VA_ARGS__) +//--------------------------------------------------------------------+ +// Weak stubs: invoked if no strong implementation is available +//--------------------------------------------------------------------+ +TU_ATTR_WEAK void tuh_midi_descriptor_cb(uint8_t idx, const tuh_midi_descriptor_cb_t * desc_cb_data) { (void) idx; (void) desc_cb_data; } +TU_ATTR_WEAK void tuh_midi_mount_cb(uint8_t idx, const tuh_midi_mount_cb_t* mount_cb_data) { (void) idx; (void) mount_cb_data; } +TU_ATTR_WEAK void tuh_midi_umount_cb(uint8_t idx) { (void) idx; } +TU_ATTR_WEAK void tuh_midi_rx_cb(uint8_t idx, uint32_t xferred_bytes) { (void) idx; (void) xferred_bytes; } +TU_ATTR_WEAK void tuh_midi_tx_cb(uint8_t idx, uint32_t xferred_bytes) { (void) idx; (void) xferred_bytes; } + //--------------------------------------------------------------------+ // MACRO CONSTANT TYPEDEF //--------------------------------------------------------------------+ @@ -52,8 +61,8 @@ typedef struct { uint8_t ep_in; // IN endpoint address uint8_t ep_out; // OUT endpoint address - uint8_t num_cables_rx; // IN endpoint CS descriptor bNumEmbMIDIJack value - uint8_t num_cables_tx; // OUT endpoint CS descriptor bNumEmbMIDIJack value + uint8_t rx_cable_count; // IN endpoint CS descriptor bNumEmbMIDIJack value + uint8_t tx_cable_count; // OUT endpoint CS descriptor bNumEmbMIDIJack value #if CFG_TUH_MIDI_STREAM_API // For Stream read()/write() API @@ -135,16 +144,13 @@ void midih_close(uint8_t daddr) { midih_interface_t* p_midi = &_midi_host[idx]; if (p_midi->daddr == daddr) { TU_LOG_DRV(" MIDI close addr = %u index = %u\r\n", daddr, idx); - - if (tuh_midi_umount_cb) { - tuh_midi_umount_cb(idx); - } + tuh_midi_umount_cb(idx); p_midi->ep_in = 0; p_midi->ep_out = 0; p_midi->bInterfaceNumber = 0; - p_midi->num_cables_rx = 0; - p_midi->num_cables_tx = 0; + p_midi->rx_cable_count = 0; + p_midi->tx_cable_count = 0; p_midi->daddr = 0; p_midi->mounted = false; tu_memclr(&p_midi->stream_read, sizeof(p_midi->stream_read)); @@ -163,33 +169,16 @@ bool midih_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, uint midih_interface_t *p_midi_host = &_midi_host[idx]; if (ep_addr == p_midi_host->ep_stream.rx.ep_addr) { - // receive new data if available + // receive new data, put it into FIFO and invoke callback if available if (xferred_bytes) { - // put in the RX FIFO only non-zero MIDI IN 4-byte packets - uint32_t packets_queued = 0; - uint8_t *buf = _midi_epbuf->rx; - const uint32_t npackets = xferred_bytes / 4; - for (uint32_t p = 0; p < npackets; p++) { - // some devices send back all zero packets even if there is no data ready - const uint32_t packet = tu_unaligned_read32(buf); - if (packet != 0) { - tu_edpt_stream_read_xfer_complete_with_buf(&p_midi_host->ep_stream.rx, buf, 4); - ++packets_queued; - TU_LOG3("MIDI RX=%08x\r\n", packet); - } - buf += 4; - } - - if (tuh_midi_rx_cb) { - tuh_midi_rx_cb(idx, packets_queued); - } + tu_edpt_stream_read_xfer_complete(&p_midi_host->ep_stream.rx, xferred_bytes); + tuh_midi_rx_cb(idx, xferred_bytes); } tu_edpt_stream_read_xfer(dev_addr, &p_midi_host->ep_stream.rx); // prepare for next transfer } else if (ep_addr == p_midi_host->ep_stream.tx.ep_addr) { - if (tuh_midi_tx_cb) { - tuh_midi_tx_cb(idx); - } + tuh_midi_tx_cb(idx, xferred_bytes); + if (0 == tu_edpt_stream_write_xfer(dev_addr, &p_midi_host->ep_stream.tx)) { // If there is no data left, a ZLP should be sent if // xferred_bytes is multiple of EP size and not zero @@ -207,7 +196,6 @@ bool midih_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *d (void) rhport; TU_VERIFY(TUSB_CLASS_AUDIO == desc_itf->bInterfaceClass); - // const uint8_t* p_start = ((uint8_t const*) desc_itf); const uint8_t *p_end = ((const uint8_t *) desc_itf) + max_len; const uint8_t *p_desc = (const uint8_t *) desc_itf; @@ -286,14 +274,14 @@ bool midih_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *d TU_LOG_DRV(" Endpoint and CS_Endpoint descriptor %02x\r\n", p_ep->bEndpointAddress); if (tu_edpt_dir(p_ep->bEndpointAddress) == TUSB_DIR_OUT) { p_midi->ep_out = p_ep->bEndpointAddress; - p_midi->num_cables_tx = p_csep->bNumEmbMIDIJack; + p_midi->tx_cable_count = p_csep->bNumEmbMIDIJack; desc_cb.desc_epout = p_ep; TU_ASSERT(tuh_edpt_open(dev_addr, p_ep)); tu_edpt_stream_open(&p_midi->ep_stream.tx, p_ep); } else { p_midi->ep_in = p_ep->bEndpointAddress; - p_midi->num_cables_rx = p_csep->bNumEmbMIDIJack; + p_midi->rx_cable_count = p_csep->bNumEmbMIDIJack; desc_cb.desc_epin = p_ep; TU_ASSERT(tuh_edpt_open(dev_addr, p_ep)); @@ -309,10 +297,7 @@ bool midih_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *d desc_cb.desc_midi_total_len = (uint16_t) ((uintptr_t)p_desc - (uintptr_t) desc_itf); p_midi->daddr = dev_addr; - - if (tuh_midi_descriptor_cb) { - tuh_midi_descriptor_cb(idx, &desc_cb); - } + tuh_midi_descriptor_cb(idx, &desc_cb); return true; } @@ -323,9 +308,13 @@ bool midih_set_config(uint8_t dev_addr, uint8_t itf_num) { midih_interface_t *p_midi = &_midi_host[idx]; p_midi->mounted = true; - if (tuh_midi_mount_cb) { - tuh_midi_mount_cb(idx, p_midi->num_cables_rx, p_midi->num_cables_tx); - } + const tuh_midi_mount_cb_t mount_cb_data = { + .daddr = dev_addr, + .bInterfaceNumber = itf_num, + .rx_cable_count = p_midi->rx_cable_count, + .tx_cable_count = p_midi->tx_cable_count, + }; + tuh_midi_mount_cb(idx, &mount_cb_data); tu_edpt_stream_read_xfer(dev_addr, &p_midi->ep_stream.rx); // prepare for incoming data @@ -355,18 +344,18 @@ uint8_t tuh_midi_itf_get_index(uint8_t daddr, uint8_t itf_num) { return TUSB_INDEX_INVALID_8; } -uint8_t tuh_midi_get_num_tx_cables (uint8_t idx) { +uint8_t tuh_midi_get_tx_cable_count (uint8_t idx) { TU_VERIFY(idx < CFG_TUH_MIDI); midih_interface_t *p_midi = &_midi_host[idx]; TU_VERIFY(p_midi->ep_stream.tx.ep_addr != 0, 0); - return p_midi->num_cables_tx; + return p_midi->tx_cable_count; } -uint8_t tuh_midi_get_num_rx_cables (uint8_t idx) { +uint8_t tuh_midi_get_rx_cable_count (uint8_t idx) { TU_VERIFY(idx < CFG_TUH_MIDI); midih_interface_t *p_midi = &_midi_host[idx]; TU_VERIFY(p_midi->ep_stream.rx.ep_addr != 0, 0); - return p_midi->num_cables_rx; + return p_midi->rx_cable_count; } uint32_t tuh_midi_read_available(uint8_t idx) { @@ -410,7 +399,7 @@ uint32_t tuh_midi_packet_write_n(uint8_t idx, const uint8_t* buffer, uint32_t bu uint32_t tuh_midi_stream_write(uint8_t idx, uint8_t cable_num, uint8_t const *buffer, uint32_t bufsize) { TU_VERIFY(idx < CFG_TUH_MIDI && buffer && bufsize > 0); midih_interface_t *p_midi = &_midi_host[idx]; - TU_VERIFY(cable_num < p_midi->num_cables_tx); + TU_VERIFY(cable_num < p_midi->tx_cable_count); midi_driver_stream_t *stream = &p_midi->stream_write; uint32_t byte_count = 0; @@ -520,7 +509,7 @@ uint32_t tuh_midi_stream_read(uint8_t idx, uint8_t *p_cable_num, uint8_t *p_buff while (nread == 4 && bytes_buffered < bufsize) { *p_cable_num = (p_midi->stream_read.buffer[0] >> 4) & 0x0f; uint8_t bytes_to_add_to_stream = 0; - if (*p_cable_num < p_midi->num_cables_rx) { + if (*p_cable_num < p_midi->rx_cable_count) { // ignore the CIN field; too many devices out there encode this wrong uint8_t status = p_midi->stream_read.buffer[1]; uint16_t cable_mask = (uint16_t) (1 << *p_cable_num); diff --git a/src/class/midi/midi_host.h b/src/class/midi/midi_host.h index 717e6ba67..b06bb43d7 100644 --- a/src/class/midi/midi_host.h +++ b/src/class/midi/midi_host.h @@ -37,10 +37,6 @@ //--------------------------------------------------------------------+ // Class Driver Configuration //--------------------------------------------------------------------+ -#ifndef CFG_TUH_MAX_CABLES -#define CFG_TUH_MAX_CABLES 16 -#endif - #ifndef CFG_TUH_MIDI_RX_BUFSIZE #define CFG_TUH_MIDI_RX_BUFSIZE TUH_EPSIZE_BULK_MPS #endif @@ -60,7 +56,7 @@ #endif //--------------------------------------------------------------------+ -// Application API +// Application Types //--------------------------------------------------------------------+ typedef struct { const tusb_desc_interface_t* desc_audio_control; @@ -76,6 +72,17 @@ typedef struct { const uint8_t* desc_jack[16]; // list of jack descriptors (embedded + external) } tuh_midi_descriptor_cb_t; +typedef struct { + uint8_t daddr; + uint8_t bInterfaceNumber; // interface number of MIDI streaming + uint8_t rx_cable_count; + uint8_t tx_cable_count; +} tuh_midi_mount_cb_t; + +//--------------------------------------------------------------------+ +// Application API +//--------------------------------------------------------------------+ + // Check if MIDI interface is mounted bool tuh_midi_mounted(uint8_t idx); @@ -84,10 +91,10 @@ bool tuh_midi_mounted(uint8_t idx); uint8_t tuh_midi_itf_get_index(uint8_t daddr, uint8_t itf_num); // return the number of virtual midi cables on the device's IN endpoint -uint8_t tuh_midi_get_num_rx_cables(uint8_t idx); +uint8_t tuh_midi_get_rx_cable_count(uint8_t idx); // return the number of virtual midi cables on the device's OUT endpoint -uint8_t tuh_midi_get_num_tx_cables(uint8_t idx); +uint8_t tuh_midi_get_tx_cable_count(uint8_t idx); // return the raw number of bytes available. // Note: this is related but not the same as number of stream bytes available. @@ -151,16 +158,19 @@ uint32_t tuh_midi_stream_read(uint8_t idx, uint8_t *p_cable_num, uint8_t *p_buff // Invoked when MIDI interface is detected in enumeration. Application can copy/parse descriptor if needed. // Note: may be fired before tuh_midi_mount_cb(), therefore midi interface is not mounted/ready. -TU_ATTR_WEAK void tuh_midi_descriptor_cb(uint8_t idx, const tuh_midi_descriptor_cb_t * desc_cb); +void tuh_midi_descriptor_cb(uint8_t idx, const tuh_midi_descriptor_cb_t * desc_cb_data); // Invoked when device with MIDI interface is mounted. -TU_ATTR_WEAK void tuh_midi_mount_cb(uint8_t idx, uint8_t num_cables_rx, uint16_t num_cables_tx); +void tuh_midi_mount_cb(uint8_t idx, const tuh_midi_mount_cb_t* mount_cb_data); // Invoked when device with MIDI interface is un-mounted -TU_ATTR_WEAK void tuh_midi_umount_cb(uint8_t idx); +void tuh_midi_umount_cb(uint8_t idx); + +// Invoked when received new data +void tuh_midi_rx_cb(uint8_t idx, uint32_t xferred_bytes); -TU_ATTR_WEAK void tuh_midi_rx_cb(uint8_t idx, uint32_t num_packets); -TU_ATTR_WEAK void tuh_midi_tx_cb(uint8_t idx); +// Invoked when a TX is complete and therefore space becomes available in TX buffer +void tuh_midi_tx_cb(uint8_t idx, uint32_t xferred_bytes); //--------------------------------------------------------------------+ // Internal Class Driver API diff --git a/src/host/usbh_pvt.h b/src/host/usbh_pvt.h index d27c4baa2..bfa1fb2ba 100644 --- a/src/host/usbh_pvt.h +++ b/src/host/usbh_pvt.h @@ -41,10 +41,6 @@ #define TU_LOG_INT_USBH(...) TU_LOG_INT(CFG_TUH_LOG_LEVEL, __VA_ARGS__) #define TU_LOG_HEX_USBH(...) TU_LOG_HEX(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 //--------------------------------------------------------------------+ -- cgit v1.3.1 From 39e6375b74b38b01e7868c283874b3a305b524e1 Mon Sep 17 00:00:00 2001 From: hathach Date: Thu, 6 Mar 2025 10:26:45 +0700 Subject: midi host: skip rx data with all zeroes --- examples/host/midi_rx/src/main.c | 2 +- src/class/midi/midi_host.c | 17 ++++++++-------- src/common/tusb_common.h | 42 +++++++++++++++++++++++++--------------- 3 files changed, 36 insertions(+), 25 deletions(-) (limited to 'src/class') diff --git a/examples/host/midi_rx/src/main.c b/examples/host/midi_rx/src/main.c index d26321e5d..78b1a11b9 100644 --- a/examples/host/midi_rx/src/main.c +++ b/examples/host/midi_rx/src/main.c @@ -110,7 +110,7 @@ void tuh_midi_rx_cb(uint8_t idx, uint32_t xferred_bytes) { uint8_t cable_num = 0; uint32_t bytes_read = tuh_midi_stream_read(idx, &cable_num, buffer, sizeof(buffer)); - printf("Cable %u rx %lu bytes: ", cable_num, bytes_read); + printf("Cable %u rx: ", cable_num); for (uint32_t i = 0; i < bytes_read; i++) { printf("%02X ", buffer[i]); } diff --git a/src/class/midi/midi_host.c b/src/class/midi/midi_host.c index a4b1ebd2e..7f7d536d8 100644 --- a/src/class/midi/midi_host.c +++ b/src/class/midi/midi_host.c @@ -166,23 +166,24 @@ bool midih_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, uint (void) result; const uint8_t idx = get_idx_by_ep_addr(dev_addr, ep_addr); TU_VERIFY(idx < CFG_TUH_MIDI); - midih_interface_t *p_midi_host = &_midi_host[idx]; + midih_interface_t *p_midi = &_midi_host[idx]; - if (ep_addr == p_midi_host->ep_stream.rx.ep_addr) { + if (ep_addr == p_midi->ep_stream.rx.ep_addr) { // receive new data, put it into FIFO and invoke callback if available - if (xferred_bytes) { - tu_edpt_stream_read_xfer_complete(&p_midi_host->ep_stream.rx, xferred_bytes); + // Note: some devices send back all zero packets even if there is no data ready + if (xferred_bytes && !tu_mem_is_zero(p_midi->ep_stream.rx.ep_buf, xferred_bytes)) { + tu_edpt_stream_read_xfer_complete(&p_midi->ep_stream.rx, xferred_bytes); tuh_midi_rx_cb(idx, xferred_bytes); } - tu_edpt_stream_read_xfer(dev_addr, &p_midi_host->ep_stream.rx); // prepare for next transfer - } else if (ep_addr == p_midi_host->ep_stream.tx.ep_addr) { + tu_edpt_stream_read_xfer(dev_addr, &p_midi->ep_stream.rx); // prepare for next transfer + } else if (ep_addr == p_midi->ep_stream.tx.ep_addr) { tuh_midi_tx_cb(idx, xferred_bytes); - if (0 == tu_edpt_stream_write_xfer(dev_addr, &p_midi_host->ep_stream.tx)) { + if (0 == tu_edpt_stream_write_xfer(dev_addr, &p_midi->ep_stream.tx)) { // If there is no data left, a ZLP should be sent if // xferred_bytes is multiple of EP size and not zero - tu_edpt_stream_write_zlp_if_needed(dev_addr, &p_midi_host->ep_stream.tx, xferred_bytes); + tu_edpt_stream_write_zlp_if_needed(dev_addr, &p_midi->ep_stream.tx, xferred_bytes); } } diff --git a/src/common/tusb_common.h b/src/common/tusb_common.h index 74cac965d..0351a3d8f 100644 --- a/src/common/tusb_common.h +++ b/src/common/tusb_common.h @@ -120,6 +120,22 @@ TU_ATTR_ALWAYS_INLINE static inline int tu_memcpy_s(void *dest, size_t destsz, c return 0; } +TU_ATTR_ALWAYS_INLINE static inline bool tu_mem_is_zero(const void *buffer, size_t size) { + const uint8_t* buf8 = (const uint8_t*) buffer; + for (size_t i = 0; i < size; i++) { + if (buf8[i] != 0) { return false; } + } + return true; +} + +TU_ATTR_ALWAYS_INLINE static inline bool tu_mem_is_ff(const void *buffer, size_t size) { + const uint8_t* buf8 = (const uint8_t*) buffer; + for (size_t i = 0; i < size; i++) { + if (buf8[i] != 0xff) { return false; } + } + return true; +} + //------------- Bytes -------------// TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_u32(uint8_t b3, uint8_t b2, uint8_t b1, uint8_t b0) { @@ -181,8 +197,7 @@ TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_round_up(uint32_t v, uint32_t f) // log2 of a value is its MSB's position // TODO use clz TODO remove -static inline uint8_t tu_log2(uint32_t value) -{ +TU_ATTR_ALWAYS_INLINE static inline uint8_t tu_log2(uint32_t value) { uint8_t result = 0; while (value >>= 1) { result++; } return result; @@ -193,8 +208,7 @@ static inline uint8_t tu_log2(uint32_t value) // return sizeof(uint32_t) * CHAR_BIT - __builtin_clz(x) - 1; //} -static inline bool tu_is_power_of_two(uint32_t value) -{ +TU_ATTR_ALWAYS_INLINE static inline bool tu_is_power_of_two(uint32_t value) { return (value != 0) && ((value & (value - 1)) == 0); } @@ -205,27 +219,23 @@ static inline bool tu_is_power_of_two(uint32_t value) typedef struct { uint16_t val; } TU_ATTR_PACKED tu_unaligned_uint16_t; typedef struct { uint32_t val; } TU_ATTR_PACKED tu_unaligned_uint32_t; -TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_unaligned_read32(const void* mem) -{ - tu_unaligned_uint32_t const* ua32 = (tu_unaligned_uint32_t const*) mem; +TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_unaligned_read32(const void *mem) { + tu_unaligned_uint32_t const *ua32 = (tu_unaligned_uint32_t const *) mem; return ua32->val; } -TU_ATTR_ALWAYS_INLINE static inline void tu_unaligned_write32(void* mem, uint32_t value) -{ - tu_unaligned_uint32_t* ua32 = (tu_unaligned_uint32_t*) mem; +TU_ATTR_ALWAYS_INLINE static inline void tu_unaligned_write32(void *mem, uint32_t value) { + tu_unaligned_uint32_t *ua32 = (tu_unaligned_uint32_t *) mem; ua32->val = value; } -TU_ATTR_ALWAYS_INLINE static inline uint16_t tu_unaligned_read16(const void* mem) -{ - tu_unaligned_uint16_t const* ua16 = (tu_unaligned_uint16_t const*) mem; +TU_ATTR_ALWAYS_INLINE static inline uint16_t tu_unaligned_read16(const void *mem) { + tu_unaligned_uint16_t const *ua16 = (tu_unaligned_uint16_t const *) mem; return ua16->val; } -TU_ATTR_ALWAYS_INLINE static inline void tu_unaligned_write16(void* mem, uint16_t value) -{ - tu_unaligned_uint16_t* ua16 = (tu_unaligned_uint16_t*) mem; +TU_ATTR_ALWAYS_INLINE static inline void tu_unaligned_write16(void *mem, uint16_t value) { + tu_unaligned_uint16_t *ua16 = (tu_unaligned_uint16_t *) mem; ua16->val = value; } -- cgit v1.3.1 From ee234a84caf59d23395ed70f5e1c9d772e3f958b Mon Sep 17 00:00:00 2001 From: hathach Date: Thu, 6 Mar 2025 11:03:47 +0700 Subject: hack: force/overwrite endpoint mps to 64 for device that incorrectly report 512 bytes for bulk in fullspeed mode. --- src/class/midi/midi_host.c | 4 ++-- src/common/tusb_private.h | 2 +- src/device/usbd.c | 4 ++-- src/host/usbh.c | 2 +- src/tusb.c | 15 ++++++++++++--- 5 files changed, 18 insertions(+), 9 deletions(-) (limited to 'src/class') diff --git a/src/class/midi/midi_host.c b/src/class/midi/midi_host.c index 7f7d536d8..03144eb45 100644 --- a/src/class/midi/midi_host.c +++ b/src/class/midi/midi_host.c @@ -267,10 +267,10 @@ bool midih_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *d break; case TUSB_DESC_ENDPOINT: { - tusb_desc_endpoint_t const *p_ep = (tusb_desc_endpoint_t const *) p_desc; + const tusb_desc_endpoint_t *p_ep = (const tusb_desc_endpoint_t *) p_desc; p_desc = tu_desc_next(p_desc); // next to CS endpoint TU_VERIFY(p_desc < p_end && tu_desc_next(p_desc) <= p_end); - midi_desc_cs_endpoint_t const *p_csep = (midi_desc_cs_endpoint_t const *) p_desc; + const midi_desc_cs_endpoint_t *p_csep = (const midi_desc_cs_endpoint_t *) p_desc; TU_LOG_DRV(" Endpoint and CS_Endpoint descriptor %02x\r\n", p_ep->bEndpointAddress); if (tu_edpt_dir(p_ep->bEndpointAddress) == TUSB_DIR_OUT) { diff --git a/src/common/tusb_private.h b/src/common/tusb_private.h index 445882243..31aca8a31 100644 --- a/src/common/tusb_private.h +++ b/src/common/tusb_private.h @@ -67,7 +67,7 @@ typedef struct { //--------------------------------------------------------------------+ // Check if endpoint descriptor is valid per USB specs -bool tu_edpt_validate(tusb_desc_endpoint_t const * desc_ep, tusb_speed_t speed); +bool tu_edpt_validate(tusb_desc_endpoint_t const * desc_ep, tusb_speed_t speed, bool is_host); // Bind all endpoint of a interface descriptor to class driver void tu_edpt_bind_driver(uint8_t ep2drv[][2], tusb_desc_interface_t const* p_desc, uint16_t desc_len, uint8_t driver_id); diff --git a/src/device/usbd.c b/src/device/usbd.c index faf926855..fb5cec49d 100644 --- a/src/device/usbd.c +++ b/src/device/usbd.c @@ -1296,7 +1296,7 @@ bool usbd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const* desc_ep) { rhport = _usbd_rhport; TU_ASSERT(tu_edpt_number(desc_ep->bEndpointAddress) < CFG_TUD_ENDPPOINT_MAX); - TU_ASSERT(tu_edpt_validate(desc_ep, (tusb_speed_t) _usbd_dev.speed)); + TU_ASSERT(tu_edpt_validate(desc_ep, (tusb_speed_t) _usbd_dev.speed, false)); return dcd_edpt_open(rhport, desc_ep); } @@ -1497,7 +1497,7 @@ bool usbd_edpt_iso_activate(uint8_t rhport, tusb_desc_endpoint_t const* desc_ep) uint8_t const dir = tu_edpt_dir(desc_ep->bEndpointAddress); TU_ASSERT(epnum < CFG_TUD_ENDPPOINT_MAX); - TU_ASSERT(tu_edpt_validate(desc_ep, (tusb_speed_t) _usbd_dev.speed)); + TU_ASSERT(tu_edpt_validate(desc_ep, (tusb_speed_t) _usbd_dev.speed, false)); _usbd_dev.ep_status[epnum][dir].stalled = 0; _usbd_dev.ep_status[epnum][dir].busy = 0; diff --git a/src/host/usbh.c b/src/host/usbh.c index 609fe5000..c87f058cd 100644 --- a/src/host/usbh.c +++ b/src/host/usbh.c @@ -986,7 +986,7 @@ static bool usbh_edpt_control_open(uint8_t dev_addr, uint8_t max_packet_size) { } bool tuh_edpt_open(uint8_t dev_addr, tusb_desc_endpoint_t const* desc_ep) { - TU_ASSERT(tu_edpt_validate(desc_ep, tuh_speed_get(dev_addr))); + TU_ASSERT(tu_edpt_validate(desc_ep, tuh_speed_get(dev_addr), true)); return hcd_edpt_open(usbh_get_rhport(dev_addr), dev_addr, desc_ep); } diff --git a/src/tusb.c b/src/tusb.c index 9303e9bc4..13b89997c 100644 --- a/src/tusb.c +++ b/src/tusb.c @@ -205,7 +205,7 @@ bool tu_edpt_release(tu_edpt_state_t* ep_state, osal_mutex_t mutex) { return ret; } -bool tu_edpt_validate(tusb_desc_endpoint_t const* desc_ep, tusb_speed_t speed) { +bool tu_edpt_validate(tusb_desc_endpoint_t const* desc_ep, tusb_speed_t speed, bool is_host) { uint16_t const max_packet_size = tu_edpt_packet_size(desc_ep); TU_LOG2(" Open EP %02X with Size = %u\r\n", desc_ep->bEndpointAddress, max_packet_size); @@ -221,8 +221,17 @@ bool tu_edpt_validate(tusb_desc_endpoint_t const* desc_ep, tusb_speed_t speed) { // Bulk highspeed must be EXACTLY 512 TU_ASSERT(max_packet_size == 512); } else { - // TODO Bulk fullspeed can only be 8, 16, 32, 64 - TU_ASSERT(max_packet_size <= 64); + // Bulk fullspeed can only be 8, 16, 32, 64 + if (is_host && max_packet_size == 512) { + // HACK: while in host mode, some device incorrectly always report 512 regardless of link speed + // overwrite descriptor to force 64 + TU_LOG1(" WARN: EP max packet size is 512 in fullspeed, force to 64\r\n"); + tusb_desc_endpoint_t* hacked_ep = (tusb_desc_endpoint_t*) (uintptr_t) desc_ep; + hacked_ep->wMaxPacketSize = tu_htole16(64); + } else { + TU_ASSERT(max_packet_size == 8 || max_packet_size == 16 || + max_packet_size == 32 || max_packet_size == 64); + } } break; -- cgit v1.3.1 From cf94b3f5fc6efdfc25b7c434852f4b04af2dddc7 Mon Sep 17 00:00:00 2001 From: "Cynventria[CitRA]" <45027522+Cynventria@users.noreply.github.com> Date: Mon, 10 Mar 2025 14:22:29 +0800 Subject: fix desc_end in vendord_open() minor fix on calculation of desc_end in vendord_open( ) for descriptor prasing --- src/class/vendor/vendor_device.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/class') diff --git a/src/class/vendor/vendor_device.c b/src/class/vendor/vendor_device.c index 6f9b4853f..2fc0ac944 100644 --- a/src/class/vendor/vendor_device.c +++ b/src/class/vendor/vendor_device.c @@ -197,7 +197,7 @@ void vendord_reset(uint8_t rhport) { uint16_t vendord_open(uint8_t rhport, const tusb_desc_interface_t* desc_itf, uint16_t max_len) { TU_VERIFY(TUSB_CLASS_VENDOR_SPECIFIC == desc_itf->bInterfaceClass, 0); const uint8_t* p_desc = tu_desc_next(desc_itf); - const uint8_t* desc_end = p_desc + max_len; + const uint8_t* desc_end = (uint8_t const*)desc_itf + max_len; // Find available interface vendord_interface_t* p_vendor = NULL; -- cgit v1.3.1 From b80800f18205ae23d571438d55e078a1dcc295e8 Mon Sep 17 00:00:00 2001 From: rppicomidi Date: Thu, 13 Mar 2025 10:04:56 -0700 Subject: Only clear stream_read & stream_write if they are defined --- src/class/midi/midi_host.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/class') diff --git a/src/class/midi/midi_host.c b/src/class/midi/midi_host.c index 03144eb45..4d824e04c 100644 --- a/src/class/midi/midi_host.c +++ b/src/class/midi/midi_host.c @@ -153,9 +153,10 @@ void midih_close(uint8_t daddr) { p_midi->tx_cable_count = 0; p_midi->daddr = 0; p_midi->mounted = false; +#if CFG_TUH_MIDI_STREAM_API tu_memclr(&p_midi->stream_read, sizeof(p_midi->stream_read)); tu_memclr(&p_midi->stream_write, sizeof(p_midi->stream_write)); - +#endif tu_edpt_stream_close(&p_midi->ep_stream.rx); tu_edpt_stream_close(&p_midi->ep_stream.tx); } -- cgit v1.3.1 From de45e4b01a55182f494577a8bf8b46ad51d6eb9f Mon Sep 17 00:00:00 2001 From: HiFiPhile Date: Sat, 15 Mar 2025 23:49:11 +0100 Subject: Add ctrl buffer alignment. Signed-off-by: HiFiPhile --- 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 388168424..7a6fd453f 100644 --- a/src/class/audio/audio_device.c +++ b/src/class/audio/audio_device.c @@ -208,15 +208,15 @@ tu_static CFG_TUD_MEM_SECTION struct { #endif// CFG_TUD_AUDIO_ENABLE_EP_OUT && (USE_LINEAR_BUFFER || CFG_TUD_AUDIO_ENABLE_DECODING) // Control buffers -tu_static uint8_t ctrl_buf_1[CFG_TUD_AUDIO_FUNC_1_CTRL_BUF_SZ]; - -#if CFG_TUD_AUDIO > 1 -tu_static uint8_t ctrl_buf_2[CFG_TUD_AUDIO_FUNC_2_CTRL_BUF_SZ]; -#endif - -#if CFG_TUD_AUDIO > 2 -tu_static uint8_t ctrl_buf_3[CFG_TUD_AUDIO_FUNC_3_CTRL_BUF_SZ]; -#endif +tu_static CFG_TUD_MEM_SECTION struct { + TUD_EPBUF_DEF(buf1, CFG_TUD_AUDIO_FUNC_1_CTRL_BUF_SZ); + #if CFG_TUD_AUDIO > 1 + TUD_EPBUF_DEF(buf2, CFG_TUD_AUDIO_FUNC_2_CTRL_BUF_SZ); + #endif + #if CFG_TUD_AUDIO > 2 + TUD_EPBUF_DEF(buf3, CFG_TUD_AUDIO_FUNC_3_CTRL_BUF_SZ); + #endif +} ctrl_buf; // Active alternate setting of interfaces tu_static uint8_t alt_setting_1[CFG_TUD_AUDIO_FUNC_1_N_AS_INT]; @@ -1223,18 +1223,18 @@ void audiod_init(void) { // Initialize control buffers switch (i) { case 0: - audio->ctrl_buf = ctrl_buf_1; + audio->ctrl_buf = ctrl_buf.buf1; audio->ctrl_buf_sz = CFG_TUD_AUDIO_FUNC_1_CTRL_BUF_SZ; break; #if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_CTRL_BUF_SZ > 0 case 1: - audio->ctrl_buf = ctrl_buf_2; + audio->ctrl_buf = ctrl_buf.buf2; audio->ctrl_buf_sz = CFG_TUD_AUDIO_FUNC_2_CTRL_BUF_SZ; break; #endif #if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_CTRL_BUF_SZ > 0 case 2: - audio->ctrl_buf = ctrl_buf_3; + audio->ctrl_buf = ctrl_buf.buf3; audio->ctrl_buf_sz = CFG_TUD_AUDIO_FUNC_3_CTRL_BUF_SZ; break; #endif -- cgit v1.3.1 From 31b3a2f63bcf4f1969ada9d0c099444959b37388 Mon Sep 17 00:00:00 2001 From: rppicomidi Date: Sat, 15 Mar 2025 11:20:57 -0700 Subject: Fix 3031: implement tuh_midi_itf_get_info() --- src/class/midi/midi_host.c | 23 +++++++++++++++++++++++ src/class/midi/midi_host.h | 4 ++++ 2 files changed, 27 insertions(+) (limited to 'src/class') diff --git a/src/class/midi/midi_host.c b/src/class/midi/midi_host.c index 4d824e04c..9019d476b 100644 --- a/src/class/midi/midi_host.c +++ b/src/class/midi/midi_host.c @@ -346,6 +346,29 @@ uint8_t tuh_midi_itf_get_index(uint8_t daddr, uint8_t itf_num) { return TUSB_INDEX_INVALID_8; } +bool tuh_midi_itf_get_info(uint8_t idx, tuh_itf_info_t* info) +{ + midih_interface_t* p_midi = &_midi_host[idx]; + TU_VERIFY(p_midi && info); + + info->daddr = p_midi->daddr; + + // re-construct descriptor + tusb_desc_interface_t* desc = &info->desc; + desc->bLength = sizeof(tusb_desc_interface_t); + desc->bDescriptorType = TUSB_DESC_INTERFACE; + + desc->bInterfaceNumber = p_midi->bInterfaceNumber; + desc->bAlternateSetting = 0; + desc->bNumEndpoints = (p_midi->ep_in != 0 ? 1:0) + (p_midi->ep_out != 0 ? 1:0); + desc->bInterfaceClass = TUSB_CLASS_AUDIO; + desc->bInterfaceSubClass = AUDIO_SUBCLASS_MIDI_STREAMING; + desc->bInterfaceProtocol = 0; + desc->iInterface = 0; + + return true; +} + uint8_t tuh_midi_get_tx_cable_count (uint8_t idx) { TU_VERIFY(idx < CFG_TUH_MIDI); midih_interface_t *p_midi = &_midi_host[idx]; diff --git a/src/class/midi/midi_host.h b/src/class/midi/midi_host.h index b06bb43d7..67df25a82 100644 --- a/src/class/midi/midi_host.h +++ b/src/class/midi/midi_host.h @@ -90,6 +90,10 @@ bool tuh_midi_mounted(uint8_t idx); // return TUSB_INDEX_INVALID_8 (0xFF) if not found uint8_t tuh_midi_itf_get_index(uint8_t daddr, uint8_t itf_num); +// Get Interface information +// return true if index is correct and interface is currently mounted +bool tuh_midi_itf_get_info(uint8_t idx, tuh_itf_info_t* info); + // return the number of virtual midi cables on the device's IN endpoint uint8_t tuh_midi_get_rx_cable_count(uint8_t idx); -- cgit v1.3.1 From 5ecea4eefe13ea93095da710dfcf3b3fee578c8e Mon Sep 17 00:00:00 2001 From: rppicomidi Date: Tue, 18 Mar 2025 07:41:49 -0700 Subject: fix tuh_midi_itf_get_info() desc->iInterface value --- src/class/midi/midi_host.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'src/class') diff --git a/src/class/midi/midi_host.c b/src/class/midi/midi_host.c index 9019d476b..d6d204b7b 100644 --- a/src/class/midi/midi_host.c +++ b/src/class/midi/midi_host.c @@ -82,6 +82,7 @@ typedef struct { } ep_stream; bool mounted; + uint8_t iInterface; // for tuh_midi_itf_get_info() }midih_interface_t; typedef struct { @@ -228,6 +229,7 @@ bool midih_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *d TU_LOG_DRV("MIDI opening Interface %u (addr = %u)\r\n", desc_itf->bInterfaceNumber, dev_addr); p_midi->bInterfaceNumber = desc_itf->bInterfaceNumber; + p_midi->iInterface = desc_itf->iInterface; p_midi->itf_count++; desc_cb.desc_midi = desc_itf; @@ -346,8 +348,7 @@ uint8_t tuh_midi_itf_get_index(uint8_t daddr, uint8_t itf_num) { return TUSB_INDEX_INVALID_8; } -bool tuh_midi_itf_get_info(uint8_t idx, tuh_itf_info_t* info) -{ +bool tuh_midi_itf_get_info(uint8_t idx, tuh_itf_info_t* info) { midih_interface_t* p_midi = &_midi_host[idx]; TU_VERIFY(p_midi && info); @@ -364,7 +365,7 @@ bool tuh_midi_itf_get_info(uint8_t idx, tuh_itf_info_t* info) desc->bInterfaceClass = TUSB_CLASS_AUDIO; desc->bInterfaceSubClass = AUDIO_SUBCLASS_MIDI_STREAMING; desc->bInterfaceProtocol = 0; - desc->iInterface = 0; + desc->iInterface = p_midi->iInterface; return true; } -- cgit v1.3.1 From 62f00bdf5d8b2a5941aed3d96865bbe24b117455 Mon Sep 17 00:00:00 2001 From: rppicomidi Date: Tue, 18 Mar 2025 07:42:47 -0700 Subject: Fix compiler conversion error warning --- src/class/midi/midi_host.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/class') diff --git a/src/class/midi/midi_host.c b/src/class/midi/midi_host.c index d6d204b7b..85253f5ca 100644 --- a/src/class/midi/midi_host.c +++ b/src/class/midi/midi_host.c @@ -361,7 +361,7 @@ bool tuh_midi_itf_get_info(uint8_t idx, tuh_itf_info_t* info) { desc->bInterfaceNumber = p_midi->bInterfaceNumber; desc->bAlternateSetting = 0; - desc->bNumEndpoints = (p_midi->ep_in != 0 ? 1:0) + (p_midi->ep_out != 0 ? 1:0); + desc->bNumEndpoints = (uint8_t)((p_midi->ep_in != 0 ? 1:0) + (p_midi->ep_out != 0 ? 1:0)); desc->bInterfaceClass = TUSB_CLASS_AUDIO; desc->bInterfaceSubClass = AUDIO_SUBCLASS_MIDI_STREAMING; desc->bInterfaceProtocol = 0; -- cgit v1.3.1 From 05e4f8b77786a6bbc4a43e3b8574689714ca3138 Mon Sep 17 00:00:00 2001 From: rppicomidi Date: Wed, 19 Mar 2025 05:57:01 -0700 Subject: Move iInterface per review comment --- src/class/midi/midi_host.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/class') diff --git a/src/class/midi/midi_host.c b/src/class/midi/midi_host.c index 85253f5ca..cfea0c080 100644 --- a/src/class/midi/midi_host.c +++ b/src/class/midi/midi_host.c @@ -56,6 +56,7 @@ TU_ATTR_WEAK void tuh_midi_tx_cb(uint8_t idx, uint32_t xferred_bytes) { (void) i typedef struct { uint8_t daddr; uint8_t bInterfaceNumber; // interface number of MIDI streaming + uint8_t iInterface; uint8_t itf_count; // number of interface including Audio Control + MIDI streaming uint8_t ep_in; // IN endpoint address @@ -82,7 +83,6 @@ typedef struct { } ep_stream; bool mounted; - uint8_t iInterface; // for tuh_midi_itf_get_info() }midih_interface_t; typedef struct { -- cgit v1.3.1 From 4b46493cb4f8699c95e01783eee5cf90ca7810e2 Mon Sep 17 00:00:00 2001 From: rppicomidi Date: Thu, 20 Mar 2025 06:27:23 -0700 Subject: Fix #3033: Increase array bounds and test for overflow --- src/class/midi/midi_host.c | 3 ++- src/class/midi/midi_host.h | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'src/class') diff --git a/src/class/midi/midi_host.c b/src/class/midi/midi_host.c index cfea0c080..68e46aca3 100644 --- a/src/class/midi/midi_host.c +++ b/src/class/midi/midi_host.c @@ -254,7 +254,8 @@ bool midih_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *d TU_LOG_DRV(" Jack %s %s descriptor \r\n", tu_desc_subtype(p_desc) == MIDI_CS_INTERFACE_IN_JACK ? "IN" : "OUT", p_desc[3] == MIDI_JACK_EXTERNAL ? "External" : "Embedded"); - desc_cb.desc_jack[desc_cb.jack_num++] = p_desc; + if (desc_cb.jack_num < TU_ARRAY_SIZE(desc_cb.desc_jack)) + desc_cb.desc_jack[desc_cb.jack_num++] = p_desc; break; } diff --git a/src/class/midi/midi_host.h b/src/class/midi/midi_host.h index 67df25a82..06554a03d 100644 --- a/src/class/midi/midi_host.h +++ b/src/class/midi/midi_host.h @@ -69,7 +69,7 @@ typedef struct { const tusb_desc_endpoint_t* desc_epout; // endpoint OUT descriptor, CS_ENDPOINT is right after uint8_t jack_num; - const uint8_t* desc_jack[16]; // list of jack descriptors (embedded + external) + const uint8_t* desc_jack[32]; // list of jack descriptors (embedded + external) } tuh_midi_descriptor_cb_t; typedef struct { -- cgit v1.3.1 From b0def52f45439c3dc41a0c370115deb54cd443e4 Mon Sep 17 00:00:00 2001 From: rppicomidi Date: Fri, 21 Mar 2025 07:13:01 -0700 Subject: Move misplaced statement --- src/class/midi/midi_host.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/class') diff --git a/src/class/midi/midi_host.c b/src/class/midi/midi_host.c index 68e46aca3..b252e8466 100644 --- a/src/class/midi/midi_host.c +++ b/src/class/midi/midi_host.c @@ -591,8 +591,8 @@ uint32_t tuh_midi_stream_read(uint8_t idx, uint8_t *p_cable_num, uint8_t *p_buff break; default: break; - cable_sysex_in_progress &= (uint16_t) ~cable_mask; } + cable_sysex_in_progress &= (uint16_t) ~cable_mask; } else { // Real-time message: can be inserted into a sysex message, // so do don't clear cable_sysex_in_progress bit -- cgit v1.3.1 From 3324a327cbd82d18305030ba2247cbbc71dc9f19 Mon Sep 17 00:00:00 2001 From: rppicomidi Date: Fri, 21 Mar 2025 07:14:10 -0700 Subject: Fix #3033: address review comment --- src/class/midi/midi_host.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/class') diff --git a/src/class/midi/midi_host.c b/src/class/midi/midi_host.c index b252e8466..cd6e115ee 100644 --- a/src/class/midi/midi_host.c +++ b/src/class/midi/midi_host.c @@ -254,8 +254,9 @@ bool midih_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *d TU_LOG_DRV(" Jack %s %s descriptor \r\n", tu_desc_subtype(p_desc) == MIDI_CS_INTERFACE_IN_JACK ? "IN" : "OUT", p_desc[3] == MIDI_JACK_EXTERNAL ? "External" : "Embedded"); - if (desc_cb.jack_num < TU_ARRAY_SIZE(desc_cb.desc_jack)) + if (desc_cb.jack_num < TU_ARRAY_SIZE(desc_cb.desc_jack)) { desc_cb.desc_jack[desc_cb.jack_num++] = p_desc; + } break; } -- cgit v1.3.1 From db537861b2e39debe09009762a968edfcd4a9618 Mon Sep 17 00:00:00 2001 From: hathach Date: Mon, 24 Mar 2025 22:58:21 +0700 Subject: device cdc: rename tud_cdc_configure_fifo/_t to tud_cdc_configure/_t add tx_overwritabe_if_not_connected for cdc driver configure --- src/class/cdc/cdc_device.c | 38 ++++++++++++++++++++------------------ src/class/cdc/cdc_device.h | 22 ++++++++++++++++------ src/common/tusb_fifo.c | 7 +++++-- 3 files changed, 41 insertions(+), 26 deletions(-) (limited to 'src/class') diff --git a/src/class/cdc/cdc_device.c b/src/class/cdc/cdc_device.c index efb672201..4d19adeb4 100644 --- a/src/class/cdc/cdc_device.c +++ b/src/class/cdc/cdc_device.c @@ -82,7 +82,7 @@ typedef struct { static cdcd_interface_t _cdcd_itf[CFG_TUD_CDC]; CFG_TUD_MEM_SECTION static cdcd_epbuf_t _cdcd_epbuf[CFG_TUD_CDC]; -static tud_cdc_configure_fifo_t _cdcd_fifo_cfg; +static tud_cdc_configure_t _cdcd_cfg = TUD_CDC_CONFIGURE_DEFAULT(); static bool _prep_out_transaction(uint8_t itf) { const uint8_t rhport = 0; @@ -119,9 +119,9 @@ static bool _prep_out_transaction(uint8_t itf) { // APPLICATION API //--------------------------------------------------------------------+ -bool tud_cdc_configure_fifo(const tud_cdc_configure_fifo_t* cfg) { - TU_VERIFY(cfg); - _cdcd_fifo_cfg = (*cfg); +bool tud_cdc_configure(const tud_cdc_configure_t* driver_cfg) { + TU_VERIFY(driver_cfg); + _cdcd_cfg = *driver_cfg; return true; } @@ -175,7 +175,7 @@ void tud_cdc_n_read_flush(uint8_t itf) { //--------------------------------------------------------------------+ uint32_t tud_cdc_n_write(uint8_t itf, const void* 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, UINT16_MAX)); + uint16_t wr_count = tu_fifo_write_n(&p_cdc->tx_ff, buffer, (uint16_t) TU_MIN(bufsize, UINT16_MAX)); // flush if queue more than packet size if (tu_fifo_count(&p_cdc->tx_ff) >= BULK_PACKET_SIZE @@ -186,7 +186,7 @@ uint32_t tud_cdc_n_write(uint8_t itf, const void* buffer, uint32_t bufsize) { tud_cdc_n_write_flush(itf); } - return ret; + return wr_count; } uint32_t tud_cdc_n_write_flush(uint8_t itf) { @@ -233,8 +233,6 @@ bool tud_cdc_n_write_clear(uint8_t itf) { //--------------------------------------------------------------------+ void cdcd_init(void) { tu_memclr(_cdcd_itf, sizeof(_cdcd_itf)); - tu_memclr(&_cdcd_fifo_cfg, sizeof(_cdcd_fifo_cfg)); - for (uint8_t i = 0; i < CFG_TUD_CDC; i++) { cdcd_interface_t* p_cdc = &_cdcd_itf[i]; @@ -249,10 +247,10 @@ void cdcd_init(void) { // Config RX fifo tu_fifo_config(&p_cdc->rx_ff, p_cdc->rx_ff_buf, TU_ARRAY_SIZE(p_cdc->rx_ff_buf), 1, false); - // Config TX fifo as overwritable at initialization and will be changed to non-overwritable - // if terminal supports DTR bit. Without DTR we do not know if data is actually polled by terminal. - // 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); + // TX fifo can be configured to change to overwritable if not connected (DTR bit not set). Without DTR we do not + // know if data is actually polled by terminal. This way the most current data is prioritized. + // Default: is overwritable + tu_fifo_config(&p_cdc->tx_ff, p_cdc->tx_ff_buf, TU_ARRAY_SIZE(p_cdc->tx_ff_buf), 1, _cdcd_cfg.tx_overwritabe_if_not_connected); #if OSAL_MUTEX_REQUIRED osal_mutex_t mutex_rd = osal_mutex_create(&p_cdc->rx_ff_mutex); @@ -294,13 +292,13 @@ void cdcd_reset(uint8_t rhport) { cdcd_interface_t* p_cdc = &_cdcd_itf[i]; tu_memclr(p_cdc, ITF_MEM_RESET_SIZE); - if (!_cdcd_fifo_cfg.rx_persistent) { + if (!_cdcd_cfg.rx_persistent) { tu_fifo_clear(&p_cdc->rx_ff); } - if (!_cdcd_fifo_cfg.tx_persistent) { + if (!_cdcd_cfg.tx_persistent) { tu_fifo_clear(&p_cdc->tx_ff); } - tu_fifo_set_overwritable(&p_cdc->tx_ff, true); + tu_fifo_set_overwritable(&p_cdc->tx_ff, _cdcd_cfg.tx_overwritabe_if_not_connected); } } @@ -414,8 +412,12 @@ bool cdcd_control_xfer_cb(uint8_t rhport, uint8_t stage, const tusb_control_requ p_cdc->line_state = (uint8_t) request->wValue; - // Disable fifo overwriting if DTR bit is set - tu_fifo_set_overwritable(&p_cdc->tx_ff, !dtr); + // If enabled: fifo overwriting is disabled if DTR bit is set and vice versa + if (_cdcd_cfg.tx_overwritabe_if_not_connected) { + tu_fifo_set_overwritable(&p_cdc->tx_ff, !dtr); + } else { + tu_fifo_set_overwritable(&p_cdc->tx_ff, false); + } TU_LOG_DRV(" Set Control Line State: DTR = %d, RTS = %d\r\n", dtr, rts); @@ -496,7 +498,7 @@ bool cdcd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_ // xferred_bytes is multiple of EP Packet size and not zero if (!tu_fifo_count(&p_cdc->tx_ff) && xferred_bytes && (0 == (xferred_bytes & (BULK_PACKET_SIZE - 1)))) { if (usbd_edpt_claim(rhport, p_cdc->ep_in)) { - usbd_edpt_xfer(rhport, p_cdc->ep_in, NULL, 0); + TU_ASSERT(usbd_edpt_xfer(rhport, p_cdc->ep_in, NULL, 0)); } } } diff --git a/src/class/cdc/cdc_device.h b/src/class/cdc/cdc_device.h index 2d5ba2575..b653ebd74 100644 --- a/src/class/cdc/cdc_device.h +++ b/src/class/cdc/cdc_device.h @@ -48,14 +48,24 @@ //--------------------------------------------------------------------+ // Driver Configuration //--------------------------------------------------------------------+ - typedef struct TU_ATTR_PACKED { - uint8_t rx_persistent : 1; // keep rx fifo on bus reset or disconnect - uint8_t tx_persistent : 1; // keep tx fifo on bus reset or disconnect -} tud_cdc_configure_fifo_t; + uint8_t rx_persistent : 1; // keep rx fifo data even with bus reset or disconnect + uint8_t tx_persistent : 1; // keep tx fifo data even with reset or disconnect + uint8_t tx_overwritabe_if_not_connected : 1; // if not connected, tx fifo can be overwritten +} tud_cdc_configure_t; + +#define TUD_CDC_CONFIGURE_DEFAULT() { \ + .rx_persistent = 0, \ + .tx_persistent = 0, \ + .tx_overwritabe_if_not_connected = 1, \ +} + +// Configure CDC driver behavior +bool tud_cdc_configure(const tud_cdc_configure_t* driver_cfg); -// Configure CDC FIFOs behavior -bool tud_cdc_configure_fifo(tud_cdc_configure_fifo_t const* cfg); +// Backward compatible +#define tud_cdc_configure_fifo_t tud_cdc_configure_t +#define tud_cdc_configure_fifo tud_cdc_configure //--------------------------------------------------------------------+ // Application API (Multiple Ports) i.e. CFG_TUD_CDC > 1 diff --git a/src/common/tusb_fifo.c b/src/common/tusb_fifo.c index 5f2dcabad..ecf002b09 100644 --- a/src/common/tusb_fifo.c +++ b/src/common/tusb_fifo.c @@ -916,8 +916,11 @@ bool tu_fifo_clear(tu_fifo_t *f) Overwritable mode the fifo is set to */ /******************************************************************************/ -bool tu_fifo_set_overwritable(tu_fifo_t *f, bool overwritable) -{ +bool tu_fifo_set_overwritable(tu_fifo_t *f, bool overwritable) { + if (f->overwritable == overwritable) { + return true; + } + _ff_lock(f->mutex_wr); _ff_lock(f->mutex_rd); -- cgit v1.3.1 From b1eedf4d1d95d6e8c7de425080a107a33cbf0e5d Mon Sep 17 00:00:00 2001 From: hathach Date: Thu, 17 Apr 2025 14:34:55 +0700 Subject: fix iar make build with wb and u5 --- examples/build_system/make/cpu/cortex-m4.mk | 4 ++-- examples/host/msc_file_explorer/Makefile | 2 +- hw/bsp/broadcom_32bit/family.mk | 2 +- hw/bsp/broadcom_64bit/family.mk | 2 +- hw/bsp/kinetis_k32l2/boards/frdm_k32l2a4s/board.mk | 2 +- hw/bsp/lpc15/family.mk | 2 +- hw/bsp/lpc17/family.mk | 2 +- hw/bsp/lpc18/family.mk | 2 +- hw/bsp/lpc40/family.mk | 2 +- hw/bsp/lpc43/family.mk | 6 +++--- hw/bsp/stm32f4/family.mk | 1 - hw/bsp/stm32u5/boards/b_u585i_iot2a/board.mk | 4 +--- hw/bsp/stm32u5/boards/stm32u545nucleo/board.mk | 4 +--- hw/bsp/stm32u5/boards/stm32u575eval/board.mk | 4 +--- hw/bsp/stm32u5/boards/stm32u575nucleo/board.mk | 4 +--- hw/bsp/stm32u5/boards/stm32u5a5nucleo/board.mk | 4 +--- hw/bsp/stm32u5/family.mk | 7 +++++++ hw/bsp/stm32wb/family.mk | 21 +++++++++++++-------- src/class/msc/msc_device.c | 5 +++-- 19 files changed, 41 insertions(+), 39 deletions(-) (limited to 'src/class') diff --git a/examples/build_system/make/cpu/cortex-m4.mk b/examples/build_system/make/cpu/cortex-m4.mk index 4e16819d1..57d6e126d 100644 --- a/examples/build_system/make/cpu/cortex-m4.mk +++ b/examples/build_system/make/cpu/cortex-m4.mk @@ -12,8 +12,8 @@ else ifeq ($(TOOLCHAIN),clang) -mfpu=fpv4-sp-d16 \ else ifeq ($(TOOLCHAIN),iar) - CFLAGS += --cpu cortex-m4 --fpu VFPv4 - ASFLAGS += --cpu cortex-m4 --fpu VFPv4 + CFLAGS += --cpu cortex-m4 --fpu VFPv4-SP + ASFLAGS += --cpu cortex-m4 --fpu VFPv4-SP else $(error "TOOLCHAIN is not supported") diff --git a/examples/host/msc_file_explorer/Makefile b/examples/host/msc_file_explorer/Makefile index c7d6a7cae..f0872376f 100644 --- a/examples/host/msc_file_explorer/Makefile +++ b/examples/host/msc_file_explorer/Makefile @@ -22,6 +22,6 @@ SRC_C += \ $(FATFS_PATH)/ffunicode.c \ # suppress warning caused by fatfs -CFLAGS += -Wno-error=cast-qual +CFLAGS_GCC += -Wno-error=cast-qual include ../../build_system/make/rules.mk diff --git a/hw/bsp/broadcom_32bit/family.mk b/hw/bsp/broadcom_32bit/family.mk index a282e9961..9d4a3b76c 100644 --- a/hw/bsp/broadcom_32bit/family.mk +++ b/hw/bsp/broadcom_32bit/family.mk @@ -15,7 +15,7 @@ CFLAGS += \ CROSS_COMPILE = arm-none-eabi- # mcu driver cause following warnings -CFLAGS += -Wno-error=cast-qual -Wno-error=redundant-decls +CFLAGS_GCC += -Wno-error=cast-qual -Wno-error=redundant-decls SRC_C += \ src/portable/synopsys/dwc2/dcd_dwc2.c \ diff --git a/hw/bsp/broadcom_64bit/family.mk b/hw/bsp/broadcom_64bit/family.mk index 37d381f9f..1ce80e22b 100644 --- a/hw/bsp/broadcom_64bit/family.mk +++ b/hw/bsp/broadcom_64bit/family.mk @@ -14,7 +14,7 @@ CFLAGS += \ CROSS_COMPILE = aarch64-none-elf- # mcu driver cause following warnings -CFLAGS += -Wno-error=cast-qual -Wno-error=redundant-decls +CFLAGS_GCC += -Wno-error=cast-qual -Wno-error=redundant-decls SRC_C += \ src/portable/synopsys/dwc2/dcd_dwc2.c \ diff --git a/hw/bsp/kinetis_k32l2/boards/frdm_k32l2a4s/board.mk b/hw/bsp/kinetis_k32l2/boards/frdm_k32l2a4s/board.mk index c4dc65b63..fb3eb2a03 100644 --- a/hw/bsp/kinetis_k32l2/boards/frdm_k32l2a4s/board.mk +++ b/hw/bsp/kinetis_k32l2/boards/frdm_k32l2a4s/board.mk @@ -3,7 +3,7 @@ MCU = K32L2A41A CFLAGS += -DCPU_K32L2A41VLH1A # mcu driver cause following warnings -CFLAGS += -Wno-error=unused-parameter -Wno-error=redundant-decls -Wno-error=cast-qual +CFLAGS_GCC += -Wno-error=unused-parameter -Wno-error=redundant-decls -Wno-error=cast-qual # All source paths should be relative to the top level. LD_FILE = $(MCU_DIR)/gcc/K32L2A41xxxxA_flash.ld diff --git a/hw/bsp/lpc15/family.mk b/hw/bsp/lpc15/family.mk index b83e008e8..3b63580c0 100644 --- a/hw/bsp/lpc15/family.mk +++ b/hw/bsp/lpc15/family.mk @@ -15,7 +15,7 @@ CFLAGS += \ LDFLAGS_GCC += -specs=nosys.specs -specs=nano.specs # mcu driver cause following warnings -CFLAGS += -Wno-error=strict-prototypes -Wno-error=unused-parameter -Wno-error=unused-variable -Wno-error=cast-qual +CFLAGS_GCC += -Wno-error=strict-prototypes -Wno-error=unused-parameter -Wno-error=unused-variable -Wno-error=cast-qual MCU_DIR = hw/mcu/nxp/lpcopen/lpc15xx/lpc_chip_15xx diff --git a/hw/bsp/lpc17/family.mk b/hw/bsp/lpc17/family.mk index d719a47b7..551eb9e62 100644 --- a/hw/bsp/lpc17/family.mk +++ b/hw/bsp/lpc17/family.mk @@ -13,7 +13,7 @@ CFLAGS += \ -DRTC_EV_SUPPORT=0 # lpc_types.h cause following errors -CFLAGS += -Wno-error=strict-prototypes -Wno-error=cast-qual +CFLAGS_GCC += -Wno-error=strict-prototypes -Wno-error=cast-qual # caused by freeRTOS port !! CFLAGS += -Wno-error=maybe-uninitialized diff --git a/hw/bsp/lpc18/family.mk b/hw/bsp/lpc18/family.mk index f120f63b2..87b831255 100644 --- a/hw/bsp/lpc18/family.mk +++ b/hw/bsp/lpc18/family.mk @@ -12,7 +12,7 @@ CFLAGS += \ -DCFG_TUSB_MCU=OPT_MCU_LPC18XX # mcu driver cause following warnings -CFLAGS += -Wno-error=unused-parameter -Wno-error=cast-qual +CFLAGS_GCC += -Wno-error=unused-parameter -Wno-error=cast-qual LDFLAGS_GCC += --specs=nosys.specs --specs=nano.specs diff --git a/hw/bsp/lpc40/family.mk b/hw/bsp/lpc40/family.mk index ef9fe57b2..06155c760 100644 --- a/hw/bsp/lpc40/family.mk +++ b/hw/bsp/lpc40/family.mk @@ -13,7 +13,7 @@ CFLAGS += \ -DCFG_TUSB_MCU=OPT_MCU_LPC40XX # mcu driver cause following warnings -CFLAGS += -Wno-error=strict-prototypes -Wno-error=unused-parameter -Wno-error=cast-qual +CFLAGS_GCC += -Wno-error=strict-prototypes -Wno-error=unused-parameter -Wno-error=cast-qual LDFLAGS_GCC += --specs=nosys.specs --specs=nano.specs diff --git a/hw/bsp/lpc43/family.mk b/hw/bsp/lpc43/family.mk index e1406aae7..4a2ba6ec3 100644 --- a/hw/bsp/lpc43/family.mk +++ b/hw/bsp/lpc43/family.mk @@ -5,14 +5,14 @@ include ${TOP}/${BOARD_PATH}/board.mk CPU_CORE ?= cortex-m4 CFLAGS += \ - -flto \ - -nostdlib \ -DCORE_M4 \ -D__USE_LPCOPEN \ -DCFG_TUSB_MCU=OPT_MCU_LPC43XX # mcu driver cause following warnings -CFLAGS += \ +CFLAGS_GCC += \ + -flto \ + -nostdlib \ -Wno-error=unused-parameter \ -Wno-error=cast-qual \ -Wno-error=incompatible-pointer-types \ diff --git a/hw/bsp/stm32f4/family.mk b/hw/bsp/stm32f4/family.mk index 51ff43a60..c3c41dc3f 100644 --- a/hw/bsp/stm32f4/family.mk +++ b/hw/bsp/stm32f4/family.mk @@ -1,6 +1,5 @@ UF2_FAMILY_ID = 0x57755a57 ST_FAMILY = f4 -DEPS_SUBMODULES += lib/CMSIS_5 hw/mcu/st/cmsis_device_$(ST_FAMILY) hw/mcu/st/stm32$(ST_FAMILY)xx_hal_driver ST_CMSIS = hw/mcu/st/cmsis_device_$(ST_FAMILY) ST_HAL_DRIVER = hw/mcu/st/stm32$(ST_FAMILY)xx_hal_driver diff --git a/hw/bsp/stm32u5/boards/b_u585i_iot2a/board.mk b/hw/bsp/stm32u5/boards/b_u585i_iot2a/board.mk index ae63afef3..0a2c47030 100644 --- a/hw/bsp/stm32u5/boards/b_u585i_iot2a/board.mk +++ b/hw/bsp/stm32u5/boards/b_u585i_iot2a/board.mk @@ -1,11 +1,9 @@ +MCU_VARIANT = stm32u585xx CFLAGS += \ -DSTM32U585xx \ # All source paths should be relative to the top level. LD_FILE = ${FAMILY_PATH}/linker/STM32U575xx_FLASH.ld -SRC_S += $(ST_CMSIS)/Source/Templates/gcc/startup_stm32u575xx.s - -MCU_VARIANT = stm32u585xx # For flash-jlink target JLINK_DEVICE = stm32u585zi diff --git a/hw/bsp/stm32u5/boards/stm32u545nucleo/board.mk b/hw/bsp/stm32u5/boards/stm32u545nucleo/board.mk index 072c595fb..0aba57ce4 100644 --- a/hw/bsp/stm32u5/boards/stm32u545nucleo/board.mk +++ b/hw/bsp/stm32u5/boards/stm32u545nucleo/board.mk @@ -1,11 +1,9 @@ +MCU_VARIANT = stm32u545xx CFLAGS += \ -DSTM32U545xx \ # All source paths should be relative to the top level. LD_FILE = ${FAMILY_PATH}/linker/STM32U545xx_FLASH.ld -SRC_S += $(ST_CMSIS)/Source/Templates/gcc/startup_stm32u545xx.s - -MCU_VARIANT = stm32u545xx # For flash-jlink target JLINK_DEVICE = stm32u545re diff --git a/hw/bsp/stm32u5/boards/stm32u575eval/board.mk b/hw/bsp/stm32u5/boards/stm32u575eval/board.mk index fee56f2ba..4bc9fea10 100644 --- a/hw/bsp/stm32u5/boards/stm32u575eval/board.mk +++ b/hw/bsp/stm32u5/boards/stm32u575eval/board.mk @@ -1,11 +1,9 @@ +MCU_VARIANT = stm32u575xx CFLAGS += \ -DSTM32U575xx \ # All source paths should be relative to the top level. LD_FILE = ${FAMILY_PATH}/linker/STM32U575xx_FLASH.ld -SRC_S += $(ST_CMSIS)/Source/Templates/gcc/startup_stm32u575xx.s - -MCU_VARIANT = stm32u575xx # For flash-jlink target JLINK_DEVICE = stm32u575ai diff --git a/hw/bsp/stm32u5/boards/stm32u575nucleo/board.mk b/hw/bsp/stm32u5/boards/stm32u575nucleo/board.mk index c83ec3999..d09dc5c46 100644 --- a/hw/bsp/stm32u5/boards/stm32u575nucleo/board.mk +++ b/hw/bsp/stm32u5/boards/stm32u575nucleo/board.mk @@ -1,11 +1,9 @@ +MCU_VARIANT = stm32u575xx CFLAGS += \ -DSTM32U575xx \ # All source paths should be relative to the top level. LD_FILE = ${FAMILY_PATH}/linker/STM32U575xx_FLASH.ld -SRC_S += $(ST_CMSIS)/Source/Templates/gcc/startup_stm32u575xx.s - -MCU_VARIANT = stm32u575xx # For flash-jlink target JLINK_DEVICE = stm32u575zi diff --git a/hw/bsp/stm32u5/boards/stm32u5a5nucleo/board.mk b/hw/bsp/stm32u5/boards/stm32u5a5nucleo/board.mk index 4bebe3330..c9fdbac1a 100644 --- a/hw/bsp/stm32u5/boards/stm32u5a5nucleo/board.mk +++ b/hw/bsp/stm32u5/boards/stm32u5a5nucleo/board.mk @@ -1,3 +1,4 @@ +MCU_VARIANT = stm32u5a5xx CFLAGS += \ -DSTM32U5A5xx \ -DHSE_VALUE=16000000UL \ @@ -5,8 +6,5 @@ CFLAGS += \ # All source paths should be relative to the top level. LD_FILE = ${BOARD_PATH}/STM32U5A5ZJTXQ_FLASH.ld -SRC_S += $(ST_CMSIS)/Source/Templates/gcc/startup_stm32u5a5xx.s - -MCU_VARIANT = stm32u5a5xx # For flash-jlink target JLINK_DEVICE = stm32u575zi diff --git a/hw/bsp/stm32u5/family.mk b/hw/bsp/stm32u5/family.mk index 05fe4608a..7fc728dcf 100644 --- a/hw/bsp/stm32u5/family.mk +++ b/hw/bsp/stm32u5/family.mk @@ -57,5 +57,12 @@ INC += \ $(TOP)/$(ST_HAL_DRIVER)/Inc \ $(TOP)/$(BOARD_PATH) +# Startup +SRC_S_GCC += $(ST_CMSIS)/Source/Templates/gcc/startup_$(MCU_VARIANT).s +SRC_S_IAR += $(ST_CMSIS)/Source/Templates/iar/startup_$(MCU_VARIANT).s + +# Linker +LD_FILE_IAR ?= $(ST_CMSIS)/Source/Templates/iar/linker/$(MCU_VARIANT)_flash.icf + # flash target using on-board stlink flash: flash-stlink diff --git a/hw/bsp/stm32wb/family.mk b/hw/bsp/stm32wb/family.mk index de8372eea..a80ff6f5b 100644 --- a/hw/bsp/stm32wb/family.mk +++ b/hw/bsp/stm32wb/family.mk @@ -9,14 +9,12 @@ include $(TOP)/$(BOARD_PATH)/board.mk CPU_CORE ?= cortex-m4 CFLAGS += \ - -flto \ - -nostdlib -nostartfiles \ -DCFG_TUSB_MCU=OPT_MCU_STM32WB -# suppress warning caused by vendor mcu driver -CFLAGS += -Wno-error=cast-align -Wno-unused-parameter - -LD_FILE ?= ${ST_CMSIS}/Source/Templates/gcc/linker/${MCU_VARIANT}_flash_cm4.ld +CFLAGS_GCC += \ + -flto \ + -nostdlib -nostartfiles \ + -Wno-error=cast-align -Wno-unused-parameter LDFLAGS_GCC += -specs=nosys.specs -specs=nano.specs @@ -25,19 +23,26 @@ SRC_C += \ $(ST_CMSIS)/Source/Templates/system_${ST_PREFIX}.c \ $(ST_HAL_DRIVER)/Src/${ST_PREFIX}_hal.c \ $(ST_HAL_DRIVER)/Src/${ST_PREFIX}_hal_cortex.c \ + $(ST_HAL_DRIVER)/Src/${ST_PREFIX}_hal_pwr.c \ $(ST_HAL_DRIVER)/Src/${ST_PREFIX}_hal_pwr_ex.c \ $(ST_HAL_DRIVER)/Src/${ST_PREFIX}_hal_rcc.c \ $(ST_HAL_DRIVER)/Src/${ST_PREFIX}_hal_rcc_ex.c \ $(ST_HAL_DRIVER)/Src/${ST_PREFIX}_hal_uart.c \ $(ST_HAL_DRIVER)/Src/${ST_PREFIX}_hal_gpio.c -SRC_S += $(ST_CMSIS)/Source/Templates/gcc/startup_${MCU_VARIANT}_cm4.s - INC += \ $(TOP)/$(BOARD_PATH) \ $(TOP)/lib/CMSIS_5/CMSIS/Core/Include \ $(TOP)/$(ST_CMSIS)/Include \ $(TOP)/$(ST_HAL_DRIVER)/Inc +# Startup +SRC_S_GCC += $(ST_CMSIS)/Source/Templates/gcc/startup_$(MCU_VARIANT)_cm4.s +SRC_S_IAR += $(ST_CMSIS)/Source/Templates/iar/startup_$(MCU_VARIANT)_cm4.s + +# Linker +LD_FILE_GCC ?= ${ST_CMSIS}/Source/Templates/gcc/linker/${MCU_VARIANT}_flash_cm4.ld +LD_FILE_IAR ?= $(ST_CMSIS)/Source/Templates/iar/linker/$(MCU_VARIANT)_flash_cm4.icf + # flash target using on-board stlink flash: flash-stlink diff --git a/src/class/msc/msc_device.c b/src/class/msc/msc_device.c index 6670045aa..87c77c9a7 100644 --- a/src/class/msc/msc_device.c +++ b/src/class/msc/msc_device.c @@ -344,7 +344,7 @@ bool mscd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t msc_csw_t * p_csw = &p_msc->csw; switch (p_msc->stage) { - case MSC_STAGE_CMD: + case MSC_STAGE_CMD: { //------------- new CBW received -------------// // Complete IN while waiting for CMD is usually Status of previous SCSI op, ignore it if (ep_addr != p_msc->ep_out) { @@ -441,7 +441,8 @@ bool mscd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t } } } - break; + break; + } case MSC_STAGE_DATA: TU_LOG_DRV(" SCSI Data [Lun%u]\r\n", p_cbw->lun); -- cgit v1.3.1 From f5944d35b093f63a9bd66a1b4a7414b7db5dce44 Mon Sep 17 00:00:00 2001 From: ZakDanger Date: Fri, 9 May 2025 18:17:07 +1000 Subject: vendor device open fix for descriptor parsing --- src/class/vendor/vendor_device.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'src/class') diff --git a/src/class/vendor/vendor_device.c b/src/class/vendor/vendor_device.c index 2fc0ac944..d7cef20ff 100644 --- a/src/class/vendor/vendor_device.c +++ b/src/class/vendor/vendor_device.c @@ -196,8 +196,9 @@ void vendord_reset(uint8_t rhport) { uint16_t vendord_open(uint8_t rhport, const tusb_desc_interface_t* desc_itf, uint16_t max_len) { TU_VERIFY(TUSB_CLASS_VENDOR_SPECIFIC == desc_itf->bInterfaceClass, 0); - const uint8_t* p_desc = tu_desc_next(desc_itf); - const uint8_t* desc_end = (uint8_t const*)desc_itf + max_len; + const uint8_t* p_desc = (const uint8_t*)desc_itf; + const uint8_t* desc_end = p_desc + max_len; + p_desc = tu_desc_next(p_desc); // Find available interface vendord_interface_t* p_vendor = NULL; @@ -235,6 +236,11 @@ uint16_t vendord_open(uint8_t rhport, const tusb_desc_interface_t* desc_itf, uin p_desc = tu_desc_next(p_desc); } + // skip any other descriptors until the next interface descriptor, or end of all descriptors + while ( (TUSB_DESC_INTERFACE != tu_desc_type(p_desc)) && (p_desc < desc_end) ) { + p_desc = tu_desc_next(p_desc); + } + return (uint16_t) ((uintptr_t) p_desc - (uintptr_t) desc_itf); } -- cgit v1.3.1 From ae8c00f5d79629eddb22b9b442cd72f892b5eef6 Mon Sep 17 00:00:00 2001 From: ZakDanger Date: Fri, 9 May 2025 20:42:19 +1000 Subject: revert 'end fix' --- src/class/vendor/vendor_device.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'src/class') diff --git a/src/class/vendor/vendor_device.c b/src/class/vendor/vendor_device.c index d7cef20ff..6f41a9f3b 100644 --- a/src/class/vendor/vendor_device.c +++ b/src/class/vendor/vendor_device.c @@ -196,9 +196,8 @@ void vendord_reset(uint8_t rhport) { uint16_t vendord_open(uint8_t rhport, const tusb_desc_interface_t* desc_itf, uint16_t max_len) { TU_VERIFY(TUSB_CLASS_VENDOR_SPECIFIC == desc_itf->bInterfaceClass, 0); - const uint8_t* p_desc = (const uint8_t*)desc_itf; - const uint8_t* desc_end = p_desc + max_len; - p_desc = tu_desc_next(p_desc); + const uint8_t* p_desc = tu_desc_next(p_desc); + const uint8_t* desc_end = (const uint8_t*)desc_itf + max_len; // Find available interface vendord_interface_t* p_vendor = NULL; -- cgit v1.3.1 From 6b30a61bdbeeccf2b9447971c17d75946881b64f Mon Sep 17 00:00:00 2001 From: ZakDanger Date: Fri, 9 May 2025 20:44:11 +1000 Subject: revert 'end fix' --- src/class/vendor/vendor_device.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/class') diff --git a/src/class/vendor/vendor_device.c b/src/class/vendor/vendor_device.c index 6f41a9f3b..8d6e980a2 100644 --- a/src/class/vendor/vendor_device.c +++ b/src/class/vendor/vendor_device.c @@ -196,7 +196,7 @@ void vendord_reset(uint8_t rhport) { uint16_t vendord_open(uint8_t rhport, const tusb_desc_interface_t* desc_itf, uint16_t max_len) { TU_VERIFY(TUSB_CLASS_VENDOR_SPECIFIC == desc_itf->bInterfaceClass, 0); - const uint8_t* p_desc = tu_desc_next(p_desc); + const uint8_t* p_desc = tu_desc_next(desc_itf); const uint8_t* desc_end = (const uint8_t*)desc_itf + max_len; // Find available interface -- cgit v1.3.1 From a2117d5d0fb0eea1f76fe7db25642df7a9c83324 Mon Sep 17 00:00:00 2001 From: HiFiPhile Date: Fri, 9 May 2025 16:43:19 +0200 Subject: simplify vendord_open parsing loop Signed-off-by: HiFiPhile --- src/class/vendor/vendor_device.c | 37 ++++++++++++------------------------- 1 file changed, 12 insertions(+), 25 deletions(-) (limited to 'src/class') diff --git a/src/class/vendor/vendor_device.c b/src/class/vendor/vendor_device.c index 8d6e980a2..0f0b0cbb2 100644 --- a/src/class/vendor/vendor_device.c +++ b/src/class/vendor/vendor_device.c @@ -210,33 +210,20 @@ uint16_t vendord_open(uint8_t rhport, const tusb_desc_interface_t* desc_itf, uin TU_VERIFY(p_vendor, 0); p_vendor->itf_num = desc_itf->bInterfaceNumber; - uint8_t found_ep = 0; - while (found_ep < desc_itf->bNumEndpoints) { - // skip non-endpoint descriptors - while ( (TUSB_DESC_ENDPOINT != tu_desc_type(p_desc)) && (p_desc < desc_end) ) { - p_desc = tu_desc_next(p_desc); + while (TUSB_DESC_INTERFACE != tu_desc_type(p_desc) && (desc_end - p_desc > 0)) { + if (TUSB_DESC_ENDPOINT == tu_desc_type(p_desc)) { + const tusb_desc_endpoint_t* desc_ep = (const tusb_desc_endpoint_t*) p_desc; + TU_ASSERT(usbd_edpt_open(rhport, desc_ep)); + + if (tu_edpt_dir(desc_ep->bEndpointAddress) == TUSB_DIR_IN) { + tu_edpt_stream_open(&p_vendor->tx.stream, desc_ep); + tud_vendor_n_write_flush((uint8_t)(p_vendor - _vendord_itf)); + } else { + tu_edpt_stream_open(&p_vendor->rx.stream, desc_ep); + TU_ASSERT(tu_edpt_stream_read_xfer(rhport, &p_vendor->rx.stream) > 0, 0); // prepare for incoming data + } } - if (p_desc >= desc_end) { - break; - } - - const tusb_desc_endpoint_t* desc_ep = (const tusb_desc_endpoint_t*) p_desc; - TU_ASSERT(usbd_edpt_open(rhport, desc_ep)); - found_ep++; - - if (tu_edpt_dir(desc_ep->bEndpointAddress) == TUSB_DIR_IN) { - tu_edpt_stream_open(&p_vendor->tx.stream, desc_ep); - tud_vendor_n_write_flush((uint8_t)(p_vendor - _vendord_itf)); - } else { - tu_edpt_stream_open(&p_vendor->rx.stream, desc_ep); - TU_ASSERT(tu_edpt_stream_read_xfer(rhport, &p_vendor->rx.stream) > 0, 0); // prepare for incoming data - } - - p_desc = tu_desc_next(p_desc); - } - // skip any other descriptors until the next interface descriptor, or end of all descriptors - while ( (TUSB_DESC_INTERFACE != tu_desc_type(p_desc)) && (p_desc < desc_end) ) { p_desc = tu_desc_next(p_desc); } -- cgit v1.3.1 From baf67539fc2d328a6274c35c18c90da27c37bc60 Mon Sep 17 00:00:00 2001 From: hathach Date: Tue, 13 May 2025 10:28:42 +0700 Subject: fix warnings, minor clean up --- .github/actions/setup_toolchain/toolchain.json | 2 +- examples/host/cdc_msc_hid/src/hid_app.c | 100 ++++++++----------------- src/class/cdc/cdc_host.c | 2 +- src/class/hid/hid_host.c | 6 +- src/host/hub.c | 1 - src/host/usbh.c | 5 +- 6 files changed, 41 insertions(+), 75 deletions(-) (limited to 'src/class') diff --git a/.github/actions/setup_toolchain/toolchain.json b/.github/actions/setup_toolchain/toolchain.json index ea07ca344..f7123ef11 100644 --- a/.github/actions/setup_toolchain/toolchain.json +++ b/.github/actions/setup_toolchain/toolchain.json @@ -1,7 +1,7 @@ { "aarch64-gcc": "https://developer.arm.com/-/media/Files/downloads/gnu-a/10.3-2021.07/binrel/gcc-arm-10.3-2021.07-x86_64-aarch64-none-elf.tar.xz", "arm-clang": "https://github.com/ARM-software/LLVM-embedded-toolchain-for-Arm/releases/download/release-19.1.1/LLVM-ET-Arm-19.1.1-Linux-x86_64.tar.xz", - "arm-gcc": "https://github.com/xpack-dev-tools/gcc-xpack/releases/download/v14.2.0-1/xpack-gcc-14.2.0-1-linux-x64.tar.gz", + "arm-gcc": "https://github.com/xpack-dev-tools/arm-none-eabi-gcc-xpack/releases/download/v14.2.1-1.1/xpack-arm-none-eabi-gcc-14.2.1-1.1-linux-x64.tar.gz", "msp430-gcc": "http://software-dl.ti.com/msp430/msp430_public_sw/mcu/msp430/MSPGCC/9_2_0_0/export/msp430-gcc-9.2.0.50_linux64.tar.bz2", "riscv-gcc": "https://github.com/xpack-dev-tools/riscv-none-elf-gcc-xpack/releases/download/v13.2.0-2/xpack-riscv-none-elf-gcc-13.2.0-2-linux-x64.tar.gz", "rx-gcc": "https://github.com/hathach/rx_device/releases/download/0.0.1/gcc-8.3.0.202411-GNURX-ELF.run", diff --git a/examples/host/cdc_msc_hid/src/hid_app.c b/examples/host/cdc_msc_hid/src/hid_app.c index a751c9c80..6f01d6f45 100644 --- a/examples/host/cdc_msc_hid/src/hid_app.c +++ b/examples/host/cdc_msc_hid/src/hid_app.c @@ -29,14 +29,9 @@ //--------------------------------------------------------------------+ // MACRO TYPEDEF CONSTANT ENUM DECLARATION //--------------------------------------------------------------------+ +#define MAX_REPORT 4 -// If your host terminal support ansi escape code such as TeraTerm -// it can be use to simulate mouse cursor movement within terminal -#define USE_ANSI_ESCAPE 0 - -#define MAX_REPORT 4 - -static uint8_t const keycode2ascii[128][2] = { HID_KEYCODE_TO_ASCII }; +static uint8_t const keycode2ascii[128][2] = {HID_KEYCODE_TO_ASCII}; // Each HID instance can has multiple reports static struct { @@ -45,8 +40,8 @@ static struct { } hid_info[CFG_TUH_HID]; 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); +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_task(void) { // nothing to do @@ -70,7 +65,7 @@ void tuh_hid_mount_cb(uint8_t dev_addr, uint8_t instance, uint8_t const *desc_re printf("HID Interface Protocol = %s\r\n", protocol_str[itf_protocol]); - // By default host stack will use activate boot protocol on supported interface. + // By default, host stack will use boot protocol on supported interface. // Therefore for this simple example, we only need to parse generic report descriptor (with built-in parser) if (itf_protocol == HID_ITF_PROTOCOL_NONE) { hid_info[instance].report_count = tuh_hid_parse_report_descriptor(hid_info[instance].report_info, MAX_REPORT, desc_report, desc_len); @@ -121,7 +116,7 @@ void tuh_hid_report_received_cb(uint8_t dev_addr, uint8_t instance, uint8_t cons //--------------------------------------------------------------------+ // look up new key in previous keys -static inline bool find_key_in_report(hid_keyboard_report_t const* report, uint8_t keycode) { +static inline bool find_key_in_report(hid_keyboard_report_t const *report, uint8_t keycode) { for (uint8_t i = 0; i < 6; i++) { if (report->keycode[i] == keycode) { return true; @@ -130,28 +125,25 @@ static inline bool find_key_in_report(hid_keyboard_report_t const* report, uint8 return false; } -static void process_kbd_report(hid_keyboard_report_t const *report) -{ - static hid_keyboard_report_t prev_report = { 0, 0, {0} }; // previous report to check key released +static void process_kbd_report(hid_keyboard_report_t const *report) { + static hid_keyboard_report_t prev_report = {0, 0, {0}};// previous report to check key released //------------- example code ignore control (non-printable) key affects -------------// - for(uint8_t i=0; i<6; i++) - { - if ( report->keycode[i] ) - { - if ( find_key_in_report(&prev_report, report->keycode[i]) ) - { + for (uint8_t i = 0; i < 6; i++) { + if (report->keycode[i]) { + if (find_key_in_report(&prev_report, report->keycode[i])) { // exist in previous report means the current key is holding - }else - { + } else { // not existed in previous report means the current key is pressed bool const is_shift = report->modifier & (KEYBOARD_MODIFIER_LEFTSHIFT | KEYBOARD_MODIFIER_RIGHTSHIFT); uint8_t ch = keycode2ascii[report->keycode[i]][is_shift ? 1 : 0]; putchar(ch); - if ( ch == '\r' ) putchar('\n'); // added new line for enter key + if (ch == '\r') { + putchar('\n'); + } - #ifndef __ICCARM__ // TODO IAR doesn't support stream control ? - fflush(stdout); // flush right away, else nanolib will wait for newline + #ifndef __ICCARM__ // TODO IAR doesn't support stream control ? + fflush(stdout);// flush right away, else nanolib will wait for newline #endif } } @@ -166,55 +158,22 @@ static void process_kbd_report(hid_keyboard_report_t const *report) //--------------------------------------------------------------------+ static void cursor_movement(int8_t x, int8_t y, int8_t wheel) { -#if USE_ANSI_ESCAPE - // Move X using ansi escape - if ( x < 0) - { - printf(ANSI_CURSOR_BACKWARD(%d), (-x)); // move left - }else if ( x > 0) - { - printf(ANSI_CURSOR_FORWARD(%d), x); // move right - } - - // Move Y using ansi escape - if ( y < 0) - { - printf(ANSI_CURSOR_UP(%d), (-y)); // move up - }else if ( y > 0) - { - printf(ANSI_CURSOR_DOWN(%d), y); // move down - } - - // Scroll using ansi escape - if (wheel < 0) - { - printf(ANSI_SCROLL_UP(%d), (-wheel)); // scroll up - }else if (wheel > 0) - { - printf(ANSI_SCROLL_DOWN(%d), wheel); // scroll down - } - - printf("\r\n"); -#else printf("(%d %d %d)\r\n", x, y, wheel); -#endif } -static void process_mouse_report(hid_mouse_report_t const * report) -{ - static hid_mouse_report_t prev_report = { 0 }; +static void process_mouse_report(hid_mouse_report_t const *report) { + static hid_mouse_report_t prev_report = {0}; - //------------- button state -------------// + // button state uint8_t button_changed_mask = report->buttons ^ prev_report.buttons; - if ( button_changed_mask & report->buttons) - { + if (button_changed_mask & report->buttons) { printf(" %c%c%c ", - report->buttons & MOUSE_BUTTON_LEFT ? 'L' : '-', - report->buttons & MOUSE_BUTTON_MIDDLE ? 'M' : '-', - report->buttons & MOUSE_BUTTON_RIGHT ? 'R' : '-'); + report->buttons & MOUSE_BUTTON_LEFT ? 'L' : '-', + report->buttons & MOUSE_BUTTON_MIDDLE ? 'M' : '-', + report->buttons & MOUSE_BUTTON_RIGHT ? 'R' : '-'); } - //------------- cursor movement -------------// + // cursor movement cursor_movement(report->x, report->y, report->wheel); } @@ -263,18 +222,23 @@ static void process_generic_report(uint8_t dev_addr, uint8_t instance, uint8_t c if (rpt_info->usage_page == HID_USAGE_PAGE_DESKTOP) { switch (rpt_info->usage) { case HID_USAGE_DESKTOP_KEYBOARD: - TU_LOG1("HID receive keyboard report\r\n"); + TU_LOG2("HID receive keyboard report\r\n"); // Assume keyboard follow boot report layout process_kbd_report((hid_keyboard_report_t const *) report); break; case HID_USAGE_DESKTOP_MOUSE: - TU_LOG1("HID receive mouse report\r\n"); + TU_LOG2("HID receive mouse report\r\n"); // Assume mouse follow boot report layout process_mouse_report((hid_mouse_report_t const *) report); break; default: + printf("report[%u] ", rpt_info->report_id); + for (uint8_t i = 0; i < len; i++) { + printf("%02X ", report[i]); + } + printf("\r\n"); break; } } diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index 4058857c5..bf245db3f 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -672,7 +672,7 @@ void cdch_close(uint8_t daddr) { bool cdch_xfer_cb(uint8_t daddr, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes) { // TODO handle stall response, retry failed transfer ... - TU_ASSERT(event == XFER_RESULT_SUCCESS); + TU_VERIFY(event == XFER_RESULT_SUCCESS); uint8_t const idx = get_idx_by_ep_addr(daddr, ep_addr); cdch_interface_t * p_cdc = get_itf(idx); diff --git a/src/class/hid/hid_host.c b/src/class/hid/hid_host.c index a3cc7d6d7..57e437196 100644 --- a/src/class/hid/hid_host.c +++ b/src/class/hid/hid_host.c @@ -444,7 +444,7 @@ bool hidh_xfer_cb(uint8_t daddr, uint8_t ep_addr, xfer_result_t result, uint32_t hidh_epbuf_t* epbuf = get_hid_epbuf(idx); if (dir == TUSB_DIR_IN) { - TU_LOG_DRV(" Get Report callback (%u, %u)\r\n", daddr, idx); + TU_LOG_DRV(" [idx=%u] Get Report callback\r\n", idx); TU_LOG3_MEM(epbuf->epin, xferred_bytes, 2); tuh_hid_report_received_cb(daddr, idx, epbuf->epin, (uint16_t) xferred_bytes); } else { @@ -461,7 +461,9 @@ void hidh_close(uint8_t daddr) { hidh_interface_t* p_hid = &_hidh_itf[i]; 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); + } tu_memclr(p_hid, sizeof(hidh_interface_t)); } } diff --git a/src/host/hub.c b/src/host/hub.c index 0ed0e0c42..0b172a596 100644 --- a/src/host/hub.c +++ b/src/host/hub.c @@ -201,7 +201,6 @@ bool hub_port_get_status(uint8_t hub_addr, uint8_t hub_port, void* resp, bool hub_port_get_status_local(uint8_t hub_addr, uint8_t hub_port, hub_port_status_response_t* resp) { (void) hub_port; - TU_VERIFY(hub_addr > CFG_TUH_DEVICE_MAX); hub_interface_t* p_hub = get_hub_itf(hub_addr); *resp = p_hub->port_status; return true; diff --git a/src/host/usbh.c b/src/host/usbh.c index a3d79a105..8ab1402dc 100644 --- a/src/host/usbh.c +++ b/src/host/usbh.c @@ -579,7 +579,8 @@ void tuh_task_ext(uint32_t timeout_ms, bool in_isr) { uint8_t const epnum = tu_edpt_number(ep_addr); uint8_t const ep_dir = (uint8_t) tu_edpt_dir(ep_addr); - TU_LOG_USBH("on EP %02X with %u bytes: %s\r\n", ep_addr, (unsigned int) event.xfer_complete.len, tu_str_xfer_result[event.xfer_complete.result]); + TU_LOG_USBH("[:%u] on EP %02X with %u bytes: %s\r\n", + event.dev_addr, ep_addr, (unsigned int) event.xfer_complete.len, tu_str_xfer_result[event.xfer_complete.result]); if (event.dev_addr == 0) { // device 0 only has control endpoint @@ -618,7 +619,7 @@ void tuh_task_ext(uint32_t timeout_ms, bool in_isr) { uint8_t drv_id = dev->ep2drv[epnum][ep_dir]; usbh_class_driver_t const* driver = get_driver(drv_id); if (driver) { - TU_LOG_USBH("%s xfer callback\r\n", driver->name); + 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); } else { -- cgit v1.3.1 From 67389f37f2a9dabc33b9f180d49c827e9616572c Mon Sep 17 00:00:00 2001 From: hathach Date: Fri, 16 May 2025 16:39:53 +0700 Subject: follow up to pr3118, interface also end with IAD. Add more checks --- src/class/vendor/vendor_device.c | 22 +++++++++++++++------- src/common/tusb_types.h | 6 ++++++ 2 files changed, 21 insertions(+), 7 deletions(-) (limited to 'src/class') diff --git a/src/class/vendor/vendor_device.c b/src/class/vendor/vendor_device.c index 0f0b0cbb2..7f1fd8c41 100644 --- a/src/class/vendor/vendor_device.c +++ b/src/class/vendor/vendor_device.c @@ -196,8 +196,8 @@ void vendord_reset(uint8_t rhport) { uint16_t vendord_open(uint8_t rhport, const tusb_desc_interface_t* desc_itf, uint16_t max_len) { TU_VERIFY(TUSB_CLASS_VENDOR_SPECIFIC == desc_itf->bInterfaceClass, 0); - const uint8_t* p_desc = tu_desc_next(desc_itf); const uint8_t* desc_end = (const uint8_t*)desc_itf + max_len; + const uint8_t* p_desc = tu_desc_next(desc_itf); // Find available interface vendord_interface_t* p_vendor = NULL; @@ -210,17 +210,25 @@ uint16_t vendord_open(uint8_t rhport, const tusb_desc_interface_t* desc_itf, uin TU_VERIFY(p_vendor, 0); p_vendor->itf_num = desc_itf->bInterfaceNumber; - while (TUSB_DESC_INTERFACE != tu_desc_type(p_desc) && (desc_end - p_desc > 0)) { - if (TUSB_DESC_ENDPOINT == tu_desc_type(p_desc)) { + while (tu_desc_is_valid(p_desc, desc_end)) { + const uint8_t desc_type = tu_desc_type(p_desc); + if (desc_type == TUSB_DESC_INTERFACE || desc_type == TUSB_DESC_INTERFACE_ASSOCIATION) { + break; // end of this interface + } else if (desc_type == TUSB_DESC_ENDPOINT) { const tusb_desc_endpoint_t* desc_ep = (const tusb_desc_endpoint_t*) p_desc; TU_ASSERT(usbd_edpt_open(rhport, desc_ep)); + // open endpoint stream, skip if already opened if (tu_edpt_dir(desc_ep->bEndpointAddress) == TUSB_DIR_IN) { - tu_edpt_stream_open(&p_vendor->tx.stream, desc_ep); - tud_vendor_n_write_flush((uint8_t)(p_vendor - _vendord_itf)); + if (p_vendor->tx.stream.ep_addr == 0) { + tu_edpt_stream_open(&p_vendor->tx.stream, desc_ep); + tud_vendor_n_write_flush((uint8_t)(p_vendor - _vendord_itf)); + } } else { - tu_edpt_stream_open(&p_vendor->rx.stream, desc_ep); - TU_ASSERT(tu_edpt_stream_read_xfer(rhport, &p_vendor->rx.stream) > 0, 0); // prepare for incoming data + if (p_vendor->rx.stream.ep_addr == 0) { + tu_edpt_stream_open(&p_vendor->rx.stream, desc_ep); + TU_ASSERT(tu_edpt_stream_read_xfer(rhport, &p_vendor->rx.stream) > 0, 0); // prepare for incoming data + } } } diff --git a/src/common/tusb_types.h b/src/common/tusb_types.h index e000a4bd3..fd7f01b67 100644 --- a/src/common/tusb_types.h +++ b/src/common/tusb_types.h @@ -586,6 +586,12 @@ TU_ATTR_ALWAYS_INLINE static inline uint8_t tu_desc_subtype(void const* desc) { return ((uint8_t const*) desc)[DESC_OFFSET_SUBTYPE]; } +TU_ATTR_ALWAYS_INLINE static inline uint8_t tu_desc_is_valid(void const* desc, uint8_t const* desc_end) { + const uint8_t* desc8 = (uint8_t const*) desc; + return (desc8 < desc_end) && (tu_desc_next(desc) <= desc_end); +} + + // find descriptor that match byte1 (type) uint8_t const * tu_desc_find(uint8_t const* desc, uint8_t const* end, uint8_t byte1); -- cgit v1.3.1 From 5de4a23abe315ecc5f9387ced910f54e29e0e69e Mon Sep 17 00:00:00 2001 From: Andrew Leech Date: Tue, 27 May 2025 15:06:05 +1000 Subject: Add USB NCM link state control support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This adds the ability to dynamically control the network link state for NCM devices. The host OS will see the network interface as connected/disconnected based on the link state. New API: - tud_network_link_state(rhport, is_up): Set link up/down state Example updates: - Added button control to toggle link state - Fixed LWIP integration to properly handle link state changes - Added printf to show correct protocol (NCM vs RNDIS/ECM) 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- examples/device/net_lwip_webserver/src/lwipopts.h | 1 + examples/device/net_lwip_webserver/src/main.c | 73 +++++++++++++++++++--- .../device/net_lwip_webserver/src/tusb_config.h | 2 + src/class/net/ncm_device.c | 36 ++++++++++- src/class/net/net_device.h | 5 ++ 5 files changed, 107 insertions(+), 10 deletions(-) (limited to 'src/class') diff --git a/examples/device/net_lwip_webserver/src/lwipopts.h b/examples/device/net_lwip_webserver/src/lwipopts.h index 41e8f0d67..04949cef9 100644 --- a/examples/device/net_lwip_webserver/src/lwipopts.h +++ b/examples/device/net_lwip_webserver/src/lwipopts.h @@ -58,6 +58,7 @@ #define LWIP_HTTPD_SSI_INCLUDE_TAG 0 #define LWIP_SINGLE_NETIF 1 +#define LWIP_NETIF_LINK_CALLBACK 1 #define PBUF_POOL_SIZE 4 diff --git a/examples/device/net_lwip_webserver/src/main.c b/examples/device/net_lwip_webserver/src/main.c index 36f402332..41f02576f 100644 --- a/examples/device/net_lwip_webserver/src/main.c +++ b/examples/device/net_lwip_webserver/src/main.c @@ -31,6 +31,12 @@ this appears as either a RNDIS or CDC-ECM USB virtual network adapter; the OS pi RNDIS should be valid on Linux and Windows hosts, and CDC-ECM should be valid on Linux and macOS hosts The MCU appears to the host as IP address 192.168.7.1, and provides a DHCP server, DNS server, and web server. + +Link State Control: +- Press the user button to toggle the network link state (UP/DOWN) +- This simulates "ethernet cable unplugged/plugged" events +- The host OS will see the network interface as disconnected/connected accordingly +- Use this to test network error handling and recovery in host applications */ /* Some smartphones *may* work with this implementation as well, but likely have limited (broken) drivers, @@ -137,6 +143,12 @@ static err_t netif_init_cb(struct netif *netif) { return ERR_OK; } +/* notifies the USB host about the link state change. */ +static void usbnet_netif_link_callback(struct netif *netif) { + bool link_up = netif_is_link_up(netif); + tud_network_link_state(BOARD_TUD_RHPORT, link_up); +} + static void init_lwip(void) { struct netif *netif = &netif_data; @@ -147,11 +159,19 @@ static void init_lwip(void) { memcpy(netif->hwaddr, tud_network_mac_address, sizeof(tud_network_mac_address)); netif->hwaddr[5] ^= 0x01; - netif = netif_add(netif, &ipaddr, &netmask, &gateway, NULL, netif_init_cb, ip_input); + netif = netif_add(netif, &ipaddr, &netmask, &gateway, NULL, netif_init_cb, ethernet_input); #if LWIP_IPV6 netif_create_ip6_linklocal_address(netif, 1); #endif netif_set_default(netif); + +#if LWIP_NETIF_LINK_CALLBACK + // Set the link callback to notify USB host about link state changes + netif_set_link_callback(netif, usbnet_netif_link_callback); + netif_set_link_up(netif); +#else + tud_network_link_state(BOARD_TUD_RHPORT, true); +#endif } /* handle any DNS requests from dns-server */ @@ -171,13 +191,16 @@ bool tud_network_recv_cb(const uint8_t *src, uint16_t size) { if (size) { struct pbuf *p = pbuf_alloc(PBUF_RAW, size, PBUF_POOL); - if (p) { - /* pbuf_alloc() has already initialized struct; all we need to do is copy the data */ - memcpy(p->payload, src, size); - - /* store away the pointer for service_traffic() to later handle */ - received_frame = p; + if (p == NULL) { + printf("ERROR: Failed to allocate pbuf of size %d\n", size); + return false; } + + /* Copy buf to pbuf */ + pbuf_take(p, src, size); + + /* store away the pointer for service_traffic() to later handle */ + received_frame = p; } return true; @@ -194,12 +217,14 @@ uint16_t tud_network_xmit_cb(uint8_t *dst, void *ref, uint16_t arg) { static void service_traffic(void) { /* handle any packet received by tud_network_recv_cb() */ if (received_frame) { + struct netif *netif = &netif_data; // Surrender ownership of our pbuf unless there was an error // Only call pbuf_free if not Ok else it will panic with "pbuf_free: p->ref > 0" // or steal it from whatever took ownership of it with undefined consequences. // See: https://savannah.nongnu.org/patch/index.php?10121 - if (ethernet_input(received_frame, &netif_data)!=ERR_OK) { - pbuf_free(received_frame); + if (netif->input(received_frame, netif) != ERR_OK) { + printf("ERROR: netif input failed\n"); + pbuf_free(received_frame); } received_frame = NULL; tud_network_recv_renew(); @@ -216,6 +241,28 @@ void tud_network_init_cb(void) { } } +static void handle_link_state_switch(void) { + /* Check for button press to toggle link state */ + static bool last_link_state = true; + static bool last_button_state = false; + bool current_button_state = board_button_read(); + + if (current_button_state && !last_button_state) { + /* Button pressed - toggle link state */ + last_link_state = !last_link_state; + if (last_link_state) { + printf("Link state: UP\n"); + netif_set_link_up(&netif_data); + } else { + printf("Link state: DOWN\n"); + netif_set_link_down(&netif_data); + } + /* LWIP callback will notify USB host about the change */ + } + last_button_state = current_button_state; + +} + int main(void) { /* initialize TinyUSB */ board_init(); @@ -243,15 +290,23 @@ int main(void) { lwiperf_start_tcp_server_default(NULL, NULL); #endif +#if CFG_TUD_NCM + printf("USB NCM network interface initialized\n"); +#elif CFG_TUD_ECM_RNDIS + printf("USB RNDIS/ECM network interface initialized\n"); +#endif + while (1) { tud_task(); service_traffic(); + handle_link_state_switch(); } return 0; } /* lwip has provision for using a mutex, when applicable */ +/* This implementation is for single-threaded use only */ sys_prot_t sys_arch_protect(void) { return 0; } diff --git a/examples/device/net_lwip_webserver/src/tusb_config.h b/examples/device/net_lwip_webserver/src/tusb_config.h index 22082fc81..c774f59ff 100644 --- a/examples/device/net_lwip_webserver/src/tusb_config.h +++ b/examples/device/net_lwip_webserver/src/tusb_config.h @@ -85,6 +85,7 @@ extern "C" { #endif // Use different configurations to test all net devices (also due to resource limitations) +#ifndef USE_ECM #if TU_CHECK_MCU(OPT_MCU_LPC15XX, OPT_MCU_LPC40XX, OPT_MCU_LPC51UXX, OPT_MCU_LPC54) #define USE_ECM 1 #elif TU_CHECK_MCU(OPT_MCU_SAMD21, OPT_MCU_SAML21, OPT_MCU_SAML22) @@ -97,6 +98,7 @@ extern "C" { #define USE_ECM 0 #define INCLUDE_IPERF #endif +#endif //-------------------------------------------------------------------- // NCM CLASS CONFIGURATION, SEE "ncm.h" FOR PERFORMANCE TUNING diff --git a/src/class/net/ncm_device.c b/src/class/net/ncm_device.c index f9fda0698..02833c5f1 100644 --- a/src/class/net/ncm_device.c +++ b/src/class/net/ncm_device.c @@ -110,6 +110,7 @@ typedef struct { NOTIFICATION_DONE } notification_xmit_state; // state of notification transmission bool notification_xmit_is_running; // notification is currently transmitted + bool link_is_up; // current link state // misc bool tud_network_recv_renew_active; // tud_network_recv_renew() is active (avoid recursive invocations) @@ -218,7 +219,7 @@ static void notification_xmit(uint8_t rhport, bool force_next) { .direction = TUSB_DIR_IN }, .bRequest = CDC_NOTIF_NETWORK_CONNECTION, - .wValue = 1 /* Connected */, + .wValue = ncm_interface.link_is_up ? 1 : 0, /* Dynamic link state */ .wIndex = ncm_interface.itf_num, .wLength = 0, }, @@ -232,6 +233,7 @@ static void notification_xmit(uint8_t rhport, bool force_next) { ncm_interface.notification_xmit_is_running = true; } else { TU_LOG_DRV(" NOTIFICATION_FINISHED\n"); + ncm_interface.notification_xmit_is_running = false; } } // notification_xmit @@ -755,6 +757,32 @@ static void tud_network_recv_renew_r(uint8_t rhport) { tud_network_recv_renew(); } // tud_network_recv_renew +/** + * Set the link state and send notification to host + */ +void tud_network_link_state(uint8_t rhport, bool is_up) { + TU_LOG_DRV("tud_network_link_state(%d, %d)\n", rhport, is_up); + + if (ncm_interface.link_is_up == is_up) { + // No change in link state + return; + } + + ncm_interface.link_is_up = is_up; + + // Only send notification if we have an active data interface + if (ncm_interface.itf_data_alt != 1) { + TU_LOG_DRV(" link state notification skipped (interface not active)\n"); + return; + } + + // Reset notification state to send link state update + ncm_interface.notification_xmit_state = NOTIFICATION_CONNECTED; + + // Trigger notification transmission + notification_xmit(rhport, false); +} + //----------------------------------------------------------------------------- // // all the netd_*() stuff (interface TinyUSB -> driver) @@ -774,6 +802,12 @@ void netd_init(void) { for (int i = 0; i < RECV_NTB_N; ++i) { ncm_interface.recv_free_ntb[i] = &ncm_epbuf.recv[i].ntb; } + // Default link state - can be configured via CFG_TUD_NCM_DEFAULT_LINK_UP + #ifdef CFG_TUD_NCM_DEFAULT_LINK_UP + ncm_interface.link_is_up = CFG_TUD_NCM_DEFAULT_LINK_UP; + #else + ncm_interface.link_is_up = true; // Default to link up if not set. + #endif } // netd_init /** diff --git a/src/class/net/net_device.h b/src/class/net/net_device.h index 4c9a92f2d..fff2623b7 100644 --- a/src/class/net/net_device.h +++ b/src/class/net/net_device.h @@ -87,6 +87,11 @@ 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 -------------// + +// Set the network link state (up/down) and notify the host +void tud_network_link_state(uint8_t rhport, bool is_up); + //--------------------------------------------------------------------+ // INTERNAL USBD-CLASS DRIVER API //--------------------------------------------------------------------+ -- cgit v1.3.1 From 9021efcacb9d7380bce9d5c9e075b41cb8f28da5 Mon Sep 17 00:00:00 2001 From: Andrew Leech Date: Tue, 27 May 2025 15:06:27 +1000 Subject: Add link state control support for ECM mode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Extends the link state control feature to CDC-ECM mode. RNDIS mode prints state changes but doesn't send notifications to the host yet (would require RNDIS_INDICATE_STATUS_MSG). For ECM: - Tracks link state and sends proper CDC notifications - Handles notification endpoint busy conditions - Only sends connection notification when link is actually up 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- src/class/net/ecm_rndis_device.c | 48 ++++++++++++++++++++++++++++++++++------ 1 file changed, 41 insertions(+), 7 deletions(-) (limited to 'src/class') diff --git a/src/class/net/ecm_rndis_device.c b/src/class/net/ecm_rndis_device.c index a54e6d662..f1a88b3c0 100644 --- a/src/class/net/ecm_rndis_device.c +++ b/src/class/net/ecm_rndis_device.c @@ -81,6 +81,7 @@ typedef struct { static netd_interface_t _netd_itf; CFG_TUD_MEM_SECTION static netd_epbuf_t _netd_epbuf; static bool can_xmit; +static bool ecm_link_is_up = true; // Store link state for ECM mode void tud_network_recv_renew(void) { usbd_edpt_xfer(0, _netd_itf.ep_out, _netd_epbuf.rx, NETD_PACKET_SIZE); @@ -95,7 +96,11 @@ void netd_report(uint8_t *buf, uint16_t len) { const uint8_t rhport = 0; len = tu_min16(len, sizeof(ecm_notify_t)); - TU_VERIFY(usbd_edpt_claim(rhport, _netd_itf.ep_notif), ); + if (!usbd_edpt_claim(rhport, _netd_itf.ep_notif)) { + TU_LOG1("ECM: Failed to claim notification endpoint\n"); + return; + } + memcpy(_netd_epbuf.notify, buf, len); usbd_edpt_xfer(rhport, _netd_itf.ep_notif, _netd_epbuf.notify, len); } @@ -196,11 +201,11 @@ uint16_t netd_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint1 } static void ecm_report(bool nc) { - const ecm_notify_t ecm_notify_nc = { + ecm_notify_t ecm_notify_nc = { .header = { .bmRequestType = 0xA1, .bRequest = 0, /* NETWORK_CONNECTION aka NetworkConnection */ - .wValue = 1, /* Connected */ + .wValue = ecm_link_is_up ? 1 : 0, /* Use current link state */ .wLength = 0, }, }; @@ -286,7 +291,10 @@ bool netd_control_xfer_cb (uint8_t rhport, uint8_t stage, tusb_control_request_t /* the only required CDC-ECM Management Element Request is SetEthernetPacketFilter */ if (0x43 /* SET_ETHERNET_PACKET_FILTER */ == request->bRequest) { tud_control_xfer(rhport, request, NULL, 0); - ecm_report(true); + // Only send connection notification if link is up + if (ecm_link_is_up) { + ecm_report(true); + } } } else { if (request->bmRequestType_bit.direction == TUSB_DIR_IN) { @@ -363,9 +371,8 @@ bool netd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_ } if (_netd_itf.ecm_mode && (ep_addr == _netd_itf.ep_notif)) { - if (sizeof(tusb_control_request_t) == xferred_bytes) { - ecm_report(false); - } + // Notification transfer complete - endpoint is now free + // Don't automatically send speed change notification after link state changes } return true; @@ -398,4 +405,31 @@ void tud_network_xmit(void *ref, uint16_t arg) { do_in_xfer(_netd_epbuf.tx, len); } +// Set the network link state (up/down) and notify the host +void tud_network_link_state(uint8_t rhport, bool is_up) { + (void)rhport; + + if (_netd_itf.ecm_mode) { + ecm_link_is_up = is_up; + + // For ECM mode, send network connection notification only + // Don't trigger speed change notification for link state changes + ecm_notify_t notify = { + .header = { + .bmRequestType = 0xA1, + .bRequest = 0, /* NETWORK_CONNECTION */ + .wValue = is_up ? 1 : 0, /* 0 = disconnected, 1 = connected */ + .wLength = 0, + }, + }; + notify.header.wIndex = _netd_itf.itf_num; + netd_report((uint8_t *)¬ify, sizeof(notify.header)); + } else { + // For RNDIS mode, we would need to implement RNDIS status indication + // This is more complex and requires RNDIS_INDICATE_STATUS_MSG + // For now, RNDIS doesn't support dynamic link state changes + (void)is_up; + } +} + #endif -- cgit v1.3.1 From dc0038f6147584dce64323bb4895a3632c312bc1 Mon Sep 17 00:00:00 2001 From: HiFiPhile Date: Thu, 29 May 2025 13:50:05 +0200 Subject: uac2: remove support fifo Signed-off-by: HiFiPhile --- examples/device/audio_4_channel_mic/src/main.c | 35 - .../device/audio_4_channel_mic/src/tusb_config.h | 15 - .../device/audio_4_channel_mic_freertos/src/main.c | 35 - .../audio_4_channel_mic_freertos/src/tusb_config.h | 15 - src/class/audio/audio_device.c | 872 ++------------------- src/class/audio/audio_device.h | 236 +----- 6 files changed, 74 insertions(+), 1134 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 e8c40309e..f78e48f0c 100644 --- a/examples/device/audio_4_channel_mic/src/main.c +++ b/examples/device/audio_4_channel_mic/src/main.c @@ -69,13 +69,8 @@ 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_N_CHANNELS_TX*CFG_TUD_AUDIO_FUNC_1_SAMPLE_RATE/1000/CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO]; -#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_FUNC_1_N_CHANNELS_TX*CFG_TUD_AUDIO_FUNC_1_SAMPLE_RATE/1000]; -#endif void led_blinking_task(void); void audio_task(void); @@ -106,27 +101,6 @@ 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 = 0; - for (uint16_t cnt = 0; cnt < AUDIO_SAMPLE_RATE/1000; cnt++) - { - // CH0 saw wave - *p_buff++ = dataVal; - // CH1 inverted saw wave - *p_buff++ = 3200 + AUDIO_SAMPLE_RATE/1000 - dataVal; - dataVal+= 32; - } - p_buff = i2s_dummy_buffer[1]; - for (uint16_t cnt = 0; cnt < AUDIO_SAMPLE_RATE/1000; cnt++) - { - // CH3 square wave - *p_buff++ = cnt < (AUDIO_SAMPLE_RATE/1000/2) ? 3400:5000; - // CH4 sinus wave - float t = 2*3.1415f * cnt / (AUDIO_SAMPLE_RATE/1000); - *p_buff++ = (uint16_t)((int16_t)(sinf(t) * 750) + 6000); - } -#else uint16_t * p_buff = i2s_dummy_buffer; uint16_t dataVal = 0; for (uint16_t cnt = 0; cnt < AUDIO_SAMPLE_RATE/1000; cnt++) @@ -142,7 +116,6 @@ int main(void) float t = 2*3.1415f * cnt / (AUDIO_SAMPLE_RATE/1000); *p_buff++ = (uint16_t)((int16_t)(sinf(t) * 750) + 6000); } -#endif while (1) { @@ -195,15 +168,7 @@ void audio_task(void) uint32_t curr_ms = board_millis(); if ( start_ms == curr_ms ) return; // not enough time start_ms = curr_ms; -#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 } //--------------------------------------------------------------------+ 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 46484f847..446a7a32a 100644 --- a/examples/device/audio_4_channel_mic/src/tusb_config.h +++ b/examples/device/audio_4_channel_mic/src/tusb_config.h @@ -115,26 +115,11 @@ 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 1 #define CFG_TUD_AUDIO_EP_IN_FLOW_CONTROL 1 -#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_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 (TUD_OPT_HIGH_SPEED ? 32 : 4) * (CFG_TUD_AUDIO_EP_SZ_IN / CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO) // Example write FIFO every 1ms, so it should be 8 times larger for HS device - -#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 (TUD_OPT_HIGH_SPEED ? 32 : 4) * CFG_TUD_AUDIO_EP_SZ_IN // Example write FIFO every 1ms, so it should be 8 times larger for HS device -#endif - #ifdef __cplusplus } #endif diff --git a/examples/device/audio_4_channel_mic_freertos/src/main.c b/examples/device/audio_4_channel_mic_freertos/src/main.c index c9de4029a..99278b5cc 100644 --- a/examples/device/audio_4_channel_mic_freertos/src/main.c +++ b/examples/device/audio_4_channel_mic_freertos/src/main.c @@ -105,13 +105,8 @@ 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_N_CHANNELS_TX*CFG_TUD_AUDIO_FUNC_1_SAMPLE_RATE/1000/CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO]; -#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_FUNC_1_N_CHANNELS_TX*CFG_TUD_AUDIO_FUNC_1_SAMPLE_RATE/1000]; -#endif void led_blinking_task(void* param); void usb_device_task(void* param); @@ -132,27 +127,6 @@ 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 = 0; - for (uint16_t cnt = 0; cnt < AUDIO_SAMPLE_RATE/1000; cnt++) - { - // CH0 saw wave - *p_buff++ = dataVal; - // CH1 inverted saw wave - *p_buff++ = 3200 + AUDIO_SAMPLE_RATE/1000 - dataVal; - dataVal+= 32; - } - p_buff = i2s_dummy_buffer[1]; - for (uint16_t cnt = 0; cnt < AUDIO_SAMPLE_RATE/1000; cnt++) - { - // CH3 square wave - *p_buff++ = cnt < (AUDIO_SAMPLE_RATE/1000/2) ? 3400:5000; - // CH4 sinus wave - float t = 2*3.1415f * cnt / (AUDIO_SAMPLE_RATE/1000); - *p_buff++ = (uint16_t)((int16_t)(sinf(t) * 750) + 6000); - } -#else uint16_t * p_buff = i2s_dummy_buffer; uint16_t dataVal = 0; for (uint16_t cnt = 0; cnt < AUDIO_SAMPLE_RATE/1000; cnt++) @@ -168,7 +142,6 @@ int main(void) float t = 2*3.1415f * cnt / (AUDIO_SAMPLE_RATE/1000); *p_buff++ = (uint16_t)((int16_t)(sinf(t) * 750) + 6000); } -#endif #if configSUPPORT_STATIC_ALLOCATION // blinky task @@ -269,15 +242,7 @@ void audio_task(void* param) // Here we simulate a I2S receive callback every 1ms. while (1) { vTaskDelay(1); -#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 } } diff --git a/examples/device/audio_4_channel_mic_freertos/src/tusb_config.h b/examples/device/audio_4_channel_mic_freertos/src/tusb_config.h index 5cd93b0d6..5ac51b153 100644 --- a/examples/device/audio_4_channel_mic_freertos/src/tusb_config.h +++ b/examples/device/audio_4_channel_mic_freertos/src/tusb_config.h @@ -121,26 +121,11 @@ 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 1 #define CFG_TUD_AUDIO_EP_IN_FLOW_CONTROL 1 -#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_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 (TUD_OPT_HIGH_SPEED ? 32 : 4) * (CFG_TUD_AUDIO_EP_SZ_IN / CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO) // Example write FIFO every 1ms, so it should be 8 times larger for HS device - -#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 (TUD_OPT_HIGH_SPEED ? 32 : 4) * CFG_TUD_AUDIO_EP_SZ_IN // Example write FIFO every 1ms, so it should be 8 times larger for HS device -#endif - #ifdef __cplusplus } #endif diff --git a/src/class/audio/audio_device.c b/src/class/audio/audio_device.c index 7a6fd453f..11a3d4a73 100644 --- a/src/class/audio/audio_device.c +++ b/src/class/audio/audio_device.c @@ -108,19 +108,19 @@ #endif // Put swap buffer in USB section only if necessary -#if USE_LINEAR_BUFFER || CFG_TUD_AUDIO_ENABLE_ENCODING +#if USE_LINEAR_BUFFER #define IN_SW_BUF_MEM_ATTR TU_ATTR_ALIGNED(4) #else #define IN_SW_BUF_MEM_ATTR CFG_TUD_MEM_SECTION CFG_TUD_MEM_ALIGN #endif -#if USE_LINEAR_BUFFER || CFG_TUD_AUDIO_ENABLE_DECODING +#if USE_LINEAR_BUFFER #define OUT_SW_BUF_MEM_ATTR TU_ATTR_ALIGNED(4) #else #define OUT_SW_BUF_MEM_ATTR CFG_TUD_MEM_SECTION CFG_TUD_MEM_ALIGN #endif // EP IN software buffers and mutexes -#if CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_ENCODING +#if CFG_TUD_AUDIO_ENABLE_EP_IN tu_static IN_SW_BUF_MEM_ATTR struct { #if CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ > 0 TUD_EPBUF_DEF(buf_1, CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ); @@ -144,12 +144,11 @@ tu_static IN_SW_BUF_MEM_ATTR struct { tu_static osal_mutex_def_t ep_in_ff_mutex_wr_3; #endif #endif -#endif// CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_ENCODING +#endif// CFG_TUD_AUDIO_ENABLE_EP_IN // Linear buffer TX in case: // - target MCU is not capable of handling a ring buffer FIFO e.g. no hardware buffer is available or driver is would need to be changed dramatically OR -// - the software encoding is used - in this case the linear buffers serve as a target memory where logical channels are encoded into -#if CFG_TUD_AUDIO_ENABLE_EP_IN && (USE_LINEAR_BUFFER || CFG_TUD_AUDIO_ENABLE_ENCODING) +#if CFG_TUD_AUDIO_ENABLE_EP_IN && USE_LINEAR_BUFFER tu_static CFG_TUD_MEM_SECTION struct { #if CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX > 0 TUD_EPBUF_DEF(buf_1, CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX); @@ -161,10 +160,10 @@ tu_static CFG_TUD_MEM_SECTION struct { TUD_EPBUF_DEF(buf_3, CFG_TUD_AUDIO_FUNC_3_EP_IN_SZ_MAX); #endif } lin_buf_in; -#endif// CFG_TUD_AUDIO_ENABLE_EP_IN && (USE_LINEAR_BUFFER || CFG_TUD_AUDIO_ENABLE_DECODING) +#endif// CFG_TUD_AUDIO_ENABLE_EP_IN && USE_LINEAR_BUFFER // EP OUT software buffers and mutexes -#if CFG_TUD_AUDIO_ENABLE_EP_OUT && !CFG_TUD_AUDIO_ENABLE_DECODING +#if CFG_TUD_AUDIO_ENABLE_EP_OUT tu_static OUT_SW_BUF_MEM_ATTR struct { #if CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ > 0 TUD_EPBUF_DEF(buf_1, CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ); @@ -188,12 +187,11 @@ tu_static OUT_SW_BUF_MEM_ATTR struct { tu_static osal_mutex_def_t ep_out_ff_mutex_rd_3; #endif #endif -#endif// CFG_TUD_AUDIO_ENABLE_EP_OUT && !CFG_TUD_AUDIO_ENABLE_DECODING +#endif// CFG_TUD_AUDIO_ENABLE_EP_OUT // Linear buffer RX in case: // - target MCU is not capable of handling a ring buffer FIFO e.g. no hardware buffer is available or driver is would need to be changed dramatically OR -// - the software encoding is used - in this case the linear buffers serve as a target memory where logical channels are encoded into -#if CFG_TUD_AUDIO_ENABLE_EP_OUT && (USE_LINEAR_BUFFER || CFG_TUD_AUDIO_ENABLE_DECODING) +#if CFG_TUD_AUDIO_ENABLE_EP_OUT && USE_LINEAR_BUFFER tu_static CFG_TUD_MEM_SECTION struct { #if CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX > 0 TUD_EPBUF_DEF(buf_1, CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX); @@ -205,7 +203,7 @@ tu_static CFG_TUD_MEM_SECTION struct { TUD_EPBUF_DEF(buf_3, CFG_TUD_AUDIO_FUNC_3_EP_OUT_SZ_MAX); #endif } lin_buf_out; -#endif// CFG_TUD_AUDIO_ENABLE_EP_OUT && (USE_LINEAR_BUFFER || CFG_TUD_AUDIO_ENABLE_DECODING) +#endif// CFG_TUD_AUDIO_ENABLE_EP_OUT && USE_LINEAR_BUFFER // Control buffers tu_static CFG_TUD_MEM_SECTION struct { @@ -229,59 +227,6 @@ tu_static uint8_t alt_setting_2[CFG_TUD_AUDIO_FUNC_2_N_AS_INT]; tu_static uint8_t alt_setting_3[CFG_TUD_AUDIO_FUNC_3_N_AS_INT]; #endif -// 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 - tu_static TU_ATTR_ALIGNED(4) 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_static tu_fifo_t tx_supp_ff_1[CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO]; - #if CFG_FIFO_MUTEX - tu_static 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 - #endif - #endif - - #if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_TX_SUPP_SW_FIFO_SZ > 0 - tu_static TU_ATTR_ALIGNED(4) 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_static tu_fifo_t tx_supp_ff_2[CFG_TUD_AUDIO_FUNC_2_N_TX_SUPP_SW_FIFO]; - #if CFG_FIFO_MUTEX - tu_static 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 - #endif - #endif - - #if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_TX_SUPP_SW_FIFO_SZ > 0 - tu_static TU_ATTR_ALIGNED(4) 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_static tu_fifo_t tx_supp_ff_3[CFG_TUD_AUDIO_FUNC_3_N_TX_SUPP_SW_FIFO]; - #if CFG_FIFO_MUTEX - tu_static 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 - #endif - #endif -#endif - -#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_DECODING - #if CFG_TUD_AUDIO_FUNC_1_RX_SUPP_SW_FIFO_SZ > 0 - tu_static TU_ATTR_ALIGNED(4) 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_static tu_fifo_t rx_supp_ff_1[CFG_TUD_AUDIO_FUNC_1_N_RX_SUPP_SW_FIFO]; - #if CFG_FIFO_MUTEX - tu_static 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 - #endif - #endif - - #if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_RX_SUPP_SW_FIFO_SZ > 0 - tu_static TU_ATTR_ALIGNED(4) 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_static tu_fifo_t rx_supp_ff_2[CFG_TUD_AUDIO_FUNC_2_N_RX_SUPP_SW_FIFO]; - #if CFG_FIFO_MUTEX - tu_static 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 - #endif - #endif - - #if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_RX_SUPP_SW_FIFO_SZ > 0 - tu_static TU_ATTR_ALIGNED(4) 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_static tu_fifo_t rx_supp_ff_3[CFG_TUD_AUDIO_FUNC_3_N_RX_SUPP_SW_FIFO]; - #if CFG_FIFO_MUTEX - tu_static 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 - #endif - #endif -#endif - // Aligned buffer for feedback EP #if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP tu_static CFG_TUD_MEM_SECTION struct { @@ -363,19 +308,6 @@ typedef struct } feedback; #endif// CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP -// Decoding parameters - parameters are set when alternate AS interface is set by host -// Coding is currently only supported for EP. Software coding corresponding to AS interfaces without EPs are not supported currently. -#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_DECODING - audio_format_type_t format_type_rx; - uint8_t n_channels_rx; - - #if CFG_TUD_AUDIO_ENABLE_TYPE_I_DECODING - audio_data_format_type_I_t format_type_I_rx; - uint8_t n_bytes_per_sample_rx; - uint8_t n_ff_used_rx; - #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]; @@ -384,15 +316,10 @@ typedef struct #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 || CFG_TUD_AUDIO_EP_IN_FLOW_CONTROL) +#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_EP_IN_FLOW_CONTROL audio_format_type_t format_type_tx; uint8_t n_channels_tx; uint8_t n_bytes_per_sample_tx; - - #if CFG_TUD_AUDIO_ENABLE_TYPE_I_ENCODING - audio_data_format_type_I_t format_type_I_tx; - uint8_t n_ff_used_tx; - #endif #endif /*------------- From this point, data is not cleared by bus reset -------------*/ @@ -405,40 +332,21 @@ typedef struct uint8_t *alt_setting;// We need to save the current alternate setting this way, because it is possible that there are AS interfaces which do not have an EP! // EP Transfer buffers and FIFOs -#if CFG_TUD_AUDIO_ENABLE_EP_OUT && !CFG_TUD_AUDIO_ENABLE_DECODING +#if CFG_TUD_AUDIO_ENABLE_EP_OUT tu_fifo_t ep_out_ff; #endif -#if CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_ENCODING +#if CFG_TUD_AUDIO_ENABLE_EP_IN tu_fifo_t ep_in_ff; #endif -// Support FIFOs for software encoding and decoding -#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_DECODING - tu_fifo_t *rx_supp_ff; - uint8_t n_rx_supp_ff; - uint16_t rx_supp_ff_sz_max; - #if CFG_TUD_AUDIO_ENABLE_TYPE_I_DECODING - uint8_t n_channels_per_ff_rx; - #endif -#endif - -#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_ENCODING - tu_fifo_t *tx_supp_ff; - uint8_t n_tx_supp_ff; - uint16_t tx_supp_ff_sz_max; - #if CFG_TUD_AUDIO_ENABLE_TYPE_I_ENCODING - uint8_t n_channels_per_ff_tx; - #endif -#endif - -// Linear buffer in case target MCU is not capable of handling a ring buffer FIFO e.g. no hardware buffer is available or driver is would need to be changed dramatically OR the support FIFOs are used -#if CFG_TUD_AUDIO_ENABLE_EP_OUT && (USE_LINEAR_BUFFER || CFG_TUD_AUDIO_ENABLE_DECODING) +// Linear buffer in case target MCU is not capable of handling a ring buffer FIFO e.g. no hardware buffer is available or driver is would need to be changed dramatically +#if CFG_TUD_AUDIO_ENABLE_EP_OUT && USE_LINEAR_BUFFER uint8_t *lin_buf_out; #define USE_LINEAR_BUFFER_RX 1 #endif -#if CFG_TUD_AUDIO_ENABLE_EP_IN && (USE_LINEAR_BUFFER || CFG_TUD_AUDIO_ENABLE_ENCODING) +#if CFG_TUD_AUDIO_ENABLE_EP_IN && USE_LINEAR_BUFFER uint8_t *lin_buf_in; #define USE_LINEAR_BUFFER_TX 1 #endif @@ -604,18 +512,10 @@ tu_static CFG_TUD_MEM_SECTION audiod_function_t _audiod_fct[CFG_TUD_AUDIO]; static bool audiod_rx_done_cb(uint8_t rhport, audiod_function_t *audio, uint16_t n_bytes_received); #endif -#if CFG_TUD_AUDIO_ENABLE_DECODING && CFG_TUD_AUDIO_ENABLE_EP_OUT -static bool audiod_decode_type_I_pcm(uint8_t rhport, audiod_function_t *audio, uint16_t n_bytes_received); -#endif - #if CFG_TUD_AUDIO_ENABLE_EP_IN static bool audiod_tx_done_cb(uint8_t rhport, audiod_function_t *audio); #endif -#if CFG_TUD_AUDIO_ENABLE_ENCODING && CFG_TUD_AUDIO_ENABLE_EP_IN -static uint16_t audiod_encode_type_I_pcm(uint8_t rhport, audiod_function_t *audio); -#endif - static bool audiod_get_interface(uint8_t rhport, tusb_control_request_t const *p_request); static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const *p_request); @@ -626,11 +526,8 @@ 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_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); -#endif - #if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_EP_IN_FLOW_CONTROL +static void audiod_parse_flow_control_params(audiod_function_t *audio, uint8_t const *p_desc); 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 @@ -651,7 +548,7 @@ bool tud_audio_n_mounted(uint8_t func_id) { // READ API //--------------------------------------------------------------------+ -#if CFG_TUD_AUDIO_ENABLE_EP_OUT && !CFG_TUD_AUDIO_ENABLE_DECODING +#if CFG_TUD_AUDIO_ENABLE_EP_OUT uint16_t tud_audio_n_available(uint8_t func_id) { TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL); @@ -673,36 +570,7 @@ tu_fifo_t *tud_audio_n_get_ep_out_ff(uint8_t func_id) { return NULL; } -#endif - -#if CFG_TUD_AUDIO_ENABLE_DECODING && CFG_TUD_AUDIO_ENABLE_EP_OUT -// Delete all content in the support RX FIFOs -bool tud_audio_n_clear_rx_support_ff(uint8_t func_id, uint8_t ff_idx) { - TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL && ff_idx < _audiod_fct[func_id].n_rx_supp_ff); - return tu_fifo_clear(&_audiod_fct[func_id].rx_supp_ff[ff_idx]); -} - -uint16_t tud_audio_n_available_support_ff(uint8_t func_id, uint8_t ff_idx) { - TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL && ff_idx < _audiod_fct[func_id].n_rx_supp_ff); - return tu_fifo_count(&_audiod_fct[func_id].rx_supp_ff[ff_idx]); -} - -uint16_t tud_audio_n_read_support_ff(uint8_t func_id, uint8_t ff_idx, void *buffer, uint16_t bufsize) { - TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL && ff_idx < _audiod_fct[func_id].n_rx_supp_ff); - return tu_fifo_read_n(&_audiod_fct[func_id].rx_supp_ff[ff_idx], buffer, bufsize); -} - -tu_fifo_t *tud_audio_n_get_rx_support_ff(uint8_t func_id, uint8_t ff_idx) { - if (func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL && ff_idx < _audiod_fct[func_id].n_rx_supp_ff) return &_audiod_fct[func_id].rx_supp_ff[ff_idx]; - return NULL; -} -#endif - -// This function is called once an audio packet is received by the USB and is responsible for putting data from USB memory into EP_OUT_FIFO (or support FIFOs + decoding of received stream into audio channels). -// If you prefer your own (more efficient) implementation suiting your purpose set CFG_TUD_AUDIO_ENABLE_DECODING = 0. - -#if CFG_TUD_AUDIO_ENABLE_EP_OUT - +// This function is called once an audio packet is received by the USB and is responsible for putting data from USB memory into EP_OUT_FIFO. static bool audiod_rx_done_cb(uint8_t rhport, audiod_function_t *audio, uint16_t n_bytes_received) { uint8_t idxItf = 0; uint8_t const *dummy2; @@ -711,62 +579,24 @@ static bool audiod_rx_done_cb(uint8_t rhport, audiod_function_t *audio, uint16_t idx_audio_fct = audiod_get_audio_fct_idx(audio); TU_VERIFY(audiod_get_AS_interface_index(audio->ep_out_as_intf_num, audio, &idxItf, &dummy2)); - // Call a weak callback here - a possibility for user to get informed an audio packet was received and data gets now loaded into EP FIFO (or decoded into support RX software FIFO) + // Call a weak callback here - a possibility for user to get informed an audio packet was received and data gets now loaded into EP FIFO TU_VERIFY(tud_audio_rx_done_pre_read_cb(rhport, n_bytes_received, idx_audio_fct, audio->ep_out, audio->alt_setting[idxItf])); - #if CFG_TUD_AUDIO_ENABLE_DECODING - - switch (audio->format_type_rx) { - case AUDIO_FORMAT_TYPE_UNDEFINED: - // INDIVIDUAL DECODING PROCEDURE REQUIRED HERE! - TU_LOG2(" Desired CFG_TUD_AUDIO_FORMAT encoding not implemented!\r\n"); - TU_BREAKPOINT(); - break; - - case AUDIO_FORMAT_TYPE_I: - - switch (audio->format_type_I_rx) { - case AUDIO_DATA_FORMAT_TYPE_I_PCM: - TU_VERIFY(audiod_decode_type_I_pcm(rhport, audio, n_bytes_received)); - break; - - default: - // DESIRED CFG_TUD_AUDIO_FORMAT_TYPE_I_RX NOT IMPLEMENTED! - TU_LOG2(" Desired CFG_TUD_AUDIO_FORMAT_TYPE_I_RX encoding not implemented!\r\n"); - TU_BREAKPOINT(); - break; - } - break; - - default: - // Desired CFG_TUD_AUDIO_FORMAT_TYPE_RX not implemented! - TU_LOG2(" Desired CFG_TUD_AUDIO_FORMAT_TYPE_RX not implemented!\r\n"); - TU_BREAKPOINT(); - break; - } - - // Prepare for next transmission - TU_VERIFY(usbd_edpt_xfer(rhport, audio->ep_out, audio->lin_buf_out, audio->ep_out_sz), false); - - #else - - #if USE_LINEAR_BUFFER_RX + #if USE_LINEAR_BUFFER_RX // Data currently is in linear buffer, copy into EP OUT FIFO TU_VERIFY(tu_fifo_write_n(&audio->ep_out_ff, audio->lin_buf_out, n_bytes_received)); // Schedule for next receive TU_VERIFY(usbd_edpt_xfer(rhport, audio->ep_out, audio->lin_buf_out, audio->ep_out_sz), false); - #else + #else // Data is already placed in EP FIFO, schedule for next receive TU_VERIFY(usbd_edpt_xfer_fifo(rhport, audio->ep_out, &audio->ep_out_ff, audio->ep_out_sz), false); - #endif + #endif - #if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP + #if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP if (audio->feedback.compute_method == AUDIO_FEEDBACK_METHOD_FIFO_COUNT) { audiod_fb_fifo_count_update(audio, tu_fifo_count(&audio->ep_out_ff)); } - #endif - #endif // Call a weak callback here - a possibility for user to get informed decoding was completed @@ -777,103 +607,11 @@ static bool audiod_rx_done_cb(uint8_t rhport, audiod_function_t *audio, uint16_t #endif//CFG_TUD_AUDIO_ENABLE_EP_OUT -// The following functions are used in case CFG_TUD_AUDIO_ENABLE_DECODING != 0 -#if CFG_TUD_AUDIO_ENABLE_DECODING && CFG_TUD_AUDIO_ENABLE_EP_OUT - -// Decoding according to 2.3.1.5 Audio Streams - -// Helper function -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 (nBytesPerSample * 2) - 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 (nBytesPerSample == 1) { - while (dst16 < dst_end16) { - *dst16++ = *src16++; - src16 += n_ff_used - 1; - } - return src16; - } else if (nBytesPerSample == 2) { - while (dst32 < dst_end32) { - *dst32++ = *src32++; - src32 += n_ff_used - 1; - } - return src32; - } else if (nBytesPerSample == 3) { - while (dst16 < dst_end16) { - *dst16++ = *src16++; - *dst16++ = *src16++; - *dst16++ = *src16++; - src16 += 3 * (n_ff_used - 1); - } - return src16; - } else// nBytesPerSample == 4 - { - while (dst32 < dst_end32) { - *dst32++ = *src32++; - *dst32++ = *src32++; - src32 += 2 * (n_ff_used - 1); - } - return src32; - } -} - -static bool audiod_decode_type_I_pcm(uint8_t rhport, audiod_function_t *audio, uint16_t n_bytes_received) { - (void) rhport; - - // Determine amount of samples - uint8_t const n_ff_used = audio->n_ff_used_rx; - uint16_t const nBytesPerFFToRead = n_bytes_received / n_ff_used; - uint8_t cnt_ff; - - // Decode - uint8_t *src; - uint8_t *dst_end; - - tu_fifo_buffer_info_t info; - - for (cnt_ff = 0; cnt_ff < n_ff_used; cnt_ff++) { - tu_fifo_get_write_info(&audio->rx_supp_ff[cnt_ff], &info); - - if (info.len_lin != 0) { - info.len_lin = tu_min16(nBytesPerFFToRead, info.len_lin); - src = &audio->lin_buf_out[cnt_ff * audio->n_channels_per_ff_rx * audio->n_bytes_per_sample_rx]; - dst_end = info.ptr_lin + info.len_lin; - src = audiod_interleaved_copy_bytes_fast_decode(audio->n_bytes_per_sample_rx, info.ptr_lin, dst_end, src, n_ff_used); - - // Handle wrapped part of FIFO - info.len_wrap = tu_min16(nBytesPerFFToRead - info.len_lin, info.len_wrap); - if (info.len_wrap != 0) { - dst_end = info.ptr_wrap + info.len_wrap; - audiod_interleaved_copy_bytes_fast_decode(audio->n_bytes_per_sample_rx, info.ptr_wrap, dst_end, src, n_ff_used); - } - tu_fifo_advance_write_pointer(&audio->rx_supp_ff[cnt_ff], info.len_lin + info.len_wrap); - } - } - - // Number of bytes should be a multiple of CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX * CFG_TUD_AUDIO_N_CHANNELS_RX but checking makes no sense - no way to correct it - // TU_VERIFY(cnt != n_bytes); - - #if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP - if (audio->feedback.compute_method == AUDIO_FEEDBACK_METHOD_FIFO_COUNT) { - audiod_fb_fifo_count_update(audio, tu_fifo_count(&audio->rx_supp_ff[0])); - } - #endif - - return true; -} -#endif//CFG_TUD_AUDIO_ENABLE_DECODING - //--------------------------------------------------------------------+ // WRITE API //--------------------------------------------------------------------+ -#if CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_ENCODING +#if CFG_TUD_AUDIO_ENABLE_EP_IN /** * \brief Write data to EP in buffer @@ -902,71 +640,8 @@ tu_fifo_t *tud_audio_n_get_ep_in_ff(uint8_t func_id) { return NULL; } -#endif - -#if CFG_TUD_AUDIO_ENABLE_ENCODING && CFG_TUD_AUDIO_ENABLE_EP_IN - -uint16_t tud_audio_n_flush_tx_support_ff(uint8_t func_id)// Force all content in the support TX FIFOs to be written into linear buffer and schedule a transmit -{ - TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL); - audiod_function_t *audio = &_audiod_fct[func_id]; - - uint16_t n_bytes_copied = tu_fifo_count(&audio->tx_supp_ff[0]); - - TU_VERIFY(audiod_tx_done_cb(audio->rhport, audio)); - - n_bytes_copied -= tu_fifo_count(&audio->tx_supp_ff[0]); - n_bytes_copied = n_bytes_copied * audio->tx_supp_ff[0].item_size; - - return n_bytes_copied; -} - -bool tud_audio_n_clear_tx_support_ff(uint8_t func_id, uint8_t ff_idx) { - TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL && ff_idx < _audiod_fct[func_id].n_tx_supp_ff); - return tu_fifo_clear(&_audiod_fct[func_id].tx_supp_ff[ff_idx]); -} - -uint16_t tud_audio_n_write_support_ff(uint8_t func_id, uint8_t ff_idx, const void *data, uint16_t len) { - TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL && ff_idx < _audiod_fct[func_id].n_tx_supp_ff); - return tu_fifo_write_n(&_audiod_fct[func_id].tx_supp_ff[ff_idx], data, len); -} - -tu_fifo_t *tud_audio_n_get_tx_support_ff(uint8_t func_id, uint8_t ff_idx) { - if (func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL && ff_idx < _audiod_fct[func_id].n_tx_supp_ff) return &_audiod_fct[func_id].tx_supp_ff[ff_idx]; - return NULL; -} - -#endif - - -#if CFG_TUD_AUDIO_ENABLE_INTERRUPT_EP -// If no interrupt transmit is pending bytes get written into buffer and a transmit is scheduled - once transmit completed tud_audio_int_done_cb() is called in inform user -bool tud_audio_int_n_write(uint8_t func_id, const audio_interrupt_data_t *data) { - TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL); - - 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_claim(_audiod_fct[func_id].rhport, _audiod_fct[func_id].ep_int)); - - // Check length - if (tu_memcpy_s(int_ep_buf[func_id].buf, sizeof(int_ep_buf[func_id].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, int_ep_buf[func_id].buf, sizeof(int_ep_buf[func_id].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. -// If you prefer your own (more efficient) implementation suiting your purpose set CFG_TUD_AUDIO_ENABLE_ENCODING = 0 and use tud_audio_n_write. - // n_bytes_copied - Informs caller how many bytes were loaded. In case n_bytes_copied = 0, a ZLP is scheduled to inform host no data is available for current frame. -#if CFG_TUD_AUDIO_ENABLE_EP_IN static bool audiod_tx_done_cb(uint8_t rhport, audiod_function_t *audio) { uint8_t idxItf; uint8_t const *dummy2; @@ -984,59 +659,18 @@ static bool audiod_tx_done_cb(uint8_t rhport, audiod_function_t *audio) { // Send everything in ISO EP FIFO uint16_t n_bytes_tx; - // If support FIFOs are used, encode and schedule transmit - #if CFG_TUD_AUDIO_ENABLE_ENCODING && CFG_TUD_AUDIO_ENABLE_EP_IN - switch (audio->format_type_tx) { - case AUDIO_FORMAT_TYPE_UNDEFINED: - // INDIVIDUAL ENCODING PROCEDURE REQUIRED HERE! - TU_LOG2(" Desired CFG_TUD_AUDIO_FORMAT encoding not implemented!\r\n"); - TU_BREAKPOINT(); - n_bytes_tx = 0; - break; - - case AUDIO_FORMAT_TYPE_I: - - switch (audio->format_type_I_tx) { - case AUDIO_DATA_FORMAT_TYPE_I_PCM: - - n_bytes_tx = audiod_encode_type_I_pcm(rhport, audio); - break; - - default: - // YOUR ENCODING IS REQUIRED HERE! - TU_LOG2(" Desired CFG_TUD_AUDIO_FORMAT_TYPE_I_TX encoding not implemented!\r\n"); - TU_BREAKPOINT(); - n_bytes_tx = 0; - break; - } - break; - - default: - // Desired CFG_TUD_AUDIO_FORMAT_TYPE_TX not implemented! - TU_LOG2(" Desired CFG_TUD_AUDIO_FORMAT_TYPE_TX not implemented!\r\n"); - TU_BREAKPOINT(); - n_bytes_tx = 0; - break; - } - - TU_VERIFY(usbd_edpt_xfer(rhport, audio->ep_in, audio->lin_buf_in, n_bytes_tx)); - - #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 - // packet_sz_tx is based on total packet size, here we want size for each support buffer. + #if CFG_TUD_AUDIO_EP_IN_FLOW_CONTROL + // packet_sz_tx is based on total packet size 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 + #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 + #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)); - #else + #else // Send everything in ISO EP FIFO TU_VERIFY(usbd_edpt_xfer_fifo(rhport, audio->ep_in, &audio->ep_in_ff, n_bytes_tx)); - #endif - #endif // Call a weak callback here - a possibility for user to get informed former TX was completed and how many bytes were loaded for the next frame @@ -1045,140 +679,33 @@ static bool audiod_tx_done_cb(uint8_t rhport, audiod_function_t *audio) { return true; } -#endif//CFG_TUD_AUDIO_ENABLE_EP_IN - -#if CFG_TUD_AUDIO_ENABLE_ENCODING && CFG_TUD_AUDIO_ENABLE_EP_IN -// Take samples from the support buffer and encode them into the IN EP software FIFO -// Returns number of bytes written into linear buffer - -/* 2.3.1.7.1 PCM Format -The PCM (Pulse Coded Modulation) format is the most commonly used audio format to represent audio -data streams. The audio data is not compressed and uses a signed two’s-complement fixed point format. It -is left-justified (the sign bit is the Msb) and data is padded with trailing zeros to fill the remaining unused -bits of the subslot. The binary point is located to the right of the sign bit so that all values lie within the -range [-1, +1) - */ - -/* - * This function encodes channels saved within the support FIFOs into one stream by interleaving the PCM samples - * in the support FIFOs according to 2.3.1.5 Audio Streams. It does not control justification (left or right) and - * does not change the number of bytes per sample. - * */ - -// Helper function -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 (nBytesPerSample * 2) - 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 (nBytesPerSample == 1) { - while (src16 < src_end16) { - *dst16++ = *src16++; - dst16 += n_ff_used - 1; - } - return dst16; - } else if (nBytesPerSample == 2) { - while (src32 < src_end32) { - *dst32++ = *src32++; - dst32 += n_ff_used - 1; - } - return dst32; - } else if (nBytesPerSample == 3) { - while (src16 < src_end16) { - *dst16++ = *src16++; - *dst16++ = *src16++; - *dst16++ = *src16++; - dst16 += 3 * (n_ff_used - 1); - } - return dst16; - } else// nBytesPerSample == 4 - { - while (src32 < src_end32) { - *dst32++ = *src32++; - *dst32++ = *src32++; - dst32 += 2 * (n_ff_used - 1); - } - return dst32; - } -} - -static uint16_t audiod_encode_type_I_pcm(uint8_t rhport, audiod_function_t *audio) { - // This function relies on the fact that the length of the support FIFOs was configured to be a multiple of the active sample size in bytes s.t. no sample is split within a wrap - // This is ensured within set_interface, where the FIFOs are reconfigured according to this size - - // We encode directly into IN EP's linear buffer - abort if previous transfer not complete - TU_VERIFY(!usbd_edpt_busy(rhport, audio->ep_in)); - - // Determine amount of samples - uint8_t const n_ff_used = audio->n_ff_used_tx; - uint16_t nBytesPerFFToSend = tu_fifo_count(&audio->tx_supp_ff[0]); - uint8_t cnt_ff; - - for (cnt_ff = 1; cnt_ff < n_ff_used; cnt_ff++) { - uint16_t const count = tu_fifo_count(&audio->tx_supp_ff[cnt_ff]); - if (count < nBytesPerFFToSend) { - nBytesPerFFToSend = count; - } - } - - #if CFG_TUD_AUDIO_EP_IN_FLOW_CONTROL - 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. - 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, 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_sample_tx; - nBytesPerFFToSend = (nBytesPerFFToSend / nSlotSize) * nSlotSize; - #endif - - // Encode - uint8_t *dst; - uint8_t *src_end; - - tu_fifo_buffer_info_t info; - - for (cnt_ff = 0; cnt_ff < n_ff_used; cnt_ff++) { - dst = &audio->lin_buf_in[cnt_ff * audio->n_channels_per_ff_tx * audio->n_bytes_per_sample_tx]; - - tu_fifo_get_read_info(&audio->tx_supp_ff[cnt_ff], &info); +#endif - if (info.len_lin != 0) { - info.len_lin = tu_min16(nBytesPerFFToSend, info.len_lin);// Limit up to desired length - src_end = (uint8_t *) info.ptr_lin + info.len_lin; - dst = audiod_interleaved_copy_bytes_fast_encode(audio->n_bytes_per_sample_tx, info.ptr_lin, src_end, dst, n_ff_used); +#if CFG_TUD_AUDIO_ENABLE_INTERRUPT_EP +// If no interrupt transmit is pending bytes get written into buffer and a transmit is scheduled - once transmit completed tud_audio_int_done_cb() is called in inform user +bool tud_audio_int_n_write(uint8_t func_id, const audio_interrupt_data_t *data) { + TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL); - // Limit up to desired length - info.len_wrap = tu_min16(nBytesPerFFToSend - info.len_lin, info.len_wrap); + TU_VERIFY(_audiod_fct[func_id].ep_int != 0); - // Handle wrapped part of FIFO - if (info.len_wrap != 0) { - src_end = (uint8_t *) info.ptr_wrap + info.len_wrap; - audiod_interleaved_copy_bytes_fast_encode(audio->n_bytes_per_sample_tx, info.ptr_wrap, src_end, dst, n_ff_used); - } + // We write directly into the EP's buffer - abort if previous transfer not complete + TU_VERIFY(usbd_edpt_claim(_audiod_fct[func_id].rhport, _audiod_fct[func_id].ep_int)); - tu_fifo_advance_read_pointer(&audio->tx_supp_ff[cnt_ff], info.len_lin + info.len_wrap); - } + // Check length + if (tu_memcpy_s(int_ep_buf[func_id].buf, sizeof(int_ep_buf[func_id].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, int_ep_buf[func_id].buf, sizeof(int_ep_buf[func_id].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 nBytesPerFFToSend * n_ff_used; + return true; } -#endif//CFG_TUD_AUDIO_ENABLE_ENCODING - -// This function is called once a transmit of a feedback packet was successfully completed. Here, we get the next feedback value to be sent +#endif #if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP +// This function is called once a transmit of a feedback packet was successfully completed. Here, we get the next feedback value to be sent static inline bool audiod_fb_send(audiod_function_t *audio) { bool apply_correction = (TUSB_SPEED_FULL == tud_speed_get()) && audio->feedback.format_correction; // Format the feedback value @@ -1260,7 +787,7 @@ void audiod_init(void) { } // Initialize IN EP FIFO if required -#if CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_ENCODING +#if CFG_TUD_AUDIO_ENABLE_EP_IN switch (i) { #if CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ > 0 @@ -1288,7 +815,7 @@ void audiod_init(void) { break; #endif } -#endif// CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_ENCODING +#endif// CFG_TUD_AUDIO_ENABLE_EP_IN // Initialize linear buffers #if USE_LINEAR_BUFFER_TX @@ -1312,7 +839,7 @@ void audiod_init(void) { #endif// USE_LINEAR_BUFFER_TX // Initialize OUT EP FIFO if required -#if CFG_TUD_AUDIO_ENABLE_EP_OUT && !CFG_TUD_AUDIO_ENABLE_DECODING +#if CFG_TUD_AUDIO_ENABLE_EP_OUT switch (i) { #if CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ > 0 @@ -1340,7 +867,7 @@ void audiod_init(void) { break; #endif } -#endif// CFG_TUD_AUDIO_ENABLE_EP_OUT && !CFG_TUD_AUDIO_ENABLE_DECODING +#endif// CFG_TUD_AUDIO_ENABLE_EP_OUT // Initialize linear buffers #if USE_LINEAR_BUFFER_RX @@ -1382,150 +909,6 @@ void audiod_init(void) { #endif } #endif// CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP - - // Initialize TX support FIFOs if required -#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_ENCODING - - switch (i) { - #if CFG_TUD_AUDIO_FUNC_1_TX_SUPP_SW_FIFO_SZ > 0 - case 0: - audio->tx_supp_ff = tx_supp_ff_1; - audio->n_tx_supp_ff = CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO; - audio->tx_supp_ff_sz_max = CFG_TUD_AUDIO_FUNC_1_TX_SUPP_SW_FIFO_SZ; - for (uint8_t cnt = 0; cnt < CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO; cnt++) { - tu_fifo_config(&tx_supp_ff_1[cnt], tx_supp_ff_buf_1[cnt], CFG_TUD_AUDIO_FUNC_1_TX_SUPP_SW_FIFO_SZ, 1, true); - #if CFG_FIFO_MUTEX - tu_fifo_config_mutex(&tx_supp_ff_1[cnt], osal_mutex_create(&tx_supp_ff_mutex_wr_1[cnt]), NULL); - #endif - } - - break; - #endif// CFG_TUD_AUDIO_FUNC_1_TX_SUPP_SW_FIFO_SZ > 0 - - #if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_TX_SUPP_SW_FIFO_SZ > 0 - case 1: - audio->tx_supp_ff = tx_supp_ff_2; - audio->n_tx_supp_ff = CFG_TUD_AUDIO_FUNC_2_N_TX_SUPP_SW_FIFO; - audio->tx_supp_ff_sz_max = CFG_TUD_AUDIO_FUNC_2_TX_SUPP_SW_FIFO_SZ; - for (uint8_t cnt = 0; cnt < CFG_TUD_AUDIO_FUNC_2_N_TX_SUPP_SW_FIFO; cnt++) { - tu_fifo_config(&tx_supp_ff_2[cnt], tx_supp_ff_buf_2[cnt], CFG_TUD_AUDIO_FUNC_2_TX_SUPP_SW_FIFO_SZ, 1, true); - #if CFG_FIFO_MUTEX - tu_fifo_config_mutex(&tx_supp_ff_2[cnt], osal_mutex_create(&tx_supp_ff_mutex_wr_2[cnt]), NULL); - #endif - } - - break; - #endif// CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_TX_SUPP_SW_FIFO_SZ > 0 - - #if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_TX_SUPP_SW_FIFO_SZ > 0 - case 2: - audio->tx_supp_ff = tx_supp_ff_3; - audio->n_tx_supp_ff = CFG_TUD_AUDIO_FUNC_3_N_TX_SUPP_SW_FIFO; - audio->tx_supp_ff_sz_max = CFG_TUD_AUDIO_FUNC_3_TX_SUPP_SW_FIFO_SZ; - for (uint8_t cnt = 0; cnt < CFG_TUD_AUDIO_FUNC_3_N_TX_SUPP_SW_FIFO; cnt++) { - tu_fifo_config(&tx_supp_ff_3[cnt], tx_supp_ff_buf_3[cnt], CFG_TUD_AUDIO_FUNC_3_TX_SUPP_SW_FIFO_SZ, 1, true); - #if CFG_FIFO_MUTEX - tu_fifo_config_mutex(&tx_supp_ff_3[cnt], osal_mutex_create(&tx_supp_ff_mutex_wr_3[cnt]), NULL); - #endif - } - - break; - #endif// CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_TX_SUPP_SW_FIFO_SZ > 0 - } -#endif// CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_ENCODING - - // Set encoding parameters for Type_I formats -#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 - case 0: - audio->n_channels_per_ff_tx = CFG_TUD_AUDIO_FUNC_1_CHANNEL_PER_FIFO_TX; - break; - #endif - #if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_TX_SUPP_SW_FIFO_SZ > 0 - case 1: - audio->n_channels_per_ff_tx = CFG_TUD_AUDIO_FUNC_2_CHANNEL_PER_FIFO_TX; - break; - #endif - #if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_TX_SUPP_SW_FIFO_SZ > 0 - case 2: - audio->n_channels_per_ff_tx = CFG_TUD_AUDIO_FUNC_3_CHANNEL_PER_FIFO_TX; - break; - #endif - } -#endif// CFG_TUD_AUDIO_ENABLE_TYPE_I_ENCODING - - // Initialize RX support FIFOs if required -#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_DECODING - - switch (i) { - #if CFG_TUD_AUDIO_FUNC_1_RX_SUPP_SW_FIFO_SZ > 0 - case 0: - audio->rx_supp_ff = rx_supp_ff_1; - audio->n_rx_supp_ff = CFG_TUD_AUDIO_FUNC_1_N_RX_SUPP_SW_FIFO; - audio->rx_supp_ff_sz_max = CFG_TUD_AUDIO_FUNC_1_RX_SUPP_SW_FIFO_SZ; - for (uint8_t cnt = 0; cnt < CFG_TUD_AUDIO_FUNC_1_N_RX_SUPP_SW_FIFO; cnt++) { - tu_fifo_config(&rx_supp_ff_1[cnt], rx_supp_ff_buf_1[cnt], CFG_TUD_AUDIO_FUNC_1_RX_SUPP_SW_FIFO_SZ, 1, true); - #if CFG_FIFO_MUTEX - tu_fifo_config_mutex(&rx_supp_ff_1[cnt], osal_mutex_create(&rx_supp_ff_mutex_rd_1[cnt]), NULL); - #endif - } - - break; - #endif// CFG_TUD_AUDIO_FUNC_1_RX_SUPP_SW_FIFO_SZ > 0 - - #if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_RX_SUPP_SW_FIFO_SZ > 0 - case 1: - audio->rx_supp_ff = rx_supp_ff_2; - audio->n_rx_supp_ff = CFG_TUD_AUDIO_FUNC_2_N_RX_SUPP_SW_FIFO; - audio->rx_supp_ff_sz_max = CFG_TUD_AUDIO_FUNC_2_RX_SUPP_SW_FIFO_SZ; - for (uint8_t cnt = 0; cnt < CFG_TUD_AUDIO_FUNC_2_N_RX_SUPP_SW_FIFO; cnt++) { - tu_fifo_config(&rx_supp_ff_2[cnt], rx_supp_ff_buf_2[cnt], CFG_TUD_AUDIO_FUNC_2_RX_SUPP_SW_FIFO_SZ, 1, true); - #if CFG_FIFO_MUTEX - tu_fifo_config_mutex(&rx_supp_ff_2[cnt], osal_mutex_create(&rx_supp_ff_mutex_rd_2[cnt]), NULL); - #endif - } - - break; - #endif// CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_RX_SUPP_SW_FIFO_SZ > 0 - - #if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_RX_SUPP_SW_FIFO_SZ > 0 - case 2: - audio->rx_supp_ff = rx_supp_ff_3; - audio->n_rx_supp_ff = CFG_TUD_AUDIO_FUNC_3_N_RX_SUPP_SW_FIFO; - audio->rx_supp_ff_sz_max = CFG_TUD_AUDIO_FUNC_3_RX_SUPP_SW_FIFO_SZ; - for (uint8_t cnt = 0; cnt < CFG_TUD_AUDIO_FUNC_3_N_RX_SUPP_SW_FIFO; cnt++) { - tu_fifo_config(&rx_supp_ff_3[cnt], rx_supp_ff_buf_3[cnt], CFG_TUD_AUDIO_FUNC_3_RX_SUPP_SW_FIFO_SZ, 1, true); - #if CFG_FIFO_MUTEX - tu_fifo_config_mutex(&rx_supp_ff_3[cnt], osal_mutex_create(&rx_supp_ff_mutex_rd_3[cnt]), NULL); - #endif - } - - break; - #endif// CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_RX_SUPP_SW_FIFO_SZ > 0 - } -#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_DECODING - switch (i) { - #if CFG_TUD_AUDIO_FUNC_1_RX_SUPP_SW_FIFO_SZ > 0 - case 0: - audio->n_channels_per_ff_rx = CFG_TUD_AUDIO_FUNC_1_CHANNEL_PER_FIFO_RX; - break; - #endif - #if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_RX_SUPP_SW_FIFO_SZ > 0 - case 1: - audio->n_channels_per_ff_rx = CFG_TUD_AUDIO_FUNC_2_CHANNEL_PER_FIFO_RX; - break; - #endif - #if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_RX_SUPP_SW_FIFO_SZ > 0 - case 2: - audio->n_channels_per_ff_rx = CFG_TUD_AUDIO_FUNC_3_CHANNEL_PER_FIFO_RX; - break; - #endif - } -#endif// CFG_TUD_AUDIO_ENABLE_TYPE_I_DECODING } } @@ -1540,25 +923,13 @@ void audiod_reset(uint8_t rhport) { audiod_function_t *audio = &_audiod_fct[i]; tu_memclr(audio, ITF_MEM_RESET_SIZE); -#if CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_ENCODING +#if CFG_TUD_AUDIO_ENABLE_EP_IN tu_fifo_clear(&audio->ep_in_ff); #endif -#if CFG_TUD_AUDIO_ENABLE_EP_OUT && !CFG_TUD_AUDIO_ENABLE_DECODING +#if CFG_TUD_AUDIO_ENABLE_EP_OUT tu_fifo_clear(&audio->ep_out_ff); #endif - -#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_ENCODING - for (uint8_t cnt = 0; cnt < audio->n_tx_supp_ff; cnt++) { - tu_fifo_clear(&audio->tx_supp_ff[cnt]); - } -#endif - -#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_DECODING - for (uint8_t cnt = 0; cnt < audio->n_rx_supp_ff; cnt++) { - tu_fifo_clear(&audio->rx_supp_ff[cnt]); - } -#endif } } @@ -1783,13 +1154,7 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const *p #endif // Clear FIFOs, since data is no longer valid - #if !CFG_TUD_AUDIO_ENABLE_ENCODING tu_fifo_clear(&audio->ep_in_ff); - #else - for (uint8_t cnt = 0; cnt < audio->n_tx_supp_ff; cnt++) { - tu_fifo_clear(&audio->tx_supp_ff[cnt]); - } - #endif // Invoke callback - can be used to stop data sampling TU_VERIFY(tud_audio_set_itf_close_EP_cb(rhport, p_request)); @@ -1812,13 +1177,7 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const *p #endif // Clear FIFOs, since data is no longer valid - #if !CFG_TUD_AUDIO_ENABLE_DECODING tu_fifo_clear(&audio->ep_out_ff); - #else - for (uint8_t cnt = 0; cnt < audio->n_rx_supp_ff; cnt++) { - tu_fifo_clear(&audio->rx_supp_ff[cnt]); - } - #endif // Invoke callback - can be used to stop data sampling TU_VERIFY(tud_audio_set_itf_close_EP_cb(rhport, p_request)); @@ -1848,7 +1207,7 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const *p while (p_desc_end - p_desc > 0) { // 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_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) +#if CFG_TUD_AUDIO_ENABLE_EP_IN && 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 @@ -1875,21 +1234,10 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const *p audio->ep_in_as_intf_num = itf; 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 || 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_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_sample_tx)) * (audio->n_channels_per_ff_tx * audio->n_bytes_per_sample_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); - } - audio->n_ff_used_tx = audio->n_channels_tx / audio->n_channels_per_ff_tx; - TU_ASSERT(audio->n_ff_used_tx <= audio->n_tx_supp_ff); - #endif + // If flow control is enabled, parse for the corresponding parameters - doing this here means only AS interfaces with EPs get scanned for parameters + #if CFG_TUD_AUDIO_EP_IN_FLOW_CONTROL + audiod_parse_flow_control_params(audio, p_desc_parse_for_params); #endif - // Schedule first transmit if alternate interface is not zero i.e. streaming is disabled - in case no sample data is available a ZLP is loaded // It is necessary to trigger this here since the refill is done with an RX FIFO empty interrupt which can only trigger if something was in there TU_VERIFY(audiod_tx_done_cb(rhport, &_audiod_fct[func_id])); @@ -1897,7 +1245,6 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const *p #endif// CFG_TUD_AUDIO_ENABLE_EP_IN #if CFG_TUD_AUDIO_ENABLE_EP_OUT - if (tu_edpt_dir(ep_addr) == TUSB_DIR_OUT)// Checking usage not necessary { // Save address @@ -1905,20 +1252,6 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const *p audio->ep_out_as_intf_num = itf; audio->ep_out_sz = tu_edpt_packet_size(desc_ep); - #if CFG_TUD_AUDIO_ENABLE_DECODING - 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_DECODING - const uint16_t active_fifo_depth = (audio->rx_supp_ff_sz_max / audio->n_bytes_per_sample_rx) * audio->n_bytes_per_sample_rx; - for (uint8_t cnt = 0; cnt < audio->n_rx_supp_ff; cnt++) { - tu_fifo_config(&audio->rx_supp_ff[cnt], audio->rx_supp_ff[cnt].buffer, active_fifo_depth, 1, true); - } - audio->n_ff_used_rx = audio->n_channels_rx / audio->n_channels_per_ff_rx; - TU_ASSERT(audio->n_ff_used_rx <= audio->n_rx_supp_ff); - #endif - #endif - // Prepare for incoming data #if USE_LINEAR_BUFFER_RX TU_VERIFY(usbd_edpt_xfer(rhport, audio->ep_out, audio->lin_buf_out, audio->ep_out_sz), false); @@ -1971,12 +1304,7 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const *p case AUDIO_FEEDBACK_METHOD_FIFO_COUNT: { // Initialize the threshold level to half filled - uint16_t fifo_lvl_thr; - #if CFG_TUD_AUDIO_ENABLE_DECODING - fifo_lvl_thr = tu_fifo_depth(&audio->rx_supp_ff[0]) / 2; - #else - fifo_lvl_thr = tu_fifo_depth(&audio->ep_out_ff) / 2; - #endif + uint16_t fifo_lvl_thr = tu_fifo_depth(&audio->ep_out_ff) / 2; audio->feedback.compute.fifo_count.fifo_lvl_thr = fifo_lvl_thr; audio->feedback.compute.fifo_count.fifo_lvl_avg = ((uint32_t) fifo_lvl_thr) << 16; // Avoid 64bit division @@ -2555,86 +1883,22 @@ static bool audiod_verify_ep_exists(uint8_t ep, uint8_t *func_id) { return false; } -#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! -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) { - #if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_EP_OUT - if (as_itf != audio->ep_in_as_intf_num && as_itf != audio->ep_out_as_intf_num) return;// Abort, this interface has no EP, this driver does not support this currently - #endif - #if CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_EP_OUT - if (as_itf != audio->ep_in_as_intf_num) return; - #endif - #if !CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_EP_OUT - if (as_itf != audio->ep_out_as_intf_num) return; - #endif +#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_EP_IN_FLOW_CONTROL +static void audiod_parse_flow_control_params(audiod_function_t *audio, uint8_t const *p_desc) { p_desc = tu_desc_next(p_desc);// Exclude standard AS interface descriptor of current alternate interface descriptor - // Condition modified from p_desc < p_desc_end to prevent gcc>=12 strict-overflow warning - while (p_desc_end - p_desc > 0) { - // Abort if follow up descriptor is a new standard interface descriptor - indicates the last AS descriptor was already finished - if (tu_desc_type(p_desc) == TUSB_DESC_INTERFACE) break; - - // Look for a Class-Specific AS Interface Descriptor(4.9.2) to verify format type and format and also to get number of physical channels - if (tu_desc_type(p_desc) == TUSB_DESC_CS_INTERFACE && tu_desc_subtype(p_desc) == AUDIO_CS_AS_INTERFACE_AS_GENERAL) { - #if CFG_TUD_AUDIO_ENABLE_EP_IN - if (as_itf == audio->ep_in_as_intf_num) { - audio->n_channels_tx = ((audio_desc_cs_as_interface_t const *) p_desc)->bNrChannels; - audio->format_type_tx = (audio_format_type_t) (((audio_desc_cs_as_interface_t const *) p_desc)->bFormatType); - - #if CFG_TUD_AUDIO_ENABLE_TYPE_I_ENCODING - audio->format_type_I_tx = (audio_data_format_type_I_t) (((audio_desc_cs_as_interface_t const *) p_desc)->bmFormats); - #endif - } - #endif - - #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; - audio->format_type_rx = ((audio_desc_cs_as_interface_t const *) p_desc)->bFormatType; - #if CFG_TUD_AUDIO_ENABLE_TYPE_I_DECODING - audio->format_type_I_rx = ((audio_desc_cs_as_interface_t const *) p_desc)->bmFormats; - #endif - } - #endif - } + // Look for a Class-Specific AS Interface Descriptor(4.9.2) to verify format type and format and also to get number of physical channels + if (tu_desc_type(p_desc) == TUSB_DESC_CS_INTERFACE && tu_desc_subtype(p_desc) == AUDIO_CS_AS_INTERFACE_AS_GENERAL) { + audio->n_channels_tx = ((audio_desc_cs_as_interface_t const *) p_desc)->bNrChannels; + audio->format_type_tx = (audio_format_type_t) (((audio_desc_cs_as_interface_t const *) p_desc)->bFormatType); // 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_EP_IN_FLOW_CONTROL || CFG_TUD_AUDIO_ENABLE_TYPE_I_DECODING + p_desc = tu_desc_next(p_desc); 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 - if (as_itf != audio->ep_in_as_intf_num && as_itf != audio->ep_out_as_intf_num) break;// Abort loop, this interface has no EP, this driver does not support this currently - #endif - #if CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_EP_OUT - if (as_itf != audio->ep_in_as_intf_num) break; - #endif - #if !CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_EP_OUT - if (as_itf != audio->ep_out_as_intf_num) break; - #endif - - #if CFG_TUD_AUDIO_ENABLE_EP_IN - if (as_itf == audio->ep_in_as_intf_num) { - audio->n_bytes_per_sample_tx = ((audio_desc_type_I_format_t const *) p_desc)->bSubslotSize; - } - #endif - - #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_sample_rx = ((audio_desc_type_I_format_t const *) p_desc)->bSubslotSize; - } - #endif + audio->n_bytes_per_sample_tx = ((audio_desc_type_I_format_t const *) p_desc)->bSubslotSize; } - #endif - - // Other format types are not supported yet - - p_desc = tu_desc_next(p_desc); } } -#endif - -#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_EP_IN_FLOW_CONTROL static bool audiod_calc_tx_packet_sz(audiod_function_t *audio) { TU_VERIFY(audio->format_type_tx == AUDIO_FORMAT_TYPE_I); diff --git a/src/class/audio/audio_device.h b/src/class/audio/audio_device.h index 0a7bff212..603535b2a 100644 --- a/src/class/audio/audio_device.h +++ b/src/class/audio/audio_device.h @@ -206,153 +206,6 @@ // Audio control interrupt EP - 6 Bytes according to UAC 2 specification (p. 74) #define CFG_TUD_AUDIO_INTERRUPT_EP_SZ 6 -// Use software encoding/decoding - -// The software coding feature of the driver is not mandatory. It is useful if, for instance, you have two I2S streams which need to be interleaved -// into a single PCM stream as SAMPLE_1 | SAMPLE_2 | SAMPLE_3 | SAMPLE_4. -// -// Currently, only PCM type I encoding/decoding is supported! -// -// If the coding feature is to be used, support FIFOs need to be configured. Their sizes and numbers are defined below. - -// Encoding/decoding is done in software and thus time consuming. If you can encode/decode your stream more efficiently do not use the -// support FIFOs but write/read directly into/from the EP_X_SW_BUFFER_FIFOs using -// - tud_audio_n_write() or -// - tud_audio_n_read(). -// To write/read to/from the support FIFOs use -// - tud_audio_n_write_support_ff() or -// - tud_audio_n_read_support_ff(). -// -// The encoding/decoding format type done is defined below. -// -// The encoding/decoding starts when the private callback functions -// - audio_tx_done_cb() -// - audio_rx_done_cb() -// are invoked. If support FIFOs are used, the corresponding encoding/decoding functions are called from there. -// Once encoding/decoding is done the result is put directly into the EP_X_SW_BUFFER_FIFOs. You can use the public callback functions -// - tud_audio_tx_done_pre_load_cb() or tud_audio_tx_done_post_load_cb() -// - tud_audio_rx_done_pre_read_cb() or tud_audio_rx_done_post_read_cb() -// if you want to get informed what happened. -// -// If you don't use the support FIFOs you may use the public callback functions -// - tud_audio_tx_done_pre_load_cb() or tud_audio_tx_done_post_load_cb() -// - tud_audio_rx_done_pre_read_cb() or tud_audio_rx_done_post_read_cb() -// to write/read from/into the EP_X_SW_BUFFER_FIFOs at the right time. -// -// If you need a different encoding which is not support so far implement it in the -// - audio_tx_done_cb() -// - audio_rx_done_cb() -// functions. - -// Enable encoding/decodings - for these to work, support FIFOs need to be setup in appropriate numbers and size -// The actual coding parameters of active AS alternate interface is parsed from the descriptors - -// The item size of the FIFO is always fixed to one i.e. bytes! Furthermore, the actively used FIFO depth is reconfigured such that the depth is a multiple -// of the current sample size in order to avoid samples to get split up in case of a wrap in the FIFO ring buffer (depth = (max_depth / sample_sz) * sample_sz)! -// This is important to remind in case you use DMAs! If the sample sizes changes, the DMA MUST BE RECONFIGURED just like the FIFOs for a different depth!!! - -// For PCM encoding/decoding - -#ifndef CFG_TUD_AUDIO_ENABLE_ENCODING -#define CFG_TUD_AUDIO_ENABLE_ENCODING 0 -#endif - -#ifndef CFG_TUD_AUDIO_ENABLE_DECODING -#define CFG_TUD_AUDIO_ENABLE_DECODING 0 -#endif - -// This enabling allows to save the current coding parameters e.g. # of bytes per sample etc. - TYPE_I includes common PCM encoding -#ifndef CFG_TUD_AUDIO_ENABLE_TYPE_I_ENCODING -#define CFG_TUD_AUDIO_ENABLE_TYPE_I_ENCODING 0 -#endif - -#ifndef CFG_TUD_AUDIO_ENABLE_TYPE_I_DECODING -#define CFG_TUD_AUDIO_ENABLE_TYPE_I_DECODING 0 -#endif - -// Type I Coding parameters not given within UAC2 descriptors -// It would be possible to allow for a more flexible setting and not fix this parameter as done below. However, this is most often not needed and kept for later if really necessary. The more flexible setting could be implemented within set_interface(), however, how the values are saved per alternate setting is to be determined! -#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_ENCODING && CFG_TUD_AUDIO_ENABLE_TYPE_I_ENCODING -#ifndef CFG_TUD_AUDIO_FUNC_1_CHANNEL_PER_FIFO_TX -#error You must tell the driver the number of channels per FIFO for the interleaved encoding! E.g. for an I2S interface having two channels, CHANNEL_PER_FIFO = 2 as the I2S stream having two channels is usually saved within one FIFO -#endif -#if CFG_TUD_AUDIO > 1 -#ifndef CFG_TUD_AUDIO_FUNC_2_CHANNEL_PER_FIFO_TX -#error You must tell the driver the number of channels per FIFO for the interleaved encoding! E.g. for an I2S interface having two channels, CHANNEL_PER_FIFO = 2 as the I2S stream having two channels is usually saved within one FIFO -#endif -#endif -#if CFG_TUD_AUDIO > 2 -#ifndef CFG_TUD_AUDIO_FUNC_3_CHANNEL_PER_FIFO_TX -#error You must tell the driver the number of channels per FIFO for the interleaved encoding! E.g. for an I2S interface having two channels, CHANNEL_PER_FIFO = 2 as the I2S stream having two channels is usually saved within one FIFO -#endif -#endif -#endif - -#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_DECODING && CFG_TUD_AUDIO_ENABLE_TYPE_I_DECODING -#ifndef CFG_TUD_AUDIO_FUNC_1_CHANNEL_PER_FIFO_RX -#error You must tell the driver the number of channels per FIFO for the interleaved encoding! E.g. for an I2S interface having two channels, CHANNEL_PER_FIFO = 2 as the I2S stream having two channels is usually saved within one FIFO -#endif -#if CFG_TUD_AUDIO > 1 -#ifndef CFG_TUD_AUDIO_FUNC_2_CHANNEL_PER_FIFO_RX -#error You must tell the driver the number of channels per FIFO for the interleaved encoding! E.g. for an I2S interface having two channels, CHANNEL_PER_FIFO = 2 as the I2S stream having two channels is usually saved within one FIFO -#endif -#endif -#if CFG_TUD_AUDIO > 2 -#ifndef CFG_TUD_AUDIO_FUNC_3_CHANNEL_PER_FIFO_RX -#error You must tell the driver the number of channels per FIFO for the interleaved encoding! E.g. for an I2S interface having two channels, CHANNEL_PER_FIFO = 2 as the I2S stream having two channels is usually saved within one FIFO -#endif -#endif -#endif - -// Remaining types not support so far - -// Number of support FIFOs to set up - multiple channels can be handled by one FIFO - very common is two channels per FIFO stemming from one I2S interface -#ifndef CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO -#define CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO 0 -#endif -#ifndef CFG_TUD_AUDIO_FUNC_2_N_TX_SUPP_SW_FIFO -#define CFG_TUD_AUDIO_FUNC_2_N_TX_SUPP_SW_FIFO 0 -#endif -#ifndef CFG_TUD_AUDIO_FUNC_3_N_TX_SUPP_SW_FIFO -#define CFG_TUD_AUDIO_FUNC_3_N_TX_SUPP_SW_FIFO 0 -#endif - -#ifndef CFG_TUD_AUDIO_FUNC_1_N_RX_SUPP_SW_FIFO -#define CFG_TUD_AUDIO_FUNC_1_N_RX_SUPP_SW_FIFO 0 -#endif -#ifndef CFG_TUD_AUDIO_FUNC_2_N_RX_SUPP_SW_FIFO -#define CFG_TUD_AUDIO_FUNC_2_N_RX_SUPP_SW_FIFO 0 -#endif -#ifndef CFG_TUD_AUDIO_FUNC_3_N_RX_SUPP_SW_FIFO -#define CFG_TUD_AUDIO_FUNC_3_N_RX_SUPP_SW_FIFO 0 -#endif - -// Size of support FIFOs IN BYTES - if size > 0 there are as many FIFOs set up as CFG_TUD_AUDIO_FUNC_X_N_TX_SUPP_SW_FIFO and CFG_TUD_AUDIO_FUNC_X_N_RX_SUPP_SW_FIFO -#ifndef CFG_TUD_AUDIO_FUNC_1_TX_SUPP_SW_FIFO_SZ -#define CFG_TUD_AUDIO_FUNC_1_TX_SUPP_SW_FIFO_SZ 0 // FIFO size - minimum size: ceil(f_s/1000) * max(# of TX channels) / (# of TX support FIFOs) * max(# of bytes per sample) -#endif -#ifndef CFG_TUD_AUDIO_FUNC_2_TX_SUPP_SW_FIFO_SZ -#define CFG_TUD_AUDIO_FUNC_2_TX_SUPP_SW_FIFO_SZ 0 -#endif -#ifndef CFG_TUD_AUDIO_FUNC_3_TX_SUPP_SW_FIFO_SZ -#define CFG_TUD_AUDIO_FUNC_3_TX_SUPP_SW_FIFO_SZ 0 -#endif - -#ifndef CFG_TUD_AUDIO_FUNC_1_RX_SUPP_SW_FIFO_SZ -#define CFG_TUD_AUDIO_FUNC_1_RX_SUPP_SW_FIFO_SZ 0 // FIFO size - minimum size: ceil(f_s/1000) * max(# of RX channels) / (# of RX support FIFOs) * max(# of bytes per sample) -#endif -#ifndef CFG_TUD_AUDIO_FUNC_2_RX_SUPP_SW_FIFO_SZ -#define CFG_TUD_AUDIO_FUNC_2_RX_SUPP_SW_FIFO_SZ 0 -#endif -#ifndef CFG_TUD_AUDIO_FUNC_3_RX_SUPP_SW_FIFO_SZ -#define CFG_TUD_AUDIO_FUNC_3_RX_SUPP_SW_FIFO_SZ 0 -#endif - -//static_assert(sizeof(tud_audio_desc_lengths) != CFG_TUD_AUDIO, "Supply audio function descriptor pack length!"); - -// Supported types of this driver: -// AUDIO_DATA_FORMAT_TYPE_I_PCM - Required definitions: CFG_TUD_AUDIO_N_CHANNELS and CFG_TUD_AUDIO_BYTES_PER_CHANNEL - #ifdef __cplusplus extern "C" { #endif @@ -368,38 +221,23 @@ extern "C" { //--------------------------------------------------------------------+ bool tud_audio_n_mounted (uint8_t func_id); -#if CFG_TUD_AUDIO_ENABLE_EP_OUT && !CFG_TUD_AUDIO_ENABLE_DECODING +#if CFG_TUD_AUDIO_ENABLE_EP_OUT uint16_t tud_audio_n_available (uint8_t func_id); uint16_t tud_audio_n_read (uint8_t func_id, void* buffer, uint16_t bufsize); bool tud_audio_n_clear_ep_out_ff (uint8_t func_id); // Delete all content in the EP OUT FIFO tu_fifo_t* tud_audio_n_get_ep_out_ff (uint8_t func_id); #endif -#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_DECODING -bool tud_audio_n_clear_rx_support_ff (uint8_t func_id, uint8_t ff_idx); // Delete all content in the support RX FIFOs -uint16_t tud_audio_n_available_support_ff (uint8_t func_id, uint8_t ff_idx); -uint16_t tud_audio_n_read_support_ff (uint8_t func_id, uint8_t ff_idx, void* buffer, uint16_t bufsize); -tu_fifo_t* tud_audio_n_get_rx_support_ff (uint8_t func_id, uint8_t ff_idx); -#endif - -#if CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_ENCODING +#if CFG_TUD_AUDIO_ENABLE_EP_IN uint16_t tud_audio_n_write (uint8_t func_id, const void * data, uint16_t len); bool tud_audio_n_clear_ep_in_ff (uint8_t func_id); // Delete all content in the EP IN FIFO tu_fifo_t* tud_audio_n_get_ep_in_ff (uint8_t func_id); #endif -#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_ENCODING -uint16_t tud_audio_n_flush_tx_support_ff (uint8_t func_id); // Force all content in the support TX FIFOs to be written into EP SW FIFO -bool tud_audio_n_clear_tx_support_ff (uint8_t func_id, uint8_t ff_idx); -uint16_t tud_audio_n_write_support_ff (uint8_t func_id, uint8_t ff_idx, const void * data, uint16_t len); -tu_fifo_t* tud_audio_n_get_tx_support_ff (uint8_t func_id, uint8_t ff_idx); -#endif - #if CFG_TUD_AUDIO_ENABLE_INTERRUPT_EP bool tud_audio_int_n_write (uint8_t func_id, const audio_interrupt_data_t * data); #endif - //--------------------------------------------------------------------+ // Application API (Interface0) //--------------------------------------------------------------------+ @@ -408,35 +246,21 @@ static inline bool tud_audio_mounted (void); // RX API -#if CFG_TUD_AUDIO_ENABLE_EP_OUT && !CFG_TUD_AUDIO_ENABLE_DECODING +#if CFG_TUD_AUDIO_ENABLE_EP_OUT static inline uint16_t tud_audio_available (void); static inline bool tud_audio_clear_ep_out_ff (void); // Delete all content in the EP OUT FIFO static inline uint16_t tud_audio_read (void* buffer, uint16_t bufsize); static inline tu_fifo_t* tud_audio_get_ep_out_ff (void); #endif -#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_DECODING -static inline bool tud_audio_clear_rx_support_ff (uint8_t ff_idx); -static inline uint16_t tud_audio_available_support_ff (uint8_t ff_idx); -static inline uint16_t tud_audio_read_support_ff (uint8_t ff_idx, void* buffer, uint16_t bufsize); -static inline tu_fifo_t* tud_audio_get_rx_support_ff (uint8_t ff_idx); -#endif - // TX API -#if CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_ENCODING +#if CFG_TUD_AUDIO_ENABLE_EP_IN static inline uint16_t tud_audio_write (const void * data, uint16_t len); static inline bool tud_audio_clear_ep_in_ff (void); static inline tu_fifo_t* tud_audio_get_ep_in_ff (void); #endif -#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_ENCODING -static inline uint16_t tud_audio_flush_tx_support_ff (void); -static inline uint16_t tud_audio_clear_tx_support_ff (uint8_t ff_idx); -static inline uint16_t tud_audio_write_support_ff (uint8_t ff_idx, const void * data, uint16_t len); -static inline tu_fifo_t* tud_audio_get_tx_support_ff (uint8_t ff_idx); -#endif - // INT CTR API #if CFG_TUD_AUDIO_ENABLE_INTERRUPT_EP @@ -593,7 +417,7 @@ static inline bool tud_audio_mounted(void) // RX API -#if CFG_TUD_AUDIO_ENABLE_EP_OUT && !CFG_TUD_AUDIO_ENABLE_DECODING +#if CFG_TUD_AUDIO_ENABLE_EP_OUT static inline uint16_t tud_audio_available(void) { @@ -617,33 +441,9 @@ static inline tu_fifo_t* tud_audio_get_ep_out_ff(void) #endif -#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_DECODING - -static inline bool tud_audio_clear_rx_support_ff(uint8_t ff_idx) -{ - return tud_audio_n_clear_rx_support_ff(0, ff_idx); -} - -static inline uint16_t tud_audio_available_support_ff(uint8_t ff_idx) -{ - return tud_audio_n_available_support_ff(0, ff_idx); -} - -static inline uint16_t tud_audio_read_support_ff(uint8_t ff_idx, void* buffer, uint16_t bufsize) -{ - return tud_audio_n_read_support_ff(0, ff_idx, buffer, bufsize); -} - -static inline tu_fifo_t* tud_audio_get_rx_support_ff(uint8_t ff_idx) -{ - return tud_audio_n_get_rx_support_ff(0, ff_idx); -} - -#endif - // TX API -#if CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_ENCODING +#if CFG_TUD_AUDIO_ENABLE_EP_IN static inline uint16_t tud_audio_write(const void * data, uint16_t len) { @@ -662,30 +462,6 @@ static inline tu_fifo_t* tud_audio_get_ep_in_ff(void) #endif -#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_ENCODING - -static inline uint16_t tud_audio_flush_tx_support_ff(void) -{ - return tud_audio_n_flush_tx_support_ff(0); -} - -static inline uint16_t tud_audio_clear_tx_support_ff(uint8_t ff_idx) -{ - return tud_audio_n_clear_tx_support_ff(0, ff_idx); -} - -static inline uint16_t tud_audio_write_support_ff(uint8_t ff_idx, const void * data, uint16_t len) -{ - return tud_audio_n_write_support_ff(0, ff_idx, data, len); -} - -static inline tu_fifo_t* tud_audio_get_tx_support_ff(uint8_t ff_idx) -{ - return tud_audio_n_get_tx_support_ff(0, ff_idx); -} - -#endif - #if CFG_TUD_AUDIO_ENABLE_INTERRUPT_EP static inline bool tud_audio_int_write(const audio_interrupt_data_t * data) { -- cgit v1.3.1 From 1ccb10e3f1418e51c03898f7ea2067208fd642b5 Mon Sep 17 00:00:00 2001 From: HiFiPhile Date: Sun, 8 Jun 2025 13:53:23 +0200 Subject: Fix ECM compile Signed-off-by: HiFiPhile --- src/class/net/ecm_rndis_device.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'src/class') diff --git a/src/class/net/ecm_rndis_device.c b/src/class/net/ecm_rndis_device.c index f1a88b3c0..299eb97c8 100644 --- a/src/class/net/ecm_rndis_device.c +++ b/src/class/net/ecm_rndis_device.c @@ -186,8 +186,6 @@ uint16_t netd_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint1 // Open endpoint pair for RNDIS TU_ASSERT(usbd_open_edpt_pair(rhport, p_desc, 2, TUSB_XFER_BULK, &_netd_itf.ep_out, &_netd_itf.ep_in), 0); - tud_network_init_cb(); - // we are ready to transmit a packet can_xmit = true; @@ -264,7 +262,6 @@ bool netd_control_xfer_cb (uint8_t rhport, uint8_t stage, tusb_control_request_t // TODO should be merge with RNDIS's after endpoint opened // Also should have opposite callback for application to disable network !! - tud_network_init_cb(); can_xmit = true; // we are ready to transmit a packet tud_network_recv_renew(); // prepare for incoming packets } -- cgit v1.3.1 From d4abf43f226b5594c935c60c38d05a90359763e1 Mon Sep 17 00:00:00 2001 From: hathach Date: Tue, 17 Jun 2025 22:16:13 +0700 Subject: add common cdch_process_set_config() to safely complete set_config() when it failed. driver_process_set_config() also pass drv index with user_data --- examples/host/cdc_msc_hid/src/cdc_app.c | 13 +- src/class/cdc/cdc_host.c | 887 ++++++++++++++++---------------- 2 files changed, 453 insertions(+), 447 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 e68ec383b..6f4433f22 100644 --- a/examples/host/cdc_msc_hid/src/cdc_app.c +++ b/examples/host/cdc_msc_hid/src/cdc_app.c @@ -31,8 +31,7 @@ static size_t get_console_inputs(uint8_t* buf, size_t bufsize) { size_t count = 0; while (count < bufsize) { int ch = board_getchar(); - if (ch <= 0) break; - + if (ch <= 0) { break; } buf[count] = (uint8_t) ch; count++; } @@ -69,10 +68,12 @@ void tuh_cdc_rx_cb(uint8_t idx) { uint32_t const bufsize = sizeof(buf) - 1; // forward cdc interfaces -> console - uint32_t count = tuh_cdc_read(idx, buf, bufsize); - buf[count] = 0; - - printf("%s", (char*) buf); + const uint32_t count = tuh_cdc_read(idx, buf, bufsize); + if (count) { + buf[count] = 0; + printf("%s", (char*) buf); + fflush(stdout); + } } // Invoked when a device with CDC interface is mounted diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index 5d5da9796..b6e9cb297 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -52,17 +52,6 @@ serial_drivers[p_cdc->serial_drid].name, ##__VA_ARGS__) #define TU_LOG_P_CDC_BOOL(TXT,VAL) TU_LOG_P_CDC(TXT " " #VAL " = %d", VAL) -// assert and set config complete -#define TU_ASSERT_COMPLETE_DEFINE(_cond, _itf_offset) \ - do { \ - if (!(_cond)) { _MESS_FAILED(); TU_BREAKPOINT(); set_config_complete(idx, _itf_offset, false); } \ - } while(0) - -#define TU_ASSERT_COMPLETE_1ARGS(_cond) TU_ASSERT_COMPLETE_DEFINE(_cond, 0) -#define TU_ASSERT_COMPLETE_2ARGS(_cond, _itf_offset) TU_ASSERT_COMPLETE_DEFINE(_cond, _itf_offset) - -#define TU_ASSERT_COMPLETE(...) _GET_3RD_ARG(__VA_ARGS__, TU_ASSERT_COMPLETE_2ARGS, TU_ASSERT_COMPLETE_1ARGS, _dummy)(__VA_ARGS__) - // handle line control defines #if defined(CFG_TUH_CDC_LINE_CONTROL_ON_ENUM) && \ (defined(CFG_TUH_CDC_DTR_CONTROL_ON_ENUM) || defined(CFG_TUH_CDC_RTS_CONTROL_ON_ENUM)) @@ -142,9 +131,14 @@ CFG_TUH_MEM_SECTION static cdch_epbuf_t cdch_epbuf[CFG_TUH_CDC]; // Serial Driver //--------------------------------------------------------------------+ +// for process_set_config user_data: idx (byte1) and state (byte0) +#define PROCESS_CONFIG_STATE(_idx, _state) tu_u16(_idx, _state) + +static void cdch_process_set_config(tuh_xfer_t *xfer); + //------------- 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_process_set_config(tuh_xfer_t * xfer); static bool acm_set_baudrate(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); static bool acm_set_data_format(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); @@ -159,7 +153,7 @@ static uint16_t const ftdi_vid_pid_list[][2] = {CFG_TUH_CDC_FTDI_VID_PID_LIST}; #endif 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_proccess_set_config(tuh_xfer_t * xfer); static bool ftdi_set_baudrate(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); static bool ftdi_set_data_format(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); @@ -172,7 +166,7 @@ static bool ftdi_set_modem_ctrl(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete 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); +static bool cp210x_process_set_config(tuh_xfer_t * xfer); static bool cp210x_set_baudrate(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); static bool cp210x_set_data_format(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); @@ -185,7 +179,7 @@ static bool cp210x_set_modem_ctrl(cdch_interface_t * p_cdc, tuh_xfer_cb_t comple 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_process_set_config(tuh_xfer_t *xfer); static bool ch34x_set_baudrate(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); static bool ch34x_set_data_format(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); @@ -201,7 +195,7 @@ static const struct pl2303_type_data pl2303_type_data[TYPE_COUNT] = {PL2303_TYPE CFG_TUH_MEM_SECTION CFG_TUH_MEM_ALIGN static bool pl2303_open(uint8_t daddr, tusb_desc_interface_t const * itf_desc, uint16_t max_len); -static void pl2303_process_config(tuh_xfer_t * xfer); +static bool pl2303_process_set_config(tuh_xfer_t *xfer); static bool pl2303_set_baudrate(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); static bool pl2303_set_data_format(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); @@ -236,7 +230,7 @@ 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 process_set_config)(tuh_xfer_t * xfer); bool (*const set_control_line_state)(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); bool (*const set_baudrate)(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); bool (*const set_data_format)(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); @@ -252,7 +246,7 @@ static const cdch_serial_driver_t serial_drivers[] = { .vid_pid_list = NULL, .vid_pid_count = 0, .open = acm_open, - .process_set_config = acm_process_config, + .process_set_config = acm_process_set_config, .set_control_line_state = acm_set_control_line_state, .set_baudrate = acm_set_baudrate, .set_data_format = acm_set_data_format, @@ -267,7 +261,7 @@ static const cdch_serial_driver_t serial_drivers[] = { .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, + .process_set_config = ftdi_proccess_set_config, .set_control_line_state = ftdi_set_modem_ctrl, .set_baudrate = ftdi_set_baudrate, .set_data_format = ftdi_set_data_format, @@ -283,7 +277,7 @@ static const cdch_serial_driver_t serial_drivers[] = { .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, + .process_set_config = cp210x_process_set_config, .set_control_line_state = cp210x_set_modem_ctrl, .set_baudrate = cp210x_set_baudrate, .set_data_format = cp210x_set_data_format, @@ -299,7 +293,7 @@ static const cdch_serial_driver_t serial_drivers[] = { .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, + .process_set_config = ch34x_process_set_config, .set_control_line_state = ch34x_set_modem_ctrl, .set_baudrate = ch34x_set_baudrate, .set_data_format = ch34x_set_data_format, @@ -315,7 +309,7 @@ static const cdch_serial_driver_t serial_drivers[] = { .vid_pid_list = pl2303_vid_pid_list, .vid_pid_count = TU_ARRAY_SIZE(pl2303_vid_pid_list), .open = pl2303_open, - .process_set_config = pl2303_process_config, + .process_set_config = pl2303_process_set_config, .set_control_line_state = pl2303_set_modem_ctrl, .set_baudrate = pl2303_set_baudrate, .set_data_format = pl2303_set_data_format, @@ -378,9 +372,8 @@ static bool open_ep_stream_pair(cdch_interface_t * p_cdc , tusb_desc_endpoint_t uint8_t tuh_cdc_itf_get_index(uint8_t daddr, uint8_t itf_num) { for (uint8_t i = 0; i < CFG_TUH_CDC; i++) { const cdch_interface_t * p_cdc = &cdch_data[i]; - if (p_cdc->daddr == daddr && p_cdc->bInterfaceNumber == itf_num) return i; + if (p_cdc->daddr == daddr && p_cdc->bInterfaceNumber == itf_num) { return i; } } - return TUSB_INDEX_INVALID_8; } @@ -642,18 +635,18 @@ bool tuh_cdc_set_dtr(uint8_t idx, bool dtr_state, tuh_xfer_cb_t complete_cb, uin } bool tuh_cdc_set_rts(uint8_t idx, bool rts_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - cdch_interface_t * p_cdc = get_itf(idx); + cdch_interface_t *p_cdc = get_itf(idx); TU_VERIFY(p_cdc && p_cdc->serial_drid < SERIAL_DRIVER_COUNT); - cdc_line_control_state_t const line_state = { .rts = rts_state, .dtr = p_cdc->line_state.dtr }; + cdc_line_control_state_t const line_state = {.rts = rts_state, .dtr = p_cdc->line_state.dtr}; return tuh_cdc_set_control_line_state_u(idx, line_state, complete_cb, user_data); } bool tuh_cdc_set_baudrate(uint8_t idx, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - cdch_interface_t * p_cdc = get_itf(idx); + cdch_interface_t *p_cdc = get_itf(idx); TU_VERIFY(p_cdc && p_cdc->serial_drid < SERIAL_DRIVER_COUNT); TU_LOG_P_CDC("set baudrate %lu", baudrate); - cdch_serial_driver_t const * driver = &serial_drivers[p_cdc->serial_drid]; + cdch_serial_driver_t const *driver = &serial_drivers[p_cdc->serial_drid]; p_cdc->requested_line_coding.bit_rate = baudrate; @@ -669,12 +662,12 @@ 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); + cdch_interface_t *p_cdc = get_itf(idx); TU_VERIFY(p_cdc && p_cdc->serial_drid < SERIAL_DRIVER_COUNT); TU_LOG_P_CDC("set data format %u%c%s", data_bits, CDC_LINE_CODING_PARITY_CHAR(parity), CDC_LINE_CODING_STOP_BITS_TEXT(stop_bits)); - cdch_serial_driver_t const * driver = &serial_drivers[p_cdc->serial_drid]; + cdch_serial_driver_t const *driver = &serial_drivers[p_cdc->serial_drid]; p_cdc->requested_line_coding.stop_bits = stop_bits; p_cdc->requested_line_coding.parity = parity; @@ -692,15 +685,15 @@ bool tuh_cdc_set_data_format(uint8_t idx, uint8_t stop_bits, uint8_t parity, uin return ret; } -bool tuh_cdc_set_line_coding(uint8_t idx, cdc_line_coding_t const * line_coding, +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); + cdch_interface_t *p_cdc = get_itf(idx); TU_VERIFY(p_cdc && p_cdc->serial_drid < SERIAL_DRIVER_COUNT); TU_LOG_P_CDC("set line coding %lu %u%c%s", line_coding->bit_rate, line_coding->data_bits, CDC_LINE_CODING_PARITY_CHAR(line_coding->parity), CDC_LINE_CODING_STOP_BITS_TEXT(line_coding->stop_bits)); - cdch_serial_driver_t const * driver = &serial_drivers[p_cdc->serial_drid]; + cdch_serial_driver_t const *driver = &serial_drivers[p_cdc->serial_drid]; p_cdc->requested_line_coding = *line_coding; @@ -722,8 +715,8 @@ bool cdch_init(void) { TU_LOG_DRV("sizeof(cdch_interface_t) = %u\r\n", sizeof(cdch_interface_t)); tu_memclr(cdch_data, sizeof(cdch_data)); for (size_t i = 0; i < CFG_TUH_CDC; i++) { - cdch_interface_t* p_cdc = &cdch_data[i]; - cdch_epbuf_t* epbuf = &cdch_epbuf[i]; + cdch_interface_t *p_cdc = &cdch_data[i]; + cdch_epbuf_t *epbuf = &cdch_epbuf[i]; tu_edpt_stream_init(&p_cdc->stream.tx, true, true, false, p_cdc->stream.tx_ff_buf, CFG_TUH_CDC_TX_BUFSIZE, epbuf->tx, CFG_TUH_CDC_TX_EPSIZE); @@ -738,7 +731,7 @@ bool cdch_init(void) { bool cdch_deinit(void) { for (size_t i = 0; i < CFG_TUH_CDC; i++) { - cdch_interface_t* p_cdc = &cdch_data[i]; + cdch_interface_t *p_cdc = &cdch_data[i]; tu_edpt_stream_deinit(&p_cdc->stream.tx); tu_edpt_stream_deinit(&p_cdc->stream.rx); } @@ -747,7 +740,7 @@ bool cdch_deinit(void) { void cdch_close(uint8_t daddr) { for (uint8_t idx = 0; idx < CFG_TUH_CDC; idx++) { - cdch_interface_t * p_cdc = &cdch_data[idx]; + cdch_interface_t *p_cdc = &cdch_data[idx]; if (p_cdc->daddr == daddr) { TU_LOG_P_CDC("close"); @@ -770,7 +763,7 @@ bool cdch_xfer_cb(uint8_t daddr, uint8_t ep_addr, xfer_result_t event, uint32_t TU_VERIFY(event == XFER_RESULT_SUCCESS); uint8_t const idx = get_idx_by_ep_addr(daddr, ep_addr); - cdch_interface_t * p_cdc = get_itf(idx); + cdch_interface_t *p_cdc = get_itf(idx); TU_ASSERT(p_cdc); if (ep_addr == p_cdc->stream.tx.ep_addr) { @@ -779,31 +772,36 @@ bool cdch_xfer_cb(uint8_t daddr, uint8_t ep_addr, xfer_result_t event, uint32_t tuh_cdc_tx_complete_cb(idx); } - if ( 0 == tu_edpt_stream_write_xfer(daddr, &p_cdc->stream.tx) ) { + if (0 == tu_edpt_stream_write_xfer(daddr, &p_cdc->stream.tx)) { // If there is no data left, a ZLP should be sent if: // - xferred_bytes is multiple of EP Packet size and not zero tu_edpt_stream_write_zlp_if_needed(daddr, &p_cdc->stream.tx, xferred_bytes); } } else if (ep_addr == p_cdc->stream.rx.ep_addr) { #if CFG_TUH_CDC_FTDI - if (p_cdc->serial_drid == SERIAL_DRIVER_FTDI && xferred_bytes > 2) { + if (p_cdc->serial_drid == SERIAL_DRIVER_FTDI) { // FTDI reserve 2 bytes for status // uint8_t status[2] = {p_cdc->stream.rx.ep_buf[0], p_cdc->stream.rx.ep_buf[1]}; - tu_edpt_stream_read_xfer_complete_with_buf(&p_cdc->stream.rx, p_cdc->stream.rx.ep_buf+2, xferred_bytes-2); - }else + if (xferred_bytes > 2) { + tu_edpt_stream_read_xfer_complete_with_buf(&p_cdc->stream.rx, p_cdc->stream.rx.ep_buf + 2, xferred_bytes - 2); + + if (tuh_cdc_rx_cb) { + tuh_cdc_rx_cb(idx); // invoke receive callback + } + } + } else #endif { tu_edpt_stream_read_xfer_complete(&p_cdc->stream.rx, xferred_bytes); - } - // invoke receive callback - if (tuh_cdc_rx_cb) { - tuh_cdc_rx_cb(idx); + if (tuh_cdc_rx_cb) { + tuh_cdc_rx_cb(idx); // invoke receive callback + } } // prepare for next transfer if needed tu_edpt_stream_read_xfer(daddr, &p_cdc->stream.rx); - }else if ( ep_addr == p_cdc->ep_notif ) { + } else if (ep_addr == p_cdc->ep_notif) { // TODO handle notification endpoint } else { TU_ASSERT(false); @@ -816,7 +814,7 @@ 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) { +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); @@ -834,9 +832,9 @@ static bool open_ep_stream_pair(cdch_interface_t * p_cdc, tusb_desc_endpoint_t c 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; - cdch_serial_driver_t const * driver_detected = NULL; + cdch_serial_driver_t const *driver_detected = NULL; // For CDC: only support ACM subclass // Note: Protocol 0xFF can be RNDIS device @@ -849,7 +847,7 @@ bool cdch_open(uint8_t rhport, uint8_t daddr, tusb_desc_interface_t const * itf_ TU_VERIFY(tuh_vid_pid_get(daddr, &vid, &pid)); for (size_t dr = 1; dr < SERIAL_DRIVER_COUNT; dr++) { - cdch_serial_driver_t const * driver = &serial_drivers[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) { driver_detected = driver; @@ -865,7 +863,7 @@ bool cdch_open(uint8_t rhport, uint8_t daddr, tusb_desc_interface_t const * itf_ if (driver_detected) { TU_LOG_CDC("open", daddr, itf_desc->bInterfaceNumber, driver_detected->name); bool ret = driver_detected->open(daddr, itf_desc, max_len); -// TU_LOG_CDC("opened ret = %s", daddr, itf_desc->bInterfaceNumber, driver_detected->name, ret ? "true" : "FALSE" ); + // TU_LOG_CDC("opened ret = %s", daddr, itf_desc->bInterfaceNumber, driver_detected->name, ret ? "true" : "FALSE" ); return ret; } @@ -873,8 +871,8 @@ bool cdch_open(uint8_t rhport, uint8_t daddr, tusb_desc_interface_t const * itf_ } static void set_config_complete(uint8_t idx, uint8_t itf_offset, bool success) { - cdch_interface_t * p_cdc = get_itf(idx); - TU_ASSERT(p_cdc,); + cdch_interface_t *p_cdc = get_itf(idx); + TU_ASSERT(p_cdc, ); TU_LOG_P_CDC_BOOL("set config complete", success); if (success) { @@ -894,22 +892,32 @@ static void set_config_complete(uint8_t idx, uint8_t itf_offset, bool success) { usbh_driver_set_config_complete(p_cdc->daddr, p_cdc->bInterfaceNumber + itf_offset); } +static void cdch_process_set_config(tuh_xfer_t *xfer) { + const uint8_t idx = tu_u32_byte1(xfer->user_data); + cdch_interface_t *p_cdc = get_itf(idx); + TU_ASSERT(p_cdc && p_cdc->serial_drid < SERIAL_DRIVER_COUNT,); + + if (!serial_drivers[p_cdc->serial_drid].process_set_config(xfer)) { + const uint8_t itf_offset = (p_cdc->serial_drid == SERIAL_DRIVER_ACM) ? 1 : 0; + set_config_complete(idx, itf_offset, false); + } +} + bool cdch_set_config(uint8_t daddr, uint8_t itf_num) { tusb_control_request_t request; request.wIndex = tu_htole16((uint16_t) itf_num); uint8_t const idx = tuh_cdc_itf_get_index(daddr, itf_num); - cdch_interface_t * p_cdc = get_itf(idx); + cdch_interface_t *p_cdc = get_itf(idx); TU_ASSERT(p_cdc && p_cdc->serial_drid < SERIAL_DRIVER_COUNT); TU_LOG_P_CDC("set config"); // fake transfer to kick-off process_set_config() tuh_xfer_t xfer; - xfer.daddr = daddr; + xfer.daddr = daddr; xfer.result = XFER_RESULT_SUCCESS; - xfer.setup = &request; - xfer.user_data = 0; // initial state 0 - - serial_drivers[p_cdc->serial_drid].process_set_config(&xfer); + xfer.setup = &request; + xfer.user_data = PROCESS_CONFIG_STATE(idx, 0); // initial state 0 + cdch_process_set_config(&xfer); return true; } @@ -921,11 +929,11 @@ bool cdch_set_config(uint8_t daddr, uint8_t itf_num) { //------------- Driver API -------------// // internal control complete to update state such as line state, encoding -static void acm_internal_control_complete(tuh_xfer_t * xfer) { +static void acm_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,); + cdch_interface_t *p_cdc = get_itf(idx); + TU_ASSERT(p_cdc, ); bool const success = (xfer->result == XFER_RESULT_SUCCESS); TU_LOG_P_CDC_BOOL("control complete", success); @@ -949,7 +957,7 @@ static void acm_internal_control_complete(tuh_xfer_t * xfer) { } } -static bool acm_set_control_line_state(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { +static bool acm_set_control_line_state(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { TU_VERIFY(p_cdc->acm_capability.support_line_request); tusb_control_request_t const request = { @@ -980,10 +988,10 @@ static bool acm_set_control_line_state(cdch_interface_t * p_cdc, tuh_xfer_cb_t c return true; } -static bool acm_set_line_coding(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { +static bool acm_set_line_coding(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { TU_VERIFY(p_cdc->acm_capability.support_line_request); TU_VERIFY((p_cdc->requested_line_coding.data_bits >= 5 && p_cdc->requested_line_coding.data_bits <= 8) || - p_cdc->requested_line_coding.data_bits == 16); + p_cdc->requested_line_coding.data_bits == 16); tusb_control_request_t const request = { .bmRequestType_bit = { @@ -998,7 +1006,7 @@ static bool acm_set_line_coding(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete }; // use usbh enum buf to hold line coding since user line_coding variable does not live long enough - uint8_t * enum_buf = usbh_get_enum_buf(); + uint8_t *enum_buf = usbh_get_enum_buf(); memcpy(enum_buf, &p_cdc->requested_line_coding, sizeof(cdc_line_coding_t)); p_cdc->user_control_cb = complete_cb; @@ -1017,13 +1025,13 @@ static bool acm_set_line_coding(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete return true; } -static bool acm_set_data_format(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { +static bool acm_set_data_format(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { p_cdc->requested_line_coding.bit_rate = p_cdc->line_coding.bit_rate; return acm_set_line_coding(p_cdc, complete_cb, user_data); } -static bool acm_set_baudrate(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { +static bool acm_set_baudrate(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { p_cdc->requested_line_coding.stop_bits = p_cdc->line_coding.stop_bits; p_cdc->requested_line_coding.parity = p_cdc->line_coding.parity; p_cdc->requested_line_coding.data_bits = p_cdc->line_coding.data_bits; @@ -1036,19 +1044,19 @@ static bool acm_set_baudrate(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb enum { CONFIG_ACM_SET_CONTROL_LINE_STATE = 0, CONFIG_ACM_SET_LINE_CODING, - CONFIG_ACM_COMPLETE, + 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))) { @@ -1063,7 +1071,7 @@ static bool acm_open(uint8_t daddr, tusb_desc_interface_t const * itf_desc, uint // Open notification endpoint of control interface if any 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)); p_cdc->ep_notif = desc_ep->bEndpointAddress; @@ -1084,31 +1092,31 @@ static bool acm_open(uint8_t daddr, tusb_desc_interface_t const * itf_desc, uint return true; } -static void acm_process_config(tuh_xfer_t * xfer) { - uintptr_t const state = xfer->user_data; +static bool acm_process_set_config(tuh_xfer_t *xfer) { + const uint8_t state = (uint8_t) 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_COMPLETE(p_cdc && xfer->result == XFER_RESULT_SUCCESS, 1); + cdch_interface_t *p_cdc = get_itf(idx); + TU_ASSERT(p_cdc && xfer->result == XFER_RESULT_SUCCESS); switch (state) { case CONFIG_ACM_SET_CONTROL_LINE_STATE: #ifdef LINE_CONTROL_ON_ENUM - if (p_cdc->acm_capability.support_line_request) { - p_cdc->requested_line_state.all = LINE_CONTROL_ON_ENUM; - TU_ASSERT_COMPLETE(acm_set_control_line_state(p_cdc, acm_process_config, CONFIG_ACM_SET_LINE_CODING), 1); - break; - } + if (p_cdc->acm_capability.support_line_request) { + p_cdc->requested_line_state.all = LINE_CONTROL_ON_ENUM; + TU_ASSERT(acm_set_control_line_state(p_cdc, cdch_process_set_config, PROCESS_CONFIG_STATE(idx, CONFIG_ACM_SET_LINE_CODING))); + break; + } #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) { - p_cdc->requested_line_coding = (cdc_line_coding_t) CFG_TUH_CDC_LINE_CODING_ON_ENUM; - TU_ASSERT_COMPLETE(acm_set_line_coding(p_cdc, acm_process_config, CONFIG_ACM_COMPLETE), 1); - break; - } + if (p_cdc->acm_capability.support_line_request) { + p_cdc->requested_line_coding = (cdc_line_coding_t) CFG_TUH_CDC_LINE_CODING_ON_ENUM; + TU_ASSERT(acm_set_line_coding(p_cdc, cdch_process_set_config, PROCESS_CONFIG_STATE(idx, CONFIG_ACM_COMPLETE))); + break; + } #endif TU_ATTR_FALLTHROUGH; @@ -1118,9 +1126,10 @@ static void acm_process_config(tuh_xfer_t * xfer) { break; default: - set_config_complete(idx, 1, false); - break; + return false; // invalid state } + + return true; } //--------------------------------------------------------------------+ @@ -1128,14 +1137,14 @@ static void acm_process_config(tuh_xfer_t * xfer) { //--------------------------------------------------------------------+ #if CFG_TUH_CDC_FTDI -static bool ftdi_determine_type(cdch_interface_t * p_cdc); -static uint32_t ftdi_get_divisor(cdch_interface_t * p_cdc); -static uint8_t ftdi_get_idx(tuh_xfer_t * xfer); +static bool ftdi_determine_type(cdch_interface_t *p_cdc); +static uint32_t ftdi_get_divisor(cdch_interface_t *p_cdc); +static uint8_t ftdi_get_idx(tuh_xfer_t *xfer); //------------- Control Request -------------// // set request without data -static bool ftdi_set_request(cdch_interface_t * p_cdc, uint8_t request, uint8_t requesttype, +static bool ftdi_set_request(cdch_interface_t *p_cdc, uint8_t request, uint8_t requesttype, uint16_t value, uint16_t index, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { tusb_control_request_t const request_setup = { .bmRequestType = requesttype, @@ -1167,37 +1176,36 @@ static int8_t ftdi_write_latency_timer(cdch_interface_t * p_cdc, uint16_t latenc } #endif -static inline bool ftdi_sio_reset(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { +static inline bool ftdi_sio_reset(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { return ftdi_set_request(p_cdc, FTDI_SIO_RESET_REQUEST, FTDI_SIO_RESET_REQUEST_TYPE, FTDI_SIO_RESET_SIO, p_cdc->ftdi.channel, complete_cb, user_data); } -static bool ftdi_change_speed(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { +static bool ftdi_change_speed(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { uint32_t index_value = ftdi_get_divisor(p_cdc); TU_VERIFY(index_value); uint16_t value = (uint16_t) index_value; uint16_t index = (uint16_t) (index_value >> 16); if (p_cdc->ftdi.channel) { - index = (uint16_t)((index << 8) | p_cdc->ftdi.channel); + index = (uint16_t) ((index << 8) | p_cdc->ftdi.channel); } return ftdi_set_request(p_cdc, FTDI_SIO_SET_BAUDRATE_REQUEST, FTDI_SIO_SET_BAUDRATE_REQUEST_TYPE, value, index, complete_cb, user_data); } -static bool ftdi_set_data_request(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { +static bool ftdi_set_data_request(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { TU_VERIFY(p_cdc->requested_line_coding.data_bits >= 7 && p_cdc->requested_line_coding.data_bits <= 8, 0); - uint16_t value = (uint16_t) ( - (p_cdc->requested_line_coding.data_bits & 0xfUL) | // data bit quantity is stored in bits 0-3 - (p_cdc->requested_line_coding.parity & 0x7UL) << 8 | // parity is stored in bits 8-10, same coding - (p_cdc->requested_line_coding.stop_bits & 0x3UL) << 11 ); // stop bits quantity is stored in bits 11-12, same coding - // not each FTDI supports 1.5 stop bits + uint16_t value = (uint16_t) ((p_cdc->requested_line_coding.data_bits & 0xfUL) | // data bit quantity is stored in bits 0-3 + (p_cdc->requested_line_coding.parity & 0x7UL) << 8 | // parity is stored in bits 8-10, same coding + (p_cdc->requested_line_coding.stop_bits & 0x3UL) << 11); // stop bits quantity is stored in bits 11-12, same coding + // not each FTDI supports 1.5 stop bits return ftdi_set_request(p_cdc, FTDI_SIO_SET_DATA_REQUEST, FTDI_SIO_SET_DATA_REQUEST_TYPE, value, p_cdc->ftdi.channel, complete_cb, user_data); } -static inline bool ftdi_update_mctrl(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { +static inline bool ftdi_update_mctrl(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { uint16_t value = (uint16_t) ((p_cdc->requested_line_state.dtr ? FTDI_SIO_SET_DTR_HIGH : FTDI_SIO_SET_DTR_LOW) | (p_cdc->requested_line_state.rts ? FTDI_SIO_SET_RTS_HIGH : FTDI_SIO_SET_RTS_LOW)); @@ -1208,10 +1216,10 @@ static inline bool ftdi_update_mctrl(cdch_interface_t * p_cdc, tuh_xfer_cb_t com //------------- Driver API -------------// // internal control complete to update state such as line state, line_coding -static void ftdi_internal_control_complete(tuh_xfer_t * xfer) { +static void ftdi_internal_control_complete(tuh_xfer_t *xfer) { uint8_t const idx = ftdi_get_idx(xfer); - cdch_interface_t * p_cdc = get_itf(idx); - TU_ASSERT(p_cdc,); + cdch_interface_t *p_cdc = get_itf(idx); + TU_ASSERT(p_cdc, ); bool const success = (xfer->result == XFER_RESULT_SUCCESS); TU_LOG_P_CDC_BOOL("control complete", success); @@ -1238,24 +1246,24 @@ static void ftdi_internal_control_complete(tuh_xfer_t * xfer) { } } -static bool ftdi_set_data_format(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { +static bool ftdi_set_data_format(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { p_cdc->user_control_cb = complete_cb; TU_ASSERT(ftdi_set_data_request(p_cdc, complete_cb ? ftdi_internal_control_complete : NULL, user_data)); return true; } -static bool ftdi_set_baudrate(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { +static bool ftdi_set_baudrate(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { p_cdc->user_control_cb = complete_cb; TU_ASSERT(ftdi_change_speed(p_cdc, complete_cb ? ftdi_internal_control_complete : NULL, user_data)); return true; } -static void ftdi_set_line_coding_stage1_complete(tuh_xfer_t * xfer) { +static void ftdi_set_line_coding_stage1_complete(tuh_xfer_t *xfer) { uint8_t const idx = ftdi_get_idx(xfer); - cdch_interface_t * p_cdc = get_itf(idx); - TU_ASSERT(p_cdc,); + cdch_interface_t *p_cdc = get_itf(idx); + TU_ASSERT(p_cdc, ); uint8_t const itf_num = p_cdc->bInterfaceNumber; set_line_coding_stage1_complete(xfer, itf_num, ftdi_set_data_request, // control request function to set data format @@ -1272,7 +1280,7 @@ static bool ftdi_set_line_coding(cdch_interface_t * p_cdc, tuh_xfer_cb_t complet complete_cb, user_data); } -static bool ftdi_set_modem_ctrl(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { +static bool ftdi_set_modem_ctrl(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { p_cdc->user_control_cb = complete_cb; TU_ASSERT(ftdi_update_mctrl(p_cdc, complete_cb ? ftdi_internal_control_complete : NULL, user_data)); @@ -1293,19 +1301,19 @@ enum { CONFIG_FTDI_COMPLETE }; -static bool ftdi_open(uint8_t daddr, const tusb_desc_interface_t * itf_desc, uint16_t max_len) { +static bool ftdi_open(uint8_t daddr, const tusb_desc_interface_t *itf_desc, uint16_t max_len) { // FTDI Interface includes 1 vendor interface + 2 bulk endpoints TU_VERIFY(itf_desc->bInterfaceSubClass == 0xff && itf_desc->bInterfaceProtocol == 0xff && itf_desc->bNumEndpoints == 2); - TU_VERIFY(sizeof(tusb_desc_interface_t) + 2*sizeof(tusb_desc_endpoint_t) <= max_len); + 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); + cdch_interface_t *p_cdc = make_new_itf(daddr, itf_desc); TU_VERIFY(p_cdc); p_cdc->serial_drid = SERIAL_DRIVER_FTDI; // 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); /* * NOTE: Some customers have programmed FT232R/FT245R devices @@ -1317,22 +1325,20 @@ static bool ftdi_open(uint8_t daddr, const tusb_desc_interface_t * itf_desc, uin return open_ep_stream_pair(p_cdc, desc_ep); } -static void ftdi_process_config(tuh_xfer_t * xfer) { - uintptr_t const state = xfer->user_data; +static bool ftdi_proccess_set_config(tuh_xfer_t *xfer) { + const uint8_t state = (uint8_t) xfer->user_data; uint8_t const idx = ftdi_get_idx(xfer); - cdch_interface_t * p_cdc = get_itf(idx); - TU_ASSERT_COMPLETE(p_cdc && xfer->result == XFER_RESULT_SUCCESS); + cdch_interface_t *p_cdc = get_itf(idx); uint8_t const itf_num = p_cdc->bInterfaceNumber; + TU_ASSERT(p_cdc && xfer->result == XFER_RESULT_SUCCESS); - switch(state) { - + switch (state) { // from here sequence overtaken from Linux Kernel function ftdi_port_probe() case CONFIG_FTDI_GET_DESC: // get device descriptor - p_cdc->user_control_cb = ftdi_process_config; // set once for whole process config - if (itf_num == 0) { // only necessary for 1st interface. other interface overtake type from interface 0 - TU_ASSERT_COMPLETE(tuh_descriptor_get_device(xfer->daddr, &desc_dev, sizeof(tusb_desc_device_t), - ftdi_process_config, CONFIG_FTDI_DETERMINE_TYPE)); + if (itf_num == 0) { // only necessary for 1st interface. other interface overtake type from interface 0 + TU_ASSERT(tuh_descriptor_get_device(xfer->daddr, &desc_dev, sizeof(tusb_desc_device_t), + cdch_process_set_config, PROCESS_CONFIG_STATE(idx, CONFIG_FTDI_DETERMINE_TYPE))); break; } TU_ATTR_FALLTHROUGH; @@ -1340,66 +1346,67 @@ static void ftdi_process_config(tuh_xfer_t * xfer) { case CONFIG_FTDI_DETERMINE_TYPE: // determine type if (itf_num == 0) { - TU_ASSERT_COMPLETE(ftdi_determine_type(p_cdc)); + TU_ASSERT(ftdi_determine_type(p_cdc)); } else { // other interfaces have same type as interface 0 uint8_t const idx_itf0 = tuh_cdc_itf_get_index(xfer->daddr, 0); - cdch_interface_t const * p_cdc_itf0 = get_itf(idx_itf0); - TU_ASSERT_COMPLETE(p_cdc_itf0); - if (p_cdc_itf0) { - p_cdc->ftdi.chip_type = p_cdc_itf0->ftdi.chip_type; - } + cdch_interface_t const *p_cdc_itf0 = get_itf(idx_itf0); + TU_ASSERT(p_cdc_itf0); + p_cdc->ftdi.chip_type = p_cdc_itf0->ftdi.chip_type; } TU_ATTR_FALLTHROUGH; case CONFIG_FTDI_WRITE_LATENCY: #ifdef CFG_TUH_CDC_FTDI_LATENCY - int8_t result = ftdi_write_latency_timer(p_cdc, CFG_TUH_CDC_FTDI_LATENCY, ftdi_process_config, - CONFIG_FTDI_SIO_RESET); - TU_ASSERT_COMPLETE(result != FTDI_FAIL); - if(result == FTDI_REQUESTED) { - break; - } // else FTDI_NOT_POSSIBLE => continue directly with next state + int8_t result = ftdi_write_latency_timer(p_cdc, CFG_TUH_CDC_FTDI_LATENCY, ftdi_process_config, + CONFIG_FTDI_SIO_RESET); + TU_ASSERT(result != FTDI_FAIL); + if (result == FTDI_REQUESTED) { + break; + }// else FTDI_NOT_POSSIBLE => continue directly with next state #endif TU_ATTR_FALLTHROUGH; - // from here sequence overtaken from Linux Kernel function ftdi_open() + // from here sequence overtaken from Linux Kernel function ftdi_open() case CONFIG_FTDI_SIO_RESET: - TU_ASSERT_COMPLETE(ftdi_sio_reset(p_cdc, ftdi_process_config, CONFIG_FTDI_SET_DATA)); + p_cdc->user_control_cb = cdch_process_set_config; + TU_ASSERT(ftdi_sio_reset(p_cdc, cdch_process_set_config, PROCESS_CONFIG_STATE(idx, CONFIG_FTDI_SET_DATA))); break; - // from here sequence overtaken from Linux Kernel function ftdi_set_termios() + // from here sequence overtaken from Linux Kernel function ftdi_set_termios() case CONFIG_FTDI_SET_DATA: #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM - p_cdc->requested_line_coding = (cdc_line_coding_t) CFG_TUH_CDC_LINE_CODING_ON_ENUM; - TU_ASSERT_COMPLETE(ftdi_set_data_request(p_cdc, ftdi_internal_control_complete, CONFIG_FTDI_SET_BAUDRATE)); - break; + p_cdc->requested_line_coding = (cdc_line_coding_t) CFG_TUH_CDC_LINE_CODING_ON_ENUM; + p_cdc->user_control_cb = cdch_process_set_config; + TU_ASSERT(ftdi_set_data_request(p_cdc, ftdi_internal_control_complete, PROCESS_CONFIG_STATE(idx, CONFIG_FTDI_SET_BAUDRATE))); + break; #else - TU_ATTR_FALLTHROUGH; + TU_ATTR_FALLTHROUGH; #endif case CONFIG_FTDI_SET_BAUDRATE: #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM - TU_ASSERT_COMPLETE(ftdi_change_speed(p_cdc, ftdi_internal_control_complete, CONFIG_FTDI_FLOW_CONTROL)); - break; + p_cdc->user_control_cb = cdch_process_set_config; + TU_ASSERT(ftdi_change_speed(p_cdc, ftdi_internal_control_complete, PROCESS_CONFIG_STATE(idx, CONFIG_FTDI_FLOW_CONTROL))); + break; #else - TU_ATTR_FALLTHROUGH; + TU_ATTR_FALLTHROUGH; #endif case CONFIG_FTDI_FLOW_CONTROL: // disable flow control - TU_ASSERT_COMPLETE(ftdi_set_request(p_cdc, FTDI_SIO_SET_FLOW_CTRL_REQUEST, FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE, - FTDI_SIO_DISABLE_FLOW_CTRL, p_cdc->ftdi.channel, - ftdi_process_config, CONFIG_FTDI_MODEM_CTRL)); + TU_ASSERT(ftdi_set_request(p_cdc, FTDI_SIO_SET_FLOW_CTRL_REQUEST, FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE, FTDI_SIO_DISABLE_FLOW_CTRL, + p_cdc->ftdi.channel, cdch_process_set_config, PROCESS_CONFIG_STATE(idx, CONFIG_FTDI_MODEM_CTRL))); break; case CONFIG_FTDI_MODEM_CTRL: #ifdef LINE_CONTROL_ON_ENUM - p_cdc->requested_line_state.all = LINE_CONTROL_ON_ENUM; - TU_ASSERT_COMPLETE(ftdi_update_mctrl(p_cdc, ftdi_internal_control_complete, CONFIG_FTDI_COMPLETE)); - break; + p_cdc->requested_line_state.all = LINE_CONTROL_ON_ENUM; + p_cdc->user_control_cb = cdch_process_set_config; + TU_ASSERT(ftdi_update_mctrl(p_cdc, ftdi_internal_control_complete, PROCESS_CONFIG_STATE(idx, CONFIG_FTDI_COMPLETE))); + break; #else - TU_ATTR_FALLTHROUGH; + TU_ATTR_FALLTHROUGH; #endif case CONFIG_FTDI_COMPLETE: @@ -1407,15 +1414,15 @@ static void ftdi_process_config(tuh_xfer_t * xfer) { break; default: - TU_ASSERT_COMPLETE(false); - break; + return false; } + + return true; } //------------- Helper -------------// -static bool ftdi_determine_type(cdch_interface_t * p_cdc) -{ +static bool ftdi_determine_type(cdch_interface_t *p_cdc) { uint16_t const version = desc_dev->bcdDevice; uint8_t const itf_num = p_cdc->bInterfaceNumber; @@ -1527,28 +1534,27 @@ static bool ftdi_determine_type(cdch_interface_t * p_cdc) //} static uint32_t ftdi_232bm_baud_base_to_divisor(uint32_t baud, uint32_t base) { - uint8_t divfrac[8] = { 0, 3, 2, 4, 1, 5, 6, 7 }; + uint8_t divfrac[8] = {0, 3, 2, 4, 1, 5, 6, 7}; uint32_t divisor; /* divisor shifted 3 bits to the left */ uint32_t divisor3 = DIV_ROUND_CLOSEST(base, 2 * baud); divisor = divisor3 >> 3; - divisor |= (uint32_t)divfrac[divisor3 & 0x7] << 14; + divisor |= (uint32_t) divfrac[divisor3 & 0x7] << 14; /* Deal with special cases for highest baud rates. */ - if (divisor == 1) /* 1.0 */ + if (divisor == 1) /* 1.0 */ { divisor = 0; - else if (divisor == 0x4001) /* 1.5 */ + } else if (divisor == 0x4001) /* 1.5 */ { divisor = 1; + } return divisor; } -static inline uint32_t ftdi_232bm_baud_to_divisor(uint32_t baud) -{ - return ftdi_232bm_baud_base_to_divisor(baud, 48000000); +static inline uint32_t ftdi_232bm_baud_to_divisor(uint32_t baud) { + return ftdi_232bm_baud_base_to_divisor(baud, 48000000); } -static uint32_t ftdi_2232h_baud_base_to_divisor(uint32_t baud, uint32_t base) -{ - static const unsigned char divfrac[8] = { 0, 3, 2, 4, 1, 5, 6, 7 }; +static uint32_t ftdi_2232h_baud_base_to_divisor(uint32_t baud, uint32_t base) { + static const unsigned char divfrac[8] = {0, 3, 2, 4, 1, 5, 6, 7}; uint32_t divisor; uint32_t divisor3; @@ -1556,12 +1562,13 @@ static uint32_t ftdi_2232h_baud_base_to_divisor(uint32_t baud, uint32_t base) divisor3 = DIV_ROUND_CLOSEST(8 * base, 10 * baud); divisor = divisor3 >> 3; - divisor |= (uint32_t)divfrac[divisor3 & 0x7] << 14; + divisor |= (uint32_t) divfrac[divisor3 & 0x7] << 14; /* Deal with special cases for highest baud rates. */ - if (divisor == 1) /* 1.0 */ + if (divisor == 1) /* 1.0 */ { divisor = 0; - else if (divisor == 0x4001) /* 1.5 */ + } else if (divisor == 0x4001) /* 1.5 */ { divisor = 1; + } /* * Set this bit to turn off a divide by 2.5 on baud rate generator * This enables baud rates up to 12Mbaud but cannot reach below 1200 @@ -1571,13 +1578,11 @@ static uint32_t ftdi_2232h_baud_base_to_divisor(uint32_t baud, uint32_t base) return divisor; } -static inline uint32_t ftdi_2232h_baud_to_divisor(uint32_t baud) -{ - return ftdi_2232h_baud_base_to_divisor(baud, (uint32_t) 120000000); +static inline uint32_t ftdi_2232h_baud_to_divisor(uint32_t baud) { + return ftdi_2232h_baud_base_to_divisor(baud, (uint32_t) 120000000); } -static inline uint32_t ftdi_get_divisor(cdch_interface_t * p_cdc) -{ +static inline uint32_t ftdi_get_divisor(cdch_interface_t *p_cdc) { uint32_t baud = p_cdc->requested_line_coding.bit_rate; uint32_t div_value = 0; TU_VERIFY(baud); @@ -1646,13 +1651,13 @@ static inline uint32_t ftdi_get_divisor(cdch_interface_t * p_cdc) return div_value; } -static uint8_t ftdi_get_idx(tuh_xfer_t * xfer) { - uint8_t const channel = (uint8_t) tu_le16toh(xfer->setup->wIndex); // channel index, or 0 for legacy types +static uint8_t ftdi_get_idx(tuh_xfer_t *xfer) { + uint8_t const channel = (uint8_t) tu_le16toh(xfer->setup->wIndex);// channel index, or 0 for legacy types for (uint8_t i = 0; i < CFG_TUH_CDC; i++) { - const cdch_interface_t * p_cdc = &cdch_data[i]; + const cdch_interface_t *p_cdc = &cdch_data[i]; if (p_cdc->daddr == xfer->daddr && (!p_cdc->ftdi.channel || // 0 for legacy types (only interface 0) - channel == p_cdc->ftdi.channel)) { // or multi-channel types (interfaces 0..n) + channel == p_cdc->ftdi.channel)) {// or multi-channel types (interfaces 0..n) return i; } } @@ -1703,29 +1708,28 @@ static bool cp210x_set_request(cdch_interface_t * p_cdc, uint8_t command, uint16 return tuh_control_xfer(&xfer); } -static inline bool cp210x_ifc_enable(cdch_interface_t * p_cdc, uint16_t enabled, +static inline bool cp210x_ifc_enable(cdch_interface_t *p_cdc, uint16_t enabled, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { return cp210x_set_request(p_cdc, CP210X_IFC_ENABLE, enabled, NULL, 0, complete_cb, user_data); } -static bool cp210x_set_baudrate_request(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { +static bool cp210x_set_baudrate_request(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { // Not every baud rate is supported. See datasheets and AN205 "CP210x Baud Rate Support" uint32_t baud_le = tu_htole32(p_cdc->requested_line_coding.bit_rate); return cp210x_set_request(p_cdc, CP210X_SET_BAUDRATE, 0, (uint8_t *) &baud_le, 4, complete_cb, user_data); } -static bool cp210x_set_line_ctl(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { +static bool cp210x_set_line_ctl(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { TU_VERIFY(p_cdc->requested_line_coding.data_bits >= 5 && p_cdc->requested_line_coding.data_bits <= 8, 0); - uint16_t lcr = (uint16_t) ( - (p_cdc->requested_line_coding.data_bits & 0xfUL) << 8 | // data bit quantity is stored in bits 8-11 - (p_cdc->requested_line_coding.parity & 0xfUL) << 4 | // parity is stored in bits 4-7, same coding - (p_cdc->requested_line_coding.stop_bits & 0xfUL)); // parity is stored in bits 0-3, same coding + uint16_t lcr = (uint16_t) ((p_cdc->requested_line_coding.data_bits & 0xfUL) << 8 | // data bit quantity is stored in bits 8-11 + (p_cdc->requested_line_coding.parity & 0xfUL) << 4 | // parity is stored in bits 4-7, same coding + (p_cdc->requested_line_coding.stop_bits & 0xfUL)); // parity is stored in bits 0-3, same coding return cp210x_set_request(p_cdc, CP210X_SET_LINE_CTL, lcr, NULL, 0, complete_cb, user_data); } -static inline bool cp210x_set_mhs(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { +static inline bool cp210x_set_mhs(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { // CP210x has the same bit coding return cp210x_set_request(p_cdc, CP210X_SET_MHS, (uint16_t) (CP210X_CONTROL_WRITE_DTR | CP210X_CONTROL_WRITE_RTS | @@ -1736,16 +1740,16 @@ static inline bool cp210x_set_mhs(cdch_interface_t * p_cdc, tuh_xfer_cb_t comple //------------- Driver API -------------// // internal control complete to update state such as line state, encoding -static void cp210x_internal_control_complete(tuh_xfer_t * xfer) { +static void cp210x_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,); + cdch_interface_t *p_cdc = get_itf(idx); + TU_ASSERT(p_cdc, ); bool const success = (xfer->result == XFER_RESULT_SUCCESS); TU_LOG_P_CDC_BOOL("control complete", success); if (success) { - switch(xfer->setup->bRequest) { + switch (xfer->setup->bRequest) { case CP210X_SET_MHS: p_cdc->line_state = p_cdc->requested_line_state; break; @@ -1770,21 +1774,21 @@ static void cp210x_internal_control_complete(tuh_xfer_t * xfer) { } } -static bool cp210x_set_baudrate(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { +static bool cp210x_set_baudrate(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { p_cdc->user_control_cb = complete_cb; TU_ASSERT(cp210x_set_baudrate_request(p_cdc, complete_cb ? cp210x_internal_control_complete : NULL, user_data)); return true; } -static bool cp210x_set_data_format(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { +static bool cp210x_set_data_format(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { p_cdc->user_control_cb = complete_cb; TU_ASSERT(cp210x_set_line_ctl(p_cdc, complete_cb ? cp210x_internal_control_complete : NULL, user_data)); return true; } -static void cp210x_set_line_coding_stage1_complete(tuh_xfer_t * xfer) { +static void cp210x_set_line_coding_stage1_complete(tuh_xfer_t *xfer) { uint8_t const itf_num = (uint8_t) tu_le16toh(xfer->setup->wIndex); set_line_coding_stage1_complete(xfer, itf_num, cp210x_set_line_ctl, // control request function to set data format @@ -1792,7 +1796,7 @@ static void cp210x_set_line_coding_stage1_complete(tuh_xfer_t * xfer) { } // 2 stages: set baudrate (stage1) + set data format (stage2) -static bool cp210x_set_line_coding(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { +static bool cp210x_set_line_coding(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { return set_line_coding_sequence(p_cdc, cp210x_set_baudrate_request, // control request function to set baudrate cp210x_set_line_ctl, // control request function to set data format @@ -1801,7 +1805,7 @@ static bool cp210x_set_line_coding(cdch_interface_t * p_cdc, tuh_xfer_cb_t compl complete_cb, user_data); } -static bool cp210x_set_modem_ctrl(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { +static bool cp210x_set_modem_ctrl(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { p_cdc->user_control_cb = complete_cb; TU_ASSERT(cp210x_set_mhs(p_cdc, complete_cb ? cp210x_internal_control_complete : NULL, user_data)); @@ -1818,64 +1822,66 @@ enum { CONFIG_CP210X_COMPLETE }; -static bool cp210x_open(uint8_t daddr, tusb_desc_interface_t const * itf_desc, uint16_t max_len) { +static bool cp210x_open(uint8_t daddr, tusb_desc_interface_t const *itf_desc, uint16_t max_len) { // CP210x Interface includes 1 vendor interface + 2 bulk endpoints TU_VERIFY(itf_desc->bInterfaceSubClass == 0 && itf_desc->bInterfaceProtocol == 0 && itf_desc->bNumEndpoints == 2); - TU_VERIFY(sizeof(tusb_desc_interface_t) + 2*sizeof(tusb_desc_endpoint_t) <= max_len); + 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); + cdch_interface_t *p_cdc = make_new_itf(daddr, itf_desc); TU_VERIFY(p_cdc); p_cdc->serial_drid = SERIAL_DRIVER_CP210X; // 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); } -static void cp210x_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); +static bool cp210x_process_set_config(tuh_xfer_t *xfer) { + const uint8_t state = (uint8_t) 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_COMPLETE(p_cdc && xfer->result == XFER_RESULT_SUCCESS); + TU_ASSERT(p_cdc && xfer->result == XFER_RESULT_SUCCESS); switch (state) { case CONFIG_CP210X_IFC_ENABLE: - p_cdc->user_control_cb = cp210x_process_config; // set once for whole process config - TU_ASSERT_COMPLETE(cp210x_ifc_enable(p_cdc, CP210X_UART_ENABLE, cp210x_process_config, - CONFIG_CP210X_SET_BAUDRATE_REQUEST)); + TU_ASSERT(cp210x_ifc_enable(p_cdc, CP210X_UART_ENABLE, cdch_process_set_config, + PROCESS_CONFIG_STATE(idx, CONFIG_CP210X_SET_BAUDRATE_REQUEST))); break; case CONFIG_CP210X_SET_BAUDRATE_REQUEST: #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM - p_cdc->requested_line_coding = (cdc_line_coding_t) CFG_TUH_CDC_LINE_CODING_ON_ENUM; - TU_ASSERT_COMPLETE(cp210x_set_baudrate_request(p_cdc, cp210x_internal_control_complete, - CONFIG_CP210X_SET_LINE_CTL)); - break; + p_cdc->requested_line_coding = (cdc_line_coding_t) CFG_TUH_CDC_LINE_CODING_ON_ENUM; + p_cdc->user_control_cb = cdch_process_set_config; + TU_ASSERT(cp210x_set_baudrate_request(p_cdc, cp210x_internal_control_complete, + PROCESS_CONFIG_STATE(idx, CONFIG_CP210X_SET_LINE_CTL))); + break; #else - TU_ATTR_FALLTHROUGH; + TU_ATTR_FALLTHROUGH; #endif case CONFIG_CP210X_SET_LINE_CTL: #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM - TU_ASSERT_COMPLETE(cp210x_set_line_ctl(p_cdc, cp210x_internal_control_complete, - CONFIG_CP210X_SET_DTR_RTS)); - break; + p_cdc->user_control_cb = cdch_process_set_config; + TU_ASSERT(cp210x_set_line_ctl(p_cdc, cp210x_internal_control_complete, + PROCESS_CONFIG_STATE(idx, CONFIG_CP210X_SET_DTR_RTS))); + break; #else - TU_ATTR_FALLTHROUGH; + TU_ATTR_FALLTHROUGH; #endif case CONFIG_CP210X_SET_DTR_RTS: #ifdef LINE_CONTROL_ON_ENUM - p_cdc->requested_line_state.all = LINE_CONTROL_ON_ENUM; - TU_ASSERT_COMPLETE(cp210x_set_mhs(p_cdc, cp210x_internal_control_complete, - CONFIG_CP210X_COMPLETE)); - break; + p_cdc->requested_line_state.all = LINE_CONTROL_ON_ENUM; + p_cdc->user_control_cb = cdch_process_set_config; + TU_ASSERT(cp210x_set_mhs(p_cdc, cp210x_internal_control_complete, + PROCESS_CONFIG_STATE(idx, CONFIG_CP210X_COMPLETE))); + break; #else - TU_ATTR_FALLTHROUGH; + TU_ATTR_FALLTHROUGH; #endif case CONFIG_CP210X_COMPLETE: @@ -1883,9 +1889,10 @@ static void cp210x_process_config(tuh_xfer_t * xfer) { break; default: - TU_ASSERT_COMPLETE(false); - break; + return false; } + + return true; } #endif @@ -1896,13 +1903,13 @@ static void cp210x_process_config(tuh_xfer_t * xfer) { #if CFG_TUH_CDC_CH34X -static uint8_t ch34x_get_lcr(cdch_interface_t * p_cdc); -static uint16_t ch34x_get_divisor_prescaler(cdch_interface_t * p_cdc); +static uint8_t ch34x_get_lcr(cdch_interface_t *p_cdc); +static uint16_t ch34x_get_divisor_prescaler(cdch_interface_t *p_cdc); //------------- 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, +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 = { @@ -1917,7 +1924,7 @@ static bool ch34x_set_request(cdch_interface_t * p_cdc, uint8_t direction, uint8 }; // use usbh enum buf since application variable does not live long enough - uint8_t * enum_buf = NULL; + uint8_t *enum_buf = NULL; if (buffer && length > 0) { enum_buf = usbh_get_enum_buf(); @@ -1938,18 +1945,18 @@ static bool ch34x_set_request(cdch_interface_t * p_cdc, uint8_t direction, uint8 return tuh_control_xfer(&xfer); } -static inline bool ch34x_control_out(cdch_interface_t * p_cdc, uint8_t request, uint16_t value, uint16_t index, +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 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) { +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); } -static inline bool ch34x_write_reg(cdch_interface_t * p_cdc, uint16_t reg, uint16_t reg_value, +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); } @@ -1960,36 +1967,33 @@ static inline bool ch34x_write_reg(cdch_interface_t * p_cdc, uint16_t reg, uint1 // return ch34x_control_in ( p_cdc, CH34X_REQ_READ_REG, reg, 0, buffer, buffersize, complete_cb, user_data ); //} -static bool ch34x_write_reg_data_format(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { +static bool ch34x_write_reg_data_format(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { uint8_t const lcr = ch34x_get_lcr(p_cdc); TU_VERIFY(lcr); - return ch34x_write_reg(p_cdc, CH32X_REG16_LCR2_LCR, lcr, complete_cb, user_data); } -static bool ch34x_write_reg_baudrate(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { +static bool ch34x_write_reg_baudrate(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { uint16_t const div_ps = ch34x_get_divisor_prescaler(p_cdc); TU_VERIFY(div_ps); - return ch34x_write_reg(p_cdc, CH34X_REG16_DIVISOR_PRESCALER, div_ps, complete_cb, user_data); } -static bool ch34x_modem_ctrl_request(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - uint8_t control = ~((p_cdc->requested_line_state.rts ? CH34X_BIT_RTS : 0) | // CH34x signals are inverted +static bool ch34x_modem_ctrl_request(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + uint8_t control = ~((p_cdc->requested_line_state.rts ? CH34X_BIT_RTS : 0) |// CH34x signals are inverted (p_cdc->requested_line_state.dtr ? CH34X_BIT_DTR : 0)); - return ch34x_control_out(p_cdc, CH34X_REQ_MODEM_CTRL, control, 0, complete_cb, user_data); } //------------- Driver API -------------// // internal control complete to update state such as line state, encoding -static void ch34x_internal_control_complete(tuh_xfer_t * xfer) { +static void ch34x_internal_control_complete(tuh_xfer_t *xfer) { // CH34x has only interface 0, because wIndex is used as payload and not for bInterfaceNumber uint8_t const itf_num = 0; uint8_t 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, ); bool const success = (xfer->result == XFER_RESULT_SUCCESS); TU_LOG_P_CDC_BOOL("control complete", success); @@ -2028,21 +2032,21 @@ static void ch34x_internal_control_complete(tuh_xfer_t * xfer) { } } -static bool ch34x_set_data_format(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { +static bool ch34x_set_data_format(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { p_cdc->user_control_cb = complete_cb; TU_ASSERT(ch34x_write_reg_data_format(p_cdc, complete_cb ? ch34x_internal_control_complete : NULL, user_data)); return true; } -static bool ch34x_set_baudrate(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { +static bool ch34x_set_baudrate(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { p_cdc->user_control_cb = complete_cb; TU_ASSERT(ch34x_write_reg_baudrate(p_cdc, complete_cb ? ch34x_internal_control_complete : NULL, user_data)); return true; } -static void ch34x_set_line_coding_stage1_complete(tuh_xfer_t * xfer) { +static void ch34x_set_line_coding_stage1_complete(tuh_xfer_t *xfer) { // CH34x has only interface 0, because wIndex is used as payload and not for bInterfaceNumber uint8_t const itf_num = 0; set_line_coding_stage1_complete(xfer, itf_num, @@ -2103,20 +2107,19 @@ static bool ch34x_open(uint8_t daddr, tusb_desc_interface_t const * itf_desc, ui return true; } -static void ch34x_process_config(tuh_xfer_t* xfer) { - uintptr_t const state = xfer->user_data; - // CH34x has only interface 0, because wIndex is used as payload and not for bInterfaceNumber - uint8_t const itf_num = 0; +static bool ch34x_process_set_config(tuh_xfer_t *xfer) { + const uint8_t state = (uint8_t) xfer->user_data; + uint8_t const itf_num = 0; // CH34x has only interface 0, since wIndex is used as payload uint8_t const idx = tuh_cdc_itf_get_index(xfer->daddr, itf_num); - cdch_interface_t * p_cdc = get_itf(idx); - TU_ASSERT_COMPLETE(p_cdc && xfer->result == XFER_RESULT_SUCCESS); - uint8_t buffer[2]; // TODO remove + cdch_interface_t *p_cdc = get_itf(idx); + uint8_t buffer[2];// TODO remove + + TU_ASSERT(p_cdc && xfer->result == XFER_RESULT_SUCCESS); switch (state) { case CONFIG_CH34X_READ_VERSION: - p_cdc->user_control_cb = ch34x_process_config; // set once for whole process config - TU_ASSERT_COMPLETE(ch34x_control_in(p_cdc, CH34X_REQ_READ_VERSION, 0, 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, + cdch_process_set_config, PROCESS_CONFIG_STATE(idx, CONFIG_CH34X_SERIAL_INIT))); break; case CONFIG_CH34X_SERIAL_INIT: { @@ -2125,39 +2128,39 @@ static void ch34x_process_config(tuh_xfer_t* xfer) { TU_LOG_P_CDC("Chip Version = 0x%02x", version); // only versions >= 0x30 are tested, below 0x30 seems having other programming // see drivers from WCH vendor, Linux kernel and FreeBSD - TU_ASSERT_COMPLETE(version >= 0x30); - // init CH34x with line coding - p_cdc->requested_line_coding = (cdc_line_coding_t) CFG_TUH_CDC_LINE_CODING_ON_ENUM_CH34X; - uint16_t const div_ps = ch34x_get_divisor_prescaler(p_cdc); - TU_ASSERT_COMPLETE(div_ps); - uint8_t const lcr = ch34x_get_lcr(p_cdc); - TU_ASSERT_COMPLETE(lcr); - TU_ASSERT_COMPLETE(ch34x_control_out(p_cdc, CH34X_REQ_SERIAL_INIT, tu_u16(lcr, 0x9c), div_ps, - ch34x_process_config, CONFIG_CH34X_SPECIAL_REG_WRITE)); + if (version >= 0x30) { + // init CH34x with line coding + p_cdc->requested_line_coding = (cdc_line_coding_t) CFG_TUH_CDC_LINE_CODING_ON_ENUM_CH34X; + uint16_t const div_ps = ch34x_get_divisor_prescaler(p_cdc); + uint8_t const lcr = ch34x_get_lcr(p_cdc); + TU_ASSERT(div_ps != 0 && lcr != 0); + TU_ASSERT(ch34x_control_out(p_cdc, CH34X_REQ_SERIAL_INIT, tu_u16(lcr, 0x9c), div_ps, + cdch_process_set_config, PROCESS_CONFIG_STATE(idx, CONFIG_CH34X_SPECIAL_REG_WRITE))); + } break; } case CONFIG_CH34X_SPECIAL_REG_WRITE: // 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_COMPLETE(ch34x_write_reg(p_cdc, TU_U16(CH341_REG_0x0F, CH341_REG_0x2C), 0x0007, - ch34x_process_config, CONFIG_CH34X_FLOW_CONTROL)); + TU_ASSERT(ch34x_write_reg(p_cdc, TU_U16(CH341_REG_0x0F, CH341_REG_0x2C), 0x0007, + cdch_process_set_config, PROCESS_CONFIG_STATE(idx, CONFIG_CH34X_FLOW_CONTROL))); break; case CONFIG_CH34X_FLOW_CONTROL: // no hardware flow control - TU_ASSERT_COMPLETE(ch34x_write_reg(p_cdc, TU_U16(CH341_REG_0x27, CH341_REG_0x27), 0x0000, - ch34x_process_config, CONFIG_CH34X_MODEM_CONTROL)); + TU_ASSERT(ch34x_write_reg(p_cdc, TU_U16(CH341_REG_0x27, CH341_REG_0x27), 0x0000, + cdch_process_set_config, PROCESS_CONFIG_STATE(idx, CONFIG_CH34X_MODEM_CONTROL))); break; case CONFIG_CH34X_MODEM_CONTROL: #ifdef LINE_CONTROL_ON_ENUM - p_cdc->requested_line_state.all = LINE_CONTROL_ON_ENUM; - TU_ASSERT_COMPLETE(ch34x_modem_ctrl_request(p_cdc, ch34x_internal_control_complete, - CONFIG_CH34X_COMPLETE)); - break; + p_cdc->requested_line_state.all = LINE_CONTROL_ON_ENUM; + p_cdc->user_control_cb = cdch_process_set_config; + TU_ASSERT(ch34x_modem_ctrl_request(p_cdc, ch34x_internal_control_complete, PROCESS_CONFIG_STATE(idx, CONFIG_CH34X_COMPLETE))); + break; #else - TU_ATTR_FALLTHROUGH; + TU_ATTR_FALLTHROUGH; #endif case CONFIG_CH34X_COMPLETE: @@ -2165,15 +2168,16 @@ static void ch34x_process_config(tuh_xfer_t* xfer) { break; default: - TU_ASSERT_COMPLETE(false); break; } + + return true; } //------------- Helper -------------// // calculate divisor and prescaler for baudrate, return it as 16-bit combined value -static uint16_t ch34x_get_divisor_prescaler(cdch_interface_t * p_cdc) { +static uint16_t ch34x_get_divisor_prescaler(cdch_interface_t *p_cdc) { uint32_t const baval = p_cdc->requested_line_coding.bit_rate; uint8_t a; uint8_t b; @@ -2219,20 +2223,20 @@ static uint16_t ch34x_get_divisor_prescaler(cdch_interface_t * p_cdc) { // 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) ((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(cdch_interface_t * p_cdc) { +static uint8_t ch34x_get_lcr(cdch_interface_t *p_cdc) { uint8_t const stop_bits = p_cdc->requested_line_coding.stop_bits; - uint8_t const parity = p_cdc->requested_line_coding.parity; + uint8_t const parity = p_cdc->requested_line_coding.parity; uint8_t const data_bits = p_cdc->requested_line_coding.data_bits; uint8_t lcr = CH34X_LCR_ENABLE_RX | CH34X_LCR_ENABLE_TX; TU_VERIFY(data_bits >= 5 && data_bits <= 8); lcr |= (uint8_t) (data_bits - 5); - switch(parity) { + switch (parity) { case CDC_LINE_CODING_PARITY_NONE: break; @@ -2271,14 +2275,13 @@ static uint8_t ch34x_get_lcr(cdch_interface_t * p_cdc) { //--------------------------------------------------------------------+ #if CFG_TUH_CDC_PL2303 -static int8_t pl2303_detect_type(cdch_interface_t * p_cdc, uint8_t step, +static int8_t pl2303_detect_type(cdch_interface_t *p_cdc, uint8_t step, tuh_xfer_cb_t complete_cb, uintptr_t user_data); -static bool pl2303_encode_baud_rate(cdch_interface_t * p_cdc, uint8_t buf[PL2303_LINE_CODING_BAUDRATE_BUFSIZE]); +static bool pl2303_encode_baud_rate(cdch_interface_t *p_cdc, uint8_t buf[PL2303_LINE_CODING_BAUDRATE_BUFSIZE]); //------------- Control Request -------------// - -static bool pl2303_set_request(cdch_interface_t * p_cdc, uint8_t request, uint8_t requesttype, - uint16_t value, uint16_t index, uint8_t * buffer, uint16_t length, +static bool pl2303_set_request(cdch_interface_t *p_cdc, uint8_t request, uint8_t requesttype, + 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 = requesttype, @@ -2289,7 +2292,7 @@ static bool pl2303_set_request(cdch_interface_t * p_cdc, uint8_t request, uint8_ }; // use usbh enum buf since application variable does not live long enough - uint8_t * enum_buf = NULL; + uint8_t *enum_buf = NULL; if (buffer && length > 0) { enum_buf = usbh_get_enum_buf(); @@ -2310,34 +2313,28 @@ static bool pl2303_set_request(cdch_interface_t * p_cdc, uint8_t request, uint8_ return tuh_control_xfer(&xfer); } -static bool pl2303_vendor_read(cdch_interface_t * p_cdc, uint16_t value, uint8_t * buf, - tuh_xfer_cb_t complete_cb, uintptr_t user_data) -{ - uint8_t request = p_cdc->pl2303.serial_private.type == &pl2303_type_data[TYPE_HXN] ? - PL2303_VENDOR_READ_NREQUEST : PL2303_VENDOR_READ_REQUEST; +static bool pl2303_vendor_read(cdch_interface_t *p_cdc, uint16_t value, uint8_t *buf, + tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + uint8_t request = p_cdc->pl2303.serial_private.type == &pl2303_type_data[TYPE_HXN] ? PL2303_VENDOR_READ_NREQUEST : PL2303_VENDOR_READ_REQUEST; return pl2303_set_request(p_cdc, request, PL2303_VENDOR_READ_REQUEST_TYPE, value, 0, buf, 1, complete_cb, user_data); } -static bool pl2303_vendor_write(cdch_interface_t * p_cdc, uint16_t value, uint16_t index, - tuh_xfer_cb_t complete_cb, uintptr_t user_data) -{ - uint8_t request = p_cdc->pl2303.serial_private.type == &pl2303_type_data[TYPE_HXN] ? - PL2303_VENDOR_WRITE_NREQUEST : PL2303_VENDOR_WRITE_REQUEST; +static bool pl2303_vendor_write(cdch_interface_t *p_cdc, uint16_t value, uint16_t index, + tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + uint8_t request = p_cdc->pl2303.serial_private.type == &pl2303_type_data[TYPE_HXN] ? PL2303_VENDOR_WRITE_NREQUEST : PL2303_VENDOR_WRITE_REQUEST; return pl2303_set_request(p_cdc, request, PL2303_VENDOR_WRITE_REQUEST_TYPE, value, index, NULL, 0, complete_cb, user_data); } -static inline bool pl2303_supports_hx_status(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) -{ +static inline bool pl2303_supports_hx_status(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { uint8_t buf = 0; return pl2303_set_request(p_cdc, PL2303_VENDOR_READ_REQUEST, PL2303_VENDOR_READ_REQUEST_TYPE, PL2303_READ_TYPE_HX_STATUS, 0, &buf, 1, complete_cb, user_data); } -static inline bool pl2303_set_control_lines(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) -{ +static inline bool pl2303_set_control_lines(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { // PL2303 has the same bit coding return pl2303_set_request(p_cdc, PL2303_SET_CONTROL_REQUEST, PL2303_SET_CONTROL_REQUEST_TYPE, p_cdc->requested_line_state.all, 0, NULL, 0, complete_cb, user_data); @@ -2348,7 +2345,7 @@ static inline bool pl2303_set_control_lines(cdch_interface_t * p_cdc, tuh_xfer_c // return pl2303_set_request(p_cdc, PL2303_GET_LINE_REQUEST, PL2303_GET_LINE_REQUEST_TYPE, 0, 0, buf, PL2303_LINE_CODING_BUFSIZE); //} -static bool pl2303_set_line_request(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { +static bool pl2303_set_line_request(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { // the caller has to precheck, that the new line coding different than the current, else false returned uint8_t buf[PL2303_LINE_CODING_BUFSIZE]; /* @@ -2390,8 +2387,7 @@ static bool pl2303_set_line_request(cdch_interface_t * p_cdc, tuh_xfer_cb_t comp // return pl2303_set_request(p_cdc, PL2303_BREAK_REQUEST, PL2303_BREAK_REQUEST_TYPE, state, 0, NULL, 0); //} -static inline int pl2303_clear_halt(cdch_interface_t * p_cdc, uint8_t endp, tuh_xfer_cb_t complete_cb, uintptr_t user_data) -{ +static inline int pl2303_clear_halt(cdch_interface_t *p_cdc, uint8_t endp, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { /* we don't care if it wasn't halted first. in fact some devices * (like some ibmcam model 1 units) seem to expect hosts to make * this request for iso endpoints, which can't halt! @@ -2403,22 +2399,22 @@ static inline int pl2303_clear_halt(cdch_interface_t * p_cdc, uint8_t endp, tuh_ //------------- Driver API -------------// // internal control complete to update state such as line state, encoding -static void pl2303_internal_control_complete(tuh_xfer_t * xfer) { +static void pl2303_internal_control_complete(tuh_xfer_t *xfer) { // PL2303 has only interface 0, because wIndex is used as payload and not for bInterfaceNumber uint8_t const itf_num = 0; uint8_t 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, ); bool const success = (xfer->result == XFER_RESULT_SUCCESS); TU_LOG_P_CDC_BOOL("control complete", success); if (success) { if (xfer->setup->bRequest == PL2303_SET_LINE_REQUEST && - xfer->setup->bmRequestType == PL2303_SET_LINE_REQUEST_TYPE) { + xfer->setup->bmRequestType == PL2303_SET_LINE_REQUEST_TYPE) { p_cdc->line_coding = p_cdc->requested_line_coding; } if (xfer->setup->bRequest == PL2303_SET_CONTROL_REQUEST && - xfer->setup->bmRequestType == PL2303_SET_CONTROL_REQUEST_TYPE) { + xfer->setup->bmRequestType == PL2303_SET_CONTROL_REQUEST_TYPE) { p_cdc->line_state = p_cdc->requested_line_state; } } @@ -2429,14 +2425,14 @@ static void pl2303_internal_control_complete(tuh_xfer_t * xfer) { } } -static bool pl2303_set_line_coding(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { +static bool pl2303_set_line_coding(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { p_cdc->user_control_cb = complete_cb; TU_ASSERT(pl2303_set_line_request(p_cdc, complete_cb ? pl2303_internal_control_complete : NULL, user_data)); return true; } -static bool pl2303_set_data_format(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { +static bool pl2303_set_data_format(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { p_cdc->requested_line_coding.bit_rate = p_cdc->line_coding.bit_rate; p_cdc->user_control_cb = complete_cb; TU_ASSERT(pl2303_set_line_request(p_cdc, complete_cb ? pl2303_internal_control_complete : NULL, user_data)); @@ -2444,7 +2440,7 @@ static bool pl2303_set_data_format(cdch_interface_t * p_cdc, tuh_xfer_cb_t compl return true; } -static bool pl2303_set_baudrate(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { +static bool pl2303_set_baudrate(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { p_cdc->requested_line_coding.stop_bits = p_cdc->line_coding.stop_bits; p_cdc->requested_line_coding.parity = p_cdc->line_coding.parity; p_cdc->requested_line_coding.data_bits = p_cdc->line_coding.data_bits; @@ -2454,7 +2450,7 @@ static bool pl2303_set_baudrate(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete return true; } -static bool pl2303_set_modem_ctrl(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { +static bool pl2303_set_modem_ctrl(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { // PL2303 has the same bit coding p_cdc->user_control_cb = complete_cb; TU_ASSERT(pl2303_set_control_lines(p_cdc, complete_cb ? pl2303_internal_control_complete : NULL, user_data)); @@ -2487,19 +2483,19 @@ enum { CONFIG_PL2303_COMPLETE }; -static bool pl2303_open(uint8_t daddr, tusb_desc_interface_t const * itf_desc, uint16_t max_len) { +static bool pl2303_open(uint8_t daddr, tusb_desc_interface_t const *itf_desc, uint16_t max_len) { // PL2303 Interface includes 1 vendor interface + 1 interrupt endpoints + 2 bulk 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); + cdch_interface_t *p_cdc = make_new_itf(daddr, itf_desc); TU_VERIFY(p_cdc); p_cdc->serial_drid = SERIAL_DRIVER_PL2303; p_cdc->pl2303.serial_private.quirks = 0; p_cdc->pl2303.supports_hx_status = false; - 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); // Interrupt endpoint: not used for now TU_ASSERT(TUSB_DESC_ENDPOINT == tu_desc_type(desc_ep) && @@ -2514,158 +2510,167 @@ static bool pl2303_open(uint8_t daddr, tusb_desc_interface_t const * itf_desc, u return true; } -static void pl2303_process_config(tuh_xfer_t * xfer) { - uintptr_t const state = xfer->user_data; +static bool pl2303_process_set_config(tuh_xfer_t *xfer) { + const uint8_t state = (uint8_t) xfer->user_data; // PL2303 has only interface 0, because wIndex is used 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); + cdch_interface_t *p_cdc = get_itf(idx); // state CONFIG_PL2303_READ1 may have no success due to expected stall by pl2303_supports_hx_status() - TU_ASSERT_COMPLETE(p_cdc && (xfer->result == XFER_RESULT_SUCCESS || xfer->user_data == CONFIG_PL2303_READ1)); uint8_t buf = 0; int8_t type; + TU_ASSERT(p_cdc && (xfer->result == XFER_RESULT_SUCCESS || xfer->user_data == CONFIG_PL2303_READ1)); switch (state) { - // from here sequence overtaken from Linux Kernel function pl2303_startup() case CONFIG_PL2303_GET_DESC: - p_cdc->user_control_cb = pl2303_process_config; // set once for whole process config + p_cdc->user_control_cb = cdch_process_set_config;// set once for whole process config // get device descriptor - TU_ASSERT_COMPLETE(tuh_descriptor_get_device(xfer->daddr, &desc_dev, sizeof(tusb_desc_device_t), - pl2303_process_config, CONFIG_PL2303_DETECT_TYPE)); + TU_ASSERT(tuh_descriptor_get_device(xfer->daddr, &desc_dev, sizeof(tusb_desc_device_t), + cdch_process_set_config, PROCESS_CONFIG_STATE(idx, CONFIG_PL2303_DETECT_TYPE))); break; case CONFIG_PL2303_DETECT_TYPE: // get type and quirks (step 1) - type = pl2303_detect_type (p_cdc, 1, pl2303_process_config, CONFIG_PL2303_READ1); // step 1 - TU_ASSERT_COMPLETE(type!=PL2303_DETECT_TYPE_FAILED); + type = pl2303_detect_type(p_cdc, 1, cdch_process_set_config, PROCESS_CONFIG_STATE(idx, CONFIG_PL2303_READ1)); + TU_ASSERT(type != PL2303_DETECT_TYPE_FAILED); if (type == PL2303_SUPPORTS_HX_STATUS_TRIGGERED) { break; - } // else: no transfer triggered and continue with CONFIG_PL2303_READ1 + }// else: no transfer triggered and continue with CONFIG_PL2303_READ1 TU_ATTR_FALLTHROUGH; case CONFIG_PL2303_READ1: // get supports_hx_status, type and quirks (step 2), do special read - p_cdc->pl2303.supports_hx_status = ( // will not be true, if coming directly from previous case - xfer->user_data == CONFIG_PL2303_READ1 && xfer->result == XFER_RESULT_SUCCESS ); - type = pl2303_detect_type (p_cdc, 2, NULL, 0); // step 2 now with supports_hx_status - TU_ASSERT_COMPLETE(type!=PL2303_DETECT_TYPE_FAILED); + p_cdc->pl2303.supports_hx_status = (// will not be true, if coming directly from previous case + xfer->user_data == CONFIG_PL2303_READ1 && xfer->result == XFER_RESULT_SUCCESS); + type = pl2303_detect_type(p_cdc, 2, NULL, 0); // step 2 now with supports_hx_status + TU_ASSERT(type != PL2303_DETECT_TYPE_FAILED); p_cdc->pl2303.serial_private.type = &pl2303_type_data[type]; p_cdc->pl2303.serial_private.quirks |= p_cdc->pl2303.serial_private.type->quirks; - #if CFG_TUSB_DEBUG >= CFG_TUH_CDC_LOG_LEVEL && 0 // can be activated if necessary - TU_LOG_P_CDC("bDeviceClass = 0x%02x bMaxPacketSize0 = %u bcdUSB = 0x%04x bcdDevice = 0x%04x", - desc_dev->bDeviceClass, desc_dev->bMaxPacketSize0, - desc_dev->bcdUSB, desc_dev->bcdDevice ); - uint16_t vid, pid; - TU_ASSERT_COMPLETE(tuh_vid_pid_get(p_cdc->daddr, &vid, &pid)); - TU_LOG_P_CDC("vid = 0x%04x pid = 0x%04x supports_hx_status = %u type = %s quirks = %u", - vid, pid, p_cdc->pl2303.supports_hx_status, - p_cdc->pl2303.serial_private.type->name, p_cdc->pl2303.serial_private.quirks); + #if CFG_TUSB_DEBUG >= CFG_TUH_CDC_LOG_LEVEL && 0// can be activated if necessary + TU_LOG_P_CDC("bDeviceClass = 0x%02x bMaxPacketSize0 = %u bcdUSB = 0x%04x bcdDevice = 0x%04x", + desc_dev->bDeviceClass, desc_dev->bMaxPacketSize0, + desc_dev->bcdUSB, desc_dev->bcdDevice); + uint16_t vid, pid; + TU_ASSERT(tuh_vid_pid_get(p_cdc->daddr, &vid, &pid)); + TU_LOG_P_CDC("vid = 0x%04x pid = 0x%04x supports_hx_status = %u type = %s quirks = %u", + vid, pid, p_cdc->pl2303.supports_hx_status, + p_cdc->pl2303.serial_private.type->name, p_cdc->pl2303.serial_private.quirks); #endif // purpose unknown, overtaken from Linux Kernel driver if (p_cdc->pl2303.serial_private.type != &pl2303_type_data[TYPE_HXN]) { - TU_ASSERT_COMPLETE(pl2303_vendor_read(p_cdc, 0x8484, &buf, pl2303_process_config, CONFIG_PL2303_WRITE1)); + TU_ASSERT(pl2303_vendor_read(p_cdc, 0x8484, &buf, + cdch_process_set_config, PROCESS_CONFIG_STATE(idx, CONFIG_PL2303_WRITE1))); break; - } // else: continue with next step + }// else: continue with next step TU_ATTR_FALLTHROUGH; case CONFIG_PL2303_WRITE1: // purpose unknown, overtaken from Linux Kernel driver if (p_cdc->pl2303.serial_private.type != &pl2303_type_data[TYPE_HXN]) { - TU_ASSERT_COMPLETE(pl2303_vendor_write(p_cdc, 0x0404, 0, pl2303_process_config, CONFIG_PL2303_READ2)); + TU_ASSERT(pl2303_vendor_write(p_cdc, 0x0404, 0, + cdch_process_set_config, PROCESS_CONFIG_STATE(idx, CONFIG_PL2303_READ2))); break; - } // else: continue with next step + }// else: continue with next step TU_ATTR_FALLTHROUGH; case CONFIG_PL2303_READ2: // purpose unknown, overtaken from Linux Kernel driver if (p_cdc->pl2303.serial_private.type != &pl2303_type_data[TYPE_HXN]) { - TU_ASSERT_COMPLETE(pl2303_vendor_read(p_cdc, 0x8484, &buf, pl2303_process_config, CONFIG_PL2303_READ3)); + TU_ASSERT(pl2303_vendor_read(p_cdc, 0x8484, &buf, + cdch_process_set_config, PROCESS_CONFIG_STATE(idx, CONFIG_PL2303_READ3))); break; - } // else: continue with next step + }// else: continue with next step TU_ATTR_FALLTHROUGH; case CONFIG_PL2303_READ3: // purpose unknown, overtaken from Linux Kernel driver if (p_cdc->pl2303.serial_private.type != &pl2303_type_data[TYPE_HXN]) { - TU_ASSERT_COMPLETE(pl2303_vendor_read(p_cdc, 0x8383, &buf, pl2303_process_config, CONFIG_PL2303_READ4)); + TU_ASSERT(pl2303_vendor_read(p_cdc, 0x8383, &buf, + cdch_process_set_config, PROCESS_CONFIG_STATE(idx, CONFIG_PL2303_READ4))); break; - } // else: continue with next step + }// else: continue with next step TU_ATTR_FALLTHROUGH; case CONFIG_PL2303_READ4: // purpose unknown, overtaken from Linux Kernel driver if (p_cdc->pl2303.serial_private.type != &pl2303_type_data[TYPE_HXN]) { - TU_ASSERT_COMPLETE(pl2303_vendor_read(p_cdc, 0x8484, &buf, pl2303_process_config, CONFIG_PL2303_WRITE2)); + TU_ASSERT(pl2303_vendor_read(p_cdc, 0x8484, &buf, + cdch_process_set_config, PROCESS_CONFIG_STATE(idx, CONFIG_PL2303_WRITE2))); break; - } // else: continue with next step + }// else: continue with next step TU_ATTR_FALLTHROUGH; case CONFIG_PL2303_WRITE2: // purpose unknown, overtaken from Linux Kernel driver if (p_cdc->pl2303.serial_private.type != &pl2303_type_data[TYPE_HXN]) { - TU_ASSERT_COMPLETE(pl2303_vendor_write(p_cdc, 0x0404, 1, pl2303_process_config, CONFIG_PL2303_READ5)); + TU_ASSERT(pl2303_vendor_write(p_cdc, 0x0404, 1, + cdch_process_set_config, PROCESS_CONFIG_STATE(idx, CONFIG_PL2303_READ5))); break; - } // else: continue with next step + }// else: continue with next step TU_ATTR_FALLTHROUGH; case CONFIG_PL2303_READ5: // purpose unknown, overtaken from Linux Kernel driver if (p_cdc->pl2303.serial_private.type != &pl2303_type_data[TYPE_HXN]) { - TU_ASSERT_COMPLETE(pl2303_vendor_read(p_cdc, 0x8484, &buf, pl2303_process_config, CONFIG_PL2303_READ6)); + TU_ASSERT(pl2303_vendor_read(p_cdc, 0x8484, &buf, + cdch_process_set_config, PROCESS_CONFIG_STATE(idx, CONFIG_PL2303_READ6))); break; - } // else: continue with next step + }// else: continue with next step TU_ATTR_FALLTHROUGH; case CONFIG_PL2303_READ6: // purpose unknown, overtaken from Linux Kernel driver if (p_cdc->pl2303.serial_private.type != &pl2303_type_data[TYPE_HXN]) { - TU_ASSERT_COMPLETE(pl2303_vendor_read(p_cdc, 0x8383, &buf, pl2303_process_config, CONFIG_PL2303_WRITE3)); + TU_ASSERT(pl2303_vendor_read(p_cdc, 0x8383, &buf, + cdch_process_set_config, PROCESS_CONFIG_STATE(idx, CONFIG_PL2303_WRITE3))); break; - } // else: continue with next step + }// else: continue with next step TU_ATTR_FALLTHROUGH; case CONFIG_PL2303_WRITE3: // purpose unknown, overtaken from Linux Kernel driver if (p_cdc->pl2303.serial_private.type != &pl2303_type_data[TYPE_HXN]) { - TU_ASSERT_COMPLETE(pl2303_vendor_write(p_cdc, 0, 1, pl2303_process_config, CONFIG_PL2303_WRITE4)); + TU_ASSERT(pl2303_vendor_write(p_cdc, 0, 1, + cdch_process_set_config, PROCESS_CONFIG_STATE(idx, CONFIG_PL2303_WRITE4))); break; - } // else: continue with next step + }// else: continue with next step TU_ATTR_FALLTHROUGH; case CONFIG_PL2303_WRITE4: // purpose unknown, overtaken from Linux Kernel driver if (p_cdc->pl2303.serial_private.type != &pl2303_type_data[TYPE_HXN]) { - TU_ASSERT_COMPLETE(pl2303_vendor_write(p_cdc, 1, 0, pl2303_process_config, CONFIG_PL2303_WRITE5)); + TU_ASSERT(pl2303_vendor_write(p_cdc, 1, 0, + cdch_process_set_config, PROCESS_CONFIG_STATE(idx, CONFIG_PL2303_WRITE5))); break; - } // else: continue with next step + }// else: continue with next step TU_ATTR_FALLTHROUGH; case CONFIG_PL2303_WRITE5: // purpose unknown, overtaken from Linux Kernel driver if (p_cdc->pl2303.serial_private.type != &pl2303_type_data[TYPE_HXN]) { - if (p_cdc->pl2303.serial_private.quirks & PL2303_QUIRK_LEGACY) { - TU_ASSERT_COMPLETE(pl2303_vendor_write(p_cdc, 2, 0x24, pl2303_process_config, CONFIG_PL2303_RESET_ENDP1)); - } else { - TU_ASSERT_COMPLETE(pl2303_vendor_write(p_cdc, 2, 0x44, pl2303_process_config, CONFIG_PL2303_RESET_ENDP1)); - } + uint16_t const windex = (p_cdc->pl2303.serial_private.quirks & PL2303_QUIRK_LEGACY) ? 0x24 : 0x44; + TU_ASSERT(pl2303_vendor_write(p_cdc, 2, windex, + cdch_process_set_config, PROCESS_CONFIG_STATE(idx, CONFIG_PL2303_RESET_ENDP1))); break; - } // else: continue with next step + }// else: continue with next step TU_ATTR_FALLTHROUGH; - // from here sequence overtaken from Linux Kernel function pl2303_open() + // from here sequence overtaken from Linux Kernel function pl2303_open() case CONFIG_PL2303_RESET_ENDP1: // step 1 if (p_cdc->pl2303.serial_private.quirks & PL2303_QUIRK_LEGACY) { - TU_ASSERT_COMPLETE(pl2303_clear_halt(p_cdc, PL2303_OUT_EP, pl2303_process_config, CONFIG_PL2303_RESET_ENDP2)); + TU_ASSERT(pl2303_clear_halt(p_cdc, PL2303_OUT_EP, + cdch_process_set_config, PROCESS_CONFIG_STATE(idx, CONFIG_PL2303_RESET_ENDP2))); } else { /* reset upstream data pipes */ if (p_cdc->pl2303.serial_private.type == &pl2303_type_data[TYPE_HXN]) { - TU_ASSERT_COMPLETE(pl2303_vendor_write(p_cdc, PL2303_HXN_RESET_REG, // skip CONFIG_PL2303_RESET_ENDP2, no 2nd step + TU_ASSERT(pl2303_vendor_write(p_cdc, PL2303_HXN_RESET_REG,// skip CONFIG_PL2303_RESET_ENDP2, no 2nd step PL2303_HXN_RESET_UPSTREAM_PIPE | PL2303_HXN_RESET_DOWNSTREAM_PIPE, - pl2303_process_config, CONFIG_PL2303_LINE_CODING)); + cdch_process_set_config, PROCESS_CONFIG_STATE(idx, CONFIG_PL2303_LINE_CODING))); } else { - pl2303_vendor_write(p_cdc, 8, 0, pl2303_process_config, CONFIG_PL2303_RESET_ENDP2); + pl2303_vendor_write(p_cdc, 8, 0, + cdch_process_set_config, PROCESS_CONFIG_STATE(idx, CONFIG_PL2303_RESET_ENDP2)); } } break; @@ -2673,91 +2678,96 @@ static void pl2303_process_config(tuh_xfer_t * xfer) { case CONFIG_PL2303_RESET_ENDP2: // step 2 if (p_cdc->pl2303.serial_private.quirks & PL2303_QUIRK_LEGACY) { - TU_ASSERT_COMPLETE(pl2303_clear_halt(p_cdc, PL2303_IN_EP, pl2303_process_config, CONFIG_PL2303_LINE_CODING)); + TU_ASSERT(pl2303_clear_halt(p_cdc, PL2303_IN_EP, + cdch_process_set_config, PROCESS_CONFIG_STATE(idx, CONFIG_PL2303_LINE_CODING))); } else { /* reset upstream data pipes */ if (p_cdc->pl2303.serial_private.type == &pl2303_type_data[TYPE_HXN]) { // here nothing to do, only structure of previous step overtaken for better reading and comparison } else { - TU_ASSERT_COMPLETE(pl2303_vendor_write(p_cdc, 9, 0, pl2303_process_config, CONFIG_PL2303_LINE_CODING)); + TU_ASSERT(pl2303_vendor_write(p_cdc, 9, 0, + cdch_process_set_config, PROCESS_CONFIG_STATE(idx, CONFIG_PL2303_LINE_CODING))); } } break; - // from here sequence overtaken from Linux Kernel function pl2303_set_termios() - // unnecessary pl2303_get_line_request() is skipped due to a stall + // from here sequence overtaken from Linux Kernel function pl2303_set_termios() + // unnecessary pl2303_get_line_request() is skipped due to a stall case CONFIG_PL2303_LINE_CODING: - #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM - p_cdc->requested_line_coding = (cdc_line_coding_t) CFG_TUH_CDC_LINE_CODING_ON_ENUM; - TU_ASSERT_COMPLETE( pl2303_set_line_request(p_cdc, pl2303_internal_control_complete, CONFIG_PL2303_MODEM_CONTROL)); - break; - #else - TU_ATTR_FALLTHROUGH; - #endif + #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM + p_cdc->requested_line_coding = (cdc_line_coding_t) CFG_TUH_CDC_LINE_CODING_ON_ENUM; + TU_ASSERT(pl2303_set_line_request(p_cdc, pl2303_internal_control_complete, + PROCESS_CONFIG_STATE(idx, CONFIG_PL2303_MODEM_CONTROL))); + break; + #else + TU_ATTR_FALLTHROUGH; + #endif case CONFIG_PL2303_MODEM_CONTROL: - #ifdef LINE_CONTROL_ON_ENUM - p_cdc->requested_line_state.all = LINE_CONTROL_ON_ENUM; - TU_ASSERT_COMPLETE(pl2303_set_control_lines(p_cdc, pl2303_internal_control_complete, CONFIG_PL2303_COMPLETE)); - break; - #else - TU_ATTR_FALLTHROUGH; - #endif + #ifdef LINE_CONTROL_ON_ENUM + p_cdc->requested_line_state.all = LINE_CONTROL_ON_ENUM; + TU_ASSERT(pl2303_set_control_lines(p_cdc, pl2303_internal_control_complete, + PROCESS_CONFIG_STATE(idx, CONFIG_PL2303_COMPLETE))); + break; + #else + TU_ATTR_FALLTHROUGH; + #endif -// skipped, because it's not working with each PL230x. flow control can be also set by PL2303 EEPROM Writer Program -// case CONFIG_PL2303_FLOW_CTRL_READ: -// // read flow control register for modify & write back in next step -// if (p_cdc->pl2303.serial_private.type == &pl2303_type_data[TYPE_HXN]) { -// TU_LOG_P_CDC ( "1\r\n" ); -// TU_ASSERT_COMPLETE(pl2303_vendor_read(p_cdc, PL2303_HXN_FLOWCTRL_REG, &buf, pl2303_process_config, -// CONFIG_PL2303_FLOW_CTRL_WRITE)); -// } else { -// TU_LOG_P_CDC ( "2\r\n" ); -// TU_ASSERT_COMPLETE(pl2303_vendor_read(p_cdc, 0, &buf, pl2303_process_config, CONFIG_PL2303_FLOW_CTRL_WRITE)); -// } -// break; -// -// case CONFIG_PL2303_FLOW_CTRL_WRITE: -// // no flow control -// buf = xfer->buffer[0]; -// if (p_cdc->pl2303.serial_private.type == &pl2303_type_data[TYPE_HXN]) { -// buf &= (uint8_t) ~PL2303_HXN_FLOWCTRL_MASK; -// buf |= PL2303_HXN_FLOWCTRL_NONE; -// TU_ASSERT_COMPLETE(pl2303_vendor_write(p_cdc, PL2303_HXN_FLOWCTRL_REG, buf, pl2303_process_config, -// CONFIG_PL2303_COMPLETE)); -// } else { -// buf &= (uint8_t) ~PL2303_FLOWCTRL_MASK; -// TU_ASSERT_COMPLETE(pl2303_vendor_write(p_cdc, 0, buf, pl2303_process_config, CONFIG_PL2303_COMPLETE)); -// } -// break; + // skipped, because it's not working with each PL230x. flow control can be also set by PL2303 EEPROM Writer Program + // case CONFIG_PL2303_FLOW_CTRL_READ: + // // read flow control register for modify & write back in next step + // if (p_cdc->pl2303.serial_private.type == &pl2303_type_data[TYPE_HXN]) { + // TU_LOG_P_CDC ( "1\r\n" ); + // TU_ASSERT(pl2303_vendor_read(p_cdc, PL2303_HXN_FLOWCTRL_REG, &buf, + // cdch_process_set_config, PROCESS_CONFIG_STATE(idx, CONFIG_PL2303_FLOW_CTRL_WRITE))); + // } else { + // TU_LOG_P_CDC ( "2\r\n" ); + // TU_ASSERT(pl2303_vendor_read(p_cdc, 0, &buf, cdch_process_set_config, CONFIG_PL2303_FLOW_CTRL_WRITE)); + // } + // break; + // + // case CONFIG_PL2303_FLOW_CTRL_WRITE: + // // no flow control + // buf = xfer->buffer[0]; + // if (p_cdc->pl2303.serial_private.type == &pl2303_type_data[TYPE_HXN]) { + // buf &= (uint8_t) ~PL2303_HXN_FLOWCTRL_MASK; + // buf |= PL2303_HXN_FLOWCTRL_NONE; + // TU_ASSERT(pl2303_vendor_write(p_cdc, PL2303_HXN_FLOWCTRL_REG, buf, + // cdch_process_set_config, PROCESS_CONFIG_STATE(idx, CONFIG_PL2303_COMPLETE))); + // } else { + // buf &= (uint8_t) ~PL2303_FLOWCTRL_MASK; + // TU_ASSERT(pl2303_vendor_write(p_cdc, 0, buf, + // cdch_process_set_config, PROCESS_CONFIG_STATE(idx, CONFIG_PL2303_COMPLETE))); + // } + // break; case CONFIG_PL2303_COMPLETE: set_config_complete(idx, 0, true); break; default: - TU_ASSERT_COMPLETE(false); - break; + return false; } + + return true; } //------------- Helper -------------// -static int8_t pl2303_detect_type(cdch_interface_t * p_cdc, uint8_t step, - tuh_xfer_cb_t complete_cb, uintptr_t user_data ) -{ +static int8_t pl2303_detect_type(cdch_interface_t *p_cdc, uint8_t step, + tuh_xfer_cb_t complete_cb, uintptr_t user_data) { /* * Legacy PL2303H, variants 0 and 1 (difference unknown). */ if (desc_dev->bDeviceClass == 0x02) { - return TYPE_H; /* variant 0 */ + return TYPE_H; /* variant 0 */ } if (desc_dev->bMaxPacketSize0 != 0x40) { if (desc_dev->bDeviceClass == 0x00 || desc_dev->bDeviceClass == 0xff) { - return TYPE_H; /* variant 1 */ + return TYPE_H; /* variant 1 */ } - return TYPE_H; /* variant 0 */ + return TYPE_H; /* variant 0 */ } switch (desc_dev->bcdUSB) { @@ -2782,7 +2792,7 @@ static int8_t pl2303_detect_type(cdch_interface_t * p_cdc, uint8_t step, case 0x300: /* GT / TA */ if (step == 1) { // step 1 trigger pl2303_supports_hx_status() request - TU_ASSERT(pl2303_supports_hx_status (p_cdc, complete_cb, user_data), PL2303_DETECT_TYPE_FAILED); + TU_ASSERT(pl2303_supports_hx_status(p_cdc, complete_cb, user_data), PL2303_DETECT_TYPE_FAILED); return PL2303_SUPPORTS_HX_STATUS_TRIGGERED; } else { // step 2 use supports_hx_status @@ -2798,7 +2808,7 @@ static int8_t pl2303_detect_type(cdch_interface_t * p_cdc, uint8_t step, case 0x500: /* GE / TB */ if (step == 1) { // step 1 trigger pl2303_supports_hx_status() request - TU_ASSERT(pl2303_supports_hx_status (p_cdc, complete_cb, user_data), PL2303_DETECT_TYPE_FAILED); + TU_ASSERT(pl2303_supports_hx_status(p_cdc, complete_cb, user_data), PL2303_DETECT_TYPE_FAILED); return PL2303_SUPPORTS_HX_STATUS_TRIGGERED; } else { // step 2 use supports_hx_status @@ -2829,8 +2839,7 @@ static int8_t pl2303_detect_type(cdch_interface_t * p_cdc, uint8_t step, * Returns the nearest supported baud rate that can be set directly without * using divisors. */ -static uint32_t pl2303_get_supported_baud_rate(uint32_t baud) -{ +static uint32_t pl2303_get_supported_baud_rate(uint32_t baud) { static const uint32_t baud_sup[] = { 75, 150, 300, 600, 1200, 1800, 2400, 3600, 4800, 7200, 9600, 14400, 19200, 28800, 38400, 57600, 115200, 230400, 460800, @@ -2859,8 +2868,7 @@ static uint32_t pl2303_get_supported_baud_rate(uint32_t baud) * NOTE: If unsupported baud rates are set directly, the PL2303 seems to * use 9600 baud. */ -static uint32_t pl2303_encode_baud_rate_direct(uint8_t buf[PL2303_LINE_CODING_BAUDRATE_BUFSIZE], uint32_t baud) -{ +static uint32_t pl2303_encode_baud_rate_direct(uint8_t buf[PL2303_LINE_CODING_BAUDRATE_BUFSIZE], uint32_t baud) { uint32_t baud_le = tu_htole32(baud); buf[0] = (uint8_t) ( baud_le & 0xff); buf[1] = (uint8_t) ((baud_le >> 8) & 0xff); @@ -2870,8 +2878,7 @@ static uint32_t pl2303_encode_baud_rate_direct(uint8_t buf[PL2303_LINE_CODING_BA return baud; } -static uint32_t pl2303_encode_baud_rate_divisor(uint8_t buf[PL2303_LINE_CODING_BAUDRATE_BUFSIZE], uint32_t baud) -{ +static uint32_t pl2303_encode_baud_rate_divisor(uint8_t buf[PL2303_LINE_CODING_BAUDRATE_BUFSIZE], uint32_t baud) { uint32_t baseline, mantissa, exponent; /* @@ -2899,7 +2906,7 @@ static uint32_t pl2303_encode_baud_rate_divisor(uint8_t buf[PL2303_LINE_CODING_B buf[3] = 0x80; buf[2] = 0; - buf[1] = (uint8_t) ((exponent << 1 | mantissa >> 8) & 0xff); + buf[1] = (uint8_t) ((exponent << 1 | mantissa >> 8) & 0xff); buf[0] = (uint8_t) (mantissa & 0xff); /* Calculate and return the exact baud rate. */ @@ -2908,8 +2915,7 @@ static uint32_t pl2303_encode_baud_rate_divisor(uint8_t buf[PL2303_LINE_CODING_B return baud; } -static uint32_t pl2303_encode_baud_rate_divisor_alt(uint8_t buf[PL2303_LINE_CODING_BAUDRATE_BUFSIZE], uint32_t baud) -{ +static uint32_t pl2303_encode_baud_rate_divisor_alt(uint8_t buf[PL2303_LINE_CODING_BAUDRATE_BUFSIZE], uint32_t baud) { uint32_t baseline, mantissa, exponent; /* @@ -2922,7 +2928,7 @@ static uint32_t pl2303_encode_baud_rate_divisor_alt(uint8_t buf[PL2303_LINE_CODI baseline = 12000000 * 32; mantissa = baseline / baud; if (mantissa == 0) { - mantissa = 1; /* Avoid dividing by zero if baud > 32 * 12M. */ + mantissa = 1; /* Avoid dividing by zero if baud > 32 * 12M. */ } exponent = 0; while (mantissa >= 2048) { @@ -2938,7 +2944,7 @@ static uint32_t pl2303_encode_baud_rate_divisor_alt(uint8_t buf[PL2303_LINE_CODI buf[3] = 0x80; buf[2] = (uint8_t) (exponent & 0x01); - buf[1] = (uint8_t) (((exponent & (uint32_t) ~0x01) << 4 | mantissa >> 8 ) & 0xff); + buf[1] = (uint8_t) (((exponent & (uint32_t) ~0x01) << 4 | mantissa >> 8) & 0xff); buf[0] = (uint8_t) (mantissa & 0xff); /* Calculate and return the exact baud rate. */ @@ -2947,8 +2953,7 @@ static uint32_t pl2303_encode_baud_rate_divisor_alt(uint8_t buf[PL2303_LINE_CODI return baud; } -static bool pl2303_encode_baud_rate(cdch_interface_t * p_cdc, uint8_t buf[PL2303_LINE_CODING_BAUDRATE_BUFSIZE]) -{ +static bool pl2303_encode_baud_rate(cdch_interface_t *p_cdc, uint8_t buf[PL2303_LINE_CODING_BAUDRATE_BUFSIZE]) { uint32_t baud = p_cdc->requested_line_coding.bit_rate; uint32_t baud_sup; -- cgit v1.3.1 From 506edc626709ca92dd9c38d6c6f5813f30a27692 Mon Sep 17 00:00:00 2001 From: hathach Date: Wed, 18 Jun 2025 18:55:31 +0700 Subject: add get_itf_by_xfer() to better determine cdc interface from xfer complete callback --- src/class/cdc/cdc_host.c | 182 +++++++++++++++++++++++++++-------------------- 1 file changed, 105 insertions(+), 77 deletions(-) (limited to 'src/class') diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index b6e9cb297..3be61e654 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -131,9 +131,6 @@ CFG_TUH_MEM_SECTION static cdch_epbuf_t cdch_epbuf[CFG_TUH_CDC]; // Serial Driver //--------------------------------------------------------------------+ -// for process_set_config user_data: idx (byte1) and state (byte0) -#define PROCESS_CONFIG_STATE(_idx, _state) tu_u16(_idx, _state) - static void cdch_process_set_config(tuh_xfer_t *xfer); //------------- ACM prototypes -------------// @@ -327,13 +324,16 @@ TU_VERIFY_STATIC(TU_ARRAY_SIZE(serial_drivers) == SERIAL_DRIVER_COUNT, "Serial d // INTERNAL OBJECT & FUNCTION DECLARATION //--------------------------------------------------------------------+ -static inline cdch_interface_t * get_itf(uint8_t idx) { +TU_ATTR_ALWAYS_INLINE 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; } +TU_ATTR_ALWAYS_INLINE static inline uint8_t get_idx_by_ptr(cdch_interface_t* p_cdc) { + return p_cdc - cdch_data; +} + static inline uint8_t get_idx_by_ep_addr(uint8_t daddr, uint8_t ep_addr) { for(uint8_t i=0; idaddr != 0, NULL); + for(uint8_t i=0; idaddr == xfer->daddr) { + switch (p_cdc->serial_drid) { + #if CFG_TUH_CDC_CP210X + case SERIAL_DRIVER_CP210X: + #endif + case SERIAL_DRIVER_ACM: { + // Driver use wIndex for bInterfaceNumber + const uint8_t itf_num = (uint8_t) tu_le16toh(xfer->setup->wIndex); + if (p_cdc->bInterfaceNumber == itf_num) { + return p_cdc; + } + break; + } + + #if CFG_TUH_CDC_FTDI + case SERIAL_DRIVER_FTDI: { + // FTDI uses wIndex for channel number, if channel is 0 then it is the default channel + const uint8_t channel = (uint8_t) tu_le16toh(xfer->setup->wIndex); + if (p_cdc->ftdi.channel == 0 || p_cdc->ftdi.channel == channel) { + return p_cdc; + } + break; + } + #endif + + #if CFG_TUH_CDC_CH34X + case SERIAL_DRIVER_CH34X: + // ch34x has only one interface + return p_cdc; + #endif + + #if CFG_TUH_CDC_PL2303 + case SERIAL_DRIVER_PL2303: + // pl2303 has only one interface + return p_cdc; + #endif + + default: + break; + } + } + } + + return NULL; +} + static cdch_interface_t * make_new_itf(uint8_t daddr, tusb_desc_interface_t const * itf_desc) { for(uint8_t i=0; iserial_drid < SERIAL_DRIVER_COUNT); - TU_LOG_P_CDC("set control line state dtr = %u rts = %u", line_state.dtr, line_state.rts ); + TU_LOG_P_CDC("set control line state dtr = %u rts = %u", line_state.dtr, line_state.rts); cdch_serial_driver_t const * driver = &serial_drivers[p_cdc->serial_drid]; p_cdc->requested_line_state = line_state; @@ -614,8 +665,6 @@ bool tuh_cdc_set_control_line_state_u(uint8_t idx, cdc_line_control_state_t line if (ret && !complete_cb) { p_cdc->line_state = line_state; } -// TU_LOG_P_CDC_BOOL("set control line state", ret); - return ret; } @@ -893,9 +942,9 @@ static void set_config_complete(uint8_t idx, uint8_t itf_offset, bool success) { } static void cdch_process_set_config(tuh_xfer_t *xfer) { - const uint8_t idx = tu_u32_byte1(xfer->user_data); - cdch_interface_t *p_cdc = get_itf(idx); + cdch_interface_t *p_cdc = get_itf_by_xfer(xfer); TU_ASSERT(p_cdc && p_cdc->serial_drid < SERIAL_DRIVER_COUNT,); + const uint8_t idx = get_idx_by_ptr(p_cdc); if (!serial_drivers[p_cdc->serial_drid].process_set_config(xfer)) { const uint8_t itf_offset = (p_cdc->serial_drid == SERIAL_DRIVER_ACM) ? 1 : 0; @@ -916,7 +965,7 @@ bool cdch_set_config(uint8_t daddr, uint8_t itf_num) { xfer.daddr = daddr; xfer.result = XFER_RESULT_SUCCESS; xfer.setup = &request; - xfer.user_data = PROCESS_CONFIG_STATE(idx, 0); // initial state 0 + xfer.user_data = 0; // initial state 0 cdch_process_set_config(&xfer); return true; @@ -1093,7 +1142,7 @@ static bool acm_open(uint8_t daddr, tusb_desc_interface_t const *itf_desc, uint1 } static bool acm_process_set_config(tuh_xfer_t *xfer) { - const uint8_t state = (uint8_t) xfer->user_data; + const uintptr_t 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); @@ -1104,7 +1153,7 @@ static bool acm_process_set_config(tuh_xfer_t *xfer) { #ifdef LINE_CONTROL_ON_ENUM if (p_cdc->acm_capability.support_line_request) { p_cdc->requested_line_state.all = LINE_CONTROL_ON_ENUM; - TU_ASSERT(acm_set_control_line_state(p_cdc, cdch_process_set_config, PROCESS_CONFIG_STATE(idx, CONFIG_ACM_SET_LINE_CODING))); + TU_ASSERT(acm_set_control_line_state(p_cdc, cdch_process_set_config, CONFIG_ACM_SET_LINE_CODING)); break; } #endif @@ -1114,7 +1163,7 @@ static bool acm_process_set_config(tuh_xfer_t *xfer) { #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM if (p_cdc->acm_capability.support_line_request) { p_cdc->requested_line_coding = (cdc_line_coding_t) CFG_TUH_CDC_LINE_CODING_ON_ENUM; - TU_ASSERT(acm_set_line_coding(p_cdc, cdch_process_set_config, PROCESS_CONFIG_STATE(idx, CONFIG_ACM_COMPLETE))); + TU_ASSERT(acm_set_line_coding(p_cdc, cdch_process_set_config, CONFIG_ACM_COMPLETE)); break; } #endif @@ -1326,7 +1375,7 @@ static bool ftdi_open(uint8_t daddr, const tusb_desc_interface_t *itf_desc, uint } static bool ftdi_proccess_set_config(tuh_xfer_t *xfer) { - const uint8_t state = (uint8_t) xfer->user_data; + const uintptr_t state = xfer->user_data; uint8_t const idx = ftdi_get_idx(xfer); cdch_interface_t *p_cdc = get_itf(idx); uint8_t const itf_num = p_cdc->bInterfaceNumber; @@ -1338,7 +1387,7 @@ static bool ftdi_proccess_set_config(tuh_xfer_t *xfer) { // get device descriptor if (itf_num == 0) { // only necessary for 1st interface. other interface overtake type from interface 0 TU_ASSERT(tuh_descriptor_get_device(xfer->daddr, &desc_dev, sizeof(tusb_desc_device_t), - cdch_process_set_config, PROCESS_CONFIG_STATE(idx, CONFIG_FTDI_DETERMINE_TYPE))); + cdch_process_set_config, CONFIG_FTDI_DETERMINE_TYPE)); break; } TU_ATTR_FALLTHROUGH; @@ -1370,7 +1419,7 @@ static bool ftdi_proccess_set_config(tuh_xfer_t *xfer) { // from here sequence overtaken from Linux Kernel function ftdi_open() case CONFIG_FTDI_SIO_RESET: p_cdc->user_control_cb = cdch_process_set_config; - TU_ASSERT(ftdi_sio_reset(p_cdc, cdch_process_set_config, PROCESS_CONFIG_STATE(idx, CONFIG_FTDI_SET_DATA))); + TU_ASSERT(ftdi_sio_reset(p_cdc, cdch_process_set_config, CONFIG_FTDI_SET_DATA)); break; // from here sequence overtaken from Linux Kernel function ftdi_set_termios() @@ -1378,7 +1427,7 @@ static bool ftdi_proccess_set_config(tuh_xfer_t *xfer) { #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM p_cdc->requested_line_coding = (cdc_line_coding_t) CFG_TUH_CDC_LINE_CODING_ON_ENUM; p_cdc->user_control_cb = cdch_process_set_config; - TU_ASSERT(ftdi_set_data_request(p_cdc, ftdi_internal_control_complete, PROCESS_CONFIG_STATE(idx, CONFIG_FTDI_SET_BAUDRATE))); + TU_ASSERT(ftdi_set_data_request(p_cdc, ftdi_internal_control_complete, CONFIG_FTDI_SET_BAUDRATE)); break; #else TU_ATTR_FALLTHROUGH; @@ -1387,7 +1436,7 @@ static bool ftdi_proccess_set_config(tuh_xfer_t *xfer) { case CONFIG_FTDI_SET_BAUDRATE: #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM p_cdc->user_control_cb = cdch_process_set_config; - TU_ASSERT(ftdi_change_speed(p_cdc, ftdi_internal_control_complete, PROCESS_CONFIG_STATE(idx, CONFIG_FTDI_FLOW_CONTROL))); + TU_ASSERT(ftdi_change_speed(p_cdc, ftdi_internal_control_complete, CONFIG_FTDI_FLOW_CONTROL)); break; #else TU_ATTR_FALLTHROUGH; @@ -1396,14 +1445,14 @@ static bool ftdi_proccess_set_config(tuh_xfer_t *xfer) { case CONFIG_FTDI_FLOW_CONTROL: // disable flow control TU_ASSERT(ftdi_set_request(p_cdc, FTDI_SIO_SET_FLOW_CTRL_REQUEST, FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE, FTDI_SIO_DISABLE_FLOW_CTRL, - p_cdc->ftdi.channel, cdch_process_set_config, PROCESS_CONFIG_STATE(idx, CONFIG_FTDI_MODEM_CTRL))); + p_cdc->ftdi.channel, cdch_process_set_config, CONFIG_FTDI_MODEM_CTRL)); break; case CONFIG_FTDI_MODEM_CTRL: #ifdef LINE_CONTROL_ON_ENUM p_cdc->requested_line_state.all = LINE_CONTROL_ON_ENUM; p_cdc->user_control_cb = cdch_process_set_config; - TU_ASSERT(ftdi_update_mctrl(p_cdc, ftdi_internal_control_complete, PROCESS_CONFIG_STATE(idx, CONFIG_FTDI_COMPLETE))); + TU_ASSERT(ftdi_update_mctrl(p_cdc, ftdi_internal_control_complete, CONFIG_FTDI_COMPLETE)); break; #else TU_ATTR_FALLTHROUGH; @@ -1840,7 +1889,7 @@ static bool cp210x_open(uint8_t daddr, tusb_desc_interface_t const *itf_desc, ui } static bool cp210x_process_set_config(tuh_xfer_t *xfer) { - const uint8_t state = (uint8_t) xfer->user_data; + const uintptr_t 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); @@ -1848,16 +1897,14 @@ static bool cp210x_process_set_config(tuh_xfer_t *xfer) { switch (state) { case CONFIG_CP210X_IFC_ENABLE: - TU_ASSERT(cp210x_ifc_enable(p_cdc, CP210X_UART_ENABLE, cdch_process_set_config, - PROCESS_CONFIG_STATE(idx, CONFIG_CP210X_SET_BAUDRATE_REQUEST))); + TU_ASSERT(cp210x_ifc_enable(p_cdc, CP210X_UART_ENABLE, cdch_process_set_config, CONFIG_CP210X_SET_BAUDRATE_REQUEST)); break; case CONFIG_CP210X_SET_BAUDRATE_REQUEST: #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM p_cdc->requested_line_coding = (cdc_line_coding_t) CFG_TUH_CDC_LINE_CODING_ON_ENUM; p_cdc->user_control_cb = cdch_process_set_config; - TU_ASSERT(cp210x_set_baudrate_request(p_cdc, cp210x_internal_control_complete, - PROCESS_CONFIG_STATE(idx, CONFIG_CP210X_SET_LINE_CTL))); + TU_ASSERT(cp210x_set_baudrate_request(p_cdc, cp210x_internal_control_complete, CONFIG_CP210X_SET_LINE_CTL)); break; #else TU_ATTR_FALLTHROUGH; @@ -1866,8 +1913,7 @@ static bool cp210x_process_set_config(tuh_xfer_t *xfer) { case CONFIG_CP210X_SET_LINE_CTL: #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM p_cdc->user_control_cb = cdch_process_set_config; - TU_ASSERT(cp210x_set_line_ctl(p_cdc, cp210x_internal_control_complete, - PROCESS_CONFIG_STATE(idx, CONFIG_CP210X_SET_DTR_RTS))); + TU_ASSERT(cp210x_set_line_ctl(p_cdc, cp210x_internal_control_complete, CONFIG_CP210X_SET_DTR_RTS)); break; #else TU_ATTR_FALLTHROUGH; @@ -1877,8 +1923,7 @@ static bool cp210x_process_set_config(tuh_xfer_t *xfer) { #ifdef LINE_CONTROL_ON_ENUM p_cdc->requested_line_state.all = LINE_CONTROL_ON_ENUM; p_cdc->user_control_cb = cdch_process_set_config; - TU_ASSERT(cp210x_set_mhs(p_cdc, cp210x_internal_control_complete, - PROCESS_CONFIG_STATE(idx, CONFIG_CP210X_COMPLETE))); + TU_ASSERT(cp210x_set_mhs(p_cdc, cp210x_internal_control_complete, CONFIG_CP210X_COMPLETE)); break; #else TU_ATTR_FALLTHROUGH; @@ -2108,7 +2153,7 @@ static bool ch34x_open(uint8_t daddr, tusb_desc_interface_t const * itf_desc, ui } static bool ch34x_process_set_config(tuh_xfer_t *xfer) { - const uint8_t state = (uint8_t) xfer->user_data; + const uintptr_t state = xfer->user_data; uint8_t const itf_num = 0; // CH34x has only interface 0, since wIndex is used as payload uint8_t const idx = tuh_cdc_itf_get_index(xfer->daddr, itf_num); cdch_interface_t *p_cdc = get_itf(idx); @@ -2119,7 +2164,7 @@ static bool ch34x_process_set_config(tuh_xfer_t *xfer) { switch (state) { case CONFIG_CH34X_READ_VERSION: TU_ASSERT(ch34x_control_in(p_cdc, CH34X_REQ_READ_VERSION, 0, 0, buffer, 2, - cdch_process_set_config, PROCESS_CONFIG_STATE(idx, CONFIG_CH34X_SERIAL_INIT))); + cdch_process_set_config, CONFIG_CH34X_SERIAL_INIT)); break; case CONFIG_CH34X_SERIAL_INIT: { @@ -2135,7 +2180,7 @@ static bool ch34x_process_set_config(tuh_xfer_t *xfer) { uint8_t const lcr = ch34x_get_lcr(p_cdc); TU_ASSERT(div_ps != 0 && lcr != 0); TU_ASSERT(ch34x_control_out(p_cdc, CH34X_REQ_SERIAL_INIT, tu_u16(lcr, 0x9c), div_ps, - cdch_process_set_config, PROCESS_CONFIG_STATE(idx, CONFIG_CH34X_SPECIAL_REG_WRITE))); + cdch_process_set_config, CONFIG_CH34X_SPECIAL_REG_WRITE)); } break; } @@ -2144,20 +2189,20 @@ static bool ch34x_process_set_config(tuh_xfer_t *xfer) { // 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, - cdch_process_set_config, PROCESS_CONFIG_STATE(idx, CONFIG_CH34X_FLOW_CONTROL))); + cdch_process_set_config, CONFIG_CH34X_FLOW_CONTROL)); break; case CONFIG_CH34X_FLOW_CONTROL: // no hardware flow control TU_ASSERT(ch34x_write_reg(p_cdc, TU_U16(CH341_REG_0x27, CH341_REG_0x27), 0x0000, - cdch_process_set_config, PROCESS_CONFIG_STATE(idx, CONFIG_CH34X_MODEM_CONTROL))); + cdch_process_set_config, CONFIG_CH34X_MODEM_CONTROL)); break; case CONFIG_CH34X_MODEM_CONTROL: #ifdef LINE_CONTROL_ON_ENUM p_cdc->requested_line_state.all = LINE_CONTROL_ON_ENUM; p_cdc->user_control_cb = cdch_process_set_config; - TU_ASSERT(ch34x_modem_ctrl_request(p_cdc, ch34x_internal_control_complete, PROCESS_CONFIG_STATE(idx, CONFIG_CH34X_COMPLETE))); + TU_ASSERT(ch34x_modem_ctrl_request(p_cdc, ch34x_internal_control_complete, CONFIG_CH34X_COMPLETE)); break; #else TU_ATTR_FALLTHROUGH; @@ -2511,7 +2556,7 @@ static bool pl2303_open(uint8_t daddr, tusb_desc_interface_t const *itf_desc, ui } static bool pl2303_process_set_config(tuh_xfer_t *xfer) { - const uint8_t state = (uint8_t) xfer->user_data; + const uintptr_t state = xfer->user_data; // PL2303 has only interface 0, because wIndex is used 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); @@ -2527,12 +2572,12 @@ static bool pl2303_process_set_config(tuh_xfer_t *xfer) { p_cdc->user_control_cb = cdch_process_set_config;// set once for whole process config // get device descriptor TU_ASSERT(tuh_descriptor_get_device(xfer->daddr, &desc_dev, sizeof(tusb_desc_device_t), - cdch_process_set_config, PROCESS_CONFIG_STATE(idx, CONFIG_PL2303_DETECT_TYPE))); + cdch_process_set_config, CONFIG_PL2303_DETECT_TYPE)); break; case CONFIG_PL2303_DETECT_TYPE: // get type and quirks (step 1) - type = pl2303_detect_type(p_cdc, 1, cdch_process_set_config, PROCESS_CONFIG_STATE(idx, CONFIG_PL2303_READ1)); + type = pl2303_detect_type(p_cdc, 1, cdch_process_set_config, CONFIG_PL2303_READ1); TU_ASSERT(type != PL2303_DETECT_TYPE_FAILED); if (type == PL2303_SUPPORTS_HX_STATUS_TRIGGERED) { break; @@ -2559,8 +2604,7 @@ static bool pl2303_process_set_config(tuh_xfer_t *xfer) { #endif // purpose unknown, overtaken from Linux Kernel driver if (p_cdc->pl2303.serial_private.type != &pl2303_type_data[TYPE_HXN]) { - TU_ASSERT(pl2303_vendor_read(p_cdc, 0x8484, &buf, - cdch_process_set_config, PROCESS_CONFIG_STATE(idx, CONFIG_PL2303_WRITE1))); + TU_ASSERT(pl2303_vendor_read(p_cdc, 0x8484, &buf, cdch_process_set_config, CONFIG_PL2303_WRITE1)); break; }// else: continue with next step TU_ATTR_FALLTHROUGH; @@ -2568,8 +2612,7 @@ static bool pl2303_process_set_config(tuh_xfer_t *xfer) { case CONFIG_PL2303_WRITE1: // purpose unknown, overtaken from Linux Kernel driver if (p_cdc->pl2303.serial_private.type != &pl2303_type_data[TYPE_HXN]) { - TU_ASSERT(pl2303_vendor_write(p_cdc, 0x0404, 0, - cdch_process_set_config, PROCESS_CONFIG_STATE(idx, CONFIG_PL2303_READ2))); + TU_ASSERT(pl2303_vendor_write(p_cdc, 0x0404, 0, cdch_process_set_config, CONFIG_PL2303_READ2)); break; }// else: continue with next step TU_ATTR_FALLTHROUGH; @@ -2577,8 +2620,7 @@ static bool pl2303_process_set_config(tuh_xfer_t *xfer) { case CONFIG_PL2303_READ2: // purpose unknown, overtaken from Linux Kernel driver if (p_cdc->pl2303.serial_private.type != &pl2303_type_data[TYPE_HXN]) { - TU_ASSERT(pl2303_vendor_read(p_cdc, 0x8484, &buf, - cdch_process_set_config, PROCESS_CONFIG_STATE(idx, CONFIG_PL2303_READ3))); + TU_ASSERT(pl2303_vendor_read(p_cdc, 0x8484, &buf, cdch_process_set_config, CONFIG_PL2303_READ3)); break; }// else: continue with next step TU_ATTR_FALLTHROUGH; @@ -2586,8 +2628,7 @@ static bool pl2303_process_set_config(tuh_xfer_t *xfer) { case CONFIG_PL2303_READ3: // purpose unknown, overtaken from Linux Kernel driver if (p_cdc->pl2303.serial_private.type != &pl2303_type_data[TYPE_HXN]) { - TU_ASSERT(pl2303_vendor_read(p_cdc, 0x8383, &buf, - cdch_process_set_config, PROCESS_CONFIG_STATE(idx, CONFIG_PL2303_READ4))); + TU_ASSERT(pl2303_vendor_read(p_cdc, 0x8383, &buf, cdch_process_set_config, CONFIG_PL2303_READ4)); break; }// else: continue with next step TU_ATTR_FALLTHROUGH; @@ -2595,8 +2636,7 @@ static bool pl2303_process_set_config(tuh_xfer_t *xfer) { case CONFIG_PL2303_READ4: // purpose unknown, overtaken from Linux Kernel driver if (p_cdc->pl2303.serial_private.type != &pl2303_type_data[TYPE_HXN]) { - TU_ASSERT(pl2303_vendor_read(p_cdc, 0x8484, &buf, - cdch_process_set_config, PROCESS_CONFIG_STATE(idx, CONFIG_PL2303_WRITE2))); + TU_ASSERT(pl2303_vendor_read(p_cdc, 0x8484, &buf, cdch_process_set_config, CONFIG_PL2303_WRITE2)); break; }// else: continue with next step TU_ATTR_FALLTHROUGH; @@ -2604,8 +2644,7 @@ static bool pl2303_process_set_config(tuh_xfer_t *xfer) { case CONFIG_PL2303_WRITE2: // purpose unknown, overtaken from Linux Kernel driver if (p_cdc->pl2303.serial_private.type != &pl2303_type_data[TYPE_HXN]) { - TU_ASSERT(pl2303_vendor_write(p_cdc, 0x0404, 1, - cdch_process_set_config, PROCESS_CONFIG_STATE(idx, CONFIG_PL2303_READ5))); + TU_ASSERT(pl2303_vendor_write(p_cdc, 0x0404, 1, cdch_process_set_config, CONFIG_PL2303_READ5)); break; }// else: continue with next step TU_ATTR_FALLTHROUGH; @@ -2613,8 +2652,7 @@ static bool pl2303_process_set_config(tuh_xfer_t *xfer) { case CONFIG_PL2303_READ5: // purpose unknown, overtaken from Linux Kernel driver if (p_cdc->pl2303.serial_private.type != &pl2303_type_data[TYPE_HXN]) { - TU_ASSERT(pl2303_vendor_read(p_cdc, 0x8484, &buf, - cdch_process_set_config, PROCESS_CONFIG_STATE(idx, CONFIG_PL2303_READ6))); + TU_ASSERT(pl2303_vendor_read(p_cdc, 0x8484, &buf, cdch_process_set_config, CONFIG_PL2303_READ6)); break; }// else: continue with next step TU_ATTR_FALLTHROUGH; @@ -2622,8 +2660,7 @@ static bool pl2303_process_set_config(tuh_xfer_t *xfer) { case CONFIG_PL2303_READ6: // purpose unknown, overtaken from Linux Kernel driver if (p_cdc->pl2303.serial_private.type != &pl2303_type_data[TYPE_HXN]) { - TU_ASSERT(pl2303_vendor_read(p_cdc, 0x8383, &buf, - cdch_process_set_config, PROCESS_CONFIG_STATE(idx, CONFIG_PL2303_WRITE3))); + TU_ASSERT(pl2303_vendor_read(p_cdc, 0x8383, &buf, cdch_process_set_config, CONFIG_PL2303_WRITE3)); break; }// else: continue with next step TU_ATTR_FALLTHROUGH; @@ -2631,8 +2668,7 @@ static bool pl2303_process_set_config(tuh_xfer_t *xfer) { case CONFIG_PL2303_WRITE3: // purpose unknown, overtaken from Linux Kernel driver if (p_cdc->pl2303.serial_private.type != &pl2303_type_data[TYPE_HXN]) { - TU_ASSERT(pl2303_vendor_write(p_cdc, 0, 1, - cdch_process_set_config, PROCESS_CONFIG_STATE(idx, CONFIG_PL2303_WRITE4))); + TU_ASSERT(pl2303_vendor_write(p_cdc, 0, 1, cdch_process_set_config, CONFIG_PL2303_WRITE4)); break; }// else: continue with next step TU_ATTR_FALLTHROUGH; @@ -2640,8 +2676,7 @@ static bool pl2303_process_set_config(tuh_xfer_t *xfer) { case CONFIG_PL2303_WRITE4: // purpose unknown, overtaken from Linux Kernel driver if (p_cdc->pl2303.serial_private.type != &pl2303_type_data[TYPE_HXN]) { - TU_ASSERT(pl2303_vendor_write(p_cdc, 1, 0, - cdch_process_set_config, PROCESS_CONFIG_STATE(idx, CONFIG_PL2303_WRITE5))); + TU_ASSERT(pl2303_vendor_write(p_cdc, 1, 0, cdch_process_set_config, CONFIG_PL2303_WRITE5)); break; }// else: continue with next step TU_ATTR_FALLTHROUGH; @@ -2650,8 +2685,7 @@ static bool pl2303_process_set_config(tuh_xfer_t *xfer) { // purpose unknown, overtaken from Linux Kernel driver if (p_cdc->pl2303.serial_private.type != &pl2303_type_data[TYPE_HXN]) { uint16_t const windex = (p_cdc->pl2303.serial_private.quirks & PL2303_QUIRK_LEGACY) ? 0x24 : 0x44; - TU_ASSERT(pl2303_vendor_write(p_cdc, 2, windex, - cdch_process_set_config, PROCESS_CONFIG_STATE(idx, CONFIG_PL2303_RESET_ENDP1))); + TU_ASSERT(pl2303_vendor_write(p_cdc, 2, windex, cdch_process_set_config, CONFIG_PL2303_RESET_ENDP1)); break; }// else: continue with next step TU_ATTR_FALLTHROUGH; @@ -2660,17 +2694,15 @@ static bool pl2303_process_set_config(tuh_xfer_t *xfer) { case CONFIG_PL2303_RESET_ENDP1: // step 1 if (p_cdc->pl2303.serial_private.quirks & PL2303_QUIRK_LEGACY) { - TU_ASSERT(pl2303_clear_halt(p_cdc, PL2303_OUT_EP, - cdch_process_set_config, PROCESS_CONFIG_STATE(idx, CONFIG_PL2303_RESET_ENDP2))); + TU_ASSERT(pl2303_clear_halt(p_cdc, PL2303_OUT_EP, cdch_process_set_config, CONFIG_PL2303_RESET_ENDP2)); } else { /* reset upstream data pipes */ if (p_cdc->pl2303.serial_private.type == &pl2303_type_data[TYPE_HXN]) { TU_ASSERT(pl2303_vendor_write(p_cdc, PL2303_HXN_RESET_REG,// skip CONFIG_PL2303_RESET_ENDP2, no 2nd step PL2303_HXN_RESET_UPSTREAM_PIPE | PL2303_HXN_RESET_DOWNSTREAM_PIPE, - cdch_process_set_config, PROCESS_CONFIG_STATE(idx, CONFIG_PL2303_LINE_CODING))); + cdch_process_set_config, CONFIG_PL2303_LINE_CODING)); } else { - pl2303_vendor_write(p_cdc, 8, 0, - cdch_process_set_config, PROCESS_CONFIG_STATE(idx, CONFIG_PL2303_RESET_ENDP2)); + pl2303_vendor_write(p_cdc, 8, 0, cdch_process_set_config, CONFIG_PL2303_RESET_ENDP2); } } break; @@ -2678,15 +2710,13 @@ static bool pl2303_process_set_config(tuh_xfer_t *xfer) { case CONFIG_PL2303_RESET_ENDP2: // step 2 if (p_cdc->pl2303.serial_private.quirks & PL2303_QUIRK_LEGACY) { - TU_ASSERT(pl2303_clear_halt(p_cdc, PL2303_IN_EP, - cdch_process_set_config, PROCESS_CONFIG_STATE(idx, CONFIG_PL2303_LINE_CODING))); + TU_ASSERT(pl2303_clear_halt(p_cdc, PL2303_IN_EP, cdch_process_set_config, CONFIG_PL2303_LINE_CODING)); } else { /* reset upstream data pipes */ if (p_cdc->pl2303.serial_private.type == &pl2303_type_data[TYPE_HXN]) { // here nothing to do, only structure of previous step overtaken for better reading and comparison } else { - TU_ASSERT(pl2303_vendor_write(p_cdc, 9, 0, - cdch_process_set_config, PROCESS_CONFIG_STATE(idx, CONFIG_PL2303_LINE_CODING))); + TU_ASSERT(pl2303_vendor_write(p_cdc, 9, 0, cdch_process_set_config, CONFIG_PL2303_LINE_CODING)); } } break; @@ -2696,8 +2726,7 @@ static bool pl2303_process_set_config(tuh_xfer_t *xfer) { case CONFIG_PL2303_LINE_CODING: #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM p_cdc->requested_line_coding = (cdc_line_coding_t) CFG_TUH_CDC_LINE_CODING_ON_ENUM; - TU_ASSERT(pl2303_set_line_request(p_cdc, pl2303_internal_control_complete, - PROCESS_CONFIG_STATE(idx, CONFIG_PL2303_MODEM_CONTROL))); + TU_ASSERT(pl2303_set_line_request(p_cdc, pl2303_internal_control_complete, CONFIG_PL2303_MODEM_CONTROL)); break; #else TU_ATTR_FALLTHROUGH; @@ -2706,8 +2735,7 @@ static bool pl2303_process_set_config(tuh_xfer_t *xfer) { case CONFIG_PL2303_MODEM_CONTROL: #ifdef LINE_CONTROL_ON_ENUM p_cdc->requested_line_state.all = LINE_CONTROL_ON_ENUM; - TU_ASSERT(pl2303_set_control_lines(p_cdc, pl2303_internal_control_complete, - PROCESS_CONFIG_STATE(idx, CONFIG_PL2303_COMPLETE))); + TU_ASSERT(pl2303_set_control_lines(p_cdc, pl2303_internal_control_complete, CONFIG_PL2303_COMPLETE)); break; #else TU_ATTR_FALLTHROUGH; @@ -2719,7 +2747,7 @@ static bool pl2303_process_set_config(tuh_xfer_t *xfer) { // if (p_cdc->pl2303.serial_private.type == &pl2303_type_data[TYPE_HXN]) { // TU_LOG_P_CDC ( "1\r\n" ); // TU_ASSERT(pl2303_vendor_read(p_cdc, PL2303_HXN_FLOWCTRL_REG, &buf, - // cdch_process_set_config, PROCESS_CONFIG_STATE(idx, CONFIG_PL2303_FLOW_CTRL_WRITE))); + // cdch_process_set_config, CONFIG_PL2303_FLOW_CTRL_WRITE)); // } else { // TU_LOG_P_CDC ( "2\r\n" ); // TU_ASSERT(pl2303_vendor_read(p_cdc, 0, &buf, cdch_process_set_config, CONFIG_PL2303_FLOW_CTRL_WRITE)); @@ -2733,11 +2761,11 @@ static bool pl2303_process_set_config(tuh_xfer_t *xfer) { // buf &= (uint8_t) ~PL2303_HXN_FLOWCTRL_MASK; // buf |= PL2303_HXN_FLOWCTRL_NONE; // TU_ASSERT(pl2303_vendor_write(p_cdc, PL2303_HXN_FLOWCTRL_REG, buf, - // cdch_process_set_config, PROCESS_CONFIG_STATE(idx, CONFIG_PL2303_COMPLETE))); + // cdch_process_set_config, CONFIG_PL2303_COMPLETE)); // } else { // buf &= (uint8_t) ~PL2303_FLOWCTRL_MASK; // TU_ASSERT(pl2303_vendor_write(p_cdc, 0, buf, - // cdch_process_set_config, PROCESS_CONFIG_STATE(idx, CONFIG_PL2303_COMPLETE))); + // cdch_process_set_config, CONFIG_PL2303_COMPLETE)); // } // break; -- cgit v1.3.1 From 9503883ba7f99523a14082ce68a5f900585747b0 Mon Sep 17 00:00:00 2001 From: hathach Date: Wed, 18 Jun 2025 23:35:44 +0700 Subject: usbh: add new API tuh_descriptor_get_device_local() cdc host: remove the local desc_dev and the get_device descriptor call for ftdi and pl2303 --- src/class/cdc/cdc_host.c | 141 +++++++++++++++-------------------------------- src/common/tusb_types.h | 1 - src/host/usbh.c | 58 ++++++++++++++----- src/host/usbh.h | 3 + 4 files changed, 91 insertions(+), 112 deletions(-) (limited to 'src/class') diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index 3be61e654..d704d82d7 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -123,10 +123,6 @@ typedef struct { static cdch_interface_t cdch_data[CFG_TUH_CDC]; CFG_TUH_MEM_SECTION static cdch_epbuf_t cdch_epbuf[CFG_TUH_CDC]; -#if CFG_TUH_CDC_FTDI || CFG_TUH_CDC_PL2303 - static tusb_desc_device_t desc_dev[CFG_TUH_ENUMERATION_BUFSIZE]; -#endif - //--------------------------------------------------------------------+ // Serial Driver //--------------------------------------------------------------------+ @@ -189,8 +185,6 @@ static bool ch34x_set_modem_ctrl(cdch_interface_t * p_cdc, tuh_xfer_cb_t complet static uint16_t const pl2303_vid_pid_list[][2] = {CFG_TUH_CDC_PL2303_VID_PID_LIST}; static const struct pl2303_type_data pl2303_type_data[TYPE_COUNT] = {PL2303_TYPE_DATA}; -CFG_TUH_MEM_SECTION CFG_TUH_MEM_ALIGN - static bool pl2303_open(uint8_t daddr, tusb_desc_interface_t const * itf_desc, uint16_t max_len); static bool pl2303_process_set_config(tuh_xfer_t *xfer); @@ -331,7 +325,7 @@ TU_ATTR_ALWAYS_INLINE static inline cdch_interface_t * get_itf(uint8_t idx) { } TU_ATTR_ALWAYS_INLINE static inline uint8_t get_idx_by_ptr(cdch_interface_t* p_cdc) { - return p_cdc - cdch_data; + return (uint8_t) (p_cdc - cdch_data); } static inline uint8_t get_idx_by_ep_addr(uint8_t daddr, uint8_t ep_addr) { @@ -434,7 +428,7 @@ bool tuh_cdc_itf_get_info(uint8_t idx, tuh_itf_info_t * info) { info->daddr = p_cdc->daddr; - // re-construct descriptor + // re-construct interface descriptor tusb_desc_interface_t * desc = &info->desc; desc->bLength = sizeof(tusb_desc_interface_t); desc->bDescriptorType = TUSB_DESC_INTERFACE; @@ -975,8 +969,6 @@ bool cdch_set_config(uint8_t daddr, uint8_t itf_num) { // ACM //--------------------------------------------------------------------+ -//------------- Driver API -------------// - // internal control complete to update state such as line state, encoding static void acm_internal_control_complete(tuh_xfer_t *xfer) { uint8_t const itf_num = (uint8_t) tu_le16toh(xfer->setup->wIndex); @@ -1089,7 +1081,6 @@ static bool acm_set_baudrate(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, } //------------- Enumeration -------------// - enum { CONFIG_ACM_SET_CONTROL_LINE_STATE = 0, CONFIG_ACM_SET_LINE_CODING, @@ -1339,8 +1330,7 @@ static bool ftdi_set_modem_ctrl(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_ //------------- Enumeration -------------// enum { - CONFIG_FTDI_GET_DESC = 0, - CONFIG_FTDI_DETERMINE_TYPE, + CONFIG_FTDI_DETERMINE_TYPE = 0, CONFIG_FTDI_WRITE_LATENCY, CONFIG_FTDI_SIO_RESET, CONFIG_FTDI_SET_DATA, @@ -1383,15 +1373,6 @@ static bool ftdi_proccess_set_config(tuh_xfer_t *xfer) { switch (state) { // from here sequence overtaken from Linux Kernel function ftdi_port_probe() - case CONFIG_FTDI_GET_DESC: - // get device descriptor - if (itf_num == 0) { // only necessary for 1st interface. other interface overtake type from interface 0 - TU_ASSERT(tuh_descriptor_get_device(xfer->daddr, &desc_dev, sizeof(tusb_desc_device_t), - cdch_process_set_config, CONFIG_FTDI_DETERMINE_TYPE)); - break; - } - TU_ATTR_FALLTHROUGH; - case CONFIG_FTDI_DETERMINE_TYPE: // determine type if (itf_num == 0) { @@ -1472,7 +1453,9 @@ static bool ftdi_proccess_set_config(tuh_xfer_t *xfer) { //------------- Helper -------------// static bool ftdi_determine_type(cdch_interface_t *p_cdc) { - uint16_t const version = desc_dev->bcdDevice; + tusb_desc_device_t desc_dev; + TU_VERIFY(tuh_descriptor_get_device_local(p_cdc->daddr, &desc_dev)); + uint16_t const version = desc_dev.bcdDevice; uint8_t const itf_num = p_cdc->bInterfaceNumber; p_cdc->ftdi.chip_type = UNKNOWN; @@ -1482,8 +1465,7 @@ static bool ftdi_determine_type(cdch_interface_t *p_cdc) { switch (version) { case 0x200: - // FT232A not supported to keep it simple (no extra _read_latency_timer()) - // not testable + // FT232A not supported to keep it simple (no extra _read_latency_timer()) not testable // p_cdc->ftdi.chip_type = FT232A; // p_cdc->ftdi.baud_base = 48000000 / 2; // p_cdc->ftdi.channel = 0; @@ -1497,50 +1479,20 @@ static bool ftdi_determine_type(cdch_interface_t *p_cdc) { // p_cdc->ftdi.chip_type = FT232B; // } break; - case 0x400: - p_cdc->ftdi.chip_type = FT232B; - p_cdc->ftdi.channel = 0; - break; - case 0x500: - p_cdc->ftdi.chip_type = FT2232C; - break; - case 0x600: - p_cdc->ftdi.chip_type = FT232R; - p_cdc->ftdi.channel = 0; - break; - case 0x700: - p_cdc->ftdi.chip_type = FT2232H; - break; - case 0x800: - p_cdc->ftdi.chip_type = FT4232H; - break; - case 0x900: - p_cdc->ftdi.chip_type = FT232H; - break; - case 0x1000: - p_cdc->ftdi.chip_type = FTX; - break; - case 0x2800: - p_cdc->ftdi.chip_type = FT2233HP; - break; - case 0x2900: - p_cdc->ftdi.chip_type = FT4233HP; - break; - case 0x3000: - p_cdc->ftdi.chip_type = FT2232HP; - break; - case 0x3100: - p_cdc->ftdi.chip_type = FT4232HP; - break; - case 0x3200: - p_cdc->ftdi.chip_type = FT233HP; - break; - case 0x3300: - p_cdc->ftdi.chip_type = FT232HP; - break; - case 0x3600: - p_cdc->ftdi.chip_type = FT4232HA; - break; + case 0x400: p_cdc->ftdi.chip_type = FT232B; p_cdc->ftdi.channel = 0; break; + case 0x500: p_cdc->ftdi.chip_type = FT2232C; break; + case 0x600: p_cdc->ftdi.chip_type = FT232R; p_cdc->ftdi.channel = 0; break; + case 0x700: p_cdc->ftdi.chip_type = FT2232H; break; + case 0x800: p_cdc->ftdi.chip_type = FT4232H; break; + case 0x900: p_cdc->ftdi.chip_type = FT232H; break; + case 0x1000: p_cdc->ftdi.chip_type = FTX; break; + case 0x2800: p_cdc->ftdi.chip_type = FT2233HP; break; + case 0x2900: p_cdc->ftdi.chip_type = FT4233HP; break; + case 0x3000: p_cdc->ftdi.chip_type = FT2232HP; break; + case 0x3100: p_cdc->ftdi.chip_type = FT4232HP; break; + case 0x3200: p_cdc->ftdi.chip_type = FT233HP; break; + case 0x3300: p_cdc->ftdi.chip_type = FT232HP; break; + case 0x3600: p_cdc->ftdi.chip_type = FT4232HA; break; default: if (version < 0x200) { p_cdc->ftdi.chip_type = SIO; @@ -1550,7 +1502,7 @@ static bool ftdi_determine_type(cdch_interface_t *p_cdc) { } TU_LOG_P_CDC("%s detected (bcdDevice = 0x%04x)", - ftdi_chip_name[p_cdc->ftdi.chip_type], desc_dev->bcdDevice); + ftdi_chip_name[p_cdc->ftdi.chip_type], version); return (p_cdc->ftdi.chip_type != UNKNOWN); } @@ -2025,7 +1977,8 @@ static bool ch34x_write_reg_baudrate(cdch_interface_t *p_cdc, tuh_xfer_cb_t comp } static bool ch34x_modem_ctrl_request(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - uint8_t control = ~((p_cdc->requested_line_state.rts ? CH34X_BIT_RTS : 0) |// CH34x signals are inverted + // CH34x signals are inverted + uint8_t control = ~((p_cdc->requested_line_state.rts ? CH34X_BIT_RTS : 0) | (p_cdc->requested_line_state.dtr ? CH34X_BIT_DTR : 0)); return ch34x_control_out(p_cdc, CH34X_REQ_MODEM_CTRL, control, 0, complete_cb, user_data); } @@ -2506,8 +2459,7 @@ static bool pl2303_set_modem_ctrl(cdch_interface_t *p_cdc, tuh_xfer_cb_t complet //------------- Enumeration -------------// enum { - CONFIG_PL2303_GET_DESC = 0, - CONFIG_PL2303_DETECT_TYPE, + CONFIG_PL2303_DETECT_TYPE = 0, CONFIG_PL2303_READ1, CONFIG_PL2303_WRITE1, CONFIG_PL2303_READ2, @@ -2568,14 +2520,8 @@ static bool pl2303_process_set_config(tuh_xfer_t *xfer) { TU_ASSERT(p_cdc && (xfer->result == XFER_RESULT_SUCCESS || xfer->user_data == CONFIG_PL2303_READ1)); switch (state) { // from here sequence overtaken from Linux Kernel function pl2303_startup() - case CONFIG_PL2303_GET_DESC: - p_cdc->user_control_cb = cdch_process_set_config;// set once for whole process config - // get device descriptor - TU_ASSERT(tuh_descriptor_get_device(xfer->daddr, &desc_dev, sizeof(tusb_desc_device_t), - cdch_process_set_config, CONFIG_PL2303_DETECT_TYPE)); - break; - case CONFIG_PL2303_DETECT_TYPE: + p_cdc->user_control_cb = cdch_process_set_config;// set once for whole process config // get type and quirks (step 1) type = pl2303_detect_type(p_cdc, 1, cdch_process_set_config, CONFIG_PL2303_READ1); TU_ASSERT(type != PL2303_DETECT_TYPE_FAILED); @@ -2784,39 +2730,39 @@ static bool pl2303_process_set_config(tuh_xfer_t *xfer) { static int8_t pl2303_detect_type(cdch_interface_t *p_cdc, uint8_t step, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - /* - * Legacy PL2303H, variants 0 and 1 (difference unknown). - */ - if (desc_dev->bDeviceClass == 0x02) { + tusb_desc_device_t desc_dev; + TU_VERIFY(tuh_descriptor_get_device_local(p_cdc->daddr, &desc_dev), PL2303_DETECT_TYPE_FAILED); + + // Legacy PL2303H, variants 0 and 1 (difference unknown). + if (desc_dev.bDeviceClass == 0x02) { return TYPE_H; /* variant 0 */ } - if (desc_dev->bMaxPacketSize0 != 0x40) { - if (desc_dev->bDeviceClass == 0x00 || desc_dev->bDeviceClass == 0xff) { + if (desc_dev.bMaxPacketSize0 != 0x40) { + if (desc_dev.bDeviceClass == 0x00 || desc_dev.bDeviceClass == 0xff) { return TYPE_H; /* variant 1 */ } return TYPE_H; /* variant 0 */ } - switch (desc_dev->bcdUSB) { + switch (desc_dev.bcdUSB) { case 0x101: /* USB 1.0.1? Let's assume they meant 1.1... */ TU_ATTR_FALLTHROUGH; case 0x110: - switch (desc_dev->bcdDevice) { - case 0x300: - return TYPE_HX; - case 0x400: - return TYPE_HXD; - default: - return TYPE_HX; + switch (desc_dev.bcdDevice) { + case 0x300: return TYPE_HX; + case 0x400: return TYPE_HXD; + default: return TYPE_HX; } break; + case 0x200: - switch (desc_dev->bcdDevice) { + switch (desc_dev.bcdDevice) { case 0x100: /* GC */ case 0x105: return TYPE_HXN; + case 0x300: /* GT / TA */ if (step == 1) { // step 1 trigger pl2303_supports_hx_status() request @@ -2833,6 +2779,7 @@ static int8_t pl2303_detect_type(cdch_interface_t *p_cdc, uint8_t step, case 0x400: /* GL */ case 0x405: return TYPE_HXN; + case 0x500: /* GE / TB */ if (step == 1) { // step 1 trigger pl2303_supports_hx_status() request @@ -2851,6 +2798,7 @@ static int8_t pl2303_detect_type(cdch_interface_t *p_cdc, uint8_t step, case 0x700: /* GR */ case 0x705: return TYPE_HXN; + default: break; } @@ -2858,8 +2806,7 @@ static int8_t pl2303_detect_type(cdch_interface_t *p_cdc, uint8_t step, default: break; } - TU_LOG_P_CDC("unknown device type bcdUSB = 0x%04x", desc_dev->bcdUSB); - + TU_LOG_P_CDC("unknown device type bcdUSB = 0x%04x", desc_dev.bcdUSB); return PL2303_DETECT_TYPE_FAILED; } diff --git a/src/common/tusb_types.h b/src/common/tusb_types.h index fd7f01b67..ff5d8b66a 100644 --- a/src/common/tusb_types.h +++ b/src/common/tusb_types.h @@ -345,7 +345,6 @@ typedef struct TU_ATTR_PACKED { uint8_t iManufacturer ; ///< Index of string descriptor describing manufacturer. uint8_t iProduct ; ///< Index of string descriptor describing product. uint8_t iSerialNumber ; ///< Index of string descriptor describing the device's serial number. - uint8_t bNumConfigurations ; ///< Number of possible configurations. } tusb_desc_device_t; diff --git a/src/host/usbh.c b/src/host/usbh.c index f2e5c1f0e..08c362171 100644 --- a/src/host/usbh.c +++ b/src/host/usbh.c @@ -94,26 +94,28 @@ TU_ATTR_WEAK bool hcd_dcache_clean_invalidate(const void* addr, uint32_t data_si typedef struct { tuh_bus_info_t bus_info; - // Device State - struct TU_ATTR_PACKED { - volatile uint8_t connected : 1; // After 1st transfer - volatile uint8_t addressed : 1; // After SET_ADDR - volatile uint8_t configured : 1; // After SET_CONFIG and all drivers are configured - volatile uint8_t suspended : 1; // Bus suspended - // volatile uint8_t removing : 1; // Physically disconnected, waiting to be processed by usbh - }; - // Device Descriptor - uint8_t ep0_size; + uint16_t bcdUSB; + uint8_t bDeviceClass; + uint8_t bDeviceSubClass; + uint8_t bDeviceProtocol; + uint8_t bMaxPacketSize0; uint16_t idVendor; uint16_t idProduct; + uint16_t bcdDevice; uint8_t iManufacturer; uint8_t iProduct; uint8_t iSerialNumber; uint8_t bNumConfigurations; - // Configuration Descriptor - // uint8_t interface_count; // bNumInterfaces alias + // Device State + struct TU_ATTR_PACKED { + volatile uint8_t connected : 1; // After 1st transfer + volatile uint8_t addressed : 1; // After SET_ADDR + volatile uint8_t configured : 1; // After SET_CONFIG and all drivers are configured + volatile uint8_t suspended : 1; // Bus suspended + // volatile uint8_t removing : 1; // Physically disconnected, waiting to be processed by usbh + }; // Endpoint & Interface uint8_t itf2drv[CFG_TUH_INTERFACE_MAX]; // map interface number to driver (0xff is invalid) @@ -373,6 +375,28 @@ bool tuh_vid_pid_get(uint8_t dev_addr, uint16_t *vid, uint16_t *pid) { return true; } +bool tuh_descriptor_get_device_local(uint8_t daddr, tusb_desc_device_t* desc_device) { + usbh_device_t *dev = get_device(daddr); + TU_VERIFY(dev && desc_device); + + desc_device->bLength = sizeof(tusb_desc_device_t); + desc_device->bDescriptorType = TUSB_DESC_DEVICE; + desc_device->bcdUSB = dev->bcdUSB; + desc_device->bDeviceClass = dev->bDeviceClass; + desc_device->bDeviceSubClass = dev->bDeviceSubClass; + desc_device->bDeviceProtocol = dev->bDeviceProtocol; + desc_device->bMaxPacketSize0 = dev->bMaxPacketSize0; + desc_device->idVendor = dev->idVendor; + desc_device->idProduct = dev->idProduct; + desc_device->bcdDevice = dev->bcdDevice; + desc_device->iManufacturer = dev->iManufacturer; + desc_device->iProduct = dev->iProduct; + desc_device->iSerialNumber = dev->iSerialNumber; + desc_device->bNumConfigurations = dev->bNumConfigurations; + + return true; +} + tusb_speed_t tuh_speed_get(uint8_t daddr) { tuh_bus_info_t bus_info; tuh_bus_info_get(daddr, &bus_info); @@ -1579,7 +1603,7 @@ static void process_enumeration(tuh_xfer_t* xfer) { usbh_device_t* new_dev = get_device(new_addr); new_dev->bus_info = *dev0_bus; new_dev->connected = 1; - new_dev->ep0_size = desc_device->bMaxPacketSize0; + new_dev->bMaxPacketSize0 = desc_device->bMaxPacketSize0; TU_ASSERT(tuh_address_set(0, new_addr, process_enumeration, ENUM_GET_DEVICE_DESC),); break; @@ -1596,7 +1620,7 @@ static void process_enumeration(tuh_xfer_t* xfer) { usbh_device_close(dev0_bus->rhport, 0); // close dev0 - TU_ASSERT(usbh_edpt_control_open(new_addr, new_dev->ep0_size),); // open new control endpoint + TU_ASSERT(usbh_edpt_control_open(new_addr, new_dev->bMaxPacketSize0),); // open new control endpoint TU_LOG_USBH("Get Device Descriptor\r\n"); TU_ASSERT(tuh_descriptor_get_device(new_addr, _usbh_epbuf.ctrl, sizeof(tusb_desc_device_t), @@ -1609,8 +1633,14 @@ static void process_enumeration(tuh_xfer_t* xfer) { case ENUM_GET_STRING_LANGUAGE_ID_LEN: { // save the received device descriptor tusb_desc_device_t const *desc_device = (tusb_desc_device_t const *) _usbh_epbuf.ctrl; + dev->bcdUSB = desc_device->bcdUSB; + dev->bDeviceClass = desc_device->bDeviceClass; + dev->bDeviceSubClass = desc_device->bDeviceSubClass; + dev->bDeviceProtocol = desc_device->bDeviceProtocol; + dev->bMaxPacketSize0 = desc_device->bMaxPacketSize0; dev->idVendor = desc_device->idVendor; dev->idProduct = desc_device->idProduct; + dev->bcdDevice = desc_device->bcdDevice; dev->iManufacturer = desc_device->iManufacturer; dev->iProduct = desc_device->iProduct; dev->iSerialNumber = desc_device->iSerialNumber; diff --git a/src/host/usbh.h b/src/host/usbh.h index 13eede869..1ee511722 100644 --- a/src/host/usbh.h +++ b/src/host/usbh.h @@ -204,6 +204,9 @@ bool tuh_rhport_reset_bus(uint8_t rhport, bool active); // Get VID/PID of device bool tuh_vid_pid_get(uint8_t daddr, uint16_t* vid, uint16_t* pid); +// Get local (cached) device descriptor once device is enumerated +bool tuh_descriptor_get_device_local(uint8_t daddr, tusb_desc_device_t* desc_device); + // Get speed of device tusb_speed_t tuh_speed_get(uint8_t daddr); -- cgit v1.3.1 From 2adb305ea71f69b38c6c01cc054d8e323dd25e0e Mon Sep 17 00:00:00 2001 From: hathach Date: Thu, 19 Jun 2025 15:30:02 +0700 Subject: house keeping --- src/class/cdc/cdc_host.c | 183 ++++++++++++++++++++-------------------- src/class/cdc/serial/ftdi_sio.h | 74 ++++++++-------- src/class/cdc/serial/pl2303.h | 42 ++++----- 3 files changed, 151 insertions(+), 148 deletions(-) (limited to 'src/class') diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index d704d82d7..ce98e3b3d 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -111,13 +111,13 @@ typedef struct { tu_edpt_stream_t rx; uint8_t tx_ff_buf[CFG_TUH_CDC_TX_BUFSIZE]; - uint8_t rx_ff_buf[CFG_TUH_CDC_TX_BUFSIZE]; + uint8_t rx_ff_buf[CFG_TUH_CDC_RX_BUFSIZE]; } stream; } cdch_interface_t; typedef struct { TUH_EPBUF_DEF(tx, CFG_TUH_CDC_TX_EPSIZE); - TUH_EPBUF_DEF(rx, CFG_TUH_CDC_TX_EPSIZE); + TUH_EPBUF_DEF(rx, CFG_TUH_CDC_RX_EPSIZE); } cdch_epbuf_t; static cdch_interface_t cdch_data[CFG_TUH_CDC]; @@ -141,10 +141,6 @@ static bool acm_set_control_line_state(cdch_interface_t * p_cdc, tuh_xfer_cb_t c //------------- FTDI prototypes -------------// #if CFG_TUH_CDC_FTDI static uint16_t const ftdi_vid_pid_list[][2] = {CFG_TUH_CDC_FTDI_VID_PID_LIST}; -#if CFG_TUSB_DEBUG && CFG_TUSB_DEBUG >= CFG_TUH_CDC_LOG_LEVEL - static uint8_t const * ftdi_chip_name[] = { FTDI_CHIP_NAMES }; -#endif - static bool ftdi_open(uint8_t daddr, const tusb_desc_interface_t * itf_desc, uint16_t max_len); static bool ftdi_proccess_set_config(tuh_xfer_t * xfer); @@ -183,7 +179,7 @@ static bool ch34x_set_modem_ctrl(cdch_interface_t * p_cdc, tuh_xfer_cb_t complet //------------- PL2303 prototypes -------------// #if CFG_TUH_CDC_PL2303 static uint16_t const pl2303_vid_pid_list[][2] = {CFG_TUH_CDC_PL2303_VID_PID_LIST}; -static const struct pl2303_type_data pl2303_type_data[TYPE_COUNT] = {PL2303_TYPE_DATA}; +static const pl2303_type_data_t pl2303_type_data[PL2303_TYPE_COUNT] = {PL2303_TYPE_DATA}; static bool pl2303_open(uint8_t daddr, tusb_desc_interface_t const * itf_desc, uint16_t max_len); static bool pl2303_process_set_config(tuh_xfer_t *xfer); @@ -1209,7 +1205,7 @@ static bool ftdi_set_request(cdch_interface_t *p_cdc, uint8_t request, uint8_t r #ifdef CFG_TUH_CDC_FTDI_LATENCY static int8_t ftdi_write_latency_timer(cdch_interface_t * p_cdc, uint16_t latency, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - if (p_cdc->ftdi.chip_type == SIO /* || p_cdc->ftdi.chip_type == FT232A */ ) + if (p_cdc->ftdi.chip_type == FTDI_SIO /* || p_cdc->ftdi.chip_type == FT232A */ ) return FTDI_NOT_POSSIBLE; return ftdi_set_request(p_cdc, FTDI_SIO_SET_LATENCY_TIMER_REQUEST, FTDI_SIO_SET_LATENCY_TIMER_REQUEST_TYPE, latency, p_cdc->ftdi.channel, complete_cb, user_data) ? FTDI_REQUESTED : FTDI_FAIL; @@ -1458,7 +1454,7 @@ static bool ftdi_determine_type(cdch_interface_t *p_cdc) { uint16_t const version = desc_dev.bcdDevice; uint8_t const itf_num = p_cdc->bInterfaceNumber; - p_cdc->ftdi.chip_type = UNKNOWN; + p_cdc->ftdi.chip_type = FTDI_UNKNOWN; /* Assume Hi-Speed type */ p_cdc->ftdi.channel = CHANNEL_A + itf_num; @@ -1476,35 +1472,40 @@ static bool ftdi_determine_type(cdch_interface_t *p_cdc) { // */ // if (desc->iSerialNumber == 0 && // _read_latency_timer(port) >= 0) { - // p_cdc->ftdi.chip_type = FT232B; + // p_cdc->ftdi.chip_type = FTDI_FT232B; // } break; - case 0x400: p_cdc->ftdi.chip_type = FT232B; p_cdc->ftdi.channel = 0; break; - case 0x500: p_cdc->ftdi.chip_type = FT2232C; break; - case 0x600: p_cdc->ftdi.chip_type = FT232R; p_cdc->ftdi.channel = 0; break; - case 0x700: p_cdc->ftdi.chip_type = FT2232H; break; - case 0x800: p_cdc->ftdi.chip_type = FT4232H; break; - case 0x900: p_cdc->ftdi.chip_type = FT232H; break; - case 0x1000: p_cdc->ftdi.chip_type = FTX; break; - case 0x2800: p_cdc->ftdi.chip_type = FT2233HP; break; - case 0x2900: p_cdc->ftdi.chip_type = FT4233HP; break; - case 0x3000: p_cdc->ftdi.chip_type = FT2232HP; break; - case 0x3100: p_cdc->ftdi.chip_type = FT4232HP; break; - case 0x3200: p_cdc->ftdi.chip_type = FT233HP; break; - case 0x3300: p_cdc->ftdi.chip_type = FT232HP; break; - case 0x3600: p_cdc->ftdi.chip_type = FT4232HA; break; + + case 0x400 : p_cdc->ftdi.chip_type = FTDI_FT232B; p_cdc->ftdi.channel = 0; break; + case 0x500 : p_cdc->ftdi.chip_type = FTDI_FT2232C; break; + case 0x600 : p_cdc->ftdi.chip_type = FTDI_FT232R; p_cdc->ftdi.channel = 0; break; + case 0x700 : p_cdc->ftdi.chip_type = FTDI_FT2232H; break; + case 0x800 : p_cdc->ftdi.chip_type = FTDI_FT4232H; break; + case 0x900 : p_cdc->ftdi.chip_type = FTDI_FT232H; break; + case 0x1000: p_cdc->ftdi.chip_type = FTDI_FTX; break; + case 0x2800: p_cdc->ftdi.chip_type = FTDI_FT2233HP; break; + case 0x2900: p_cdc->ftdi.chip_type = FTDI_FT4233HP; break; + case 0x3000: p_cdc->ftdi.chip_type = FTDI_FT2232HP; break; + case 0x3100: p_cdc->ftdi.chip_type = FTDI_FT4232HP; break; + case 0x3200: p_cdc->ftdi.chip_type = FTDI_FT233HP; break; + case 0x3300: p_cdc->ftdi.chip_type = FTDI_FT232HP; break; + case 0x3600: p_cdc->ftdi.chip_type = FTDI_FT4232HA; break; + default: if (version < 0x200) { - p_cdc->ftdi.chip_type = SIO; + p_cdc->ftdi.chip_type = FTDI_SIO; p_cdc->ftdi.channel = 0; } break; } + #if CFG_TUSB_DEBUG >= CFG_TUH_CDC_LOG_LEVEL + const char * ftdi_chip_name[] = { FTDI_CHIP_NAMES }; TU_LOG_P_CDC("%s detected (bcdDevice = 0x%04x)", ftdi_chip_name[p_cdc->ftdi.chip_type], version); + #endif - return (p_cdc->ftdi.chip_type != UNKNOWN); + return (p_cdc->ftdi.chip_type != FTDI_UNKNOWN); } // FT232A not supported @@ -1589,9 +1590,9 @@ static inline uint32_t ftdi_get_divisor(cdch_interface_t *p_cdc) { TU_VERIFY(baud); switch (p_cdc->ftdi.chip_type) { - case UNKNOWN: + case FTDI_UNKNOWN: return 0; - case SIO: + case FTDI_SIO: switch (baud) { case 300: div_value = ftdi_sio_b300; break; case 600: div_value = ftdi_sio_b600; break; @@ -1620,23 +1621,23 @@ static inline uint32_t ftdi_get_divisor(cdch_interface_t *p_cdc) { // div_okay = false; // } // break; - case FT232B: - case FT2232C: - case FT232R: - case FTX: + case FTDI_FT232B: + case FTDI_FT2232C: + case FTDI_FT232R: + case FTDI_FTX: TU_VERIFY(baud <= 3000000); // else Baud rate too high! div_value = ftdi_232bm_baud_to_divisor(baud); break; - case FT232H: - case FT2232H: - case FT4232H: - case FT4232HA: - case FT232HP: - case FT233HP: - case FT2232HP: - case FT2233HP: - case FT4232HP: - case FT4233HP: + case FTDI_FT232H: + case FTDI_FT2232H: + case FTDI_FT4232H: + case FTDI_FT4232HA: + case FTDI_FT232HP: + case FTDI_FT233HP: + case FTDI_FT2232HP: + case FTDI_FT2233HP: + case FTDI_FT4232HP: + case FTDI_FT4233HP: default: TU_VERIFY(baud <= 12000000); // else Baud rate too high! if (baud >= 1200) { @@ -2273,8 +2274,7 @@ static uint8_t ch34x_get_lcr(cdch_interface_t *p_cdc) { //--------------------------------------------------------------------+ #if CFG_TUH_CDC_PL2303 -static int8_t pl2303_detect_type(cdch_interface_t *p_cdc, uint8_t step, - tuh_xfer_cb_t complete_cb, uintptr_t user_data); +static int8_t pl2303_detect_type(cdch_interface_t *p_cdc, uint8_t step); static bool pl2303_encode_baud_rate(cdch_interface_t *p_cdc, uint8_t buf[PL2303_LINE_CODING_BAUDRATE_BUFSIZE]); //------------- Control Request -------------// @@ -2313,14 +2313,13 @@ static bool pl2303_set_request(cdch_interface_t *p_cdc, uint8_t request, uint8_t static bool pl2303_vendor_read(cdch_interface_t *p_cdc, uint16_t value, uint8_t *buf, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - uint8_t request = p_cdc->pl2303.serial_private.type == &pl2303_type_data[TYPE_HXN] ? PL2303_VENDOR_READ_NREQUEST : PL2303_VENDOR_READ_REQUEST; - + uint8_t request = p_cdc->pl2303.serial_private.type == &pl2303_type_data[PL2303_TYPE_HXN] ? PL2303_VENDOR_READ_NREQUEST : PL2303_VENDOR_READ_REQUEST; return pl2303_set_request(p_cdc, request, PL2303_VENDOR_READ_REQUEST_TYPE, value, 0, buf, 1, complete_cb, user_data); } static bool pl2303_vendor_write(cdch_interface_t *p_cdc, uint16_t value, uint16_t index, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - uint8_t request = p_cdc->pl2303.serial_private.type == &pl2303_type_data[TYPE_HXN] ? PL2303_VENDOR_WRITE_NREQUEST : PL2303_VENDOR_WRITE_REQUEST; + uint8_t request = p_cdc->pl2303.serial_private.type == &pl2303_type_data[PL2303_TYPE_HXN] ? PL2303_VENDOR_WRITE_NREQUEST : PL2303_VENDOR_WRITE_REQUEST; return pl2303_set_request(p_cdc, request, PL2303_VENDOR_WRITE_REQUEST_TYPE, value, index, NULL, 0, complete_cb, user_data); } @@ -2517,25 +2516,30 @@ static bool pl2303_process_set_config(tuh_xfer_t *xfer) { uint8_t buf = 0; int8_t type; - TU_ASSERT(p_cdc && (xfer->result == XFER_RESULT_SUCCESS || xfer->user_data == CONFIG_PL2303_READ1)); + TU_ASSERT(p_cdc && (xfer->result == XFER_RESULT_SUCCESS || state == CONFIG_PL2303_READ1)); switch (state) { // from here sequence overtaken from Linux Kernel function pl2303_startup() case CONFIG_PL2303_DETECT_TYPE: p_cdc->user_control_cb = cdch_process_set_config;// set once for whole process config // get type and quirks (step 1) - type = pl2303_detect_type(p_cdc, 1, cdch_process_set_config, CONFIG_PL2303_READ1); - TU_ASSERT(type != PL2303_DETECT_TYPE_FAILED); - if (type == PL2303_SUPPORTS_HX_STATUS_TRIGGERED) { + type = pl2303_detect_type(p_cdc, 1); + TU_ASSERT(type != PL2303_TYPE_UNKNOWN); + if (type == PL2303_TYPE_NEED_SUPPORTS_HX_STATUS) { + TU_ASSERT(pl2303_supports_hx_status(p_cdc, cdch_process_set_config, CONFIG_PL2303_READ1)); break; - }// else: no transfer triggered and continue with CONFIG_PL2303_READ1 - TU_ATTR_FALLTHROUGH; + } else { + // no transfer triggered and continue with CONFIG_PL2303_READ1 + TU_ATTR_FALLTHROUGH; + } case CONFIG_PL2303_READ1: // get supports_hx_status, type and quirks (step 2), do special read - p_cdc->pl2303.supports_hx_status = (// will not be true, if coming directly from previous case - xfer->user_data == CONFIG_PL2303_READ1 && xfer->result == XFER_RESULT_SUCCESS); - type = pl2303_detect_type(p_cdc, 2, NULL, 0); // step 2 now with supports_hx_status - TU_ASSERT(type != PL2303_DETECT_TYPE_FAILED); + // will not be true, if coming directly from previous case + if (xfer->user_data == CONFIG_PL2303_READ1 && xfer->result == XFER_RESULT_SUCCESS) { + p_cdc->pl2303.supports_hx_status = true; + } + type = pl2303_detect_type(p_cdc, 2); // step 2 now with supports_hx_status + TU_ASSERT(type != PL2303_TYPE_UNKNOWN); p_cdc->pl2303.serial_private.type = &pl2303_type_data[type]; p_cdc->pl2303.serial_private.quirks |= p_cdc->pl2303.serial_private.type->quirks; #if CFG_TUSB_DEBUG >= CFG_TUH_CDC_LOG_LEVEL && 0// can be activated if necessary @@ -2549,7 +2553,7 @@ static bool pl2303_process_set_config(tuh_xfer_t *xfer) { p_cdc->pl2303.serial_private.type->name, p_cdc->pl2303.serial_private.quirks); #endif // purpose unknown, overtaken from Linux Kernel driver - if (p_cdc->pl2303.serial_private.type != &pl2303_type_data[TYPE_HXN]) { + if (p_cdc->pl2303.serial_private.type != &pl2303_type_data[PL2303_TYPE_HXN]) { TU_ASSERT(pl2303_vendor_read(p_cdc, 0x8484, &buf, cdch_process_set_config, CONFIG_PL2303_WRITE1)); break; }// else: continue with next step @@ -2557,7 +2561,7 @@ static bool pl2303_process_set_config(tuh_xfer_t *xfer) { case CONFIG_PL2303_WRITE1: // purpose unknown, overtaken from Linux Kernel driver - if (p_cdc->pl2303.serial_private.type != &pl2303_type_data[TYPE_HXN]) { + if (p_cdc->pl2303.serial_private.type != &pl2303_type_data[PL2303_TYPE_HXN]) { TU_ASSERT(pl2303_vendor_write(p_cdc, 0x0404, 0, cdch_process_set_config, CONFIG_PL2303_READ2)); break; }// else: continue with next step @@ -2565,7 +2569,7 @@ static bool pl2303_process_set_config(tuh_xfer_t *xfer) { case CONFIG_PL2303_READ2: // purpose unknown, overtaken from Linux Kernel driver - if (p_cdc->pl2303.serial_private.type != &pl2303_type_data[TYPE_HXN]) { + if (p_cdc->pl2303.serial_private.type != &pl2303_type_data[PL2303_TYPE_HXN]) { TU_ASSERT(pl2303_vendor_read(p_cdc, 0x8484, &buf, cdch_process_set_config, CONFIG_PL2303_READ3)); break; }// else: continue with next step @@ -2573,7 +2577,7 @@ static bool pl2303_process_set_config(tuh_xfer_t *xfer) { case CONFIG_PL2303_READ3: // purpose unknown, overtaken from Linux Kernel driver - if (p_cdc->pl2303.serial_private.type != &pl2303_type_data[TYPE_HXN]) { + if (p_cdc->pl2303.serial_private.type != &pl2303_type_data[PL2303_TYPE_HXN]) { TU_ASSERT(pl2303_vendor_read(p_cdc, 0x8383, &buf, cdch_process_set_config, CONFIG_PL2303_READ4)); break; }// else: continue with next step @@ -2581,7 +2585,7 @@ static bool pl2303_process_set_config(tuh_xfer_t *xfer) { case CONFIG_PL2303_READ4: // purpose unknown, overtaken from Linux Kernel driver - if (p_cdc->pl2303.serial_private.type != &pl2303_type_data[TYPE_HXN]) { + if (p_cdc->pl2303.serial_private.type != &pl2303_type_data[PL2303_TYPE_HXN]) { TU_ASSERT(pl2303_vendor_read(p_cdc, 0x8484, &buf, cdch_process_set_config, CONFIG_PL2303_WRITE2)); break; }// else: continue with next step @@ -2589,7 +2593,7 @@ static bool pl2303_process_set_config(tuh_xfer_t *xfer) { case CONFIG_PL2303_WRITE2: // purpose unknown, overtaken from Linux Kernel driver - if (p_cdc->pl2303.serial_private.type != &pl2303_type_data[TYPE_HXN]) { + if (p_cdc->pl2303.serial_private.type != &pl2303_type_data[PL2303_TYPE_HXN]) { TU_ASSERT(pl2303_vendor_write(p_cdc, 0x0404, 1, cdch_process_set_config, CONFIG_PL2303_READ5)); break; }// else: continue with next step @@ -2597,7 +2601,7 @@ static bool pl2303_process_set_config(tuh_xfer_t *xfer) { case CONFIG_PL2303_READ5: // purpose unknown, overtaken from Linux Kernel driver - if (p_cdc->pl2303.serial_private.type != &pl2303_type_data[TYPE_HXN]) { + if (p_cdc->pl2303.serial_private.type != &pl2303_type_data[PL2303_TYPE_HXN]) { TU_ASSERT(pl2303_vendor_read(p_cdc, 0x8484, &buf, cdch_process_set_config, CONFIG_PL2303_READ6)); break; }// else: continue with next step @@ -2605,7 +2609,7 @@ static bool pl2303_process_set_config(tuh_xfer_t *xfer) { case CONFIG_PL2303_READ6: // purpose unknown, overtaken from Linux Kernel driver - if (p_cdc->pl2303.serial_private.type != &pl2303_type_data[TYPE_HXN]) { + if (p_cdc->pl2303.serial_private.type != &pl2303_type_data[PL2303_TYPE_HXN]) { TU_ASSERT(pl2303_vendor_read(p_cdc, 0x8383, &buf, cdch_process_set_config, CONFIG_PL2303_WRITE3)); break; }// else: continue with next step @@ -2613,7 +2617,7 @@ static bool pl2303_process_set_config(tuh_xfer_t *xfer) { case CONFIG_PL2303_WRITE3: // purpose unknown, overtaken from Linux Kernel driver - if (p_cdc->pl2303.serial_private.type != &pl2303_type_data[TYPE_HXN]) { + if (p_cdc->pl2303.serial_private.type != &pl2303_type_data[PL2303_TYPE_HXN]) { TU_ASSERT(pl2303_vendor_write(p_cdc, 0, 1, cdch_process_set_config, CONFIG_PL2303_WRITE4)); break; }// else: continue with next step @@ -2621,7 +2625,7 @@ static bool pl2303_process_set_config(tuh_xfer_t *xfer) { case CONFIG_PL2303_WRITE4: // purpose unknown, overtaken from Linux Kernel driver - if (p_cdc->pl2303.serial_private.type != &pl2303_type_data[TYPE_HXN]) { + if (p_cdc->pl2303.serial_private.type != &pl2303_type_data[PL2303_TYPE_HXN]) { TU_ASSERT(pl2303_vendor_write(p_cdc, 1, 0, cdch_process_set_config, CONFIG_PL2303_WRITE5)); break; }// else: continue with next step @@ -2629,7 +2633,7 @@ static bool pl2303_process_set_config(tuh_xfer_t *xfer) { case CONFIG_PL2303_WRITE5: // purpose unknown, overtaken from Linux Kernel driver - if (p_cdc->pl2303.serial_private.type != &pl2303_type_data[TYPE_HXN]) { + if (p_cdc->pl2303.serial_private.type != &pl2303_type_data[PL2303_TYPE_HXN]) { uint16_t const windex = (p_cdc->pl2303.serial_private.quirks & PL2303_QUIRK_LEGACY) ? 0x24 : 0x44; TU_ASSERT(pl2303_vendor_write(p_cdc, 2, windex, cdch_process_set_config, CONFIG_PL2303_RESET_ENDP1)); break; @@ -2643,7 +2647,7 @@ static bool pl2303_process_set_config(tuh_xfer_t *xfer) { TU_ASSERT(pl2303_clear_halt(p_cdc, PL2303_OUT_EP, cdch_process_set_config, CONFIG_PL2303_RESET_ENDP2)); } else { /* reset upstream data pipes */ - if (p_cdc->pl2303.serial_private.type == &pl2303_type_data[TYPE_HXN]) { + if (p_cdc->pl2303.serial_private.type == &pl2303_type_data[PL2303_TYPE_HXN]) { TU_ASSERT(pl2303_vendor_write(p_cdc, PL2303_HXN_RESET_REG,// skip CONFIG_PL2303_RESET_ENDP2, no 2nd step PL2303_HXN_RESET_UPSTREAM_PIPE | PL2303_HXN_RESET_DOWNSTREAM_PIPE, cdch_process_set_config, CONFIG_PL2303_LINE_CODING)); @@ -2659,7 +2663,7 @@ static bool pl2303_process_set_config(tuh_xfer_t *xfer) { TU_ASSERT(pl2303_clear_halt(p_cdc, PL2303_IN_EP, cdch_process_set_config, CONFIG_PL2303_LINE_CODING)); } else { /* reset upstream data pipes */ - if (p_cdc->pl2303.serial_private.type == &pl2303_type_data[TYPE_HXN]) { + if (p_cdc->pl2303.serial_private.type == &pl2303_type_data[PL2303_TYPE_HXN]) { // here nothing to do, only structure of previous step overtaken for better reading and comparison } else { TU_ASSERT(pl2303_vendor_write(p_cdc, 9, 0, cdch_process_set_config, CONFIG_PL2303_LINE_CODING)); @@ -2690,7 +2694,7 @@ static bool pl2303_process_set_config(tuh_xfer_t *xfer) { // skipped, because it's not working with each PL230x. flow control can be also set by PL2303 EEPROM Writer Program // case CONFIG_PL2303_FLOW_CTRL_READ: // // read flow control register for modify & write back in next step - // if (p_cdc->pl2303.serial_private.type == &pl2303_type_data[TYPE_HXN]) { + // if (p_cdc->pl2303.serial_private.type == &pl2303_type_data[PL2303_TYPE_HXN]) { // TU_LOG_P_CDC ( "1\r\n" ); // TU_ASSERT(pl2303_vendor_read(p_cdc, PL2303_HXN_FLOWCTRL_REG, &buf, // cdch_process_set_config, CONFIG_PL2303_FLOW_CTRL_WRITE)); @@ -2703,7 +2707,7 @@ static bool pl2303_process_set_config(tuh_xfer_t *xfer) { // case CONFIG_PL2303_FLOW_CTRL_WRITE: // // no flow control // buf = xfer->buffer[0]; - // if (p_cdc->pl2303.serial_private.type == &pl2303_type_data[TYPE_HXN]) { + // if (p_cdc->pl2303.serial_private.type == &pl2303_type_data[PL2303_TYPE_HXN]) { // buf &= (uint8_t) ~PL2303_HXN_FLOWCTRL_MASK; // buf |= PL2303_HXN_FLOWCTRL_NONE; // TU_ASSERT(pl2303_vendor_write(p_cdc, PL2303_HXN_FLOWCTRL_REG, buf, @@ -2728,21 +2732,20 @@ static bool pl2303_process_set_config(tuh_xfer_t *xfer) { //------------- Helper -------------// -static int8_t pl2303_detect_type(cdch_interface_t *p_cdc, uint8_t step, - tuh_xfer_cb_t complete_cb, uintptr_t user_data) { +static int8_t pl2303_detect_type(cdch_interface_t *p_cdc, uint8_t step) { tusb_desc_device_t desc_dev; - TU_VERIFY(tuh_descriptor_get_device_local(p_cdc->daddr, &desc_dev), PL2303_DETECT_TYPE_FAILED); + TU_VERIFY(tuh_descriptor_get_device_local(p_cdc->daddr, &desc_dev), PL2303_TYPE_UNKNOWN); // Legacy PL2303H, variants 0 and 1 (difference unknown). if (desc_dev.bDeviceClass == 0x02) { - return TYPE_H; /* variant 0 */ + return PL2303_TYPE_H; /* variant 0 */ } if (desc_dev.bMaxPacketSize0 != 0x40) { if (desc_dev.bDeviceClass == 0x00 || desc_dev.bDeviceClass == 0xff) { - return TYPE_H; /* variant 1 */ + return PL2303_TYPE_H; /* variant 1 */ } - return TYPE_H; /* variant 0 */ + return PL2303_TYPE_H; /* variant 0 */ } switch (desc_dev.bcdUSB) { @@ -2751,9 +2754,9 @@ static int8_t pl2303_detect_type(cdch_interface_t *p_cdc, uint8_t step, TU_ATTR_FALLTHROUGH; case 0x110: switch (desc_dev.bcdDevice) { - case 0x300: return TYPE_HX; - case 0x400: return TYPE_HXD; - default: return TYPE_HX; + case 0x300: return PL2303_TYPE_HX; + case 0x400: return PL2303_TYPE_HXD; + default: return PL2303_TYPE_HX; } break; @@ -2761,34 +2764,32 @@ static int8_t pl2303_detect_type(cdch_interface_t *p_cdc, uint8_t step, switch (desc_dev.bcdDevice) { case 0x100: /* GC */ case 0x105: - return TYPE_HXN; + return PL2303_TYPE_HXN; case 0x300: /* GT / TA */ if (step == 1) { // step 1 trigger pl2303_supports_hx_status() request - TU_ASSERT(pl2303_supports_hx_status(p_cdc, complete_cb, user_data), PL2303_DETECT_TYPE_FAILED); - return PL2303_SUPPORTS_HX_STATUS_TRIGGERED; + return PL2303_TYPE_NEED_SUPPORTS_HX_STATUS; } else { // step 2 use supports_hx_status if (p_cdc->pl2303.supports_hx_status) { - return TYPE_TA; + return PL2303_TYPE_TA; } } TU_ATTR_FALLTHROUGH; case 0x305: case 0x400: /* GL */ case 0x405: - return TYPE_HXN; + return PL2303_TYPE_HXN; case 0x500: /* GE / TB */ if (step == 1) { // step 1 trigger pl2303_supports_hx_status() request - TU_ASSERT(pl2303_supports_hx_status(p_cdc, complete_cb, user_data), PL2303_DETECT_TYPE_FAILED); - return PL2303_SUPPORTS_HX_STATUS_TRIGGERED; + return PL2303_TYPE_NEED_SUPPORTS_HX_STATUS; } else { // step 2 use supports_hx_status if (p_cdc->pl2303.supports_hx_status) { - return TYPE_TB; + return PL2303_TYPE_TB; } } TU_ATTR_FALLTHROUGH; @@ -2797,7 +2798,7 @@ static int8_t pl2303_detect_type(cdch_interface_t *p_cdc, uint8_t step, case 0x605: case 0x700: /* GR */ case 0x705: - return TYPE_HXN; + return PL2303_TYPE_HXN; default: break; @@ -2807,7 +2808,7 @@ static int8_t pl2303_detect_type(cdch_interface_t *p_cdc, uint8_t step, } TU_LOG_P_CDC("unknown device type bcdUSB = 0x%04x", desc_dev.bcdUSB); - return PL2303_DETECT_TYPE_FAILED; + return PL2303_TYPE_UNKNOWN; } /* diff --git a/src/class/cdc/serial/ftdi_sio.h b/src/class/cdc/serial/ftdi_sio.h index f621b3912..8abf74f11 100644 --- a/src/class/cdc/serial/ftdi_sio.h +++ b/src/class/cdc/serial/ftdi_sio.h @@ -165,48 +165,48 @@ enum ftdi_sio_baudrate { #define FTDI_RS_FIFO (1 << 7) // chip types and names -enum ftdi_chip_type { - SIO = 0, -// FT232A, - FT232B, - FT2232C, - FT232R, - FT232H, - FT2232H, - FT4232H, - FT4232HA, - FT232HP, - FT233HP, - FT2232HP, - FT2233HP, - FT4232HP, - FT4233HP, - FTX, - UNKNOWN -}; +typedef enum ftdi_chip_type { + FTDI_SIO = 0, +// FTDI_FT232A, + FTDI_FT232B, + FTDI_FT2232C, + FTDI_FT232R, + FTDI_FT232H, + FTDI_FT2232H, + FTDI_FT4232H, + FTDI_FT4232HA, + FTDI_FT232HP, + FTDI_FT233HP, + FTDI_FT2232HP, + FTDI_FT2233HP, + FTDI_FT4232HP, + FTDI_FT4233HP, + FTDI_FTX, + FTDI_UNKNOWN +} ftdi_chip_type_t; #define FTDI_CHIP_NAMES \ - [SIO] = (uint8_t const*) "SIO", /* the serial part of FT8U100AX */ \ -/* [FT232A] = (uint8_t const*) "FT232A", */ \ - [FT232B] = (uint8_t const*) "FT232B", \ - [FT2232C] = (uint8_t const*) "FT2232C/D", \ - [FT232R] = (uint8_t const*) "FT232R", \ - [FT232H] = (uint8_t const*) "FT232H", \ - [FT2232H] = (uint8_t const*) "FT2232H", \ - [FT4232H] = (uint8_t const*) "FT4232H", \ - [FT4232HA] = (uint8_t const*) "FT4232HA", \ - [FT232HP] = (uint8_t const*) "FT232HP", \ - [FT233HP] = (uint8_t const*) "FT233HP", \ - [FT2232HP] = (uint8_t const*) "FT2232HP", \ - [FT2233HP] = (uint8_t const*) "FT2233HP", \ - [FT4232HP] = (uint8_t const*) "FT4232HP", \ - [FT4233HP] = (uint8_t const*) "FT4233HP", \ - [FTX] = (uint8_t const*) "FT-X", \ - [UNKNOWN] = (uint8_t const*) "UNKNOWN" + [FTDI_SIO] = "SIO", /* the serial part of FT8U100AX */ \ +/* [FTDI_FT232A] = "FT232A", */ \ + [FTDI_FT232B] = "FT232B", \ + [FTDI_FT2232C] = "FT2232C/D", \ + [FTDI_FT232R] = "FT232R", \ + [FTDI_FT232H] = "FT232H", \ + [FTDI_FT2232H] = "FTDI_FT2232H", \ + [FTDI_FT4232H] = "FT4232H", \ + [FTDI_FT4232HA] = "FT4232HA", \ + [FTDI_FT232HP] = "FT232HP", \ + [FTDI_FT233HP] = "FT233HP", \ + [FTDI_FT2232HP] = "FT2232HP", \ + [FTDI_FT2233HP] = "FT2233HP", \ + [FTDI_FT4232HP] = "FT4232HP", \ + [FTDI_FT4233HP] = "FT4233HP", \ + [FTDI_FTX] = "FT-X", \ + [FTDI_UNKNOWN] = "UNKNOWN" // private interface data typedef struct ftdi_private { - enum ftdi_chip_type chip_type; + ftdi_chip_type_t chip_type; uint8_t channel; // channel index, or 0 for legacy types } ftdi_private_t; diff --git a/src/class/cdc/serial/pl2303.h b/src/class/cdc/serial/pl2303.h index d69bdbfae..40311260d 100644 --- a/src/class/cdc/serial/pl2303.h +++ b/src/class/cdc/serial/pl2303.h @@ -96,51 +96,53 @@ #define PL2303_HXN_FLOWCTRL_XON_XOFF 0x0c // type data -enum pl2303_type { - TYPE_H, - TYPE_HX, - TYPE_TA, - TYPE_TB, - TYPE_HXD, - TYPE_HXN, - TYPE_COUNT -}; - -struct pl2303_type_data { +typedef enum pl2303_type { + PL2303_TYPE_H, + PL2303_TYPE_HX, + PL2303_TYPE_TA, + PL2303_TYPE_TB, + PL2303_TYPE_HXD, + PL2303_TYPE_HXN, + // PL2303_TYPE_NEED_SUPPORTS_HX_STATUS, + // PL2303_TYPE_UNKNOWN, + PL2303_TYPE_COUNT +} pl2303_type_t; + +typedef struct pl2303_type_data { uint8_t const *name; uint32_t const max_baud_rate; uint8_t const quirks; uint16_t const no_autoxonxoff:1; uint16_t const no_divisors:1; uint16_t const alt_divisors:1; -}; +} pl2303_type_data_t; #define PL2303_TYPE_DATA \ - [TYPE_H] = { \ + [PL2303_TYPE_H] = { \ .name = (uint8_t const*)"H", \ .max_baud_rate = 1228800, \ .quirks = PL2303_QUIRK_LEGACY, \ .no_autoxonxoff = true, \ }, \ - [TYPE_HX] = { \ + [PL2303_TYPE_HX] = { \ .name = (uint8_t const*)"HX", \ .max_baud_rate = 6000000, \ }, \ - [TYPE_TA] = { \ + [PL2303_TYPE_TA] = { \ .name = (uint8_t const*)"TA", \ .max_baud_rate = 6000000, \ .alt_divisors = true, \ }, \ - [TYPE_TB] = { \ + [PL2303_TYPE_TB] = { \ .name = (uint8_t const*)"TB", \ .max_baud_rate = 12000000, \ .alt_divisors = true, \ }, \ - [TYPE_HXD] = { \ + [PL2303_TYPE_HXD] = { \ .name = (uint8_t const*)"HXD", \ .max_baud_rate = 12000000, \ }, \ - [TYPE_HXN] = { \ + [PL2303_TYPE_HXN] = { \ .name = (uint8_t const*)"G (HXN)", \ .max_baud_rate = 12000000, \ .no_divisors = true, \ @@ -166,7 +168,7 @@ typedef struct TU_ATTR_PACKED { #define PL2303_IN_EP 0x83 // return values of pl2303_detect_type() -#define PL2303_SUPPORTS_HX_STATUS_TRIGGERED -1 -#define PL2303_DETECT_TYPE_FAILED -2 +#define PL2303_TYPE_NEED_SUPPORTS_HX_STATUS -1 +#define PL2303_TYPE_UNKNOWN -2 #endif // TUSB_PL2303_H -- cgit v1.3.1 From ec1a26251d0161d5e7c11f4ca552af154cf08dbd Mon Sep 17 00:00:00 2001 From: hathach Date: Thu, 19 Jun 2025 17:05:21 +0700 Subject: clean up pl2303 type data --- src/class/cdc/cdc_host.c | 130 +++++++++++++++++++----------------------- src/class/cdc/serial/pl2303.h | 46 +++++---------- 2 files changed, 74 insertions(+), 102 deletions(-) (limited to 'src/class') diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index ce98e3b3d..dae38ba42 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -2274,7 +2274,7 @@ static uint8_t ch34x_get_lcr(cdch_interface_t *p_cdc) { //--------------------------------------------------------------------+ #if CFG_TUH_CDC_PL2303 -static int8_t pl2303_detect_type(cdch_interface_t *p_cdc, uint8_t step); +static pl2303_type_t pl2303_detect_type(cdch_interface_t *p_cdc, uint8_t step); static bool pl2303_encode_baud_rate(cdch_interface_t *p_cdc, uint8_t buf[PL2303_LINE_CODING_BAUDRATE_BUFSIZE]); //------------- Control Request -------------// @@ -2313,20 +2313,18 @@ static bool pl2303_set_request(cdch_interface_t *p_cdc, uint8_t request, uint8_t static bool pl2303_vendor_read(cdch_interface_t *p_cdc, uint16_t value, uint8_t *buf, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - uint8_t request = p_cdc->pl2303.serial_private.type == &pl2303_type_data[PL2303_TYPE_HXN] ? PL2303_VENDOR_READ_NREQUEST : PL2303_VENDOR_READ_REQUEST; + uint8_t request = p_cdc->pl2303.type == PL2303_TYPE_HXN ? PL2303_VENDOR_READ_NREQUEST : PL2303_VENDOR_READ_REQUEST; return pl2303_set_request(p_cdc, request, PL2303_VENDOR_READ_REQUEST_TYPE, value, 0, buf, 1, complete_cb, user_data); } static bool pl2303_vendor_write(cdch_interface_t *p_cdc, uint16_t value, uint16_t index, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - uint8_t request = p_cdc->pl2303.serial_private.type == &pl2303_type_data[PL2303_TYPE_HXN] ? PL2303_VENDOR_WRITE_NREQUEST : PL2303_VENDOR_WRITE_REQUEST; - + uint8_t request = p_cdc->pl2303.type == PL2303_TYPE_HXN ? PL2303_VENDOR_WRITE_NREQUEST : PL2303_VENDOR_WRITE_REQUEST; return pl2303_set_request(p_cdc, request, PL2303_VENDOR_WRITE_REQUEST_TYPE, value, index, NULL, 0, complete_cb, user_data); } static inline bool pl2303_supports_hx_status(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { uint8_t buf = 0; - return pl2303_set_request(p_cdc, PL2303_VENDOR_READ_REQUEST, PL2303_VENDOR_READ_REQUEST_TYPE, PL2303_READ_TYPE_HX_STATUS, 0, &buf, 1, complete_cb, user_data); } @@ -2425,7 +2423,6 @@ static void pl2303_internal_control_complete(tuh_xfer_t *xfer) { static bool pl2303_set_line_coding(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { p_cdc->user_control_cb = complete_cb; TU_ASSERT(pl2303_set_line_request(p_cdc, complete_cb ? pl2303_internal_control_complete : NULL, user_data)); - return true; } @@ -2433,7 +2430,6 @@ static bool pl2303_set_data_format(cdch_interface_t *p_cdc, tuh_xfer_cb_t comple p_cdc->requested_line_coding.bit_rate = p_cdc->line_coding.bit_rate; p_cdc->user_control_cb = complete_cb; TU_ASSERT(pl2303_set_line_request(p_cdc, complete_cb ? pl2303_internal_control_complete : NULL, user_data)); - return true; } @@ -2443,7 +2439,6 @@ static bool pl2303_set_baudrate(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_ p_cdc->requested_line_coding.data_bits = p_cdc->line_coding.data_bits; p_cdc->user_control_cb = complete_cb; TU_ASSERT(pl2303_set_line_request(p_cdc, complete_cb ? pl2303_internal_control_complete : NULL, user_data)); - return true; } @@ -2451,7 +2446,6 @@ static bool pl2303_set_modem_ctrl(cdch_interface_t *p_cdc, tuh_xfer_cb_t complet // PL2303 has the same bit coding p_cdc->user_control_cb = complete_cb; TU_ASSERT(pl2303_set_control_lines(p_cdc, complete_cb ? pl2303_internal_control_complete : NULL, user_data)); - return true; } @@ -2488,7 +2482,7 @@ static bool pl2303_open(uint8_t daddr, tusb_desc_interface_t const *itf_desc, ui TU_VERIFY(p_cdc); p_cdc->serial_drid = SERIAL_DRIVER_PL2303; - p_cdc->pl2303.serial_private.quirks = 0; + p_cdc->pl2303.quirks = 0; p_cdc->pl2303.supports_hx_status = false; tusb_desc_endpoint_t const *desc_ep = (tusb_desc_endpoint_t const *) tu_desc_next(itf_desc); @@ -2514,7 +2508,7 @@ static bool pl2303_process_set_config(tuh_xfer_t *xfer) { cdch_interface_t *p_cdc = get_itf(idx); // state CONFIG_PL2303_READ1 may have no success due to expected stall by pl2303_supports_hx_status() uint8_t buf = 0; - int8_t type; + pl2303_type_t type; TU_ASSERT(p_cdc && (xfer->result == XFER_RESULT_SUCCESS || state == CONFIG_PL2303_READ1)); switch (state) { @@ -2540,20 +2534,13 @@ static bool pl2303_process_set_config(tuh_xfer_t *xfer) { } type = pl2303_detect_type(p_cdc, 2); // step 2 now with supports_hx_status TU_ASSERT(type != PL2303_TYPE_UNKNOWN); - p_cdc->pl2303.serial_private.type = &pl2303_type_data[type]; - p_cdc->pl2303.serial_private.quirks |= p_cdc->pl2303.serial_private.type->quirks; - #if CFG_TUSB_DEBUG >= CFG_TUH_CDC_LOG_LEVEL && 0// can be activated if necessary - TU_LOG_P_CDC("bDeviceClass = 0x%02x bMaxPacketSize0 = %u bcdUSB = 0x%04x bcdDevice = 0x%04x", - desc_dev->bDeviceClass, desc_dev->bMaxPacketSize0, - desc_dev->bcdUSB, desc_dev->bcdDevice); - uint16_t vid, pid; - TU_ASSERT(tuh_vid_pid_get(p_cdc->daddr, &vid, &pid)); - TU_LOG_P_CDC("vid = 0x%04x pid = 0x%04x supports_hx_status = %u type = %s quirks = %u", - vid, pid, p_cdc->pl2303.supports_hx_status, - p_cdc->pl2303.serial_private.type->name, p_cdc->pl2303.serial_private.quirks); - #endif + TU_LOG_DRV(" PL2303 type detected: %u\r\n", type); + + p_cdc->pl2303.type = type; + p_cdc->pl2303.quirks |= pl2303_type_data[type].quirks; + // purpose unknown, overtaken from Linux Kernel driver - if (p_cdc->pl2303.serial_private.type != &pl2303_type_data[PL2303_TYPE_HXN]) { + if (p_cdc->pl2303.type != PL2303_TYPE_HXN) { TU_ASSERT(pl2303_vendor_read(p_cdc, 0x8484, &buf, cdch_process_set_config, CONFIG_PL2303_WRITE1)); break; }// else: continue with next step @@ -2561,7 +2548,7 @@ static bool pl2303_process_set_config(tuh_xfer_t *xfer) { case CONFIG_PL2303_WRITE1: // purpose unknown, overtaken from Linux Kernel driver - if (p_cdc->pl2303.serial_private.type != &pl2303_type_data[PL2303_TYPE_HXN]) { + if (p_cdc->pl2303.type != PL2303_TYPE_HXN) { TU_ASSERT(pl2303_vendor_write(p_cdc, 0x0404, 0, cdch_process_set_config, CONFIG_PL2303_READ2)); break; }// else: continue with next step @@ -2569,7 +2556,7 @@ static bool pl2303_process_set_config(tuh_xfer_t *xfer) { case CONFIG_PL2303_READ2: // purpose unknown, overtaken from Linux Kernel driver - if (p_cdc->pl2303.serial_private.type != &pl2303_type_data[PL2303_TYPE_HXN]) { + if (p_cdc->pl2303.type != PL2303_TYPE_HXN) { TU_ASSERT(pl2303_vendor_read(p_cdc, 0x8484, &buf, cdch_process_set_config, CONFIG_PL2303_READ3)); break; }// else: continue with next step @@ -2577,7 +2564,7 @@ static bool pl2303_process_set_config(tuh_xfer_t *xfer) { case CONFIG_PL2303_READ3: // purpose unknown, overtaken from Linux Kernel driver - if (p_cdc->pl2303.serial_private.type != &pl2303_type_data[PL2303_TYPE_HXN]) { + if (p_cdc->pl2303.type != PL2303_TYPE_HXN) { TU_ASSERT(pl2303_vendor_read(p_cdc, 0x8383, &buf, cdch_process_set_config, CONFIG_PL2303_READ4)); break; }// else: continue with next step @@ -2585,7 +2572,7 @@ static bool pl2303_process_set_config(tuh_xfer_t *xfer) { case CONFIG_PL2303_READ4: // purpose unknown, overtaken from Linux Kernel driver - if (p_cdc->pl2303.serial_private.type != &pl2303_type_data[PL2303_TYPE_HXN]) { + if (p_cdc->pl2303.type != PL2303_TYPE_HXN) { TU_ASSERT(pl2303_vendor_read(p_cdc, 0x8484, &buf, cdch_process_set_config, CONFIG_PL2303_WRITE2)); break; }// else: continue with next step @@ -2593,7 +2580,7 @@ static bool pl2303_process_set_config(tuh_xfer_t *xfer) { case CONFIG_PL2303_WRITE2: // purpose unknown, overtaken from Linux Kernel driver - if (p_cdc->pl2303.serial_private.type != &pl2303_type_data[PL2303_TYPE_HXN]) { + if (p_cdc->pl2303.type != PL2303_TYPE_HXN) { TU_ASSERT(pl2303_vendor_write(p_cdc, 0x0404, 1, cdch_process_set_config, CONFIG_PL2303_READ5)); break; }// else: continue with next step @@ -2601,7 +2588,7 @@ static bool pl2303_process_set_config(tuh_xfer_t *xfer) { case CONFIG_PL2303_READ5: // purpose unknown, overtaken from Linux Kernel driver - if (p_cdc->pl2303.serial_private.type != &pl2303_type_data[PL2303_TYPE_HXN]) { + if (p_cdc->pl2303.type != PL2303_TYPE_HXN) { TU_ASSERT(pl2303_vendor_read(p_cdc, 0x8484, &buf, cdch_process_set_config, CONFIG_PL2303_READ6)); break; }// else: continue with next step @@ -2609,7 +2596,7 @@ static bool pl2303_process_set_config(tuh_xfer_t *xfer) { case CONFIG_PL2303_READ6: // purpose unknown, overtaken from Linux Kernel driver - if (p_cdc->pl2303.serial_private.type != &pl2303_type_data[PL2303_TYPE_HXN]) { + if (p_cdc->pl2303.type != PL2303_TYPE_HXN) { TU_ASSERT(pl2303_vendor_read(p_cdc, 0x8383, &buf, cdch_process_set_config, CONFIG_PL2303_WRITE3)); break; }// else: continue with next step @@ -2617,7 +2604,7 @@ static bool pl2303_process_set_config(tuh_xfer_t *xfer) { case CONFIG_PL2303_WRITE3: // purpose unknown, overtaken from Linux Kernel driver - if (p_cdc->pl2303.serial_private.type != &pl2303_type_data[PL2303_TYPE_HXN]) { + if (p_cdc->pl2303.type != PL2303_TYPE_HXN) { TU_ASSERT(pl2303_vendor_write(p_cdc, 0, 1, cdch_process_set_config, CONFIG_PL2303_WRITE4)); break; }// else: continue with next step @@ -2625,7 +2612,7 @@ static bool pl2303_process_set_config(tuh_xfer_t *xfer) { case CONFIG_PL2303_WRITE4: // purpose unknown, overtaken from Linux Kernel driver - if (p_cdc->pl2303.serial_private.type != &pl2303_type_data[PL2303_TYPE_HXN]) { + if (p_cdc->pl2303.type != PL2303_TYPE_HXN) { TU_ASSERT(pl2303_vendor_write(p_cdc, 1, 0, cdch_process_set_config, CONFIG_PL2303_WRITE5)); break; }// else: continue with next step @@ -2633,21 +2620,21 @@ static bool pl2303_process_set_config(tuh_xfer_t *xfer) { case CONFIG_PL2303_WRITE5: // purpose unknown, overtaken from Linux Kernel driver - if (p_cdc->pl2303.serial_private.type != &pl2303_type_data[PL2303_TYPE_HXN]) { - uint16_t const windex = (p_cdc->pl2303.serial_private.quirks & PL2303_QUIRK_LEGACY) ? 0x24 : 0x44; + if (p_cdc->pl2303.type != PL2303_TYPE_HXN) { + uint16_t const windex = (p_cdc->pl2303.quirks & PL2303_QUIRK_LEGACY) ? 0x24 : 0x44; TU_ASSERT(pl2303_vendor_write(p_cdc, 2, windex, cdch_process_set_config, CONFIG_PL2303_RESET_ENDP1)); break; }// else: continue with next step TU_ATTR_FALLTHROUGH; - // from here sequence overtaken from Linux Kernel function pl2303_open() + // from here sequence overtaken from Linux Kernel function pl2303_open() case CONFIG_PL2303_RESET_ENDP1: // step 1 - if (p_cdc->pl2303.serial_private.quirks & PL2303_QUIRK_LEGACY) { + if (p_cdc->pl2303.quirks & PL2303_QUIRK_LEGACY) { TU_ASSERT(pl2303_clear_halt(p_cdc, PL2303_OUT_EP, cdch_process_set_config, CONFIG_PL2303_RESET_ENDP2)); } else { /* reset upstream data pipes */ - if (p_cdc->pl2303.serial_private.type == &pl2303_type_data[PL2303_TYPE_HXN]) { + if (p_cdc->pl2303.type == PL2303_TYPE_HXN) { TU_ASSERT(pl2303_vendor_write(p_cdc, PL2303_HXN_RESET_REG,// skip CONFIG_PL2303_RESET_ENDP2, no 2nd step PL2303_HXN_RESET_UPSTREAM_PIPE | PL2303_HXN_RESET_DOWNSTREAM_PIPE, cdch_process_set_config, CONFIG_PL2303_LINE_CODING)); @@ -2659,11 +2646,11 @@ static bool pl2303_process_set_config(tuh_xfer_t *xfer) { case CONFIG_PL2303_RESET_ENDP2: // step 2 - if (p_cdc->pl2303.serial_private.quirks & PL2303_QUIRK_LEGACY) { + if (p_cdc->pl2303.quirks & PL2303_QUIRK_LEGACY) { TU_ASSERT(pl2303_clear_halt(p_cdc, PL2303_IN_EP, cdch_process_set_config, CONFIG_PL2303_LINE_CODING)); } else { /* reset upstream data pipes */ - if (p_cdc->pl2303.serial_private.type == &pl2303_type_data[PL2303_TYPE_HXN]) { + if (p_cdc->pl2303.type == PL2303_TYPE_HXN) { // here nothing to do, only structure of previous step overtaken for better reading and comparison } else { TU_ASSERT(pl2303_vendor_write(p_cdc, 9, 0, cdch_process_set_config, CONFIG_PL2303_LINE_CODING)); @@ -2691,33 +2678,33 @@ static bool pl2303_process_set_config(tuh_xfer_t *xfer) { TU_ATTR_FALLTHROUGH; #endif - // skipped, because it's not working with each PL230x. flow control can be also set by PL2303 EEPROM Writer Program - // case CONFIG_PL2303_FLOW_CTRL_READ: - // // read flow control register for modify & write back in next step - // if (p_cdc->pl2303.serial_private.type == &pl2303_type_data[PL2303_TYPE_HXN]) { - // TU_LOG_P_CDC ( "1\r\n" ); - // TU_ASSERT(pl2303_vendor_read(p_cdc, PL2303_HXN_FLOWCTRL_REG, &buf, - // cdch_process_set_config, CONFIG_PL2303_FLOW_CTRL_WRITE)); - // } else { - // TU_LOG_P_CDC ( "2\r\n" ); - // TU_ASSERT(pl2303_vendor_read(p_cdc, 0, &buf, cdch_process_set_config, CONFIG_PL2303_FLOW_CTRL_WRITE)); - // } - // break; - // - // case CONFIG_PL2303_FLOW_CTRL_WRITE: - // // no flow control - // buf = xfer->buffer[0]; - // if (p_cdc->pl2303.serial_private.type == &pl2303_type_data[PL2303_TYPE_HXN]) { - // buf &= (uint8_t) ~PL2303_HXN_FLOWCTRL_MASK; - // buf |= PL2303_HXN_FLOWCTRL_NONE; - // TU_ASSERT(pl2303_vendor_write(p_cdc, PL2303_HXN_FLOWCTRL_REG, buf, - // cdch_process_set_config, CONFIG_PL2303_COMPLETE)); - // } else { - // buf &= (uint8_t) ~PL2303_FLOWCTRL_MASK; - // TU_ASSERT(pl2303_vendor_write(p_cdc, 0, buf, - // cdch_process_set_config, CONFIG_PL2303_COMPLETE)); - // } - // break; + // skipped, because it's not working with each PL230x. flow control can be also set by PL2303 EEPROM Writer Program + // case CONFIG_PL2303_FLOW_CTRL_READ: + // // read flow control register for modify & write back in next step + // if (p_cdc->pl2303.type == PL2303_TYPE_HXN) { + // TU_LOG_P_CDC ( "1\r\n" ); + // TU_ASSERT(pl2303_vendor_read(p_cdc, PL2303_HXN_FLOWCTRL_REG, &buf, + // cdch_process_set_config, CONFIG_PL2303_FLOW_CTRL_WRITE)); + // } else { + // TU_LOG_P_CDC ( "2\r\n" ); + // TU_ASSERT(pl2303_vendor_read(p_cdc, 0, &buf, cdch_process_set_config, CONFIG_PL2303_FLOW_CTRL_WRITE)); + // } + // break; + // + // case CONFIG_PL2303_FLOW_CTRL_WRITE: + // // no flow control + // buf = xfer->buffer[0]; + // if (p_cdc->pl2303.type == PL2303_TYPE_HXN) { + // buf &= (uint8_t) ~PL2303_HXN_FLOWCTRL_MASK; + // buf |= PL2303_HXN_FLOWCTRL_NONE; + // TU_ASSERT(pl2303_vendor_write(p_cdc, PL2303_HXN_FLOWCTRL_REG, buf, + // cdch_process_set_config, CONFIG_PL2303_COMPLETE)); + // } else { + // buf &= (uint8_t) ~PL2303_FLOWCTRL_MASK; + // TU_ASSERT(pl2303_vendor_write(p_cdc, 0, buf, + // cdch_process_set_config, CONFIG_PL2303_COMPLETE)); + // } + // break; case CONFIG_PL2303_COMPLETE: set_config_complete(idx, 0, true); @@ -2732,7 +2719,7 @@ static bool pl2303_process_set_config(tuh_xfer_t *xfer) { //------------- Helper -------------// -static int8_t pl2303_detect_type(cdch_interface_t *p_cdc, uint8_t step) { +static pl2303_type_t pl2303_detect_type(cdch_interface_t *p_cdc, uint8_t step) { tusb_desc_device_t desc_dev; TU_VERIFY(tuh_descriptor_get_device_local(p_cdc->daddr, &desc_dev), PL2303_TYPE_UNKNOWN); @@ -2932,13 +2919,14 @@ static uint32_t pl2303_encode_baud_rate_divisor_alt(uint8_t buf[PL2303_LINE_CODI static bool pl2303_encode_baud_rate(cdch_interface_t *p_cdc, uint8_t buf[PL2303_LINE_CODING_BAUDRATE_BUFSIZE]) { uint32_t baud = p_cdc->requested_line_coding.bit_rate; uint32_t baud_sup; + const pl2303_type_data_t* type_data = &pl2303_type_data[p_cdc->pl2303.type]; - TU_VERIFY(baud && baud <= p_cdc->pl2303.serial_private.type->max_baud_rate); + TU_VERIFY(baud && baud <= type_data->max_baud_rate); /* * Use direct method for supported baud rates, otherwise use divisors. * Newer chip types do not support divisor encoding. */ - if (p_cdc->pl2303.serial_private.type->no_divisors) { + if (type_data->no_divisors) { baud_sup = baud; } else { baud_sup = pl2303_get_supported_baud_rate(baud); @@ -2946,7 +2934,7 @@ static bool pl2303_encode_baud_rate(cdch_interface_t *p_cdc, uint8_t buf[PL2303_ if (baud == baud_sup) { baud = pl2303_encode_baud_rate_direct(buf, baud); - } else if (p_cdc->pl2303.serial_private.type->alt_divisors) { + } else if (type_data->alt_divisors) { baud = pl2303_encode_baud_rate_divisor_alt(buf, baud); } else { baud = pl2303_encode_baud_rate_divisor(buf, baud); diff --git a/src/class/cdc/serial/pl2303.h b/src/class/cdc/serial/pl2303.h index 40311260d..c01dac0e1 100644 --- a/src/class/cdc/serial/pl2303.h +++ b/src/class/cdc/serial/pl2303.h @@ -97,65 +97,53 @@ // type data typedef enum pl2303_type { - PL2303_TYPE_H, - PL2303_TYPE_HX, - PL2303_TYPE_TA, - PL2303_TYPE_TB, - PL2303_TYPE_HXD, - PL2303_TYPE_HXN, - // PL2303_TYPE_NEED_SUPPORTS_HX_STATUS, - // PL2303_TYPE_UNKNOWN, - PL2303_TYPE_COUNT + PL2303_TYPE_H = 0, // 0 + PL2303_TYPE_HX, // 1 + PL2303_TYPE_TA, // 2 + PL2303_TYPE_TB, // 3 + PL2303_TYPE_HXD, // 4 + PL2303_TYPE_HXN, // 5 + PL2303_TYPE_COUNT, + PL2303_TYPE_NEED_SUPPORTS_HX_STATUS, + PL2303_TYPE_UNKNOWN, } pl2303_type_t; typedef struct pl2303_type_data { - uint8_t const *name; uint32_t const max_baud_rate; - uint8_t const quirks; - uint16_t const no_autoxonxoff:1; - uint16_t const no_divisors:1; - uint16_t const alt_divisors:1; + uint8_t const quirks; + uint8_t const no_autoxonxoff : 1; + uint8_t const no_divisors : 1; + uint8_t const alt_divisors : 1; } pl2303_type_data_t; #define PL2303_TYPE_DATA \ [PL2303_TYPE_H] = { \ - .name = (uint8_t const*)"H", \ .max_baud_rate = 1228800, \ .quirks = PL2303_QUIRK_LEGACY, \ .no_autoxonxoff = true, \ }, \ [PL2303_TYPE_HX] = { \ - .name = (uint8_t const*)"HX", \ .max_baud_rate = 6000000, \ }, \ [PL2303_TYPE_TA] = { \ - .name = (uint8_t const*)"TA", \ .max_baud_rate = 6000000, \ .alt_divisors = true, \ }, \ [PL2303_TYPE_TB] = { \ - .name = (uint8_t const*)"TB", \ .max_baud_rate = 12000000, \ .alt_divisors = true, \ }, \ [PL2303_TYPE_HXD] = { \ - .name = (uint8_t const*)"HXD", \ .max_baud_rate = 12000000, \ }, \ [PL2303_TYPE_HXN] = { \ - .name = (uint8_t const*)"G (HXN)", \ .max_baud_rate = 12000000, \ .no_divisors = true, \ } -// private data types -struct pl2303_serial_private { - const struct pl2303_type_data* type; - uint8_t quirks; -}; - typedef struct TU_ATTR_PACKED { - struct pl2303_serial_private serial_private; + pl2303_type_t type; + uint8_t quirks; bool supports_hx_status; } pl2303_private_t; @@ -167,8 +155,4 @@ typedef struct TU_ATTR_PACKED { #define PL2303_OUT_EP 0x02 #define PL2303_IN_EP 0x83 -// return values of pl2303_detect_type() -#define PL2303_TYPE_NEED_SUPPORTS_HX_STATUS -1 -#define PL2303_TYPE_UNKNOWN -2 - #endif // TUSB_PL2303_H -- cgit v1.3.1 From fa3ec44533ff986688318c3f80e9f373f55318f0 Mon Sep 17 00:00:00 2001 From: hathach Date: Thu, 19 Jun 2025 17:22:26 +0700 Subject: revert CFG_TUH_CDC_DTR/RTS_CONTROL_ON_ENUM --- examples/host/cdc_msc_hid/src/tusb_config.h | 5 +-- .../host/cdc_msc_hid_freertos/src/tusb_config.h | 3 +- src/class/cdc/cdc.h | 14 +++---- src/class/cdc/cdc_host.c | 49 +++++++--------------- 4 files changed, 24 insertions(+), 47 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 4bd5b0472..e610c5672 100644 --- a/examples/host/cdc_msc_hid/src/tusb_config.h +++ b/examples/host/cdc_msc_hid/src/tusb_config.h @@ -103,7 +103,7 @@ #define CFG_TUH_ENUMERATION_BUFSIZE 256 #define CFG_TUH_HUB 1 // number of supported hubs -#define CFG_TUH_CDC 1 // number of supported CDC devices. also activates CDC ACM +#define CFG_TUH_CDC 4 // number of supported CDC devices. also activates 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 @@ -122,8 +122,7 @@ //------------- CDC -------------// // Set Line Control state on enumeration/mounted: -#define CFG_TUH_CDC_DTR_CONTROL_ON_ENUM true -#define CFG_TUH_CDC_RTS_CONTROL_ON_ENUM true +#define CFG_TUH_CDC_LINE_CONTROL_ON_ENUM (CDC_CONTROL_LINE_STATE_DTR | CDC_CONTROL_LINE_STATE_RTS) // 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 94b121672..05deecba0 100644 --- a/examples/host/cdc_msc_hid_freertos/src/tusb_config.h +++ b/examples/host/cdc_msc_hid_freertos/src/tusb_config.h @@ -127,8 +127,7 @@ //------------- CDC -------------// // Set Line Control state on enumeration/mounted: -#define CFG_TUH_CDC_DTR_CONTROL_ON_ENUM true -#define CFG_TUH_CDC_RTS_CONTROL_ON_ENUM true +#define CFG_TUH_CDC_LINE_CONTROL_ON_ENUM (CDC_CONTROL_LINE_STATE_DTR | CDC_CONTROL_LINE_STATE_RTS) // 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.h b/src/class/cdc/cdc.h index 10aed79ab..9f3ace63c 100644 --- a/src/class/cdc/cdc.h +++ b/src/class/cdc/cdc.h @@ -404,8 +404,7 @@ static inline uint8_t cdc_functional_desc_typeof(uint8_t const * p_desc) //--------------------------------------------------------------------+ // Requests //--------------------------------------------------------------------+ -typedef struct TU_ATTR_PACKED -{ +typedef struct TU_ATTR_PACKED { uint32_t bit_rate; uint8_t stop_bits; ///< 0: 1 stop bit - 1: 1.5 stop bits - 2: 2 stop bits uint8_t parity; ///< 0: None - 1: Odd - 2: Even - 3: Mark - 4: Space @@ -414,14 +413,13 @@ typedef struct TU_ATTR_PACKED TU_VERIFY_STATIC(sizeof(cdc_line_coding_t) == 7, "size is not correct"); -typedef union TU_ATTR_PACKED -{ +typedef union TU_ATTR_PACKED { struct { - uint8_t dtr : 1; - uint8_t rts : 1; - uint8_t : 6; + uint8_t dtr : 1; + uint8_t rts : 1; + uint8_t : 6; }; - uint8_t all; + uint8_t value; } cdc_line_control_state_t; TU_VERIFY_STATIC(sizeof(cdc_line_control_state_t) == 1, "size is not correct"); diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index dae38ba42..7259e819f 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -52,25 +52,6 @@ serial_drivers[p_cdc->serial_drid].name, ##__VA_ARGS__) #define TU_LOG_P_CDC_BOOL(TXT,VAL) TU_LOG_P_CDC(TXT " " #VAL " = %d", VAL) -// handle line control defines -#if defined(CFG_TUH_CDC_LINE_CONTROL_ON_ENUM) && \ - (defined(CFG_TUH_CDC_DTR_CONTROL_ON_ENUM) || defined(CFG_TUH_CDC_RTS_CONTROL_ON_ENUM)) - TU_VERIFY_STATIC(false, "Contradictory line control defines"); -#endif - -#ifdef CFG_TUH_CDC_LINE_CONTROL_ON_ENUM - #define LINE_CONTROL_ON_ENUM CFG_TUH_CDC_LINE_CONTROL_ON_ENUM -#elif defined(CFG_TUH_CDC_DTR_CONTROL_ON_ENUM) || defined(CFG_TUH_CDC_RTS_CONTROL_ON_ENUM) - #ifndef CFG_TUH_CDC_DTR_CONTROL_ON_ENUM - #define CFG_TUH_CDC_DTR_CONTROL_ON_ENUM 0 - #endif - #ifndef CFG_TUH_CDC_RTS_CONTROL_ON_ENUM - #define CFG_TUH_CDC_RTS_CONTROL_ON_ENUM 0 - #endif - #define LINE_CONTROL_ON_ENUM ( ( CFG_TUH_CDC_DTR_CONTROL_ON_ENUM ? CDC_CONTROL_LINE_STATE_DTR : 0 ) | \ - ( CFG_TUH_CDC_RTS_CONTROL_ON_ENUM ? CDC_CONTROL_LINE_STATE_RTS : 0 ) ) -#endif - //--------------------------------------------------------------------+ // Host CDC Interface //--------------------------------------------------------------------+ @@ -396,7 +377,7 @@ static cdch_interface_t * make_new_itf(uint8_t daddr, tusb_desc_interface_t cons p_cdc->bInterfaceSubClass = itf_desc->bInterfaceSubClass; p_cdc->bInterfaceProtocol = itf_desc->bInterfaceProtocol; p_cdc->line_coding = (cdc_line_coding_t) { 0, 0, 0, 0 }; - p_cdc->line_state.all = 0; + p_cdc->line_state.value = 0; return p_cdc; } } @@ -661,7 +642,7 @@ bool tuh_cdc_set_control_line_state_u(uint8_t idx, cdc_line_control_state_t line bool tuh_cdc_set_control_line_state(uint8_t idx, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { // uses uint16_t for line_state => DTR (bit 0), RTS (bit 1) - return tuh_cdc_set_control_line_state_u(idx, (cdc_line_control_state_t) { .all = (uint8_t) line_state }, + return tuh_cdc_set_control_line_state_u(idx, (cdc_line_control_state_t) { .value = (uint8_t) line_state }, complete_cb, user_data); } @@ -1004,7 +985,7 @@ static bool acm_set_control_line_state(cdch_interface_t *p_cdc, tuh_xfer_cb_t co .direction = TUSB_DIR_OUT }, .bRequest = CDC_REQUEST_SET_CONTROL_LINE_STATE, - .wValue = tu_htole16((uint16_t) p_cdc->requested_line_state.all), + .wValue = tu_htole16((uint16_t) p_cdc->requested_line_state.value), .wIndex = tu_htole16((uint16_t) p_cdc->bInterfaceNumber), .wLength = 0 }; @@ -1137,9 +1118,9 @@ static bool acm_process_set_config(tuh_xfer_t *xfer) { switch (state) { case CONFIG_ACM_SET_CONTROL_LINE_STATE: - #ifdef LINE_CONTROL_ON_ENUM + #ifdef CFG_TUH_CDC_LINE_CONTROL_ON_ENUM if (p_cdc->acm_capability.support_line_request) { - p_cdc->requested_line_state.all = LINE_CONTROL_ON_ENUM; + p_cdc->requested_line_state.value = CFG_TUH_CDC_LINE_CONTROL_ON_ENUM; TU_ASSERT(acm_set_control_line_state(p_cdc, cdch_process_set_config, CONFIG_ACM_SET_LINE_CODING)); break; } @@ -1426,8 +1407,8 @@ static bool ftdi_proccess_set_config(tuh_xfer_t *xfer) { break; case CONFIG_FTDI_MODEM_CTRL: - #ifdef LINE_CONTROL_ON_ENUM - p_cdc->requested_line_state.all = LINE_CONTROL_ON_ENUM; + #ifdef CFG_TUH_CDC_LINE_CONTROL_ON_ENUM + p_cdc->requested_line_state.value = CFG_TUH_CDC_LINE_CONTROL_ON_ENUM; p_cdc->user_control_cb = cdch_process_set_config; TU_ASSERT(ftdi_update_mctrl(p_cdc, ftdi_internal_control_complete, CONFIG_FTDI_COMPLETE)); break; @@ -1735,7 +1716,7 @@ static inline bool cp210x_set_mhs(cdch_interface_t *p_cdc, tuh_xfer_cb_t complet // CP210x has the same bit coding return cp210x_set_request(p_cdc, CP210X_SET_MHS, (uint16_t) (CP210X_CONTROL_WRITE_DTR | CP210X_CONTROL_WRITE_RTS | - p_cdc->requested_line_state.all), + p_cdc->requested_line_state.value), NULL, 0, complete_cb, user_data); } @@ -1873,8 +1854,8 @@ static bool cp210x_process_set_config(tuh_xfer_t *xfer) { #endif case CONFIG_CP210X_SET_DTR_RTS: - #ifdef LINE_CONTROL_ON_ENUM - p_cdc->requested_line_state.all = LINE_CONTROL_ON_ENUM; + #ifdef CFG_TUH_CDC_LINE_CONTROL_ON_ENUM + p_cdc->requested_line_state.value = CFG_TUH_CDC_LINE_CONTROL_ON_ENUM; p_cdc->user_control_cb = cdch_process_set_config; TU_ASSERT(cp210x_set_mhs(p_cdc, cp210x_internal_control_complete, CONFIG_CP210X_COMPLETE)); break; @@ -2153,8 +2134,8 @@ static bool ch34x_process_set_config(tuh_xfer_t *xfer) { break; case CONFIG_CH34X_MODEM_CONTROL: - #ifdef LINE_CONTROL_ON_ENUM - p_cdc->requested_line_state.all = LINE_CONTROL_ON_ENUM; + #ifdef CFG_TUH_CDC_LINE_CONTROL_ON_ENUM + p_cdc->requested_line_state.value = CFG_TUH_CDC_LINE_CONTROL_ON_ENUM; p_cdc->user_control_cb = cdch_process_set_config; TU_ASSERT(ch34x_modem_ctrl_request(p_cdc, ch34x_internal_control_complete, CONFIG_CH34X_COMPLETE)); break; @@ -2332,7 +2313,7 @@ static inline bool pl2303_supports_hx_status(cdch_interface_t *p_cdc, tuh_xfer_c static inline bool pl2303_set_control_lines(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { // PL2303 has the same bit coding return pl2303_set_request(p_cdc, PL2303_SET_CONTROL_REQUEST, PL2303_SET_CONTROL_REQUEST_TYPE, - p_cdc->requested_line_state.all, 0, NULL, 0, complete_cb, user_data); + p_cdc->requested_line_state.value, 0, NULL, 0, complete_cb, user_data); } //static bool pl2303_get_line_request(cdch_interface_t * p_cdc, uint8_t buf[PL2303_LINE_CODING_BUFSIZE]) @@ -2670,8 +2651,8 @@ static bool pl2303_process_set_config(tuh_xfer_t *xfer) { #endif case CONFIG_PL2303_MODEM_CONTROL: - #ifdef LINE_CONTROL_ON_ENUM - p_cdc->requested_line_state.all = LINE_CONTROL_ON_ENUM; + #ifdef CFG_TUH_CDC_LINE_CONTROL_ON_ENUM + p_cdc->requested_line_state.value = CFG_TUH_CDC_LINE_CONTROL_ON_ENUM; TU_ASSERT(pl2303_set_control_lines(p_cdc, pl2303_internal_control_complete, CONFIG_PL2303_COMPLETE)); break; #else -- cgit v1.3.1 From ce9140a150f685ae228362c5fcd0b85a7900e67a Mon Sep 17 00:00:00 2001 From: hathach Date: Thu, 19 Jun 2025 17:57:21 +0700 Subject: rename tuh_cdc_get_local_line_coding to tuh_cdc_get_line_coding_local add tuh_cdc_get_control_line_state_local() implement tuh_cdc_get/set_dtr/rts() as inline --- src/class/cdc/cdc_host.c | 55 ++++++++---------------------------------------- src/class/cdc/cdc_host.h | 45 +++++++++++++++++++++++++++++---------- 2 files changed, 43 insertions(+), 57 deletions(-) (limited to 'src/class') diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index 7259e819f..80b01f928 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -427,27 +427,14 @@ bool tuh_cdc_mounted(uint8_t idx) { return p_cdc->mounted; } -bool tuh_cdc_get_dtr(uint8_t idx) { +bool tuh_cdc_get_control_line_state_local(uint8_t idx, uint16_t* line_state) { cdch_interface_t * p_cdc = get_itf(idx); TU_VERIFY(p_cdc); - - bool ret = p_cdc->line_state.dtr; -// TU_LOG_P_CDC_BOOL("get DTR", ret); - - return ret; -} - -bool tuh_cdc_get_rts(uint8_t idx) { - cdch_interface_t * p_cdc = get_itf(idx); - TU_VERIFY(p_cdc); - - bool ret = p_cdc->line_state.rts; -// TU_LOG_P_CDC_BOOL("get RTS", ret); - - return ret; + *line_state = p_cdc->line_state.value; + return true; } -bool tuh_cdc_get_local_line_coding(uint8_t idx, cdc_line_coding_t * line_coding) { +bool tuh_cdc_get_line_coding_local(uint8_t idx, cdc_line_coding_t * line_coding) { cdch_interface_t * p_cdc = get_itf(idx); TU_VERIFY(p_cdc); @@ -622,46 +609,22 @@ static bool set_function_call ( } } -bool tuh_cdc_set_control_line_state_u(uint8_t idx, cdc_line_control_state_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - // uses cdc_line_control_state_t union for line_state +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); - TU_LOG_P_CDC("set control line state dtr = %u rts = %u", line_state.dtr, line_state.rts); cdch_serial_driver_t const * driver = &serial_drivers[p_cdc->serial_drid]; - p_cdc->requested_line_state = line_state; + p_cdc->requested_line_state.value = (uint8_t) line_state; + TU_LOG_P_CDC("set control line state dtr = %u rts = %u", p_cdc->requested_line_state.dtr, p_cdc->requested_line_state.rts); - bool ret = set_function_call(p_cdc, driver->set_control_line_state, complete_cb, user_data); + const bool ret = set_function_call(p_cdc, driver->set_control_line_state, complete_cb, user_data); if (ret && !complete_cb) { - p_cdc->line_state = line_state; + p_cdc->line_state = p_cdc->requested_line_state; } return ret; } -bool tuh_cdc_set_control_line_state(uint8_t idx, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - // uses uint16_t for line_state => DTR (bit 0), RTS (bit 1) - - return tuh_cdc_set_control_line_state_u(idx, (cdc_line_control_state_t) { .value = (uint8_t) line_state }, - complete_cb, user_data); -} - -bool tuh_cdc_set_dtr(uint8_t idx, bool dtr_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); - cdc_line_control_state_t const line_state = { .dtr = dtr_state, .rts = p_cdc->line_state.rts }; - - return tuh_cdc_set_control_line_state_u(idx, line_state, complete_cb, user_data); -} - -bool tuh_cdc_set_rts(uint8_t idx, bool rts_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); - cdc_line_control_state_t const line_state = {.rts = rts_state, .dtr = p_cdc->line_state.dtr}; - - return tuh_cdc_set_control_line_state_u(idx, line_state, complete_cb, user_data); -} - bool tuh_cdc_set_baudrate(uint8_t idx, uint32_t baudrate, 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); diff --git a/src/class/cdc/cdc_host.h b/src/class/cdc/cdc_host.h index 63eb1fc0f..688164cb2 100644 --- a/src/class/cdc/cdc_host.h +++ b/src/class/cdc/cdc_host.h @@ -69,14 +69,27 @@ uint8_t tuh_cdc_itf_get_index(uint8_t daddr, uint8_t itf_num); // return true if index is correct and interface is currently mounted bool tuh_cdc_itf_get_info(uint8_t idx, tuh_itf_info_t* info); -// Check if a interface is mounted +// Check if an interface is mounted bool tuh_cdc_mounted(uint8_t idx); +// Get local (cached) line state +// This function should return correct values if tuh_cdc_set_control_line_state() / tuh_cdc_get_control_line_state() +// are invoked previously or CFG_TUH_CDC_LINE_STATE_ON_ENUM is defined. +bool tuh_cdc_get_control_line_state_local(uint8_t idx, uint16_t* line_state); + // Get current DTR status -bool tuh_cdc_get_dtr(uint8_t idx); +TU_ATTR_ALWAYS_INLINE static inline bool tuh_cdc_get_dtr(uint8_t idx) { + uint16_t line_state; + TU_VERIFY(tuh_cdc_get_control_line_state_local(idx, &line_state)); + return (line_state & CDC_CONTROL_LINE_STATE_DTR) != 0; +} // Get current RTS status -bool tuh_cdc_get_rts(uint8_t idx); +TU_ATTR_ALWAYS_INLINE static inline bool tuh_cdc_get_rts(uint8_t idx) { + uint16_t line_state; + TU_VERIFY(tuh_cdc_get_control_line_state_local(idx, &line_state)); + return (line_state & CDC_CONTROL_LINE_STATE_RTS) != 0; +} // Check if interface is connected (DTR active) TU_ATTR_ALWAYS_INLINE static inline bool tuh_cdc_connected(uint8_t idx) { @@ -87,7 +100,9 @@ TU_ATTR_ALWAYS_INLINE static inline bool tuh_cdc_connected(uint8_t idx) { // This function should return correct values if tuh_cdc_set_line_coding() / tuh_cdc_get_line_coding() // are invoked previously or CFG_TUH_CDC_LINE_CODING_ON_ENUM is defined. // NOTE: This function does not make any USB transfer request to device. -bool tuh_cdc_get_local_line_coding(uint8_t idx, cdc_line_coding_t* line_coding); +bool tuh_cdc_get_line_coding_local(uint8_t idx, cdc_line_coding_t* line_coding); + +#define tuh_cdc_get_local_line_coding tuh_cdc_get_line_coding_local // backward compatibility //--------------------------------------------------------------------+ // Write API @@ -131,14 +146,22 @@ 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 -bool tuh_cdc_set_control_line_state_u(uint8_t idx, cdc_line_control_state_t line_state, // uses cdc_line_control_state_t union for line_state - tuh_xfer_cb_t complete_cb, uintptr_t user_data); -bool tuh_cdc_set_control_line_state(uint8_t idx, uint16_t line_state, // uses uint16_t for line_state (legacy function) - tuh_xfer_cb_t complete_cb, uintptr_t user_data); // DTR (bit 0), RTS (bit 1) +// Request to Set Control Line State: DTR (bit 0), RTS (bit 1) +bool tuh_cdc_set_control_line_state(uint8_t idx, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data); -bool tuh_cdc_set_dtr(uint8_t idx, bool dtr_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data); // Request to Set DTR -bool tuh_cdc_set_rts(uint8_t idx, bool rts_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data); // Request to Set RTS +// Request to Set DTR +TU_ATTR_ALWAYS_INLINE static inline bool tuh_cdc_set_dtr(uint8_t idx, bool dtr_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + cdc_line_control_state_t line_state = { .dtr = dtr_state }; + line_state.rts = tuh_cdc_get_rts(idx); + return tuh_cdc_set_control_line_state(idx, line_state.value, complete_cb, user_data); +} + +// Request to Set RTS +TU_ATTR_ALWAYS_INLINE static inline bool tuh_cdc_set_rts(uint8_t idx, bool rts_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + cdc_line_control_state_t line_state = { .rts = rts_state }; + line_state.dtr = tuh_cdc_get_dtr(idx); + return tuh_cdc_set_control_line_state(idx, line_state.value, complete_cb, user_data); +} // 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); -- cgit v1.3.1 From 221b5288e43feff140c695af4481b7815f1b56cd Mon Sep 17 00:00:00 2001 From: hathach Date: Thu, 19 Jun 2025 18:14:24 +0700 Subject: union ftdi/pl2303/acm data to save memory. --- src/class/cdc/cdc_host.c | 281 ++++++++++++++++++++++++----------------------- 1 file changed, 142 insertions(+), 139 deletions(-) (limited to 'src/class') diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index 80b01f928..2fe2c85bc 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -65,27 +65,30 @@ typedef struct { uint8_t ep_notif; uint8_t serial_drid; // Serial Driver ID bool mounted; // Enumeration is complete - cdc_acm_capability_t acm_capability; - TU_ATTR_ALIGNED(4) cdc_line_coding_t line_coding; // Baudrate, stop bits, parity, data width - TU_ATTR_ALIGNED(4) cdc_line_coding_t requested_line_coding; - // 1 byte padding - - cdc_line_control_state_t line_state; - cdc_line_control_state_t requested_line_state; + struct { + TU_ATTR_ALIGNED(4) cdc_line_coding_t coding; // Baudrate, stop bits, parity, data width + cdc_line_control_state_t control_state; // DTR, RTS + } line, requested_line; - tuh_xfer_cb_t user_control_cb; + tuh_xfer_cb_t user_complete_cb; // required since we handle request internally first #if CFG_TUH_CDC_FTDI || CFG_TUH_CDC_CP210X || CFG_TUH_CDC_CH34X tuh_xfer_cb_t requested_complete_cb; #endif - #if CFG_TUH_CDC_FTDI + union { + struct { + cdc_acm_capability_t capability; + } acm; + + #if CFG_TUH_CDC_FTDI ftdi_private_t ftdi; - #endif + #endif - #if CFG_TUH_CDC_PL2303 + #if CFG_TUH_CDC_PL2303 pl2303_private_t pl2303; - #endif + #endif + }; struct { tu_edpt_stream_t tx; @@ -376,8 +379,8 @@ static cdch_interface_t * make_new_itf(uint8_t daddr, tusb_desc_interface_t cons p_cdc->bInterfaceNumber = itf_desc->bInterfaceNumber; p_cdc->bInterfaceSubClass = itf_desc->bInterfaceSubClass; p_cdc->bInterfaceProtocol = itf_desc->bInterfaceProtocol; - p_cdc->line_coding = (cdc_line_coding_t) { 0, 0, 0, 0 }; - p_cdc->line_state.value = 0; + p_cdc->line.coding = (cdc_line_coding_t) { 0, 0, 0, 0 }; + p_cdc->line.control_state.value = 0; return p_cdc; } } @@ -430,7 +433,7 @@ bool tuh_cdc_mounted(uint8_t idx) { bool tuh_cdc_get_control_line_state_local(uint8_t idx, uint16_t* line_state) { cdch_interface_t * p_cdc = get_itf(idx); TU_VERIFY(p_cdc); - *line_state = p_cdc->line_state.value; + *line_state = p_cdc->line.control_state.value; return true; } @@ -438,10 +441,10 @@ bool tuh_cdc_get_line_coding_local(uint8_t idx, cdc_line_coding_t * line_coding) cdch_interface_t * p_cdc = get_itf(idx); TU_VERIFY(p_cdc); - *line_coding = p_cdc->line_coding; + *line_coding = p_cdc->line.coding; TU_LOG_P_CDC("get line coding %lu %u%c%s", - p_cdc->line_coding.bit_rate, p_cdc->line_coding.data_bits, - CDC_LINE_CODING_PARITY_CHAR(p_cdc->line_coding.parity), + p_cdc->line.coding.bit_rate, p_cdc->line.coding.data_bits, + CDC_LINE_CODING_PARITY_CHAR(p_cdc->line.coding.parity), CDC_LINE_CODING_STOP_BITS_TEXT(line_coding->stop_bits)); return true; @@ -533,7 +536,7 @@ static bool set_line_coding_sequence( // non-blocking // stage 1 set baudrate p_cdc->requested_complete_cb = complete_cb; // store complete_cb to be used in set_line_coding_stage1_complete() - p_cdc->user_control_cb = set_line_coding_stage1_complete; + p_cdc->user_complete_cb = set_line_coding_stage1_complete; return set_baudrate_request(p_cdc, internal_control_complete, user_data); } else { // blocking sequence @@ -549,7 +552,7 @@ static bool set_line_coding_sequence( TU_VERIFY(result == XFER_RESULT_SUCCESS); // overtake baudrate after successful request - p_cdc->line_coding.bit_rate = p_cdc->requested_line_coding.bit_rate; + p_cdc->line.coding.bit_rate = p_cdc->requested_line.coding.bit_rate; // stage 2 set data format result = XFER_RESULT_INVALID; @@ -577,7 +580,7 @@ static void set_line_coding_stage1_complete( if (xfer->result == XFER_RESULT_SUCCESS) { // stage 1 success, continue with stage 2 - p_cdc->user_control_cb = p_cdc->requested_complete_cb; + p_cdc->user_complete_cb = p_cdc->requested_complete_cb; set_data_format_request(p_cdc, internal_control_complete, xfer->user_data); } else { // stage 1 failed, notify user @@ -614,13 +617,13 @@ 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]; - p_cdc->requested_line_state.value = (uint8_t) line_state; - TU_LOG_P_CDC("set control line state dtr = %u rts = %u", p_cdc->requested_line_state.dtr, p_cdc->requested_line_state.rts); + p_cdc->requested_line.control_state.value = (uint8_t) line_state; + TU_LOG_P_CDC("set control line state dtr = %u rts = %u", p_cdc->requested_line.control_state.dtr, p_cdc->requested_line.control_state.rts); const bool ret = set_function_call(p_cdc, driver->set_control_line_state, complete_cb, user_data); if (ret && !complete_cb) { - p_cdc->line_state = p_cdc->requested_line_state; + p_cdc->line.control_state = p_cdc->requested_line.control_state; } return ret; } @@ -631,12 +634,12 @@ bool tuh_cdc_set_baudrate(uint8_t idx, uint32_t baudrate, tuh_xfer_cb_t complete TU_LOG_P_CDC("set baudrate %lu", baudrate); cdch_serial_driver_t const *driver = &serial_drivers[p_cdc->serial_drid]; - p_cdc->requested_line_coding.bit_rate = baudrate; + p_cdc->requested_line.coding.bit_rate = baudrate; bool ret = set_function_call(p_cdc, driver->set_baudrate, complete_cb, user_data); if (ret && !complete_cb) { - p_cdc->line_coding.bit_rate = baudrate; + p_cdc->line.coding.bit_rate = baudrate; } // TU_LOG_P_CDC_BOOL("set baudrate", ret); @@ -652,16 +655,16 @@ bool tuh_cdc_set_data_format(uint8_t idx, uint8_t stop_bits, uint8_t parity, uin CDC_LINE_CODING_STOP_BITS_TEXT(stop_bits)); cdch_serial_driver_t const *driver = &serial_drivers[p_cdc->serial_drid]; - 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; + 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; bool ret = set_function_call(p_cdc, driver->set_data_format, complete_cb, user_data); if (ret && !complete_cb) { - p_cdc->line_coding.stop_bits = stop_bits; - p_cdc->line_coding.parity = parity; - p_cdc->line_coding.data_bits = data_bits; + p_cdc->line.coding.stop_bits = stop_bits; + p_cdc->line.coding.parity = parity; + p_cdc->line.coding.data_bits = data_bits; } // TU_LOG_P_CDC_BOOL("set data format", ret); @@ -678,12 +681,12 @@ bool tuh_cdc_set_line_coding(uint8_t idx, cdc_line_coding_t const *line_coding, CDC_LINE_CODING_STOP_BITS_TEXT(line_coding->stop_bits)); cdch_serial_driver_t const *driver = &serial_drivers[p_cdc->serial_drid]; - p_cdc->requested_line_coding = *line_coding; + p_cdc->requested_line.coding = *line_coding; bool ret = set_function_call(p_cdc, driver->set_line_coding, complete_cb, user_data); if (ret && !complete_cb) { - p_cdc->line_coding = *line_coding; + p_cdc->line.coding = *line_coding; } // TU_LOG_P_CDC_BOOL("set line coding", ret); @@ -921,25 +924,25 @@ static void acm_internal_control_complete(tuh_xfer_t *xfer) { if (success) { switch (xfer->setup->bRequest) { case CDC_REQUEST_SET_CONTROL_LINE_STATE: - p_cdc->line_state = p_cdc->requested_line_state; + p_cdc->line.control_state = p_cdc->requested_line.control_state; break; case CDC_REQUEST_SET_LINE_CODING: - p_cdc->line_coding = p_cdc->requested_line_coding; + p_cdc->line.coding = p_cdc->requested_line.coding; break; default: break; } } - xfer->complete_cb = p_cdc->user_control_cb; + xfer->complete_cb = p_cdc->user_complete_cb; if (xfer->complete_cb) { xfer->complete_cb(xfer); } } static bool acm_set_control_line_state(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - TU_VERIFY(p_cdc->acm_capability.support_line_request); + TU_VERIFY(p_cdc->acm.capability.support_line_request); tusb_control_request_t const request = { .bmRequestType_bit = { @@ -948,12 +951,12 @@ static bool acm_set_control_line_state(cdch_interface_t *p_cdc, tuh_xfer_cb_t co .direction = TUSB_DIR_OUT }, .bRequest = CDC_REQUEST_SET_CONTROL_LINE_STATE, - .wValue = tu_htole16((uint16_t) p_cdc->requested_line_state.value), + .wValue = tu_htole16((uint16_t) p_cdc->requested_line.control_state.value), .wIndex = tu_htole16((uint16_t) p_cdc->bInterfaceNumber), .wLength = 0 }; - p_cdc->user_control_cb = complete_cb; + p_cdc->user_complete_cb = complete_cb; tuh_xfer_t xfer = { .daddr = p_cdc->daddr, @@ -970,9 +973,9 @@ static bool acm_set_control_line_state(cdch_interface_t *p_cdc, tuh_xfer_cb_t co } static bool acm_set_line_coding(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - TU_VERIFY(p_cdc->acm_capability.support_line_request); - TU_VERIFY((p_cdc->requested_line_coding.data_bits >= 5 && p_cdc->requested_line_coding.data_bits <= 8) || - p_cdc->requested_line_coding.data_bits == 16); + TU_VERIFY(p_cdc->acm.capability.support_line_request); + TU_VERIFY((p_cdc->requested_line.coding.data_bits >= 5 && p_cdc->requested_line.coding.data_bits <= 8) || + p_cdc->requested_line.coding.data_bits == 16); tusb_control_request_t const request = { .bmRequestType_bit = { @@ -988,9 +991,9 @@ static bool acm_set_line_coding(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_ // use usbh enum buf to hold line coding since user line_coding variable does not live long enough uint8_t *enum_buf = usbh_get_enum_buf(); - memcpy(enum_buf, &p_cdc->requested_line_coding, sizeof(cdc_line_coding_t)); + memcpy(enum_buf, &p_cdc->requested_line.coding, sizeof(cdc_line_coding_t)); - p_cdc->user_control_cb = complete_cb; + p_cdc->user_complete_cb = complete_cb; tuh_xfer_t xfer = { .daddr = p_cdc->daddr, @@ -1007,15 +1010,15 @@ static bool acm_set_line_coding(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_ } static bool acm_set_data_format(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - p_cdc->requested_line_coding.bit_rate = p_cdc->line_coding.bit_rate; + p_cdc->requested_line.coding.bit_rate = p_cdc->line.coding.bit_rate; return acm_set_line_coding(p_cdc, complete_cb, user_data); } static bool acm_set_baudrate(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - p_cdc->requested_line_coding.stop_bits = p_cdc->line_coding.stop_bits; - p_cdc->requested_line_coding.parity = p_cdc->line_coding.parity; - p_cdc->requested_line_coding.data_bits = p_cdc->line_coding.data_bits; + p_cdc->requested_line.coding.stop_bits = p_cdc->line.coding.stop_bits; + p_cdc->requested_line.coding.parity = p_cdc->line.coding.parity; + p_cdc->requested_line.coding.data_bits = p_cdc->line.coding.data_bits; return acm_set_line_coding(p_cdc, complete_cb, user_data); } @@ -1042,7 +1045,7 @@ static bool acm_open(uint8_t daddr, tusb_desc_interface_t const *itf_desc, uint1 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); @@ -1082,8 +1085,8 @@ static bool acm_process_set_config(tuh_xfer_t *xfer) { switch (state) { case CONFIG_ACM_SET_CONTROL_LINE_STATE: #ifdef CFG_TUH_CDC_LINE_CONTROL_ON_ENUM - if (p_cdc->acm_capability.support_line_request) { - p_cdc->requested_line_state.value = CFG_TUH_CDC_LINE_CONTROL_ON_ENUM; + if (p_cdc->acm.capability.support_line_request) { + p_cdc->requested_line.control_state.value = CFG_TUH_CDC_LINE_CONTROL_ON_ENUM; TU_ASSERT(acm_set_control_line_state(p_cdc, cdch_process_set_config, CONFIG_ACM_SET_LINE_CODING)); break; } @@ -1092,8 +1095,8 @@ static bool acm_process_set_config(tuh_xfer_t *xfer) { case CONFIG_ACM_SET_LINE_CODING: #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM - if (p_cdc->acm_capability.support_line_request) { - p_cdc->requested_line_coding = (cdc_line_coding_t) CFG_TUH_CDC_LINE_CODING_ON_ENUM; + if (p_cdc->acm.capability.support_line_request) { + p_cdc->requested_line.coding = (cdc_line_coding_t) CFG_TUH_CDC_LINE_CODING_ON_ENUM; TU_ASSERT(acm_set_line_coding(p_cdc, cdch_process_set_config, CONFIG_ACM_COMPLETE)); break; } @@ -1175,10 +1178,10 @@ static bool ftdi_change_speed(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb } static bool ftdi_set_data_request(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - TU_VERIFY(p_cdc->requested_line_coding.data_bits >= 7 && p_cdc->requested_line_coding.data_bits <= 8, 0); - uint16_t value = (uint16_t) ((p_cdc->requested_line_coding.data_bits & 0xfUL) | // data bit quantity is stored in bits 0-3 - (p_cdc->requested_line_coding.parity & 0x7UL) << 8 | // parity is stored in bits 8-10, same coding - (p_cdc->requested_line_coding.stop_bits & 0x3UL) << 11); // stop bits quantity is stored in bits 11-12, same coding + TU_VERIFY(p_cdc->requested_line.coding.data_bits >= 7 && p_cdc->requested_line.coding.data_bits <= 8, 0); + uint16_t value = (uint16_t) ((p_cdc->requested_line.coding.data_bits & 0xfUL) | // data bit quantity is stored in bits 0-3 + (p_cdc->requested_line.coding.parity & 0x7UL) << 8 | // parity is stored in bits 8-10, same coding + (p_cdc->requested_line.coding.stop_bits & 0x3UL) << 11); // stop bits quantity is stored in bits 11-12, same coding // not each FTDI supports 1.5 stop bits return ftdi_set_request(p_cdc, FTDI_SIO_SET_DATA_REQUEST, FTDI_SIO_SET_DATA_REQUEST_TYPE, @@ -1186,8 +1189,8 @@ static bool ftdi_set_data_request(cdch_interface_t *p_cdc, tuh_xfer_cb_t complet } static inline bool ftdi_update_mctrl(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - uint16_t value = (uint16_t) ((p_cdc->requested_line_state.dtr ? FTDI_SIO_SET_DTR_HIGH : FTDI_SIO_SET_DTR_LOW) | - (p_cdc->requested_line_state.rts ? FTDI_SIO_SET_RTS_HIGH : FTDI_SIO_SET_RTS_LOW)); + uint16_t value = (uint16_t) ((p_cdc->requested_line.control_state.dtr ? FTDI_SIO_SET_DTR_HIGH : FTDI_SIO_SET_DTR_LOW) | + (p_cdc->requested_line.control_state.rts ? FTDI_SIO_SET_RTS_HIGH : FTDI_SIO_SET_RTS_LOW)); return ftdi_set_request(p_cdc, FTDI_SIO_SET_MODEM_CTRL_REQUEST, FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE, value, p_cdc->ftdi.channel, complete_cb, user_data); @@ -1206,35 +1209,35 @@ static void ftdi_internal_control_complete(tuh_xfer_t *xfer) { if (success) { if (xfer->setup->bRequest == FTDI_SIO_SET_MODEM_CTRL_REQUEST && xfer->setup->bmRequestType == FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE ) { - p_cdc->line_state = p_cdc->requested_line_state; + p_cdc->line.control_state = p_cdc->requested_line.control_state; } if (xfer->setup->bRequest == FTDI_SIO_SET_DATA_REQUEST && xfer->setup->bmRequestType == FTDI_SIO_SET_DATA_REQUEST_TYPE ) { - 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; + 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; } if (xfer->setup->bRequest == FTDI_SIO_SET_BAUDRATE_REQUEST && xfer->setup->bmRequestType == FTDI_SIO_SET_BAUDRATE_REQUEST_TYPE ) { - p_cdc->line_coding.bit_rate = p_cdc->requested_line_coding.bit_rate; + p_cdc->line.coding.bit_rate = p_cdc->requested_line.coding.bit_rate; } } - xfer->complete_cb = p_cdc->user_control_cb; + xfer->complete_cb = p_cdc->user_complete_cb; if (xfer->complete_cb) { xfer->complete_cb(xfer); } } static bool ftdi_set_data_format(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - p_cdc->user_control_cb = complete_cb; + p_cdc->user_complete_cb = complete_cb; TU_ASSERT(ftdi_set_data_request(p_cdc, complete_cb ? ftdi_internal_control_complete : NULL, user_data)); return true; } static bool ftdi_set_baudrate(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - p_cdc->user_control_cb = complete_cb; + p_cdc->user_complete_cb = complete_cb; TU_ASSERT(ftdi_change_speed(p_cdc, complete_cb ? ftdi_internal_control_complete : NULL, user_data)); return true; @@ -1261,7 +1264,7 @@ static bool ftdi_set_line_coding(cdch_interface_t * p_cdc, tuh_xfer_cb_t complet } static bool ftdi_set_modem_ctrl(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - p_cdc->user_control_cb = complete_cb; + p_cdc->user_complete_cb = complete_cb; TU_ASSERT(ftdi_update_mctrl(p_cdc, complete_cb ? ftdi_internal_control_complete : NULL, user_data)); return true; @@ -1339,15 +1342,15 @@ static bool ftdi_proccess_set_config(tuh_xfer_t *xfer) { // from here sequence overtaken from Linux Kernel function ftdi_open() case CONFIG_FTDI_SIO_RESET: - p_cdc->user_control_cb = cdch_process_set_config; + p_cdc->user_complete_cb = cdch_process_set_config; TU_ASSERT(ftdi_sio_reset(p_cdc, cdch_process_set_config, CONFIG_FTDI_SET_DATA)); break; // from here sequence overtaken from Linux Kernel function ftdi_set_termios() case CONFIG_FTDI_SET_DATA: #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM - p_cdc->requested_line_coding = (cdc_line_coding_t) CFG_TUH_CDC_LINE_CODING_ON_ENUM; - p_cdc->user_control_cb = cdch_process_set_config; + p_cdc->requested_line.coding = (cdc_line_coding_t) CFG_TUH_CDC_LINE_CODING_ON_ENUM; + p_cdc->user_complete_cb = cdch_process_set_config; TU_ASSERT(ftdi_set_data_request(p_cdc, ftdi_internal_control_complete, CONFIG_FTDI_SET_BAUDRATE)); break; #else @@ -1356,7 +1359,7 @@ static bool ftdi_proccess_set_config(tuh_xfer_t *xfer) { case CONFIG_FTDI_SET_BAUDRATE: #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM - p_cdc->user_control_cb = cdch_process_set_config; + p_cdc->user_complete_cb = cdch_process_set_config; TU_ASSERT(ftdi_change_speed(p_cdc, ftdi_internal_control_complete, CONFIG_FTDI_FLOW_CONTROL)); break; #else @@ -1371,8 +1374,8 @@ static bool ftdi_proccess_set_config(tuh_xfer_t *xfer) { case CONFIG_FTDI_MODEM_CTRL: #ifdef CFG_TUH_CDC_LINE_CONTROL_ON_ENUM - p_cdc->requested_line_state.value = CFG_TUH_CDC_LINE_CONTROL_ON_ENUM; - p_cdc->user_control_cb = cdch_process_set_config; + p_cdc->requested_line.control_state.value = CFG_TUH_CDC_LINE_CONTROL_ON_ENUM; + p_cdc->user_complete_cb = cdch_process_set_config; TU_ASSERT(ftdi_update_mctrl(p_cdc, ftdi_internal_control_complete, CONFIG_FTDI_COMPLETE)); break; #else @@ -1529,7 +1532,7 @@ static inline uint32_t ftdi_2232h_baud_to_divisor(uint32_t baud) { } static inline uint32_t ftdi_get_divisor(cdch_interface_t *p_cdc) { - uint32_t baud = p_cdc->requested_line_coding.bit_rate; + uint32_t baud = p_cdc->requested_line.coding.bit_rate; uint32_t div_value = 0; TU_VERIFY(baud); @@ -1661,16 +1664,16 @@ static inline bool cp210x_ifc_enable(cdch_interface_t *p_cdc, uint16_t enabled, static bool cp210x_set_baudrate_request(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { // Not every baud rate is supported. See datasheets and AN205 "CP210x Baud Rate Support" - uint32_t baud_le = tu_htole32(p_cdc->requested_line_coding.bit_rate); + uint32_t baud_le = tu_htole32(p_cdc->requested_line.coding.bit_rate); return cp210x_set_request(p_cdc, CP210X_SET_BAUDRATE, 0, (uint8_t *) &baud_le, 4, complete_cb, user_data); } static bool cp210x_set_line_ctl(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - TU_VERIFY(p_cdc->requested_line_coding.data_bits >= 5 && p_cdc->requested_line_coding.data_bits <= 8, 0); - uint16_t lcr = (uint16_t) ((p_cdc->requested_line_coding.data_bits & 0xfUL) << 8 | // data bit quantity is stored in bits 8-11 - (p_cdc->requested_line_coding.parity & 0xfUL) << 4 | // parity is stored in bits 4-7, same coding - (p_cdc->requested_line_coding.stop_bits & 0xfUL)); // parity is stored in bits 0-3, same coding + TU_VERIFY(p_cdc->requested_line.coding.data_bits >= 5 && p_cdc->requested_line.coding.data_bits <= 8, 0); + uint16_t lcr = (uint16_t) ((p_cdc->requested_line.coding.data_bits & 0xfUL) << 8 | // data bit quantity is stored in bits 8-11 + (p_cdc->requested_line.coding.parity & 0xfUL) << 4 | // parity is stored in bits 4-7, same coding + (p_cdc->requested_line.coding.stop_bits & 0xfUL)); // parity is stored in bits 0-3, same coding return cp210x_set_request(p_cdc, CP210X_SET_LINE_CTL, lcr, NULL, 0, complete_cb, user_data); } @@ -1679,7 +1682,7 @@ static inline bool cp210x_set_mhs(cdch_interface_t *p_cdc, tuh_xfer_cb_t complet // CP210x has the same bit coding return cp210x_set_request(p_cdc, CP210X_SET_MHS, (uint16_t) (CP210X_CONTROL_WRITE_DTR | CP210X_CONTROL_WRITE_RTS | - p_cdc->requested_line_state.value), + p_cdc->requested_line.control_state.value), NULL, 0, complete_cb, user_data); } @@ -1697,38 +1700,38 @@ static void cp210x_internal_control_complete(tuh_xfer_t *xfer) { if (success) { switch (xfer->setup->bRequest) { case CP210X_SET_MHS: - p_cdc->line_state = p_cdc->requested_line_state; + p_cdc->line.control_state = p_cdc->requested_line.control_state; break; case CP210X_SET_LINE_CTL: - 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; + 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; case CP210X_SET_BAUDRATE: - p_cdc->line_coding.bit_rate = p_cdc->requested_line_coding.bit_rate; + p_cdc->line.coding.bit_rate = p_cdc->requested_line.coding.bit_rate; break; default: break; } } - xfer->complete_cb = p_cdc->user_control_cb; + xfer->complete_cb = p_cdc->user_complete_cb; if (xfer->complete_cb) { xfer->complete_cb(xfer); } } static bool cp210x_set_baudrate(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - p_cdc->user_control_cb = complete_cb; + p_cdc->user_complete_cb = complete_cb; TU_ASSERT(cp210x_set_baudrate_request(p_cdc, complete_cb ? cp210x_internal_control_complete : NULL, user_data)); return true; } static bool cp210x_set_data_format(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - p_cdc->user_control_cb = complete_cb; + p_cdc->user_complete_cb = complete_cb; TU_ASSERT(cp210x_set_line_ctl(p_cdc, complete_cb ? cp210x_internal_control_complete : NULL, user_data)); return true; @@ -1752,7 +1755,7 @@ static bool cp210x_set_line_coding(cdch_interface_t *p_cdc, tuh_xfer_cb_t comple } static bool cp210x_set_modem_ctrl(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - p_cdc->user_control_cb = complete_cb; + p_cdc->user_complete_cb = complete_cb; TU_ASSERT(cp210x_set_mhs(p_cdc, complete_cb ? cp210x_internal_control_complete : NULL, user_data)); return true; @@ -1799,8 +1802,8 @@ static bool cp210x_process_set_config(tuh_xfer_t *xfer) { case CONFIG_CP210X_SET_BAUDRATE_REQUEST: #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM - p_cdc->requested_line_coding = (cdc_line_coding_t) CFG_TUH_CDC_LINE_CODING_ON_ENUM; - p_cdc->user_control_cb = cdch_process_set_config; + p_cdc->requested_line.coding = (cdc_line_coding_t) CFG_TUH_CDC_LINE_CODING_ON_ENUM; + p_cdc->user_complete_cb = cdch_process_set_config; TU_ASSERT(cp210x_set_baudrate_request(p_cdc, cp210x_internal_control_complete, CONFIG_CP210X_SET_LINE_CTL)); break; #else @@ -1809,7 +1812,7 @@ static bool cp210x_process_set_config(tuh_xfer_t *xfer) { case CONFIG_CP210X_SET_LINE_CTL: #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM - p_cdc->user_control_cb = cdch_process_set_config; + p_cdc->user_complete_cb = cdch_process_set_config; TU_ASSERT(cp210x_set_line_ctl(p_cdc, cp210x_internal_control_complete, CONFIG_CP210X_SET_DTR_RTS)); break; #else @@ -1818,8 +1821,8 @@ static bool cp210x_process_set_config(tuh_xfer_t *xfer) { case CONFIG_CP210X_SET_DTR_RTS: #ifdef CFG_TUH_CDC_LINE_CONTROL_ON_ENUM - p_cdc->requested_line_state.value = CFG_TUH_CDC_LINE_CONTROL_ON_ENUM; - p_cdc->user_control_cb = cdch_process_set_config; + p_cdc->requested_line.control_state.value = CFG_TUH_CDC_LINE_CONTROL_ON_ENUM; + p_cdc->user_complete_cb = cdch_process_set_config; TU_ASSERT(cp210x_set_mhs(p_cdc, cp210x_internal_control_complete, CONFIG_CP210X_COMPLETE)); break; #else @@ -1923,8 +1926,8 @@ static bool ch34x_write_reg_baudrate(cdch_interface_t *p_cdc, tuh_xfer_cb_t comp static bool ch34x_modem_ctrl_request(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { // CH34x signals are inverted - uint8_t control = ~((p_cdc->requested_line_state.rts ? CH34X_BIT_RTS : 0) | - (p_cdc->requested_line_state.dtr ? CH34X_BIT_DTR : 0)); + uint8_t control = ~((p_cdc->requested_line.control_state.rts ? CH34X_BIT_RTS : 0) | + (p_cdc->requested_line.control_state.dtr ? CH34X_BIT_DTR : 0)); return ch34x_control_out(p_cdc, CH34X_REQ_MODEM_CTRL, control, 0, complete_cb, user_data); } @@ -1947,14 +1950,14 @@ static void ch34x_internal_control_complete(tuh_xfer_t *xfer) { switch (tu_le16toh(xfer->setup->wValue)) { case CH34X_REG16_DIVISOR_PRESCALER: // baudrate - p_cdc->line_coding.bit_rate = p_cdc->requested_line_coding.bit_rate; + 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; + 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; @@ -1962,28 +1965,28 @@ static void ch34x_internal_control_complete(tuh_xfer_t *xfer) { break; case CH34X_REQ_MODEM_CTRL: - p_cdc->line_state = p_cdc->requested_line_state; + p_cdc->line.control_state = p_cdc->requested_line.control_state; break; default: break; } } - xfer->complete_cb = p_cdc->user_control_cb; + xfer->complete_cb = p_cdc->user_complete_cb; if (xfer->complete_cb) { xfer->complete_cb(xfer); } } static bool ch34x_set_data_format(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - p_cdc->user_control_cb = complete_cb; + p_cdc->user_complete_cb = complete_cb; TU_ASSERT(ch34x_write_reg_data_format(p_cdc, complete_cb ? ch34x_internal_control_complete : NULL, user_data)); return true; } static bool ch34x_set_baudrate(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - p_cdc->user_control_cb = complete_cb; + p_cdc->user_complete_cb = complete_cb; TU_ASSERT(ch34x_write_reg_baudrate(p_cdc, complete_cb ? ch34x_internal_control_complete : NULL, user_data)); return true; @@ -2008,7 +2011,7 @@ static bool ch34x_set_line_coding(cdch_interface_t * p_cdc, tuh_xfer_cb_t comple } static bool ch34x_set_modem_ctrl(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - p_cdc->user_control_cb = complete_cb; + p_cdc->user_complete_cb = complete_cb; TU_ASSERT(ch34x_modem_ctrl_request(p_cdc, complete_cb ? ch34x_internal_control_complete : NULL, user_data)); return true; @@ -2073,7 +2076,7 @@ static bool ch34x_process_set_config(tuh_xfer_t *xfer) { // see drivers from WCH vendor, Linux kernel and FreeBSD if (version >= 0x30) { // init CH34x with line coding - p_cdc->requested_line_coding = (cdc_line_coding_t) CFG_TUH_CDC_LINE_CODING_ON_ENUM_CH34X; + p_cdc->requested_line.coding = (cdc_line_coding_t) CFG_TUH_CDC_LINE_CODING_ON_ENUM_CH34X; uint16_t const div_ps = ch34x_get_divisor_prescaler(p_cdc); uint8_t const lcr = ch34x_get_lcr(p_cdc); TU_ASSERT(div_ps != 0 && lcr != 0); @@ -2085,7 +2088,7 @@ static bool ch34x_process_set_config(tuh_xfer_t *xfer) { case CONFIG_CH34X_SPECIAL_REG_WRITE: // 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; + 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, cdch_process_set_config, CONFIG_CH34X_FLOW_CONTROL)); break; @@ -2098,8 +2101,8 @@ static bool ch34x_process_set_config(tuh_xfer_t *xfer) { case CONFIG_CH34X_MODEM_CONTROL: #ifdef CFG_TUH_CDC_LINE_CONTROL_ON_ENUM - p_cdc->requested_line_state.value = CFG_TUH_CDC_LINE_CONTROL_ON_ENUM; - p_cdc->user_control_cb = cdch_process_set_config; + p_cdc->requested_line.control_state.value = CFG_TUH_CDC_LINE_CONTROL_ON_ENUM; + p_cdc->user_complete_cb = cdch_process_set_config; TU_ASSERT(ch34x_modem_ctrl_request(p_cdc, ch34x_internal_control_complete, CONFIG_CH34X_COMPLETE)); break; #else @@ -2121,7 +2124,7 @@ static bool ch34x_process_set_config(tuh_xfer_t *xfer) { // calculate divisor and prescaler for baudrate, return it as 16-bit combined value static uint16_t ch34x_get_divisor_prescaler(cdch_interface_t *p_cdc) { - uint32_t const baval = p_cdc->requested_line_coding.bit_rate; + uint32_t const baval = p_cdc->requested_line.coding.bit_rate; uint8_t a; uint8_t b; uint32_t c; @@ -2171,9 +2174,9 @@ static uint16_t ch34x_get_divisor_prescaler(cdch_interface_t *p_cdc) { // calculate lcr value from data coding static uint8_t ch34x_get_lcr(cdch_interface_t *p_cdc) { - uint8_t const stop_bits = p_cdc->requested_line_coding.stop_bits; - uint8_t const parity = p_cdc->requested_line_coding.parity; - uint8_t const data_bits = p_cdc->requested_line_coding.data_bits; + uint8_t const stop_bits = p_cdc->requested_line.coding.stop_bits; + uint8_t const parity = p_cdc->requested_line.coding.parity; + uint8_t const data_bits = p_cdc->requested_line.coding.data_bits; uint8_t lcr = CH34X_LCR_ENABLE_RX | CH34X_LCR_ENABLE_TX; TU_VERIFY(data_bits >= 5 && data_bits <= 8); @@ -2276,7 +2279,7 @@ static inline bool pl2303_supports_hx_status(cdch_interface_t *p_cdc, tuh_xfer_c static inline bool pl2303_set_control_lines(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { // PL2303 has the same bit coding return pl2303_set_request(p_cdc, PL2303_SET_CONTROL_REQUEST, PL2303_SET_CONTROL_REQUEST_TYPE, - p_cdc->requested_line_state.value, 0, NULL, 0, complete_cb, user_data); + p_cdc->requested_line.control_state.value, 0, NULL, 0, complete_cb, user_data); } //static bool pl2303_get_line_request(cdch_interface_t * p_cdc, uint8_t buf[PL2303_LINE_CODING_BUFSIZE]) @@ -2292,14 +2295,14 @@ static bool pl2303_set_line_request(cdch_interface_t *p_cdc, tuh_xfer_cb_t compl * even to the same values as before. Thus we actually need to filter * in this specific case. */ - TU_VERIFY(p_cdc->requested_line_coding.data_bits != p_cdc->line_coding.data_bits || - p_cdc->requested_line_coding.stop_bits != p_cdc->line_coding.stop_bits || - p_cdc->requested_line_coding.parity != p_cdc->line_coding.parity || - p_cdc->requested_line_coding.bit_rate != p_cdc->line_coding.bit_rate ); + TU_VERIFY(p_cdc->requested_line.coding.data_bits != p_cdc->line.coding.data_bits || + p_cdc->requested_line.coding.stop_bits != p_cdc->line.coding.stop_bits || + p_cdc->requested_line.coding.parity != p_cdc->line.coding.parity || + p_cdc->requested_line.coding.bit_rate != p_cdc->line.coding.bit_rate ); /* For reference buf[6] data bits value */ - TU_VERIFY(p_cdc->requested_line_coding.data_bits >= 5 && p_cdc->requested_line_coding.data_bits <= 8, 0); - buf[6] = p_cdc->requested_line_coding.data_bits; + TU_VERIFY(p_cdc->requested_line.coding.data_bits >= 5 && p_cdc->requested_line.coding.data_bits <= 8, 0); + buf[6] = p_cdc->requested_line.coding.data_bits; /* For reference buf[0]:buf[3] baud rate value */ TU_VERIFY(pl2303_encode_baud_rate(p_cdc, &buf[0])); @@ -2307,14 +2310,14 @@ static bool pl2303_set_line_request(cdch_interface_t *p_cdc, tuh_xfer_cb_t compl /* For reference buf[4]=0 is 1 stop bits */ /* For reference buf[4]=1 is 1.5 stop bits */ /* For reference buf[4]=2 is 2 stop bits */ - buf[4] = p_cdc->requested_line_coding.stop_bits; // PL2303 has the same coding + buf[4] = p_cdc->requested_line.coding.stop_bits; // PL2303 has the same coding /* For reference buf[5]=0 is none parity */ /* For reference buf[5]=1 is odd parity */ /* For reference buf[5]=2 is even parity */ /* For reference buf[5]=3 is mark parity */ /* For reference buf[5]=4 is space parity */ - buf[5] = p_cdc->requested_line_coding.parity; // PL2303 has the same coding + buf[5] = p_cdc->requested_line.coding.parity; // PL2303 has the same coding return pl2303_set_request(p_cdc, PL2303_SET_LINE_REQUEST, PL2303_SET_LINE_REQUEST_TYPE, 0, 0, buf, PL2303_LINE_CODING_BUFSIZE, complete_cb, user_data); @@ -2350,45 +2353,45 @@ static void pl2303_internal_control_complete(tuh_xfer_t *xfer) { if (success) { if (xfer->setup->bRequest == PL2303_SET_LINE_REQUEST && xfer->setup->bmRequestType == PL2303_SET_LINE_REQUEST_TYPE) { - p_cdc->line_coding = p_cdc->requested_line_coding; + p_cdc->line.coding = p_cdc->requested_line.coding; } if (xfer->setup->bRequest == PL2303_SET_CONTROL_REQUEST && xfer->setup->bmRequestType == PL2303_SET_CONTROL_REQUEST_TYPE) { - p_cdc->line_state = p_cdc->requested_line_state; + p_cdc->line.control_state = p_cdc->requested_line.control_state; } } - xfer->complete_cb = p_cdc->user_control_cb; + xfer->complete_cb = p_cdc->user_complete_cb; if (xfer->complete_cb) { xfer->complete_cb(xfer); } } static bool pl2303_set_line_coding(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - p_cdc->user_control_cb = complete_cb; + p_cdc->user_complete_cb = complete_cb; TU_ASSERT(pl2303_set_line_request(p_cdc, complete_cb ? pl2303_internal_control_complete : NULL, user_data)); return true; } static bool pl2303_set_data_format(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - p_cdc->requested_line_coding.bit_rate = p_cdc->line_coding.bit_rate; - p_cdc->user_control_cb = complete_cb; + p_cdc->requested_line.coding.bit_rate = p_cdc->line.coding.bit_rate; + p_cdc->user_complete_cb = complete_cb; TU_ASSERT(pl2303_set_line_request(p_cdc, complete_cb ? pl2303_internal_control_complete : NULL, user_data)); return true; } static bool pl2303_set_baudrate(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - p_cdc->requested_line_coding.stop_bits = p_cdc->line_coding.stop_bits; - p_cdc->requested_line_coding.parity = p_cdc->line_coding.parity; - p_cdc->requested_line_coding.data_bits = p_cdc->line_coding.data_bits; - p_cdc->user_control_cb = complete_cb; + p_cdc->requested_line.coding.stop_bits = p_cdc->line.coding.stop_bits; + p_cdc->requested_line.coding.parity = p_cdc->line.coding.parity; + p_cdc->requested_line.coding.data_bits = p_cdc->line.coding.data_bits; + p_cdc->user_complete_cb = complete_cb; TU_ASSERT(pl2303_set_line_request(p_cdc, complete_cb ? pl2303_internal_control_complete : NULL, user_data)); return true; } static bool pl2303_set_modem_ctrl(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { // PL2303 has the same bit coding - p_cdc->user_control_cb = complete_cb; + p_cdc->user_complete_cb = complete_cb; TU_ASSERT(pl2303_set_control_lines(p_cdc, complete_cb ? pl2303_internal_control_complete : NULL, user_data)); return true; } @@ -2458,7 +2461,7 @@ static bool pl2303_process_set_config(tuh_xfer_t *xfer) { switch (state) { // from here sequence overtaken from Linux Kernel function pl2303_startup() case CONFIG_PL2303_DETECT_TYPE: - p_cdc->user_control_cb = cdch_process_set_config;// set once for whole process config + p_cdc->user_complete_cb = cdch_process_set_config;// set once for whole process config // get type and quirks (step 1) type = pl2303_detect_type(p_cdc, 1); TU_ASSERT(type != PL2303_TYPE_UNKNOWN); @@ -2606,7 +2609,7 @@ static bool pl2303_process_set_config(tuh_xfer_t *xfer) { // unnecessary pl2303_get_line_request() is skipped due to a stall case CONFIG_PL2303_LINE_CODING: #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM - p_cdc->requested_line_coding = (cdc_line_coding_t) CFG_TUH_CDC_LINE_CODING_ON_ENUM; + p_cdc->requested_line.coding = (cdc_line_coding_t) CFG_TUH_CDC_LINE_CODING_ON_ENUM; TU_ASSERT(pl2303_set_line_request(p_cdc, pl2303_internal_control_complete, CONFIG_PL2303_MODEM_CONTROL)); break; #else @@ -2615,7 +2618,7 @@ static bool pl2303_process_set_config(tuh_xfer_t *xfer) { case CONFIG_PL2303_MODEM_CONTROL: #ifdef CFG_TUH_CDC_LINE_CONTROL_ON_ENUM - p_cdc->requested_line_state.value = CFG_TUH_CDC_LINE_CONTROL_ON_ENUM; + p_cdc->requested_line.control_state.value = CFG_TUH_CDC_LINE_CONTROL_ON_ENUM; TU_ASSERT(pl2303_set_control_lines(p_cdc, pl2303_internal_control_complete, CONFIG_PL2303_COMPLETE)); break; #else @@ -2861,7 +2864,7 @@ static uint32_t pl2303_encode_baud_rate_divisor_alt(uint8_t buf[PL2303_LINE_CODI } static bool pl2303_encode_baud_rate(cdch_interface_t *p_cdc, uint8_t buf[PL2303_LINE_CODING_BAUDRATE_BUFSIZE]) { - uint32_t baud = p_cdc->requested_line_coding.bit_rate; + uint32_t baud = p_cdc->requested_line.coding.bit_rate; uint32_t baud_sup; const pl2303_type_data_t* type_data = &pl2303_type_data[p_cdc->pl2303.type]; -- cgit v1.3.1 From adf6cbfe03523cd8f7e23cb7f2edbb4304a6cd89 Mon Sep 17 00:00:00 2001 From: hathach Date: Fri, 20 Jun 2025 12:52:34 +0700 Subject: cdch clean up and refactor, add explicit sync() API --- examples/host/cdc_msc_hid/src/cdc_app.c | 2 +- src/class/cdc/cdc_host.c | 172 +++++++++++++------------------- src/class/cdc/cdc_host.h | 48 +++++++-- src/class/cdc/serial/pl2303.h | 33 +++--- 4 files changed, 127 insertions(+), 128 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 6f4433f22..2fa9a8560 100644 --- a/examples/host/cdc_msc_hid/src/cdc_app.c +++ b/examples/host/cdc_msc_hid/src/cdc_app.c @@ -89,7 +89,7 @@ void tuh_cdc_mount_cb(uint8_t idx) { // 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)) { + if (tuh_cdc_get_line_coding_local(idx, &line_coding)) { 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); } diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index 2fe2c85bc..50d0a020d 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -42,15 +42,15 @@ // 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 + #define CFG_TUH_CDC_LOG_LEVEL 1 #endif -#define TU_LOG_DRV(...) TU_LOG(CFG_TUH_CDC_LOG_LEVEL, __VA_ARGS__) -#define TU_LOG_CDC(TXT,DADDR,ITF_NUM,NAME,...) TU_LOG_DRV("[:%u:%u] CDCh %s " TXT "\r\n", \ - DADDR, ITF_NUM, NAME, ##__VA_ARGS__) -#define TU_LOG_P_CDC(TXT,...) TU_LOG_CDC(TXT, p_cdc->daddr, p_cdc->bInterfaceNumber, \ - serial_drivers[p_cdc->serial_drid].name, ##__VA_ARGS__) -#define TU_LOG_P_CDC_BOOL(TXT,VAL) TU_LOG_P_CDC(TXT " " #VAL " = %d", VAL) +#define TU_LOG_DRV(...) TU_LOG(CFG_TUH_CDC_LOG_LEVEL, __VA_ARGS__) +#define TU_LOG_CDC(_cdc, _format, ...) TU_LOG_DRV("[:%u:%u] CDCh %s " _format "\r\n", _cdc->daddr, _cdc->bInterfaceNumber, \ + serial_drivers[_cdc->serial_drid].name, ##__VA_ARGS__) + +// Driver that need to set line coding in two stages: baudrate then data format. +#define DRIVER_2STAGE_SET_LINE_CODING (CFG_TUH_CDC_FTDI || CFG_TUH_CDC_CP210X || CFG_TUH_CDC_CH34X) //--------------------------------------------------------------------+ // Host CDC Interface @@ -72,7 +72,8 @@ typedef struct { } line, requested_line; tuh_xfer_cb_t user_complete_cb; // required since we handle request internally first - #if CFG_TUH_CDC_FTDI || CFG_TUH_CDC_CP210X || CFG_TUH_CDC_CH34X + + #if DRIVER_2STAGE_SET_LINE_CODING tuh_xfer_cb_t requested_complete_cb; #endif @@ -197,49 +198,57 @@ enum { SERIAL_DRIVER_COUNT }; +typedef bool (*serial_driver_func_t)(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); + typedef struct { uint16_t const (*vid_pid_list)[2]; uint16_t const vid_pid_count; + bool is_2stage_line_coding; // true if driver requires to set baudrate then data format separately + bool (*const open)(uint8_t daddr, const tusb_desc_interface_t * itf_desc, uint16_t max_len); bool (*const process_set_config)(tuh_xfer_t * xfer); - bool (*const set_control_line_state)(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); - bool (*const set_baudrate)(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); - bool (*const set_data_format)(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); - bool (*const set_line_coding)(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); + const serial_driver_func_t set_control_line_state; + const serial_driver_func_t set_baudrate; + const serial_driver_func_t set_data_format; + const serial_driver_func_t set_line_coding; #if CFG_TUSB_DEBUG && CFG_TUSB_DEBUG >= CFG_TUH_CDC_LOG_LEVEL - uint8_t const * name; + const char * name; #endif } cdch_serial_driver_t; +#if CFG_TUSB_DEBUG >= CFG_TUH_CDC_LOG_LEVEL + #define DRIVER_NAME_DECLARE(_str) .name = _str +#else + #define DRIVER_NAME_DECLARE(_str) +#endif + // Note driver list must be in the same order as SERIAL_DRIVER enum static const cdch_serial_driver_t serial_drivers[] = { { .vid_pid_list = NULL, .vid_pid_count = 0, + .is_2stage_line_coding = false, .open = acm_open, .process_set_config = acm_process_set_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, - #if CFG_TUSB_DEBUG && CFG_TUSB_DEBUG >= CFG_TUH_CDC_LOG_LEVEL - .name = (uint8_t const *) "ACM" - #endif + DRIVER_NAME_DECLARE("ACM") }, #if CFG_TUH_CDC_FTDI { .vid_pid_list = ftdi_vid_pid_list, .vid_pid_count = TU_ARRAY_SIZE(ftdi_vid_pid_list), + .is_2stage_line_coding = true, .open = ftdi_open, .process_set_config = ftdi_proccess_set_config, .set_control_line_state = ftdi_set_modem_ctrl, .set_baudrate = ftdi_set_baudrate, .set_data_format = ftdi_set_data_format, .set_line_coding = ftdi_set_line_coding, - #if CFG_TUSB_DEBUG && CFG_TUSB_DEBUG >= CFG_TUH_CDC_LOG_LEVEL - .name = (uint8_t const *) "FTDI" - #endif + DRIVER_NAME_DECLARE("FTDI") }, #endif @@ -247,15 +256,14 @@ static const cdch_serial_driver_t serial_drivers[] = { { .vid_pid_list = cp210x_vid_pid_list, .vid_pid_count = TU_ARRAY_SIZE(cp210x_vid_pid_list), + .is_2stage_line_coding = true, .open = cp210x_open, .process_set_config = cp210x_process_set_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, - #if CFG_TUSB_DEBUG && CFG_TUSB_DEBUG >= CFG_TUH_CDC_LOG_LEVEL - .name = (uint8_t const *) "CP210x" - #endif + DRIVER_NAME_DECLARE("CP210x") }, #endif @@ -263,15 +271,14 @@ static const cdch_serial_driver_t serial_drivers[] = { { .vid_pid_list = ch34x_vid_pid_list, .vid_pid_count = TU_ARRAY_SIZE(ch34x_vid_pid_list), + .is_2stage_line_coding = true, .open = ch34x_open, .process_set_config = ch34x_process_set_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, - #if CFG_TUSB_DEBUG && CFG_TUSB_DEBUG >= CFG_TUH_CDC_LOG_LEVEL - .name = (uint8_t const *) "CH34x" - #endif + DRIVER_NAME_DECLARE("CH34x") }, #endif @@ -279,15 +286,14 @@ static const cdch_serial_driver_t serial_drivers[] = { { .vid_pid_list = pl2303_vid_pid_list, .vid_pid_count = TU_ARRAY_SIZE(pl2303_vid_pid_list), + .is_2stage_line_coding = false, .open = pl2303_open, .process_set_config = pl2303_process_set_config, .set_control_line_state = pl2303_set_modem_ctrl, .set_baudrate = pl2303_set_baudrate, .set_data_format = pl2303_set_data_format, .set_line_coding = pl2303_set_line_coding, - #if CFG_TUSB_DEBUG && CFG_TUSB_DEBUG >= CFG_TUH_CDC_LOG_LEVEL - .name = (uint8_t const *) "PL2303" - #endif + DRIVER_NAME_DECLARE("PL2303") } #endif }; @@ -440,13 +446,7 @@ bool tuh_cdc_get_control_line_state_local(uint8_t idx, uint16_t* line_state) { bool tuh_cdc_get_line_coding_local(uint8_t idx, cdc_line_coding_t * line_coding) { cdch_interface_t * p_cdc = get_itf(idx); TU_VERIFY(p_cdc); - *line_coding = p_cdc->line.coding; - TU_LOG_P_CDC("get line coding %lu %u%c%s", - p_cdc->line.coding.bit_rate, p_cdc->line.coding.data_bits, - CDC_LINE_CODING_PARITY_CHAR(p_cdc->line.coding.parity), - CDC_LINE_CODING_STOP_BITS_TEXT(line_coding->stop_bits)); - return true; } @@ -520,29 +520,27 @@ bool tuh_cdc_read_clear (uint8_t idx) { // Control Endpoint API //--------------------------------------------------------------------+ +#if DRIVER_2STAGE_SET_LINE_CODING + // set line coding using sequence with 2 stages: set baudrate (stage1) + set data format (stage2) static bool set_line_coding_sequence( cdch_interface_t * p_cdc, - // control request function to set baudrate - bool (*set_baudrate_request)(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data), - // control request function to set data format - bool (*set_data_format_request)(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data), - // function to be called after stage 1 completed - void (*set_line_coding_stage1_complete)(tuh_xfer_t * xfer), - // control complete function to be called after request - void (*internal_control_complete)(tuh_xfer_t * xfer), + serial_driver_func_t set_baudrate, + serial_driver_func_t set_data_format, + tuh_xfer_cb_t set_line_coding_stage1_complete, // function to be called after stage 1 completed + tuh_xfer_cb_t internal_control_complete, // control complete function to be called after request tuh_xfer_cb_t complete_cb, uintptr_t user_data) { if (complete_cb) { // non-blocking // stage 1 set baudrate p_cdc->requested_complete_cb = complete_cb; // store complete_cb to be used in set_line_coding_stage1_complete() p_cdc->user_complete_cb = set_line_coding_stage1_complete; - return set_baudrate_request(p_cdc, internal_control_complete, user_data); + return set_baudrate(p_cdc, internal_control_complete, user_data); } else { // blocking sequence // stage 1 set baudrate xfer_result_t result = XFER_RESULT_INVALID; // use local result, because user_data ptr may be NULL - bool ret = set_baudrate_request(p_cdc, NULL, (uintptr_t) &result); + bool ret = set_baudrate(p_cdc, NULL, (uintptr_t) &result); if (user_data) { *((xfer_result_t *) user_data) = result; @@ -556,7 +554,7 @@ static bool set_line_coding_sequence( // stage 2 set data format result = XFER_RESULT_INVALID; - ret = set_data_format_request(p_cdc, NULL, (uintptr_t) &result); + ret = set_data_format(p_cdc, NULL, (uintptr_t) &result); if (user_data) { *((xfer_result_t *) user_data) = result; @@ -590,58 +588,35 @@ static void set_line_coding_stage1_complete( } } } - -// call of (non-)blocking set-functions (to set line state, baudrate, ...) -static bool set_function_call ( - cdch_interface_t * p_cdc, - bool (*set_function)(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data), - tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - if (complete_cb) { - // non-blocking with call back - return set_function(p_cdc, complete_cb, user_data); - } else { - // blocking - xfer_result_t result = XFER_RESULT_INVALID; // use local result, because user_data ptr may be NULL - bool ret = set_function(p_cdc, NULL, (uintptr_t) &result); - - if (user_data) { - *((xfer_result_t *) user_data) = result; - } - - return (ret && result == XFER_RESULT_SUCCESS); - } -} +#endif 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); + TU_LOG_CDC(p_cdc, "set control line state dtr = %u rts = %u", p_cdc->requested_line.control_state.dtr, p_cdc->requested_line.control_state.rts); cdch_serial_driver_t const * driver = &serial_drivers[p_cdc->serial_drid]; p_cdc->requested_line.control_state.value = (uint8_t) line_state; - TU_LOG_P_CDC("set control line state dtr = %u rts = %u", p_cdc->requested_line.control_state.dtr, p_cdc->requested_line.control_state.rts); - - const bool ret = set_function_call(p_cdc, driver->set_control_line_state, complete_cb, user_data); - + const bool ret = driver->set_control_line_state(p_cdc, complete_cb, user_data); if (ret && !complete_cb) { - p_cdc->line.control_state = p_cdc->requested_line.control_state; + // blocking, update line state if request was successful + p_cdc->line.control_state.value = (uint8_t) line_state; } + return ret; } bool tuh_cdc_set_baudrate(uint8_t idx, uint32_t baudrate, 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); - TU_LOG_P_CDC("set baudrate %lu", baudrate); + TU_LOG_CDC(p_cdc, "set baudrate %lu", baudrate); cdch_serial_driver_t const *driver = &serial_drivers[p_cdc->serial_drid]; p_cdc->requested_line.coding.bit_rate = baudrate; - - bool ret = set_function_call(p_cdc, driver->set_baudrate, complete_cb, user_data); - + const bool ret = driver->set_baudrate(p_cdc, complete_cb, user_data); if (ret && !complete_cb) { p_cdc->line.coding.bit_rate = baudrate; } -// TU_LOG_P_CDC_BOOL("set baudrate", ret); return ret; } @@ -650,7 +625,7 @@ bool tuh_cdc_set_data_format(uint8_t idx, uint8_t stop_bits, uint8_t parity, uin 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); - TU_LOG_P_CDC("set data format %u%c%s", + TU_LOG_CDC(p_cdc, "set data format %u%c%s", data_bits, CDC_LINE_CODING_PARITY_CHAR(parity), CDC_LINE_CODING_STOP_BITS_TEXT(stop_bits)); cdch_serial_driver_t const *driver = &serial_drivers[p_cdc->serial_drid]; @@ -659,15 +634,13 @@ bool tuh_cdc_set_data_format(uint8_t idx, uint8_t stop_bits, uint8_t parity, uin p_cdc->requested_line.coding.parity = parity; p_cdc->requested_line.coding.data_bits = data_bits; - bool ret = set_function_call(p_cdc, driver->set_data_format, complete_cb, user_data); + const bool ret = driver->set_data_format(p_cdc, complete_cb, user_data); if (ret && !complete_cb) { p_cdc->line.coding.stop_bits = stop_bits; p_cdc->line.coding.parity = parity; p_cdc->line.coding.data_bits = data_bits; } -// TU_LOG_P_CDC_BOOL("set data format", ret); - return ret; } @@ -675,7 +648,7 @@ 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); - TU_LOG_P_CDC("set line coding %lu %u%c%s", + TU_LOG_CDC(p_cdc, "set line coding %lu %u%c%s", line_coding->bit_rate, line_coding->data_bits, CDC_LINE_CODING_PARITY_CHAR(line_coding->parity), CDC_LINE_CODING_STOP_BITS_TEXT(line_coding->stop_bits)); @@ -683,12 +656,11 @@ bool tuh_cdc_set_line_coding(uint8_t idx, cdc_line_coding_t const *line_coding, p_cdc->requested_line.coding = *line_coding; - bool ret = set_function_call(p_cdc, driver->set_line_coding, complete_cb, user_data); + const bool ret = driver->set_line_coding(p_cdc, complete_cb, user_data); if (ret && !complete_cb) { p_cdc->line.coding = *line_coding; } -// TU_LOG_P_CDC_BOOL("set line coding", ret); return ret; } @@ -728,7 +700,7 @@ void cdch_close(uint8_t daddr) { for (uint8_t idx = 0; idx < CFG_TUH_CDC; idx++) { cdch_interface_t *p_cdc = &cdch_data[idx]; if (p_cdc->daddr == daddr) { - TU_LOG_P_CDC("close"); + TU_LOG_CDC(p_cdc, "close"); // Invoke application callback if (tuh_cdc_umount_cb) { @@ -847,9 +819,8 @@ bool cdch_open(uint8_t rhport, uint8_t daddr, tusb_desc_interface_t const *itf_d } if (driver_detected) { - TU_LOG_CDC("open", daddr, itf_desc->bInterfaceNumber, driver_detected->name); - bool ret = driver_detected->open(daddr, itf_desc, max_len); - // TU_LOG_CDC("opened ret = %s", daddr, itf_desc->bInterfaceNumber, driver_detected->name, ret ? "true" : "FALSE" ); + const bool ret = driver_detected->open(daddr, itf_desc, max_len); + TU_LOG_DRV("[:%u:%u] CDCh %s open %s\r\n", daddr, itf_desc->bInterfaceNumber, driver_detected->name, ret ? "OK" : "FAILED"); return ret; } @@ -859,7 +830,6 @@ bool cdch_open(uint8_t rhport, uint8_t daddr, tusb_desc_interface_t const *itf_d static void set_config_complete(uint8_t idx, uint8_t itf_offset, bool success) { cdch_interface_t *p_cdc = get_itf(idx); TU_ASSERT(p_cdc, ); - TU_LOG_P_CDC_BOOL("set config complete", success); if (success) { p_cdc->mounted = true; @@ -883,6 +853,8 @@ static void cdch_process_set_config(tuh_xfer_t *xfer) { TU_ASSERT(p_cdc && p_cdc->serial_drid < SERIAL_DRIVER_COUNT,); const uint8_t idx = get_idx_by_ptr(p_cdc); + TU_LOG_DRV(" state = %u\r\n", xfer->user_data); + if (!serial_drivers[p_cdc->serial_drid].process_set_config(xfer)) { const uint8_t itf_offset = (p_cdc->serial_drid == SERIAL_DRIVER_ACM) ? 1 : 0; set_config_complete(idx, itf_offset, false); @@ -895,7 +867,7 @@ bool cdch_set_config(uint8_t daddr, uint8_t itf_num) { uint8_t const idx = tuh_cdc_itf_get_index(daddr, itf_num); cdch_interface_t *p_cdc = get_itf(idx); TU_ASSERT(p_cdc && p_cdc->serial_drid < SERIAL_DRIVER_COUNT); - TU_LOG_P_CDC("set config"); + TU_LOG_CDC(p_cdc, "set config"); // fake transfer to kick-off process_set_config() tuh_xfer_t xfer; @@ -919,7 +891,6 @@ static void acm_internal_control_complete(tuh_xfer_t *xfer) { cdch_interface_t *p_cdc = get_itf(idx); TU_ASSERT(p_cdc, ); bool const success = (xfer->result == XFER_RESULT_SUCCESS); - TU_LOG_P_CDC_BOOL("control complete", success); if (success) { switch (xfer->setup->bRequest) { @@ -1204,7 +1175,6 @@ static void ftdi_internal_control_complete(tuh_xfer_t *xfer) { cdch_interface_t *p_cdc = get_itf(idx); TU_ASSERT(p_cdc, ); bool const success = (xfer->result == XFER_RESULT_SUCCESS); - TU_LOG_P_CDC_BOOL("control complete", success); if (success) { if (xfer->setup->bRequest == FTDI_SIO_SET_MODEM_CTRL_REQUEST && @@ -1232,14 +1202,12 @@ static void ftdi_internal_control_complete(tuh_xfer_t *xfer) { static bool ftdi_set_data_format(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { p_cdc->user_complete_cb = complete_cb; TU_ASSERT(ftdi_set_data_request(p_cdc, complete_cb ? ftdi_internal_control_complete : NULL, user_data)); - return true; } static bool ftdi_set_baudrate(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { p_cdc->user_complete_cb = complete_cb; TU_ASSERT(ftdi_change_speed(p_cdc, complete_cb ? ftdi_internal_control_complete : NULL, user_data)); - return true; } @@ -1271,7 +1239,6 @@ static bool ftdi_set_modem_ctrl(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_ } //------------- Enumeration -------------// - enum { CONFIG_FTDI_DETERMINE_TYPE = 0, CONFIG_FTDI_WRITE_LATENCY, @@ -1448,7 +1415,7 @@ static bool ftdi_determine_type(cdch_interface_t *p_cdc) { #if CFG_TUSB_DEBUG >= CFG_TUH_CDC_LOG_LEVEL const char * ftdi_chip_name[] = { FTDI_CHIP_NAMES }; - TU_LOG_P_CDC("%s detected (bcdDevice = 0x%04x)", + TU_LOG_CDC(p_cdc, "%s detected (bcdDevice = 0x%04x)", ftdi_chip_name[p_cdc->ftdi.chip_type], version); #endif @@ -1595,7 +1562,7 @@ static inline uint32_t ftdi_get_divisor(cdch_interface_t *p_cdc) { break; } - TU_LOG_P_CDC("Baudrate divisor = 0x%lu", div_value); + TU_LOG_CDC(p_cdc, "Baudrate divisor = 0x%lu", div_value); return div_value; } @@ -1695,7 +1662,6 @@ static void cp210x_internal_control_complete(tuh_xfer_t *xfer) { cdch_interface_t *p_cdc = get_itf(idx); TU_ASSERT(p_cdc, ); bool const success = (xfer->result == XFER_RESULT_SUCCESS); - TU_LOG_P_CDC_BOOL("control complete", success); if (success) { switch (xfer->setup->bRequest) { @@ -1795,7 +1761,7 @@ static bool cp210x_process_set_config(tuh_xfer_t *xfer) { cdch_interface_t *p_cdc = get_itf(idx); TU_ASSERT(p_cdc && xfer->result == XFER_RESULT_SUCCESS); - switch (state) { + switch (state) { case CONFIG_CP210X_IFC_ENABLE: TU_ASSERT(cp210x_ifc_enable(p_cdc, CP210X_UART_ENABLE, cdch_process_set_config, CONFIG_CP210X_SET_BAUDRATE_REQUEST)); break; @@ -1941,7 +1907,6 @@ static void ch34x_internal_control_complete(tuh_xfer_t *xfer) { cdch_interface_t *p_cdc = get_itf(idx); TU_ASSERT(p_cdc, ); bool const success = (xfer->result == XFER_RESULT_SUCCESS); - TU_LOG_P_CDC_BOOL("control complete", success); if (success) { switch (xfer->setup->bRequest) { @@ -2059,7 +2024,6 @@ static bool ch34x_process_set_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); uint8_t buffer[2];// TODO remove - TU_ASSERT(p_cdc && xfer->result == XFER_RESULT_SUCCESS); switch (state) { @@ -2071,7 +2035,7 @@ static bool ch34x_process_set_config(tuh_xfer_t *xfer) { case CONFIG_CH34X_SERIAL_INIT: { // handle version read data, set CH34x line coding (incl. baudrate) uint8_t const version = xfer->buffer[0]; - TU_LOG_P_CDC("Chip Version = 0x%02x", version); + TU_LOG_CDC(p_cdc, "Chip Version = 0x%02x", version); // only versions >= 0x30 are tested, below 0x30 seems having other programming // see drivers from WCH vendor, Linux kernel and FreeBSD if (version >= 0x30) { @@ -2348,7 +2312,6 @@ static void pl2303_internal_control_complete(tuh_xfer_t *xfer) { cdch_interface_t *p_cdc = get_itf(idx); TU_ASSERT(p_cdc, ); bool const success = (xfer->result == XFER_RESULT_SUCCESS); - TU_LOG_P_CDC_BOOL("control complete", success); if (success) { if (xfer->setup->bRequest == PL2303_SET_LINE_REQUEST && @@ -2458,6 +2421,7 @@ static bool pl2303_process_set_config(tuh_xfer_t *xfer) { pl2303_type_t type; TU_ASSERT(p_cdc && (xfer->result == XFER_RESULT_SUCCESS || state == CONFIG_PL2303_READ1)); + switch (state) { // from here sequence overtaken from Linux Kernel function pl2303_startup() case CONFIG_PL2303_DETECT_TYPE: @@ -2741,7 +2705,7 @@ static pl2303_type_t pl2303_detect_type(cdch_interface_t *p_cdc, uint8_t step) { default: break; } - TU_LOG_P_CDC("unknown device type bcdUSB = 0x%04x", desc_dev.bcdUSB); + TU_LOG_CDC(p_cdc, "unknown device type bcdUSB = 0x%04x", desc_dev.bcdUSB); return PL2303_TYPE_UNKNOWN; } @@ -2886,7 +2850,7 @@ static bool pl2303_encode_baud_rate(cdch_interface_t *p_cdc, uint8_t buf[PL2303_ } else { baud = pl2303_encode_baud_rate_divisor(buf, baud); } - TU_LOG_P_CDC("real baudrate %lu", baud); + TU_LOG_CDC(p_cdc, "real baudrate %lu", baud); return true; } diff --git a/src/class/cdc/cdc_host.h b/src/class/cdc/cdc_host.h index 688164cb2..37bfca270 100644 --- a/src/class/cdc/cdc_host.h +++ b/src/class/cdc/cdc_host.h @@ -137,13 +137,12 @@ bool tuh_cdc_peek(uint8_t idx, uint8_t* ch); bool tuh_cdc_read_clear (uint8_t idx); //--------------------------------------------------------------------+ -// Control Endpoint (Request) API +// Control Request API // Each Function will make a USB control transfer request to/from device // - If complete_cb is provided, the function will return immediately and invoke // the callback when request is complete. // - If complete_cb is NULL, the function will block until request is complete. -// - In this case, user_data should be pointed to xfer_result_t to hold the transfer result. -// - The function will return true if transfer is successful, false otherwise. +// In this case, user_data should be usb_xfer_result_t* to hold the transfer result. //--------------------------------------------------------------------+ // Request to Set Control Line State: DTR (bit 0), RTS (bit 1) @@ -179,17 +178,52 @@ bool tuh_cdc_set_line_coding(uint8_t idx, cdc_line_coding_t const* line_coding, // bool tuh_cdc_get_line_coding(uint8_t idx, cdc_line_coding_t* 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) { +TU_ATTR_ALWAYS_INLINE static inline 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) { +TU_ATTR_ALWAYS_INLINE static inline 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); } +//--------------------------------------------------------------------+ +// Control Request Sync API +// Each Function will make a USB control transfer request to/from device the function will block until request is +// complete. The function will return the transfer request result +//--------------------------------------------------------------------+ +TU_ATTR_ALWAYS_INLINE static inline tusb_xfer_result_t tuh_cdc_set_control_line_state_sync(uint8_t idx, uint16_t line_state) { + TU_API_SYNC(tuh_cdc_set_control_line_state, idx, line_state); +} + +TU_ATTR_ALWAYS_INLINE static inline tusb_xfer_result_t tuh_cdc_set_dtr_sync(uint8_t idx, bool dtr_state) { + TU_API_SYNC(tuh_cdc_set_dtr, idx, dtr_state); +} + +TU_ATTR_ALWAYS_INLINE static inline tusb_xfer_result_t tuh_cdc_set_rts_sync(uint8_t idx, bool rts_state) { + TU_API_SYNC(tuh_cdc_set_rts, idx, rts_state); +} + +TU_ATTR_ALWAYS_INLINE static inline tusb_xfer_result_t tuh_cdc_set_baudrate_sync(uint8_t idx, uint32_t baudrate) { + TU_API_SYNC(tuh_cdc_set_baudrate, idx, baudrate); +} + +TU_ATTR_ALWAYS_INLINE static inline tusb_xfer_result_t tuh_cdc_set_data_format_sync(uint8_t idx, uint8_t stop_bits, uint8_t parity, uint8_t data_bits) { + TU_API_SYNC(tuh_cdc_set_data_format, idx, stop_bits, parity, data_bits); +} + +TU_ATTR_ALWAYS_INLINE static inline tusb_xfer_result_t tuh_cdc_set_line_coding_sync(uint8_t idx, cdc_line_coding_t const* line_coding) { + TU_API_SYNC(tuh_cdc_set_line_coding, idx, line_coding); +} + +TU_ATTR_ALWAYS_INLINE static inline tusb_xfer_result_t tuh_cdc_connect_sync(uint8_t idx) { + TU_API_SYNC(tuh_cdc_connect, idx); +} + +TU_ATTR_ALWAYS_INLINE static inline tusb_xfer_result_t tuh_cdc_disconnect_sync(uint8_t idx) { + TU_API_SYNC(tuh_cdc_disconnect, idx); +} + //--------------------------------------------------------------------+ // CDC APPLICATION CALLBACKS //--------------------------------------------------------------------+ diff --git a/src/class/cdc/serial/pl2303.h b/src/class/cdc/serial/pl2303.h index c01dac0e1..63910c7bb 100644 --- a/src/class/cdc/serial/pl2303.h +++ b/src/class/cdc/serial/pl2303.h @@ -109,36 +109,37 @@ typedef enum pl2303_type { } pl2303_type_t; typedef struct pl2303_type_data { - uint32_t const max_baud_rate; - uint8_t const quirks; - uint8_t const no_autoxonxoff : 1; - uint8_t const no_divisors : 1; - uint8_t const alt_divisors : 1; + uint32_t max_baud_rate; + uint8_t quirks; + uint8_t no_autoxonxoff : 1; + uint8_t no_divisors : 1; + uint8_t alt_divisors : 1; } pl2303_type_data_t; #define PL2303_TYPE_DATA \ [PL2303_TYPE_H] = { \ - .max_baud_rate = 1228800, \ - .quirks = PL2303_QUIRK_LEGACY, \ - .no_autoxonxoff = true, \ + .max_baud_rate = 1228800, .quirks = PL2303_QUIRK_LEGACY, \ + .no_autoxonxoff = 1, .no_divisors = 0, .alt_divisors = 0 \ }, \ [PL2303_TYPE_HX] = { \ - .max_baud_rate = 6000000, \ + .max_baud_rate = 6000000, .quirks = 0, \ + .no_autoxonxoff = 0, .no_divisors = 0, .alt_divisors = 0 \ }, \ [PL2303_TYPE_TA] = { \ - .max_baud_rate = 6000000, \ - .alt_divisors = true, \ + .max_baud_rate = 6000000, .quirks = 0, \ + .no_autoxonxoff = 0, .no_divisors = 0, .alt_divisors = 1 \ }, \ [PL2303_TYPE_TB] = { \ - .max_baud_rate = 12000000, \ - .alt_divisors = true, \ + .max_baud_rate = 12000000, .quirks = 0, \ + .no_autoxonxoff = 0, .no_divisors = 0, .alt_divisors = 1 \ }, \ [PL2303_TYPE_HXD] = { \ - .max_baud_rate = 12000000, \ + .max_baud_rate = 12000000, .quirks = 0, \ + .no_autoxonxoff = 0, .no_divisors = 0, .alt_divisors = 0 \ }, \ [PL2303_TYPE_HXN] = { \ - .max_baud_rate = 12000000, \ - .no_divisors = true, \ + .max_baud_rate = 12000000, .quirks = 0, \ + .no_autoxonxoff = 0, .no_divisors = 1, .alt_divisors = 0 \ } typedef struct TU_ATTR_PACKED { -- cgit v1.3.1 From 900d0d974b177959ffeaa1f34de72daf2ef72694 Mon Sep 17 00:00:00 2001 From: hathach Date: Fri, 20 Jun 2025 17:04:40 +0700 Subject: refactor change signature of serial driver's process_set_config adding serial driver's request_complete() --- src/class/cdc/cdc_host.c | 185 +++++++++++++++++++++-------------------------- 1 file changed, 84 insertions(+), 101 deletions(-) (limited to 'src/class') diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index 50d0a020d..f36487758 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -112,11 +112,13 @@ CFG_TUH_MEM_SECTION static cdch_epbuf_t cdch_epbuf[CFG_TUH_CDC]; // Serial Driver //--------------------------------------------------------------------+ +// General driver static void cdch_process_set_config(tuh_xfer_t *xfer); +static void cdch_internal_control_complete(tuh_xfer_t *xfer); //------------- ACM prototypes -------------// static bool acm_open(uint8_t daddr, tusb_desc_interface_t const * itf_desc, uint16_t max_len); -static bool acm_process_set_config(tuh_xfer_t * xfer); +static bool acm_process_set_config(cdch_interface_t *p_cdc, tuh_xfer_t *xfer); static bool acm_set_baudrate(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); static bool acm_set_data_format(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); @@ -127,7 +129,8 @@ static bool acm_set_control_line_state(cdch_interface_t * p_cdc, tuh_xfer_cb_t c #if CFG_TUH_CDC_FTDI static uint16_t const ftdi_vid_pid_list[][2] = {CFG_TUH_CDC_FTDI_VID_PID_LIST}; static bool ftdi_open(uint8_t daddr, const tusb_desc_interface_t * itf_desc, uint16_t max_len); -static bool ftdi_proccess_set_config(tuh_xfer_t * xfer); +static bool ftdi_proccess_set_config(cdch_interface_t *p_cdc, tuh_xfer_t *xfer); +static void ftdi_internal_control_complete(cdch_interface_t* p_cdc, tuh_xfer_t *xfer); static bool ftdi_set_baudrate(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); static bool ftdi_set_data_format(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); @@ -140,7 +143,9 @@ static bool ftdi_set_modem_ctrl(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete 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 bool cp210x_process_set_config(tuh_xfer_t * xfer); +static bool cp210x_process_set_config(cdch_interface_t *p_cdc, tuh_xfer_t *xfer); +static void acm_internal_control_complete(tuh_xfer_t *xfer); +static void cp210x_internal_control_complete(tuh_xfer_t *xfer); static bool cp210x_set_baudrate(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); static bool cp210x_set_data_format(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); @@ -153,7 +158,8 @@ static bool cp210x_set_modem_ctrl(cdch_interface_t * p_cdc, tuh_xfer_cb_t comple 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 bool ch34x_process_set_config(tuh_xfer_t *xfer); +static bool ch34x_process_set_config(cdch_interface_t *p_cdc, tuh_xfer_t *xfer); +static void ch34x_internal_control_complete(tuh_xfer_t *xfer); static bool ch34x_set_baudrate(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); static bool ch34x_set_data_format(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); @@ -167,7 +173,8 @@ static uint16_t const pl2303_vid_pid_list[][2] = {CFG_TUH_CDC_PL2303_VID_PID_LIS static const pl2303_type_data_t pl2303_type_data[PL2303_TYPE_COUNT] = {PL2303_TYPE_DATA}; static bool pl2303_open(uint8_t daddr, tusb_desc_interface_t const * itf_desc, uint16_t max_len); -static bool pl2303_process_set_config(tuh_xfer_t *xfer); +static bool pl2303_process_set_config(cdch_interface_t *p_cdc, tuh_xfer_t *xfer); +static void pl2303_internal_control_complete(tuh_xfer_t *xfer); static bool pl2303_set_baudrate(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); static bool pl2303_set_data_format(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); @@ -206,11 +213,11 @@ typedef struct { bool is_2stage_line_coding; // true if driver requires to set baudrate then data format separately bool (*const open)(uint8_t daddr, const tusb_desc_interface_t * itf_desc, uint16_t max_len); - bool (*const process_set_config)(tuh_xfer_t * xfer); - const serial_driver_func_t set_control_line_state; - const serial_driver_func_t set_baudrate; - const serial_driver_func_t set_data_format; - const serial_driver_func_t set_line_coding; + bool (*const process_set_config)(cdch_interface_t * p_cdc, tuh_xfer_t * xfer); + void (*const request_complete)(cdch_interface_t * p_cdc, tuh_xfer_t * xfer); // internal request complete handler to update line state + + serial_driver_func_t set_control_line_state, set_baudrate, set_data_format, set_line_coding; + #if CFG_TUSB_DEBUG && CFG_TUSB_DEBUG >= CFG_TUH_CDC_LOG_LEVEL const char * name; #endif @@ -244,6 +251,7 @@ static const cdch_serial_driver_t serial_drivers[] = { .is_2stage_line_coding = true, .open = ftdi_open, .process_set_config = ftdi_proccess_set_config, + .request_complete = ftdi_internal_control_complete, .set_control_line_state = ftdi_set_modem_ctrl, .set_baudrate = ftdi_set_baudrate, .set_data_format = ftdi_set_data_format, @@ -827,11 +835,9 @@ bool cdch_open(uint8_t rhport, uint8_t daddr, tusb_desc_interface_t const *itf_d return false; } -static void set_config_complete(uint8_t idx, uint8_t itf_offset, bool success) { - cdch_interface_t *p_cdc = get_itf(idx); - TU_ASSERT(p_cdc, ); - +static void set_config_complete(cdch_interface_t *p_cdc, uint8_t itf_offset, bool success) { if (success) { + const uint8_t idx = get_idx_by_ptr(p_cdc); p_cdc->mounted = true; if (tuh_cdc_mount_cb) { tuh_cdc_mount_cb(idx); @@ -848,19 +854,6 @@ static void set_config_complete(uint8_t idx, uint8_t itf_offset, bool success) { usbh_driver_set_config_complete(p_cdc->daddr, p_cdc->bInterfaceNumber + itf_offset); } -static void cdch_process_set_config(tuh_xfer_t *xfer) { - cdch_interface_t *p_cdc = get_itf_by_xfer(xfer); - TU_ASSERT(p_cdc && p_cdc->serial_drid < SERIAL_DRIVER_COUNT,); - const uint8_t idx = get_idx_by_ptr(p_cdc); - - TU_LOG_DRV(" state = %u\r\n", xfer->user_data); - - if (!serial_drivers[p_cdc->serial_drid].process_set_config(xfer)) { - const uint8_t itf_offset = (p_cdc->serial_drid == SERIAL_DRIVER_ACM) ? 1 : 0; - set_config_complete(idx, itf_offset, false); - } -} - bool cdch_set_config(uint8_t daddr, uint8_t itf_num) { tusb_control_request_t request; request.wIndex = tu_htole16((uint16_t) itf_num); @@ -880,6 +873,32 @@ bool cdch_set_config(uint8_t daddr, uint8_t itf_num) { return true; } + +static void cdch_process_set_config(tuh_xfer_t *xfer) { + cdch_interface_t *p_cdc = get_itf_by_xfer(xfer); + TU_ASSERT(p_cdc && p_cdc->serial_drid < SERIAL_DRIVER_COUNT,); + TU_LOG_DRV(" state = %u\r\n", xfer->user_data); + + if (!serial_drivers[p_cdc->serial_drid].process_set_config(p_cdc, xfer)) { + const uint8_t itf_offset = (p_cdc->serial_drid == SERIAL_DRIVER_ACM) ? 1 : 0; + set_config_complete(p_cdc, itf_offset, false); + } +} + +static void cdch_internal_control_complete(tuh_xfer_t *xfer) { + cdch_interface_t *p_cdc = get_itf_by_xfer(xfer); + TU_ASSERT(p_cdc && p_cdc->serial_drid < SERIAL_DRIVER_COUNT,); + + TU_LOG_DRV(" request result = %u\r\n", xfer->result); + serial_drivers[p_cdc->serial_drid].request_complete(p_cdc, xfer); + + // Invoke application callback + xfer->complete_cb = p_cdc->user_complete_cb; + if (xfer->complete_cb) { + xfer->complete_cb(xfer); + } +} + //--------------------------------------------------------------------+ // ACM //--------------------------------------------------------------------+ @@ -1046,13 +1065,9 @@ static bool acm_open(uint8_t daddr, tusb_desc_interface_t const *itf_desc, uint1 return true; } -static bool acm_process_set_config(tuh_xfer_t *xfer) { +static bool acm_process_set_config(cdch_interface_t *p_cdc, tuh_xfer_t *xfer) { + TU_ASSERT(xfer->result == XFER_RESULT_SUCCESS); const uintptr_t 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 && xfer->result == XFER_RESULT_SUCCESS); - switch (state) { case CONFIG_ACM_SET_CONTROL_LINE_STATE: #ifdef CFG_TUH_CDC_LINE_CONTROL_ON_ENUM @@ -1076,7 +1091,7 @@ static bool acm_process_set_config(tuh_xfer_t *xfer) { case CONFIG_ACM_COMPLETE: // itf_num+1 to account for data interface as well - set_config_complete(idx, 1, true); + set_config_complete(p_cdc, 1, true); break; default: @@ -1159,55 +1174,38 @@ static bool ftdi_set_data_request(cdch_interface_t *p_cdc, tuh_xfer_cb_t complet value, p_cdc->ftdi.channel, complete_cb, user_data); } -static inline bool ftdi_update_mctrl(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - uint16_t value = (uint16_t) ((p_cdc->requested_line.control_state.dtr ? FTDI_SIO_SET_DTR_HIGH : FTDI_SIO_SET_DTR_LOW) | - (p_cdc->requested_line.control_state.rts ? FTDI_SIO_SET_RTS_HIGH : FTDI_SIO_SET_RTS_LOW)); - - return ftdi_set_request(p_cdc, FTDI_SIO_SET_MODEM_CTRL_REQUEST, FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE, - value, p_cdc->ftdi.channel, complete_cb, user_data); -} - //------------- Driver API -------------// // internal control complete to update state such as line state, line_coding -static void ftdi_internal_control_complete(tuh_xfer_t *xfer) { - uint8_t const idx = ftdi_get_idx(xfer); - cdch_interface_t *p_cdc = get_itf(idx); - TU_ASSERT(p_cdc, ); - bool const success = (xfer->result == XFER_RESULT_SUCCESS); - - if (success) { - if (xfer->setup->bRequest == FTDI_SIO_SET_MODEM_CTRL_REQUEST && - xfer->setup->bmRequestType == FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE ) { +static void ftdi_internal_control_complete(cdch_interface_t* p_cdc, tuh_xfer_t *xfer) { + const tusb_control_request_t * setup = xfer->setup; + if (xfer->result == XFER_RESULT_SUCCESS) { + if (setup->bRequest == FTDI_SIO_SET_MODEM_CTRL_REQUEST && + setup->bmRequestType == FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE ) { p_cdc->line.control_state = p_cdc->requested_line.control_state; } - if (xfer->setup->bRequest == FTDI_SIO_SET_DATA_REQUEST && - xfer->setup->bmRequestType == FTDI_SIO_SET_DATA_REQUEST_TYPE ) { + if (setup->bRequest == FTDI_SIO_SET_DATA_REQUEST && + setup->bmRequestType == FTDI_SIO_SET_DATA_REQUEST_TYPE ) { 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; } - if (xfer->setup->bRequest == FTDI_SIO_SET_BAUDRATE_REQUEST && - xfer->setup->bmRequestType == FTDI_SIO_SET_BAUDRATE_REQUEST_TYPE ) { + if (setup->bRequest == FTDI_SIO_SET_BAUDRATE_REQUEST && + setup->bmRequestType == FTDI_SIO_SET_BAUDRATE_REQUEST_TYPE ) { p_cdc->line.coding.bit_rate = p_cdc->requested_line.coding.bit_rate; } } - - xfer->complete_cb = p_cdc->user_complete_cb; - if (xfer->complete_cb) { - xfer->complete_cb(xfer); - } } static bool ftdi_set_data_format(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { p_cdc->user_complete_cb = complete_cb; - TU_ASSERT(ftdi_set_data_request(p_cdc, complete_cb ? ftdi_internal_control_complete : NULL, user_data)); + TU_ASSERT(ftdi_set_data_request(p_cdc, complete_cb ? cdch_internal_control_complete : NULL, user_data)); return true; } static bool ftdi_set_baudrate(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { p_cdc->user_complete_cb = complete_cb; - TU_ASSERT(ftdi_change_speed(p_cdc, complete_cb ? ftdi_internal_control_complete : NULL, user_data)); + TU_ASSERT(ftdi_change_speed(p_cdc, complete_cb ? cdch_internal_control_complete : NULL, user_data)); return true; } @@ -1218,7 +1216,7 @@ static void ftdi_set_line_coding_stage1_complete(tuh_xfer_t *xfer) { uint8_t const itf_num = p_cdc->bInterfaceNumber; set_line_coding_stage1_complete(xfer, itf_num, ftdi_set_data_request, // control request function to set data format - ftdi_internal_control_complete); // control complete function to be called after request + cdch_internal_control_complete); // control complete function to be called after request } // 2 stages: set baudrate (stage1) + set data format (stage2) @@ -1227,15 +1225,16 @@ static bool ftdi_set_line_coding(cdch_interface_t * p_cdc, tuh_xfer_cb_t complet ftdi_change_speed, // control request function to set baudrate ftdi_set_data_request, // control request function to set data format ftdi_set_line_coding_stage1_complete, // function to be called after stage 1 completed - ftdi_internal_control_complete, // control complete function to be called after request + cdch_internal_control_complete, // control complete function to be called after request complete_cb, user_data); } static bool ftdi_set_modem_ctrl(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + uint16_t line_state = (uint16_t) ((p_cdc->requested_line.control_state.dtr ? FTDI_SIO_SET_DTR_HIGH : FTDI_SIO_SET_DTR_LOW) | + (p_cdc->requested_line.control_state.rts ? FTDI_SIO_SET_RTS_HIGH : FTDI_SIO_SET_RTS_LOW)); p_cdc->user_complete_cb = complete_cb; - TU_ASSERT(ftdi_update_mctrl(p_cdc, complete_cb ? ftdi_internal_control_complete : NULL, user_data)); - - return true; + return ftdi_set_request(p_cdc, FTDI_SIO_SET_MODEM_CTRL_REQUEST, FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE, + line_state, p_cdc->ftdi.channel, complete_cb ? cdch_internal_control_complete : NULL, user_data); } //------------- Enumeration -------------// @@ -1274,18 +1273,14 @@ static bool ftdi_open(uint8_t daddr, const tusb_desc_interface_t *itf_desc, uint return open_ep_stream_pair(p_cdc, desc_ep); } -static bool ftdi_proccess_set_config(tuh_xfer_t *xfer) { +static bool ftdi_proccess_set_config(cdch_interface_t *p_cdc, tuh_xfer_t *xfer) { + TU_ASSERT(xfer->result == XFER_RESULT_SUCCESS); const uintptr_t state = xfer->user_data; - uint8_t const idx = ftdi_get_idx(xfer); - cdch_interface_t *p_cdc = get_itf(idx); - uint8_t const itf_num = p_cdc->bInterfaceNumber; - TU_ASSERT(p_cdc && xfer->result == XFER_RESULT_SUCCESS); - switch (state) { // from here sequence overtaken from Linux Kernel function ftdi_port_probe() case CONFIG_FTDI_DETERMINE_TYPE: // determine type - if (itf_num == 0) { + if (p_cdc->bInterfaceNumber == 0) { TU_ASSERT(ftdi_determine_type(p_cdc)); } else { // other interfaces have same type as interface 0 @@ -1318,7 +1313,7 @@ static bool ftdi_proccess_set_config(tuh_xfer_t *xfer) { #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM p_cdc->requested_line.coding = (cdc_line_coding_t) CFG_TUH_CDC_LINE_CODING_ON_ENUM; p_cdc->user_complete_cb = cdch_process_set_config; - TU_ASSERT(ftdi_set_data_request(p_cdc, ftdi_internal_control_complete, CONFIG_FTDI_SET_BAUDRATE)); + TU_ASSERT(ftdi_set_data_request(p_cdc, cdch_internal_control_complete, CONFIG_FTDI_SET_BAUDRATE)); break; #else TU_ATTR_FALLTHROUGH; @@ -1327,7 +1322,7 @@ static bool ftdi_proccess_set_config(tuh_xfer_t *xfer) { case CONFIG_FTDI_SET_BAUDRATE: #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM p_cdc->user_complete_cb = cdch_process_set_config; - TU_ASSERT(ftdi_change_speed(p_cdc, ftdi_internal_control_complete, CONFIG_FTDI_FLOW_CONTROL)); + TU_ASSERT(ftdi_change_speed(p_cdc, cdch_internal_control_complete, CONFIG_FTDI_FLOW_CONTROL)); break; #else TU_ATTR_FALLTHROUGH; @@ -1342,15 +1337,14 @@ static bool ftdi_proccess_set_config(tuh_xfer_t *xfer) { case CONFIG_FTDI_MODEM_CTRL: #ifdef CFG_TUH_CDC_LINE_CONTROL_ON_ENUM p_cdc->requested_line.control_state.value = CFG_TUH_CDC_LINE_CONTROL_ON_ENUM; - p_cdc->user_complete_cb = cdch_process_set_config; - TU_ASSERT(ftdi_update_mctrl(p_cdc, ftdi_internal_control_complete, CONFIG_FTDI_COMPLETE)); + TU_ASSERT(ftdi_set_modem_ctrl(p_cdc, cdch_process_set_config, CONFIG_FTDI_COMPLETE)); break; #else TU_ATTR_FALLTHROUGH; #endif case CONFIG_FTDI_COMPLETE: - set_config_complete(idx, 0, true); + set_config_complete(p_cdc, 0, true); break; default: @@ -1754,12 +1748,9 @@ static bool cp210x_open(uint8_t daddr, tusb_desc_interface_t const *itf_desc, ui return open_ep_stream_pair(p_cdc, desc_ep); } -static bool cp210x_process_set_config(tuh_xfer_t *xfer) { +static bool cp210x_process_set_config(cdch_interface_t *p_cdc, tuh_xfer_t *xfer) { + TU_ASSERT(xfer->result == XFER_RESULT_SUCCESS); const uintptr_t 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 && xfer->result == XFER_RESULT_SUCCESS); switch (state) { case CONFIG_CP210X_IFC_ENABLE: @@ -1796,7 +1787,7 @@ static bool cp210x_process_set_config(tuh_xfer_t *xfer) { #endif case CONFIG_CP210X_COMPLETE: - set_config_complete(idx, 0, true); + set_config_complete(p_cdc, 0, true); break; default: @@ -2018,13 +2009,10 @@ static bool ch34x_open(uint8_t daddr, tusb_desc_interface_t const * itf_desc, ui return true; } -static bool ch34x_process_set_config(tuh_xfer_t *xfer) { - const uintptr_t state = xfer->user_data; - uint8_t const itf_num = 0; // CH34x has only interface 0, since wIndex is used as payload - uint8_t const idx = tuh_cdc_itf_get_index(xfer->daddr, itf_num); - cdch_interface_t *p_cdc = get_itf(idx); +static bool ch34x_process_set_config(cdch_interface_t *p_cdc, tuh_xfer_t *xfer) { uint8_t buffer[2];// TODO remove - TU_ASSERT(p_cdc && xfer->result == XFER_RESULT_SUCCESS); + TU_ASSERT(xfer->result == XFER_RESULT_SUCCESS); + const uintptr_t state = xfer->user_data; switch (state) { case CONFIG_CH34X_READ_VERSION: @@ -2074,7 +2062,7 @@ static bool ch34x_process_set_config(tuh_xfer_t *xfer) { #endif case CONFIG_CH34X_COMPLETE: - set_config_complete(idx, 0, true); + set_config_complete(p_cdc, 0, true); break; default: @@ -2410,18 +2398,13 @@ static bool pl2303_open(uint8_t daddr, tusb_desc_interface_t const *itf_desc, ui return true; } -static bool pl2303_process_set_config(tuh_xfer_t *xfer) { - const uintptr_t state = xfer->user_data; - // PL2303 has only interface 0, because wIndex is used 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); +static bool pl2303_process_set_config(cdch_interface_t *p_cdc, tuh_xfer_t *xfer) { // state CONFIG_PL2303_READ1 may have no success due to expected stall by pl2303_supports_hx_status() + const uintptr_t state = xfer->user_data; + TU_ASSERT(xfer->result == XFER_RESULT_SUCCESS || state == CONFIG_PL2303_READ1); uint8_t buf = 0; pl2303_type_t type; - TU_ASSERT(p_cdc && (xfer->result == XFER_RESULT_SUCCESS || state == CONFIG_PL2303_READ1)); - switch (state) { // from here sequence overtaken from Linux Kernel function pl2303_startup() case CONFIG_PL2303_DETECT_TYPE: @@ -2618,7 +2601,7 @@ static bool pl2303_process_set_config(tuh_xfer_t *xfer) { // break; case CONFIG_PL2303_COMPLETE: - set_config_complete(idx, 0, true); + set_config_complete(p_cdc, 0, true); break; default: -- cgit v1.3.1 From 470e12febca6e371de03120508ef44db28e8501d Mon Sep 17 00:00:00 2001 From: hathach Date: Fri, 20 Jun 2025 17:25:58 +0700 Subject: refactor, add cdch_internal_control_complete() --- src/class/cdc/cdc_host.c | 233 +++++++++++++++++++---------------------------- 1 file changed, 95 insertions(+), 138 deletions(-) (limited to 'src/class') diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index f36487758..1786f7815 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -119,6 +119,7 @@ static void cdch_internal_control_complete(tuh_xfer_t *xfer); //------------- ACM prototypes -------------// static bool acm_open(uint8_t daddr, tusb_desc_interface_t const * itf_desc, uint16_t max_len); static bool acm_process_set_config(cdch_interface_t *p_cdc, tuh_xfer_t *xfer); +static void acm_internal_control_complete(cdch_interface_t *p_cdc, tuh_xfer_t *xfer); static bool acm_set_baudrate(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); static bool acm_set_data_format(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); @@ -144,8 +145,7 @@ 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 bool cp210x_process_set_config(cdch_interface_t *p_cdc, tuh_xfer_t *xfer); -static void acm_internal_control_complete(tuh_xfer_t *xfer); -static void cp210x_internal_control_complete(tuh_xfer_t *xfer); +static void cp210x_internal_control_complete(cdch_interface_t *p_cdc, tuh_xfer_t *xfer); static bool cp210x_set_baudrate(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); static bool cp210x_set_data_format(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); @@ -159,7 +159,7 @@ 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 bool ch34x_process_set_config(cdch_interface_t *p_cdc, tuh_xfer_t *xfer); -static void ch34x_internal_control_complete(tuh_xfer_t *xfer); +static void ch34x_internal_control_complete(cdch_interface_t *p_cdc, tuh_xfer_t *xfer); static bool ch34x_set_baudrate(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); static bool ch34x_set_data_format(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); @@ -174,7 +174,7 @@ static const pl2303_type_data_t pl2303_type_data[PL2303_TYPE_COUNT] = {PL2303_TY static bool pl2303_open(uint8_t daddr, tusb_desc_interface_t const * itf_desc, uint16_t max_len); static bool pl2303_process_set_config(cdch_interface_t *p_cdc, tuh_xfer_t *xfer); -static void pl2303_internal_control_complete(tuh_xfer_t *xfer); +static void pl2303_internal_control_complete(cdch_interface_t *p_cdc, tuh_xfer_t *xfer); static bool pl2303_set_baudrate(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); static bool pl2303_set_data_format(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); @@ -237,6 +237,8 @@ static const cdch_serial_driver_t serial_drivers[] = { .is_2stage_line_coding = false, .open = acm_open, .process_set_config = acm_process_set_config, + .request_complete = acm_internal_control_complete, + .set_control_line_state = acm_set_control_line_state, .set_baudrate = acm_set_baudrate, .set_data_format = acm_set_data_format, @@ -252,6 +254,7 @@ static const cdch_serial_driver_t serial_drivers[] = { .open = ftdi_open, .process_set_config = ftdi_proccess_set_config, .request_complete = ftdi_internal_control_complete, + .set_control_line_state = ftdi_set_modem_ctrl, .set_baudrate = ftdi_set_baudrate, .set_data_format = ftdi_set_data_format, @@ -267,6 +270,8 @@ static const cdch_serial_driver_t serial_drivers[] = { .is_2stage_line_coding = true, .open = cp210x_open, .process_set_config = cp210x_process_set_config, + .request_complete = cp210x_internal_control_complete, + .set_control_line_state = cp210x_set_modem_ctrl, .set_baudrate = cp210x_set_baudrate, .set_data_format = cp210x_set_data_format, @@ -282,6 +287,8 @@ static const cdch_serial_driver_t serial_drivers[] = { .is_2stage_line_coding = true, .open = ch34x_open, .process_set_config = ch34x_process_set_config, + .request_complete = ch34x_internal_control_complete, + .set_control_line_state = ch34x_set_modem_ctrl, .set_baudrate = ch34x_set_baudrate, .set_data_format = ch34x_set_data_format, @@ -297,6 +304,8 @@ static const cdch_serial_driver_t serial_drivers[] = { .is_2stage_line_coding = false, .open = pl2303_open, .process_set_config = pl2303_process_set_config, + .request_complete = pl2303_internal_control_complete, + .set_control_line_state = pl2303_set_modem_ctrl, .set_baudrate = pl2303_set_baudrate, .set_data_format = pl2303_set_data_format, @@ -904,37 +913,28 @@ static void cdch_internal_control_complete(tuh_xfer_t *xfer) { //--------------------------------------------------------------------+ // internal control complete to update state such as line state, encoding -static void acm_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, ); - bool const success = (xfer->result == XFER_RESULT_SUCCESS); - - if (success) { - switch (xfer->setup->bRequest) { - case CDC_REQUEST_SET_CONTROL_LINE_STATE: - p_cdc->line.control_state = p_cdc->requested_line.control_state; - break; +static void acm_internal_control_complete(cdch_interface_t *p_cdc, tuh_xfer_t *xfer) { + TU_VERIFY (xfer->result == XFER_RESULT_SUCCESS,); + const tusb_control_request_t * setup = xfer->setup; - case CDC_REQUEST_SET_LINE_CODING: - p_cdc->line.coding = p_cdc->requested_line.coding; - break; + switch (setup->bRequest) { + case CDC_REQUEST_SET_CONTROL_LINE_STATE: + p_cdc->line.control_state = p_cdc->requested_line.control_state; + break; - default: break; - } - } + case CDC_REQUEST_SET_LINE_CODING: + p_cdc->line.coding = p_cdc->requested_line.coding; + break; - xfer->complete_cb = p_cdc->user_complete_cb; - if (xfer->complete_cb) { - xfer->complete_cb(xfer); + default: + break; } } static bool acm_set_control_line_state(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { TU_VERIFY(p_cdc->acm.capability.support_line_request); - tusb_control_request_t const request = { + const tusb_control_request_t request = { .bmRequestType_bit = { .recipient = TUSB_REQ_RCPT_INTERFACE, .type = TUSB_REQ_TYPE_CLASS, @@ -953,7 +953,7 @@ static bool acm_set_control_line_state(cdch_interface_t *p_cdc, tuh_xfer_cb_t co .ep_addr = 0, .setup = &request, .buffer = NULL, - .complete_cb = complete_cb ? acm_internal_control_complete : NULL, + .complete_cb = complete_cb ? cdch_internal_control_complete : NULL, .user_data = user_data }; @@ -990,7 +990,7 @@ static bool acm_set_line_coding(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_ .ep_addr = 0, .setup = &request, .buffer = enum_buf, - .complete_cb = complete_cb ? acm_internal_control_complete : NULL, + .complete_cb = complete_cb ? cdch_internal_control_complete : NULL, .user_data = user_data }; @@ -1178,6 +1178,7 @@ static bool ftdi_set_data_request(cdch_interface_t *p_cdc, tuh_xfer_cb_t complet // internal control complete to update state such as line state, line_coding static void ftdi_internal_control_complete(cdch_interface_t* p_cdc, tuh_xfer_t *xfer) { + TU_VERIFY(xfer->result == XFER_RESULT_SUCCESS,); const tusb_control_request_t * setup = xfer->setup; if (xfer->result == XFER_RESULT_SUCCESS) { if (setup->bRequest == FTDI_SIO_SET_MODEM_CTRL_REQUEST && @@ -1650,50 +1651,36 @@ static inline bool cp210x_set_mhs(cdch_interface_t *p_cdc, tuh_xfer_cb_t complet //------------- Driver API -------------// // internal control complete to update state such as line state, encoding -static void cp210x_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, ); - bool const success = (xfer->result == XFER_RESULT_SUCCESS); - - if (success) { - switch (xfer->setup->bRequest) { - case CP210X_SET_MHS: - p_cdc->line.control_state = p_cdc->requested_line.control_state; - break; - - case CP210X_SET_LINE_CTL: - 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; +static void cp210x_internal_control_complete(cdch_interface_t *p_cdc, tuh_xfer_t *xfer) { + TU_VERIFY(xfer->result == XFER_RESULT_SUCCESS,); + switch (xfer->setup->bRequest) { + case CP210X_SET_MHS: + p_cdc->line.control_state = p_cdc->requested_line.control_state; + break; - case CP210X_SET_BAUDRATE: - p_cdc->line.coding.bit_rate = p_cdc->requested_line.coding.bit_rate; - break; + case CP210X_SET_LINE_CTL: + 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; - } - } + case CP210X_SET_BAUDRATE: + p_cdc->line.coding.bit_rate = p_cdc->requested_line.coding.bit_rate; + break; - xfer->complete_cb = p_cdc->user_complete_cb; - if (xfer->complete_cb) { - xfer->complete_cb(xfer); + default: break; } } static bool cp210x_set_baudrate(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { p_cdc->user_complete_cb = complete_cb; - TU_ASSERT(cp210x_set_baudrate_request(p_cdc, complete_cb ? cp210x_internal_control_complete : NULL, user_data)); - + TU_ASSERT(cp210x_set_baudrate_request(p_cdc, complete_cb ? cdch_internal_control_complete : NULL, user_data)); return true; } static bool cp210x_set_data_format(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { p_cdc->user_complete_cb = complete_cb; - TU_ASSERT(cp210x_set_line_ctl(p_cdc, complete_cb ? cp210x_internal_control_complete : NULL, user_data)); - + TU_ASSERT(cp210x_set_line_ctl(p_cdc, complete_cb ? cdch_internal_control_complete : NULL, user_data)); return true; } @@ -1701,7 +1688,7 @@ static void cp210x_set_line_coding_stage1_complete(tuh_xfer_t *xfer) { uint8_t const itf_num = (uint8_t) tu_le16toh(xfer->setup->wIndex); set_line_coding_stage1_complete(xfer, itf_num, cp210x_set_line_ctl, // control request function to set data format - cp210x_internal_control_complete); // control complete function to be called after request + cdch_internal_control_complete); // control complete function to be called after request } // 2 stages: set baudrate (stage1) + set data format (stage2) @@ -1710,14 +1697,13 @@ static bool cp210x_set_line_coding(cdch_interface_t *p_cdc, tuh_xfer_cb_t comple cp210x_set_baudrate_request, // control request function to set baudrate cp210x_set_line_ctl, // control request function to set data format cp210x_set_line_coding_stage1_complete, // function to be called after stage 1 completed - cp210x_internal_control_complete, // control complete function to be called after request + cdch_internal_control_complete, // control complete function to be called after request complete_cb, user_data); } static bool cp210x_set_modem_ctrl(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { p_cdc->user_complete_cb = complete_cb; - TU_ASSERT(cp210x_set_mhs(p_cdc, complete_cb ? cp210x_internal_control_complete : NULL, user_data)); - + TU_ASSERT(cp210x_set_mhs(p_cdc, complete_cb ? cdch_internal_control_complete : NULL, user_data)); return true; } @@ -1761,7 +1747,7 @@ static bool cp210x_process_set_config(cdch_interface_t *p_cdc, tuh_xfer_t *xfer) #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM p_cdc->requested_line.coding = (cdc_line_coding_t) CFG_TUH_CDC_LINE_CODING_ON_ENUM; p_cdc->user_complete_cb = cdch_process_set_config; - TU_ASSERT(cp210x_set_baudrate_request(p_cdc, cp210x_internal_control_complete, CONFIG_CP210X_SET_LINE_CTL)); + TU_ASSERT(cp210x_set_baudrate_request(p_cdc, cdch_internal_control_complete, CONFIG_CP210X_SET_LINE_CTL)); break; #else TU_ATTR_FALLTHROUGH; @@ -1770,7 +1756,7 @@ static bool cp210x_process_set_config(cdch_interface_t *p_cdc, tuh_xfer_t *xfer) case CONFIG_CP210X_SET_LINE_CTL: #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM p_cdc->user_complete_cb = cdch_process_set_config; - TU_ASSERT(cp210x_set_line_ctl(p_cdc, cp210x_internal_control_complete, CONFIG_CP210X_SET_DTR_RTS)); + TU_ASSERT(cp210x_set_line_ctl(p_cdc, cdch_internal_control_complete, CONFIG_CP210X_SET_DTR_RTS)); break; #else TU_ATTR_FALLTHROUGH; @@ -1780,7 +1766,7 @@ static bool cp210x_process_set_config(cdch_interface_t *p_cdc, tuh_xfer_t *xfer) #ifdef CFG_TUH_CDC_LINE_CONTROL_ON_ENUM p_cdc->requested_line.control_state.value = CFG_TUH_CDC_LINE_CONTROL_ON_ENUM; p_cdc->user_complete_cb = cdch_process_set_config; - TU_ASSERT(cp210x_set_mhs(p_cdc, cp210x_internal_control_complete, CONFIG_CP210X_COMPLETE)); + TU_ASSERT(cp210x_set_mhs(p_cdc, cdch_internal_control_complete, CONFIG_CP210X_COMPLETE)); break; #else TU_ATTR_FALLTHROUGH; @@ -1891,60 +1877,45 @@ static bool ch34x_modem_ctrl_request(cdch_interface_t *p_cdc, tuh_xfer_cb_t comp //------------- Driver API -------------// // internal control complete to update state such as line state, encoding -static void ch34x_internal_control_complete(tuh_xfer_t *xfer) { - // CH34x has only interface 0, because wIndex is used as payload and not for bInterfaceNumber - uint8_t const itf_num = 0; - uint8_t idx = tuh_cdc_itf_get_index(xfer->daddr, itf_num); - cdch_interface_t *p_cdc = get_itf(idx); - TU_ASSERT(p_cdc, ); - bool const success = (xfer->result == XFER_RESULT_SUCCESS); +static void ch34x_internal_control_complete(cdch_interface_t *p_cdc, tuh_xfer_t *xfer) { + TU_VERIFY(xfer->result == XFER_RESULT_SUCCESS,); + switch (xfer->setup->bRequest) { + case CH34X_REQ_WRITE_REG: + // register write request + switch (tu_le16toh(xfer->setup->wValue)) { + case CH34X_REG16_DIVISOR_PRESCALER: + // baudrate + p_cdc->line.coding.bit_rate = p_cdc->requested_line.coding.bit_rate; + break; - if (success) { - switch (xfer->setup->bRequest) { - case CH34X_REQ_WRITE_REG: - // register write request - switch (tu_le16toh(xfer->setup->wValue)) { - 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 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; - case CH34X_REQ_MODEM_CTRL: - p_cdc->line.control_state = p_cdc->requested_line.control_state; - break; + default: break; + } + break; - default: break; - } - } + case CH34X_REQ_MODEM_CTRL: + p_cdc->line.control_state = p_cdc->requested_line.control_state; + break; - xfer->complete_cb = p_cdc->user_complete_cb; - if (xfer->complete_cb) { - xfer->complete_cb(xfer); + default: break; } } static bool ch34x_set_data_format(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { p_cdc->user_complete_cb = complete_cb; - TU_ASSERT(ch34x_write_reg_data_format(p_cdc, complete_cb ? ch34x_internal_control_complete : NULL, user_data)); - + TU_ASSERT(ch34x_write_reg_data_format(p_cdc, complete_cb ? cdch_internal_control_complete : NULL, user_data)); return true; } static bool ch34x_set_baudrate(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { p_cdc->user_complete_cb = complete_cb; - TU_ASSERT(ch34x_write_reg_baudrate(p_cdc, complete_cb ? ch34x_internal_control_complete : NULL, user_data)); - + TU_ASSERT(ch34x_write_reg_baudrate(p_cdc, complete_cb ? cdch_internal_control_complete : NULL, user_data)); return true; } @@ -1953,7 +1924,7 @@ static void ch34x_set_line_coding_stage1_complete(tuh_xfer_t *xfer) { uint8_t const itf_num = 0; set_line_coding_stage1_complete(xfer, itf_num, ch34x_write_reg_data_format, // control request function to set data format - ch34x_internal_control_complete); // control complete function to be called after request + cdch_internal_control_complete); // control complete function to be called after request } // 2 stages: set baudrate (stage1) + set data format (stage2) @@ -1962,14 +1933,13 @@ static bool ch34x_set_line_coding(cdch_interface_t * p_cdc, tuh_xfer_cb_t comple ch34x_write_reg_baudrate, // control request function to set baudrate ch34x_write_reg_data_format, // control request function to set data format ch34x_set_line_coding_stage1_complete, // function to be called after stage 1 completed - ch34x_internal_control_complete, // control complete function to be called after request + cdch_internal_control_complete, // control complete function to be called after request complete_cb, user_data); } static bool ch34x_set_modem_ctrl(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { p_cdc->user_complete_cb = complete_cb; - TU_ASSERT(ch34x_modem_ctrl_request(p_cdc, complete_cb ? ch34x_internal_control_complete : NULL, user_data)); - + TU_ASSERT(ch34x_modem_ctrl_request(p_cdc, complete_cb ? cdch_internal_control_complete : NULL, user_data)); return true; } @@ -2055,7 +2025,7 @@ static bool ch34x_process_set_config(cdch_interface_t *p_cdc, tuh_xfer_t *xfer) #ifdef CFG_TUH_CDC_LINE_CONTROL_ON_ENUM p_cdc->requested_line.control_state.value = CFG_TUH_CDC_LINE_CONTROL_ON_ENUM; p_cdc->user_complete_cb = cdch_process_set_config; - TU_ASSERT(ch34x_modem_ctrl_request(p_cdc, ch34x_internal_control_complete, CONFIG_CH34X_COMPLETE)); + TU_ASSERT(ch34x_modem_ctrl_request(p_cdc, cdch_internal_control_complete, CONFIG_CH34X_COMPLETE)); break; #else TU_ATTR_FALLTHROUGH; @@ -2293,41 +2263,28 @@ static inline int pl2303_clear_halt(cdch_interface_t *p_cdc, uint8_t endp, tuh_x //------------- Driver API -------------// // internal control complete to update state such as line state, encoding -static void pl2303_internal_control_complete(tuh_xfer_t *xfer) { - // PL2303 has only interface 0, because wIndex is used as payload and not for bInterfaceNumber - uint8_t const itf_num = 0; - uint8_t idx = tuh_cdc_itf_get_index(xfer->daddr, itf_num); - cdch_interface_t *p_cdc = get_itf(idx); - TU_ASSERT(p_cdc, ); - bool const success = (xfer->result == XFER_RESULT_SUCCESS); - - if (success) { - if (xfer->setup->bRequest == PL2303_SET_LINE_REQUEST && - xfer->setup->bmRequestType == PL2303_SET_LINE_REQUEST_TYPE) { - p_cdc->line.coding = p_cdc->requested_line.coding; - } - if (xfer->setup->bRequest == PL2303_SET_CONTROL_REQUEST && - xfer->setup->bmRequestType == PL2303_SET_CONTROL_REQUEST_TYPE) { - p_cdc->line.control_state = p_cdc->requested_line.control_state; - } +static void pl2303_internal_control_complete(cdch_interface_t *p_cdc, tuh_xfer_t *xfer) { + TU_VERIFY(xfer->result == XFER_RESULT_SUCCESS,); + if (xfer->setup->bRequest == PL2303_SET_LINE_REQUEST && + xfer->setup->bmRequestType == PL2303_SET_LINE_REQUEST_TYPE) { + p_cdc->line.coding = p_cdc->requested_line.coding; } - - xfer->complete_cb = p_cdc->user_complete_cb; - if (xfer->complete_cb) { - xfer->complete_cb(xfer); + if (xfer->setup->bRequest == PL2303_SET_CONTROL_REQUEST && + xfer->setup->bmRequestType == PL2303_SET_CONTROL_REQUEST_TYPE) { + p_cdc->line.control_state = p_cdc->requested_line.control_state; } } static bool pl2303_set_line_coding(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { p_cdc->user_complete_cb = complete_cb; - TU_ASSERT(pl2303_set_line_request(p_cdc, complete_cb ? pl2303_internal_control_complete : NULL, user_data)); + TU_ASSERT(pl2303_set_line_request(p_cdc, complete_cb ? cdch_internal_control_complete : NULL, user_data)); return true; } static bool pl2303_set_data_format(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { p_cdc->requested_line.coding.bit_rate = p_cdc->line.coding.bit_rate; p_cdc->user_complete_cb = complete_cb; - TU_ASSERT(pl2303_set_line_request(p_cdc, complete_cb ? pl2303_internal_control_complete : NULL, user_data)); + TU_ASSERT(pl2303_set_line_request(p_cdc, complete_cb ? cdch_internal_control_complete : NULL, user_data)); return true; } @@ -2336,14 +2293,14 @@ static bool pl2303_set_baudrate(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_ p_cdc->requested_line.coding.parity = p_cdc->line.coding.parity; p_cdc->requested_line.coding.data_bits = p_cdc->line.coding.data_bits; p_cdc->user_complete_cb = complete_cb; - TU_ASSERT(pl2303_set_line_request(p_cdc, complete_cb ? pl2303_internal_control_complete : NULL, user_data)); + TU_ASSERT(pl2303_set_line_request(p_cdc, complete_cb ? cdch_internal_control_complete : NULL, user_data)); return true; } static bool pl2303_set_modem_ctrl(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { // PL2303 has the same bit coding p_cdc->user_complete_cb = complete_cb; - TU_ASSERT(pl2303_set_control_lines(p_cdc, complete_cb ? pl2303_internal_control_complete : NULL, user_data)); + TU_ASSERT(pl2303_set_control_lines(p_cdc, complete_cb ? cdch_internal_control_complete : NULL, user_data)); return true; } @@ -2557,7 +2514,7 @@ static bool pl2303_process_set_config(cdch_interface_t *p_cdc, tuh_xfer_t *xfer) case CONFIG_PL2303_LINE_CODING: #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM p_cdc->requested_line.coding = (cdc_line_coding_t) CFG_TUH_CDC_LINE_CODING_ON_ENUM; - TU_ASSERT(pl2303_set_line_request(p_cdc, pl2303_internal_control_complete, CONFIG_PL2303_MODEM_CONTROL)); + TU_ASSERT(pl2303_set_line_request(p_cdc, cdch_internal_control_complete, CONFIG_PL2303_MODEM_CONTROL)); break; #else TU_ATTR_FALLTHROUGH; @@ -2566,7 +2523,7 @@ static bool pl2303_process_set_config(cdch_interface_t *p_cdc, tuh_xfer_t *xfer) case CONFIG_PL2303_MODEM_CONTROL: #ifdef CFG_TUH_CDC_LINE_CONTROL_ON_ENUM p_cdc->requested_line.control_state.value = CFG_TUH_CDC_LINE_CONTROL_ON_ENUM; - TU_ASSERT(pl2303_set_control_lines(p_cdc, pl2303_internal_control_complete, CONFIG_PL2303_COMPLETE)); + TU_ASSERT(pl2303_set_control_lines(p_cdc, cdch_internal_control_complete, CONFIG_PL2303_COMPLETE)); break; #else TU_ATTR_FALLTHROUGH; -- cgit v1.3.1 From 2843eb405252ba4f8475c86d346b95547fb4020c Mon Sep 17 00:00:00 2001 From: milek7 Date: Thu, 26 Jun 2025 00:03:25 +0200 Subject: audio_device: Fix data IN endpoints with implicit feedback --- src/class/audio/audio_device.c | 33 ++++++++++++++++++--------------- 1 file changed, 18 insertions(+), 15 deletions(-) (limited to 'src/class') diff --git a/src/class/audio/audio_device.c b/src/class/audio/audio_device.c index 11a3d4a73..a877dc900 100644 --- a/src/class/audio/audio_device.c +++ b/src/class/audio/audio_device.c @@ -1003,20 +1003,22 @@ uint16_t audiod_open(uint8_t rhport, tusb_desc_interface_t const *itf_desc, uint ep_fb = desc_ep->bEndpointAddress; } #endif - // 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); + // Data or data with implicit feedback IN EP + if (tu_edpt_dir(desc_ep->bEndpointAddress) == TUSB_DIR_IN + && (desc_ep->bmAttributes.usage == 0 || desc_ep->bmAttributes.usage == 2)) { + ep_in = desc_ep->bEndpointAddress; + ep_in_size = TU_MAX(tu_edpt_packet_size(desc_ep), ep_in_size); + } #endif - } 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); - #endif - } + // Data OUT EP + if (tu_edpt_dir(desc_ep->bEndpointAddress) == TUSB_DIR_OUT + && desc_ep->bmAttributes.usage == 0) { + ep_out = desc_ep->bEndpointAddress; + ep_out_size = TU_MAX(tu_edpt_packet_size(desc_ep), ep_out_size); } + #endif } } @@ -1052,10 +1054,10 @@ uint16_t audiod_open(uint8_t rhport, tusb_desc_interface_t const *itf_desc, uint 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; - } + // For data or data with implicit feedback IN EP + if (tu_edpt_dir(desc_ep->bEndpointAddress) == TUSB_DIR_IN + && (desc_ep->bmAttributes.usage == 0 || desc_ep->bmAttributes.usage == 2)) { + _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) { @@ -1227,7 +1229,8 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const *p usbd_edpt_clear_stall(rhport, ep_addr); #if CFG_TUD_AUDIO_ENABLE_EP_IN - if (tu_edpt_dir(ep_addr) == TUSB_DIR_IN && desc_ep->bmAttributes.usage == 0x00)// Check if usage is data EP + // For data or data with implicit feedback IN EP + if (tu_edpt_dir(ep_addr) == TUSB_DIR_IN && (desc_ep->bmAttributes.usage == 0 || desc_ep->bmAttributes.usage == 2)) { // Save address audio->ep_in = ep_addr; -- cgit v1.3.1 From 8b5d703f74153c75dd9e4cfb224dbe74e4e262fa Mon Sep 17 00:00:00 2001 From: hathach Date: Fri, 27 Jun 2025 15:57:18 +0700 Subject: major refactor to generalize cdch serial driver - add common 2 stage set line coding for driver without direct set_line_coding support e.g ftdi, cp210x, ch34x - add common cdch_process_line_state_on_enum() to handle cfg line state on enum e.g CFG_TUH_CDC_LINE_CONTROL/CODING_ON_ENUM - refactor cdch_internal_control_complete and user_complete_cb to be managed by tuh_cdc_ API instead of serial driver --- src/class/cdc/cdc_host.c | 661 ++++++++++++++++--------------------------- src/class/cdc/serial/ch34x.h | 4 +- 2 files changed, 245 insertions(+), 420 deletions(-) (limited to 'src/class') diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index 1786f7815..7926aa9fc 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -45,12 +45,9 @@ #define CFG_TUH_CDC_LOG_LEVEL 1 #endif -#define TU_LOG_DRV(...) TU_LOG(CFG_TUH_CDC_LOG_LEVEL, __VA_ARGS__) -#define TU_LOG_CDC(_cdc, _format, ...) TU_LOG_DRV("[:%u:%u] CDCh %s " _format "\r\n", _cdc->daddr, _cdc->bInterfaceNumber, \ - serial_drivers[_cdc->serial_drid].name, ##__VA_ARGS__) - -// Driver that need to set line coding in two stages: baudrate then data format. -#define DRIVER_2STAGE_SET_LINE_CODING (CFG_TUH_CDC_FTDI || CFG_TUH_CDC_CP210X || CFG_TUH_CDC_CH34X) +#define TU_LOG_DRV(...) TU_LOG(CFG_TUH_CDC_LOG_LEVEL, __VA_ARGS__) +#define TU_LOG_CDC(_cdc, _format, ...) TU_LOG_DRV("[:%u:%u] CDCh %s " _format "\r\n", _cdc->daddr, _cdc->bInterfaceNumber, \ + serial_drivers[_cdc->serial_drid].name, ##__VA_ARGS__) //--------------------------------------------------------------------+ // Host CDC Interface @@ -73,10 +70,6 @@ typedef struct { tuh_xfer_cb_t user_complete_cb; // required since we handle request internally first - #if DRIVER_2STAGE_SET_LINE_CODING - tuh_xfer_cb_t requested_complete_cb; - #endif - union { struct { cdc_acm_capability_t capability; @@ -114,7 +107,10 @@ CFG_TUH_MEM_SECTION static cdch_epbuf_t cdch_epbuf[CFG_TUH_CDC]; // General driver static void cdch_process_set_config(tuh_xfer_t *xfer); +static void cdch_process_line_state_on_enum(tuh_xfer_t *xfer); // invoked after set config is processed static void cdch_internal_control_complete(tuh_xfer_t *xfer); +static void cdch_set_line_coding_stage1_baudrate_complete(tuh_xfer_t *xfer); +static void cdch_set_line_coding_stage2_data_format_complete(tuh_xfer_t *xfer); //------------- ACM prototypes -------------// static bool acm_open(uint8_t daddr, tusb_desc_interface_t const * itf_desc, uint16_t max_len); @@ -135,7 +131,6 @@ static void ftdi_internal_control_complete(cdch_interface_t* p_cdc, tuh_xfer_t * static bool ftdi_set_baudrate(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); static bool ftdi_set_data_format(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); -static bool ftdi_set_line_coding(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); static bool ftdi_set_modem_ctrl(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); #endif @@ -149,7 +144,6 @@ static void cp210x_internal_control_complete(cdch_interface_t *p_cdc, tuh_xfer_t static bool cp210x_set_baudrate(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); static bool cp210x_set_data_format(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); -static bool cp210x_set_line_coding(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); static bool cp210x_set_modem_ctrl(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); #endif @@ -163,7 +157,6 @@ static void ch34x_internal_control_complete(cdch_interface_t *p_cdc, tuh_xfer_t static bool ch34x_set_baudrate(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); static bool ch34x_set_data_format(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); -static bool ch34x_set_line_coding(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); static bool ch34x_set_modem_ctrl(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); #endif @@ -210,8 +203,6 @@ typedef bool (*serial_driver_func_t)(cdch_interface_t * p_cdc, tuh_xfer_cb_t com typedef struct { uint16_t const (*vid_pid_list)[2]; uint16_t const vid_pid_count; - bool is_2stage_line_coding; // true if driver requires to set baudrate then data format separately - bool (*const open)(uint8_t daddr, const tusb_desc_interface_t * itf_desc, uint16_t max_len); bool (*const process_set_config)(cdch_interface_t * p_cdc, tuh_xfer_t * xfer); void (*const request_complete)(cdch_interface_t * p_cdc, tuh_xfer_t * xfer); // internal request complete handler to update line state @@ -234,7 +225,6 @@ static const cdch_serial_driver_t serial_drivers[] = { { .vid_pid_list = NULL, .vid_pid_count = 0, - .is_2stage_line_coding = false, .open = acm_open, .process_set_config = acm_process_set_config, .request_complete = acm_internal_control_complete, @@ -250,15 +240,13 @@ static const cdch_serial_driver_t serial_drivers[] = { { .vid_pid_list = ftdi_vid_pid_list, .vid_pid_count = TU_ARRAY_SIZE(ftdi_vid_pid_list), - .is_2stage_line_coding = true, .open = ftdi_open, .process_set_config = ftdi_proccess_set_config, .request_complete = ftdi_internal_control_complete, - .set_control_line_state = ftdi_set_modem_ctrl, .set_baudrate = ftdi_set_baudrate, .set_data_format = ftdi_set_data_format, - .set_line_coding = ftdi_set_line_coding, + .set_line_coding = NULL, // 2 stage set line coding DRIVER_NAME_DECLARE("FTDI") }, #endif @@ -267,15 +255,13 @@ static const cdch_serial_driver_t serial_drivers[] = { { .vid_pid_list = cp210x_vid_pid_list, .vid_pid_count = TU_ARRAY_SIZE(cp210x_vid_pid_list), - .is_2stage_line_coding = true, .open = cp210x_open, .process_set_config = cp210x_process_set_config, .request_complete = cp210x_internal_control_complete, - .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, + .set_line_coding = NULL, // 2 stage set line coding DRIVER_NAME_DECLARE("CP210x") }, #endif @@ -284,7 +270,6 @@ static const cdch_serial_driver_t serial_drivers[] = { { .vid_pid_list = ch34x_vid_pid_list, .vid_pid_count = TU_ARRAY_SIZE(ch34x_vid_pid_list), - .is_2stage_line_coding = true, .open = ch34x_open, .process_set_config = ch34x_process_set_config, .request_complete = ch34x_internal_control_complete, @@ -292,7 +277,7 @@ static const cdch_serial_driver_t serial_drivers[] = { .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, + .set_line_coding = NULL, // 2 stage set line coding DRIVER_NAME_DECLARE("CH34x") }, #endif @@ -301,11 +286,9 @@ static const cdch_serial_driver_t serial_drivers[] = { { .vid_pid_list = pl2303_vid_pid_list, .vid_pid_count = TU_ARRAY_SIZE(pl2303_vid_pid_list), - .is_2stage_line_coding = false, .open = pl2303_open, .process_set_config = pl2303_process_set_config, .request_complete = pl2303_internal_control_complete, - .set_control_line_state = pl2303_set_modem_ctrl, .set_baudrate = pl2303_set_baudrate, .set_data_format = pl2303_set_data_format, @@ -474,28 +457,24 @@ bool tuh_cdc_get_line_coding_local(uint8_t idx, cdc_line_coding_t * line_coding) 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->daddr, &p_cdc->stream.tx, buffer, bufsize); } 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->daddr, &p_cdc->stream.tx); } 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) { cdch_interface_t * p_cdc = get_itf(idx); TU_VERIFY(p_cdc); - return tu_edpt_stream_write_available(p_cdc->daddr, &p_cdc->stream.tx); } @@ -506,21 +485,18 @@ uint32_t tuh_cdc_write_available(uint8_t idx) { 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->daddr, &p_cdc->stream.rx, buffer, bufsize); } 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) { cdch_interface_t * p_cdc = get_itf(idx); TU_VERIFY(p_cdc); - return tu_edpt_stream_peek(&p_cdc->stream.rx, ch); } @@ -537,105 +513,40 @@ bool tuh_cdc_read_clear (uint8_t idx) { // Control Endpoint API //--------------------------------------------------------------------+ -#if DRIVER_2STAGE_SET_LINE_CODING - -// set line coding using sequence with 2 stages: set baudrate (stage1) + set data format (stage2) -static bool set_line_coding_sequence( - cdch_interface_t * p_cdc, - serial_driver_func_t set_baudrate, - serial_driver_func_t set_data_format, - tuh_xfer_cb_t set_line_coding_stage1_complete, // function to be called after stage 1 completed - tuh_xfer_cb_t internal_control_complete, // control complete function to be called after request - tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - if (complete_cb) { - // non-blocking - // stage 1 set baudrate - p_cdc->requested_complete_cb = complete_cb; // store complete_cb to be used in set_line_coding_stage1_complete() - p_cdc->user_complete_cb = set_line_coding_stage1_complete; - return set_baudrate(p_cdc, internal_control_complete, user_data); - } else { - // blocking sequence - // stage 1 set baudrate - xfer_result_t result = XFER_RESULT_INVALID; // use local result, because user_data ptr may be NULL - bool ret = set_baudrate(p_cdc, NULL, (uintptr_t) &result); - - if (user_data) { - *((xfer_result_t *) user_data) = result; - } - - TU_ASSERT(ret); - TU_VERIFY(result == XFER_RESULT_SUCCESS); - - // overtake baudrate after successful request - p_cdc->line.coding.bit_rate = p_cdc->requested_line.coding.bit_rate; - - // stage 2 set data format - result = XFER_RESULT_INVALID; - ret = set_data_format(p_cdc, NULL, (uintptr_t) &result); - - if (user_data) { - *((xfer_result_t *) user_data) = result; - } - - TU_ASSERT(ret); - return (result == XFER_RESULT_SUCCESS); - // the overtaking of remaining requested_line_coding will be done in tuh_cdc_set_line_coding() - } -} - -static void set_line_coding_stage1_complete( - tuh_xfer_t * xfer, uint8_t const itf_num, - // control request function to set data format - bool (*set_data_format_request)(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data), - // control complete function to be called after request - void (*internal_control_complete)(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); - TU_ASSERT(p_cdc,); - - if (xfer->result == XFER_RESULT_SUCCESS) { - // stage 1 success, continue with stage 2 - p_cdc->user_complete_cb = p_cdc->requested_complete_cb; - set_data_format_request(p_cdc, internal_control_complete, xfer->user_data); - } else { - // stage 1 failed, notify user - xfer->complete_cb = p_cdc->requested_complete_cb; - if (xfer->complete_cb) { - xfer->complete_cb(xfer); - } - } -} -#endif - 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); TU_LOG_CDC(p_cdc, "set control line state dtr = %u rts = %u", p_cdc->requested_line.control_state.dtr, p_cdc->requested_line.control_state.rts); - cdch_serial_driver_t const * driver = &serial_drivers[p_cdc->serial_drid]; + const cdch_serial_driver_t * driver = &serial_drivers[p_cdc->serial_drid]; p_cdc->requested_line.control_state.value = (uint8_t) line_state; - const bool ret = driver->set_control_line_state(p_cdc, complete_cb, user_data); - if (ret && !complete_cb) { + p_cdc->user_complete_cb = complete_cb; + TU_VERIFY(driver->set_control_line_state(p_cdc, complete_cb ? cdch_internal_control_complete : NULL, user_data)); + + if (!complete_cb) { // blocking, update line state if request was successful p_cdc->line.control_state.value = (uint8_t) line_state; } - return ret; + return true; } bool tuh_cdc_set_baudrate(uint8_t idx, uint32_t baudrate, 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); TU_LOG_CDC(p_cdc, "set baudrate %lu", baudrate); - cdch_serial_driver_t const *driver = &serial_drivers[p_cdc->serial_drid]; + const cdch_serial_driver_t *driver = &serial_drivers[p_cdc->serial_drid]; + p_cdc->requested_line = p_cdc->line; // keep current line coding p_cdc->requested_line.coding.bit_rate = baudrate; - const bool ret = driver->set_baudrate(p_cdc, complete_cb, user_data); - if (ret && !complete_cb) { + p_cdc->user_complete_cb = complete_cb; + TU_VERIFY(driver->set_baudrate(p_cdc, complete_cb ? cdch_internal_control_complete : NULL, user_data)); + + if (!complete_cb) { p_cdc->line.coding.bit_rate = baudrate; } - return ret; + return true; } bool tuh_cdc_set_data_format(uint8_t idx, uint8_t stop_bits, uint8_t parity, uint8_t data_bits, @@ -645,20 +556,24 @@ bool tuh_cdc_set_data_format(uint8_t idx, uint8_t stop_bits, uint8_t parity, uin TU_LOG_CDC(p_cdc, "set data format %u%c%s", data_bits, CDC_LINE_CODING_PARITY_CHAR(parity), CDC_LINE_CODING_STOP_BITS_TEXT(stop_bits)); - cdch_serial_driver_t const *driver = &serial_drivers[p_cdc->serial_drid]; + const cdch_serial_driver_t *driver = &serial_drivers[p_cdc->serial_drid]; + p_cdc->requested_line = p_cdc->line; // keep current line coding 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; - const bool ret = driver->set_data_format(p_cdc, complete_cb, user_data); + p_cdc->user_complete_cb = complete_cb; + TU_VERIFY(driver->set_data_format(p_cdc, complete_cb ? cdch_internal_control_complete : NULL, user_data)); - if (ret && !complete_cb) { + if (!complete_cb) { + // blocking p_cdc->line.coding.stop_bits = stop_bits; p_cdc->line.coding.parity = parity; p_cdc->line.coding.data_bits = data_bits; } - return ret; + + return true; } bool tuh_cdc_set_line_coding(uint8_t idx, cdc_line_coding_t const *line_coding, @@ -670,16 +585,43 @@ bool tuh_cdc_set_line_coding(uint8_t idx, cdc_line_coding_t const *line_coding, CDC_LINE_CODING_PARITY_CHAR(line_coding->parity), CDC_LINE_CODING_STOP_BITS_TEXT(line_coding->stop_bits)); cdch_serial_driver_t const *driver = &serial_drivers[p_cdc->serial_drid]; - p_cdc->requested_line.coding = *line_coding; - const bool ret = driver->set_line_coding(p_cdc, complete_cb, user_data); + if (driver->set_line_coding) { + // driver support set_line_coding request + TU_VERIFY(driver->set_line_coding(p_cdc, complete_cb, user_data)); + + if (!complete_cb) { + p_cdc->line.coding = *line_coding; + } + } else { + // driver does not support set_line_coding and need 2 stage to set baudrate and data format separately + if (complete_cb) { + // non-blocking + p_cdc->user_complete_cb = complete_cb; + TU_VERIFY(driver->set_baudrate(p_cdc, cdch_set_line_coding_stage1_baudrate_complete, user_data)); + } else { + // blocking + xfer_result_t result = XFER_RESULT_INVALID; + + TU_VERIFY(driver->set_baudrate(p_cdc, NULL, (uintptr_t) &result)); + if (user_data) { + *((xfer_result_t *) user_data) = result; + } + TU_VERIFY(result == XFER_RESULT_SUCCESS); + p_cdc->line.coding.bit_rate = p_cdc->requested_line.coding.bit_rate; // update baudrate - if (ret && !complete_cb) { - p_cdc->line.coding = *line_coding; + result = XFER_RESULT_INVALID; + TU_VERIFY(driver->set_data_format(p_cdc, NULL, (uintptr_t) &result)); + if (user_data) { + *((xfer_result_t *) user_data) = result; + } + TU_VERIFY(result == XFER_RESULT_SUCCESS); + p_cdc->line.coding = p_cdc->requested_line.coding; // update data format + } } - return ret; + return true; } //--------------------------------------------------------------------+ @@ -809,41 +751,50 @@ static bool open_ep_stream_pair(cdch_interface_t *p_cdc, tusb_desc_endpoint_t co bool cdch_open(uint8_t rhport, uint8_t daddr, tusb_desc_interface_t const *itf_desc, uint16_t max_len) { (void) rhport; - cdch_serial_driver_t const *driver_detected = NULL; - // 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) { return acm_open(daddr, itf_desc, max_len); - } 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)); - - 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) { - driver_detected = driver; - break; + } 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)); + + for (size_t dr = 1; dr < SERIAL_DRIVER_COUNT; dr++) { + const cdch_serial_driver_t *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) { + const bool ret = driver->open(daddr, itf_desc, max_len); + TU_LOG_DRV("[:%u:%u] CDCh %s open %s\r\n", daddr, itf_desc->bInterfaceNumber, driver->name, ret ? "OK" : "FAILED"); + return ret; + } + } } - } - if (driver_detected) { - break; - } - } - } - - if (driver_detected) { - const bool ret = driver_detected->open(daddr, itf_desc, max_len); - TU_LOG_DRV("[:%u:%u] CDCh %s open %s\r\n", daddr, itf_desc->bInterfaceNumber, driver_detected->name, ret ? "OK" : "FAILED"); - return ret; - } + } return false; } +bool cdch_set_config(uint8_t daddr, uint8_t itf_num) { + tusb_control_request_t request; + request.wIndex = tu_htole16((uint16_t) itf_num); + uint8_t const idx = tuh_cdc_itf_get_index(daddr, itf_num); + cdch_interface_t *p_cdc = get_itf(idx); + TU_ASSERT(p_cdc && p_cdc->serial_drid < SERIAL_DRIVER_COUNT); + TU_LOG_CDC(p_cdc, "set config"); + + // fake transfer to kick-off process_set_config() + tuh_xfer_t xfer; + xfer.daddr = daddr; + xfer.result = XFER_RESULT_SUCCESS; + xfer.setup = &request; + xfer.user_data = 0; // initial state 0 + cdch_process_set_config(&xfer); + + return true; +} + static void set_config_complete(cdch_interface_t *p_cdc, uint8_t itf_offset, bool success) { if (success) { const uint8_t idx = get_idx_by_ptr(p_cdc); @@ -863,43 +814,81 @@ static void set_config_complete(cdch_interface_t *p_cdc, uint8_t itf_offset, boo usbh_driver_set_config_complete(p_cdc->daddr, p_cdc->bInterfaceNumber + itf_offset); } -bool cdch_set_config(uint8_t daddr, uint8_t itf_num) { - tusb_control_request_t request; - request.wIndex = tu_htole16((uint16_t) itf_num); - uint8_t const idx = tuh_cdc_itf_get_index(daddr, itf_num); - cdch_interface_t *p_cdc = get_itf(idx); - TU_ASSERT(p_cdc && p_cdc->serial_drid < SERIAL_DRIVER_COUNT); - TU_LOG_CDC(p_cdc, "set config"); +static void cdch_process_set_config(tuh_xfer_t *xfer) { + cdch_interface_t *p_cdc = get_itf_by_xfer(xfer); + TU_ASSERT(p_cdc && p_cdc->serial_drid < SERIAL_DRIVER_COUNT,); + TU_LOG_DRV(" state = %u\r\n", xfer->user_data); + const cdch_serial_driver_t *driver = &serial_drivers[p_cdc->serial_drid]; - // fake transfer to kick-off process_set_config() - tuh_xfer_t xfer; - xfer.daddr = daddr; - xfer.result = XFER_RESULT_SUCCESS; - xfer.setup = &request; - xfer.user_data = 0; // initial state 0 - cdch_process_set_config(&xfer); + if (!driver->process_set_config(p_cdc, xfer)) { + const uint8_t itf_offset = (p_cdc->serial_drid == SERIAL_DRIVER_ACM) ? 1 : 0; + set_config_complete(p_cdc, itf_offset, false); + } +} + +static bool set_line_state_on_enum(cdch_interface_t *p_cdc, tuh_xfer_t *xfer) { + enum { + ENUM_SET_LINE_CODING = 0, + ENUM_SET_LINE_CONTROL, + ENUM_SET_LINE_COMPLETE, + }; + const uint8_t idx = get_idx_by_ptr(p_cdc); + const uintptr_t state = xfer->user_data; + + switch (state) { + case ENUM_SET_LINE_CODING: { + #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM + // ch34x already set line coding in serial init + if (p_cdc->serial_drid != SERIAL_DRIVER_CH34X) { + const cdc_line_coding_t line_coding = (cdc_line_coding_t) CFG_TUH_CDC_LINE_CODING_ON_ENUM; + TU_ASSERT(tuh_cdc_set_line_coding(idx, &line_coding, + cdch_process_line_state_on_enum, ENUM_SET_LINE_CONTROL)); + break; + } + #endif + TU_ATTR_FALLTHROUGH; + } + + case ENUM_SET_LINE_CONTROL: + #ifdef CFG_TUH_CDC_LINE_CONTROL_ON_ENUM + TU_ASSERT(tuh_cdc_set_control_line_state(idx, CFG_TUH_CDC_LINE_CONTROL_ON_ENUM, + cdch_process_line_state_on_enum, ENUM_SET_LINE_COMPLETE)); + break; + #else + TU_ATTR_FALLTHROUGH; + #endif + + case ENUM_SET_LINE_COMPLETE: { + const uint8_t itf_offset = (p_cdc->serial_drid == SERIAL_DRIVER_ACM) ? 1 : 0; + set_config_complete(p_cdc, itf_offset, true); + break; + } + + default: + return false; + } return true; } - -static void cdch_process_set_config(tuh_xfer_t *xfer) { +static void cdch_process_line_state_on_enum(tuh_xfer_t *xfer) { cdch_interface_t *p_cdc = get_itf_by_xfer(xfer); TU_ASSERT(p_cdc && p_cdc->serial_drid < SERIAL_DRIVER_COUNT,); - TU_LOG_DRV(" state = %u\r\n", xfer->user_data); + TU_LOG_DRV(" xfer result = %u\r\n", xfer->result); - if (!serial_drivers[p_cdc->serial_drid].process_set_config(p_cdc, xfer)) { + if (xfer->result != XFER_RESULT_SUCCESS || !set_line_state_on_enum(p_cdc, xfer)) { const uint8_t itf_offset = (p_cdc->serial_drid == SERIAL_DRIVER_ACM) ? 1 : 0; set_config_complete(p_cdc, itf_offset, false); } } + static void cdch_internal_control_complete(tuh_xfer_t *xfer) { cdch_interface_t *p_cdc = get_itf_by_xfer(xfer); TU_ASSERT(p_cdc && p_cdc->serial_drid < SERIAL_DRIVER_COUNT,); - TU_LOG_DRV(" request result = %u\r\n", xfer->result); - serial_drivers[p_cdc->serial_drid].request_complete(p_cdc, xfer); + const cdch_serial_driver_t *driver = &serial_drivers[p_cdc->serial_drid]; + driver->request_complete(p_cdc, xfer); // Invoke application callback xfer->complete_cb = p_cdc->user_complete_cb; @@ -908,6 +897,38 @@ static void cdch_internal_control_complete(tuh_xfer_t *xfer) { } } +static void cdch_set_line_coding_stage1_baudrate_complete(tuh_xfer_t *xfer) { + cdch_interface_t *p_cdc = get_itf_by_xfer(xfer); + TU_ASSERT(p_cdc && p_cdc->serial_drid < SERIAL_DRIVER_COUNT,); + TU_LOG_DRV(" stage1 set baudrate result = %u\r\n", xfer->result); + const cdch_serial_driver_t *driver = &serial_drivers[p_cdc->serial_drid]; + + if (xfer->result == XFER_RESULT_SUCCESS) { + p_cdc->line.coding.bit_rate = p_cdc->requested_line.coding.bit_rate; // update baudrate + TU_ASSERT(driver->set_data_format(p_cdc, cdch_set_line_coding_stage2_data_format_complete, xfer->user_data),); + } else { + xfer->complete_cb = p_cdc->user_complete_cb; + if (xfer->complete_cb) { + xfer->complete_cb(xfer); + } + } +} + +static void cdch_set_line_coding_stage2_data_format_complete(tuh_xfer_t *xfer) { + cdch_interface_t *p_cdc = get_itf_by_xfer(xfer); + TU_ASSERT(p_cdc && p_cdc->serial_drid < SERIAL_DRIVER_COUNT,); + TU_LOG_DRV(" stage2 set data format result = %u\r\n", xfer->result); + + if (xfer->result == XFER_RESULT_SUCCESS) { + p_cdc->line.coding = p_cdc->requested_line.coding; // update data format + } + + xfer->complete_cb = p_cdc->user_complete_cb; + if (xfer->complete_cb) { + xfer->complete_cb(xfer); + } +} + //--------------------------------------------------------------------+ // ACM //--------------------------------------------------------------------+ @@ -1000,16 +1021,10 @@ static bool acm_set_line_coding(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_ } static bool acm_set_data_format(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - p_cdc->requested_line.coding.bit_rate = p_cdc->line.coding.bit_rate; - return acm_set_line_coding(p_cdc, complete_cb, user_data); } static bool acm_set_baudrate(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - p_cdc->requested_line.coding.stop_bits = p_cdc->line.coding.stop_bits; - p_cdc->requested_line.coding.parity = p_cdc->line.coding.parity; - p_cdc->requested_line.coding.data_bits = p_cdc->line.coding.data_bits; - return acm_set_line_coding(p_cdc, complete_cb, user_data); } @@ -1108,7 +1123,6 @@ static bool acm_process_set_config(cdch_interface_t *p_cdc, tuh_xfer_t *xfer) { static bool ftdi_determine_type(cdch_interface_t *p_cdc); static uint32_t ftdi_get_divisor(cdch_interface_t *p_cdc); -static uint8_t ftdi_get_idx(tuh_xfer_t *xfer); //------------- Control Request -------------// @@ -1150,29 +1164,6 @@ static inline bool ftdi_sio_reset(cdch_interface_t *p_cdc, tuh_xfer_cb_t complet p_cdc->ftdi.channel, complete_cb, user_data); } -static bool ftdi_change_speed(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - uint32_t index_value = ftdi_get_divisor(p_cdc); - TU_VERIFY(index_value); - uint16_t value = (uint16_t) index_value; - uint16_t index = (uint16_t) (index_value >> 16); - if (p_cdc->ftdi.channel) { - index = (uint16_t) ((index << 8) | p_cdc->ftdi.channel); - } - - return ftdi_set_request(p_cdc, FTDI_SIO_SET_BAUDRATE_REQUEST, FTDI_SIO_SET_BAUDRATE_REQUEST_TYPE, - value, index, complete_cb, user_data); -} - -static bool ftdi_set_data_request(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - TU_VERIFY(p_cdc->requested_line.coding.data_bits >= 7 && p_cdc->requested_line.coding.data_bits <= 8, 0); - uint16_t value = (uint16_t) ((p_cdc->requested_line.coding.data_bits & 0xfUL) | // data bit quantity is stored in bits 0-3 - (p_cdc->requested_line.coding.parity & 0x7UL) << 8 | // parity is stored in bits 8-10, same coding - (p_cdc->requested_line.coding.stop_bits & 0x3UL) << 11); // stop bits quantity is stored in bits 11-12, same coding - // not each FTDI supports 1.5 stop bits - - return ftdi_set_request(p_cdc, FTDI_SIO_SET_DATA_REQUEST, FTDI_SIO_SET_DATA_REQUEST_TYPE, - value, p_cdc->ftdi.channel, complete_cb, user_data); -} //------------- Driver API -------------// @@ -1199,41 +1190,31 @@ static void ftdi_internal_control_complete(cdch_interface_t* p_cdc, tuh_xfer_t * } static bool ftdi_set_data_format(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - p_cdc->user_complete_cb = complete_cb; - TU_ASSERT(ftdi_set_data_request(p_cdc, complete_cb ? cdch_internal_control_complete : NULL, user_data)); - return true; + TU_VERIFY(p_cdc->requested_line.coding.data_bits >= 7 && p_cdc->requested_line.coding.data_bits <= 8, 0); + uint16_t value = (uint16_t) ((p_cdc->requested_line.coding.data_bits & 0xfUL) | // data bit quantity is stored in bits 0-3 + (p_cdc->requested_line.coding.parity & 0x7UL) << 8 | // parity is stored in bits 8-10, same coding + (p_cdc->requested_line.coding.stop_bits & 0x3UL) << 11); // stop bits quantity is stored in bits 11-12, same coding + // not each FTDI supports 1.5 stop bits + return ftdi_set_request(p_cdc, FTDI_SIO_SET_DATA_REQUEST, FTDI_SIO_SET_DATA_REQUEST_TYPE, + value, p_cdc->ftdi.channel, complete_cb, user_data); } static bool ftdi_set_baudrate(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - p_cdc->user_complete_cb = complete_cb; - TU_ASSERT(ftdi_change_speed(p_cdc, complete_cb ? cdch_internal_control_complete : NULL, user_data)); - return true; -} - -static void ftdi_set_line_coding_stage1_complete(tuh_xfer_t *xfer) { - uint8_t const idx = ftdi_get_idx(xfer); - cdch_interface_t *p_cdc = get_itf(idx); - TU_ASSERT(p_cdc, ); - uint8_t const itf_num = p_cdc->bInterfaceNumber; - set_line_coding_stage1_complete(xfer, itf_num, - ftdi_set_data_request, // control request function to set data format - cdch_internal_control_complete); // control complete function to be called after request -} + uint32_t index_value = ftdi_get_divisor(p_cdc); + TU_VERIFY(index_value); + uint16_t value = (uint16_t) index_value; + uint16_t index = (uint16_t) (index_value >> 16); + if (p_cdc->ftdi.channel) { + index = (uint16_t) ((index << 8) | p_cdc->ftdi.channel); + } -// 2 stages: set baudrate (stage1) + set data format (stage2) -static bool ftdi_set_line_coding(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - return set_line_coding_sequence(p_cdc, - ftdi_change_speed, // control request function to set baudrate - ftdi_set_data_request, // control request function to set data format - ftdi_set_line_coding_stage1_complete, // function to be called after stage 1 completed - cdch_internal_control_complete, // control complete function to be called after request - complete_cb, user_data); + return ftdi_set_request(p_cdc, FTDI_SIO_SET_BAUDRATE_REQUEST, FTDI_SIO_SET_BAUDRATE_REQUEST_TYPE, + value, index, complete_cb, user_data); } static bool ftdi_set_modem_ctrl(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { uint16_t line_state = (uint16_t) ((p_cdc->requested_line.control_state.dtr ? FTDI_SIO_SET_DTR_HIGH : FTDI_SIO_SET_DTR_LOW) | (p_cdc->requested_line.control_state.rts ? FTDI_SIO_SET_RTS_HIGH : FTDI_SIO_SET_RTS_LOW)); - p_cdc->user_complete_cb = complete_cb; return ftdi_set_request(p_cdc, FTDI_SIO_SET_MODEM_CTRL_REQUEST, FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE, line_state, p_cdc->ftdi.channel, complete_cb ? cdch_internal_control_complete : NULL, user_data); } @@ -1243,10 +1224,7 @@ enum { CONFIG_FTDI_DETERMINE_TYPE = 0, CONFIG_FTDI_WRITE_LATENCY, CONFIG_FTDI_SIO_RESET, - CONFIG_FTDI_SET_DATA, - CONFIG_FTDI_SET_BAUDRATE, CONFIG_FTDI_FLOW_CONTROL, - CONFIG_FTDI_MODEM_CTRL, CONFIG_FTDI_COMPLETE }; @@ -1305,48 +1283,20 @@ static bool ftdi_proccess_set_config(cdch_interface_t *p_cdc, tuh_xfer_t *xfer) // from here sequence overtaken from Linux Kernel function ftdi_open() case CONFIG_FTDI_SIO_RESET: - p_cdc->user_complete_cb = cdch_process_set_config; - TU_ASSERT(ftdi_sio_reset(p_cdc, cdch_process_set_config, CONFIG_FTDI_SET_DATA)); - break; - - // from here sequence overtaken from Linux Kernel function ftdi_set_termios() - case CONFIG_FTDI_SET_DATA: - #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM - p_cdc->requested_line.coding = (cdc_line_coding_t) CFG_TUH_CDC_LINE_CODING_ON_ENUM; - p_cdc->user_complete_cb = cdch_process_set_config; - TU_ASSERT(ftdi_set_data_request(p_cdc, cdch_internal_control_complete, CONFIG_FTDI_SET_BAUDRATE)); - break; - #else - TU_ATTR_FALLTHROUGH; - #endif - - case CONFIG_FTDI_SET_BAUDRATE: - #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM - p_cdc->user_complete_cb = cdch_process_set_config; - TU_ASSERT(ftdi_change_speed(p_cdc, cdch_internal_control_complete, CONFIG_FTDI_FLOW_CONTROL)); + TU_ASSERT(ftdi_sio_reset(p_cdc, cdch_process_set_config, CONFIG_FTDI_FLOW_CONTROL)); break; - #else - TU_ATTR_FALLTHROUGH; - #endif case CONFIG_FTDI_FLOW_CONTROL: // disable flow control TU_ASSERT(ftdi_set_request(p_cdc, FTDI_SIO_SET_FLOW_CTRL_REQUEST, FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE, FTDI_SIO_DISABLE_FLOW_CTRL, - p_cdc->ftdi.channel, cdch_process_set_config, CONFIG_FTDI_MODEM_CTRL)); + p_cdc->ftdi.channel, cdch_process_set_config, CONFIG_FTDI_COMPLETE)); break; - case CONFIG_FTDI_MODEM_CTRL: - #ifdef CFG_TUH_CDC_LINE_CONTROL_ON_ENUM - p_cdc->requested_line.control_state.value = CFG_TUH_CDC_LINE_CONTROL_ON_ENUM; - TU_ASSERT(ftdi_set_modem_ctrl(p_cdc, cdch_process_set_config, CONFIG_FTDI_COMPLETE)); - break; - #else - TU_ATTR_FALLTHROUGH; - #endif - - case CONFIG_FTDI_COMPLETE: - set_config_complete(p_cdc, 0, true); + case CONFIG_FTDI_COMPLETE: { + xfer->user_data = 0; // kick-off set line state on enum + cdch_process_line_state_on_enum(xfer); break; + } default: return false; @@ -1562,20 +1512,6 @@ static inline uint32_t ftdi_get_divisor(cdch_interface_t *p_cdc) { return div_value; } -static uint8_t ftdi_get_idx(tuh_xfer_t *xfer) { - uint8_t const channel = (uint8_t) tu_le16toh(xfer->setup->wIndex);// channel index, or 0 for legacy types - 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 && - (!p_cdc->ftdi.channel || // 0 for legacy types (only interface 0) - channel == p_cdc->ftdi.channel)) {// or multi-channel types (interfaces 0..n) - return i; - } - } - - return TUSB_INDEX_INVALID_8; -} - #endif //--------------------------------------------------------------------+ @@ -1619,32 +1555,14 @@ static bool cp210x_set_request(cdch_interface_t * p_cdc, uint8_t command, uint16 return tuh_control_xfer(&xfer); } -static inline bool cp210x_ifc_enable(cdch_interface_t *p_cdc, uint16_t enabled, - tuh_xfer_cb_t complete_cb, uintptr_t user_data) { +TU_ATTR_ALWAYS_INLINE static inline bool cp210x_ifc_enable(cdch_interface_t *p_cdc, uint16_t enabled, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { return cp210x_set_request(p_cdc, CP210X_IFC_ENABLE, enabled, NULL, 0, complete_cb, user_data); } -static bool cp210x_set_baudrate_request(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - // Not every baud rate is supported. See datasheets and AN205 "CP210x Baud Rate Support" - uint32_t baud_le = tu_htole32(p_cdc->requested_line.coding.bit_rate); - - return cp210x_set_request(p_cdc, CP210X_SET_BAUDRATE, 0, (uint8_t *) &baud_le, 4, complete_cb, user_data); -} - -static bool cp210x_set_line_ctl(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - TU_VERIFY(p_cdc->requested_line.coding.data_bits >= 5 && p_cdc->requested_line.coding.data_bits <= 8, 0); - uint16_t lcr = (uint16_t) ((p_cdc->requested_line.coding.data_bits & 0xfUL) << 8 | // data bit quantity is stored in bits 8-11 - (p_cdc->requested_line.coding.parity & 0xfUL) << 4 | // parity is stored in bits 4-7, same coding - (p_cdc->requested_line.coding.stop_bits & 0xfUL)); // parity is stored in bits 0-3, same coding - - return cp210x_set_request(p_cdc, CP210X_SET_LINE_CTL, lcr, NULL, 0, complete_cb, user_data); -} - -static inline bool cp210x_set_mhs(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { +TU_ATTR_ALWAYS_INLINE static inline bool cp210x_set_mhs(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { // CP210x has the same bit coding return cp210x_set_request(p_cdc, CP210X_SET_MHS, - (uint16_t) (CP210X_CONTROL_WRITE_DTR | CP210X_CONTROL_WRITE_RTS | - p_cdc->requested_line.control_state.value), + (uint16_t) (CP210X_CONTROL_WRITE_DTR | CP210X_CONTROL_WRITE_RTS | p_cdc->requested_line.control_state.value), NULL, 0, complete_cb, user_data); } @@ -1673,47 +1591,28 @@ static void cp210x_internal_control_complete(cdch_interface_t *p_cdc, tuh_xfer_t } static bool cp210x_set_baudrate(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - p_cdc->user_complete_cb = complete_cb; - TU_ASSERT(cp210x_set_baudrate_request(p_cdc, complete_cb ? cdch_internal_control_complete : NULL, user_data)); - return true; + // Not every baud rate is supported. See datasheets and AN205 "CP210x Baud Rate Support" + uint32_t baud_le = tu_htole32(p_cdc->requested_line.coding.bit_rate); + return cp210x_set_request(p_cdc, CP210X_SET_BAUDRATE, 0, (uint8_t *) &baud_le, 4, complete_cb, user_data); } static bool cp210x_set_data_format(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - p_cdc->user_complete_cb = complete_cb; - TU_ASSERT(cp210x_set_line_ctl(p_cdc, complete_cb ? cdch_internal_control_complete : NULL, user_data)); - return true; -} - -static void cp210x_set_line_coding_stage1_complete(tuh_xfer_t *xfer) { - uint8_t const itf_num = (uint8_t) tu_le16toh(xfer->setup->wIndex); - set_line_coding_stage1_complete(xfer, itf_num, - cp210x_set_line_ctl, // control request function to set data format - cdch_internal_control_complete); // control complete function to be called after request -} + TU_VERIFY(p_cdc->requested_line.coding.data_bits >= 5 && p_cdc->requested_line.coding.data_bits <= 8, 0); + uint16_t lcr = (uint16_t) ((p_cdc->requested_line.coding.data_bits & 0xfUL) << 8 | // data bit quantity is stored in bits 8-11 + (p_cdc->requested_line.coding.parity & 0xfUL) << 4 | // parity is stored in bits 4-7, same coding + (p_cdc->requested_line.coding.stop_bits & 0xfUL)); // parity is stored in bits 0-3, same coding -// 2 stages: set baudrate (stage1) + set data format (stage2) -static bool cp210x_set_line_coding(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - return set_line_coding_sequence(p_cdc, - cp210x_set_baudrate_request, // control request function to set baudrate - cp210x_set_line_ctl, // control request function to set data format - cp210x_set_line_coding_stage1_complete, // function to be called after stage 1 completed - cdch_internal_control_complete, // control complete function to be called after request - complete_cb, user_data); + return cp210x_set_request(p_cdc, CP210X_SET_LINE_CTL, lcr, NULL, 0, complete_cb, user_data); } static bool cp210x_set_modem_ctrl(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - p_cdc->user_complete_cb = complete_cb; - TU_ASSERT(cp210x_set_mhs(p_cdc, complete_cb ? cdch_internal_control_complete : NULL, user_data)); - return true; + return cp210x_set_mhs(p_cdc, complete_cb, user_data); } //------------- Enumeration -------------// enum { CONFIG_CP210X_IFC_ENABLE = 0, - CONFIG_CP210X_SET_BAUDRATE_REQUEST, - CONFIG_CP210X_SET_LINE_CTL, - CONFIG_CP210X_SET_DTR_RTS, CONFIG_CP210X_COMPLETE }; @@ -1740,40 +1639,12 @@ static bool cp210x_process_set_config(cdch_interface_t *p_cdc, tuh_xfer_t *xfer) switch (state) { case CONFIG_CP210X_IFC_ENABLE: - TU_ASSERT(cp210x_ifc_enable(p_cdc, CP210X_UART_ENABLE, cdch_process_set_config, CONFIG_CP210X_SET_BAUDRATE_REQUEST)); + TU_ASSERT(cp210x_ifc_enable(p_cdc, CP210X_UART_ENABLE, cdch_process_set_config, CONFIG_CP210X_COMPLETE)); break; - case CONFIG_CP210X_SET_BAUDRATE_REQUEST: - #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM - p_cdc->requested_line.coding = (cdc_line_coding_t) CFG_TUH_CDC_LINE_CODING_ON_ENUM; - p_cdc->user_complete_cb = cdch_process_set_config; - TU_ASSERT(cp210x_set_baudrate_request(p_cdc, cdch_internal_control_complete, CONFIG_CP210X_SET_LINE_CTL)); - break; - #else - TU_ATTR_FALLTHROUGH; - #endif - - case CONFIG_CP210X_SET_LINE_CTL: - #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM - p_cdc->user_complete_cb = cdch_process_set_config; - TU_ASSERT(cp210x_set_line_ctl(p_cdc, cdch_internal_control_complete, CONFIG_CP210X_SET_DTR_RTS)); - break; - #else - TU_ATTR_FALLTHROUGH; - #endif - - case CONFIG_CP210X_SET_DTR_RTS: - #ifdef CFG_TUH_CDC_LINE_CONTROL_ON_ENUM - p_cdc->requested_line.control_state.value = CFG_TUH_CDC_LINE_CONTROL_ON_ENUM; - p_cdc->user_complete_cb = cdch_process_set_config; - TU_ASSERT(cp210x_set_mhs(p_cdc, cdch_internal_control_complete, CONFIG_CP210X_COMPLETE)); - break; - #else - TU_ATTR_FALLTHROUGH; - #endif - case CONFIG_CP210X_COMPLETE: - set_config_complete(p_cdc, 0, true); + xfer->user_data = 0;// kick-off set line state on enum + cdch_process_line_state_on_enum(xfer); break; default: @@ -1833,19 +1704,19 @@ static bool ch34x_set_request(cdch_interface_t *p_cdc, uint8_t direction, uint8_ return tuh_control_xfer(&xfer); } -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) { +TU_ATTR_ALWAYS_INLINE 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 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) { +TU_ATTR_ALWAYS_INLINE 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); } -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) { +TU_ATTR_ALWAYS_INLINE 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); } @@ -1855,25 +1726,6 @@ static inline bool ch34x_write_reg(cdch_interface_t *p_cdc, uint16_t reg, uint16 // return ch34x_control_in ( p_cdc, CH34X_REQ_READ_REG, reg, 0, buffer, buffersize, complete_cb, user_data ); //} -static bool ch34x_write_reg_data_format(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - uint8_t const lcr = ch34x_get_lcr(p_cdc); - TU_VERIFY(lcr); - return ch34x_write_reg(p_cdc, CH32X_REG16_LCR2_LCR, lcr, complete_cb, user_data); -} - -static bool ch34x_write_reg_baudrate(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - uint16_t const div_ps = ch34x_get_divisor_prescaler(p_cdc); - TU_VERIFY(div_ps); - return ch34x_write_reg(p_cdc, CH34X_REG16_DIVISOR_PRESCALER, div_ps, complete_cb, user_data); -} - -static bool ch34x_modem_ctrl_request(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - // CH34x signals are inverted - uint8_t control = ~((p_cdc->requested_line.control_state.rts ? CH34X_BIT_RTS : 0) | - (p_cdc->requested_line.control_state.dtr ? CH34X_BIT_DTR : 0)); - return ch34x_control_out(p_cdc, CH34X_REQ_MODEM_CTRL, control, 0, complete_cb, user_data); -} - //------------- Driver API -------------// // internal control complete to update state such as line state, encoding @@ -1908,39 +1760,22 @@ static void ch34x_internal_control_complete(cdch_interface_t *p_cdc, tuh_xfer_t } static bool ch34x_set_data_format(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - p_cdc->user_complete_cb = complete_cb; - TU_ASSERT(ch34x_write_reg_data_format(p_cdc, complete_cb ? cdch_internal_control_complete : NULL, user_data)); - return true; + const uint8_t lcr = ch34x_get_lcr(p_cdc); + TU_VERIFY(lcr); + return ch34x_write_reg(p_cdc, CH32X_REG16_LCR2_LCR, lcr, complete_cb, user_data); } static bool ch34x_set_baudrate(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - p_cdc->user_complete_cb = complete_cb; - TU_ASSERT(ch34x_write_reg_baudrate(p_cdc, complete_cb ? cdch_internal_control_complete : NULL, user_data)); - return true; -} - -static void ch34x_set_line_coding_stage1_complete(tuh_xfer_t *xfer) { - // CH34x has only interface 0, because wIndex is used as payload and not for bInterfaceNumber - uint8_t const itf_num = 0; - set_line_coding_stage1_complete(xfer, itf_num, - ch34x_write_reg_data_format, // control request function to set data format - cdch_internal_control_complete); // control complete function to be called after request -} - -// 2 stages: set baudrate (stage1) + set data format (stage2) -static bool ch34x_set_line_coding(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - return set_line_coding_sequence(p_cdc, - ch34x_write_reg_baudrate, // control request function to set baudrate - ch34x_write_reg_data_format, // control request function to set data format - ch34x_set_line_coding_stage1_complete, // function to be called after stage 1 completed - cdch_internal_control_complete, // control complete function to be called after request - complete_cb, user_data); + const uint16_t div_ps = ch34x_get_divisor_prescaler(p_cdc); + TU_VERIFY(div_ps); + return ch34x_write_reg(p_cdc, CH34X_REG16_DIVISOR_PRESCALER, div_ps, complete_cb, user_data); } static bool ch34x_set_modem_ctrl(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - p_cdc->user_complete_cb = complete_cb; - TU_ASSERT(ch34x_modem_ctrl_request(p_cdc, complete_cb ? cdch_internal_control_complete : NULL, user_data)); - return true; + // CH34x signals are inverted + uint8_t control = ~((p_cdc->requested_line.control_state.rts ? CH34X_BIT_RTS : 0) | + (p_cdc->requested_line.control_state.dtr ? CH34X_BIT_DTR : 0)); + return ch34x_control_out(p_cdc, CH34X_REQ_MODEM_CTRL, control, 0, complete_cb, user_data); } //------------- Enumeration -------------// @@ -1950,7 +1785,6 @@ enum { CONFIG_CH34X_SERIAL_INIT, CONFIG_CH34X_SPECIAL_REG_WRITE, CONFIG_CH34X_FLOW_CONTROL, - CONFIG_CH34X_MODEM_CONTROL, CONFIG_CH34X_COMPLETE }; @@ -2018,25 +1852,16 @@ static bool ch34x_process_set_config(cdch_interface_t *p_cdc, tuh_xfer_t *xfer) case CONFIG_CH34X_FLOW_CONTROL: // no hardware flow control TU_ASSERT(ch34x_write_reg(p_cdc, TU_U16(CH341_REG_0x27, CH341_REG_0x27), 0x0000, - cdch_process_set_config, CONFIG_CH34X_MODEM_CONTROL)); + cdch_process_set_config, CONFIG_CH34X_COMPLETE)); break; - case CONFIG_CH34X_MODEM_CONTROL: - #ifdef CFG_TUH_CDC_LINE_CONTROL_ON_ENUM - p_cdc->requested_line.control_state.value = CFG_TUH_CDC_LINE_CONTROL_ON_ENUM; - p_cdc->user_complete_cb = cdch_process_set_config; - TU_ASSERT(ch34x_modem_ctrl_request(p_cdc, cdch_internal_control_complete, CONFIG_CH34X_COMPLETE)); - break; - #else - TU_ATTR_FALLTHROUGH; - #endif - case CONFIG_CH34X_COMPLETE: - set_config_complete(p_cdc, 0, true); + xfer->user_data = 0; // kick-off set line state on enum + cdch_process_line_state_on_enum(xfer); break; default: - break; + return false; } return true; diff --git a/src/class/cdc/serial/ch34x.h b/src/class/cdc/serial/ch34x.h index 7d91f01fe..0e08b0acd 100644 --- a/src/class/cdc/serial/ch34x.h +++ b/src/class/cdc/serial/ch34x.h @@ -34,9 +34,9 @@ // 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 + #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 } + #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 -- cgit v1.3.1 From f4d049e61ba12c8ba6fcd23c18fe5089ff899186 Mon Sep 17 00:00:00 2001 From: hathach Date: Fri, 27 Jun 2025 17:05:49 +0700 Subject: update acm and pl2303 to match the rest of drivers --- src/class/cdc/cdc_host.c | 218 +++++++++++++---------------------------------- 1 file changed, 59 insertions(+), 159 deletions(-) (limited to 'src/class') diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index 7926aa9fc..81337cde4 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -117,8 +117,6 @@ static bool acm_open(uint8_t daddr, tusb_desc_interface_t const * itf_desc, uint static bool acm_process_set_config(cdch_interface_t *p_cdc, tuh_xfer_t *xfer); static void acm_internal_control_complete(cdch_interface_t *p_cdc, tuh_xfer_t *xfer); -static bool acm_set_baudrate(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); -static bool acm_set_data_format(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); static bool acm_set_line_coding(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); static bool acm_set_control_line_state(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); @@ -169,8 +167,6 @@ static bool pl2303_open(uint8_t daddr, tusb_desc_interface_t const * itf_desc, u static bool pl2303_process_set_config(cdch_interface_t *p_cdc, tuh_xfer_t *xfer); static void pl2303_internal_control_complete(cdch_interface_t *p_cdc, tuh_xfer_t *xfer); -static bool pl2303_set_baudrate(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); -static bool pl2303_set_data_format(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); static bool pl2303_set_line_coding(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); static bool pl2303_set_modem_ctrl(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); #endif @@ -228,10 +224,9 @@ static const cdch_serial_driver_t serial_drivers[] = { .open = acm_open, .process_set_config = acm_process_set_config, .request_complete = acm_internal_control_complete, - .set_control_line_state = acm_set_control_line_state, - .set_baudrate = acm_set_baudrate, - .set_data_format = acm_set_data_format, + .set_baudrate = acm_set_line_coding, + .set_data_format = acm_set_line_coding, .set_line_coding = acm_set_line_coding, DRIVER_NAME_DECLARE("ACM") }, @@ -290,8 +285,8 @@ static const cdch_serial_driver_t serial_drivers[] = { .process_set_config = pl2303_process_set_config, .request_complete = pl2303_internal_control_complete, .set_control_line_state = pl2303_set_modem_ctrl, - .set_baudrate = pl2303_set_baudrate, - .set_data_format = pl2303_set_data_format, + .set_baudrate = pl2303_set_line_coding, + .set_data_format = pl2303_set_line_coding, .set_line_coding = pl2303_set_line_coding, DRIVER_NAME_DECLARE("PL2303") } @@ -586,10 +581,11 @@ bool tuh_cdc_set_line_coding(uint8_t idx, cdc_line_coding_t const *line_coding, CDC_LINE_CODING_STOP_BITS_TEXT(line_coding->stop_bits)); cdch_serial_driver_t const *driver = &serial_drivers[p_cdc->serial_drid]; p_cdc->requested_line.coding = *line_coding; + p_cdc->user_complete_cb = complete_cb; if (driver->set_line_coding) { // driver support set_line_coding request - TU_VERIFY(driver->set_line_coding(p_cdc, complete_cb, user_data)); + TU_VERIFY(driver->set_line_coding(p_cdc, complete_cb ? cdch_internal_control_complete : NULL, user_data)); if (!complete_cb) { p_cdc->line.coding = *line_coding; @@ -598,7 +594,6 @@ bool tuh_cdc_set_line_coding(uint8_t idx, cdc_line_coding_t const *line_coding, // driver does not support set_line_coding and need 2 stage to set baudrate and data format separately if (complete_cb) { // non-blocking - p_cdc->user_complete_cb = complete_cb; TU_VERIFY(driver->set_baudrate(p_cdc, cdch_set_line_coding_stage1_baudrate_complete, user_data)); } else { // blocking @@ -795,7 +790,7 @@ bool cdch_set_config(uint8_t daddr, uint8_t itf_num) { return true; } -static void set_config_complete(cdch_interface_t *p_cdc, uint8_t itf_offset, bool success) { +static void set_config_complete(cdch_interface_t *p_cdc, bool success) { if (success) { const uint8_t idx = get_idx_by_ptr(p_cdc); p_cdc->mounted = true; @@ -811,6 +806,7 @@ static void set_config_complete(cdch_interface_t *p_cdc, uint8_t itf_offset, boo } // notify usbh that driver enumeration is complete + const uint8_t itf_offset = (p_cdc->serial_drid == SERIAL_DRIVER_ACM) ? 1 : 0; usbh_driver_set_config_complete(p_cdc->daddr, p_cdc->bInterfaceNumber + itf_offset); } @@ -821,8 +817,7 @@ static void cdch_process_set_config(tuh_xfer_t *xfer) { const cdch_serial_driver_t *driver = &serial_drivers[p_cdc->serial_drid]; if (!driver->process_set_config(p_cdc, xfer)) { - const uint8_t itf_offset = (p_cdc->serial_drid == SERIAL_DRIVER_ACM) ? 1 : 0; - set_config_complete(p_cdc, itf_offset, false); + set_config_complete(p_cdc, false); } } @@ -858,11 +853,9 @@ static bool set_line_state_on_enum(cdch_interface_t *p_cdc, tuh_xfer_t *xfer) { TU_ATTR_FALLTHROUGH; #endif - case ENUM_SET_LINE_COMPLETE: { - const uint8_t itf_offset = (p_cdc->serial_drid == SERIAL_DRIVER_ACM) ? 1 : 0; - set_config_complete(p_cdc, itf_offset, true); + case ENUM_SET_LINE_COMPLETE: + set_config_complete(p_cdc, true); break; - } default: return false; @@ -874,11 +867,8 @@ static bool set_line_state_on_enum(cdch_interface_t *p_cdc, tuh_xfer_t *xfer) { static void cdch_process_line_state_on_enum(tuh_xfer_t *xfer) { cdch_interface_t *p_cdc = get_itf_by_xfer(xfer); TU_ASSERT(p_cdc && p_cdc->serial_drid < SERIAL_DRIVER_COUNT,); - TU_LOG_DRV(" xfer result = %u\r\n", xfer->result); - if (xfer->result != XFER_RESULT_SUCCESS || !set_line_state_on_enum(p_cdc, xfer)) { - const uint8_t itf_offset = (p_cdc->serial_drid == SERIAL_DRIVER_ACM) ? 1 : 0; - set_config_complete(p_cdc, itf_offset, false); + set_config_complete(p_cdc, false); } } @@ -967,20 +957,16 @@ static bool acm_set_control_line_state(cdch_interface_t *p_cdc, tuh_xfer_cb_t co .wLength = 0 }; - p_cdc->user_complete_cb = complete_cb; - tuh_xfer_t xfer = { .daddr = p_cdc->daddr, .ep_addr = 0, .setup = &request, .buffer = NULL, - .complete_cb = complete_cb ? cdch_internal_control_complete : NULL, + .complete_cb = complete_cb, .user_data = user_data }; - TU_ASSERT(tuh_control_xfer(&xfer)); - - return true; + return tuh_control_xfer(&xfer); } static bool acm_set_line_coding(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { @@ -1004,35 +990,21 @@ static bool acm_set_line_coding(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_ uint8_t *enum_buf = usbh_get_enum_buf(); memcpy(enum_buf, &p_cdc->requested_line.coding, sizeof(cdc_line_coding_t)); - p_cdc->user_complete_cb = complete_cb; - tuh_xfer_t xfer = { .daddr = p_cdc->daddr, .ep_addr = 0, .setup = &request, .buffer = enum_buf, - .complete_cb = complete_cb ? cdch_internal_control_complete : NULL, + .complete_cb = complete_cb, .user_data = user_data }; - TU_ASSERT(tuh_control_xfer(&xfer)); - - return true; -} - -static bool acm_set_data_format(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - return acm_set_line_coding(p_cdc, complete_cb, user_data); -} - -static bool acm_set_baudrate(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - return acm_set_line_coding(p_cdc, complete_cb, user_data); + return tuh_control_xfer(&xfer); } //------------- Enumeration -------------// enum { - CONFIG_ACM_SET_CONTROL_LINE_STATE = 0, - CONFIG_ACM_SET_LINE_CODING, - CONFIG_ACM_COMPLETE + CONFIG_ACM_COMPLETE = 0 }; static bool acm_open(uint8_t daddr, tusb_desc_interface_t const *itf_desc, uint16_t max_len) { @@ -1084,30 +1056,11 @@ static bool acm_process_set_config(cdch_interface_t *p_cdc, tuh_xfer_t *xfer) { TU_ASSERT(xfer->result == XFER_RESULT_SUCCESS); const uintptr_t state = xfer->user_data; switch (state) { - case CONFIG_ACM_SET_CONTROL_LINE_STATE: - #ifdef CFG_TUH_CDC_LINE_CONTROL_ON_ENUM - if (p_cdc->acm.capability.support_line_request) { - p_cdc->requested_line.control_state.value = CFG_TUH_CDC_LINE_CONTROL_ON_ENUM; - TU_ASSERT(acm_set_control_line_state(p_cdc, cdch_process_set_config, CONFIG_ACM_SET_LINE_CODING)); - break; - } - #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) { - p_cdc->requested_line.coding = (cdc_line_coding_t) CFG_TUH_CDC_LINE_CODING_ON_ENUM; - TU_ASSERT(acm_set_line_coding(p_cdc, cdch_process_set_config, CONFIG_ACM_COMPLETE)); - break; - } - #endif - TU_ATTR_FALLTHROUGH; - - case CONFIG_ACM_COMPLETE: - // itf_num+1 to account for data interface as well - set_config_complete(p_cdc, 1, true); + case CONFIG_ACM_COMPLETE: { + xfer->user_data = 0; // kick-off set line state on enum + cdch_process_line_state_on_enum(xfer); break; + } default: return false; // invalid state @@ -2023,18 +1976,40 @@ static inline bool pl2303_supports_hx_status(cdch_interface_t *p_cdc, tuh_xfer_c &buf, 1, complete_cb, user_data); } -static inline bool pl2303_set_control_lines(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - // PL2303 has the same bit coding - return pl2303_set_request(p_cdc, PL2303_SET_CONTROL_REQUEST, PL2303_SET_CONTROL_REQUEST_TYPE, - p_cdc->requested_line.control_state.value, 0, NULL, 0, complete_cb, user_data); -} - -//static bool pl2303_get_line_request(cdch_interface_t * p_cdc, uint8_t buf[PL2303_LINE_CODING_BUFSIZE]) -//{ +//static bool pl2303_get_line_request(cdch_interface_t * p_cdc, uint8_t buf[PL2303_LINE_CODING_BUFSIZE]) { // return pl2303_set_request(p_cdc, PL2303_GET_LINE_REQUEST, PL2303_GET_LINE_REQUEST_TYPE, 0, 0, buf, PL2303_LINE_CODING_BUFSIZE); //} -static bool pl2303_set_line_request(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { +//static bool pl2303_set_break(cdch_interface_t * p_cdc, bool enable) { +// uint16_t state = enable ? PL2303_BREAK_ON : PL2303_BREAK_OFF; +// return pl2303_set_request(p_cdc, PL2303_BREAK_REQUEST, PL2303_BREAK_REQUEST_TYPE, state, 0, NULL, 0); +//} + +static inline int pl2303_clear_halt(cdch_interface_t *p_cdc, uint8_t endp, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + /* we don't care if it wasn't halted first. in fact some devices + * (like some ibmcam model 1 units) seem to expect hosts to make + * this request for iso endpoints, which can't halt! + */ + return pl2303_set_request(p_cdc, TUSB_REQ_CLEAR_FEATURE, PL2303_CLEAR_HALT_REQUEST_TYPE, TUSB_REQ_FEATURE_EDPT_HALT, endp, + NULL, 0, complete_cb, user_data); +} + +//------------- Driver API -------------// + +// internal control complete to update state such as line state, encoding +static void pl2303_internal_control_complete(cdch_interface_t *p_cdc, tuh_xfer_t *xfer) { + TU_VERIFY(xfer->result == XFER_RESULT_SUCCESS,); + if (xfer->setup->bRequest == PL2303_SET_LINE_REQUEST && + xfer->setup->bmRequestType == PL2303_SET_LINE_REQUEST_TYPE) { + p_cdc->line.coding = p_cdc->requested_line.coding; + } + if (xfer->setup->bRequest == PL2303_SET_CONTROL_REQUEST && + xfer->setup->bmRequestType == PL2303_SET_CONTROL_REQUEST_TYPE) { + p_cdc->line.control_state = p_cdc->requested_line.control_state; + } +} + +static bool pl2303_set_line_coding(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { // the caller has to precheck, that the new line coding different than the current, else false returned uint8_t buf[PL2303_LINE_CODING_BUFSIZE]; /* @@ -2070,63 +2045,10 @@ static bool pl2303_set_line_request(cdch_interface_t *p_cdc, tuh_xfer_cb_t compl buf, PL2303_LINE_CODING_BUFSIZE, complete_cb, user_data); } -//static bool pl2303_set_break(cdch_interface_t * p_cdc, bool enable) -//{ -// uint16_t state = enable ? PL2303_BREAK_ON : PL2303_BREAK_OFF; -// return pl2303_set_request(p_cdc, PL2303_BREAK_REQUEST, PL2303_BREAK_REQUEST_TYPE, state, 0, NULL, 0); -//} - -static inline int pl2303_clear_halt(cdch_interface_t *p_cdc, uint8_t endp, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - /* we don't care if it wasn't halted first. in fact some devices - * (like some ibmcam model 1 units) seem to expect hosts to make - * this request for iso endpoints, which can't halt! - */ - return pl2303_set_request(p_cdc, TUSB_REQ_CLEAR_FEATURE, PL2303_CLEAR_HALT_REQUEST_TYPE, TUSB_REQ_FEATURE_EDPT_HALT, endp, - NULL, 0, complete_cb, user_data); -} - -//------------- Driver API -------------// - -// internal control complete to update state such as line state, encoding -static void pl2303_internal_control_complete(cdch_interface_t *p_cdc, tuh_xfer_t *xfer) { - TU_VERIFY(xfer->result == XFER_RESULT_SUCCESS,); - if (xfer->setup->bRequest == PL2303_SET_LINE_REQUEST && - xfer->setup->bmRequestType == PL2303_SET_LINE_REQUEST_TYPE) { - p_cdc->line.coding = p_cdc->requested_line.coding; - } - if (xfer->setup->bRequest == PL2303_SET_CONTROL_REQUEST && - xfer->setup->bmRequestType == PL2303_SET_CONTROL_REQUEST_TYPE) { - p_cdc->line.control_state = p_cdc->requested_line.control_state; - } -} - -static bool pl2303_set_line_coding(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - p_cdc->user_complete_cb = complete_cb; - TU_ASSERT(pl2303_set_line_request(p_cdc, complete_cb ? cdch_internal_control_complete : NULL, user_data)); - return true; -} - -static bool pl2303_set_data_format(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - p_cdc->requested_line.coding.bit_rate = p_cdc->line.coding.bit_rate; - p_cdc->user_complete_cb = complete_cb; - TU_ASSERT(pl2303_set_line_request(p_cdc, complete_cb ? cdch_internal_control_complete : NULL, user_data)); - return true; -} - -static bool pl2303_set_baudrate(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - p_cdc->requested_line.coding.stop_bits = p_cdc->line.coding.stop_bits; - p_cdc->requested_line.coding.parity = p_cdc->line.coding.parity; - p_cdc->requested_line.coding.data_bits = p_cdc->line.coding.data_bits; - p_cdc->user_complete_cb = complete_cb; - TU_ASSERT(pl2303_set_line_request(p_cdc, complete_cb ? cdch_internal_control_complete : NULL, user_data)); - return true; -} - static bool pl2303_set_modem_ctrl(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { // PL2303 has the same bit coding - p_cdc->user_complete_cb = complete_cb; - TU_ASSERT(pl2303_set_control_lines(p_cdc, complete_cb ? cdch_internal_control_complete : NULL, user_data)); - return true; + return pl2303_set_request(p_cdc, PL2303_SET_CONTROL_REQUEST, PL2303_SET_CONTROL_REQUEST_TYPE, + p_cdc->requested_line.control_state.value, 0, NULL, 0, complete_cb, user_data); } //------------- Enumeration -------------// @@ -2146,8 +2068,6 @@ enum { CONFIG_PL2303_WRITE5, CONFIG_PL2303_RESET_ENDP1, CONFIG_PL2303_RESET_ENDP2, - CONFIG_PL2303_LINE_CODING, - CONFIG_PL2303_MODEM_CONTROL, // CONFIG_PL2303_FLOW_CTRL_READ, // CONFIG_PL2303_FLOW_CTRL_WRITE, CONFIG_PL2303_COMPLETE @@ -2190,7 +2110,6 @@ static bool pl2303_process_set_config(cdch_interface_t *p_cdc, tuh_xfer_t *xfer) switch (state) { // from here sequence overtaken from Linux Kernel function pl2303_startup() case CONFIG_PL2303_DETECT_TYPE: - p_cdc->user_complete_cb = cdch_process_set_config;// set once for whole process config // get type and quirks (step 1) type = pl2303_detect_type(p_cdc, 1); TU_ASSERT(type != PL2303_TYPE_UNKNOWN); @@ -2313,7 +2232,7 @@ static bool pl2303_process_set_config(cdch_interface_t *p_cdc, tuh_xfer_t *xfer) if (p_cdc->pl2303.type == PL2303_TYPE_HXN) { TU_ASSERT(pl2303_vendor_write(p_cdc, PL2303_HXN_RESET_REG,// skip CONFIG_PL2303_RESET_ENDP2, no 2nd step PL2303_HXN_RESET_UPSTREAM_PIPE | PL2303_HXN_RESET_DOWNSTREAM_PIPE, - cdch_process_set_config, CONFIG_PL2303_LINE_CODING)); + cdch_process_set_config, CONFIG_PL2303_COMPLETE)); } else { pl2303_vendor_write(p_cdc, 8, 0, cdch_process_set_config, CONFIG_PL2303_RESET_ENDP2); } @@ -2323,37 +2242,17 @@ static bool pl2303_process_set_config(cdch_interface_t *p_cdc, tuh_xfer_t *xfer) case CONFIG_PL2303_RESET_ENDP2: // step 2 if (p_cdc->pl2303.quirks & PL2303_QUIRK_LEGACY) { - TU_ASSERT(pl2303_clear_halt(p_cdc, PL2303_IN_EP, cdch_process_set_config, CONFIG_PL2303_LINE_CODING)); + TU_ASSERT(pl2303_clear_halt(p_cdc, PL2303_IN_EP, cdch_process_set_config, CONFIG_PL2303_COMPLETE)); } else { /* reset upstream data pipes */ if (p_cdc->pl2303.type == PL2303_TYPE_HXN) { // here nothing to do, only structure of previous step overtaken for better reading and comparison } else { - TU_ASSERT(pl2303_vendor_write(p_cdc, 9, 0, cdch_process_set_config, CONFIG_PL2303_LINE_CODING)); + TU_ASSERT(pl2303_vendor_write(p_cdc, 9, 0, cdch_process_set_config, CONFIG_PL2303_COMPLETE)); } } break; - // from here sequence overtaken from Linux Kernel function pl2303_set_termios() - // unnecessary pl2303_get_line_request() is skipped due to a stall - case CONFIG_PL2303_LINE_CODING: - #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM - p_cdc->requested_line.coding = (cdc_line_coding_t) CFG_TUH_CDC_LINE_CODING_ON_ENUM; - TU_ASSERT(pl2303_set_line_request(p_cdc, cdch_internal_control_complete, CONFIG_PL2303_MODEM_CONTROL)); - break; - #else - TU_ATTR_FALLTHROUGH; - #endif - - case CONFIG_PL2303_MODEM_CONTROL: - #ifdef CFG_TUH_CDC_LINE_CONTROL_ON_ENUM - p_cdc->requested_line.control_state.value = CFG_TUH_CDC_LINE_CONTROL_ON_ENUM; - TU_ASSERT(pl2303_set_control_lines(p_cdc, cdch_internal_control_complete, CONFIG_PL2303_COMPLETE)); - break; - #else - TU_ATTR_FALLTHROUGH; - #endif - // skipped, because it's not working with each PL230x. flow control can be also set by PL2303 EEPROM Writer Program // case CONFIG_PL2303_FLOW_CTRL_READ: // // read flow control register for modify & write back in next step @@ -2383,7 +2282,8 @@ static bool pl2303_process_set_config(cdch_interface_t *p_cdc, tuh_xfer_t *xfer) // break; case CONFIG_PL2303_COMPLETE: - set_config_complete(p_cdc, 0, true); + xfer->user_data = 0; // kick-off set line state on enum + cdch_process_line_state_on_enum(xfer); break; default: -- cgit v1.3.1 From 0194b8434f318b2bd7357ba954291d03d3b26286 Mon Sep 17 00:00:00 2001 From: hathach Date: Fri, 27 Jun 2025 17:25:20 +0700 Subject: use enum buf for process_set_config for ch34x and pl2303 --- src/class/cdc/cdc_host.c | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) (limited to 'src/class') diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index 81337cde4..ebbd9c18c 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -1054,7 +1054,9 @@ static bool acm_open(uint8_t daddr, tusb_desc_interface_t const *itf_desc, uint1 static bool acm_process_set_config(cdch_interface_t *p_cdc, tuh_xfer_t *xfer) { TU_ASSERT(xfer->result == XFER_RESULT_SUCCESS); + (void) p_cdc; const uintptr_t state = xfer->user_data; + switch (state) { case CONFIG_ACM_COMPLETE: { xfer->user_data = 0; // kick-off set line state on enum @@ -1767,15 +1769,16 @@ static bool ch34x_open(uint8_t daddr, tusb_desc_interface_t const * itf_desc, ui } static bool ch34x_process_set_config(cdch_interface_t *p_cdc, tuh_xfer_t *xfer) { - uint8_t buffer[2];// TODO remove TU_ASSERT(xfer->result == XFER_RESULT_SUCCESS); const uintptr_t state = xfer->user_data; switch (state) { - case CONFIG_CH34X_READ_VERSION: - TU_ASSERT(ch34x_control_in(p_cdc, CH34X_REQ_READ_VERSION, 0, 0, buffer, 2, + case CONFIG_CH34X_READ_VERSION: { + uint8_t* enum_buf = usbh_get_enum_buf(); + TU_ASSERT(ch34x_control_in(p_cdc, CH34X_REQ_READ_VERSION, 0, 0, enum_buf, 2, cdch_process_set_config, CONFIG_CH34X_SERIAL_INIT)); break; + } case CONFIG_CH34X_SERIAL_INIT: { // handle version read data, set CH34x line coding (incl. baudrate) @@ -2104,7 +2107,7 @@ static bool pl2303_process_set_config(cdch_interface_t *p_cdc, tuh_xfer_t *xfer) // state CONFIG_PL2303_READ1 may have no success due to expected stall by pl2303_supports_hx_status() const uintptr_t state = xfer->user_data; TU_ASSERT(xfer->result == XFER_RESULT_SUCCESS || state == CONFIG_PL2303_READ1); - uint8_t buf = 0; + uint8_t* enum_buf = usbh_get_enum_buf(); pl2303_type_t type; switch (state) { @@ -2136,7 +2139,7 @@ static bool pl2303_process_set_config(cdch_interface_t *p_cdc, tuh_xfer_t *xfer) // purpose unknown, overtaken from Linux Kernel driver if (p_cdc->pl2303.type != PL2303_TYPE_HXN) { - TU_ASSERT(pl2303_vendor_read(p_cdc, 0x8484, &buf, cdch_process_set_config, CONFIG_PL2303_WRITE1)); + TU_ASSERT(pl2303_vendor_read(p_cdc, 0x8484, enum_buf, cdch_process_set_config, CONFIG_PL2303_WRITE1)); break; }// else: continue with next step TU_ATTR_FALLTHROUGH; @@ -2152,7 +2155,7 @@ static bool pl2303_process_set_config(cdch_interface_t *p_cdc, tuh_xfer_t *xfer) case CONFIG_PL2303_READ2: // purpose unknown, overtaken from Linux Kernel driver if (p_cdc->pl2303.type != PL2303_TYPE_HXN) { - TU_ASSERT(pl2303_vendor_read(p_cdc, 0x8484, &buf, cdch_process_set_config, CONFIG_PL2303_READ3)); + TU_ASSERT(pl2303_vendor_read(p_cdc, 0x8484, enum_buf, cdch_process_set_config, CONFIG_PL2303_READ3)); break; }// else: continue with next step TU_ATTR_FALLTHROUGH; @@ -2160,7 +2163,7 @@ static bool pl2303_process_set_config(cdch_interface_t *p_cdc, tuh_xfer_t *xfer) case CONFIG_PL2303_READ3: // purpose unknown, overtaken from Linux Kernel driver if (p_cdc->pl2303.type != PL2303_TYPE_HXN) { - TU_ASSERT(pl2303_vendor_read(p_cdc, 0x8383, &buf, cdch_process_set_config, CONFIG_PL2303_READ4)); + TU_ASSERT(pl2303_vendor_read(p_cdc, 0x8383, enum_buf, cdch_process_set_config, CONFIG_PL2303_READ4)); break; }// else: continue with next step TU_ATTR_FALLTHROUGH; @@ -2168,7 +2171,7 @@ static bool pl2303_process_set_config(cdch_interface_t *p_cdc, tuh_xfer_t *xfer) case CONFIG_PL2303_READ4: // purpose unknown, overtaken from Linux Kernel driver if (p_cdc->pl2303.type != PL2303_TYPE_HXN) { - TU_ASSERT(pl2303_vendor_read(p_cdc, 0x8484, &buf, cdch_process_set_config, CONFIG_PL2303_WRITE2)); + TU_ASSERT(pl2303_vendor_read(p_cdc, 0x8484, enum_buf, cdch_process_set_config, CONFIG_PL2303_WRITE2)); break; }// else: continue with next step TU_ATTR_FALLTHROUGH; @@ -2184,7 +2187,7 @@ static bool pl2303_process_set_config(cdch_interface_t *p_cdc, tuh_xfer_t *xfer) case CONFIG_PL2303_READ5: // purpose unknown, overtaken from Linux Kernel driver if (p_cdc->pl2303.type != PL2303_TYPE_HXN) { - TU_ASSERT(pl2303_vendor_read(p_cdc, 0x8484, &buf, cdch_process_set_config, CONFIG_PL2303_READ6)); + TU_ASSERT(pl2303_vendor_read(p_cdc, 0x8484, enum_buf, cdch_process_set_config, CONFIG_PL2303_READ6)); break; }// else: continue with next step TU_ATTR_FALLTHROUGH; @@ -2192,7 +2195,7 @@ static bool pl2303_process_set_config(cdch_interface_t *p_cdc, tuh_xfer_t *xfer) case CONFIG_PL2303_READ6: // purpose unknown, overtaken from Linux Kernel driver if (p_cdc->pl2303.type != PL2303_TYPE_HXN) { - TU_ASSERT(pl2303_vendor_read(p_cdc, 0x8383, &buf, cdch_process_set_config, CONFIG_PL2303_WRITE3)); + TU_ASSERT(pl2303_vendor_read(p_cdc, 0x8383, enum_buf, cdch_process_set_config, CONFIG_PL2303_WRITE3)); break; }// else: continue with next step TU_ATTR_FALLTHROUGH; -- cgit v1.3.1 From d86362414e9c467d93f37672228e220a718de81d Mon Sep 17 00:00:00 2001 From: hathach Date: Fri, 27 Jun 2025 17:57:26 +0700 Subject: clean up --- examples/host/cdc_msc_hid/src/tusb_config.h | 3 +- .../host/cdc_msc_hid_freertos/src/tusb_config.h | 1 + src/class/cdc/cdc_host.c | 34 +++++++++++----------- 3 files changed, 20 insertions(+), 18 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 e610c5672..2f8cb5e03 100644 --- a/examples/host/cdc_msc_hid/src/tusb_config.h +++ b/examples/host/cdc_msc_hid/src/tusb_config.h @@ -103,7 +103,7 @@ #define CFG_TUH_ENUMERATION_BUFSIZE 256 #define CFG_TUH_HUB 1 // number of supported hubs -#define CFG_TUH_CDC 4 // number of supported CDC devices. also activates CDC ACM +#define CFG_TUH_CDC 2 // number of supported CDC devices. also activates 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 @@ -122,6 +122,7 @@ //------------- CDC -------------// // Set Line Control state on enumeration/mounted: +// DTR ( bit 0), RTS (bit 1) #define CFG_TUH_CDC_LINE_CONTROL_ON_ENUM (CDC_CONTROL_LINE_STATE_DTR | CDC_CONTROL_LINE_STATE_RTS) // Set Line Coding on enumeration/mounted, value for cdc_line_coding_t 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 05deecba0..bc8887211 100644 --- a/examples/host/cdc_msc_hid_freertos/src/tusb_config.h +++ b/examples/host/cdc_msc_hid_freertos/src/tusb_config.h @@ -127,6 +127,7 @@ //------------- CDC -------------// // Set Line Control state on enumeration/mounted: +// DTR ( bit 0), RTS (bit 1) #define CFG_TUH_CDC_LINE_CONTROL_ON_ENUM (CDC_CONTROL_LINE_STATE_DTR | CDC_CONTROL_LINE_STATE_RTS) // Set Line Coding on enumeration/mounted, value for cdc_line_coding_t diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index ebbd9c18c..f4567fac4 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -42,7 +42,7 @@ // 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 1 + #define CFG_TUH_CDC_LOG_LEVEL 2 #endif #define TU_LOG_DRV(...) TU_LOG(CFG_TUH_CDC_LOG_LEVEL, __VA_ARGS__) @@ -748,25 +748,25 @@ bool cdch_open(uint8_t rhport, uint8_t daddr, tusb_desc_interface_t const *itf_d (void) rhport; // For CDC: only support ACM subclass // Note: Protocol 0xFF can be RNDIS device - if (TUSB_CLASS_CDC == itf_desc->bInterfaceClass && + if (TUSB_CLASS_CDC == itf_desc->bInterfaceClass && CDC_COMM_SUBCLASS_ABSTRACT_CONTROL_MODEL == itf_desc->bInterfaceSubClass) { return acm_open(daddr, itf_desc, max_len); - } 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)); - - for (size_t dr = 1; dr < SERIAL_DRIVER_COUNT; dr++) { - const cdch_serial_driver_t *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) { - const bool ret = driver->open(daddr, itf_desc, max_len); - TU_LOG_DRV("[:%u:%u] CDCh %s open %s\r\n", daddr, itf_desc->bInterfaceNumber, driver->name, ret ? "OK" : "FAILED"); - return ret; - } - } + } 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)); + + for (size_t dr = 1; dr < SERIAL_DRIVER_COUNT; dr++) { + const cdch_serial_driver_t *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) { + const bool ret = driver->open(daddr, itf_desc, max_len); + TU_LOG_DRV("[:%u:%u] CDCh %s open %s\r\n", daddr, itf_desc->bInterfaceNumber, driver->name, ret ? "OK" : "FAILED"); + return ret; } - } + } + } + } return false; } -- cgit v1.3.1 From d22cbe4cb5b88c869754e91c97eff513ed8b7b33 Mon Sep 17 00:00:00 2001 From: hathach Date: Tue, 1 Jul 2025 20:13:21 +0700 Subject: refactor async io, add in_isr argument to tud_msc_async_io_done() use cbw.command[0] for pending IO command --- src/class/msc/msc_device.c | 209 +++++++++++++++++++++------------------------ src/class/msc/msc_device.h | 70 ++++++--------- 2 files changed, 122 insertions(+), 157 deletions(-) (limited to 'src/class') diff --git a/src/class/msc/msc_device.c b/src/class/msc/msc_device.c index e583f6ba8..709734b87 100644 --- a/src/class/msc/msc_device.c +++ b/src/class/msc/msc_device.c @@ -52,36 +52,27 @@ enum { MSC_STAGE_NEED_RESET, }; -enum { - MSC_NEXT_OP_NONE = 0, - MSC_NEXT_OP_READ10, - MSC_NEXT_OP_WRITE10, - MSC_NEXT_OP_STATUS -}; - typedef struct { - TU_ATTR_ALIGNED(4) msc_cbw_t cbw; - TU_ATTR_ALIGNED(4) msc_csw_t csw; - + TU_ATTR_ALIGNED(4) msc_cbw_t cbw; // 31 bytes uint8_t rhport; + + TU_ATTR_ALIGNED(4) msc_csw_t csw; // 13 bytes uint8_t itf_num; uint8_t ep_in; uint8_t ep_out; - // Bulk Only Transfer (BOT) Protocol - uint8_t stage; - uint32_t total_len; // byte to be transferred, can be smaller than total_bytes in cbw uint32_t xferred_len; // numbered of bytes transferred so far in the Data Stage - // Sense Response Data + // Bulk Only Transfer (BOT) Protocol + uint8_t stage; + + // SCSI Sense Response Data uint8_t sense_key; uint8_t add_sense_code; uint8_t add_sense_qualifier; - // Async IO - uint8_t next_op; - uint32_t xferred_bytes; + uint8_t pending_io; // pending async IO }mscd_interface_t; static mscd_interface_t _mscd_itf; @@ -95,12 +86,11 @@ CFG_TUD_MEM_SECTION static struct { //--------------------------------------------------------------------+ static int32_t proc_builtin_scsi(uint8_t lun, uint8_t const scsi_cmd[16], uint8_t* buffer, uint32_t bufsize); static void proc_read10_cmd(mscd_interface_t* p_msc); -static void proc_read10_next(mscd_interface_t* p_msc, int32_t nbytes); +static void proc_read_io_data(mscd_interface_t* p_msc, int32_t nbytes); static void proc_write10_cmd(mscd_interface_t* p_msc); -static void proc_write10_new_data(mscd_interface_t* p_msc, uint32_t xferred_bytes); -static void proc_write10_next(mscd_interface_t* p_msc, uint32_t xferred_bytes, int32_t nbytes); +static void proc_write10_host_data(mscd_interface_t* p_msc, uint32_t xferred_bytes); +static void proc_write_io_data(mscd_interface_t* p_msc, uint32_t xferred_bytes, int32_t nbytes); static bool proc_stage_status(mscd_interface_t* p_msc); -static void tud_msc_async_io_done_cb(void* bytes_processed); TU_ATTR_ALWAYS_INLINE static inline bool is_data_in(uint8_t dir) { return tu_bit_test(dir, 7); @@ -195,30 +185,31 @@ static uint8_t rdwr10_validate_cmd(msc_cbw_t const* cbw) { return status; } -static bool proc_stage_status(mscd_interface_t* p_msc) { +static bool proc_stage_status(mscd_interface_t *p_msc) { uint8_t rhport = p_msc->rhport; - msc_cbw_t const* p_cbw = &p_msc->cbw; + msc_cbw_t const *p_cbw = &p_msc->cbw; + // skip status if epin is currently stalled, will do it when received Clear Stall request - if (!usbd_edpt_stalled(rhport, p_msc->ep_in)) { - if ((p_cbw->total_bytes > p_msc->xferred_len) && is_data_in(p_cbw->dir)) { - // 6.7 The 13 Cases: case 5 (Hi > Di): STALL before status - // TU_LOG_DRV(" SCSI case 5 (Hi > Di): %lu > %lu\r\n", p_cbw->total_bytes, p_msc->xferred_len); - usbd_edpt_stall(rhport, p_msc->ep_in); - } else { - TU_ASSERT(send_csw(p_msc)); - } + if (!usbd_edpt_stalled(rhport, p_msc->ep_in)) { + if ((p_cbw->total_bytes > p_msc->xferred_len) && is_data_in(p_cbw->dir)) { + // 6.7 The 13 Cases: case 5 (Hi > Di): STALL before status + // TU_LOG_DRV(" SCSI case 5 (Hi > Di): %lu > %lu\r\n", p_cbw->total_bytes, p_msc->xferred_len); + usbd_edpt_stall(rhport, p_msc->ep_in); + } else { + TU_ASSERT(send_csw(p_msc)); } + } - #if TU_CHECK_MCU(OPT_MCU_CXD56) - // WORKAROUND: cxd56 has its own nuttx usb stack which does not forward Set/ClearFeature(Endpoint) to DCD. - // There is no way for us to know when EP is un-stall, therefore we will unconditionally un-stall here and - // hope everything will work - if ( usbd_edpt_stalled(rhport, p_msc->ep_in) ) { - usbd_edpt_clear_stall(rhport, p_msc->ep_in); - send_csw(p_msc); - } - #endif - return true; + #if TU_CHECK_MCU(OPT_MCU_CXD56) + // WORKAROUND: cxd56 has its own nuttx usb stack which does not forward Set/ClearFeature(Endpoint) to DCD. + // There is no way for us to know when EP is un-stall, therefore we will unconditionally un-stall here and + // hope everything will work + if (usbd_edpt_stalled(rhport, p_msc->ep_in)) { + usbd_edpt_clear_stall(rhport, p_msc->ep_in); + send_csw(p_msc); + } + #endif + return true; } //--------------------------------------------------------------------+ @@ -258,39 +249,57 @@ bool tud_msc_set_sense(uint8_t lun, uint8_t sense_key, uint8_t add_sense_code, u return true; } -static inline void set_sense_medium_not_present(uint8_t lun) { +TU_ATTR_ALWAYS_INLINE static inline void set_sense_medium_not_present(uint8_t lun) { // default sense is NOT READY, MEDIUM NOT PRESENT tud_msc_set_sense(lun, SCSI_SENSE_NOT_READY, 0x3A, 0x00); } -void tud_msc_async_io_done(int32_t bytes_processed) { - // Precheck to avoid queueing multiple RW done callback - TU_VERIFY(_mscd_itf.next_op != MSC_NEXT_OP_NONE,); - // Call usbd_edpt_xfer() in tud_task() to avoid racing condition - usbd_defer_func(tud_msc_async_io_done_cb, (void*) (intptr_t)bytes_processed, false); +static void proc_async_io_done(void *bytes_processed) { + mscd_interface_t *p_msc = &_mscd_itf; + TU_VERIFY(p_msc->pending_io, ); + const int32_t nbytes = (int32_t) (intptr_t) bytes_processed; + const uint8_t cmd = p_msc->cbw.command[0]; + + p_msc->pending_io = 0; + switch (cmd) { + case SCSI_CMD_READ_10: + proc_read_io_data(p_msc, nbytes); + break; + + case SCSI_CMD_WRITE_10: + proc_write_io_data(p_msc, (uint32_t) nbytes, nbytes); + break; + + default: break; + } + + // send status if stage is transitioned to STATUS + if (p_msc->stage == MSC_STAGE_STATUS) { + proc_stage_status(p_msc); + } } -static void tud_msc_async_io_done_cb(void* bytes_processed) { - TU_VERIFY(_mscd_itf.next_op != MSC_NEXT_OP_NONE,); - uint8_t next_op = _mscd_itf.next_op; - _mscd_itf.next_op = MSC_NEXT_OP_NONE; - int32_t nbytes = (int32_t)(intptr_t)bytes_processed; - // READ10 - if (next_op == MSC_NEXT_OP_READ10) { - proc_read10_next(&_mscd_itf, nbytes); - } else if (next_op == MSC_NEXT_OP_WRITE10) { - proc_write10_next(&_mscd_itf, _mscd_itf.xferred_bytes, nbytes); - // Need to manually invoke CSW transfer - if (_mscd_itf.stage == MSC_STAGE_STATUS) { - proc_stage_status(&_mscd_itf); - } +bool tud_msc_async_io_done(int32_t bytes_io, bool in_isr) { + // Precheck to avoid queueing multiple RW done callback + TU_VERIFY(_mscd_itf.pending_io); + if (bytes_io == 0) { + bytes_io = TUD_MSC_RET_ERROR; // 0 is treated as error, no sense to call this with BUSY here + } + + if (in_isr) { + usbd_defer_func(proc_async_io_done, (void*) (intptr_t)bytes_io, in_isr); + } else { + proc_async_io_done((void*)(intptr_t) bytes_io); } + + return true; } //--------------------------------------------------------------------+ // USBD Driver API //--------------------------------------------------------------------+ void mscd_init(void) { + TU_LOG_INT(CFG_TUD_MSC_LOG_LEVEL, sizeof(mscd_interface_t)); tu_memclr(&_mscd_itf, sizeof(mscd_interface_t)); } @@ -528,7 +537,7 @@ bool mscd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t proc_read10_cmd(p_msc); } } else if (SCSI_CMD_WRITE_10 == p_cbw->command[0]) { - proc_write10_new_data(p_msc, xferred_bytes); + proc_write10_host_data(p_msc, xferred_bytes); } else { p_msc->xferred_len += xferred_bytes; @@ -560,7 +569,7 @@ bool mscd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t break; case MSC_STAGE_STATUS_SENT: - // Wait for the Status phase to complete + // Status phase is complete if ((ep_addr == p_msc->ep_in) && (xferred_bytes == sizeof(msc_csw_t))) { TU_LOG_DRV(" SCSI Status [Lun%u] = %u\r\n", p_cbw->lun, p_csw->status); // TU_LOG_MEM(CFG_TUD_MSC_LOG_LEVEL, p_csw, xferred_bytes, 2); @@ -590,7 +599,7 @@ bool mscd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t TU_ASSERT(prepare_cbw(p_msc)); } else { - // Any xfer ended here is consider unknown error, ignore it + // Any xfer ended here is considered unknown error, ignore it TU_LOG1(" Warning expect SCSI Status but received unknown data\r\n"); } break; @@ -696,8 +705,7 @@ static int32_t proc_builtin_scsi(uint8_t lun, uint8_t const scsi_cmd[16], uint8_ break; case SCSI_CMD_READ_FORMAT_CAPACITY: { - scsi_read_format_capacity_data_t read_fmt_capa = - { + scsi_read_format_capacity_data_t read_fmt_capa = { .list_length = 8, .block_num = 0, .descriptor_type = 2, // formatted media @@ -729,8 +737,7 @@ static int32_t proc_builtin_scsi(uint8_t lun, uint8_t const scsi_cmd[16], uint8_ break; case SCSI_CMD_INQUIRY: { - scsi_inquiry_resp_t inquiry_rsp = - { + scsi_inquiry_resp_t inquiry_rsp = { .is_removable = 1, .version = 2, .response_data_format = 2, @@ -750,8 +757,7 @@ static int32_t proc_builtin_scsi(uint8_t lun, uint8_t const scsi_cmd[16], uint8_ break; case SCSI_CMD_MODE_SENSE_6: { - scsi_mode_sense6_resp_t mode_resp = - { + scsi_mode_sense6_resp_t mode_resp = { .data_len = 3, .medium_type = 0, .write_protected = false, @@ -772,8 +778,7 @@ static int32_t proc_builtin_scsi(uint8_t lun, uint8_t const scsi_cmd[16], uint8_ break; case SCSI_CMD_REQUEST_SENSE: { - scsi_sense_fixed_resp_t sense_rsp = - { + scsi_sense_fixed_resp_t sense_rsp = { .response_code = 0x70, // current, fixed format .valid = 1 }; @@ -805,32 +810,27 @@ static int32_t proc_builtin_scsi(uint8_t lun, uint8_t const scsi_cmd[16], uint8_ static void proc_read10_cmd(mscd_interface_t* p_msc) { msc_cbw_t const* p_cbw = &p_msc->cbw; - - // block size already verified not zero - uint16_t const block_sz = rdwr10_get_blocksize(p_cbw); - - // Adjust lba with transferred bytes + uint16_t const block_sz = rdwr10_get_blocksize(p_cbw); // already verified non-zero + // Adjust lba & offset with transferred bytes uint32_t const lba = rdwr10_get_lba(p_cbw->command) + (p_msc->xferred_len / block_sz); + uint32_t const offset = p_msc->xferred_len % block_sz; // remaining bytes capped at class buffer int32_t nbytes = (int32_t)tu_min32(CFG_TUD_MSC_EP_BUFSIZE, p_cbw->total_bytes - p_msc->xferred_len); - // Application can consume smaller bytes - uint32_t const offset = p_msc->xferred_len % block_sz; - - p_msc->next_op = MSC_NEXT_OP_READ10; + p_msc->pending_io = 1; nbytes = tud_msc_read10_cb(p_cbw->lun, lba, offset, _mscd_epbuf.buf, (uint32_t)nbytes); if (nbytes != TUD_MSC_RET_ASYNC) { - p_msc->next_op = MSC_NEXT_OP_NONE; - proc_read10_next(p_msc, nbytes); + p_msc->pending_io = 0; + proc_read_io_data(p_msc, nbytes); } } -static void proc_read10_next(mscd_interface_t* p_msc, int32_t nbytes) { +static void proc_read_io_data(mscd_interface_t* p_msc, int32_t nbytes) { uint8_t rhport = p_msc->rhport; if (nbytes < 0) { // negative means error -> endpoint is stalled & status in CSW set to failed - TU_LOG_DRV(" tud_msc_read10_cb() return -1\r\n"); + TU_LOG_DRV(" IO read() failed\r\n"); // set sense msc_cbw_t const* p_cbw = &p_msc->cbw; @@ -838,7 +838,7 @@ static void proc_read10_next(mscd_interface_t* p_msc, int32_t nbytes) { fail_scsi_op(p_msc, MSC_CSW_STATUS_FAILED); } else if (nbytes == 0) { - // zero means not ready -> simulate an transfer complete so that this driver callback will fired again + // zero means not ready -> fake a transfer complete so that this driver callback will fire again dcd_event_xfer_complete(rhport, p_msc->ep_in, 0, XFER_RESULT_SUCCESS, false); } else { TU_ASSERT(usbd_edpt_xfer(rhport, p_msc->ep_in, _mscd_epbuf.buf, (uint16_t) nbytes),); @@ -864,55 +864,42 @@ static void proc_write10_cmd(mscd_interface_t* p_msc) { // remaining bytes capped at class buffer uint16_t nbytes = (uint16_t)tu_min32(CFG_TUD_MSC_EP_BUFSIZE, p_cbw->total_bytes - p_msc->xferred_len); // Write10 callback will be called later when usb transfer complete - uint8_t rhport = p_msc->rhport; - TU_ASSERT(usbd_edpt_xfer(rhport, p_msc->ep_out, _mscd_epbuf.buf, nbytes),); + TU_ASSERT(usbd_edpt_xfer(p_msc->rhport, p_msc->ep_out, _mscd_epbuf.buf, nbytes),); } // process new data arrived from WRITE10 -static void proc_write10_new_data(mscd_interface_t* p_msc, uint32_t xferred_bytes) { +static void proc_write10_host_data(mscd_interface_t* p_msc, uint32_t xferred_bytes) { msc_cbw_t const* p_cbw = &p_msc->cbw; + uint16_t const block_sz = rdwr10_get_blocksize(p_cbw); // already verified non-zero - // block size already verified not zero - uint16_t const block_sz = rdwr10_get_blocksize(p_cbw); - - // Adjust lba with transferred bytes + // Adjust lba & offset with transferred bytes uint32_t const lba = rdwr10_get_lba(p_cbw->command) + (p_msc->xferred_len / block_sz); - - // Invoke callback to consume new data uint32_t const offset = p_msc->xferred_len % block_sz; - p_msc->next_op = MSC_NEXT_OP_WRITE10; - p_msc->xferred_bytes = xferred_bytes; + p_msc->pending_io = 1; int32_t nbytes = tud_msc_write10_cb(p_cbw->lun, lba, offset, _mscd_epbuf.buf, xferred_bytes); if (nbytes != TUD_MSC_RET_ASYNC) { - p_msc->next_op = MSC_NEXT_OP_NONE; - proc_write10_next(p_msc, xferred_bytes, nbytes); + p_msc->pending_io = 0; + proc_write_io_data(p_msc, xferred_bytes, nbytes); } } -static void proc_write10_next(mscd_interface_t* p_msc, uint32_t xferred_bytes, int32_t nbytes) { +static void proc_write_io_data(mscd_interface_t* p_msc, uint32_t xferred_bytes, int32_t nbytes) { if (nbytes < 0) { // negative means error -> failed this scsi op - TU_LOG_DRV(" tud_msc_write10_cb() return -1\r\n"); - - // update actual byte before failed - p_msc->xferred_len += xferred_bytes; - - msc_cbw_t const* p_cbw = &p_msc->cbw; - set_sense_medium_not_present(p_cbw->lun); + TU_LOG_DRV(" IO write() failed\r\n"); + set_sense_medium_not_present(p_msc->cbw.lun); fail_scsi_op(p_msc, MSC_CSW_STATUS_FAILED); } else { if ((uint32_t)nbytes < xferred_bytes) { // Application consume less than what we got (including zero) const uint32_t left_over = xferred_bytes - (uint32_t)nbytes; if (nbytes > 0) { - p_msc->xferred_len += (uint16_t)nbytes; memmove(_mscd_epbuf.buf, _mscd_epbuf.buf + nbytes, left_over); } - // simulate a transfer complete with adjusted parameters --> callback will be invoked with adjusted parameter - uint8_t rhport = p_msc->rhport; - dcd_event_xfer_complete(rhport, p_msc->ep_out, left_over, XFER_RESULT_SUCCESS, false); + // fake a transfer complete with adjusted parameters --> callback will be invoked with adjusted parameters + dcd_event_xfer_complete(p_msc->rhport, p_msc->ep_out, left_over, XFER_RESULT_SUCCESS, false); } else { // Application consume all bytes in our buffer p_msc->xferred_len += xferred_bytes; diff --git a/src/class/msc/msc_device.h b/src/class/msc/msc_device.h index 7162b11e4..2ad31c245 100644 --- a/src/class/msc/msc_device.h +++ b/src/class/msc/msc_device.h @@ -49,10 +49,11 @@ #endif // Return value of callback functions -// Error -#define TUD_MSC_RET_ERROR -1 -// Asynchronous IO -#define TUD_MSC_RET_ASYNC -16 +enum { + TUD_MSC_RET_BUSY = 0, // Busy, e.g disk I/O is not ready + TUD_MSC_RET_ERROR = -1, + TUD_MSC_RET_ASYNC = -2, // Asynchronous IO +}; TU_VERIFY_STATIC(CFG_TUD_MSC_EP_BUFSIZE < UINT16_MAX, "Size is not correct"); @@ -63,54 +64,31 @@ TU_VERIFY_STATIC(CFG_TUD_MSC_EP_BUFSIZE < UINT16_MAX, "Size is not correct"); // Set SCSI sense response bool tud_msc_set_sense(uint8_t lun, uint8_t sense_key, uint8_t add_sense_code, uint8_t add_sense_qualifier); -// Called once asynchronous read/write operation is done -// bytes_processed has the same meaning of tud_msc_read10_cb() / -// tud_msc_write10_cb() return value -void tud_msc_async_io_done(int32_t bytes_processed); +// Called by Application once asynchronous I/O operation is done +// bytes_io is number of bytes in I/O op, typically the bufsize in read/write_cb() or +// TUD_MSC_RET_ERROR (-1) for error. Note TUD_MSC_RET_BUSY (0) will be treated as error as well. +bool tud_msc_async_io_done(int32_t bytes_io, bool in_isr); //--------------------------------------------------------------------+ // Application Callbacks (WEAK is optional) //--------------------------------------------------------------------+ -// Invoked when received SCSI READ10 command -// - Address = lba * BLOCK_SIZE + offset -// - offset is only needed if CFG_TUD_MSC_EP_BUFSIZE is smaller than BLOCK_SIZE. -// -// - Application fill the buffer (up to bufsize) with address contents and return number of bytes read or status. -// -// - ret < bufsize : These bytes are transferred first and callback will be invoked again for remaining data. -// -// - ret == 0 : Indicate application is not ready yet e.g disk I/O busy. -// Callback will be invoked again with the same parameters later on. -// -// - ret == TUD_MSC_RET_ERROR (-1) -// : Indicate application error e.g invalid address. This request will be STALLed -// and return failed status in command status wrapper phase. -// -// - ret == TUD_MSC_RET_ASYNC (-16) -// : Data reading will be done asynchronously in a background task. Application should return immediately. -// tud_msc_async_io_done() must be called once reading is done to signal completion. +/* + Invoked when received SCSI READ10/WRITE10 command + - Address = lba * BLOCK_SIZE + offset + - offset is only needed if CFG_TUD_MSC_EP_BUFSIZE is smaller than BLOCK_SIZE. + - Application fill the buffer (up to bufsize) with address contents and return number of bytes read or status. + - 0 < ret < bufsize: These bytes are transferred first and callback will be invoked again for remaining data. + - ret == TUD_MSC_RET_BUSY + Application is buys e.g disk I/O not ready. + Callback will be invoked again with the same parameters later on. + - ret == TUD_MSC_RET_ERROR + error such as invalid address. This request will be STALLed and scsi command will be failed + - ret == TUD_MSC_RET_ASYNC + Data I/O will be done asynchronously in a background task. Application should return immediately. + tud_msc_async_io_done() must be called once IO/ is done to signal completion. +*/ int32_t tud_msc_read10_cb (uint8_t lun, uint32_t lba, uint32_t offset, void* buffer, uint32_t bufsize); - -// Invoked when received SCSI WRITE10 command -// - Address = lba * BLOCK_SIZE + offset -// - offset is only needed if CFG_TUD_MSC_EP_BUFSIZE is smaller than BLOCK_SIZE. -// -// - Application writes data from buffer to address contents (up to bufsize) and returns the number of bytes written or status. -// -// - ret < bufsize : Callback will be invoked again with remaining data later on. -// -// - ret == 0 : Indicate application is not ready yet e.g disk I/O busy. -// Callback will be invoked again with the same parameters later on. -// -// - ret == TUD_MSC_RET_ERROR (-1) -// : Indicate application error e.g invalid address. This request will be STALLed -// and return failed status in command status wrapper phase. -// -// - ret == TUD_MSC_RET_ASYNC (-16) -// : Data writing will be done asynchronously in a background task. Application should return immediately. -// tud_msc_async_io_done() must be called once writing is done to signal completion. -// TODO change buffer to const uint8_t* int32_t tud_msc_write10_cb (uint8_t lun, uint32_t lba, uint32_t offset, uint8_t* buffer, uint32_t bufsize); // Invoked when received SCSI_CMD_INQUIRY -- cgit v1.3.1 From 216a35e59a095e6ccb70f7c9bd4f7bc737f44140 Mon Sep 17 00:00:00 2001 From: hathach Date: Tue, 1 Jul 2025 20:15:16 +0700 Subject: update example --- examples/device/cdc_msc_freertos/src/msc_disk.c | 117 +++++++++------------ examples/device/cdc_msc_freertos/src/tusb_config.h | 6 -- src/class/msc/msc_device.c | 6 +- 3 files changed, 55 insertions(+), 74 deletions(-) (limited to 'src/class') diff --git a/examples/device/cdc_msc_freertos/src/msc_disk.c b/examples/device/cdc_msc_freertos/src/msc_disk.c index c2aaca847..d1ff2f71b 100644 --- a/examples/device/cdc_msc_freertos/src/msc_disk.c +++ b/examples/device/cdc_msc_freertos/src/msc_disk.c @@ -28,8 +28,13 @@ #if CFG_TUD_MSC -#if CFG_EXAMPLE_MSC_ASYNC_IO +// Use async IO in example or not +#define CFG_EXAMPLE_MSC_ASYNC_IO 1 + +// Simulate read/write operation delay +#define CFG_EXAMPLE_MSC_IO_DELAY_MS 0 +#if CFG_EXAMPLE_MSC_ASYNC_IO #define IO_STACK_SIZE configMINIMAL_STACK_SIZE typedef struct { @@ -66,8 +71,7 @@ static bool ejected = false; If you find any bugs or get any questions, feel free to file an\r\n\ issue at github.com/hathach/tinyusb" -enum -{ +enum { DISK_BLOCK_NUM = 16, // 8KB is the smallest size that windows allow to mount DISK_BLOCK_SIZE = 512 }; @@ -162,18 +166,20 @@ static void io_task(void *params) { io_ops_t io_ops; while (1) { if (xQueueReceive(io_queue, &io_ops, portMAX_DELAY)) { + const uint8_t* addr = msc_disk[io_ops.lba] + io_ops.offset; + int32_t nbytes = io_ops.bufsize; if (io_ops.is_read) { - uint8_t const* addr = msc_disk[io_ops.lba] + io_ops.offset; memcpy(io_ops.buffer, addr, io_ops.bufsize); } else { #ifndef CFG_EXAMPLE_MSC_READONLY - uint8_t* addr = msc_disk[io_ops.lba] + io_ops.offset; - memcpy(addr, io_ops.buffer, io_ops.bufsize); + memcpy((uint8_t*) addr, io_ops.buffer, io_ops.bufsize); +#else + nbytes = -1; // failed to write #endif } tusb_time_delay_ms_api(CFG_EXAMPLE_MSC_IO_DELAY_MS); - tud_msc_async_io_done(io_ops.bufsize); + tud_msc_async_io_done(nbytes, false); } } } @@ -184,14 +190,11 @@ void msc_disk_init() {} // Invoked when received SCSI_CMD_INQUIRY // Application fill vendor id, product id and revision with string up to 8, 16, 4 characters respectively -void tud_msc_inquiry_cb(uint8_t lun, uint8_t vendor_id[8], uint8_t product_id[16], uint8_t product_rev[4]) -{ +void tud_msc_inquiry_cb(uint8_t lun, uint8_t vendor_id[8], uint8_t product_id[16], uint8_t product_rev[4]) { (void) lun; - const char vid[] = "TinyUSB"; const char pid[] = "Mass Storage"; const char rev[] = "1.0"; - memcpy(vendor_id , vid, strlen(vid)); memcpy(product_id , pid, strlen(pid)); memcpy(product_rev, rev, strlen(rev)); @@ -199,8 +202,7 @@ void tud_msc_inquiry_cb(uint8_t lun, uint8_t vendor_id[8], uint8_t product_id[16 // Invoked when received Test Unit Ready command. // return true allowing host to read/write this LUN e.g SD card inserted -bool tud_msc_test_unit_ready_cb(uint8_t lun) -{ +bool tud_msc_test_unit_ready_cb(uint8_t lun) { (void) lun; // RAM disk is ready until ejected @@ -215,10 +217,8 @@ bool tud_msc_test_unit_ready_cb(uint8_t lun) // Invoked when received SCSI_CMD_READ_CAPACITY_10 and SCSI_CMD_READ_FORMAT_CAPACITY to determine the disk size // Application update block count and block size -void tud_msc_capacity_cb(uint8_t lun, uint32_t* block_count, uint16_t* block_size) -{ +void tud_msc_capacity_cb(uint8_t lun, uint32_t* block_count, uint16_t* block_size) { (void) lun; - *block_count = DISK_BLOCK_NUM; *block_size = DISK_BLOCK_SIZE; } @@ -226,18 +226,14 @@ void tud_msc_capacity_cb(uint8_t lun, uint32_t* block_count, uint16_t* block_siz // Invoked when received Start Stop Unit command // - Start = 0 : stopped power mode, if load_eject = 1 : unload disk storage // - Start = 1 : active mode, if load_eject = 1 : load disk storage -bool tud_msc_start_stop_cb(uint8_t lun, uint8_t power_condition, bool start, bool load_eject) -{ +bool tud_msc_start_stop_cb(uint8_t lun, uint8_t power_condition, bool start, bool load_eject) { (void) lun; (void) power_condition; - if ( load_eject ) - { - if (start) - { + if (load_eject) { + if (start) { // load disk storage - }else - { + } else { // unload disk storage ejected = true; } @@ -248,116 +244,107 @@ bool tud_msc_start_stop_cb(uint8_t lun, uint8_t power_condition, bool start, boo // Callback invoked when received READ10 command. // Copy disk's data to buffer (up to bufsize) and return number of copied bytes. -int32_t tud_msc_read10_cb(uint8_t lun, uint32_t lba, uint32_t offset, void* buffer, uint32_t bufsize) -{ +int32_t tud_msc_read10_cb(uint8_t lun, uint32_t lba, uint32_t offset, void* buffer, uint32_t bufsize) { (void) lun; // out of ramdisk - if ( lba >= DISK_BLOCK_NUM ) { + if (lba >= DISK_BLOCK_NUM) { return TUD_MSC_RET_ERROR; } // Check for overflow of offset + bufsize - if ( lba * DISK_BLOCK_SIZE + offset + bufsize > DISK_BLOCK_NUM * DISK_BLOCK_SIZE ) { + if (lba * DISK_BLOCK_SIZE + offset + bufsize > DISK_BLOCK_NUM * DISK_BLOCK_SIZE) { return TUD_MSC_RET_ERROR; } -#if CFG_EXAMPLE_MSC_ASYNC_IO - io_ops_t io_ops = { .is_read = true, .lun = lun, .lba = lba, .offset = offset, .buffer = buffer, .bufsize = bufsize }; + #if CFG_EXAMPLE_MSC_ASYNC_IO + io_ops_t io_ops = {.is_read = true, .lun = lun, .lba = lba, .offset = offset, .buffer = buffer, .bufsize = bufsize}; // Send IO operation to IO task TU_ASSERT(xQueueSend(io_queue, &io_ops, 0) == pdPASS); return TUD_MSC_RET_ASYNC; -#else - uint8_t const* addr = msc_disk[lba] + offset; + #else + uint8_t const *addr = msc_disk[lba] + offset; memcpy(buffer, addr, bufsize); - tusb_time_delay_ms_api(CFG_EXAMPLE_MSC_IO_DELAY_MS); - return bufsize; -#endif + #endif } -bool tud_msc_is_writable_cb (uint8_t lun) -{ +bool tud_msc_is_writable_cb (uint8_t lun) { (void) lun; -#ifdef CFG_EXAMPLE_MSC_READONLY + #ifdef CFG_EXAMPLE_MSC_READONLY return false; -#else + #else return true; -#endif + #endif } // Callback invoked when received WRITE10 command. // Process data in buffer to disk's storage and return number of written bytes -int32_t tud_msc_write10_cb(uint8_t lun, uint32_t lba, uint32_t offset, uint8_t* buffer, uint32_t bufsize) -{ +int32_t tud_msc_write10_cb(uint8_t lun, uint32_t lba, uint32_t offset, uint8_t* buffer, uint32_t bufsize) { // out of ramdisk - if ( lba >= DISK_BLOCK_NUM ) { + if (lba >= DISK_BLOCK_NUM) { return TUD_MSC_RET_ERROR; } // Check for overflow of offset + bufsize - if ( lba * DISK_BLOCK_SIZE + offset + bufsize > DISK_BLOCK_NUM * DISK_BLOCK_SIZE ) { + if (lba * DISK_BLOCK_SIZE + offset + bufsize > DISK_BLOCK_NUM * DISK_BLOCK_SIZE) { return TUD_MSC_RET_ERROR; } -#ifdef CFG_EXAMPLE_MSC_READONLY - (void) lun; (void) buffer; + #ifdef CFG_EXAMPLE_MSC_READONLY + (void) lun; + (void) buffer; return bufsize; -#endif + #endif -#if CFG_EXAMPLE_MSC_ASYNC_IO - io_ops_t io_ops = { .is_read = false, .lun = lun, .lba = lba, .offset = offset, .buffer = buffer, .bufsize = bufsize }; + #if CFG_EXAMPLE_MSC_ASYNC_IO + io_ops_t io_ops = {.is_read = false, .lun = lun, .lba = lba, .offset = offset, .buffer = buffer, .bufsize = bufsize}; // Send IO operation to IO task TU_ASSERT(xQueueSend(io_queue, &io_ops, 0) == pdPASS); return TUD_MSC_RET_ASYNC; -#else - uint8_t* addr = msc_disk[lba] + offset; + #else + uint8_t *addr = msc_disk[lba] + offset; memcpy(addr, buffer, bufsize); tusb_time_delay_ms_api(CFG_EXAMPLE_MSC_IO_DELAY_MS); return bufsize; -#endif + #endif } // Callback invoked when received an SCSI command not in built-in list below // - READ_CAPACITY10, READ_FORMAT_CAPACITY, INQUIRY, MODE_SENSE6, REQUEST_SENSE // - READ10 and WRITE10 has their own callbacks -int32_t tud_msc_scsi_cb (uint8_t lun, uint8_t const scsi_cmd[16], void* buffer, uint16_t bufsize) -{ +int32_t tud_msc_scsi_cb (uint8_t lun, uint8_t const scsi_cmd[16], void* buffer, uint16_t bufsize) { // read10 & write10 has their own callback and MUST not be handled here - void const* response = NULL; + void const *response = NULL; int32_t resplen = 0; // most scsi handled is input bool in_xfer = true; - switch (scsi_cmd[0]) - { + switch (scsi_cmd[0]) { default: // Set Sense = Invalid Command Operation tud_msc_set_sense(lun, SCSI_SENSE_ILLEGAL_REQUEST, 0x20, 0x00); // negative means error -> tinyusb could stall and/or response with failed status resplen = -1; - break; + break; } // return resplen must not larger than bufsize - if ( resplen > bufsize ) resplen = bufsize; + if (resplen > bufsize) { resplen = bufsize; } - if ( response && (resplen > 0) ) - { - if(in_xfer) - { + if (response && (resplen > 0)) { + if (in_xfer) { memcpy(buffer, response, (size_t) resplen); - }else - { + } else { // SCSI output } } diff --git a/examples/device/cdc_msc_freertos/src/tusb_config.h b/examples/device/cdc_msc_freertos/src/tusb_config.h index d70456287..c3f2f7fb5 100644 --- a/examples/device/cdc_msc_freertos/src/tusb_config.h +++ b/examples/device/cdc_msc_freertos/src/tusb_config.h @@ -114,12 +114,6 @@ // MSC Buffer size of Device Mass storage #define CFG_TUD_MSC_EP_BUFSIZE 512 -// Use async IO in example or not -#define CFG_EXAMPLE_MSC_ASYNC_IO 1 - -// Simulate read/write operation delay -#define CFG_EXAMPLE_MSC_IO_DELAY_MS 0 - #ifdef __cplusplus } #endif diff --git a/src/class/msc/msc_device.c b/src/class/msc/msc_device.c index 709734b87..a8c52b6bd 100644 --- a/src/class/msc/msc_device.c +++ b/src/class/msc/msc_device.c @@ -828,8 +828,8 @@ static void proc_read10_cmd(mscd_interface_t* p_msc) { static void proc_read_io_data(mscd_interface_t* p_msc, int32_t nbytes) { uint8_t rhport = p_msc->rhport; - if (nbytes < 0) { - // negative means error -> endpoint is stalled & status in CSW set to failed + if (nbytes == TUD_MSC_RET_ERROR) { + // error -> endpoint is stalled & status in CSW set to failed TU_LOG_DRV(" IO read() failed\r\n"); // set sense @@ -837,7 +837,7 @@ static void proc_read_io_data(mscd_interface_t* p_msc, int32_t nbytes) { set_sense_medium_not_present(p_cbw->lun); fail_scsi_op(p_msc, MSC_CSW_STATUS_FAILED); - } else if (nbytes == 0) { + } else if (nbytes == TUD_MSC_RET_BUSY) { // zero means not ready -> fake a transfer complete so that this driver callback will fire again dcd_event_xfer_complete(rhport, p_msc->ep_in, 0, XFER_RESULT_SUCCESS, false); } else { -- cgit v1.3.1 From c96cc4369f1b97efe85575f3e5633e38598e9fc2 Mon Sep 17 00:00:00 2001 From: hathach Date: Tue, 1 Jul 2025 21:52:57 +0700 Subject: defer proc_async_io_done() --- src/class/msc/msc_device.c | 64 +++++++++++++++++++++++++--------------------- src/class/msc/msc_device.h | 9 +++---- 2 files changed, 39 insertions(+), 34 deletions(-) (limited to 'src/class') diff --git a/src/class/msc/msc_device.c b/src/class/msc/msc_device.c index a8c52b6bd..747ad03ed 100644 --- a/src/class/msc/msc_device.c +++ b/src/class/msc/msc_device.c @@ -254,10 +254,10 @@ TU_ATTR_ALWAYS_INLINE static inline void set_sense_medium_not_present(uint8_t lu tud_msc_set_sense(lun, SCSI_SENSE_NOT_READY, 0x3A, 0x00); } -static void proc_async_io_done(void *bytes_processed) { +static void proc_async_io_done(void *bytes_io) { mscd_interface_t *p_msc = &_mscd_itf; TU_VERIFY(p_msc->pending_io, ); - const int32_t nbytes = (int32_t) (intptr_t) bytes_processed; + const int32_t nbytes = (int32_t) (intptr_t) bytes_io; const uint8_t cmd = p_msc->cbw.command[0]; p_msc->pending_io = 0; @@ -283,15 +283,9 @@ bool tud_msc_async_io_done(int32_t bytes_io, bool in_isr) { // Precheck to avoid queueing multiple RW done callback TU_VERIFY(_mscd_itf.pending_io); if (bytes_io == 0) { - bytes_io = TUD_MSC_RET_ERROR; // 0 is treated as error, no sense to call this with BUSY here + bytes_io = TUD_MSC_RET_ERROR; // 0 is treated as error, no reason to call this with BUSY here } - - if (in_isr) { - usbd_defer_func(proc_async_io_done, (void*) (intptr_t)bytes_io, in_isr); - } else { - proc_async_io_done((void*)(intptr_t) bytes_io); - } - + usbd_defer_func(proc_async_io_done, (void *) (intptr_t) bytes_io, in_isr); return true; } @@ -827,21 +821,26 @@ static void proc_read10_cmd(mscd_interface_t* p_msc) { } static void proc_read_io_data(mscd_interface_t* p_msc, int32_t nbytes) { - uint8_t rhport = p_msc->rhport; - if (nbytes == TUD_MSC_RET_ERROR) { - // error -> endpoint is stalled & status in CSW set to failed - TU_LOG_DRV(" IO read() failed\r\n"); - - // set sense - msc_cbw_t const* p_cbw = &p_msc->cbw; - set_sense_medium_not_present(p_cbw->lun); - - fail_scsi_op(p_msc, MSC_CSW_STATUS_FAILED); - } else if (nbytes == TUD_MSC_RET_BUSY) { - // zero means not ready -> fake a transfer complete so that this driver callback will fire again - dcd_event_xfer_complete(rhport, p_msc->ep_in, 0, XFER_RESULT_SUCCESS, false); - } else { + const uint8_t rhport = p_msc->rhport; + if (nbytes > 0) { TU_ASSERT(usbd_edpt_xfer(rhport, p_msc->ep_in, _mscd_epbuf.buf, (uint16_t) nbytes),); + } else { + // nbytes is status + switch (nbytes) { + case TUD_MSC_RET_ERROR: + // error -> endpoint is stalled & status in CSW set to failed + TU_LOG_DRV(" IO read() failed\r\n"); + set_sense_medium_not_present(p_msc->cbw.lun); + fail_scsi_op(p_msc, MSC_CSW_STATUS_FAILED); + break; + + case TUD_MSC_RET_BUSY: + // not ready yet -> fake a transfer complete so that this driver callback will fire again + dcd_event_xfer_complete(rhport, p_msc->ep_in, 0, XFER_RESULT_SUCCESS, false); + break; + + default: break; + } } } @@ -886,13 +885,20 @@ static void proc_write10_host_data(mscd_interface_t* p_msc, uint32_t xferred_byt static void proc_write_io_data(mscd_interface_t* p_msc, uint32_t xferred_bytes, int32_t nbytes) { if (nbytes < 0) { - // negative means error -> failed this scsi op - TU_LOG_DRV(" IO write() failed\r\n"); - set_sense_medium_not_present(p_msc->cbw.lun); - fail_scsi_op(p_msc, MSC_CSW_STATUS_FAILED); + // nbytes is status + switch (nbytes) { + case TUD_MSC_RET_ERROR: + // IO error -> failed this scsi op + TU_LOG_DRV(" IO write() failed\r\n"); + set_sense_medium_not_present(p_msc->cbw.lun); + fail_scsi_op(p_msc, MSC_CSW_STATUS_FAILED); + break; + + default: break; + } } else { if ((uint32_t)nbytes < xferred_bytes) { - // Application consume less than what we got (including zero) + // Application consume less than what we got including TUD_MSC_RET_BUSY (0) const uint32_t left_over = xferred_bytes - (uint32_t)nbytes; if (nbytes > 0) { memmove(_mscd_epbuf.buf, _mscd_epbuf.buf + nbytes, left_over); diff --git a/src/class/msc/msc_device.h b/src/class/msc/msc_device.h index 2ad31c245..f2ea256b4 100644 --- a/src/class/msc/msc_device.h +++ b/src/class/msc/msc_device.h @@ -79,12 +79,11 @@ bool tud_msc_async_io_done(int32_t bytes_io, bool in_isr); - offset is only needed if CFG_TUD_MSC_EP_BUFSIZE is smaller than BLOCK_SIZE. - Application fill the buffer (up to bufsize) with address contents and return number of bytes read or status. - 0 < ret < bufsize: These bytes are transferred first and callback will be invoked again for remaining data. - - ret == TUD_MSC_RET_BUSY - Application is buys e.g disk I/O not ready. - Callback will be invoked again with the same parameters later on. - - ret == TUD_MSC_RET_ERROR + - TUD_MSC_RET_BUSY + Application is buys e.g disk I/O not ready. Callback will be invoked again with the same parameters later on. + - TUD_MSC_RET_ERROR error such as invalid address. This request will be STALLed and scsi command will be failed - - ret == TUD_MSC_RET_ASYNC + - TUD_MSC_RET_ASYNC Data I/O will be done asynchronously in a background task. Application should return immediately. tud_msc_async_io_done() must be called once IO/ is done to signal completion. */ -- cgit v1.3.1