3 Copyright (C) Dean Camera, 2019.
5 dean [at] fourwalledcubicle [dot] com
10 Copyright 2019 Dean Camera (dean [at] fourwalledcubicle [dot] com)
11 Copyright 2019 Filipe Rodrigues (filipepazrodrigues [at] gmail [dot] com)
13 Permission to use, copy, modify, distribute, and sell this
14 software and its documentation for any purpose is hereby granted
15 without fee, provided that the above copyright notice appear in
16 all copies and that both that the copyright notice and this
17 permission notice and warranty disclaimer appear in supporting
18 documentation, and that the name of the author not be used in
19 advertising or publicity pertaining to distribution of the
20 software without specific, written prior permission.
22 The author disclaims all warranties with regard to this
23 software, including all implied warranties of merchantability
24 and fitness. In no event shall the author be liable for any
25 special, indirect or consequential damages or any damages
26 whatsoever resulting from loss of use, data or profits, whether
27 in an action of contract, negligence or other tortious action,
28 arising out of or in connection with the use or performance of
34 * Main source file for the CCID demo. This file contains the main tasks of the demo and
35 * is responsible for the initial application hardware configuration.
38 * LUFA is not a secure USB stack, and has not undergone, not is it expected to pass, any
39 * form of security audit. The CCID class here is presented as-is and is intended for
40 * research purposes only, and *should not* be used in a security critical application
41 * under any circumstances.
44 * This code is not production ready and should not by any means be considered safe.
45 * If you plan to integrate it into your application, you should seriously consider strong
46 * encryption algorithms or a secure microprocessor. Since Atmel AVR microprocessors do not
47 * have any security requirement (therefore they don't offer any known protection against
48 * side channel attacks or fault injection) a secure microprocessor is the best option.
54 static uint8_t AbortedSeq
;
56 static USB_CCID_ProtocolData_T0_t ProtocolData
=
61 .WaitingIntegerT0
= 0x0A,
65 /** Main program entry point. This routine configures the hardware required by the application, then
66 * enters a loop to run the application tasks in sequence.
72 LEDs_SetAllLEDs(LEDMASK_USB_NOTREADY
);
73 GlobalInterruptEnable();
82 /** Configures the board hardware and chip peripherals for the demo's functionality. */
83 void SetupHardware(void)
85 #if (ARCH == ARCH_AVR8)
86 /* Disable watchdog if enabled by bootloader/fuses */
87 MCUSR
&= ~(1 << WDRF
);
90 /* Disable clock division */
91 clock_prescale_set(clock_div_1
);
92 #elif (ARCH == ARCH_XMEGA)
93 /* Start the PLL to multiply the 2MHz RC oscillator to 32MHz and switch the CPU core to run from it */
94 XMEGACLK_StartPLL(CLOCK_SRC_INT_RC2MHZ
, 2000000, F_CPU
);
95 XMEGACLK_SetCPUClockSource(CLOCK_SRC_PLL
);
97 /* Start the 32MHz internal RC oscillator and start the DFLL to increase it to 48MHz using the USB SOF as a reference */
98 XMEGACLK_StartInternalOscillator(CLOCK_SRC_INT_RC32MHZ
);
99 XMEGACLK_StartDFLL(CLOCK_SRC_INT_RC32MHZ
, DFLL_REF_INT_USBSOF
, F_USB
);
101 PMIC
.CTRL
= PMIC_LOLVLEN_bm
| PMIC_MEDLVLEN_bm
| PMIC_HILVLEN_bm
;
104 /* Hardware Initialization */
109 /** Event handler for the USB_Connect event. This indicates that the device is enumerating via the status LEDs. */
110 void EVENT_USB_Device_Connect(void)
112 /* Indicate USB enumerating */
113 LEDs_SetAllLEDs(LEDMASK_USB_ENUMERATING
);
116 /** Event handler for the USB_Disconnect event. This indicates that the device is no longer connected to a host via
119 void EVENT_USB_Device_Disconnect(void)
121 /* Indicate USB not ready */
122 LEDs_SetAllLEDs(LEDMASK_USB_NOTREADY
);
125 /** Event handler for the USB_ConfigurationChanged event. This is fired when the host set the current configuration
126 * of the USB device after enumeration - the device endpoints are configured.
128 void EVENT_USB_Device_ConfigurationChanged(void)
130 bool ConfigSuccess
= true;
132 /* Setup CCID Data Endpoints */
133 ConfigSuccess
&= Endpoint_ConfigureEndpoint(CCID_IN_EPADDR
, EP_TYPE_BULK
, CCID_EPSIZE
, 1);
134 ConfigSuccess
&= Endpoint_ConfigureEndpoint(CCID_OUT_EPADDR
, EP_TYPE_BULK
, CCID_EPSIZE
, 1);
136 /* Indicate endpoint configuration success or failure */
137 LEDs_SetAllLEDs(ConfigSuccess ? LEDMASK_USB_READY
: LEDMASK_USB_ERROR
);
140 /** Event handler for the USB_ControlRequest event. This is used to catch and process control requests sent to
141 * the device from the USB host before passing along unhandled control requests to the library for processing
144 void EVENT_USB_Device_ControlRequest(void)
146 switch (USB_ControlRequest
.bRequest
)
150 // Initiates the abort process
151 // The host should send 2 messages in the following order:
152 // - CCID_ABORT control request
153 // - CCID_PC_t_PCo_RDR_Abort command
155 // If the device is still processing a message, it should fail it until receiving a CCIRPC_to_RDR_Abort
158 // When the device receives the CCIRPC_to_RDR_Abort message, it replies with RDR_to_PC_SlotStatus
159 // and the abort process ends
161 // The wValue field contains the slot number (bSlot) in the low byte and the sequence number (bSeq) in
163 uint8_t Slot
= USB_ControlRequest
.wValue
& 0xFF;
164 uint8_t Seq
= USB_ControlRequest
.wValue
>> 8;
166 if (USB_ControlRequest
.bmRequestType
== (REQDIR_DEVICETOHOST
| REQTYPE_CLASS
| REQREC_INTERFACE
) && Slot
== 0)
168 Endpoint_ClearSETUP();
179 case CCID_GET_CLOCK_FREQUENCIES
:
181 if (USB_ControlRequest
.bmRequestType
== (REQDIR_DEVICETOHOST
| REQTYPE_CLASS
| REQREC_INTERFACE
))
183 Endpoint_ClearSETUP();
184 Endpoint_Write_8(0); // Not supported
191 case CCID_GET_DATA_RATES
:
193 if (USB_ControlRequest
.bmRequestType
== (REQDIR_DEVICETOHOST
| REQTYPE_CLASS
| REQREC_INTERFACE
))
195 Endpoint_ClearSETUP();
196 Endpoint_Write_8(0); // Not supported
205 /** Event handler for the CCID_PC_to_RDR_IccPowerOn message. This message is sent to the device
206 * whenever an application at the host wants to send a power off signal to a slot.
207 * THe slot must reply back with a recognizable ATR (answer to reset)
209 uint8_t CCID_IccPowerOn(uint8_t Slot
,
211 uint8_t* const AtrLength
,
212 uint8_t* const Error
)
216 Iso7816_CreateSimpleAtr(Atr
, AtrLength
);
218 *Error
= CCID_ERROR_NO_ERROR
;
219 return CCID_COMMANDSTATUS_PROCESSEDWITHOUTERROR
| CCID_ICCSTATUS_PRESENTANDACTIVE
;
223 *Error
= CCID_ERROR_SLOT_NOT_FOUND
;
224 return CCID_COMMANDSTATUS_FAILED
| CCID_ICCSTATUS_NOICCPRESENT
;
228 /** Event handler for the CCID_PC_to_RDR_IccPowerOff message. This message is sent to the device
229 * whenever an application at the host wants to send a power off signal to a slot.
231 uint8_t CCID_IccPowerOff(uint8_t Slot
,
232 uint8_t* const Error
)
236 *Error
= CCID_ERROR_NO_ERROR
;
237 return CCID_COMMANDSTATUS_PROCESSEDWITHOUTERROR
| CCID_ICCSTATUS_NOICCPRESENT
;
241 *Error
= CCID_ERROR_SLOT_NOT_FOUND
;
242 return CCID_COMMANDSTATUS_FAILED
| CCID_ICCSTATUS_NOICCPRESENT
;
246 /** Event handler for the CCID_PC_to_RDR_GetSlotStatus. THis message is sent to
247 * the device whenever an application at the host wants to get the current
250 uint8_t CCID_GetSlotStatus(uint8_t Slot
,
251 uint8_t* const Error
)
255 *Error
= CCID_ERROR_NO_ERROR
;
256 return CCID_COMMANDSTATUS_PROCESSEDWITHOUTERROR
| CCID_ICCSTATUS_PRESENTANDACTIVE
;
260 *Error
= CCID_ERROR_SLOT_NOT_FOUND
;
261 return CCID_COMMANDSTATUS_FAILED
| CCID_ICCSTATUS_NOICCPRESENT
;
265 /** Event handler for the CCID_PC_to_RDR_SetParameters when T=0. This message is sent to
266 * the device whenever an application at the host wants to set the
267 * parameters for a given slot.
269 uint8_t CCID_SetParameters_T0(uint8_t Slot
,
270 uint8_t* const Error
,
271 USB_CCID_ProtocolData_T0_t
* const T0
)
276 memcpy(&ProtocolData
, T0
, sizeof(USB_CCID_ProtocolData_T0_t
));
278 *Error
= CCID_ERROR_NO_ERROR
;
279 return CCID_COMMANDSTATUS_PROCESSEDWITHOUTERROR
| CCID_ICCSTATUS_PRESENTANDACTIVE
;
283 *Error
= CCID_ERROR_SLOT_NOT_FOUND
;
284 return CCID_COMMANDSTATUS_FAILED
| CCID_ICCSTATUS_NOICCPRESENT
;
288 /** Event handler for the CCID_PC_to_RDR_GetParameters when T=0. This message is sent to
289 * the device whenever an application at the host wants to get the current
290 * parameters for a given slot.
292 uint8_t CCID_GetParameters_T0(uint8_t Slot
,
293 uint8_t* const Error
,
294 uint8_t* ProtocolNum
,
295 USB_CCID_ProtocolData_T0_t
* const T0
)
300 *ProtocolNum
= CCID_PROTOCOLNUM_T0
;
301 memcpy(T0
, &ProtocolData
, sizeof(USB_CCID_ProtocolData_T0_t
));
303 *Error
= CCID_ERROR_NO_ERROR
;
304 return CCID_COMMANDSTATUS_PROCESSEDWITHOUTERROR
| CCID_ICCSTATUS_PRESENTANDACTIVE
;
308 *Error
= CCID_ERROR_SLOT_NOT_FOUND
;
309 return CCID_COMMANDSTATUS_FAILED
| CCID_ICCSTATUS_NOICCPRESENT
;
313 /** Event handler for the CCID_PC_to_RDR_XfrBlock. This message is sent to the device
314 * whenever an application at the host wants to send a block of bytes to the device
315 * THe device reply back with an array of bytes
317 uint8_t CCID_XfrBlock(uint8_t Slot
,
318 uint8_t* const ReceivedBuffer
,
319 uint8_t ReceivedBufferSize
,
320 uint8_t* const SendBuffer
,
321 uint8_t* const SentBufferSize
,
322 uint8_t* const Error
)
326 uint8_t OkResponse
[2] = {0x90, 0x00};
328 memcpy(SendBuffer
, OkResponse
, sizeof(OkResponse
));
329 *SentBufferSize
= sizeof(OkResponse
);
331 *Error
= CCID_ERROR_NO_ERROR
;
332 return CCID_COMMANDSTATUS_PROCESSEDWITHOUTERROR
| CCID_ICCSTATUS_NOICCPRESENT
;
336 *Error
= CCID_ERROR_SLOT_NOT_FOUND
;
337 return CCID_COMMANDSTATUS_FAILED
| CCID_ICCSTATUS_NOICCPRESENT
;
341 /** Event handler for the CCID_PC_to_RDR_ABort message. This message is sent to the device
342 * whenever an application wants to abort the current operation. A previous CCID_ABORT
343 * control message has to be sent before this one in order to start the abort operation.
345 uint8_t CCID_Abort(uint8_t Slot
,
347 uint8_t* const Error
)
349 if (Aborted
&& Slot
== 0 && AbortedSeq
== Seq
)
354 *Error
= CCID_ERROR_NO_ERROR
;
355 return CCID_COMMANDSTATUS_PROCESSEDWITHOUTERROR
| CCID_ICCSTATUS_PRESENTANDACTIVE
;
359 *Error
= CCID_ERROR_CMD_NOT_ABORTED
;
360 return CCID_COMMANDSTATUS_PROCESSEDWITHOUTERROR
| CCID_ICCSTATUS_PRESENTANDACTIVE
;
364 *Error
= CCID_ERROR_SLOT_NOT_FOUND
;
365 return CCID_COMMANDSTATUS_FAILED
| CCID_ICCSTATUS_NOICCPRESENT
;
368 *Error
= CCID_ERROR_NOT_SUPPORTED
;
369 return CCID_COMMANDSTATUS_FAILED
| CCID_ICCSTATUS_NOICCPRESENT
;
372 /** Gets and status and verifies whether an error occurred. */
373 bool CCID_CheckStatusNoError(uint8_t Status
)
375 return (Status
& 0xC0) == 0x0;
378 /** Function to manage CCID request parsing and responses back to the host. */
381 Endpoint_SelectEndpoint(CCID_OUT_EPADDR
);
383 uint8_t RequestBuffer
[CCID_EPSIZE
- sizeof(USB_CCID_BulkMessage_Header_t
)];
384 uint8_t ResponseBuffer
[CCID_EPSIZE
];
388 if (Endpoint_IsOUTReceived())
390 USB_CCID_BulkMessage_Header_t CCIDHeader
;
391 CCIDHeader
.MessageType
= Endpoint_Read_8();
392 CCIDHeader
.Length
= Endpoint_Read_32_LE();
393 CCIDHeader
.Slot
= Endpoint_Read_8();
394 CCIDHeader
.Seq
= Endpoint_Read_8();
397 uint8_t Error
= CCID_ERROR_NO_ERROR
;
399 switch (CCIDHeader
.MessageType
)
401 case CCID_PC_to_RDR_IccPowerOn
:
404 USB_CCID_RDR_to_PC_DataBlock_t
* ResponseATR
= (USB_CCID_RDR_to_PC_DataBlock_t
*)&ResponseBuffer
;
406 ResponseATR
->CCIDHeader
.MessageType
= CCID_RDR_to_PC_DataBlock
;
407 ResponseATR
->CCIDHeader
.Slot
= CCIDHeader
.Slot
;
408 ResponseATR
->CCIDHeader
.Seq
= CCIDHeader
.Seq
;
409 ResponseATR
->ChainParam
= 0;
411 Status
= CCID_IccPowerOn(ResponseATR
->CCIDHeader
.Slot
, (uint8_t* )ResponseATR
->Data
, &AtrLength
, &Error
);
413 if (CCID_CheckStatusNoError(Status
) && !Aborted
)
415 ResponseATR
->CCIDHeader
.Length
= AtrLength
;
419 Status
= CCID_COMMANDSTATUS_FAILED
| CCID_ICCSTATUS_PRESENTANDACTIVE
;
420 Error
= CCID_ERROR_CMD_ABORTED
;
428 ResponseATR
->Status
= Status
;
429 ResponseATR
->Error
= Error
;
433 Endpoint_SelectEndpoint(CCID_IN_EPADDR
);
434 Endpoint_Write_Stream_LE(ResponseATR
, sizeof(USB_CCID_RDR_to_PC_DataBlock_t
) + AtrLength
, NULL
);
439 case CCID_PC_to_RDR_IccPowerOff
:
441 USB_CCID_RDR_to_PC_SlotStatus_t
* ResponsePowerOff
= (USB_CCID_RDR_to_PC_SlotStatus_t
*)&ResponseBuffer
;
442 ResponsePowerOff
->CCIDHeader
.MessageType
= CCID_RDR_to_PC_SlotStatus
;
443 ResponsePowerOff
->CCIDHeader
.Length
= 0;
444 ResponsePowerOff
->CCIDHeader
.Slot
= CCIDHeader
.Slot
;
445 ResponsePowerOff
->CCIDHeader
.Seq
= CCIDHeader
.Seq
;
447 ResponsePowerOff
->ClockStatus
= 0;
449 Status
= CCID_IccPowerOff(CCIDHeader
.Slot
, &Error
);
451 ResponsePowerOff
->Status
= Status
;
452 ResponsePowerOff
->Error
= Error
;
456 Endpoint_SelectEndpoint(CCID_IN_EPADDR
);
457 Endpoint_Write_Stream_LE(ResponsePowerOff
, sizeof(USB_CCID_RDR_to_PC_SlotStatus_t
), NULL
);
462 case CCID_PC_to_RDR_GetSlotStatus
:
464 USB_CCID_RDR_to_PC_SlotStatus_t
* ResponseSlotStatus
= (USB_CCID_RDR_to_PC_SlotStatus_t
*)&ResponseBuffer
;
465 ResponseSlotStatus
->CCIDHeader
.MessageType
= CCID_RDR_to_PC_SlotStatus
;
466 ResponseSlotStatus
->CCIDHeader
.Length
= 0;
467 ResponseSlotStatus
->CCIDHeader
.Slot
= CCIDHeader
.Slot
;
468 ResponseSlotStatus
->CCIDHeader
.Seq
= CCIDHeader
.Seq
;
470 ResponseSlotStatus
->ClockStatus
= 0;
472 Status
= CCID_GetSlotStatus(CCIDHeader
.Slot
, &Error
);
474 ResponseSlotStatus
->Status
= Status
;
475 ResponseSlotStatus
->Error
= Error
;
479 Endpoint_SelectEndpoint(CCID_IN_EPADDR
);
480 Endpoint_Write_Stream_LE(ResponseSlotStatus
, sizeof(USB_CCID_RDR_to_PC_SlotStatus_t
), NULL
);
485 case CCID_PC_to_RDR_SetParameters
:
487 uint8_t ProtocolNum
= Endpoint_Read_8();
488 uint8_t RFU
= Endpoint_Read_16_LE();
492 USB_CCID_RDR_to_PC_Parameters_t
* ResponseParametersStatus
= (USB_CCID_RDR_to_PC_Parameters_t
*)&ResponseBuffer
;
493 ResponseParametersStatus
->CCIDHeader
.MessageType
= CCID_RDR_to_PC_Parameters
;
494 ResponseParametersStatus
->CCIDHeader
.Length
= 0;
495 ResponseParametersStatus
->CCIDHeader
.Slot
= CCIDHeader
.Slot
;
496 ResponseParametersStatus
->CCIDHeader
.Seq
= CCIDHeader
.Seq
;
498 if (ProtocolNum
== CCID_PROTOCOLNUM_T0
)
500 if ((CCIDHeader
.Length
* sizeof(uint8_t)) == sizeof(USB_CCID_ProtocolData_T0_t
))
502 Endpoint_Read_Stream_LE(RequestBuffer
, CCIDHeader
.Length
* sizeof(uint8_t), NULL
);
504 Status
= CCID_SetParameters_T0(CCIDHeader
.Slot
, &Error
, (USB_CCID_ProtocolData_T0_t
*)RequestBuffer
);
505 if (CCID_CheckStatusNoError(Status
))
507 ResponseParametersStatus
->CCIDHeader
.Length
= CCIDHeader
.Length
;
508 Status
= CCID_GetParameters_T0(CCIDHeader
.Slot
, &Error
, &ResponseParametersStatus
->ProtocolNum
, (USB_CCID_ProtocolData_T0_t
*) &ResponseParametersStatus
->ProtocolData
);
514 Status
= CCID_COMMANDSTATUS_FAILED
| CCID_ICCSTATUS_PRESENTANDACTIVE
;
519 ResponseParametersStatus
->ProtocolNum
= CCID_PROTOCOLNUM_T0
;
521 // For now, we don't support T=1 protocol
522 Error
= CCID_ERROR_PARAMETERS_PROTOCOL_NOT_SUPPORTED
;
523 Status
= CCID_COMMANDSTATUS_ERROR
| CCID_ICCSTATUS_PRESENTANDACTIVE
;
526 ResponseParametersStatus
->Status
= Status
;
527 ResponseParametersStatus
->Error
= Error
;
531 Endpoint_SelectEndpoint(CCID_IN_EPADDR
);
532 Endpoint_Write_Stream_LE(ResponseParametersStatus
, sizeof(USB_CCID_BulkMessage_Header_t
) + 3 + ResponseParametersStatus
->CCIDHeader
.Length
, NULL
);
537 case CCID_PC_to_RDR_GetParameters
:
539 USB_CCID_RDR_to_PC_Parameters_t
* ResponseParametersStatus
= (USB_CCID_RDR_to_PC_Parameters_t
*)&ResponseBuffer
;
540 ResponseParametersStatus
->CCIDHeader
.MessageType
= CCID_RDR_to_PC_Parameters
;
541 ResponseParametersStatus
->CCIDHeader
.Length
= sizeof(USB_CCID_ProtocolData_T0_t
);
542 ResponseParametersStatus
->CCIDHeader
.Slot
= CCIDHeader
.Slot
;
543 ResponseParametersStatus
->CCIDHeader
.Seq
= CCIDHeader
.Seq
;
545 Status
= CCID_GetParameters_T0(CCIDHeader
.Slot
, &Error
, &ResponseParametersStatus
->ProtocolNum
, (USB_CCID_ProtocolData_T0_t
*) &ResponseParametersStatus
->ProtocolData
);
547 ResponseParametersStatus
->Status
= Status
;
548 ResponseParametersStatus
->Error
= Error
;
552 Endpoint_SelectEndpoint(CCID_IN_EPADDR
);
553 Endpoint_Write_Stream_LE(ResponseParametersStatus
, sizeof(USB_CCID_BulkMessage_Header_t
) + 3 + ResponseParametersStatus
->CCIDHeader
.Length
, NULL
);
558 case CCID_PC_to_RDR_XfrBlock
:
560 uint8_t Bwi
= Endpoint_Read_8();
561 uint16_t LevelParameter
= Endpoint_Read_16_LE();
564 (void)LevelParameter
;
566 Endpoint_Read_Stream_LE(RequestBuffer
, CCIDHeader
.Length
* sizeof(uint8_t), NULL
);
568 uint8_t ResponseDataLength
= 0;
570 USB_CCID_RDR_to_PC_DataBlock_t
* ResponseBlock
= (USB_CCID_RDR_to_PC_DataBlock_t
*)&ResponseBuffer
;
571 ResponseBlock
->CCIDHeader
.MessageType
= CCID_RDR_to_PC_DataBlock
;
572 ResponseBlock
->CCIDHeader
.Slot
= CCIDHeader
.Slot
;
573 ResponseBlock
->CCIDHeader
.Seq
= CCIDHeader
.Seq
;
575 ResponseBlock
->ChainParam
= 0;
577 Status
= CCID_XfrBlock(CCIDHeader
.Slot
, RequestBuffer
, CCIDHeader
.Length
, (uint8_t*) &ResponseBlock
->Data
, &ResponseDataLength
, &Error
);
579 if (CCID_CheckStatusNoError(Status
) && !Aborted
)
581 ResponseBlock
->CCIDHeader
.Length
= ResponseDataLength
;
585 Status
= CCID_COMMANDSTATUS_FAILED
| CCID_ICCSTATUS_PRESENTANDACTIVE
;
586 Error
= CCID_ERROR_CMD_ABORTED
;
587 ResponseDataLength
= 0;
591 ResponseDataLength
= 0;
594 ResponseBlock
->Status
= Status
;
595 ResponseBlock
->Error
= Error
;
599 Endpoint_SelectEndpoint(CCID_IN_EPADDR
);
600 Endpoint_Write_Stream_LE(ResponseBlock
, sizeof(USB_CCID_RDR_to_PC_DataBlock_t
) + ResponseDataLength
, NULL
);
605 case CCID_PC_to_RDR_Abort
:
607 USB_CCID_RDR_to_PC_SlotStatus_t
* ResponseAbort
= (USB_CCID_RDR_to_PC_SlotStatus_t
*)&ResponseBuffer
;
608 ResponseAbort
->CCIDHeader
.MessageType
= CCID_RDR_to_PC_SlotStatus
;
609 ResponseAbort
->CCIDHeader
.Length
= 0;
610 ResponseAbort
->CCIDHeader
.Slot
= CCIDHeader
.Slot
;
611 ResponseAbort
->CCIDHeader
.Seq
= CCIDHeader
.Seq
;
613 ResponseAbort
->ClockStatus
= 0;
615 Status
= CCID_Abort(CCIDHeader
.Slot
, CCIDHeader
.Seq
, &Error
);
617 ResponseAbort
->Status
= Status
;
618 ResponseAbort
->Error
= Error
;
622 Endpoint_SelectEndpoint(CCID_IN_EPADDR
);
623 Endpoint_Write_Stream_LE(ResponseAbort
, sizeof(USB_CCID_RDR_to_PC_SlotStatus_t
), NULL
);
630 memset(ResponseBuffer
, 0x00, sizeof(ResponseBuffer
));
632 Endpoint_SelectEndpoint(CCID_IN_EPADDR
);
633 Endpoint_Write_Stream_LE(ResponseBuffer
, sizeof(ResponseBuffer
), NULL
);