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