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 /** USBX Component                                                        */
14 /**                                                                       */
15 /**   Device CDC_ECM Class                                                */
16 /**                                                                       */
17 /**************************************************************************/
18 /**************************************************************************/
19 
20 #define UX_SOURCE_CODE
21 
22 
23 /* Include necessary system files.  */
24 
25 #include "ux_api.h"
26 #include "ux_device_class_cdc_ecm.h"
27 #include "ux_device_stack.h"
28 
29 
30 /**************************************************************************/
31 /*                                                                        */
32 /*  FUNCTION                                               RELEASE        */
33 /*                                                                        */
34 /*    _ux_device_class_cdc_ecm_change                     PORTABLE C      */
35 /*                                                           6.3.0        */
36 /*  AUTHOR                                                                */
37 /*                                                                        */
38 /*    Chaoqiong Xiao, Microsoft Corporation                               */
39 /*                                                                        */
40 /*  DESCRIPTION                                                           */
41 /*                                                                        */
42 /*    This function changes the interface of the CDC_ECM device           */
43 /*                                                                        */
44 /*  INPUT                                                                 */
45 /*                                                                        */
46 /*    command                           Pointer to cdc_ecm command        */
47 /*                                                                        */
48 /*  OUTPUT                                                                */
49 /*                                                                        */
50 /*    Completion Status                                                   */
51 /*                                                                        */
52 /*  CALLS                                                                 */
53 /*                                                                        */
54 /*    _ux_network_driver_link_up            Link status up                */
55 /*    _ux_network_driver_link_down          Link status down              */
56 /*    _ux_utility_memory_set                Set memory                    */
57 /*    _ux_device_thread_resume              Resume thread                 */
58 /*    _ux_device_event_flags_set            Set event flags               */
59 /*    _ux_device_stack_transfer_all_request_abort                         */
60 /*                                          Abort transfer                */
61 /*                                                                        */
62 /*  CALLED BY                                                             */
63 /*                                                                        */
64 /*    USBX Source Code                                                    */
65 /*                                                                        */
66 /*  RELEASE HISTORY                                                       */
67 /*                                                                        */
68 /*    DATE              NAME                      DESCRIPTION             */
69 /*                                                                        */
70 /*  05-19-2020     Chaoqiong Xiao           Initial Version 6.0           */
71 /*  09-30-2020     Chaoqiong Xiao           Modified comment(s),          */
72 /*                                            verified memset and memcpy  */
73 /*                                            cases, used UX prefix to    */
74 /*                                            refer to TX symbols instead */
75 /*                                            of using them directly,     */
76 /*                                            resulting in version 6.1    */
77 /*  01-31-2022     Chaoqiong Xiao           Modified comment(s),          */
78 /*                                            refined macros names,       */
79 /*                                            resulting in version 6.1.10 */
80 /*  04-25-2022     Chaoqiong Xiao           Modified comment(s),          */
81 /*                                            fixed standalone compile,   */
82 /*                                            resulting in version 6.1.11 */
83 /*  07-29-2022     Chaoqiong Xiao           Modified comment(s),          */
84 /*                                            fixed parameter/variable    */
85 /*                                            names conflict C++ keyword, */
86 /*                                            resulting in version 6.1.12 */
87 /*  10-31-2023     Chaoqiong Xiao           Modified comment(s),          */
88 /*                                            added zero copy support,    */
89 /*                                            added a new mode to manage  */
90 /*                                            endpoint buffer in classes, */
91 /*                                            resulting in version 6.3.0  */
92 /*                                                                        */
93 /**************************************************************************/
_ux_device_class_cdc_ecm_change(UX_SLAVE_CLASS_COMMAND * command)94 UINT  _ux_device_class_cdc_ecm_change(UX_SLAVE_CLASS_COMMAND *command)
95 {
96 
97 UX_SLAVE_INTERFACE                      *interface_ptr;
98 UX_SLAVE_CLASS                          *class_ptr;
99 UX_SLAVE_CLASS_CDC_ECM                  *cdc_ecm;
100 UX_SLAVE_ENDPOINT                       *endpoint;
101 
102     /* Get the class container.  */
103     class_ptr =  command -> ux_slave_class_command_class_ptr;
104 
105     /* Get the class instance in the container.  */
106     cdc_ecm = (UX_SLAVE_CLASS_CDC_ECM *) class_ptr -> ux_slave_class_instance;
107 
108     /* Get the interface that owns this instance.  */
109     interface_ptr =  (UX_SLAVE_INTERFACE  *) command -> ux_slave_class_command_interface;
110 
111     /* Locate the endpoints.  Control and Bulk in/out for Data Interface.  */
112     endpoint =  interface_ptr -> ux_slave_interface_first_endpoint;
113 
114     /* If the interface to mount has a non zero alternate setting, the class is really active with
115        the endpoints active.  If the interface reverts to alternate setting 0, it needs to have
116        the pending transactions terminated.  */
117     if (interface_ptr -> ux_slave_interface_descriptor.bAlternateSetting != 0)
118     {
119 
120         /* Parse all endpoints.  */
121         while (endpoint != UX_NULL)
122         {
123 
124             /* Check the endpoint direction, and type.  */
125             if ((endpoint -> ux_slave_endpoint_descriptor.bEndpointAddress & UX_ENDPOINT_DIRECTION) == UX_ENDPOINT_IN)
126             {
127 
128                 /* Look at type.  */
129                 if ((endpoint -> ux_slave_endpoint_descriptor.bmAttributes & UX_MASK_ENDPOINT_TYPE) == UX_BULK_ENDPOINT)
130 
131                     /* We have found the bulk in endpoint, save it.  */
132                     cdc_ecm -> ux_slave_class_cdc_ecm_bulkin_endpoint =  endpoint;
133 #if (UX_DEVICE_ENDPOINT_BUFFER_OWNER == 1) && !defined(UX_DEVICE_CLASS_CDC_ECM_ZERO_COPY)
134                     endpoint -> ux_slave_endpoint_transfer_request.
135                         ux_slave_transfer_request_data_pointer =
136                                 UX_DEVICE_CLASS_CDC_ECM_BULKIN_BUFFER(cdc_ecm);
137 #endif
138             }
139             else
140             {
141                 /* Look at type for out endpoint.  */
142                 if ((endpoint -> ux_slave_endpoint_descriptor.bmAttributes & UX_MASK_ENDPOINT_TYPE) == UX_BULK_ENDPOINT)
143 
144                     /* We have found the bulk out endpoint, save it.  */
145                     cdc_ecm -> ux_slave_class_cdc_ecm_bulkout_endpoint =  endpoint;
146 #if (UX_DEVICE_ENDPOINT_BUFFER_OWNER == 1) && !defined(UX_DEVICE_CLASS_CDC_ECM_ZERO_COPY)
147                     endpoint -> ux_slave_endpoint_transfer_request.
148                         ux_slave_transfer_request_data_pointer =
149                                 UX_DEVICE_CLASS_CDC_ECM_BULKOUT_BUFFER(cdc_ecm);
150 #endif
151             }
152 
153             /* Next endpoint.  */
154             endpoint =  endpoint -> ux_slave_endpoint_next_endpoint;
155         }
156 
157         /* Now check if all endpoints have been found.  */
158         if (cdc_ecm -> ux_slave_class_cdc_ecm_bulkout_endpoint == UX_NULL || cdc_ecm -> ux_slave_class_cdc_ecm_bulkin_endpoint == UX_NULL)
159 
160             /* Not all endpoints have been found. Major error, do not proceed.  */
161             return(UX_ERROR);
162 
163         /* Declare the link to be up. */
164         cdc_ecm -> ux_slave_class_cdc_ecm_link_state = UX_DEVICE_CLASS_CDC_ECM_LINK_STATE_UP;
165 
166         /* Communicate the state with the network driver.  */
167         _ux_network_driver_link_up(cdc_ecm -> ux_slave_class_cdc_ecm_network_handle);
168 
169 #if (UX_DEVICE_ENDPOINT_BUFFER_OWNER == 1) && defined(UX_DEVICE_CLASS_CDC_ECM_ZERO_COPY)
170 
171         /* There is no endpoint buffer.  */
172 #else
173 
174         /* Reset the endpoint buffers.  */
175         _ux_utility_memory_set(cdc_ecm -> ux_slave_class_cdc_ecm_bulkout_endpoint -> ux_slave_endpoint_transfer_request.
176                                         ux_slave_transfer_request_data_pointer, 0, UX_DEVICE_CLASS_CDC_ECM_BULKOUT_BUFFER_SIZE); /* Use case of memset is verified. */
177         _ux_utility_memory_set(cdc_ecm -> ux_slave_class_cdc_ecm_bulkin_endpoint -> ux_slave_endpoint_transfer_request.
178                                         ux_slave_transfer_request_data_pointer, 0, UX_DEVICE_CLASS_CDC_ECM_BULKIN_BUFFER_SIZE); /* Use case of memset is verified. */
179 #endif
180 
181         /* Resume the endpoint threads.  */
182         _ux_device_thread_resume(&cdc_ecm -> ux_slave_class_cdc_ecm_bulkout_thread);
183         _ux_device_thread_resume(&cdc_ecm -> ux_slave_class_cdc_ecm_bulkin_thread);
184 
185         /* Wake up the Interrupt thread and send a network notification to the host.  */
186         _ux_device_event_flags_set(&cdc_ecm -> ux_slave_class_cdc_ecm_event_flags_group, UX_DEVICE_CLASS_CDC_ECM_NETWORK_NOTIFICATION_EVENT, UX_OR);
187 
188         /* If there is an activate function call it.  */
189         if (cdc_ecm -> ux_slave_class_cdc_ecm_parameter.ux_slave_class_cdc_ecm_instance_activate != UX_NULL)
190 
191             /* Invoke the application.  */
192             cdc_ecm -> ux_slave_class_cdc_ecm_parameter.ux_slave_class_cdc_ecm_instance_activate(cdc_ecm);
193     }
194     else
195     {
196 
197         /* In this case, we are reverting to the Alternate Setting 0.  */
198 
199         /* Declare the link to be down.  */
200         cdc_ecm -> ux_slave_class_cdc_ecm_link_state = UX_DEVICE_CLASS_CDC_ECM_LINK_STATE_DOWN;
201 
202         /* Communicate the state with the network driver.  */
203         _ux_network_driver_link_down(cdc_ecm -> ux_slave_class_cdc_ecm_network_handle);
204 
205         /* Terminate the transactions pending on the bulk in endpoint.  If there is a transfer on the
206            bulk out endpoint, we simply let it finish and let NetX throw it away.  */
207         _ux_device_stack_transfer_all_request_abort(cdc_ecm -> ux_slave_class_cdc_ecm_bulkin_endpoint, UX_TRANSFER_APPLICATION_RESET);
208 
209         /* Notify the thread waiting for network notification events. In this case,
210            the event is that the link state has been switched to down.  */
211         _ux_device_event_flags_set(&cdc_ecm -> ux_slave_class_cdc_ecm_event_flags_group, UX_DEVICE_CLASS_CDC_ECM_NETWORK_NOTIFICATION_EVENT, UX_OR);
212 
213         /* Wake up the bulk in thread so that it can clean up the xmit queue.  */
214         _ux_device_event_flags_set(&cdc_ecm -> ux_slave_class_cdc_ecm_event_flags_group, UX_DEVICE_CLASS_CDC_ECM_NEW_DEVICE_STATE_CHANGE_EVENT, UX_OR);
215 
216         /* If there is a deactivate function call it.  */
217         if (cdc_ecm -> ux_slave_class_cdc_ecm_parameter.ux_slave_class_cdc_ecm_instance_deactivate != UX_NULL)
218 
219             /* Invoke the application.  */
220             cdc_ecm -> ux_slave_class_cdc_ecm_parameter.ux_slave_class_cdc_ecm_instance_deactivate(cdc_ecm);
221     }
222 
223     /* Set the CDC ECM alternate setting to the new one.  */
224     cdc_ecm -> ux_slave_class_cdc_ecm_current_alternate_setting = interface_ptr -> ux_slave_interface_descriptor.bAlternateSetting;
225 
226     /* If trace is enabled, insert this event into the trace buffer.  */
227     UX_TRACE_IN_LINE_INSERT(UX_TRACE_DEVICE_CLASS_CDC_ECM_CHANGE, cdc_ecm, 0, 0, 0, UX_TRACE_DEVICE_CLASS_EVENTS, 0, 0)
228 
229     /* If trace is enabled, register this object.  */
230     UX_TRACE_OBJECT_REGISTER(UX_TRACE_DEVICE_OBJECT_TYPE_INTERFACE, cdc_ecm, 0, 0, 0)
231 
232     /* Return completion status.  */
233     return(UX_SUCCESS);
234 }
235 
236