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 /** USBX Component */
15 /** */
16 /** Device CCID Class */
17 /** */
18 /**************************************************************************/
19 /**************************************************************************/
20
21 #define UX_SOURCE_CODE
22
23
24 /* Include necessary system files. */
25
26 #include "ux_api.h"
27 #include "ux_device_class_ccid.h"
28 #include "ux_device_stack.h"
29
30
31 #if defined(UX_DEVICE_STANDALONE)
32
33
34 /**************************************************************************/
35 /* */
36 /* FUNCTION RELEASE */
37 /* */
38 /* _ux_device_class_ccid_runner_task_run PORTABLE C */
39 /* 6.2.1 */
40 /* AUTHOR */
41 /* */
42 /* Chaoqiong Xiao, Microsoft Corporation */
43 /* */
44 /* DESCRIPTION */
45 /* */
46 /* This function is the background task of the CCID. */
47 /* */
48 /* It's for standalone mode. */
49 /* */
50 /* INPUT */
51 /* */
52 /* ccid Pointer to CCID class */
53 /* */
54 /* OUTPUT */
55 /* */
56 /* State machine status */
57 /* UX_STATE_EXIT Device not configured */
58 /* UX_STATE_IDLE No streaming transfer running */
59 /* UX_STATE_WAIT Streaming transfer running */
60 /* */
61 /* CALLS */
62 /* */
63 /* */
64 /* CALLED BY */
65 /* */
66 /* USBX Device Stack */
67 /* */
68 /* RELEASE HISTORY */
69 /* */
70 /* DATE NAME DESCRIPTION */
71 /* */
72 /* 03-08-2023 Chaoqiong Xiao Initial Version 6.2.1 */
73 /* */
74 /**************************************************************************/
_ux_device_class_ccid_runner_task_run(UX_DEVICE_CLASS_CCID * ccid)75 UINT _ux_device_class_ccid_runner_task_run(UX_DEVICE_CLASS_CCID *ccid)
76 {
77
78 UX_SLAVE_DEVICE *device;
79 UX_DEVICE_CLASS_CCID_PARAMETER *parameter;
80 UX_DEVICE_CLASS_CCID_HANDLE *handles;
81 UX_DEVICE_CLASS_CCID_HANDLE handle;
82 UX_DEVICE_CLASS_CCID_RUNNER *runner;
83 UX_DEVICE_CLASS_CCID_SLOT *slot;
84 UX_DEVICE_CLASS_CCID_MESSAGE_HEADER *cmd;
85 UX_DEVICE_CLASS_CCID_COMMAND_SETT *cmd_sett;
86 UX_DEVICE_CLASS_CCID_RDR_TO_PC_SLOT_STATUS_HEADER *rsp;
87 UX_DEVICE_CLASS_CCID_MESSAGES *messages;
88 ULONG cmd_checks;
89 UINT status;
90 INT immediate_state = UX_TRUE;
91
92
93 /* Get the pointer to the device. */
94 device = &_ux_system_slave -> ux_system_slave_device;
95
96 /* Check if the device is configured. */
97 if (device -> ux_slave_device_state != UX_DEVICE_CONFIGURED)
98 return(UX_STATE_EXIT);
99
100 /* Get CCID runner (optimized only 1 runner). */
101 runner = ccid -> ux_device_class_ccid_runners;
102
103 /* Slot to handle (optimized for only one slot). */
104 slot = ccid -> ux_device_class_ccid_slots;
105
106 /* Get CCID parameter. */
107 parameter = &ccid -> ux_device_class_ccid_parameter;
108
109 /* Get CCID messages. */
110 messages = &runner -> ux_device_class_ccid_runner_messages;
111
112 /* Get command and response buffers. */
113 cmd = (UX_DEVICE_CLASS_CCID_MESSAGE_HEADER *)
114 runner -> ux_device_class_ccid_runner_command;
115 rsp = (UX_DEVICE_CLASS_CCID_RDR_TO_PC_SLOT_STATUS_HEADER *)
116 runner -> ux_device_class_ccid_runner_response;
117
118 /* Process states. */
119 while(immediate_state)
120 {
121
122 /* Check states. */
123 switch(runner -> ux_device_class_ccid_runner_state)
124 {
125 case UX_DEVICE_CLASS_CCID_RUNNER_IDLE:
126 return(UX_STATE_IDLE);
127
128 case UX_DEVICE_CLASS_CCID_RUNNER_START:
129
130 /* Command settings. */
131 cmd_sett = (UX_DEVICE_CLASS_CCID_COMMAND_SETT *)_ux_device_class_ccid_command_sett;
132 cmd_sett += runner -> ux_device_class_ccid_runner_command_index;
133
134 /* Message to pass to application. */
135 messages -> ux_device_class_ccid_messages_pc_to_rdr = (UCHAR *)cmd;
136 messages -> ux_device_class_ccid_messages_rdr_to_pc = (UCHAR *)rsp;
137
138 /* Internal checks. */
139 cmd_checks = (ULONG)cmd_sett -> ux_device_class_ccid_command_sett_flags;
140 cmd_checks &= (ULONG)slot -> ux_device_class_ccid_slot_flags;
141
142 /* Check hardware error! */
143 if (cmd_checks & UX_DEVICE_CLASS_CCID_FLAG_HW_ERROR)
144 {
145
146 /* Response: (1,1,HW_ERROR). */
147 rsp -> bStatus = UX_DEVICE_CLASS_CCID_SLOT_STATUS(1, 1);
148 rsp -> bError = UX_DEVICE_CLASS_CCID_HW_ERROR;
149
150 /* Send response. */
151 _ux_device_class_ccid_response(ccid, (UCHAR *)rsp,
152 messages -> ux_device_class_ccid_messages_rdr_to_pc_length);
153
154 /* Runner is idle (status is updated after response sent). */
155 runner -> ux_device_class_ccid_runner_state = UX_DEVICE_CLASS_CCID_RUNNER_IDLE;
156 continue;
157 }
158
159 /* Check auto sequencing! */
160 if (cmd_checks & UX_DEVICE_CLASS_CCID_FLAG_AUTO_SEQUENCING)
161 {
162
163 /* Response: (1,1,BUSY_WITH_AUTO_SEQUENCE). */
164 rsp -> bStatus = UX_DEVICE_CLASS_CCID_SLOT_STATUS(1, 1);
165 rsp -> bError = UX_DEVICE_CLASS_CCID_BUSY_WITH_AUTO_SEQUENCE;
166
167 /* Send response. */
168 _ux_device_class_ccid_response(ccid, (UCHAR *)rsp,
169 messages -> ux_device_class_ccid_messages_rdr_to_pc_length);
170
171 /* Runner is idle (status is updated after response sent). */
172 runner -> ux_device_class_ccid_runner_state = UX_DEVICE_CLASS_CCID_RUNNER_IDLE;
173 continue;
174 }
175
176 /* Get command to process, application can fill status. */
177 handles = (UX_DEVICE_CLASS_CCID_HANDLE *)parameter -> ux_device_class_ccid_handles;
178 handle = handles[(INT)cmd_sett -> ux_device_class_ccid_command_sett_handle_index];
179
180 /* Initialize response length based on type. */
181 switch(rsp -> bMessageType)
182 {
183 case UX_DEVICE_CLASS_CCID_RDR_TO_PC_DATA_RATE_AND_CLOCK_FREQ:
184
185 /* Length fixed to 10+8. */
186 messages -> ux_device_class_ccid_messages_rdr_to_pc_length = 18;
187 UX_DEVICE_CLASS_CCID_MESSAGE_LENGTH_SET(rsp, 8);
188 break;
189
190 case UX_DEVICE_CLASS_CCID_RDR_TO_PC_SLOT_STATUS:
191
192 /* Length fixed to 10. */
193 messages -> ux_device_class_ccid_messages_rdr_to_pc_length =
194 UX_DEVICE_CLASS_CCID_MESSAGE_HEADER_LENGTH;
195 break;
196
197 default:
198
199 /* There is possible data, set length to max transfer length. */
200 messages -> ux_device_class_ccid_messages_rdr_to_pc_length =
201 parameter -> ux_device_class_ccid_max_transfer_length;
202 break;
203 }
204
205 /* Save handle that is running. */
206 runner -> ux_device_class_ccid_runner_handle = handle;
207
208 /* Fall through. */
209 case UX_DEVICE_CLASS_CCID_RUNNER_HANDLE:
210
211 /* Run handle (state machine). */
212 status = runner -> ux_device_class_ccid_runner_handle(cmd -> bSlot, messages);
213
214 /* Error cases. */
215 if (status < UX_STATE_NEXT ||
216 slot -> ux_device_class_ccid_slot_aborting)
217 {
218
219 /* There is no response in this case. */
220 runner -> ux_device_class_ccid_runner_state = UX_DEVICE_CLASS_CCID_RUNNER_IDLE;
221 return(UX_STATE_IDLE);
222 }
223
224 /* Done case. */
225 if (status == UX_STATE_NEXT)
226 {
227
228 /* Next: response start. */
229 runner -> ux_device_class_ccid_runner_state = UX_DEVICE_CLASS_CCID_RUNNER_RSP_START;
230 continue;
231 }
232
233 /* Waiting. */
234 return(UX_STATE_WAIT);
235
236 case UX_DEVICE_CLASS_CCID_RUNNER_RSP_START:
237
238 /* Wait response idle. */
239 if (ccid -> ux_device_class_ccid_rsp_state != UX_DEVICE_CLASS_CCID_RSP_IDLE)
240 return(UX_STATE_WAIT);
241
242 /* Send response. */
243 _ux_device_class_ccid_response(ccid, (UCHAR *)rsp,
244 messages -> ux_device_class_ccid_messages_rdr_to_pc_length);
245
246 /* Runner is idle (status is updated after response sent). */
247 runner -> ux_device_class_ccid_runner_state = UX_DEVICE_CLASS_CCID_RUNNER_IDLE;
248 continue;
249
250 default:
251 break;
252 }
253
254 /* Break the loop. */
255 immediate_state = UX_FALSE;
256 }
257
258 /* Unhandled state. */
259 return(UX_STATE_EXIT);
260 }
261
262 #endif
263