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 /** Asix Class */
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_class_asix.h"
29 #include "ux_host_stack.h"
30
31
32 /**************************************************************************/
33 /* */
34 /* FUNCTION RELEASE */
35 /* */
36 /* _ux_host_class_asix_activate PORTABLE C */
37 /* 6.3.0 */
38 /* AUTHOR */
39 /* */
40 /* Chaoqiong Xiao, Microsoft Corporation */
41 /* */
42 /* DESCRIPTION */
43 /* */
44 /* This function creates the asix instance, configure the device. */
45 /* WARNING !!!! The NX_PHYSICAL_HEADER should be set to 20 in nx_api.h */
46 /* */
47 /* INPUT */
48 /* */
49 /* command Asix class command pointer */
50 /* */
51 /* OUTPUT */
52 /* */
53 /* Completion Status */
54 /* */
55 /* CALLS */
56 /* */
57 /* _ux_host_class_asix_configure Configure asix class */
58 /* _ux_host_class_asix_endpoints_get Get endpoints of asix */
59 /* _ux_host_class_asix_setup Set up asix */
60 /* _ux_host_stack_class_instance_create Create class instance */
61 /* _ux_host_stack_class_instance_destroy Destroy the class instance */
62 /* _ux_host_stack_transfer_request Transfer request */
63 /* _ux_utility_memory_allocate Allocate memory block */
64 /* _ux_utility_memory_free Free memory block */
65 /* _ux_host_semaphore_create Create semaphore */
66 /* _ux_host_semaphore_delete Delete semaphore */
67 /* _ux_utility_thread_create Create thread */
68 /* _ux_utility_thread_delete Delete thread */
69 /* nx_packet_pool_create Create NetX packet pool */
70 /* */
71 /* CALLED BY */
72 /* */
73 /* _ux_host_class_asix_entry Entry of asix class */
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 /* used UX prefix to refer to */
82 /* TX symbols instead of using */
83 /* them directly, */
84 /* resulting in version 6.1 */
85 /* 01-31-2022 Chaoqiong Xiao Modified comment(s), */
86 /* refined macros names, */
87 /* resulting in version 6.1.10 */
88 /* 10-31-2022 Chaoqiong Xiao Modified comment(s), */
89 /* moved NX driver activate, */
90 /* added reception buffer, */
91 /* removed internal NX pool, */
92 /* resulting in version 6.2.0 */
93 /* 10-31-2023 Chaoqiong Xiao Modified comment(s), */
94 /* masked in standalone build, */
95 /* resulting in version 6.3.0 */
96 /* */
97 /**************************************************************************/
_ux_host_class_asix_activate(UX_HOST_CLASS_COMMAND * command)98 UINT _ux_host_class_asix_activate(UX_HOST_CLASS_COMMAND *command)
99 {
100 #if (NX_PHYSICAL_HEADER < 20) || defined(UX_HOST_STANDALONE)
101
102 UX_PARAMETER_NOT_USED(command);
103
104 /* Function not supported due to NX lib settings/standalone mode. */
105 _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_FUNCTION_NOT_SUPPORTED);
106 return(UX_FUNCTION_NOT_SUPPORTED);
107 #else
108 UX_DEVICE *device;
109 UX_HOST_CLASS_ASIX *asix;
110 UINT status;
111 UX_TRANSFER *transfer_request;
112 ULONG physical_address_msw;
113 ULONG physical_address_lsw;
114
115
116 /* We need to make sure that the value of the NX_PHYSICAL_HEADER is at least 20.
117 This should be changed in the nx_user.h file */
118
119
120 /* The asix class is always activated by the device descriptor. */
121 device = (UX_DEVICE *) command -> ux_host_class_command_container;
122
123 /* Obtain memory for this class instance. */
124 asix = _ux_utility_memory_allocate(UX_NO_ALIGN, UX_CACHE_SAFE_MEMORY, sizeof(UX_HOST_CLASS_ASIX));
125 if (asix == UX_NULL)
126 return(UX_MEMORY_INSUFFICIENT);
127
128 /* Store the class container into this instance. */
129 asix -> ux_host_class_asix_class = command -> ux_host_class_command_class_ptr;
130
131 /* Store the device container into the asix class instance. */
132 asix -> ux_host_class_asix_device = device;
133
134 /* Store the instance in the device container, this is for the USBX stack
135 when it needs to invoke the class for deactivation. */
136 device -> ux_device_class_instance = (VOID *) asix;
137
138 /* Create this class instance. */
139 _ux_host_stack_class_instance_create(asix -> ux_host_class_asix_class, (VOID *) asix);
140
141 /* Configure the asix class. */
142 status = _ux_host_class_asix_configure(asix);
143
144 /* Get the asix endpoint(s). We need to search for Bulk Out and Bulk In endpoints
145 and the interrupt endpoint. */
146 if (status == UX_SUCCESS)
147 status = _ux_host_class_asix_endpoints_get(asix);
148
149 /* Create the semaphore to protect 2 threads from accessing the same asix instance. */
150 if (status == UX_SUCCESS)
151 {
152 status = _ux_host_semaphore_create(&asix -> ux_host_class_asix_semaphore, "ux_host_class_asix_semaphore", 1);
153 if (status != UX_SUCCESS)
154 status = UX_SEMAPHORE_ERROR;
155 }
156
157 /* Create the semaphore to wake up the Asix thread. */
158 if(status == UX_SUCCESS)
159 {
160 status = _ux_host_semaphore_create(&asix -> ux_host_class_asix_interrupt_notification_semaphore, "ux_host_class_asix_interrupt_notification_semaphore", 0);
161 if (status != UX_SUCCESS)
162 status = UX_SEMAPHORE_ERROR;
163 }
164
165 /* Allocate a Thread stack. */
166 if (status == UX_SUCCESS)
167 {
168 asix -> ux_host_class_asix_thread_stack =
169 _ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, UX_THREAD_STACK_SIZE);
170
171 /* Check the completion status. */
172 if (asix -> ux_host_class_asix_thread_stack == UX_NULL)
173 status = UX_MEMORY_INSUFFICIENT;
174 }
175
176 /* Create the asix class thread. */
177 if (status == UX_SUCCESS)
178 {
179 status = _ux_utility_thread_create(&asix -> ux_host_class_asix_thread,
180 "ux_asix_thread", _ux_host_class_asix_thread,
181 (ULONG) asix,
182 asix -> ux_host_class_asix_thread_stack,
183 UX_THREAD_STACK_SIZE,
184 UX_THREAD_PRIORITY_CLASS,
185 UX_THREAD_PRIORITY_CLASS,
186 TX_NO_TIME_SLICE, UX_AUTO_START);
187
188 /* Check the completion status. */
189 if (status != UX_SUCCESS)
190 status = UX_THREAD_ERROR;
191 }
192
193 UX_THREAD_EXTENSION_PTR_SET(&(asix -> ux_host_class_asix_thread), asix)
194
195 /* The asix chip needs to be setup properly. */
196 if (status == UX_SUCCESS)
197 status = _ux_host_class_asix_setup(asix);
198
199 /* Go on if there is no error. */
200 if (status == UX_SUCCESS)
201 {
202
203 /* The ethernet link is down by default. */
204 asix -> ux_host_class_asix_link_state = UX_HOST_CLASS_ASIX_LINK_STATE_DOWN;
205
206 /* Start the interrupt pipe now. */
207 transfer_request = &asix -> ux_host_class_asix_interrupt_endpoint -> ux_endpoint_transfer_request;
208 status = _ux_host_stack_transfer_request(transfer_request);
209 }
210
211 /* Allocate some memory for reception. */
212 if (status == UX_SUCCESS)
213 {
214 asix -> ux_host_class_asix_receive_buffer = _ux_utility_memory_allocate(UX_SAFE_ALIGN, UX_CACHE_SAFE_MEMORY, UX_HOST_CLASS_ASIX_RECEIVE_BUFFER_SIZE);
215 if (asix -> ux_host_class_asix_receive_buffer == UX_NULL)
216 status = UX_MEMORY_INSUFFICIENT;
217 }
218
219 /* Activate network driver. */
220 if (status == UX_SUCCESS)
221 {
222
223 /* Setup the physical address of this IP instance. */
224 physical_address_msw = (ULONG)((asix -> ux_host_class_asix_node_id[0] << 8) | (asix -> ux_host_class_asix_node_id[1]));
225 physical_address_lsw = (ULONG)((asix -> ux_host_class_asix_node_id[2] << 24) | (asix -> ux_host_class_asix_node_id[3] << 16) |
226 (asix -> ux_host_class_asix_node_id[4] << 8) | (asix -> ux_host_class_asix_node_id[5]));
227
228 /* Register this interface to the NetX USB interface broker. */
229 status = _ux_network_driver_activate((VOID *) asix, _ux_host_class_asix_write,
230 &asix -> ux_host_class_asix_network_handle,
231 physical_address_msw,
232 physical_address_lsw);
233 }
234
235 /* Do final things if success. */
236 if (status == UX_SUCCESS)
237 {
238
239 /* Mark the asix instance as live now. */
240 asix -> ux_host_class_asix_state = UX_HOST_CLASS_INSTANCE_LIVE;
241
242 /* If all is fine and the device is mounted, we need to inform the application
243 if a function has been programmed in the system structure. */
244 if (_ux_system_host -> ux_system_host_change_function != UX_NULL)
245 {
246
247 /* Call system change function. */
248 _ux_system_host -> ux_system_host_change_function(UX_DEVICE_INSERTION, asix -> ux_host_class_asix_class, (VOID *) asix);
249 }
250
251 /* If trace is enabled, insert this event into the trace buffer. */
252 UX_TRACE_IN_LINE_INSERT(UX_TRACE_HOST_CLASS_ASIX_ACTIVATE, asix, 0, 0, 0, UX_TRACE_HOST_CLASS_EVENTS, 0, 0)
253
254 /* If trace is enabled, register this object. */
255 UX_TRACE_OBJECT_REGISTER(UX_TRACE_HOST_OBJECT_TYPE_INTERFACE, asix, 0, 0, 0)
256
257 /* Return completion status. */
258 return(UX_SUCCESS);
259 }
260
261 /* There was a problem, so free the resources. */
262
263 /* Free asix -> ux_host_class_asix_receive_buffer. */
264 if (asix -> ux_host_class_asix_receive_buffer)
265 _ux_utility_memory_free(asix -> ux_host_class_asix_receive_buffer);
266
267 /* Free asix -> ux_host_class_asix_thread. */
268 if (asix -> ux_host_class_asix_thread.tx_thread_id)
269 _ux_utility_thread_delete(&asix -> ux_host_class_asix_thread);
270
271 /* Free asix -> ux_host_class_asix_thread_stack. */
272 if (asix -> ux_host_class_asix_thread_stack)
273 _ux_utility_memory_free(asix -> ux_host_class_asix_thread_stack);
274
275 /* Free asix -> ux_host_class_asix_interrupt_notification_semaphore. */
276 if (asix -> ux_host_class_asix_interrupt_notification_semaphore.tx_semaphore_id != 0)
277 _ux_host_semaphore_delete(&asix -> ux_host_class_asix_interrupt_notification_semaphore);
278
279 /* Free asix -> ux_host_class_asix_semaphore. */
280 if (asix -> ux_host_class_asix_semaphore.tx_semaphore_id != 0)
281 _ux_host_semaphore_delete(&asix -> ux_host_class_asix_semaphore);
282
283 /* Destroy class instance. */
284 _ux_host_stack_class_instance_destroy(asix -> ux_host_class_asix_class, (VOID *) asix);
285
286 /* Detach instance. */
287 device -> ux_device_class_instance = UX_NULL;
288
289 /* Free instance memory. */
290 _ux_utility_memory_free(asix);
291
292 /* Return completion status. */
293 return(status);
294 #endif
295 }
296
297