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 /**   CDC ECM 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_cdc_ecm.h"
29 #include "ux_host_stack.h"
30 
31 
32 /**************************************************************************/
33 /*                                                                        */
34 /*  FUNCTION                                               RELEASE        */
35 /*                                                                        */
36 /*    _ux_host_class_cdc_ecm_interrupt_notification       PORTABLE C      */
37 /*                                                           6.1.11       */
38 /*  AUTHOR                                                                */
39 /*                                                                        */
40 /*    Chaoqiong Xiao, Microsoft Corporation                               */
41 /*                                                                        */
42 /*  DESCRIPTION                                                           */
43 /*                                                                        */
44 /*    This function is called by the stack when an interrupt packet as    */
45 /*    been received.                                                      */
46 /*                                                                        */
47 /*  INPUT                                                                 */
48 /*                                                                        */
49 /*    transfer_request                      Pointer to transfer request   */
50 /*                                                                        */
51 /*  OUTPUT                                                                */
52 /*                                                                        */
53 /*    None                                                                */
54 /*                                                                        */
55 /*  CALLS                                                                 */
56 /*                                                                        */
57 /*    None                                                                */
58 /*                                                                        */
59 /*  CALLED BY                                                             */
60 /*                                                                        */
61 /*    USBX stack                                                          */
62 /*                                                                        */
63 /*  RELEASE HISTORY                                                       */
64 /*                                                                        */
65 /*    DATE              NAME                      DESCRIPTION             */
66 /*                                                                        */
67 /*  05-19-2020     Chaoqiong Xiao           Initial Version 6.0           */
68 /*  09-30-2020     Chaoqiong Xiao           Modified comment(s),          */
69 /*                                            resulting in version 6.1    */
70 /*  01-31-2022     Chaoqiong Xiao           Modified comment(s),          */
71 /*                                            refined macros names,       */
72 /*                                            resulting in version 6.1.10 */
73 /*  04-25-2022     Chaoqiong Xiao           Modified comment(s),          */
74 /*                                            fixed standalone compile,   */
75 /*                                            resulting in version 6.1.11 */
76 /*                                                                        */
77 /**************************************************************************/
_ux_host_class_cdc_ecm_interrupt_notification(UX_TRANSFER * transfer_request)78 VOID  _ux_host_class_cdc_ecm_interrupt_notification(UX_TRANSFER *transfer_request)
79 {
80 
81 UX_HOST_CLASS_CDC_ECM                       *cdc_ecm;
82 ULONG                                       notification_type;
83 ULONG                                       notification_value;
84 
85 
86     /* Get the control class instance for this transfer request.  */
87     cdc_ecm =  (UX_HOST_CLASS_CDC_ECM *) transfer_request -> ux_transfer_request_class_instance;
88 
89     /* Check the state of the transfer.  If there is an error, we do not proceed with this notification.  */
90     if (transfer_request -> ux_transfer_request_completion_code != UX_SUCCESS)
91 
92         /* We do not proceed.  */
93         return;
94 
95     /* Check if the class is in shutdown.  */
96     if (cdc_ecm -> ux_host_class_cdc_ecm_state ==  UX_HOST_CLASS_INSTANCE_SHUTDOWN)
97 
98         /* We do not proceed.  */
99         return;
100 
101     /* Increment the notification count.   */
102     cdc_ecm -> ux_host_class_cdc_ecm_notification_count++;
103 
104     /* Get the notification.  */
105     notification_type = (ULONG) *(transfer_request -> ux_transfer_request_data_pointer + UX_HOST_CLASS_CDC_ECM_NPF_NOTIFICATION_TYPE);
106 
107     /* And the value.  */
108     notification_value = (ULONG) *(transfer_request -> ux_transfer_request_data_pointer + UX_HOST_CLASS_CDC_ECM_NPF_VALUE);
109 
110     /* Check if the notification is a Network notification.  */
111     if (notification_type == UX_HOST_CLASS_CDC_ECM_NOTIFICATION_NETWORK_CONNECTION)
112     {
113 
114         /* Check the state of the link.  */
115         if (notification_value == UX_HOST_CLASS_CDC_ECM_NOTIFICATION_NETWORK_LINK_UP)
116         {
117 
118             /* Link is up. See if we know about that.  */
119             if (cdc_ecm -> ux_host_class_cdc_ecm_link_state != UX_HOST_CLASS_CDC_ECM_LINK_STATE_UP &&
120                 cdc_ecm -> ux_host_class_cdc_ecm_link_state != UX_HOST_CLASS_CDC_ECM_LINK_STATE_PENDING_UP)
121             {
122 
123                 /* Memorize the new link state.  */
124                 cdc_ecm -> ux_host_class_cdc_ecm_link_state =  UX_HOST_CLASS_CDC_ECM_LINK_STATE_PENDING_UP;
125 
126                 /* We need to inform the cdc_ecm thread of this change.  */
127                 _ux_host_semaphore_put(&cdc_ecm -> ux_host_class_cdc_ecm_interrupt_notification_semaphore);
128             }
129         }
130         else
131         {
132 
133             /* Link is down. See if we know about that.  */
134             if (cdc_ecm -> ux_host_class_cdc_ecm_link_state != UX_HOST_CLASS_CDC_ECM_LINK_STATE_DOWN &&
135                 cdc_ecm -> ux_host_class_cdc_ecm_link_state != UX_HOST_CLASS_CDC_ECM_LINK_STATE_PENDING_DOWN)
136             {
137 
138                 /* We need to abort any transfers on the bulk in endpoint.  */
139 
140                 /* Make sure no one does any more transfers.  */
141                 cdc_ecm -> ux_host_class_cdc_ecm_link_state =  UX_HOST_CLASS_CDC_ECM_LINK_STATE_PENDING_DOWN;
142 
143                 /* Now abort all transfers. It's possible we're executing right before the transfer
144                    is armed. If this is the case, then the transfer will not be aborted if we do the abort right now; instead,
145                    we should wait until after the transfer is armed. We must look at the CDC-ECM thread's state.  */
146 
147                 /* Is it in the process of checking the link state and arming the transfer?  */
148                 if (cdc_ecm -> ux_host_class_cdc_ecm_bulk_in_transfer_check_and_arm_in_process == UX_TRUE)
149                 {
150 
151                     /* Yes. We must wait for it to finish arming the transfer.  */
152 
153                     /* Let the CDC-ECM thread know we're waiting so it can wake us up.  */
154                     cdc_ecm -> ux_host_class_cdc_ecm_bulk_in_transfer_waiting_for_check_and_arm_to_finish =  UX_TRUE;
155 
156                     /* Wait for the transfer to be armed, or possibly an error. The CDC-ECM thread will wake us up.  */
157                     _ux_host_semaphore_get_norc(&cdc_ecm -> ux_host_class_cdc_ecm_bulk_in_transfer_waiting_for_check_and_arm_to_finish_semaphore, UX_WAIT_FOREVER);
158 
159                     /* We're no longer waiting.  */
160                     cdc_ecm -> ux_host_class_cdc_ecm_bulk_in_transfer_waiting_for_check_and_arm_to_finish =  UX_FALSE;
161                 }
162 
163                 /* Now we can abort the transfer.  */
164                 _ux_host_stack_transfer_request_abort(&cdc_ecm -> ux_host_class_cdc_ecm_bulk_in_endpoint -> ux_endpoint_transfer_request);
165 
166                 /* We need to inform the CDC-ECM thread of this change.  */
167                 _ux_host_semaphore_put(&cdc_ecm -> ux_host_class_cdc_ecm_interrupt_notification_semaphore);
168             }
169         }
170     }
171 
172     /* Reactivate the CDC_ECM interrupt pipe.  */
173     _ux_host_stack_transfer_request(transfer_request);
174 
175     /* If trace is enabled, insert this event into the trace buffer.  */
176     UX_TRACE_IN_LINE_INSERT(UX_TRACE_HOST_CLASS_CDC_ECM_INTERRUPT_NOTIFICATION, cdc_ecm, 0, 0, 0, UX_TRACE_HOST_CLASS_EVENTS, 0, 0)
177 
178     /* Return to caller.  */
179     return;
180 }
181 
182