3      Copyright (C) Dean Camera, 2020. 
   5   dean [at] fourwalledcubicle [dot] com 
  10   Copyright 2020  Dean Camera (dean [at] fourwalledcubicle [dot] com) 
  11   Copyright 2020  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 
  32 #define  __INCLUDE_FROM_USB_DRIVER 
  33 #include "../../Core/USBMode.h" 
  35 #if defined(USB_CAN_BE_DEVICE) 
  37 #define  __INCLUDE_FROM_CCID_DRIVER 
  38 #define  __INCLUDE_FROM_CCID_DEVICE_C 
  39 #include "CCIDClassDevice.h" 
  42 bool CCID_CheckStatusNoError(uint8_t Status
) 
  44         return (Status 
& 0xC0) == 0x0; 
  47 void CCID_Device_ProcessControlRequest(USB_ClassInfo_CCID_Device_t
* const CCIDInterfaceInfo
) 
  49         if (!(Endpoint_IsSETUPReceived())) 
  52         if (USB_ControlRequest
.wIndex 
!= CCIDInterfaceInfo
->Config
.InterfaceNumber
) 
  55         switch (USB_ControlRequest
.bRequest
) 
  59                         // Initiates the abort process. 
  60                         // The host should send 2 messages in the following order: 
  61                         //      - CCID_ABORT control request 
  62                         //      - CCID_PC_t_PCo_RDR_Abort command 
  64                         // If the device is still processing a message, it should fail it until receiving a CCIRPC_to_RDR_Abort 
  67                         // When the device receives the CCIRPC_to_RDR_Abort message, it replies with RDR_to_PC_SlotStatus 
  68                         // and the abort process ends. 
  70                         // The wValue field contains the slot number (bSlot) in the low byte and the sequence number (bSeq) in 
  72                         uint8_t Slot 
= USB_ControlRequest
.wValue 
& 0xFF; 
  73                         uint8_t Seq  
= USB_ControlRequest
.wValue 
>> 8; 
  75                         if (USB_ControlRequest
.bmRequestType 
== (REQDIR_DEVICETOHOST 
| REQTYPE_CLASS 
| REQREC_INTERFACE
) && Slot 
== 0) 
  77                                 Endpoint_ClearSETUP(); 
  79                                 CCIDInterfaceInfo
->State
.Aborted 
= true; 
  80                                 CCIDInterfaceInfo
->State
.AbortedSeq 
= Seq
; 
  88                 case CCID_GET_CLOCK_FREQUENCIES
: 
  90                         if (USB_ControlRequest
.bmRequestType 
== (REQDIR_DEVICETOHOST 
| REQTYPE_CLASS 
| REQREC_INTERFACE
)) 
  93                                 Endpoint_ClearSETUP(); 
  94                                 Endpoint_Write_8(0); // Not supported 
 100                 case CCID_GET_DATA_RATES
: 
 102                         if (USB_ControlRequest
.bmRequestType 
== (REQDIR_DEVICETOHOST 
| REQTYPE_CLASS 
| REQREC_INTERFACE
)) 
 105                                 Endpoint_ClearSETUP(); 
 106                                 Endpoint_Write_8(0); // Not supported 
 114 bool CCID_Device_ConfigureEndpoints(USB_ClassInfo_CCID_Device_t
* const CCIDInterfaceInfo
) 
 116         CCIDInterfaceInfo
->Config
.DataINEndpoint
.Type  
= EP_TYPE_BULK
; 
 117         CCIDInterfaceInfo
->Config
.DataOUTEndpoint
.Type 
= EP_TYPE_BULK
; 
 119         if (!(Endpoint_ConfigureEndpointTable(&CCIDInterfaceInfo
->Config
.DataINEndpoint
, 1))) 
 122         if (!(Endpoint_ConfigureEndpointTable(&CCIDInterfaceInfo
->Config
.DataOUTEndpoint
, 1))) 
 128 void CCID_Device_USBTask(USB_ClassInfo_CCID_Device_t
* const CCIDInterfaceInfo
) 
 130         Endpoint_SelectEndpoint(CCIDInterfaceInfo
->Config
.DataOUTEndpoint
.Address
); 
 132         uint8_t RequestBuffer
[0x40 - sizeof(USB_CCID_BulkMessage_Header_t
)]; 
 133         uint8_t ResponseBuffer
[0x40]; 
 135         CCIDInterfaceInfo
->State
.Aborted    
= false; 
 136         CCIDInterfaceInfo
->State
.AbortedSeq 
= -1; 
 138         if (Endpoint_IsOUTReceived()) 
 140                 USB_CCID_BulkMessage_Header_t CCIDHeader
; 
 141                 CCIDHeader
.MessageType 
= Endpoint_Read_8(); 
 142                 CCIDHeader
