blob: 0bba14707fb8ad768ecd31c66cd7b3ed7abcfcda [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
76/// Returns the minimum between two values.
77#define MIN(a, b) ((a < b) ? a : b)
78
79//------------------------------------------------------------------------------
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 Quast4b1e98d2015-04-06 23:28:02 +0200126 configurationDescriptorsFS = (CCIDDriverConfigurationDescriptors *) configurationDescriptorsArr[CFG_NUM_CCID];
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{
142 TRACE_DEBUG(".");
143
144 // Header fields settings
145 ccidDriver.sCcidMessage.bMessageType = RDR_TO_PC_SLOTSTATUS;
146 ccidDriver.sCcidMessage.wLength = 0;
147 ccidDriver.sCcidMessage.bStatus = ccidDriver.SlotStatus;
148 ccidDriver.sCcidMessage.bError = 0;
149 // 00h Clock running
150 // 01h Clock stopped in state L
151 // 02h Clock stopped in state H
152 // 03h Clock stopped in an unknown state
153 // All other values are Reserved for Future Use.
154 ccidDriver.sCcidMessage.bSpecific = 0;
155}
156
157//------------------------------------------------------------------------------
158/// Response Pipe, Bulk-IN Messages
159/// Answer to PC_to_RDR_IccPowerOn
160//------------------------------------------------------------------------------
161static void RDRtoPCDatablock_ATR( void )
162{
163 unsigned char i;
164 unsigned char Atr[ATR_SIZE_MAX];
165 unsigned char length;
166 uint32_t status;
167
168 TRACE_DEBUG(".");
169
Christina Quast1a224af2015-03-10 15:11:37 +0100170 status = ISO7816_Datablock_ATR( Atr, &length );
Christina Quastb58434e2015-03-09 17:13:07 +0100171// ISO7816_Decode_ATR( Atr );
172
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100173 if (status == 0) {
174 TRACE_DEBUG("Timeout occured while reading ATR");
175// FIXME: react properly to timeout..
176// return;
177 }
178
Christina Quastb58434e2015-03-09 17:13:07 +0100179// FIXME: More tests? Is bProtocol = Atr[3] ?
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100180 if( length > 5 ) {
Christina Quastb58434e2015-03-09 17:13:07 +0100181 ccidDriver.ProtocolDataStructure[1] = Atr[3]&0x0F; // TD(1)
182 ccidDriver.bProtocol = Atr[3]&0x0F; // TD(1)
183 TRACE_INFO("Protocol data structure: 0x%x, bProtocol: 0x%x\n\r",
184 ccidDriver.ProtocolDataStructure[1], ccidDriver.bProtocol);
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100185 }
186
187 // S_ccid_protocol_t0
188 // bmFindexDindex
189 ccidDriver.ProtocolDataStructure[0] = Atr[2]; // TA(1)
190
191 // bmTCCKST0
192 // For T=0 ,B0 – 0b, B7-2 – 000000b
193 // B1 – Convention used (b1=0 for direct, b1=1 for inverse)
194
195 // bGuardTimeT0
196 // Extra Guardtime between two characters. Add 0 to 254 etu to the normal
197 // guardtime of 12etu. FFh is the same as 00h.
198 ccidDriver.ProtocolDataStructure[2] = Atr[4]; // TC(1)
199 // AT91C_BASE_US0->US_TTGR = 0; // TC1
200
201 // bWaitingIntegerT0
202 // WI for T=0 used to define WWT
203 ccidDriver.ProtocolDataStructure[3] = Atr[7]; // TC(2)
204
205 // bClockStop
206 // ICC Clock Stop Support
207 // 00 = Stopping the Clock is not allowed
208 // 01 = Stop with Clock signal Low
209 // 02 = Stop with Clock signal High
210 // 03 = Stop with Clock either High or Low
211 ccidDriver.ProtocolDataStructure[4] = 0x00; // 0 to 3
212
213 // Header fields settings
214 ccidDriver.sCcidMessage.bMessageType = RDR_TO_PC_DATABLOCK;
215 ccidDriver.sCcidMessage.wLength = length; // Size of ATR
216 ccidDriver.sCcidMessage.bSizeToSend += length; // Size of ATR
217 // bChainParameter: 00 the response APDU begins and ends in this command
218 ccidDriver.sCcidMessage.bSpecific = 0;
219
220 for( i=0; i<length; i++ ) {
221
222 ccidDriver.sCcidMessage.abData[i] = Atr[i];
223 }
224
225 // Set the slot to an active status
226 ccidDriver.sCcidMessage.bStatus = 0;
227 ccidDriver.sCcidMessage.bError = 0;
228}
229
230//------------------------------------------------------------------------------
231/// Response Pipe, Bulk-IN Messages
232/// In other cases, the response message has the following format:
233/// The response data will contain the optional data returned by the ICC,
234/// followed by the 2 byte-size status words SW1-SW2.
235///
236/// Answer to:
237/// PC_to_RDR_XfrBlock
238/// PC_to_RDR_Secure
239//------------------------------------------------------------------------------
240static void RDRtoPCDatablock( void )
241{
242 //TRACE_DEBUG(".");
243
244 // Header fields settings
245 ccidDriver.sCcidMessage.bMessageType = RDR_TO_PC_DATABLOCK;
246 ccidDriver.sCcidMessage.bSizeToSend += ccidDriver.sCcidMessage.wLength;
247 // bChainParameter: 00 the response APDU begins and ends in this command
248 ccidDriver.sCcidMessage.bSpecific = 0;
249
250 // Set the slot to an active status
251 ccidDriver.sCcidMessage.bStatus = 0;
252 ccidDriver.sCcidMessage.bError = 0;
253}
254
255//------------------------------------------------------------------------------
256/// Response Pipe, Bulk-IN Messages
257/// Answer to:
258/// PC_to_RDR_GetParameters
259/// PC_to_RDR_ResetParameters
260/// PC_to_RDR_SetParameters
261//------------------------------------------------------------------------------
262static void RDRtoPCParameters( void )
263{
264 unsigned int i;
265
266 TRACE_DEBUG(".");
267
268 // Header fields settings
269 ccidDriver.sCcidMessage.bMessageType = RDR_TO_PC_PARAMETERS;
270
271 //ccidDriver.sCcidMessage.bStatus = 0;
272 ccidDriver.sCcidMessage.bError = 0;
273
274 if( ccidDriver.ProtocolDataStructure[1] == PROTOCOL_TO ) {
275
276 // T=0
277 ccidDriver.sCcidMessage.wLength = sizeof(S_ccid_protocol_t0);
278 ccidDriver.sCcidMessage.bSpecific = PROTOCOL_TO;
279 }
280 else {
281
282 // T=1
283 ccidDriver.sCcidMessage.wLength = sizeof(S_ccid_protocol_t1);
284 ccidDriver.sCcidMessage.bSpecific = PROTOCOL_T1;
285 }
286
287 ccidDriver.sCcidMessage.bSizeToSend += ccidDriver.sCcidMessage.wLength;
288
289 for( i=0; i<ccidDriver.sCcidMessage.wLength; i++ ) {
290 ccidDriver.sCcidMessage.abData[i] = ccidDriver.ProtocolDataStructure[i];
291 }
292
293}
294
295//------------------------------------------------------------------------------
296/// Response Pipe, Bulk-IN Messages
297/// Answer to:
298/// PC_to_RDR_Escape
299//------------------------------------------------------------------------------
300static void RDRtoPCEscape( unsigned char length, unsigned char *data_send_from_CCID )
301{
302 unsigned int i;
303
304 TRACE_DEBUG(".");
305
306 // Header fields settings
307 ccidDriver.sCcidMessage.bMessageType = RDR_TO_PC_ESCAPE;
308
309 ccidDriver.sCcidMessage.wLength = length;
310
311 ccidDriver.sCcidMessage.bStatus = 0;
312 ccidDriver.sCcidMessage.bError = 0;
313
314 ccidDriver.sCcidMessage.bSpecific = 0; // bRFU
315
316 for( i=0; i<length; i++ ) {
317 ccidDriver.sCcidMessage.abData[i] = data_send_from_CCID[i];
318 }
319}
320
321//------------------------------------------------------------------------------
322/// Response Pipe, Bulk-IN Messages
323/// Answer to:
324/// PC_to_RDR_SetDataRateAndClockFrequency
325//------------------------------------------------------------------------------
326static void RDRtoPCDataRateAndClockFrequency( unsigned int dwClockFrequency,
327 unsigned int dwDataRate )
328{
329 TRACE_DEBUG(".");
330
331 // Header fields settings
332 ccidDriver.sCcidMessage.bMessageType = RDR_TO_PC_DATARATEANDCLOCKFREQUENCY;
333
334 ccidDriver.sCcidMessage.wLength = 8;
335
336 ccidDriver.sCcidMessage.bStatus = 0;
337 ccidDriver.sCcidMessage.bError = 0;
338
339 ccidDriver.sCcidMessage.bSpecific = 0; // bRFU
340
341 ccidDriver.sCcidMessage.abData[0] = dwClockFrequency;
342
343 ccidDriver.sCcidMessage.abData[4] = dwDataRate;
344}
345
346//------------------------------------------------------------------------------
347/// Command Pipe, Bulk-OUT Messages
348/// Power On Command - Cold Reset & Warm Reset
349/// Return the ATR to the host
350//------------------------------------------------------------------------------
351static void PCtoRDRIccPowerOn( void )
352{
353 TRACE_DEBUG(".");
354 if( CCID_FEATURES_AUTO_VOLT == (configurationDescriptorsFS->ccid.dwFeatures & CCID_FEATURES_AUTO_VOLT) ) {
355
356 //bPowerSelect = ccidDriver.sCcidCommand.bSpecific_0;
357 ccidDriver.sCcidCommand.bSpecific_0 = VOLTS_AUTO;
358 }
359
360 ISO7816_warm_reset();
361// ISO7816_cold_reset();
362
363 // for emulation only //JCB
364 if ( ccidDriver.sCcidCommand.bSpecific_0 != VOLTS_5_0 ) {
365
366 TRACE_ERROR("POWER_NOT_SUPPORTED\n\r");
367 }
368
369 else {
370
371 RDRtoPCDatablock_ATR();
372
373 }
374}
375
376//------------------------------------------------------------------------------
377/// Command Pipe, Bulk-OUT Messages
378/// Power Off Command - Set the ICC in an inactive state
379/// Return the slot status to the host
380//------------------------------------------------------------------------------
381static void PCtoRDRIccPowerOff( void )
382{
383 unsigned char bStatus;
384
385 TRACE_DEBUG(".");
386
387 ISO7816_IccPowerOff();
388
389 //JCB stub
390 bStatus = ICC_BS_PRESENT_NOTACTIVATED;
391
392 // Set the slot to an inactive status
393 ccidDriver.sCcidMessage.bStatus = 0;
394 ccidDriver.sCcidMessage.bError = 0;
395
396 // if error, see Table 6.1-2 errors
397
398 // Return the slot status to the host
399 RDRtoPCSlotStatus();
400}
401
402//------------------------------------------------------------------------------
403/// Command Pipe, Bulk-OUT Messages
404/// Get slot status
405//------------------------------------------------------------------------------
406static void PCtoRDRGetSlotStatus( void )
407{
408 TRACE_DEBUG(".");
409
410 ccidDriver.sCcidMessage.bStatus = 0;
411 ccidDriver.sCcidMessage.bError = 0;
412
413 // Return the slot status to the host
414 RDRtoPCSlotStatus();
415}
416
417//------------------------------------------------------------------------------
418/// Command Pipe, Bulk-OUT Messages
419/// If the command header is valid, an APDU command is received and can be read
420/// by the application
421//------------------------------------------------------------------------------
422static void PCtoRDRXfrBlock( void )
423{
Christina Quast73c2b642015-04-07 13:49:26 +0200424 uint16_t msglen = 0;
425 uint32_t ret;
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100426
427 //TRACE_DEBUG(".");
428
429 // Check the block length
430 if ( ccidDriver.sCcidCommand.wLength > (configurationDescriptorsFS->ccid.dwMaxCCIDMessageLength-10) ) {
431
432 ccidDriver.sCcidMessage.bStatus = 1;
433 ccidDriver.sCcidMessage.bError = 0;
434 }
435 // check bBWI
436 else if ( 0 != ccidDriver.sCcidCommand.bSpecific_0 ) {
437
438 TRACE_ERROR("Bad bBWI\n\r");
439 }
440 else {
441
442 // APDU or TPDU
443 switch(configurationDescriptorsFS->ccid.dwFeatures
444 & (CCID_FEATURES_EXC_TPDU|CCID_FEATURES_EXC_SAPDU|CCID_FEATURES_EXC_APDU)) {
445
446 case CCID_FEATURES_EXC_TPDU:
447 if (ccidDriver.ProtocolDataStructure[1] == PROTOCOL_TO) {
Christina Quastb58434e2015-03-09 17:13:07 +0100448 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 +0100449
450 // Send commande APDU
Christina Quast73c2b642015-04-07 13:49:26 +0200451 ret = ISO7816_XfrBlockTPDU_T0( ccidDriver.sCcidCommand.APDU ,
452 ccidDriver.sCcidMessage.abData,
453 ccidDriver.sCcidCommand.wLength,
454 &msglen );
455 if (ret != 0) {
456 TRACE_ERROR("APDU could not be sent: (US_CSR = 0x%x)", ret);
457 return;
458 }
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100459 }
460 else {
461 if (ccidDriver.ProtocolDataStructure[1] == PROTOCOL_T1) {
462 TRACE_INFO("Not supported T=1\n\r");
463 }
464 else {
Christina Quastb58434e2015-03-09 17:13:07 +0100465 TRACE_INFO("Not supported 0x%x\n\r", ccidDriver.ProtocolDataStructure[1]);
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100466 }
467 }
468 break;
469
470 case CCID_FEATURES_EXC_APDU:
Christina Quastb58434e2015-03-09 17:13:07 +0100471 TRACE_INFO("Not supported CCID_FEATURES_EXC_APDU\n\r");
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100472 break;
473
474 default:
475 break;
476 }
477
478 }
479
Christina Quast73c2b642015-04-07 13:49:26 +0200480 ccidDriver.sCcidMessage.wLength = msglen;
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100481 TRACE_DEBUG("USB: 0x%X, 0x%X, 0x%X, 0x%X, 0x%X\n\r", ccidDriver.sCcidMessage.abData[0],
482 ccidDriver.sCcidMessage.abData[1],
483 ccidDriver.sCcidMessage.abData[2],
484 ccidDriver.sCcidMessage.abData[3],
485 ccidDriver.sCcidMessage.abData[4] );
486 RDRtoPCDatablock();
487
488}
489
490//------------------------------------------------------------------------------
491/// Command Pipe, Bulk-OUT Messages
492/// return parameters by the command: RDR_to_PC_Parameters
493//------------------------------------------------------------------------------
494static void PCtoRDRGetParameters( void )
495{
496 TRACE_DEBUG(".");
497
498 // We support only one slot
499
500 // bmIccStatus
501 if( ISO7816_StatusReset() ) {
502 // 0: An ICC is present and active (power is on and stable, RST is inactive
503 ccidDriver.sCcidMessage.bStatus = 0;
504 }
505 else {
506 // 1: An ICC is present and inactive (not activated or shut down by hardware error)
507 ccidDriver.sCcidMessage.bStatus = 1;
508 }
509
510 RDRtoPCParameters();
511}
512
513//------------------------------------------------------------------------------
514/// Command Pipe, Bulk-OUT Messages
515/// This command resets the slot parameters to their default values
516//------------------------------------------------------------------------------
517static void PCtoRDRResetParameters( void )
518{
519 TRACE_DEBUG(".");
520
521 ccidDriver.SlotStatus = ICC_NOT_PRESENT;
522 ccidDriver.sCcidMessage.bStatus = ccidDriver.SlotStatus;
523
524 RDRtoPCParameters();
525}
526
527//------------------------------------------------------------------------------
528/// Command Pipe, Bulk-OUT Messages
529/// This command is used to change the parameters for a given slot.
530//------------------------------------------------------------------------------
531static void PCtoRDRSetParameters( void )
532{
533 TRACE_DEBUG(".");
534
535 ccidDriver.SlotStatus = ccidDriver.sCcidCommand.bSlot;
536 ccidDriver.sCcidMessage.bStatus = ccidDriver.SlotStatus;
537 // Not all feature supported
538
539 RDRtoPCParameters();
540}
541
542//------------------------------------------------------------------------------
543/// Command Pipe, Bulk-OUT Messages
544/// This command allows the CCID manufacturer to define and access extended
545/// features.
546/// Information sent via this command is processed by the CCID control logic.
547//------------------------------------------------------------------------------
548static void PCtoRDREscape( void )
549{
550 TRACE_DEBUG(".");
551
552 // If needed by the user
553 ISO7816_Escape();
554
555 // stub, return all value send
556 RDRtoPCEscape( ccidDriver.sCcidCommand.wLength, ccidDriver.sCcidCommand.APDU);
557}
558
559//------------------------------------------------------------------------------
560/// Command Pipe, Bulk-OUT Messages
561/// This command stops or restarts the clock.
562//------------------------------------------------------------------------------
563static void PCtoRDRICCClock( void )
564{
565 TRACE_DEBUG(".");
566
567 if( 0 == ccidDriver.sCcidCommand.bSpecific_0 ) {
568 // restarts the clock
569 ISO7816_RestartClock();
570 }
571 else {
572 // stop clock in the state shown in the bClockStop field
573 ISO7816_StopClock();
574 }
575
576 RDRtoPCSlotStatus( );
577}
578
579//------------------------------------------------------------------------------
580/// Command Pipe, Bulk-OUT Messages
581/// This command changes the parameters used to perform the transportation of
582/// APDU messages by the T=0 protocol.
583//------------------------------------------------------------------------------
584static void PCtoRDRtoAPDU( void )
585{
586 unsigned char bmChanges;
587 unsigned char bClassGetResponse;
588 unsigned char bClassEnvelope;
589
590 TRACE_DEBUG(".");
591
592 if( configurationDescriptorsFS->ccid.dwFeatures == (CCID_FEATURES_EXC_SAPDU|CCID_FEATURES_EXC_APDU) ) {
593
594 bmChanges = ccidDriver.sCcidCommand.bSpecific_0;
595 bClassGetResponse = ccidDriver.sCcidCommand.bSpecific_1;
596 bClassEnvelope = ccidDriver.sCcidCommand.bSpecific_2;
597
598 ISO7816_toAPDU();
599 }
600
601 RDRtoPCSlotStatus();
602}
603
604//------------------------------------------------------------------------------
605/// Command Pipe, Bulk-OUT Messages
606/// This is a command message to allow entering the PIN for verification or
607/// modification.
608//------------------------------------------------------------------------------
609static void PCtoRDRSecure( void )
610{
611 TRACE_DEBUG(".");
612
613 TRACE_DEBUG("For user\n\r");
614}
615
616//------------------------------------------------------------------------------
617/// Command Pipe, Bulk-OUT Messages
618/// This command is used to manage motorized type CCID functionality.
619/// The Lock Card function is used to hold the ICC.
620/// This prevents an ICC from being easily removed from the CCID.
621/// The Unlock Card function is used to remove the hold initiated by the Lock
622/// Card function
623//------------------------------------------------------------------------------
624static void PCtoRDRMechanical( void )
625{
626 TRACE_DEBUG(".");
627 TRACE_DEBUG("Not implemented\n\r");
628
629 RDRtoPCSlotStatus();
630}
631
632//------------------------------------------------------------------------------
633/// Command Pipe, Bulk-OUT Messages
634/// This command is used with the Control pipe Abort request to tell the CCID
635/// to stop any current transfer at the specified slot and return to a state
636/// where the slot is ready to accept a new command pipe Bulk-OUT message.
637//------------------------------------------------------------------------------
638static void PCtoRDRAbort( void )
639{
640 TRACE_DEBUG(".");
641
642 RDRtoPCSlotStatus();
643}
644
645//------------------------------------------------------------------------------
646/// Command Pipe, Bulk-OUT Messages
647/// This command is used to manually set the data rate and clock frequency of
648/// a specific slot.
649//------------------------------------------------------------------------------
650static void PCtoRDRSetDataRateAndClockFrequency( void )
651{
652 unsigned int dwClockFrequency;
653 unsigned int dwDataRate;
654
655 TRACE_DEBUG(".");
656
657 dwClockFrequency = ccidDriver.sCcidCommand.APDU[0]
658 + (ccidDriver.sCcidCommand.APDU[1]<<8)
659 + (ccidDriver.sCcidCommand.APDU[2]<<16)
660 + (ccidDriver.sCcidCommand.APDU[3]<<24);
661
662 dwDataRate = ccidDriver.sCcidCommand.APDU[4]
663 + (ccidDriver.sCcidCommand.APDU[5]<<8)
664 + (ccidDriver.sCcidCommand.APDU[6]<<16)
665 + (ccidDriver.sCcidCommand.APDU[7]<<24);
666
667 ISO7816_SetDataRateandClockFrequency( dwClockFrequency, dwDataRate );
668
669 RDRtoPCDataRateAndClockFrequency( dwClockFrequency, dwDataRate );
670
671}
672
673//------------------------------------------------------------------------------
674/// Report the CMD_NOT_SUPPORTED error to the host
675//------------------------------------------------------------------------------
676static void vCCIDCommandNotSupported( void )
677{
678 // Command not supported
679 // vCCIDReportError(CMD_NOT_SUPPORTED);
680
681 TRACE_DEBUG("CMD_NOT_SUPPORTED\n\r");
682
683 // Header fields settings
684 ccidDriver.sCcidMessage.bMessageType = RDR_TO_PC_SLOTSTATUS;
685 ccidDriver.sCcidMessage.wLength = 0;
686 ccidDriver.sCcidMessage.bSpecific = 0;
687
688 ccidDriver.sCcidMessage.bStatus |= ICC_CS_FAILED;
689
690 // Send the response to the host
691 //vCCIDSendResponse();
692}
693
694//------------------------------------------------------------------------------
695/// Sent CCID response on USB
696//------------------------------------------------------------------------------
697static void vCCIDSendResponse( void )
698{
699 unsigned char bStatus;
700 TRACE_DEBUG(".");
701
702 do {
703 bStatus = USBD_Write( CCID_EPT_DATA_IN, (void*)&ccidDriver.sCcidMessage,
704 ccidDriver.sCcidMessage.bSizeToSend, 0, 0 );
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100705 } while (bStatus != USBD_STATUS_SUCCESS);
Christina Quast1a224af2015-03-10 15:11:37 +0100706
707 TRACE_DEBUG("bStatus: 0x%x\n\r", bStatus);
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100708}
709
710
711//------------------------------------------------------------------------------
712/// Description: CCID Command dispatcher
713//------------------------------------------------------------------------------
714static void CCIDCommandDispatcher( void )
715{
716 unsigned char MessageToSend = 0;
717
718 TRACE_DEBUG("Command: 0x%X 0x%x 0x%X 0x%X 0x%X 0x%X 0x%X\n\r\n\r",
719 (unsigned int)ccidDriver.sCcidCommand.bMessageType,
720 (unsigned int)ccidDriver.sCcidCommand.wLength,
721 (unsigned int)ccidDriver.sCcidCommand.bSlot,
722 (unsigned int)ccidDriver.sCcidCommand.bSeq,
723 (unsigned int)ccidDriver.sCcidCommand.bSpecific_0,
724 (unsigned int)ccidDriver.sCcidCommand.bSpecific_1,
725 (unsigned int)ccidDriver.sCcidCommand.bSpecific_2);
726
727 // Check the slot number
728 if ( ccidDriver.sCcidCommand.bSlot > 0 ) {
729
730 TRACE_ERROR("BAD_SLOT_NUMBER\n\r");
731 }
732
Christina Quastb58434e2015-03-09 17:13:07 +0100733 TRACE_INFO("typ=0x%X\n\r", ccidDriver.sCcidCommand.bMessageType);
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100734
735 ccidDriver.sCcidMessage.bStatus = 0;
736
737 ccidDriver.sCcidMessage.bSeq = ccidDriver.sCcidCommand.bSeq;
738 ccidDriver.sCcidMessage.bSlot = ccidDriver.sCcidCommand.bSlot;
739
740 ccidDriver.sCcidMessage.bSizeToSend = sizeof(S_ccid_bulk_in_header)-(ABDATA_SIZE+1);
741
742
743 // Command dispatcher
744 switch ( ccidDriver.sCcidCommand.bMessageType ) {
745
746 case PC_TO_RDR_ICCPOWERON:
747 PCtoRDRIccPowerOn();
748 MessageToSend = 1;
749 break;
750
751 case PC_TO_RDR_ICCPOWEROFF:
752 PCtoRDRIccPowerOff();
753 MessageToSend = 1;
754 break;
755
756 case PC_TO_RDR_GETSLOTSTATUS:
757 PCtoRDRGetSlotStatus();
758 MessageToSend = 1;
759 break;
760
761 case PC_TO_RDR_XFRBLOCK:
762 PCtoRDRXfrBlock();
763 MessageToSend = 1;
764 break;
765
766 case PC_TO_RDR_GETPARAMETERS:
767 PCtoRDRGetParameters();
768 MessageToSend = 1;
769 break;
770
771 case PC_TO_RDR_RESETPARAMETERS:
772 PCtoRDRResetParameters();
773 MessageToSend = 1;
774 break;
775
776 case PC_TO_RDR_SETPARAMETERS:
777 PCtoRDRSetParameters();
778 MessageToSend = 1;
779 break;
780
781 case PC_TO_RDR_ESCAPE:
782 PCtoRDREscape();
783 MessageToSend = 1;
784 break;
785
786 case PC_TO_RDR_ICCCLOCK:
787 PCtoRDRICCClock();
788 MessageToSend = 1;
789 break;
790
791 case PC_TO_RDR_T0APDU:
792 // Only CCIDs reporting a short or extended APDU level in the dwFeatures
793 // field of the CCID class descriptor may take this command into account.
794 if( (CCID_FEATURES_EXC_SAPDU == (CCID_FEATURES_EXC_SAPDU&configurationDescriptorsFS->ccid.dwFeatures))
795 || (CCID_FEATURES_EXC_APDU == (CCID_FEATURES_EXC_APDU &configurationDescriptorsFS->ccid.dwFeatures)) ) {
796
797 // command supported
798 PCtoRDRtoAPDU();
799 }
800 else {
801 // command not supported
Christina Quastb58434e2015-03-09 17:13:07 +0100802 TRACE_INFO("Not supported: PC_TO_RDR_T0APDU\n\r");
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100803 vCCIDCommandNotSupported();
804 }
805 MessageToSend = 1;
806 break;
807
808 case PC_TO_RDR_SECURE:
809 PCtoRDRSecure();
810 MessageToSend = 1;
811 break;
812
813 case PC_TO_RDR_MECHANICAL:
814 PCtoRDRMechanical();
815 MessageToSend = 1;
816 break;
817
818 case PC_TO_RDR_ABORT:
819 PCtoRDRAbort();
820 MessageToSend = 1;
821 break;
822
823 case PC_TO_RDR_SETDATARATEANDCLOCKFREQUENCY:
824 PCtoRDRSetDataRateAndClockFrequency();
825 MessageToSend = 1;
826 break;
827
828 default:
Christina Quastb58434e2015-03-09 17:13:07 +0100829 TRACE_DEBUG("default: Not supported: 0x%X\n\r", ccidDriver.sCcidCommand.bMessageType);
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100830 vCCIDCommandNotSupported();
831 MessageToSend = 1;
832 break;
833
834 }
835
836 if( MessageToSend == 1 ) {
837 vCCIDSendResponse();
838 }
839}
840
841
Christina Quast46f5cca2015-04-06 23:29:42 +0200842#if 0
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100843//------------------------------------------------------------------------------
844/// SETUP request handler for a CCID device
845/// \param pRequest Pointer to a USBGenericRequest instance
846//------------------------------------------------------------------------------
847static void CCID_RequestHandler(const USBGenericRequest *pRequest)
848{
849 TRACE_DEBUG("CCID_RHl\n\r");
850
851 // Check if this is a class request
852 if (USBGenericRequest_GetType(pRequest) == USBGenericRequest_CLASS) {
853
854 // Check if the request is supported
855 switch (USBGenericRequest_GetRequest(pRequest)) {
856
857 case CCIDGenericRequest_ABORT:
858 TRACE_DEBUG("CCIDGenericRequest_ABORT\n\r");
859 break;
860
861 case CCIDGenericRequest_GET_CLOCK_FREQUENCIES:
Christina Quastb58434e2015-03-09 17:13:07 +0100862 TRACE_DEBUG("Not supported: CCIDGenericRequest_GET_CLOCK_FREQUENCIES\n\r");
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100863 // A CCID with bNumClockSupported equal to 00h does not have
864 // to support this request
865 break;
866
867 case CCIDGenericRequest_GET_DATA_RATES:
Christina Quastb58434e2015-03-09 17:13:07 +0100868 TRACE_DEBUG("Not supported: CCIDGenericRequest_GET_DATA_RATES\n\r");
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100869 // A CCID with bNumDataRatesSupported equal to 00h does not have
870 // to support this request.
871 break;
872
873 default:
874 TRACE_WARNING( "CCIDDriver_RequestHandler: Unsupported request (%d)\n\r",
875 USBGenericRequest_GetRequest(pRequest));
876 USBD_Stall(0);
877 }
878 }
879
880 else if (USBGenericRequest_GetType(pRequest) == USBGenericRequest_STANDARD) {
881
882 // Forward request to the standard handler
883 USBDDriver_RequestHandler(&(ccidDriver.usbdDriver), pRequest);
884 }
885 else {
886
887 // Unsupported request type
888 TRACE_WARNING( "CCIDDriver_RequestHandler: Unsupported request type (%d)\n\r",
889 USBGenericRequest_GetType(pRequest));
890 USBD_Stall(0);
891 }
892}
893
894
895//------------------------------------------------------------------------------
896// Exported functions
897//------------------------------------------------------------------------------
898
899//------------------------------------------------------------------------------
900/// Optional callback re-implementation
901//------------------------------------------------------------------------------
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100902#if !defined(NOAUTOCALLBACK)
903// not static function
904void USBDCallbacks_RequestReceived(const USBGenericRequest *request)
905{
906 CCID_RequestHandler(request);
907}
908#endif
909#endif
910
911
912//------------------------------------------------------------------------------
913/// Handles SmartCart request
914//------------------------------------------------------------------------------
915void CCID_SmartCardRequest( void )
916{
917 unsigned char bStatus;
918 TRACE_DEBUG(".");
919
920 do {
921
922 bStatus = CCID_Read( (void*)&ccidDriver.sCcidCommand,
923 sizeof(S_ccid_bulk_out_header),
924 (TransferCallback)&CCIDCommandDispatcher,
925 (void*)0 );
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100926 }
927 while (bStatus != USBD_STATUS_SUCCESS);
Christina Quast1a224af2015-03-10 15:11:37 +0100928 TRACE_DEBUG("bStat: %x\n\r", bStatus);
Christina Quastdb7b1ab2015-03-03 12:34:36 +0100929}
930
931
932//------------------------------------------------------------------------------
933/// Reads data from the Data OUT endpoint
934/// \param pBuffer Buffer to store the received data
935/// \param dLength data buffer length
936/// \param fCallback Optional callback function
937/// \param pArgument Optional parameter for the callback function
938/// \return USBD_STATUS_LOCKED or USBD_STATUS_SUCCESS
939//------------------------------------------------------------------------------
940unsigned char CCID_Read(void *pBuffer,
941 unsigned int dLength,
942 TransferCallback fCallback,
943 void *pArgument)
944{
945 return USBD_Read(CCID_EPT_DATA_OUT, pBuffer, dLength, fCallback, pArgument);
946}
947
948//------------------------------------------------------------------------------
949/// Sends data through the Data IN endpoint
950/// \param pBuffer Buffer holding the data to transmit
951/// \param dLength Length of data buffer
952/// \param fCallback Optional callback function
953/// \param pArgument Optional parameter for the callback function
954/// \return USBD_STATUS_LOCKED or USBD_STATUS_SUCCESS
955//------------------------------------------------------------------------------
956unsigned char CCID_Write(void *pBuffer,
957 unsigned int dLength,
958 TransferCallback fCallback,
959 void *pArgument)
960{
961 return USBD_Write(CCID_EPT_DATA_IN, pBuffer, dLength, fCallback, pArgument);
962}
963
964//------------------------------------------------------------------------------
965/// Sends data through the interrupt endpoint, ICC insertion event
966/// RDR_to_PC_NotifySlotChange
967/// \return USBD_STATUS_LOCKED or USBD_STATUS_SUCCESS
968//------------------------------------------------------------------------------
969unsigned char CCID_Insertion( void )
970{
971 TRACE_DEBUG(".");
972
973 // Build the Interrupt-IN message
974 ccidDriver.BufferINT[0] = RDR_TO_PC_NOTIFYSLOTCHANGE;
975 ccidDriver.BufferINT[1] = ICC_INSERTED_EVENT;
976 ccidDriver.SlotStatus = ICC_INSERTED_EVENT;
977
978 // Notify the host that a ICC is inserted
979 return USBD_Write( CCID_EPT_NOTIFICATION, ccidDriver.BufferINT, 2, 0, 0 );
980}
981
982//------------------------------------------------------------------------------
983/// Sends data through the interrupt endpoint, ICC removal event
984/// RDR_to_PC_NotifySlotChange
985/// \return USBD_STATUS_LOCKED or USBD_STATUS_SUCCESS
986//------------------------------------------------------------------------------
987unsigned char CCID_Removal( void )
988{
989 TRACE_DEBUG(".");
990
991 // Build the Interrupt-IN message
992 ccidDriver.BufferINT[0] = RDR_TO_PC_NOTIFYSLOTCHANGE;
993 ccidDriver.BufferINT[1] = ICC_NOT_PRESENT;
994 ccidDriver.SlotStatus = ICC_NOT_PRESENT;
995
996 // Notify the host that a ICC is inserted
997 return USBD_Write( CCID_EPT_NOTIFICATION, ccidDriver.BufferINT, 2, 0, 0 );
998}
999
1000//------------------------------------------------------------------------------
1001/// Interrupt-IN Messages
1002/// This message is sent when any bit in the bHardwareErrorCode field is set.
1003/// If this message is sent when there is no “outstanding” command, the bSeq
1004/// field will be undefined.
1005/// \param bSlot ICC slot number
1006/// \param bSeq Sequence number of the bulk OUT command when the hardware error
1007/// occured
1008/// \param bHardwareErrorCode Hardware error code
1009/// \return USBD_STATUS_LOCKED or USBD_STATUS_SUCCESS
1010//------------------------------------------------------------------------------
1011unsigned char RDRtoPCHardwareError( unsigned char bSlot,
1012 unsigned char bSeq,
1013 unsigned char bHardwareErrorCode )
1014{
1015 TRACE_DEBUG(".");
1016
1017 // Build the Interrupt-IN message
1018 ccidDriver.BufferINT[0] = RDR_TO_PC_HARDWAREERROR;
1019 ccidDriver.BufferINT[1] = bSlot;
1020 ccidDriver.BufferINT[2] = bSeq;
1021 ccidDriver.BufferINT[3] = bHardwareErrorCode;
1022
1023 // Notify the host that a ICC is inserted
1024 return USBD_Write( CCID_EPT_NOTIFICATION, ccidDriver.BufferINT, 4, 0, 0 );
1025}
1026
1027