blob: 02ab63e175d1439fbd96e0c26046a8b860f0c40e [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"
47#include <USBDDriver.h>
48#include <USBRequests.h>
49#include <USBDescriptors.h>
50//#include <usb/device/dfu/dfu.h>
51#include <cciddriverdescriptors.h>
52
53// FIXME: Remove DFU related stuff
54/* no DFU bootloader is being used */
55#define DFU_NUM_IF 0
56#define DFU_IF_DESCRIPTORS_STRUCT
57#define DFU_IF_DESCRIPTORS
58
59#define DFU_NUM_STRINGS 0
60#define DFU_STRING_DESCRIPTORS
61
Christina Quastdb7b1ab2015-03-03 12:34:36 +010062//------------------------------------------------------------------------------
63// Local definition
64//------------------------------------------------------------------------------
65
66/// Constants: IDs: Device product ID.
67//#define CCIDDriverDescriptors_PRODUCTID 0x6129
68#define CCIDDriverDescriptors_PRODUCTID SIMTRACE_PRODUCT_ID
69/// Constants: IDs: Device vendor ID.
70#define CCIDDriverDescriptors_VENDORID ATMEL_VENDOR_ID
71//#define CCIDDriverDescriptors_VENDORID 0x03EB
72/// Constants: IDs: Device release number.
73#define CCIDDriverDescriptors_RELEASE 0x0100
74
Christina Quastdb7b1ab2015-03-03 12:34:36 +010075//------------------------------------------------------------------------------
76// Types
77//------------------------------------------------------------------------------
78
79/// Driver structure for an CCID device
80typedef struct {
81
82 /// Standard USB device driver instance
83 USBDDriver usbdDriver;
84 /// CCID message
85 S_ccid_bulk_in_header sCcidMessage;
86 /// CCID command
87 S_ccid_bulk_out_header sCcidCommand;
88 /// Interrupt message answer
89 unsigned char BufferINT[4];
90 /// Buffer data of message
91 unsigned char ProtocolDataStructure[10];
92 /// Protocol used
93 unsigned char bProtocol;
94 /// SlotStatus
95 /// Bit 0 = Slot 0 current state
96 /// Bit 1 = Slot 0 changed status
97 /// Bit 2 = Slot 1 current state
98 /// Bit 3 = Slot 1 changed status
99 /// Bit 4 = Slot 2 current state
100 /// Bit 5 = Slot 2 changed status
101 unsigned char SlotStatus;
102
103} CCIDDriver;
104
105//------------------------------------------------------------------------------
106// Local variables
107//------------------------------------------------------------------------------
108
109/// Static instance of the CCID device driver.
110static CCIDDriver ccidDriver;
111static CCIDDriverConfigurationDescriptors *configurationDescriptorsFS;
112
113//------------------------------------------------------------------------------
114// Internal functions
115//------------------------------------------------------------------------------
116
117//------------------------------------------------------------------------------
118/// Initializes the CCID device driver.
119//------------------------------------------------------------------------------
120void CCIDDriver_Initialize( void )
121{
Christina Quast7f634862015-04-09 13:34:53 +0200122 configurationDescriptorsFS = (CCIDDriverConfigurationDescriptors *) configurationDescriptorsArr[CFG_NUM_CCID-1];
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100123}
124
125//------------------------------------------------------------------------------
126/// Response Pipe, Bulk-IN Messages
127/// Return the Slot Status to the host
128/// Answer to:
129/// PC_to_RDR_IccPowerOff
130/// PC_to_RDR_GetSlotStatus
131/// PC_to_RDR_IccClock
132/// PC_to_RDR_T0APDU
133/// PC_to_RDR_Mechanical
134/// PC_to_RDR_Abort and Class specific ABORT request
135//------------------------------------------------------------------------------
136static void RDRtoPCSlotStatus( void )
137{
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100138 // Header fields settings
139 ccidDriver.sCcidMessage.bMessageType = RDR_TO_PC_SLOTSTATUS;
140 ccidDriver.sCcidMessage.wLength = 0;
Christina Quast20a68142015-04-09 13:36:28 +0200141
142 if (ccidDriver.SlotStatus == ICC_INSERTED_EVENT) {
143 ccidDriver.sCcidMessage.bStatus = 0; /* ICC present and active card */
144 } else if (ccidDriver.SlotStatus == ICC_NOT_PRESENT) {
145 ccidDriver.sCcidMessage.bStatus = 2; /* No ICC present*/
146 } else{
147 TRACE_ERROR("Strange bStatus");
148 ccidDriver.sCcidMessage.bStatus = 0;
149 }
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100150 ccidDriver.sCcidMessage.bError = 0;
151 // 00h Clock running
152 // 01h Clock stopped in state L
153 // 02h Clock stopped in state H
154 // 03h Clock stopped in an unknown state
155 // All other values are Reserved for Future Use.
156 ccidDriver.sCcidMessage.bSpecific = 0;
157}
158
159//------------------------------------------------------------------------------
160/// Response Pipe, Bulk-IN Messages
161/// Answer to PC_to_RDR_IccPowerOn
162//------------------------------------------------------------------------------
163static void RDRtoPCDatablock_ATR( void )
164{
165 unsigned char i;
166 unsigned char Atr[ATR_SIZE_MAX];
167 unsigned char length;
168 uint32_t status;
169
170 TRACE_DEBUG(".");
171
Christina Quast1a224af2015-03-10 15:11:37 +0100172 status = ISO7816_Datablock_ATR( Atr, &length );
Christina Quastbf464ae2015-04-09 19:42:48 +0200173 ISO7816_Decode_ATR( Atr );
Christina Quastb58434e2015-03-09 17:13:07 +0100174
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100175 if (status == 0) {
176 TRACE_DEBUG("Timeout occured while reading ATR");
177// FIXME: react properly to timeout..
178// return;
179 }
180
Christina Quastb58434e2015-03-09 17:13:07 +0100181// FIXME: More tests? Is bProtocol = Atr[3] ?
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100182 if( length > 5 ) {
Christina Quastb58434e2015-03-09 17:13:07 +0100183 ccidDriver.ProtocolDataStructure[1] = Atr[3]&0x0F; // TD(1)
184 ccidDriver.bProtocol = Atr[3]&0x0F; // TD(1)
Christina Quastbf464ae2015-04-09 19:42:48 +0200185 TRACE_INFO("Protocol data structure: 0x%x\n\r",
186 ccidDriver.ProtocolDataStructure[1]);
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100187 }
188
189 // S_ccid_protocol_t0
190 // bmFindexDindex
191 ccidDriver.ProtocolDataStructure[0] = Atr[2]; // TA(1)
192
193 // bmTCCKST0
194 // For T=0 ,B0 – 0b, B7-2 – 000000b
195 // B1 – Convention used (b1=0 for direct, b1=1 for inverse)
196
197 // bGuardTimeT0
198 // Extra Guardtime between two characters. Add 0 to 254 etu to the normal
199 // guardtime of 12etu. FFh is the same as 00h.
200 ccidDriver.ProtocolDataStructure[2] = Atr[4]; // TC(1)
201 // AT91C_BASE_US0->US_TTGR = 0; // TC1
202
203 // bWaitingIntegerT0
204 // WI for T=0 used to define WWT
205 ccidDriver.ProtocolDataStructure[3] = Atr[7]; // TC(2)
206
207 // bClockStop
208 // ICC Clock Stop Support
209 // 00 = Stopping the Clock is not allowed
210 // 01 = Stop with Clock signal Low
211 // 02 = Stop with Clock signal High
212 // 03 = Stop with Clock either High or Low
213 ccidDriver.ProtocolDataStructure[4] = 0x00; // 0 to 3
214
215 // Header fields settings
216 ccidDriver.sCcidMessage.bMessageType = RDR_TO_PC_DATABLOCK;
217 ccidDriver.sCcidMessage.wLength = length; // Size of ATR
218 ccidDriver.sCcidMessage.bSizeToSend += length; // Size of ATR
219 // bChainParameter: 00 the response APDU begins and ends in this command
220 ccidDriver.sCcidMessage.bSpecific = 0;
221
222 for( i=0; i<length; i++ ) {
223
224 ccidDriver.sCcidMessage.abData[i] = Atr[i];
225 }
226
227 // Set the slot to an active status
228 ccidDriver.sCcidMessage.bStatus = 0;
229 ccidDriver.sCcidMessage.bError = 0;
230}
231
232//------------------------------------------------------------------------------
233/// Response Pipe, Bulk-IN Messages
234/// In other cases, the response message has the following format:
235/// The response data will contain the optional data returned by the ICC,
236/// followed by the 2 byte-size status words SW1-SW2.
237///
238/// Answer to:
239/// PC_to_RDR_XfrBlock
240/// PC_to_RDR_Secure
241//------------------------------------------------------------------------------
242static void RDRtoPCDatablock( void )
243{
244 //TRACE_DEBUG(".");
245
246 // Header fields settings
247 ccidDriver.sCcidMessage.bMessageType = RDR_TO_PC_DATABLOCK;
248 ccidDriver.sCcidMessage.bSizeToSend += ccidDriver.sCcidMessage.wLength;
249 // bChainParameter: 00 the response APDU begins and ends in this command
250 ccidDriver.sCcidMessage.bSpecific = 0;
251
252 // Set the slot to an active status
253 ccidDriver.sCcidMessage.bStatus = 0;
254 ccidDriver.sCcidMessage.bError = 0;
255}
256
257//------------------------------------------------------------------------------
258/// Response Pipe, Bulk-IN Messages
259/// Answer to:
260/// PC_to_RDR_GetParameters
261/// PC_to_RDR_ResetParameters
262/// PC_to_RDR_SetParameters
263//------------------------------------------------------------------------------
264static void RDRtoPCParameters( void )
265{
266 unsigned int i;
267
268 TRACE_DEBUG(".");
269
270 // Header fields settings
271 ccidDriver.sCcidMessage.bMessageType = RDR_TO_PC_PARAMETERS;
272
273 //ccidDriver.sCcidMessage.bStatus = 0;
274 ccidDriver.sCcidMessage.bError = 0;
275
276 if( ccidDriver.ProtocolDataStructure[1] == PROTOCOL_TO ) {
277
278 // T=0
279 ccidDriver.sCcidMessage.wLength = sizeof(S_ccid_protocol_t0);
280 ccidDriver.sCcidMessage.bSpecific = PROTOCOL_TO;
281 }
282 else {
283
284 // T=1
285 ccidDriver.sCcidMessage.wLength = sizeof(S_ccid_protocol_t1);
286 ccidDriver.sCcidMessage.bSpecific = PROTOCOL_T1;
287 }
288
289 ccidDriver.sCcidMessage.bSizeToSend += ccidDriver.sCcidMessage.wLength;
290
291 for( i=0; i<ccidDriver.sCcidMessage.wLength; i++ ) {
292 ccidDriver.sCcidMessage.abData[i] = ccidDriver.ProtocolDataStructure[i];
293 }
294
295}
296
297//------------------------------------------------------------------------------
298/// Response Pipe, Bulk-IN Messages
299/// Answer to:
300/// PC_to_RDR_Escape
301//------------------------------------------------------------------------------
302static void RDRtoPCEscape( unsigned char length, unsigned char *data_send_from_CCID )
303{
304 unsigned int i;
305
306 TRACE_DEBUG(".");
307
308 // Header fields settings
309 ccidDriver.sCcidMessage.bMessageType = RDR_TO_PC_ESCAPE;
310
311 ccidDriver.sCcidMessage.wLength = length;
312
313 ccidDriver.sCcidMessage.bStatus = 0;
314 ccidDriver.sCcidMessage.bError = 0;
315
316 ccidDriver.sCcidMessage.bSpecific = 0; // bRFU
317
318 for( i=0; i<length; i++ ) {
319 ccidDriver.sCcidMessage.abData[i] = data_send_from_CCID[i];
320 }
321}
322
323//------------------------------------------------------------------------------
324/// Response Pipe, Bulk-IN Messages
325/// Answer to:
326/// PC_to_RDR_SetDataRateAndClockFrequency
327//------------------------------------------------------------------------------
328static void RDRtoPCDataRateAndClockFrequency( unsigned int dwClockFrequency,
329 unsigned int dwDataRate )
330{
331 TRACE_DEBUG(".");
332
333 // Header fields settings
334 ccidDriver.sCcidMessage.bMessageType = RDR_TO_PC_DATARATEANDCLOCKFREQUENCY;
335
336 ccidDriver.sCcidMessage.wLength = 8;
337
338 ccidDriver.sCcidMessage.bStatus = 0;
339 ccidDriver.sCcidMessage.bError = 0;
340
341 ccidDriver.sCcidMessage.bSpecific = 0; // bRFU
342
343 ccidDriver.sCcidMessage.abData[0] = dwClockFrequency;
344
345 ccidDriver.sCcidMessage.abData[4] = dwDataRate;
346}
347
348//------------------------------------------------------------------------------
349/// Command Pipe, Bulk-OUT Messages
350/// Power On Command - Cold Reset & Warm Reset
351/// Return the ATR to the host
352//------------------------------------------------------------------------------
353static void PCtoRDRIccPowerOn( void )
354{
355 TRACE_DEBUG(".");
356 if( CCID_FEATURES_AUTO_VOLT == (configurationDescriptorsFS->ccid.dwFeatures & CCID_FEATURES_AUTO_VOLT) ) {
357
358 //bPowerSelect = ccidDriver.sCcidCommand.bSpecific_0;
359 ccidDriver.sCcidCommand.bSpecific_0 = VOLTS_AUTO;
360 }
361
362 ISO7816_warm_reset();
363// ISO7816_cold_reset();
364
365 // for emulation only //JCB
366 if ( ccidDriver.sCcidCommand.bSpecific_0 != VOLTS_5_0 ) {
367
368 TRACE_ERROR("POWER_NOT_SUPPORTED\n\r");
369 }
370
371 else {
372
373 RDRtoPCDatablock_ATR();
374
375 }
376}
377
378//------------------------------------------------------------------------------
379/// Command Pipe, Bulk-OUT Messages
380/// Power Off Command - Set the ICC in an inactive state
381/// Return the slot status to the host
382//------------------------------------------------------------------------------
383static void PCtoRDRIccPowerOff( void )
384{
385 unsigned char bStatus;
386
387 TRACE_DEBUG(".");
388
389 ISO7816_IccPowerOff();
390
391 //JCB stub
392 bStatus = ICC_BS_PRESENT_NOTACTIVATED;
393
394 // Set the slot to an inactive status
395 ccidDriver.sCcidMessage.bStatus = 0;
396 ccidDriver.sCcidMessage.bError = 0;
397
398 // if error, see Table 6.1-2 errors
399
400 // Return the slot status to the host
401 RDRtoPCSlotStatus();
402}
403
404//------------------------------------------------------------------------------
405/// Command Pipe, Bulk-OUT Messages
406/// Get slot status
407//------------------------------------------------------------------------------
408static void PCtoRDRGetSlotStatus( void )
409{
410 TRACE_DEBUG(".");
411
412 ccidDriver.sCcidMessage.bStatus = 0;
413 ccidDriver.sCcidMessage.bError = 0;
414
415 // Return the slot status to the host
416 RDRtoPCSlotStatus();
417}
418
419//------------------------------------------------------------------------------
420/// Command Pipe, Bulk-OUT Messages
421/// If the command header is valid, an APDU command is received and can be read
422/// by the application
423//------------------------------------------------------------------------------
424static void PCtoRDRXfrBlock( void )
425{
Christina Quast73c2b642015-04-07 13:49:26 +0200426 uint16_t msglen = 0;
427 uint32_t ret;
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100428
Christina Quast4a30a372015-05-08 15:34:25 +0200429 TRACE_DEBUG("PCtoRDRXfrBlock\n");
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100430
431 // Check the block length
432 if ( ccidDriver.sCcidCommand.wLength > (configurationDescriptorsFS->ccid.dwMaxCCIDMessageLength-10) ) {
Christina Quast4a30a372015-05-08 15:34:25 +0200433 TRACE_DEBUG("Err block/msg len");
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100434 ccidDriver.sCcidMessage.bStatus = 1;
435 ccidDriver.sCcidMessage.bError = 0;
436 }
437 // check bBWI
438 else if ( 0 != ccidDriver.sCcidCommand.bSpecific_0 ) {
439
440 TRACE_ERROR("Bad bBWI\n\r");
441 }
442 else {
443
444 // APDU or TPDU
445 switch(configurationDescriptorsFS->ccid.dwFeatures
446 & (CCID_FEATURES_EXC_TPDU|CCID_FEATURES_EXC_SAPDU|CCID_FEATURES_EXC_APDU)) {
447
448 case CCID_FEATURES_EXC_TPDU:
449 if (ccidDriver.ProtocolDataStructure[1] == PROTOCOL_TO) {
Christina Quast4a30a372015-05-08 15:34:25 +0200450 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 +0100451
452 // Send commande APDU
Christina Quast73c2b642015-04-07 13:49:26 +0200453 ret = ISO7816_XfrBlockTPDU_T0( ccidDriver.sCcidCommand.APDU ,
454 ccidDriver.sCcidMessage.abData,
455 ccidDriver.sCcidCommand.wLength,
456 &msglen );
457 if (ret != 0) {
458 TRACE_ERROR("APDU could not be sent: (US_CSR = 0x%x)", ret);
459 return;
460 }
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100461 }
462 else {
463 if (ccidDriver.ProtocolDataStructure[1] == PROTOCOL_T1) {
Christina Quast4a30a372015-05-08 15:34:25 +0200464 TRACE_DEBUG("Not supported T=1\n\r");
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100465 }
466 else {
Christina Quast4a30a372015-05-08 15:34:25 +0200467 TRACE_DEBUG("Not supported 0x%x\n\r", ccidDriver.ProtocolDataStructure[1]);
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100468 }
469 }
470 break;
471
472 case CCID_FEATURES_EXC_APDU:
Christina Quast4a30a372015-05-08 15:34:25 +0200473 TRACE_DEBUG("Not supported CCID_FEATURES_EXC_APDU\n\r");
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100474 break;
475
476 default:
477 break;
478 }
479
480 }
481
Christina Quast73c2b642015-04-07 13:49:26 +0200482 ccidDriver.sCcidMessage.wLength = msglen;
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100483 TRACE_DEBUG("USB: 0x%X, 0x%X, 0x%X, 0x%X, 0x%X\n\r", ccidDriver.sCcidMessage.abData[0],
484 ccidDriver.sCcidMessage.abData[1],
485 ccidDriver.sCcidMessage.abData[2],
486 ccidDriver.sCcidMessage.abData[3],
487 ccidDriver.sCcidMessage.abData[4] );
488 RDRtoPCDatablock();
489
490}
491
492//------------------------------------------------------------------------------
493/// Command Pipe, Bulk-OUT Messages
494/// return parameters by the command: RDR_to_PC_Parameters
495//------------------------------------------------------------------------------
496static void PCtoRDRGetParameters( void )
497{
498 TRACE_DEBUG(".");
499
500 // We support only one slot
501
502 // bmIccStatus
503 if( ISO7816_StatusReset() ) {
504 // 0: An ICC is present and active (power is on and stable, RST is inactive
505 ccidDriver.sCcidMessage.bStatus = 0;
506 }
507 else {
508 // 1: An ICC is present and inactive (not activated or shut down by hardware error)
509 ccidDriver.sCcidMessage.bStatus = 1;
510 }
511
512 RDRtoPCParameters();
513}
514
515//------------------------------------------------------------------------------
516/// Command Pipe, Bulk-OUT Messages
517/// This command resets the slot parameters to their default values
518//------------------------------------------------------------------------------
519static void PCtoRDRResetParameters( void )
520{
521 TRACE_DEBUG(".");
522
523 ccidDriver.SlotStatus = ICC_NOT_PRESENT;
524 ccidDriver.sCcidMessage.bStatus = ccidDriver.SlotStatus;
525
526 RDRtoPCParameters();
527}
528
529//------------------------------------------------------------------------------
530/// Command Pipe, Bulk-OUT Messages
531/// This command is used to change the parameters for a given slot.
532//------------------------------------------------------------------------------
533static void PCtoRDRSetParameters( void )
534{
535 TRACE_DEBUG(".");
536
537 ccidDriver.SlotStatus = ccidDriver.sCcidCommand.bSlot;
538 ccidDriver.sCcidMessage.bStatus = ccidDriver.SlotStatus;
539 // Not all feature supported
540
541 RDRtoPCParameters();
542}
543
544//------------------------------------------------------------------------------
545/// Command Pipe, Bulk-OUT Messages
546/// This command allows the CCID manufacturer to define and access extended
547/// features.
548/// Information sent via this command is processed by the CCID control logic.
549//------------------------------------------------------------------------------
550static void PCtoRDREscape( void )
551{
552 TRACE_DEBUG(".");
553
554 // If needed by the user
555 ISO7816_Escape();
556
557 // stub, return all value send
558 RDRtoPCEscape( ccidDriver.sCcidCommand.wLength, ccidDriver.sCcidCommand.APDU);
559}
560
561//------------------------------------------------------------------------------
562/// Command Pipe, Bulk-OUT Messages
563/// This command stops or restarts the clock.
564//------------------------------------------------------------------------------
565static void PCtoRDRICCClock( void )
566{
567 TRACE_DEBUG(".");
568
569 if( 0 == ccidDriver.sCcidCommand.bSpecific_0 ) {
570 // restarts the clock
571 ISO7816_RestartClock();
572 }
573 else {
574 // stop clock in the state shown in the bClockStop field
575 ISO7816_StopClock();
576 }
577
578 RDRtoPCSlotStatus( );
579}
580
581//------------------------------------------------------------------------------
582/// Command Pipe, Bulk-OUT Messages
583/// This command changes the parameters used to perform the transportation of
584/// APDU messages by the T=0 protocol.
585//------------------------------------------------------------------------------
586static void PCtoRDRtoAPDU( void )
587{
588 unsigned char bmChanges;
589 unsigned char bClassGetResponse;
590 unsigned char bClassEnvelope;
591
Christina Quastbf464ae2015-04-09 19:42:48 +0200592 TRACE_INFO(".");
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100593
594 if( configurationDescriptorsFS->ccid.dwFeatures == (CCID_FEATURES_EXC_SAPDU|CCID_FEATURES_EXC_APDU) ) {
595
596 bmChanges = ccidDriver.sCcidCommand.bSpecific_0;
597 bClassGetResponse = ccidDriver.sCcidCommand.bSpecific_1;
598 bClassEnvelope = ccidDriver.sCcidCommand.bSpecific_2;
599
600 ISO7816_toAPDU();
601 }
602
603 RDRtoPCSlotStatus();
604}
605
606//------------------------------------------------------------------------------
607/// Command Pipe, Bulk-OUT Messages
608/// This is a command message to allow entering the PIN for verification or
609/// modification.
610//------------------------------------------------------------------------------
611static void PCtoRDRSecure( void )
612{
613 TRACE_DEBUG(".");
614
615 TRACE_DEBUG("For user\n\r");
616}
617
618//------------------------------------------------------------------------------
619/// Command Pipe, Bulk-OUT Messages
620/// This command is used to manage motorized type CCID functionality.
621/// The Lock Card function is used to hold the ICC.
622/// This prevents an ICC from being easily removed from the CCID.
623/// The Unlock Card function is used to remove the hold initiated by the Lock
624/// Card function
625//------------------------------------------------------------------------------
626static void PCtoRDRMechanical( void )
627{
628 TRACE_DEBUG(".");
629 TRACE_DEBUG("Not implemented\n\r");
630
631 RDRtoPCSlotStatus();
632}
633
634//------------------------------------------------------------------------------
635/// Command Pipe, Bulk-OUT Messages
636/// This command is used with the Control pipe Abort request to tell the CCID
637/// to stop any current transfer at the specified slot and return to a state
638/// where the slot is ready to accept a new command pipe Bulk-OUT message.
639//------------------------------------------------------------------------------
640static void PCtoRDRAbort( void )
641{
642 TRACE_DEBUG(".");
643
644 RDRtoPCSlotStatus();
645}
646
647//------------------------------------------------------------------------------
648/// Command Pipe, Bulk-OUT Messages
649/// This command is used to manually set the data rate and clock frequency of
650/// a specific slot.
651//------------------------------------------------------------------------------
652static void PCtoRDRSetDataRateAndClockFrequency( void )
653{
654 unsigned int dwClockFrequency;
655 unsigned int dwDataRate;
656
657 TRACE_DEBUG(".");
658
659 dwClockFrequency = ccidDriver.sCcidCommand.APDU[0]
660 + (ccidDriver.sCcidCommand.APDU[1]<<8)
661 + (ccidDriver.sCcidCommand.APDU[2]<<16)
662 + (ccidDriver.sCcidCommand.APDU[3]<<24);
663
664 dwDataRate = ccidDriver.sCcidCommand.APDU[4]
665 + (ccidDriver.sCcidCommand.APDU[5]<<8)
666 + (ccidDriver.sCcidCommand.APDU[6]<<16)
667 + (ccidDriver.sCcidCommand.APDU[7]<<24);
668
669 ISO7816_SetDataRateandClockFrequency( dwClockFrequency, dwDataRate );
670
671 RDRtoPCDataRateAndClockFrequency( dwClockFrequency, dwDataRate );
672
673}
674
675//------------------------------------------------------------------------------
676/// Report the CMD_NOT_SUPPORTED error to the host
677//------------------------------------------------------------------------------
678static void vCCIDCommandNotSupported( void )
679{
680 // Command not supported
681 // vCCIDReportError(CMD_NOT_SUPPORTED);
682
683 TRACE_DEBUG("CMD_NOT_SUPPORTED\n\r");
684
685 // Header fields settings
686 ccidDriver.sCcidMessage.bMessageType = RDR_TO_PC_SLOTSTATUS;
687 ccidDriver.sCcidMessage.wLength = 0;
688 ccidDriver.sCcidMessage.bSpecific = 0;
689
690 ccidDriver.sCcidMessage.bStatus |= ICC_CS_FAILED;
691
692 // Send the response to the host
693 //vCCIDSendResponse();
694}
695
696//------------------------------------------------------------------------------
697/// Sent CCID response on USB
698//------------------------------------------------------------------------------
699static void vCCIDSendResponse( void )
700{
701 unsigned char bStatus;
702 TRACE_DEBUG(".");
703
704 do {
Christina Quast7dab6ab2015-04-09 16:53:32 +0200705 bStatus = CCID_Write((void*)&ccidDriver.sCcidMessage,
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100706 ccidDriver.sCcidMessage.bSizeToSend, 0, 0 );
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100707 } while (bStatus != USBD_STATUS_SUCCESS);
Christina Quast1a224af2015-03-10 15:11:37 +0100708
709 TRACE_DEBUG("bStatus: 0x%x\n\r", bStatus);
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100710}
711
712
713//------------------------------------------------------------------------------
714/// Description: CCID Command dispatcher
715//------------------------------------------------------------------------------
Christina Quastb878df92015-04-09 16:54:36 +0200716static void CCIDCommandDispatcher( void *pArg, uint8_t status, uint32_t transferred, uint32_t remaining )
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100717{
718 unsigned char MessageToSend = 0;
719
Christina Quastb878df92015-04-09 16:54:36 +0200720 if (status != USBD_STATUS_SUCCESS) {
721 TRACE_ERROR("USB error: %d", status);
722 return;
723 }
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100724 TRACE_DEBUG("Command: 0x%X 0x%x 0x%X 0x%X 0x%X 0x%X 0x%X\n\r\n\r",
725 (unsigned int)ccidDriver.sCcidCommand.bMessageType,
726 (unsigned int)ccidDriver.sCcidCommand.wLength,
727 (unsigned int)ccidDriver.sCcidCommand.bSlot,
728 (unsigned int)ccidDriver.sCcidCommand.bSeq,
729 (unsigned int)ccidDriver.sCcidCommand.bSpecific_0,
730 (unsigned int)ccidDriver.sCcidCommand.bSpecific_1,
731 (unsigned int)ccidDriver.sCcidCommand.bSpecific_2);
732
733 // Check the slot number
734 if ( ccidDriver.sCcidCommand.bSlot > 0 ) {
735
736 TRACE_ERROR("BAD_SLOT_NUMBER\n\r");
737 }
738
Christina Quastb58434e2015-03-09 17:13:07 +0100739 TRACE_INFO("typ=0x%X\n\r", ccidDriver.sCcidCommand.bMessageType);
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100740
741 ccidDriver.sCcidMessage.bStatus = 0;
742
743 ccidDriver.sCcidMessage.bSeq = ccidDriver.sCcidCommand.bSeq;
744 ccidDriver.sCcidMessage.bSlot = ccidDriver.sCcidCommand.bSlot;
745
746 ccidDriver.sCcidMessage.bSizeToSend = sizeof(S_ccid_bulk_in_header)-(ABDATA_SIZE+1);
747
748
749 // Command dispatcher
750 switch ( ccidDriver.sCcidCommand.bMessageType ) {
751
752 case PC_TO_RDR_ICCPOWERON:
753 PCtoRDRIccPowerOn();
754 MessageToSend = 1;
755 break;
756
757 case PC_TO_RDR_ICCPOWEROFF:
758 PCtoRDRIccPowerOff();
759 MessageToSend = 1;
760 break;
761
762 case PC_TO_RDR_GETSLOTSTATUS:
763 PCtoRDRGetSlotStatus();
764 MessageToSend = 1;
765 break;
766
767 case PC_TO_RDR_XFRBLOCK:
768 PCtoRDRXfrBlock();
769 MessageToSend = 1;
770 break;
771
772 case PC_TO_RDR_GETPARAMETERS:
773 PCtoRDRGetParameters();
774 MessageToSend = 1;
775 break;
776
777 case PC_TO_RDR_RESETPARAMETERS:
778 PCtoRDRResetParameters();
779 MessageToSend = 1;
780 break;
781
782 case PC_TO_RDR_SETPARAMETERS:
783 PCtoRDRSetParameters();
784 MessageToSend = 1;
785 break;
786
787 case PC_TO_RDR_ESCAPE:
788 PCtoRDREscape();
789 MessageToSend = 1;
790 break;
791
792 case PC_TO_RDR_ICCCLOCK:
793 PCtoRDRICCClock();
794 MessageToSend = 1;
795 break;
796
797 case PC_TO_RDR_T0APDU:
798 // Only CCIDs reporting a short or extended APDU level in the dwFeatures
799 // field of the CCID class descriptor may take this command into account.
800 if( (CCID_FEATURES_EXC_SAPDU == (CCID_FEATURES_EXC_SAPDU&configurationDescriptorsFS->ccid.dwFeatures))
801 || (CCID_FEATURES_EXC_APDU == (CCID_FEATURES_EXC_APDU &configurationDescriptorsFS->ccid.dwFeatures)) ) {
802
803 // command supported
804 PCtoRDRtoAPDU();
805 }
806 else {
807 // command not supported
Christina Quastb58434e2015-03-09 17:13:07 +0100808 TRACE_INFO("Not supported: PC_TO_RDR_T0APDU\n\r");
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100809 vCCIDCommandNotSupported();
810 }
811 MessageToSend = 1;
812 break;
813
814 case PC_TO_RDR_SECURE:
815 PCtoRDRSecure();
816 MessageToSend = 1;
817 break;
818
819 case PC_TO_RDR_MECHANICAL:
820 PCtoRDRMechanical();
821 MessageToSend = 1;
822 break;
823
824 case PC_TO_RDR_ABORT:
825 PCtoRDRAbort();
826 MessageToSend = 1;
827 break;
828
829 case PC_TO_RDR_SETDATARATEANDCLOCKFREQUENCY:
830 PCtoRDRSetDataRateAndClockFrequency();
831 MessageToSend = 1;
832 break;
833
834 default:
Christina Quastb58434e2015-03-09 17:13:07 +0100835 TRACE_DEBUG("default: Not supported: 0x%X\n\r", ccidDriver.sCcidCommand.bMessageType);
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100836 vCCIDCommandNotSupported();
837 MessageToSend = 1;
838 break;
839
840 }
841
842 if( MessageToSend == 1 ) {
843 vCCIDSendResponse();
844 }
845}
846
847
Christina Quast46f5cca2015-04-06 23:29:42 +0200848#if 0
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100849//------------------------------------------------------------------------------
850/// SETUP request handler for a CCID device
851/// \param pRequest Pointer to a USBGenericRequest instance
852//------------------------------------------------------------------------------
853static void CCID_RequestHandler(const USBGenericRequest *pRequest)
854{
855 TRACE_DEBUG("CCID_RHl\n\r");
856
857 // Check if this is a class request
858 if (USBGenericRequest_GetType(pRequest) == USBGenericRequest_CLASS) {
859
860 // Check if the request is supported
861 switch (USBGenericRequest_GetRequest(pRequest)) {
862
863 case CCIDGenericRequest_ABORT:
864 TRACE_DEBUG("CCIDGenericRequest_ABORT\n\r");
865 break;
866
867 case CCIDGenericRequest_GET_CLOCK_FREQUENCIES:
Christina Quastb58434e2015-03-09 17:13:07 +0100868 TRACE_DEBUG("Not supported: CCIDGenericRequest_GET_CLOCK_FREQUENCIES\n\r");
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100869 // A CCID with bNumClockSupported equal to 00h does not have
870 // to support this request
871 break;
872
873 case CCIDGenericRequest_GET_DATA_RATES:
Christina Quastb58434e2015-03-09 17:13:07 +0100874 TRACE_DEBUG("Not supported: CCIDGenericRequest_GET_DATA_RATES\n\r");
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100875 // A CCID with bNumDataRatesSupported equal to 00h does not have
876 // to support this request.
877 break;
878
879 default:
880 TRACE_WARNING( "CCIDDriver_RequestHandler: Unsupported request (%d)\n\r",
881 USBGenericRequest_GetRequest(pRequest));
882 USBD_Stall(0);
883 }
884 }
885
886 else if (USBGenericRequest_GetType(pRequest) == USBGenericRequest_STANDARD) {
887
888 // Forward request to the standard handler
889 USBDDriver_RequestHandler(&(ccidDriver.usbdDriver), pRequest);
890 }
891 else {
892
893 // Unsupported request type
894 TRACE_WARNING( "CCIDDriver_RequestHandler: Unsupported request type (%d)\n\r",
895 USBGenericRequest_GetType(pRequest));
896 USBD_Stall(0);
897 }
898}
899
900
901//------------------------------------------------------------------------------
902// Exported functions
903//------------------------------------------------------------------------------
904
905//------------------------------------------------------------------------------
906/// Optional callback re-implementation
907//------------------------------------------------------------------------------
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100908#if !defined(NOAUTOCALLBACK)
909// not static function
910void USBDCallbacks_RequestReceived(const USBGenericRequest *request)
911{
912 CCID_RequestHandler(request);
913}
914#endif
915#endif
916
917
918//------------------------------------------------------------------------------
919/// Handles SmartCart request
920//------------------------------------------------------------------------------
921void CCID_SmartCardRequest( void )
922{
923 unsigned char bStatus;
Christina Quastddb1e7b2015-04-21 23:02:36 +0200924 TRACE_DEBUG("CCID_req\n");
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100925
926 do {
927
928 bStatus = CCID_Read( (void*)&ccidDriver.sCcidCommand,
929 sizeof(S_ccid_bulk_out_header),
930 (TransferCallback)&CCIDCommandDispatcher,
931 (void*)0 );
Christina Quastddb1e7b2015-04-21 23:02:36 +0200932 }
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,
946 unsigned int dLength,
947 TransferCallback fCallback,
948 void *pArgument)
949{
950 return USBD_Read(CCID_EPT_DATA_OUT, pBuffer, dLength, fCallback, pArgument);
951}
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,
962 unsigned int dLength,
963 TransferCallback fCallback,
964 void *pArgument)
965{
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100966 return USBD_Write(CCID_EPT_DATA_IN, pBuffer, dLength, fCallback, pArgument);
967}
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{
976 TRACE_DEBUG(".");
977
978 // 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;
982
983 // Notify the host that a ICC is inserted
984 return USBD_Write( CCID_EPT_NOTIFICATION, ccidDriver.BufferINT, 2, 0, 0 );
985}
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{
994 TRACE_DEBUG(".");
995
996 // 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;
1000
1001 // Notify the host that a ICC is inserted
1002 return USBD_Write( CCID_EPT_NOTIFICATION, ccidDriver.BufferINT, 2, 0, 0 );
1003}
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,
1017 unsigned char bSeq,
1018 unsigned char bHardwareErrorCode )
1019{
1020 TRACE_DEBUG(".");
1021
1022 // 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;
1027
1028 // Notify the host that a ICC is inserted
1029 return USBD_Write( CCID_EPT_NOTIFICATION, ccidDriver.BufferINT, 4, 0, 0 );
1030}
1031
1032