|
|
/*++
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; }
|