X-Git-Url: http://git.linex4red.de/pub/lufa.git/blobdiff_plain/bc57f4ea5afd29f2e0f0175d14cf1540b4408de8..refs/heads/master:/Demos/Device/LowLevel/CCID/CCID.c diff --git a/Demos/Device/LowLevel/CCID/CCID.c b/Demos/Device/LowLevel/CCID/CCID.c index 764392de0..c21462df4 100644 --- a/Demos/Device/LowLevel/CCID/CCID.c +++ b/Demos/Device/LowLevel/CCID/CCID.c @@ -1,14 +1,14 @@ /* LUFA Library - Copyright (C) Dean Camera, 2018. + Copyright (C) Dean Camera, 2021. dean [at] fourwalledcubicle [dot] com www.lufa-lib.org */ /* - Copyright 2018 Dean Camera (dean [at] fourwalledcubicle [dot] com) - Copyright 2018 Filipe Rodrigues (filipepazrodrigues [at] gmail [dot] com) + Copyright 2021 Dean Camera (dean [at] fourwalledcubicle [dot] com) + Copyright 2021 Filipe Rodrigues (filipepazrodrigues [at] gmail [dot] com) Permission to use, copy, modify, distribute, and sell this software and its documentation for any purpose is hereby granted @@ -53,6 +53,14 @@ static bool Aborted; static uint8_t AbortedSeq; +static USB_CCID_ProtocolData_T0_t ProtocolData = + { + .FindexDindex = 0x11, + .TCCKST0 = 0x00, + .GuardTimeT0 = 0x00, + .WaitingIntegerT0 = 0x0A, + .ClockStop = 0x00, + }; /** Main program entry point. This routine configures the hardware required by the application, then * enters a loop to run the application tasks in sequence. @@ -167,6 +175,7 @@ void EVENT_USB_Device_ControlRequest(void) break; } + case CCID_GET_CLOCK_FREQUENCIES: { if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE)) @@ -178,6 +187,7 @@ void EVENT_USB_Device_ControlRequest(void) break; } + case CCID_GET_DATA_RATES: { if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE)) @@ -196,21 +206,21 @@ void EVENT_USB_Device_ControlRequest(void) * whenever an application at the host wants to send a power off signal to a slot. * THe slot must reply back with a recognizable ATR (answer to reset) */ -uint8_t CCID_IccPowerOn(uint8_t slot, - uint8_t* const atr, - uint8_t* const atrLength, - uint8_t* const error) +uint8_t CCID_IccPowerOn(uint8_t Slot, + uint8_t* const Atr, + uint8_t* const AtrLength, + uint8_t* const Error) { - if (slot == 0) + if (Slot == 0) { - Iso7816_CreateSimpleAtr(atr, atrLength); + Iso7816_CreateSimpleAtr(Atr, AtrLength); - *error = CCID_ERROR_NO_ERROR; + *Error = CCID_ERROR_NO_ERROR; return CCID_COMMANDSTATUS_PROCESSEDWITHOUTERROR | CCID_ICCSTATUS_PRESENTANDACTIVE; } else { - *error = CCID_ERROR_SLOT_NOT_FOUND; + *Error = CCID_ERROR_SLOT_NOT_FOUND; return CCID_COMMANDSTATUS_FAILED | CCID_ICCSTATUS_NOICCPRESENT; } } @@ -218,74 +228,151 @@ uint8_t CCID_IccPowerOn(uint8_t slot, /** Event handler for the CCID_PC_to_RDR_IccPowerOff message. This message is sent to the device * whenever an application at the host wants to send a power off signal to a slot. */ -uint8_t CCID_IccPowerOff(uint8_t slot, - uint8_t* const error) +uint8_t CCID_IccPowerOff(uint8_t Slot, + uint8_t* const Error) { - if (slot == 0) + if (Slot == 0) { - *error = CCID_ERROR_NO_ERROR; + *Error = CCID_ERROR_NO_ERROR; return CCID_COMMANDSTATUS_PROCESSEDWITHOUTERROR | CCID_ICCSTATUS_NOICCPRESENT; } else { - *error = CCID_ERROR_SLOT_NOT_FOUND; + *Error = CCID_ERROR_SLOT_NOT_FOUND; return CCID_COMMANDSTATUS_FAILED | CCID_ICCSTATUS_NOICCPRESENT; } } /** Event handler for the CCID_PC_to_RDR_GetSlotStatus. THis message is sent to - * the device whenever an application at the host wants to the get the current + * the device whenever an application at the host wants to get the current * slot status. */ -uint8_t CCID_GetSlotStatus(uint8_t slot, - uint8_t* const error) +uint8_t CCID_GetSlotStatus(uint8_t Slot, + uint8_t* const Error) +{ + if (Slot == 0) + { + *Error = CCID_ERROR_NO_ERROR; + return CCID_COMMANDSTATUS_PROCESSEDWITHOUTERROR | CCID_ICCSTATUS_PRESENTANDACTIVE; + } + else + { + *Error = CCID_ERROR_SLOT_NOT_FOUND; + return CCID_COMMANDSTATUS_FAILED | CCID_ICCSTATUS_NOICCPRESENT; + } +} + +/** Event handler for the CCID_PC_to_RDR_SetParameters when T=0. This message is sent to + * the device whenever an application at the host wants to set the + * parameters for a given slot. + */ +uint8_t CCID_SetParameters_T0(uint8_t Slot, + uint8_t* const Error, + USB_CCID_ProtocolData_T0_t* const T0) +{ + if (Slot == 0) + { + // Set parameters + memcpy(&ProtocolData, T0, sizeof(USB_CCID_ProtocolData_T0_t)); + + *Error = CCID_ERROR_NO_ERROR; + return CCID_COMMANDSTATUS_PROCESSEDWITHOUTERROR | CCID_ICCSTATUS_PRESENTANDACTIVE; + } + else + { + *Error = CCID_ERROR_SLOT_NOT_FOUND; + return CCID_COMMANDSTATUS_FAILED | CCID_ICCSTATUS_NOICCPRESENT; + } +} + +/** Event handler for the CCID_PC_to_RDR_GetParameters when T=0. This message is sent to + * the device whenever an application at the host wants to get the current + * parameters for a given slot. + */ +uint8_t CCID_GetParameters_T0(uint8_t Slot, + uint8_t* const Error, + uint8_t* ProtocolNum, + USB_CCID_ProtocolData_T0_t* const T0) { - if (slot == 0) + if (Slot == 0) { - *error = CCID_ERROR_NO_ERROR; + + *ProtocolNum = CCID_PROTOCOLNUM_T0; + memcpy(T0, &ProtocolData, sizeof(USB_CCID_ProtocolData_T0_t)); + + *Error = CCID_ERROR_NO_ERROR; return CCID_COMMANDSTATUS_PROCESSEDWITHOUTERROR | CCID_ICCSTATUS_PRESENTANDACTIVE; } else { - *error = CCID_ERROR_SLOT_NOT_FOUND; + *Error = CCID_ERROR_SLOT_NOT_FOUND; return CCID_COMMANDSTATUS_FAILED | CCID_ICCSTATUS_NOICCPRESENT; } } +/** Event handler for the CCID_PC_to_RDR_XfrBlock. This message is sent to the device + * whenever an application at the host wants to send a block of bytes to the device + * THe device reply back with an array of bytes + */ +uint8_t CCID_XfrBlock(uint8_t Slot, + uint8_t* const ReceivedBuffer, + uint8_t ReceivedBufferSize, + uint8_t* const SendBuffer, + uint8_t* const SentBufferSize, + uint8_t* const Error) +{ + if (Slot == 0) + { + uint8_t OkResponse[2] = {0x90, 0x00}; + + memcpy(SendBuffer, OkResponse, sizeof(OkResponse)); + *SentBufferSize = sizeof(OkResponse); + + *Error = CCID_ERROR_NO_ERROR; + return CCID_COMMANDSTATUS_PROCESSEDWITHOUTERROR | CCID_ICCSTATUS_NOICCPRESENT; + } + else + { + *Error = CCID_ERROR_SLOT_NOT_FOUND; + return CCID_COMMANDSTATUS_FAILED | CCID_ICCSTATUS_NOICCPRESENT; + } +} + /** Event handler for the CCID_PC_to_RDR_ABort message. This message is sent to the device * whenever an application wants to abort the current operation. A previous CCID_ABORT * control message has to be sent before this one in order to start the abort operation. */ -uint8_t CCID_Abort(uint8_t slot, - uint8_t seq, - uint8_t* const error) +uint8_t CCID_Abort(uint8_t Slot, + uint8_t Seq, + uint8_t* const Error) { - if (Aborted && slot == 0 && AbortedSeq == seq) + if (Aborted && Slot == 0 && AbortedSeq == Seq) { - Aborted = false; + Aborted = false; AbortedSeq = -1; - *error = CCID_ERROR_NO_ERROR; + + *Error = CCID_ERROR_NO_ERROR; return CCID_COMMANDSTATUS_PROCESSEDWITHOUTERROR | CCID_ICCSTATUS_PRESENTANDACTIVE; } else if (!Aborted) { - *error = CCID_ERROR_CMD_NOT_ABORTED; + *Error = CCID_ERROR_CMD_NOT_ABORTED; return CCID_COMMANDSTATUS_PROCESSEDWITHOUTERROR | CCID_ICCSTATUS_PRESENTANDACTIVE; } - else if (slot != 0) + else if (Slot != 0) { - *error = CCID_ERROR_SLOT_NOT_FOUND; + *Error = CCID_ERROR_SLOT_NOT_FOUND; return CCID_COMMANDSTATUS_FAILED | CCID_ICCSTATUS_NOICCPRESENT; } - *error = CCID_ERROR_NOT_SUPPORTED; + *Error = CCID_ERROR_NOT_SUPPORTED; return CCID_COMMANDSTATUS_FAILED | CCID_ICCSTATUS_NOICCPRESENT; } /** Gets and status and verifies whether an error occurred. */ -bool CCID_CheckStatusNoError(uint8_t status) +bool CCID_CheckStatusNoError(uint8_t Status) { - return (status & 0xC0) == 0x0; + return (Status & 0xC0) == 0x0; } /** Function to manage CCID request parsing and responses back to the host. */ @@ -293,7 +380,8 @@ void CCID_Task(void) { Endpoint_SelectEndpoint(CCID_OUT_EPADDR); - uint8_t BlockBuffer[0x20]; + uint8_t RequestBuffer[CCID_EPSIZE - sizeof(USB_CCID_BulkMessage_Header_t)]; + uint8_t ResponseBuffer[CCID_EPSIZE]; Aborted = false; AbortedSeq = -1; @@ -313,7 +401,7 @@ void CCID_Task(void) case CCID_PC_to_RDR_IccPowerOn: { uint8_t AtrLength; - USB_CCID_RDR_to_PC_DataBlock_t* ResponseATR = (USB_CCID_RDR_to_PC_DataBlock_t*)&BlockBuffer; + USB_CCID_RDR_to_PC_DataBlock_t* ResponseATR = (USB_CCID_RDR_to_PC_DataBlock_t*)&ResponseBuffer; ResponseATR->CCIDHeader.MessageType = CCID_RDR_to_PC_DataBlock; ResponseATR->CCIDHeader.Slot = CCIDHeader.Slot; @@ -350,7 +438,7 @@ void CCID_Task(void) case CCID_PC_to_RDR_IccPowerOff: { - USB_CCID_RDR_to_PC_SlotStatus_t* ResponsePowerOff = (USB_CCID_RDR_to_PC_SlotStatus_t*)&BlockBuffer; + USB_CCID_RDR_to_PC_SlotStatus_t* ResponsePowerOff = (USB_CCID_RDR_to_PC_SlotStatus_t*)&ResponseBuffer; ResponsePowerOff->CCIDHeader.MessageType = CCID_RDR_to_PC_SlotStatus; ResponsePowerOff->CCIDHeader.Length = 0; ResponsePowerOff->CCIDHeader.Slot = CCIDHeader.Slot; @@ -373,7 +461,7 @@ void CCID_Task(void) case CCID_PC_to_RDR_GetSlotStatus: { - USB_CCID_RDR_to_PC_SlotStatus_t* ResponseSlotStatus = (USB_CCID_RDR_to_PC_SlotStatus_t*)&BlockBuffer; + USB_CCID_RDR_to_PC_SlotStatus_t* ResponseSlotStatus = (USB_CCID_RDR_to_PC_SlotStatus_t*)&ResponseBuffer; ResponseSlotStatus->CCIDHeader.MessageType = CCID_RDR_to_PC_SlotStatus; ResponseSlotStatus->CCIDHeader.Length = 0; ResponseSlotStatus->CCIDHeader.Slot = CCIDHeader.Slot; @@ -394,9 +482,132 @@ void CCID_Task(void) break; } + case CCID_PC_to_RDR_SetParameters: + { + uint8_t ProtocolNum = Endpoint_Read_8(); + uint8_t RFU = Endpoint_Read_16_LE(); + + (void)RFU; + + USB_CCID_RDR_to_PC_Parameters_t* ResponseParametersStatus = (USB_CCID_RDR_to_PC_Parameters_t*)&ResponseBuffer; + ResponseParametersStatus->CCIDHeader.MessageType = CCID_RDR_to_PC_Parameters; + ResponseParametersStatus->CCIDHeader.Length = 0; + ResponseParametersStatus->CCIDHeader.Slot = CCIDHeader.Slot; + ResponseParametersStatus->CCIDHeader.Seq = CCIDHeader.Seq; + + if (ProtocolNum == CCID_PROTOCOLNUM_T0) + { + if ((CCIDHeader.Length * sizeof(uint8_t)) == sizeof(USB_CCID_ProtocolData_T0_t)) + { + Endpoint_Read_Stream_LE(RequestBuffer, CCIDHeader.Length * sizeof(uint8_t), NULL); + + Status = CCID_SetParameters_T0(CCIDHeader.Slot, &Error, (USB_CCID_ProtocolData_T0_t*)RequestBuffer); + if (CCID_CheckStatusNoError(Status)) + { + ResponseParametersStatus->CCIDHeader.Length = CCIDHeader.Length; + Status = CCID_GetParameters_T0(CCIDHeader.Slot, &Error, &ResponseParametersStatus->ProtocolNum, (USB_CCID_ProtocolData_T0_t*) &ResponseParametersStatus->ProtocolData); + } + } + else + { + // Unexpected length + Status = CCID_COMMANDSTATUS_FAILED | CCID_ICCSTATUS_PRESENTANDACTIVE; + } + } + else + { + ResponseParametersStatus->ProtocolNum = CCID_PROTOCOLNUM_T0; + + // For now, we don't support T=1 protocol + Error = CCID_ERROR_PARAMETERS_PROTOCOL_NOT_SUPPORTED; + Status = CCID_COMMANDSTATUS_ERROR | CCID_ICCSTATUS_PRESENTANDACTIVE; + } + + ResponseParametersStatus->Status = Status; + ResponseParametersStatus->Error = Error; + + Endpoint_ClearOUT(); + + Endpoint_SelectEndpoint(CCID_IN_EPADDR); + Endpoint_Write_Stream_LE(ResponseParametersStatus, sizeof(USB_CCID_BulkMessage_Header_t) + 3 + ResponseParametersStatus->CCIDHeader.Length, NULL); + Endpoint_ClearIN(); + break; + } + + case CCID_PC_to_RDR_GetParameters: + { + USB_CCID_RDR_to_PC_Parameters_t* ResponseParametersStatus = (USB_CCID_RDR_to_PC_Parameters_t*)&ResponseBuffer; + ResponseParametersStatus->CCIDHeader.MessageType = CCID_RDR_to_PC_Parameters; + ResponseParametersStatus->CCIDHeader.Length = sizeof(USB_CCID_ProtocolData_T0_t); + ResponseParametersStatus->CCIDHeader.Slot = CCIDHeader.Slot; + ResponseParametersStatus->CCIDHeader.Seq = CCIDHeader.Seq; + + Status = CCID_GetParameters_T0(CCIDHeader.Slot, &Error, &ResponseParametersStatus->ProtocolNum, (USB_CCID_ProtocolData_T0_t*) &ResponseParametersStatus->ProtocolData); + + ResponseParametersStatus->Status = Status; + ResponseParametersStatus->Error = Error; + + Endpoint_ClearOUT(); + + Endpoint_SelectEndpoint(CCID_IN_EPADDR); + Endpoint_Write_Stream_LE(ResponseParametersStatus, sizeof(USB_CCID_BulkMessage_Header_t) + 3 + ResponseParametersStatus->CCIDHeader.Length, NULL); + Endpoint_ClearIN(); + break; + } + + case CCID_PC_to_RDR_XfrBlock: + { + uint8_t Bwi = Endpoint_Read_8(); + uint16_t LevelParameter = Endpoint_Read_16_LE(); + + (void)Bwi; + (void)LevelParameter; + + if (CCIDHeader.Length * sizeof(uint8_t) > sizeof(RequestBuffer)) + break; + + Endpoint_Read_Stream_LE(RequestBuffer, CCIDHeader.Length * sizeof(uint8_t), NULL); + + uint8_t ResponseDataLength = 0; + + USB_CCID_RDR_to_PC_DataBlock_t* ResponseBlock = (USB_CCID_RDR_to_PC_DataBlock_t*)&ResponseBuffer; + ResponseBlock->CCIDHeader.MessageType = CCID_RDR_to_PC_DataBlock; + ResponseBlock->CCIDHeader.Slot = CCIDHeader.Slot; + ResponseBlock->CCIDHeader.Seq = CCIDHeader.Seq; + + ResponseBlock->ChainParam = 0; + + Status = CCID_XfrBlock(CCIDHeader.Slot, RequestBuffer, CCIDHeader.Length, (uint8_t*) &ResponseBlock->Data, &ResponseDataLength, &Error); + + if (CCID_CheckStatusNoError(Status) && !Aborted) + { + ResponseBlock->CCIDHeader.Length = ResponseDataLength; + } + else if (Aborted) + { + Status = CCID_COMMANDSTATUS_FAILED | CCID_ICCSTATUS_PRESENTANDACTIVE; + Error = CCID_ERROR_CMD_ABORTED; + ResponseDataLength = 0; + } + else + { + ResponseDataLength = 0; + } + + ResponseBlock->Status = Status; + ResponseBlock->Error = Error; + + Endpoint_ClearOUT(); + + Endpoint_SelectEndpoint(CCID_IN_EPADDR); + Endpoint_Write_Stream_LE(ResponseBlock, sizeof(USB_CCID_RDR_to_PC_DataBlock_t) + ResponseDataLength, NULL); + Endpoint_ClearIN(); + break; + } + case CCID_PC_to_RDR_Abort: { - USB_CCID_RDR_to_PC_SlotStatus_t* ResponseAbort = (USB_CCID_RDR_to_PC_SlotStatus_t*)&BlockBuffer; + USB_CCID_RDR_to_PC_SlotStatus_t* ResponseAbort = (USB_CCID_RDR_to_PC_SlotStatus_t*)&ResponseBuffer; ResponseAbort->CCIDHeader.MessageType = CCID_RDR_to_PC_SlotStatus; ResponseAbort->CCIDHeader.Length = 0; ResponseAbort->CCIDHeader.Slot = CCIDHeader.Slot; @@ -416,12 +627,13 @@ void CCID_Task(void) Endpoint_ClearIN(); break; } + default: { - memset(BlockBuffer, 0x00, sizeof(BlockBuffer)); + memset(ResponseBuffer, 0x00, sizeof(ResponseBuffer)); Endpoint_SelectEndpoint(CCID_IN_EPADDR); - Endpoint_Write_Stream_LE(BlockBuffer, sizeof(BlockBuffer), NULL); + Endpoint_Write_Stream_LE(ResponseBuffer, sizeof(ResponseBuffer), NULL); Endpoint_ClearIN(); } }