.Length      
= Endpoint_Read_32_LE(); 
 143                 CCIDHeader
.Slot        
= Endpoint_Read_8(); 
 144                 CCIDHeader
.Seq         
= Endpoint_Read_8(); 
 147                 uint8_t Error 
= CCID_ERROR_NO_ERROR
; 
 149                 switch (CCIDHeader
.MessageType
) 
 151                         case CCID_PC_to_RDR_IccPowerOn
: 
 154                                 USB_CCID_RDR_to_PC_DataBlock_t
* ResponseATR 
= (USB_CCID_RDR_to_PC_DataBlock_t
*)&ResponseBuffer
; 
 156                                 ResponseATR
->CCIDHeader
.MessageType 
= CCID_RDR_to_PC_DataBlock
; 
 157                                 ResponseATR
->CCIDHeader
.Slot        
= CCIDHeader
.Slot
; 
 158                                 ResponseATR
->CCIDHeader
.Seq         
= CCIDHeader
.Seq
; 
 159                                 ResponseATR
->ChainParam             
= 0; 
 161                                 Status 
= CALLBACK_CCID_IccPowerOn(CCIDInterfaceInfo
, ResponseATR
->CCIDHeader
.Slot
, (uint8_t*)ResponseATR
->Data
, &AtrLength
, &Error
); 
 163                                 if (CCID_CheckStatusNoError(Status
) && !CCIDInterfaceInfo
->State
.Aborted
) 
 165                                         ResponseATR
->CCIDHeader
.Length 
= AtrLength
; 
 167                                 else if (CCIDInterfaceInfo
->State
.Aborted
) 
 169                                         Status 
= CCID_COMMANDSTATUS_FAILED 
| CCID_ICCSTATUS_PRESENTANDACTIVE
; 
 170                                         Error  
= CCID_ERROR_CMD_ABORTED
; 
 178                                 ResponseATR
->Status 
= Status
; 
 179                                 ResponseATR
->Error  
= Error
; 
 183                                 Endpoint_SelectEndpoint(CCIDInterfaceInfo
->Config
.DataINEndpoint
.Address
); 
 184                                 Endpoint_Write_Stream_LE(ResponseATR
, sizeof(USB_CCID_RDR_to_PC_DataBlock_t
) + AtrLength
, NULL
); 
 189                         case CCID_PC_to_RDR_IccPowerOff
: 
 191                                 USB_CCID_RDR_to_PC_SlotStatus_t
* ResponsePowerOff 
= (USB_CCID_RDR_to_PC_SlotStatus_t
*)&ResponseBuffer
; 
 192                                 ResponsePowerOff
->CCIDHeader
.MessageType 
= CCID_RDR_to_PC_SlotStatus
; 
 193                                 ResponsePowerOff
->CCIDHeader
.Length      
= 0; 
 194                                 ResponsePowerOff
->CCIDHeader
.Slot        
= CCIDHeader
.Slot
; 
 195                                 ResponsePowerOff
->CCIDHeader
.Seq         
= CCIDHeader
.Seq
; 
 197                                 ResponsePowerOff
->ClockStatus 
= 0; 
 199                                 Status 
= CALLBACK_CCID_IccPowerOff(CCIDInterfaceInfo
, CCIDHeader
.Slot
, &Error
); 
 201                                 ResponsePowerOff
->Status 
= Status
; 
 202                                 ResponsePowerOff
->Error  
= Error
; 
 206                                 Endpoint_SelectEndpoint(CCIDInterfaceInfo
->Config
.DataINEndpoint
.Address
); 
 207                                 Endpoint_Write_Stream_LE(ResponsePowerOff
, sizeof(USB_CCID_RDR_to_PC_SlotStatus_t
), NULL
); 
 212                         case CCID_PC_to_RDR_GetSlotStatus
: 
 214                                 USB_CCID_RDR_to_PC_SlotStatus_t
* ResponseSlotStatus 
= (USB_CCID_RDR_to_PC_SlotStatus_t
*)&ResponseBuffer
; 
 215                                 ResponseSlotStatus
->CCIDHeader
.MessageType 
= CCID_RDR_to_PC_SlotStatus
; 
 216                                 ResponseSlotStatus
->CCIDHeader
.Length      
= 0; 
 217                                 ResponseSlotStatus
->CCIDHeader
.Slot        
= CCIDHeader
.Slot
; 
 218                                 ResponseSlotStatus
->CCIDHeader
.Seq         
= CCIDHeader
.Seq
; 
 220                                 ResponseSlotStatus
->ClockStatus 
= 0; 
 222                                 Status 
= CALLBACK_CCID_GetSlotStatus(CCIDInterfaceInfo
, CCIDHeader
.Slot
, &Error
); 
 224                                 ResponseSlotStatus
->Status 
= Status
; 
 225                                 ResponseSlotStatus
