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 /*  FUNCTION                                               RELEASE        */
35 /*                                                                        */
36 /*    _ux_device_class_ccid_runner_thread_entry           PORTABLE C      */
37 /*                                                           6.2.1        */
38 /*  AUTHOR                                                                */
39 /*                                                                        */
40 /*    Chaoqiong Xiao, Microsoft Corporation                               */
41 /*                                                                        */
42 /*  DESCRIPTION                                                           */
43 /*                                                                        */
44 /*    This function is the thread of the CCID command handling. It        */
45 /*    is waiting for the event to start command processing.               */
46 /*                                                                        */
47 /*  INPUT                                                                 */
48 /*                                                                        */
49 /*    ccid_runner                           Address of CCID runner (32b)  */
50 /*                                                                        */
51 /*  OUTPUT                                                                */
52 /*                                                                        */
53 /*    None                                                                */
54 /*                                                                        */
55 /*  CALLS                                                                 */
56 /*                                                                        */
57 /*    _ux_device_stack_transfer_request     Request transfer              */
58 /*                                                                        */
59 /*  CALLED BY                                                             */
60 /*                                                                        */
61 /*    ThreadX                                                             */
62 /*                                                                        */
63 /*  RELEASE HISTORY                                                       */
64 /*                                                                        */
65 /*    DATE              NAME                      DESCRIPTION             */
66 /*                                                                        */
67 /*  04-25-2022     Chaoqiong Xiao           Initial Version 6.1.11        */
68 /*  03-08-2023     Chaoqiong Xiao           Modified comment(s),          */
69 /*                                            added standalone support,   */
70 /*                                            resulting in version 6.2.1  */
71 /*                                                                        */
72 /**************************************************************************/
_ux_device_class_ccid_runner_thread_entry(ULONG ccid_runner)73 VOID  _ux_device_class_ccid_runner_thread_entry(ULONG ccid_runner)
74 {
75 
76 UX_SLAVE_DEVICE                                     *device;
77 UX_DEVICE_CLASS_CCID                                *ccid;
78 UX_DEVICE_CLASS_CCID_PARAMETER                      *parameter;
79 UX_DEVICE_CLASS_CCID_HANDLE                         *handles;
80 UX_DEVICE_CLASS_CCID_HANDLE                         handle;
81 UX_DEVICE_CLASS_CCID_RUNNER                         *runner;
82 UX_DEVICE_CLASS_CCID_SLOT                           *slot;
83 UX_DEVICE_CLASS_CCID_MESSAGE_HEADER                 *cmd;
84 UX_DEVICE_CLASS_CCID_COMMAND_SETT                   *cmd_sett;
85 UX_DEVICE_CLASS_CCID_RDR_TO_PC_SLOT_STATUS_HEADER   *rsp;
86 UX_DEVICE_CLASS_CCID_MESSAGES                       messages;
87 ULONG                                               event_mask, flags;
88 ULONG                                               cmd_checks;
89 UINT                                                status;
90 
91     /* Cast properly the ccid runner.  */
92     UX_THREAD_EXTENSION_PTR_GET(runner, UX_DEVICE_CLASS_CCID_RUNNER, ccid_runner)
93 
94     /* Get the pointer to the device.  */
95     device =  &_ux_system_slave -> ux_system_slave_device;
96 
97     /* Get CCID instance.  */
98     ccid = runner -> ux_device_class_ccid_runner_ccid;
99 
100     /* Get CCID parameter.  */
101     parameter = &ccid -> ux_device_class_ccid_parameter;
102 
103     /* Get event mask to wait.  */
104     event_mask = 1u << runner -> ux_device_class_ccid_runner_id;
105 
106     /* This thread runs forever but can be suspended or resumed by the user application.  */
107     status = UX_SUCCESS;
108     while(1)
109     {
110 
111         /* Check device state.  */
112         if (device -> ux_slave_device_state != UX_DEVICE_CONFIGURED)
113         {
114             _ux_utility_thread_suspend(&runner -> ux_device_class_ccid_runner_thread);
115             continue;
116         }
117 
118         /* Wait signal.  */
119         status = _ux_utility_event_flags_get(&ccid -> ux_device_class_ccid_events,
120                             event_mask, UX_OR_CLEAR, &flags, UX_WAIT_FOREVER);
121         if (status != UX_SUCCESS)
122         {
123             _ux_utility_thread_suspend(&runner -> ux_device_class_ccid_runner_thread);
124             continue;
125         }
126 
127         /* We have a command to process.  */
128         cmd = (UX_DEVICE_CLASS_CCID_MESSAGE_HEADER *)
129                                 runner -> ux_device_class_ccid_runner_command;
130         rsp = (UX_DEVICE_CLASS_CCID_RDR_TO_PC_SLOT_STATUS_HEADER *)
131                                 runner -> ux_device_class_ccid_runner_response;
132 
133         /* Slot to handle.  */
134         slot  = ccid -> ux_device_class_ccid_slots;
135         slot += runner -> ux_device_class_ccid_runner_slot;
136 
137         /* Command settings.  */
138         cmd_sett  = (UX_DEVICE_CLASS_CCID_COMMAND_SETT *)_ux_device_class_ccid_command_sett;
139         cmd_sett += runner -> ux_device_class_ccid_runner_command_index;
140 
141         /* Message to pass to application.  */
142         messages.ux_device_class_ccid_messages_pc_to_rdr = (UCHAR *)cmd;
143         messages.ux_device_class_ccid_messages_rdr_to_pc = (UCHAR *)rsp;
144 
145         /* Internal checks.  */
146         cmd_checks  = (ULONG)cmd_sett -> ux_device_class_ccid_command_sett_flags;
147         cmd_checks &= (ULONG)slot -> ux_device_class_ccid_slot_flags;
148 
149         /* Check hardware error!  */
150         if (cmd_checks & UX_DEVICE_CLASS_CCID_FLAG_HW_ERROR)
151         {
152 
153             /* Response: (1,1,HW_ERROR).  */
154             rsp -> bStatus = UX_DEVICE_CLASS_CCID_SLOT_STATUS(1, 1);
155             rsp -> bError  = UX_DEVICE_CLASS_CCID_HW_ERROR;
156         }
157 
158         /* Check auto sequencing!  */
159         else if (cmd_checks & UX_DEVICE_CLASS_CCID_FLAG_AUTO_SEQUENCING)
160         {
161 
162             /* Response: (1,1,BUSY_WITH_AUTO_SEQUENCE).  */
163             rsp -> bStatus = UX_DEVICE_CLASS_CCID_SLOT_STATUS(1, 1);
164             rsp -> bError  = UX_DEVICE_CLASS_CCID_BUSY_WITH_AUTO_SEQUENCE;
165         }
166 
167         /* Process command, application can fill status.  */
168         else
169         {
170 
171             handles = (UX_DEVICE_CLASS_CCID_HANDLE *)parameter -> ux_device_class_ccid_handles;
172             handle = handles[(INT)cmd_sett -> ux_device_class_ccid_command_sett_handle_index];
173 
174             /* Initialize response length based on type.  */
175             switch(rsp -> bMessageType)
176             {
177             case UX_DEVICE_CLASS_CCID_RDR_TO_PC_DATA_RATE_AND_CLOCK_FREQ:
178 
179                 /* Length fixed to 10+8.  */
180                 messages.ux_device_class_ccid_messages_rdr_to_pc_length = 18;
181                 UX_DEVICE_CLASS_CCID_MESSAGE_LENGTH_SET(rsp, 8);
182                 break;
183 
184             case UX_DEVICE_CLASS_CCID_RDR_TO_PC_SLOT_STATUS:
185 
186                 /* Length fixed to 10.  */
187                 messages.ux_device_class_ccid_messages_rdr_to_pc_length =
188                                     UX_DEVICE_CLASS_CCID_MESSAGE_HEADER_LENGTH;
189                 break;
190 
191             default:
192 
193                 /* There is possible data, set length to max transfer length.  */
194                 messages.ux_device_class_ccid_messages_rdr_to_pc_length =
195                         parameter -> ux_device_class_ccid_max_transfer_length;
196                 break;
197             }
198 
199             /* Invoke application callback.  */
200             status = handle(cmd -> bSlot, &messages);
201 
202             /* Save application status updates.  */
203 
204             /* Save bmICCStatus.  */
205             slot -> ux_device_class_ccid_slot_icc_status = rsp->bStatus &
206                                     UX_DEVICE_CLASS_CCID_SLOT_STATUS_ICC_MASK;
207 
208             /* Save bClockStatus.  */
209             slot -> ux_device_class_ccid_slot_clock_status = rsp->bClockStatus;
210         }
211 
212         /* If failed (aborted), no response.  */
213         if (status != UX_SUCCESS)
214             continue;
215         if (slot -> ux_device_class_ccid_slot_aborting)
216             continue;
217 
218         /* Send response.  */
219         _ux_device_class_ccid_response(ccid, (UCHAR *)rsp,
220                     messages.ux_device_class_ccid_messages_rdr_to_pc_length);
221 
222         _ux_device_class_ccid_lock(ccid);
223 
224         /* Free runner.  */
225         runner -> ux_device_class_ccid_runner_slot = -1;
226         ccid -> ux_device_class_ccid_n_busy --;
227 
228         /* Clear slot busy.  */
229         slot -> ux_device_class_ccid_slot_runner = -1;
230 
231         _ux_device_class_ccid_unlock(ccid);
232     }
233 }
234 #endif
235