1 /*
2  * Copyright (c) 2015, Freescale Semiconductor, Inc.
3  * Copyright 2016 NXP
4  * All rights reserved.
5  *
6  * SPDX-License-Identifier: BSD-3-Clause
7  */
8 
9 #include "usb_device_config.h"
10 #include "usb.h"
11 #include "usb_device.h"
12 
13 #include "usb_device_class.h"
14 
15 #if ((defined(USB_DEVICE_CONFIG_CCID)) && (USB_DEVICE_CONFIG_CCID > 0U))
16 #include "usb_device_ccid.h"
17 
18 /*******************************************************************************
19  * Definitions
20  ******************************************************************************/
21 
22 /*******************************************************************************
23  * Prototypes
24  ******************************************************************************/
25 
26 static usb_status_t USB_DeviceCcidAllocateHandle(usb_device_ccid_struct_t **handle);
27 static usb_status_t USB_DeviceCcidFreeHandle(usb_device_ccid_struct_t *handle);
28 static usb_status_t USB_DeviceCcidRemoveTransfer(usb_device_ccid_transfer_struct_t **transfer_queue,
29                                                  usb_device_ccid_transfer_struct_t **transfer);
30 static usb_status_t USB_DeviceCcidAddTransfer(usb_device_ccid_transfer_struct_t **transfer_queue,
31                                               usb_device_ccid_transfer_struct_t *transfer);
32 static usb_status_t USB_DeviceCcidInterruptIn(usb_device_handle deviceHandle,
33                                               usb_device_endpoint_callback_message_struct_t *event,
34                                               void *callbackParam);
35 static usb_status_t USB_DeviceCcidBulkIn(usb_device_handle deviceHandle,
36                                          usb_device_endpoint_callback_message_struct_t *event,
37                                          void *callbackParam);
38 static usb_status_t USB_DeviceCcidBulkOut(usb_device_handle deviceHandle,
39                                           usb_device_endpoint_callback_message_struct_t *event,
40                                           void *callbackParam);
41 static usb_status_t USB_DeviceCcidEndpointsInit(usb_device_ccid_struct_t *ccidHandle);
42 static usb_status_t USB_DeviceCcidEndpointsDeinit(usb_device_ccid_struct_t *ccidHandle);
43 
44 /*******************************************************************************
45  * Variables
46  ******************************************************************************/
47 
USB_RAM_ADDRESS_ALIGNMENT(USB_DATA_ALIGN_SIZE)48 USB_GLOBAL USB_RAM_ADDRESS_ALIGNMENT(USB_DATA_ALIGN_SIZE) static usb_device_ccid_struct_t
49     s_UsbDeviceCcidHandle[USB_DEVICE_CONFIG_CCID];
50 
51 /*******************************************************************************
52  * API
53  ******************************************************************************/
54 
55 /*!
56  * @brief Allocate a device ccid class handle.
57  *
58  * This function allocates a device ccid class handle.
59  *
60  * @param handle          It is out parameter, is used to return pointer of the device ccid class handle to the caller.
61  *
62  * @retval kStatus_USB_Success              Get a device ccid class handle successfully.
63  * @retval kStatus_USB_Busy                 Cannot allocate a device ccid class handle.
64  */
65 static usb_status_t USB_DeviceCcidAllocateHandle(usb_device_ccid_struct_t **handle)
66 {
67     uint32_t count;
68     for (count = 0U; count < USB_DEVICE_CONFIG_CCID; count++)
69     {
70         if (NULL == s_UsbDeviceCcidHandle[count].handle)
71         {
72             *handle = &s_UsbDeviceCcidHandle[count];
73             return kStatus_USB_Success;
74         }
75     }
76 
77     return kStatus_USB_Busy;
78 }
79 
80 /*!
81  * @brief Free a device ccid class handle.
82  *
83  * This function frees a device ccid class handle.
84  *
85  * @param handle          The device ccid class handle.
86  *
87  * @retval kStatus_USB_Success              Free device ccid class handle successfully.
88  */
USB_DeviceCcidFreeHandle(usb_device_ccid_struct_t * handle)89 static usb_status_t USB_DeviceCcidFreeHandle(usb_device_ccid_struct_t *handle)
90 {
91     handle->handle        = NULL;
92     handle->configStruct  = (usb_device_class_config_struct_t *)NULL;
93     handle->configuration = 0U;
94     handle->alternate     = 0U;
95     return kStatus_USB_Success;
96 }
97 
98 /*!
99  * @brief Remove a transfer node from a queue.
100  *
101  * This function removes a transfer node from a queue.
102  *
103  * @param transfer_queue          A pointer points to a queue pointer.
104  * @param transfer                It is an OUT parameter, return the transfer node pointer.
105  *
106  * @retval kStatus_USB_Success              Free device ccid class handle successfully.
107  * @retval kStatus_USB_Busy                 Can not get transfer node due to the queue is empty.
108  */
USB_DeviceCcidRemoveTransfer(usb_device_ccid_transfer_struct_t ** transfer_queue,usb_device_ccid_transfer_struct_t ** transfer)109 static usb_status_t USB_DeviceCcidRemoveTransfer(usb_device_ccid_transfer_struct_t **transfer_queue,
110                                                  usb_device_ccid_transfer_struct_t **transfer)
111 {
112     OSA_SR_ALLOC();
113 
114     if ((NULL == transfer_queue) || (NULL == transfer))
115     {
116         return kStatus_USB_InvalidParameter;
117     }
118 
119     OSA_ENTER_CRITICAL();
120     *transfer = *transfer_queue;
121     if (NULL != *transfer_queue)
122     {
123         *transfer_queue = (*transfer_queue)->next;
124         OSA_EXIT_CRITICAL();
125         return kStatus_USB_Success;
126     }
127     OSA_EXIT_CRITICAL();
128     return kStatus_USB_Busy;
129 }
130 
131 /*!
132  * @brief Add a transfer node to a queue.
133  *
134  * This function adds a transfer node to a queue.
135  *
136  * @param transfer_queue          A pointer points to a queue pointer.
137  * @param transfer                The transfer node pointer.
138  *
139  * @retval kStatus_USB_Success              Free device ccid class handle successfully.
140  * @retval kStatus_USB_Error                The transfer node has been added.
141  */
USB_DeviceCcidAddTransfer(usb_device_ccid_transfer_struct_t ** transfer_queue,usb_device_ccid_transfer_struct_t * transfer)142 static usb_status_t USB_DeviceCcidAddTransfer(usb_device_ccid_transfer_struct_t **transfer_queue,
143                                               usb_device_ccid_transfer_struct_t *transfer)
144 {
145     usb_device_ccid_transfer_struct_t *p;
146     usb_device_ccid_transfer_struct_t *q;
147     OSA_SR_ALLOC();
148 
149     if (NULL == transfer_queue)
150     {
151         return kStatus_USB_InvalidParameter;
152     }
153     p = *transfer_queue;
154     q = *transfer_queue;
155 
156     OSA_ENTER_CRITICAL();
157     while (NULL != p)
158     {
159         q = p;
160         if (p == transfer)
161         {
162             OSA_EXIT_CRITICAL();
163             return kStatus_USB_Error;
164         }
165         p = p->next;
166     }
167     transfer->next = NULL;
168     if (NULL != q)
169     {
170         q->next = transfer;
171     }
172     else
173     {
174         *transfer_queue = transfer;
175     }
176     OSA_EXIT_CRITICAL();
177     return kStatus_USB_Success;
178 }
179 
180 /*!
181  * @brief Interrupt IN endpoint callback function.
182  *
183  * This callback function is used to notify uplayer the transfser result of a transfer.
184  * This callback pointer is passed when the interrupt IN pipe initialized.
185  *
186  * @param deviceHandle          The device handle. It equals the value returned from USB_DeviceInit.
187  * @param event                  The result of the interrupt IN pipe transfer.
188  * @param callbackParam         The parameter for this callback. It is same with
189  * usb_device_endpoint_callback_struct_t::callbackParam. In the class, the value is the ccid class handle.
190  *
191  * @return A USB error code or kStatus_USB_Success.
192  */
USB_DeviceCcidInterruptIn(usb_device_handle deviceHandle,usb_device_endpoint_callback_message_struct_t * event,void * callbackParam)193 static usb_status_t USB_DeviceCcidInterruptIn(usb_device_handle deviceHandle,
194                                               usb_device_endpoint_callback_message_struct_t *event,
195                                               void *callbackParam)
196 {
197     usb_device_ccid_struct_t *ccidHandle = (usb_device_ccid_struct_t *)callbackParam;
198     usb_device_ccid_notification_struct_t notification;
199     usb_status_t error = kStatus_USB_Success;
200     void *temp;
201     OSA_SR_ALLOC();
202 
203     if (((NULL == deviceHandle) || (NULL == callbackParam) || (NULL == event)) || (NULL == event->buffer))
204     {
205         return kStatus_USB_Error;
206     }
207 
208     /* Save the transed buffer address and length */
209     notification.buffer = event->buffer;
210     notification.length = event->length;
211     temp                = (void *)event->buffer;
212     usb_device_ccid_notify_slot_chnage_notification_t *ccidNotify =
213         (usb_device_ccid_notify_slot_chnage_notification_t *)temp;
214 
215     if (USB_DEVICE_CCID_RDR_TO_PC_NOTIFYSLOTCHANGE == ccidNotify->bMessageType)
216     {
217         if (NULL != ccidHandle->configStruct->classCallback)
218         {
219             /* Notify the up layer, the slot change notification sent.
220             classCallback is initialized in classInit of s_UsbDeviceClassInterfaceMap,
221             it is from the second parameter of classInit */
222 #if (defined(USB_DEVICE_CONFIG_RETURN_VALUE_CHECK) && (USB_DEVICE_CONFIG_RETURN_VALUE_CHECK > 0U))
223             if (kStatus_USB_Success != ccidHandle->configStruct->classCallback((class_handle_t)ccidHandle,
224                                                                                kUSB_DeviceCcidEventSlotChangeSent,
225                                                                                &notification))
226             {
227                 return kStatus_USB_Error;
228             }
229 #else
230             (void)ccidHandle->configStruct->classCallback((class_handle_t)ccidHandle,
231                                                           kUSB_DeviceCcidEventSlotChangeSent, &notification);
232 #endif
233         }
234     }
235     else if (USB_DEVICE_CCID_RDR_TO_PC_HARDWAREERROR == ccidNotify->bMessageType)
236     {
237         if (NULL != ccidHandle->configStruct->classCallback)
238         {
239             /* Notify the up layer, the hardware error notification sent.
240             classCallback is initialized in classInit of s_UsbDeviceClassInterfaceMap,
241             it is from the second parameter of classInit */
242 #if (defined(USB_DEVICE_CONFIG_RETURN_VALUE_CHECK) && (USB_DEVICE_CONFIG_RETURN_VALUE_CHECK > 0U))
243             if (kStatus_USB_Success != ccidHandle->configStruct->classCallback((class_handle_t)ccidHandle,
244                                                                                kUSB_DeviceCcidEventHardwareErrorSent,
245                                                                                &notification))
246             {
247                 return kStatus_USB_Error;
248             }
249 #else
250             (void)ccidHandle->configStruct->classCallback((class_handle_t)ccidHandle,
251                                                           kUSB_DeviceCcidEventHardwareErrorSent, &notification);
252 #endif
253         }
254     }
255     else
256     {
257         /*no action*/;
258     }
259     OSA_ENTER_CRITICAL();
260     if ((0U != ccidHandle->configuration) && (0U != ccidHandle->endpointInterruptIn))
261     {
262         /* If there is a blocking slot changed notification, send it to the host */
263         if (0U != ccidHandle->slotsChanged)
264         {
265             ccidHandle->slotsSendingChangeBuffer[0] = ccidHandle->slotsChangeBuffer[0];
266             for (uint8_t i = 1U; i < sizeof(ccidHandle->slotsChangeBuffer); i++)
267             {
268                 ccidHandle->slotsSendingChangeBuffer[i] = ccidHandle->slotsChangeBuffer[i];
269                 ccidHandle->slotsChangeBuffer[i] &= (uint8_t)(~0xAAU);
270             }
271             error = USB_DeviceSendRequest(ccidHandle->handle, ccidHandle->endpointInterruptIn,
272                                           ccidHandle->slotsSendingChangeBuffer,
273                                           sizeof(ccidHandle->slotsSendingChangeBuffer));
274             if (kStatus_USB_Success == error)
275             {
276                 ccidHandle->slotsChanged    = 0U;
277                 ccidHandle->interruptInBusy = 1U;
278             }
279             else
280             {
281                 ccidHandle->interruptInBusy = 0U;
282             }
283         }
284         else
285         {
286             ccidHandle->interruptInBusy = 0U;
287         }
288         error = kStatus_USB_Success;
289     }
290     OSA_EXIT_CRITICAL();
291     return error;
292 }
293 
294 /*!
295  * @brief Bulk IN endpoint callback function.
296  *
297  * This callback function is used to notify uplayer the transfser result of a transfer.
298  * This callback pointer is passed when the Bulk IN pipe initialized.
299  *
300  * @param deviceHandle   The device handle. It equals the value returned from USB_DeviceInit.
301  * @param event           The result of the Bulk IN pipe transfer.
302  * @param callbackParam  The parameter for this callback. It is same with
303  * usb_device_endpoint_callback_struct_t::callbackParam. In the class, the value is the ccid class handle.
304  *
305  * @return A USB error code or kStatus_USB_Success.
306  */
USB_DeviceCcidBulkIn(usb_device_handle deviceHandle,usb_device_endpoint_callback_message_struct_t * event,void * callbackParam)307 static usb_status_t USB_DeviceCcidBulkIn(usb_device_handle deviceHandle,
308                                          usb_device_endpoint_callback_message_struct_t *event,
309                                          void *callbackParam)
310 {
311     usb_device_ccid_struct_t *ccidHandle = (usb_device_ccid_struct_t *)callbackParam;
312     usb_device_ccid_transfer_struct_t *transfer;
313     usb_status_t error = kStatus_USB_Error;
314 
315     /* endpoint callback length is USB_CANCELLED_TRANSFER_LENGTH (0xFFFFFFFFU) when transfer is canceled */
316     if (((NULL == deviceHandle) || (NULL == callbackParam) || (NULL == event)) || (NULL == event->buffer) ||
317         (USB_CANCELLED_TRANSFER_LENGTH == event->length))
318     {
319         return kStatus_USB_Error;
320     }
321 
322     /* Remove the transed transfer from the busy queue. */
323     if (kStatus_USB_Success == USB_DeviceCcidRemoveTransfer(&ccidHandle->transferHead, &transfer))
324     {
325         if (NULL != ccidHandle->configStruct->classCallback)
326         {
327             /* Notify the up layer, the response sent.
328             classCallback is initialized in classInit of s_UsbDeviceClassInterfaceMap,
329             it is from the second parameter of classInit */
330 #if (defined(USB_DEVICE_CONFIG_RETURN_VALUE_CHECK) && (USB_DEVICE_CONFIG_RETURN_VALUE_CHECK > 0U))
331             if (kStatus_USB_Success != ccidHandle->configStruct->classCallback((class_handle_t)ccidHandle,
332                                                                                kUSB_DeviceCcidEventResponseSent,
333                                                                                transfer->buffer))
334             {
335                 return kStatus_USB_Error;
336             }
337 #else
338             (void)ccidHandle->configStruct->classCallback((class_handle_t)ccidHandle, kUSB_DeviceCcidEventResponseSent,
339                                                           transfer->buffer);
340 #endif
341         }
342         /* Add the transfer node to the idle queue */
343 #if (defined(USB_DEVICE_CONFIG_RETURN_VALUE_CHECK) && (USB_DEVICE_CONFIG_RETURN_VALUE_CHECK > 0U))
344         if (kStatus_USB_Success != USB_DeviceCcidAddTransfer(&ccidHandle->transferFree, transfer))
345         {
346             return kStatus_USB_Error;
347         }
348 #else
349         (void)USB_DeviceCcidAddTransfer(&ccidHandle->transferFree, transfer);
350 #endif
351     }
352 
353     /* Clear the bulk IN pipe busy flag. */
354     ccidHandle->bulkInBusy = 0U;
355     /* If there is a blocking transfer, send it to the host */
356     if (NULL != ccidHandle->transferHead)
357     {
358         error = USB_DeviceSendRequest(ccidHandle->handle, ccidHandle->endpointBulkIn, ccidHandle->transferHead->buffer,
359                                       ccidHandle->transferHead->length);
360         if (kStatus_USB_Success == error)
361         {
362             ccidHandle->bulkInBusy = 1U;
363         }
364     }
365     return error;
366 }
367 
368 /*!
369  * @brief Bulk OUT endpoint callback function.
370  *
371  * This callback function is used to notify uplayer the transfser result of a transfer.
372  * This callback pointer is passed when the Bulk OUT pipe initialized.
373  *
374  * @param deviceHandle   The device handle. It equals the value returned from USB_DeviceInit.
375  * @param event           The result of the Bulk OUT pipe transfer.
376  * @param callbackParam  The parameter for this callback. It is same with
377  * usb_device_endpoint_callback_struct_t::callbackParam. In the class, the value is the ccid class handle.
378  *
379  * @return A USB error code or kStatus_USB_Success.
380  */
USB_DeviceCcidBulkOut(usb_device_handle deviceHandle,usb_device_endpoint_callback_message_struct_t * event,void * callbackParam)381 static usb_status_t USB_DeviceCcidBulkOut(usb_device_handle deviceHandle,
382                                           usb_device_endpoint_callback_message_struct_t *event,
383                                           void *callbackParam)
384 {
385     usb_device_ccid_struct_t *ccidHandle;
386     usb_device_ccid_common_command_t *commonRequest;
387     usb_device_ccid_transfer_struct_t *transfer = NULL;
388     void *temp;
389     usb_status_t usbError  = kStatus_USB_InvalidRequest;
390     uint8_t response_error = USB_DEVICE_CCID_SLOT_ERROR_COMMAND_NOT_SUPPORTED;
391 
392     /* endpoint callback length is USB_CANCELLED_TRANSFER_LENGTH (0xFFFFFFFFU) when transfer is canceled */
393     if (((NULL == deviceHandle) || (NULL == callbackParam) || (NULL == event)) || (NULL == event->buffer) ||
394         (USB_CANCELLED_TRANSFER_LENGTH == event->length))
395     {
396         return kStatus_USB_Error;
397     }
398     ccidHandle    = (usb_device_ccid_struct_t *)callbackParam;
399     temp          = (void *)event->buffer;
400     commonRequest = (usb_device_ccid_common_command_t *)temp;
401 
402     /* Check the slot is valid or not */
403     temp = (void *)&commonRequest->dwLength;
404     if ((ccidHandle->slots <= commonRequest->bSlot) ||
405         (event->length <
406          (USB_LONG_FROM_LITTLE_ENDIAN_ADDRESS(((uint8_t *)temp)) + USB_DEVICE_CCID_COMMAND_HEADER_LENGTH)))
407     {
408         if (ccidHandle->slots <= commonRequest->bSlot)
409         {
410             response_error = USB_DEVICE_CCID_SLOT_ERROR_SLOT_NOT_EXIST;
411         }
412         else
413         {
414             response_error = USB_DEVICE_CCID_SLOT_ERROR_BAD_LENGTH;
415         }
416     }
417     else
418     {
419         /* If the slot is valid, handle the host's request */
420         ccidHandle->slotsSequenceNumber[commonRequest->bSlot] = commonRequest->bSeq;
421         switch (commonRequest->bMessageType)
422         {
423             case USB_DEVICE_CCID_PC_TO_RDR_ICCPOWERON:
424             case USB_DEVICE_CCID_PC_TO_RDR_ICCPOWEROFF:
425             case USB_DEVICE_CCID_PC_TO_RDR_GETSLOTSTATUS:
426             case USB_DEVICE_CCID_PC_TO_RDR_XFRBLOCK:
427             case USB_DEVICE_CCID_PC_TO_RDR_GETPARAMETERS:
428             case USB_DEVICE_CCID_PC_TO_RDR_RESETPARAMETERS:
429             case USB_DEVICE_CCID_PC_TO_RDR_SETPARAMETERS:
430             case USB_DEVICE_CCID_PC_TO_RDR_ESCAPE:
431             case USB_DEVICE_CCID_PC_TO_RDR_ICCCLOCK:
432             case USB_DEVICE_CCID_PC_TO_RDR_T0APDU:
433             case USB_DEVICE_CCID_PC_TO_RDR_SECURE:
434             case USB_DEVICE_CCID_PC_TO_RDR_MECHANICAL:
435             case USB_DEVICE_CCID_PC_TO_RDR_ABORT:
436             case USB_DEVICE_CCID_PC_TO_RDR_SETDATARATEANDCLOCKFREQUENCY:
437                 if (NULL != ccidHandle->configStruct->classCallback)
438                 {
439                     usb_device_ccid_command_struct_t command;
440                     command.commandBuffer = event->buffer;
441                     command.commandLength = event->length;
442                     /* Notify the up layer, the command received, and then the application need to handle the command.
443                     classCallback is initialized in classInit of s_UsbDeviceClassInterfaceMap,
444                     it is from the second parameter of classInit */
445                     usbError = ccidHandle->configStruct->classCallback((class_handle_t)ccidHandle,
446                                                                        kUSB_DeviceCcidEventCommandReceived, &command);
447                     if (kStatus_USB_Success == usbError)
448                     {
449                         /* Get a new transfer node from the idle queue */
450                         if (kStatus_USB_Success == USB_DeviceCcidRemoveTransfer(&ccidHandle->transferFree, &transfer))
451                         {
452                             /* Save the response buffer and data length to the transfer node */
453                             transfer->buffer = command.responseBuffer;
454                             transfer->length = command.responseLength;
455                             /* Add the transfer node to the busy queue */
456 #if (defined(USB_DEVICE_CONFIG_RETURN_VALUE_CHECK) && (USB_DEVICE_CONFIG_RETURN_VALUE_CHECK > 0U))
457                             if (kStatus_USB_Success != USB_DeviceCcidAddTransfer(&ccidHandle->transferHead, transfer))
458                             {
459                                 return kStatus_USB_Error;
460                             }
461 #else
462                             (void)USB_DeviceCcidAddTransfer(&ccidHandle->transferHead, transfer);
463 #endif
464                             if (0U == ccidHandle->bulkInBusy)
465                             {
466                                 /* If the bulk IN pipe is idle, send the response data to the host */
467                                 if (kStatus_USB_Success == USB_DeviceSendRequest(ccidHandle->handle,
468                                                                                  ccidHandle->endpointBulkIn,
469                                                                                  transfer->buffer, transfer->length))
470                                 {
471                                     ccidHandle->bulkInBusy = 1U;
472                                 }
473                             }
474                         }
475                     }
476                 }
477                 break;
478             default:
479                 /*no action*/
480                 break;
481         }
482     }
483 
484     /* Response the host when the command failed. */
485     if (kStatus_USB_Success != usbError)
486     {
487         if (kStatus_USB_Success == USB_DeviceCcidRemoveTransfer(&ccidHandle->transferFree, &transfer))
488         {
489             usb_device_ccid_slot_status_struct_t slotStatus;
490             transfer->buffer                = (uint8_t *)&transfer->response;
491             transfer->length                = sizeof(transfer->response);
492             transfer->response.bMessageType = USB_DEVICE_CCID_RDR_TO_PC_SLOTSTATUS;
493             temp                            = (void *)&transfer->response.dwLength;
494             USB_LONG_TO_LITTLE_ENDIAN_ADDRESS(0U, ((uint8_t *)temp));
495             transfer->response.bSlot = commonRequest->bSlot;
496             transfer->response.bSeq  = commonRequest->bSeq;
497             slotStatus.clockStatus   = USB_DEVICE_CCID_CLCOK_STATUS_CLOCK_STOPPED_UNKNOWN;
498             slotStatus.slot          = commonRequest->bSlot;
499             slotStatus.present       = USB_DEVICE_CCID_SLOT_STATUS_ICC_NOT_PRESENT;
500             if (NULL != ccidHandle->configStruct->classCallback)
501             {
502                 /* classCallback is initialized in classInit of s_UsbDeviceClassInterfaceMap,
503                 it is from the second parameter of classInit*/
504 #if (defined(USB_DEVICE_CONFIG_RETURN_VALUE_CHECK) && (USB_DEVICE_CONFIG_RETURN_VALUE_CHECK > 0U))
505                 if (kStatus_USB_Success != ccidHandle->configStruct->classCallback((class_handle_t)ccidHandle,
506                                                                                    kUSB_DeviceCcidEventGetSlotStatus,
507                                                                                    &slotStatus))
508                 {
509                     return kStatus_USB_Error;
510                 }
511 #else
512                 (void)ccidHandle->configStruct->classCallback((class_handle_t)ccidHandle,
513                                                               kUSB_DeviceCcidEventGetSlotStatus, &slotStatus);
514 #endif
515             }
516             transfer->response.bStatus      = slotStatus.present | USB_DEVICE_CCID_SLOT_STATUS_COMMAND_STATUS_FAILED;
517             transfer->response.bError       = response_error;
518             transfer->response.bClockStatus = slotStatus.clockStatus;
519 #if (defined(USB_DEVICE_CONFIG_RETURN_VALUE_CHECK) && (USB_DEVICE_CONFIG_RETURN_VALUE_CHECK > 0U))
520             if (kStatus_USB_Success != USB_DeviceCcidAddTransfer(&ccidHandle->transferHead, transfer))
521             {
522                 return kStatus_USB_Error;
523             }
524 #else
525             (void)USB_DeviceCcidAddTransfer(&ccidHandle->transferHead, transfer);
526 #endif
527             if (0U == ccidHandle->bulkInBusy)
528             {
529                 usbError = USB_DeviceSendRequest(ccidHandle->handle, ccidHandle->endpointBulkIn, transfer->buffer,
530                                                  transfer->length);
531                 if (kStatus_USB_Success == usbError)
532                 {
533                     ccidHandle->bulkInBusy = 1U;
534                 }
535             }
536         }
537     }
538     /* Prime next transfer to receive a command from the host */
539     if (0U != ccidHandle->endpointBulkOut)
540     {
541 #if (defined(USB_DEVICE_CONFIG_RETURN_VALUE_CHECK) && (USB_DEVICE_CONFIG_RETURN_VALUE_CHECK > 0U))
542         usbError = USB_DeviceRecvRequest(ccidHandle->handle, ccidHandle->endpointBulkOut, ccidHandle->commandBuffer,
543                                          sizeof(ccidHandle->commandBuffer));
544 #else
545         (void)USB_DeviceRecvRequest(ccidHandle->handle, ccidHandle->endpointBulkOut, ccidHandle->commandBuffer,
546                                     sizeof(ccidHandle->commandBuffer));
547 #endif
548     }
549     return usbError;
550 }
551 
552 /*!
553  * @brief Initialize the endpoints of the ccid class.
554  *
555  * This callback function is used to initialize the endpoints of the ccide class.
556  *
557  * @param ccidHandle          The device ccid class handle. It equals the value returned from
558  * usb_device_class_config_struct_t::classHandle.
559  *
560  * @return A USB error code or kStatus_USB_Success.
561  */
USB_DeviceCcidEndpointsInit(usb_device_ccid_struct_t * ccidHandle)562 static usb_status_t USB_DeviceCcidEndpointsInit(usb_device_ccid_struct_t *ccidHandle)
563 {
564     usb_device_interface_list_t *interfaceList;
565     usb_device_interface_struct_t *interface = (usb_device_interface_struct_t *)NULL;
566     usb_status_t status                      = kStatus_USB_Error;
567 
568     /* Check the configuration is valid or not. */
569     if (0U == ccidHandle->configuration)
570     {
571         return status;
572     }
573 
574     if (ccidHandle->configuration > ccidHandle->configStruct->classInfomation->configurations)
575     {
576         return status;
577     }
578 
579     /* Get the interface list of the new configuration. */
580     if (NULL == ccidHandle->configStruct->classInfomation->interfaceList)
581     {
582         return status;
583     }
584     interfaceList = &ccidHandle->configStruct->classInfomation->interfaceList[ccidHandle->configuration - 1U];
585 
586     /* Find stream interface by using the alternate setting of the interface. */
587     for (uint32_t count = 0U; count < interfaceList->count; count++)
588     {
589         if ((USB_DEVICE_CCID_CLASS_CODE == interfaceList->interfaces[count].classCode) &&
590             (USB_DEVICE_CCID_SUBCLASS_CODE == interfaceList->interfaces[count].subclassCode) &&
591             (USB_DEVICE_CCID_PROTOCOL_CODE == interfaceList->interfaces[count].protocolCode))
592         {
593             for (uint32_t index = 0U; index < interfaceList->interfaces[count].count; index++)
594             {
595                 if (interfaceList->interfaces[count].interface[index].alternateSetting == ccidHandle->alternate)
596                 {
597                     interface = &interfaceList->interfaces[count].interface[index];
598                     break;
599                 }
600             }
601             ccidHandle->interfaceNumber = interfaceList->interfaces[count].interfaceNumber;
602             break;
603         }
604     }
605     if (NULL == interface)
606     {
607         /* Return error if the stream interface is not found. */
608         return status;
609     }
610     /* Keep new interface handle. */
611     ccidHandle->interfaceHandle = interface;
612     /* Initialize the endpoints of the new interface. */
613     for (uint32_t count = 0U; count < interface->endpointList.count; count++)
614     {
615         usb_device_endpoint_init_struct_t epInitStruct;
616         usb_device_endpoint_callback_struct_t epCallback;
617         epInitStruct.zlt             = 0U;
618         epInitStruct.interval        = interface->endpointList.endpoint[count].interval;
619         epInitStruct.endpointAddress = interface->endpointList.endpoint[count].endpointAddress;
620         epInitStruct.maxPacketSize   = interface->endpointList.endpoint[count].maxPacketSize;
621         epInitStruct.transferType    = interface->endpointList.endpoint[count].transferType;
622 
623         if ((USB_ENDPOINT_BULK == (epInitStruct.transferType & USB_DESCRIPTOR_ENDPOINT_ATTRIBUTE_TYPE_MASK)) &&
624             (USB_IN == ((epInitStruct.endpointAddress & USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_MASK) >>
625                         USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_SHIFT)))
626         {
627             epCallback.callbackFn      = USB_DeviceCcidBulkIn;
628             epInitStruct.zlt           = 1U;
629             ccidHandle->endpointBulkIn = epInitStruct.endpointAddress & USB_DESCRIPTOR_ENDPOINT_ADDRESS_NUMBER_MASK;
630         }
631         else if ((USB_ENDPOINT_BULK == (epInitStruct.transferType & USB_DESCRIPTOR_ENDPOINT_ATTRIBUTE_TYPE_MASK)) &&
632                  (USB_OUT == ((epInitStruct.endpointAddress & USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_MASK) >>
633                               USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_SHIFT)))
634         {
635             epCallback.callbackFn       = USB_DeviceCcidBulkOut;
636             ccidHandle->endpointBulkOut = epInitStruct.endpointAddress & USB_DESCRIPTOR_ENDPOINT_ADDRESS_NUMBER_MASK;
637         }
638         else
639         {
640             epCallback.callbackFn = USB_DeviceCcidInterruptIn;
641             ccidHandle->endpointInterruptIn =
642                 epInitStruct.endpointAddress & USB_DESCRIPTOR_ENDPOINT_ADDRESS_NUMBER_MASK;
643         }
644         epCallback.callbackParam = ccidHandle;
645 
646         status = USB_DeviceInitEndpoint(ccidHandle->handle, &epInitStruct, &epCallback);
647     }
648     return status;
649 }
650 
651 /*!
652  * @brief De-initialize the endpoints of the ccid class.
653  *
654  * This callback function is used to de-initialize the stream endpoints of the ccid class.
655  *
656  * @param ccidHandle          The device ccid class handle. It equals the value returned from
657  * usb_device_class_config_struct_t::classHandle.
658  *
659  * @return A USB error code or kStatus_USB_Success.
660  */
USB_DeviceCcidEndpointsDeinit(usb_device_ccid_struct_t * ccidHandle)661 static usb_status_t USB_DeviceCcidEndpointsDeinit(usb_device_ccid_struct_t *ccidHandle)
662 {
663     usb_status_t status = kStatus_USB_Error;
664 
665     if (NULL == ccidHandle->interfaceHandle)
666     {
667         return status;
668     }
669     /* De-initialize all endpoints of the interface */
670     for (uint32_t count = 0U; count < ccidHandle->interfaceHandle->endpointList.count; count++)
671     {
672         status = USB_DeviceDeinitEndpoint(ccidHandle->handle,
673                                           ccidHandle->interfaceHandle->endpointList.endpoint[count].endpointAddress);
674     }
675     ccidHandle->endpointBulkIn      = 0U;
676     ccidHandle->endpointBulkOut     = 0U;
677     ccidHandle->endpointInterruptIn = 0U;
678     ccidHandle->interfaceHandle     = NULL;
679     return status;
680 }
681 
682 /*!
683  * @brief Handle the event passed to the ccid class.
684  *
685  * This function handles the event passed to the ccid class.
686  *
687  * @param handle          The ccid class handle, got from the usb_device_class_config_struct_t::classHandle.
688  * @param event           The event codes. Please refer to the enumeration usb_device_class_event_t.
689  * @param param           The param type is determined by the event code.
690  *
691  * @return A USB error code or kStatus_USB_Success.
692  * @retval kStatus_USB_Success              Free device handle successfully.
693  * @retval kStatus_USB_InvalidParameter     The device handle not be found.
694  * @retval kStatus_USB_InvalidRequest       The request is invalid, and the control pipe will be stalled by the caller.
695  */
USB_DeviceCcidEvent(void * handle,uint32_t event,void * param)696 usb_status_t USB_DeviceCcidEvent(void *handle, uint32_t event, void *param)
697 {
698     usb_device_ccid_struct_t *ccidHandle;
699     usb_device_ccid_notify_slot_chnage_notification_t *ccidNotify;
700     uint8_t *temp8;
701     void *temp;
702     usb_status_t status = kStatus_USB_Error;
703     uint16_t interfaceAlternate;
704     uint8_t alternate;
705     usb_device_class_event_t eventCode = (usb_device_class_event_t)event;
706     OSA_SR_ALLOC();
707 
708     if ((NULL == param) || (NULL == handle))
709     {
710         return kStatus_USB_InvalidHandle;
711     }
712 
713     /* Get the ccid class handle. */
714     ccidHandle = (usb_device_ccid_struct_t *)handle;
715 
716     switch (eventCode)
717     {
718         case kUSB_DeviceClassEventDeviceReset:
719             /* Bus reset, clear the configuration. */
720             ccidHandle->configuration = 0U;
721             break;
722         case kUSB_DeviceClassEventSetConfiguration:
723             /* Get the new configuration. */
724             temp8 = ((uint8_t *)param);
725             if (NULL == ccidHandle->configStruct)
726             {
727                 break;
728             }
729             if (*temp8 == ccidHandle->configuration)
730             {
731                 break;
732             }
733 
734             /* De-initialize the endpoints when current configuration is none zero. */
735             if (0U != ccidHandle->configuration)
736             {
737                 status = USB_DeviceCcidEndpointsDeinit(ccidHandle);
738             }
739             OSA_ENTER_CRITICAL();
740             /* Save new configuration. */
741             ccidHandle->configuration = *temp8;
742             /* Clear the alternate setting value. */
743             ccidHandle->alternate = 0U;
744 
745             /* Clear BULK IN pipe busy status */
746             ccidHandle->bulkInBusy = 0U;
747             /* Clear Interrupt IN pipe busy status */
748             ccidHandle->interruptInBusy = 0U;
749             /* Clear slot changed status */
750             ccidHandle->slotsChanged = 0U;
751 
752             /* Reset the idle queue and busy queue */
753             ccidHandle->transferFree = &ccidHandle->transfers[0];
754             ccidHandle->transferHead = &ccidHandle->transfers[0];
755             for (uint8_t i = 1U; i < USB_DEVICE_CONFIG_CCID_TRANSFER_COUNT; i++)
756             {
757                 ccidHandle->transferHead->next = &ccidHandle->transfers[i];
758                 ccidHandle->transferHead       = &ccidHandle->transfers[i];
759             }
760             ccidHandle->transferHead->next = NULL;
761             ccidHandle->transferHead       = NULL;
762 
763             /* Initialize the endpoints of the new current configuration by using the alternate setting 0. */
764             status = USB_DeviceCcidEndpointsInit(ccidHandle);
765             if (0U != ccidHandle->endpointBulkOut)
766             {
767                 /* Prime a transfer to receive a command from the host */
768 #if (defined(USB_DEVICE_CONFIG_RETURN_VALUE_CHECK) && (USB_DEVICE_CONFIG_RETURN_VALUE_CHECK > 0U))
769                 status = USB_DeviceRecvRequest(ccidHandle->handle, ccidHandle->endpointBulkOut,
770                                                ccidHandle->commandBuffer, sizeof(ccidHandle->commandBuffer));
771 #else
772                 (void)USB_DeviceRecvRequest(ccidHandle->handle, ccidHandle->endpointBulkOut, ccidHandle->commandBuffer,
773                                             sizeof(ccidHandle->commandBuffer));
774 #endif
775             }
776 
777             /* Notify the host the slot changed when the interrut IN pipe is valid and there are some ICC present. */
778             if (0U != ccidHandle->endpointInterruptIn)
779             {
780                 uint8_t send_slot_change = 0U;
781                 temp                     = (void *)&ccidHandle->slotsChangeBuffer[0];
782                 ccidNotify               = (usb_device_ccid_notify_slot_chnage_notification_t *)temp;
783 
784                 ccidNotify->bMessageType = USB_DEVICE_CCID_RDR_TO_PC_NOTIFYSLOTCHANGE;
785                 for (uint8_t i = 0U; i < USB_DEVICE_CONFIG_CCID_SLOT_MAX; i++)
786                 {
787                     if (0U != (ccidNotify->bmSlotICCState[i >> 2] & (0x01U << ((i % 4U) << 1U))))
788                     {
789                         ccidNotify->bmSlotICCState[i >> 2] |= (0x02U << ((i % 4U) << 1U));
790                         send_slot_change = 1U;
791                     }
792                 }
793                 if (0U != send_slot_change)
794                 {
795                     ccidHandle->slotsSendingChangeBuffer[0] = ccidHandle->slotsChangeBuffer[0];
796                     for (uint8_t i = 1U; i < sizeof(ccidHandle->slotsChangeBuffer); i++)
797                     {
798                         ccidHandle->slotsSendingChangeBuffer[i] = ccidHandle->slotsChangeBuffer[i];
799                         ccidHandle->slotsChangeBuffer[i] &= (uint8_t)(~0xAAU);
800                     }
801                     status = USB_DeviceSendRequest(ccidHandle->handle, ccidHandle->endpointInterruptIn,
802                                                    ccidHandle->slotsSendingChangeBuffer,
803                                                    sizeof(ccidHandle->slotsSendingChangeBuffer));
804                     if (kStatus_USB_Success == status)
805                     {
806                         ccidHandle->interruptInBusy = 1U;
807                     }
808                 }
809             }
810             OSA_EXIT_CRITICAL();
811             break;
812         case kUSB_DeviceClassEventSetInterface:
813             if (NULL == ccidHandle->configStruct)
814             {
815                 break;
816             }
817 
818             /* Get the new alternate setting of the interface */
819             interfaceAlternate = *((uint16_t *)param);
820             /* Get the alternate setting value */
821             alternate = (uint8_t)(interfaceAlternate & 0xFFU);
822 
823             /* Whether the interface belongs to the class. */
824             if (ccidHandle->interfaceNumber != ((uint8_t)(interfaceAlternate >> 8U)))
825             {
826                 break;
827             }
828             if (alternate == ccidHandle->alternate)
829             {
830                 break;
831             }
832             /* De-initialize old endpoints */
833             status                = USB_DeviceCcidEndpointsDeinit(ccidHandle);
834             ccidHandle->alternate = alternate;
835             /* Initialize new endpoints */
836             status = USB_DeviceCcidEndpointsInit(ccidHandle);
837             if (0U != ccidHandle->endpointBulkOut)
838             {
839                 /* Prime a transfer to receive a command from the host */
840 #if (defined(USB_DEVICE_CONFIG_RETURN_VALUE_CHECK) && (USB_DEVICE_CONFIG_RETURN_VALUE_CHECK > 0U))
841                 status = USB_DeviceRecvRequest(ccidHandle->handle, ccidHandle->endpointBulkOut,
842                                                ccidHandle->commandBuffer, sizeof(ccidHandle->commandBuffer));
843 #else
844                 (void)USB_DeviceRecvRequest(ccidHandle->handle, ccidHandle->endpointBulkOut, ccidHandle->commandBuffer,
845                                             sizeof(ccidHandle->commandBuffer));
846 #endif
847             }
848             break;
849         case kUSB_DeviceClassEventSetEndpointHalt:
850             if ((NULL == ccidHandle->configStruct) || (NULL == ccidHandle->interfaceHandle))
851             {
852                 break;
853             }
854             /* Get the endpoint address */
855             temp8 = ((uint8_t *)param);
856             for (uint32_t count = 0U; count < ccidHandle->interfaceHandle->endpointList.count; count++)
857             {
858                 if (*temp8 == ccidHandle->interfaceHandle->endpointList.endpoint[count].endpointAddress)
859                 {
860                     /* Only stall the endpoint belongs to the interface of the class */
861                     status = USB_DeviceStallEndpoint(ccidHandle->handle, *temp8);
862                 }
863             }
864             break;
865         case kUSB_DeviceClassEventClearEndpointHalt:
866             if ((NULL == ccidHandle->configStruct) || (NULL == ccidHandle->interfaceHandle))
867             {
868                 break;
869             }
870             /* Get the endpoint address */
871             temp8 = ((uint8_t *)param);
872             for (uint32_t count = 0U; count < ccidHandle->interfaceHandle->endpointList.count; count++)
873             {
874                 if (*temp8 == ccidHandle->interfaceHandle->endpointList.endpoint[count].endpointAddress)
875                 {
876                     /* Only un-stall the endpoint belongs to the interface of the class */
877                     status = USB_DeviceUnstallEndpoint(ccidHandle->handle, *temp8);
878                 }
879             }
880             break;
881         case kUSB_DeviceClassEventClassRequest:
882         {
883             /* Handle the ccid class specific request. */
884             usb_device_control_request_struct_t *controlRequest = (usb_device_control_request_struct_t *)param;
885 
886             if ((controlRequest->setup->bmRequestType & USB_REQUEST_TYPE_RECIPIENT_MASK) !=
887                 USB_REQUEST_TYPE_RECIPIENT_INTERFACE)
888             {
889                 break;
890             }
891 
892             if ((controlRequest->setup->wIndex & 0xFFU) != ccidHandle->interfaceNumber)
893             {
894                 break;
895             }
896 
897             switch (controlRequest->setup->bRequest)
898             {
899                 case USB_DEVICE_CCID_ABORT:
900                     /* Abort a command */
901                     if (NULL != ccidHandle->configStruct->classCallback)
902                     {
903                         /* classCallback is initialized in classInit of s_UsbDeviceClassInterfaceMap,
904                         it is from the second parameter of classInit */
905                         status = ccidHandle->configStruct->classCallback((class_handle_t)ccidHandle,
906                                                                          kUSB_DeviceCcidEventCommandAbort,
907                                                                          &controlRequest->setup->wValue);
908                     }
909                     break;
910                 case USB_DEVICE_CCID_GET_CLOCK_FREQUENCIES:
911                     /* Get the clock frequencies */
912                     if (NULL != ccidHandle->configStruct->classCallback)
913                     {
914                         usb_device_ccid_control_request_struct_t ccid_request;
915                         /* classCallback is initialized in classInit of s_UsbDeviceClassInterfaceMap,
916                         it is from the second parameter of classInit */
917                         status = ccidHandle->configStruct->classCallback(
918                             (class_handle_t)ccidHandle, kUSB_DeviceCcidEventGetClockFrequencies, &ccid_request);
919                         if (kStatus_USB_Success == status)
920                         {
921                             controlRequest->buffer = ccid_request.buffer;
922                             controlRequest->length = ccid_request.length;
923                         }
924                     }
925                     break;
926                 case USB_DEVICE_CCID_GET_DATA_RATES:
927                     /* Get the data rates */
928                     if (NULL != ccidHandle->configStruct->classCallback)
929                     {
930                         usb_device_ccid_control_request_struct_t ccid_request;
931                         /* classCallback is initialized in classInit of s_UsbDeviceClassInterfaceMap,
932                         it is from the second parameter of classInit */
933                         status = ccidHandle->configStruct->classCallback(
934                             (class_handle_t)ccidHandle, kUSB_DeviceCcidEventGetDataRate, &ccid_request);
935                         if (kStatus_USB_Success == status)
936                         {
937                             controlRequest->buffer = ccid_request.buffer;
938                             controlRequest->length = ccid_request.length;
939                         }
940                     }
941                     break;
942                 default:
943                     status = kStatus_USB_InvalidRequest;
944                     break;
945             }
946         }
947         break;
948         default:
949             /*no action*/
950             break;
951     }
952     return status;
953 }
954 
955 /*!
956  * @brief Initialize the ccid class.
957  *
958  * This function is used to initialize the ccid class.
959  *
960  * @param controllerId   The controller id of the USB IP. Please refer to the enumeration usb_controller_index_t.
961  * @param config          The class configuration information.
962  * @param handle          It is out parameter, is used to return pointer of the video class handle to the caller.
963  *
964  * @return A USB error code or kStatus_USB_Success.
965  */
USB_DeviceCcidInit(uint8_t controllerId,usb_device_class_config_struct_t * config,class_handle_t * handle)966 usb_status_t USB_DeviceCcidInit(uint8_t controllerId, usb_device_class_config_struct_t *config, class_handle_t *handle)
967 {
968     usb_device_ccid_struct_t *ccidHandle;
969     usb_status_t error;
970 
971     /* Allocate a ccid class handle. */
972     error = USB_DeviceCcidAllocateHandle(&ccidHandle);
973 
974     if (kStatus_USB_Success != error)
975     {
976         return error;
977     }
978     /* Get the device handle according to the controller id. */
979     error = USB_DeviceClassGetDeviceHandle(controllerId, &ccidHandle->handle);
980 
981     if (kStatus_USB_Success != error)
982     {
983         return error;
984     }
985 
986     if (NULL == ccidHandle->handle)
987     {
988 #if (defined(USB_DEVICE_CONFIG_RETURN_VALUE_CHECK) && (USB_DEVICE_CONFIG_RETURN_VALUE_CHECK > 0U))
989         error = USB_DeviceCcidFreeHandle(ccidHandle);
990 #else
991         (void)USB_DeviceCcidFreeHandle(ccidHandle);
992 #endif
993         return kStatus_USB_InvalidHandle;
994     }
995     /* Save the configuration of the class. */
996     ccidHandle->configStruct = config;
997     /* Clear the configuration value. */
998     ccidHandle->configuration       = 0U;
999     ccidHandle->alternate           = 0xffU;
1000     ccidHandle->bulkInBusy          = 0U;
1001     ccidHandle->endpointBulkIn      = 0U;
1002     ccidHandle->endpointBulkOut     = 0U;
1003     ccidHandle->endpointInterruptIn = 0U;
1004     ccidHandle->slots               = 0U;
1005     ccidHandle->interruptInBusy     = 0U;
1006     ccidHandle->slotsChanged        = 0U;
1007 
1008     if (NULL != ccidHandle->configStruct->classCallback)
1009     {
1010         /* Get the max slot count of the application.
1011         classCallback is initialized in classInit of s_UsbDeviceClassInterfaceMap,
1012         it is from the second parameter of classInit */
1013 #if (defined(USB_DEVICE_CONFIG_RETURN_VALUE_CHECK) && (USB_DEVICE_CONFIG_RETURN_VALUE_CHECK > 0U))
1014         if (kStatus_USB_Success != ccidHandle->configStruct->classCallback((class_handle_t)ccidHandle,
1015                                                                            kUSB_DeviceCcidEventGetSlotCount,
1016                                                                            &ccidHandle->slots))
1017         {
1018             return kStatus_USB_Error;
1019         }
1020 #else
1021         (void)ccidHandle->configStruct->classCallback((class_handle_t)ccidHandle, kUSB_DeviceCcidEventGetSlotCount,
1022                                                       &ccidHandle->slots);
1023 #endif
1024     }
1025 
1026     if (ccidHandle->slots > USB_DEVICE_CONFIG_CCID_SLOT_MAX)
1027     {
1028 #if (defined(USB_DEVICE_CONFIG_RETURN_VALUE_CHECK) && (USB_DEVICE_CONFIG_RETURN_VALUE_CHECK > 0U))
1029         error = USB_DeviceCcidFreeHandle(ccidHandle);
1030 #else
1031         (void)USB_DeviceCcidFreeHandle(ccidHandle);
1032 #endif
1033         return kStatus_USB_Error;
1034     }
1035 
1036     ccidHandle->transferFree = &ccidHandle->transfers[0];
1037     ccidHandle->transferHead = &ccidHandle->transfers[0];
1038     for (uint8_t i = 1U; i < USB_DEVICE_CONFIG_CCID_TRANSFER_COUNT; i++)
1039     {
1040         ccidHandle->transferHead->next = &ccidHandle->transfers[i];
1041         ccidHandle->transferHead       = &ccidHandle->transfers[i];
1042     }
1043     ccidHandle->transferHead->next = NULL;
1044     ccidHandle->transferHead       = NULL;
1045 
1046     *handle = (class_handle_t)ccidHandle;
1047     return error;
1048 }
1049 
1050 /*!
1051  * @brief De-initialize the device ccid class.
1052  *
1053  * The function de-initializes the device ccid class.
1054  *
1055  * @param handle The ccid class handle got from usb_device_class_config_struct_t::classHandle.
1056  *
1057  * @return A USB error code or kStatus_USB_Success.
1058  */
USB_DeviceCcidDeinit(class_handle_t handle)1059 usb_status_t USB_DeviceCcidDeinit(class_handle_t handle)
1060 {
1061     usb_device_ccid_struct_t *ccidHandle;
1062     usb_status_t status;
1063 
1064     ccidHandle = (usb_device_ccid_struct_t *)handle;
1065 
1066     if (NULL == ccidHandle)
1067     {
1068         return kStatus_USB_InvalidHandle;
1069     }
1070     /* De-initialzie the endpoints. */
1071     status = USB_DeviceCcidEndpointsDeinit(ccidHandle);
1072     /* Free the ccid class handle. */
1073 #if (defined(USB_DEVICE_CONFIG_RETURN_VALUE_CHECK) && (USB_DEVICE_CONFIG_RETURN_VALUE_CHECK > 0U))
1074     status = USB_DeviceCcidFreeHandle(ccidHandle);
1075 #else
1076     (void)USB_DeviceCcidFreeHandle(ccidHandle);
1077 #endif
1078     return status;
1079 }
1080 
1081 /*!
1082  * @brief Notify the slot status changed.
1083  *
1084  * The function is used to notify the slot status changed. This is a un-blocking function, the event
1085  * kUSB_DeviceCcidEventSlotChangeSent
1086  * will be asserted when the transfer completed.
1087  *
1088  * The slot status may not be sent to the host if the interrupt IN pipe is busy. And the status will be save internally,
1089  * and will be sent to the host when the interrupt IN pipe callback called. So, the event
1090  * kUSB_DeviceCcidEventSlotChangeSent
1091  * happened times will not equal to the function call times of this function.
1092  *
1093  * @param handle The ccid class handle got from usb_device_class_config_struct_t::classHandle.
1094  * @param slot   The changed slot number.
1095  * @param state  The changed slot status.
1096  *
1097  * @return A USB error code or kStatus_USB_Success.
1098  */
USB_DeviceCcidNotifySlotChange(class_handle_t handle,uint8_t slot,usb_device_ccid_slot_state_t state)1099 usb_status_t USB_DeviceCcidNotifySlotChange(class_handle_t handle, uint8_t slot, usb_device_ccid_slot_state_t state)
1100 {
1101     usb_device_ccid_struct_t *ccidHandle;
1102     usb_device_ccid_notify_slot_chnage_notification_t *ccidNotify;
1103     void *temp;
1104     usb_status_t error = kStatus_USB_Error;
1105     OSA_SR_ALLOC();
1106 
1107     ccidHandle = (usb_device_ccid_struct_t *)handle;
1108 
1109     if (NULL == ccidHandle)
1110     {
1111         return kStatus_USB_InvalidHandle;
1112     }
1113 
1114     if (slot >= USB_DEVICE_CONFIG_CCID_SLOT_MAX)
1115     {
1116         return kStatus_USB_InvalidParameter;
1117     }
1118 
1119     OSA_ENTER_CRITICAL();
1120     temp       = (void *)&ccidHandle->slotsChangeBuffer[0];
1121     ccidNotify = (usb_device_ccid_notify_slot_chnage_notification_t *)temp;
1122 
1123     ccidNotify->bMessageType = USB_DEVICE_CCID_RDR_TO_PC_NOTIFYSLOTCHANGE;
1124     ccidNotify->bmSlotICCState[slot >> 2] &= ~(0x03U << ((slot % 4U) << 1U));
1125     ccidNotify->bmSlotICCState[slot >> 2] |=
1126         ((0x02U | ((kUSB_DeviceCcidSlotStateNoPresent == state) ? 0x00U : 0x01U)) << ((slot % 4U) << 1U));
1127 
1128     if ((0U != ccidHandle->configuration) && (0U != ccidHandle->endpointInterruptIn))
1129     {
1130         if (0U == ccidHandle->interruptInBusy)
1131         {
1132             ccidHandle->slotsSendingChangeBuffer[0] = ccidHandle->slotsChangeBuffer[0];
1133             for (uint8_t i = 1U; i < sizeof(ccidHandle->slotsChangeBuffer); i++)
1134             {
1135                 ccidHandle->slotsSendingChangeBuffer[i] = ccidHandle->slotsChangeBuffer[i];
1136                 ccidHandle->slotsChangeBuffer[i] &= (uint8_t)(~0xAAU);
1137             }
1138             error = USB_DeviceSendRequest(ccidHandle->handle, ccidHandle->endpointInterruptIn,
1139                                           ccidHandle->slotsSendingChangeBuffer,
1140                                           sizeof(ccidHandle->slotsSendingChangeBuffer));
1141             if (kStatus_USB_Success == error)
1142             {
1143                 ccidHandle->interruptInBusy = 1U;
1144             }
1145         }
1146         else
1147         {
1148             ccidHandle->slotsChanged = 1U;
1149         }
1150     }
1151     OSA_EXIT_CRITICAL();
1152     return error;
1153 }
1154 
1155 /*!
1156  * @brief Notify the slot status changed.
1157  *
1158  * The function is used to notify the hardware error. This is a un-blocking function, the event
1159  * kUSB_DeviceCcidEventHardwareErrorSent
1160  * will be asserted when the transfer completed.
1161  *
1162  * If the interrupt IN pipe is busy, the function will return an error kStatus_USB_Error.
1163  *
1164  * @param handle      The ccid class handle got from usb_device_class_config_struct_t::classHandle.
1165  * @param slot        The changed slot number.
1166  * @param errorCode  The hardware error code.
1167  *
1168  * @return A USB error code or kStatus_USB_Success.
1169  */
USB_DeviceCcidNotifyHardwareError(class_handle_t handle,uint8_t slot,usb_device_ccid_hardware_error_t errorCode)1170 usb_status_t USB_DeviceCcidNotifyHardwareError(class_handle_t handle,
1171                                                uint8_t slot,
1172                                                usb_device_ccid_hardware_error_t errorCode)
1173 {
1174     usb_device_ccid_struct_t *ccidHandle;
1175     usb_status_t error = kStatus_USB_Error;
1176     OSA_SR_ALLOC();
1177 
1178     ccidHandle = (usb_device_ccid_struct_t *)handle;
1179 
1180     if (NULL == ccidHandle)
1181     {
1182         return kStatus_USB_InvalidHandle;
1183     }
1184 
1185     if (slot >= USB_DEVICE_CONFIG_CCID_SLOT_MAX)
1186     {
1187         return kStatus_USB_InvalidParameter;
1188     }
1189 
1190     ccidHandle->hardwareError.bMessageType       = USB_DEVICE_CCID_RDR_TO_PC_HARDWAREERROR;
1191     ccidHandle->hardwareError.bHardwareErrorCode = (uint8_t)errorCode;
1192     ccidHandle->hardwareError.bSlot              = slot;
1193     ccidHandle->hardwareError.bSeq               = ccidHandle->slotsSequenceNumber[slot];
1194 
1195     OSA_ENTER_CRITICAL();
1196     if ((0U != ccidHandle->configuration) && (0U != ccidHandle->endpointInterruptIn))
1197     {
1198         if (0U == ccidHandle->interruptInBusy)
1199         {
1200             error = USB_DeviceSendRequest(ccidHandle->handle, ccidHandle->endpointInterruptIn,
1201                                           (uint8_t *)&ccidHandle->hardwareError, sizeof(ccidHandle->hardwareError));
1202             if (kStatus_USB_Success == error)
1203             {
1204                 ccidHandle->interruptInBusy = 1U;
1205             }
1206         }
1207     }
1208     OSA_EXIT_CRITICAL();
1209     return error;
1210 }
1211 #endif
1212