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 /** Host Stack */
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_stack.h"
30
31
32 /**************************************************************************/
33 /* */
34 /* FUNCTION RELEASE */
35 /* */
36 /* _ux_host_stack_new_endpoint_create PORTABLE C */
37 /* 6.1.11 */
38 /* AUTHOR */
39 /* */
40 /* Chaoqiong Xiao, Microsoft Corporation */
41 /* */
42 /* DESCRIPTION */
43 /* */
44 /* This function creates a new endpoint for the current interface */
45 /* scanned. The endpoint is hooked to the interface that owns it. */
46 /* It is not active yet until either the default interface for the */
47 /* configuration is selected by a SET_CONFIGURATION or when an */
48 /* alternate setting for this interface is set. */
49 /* */
50 /* INPUT */
51 /* */
52 /* interface Interface container that owns */
53 /* this endpoint */
54 /* endpoint_pointer Pointer to a unparsed */
55 /* endpoint descriptor */
56 /* */
57 /* OUTPUT */
58 /* */
59 /* Completion Status */
60 /* */
61 /* CALLS */
62 /* */
63 /* _ux_utility_descriptor_parse Parse the descriptor */
64 /* _ux_utility_memory_allocate Allocate memory block */
65 /* */
66 /* CALLED BY */
67 /* */
68 /* USBX Components */
69 /* */
70 /* RELEASE HISTORY */
71 /* */
72 /* DATE NAME DESCRIPTION */
73 /* */
74 /* 05-19-2020 Chaoqiong Xiao Initial Version 6.0 */
75 /* 09-30-2020 Chaoqiong Xiao Modified comment(s), */
76 /* resulting in version 6.1 */
77 /* 10-15-2021 Chaoqiong Xiao Modified comment(s), */
78 /* added descriptor validate, */
79 /* resulting in version 6.1.9 */
80 /* 04-25-2022 Chaoqiong Xiao Modified comment(s), */
81 /* internal clean up, */
82 /* fixed size calculation, */
83 /* resulting in version 6.1.11 */
84 /* */
85 /**************************************************************************/
_ux_host_stack_new_endpoint_create(UX_INTERFACE * interface_ptr,UCHAR * interface_endpoint)86 UINT _ux_host_stack_new_endpoint_create(UX_INTERFACE *interface_ptr,
87 UCHAR * interface_endpoint)
88 {
89
90 UX_ENDPOINT *endpoint;
91 UX_ENDPOINT *list_endpoint;
92 ULONG endpoint_type;
93 ULONG packet_size;
94 ULONG n_tran;
95
96 /* Obtain memory for storing this new endpoint. */
97 endpoint = (UX_ENDPOINT *) _ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, sizeof(UX_ENDPOINT));
98 if (endpoint == UX_NULL)
99 return(UX_MEMORY_INSUFFICIENT);
100
101 /* If trace is enabled, insert this event into the trace buffer. */
102 UX_TRACE_IN_LINE_INSERT(UX_TRACE_HOST_STACK_NEW_ENDPOINT_CREATE, interface_ptr, endpoint, 0, 0, UX_TRACE_HOST_STACK_EVENTS, 0, 0)
103
104 /* Save the endpoint handle in the container, this is for ensuring the
105 endpoint container is not corrupted. */
106 endpoint -> ux_endpoint = (ULONG) (ALIGN_TYPE) endpoint;
107
108 /* The endpoint container has a built in transfer_request.
109 The transfer_request needs to point to the endpoint as well. */
110 endpoint -> ux_endpoint_transfer_request.ux_transfer_request_endpoint = endpoint;
111
112 /* Save the pointer to the device. This is useful for the HCD layer. */
113 endpoint -> ux_endpoint_device = interface_ptr -> ux_interface_configuration -> ux_configuration_device;
114
115 /* Parse the interface descriptor and make it machine independent. */
116 _ux_utility_descriptor_parse(interface_endpoint,
117 _ux_system_endpoint_descriptor_structure,
118 UX_ENDPOINT_DESCRIPTOR_ENTRIES,
119 (UCHAR *) &endpoint -> ux_endpoint_descriptor);
120
121 /* Check endpoint size and interval to see if they are valid. */
122 endpoint_type = endpoint -> ux_endpoint_descriptor.bmAttributes & UX_MASK_ENDPOINT_TYPE;
123
124 /* Endpoint size should not be zero. */
125 if (endpoint -> ux_endpoint_descriptor.wMaxPacketSize == 0)
126 {
127 _ux_utility_memory_free(endpoint);
128 return(UX_DESCRIPTOR_CORRUPTED);
129 }
130
131 /* Control/bulk endpoint, 8, 16, 32, 64, ... 512 can be accepted.
132 Note non-standard size in 2^N is accepted since they really works. */
133 if (endpoint_type == UX_CONTROL_ENDPOINT || endpoint_type == UX_BULK_ENDPOINT)
134 {
135 for (packet_size = 8; packet_size <= 512; packet_size <<= 1)
136 {
137 if (packet_size == endpoint -> ux_endpoint_descriptor.wMaxPacketSize)
138 break;
139 }
140
141 /* If endpoint size not valid, return error. */
142 if (packet_size > 512)
143 {
144 _ux_utility_memory_free(endpoint);
145 return(UX_DESCRIPTOR_CORRUPTED);
146 }
147 }
148
149 /* Interrupt/isochronous endpoint, max 1024 and 3 transactions can be accepted. */
150 else
151 {
152
153 /* Max size over 1024 is not allowed. */
154 packet_size = endpoint -> ux_endpoint_descriptor.wMaxPacketSize & UX_MAX_PACKET_SIZE_MASK;
155 if (packet_size > 1024)
156 {
157 _ux_utility_memory_free(endpoint);
158 return(UX_DESCRIPTOR_CORRUPTED);
159 }
160
161 /* Number transaction over 2 additional is not allowed. */
162 n_tran = endpoint -> ux_endpoint_descriptor.wMaxPacketSize & UX_MAX_NUMBER_OF_TRANSACTIONS_MASK;
163 if (n_tran >= UX_MAX_NUMBER_OF_TRANSACTIONS_MASK)
164 {
165 _ux_utility_memory_free(endpoint);
166 return(UX_DESCRIPTOR_CORRUPTED);
167 }
168
169 /* Isochronous/high speed interrupt interval should be 1~16. */
170 if (endpoint -> ux_endpoint_descriptor.bInterval < 1)
171 {
172 _ux_utility_memory_free(endpoint);
173 return(UX_DESCRIPTOR_CORRUPTED);
174 }
175 if ((endpoint_type == UX_ISOCHRONOUS_ENDPOINT) ||
176 (interface_ptr -> ux_interface_configuration -> ux_configuration_device
177 -> ux_device_speed == UX_HIGH_SPEED_DEVICE)
178 )
179 {
180 if (endpoint -> ux_endpoint_descriptor.bInterval > 16)
181 {
182 _ux_utility_memory_free(endpoint);
183 return(UX_DESCRIPTOR_CORRUPTED);
184 }
185 }
186
187 /* Save final packet size. */
188 n_tran >>= UX_MAX_NUMBER_OF_TRANSACTIONS_SHIFT;
189 packet_size *= (n_tran + 1);
190 }
191
192 /* Save transfer packet size. */
193 endpoint -> ux_endpoint_transfer_request.ux_transfer_request_packet_length = packet_size;
194
195 /* The interface that owns this endpoint is memorized in the
196 endpoint container itself, easier for back chaining. */
197 endpoint -> ux_endpoint_interface = interface_ptr;
198
199 /* There is 2 cases for the creation of the endpoint descriptor
200 if this is the first one, the endpoint descriptor is hooked
201 to the interface.
202 If it is not the first one, the endpoint is hooked to the
203 end of the chain of endpoints. */
204 if (interface_ptr -> ux_interface_first_endpoint == UX_NULL)
205 {
206
207 interface_ptr -> ux_interface_first_endpoint = endpoint;
208 }
209 else
210 {
211
212 list_endpoint = interface_ptr -> ux_interface_first_endpoint;
213
214 /* Traverse the list until the end. */
215 while (list_endpoint -> ux_endpoint_next_endpoint != UX_NULL)
216 list_endpoint = list_endpoint -> ux_endpoint_next_endpoint;
217
218 /* Hook the endpoint. */
219 list_endpoint -> ux_endpoint_next_endpoint = endpoint;
220 }
221
222 /* Return successful status. */
223 return(UX_SUCCESS);
224 }
225
226