From 1e9e7bc8b88af32f466f7438a06fb8dc96b3035d Mon Sep 17 00:00:00 2001
From: Filipe Rodrigues <filipepazrodrigues@gmail.com>
Date: Sun, 17 Jun 2018 17:51:09 -0700
Subject: [PATCH] CCID: Add support for PC-to-Reader XfrBlock message

---
 Demos/Device/ClassDriver/CCID/CCID.c          | 28 ++++++
 Demos/Device/ClassDriver/CCID/CCID.h          |  7 ++
 Demos/Device/ClassDriver/CCID/Descriptors.c   |  4 +-
 Demos/Device/ClassDriver/CCID/Descriptors.h   |  2 +-
 Demos/Device/LowLevel/CCID/CCID.c             | 89 +++++++++++++++++--
 Demos/Device/LowLevel/CCID/Descriptors.c      |  4 +-
 .../HostTestApp/test_generic_ccid_libusb.js   | 15 ++--
 .../USB/Class/Common/CCIDClassCommon.h        | 20 +++++
 .../USB/Class/Device/CCIDClassDevice.c        | 64 +++++++++++--
 .../USB/Class/Device/CCIDClassDevice.h        | 22 +++++
 10 files changed, 231 insertions(+), 24 deletions(-)

diff --git a/Demos/Device/ClassDriver/CCID/CCID.c b/Demos/Device/ClassDriver/CCID/CCID.c
index 9059ad40d..bb4c11c45 100644
--- a/Demos/Device/ClassDriver/CCID/CCID.c
+++ b/Demos/Device/ClassDriver/CCID/CCID.c
@@ -213,6 +213,34 @@ uint8_t CALLBACK_CCID_GetSlotStatus(USB_ClassInfo_CCID_Device_t* const CCIDInter
 	}
 }
 
+/** 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 CALLBACK_CCID_XfrBlock(USB_ClassInfo_CCID_Device_t* const CCIDInterfaceInfo,
+							   uint8_t slot,
+							   uint8_t* const receivedBuffer,
+							   uint8_t receivedBufferSize,
+							   uint8_t* const sendBuffer,
+							   uint8_t* const sentBufferSize,
+							   uint8_t* const error)
+{
+	if (slot < CCID_Interface.Config.TotalSlots)
+	{
+		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;
+	}
+}
+
 uint8_t CALLBACK_CCID_Abort(USB_ClassInfo_CCID_Device_t* const CCIDInterfaceInfo,
                             uint8_t slot,
 							uint8_t seq,
diff --git a/Demos/Device/ClassDriver/CCID/CCID.h b/Demos/Device/ClassDriver/CCID/CCID.h
index f6dd4adf5..88c29aef1 100644
--- a/Demos/Device/ClassDriver/CCID/CCID.h
+++ b/Demos/Device/ClassDriver/CCID/CCID.h
@@ -86,6 +86,13 @@
 		uint8_t CALLBACK_CCID_GetSlotStatus(USB_ClassInfo_CCID_Device_t* const CCIDInterfaceInfo,
 		                                    uint8_t slot,
 		                                    uint8_t* const error);
+		uint8_t CALLBACK_CCID_XfrBlock(USB_ClassInfo_CCID_Device_t* const CCIDInterfaceInfo,
+									   uint8_t slot,
+									   uint8_t* const receivedBuffer,
+									   uint8_t receivedBufferSize,
+									   uint8_t* const sendBuffer,
+									   uint8_t* const sentBufferSize,
+									   uint8_t* const error);
 		uint8_t CALLBACK_CCID_Abort(USB_ClassInfo_CCID_Device_t* const CCIDInterfaceInfo,
 		                            uint8_t slot,
 		                            uint8_t seq,
diff --git a/Demos/Device/ClassDriver/CCID/Descriptors.c b/Demos/Device/ClassDriver/CCID/Descriptors.c
index 43a696194..886042668 100644
--- a/Demos/Device/ClassDriver/CCID/Descriptors.c
+++ b/Demos/Device/ClassDriver/CCID/Descriptors.c
@@ -117,8 +117,8 @@ const USB_Descriptor_Configuration_t PROGMEM ConfigurationDescriptor =
 			.MaxIFSD				= 2038,
 			.SynchProtocols			= 0,
 			.Mechanical				= 0,
-			.Features				= 0x0400fe,
-			.MaxCCIDMessageLength	= 0x0c00,
+			.Features				= CCID_Features_ExchangeLevel_ShortAPDU | CCID_Features_Auto_ParameterConfiguration| CCID_Features_Auto_ICCActivation | CCID_Features_Auto_VoltageSelection,
+			.MaxCCIDMessageLength	= CCID_EPSIZE,
 			.ClassGetResponse		= 0xff,
 			.ClassEnvelope			= 0xff,
 			.LcdLayout				= 0,
diff --git a/Demos/Device/ClassDriver/CCID/Descriptors.h b/Demos/Device/ClassDriver/CCID/Descriptors.h
index 239d612ab..63672d1b7 100644
--- a/Demos/Device/ClassDriver/CCID/Descriptors.h
+++ b/Demos/Device/ClassDriver/CCID/Descriptors.h
@@ -49,7 +49,7 @@
 		/** Endpoint address of the CCID data OUT endpoint, for host-to-device data transfers. */
 		#define CCID_OUT_EPADDR      (ENDPOINT_DIR_OUT | 1)
 
