windows-nt/Source/XPSP1/NT/drivers/smartcrd/gcr410p/gioctl0a.c
2020-09-26 16:20:57 +08:00

2164 lines
65 KiB
C

/*++
Copyright (c) 1998 Gemplus Development
Name:
GIOCTL0A.C (Gemplus IOCTL Smart card Reader module 0A)
Description:
This module holds the IOCTL functions for a smart card reader driver
in compliance with PC/SC.
Environment:
Kernel mode
Revision History :
dd/mm/yy
13/03/98: V1.00.001 (GPZ)
- Start of development.
26/04/98: V1.00.002 (GPZ)
- Add the RestoreCommunication function for the Power Management.
18/06/98: V1.00.003 (GPZ)
- Send a classic PowerUp command (0x12 only) for a Warm reset
in case of the Transparent protocol is selected.
- The functions which use KeAcquireSpinLock/KeAcquireCancelSpinlock
must be NOT PAGEABLE.
28/08/98: V1.00.004 (GPZ)
- Check the size of the output buffers before a RtlCopyMemory.
22/01/99: V1.00.005 (YN)
- Change the way to increase com port speed
--*/
#include "gntscr.h"
#include "gntser.h"
#include "gntscr0a.h"
//#pragma alloc_text(PAGEABLE, GDDK_0ASetProtocol)
//#pragma alloc_text(PAGEABLE, GDDK_0ATransmit)
//#pragma alloc_text(PAGEABLE, GDDK_0AVendorIoctl)
//
// Static functions declaration section:
//
static void GDDK_0ASetTransparentConfig(PSMARTCARD_EXTENSION,BYTE);
//
// Static variables declaration section:
// - dataRatesSupported: holds all the supported data rates.
//
static ULONG
dataRatesSupported[] = {
9909, 13212, 14400, 15855,
19200, 19819, 26425, 28800,
31710, 38400, 39638, 52851,
57600, 76800, 79277, 105703,
115200, 158554
};
NTSTATUS
GDDK_0AReaderPower(
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.
Return Value:
STATUS_SUCCESS - We could execute the request.
STATUS_NOT_SUPPORTED - We could not support the minor Ioctl.
--*/
{
NTSTATUS status;
BYTE cmd[5],rbuff[HOR3GLL_BUFFER_SIZE];
USHORT rlen;
KIRQL irql;
READER_EXTENSION
*param = SmartcardExtension->ReaderExtension;
SmartcardDebug(
DEBUG_IOCTL,
("%s!GDDK_0AReaderPower: Enter\n",
SC_DRIVER_NAME)
);
//
// Since power down triggers the UpdateSerialStatus function, we have
// to inform it that we forced the change of the status and not the user
// (who might have removed and inserted a card)
//
SmartcardExtension->ReaderExtension->PowerRequest = TRUE;
// Lock the mutex to avoid a call of an other command.
GDDK_0ALockExchange(SmartcardExtension);
switch(SmartcardExtension->MinorIoControlCode) {
case SCARD_POWER_DOWN:
SmartcardDebug(
DEBUG_IOCTL,
("%s!GDDK_0AReaderPower: SCARD_POWER_DOWN\n",
SC_DRIVER_NAME)
);
//
// ICC is powered Down
//
rlen = HOR3GLL_BUFFER_SIZE;
cmd[0] = HOR3GLL_IFD_CMD_ICC_POWER_DOWN;
status = GDDK_Oros3Exchange(
param->Handle,
HOR3GLL_LOW_TIME,
1,
cmd,
&rlen,
rbuff
);
if (status == STATUS_SUCCESS) {
status = GDDK_Translate(rbuff[0],RDF_CARD_POWER);
}
//
// Set the card CurrentState
//
SmartcardExtension->CardCapabilities.Protocol.Selected =
SCARD_PROTOCOL_UNDEFINED;
SmartcardExtension->CardCapabilities.ATR.Length = 0;
rlen = HOR3GLL_BUFFER_SIZE;
cmd[0] = HOR3GLL_IFD_CMD_ICC_STATUS;
status = GDDK_Oros3Exchange(
param->Handle,
HOR3GLL_LOW_TIME,
1,
cmd,
&rlen,
rbuff
);
if (status == STATUS_SUCCESS) {
status = GDDK_Translate(rbuff[0],0);
}
if (status == STATUS_SUCCESS) {
KeAcquireSpinLock(
&SmartcardExtension->OsData->SpinLock,
&irql
);
if ((rbuff[1] & 0x04) == 0) {
SmartcardExtension->ReaderCapabilities.CurrentState =
SCARD_ABSENT;
} else if ((rbuff[1] & 0x02) == 0) {
SmartcardExtension->ReaderCapabilities.CurrentState =
SCARD_SWALLOWED;
}
KeReleaseSpinLock(
&SmartcardExtension->OsData->SpinLock,
irql
);
}
break;
case SCARD_COLD_RESET:
case SCARD_WARM_RESET:
SmartcardDebug(
DEBUG_IOCTL,
("%s!GDDK_0AReaderPower: SCARD_COLD_RESET or SCARD_WARM_RESET\n",
SC_DRIVER_NAME)
);
status = GDDK_0AIccReset(
SmartcardExtension,
SmartcardExtension->MinorIoControlCode
);
if (status == STATUS_SUCCESS) {
//
// Check if we have a reply buffer.
// smclib makes sure that it is big enough
// if there is a buffer
//
if (SmartcardExtension->IoRequest.ReplyBuffer) {
RtlCopyMemory(
SmartcardExtension->IoRequest.ReplyBuffer,
SmartcardExtension->CardCapabilities.ATR.Buffer,
SmartcardExtension->CardCapabilities.ATR.Length
);
*SmartcardExtension->IoRequest.Information =
SmartcardExtension->CardCapabilities.ATR.Length;
} else {
status = STATUS_BUFFER_TOO_SMALL;
}
}
break;
default:
SmartcardDebug(
DEBUG_ERROR,
("%s!GDDK_0AReaderPower: Minor IOCTL not supported!\n",
SC_DRIVER_NAME)
);
status = STATUS_NOT_SUPPORTED;
}
SmartcardExtension->ReaderExtension->PowerRequest = FALSE;
SmartcardDebug(
DEBUG_IOCTL,
("%s!GDDK_0AReaderPower: Exit=%X(hex)\n",
SC_DRIVER_NAME,
status)
);
// Unlock the mutex.
GDDK_0AUnlockExchange(SmartcardExtension);
return (status);
}
NTSTATUS
GDDK_0AIccReset(
PSMARTCARD_EXTENSION SmartcardExtension,
ULONG ResetType
)
/*++
Routine Description:
This function provides 2 differents functionnality
- Cold reset (SCARD_COLD_RESET),
- Warm reset (SCARD_WARM_RESET),
Arguments:
SmartcardExtension - is a pointer on the SmartCardExtension structure of
the current device.
ResetType - type of the reset (SCARD_COLD_RESET or SCARD_WARM_RESET)
Return Value:
STATUS_SUCCESS - We could execute the request.
STATUS_NOT_SUPPORTED - We could not support the minor Ioctl.
--*/
{
NTSTATUS status;
BYTE cmd[5],
rbuff[HOR3GLL_BUFFER_SIZE];
USHORT rlen;
KEVENT event;
LARGE_INTEGER timeout;
READER_EXTENSION *param = SmartcardExtension->ReaderExtension;
SmartcardExtension->ReaderExtension->IccConfig.PTSMode = IFD_WITHOUT_PTS_REQUEST;
switch(ResetType) {
case SCARD_COLD_RESET:
if (param->IccConfig.ICCType != ISOCARD) {
//
// Defines the type of the card (ISOCARD) and set the card presence
//
param->IccConfig.ICCType = ISOCARD;
rlen = HOR3GLL_BUFFER_SIZE;
cmd[0] = HOR3GLL_IFD_CMD_ICC_DEFINE_TYPE;
cmd[1] = (BYTE) param->IccConfig.ICCType;
cmd[2] = (BYTE) param->IccConfig.ICCVpp;
cmd[3] = (BYTE) param->IccConfig.ICCPresence;
status = GDDK_Oros3Exchange(
param->Handle,
HOR3GLL_LOW_TIME,
4,
cmd,
&rlen,
rbuff
);
if (status == STATUS_SUCCESS) {
status = GDDK_Translate(rbuff[0],RDF_CARD_POWER);
}
if (status != STATUS_SUCCESS) {
return(status);
}
}
//
// ICC is powered Down
//
rlen = HOR3GLL_BUFFER_SIZE;
cmd[0] = HOR3GLL_IFD_CMD_ICC_POWER_DOWN;
status = GDDK_Oros3Exchange(
param->Handle,
HOR3GLL_LOW_TIME,
1,
cmd,
&rlen,
rbuff
);
if (status == STATUS_SUCCESS) {
status = GDDK_Translate(rbuff[0],RDF_CARD_POWER);
}
if (status != STATUS_SUCCESS) {
return(status);
}
if (param->PowerTimeOut) {
//
// Waits for the Power Timeout to be elapsed.
//
KeInitializeEvent(&event,NotificationEvent,FALSE);
timeout.QuadPart = -((LONGLONG) param->PowerTimeOut * 10 * 1000);
KeWaitForSingleObject(&event,
Suspended,
KernelMode,
FALSE,
&timeout);
}
case SCARD_WARM_RESET:
//
// ICC is powered up (GDDK_Oros3IccPowerUp).
//
rlen = HOR3GLL_BUFFER_SIZE;
if (param->IccConfig.ICCType == TRANSPARENT_PROTOCOL) {
status = GDDK_Oros3IccPowerUp(
param->Handle,
param->CmdTimeOut,
0xFF,
IFD_DEFAULT_MODE,
0,
0,
0,
0,
&rlen,
rbuff
);
} else {
status = GDDK_Oros3IccPowerUp(
param->Handle,
param->CmdTimeOut,
param->IccConfig.ICCVcc,
param->IccConfig.PTSMode,
param->IccConfig.PTS0,
param->IccConfig.PTS1,
param->IccConfig.PTS2,
param->IccConfig.PTS3,
&rlen,
rbuff
);
}
if (status == STATUS_SUCCESS) {
status = GDDK_Translate(rbuff[0],RDF_CARD_POWER);
}
if (status != STATUS_SUCCESS) {
return(status);
}
//
// Copy ATR to smart card struct (remove the reader status byte)
// The lib needs the ATR for evaluation of the card parameters
//
if (
(SmartcardExtension->SmartcardReply.BufferSize >= (ULONG) (rlen - 1))
&&
(sizeof(SmartcardExtension->CardCapabilities.ATR.Buffer) >= (ULONG)(rlen - 1))
) {
RtlCopyMemory(
SmartcardExtension->SmartcardReply.Buffer,
rbuff + 1,
rlen - 1
);
SmartcardExtension->SmartcardReply.BufferLength = (ULONG) (rlen - 1);
RtlCopyMemory(
SmartcardExtension->CardCapabilities.ATR.Buffer,
SmartcardExtension->SmartcardReply.Buffer,
SmartcardExtension->SmartcardReply.BufferLength
);
SmartcardExtension->CardCapabilities.ATR.Length =
(UCHAR) SmartcardExtension->SmartcardReply.BufferLength;
SmartcardExtension->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
//
status = SmartcardUpdateCardCapabilities(SmartcardExtension);
} else {
status = STATUS_BUFFER_TOO_SMALL;
}
break;
default:
status = STATUS_NOT_SUPPORTED;
}
return (status);
}
NTSTATUS
GDDK_0ASetProtocol(
PSMARTCARD_EXTENSION SmartcardExtension
)
/*++
Routine Description:
The smart card lib requires to have this function. It is called
to set a the transmission protocol and parameters. If this function
is called with a protocol mask (which means the caller doesn't card
about a particular protocol to be set) we first look if we can
set T=1 and the T=0
Arguments:
SmartcardExtension - is a pointer on the SmartCardExtension structure of
the current device.
Return Value:
STATUS_SUCCESS - We could execute the request.
STATUS_DEVICE_PROTOCOL_ERROR - We could not support the protocol requested.
--*/
{
NTSTATUS status;
BYTE rbuff[HOR3GLL_BUFFER_SIZE];
USHORT rlen;
READER_EXTENSION *param = SmartcardExtension->ReaderExtension;
PSERIAL_READER_CONFIG serialConfigData =
&SmartcardExtension->ReaderExtension->SerialConfigData;
PAGED_CODE();
SmartcardDebug(
DEBUG_TRACE,
("%s!GDDK_0ASetProtocol: Enter\n",
SC_DRIVER_NAME)
);
// Lock the mutex to avoid a call of an other command.
GDDK_0ALockExchange(SmartcardExtension);
__try {
//
// 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.
//
if (SmartcardExtension->ReaderCapabilities.CurrentState == SCARD_SPECIFIC &&
(SmartcardExtension->CardCapabilities.Protocol.Selected &
SmartcardExtension->MinorIoControlCode)
) {
status = STATUS_SUCCESS;
__leave;
}
while(TRUE) {
//
// Select T=1 or T=0 and indicate that pts1 follows
//
if ( SmartcardExtension->CardCapabilities.Protocol.Supported &
SmartcardExtension->MinorIoControlCode &
SCARD_PROTOCOL_T1
) {
SmartcardExtension->ReaderExtension->IccConfig.PTS0 = IFD_NEGOTIATE_T1 | IFD_NEGOTIATE_PTS1;
SmartcardExtension->CardCapabilities.Protocol.Selected = SCARD_PROTOCOL_T1;
} else if ( SmartcardExtension->CardCapabilities.Protocol.Supported &
SmartcardExtension->MinorIoControlCode &
SCARD_PROTOCOL_T0
) {
SmartcardExtension->ReaderExtension->IccConfig.PTS0 = IFD_NEGOTIATE_T0 | IFD_NEGOTIATE_PTS1;
SmartcardExtension->CardCapabilities.Protocol.Selected = SCARD_PROTOCOL_T0;
} else {
status = STATUS_INVALID_DEVICE_REQUEST;
__leave;
}
//
// Set pts1 which codes Fl and Dl
//
SmartcardExtension->ReaderExtension->IccConfig.PTS1 =
SmartcardExtension->CardCapabilities.PtsData.Fl << 4 |
SmartcardExtension->CardCapabilities.PtsData.Dl;
param->IccConfig.PTSMode = IFD_NEGOTIATE_PTS_MANUALLY;
rlen = HOR3GLL_BUFFER_SIZE;
status = GDDK_Oros3IccPowerUp(
param->Handle,
param->CmdTimeOut,
param->IccConfig.ICCVcc,
param->IccConfig.PTSMode,
param->IccConfig.PTS0,
param->IccConfig.PTS1,
param->IccConfig.PTS2,
param->IccConfig.PTS3,
&rlen,
rbuff
);
if (status == STATUS_SUCCESS) {
status = GDDK_Translate(rbuff[0],RDF_CARD_POWER);
}
if (status == STATUS_SUCCESS ) {
//The card replied correctly to our pts-request
SmartcardDebug(
DEBUG_TRACE,
("%s!GDDK_0ASetProtocol: PTS Request OK\n",
SC_DRIVER_NAME)
);
break;
} else if (SmartcardExtension->CardCapabilities.PtsData.Type !=
PTS_TYPE_DEFAULT
) {
SmartcardDebug(
DEBUG_TRACE,
("%s!GDDK_0ASetProtocol: PTS failed. Trying default parameters...\n",
SC_DRIVER_NAME)
);
//
// The card did either NOT reply or it replied incorrectly
// so try default values.
// Set PtsData Type to Default and do a cold reset
//
SmartcardExtension->CardCapabilities.PtsData.Type =
PTS_TYPE_DEFAULT;
status = GDDK_0AIccReset(SmartcardExtension,SCARD_COLD_RESET);
continue;
}
//
// The card failed the pts-request
//
status = STATUS_DEVICE_PROTOCOL_ERROR;
__leave;
} //End of the while
//
// The card replied correctly to the pts request
// Set the appropriate parameters for the port
//
if ( SmartcardExtension->CardCapabilities.Protocol.Selected &
SCARD_PROTOCOL_T1
) {
serialConfigData->Timeouts.ReadIntervalTimeout = 10 +
SmartcardExtension->CardCapabilities.T1.CWT / 1000;
}
else if ( SmartcardExtension->CardCapabilities.Protocol.Selected &
SCARD_PROTOCOL_T0
) {
serialConfigData->Timeouts.ReadIntervalTimeout = 10 +
SmartcardExtension->CardCapabilities.T0.WT / 1000;
}
//
// Now indicate that we're in specific mode
// and return the selected protocol to the caller
//
SmartcardExtension->ReaderCapabilities.CurrentState = SCARD_SPECIFIC;
*(PULONG) SmartcardExtension->IoRequest.ReplyBuffer =
SmartcardExtension->CardCapabilities.Protocol.Selected;
*SmartcardExtension->IoRequest.Information =
sizeof(SmartcardExtension->CardCapabilities.Protocol.Selected);
}
__finally
{
if (status != STATUS_SUCCESS) {
SmartcardExtension->CardCapabilities.Protocol.Selected =
SCARD_PROTOCOL_UNDEFINED;
*SmartcardExtension->IoRequest.Information = 0;
}
}
SmartcardDebug(
DEBUG_TRACE,
("%s!GDDK_0ASetProtocol: Exit=%lX(hex)\n",
SC_DRIVER_NAME,
status)
);
// Unlock the mutex.
GDDK_0AUnlockExchange(SmartcardExtension);
return status;
}
NTSTATUS
GDDK_0ATransmit(
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.
Return Value:
STATUS_SUCCESS - We could execute the request.
STATUS_INVALID_DEVICE_STATE - If the protocol specified is different from
the protocol selected
STATUS_INVALID_DEVICE_REQUEST - We could not support the protocol specified.
--*/
{
NTSTATUS status;
PUCHAR requestBuffer = SmartcardExtension->SmartcardRequest.Buffer,
replyBuffer = SmartcardExtension->SmartcardReply.Buffer;
PULONG requestLength = &SmartcardExtension->SmartcardRequest.BufferLength;
PSCARD_IO_REQUEST scardIoRequest = (PSCARD_IO_REQUEST)
SmartcardExtension->OsData->CurrentIrp->AssociatedIrp.SystemBuffer;
READER_EXTENSION *param = SmartcardExtension->ReaderExtension;
USHORT rlen,
rlenCmd;
BYTE cmd[5],
rbuff[HOR3GLL_BUFFER_SIZE],
rbuffCmd[HOR3GLL_BUFFER_SIZE];
ULONG t1Timeout;
PAGED_CODE();
SmartcardDebug(
DEBUG_IOCTL,
("%s!GDDK_0ATransmit: Enter\n",
SC_DRIVER_NAME)
);
//Set the reply buffer length to 0.
*SmartcardExtension->IoRequest.Information = 0;
status = STATUS_SUCCESS;
//
// Verify if the protocol specified is the same than the protocol selected.
//
*requestLength = 0;
if (SmartcardExtension->CardCapabilities.Protocol.Selected !=
scardIoRequest->dwProtocol) {
return (STATUS_INVALID_DEVICE_STATE);
}
// Lock the mutex to avoid a call of an other command.
GDDK_0ALockExchange(SmartcardExtension);
switch (SmartcardExtension->CardCapabilities.Protocol.Selected) {
// For RAW protocol we return STATUS_INVALID_DEVICE_STATE
case SCARD_PROTOCOL_RAW:
status = STATUS_INVALID_DEVICE_STATE;
break;
//
// T=0 PROTOCOL:
// Call the SmartCardT0Request which updates the SmartcardRequest struct.
//
case SCARD_PROTOCOL_T0:
SmartcardExtension->SmartcardRequest.BufferLength = 0;
status = SmartcardT0Request(SmartcardExtension);
if (status == STATUS_SUCCESS) {
rlen = HOR3GLL_BUFFER_SIZE;
//
// If the length LEx > 0
// Then
// Is an ISO Out command.
// If LEx > SC_IFD_T0_MAXIMUM_LEX (256) we return STATUS_BUFFER_TOO_SMALL
// Call the GDDK_Oros3IsoOutput
//
if (SmartcardExtension->T0.Le > 0) {
if (SmartcardExtension->T0.Le > SC_IFD_T0_MAXIMUM_LEX) {
status = STATUS_BUFFER_TOO_SMALL;
}
if (status == STATUS_SUCCESS) {
status = GDDK_Oros3IsoOutput(
param->Handle,
param->APDUTimeOut,
HOR3GLL_IFD_CMD_ICC_ISO_OUT,
(BYTE *)SmartcardExtension->SmartcardRequest.Buffer,
&rlen,
rbuff
);
}
} else {
//
// Else Is an ISO In command.
// If LC > SC_IFD_T0_MAXIMUM_LC (255) we return STATUS_BUFFER_TOO_SMALL
// Call the GDDK_Oros3IsoInput
//
if (SmartcardExtension->T0.Lc > SC_IFD_T0_MAXIMUM_LC) {
status = STATUS_BUFFER_TOO_SMALL;
}
if (status == STATUS_SUCCESS) {
status = GDDK_Oros3IsoInput(
param->Handle,
param->APDUTimeOut,
HOR3GLL_IFD_CMD_ICC_ISO_IN,
(BYTE *)SmartcardExtension->SmartcardRequest.Buffer,
(BYTE *)SmartcardExtension->SmartcardRequest.Buffer + 5,
&rlen,
rbuff
);
}
}
}
if (status == STATUS_SUCCESS) {
status = GDDK_Translate(rbuff[0],RDF_TRANSMIT);
}
//
// If the Status is Success
// Copy the response in the SmartcardReply buffer. Remove the status
// of the reader.
// Call the SmartcardT0reply function to update the IORequest struct.
//
if (status == STATUS_SUCCESS){
ASSERT(SmartcardExtension->SmartcardReply.BufferSize >= (ULONG) (rlen - 1));
RtlCopyMemory(
SmartcardExtension->SmartcardReply.Buffer,
rbuff + 1,
rlen - 1
);
SmartcardExtension->SmartcardReply.BufferLength = (ULONG) (rlen - 1);
status = SmartcardT0Reply(SmartcardExtension);
}
break;
//
// T=1 PROTOCOL:
//
case SCARD_PROTOCOL_T1:
//
// If the current card type <> TRANSPARENT_PROTOCOL,
//
if (param->IccConfig.ICCType != TRANSPARENT_PROTOCOL) {
// We read the status of the card to known the current voltage and the TA1
rlenCmd = HOR3GLL_BUFFER_SIZE;
cmd[0] = HOR3GLL_IFD_CMD_ICC_STATUS;
status = GDDK_Oros3Exchange(
param->Handle,
HOR3GLL_LOW_TIME,
1,
cmd,
&rlenCmd,
rbuffCmd
);
param->TransparentConfig.CFG = rbuffCmd[1] & 0x01; //Vcc
param->TransparentConfig.Fi = rbuffCmd[3] >>4; //Fi
param->TransparentConfig.Di = 0x0F & rbuffCmd[3]; //Di
//We define the type of the card.
rlenCmd = HOR3GLL_BUFFER_SIZE;
param->IccConfig.ICCType = TRANSPARENT_PROTOCOL;
cmd[0] = HOR3GLL_IFD_CMD_ICC_DEFINE_TYPE;
cmd[1] = (BYTE) param->IccConfig.ICCType;
cmd[2] = (BYTE) param->IccConfig.ICCVpp;
cmd[3] = (BYTE) param->IccConfig.ICCPresence ;
status = GDDK_Oros3Exchange(
param->Handle,
HOR3GLL_LOW_TIME,
4,
cmd,
&rlenCmd,
rbuffCmd
);
if (status == STATUS_SUCCESS) {
status = GDDK_Translate(rbuffCmd[0],RDF_TRANSMIT);
}
if (status != STATUS_SUCCESS) {
break;
}
// Set the transparent configuration
GDDK_0ASetTransparentConfig(SmartcardExtension,SmartcardExtension->T1.Wtx);
}
//
// Loop for the T=1 management
//
do {
PULONG requestLength = &SmartcardExtension->SmartcardRequest.BufferLength;
// Tell the lib function how many bytes I need for the prologue
//
*requestLength = 0;
status = SmartcardT1Request(SmartcardExtension);
if (status != STATUS_SUCCESS) {
break;
}
if (SmartcardExtension->T1.Wtx) {
// Compute the timeout for the Oros3Exchange (WTX * BWT)
t1Timeout = SmartcardExtension->CardCapabilities.T1.BWT / 1000;
t1Timeout *= SmartcardExtension->T1.Wtx;
t1Timeout += 500;
GDDK_0ASetTransparentConfig(SmartcardExtension,SmartcardExtension->T1.Wtx);
} else {
t1Timeout = SmartcardExtension->CardCapabilities.T1.BWT / 1000;
t1Timeout += 500;
}
SER_SetPortTimeout(param->Handle, t1Timeout);
rlen = HOR3GLL_BUFFER_SIZE;
status = GDDK_Oros3TransparentExchange(
param->Handle,
t1Timeout,
(USHORT) SmartcardExtension->SmartcardRequest.BufferLength,
SmartcardExtension->SmartcardRequest.Buffer,
&rlen,
rbuff
);
if (status == STATUS_SUCCESS) {
status = GDDK_Translate(rbuff[0],RDF_TRANSMIT);
}
if (status != STATUS_SUCCESS) {
rlen = 1;
}
if (SmartcardExtension->T1.Wtx) {
// Set the reader BWI to the default value
GDDK_0ASetTransparentConfig(SmartcardExtension,0);
}
// Copy the response in the reply buffer
if (SmartcardExtension->SmartcardReply.BufferSize >= (ULONG) (rlen -1)) {
SmartcardExtension->SmartcardReply.BufferLength = (ULONG) (rlen - 1);
if (SmartcardExtension->SmartcardReply.BufferLength > 0) {
RtlCopyMemory(
SmartcardExtension->SmartcardReply.Buffer,
rbuff + 1,
rlen - 1
);
}
}
status = SmartcardT1Reply(SmartcardExtension);
} while (status == STATUS_MORE_PROCESSING_REQUIRED);
break;
default:
status = STATUS_INVALID_DEVICE_REQUEST;
break;
}
SER_SetPortTimeout(param->Handle, HOR3COMM_CHAR_TIMEOUT);
// Unlock the mutex.
GDDK_0AUnlockExchange(SmartcardExtension);
SmartcardDebug(
DEBUG_IOCTL,
("%s!GDDK_0ATransmit: Exit=%X(hex)\n",
SC_DRIVER_NAME,
status)
);
if (status != STATUS_SUCCESS) {
SmartcardDebug(
DEBUG_ERROR,
("%s!GDDK_0ATransmit: failed! status=%X(hex)\n",
SC_DRIVER_NAME,
status)
);
}
return (status);
}
NTSTATUS
GDDK_0ACardTracking(
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.
--*/
{
KIRQL oldIrql;
//
// Set cancel routine for the notification irp
//
IoAcquireCancelSpinLock(&oldIrql);
IoSetCancelRoutine(
SmartcardExtension->OsData->NotificationIrp,
GCR410PCancel
);
IoReleaseCancelSpinLock(oldIrql);
return STATUS_PENDING;
}
NTSTATUS
GDDK_0AVendorIoctl(
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.
--*/
{
NTSTATUS status = STATUS_SUCCESS;
READER_EXTENSION *param = SmartcardExtension->ReaderExtension;
USHORT rlen;
BYTE rbuff[HOR3GLL_BUFFER_SIZE];
PAGED_CODE();
ASSERT(SmartcardExtension != NULL);
SmartcardDebug(
DEBUG_IOCTL,
("%s!GDDK_0AVendorIoctl: Enter, IoControlCode=%lX(hex)\n",
SC_DRIVER_NAME,
SmartcardExtension->MajorIoControlCode)
);
// Lock the mutex to avoid a call of an other command.
GDDK_0ALockExchange(SmartcardExtension);
// Set the reply buffer length to 0.
*SmartcardExtension->IoRequest.Information = 0;
switch(SmartcardExtension->MajorIoControlCode) {
//
// For IOCTL_SMARTCARD_VENDOR_GET_ATTRIBUTE and IOCTL_VENDOR_SMARTCARD_SET_ATTRIBUTE
// Call the GDDK_0AVendorTag function
//
case IOCTL_SMARTCARD_VENDOR_GET_ATTRIBUTE:
case IOCTL_SMARTCARD_VENDOR_SET_ATTRIBUTE:
status = GDDK_0AVendorTag(
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;
//
// For IOCTL_SMARTCARD_VENDOR_IFD_EXCHANGE
// Send the command to the reader
//
case IOCTL_SMARTCARD_VENDOR_IFD_EXCHANGE:
rlen = (USHORT) HOR3GLL_BUFFER_SIZE;
status = GDDK_Oros3Exchange(
param->Handle,
HOR3GLL_LOW_TIME,
(USHORT) SmartcardExtension->IoRequest.RequestBufferLength,
(BYTE *) SmartcardExtension->IoRequest.RequestBuffer,
&rlen,
rbuff
);
if (status != STATUS_SUCCESS) {
break;
}
if (SmartcardExtension->IoRequest.ReplyBufferLength < (ULONG) rlen) {
status = STATUS_BUFFER_TOO_SMALL;
break;
}
RtlCopyMemory(
SmartcardExtension->IoRequest.ReplyBuffer,
rbuff,
rlen
);
*(SmartcardExtension->IoRequest.Information) = (ULONG) rlen;
status = STATUS_SUCCESS;
break;
default:
status = STATUS_NOT_SUPPORTED;
break;
}
// Unlock the mutex.
GDDK_0AUnlockExchange(SmartcardExtension);
SmartcardDebug(
DEBUG_IOCTL,
("%s!GDDK_0AVendorIoctl: Exit=%X(hex)\n",
SC_DRIVER_NAME,
status)
);
return status;
}
NTSTATUS
GDDK_0AVendorTag(
PSMARTCARD_EXTENSION SmartcardExtension,
ULONG IoControlCode,
ULONG BufferInLen,
PUCHAR BufferIn,
ULONG BufferOutLen,
PUCHAR BufferOut,
PULONG 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.
BufferInLen - holds the length of the input data.
BufferIn - holds the input data.
BufferOutLen - holds the size of the output buffer.
BufferOut - the output buffer.
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.
--*/
{
ULONG TagValue;
PREADER_EXTENSION pReaderExtension = SmartcardExtension->ReaderExtension;
ASSERT(pReaderExtension != NULL);
// Set the reply buffer length to 0.
*LengthOut = 0l;
// Verify the length of the Tag
if (BufferInLen < 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) {
// Get an attribute
case IOCTL_SMARTCARD_VENDOR_GET_ATTRIBUTE:
switch (TagValue) {
// Baud rate of the reader (SCARD_ATTR_SPEC_BAUD_RATE)
case SCARD_ATTR_SPEC_BAUD_RATE:
if (BufferOutLen < (ULONG) sizeof(pReaderExtension->IFDBaudRate)) {
return(STATUS_BUFFER_TOO_SMALL);
}
RtlCopyMemory(
BufferOut,
&pReaderExtension->IFDBaudRate,
sizeof(pReaderExtension->IFDBaudRate)
);
*(LengthOut) = (ULONG) sizeof(pReaderExtension->IFDBaudRate);
return (STATUS_SUCCESS);
break;
// Power Timeout (SCARD_ATTR_SPEC_POWER_TIMEOUT)
case SCARD_ATTR_SPEC_POWER_TIMEOUT:
if (BufferOutLen < (ULONG) sizeof(pReaderExtension->PowerTimeOut)) {
return(STATUS_BUFFER_TOO_SMALL);
}
RtlCopyMemory(
BufferOut,
&pReaderExtension->PowerTimeOut,
sizeof(pReaderExtension->PowerTimeOut)
);
*(LengthOut) = (ULONG) sizeof(pReaderExtension->PowerTimeOut);
return STATUS_SUCCESS;
break;
// Command Timeout (SCARD_ATTR_SPEC_CMD_TIMEOUT)
case SCARD_ATTR_SPEC_CMD_TIMEOUT:
if (BufferOutLen < (ULONG) sizeof(pReaderExtension->CmdTimeOut)) {
return(STATUS_BUFFER_TOO_SMALL);
}
RtlCopyMemory(
BufferOut,
&pReaderExtension->CmdTimeOut,
sizeof(pReaderExtension->CmdTimeOut)
);
*(LengthOut) = (ULONG) sizeof(pReaderExtension->CmdTimeOut);
return STATUS_SUCCESS;
break;
// APDU Timeout (SCARD_ATTR_SPEC_APDU_TIMEOUT)
case SCARD_ATTR_SPEC_APDU_TIMEOUT:
if (BufferOutLen < (ULONG) sizeof(pReaderExtension->APDUTimeOut)) {
return(STATUS_BUFFER_TOO_SMALL);
}
RtlCopyMemory(
BufferOut,
&pReaderExtension->APDUTimeOut,
sizeof(pReaderExtension->APDUTimeOut)
);
*(LengthOut) = (ULONG) sizeof(pReaderExtension->APDUTimeOut);
return STATUS_SUCCESS;
break;
// Unknown tag, we return STATUS_NOT_SUPPORTED
default:
return STATUS_NOT_SUPPORTED;
break;
}
break;
// Set the value of one tag (IOCTL_SMARTCARD_VENDOR_SET_ATTRIBUTE)
case IOCTL_SMARTCARD_VENDOR_SET_ATTRIBUTE:
switch (TagValue) {
// Power Timeout (SCARD_ATTR_SPEC_POWER_TIMEOUT)
case SCARD_ATTR_SPEC_POWER_TIMEOUT:
if (BufferInLen <(ULONG) (sizeof(pReaderExtension->PowerTimeOut) + sizeof(TagValue))) {
return(STATUS_BUFFER_TOO_SMALL);
}
RtlCopyMemory(
&pReaderExtension->PowerTimeOut,
BufferIn + sizeof(TagValue),
sizeof(pReaderExtension->PowerTimeOut)
);
return STATUS_SUCCESS;
break;
// Command Timeout (SCARD_ATTR_SPEC_CMD_TIMEOUT)
case SCARD_ATTR_SPEC_CMD_TIMEOUT:
if (BufferInLen <(ULONG) (sizeof(pReaderExtension->CmdTimeOut) + sizeof(TagValue))) {
return(STATUS_BUFFER_TOO_SMALL);
}
RtlCopyMemory(
&pReaderExtension->CmdTimeOut,
BufferIn + sizeof(TagValue),
sizeof(pReaderExtension->CmdTimeOut)
);
return STATUS_SUCCESS;
break;
// Command Timeout (SCARD_ATTR_SPEC_APDU_TIMEOUT)
case SCARD_ATTR_SPEC_APDU_TIMEOUT:
if (BufferInLen <(ULONG) (sizeof(pReaderExtension->APDUTimeOut) + sizeof(TagValue))) {
return(STATUS_BUFFER_TOO_SMALL);
}
RtlCopyMemory(
&pReaderExtension->APDUTimeOut,
BufferIn + sizeof(TagValue),
sizeof(pReaderExtension->APDUTimeOut)
);
return STATUS_SUCCESS;
break;
// Unknown tag, we return STATUS_NOT_SUPPORTED
default:
return STATUS_NOT_SUPPORTED;
}
break;
default:
return STATUS_NOT_SUPPORTED;
break;
}
}
NTSTATUS
GDDK_0AOpenChannel(
PSMARTCARD_EXTENSION SmartcardExtension,
CONST ULONG DeviceNumber,
CONST ULONG PortSerialNumber,
CONST ULONG MaximalBaudRate
)
/*++
Routine Description:
This routine try to establish a connection with a reader, and after
update the characteristic of this reader.
Arguments:
SmartcardExtension - is a pointer on the SmartCardExtension structure of
the current device.
DeviceNumber - holds the current device number (0 to MAX_DEVICES).
PortSerialNumber - holds the port serial number (0 to HGTSER_MAX_PORT).
MaximalBaudRate - holds the maximal speed specified for the reader.
Return Value:
STATUS_SUCCESS - We could execute the request.
--*/
{
NTSTATUS status = STATUS_SUCCESS;
short handle,portcom;
char os_string[HOR3GLL_OS_STRING_SIZE];
USHORT os_length = HOR3GLL_OS_STRING_SIZE;
USHORT user;
TGTSER_PORT comm;
ULONG br;
BYTE minorVersion,majorVersion;
COM_SERIAL serial_channel;
USHORT rlen;
BYTE cmd[5],rbuff[HOR3GLL_BUFFER_SIZE];
LARGE_INTEGER timeout;
// Update the serial communication channel information:
serial_channel.Port = PortSerialNumber + G_COM1;
serial_channel.BaudRate = MaximalBaudRate;
serial_channel.pSmartcardExtension = SmartcardExtension;
// Initializes a mutex object (in a high level) for the exchange commands with
// the smart card reader.
KeInitializeMutex(
&SmartcardExtension->ReaderExtension->ExchangeMutex,
3
);
// Initializes a mutex object (in a high level) for the long APDU commands with
// the smart card reader.
KeInitializeMutex(
&SmartcardExtension->ReaderExtension->LongAPDUMutex,
3
);
// Open a communication channel (GDDK_Oros3OpenComm).
// The reader baudrate is automatically detected by this function.
handle = (short)DeviceNumber;
status = GDDK_Oros3OpenComm(&serial_channel,handle);
if (status == STATUS_DEVICE_ALREADY_ATTACHED) {
status = GDDK_SerPortAddUser((USHORT) serial_channel.Port,&portcom);
if (status != STATUS_SUCCESS) {
return (status);
}
GDDK_GBPOpen(handle,2,4,portcom);
}
if (status != STATUS_SUCCESS) {
return (status);
}
//
// Verify the Firmware version: this driver support only the PnP GemCore based
// readers
//
cmd[0] = (BYTE) HOR3GLL_IFD_CMD_MEM_RD;
cmd[1] = (BYTE)HOR3GLL_IFD_TYP_VERSION;
cmd[2] = HIBYTE(HOR3GLL_IFD_ADD_VERSION);
cmd[3] = LOBYTE(HOR3GLL_IFD_ADD_VERSION);
cmd[4] = (BYTE)HOR3GLL_IFD_LEN_VERSION;
status = GDDK_Oros3Exchange(
handle,
HOR3GLL_LOW_TIME,
5,
cmd,
&os_length,
os_string
);
if (status != STATUS_SUCCESS) {
GDDK_Oros3CloseComm(handle);
return (status);
}
if (os_length >= (USHORT)strlen(IFD_FIRMWARE_VERSION)) {
if (memcmp(os_string + 1,IFD_FIRMWARE_VERSION,strlen(IFD_FIRMWARE_VERSION))) {
GDDK_Oros3CloseComm(handle);
return (STATUS_INVALID_DEVICE_STATE);
}
} else {
GDDK_Oros3CloseComm(handle);
return (STATUS_INVALID_DEVICE_STATE);
}
// GemCore Rx.yy-yz
// x = major version
// y = minor version
// z = M if masked version
majorVersion = os_string[strlen(IFD_FIRMWARE_VERSION) + 1] - '0';
minorVersion = 100 * (os_string[strlen(IFD_FIRMWARE_VERSION) + 3] - '0');
minorVersion += 10 * (os_string[strlen(IFD_FIRMWARE_VERSION) + 4] - '0');
minorVersion += (os_string[strlen(IFD_FIRMWARE_VERSION) + 6] - '0');
SmartcardDebug(
DEBUG_TRACE,
("%s!GDDK_0AOpenChannel: GemCore version = %d.%d\n",
SC_DRIVER_NAME,
majorVersion,
minorVersion)
);
if ((majorVersion < IFD_VERSION_MAJOR) || (minorVersion < IFD_VERSION_MINOR)) {
GDDK_Oros3CloseComm(handle);
SmartcardDebug(
DEBUG_ERROR,
("%s!GDDK_0AOpenChannel: The firmware version is not supported by the driver!\n",
SC_DRIVER_NAME)
);
return (STATUS_BAD_DEVICE_TYPE);
}
// Optimizes the baudrate:
// Initializes the comm variable to modify the used baud rate.
status = GDDK_GBPChannelToPortComm(handle,&portcom);
if (status != STATUS_SUCCESS) {
GDDK_Oros3CloseComm(handle);
return status;
}
status = GDDK_SerPortGetState(
portcom,
&comm,
&user
);
if (status != STATUS_SUCCESS) {
GDDK_Oros3CloseComm(handle);
return status;
}
//ISV
// Connection was established
// Now try to connect at max speed!
comm.BaudRate = serial_channel.BaudRate;
SmartcardDebug(
DEBUG_TRACE,
("%s!GDDK_0AOpenChannel: Connection established at %d baud rate\n",
SC_DRIVER_NAME,comm.BaudRate));
// Unsupported baud rate
if(comm.BaudRate >= 38400)
{
SmartcardDebug(DEBUG_ERROR,("GDDK_0AOpenChannel: ###### UNSUPPORTED BAUD RATE %d\n", comm.BaudRate));
GDDK_Oros3CloseComm(handle);
return (STATUS_INVALID_DEVICE_STATE);
}
// Maximum baud rate is already set - nothing to do
if(comm.BaudRate==38400)
{
SmartcardDebug(DEBUG_DRIVER,("GDDK_0AOpenChannel: MAX SPEED SET TO 38400!\n"));
}
else
{
// Try to negotiate a better baud rate.
int i=0;
BOOLEAN bBetterBaudRate=FALSE;
ULONG brList[3] = {38400, 19200, 9600};
USHORT brListLength = 3;
ULONG previousBaudRate = 0;
KEVENT event;
previousBaudRate = comm.BaudRate;
i = 0;
while ( (i < brListLength) &&
(bBetterBaudRate == FALSE) )
{
br = brList[i];
// The reader is switched to the selected value (GDDK_Oros3SIOConfigure). The
// function status is not tested because, as the IFD has switched
// immediatly, it is not possible to read its response.
comm.BaudRate = br;
rlen = 0;
rbuff[0]=0x0;
GDDK_Oros3SIOConfigure(
handle,
HOR3GLL_LOW_TIME,
0,
8,
comm.BaudRate,
&rlen,
rbuff,
FALSE
);
//
// Waits for the fisrt command is processed by the reader
// 500 ms is enought
//
KeInitializeEvent(&event,NotificationEvent,FALSE);
timeout.QuadPart = -((LONGLONG) 500 * 1000);
KeWaitForSingleObject(&event,
Suspended,
KernelMode,
FALSE,
&timeout);
// Host is switched to the selected value (GDDK_SerPortSetState).
// If this call is successful,
// Then
// The last command is re-sent to read the IFD response.
// response is optionnaly initialized with the translated IFD status.
status = GDDK_SerPortSetState(
portcom,
&comm
);
if (status == STATUS_SUCCESS)
{
rlen = HOR3GLL_BUFFER_SIZE;
rbuff[0]=0x0;
status = GDDK_Oros3SIOConfigure(
handle,
HOR3GLL_LOW_TIME,
0,
8,
comm.BaudRate,
&rlen,
rbuff,
TRUE
);
if (status == STATUS_SUCCESS)
{
bBetterBaudRate = TRUE;
}
}
} // endwhile
// Check if a better baudrate was negotiated
if (bBetterBaudRate==FALSE)
{
//*** Can come back to the previous one
// return an error message right now.
GDDK_Oros3CloseComm(handle);
return (STATUS_INVALID_DEVICE_STATE);
}
}
SmartcardDebug(
DEBUG_TRACE,
("%s!GDDK_0AOpenChannel: Reader speed was set to %d baud rate\n",
SC_DRIVER_NAME,comm.BaudRate));
// Sends the SetMode command with parameter 0 to disable TLP compatibility.
rlen = HOR3GLL_BUFFER_SIZE;
cmd[0] = (BYTE) HOR3GLL_IFD_CMD_MODE_SET;
cmd[1] = (BYTE) 0x00;
cmd[2] = (BYTE) 0x00;
status = GDDK_Oros3Exchange(
handle,
HOR3GLL_LOW_TIME,
3,
cmd,
&rlen,
rbuff
);
if (status != STATUS_SUCCESS) {
GDDK_Oros3CloseComm(handle);
return (status);
}
// Reader capabilities:
// - the type of the reader (SCARD_READER_TYPE_SERIAL)
// - the channel for the reader (PortSerialNumber)
// - the protocols supported by the reader (SCARD_PROTOCOL_T0, SCARD_PROTOCOL_T1)
// - the mechanical characteristic of the reader:
SmartcardExtension->ReaderCapabilities.ReaderType =
SCARD_READER_TYPE_SERIAL;
SmartcardExtension->ReaderCapabilities.Channel =
PortSerialNumber;
SmartcardExtension->ReaderCapabilities.SupportedProtocols =
SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1;
SmartcardExtension->ReaderCapabilities.MechProperties = 0;
// Reader capabilities (continue):
// - the default clock frequency (SC_IFD_DEFAULT_CLK_FREQUENCY)
// - the maximum clock frequency (SC_IFD_MAXIMUM_CLK_FREQUENCY)
// - the default data rate (SC_IFD_DEFAULT_DATA_RATE)
// - the maximum data rate (SC_IFD_MAXIMUM_DATA_RATE)
// - the maximum IFSD (SC_IFD_MAXIMUM_IFSD)
// - the power management is set to 0.
SmartcardExtension->ReaderCapabilities.CLKFrequency.Default =
SC_IFD_DEFAULT_CLK_FREQUENCY;
SmartcardExtension->ReaderCapabilities.CLKFrequency.Max =
SC_IFD_MAXIMUM_CLK_FREQUENCY;
SmartcardExtension->ReaderCapabilities.DataRate.Default =
SC_IFD_DEFAULT_DATA_RATE;
SmartcardExtension->ReaderCapabilities.DataRate.Max =
SC_IFD_MAXIMUM_DATA_RATE;
SmartcardExtension->ReaderCapabilities.MaxIFSD =
SC_IFD_MAXIMUM_IFSD;
SmartcardExtension->ReaderCapabilities.PowerMgmtSupport = 0;
// Reader capabilities (continue):
// - List all the supported data rates
SmartcardExtension->ReaderCapabilities.DataRatesSupported.List =
dataRatesSupported;
SmartcardExtension->ReaderCapabilities.DataRatesSupported.Entries =
sizeof(dataRatesSupported) / sizeof(dataRatesSupported[0]);
// Vendor Attributes:
// - the vendor information (SC_VENDOR_NAME)
strcpy(
SmartcardExtension->VendorAttr.VendorName.Buffer,
SC_VENDOR_NAME
);
SmartcardExtension->VendorAttr.VendorName.Length =
(USHORT) strlen(SmartcardExtension->VendorAttr.VendorName.Buffer);
// Vendor Attributes (continue):
// - the UnitNo information. Is set to the device number.
// - the IFD serial number (is set to a NULL string).
// - the IFD version is set.
strcpy(SmartcardExtension->VendorAttr.IfdType.Buffer,SC_IFD_TYPE);
SmartcardExtension->VendorAttr.IfdType.Length =
(USHORT) strlen(SmartcardExtension->VendorAttr.IfdType.Buffer);
SmartcardExtension->VendorAttr.UnitNo = DeviceNumber;
SmartcardExtension->VendorAttr.IfdSerialNo.Length = 0;
SmartcardExtension->VendorAttr.IfdVersion.VersionMajor = (UCHAR)majorVersion;
SmartcardExtension->VendorAttr.IfdVersion.VersionMinor = (UCHAR)minorVersion;
SmartcardExtension->VendorAttr.IfdVersion.BuildNumber = 0;
// Reader Extension:
// - the Handle of the reader.
// - the IFD number of the reader.
// - the ICCType (ISOCARD).
// - the ICCVpp (HOR3GLL_DEFAULT_VPP).
// - the ICCPresence.
// - the command timeout for the reader (HOR3GLL_DEFAULT_TIME).
// - the IFD baud rate.
// - the power timeout (0).
// - the selected VCC power supply voltage value.
// - the PTS negotiate mode.
// - the parameter PTS0.
// - the parameter PTS1.
// - the parameter PTS2.
// - the parameter PTS3.
SmartcardExtension->ReaderExtension->Handle = handle;
SmartcardExtension->ReaderExtension->APDUTimeOut = HOR3GLL_APDU_TIMEOUT;
SmartcardExtension->ReaderExtension->CmdTimeOut = HOR3GLL_DEFAULT_TIME;
SmartcardExtension->ReaderExtension->IFDBaudRate = br;
SmartcardExtension->ReaderExtension->PowerTimeOut = ICC_DEFAULT_POWER_TIMOUT;
SmartcardExtension->ReaderExtension->MaximalBaudRate = MaximalBaudRate;
SmartcardExtension->ReaderExtension->IccConfig.ICCType = ISOCARD;
SmartcardExtension->ReaderExtension->IccConfig.ICCVpp = HOR3GLL_DEFAULT_VPP;
SmartcardExtension->ReaderExtension->IccConfig.ICCVcc = ICC_VCC_5V;
SmartcardExtension->ReaderExtension->IccConfig.PTSMode = IFD_DEFAULT_MODE;
SmartcardExtension->ReaderExtension->IccConfig.PTS0 = 0;
SmartcardExtension->ReaderExtension->IccConfig.PTS1 = 0;
SmartcardExtension->ReaderExtension->IccConfig.PTS2 = 0;
SmartcardExtension->ReaderExtension->IccConfig.PTS3 = 0;
SmartcardExtension->ReaderExtension->IccConfig.ICCPresence = 0x0D;
// Define the type of the card (ISOCARD) and set the card presence
rlen = HOR3GLL_BUFFER_SIZE;
cmd[0] = HOR3GLL_IFD_CMD_ICC_DEFINE_TYPE;
cmd[1] = (BYTE) SmartcardExtension->ReaderExtension->IccConfig.ICCType;
cmd[2] = (BYTE) SmartcardExtension->ReaderExtension->IccConfig.ICCVpp;
cmd[3] = (BYTE) SmartcardExtension->ReaderExtension->IccConfig.ICCPresence ;
status = GDDK_Oros3Exchange(
handle,
HOR3GLL_LOW_TIME,
4,
cmd,
&rlen,
rbuff
);
if (status == STATUS_SUCCESS) {
status = GDDK_Translate(rbuff[0],0);
}
if (status != STATUS_SUCCESS) {
GDDK_Oros3CloseComm(handle);
return(status);
}
// Update the status of the card
GDDK_0AUpdateCardStatus(SmartcardExtension);
return(STATUS_SUCCESS);
}
NTSTATUS
GDDK_0ACloseChannel(
PSMARTCARD_EXTENSION SmartcardExtension
)
/*++
Routine Description:
This routine close a conection previously opened with a reader.
Arguments:
SmartcardExtension - is a pointer on the SmartCardExtension structure of
the current device.
Return Value:
STATUS_SUCCESS - We could execute the request.
--*/
{
READER_EXTENSION *param = SmartcardExtension->ReaderExtension;
USHORT rlen;
BYTE cmd[1],rbuff[HOR3GLL_BUFFER_SIZE];
// Call power down function:
rlen = HOR3GLL_BUFFER_SIZE;
cmd[0] = HOR3GLL_IFD_CMD_ICC_POWER_DOWN;
return(
GDDK_Oros3Exchange(
param->Handle,
HOR3GLL_LOW_TIME,
1,
cmd,
&rlen,
rbuff
)
);
}
NTSTATUS
GDDK_0AUpdateCardStatus(
PSMARTCARD_EXTENSION pSmartcardExtension
)
/*++
Routine Description:
This function send a command to the reader to known the state of the card.
Arguments:
SmartcardExtension - is a pointer on the SmartCardExtension structure of
the current device.
Return Value:
STATUS_SUCCESS - We could execute the request.
--*/
{
BYTE cmd[1];
READER_EXTENSION *param = pSmartcardExtension->ReaderExtension;
USHORT rlen;
BYTE rbuff[HOR3GLL_BUFFER_SIZE];
KIRQL irql;
NTSTATUS status;
// Read the status of the reader
cmd[0] = HOR3GLL_IFD_CMD_ICC_STATUS;
rlen = HOR3GLL_BUFFER_SIZE;
status = GDDK_Oros3Exchange(
param->Handle,
HOR3GLL_LOW_TIME,
(const USHORT)1,
(const BYTE *)cmd,
&rlen,
rbuff
);
if (status == STATUS_SUCCESS) {
status = GDDK_Translate(rbuff[0],0);
}
if (status != STATUS_SUCCESS) {
return status;
}
KeAcquireSpinLock(
&pSmartcardExtension->OsData->SpinLock,
&irql
);
if ((rbuff[1] & 0x04) == 0) {
// The card is absent
pSmartcardExtension->ReaderCapabilities.CurrentState = SCARD_ABSENT;
pSmartcardExtension->CardCapabilities.Protocol.Selected = SCARD_PROTOCOL_UNDEFINED;
pSmartcardExtension->CardCapabilities.ATR.Length = 0;
SmartcardDebug(
DEBUG_TRACE,
("%s!GDDK_0AUpdateCardStatus: Card removed\n",
SC_DRIVER_NAME)
);
} else if ((rbuff[1] & 0x02) == 0) {
// The card is present
pSmartcardExtension->ReaderCapabilities.CurrentState = SCARD_SWALLOWED;
pSmartcardExtension->CardCapabilities.Protocol.Selected = SCARD_PROTOCOL_UNDEFINED;
pSmartcardExtension->CardCapabilities.ATR.Length = 0;
SmartcardDebug(
DEBUG_TRACE,
("%s!GDDK_0AUpdateCardStatus: Card inserted\n",
SC_DRIVER_NAME)
);
}
KeReleaseSpinLock(
&pSmartcardExtension->OsData->SpinLock,
irql
);
return status;
}
VOID
GDDK_0ALockExchange(
PSMARTCARD_EXTENSION SmartcardExtension
)
/*++
Routine Description:
Wait the release of the ExchangeMutex and take this.
Arguments:
SmartcardExtension - is a pointer on the SmartCardExtension structure of
the current device.
Return Value:
STATUS_SUCCESS - We could execute the request.
--*/
{
KeWaitForMutexObject(
&SmartcardExtension->ReaderExtension->LongAPDUMutex,
Executive,
KernelMode,
FALSE,
NULL
);
}
VOID
GDDK_0AUnlockExchange(
PSMARTCARD_EXTENSION SmartcardExtension
)
/*++
Routine Description:
Release of the Exchange mutex.
Arguments:
SmartcardExtension - is a pointer on the SmartCardExtension structure of
the current device.
--*/
{
KeReleaseMutex(
&SmartcardExtension->ReaderExtension->LongAPDUMutex,
FALSE
);
}
static VOID
GDDK_0ASetTransparentConfig(
PSMARTCARD_EXTENSION SmartcardExtension,
BYTE NewWtx
)
/*++
Routine Description:
Set the parameters of the transparent mode.
Arguments:
SmartcardExtension - is a pointer on the SmartCardExtension structure of
the current device.
NewWtx - holds the value (ms) of the new Wtx
--*/
{
READER_EXTENSION *param = SmartcardExtension->ReaderExtension;
LONG etu;
BYTE temp,mask,index;
USHORT rlen;
BYTE cmd[6],rbuff[HOR3GLL_BUFFER_SIZE];
NTSTATUS status;
// Inverse or direct conversion
if (SmartcardExtension->CardCapabilities.InversConvention)
param->TransparentConfig.CFG |= 0x20;
else
param->TransparentConfig.CFG &= 0xDF;
// Transparent T=1 like (with 1 byte for the length).
param->TransparentConfig.CFG |= 0x08;
// ETU = ((F[Fi]/D[Di]) - 1) / 3
etu = SmartcardExtension->CardCapabilities.ClockRateConversion[
(BYTE) param->TransparentConfig.Fi].F;
if (SmartcardExtension->CardCapabilities.BitRateAdjustment[
(BYTE) param->TransparentConfig.Fi].DNumerator) {
etu /= SmartcardExtension->CardCapabilities.BitRateAdjustment[
(BYTE) param->TransparentConfig.Fi].DNumerator;
}
etu -= 1;
etu /= 3;
param->TransparentConfig.ETU = (BYTE) ( 0x000000FF & etu);
if (SmartcardExtension->CardCapabilities.N == 0xFF) {
param->TransparentConfig.EGT = (BYTE) 0x00;
} else {
param->TransparentConfig.EGT = (BYTE) SmartcardExtension->CardCapabilities.N;
}
param->TransparentConfig.CWT = (BYTE) SmartcardExtension->CardCapabilities.T1.CWI;
if (NewWtx) {
for (mask = 0x80,index = 8; index !=0x00; index--) {
temp = NewWtx & mask;
if (temp == mask)
break;
mask = mask/2;
}
param->TransparentConfig.BWI = SmartcardExtension->CardCapabilities.T1.BWI + index;
} else {
param->TransparentConfig.BWI = SmartcardExtension->CardCapabilities.T1.BWI;
}
// Now we send the configuration command
rlen = HOR3GLL_BUFFER_SIZE;
cmd[0] = HOR3GLL_IFD_CMD_TRANS_CONFIG;
cmd[1] = param->TransparentConfig.CFG;
cmd[2] = param->TransparentConfig.ETU;
cmd[3] = param->TransparentConfig.EGT;
cmd[4] = param->TransparentConfig.CWT;
cmd[5] = param->TransparentConfig.BWI;
status = GDDK_Oros3Exchange(
param->Handle,
HOR3GLL_LOW_TIME,
6,
cmd,
&rlen,
rbuff
);
}
NTSTATUS
GDDK_0ARestoreCommunication(
PSMARTCARD_EXTENSION SmartcardExtension
)
/*++
Routine Description:
Restore the communication with the reader at the good speed.
Arguments:
SmartcardExtension - is a pointer on the SmartCardExtension structure of
the current device.
--*/
{
TGTSER_PORT comm;
BYTE cmd[10],rbuff[HOR3GLL_BUFFER_SIZE];
USHORT user,rlen;
ULONG br;
SHORT portcom;
KEVENT event;
LARGE_INTEGER timeout;
NTSTATUS status;
READER_EXTENSION *param = SmartcardExtension->ReaderExtension;
// Loop while a right response has not been received. We start at 9600
status = GDDK_GBPChannelToPortComm(param->Handle,&portcom);
if (status != STATUS_SUCCESS) {
return status;
}
status = GDDK_SerPortGetState(portcom,&comm,&user);
if (status != STATUS_SUCCESS) {
return status;
}
comm.BaudRate = 9600;
GDDK_SerPortSetState(portcom,&comm);
GDDK_0ALockExchange(SmartcardExtension);
__try {
do {
// Wait for HOR3COMM_CHAR_TIME ms before any command for IFD to forget any
// previous received byte.
KeInitializeEvent(&event,NotificationEvent,FALSE);
timeout.QuadPart = -((LONGLONG) HOR3COMM_CHAR_TIME*10*1000);
KeWaitForSingleObject(
&event,
Suspended,
KernelMode,
FALSE,
&timeout
);
SmartcardDebug(
DEBUG_TRACE,
("%s!GDDK_0ARestoreCommunication: Try at baud rate = %d\n",
SC_DRIVER_NAME,
comm.BaudRate)
);
// Define the type of the card (ISOCARD) and set the card presence
rlen = HOR3GLL_BUFFER_SIZE;
SmartcardExtension->ReaderExtension->IccConfig.ICCType = ISOCARD;
cmd[0] = HOR3GLL_IFD_CMD_ICC_DEFINE_TYPE;
cmd[1] = (BYTE) SmartcardExtension->ReaderExtension->IccConfig.ICCType;
cmd[2] = (BYTE) SmartcardExtension->ReaderExtension->IccConfig.ICCVpp;
cmd[3] = (BYTE) SmartcardExtension->ReaderExtension->IccConfig.ICCPresence ;
status = GDDK_Oros3Exchange(
param->Handle,
HOR3GLL_LOW_TIME,
4,
cmd,
&rlen,
rbuff
);
if (status != STATUS_SUCCESS) {
if (comm.BaudRate == 9600lu) {
comm.BaudRate = 38400lu;
} else if (comm.BaudRate == 38400lu) {
comm.BaudRate = 19200lu;
} else {
status = STATUS_INVALID_DEVICE_STATE;
__leave;
}
// The new baud rate configuration is set.
GDDK_SerPortSetState(portcom,&comm);
} else {
break;
}
} while (status != STATUS_SUCCESS);
SmartcardDebug(
DEBUG_ERROR,
("%s!GDDK_0ARestoreCommunication: Baud rate = %d\n",
SC_DRIVER_NAME,
comm.BaudRate)
);
// Optimizes the baudrate:
if(param->MaximalBaudRate > comm.BaudRate) {
br = comm.BaudRate;
for(;br < param->MaximalBaudRate;) {
br = br * 2;
// The reader is switched to the selected value (GDDK_Oros3SIOConfigure). The
// function status is not tested because, as the IFD has switched
// immediatly, it is not possible to read its response.
SmartcardDebug(
DEBUG_TRACE,
("%s!GDDK_0ARestoreCommunication: Optimize baud rate = %d\n",
SC_DRIVER_NAME,
comm.BaudRate)
);
comm.BaudRate = br;
rlen = 0;
GDDK_Oros3SIOConfigure(
param->Handle,
HOR3GLL_LOW_TIME,
0,
8,
comm.BaudRate,
&rlen,
rbuff,
FALSE
);
//
// Waits for the fisrt command is process by the reader
// 500 ms is enought
//
KeInitializeEvent(&event,NotificationEvent,FALSE);
timeout.QuadPart = -((LONGLONG) 500 * 1000);
KeWaitForSingleObject(&event,
Suspended,
KernelMode,
FALSE,
&timeout);
// Host is switched to the selected value (GDDK_SerPortSetState).
// If this call is successful,
// Then
// The last command is re-sent to read the IFD response.
// response is optionnaly initialized with the translated IFD status.
status = GDDK_SerPortSetState(portcom,&comm);
SmartcardDebug(
DEBUG_TRACE,
("%s!GDDK_0ARestoreCommunication: Set baud rate = %d\n",
SC_DRIVER_NAME,
comm.BaudRate)
);
if (status == STATUS_SUCCESS) {
rlen = HOR3GLL_BUFFER_SIZE;
status = GDDK_Oros3SIOConfigure(
param->Handle,
HOR3GLL_LOW_TIME,
0,
8,
comm.BaudRate,
&rlen,
rbuff,
TRUE
);
if (status == STATUS_SUCCESS) {
status = GDDK_Translate(rbuff[0],0);
}
if (status != STATUS_SUCCESS) {
break;
}
}
}
if ((br > 38400) || (status != STATUS_SUCCESS)) {
status = STATUS_INVALID_DEVICE_STATE;
__leave;
}
}
SmartcardDebug(
DEBUG_TRACE,
("%s!GDDK_0ARestoreCommunication: Current baud rate = %d\n",
SC_DRIVER_NAME,
comm.BaudRate)
);
// Send the SetMode command with parameter 0 to disable TLP compatibility.
rlen = HOR3GLL_BUFFER_SIZE;
cmd[0] = (BYTE) HOR3GLL_IFD_CMD_MODE_SET;
cmd[1] = (BYTE) 0x00;
cmd[2] = (BYTE) 0x00;
status = GDDK_Oros3Exchange(
param->Handle,
HOR3GLL_LOW_TIME,
3,
cmd,
&rlen,
rbuff
);
if (status != STATUS_SUCCESS) {
__leave;
}
// Update the status of the card
GDDK_0AUpdateCardStatus(SmartcardExtension);
}
__finally {
if (status != STATUS_SUCCESS) {
SmartcardDebug(
DEBUG_ERROR,
("%s!GDDK_0ARestoreCommunication: Failed\n",
SC_DRIVER_NAME,
comm.BaudRate)
);
}
}
GDDK_0AUnlockExchange(SmartcardExtension);
SmartcardDebug(
DEBUG_TRACE,
("%s!GDDK_0ARestoreCommunication: Exit=%X(hex)\n",
SC_DRIVER_NAME,
status)
);
return status;
}