diff options
Diffstat (limited to 'class')
| -rw-r--r-- | class/adb/usbd_adb.c | 2 | ||||
| -rw-r--r-- | class/audio/usb_audio.h | 40 | ||||
| -rw-r--r-- | class/audio/usbh_audio.c | 4 | ||||
| -rw-r--r-- | class/cdc/usb_cdc.h | 3 | ||||
| -rw-r--r-- | class/cdc/usbd_cdc_ncm.c | 545 | ||||
| -rw-r--r-- | class/cdc/usbd_cdc_ncm.h | 41 | ||||
| -rw-r--r-- | class/hub/usbh_hub.c | 13 | ||||
| -rw-r--r-- | class/msc/usbd_msc.c | 41 | ||||
| -rw-r--r-- | class/serial/usbh_serial.c | 68 | ||||
| -rw-r--r-- | class/serial/usbh_serial.h | 13 |
10 files changed, 720 insertions, 50 deletions
diff --git a/class/adb/usbd_adb.c b/class/adb/usbd_adb.c index dc664309..d147834f 100644 --- a/class/adb/usbd_adb.c +++ b/class/adb/usbd_adb.c @@ -115,7 +115,7 @@ void usbd_adb_bulk_out(uint8_t busid, uint8_t ep, uint32_t nbytes) if (adb_client.common_state == ADB_STATE_READ_MSG) { USB_ASSERT(nbytes == sizeof(struct adb_msg)); - USB_ASSERT(rx_packet.msg.data_length <= sizeof(rx_packet.payload)); + USB_ASSERT(rx_packet.msg.data_length < sizeof(rx_packet.payload)); USB_LOG_DBG("command:%x arg0:%x arg1:%x len:%d\r\n", rx_packet.msg.command, diff --git a/class/audio/usb_audio.h b/class/audio/usb_audio.h index 95609765..efb758ae 100644 --- a/class/audio/usb_audio.h +++ b/class/audio/usb_audio.h @@ -687,6 +687,10 @@ struct audio_cs_if_as_general_descriptor { #define AUDIO_SIZEOF_AS_GENERAL_DESC (7) +#ifndef CONFIG_USBHOST_AUDIO_MAX_SAMPLE_FREQ_NUM +#define CONFIG_USBHOST_AUDIO_MAX_SAMPLE_FREQ_NUM 8 +#endif + struct audio_cs_if_as_format_type_descriptor { uint8_t bLength; uint8_t bDescriptorType; @@ -696,7 +700,7 @@ struct audio_cs_if_as_format_type_descriptor { uint8_t bSubframeSize; uint8_t bBitResolution; uint8_t bSamFreqType; - uint8_t tSamFreq[3]; + uint8_t tSamFreq[3 * CONFIG_USBHOST_AUDIO_MAX_SAMPLE_FREQ_NUM]; } __PACKED; #define AUDIO_SIZEOF_FORMAT_TYPE_DESC(bSamFreqType) (8 + 3 * (bSamFreqType)) @@ -1344,19 +1348,27 @@ struct audio_v2_control_range3_param_block { #define AUDIO_SAMPLE_FREQ_4B(frq) (uint8_t)(frq), (uint8_t)((frq >> 8)), \ (uint8_t)((frq >> 16)), (uint8_t)((frq >> 24)) -/* format 10.14 */ -#define AUDIO_FREQ_TO_FEEDBACK_FS(freq) ((freq << 10) / 1000) -#define AUDIO_FEEDBACK_TO_BUF_FS(buf, feedback) \ - buf[0] = ((feedback << 4) & 0xFFU); \ - buf[1] = (((feedback << 4) >> 8U) & 0xFFU); \ - buf[2] = (((feedback << 4) >> 16U) & 0xFFU) +/* FS feedback uses 10.14 samples per audio data service interval. */ +#define AUDIO_FREQ_TO_FEEDBACK_FS(freq) ((uint32_t)(((uint64_t)(freq) << 10U) / 1000U)) +#define AUDIO_FEEDBACK_TO_FREQ_FS(feedback) ((uint32_t)(((uint64_t)(feedback) * 1000U) >> 10U)) +#define AUDIO_FEEDBACK_TO_BUF_FS_INTERVAL(buf, feedback, interval) do { \ + uint32_t audio_feedback_value = (uint32_t)((uint64_t)(feedback) << ((interval) + 3U)); \ + (buf)[0] = (uint8_t)(audio_feedback_value); \ + (buf)[1] = (uint8_t)(audio_feedback_value >> 8U); \ + (buf)[2] = (uint8_t)(audio_feedback_value >> 16U); \ +} while (0) +#define AUDIO_FEEDBACK_TO_BUF_FS(buf, feedback) AUDIO_FEEDBACK_TO_BUF_FS_INTERVAL(buf, feedback, 1U) -/* format 16.16 */ -#define AUDIO_FREQ_TO_FEEDBACK_HS(freq) ((freq << 13) / 1000) -#define AUDIO_FEEDBACK_TO_BUF_HS(buf, feedback) \ - buf[0] = (((feedback & 0x00001FFFu) << 3) & 0xFFu); \ - buf[1] = ((((feedback & 0x00001FFFu) << 3) >> 8) & 0xFFu); \ - buf[2] = (((feedback & 0x01FFE000u) >> 13) & 0xFFu); \ - buf[3] = (((feedback & 0x01FFE000u) >> 21) & 0xFFu) +/* Keep HS feedback in 16.16 samples per microframe, then scale it by the audio data endpoint interval when serialized. */ +#define AUDIO_FREQ_TO_FEEDBACK_HS(freq) ((uint32_t)(((uint64_t)(freq) << 16U) / 8000U)) +#define AUDIO_FEEDBACK_TO_FREQ_HS(feedback) ((uint32_t)(((uint64_t)(feedback) * 8000U) >> 16U)) +#define AUDIO_FEEDBACK_TO_BUF_HS_INTERVAL(buf, feedback, interval) do { \ + uint32_t audio_feedback_value = (uint32_t)((uint64_t)(feedback) << ((interval) - 1U)); \ + (buf)[0] = (uint8_t)(audio_feedback_value); \ + (buf)[1] = (uint8_t)(audio_feedback_value >> 8U); \ + (buf)[2] = (uint8_t)(audio_feedback_value >> 16U); \ + (buf)[3] = (uint8_t)(audio_feedback_value >> 24U); \ +} while (0) +#define AUDIO_FEEDBACK_TO_BUF_HS(buf, feedback) AUDIO_FEEDBACK_TO_BUF_HS_INTERVAL(buf, feedback, 4U) #endif /* USB_AUDIO_H */ diff --git a/class/audio/usbh_audio.c b/class/audio/usbh_audio.c index ee0a3349..185e4f3e 100644 --- a/class/audio/usbh_audio.c +++ b/class/audio/usbh_audio.c @@ -694,12 +694,12 @@ static int usbh_audio_ctrl_connect(struct usbh_hubport *hport, uint8_t intf) case AUDIO_STREAMING_FORMAT_TYPE: { struct audio_cs_if_as_format_type_descriptor *desc = (struct audio_cs_if_as_format_type_descriptor *)p; - USB_ASSERT(desc->bSamFreqType == 1); + USB_ASSERT(desc->bSamFreqType <= CONFIG_USBHOST_AUDIO_MAX_SAMPLE_FREQ_NUM && desc->bSamFreqType > 0); USB_ASSERT(desc->bNrChannels <= CONFIG_USBHOST_AUDIO_MAX_CHANNELS); USB_ASSERT(cur_alt_setting < CONFIG_USBHOST_MAX_INTF_ALTSETTINGS); audio_class->as_msg_table[cur_iface - audio_class->ctrl_intf - 1].bNrChannels = desc->bNrChannels; - memcpy(&audio_class->as_msg_table[cur_iface - audio_class->ctrl_intf - 1].as_format[cur_alt_setting], desc, AUDIO_SIZEOF_FORMAT_TYPE_DESC(1)); + memcpy(&audio_class->as_msg_table[cur_iface - audio_class->ctrl_intf - 1].as_format[cur_alt_setting], desc, AUDIO_SIZEOF_FORMAT_TYPE_DESC(desc->bSamFreqType)); } break; default: break; diff --git a/class/cdc/usb_cdc.h b/class/cdc/usb_cdc.h index a21bc3b2..c80a107e 100644 --- a/class/cdc/usb_cdc.h +++ b/class/cdc/usb_cdc.h @@ -275,6 +275,9 @@ #define CDC_ECM_NOTIFY_CODE_RESPONSE_AVAILABLE 0x01 #define CDC_ECM_NOTIFY_CODE_CONNECTION_SPEED_CHANGE 0x2A +#define CDC_NCM_CONNECT_SPEED_UPSTREAM 0x004C4B40U /* 5Mbps */ +#define CDC_NCM_CONNECT_SPEED_DOWNSTREAM 0x004C4B40U /* 5Mbps */ + #define CDC_NCM_NTH16_SIGNATURE 0x484D434E #define CDC_NCM_NDP16_SIGNATURE_NCM0 0x304D434E #define CDC_NCM_NDP16_SIGNATURE_NCM1 0x314D434E diff --git a/class/cdc/usbd_cdc_ncm.c b/class/cdc/usbd_cdc_ncm.c new file mode 100644 index 00000000..68a272ee --- /dev/null +++ b/class/cdc/usbd_cdc_ncm.c @@ -0,0 +1,545 @@ +/* + * Copyright (c) 2026, 54fire + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include <string.h> +#include "usbd_core.h" +#include "usbd_cdc_ncm.h" + +#define CDC_NCM_OUT_EP_IDX 0 +#define CDC_NCM_IN_EP_IDX 1 +#define CDC_NCM_INT_EP_IDX 2 + +#define CONFIG_CDC_NCM_ETH_MAX_SEGSZE 1514U +#define CONFIG_CDC_NCM_NTB_MAX_SIZE 2048U +#define CDC_NCM_NTH16_LEN 12U +#define CDC_NCM_NDP16_LEN 16U +#define CDC_NCM_DATAGRAM_OFFSET 16U + +static struct usbd_endpoint cdc_ncm_ep_data[3]; + +#ifdef CONFIG_USBDEV_CDC_NCM_USING_LWIP +static USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_cdc_ncm_rx_buffer[USB_ALIGN_UP(CONFIG_CDC_NCM_NTB_MAX_SIZE, CONFIG_USB_ALIGN_SIZE)]; +static USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_cdc_ncm_tx_buffer[USB_ALIGN_UP(CONFIG_CDC_NCM_NTB_MAX_SIZE, CONFIG_USB_ALIGN_SIZE)]; +#endif +static USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_cdc_ncm_ctrl_buf[USB_ALIGN_UP(32, CONFIG_USB_ALIGN_SIZE)]; +static USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_cdc_ncm_notify_buf[USB_ALIGN_UP(16, CONFIG_USB_ALIGN_SIZE)]; + +static volatile uint32_t g_cdc_ncm_rx_ntb_length = 0; +static volatile uint32_t g_cdc_ncm_tx_ntb_length = 0; +static volatile bool g_cdc_ncm_data_alt_active = false; +static uint8_t *g_cdc_ncm_rx_data_buffer = NULL; +static uint32_t g_cdc_ncm_rx_total_length = 0; +static uint16_t g_cdc_ncm_rx_datagram_pos = 0; +static uint16_t g_cdc_ncm_rx_ndp_index = 0; +static uint16_t g_cdc_ncm_rx_sequence = 0; +static uint16_t g_cdc_ncm_tx_sequence = 0; +static uint16_t g_cdc_ncm_max_datagram_size = CONFIG_CDC_NCM_ETH_MAX_SEGSZE; +static uint32_t g_cdc_ncm_ntb_in_max_size = CONFIG_CDC_NCM_NTB_MAX_SIZE; +static uint32_t g_cdc_ncm_ntb_out_max_size = CONFIG_CDC_NCM_NTB_MAX_SIZE; +static uint16_t g_cdc_ncm_ntb_format = 0; +static uint16_t g_cdc_ncm_packet_filter = 0; +static volatile uint8_t g_current_net_status = 0; +static volatile uint8_t g_cmd_intf = 0; +static uint8_t g_cdc_ncm_mac[6] = { 0 }; +static bool g_cdc_ncm_ep_registered = false; + +static uint32_t g_connect_speed_table[2] = { CDC_NCM_CONNECT_SPEED_UPSTREAM, CDC_NCM_CONNECT_SPEED_DOWNSTREAM }; + +static void usbd_cdc_ncm_send_notify(uint8_t notifycode, uint8_t value, uint32_t *speed) +{ + struct cdc_eth_notification *notify = (struct cdc_eth_notification *)g_cdc_ncm_notify_buf; + uint8_t bytes2send = 0; + + memset(g_cdc_ncm_notify_buf, 0, 16); + notify->bmRequestType = CDC_ECM_BMREQUEST_TYPE_ECM; + notify->bNotificationType = notifycode; + notify->wIndex = g_cmd_intf; + + switch (notifycode) { + case CDC_ECM_NOTIFY_CODE_NETWORK_CONNECTION: + notify->wValue = value; + bytes2send = 8; + break; + case CDC_ECM_NOTIFY_CODE_RESPONSE_AVAILABLE: + bytes2send = 8; + break; + case CDC_ECM_NOTIFY_CODE_CONNECTION_SPEED_CHANGE: + notify->wLength = 8; + if (speed) { + memcpy(notify->data, speed, 8); + } + bytes2send = 16; + break; + default: + break; + } + + if (usb_device_is_configured(0) && bytes2send) { + usbd_ep_start_write(0, cdc_ncm_ep_data[CDC_NCM_INT_EP_IDX].ep_addr, g_cdc_ncm_notify_buf, bytes2send); + } +} + +static void usbd_cdc_ncm_fill_ntb_parameters(void) +{ + memset(g_cdc_ncm_ctrl_buf, 0, 32); + SET_LE16(&g_cdc_ncm_ctrl_buf[0], 28); /* wLength */ + SET_LE16(&g_cdc_ncm_ctrl_buf[2], 0x0001); /* NTB16 only */ + SET_LE32(&g_cdc_ncm_ctrl_buf[4], g_cdc_ncm_ntb_in_max_size); /* device-to-host NTB */ + SET_LE16(&g_cdc_ncm_ctrl_buf[8], 4); /* wNdbInDivisor */ + SET_LE16(&g_cdc_ncm_ctrl_buf[10], 0); /* wNdbInPayloadRemainder */ + SET_LE16(&g_cdc_ncm_ctrl_buf[12], 4); /* wNdbInAlignment */ + SET_LE16(&g_cdc_ncm_ctrl_buf[14], 0); /* wReserved */ + SET_LE32(&g_cdc_ncm_ctrl_buf[16], g_cdc_ncm_ntb_out_max_size);/* host-to-device NTB */ + SET_LE16(&g_cdc_ncm_ctrl_buf[20], 4); /* wNdbOutDivisor */ + SET_LE16(&g_cdc_ncm_ctrl_buf[22], 0); /* wNdbOutPayloadRemainder */ + SET_LE16(&g_cdc_ncm_ctrl_buf[24], 4); /* wNdbOutAlignment */ + SET_LE16(&g_cdc_ncm_ctrl_buf[26], 1); /* one datagram preferred */ +} + +static int cdc_ncm_class_interface_request_handler(uint8_t busid, struct usb_setup_packet *setup, uint8_t **data, uint32_t *len) +{ + (void)busid; + + g_cmd_intf = LO_BYTE(setup->wIndex); + + switch (setup->bRequest) { + case CDC_REQUEST_GET_NTB_PARAMETERS: + usbd_cdc_ncm_fill_ntb_parameters(); + *data = g_cdc_ncm_ctrl_buf; + *len = 28; + break; + case CDC_REQUEST_GET_NTB_FORMAT: + SET_LE16(g_cdc_ncm_ctrl_buf, g_cdc_ncm_ntb_format); + *data = g_cdc_ncm_ctrl_buf; + *len = 2; + break; + case CDC_REQUEST_SET_NTB_FORMAT: + if (setup->wValue != 0) { + return -1; + } + g_cdc_ncm_ntb_format = 0; + break; + case CDC_REQUEST_GET_NTB_INPUT_SIZE: + SET_LE32(g_cdc_ncm_ctrl_buf, g_cdc_ncm_ntb_in_max_size); + *data = g_cdc_ncm_ctrl_buf; + *len = 4; + break; + case CDC_REQUEST_SET_NTB_INPUT_SIZE: + if (setup->wLength >= 4 && data && *data) { + uint32_t ntb_size = GET_LE32(*data); + if (ntb_size >= (CDC_NCM_DATAGRAM_OFFSET + CDC_NCM_NDP16_LEN) && ntb_size <= CONFIG_CDC_NCM_NTB_MAX_SIZE) { + g_cdc_ncm_ntb_in_max_size = ntb_size; + } + } + break; + case CDC_REQUEST_GET_MAX_DATAGRAM_SIZE: + SET_LE16(g_cdc_ncm_ctrl_buf, g_cdc_ncm_max_datagram_size); + *data = g_cdc_ncm_ctrl_buf; + *len = 2; + break; + case CDC_REQUEST_SET_MAX_DATAGRAM_SIZE: + if (setup->wLength >= 2 && data && *data) { + uint16_t max_datagram_size = GET_LE16(*data); + if (max_datagram_size >= 64 && max_datagram_size <= CONFIG_CDC_NCM_ETH_MAX_SEGSZE) { + g_cdc_ncm_max_datagram_size = max_datagram_size; + } + } else if (setup->wValue >= 64 && setup->wValue <= CONFIG_CDC_NCM_ETH_MAX_SEGSZE) { + g_cdc_ncm_max_datagram_size = setup->wValue; + } + break; + case CDC_REQUEST_GET_CRC_MODE: + SET_LE16(g_cdc_ncm_ctrl_buf, 0); + *data = g_cdc_ncm_ctrl_buf; + *len = 2; + break; + case CDC_REQUEST_SET_CRC_MODE: + if (setup->wValue != 0) { + return -1; + } + break; + case CDC_REQUEST_GET_NET_ADDRESS: + memcpy(g_cdc_ncm_ctrl_buf, g_cdc_ncm_mac, 6); + *data = g_cdc_ncm_ctrl_buf; + *len = 6; + break; + case CDC_REQUEST_SET_NET_ADDRESS: + if (setup->wLength >= 6 && data && *data) { + memcpy(g_cdc_ncm_mac, *data, 6); + } + break; + case CDC_REQUEST_SET_ETHERNET_PACKET_FILTER: + g_cdc_ncm_packet_filter = setup->wValue; + g_connect_speed_table[0] = 100000000; + g_connect_speed_table[1] = 100000000; + usbd_cdc_ncm_set_connect(g_cdc_ncm_packet_filter != 0, g_connect_speed_table); + break; + case CDC_REQUEST_SET_ETHERNET_MULTICAST_FILTERS: + case CDC_REQUEST_SET_ETHERNET_PMP_FILTER: + break; + default: + USB_LOG_WRN("Unhandled CDC NCM Class bRequest 0x%02x\r\n", setup->bRequest); + return -1; + } + + return 0; +} + +static void cdc_ncm_notify_handler(uint8_t busid, uint8_t event, void *arg) +{ + (void)busid; + + switch (event) { + case USBD_EVENT_RESET: + case USBD_EVENT_DISCONNECTED: + g_current_net_status = 0; + g_cdc_ncm_rx_ntb_length = 0; + g_cdc_ncm_tx_ntb_length = 0; + g_cdc_ncm_data_alt_active = false; + g_cdc_ncm_rx_datagram_pos = 0; + g_cdc_ncm_rx_ndp_index = 0; + break; + case USBD_EVENT_SET_INTERFACE: { +#ifdef CONFIG_USBDEV_CDC_NCM_USING_LWIP + struct usb_interface_descriptor *desc = (struct usb_interface_descriptor *)arg; + + if (desc && desc->bAlternateSetting == 1) { + g_cdc_ncm_data_alt_active = true; + usbd_cdc_ncm_start_read(g_cdc_ncm_rx_buffer, g_cdc_ncm_ntb_out_max_size); + } else { + g_cdc_ncm_data_alt_active = false; + g_cdc_ncm_tx_ntb_length = 0; + } +#else + (void)arg; +#endif + break; + } + default: + break; + } +} + +static void cdc_ncm_bulk_out(uint8_t busid, uint8_t ep, uint32_t nbytes) +{ + (void)busid; + (void)ep; + + g_cdc_ncm_rx_ntb_length = nbytes; + g_cdc_ncm_rx_datagram_pos = 0; + g_cdc_ncm_rx_ndp_index = 0; + usbd_cdc_ncm_data_recv_done(g_cdc_ncm_rx_ntb_length); +} + +static void cdc_ncm_bulk_in(uint8_t busid, uint8_t ep, uint32_t nbytes) +{ + (void)busid; + + if ((nbytes % usbd_get_ep_mps(0, ep)) == 0 && nbytes) { + usbd_ep_start_write(0, ep, NULL, 0); + } else { + usbd_cdc_ncm_data_send_done(g_cdc_ncm_tx_ntb_length); + g_cdc_ncm_tx_ntb_length = 0; + } +} + +static void cdc_ncm_int_in(uint8_t busid, uint8_t ep, uint32_t nbytes) +{ + (void)busid; + (void)ep; + (void)nbytes; + + if (g_current_net_status == 2) { + g_current_net_status = 3; + usbd_cdc_ncm_send_notify(CDC_ECM_NOTIFY_CODE_CONNECTION_SPEED_CHANGE, 0, g_connect_speed_table); + } else { + g_current_net_status = 0; + } +} + +int usbd_cdc_ncm_start_write(uint8_t *buf, uint32_t len) +{ + int ret; + + if (!usb_device_is_configured(0) || !g_cdc_ncm_data_alt_active) { + return -USB_ERR_NOTCONN; + } + + if (g_cdc_ncm_tx_ntb_length > 0) { + return -USB_ERR_BUSY; + } + + /* mark busy before submitting: the transfer may complete in interrupt + context before usbd_ep_start_write() returns */ + g_cdc_ncm_tx_ntb_length = len; + ret = usbd_ep_start_write(0, cdc_ncm_ep_data[CDC_NCM_IN_EP_IDX].ep_addr, buf, len); + if (ret != 0) { + g_cdc_ncm_tx_ntb_length = 0; + return ret; + } + + USB_LOG_DBG("txlen:%d\r\n", g_cdc_ncm_tx_ntb_length); + return 0; +} + +int usbd_cdc_ncm_start_read(uint8_t *buf, uint32_t len) +{ + if (!usb_device_is_configured(0)) { + return -USB_ERR_NOTCONN; + } + + g_cdc_ncm_rx_data_buffer = buf; + g_cdc_ncm_rx_total_length = len; + g_cdc_ncm_rx_ntb_length = 0; + g_cdc_ncm_rx_datagram_pos = 0; + g_cdc_ncm_rx_ndp_index = 0; + return usbd_ep_start_read(0, cdc_ncm_ep_data[CDC_NCM_OUT_EP_IDX].ep_addr, buf, len); +} + +#ifdef CONFIG_USBDEV_CDC_NCM_USING_LWIP +static bool cdc_ncm_check_ndp16(uint16_t ndp_index) +{ + struct cdc_ncm_ndp16 *ndp16; + uint32_t signature; + uint16_t ndp_len; + + if (ndp_index == 0 || (uint32_t)ndp_index + sizeof(struct cdc_ncm_ndp16) > g_cdc_ncm_rx_ntb_length) { + return false; + } + + ndp16 = (struct cdc_ncm_ndp16 *)&g_cdc_ncm_rx_data_buffer[ndp_index]; + signature = GET_LE32((uint8_t *)&ndp16->dwSignature); + ndp_len = GET_LE16((uint8_t *)&ndp16->wLength); + + if ((signature != CDC_NCM_NDP16_SIGNATURE_NCM0) && + (signature != CDC_NCM_NDP16_SIGNATURE_NCM1)) { + USB_LOG_WRN("invalid ncm ndp16 signature\r\n"); + return false; + } + + if (ndp_len < 12 || (uint32_t)ndp_index + ndp_len > g_cdc_ncm_rx_ntb_length) { + USB_LOG_WRN("invalid ncm ndp16 len\r\n"); + return false; + } + + return true; +} + +static bool cdc_ncm_prepare_rx_ndp(void) +{ + struct cdc_ncm_nth16 *nth16; + uint16_t ndp_index; + + if (g_cdc_ncm_rx_ntb_length < (CDC_NCM_NTH16_LEN + CDC_NCM_NDP16_LEN)) { + return false; + } + + nth16 = (struct cdc_ncm_nth16 *)g_cdc_ncm_rx_data_buffer; + ndp_index = GET_LE16((uint8_t *)&nth16->wNdpIndex); + if (GET_LE32((uint8_t *)&nth16->dwSignature) != CDC_NCM_NTH16_SIGNATURE || + GET_LE16((uint8_t *)&nth16->wHeaderLength) != CDC_NCM_NTH16_LEN || + (uint32_t)GET_LE16((uint8_t *)&nth16->wBlockLength) > g_cdc_ncm_rx_ntb_length || + !cdc_ncm_check_ndp16(ndp_index)) { + USB_LOG_WRN("invalid ncm nth16\r\n"); + return false; + } + + g_cdc_ncm_rx_ndp_index = ndp_index; + g_cdc_ncm_rx_sequence = GET_LE16((uint8_t *)&nth16->wSequence); + (void)g_cdc_ncm_rx_sequence; + return true; +} + +struct pbuf *usbd_cdc_ncm_eth_rx(void) +{ + struct cdc_ncm_ndp16 *ndp16; + uint16_t ndp_len; + uint16_t next_ndp_index; + + if (g_cdc_ncm_rx_ntb_length == 0 || g_cdc_ncm_rx_data_buffer == NULL) { + return NULL; + } + + if (g_cdc_ncm_rx_ndp_index == 0 && !cdc_ncm_prepare_rx_ndp()) { + usbd_cdc_ncm_start_read(g_cdc_ncm_rx_buffer, g_cdc_ncm_ntb_out_max_size); + return NULL; + } + + for (;;) { + ndp16 = (struct cdc_ncm_ndp16 *)&g_cdc_ncm_rx_data_buffer[g_cdc_ncm_rx_ndp_index]; + ndp_len = GET_LE16((uint8_t *)&ndp16->wLength); + + while ((8 + 4 * (g_cdc_ncm_rx_datagram_pos + 1)) <= ndp_len) { + struct cdc_ncm_ndp16_datagram *datagram; + uint16_t index; + uint16_t length; + struct pbuf *p; + + datagram = (struct cdc_ncm_ndp16_datagram *)&g_cdc_ncm_rx_data_buffer[g_cdc_ncm_rx_ndp_index + 8 + 4 * g_cdc_ncm_rx_datagram_pos]; + g_cdc_ncm_rx_datagram_pos++; + index = GET_LE16((uint8_t *)&datagram->wDatagramIndex); + length = GET_LE16((uint8_t *)&datagram->wDatagramLength); + + if (index == 0 || length == 0) { + break; + } + if ((uint32_t)index + length > g_cdc_ncm_rx_ntb_length || length > g_cdc_ncm_max_datagram_size) { + USB_LOG_WRN("invalid ncm datagram index:%u len:%u\r\n", index, length); + continue; + } + + p = pbuf_alloc(PBUF_RAW, length, PBUF_POOL); + if (p == NULL) { + USB_LOG_WRN("ncm pbuf alloc failed\r\n"); + usbd_cdc_ncm_start_read(g_cdc_ncm_rx_buffer, g_cdc_ncm_ntb_out_max_size); + return NULL; + } + if (pbuf_take(p, &g_cdc_ncm_rx_data_buffer[index], length) != ERR_OK) { + pbuf_free(p); + continue; + } + + USB_LOG_DBG("rxlen:%d\r\n", length); + return p; + } + + /* current ndp is exhausted, follow the ndp chain if present */ + next_ndp_index = GET_LE16((uint8_t *)&ndp16->wNextNdpIndex); + if (next_ndp_index == 0 || !cdc_ncm_check_ndp16(next_ndp_index)) { + break; + } + g_cdc_ncm_rx_ndp_index = next_ndp_index; + g_cdc_ncm_rx_datagram_pos = 0; + } + + usbd_cdc_ncm_start_read(g_cdc_ncm_rx_buffer, g_cdc_ncm_ntb_out_max_size); + return NULL; +} + +int usbd_cdc_ncm_eth_tx(struct pbuf *p) +{ + struct cdc_ncm_nth16 *nth16; + struct cdc_ncm_ndp16 *ndp16; + struct cdc_ncm_ndp16_datagram *datagram; + struct pbuf *q; + uint8_t *buffer; + uint16_t payload_len; + uint16_t aligned_payload_len; + uint16_t ndp_index; + uint16_t block_len; + + if (!usb_device_is_configured(0)) { + return -USB_ERR_NOTCONN; + } + + if (g_cdc_ncm_tx_ntb_length > 0) { + return -USB_ERR_BUSY; + } + + if (p->tot_len > g_cdc_ncm_max_datagram_size) { + USB_LOG_WRN("ncm tx frame too large:%u\r\n", p->tot_len); + return -USB_ERR_INVAL; + } + + payload_len = p->tot_len; + aligned_payload_len = USB_ALIGN_UP(payload_len, 4); + ndp_index = CDC_NCM_DATAGRAM_OFFSET + aligned_payload_len; + block_len = ndp_index + CDC_NCM_NDP16_LEN; + if (block_len > sizeof(g_cdc_ncm_tx_buffer) || block_len > g_cdc_ncm_ntb_in_max_size) { + return -USB_ERR_INVAL; + } + + memset(g_cdc_ncm_tx_buffer, 0, block_len); + buffer = &g_cdc_ncm_tx_buffer[CDC_NCM_DATAGRAM_OFFSET]; + for (q = p; q != NULL && payload_len > 0; q = q->next) { + uint16_t copy_len = MIN(q->len, payload_len); + usb_memcpy(buffer, q->payload, copy_len); + buffer += copy_len; + payload_len -= copy_len; + } + payload_len = p->tot_len; + + nth16 = (struct cdc_ncm_nth16 *)&g_cdc_ncm_tx_buffer[0]; + SET_LE32((uint8_t *)&nth16->dwSignature, CDC_NCM_NTH16_SIGNATURE); + SET_LE16((uint8_t *)&nth16->wHeaderLength, CDC_NCM_NTH16_LEN); + SET_LE16((uint8_t *)&nth16->wSequence, g_cdc_ncm_tx_sequence++); + SET_LE16((uint8_t *)&nth16->wBlockLength, block_len); + SET_LE16((uint8_t *)&nth16->wNdpIndex, ndp_index); + + ndp16 = (struct cdc_ncm_ndp16 *)&g_cdc_ncm_tx_buffer[ndp_index]; + SET_LE32((uint8_t *)&ndp16->dwSignature, CDC_NCM_NDP16_SIGNATURE_NCM0); + SET_LE16((uint8_t *)&ndp16->wLength, CDC_NCM_NDP16_LEN); + SET_LE16((uint8_t *)&ndp16->wNextNdpIndex, 0); + + datagram = (struct cdc_ncm_ndp16_datagram *)&g_cdc_ncm_tx_buffer[ndp_index + 8]; + SET_LE16((uint8_t *)&datagram[0].wDatagramIndex, CDC_NCM_DATAGRAM_OFFSET); + SET_LE16((uint8_t *)&datagram[0].wDatagramLength, payload_len); + datagram[1].wDatagramIndex = 0; + datagram[1].wDatagramLength = 0; + + return usbd_cdc_ncm_start_write(g_cdc_ncm_tx_buffer, block_len); +} +#endif + +struct usbd_interface *usbd_cdc_ncm_init_intf(struct usbd_interface *intf, + const uint8_t int_ep, + const uint8_t out_ep, + const uint8_t in_ep, + uint8_t mac[6]) +{ + memcpy(g_cdc_ncm_mac, mac, 6); + + intf->class_interface_handler = cdc_ncm_class_interface_request_handler; + intf->class_endpoint_handler = NULL; + intf->vendor_handler = NULL; + intf->notify_handler = cdc_ncm_notify_handler; + + /* control and data interfaces share the same endpoints, register them only once */ + if (!g_cdc_ncm_ep_registered) { + g_cdc_ncm_ep_registered = true; + + cdc_ncm_ep_data[CDC_NCM_OUT_EP_IDX].ep_addr = out_ep; + cdc_ncm_ep_data[CDC_NCM_OUT_EP_IDX].ep_cb = cdc_ncm_bulk_out; + cdc_ncm_ep_data[CDC_NCM_IN_EP_IDX].ep_addr = in_ep; + cdc_ncm_ep_data[CDC_NCM_IN_EP_IDX].ep_cb = cdc_ncm_bulk_in; + cdc_ncm_ep_data[CDC_NCM_INT_EP_IDX].ep_addr = int_ep; + cdc_ncm_ep_data[CDC_NCM_INT_EP_IDX].ep_cb = cdc_ncm_int_in; + + usbd_add_endpoint(0, &cdc_ncm_ep_data[CDC_NCM_OUT_EP_IDX]); + usbd_add_endpoint(0, &cdc_ncm_ep_data[CDC_NCM_IN_EP_IDX]); + usbd_add_endpoint(0, &cdc_ncm_ep_data[CDC_NCM_INT_EP_IDX]); + } + + return intf; +} + +int usbd_cdc_ncm_set_connect(bool connect, uint32_t speed[2]) +{ + if (!usb_device_is_configured(0)) { + return -USB_ERR_NOTCONN; + } + + if (connect) { + g_current_net_status = 2; + if (speed) { + memcpy(g_connect_speed_table, speed, 8); + } + usbd_cdc_ncm_send_notify(CDC_ECM_NOTIFY_CODE_NETWORK_CONNECTION, CDC_ECM_NET_CONNECTED, NULL); + } else { + g_current_net_status = 1; + usbd_cdc_ncm_send_notify(CDC_ECM_NOTIFY_CODE_NETWORK_CONNECTION, CDC_ECM_NET_DISCONNECTED, NULL); + } + + return 0; +} + +__WEAK void usbd_cdc_ncm_data_recv_done(uint32_t len) +{ + (void)len; +} + +__WEAK void usbd_cdc_ncm_data_send_done(uint32_t len) +{ + (void)len; +} diff --git a/class/cdc/usbd_cdc_ncm.h b/class/cdc/usbd_cdc_ncm.h new file mode 100644 index 00000000..7a232c32 --- /dev/null +++ b/class/cdc/usbd_cdc_ncm.h @@ -0,0 +1,41 @@ +/* + * CherryUSB CDC NCM device class glue + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef USBD_CDC_NCM_H +#define USBD_CDC_NCM_H + +#include <stdint.h> +#include <stdbool.h> +#include "usb_cdc.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct usbd_interface *usbd_cdc_ncm_init_intf(struct usbd_interface *intf, + const uint8_t int_ep, + const uint8_t out_ep, + const uint8_t in_ep, + uint8_t mac[6]); + +int usbd_cdc_ncm_set_connect(bool connect, uint32_t speed[2]); + +void usbd_cdc_ncm_data_recv_done(uint32_t len); +void usbd_cdc_ncm_data_send_done(uint32_t len); +int usbd_cdc_ncm_start_write(uint8_t *buf, uint32_t len); +int usbd_cdc_ncm_start_read(uint8_t *buf, uint32_t len); + +#ifdef CONFIG_USBDEV_CDC_NCM_USING_LWIP +#include "lwip/netif.h" +#include "lwip/pbuf.h" +struct pbuf *usbd_cdc_ncm_eth_rx(void); +int usbd_cdc_ncm_eth_tx(struct pbuf *p); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* USBD_CDC_NCM_H */ diff --git a/class/hub/usbh_hub.c b/class/hub/usbh_hub.c index 5538de86..26601d01 100644 --- a/class/hub/usbh_hub.c +++ b/class/hub/usbh_hub.c @@ -731,21 +731,21 @@ int usbh_hub_initialize(struct usbh_bus *bus) bus->hub_mq = usb_osal_mq_create(7); if (bus->hub_mq == NULL) { - USB_LOG_ERR("Failed to create hub mq\r\n"); - return -1; + return -USB_ERR_NOMEM; } bus->hub_sem = usb_osal_sem_create(0); if (bus->hub_sem == NULL) { - USB_LOG_ERR("Failed to create hub sem\r\n"); - return -1; + usb_osal_mq_delete(bus->hub_mq); + return -USB_ERR_NOMEM; } snprintf(thread_name, 32, "usbh_hub%u", bus->busid); bus->hub_thread = usb_osal_thread_create(thread_name, CONFIG_USBHOST_PSC_STACKSIZE, CONFIG_USBHOST_PSC_PRIO, usbh_hub_thread, bus); if (bus->hub_thread == NULL) { - USB_LOG_ERR("Failed to create hub thread\r\n"); - return -1; + usb_osal_mq_delete(bus->hub_mq); + usb_osal_sem_delete(bus->hub_sem); + return -USB_ERR_NOMEM; } return 0; } @@ -759,6 +759,7 @@ int usbh_hub_deinitialize(struct usbh_bus *bus) usb_osal_mq_send(bus->hub_mq, (uintptr_t)NULL); usb_osal_sem_take(bus->hub_sem, USB_OSAL_WAITING_FOREVER); usb_osal_sem_delete(bus->hub_sem); + usb_osal_mq_delete(bus->hub_mq); bus->hub_mq = NULL; bus->hub_sem = NULL; diff --git a/class/msc/usbd_msc.c b/class/msc/usbd_msc.c index 6523ffb9..58e78c2c 100644 --- a/class/msc/usbd_msc.c +++ b/class/msc/usbd_msc.c @@ -103,11 +103,12 @@ void msc_storage_notify_handler(uint8_t busid, uint8_t event, void *arg) #if defined(CONFIG_USBDEV_MSC_THREAD) g_usbd_msc[busid].usbd_msc_mq = usb_osal_mq_create(1); if (g_usbd_msc[busid].usbd_msc_mq == NULL) { - USB_LOG_ERR("No memory to alloc for g_usbd_msc[busid].usbd_msc_mq\r\n"); + return; } g_usbd_msc[busid].usbd_msc_thread = usb_osal_thread_create("usbd_msc", CONFIG_USBDEV_MSC_STACKSIZE, CONFIG_USBDEV_MSC_PRIO, usbdev_msc_thread, (void *)(uint32_t)busid); if (g_usbd_msc[busid].usbd_msc_thread == NULL) { - USB_LOG_ERR("No memory to alloc for g_usbd_msc[busid].usbd_msc_thread\r\n"); + usb_osal_mq_delete(g_usbd_msc[busid].usbd_msc_mq); + return; } #elif defined(CONFIG_USBDEV_MSC_POLLING) g_usbd_msc[busid].event = 0; @@ -504,6 +505,39 @@ static bool SCSI_readCapacity10(uint8_t busid, uint8_t **data, uint32_t *len) return true; } +static bool SCSI_readCapacity16(uint8_t busid, uint8_t **data, uint32_t *len) +{ + uint8_t capacity16[32]; + uint32_t last_lba; + uint32_t blk_size; + + /* service action 0x10 = READ CAPACITY(16); other service actions unsupported */ + if ((g_usbd_msc[busid].cbw.dDataLength == 0U) || + ((g_usbd_msc[busid].cbw.CB[1] & 0x1fU) != 0x10U)) { + SCSI_SetSenseData(busid, SCSI_KCQIR_INVALIDCOMMAND); + return false; + } + + last_lba = g_usbd_msc[busid].scsi_blk_nbr[g_usbd_msc[busid].cbw.bLUN] - 1U; + blk_size = g_usbd_msc[busid].scsi_blk_size[g_usbd_msc[busid].cbw.bLUN]; + + memset(capacity16, 0, sizeof(capacity16)); + /* 8-byte LBA (project volume < 4G, upper 4 bytes stay 0) */ + capacity16[4] = (uint8_t)((last_lba >> 24) & 0xff); + capacity16[5] = (uint8_t)((last_lba >> 16) & 0xff); + capacity16[6] = (uint8_t)((last_lba >> 8) & 0xff); + capacity16[7] = (uint8_t)(last_lba & 0xff); + /* 4-byte block length */ + capacity16[8] = (uint8_t)((blk_size >> 24) & 0xff); + capacity16[9] = (uint8_t)((blk_size >> 16) & 0xff); + capacity16[10] = (uint8_t)((blk_size >> 8) & 0xff); + capacity16[11] = (uint8_t)(blk_size & 0xff); + + memcpy(*data, (uint8_t *)capacity16, sizeof(capacity16)); + *len = sizeof(capacity16); + return true; +} + static bool SCSI_read10(uint8_t busid, uint8_t **data, uint32_t *len) { (void)data; @@ -727,6 +761,9 @@ static bool SCSI_CBWDecode(uint8_t busid, uint32_t nbytes) case SCSI_CMD_READCAPACITY10: ret = SCSI_readCapacity10(busid, &buf2send, &len2send); break; + case SCSI_CMD_READCAPACITY16: + ret = SCSI_readCapacity16(busid, &buf2send, &len2send); + break; case SCSI_CMD_READ10: ret = SCSI_read10(busid, NULL, 0); break; diff --git a/class/serial/usbh_serial.c b/class/serial/usbh_serial.c index 66aa51fc..5cc96fd1 100644 --- a/class/serial/usbh_serial.c +++ b/class/serial/usbh_serial.c @@ -19,7 +19,9 @@ static struct usbh_serial g_serial_class[CONFIG_USBHOST_MAX_SERIAL_CLASS]; static uint32_t g_devinuse = 0; static uint32_t g_cdcacm_devinuse = 0; -USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_serial_iobuffer[CONFIG_USBHOST_MAX_SERIAL_CLASS][USB_ALIGN_UP((USBH_SERIAL_RX2_NOCACHE_OFFSET + USBH_SERIAL_RX2_NOCACHE_SIZE), CONFIG_USB_ALIGN_SIZE)]; +USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_serial_iobuffer[CONFIG_USBHOST_MAX_SERIAL_CLASS][USB_ALIGN_UP((USBH_SERIAL_RX2_NOCACHE_OFFSET + CONFIG_USBHOST_SERIAL_BULKIN_SIZE), CONFIG_USB_ALIGN_SIZE)]; + +static void usbh_serial_callback(void *arg, int nbytes); static struct usbh_serial *usbh_serial_alloc(bool is_cdcacm) { @@ -35,6 +37,11 @@ static struct usbh_serial *usbh_serial_alloc(bool is_cdcacm) g_serial_class[devno].iobuffer = g_serial_iobuffer[devno]; g_serial_class[devno].rx_complete_sem = usb_osal_sem_create(0); + if (g_serial_class[devno].rx_complete_sem == NULL) { + g_devinuse &= ~(1U << devno); + return NULL; + } + if (is_cdcacm) { for (devno2 = 0; devno2 < CONFIG_USBHOST_MAX_SERIAL_CLASS; devno2++) { if ((g_cdcacm_devinuse & (1U << devno2)) == 0) { @@ -67,15 +74,28 @@ static void usbh_serial_free(struct usbh_serial *serial) if (g_serial_class[devno].rx_complete_sem) { usb_osal_sem_delete(g_serial_class[devno].rx_complete_sem); + g_serial_class[devno].rx_complete_sem = NULL; } } +static int usbh_serial_rx_restart(struct usbh_serial *serial) +{ + /* resubmit the read urb */ + serial->rx_errorcode = 0; + usbh_bulk_urb_fill(&serial->bulkin_urb, serial->hport, serial->bulkin, &serial->iobuffer[serial->rx_buf_index ? USBH_SERIAL_RX2_NOCACHE_OFFSET : USBH_SERIAL_RX_NOCACHE_OFFSET], CONFIG_USBHOST_SERIAL_BULKIN_SIZE, + 0, usbh_serial_callback, serial); + return usbh_submit_urb(&serial->bulkin_urb); +} + static void usbh_serial_callback(void *arg, int nbytes) { struct usbh_serial *serial = (struct usbh_serial *)arg; - uint32_t free_space; + uint8_t prev_buf_index; int ret; + if (!serial) + return; + if (nbytes < 0) { if (nbytes != -USB_ERR_SHUTDOWN) { USB_LOG_ERR("serial transfer error: %d\n", nbytes); @@ -93,30 +113,29 @@ static void usbh_serial_callback(void *arg, int nbytes) } if (nbytes >= serial->driver->ignore_rx_header) { - /* resubmit the read urb */ - usbh_bulk_urb_fill(&serial->bulkin_urb, serial->hport, serial->bulkin, &serial->iobuffer[serial->rx_buf_index ? USBH_SERIAL_RX_NOCACHE_OFFSET : USBH_SERIAL_RX2_NOCACHE_OFFSET], serial->bulkin->wMaxPacketSize, - 0, usbh_serial_callback, serial); - ret = usbh_submit_urb(&serial->bulkin_urb); - if (ret < 0) { - USB_LOG_ERR("serial submit failed: %d\n", ret); - serial->rx_errorcode = ret; - usb_osal_sem_give(serial->rx_complete_sem); - return; - } - - free_space = usb_ringbuffer_get_free(&serial->rx_rb); - if (free_space < (nbytes - serial->driver->ignore_rx_header)) { - USB_LOG_ERR("serial rx ringbuffer overflow, free space: %u, rx size: %u\n", free_space, (nbytes - serial->driver->ignore_rx_header)); + prev_buf_index = serial->rx_buf_index; + serial->rx_buf_index ^= 1; + // next ringbuffer write will cause overflow, so don't resubmit the read urb + if (((nbytes - serial->driver->ignore_rx_header) + CONFIG_USBHOST_SERIAL_BULKIN_SIZE) > usb_ringbuffer_get_free(&serial->rx_rb)) { + serial->rx_pending = true; + } else { + serial->rx_pending = false; + ret = usbh_serial_rx_restart(serial); + if (ret < 0) { + USB_LOG_ERR("serial submit failed: %d\n", ret); + serial->rx_errorcode = ret; + usb_osal_sem_give(serial->rx_complete_sem); + return; + } } usb_ringbuffer_write(&serial->rx_rb, - &serial->iobuffer[(serial->rx_buf_index ? USBH_SERIAL_RX2_NOCACHE_OFFSET : USBH_SERIAL_RX_NOCACHE_OFFSET) + serial->driver->ignore_rx_header], + &serial->iobuffer[(prev_buf_index ? USBH_SERIAL_RX2_NOCACHE_OFFSET : USBH_SERIAL_RX_NOCACHE_OFFSET) + serial->driver->ignore_rx_header], (nbytes - serial->driver->ignore_rx_header)); if (serial->rx_complete_callback) { serial->rx_complete_callback(serial, nbytes - serial->driver->ignore_rx_header); } - serial->rx_buf_index ^= 1; serial->rx_errorcode = 0; usb_osal_sem_give(serial->rx_complete_sem); } @@ -375,10 +394,7 @@ int usbh_serial_control(struct usbh_serial *serial, int cmd, void *arg) usb_ringbuffer_reset(&serial->rx_rb); usb_osal_sem_reset(serial->rx_complete_sem); serial->rx_buf_index = 0; - usbh_bulk_urb_fill(&serial->bulkin_urb, serial->hport, serial->bulkin, &serial->iobuffer[serial->rx_buf_index ? USBH_SERIAL_RX2_NOCACHE_OFFSET : USBH_SERIAL_RX_NOCACHE_OFFSET], serial->bulkin->wMaxPacketSize, - 0, usbh_serial_callback, serial); - ret = usbh_submit_urb(&serial->bulkin_urb); - + ret = usbh_serial_rx_restart(serial); return ret; } break; case USBH_SERIAL_CMD_GET_ATTR: { @@ -480,6 +496,14 @@ int usbh_serial_read(struct usbh_serial *serial, void *buffer, uint32_t buflen) return -USB_ERR_NODEV; } + if (usb_ringbuffer_get_free(&serial->rx_rb) >= CONFIG_USBHOST_SERIAL_BULKIN_SIZE && serial->rx_pending) { + serial->rx_pending = false; + ret = usbh_serial_rx_restart(serial); + if (ret < 0) { + return ret; + } + } + if (serial->open_flags & USBH_SERIAL_O_NONBLOCK) { return usb_ringbuffer_read(&serial->rx_rb, buffer, buflen); } else { diff --git a/class/serial/usbh_serial.h b/class/serial/usbh_serial.h index 06a31709..17d0bd43 100644 --- a/class/serial/usbh_serial.h +++ b/class/serial/usbh_serial.h @@ -9,14 +9,20 @@ #include "usb_cdc.h" +#ifndef CONFIG_USBHOST_SERIAL_BULKIN_SIZE +#define CONFIG_USBHOST_SERIAL_BULKIN_SIZE 512 +#endif + #define USBH_SERIAL_CTRL_NOCACHE_OFFSET 0 #define USBH_SERIAL_CTRL_NOCACHE_SIZE 32 #define USBH_SERIAL_INT_NOCACHE_OFFSET USB_ALIGN_UP(USBH_SERIAL_CTRL_NOCACHE_SIZE, CONFIG_USB_ALIGN_SIZE) #define USBH_SERIAL_INT_NOCACHE_SIZE 32 #define USBH_SERIAL_RX_NOCACHE_OFFSET USB_ALIGN_UP((USBH_SERIAL_INT_NOCACHE_OFFSET + USBH_SERIAL_INT_NOCACHE_SIZE), CONFIG_USB_ALIGN_SIZE) -#define USBH_SERIAL_RX_NOCACHE_SIZE 512 -#define USBH_SERIAL_RX2_NOCACHE_OFFSET USB_ALIGN_UP((USBH_SERIAL_RX_NOCACHE_OFFSET + USBH_SERIAL_RX_NOCACHE_SIZE), CONFIG_USB_ALIGN_SIZE) -#define USBH_SERIAL_RX2_NOCACHE_SIZE 512 +#define USBH_SERIAL_RX2_NOCACHE_OFFSET USB_ALIGN_UP((USBH_SERIAL_RX_NOCACHE_OFFSET + CONFIG_USBHOST_SERIAL_BULKIN_SIZE), CONFIG_USB_ALIGN_SIZE) + +#if CONFIG_USBHOST_SERIAL_RX_SIZE < CONFIG_USBHOST_SERIAL_BULKIN_SIZE +#error "CONFIG_USBHOST_SERIAL_RX_SIZE must be greater than or equal to CONFIG_USBHOST_SERIAL_BULKIN_SIZE" +#endif #define USBH_SERIAL_DATABITS_5 5 #define USBH_SERIAL_DATABITS_6 6 @@ -142,6 +148,7 @@ struct usbh_serial { uint8_t rx_buf_index; int rx_errorcode; usbh_serial_rx_complete_callback_t rx_complete_callback; + bool rx_pending; void *priv; /* Private Data */ void *user_data; /* User Data */ |