-		/** Endpoint size in bytes of the Audio isochronous streaming data IN and OUT endpoints. */
+		/** Endpoint size in bytes of the CCID data being sent between IN and OUT endpoints. */
 		#define CCID_EPSIZE          64
 
 
diff --git a/Demos/Device/LowLevel/CCID/CCID.c b/Demos/Device/LowLevel/CCID/CCID.c
index 764392de0..24849dc12 100644
--- a/Demos/Device/LowLevel/CCID/CCID.c
+++ b/Demos/Device/LowLevel/CCID/CCID.c
@@ -252,6 +252,33 @@ uint8_t CCID_GetSlotStatus(uint8_t slot,
 	}
 }
 
+/** 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.
@@ -293,7 +320,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 +341,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 +378,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 +401,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 +422,56 @@ void CCID_Task(void)
 				break;
 			}
 
+			case CCID_PC_to_RDR_XfrBlock:
+			{
+				uint8_t  Bwi            = Endpoint_Read_8();
+				uint16_t LevelParameter = Endpoint_Read_16_LE();
+
+				(void)Bwi;
+				(void)LevelParameter;
+
+				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, &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;
@@ -418,10 +493,10 @@ void CCID_Task(void)
 			}
 			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();
 			}
 		}
diff --git a/Demos/Device/LowLevel/CCID/Descriptors.c b/Demos/Device/LowLevel/CCID/Descriptors.c
index c82216c9b..5e092e2e4 100644
--- a/Demos/Device/LowLevel/CCID/Descriptors.c
+++ b/Demos/Device/LowLevel/CCID/Descriptors.c
@@ -119,8 +119,8 @@ const USB_Descriptor_Configuration_t PROGMEM ConfigurationDescriptor =
 			.MaxIFSD				= 2038,
 			.SynchProtocols			= 0,
 			.Mechanical				= 0,
-			.Features				= 0x0400fe,
-			.MaxCCIDMessageLength	= 0x0c00,
+			.Features				= CCID_Features_ExchangeLevel_ShortAPDU | CCID_Features_Auto_ParameterConfiguration| CCID_Features_Auto_ICCActivation | CCID_Features_Auto_VoltageSelection,
+			.MaxCCIDMessageLength	= CCID_EPSIZE,
 			.ClassGetResponse		= 0xff,
 			.ClassEnvelope			= 0xff,
 			.LcdLayout				= 0,
diff --git a/Demos/Device/LowLevel/CCID/HostTestApp/test_generic_ccid_libusb.js b/Demos/Device/LowLevel/CCID/HostTestApp/test_generic_ccid_libusb.js
index 993c0e550..e521cdb5a 100644
--- a/Demos/Device/LowLevel/CCID/HostTestApp/test_generic_ccid_libusb.js
+++ b/Demos/Device/LowLevel/CCID/HostTestApp/test_generic_ccid_libusb.js
@@ -106,17 +106,16 @@ function GetSlotStatusMessage(slot, seq)
     ];
 }
 
-function XfrBlockMessage(slot, seq)
+function XfrBlockMessage(slot, seq, apdu)
 {
     return [
         CCID_PC_to_RDR_XfrBlock, //message type
-        5, 0, 0, 0, //length (05)
+        apdu.length, 0, 0, 0, //length: only for < 0xFF
         slot,
         seq,
         0, //BWI 
-        0, 0, //level parameter
-        0, 0xfd, 0, 0, 0 //message
-    ];
+        0, 0 //level parameter
+    ].concat(apdu);
 
 }
 
@@ -140,6 +139,12 @@ function startTest()
         },
         function(callback) {
             read(ccidInterface, 10, callback);
+        },
+        function(callback) {
+            write(ccidInterface, new Buffer(XfrBlockMessage(0, 4, [0x0, 0xFD, 0x0, 0x0, 0x0])), callback);
+        },
+        function(callback) {
+            read(ccidInterface, 10 + 2, callback);
         }
         ]);
 }
diff --git a/LUFA/Drivers/USB/Class/Common/CCIDClassCommon.h b/LUFA/Drivers/USB/Class/Common/CCIDClassCommon.h
index 6cedcad36..cf8fdbae0 100644
--- a/LUFA/Drivers/USB/Class/Common/CCIDClassCommon.h
+++ b/LUFA/Drivers/USB/Class/Common/CCIDClassCommon.h
@@ -153,6 +153,26 @@
 			CCID_DTYPE_Functional                       = 0x21, /**< CCID class specific Interface functional descriptor. */
 		};
 
