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 ¬ification))
226 {
227 return kStatus_USB_Error;
228 }
229 #else
230 (void)ccidHandle->configStruct->classCallback((class_handle_t)ccidHandle,
231 kUSB_DeviceCcidEventSlotChangeSent, ¬ification);
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 ¬ification))
246 {
247 return kStatus_USB_Error;
248 }
249 #else
250 (void)ccidHandle->configStruct->classCallback((class_handle_t)ccidHandle,
251 kUSB_DeviceCcidEventHardwareErrorSent, ¬ification);
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