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

1346 lines
34 KiB
C

/*++
Copyright (C) Microsoft Corporation and Litronic, 1998 - 1999
Module Name:
L220SCR.c - Main module for Driver
Abstract:
Author:
Brian Manahan
Environment:
Kernel mode
Revision History :
--*/
#include <stdio.h>
#include "L220SCR.h"
// Make functions pageable
#pragma alloc_text(PAGEABLE, Lit220IsCardPresent)
#pragma alloc_text(PAGEABLE, Lit220Initialize)
#pragma alloc_text(PAGEABLE, Lit220ConfigureSerialPort)
#pragma alloc_text(PAGEABLE, Lit220CreateClose)
#pragma alloc_text(PAGEABLE, Lit220Unload)
#pragma alloc_text(PAGEABLE, Lit220InitializeInputFilter)
#if DBG
#pragma optimize ("", off)
#endif
BOOLEAN
Lit220IsCardPresent(
IN PSMARTCARD_EXTENSION SmartcardExtension
)
/*++
Routine Description:
This routine checks if a card is in the socket. It is only done
when the driver starts to set the intial state. After that the
reader will tell us when the status changes.
It makes synchronous calls to the serial port.
--*/
{
PSMARTCARD_REQUEST smartcardRequest = &SmartcardExtension->SmartcardRequest;
NTSTATUS status;
PAGED_CODE();
SmartcardDebug(
DEBUG_TRACE,
("%s!Lit220IsCardPresent: Enter\n",
DRIVER_NAME)
);
smartcardRequest->BufferLength = 0;
//
// Send a get reader status to see if a card is inserted
//
smartcardRequest->Buffer[smartcardRequest->BufferLength++] =
LIT220_READER_ATTENTION;
smartcardRequest->Buffer[smartcardRequest->BufferLength++] =
LIT220_READER_ATTENTION;
smartcardRequest->Buffer[smartcardRequest->BufferLength++] =
LIT220_GET_READER_STATUS;
//
// We Expect to get a response
//
SmartcardExtension->ReaderExtension->WaitMask |= WAIT_DATA;
// Send the command
status = Lit220Command(
SmartcardExtension
);
if (status != STATUS_SUCCESS) {
return FALSE;
}
// Check if length is correct
if (SmartcardExtension->SmartcardReply.BufferLength != LIT220_READER_STATUS_LEN) {
SmartcardDebug(
DEBUG_ERROR,
("%s!Lit220IsCardPresent: Reader response - bufLen %X, should be %X\n",
DRIVER_NAME,
SmartcardExtension->SmartcardReply.BufferLength,
LIT220_READER_STATUS_LEN)
);
return FALSE;
}
// Check status byte to see if card is inserted
if (SmartcardExtension->SmartcardReply.Buffer[0] & LIT220_STATUS_CARD_INSERTED) {
SmartcardDebug(
DEBUG_DRIVER,
("%s!Lit220IsCardPresent: Card is inserted\n",
DRIVER_NAME)
);
return TRUE;
}
SmartcardDebug(
DEBUG_DRIVER,
("%s!Lit220IsCardPresent: Card is not inserted\n",
DRIVER_NAME)
);
return FALSE;
}
NTSTATUS
Lit220Initialize(
IN PSMARTCARD_EXTENSION SmartcardExtension
)
/*++
Routine Description:
This routine initializes the reader for use.
It sets up the serial communications, checks to make sure our
reader is attached, checks if a card is inserted or not and
sets up the input filter for receiving bytes from the reader
asynchronously.
--*/
{
PREADER_EXTENSION readerExtension;
NTSTATUS status;
PAGED_CODE();
SmartcardDebug(
DEBUG_TRACE,
("%s!Lit220Initialize: Enter - SmartcardExtension %X\n",
DRIVER_NAME,
SmartcardExtension)
);
readerExtension = SmartcardExtension->ReaderExtension;
//
// Set the serial config data
//
// We always talk to the at 57600 no matter what speed the reader talks to the card
readerExtension->SerialConfigData.BaudRate.BaudRate = 57600;
readerExtension->SerialConfigData.LineControl.StopBits = STOP_BITS_2;
readerExtension->SerialConfigData.LineControl.Parity = EVEN_PARITY;
readerExtension->SerialConfigData.LineControl.WordLength = SERIAL_DATABITS_8;
//
// set timeouts
//
readerExtension->SerialConfigData.Timeouts.ReadIntervalTimeout = 10;
readerExtension->SerialConfigData.Timeouts.ReadTotalTimeoutConstant = 1;
readerExtension->SerialConfigData.Timeouts.ReadTotalTimeoutMultiplier = 1;
//
// set special characters
//
readerExtension->SerialConfigData.SerialChars.ErrorChar = 0;
readerExtension->SerialConfigData.SerialChars.EofChar = 0;
readerExtension->SerialConfigData.SerialChars.EventChar = 0;
readerExtension->SerialConfigData.SerialChars.XonChar = 0;
readerExtension->SerialConfigData.SerialChars.XoffChar = 0;
readerExtension->SerialConfigData.SerialChars.BreakChar = 0xFF;
//
// Set handflow
//
readerExtension->SerialConfigData.HandFlow.XonLimit = 0;
readerExtension->SerialConfigData.HandFlow.XoffLimit = 0;
readerExtension->SerialConfigData.HandFlow.FlowReplace = SERIAL_XOFF_CONTINUE ;
readerExtension->SerialConfigData.HandFlow.ControlHandShake = 0;
//
// Now setup default the card state
//
SmartcardExtension->ReaderCapabilities.CurrentState = (ULONG) SCARD_UNKNOWN;
//
// Set the MechProperties
//
SmartcardExtension->ReaderCapabilities.MechProperties = 0;
try {
//
// Configure the serial port
//
status = Lit220ConfigureSerialPort(
SmartcardExtension
);
if (status != STATUS_SUCCESS) {
SmartcardLogError(
SmartcardExtension->OsData->DeviceObject,
LIT220_SERIAL_COMUNICATION_FAILURE,
NULL,
0
);
SmartcardDebug(DEBUG_ERROR,
("%s!Lit220Initialize: ConfiguringSerialPort failed %X\n",
DRIVER_NAME,
status)
);
leave;
}
//
// Initailize the input filter now
//
status = Lit220InitializeInputFilter(
SmartcardExtension
);
if (status != STATUS_SUCCESS) {
SmartcardLogError(
SmartcardExtension->OsData->DeviceObject,
LIT220_SERIAL_COMUNICATION_FAILURE,
NULL,
0
);
SmartcardDebug(DEBUG_ERROR,
("%s!Lit220Initialize: Lit220InitializeInputFilter failed %X\n",
DRIVER_NAME, status)
);
leave;
}
//
// Now check if the card is inserted
//
if (Lit220IsCardPresent(SmartcardExtension)) {
// Card is inserted
SmartcardExtension->ReaderCapabilities.CurrentState =
SCARD_SWALLOWED;
SmartcardExtension->CardCapabilities.Protocol.Selected =
SCARD_PROTOCOL_UNDEFINED;
SmartcardExtension->ReaderExtension->CardIn = TRUE;
} else {
// Card is not inserted
SmartcardExtension->ReaderCapabilities.CurrentState =
SCARD_ABSENT;
SmartcardExtension->CardCapabilities.Protocol.Selected =
SCARD_PROTOCOL_UNDEFINED;
SmartcardExtension->ReaderExtension->CardIn = FALSE;
}
}
finally
{
SmartcardDebug(DEBUG_TRACE,
("%s!Lit220Initialize: Exit - status %X\n",
DRIVER_NAME, status)
);
}
return status;
}
NTSTATUS
Lit220ConfigureSerialPort(
PSMARTCARD_EXTENSION SmartcardExtension
)
/*++
Routine Description:
This routine will appropriately configure the serial port.
It makes synchronous calls to the serial port.
Arguments:
SmartcardExtension - Pointer to smart card struct
Return Value:
NTSTATUS
--*/
{
PSERIAL_READER_CONFIG configData = &SmartcardExtension->ReaderExtension->SerialConfigData;
NTSTATUS status = STATUS_SUCCESS;
LARGE_INTEGER WaitTime;
PSERIALPERF_STATS perfData;
USHORT indx;
PUCHAR request = SmartcardExtension->SmartcardRequest.Buffer;
PAGED_CODE();
SmartcardExtension->SmartcardRequest.BufferLength = 0;
SmartcardExtension->SmartcardReply.BufferLength =
SmartcardExtension->SmartcardReply.BufferSize;
for (indx = 0; NT_SUCCESS(status); indx++) {
switch (indx) {
case 0:
//
// Set up baudrate for the Lit220 reader
//
SmartcardExtension->ReaderExtension->SerialIoControlCode =
IOCTL_SERIAL_SET_BAUD_RATE;
SmartcardExtension->SmartcardRequest.Buffer =
(PUCHAR) &configData->BaudRate;
SmartcardExtension->SmartcardRequest.BufferLength =
sizeof(SERIAL_BAUD_RATE);
break;
case 1:
//
// Set up line control parameters
//
SmartcardExtension->ReaderExtension->SerialIoControlCode =
IOCTL_SERIAL_SET_LINE_CONTROL;
SmartcardExtension->SmartcardRequest.Buffer =
(PUCHAR) &configData->LineControl;
SmartcardExtension->SmartcardRequest.BufferLength =
sizeof(SERIAL_LINE_CONTROL);
break;
case 2:
//
// Set serial special characters
//
SmartcardExtension->ReaderExtension->SerialIoControlCode =
IOCTL_SERIAL_SET_CHARS;
SmartcardExtension->SmartcardRequest.Buffer =
(PUCHAR) &configData->SerialChars;
SmartcardExtension->SmartcardRequest.BufferLength =
sizeof(SERIAL_CHARS);
break;
case 3:
//
// Set up timeouts
//
SmartcardExtension->ReaderExtension->SerialIoControlCode =
IOCTL_SERIAL_SET_TIMEOUTS;
SmartcardExtension->SmartcardRequest.Buffer =
(PUCHAR) &configData->Timeouts;
SmartcardExtension->SmartcardRequest.BufferLength =
sizeof(SERIAL_TIMEOUTS);
break;
case 4:
//
// Set flowcontrol and handshaking
//
SmartcardExtension->ReaderExtension->SerialIoControlCode =
IOCTL_SERIAL_SET_HANDFLOW;
SmartcardExtension->SmartcardRequest.Buffer =
(PUCHAR) &configData->HandFlow;
SmartcardExtension->SmartcardRequest.BufferLength =
sizeof(SERIAL_HANDFLOW);
break;
case 5:
//
// Set break off
//
SmartcardExtension->ReaderExtension->SerialIoControlCode =
IOCTL_SERIAL_SET_BREAK_OFF;
break;
case 6:
SmartcardExtension->ReaderExtension->SerialIoControlCode =
IOCTL_SERIAL_SET_DTR;
break;
case 7:
// 500ms delay before we send the next command
// To give the reader a chance to calm down after we started it.
WaitTime.HighPart = -1;
WaitTime.LowPart = -500 * 10000;
KeDelayExecutionThread(
KernelMode,
FALSE,
&WaitTime
);
// Clear possible error condition with the serial port
perfData =
(PSERIALPERF_STATS) SmartcardExtension->SmartcardReply.Buffer;
// we have to call GetCommStatus to reset the error condition
SmartcardExtension->ReaderExtension->SerialIoControlCode =
IOCTL_SERIAL_GET_COMMSTATUS;
SmartcardExtension->SmartcardRequest.BufferLength = 0;
SmartcardExtension->SmartcardReply.BufferLength =
sizeof(SERIAL_STATUS);
break;
case 8:
return STATUS_SUCCESS;
}
// Send the command to the serial driver
status = Lit220SerialIo(SmartcardExtension);
//
// restore pointer to original request buffer
//
SmartcardExtension->SmartcardRequest.Buffer = request;
}
return status;
}
NTSTATUS
Lit220CreateClose(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
/*++
Routine Description:
This routine is called by the I/O system when the device is opened or closed.
Arguments:
DeviceObject - Pointer to device object for this miniport
Irp - IRP involved.
Return Value:
STATUS_SUCCESS.
--*/
{
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
NTSTATUS status = STATUS_SUCCESS;
if (irpStack->MajorFunction == IRP_MJ_CREATE) {
status = SmartcardAcquireRemoveLockWithTag(
&deviceExtension->SmartcardExtension,
'lCrC'
);
if (status != STATUS_SUCCESS) {
status = STATUS_DEVICE_REMOVED;
} else {
// test if the device has been opened already
if (InterlockedCompareExchange(
&deviceExtension->ReaderOpen,
TRUE,
FALSE) == FALSE) {
SmartcardDebug(
DEBUG_DRIVER,
("%s!Lit220CreateClose: Open\n",
DRIVER_NAME)
);
} else {
// the device is already in use
status = STATUS_UNSUCCESSFUL;
// release the lock
SmartcardReleaseRemoveLockWithTag(
&deviceExtension->SmartcardExtension,
'lCrC'
);
}
}
} else {
SmartcardDebug(
DEBUG_DRIVER,
("%s!Lit220CreateClose: Close\n",
DRIVER_NAME)
);
SmartcardReleaseRemoveLockWithTag(
&deviceExtension->SmartcardExtension,
'lCrC'
);
deviceExtension->ReaderOpen = FALSE;
}
Irp->IoStatus.Status = status;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return status;
}
NTSTATUS
Lit220Cancel(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
/*++
Routine Description:
This routine is called by the I/O system
when the irp should be cancelled
Arguments:
DeviceObject - Pointer to device object for this miniport
Irp - IRP involved.
Return Value:
STATUS_CANCELLED
--*/
{
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
PSMARTCARD_EXTENSION smartcardExtension = &deviceExtension->SmartcardExtension;
SmartcardDebug(
DEBUG_TRACE,
("%s!Lit220Cancel: Enter\n",
DRIVER_NAME)
);
ASSERT(Irp == smartcardExtension->OsData->NotificationIrp);
IoReleaseCancelSpinLock(
Irp->CancelIrql
);
Lit220CompleteCardTracking(
smartcardExtension
);
SmartcardDebug(
DEBUG_TRACE,
("%s!Lit220Cancel: Exit\n",
DRIVER_NAME)
);
return STATUS_CANCELLED;
}
NTSTATUS
Lit220Cleanup(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
/*++
Routine Description:
This routine is called by the I/O system when the calling thread terminates
or when the irp should be cancelled
Arguments:
DeviceObject - Pointer to device object for this miniport
Irp - IRP involved.
Return Value:
STATUS_CANCELLED
--*/
{
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
PSMARTCARD_EXTENSION smartcardExtension = &deviceExtension->SmartcardExtension;
PREADER_EXTENSION ReaderExtension = smartcardExtension->ReaderExtension;
NTSTATUS status = STATUS_SUCCESS;
KIRQL oldOsDataIrql;
SmartcardDebug(
DEBUG_TRACE,
("%s!Lit220Cleanup: Enter\n",
DRIVER_NAME)
);
Lit220CompleteCardTracking(smartcardExtension);
SmartcardDebug(
DEBUG_DRIVER,
("%s!Lit220Cleanup: Completing IRP %lx\n",
DRIVER_NAME,
Irp)
);
Irp->IoStatus.Information = 0;
Irp->IoStatus.Status = STATUS_SUCCESS;
IoCompleteRequest(
Irp,
IO_NO_INCREMENT
);
SmartcardDebug(
DEBUG_TRACE,
("%s!Lit220Cleanup: Exit\n",
DRIVER_NAME)
);
return STATUS_SUCCESS;
}
VOID
Lit220Unload(
IN PDRIVER_OBJECT DriverObject
)
/*++
Routine Description:
The driver unload routine. This is called by the I/O system
when the device is unloaded from memory.
Arguments:
DriverObject - Pointer to driver object created by system.
Return Value:
STATUS_SUCCESS.
--*/
{
PDEVICE_OBJECT deviceObject = DriverObject->DeviceObject;
NTSTATUS status;
PAGED_CODE();
SmartcardDebug(
DEBUG_TRACE,
("%s!Lit220Unload: Enter\n",
DRIVER_NAME)
);
//
// All the device objects should be gone.
//
ASSERT (NULL == DriverObject->DeviceObject);
//
// Here we free any resources allocated in DriverEntry
//
SmartcardDebug(
DEBUG_TRACE,
("%s!Lit220Unload: Exit\n",
DRIVER_NAME)
);
}
NTSTATUS
Lit220SerialIo(
IN PSMARTCARD_EXTENSION SmartcardExtension
)
/*++
Routine Description:
This routine sends IOCTL's to the serial driver. It waits on for their
completion, and then returns.
Arguments:
Return Value:
NTSTATUS
--*/
{
NTSTATUS status;
ULONG currentByte = 0;
DWORD indx;
PDEVICE_EXTENSION devExt = SmartcardExtension->OsData->DeviceObject->DeviceExtension;
if (KeReadStateEvent(&devExt->SerialCloseDone)) {
//
// we have no connection to serial, fail the call
// this could be the case if the reader was removed
// during stand by / hibernation
//
return STATUS_UNSUCCESSFUL;
}
//
// Check if the buffers are large enough
//
ASSERT(SmartcardExtension->SmartcardReply.BufferLength <=
SmartcardExtension->SmartcardReply.BufferSize);
ASSERT(SmartcardExtension->SmartcardRequest.BufferLength <=
SmartcardExtension->SmartcardRequest.BufferSize);
if (SmartcardExtension->SmartcardReply.BufferLength >
SmartcardExtension->SmartcardReply.BufferSize ||
SmartcardExtension->SmartcardRequest.BufferLength >
SmartcardExtension->SmartcardRequest.BufferSize) {
SmartcardLogError(
SmartcardExtension->OsData->DeviceObject,
LIT220_BUFFER_TOO_SMALL,
NULL,
0
);
return STATUS_BUFFER_TOO_SMALL;
}
do {
IO_STATUS_BLOCK ioStatus;
KEVENT event;
PIRP irp;
PIO_STACK_LOCATION irpNextStack;
PUCHAR requestBuffer = NULL;
PUCHAR replyBuffer = SmartcardExtension->SmartcardReply.Buffer;
ULONG requestBufferLength = 0;
ULONG replyBufferLength = SmartcardExtension->SmartcardReply.BufferLength;
KeInitializeEvent(
&event,
NotificationEvent,
FALSE
);
if (SmartcardExtension->ReaderExtension->SerialIoControlCode ==
IOCTL_SMARTCARD_220_WRITE) {
//
// If we write data to the smart card we only write byte by byte,
// because we have to insert a delay between every sent byte
//
requestBufferLength =
SmartcardExtension->SmartcardRequest.BufferLength;
requestBuffer =
SmartcardExtension->SmartcardRequest.Buffer;
#if DBG // DbgPrint the buffer
SmartcardDebug(
DEBUG_DRIVER,
("%s!Lit220SerialIo - Sending Buffer - ",
DRIVER_NAME)
);
for (indx=0; indx<requestBufferLength; indx++){
SmartcardDebug(
DEBUG_DRIVER,
("%X, ",
requestBuffer[indx])
);
}
SmartcardDebug(
DEBUG_DRIVER,
("\n")
);
#endif
} else {
requestBufferLength =
SmartcardExtension->SmartcardRequest.BufferLength;
requestBuffer =
(requestBufferLength ?
SmartcardExtension->SmartcardRequest.Buffer : NULL);
}
//
// Build irp to be sent to serial driver
//
irp = IoBuildDeviceIoControlRequest(
SmartcardExtension->ReaderExtension->SerialIoControlCode,
SmartcardExtension->ReaderExtension->ConnectedSerialPort,
requestBuffer,
requestBufferLength,
replyBuffer,
replyBufferLength,
FALSE,
&event,
&ioStatus
);
ASSERT(irp != NULL);
if (irp == NULL) {
return STATUS_INSUFFICIENT_RESOURCES;
}
irpNextStack = IoGetNextIrpStackLocation(irp);
switch (SmartcardExtension->ReaderExtension->SerialIoControlCode) {
//
// The serial driver trasfers data from/to irp->AssociatedIrp.SystemBuffer
//
case IOCTL_SMARTCARD_220_WRITE:
irpNextStack->MajorFunction = IRP_MJ_WRITE;
irpNextStack->Parameters.Write.Length =
SmartcardExtension->SmartcardRequest.BufferLength;
break;
case IOCTL_SMARTCARD_220_READ:
irpNextStack->MajorFunction = IRP_MJ_READ;
irpNextStack->Parameters.Read.Length =
SmartcardExtension->SmartcardReply.BufferLength;
break;
}
// Send the command to the serial driver
status = IoCallDriver(
SmartcardExtension->ReaderExtension->ConnectedSerialPort,
irp
);
if (status == STATUS_PENDING) {
// Wait for the command to complete
KeWaitForSingleObject(
&event,
Suspended,
KernelMode,
FALSE,
NULL
);
status = ioStatus.Status;
}
} while (status == STATUS_MORE_PROCESSING_REQUIRED);
return status;
}
NTSTATUS
Lit220InitializeInputFilter(
PSMARTCARD_EXTENSION SmartcardExtension
)
/*++
Routine Description:
This routine initialized input filter. It calls the serial driver to
set a wait mask for character input or DSR change. After that it installs a completion
routine to be called when a character is received or when DSR changes.
The completion routine for the wait is Lit220SerialEventCallback and that IRP will
run until the device is ready to be removed.
Arguments:
SmartcardExtension - Pointer to our smartcard structure
Return Value:
NTSTATUS
--*/
{
NTSTATUS status;
PREADER_EXTENSION readerExtension = SmartcardExtension->ReaderExtension;
PAGED_CODE();
// Set the WaitMask
SmartcardExtension->ReaderExtension->SerialConfigData.WaitMask =
SERIAL_EV_RXCHAR | SERIAL_EV_DSR;
KeInitializeEvent(
&SmartcardExtension->ReaderExtension->CardStatus.Event,
NotificationEvent,
FALSE
);
try {
//
// Send a wait mask to the serial driver.
// This call only sets the wait mask.
// We want to be informed if a character is received
//
SmartcardExtension->ReaderExtension->CardStatus.Irp = IoBuildDeviceIoControlRequest(
IOCTL_SERIAL_SET_WAIT_MASK,
SmartcardExtension->ReaderExtension->ConnectedSerialPort,
&SmartcardExtension->ReaderExtension->SerialConfigData.WaitMask,
sizeof(SmartcardExtension->ReaderExtension->SerialConfigData.WaitMask),
NULL,
0,
FALSE,
&(SmartcardExtension->ReaderExtension->CardStatus.Event),
&(SmartcardExtension->ReaderExtension->CardStatus.IoStatus)
);
if (SmartcardExtension->ReaderExtension->CardStatus.Irp == NULL) {
SmartcardDebug(
DEBUG_DRIVER,
("%s!Lit220InitializeCardTracking: Error STATUS_INSUFFICIENT_RESOURCES\n",
DRIVER_NAME);
);
status = STATUS_INSUFFICIENT_RESOURCES;
leave;
}
// Call the serial driver
status = IoCallDriver(
SmartcardExtension->ReaderExtension->ConnectedSerialPort,
SmartcardExtension->ReaderExtension->CardStatus.Irp,
);
if (status == STATUS_SUCCESS) {
KIRQL oldIrql;
LARGE_INTEGER delayPeriod;
PIO_STACK_LOCATION irpSp;
//
// Now tell the serial driver that we want to be informed
// if a character is received or DSR changes
//
readerExtension->CardStatus.Irp = IoAllocateIrp(
(CCHAR) (SmartcardExtension->OsData->DeviceObject->StackSize + 1),
FALSE
);
if (readerExtension->CardStatus.Irp == NULL) {
return STATUS_INSUFFICIENT_RESOURCES;
}
irpSp = IoGetNextIrpStackLocation( readerExtension->CardStatus.Irp );
irpSp->MajorFunction = IRP_MJ_DEVICE_CONTROL;
irpSp->Parameters.DeviceIoControl.InputBufferLength = 0;
irpSp->Parameters.DeviceIoControl.OutputBufferLength =
sizeof(readerExtension->SerialConfigData.WaitMask);
irpSp->Parameters.DeviceIoControl.IoControlCode =
IOCTL_SERIAL_WAIT_ON_MASK;
readerExtension->CardStatus.Irp->AssociatedIrp.SystemBuffer =
&readerExtension->SerialConfigData.WaitMask;
//
// this artificial delay is necessary to make this driver work
// with digi board cards
//
delayPeriod.HighPart = -1;
delayPeriod.LowPart = 100l * 1000 * (-10);
KeDelayExecutionThread(
KernelMode,
FALSE,
&delayPeriod
);
// We simulate a callback now that triggers the card supervision
Lit220SerialEventCallback(
SmartcardExtension->OsData->DeviceObject,
SmartcardExtension->ReaderExtension->CardStatus.Irp,
SmartcardExtension
);
status = STATUS_SUCCESS;
}
}
finally {
if (status != STATUS_SUCCESS) {
SmartcardDebug(
DEBUG_ERROR,
("%s(Lit220InitializeInputFilter): Initialization failed - stauts %X\n",
DRIVER_NAME,
status)
);
// Clear the WaitMask since we did not get the call out that does the wait
SmartcardExtension->ReaderExtension->SerialConfigData.WaitMask =
0;
}
}
return status;
}
NTSTATUS
Lit220SystemControl(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
/*++
Routine Description:
Arguments:
DeviceObject - Pointer to device object for this miniport
Irp - IRP involved.
Return Value:
STATUS_SUCCESS.
--*/
{
PDEVICE_EXTENSION DeviceExtension;
PSMARTCARD_EXTENSION SmartcardExtension;
PREADER_EXTENSION ReaderExtension;
NTSTATUS status = STATUS_SUCCESS;
DeviceExtension = DeviceObject->DeviceExtension;
SmartcardExtension = &DeviceExtension->SmartcardExtension;
ReaderExtension = SmartcardExtension->ReaderExtension;
IoSkipCurrentIrpStackLocation(Irp);
status = IoCallDriver(ReaderExtension->BusDeviceObject, Irp);
return status;
}
NTSTATUS
Lit220DeviceControl(
PDEVICE_OBJECT DeviceObject,
PIRP Irp
)
/*++
Routine Description:
This is the main entry point for the PCSC resource manager.
We pass all commands to the smartcard libary and let the smartcard
library call us directly when needed (If device is ready to receive
calls).
If the device is not ready we will hold the IRP until we get a signal
that it is safe to send IRPs again.
If the device is removed we return an error instead of calling the
smartcard library.
Arguments:
Return Value:
NTSTATUS
--*/
{
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
PSMARTCARD_EXTENSION smartcardExtension = &deviceExtension->SmartcardExtension;
PREADER_EXTENSION ReaderExtension = smartcardExtension->ReaderExtension;
NTSTATUS status;
KIRQL irql;
SmartcardDebug(
DEBUG_DRIVER,
("%s(Lit220DeviceControl): Enter DeviceObject %X, Irp %X\n",
DRIVER_NAME,
DeviceObject,
Irp)
);
if (smartcardExtension->ReaderExtension->SerialConfigData.WaitMask == 0) {
//
// the wait mask is set to 0 whenever the device was either
// surprise-removed or politely removed
//
status = STATUS_DEVICE_REMOVED;
}
// Increment the IRP count
KeAcquireSpinLock(&deviceExtension->SpinLock, &irql);
if (deviceExtension->IoCount == 0) {
KeReleaseSpinLock(&deviceExtension->SpinLock, irql);
status = KeWaitForSingleObject(
&deviceExtension->ReaderStarted,
Executive,
KernelMode,
FALSE,
NULL
);
ASSERT(status == STATUS_SUCCESS);
KeAcquireSpinLock(&deviceExtension->SpinLock, &irql);
}
ASSERT(deviceExtension->IoCount >= 0);
deviceExtension->IoCount++;
KeReleaseSpinLock(&deviceExtension->SpinLock, irql);
status = SmartcardAcquireRemoveLockWithTag(
smartcardExtension,
'tcoI');
if ((status != STATUS_SUCCESS) || (ReaderExtension->DeviceRemoved)) {
// the device has been removed. Fail the call
Irp->IoStatus.Information = 0;
Irp->IoStatus.Status = STATUS_DEVICE_REMOVED;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
SmartcardReleaseRemoveLockWithTag(
smartcardExtension,
'tcoI');
return STATUS_DEVICE_REMOVED;
}
ASSERT(deviceExtension->SmartcardExtension.ReaderExtension->ReaderPowerState ==
PowerReaderWorking);
//
// We are in the common situation where we send the IRP
// to the smartcard lib to handle it.
//
status = SmartcardDeviceControl(
&(deviceExtension->SmartcardExtension),
Irp
);
SmartcardReleaseRemoveLockWithTag(
smartcardExtension,
'tcoI');
// Decrement the IRP count
KeAcquireSpinLock(&deviceExtension->SpinLock, &irql);
deviceExtension->IoCount--;
ASSERT(deviceExtension->IoCount >= 0);
KeReleaseSpinLock(&deviceExtension->SpinLock, irql);
SmartcardDebug(
DEBUG_TRACE,
("%s!Lit220DeviceControl: Exit %X\n",
DRIVER_NAME, status)
);
return status;
}
NTSTATUS
Lit220GetReaderError(
PSMARTCARD_EXTENSION SmartcardExtension
)
/*++
Routine Description:
This routine checks the status of the previous error to determine the
correct error code to return.
The default error is timeout if we cannot determine the error from the
reader.
--*/
{
static ULONG PreventReentry = FALSE;
PSMARTCARD_REQUEST smartcardRequest = &SmartcardExtension->SmartcardRequest;
NTSTATUS status = STATUS_TIMEOUT;
LARGE_INTEGER WaitTime;
KIRQL irql;
// 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!
WaitTime.HighPart = -1;
WaitTime.LowPart = -10 * 1000 * 1000; // Wait 1S for reader to recover from error.
KeDelayExecutionThread(
KernelMode,
FALSE,
&WaitTime
);
// Prevent a nack from this call from recursively calling itself
if (InterlockedExchange(
&PreventReentry,
TRUE))
{
// Default error to timeout if reader keeps failing our calls
return STATUS_TIMEOUT;
}
SmartcardDebug(
DEBUG_TRACE,
("%s!Lit220GetReaderError: Enter\n",
DRIVER_NAME)
);
smartcardRequest->BufferLength = 0;
//
// Send a get reader status to see if a card is inserted
//
smartcardRequest->Buffer[smartcardRequest->BufferLength++] =
LIT220_READER_ATTENTION;
smartcardRequest->Buffer[smartcardRequest->BufferLength++] =
LIT220_READER_ATTENTION;
smartcardRequest->Buffer[smartcardRequest->BufferLength++] =
LIT220_GET_READER_STATUS;
//
// We Expect to get a response
//
SmartcardExtension->ReaderExtension->WaitMask |= WAIT_DATA;
// Send the command
status = Lit220Command(
SmartcardExtension
);
if (status == STATUS_SUCCESS) {
// Check if length is correct
if (SmartcardExtension->SmartcardReply.BufferLength != LIT220_READER_STATUS_LEN) {
// Return a status timeout because the reader failed to respond
status = STATUS_TIMEOUT;
}
if (status == STATUS_SUCCESS) {
// Check the error byte to see if there was a protocol error
// otherwise assume timeout
if (SmartcardExtension->SmartcardReply.Buffer[1] & 0x04) {
status = STATUS_TIMEOUT;
} else {
status = STATUS_DEVICE_PROTOCOL_ERROR;
}
// Check status byte to see if card is inserted
// and send a notification accordingly
if (SmartcardExtension->SmartcardReply.Buffer[0] & LIT220_STATUS_CARD_INSERTED) {
Lit220NotifyCardChange(
SmartcardExtension,
TRUE
);
} else {
Lit220NotifyCardChange(
SmartcardExtension,
FALSE
);
}
}
}
InterlockedExchange(
&PreventReentry,
FALSE);
return status;
}