1 /***************************************************************************
2 * Copyright (c) 2024 Microsoft Corporation
3 *
4 * This program and the accompanying materials are made available under the
5 * terms of the MIT License which is available at
6 * https://opensource.org/licenses/MIT.
7 *
8 * SPDX-License-Identifier: MIT
9 **************************************************************************/
10
11
12 /**************************************************************************/
13 /**************************************************************************/
14 /** */
15 /** USBX Component */
16 /** */
17 /** Host Stack */
18 /** */
19 /**************************************************************************/
20 /**************************************************************************/
21
22
23 /* Include necessary system files. */
24
25 #define UX_SOURCE_CODE
26
27 #include "ux_api.h"
28 #include "ux_host_stack.h"
29
30
31 /**************************************************************************/
32 /* */
33 /* FUNCTION RELEASE */
34 /* */
35 /* _ux_host_stack_new_interface_create PORTABLE C */
36 /* 6.1.12 */
37 /* AUTHOR */
38 /* */
39 /* Chaoqiong Xiao, Microsoft Corporation */
40 /* */
41 /* DESCRIPTION */
42 /* */
43 /* This function creates a new interface for the current configuration */
44 /* scanned. A device has at least 1 alternate setting per interface */
45 /* which is the default one. */
46 /* */
47 /* The interface is hooked to the configuration that owns it. */
48 /* */
49 /* From the interface descriptor, all the endpoints are hooked but */
50 /* not activated. */
51 /* */
52 /* INPUT */
53 /* */
54 /* configuration Configuration container that */
55 /* owns this interface */
56 /* interface_pointer Pointer to a unparsed */
57 /* interface descriptor */
58 /* length Length remaining in this */
59 /* descriptor */
60 /* */
61 /* OUTPUT */
62 /* */
63 /* Completion Status */
64 /* */
65 /* CALLS */
66 /* */
67 /* _ux_host_stack_new_endpoint_create Create new endpoint */
68 /* _ux_utility_descriptor_parse Parse the descriptor */
69 /* _ux_utility_memory_allocate Allocate memory block */
70 /* */
71 /* CALLED BY */
72 /* */
73 /* USBX Components */
74 /* */
75 /* RELEASE HISTORY */
76 /* */
77 /* DATE NAME DESCRIPTION */
78 /* */
79 /* 05-19-2020 Chaoqiong Xiao Initial Version 6.0 */
80 /* 09-30-2020 Chaoqiong Xiao Modified comment(s), */
81 /* resulting in version 6.1 */
82 /* 07-29-2022 Chaoqiong Xiao Modified comment(s), */
83 /* fixed parameter/variable */
84 /* names conflict C++ keyword, */
85 /* resulting in version 6.1.12 */
86 /* */
87 /**************************************************************************/
_ux_host_stack_new_interface_create(UX_CONFIGURATION * configuration,UCHAR * descriptor,ULONG length)88 UINT _ux_host_stack_new_interface_create(UX_CONFIGURATION *configuration,
89 UCHAR * descriptor, ULONG length)
90 {
91
92 UX_INTERFACE *list_interface;
93 UX_INTERFACE *interface_ptr;
94 UINT number_endpoints;
95 UINT descriptor_length;
96 UINT descriptor_type;
97 UINT status;
98 UCHAR *this_interface_descriptor;
99
100 /* Obtain memory for storing this new interface. */
101 interface_ptr = (UX_INTERFACE *) _ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, sizeof(UX_INTERFACE));
102
103 /* If no memory left, exit with error. */
104 if (interface_ptr == UX_NULL)
105 return(UX_MEMORY_INSUFFICIENT);
106
107 /* Save the interface handle in the container, this is for ensuring the
108 interface container is not corrupted. */
109 interface_ptr -> ux_interface_handle = (ULONG) (ALIGN_TYPE) interface_ptr;
110
111 /* Parse the interface descriptor and make it machine independent. */
112 _ux_utility_descriptor_parse(descriptor,
113 _ux_system_interface_descriptor_structure,
114 UX_INTERFACE_DESCRIPTOR_ENTRIES,
115 (UCHAR *) &interface_ptr -> ux_interface_descriptor);
116
117 /* The configuration that owns this interface is memorized in the
118 interface container itself, easier for back chaining. */
119 interface_ptr -> ux_interface_configuration = configuration;
120
121 /* If the interface belongs to an IAD, remember the IAD Class/SubClass/Protocol. */
122 interface_ptr -> ux_interface_iad_class = configuration -> ux_configuration_iad_class;
123 interface_ptr -> ux_interface_iad_subclass = configuration -> ux_configuration_iad_subclass;
124 interface_ptr -> ux_interface_iad_protocol = configuration -> ux_configuration_iad_protocol;
125
126 /* There is 2 cases for the creation of the interface descriptor
127 if this is the first one, the interface descriptor is hooked
128 to the configuration. If it is not the first one, the interface
129 is hooked to the end of the chain of interfaces. */
130 if (configuration -> ux_configuration_first_interface == UX_NULL)
131 {
132 configuration -> ux_configuration_first_interface = interface_ptr;
133 }
134 else
135 {
136
137 list_interface = configuration -> ux_configuration_first_interface;
138
139 /* Traverse the list until we reach the end */
140 while (list_interface -> ux_interface_next_interface != UX_NULL)
141 {
142
143 list_interface = list_interface -> ux_interface_next_interface;
144 }
145
146 /* Hook the interface. */
147 list_interface -> ux_interface_next_interface = interface_ptr;
148 }
149
150 /* Traverse the interface in search of all endpoints that belong to it.
151 We need the length remaining in the descriptor and the number of endpoints
152 reported for this interface. */
153 number_endpoints = interface_ptr -> ux_interface_descriptor.bNumEndpoints;
154
155 this_interface_descriptor = descriptor;
156
157 while (length && (number_endpoints != 0))
158 {
159
160 /* Gather the length and type of the descriptor. */
161 descriptor_length = *descriptor;
162 descriptor_type = *(descriptor+1);
163
164 /* make sure this descriptor has at least the minimum length. */
165 if (descriptor_length < 3)
166 {
167
168 /* Error trap. */
169 _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_ENUMERATOR, UX_DESCRIPTOR_CORRUPTED);
170
171 /* If trace is enabled, insert this event into the trace buffer. */
172 UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_DESCRIPTOR_CORRUPTED, descriptor, 0, 0, UX_TRACE_ERRORS, 0, 0)
173
174 return(UX_DESCRIPTOR_CORRUPTED);
175 }
176
177 /* Check the type for an interface descriptor. */
178 if (descriptor_type == UX_ENDPOINT_DESCRIPTOR_ITEM)
179 {
180
181 /* We have found an endpoint descriptor for this interface. */
182 status = _ux_host_stack_new_endpoint_create(interface_ptr, descriptor);
183
184 /* Check return status. */
185 if(status != UX_SUCCESS)
186 return(status);
187
188 number_endpoints--;
189 }
190
191 /* Verify if the descriptor is still valid, or we moved to next interface. */
192 if ((descriptor_length > length) || (descriptor_type == UX_INTERFACE_DESCRIPTOR_ITEM && descriptor != this_interface_descriptor))
193 {
194
195 /* Error trap. */
196 _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_ENUMERATOR, UX_DESCRIPTOR_CORRUPTED);
197
198 /* If trace is enabled, insert this event into the trace buffer. */
199 UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_DESCRIPTOR_CORRUPTED, descriptor, 0, 0, UX_TRACE_ERRORS, 0, 0)
200
201 return(UX_DESCRIPTOR_CORRUPTED);
202 }
203
204 /* Jump to the next descriptor if we have not reached the end. */
205 descriptor += descriptor_length;
206 length -= descriptor_length;
207 }
208
209 /* Return success! */
210 return(UX_SUCCESS);
211 }
212
213