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