diff --git a/common/usbx_device_classes/inc/ux_device_class_cdc_acm.h b/common/usbx_device_classes/inc/ux_device_class_cdc_acm.h index e973676c..9ffded15 100644 --- a/common/usbx_device_classes/inc/ux_device_class_cdc_acm.h +++ b/common/usbx_device_classes/inc/ux_device_class_cdc_acm.h @@ -1,42 +1,42 @@ /*************************************************************************** - * Copyright (c) 2024 Microsoft Corporation - * + * Copyright (c) 2024 Microsoft Corporation + * * This program and the accompanying materials are made available under the * terms of the MIT License which is available at * https://opensource.org/licenses/MIT. - * + * * SPDX-License-Identifier: MIT **************************************************************************/ /**************************************************************************/ /**************************************************************************/ -/** */ -/** USBX Component */ +/** */ +/** USBX Component */ /** */ /** CDC Class */ /** */ /**************************************************************************/ /**************************************************************************/ -/**************************************************************************/ -/* */ -/* COMPONENT DEFINITION RELEASE */ -/* */ -/* ux_device_class_cdc_acm.h PORTABLE C */ +/**************************************************************************/ +/* */ +/* COMPONENT DEFINITION RELEASE */ +/* */ +/* ux_device_class_cdc_acm.h PORTABLE C */ /* 6.3.0 */ /* AUTHOR */ /* */ /* Chaoqiong Xiao, Microsoft Corporation */ /* */ /* DESCRIPTION */ -/* */ -/* This file defines the equivalences for the USBX Device Class CDC */ -/* ACM component. */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ +/* */ +/* This file defines the equivalences for the USBX Device Class CDC */ +/* ACM component. */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ /* 05-19-2020 Chaoqiong Xiao Initial Version 6.0 */ /* 09-30-2020 Chaoqiong Xiao Modified comment(s), */ /* used UX prefix to refer to */ @@ -69,15 +69,15 @@ #ifndef UX_DEVICE_CLASS_CDC_ACM_H #define UX_DEVICE_CLASS_CDC_ACM_H -/* Determine if a C++ compiler is being used. If so, ensure that standard - C is used to process the API information. */ +/* Determine if a C++ compiler is being used. If so, ensure that standard + C is used to process the API information. */ -#ifdef __cplusplus +#ifdef __cplusplus -/* Yes, C++ compiler is present. Use standard C. */ -extern "C" { +/* Yes, C++ compiler is present. Use standard C. */ +extern "C" { -#endif +#endif /* Internal option: enable the basic USBX error checking. This define is typically used while debugging application. */ @@ -89,6 +89,12 @@ extern "C" { /* #define UX_DEVICE_CLASS_CDC_ACM_WRITE_AUTO_ZLP */ + +/* Option: enable CDC ACM interrupt notifications (Serial State / Line State Change). + When defined, the CDC ACM device class can send status notifications to the host + via an Interrupt IN endpoint (if present in the interface). */ +/* #define UX_DEVICE_CLASS_CDC_ACM_ENABLE_NOTIFICATIONS */ + /* Option: bulk out endpoint / read buffer size, must be larger than max packet size in framework, and aligned in 4-bytes. */ #ifndef UX_DEVICE_CLASS_CDC_ACM_READ_BUFFER_SIZE #define UX_DEVICE_CLASS_CDC_ACM_READ_BUFFER_SIZE 512 @@ -116,7 +122,8 @@ extern "C" { /* Define CDC Class USB Class constants. */ -#define UX_SLAVE_CLASS_CDC_ACM_CLASS 10 +#define UX_SLAVE_CLASS_CDC_ACM_CONTROL_CLASS 0x02 +#define UX_SLAVE_CLASS_CDC_ACM_DATA_CLASS 0x0A /* Device CDC Requests */ #define UX_SLAVE_CLASS_CDC_ACM_SEND_ENCAPSULATED_COMMAND 0x00 @@ -172,6 +179,15 @@ extern "C" { #define UX_SLAVE_CLASS_CDC_ACM_LINE_STATE_DTR 1 #define UX_SLAVE_CLASS_CDC_ACM_LINE_STATE_RTS 2 +/* Define CDC ACM UART state bitmap (Serial State data). */ +#define UX_DEVICE_CLASS_CDC_ACM_UART_STATE_DCD 0x0001 +#define UX_DEVICE_CLASS_CDC_ACM_UART_STATE_DSR 0x0002 +#define UX_DEVICE_CLASS_CDC_ACM_UART_STATE_BREAK 0x0004 +#define UX_DEVICE_CLASS_CDC_ACM_UART_STATE_RING_SIGNAL 0x0008 +#define UX_DEVICE_CLASS_CDC_ACM_UART_STATE_FRAMING 0x0010 +#define UX_DEVICE_CLASS_CDC_ACM_UART_STATE_PARITY 0x0020 +#define UX_DEVICE_CLASS_CDC_ACM_UART_STATE_OVERRUN 0x0040 + /* Define Transfer direction bits. */ #define UX_SLAVE_CLASS_CDC_ACM_ENDPOINT_XMIT 1 #define UX_SLAVE_CLASS_CDC_ACM_ENDPOINT_RCV 2 @@ -253,6 +269,10 @@ typedef struct UX_SLAVE_CLASS_CDC_ACM_STRUCT UCHAR ux_slave_class_cdc_acm_data_rts_state; UCHAR reserved[3]; +#if defined(UX_DEVICE_CLASS_CDC_ACM_ENABLE_NOTIFICATIONS) + USHORT ux_device_class_cdc_acm_serial_state; +#endif + #ifndef UX_DEVICE_CLASS_CDC_ACM_TRANSMISSION_DISABLE #if !defined(UX_DEVICE_STANDALONE) UX_THREAD ux_slave_class_cdc_acm_bulkin_thread; @@ -289,23 +309,23 @@ typedef struct UX_SLAVE_CLASS_CDC_ACM_STRUCT /* Define some CDC Class structures */ -typedef struct UX_SLAVE_CLASS_CDC_ACM_LINE_CODING_PARAMETER_STRUCT +typedef struct UX_SLAVE_CLASS_CDC_ACM_LINE_CODING_PARAMETER_STRUCT { ULONG ux_slave_class_cdc_acm_parameter_baudrate; UCHAR ux_slave_class_cdc_acm_parameter_stop_bit; UCHAR ux_slave_class_cdc_acm_parameter_parity; UCHAR ux_slave_class_cdc_acm_parameter_data_bit; - + } UX_SLAVE_CLASS_CDC_ACM_LINE_CODING_PARAMETER; -typedef struct UX_SLAVE_CLASS_CDC_ACM_LINE_STATE_PARAMETER_STRUCT +typedef struct UX_SLAVE_CLASS_CDC_ACM_LINE_STATE_PARAMETER_STRUCT { UCHAR ux_slave_class_cdc_acm_parameter_rts; UCHAR ux_slave_class_cdc_acm_parameter_dtr; - + } UX_SLAVE_CLASS_CDC_ACM_LINE_STATE_PARAMETER; -typedef struct UX_SLAVE_CLASS_CDC_ACM_CALLBACK_PARAMETER_STRUCT +typedef struct UX_SLAVE_CLASS_CDC_ACM_CALLBACK_PARAMETER_STRUCT { UINT (*ux_device_class_cdc_acm_parameter_write_callback)(struct UX_SLAVE_CLASS_CDC_ACM_STRUCT *cdc_acm, UINT status, ULONG length); UINT (*ux_device_class_cdc_acm_parameter_read_callback)(struct UX_SLAVE_CLASS_CDC_ACM_STRUCT *cdc_acm, UINT status, UCHAR *data_pointer, ULONG length); @@ -316,22 +336,22 @@ typedef struct UX_SLAVE_CLASS_CDC_ACM_CALLBACK_PARAMETER_STRUCT /* Requests - Ethernet Networking Control Model */ -#define UX_SLAVE_CLASS_CDC_ACM_SEND_ENCAPSULATED_COMMAND 0x00 +#define UX_SLAVE_CLASS_CDC_ACM_SEND_ENCAPSULATED_COMMAND 0x00 /* Issues a command in the format of the supported control protocol. The intent of this mechanism is to support networking devices (e.g., host-based cable modems) that require an additional vendor-defined interface for media specific hardware configuration and management. */ -#define UX_SLAVE_CLASS_CDC_ACM_GET_ENCAPSULATED_RESPONSE 0x01 +#define UX_SLAVE_CLASS_CDC_ACM_GET_ENCAPSULATED_RESPONSE 0x01 /* Requests a response in the format of the supported control protocol. */ -#define UX_SLAVE_CLASS_CDC_ACM_SET_ETHERNET_MULTICAST_FILTERS 0x40 +#define UX_SLAVE_CLASS_CDC_ACM_SET_ETHERNET_MULTICAST_FILTERS 0x40 /* As applications are loaded and unloaded on the host, the networking transport will instruct the device's MAC driver to change settings of the Networking device's multicast filters. */ -#define UX_SLAVE_CLASS_CDC_ACM_SET_ETHERNET_POWER_MANAGEMENT_PATTERN_FILTER 0x41 +#define UX_SLAVE_CLASS_CDC_ACM_SET_ETHERNET_POWER_MANAGEMENT_PATTERN_FILTER 0x41 /* Some hosts are able to conserve energy and stay quiet in a 'sleeping' state while not being used. USB Networking devices may provide special pattern filtering @@ -340,13 +360,13 @@ typedef struct UX_SLAVE_CLASS_CDC_ACM_CALLBACK_PARAMETER_STRUCT host (e.g., an incoming web browser connection). Primitives are needed in management plane to negotiate the setting of these special filters */ -#define UX_SLAVE_CLASS_CDC_ACM_GET_ETHERNET_POWER_MANAGEMENT_PATTERN_FILTER 0x42 +#define UX_SLAVE_CLASS_CDC_ACM_GET_ETHERNET_POWER_MANAGEMENT_PATTERN_FILTER 0x42 /* Retrieves the status of the above power management pattern filter setting */ -#define UX_SLAVE_CLASS_CDC_ACM_SET_ETHERNET_PACKET_FILTER 0x43 +#define UX_SLAVE_CLASS_CDC_ACM_SET_ETHERNET_PACKET_FILTER 0x43 /* Sets device filter for running a network analyzer application on the host machine */ -#define UX_SLAVE_CLASS_CDC_ACM_GET_ETHERNET_STATISTIC 0x44 +#define UX_SLAVE_CLASS_CDC_ACM_GET_ETHERNET_STATISTIC 0x44 /* Retrieves Ethernet device statistics such as frames transmitted, frames received, and bad frames received. */ @@ -363,20 +383,20 @@ UINT _ux_device_class_cdc_acm_deactivate(UX_SLAVE_CLASS_COMMAND *command); UINT _ux_device_class_cdc_acm_entry(UX_SLAVE_CLASS_COMMAND *command); UINT _ux_device_class_cdc_acm_initialize(UX_SLAVE_CLASS_COMMAND *command); UINT _ux_device_class_cdc_acm_uninitialize(UX_SLAVE_CLASS_COMMAND *command); -UINT _ux_device_class_cdc_acm_write(UX_SLAVE_CLASS_CDC_ACM *cdc_acm, UCHAR *buffer, +UINT _ux_device_class_cdc_acm_write(UX_SLAVE_CLASS_CDC_ACM *cdc_acm, UCHAR *buffer, ULONG requested_length, ULONG *actual_length); -UINT _ux_device_class_cdc_acm_read(UX_SLAVE_CLASS_CDC_ACM *cdc_acm, UCHAR *buffer, +UINT _ux_device_class_cdc_acm_read(UX_SLAVE_CLASS_CDC_ACM *cdc_acm, UCHAR *buffer, ULONG requested_length, ULONG *actual_length); UINT _ux_device_class_cdc_acm_ioctl(UX_SLAVE_CLASS_CDC_ACM *cdc_acm, ULONG ioctl_function, VOID *parameter); VOID _ux_device_class_cdc_acm_bulkin_thread(ULONG class_pointer); VOID _ux_device_class_cdc_acm_bulkout_thread(ULONG class_pointer); -UINT _ux_device_class_cdc_acm_write_with_callback(UX_SLAVE_CLASS_CDC_ACM *cdc_acm, UCHAR *buffer, +UINT _ux_device_class_cdc_acm_write_with_callback(UX_SLAVE_CLASS_CDC_ACM *cdc_acm, UCHAR *buffer, ULONG requested_length); -UINT _ux_device_class_cdc_acm_write_run(UX_SLAVE_CLASS_CDC_ACM *cdc_acm, UCHAR *buffer, +UINT _ux_device_class_cdc_acm_write_run(UX_SLAVE_CLASS_CDC_ACM *cdc_acm, UCHAR *buffer, ULONG requested_length, ULONG *actual_length); -UINT _ux_device_class_cdc_acm_read_run(UX_SLAVE_CLASS_CDC_ACM *cdc_acm, UCHAR *buffer, +UINT _ux_device_class_cdc_acm_read_run(UX_SLAVE_CLASS_CDC_ACM *cdc_acm, UCHAR *buffer, ULONG requested_length, ULONG *actual_length); UINT _ux_device_class_cdc_acm_tasks_run(VOID *instance); @@ -419,10 +439,10 @@ UINT _uxe_device_class_cdc_acm_read_run(UX_SLAVE_CLASS_CDC_ACM *cdc_acm, UCHAR #endif -/* Determine if a C++ compiler is being used. If so, complete the standard - C conditional started above. */ +/* Determine if a C++ compiler is being used. If so, complete the standard + C conditional started above. */ #ifdef __cplusplus -} -#endif +} +#endif #endif /* UX_DEVICE_CLASS_CDC_ACM_H */ diff --git a/common/usbx_device_classes/src/ux_device_class_cdc_acm_bulkin_thread.c b/common/usbx_device_classes/src/ux_device_class_cdc_acm_bulkin_thread.c index 9836247a..5e6caab8 100644 --- a/common/usbx_device_classes/src/ux_device_class_cdc_acm_bulkin_thread.c +++ b/common/usbx_device_classes/src/ux_device_class_cdc_acm_bulkin_thread.c @@ -1,10 +1,10 @@ /*************************************************************************** - * Copyright (c) 2024 Microsoft Corporation - * + * Copyright (c) 2024 Microsoft Corporation + * * This program and the accompanying materials are made available under the * terms of the MIT License which is available at * https://opensource.org/licenses/MIT. - * + * * SPDX-License-Identifier: MIT **************************************************************************/ @@ -13,7 +13,7 @@ /** */ /** USBX Component */ /** */ -/** Device CDC_ACM Class */ +/** Device CDC ACM Class */ /** */ /**************************************************************************/ /**************************************************************************/ @@ -123,11 +123,19 @@ ULONG sent_length; /* This is the first time we are activated. We need the interface to the class. */ interface_ptr = cdc_acm -> ux_slave_class_cdc_acm_interface; + /* Locate data interface. */ + if (interface_ptr -> ux_slave_interface_descriptor.bInterfaceClass != UX_SLAVE_CLASS_CDC_ACM_DATA_CLASS) + { + /* So the next interface is data interface. */ + interface_ptr = interface_ptr -> ux_slave_interface_next_interface; + } + /* Locate the endpoints. */ endpoint = interface_ptr -> ux_slave_interface_first_endpoint; /* Check the endpoint direction, if IN we have the correct endpoint. */ - if ((endpoint -> ux_slave_endpoint_descriptor.bEndpointAddress & UX_ENDPOINT_DIRECTION) != UX_ENDPOINT_IN) + if (((endpoint -> ux_slave_endpoint_descriptor.bEndpointAddress & UX_ENDPOINT_DIRECTION) != UX_ENDPOINT_IN) || + ((endpoint -> ux_slave_endpoint_descriptor.bmAttributes & UX_MASK_ENDPOINT_TYPE) != UX_BULK_ENDPOINT)) { /* So the next endpoint has to be the IN endpoint. */ @@ -278,8 +286,9 @@ ULONG sent_length; } } - /* We need to suspend ourselves. We will be resumed by the device enumeration module or when a change of alternate setting happens. */ - _ux_device_thread_suspend(&cdc_acm -> ux_slave_class_cdc_acm_bulkin_thread); + /* We need to suspend ourselves. We will be resumed by the device enumeration + module or when a change of alternate setting happens. */ + _ux_device_thread_suspend(&cdc_acm -> ux_slave_class_cdc_acm_bulkin_thread); } } #endif diff --git a/common/usbx_device_classes/src/ux_device_class_cdc_acm_bulkout_thread.c b/common/usbx_device_classes/src/ux_device_class_cdc_acm_bulkout_thread.c index 28c15a22..68bebf4d 100644 --- a/common/usbx_device_classes/src/ux_device_class_cdc_acm_bulkout_thread.c +++ b/common/usbx_device_classes/src/ux_device_class_cdc_acm_bulkout_thread.c @@ -1,10 +1,10 @@ /*************************************************************************** - * Copyright (c) 2024 Microsoft Corporation - * + * Copyright (c) 2024 Microsoft Corporation + * * This program and the accompanying materials are made available under the * terms of the MIT License which is available at * https://opensource.org/licenses/MIT. - * + * * SPDX-License-Identifier: MIT **************************************************************************/ @@ -13,7 +13,7 @@ /** */ /** USBX Component */ /** */ -/** Device CDC_ACM Class */ +/** Device CDC ACM Class */ /** */ /**************************************************************************/ /**************************************************************************/ @@ -108,11 +108,19 @@ UINT status; /* This is the first time we are activated. We need the interface to the class. */ interface_ptr = cdc_acm -> ux_slave_class_cdc_acm_interface; + /* Locate data interface. */ + if (interface_ptr -> ux_slave_interface_descriptor.bInterfaceClass != UX_SLAVE_CLASS_CDC_ACM_DATA_CLASS) + { + /* So the next interface is data interface. */ + interface_ptr = interface_ptr -> ux_slave_interface_next_interface; + } + /* Locate the endpoints. */ endpoint = interface_ptr -> ux_slave_interface_first_endpoint; /* Check the endpoint direction, if OUT we have the correct endpoint. */ - if ((endpoint -> ux_slave_endpoint_descriptor.bEndpointAddress & UX_ENDPOINT_DIRECTION) != UX_ENDPOINT_OUT) + if (((endpoint -> ux_slave_endpoint_descriptor.bEndpointAddress & UX_ENDPOINT_DIRECTION) != UX_ENDPOINT_OUT) || + ((endpoint -> ux_slave_endpoint_descriptor.bmAttributes & UX_MASK_ENDPOINT_TYPE) != UX_BULK_ENDPOINT)) { /* So the next endpoint has to be the OUT endpoint. */ diff --git a/common/usbx_device_classes/src/ux_device_class_cdc_acm_entry.c b/common/usbx_device_classes/src/ux_device_class_cdc_acm_entry.c index ea519105..97fd5d7f 100644 --- a/common/usbx_device_classes/src/ux_device_class_cdc_acm_entry.c +++ b/common/usbx_device_classes/src/ux_device_class_cdc_acm_entry.c @@ -13,7 +13,7 @@ /** */ /** USBX Component */ /** */ -/** Device CDC Class */ +/** Device CDC ACM Class */ /** */ /**************************************************************************/ /**************************************************************************/ @@ -33,7 +33,7 @@ /* FUNCTION RELEASE */ /* */ /* _ux_device_class_cdc_acm_entry PORTABLE C */ -/* 6.x */ +/* 6.4.2 */ /* AUTHOR */ /* */ /* Chaoqiong Xiao, Microsoft Corporation */ @@ -72,10 +72,10 @@ /* 05-19-2020 Chaoqiong Xiao Initial Version 6.0 */ /* 09-30-2020 Chaoqiong Xiao Modified comment(s), */ /* resulting in version 6.1 */ -/* xx-xx-xxxx Mohamed ayed Modified comment(s), */ +/* 02-24-2025 Mohamed AYED Modified comment(s), */ /* fix typo, */ /* remove extra spaces, */ -/* resulting in version 6.x */ +/* resulting in version 6.4.2 */ /* */ /**************************************************************************/ UINT _ux_device_class_cdc_acm_entry(UX_SLAVE_CLASS_COMMAND *command) @@ -108,7 +108,8 @@ UINT status; case UX_SLAVE_CLASS_COMMAND_QUERY: /* Check the CLASS definition in the interface descriptor. */ - if (command -> ux_slave_class_command_class == UX_SLAVE_CLASS_CDC_ACM_CLASS) + if ((command -> ux_slave_class_command_class == UX_SLAVE_CLASS_CDC_ACM_CONTROL_CLASS) || + (command -> ux_slave_class_command_class == UX_SLAVE_CLASS_CDC_ACM_DATA_CLASS)) return(UX_SUCCESS); else return(UX_NO_CLASS_MATCH); @@ -149,4 +150,3 @@ UINT status; return(UX_FUNCTION_NOT_SUPPORTED); } } - diff --git a/common/usbx_device_classes/src/ux_device_class_cdc_acm_read.c b/common/usbx_device_classes/src/ux_device_class_cdc_acm_read.c index 994740ac..b4ffb3a3 100644 --- a/common/usbx_device_classes/src/ux_device_class_cdc_acm_read.c +++ b/common/usbx_device_classes/src/ux_device_class_cdc_acm_read.c @@ -1,19 +1,19 @@ /*************************************************************************** - * Copyright (c) 2024 Microsoft Corporation - * + * Copyright (c) 2024 Microsoft Corporation + * * This program and the accompanying materials are made available under the * terms of the MIT License which is available at * https://opensource.org/licenses/MIT. - * + * * SPDX-License-Identifier: MIT **************************************************************************/ /**************************************************************************/ /**************************************************************************/ -/** */ -/** USBX Component */ /** */ -/** Device CDC Class */ +/** USBX Component */ +/** */ +/** Device CDC ACM Class */ /** */ /**************************************************************************/ /**************************************************************************/ @@ -29,50 +29,50 @@ #if !defined(UX_DEVICE_STANDALONE) -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _ux_device_class_cdc_acm_read PORTABLE C */ +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _ux_device_class_cdc_acm_read PORTABLE C */ /* 6.3.0 */ /* AUTHOR */ /* */ /* Chaoqiong Xiao, Microsoft Corporation */ /* */ /* DESCRIPTION */ -/* */ -/* This function reads from the CDC class. */ -/* */ +/* */ +/* This function reads from the CDC class. */ +/* */ /* It's for RTOS mode. */ -/* */ -/* INPUT */ -/* */ -/* cdc_acm Address of cdc_acm class */ -/* instance */ +/* */ +/* INPUT */ +/* */ +/* cdc_acm Address of cdc_acm class */ +/* instance */ /* buffer Pointer to buffer to save */ /* received data */ /* requested_length Length of bytes to read */ /* actual_length Pointer to save number of */ /* bytes read */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* _ux_device_stack_transfer_request Transfer request */ -/* _ux_utility_memory_copy Copy memory */ -/* _ux_device_mutex_off Release mutex */ -/* */ -/* CALLED BY */ -/* */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* _ux_device_stack_transfer_request Transfer request */ +/* _ux_utility_memory_copy Copy memory */ +/* _ux_device_mutex_off Release mutex */ +/* */ +/* CALLED BY */ +/* */ /* Application */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ /* 05-19-2020 Chaoqiong Xiao Initial Version 6.0 */ /* 09-30-2020 Chaoqiong Xiao Modified comment(s), */ /* verified memset and memcpy */ @@ -96,8 +96,8 @@ /* resulting in version 6.3.0 */ /* */ /**************************************************************************/ -UINT _ux_device_class_cdc_acm_read(UX_SLAVE_CLASS_CDC_ACM *cdc_acm, UCHAR *buffer, - ULONG requested_length, ULONG *actual_length) +UINT _ux_device_class_cdc_acm_read(UX_SLAVE_CLASS_CDC_ACM *cdc_acm, UCHAR *buffer, + ULONG requested_length, ULONG *actual_length) { UX_SLAVE_ENDPOINT *endpoint; @@ -114,17 +114,17 @@ ULONG local_requested_length; /* Check if current cdc-acm is using callback or not. We cannot use direct reads with callback on. */ if (cdc_acm -> ux_slave_class_cdc_acm_transmission_status == UX_TRUE) - + /* Not allowed. */ return(UX_ERROR); #endif /* Get the pointer to the device. */ device = &_ux_system_slave -> ux_system_slave_device; - + /* As long as the device is in the CONFIGURED state. */ if (device -> ux_slave_device_state != UX_DEVICE_CONFIGURED) - { + { /* Error trap. */ _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_CONFIGURATION_HANDLE_UNKNOWN); @@ -132,19 +132,27 @@ ULONG local_requested_length; /* If trace is enabled, insert this event into the trace buffer. */ UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_CONFIGURATION_HANDLE_UNKNOWN, device, 0, 0, UX_TRACE_ERRORS, 0, 0) - + /* Cannot proceed with command, the interface is down. */ return(UX_CONFIGURATION_HANDLE_UNKNOWN); } - + /* This is the first time we are activated. We need the interface to the class. */ interface_ptr = cdc_acm -> ux_slave_class_cdc_acm_interface; - + + /* Locate data interface. */ + if (interface_ptr -> ux_slave_interface_descriptor.bInterfaceClass != UX_SLAVE_CLASS_CDC_ACM_DATA_CLASS) + { + /* So the next interface is data interface. */ + interface_ptr = interface_ptr -> ux_slave_interface_next_interface; + } + /* Locate the endpoints. */ endpoint = interface_ptr -> ux_slave_interface_first_endpoint; - + /* Check the endpoint direction, if OUT we have the correct endpoint. */ - if ((endpoint -> ux_slave_endpoint_descriptor.bEndpointAddress & UX_ENDPOINT_DIRECTION) != UX_ENDPOINT_OUT) + if (((endpoint -> ux_slave_endpoint_descriptor.bEndpointAddress & UX_ENDPOINT_DIRECTION) != UX_ENDPOINT_OUT) || + ((endpoint -> ux_slave_endpoint_descriptor.bmAttributes & UX_MASK_ENDPOINT_TYPE) != UX_BULK_ENDPOINT)) { /* So the next endpoint has to be the OUT endpoint. */ @@ -185,48 +193,48 @@ ULONG local_requested_length; /* Check if we need more transactions. */ while (device -> ux_slave_device_state == UX_DEVICE_CONFIGURED && requested_length != 0) - { - + { + /* Check if we have enough in the local buffer. */ if (requested_length > endpoint -> ux_slave_endpoint_descriptor.wMaxPacketSize) - + /* We have too much to transfer. */ local_requested_length = endpoint -> ux_slave_endpoint_descriptor.wMaxPacketSize; - + else - + /* We can proceed with the demanded length. */ local_requested_length = requested_length; - + /* Send the request to the device controller. */ status = _ux_device_stack_transfer_request(transfer_request, local_requested_length, local_requested_length); - - /* Check the status */ + + /* Check the status */ if (status == UX_SUCCESS) { /* We need to copy the buffer locally. */ _ux_utility_memory_copy(buffer, transfer_request -> ux_slave_transfer_request_data_pointer, transfer_request -> ux_slave_transfer_request_actual_length); /* Use case of memcpy is verified. */ - + /* Next buffer address. */ buffer += transfer_request -> ux_slave_transfer_request_actual_length; - + /* Set the length actually received. */ - *actual_length += transfer_request -> ux_slave_transfer_request_actual_length; - + *actual_length += transfer_request -> ux_slave_transfer_request_actual_length; + /* Decrement what left has to be done. */ requested_length -= transfer_request -> ux_slave_transfer_request_actual_length; /* Is this a short packet or a ZLP indicating we are done with this transfer ? */ if (transfer_request -> ux_slave_transfer_request_actual_length < endpoint -> ux_slave_endpoint_descriptor.wMaxPacketSize) - { + { /* We are done. */ /* Free Mutex resource. */ _ux_device_mutex_off(&cdc_acm -> ux_slave_class_cdc_acm_endpoint_out_mutex); - + /* Return with success. */ return(UX_SUCCESS); @@ -234,13 +242,13 @@ ULONG local_requested_length; } else { - + /* Free Mutex resource. */ _ux_device_mutex_off(&cdc_acm -> ux_slave_class_cdc_acm_endpoint_out_mutex); - + /* We got an error. */ return(status); - } + } } #endif @@ -250,7 +258,7 @@ ULONG local_requested_length; /* Check why we got here, either completion or device was extracted. */ if (device -> ux_slave_device_state != UX_DEVICE_CONFIGURED) - { + { /* Error trap. */ _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_TRANSFER_NO_ANSWER); @@ -262,9 +270,9 @@ ULONG local_requested_length; return (UX_TRANSFER_NO_ANSWER); } else - + /* Simply return the last transaction result. */ - return(status); + return(status); } /**************************************************************************/ @@ -322,5 +330,4 @@ UINT _uxe_device_class_cdc_acm_read(UX_SLAVE_CLASS_CDC_ACM *cdc_acm, UCHAR *buff return (_ux_device_class_cdc_acm_read(cdc_acm, buffer, requested_length, actual_length)); } - -#endif \ No newline at end of file +#endif diff --git a/common/usbx_device_classes/src/ux_device_class_cdc_acm_read_run.c b/common/usbx_device_classes/src/ux_device_class_cdc_acm_read_run.c index 69b74aaf..d53c3e6c 100644 --- a/common/usbx_device_classes/src/ux_device_class_cdc_acm_read_run.c +++ b/common/usbx_device_classes/src/ux_device_class_cdc_acm_read_run.c @@ -1,10 +1,10 @@ /*************************************************************************** - * Copyright (c) 2024 Microsoft Corporation - * + * Copyright (c) 2024 Microsoft Corporation + * * This program and the accompanying materials are made available under the * terms of the MIT License which is available at * https://opensource.org/licenses/MIT. - * + * * SPDX-License-Identifier: MIT **************************************************************************/ @@ -13,7 +13,7 @@ /** */ /** USBX Component */ /** */ -/** Device CDC Class */ +/** Device CDC ACM Class */ /** */ /**************************************************************************/ /**************************************************************************/ @@ -135,11 +135,19 @@ UINT status = UX_SUCCESS; /* This is the first time we are activated. We need the interface to the class. */ class_interface = cdc_acm -> ux_slave_class_cdc_acm_interface; + /* Locate data interface. */ + if (class_interface -> ux_slave_interface_descriptor.bInterfaceClass != UX_SLAVE_CLASS_CDC_ACM_DATA_CLASS) + { + /* So the next interface is data interface. */ + class_interface = class_interface -> ux_slave_interface_next_interface; + } + /* Locate the endpoints. */ endpoint = class_interface -> ux_slave_interface_first_endpoint; /* Check the endpoint direction, if OUT we have the correct endpoint. */ - if ((endpoint -> ux_slave_endpoint_descriptor.bEndpointAddress & UX_ENDPOINT_DIRECTION) != UX_ENDPOINT_OUT) + if (((endpoint -> ux_slave_endpoint_descriptor.bEndpointAddress & UX_ENDPOINT_DIRECTION) != UX_ENDPOINT_OUT) || + ((endpoint -> ux_slave_endpoint_descriptor.bmAttributes & UX_MASK_ENDPOINT_TYPE) != UX_BULK_ENDPOINT)) { /* So the next endpoint has to be the OUT endpoint. */ @@ -309,7 +317,7 @@ UINT status = UX_SUCCESS; cdc_acm -> ux_device_class_cdc_acm_read_status = UX_INVALID_STATE; break; } - + /* Error cases. */ return(UX_STATE_EXIT); diff --git a/common/usbx_device_classes/src/ux_device_class_cdc_acm_write.c b/common/usbx_device_classes/src/ux_device_class_cdc_acm_write.c index 33eb616d..d2618c80 100644 --- a/common/usbx_device_classes/src/ux_device_class_cdc_acm_write.c +++ b/common/usbx_device_classes/src/ux_device_class_cdc_acm_write.c @@ -1,19 +1,19 @@ /*************************************************************************** - * Copyright (c) 2024 Microsoft Corporation - * + * Copyright (c) 2024 Microsoft Corporation + * * This program and the accompanying materials are made available under the * terms of the MIT License which is available at * https://opensource.org/licenses/MIT. - * + * * SPDX-License-Identifier: MIT **************************************************************************/ /**************************************************************************/ /**************************************************************************/ -/** */ -/** USBX Component */ /** */ -/** Device CDC Class */ +/** USBX Component */ +/** */ +/** Device CDC ACM Class */ /** */ /**************************************************************************/ /**************************************************************************/ @@ -29,51 +29,51 @@ #if !defined(UX_DEVICE_STANDALONE) -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _ux_device_class_cdc_acm_write PORTABLE C */ +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _ux_device_class_cdc_acm_write PORTABLE C */ /* 6.3.0 */ /* AUTHOR */ /* */ /* Chaoqiong Xiao, Microsoft Corporation */ /* */ /* DESCRIPTION */ -/* */ -/* This function writes to the CDC class. */ -/* */ +/* */ +/* This function writes to the CDC class. */ +/* */ /* It's for RTOS mode. */ -/* */ -/* INPUT */ -/* */ -/* cdc_acm Address of cdc_acm class */ -/* instance */ +/* */ +/* INPUT */ +/* */ +/* cdc_acm Address of cdc_acm class */ +/* instance */ /* buffer Pointer to data to write */ /* requested_length Length of bytes to write, */ /* set to 0 to issue ZLP */ /* actual_length Pointer to save number of */ /* bytes written */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* _ux_utility_memory_copy Copy memory */ -/* _ux_device_stack_transfer_request Transfer request */ -/* _ux_device_mutex_on Take Mutex */ -/* _ux_device_mutex_off Release Mutex */ -/* */ -/* CALLED BY */ -/* */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* _ux_utility_memory_copy Copy memory */ +/* _ux_device_stack_transfer_request Transfer request */ +/* _ux_device_mutex_on Take Mutex */ +/* _ux_device_mutex_off Release Mutex */ +/* */ +/* CALLED BY */ +/* */ /* Application */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ /* 05-19-2020 Chaoqiong Xiao Initial Version 6.0 */ /* 09-30-2020 Chaoqiong Xiao Modified comment(s), */ /* verified memset and memcpy */ @@ -98,8 +98,8 @@ /* resulting in version 6.3.0 */ /* */ /**************************************************************************/ -UINT _ux_device_class_cdc_acm_write(UX_SLAVE_CLASS_CDC_ACM *cdc_acm, UCHAR *buffer, - ULONG requested_length, ULONG *actual_length) +UINT _ux_device_class_cdc_acm_write(UX_SLAVE_CLASS_CDC_ACM *cdc_acm, UCHAR *buffer, + ULONG requested_length, ULONG *actual_length) { UX_SLAVE_ENDPOINT *endpoint; @@ -117,36 +117,44 @@ UINT status = 0; /* Check if current cdc-acm is using callback or not. We cannot use direct reads with callback on. */ if (cdc_acm -> ux_slave_class_cdc_acm_transmission_status == UX_TRUE) - + /* Not allowed. */ return(UX_ERROR); #endif /* Get the pointer to the device. */ device = &_ux_system_slave -> ux_system_slave_device; - + /* As long as the device is in the CONFIGURED state. */ if (device -> ux_slave_device_state != UX_DEVICE_CONFIGURED) { - + /* Error trap. */ _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_CONFIGURATION_HANDLE_UNKNOWN); /* If trace is enabled, insert this event into the trace buffer. */ UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_CONFIGURATION_HANDLE_UNKNOWN, device, 0, 0, UX_TRACE_ERRORS, 0, 0) - + /* Cannot proceed with command, the interface is down. */ return(UX_CONFIGURATION_HANDLE_UNKNOWN); } - + /* We need the interface to the class. */ interface_ptr = cdc_acm -> ux_slave_class_cdc_acm_interface; - + + /* Locate data interface. */ + if (interface_ptr -> ux_slave_interface_descriptor.bInterfaceClass != UX_SLAVE_CLASS_CDC_ACM_DATA_CLASS) + { + /* So the next interface is data interface. */ + interface_ptr = interface_ptr -> ux_slave_interface_next_interface; + } + /* Locate the endpoints. */ endpoint = interface_ptr -> ux_slave_interface_first_endpoint; - + /* Check the endpoint direction, if IN we have the correct endpoint. */ - if ((endpoint -> ux_slave_endpoint_descriptor.bEndpointAddress & UX_ENDPOINT_DIRECTION) != UX_ENDPOINT_IN) + if (((endpoint -> ux_slave_endpoint_descriptor.bEndpointAddress & UX_ENDPOINT_DIRECTION) != UX_ENDPOINT_IN) || + ((endpoint -> ux_slave_endpoint_descriptor.bmAttributes & UX_MASK_ENDPOINT_TYPE) != UX_BULK_ENDPOINT)) { /* So the next endpoint has to be the IN endpoint. */ @@ -174,7 +182,7 @@ UINT status = 0; /* Check if the application forces a 0 length packet. */ if (device -> ux_slave_device_state == UX_DEVICE_CONFIGURED && requested_length == 0) { - + /* Send the request for 0 byte packet to the device controller. */ status = _ux_device_stack_transfer_request(transfer_request, 0, 0); @@ -183,7 +191,7 @@ UINT status = 0; /* Return the status. */ return(status); - + } else @@ -214,14 +222,14 @@ UINT status = 0; /* Check if we need more transactions. */ local_host_length = UX_DEVICE_CLASS_CDC_ACM_WRITE_BUFFER_SIZE; while (device -> ux_slave_device_state == UX_DEVICE_CONFIGURED && requested_length != 0) - { - + { + /* Check if we have enough in the local buffer. */ if (requested_length > UX_DEVICE_CLASS_CDC_ACM_WRITE_BUFFER_SIZE) - + /* We have too much to transfer. */ local_requested_length = UX_DEVICE_CLASS_CDC_ACM_WRITE_BUFFER_SIZE; - + else { @@ -238,36 +246,36 @@ UINT status = 0; local_host_length = UX_DEVICE_CLASS_CDC_ACM_WRITE_BUFFER_SIZE + 1; #endif } - + /* On a out, we copy the buffer to the caller. Not very efficient but it makes the API easier. */ _ux_utility_memory_copy(transfer_request -> ux_slave_transfer_request_data_pointer, buffer, local_requested_length); /* Use case of memcpy is verified. */ - + /* Send the request to the device controller. */ status = _ux_device_stack_transfer_request(transfer_request, local_requested_length, local_host_length); - - /* Check the status */ + + /* Check the status */ if (status == UX_SUCCESS) { - + /* Next buffer address. */ buffer += transfer_request -> ux_slave_transfer_request_actual_length; - + /* Set the length actually received. */ - *actual_length += transfer_request -> ux_slave_transfer_request_actual_length; - + *actual_length += transfer_request -> ux_slave_transfer_request_actual_length; + /* Decrement what left has to be done. */ requested_length -= transfer_request -> ux_slave_transfer_request_actual_length; - + } - + else { - + /* Free Mutex resource. */ _ux_device_mutex_off(&cdc_acm -> ux_slave_class_cdc_acm_endpoint_in_mutex); - + /* We had an error, abort. */ return(status); } @@ -275,14 +283,14 @@ UINT status = 0; #endif /* _BUFF_OWNER && _ZERO_COPY */ } - + /* Free Mutex resource. */ _ux_device_mutex_off(&cdc_acm -> ux_slave_class_cdc_acm_endpoint_in_mutex); /* Check why we got here, either completion or device was extracted. */ if (device -> ux_slave_device_state != UX_DEVICE_CONFIGURED) { - + /* Error trap. */ _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_TRANSFER_NO_ANSWER); @@ -293,10 +301,10 @@ UINT status = 0; return (UX_TRANSFER_NO_ANSWER); } else - + /* Simply return the last transaction result. */ - return(status); - + return(status); + } /**************************************************************************/ @@ -354,5 +362,4 @@ UINT _uxe_device_class_cdc_acm_write(UX_SLAVE_CLASS_CDC_ACM *cdc_acm, UCHAR *buf return (_ux_device_class_cdc_acm_write(cdc_acm, buffer, requested_length, actual_length)); } - -#endif \ No newline at end of file +#endif diff --git a/common/usbx_device_classes/src/ux_device_class_cdc_acm_write_run.c b/common/usbx_device_classes/src/ux_device_class_cdc_acm_write_run.c index 7a18d29e..124cb6e6 100644 --- a/common/usbx_device_classes/src/ux_device_class_cdc_acm_write_run.c +++ b/common/usbx_device_classes/src/ux_device_class_cdc_acm_write_run.c @@ -1,10 +1,10 @@ /*************************************************************************** - * Copyright (c) 2024 Microsoft Corporation - * + * Copyright (c) 2024 Microsoft Corporation + * * This program and the accompanying materials are made available under the * terms of the MIT License which is available at * https://opensource.org/licenses/MIT. - * + * * SPDX-License-Identifier: MIT **************************************************************************/ @@ -13,7 +13,7 @@ /** */ /** USBX Component */ /** */ -/** Device CDC Class */ +/** Device CDC ACM Class */ /** */ /**************************************************************************/ /**************************************************************************/ @@ -29,8 +29,6 @@ #if defined(UX_DEVICE_STANDALONE) - - /**************************************************************************/ /* */ /* FUNCTION RELEASE */ @@ -94,8 +92,8 @@ /* resulting in version 6.3.0 */ /* */ /**************************************************************************/ -UINT _ux_device_class_cdc_acm_write_run(UX_SLAVE_CLASS_CDC_ACM *cdc_acm, - UCHAR *buffer, ULONG requested_length, ULONG *actual_length) +UINT _ux_device_class_cdc_acm_write_run(UX_SLAVE_CLASS_CDC_ACM *cdc_acm, UCHAR *buffer, + ULONG requested_length, ULONG *actual_length) { UX_SLAVE_ENDPOINT *endpoint; @@ -142,11 +140,19 @@ UINT zlp = UX_FALSE; /* We need the interface to the class. */ interface_ptr = cdc_acm -> ux_slave_class_cdc_acm_interface; + /* Locate data interface. */ + if (interface_ptr -> ux_slave_interface_descriptor.bInterfaceClass != UX_SLAVE_CLASS_CDC_ACM_DATA_CLASS) + { + /* So the next interface is data interface. */ + interface_ptr = interface_ptr -> ux_slave_interface_next_interface; + } + /* Locate the endpoints. */ endpoint = interface_ptr -> ux_slave_interface_first_endpoint; /* Check the endpoint direction, if IN we have the correct endpoint. */ - if ((endpoint -> ux_slave_endpoint_descriptor.bEndpointAddress & UX_ENDPOINT_DIRECTION) != UX_ENDPOINT_IN) + if (((endpoint -> ux_slave_endpoint_descriptor.bEndpointAddress & UX_ENDPOINT_DIRECTION) != UX_ENDPOINT_IN) || + ((endpoint -> ux_slave_endpoint_descriptor.bmAttributes & UX_MASK_ENDPOINT_TYPE) != UX_BULK_ENDPOINT)) { /* So the next endpoint has to be the IN endpoint. */ @@ -266,7 +272,7 @@ UINT zlp = UX_FALSE; /* On a out, we copy the buffer to the caller. Not very efficient but it makes the API easier. */ - _ux_utility_memory_copy(transfer_request -> ux_slave_transfer_request_data_pointer, + _ux_utility_memory_copy(transfer_request -> ux_slave_transfer_request_data_pointer, cdc_acm -> ux_device_class_cdc_acm_write_buffer, cdc_acm -> ux_device_class_cdc_acm_write_transfer_length); /* Use case of memcpy is verified. */ @@ -395,5 +401,4 @@ UINT _uxe_device_class_cdc_acm_write_run(UX_SLAVE_CLASS_CDC_ACM *cdc_acm, return (_ux_device_class_cdc_acm_write_run(cdc_acm, buffer, requested_length, actual_length)); } - #endif diff --git a/test/regression/usbx_ux_device_stack_standard_request_tests.c b/test/regression/usbx_ux_device_stack_standard_request_tests.c index 18ce0311..fb7878f6 100644 --- a/test/regression/usbx_ux_device_stack_standard_request_tests.c +++ b/test/regression/usbx_ux_device_stack_standard_request_tests.c @@ -744,6 +744,7 @@ static UINT test_ms_vendor_request(ULONG request, ULONG request_value, ULONG req static UINT test_ux_device_class_cdc_acm_entry(UX_SLAVE_CLASS_COMMAND *command) + { if (class_entry_rc != UX_SUCCESS) return class_entry_rc; @@ -1433,8 +1434,8 @@ UX_SLAVE_TRANSFER *slave_transfer_request; UCHAR string_descriptor_manufacturer_length = *(string_framework + 3); UCHAR get_string_descriptor_manufacturer_expected[] = { - /* bLength. '2 +' is for bLength and bDescriptorType, '0x0c' is the length of - the string, and '*2' is because it's 16-bit unicode, where each character + /* bLength. '2 +' is for bLength and bDescriptorType, '0x0c' is the length of + the string, and '*2' is because it's 16-bit unicode, where each character is 2 bytes, the LSB is the value, and MSB is 0 (for ascii anyways). */ (UCHAR)(2 + string_descriptor_manufacturer_length*2), @@ -1446,7 +1447,7 @@ UX_SLAVE_TRANSFER *slave_transfer_request; 0x78, 0x00, 0x70, 0x00, 0x72, 0x00, - 0x65, 0x00, + 0x65, 0x00, 0x73, 0x00, 0x20, 0x00, 0x4c, 0x00, @@ -2064,6 +2065,7 @@ UX_SLAVE_TRANSFER *slave_transfer_request; stepinfo(">>>>>>>>>>>>>>>> Test MS Vendor Request\n"); transfer_request -> ux_transfer_request_function = UX_DEMO_VENDOR_REQUEST; + transfer_request -> ux_transfer_request_type = UX_REQUEST_IN | UX_REQUEST_TYPE_VENDOR | UX_REQUEST_TARGET_DEVICE; vendor_req_rc = UX_ERROR; status = ux_host_stack_transfer_request(transfer_request);