->Error  
= Error
; 
 229                                 Endpoint_SelectEndpoint(CCIDInterfaceInfo
->Config
.DataINEndpoint
.Address
); 
 230                                 Endpoint_Write_Stream_LE(ResponseSlotStatus
, sizeof(USB_CCID_RDR_to_PC_SlotStatus_t
), NULL
); 
 235                         case CCID_PC_to_RDR_SetParameters
: 
 237                                 uint8_t ProtocolNum 
= Endpoint_Read_8(); 
 238                                 uint8_t RFU         
= Endpoint_Read_16_LE(); 
 242                                 USB_CCID_RDR_to_PC_Parameters_t
* ResponseParametersStatus 
= (USB_CCID_RDR_to_PC_Parameters_t
*)&ResponseBuffer
; 
 243                                 ResponseParametersStatus
->CCIDHeader
.MessageType 
= CCID_RDR_to_PC_Parameters
; 
 244                                 ResponseParametersStatus
->CCIDHeader
.Length      
= 0; 
 245                                 ResponseParametersStatus
->CCIDHeader
.Slot        
= CCIDHeader
.Slot
; 
 246                                 ResponseParametersStatus
->CCIDHeader
.Seq         
= CCIDHeader
.Seq
; 
 248                                 if (ProtocolNum 
== CCID_PROTOCOLNUM_T0
) 
 250                                         if (CCIDHeader
.Length 
* sizeof(uint8_t) == sizeof(USB_CCID_ProtocolData_T0_t
)) 
 253                                                 Endpoint_Read_Stream_LE(RequestBuffer
, CCIDHeader
.Length 
* sizeof(uint8_t), NULL
); 
 254                                                 Status 
= CALLBACK_CCID_SetParameters_T0(CCIDInterfaceInfo
, CCIDHeader
.Slot
, &Error
, (USB_CCID_ProtocolData_T0_t
*) RequestBuffer
); 
 255                                                 if (CCID_CheckStatusNoError(Status
)) 
 257                                                         ResponseParametersStatus
->CCIDHeader
.Length 
= CCIDHeader
.Length
; 
 258                                                         Status 
= CALLBACK_CCID_GetParameters_T0(CCIDInterfaceInfo
, CCIDHeader
.Slot
, &Error
, &ResponseParametersStatus
->ProtocolNum
, (USB_CCID_ProtocolData_T0_t
*) &ResponseParametersStatus
->ProtocolData
); 
 264                                                 Status 
= CCID_COMMANDSTATUS_FAILED 
| CCID_ICCSTATUS_PRESENTANDACTIVE
; 
 269                                         ResponseParametersStatus
->ProtocolNum 
= CCID_PROTOCOLNUM_T0
; 
 271                                         // For now, we don't support T=1 protocol 
 272                                         Error  
= CCID_ERROR_PARAMETERS_PROTOCOL_NOT_SUPPORTED
; 
 273                                         Status 
= CCID_COMMANDSTATUS_ERROR 
| CCID_ICCSTATUS_PRESENTANDACTIVE
; 
 276                                 ResponseParametersStatus
->Status 
= Status
; 
 277                                 ResponseParametersStatus
->Error  
= Error
; 
 281                                 Endpoint_SelectEndpoint(CCIDInterfaceInfo
->Config
.DataINEndpoint
.Address
); 
 282                                 Endpoint_Write_Stream_LE(ResponseParametersStatus
, sizeof(USB_CCID_BulkMessage_Header_t
) + 3 + ResponseParametersStatus
->CCIDHeader
.Length 
, NULL
); 
 287                         case CCID_PC_to_RDR_GetParameters
: 
 289                                 USB_CCID_RDR_to_PC_Parameters_t
* ResponseParametersStatus 
= (USB_CCID_RDR_to_PC_Parameters_t
*)&ResponseBuffer
; 
 290                                 ResponseParametersStatus
->CCIDHeader
.MessageType 
= CCID_RDR_to_PC_Parameters
; 
 291                                 ResponseParametersStatus
->CCIDHeader
.Length      
= sizeof(USB_CCID_ProtocolData_T0_t
); 
 292                                 ResponseParametersStatus
->CCIDHeader
.Slot        
= CCIDHeader
.Slot
; 
 293                                 ResponseParametersStatus
->CCIDHeader
.Seq         
= CCIDHeader
.Seq
; 
 295                                 Status 
= CALLBACK_CCID_GetParameters_T0(CCIDInterfaceInfo
, CCIDHeader
.Slot
, &Error
, &ResponseParametersStatus
->ProtocolNum
, (USB_CCID_ProtocolData_T0_t
*) &ResponseParametersStatus
->ProtocolData
); 
 297                                 ResponseParametersStatus
->Status 
= Status
; 
 298                                 ResponseParametersStatus
