blob: 7379dc53a75e1cf0c8038e97d16a3f11926e00ae [file] [log] [blame]
Christina Quastdb7b1ab2015-03-03 12:34:36 +01001/* ----------------------------------------------------------------------------
2 * ATMEL Microcontroller Software Support
3 * ----------------------------------------------------------------------------
4 * Copyright (c) 2008, Atmel Corporation
5 *
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions are met:
10 *
11 * - Redistributions of source code must retain the above copyright notice,
12 * this list of conditions and the disclaimer below.
13 *
14 * Atmel's name may not be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
20 * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
23 * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
24 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
25 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
26 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 * ----------------------------------------------------------------------------
28 */
29
30//------------------------------------------------------------------------------
31/// \unit
32///
33/// !Purpose
34///
35/// CCID driver
36///
37/// !Usage
38///
39/// Explanation on the usage of the code made available through the header file.
40//------------------------------------------------------------------------------
41
42//------------------------------------------------------------------------------
43// Headers
44//------------------------------------------------------------------------------
45
46#include "board.h"
Harald Welte16055642016-03-03 11:02:45 +010047#include "simtrace.h"
48
49#ifdef HAVE_CCID
50
Christina Quastdb7b1ab2015-03-03 12:34:36 +010051#include <USBDDriver.h>
52#include <USBRequests.h>
53#include <USBDescriptors.h>
54//#include <usb/device/dfu/dfu.h>
55#include <cciddriverdescriptors.h>
56
57// FIXME: Remove DFU related stuff
58/* no DFU bootloader is being used */
59#define DFU_NUM_IF 0
60#define DFU_IF_DESCRIPTORS_STRUCT
61#define DFU_IF_DESCRIPTORS
62
63#define DFU_NUM_STRINGS 0
64#define DFU_STRING_DESCRIPTORS
65
Christina Quastdb7b1ab2015-03-03 12:34:36 +010066//------------------------------------------------------------------------------
67// Local definition
68//------------------------------------------------------------------------------
69
70/// Constants: IDs: Device product ID.
71//#define CCIDDriverDescriptors_PRODUCTID 0x6129
72#define CCIDDriverDescriptors_PRODUCTID SIMTRACE_PRODUCT_ID
73/// Constants: IDs: Device vendor ID.
74#define CCIDDriverDescriptors_VENDORID ATMEL_VENDOR_ID
75//#define CCIDDriverDescriptors_VENDORID 0x03EB
76/// Constants: IDs: Device release number.
77#define CCIDDriverDescriptors_RELEASE 0x0100
78
Christina Quastdb7b1ab2015-03-03 12:34:36 +010079//------------------------------------------------------------------------------
80// Types
81//------------------------------------------------------------------------------
82
83/// Driver structure for an CCID device
84typedef struct {
85
86 /// Standard USB device driver instance
87 USBDDriver usbdDriver;
88 /// CCID message
89 S_ccid_bulk_in_header sCcidMessage;
90 /// CCID command
91 S_ccid_bulk_out_header sCcidCommand;
92 /// Interrupt message answer
93 unsigned char BufferINT[4];
94 /// Buffer data of message
95 unsigned char ProtocolDataStructure[10];
96 /// Protocol used
97 unsigned char bProtocol;
98 /// SlotStatus
99 /// Bit 0 = Slot 0 current state
100 /// Bit 1 = Slot 0 changed status
101 /// Bit 2 = Slot 1 current state
102 /// Bit 3 = Slot 1 changed status
103 /// Bit 4 = Slot 2 current state
104 /// Bit 5 = Slot 2 changed status
105 unsigned char SlotStatus;
106
107} CCIDDriver;
108
109//------------------------------------------------------------------------------
110// Local variables
111//------------------------------------------------------------------------------
112
113/// Static instance of the CCID device driver.
114static CCIDDriver ccidDriver;
115static CCIDDriverConfigurationDescriptors *configurationDescriptorsFS;
116
117//------------------------------------------------------------------------------
118// Internal functions
119//------------------------------------------------------------------------------
120
121//------------------------------------------------------------------------------
122/// Initializes the CCID device driver.
123//------------------------------------------------------------------------------
124void CCIDDriver_Initialize( void )
125{
Christina Quast7f634862015-04-09 13:34:53 +0200126 configurationDescriptorsFS = (CCIDDriverConfigurationDescriptors *) configurationDescriptorsArr[CFG_NUM_CCID-1];
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100127}
128
129//------------------------------------------------------------------------------
130/// Response Pipe, Bulk-IN Messages
131/// Return the Slot Status to the host
132/// Answer to:
133/// PC_to_RDR_IccPowerOff
134/// PC_to_RDR_GetSlotStatus
135/// PC_to_RDR_IccClock
136/// PC_to_RDR_T0APDU
137/// PC_to_RDR_Mechanical
138/// PC_to_RDR_Abort and Class specific ABORT request
139//------------------------------------------------------------------------------
140static void RDRtoPCSlotStatus( void )
141{
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100142 // Header fields settings
143 ccidDriver.sCcidMessage.bMessageType = RDR_TO_PC_SLOTSTATUS;
144 ccidDriver.sCcidMessage.wLength = 0;
Christina Quast20a68142015-04-09 13:36:28 +0200145
146 if (ccidDriver.SlotStatus == ICC_INSERTED_EVENT) {
147 ccidDriver.sCcidMessage.bStatus = 0; /* ICC present and active card */
148 } else if (ccidDriver.SlotStatus == ICC_NOT_PRESENT) {
149 ccidDriver.sCcidMessage.bStatus = 2; /* No ICC present*/
150 } else{
151 TRACE_ERROR("Strange bStatus");
152 ccidDriver.sCcidMessage.bStatus = 0;
153 }
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100154 ccidDriver.sCcidMessage.bError = 0;
155 // 00h Clock running
156 // 01h Clock stopped in state L
157 // 02h Clock stopped in state H
158 // 03h Clock stopped in an unknown state
159 // All other values are Reserved for Future Use.
160 ccidDriver.sCcidMessage.bSpecific = 0;
161}
162
163//------------------------------------------------------------------------------
164/// Response Pipe, Bulk-IN Messages
165/// Answer to PC_to_RDR_IccPowerOn
166//------------------------------------------------------------------------------
167static void RDRtoPCDatablock_ATR( void )
168{
169 unsigned char i;
170 unsigned char Atr[ATR_SIZE_MAX];
171 unsigned char length;
172 uint32_t status;
173
174 TRACE_DEBUG(".");
175
Christina Quast1a224af2015-03-10 15:11:37 +0100176 status = ISO7816_Datablock_ATR( Atr, &length );
Christina Quastbf464ae2015-04-09 19:42:48 +0200177 ISO7816_Decode_ATR( Atr );
Christina Quastb58434e2015-03-09 17:13:07 +0100178
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100179 if (status == 0) {
180 TRACE_DEBUG("Timeout occured while reading ATR");
181// FIXME: react properly to timeout..
182// return;
183 }
184
Christina Quastb58434e2015-03-09 17:13:07 +0100185// FIXME: More tests? Is bProtocol = Atr[3] ?
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100186 if( length > 5 ) {
Christina Quastb58434e2015-03-09 17:13:07 +0100187 ccidDriver.ProtocolDataStructure[1] = Atr[3]&0x0F; // TD(1)
188 ccidDriver.bProtocol = Atr[3]&0x0F; // TD(1)
Christina Quastbf464ae2015-04-09 19:42:48 +0200189 TRACE_INFO("Protocol data structure: 0x%x\n\r",
190 ccidDriver.ProtocolDataStructure[1]);
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100191 }
192
193 // S_ccid_protocol_t0
194 // bmFindexDindex
195 ccidDriver.ProtocolDataStructure[0] = Atr[2]; // TA(1)
196
197 // bmTCCKST0
198 // For T=0 ,B0 – 0b, B7-2 – 000000b
199 // B1 – Convention used (b1=0 for direct, b1=1 for inverse)
200
201 // bGuardTimeT0
202 // Extra Guardtime between two characters. Add 0 to 254 etu to the normal
203 // guardtime of 12etu. FFh is the same as 00h.
204 ccidDriver.ProtocolDataStructure[2] = Atr[4]; // TC(1)
205 // AT91C_BASE_US0->US_TTGR = 0; // TC1
206
207 // bWaitingIntegerT0
208 // WI for T=0 used to define WWT
209 ccidDriver.ProtocolDataStructure[3] = Atr[7]; // TC(2)
210
211 // bClockStop
212 // ICC Clock Stop Support
213 // 00 = Stopping the Clock is not allowed
214 // 01 = Stop with Clock signal Low
215 // 02 = Stop with Clock signal High
216 // 03 = Stop with Clock either High or Low
217 ccidDriver.ProtocolDataStructure[4] = 0x00; // 0 to 3
218
219 // Header fields settings
220 ccidDriver.sCcidMessage.bMessageType = RDR_TO_PC_DATABLOCK;
221 ccidDriver.sCcidMessage.wLength = length; // Size of ATR
222 ccidDriver.sCcidMessage.bSizeToSend += length; // Size of ATR
223 // bChainParameter: 00 the response APDU begins and ends in this command
224 ccidDriver.sCcidMessage.bSpecific = 0;
225
226 for( i=0; i<length; i++ ) {
227
228 ccidDriver.sCcidMessage.abData[i] = Atr[i];
229 }
230
231 // Set the slot to an active status
232 ccidDriver.sCcidMessage.bStatus = 0;
233 ccidDriver.sCcidMessage.bError = 0;
234}
235
236//------------------------------------------------------------------------------
237/// Response Pipe, Bulk-IN Messages
238/// In other cases, the response message has the following format:
239/// The response data will contain the optional data returned by the ICC,
240/// followed by the 2 byte-size status words SW1-SW2.
241///
242/// Answer to:
243/// PC_to_RDR_XfrBlock
244/// PC_to_RDR_Secure
245//------------------------------------------------------------------------------
246static void RDRtoPCDatablock( void )
247{
248 //TRACE_DEBUG(".");
249
250 // Header fields settings
251 ccidDriver.sCcidMessage.bMessageType = RDR_TO_PC_DATABLOCK;
252 ccidDriver.sCcidMessage.bSizeToSend += ccidDriver.sCcidMessage.wLength;
253 // bChainParameter: 00 the response APDU begins and ends in this command
254 ccidDriver.sCcidMessage.bSpecific = 0;
255
256 // Set the slot to an active status
257 ccidDriver.sCcidMessage.bStatus = 0;
258 ccidDriver.sCcidMessage.bError = 0;
259}
260
261//------------------------------------------------------------------------------
262/// Response Pipe, Bulk-IN Messages
263/// Answer to:
264/// PC_to_RDR_GetParameters
265/// PC_to_RDR_ResetParameters
266/// PC_to_RDR_SetParameters
267//------------------------------------------------------------------------------
268static void RDRtoPCParameters( void )
269{
270 unsigned int i;
271
272 TRACE_DEBUG(".");
273
274 // Header fields settings
275 ccidDriver.sCcidMessage.bMessageType = RDR_TO_PC_PARAMETERS;
276
277 //ccidDriver.sCcidMessage.bStatus = 0;
278 ccidDriver.sCcidMessage.bError = 0;
279
280 if( ccidDriver.ProtocolDataStructure[1] == PROTOCOL_TO ) {
281
282 // T=0
283 ccidDriver.sCcidMessage.wLength = sizeof(S_ccid_protocol_t0);
284 ccidDriver.sCcidMessage.bSpecific = PROTOCOL_TO;
285 }
286 else {
287
288 // T=1
289 ccidDriver.sCcidMessage.wLength = sizeof(S_ccid_protocol_t1);
290 ccidDriver.sCcidMessage.bSpecific = PROTOCOL_T1;
291 }
292
293 ccidDriver.sCcidMessage.bSizeToSend += ccidDriver.sCcidMessage.wLength;
294
295 for( i=0; i<ccidDriver.sCcidMessage.wLength; i++ ) {
296 ccidDriver.sCcidMessage.abData[i] = ccidDriver.ProtocolDataStructure[i];
297 }
298
299}
300
301//------------------------------------------------------------------------------
302/// Response Pipe, Bulk-IN Messages
303/// Answer to:
304/// PC_to_RDR_Escape
305//------------------------------------------------------------------------------
306static void RDRtoPCEscape( unsigned char length, unsigned char *data_send_from_CCID )
307{
308 unsigned int i;
309
310 TRACE_DEBUG(".");
311
312 // Header fields settings
313 ccidDriver.sCcidMessage.bMessageType = RDR_TO_PC_ESCAPE;
314
315 ccidDriver.sCcidMessage.wLength = length;
316
317 ccidDriver.sCcidMessage.bStatus = 0;
318 ccidDriver.sCcidMessage.bError = 0;
319
320 ccidDriver.sCcidMessage.bSpecific = 0; // bRFU
321
322 for( i=0; i<length; i++ ) {
323 ccidDriver.sCcidMessage.abData[i] = data_send_from_CCID[i];
324 }
325}
326
327//------------------------------------------------------------------------------
328/// Response Pipe, Bulk-IN Messages
329/// Answer to:
330/// PC_to_RDR_SetDataRateAndClockFrequency
331//------------------------------------------------------------------------------
332static void RDRtoPCDataRateAndClockFrequency( unsigned int dwClockFrequency,
333 unsigned int dwDataRate )
334{
335 TRACE_DEBUG(".");
336
337 // Header fields settings
338 ccidDriver.sCcidMessage.bMessageType = RDR_TO_PC_DATARATEANDCLOCKFREQUENCY;
339
340 ccidDriver.sCcidMessage.wLength = 8;
341
342 ccidDriver.sCcidMessage.bStatus = 0;
343 ccidDriver.sCcidMessage.bError = 0;
344
345 ccidDriver.sCcidMessage.bSpecific = 0; // bRFU
346
347 ccidDriver.sCcidMessage.abData[0] = dwClockFrequency;
348
349 ccidDriver.sCcidMessage.abData[4] = dwDataRate;
350}
351
352//------------------------------------------------------------------------------
353/// Command Pipe, Bulk-OUT Messages
354/// Power On Command - Cold Reset & Warm Reset
355/// Return the ATR to the host
356//------------------------------------------------------------------------------
357static void PCtoRDRIccPowerOn( void )
358{
359 TRACE_DEBUG(".");
360 if( CCID_FEATURES_AUTO_VOLT == (configurationDescriptorsFS->ccid.dwFeatures & CCID_FEATURES_AUTO_VOLT) ) {
361
362 //bPowerSelect = ccidDriver.sCcidCommand.bSpecific_0;
363 ccidDriver.sCcidCommand.bSpecific_0 = VOLTS_AUTO;
364 }
365
366 ISO7816_warm_reset();
367// ISO7816_cold_reset();
368
369 // for emulation only //JCB
370 if ( ccidDriver.sCcidCommand.bSpecific_0 != VOLTS_5_0 ) {
371
372 TRACE_ERROR("POWER_NOT_SUPPORTED\n\r");
373 }
374
375 else {
376
377 RDRtoPCDatablock_ATR();
378
379 }
380}
381
382//------------------------------------------------------------------------------
383/// Command Pipe, Bulk-OUT Messages
384/// Power Off Command - Set the ICC in an inactive state
385/// Return the slot status to the host
386//------------------------------------------------------------------------------
387static void PCtoRDRIccPowerOff( void )
388{
389 unsigned char bStatus;
390
391 TRACE_DEBUG(".");
392
393 ISO7816_IccPowerOff();
394
395 //JCB stub
396 bStatus = ICC_BS_PRESENT_NOTACTIVATED;
397
398 // Set the slot to an inactive status
399 ccidDriver.sCcidMessage.bStatus = 0;
400 ccidDriver.sCcidMessage.bError = 0;
401
402 // if error, see Table 6.1-2 errors
403
404 // Return the slot status to the host
405 RDRtoPCSlotStatus();
406}
407
408//------------------------------------------------------------------------------
409/// Command Pipe, Bulk-OUT Messages
410/// Get slot status
411//------------------------------------------------------------------------------
412static void PCtoRDRGetSlotStatus( void )
413{
414 TRACE_DEBUG(".");
415
416 ccidDriver.sCcidMessage.bStatus = 0;
417 ccidDriver.sCcidMessage.bError = 0;
418
419 // Return the slot status to the host
420 RDRtoPCSlotStatus();
421}
422
423//------------------------------------------------------------------------------
424/// Command Pipe, Bulk-OUT Messages
425/// If the command header is valid, an APDU command is received and can be read
426/// by the application
427//------------------------------------------------------------------------------
428static void PCtoRDRXfrBlock( void )
429{
Christina Quast73c2b642015-04-07 13:49:26 +0200430 uint16_t msglen = 0;
431 uint32_t ret;
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100432
Christina Quast4a30a372015-05-08 15:34:25 +0200433 TRACE_DEBUG("PCtoRDRXfrBlock\n");
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100434
435 // Check the block length
436 if ( ccidDriver.sCcidCommand.wLength > (configurationDescriptorsFS->ccid.dwMaxCCIDMessageLength-10) ) {
Christina Quast4a30a372015-05-08 15:34:25 +0200437 TRACE_DEBUG("Err block/msg len");
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100438 ccidDriver.sCcidMessage.bStatus = 1;
439 ccidDriver.sCcidMessage.bError = 0;
440 }
441 // check bBWI
442 else if ( 0 != ccidDriver.sCcidCommand.bSpecific_0 ) {
443
444 TRACE_ERROR("Bad bBWI\n\r");
445 }
446 else {
447
448 // APDU or TPDU
449 switch(configurationDescriptorsFS->ccid.dwFeatures
450 & (CCID_FEATURES_EXC_TPDU|CCID_FEATURES_EXC_SAPDU|CCID_FEATURES_EXC_APDU)) {
451
452 case CCID_FEATURES_EXC_TPDU:
453 if (ccidDriver.ProtocolDataStructure[1] == PROTOCOL_TO) {
Christina Quast4a30a372015-05-08 15:34:25 +0200454 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 +0100455
456 // Send commande APDU
Christina Quast73c2b642015-04-07 13:49:26 +0200457 ret = ISO7816_XfrBlockTPDU_T0( ccidDriver.sCcidCommand.APDU ,
458 ccidDriver.sCcidMessage.abData,
459 ccidDriver.sCcidCommand.wLength,
460 &msglen );
461 if (ret != 0) {
462 TRACE_ERROR("APDU could not be sent: (US_CSR = 0x%x)", ret);
463 return;
464 }
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100465 }
466 else {
467 if (ccidDriver.ProtocolDataStructure[1] == PROTOCOL_T1) {
Christina Quast4a30a372015-05-08 15:34:25 +0200468 TRACE_DEBUG("Not supported T=1\n\r");
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100469 }
470 else {
Christina Quast4a30a372015-05-08 15:34:25 +0200471 TRACE_DEBUG("Not supported 0x%x\n\r", ccidDriver.ProtocolDataStructure[1]);
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100472 }
473 }
474 break;
475
476 case CCID_FEATURES_EXC_APDU:
Christina Quast4a30a372015-05-08 15:34:25 +0200477 TRACE_DEBUG("Not supported CCID_FEATURES_EXC_APDU\n\r");
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100478 break;
479
480 default:
481 break;
482 }
483
484 }
485
Christina Quast73c2b642015-04-07 13:49:26 +0200486 ccidDriver.sCcidMessage.wLength = msglen;
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100487 TRACE_DEBUG("USB: 0x%X, 0x%X, 0x%X, 0x%X, 0x%X\n\r", ccidDriver.sCcidMessage.abData[0],
488 ccidDriver.sCcidMessage.abData[1],
489 ccidDriver.sCcidMessage.abData[2],
490 ccidDriver.sCcidMessage.abData[3],
491 ccidDriver.sCcidMessage.abData[4] );
492 RDRtoPCDatablock();
493
494}
495
496//------------------------------------------------------------------------------
497/// Command Pipe, Bulk-OUT Messages
498/// return parameters by the command: RDR_to_PC_Parameters
499//------------------------------------------------------------------------------
500static void PCtoRDRGetParameters( void )
501{
502 TRACE_DEBUG(".");
503
504 // We support only one slot
505
506 // bmIccStatus
507 if( ISO7816_StatusReset() ) {
508 // 0: An ICC is present and active (power is on and stable, RST is inactive
509 ccidDriver.sCcidMessage.bStatus = 0;
510 }
511 else {
512 // 1: An ICC is present and inactive (not activated or shut down by hardware error)
513 ccidDriver.sCcidMessage.bStatus = 1;
514 }
515
516 RDRtoPCParameters();
517}
518
519//------------------------------------------------------------------------------
520/// Command Pipe, Bulk-OUT Messages
521/// This command resets the slot parameters to their default values
522//------------------------------------------------------------------------------
523static void PCtoRDRResetParameters( void )
524{
525 TRACE_DEBUG(".");
526
527 ccidDriver.SlotStatus = ICC_NOT_PRESENT;
528 ccidDriver.sCcidMessage.bStatus = ccidDriver.SlotStatus;
529
530 RDRtoPCParameters();
531}
532
533//------------------------------------------------------------------------------
534/// Command Pipe, Bulk-OUT Messages
535/// This command is used to change the parameters for a given slot.
536//------------------------------------------------------------------------------
537static void PCtoRDRSetParameters( void )
538{
539 TRACE_DEBUG(".");
540
541 ccidDriver.SlotStatus = ccidDriver.sCcidCommand.bSlot;
542 ccidDriver.sCcidMessage.bStatus = ccidDriver.SlotStatus;
543 // Not all feature supported
544
545 RDRtoPCParameters();
546}
547
548//------------------------------------------------------------------------------
549/// Command Pipe, Bulk-OUT Messages
550/// This command allows the CCID manufacturer to define and access extended
551/// features.
552/// Information sent via this command is processed by the CCID control logic.
553//------------------------------------------------------------------------------
554static void PCtoRDREscape( void )
555{
556 TRACE_DEBUG(".");
557
558 // If needed by the user
559 ISO7816_Escape();
560
561 // stub, return all value send
562 RDRtoPCEscape( ccidDriver.sCcidCommand.wLength, ccidDriver.sCcidCommand.APDU);
563}
564
565//------------------------------------------------------------------------------
566/// Command Pipe, Bulk-OUT Messages
567/// This command stops or restarts the clock.
568//------------------------------------------------------------------------------
569static void PCtoRDRICCClock( void )
570{
571 TRACE_DEBUG(".");
572
573 if( 0 == ccidDriver.sCcidCommand.bSpecific_0 ) {
574 // restarts the clock
575 ISO7816_RestartClock();
576 }
577 else {
578 // stop clock in the state shown in the bClockStop field
579 ISO7816_StopClock();
580 }
581
582 RDRtoPCSlotStatus( );
583}
584
585//------------------------------------------------------------------------------
586/// Command Pipe, Bulk-OUT Messages
587/// This command changes the parameters used to perform the transportation of
588/// APDU messages by the T=0 protocol.
589//------------------------------------------------------------------------------
590static void PCtoRDRtoAPDU( void )
591{
592 unsigned char bmChanges;
593 unsigned char bClassGetResponse;
594 unsigned char bClassEnvelope;
595
Christina Quastbf464ae2015-04-09 19:42:48 +0200596 TRACE_INFO(".");
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100597
598 if( configurationDescriptorsFS->ccid.dwFeatures == (CCID_FEATURES_EXC_SAPDU|CCID_FEATURES_EXC_APDU) ) {
599
600 bmChanges = ccidDriver.sCcidCommand.bSpecific_0;
601 bClassGetResponse = ccidDriver.sCcidCommand.bSpecific_1;
602 bClassEnvelope = ccidDriver.sCcidCommand.bSpecific_2;
603
604 ISO7816_toAPDU();
605 }
606
607 RDRtoPCSlotStatus();
608}
609
610//------------------------------------------------------------------------------
611/// Command Pipe, Bulk-OUT Messages
612/// This is a command message to allow entering the PIN for verification or
613/// modification.
614//------------------------------------------------------------------------------
615static void PCtoRDRSecure( void )
616{
617 TRACE_DEBUG(".");
618
619 TRACE_DEBUG("For user\n\r");
620}
621
622//------------------------------------------------------------------------------
623/// Command Pipe, Bulk-OUT Messages
624/// This command is used to manage motorized type CCID functionality.
625/// The Lock Card function is used to hold the ICC.
626/// This prevents an ICC from being easily removed from the CCID.
627/// The Unlock Card function is used to remove the hold initiated by the Lock
628/// Card function
629//------------------------------------------------------------------------------
630static void PCtoRDRMechanical( void )
631{
632 TRACE_DEBUG(".");
633 TRACE_DEBUG("Not implemented\n\r");
634
635 RDRtoPCSlotStatus();
636}
637
638//------------------------------------------------------------------------------
639/// Command Pipe, Bulk-OUT Messages
640/// This command is used with the Control pipe Abort request to tell the CCID
641/// to stop any current transfer at the specified slot and return to a state
642/// where the slot is ready to accept a new command pipe Bulk-OUT message.
643//------------------------------------------------------------------------------
644static void PCtoRDRAbort( void )
645{
646 TRACE_DEBUG(".");
647
648 RDRtoPCSlotStatus();
649}
650
651//------------------------------------------------------------------------------
652/// Command Pipe, Bulk-OUT Messages
653/// This command is used to manually set the data rate and clock frequency of
654/// a specific slot.
655//------------------------------------------------------------------------------
656static void PCtoRDRSetDataRateAndClockFrequency( void )
657{
658 unsigned int dwClockFrequency;
659 unsigned int dwDataRate;
660
661 TRACE_DEBUG(".");
662
663 dwClockFrequency = ccidDriver.sCcidCommand.APDU[0]
664 + (ccidDriver.sCcidCommand.APDU[1]<<8)
665 + (ccidDriver.sCcidCommand.APDU[2]<<16)
666 + (ccidDriver.sCcidCommand.APDU[3]<<24);
667
668 dwDataRate = ccidDriver.sCcidCommand.APDU[4]
669 + (ccidDriver.sCcidCommand.APDU[5]<<8)
670 + (ccidDriver.sCcidCommand.APDU[6]<<16)
671 + (ccidDriver.sCcidCommand.APDU[7]<<24);
672
673 ISO7816_SetDataRateandClockFrequency( dwClockFrequency, dwDataRate );
674
675 RDRtoPCDataRateAndClockFrequency( dwClockFrequency, dwDataRate );
676
677}
678
679//------------------------------------------------------------------------------
680/// Report the CMD_NOT_SUPPORTED error to the host
681//------------------------------------------------------------------------------
682static void vCCIDCommandNotSupported( void )
683{
684 // Command not supported
685 // vCCIDReportError(CMD_NOT_SUPPORTED);
686
687 TRACE_DEBUG("CMD_NOT_SUPPORTED\n\r");
688
689 // Header fields settings
690 ccidDriver.sCcidMessage.bMessageType = RDR_TO_PC_SLOTSTATUS;
691 ccidDriver.sCcidMessage.wLength = 0;
692 ccidDriver.sCcidMessage.bSpecific = 0;
693
694 ccidDriver.sCcidMessage.bStatus |= ICC_CS_FAILED;
695
696 // Send the response to the host
697 //vCCIDSendResponse();
698}
699
700//------------------------------------------------------------------------------
701/// Sent CCID response on USB
702//------------------------------------------------------------------------------
703static void vCCIDSendResponse( void )
704{
705 unsigned char bStatus;
706 TRACE_DEBUG(".");
707
708 do {
Christina Quast7dab6ab2015-04-09 16:53:32 +0200709 bStatus = CCID_Write((void*)&ccidDriver.sCcidMessage,
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100710 ccidDriver.sCcidMessage.bSizeToSend, 0, 0 );
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100711 } while (bStatus != USBD_STATUS_SUCCESS);
Christina Quast1a224af2015-03-10 15:11:37 +0100712
713 TRACE_DEBUG("bStatus: 0x%x\n\r", bStatus);
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100714}
715
716
717//------------------------------------------------------------------------------
718/// Description: CCID Command dispatcher
719//------------------------------------------------------------------------------
Christina Quastb878df92015-04-09 16:54:36 +0200720static void CCIDCommandDispatcher( void *pArg, uint8_t status, uint32_t transferred, uint32_t remaining )
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100721{
722 unsigned char MessageToSend = 0;
723
Christina Quastb878df92015-04-09 16:54:36 +0200724 if (status != USBD_STATUS_SUCCESS) {
725 TRACE_ERROR("USB error: %d", status);
726 return;
727 }
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100728 TRACE_DEBUG("Command: 0x%X 0x%x 0x%X 0x%X 0x%X 0x%X 0x%X\n\r\n\r",
729 (unsigned int)ccidDriver.sCcidCommand.bMessageType,
730 (unsigned int)ccidDriver.sCcidCommand.wLength,
731 (unsigned int)ccidDriver.sCcidCommand.bSlot,
732 (unsigned int)ccidDriver.sCcidCommand.bSeq,
733 (unsigned int)ccidDriver.sCcidCommand.bSpecific_0,
734 (unsigned int)ccidDriver.sCcidCommand.bSpecific_1,
735 (unsigned int)ccidDriver.sCcidCommand.bSpecific_2);
736
737 // Check the slot number
738 if ( ccidDriver.sCcidCommand.bSlot > 0 ) {
739
740 TRACE_ERROR("BAD_SLOT_NUMBER\n\r");
741 }
742
Christina Quastb58434e2015-03-09 17:13:07 +0100743 TRACE_INFO("typ=0x%X\n\r", ccidDriver.sCcidCommand.bMessageType);
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100744
745 ccidDriver.sCcidMessage.bStatus = 0;
746
747 ccidDriver.sCcidMessage.bSeq = ccidDriver.sCcidCommand.bSeq;
748 ccidDriver.sCcidMessage.bSlot = ccidDriver.sCcidCommand.bSlot;
749
750 ccidDriver.sCcidMessage.bSizeToSend = sizeof(S_ccid_bulk_in_header)-(ABDATA_SIZE+1);
751
752
753 // Command dispatcher
754 switch ( ccidDriver.sCcidCommand.bMessageType ) {
755
756 case PC_TO_RDR_ICCPOWERON:
757 PCtoRDRIccPowerOn();
758 MessageToSend = 1;
759 break;
760
761 case PC_TO_RDR_ICCPOWEROFF:
762 PCtoRDRIccPowerOff();
763 MessageToSend = 1;
764 break;
765
766 case PC_TO_RDR_GETSLOTSTATUS:
767 PCtoRDRGetSlotStatus();
768 MessageToSend = 1;
769 break;
770
771 case PC_TO_RDR_XFRBLOCK:
772 PCtoRDRXfrBlock();
773 MessageToSend = 1;
774 break;
775
776 case PC_TO_RDR_GETPARAMETERS:
777 PCtoRDRGetParameters();
778 MessageToSend = 1;
779 break;
780
781 case PC_TO_RDR_RESETPARAMETERS:
782 PCtoRDRResetParameters();
783 MessageToSend = 1;
784 break;
785
786 case PC_TO_RDR_SETPARAMETERS:
787 PCtoRDRSetParameters();
788 MessageToSend = 1;
789 break;
790
791 case PC_TO_RDR_ESCAPE:
792 PCtoRDREscape();
793 MessageToSend = 1;
794 break;
795
796 case PC_TO_RDR_ICCCLOCK:
797 PCtoRDRICCClock();
798 MessageToSend = 1;
799 break;
800
801 case PC_TO_RDR_T0APDU:
802 // Only CCIDs reporting a short or extended APDU level in the dwFeatures
803 // field of the CCID class descriptor may take this command into account.
804 if( (CCID_FEATURES_EXC_SAPDU == (CCID_FEATURES_EXC_SAPDU&configurationDescriptorsFS->ccid.dwFeatures))
805 || (CCID_FEATURES_EXC_APDU == (CCID_FEATURES_EXC_APDU &configurationDescriptorsFS->ccid.dwFeatures)) ) {
806
807 // command supported
808 PCtoRDRtoAPDU();
809 }
810 else {
811 // command not supported
Christina Quastb58434e2015-03-09 17:13:07 +0100812 TRACE_INFO("Not supported: PC_TO_RDR_T0APDU\n\r");
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100813 vCCIDCommandNotSupported();
814 }
815 MessageToSend = 1;
816 break;
817
818 case PC_TO_RDR_SECURE:
819 PCtoRDRSecure();
820 MessageToSend = 1;
821 break;
822
823 case PC_TO_RDR_MECHANICAL:
824 PCtoRDRMechanical();
825 MessageToSend = 1;
826 break;
827
828 case PC_TO_RDR_ABORT:
829 PCtoRDRAbort();
830 MessageToSend = 1;
831 break;
832
833 case PC_TO_RDR_SETDATARATEANDCLOCKFREQUENCY:
834 PCtoRDRSetDataRateAndClockFrequency();
835 MessageToSend = 1;
836 break;
837
838 default:
Christina Quastb58434e2015-03-09 17:13:07 +0100839 TRACE_DEBUG("default: Not supported: 0x%X\n\r", ccidDriver.sCcidCommand.bMessageType);
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100840 vCCIDCommandNotSupported();
841 MessageToSend = 1;
842 break;
843
844 }
845
846 if( MessageToSend == 1 ) {
847 vCCIDSendResponse();
848 }
849}
850
851
Christina Quast46f5cca2015-04-06 23:29:42 +0200852#if 0
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100853//------------------------------------------------------------------------------
854/// SETUP request handler for a CCID device
855/// \param pRequest Pointer to a USBGenericRequest instance
856//------------------------------------------------------------------------------
857static void CCID_RequestHandler(const USBGenericRequest *pRequest)
858{
859 TRACE_DEBUG("CCID_RHl\n\r");
860
861 // Check if this is a class request
862 if (USBGenericRequest_GetType(pRequest) == USBGenericRequest_CLASS) {
863
864 // Check if the request is supported
865 switch (USBGenericRequest_GetRequest(pRequest)) {
866
867 case CCIDGenericRequest_ABORT:
868 TRACE_DEBUG("CCIDGenericRequest_ABORT\n\r");
869 break;
870
871 case CCIDGenericRequest_GET_CLOCK_FREQUENCIES:
Christina Quastb58434e2015-03-09 17:13:07 +0100872 TRACE_DEBUG("Not supported: CCIDGenericRequest_GET_CLOCK_FREQUENCIES\n\r");
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100873 // A CCID with bNumClockSupported equal to 00h does not have
874 // to support this request
875 break;
876
877 case CCIDGenericRequest_GET_DATA_RATES:
Christina Quastb58434e2015-03-09 17:13:07 +0100878 TRACE_DEBUG("Not supported: CCIDGenericRequest_GET_DATA_RATES\n\r");
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100879 // A CCID with bNumDataRatesSupported equal to 00h does not have
880 // to support this request.
881 break;
882
883 default:
884 TRACE_WARNING( "CCIDDriver_RequestHandler: Unsupported request (%d)\n\r",
885 USBGenericRequest_GetRequest(pRequest));
886 USBD_Stall(0);
887 }
888 }
889
890 else if (USBGenericRequest_GetType(pRequest) == USBGenericRequest_STANDARD) {
891
892 // Forward request to the standard handler
893 USBDDriver_RequestHandler(&(ccidDriver.usbdDriver), pRequest);
894 }
895 else {
896
897 // Unsupported request type
898 TRACE_WARNING( "CCIDDriver_RequestHandler: Unsupported request type (%d)\n\r",
899 USBGenericRequest_GetType(pRequest));
900 USBD_Stall(0);
901 }
902}
903
904
905//------------------------------------------------------------------------------
906// Exported functions
907//------------------------------------------------------------------------------
908
909//------------------------------------------------------------------------------
910/// Optional callback re-implementation
911//------------------------------------------------------------------------------
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100912#if !defined(NOAUTOCALLBACK)
913// not static function
914void USBDCallbacks_RequestReceived(const USBGenericRequest *request)
915{
916 CCID_RequestHandler(request);
917}
918#endif
919#endif
920
921
922//------------------------------------------------------------------------------
923/// Handles SmartCart request
924//------------------------------------------------------------------------------
925void CCID_SmartCardRequest( void )
926{
927 unsigned char bStatus;
Christina Quastddb1e7b2015-04-21 23:02:36 +0200928 TRACE_DEBUG("CCID_req\n");
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100929
930 do {
931
932 bStatus = CCID_Read( (void*)&ccidDriver.sCcidCommand,
933 sizeof(S_ccid_bulk_out_header),
934 (TransferCallback)&CCIDCommandDispatcher,
935 (void*)0 );
Christina Quastddb1e7b2015-04-21 23:02:36 +0200936 }
937 while (0);
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100938}
939
940
941//------------------------------------------------------------------------------
942/// Reads data from the Data OUT endpoint
943/// \param pBuffer Buffer to store the received data
944/// \param dLength data buffer length
945/// \param fCallback Optional callback function
946/// \param pArgument Optional parameter for the callback function
947/// \return USBD_STATUS_LOCKED or USBD_STATUS_SUCCESS
948//------------------------------------------------------------------------------
949unsigned char CCID_Read(void *pBuffer,
950 unsigned int dLength,
951 TransferCallback fCallback,
952 void *pArgument)
953{
954 return USBD_Read(CCID_EPT_DATA_OUT, pBuffer, dLength, fCallback, pArgument);
955}
956
957//------------------------------------------------------------------------------
958/// Sends data through the Data IN endpoint
959/// \param pBuffer Buffer holding the data to transmit
960/// \param dLength Length of data buffer
961/// \param fCallback Optional callback function
962/// \param pArgument Optional parameter for the callback function
963/// \return USBD_STATUS_LOCKED or USBD_STATUS_SUCCESS
964//------------------------------------------------------------------------------
965unsigned char CCID_Write(void *pBuffer,
966 unsigned int dLength,
967 TransferCallback fCallback,
968 void *pArgument)
969{
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100970 return USBD_Write(CCID_EPT_DATA_IN, pBuffer, dLength, fCallback, pArgument);
971}
972
973//------------------------------------------------------------------------------
974/// Sends data through the interrupt endpoint, ICC insertion event
975/// RDR_to_PC_NotifySlotChange
976/// \return USBD_STATUS_LOCKED or USBD_STATUS_SUCCESS
977//------------------------------------------------------------------------------
978unsigned char CCID_Insertion( void )
979{
980 TRACE_DEBUG(".");
981
982 // Build the Interrupt-IN message
983 ccidDriver.BufferINT[0] = RDR_TO_PC_NOTIFYSLOTCHANGE;
984 ccidDriver.BufferINT[1] = ICC_INSERTED_EVENT;
985 ccidDriver.SlotStatus = ICC_INSERTED_EVENT;
986
987 // Notify the host that a ICC is inserted
988 return USBD_Write( CCID_EPT_NOTIFICATION, ccidDriver.BufferINT, 2, 0, 0 );
989}
990
991//------------------------------------------------------------------------------
992/// Sends data through the interrupt endpoint, ICC removal event
993/// RDR_to_PC_NotifySlotChange
994/// \return USBD_STATUS_LOCKED or USBD_STATUS_SUCCESS
995//------------------------------------------------------------------------------
996unsigned char CCID_Removal( void )
997{
998 TRACE_DEBUG(".");
999
1000 // Build the Interrupt-IN message
1001 ccidDriver.BufferINT[0] = RDR_TO_PC_NOTIFYSLOTCHANGE;
1002 ccidDriver.BufferINT[1] = ICC_NOT_PRESENT;
1003 ccidDriver.SlotStatus = ICC_NOT_PRESENT;
1004
1005 // Notify the host that a ICC is inserted
1006 return USBD_Write( CCID_EPT_NOTIFICATION, ccidDriver.BufferINT, 2, 0, 0 );
1007}
1008
1009//------------------------------------------------------------------------------
1010/// Interrupt-IN Messages
1011/// This message is sent when any bit in the bHardwareErrorCode field is set.
1012/// If this message is sent when there is no “outstanding” command, the bSeq
1013/// field will be undefined.
1014/// \param bSlot ICC slot number
1015/// \param bSeq Sequence number of the bulk OUT command when the hardware error
1016/// occured
1017/// \param bHardwareErrorCode Hardware error code
1018/// \return USBD_STATUS_LOCKED or USBD_STATUS_SUCCESS
1019//------------------------------------------------------------------------------
1020unsigned char RDRtoPCHardwareError( unsigned char bSlot,
1021 unsigned char bSeq,
1022 unsigned char bHardwareErrorCode )
1023{
1024 TRACE_DEBUG(".");
1025
1026 // Build the Interrupt-IN message
1027 ccidDriver.BufferINT[0] = RDR_TO_PC_HARDWAREERROR;
1028 ccidDriver.BufferINT[1] = bSlot;
1029 ccidDriver.BufferINT[2] = bSeq;
1030 ccidDriver.BufferINT[3] = bHardwareErrorCode;
1031
1032 // Notify the host that a ICC is inserted
1033 return USBD_Write( CCID_EPT_NOTIFICATION, ccidDriver.BufferINT, 4, 0, 0 );
1034}
1035
Harald Welte16055642016-03-03 11:02:45 +01001036#endif /* HAVE_CCID */