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