/***************************************************************** / / File : ifdhandler.c / Author : David Corcoran / Date : November 7, 1998 / Purpose: This provides reader specific low-level calls. / Alot of the functionality listed in the specs is / not done. I've done a minimum to get started. / See http://www.linuxnet.com for more information. / License: See file LICENSE / ******************************************************************/ #include "ctapi.h" #include "ctbcs.h" #include "ifdhandler.h" #include "LinuxDefines.h" #include "T1Hndlr.h" #include #define PCSC_DEBUG 1 static DWORD dwCurrentProtocol = 0; struct DEVICE_CAPABILITIES { STR Vendor_Name; /* Tag 0x0100 */ STR IFD_Type; /* Tag 0x0101 */ DWORD IFD_Version; /* Tag 0x0102 */ STR IFD_Serial; /* Tag 0x0103 */ DWORD IFD_Channel_ID; /* Tag 0x0110 */ DWORD Asynch_Supported; /* Tag 0x0120 */ DWORD Default_Clock; /* Tag 0x0121 */ DWORD Max_Clock; /* Tag 0x0122 */ DWORD Default_Data_Rate; /* Tag 0x0123 */ DWORD Max_Data_Rate; /* Tag 0x0124 */ DWORD Max_IFSD; /* Tag 0x0125 */ DWORD Synch_Supported; /* Tag 0x0126 */ DWORD Power_Mgmt; /* Tag 0x0131 */ DWORD Card_Auth_Devices; /* Tag 0x0140 */ DWORD User_Auth_Device; /* Tag 0x0142 */ DWORD Mechanics_Supported; /* Tag 0x0150 */ DWORD Vendor_Features; /* Tag 0x0180 - 0x01F0 User Defined. */ } Device; struct ICC_STATE { BYTE ICC_Presence; /* Tag 0x0300 */ BYTE ICC_Interface_Status; /* Tag 0x0301 */ BYTE ATR[32]; /* Tag 0x0303 */ BYTE ICC_Type; /* Tag 0x0304 */ } ICC; struct PROTOCOL_OPTIONS { DWORD Protocol_Type; /* Tag 0x0201 */ DWORD Current_Clock; /* Tag 0x0202 */ DWORD Current_F; /* Tag 0x0203 */ DWORD Current_D; /* Tag 0x0204 */ DWORD Current_N; /* Tag 0x0205 */ DWORD Current_W; /* Tag 0x0206 */ DWORD Current_IFSC; /* Tag 0x0207 */ DWORD Current_IFSD; /* Tag 0x0208 */ DWORD Current_BWT; /* Tag 0x0209 */ DWORD Current_CWT; /* Tag 0x020A */ DWORD Current_EBC; /* Tag 0x020B */ } Protocol; RESPONSECODE IO_Create_Channel ( DWORD ChannelId ) { RESPONSECODE lRetVal = IFD_SUCCESS; BYTE dad, sad; BYTE Response[MAX_RESPONSE_SIZE]; unsigned short Unibble; /* Upper 16bits of DWORD. (DDDD) */ unsigned short Lnibble; /* Lower 16bits of DWORD. (CCCC) */ BYTE pcPowerUp[] = {0x20, 0x12, 0x00, 0x00, 0x00}; unsigned int iTerm = 1; unsigned int lr; int iPort; int lc; int i; sad = 2; dad = 1; lc = 5; lr = 2; Unibble = ChannelId >> 16; /* Shift right 16 bits. */ Lnibble = ChannelId - ( Unibble << 16 ); /* Shift left and subtract. */ switch ( Unibble ) { case 0x01: /* Serial Port. */ switch ( Lnibble ) { case 0x3F8: iPort = PORT_COM1; break; case 0x2F8: iPort = PORT_COM2; break; case 0x3E8: iPort = PORT_COM3; break; case 0x2E8: iPort = PORT_COM4; break; default: lRetVal = IFD_NOT_SUPPORTED; break; } break; case 0x02: /* Parallel Port. */ lRetVal = IFD_NOT_SUPPORTED; break; case 0x04: /* PS 2 Port. */ lRetVal = IFD_NOT_SUPPORTED; break; case 0x08: /* SCSI Port. */ lRetVal = IFD_NOT_SUPPORTED; break; case 0x10: /* IDE Port. */ lRetVal = IFD_NOT_SUPPORTED; break; case 0x20: /* USB Port. */ lRetVal = IFD_NOT_SUPPORTED; break; /* case 0xFy where y is vendor defined 0 - F is NOT implemented */ default: /* Port Not Found. */ lRetVal = IFD_NOT_SUPPORTED; break; } if ( lRetVal == IFD_SUCCESS ) { if ( CT_init( iTerm, iPort ) == OK ) { if ( CT_data( iTerm, &dad, &sad, lc, pcPowerUp, &lr, Response ) == OK ) { lRetVal = IFD_SUCCESS; } else { lRetVal = IFD_COMMUNICATION_ERROR; } } else { lRetVal = IFD_COMMUNICATION_ERROR; } } return lRetVal; } RESPONSECODE IO_Close_Channel () { RESPONSECODE lRetVal = IFD_SUCCESS; unsigned int iTerm = 0; if ( CT_close( iTerm ) == OK ) { lRetVal = IFD_SUCCESS; } else { lRetVal = IFD_COMMUNICATION_ERROR; } return lRetVal; } RESPONSECODE IFD_Get_Capabilities ( DWORD Tag, BYTE Value[] ) { RESPONSECODE lRetVal; DWORD HighNibble; DWORD LowNibble; int i; HighNibble = Tag >> 8; LowNibble = Tag - ( HighNibble << 8 ); /* Shift left and subtract. */ if ( HighNibble == 0x02 ) { switch( LowNibble ) { case 0x01: lRetVal = IFD_SUCCESS; break; } } else if ( HighNibble == 0x03 ) { /* This is the ICC_STATE */ switch( LowNibble ) { case 0x00: break; case 0x01: if ( IFD_Is_ICC_Present() == IFD_SUCCESS ) { *(DWORD*)Value = IFD_ICC_PRESENT; } else { *(DWORD*)Value = IFD_ICC_NOT_PRESENT; } lRetVal = IFD_SUCCESS; break; case 0x03: memcpy(Value, ICC.ATR, MAX_ATR_SIZE); lRetVal = IFD_SUCCESS; break; case 0x04: break; default: break; } } return lRetVal; } RESPONSECODE IFD_Set_Capabilities ( DWORD Tag, BYTE Value[] ) { RESPONSECODE lRetVal; DWORD HighNibble; DWORD LowNibble; HighNibble = Tag >> 8; LowNibble = Tag - ( HighNibble << 8 ); /* Shift left and subtract. */ if ( HighNibble == 0x03 ) { /* This is the ICC_STATE */ switch( LowNibble ) { case 0x00: break; case 0x01: break; case 0x03: break; case 0x04: break; default: break; } } return lRetVal; } RESPONSECODE IFD_Set_Protocol_Parameters ( DWORD ProtocolType, BYTE SelectionFlags, BYTE PTS1, BYTE PTS2, BYTE PTS3 ) { RESPONSECODE lRetVal; lRetVal = IFD_NOT_SUPPORTED; return lRetVal; } RESPONSECODE IFD_Power_ICC ( DWORD ActionRequested ) { RESPONSECODE lRetVal; RESPONSECODE TestRsp; int i; int lc; unsigned int lr; unsigned int iTerm; BYTE sad; BYTE dad; BYTE Response[MAX_RESPONSE_SIZE]; BYTE pcPowerUp[] = {0x20, 0x12, 0x00, 0x00, 0x00}; BYTE pcPowerDown[] = {0x20, 0x15, 0x00, 0x00, 0x00}; BYTE pcReset[] = {0x20, 0x11, 0x00, 0x01, 0x00}; iTerm = 1; sad = 2; dad = 1; lc = 5; lr = 2; if ( ActionRequested == IFD_POWER_UP ) { /* if ( CT_data( iTerm, &dad, &sad, lc, pcPowerUp, &lr, Response ) == OK ) { */ sad = 2; dad = 1; lr = MAX_ATR_SIZE; TestRsp = CT_data( iTerm, &dad, &sad, lc, pcReset, &lr, Response ); if (TestRsp == OK ) { memcpy( ICC.ATR, Response, lr ); /* Copies the ATR. */ for ( i=lr-2; i < MAX_ATR_SIZE; i++ ) { /* Copies zeros to rest. */ ICC.ATR[i] = 0x00; } lRetVal = IFD_SUCCESS; } else { lRetVal = IFD_ERROR_POWER_ACTION; } /* } else { lRetVal = IFD_ERROR_POWER_ACTION; } */ } else if ( ActionRequested == IFD_POWER_DOWN ) { if ( CT_data( iTerm, &dad, &sad, lc, pcPowerDown, &lr, Response ) == OK ) { lRetVal = IFD_SUCCESS; } else { lRetVal = IFD_ERROR_POWER_ACTION; } } else if ( ActionRequested == IFD_RESET ) { if ( CT_data( iTerm, &dad, &sad, lc, pcReset, &lr, Response ) == OK ) { memcpy( ICC.ATR, Response, lr ); /* Copies the ATR. */ for ( i=lr; i < sizeof(ICC.ATR); i++ ) { /* Copies zeros to rest. */ ICC.ATR[i] = 0x00; } lRetVal = IFD_SUCCESS; } else { lRetVal = IFD_ERROR_POWER_ACTION; } } else { lRetVal = IFD_NOT_SUPPORTED; } return lRetVal; } RESPONSECODE IFD_Swallow_ICC() { RESPONSECODE lRetVal; lRetVal = IFD_ERROR_NOT_SUPPORTED; /* This is not supported. */ return lRetVal; } RESPONSECODE IFD_Eject_ICC() { RESPONSECODE lRetVal; lRetVal = IFD_ERROR_NOT_SUPPORTED; /* This is not supported. */ return lRetVal; } RESPONSECODE IFD_Confiscate_ICC() { RESPONSECODE lRetVal; lRetVal = IFD_ERROR_NOT_SUPPORTED; /* This is not supported. */ return lRetVal; } RESPONSECODE IFD_Transmit_to_ICC ( struct SCARD_IO_HEADER SendPci, BYTE CommandData[], DWORD CommandSize, BYTE ResponseData[], DWORD *ResponseSize, struct SCARD_IO_HEADER *RecvPci ) { RESPONSECODE lRetVal; int i; DWORD lc; DWORD Protocol; unsigned int lr; unsigned int iTerm; BYTE sad; BYTE dad; iTerm = 1; sad = 2; dad = 0; lc = CommandSize; /* Print Transmit Error Messaging */ #ifdef PCSC_DEBUG printf("[%04x] -> ", lc ); for ( i=0; i < lc; i++ ) { printf("%02x ", CommandData[i]); } printf("\n"); #endif if ( lc > 5 ) { lr = 2; } else { lr = CommandData[4] + 2; } if ( SendPci.Protocol == 0 ) { /* Switch modes on the 60 */ if ( dwCurrentProtocol != 0 ) { Adm_SetMode( 0, 0 ); dwCurrentProtocol = 0; } lRetVal = CT_data( iTerm, &dad, &sad, lc, CommandData, &lr, ResponseData ); if ( lRetVal != IFD_SUCCESS ) { *ResponseSize = 0; return IFD_COMMUNICATION_ERROR; } else { *ResponseSize = lr; lRetVal = IFD_SUCCESS; } } else if ( SendPci.Protocol == 1 ) { /* Switch modes on the 60 */ if ( dwCurrentProtocol != 1 ) { Adm_SetMode( 1, 0 ); dwCurrentProtocol = 1; } lRetVal = T1_ExchangeData( CommandData, lc, ResponseData, ResponseSize ); if ( lRetVal != STATUS_SUCCESS ) { *ResponseSize = 0; return IFD_COMMUNICATION_ERROR; } else { lRetVal = IFD_SUCCESS; } } else { *ResponseSize = 0; return IFD_ERROR_NOT_SUPPORTED; } /* Print Receive Error Messaging */ #ifdef PCSC_DEBUG printf("[%04x] <- ", *ResponseSize ); for ( i=0; i < lr; i++ ) { printf("%02x ", ResponseData[i]); } printf("\n"); #endif return lRetVal; } RESPONSECODE IFD_Is_ICC_Present() { RESPONSECODE lRetVal; RESPONSECODE TestRsp; int lc; unsigned int lr; unsigned int iTerm; int i; BYTE sad; BYTE dad; BYTE Response[MAX_RESPONSE_SIZE]; BYTE pcStatus[5] = {0x20, 0x13, 0x00, 0x00, 0x00}; iTerm = 0; i=0; sad = 2; dad = 1; lc = 5; lr = 7; TestRsp = CT_data( iTerm, &dad, &sad, lc, pcStatus, &lr, Response ); if ( TestRsp == OK ) { if ( Response[0] & CTBCS_DATA_STATUS_CARD ) { /* Card Inserted */ return IFD_ICC_PRESENT; } else { return IFD_ICC_NOT_PRESENT; } } return IFD_COMMUNICATION_ERROR; } RESPONSECODE IFD_Is_ICC_Absent() { RESPONSECODE lRetVal; int lc; unsigned int lr; unsigned int iTerm; BYTE sad; BYTE dad; BYTE Response[MAX_RESPONSE_SIZE]; BYTE pcStatus[5] = {0x20, 0x13, 0x00, 0x00, 0x00}; iTerm = 0; sad = 2; dad = 1; lc = 5; lr = 7; if ( CT_data( iTerm, &dad, &sad, lc, pcStatus, &lr, Response ) == OK ) { if ( ! Response[0] & CTBCS_DATA_STATUS_CARD ) { /* Card Removed */ return IFD_ICC_NOT_PRESENT; } else { return IFD_ICC_PRESENT; } } return IFD_COMMUNICATION_ERROR; }