1 /**************************************************************************/
2 /* */
3 /* Copyright (c) Microsoft Corporation. All rights reserved. */
4 /* */
5 /* This software is licensed under the Microsoft Software License */
6 /* Terms for Microsoft Azure RTOS. Full text of the license can be */
7 /* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
8 /* and in the root directory of this software. */
9 /* */
10 /**************************************************************************/
11
12
13 /**************************************************************************/
14 /**************************************************************************/
15 /** */
16 /** USBX Component */
17 /** */
18 /** CDC ACM Class */
19 /** */
20 /**************************************************************************/
21 /**************************************************************************/
22
23
24 /* Include necessary system files. */
25
26 #define UX_SOURCE_CODE
27
28 #include "ux_api.h"
29 #include "ux_host_class_cdc_acm.h"
30 #include "ux_host_stack.h"
31
32
33 /**************************************************************************/
34 /* */
35 /* FUNCTION RELEASE */
36 /* */
37 /* _ux_host_class_cdc_acm_capabilities_get PORTABLE C */
38 /* 6.2.1 */
39 /* AUTHOR */
40 /* */
41 /* Chaoqiong Xiao, Microsoft Corporation */
42 /* */
43 /* DESCRIPTION */
44 /* */
45 /* This function obtains the entire cdc_acm configuration descriptors. */
46 /* This is needed because the cdc_acm class needs to know if commands */
47 /* are routed through the comm interface or the data class. */
48 /* */
49 /* INPUT */
50 /* */
51 /* cdc_acm Pointer to cdc_acm class */
52 /* */
53 /* OUTPUT */
54 /* */
55 /* Completion Status */
56 /* */
57 /* CALLS */
58 /* */
59 /* _ux_host_stack_transfer_request Process transfer request */
60 /* _ux_utility_descriptor_parse Parse descriptor */
61 /* _ux_utility_memory_allocate Allocate memory block */
62 /* _ux_utility_memory_free Release memory block */
63 /* */
64 /* CALLED BY */
65 /* */
66 /* _ux_host_class_cdc_acm_activate */
67 /* */
68 /* RELEASE HISTORY */
69 /* */
70 /* DATE NAME DESCRIPTION */
71 /* */
72 /* 05-19-2020 Chaoqiong Xiao Initial Version 6.0 */
73 /* 09-30-2020 Chaoqiong Xiao Modified comment(s), */
74 /* resulting in version 6.1 */
75 /* 03-08-2023 Chaoqiong Xiao Modified comment(s), */
76 /* fixed capabilities get from */
77 /* multiple CDC-ACM functions, */
78 /* resulting in version 6.2.1 */
79 /* */
80 /**************************************************************************/
_ux_host_class_cdc_acm_capabilities_get(UX_HOST_CLASS_CDC_ACM * cdc_acm)81 UINT _ux_host_class_cdc_acm_capabilities_get(UX_HOST_CLASS_CDC_ACM *cdc_acm)
82 {
83
84 UCHAR *descriptor;
85 UCHAR *saved_descriptor;
86 UX_ENDPOINT *control_endpoint;
87 UX_TRANSFER *transfer_request;
88 UX_CONFIGURATION configuration;
89 UX_INTERFACE_DESCRIPTOR interface_descriptor;
90 UINT status;
91 ULONG total_descriptor_length;
92 UCHAR descriptor_length;
93 UCHAR descriptor_type;
94 UCHAR descriptor_subtype;
95 ULONG interface_found;
96
97 /* We need to get the default control endpoint transfer request pointer. */
98 control_endpoint = &cdc_acm -> ux_host_class_cdc_acm_device -> ux_device_control_endpoint;
99 transfer_request = &control_endpoint -> ux_endpoint_transfer_request;
100
101 /* Need to allocate memory for the descriptor. */
102 descriptor = _ux_utility_memory_allocate(UX_SAFE_ALIGN, UX_CACHE_SAFE_MEMORY, UX_CONFIGURATION_DESCRIPTOR_LENGTH);
103 if (descriptor == UX_NULL)
104 return(UX_MEMORY_INSUFFICIENT);
105
106 /* Save this descriptor address since we need to free it. */
107 saved_descriptor = descriptor;
108
109 /* Create a transfer request for the GET_DESCRIPTOR request. */
110 transfer_request -> ux_transfer_request_data_pointer = descriptor;
111 transfer_request -> ux_transfer_request_requested_length = UX_CONFIGURATION_DESCRIPTOR_LENGTH;
112 transfer_request -> ux_transfer_request_function = UX_GET_DESCRIPTOR;
113 transfer_request -> ux_transfer_request_type = UX_REQUEST_IN | UX_REQUEST_TYPE_STANDARD | UX_REQUEST_TARGET_DEVICE;
114 transfer_request -> ux_transfer_request_value = UX_CONFIGURATION_DESCRIPTOR_ITEM << 8;
115 transfer_request -> ux_transfer_request_index = 0;
116
117 /* Send request to HCD layer. */
118 status = _ux_host_stack_transfer_request(transfer_request);
119
120 /* Check for correct transfer and entire descriptor returned. */
121 if ((status == UX_SUCCESS) && (transfer_request -> ux_transfer_request_actual_length == UX_CONFIGURATION_DESCRIPTOR_LENGTH))
122 {
123
124 /* The descriptor is in a packed format, parse it locally. */
125 _ux_utility_descriptor_parse(descriptor, _ux_system_configuration_descriptor_structure,
126 UX_CONFIGURATION_DESCRIPTOR_ENTRIES, (UCHAR *) &configuration.ux_configuration_descriptor);
127
128 /* Now we have the configuration descriptor which will tell us how many
129 bytes there are in the entire descriptor. */
130 total_descriptor_length = configuration.ux_configuration_descriptor.wTotalLength;
131
132 /* Free the previous descriptor. */
133 _ux_utility_memory_free(descriptor);
134
135 /* Allocate enough memory to read all descriptors attached
136 to this configuration. */
137 descriptor = _ux_utility_memory_allocate(UX_SAFE_ALIGN, UX_CACHE_SAFE_MEMORY, total_descriptor_length);
138 if (descriptor == UX_NULL)
139 return(UX_MEMORY_INSUFFICIENT);
140
141 /* Save this descriptor address since we need to free it. */
142 saved_descriptor = descriptor;
143
144 /* Set the length we need to retrieve. */
145 transfer_request -> ux_transfer_request_requested_length = total_descriptor_length;
146
147 /* And reprogram the descriptor buffer address. */
148 transfer_request -> ux_transfer_request_data_pointer = descriptor;
149
150 /* Send request to HCD layer. */
151 status = _ux_host_stack_transfer_request(transfer_request);
152
153 /* Check for correct transfer and entire descriptor returned. */
154 if ((status == UX_SUCCESS) && (transfer_request -> ux_transfer_request_actual_length == total_descriptor_length))
155 {
156
157 /* Default is Interface descriptor not yet found. */
158 interface_found = UX_FALSE;
159
160 /* Scan the descriptor for the CDC Comm interface. */
161 while (total_descriptor_length)
162 {
163
164 /* Gather the length, type and subtype of the descriptor. */
165 descriptor_length = *descriptor;
166 descriptor_type = *(descriptor + 1);
167 descriptor_subtype = *(descriptor + 2);
168
169 /* Make sure this descriptor has at least the minimum length. */
170 if (descriptor_length < 3)
171 {
172
173 /* Error trap. */
174 _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_DESCRIPTOR_CORRUPTED);
175
176 /* If trace is enabled, insert this event into the trace buffer. */
177 UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_DESCRIPTOR_CORRUPTED, descriptor, 0, 0, UX_TRACE_ERRORS, 0, 0)
178
179 /* We can free the resource now. */
180 _ux_utility_memory_free(saved_descriptor);
181
182 /* Descriptor is corrupted. */
183 return(UX_DESCRIPTOR_CORRUPTED);
184 }
185
186 /* Process relative to descriptor type. */
187 switch (descriptor_type)
188 {
189
190
191 case UX_INTERFACE_DESCRIPTOR_ITEM:
192
193 /* Parse the interface descriptor and make it machine independent. */
194 _ux_utility_descriptor_parse(descriptor, _ux_system_interface_descriptor_structure,
195 UX_INTERFACE_DESCRIPTOR_ENTRIES, (UCHAR *) &interface_descriptor);
196
197 /* Ensure we have the correct interface for CDC control (current interface). */
198 if (interface_descriptor.bInterfaceNumber ==
199 cdc_acm -> ux_host_class_cdc_acm_interface ->
200 ux_interface_descriptor.bInterfaceNumber)
201 {
202
203 /* Mark we have found it. */
204 interface_found = UX_TRUE;
205
206 }
207 else
208 {
209
210 /* Haven't found it. */
211 interface_found = UX_FALSE;
212 }
213 break;
214
215
216 case UX_HOST_CLASS_CDC_ACM_CS_INTERFACE:
217
218 /* First make sure we have found the correct generic interface descriptor. */
219 if ((interface_found == UX_TRUE) && (descriptor_subtype == UX_HOST_CLASS_CDC_ACM_CALL_MANAGEMENT_DESCRIPTOR))
220 {
221
222 /* Retrieve the bmCapabilities field which indicates how ACM commands are sent to the device. */
223 cdc_acm -> ux_host_class_cdc_acm_capabilities = *(descriptor + UX_HOST_CLASS_CDC_ACM_CALL_MANAGEMENT_CAPABILITIES);
224
225
226 }
227 break;
228 }
229
230 /* Verify if the descriptor is still valid. */
231 if (descriptor_length > total_descriptor_length)
232 {
233
234 /* Error trap. */
235 _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_DESCRIPTOR_CORRUPTED);
236
237 /* If trace is enabled, insert this event into the trace buffer. */
238 UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_DESCRIPTOR_CORRUPTED, descriptor, 0, 0, UX_TRACE_ERRORS, 0, 0)
239
240 /* We can free the resource now. */
241 _ux_utility_memory_free(saved_descriptor);
242
243 return(UX_DESCRIPTOR_CORRUPTED);
244 }
245
246 /* Jump to the next descriptor if we have not reached the end. */
247 descriptor += descriptor_length;
248
249 /* And adjust the length left to parse in the descriptor. */
250 total_descriptor_length -= descriptor_length;
251 }
252
253 /* We can free the resource now. */
254 _ux_utility_memory_free(saved_descriptor);
255
256 return(UX_SUCCESS);
257 }
258 }
259
260 /* Free all used resources. */
261 _ux_utility_memory_free(saved_descriptor);
262
263 /* Return completion status. */
264 return(status);
265 }
266
267