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 
28 #if !defined(UX_DEVICE_STANDALONE)
29 #include "ux_device_class_ccid.h"
30 #include "ux_device_stack.h"
31 
32 
33 /**************************************************************************/
34 /*                                                                        */
35 /*  FUNCTION                                               RELEASE        */
36 /*                                                                        */
37 /*    _ux_device_class_ccid_notify_thread_entry           PORTABLE C      */
38 /*                                                           6.2.1        */
39 /*  AUTHOR                                                                */
40 /*                                                                        */
41 /*    Chaoqiong Xiao, Microsoft Corporation                               */
42 /*                                                                        */
43 /*  DESCRIPTION                                                           */
44 /*                                                                        */
45 /*    This function is the thread of the CCID interrupt IN endpoint. It   */
46 /*    is waiting for the application event to start interrupt IN.         */
47 /*                                                                        */
48 /*  INPUT                                                                 */
49 /*                                                                        */
50 /*    ccid_inst                             Address of ccid class         */
51 /*                                            container (32-bit)          */
52 /*                                                                        */
53 /*  OUTPUT                                                                */
54 /*                                                                        */
55 /*    None                                                                */
56 /*                                                                        */
57 /*  CALLS                                                                 */
58 /*                                                                        */
59 /*    _ux_device_stack_transfer_request     Request transfer              */
60 /*                                                                        */
61 /*  CALLED BY                                                             */
62 /*                                                                        */
63 /*    ThreadX                                                             */
64 /*                                                                        */
65 /*  RELEASE HISTORY                                                       */
66 /*                                                                        */
67 /*    DATE              NAME                      DESCRIPTION             */
68 /*                                                                        */
69 /*  04-25-2022     Chaoqiong Xiao           Initial Version 6.1.11        */
70 /*  03-08-2023     Chaoqiong Xiao           Modified comment(s),          */
71 /*                                            added standalone support,   */
72 /*                                            resulting in version 6.2.1  */
73 /*                                                                        */
74 /**************************************************************************/
_ux_device_class_ccid_notify_thread_entry(ULONG ccid_inst)75 VOID  _ux_device_class_ccid_notify_thread_entry(ULONG ccid_inst)
76 {
77 
78 UX_SLAVE_DEVICE                                     *device;
79 UX_DEVICE_CLASS_CCID                                *ccid;
80 UX_DEVICE_CLASS_CCID_SLOT                           *slot;
81 UX_DEVICE_CLASS_CCID_PARAMETER                      *parameter;
82 UX_SLAVE_ENDPOINT                                   *endpoint;
83 UX_SLAVE_TRANSFER                                   *transfer;
84 UCHAR                                               *buffer;
85 ULONG                                               length;
86 INT                                                 i;
87 UCHAR                                               icc_mask;
88 UINT                                                byte_pos, bits_pos;
89 UINT                                                status;
90 
91     /* Cast properly the ccid instance.  */
92     UX_THREAD_EXTENSION_PTR_GET(ccid, UX_DEVICE_CLASS_CCID, ccid_inst)
93 
94     /* Get the pointer to the device.  */
95     device =  &_ux_system_slave -> ux_system_slave_device;
96 
97     /* This thread runs forever but can be suspended or resumed by the user application.  */
98     status = UX_SUCCESS;
99     while(1)
100     {
101 
102         /* Error cases.  */
103         if (status != UX_SUCCESS)
104         {
105 
106             /* We need to suspend ourselves. We will be resumed by the
107                application if needed.  */
108             _ux_utility_thread_suspend(&ccid -> ux_device_class_ccid_notify_thread);
109             status = UX_SUCCESS;
110             continue;
111         }
112         status = UX_ERROR;
113 
114         /* Check device state.  */
115         if (device -> ux_slave_device_state != UX_DEVICE_CONFIGURED)
116             continue;
117 
118         /* Check endpoint.  */
119         endpoint = ccid -> ux_device_class_ccid_endpoint_notify;
120         if (endpoint == UX_NULL)
121             continue;
122         transfer = &endpoint -> ux_slave_endpoint_transfer_request;
123 
124         /* Wait event.  */
125         status = _ux_utility_semaphore_get(&ccid -> ux_device_class_ccid_notify_semaphore,
126                                            UX_WAIT_FOREVER);
127         if (status != UX_SUCCESS)
128             continue;
129 
130         /* Build slot change/hardware error message.  */
131         buffer = transfer -> ux_slave_transfer_request_data_pointer;
132         length = 0;
133 
134         /* By default no message.  */
135         buffer[UX_DEVICE_CLASS_CCID_OFFSET_MESSAGE_TYPE] = 0;
136 
137         /* Build slot hardware error message.  */
138         parameter = &ccid -> ux_device_class_ccid_parameter;
139 
140         _ux_device_class_ccid_lock(ccid);
141 
142         slot = ccid -> ux_device_class_ccid_slots;
143         for (i = 0; i < parameter -> ux_device_class_ccid_max_n_slots; i ++)
144         {
145 
146             /* Check if there is hardware error notification.  */
147             if (slot -> ux_device_class_ccid_slot_flags &
148                 UX_DEVICE_CLASS_CCID_FLAG_NOTIFY_HW_ERROR)
149             {
150                 slot -> ux_device_class_ccid_slot_flags &=
151                                 (UCHAR)~UX_DEVICE_CLASS_CCID_FLAG_NOTIFY_HW_ERROR;
152                 buffer[UX_DEVICE_CLASS_CCID_OFFSET_MESSAGE_TYPE] =
153                                 UX_DEVICE_CLASS_CCID_RDR_TO_PC_HARDWARE_ERROR;
154                 buffer[UX_DEVICE_CLASS_CCID_OFFSET_HW_ERROR_SLOT] = (UCHAR)i;
155                 buffer[UX_DEVICE_CLASS_CCID_OFFSET_HW_ERROR_SEQ] =
156                                 slot -> ux_device_class_ccid_slot_hw_error_seq;
157                 buffer[UX_DEVICE_CLASS_CCID_OFFSET_HW_ERROR_CODE] =
158                                 slot -> ux_device_class_ccid_slot_hw_error;
159                 length = 4;
160                 break;
161             }
162 
163             /* Next slot.  */
164             slot ++;
165         }
166 
167         /* Build slot changes message.  */
168         if (buffer[UX_DEVICE_CLASS_CCID_OFFSET_MESSAGE_TYPE] == 0)
169         {
170 
171             /* Scan slots.  */
172             slot = ccid -> ux_device_class_ccid_slots;
173             for (i = 0, byte_pos = 1; ; byte_pos ++)
174             {
175                 /* Reset bits.  */
176                 buffer[byte_pos] = 0;
177 
178                 /* Scan 4 slots.  */
179                 for(bits_pos = 0; bits_pos < 8; bits_pos += 2)
180                 {
181 
182                     /* Slot state bit.  */
183                     icc_mask = (UCHAR)((slot -> ux_device_class_ccid_slot_icc_status ==
184                             UX_DEVICE_CLASS_CCID_SLOT_STATUS_ICC_NOT_PRESENT) ?
185                             0u : 1u);
186 
187                     /* Check if there is change notification.  */
188                     if (slot -> ux_device_class_ccid_slot_flags &
189                         UX_DEVICE_CLASS_CCID_FLAG_NOTIFY_CHANGE)
190                     {
191                         slot -> ux_device_class_ccid_slot_flags &=
192                                     (UCHAR)~UX_DEVICE_CLASS_CCID_FLAG_NOTIFY_CHANGE;
193 
194                         /* Message type.  */
195                         buffer[UX_DEVICE_CLASS_CCID_OFFSET_MESSAGE_TYPE] =
196                             UX_DEVICE_CLASS_CCID_RDR_TO_PC_NOTIFY_SLOT_CHANGE;
197 
198                         /* Slot change bit.  */
199                         icc_mask |= (UCHAR)0x02u;
200                     }
201 
202                     /* Modify bits.  */
203                     buffer[byte_pos] |= (UCHAR)(icc_mask << bits_pos);
204 
205                     /* Next slot.  */
206                     i ++;
207                     if (i >= parameter -> ux_device_class_ccid_max_n_slots)
208                         break;
209                     slot ++;
210                 }
211                 if (i >= parameter -> ux_device_class_ccid_max_n_slots)
212                     break;
213             }
214 
215             /* Buffer length should include last byte.  */
216             length = byte_pos + 1;
217         }
218 
219         _ux_device_class_ccid_unlock(ccid);
220 
221         /* Check message to see if there is message to send.  */
222         if (buffer[UX_DEVICE_CLASS_CCID_OFFSET_MESSAGE_TYPE] == 0)
223             continue;
224 
225         /* Send request.  */
226         status = _ux_device_stack_transfer_request(transfer, length, length);
227     }
228 }
229 #endif
230