You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1013 lines
29 KiB
1013 lines
29 KiB
/*++
|
|
|
|
Copyright (C) Microsoft Corporation and Litronic, 1998 - 1999
|
|
|
|
Module Name:
|
|
|
|
L220Ser.c
|
|
|
|
Abstract:
|
|
|
|
This module contains the functions for the 220 serial smart card reader.
|
|
Most functions herein will be called by the smart card lib.
|
|
|
|
|
|
Environment:
|
|
|
|
Kernel mode only.
|
|
|
|
Notes:
|
|
|
|
Revision History:
|
|
|
|
- Created December 1996 by Klaus Schutz
|
|
|
|
- Modified December 1997 by Brian Manahan for use with
|
|
the 220 reader.
|
|
--*/
|
|
|
|
#include <stdarg.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
|
|
#include "L220SCR.h"
|
|
|
|
|
|
// Make functions pageable
|
|
#pragma alloc_text(PAGEABLE, Lit220Command)
|
|
#pragma alloc_text(PAGEABLE, Lit220IoRequest)
|
|
#pragma alloc_text(PAGEABLE, Lit220IoReply)
|
|
|
|
|
|
NTSTATUS
|
|
Lit220CardTracking(
|
|
PSMARTCARD_EXTENSION SmartcardExtension
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
The smart card lib requires to have this function. It is called
|
|
to set up event tracking for card insertion and removal events.
|
|
We set the cancel routine so the IRP can be canceled.
|
|
We always return STATUS_PENDING and the Lit220NotifyCardChange
|
|
will signal the completion when called from the Lit220InputFilter.
|
|
|
|
Arguments:
|
|
|
|
SmartcardExtension - pointer to the smart card data struct.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS
|
|
|
|
--*/
|
|
{
|
|
KIRQL oldIrql;
|
|
KIRQL oldOsDataIrql;
|
|
|
|
//
|
|
// Set the wait mask for the isr. The isr will complete the
|
|
// user request.
|
|
//
|
|
SmartcardExtension->ReaderExtension->WaitMask |= WAIT_INSERTION; // WAIT_INSERTION - wait for insertion or removal
|
|
|
|
//
|
|
// Set cancel routine for the notification irp
|
|
//
|
|
KeAcquireSpinLock(
|
|
&SmartcardExtension->OsData->SpinLock,
|
|
&oldOsDataIrql
|
|
);
|
|
|
|
ASSERT (SmartcardExtension->OsData->NotificationIrp);
|
|
|
|
if (SmartcardExtension->OsData->NotificationIrp) {
|
|
IoAcquireCancelSpinLock(
|
|
&oldIrql
|
|
);
|
|
|
|
IoSetCancelRoutine(
|
|
SmartcardExtension->OsData->NotificationIrp,
|
|
Lit220Cancel
|
|
);
|
|
|
|
IoReleaseCancelSpinLock(
|
|
oldIrql
|
|
);
|
|
|
|
} else {
|
|
SmartcardDebug(
|
|
DEBUG_ERROR,
|
|
("%s!Lit220CardTracking: SmartcardExtension->OsData->NotificationIrp is NULL!!! This should not be.\n",
|
|
DRIVER_NAME
|
|
));
|
|
}
|
|
|
|
KeReleaseSpinLock(
|
|
&SmartcardExtension->OsData->SpinLock,
|
|
oldOsDataIrql
|
|
);
|
|
|
|
SmartcardDebug(
|
|
DEBUG_TRACE,
|
|
("%s!Lit220CardTracking: Exit, WaitMask %X, NotificationIRP %X\n",
|
|
DRIVER_NAME,
|
|
SmartcardExtension->ReaderExtension->WaitMask,
|
|
SmartcardExtension->OsData->NotificationIrp
|
|
));
|
|
|
|
return STATUS_PENDING;
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
Lit220Command(
|
|
IN PSMARTCARD_EXTENSION SmartcardExtension
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine sends a command to the reader.
|
|
SerialIo is used to write the command to the reader synchronously.
|
|
We then wait for an ACK from the reader (by waiting for a signal from
|
|
the Lit220InputFilter) so we know it received the command OK.
|
|
If data is expected we wait for the data event signal from the
|
|
Lit220InputFilter to indicate that the data is ready.
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - Pointer to the device object.
|
|
|
|
Return Value:
|
|
|
|
-
|
|
|
|
--*/
|
|
{
|
|
PDEVICE_OBJECT deviceObject = SmartcardExtension->OsData->DeviceObject;
|
|
PDEVICE_EXTENSION deviceExtension = deviceObject->DeviceExtension;
|
|
PREADER_EXTENSION readerExtension = SmartcardExtension->ReaderExtension;
|
|
ULONG i;
|
|
NTSTATUS status = STATUS_UNSUCCESSFUL;
|
|
LARGE_INTEGER timeout;
|
|
ULONG localWaitMask;
|
|
ULONG retry = 1;
|
|
|
|
PAGED_CODE();
|
|
|
|
SmartcardDebug(
|
|
DEBUG_TRACE,
|
|
("%s!Lit220Command: Enter\n",
|
|
DRIVER_NAME)
|
|
);
|
|
|
|
do{
|
|
|
|
// Make sure the data & ack events are not signaled before we start
|
|
|
|
// Clear the DataEvnt
|
|
KeClearEvent(
|
|
&readerExtension->DataEvnt
|
|
);
|
|
|
|
|
|
// Clear the AckEvnt
|
|
KeClearEvent(
|
|
&readerExtension->AckEvnt
|
|
);
|
|
|
|
|
|
readerExtension->ReceivedByteNo = 0;
|
|
|
|
readerExtension->GotNack = FALSE;
|
|
|
|
// We always exect an ACK back
|
|
readerExtension->WaitMask |= WAIT_ACK;
|
|
|
|
|
|
// We need to copy the wait mask because the wait mask might change
|
|
// before we have a chance to check if we need to wait on it
|
|
localWaitMask = readerExtension->WaitMask;
|
|
|
|
//
|
|
// Send the data to the reader
|
|
//
|
|
readerExtension->SerialIoControlCode = IOCTL_SMARTCARD_220_WRITE;
|
|
|
|
// Use SerialIo to actually send the bytes to the reader
|
|
status = Lit220SerialIo(
|
|
SmartcardExtension
|
|
);
|
|
|
|
//
|
|
// Set Timeout according the protocol
|
|
//
|
|
timeout.HighPart = -1;
|
|
switch (SmartcardExtension->CardCapabilities.Protocol.Selected) {
|
|
|
|
case SCARD_PROTOCOL_UNDEFINED:
|
|
// 3 sec timeout for undefined protocol
|
|
timeout.LowPart = (ULONG)
|
|
(-30 * 1000 * 1000);
|
|
break;
|
|
|
|
case SCARD_PROTOCOL_T0:
|
|
// For t=0 protocol we must set the timeout to a very large time. This
|
|
// is becuase the card could ask for more time, but the reader must pay
|
|
// keep paying attention to the card so it can not tell us that more time
|
|
// is needed. Therefore we must trust the readers timeout, and trust that
|
|
// it will NACK us if there is a problem.
|
|
timeout.LowPart = (-10 * 1000 * 1000 * 100) + // Timeout 100 seconds
|
|
(-10) * SmartcardExtension->CardCapabilities.T0.WT;
|
|
break;
|
|
|
|
case SCARD_PROTOCOL_T1:
|
|
|
|
timeout.LowPart =
|
|
SmartcardExtension->CardCapabilities.T1.BWT *
|
|
(SmartcardExtension->T1.Wtx ? SmartcardExtension->T1.Wtx : 1);
|
|
|
|
timeout.LowPart += SmartcardExtension->CardCapabilities.T1.CWT *
|
|
SmartcardExtension->SmartcardReply.BufferLength;
|
|
|
|
// Add a little extra time for reader to respond to the PC
|
|
timeout.LowPart += 100 * 1000;
|
|
|
|
// Convert timeout to NS
|
|
timeout.LowPart *= -10;
|
|
|
|
|
|
break;
|
|
}
|
|
|
|
ASSERT(timeout.LowPart != 0);
|
|
|
|
|
|
|
|
|
|
//
|
|
// Always for the ACK
|
|
//
|
|
status = KeWaitForSingleObject(
|
|
&readerExtension->AckEvnt,
|
|
Executive,
|
|
KernelMode,
|
|
FALSE,
|
|
&timeout
|
|
);
|
|
|
|
// Did we actually get a nack instead of an ACK
|
|
if (readerExtension->GotNack) {
|
|
status = Lit220GetReaderError(SmartcardExtension);
|
|
// GetReaderError will clear this flag, but I need to
|
|
// preserve the fact that I got nacked so I must reset it.
|
|
readerExtension->GotNack = TRUE;
|
|
}
|
|
|
|
//
|
|
// Wait for the Data if requested
|
|
//
|
|
if ((localWaitMask & WAIT_DATA) && (status == STATUS_SUCCESS)) {
|
|
|
|
// Wait for signal the data is ready (at least until we timeout)
|
|
status = KeWaitForSingleObject(
|
|
&readerExtension->DataEvnt,
|
|
Executive,
|
|
KernelMode,
|
|
FALSE,
|
|
&timeout
|
|
);
|
|
|
|
// Did we get NACKed?
|
|
if (readerExtension->GotNack) {
|
|
status = Lit220GetReaderError(SmartcardExtension);
|
|
// GetReaderError will clear this flag, but I need to
|
|
// preserve the fact that I got nacked so I must reset it.
|
|
readerExtension->GotNack = TRUE;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
if (status == STATUS_TIMEOUT) {
|
|
|
|
//
|
|
// STATUS_TIMEOUT isn't correctly mapped
|
|
// to a WIN32 error, that's why we change it here
|
|
// to STATUS_IO_TIMEOUT
|
|
//
|
|
status = STATUS_IO_TIMEOUT;
|
|
|
|
SmartcardDebug(
|
|
DEBUG_ERROR,
|
|
("%s(Lit220Command): Operation timed-out\n",
|
|
DRIVER_NAME)
|
|
);
|
|
}
|
|
|
|
{ // Sometimes after a command the reader is not reader to accept another command
|
|
// so we need to wait for a short period of time for the reader to be ready. We need to
|
|
// take this out as soon as the reader is fixed!
|
|
LARGE_INTEGER WaitTime;
|
|
|
|
WaitTime.HighPart = -1;
|
|
WaitTime.LowPart = -10; // Wait 1uS
|
|
|
|
KeDelayExecutionThread(
|
|
KernelMode,
|
|
FALSE,
|
|
&WaitTime
|
|
);
|
|
}
|
|
|
|
// If we failed because the reader did not give us any response resend the command.
|
|
// The reader should respond.
|
|
if ((status != STATUS_SUCCESS) && (!readerExtension->GotNack)) {
|
|
SmartcardDebug(
|
|
DEBUG_ERROR,
|
|
("%s(Lit220Command): Reader failed to respond! Retrying once more.\n",
|
|
DRIVER_NAME)
|
|
);
|
|
} else {
|
|
break;
|
|
}
|
|
|
|
|
|
} while (retry++ <= 2);
|
|
|
|
SmartcardDebug(
|
|
DEBUG_TRACE,
|
|
("%s!Lit220Command: Exit - status %X\n",
|
|
DRIVER_NAME,
|
|
status)
|
|
);
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
Lit220SetProtocol(
|
|
PSMARTCARD_EXTENSION SmartcardExtension
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function sends a set mode command to the reader set the
|
|
protocol and the parameters for the wait protocol.
|
|
|
|
|
|
Arguments:
|
|
|
|
SmartcardExtension - Pointer to the smart card data struct
|
|
|
|
|
|
// Parameters are up to seven bytes as follows:
|
|
//
|
|
// Flags - Flags to indicate the presence or absence of the other parameters.
|
|
// SETMODE_PROTOCOL, b0 - 1 if Protocol is present.
|
|
// SETMODE_GT, b1 - 1 if GuardTime is present.
|
|
// SETMODE_WI, b2 - 1 if WorkWaitTime is present.
|
|
// SETMODE_BWI, b3 - 1 if BWI/CWI is present.
|
|
// SETMODE_WTX, b4 - 1 if BlockWaitTimeExtension is present.
|
|
// SETMODE_FI_DI, b5 - 1 if BaudRate is present.
|
|
//
|
|
// Protocol - possible values 00, 02, 10, 11, 12, 13
|
|
// encodes T, C, CKS from the ATR
|
|
// Use of this parameter may invoke a PTS request to the smartcard.
|
|
// b4 - Protocol Type (0 for T=0, 1 for T=1)
|
|
// b3 - 0
|
|
// b2 - 1 for convert 6A to 6A 00 and FA to 6A 01 on output to PS/2.
|
|
// b1 - 0 ( use to be Convention used (0 for direct, 1 for inverse))
|
|
// b0 - Checksum type (0 for LRC, 1 for CRC)
|
|
//
|
|
// GuardTime - possible values 00 to FE (0 to 254 etu between two characters)
|
|
// encodes N (Extra Guardtime) from ATR
|
|
//
|
|
// WorkWaitTime - possible values 00 to FF
|
|
// encodes WI which is Work Waiting Time (character time-out for T=0)
|
|
|
|
//
|
|
// BWI/CWI - possible values 00 to FF
|
|
// encodes BWI and CWI which are the Block and Char Wait Time
|
|
// (block and character time-out for T=1)
|
|
//
|
|
// BlockWaitTimeExtension - possible values 00 to FF
|
|
// encodes WTX which is the Block Waiting Time Extension.
|
|
// 00 = no WTX is requested by the ICC.
|
|
// vv is the multiplier of the BWT value
|
|
//
|
|
// BaudRate - possible values 00 to FF
|
|
// encodes FI and DI in the same fashion as TA1 does.
|
|
// FI is in the high nibble. DI is in the low nibble.
|
|
// D and F can be looked up in a table in PC/SC part 2 sec. 4.4.3.
|
|
// Use of this parameter may invoke a PTS request to the smartcard.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS
|
|
|
|
--*/
|
|
{
|
|
PSMARTCARD_REQUEST smartcardRequest = &SmartcardExtension->SmartcardRequest;
|
|
NTSTATUS status;
|
|
DWORD bufLen = 0;
|
|
PCHAR flags;
|
|
PCHAR protoByte;
|
|
KIRQL irql;
|
|
|
|
RtlZeroMemory(
|
|
smartcardRequest->Buffer,
|
|
8
|
|
);
|
|
|
|
// Send a set mode command to the reader
|
|
smartcardRequest->Buffer[bufLen++] = LIT220_READER_ATTENTION;
|
|
smartcardRequest->Buffer[bufLen++] = LIT220_READER_ATTENTION;
|
|
smartcardRequest->Buffer[bufLen++] = LIT220_SET_MODE;
|
|
flags = &smartcardRequest->Buffer[bufLen++];
|
|
*flags = 0;
|
|
|
|
// Set the protocol
|
|
protoByte = &smartcardRequest->Buffer[bufLen++];
|
|
*protoByte = 0;
|
|
*flags |= SETMODE_PROTOCOL;
|
|
|
|
// Set the inverse convention bit
|
|
if (SmartcardExtension->CardCapabilities.InversConvention) {
|
|
// Set the bit in the protocol paramter
|
|
*protoByte |= LIT220_READER_CONVENTION_INVERSE;
|
|
}
|
|
|
|
//
|
|
// test if caller wants to have T=0 or T=1
|
|
//
|
|
if ((SmartcardExtension->MinorIoControlCode & SCARD_PROTOCOL_T1) &&
|
|
(SmartcardExtension->CardCapabilities.Protocol.Supported & SCARD_PROTOCOL_T1)){
|
|
|
|
SmartcardExtension->CardCapabilities.Protocol.Selected =
|
|
SCARD_PROTOCOL_T1;
|
|
|
|
// Setup set mode command with T=1 parameters for protocol
|
|
*protoByte |= LIT220_READER_PROTOCOL_T1;
|
|
|
|
if (SmartcardExtension->CardCapabilities.T1.EDC & T1_CRC_CHECK) {
|
|
|
|
*protoByte |= LIT220_READER_CHECK_CRC;
|
|
}
|
|
|
|
// Set the guard time
|
|
*flags |= SETMODE_GT;
|
|
smartcardRequest->Buffer[bufLen++] =
|
|
SmartcardExtension->CardCapabilities.N;
|
|
|
|
// Set BWI and CWI
|
|
*flags |= SETMODE_BWI;
|
|
smartcardRequest->Buffer[bufLen++] =
|
|
(SmartcardExtension->CardCapabilities.T1.BWI << 4) |
|
|
(SmartcardExtension->CardCapabilities.T1.CWI);
|
|
|
|
}
|
|
else if ((SmartcardExtension->MinorIoControlCode & SCARD_PROTOCOL_T0) &&
|
|
(SmartcardExtension->CardCapabilities.Protocol.Supported & SCARD_PROTOCOL_T0))
|
|
{
|
|
|
|
SmartcardExtension->CardCapabilities.Protocol.Selected =
|
|
SCARD_PROTOCOL_T0;
|
|
|
|
|
|
// Set the guard time
|
|
*flags |= SETMODE_GT;
|
|
smartcardRequest->Buffer[bufLen++] =
|
|
SmartcardExtension->CardCapabilities.N;
|
|
|
|
// Set WI
|
|
*flags |= SETMODE_WI;
|
|
smartcardRequest->Buffer[bufLen++] =
|
|
SmartcardExtension->CardCapabilities.T0.WI;
|
|
|
|
} else {
|
|
|
|
SmartcardDebug(
|
|
DEBUG_ERROR,
|
|
("%s!Lit220SetProtocol: Error invalid protocol selected\n",
|
|
DRIVER_NAME)
|
|
);
|
|
|
|
SmartcardExtension->CardCapabilities.Protocol.Selected =
|
|
SCARD_PROTOCOL_UNDEFINED;
|
|
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
|
|
// Set FI & DI for baud rate
|
|
*flags |= SETMODE_FI_DI;
|
|
smartcardRequest->Buffer[bufLen++] =
|
|
(SmartcardExtension->CardCapabilities.PtsData.Fl << 4) |
|
|
SmartcardExtension->CardCapabilities.PtsData.Dl;
|
|
|
|
|
|
smartcardRequest->BufferLength = bufLen;
|
|
|
|
|
|
SmartcardDebug(
|
|
DEBUG_DRIVER,
|
|
("%s!Lit220SetProtocol - Sending SetMode command %x bytes, %X,%X,%X,%X,%X,%X,%X,%X,%X,%X\n",
|
|
DRIVER_NAME,
|
|
bufLen,
|
|
smartcardRequest->Buffer[0],
|
|
smartcardRequest->Buffer[1],
|
|
smartcardRequest->Buffer[2],
|
|
smartcardRequest->Buffer[3],
|
|
smartcardRequest->Buffer[4],
|
|
smartcardRequest->Buffer[5],
|
|
smartcardRequest->Buffer[6],
|
|
smartcardRequest->Buffer[7],
|
|
smartcardRequest->Buffer[8],
|
|
smartcardRequest->Buffer[9]
|
|
));
|
|
|
|
status =Lit220Command(
|
|
SmartcardExtension
|
|
);
|
|
|
|
|
|
if (status == STATUS_SUCCESS) {
|
|
// now indicate that we're in specific mode
|
|
KeAcquireSpinLock(&SmartcardExtension->OsData->SpinLock,
|
|
&irql);
|
|
SmartcardExtension->ReaderCapabilities.CurrentState = SCARD_SPECIFIC;
|
|
KeReleaseSpinLock(&SmartcardExtension->OsData->SpinLock,
|
|
irql);
|
|
return status;
|
|
}
|
|
|
|
//TODO: handle rertying code without optimal setting if optimal fails
|
|
if (SmartcardExtension->CardCapabilities.PtsData.Type !=
|
|
PTS_TYPE_DEFAULT) {
|
|
DWORD saveMinorCode = SmartcardExtension->MinorIoControlCode;
|
|
|
|
SmartcardDebug(
|
|
DEBUG_TRACE,
|
|
("%s!Lit220SetProtocol: PTS failed. Trying default parameters...\n",
|
|
DRIVER_NAME,
|
|
status)
|
|
);
|
|
//
|
|
// The card did either NOT reply or it replied incorrectly
|
|
// so try default values
|
|
//
|
|
SmartcardExtension->CardCapabilities.PtsData.Type =
|
|
PTS_TYPE_DEFAULT;
|
|
|
|
SmartcardExtension->MinorIoControlCode = SCARD_COLD_RESET;
|
|
|
|
status = Lit220Power(SmartcardExtension);
|
|
if (!NT_SUCCESS(status)) {
|
|
return status;
|
|
}
|
|
|
|
SmartcardExtension->MinorIoControlCode = saveMinorCode;
|
|
|
|
return Lit220SetProtocol(SmartcardExtension);
|
|
}
|
|
|
|
// the card failed the pts-request
|
|
status = STATUS_DEVICE_PROTOCOL_ERROR;
|
|
|
|
SmartcardDebug(
|
|
DEBUG_TRACE,
|
|
("%s!Lit220SetProtocol: Exit with error.\n",
|
|
DRIVER_NAME)
|
|
);
|
|
|
|
return status;
|
|
}
|
|
|
|
NTSTATUS
|
|
Lit220Power(
|
|
PSMARTCARD_EXTENSION SmartcardExtension
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function sends an SCARD_COLD_RESET, SCARD_WARM_RESET or SCARD_POWER_DOWN
|
|
to the reader. For cold or warm reset we set a flag indicating that an ATR
|
|
is expected. Once the Lit220InputFilter receives the ATR it will update the
|
|
card capabilites.
|
|
|
|
Arguments:
|
|
|
|
SmartcardExtension - Pointer to the smart card data struct
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS
|
|
|
|
--*/
|
|
{
|
|
PSMARTCARD_REQUEST smartcardRequest = &SmartcardExtension->SmartcardRequest;
|
|
NTSTATUS status;
|
|
KIRQL irql;
|
|
|
|
SmartcardDebug(
|
|
DEBUG_TRACE,
|
|
("%s!Lit220Power: Enter\n",
|
|
DRIVER_NAME)
|
|
);
|
|
|
|
smartcardRequest->BufferLength = 0;
|
|
|
|
|
|
// Make sure card is still present
|
|
|
|
KeAcquireSpinLock(&SmartcardExtension->OsData->SpinLock,
|
|
&irql);
|
|
if (SmartcardExtension->ReaderCapabilities.CurrentState == SCARD_ABSENT) {
|
|
KeReleaseSpinLock(&SmartcardExtension->OsData->SpinLock,
|
|
irql);
|
|
return STATUS_DEVICE_REMOVED;
|
|
} else {
|
|
KeReleaseSpinLock(&SmartcardExtension->OsData->SpinLock,
|
|
irql);
|
|
}
|
|
|
|
|
|
//
|
|
// 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;
|
|
|
|
switch(SmartcardExtension->MinorIoControlCode) {
|
|
|
|
case SCARD_COLD_RESET:
|
|
//
|
|
// Send a power-on, if the reader is already off
|
|
// it will perform a cold reset turning the power off
|
|
// the back on again.
|
|
//
|
|
smartcardRequest->Buffer[smartcardRequest->BufferLength++] =
|
|
LIT220_READER_ATTENTION;
|
|
smartcardRequest->Buffer[smartcardRequest->BufferLength++] =
|
|
LIT220_READER_ATTENTION;
|
|
smartcardRequest->Buffer[smartcardRequest->BufferLength++] =
|
|
LIT220_CARD_POWER_ON;
|
|
|
|
//
|
|
// Power-on leads to an ATR
|
|
//
|
|
SmartcardExtension->ReaderExtension->WaitMask |= WAIT_DATA;
|
|
SmartcardExtension->ReaderExtension->WaitForATR = TRUE;
|
|
break;
|
|
|
|
case SCARD_WARM_RESET:
|
|
|
|
//
|
|
// Send a reset to the reader (warm reset)
|
|
//
|
|
smartcardRequest->Buffer[smartcardRequest->BufferLength++] =
|
|
LIT220_READER_ATTENTION;
|
|
smartcardRequest->Buffer[smartcardRequest->BufferLength++] =
|
|
LIT220_READER_ATTENTION;
|
|
smartcardRequest->Buffer[smartcardRequest->BufferLength++] =
|
|
LIT220_RESET;
|
|
|
|
//
|
|
// Warm reset leads to an ATR
|
|
//
|
|
SmartcardExtension->ReaderExtension->WaitMask |= WAIT_DATA;
|
|
SmartcardExtension->ReaderExtension->WaitForATR = TRUE;
|
|
break;
|
|
|
|
case SCARD_POWER_DOWN:
|
|
//
|
|
// Send a power down to the reader
|
|
//
|
|
smartcardRequest->Buffer[smartcardRequest->BufferLength++] =
|
|
LIT220_READER_ATTENTION;
|
|
smartcardRequest->Buffer[smartcardRequest->BufferLength++] =
|
|
LIT220_READER_ATTENTION;
|
|
smartcardRequest->Buffer[smartcardRequest->BufferLength++] =
|
|
LIT220_CARD_POWER_OFF;
|
|
break;
|
|
}
|
|
|
|
// Send the command
|
|
status = Lit220Command(
|
|
SmartcardExtension
|
|
);
|
|
|
|
SmartcardExtension->ReaderExtension->PowerRequest = FALSE;
|
|
|
|
if (status == STATUS_IO_TIMEOUT) {
|
|
status = STATUS_UNRECOGNIZED_MEDIA;
|
|
}
|
|
|
|
if (status == STATUS_SUCCESS) {
|
|
if (SmartcardExtension->MinorIoControlCode == SCARD_POWER_DOWN) {
|
|
KeAcquireSpinLock(&SmartcardExtension->OsData->SpinLock,
|
|
&irql);
|
|
SmartcardExtension->ReaderCapabilities.CurrentState =
|
|
SCARD_PRESENT;
|
|
KeReleaseSpinLock(&SmartcardExtension->OsData->SpinLock,
|
|
irql);
|
|
SmartcardExtension->CardCapabilities.Protocol.Selected =
|
|
SCARD_PROTOCOL_UNDEFINED;
|
|
}
|
|
}
|
|
|
|
SmartcardDebug(
|
|
DEBUG_TRACE,
|
|
("%s!Lit220Power: Exit\n",
|
|
DRIVER_NAME)
|
|
);
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
|
|
|
|
NTSTATUS
|
|
Lit220IoRequest(
|
|
PSMARTCARD_EXTENSION SmartcardExtension
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
The routine handles IO request from the smartcard library.
|
|
It sends the command to card and processes the reply.
|
|
It may also be called from Lit220IoReply is more processing is
|
|
required.
|
|
|
|
Arguments:
|
|
|
|
SmartcardExtension - Pointer to the smart card data struct
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS status;
|
|
LENGTH length;
|
|
// ULONG offset = 0;
|
|
ULONG indx;
|
|
|
|
PAGED_CODE();
|
|
|
|
SmartcardDebug(
|
|
DEBUG_TRACE,
|
|
("%s!Lit220IoRequest: Enter\n",
|
|
DRIVER_NAME)
|
|
);
|
|
|
|
//
|
|
// Tell the lib function how many bytes I need for the prologue
|
|
//
|
|
SmartcardExtension->SmartcardRequest.BufferLength = 5;
|
|
|
|
switch (SmartcardExtension->CardCapabilities.Protocol.Selected) {
|
|
|
|
case SCARD_PROTOCOL_RAW:
|
|
SmartcardDebug(
|
|
DEBUG_DRIVER,
|
|
("%s!Lit220IoRequest - SCARD_PROTOCOL_RAW\n",
|
|
DRIVER_NAME)
|
|
);
|
|
|
|
status = SmartcardRawRequest(
|
|
SmartcardExtension
|
|
);
|
|
break;
|
|
|
|
case SCARD_PROTOCOL_T0:
|
|
SmartcardDebug(
|
|
DEBUG_DRIVER,
|
|
("%s!Lit220IoRequest - SCARD_PROTOCOL_T0\n",
|
|
DRIVER_NAME)
|
|
);
|
|
|
|
status = SmartcardT0Request(
|
|
SmartcardExtension
|
|
);
|
|
break;
|
|
|
|
case SCARD_PROTOCOL_T1:
|
|
SmartcardDebug(
|
|
DEBUG_DRIVER,
|
|
("%s!Lit220IoRequest - SCARD_PROTOCOL_T1\n",
|
|
DRIVER_NAME)
|
|
);
|
|
|
|
|
|
status = SmartcardT1Request(
|
|
SmartcardExtension
|
|
);
|
|
break;
|
|
|
|
default:
|
|
{
|
|
SmartcardDebug(
|
|
DEBUG_ERROR,
|
|
("%s!Lit220IoRequest: Invalid Device Request - protocol selected = %X\n",
|
|
DRIVER_NAME,
|
|
SmartcardExtension->CardCapabilities.Protocol.Selected)
|
|
);
|
|
|
|
status = STATUS_INVALID_DEVICE_REQUEST;
|
|
}
|
|
|
|
}
|
|
|
|
if (status == STATUS_SUCCESS) {
|
|
|
|
// Add the send block command to the front of the buffer
|
|
SmartcardExtension->SmartcardRequest.Buffer[0] =
|
|
LIT220_READER_ATTENTION;
|
|
SmartcardExtension->SmartcardRequest.Buffer[1] =
|
|
LIT220_READER_ATTENTION;
|
|
|
|
SmartcardExtension->SmartcardRequest.Buffer[2] =
|
|
LIT220_SEND_BLOCK;
|
|
|
|
length.l.l0 =
|
|
SmartcardExtension->SmartcardRequest.BufferLength - 5;
|
|
|
|
SmartcardExtension->SmartcardRequest.Buffer[3] =
|
|
length.b.b1;
|
|
|
|
SmartcardExtension->SmartcardRequest.Buffer[4] =
|
|
length.b.b0;
|
|
|
|
// We expect data back from this command
|
|
SmartcardExtension->ReaderExtension->WaitMask |= WAIT_DATA;
|
|
|
|
//
|
|
// Send the command
|
|
//
|
|
status = Lit220Command(
|
|
SmartcardExtension
|
|
);
|
|
}
|
|
|
|
|
|
if (status == STATUS_SUCCESS) {
|
|
// Process the reply
|
|
status = Lit220IoReply(
|
|
SmartcardExtension
|
|
);
|
|
}
|
|
|
|
SmartcardDebug(
|
|
DEBUG_TRACE,
|
|
("%s!Lit220IoRequest: Exit - status %X\n",
|
|
DRIVER_NAME,
|
|
status)
|
|
);
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
Lit220IoReply(
|
|
PSMARTCARD_EXTENSION SmartcardExtension
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Handles the reply from a smartcard command.
|
|
If more processing is required it will call Lit220IoRequest
|
|
to send another command.
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS status;
|
|
LENGTH length;
|
|
ULONG indx;
|
|
|
|
PAGED_CODE();
|
|
|
|
// Check which protocol is being used so we know how to respond
|
|
switch (SmartcardExtension->CardCapabilities.Protocol.Selected) {
|
|
|
|
case SCARD_PROTOCOL_RAW:
|
|
SmartcardDebug(
|
|
DEBUG_DRIVER,
|
|
("%s!Lit220IoReply: - SCARD_PROTOCOL_RAW\n",
|
|
DRIVER_NAME)
|
|
);
|
|
|
|
// Let the smartcard lib process the reply
|
|
status = SmartcardRawReply(
|
|
SmartcardExtension
|
|
);
|
|
break;
|
|
|
|
case SCARD_PROTOCOL_T0:
|
|
|
|
SmartcardDebug(
|
|
DEBUG_DRIVER,
|
|
("%s!Lit220IoReply - SCARD_PROTOCOL_T0\n",
|
|
DRIVER_NAME)
|
|
);
|
|
|
|
// The instruction seems to be tagged onto the front of the buffer
|
|
// the smartcard library does not seem to like this so we must shift the buffer.
|
|
for(indx=0;indx<SmartcardExtension->SmartcardReply.BufferLength;indx++){
|
|
SmartcardExtension->SmartcardReply.Buffer[indx] =
|
|
SmartcardExtension->SmartcardReply.Buffer[indx+1];
|
|
}
|
|
|
|
SmartcardExtension->SmartcardReply.BufferLength--;
|
|
|
|
#if DBG // DbgPrint the buffer
|
|
SmartcardDebug(
|
|
DEBUG_DRIVER,
|
|
("%s!Lit220IoReply - Buffer - ",
|
|
DRIVER_NAME)
|
|
);
|
|
for (indx=0; indx<SmartcardExtension->SmartcardReply.BufferLength; indx++){
|
|
SmartcardDebug(
|
|
DEBUG_DRIVER,
|
|
("%X, ",
|
|
SmartcardExtension->SmartcardReply.Buffer[indx])
|
|
);
|
|
}
|
|
SmartcardDebug(
|
|
DEBUG_DRIVER,
|
|
("\n")
|
|
);
|
|
#endif
|
|
|
|
// Let the smartcard lib process the reply
|
|
status = SmartcardT0Reply(
|
|
SmartcardExtension
|
|
);
|
|
|
|
break;
|
|
|
|
case SCARD_PROTOCOL_T1:
|
|
SmartcardDebug(
|
|
DEBUG_DRIVER,
|
|
("%s!Lit220IoReply - SCARD_PROTOCOL_T1\n",
|
|
DRIVER_NAME)
|
|
);
|
|
|
|
// Let the smartcard lib process the reply
|
|
status = SmartcardT1Reply(
|
|
SmartcardExtension
|
|
);
|
|
break;
|
|
|
|
default:
|
|
{
|
|
SmartcardDebug(
|
|
DEBUG_ERROR,
|
|
("%s!Lit220IoRequest: Invalid Device Request2 - protocol selected = %X\n",
|
|
DRIVER_NAME,
|
|
SmartcardExtension->CardCapabilities.Protocol.Selected)
|
|
);
|
|
|
|
return STATUS_INVALID_DEVICE_REQUEST;
|
|
}
|
|
}
|
|
|
|
// If there is more work to be done send out another IoRequest.
|
|
// The smartcard lib should have set up the buffers for the new
|
|
// IO operation.
|
|
if (status == STATUS_MORE_PROCESSING_REQUIRED) {
|
|
|
|
status = Lit220IoRequest(
|
|
SmartcardExtension
|
|
);
|
|
}
|
|
|
|
SmartcardDebug(
|
|
DEBUG_TRACE,
|
|
("%s!Lit220IoReply: - Exit - status %X\n",
|
|
DRIVER_NAME,
|
|
status)
|
|
);
|
|
|
|
return status;
|
|
}
|
|
|