+		enum CCID_Features_Auto_t
+		{
+			CCID_Features_Auto_None 					= 0x0,
+			CCID_Features_Auto_ParameterConfiguration	= 0x2,
+			CCID_Features_Auto_ICCActivation			= 0x4,
+			CCID_Features_Auto_VoltageSelection			= 0x8,
+
+			CCID_Features_Auto_ICCClockFrequencyChange	= 0x10,
+			CCID_Features_Auto_ICCBaudRateChange		= 0x20,
+			CCID_Features_Auto_ParameterNegotiation		= 0x40,
+			CCID_Features_Auto_PPS						= 0x80,
+		};
+
+		enum CCID_Features_ExchangeLevel_t
+		{
+			CCID_Features_ExchangeLevel_TPDU  				= 0x00010000,
+			CCID_Features_ExchangeLevel_ShortAPDU 			= 0x00020000,
+			CCID_Features_ExchangeLevel_ShortExtendedAPDU	= 0x00040000
+		};
+
 	/* Type Defines: */
 		typedef struct
 		{
diff --git a/LUFA/Drivers/USB/Class/Device/CCIDClassDevice.c b/LUFA/Drivers/USB/Class/Device/CCIDClassDevice.c
index 0595e0715..450ed9d9c 100644
--- a/LUFA/Drivers/USB/Class/Device/CCIDClassDevice.c
+++ b/LUFA/Drivers/USB/Class/Device/CCIDClassDevice.c
@@ -129,7 +129,9 @@ void CCID_Device_USBTask(USB_ClassInfo_CCID_Device_t* const CCIDInterfaceInfo)
 {
 	Endpoint_SelectEndpoint(CCIDInterfaceInfo->Config.DataOUTEndpoint.Address);
 
-	uint8_t BlockBuffer[0x20];
+	uint8_t RequestBuffer[0x40 - sizeof(USB_CCID_BulkMessage_Header_t)];
+	uint8_t ResponseBuffer[0x40];
+
 	CCIDInterfaceInfo->State.Aborted    = false;
 	CCIDInterfaceInfo->State.AbortedSeq = -1;
 
@@ -149,7 +151,7 @@ void CCID_Device_USBTask(USB_ClassInfo_CCID_Device_t* const CCIDInterfaceInfo)
 			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;
@@ -186,7 +188,7 @@ void CCID_Device_USBTask(USB_ClassInfo_CCID_Device_t* const CCIDInterfaceInfo)
 
 			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;
@@ -209,7 +211,7 @@ void CCID_Device_USBTask(USB_ClassInfo_CCID_Device_t* const CCIDInterfaceInfo)
 
 			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;
@@ -230,9 +232,57 @@ void CCID_Device_USBTask(USB_ClassInfo_CCID_Device_t* const CCIDInterfaceInfo)
 				break;
 			}
 
+			case CCID_PC_to_RDR_XfrBlock:
+			{
+				uint8_t  Bwi            = Endpoint_Read_8();
+				uint16_t LevelParameter = Endpoint_Read_16_LE();
+				uint8_t  ReceivedBuffer[0x4];
+
+				(void)Bwi;
+				(void)LevelParameter;
+
+				Endpoint_Read_Stream_LE(ReceivedBuffer, sizeof(ReceivedBuffer), 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 = CALLBACK_CCID_XfrBlock(CCIDInterfaceInfo, CCIDHeader.Slot, RequestBuffer, CCIDHeader.Length, (uint8_t*) &ResponseBlock->Data, &ResponseDataLength, &Error);
+
+				if (CCID_CheckStatusNoError(Status) && !CCIDInterfaceInfo->State.Aborted)
+				{
+					ResponseBlock->CCIDHeader.Length = ResponseDataLength;
+				}
+				else if(CCIDInterfaceInfo->State.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(CCIDInterfaceInfo->Config.DataINEndpoint.Address);
+				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;
@@ -255,10 +305,10 @@ void CCID_Device_USBTask(USB_ClassInfo_CCID_Device_t* const CCIDInterfaceInfo)
 
 			default:
 			{
-				memset(BlockBuffer, 0x00, sizeof(BlockBuffer));
+				memset(ResponseBuffer, 0x00, sizeof(ResponseBuffer));
 
 				Endpoint_SelectEndpoint(CCIDInterfaceInfo->Config.DataINEndpoint.Address);
-				Endpoint_Write_Stream_LE(BlockBuffer, sizeof(BlockBuffer), NULL);
+				Endpoint_Write_Stream_LE(ResponseBuffer, sizeof(ResponseBuffer), NULL);
 				Endpoint_ClearIN();
 			}
 		}
diff --git a/LUFA/Drivers/USB/Class/Device/CCIDClassDevice.h b/LUFA/Drivers/USB/Class/Device/CCIDClassDevice.h
index 245e12665..d101723c3 100644
--- a/LUFA/Drivers/USB/Class/Device/CCIDClassDevice.h
+++ b/LUFA/Drivers/USB/Class/Device/CCIDClassDevice.h
@@ -155,6 +155,28 @@
 			                                    uint8_t slot,
 			                                    uint8_t* const error) ATTR_NON_NULL_PTR_ARG(1);
 
+			/** CCID class driver callback for PC_TO_RDR_XfrBlock CCID message
+			 *  Send a block of bytes from the host to a slot in the device 
+			 *  and also received a block of bytes as a response
+			 * 
+			 *  \param[in,out] CCIDInterfaceInfo	Pointer to a structure containing a CCID Class configuration and state.
+			 *  \param[in]     slot 				The slot ID from which we want to retrieve the status.
+			 *  \param[in]     receivedBuffer 		Pointer to an array holding the received block of bytes
+			 *  \param[in]     receivedBufferSize 	The size of the received block of bytes
+			 *  \param[out]    sendBuffer 			Pointer to a buffer which will hold the bytes being sent back to the host
+			 *  \param[out]     sentBufferSize 		The size of the block of bytes being sent back to the host
+			 *  \param[out]    error				The result of the operation, or error.
+			 *
+			 *  \return	The command result code.
+			 */
+			uint8_t CALLBACK_CCID_XfrBlock(USB_ClassInfo_CCID_Device_t* const CCIDInterfaceInfo,
+										   uint8_t slot, 
+										   uint8_t* const receivedBuffer, 
+										   uint8_t receivedBufferSize, 
+										   uint8_t* const sendBuffer, 
+										   uint8_t* const sentBufferSize, 
+										   uint8_t* const error);
+
 			/** CCID class driver callback for CCID_PC_to_RDR_Abort CCID message
 			 *  Aborts a BULK out message previously sent to a slot
 			 *
-- 
GitLab