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