From b50aca03a72899763d2471c60ccfe8de1a3b1db5 Mon Sep 17 00:00:00 2001 From: MAY Date: Tue, 27 Jan 2026 05:10:43 +0100 Subject: [PATCH] device cdc acm support break request - Implements handling of UX_SLAVE_CLASS_CDC_ACM_SEND_BREAK in the CDC ACM control request path. - Ensures break state is cleared on class deactivation to avoid carrying state across disconnect/reset cycles. - Minor comment/whitespace cleanups in touched headers/sources. - Testing: Build-only / compilation sanity/send break request. (no new automated tests added). --- .../inc/ux_device_class_cdc_acm.h | 107 ++++++------ .../ux_device_class_cdc_acm_control_request.c | 117 +++++++------ .../src/ux_device_class_cdc_acm_deactivate.c | 88 +++++----- .../src/ux_device_class_cdc_acm_initialize.c | 105 ++++++------ .../src/ux_device_class_cdc_acm_ioctl.c | 155 +++++++++--------- test/regression/usbx_cdc_acm_basic_test.c | 33 +++- 6 files changed, 339 insertions(+), 266 deletions(-) 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..b275b52c 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,45 @@ /*************************************************************************** - * 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 */ /** */ -/** CDC Class */ +/** USBX Component */ +/** */ +/** Device CDC ACM Class */ /** */ /**************************************************************************/ /**************************************************************************/ -/**************************************************************************/ -/* */ -/* COMPONENT DEFINITION RELEASE */ -/* */ -/* ux_device_class_cdc_acm.h PORTABLE C */ -/* 6.3.0 */ + +/**************************************************************************/ +/**************************************************************************/ +/* */ +/* COMPONENT DEFINITION RELEASE */ +/* */ +/* ux_device_class_cdc_acm.h PORTABLE C */ +/* 6.4.6 */ /* 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 */ @@ -63,21 +66,24 @@ /* endpoint buffer in classes, */ /* added error checks support, */ /* resulting in version 6.3.0 */ +/* 01-28-2026 Mohamed AYED Modified comment(s), */ +/* support send break request */ +/* resulting in version 6.4.6 */ /* */ /**************************************************************************/ #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. */ @@ -251,6 +257,7 @@ typedef struct UX_SLAVE_CLASS_CDC_ACM_STRUCT UCHAR ux_slave_class_cdc_acm_data_bit; UCHAR ux_slave_class_cdc_acm_data_dtr_state; UCHAR ux_slave_class_cdc_acm_data_rts_state; + USHORT ux_slave_class_cdc_acm_break_duration; UCHAR reserved[3]; #ifndef UX_DEVICE_CLASS_CDC_ACM_TRANSMISSION_DISABLE @@ -289,23 +296,29 @@ 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_BREAK_PARAMETER_STRUCT +{ + USHORT ux_slave_class_cdc_acm_parameter_break_duration; + +} UX_SLAVE_CLASS_CDC_ACM_BREAK_PARAMETER; + +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 +329,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 +353,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 +376,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 +432,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_control_request.c b/common/usbx_device_classes/src/ux_device_class_cdc_acm_control_request.c index 0660bf29..0d038014 100644 --- a/common/usbx_device_classes/src/ux_device_class_cdc_acm_control_request.c +++ b/common/usbx_device_classes/src/ux_device_class_cdc_acm_control_request.c @@ -1,19 +1,20 @@ /*************************************************************************** - * 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 */ /** */ /**************************************************************************/ /**************************************************************************/ @@ -28,41 +29,41 @@ #include "ux_device_stack.h" -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _ux_device_class_cdc_acm_control_request PORTABLE C */ -/* 6.1.12 */ +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _ux_device_class_cdc_acm_control_request PORTABLE C */ +/* 6.4.6 */ /* AUTHOR */ /* */ /* Chaoqiong Xiao, Microsoft Corporation */ /* */ /* DESCRIPTION */ -/* */ -/* This function manages the based sent by the host on the control */ -/* endpoints with a CLASS or VENDOR SPECIFIC type. */ -/* */ -/* INPUT */ -/* */ -/* cdc_acm Pointer to cdc_acm class */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* _ux_device_stack_transfer_request Transfer request */ -/* */ -/* CALLED BY */ -/* */ +/* */ +/* This function manages the based sent by the host on the control */ +/* endpoints with a CLASS or VENDOR SPECIFIC type. */ +/* */ +/* INPUT */ +/* */ +/* cdc_acm Pointer to cdc_acm class */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* _ux_device_stack_transfer_request Transfer request */ +/* */ +/* CALLED BY */ +/* */ /* CDC Class */ -/* */ -/* 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), */ /* resulting in version 6.1 */ @@ -70,6 +71,9 @@ /* fixed parameter/variable */ /* names conflict C++ keyword, */ /* resulting in version 6.1.12 */ +/* 01-28-2026 Mohamed AYED Modified comment(s), */ +/* support send break request */ +/* resulting in version 6.4.6 */ /* */ /**************************************************************************/ UINT _ux_device_class_cdc_acm_control_request(UX_SLAVE_CLASS_COMMAND *command) @@ -105,7 +109,7 @@ ULONG transmit_length; request_length = _ux_utility_short_get(transfer_request -> ux_slave_transfer_request_setup + UX_SETUP_LENGTH); transmit_length = request_length ; - + /* Here we proceed only the standard request we know of at the device level. */ switch (request) { @@ -118,16 +122,16 @@ ULONG transmit_length; /* Get the line state parameters from the host. DTR signal. */ if (value & UX_SLAVE_CLASS_CDC_ACM_LINE_STATE_DTR) - cdc_acm -> ux_slave_class_cdc_acm_data_dtr_state = UX_TRUE; + cdc_acm -> ux_slave_class_cdc_acm_data_dtr_state = UX_TRUE; /* Get the line state parameters from the host. RTS signal. */ if (value & UX_SLAVE_CLASS_CDC_ACM_LINE_STATE_RTS) - cdc_acm -> ux_slave_class_cdc_acm_data_rts_state = UX_TRUE; - + cdc_acm -> ux_slave_class_cdc_acm_data_rts_state = UX_TRUE; + /* If there is a parameter change function call it. */ if (cdc_acm -> ux_slave_class_cdc_acm_parameter.ux_slave_class_cdc_acm_parameter_change != UX_NULL) - { - + { + /* Invoke the application. */ cdc_acm -> ux_slave_class_cdc_acm_parameter.ux_slave_class_cdc_acm_parameter_change(cdc_acm); } @@ -137,11 +141,11 @@ ULONG transmit_length; case UX_SLAVE_CLASS_CDC_ACM_GET_LINE_CODING: /* Setup the length appropriately. */ - if (request_length > UX_SLAVE_CLASS_CDC_ACM_LINE_CODING_RESPONSE_SIZE) + if (request_length > UX_SLAVE_CLASS_CDC_ACM_LINE_CODING_RESPONSE_SIZE) transmit_length = UX_SLAVE_CLASS_CDC_ACM_LINE_CODING_RESPONSE_SIZE; - + /* Send the line coding default parameters back to the host. */ - _ux_utility_long_put(transfer_request -> ux_slave_transfer_request_data_pointer + UX_SLAVE_CLASS_CDC_ACM_LINE_CODING_BAUDRATE_STRUCT, + _ux_utility_long_put(transfer_request -> ux_slave_transfer_request_data_pointer + UX_SLAVE_CLASS_CDC_ACM_LINE_CODING_BAUDRATE_STRUCT, cdc_acm -> ux_slave_class_cdc_acm_baudrate); *(transfer_request -> ux_slave_transfer_request_data_pointer + UX_SLAVE_CLASS_CDC_ACM_LINE_CODING_STOP_BIT_STRUCT) = cdc_acm -> ux_slave_class_cdc_acm_stop_bit; *(transfer_request -> ux_slave_transfer_request_data_pointer + UX_SLAVE_CLASS_CDC_ACM_LINE_CODING_PARITY_STRUCT) = cdc_acm -> ux_slave_class_cdc_acm_parity; @@ -149,11 +153,11 @@ ULONG transmit_length; /* Set the phase of the transfer to data out. */ transfer_request -> ux_slave_transfer_request_phase = UX_TRANSFER_PHASE_DATA_OUT; - + /* Perform the data transfer. */ _ux_device_stack_transfer_request(transfer_request, transmit_length, request_length); - break; - + break; + case UX_SLAVE_CLASS_CDC_ACM_SET_LINE_CODING: /* Get the line coding parameters from the host. */ @@ -164,14 +168,28 @@ ULONG transmit_length; /* If there is a parameter change function call it. */ if (cdc_acm -> ux_slave_class_cdc_acm_parameter.ux_slave_class_cdc_acm_parameter_change != UX_NULL) - { - + { + /* Invoke the application. */ cdc_acm -> ux_slave_class_cdc_acm_parameter.ux_slave_class_cdc_acm_parameter_change(cdc_acm); } break ; + case UX_SLAVE_CLASS_CDC_ACM_SEND_BREAK: + + /* SEND_BREAK has no data stage, wValue contains break duration in ms. + 0x0000 means stop break. + 0x0001-0xFFFE means break signal duration in ms. + 0xFFFF means indefinite break. */ + cdc_acm -> ux_slave_class_cdc_acm_break_duration = (USHORT) value; + + /* If there is a parameter change function call it. */ + if (cdc_acm -> ux_slave_class_cdc_acm_parameter.ux_slave_class_cdc_acm_parameter_change != UX_NULL) + cdc_acm -> ux_slave_class_cdc_acm_parameter.ux_slave_class_cdc_acm_parameter_change(cdc_acm); + + break; + default: /* Unknown function. It's not handled. */ @@ -181,4 +199,3 @@ ULONG transmit_length; /* It's handled. */ return(UX_SUCCESS); } - diff --git a/common/usbx_device_classes/src/ux_device_class_cdc_acm_deactivate.c b/common/usbx_device_classes/src/ux_device_class_cdc_acm_deactivate.c index fe3f510c..324a1c02 100644 --- a/common/usbx_device_classes/src/ux_device_class_cdc_acm_deactivate.c +++ b/common/usbx_device_classes/src/ux_device_class_cdc_acm_deactivate.c @@ -1,19 +1,20 @@ /*************************************************************************** - * 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 */ /** */ /**************************************************************************/ /**************************************************************************/ @@ -28,41 +29,41 @@ #include "ux_device_stack.h" -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _ux_device_class_cdc_acm_deactivate PORTABLE C */ -/* 6.1.12 */ +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _ux_device_class_cdc_acm_deactivate PORTABLE C */ +/* 6.4.6 */ /* AUTHOR */ /* */ /* Chaoqiong Xiao, Microsoft Corporation */ /* */ /* DESCRIPTION */ -/* */ -/* This function deactivate an instance of the cdc_acm class. */ -/* */ -/* INPUT */ -/* */ -/* command Pointer to a class command */ -/* */ -/* OUTPUT */ -/* */ -/* Completion Status */ -/* */ -/* CALLS */ -/* */ -/* _ux_device_stack_transfer_all_request_abort Abort all transfers */ -/* _ux_device_class_cdc_acm_ioctl IO control */ -/* */ -/* CALLED BY */ -/* */ +/* */ +/* This function deactivate an instance of the cdc_acm class. */ +/* */ +/* INPUT */ +/* */ +/* command Pointer to a class command */ +/* */ +/* OUTPUT */ +/* */ +/* Completion Status */ +/* */ +/* CALLS */ +/* */ +/* _ux_device_stack_transfer_all_request_abort Abort all transfers */ +/* _ux_device_class_cdc_acm_ioctl IO control */ +/* */ +/* CALLED BY */ +/* */ /* CDC Class */ -/* */ -/* 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), */ /* resulting in version 6.1 */ @@ -70,11 +71,14 @@ /* fixed parameter/variable */ /* names conflict C++ keyword, */ /* resulting in version 6.1.12 */ +/* 01-28-2026 Mohamed AYED Modified comment(s), */ +/* support send break request */ +/* resulting in version 6.4.6 */ /* */ /**************************************************************************/ UINT _ux_device_class_cdc_acm_deactivate(UX_SLAVE_CLASS_COMMAND *command) { - + UX_SLAVE_INTERFACE *interface_ptr; UX_SLAVE_CLASS *class_ptr; UX_SLAVE_CLASS_CDC_ACM *cdc_acm; @@ -89,17 +93,17 @@ UX_SLAVE_ENDPOINT *endpoint_out; /* We need the interface to the class. */ interface_ptr = cdc_acm -> ux_slave_class_cdc_acm_interface; - + /* Locate the endpoints. */ endpoint_in = interface_ptr -> ux_slave_interface_first_endpoint; - + /* Check the endpoint direction, if IN we have the correct endpoint. */ if ((endpoint_in -> ux_slave_endpoint_descriptor.bEndpointAddress & UX_ENDPOINT_DIRECTION) != UX_ENDPOINT_IN) { /* Wrong direction, we found the OUT endpoint first. */ endpoint_out = endpoint_in; - + /* So the next endpoint has to be the IN endpoint. */ endpoint_in = endpoint_out -> ux_slave_endpoint_next_endpoint; } @@ -109,7 +113,7 @@ UX_SLAVE_ENDPOINT *endpoint_out; /* We found the endpoint IN first, so next endpoint is OUT. */ endpoint_out = endpoint_in -> ux_slave_endpoint_next_endpoint; } - + /* Terminate the transactions pending on the endpoints. */ _ux_device_stack_transfer_all_request_abort(endpoint_in, UX_TRANSFER_BUS_RESET); _ux_device_stack_transfer_all_request_abort(endpoint_out, UX_TRANSFER_BUS_RESET); @@ -125,11 +129,13 @@ UX_SLAVE_ENDPOINT *endpoint_out; cdc_acm -> ux_slave_class_cdc_acm_parameter.ux_slave_class_cdc_acm_instance_deactivate(cdc_acm); } - /* We need to reset the DTR and RTS values so they do not carry over to the + /* We need to reset the DTR and RTS values so they do not carry over to the next connection. */ cdc_acm -> ux_slave_class_cdc_acm_data_dtr_state = 0; cdc_acm -> ux_slave_class_cdc_acm_data_rts_state = 0; + cdc_acm -> ux_slave_class_cdc_acm_break_duration = 0; + /* If trace is enabled, insert this event into the trace buffer. */ UX_TRACE_IN_LINE_INSERT(UX_TRACE_DEVICE_CLASS_CDC_ACM_DEACTIVATE, cdc_acm, 0, 0, 0, UX_TRACE_DEVICE_CLASS_EVENTS, 0, 0) diff --git a/common/usbx_device_classes/src/ux_device_class_cdc_acm_initialize.c b/common/usbx_device_classes/src/ux_device_class_cdc_acm_initialize.c index 20066a72..7c32cd99 100644 --- a/common/usbx_device_classes/src/ux_device_class_cdc_acm_initialize.c +++ b/common/usbx_device_classes/src/ux_device_class_cdc_acm_initialize.c @@ -1,18 +1,20 @@ /*************************************************************************** - * 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 */ /** */ /**************************************************************************/ /**************************************************************************/ @@ -31,43 +33,43 @@ #error UX_THREAD_STACK_SIZE too large #endif -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _ux_device_class_cdc_acm_initialize PORTABLE C */ -/* 6.3.0 */ +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _ux_device_class_cdc_acm_initialize PORTABLE C */ +/* 6.4.6 */ /* AUTHOR */ /* */ /* Chaoqiong Xiao, Microsoft Corporation */ /* */ /* DESCRIPTION */ -/* */ -/* This function initializes the USB CDC device. */ -/* */ -/* INPUT */ -/* */ -/* command Pointer to cdc_acm command */ -/* */ -/* OUTPUT */ -/* */ -/* Completion Status */ -/* */ -/* CALLS */ -/* */ -/* _ux_utility_memory_allocate Allocate memory */ -/* _ux_utility_memory_free Free memory */ -/* _ux_utility_mutex_create Create mutex */ -/* _ux_device_mutex_delete Delete mutex */ -/* */ -/* CALLED BY */ -/* */ -/* USBX Source Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ +/* */ +/* This function initializes the USB CDC device. */ +/* */ +/* INPUT */ +/* */ +/* command Pointer to cdc acm command */ +/* */ +/* OUTPUT */ +/* */ +/* Completion Status */ +/* */ +/* CALLS */ +/* */ +/* _ux_utility_memory_allocate Allocate memory */ +/* _ux_utility_memory_free Free memory */ +/* _ux_utility_mutex_create Create mutex */ +/* _ux_device_mutex_delete Delete mutex */ +/* */ +/* CALLED BY */ +/* */ +/* USBX Source Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ /* 05-19-2020 Chaoqiong Xiao Initial Version 6.0 */ /* 09-30-2020 Chaoqiong Xiao Modified comment(s), */ /* resulting in version 6.1 */ @@ -91,11 +93,14 @@ /* added a new mode to manage */ /* endpoint buffer in classes, */ /* resulting in version 6.3.0 */ +/* 01-28-2026 Mohamed AYED Modified comment(s), */ +/* support send break request */ +/* resulting in version 6.4.6 */ /* */ /**************************************************************************/ UINT _ux_device_class_cdc_acm_initialize(UX_SLAVE_CLASS_COMMAND *command) { - + UX_SLAVE_CLASS_CDC_ACM *cdc_acm; UX_SLAVE_CLASS_CDC_ACM_PARAMETER *cdc_acm_parameter; UX_SLAVE_CLASS *class_ptr; @@ -132,10 +137,10 @@ UINT status; UX_DEVICE_CLASS_CDC_ACM_ENDPOINT_BUFFER_SIZE); if (cdc_acm -> ux_device_class_cdc_acm_endpoint_buffer == UX_NULL) { - + /* Free the resources. */ _ux_utility_memory_free(cdc_acm); - + /* Return fatal error. */ return(UX_MEMORY_INSUFFICIENT); } @@ -155,10 +160,10 @@ UINT status; _ux_utility_memory_free(cdc_acm -> ux_device_class_cdc_acm_endpoint_buffer); #endif _ux_utility_memory_free(cdc_acm); - + /* Return fatal error. */ return(UX_MUTEX_ERROR); - } + } /* Out Mutex. */ status = _ux_utility_mutex_create(&cdc_acm -> ux_slave_class_cdc_acm_endpoint_out_mutex, "ux_slave_class_cdc_acm_out_mutex"); @@ -175,10 +180,10 @@ UINT status; _ux_utility_memory_free(cdc_acm -> ux_device_class_cdc_acm_endpoint_buffer); #endif _ux_utility_memory_free(cdc_acm); - + /* Return fatal error. */ return(UX_MUTEX_ERROR); - } + } #endif @@ -188,6 +193,9 @@ UINT status; cdc_acm -> ux_slave_class_cdc_acm_parity = UX_SLAVE_CLASS_CDC_ACM_LINE_CODING_PARITY; cdc_acm -> ux_slave_class_cdc_acm_data_bit = UX_SLAVE_CLASS_CDC_ACM_LINE_CODING_DATA_BIT; + /* Initialize break duration. */ + cdc_acm -> ux_slave_class_cdc_acm_break_duration = 0; + #ifndef UX_DEVICE_CLASS_CDC_ACM_TRANSMISSION_DISABLE #if defined(UX_DEVICE_STANDALONE) @@ -198,7 +206,7 @@ UINT status; /* We need to prepare the 2 threads for sending and receiving. */ /* Allocate some memory for the bulk out and in thread stack. */ - cdc_acm -> ux_slave_class_cdc_acm_bulkout_thread_stack = + cdc_acm -> ux_slave_class_cdc_acm_bulkout_thread_stack = _ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, UX_THREAD_STACK_SIZE * 2); /* Check for successful allocation. */ @@ -236,7 +244,7 @@ UINT status; does not start until we have a instance of the class. */ status = _ux_utility_thread_create( &cdc_acm -> ux_slave_class_cdc_acm_bulkin_thread, - "ux_slave_class_cdc_acm_bulkin_thread", + "ux_slave_class_cdc_acm_bulkin_thread", _ux_device_class_cdc_acm_bulkin_thread, (ULONG) (ALIGN_TYPE) cdc_acm, (VOID *) cdc_acm -> ux_slave_class_cdc_acm_bulkin_thread_stack, @@ -264,7 +272,7 @@ UINT status; does not start until we have a instance of the class. */ status = _ux_utility_thread_create( &cdc_acm -> ux_slave_class_cdc_acm_bulkout_thread, - "ux_slave_class_cdc_acm_bulkout_thread", + "ux_slave_class_cdc_acm_bulkout_thread", _ux_device_class_cdc_acm_bulkout_thread, (ULONG) (ALIGN_TYPE) cdc_acm, (VOID *) cdc_acm -> ux_slave_class_cdc_acm_bulkout_thread_stack, @@ -309,4 +317,3 @@ UINT status; /* Return completion status. */ return(UX_SUCCESS); } - diff --git a/common/usbx_device_classes/src/ux_device_class_cdc_acm_ioctl.c b/common/usbx_device_classes/src/ux_device_class_cdc_acm_ioctl.c index 852b15de..a9a21453 100644 --- a/common/usbx_device_classes/src/ux_device_class_cdc_acm_ioctl.c +++ b/common/usbx_device_classes/src/ux_device_class_cdc_acm_ioctl.c @@ -1,19 +1,20 @@ /*************************************************************************** - * 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 */ /** */ /**************************************************************************/ /**************************************************************************/ @@ -28,31 +29,33 @@ #include "ux_device_stack.h" -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _ux_device_class_cdc_acm_ioctl PORTABLE C */ +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _ux_device_class_cdc_acm_ioctl PORTABLE C */ /* 6.3.0 */ /* AUTHOR */ /* */ /* Chaoqiong Xiao, Microsoft Corporation */ /* */ /* DESCRIPTION */ -/* */ -/* This function performs certain functions on the cdc acm instance */ -/* */ -/* INPUT */ -/* */ -/* cdc_acm Address of cdc_acm class */ -/* instance */ -/* */ -/* OUTPUT */ -/* */ -/* Status */ -/* */ -/* CALLS */ -/* */ +/* */ +/* This function performs certain functions on the cdc acm instance */ +/* */ +/* INPUT */ +/* */ +/* cdc_acm Pointer to cdc acm instance */ +/* ioctl_function Ioctl function to be performed */ +/* parameter Pointer to a parameter specific */ +/* to the ioctl call */ +/* */ +/* OUTPUT */ +/* */ +/* Status */ +/* */ +/* CALLS */ +/* */ /* _ux_device_stack_transfer_abort Abort transfer */ /* _ux_utility_memory_allocate Allocate memory */ /* _ux_utility_memory_free Free memory */ @@ -60,15 +63,15 @@ /* _ux_utility_event_flags_delete Delete event flags */ /* _ux_device_thread_create Create thread */ /* _ux_device_thread_delete Delete thread */ -/* */ -/* CALLED BY */ -/* */ +/* */ +/* 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), */ /* used UX prefix to refer to */ @@ -121,68 +124,68 @@ UX_SLAVE_TRANSFER *transfer_request; { case UX_SLAVE_CLASS_CDC_ACM_IOCTL_SET_LINE_CODING: - + /* Properly cast the parameter pointer. */ line_coding = (UX_SLAVE_CLASS_CDC_ACM_LINE_CODING_PARAMETER *) parameter; - + /* Save the parameters in the cdc_acm function. */ cdc_acm -> ux_slave_class_cdc_acm_baudrate = line_coding -> ux_slave_class_cdc_acm_parameter_baudrate; cdc_acm -> ux_slave_class_cdc_acm_stop_bit = line_coding -> ux_slave_class_cdc_acm_parameter_stop_bit; cdc_acm -> ux_slave_class_cdc_acm_parity = line_coding -> ux_slave_class_cdc_acm_parameter_parity; cdc_acm -> ux_slave_class_cdc_acm_data_bit = line_coding -> ux_slave_class_cdc_acm_parameter_data_bit; - + break; - + case UX_SLAVE_CLASS_CDC_ACM_IOCTL_GET_LINE_CODING: - + /* Properly cast the parameter pointer. */ line_coding = (UX_SLAVE_CLASS_CDC_ACM_LINE_CODING_PARAMETER *) parameter; - + /* Save the parameters in the cdc_acm function. */ line_coding -> ux_slave_class_cdc_acm_parameter_baudrate = cdc_acm -> ux_slave_class_cdc_acm_baudrate; line_coding -> ux_slave_class_cdc_acm_parameter_stop_bit = cdc_acm -> ux_slave_class_cdc_acm_stop_bit; line_coding -> ux_slave_class_cdc_acm_parameter_parity = cdc_acm -> ux_slave_class_cdc_acm_parity; line_coding -> ux_slave_class_cdc_acm_parameter_data_bit = cdc_acm -> ux_slave_class_cdc_acm_data_bit; - + break; - + case UX_SLAVE_CLASS_CDC_ACM_IOCTL_GET_LINE_STATE: - + /* Properly cast the parameter pointer. */ line_state = (UX_SLAVE_CLASS_CDC_ACM_LINE_STATE_PARAMETER *) parameter; - + /* Return the DTR/RTS signals. */ line_state -> ux_slave_class_cdc_acm_parameter_rts = cdc_acm -> ux_slave_class_cdc_acm_data_rts_state; line_state -> ux_slave_class_cdc_acm_parameter_dtr = cdc_acm -> ux_slave_class_cdc_acm_data_dtr_state; - + break; - + case UX_SLAVE_CLASS_CDC_ACM_IOCTL_SET_LINE_STATE: - + /* Properly cast the parameter pointer. */ line_state = (UX_SLAVE_CLASS_CDC_ACM_LINE_STATE_PARAMETER *) parameter; - + /* Set the DTR/RTS signals. */ cdc_acm -> ux_slave_class_cdc_acm_data_rts_state = line_state -> ux_slave_class_cdc_acm_parameter_rts; cdc_acm -> ux_slave_class_cdc_acm_data_dtr_state = line_state -> ux_slave_class_cdc_acm_parameter_dtr; - + break; - + case UX_SLAVE_CLASS_CDC_ACM_IOCTL_ABORT_PIPE: /* Get the interface from the instance. */ interface_ptr = cdc_acm -> ux_slave_class_cdc_acm_interface; - + /* Locate the endpoints. */ endpoint = interface_ptr -> ux_slave_interface_first_endpoint; - + /* What direction ? */ switch( (ULONG) (ALIGN_TYPE) parameter) { - case UX_SLAVE_CLASS_CDC_ACM_ENDPOINT_XMIT : - + case UX_SLAVE_CLASS_CDC_ACM_ENDPOINT_XMIT : + /* Check the endpoint direction, if IN we have the correct endpoint. */ if ((endpoint -> ux_slave_endpoint_descriptor.bEndpointAddress & UX_ENDPOINT_DIRECTION) != UX_ENDPOINT_IN) { @@ -191,9 +194,9 @@ UX_SLAVE_TRANSFER *transfer_request; endpoint = endpoint -> ux_slave_endpoint_next_endpoint; } break; - - case UX_SLAVE_CLASS_CDC_ACM_ENDPOINT_RCV : - + + case UX_SLAVE_CLASS_CDC_ACM_ENDPOINT_RCV : + /* Check the endpoint direction, if OUT we have the correct endpoint. */ if ((endpoint -> ux_slave_endpoint_descriptor.bEndpointAddress & UX_ENDPOINT_DIRECTION) != UX_ENDPOINT_OUT) { @@ -202,11 +205,11 @@ UX_SLAVE_TRANSFER *transfer_request; endpoint = endpoint -> ux_slave_endpoint_next_endpoint; } break; - + default : - + /* Parameter not supported. Return an error. */ status = UX_ENDPOINT_HANDLE_UNKNOWN; } @@ -224,7 +227,7 @@ UX_SLAVE_TRANSFER *transfer_request; cdc_acm -> ux_device_class_cdc_acm_read_state = UX_STATE_RESET; #else - /* Check the status of the transfer. */ + /* Check the status of the transfer. */ if (transfer_request -> ux_slave_transfer_request_status == UX_TRANSFER_STATUS_PENDING) { @@ -252,7 +255,7 @@ UX_SLAVE_TRANSFER *transfer_request; /* Get the transfer request associated with the endpoint. */ transfer_request = &endpoint -> ux_slave_endpoint_transfer_request; - /* Check the status of the transfer. */ + /* Check the status of the transfer. */ if (transfer_request -> ux_slave_transfer_request_status == UX_TRANSFER_STATUS_PENDING) status = UX_ERROR; else @@ -269,9 +272,9 @@ UX_SLAVE_TRANSFER *transfer_request; { /* We should not to that ! */ return(UX_ERROR); - + } - + /* Properly cast the parameter pointer. */ callback = (UX_SLAVE_CLASS_CDC_ACM_CALLBACK_PARAMETER *) parameter; @@ -290,34 +293,34 @@ UX_SLAVE_TRANSFER *transfer_request; /* Declare the transmission with callback on. */ cdc_acm -> ux_slave_class_cdc_acm_transmission_status = UX_TRUE; - + /* We are done here. */ return(UX_SUCCESS); case UX_SLAVE_CLASS_CDC_ACM_IOCTL_TRANSMISSION_STOP: - + /* Check if we are in callback transmission already. */ if (cdc_acm -> ux_slave_class_cdc_acm_transmission_status == UX_TRUE) { - + /* Get the interface from the instance. */ interface_ptr = cdc_acm -> ux_slave_class_cdc_acm_interface; - + /* Locate the endpoints. */ endpoint = interface_ptr -> ux_slave_interface_first_endpoint; /* Get the transfer request associated with the endpoint. */ transfer_request = &endpoint -> ux_slave_endpoint_transfer_request; - + /* Abort the transfer. */ _ux_device_stack_transfer_abort(transfer_request, UX_ABORTED); - + /* Next endpoint. */ endpoint = endpoint -> ux_slave_endpoint_next_endpoint; /* Get the transfer request associated with the endpoint. */ transfer_request = &endpoint -> ux_slave_endpoint_transfer_request; - + /* Abort the transfer. */ _ux_device_stack_transfer_abort(transfer_request, UX_ABORTED); @@ -335,21 +338,21 @@ UX_SLAVE_TRANSFER *transfer_request; cdc_acm -> ux_slave_class_cdc_acm_transmission_status = UX_FALSE; } else - + /* We should not try to stop an non existing transmission. */ - return(UX_ERROR); + return(UX_ERROR); - break; + break; #endif - default: + default: /* Error trap. */ _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_FUNCTION_NOT_SUPPORTED); - + /* If trace is enabled, insert this event into the trace buffer. */ UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_FUNCTION_NOT_SUPPORTED, 0, 0, 0, UX_TRACE_ERRORS, 0, 0) - + /* Function not supported. Return an error. */ status = UX_FUNCTION_NOT_SUPPORTED; } @@ -410,4 +413,4 @@ UINT _uxe_device_class_cdc_acm_ioctl(UX_SLAVE_CLASS_CDC_ACM *cdc_acm, ULONG ioct } return (_ux_device_class_cdc_acm_ioctl(cdc_acm, ioctl_function, parameter)); -} \ No newline at end of file +} diff --git a/test/regression/usbx_cdc_acm_basic_test.c b/test/regression/usbx_cdc_acm_basic_test.c index 9997c4ce..0b7cd2a8 100644 --- a/test/regression/usbx_cdc_acm_basic_test.c +++ b/test/regression/usbx_cdc_acm_basic_test.c @@ -1177,6 +1177,7 @@ ULONG test_n; UX_HOST_CLASS_COMMAND command; UX_HOST_CLASS_COMMAND command1; ULONG mem_free; +USHORT break_ms; stepinfo("\n"); @@ -2100,10 +2101,36 @@ ULONG mem_free; } /* Try IOCTRL UX_HOST_CLASS_CDC_ACM_IOCTL_SEND_BREAK */ + stepinfo(">>>>>>>>>>>> IOCTRL UX_HOST_CLASS_CDC_ACM_IOCTL_SEND_BREAK\n"); - status = ux_host_class_cdc_acm_ioctl(cdc_acm_host_control, UX_HOST_CLASS_CDC_ACM_IOCTL_SEND_BREAK, &test_n); - /* Not supported by simulator */ - if (status == UX_SUCCESS) + + break_ms = 0xFFFF; + + status = ux_host_class_cdc_acm_ioctl(cdc_acm_host_control, UX_HOST_CLASS_CDC_ACM_IOCTL_SEND_BREAK, &break_ms); + + if ((status != UX_SUCCESS) || (cdc_acm_slave -> ux_slave_class_cdc_acm_break_duration != break_ms)) + { + + printf("ERROR #78: IOCTRL UX_HOST_CLASS_CDC_ACM_IOCTL_SEND_BREAK should fail\n"); + test_control_return(1); + } + + break_ms = 1000; + + status = ux_host_class_cdc_acm_ioctl(cdc_acm_host_control, UX_HOST_CLASS_CDC_ACM_IOCTL_SEND_BREAK, &break_ms); + + if ((status != UX_SUCCESS) || (cdc_acm_slave -> ux_slave_class_cdc_acm_break_duration != break_ms)) + { + + printf("ERROR #78: IOCTRL UX_HOST_CLASS_CDC_ACM_IOCTL_SEND_BREAK should fail\n"); + test_control_return(1); + } + + break_ms = 0x0000; + + status = ux_host_class_cdc_acm_ioctl(cdc_acm_host_control, UX_HOST_CLASS_CDC_ACM_IOCTL_SEND_BREAK, &break_ms); + + if ((status != UX_SUCCESS) || (cdc_acm_slave -> ux_slave_class_cdc_acm_break_duration != break_ms)) { printf("ERROR #78: IOCTRL UX_HOST_CLASS_CDC_ACM_IOCTL_SEND_BREAK should fail\n");