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 /** USBX Component */
14 /** */
15 /** Device CCID Class */
16 /** */
17 /**************************************************************************/
18 /**************************************************************************/
19
20 #define UX_SOURCE_CODE
21
22
23 /* Include necessary system files. */
24
25 #include "ux_api.h"
26 #include "ux_device_class_ccid.h"
27 #include "ux_device_stack.h"
28
29
30 /**************************************************************************/
31 /* */
32 /* FUNCTION RELEASE */
33 /* */
34 /* _ux_device_class_ccid_initialize PORTABLE C */
35 /* 6.3.0 */
36 /* AUTHOR */
37 /* */
38 /* Chaoqiong Xiao, Microsoft Corporation */
39 /* */
40 /* DESCRIPTION */
41 /* */
42 /* This function initializes the USB CCID device. */
43 /* */
44 /* INPUT */
45 /* */
46 /* command Pointer to ccid command */
47 /* */
48 /* OUTPUT */
49 /* */
50 /* Completion Status */
51 /* */
52 /* CALLS */
53 /* */
54 /* _ux_utility_memory_allocate Allocate memory */
55 /* _ux_utility_memory_free Free memory */
56 /* _ux_utility_semaphore_create Create semaphore */
57 /* _ux_utility_semaphore_delete Delete semaphore */
58 /* _ux_utility_mutex_create Create mutex */
59 /* _ux_device_mutex_delete Delete mutex */
60 /* _ux_utility_thread_create Create thread */
61 /* _ux_utility_thread_delete Delete thread */
62 /* _ux_utility_event_flags_create Create event flags */
63 /* _ux_utility_event_flags_delete Delete event flags */
64 /* */
65 /* CALLED BY */
66 /* */
67 /* USBX Source Code */
68 /* */
69 /* RELEASE HISTORY */
70 /* */
71 /* DATE NAME DESCRIPTION */
72 /* */
73 /* 04-25-2022 Chaoqiong Xiao Initial Version 6.1.11 */
74 /* 03-08-2023 Chaoqiong Xiao Modified comment(s), */
75 /* added standalone support, */
76 /* resulting in version 6.2.1 */
77 /* 10-31-2023 Chaoqiong Xiao Modified comment(s), */
78 /* added a new mode to manage */
79 /* endpoint buffer in classes, */
80 /* resulting in version 6.3.0 */
81 /* */
82 /**************************************************************************/
_ux_device_class_ccid_initialize(UX_SLAVE_CLASS_COMMAND * command)83 UINT _ux_device_class_ccid_initialize(UX_SLAVE_CLASS_COMMAND *command)
84 {
85 UX_DEVICE_CLASS_CCID *ccid;
86 UX_DEVICE_CLASS_CCID_RUNNER *runner;
87 UX_DEVICE_CLASS_CCID_SLOT *slot;
88 UX_DEVICE_CLASS_CCID_PARAMETER *ccid_parameter;
89 UX_SLAVE_CLASS *ccid_class;
90 UINT status;
91 ULONG memory_size;
92 ULONG ccid_size, runners_size, slots_size;
93 ULONG buffer_size, buffers_size;
94 UCHAR *memory;
95 ULONG i;
96 #if !defined(UX_DEVICE_STANDALONE)
97 ULONG stacks_size;
98 #endif
99
100 /* Get the class container. */
101 ccid_class = command -> ux_slave_class_command_class_ptr;
102
103 /* Get the pointer to the application parameters for the ccid class. */
104 ccid_parameter = command -> ux_slave_class_command_parameter;
105
106 /* Sanity check for parameters.
107 - number slots < 32
108 - number busy <= number slots
109 - message length < max request buffer size
110 */
111
112 #if !defined(UX_DEVICE_STANDALONE)
113
114 UX_ASSERT(ccid_parameter -> ux_device_class_ccid_max_n_slots <= UX_DEVICE_CLASS_CCID_MAX_N_SLOTS);
115 UX_ASSERT(ccid_parameter -> ux_device_class_ccid_max_n_busy_slots != 0);
116 UX_ASSERT(ccid_parameter -> ux_device_class_ccid_max_n_busy_slots <=
117 ccid_parameter -> ux_device_class_ccid_max_n_slots)
118 #else
119
120 /* To optimize only support 1 slot. */
121 ccid_parameter -> ux_device_class_ccid_max_n_slots = 1;
122 ccid_parameter -> ux_device_class_ccid_max_n_busy_slots = 1;
123 #endif
124
125 UX_ASSERT(ccid_parameter -> ux_device_class_ccid_max_transfer_length <=
126 UX_DEVICE_CLASS_CCID_BULK_BUFFER_SIZE);
127 UX_ASSERT(ccid_parameter->ux_device_class_ccid_handles != UX_NULL);
128
129 /* Calculate size for instance (structures already aligned). */
130 /* Max n_slots 32, considering struct size, no overflow case. */
131 ccid_size = sizeof(UX_DEVICE_CLASS_CCID);
132 memory_size = ccid_size;
133
134 runners_size = sizeof(UX_DEVICE_CLASS_CCID_RUNNER);
135 runners_size *= ccid_parameter->ux_device_class_ccid_max_n_busy_slots;
136 memory_size += runners_size;
137
138 slots_size = sizeof(UX_DEVICE_CLASS_CCID_SLOT);
139 slots_size *= ccid_parameter->ux_device_class_ccid_max_n_slots;
140 memory_size += slots_size;
141
142 buffer_size = ccid_parameter->ux_device_class_ccid_max_transfer_length;
143 buffer_size += 3u;
144 buffer_size &= ~3u;
145 ccid_parameter->ux_device_class_ccid_max_transfer_length = buffer_size;
146 if (UX_OVERFLOW_CHECK_MULC_ULONG(buffer_size, 2))
147 {
148
149 /* Error trap. */
150 _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_ERROR);
151 return(UX_ERROR);
152 }
153 buffers_size = (buffer_size << 1) & 0xFFFFFFFFu;
154 if (UX_OVERFLOW_CHECK_MULV_ULONG(buffers_size, ccid_parameter->ux_device_class_ccid_max_n_busy_slots))
155 {
156
157 /* Error trap. */
158 _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_ERROR);
159 return(UX_ERROR);
160 }
161 buffers_size = (buffers_size * ccid_parameter->ux_device_class_ccid_max_n_busy_slots) & 0xFFFFFFFFu;
162 if (UX_OVERFLOW_CHECK_ADD_ULONG(memory_size, buffer_size))
163 {
164
165 /* Error trap. */
166 _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_ERROR);
167 return(UX_ERROR);
168 }
169 memory_size = (memory_size + buffers_size) & 0xFFFFFFFFu;
170
171 #if !defined(UX_DEVICE_STANDALONE)
172
173 /* Calculate memory size for stackes. */
174 stacks_size = ccid_parameter->ux_device_class_ccid_max_n_busy_slots;
175 if (UX_OVERFLOW_CHECK_MULC_ULONG(stacks_size, UX_DEVICE_CLASS_CCID_RUNNER_THREAD_STACK_SIZE))
176 {
177
178 /* Error trap. */
179 _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_ERROR);
180 return(UX_ERROR);
181 }
182 stacks_size *= UX_DEVICE_CLASS_CCID_RUNNER_THREAD_STACK_SIZE;
183 if (UX_OVERFLOW_CHECK_ADD_ULONG(stacks_size, UX_DEVICE_CLASS_CCID_THREAD_STACK_SIZE))
184 {
185
186 /* Error trap. */
187 _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_ERROR);
188 return(UX_ERROR);
189 }
190 stacks_size += UX_DEVICE_CLASS_CCID_THREAD_STACK_SIZE;
191 if (UX_OVERFLOW_CHECK_ADD_ULONG(stacks_size, UX_DEVICE_CLASS_CCID_NOTIFY_THREAD_STACK_SIZE))
192 {
193
194 /* Error trap. */
195 _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_ERROR);
196 return(UX_ERROR);
197 }
198 stacks_size += UX_DEVICE_CLASS_CCID_NOTIFY_THREAD_STACK_SIZE;
199 if (UX_OVERFLOW_CHECK_ADD_ULONG(memory_size, stacks_size))
200 {
201
202 /* Error trap. */
203 _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_ERROR);
204 return(UX_ERROR);
205 }
206 memory_size = (memory_size + stacks_size) & 0xFFFFFFFFu;
207 #endif
208
209 /* Allocate memory for instance and other resources of the device ccid class. */
210 memory = _ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, memory_size);
211
212 /* Check for successful allocation. */
213 if (memory == UX_NULL)
214 return(UX_MEMORY_INSUFFICIENT);
215
216 /* Create and save resources for ccid, runners, slots, buffers. */
217
218 /* CCID. */
219 ccid = (UX_DEVICE_CLASS_CCID *)memory;
220 memory += ccid_size;
221
222 #if !defined(UX_DEVICE_STANDALONE)
223
224 /* CCID thread. */
225 status = _ux_utility_thread_create(
226 &ccid -> ux_device_class_ccid_thread,
227 "ux_device_class_ccid_thread",
228 _ux_device_class_ccid_thread_entry,
229 (ULONG) (ALIGN_TYPE) ccid,
230 (VOID *) memory,
231 UX_DEVICE_CLASS_CCID_THREAD_STACK_SIZE, UX_THREAD_PRIORITY_CLASS,
232 UX_THREAD_PRIORITY_CLASS, UX_NO_TIME_SLICE, UX_DONT_START);
233 if (status != UX_SUCCESS)
234 status = UX_THREAD_ERROR;
235 else
236 {
237 ccid -> ux_device_class_ccid_thread_stack = memory;
238 memory += UX_DEVICE_CLASS_CCID_THREAD_STACK_SIZE;
239 UX_THREAD_EXTENSION_PTR_SET(&(ccid -> ux_device_class_ccid_thread), ccid);
240 }
241
242 /* CCID Notify thread. */
243 if (status == UX_SUCCESS)
244 {
245 status = _ux_utility_thread_create(
246 &ccid -> ux_device_class_ccid_notify_thread,
247 "ux_device_class_ccid_notify_thread",
248 _ux_device_class_ccid_notify_thread_entry,
249 (ULONG) (ALIGN_TYPE) ccid,
250 (VOID *) memory,
251 UX_DEVICE_CLASS_CCID_NOTIFY_THREAD_STACK_SIZE, UX_THREAD_PRIORITY_CLASS,
252 UX_THREAD_PRIORITY_CLASS, UX_NO_TIME_SLICE, UX_DONT_START);
253 if (status != UX_SUCCESS)
254 status = UX_THREAD_ERROR;
255 else
256 {
257 ccid -> ux_device_class_ccid_notify_thread_stack = memory;
258 memory += UX_DEVICE_CLASS_CCID_NOTIFY_THREAD_STACK_SIZE;
259 UX_THREAD_EXTENSION_PTR_SET(&(ccid -> ux_device_class_ccid_notify_thread), ccid);
260 }
261 }
262 #else
263
264 /* Set task function. */
265 ccid_class -> ux_slave_class_task_function = _ux_device_class_ccid_tasks_run;
266
267 /* By default status is OK. */
268 status = UX_SUCCESS;
269 #endif
270
271 /* CCID runners. */
272 if (status == UX_SUCCESS)
273 {
274
275 ccid -> ux_device_class_ccid_runners = (UX_DEVICE_CLASS_CCID_RUNNER *)memory;
276 memory += runners_size;
277
278 runner = ccid -> ux_device_class_ccid_runners;
279 for (i = 0; i < ccid_parameter -> ux_device_class_ccid_max_n_busy_slots; i ++)
280 {
281
282 /* Save CCID for runner. */
283 runner -> ux_device_class_ccid_runner_ccid = ccid;
284
285 /* Save runner ID. */
286 runner -> ux_device_class_ccid_runner_id = (CHAR)i;
287
288 /* Runner is free. */
289 runner -> ux_device_class_ccid_runner_slot = -1;
290
291 /* Runner command buffer. */
292 runner -> ux_device_class_ccid_runner_command = memory;
293 memory += buffer_size;
294
295 /* Runner response buffer. */
296 runner -> ux_device_class_ccid_runner_response = memory;
297 memory += buffer_size;
298
299 #if !defined(UX_DEVICE_STANDALONE)
300
301 /* CCID runners threads. */
302 status = _ux_utility_thread_create(
303 &runner -> ux_device_class_ccid_runner_thread,
304 "ux_device_class_ccid_runner_thread",
305 _ux_device_class_ccid_runner_thread_entry,
306 (ULONG) (ALIGN_TYPE) runner,
307 (VOID *)memory,
308 UX_DEVICE_CLASS_CCID_RUNNER_THREAD_STACK_SIZE, UX_THREAD_PRIORITY_CLASS,
309 UX_THREAD_PRIORITY_CLASS, UX_NO_TIME_SLICE, UX_DONT_START);
310 if (status != UX_SUCCESS)
311 {
312 status = UX_THREAD_ERROR;
313 break;
314 }
315 else
316 {
317 runner -> ux_device_class_ccid_runner_thread_stack = memory;
318 memory += UX_DEVICE_CLASS_CCID_RUNNER_THREAD_STACK_SIZE;
319 UX_THREAD_EXTENSION_PTR_SET(&(runner -> ux_device_class_ccid_runner_thread), runner);
320 }
321 #endif
322
323 /* Next runner. */
324 runner ++;
325 }
326 }
327
328 /* CCID slots. */
329 if (status == UX_SUCCESS)
330 {
331
332 ccid -> ux_device_class_ccid_slots = (UX_DEVICE_CLASS_CCID_SLOT *)memory;
333
334 slot = ccid -> ux_device_class_ccid_slots;
335 for (i = 0; i < ccid_parameter -> ux_device_class_ccid_max_n_slots; i ++)
336 {
337
338 /* Slot not busy. */
339 slot -> ux_device_class_ccid_slot_runner = -1;
340
341 /* Slot ICC no card. */
342 slot -> ux_device_class_ccid_slot_icc_status = UX_DEVICE_CLASS_CCID_ICC_NOT_PRESENT;
343
344 /* Next slot. */
345 slot ++;
346 }
347 }
348
349 #if UX_DEVICE_ENDPOINT_BUFFER_OWNER == 1
350
351 /* Create endpoint buffers. */
352 UX_ASSERT(!UX_DEVICE_CLASS_CCID_ENDPOINT_BUFFER_SIZE_CALC_OVERFLOW);
353 ccid -> ux_device_class_ccid_endpoint_buffer = _ux_utility_memory_allocate(UX_NO_ALIGN,
354 UX_CACHE_SAFE_MEMORY, UX_DEVICE_CLASS_CCID_INTERRUPT_BUFFER_SIZE + UX_DEVICE_CLASS_CCID_BULK_BUFFER_SIZE * 2);
355 if (ccid -> ux_device_class_ccid_endpoint_buffer == UX_NULL)
356 status = UX_MEMORY_INSUFFICIENT;
357 #endif
358
359 #if !defined(UX_DEVICE_STANDALONE)
360
361 /* CCID mutexes, semaphore and event flags. */
362 if (status == UX_SUCCESS)
363 {
364
365 /* Create Event Flags. */
366 status = _ux_utility_event_flags_create(&ccid -> ux_device_class_ccid_events,
367 "ux_device_class_ccid_events");
368 if (status == UX_SUCCESS)
369 {
370
371 /* Bulk IN mutex. */
372 status = _ux_utility_mutex_create(&ccid -> ux_device_class_ccid_response_mutex,
373 "ux_device_class_ccid_response_mutex");
374 if (status == UX_SUCCESS)
375 {
376
377 /* Interrupt IN semaphore. */
378 status = _ux_utility_semaphore_create(&ccid -> ux_device_class_ccid_notify_semaphore,
379 "ux_device_class_ccid_notify_semaphore", 0);
380 if (status == UX_SUCCESS)
381 {
382
383 /* Resource access Mutex. */
384 status = _ux_utility_mutex_create(&ccid -> ux_device_class_ccid_mutex,
385 "ux_device_class_ccid_mutex");
386 if (status != UX_SUCCESS)
387 status = UX_MUTEX_ERROR;
388
389 /* If there is error, allocated semaphore should be deleted. */
390 if (status != UX_SUCCESS)
391 _ux_utility_semaphore_delete(&ccid -> ux_device_class_ccid_notify_semaphore);
392 }
393 else
394 status = UX_MUTEX_ERROR;
395
396 /* If there is error, allocated mutex should be deleted. */
397 if (status != UX_SUCCESS)
398 _ux_device_mutex_delete(&ccid -> ux_device_class_ccid_response_mutex);
399 }
400 else
401 status = UX_MUTEX_ERROR;
402
403 /* If there is error, allocated event should be deleted. */
404 if (status != UX_SUCCESS)
405 _ux_utility_event_flags_delete(&ccid -> ux_device_class_ccid_events);
406 }
407 else
408 status = UX_EVENT_ERROR;
409 }
410 #endif
411
412 /* Success case. */
413 if (status == UX_SUCCESS)
414 {
415
416 /* Save the address of the CDC instance inside the CDC container. */
417 ccid_class -> ux_slave_class_instance = (VOID *) ccid;
418
419 /* Store parameters. */
420 _ux_utility_memory_copy(&ccid -> ux_device_class_ccid_parameter, ccid_parameter,
421 sizeof(UX_DEVICE_CLASS_CCID_PARAMETER)); /* Use case of memcpy is verified. */
422
423 /* Return success status. */
424 return(UX_SUCCESS);
425 }
426
427 /* Error cases. */
428
429 /* In this case, mutexes and events are not created or has been handled. */
430
431 #if !defined(UX_DEVICE_STANDALONE)
432
433 /* Check thread states and free them. */
434 if (ccid -> ux_device_class_ccid_thread_stack)
435 _ux_utility_thread_delete(&ccid -> ux_device_class_ccid_thread);
436 for (i = 0; i < ccid_parameter -> ux_device_class_ccid_max_n_busy_slots; i ++)
437 {
438 runner = &ccid -> ux_device_class_ccid_runners[i];
439 if (runner -> ux_device_class_ccid_runner_thread_stack)
440 _ux_utility_thread_delete(&runner -> ux_device_class_ccid_runner_thread);
441 }
442 if (ccid -> ux_device_class_ccid_notify_thread_stack)
443 _ux_utility_thread_delete(&ccid -> ux_device_class_ccid_notify_thread);
444 #endif
445
446 #if UX_DEVICE_ENDPOINT_BUFFER_OWNER == 1
447
448 /* Free the endpoint buffers. */
449 if (ccid -> ux_device_class_ccid_endpoint_buffer)
450 _ux_utility_memory_free(ccid -> ux_device_class_ccid_endpoint_buffer);
451 #endif
452
453 /* Free the memory. */
454 _ux_utility_memory_free(ccid);
455
456 /* Return completion status. */
457 return(status);
458 }
459
460 const UX_DEVICE_CLASS_CCID_COMMAND_SETT
461 _ux_device_class_ccid_command_sett[UX_DEVICE_CLASS_CCID_N_COMMANDS + 1] =
462 {
463 {0x62, UX_DEVICE_CLASS_CCID_COMMAND_RESP_TYPE(0x62),
464 UX_DEVICE_CLASS_CCID_COMMAND_FLAGS(0x62), 0},
465 {0x63, UX_DEVICE_CLASS_CCID_COMMAND_RESP_TYPE(0x63),
466 UX_DEVICE_CLASS_CCID_COMMAND_FLAGS(0x63), 1},
467 {0x65, UX_DEVICE_CLASS_CCID_COMMAND_RESP_TYPE(0x65),
468 UX_DEVICE_CLASS_CCID_COMMAND_FLAGS(0x65), 2},
469 {0x6F, UX_DEVICE_CLASS_CCID_COMMAND_RESP_TYPE(0x6F),
470 UX_DEVICE_CLASS_CCID_COMMAND_FLAGS(0x6F), 3},
471 {0x6C, UX_DEVICE_CLASS_CCID_COMMAND_RESP_TYPE(0x6C),
472 UX_DEVICE_CLASS_CCID_COMMAND_FLAGS(0x6C), 4},
473 {0x6D, UX_DEVICE_CLASS_CCID_COMMAND_RESP_TYPE(0x6D),
474 UX_DEVICE_CLASS_CCID_COMMAND_FLAGS(0x6D), 5},
475 {0x61, UX_DEVICE_CLASS_CCID_COMMAND_RESP_TYPE(0x61),
476 UX_DEVICE_CLASS_CCID_COMMAND_FLAGS(0x61), 6},
477 {0x6B, UX_DEVICE_CLASS_CCID_COMMAND_RESP_TYPE(0x6B),
478 UX_DEVICE_CLASS_CCID_COMMAND_FLAGS(0x6B), 7},
479 {0x6E, UX_DEVICE_CLASS_CCID_COMMAND_RESP_TYPE(0x6E),
480 UX_DEVICE_CLASS_CCID_COMMAND_FLAGS(0x6E), 8},
481 {0x6A, UX_DEVICE_CLASS_CCID_COMMAND_RESP_TYPE(0x6A),
482 UX_DEVICE_CLASS_CCID_COMMAND_FLAGS(0x6A), 9},
483 {0x69, UX_DEVICE_CLASS_CCID_COMMAND_RESP_TYPE(0x69),
484 UX_DEVICE_CLASS_CCID_COMMAND_FLAGS(0x69), 10},
485 {0x71, UX_DEVICE_CLASS_CCID_COMMAND_RESP_TYPE(0x71),
486 UX_DEVICE_CLASS_CCID_COMMAND_FLAGS(0x71), 11},
487 {0x72, UX_DEVICE_CLASS_CCID_COMMAND_RESP_TYPE(0x72),
488 UX_DEVICE_CLASS_CCID_COMMAND_FLAGS(0x72), 12},
489 {0x73, UX_DEVICE_CLASS_CCID_COMMAND_RESP_TYPE(0x73),
490 UX_DEVICE_CLASS_CCID_COMMAND_FLAGS(0x73), 13},
491 {0, 0, 0, -1}, /* Command not supported. */
492 };
493