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 /**   Pima 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_pima.h"
29 #include "ux_host_stack.h"
30 
31 
32 /**************************************************************************/
33 /*                                                                        */
34 /*  FUNCTION                                               RELEASE        */
35 /*                                                                        */
36 /*    _ux_host_class_pima_notification                    PORTABLE C      */
37 /*                                                           6.1          */
38 /*  AUTHOR                                                                */
39 /*                                                                        */
40 /*    Chaoqiong Xiao, Microsoft Corporation                               */
41 /*                                                                        */
42 /*  DESCRIPTION                                                           */
43 /*                                                                        */
44 /*    This function is called by the completion thread when a transfer    */
45 /*    request has been completed either because the transfer is           */
46 /*    successful or there was an error.                                   */
47 /*                                                                        */
48 /*  INPUT                                                                 */
49 /*                                                                        */
50 /*    transfer_request                      Pointer to transfer request   */
51 /*                                                                        */
52 /*  OUTPUT                                                                */
53 /*                                                                        */
54 /*    None                                                                */
55 /*                                                                        */
56 /*  CALLS                                                                 */
57 /*                                                                        */
58 /*    _ux_host_stack_transfer_request       Transfer request              */
59 /*    _ux_utility_memory_copy               Copy memory                   */
60 /*    _ux_utility_short_get                 Get 16-bit value              */
61 /*    _ux_utility_long_get                  Get 32-bit value              */
62 /*                                                                        */
63 /*  CALLED BY                                                             */
64 /*                                                                        */
65 /*    USBX stack                                                          */
66 /*                                                                        */
67 /*  RELEASE HISTORY                                                       */
68 /*                                                                        */
69 /*    DATE              NAME                      DESCRIPTION             */
70 /*                                                                        */
71 /*  05-19-2020     Chaoqiong Xiao           Initial Version 6.0           */
72 /*  09-30-2020     Chaoqiong Xiao           Modified comment(s),          */
73 /*                                            verified memset and memcpy  */
74 /*                                            cases,                      */
75 /*                                            resulting in version 6.1    */
76 /*                                                                        */
77 /**************************************************************************/
_ux_host_class_pima_notification(UX_TRANSFER * transfer_request)78 VOID  _ux_host_class_pima_notification(UX_TRANSFER *transfer_request)
79 {
80 
81 UX_HOST_CLASS_PIMA                       *pima;
82 UX_HOST_CLASS_PIMA_SESSION                 *pima_session;
83 UX_HOST_CLASS_PIMA_EVENT                pima_event;
84 
85     /* Get the class instance for this transfer request.  */
86     pima =  (UX_HOST_CLASS_PIMA *) transfer_request -> ux_transfer_request_class_instance;
87 
88     /* Check the state of the transfer.  If there is an error, we do not proceed with this notification.  */
89     if (transfer_request -> ux_transfer_request_completion_code != UX_SUCCESS)
90     {
91 
92         /* We have an error. We do not rehook another transfer if the device instance is shutting down or
93            if the transfer was aborted by the class..  */
94         if ((pima -> ux_host_class_pima_state ==  UX_HOST_CLASS_INSTANCE_SHUTDOWN) ||
95             (transfer_request -> ux_transfer_request_completion_code == UX_TRANSFER_STATUS_ABORT))
96 
97             /* We do not proceed.  */
98             return;
99         else
100 
101         {
102 
103             /* Reactivate the PIMA interrupt pipe.  */
104             _ux_host_stack_transfer_request(transfer_request);
105 
106             /* We do not proceed.  */
107             return;
108         }
109 
110     }
111 
112     /* Check if this packet is the first, if so we have the total length expected in the event.  */
113     if (pima -> ux_host_class_pima_event_buffer_current_length == 0)
114     {
115 
116         /* First packet. Maybe the only one needed. It may happen that the notification event is split amongst
117            several interrupt packets.  */
118         pima -> ux_host_class_pima_event_buffer_expected_length  = _ux_utility_long_get(transfer_request -> ux_transfer_request_data_pointer
119                                                                                             + UX_HOST_CLASS_PIMA_AEI_DATA_LENGTH);
120 
121         /* Set the current offset to the beginning of the buffer.  */
122         pima -> ux_host_class_pima_event_buffer_current_offset =  pima -> ux_host_class_pima_event_buffer;
123 
124     }
125 
126     /* Check the length of this payload and make sure we have enough space.  */
127     if ((pima -> ux_host_class_pima_event_buffer_current_length + transfer_request -> ux_transfer_request_actual_length) <=
128             UX_HOST_CLASS_PIMA_AEI_MAX_LENGTH)
129     {
130 
131         /* We copy the current payload into our event notification buffer.  */
132         _ux_utility_memory_copy(pima -> ux_host_class_pima_event_buffer_current_offset, transfer_request -> ux_transfer_request_data_pointer,
133                             transfer_request -> ux_transfer_request_actual_length); /* Use case of memcpy is verified. */
134 
135         /* Set the new offset address. */
136         pima -> ux_host_class_pima_event_buffer_current_offset += transfer_request -> ux_transfer_request_actual_length;
137 
138         /* Adjust the length.  */
139         pima -> ux_host_class_pima_event_buffer_current_length += transfer_request -> ux_transfer_request_actual_length;
140     }
141     else
142 
143         /* We come here when we have a buffer overflow. Do not proceed.  */
144         return;
145 
146     /* Check if we have a complete notification event.  */
147     if (pima -> ux_host_class_pima_event_buffer_current_length == pima -> ux_host_class_pima_event_buffer_expected_length)
148     {
149 
150         /* Save the current event in the pima instance.  First, unpack the event code.  */
151         pima -> ux_host_class_pima_event_code = _ux_utility_short_get(pima -> ux_host_class_pima_event_buffer + UX_HOST_CLASS_PIMA_AEI_EVENT_CODE);
152 
153         /* Unpack the Transaction ID.  */
154         pima -> ux_host_class_pima_event_transaction_id = _ux_utility_long_get(pima -> ux_host_class_pima_event_buffer + UX_HOST_CLASS_PIMA_AEI_TRANSACTION_ID);
155 
156         /* Unpack the parameter 1.  */
157         pima -> ux_host_class_pima_event_parameter_1 = _ux_utility_long_get(pima -> ux_host_class_pima_event_buffer + UX_HOST_CLASS_PIMA_AEI_PARAMETER_1);
158 
159         /* Unpack the parameter 2.  */
160         pima -> ux_host_class_pima_event_parameter_2 = _ux_utility_long_get(pima -> ux_host_class_pima_event_buffer + UX_HOST_CLASS_PIMA_AEI_PARAMETER_2);
161 
162         /* Unpack the parameter 3.  */
163         pima -> ux_host_class_pima_event_parameter_3 = _ux_utility_long_get(pima -> ux_host_class_pima_event_buffer + UX_HOST_CLASS_PIMA_AEI_PARAMETER_3);
164 
165         /* Check if a session is valid.  */
166         if (pima -> ux_host_class_pima_session != UX_NULL)
167         {
168 
169             /* Get session pointer.  */
170             pima_session =  pima -> ux_host_class_pima_session;
171 
172             /* Check if this session is valid or not.  */
173             if ((pima_session -> ux_host_class_pima_session_magic == UX_HOST_CLASS_PIMA_MAGIC_NUMBER) &&
174                (pima_session -> ux_host_class_pima_session_state == UX_HOST_CLASS_PIMA_SESSION_STATE_OPENED))
175             {
176 
177                 /* If the application demanded a callback when event occur, create a event notification
178                    message.  */
179                 if (pima_session -> ux_host_class_pima_session_event_callback != UX_NULL)
180                 {
181 
182                     /* Fill in the pima event structure. First with pima instance.  */
183                     pima_event.ux_host_class_pima_event_pima_instance = pima;
184 
185                     /* Fill in the opened session pointer.  Since the pima class only supports
186                        one session, this address is hardwired to the opened session and is not coming from
187                        the event buffer.  */
188                     pima_event.ux_host_class_pima_event_session = pima_session;
189 
190                     /* Fill in all the event parameters in the event callback structure.  */
191                     pima_event.ux_host_class_pima_event_code =  pima -> ux_host_class_pima_event_code;
192                     pima_event.ux_host_class_pima_event_transaction_id =  pima -> ux_host_class_pima_event_transaction_id;
193                     pima_event.ux_host_class_pima_event_parameter_1 =  pima -> ux_host_class_pima_event_parameter_1;
194                     pima_event.ux_host_class_pima_event_parameter_2 =  pima -> ux_host_class_pima_event_parameter_2;
195                     pima_event.ux_host_class_pima_event_parameter_3 =  pima -> ux_host_class_pima_event_parameter_3;
196 
197                     /* Send this event to the application.  */
198                     pima_session -> ux_host_class_pima_session_event_callback(&pima_event);
199 
200                     /* If trace is enabled, insert this event into the trace buffer.  */
201                     UX_TRACE_IN_LINE_INSERT(UX_TRACE_HOST_CLASS_PIMA_NOTIFICATION, pima,
202                                             pima -> ux_host_class_pima_event_code,
203                                             pima -> ux_host_class_pima_event_transaction_id,
204                                             pima -> ux_host_class_pima_event_parameter_1,
205                                             UX_TRACE_HOST_CLASS_EVENTS, 0, 0)
206 
207                 }
208             }
209         }
210 
211         /* We will receive a complete new transaction.  */
212         pima -> ux_host_class_pima_event_buffer_current_length =  0;
213     }
214     /* Reactivate the PIMA interrupt pipe.  */
215     _ux_host_stack_transfer_request(transfer_request);
216 
217     /* Return to caller.  */
218     return;
219 }
220 
221