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