📄 tlp3nt.c
字号:
// a) The serial driver can't be used without opening it
// b) The call will go through serenum first which informs
// it to stop looking/polling for new devices.
//
irp->UserIosb = &ioStatusBlock;
IoSetNextIrpStackLocation(irp);
irpStack = IoGetCurrentIrpStackLocation(irp);
irpStack->MajorFunction = IRP_MJ_CREATE;
irpStack->Parameters.Create.Options = 0;
irpStack->Parameters.Create.ShareAccess = 0;
irpStack->Parameters.Create.FileAttributes = 0;
irpStack->Parameters.Create.EaLength = 0;
status = TLP3CallSerialDriver(
ATTACHED_DEVICE_OBJECT,
irp
);
if (status != STATUS_SUCCESS) {
leave;
}
KeClearEvent(&READER_EXTENSION_L(SerialCloseDone));
status = TLP3ConfigureSerialPort(&deviceExtension->SmartcardExtension);
if (status != STATUS_SUCCESS) {
leave;
}
status = TLP3StartSerialEventTracking(
&deviceExtension->SmartcardExtension
);
if (status != STATUS_SUCCESS) {
leave;
}
status = IoSetDeviceInterfaceState(
&deviceExtension->PnPDeviceName,
TRUE
);
if (status != STATUS_SUCCESS) {
leave;
}
KeSetEvent(&deviceExtension->ReaderStarted, 0, FALSE);
}
_finally {
if (status == STATUS_SHARED_IRQ_BUSY) {
SmartcardLogError(
DeviceObject,
TLP3_IRQ_BUSY,
NULL,
status
);
}
if (status != STATUS_SUCCESS) {
TLP3StopDevice(DeviceObject);
}
IoFreeIrp(irp);
}
SmartcardDebug(
DEBUG_TRACE,
( "%s!TLP3StartDevice: Exit %lx\n",
DRIVER_NAME,
status)
);
return status;
}
VOID
TLP3StopDevice(
IN PDEVICE_OBJECT DeviceObject
)
/*++
Routine Description:
Finishes card tracking requests and closes the connection to the
serial driver.
--*/
{
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
PSMARTCARD_EXTENSION smartcardExtension = &deviceExtension->SmartcardExtension;
SmartcardDebug(
DEBUG_TRACE,
( "%s!TLP3StopDevice: Enter\n",
DRIVER_NAME)
);
if (KeReadStateEvent(&READER_EXTENSION_L(SerialCloseDone)) == 0l) {
NTSTATUS status;
PUCHAR requestBuffer;
PSMARTCARD_EXTENSION smartcardExtension =
&deviceExtension->SmartcardExtension;
// test if we ever started event tracking
if (smartcardExtension->ReaderExtension->SerialConfigData.SerialWaitMask == 0) {
// no, we did not
// We 'only' need to close the serial port
TLP3CloseSerialPort(DeviceObject, NULL);
} else {
//
// We now inform the serial driver that we're not longer
// interested in serial events. This will also free the irp
// we use for those io-completions
//
smartcardExtension->ReaderExtension->SerialConfigData.SerialWaitMask = 0;
// save the pointer
requestBuffer = smartcardExtension->SmartcardRequest.Buffer;
*(PULONG) smartcardExtension->SmartcardRequest.Buffer =
smartcardExtension->ReaderExtension->SerialConfigData.SerialWaitMask;
smartcardExtension->SmartcardRequest.BufferLength = sizeof(ULONG);
smartcardExtension->ReaderExtension->SerialIoControlCode =
IOCTL_SERIAL_SET_WAIT_MASK;
// We don't expect to get bytes back
smartcardExtension->SmartcardReply.BufferLength = 0;
TLP3SerialIo(smartcardExtension);
// restore the pointer
smartcardExtension->SmartcardRequest.Buffer = requestBuffer;
// now wait until the connetion to serial is closed
status = KeWaitForSingleObject(
&READER_EXTENSION_L(SerialCloseDone),
Executive,
KernelMode,
FALSE,
NULL
);
ASSERT(status == STATUS_SUCCESS);
}
}
SmartcardDebug(
DEBUG_TRACE,
( "%s!TLP3StopDevice: Exit\n",
DRIVER_NAME)
);
}
NTSTATUS
TLP3SystemControl(
PDEVICE_OBJECT DeviceObject,
PIRP Irp
)
/*++
--*/
{
PDEVICE_EXTENSION DeviceExtension;
NTSTATUS status = STATUS_SUCCESS;
DeviceExtension = DeviceObject->DeviceExtension;
IoSkipCurrentIrpStackLocation(Irp);
status = IoCallDriver(DeviceExtension->SmartcardExtension.ReaderExtension->AttachedDeviceObject, Irp);
return status;
}
NTSTATUS
TLP3DeviceControl(
PDEVICE_OBJECT DeviceObject,
PIRP Irp
)
/*++
Routine Description:
This is our IOCTL dispatch function
--*/
{
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
PSMARTCARD_EXTENSION smartcardExtension = &deviceExtension->SmartcardExtension;
NTSTATUS status = STATUS_SUCCESS;
KIRQL irql;
#ifdef SIMULATION
RTL_QUERY_REGISTRY_TABLE parameters[2];
#endif
SmartcardDebug(
DEBUG_TRACE,
( "%s!TLP3DeviceControl: Enter\n",
DRIVER_NAME)
);
if (smartcardExtension->ReaderExtension->SerialConfigData.SerialWaitMask == 0) {
//
// the wait mask is set to 0 whenever the device was either
// surprise-removed or politely removed
//
status = STATUS_DEVICE_REMOVED;
}
if (status == STATUS_SUCCESS) {
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) {
// the device has been removed. Fail the call
Irp->IoStatus.Information = 0;
Irp->IoStatus.Status = STATUS_DEVICE_REMOVED;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_DEVICE_REMOVED;
}
#ifdef SIMULATION
if (DriverKey) {
ULONG oldLevel =
smartcardExtension->ReaderExtension->SimulationLevel;
RtlZeroMemory(parameters, sizeof(parameters));
parameters[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
parameters[0].Name = L"SimulationLevel";
parameters[0].EntryContext =
&smartcardExtension->ReaderExtension->SimulationLevel;
parameters[0].DefaultType = REG_DWORD;
parameters[0].DefaultData =
&smartcardExtension->ReaderExtension->SimulationLevel;
parameters[0].DefaultLength = sizeof(ULONG);
if (RtlQueryRegistryValues(
RTL_REGISTRY_ABSOLUTE,
DriverKey,
parameters,
NULL,
NULL
) == STATUS_SUCCESS) {
SmartcardDebug(
smartcardExtension->ReaderExtension->SimulationLevel == oldLevel ? 0 : DEBUG_SIMULATION,
( "%s!TLP3AddDevice: SimulationLevel set to %lx\n",
DRIVER_NAME,
smartcardExtension->ReaderExtension->SimulationLevel)
);
}
}
#endif
ASSERT(smartcardExtension->ReaderExtension->ReaderPowerState ==
PowerReaderWorking);
status = SmartcardDeviceControl(
smartcardExtension,
Irp
);
SmartcardReleaseRemoveLockWithTag(smartcardExtension, 'tcoI');
KeAcquireSpinLock(&deviceExtension->SpinLock, &irql);
deviceExtension->IoCount--;
ASSERT(deviceExtension->IoCount >= 0);
KeReleaseSpinLock(&deviceExtension->SpinLock, irql);
SmartcardDebug(
DEBUG_TRACE,
( "%s!TLP3DeviceControl: Exit %lx\n",
DRIVER_NAME,
status)
);
return status;
}
VOID
TLP3CloseSerialPort(
IN PDEVICE_OBJECT DeviceObject,
IN PVOID Context
)
/*++
Routine Description:
This function closes the connection to the serial driver when the reader
has been removed (unplugged). This function runs as a system thread at
IRQL == PASSIVE_LEVEL. It waits for the remove event that is set by
the IoCompletionRoutine
--*/
{
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
PSMARTCARD_EXTENSION smartcardExtension = &deviceExtension->SmartcardExtension;
NTSTATUS status;
PIRP irp;
PIO_STACK_LOCATION irpStack;
IO_STATUS_BLOCK ioStatusBlock;
UNREFERENCED_PARAMETER(Context);
SmartcardDebug(
DEBUG_TRACE,
( "%s!TLP3CloseSerialPort: Enter\n",
DRIVER_NAME)
);
//
// first mark this device as 'gone'.
// This will prevent that someone can re-open the device
// We intentionally ignore possible errors
//
IoSetDeviceInterfaceState(
&deviceExtension->PnPDeviceName,
FALSE
);
irp = IoAllocateIrp(
(CCHAR) (DeviceObject->StackSize + 1),
FALSE
);
ASSERT(irp != NULL);
if (irp) {
SmartcardDebug(
DEBUG_DRIVER,
( "%s!TLP3CloseSerialPort: Sending IRP_MJ_CLOSE\n",
DRIVER_NAME)
);
IoSetNextIrpStackLocation(irp);
//
// We send down a close to the serial driver. This close goes
// through serenum first which will trigger it to start looking
// for changes on the com-port. Since our device is gone it will
// call the device removal event of our PnP dispatch.
//
irp->UserIosb = &ioStatusBlock;
irpStack = IoGetCurrentIrpStackLocation( irp );
irpStack->MajorFunction = IRP_MJ_CLOSE;
status = TLP3CallSerialDriver(
ATTACHED_DEVICE_OBJECT,
irp
);
ASSERT(status == STATUS_SUCCESS);
IoFreeIrp(irp);
}
// now 'signal' that we closed the serial driver
KeSetEvent(
&READER_EXTENSION_L(SerialCloseDone),
0,
FALSE
);
SmartcardDebug(
DEBUG_INFO,
( "%s!TLP3CloseSerialPort: Exit\n",
DRIVER_NAME)
);
}
NTSTATUS
TLP3IoCompletion (
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PKEVENT Event
)
{
UNREFERENCED_PARAMETER (DeviceObject);
if (Irp->Cancel) {
Irp->IoStatus.Status = STATUS_CANCELLED;
} else {
Irp->IoStatus.Status = STATUS_MORE_PROCESSING_REQUIRED;
}
KeSetEvent (Event, 0, FALSE);
return STATUS_MORE_PROCESSING_REQUIRED;
}
NTSTATUS
TLP3CallSerialDriver(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
/*++
Routine Description:
Send an Irp to the serial 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 when the serial driver is done
//
KeInitializeEvent(
&Event,
NotificationEvent,
FALSE
);
// Our IoCompletionRoutine sets only our event
IoSetCompletionRoutine (
Irp,
TLP3IoCompletion,
&Event,
TRUE,
TRUE,
TRUE
);
if (IoGetCurrentIrpStackLocation(Irp)->MajorFunction == IRP_MJ_POWER) {
status = PoCallDriver(DeviceObject, Irp);
} else {
// Call the serial driver
status = IoCallDriver(DeviceObject, Irp);
}
// Wait until the serial driver has processed the Irp
if (status == STATUS_PENDING) {
status = KeWaitForSingleObject(
&Event,
Executive,
KernelMode,
FALSE,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -