blob: 2f07f287a653309ca60ec6b6c65d0430bf293187 [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 Quastbf464ae2015-04-09 19:42:48 +020062#define PR TRACE_INFO
Christina Quastdb7b1ab2015-03-03 12:34:36 +010063
64//------------------------------------------------------------------------------
65// Local definition
66//------------------------------------------------------------------------------
67
68/// Constants: IDs: Device product ID.
69//#define CCIDDriverDescriptors_PRODUCTID 0x6129
70#define CCIDDriverDescriptors_PRODUCTID SIMTRACE_PRODUCT_ID
71/// Constants: IDs: Device vendor ID.
72#define CCIDDriverDescriptors_VENDORID ATMEL_VENDOR_ID
73//#define CCIDDriverDescriptors_VENDORID 0x03EB
74/// Constants: IDs: Device release number.
75#define CCIDDriverDescriptors_RELEASE 0x0100
76
Christina Quastdb7b1ab2015-03-03 12:34:36 +010077//------------------------------------------------------------------------------
78// Types
79//------------------------------------------------------------------------------
80
81/// Driver structure for an CCID device
82typedef struct {
83
84 /// Standard USB device driver instance
85 USBDDriver usbdDriver;
86 /// 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;
104
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{
Christina Quast7f634862015-04-09 13:34:53 +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{
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100140 // Header fields settings
141 ccidDriver.sCcidMessage.bMessageType = RDR_TO_PC_SLOTSTATUS;
142 ccidDriver.sCcidMessage.wLength = 0;
Christina Quast20a68142015-04-09 13:36:28 +0200143
144 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 }
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100152 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;
159}
160
161//------------------------------------------------------------------------------
162/// Response Pipe, Bulk-IN Messages
163/// Answer to PC_to_RDR_IccPowerOn
164//------------------------------------------------------------------------------
165static void RDRtoPCDatablock_ATR( void )
166{
167 unsigned char i;
168 unsigned char Atr[ATR_SIZE_MAX];
169 unsigned char length;
170 uint32_t status;
171
172 TRACE_DEBUG(".");
173
Christina Quast1a224af2015-03-10 15:11:37 +0100174 status = ISO7816_Datablock_ATR( Atr, &length );
Christina Quastbf464ae2015-04-09 19:42:48 +0200175 ISO7816_Decode_ATR( Atr );
Christina Quastb58434e2015-03-09 17:13:07 +0100176
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100177 if (status == 0) {
178 TRACE_DEBUG("Timeout occured while reading ATR");
179// FIXME: react properly to timeout..
180// return;
181 }
182
Christina Quastb58434e2015-03-09 17:13:07 +0100183// FIXME: More tests? Is bProtocol = Atr[3] ?
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100184 if( length > 5 ) {
Christina Quastb58434e2015-03-09 17:13:07 +0100185 ccidDriver.ProtocolDataStructure[1] = Atr[3]&0x0F; // TD(1)
186 ccidDriver.bProtocol = Atr[3]&0x0F; // TD(1)
Christina Quastbf464ae2015-04-09 19:42:48 +0200187 TRACE_INFO("Protocol data structure: 0x%x\n\r",
188 ccidDriver.ProtocolDataStructure[1]);
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100189 }
190
191 // S_ccid_protocol_t0
192 // bmFindexDindex
193 ccidDriver.ProtocolDataStructure[0] = Atr[2]; // TA(1)
194
195 // bmTCCKST0
196 // For T=0 ,B0 – 0b, B7-2 – 000000b
197 // B1 – Convention used (b1=0 for direct, b1=1 for inverse)
198
199 // 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
204
205 // bWaitingIntegerT0
206 // WI for T=0 used to define WWT
207 ccidDriver.ProtocolDataStructure[3] = Atr[7]; // TC(2)
208
209 // 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
216
217 // 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;
223
224 for( i=0; i<length; i++ ) {
225
226 ccidDriver.sCcidMessage.abData[i] = Atr[i];
227 }
228
229 // Set the slot to an active status
230 ccidDriver.sCcidMessage.bStatus = 0;
231 ccidDriver.sCcidMessage.bError = 0;
232}
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{
246 //TRACE_DEBUG(".");
247
248 // 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;
253
254 // Set the slot to an active status
255 ccidDriver.sCcidMessage.bStatus = 0;
256 ccidDriver.sCcidMessage.bError = 0;
257}
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{
268 unsigned int i;
269
270 TRACE_DEBUG(".");
271
272 // Header fields settings
273 ccidDriver.sCcidMessage.bMessageType = RDR_TO_PC_PARAMETERS;
274
275 //ccidDriver.sCcidMessage.bStatus = 0;
276 ccidDriver.sCcidMessage.bError = 0;
277
278 if( ccidDriver.ProtocolDataStructure[1] == PROTOCOL_TO ) {
279
280 // T=0
281 ccidDriver.sCcidMessage.wLength = sizeof(S_ccid_protocol_t0);
282 ccidDriver.sCcidMessage.bSpecific = PROTOCOL_TO;
283 }
284 else {
285
286 // T=1
287 ccidDriver.sCcidMessage.wLength = sizeof(S_ccid_protocol_t1);
288 ccidDriver.sCcidMessage.bSpecific = PROTOCOL_T1;
289 }
290
291 ccidDriver.sCcidMessage.bSizeToSend += ccidDriver.sCcidMessage.wLength;
292
293 for( i=0; i<ccidDriver.sCcidMessage.wLength; i++ ) {
294 ccidDriver.sCcidMessage.abData[i] = ccidDriver.ProtocolDataStructure[i];
295 }
296
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{
306 unsigned int i;
307
308 TRACE_DEBUG(".");
309
310 // Header fields settings
311 ccidDriver.sCcidMessage.bMessageType = RDR_TO_PC_ESCAPE;
312
313 ccidDriver.sCcidMessage.wLength = length;
314
315 ccidDriver.sCcidMessage.bStatus = 0;
316 ccidDriver.sCcidMessage.bError = 0;
317
318 ccidDriver.sCcidMessage.bSpecific = 0; // bRFU
319
320 for( i=0; i<length; i++ ) {
321 ccidDriver.sCcidMessage.abData[i] = data_send_from_CCID[i];
322 }
323}
324
325//------------------------------------------------------------------------------
326/// Response Pipe, Bulk-IN Messages
327/// Answer to:
328/// PC_to_RDR_SetDataRateAndClockFrequency
329//------------------------------------------------------------------------------
330static void RDRtoPCDataRateAndClockFrequency( unsigned int dwClockFrequency,
331 unsigned int dwDataRate )
332{
333 TRACE_DEBUG(".");
334
335 // Header fields settings
336 ccidDriver.sCcidMessage.bMessageType = RDR_TO_PC_DATARATEANDCLOCKFREQUENCY;
337
338 ccidDriver.sCcidMessage.wLength = 8;
339
340 ccidDriver.sCcidMessage.bStatus = 0;
341 ccidDriver.sCcidMessage.bError = 0;
342
343 ccidDriver.sCcidMessage.bSpecific = 0; // bRFU
344
345 ccidDriver.sCcidMessage.abData[0] = dwClockFrequency;
346
347 ccidDriver.sCcidMessage.abData[4] = dwDataRate;
348}
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{
357 TRACE_DEBUG(".");
358 if( CCID_FEATURES_AUTO_VOLT == (configurationDescriptorsFS->ccid.dwFeatures & CCID_FEATURES_AUTO_VOLT) ) {
359
360 //bPowerSelect = ccidDriver.sCcidCommand.bSpecific_0;
361 ccidDriver.sCcidCommand.bSpecific_0 = VOLTS_AUTO;
362 }
363
364 ISO7816_warm_reset();
365// ISO7816_cold_reset();
366
367 // for emulation only //JCB
368 if ( ccidDriver.sCcidCommand.bSpecific_0 != VOLTS_5_0 ) {
369
370 TRACE_ERROR("POWER_NOT_SUPPORTED\n\r");
371 }
372
373 else {
374
375 RDRtoPCDatablock_ATR();
376
377 }
378}
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{
387 unsigned char bStatus;
388
389 TRACE_DEBUG(".");
390
391 ISO7816_IccPowerOff();
392
393 //JCB stub
394 bStatus = ICC_BS_PRESENT_NOTACTIVATED;
395
396 // Set the slot to an inactive status
397 ccidDriver.sCcidMessage.bStatus = 0;
398 ccidDriver.sCcidMessage.bError = 0;
399
400 // if error, see Table 6.1-2 errors
401
402 // Return the slot status to the host
403 RDRtoPCSlotStatus();
404}
405
406//------------------------------------------------------------------------------
407/// Command Pipe, Bulk-OUT Messages
408/// Get slot status
409//------------------------------------------------------------------------------
410static void PCtoRDRGetSlotStatus( void )
411{
412 TRACE_DEBUG(".");
413
414 ccidDriver.sCcidMessage.bStatus = 0;
415 ccidDriver.sCcidMessage.bError = 0;
416
417 // Return the slot status to the host
418 RDRtoPCSlotStatus();
419}
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{
Christina Quast73c2b642015-04-07 13:49:26 +0200428 uint16_t msglen = 0;
429 uint32_t ret;
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100430
Christina Quastbf464ae2015-04-09 19:42:48 +0200431 PR("PCtoRDRXfrBlock\n");
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100432
433 // Check the block length
434 if ( ccidDriver.sCcidCommand.wLength > (configurationDescriptorsFS->ccid.dwMaxCCIDMessageLength-10) ) {
Christina Quastbf464ae2015-04-09 19:42:48 +0200435 PR("Err block/msg len");
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100436 ccidDriver.sCcidMessage.bStatus = 1;
437 ccidDriver.sCcidMessage.bError = 0;
438 }
439 // check bBWI
440 else if ( 0 != ccidDriver.sCcidCommand.bSpecific_0 ) {
441
442 TRACE_ERROR("Bad bBWI\n\r");
443 }
444 else {
445
446 // APDU or TPDU
447 switch(configurationDescriptorsFS->ccid.dwFeatures
448 & (CCID_FEATURES_EXC_TPDU|CCID_FEATURES_EXC_SAPDU|CCID_FEATURES_EXC_APDU)) {
449
450 case CCID_FEATURES_EXC_TPDU:
451 if (ccidDriver.ProtocolDataStructure[1] == PROTOCOL_TO) {
Christina Quastbf464ae2015-04-09 19:42:48 +0200452 PR("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
454 // Send commande APDU
Christina Quast73c2b642015-04-07 13:49:26 +0200455 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 }
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100463 }
464 else {
465 if (ccidDriver.ProtocolDataStructure[1] == PROTOCOL_T1) {
Christina Quastbf464ae2015-04-09 19:42:48 +0200466 PR("Not supported T=1\n\r");
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100467 }
468 else {
Christina Quastbf464ae2015-04-09 19:42:48 +0200469 PR("Not supported 0x%x\n\r", ccidDriver.ProtocolDataStructure[1]);
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100470 }
471 }
472 break;
473
474 case CCID_FEATURES_EXC_APDU:
Christina Quastbf464ae2015-04-09 19:42:48 +0200475 PR("Not supported CCID_FEATURES_EXC_APDU\n\r");
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100476 break;
477
478 default:
479 break;
480 }
481
482 }
483
Christina Quast73c2b642015-04-07 13:49:26 +0200484 ccidDriver.sCcidMessage.wLength = msglen;
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100485 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();
491
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{
500 TRACE_DEBUG(".");
501
502 // We support only one slot
503
504 // 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 }
513
514 RDRtoPCParameters();
515}
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{
523 TRACE_DEBUG(".");
524
525 ccidDriver.SlotStatus = ICC_NOT_PRESENT;
526 ccidDriver.sCcidMessage.bStatus = ccidDriver.SlotStatus;
527
528 RDRtoPCParameters();
529}
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{
537 TRACE_DEBUG(".");
538
539 ccidDriver.SlotStatus = ccidDriver.sCcidCommand.bSlot;
540 ccidDriver.sCcidMessage.bStatus = ccidDriver.SlotStatus;
541 // Not all feature supported
542
543 RDRtoPCParameters();
544}
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{
554 TRACE_DEBUG(".");
555
556 // If needed by the user
557 ISO7816_Escape();
558
559 // stub, return all value send
560 RDRtoPCEscape( ccidDriver.sCcidCommand.wLength, ccidDriver.sCcidCommand.APDU);
561}
562
563//------------------------------------------------------------------------------
564/// Command Pipe, Bulk-OUT Messages
565/// This command stops or restarts the clock.
566//------------------------------------------------------------------------------
567static void PCtoRDRICCClock( void )
568{
569 TRACE_DEBUG(".");
570
571 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 }
579
580 RDRtoPCSlotStatus( );
581}
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{
590 unsigned char bmChanges;
591 unsigned char bClassGetResponse;
592 unsigned char bClassEnvelope;
593
Christina Quastbf464ae2015-04-09 19:42:48 +0200594 TRACE_INFO(".");
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100595
596 if( configurationDescriptorsFS->ccid.dwFeatures == (CCID_FEATURES_EXC_SAPDU|CCID_FEATURES_EXC_APDU) ) {
597
598 bmChanges = ccidDriver.sCcidCommand.bSpecific_0;
599 bClassGetResponse = ccidDriver.sCcidCommand.bSpecific_1;
600 bClassEnvelope = ccidDriver.sCcidCommand.bSpecific_2;
601
602 ISO7816_toAPDU();
603 }
604
605 RDRtoPCSlotStatus();
606}
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{
615 TRACE_DEBUG(".");
616
617 TRACE_DEBUG("For user\n\r");
618}
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{
630 TRACE_DEBUG(".");
631 TRACE_DEBUG("Not implemented\n\r");
632
633 RDRtoPCSlotStatus();
634}
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{
644 TRACE_DEBUG(".");
645
646 RDRtoPCSlotStatus();
647}
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{
656 unsigned int dwClockFrequency;
657 unsigned int dwDataRate;
658
659 TRACE_DEBUG(".");
660
661 dwClockFrequency = ccidDriver.sCcidCommand.APDU[0]
662 + (ccidDriver.sCcidCommand.APDU[1]<<8)
663 + (ccidDriver.sCcidCommand.APDU[2]<<16)
664 + (ccidDriver.sCcidCommand.APDU[3]<<24);
665
666 dwDataRate = ccidDriver.sCcidCommand.APDU[4]
667 + (ccidDriver.sCcidCommand.APDU[5]<<8)
668 + (ccidDriver.sCcidCommand.APDU[6]<<16)
669 + (ccidDriver.sCcidCommand.APDU[7]<<24);
670
671 ISO7816_SetDataRateandClockFrequency( dwClockFrequency, dwDataRate );
672
673 RDRtoPCDataRateAndClockFrequency( dwClockFrequency, dwDataRate );
674
675}
676
677//------------------------------------------------------------------------------
678/// Report the CMD_NOT_SUPPORTED error to the host
679//------------------------------------------------------------------------------
680static void vCCIDCommandNotSupported( void )
681{
682 // Command not supported
683 // vCCIDReportError(CMD_NOT_SUPPORTED);
684
685 TRACE_DEBUG("CMD_NOT_SUPPORTED\n\r");
686
687 // Header fields settings
688 ccidDriver.sCcidMessage.bMessageType = RDR_TO_PC_SLOTSTATUS;
689 ccidDriver.sCcidMessage.wLength = 0;
690 ccidDriver.sCcidMessage.bSpecific = 0;
691
692 ccidDriver.sCcidMessage.bStatus |= ICC_CS_FAILED;
693
694 // Send the response to the host
695 //vCCIDSendResponse();
696}
697
698//------------------------------------------------------------------------------
699/// Sent CCID response on USB
700//------------------------------------------------------------------------------
701static void vCCIDSendResponse( void )
702{
703 unsigned char bStatus;
704 TRACE_DEBUG(".");
705
706 do {
Christina Quast7dab6ab2015-04-09 16:53:32 +0200707 bStatus = CCID_Write((void*)&ccidDriver.sCcidMessage,
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100708 ccidDriver.sCcidMessage.bSizeToSend, 0, 0 );
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100709 } while (bStatus != USBD_STATUS_SUCCESS);
Christina Quast1a224af2015-03-10 15:11:37 +0100710
711 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{
720 unsigned char MessageToSend = 0;
721
Christina Quastb878df92015-04-09 16:54:36 +0200722 if (status != USBD_STATUS_SUCCESS) {
723 TRACE_ERROR("USB error: %d", status);
724 return;
725 }
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100726 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);
734
735 // Check the slot number
736 if ( ccidDriver.sCcidCommand.bSlot > 0 ) {
737
738 TRACE_ERROR("BAD_SLOT_NUMBER\n\r");
739 }
740
Christina Quastb58434e2015-03-09 17:13:07 +0100741 TRACE_INFO("typ=0x%X\n\r", ccidDriver.sCcidCommand.bMessageType);
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100742
743 ccidDriver.sCcidMessage.bStatus = 0;
744
745 ccidDriver.sCcidMessage.bSeq = ccidDriver.sCcidCommand.bSeq;
746 ccidDriver.sCcidMessage.bSlot = ccidDriver.sCcidCommand.bSlot;
747
748 ccidDriver.sCcidMessage.bSizeToSend = sizeof(S_ccid_bulk_in_header)-(ABDATA_SIZE+1);
749
750
751 // Command dispatcher
752 switch ( ccidDriver.sCcidCommand.bMessageType ) {
753
754 case PC_TO_RDR_ICCPOWERON:
755 PCtoRDRIccPowerOn();
756 MessageToSend = 1;
757 break;
758
759 case PC_TO_RDR_ICCPOWEROFF:
760 PCtoRDRIccPowerOff();
761 MessageToSend = 1;
762 break;
763
764 case PC_TO_RDR_GETSLOTSTATUS:
765 PCtoRDRGetSlotStatus();
766 MessageToSend = 1;
767 break;
768
769 case PC_TO_RDR_XFRBLOCK:
770 PCtoRDRXfrBlock();
771 MessageToSend = 1;
772 break;
773
774 case PC_TO_RDR_GETPARAMETERS:
775 PCtoRDRGetParameters();
776 MessageToSend = 1;
777 break;
778
779 case PC_TO_RDR_RESETPARAMETERS:
780 PCtoRDRResetParameters();
781 MessageToSend = 1;
782 break;
783
784 case PC_TO_RDR_SETPARAMETERS:
785 PCtoRDRSetParameters();
786 MessageToSend = 1;
787 break;
788
789 case PC_TO_RDR_ESCAPE:
790 PCtoRDREscape();
791 MessageToSend = 1;
792 break;
793
794 case PC_TO_RDR_ICCCLOCK:
795 PCtoRDRICCClock();
796 MessageToSend = 1;
797 break;
798
799 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)) ) {
804
805 // command supported
806 PCtoRDRtoAPDU();
807 }
808 else {
809 // command not supported
Christina Quastb58434e2015-03-09 17:13:07 +0100810 TRACE_INFO("Not supported: PC_TO_RDR_T0APDU\n\r");
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100811 vCCIDCommandNotSupported();
812 }
813 MessageToSend = 1;
814 break;
815
816 case PC_TO_RDR_SECURE:
817 PCtoRDRSecure();
818 MessageToSend = 1;
819 break;
820
821 case PC_TO_RDR_MECHANICAL:
822 PCtoRDRMechanical();
823 MessageToSend = 1;
824 break;
825
826 case PC_TO_RDR_ABORT:
827 PCtoRDRAbort();
828 MessageToSend = 1;
829 break;
830
831 case PC_TO_RDR_SETDATARATEANDCLOCKFREQUENCY:
832 PCtoRDRSetDataRateAndClockFrequency();
833 MessageToSend = 1;
834 break;
835
836 default:
Christina Quastb58434e2015-03-09 17:13:07 +0100837 TRACE_DEBUG("default: Not supported: 0x%X\n\r", ccidDriver.sCcidCommand.bMessageType);
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100838 vCCIDCommandNotSupported();
839 MessageToSend = 1;
840 break;
841
842 }
843
844 if( MessageToSend == 1 ) {
845 vCCIDSendResponse();
846 }
847}
848
849
Christina Quast46f5cca2015-04-06 23:29:42 +0200850#if 0
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100851//------------------------------------------------------------------------------
852/// SETUP request handler for a CCID device
853/// \param pRequest Pointer to a USBGenericRequest instance
854//------------------------------------------------------------------------------
855static void CCID_RequestHandler(const USBGenericRequest *pRequest)
856{
857 TRACE_DEBUG("CCID_RHl\n\r");
858
859 // Check if this is a class request
860 if (USBGenericRequest_GetType(pRequest) == USBGenericRequest_CLASS) {
861
862 // Check if the request is supported
863 switch (USBGenericRequest_GetRequest(pRequest)) {
864
865 case CCIDGenericRequest_ABORT:
866 TRACE_DEBUG("CCIDGenericRequest_ABORT\n\r");
867 break;
868
869 case CCIDGenericRequest_GET_CLOCK_FREQUENCIES:
Christina Quastb58434e2015-03-09 17:13:07 +0100870 TRACE_DEBUG("Not supported: CCIDGenericRequest_GET_CLOCK_FREQUENCIES\n\r");
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100871 // A CCID with bNumClockSupported equal to 00h does not have
872 // to support this request
873 break;
874
875 case CCIDGenericRequest_GET_DATA_RATES:
Christina Quastb58434e2015-03-09 17:13:07 +0100876 TRACE_DEBUG("Not supported: CCIDGenericRequest_GET_DATA_RATES\n\r");
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100877 // A CCID with bNumDataRatesSupported equal to 00h does not have
878 // to support this request.
879 break;
880
881 default:
882 TRACE_WARNING( "CCIDDriver_RequestHandler: Unsupported request (%d)\n\r",
883 USBGenericRequest_GetRequest(pRequest));
884 USBD_Stall(0);
885 }
886 }
887
888 else if (USBGenericRequest_GetType(pRequest) == USBGenericRequest_STANDARD) {
889
890 // Forward request to the standard handler
891 USBDDriver_RequestHandler(&(ccidDriver.usbdDriver), pRequest);
892 }
893 else {
894
895 // Unsupported request type
896 TRACE_WARNING( "CCIDDriver_RequestHandler: Unsupported request type (%d)\n\r",
897 USBGenericRequest_GetType(pRequest));
898 USBD_Stall(0);
899 }
900}
901
902
903//------------------------------------------------------------------------------
904// Exported functions
905//------------------------------------------------------------------------------
906
907//------------------------------------------------------------------------------
908/// Optional callback re-implementation
909//------------------------------------------------------------------------------
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100910#if !defined(NOAUTOCALLBACK)
911// not static function
912void USBDCallbacks_RequestReceived(const USBGenericRequest *request)
913{
914 CCID_RequestHandler(request);
915}
916#endif
917#endif
918
919
920//------------------------------------------------------------------------------
921/// Handles SmartCart request
922//------------------------------------------------------------------------------
923void CCID_SmartCardRequest( void )
924{
925 unsigned char bStatus;
Christina Quastbf464ae2015-04-09 19:42:48 +0200926 TRACE_INFO("CCID_req\n");
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100927
928 do {
929
930 bStatus = CCID_Read( (void*)&ccidDriver.sCcidCommand,
931 sizeof(S_ccid_bulk_out_header),
932 (TransferCallback)&CCIDCommandDispatcher,
933 (void*)0 );
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100934 }
935 while (bStatus != USBD_STATUS_SUCCESS);
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100936}
937
938
939//------------------------------------------------------------------------------
940/// Reads data from the Data OUT endpoint
941/// \param pBuffer Buffer to store the received data
942/// \param dLength data buffer length
943/// \param fCallback Optional callback function
944/// \param pArgument Optional parameter for the callback function
945/// \return USBD_STATUS_LOCKED or USBD_STATUS_SUCCESS
946//------------------------------------------------------------------------------
947unsigned char CCID_Read(void *pBuffer,
948 unsigned int dLength,
949 TransferCallback fCallback,
950 void *pArgument)
951{
952 return USBD_Read(CCID_EPT_DATA_OUT, pBuffer, dLength, fCallback, pArgument);
953}
954
955//------------------------------------------------------------------------------
956/// Sends data through the Data IN endpoint
957/// \param pBuffer Buffer holding the data to transmit
958/// \param dLength Length of data buffer
959/// \param fCallback Optional callback function
960/// \param pArgument Optional parameter for the callback function
961/// \return USBD_STATUS_LOCKED or USBD_STATUS_SUCCESS
962//------------------------------------------------------------------------------
963unsigned char CCID_Write(void *pBuffer,
964 unsigned int dLength,
965 TransferCallback fCallback,
966 void *pArgument)
967{
Christina Quastbf464ae2015-04-09 19:42:48 +0200968 PR("ccid wr\n");
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100969 return USBD_Write(CCID_EPT_DATA_IN, pBuffer, dLength, fCallback, pArgument);
970}
971
972//------------------------------------------------------------------------------
973/// Sends data through the interrupt endpoint, ICC insertion event
974/// RDR_to_PC_NotifySlotChange
975/// \return USBD_STATUS_LOCKED or USBD_STATUS_SUCCESS
976//------------------------------------------------------------------------------
977unsigned char CCID_Insertion( void )
978{
979 TRACE_DEBUG(".");
980
981 // Build the Interrupt-IN message
982 ccidDriver.BufferINT[0] = RDR_TO_PC_NOTIFYSLOTCHANGE;
983 ccidDriver.BufferINT[1] = ICC_INSERTED_EVENT;
984 ccidDriver.SlotStatus = ICC_INSERTED_EVENT;
985
986 // Notify the host that a ICC is inserted
987 return USBD_Write( CCID_EPT_NOTIFICATION, ccidDriver.BufferINT, 2, 0, 0 );
988}
989
990//------------------------------------------------------------------------------
991/// Sends data through the interrupt endpoint, ICC removal event
992/// RDR_to_PC_NotifySlotChange
993/// \return USBD_STATUS_LOCKED or USBD_STATUS_SUCCESS
994//------------------------------------------------------------------------------
995unsigned char CCID_Removal( void )
996{
997 TRACE_DEBUG(".");
998
999 // Build the Interrupt-IN message
1000 ccidDriver.BufferINT[0] = RDR_TO_PC_NOTIFYSLOTCHANGE;
1001 ccidDriver.BufferINT[1] = ICC_NOT_PRESENT;
1002 ccidDriver.SlotStatus = ICC_NOT_PRESENT;
1003
1004 // Notify the host that a ICC is inserted
1005 return USBD_Write( CCID_EPT_NOTIFICATION, ccidDriver.BufferINT, 2, 0, 0 );
1006}
1007
1008//------------------------------------------------------------------------------
1009/// Interrupt-IN Messages
1010/// This message is sent when any bit in the bHardwareErrorCode field is set.
1011/// If this message is sent when there is no “outstanding” command, the bSeq
1012/// field will be undefined.
1013/// \param bSlot ICC slot number
1014/// \param bSeq Sequence number of the bulk OUT command when the hardware error
1015/// occured
1016/// \param bHardwareErrorCode Hardware error code
1017/// \return USBD_STATUS_LOCKED or USBD_STATUS_SUCCESS
1018//------------------------------------------------------------------------------
1019unsigned char RDRtoPCHardwareError( unsigned char bSlot,
1020 unsigned char bSeq,
1021 unsigned char bHardwareErrorCode )
1022{
1023 TRACE_DEBUG(".");
1024
1025 // Build the Interrupt-IN message
1026 ccidDriver.BufferINT[0] = RDR_TO_PC_HARDWAREERROR;
1027 ccidDriver.BufferINT[1] = bSlot;
1028 ccidDriver.BufferINT[2] = bSeq;
1029 ccidDriver.BufferINT[3] = bHardwareErrorCode;
1030
1031 // Notify the host that a ICC is inserted
1032 return USBD_Write( CCID_EPT_NOTIFICATION, ccidDriver.BufferINT, 4, 0, 0 );
1033}
1034
1035