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