3 Copyright (C) Dean Camera, 2018.
5 dean [at] fourwalledcubicle [dot] com
10 Copyright 2018 Dean Camera (dean [at] fourwalledcubicle [dot] com)
11 Copyright 2018 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
);
234 case CCID_PC_to_RDR_SetParameters
:
236 uint8_t ProtocolNum
= Endpoint_Read_8();
237 uint8_t RFU
= Endpoint_Read_16_LE();
241 USB_CCID_RDR_to_PC_Parameters_t
* ResponseParametersStatus
= (USB_CCID_RDR_to_PC_Parameters_t
*)&ResponseBuffer
;
242 ResponseParametersStatus
->CCIDHeader
.MessageType
= CCID_RDR_to_PC_Parameters
;
243 ResponseParametersStatus
->CCIDHeader
.Length
= 0;
244 ResponseParametersStatus
->CCIDHeader
.Slot
= CCIDHeader
.Slot
;
245 ResponseParametersStatus
->CCIDHeader
.Seq
= CCIDHeader
.Seq
;
247 if(ProtocolNum
== CCID_PROTOCOLNUM_T0
)
249 if(CCIDHeader
.Length
* sizeof(uint8_t) == sizeof(USB_CCID_ProtocolData_T0_t
))
252 Endpoint_Read_Stream_LE(RequestBuffer
, CCIDHeader
.Length
* sizeof(uint8_t), NULL
);
253 Status
= CALLBACK_CCID_SetParameters_T0(CCIDInterfaceInfo
, CCIDHeader
.Slot
, &Error
, (USB_CCID_ProtocolData_T0_t
*) RequestBuffer
);
254 if(CCID_CheckStatusNoError(Status
))
256 ResponseParametersStatus
->CCIDHeader
.Length
= CCIDHeader
.Length
;
257 Status
= CALLBACK_CCID_GetParameters_T0(CCIDInterfaceInfo
, CCIDHeader
.Slot
, &Error
, &ResponseParametersStatus
->ProtocolNum
, (USB_CCID_ProtocolData_T0_t
*) &ResponseParametersStatus
->ProtocolData
);
263 Status
= CCID_COMMANDSTATUS_FAILED
| CCID_ICCSTATUS_PRESENTANDACTIVE
;
268 ResponseParametersStatus
->ProtocolNum
= CCID_PROTOCOLNUM_T0
;
269 //for now, we don't support T=1 protocol
270 Error
= CCID_ERROR_PARAMETERS_PROTOCOL_NOT_SUPPORTED
;
271 Status
= CCID_COMMANDSTATUS_ERROR
| CCID_ICCSTATUS_PRESENTANDACTIVE
;
274 ResponseParametersStatus
->Status
= Status
;
275 ResponseParametersStatus
->Error
= Error
;
279 Endpoint_SelectEndpoint(CCIDInterfaceInfo
->Config
.DataINEndpoint
.Address
);
280 Endpoint_Write_Stream_LE(ResponseParametersStatus
, sizeof(USB_CCID_BulkMessage_Header_t
) + 3 + ResponseParametersStatus
->CCIDHeader
.Length
, NULL
);
284 case CCID_PC_to_RDR_GetParameters
:
286 USB_CCID_RDR_to_PC_Parameters_t
* ResponseParametersStatus
= (USB_CCID_RDR_to_PC_Parameters_t
*)&ResponseBuffer
;
287 ResponseParametersStatus
->CCIDHeader
.MessageType
= CCID_RDR_to_PC_Parameters
;
288 ResponseParametersStatus
->CCIDHeader
.Length
= sizeof(USB_CCID_ProtocolData_T0_t
);
289 ResponseParametersStatus
->CCIDHeader
.Slot
= CCIDHeader
.Slot
;
290 ResponseParametersStatus
->CCIDHeader
.Seq
= CCIDHeader
.Seq
;
292 Status
= CALLBACK_CCID_GetParameters_T0(CCIDInterfaceInfo
, CCIDHeader
.Slot
, &Error
, &ResponseParametersStatus
->ProtocolNum
, (USB_CCID_ProtocolData_T0_t
*) &ResponseParametersStatus
->ProtocolData
);
294 ResponseParametersStatus
->Status
= Status
;
295 ResponseParametersStatus
->Error
= Error
;
299 Endpoint_SelectEndpoint(CCIDInterfaceInfo
->Config
.DataINEndpoint
.Address
);
300 Endpoint_Write_Stream_LE(ResponseParametersStatus
, sizeof(USB_CCID_BulkMessage_Header_t
) + 3 + ResponseParametersStatus
->CCIDHeader
.Length
, NULL
);
304 case CCID_PC_to_RDR_XfrBlock
:
306 uint8_t Bwi
= Endpoint_Read_8();
307 uint16_t LevelParameter
= Endpoint_Read_16_LE();
308 uint8_t ReceivedBuffer
[0x4];
311 (void)LevelParameter
;
313 Endpoint_Read_Stream_LE(ReceivedBuffer
, sizeof(ReceivedBuffer
), NULL
);
315 uint8_t ResponseDataLength
= 0;
317 USB_CCID_RDR_to_PC_DataBlock_t
* ResponseBlock
= (USB_CCID_RDR_to_PC_DataBlock_t
*)&ResponseBuffer
;
318 ResponseBlock
->CCIDHeader
.MessageType
= CCID_RDR_to_PC_DataBlock
;
319 ResponseBlock
->CCIDHeader
.Slot
= CCIDHeader
.Slot
;
320 ResponseBlock
->CCIDHeader
.Seq
= CCIDHeader
.Seq
;
322 ResponseBlock
->ChainParam
= 0;
324 Status
= CALLBACK_CCID_XfrBlock(CCIDInterfaceInfo
, CCIDHeader
.Slot
, RequestBuffer
, CCIDHeader
.Length
, (uint8_t*) &ResponseBlock
->Data
, &ResponseDataLength
, &Error
);
326 if (CCID_CheckStatusNoError(Status
) && !CCIDInterfaceInfo
->State
.Aborted
)
328 ResponseBlock
->CCIDHeader
.Length
= ResponseDataLength
;
330 else if(CCIDInterfaceInfo
->State
.Aborted
)
332 Status
= CCID_COMMANDSTATUS_FAILED
| CCID_ICCSTATUS_PRESENTANDACTIVE
;
333 Error
= CCID_ERROR_CMD_ABORTED
;
334 ResponseDataLength
= 0;
338 ResponseDataLength
= 0;
341 ResponseBlock
->Status
= Status
;
342 ResponseBlock
->Error
= Error
;
346 Endpoint_SelectEndpoint(CCIDInterfaceInfo
->Config
.DataINEndpoint
.Address
);
347 Endpoint_Write_Stream_LE(ResponseBlock
, sizeof(USB_CCID_RDR_to_PC_DataBlock_t
) + ResponseDataLength
, NULL
);
352 case CCID_PC_to_RDR_Abort
:
354 USB_CCID_RDR_to_PC_SlotStatus_t
* ResponseAbort
= (USB_CCID_RDR_to_PC_SlotStatus_t
*)&ResponseBuffer
;
355 ResponseAbort
->CCIDHeader
.MessageType
= CCID_RDR_to_PC_SlotStatus
;
356 ResponseAbort
->CCIDHeader
.Length
= 0;
357 ResponseAbort
->CCIDHeader
.Slot
= CCIDHeader
.Slot
;
358 ResponseAbort
->CCIDHeader
.Seq
= CCIDHeader
.Seq
;
360 ResponseAbort
->ClockStatus
= 0;
362 Status
= CALLBACK_CCID_Abort(CCIDInterfaceInfo
, CCIDHeader
.Slot
, CCIDHeader
.Seq
, &Error
);
364 ResponseAbort
->Status
= Status
;
365 ResponseAbort
->Error
= Error
;
369 Endpoint_SelectEndpoint(CCIDInterfaceInfo
->Config
.DataINEndpoint
.Address
);
370 Endpoint_Write_Stream_LE(ResponseAbort
, sizeof(USB_CCID_RDR_to_PC_SlotStatus_t
), NULL
);
377 memset(ResponseBuffer
, 0x00, sizeof(ResponseBuffer
));
379 Endpoint_SelectEndpoint(CCIDInterfaceInfo
->Config
.DataINEndpoint
.Address
);
380 Endpoint_Write_Stream_LE(ResponseBuffer
, sizeof(ResponseBuffer
), NULL
);