📄 pscrnt.c
字号:
/*++
Copyright (c) 1997 - 1999 SCM Microsystems, Inc.
Module Name:
PscrNT.c
Abstract:
Main Driver Module - NT Version
Author:
Andreas Straub
Revision History:
Andreas Straub 1.00 8/18/1997 Initial Version
Klaus Schuetz 1.01 9/20/1997 Timing changed
Andreas Straub 1.02 9/24/1997 Low Level error handling,
minor bugfixes, clanup
Andreas Straub 1.03 10/8/1997 Timing changed, generic SCM
interface changed
Andreas Straub 1.04 10/18/1997 Interrupt handling changed
Andreas Straub 1.05 10/19/1997 Generic IOCTL's added
Andreas Straub 1.06 10/25/1997 Timeout limit for FW update variable
Andreas Straub 1.07 11/7/1997 Version information added
Klaus Schuetz 1.08 11/10/1997 PnP capabilities added
Klaus Schuetz Cleanup added
--*/
#include <PscrNT.h>
#include <PscrCmd.h>
#include <PscrCB.h>
#include <PscrLog.h>
#include <PscrVers.h>
#pragma alloc_text(INIT, DriverEntry)
#pragma alloc_text(PAGEABLE, PscrAddDevice)
#pragma alloc_text(PAGEABLE, PscrCreateAndStartDevice)
#pragma alloc_text(PAGEABLE, PscrCreateDevice)
#pragma alloc_text(PAGEABLE, PscrStartDevice)
#pragma alloc_text(PAGEABLE, PscrUnloadDriver)
#pragma alloc_text(PAGEABLE, PscrCreateClose)
BOOLEAN DeviceSlot[PSCR_MAX_DEVICE];
NTSTATUS
DriverEntry(
PDRIVER_OBJECT DriverObject,
PUNICODE_STRING RegistryPath
)
/*++
DriverEntry:
entry function of the driver. setup the callbacks for the OS and try to
initialize a device object for every device in the system
Arguments:
DriverObject context of the driver
RegistryPath path to the registry entry for the driver
Return Value:
STATUS_SUCCESS
STATUS_UNSUCCESSFUL
--*/
{
NTSTATUS NTStatus = STATUS_SUCCESS;
ULONG Device;
SmartcardDebug(
DEBUG_TRACE,
( "PSCR!DriverEntry: Enter\n" )
);
// tell the system our entry points
DriverObject->MajorFunction[IRP_MJ_CREATE] =
DriverObject->MajorFunction[IRP_MJ_CLOSE] = PscrCreateClose;
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = PscrDeviceIoControl;
DriverObject->MajorFunction[IRP_MJ_CLEANUP] = PscrCleanup;
DriverObject->MajorFunction[IRP_MJ_PNP] = PscrPnP;
DriverObject->MajorFunction[IRP_MJ_POWER] = PscrPower;
DriverObject->DriverExtension->AddDevice = PscrAddDevice;
DriverObject->DriverUnload = PscrUnloadDriver;
SmartcardDebug(
DEBUG_TRACE,
("PSCR!DriverEntry: Exit %x\n",
NTStatus)
);
return NTStatus;
}
NTSTATUS
PscrAddDevice(
IN PDRIVER_OBJECT DriverObject,
IN PDEVICE_OBJECT PhysicalDeviceObject
)
/*++
Routine Description:
This function is called by the pnp manager. This is used to create
a new device instance.
--*/
{
NTSTATUS status;
UNICODE_STRING vendorNameU, ifdTypeU;
ANSI_STRING vendorNameA, ifdTypeA;
HANDLE regKey = NULL;
PDEVICE_OBJECT DeviceObject = NULL;
SmartcardDebug(
DEBUG_TRACE,
( "PSCR!PscrAddDevice: Enter\n" )
);
try {
ULONG DeviceInstance;
UNICODE_STRING DriverID;
PDEVICE_EXTENSION DeviceExtension;
PREADER_EXTENSION ReaderExtension;
PSMARTCARD_EXTENSION SmartcardExtension;
RTL_QUERY_REGISTRY_TABLE parameters[3];
RtlZeroMemory(parameters, sizeof(parameters));
RtlZeroMemory(&vendorNameU, sizeof(vendorNameU));
RtlZeroMemory(&ifdTypeU, sizeof(ifdTypeU));
RtlZeroMemory(&vendorNameA, sizeof(vendorNameA));
RtlZeroMemory(&ifdTypeA, sizeof(ifdTypeA));
for( DeviceInstance = 0; DeviceInstance < PSCR_MAX_DEVICE; DeviceInstance++ )
{
if (DeviceSlot[DeviceInstance] == FALSE) {
DeviceSlot[DeviceInstance] = TRUE;
break;
}
}
if (DeviceInstance == PSCR_MAX_DEVICE) {
status = STATUS_INSUFFICIENT_RESOURCES;
leave;
}
// Create the device object
status = IoCreateDevice(
DriverObject,
sizeof(DEVICE_EXTENSION),
NULL,
FILE_DEVICE_SMARTCARD,
0,
TRUE,
&DeviceObject
);
if (status != STATUS_SUCCESS) {
SmartcardLogError(
DriverObject,
PSCR_INSUFFICIENT_RESOURCES,
NULL,
0
);
leave;
}
// set up the device extension.
DeviceExtension = DeviceObject->DeviceExtension;
SmartcardExtension = &DeviceExtension->SmartcardExtension;
// initialize the DPC routine
KeInitializeDpc(
&DeviceExtension->DpcObject,
PscrDpcRoutine,
DeviceObject
);
KeInitializeSpinLock(&DeviceExtension->SpinLock);
// Used for device removal notification
KeInitializeEvent(
&DeviceExtension->ReaderRemoved,
NotificationEvent,
FALSE
);
// Used for stop / start notification
KeInitializeEvent(
&DeviceExtension->ReaderStarted,
NotificationEvent,
FALSE
);
// allocate the reader extension
ReaderExtension = ExAllocatePool(
NonPagedPool,
sizeof( READER_EXTENSION )
);
if( ReaderExtension == NULL ) {
SmartcardLogError(
DriverObject,
PSCR_INSUFFICIENT_RESOURCES,
NULL,
0
);
status = STATUS_INSUFFICIENT_RESOURCES;
leave;
}
RtlZeroMemory( ReaderExtension, sizeof( READER_EXTENSION ));
SmartcardExtension->ReaderExtension = ReaderExtension;
// setup smartcard extension - callback's
SmartcardExtension->ReaderFunction[RDF_CARD_POWER] = CBCardPower;
SmartcardExtension->ReaderFunction[RDF_TRANSMIT] = CBTransmit;
SmartcardExtension->ReaderFunction[RDF_CARD_TRACKING] = CBCardTracking;
SmartcardExtension->ReaderFunction[RDF_SET_PROTOCOL] = CBSetProtocol;
SmartcardExtension->ReaderFunction[RDF_IOCTL_VENDOR] = PscrGenericIOCTL;
// setup smartcard extension - vendor attribute
RtlCopyMemory(
SmartcardExtension->VendorAttr.VendorName.Buffer,
PSCR_VENDOR_NAME,
sizeof( PSCR_VENDOR_NAME )
);
SmartcardExtension->VendorAttr.VendorName.Length =
sizeof( PSCR_VENDOR_NAME );
RtlCopyMemory(
SmartcardExtension->VendorAttr.IfdType.Buffer,
PSCR_IFD_TYPE,
sizeof( PSCR_IFD_TYPE )
);
SmartcardExtension->VendorAttr.IfdType.Length =
sizeof( PSCR_IFD_TYPE );
SmartcardExtension->VendorAttr.UnitNo =
DeviceInstance;
SmartcardExtension->VendorAttr.IfdVersion.BuildNumber = 0;
// store firmware revision in ifd version
SmartcardExtension->VendorAttr.IfdVersion.VersionMajor =
ReaderExtension->FirmwareMajor;
SmartcardExtension->VendorAttr.IfdVersion.VersionMinor =
ReaderExtension->FirmwareMinor;
SmartcardExtension->VendorAttr.IfdSerialNo.Length = 0;
// setup smartcard extension - reader capabilities
SmartcardExtension->ReaderCapabilities.SupportedProtocols =
SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1;
SmartcardExtension->ReaderCapabilities.ReaderType =
SCARD_READER_TYPE_PCMCIA;
SmartcardExtension->ReaderCapabilities.MechProperties = 0;
SmartcardExtension->ReaderCapabilities.Channel = 0;
SmartcardExtension->ReaderCapabilities.CLKFrequency.Default = 4000;
SmartcardExtension->ReaderCapabilities.CLKFrequency.Max = 4000;
SmartcardExtension->ReaderCapabilities.DataRate.Default = 10750;
SmartcardExtension->ReaderCapabilities.DataRate.Max = 10750;
// enter correct version of the lib
SmartcardExtension->Version = SMCLIB_VERSION;
SmartcardExtension->SmartcardRequest.BufferSize = MIN_BUFFER_SIZE;
SmartcardExtension->SmartcardReply.BufferSize = MIN_BUFFER_SIZE;
SmartcardExtension->ReaderExtension->ReaderPowerState =
PowerReaderWorking;
status = SmartcardInitialize(SmartcardExtension);
if (status != STATUS_SUCCESS) {
SmartcardLogError(
DriverObject,
PSCR_INSUFFICIENT_RESOURCES,
NULL,
0
);
leave;
}
// tell the lib our device object
SmartcardExtension->OsData->DeviceObject = DeviceObject;
DeviceExtension->AttachedPDO = IoAttachDeviceToDeviceStack(
DeviceObject,
PhysicalDeviceObject
);
if (DeviceExtension->AttachedPDO == NULL) {
status = STATUS_UNSUCCESSFUL;
leave;
}
// register our new device
status = IoRegisterDeviceInterface(
PhysicalDeviceObject,
&SmartCardReaderGuid,
NULL,
&DeviceExtension->DeviceName
);
ASSERT(status == STATUS_SUCCESS);
DeviceObject->Flags |= DO_BUFFERED_IO;
DeviceObject->Flags |= DO_POWER_PAGABLE;
DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
//
// try to read the reader name from the registry
// if that does not work, we will use the default
// (hardcoded) name
//
if (IoOpenDeviceRegistryKey(
PhysicalDeviceObject,
PLUGPLAY_REGKEY_DEVICE,
KEY_READ,
®Key
) != STATUS_SUCCESS) {
leave;
}
parameters[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
parameters[0].Name = L"VendorName";
parameters[0].EntryContext = &vendorNameU;
parameters[0].DefaultType = REG_SZ;
parameters[0].DefaultData = &vendorNameU;
parameters[0].DefaultLength = 0;
parameters[1].Flags = RTL_QUERY_REGISTRY_DIRECT;
parameters[1].Name = L"IfdType";
parameters[1].EntryContext = &ifdTypeU;
parameters[1].DefaultType = REG_SZ;
parameters[1].DefaultData = &ifdTypeU;
parameters[1].DefaultLength = 0;
if (RtlQueryRegistryValues(
RTL_REGISTRY_HANDLE,
(PWSTR) regKey,
parameters,
NULL,
NULL
) != STATUS_SUCCESS) {
leave;
}
if (RtlUnicodeStringToAnsiString(
&vendorNameA,
&vendorNameU,
TRUE
) != STATUS_SUCCESS) {
leave;
}
if (RtlUnicodeStringToAnsiString(
&ifdTypeA,
&ifdTypeU,
TRUE
) != STATUS_SUCCESS) {
leave;
}
if (vendorNameA.Length == 0 ||
vendorNameA.Length > MAXIMUM_ATTR_STRING_LENGTH ||
ifdTypeA.Length == 0 ||
ifdTypeA.Length > MAXIMUM_ATTR_STRING_LENGTH) {
leave;
}
RtlCopyMemory(
SmartcardExtension->VendorAttr.VendorName.Buffer,
vendorNameA.Buffer,
vendorNameA.Length
);
SmartcardExtension->VendorAttr.VendorName.Length =
vendorNameA.Length;
RtlCopyMemory(
SmartcardExtension->VendorAttr.IfdType.Buffer,
ifdTypeA.Buffer,
ifdTypeA.Length
);
SmartcardExtension->VendorAttr.IfdType.Length =
ifdTypeA.Length;
}
finally {
if (vendorNameU.Buffer) {
RtlFreeUnicodeString(&vendorNameU);
}
if (ifdTypeU.Buffer) {
RtlFreeUnicodeString(&ifdTypeU);
}
if (vendorNameA.Buffer) {
RtlFreeAnsiString(&vendorNameA);
}
if (ifdTypeA.Buffer) {
RtlFreeAnsiString(&ifdTypeA);
}
if (regKey != NULL) {
ZwClose(regKey);
}
if (status != STATUS_SUCCESS) {
PscrUnloadDevice(DeviceObject);
}
SmartcardDebug(
DEBUG_TRACE,
( "PSCR!PscrAddDevice: Exit %x\n",
status)
);
return status;
}
}
NTSTATUS
PscrCallPcmciaDriver(
IN PDEVICE_OBJECT AttachedPDO,
IN PIRP Irp
)
/*++
Routine Description:
Send an Irp to the pcmcia driver and wait until the pcmcia driver has
finished the request.
To make sure that the pcmcia driver will not complete the Irp we first
initialize an event and set our own completion routine for the Irp.
When the pcmcia driver has processed the Irp the completion routine will
set the event and tell the IO manager that more processing is required.
By waiting for the event we make sure that we continue only if the pcmcia
driver has processed the Irp completely.
Return Value:
status returned by the pcmcia driver
--*/
{
NTSTATUS status = STATUS_SUCCESS;
KEVENT Event;
// Copy our stack location to the next.
IoCopyCurrentIrpStackLocationToNext(Irp);
//
// initialize an event for process synchronization. the event is passed
// to our completion routine and will be set if the pcmcia driver is done
//
KeInitializeEvent(
&Event,
NotificationEvent,
FALSE
);
// Our IoCompletionRoutine sets only our event
IoSetCompletionRoutine (
Irp,
PscrPcmciaCallComplete,
&Event,
TRUE,
TRUE,
TRUE
);
if (IoGetCurrentIrpStackLocation(Irp)->MajorFunction == IRP_MJ_POWER) {
status = PoCallDriver(AttachedPDO, Irp);
} else {
// Call the serial driver
status = IoCallDriver(AttachedPDO, Irp);
}
// Wait until the pcmcia driver has processed the Irp
if (status == STATUS_PENDING) {
status = KeWaitForSingleObject(
&Event,
Executive,
KernelMode,
FALSE,
NULL
);
if (status == STATUS_SUCCESS) {
status = Irp->IoStatus.Status;
}
}
return status;
}
NTSTATUS
PscrPcmciaCallComplete (
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PKEVENT Event
)
/*++
Routine Description:
Completion routine for an Irp sent to the pcmcia driver. The event will
be set to notify that the pcmcia driver is done. The routine will not
'complete' the Irp, so the caller of PscrCallPcmciaDriver can continue.
--*/
{
UNREFERENCED_PARAMETER (DeviceObject);
if (Irp->Cancel) {
Irp->IoStatus.Status = STATUS_CANCELLED;
}
KeSetEvent (Event, 0, FALSE);
return STATUS_MORE_PROCESSING_REQUIRED;
}
NTSTATUS
PscrPnP(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
/*++
Routine Description:
driver callback for pnp manager
All other requests will be passed to the pcmcia driver to ensure correct processing.
--*/
{
NTSTATUS status = STATUS_SUCCESS;
PDEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
PIO_STACK_LOCATION IrpStack;
PDEVICE_OBJECT AttachedPDO;
BOOLEAN deviceRemoved = FALSE, irpSkipped = FALSE;
KIRQL irql;
LARGE_INTEGER timeout;
SmartcardDebug(
DEBUG_TRACE,
( "PSCR!PscrPnPDeviceControl: Enter\n" )
);
status = SmartcardAcquireRemoveLock(&DeviceExtension->SmartcardExtension);
ASSERT(status == STATUS_SUCCESS);
if (status != STATUS_SUCCESS) {
Irp->IoStatus.Information = 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -