|
|
/***************************************************************************
Copyright (c) 2002 Microsoft Corporation
Module Name:
SCUTIL.C
Abstract:
Routines for Smartcard Driver Utility Library
Environment:
Kernel Mode Only
Notes:
THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
Copyright (c) 2001 Microsoft Corporation. All Rights Reserved.
Revision History:
05/14/2002 : created
Authors:
Randy Aull
****************************************************************************/
#include "pch.h"
VOID IncIoCount( PSCUTIL_EXTENSION pExt ) { ULONG count; count = InterlockedIncrement(&pExt->IoCount);
KeClearEvent(&pExt->OkToStop);
}
VOID DecIoCount( PSCUTIL_EXTENSION pExt ) { ULONG count;
count = InterlockedDecrement(&pExt->IoCount);
if (count == 0) { KeSetEvent(&pExt->OkToStop, 0, FALSE); }
} VOID StartIoctls( PSCUTIL_EXTENSION pExt ) {
LIST_ENTRY head;
InterlockedExchange(&pExt->IoctlQueueState, PASS_IOCTLS);
pExt->RestartIoctls = TRUE; // Now drain the queued list
InitializeListHead(&head); IrpList_Drain(&pExt->PendingIrpQueue, &head); while (!IsListEmpty(&head)) { PLIST_ENTRY ple; PIRP pIrp; ple = RemoveHeadList(&head); pIrp = CONTAINING_RECORD(ple, IRP, Tail.Overlay.ListEntry);
IncIoCount(pExt); SmartcardDeviceControl(pExt->SmartcardExtension, pIrp); DecIoCount(pExt);
IoReleaseRemoveLock(pExt->RemoveLock, pIrp); } }
VOID StopIoctls( PSCUTIL_EXTENSION pExt ) { InterlockedExchange(&pExt->IoctlQueueState, QUEUE_IOCTLS);
}
VOID FailIoctls( PSCUTIL_EXTENSION pExt ) {
LIST_ENTRY head;
InterlockedExchange(&pExt->IoctlQueueState, FAIL_IOCTLS);
InitializeListHead(&head); IrpList_Drain(&pExt->PendingIrpQueue, &head);
while (!IsListEmpty(&head)) {
PLIST_ENTRY ple; PIRP pIrp;
ple = RemoveHeadList(&head); pIrp = CONTAINING_RECORD(ple, IRP, Tail.Overlay.ListEntry);
IoReleaseRemoveLock(pExt->RemoveLock, pIrp);
pIrp->IoStatus.Information = 0; pIrp->IoStatus.Status = STATUS_DELETE_PENDING; IoCompleteRequest(pIrp, IO_NO_INCREMENT); }
}
QUEUE_STATE GetIoctlQueueState( PSCUTIL_EXTENSION pExt ) {
return InterlockedCompareExchange(&pExt->IoctlQueueState, PASS_IOCTLS, INVALID_STATE);
}
NTSTATUS ScUtil_SystemControl( PDEVICE_OBJECT DeviceObject, PIRP Irp ) /*++
Routine Description: forwards IRP_MJ_SYSTEM_CONTROL
Arguments:
Return Value:
--*/ { PSCUTIL_EXTENSION pExt = *((PSCUTIL_EXTENSION*) DeviceObject->DeviceExtension); NTSTATUS status = STATUS_SUCCESS;
__try { SmartcardDebug( DEBUG_TRACE, ("ScUtilSystemControl Enter\n"));
IoSkipCurrentIrpStackLocation(Irp); status = IoCallDriver(pExt->LowerDeviceObject, Irp);
}
__finally { SmartcardDebug( DEBUG_TRACE, ("ScUtilSystemControl Exit : 0x%x\n",status ));
}
return status; }
NTSTATUS OnRequestComplete( PDEVICE_OBJECT DeviceObject, PIRP Irp, PKEVENT Event ) /*++
Routine Description: Completion routine for UsbScForwardAndWait
Arguments:
Return Value:
--*/ { NTSTATUS status = STATUS_SUCCESS; __try {
SmartcardDebug( DEBUG_TRACE, ("OnRequestComplete Enter\n")); KeSetEvent(Event, 0, FALSE);
status = STATUS_MORE_PROCESSING_REQUIRED;
}
__finally {
SmartcardDebug( DEBUG_TRACE, ("OnRequestComplete Exit : 0x%x\n",status ));
}
return status;
}
NTSTATUS ScUtil_ForwardAndWait( PDEVICE_OBJECT DeviceObject, PIRP Irp ) /*++
Routine Description: Sends an irp down the stack and waits for its completion.
Arguments:
Return Value:
--*/ { KEVENT event; PSCUTIL_EXTENSION pExt = *((PSCUTIL_EXTENSION*) DeviceObject->DeviceExtension); NTSTATUS status = STATUS_UNSUCCESSFUL;
__try {
SmartcardDebug( DEBUG_TRACE, ("ScUtilForwardAndWait Enter\n"));
KeInitializeEvent(&event, NotificationEvent, FALSE);
IoCopyCurrentIrpStackLocationToNext(Irp); IoSetCompletionRoutine(Irp, (PIO_COMPLETION_ROUTINE) OnRequestComplete, (PVOID) &event, TRUE, TRUE, TRUE); ASSERT(pExt->LowerDeviceObject); IoCallDriver(pExt->LowerDeviceObject, Irp); KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
status = Irp->IoStatus.Status;
}
__finally {
SmartcardDebug( DEBUG_TRACE, ("ScUtilForwardAndWait Exit : 0x%x\n",status));
}
return status;
}
NTSTATUS ScUtil_Cancel( PDEVICE_OBJECT DeviceObject, PIRP Irp ) {
PSCUTIL_EXTENSION pExt = *((PSCUTIL_EXTENSION*) DeviceObject->DeviceExtension); NTSTATUS status = STATUS_SUCCESS; KIRQL irql;
__try { SmartcardDebug( DEBUG_TRACE, ("ScUtil_Cancel Enter\n"));
Irp->IoStatus.Information = 0; Irp->IoStatus.Status = STATUS_CANCELLED;
KeAcquireSpinLock(&pExt->SmartcardExtension->OsData->SpinLock, &irql);
pExt->SmartcardExtension->OsData->NotificationIrp = NULL;
KeReleaseSpinLock(&pExt->SmartcardExtension->OsData->SpinLock, irql);
IoReleaseCancelSpinLock(Irp->CancelIrql);
IoReleaseRemoveLock(pExt->RemoveLock, Irp);
IoCompleteRequest( Irp, IO_NO_INCREMENT);
}
__finally { SmartcardDebug( DEBUG_TRACE, ("ScUtil_Cancel Exit : 0x%x\n",status ));
}
return status;
}
NTSTATUS ScUtil_CancelTrackingIrp( PSCUTIL_EXTENSION pExt ) {
NTSTATUS status = STATUS_UNSUCCESSFUL; PSMARTCARD_EXTENSION pSmartcardExtension = pExt->SmartcardExtension; PIRP notificationIrp = NULL; KIRQL irql; KIRQL cancelIrql;
__try { SmartcardDebug(DEBUG_TRACE, ("Enter: ScUtil_CancelTrackingIrp\n"));
IoAcquireCancelSpinLock(&cancelIrql);
// cancel pending notification irps
KeAcquireSpinLock(&pSmartcardExtension->OsData->SpinLock, &irql);
if ( pSmartcardExtension->OsData->NotificationIrp ) {
// reset the cancel function so that it won't be called anymore
IoSetCancelRoutine(pSmartcardExtension->OsData->NotificationIrp, NULL);
pSmartcardExtension->OsData->NotificationIrp->CancelIrql = cancelIrql;
notificationIrp = pSmartcardExtension->OsData->NotificationIrp; pSmartcardExtension->OsData->NotificationIrp = NULL;
}
KeReleaseSpinLock(&pSmartcardExtension->OsData->SpinLock, irql);
if (notificationIrp) {
IoSetCancelRoutine(notificationIrp, NULL);
}
IoReleaseCancelSpinLock(cancelIrql);
if (notificationIrp) {
notificationIrp->IoStatus.Information = 0; notificationIrp->IoStatus.Status = STATUS_CANCELLED; status = STATUS_CANCELLED;
IoReleaseRemoveLock(pExt->RemoveLock, notificationIrp);
IoCompleteRequest(notificationIrp, IO_NO_INCREMENT);
}
}
__finally { SmartcardDebug(DEBUG_TRACE, ("Exit: ScUtil_CancelTrackingIrp (0x%x)\n", status)); }
return status; }
NTSTATUS ScUtil_Initialize( SCUTIL_HANDLE *UtilHandle, PDEVICE_OBJECT PhysicalDeviceObject, PDEVICE_OBJECT LowerDeviceObject, PSMARTCARD_EXTENSION SmartcardExtension, PIO_REMOVE_LOCK RemoveLock, PNP_CALLBACK StartDevice, PNP_CALLBACK StopDevice, PNP_CALLBACK RemoveDevice, PNP_CALLBACK FreeResources, POWER_CALLBACK SetPowerState ) { NTSTATUS status = STATUS_UNSUCCESSFUL;
PSCUTIL_EXTENSION pExt = (PSCUTIL_EXTENSION) ExAllocatePool(NonPagedPool, sizeof(SCUTIL_EXTENSION));
*UtilHandle = pExt;
PAGED_CODE();
__try { SmartcardDebug(DEBUG_TRACE, ("Enter: ScUtil_Initialize\n"));
pExt->LowerDeviceObject = LowerDeviceObject; pExt->PhysicalDeviceObject = PhysicalDeviceObject; pExt->SmartcardExtension = SmartcardExtension; pExt->RemoveLock = RemoveLock; pExt->StartDevice = StartDevice; pExt->StopDevice = StopDevice; pExt->RemoveDevice = RemoveDevice; pExt->FreeResources = FreeResources; pExt->SetPowerState = SetPowerState;
IoInitializeRemoveLock(RemoveLock, 'LUCS', 0, 20);
KeInitializeEvent(&pExt->OkToStop, NotificationEvent, TRUE);
pExt->IoCount = 0; pExt->ReaderOpen = 0;
pExt->PowerState = PowerDeviceUnspecified; IrpList_Init(&pExt->PendingIrpQueue, IrpList_CancelRoutine, NULL);
pExt->RestartIoctls = FALSE; SetPnPState(pExt, DEVICE_STATE_INITIALIZED);
// register our new device
status = IoRegisterDeviceInterface(PhysicalDeviceObject, &SmartCardReaderGuid, NULL, &pExt->DeviceName);
}
__finally { SmartcardDebug(DEBUG_TRACE, ("Exit: ScUtil_Initialize (0x%x)\n", status)); }
return status;
}
NTSTATUS ScUtil_DeviceIOControl( PDEVICE_OBJECT DeviceObject, PIRP Irp ) { NTSTATUS status = STATUS_UNSUCCESSFUL; PSCUTIL_EXTENSION pExt = *((PSCUTIL_EXTENSION*) DeviceObject->DeviceExtension); QUEUE_STATE state; BOOLEAN complete = FALSE;
ASSERT(pExt);
__try { SmartcardDebug(DEBUG_TRACE, ("Enter: ScUtil_DeviceIOControl\n"));
status = IoAcquireRemoveLock(pExt->RemoveLock, Irp);
if (!NT_SUCCESS(status)) {
// the device has been removed. Fail the call
status = STATUS_DEVICE_REMOVED; complete = TRUE; __leave;
} state = GetIoctlQueueState(pExt); if ( state == QUEUE_IOCTLS) { //
// Need to queue Irp
//
status = IrpList_EnqueueEx(&pExt->PendingIrpQueue, Irp, TRUE); if (!NT_SUCCESS(status)) { // the irp couldn't be queued.
IoReleaseRemoveLock(pExt->RemoveLock, Irp);
complete = TRUE; }
__leave;
} else if (state == FAIL_IOCTLS) {
status = STATUS_DEVICE_REMOVED; complete = TRUE; __leave;
} IncIoCount(pExt);
status = SmartcardDeviceControl(pExt->SmartcardExtension, Irp);
IoReleaseRemoveLock(pExt->RemoveLock, Irp);
DecIoCount(pExt);
}
__finally { if (complete) {
Irp->IoStatus.Information = 0; Irp->IoStatus.Status = status; IoCompleteRequest(Irp, IO_NO_INCREMENT); } SmartcardDebug(DEBUG_TRACE, ("Exit: ScUtil_DeviceIOControl (0x%x)\n", status)); }
return status;
}
NTSTATUS ScUtil_Cleanup( PDEVICE_OBJECT DeviceObject, PIRP Irp ) { NTSTATUS status = STATUS_UNSUCCESSFUL; PSCUTIL_EXTENSION pExt = *((PSCUTIL_EXTENSION*) DeviceObject->DeviceExtension); PSMARTCARD_EXTENSION pSmartcardExtension = pExt->SmartcardExtension; KIRQL cancelIrql; ASSERT(pExt); __try { SmartcardDebug(DEBUG_TRACE, ("Enter: ScUtil_Cleanup\n"));
ScUtil_CancelTrackingIrp(pExt);
Irp->IoStatus.Information = 0; Irp->IoStatus.Status = STATUS_SUCCESS;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
status = STATUS_SUCCESS;
}
__finally { SmartcardDebug(DEBUG_TRACE, ("Exit: ScUtil_Cleanup (0x%x)\n", status)); }
return status;
}
NTSTATUS ScUtil_UnloadDriver( PDRIVER_OBJECT DriverObject ) { NTSTATUS status = STATUS_UNSUCCESSFUL; PAGED_CODE();
__try { SmartcardDebug(DEBUG_TRACE, ("Enter: ScUtil_UnloadDriver\n")); }
__finally { SmartcardDebug(DEBUG_TRACE, ("Exit: ScUtil_UnloadDriver (0x%x)\n", status)); }
return status;
}
NTSTATUS ScUtil_CreateClose( PDEVICE_OBJECT DeviceObject, PIRP Irp ) { NTSTATUS status = STATUS_UNSUCCESSFUL; PSCUTIL_EXTENSION pExt = *((PSCUTIL_EXTENSION*) DeviceObject->DeviceExtension); PIO_STACK_LOCATION pIrpStack = IoGetCurrentIrpStackLocation(Irp);
ASSERT(pExt);
PAGED_CODE();
__try { SmartcardDebug(DEBUG_TRACE, ("Enter: ScUtil_CreateClose\n"));
if ( pIrpStack->MajorFunction == IRP_MJ_CREATE ) {
status = IoAcquireRemoveLock(pExt->RemoveLock, DeviceObject);
if (!NT_SUCCESS(status)) {
status = STATUS_DEVICE_REMOVED; __leave;
}
// test if the device has been opened already
if ( InterlockedCompareExchange(&pExt->ReaderOpen, 1, 0) == 0 ) { //
//
} else {
// the device is already in use
status = STATUS_UNSUCCESSFUL;
// release the lock
IoReleaseRemoveLock(pExt->RemoveLock, DeviceObject);
}
} else {
if (InterlockedCompareExchange(&pExt->ReaderOpen, 0, 1) == 1) { IoReleaseRemoveLock(pExt->RemoveLock, DeviceObject);
} }
}
__finally {
Irp->IoStatus.Status = status; Irp->IoStatus.Information = 0; IoCompleteRequest(Irp, IO_NO_INCREMENT);
SmartcardDebug(DEBUG_TRACE, ("Exit: ScUtil_CreateClose (0x%x)\n", status)); }
return status;
}
|