blob: 1dbdf233f88c41229d8699b68bab3e81f1095736 [file] [log] [blame]
Christina Quastdb7b1ab2015-03-03 12:34:36 +01001/* ----------------------------------------------------------------------------
2 * ATMEL Microcontroller Software Support
3 * ----------------------------------------------------------------------------
4 * Copyright (c) 2008, Atmel Corporation
5 *
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions are met:
10 *
11 * - Redistributions of source code must retain the above copyright notice,
12 * this list of conditions and the disclaimer below.
13 *
14 * Atmel's name may not be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
20 * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
23 * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
24 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
25 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
26 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 * ----------------------------------------------------------------------------
28 */
29
30//------------------------------------------------------------------------------
31/// \unit
32///
33/// !Purpose
34///
35/// CCID driver
36///
37/// !Usage
38///
39/// Explanation on the usage of the code made available through the header file.
40//------------------------------------------------------------------------------
41
42//------------------------------------------------------------------------------
43// Headers
44//------------------------------------------------------------------------------
45
46#include "board.h"
Harald Welte16055642016-03-03 11:02:45 +010047#include "simtrace.h"
48
49#ifdef HAVE_CCID
50
Christina Quastdb7b1ab2015-03-03 12:34:36 +010051#include <USBDDriver.h>
52#include <USBRequests.h>
53#include <USBDescriptors.h>
54//#include <usb/device/dfu/dfu.h>
55#include <cciddriverdescriptors.h>
56
57// FIXME: Remove DFU related stuff
58/* no DFU bootloader is being used */
59#define DFU_NUM_IF 0
60#define DFU_IF_DESCRIPTORS_STRUCT
61#define DFU_IF_DESCRIPTORS
62
63#define DFU_NUM_STRINGS 0
64#define DFU_STRING_DESCRIPTORS
65
Christina Quastdb7b1ab2015-03-03 12:34:36 +010066//------------------------------------------------------------------------------
67// Local definition
68//------------------------------------------------------------------------------
69
70/// Constants: IDs: Device product ID.
71//#define CCIDDriverDescriptors_PRODUCTID 0x6129
72#define CCIDDriverDescriptors_PRODUCTID SIMTRACE_PRODUCT_ID
73/// Constants: IDs: Device vendor ID.
74#define CCIDDriverDescriptors_VENDORID ATMEL_VENDOR_ID
75//#define CCIDDriverDescriptors_VENDORID 0x03EB
76/// Constants: IDs: Device release number.
77#define CCIDDriverDescriptors_RELEASE 0x0100
78
Christina Quastdb7b1ab2015-03-03 12:34:36 +010079//------------------------------------------------------------------------------
80// Types
81//------------------------------------------------------------------------------
82
83/// Driver structure for an CCID device
84typedef struct {
85
Kévin Redon33d1eb72018-07-08 13:58:12 +020086 /// CCID message
87 S_ccid_bulk_in_header sCcidMessage;
88 /// CCID command
89 S_ccid_bulk_out_header sCcidCommand;
90 /// Interrupt message answer
91 unsigned char BufferINT[4];
92 /// Buffer data of message
93 unsigned char ProtocolDataStructure[10];
94 /// Protocol used
95 unsigned char bProtocol;
96 /// SlotStatus
97 /// Bit 0 = Slot 0 current state
98 /// Bit 1 = Slot 0 changed status
99 /// Bit 2 = Slot 1 current state
100 /// Bit 3 = Slot 1 changed status
101 /// Bit 4 = Slot 2 current state
102 /// Bit 5 = Slot 2 changed status
103 unsigned char SlotStatus;
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100104
105} CCIDDriver;
106
107//------------------------------------------------------------------------------
108// Local variables
109//------------------------------------------------------------------------------
110
111/// Static instance of the CCID device driver.
112static CCIDDriver ccidDriver;
113static CCIDDriverConfigurationDescriptors *configurationDescriptorsFS;
114
115//------------------------------------------------------------------------------
116// Internal functions
117//------------------------------------------------------------------------------
118
119//------------------------------------------------------------------------------
120/// Initializes the CCID device driver.
121//------------------------------------------------------------------------------
122void CCIDDriver_Initialize( void )
123{
Kévin Redon33d1eb72018-07-08 13:58:12 +0200124 configurationDescriptorsFS = (CCIDDriverConfigurationDescriptors *) configurationDescriptorsArr[CFG_NUM_CCID-1];
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100125}
126
127//------------------------------------------------------------------------------
128/// Response Pipe, Bulk-IN Messages
129/// Return the Slot Status to the host
130/// Answer to:
131/// PC_to_RDR_IccPowerOff
132/// PC_to_RDR_GetSlotStatus
133/// PC_to_RDR_IccClock
134/// PC_to_RDR_T0APDU
135/// PC_to_RDR_Mechanical
136/// PC_to_RDR_Abort and Class specific ABORT request
137//------------------------------------------------------------------------------
138static void RDRtoPCSlotStatus( void )
139{
Kévin Redon33d1eb72018-07-08 13:58:12 +0200140 // Header fields settings
141 ccidDriver.sCcidMessage.bMessageType = RDR_TO_PC_SLOTSTATUS;
142 ccidDriver.sCcidMessage.wLength = 0;
Christina Quast20a68142015-04-09 13:36:28 +0200143
Kévin Redon33d1eb72018-07-08 13:58:12 +0200144 if (ccidDriver.SlotStatus == ICC_INSERTED_EVENT) {
145 ccidDriver.sCcidMessage.bStatus = 0; /* ICC present and active card */
146 } else if (ccidDriver.SlotStatus == ICC_NOT_PRESENT) {
147 ccidDriver.sCcidMessage.bStatus = 2; /* No ICC present*/
148 } else{
149 TRACE_ERROR("Strange bStatus");
150 ccidDriver.sCcidMessage.bStatus = 0;
151 }
152 ccidDriver.sCcidMessage.bError = 0;
153 // 00h Clock running
154 // 01h Clock stopped in state L
155 // 02h Clock stopped in state H
156 // 03h Clock stopped in an unknown state
157 // All other values are Reserved for Future Use.
158 ccidDriver.sCcidMessage.bSpecific = 0;
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100159}
160
161//------------------------------------------------------------------------------
162/// Response Pipe, Bulk-IN Messages
163/// Answer to PC_to_RDR_IccPowerOn
164//------------------------------------------------------------------------------
165static void RDRtoPCDatablock_ATR( void )
166{
Kévin Redon33d1eb72018-07-08 13:58:12 +0200167 unsigned char i;
168 unsigned char Atr[ATR_SIZE_MAX];
169 unsigned char length;
170 uint32_t status;
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100171
Kévin Redon33d1eb72018-07-08 13:58:12 +0200172 TRACE_DEBUG(".");
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100173
Kévin Redon33d1eb72018-07-08 13:58:12 +0200174 status = ISO7816_Datablock_ATR( Atr, &length );
175 ISO7816_Decode_ATR( Atr );
Christina Quastb58434e2015-03-09 17:13:07 +0100176
Kévin Redon33d1eb72018-07-08 13:58:12 +0200177 if (status == 0) {
178 TRACE_DEBUG("Timeout occured while reading ATR");
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100179// FIXME: react properly to timeout..
180// return;
Kévin Redon33d1eb72018-07-08 13:58:12 +0200181 }
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100182
Christina Quastb58434e2015-03-09 17:13:07 +0100183// FIXME: More tests? Is bProtocol = Atr[3] ?
Kévin Redon33d1eb72018-07-08 13:58:12 +0200184 if( length > 5 ) {
185 ccidDriver.ProtocolDataStructure[1] = Atr[3]&0x0F; // TD(1)
186 ccidDriver.bProtocol = Atr[3]&0x0F; // TD(1)
187 TRACE_INFO("Protocol data structure: 0x%x\n\r",
188 ccidDriver.ProtocolDataStructure[1]);
189 }
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100190
Kévin Redon33d1eb72018-07-08 13:58:12 +0200191 // S_ccid_protocol_t0
192 // bmFindexDindex
193 ccidDriver.ProtocolDataStructure[0] = Atr[2]; // TA(1)
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100194
Kévin Redon33d1eb72018-07-08 13:58:12 +0200195 // bmTCCKST0
196 // For T=0 ,B0 – 0b, B7-2 – 000000b
197 // B1 – Convention used (b1=0 for direct, b1=1 for inverse)
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100198
Kévin Redon33d1eb72018-07-08 13:58:12 +0200199 // bGuardTimeT0
200 // Extra Guardtime between two characters. Add 0 to 254 etu to the normal
201 // guardtime of 12etu. FFh is the same as 00h.
202 ccidDriver.ProtocolDataStructure[2] = Atr[4]; // TC(1)
203 // AT91C_BASE_US0->US_TTGR = 0; // TC1
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100204
Kévin Redon33d1eb72018-07-08 13:58:12 +0200205 // bWaitingIntegerT0
206 // WI for T=0 used to define WWT
207 ccidDriver.ProtocolDataStructure[3] = Atr[7]; // TC(2)
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100208
Kévin Redon33d1eb72018-07-08 13:58:12 +0200209 // bClockStop
210 // ICC Clock Stop Support
211 // 00 = Stopping the Clock is not allowed
212 // 01 = Stop with Clock signal Low
213 // 02 = Stop with Clock signal High
214 // 03 = Stop with Clock either High or Low
215 ccidDriver.ProtocolDataStructure[4] = 0x00; // 0 to 3
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100216
Kévin Redon33d1eb72018-07-08 13:58:12 +0200217 // Header fields settings
218 ccidDriver.sCcidMessage.bMessageType = RDR_TO_PC_DATABLOCK;
219 ccidDriver.sCcidMessage.wLength = length; // Size of ATR
220 ccidDriver.sCcidMessage.bSizeToSend += length; // Size of ATR
221 // bChainParameter: 00 the response APDU begins and ends in this command
222 ccidDriver.sCcidMessage.bSpecific = 0;
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100223
Kévin Redon33d1eb72018-07-08 13:58:12 +0200224 for( i=0; i<length; i++ ) {
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100225
Kévin Redon33d1eb72018-07-08 13:58:12 +0200226 ccidDriver.sCcidMessage.abData[i] = Atr[i];
227 }
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100228
Kévin Redon33d1eb72018-07-08 13:58:12 +0200229 // Set the slot to an active status
230 ccidDriver.sCcidMessage.bStatus = 0;
231 ccidDriver.sCcidMessage.bError = 0;
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100232}
233
234//------------------------------------------------------------------------------
235/// Response Pipe, Bulk-IN Messages
236/// In other cases, the response message has the following format:
237/// The response data will contain the optional data returned by the ICC,
238/// followed by the 2 byte-size status words SW1-SW2.
239///
240/// Answer to:
241/// PC_to_RDR_XfrBlock
242/// PC_to_RDR_Secure
243//------------------------------------------------------------------------------
244static void RDRtoPCDatablock( void )
245{
Kévin Redon33d1eb72018-07-08 13:58:12 +0200246 //TRACE_DEBUG(".");
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100247
Kévin Redon33d1eb72018-07-08 13:58:12 +0200248 // Header fields settings
249 ccidDriver.sCcidMessage.bMessageType = RDR_TO_PC_DATABLOCK;
250 ccidDriver.sCcidMessage.bSizeToSend += ccidDriver.sCcidMessage.wLength;
251 // bChainParameter: 00 the response APDU begins and ends in this command
252 ccidDriver.sCcidMessage.bSpecific = 0;
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100253
Kévin Redon33d1eb72018-07-08 13:58:12 +0200254 // Set the slot to an active status
255 ccidDriver.sCcidMessage.bStatus = 0;
256 ccidDriver.sCcidMessage.bError = 0;
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100257}
258
259//------------------------------------------------------------------------------
260/// Response Pipe, Bulk-IN Messages
261/// Answer to:
262/// PC_to_RDR_GetParameters
263/// PC_to_RDR_ResetParameters
264/// PC_to_RDR_SetParameters
265//------------------------------------------------------------------------------
266static void RDRtoPCParameters( void )
267{
Kévin Redon33d1eb72018-07-08 13:58:12 +0200268 unsigned int i;
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100269
Kévin Redon33d1eb72018-07-08 13:58:12 +0200270 TRACE_DEBUG(".");
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100271
Kévin Redon33d1eb72018-07-08 13:58:12 +0200272 // Header fields settings
273 ccidDriver.sCcidMessage.bMessageType = RDR_TO_PC_PARAMETERS;
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100274
Kévin Redon33d1eb72018-07-08 13:58:12 +0200275 //ccidDriver.sCcidMessage.bStatus = 0;
276 ccidDriver.sCcidMessage.bError = 0;
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100277
Kévin Redon33d1eb72018-07-08 13:58:12 +0200278 if( ccidDriver.ProtocolDataStructure[1] == PROTOCOL_TO ) {
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100279
Kévin Redon33d1eb72018-07-08 13:58:12 +0200280 // T=0
281 ccidDriver.sCcidMessage.wLength = sizeof(S_ccid_protocol_t0);
282 ccidDriver.sCcidMessage.bSpecific = PROTOCOL_TO;
283 }
284 else {
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100285
Kévin Redon33d1eb72018-07-08 13:58:12 +0200286 // T=1
287 ccidDriver.sCcidMessage.wLength = sizeof(S_ccid_protocol_t1);
288 ccidDriver.sCcidMessage.bSpecific = PROTOCOL_T1;
289 }
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100290
Kévin Redon33d1eb72018-07-08 13:58:12 +0200291 ccidDriver.sCcidMessage.bSizeToSend += ccidDriver.sCcidMessage.wLength;
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100292
Kévin Redon33d1eb72018-07-08 13:58:12 +0200293 for( i=0; i<ccidDriver.sCcidMessage.wLength; i++ ) {
294 ccidDriver.sCcidMessage.abData[i] = ccidDriver.ProtocolDataStructure[i];
295 }
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100296
297}
298
299//------------------------------------------------------------------------------
300/// Response Pipe, Bulk-IN Messages
301/// Answer to:
302/// PC_to_RDR_Escape
303//------------------------------------------------------------------------------
304static void RDRtoPCEscape( unsigned char length, unsigned char *data_send_from_CCID )
305{
Kévin Redon33d1eb72018-07-08 13:58:12 +0200306 unsigned int i;
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100307
Kévin Redon33d1eb72018-07-08 13:58:12 +0200308 TRACE_DEBUG(".");
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100309
Kévin Redon33d1eb72018-07-08 13:58:12 +0200310 // Header fields settings
311 ccidDriver.sCcidMessage.bMessageType = RDR_TO_PC_ESCAPE;
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100312
Kévin Redon33d1eb72018-07-08 13:58:12 +0200313 ccidDriver.sCcidMessage.wLength = length;
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100314
Kévin Redon33d1eb72018-07-08 13:58:12 +0200315 ccidDriver.sCcidMessage.bStatus = 0;
316 ccidDriver.sCcidMessage.bError = 0;
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100317
Kévin Redon33d1eb72018-07-08 13:58:12 +0200318 ccidDriver.sCcidMessage.bSpecific = 0; // bRFU
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100319
Kévin Redon33d1eb72018-07-08 13:58:12 +0200320 for( i=0; i<length; i++ ) {
321 ccidDriver.sCcidMessage.abData[i] = data_send_from_CCID[i];
322 }
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100323}
324
325//------------------------------------------------------------------------------
326/// Response Pipe, Bulk-IN Messages
327/// Answer to:
328/// PC_to_RDR_SetDataRateAndClockFrequency
329//------------------------------------------------------------------------------
330static void RDRtoPCDataRateAndClockFrequency( unsigned int dwClockFrequency,
Kévin Redon33d1eb72018-07-08 13:58:12 +0200331 unsigned int dwDataRate )
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100332{
Kévin Redon33d1eb72018-07-08 13:58:12 +0200333 TRACE_DEBUG(".");
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100334
Kévin Redon33d1eb72018-07-08 13:58:12 +0200335 // Header fields settings
336 ccidDriver.sCcidMessage.bMessageType = RDR_TO_PC_DATARATEANDCLOCKFREQUENCY;
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100337
Kévin Redon33d1eb72018-07-08 13:58:12 +0200338 ccidDriver.sCcidMessage.wLength = 8;
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100339
Kévin Redon33d1eb72018-07-08 13:58:12 +0200340 ccidDriver.sCcidMessage.bStatus = 0;
341 ccidDriver.sCcidMessage.bError = 0;
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100342
Kévin Redon33d1eb72018-07-08 13:58:12 +0200343 ccidDriver.sCcidMessage.bSpecific = 0; // bRFU
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100344
Kévin Redon33d1eb72018-07-08 13:58:12 +0200345 ccidDriver.sCcidMessage.abData[0] = dwClockFrequency;
346
347 ccidDriver.sCcidMessage.abData[4] = dwDataRate;
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100348}
349
350//------------------------------------------------------------------------------
351/// Command Pipe, Bulk-OUT Messages
352/// Power On Command - Cold Reset & Warm Reset
353/// Return the ATR to the host
354//------------------------------------------------------------------------------
355static void PCtoRDRIccPowerOn( void )
356{
Kévin Redon33d1eb72018-07-08 13:58:12 +0200357 TRACE_DEBUG(".");
358 if( CCID_FEATURES_AUTO_VOLT == (configurationDescriptorsFS->ccid.dwFeatures & CCID_FEATURES_AUTO_VOLT) ) {
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100359
Kévin Redon33d1eb72018-07-08 13:58:12 +0200360 //bPowerSelect = ccidDriver.sCcidCommand.bSpecific_0;
361 ccidDriver.sCcidCommand.bSpecific_0 = VOLTS_AUTO;
362 }
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100363
Kévin Redon33d1eb72018-07-08 13:58:12 +0200364 ISO7816_warm_reset();
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100365// ISO7816_cold_reset();
366
Kévin Redon33d1eb72018-07-08 13:58:12 +0200367 // for emulation only //JCB
368 if ( ccidDriver.sCcidCommand.bSpecific_0 != VOLTS_5_0 ) {
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100369
Kévin Redon33d1eb72018-07-08 13:58:12 +0200370 TRACE_ERROR("POWER_NOT_SUPPORTED\n\r");
371 }
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100372
Kévin Redon33d1eb72018-07-08 13:58:12 +0200373 else {
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100374
Kévin Redon33d1eb72018-07-08 13:58:12 +0200375 RDRtoPCDatablock_ATR();
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100376
Kévin Redon33d1eb72018-07-08 13:58:12 +0200377 }
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100378}
379
380//------------------------------------------------------------------------------
381/// Command Pipe, Bulk-OUT Messages
382/// Power Off Command - Set the ICC in an inactive state
383/// Return the slot status to the host
384//------------------------------------------------------------------------------
385static void PCtoRDRIccPowerOff( void )
386{
Kévin Redon33d1eb72018-07-08 13:58:12 +0200387 unsigned char bStatus;
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100388
Kévin Redon33d1eb72018-07-08 13:58:12 +0200389 TRACE_DEBUG(".");
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100390
Kévin Redon33d1eb72018-07-08 13:58:12 +0200391 ISO7816_IccPowerOff();
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100392
Kévin Redon33d1eb72018-07-08 13:58:12 +0200393 //JCB stub
394 bStatus = ICC_BS_PRESENT_NOTACTIVATED;
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100395
Kévin Redon33d1eb72018-07-08 13:58:12 +0200396 // Set the slot to an inactive status
397 ccidDriver.sCcidMessage.bStatus = 0;
398 ccidDriver.sCcidMessage.bError = 0;
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100399
Kévin Redon33d1eb72018-07-08 13:58:12 +0200400 // if error, see Table 6.1-2 errors
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100401
Kévin Redon33d1eb72018-07-08 13:58:12 +0200402 // Return the slot status to the host
403 RDRtoPCSlotStatus();
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100404}
405
406//------------------------------------------------------------------------------
407/// Command Pipe, Bulk-OUT Messages
408/// Get slot status
409//------------------------------------------------------------------------------
410static void PCtoRDRGetSlotStatus( void )
411{
Kévin Redon33d1eb72018-07-08 13:58:12 +0200412 TRACE_DEBUG(".");
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100413
Kévin Redon33d1eb72018-07-08 13:58:12 +0200414 ccidDriver.sCcidMessage.bStatus = 0;
415 ccidDriver.sCcidMessage.bError = 0;
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100416
Kévin Redon33d1eb72018-07-08 13:58:12 +0200417 // Return the slot status to the host
418 RDRtoPCSlotStatus();
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100419}
420
421//------------------------------------------------------------------------------
422/// Command Pipe, Bulk-OUT Messages
423/// If the command header is valid, an APDU command is received and can be read
424/// by the application
425//------------------------------------------------------------------------------
426static void PCtoRDRXfrBlock( void )
427{
Kévin Redon33d1eb72018-07-08 13:58:12 +0200428 uint16_t msglen = 0;
429 uint32_t ret;
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100430
Kévin Redon33d1eb72018-07-08 13:58:12 +0200431 TRACE_DEBUG("PCtoRDRXfrBlock\n");
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100432
Kévin Redon33d1eb72018-07-08 13:58:12 +0200433 // Check the block length
434 if ( ccidDriver.sCcidCommand.wLength > (configurationDescriptorsFS->ccid.dwMaxCCIDMessageLength-10) ) {
435 TRACE_DEBUG("Err block/msg len");
436 ccidDriver.sCcidMessage.bStatus = 1;
437 ccidDriver.sCcidMessage.bError = 0;
438 }
439 // check bBWI
440 else if ( 0 != ccidDriver.sCcidCommand.bSpecific_0 ) {
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100441
Kévin Redon33d1eb72018-07-08 13:58:12 +0200442 TRACE_ERROR("Bad bBWI\n\r");
443 }
444 else {
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100445
Kévin Redon33d1eb72018-07-08 13:58:12 +0200446 // APDU or TPDU
447 switch(configurationDescriptorsFS->ccid.dwFeatures
448 & (CCID_FEATURES_EXC_TPDU|CCID_FEATURES_EXC_SAPDU|CCID_FEATURES_EXC_APDU)) {
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100449
Kévin Redon33d1eb72018-07-08 13:58:12 +0200450 case CCID_FEATURES_EXC_TPDU:
451 if (ccidDriver.ProtocolDataStructure[1] == PROTOCOL_TO) {
452 TRACE_DEBUG("APDU cmd: %x %x %x ..", ccidDriver.sCcidCommand.APDU[0], ccidDriver.sCcidCommand.APDU[1],ccidDriver.sCcidCommand.APDU[2] );
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100453
Kévin Redon33d1eb72018-07-08 13:58:12 +0200454 // Send commande APDU
455 ret = ISO7816_XfrBlockTPDU_T0( ccidDriver.sCcidCommand.APDU ,
456 ccidDriver.sCcidMessage.abData,
457 ccidDriver.sCcidCommand.wLength,
458 &msglen );
459 if (ret != 0) {
460 TRACE_ERROR("APDU could not be sent: (US_CSR = 0x%x)", ret);
461 return;
462 }
463 }
464 else {
465 if (ccidDriver.ProtocolDataStructure[1] == PROTOCOL_T1) {
466 TRACE_DEBUG("Not supported T=1\n\r");
467 }
468 else {
469 TRACE_DEBUG("Not supported 0x%x\n\r", ccidDriver.ProtocolDataStructure[1]);
470 }
471 }
472 break;
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100473
Kévin Redon33d1eb72018-07-08 13:58:12 +0200474 case CCID_FEATURES_EXC_APDU:
475 TRACE_DEBUG("Not supported CCID_FEATURES_EXC_APDU\n\r");
476 break;
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100477
Kévin Redon33d1eb72018-07-08 13:58:12 +0200478 default:
479 break;
480 }
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100481
Kévin Redon33d1eb72018-07-08 13:58:12 +0200482 }
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100483
Kévin Redon33d1eb72018-07-08 13:58:12 +0200484 ccidDriver.sCcidMessage.wLength = msglen;
485 TRACE_DEBUG("USB: 0x%X, 0x%X, 0x%X, 0x%X, 0x%X\n\r", ccidDriver.sCcidMessage.abData[0],
486 ccidDriver.sCcidMessage.abData[1],
487 ccidDriver.sCcidMessage.abData[2],
488 ccidDriver.sCcidMessage.abData[3],
489 ccidDriver.sCcidMessage.abData[4] );
490 RDRtoPCDatablock();
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100491
492}
493
494//------------------------------------------------------------------------------
495/// Command Pipe, Bulk-OUT Messages
496/// return parameters by the command: RDR_to_PC_Parameters
497//------------------------------------------------------------------------------
498static void PCtoRDRGetParameters( void )
499{
Kévin Redon33d1eb72018-07-08 13:58:12 +0200500 TRACE_DEBUG(".");
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100501
Kévin Redon33d1eb72018-07-08 13:58:12 +0200502 // We support only one slot
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100503
Kévin Redon33d1eb72018-07-08 13:58:12 +0200504 // bmIccStatus
505 if( ISO7816_StatusReset() ) {
506 // 0: An ICC is present and active (power is on and stable, RST is inactive
507 ccidDriver.sCcidMessage.bStatus = 0;
508 }
509 else {
510 // 1: An ICC is present and inactive (not activated or shut down by hardware error)
511 ccidDriver.sCcidMessage.bStatus = 1;
512 }
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100513
Kévin Redon33d1eb72018-07-08 13:58:12 +0200514 RDRtoPCParameters();
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100515}
516
517//------------------------------------------------------------------------------
518/// Command Pipe, Bulk-OUT Messages
519/// This command resets the slot parameters to their default values
520//------------------------------------------------------------------------------
521static void PCtoRDRResetParameters( void )
522{
Kévin Redon33d1eb72018-07-08 13:58:12 +0200523 TRACE_DEBUG(".");
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100524
Kévin Redon33d1eb72018-07-08 13:58:12 +0200525 ccidDriver.SlotStatus = ICC_NOT_PRESENT;
526 ccidDriver.sCcidMessage.bStatus = ccidDriver.SlotStatus;
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100527
Kévin Redon33d1eb72018-07-08 13:58:12 +0200528 RDRtoPCParameters();
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100529}
530
531//------------------------------------------------------------------------------
532/// Command Pipe, Bulk-OUT Messages
533/// This command is used to change the parameters for a given slot.
534//------------------------------------------------------------------------------
535static void PCtoRDRSetParameters( void )
536{
Kévin Redon33d1eb72018-07-08 13:58:12 +0200537 TRACE_DEBUG(".");
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100538
Kévin Redon33d1eb72018-07-08 13:58:12 +0200539 ccidDriver.SlotStatus = ccidDriver.sCcidCommand.bSlot;
540 ccidDriver.sCcidMessage.bStatus = ccidDriver.SlotStatus;
541 // Not all feature supported
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100542
Kévin Redon33d1eb72018-07-08 13:58:12 +0200543 RDRtoPCParameters();
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100544}
545
546//------------------------------------------------------------------------------
547/// Command Pipe, Bulk-OUT Messages
548/// This command allows the CCID manufacturer to define and access extended
549/// features.
550/// Information sent via this command is processed by the CCID control logic.
551//------------------------------------------------------------------------------
552static void PCtoRDREscape( void )
553{
Kévin Redon33d1eb72018-07-08 13:58:12 +0200554 TRACE_DEBUG(".");
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100555
Kévin Redon33d1eb72018-07-08 13:58:12 +0200556 // If needed by the user
557 ISO7816_Escape();
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100558
Kévin Redon33d1eb72018-07-08 13:58:12 +0200559 // stub, return all value send
560 RDRtoPCEscape( ccidDriver.sCcidCommand.wLength, ccidDriver.sCcidCommand.APDU);
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100561}
562
563//------------------------------------------------------------------------------
564/// Command Pipe, Bulk-OUT Messages
565/// This command stops or restarts the clock.
566//------------------------------------------------------------------------------
567static void PCtoRDRICCClock( void )
568{
Kévin Redon33d1eb72018-07-08 13:58:12 +0200569 TRACE_DEBUG(".");
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100570
Kévin Redon33d1eb72018-07-08 13:58:12 +0200571 if( 0 == ccidDriver.sCcidCommand.bSpecific_0 ) {
572 // restarts the clock
573 ISO7816_RestartClock();
574 }
575 else {
576 // stop clock in the state shown in the bClockStop field
577 ISO7816_StopClock();
578 }
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100579
Kévin Redon33d1eb72018-07-08 13:58:12 +0200580 RDRtoPCSlotStatus( );
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100581}
582
583//------------------------------------------------------------------------------
584/// Command Pipe, Bulk-OUT Messages
585/// This command changes the parameters used to perform the transportation of
586/// APDU messages by the T=0 protocol.
587//------------------------------------------------------------------------------
588static void PCtoRDRtoAPDU( void )
589{
Kévin Redon33d1eb72018-07-08 13:58:12 +0200590 unsigned char bmChanges;
591 unsigned char bClassGetResponse;
592 unsigned char bClassEnvelope;
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100593
Kévin Redon33d1eb72018-07-08 13:58:12 +0200594 TRACE_INFO(".");
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100595
Kévin Redon33d1eb72018-07-08 13:58:12 +0200596 if( configurationDescriptorsFS->ccid.dwFeatures == (CCID_FEATURES_EXC_SAPDU|CCID_FEATURES_EXC_APDU) ) {
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100597
Kévin Redon33d1eb72018-07-08 13:58:12 +0200598 bmChanges = ccidDriver.sCcidCommand.bSpecific_0;
599 bClassGetResponse = ccidDriver.sCcidCommand.bSpecific_1;
600 bClassEnvelope = ccidDriver.sCcidCommand.bSpecific_2;
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100601
Kévin Redon33d1eb72018-07-08 13:58:12 +0200602 ISO7816_toAPDU();
603 }
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100604
Kévin Redon33d1eb72018-07-08 13:58:12 +0200605 RDRtoPCSlotStatus();
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100606}
607
608//------------------------------------------------------------------------------
609/// Command Pipe, Bulk-OUT Messages
610/// This is a command message to allow entering the PIN for verification or
611/// modification.
612//------------------------------------------------------------------------------
613static void PCtoRDRSecure( void )
614{
Kévin Redon33d1eb72018-07-08 13:58:12 +0200615 TRACE_DEBUG(".");
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100616
Kévin Redon33d1eb72018-07-08 13:58:12 +0200617 TRACE_DEBUG("For user\n\r");
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100618}
619
620//------------------------------------------------------------------------------
621/// Command Pipe, Bulk-OUT Messages
622/// This command is used to manage motorized type CCID functionality.
623/// The Lock Card function is used to hold the ICC.
624/// This prevents an ICC from being easily removed from the CCID.
625/// The Unlock Card function is used to remove the hold initiated by the Lock
626/// Card function
627//------------------------------------------------------------------------------
628static void PCtoRDRMechanical( void )
629{
Kévin Redon33d1eb72018-07-08 13:58:12 +0200630 TRACE_DEBUG(".");
631 TRACE_DEBUG("Not implemented\n\r");
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100632
Kévin Redon33d1eb72018-07-08 13:58:12 +0200633 RDRtoPCSlotStatus();
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100634}
635
636//------------------------------------------------------------------------------
637/// Command Pipe, Bulk-OUT Messages
638/// This command is used with the Control pipe Abort request to tell the CCID
639/// to stop any current transfer at the specified slot and return to a state
640/// where the slot is ready to accept a new command pipe Bulk-OUT message.
641//------------------------------------------------------------------------------
642static void PCtoRDRAbort( void )
643{
Kévin Redon33d1eb72018-07-08 13:58:12 +0200644 TRACE_DEBUG(".");
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100645
Kévin Redon33d1eb72018-07-08 13:58:12 +0200646 RDRtoPCSlotStatus();
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100647}
648
649//------------------------------------------------------------------------------
650/// Command Pipe, Bulk-OUT Messages
651/// This command is used to manually set the data rate and clock frequency of
652/// a specific slot.
653//------------------------------------------------------------------------------
654static void PCtoRDRSetDataRateAndClockFrequency( void )
655{
Kévin Redon33d1eb72018-07-08 13:58:12 +0200656 unsigned int dwClockFrequency;
657 unsigned int dwDataRate;
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100658
Kévin Redon33d1eb72018-07-08 13:58:12 +0200659 TRACE_DEBUG(".");
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100660
Kévin Redon33d1eb72018-07-08 13:58:12 +0200661 dwClockFrequency = ccidDriver.sCcidCommand.APDU[0]
662 + (ccidDriver.sCcidCommand.APDU[1]<<8)
663 + (ccidDriver.sCcidCommand.APDU[2]<<16)
664 + (ccidDriver.sCcidCommand.APDU[3]<<24);
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100665
Kévin Redon33d1eb72018-07-08 13:58:12 +0200666 dwDataRate = ccidDriver.sCcidCommand.APDU[4]
667 + (ccidDriver.sCcidCommand.APDU[5]<<8)
668 + (ccidDriver.sCcidCommand.APDU[6]<<16)
669 + (ccidDriver.sCcidCommand.APDU[7]<<24);
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100670
Kévin Redon33d1eb72018-07-08 13:58:12 +0200671 ISO7816_SetDataRateandClockFrequency( dwClockFrequency, dwDataRate );
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100672
Kévin Redon33d1eb72018-07-08 13:58:12 +0200673 RDRtoPCDataRateAndClockFrequency( dwClockFrequency, dwDataRate );
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100674
675}
676
677//------------------------------------------------------------------------------
678/// Report the CMD_NOT_SUPPORTED error to the host
679//------------------------------------------------------------------------------
680static void vCCIDCommandNotSupported( void )
681{
Kévin Redon33d1eb72018-07-08 13:58:12 +0200682 // Command not supported
683 // vCCIDReportError(CMD_NOT_SUPPORTED);
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100684
Kévin Redon33d1eb72018-07-08 13:58:12 +0200685 TRACE_DEBUG("CMD_NOT_SUPPORTED\n\r");
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100686
Kévin Redon33d1eb72018-07-08 13:58:12 +0200687 // Header fields settings
688 ccidDriver.sCcidMessage.bMessageType = RDR_TO_PC_SLOTSTATUS;
689 ccidDriver.sCcidMessage.wLength = 0;
690 ccidDriver.sCcidMessage.bSpecific = 0;
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100691
Kévin Redon33d1eb72018-07-08 13:58:12 +0200692 ccidDriver.sCcidMessage.bStatus |= ICC_CS_FAILED;
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100693
Kévin Redon33d1eb72018-07-08 13:58:12 +0200694 // Send the response to the host
695 //vCCIDSendResponse();
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100696}
697
698//------------------------------------------------------------------------------
699/// Sent CCID response on USB
700//------------------------------------------------------------------------------
701static void vCCIDSendResponse( void )
702{
Kévin Redon33d1eb72018-07-08 13:58:12 +0200703 unsigned char bStatus;
704 TRACE_DEBUG(".");
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100705
Kévin Redon33d1eb72018-07-08 13:58:12 +0200706 do {
707 bStatus = CCID_Write((void*)&ccidDriver.sCcidMessage,
708 ccidDriver.sCcidMessage.bSizeToSend, 0, 0 );
709 } while (bStatus != USBD_STATUS_SUCCESS);
Christina Quast1a224af2015-03-10 15:11:37 +0100710
Kévin Redon33d1eb72018-07-08 13:58:12 +0200711 TRACE_DEBUG("bStatus: 0x%x\n\r", bStatus);
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100712}
713
714
715//------------------------------------------------------------------------------
716/// Description: CCID Command dispatcher
717//------------------------------------------------------------------------------
Christina Quastb878df92015-04-09 16:54:36 +0200718static void CCIDCommandDispatcher( void *pArg, uint8_t status, uint32_t transferred, uint32_t remaining )
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100719{
Kévin Redon33d1eb72018-07-08 13:58:12 +0200720 unsigned char MessageToSend = 0;
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100721
Kévin Redon33d1eb72018-07-08 13:58:12 +0200722 if (status != USBD_STATUS_SUCCESS) {
723 TRACE_ERROR("USB error: %d", status);
724 return;
725 }
726 TRACE_DEBUG("Command: 0x%X 0x%x 0x%X 0x%X 0x%X 0x%X 0x%X\n\r\n\r",
727 (unsigned int)ccidDriver.sCcidCommand.bMessageType,
728 (unsigned int)ccidDriver.sCcidCommand.wLength,
729 (unsigned int)ccidDriver.sCcidCommand.bSlot,
730 (unsigned int)ccidDriver.sCcidCommand.bSeq,
731 (unsigned int)ccidDriver.sCcidCommand.bSpecific_0,
732 (unsigned int)ccidDriver.sCcidCommand.bSpecific_1,
733 (unsigned int)ccidDriver.sCcidCommand.bSpecific_2);
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100734
Kévin Redon33d1eb72018-07-08 13:58:12 +0200735 // Check the slot number
736 if ( ccidDriver.sCcidCommand.bSlot > 0 ) {
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100737
Kévin Redon33d1eb72018-07-08 13:58:12 +0200738 TRACE_ERROR("BAD_SLOT_NUMBER\n\r");
739 }
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100740
Kévin Redon33d1eb72018-07-08 13:58:12 +0200741 TRACE_INFO("typ=0x%X\n\r", ccidDriver.sCcidCommand.bMessageType);
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100742
Kévin Redon33d1eb72018-07-08 13:58:12 +0200743 ccidDriver.sCcidMessage.bStatus = 0;
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100744
Kévin Redon33d1eb72018-07-08 13:58:12 +0200745 ccidDriver.sCcidMessage.bSeq = ccidDriver.sCcidCommand.bSeq;
746 ccidDriver.sCcidMessage.bSlot = ccidDriver.sCcidCommand.bSlot;
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100747
Kévin Redon33d1eb72018-07-08 13:58:12 +0200748 ccidDriver.sCcidMessage.bSizeToSend = sizeof(S_ccid_bulk_in_header)-(ABDATA_SIZE+1);
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100749
750
Kévin Redon33d1eb72018-07-08 13:58:12 +0200751 // Command dispatcher
752 switch ( ccidDriver.sCcidCommand.bMessageType ) {
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100753
Kévin Redon33d1eb72018-07-08 13:58:12 +0200754 case PC_TO_RDR_ICCPOWERON:
755 PCtoRDRIccPowerOn();
756 MessageToSend = 1;
757 break;
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100758
Kévin Redon33d1eb72018-07-08 13:58:12 +0200759 case PC_TO_RDR_ICCPOWEROFF:
760 PCtoRDRIccPowerOff();
761 MessageToSend = 1;
762 break;
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100763
Kévin Redon33d1eb72018-07-08 13:58:12 +0200764 case PC_TO_RDR_GETSLOTSTATUS:
765 PCtoRDRGetSlotStatus();
766 MessageToSend = 1;
767 break;
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100768
Kévin Redon33d1eb72018-07-08 13:58:12 +0200769 case PC_TO_RDR_XFRBLOCK:
770 PCtoRDRXfrBlock();
771 MessageToSend = 1;
772 break;
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100773
Kévin Redon33d1eb72018-07-08 13:58:12 +0200774 case PC_TO_RDR_GETPARAMETERS:
775 PCtoRDRGetParameters();
776 MessageToSend = 1;
777 break;
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100778
Kévin Redon33d1eb72018-07-08 13:58:12 +0200779 case PC_TO_RDR_RESETPARAMETERS:
780 PCtoRDRResetParameters();
781 MessageToSend = 1;
782 break;
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100783
Kévin Redon33d1eb72018-07-08 13:58:12 +0200784 case PC_TO_RDR_SETPARAMETERS:
785 PCtoRDRSetParameters();
786 MessageToSend = 1;
787 break;
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100788
Kévin Redon33d1eb72018-07-08 13:58:12 +0200789 case PC_TO_RDR_ESCAPE:
790 PCtoRDREscape();
791 MessageToSend = 1;
792 break;
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100793
Kévin Redon33d1eb72018-07-08 13:58:12 +0200794 case PC_TO_RDR_ICCCLOCK:
795 PCtoRDRICCClock();
796 MessageToSend = 1;
797 break;
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100798
Kévin Redon33d1eb72018-07-08 13:58:12 +0200799 case PC_TO_RDR_T0APDU:
800 // Only CCIDs reporting a short or extended APDU level in the dwFeatures
801 // field of the CCID class descriptor may take this command into account.
802 if( (CCID_FEATURES_EXC_SAPDU == (CCID_FEATURES_EXC_SAPDU&configurationDescriptorsFS->ccid.dwFeatures))
803 || (CCID_FEATURES_EXC_APDU == (CCID_FEATURES_EXC_APDU &configurationDescriptorsFS->ccid.dwFeatures)) ) {
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100804
Kévin Redon33d1eb72018-07-08 13:58:12 +0200805 // command supported
806 PCtoRDRtoAPDU();
807 }
808 else {
809 // command not supported
810 TRACE_INFO("Not supported: PC_TO_RDR_T0APDU\n\r");
811 vCCIDCommandNotSupported();
812 }
813 MessageToSend = 1;
814 break;
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100815
Kévin Redon33d1eb72018-07-08 13:58:12 +0200816 case PC_TO_RDR_SECURE:
817 PCtoRDRSecure();
818 MessageToSend = 1;
819 break;
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100820
Kévin Redon33d1eb72018-07-08 13:58:12 +0200821 case PC_TO_RDR_MECHANICAL:
822 PCtoRDRMechanical();
823 MessageToSend = 1;
824 break;
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100825
Kévin Redon33d1eb72018-07-08 13:58:12 +0200826 case PC_TO_RDR_ABORT:
827 PCtoRDRAbort();
828 MessageToSend = 1;
829 break;
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100830
Kévin Redon33d1eb72018-07-08 13:58:12 +0200831 case PC_TO_RDR_SETDATARATEANDCLOCKFREQUENCY:
832 PCtoRDRSetDataRateAndClockFrequency();
833 MessageToSend = 1;
834 break;
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100835
Kévin Redon33d1eb72018-07-08 13:58:12 +0200836 default:
837 TRACE_DEBUG("default: Not supported: 0x%X\n\r", ccidDriver.sCcidCommand.bMessageType);
838 vCCIDCommandNotSupported();
839 MessageToSend = 1;
840 break;
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100841
Kévin Redon33d1eb72018-07-08 13:58:12 +0200842 }
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100843
Kévin Redon33d1eb72018-07-08 13:58:12 +0200844 if( MessageToSend == 1 ) {
845 vCCIDSendResponse();
846 }
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100847}
848
849
850//------------------------------------------------------------------------------
851/// SETUP request handler for a CCID device
852/// \param pRequest Pointer to a USBGenericRequest instance
853//------------------------------------------------------------------------------
854static void CCID_RequestHandler(const USBGenericRequest *pRequest)
855{
Kévin Redon33d1eb72018-07-08 13:58:12 +0200856 TRACE_DEBUG("CCID_RHl\n\r");
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100857
Kévin Redon33d1eb72018-07-08 13:58:12 +0200858 // Check if this is a class request
859 if (USBGenericRequest_GetType(pRequest) == USBGenericRequest_CLASS) {
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100860
Kévin Redon33d1eb72018-07-08 13:58:12 +0200861 // Check if the request is supported
862 switch (USBGenericRequest_GetRequest(pRequest)) {
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100863
Kévin Redon33d1eb72018-07-08 13:58:12 +0200864 case CCIDGenericRequest_ABORT:
865 TRACE_DEBUG("CCIDGenericRequest_ABORT\n\r");
866 break;
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100867
Kévin Redon33d1eb72018-07-08 13:58:12 +0200868 case CCIDGenericRequest_GET_CLOCK_FREQUENCIES:
869 TRACE_DEBUG("Not supported: CCIDGenericRequest_GET_CLOCK_FREQUENCIES\n\r");
870 // A CCID with bNumClockSupported equal to 00h does not have
871 // to support this request
872 break;
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100873
Kévin Redon33d1eb72018-07-08 13:58:12 +0200874 case CCIDGenericRequest_GET_DATA_RATES:
875 TRACE_DEBUG("Not supported: CCIDGenericRequest_GET_DATA_RATES\n\r");
876 // A CCID with bNumDataRatesSupported equal to 00h does not have
877 // to support this request.
878 break;
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100879
Kévin Redon33d1eb72018-07-08 13:58:12 +0200880 default:
881 TRACE_WARNING( "CCIDDriver_RequestHandler: Unsupported request (%d)\n\r",
882 USBGenericRequest_GetRequest(pRequest));
883 USBD_Stall(0);
884 }
885 }
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100886
Kévin Redon33d1eb72018-07-08 13:58:12 +0200887 else if (USBGenericRequest_GetType(pRequest) == USBGenericRequest_STANDARD) {
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100888
Kévin Redon33d1eb72018-07-08 13:58:12 +0200889 // Forward request to the standard handler
890 USBDDriver_RequestHandler(USBD_GetDriver(), pRequest);
891 }
892 else {
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100893
Kévin Redon33d1eb72018-07-08 13:58:12 +0200894 // Unsupported request type
895 TRACE_WARNING( "CCIDDriver_RequestHandler: Unsupported request type (%d)\n\r",
896 USBGenericRequest_GetType(pRequest));
897 USBD_Stall(0);
898 }
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100899}
900
901
902//------------------------------------------------------------------------------
903// Exported functions
904//------------------------------------------------------------------------------
905
906//------------------------------------------------------------------------------
907/// Optional callback re-implementation
908//------------------------------------------------------------------------------
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100909#if !defined(NOAUTOCALLBACK)
910// not static function
911void USBDCallbacks_RequestReceived(const USBGenericRequest *request)
912{
Kévin Redon33d1eb72018-07-08 13:58:12 +0200913 CCID_RequestHandler(request);
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100914}
915#endif
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100916
917
918//------------------------------------------------------------------------------
919/// Handles SmartCart request
920//------------------------------------------------------------------------------
921void CCID_SmartCardRequest( void )
922{
Kévin Redon33d1eb72018-07-08 13:58:12 +0200923 unsigned char bStatus;
924 TRACE_DEBUG("CCID_req\n");
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100925
Kévin Redon33d1eb72018-07-08 13:58:12 +0200926 do {
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100927
Kévin Redon33d1eb72018-07-08 13:58:12 +0200928 bStatus = CCID_Read( (void*)&ccidDriver.sCcidCommand,
929 sizeof(S_ccid_bulk_out_header),
930 (TransferCallback)&CCIDCommandDispatcher,
931 (void*)0 );
932 }
933 while (0);
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100934}
935
936
937//------------------------------------------------------------------------------
938/// Reads data from the Data OUT endpoint
939/// \param pBuffer Buffer to store the received data
940/// \param dLength data buffer length
941/// \param fCallback Optional callback function
942/// \param pArgument Optional parameter for the callback function
943/// \return USBD_STATUS_LOCKED or USBD_STATUS_SUCCESS
944//------------------------------------------------------------------------------
945unsigned char CCID_Read(void *pBuffer,
Kévin Redon33d1eb72018-07-08 13:58:12 +0200946 unsigned int dLength,
947 TransferCallback fCallback,
948 void *pArgument)
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100949{
Kévin Redon33d1eb72018-07-08 13:58:12 +0200950 return USBD_Read(CCID_EPT_DATA_OUT, pBuffer, dLength, fCallback, pArgument);
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100951}
952
953//------------------------------------------------------------------------------
954/// Sends data through the Data IN endpoint
955/// \param pBuffer Buffer holding the data to transmit
956/// \param dLength Length of data buffer
957/// \param fCallback Optional callback function
958/// \param pArgument Optional parameter for the callback function
959/// \return USBD_STATUS_LOCKED or USBD_STATUS_SUCCESS
960//------------------------------------------------------------------------------
961unsigned char CCID_Write(void *pBuffer,
Kévin Redon33d1eb72018-07-08 13:58:12 +0200962 unsigned int dLength,
963 TransferCallback fCallback,
964 void *pArgument)
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100965{
Kévin Redon33d1eb72018-07-08 13:58:12 +0200966 return USBD_Write(CCID_EPT_DATA_IN, pBuffer, dLength, fCallback, pArgument);
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100967}
968
969//------------------------------------------------------------------------------
970/// Sends data through the interrupt endpoint, ICC insertion event
971/// RDR_to_PC_NotifySlotChange
972/// \return USBD_STATUS_LOCKED or USBD_STATUS_SUCCESS
973//------------------------------------------------------------------------------
974unsigned char CCID_Insertion( void )
975{
Kévin Redon33d1eb72018-07-08 13:58:12 +0200976 TRACE_DEBUG(".");
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100977
Kévin Redon33d1eb72018-07-08 13:58:12 +0200978 // Build the Interrupt-IN message
979 ccidDriver.BufferINT[0] = RDR_TO_PC_NOTIFYSLOTCHANGE;
980 ccidDriver.BufferINT[1] = ICC_INSERTED_EVENT;
981 ccidDriver.SlotStatus = ICC_INSERTED_EVENT;
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100982
Kévin Redon33d1eb72018-07-08 13:58:12 +0200983 // Notify the host that a ICC is inserted
984 return USBD_Write( CCID_EPT_NOTIFICATION, ccidDriver.BufferINT, 2, 0, 0 );
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100985}
986
987//------------------------------------------------------------------------------
988/// Sends data through the interrupt endpoint, ICC removal event
989/// RDR_to_PC_NotifySlotChange
990/// \return USBD_STATUS_LOCKED or USBD_STATUS_SUCCESS
991//------------------------------------------------------------------------------
992unsigned char CCID_Removal( void )
993{
Kévin Redon33d1eb72018-07-08 13:58:12 +0200994 TRACE_DEBUG(".");
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100995
Kévin Redon33d1eb72018-07-08 13:58:12 +0200996 // Build the Interrupt-IN message
997 ccidDriver.BufferINT[0] = RDR_TO_PC_NOTIFYSLOTCHANGE;
998 ccidDriver.BufferINT[1] = ICC_NOT_PRESENT;
999 ccidDriver.SlotStatus = ICC_NOT_PRESENT;
Christina Quastdb7b1ab2015-03-03 12:34:36 +01001000
Kévin Redon33d1eb72018-07-08 13:58:12 +02001001 // Notify the host that a ICC is inserted
1002 return USBD_Write( CCID_EPT_NOTIFICATION, ccidDriver.BufferINT, 2, 0, 0 );
Christina Quastdb7b1ab2015-03-03 12:34:36 +01001003}
1004
1005//------------------------------------------------------------------------------
1006/// Interrupt-IN Messages
1007/// This message is sent when any bit in the bHardwareErrorCode field is set.
1008/// If this message is sent when there is no “outstanding” command, the bSeq
1009/// field will be undefined.
1010/// \param bSlot ICC slot number
1011/// \param bSeq Sequence number of the bulk OUT command when the hardware error
1012/// occured
1013/// \param bHardwareErrorCode Hardware error code
1014/// \return USBD_STATUS_LOCKED or USBD_STATUS_SUCCESS
1015//------------------------------------------------------------------------------
1016unsigned char RDRtoPCHardwareError( unsigned char bSlot,
Kévin Redon33d1eb72018-07-08 13:58:12 +02001017 unsigned char bSeq,
1018 unsigned char bHardwareErrorCode )
Christina Quastdb7b1ab2015-03-03 12:34:36 +01001019{
Kévin Redon33d1eb72018-07-08 13:58:12 +02001020 TRACE_DEBUG(".");
Christina Quastdb7b1ab2015-03-03 12:34:36 +01001021
Kévin Redon33d1eb72018-07-08 13:58:12 +02001022 // Build the Interrupt-IN message
1023 ccidDriver.BufferINT[0] = RDR_TO_PC_HARDWAREERROR;
1024 ccidDriver.BufferINT[1] = bSlot;
1025 ccidDriver.BufferINT[2] = bSeq;
1026 ccidDriver.BufferINT[3] = bHardwareErrorCode;
Christina Quastdb7b1ab2015-03-03 12:34:36 +01001027
Kévin Redon33d1eb72018-07-08 13:58:12 +02001028 // Notify the host that a ICC is inserted
1029 return USBD_Write( CCID_EPT_NOTIFICATION, ccidDriver.BufferINT, 4, 0, 0 );
Christina Quastdb7b1ab2015-03-03 12:34:36 +01001030}
1031
Harald Welte16055642016-03-03 11:02:45 +01001032#endif /* HAVE_CCID */