You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2257 lines
61 KiB
2257 lines
61 KiB
/*++
|
|
Copyright (c) 1998 Gemplus Development
|
|
|
|
Name:
|
|
gprcmd.c
|
|
|
|
Description:
|
|
This is the module which holds the calls to the readers
|
|
functions.
|
|
|
|
Environment:
|
|
Kernel Mode
|
|
|
|
Revision History:
|
|
06/04/99: (Y. Nadeau + M. Veillette)
|
|
- Code Review
|
|
12/03/99: V1.00.005 (Y. Nadeau)
|
|
- Fix Set protocol to give reader the time to process the change
|
|
18/09/98: V1.00.004 (Y. Nadeau)
|
|
- Correction for NT5 beta 3
|
|
06/05/98: V1.00.003 (P. Plouidy)
|
|
- Power management for NT5
|
|
10/02/98: V1.00.002 (P. Plouidy)
|
|
- Plug and Play for NT5
|
|
03/07/97: V1.00.001 (P. Plouidy)
|
|
- Start of development.
|
|
|
|
|
|
--*/
|
|
//
|
|
// Include section:
|
|
// - stdio.h: standards definitons.
|
|
// - ntddk.h: DDK Windows NT general definitons.
|
|
// - ntdef.h: Windows NT general definitons.
|
|
//
|
|
#include <stdio.h>
|
|
#include <ntddk.h>
|
|
#include <ntdef.h>
|
|
|
|
//
|
|
// - gprcmd.h: common definition for this module.
|
|
// - gprnt.h: public interface definition for the NT module.
|
|
// - gprelcmd.h : elementary commands profile
|
|
// - gemerror.h : Gemplus error codes
|
|
|
|
#include "gprnt.h"
|
|
#include "gprcmd.h"
|
|
#include "gprelcmd.h"
|
|
|
|
|
|
|
|
//
|
|
// Master driver code to load in RAM
|
|
//
|
|
UCHAR MASTER_DRIVER[133]={
|
|
0xC2,0xB5,0x12,0x14,0xC6,0xFC,0x78,0x00,0x7B,0x00,0x90,0x07,0xDF,0xE0,0xD2,0xE4,
|
|
0xF0,0xEB,0xF8,0x12,0x14,0xD0,0x12,0x0D,0x9B,0x40,0x5C,0x0B,0xDC,0xF3,0xD2,0xB4,
|
|
0x90,0x07,0xDF,0xE0,0xC2,0xE4,0xF0,0x90,0x06,0xD4,0xE4,0xF5,0x15,0xF5,0x11,0xC2,
|
|
0x4D,0xA3,0x05,0x11,0x75,0x34,0x0A,0x75,0x37,0x00,0x75,0x38,0x40,0x12,0x0B,0x75,
|
|
0x20,0x20,0x3B,0xF0,0xA3,0x05,0x11,0x7B,0x01,0x12,0x0B,0x75,0x20,0x20,0x2F,0xF0,
|
|
0xA3,0x05,0x11,0x7C,0x03,0x33,0x33,0x50,0x01,0x0B,0xDC,0xFA,0x12,0x0B,0x75,0x20,
|
|
0x20,0x1C,0xF0,0xA3,0x05,0x11,0xDB,0xF4,0xE4,0x90,0x06,0xD4,0xF0,0x75,0x16,0x00,
|
|
0x75,0x15,0x00,0x12,0x14,0x15,0x22,0x74,0x0C,0x75,0x11,0x01,0x80,0xEB,0x74,0x0D,
|
|
0x75,0x11,0x01,0x80,0xE4
|
|
};
|
|
|
|
|
|
// Hard coded structure for different values of TA1.
|
|
// eg. If TA= 0x92 is to set, this array of structure can be scanned and
|
|
// for member variable TA1 = 0x92 and that values can be written to
|
|
// approptiate location.
|
|
// This is done in ConfigureTA1() function.
|
|
struct tagCfgTa1
|
|
{
|
|
BYTE TA1;
|
|
BYTE ETU1;
|
|
BYTE ETU2;
|
|
BYTE ETU1P;
|
|
} cfg_ta1[] = {
|
|
|
|
// { 0x15, 0x01, 0x01, 0x01 },
|
|
// { 0x95, 0x01, 0x01, 0x01 },
|
|
|
|
// { 0x25, 0x03, 0x02, 0x01 },
|
|
|
|
// { 0x14, 0x05, 0x03, 0x01 },
|
|
// { 0x35, 0x05, 0x03, 0x01 },
|
|
|
|
// { 0xa5, 0x04, 0x02, 0x01 },
|
|
|
|
// { 0x94, 0x07, 0x04, 0x02 },
|
|
// { 0xb5, 0x07, 0x04, 0x02 },
|
|
|
|
// { 0x24, 0x09, 0x04, 0x04 },
|
|
// { 0x45, 0x09, 0x04, 0x04 },
|
|
|
|
{ 0x13, 0x0d, 0x06, 0x09 },
|
|
{ 0x34, 0x0d, 0x06, 0x09 },
|
|
{ 0x55, 0x0d, 0x06, 0x09 },
|
|
|
|
{ 0xa4, 0x0c, 0x06, 0x08 },
|
|
{ 0xc5, 0x0c, 0x06, 0x08 },
|
|
|
|
{ 0x65, 0x10, 0x08, 0x0c },
|
|
|
|
{ 0x93, 0x11, 0x09, 0x0d },
|
|
{ 0xb4, 0x11, 0x09, 0x0d },
|
|
{ 0xd5, 0x11, 0x09, 0x0d },
|
|
|
|
{ 0x23, 0x14, 0x0a, 0x10 },
|
|
{ 0x44, 0x14, 0x0a, 0x10 },
|
|
|
|
|
|
{ 0x12, 0x1c, 0x0e, 0x15 },
|
|
{ 0x33, 0x1c, 0x0e, 0x15 },
|
|
{ 0x54, 0x1c, 0x0e, 0x15 },
|
|
|
|
{ 0xa3, 0x1c, 0x0f, 0x15 },
|
|
{ 0xc4, 0x1c, 0x0f, 0x15 },
|
|
|
|
{ 0x64, 0x24, 0x12, 0x20 },
|
|
|
|
{ 0x92, 0x26, 0x14, 0x22 },
|
|
{ 0xb3, 0x26, 0x14, 0x22 },
|
|
{ 0xd4, 0x26, 0x14, 0x22 },
|
|
|
|
|
|
{ 0x22, 0x2b, 0x16, 0x27 },
|
|
{ 0x43, 0x2b, 0x16, 0x27 },
|
|
|
|
|
|
{ 0x11, 0x3b, 0x1e, 0x37 },
|
|
{ 0x32, 0x3b, 0x1e, 0x37 },
|
|
{ 0x53, 0x3b, 0x1e, 0x37 },
|
|
|
|
// { 0x71, 0x55, 0x2b, 0x51 },
|
|
// { 0x91, 0x55, 0x2b, 0x51 },
|
|
|
|
{ 0, 0, 0, 0 }
|
|
|
|
};
|
|
|
|
|
|
|
|
USHORT ATRLen (UCHAR *ATR, USHORT MaxChar)
|
|
/*++
|
|
|
|
Routine Description :
|
|
Used to calculate the ATR length according to its content.
|
|
Arguments
|
|
ATR - string to analyze
|
|
MaxChar - Maximum number of characters to verify.
|
|
--*/
|
|
{
|
|
USHORT Len;
|
|
UCHAR T0;
|
|
UCHAR Yi;
|
|
BOOLEAN EndInterChar;
|
|
BOOLEAN TCKPresent=FALSE;
|
|
|
|
T0 = ATR[1];
|
|
Len= 2; // TS + T0
|
|
|
|
Yi= (T0 & 0xF0);
|
|
|
|
EndInterChar = FALSE;
|
|
do
|
|
{
|
|
if (Yi & 0x10)
|
|
{
|
|
Len++; //TAi
|
|
}
|
|
if (Yi & 0x20)
|
|
{
|
|
Len++; //TBi
|
|
}
|
|
if (Yi & 0x40)
|
|
{
|
|
Len++; //TCi
|
|
}
|
|
if (Yi & 0x80)
|
|
{
|
|
if (Len < MaxChar) {
|
|
Yi = ATR[Len];
|
|
if((Yi & 0x0F)!=0)
|
|
{
|
|
TCKPresent=TRUE;
|
|
|
|
}
|
|
}
|
|
|
|
Len++; //TDi
|
|
}
|
|
else
|
|
{
|
|
EndInterChar = TRUE;
|
|
}
|
|
} while((Len < MaxChar) && (EndInterChar == FALSE));
|
|
|
|
Len = Len + (T0 & 0x0F);
|
|
|
|
if(TCKPresent==TRUE)
|
|
{
|
|
Len = Len+1; //TCK
|
|
}
|
|
|
|
return (Len);
|
|
}
|
|
|
|
|
|
|
|
BOOLEAN NeedToSwitchWithoutPTS(
|
|
BYTE *ATR,
|
|
DWORD LengthATR
|
|
)
|
|
/*++
|
|
|
|
Routine Description :
|
|
Examine if ATR identifies a specific mode (presence of TA2).
|
|
Arguments
|
|
ATR - string to analyze
|
|
LengthATR - Length of ATR.
|
|
--*/
|
|
|
|
{
|
|
DWORD pos, len;
|
|
|
|
// ATR[1] is T0. Examine precense of TD1.
|
|
if (ATR[1] & 0x80)
|
|
{
|
|
// Find position of TD1.
|
|
pos = 2;
|
|
if (ATR[1] & 0x10)
|
|
pos++;
|
|
if (ATR[1] & 0x20)
|
|
pos++;
|
|
if (ATR[1] & 0x40)
|
|
pos++;
|
|
|
|
// Here ATR[pos] is TD1. Examine presence of TA2.
|
|
if (ATR[pos] & 0x10)
|
|
{
|
|
// To be of any interest an ATR must contains at least
|
|
// TS, T0, TA1, TD1, TA2 [+ T1 .. TK] [+ TCK]
|
|
// Find the maximum length of uninteresting ATR.
|
|
if (ATR[pos] & 0x0F)
|
|
len = 5 + (ATR[1] & 0x0F);
|
|
else
|
|
len = 4 + (ATR[1] & 0x0F); // In protocol T=0 there is no TCK.
|
|
|
|
if (LengthATR > len) // Interface bytes requires changes.
|
|
if ((ATR[pos+1] & 0x10) == 0) // TA2 asks to use interface bytes.
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS ValidateDriver( PSMARTCARD_EXTENSION pSmartcardExtension)
|
|
/*++
|
|
|
|
Routine Description :
|
|
Validate the Master driver loaded in RAM at address 2100h
|
|
Arguments
|
|
pSmartcardExtension: Pointer to the SmartcardExtension structure.
|
|
--*/
|
|
{
|
|
READER_EXTENSION *pReaderExt = pSmartcardExtension->ReaderExtension;
|
|
NTSTATUS lStatus = STATUS_SUCCESS;
|
|
UCHAR Vi[GPR_BUFFER_SIZE];
|
|
UCHAR To;
|
|
USHORT Lo;
|
|
UCHAR Vo[GPR_BUFFER_SIZE];
|
|
|
|
|
|
Vi[0] = 0x83; // DIR
|
|
Vi[1] = 0x21; // ADR MSB
|
|
Vi[2] = 0x00; // ADR LSB
|
|
// Output variable initialisation
|
|
Lo = GPR_BUFFER_SIZE;
|
|
To = 0x00;
|
|
Vo[0] = 0x00;
|
|
|
|
// return a NTSTATUS
|
|
lStatus = GprllTLVExchange (
|
|
pReaderExt,
|
|
VALIDATE_DRIVER_CMD,
|
|
3,
|
|
Vi,
|
|
&To,
|
|
&Lo,
|
|
Vo
|
|
);
|
|
|
|
return (lStatus);
|
|
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS Update(
|
|
PSMARTCARD_EXTENSION pSmartcardExtension,
|
|
UCHAR Addr,
|
|
UCHAR Value)
|
|
/*++
|
|
|
|
Routine Description :
|
|
Write a value in RAM
|
|
Arguments
|
|
pSmartcardExtension: Pointer to the SmartcardExtension structure.
|
|
Addr: Address in RAM
|
|
Value: Value to write
|
|
--*/
|
|
{
|
|
READER_EXTENSION *pReaderExt = pSmartcardExtension->ReaderExtension;
|
|
NTSTATUS lStatus = STATUS_SUCCESS;
|
|
UCHAR Vi[GPR_BUFFER_SIZE];
|
|
UCHAR To;
|
|
USHORT Lo;
|
|
UCHAR Vo[GPR_BUFFER_SIZE];
|
|
|
|
Vi[0]= 0x01;
|
|
Vi[1]= Addr;
|
|
Vi[2]= Value;
|
|
|
|
// Output variable initialisation
|
|
Lo = GPR_BUFFER_SIZE;
|
|
To = 0x00;
|
|
Vo[0] = 0x00;
|
|
|
|
lStatus = GprllTLVExchange(
|
|
pReaderExt,
|
|
UPDATE_CMD,
|
|
0x03,
|
|
Vi,
|
|
&To,
|
|
&Lo,
|
|
Vo
|
|
);
|
|
|
|
return (lStatus);
|
|
|
|
}
|
|
|
|
NTSTATUS UpdateORL(
|
|
PSMARTCARD_EXTENSION pSmartcardExtension,
|
|
UCHAR Addr,
|
|
UCHAR Value)
|
|
/*++
|
|
|
|
Routine Description :
|
|
Write a value in RAM with OR mask
|
|
Arguments
|
|
pSmartcardExtension: Pointer to the SmartcardExtension structure.
|
|
--*/
|
|
{
|
|
READER_EXTENSION *pReaderExt = pSmartcardExtension->ReaderExtension;
|
|
NTSTATUS lStatus = STATUS_SUCCESS;
|
|
UCHAR Vi[GPR_BUFFER_SIZE];
|
|
UCHAR To;
|
|
USHORT Lo;
|
|
UCHAR Vo[GPR_BUFFER_SIZE];
|
|
|
|
|
|
Vi[0]= 0x02;
|
|
Vi[1]= Addr;
|
|
// Output variable initialisation
|
|
Lo = GPR_BUFFER_SIZE;
|
|
To = 0x00;
|
|
Vo[0] = 0x00;
|
|
|
|
lStatus = GprllTLVExchange(
|
|
pReaderExt,
|
|
UPDATE_CMD,
|
|
0x02,
|
|
Vi,
|
|
&To,
|
|
&Lo,
|
|
Vo
|
|
);
|
|
|
|
if (STATUS_SUCCESS != lStatus)
|
|
{
|
|
return (lStatus);
|
|
}
|
|
|
|
|
|
Vi[0]= 0x01;
|
|
Vi[1]= Addr;
|
|
Vi[2] = Vo[1] | Value;
|
|
|
|
// Output variable initialisation
|
|
Lo = GPR_BUFFER_SIZE;
|
|
To = 0x00;
|
|
Vo[0] = 0x00;
|
|
|
|
lStatus = GprllTLVExchange(
|
|
pReaderExt,
|
|
UPDATE_CMD,
|
|
0x03,
|
|
Vi,
|
|
&To,
|
|
&Lo,
|
|
Vo
|
|
);
|
|
|
|
return (lStatus);
|
|
}
|
|
|
|
|
|
NTSTATUS T0toT1( PSMARTCARD_EXTENSION pSmartcardExtension)
|
|
/*++
|
|
|
|
Routine Description :
|
|
OS patch to put the reader in T1 mode
|
|
Arguments
|
|
pSmartcardExtension: Pointer to the SmartcardExtension structure.
|
|
--*/
|
|
{
|
|
NTSTATUS lStatus = STATUS_SUCCESS;
|
|
|
|
// Verify each update to be done
|
|
lStatus = Update(pSmartcardExtension,0x09,0x03);
|
|
if (lStatus != STATUS_SUCCESS)
|
|
{
|
|
return (lStatus);
|
|
}
|
|
|
|
lStatus = Update(pSmartcardExtension,0x20,0x03);
|
|
if (lStatus != STATUS_SUCCESS)
|
|
{
|
|
return (lStatus);
|
|
}
|
|
|
|
lStatus = Update(pSmartcardExtension,0x48,0x00);
|
|
if (lStatus != STATUS_SUCCESS)
|
|
{
|
|
return (lStatus);
|
|
}
|
|
|
|
lStatus = Update(pSmartcardExtension,0x49,0x0F);
|
|
if (lStatus != STATUS_SUCCESS)
|
|
{
|
|
return (lStatus);
|
|
}
|
|
|
|
lStatus = Update(pSmartcardExtension,0x4A,0x20);
|
|
if (lStatus != STATUS_SUCCESS)
|
|
{
|
|
return (lStatus);
|
|
}
|
|
|
|
lStatus = Update(pSmartcardExtension,0x4B,0x0B);
|
|
if (lStatus != STATUS_SUCCESS)
|
|
{
|
|
return (lStatus);
|
|
}
|
|
|
|
lStatus = Update(pSmartcardExtension,0x4C,0x40);
|
|
if (lStatus != STATUS_SUCCESS)
|
|
{
|
|
return (lStatus);
|
|
}
|
|
|
|
lStatus = UpdateORL(pSmartcardExtension,0x2A,0x02);
|
|
if (lStatus != STATUS_SUCCESS)
|
|
{
|
|
return (lStatus);
|
|
}
|
|
|
|
// Give the reader the time to process the change
|
|
GprllWait(100);
|
|
|
|
return (STATUS_SUCCESS);
|
|
}
|
|
|
|
NTSTATUS T1toT0( PSMARTCARD_EXTENSION pSmartcardExtension)
|
|
/*++
|
|
|
|
Routine Description :
|
|
OS patch to put the reader in T0 mode
|
|
Arguments
|
|
pSmartcardExtension: Pointer to the SmartcardExtension structure.
|
|
--*/
|
|
{
|
|
READER_EXTENSION *pReaderExt = pSmartcardExtension->ReaderExtension;
|
|
NTSTATUS lStatus = STATUS_SUCCESS;
|
|
|
|
lStatus = Update(pSmartcardExtension,0x09,0x02);
|
|
if (lStatus != STATUS_SUCCESS)
|
|
{
|
|
return (lStatus);
|
|
}
|
|
|
|
lStatus = Update(pSmartcardExtension,0x20,0x02);
|
|
if (lStatus != STATUS_SUCCESS)
|
|
{
|
|
return (lStatus);
|
|
}
|
|
|
|
|
|
// Give the reader the time to process the change
|
|
GprllWait(100);
|
|
|
|
return (STATUS_SUCCESS);
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS IccColdReset(
|
|
PSMARTCARD_EXTENSION pSmartcardExtension
|
|
)
|
|
/*++
|
|
|
|
Routine Description :
|
|
Cold reset function.
|
|
The delay between the power down & the power up is strored
|
|
in the PowerTimeout field of the READER_EXTENSION structure.
|
|
The default value is 0.
|
|
|
|
Arguments
|
|
|
|
pSmartcardExtension: Pointer to the SmartcardExtension structure.
|
|
--*/
|
|
{
|
|
//
|
|
// Local variables:
|
|
// - pReaderExt holds the pointer to the current ReaderExtension structure
|
|
// - lStatus holds the status to return.
|
|
// - Vi Holds the input buffer of the TLV commnand.
|
|
// - To holds the Tag of the returned TLV.
|
|
// - Lo holds the Length of the buffer of the returned TLV.
|
|
// - Vo holds the Buffer of the returned TLV.
|
|
// - RespLen holds the Length of the buffer of the TLV returned by the power up command.
|
|
// - Rbuff holds the buffer of the TLV returned by the power up command.
|
|
//
|
|
READER_EXTENSION *pReaderExt = pSmartcardExtension->ReaderExtension;
|
|
NTSTATUS lStatus = STATUS_SUCCESS;
|
|
UCHAR Vi[GPR_BUFFER_SIZE];
|
|
UCHAR To;
|
|
USHORT Lo;
|
|
UCHAR Vo[GPR_BUFFER_SIZE];
|
|
USHORT RespLen;
|
|
UCHAR RespBuff[GPR_BUFFER_SIZE];
|
|
UCHAR BWTimeAdjust;
|
|
USHORT MaxChar;
|
|
|
|
|
|
// Send power on command (GprllTLVExchange: T= 20h, L = 0)
|
|
// <= response
|
|
// Output variable initialisation
|
|
RespLen = GPR_BUFFER_SIZE;
|
|
|
|
To = 0x00;
|
|
RespBuff[0] = 0x00;
|
|
|
|
lStatus = GprllTLVExchange(
|
|
pReaderExt,
|
|
OPEN_SESSION_CMD,
|
|
0x00,
|
|
Vi,
|
|
&To,
|
|
&RespLen,
|
|
RespBuff
|
|
);
|
|
if (lStatus != STATUS_SUCCESS)
|
|
{
|
|
return (lStatus);
|
|
}
|
|
|
|
// Correct the WTX pb
|
|
// Get the value set by the reader
|
|
Vi [0]=0x02;
|
|
Vi [1]=0x4A;
|
|
|
|
// Output variable initialisation
|
|
Lo = GPR_BUFFER_SIZE;
|
|
To = 0x00;
|
|
Vo[0] = 0x00;
|
|
|
|
lStatus = GprllTLVExchange(
|
|
pReaderExt,
|
|
UPDATE_CMD,
|
|
0x02,
|
|
Vi,
|
|
&To,
|
|
&Lo,
|
|
Vo
|
|
);
|
|
if (lStatus != STATUS_SUCCESS)
|
|
{
|
|
return (lStatus);
|
|
}
|
|
|
|
|
|
// adjust the value of the BWT
|
|
if(Vo[1] >= 0x80)
|
|
{
|
|
BWTimeAdjust = 0xff;
|
|
}
|
|
else
|
|
{
|
|
BWTimeAdjust = Vo[1] * 2;
|
|
}
|
|
|
|
lStatus = Update(pSmartcardExtension,0x4A,BWTimeAdjust);
|
|
|
|
|
|
if (lStatus == STATUS_SUCCESS)
|
|
{
|
|
|
|
// Get the ATR length from this function
|
|
MaxChar = RespLen - 1;
|
|
RespLen = ATRLen(RespBuff+1, MaxChar) + 1;
|
|
|
|
//
|
|
// Copy ATR to smart card struct (remove the reader status byte)
|
|
// The lib needs the ATR for evaluation of the card parameters
|
|
//
|
|
// Verification if Response buffer is larger than ATR buffer.
|
|
//
|
|
if (
|
|
(pSmartcardExtension->SmartcardReply.BufferSize >= (ULONG) (RespLen - 1)) &&
|
|
(sizeof(pSmartcardExtension->CardCapabilities.ATR.Buffer) >= (ULONG)(RespLen - 1))
|
|
)
|
|
{
|
|
|
|
RtlCopyMemory(
|
|
pSmartcardExtension->SmartcardReply.Buffer,
|
|
RespBuff + 1,
|
|
RespLen - 1
|
|
);
|
|
|
|
pSmartcardExtension->SmartcardReply.BufferLength = (ULONG) (RespLen - 1);
|
|
|
|
RtlCopyMemory(
|
|
pSmartcardExtension->CardCapabilities.ATR.Buffer,
|
|
pSmartcardExtension->SmartcardReply.Buffer,
|
|
pSmartcardExtension->SmartcardReply.BufferLength
|
|
);
|
|
|
|
pSmartcardExtension->CardCapabilities.ATR.Length =
|
|
(UCHAR) pSmartcardExtension->SmartcardReply.BufferLength ;
|
|
|
|
|
|
pSmartcardExtension->CardCapabilities.Protocol.Selected =
|
|
SCARD_PROTOCOL_UNDEFINED;
|
|
|
|
// Parse the ATR string in order to check if it as valid
|
|
// and to find out if the card uses invers convention
|
|
lStatus = SmartcardUpdateCardCapabilities(pSmartcardExtension);
|
|
|
|
if (lStatus == STATUS_SUCCESS)
|
|
{
|
|
RtlCopyMemory(
|
|
pSmartcardExtension->IoRequest.ReplyBuffer,
|
|
pSmartcardExtension->CardCapabilities.ATR.Buffer,
|
|
pSmartcardExtension->CardCapabilities.ATR.Length
|
|
);
|
|
|
|
*pSmartcardExtension->IoRequest.Information =
|
|
pSmartcardExtension->SmartcardReply.BufferLength;
|
|
|
|
//
|
|
// Implicite protocol and parameters selection?
|
|
// Verify if TA2 require to switch in TA1
|
|
//
|
|
if ( NeedToSwitchWithoutPTS(
|
|
pSmartcardExtension->CardCapabilities.ATR.Buffer,
|
|
pSmartcardExtension->CardCapabilities.ATR.Length) == FALSE)
|
|
{
|
|
// send reader parameters
|
|
IfdConfig(pSmartcardExtension, 0x11);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
lStatus = STATUS_BUFFER_TOO_SMALL;
|
|
}
|
|
|
|
}
|
|
return (lStatus);
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS IccPowerDown(
|
|
PSMARTCARD_EXTENSION pSmartcardExtension
|
|
)
|
|
/*++
|
|
|
|
Routine Description : ICC power down function
|
|
|
|
Arguments
|
|
pSmartcardExtension: Pointer to the SmartcardExtension structure.
|
|
--*/
|
|
{
|
|
// Local variables:
|
|
// - pReaderExt holds the pointer to the current ReaderExtension structure
|
|
// - lStatus holds the status to return.
|
|
// - Vi Holds the input buffer of the TLV commnand.
|
|
// - To holds the Tag of the returned TLV.
|
|
// - Lo holds the Length of the buffer of the returned TLV.
|
|
// - Vo holds the Buffer of the returned TLV.
|
|
READER_EXTENSION *pReaderExt = pSmartcardExtension->ReaderExtension;
|
|
NTSTATUS lStatus = STATUS_SUCCESS;
|
|
UCHAR Vi[GPR_BUFFER_SIZE];
|
|
UCHAR To;
|
|
USHORT Lo;
|
|
UCHAR Vo[GPR_BUFFER_SIZE];
|
|
KIRQL irql;
|
|
|
|
// Power down
|
|
|
|
// Output variable initialisation
|
|
Lo = GPR_BUFFER_SIZE;
|
|
To = 0x00;
|
|
Vo[0] = 0x00;
|
|
|
|
lStatus = GprllTLVExchange(
|
|
pReaderExt,
|
|
CLOSE_SESSION_CMD,
|
|
0x00,
|
|
Vi,
|
|
&To,
|
|
&Lo,
|
|
Vo
|
|
);
|
|
|
|
if (lStatus == STATUS_SUCCESS)
|
|
{
|
|
KeAcquireSpinLock(&pSmartcardExtension->OsData->SpinLock,
|
|
&irql);
|
|
|
|
pSmartcardExtension->ReaderCapabilities.CurrentState = SCARD_SWALLOWED;
|
|
KeReleaseSpinLock(&pSmartcardExtension->OsData->SpinLock,
|
|
irql);
|
|
|
|
}
|
|
|
|
return (lStatus);
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS IccIsoOutput(
|
|
PSMARTCARD_EXTENSION pSmartcardExtension,
|
|
const UCHAR pCommand[5],
|
|
USHORT *pRespLen,
|
|
UCHAR pRespBuff[]
|
|
)
|
|
/*++
|
|
|
|
Routine Description : This function sends an ISO OUT command to the card
|
|
|
|
Arguments
|
|
pSmartcardExtension: Pointer to the SmartcardExtension structure.
|
|
pCommand : Iso out command to send.
|
|
pRespLen : in - maximum buffer size available
|
|
out - returned buffer length.
|
|
pRespBuff: returned buffer
|
|
--*/
|
|
{
|
|
// Local variables:
|
|
// - pReaderExt holds the pointer to the current ReaderExtension structure
|
|
// - lStatus holds the status to return.
|
|
// - Vi Holds the input buffer of the TLV commnand.
|
|
// - To holds the Tag of the returned TLV.
|
|
// - Lo holds the Length of the buffer of the returned TLV.
|
|
// - Vo holds the Buffer of the returned TLV.
|
|
READER_EXTENSION *pReaderExt = pSmartcardExtension->ReaderExtension;
|
|
NTSTATUS lStatus = STATUS_SUCCESS;
|
|
UCHAR Vi[GPR_BUFFER_SIZE]= { 0x01 };
|
|
UCHAR To;
|
|
USHORT Lo;
|
|
UCHAR Vo[GPR_BUFFER_SIZE];
|
|
|
|
// The five command bytes are added in cmd buffer.
|
|
RtlCopyMemory(Vi + 1, pCommand, 5);
|
|
|
|
// The command is send to IFD.
|
|
// Fields RespLen and RespBuff are updates
|
|
// <= sResponse
|
|
Lo = *pRespLen;
|
|
To = 0x00;
|
|
Vo[0] = 0x00;
|
|
|
|
lStatus = GprllTLVExchange(
|
|
pReaderExt,
|
|
APDU_EXCHANGE_CMD,
|
|
6,
|
|
Vi,
|
|
&To,
|
|
&Lo,
|
|
Vo
|
|
);
|
|
|
|
if (lStatus != STATUS_SUCCESS)
|
|
{
|
|
*pRespLen = 0;
|
|
}
|
|
else
|
|
{
|
|
|
|
// To correct the bug of GPR400 version 1.0
|
|
// If the response is 0xE7 then correct the response
|
|
if (
|
|
(Lo != 1) &&
|
|
(pReaderExt->OsVersion<= 0x10 )&&
|
|
(Vo[0]==0xE7)
|
|
)
|
|
{
|
|
Lo = 0x03;
|
|
}
|
|
|
|
RtlCopyMemory(pRespBuff, Vo, Lo);
|
|
*pRespLen = Lo;
|
|
}
|
|
return (lStatus);
|
|
}
|
|
|
|
NTSTATUS IccIsoInput(
|
|
PSMARTCARD_EXTENSION pSmartcardExtension,
|
|
const UCHAR pCommand[5],
|
|
const UCHAR pData[],
|
|
USHORT *pRespLen,
|
|
BYTE pRespBuff[]
|
|
)
|
|
/*++
|
|
|
|
Routine Description : This function sends an ISO IN command to the card
|
|
|
|
Arguments
|
|
pSmartcardExtension: Pointer to the SmartcardExtension structure.
|
|
pCommand : Iso out command to send.
|
|
pData : data to send.
|
|
pRespLen : in - maximum buffer size available
|
|
out - returned buffer length.
|
|
pRespBuff: returned buffer
|
|
--*/
|
|
{
|
|
// Local variables:
|
|
// - pReaderExt holds the pointer to the current ReaderExtension structure
|
|
// - Ti holds the apdu command tag.
|
|
// - Li holds the Iso out command length.
|
|
// - Vi holds Icc ISO In command whose format is
|
|
// <DIR=0x00> <CLA> <INS> <P1> <P2> <Length> [ Data ]
|
|
// Length = Length + Dir + CLA + INS + P1 + P2
|
|
// - To holds the response tag
|
|
// - Lo holds th response buffer length.
|
|
// - Vo holds the response buffer
|
|
READER_EXTENSION *pReaderExt = pSmartcardExtension->ReaderExtension;
|
|
UCHAR Vi[GPR_BUFFER_SIZE] = { 0x00 };
|
|
UCHAR Ti = APDU_EXCHANGE_CMD;
|
|
UCHAR To;
|
|
UCHAR Vo[GPR_BUFFER_SIZE];
|
|
USHORT Li;
|
|
USHORT Lo;
|
|
NTSTATUS lStatus=STATUS_SUCCESS;
|
|
|
|
// Length of the the TLV = Length of data + 6
|
|
Li = pCommand[4]+6,
|
|
|
|
// The five command bytes are added in cmd buffer.
|
|
RtlCopyMemory(Vi + 1, pCommand, 5);
|
|
|
|
//The data field is added.
|
|
RtlCopyMemory(Vi + 6, pData, pCommand[4]);
|
|
|
|
// The command is send to IFD.
|
|
// Fields RespLen and RespBuff are updates
|
|
// <= sResponse
|
|
Lo = *pRespLen;
|
|
|
|
lStatus = GprllTLVExchange(
|
|
pReaderExt,
|
|
Ti,
|
|
Li,
|
|
Vi,
|
|
&To,
|
|
&Lo,
|
|
Vo
|
|
);
|
|
|
|
if (lStatus == STATUS_SUCCESS)
|
|
{
|
|
*pRespLen = Lo;
|
|
RtlCopyMemory(pRespBuff, Vo, Lo);
|
|
}
|
|
else
|
|
{
|
|
*pRespLen = 0;
|
|
}
|
|
|
|
return (lStatus);
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS IccIsoT1(
|
|
PSMARTCARD_EXTENSION pSmartcardExtension,
|
|
const USHORT Li,
|
|
const UCHAR Vi[],
|
|
USHORT *Lo,
|
|
UCHAR Vo[]
|
|
)
|
|
/*++
|
|
|
|
|
|
Routine Description : This function sends a T=1 frame to the card
|
|
|
|
|
|
|
|
Arguments
|
|
pSmartcardExtension: Pointer to the SmartcardExtension structure.
|
|
Li : Length of the frame to send.
|
|
Vi : frame to send.
|
|
Lo : in - maximum buffer size available
|
|
out - Length of the response buffer.
|
|
Vo : Response buffer.
|
|
--*/
|
|
{
|
|
// Local variables:
|
|
// - pReaderExt holds the pointer to the current ReaderExtension structure
|
|
// - Ti Tag in TLV structure to send.
|
|
// - To Tag in response TLV structure.
|
|
UCHAR Ti = APDU_EXCHANGE_CMD;
|
|
UCHAR To;
|
|
NTSTATUS lStatus = STATUS_SUCCESS;
|
|
READER_EXTENSION *pReaderExt = pSmartcardExtension->ReaderExtension;
|
|
|
|
To = 0x00;
|
|
|
|
// Return value for To is not needed, The function GprllTLVExchange verify that
|
|
// it corresponds to the Ti
|
|
lStatus = GprllTLVExchange(
|
|
pReaderExt,
|
|
Ti,
|
|
Li,
|
|
Vi,
|
|
&To,
|
|
Lo,
|
|
Vo
|
|
);
|
|
|
|
return (lStatus);
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS IfdConfig(
|
|
PSMARTCARD_EXTENSION pSmartcardExtension,
|
|
UCHAR TA1
|
|
)
|
|
/*++
|
|
|
|
Routine Description : This function Sets the correct internal values of the reader
|
|
regarding the TA1 of the ATR.
|
|
|
|
Arguments
|
|
pSmartcardExtension: Pointer to the SmartcardExtension structure.
|
|
--*/
|
|
{
|
|
// Local variables:
|
|
// - sResponse holds the called function responses.
|
|
// - pReaderExt holds the pointer to the current ReaderExtension structure
|
|
// - lStatus holds the status to return.
|
|
// - Vi Holds the input buffer of the TLV commnand.
|
|
// - To holds the Tag of the returned TLV.
|
|
// - Lo holds the Length of the buffer of the returned TLV.
|
|
// - Vo holds the Buffer of the returned TLV.
|
|
//
|
|
UCHAR Card_ETU1;
|
|
UCHAR Card_ETU2;
|
|
UCHAR Card_ETU1P;
|
|
UCHAR Card_TA1;
|
|
READER_EXTENSION *pReaderExt = pSmartcardExtension->ReaderExtension;
|
|
NTSTATUS lStatus = STATUS_SUCCESS;
|
|
USHORT i = 0;
|
|
|
|
// search TA1 parameters
|
|
do {
|
|
if ( TA1 == cfg_ta1[i].TA1 )
|
|
{
|
|
break;
|
|
}
|
|
i++;
|
|
} while ( cfg_ta1[i].TA1 != 0 );
|
|
|
|
|
|
if(cfg_ta1[i].TA1 != 0)
|
|
{
|
|
Card_TA1 = cfg_ta1[i].TA1;
|
|
Card_ETU1 = cfg_ta1[i].ETU1;
|
|
Card_ETU2 = cfg_ta1[i].ETU2;
|
|
Card_ETU1P= cfg_ta1[i].ETU1P;
|
|
}
|
|
else
|
|
{
|
|
// Default value 9600
|
|
Card_TA1 = 0x11;
|
|
Card_ETU1 = 0x3B;
|
|
Card_ETU2 = 0x1E;
|
|
Card_ETU1P= 0x37;
|
|
}
|
|
|
|
// Verify each update to be done
|
|
|
|
//Set the TA1
|
|
lStatus = Update(pSmartcardExtension,0x32,Card_TA1);
|
|
if (lStatus != STATUS_SUCCESS)
|
|
{
|
|
return (lStatus);
|
|
}
|
|
|
|
//Set the Card ETU1
|
|
lStatus = Update(pSmartcardExtension,0x35,Card_ETU1);
|
|
if (lStatus != STATUS_SUCCESS)
|
|
{
|
|
return (lStatus);
|
|
}
|
|
|
|
//Set the Card ETU2
|
|
lStatus = Update(pSmartcardExtension,0x36,Card_ETU2);
|
|
if (lStatus != STATUS_SUCCESS)
|
|
{
|
|
return (lStatus);
|
|
}
|
|
|
|
//Set the Card ETU1 P
|
|
lStatus = Update(pSmartcardExtension,0x39,Card_ETU1P);
|
|
if (lStatus != STATUS_SUCCESS)
|
|
{
|
|
return (lStatus);
|
|
}
|
|
|
|
//Set the Save TA1
|
|
lStatus = Update(pSmartcardExtension,0x3A,Card_TA1);
|
|
if (lStatus != STATUS_SUCCESS)
|
|
{
|
|
return (lStatus);
|
|
}
|
|
|
|
//Set the Save ETU1
|
|
lStatus = Update(pSmartcardExtension,0x3D,Card_ETU1);
|
|
if (lStatus != STATUS_SUCCESS)
|
|
{
|
|
return (lStatus);
|
|
}
|
|
|
|
//Set the Save ETU2
|
|
lStatus = Update(pSmartcardExtension,0x3E,Card_ETU2);
|
|
if (lStatus != STATUS_SUCCESS)
|
|
{
|
|
return (lStatus);
|
|
}
|
|
|
|
//Set the Save ETU1 P
|
|
lStatus = Update(pSmartcardExtension,0x41,Card_ETU1P);
|
|
if (lStatus != STATUS_SUCCESS)
|
|
{
|
|
return (lStatus);
|
|
}
|
|
|
|
// Give the reader the time to process the change
|
|
GprllWait(100);
|
|
|
|
return (STATUS_SUCCESS);
|
|
|
|
}
|
|
|
|
|
|
NTSTATUS IfdCheck(
|
|
PSMARTCARD_EXTENSION pSmartcardExtension
|
|
)
|
|
/*++
|
|
|
|
Routine Description : This function performs a software reset of the GPR400 using
|
|
the Handshake register and TEST if hardware okay.
|
|
|
|
Arguments
|
|
pSmartcardExtension: Pointer to the SmartcardExtension structure.
|
|
--*/
|
|
{
|
|
// Local variables:
|
|
// - pReaderExt holds the pointer to the current ReaderExtension structure
|
|
// - HandShakeRegister
|
|
//
|
|
READER_EXTENSION *pReaderExt = pSmartcardExtension->ReaderExtension;
|
|
UCHAR HandShakeRegister;
|
|
|
|
#if DBG
|
|
SmartcardDebug(
|
|
DEBUG_ERROR,
|
|
( "%s!IfdCheck: Enter\n",
|
|
SC_DRIVER_NAME)
|
|
);
|
|
#endif
|
|
|
|
// In the case that system reboot for Hibernate in
|
|
// Power management. The GPR400 signal a device was been remove
|
|
// but we have to request a second time to have the actual
|
|
// state of the reader.
|
|
|
|
HandShakeRegister = GprllReadRegister(pReaderExt,REGISTER_HANDSHAKE);
|
|
|
|
SmartcardDebug(
|
|
DEBUG_DRIVER,
|
|
("%s!IfdCheck: Read HandShakeRegister value:%x\n",
|
|
SC_DRIVER_NAME, HandShakeRegister)
|
|
);
|
|
|
|
//Set to 1 the Master Reset bit from Handshake register
|
|
GprllMaskHandshakeRegister(pReaderExt,0x01,1);
|
|
|
|
//Wait 10 ms
|
|
GprllWait(10);
|
|
|
|
//Reset the Master Reset bit from Handshake register
|
|
GprllMaskHandshakeRegister(pReaderExt,0x01,0);
|
|
|
|
//Wait 80 ms
|
|
GprllWait(80);
|
|
|
|
HandShakeRegister = GprllReadRegister(pReaderExt,REGISTER_HANDSHAKE);
|
|
|
|
SmartcardDebug(
|
|
DEBUG_DRIVER,
|
|
("%s!IfdCheck: Read HandShakeRegister 2nd time value:%x\n",
|
|
SC_DRIVER_NAME, HandShakeRegister)
|
|
);
|
|
|
|
if(HandShakeRegister != 0x80)
|
|
{
|
|
// Return reader IO problem
|
|
return (STATUS_IO_DEVICE_ERROR);
|
|
}
|
|
|
|
return (STATUS_SUCCESS);
|
|
}
|
|
|
|
|
|
NTSTATUS IfdReset(
|
|
PSMARTCARD_EXTENSION pSmartcardExtension
|
|
)
|
|
/*++
|
|
|
|
Routine Description : This function performs a software reset of the GPR400 using
|
|
the Handshake register.
|
|
|
|
Arguments
|
|
pSmartcardExtension: Pointer to the SmartcardExtension structure.
|
|
--*/
|
|
{
|
|
// Local variables:
|
|
// - sResponse holds the called function responses.
|
|
// - pReaderExt holds the pointer to the current ReaderExtension structure
|
|
// - lStatus holds the status to return.
|
|
// - Vi Holds the input buffer of the TLV commnand.
|
|
// - To holds the Tag of the returned TLV.
|
|
// - Lo holds the Length of the buffer of the returned TLV.
|
|
// - Vo holds the Buffer of the returned TLV.
|
|
READER_EXTENSION *pReaderExt = pSmartcardExtension->ReaderExtension;
|
|
NTSTATUS lStatus = STATUS_SUCCESS;
|
|
UCHAR Vi[GPR_BUFFER_SIZE];
|
|
UCHAR To;
|
|
USHORT Lo;
|
|
UCHAR Vo[GPR_BUFFER_SIZE];
|
|
|
|
#if DBG
|
|
SmartcardDebug(
|
|
DEBUG_TRACE,
|
|
( "%s!IfdReset: Enter\n",
|
|
SC_DRIVER_NAME)
|
|
);
|
|
#endif
|
|
|
|
// In the case that system reboot for Hibernate in
|
|
// Power management. The GPR400 signal a device was been remove
|
|
// but we have to request a second time to have the actual
|
|
// state of the reader.
|
|
|
|
//Set to 1 the Master Reset bit from Handshake register
|
|
GprllMaskHandshakeRegister(pReaderExt,0x01,1);
|
|
|
|
//Wait 10 ms
|
|
GprllWait(10);
|
|
|
|
//Reset the Master Reset bit from Handshake register
|
|
GprllMaskHandshakeRegister(pReaderExt,0x01,0);
|
|
|
|
//Wait 80 ms
|
|
GprllWait(80);
|
|
|
|
//Read the GPR status
|
|
Vi[0] = 0x00;
|
|
Lo = GPR_BUFFER_SIZE;
|
|
|
|
lStatus = GprllTLVExchange (
|
|
pReaderExt,
|
|
CHECK_AND_STATUS_CMD,
|
|
0x01,
|
|
Vi,
|
|
&To,
|
|
&Lo,
|
|
Vo
|
|
);
|
|
|
|
#if DBG
|
|
SmartcardDebug(
|
|
DEBUG_TRACE,
|
|
( "%s!IfdReset: GprllTLVExchange status= %x\n",
|
|
SC_DRIVER_NAME, lStatus)
|
|
);
|
|
#endif
|
|
|
|
if (lStatus != STATUS_SUCCESS)
|
|
{
|
|
SmartcardDebug(
|
|
DEBUG_TRACE,
|
|
( "%s!IfdReset: GprllTLVExchange() failed! Leaving.....\n",
|
|
SC_DRIVER_NAME)
|
|
);
|
|
|
|
return (lStatus);
|
|
}
|
|
|
|
//Memorize the GPR400 version
|
|
pReaderExt->OsVersion = Vo[1];
|
|
|
|
pSmartcardExtension->VendorAttr.IfdVersion.VersionMinor =
|
|
pReaderExt->OsVersion & 0x0f;
|
|
|
|
pSmartcardExtension->VendorAttr.IfdVersion.VersionMajor =
|
|
(pReaderExt->OsVersion & 0xf0) >> 4;
|
|
|
|
SmartcardDebug(
|
|
DEBUG_TRACE,
|
|
( "%s!IfdReset: Loading Master driver...\n",
|
|
SC_DRIVER_NAME)
|
|
);
|
|
|
|
//Load the Master Driver in RAM at @2100h
|
|
Vi[0] = 0x02; // DIR
|
|
Vi[1] = 0x01 ; // ADR MSB
|
|
Vi[2] = 0x00 ; // ADR LSB
|
|
memcpy(&Vi[3], MASTER_DRIVER, sizeof(MASTER_DRIVER));
|
|
// Output variable initialisation
|
|
Lo = GPR_BUFFER_SIZE;
|
|
To = 0x00;
|
|
Vo[0] = 0x00;
|
|
|
|
lStatus = GprllTLVExchange (
|
|
pReaderExt,
|
|
LOAD_MEMORY_CMD,
|
|
sizeof(MASTER_DRIVER) + 3,
|
|
Vi,
|
|
&To,
|
|
&Lo,
|
|
Vo
|
|
);
|
|
if (lStatus != STATUS_SUCCESS)
|
|
{
|
|
SmartcardDebug(
|
|
DEBUG_TRACE,
|
|
( "%s!IfdReset: GprllTLVExchange() failed! Leaving.....\n",
|
|
SC_DRIVER_NAME)
|
|
);
|
|
return (lStatus);
|
|
}
|
|
|
|
lStatus = ValidateDriver(pSmartcardExtension);
|
|
if (lStatus != STATUS_SUCCESS)
|
|
{
|
|
SmartcardDebug(
|
|
DEBUG_TRACE,
|
|
( "%s!IfdReset: ValidateDriver() failed! Leaving.....\n",
|
|
SC_DRIVER_NAME)
|
|
);
|
|
return (lStatus);
|
|
}
|
|
|
|
return (STATUS_SUCCESS);
|
|
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS IfdPowerDown(
|
|
PSMARTCARD_EXTENSION pSmartcardExtension
|
|
)
|
|
/*++
|
|
|
|
Routine Description :
|
|
This function powers down the IFD
|
|
|
|
Arguments
|
|
pSmartcardExtension: Pointer to the SmartcardExtension structure.
|
|
|
|
--*/
|
|
{
|
|
// Local variables:
|
|
// - sResponse holds the called function responses.
|
|
// - pReaderExt holds the pointer to the current ReaderExtension structure
|
|
// - lStatus holds the status to return.
|
|
// - Vi Holds the input buffer of the TLV commnand.
|
|
// - To holds the Tag of the returned TLV.
|
|
// - Lo holds the Length of the buffer of the returned TLV.
|
|
// - Vo holds the Buffer of the returned TLV.
|
|
READER_EXTENSION *pReaderExt = pSmartcardExtension->ReaderExtension;
|
|
NTSTATUS lStatus = STATUS_SUCCESS;
|
|
UCHAR Vi[GPR_BUFFER_SIZE];
|
|
UCHAR To;
|
|
USHORT Lo;
|
|
UCHAR Vo[GPR_BUFFER_SIZE];
|
|
|
|
// Put the GPR in Power-down mode (GprllTLVExchange T=0x40, L=1 and V=0x00)
|
|
// <== response of the GprllTLVExchange
|
|
Vi[0] = 0x00;
|
|
// Output variable initialisation
|
|
Lo = GPR_BUFFER_SIZE;
|
|
To = 0x00;
|
|
Vo[0] = 0x00;
|
|
|
|
lStatus = GprllTLVExchange(
|
|
pReaderExt,
|
|
POWER_DOWN_GPR_CMD,
|
|
0x01,
|
|
Vi,
|
|
&To,
|
|
&Lo,
|
|
Vo
|
|
);
|
|
|
|
return (lStatus);
|
|
}
|
|
|
|
|
|
NTSTATUS GprCbReaderPower(
|
|
PSMARTCARD_EXTENSION SmartcardExtension
|
|
)
|
|
/*++
|
|
|
|
Routine Description :
|
|
This function is called by the Smart card library when a
|
|
IOCTL_SMARTCARD_POWER occurs.
|
|
This function provides 3 differents functionnality, depending of the minor
|
|
IOCTL value
|
|
- Cold reset (SCARD_COLD_RESET),
|
|
- Warm reset (SCARD_WARM_RESET),
|
|
- Power down (SCARD_POWER_DOWN).
|
|
|
|
Arguments
|
|
- SmartcardExtension is a pointer on the SmartCardExtension structure of
|
|
the current device.
|
|
--*/
|
|
{
|
|
NTSTATUS lStatus = STATUS_SUCCESS;
|
|
PREADER_EXTENSION pReader;
|
|
|
|
ASSERT(SmartcardExtension != NULL);
|
|
|
|
pReader = SmartcardExtension->ReaderExtension;
|
|
waitForIdleAndBlock(pReader);
|
|
switch(SmartcardExtension->MinorIoControlCode)
|
|
{
|
|
case SCARD_POWER_DOWN:
|
|
//Power down the ICC
|
|
lStatus = IccPowerDown(SmartcardExtension);
|
|
break;
|
|
|
|
case SCARD_COLD_RESET:
|
|
// Power up the ICC after a power down and a PowerTimeout waiting time.
|
|
lStatus = IccPowerDown(SmartcardExtension);
|
|
if(lStatus != STATUS_SUCCESS)
|
|
{
|
|
break;
|
|
}
|
|
|
|
// Waits for the Power Timeout to be elapsed before the reset command.
|
|
GprllWait(SmartcardExtension->ReaderExtension->PowerTimeOut);
|
|
|
|
case SCARD_WARM_RESET:
|
|
lStatus = IccColdReset(SmartcardExtension);
|
|
break;
|
|
|
|
default:
|
|
lStatus = STATUS_NOT_SUPPORTED;
|
|
}
|
|
|
|
setIdle(pReader);
|
|
return lStatus;
|
|
}
|
|
|
|
NTSTATUS GprCbTransmit(
|
|
PSMARTCARD_EXTENSION SmartcardExtension
|
|
)
|
|
/*++
|
|
|
|
Routine Description :
|
|
|
|
This function is called by the Smart card library when a
|
|
IOCTL_SMARTCARD_TRANSMIT occurs.
|
|
This function is used to transmit a command to the card.
|
|
|
|
Arguments
|
|
- SmartcardExtension is a pointer on the SmartCardExtension structure of
|
|
the current device.
|
|
--*/
|
|
{
|
|
NTSTATUS lStatus=STATUS_SUCCESS;
|
|
PUCHAR requestBuffer = SmartcardExtension->SmartcardRequest.Buffer;
|
|
PUCHAR replyBuffer = SmartcardExtension->SmartcardReply.Buffer;
|
|
PULONG requestLength = &SmartcardExtension->SmartcardRequest.BufferLength;
|
|
PULONG replyLength = &SmartcardExtension->SmartcardReply.BufferLength;
|
|
USHORT sRespLen;
|
|
UCHAR pRespBuff[GPR_BUFFER_SIZE];
|
|
PREADER_EXTENSION pReader;
|
|
|
|
ASSERT(SmartcardExtension != NULL);
|
|
|
|
*requestLength = 0;
|
|
sRespLen = 0;
|
|
pRespBuff[0] = 0x0;
|
|
|
|
pReader = SmartcardExtension->ReaderExtension;
|
|
waitForIdleAndBlock(pReader);
|
|
switch (SmartcardExtension->CardCapabilities.Protocol.Selected)
|
|
{
|
|
// Raw
|
|
case SCARD_PROTOCOL_RAW:
|
|
lStatus = STATUS_INVALID_DEVICE_STATE;
|
|
break;
|
|
|
|
// T=0
|
|
case SCARD_PROTOCOL_T0:
|
|
lStatus = SmartcardT0Request(SmartcardExtension);
|
|
if (lStatus != STATUS_SUCCESS)
|
|
{
|
|
setIdle(pReader);
|
|
return lStatus;
|
|
}
|
|
|
|
sRespLen = GPR_BUFFER_SIZE;
|
|
pRespBuff[0] = 0x0;
|
|
|
|
if (SmartcardExtension->T0.Le > 0)
|
|
{
|
|
// ISO OUT command if BufferLength = 5
|
|
lStatus = IccIsoOutput(
|
|
SmartcardExtension,
|
|
( UCHAR *) SmartcardExtension->SmartcardRequest.Buffer,
|
|
&sRespLen,
|
|
pRespBuff
|
|
);
|
|
}
|
|
else
|
|
{
|
|
// ISO IN command if BufferLength >5 or BufferLength = 4
|
|
lStatus = IccIsoInput(
|
|
SmartcardExtension,
|
|
( UCHAR *) SmartcardExtension->SmartcardRequest.Buffer,
|
|
( UCHAR *) SmartcardExtension->SmartcardRequest.Buffer+5,
|
|
&sRespLen,
|
|
pRespBuff
|
|
);
|
|
}
|
|
if (lStatus != STATUS_SUCCESS)
|
|
{
|
|
setIdle(pReader);
|
|
return lStatus;
|
|
}
|
|
// Copy the response command without the reader status
|
|
|
|
// Verify if the buffer is large enough
|
|
if (SmartcardExtension->SmartcardReply.BufferSize >= (ULONG)(sRespLen - 1))
|
|
{
|
|
RtlCopyMemory(
|
|
SmartcardExtension->SmartcardReply.Buffer,
|
|
pRespBuff + 1,
|
|
sRespLen - 1);
|
|
SmartcardExtension->SmartcardReply.BufferLength =
|
|
(ULONG) (sRespLen - 1);
|
|
}
|
|
else
|
|
{
|
|
// SmartcardT0Reply must be called; prepare this call.
|
|
SmartcardExtension->SmartcardReply.BufferLength = 0;
|
|
}
|
|
lStatus = SmartcardT0Reply(SmartcardExtension);
|
|
|
|
break;
|
|
// T=1
|
|
case SCARD_PROTOCOL_T1:
|
|
|
|
do
|
|
{
|
|
SmartcardExtension->SmartcardRequest.BufferLength = 0;
|
|
lStatus = SmartcardT1Request(SmartcardExtension);
|
|
if(lStatus != STATUS_SUCCESS)
|
|
{
|
|
setIdle(pReader);
|
|
return lStatus;
|
|
}
|
|
|
|
sRespLen = GPR_BUFFER_SIZE;
|
|
pRespBuff[0] = 0x0;
|
|
lStatus = IccIsoT1(
|
|
SmartcardExtension,
|
|
(USHORT) SmartcardExtension->SmartcardRequest.BufferLength,
|
|
(UCHAR *) SmartcardExtension->SmartcardRequest.Buffer,
|
|
&sRespLen,
|
|
pRespBuff);
|
|
|
|
if(lStatus != STATUS_SUCCESS)
|
|
{
|
|
// do not try to access the reader anymore.
|
|
if(lStatus == STATUS_DEVICE_REMOVED)
|
|
{
|
|
setIdle(pReader);
|
|
return lStatus;
|
|
}
|
|
// Let the SmartcardT1Reply determine the status
|
|
sRespLen = 1;
|
|
}
|
|
// Copy the response of the reader in the reply buffer
|
|
// Remove the status of the reader
|
|
// Verify if the buffer is large enough
|
|
if (SmartcardExtension->SmartcardReply.BufferSize >= (ULONG)(sRespLen - 1))
|
|
{
|
|
RtlCopyMemory(
|
|
SmartcardExtension->SmartcardReply.Buffer,
|
|
pRespBuff + 1 ,
|
|
sRespLen - 1
|
|
);
|
|
SmartcardExtension->SmartcardReply.BufferLength =
|
|
(ULONG) sRespLen - 1;
|
|
}
|
|
else
|
|
{
|
|
// SmartcardT1Reply must be called; prepare this call.
|
|
SmartcardExtension->SmartcardReply.BufferLength = 0;
|
|
}
|
|
|
|
lStatus = SmartcardT1Reply(SmartcardExtension);
|
|
|
|
} while(lStatus == STATUS_MORE_PROCESSING_REQUIRED);
|
|
break;
|
|
default:
|
|
lStatus = STATUS_INVALID_DEVICE_REQUEST;
|
|
break;
|
|
}
|
|
|
|
setIdle(pReader);
|
|
return lStatus;
|
|
}
|
|
|
|
|
|
NTSTATUS GprCbSetProtocol(
|
|
PSMARTCARD_EXTENSION SmartcardExtension
|
|
)
|
|
/*++
|
|
|
|
Routine Description :
|
|
|
|
This function is called by the Smart card library when a
|
|
IOCTL_SMARTCARD_SET_PROTOCOL occurs.
|
|
The minor IOCTL value holds the protocol to set.
|
|
|
|
Arguments
|
|
- SmartcardExtension is a pointer on the SmartCardExtension structure of
|
|
the current device.
|
|
--*/
|
|
{
|
|
NTSTATUS lStatus=STATUS_SUCCESS;
|
|
UCHAR Vi[GPR_BUFFER_SIZE];
|
|
UCHAR To;
|
|
USHORT Lo;
|
|
UCHAR Vo[GPR_BUFFER_SIZE];
|
|
READER_EXTENSION *pReaderExt = SmartcardExtension->ReaderExtension;
|
|
UCHAR PTS0=0;
|
|
UCHAR Value = 0;
|
|
PREADER_EXTENSION pReader;
|
|
KIRQL irql;
|
|
|
|
|
|
ASSERT(SmartcardExtension != NULL);
|
|
|
|
|
|
pReader = SmartcardExtension->ReaderExtension;
|
|
|
|
waitForIdleAndBlock(pReader);
|
|
|
|
// Check if the card is already in specific state
|
|
// and if the caller wants to have the already selected protocol.
|
|
// We return success if this is the case.
|
|
//
|
|
*SmartcardExtension->IoRequest.Information = 0x00;
|
|
|
|
if ( SmartcardExtension->ReaderCapabilities.CurrentState == SCARD_SPECIFIC &&
|
|
( SmartcardExtension->CardCapabilities.Protocol.Selected &
|
|
SmartcardExtension->MinorIoControlCode
|
|
)
|
|
)
|
|
{
|
|
lStatus = STATUS_SUCCESS;
|
|
}
|
|
else
|
|
{
|
|
|
|
__try
|
|
{
|
|
if (SmartcardExtension->CardCapabilities.Protocol.Supported &
|
|
SmartcardExtension->MinorIoControlCode &
|
|
SCARD_PROTOCOL_T1)
|
|
{
|
|
|
|
// select T=1
|
|
SmartcardExtension->CardCapabilities.Protocol.Selected = SCARD_PROTOCOL_T1;
|
|
PTS0= 0x11;
|
|
}
|
|
else if (SmartcardExtension->CardCapabilities.Protocol.Supported &
|
|
SmartcardExtension->MinorIoControlCode &
|
|
SCARD_PROTOCOL_T0)
|
|
{
|
|
|
|
// select T=0
|
|
SmartcardExtension->CardCapabilities.Protocol.Selected = SCARD_PROTOCOL_T0;
|
|
PTS0 = 0x10;
|
|
|
|
}
|
|
else
|
|
{
|
|
lStatus = STATUS_INVALID_DEVICE_REQUEST;
|
|
__leave;
|
|
}
|
|
|
|
|
|
// Send the PTS function
|
|
Vi[0] = 0xFF;
|
|
Vi[1] = PTS0;
|
|
Vi[2] = SmartcardExtension->CardCapabilities.PtsData.Fl <<4 |
|
|
SmartcardExtension->CardCapabilities.PtsData.Dl;
|
|
Vi[3] = (0xFF ^ PTS0) ^ Vi[2];
|
|
|
|
Lo = GPR_BUFFER_SIZE;
|
|
To = 0x00;
|
|
Vo[0] = 0x00;
|
|
|
|
|
|
// Status of the PTS could be STATUS SUCCESS
|
|
// or STATUS_DEVICE_PROTOCOL_ERROR if failed.
|
|
lStatus = GprllTLVExchange(
|
|
pReaderExt,
|
|
EXEC_MEMORY_CMD,
|
|
0x04,
|
|
Vi,
|
|
&To,
|
|
&Lo,
|
|
Vo
|
|
);
|
|
|
|
#if DBG
|
|
SmartcardDebug(
|
|
DEBUG_TRACE,
|
|
( "%s!IfdReset: GprCbSetProtocol status= %x\n",
|
|
SC_DRIVER_NAME, lStatus)
|
|
);
|
|
#endif
|
|
|
|
if (lStatus != STATUS_SUCCESS)
|
|
{
|
|
__leave;
|
|
}
|
|
|
|
|
|
// reader should reply status byte of 00 or 12
|
|
// the rest is other problem with no relation with
|
|
// the PTS negociation
|
|
lStatus = STATUS_SUCCESS;
|
|
|
|
// Put the reader in the right protocol
|
|
if (SmartcardExtension->CardCapabilities.Protocol.Selected == SCARD_PROTOCOL_T1)
|
|
{
|
|
lStatus = T0toT1(SmartcardExtension);
|
|
}
|
|
else
|
|
{
|
|
lStatus = T1toT0(SmartcardExtension);
|
|
}
|
|
if (lStatus != STATUS_SUCCESS)
|
|
{
|
|
__leave;
|
|
}
|
|
|
|
|
|
lStatus = IfdConfig(SmartcardExtension, 0x11);
|
|
if (lStatus != STATUS_SUCCESS)
|
|
{
|
|
__leave;
|
|
}
|
|
|
|
}
|
|
// we change the error code to a protocol error.
|
|
__finally
|
|
{
|
|
if (lStatus != STATUS_SUCCESS &&
|
|
lStatus != STATUS_INVALID_DEVICE_REQUEST
|
|
)
|
|
{
|
|
lStatus = STATUS_DEVICE_PROTOCOL_ERROR;
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
//
|
|
// Set the reply buffer length to sizeof(ULONG).
|
|
// Check if status SUCCESS, store the selected protocol.
|
|
//
|
|
|
|
KeAcquireSpinLock(&SmartcardExtension->OsData->SpinLock,
|
|
&irql);
|
|
|
|
if (lStatus == STATUS_SUCCESS)
|
|
{
|
|
*SmartcardExtension->IoRequest.Information =
|
|
sizeof(SmartcardExtension->CardCapabilities.Protocol.Selected);
|
|
|
|
*( PULONG) SmartcardExtension->IoRequest.ReplyBuffer =
|
|
SmartcardExtension->CardCapabilities.Protocol.Selected;
|
|
|
|
SmartcardExtension->ReaderCapabilities.CurrentState = SCARD_SPECIFIC;
|
|
}
|
|
else
|
|
{
|
|
SmartcardExtension->CardCapabilities.Protocol.Selected =
|
|
SCARD_PROTOCOL_UNDEFINED;
|
|
*SmartcardExtension->IoRequest.Information = 0;
|
|
}
|
|
KeReleaseSpinLock(&SmartcardExtension->OsData->SpinLock,
|
|
irql);
|
|
|
|
setIdle(pReader);
|
|
return lStatus;
|
|
|
|
}
|
|
|
|
|
|
NTSTATUS AskForCardPresence(
|
|
PSMARTCARD_EXTENSION pSmartcardExtension
|
|
)
|
|
/*++
|
|
|
|
Routine Description :
|
|
|
|
This functions send a TLV command to the reader to know if there
|
|
is a card inserted.
|
|
|
|
The function does not wait to the answer. The treatment of the
|
|
answer is done in the interrupt routine.
|
|
|
|
Arguments
|
|
|
|
pSmartcardExtension: Pointer to the SmartcardExtension structure.
|
|
--*/
|
|
{
|
|
// Local variables:
|
|
// - pReaderExt holds the pointer to the current ReaderExtension structure
|
|
// - V holds the value for the TLV comand.
|
|
READER_EXTENSION *pReaderExt = pSmartcardExtension->ReaderExtension;
|
|
UCHAR V=0x02;
|
|
|
|
GprllSendCmd(pReaderExt,CHECK_AND_STATUS_CMD,1,&V);
|
|
|
|
return (STATUS_SUCCESS);
|
|
}
|
|
|
|
|
|
NTSTATUS SpecificTag(
|
|
PSMARTCARD_EXTENSION SmartcardExtension,
|
|
DWORD IoControlCode,
|
|
DWORD BufferInLen,
|
|
BYTE *BufferIn,
|
|
DWORD BufferOutLen,
|
|
BYTE *BufferOut,
|
|
DWORD *LengthOut
|
|
)
|
|
/*++
|
|
|
|
|
|
Routine Description :
|
|
This function is called when a specific Tag request occurs.
|
|
|
|
Arguments
|
|
- SmartcardExtension is a pointer on the SmartCardExtension structure of
|
|
the current device.
|
|
- IoControlCode holds the IOCTL value.
|
|
--*/
|
|
{
|
|
ULONG TagValue;
|
|
PREADER_EXTENSION pReaderExtension = SmartcardExtension->ReaderExtension;
|
|
|
|
//Set the reply buffer length to 0.
|
|
*LengthOut = 0;
|
|
|
|
//Verify the length of the Tag
|
|
//<== STATUS_BUFFER_TOO_SMALL
|
|
if (BufferInLen < (DWORD) sizeof(TagValue))
|
|
{
|
|
return(STATUS_BUFFER_TOO_SMALL);
|
|
}
|
|
|
|
|
|
TagValue = (ULONG) *((PULONG)BufferIn);
|
|
|
|
//Switch for the different IOCTL:
|
|
//Get the value of one tag (IOCTL_SMARTCARD_VENDOR_GET_ATTRIBUTE)
|
|
//Switch for the different Tags:
|
|
switch(IoControlCode)
|
|
{
|
|
case IOCTL_SMARTCARD_VENDOR_GET_ATTRIBUTE:
|
|
switch (TagValue)
|
|
{
|
|
// Power Timeout (SCARD_ATTR_SPEC_POWER_TIMEOUT)
|
|
// Verify the length of the output buffer.
|
|
// <== STATUS_BUFFER_TOO_SMALL
|
|
// Update the output buffer and the length.
|
|
// <== STATUS_SUCCESS
|
|
case SCARD_ATTR_SPEC_POWER_TIMEOUT:
|
|
if ( BufferOutLen < (DWORD) sizeof(pReaderExtension->PowerTimeOut))
|
|
{
|
|
return(STATUS_BUFFER_TOO_SMALL);
|
|
}
|
|
ASSERT(BufferOut != 0);
|
|
memcpy(
|
|
BufferOut,
|
|
&pReaderExtension->PowerTimeOut,
|
|
sizeof(pReaderExtension->PowerTimeOut)
|
|
);
|
|
|
|
*(LengthOut) =
|
|
(ULONG) sizeof(pReaderExtension->PowerTimeOut);
|
|
|
|
return STATUS_SUCCESS;
|
|
break;
|
|
// Command Timeout (SCARD_ATTR_SPEC_CMD_TIMEOUT)
|
|
// Verify the length of the output buffer.
|
|
// <== STATUS_BUFFER_TOO_SMALL
|
|
// Update the output buffer and the length.
|
|
// <== STATUS_SUCCESS
|
|
case SCARD_ATTR_SPEC_CMD_TIMEOUT:
|
|
if (BufferOutLen < (DWORD) sizeof(pReaderExtension->CmdTimeOut))
|
|
{
|
|
return(STATUS_BUFFER_TOO_SMALL);
|
|
}
|
|
ASSERT(BufferOut != 0);
|
|
memcpy(
|
|
BufferOut,
|
|
&pReaderExtension->CmdTimeOut,
|
|
sizeof(pReaderExtension->CmdTimeOut)
|
|
);
|
|
*(LengthOut) =
|
|
(ULONG) sizeof(pReaderExtension->CmdTimeOut);
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
break;
|
|
|
|
case SCARD_ATTR_MANUFACTURER_NAME:
|
|
if (BufferOutLen < ATTR_LENGTH)
|
|
{
|
|
return STATUS_BUFFER_TOO_SMALL;
|
|
}
|
|
// Copy the string of the Manufacturer Name
|
|
|
|
memcpy(
|
|
BufferOut,
|
|
ATTR_MANUFACTURER_NAME,
|
|
sizeof(ATTR_MANUFACTURER_NAME)
|
|
);
|
|
|
|
*(LengthOut) = (ULONG)sizeof(ATTR_MANUFACTURER_NAME);
|
|
|
|
return STATUS_SUCCESS;
|
|
break;
|
|
|
|
case SCARD_ATTR_ORIGINAL_FILENAME:
|
|
if (BufferOutLen < ATTR_LENGTH)
|
|
{
|
|
return STATUS_BUFFER_TOO_SMALL;
|
|
}
|
|
// Copy the string of the Original file name of the current driver
|
|
memcpy(
|
|
BufferOut,
|
|
ATTR_ORIGINAL_FILENAME,
|
|
sizeof(ATTR_ORIGINAL_FILENAME)
|
|
);
|
|
|
|
*(LengthOut) = (ULONG)sizeof(ATTR_ORIGINAL_FILENAME);
|
|
|
|
return STATUS_SUCCESS;
|
|
break;
|
|
|
|
// Unknown tag
|
|
// <== STATUS_NOT_SUPPORTED
|
|
default:
|
|
return STATUS_NOT_SUPPORTED;
|
|
break;
|
|
}
|
|
break;
|
|
|
|
// Set the value of one tag (IOCTL_SMARTCARD_VENDOR_SET_ATTRIBUTE)
|
|
// Switch for the different Tags:
|
|
case IOCTL_SMARTCARD_VENDOR_SET_ATTRIBUTE:
|
|
switch (TagValue)
|
|
{
|
|
// Power Timeout (SCARD_ATTR_SPEC_POWER_TIMEOUT)
|
|
// Verify the length of the input buffer.
|
|
// <== STATUS_BUFFER_TOO_SMALL
|
|
// Update the value.
|
|
// <== STATUS_SUCCESS
|
|
|
|
|
|
case SCARD_ATTR_SPEC_POWER_TIMEOUT:
|
|
if ( BufferInLen <
|
|
(DWORD) (sizeof(pReaderExtension->PowerTimeOut) +
|
|
sizeof(TagValue))
|
|
)
|
|
{
|
|
return(STATUS_BUFFER_TOO_SMALL);
|
|
}
|
|
ASSERT(BufferIn !=0);
|
|
memcpy(
|
|
&pReaderExtension->PowerTimeOut,
|
|
BufferIn + sizeof(TagValue),
|
|
sizeof(pReaderExtension->PowerTimeOut)
|
|
);
|
|
return STATUS_SUCCESS;
|
|
break;
|
|
// Command Timeout (SCARD_ATTR_SPEC_CMD_TIMEOUT)
|
|
// Verify the length of the input buffer.
|
|
// <== STATUS_BUFFER_TOO_SMALL
|
|
// Update the value.
|
|
// <== STATUS_SUCCESS
|
|
|
|
|
|
case SCARD_ATTR_SPEC_CMD_TIMEOUT:
|
|
if ( BufferInLen <
|
|
(DWORD) ( sizeof(pReaderExtension->CmdTimeOut) +
|
|
sizeof(TagValue))
|
|
)
|
|
{
|
|
return(STATUS_BUFFER_TOO_SMALL);
|
|
}
|
|
ASSERT(BufferIn != 0);
|
|
memcpy(
|
|
&pReaderExtension->CmdTimeOut,
|
|
BufferIn + sizeof(TagValue),
|
|
sizeof(pReaderExtension->CmdTimeOut)
|
|
);
|
|
return STATUS_SUCCESS;
|
|
break;
|
|
// Unknown tag
|
|
// <== STATUS_NOT_SUPPORTED
|
|
default:
|
|
return STATUS_NOT_SUPPORTED;
|
|
}
|
|
break;
|
|
default:
|
|
return STATUS_NOT_SUPPORTED;
|
|
}
|
|
}
|
|
|
|
|
|
NTSTATUS SwitchSpeed(
|
|
PSMARTCARD_EXTENSION SmartcardExtension,
|
|
ULONG BufferInLen,
|
|
PUCHAR BufferIn,
|
|
ULONG BufferOutLen,
|
|
PUCHAR BufferOut,
|
|
PULONG LengthOut
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is called when apps want to switch reader speed after a
|
|
proprietary switch speed (switch protocol) command has been sent to the
|
|
smart card.
|
|
|
|
Arguments:
|
|
|
|
SmartcardExtension - is a pointer on the SmartCardExtension structure of
|
|
the current device.
|
|
BufferInLen - holds the length of the input data.
|
|
BufferIn - holds the input data. TA1. If 0
|
|
BufferOutLen - holds the size of the output buffer.
|
|
BufferOut - the output buffer. Reader status code.
|
|
LengthOut - holds the length of the output data.
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS - We could execute the request.
|
|
STATUS_BUFFER_TOO_SMALL - The output buffer is to small.
|
|
STATUS_NOT_SUPPORTED - We could not support the Ioctl specified.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS status;
|
|
BYTE NewTA1;
|
|
ULONG i;
|
|
|
|
ASSERT(SmartcardExtension != NULL);
|
|
|
|
*LengthOut = 0;
|
|
// Just checking if IOCTL exists.
|
|
if (BufferInLen == 0)
|
|
{
|
|
SmartcardDebug(
|
|
DEBUG_INFO,
|
|
("%s!SwitchSpeed: Just checking IOCTL.\n",
|
|
SC_DRIVER_NAME)
|
|
);
|
|
return(STATUS_SUCCESS);
|
|
}
|
|
else
|
|
{
|
|
NewTA1 = BufferIn[0];
|
|
i = 0;
|
|
// Verify if this TA1 is support by the GPR400
|
|
do {
|
|
if ( NewTA1 == cfg_ta1[i].TA1 )
|
|
{
|
|
// TA1 Found!
|
|
break;
|
|
}
|
|
i++;
|
|
} while ( cfg_ta1[i].TA1 != 0 );
|
|
}
|
|
|
|
// If 0 means TA1 not found
|
|
if(cfg_ta1[i].TA1 != 0)
|
|
{
|
|
SmartcardDebug(
|
|
DEBUG_INFO,
|
|
("%s!GDDK_0ASwitchSpeed: 0x%X\n",
|
|
SC_DRIVER_NAME, NewTA1)
|
|
);
|
|
status = IfdConfig(SmartcardExtension, NewTA1);
|
|
}
|
|
else
|
|
{
|
|
// TA1 not supported
|
|
return STATUS_NOT_SUPPORTED;
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS GprCbVendorIoctl(
|
|
PSMARTCARD_EXTENSION SmartcardExtension
|
|
)
|
|
/*++
|
|
|
|
Routine Description :
|
|
|
|
This routine is called when a vendor IOCTL_SMARTCARD_ is send to the driver.
|
|
|
|
Arguments
|
|
- SmartcardExtension is a pointer on the SmartCardExtension structure of
|
|
the current device.
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS - We could execute the request.
|
|
STATUS_BUFFER_TOO_SMALL - The output buffer is to small.
|
|
STATUS_NOT_SUPPORTED - We could not support the Ioctl specified.
|
|
--*/
|
|
{
|
|
PREADER_EXTENSION pReaderExtension = SmartcardExtension->ReaderExtension;
|
|
UCHAR To;
|
|
UCHAR Vo[GPR_BUFFER_SIZE];
|
|
USHORT Lo;
|
|
USHORT BufferInLen = 0;
|
|
NTSTATUS lStatus=STATUS_SUCCESS;
|
|
PREADER_EXTENSION pReader;
|
|
|
|
ASSERT(SmartcardExtension != NULL);
|
|
|
|
// Set the reply buffer length to 0.
|
|
*SmartcardExtension->IoRequest.Information = 0;
|
|
|
|
|
|
pReader = SmartcardExtension->ReaderExtension;
|
|
|
|
waitForIdleAndBlock(pReader);
|
|
|
|
//Switch for the different IOCTL:
|
|
|
|
switch(SmartcardExtension->MajorIoControlCode)
|
|
{
|
|
|
|
case IOCTL_SMARTCARD_VENDOR_GET_ATTRIBUTE:
|
|
case IOCTL_SMARTCARD_VENDOR_SET_ATTRIBUTE:
|
|
SpecificTag(
|
|
SmartcardExtension,
|
|
(ULONG) SmartcardExtension->MajorIoControlCode,
|
|
(ULONG) SmartcardExtension->IoRequest.RequestBufferLength,
|
|
(PUCHAR) SmartcardExtension->IoRequest.RequestBuffer,
|
|
(ULONG) SmartcardExtension->IoRequest.ReplyBufferLength,
|
|
(PUCHAR) SmartcardExtension->IoRequest.ReplyBuffer,
|
|
(PULONG) SmartcardExtension->IoRequest.Information
|
|
);
|
|
break;
|
|
|
|
|
|
// IOCTL_SMARTCARD_VENDOR_IFD_EXCHANGE:
|
|
// Translate the buffer to TLV and send it to the reader.
|
|
case IOCTL_SMARTCARD_VENDOR_IFD_EXCHANGE:
|
|
|
|
if(SmartcardExtension->IoRequest.ReplyBufferLength < 3)
|
|
{
|
|
setIdle(pReader);
|
|
return(STATUS_INVALID_BUFFER_SIZE);
|
|
}
|
|
|
|
BufferInLen = (SmartcardExtension->IoRequest.RequestBuffer[2]*0x100)
|
|
+ SmartcardExtension->IoRequest.RequestBuffer[1];
|
|
|
|
if( (ULONG) BufferInLen > (SmartcardExtension->IoRequest.ReplyBufferLength - 3))
|
|
{
|
|
setIdle(pReader);
|
|
return(STATUS_INVALID_BUFFER_SIZE);
|
|
}
|
|
|
|
Lo = GPR_BUFFER_SIZE;
|
|
To = 0x00;
|
|
Vo[0] = 0x00;
|
|
|
|
lStatus = GprllTLVExchange(
|
|
pReaderExtension,
|
|
(const BYTE) SmartcardExtension->IoRequest.RequestBuffer[0],
|
|
(const USHORT) BufferInLen,
|
|
(const BYTE *) &(SmartcardExtension->IoRequest.RequestBuffer[3]),
|
|
&To,
|
|
&Lo,
|
|
Vo
|
|
);
|
|
|
|
if (lStatus != STATUS_SUCCESS)
|
|
{
|
|
setIdle(pReader);
|
|
return (lStatus);
|
|
}
|
|
|
|
// Check if there is enough space in the reply buffer
|
|
if((ULONG)(Lo+3) > SmartcardExtension->IoRequest.ReplyBufferLength)
|
|
{
|
|
setIdle(pReader);
|
|
return(STATUS_INVALID_BUFFER_SIZE);
|
|
}
|
|
else
|
|
{
|
|
ASSERT(SmartcardExtension->IoRequest.ReplyBuffer != 0);
|
|
SmartcardExtension->IoRequest.ReplyBuffer[0] = To;
|
|
SmartcardExtension->IoRequest.ReplyBuffer[1] = LOBYTE(Lo);
|
|
SmartcardExtension->IoRequest.ReplyBuffer[2] = HIBYTE(Lo);
|
|
memcpy((SmartcardExtension->IoRequest.ReplyBuffer)+3,Vo,Lo);
|
|
|
|
*(SmartcardExtension->IoRequest.Information) = (DWORD) (Lo + 3);
|
|
setIdle(pReader);
|
|
return(STATUS_SUCCESS);
|
|
}
|
|
//
|
|
// For IOCTL_SMARTCARD_VENDOR_SWITCH_SPEED
|
|
// Call the SwitchSpeed function
|
|
//
|
|
case IOCTL_SMARTCARD_VENDOR_SWITCH_SPEED:
|
|
lStatus = SwitchSpeed(
|
|
SmartcardExtension,
|
|
(ULONG) SmartcardExtension->IoRequest.RequestBufferLength,
|
|
(PUCHAR) SmartcardExtension->IoRequest.RequestBuffer,
|
|
(ULONG) SmartcardExtension->IoRequest.ReplyBufferLength,
|
|
(PUCHAR) SmartcardExtension->IoRequest.ReplyBuffer,
|
|
(PULONG) SmartcardExtension->IoRequest.Information
|
|
);
|
|
break;
|
|
|
|
default:
|
|
setIdle(pReader);
|
|
return STATUS_NOT_SUPPORTED;
|
|
}
|
|
setIdle(pReader);
|
|
return lStatus;
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS GprCbSetupCardTracking(
|
|
PSMARTCARD_EXTENSION SmartcardExtension
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is called by the Smart card library when an
|
|
IOCTL_SMARTCARD_IS_PRESENT or IOCTL_SMARTCARD_IS_ABSENT occurs.
|
|
|
|
Arguments:
|
|
|
|
SmartcardExtension - is a pointer on the SmartCardExtension structure of
|
|
the current device.
|
|
|
|
Return Value:
|
|
|
|
STATUS_PENDING - The request is in a pending mode.
|
|
|
|
--*/
|
|
{
|
|
|
|
NTSTATUS NTStatus = STATUS_PENDING;
|
|
POS_DEP_DATA pOS = NULL;
|
|
KIRQL oldIrql;
|
|
|
|
ASSERT(SmartcardExtension != NULL);
|
|
|
|
//
|
|
//Initialize
|
|
//
|
|
pOS = SmartcardExtension->OsData;
|
|
|
|
//
|
|
//Set cancel routine for the notification IRP.
|
|
//
|
|
IoAcquireCancelSpinLock(&oldIrql);
|
|
|
|
IoSetCancelRoutine(
|
|
pOS->NotificationIrp,
|
|
GprCancelEventWait
|
|
);
|
|
|
|
IoReleaseCancelSpinLock(oldIrql);
|
|
|
|
NTStatus = STATUS_PENDING;
|
|
|
|
return (NTStatus);
|
|
|
|
}
|