->Error  
= Error
; 
 302                                 Endpoint_SelectEndpoint(CCIDInterfaceInfo
->Config
.DataINEndpoint
.Address
); 
 303                                 Endpoint_Write_Stream_LE(ResponseParametersStatus
, sizeof(USB_CCID_BulkMessage_Header_t
) + 3 + ResponseParametersStatus
->CCIDHeader
.Length 
, NULL
); 
 308                         case CCID_PC_to_RDR_XfrBlock
: 
 310                                 uint8_t  Bwi            
= Endpoint_Read_8(); 
 311                                 uint16_t LevelParameter 
= Endpoint_Read_16_LE(); 
 312                                 uint8_t  ReceivedBuffer
[0x4]; 
 315                                 (void)LevelParameter
; 
 317                                 Endpoint_Read_Stream_LE(ReceivedBuffer
, sizeof(ReceivedBuffer
), NULL
); 
 319                                 uint8_t ResponseDataLength 
= 0; 
 321                                 USB_CCID_RDR_to_PC_DataBlock_t
* ResponseBlock 
= (USB_CCID_RDR_to_PC_DataBlock_t
*)&ResponseBuffer
; 
 322                                 ResponseBlock
->CCIDHeader
.MessageType 
= CCID_RDR_to_PC_DataBlock
; 
 323                                 ResponseBlock
->CCIDHeader
.Slot        
= CCIDHeader
.Slot
; 
 324                                 ResponseBlock
->CCIDHeader
.Seq         
= CCIDHeader
.Seq
; 
 326                                 ResponseBlock
->ChainParam 
= 0; 
 328                                 Status 
= CALLBACK_CCID_XfrBlock(CCIDInterfaceInfo
, CCIDHeader
.Slot
, RequestBuffer
, CCIDHeader
.Length
, (uint8_t*) &ResponseBlock
->Data
, &ResponseDataLength
, &Error
); 
 330                                 if (CCID_CheckStatusNoError(Status
) && !CCIDInterfaceInfo
->State
.Aborted
) 
 332                                         ResponseBlock
->CCIDHeader
.Length 
= ResponseDataLength
; 
 334                                 else if (CCIDInterfaceInfo
->State
.Aborted
) 
 336                                         Status 
= CCID_COMMANDSTATUS_FAILED 
| CCID_ICCSTATUS_PRESENTANDACTIVE
; 
 337                                         Error  
= CCID_ERROR_CMD_ABORTED
; 
 338                                         ResponseDataLength 
= 0; 
 342                                         ResponseDataLength 
= 0; 
 345                                 ResponseBlock
->Status 
= Status
; 
 346                                 ResponseBlock
->Error  
= Error
; 
 350                                 Endpoint_SelectEndpoint(CCIDInterfaceInfo
->Config
.DataINEndpoint
.Address
); 
 351                                 Endpoint_Write_Stream_LE(ResponseBlock
, sizeof(USB_CCID_RDR_to_PC_DataBlock_t
) + ResponseDataLength
, NULL
); 
 356                         case CCID_PC_to_RDR_Abort
: 
 358                                 USB_CCID_RDR_to_PC_SlotStatus_t
* ResponseAbort 
= (USB_CCID_RDR_to_PC_SlotStatus_t
*)&ResponseBuffer
; 
 359                                 ResponseAbort
->CCIDHeader
.MessageType 
= CCID_RDR_to_PC_SlotStatus
; 
 360                                 ResponseAbort
->CCIDHeader
.Length      
= 0; 
 361                                 ResponseAbort
->CCIDHeader
.Slot        
= CCIDHeader
.Slot
; 
 362                                 ResponseAbort
->CCIDHeader
.Seq         
= CCIDHeader
.Seq
; 
 364                                 ResponseAbort
->ClockStatus 
= 0; 
 366                                 Status 
= CALLBACK_CCID_Abort(CCIDInterfaceInfo
, CCIDHeader
.Slot
, CCIDHeader
.Seq
, &Error
); 
 368                                 ResponseAbort
->Status 
= Status
; 
 369                                 ResponseAbort
->Error  
= Error
; 
 373                                 Endpoint_SelectEndpoint(CCIDInterfaceInfo
->Config
.DataINEndpoint
.Address
); 
 374                                 Endpoint_Write_Stream_LE(ResponseAbort
, sizeof(USB_CCID_RDR_to_PC_SlotStatus_t
), NULL
); 
 381                                 memset(ResponseBuffer
, 0x00, sizeof(ResponseBuffer
)); 
 383                                 Endpoint_SelectEndpoint(CCIDInterfaceInfo
->Config
.DataINEndpoint
.Address
); 
 384                                 Endpoint_Write_Stream_LE(ResponseBuffer
, sizeof(ResponseBuffer
), NULL
);