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

4533 lines
152 KiB
C

/*****************************************************************************
@doc INT EXT
******************************************************************************
* $ProjectName: $
* $ProjectRevision: $
*-----------------------------------------------------------------------------
* $Source: z:/pr/cmeu0/sw/sccmusbm.ms/rcs/scusbwdm.c $
* $Revision: 1.9 $
*-----------------------------------------------------------------------------
* $Author: WFrischauf $
*-----------------------------------------------------------------------------
* History: see EOF
*-----------------------------------------------------------------------------
*
* Copyright © 2000 OMNIKEY AG
******************************************************************************/
#include "wdm.h"
#include "stdarg.h"
#include "stdio.h"
#include "usbdi.h"
#include "usbdlib.h"
#include "sccmusbm.h"
BOOLEAN DeviceSlot[MAXIMUM_USB_READERS];
STRING OemName[MAXIMUM_OEM_NAMES];
CHAR OemNameBuffer[MAXIMUM_OEM_NAMES][64];
BOOLEAN OemDeviceSlot[MAXIMUM_OEM_NAMES][MAXIMUM_USB_READERS];
/*****************************************************************************
Routine Description:
Arguments:
Return Value:
*****************************************************************************/
PURB CMUSB_BuildAsyncRequest(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PUSBD_PIPE_INFORMATION PipeHandle
)
{
ULONG siz;
ULONG length;
PURB urb = NULL;
PDEVICE_EXTENSION DeviceExtension;
PUSBD_INTERFACE_INFORMATION interface;
PUSBD_PIPE_INFORMATION pipeHandle = NULL;
PSMARTCARD_EXTENSION SmartcardExtension;
siz = sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER);
urb = ExAllocatePool(NonPagedPool, siz);
DeviceExtension = DeviceObject->DeviceExtension;
SmartcardExtension = &DeviceExtension->SmartcardExtension;
if (urb != NULL)
{
RtlZeroMemory(urb, siz);
urb->UrbBulkOrInterruptTransfer.Hdr.Length = (USHORT) siz;
urb->UrbBulkOrInterruptTransfer.Hdr.Function =
URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER;
urb->UrbBulkOrInterruptTransfer.PipeHandle =
PipeHandle->PipeHandle;
urb->UrbBulkOrInterruptTransfer.TransferFlags =
USBD_TRANSFER_DIRECTION_IN;
// short packet is not treated as an error.
urb->UrbBulkOrInterruptTransfer.TransferFlags |=
USBD_SHORT_TRANSFER_OK;
//
// not using linked urb's
//
urb->UrbBulkOrInterruptTransfer.UrbLink = NULL;
urb->UrbBulkOrInterruptTransfer.TransferBufferMDL = NULL;
urb->UrbBulkOrInterruptTransfer.TransferBufferLength =
SmartcardExtension->SmartcardReply.BufferLength;
urb->UrbBulkOrInterruptTransfer.TransferBuffer =
SmartcardExtension->SmartcardReply.Buffer;
}
return urb;
}
/*****************************************************************************
Routine Description:
Arguments:
Return Value:
*****************************************************************************/
NTSTATUS CMUSB_AsyncReadComplete(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Context
)
{
PURB urb;
PCMUSB_RW_CONTEXT context = Context;
PIO_STACK_LOCATION irpStack;
PDEVICE_OBJECT deviceObject;
PDEVICE_EXTENSION DeviceExtension;
PSMARTCARD_EXTENSION SmartcardExtension;
urb = context->Urb;
deviceObject = context->DeviceObject;
DeviceExtension = deviceObject->DeviceExtension;
SmartcardExtension = &DeviceExtension->SmartcardExtension;
//
// set the length based on the TransferBufferLength
// value in the URB
//
if (Irp->IoStatus.Status == STATUS_SUCCESS)
{
SmartcardExtension->SmartcardReply.BufferLength = urb->UrbBulkOrInterruptTransfer.TransferBufferLength;
SmartcardExtension->ReaderExtension->fP1Stalled = FALSE;
}
else
{
SmartcardDebug(DEBUG_DRIVER,
("%s!Irp->IoStatus.Status = %lx\n",DRIVER_NAME,Irp->IoStatus.Status));
SmartcardExtension->SmartcardReply.BufferLength = 0;
SmartcardExtension->ReaderExtension->fP1Stalled = TRUE;
}
SmartcardExtension->SmartcardReply.BufferLength = urb->UrbBulkOrInterruptTransfer.TransferBufferLength;
CMUSB_DecrementIoCount(deviceObject);
ExFreePool(context);
ExFreePool(urb);
IoFreeIrp(Irp);
/*
SmartcardDebug(DEBUG_DRIVER,
("%s!AsyncReadWriteComplete <%ld>\n",
DRIVER_NAME,SmartcardExtension->SmartcardReply.BufferLength)
);
*/
KeSetEvent(&DeviceExtension->ReadP1Completed,0,FALSE);
return STATUS_MORE_PROCESSING_REQUIRED;
}
/*****************************************************************************
Routine Description:
Arguments:
Return Value:
NT NTStatus
*****************************************************************************/
#define TIMEOUT_P1_RESPONSE 100
NTSTATUS CMUSB_ReadP1(
IN PDEVICE_OBJECT DeviceObject
)
{
NTSTATUS NTStatus;
NTSTATUS DebugStatus;
PIO_STACK_LOCATION nextStack;
PURB urb;
PCMUSB_RW_CONTEXT context = NULL;
PDEVICE_EXTENSION DeviceExtension;
PSMARTCARD_EXTENSION SmartcardExtension;
PUSBD_INTERFACE_INFORMATION interface;
PUSBD_PIPE_INFORMATION pipeHandle = NULL;
CHAR cStackSize;
PIRP IrpToUSB = NULL;
ULONG ulBytesToRead;
ULONG i;
LARGE_INTEGER liTimeoutP1;
LARGE_INTEGER liTimeoutP1Response;
BOOLEAN fStateTimer;
UCHAR bTmp;
LONG lNullPackets;
BOOLEAN fCancelTimer = FALSE;
/*
SmartcardDebug(DEBUG_TRACE,
("%s!ReadP1: Enter\n",DRIVER_NAME)
);
*/
DeviceExtension = DeviceObject->DeviceExtension;
SmartcardExtension = &DeviceExtension->SmartcardExtension;
interface = DeviceExtension->UsbInterface;
pipeHandle = &interface->Pipes[0];
if (pipeHandle == NULL)
{
NTStatus = STATUS_INVALID_HANDLE;
goto ExitCMUSB_ReadP1;
}
liTimeoutP1 = RtlConvertLongToLargeInteger(SmartcardExtension->ReaderExtension->ulTimeoutP1 * -10000);
KeSetTimer(&SmartcardExtension->ReaderExtension->P1Timer,
liTimeoutP1,
NULL);
fCancelTimer = TRUE;
// we will always read a whole packet (== 8 bytes)
ulBytesToRead = 8;
cStackSize = (CCHAR)(DeviceExtension->TopOfStackDeviceObject->StackSize+1);
lNullPackets = -1;
do
{
fStateTimer = KeReadStateTimer(&SmartcardExtension->ReaderExtension->P1Timer);
if (fStateTimer == TRUE)
{
fCancelTimer = FALSE;
NTStatus = STATUS_IO_TIMEOUT;
SmartcardExtension->SmartcardReply.BufferLength = 0L;
SmartcardDebug(DEBUG_PROTOCOL,
("%s!Timeout (%ld)while reading from P1\n",
DRIVER_NAME,SmartcardExtension->ReaderExtension->ulTimeoutP1)
);
break;
}
SmartcardExtension->SmartcardReply.BufferLength = ulBytesToRead;
IrpToUSB = IoAllocateIrp(cStackSize,FALSE);
if (IrpToUSB==NULL)
{
SmartcardExtension->SmartcardReply.BufferLength = 0L;
NTStatus = STATUS_INSUFFICIENT_RESOURCES;
goto ExitCMUSB_ReadP1;
}
urb = CMUSB_BuildAsyncRequest(DeviceObject,
IrpToUSB,
pipeHandle
);
if (urb != NULL)
{
context = ExAllocatePool(NonPagedPool, sizeof(CMUSB_RW_CONTEXT));
}
if (urb != NULL && context != NULL)
{
context->Urb = urb;
context->DeviceObject = DeviceObject;
context->Irp = IrpToUSB;
nextStack = IoGetNextIrpStackLocation(IrpToUSB);
ASSERT(nextStack != NULL);
ASSERT(DeviceObject->StackSize>1);
nextStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
nextStack->Parameters.Others.Argument1 = urb;
nextStack->Parameters.DeviceIoControl.IoControlCode =
IOCTL_INTERNAL_USB_SUBMIT_URB;
IoSetCompletionRoutine(IrpToUSB,
CMUSB_AsyncReadComplete,
context,
TRUE,
TRUE,
TRUE);
ASSERT(DeviceExtension->TopOfStackDeviceObject);
ASSERT(IrpToUSB);
KeClearEvent(&DeviceExtension->ReadP1Completed);
CMUSB_IncrementIoCount(DeviceObject);
NTStatus = IoCallDriver(DeviceExtension->TopOfStackDeviceObject,
IrpToUSB);
liTimeoutP1Response = RtlConvertLongToLargeInteger(TIMEOUT_P1_RESPONSE * -10000);
NTStatus = KeWaitForSingleObject(&DeviceExtension->ReadP1Completed,
Executive,
KernelMode,
FALSE,
&liTimeoutP1Response);
if (NTStatus == STATUS_TIMEOUT)
{
// probably the device has been removed
// there must be at least a null packet received during liTimeoutReponse
SmartcardExtension->SmartcardReply.BufferLength = 0L;
break;
}
// -----------------------------
// check if P1 has been stalled
// -----------------------------
if (SmartcardExtension->ReaderExtension->fP1Stalled == TRUE)
{
break;
}
}
else
{
SmartcardExtension->SmartcardReply.BufferLength = 0L;
NTStatus = STATUS_INSUFFICIENT_RESOURCES;
break;
}
lNullPackets++;
} while (SmartcardExtension->SmartcardReply.BufferLength == 0L);
// -----------------------------
// check if P1 has been stalled
// -----------------------------
if (SmartcardExtension->ReaderExtension->fP1Stalled == TRUE)
{
SmartcardDebug(DEBUG_DRIVER,
("%s!P1 stalled \n",DRIVER_NAME));
NTStatus = STATUS_DEVICE_DATA_ERROR;
// wait to be sure that we have a stable card state
CMUSB_Wait (50);
// P1 has been stalled ==> we must reset the pipe and send a NTStatus to enable it again
DebugStatus = CMUSB_ResetPipe(DeviceObject,pipeHandle);
}
else
{
// if no bytes have been received , NTStatus has already been set
// to STATUS_TIMEOUT
if (SmartcardExtension->SmartcardReply.BufferLength > 0 )
{
NTStatus = STATUS_SUCCESS;
#if DBG
SmartcardDebug(DEBUG_PROTOCOL,("%s!<==[P1] <%ld> ",DRIVER_NAME,lNullPackets));
for (i=0;i< SmartcardExtension->SmartcardReply.BufferLength;i++)
{
bTmp = SmartcardExtension->SmartcardReply.Buffer[i];
if (SmartcardExtension->ReaderExtension->fInverseAtr &&
SmartcardExtension->ReaderExtension->ulTimeoutP1 != DEFAULT_TIMEOUT_P1)
{
//CMUSB_InverseBuffer(&bTmp,1);
SmartcardDebug(DEBUG_PROTOCOL,("%x ",bTmp));
}
else
{
SmartcardDebug(DEBUG_PROTOCOL,("%x ",bTmp));
}
}
SmartcardDebug(DEBUG_PROTOCOL,("(%ld)\n",SmartcardExtension->SmartcardReply.BufferLength));
#endif
}
}
ExitCMUSB_ReadP1:
if (fCancelTimer == TRUE)
{
// cancel timer
// TRUE if the timer is in the queue
// FALSE if the timer is not in queue
KeCancelTimer(&SmartcardExtension->ReaderExtension->P1Timer);
}
/*
SmartcardDebug(DEBUG_TRACE,
("%s!ReadP1: Exit %lx\n",DRIVER_NAME,NTStatus));
*/
return NTStatus;
}
/*****************************************************************************
Routine Description:
Arguments:
Return Value:
NT NTStatus
*****************************************************************************/
NTSTATUS CMUSB_ReadP1_T0(
IN PDEVICE_OBJECT DeviceObject
)
{
NTSTATUS NTStatus;
PIO_STACK_LOCATION nextStack;
PURB urb;
PCMUSB_RW_CONTEXT context = NULL;
PDEVICE_EXTENSION DeviceExtension;
PSMARTCARD_EXTENSION SmartcardExtension;
PUSBD_INTERFACE_INFORMATION interface;
PUSBD_PIPE_INFORMATION pipeHandle = NULL;
CHAR cStackSize;
PIRP IrpToUSB = NULL;
ULONG ulBytesToRead;
/*
SmartcardDebug(DEBUG_TRACE,
("%s!ReadP1_T0: Enter\n",DRIVER_NAME));
*/
DeviceExtension = DeviceObject->DeviceExtension;
SmartcardExtension = &DeviceExtension->SmartcardExtension;
interface = DeviceExtension->UsbInterface;
pipeHandle = &interface->Pipes[0];
if (pipeHandle == NULL)
{
NTStatus = STATUS_INVALID_HANDLE;
goto ExitCMUSB_ReadP1;
}
ulBytesToRead = SmartcardExtension->SmartcardReply.BufferLength;
cStackSize = (CCHAR)(DeviceExtension->TopOfStackDeviceObject->StackSize+1);
IrpToUSB = IoAllocateIrp(cStackSize,FALSE);
if (IrpToUSB==NULL)
{
SmartcardExtension->SmartcardReply.BufferLength = 0L;
NTStatus = STATUS_INSUFFICIENT_RESOURCES;
goto ExitCMUSB_ReadP1;
}
urb = CMUSB_BuildAsyncRequest(DeviceObject,IrpToUSB,pipeHandle);
if (urb != NULL)
{
context = ExAllocatePool(NonPagedPool, sizeof(CMUSB_RW_CONTEXT));
}
if (urb != NULL && context != NULL)
{
context->Urb = urb;
context->DeviceObject = DeviceObject;
context->Irp = IrpToUSB;
nextStack = IoGetNextIrpStackLocation(IrpToUSB);
ASSERT(nextStack != NULL);
ASSERT(DeviceObject->StackSize>1);
nextStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
nextStack->Parameters.Others.Argument1 = urb;
nextStack->Parameters.DeviceIoControl.IoControlCode =
IOCTL_INTERNAL_USB_SUBMIT_URB;
IoSetCompletionRoutine(IrpToUSB,
CMUSB_AsyncReadComplete,
context,
TRUE,
TRUE,
TRUE);
ASSERT(DeviceExtension->TopOfStackDeviceObject);
ASSERT(IrpToUSB);
KeClearEvent(&DeviceExtension->ReadP1Completed);
CMUSB_IncrementIoCount(DeviceObject);
/*
SmartcardDebug(DEBUG_PROTOCOL,
("%s!bytes to read from P1 =%ld\n",DRIVER_NAME,ulBytesToRead));
*/
NTStatus = IoCallDriver(DeviceExtension->TopOfStackDeviceObject,
IrpToUSB);
/*
SmartcardDebug(DEBUG_DRIVER,
("%s!IoCallDriver returned %lx\n",DRIVER_NAME,NTStatus));
*/
if (NTStatus == STATUS_PENDING)
NTStatus = STATUS_SUCCESS;
}
else
{
SmartcardExtension->SmartcardReply.BufferLength = 0L;
NTStatus = STATUS_INSUFFICIENT_RESOURCES;
}
ExitCMUSB_ReadP1:
/*
SmartcardDebug(DEBUG_TRACE,
("%s!ReadP1_T0: Exit %lx\n",DRIVER_NAME,NTStatus));
*/
return NTStatus;
}
/*****************************************************************************
Routine Description:
Dispatch table routine for IRP_MJ_PNP.
Process the Plug and Play IRPs sent to this device.
Arguments:
DeviceObject - pointer to our FDO (Functional Device Object)
Irp - pointer to an I/O Request Packet
Return Value:
NT NTStatus code
*****************************************************************************/
NTSTATUS CMUSB_ProcessPnPIrp(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
{
PIO_STACK_LOCATION irpStack;
PDEVICE_EXTENSION DeviceExtension;
NTSTATUS NTStatus = STATUS_SUCCESS;
NTSTATUS waitStatus;
NTSTATUS DebugStatus;
PDEVICE_OBJECT stackDeviceObject;
KEVENT startDeviceEvent;
PDEVICE_CAPABILITIES DeviceCapabilities;
KEVENT event;
SmartcardDebug(DEBUG_TRACE,
("%s!ProcessPnPIrp: Enter\n",DRIVER_NAME));
//
// Get a pointer to the device extension
//
DeviceExtension = DeviceObject->DeviceExtension;
stackDeviceObject = DeviceExtension->TopOfStackDeviceObject;
//
// Acquire remove lock,
// so that device can not be removed while
// this function is executed
//
NTStatus = SmartcardAcquireRemoveLock(&DeviceExtension->SmartcardExtension);
ASSERT(NTStatus == STATUS_SUCCESS);
if (NTStatus != STATUS_SUCCESS)
{
Irp->IoStatus.Information = 0;
Irp->IoStatus.Status = NTStatus;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return NTStatus;
}
//
// Get a pointer to the current location in the Irp. This is where
// the function codes and parameters are located.
//
irpStack = IoGetCurrentIrpStackLocation (Irp);
// inc the FDO device extension's pending IO count for this Irp
CMUSB_IncrementIoCount(DeviceObject);
CMUSB_ASSERT( IRP_MJ_PNP == irpStack->MajorFunction );
switch (irpStack->MinorFunction)
{
// ---------------------
// IRP_MN_START_DEVICE
// ---------------------
case IRP_MN_START_DEVICE:
// The PnP Manager sends this IRP after it has assigned resources,
// if any, to the device. The device may have been recently enumerated
// and is being started for the first time, or the device may be
// restarting after being stopped for resource reconfiguration.
SmartcardDebug(DEBUG_DRIVER,
("%s!IRP_MN_START_DEVICE received\n",DRIVER_NAME));
// Initialize an event we can wait on for the PDO to be done with this irp
KeInitializeEvent(&startDeviceEvent, NotificationEvent, FALSE);
IoCopyCurrentIrpStackLocationToNext(Irp);
// Set a completion routine so it can signal our event when
// the PDO is done with the Irp
IoSetCompletionRoutine(Irp,
CMUSB_IrpCompletionRoutine,
&startDeviceEvent, // pass the event to the completion routine as the Context
TRUE, // invoke on success
TRUE, // invoke on error
TRUE); // invoke on cancellation
// let the PDO process the IRP
NTStatus = IoCallDriver(stackDeviceObject,Irp);
// if PDO is not done yet, wait for the event to be set in our completion routine
if (NTStatus == STATUS_PENDING)
{
// wait for irp to complete
waitStatus = KeWaitForSingleObject(&startDeviceEvent,
Suspended,
KernelMode,
FALSE,
NULL);
NTStatus = Irp->IoStatus.Status;
}
if (NT_SUCCESS(NTStatus))
{
// Now we're ready to do our own startup processing.
// USB client drivers such as us set up URBs (USB Request Packets) to send requests
// to the host controller driver (HCD). The URB structure defines a format for all
// possible commands that can be sent to a USB device.
// Here, we request the device descriptor and store it,
// and configure the device.
NTStatus = CMUSB_StartDevice(DeviceObject);
Irp->IoStatus.Status = NTStatus;
}
IoCompleteRequest (Irp,IO_NO_INCREMENT);
CMUSB_DecrementIoCount(DeviceObject);
// Release the remove lock
SmartcardReleaseRemoveLock(&DeviceExtension->SmartcardExtension);
return NTStatus; // end, case IRP_MN_START_DEVICE
// ------------------------
// IRP_MN_QUERY_STOP_DEVICE
// ------------------------
case IRP_MN_QUERY_STOP_DEVICE:
// The IRP_MN_QUERY_STOP_DEVICE/IRP_MN_STOP_DEVICE sequence only occurs
// during "polite" shutdowns, such as the user explicitily requesting the
// service be stopped in, or requesting unplug from the Pnp tray icon.
// This sequence is NOT received during "impolite" shutdowns,
// such as someone suddenly yanking the USB cord or otherwise
// unexpectedly disabling/resetting the device.
// If a driver sets STATUS_SUCCESS for this IRP,
// the driver must not start any operations on the device that
// would prevent that driver from successfully completing an IRP_MN_STOP_DEVICE
// for the device.
// For mass storage devices such as disk drives, while the device is in the
// stop-pending state,the driver holds IRPs that require access to the device,
// but for most USB devices, there is no 'persistent storage', so we will just
// refuse any more IO until restarted or the stop is cancelled
// If a driver in the device stack determines that the device cannot be
// stopped for resource reconfiguration, the driver is not required to pass
// the IRP down the device stack. If a query-stop IRP fails,
// the PnP Manager sends an IRP_MN_CANCEL_STOP_DEVICE to the device stack,
// notifying the drivers for the device that the query has been cancelled
// and that the device will not be stopped.
SmartcardDebug(DEBUG_DRIVER,
("%s!IRP_MN_QUERY_STOP_DEVICE\n",DRIVER_NAME));
// It is possible to receive this irp when the device has not been started
// ( as on a boot device )
if (DeviceExtension->DeviceStarted == FALSE) // if get when never started, just pass on
{
SmartcardDebug(DEBUG_DRIVER,
("%s!ProcessPnPIrp: IRP_MN_QUERY_STOP_DEVICE when device not started\n",DRIVER_NAME));
IoSkipCurrentIrpStackLocation (Irp);
NTStatus = IoCallDriver (DeviceExtension->TopOfStackDeviceObject, Irp);
CMUSB_DecrementIoCount(DeviceObject);
// Release the remove lock
SmartcardReleaseRemoveLock(&DeviceExtension->SmartcardExtension);
return NTStatus;
}
// We'll not veto it; pass it on and flag that stop was requested.
// Once StopDeviceRequested is set no new IOCTL or read/write irps will be passed
// down the stack to lower drivers; all will be quickly failed
DeviceExtension->StopDeviceRequested = TRUE;
break; // end, case IRP_MN_QUERY_STOP_DEVICE
// -------------------------
// IRP_MN_CANCEL_STOP_DEVICE
// -------------------------
case IRP_MN_CANCEL_STOP_DEVICE:
// The PnP Manager uses this IRP to inform the drivers for a device
// that the device will not be stopped for resource reconfiguration.
// This should only be received after a successful IRP_MN_QUERY_STOP_DEVICE.
SmartcardDebug(DEBUG_DRIVER,
("%s!IRP_MN_CANCEL_STOP_DEVICE received\n",DRIVER_NAME));
// It is possible to receive this irp when the device has not been started
if (DeviceExtension->DeviceStarted == FALSE) // if get when never started, just pass on
{
SmartcardDebug(DEBUG_DRIVER,
("%s!ProcessPnPIrp: IRP_MN_CANCEL_STOP_DEVICE when device not started\n",DRIVER_NAME));
IoSkipCurrentIrpStackLocation (Irp);
NTStatus = IoCallDriver (DeviceExtension->TopOfStackDeviceObject, Irp);
CMUSB_DecrementIoCount(DeviceObject);
// Release the remove lock
SmartcardReleaseRemoveLock(&DeviceExtension->SmartcardExtension);
return NTStatus;
}
// Reset this flag so new IOCTL and IO Irp processing will be re-enabled
DeviceExtension->StopDeviceRequested = FALSE;
Irp->IoStatus.Status = STATUS_SUCCESS;
break; // end, case IRP_MN_CANCEL_STOP_DEVICE
// -------------------
// IRP_MN_STOP_DEVICE
// -------------------
case IRP_MN_STOP_DEVICE:
// The PnP Manager sends this IRP to stop a device so it can reconfigure
// its hardware resources. The PnP Manager only sends this IRP if a prior
// IRP_MN_QUERY_STOP_DEVICE completed successfully.
SmartcardDebug(DEBUG_DRIVER,
("%s!IRP_MN_STOP_DEVICE received\n",DRIVER_NAME));
// Cancel any pending io requests. (there shouldn't be any)
//CMUSB_CancelPendingIo( DeviceObject );
//
// Send the select configuration urb with a NULL pointer for the configuration
// handle, this closes the configuration and puts the device in the 'unconfigured'
// state.
//
NTStatus = CMUSB_StopDevice(DeviceObject);
Irp->IoStatus.Status = NTStatus;
break; // end, case IRP_MN_STOP_DEVICE
// --------------------------
// IRP_MN_QUERY_REMOVE_DEVICE
// --------------------------
case IRP_MN_QUERY_REMOVE_DEVICE:
// In response to this IRP, drivers indicate whether the device can be
// removed without disrupting the system.
// If a driver determines it is safe to remove the device,
// the driver completes any outstanding I/O requests, arranges to hold any subsequent
// read/write requests, and sets Irp->IoStatus.Status to STATUS_SUCCESS. Function
// and filter drivers then pass the IRP to the next-lower driver in the device stack.
// The underlying bus driver calls IoCompleteRequest.
// If a driver sets STATUS_SUCCESS for this IRP, the driver must not start any
// operations on the device that would prevent that driver from succesfully completing
// an IRP_MN_REMOVE_DEVICE for the device. If a driver in the device stack determines
// that the device cannot be removed, the driver is not required to pass the
// query-remove IRP down the device stack. If a query-remove IRP fails, the PnP Manager
// sends an IRP_MN_CANCEL_REMOVE_DEVICE to the device stack, notifying the drivers for
// the device that the query has been cancelled and that the device will not be removed.
SmartcardDebug(DEBUG_DRIVER,
("%s!IRP_MN_QUERY_REMOVE_DEVICE received\n",DRIVER_NAME));
// It is possible to receive this irp when the device has not been started
if (DeviceExtension->DeviceStarted == FALSE) // if get when never started, just pass on
{
SmartcardDebug( DEBUG_DRIVER,
("%s!ProcessPnPIrp: IRP_MN_QUERY_STOP_DEVICE when device not started\n",
DRIVER_NAME)
);
IoSkipCurrentIrpStackLocation (Irp);
NTStatus = IoCallDriver (DeviceExtension->TopOfStackDeviceObject, Irp);
CMUSB_DecrementIoCount(DeviceObject);
// Release the remove lock
SmartcardReleaseRemoveLock(&DeviceExtension->SmartcardExtension);
return NTStatus;
}
if (DeviceExtension->fPnPResourceManager == TRUE)
{
// disable the reader
DebugStatus = IoSetDeviceInterfaceState(&DeviceExtension->PnPDeviceName,FALSE);
ASSERT(DebugStatus == STATUS_SUCCESS);
}
// Once RemoveDeviceRequested is set no new IOCTL or read/write irps will be passed
// down the stack to lower drivers; all will be quickly failed
DeviceExtension->RemoveDeviceRequested = TRUE;
// Wait for any io request pending in our driver to
// complete before returning success.
// This event is set when DeviceExtension->PendingIoCount goes to 1
waitStatus = KeWaitForSingleObject(&DeviceExtension->NoPendingIoEvent,
Suspended,
KernelMode,
FALSE,
NULL);
Irp->IoStatus.Status = STATUS_SUCCESS;
break; // end, case IRP_MN_QUERY_REMOVE_DEVICE
// ---------------------------
// IRP_MN_CANCEL_REMOVE_DEVICE
// ---------------------------
case IRP_MN_CANCEL_REMOVE_DEVICE:
SmartcardDebug(DEBUG_DRIVER,
("%s!IRP_MN_CANCEL_REMOVE_DEVICE received\n",DRIVER_NAME));
// The PnP Manager uses this IRP to inform the drivers
// for a device that the device will not be removed.
// It is sent only after a successful IRP_MN_QUERY_REMOVE_DEVICE.
if (DeviceExtension->DeviceStarted == FALSE) // if get when never started, just pass on
{
SmartcardDebug(DEBUG_DRIVER,
("%s!ProcessPnPIrp: IRP_MN_CANCEL_REMOVE_DEVICE when device not started\n",DRIVER_NAME));
IoSkipCurrentIrpStackLocation (Irp);
NTStatus = IoCallDriver (DeviceExtension->TopOfStackDeviceObject, Irp);
CMUSB_DecrementIoCount(DeviceObject);
// Release the remove lock
SmartcardReleaseRemoveLock(&DeviceExtension->SmartcardExtension);
return NTStatus;
}
if (DeviceExtension->fPnPResourceManager == TRUE)
{
DebugStatus = IoSetDeviceInterfaceState(&DeviceExtension->PnPDeviceName,
TRUE);
ASSERT(DebugStatus == STATUS_SUCCESS);
}
// Reset this flag so new IOCTL and IO Irp processing will be re-enabled
DeviceExtension->RemoveDeviceRequested = FALSE;
Irp->IoStatus.Status = STATUS_SUCCESS;
break; // end, case IRP_MN_CANCEL_REMOVE_DEVICE
// ---------------------
// IRP_MN_SURPRISE_REMOVAL
// ---------------------
case IRP_MN_SURPRISE_REMOVAL:
// For a surprise-style device removal ( i.e. sudden cord yank ),
// the physical device has already been removed so the PnP Manager sends
// the remove IRP without a prior query-remove. A device can be in any state
// when it receives a remove IRP as a result of a surprise-style removal.
SmartcardDebug(DEBUG_DRIVER,
("%s!IRP_MN_SURPRISE_REMOVAL received\n",DRIVER_NAME));
// match the inc at the begining of the dispatch routine
CMUSB_DecrementIoCount(DeviceObject);
if (DeviceExtension->fPnPResourceManager == TRUE)
{
// disable the reader
DebugStatus = IoSetDeviceInterfaceState(&DeviceExtension->PnPDeviceName,FALSE);
ASSERT(DebugStatus == STATUS_SUCCESS);
}
// Once RemoveDeviceRequested is set no new IOCTL or read/write irps will be passed
// down the stack to lower drivers; all will be quickly failed
DeviceExtension->DeviceSurpriseRemoval = TRUE;
//
// Mark this handled
//
Irp->IoStatus.Status = STATUS_SUCCESS;
// We don't explicitly wait for the below driver to complete, but just make
// the call and go on, finishing cleanup
IoCopyCurrentIrpStackLocationToNext(Irp);
NTStatus = IoCallDriver(stackDeviceObject,Irp);
// Release the remove lock
SmartcardReleaseRemoveLock(&DeviceExtension->SmartcardExtension);
return NTStatus;
// ---------------------
// IRP_MN_REMOVE_DEVICE
// ---------------------
case IRP_MN_REMOVE_DEVICE:
// The PnP Manager uses this IRP to direct drivers to remove a device.
// For a "polite" device removal, the PnP Manager sends an
// IRP_MN_QUERY_REMOVE_DEVICE prior to the remove IRP. In this case,
// the device is in the remove-pending state when the remove IRP arrives.
// For a surprise-style device removal ( i.e. sudden cord yank ),
// the physical device has already been removed so the PnP Manager sends
// the remove IRP without a prior query-remove. A device can be in any state
// when it receives a remove IRP as a result of a surprise-style removal.
SmartcardDebug(DEBUG_DRIVER,
("%s!IRP_MN_REMOVE_DEVICE received\n",DRIVER_NAME));
// match the inc at the begining of the dispatch routine
CMUSB_DecrementIoCount(DeviceObject);
//
// Once DeviceRemoved is set no new IOCTL or read/write irps will be passed
// down the stack to lower drivers; all will be quickly failed
//
DeviceExtension->DeviceRemoved = TRUE;
// Cancel any pending io requests; we may not have gotten a query first!
//CMUSB_CancelPendingIo( DeviceObject );
// It is possible to receive this irp when the device has not been started
if (DeviceExtension->DeviceStarted == TRUE) // if get when never started, just pass on
{
// If any pipes are still open, call USBD with URB_FUNCTION_ABORT_PIPE
// This call will also close the pipes; if any user close calls get through,
// they will be noops
CMUSB_AbortPipes( DeviceObject );
}
// We don't explicitly wait for the below driver to complete, but just make
// the call and go on, finishing cleanup
IoCopyCurrentIrpStackLocationToNext(Irp);
NTStatus = IoCallDriver(stackDeviceObject,Irp);
//
// The final decrement to device extension PendingIoCount == 0
// will set DeviceExtension->RemoveEvent, enabling device removal.
// If there is no pending IO at this point, the below decrement will be it.
// If there is still pending IO,
// the following CancelPendingIo() call will handle it.
//
CMUSB_DecrementIoCount(DeviceObject);
// wait for any io request pending in our driver to
// complete for finishing the remove
KeWaitForSingleObject(&DeviceExtension->RemoveEvent,
Suspended,
KernelMode,
FALSE,
NULL);
//
// Delete the link and FDO we created
//
CMUSB_RemoveDevice(DeviceObject);
SmartcardDebug(DEBUG_DRIVER,
("%s!ProcessPnPIrp: Detaching from %08X\n",DRIVER_NAME,
DeviceExtension->TopOfStackDeviceObject));
IoDetachDevice(DeviceExtension->TopOfStackDeviceObject);
SmartcardDebug(DEBUG_DRIVER,
("%s!ProcessPnPIrp: Deleting %08X\n",DRIVER_NAME,DeviceObject));
IoDeleteDevice (DeviceObject);
// don't release remove lock here
// because it's relesed in RemoveDevice
return NTStatus; // end, case IRP_MN_REMOVE_DEVICE
// ---------------------
// IRP_MN_QUERY_CAPABILITIES
// ---------------------
case IRP_MN_QUERY_CAPABILITIES:
//
// Get the packet.
//
DeviceCapabilities=irpStack->Parameters.DeviceCapabilities.Capabilities;
if (DeviceCapabilities->Version < 1 ||
DeviceCapabilities->Size < sizeof(DEVICE_CAPABILITIES))
{
//
// We don't support this version. Fail the requests
//
NTStatus = STATUS_UNSUCCESSFUL;
break;
}
//
// Prepare to pass the IRP down
//
// init an event to tell us when the completion routine's been called
KeInitializeEvent(&event, NotificationEvent, FALSE);
IoCopyCurrentIrpStackLocationToNext(Irp);
IoSetCompletionRoutine (Irp,
CMUSB_IrpCompletionRoutine,
&event, // pass the event as Context to completion routine
TRUE, // invoke on success
TRUE, // invoke on error
TRUE); // invoke on cancellation of the Irp
NTStatus = IoCallDriver(stackDeviceObject,Irp);
if (NTStatus == STATUS_PENDING)
{
// wait for irp to complete
NTStatus = KeWaitForSingleObject(&event,
Suspended,
KernelMode,
FALSE,
NULL);
}
// We cannot wake the system.
DeviceCapabilities->SystemWake = PowerSystemUnspecified;
DeviceCapabilities->DeviceWake = PowerDeviceUnspecified;
// We have no latencies
DeviceCapabilities->D1Latency = 0;
DeviceCapabilities->D2Latency = 0;
DeviceCapabilities->D3Latency = 0;
// No locking or ejection
DeviceCapabilities->LockSupported = FALSE;
DeviceCapabilities->EjectSupported = FALSE;
// Device can be physically removed.
// Technically there is no physical device to remove, but this bus
// driver can yank the PDO from the PlugPlay system, when ever it
// receives an IOCTL_GAMEENUM_REMOVE_PORT device control command.
DeviceCapabilities->Removable = TRUE;
// Docking device
DeviceCapabilities->DockDevice = FALSE;
// Device can not be removed any time
// it has a removeable media!!
DeviceCapabilities->SurpriseRemovalOK = FALSE;
Irp->IoStatus.Status = NTStatus;
IoCompleteRequest (Irp,IO_NO_INCREMENT);
// Decrement IO count
CMUSB_DecrementIoCount(DeviceObject);
// Release the remove lock
SmartcardReleaseRemoveLock(&DeviceExtension->SmartcardExtension);
return NTStatus; // end, case IRP_MN_QUERY_CAPABILITIES
// ---------------------
// IRP_MN_ not handled
// ---------------------
default:
SmartcardDebug(DEBUG_DRIVER,
("%s!ProcessPnPIrp: Minor PnP IOCTL not handled\n",DRIVER_NAME));
} /* case MinorFunction */
if (!NT_SUCCESS(NTStatus))
{
// if anything went wrong, return failure without passing Irp down
Irp->IoStatus.Status = NTStatus;
IoCompleteRequest (Irp,IO_NO_INCREMENT);
CMUSB_DecrementIoCount(DeviceObject);
// Release the remove lock
SmartcardReleaseRemoveLock(&DeviceExtension->SmartcardExtension);
SmartcardDebug(DEBUG_TRACE,
("%s!ProcessPnPIrp: Exit %lx\n",DRIVER_NAME,NTStatus));
return NTStatus;
}
IoCopyCurrentIrpStackLocationToNext(Irp);
//
// All PNP_POWER messages get passed to the TopOfStackDeviceObject
// we were given in PnPAddDevice
//
SmartcardDebug(DEBUG_DRIVER,
("%s!ProcessPnPIrp: Passing PnP Irp down, NTStatus = %x\n",DRIVER_NAME,NTStatus));
NTStatus = IoCallDriver(stackDeviceObject,Irp);
CMUSB_DecrementIoCount(DeviceObject);
// Release the remove lock
SmartcardReleaseRemoveLock(&DeviceExtension->SmartcardExtension);
SmartcardDebug(DEBUG_TRACE,
("%s!ProcessPnPIrp: Exit %lx\n",DRIVER_NAME,NTStatus));
return NTStatus;
}
/*****************************************************************************
Routine Description:
This routine is called to create and initialize our Functional Device Object (FDO).
For monolithic drivers, this is done in DriverEntry(), but Plug and Play devices
wait for a PnP event
Arguments:
DriverObject - pointer to the driver object for this instance of CMUSB
PhysicalDeviceObject - pointer to a device object created by the bus
Return Value:
STATUS_SUCCESS if successful,
STATUS_UNSUCCESSFUL otherwise
*****************************************************************************/
NTSTATUS CMUSB_PnPAddDevice(
IN PDRIVER_OBJECT DriverObject,
IN PDEVICE_OBJECT PhysicalDeviceObject
)
{
NTSTATUS NTStatus = STATUS_SUCCESS;
PDEVICE_OBJECT deviceObject = NULL;
PDEVICE_EXTENSION DeviceExtension;
USBD_VERSION_INFORMATION versionInformation;
ULONG i;
SmartcardDebug(DEBUG_TRACE,
("%s!PnPAddDevice: Enter\n",DRIVER_NAME));
//
// create our funtional device object (FDO)
//
NTStatus = CMUSB_CreateDeviceObject(DriverObject,
PhysicalDeviceObject,
&deviceObject);
SmartcardDebug(DEBUG_DRIVER,
("%s!PnPAddDevice: DeviceObject = %p\n",DRIVER_NAME,deviceObject));
if (NT_SUCCESS(NTStatus))
{
DeviceExtension = deviceObject->DeviceExtension;
deviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
//
// we support direct io for read/write
//
deviceObject->Flags |= DO_DIRECT_IO;
//Set this flag causes the driver to not receive a IRP_MN_STOP_DEVICE
//during suspend and also not get an IRP_MN_START_DEVICE during resume.
//This is neccesary because during the start device call,
// the GetDescriptors() call will be failed by the USB stack.
deviceObject->Flags |= DO_POWER_PAGABLE;
// initialize our device extension
//
// remember the Physical device Object
//
DeviceExtension->PhysicalDeviceObject=PhysicalDeviceObject;
//
// Attach to the PDO
//
DeviceExtension->TopOfStackDeviceObject =
IoAttachDeviceToDeviceStack(deviceObject, PhysicalDeviceObject);
// Get a copy of the physical device's capabilities into a
// DEVICE_CAPABILITIES struct in our device extension;
// We are most interested in learning which system power states
// are to be mapped to which device power states for handling
// IRP_MJ_SET_POWER Irps.
CMUSB_QueryCapabilities(PhysicalDeviceObject,
&DeviceExtension->DeviceCapabilities);
// We want to determine what level to auto-powerdown to; This is the lowest
// sleeping level that is LESS than D3;
// If all are set to D3, auto powerdown/powerup will be disabled.
DeviceExtension->PowerDownLevel = PowerDeviceUnspecified; // init to disabled
for (i=PowerSystemSleeping1; i<= PowerSystemSleeping3; i++)
{
if ( DeviceExtension->DeviceCapabilities.DeviceState[i] < PowerDeviceD3 )
DeviceExtension->PowerDownLevel = DeviceExtension->DeviceCapabilities.DeviceState[i];
}
#if DBG
//
// display the device caps
//
SmartcardDebug( DEBUG_DRIVER,("%s!PnPAddDevice: ----------- DeviceCapabilities ------------\n",
DRIVER_NAME));
SmartcardDebug( DEBUG_DRIVER, ("%s!PnPAddDevice: SystemWake = %s\n",
DRIVER_NAME,
CMUSB_StringForSysState( DeviceExtension->DeviceCapabilities.SystemWake ) ));
SmartcardDebug( DEBUG_DRIVER, ("%s!PnPAddDevice: DeviceWake = %s\n",
DRIVER_NAME,
CMUSB_StringForDevState( DeviceExtension->DeviceCapabilities.DeviceWake) ));
for (i=PowerSystemUnspecified; i< PowerSystemMaximum; i++)
{
SmartcardDebug(DEBUG_DRIVER,("%s!PnPAddDevice: sysstate %s = devstate %s\n",
DRIVER_NAME,
CMUSB_StringForSysState( i ),
CMUSB_StringForDevState( DeviceExtension->DeviceCapabilities.DeviceState[i] ))
);
}
SmartcardDebug( DEBUG_DRIVER,("PnPAddDevice: ---------------------------------------------\n"));
#endif
// We keep a pending IO count ( extension->PendingIoCount ) in the device extension.
// The first increment of this count is done on adding the device.
// Subsequently, the count is incremented for each new IRP received and
// decremented when each IRP is completed or passed on.
// Transition to 'one' therefore indicates no IO is pending and signals
// DeviceExtension->NoPendingIoEvent. This is needed for processing
// IRP_MN_QUERY_REMOVE_DEVICE
// Transition to 'zero' signals an event ( DeviceExtension->RemoveEvent )
// to enable device removal. This is used in processing for IRP_MN_REMOVE_DEVICE
//
CMUSB_IncrementIoCount(deviceObject);
}
USBD_GetUSBDIVersion(&versionInformation);
SmartcardDebug(DEBUG_TRACE,
("%s!PnPAddDevice: Exit %lx\n",DRIVER_NAME,NTStatus));
return NTStatus;
}
/*****************************************************************************
Routine Description:
Called from CMUSB_ProcessPnPIrp, the dispatch routine for IRP_MJ_PNP.
Initializes a given instance of the device on the USB.
USB client drivers such as us set up URBs (USB Request Packets) to send requests
to the host controller driver (HCD). The URB structure defines a format for all
possible commands that can be sent to a USB device.
Here, we request the device descriptor and store it, and configure the device.
Arguments:
DeviceObject - pointer to the FDO (Functional Device Object)
Return Value:
NT NTStatus code
*****************************************************************************/
NTSTATUS CMUSB_StartDevice(
IN PDEVICE_OBJECT DeviceObject
)
{
PDEVICE_EXTENSION DeviceExtension;
NTSTATUS NTStatus;
PUSB_DEVICE_DESCRIPTOR deviceDescriptor = NULL;
PURB urb;
ULONG siz;
SmartcardDebug(DEBUG_TRACE,
("%s!StartDevice: Enter\n",DRIVER_NAME));
DeviceExtension = DeviceObject->DeviceExtension;
urb = ExAllocatePool(NonPagedPool,
sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST));
if (urb != NULL)
{
siz = sizeof(USB_DEVICE_DESCRIPTOR);
deviceDescriptor = ExAllocatePool(NonPagedPool,siz);
if (deviceDescriptor != NULL)
{
UsbBuildGetDescriptorRequest(urb,
(USHORT) sizeof (struct _URB_CONTROL_DESCRIPTOR_REQUEST),
USB_DEVICE_DESCRIPTOR_TYPE,
0,
0,
deviceDescriptor,
NULL,
siz,
NULL);
NTStatus = CMUSB_CallUSBD(DeviceObject, urb);
if (NT_SUCCESS(NTStatus))
{
SmartcardDebug( DEBUG_DRIVER,("%s!StartDevice: Device Descriptor = %x, len %x\n",DRIVER_NAME,deviceDescriptor,
urb->UrbControlDescriptorRequest.TransferBufferLength));
SmartcardDebug( DEBUG_DRIVER,("%s!StartDevice: CardMan USB Device Descriptor:\n",DRIVER_NAME));
SmartcardDebug( DEBUG_DRIVER,("%s!StartDevice: -------------------------\n",DRIVER_NAME));
SmartcardDebug( DEBUG_DRIVER,("%s!StartDevice: bLength %d\n",DRIVER_NAME,deviceDescriptor->bLength));
SmartcardDebug( DEBUG_DRIVER,("%s!StartDevice: bDescriptorType 0x%x\n",DRIVER_NAME,deviceDescriptor->bDescriptorType));
SmartcardDebug( DEBUG_DRIVER,("%s!StartDevice: bcdUSB 0x%x\n",DRIVER_NAME,deviceDescriptor->bcdUSB));
SmartcardDebug( DEBUG_DRIVER,("%s!StartDevice: bDeviceClass 0x%x\n",DRIVER_NAME,deviceDescriptor->bDeviceClass));
SmartcardDebug( DEBUG_DRIVER,("%s!StartDevice: bDeviceSubClass 0x%x\n",DRIVER_NAME,deviceDescriptor->bDeviceSubClass));
SmartcardDebug( DEBUG_DRIVER,("%s!StartDevice: bDeviceProtocol 0x%x\n",DRIVER_NAME,deviceDescriptor->bDeviceProtocol));
SmartcardDebug( DEBUG_DRIVER,("%s!StartDevice: bMaxPacketSize0 0x%x\n",DRIVER_NAME,deviceDescriptor->bMaxPacketSize0));
SmartcardDebug( DEBUG_DRIVER,("%s!StartDevice: idVendor 0x%x\n",DRIVER_NAME,deviceDescriptor->idVendor));
SmartcardDebug( DEBUG_DRIVER,("%s!StartDevice: idProduct 0x%x\n",DRIVER_NAME,deviceDescriptor->idProduct));
SmartcardDebug( DEBUG_DRIVER,("%s!StartDevice: bcdDevice 0x%x\n",DRIVER_NAME,deviceDescriptor->bcdDevice));
SmartcardDebug( DEBUG_DRIVER,("%s!StartDevice: iManufacturer 0x%x\n",DRIVER_NAME,deviceDescriptor->iManufacturer));
SmartcardDebug( DEBUG_DRIVER,("%s!StartDevice: iProduct 0x%x\n",DRIVER_NAME,deviceDescriptor->iProduct));
SmartcardDebug( DEBUG_DRIVER,("%s!StartDevice: iSerialNumber 0x%x\n",DRIVER_NAME,deviceDescriptor->iSerialNumber));
SmartcardDebug( DEBUG_DRIVER,("%s!StartDevice: bNumConfigurations 0x%x\n",DRIVER_NAME,deviceDescriptor->bNumConfigurations));
}
}
else
{
// if we got here we failed to allocate deviceDescriptor
SmartcardDebug(DEBUG_ERROR,
( "%s!StartDevice: ExAllocatePool for deviceDescriptor failed\n",DRIVER_NAME));
NTStatus = STATUS_INSUFFICIENT_RESOURCES;
}
if (NT_SUCCESS(NTStatus))
{
DeviceExtension->UsbDeviceDescriptor = deviceDescriptor;
// -------------------------------------------------------------
// copy the firmware version to the reader extension structure
// -------------------------------------------------------------
DeviceExtension->SmartcardExtension.ReaderExtension->ulFWVersion =
(ULONG)(((DeviceExtension->UsbDeviceDescriptor->bcdDevice/256)*100)+
(DeviceExtension->UsbDeviceDescriptor->bcdDevice&0x00FF));
SmartcardDebug(DEBUG_DRIVER,
("%s!StartDevice: FW version = %ld\n",DRIVER_NAME,DeviceExtension->SmartcardExtension.ReaderExtension->ulFWVersion));
}
else if (deviceDescriptor != NULL)
{
ExFreePool(deviceDescriptor);
}
ExFreePool(urb);
}
else
{
// if we got here we failed to allocate the urb
SmartcardDebug(DEBUG_ERROR,
("%s!StartDevice: ExAllocatePool for usb failed\n",DRIVER_NAME));
NTStatus = STATUS_INSUFFICIENT_RESOURCES;
}
if (NT_SUCCESS(NTStatus))
{
NTStatus = CMUSB_ConfigureDevice(DeviceObject);
}
if (NT_SUCCESS(NTStatus))
{
NTStatus = CMUSB_StartCardTracking(DeviceObject);
}
if (NT_SUCCESS(NTStatus) && DeviceExtension->fPnPResourceManager == TRUE)
{
// enable interface
NTStatus = IoSetDeviceInterfaceState(&DeviceExtension->PnPDeviceName,TRUE);
}
if (NT_SUCCESS(NTStatus))
{
DeviceExtension->DeviceStarted = TRUE;
}
SmartcardDebug(DEBUG_TRACE,
("%s!StartDevice: Exit %ld\n",DRIVER_NAME,NTStatus));
return NTStatus;
}
/*****************************************************************************
Routine Description:
Called from CMUSB_ProcessPnPIrp: to
clean up our device instance's allocated buffers; free symbolic links
Arguments:
DeviceObject - pointer to the FDO
Return Value:
NT NTStatus code from free symbolic link operation
*****************************************************************************/
NTSTATUS CMUSB_RemoveDevice(
IN PDEVICE_OBJECT DeviceObject
)
{
PDEVICE_EXTENSION DeviceExtension;
PSMARTCARD_EXTENSION SmartcardExtension;
NTSTATUS NTStatus = STATUS_SUCCESS;
UNICODE_STRING deviceLinkUnicodeString;
SmartcardDebug(DEBUG_TRACE,
("%s!RemoveDevice: Enter\n",DRIVER_NAME));
DeviceExtension = DeviceObject->DeviceExtension;
SmartcardExtension = &DeviceExtension->SmartcardExtension;
SmartcardDebug(DEBUG_DRIVER,
("%s!RemoveDevice: DeviceStarted=%ld\n",DRIVER_NAME,DeviceExtension->DeviceStarted));
SmartcardDebug(DEBUG_DRIVER,
("%s!RemoveDevice: DeviceOpened=%ld\n",DRIVER_NAME,DeviceExtension->lOpenCount));
if (SmartcardExtension->OsData != NULL)
{
// complete pending card tracking requests (if any)
if (SmartcardExtension->OsData->NotificationIrp != NULL)
{
CMUSB_CompleteCardTracking(SmartcardExtension);
}
ASSERT(SmartcardExtension->OsData->NotificationIrp == NULL);
}
// Wait until we can safely unload the device
SmartcardReleaseRemoveLockAndWait(SmartcardExtension);
if (DeviceExtension->DeviceStarted == TRUE)
{
if (DeviceExtension->fPnPResourceManager == FALSE)
{
KeWaitForSingleObject(&SmartcardExtension->ReaderExtension->CardManIOMutex,
Executive,
KernelMode,
FALSE,
NULL);
// issue a card removal event for the resource manager
if (SmartcardExtension->ReaderExtension->ulOldCardState == INSERTED ||
SmartcardExtension->ReaderExtension->ulOldCardState == POWERED )
{
// card has been removed
SmartcardDebug(DEBUG_DRIVER,
("%s!RemoveDevice: Smartcard removed\n",DRIVER_NAME));
CMUSB_CompleteCardTracking(SmartcardExtension);
SmartcardExtension->ReaderExtension->ulOldCardState = UNKNOWN;
SmartcardExtension->ReaderExtension->ulNewCardState = UNKNOWN;
SmartcardExtension->ReaderCapabilities.CurrentState = SCARD_ABSENT;
SmartcardExtension->CardCapabilities.Protocol.Selected = SCARD_PROTOCOL_UNDEFINED;
SmartcardExtension->CardCapabilities.ATR.Length = 0;
RtlFillMemory((PVOID)&SmartcardExtension->ReaderExtension->CardParameters,
sizeof(CARD_PARAMETERS),0x00);
}
KeReleaseMutex(&SmartcardExtension->ReaderExtension->CardManIOMutex,FALSE);
}
CMUSB_StopDevice(DeviceObject);
}
if (DeviceExtension->fPnPResourceManager == TRUE)
{
// disable interface
NTStatus = IoSetDeviceInterfaceState(&DeviceExtension->PnPDeviceName,
FALSE);
if (DeviceExtension->PnPDeviceName.Buffer != NULL)
{
RtlFreeUnicodeString(&DeviceExtension->PnPDeviceName);
DeviceExtension->PnPDeviceName.Buffer = NULL;
}
SmartcardDebug(DEBUG_DRIVER,
("%s!RemoveDevice: PnPDeviceName.Buffer = %lx\n",DRIVER_NAME,
DeviceExtension->PnPDeviceName.Buffer));
SmartcardDebug(DEBUG_DRIVER,
("%s!RemoveDevice: PnPDeviceName.BufferLength = %lx\n",DRIVER_NAME,
DeviceExtension->PnPDeviceName.Length));
}
else
{
//
// Delete the symbolic link of the smart card reader
//
IoDeleteSymbolicLink(&DeviceExtension->DosDeviceName);
}
DeviceSlot[SmartcardExtension->ReaderExtension->ulDeviceInstance] = FALSE;
OemDeviceSlot[SmartcardExtension->ReaderExtension->ulOemNameIndex][SmartcardExtension->ReaderExtension->ulOemDeviceInstance] = FALSE;
if (DeviceExtension->lOpenCount == 0)
{
SmartcardDebug(DEBUG_DRIVER,
("%s!RemoveDevice: freeing resources\n",DRIVER_NAME));
if (DeviceExtension->fPnPResourceManager == FALSE)
{
//
// Free all allocated buffer
//
ExFreePool(DeviceExtension->DosDeviceName.Buffer);
}
ExFreePool(SmartcardExtension->ReaderExtension);
SmartcardExtension->ReaderExtension = NULL;
//
// Let the lib free the send/receive buffers
//
SmartcardExit(SmartcardExtension);
}
SmartcardDebug(DEBUG_TRACE,
("%s!RemoveDevice: Exit %lx\n",DRIVER_NAME,NTStatus));
return NTStatus;
}
/*****************************************************************************
Routine Description:
Stops a given instance of a 82930 device on the USB.
We basically just tell USB this device is now 'unconfigured'
Arguments:
DeviceObject - pointer to the device object for this instance of a 82930
Return Value:
NT NTStatus code
*****************************************************************************/
NTSTATUS CMUSB_StopDevice(
IN PDEVICE_OBJECT DeviceObject
)
{
PDEVICE_EXTENSION DeviceExtension;
PSMARTCARD_EXTENSION SmartcardExtension;
NTSTATUS NTStatus = STATUS_SUCCESS;
PURB urb;
ULONG siz;
DeviceExtension = DeviceObject->DeviceExtension;
SmartcardExtension = &DeviceExtension->SmartcardExtension;
SmartcardDebug(DEBUG_TRACE,
("%s!StopDevice: Enter\n",DRIVER_NAME));
DeviceExtension = DeviceObject->DeviceExtension;
SmartcardDebug(DEBUG_DRIVER,
("%s!StopDevice: DeviceStarted=%ld\n",DRIVER_NAME,
DeviceExtension->DeviceStarted));
SmartcardDebug( DEBUG_DRIVER,
("%s!StopDevice: DeviceOpened=%ld\n",DRIVER_NAME,
DeviceExtension->lOpenCount));
// stop update thread
CMUSB_StopCardTracking(DeviceObject);
// power down the card for saftey reasons
if (DeviceExtension->SmartcardExtension.ReaderExtension->ulOldCardState == POWERED)
{
// we have to wait for the mutex before
KeWaitForSingleObject(&DeviceExtension->SmartcardExtension.ReaderExtension->CardManIOMutex,
Executive,
KernelMode,
FALSE,
NULL);
CMUSB_PowerOffCard(&DeviceExtension->SmartcardExtension);
KeReleaseMutex(&DeviceExtension->SmartcardExtension.ReaderExtension->CardManIOMutex,
FALSE);
}
//
// Send the select configuration urb with a NULL pointer for the configuration
// handle. This closes the configuration and puts the device in the 'unconfigured'
// state.
//
siz = sizeof(struct _URB_SELECT_CONFIGURATION);
urb = ExAllocatePool(NonPagedPool,siz);
if (urb != NULL)
{
UsbBuildSelectConfigurationRequest(urb,
(USHORT) siz,
NULL);
NTStatus = CMUSB_CallUSBD(DeviceObject, urb);
ExFreePool(urb);
}
else
{
NTStatus = STATUS_INSUFFICIENT_RESOURCES;
}
// now clear the flag whcih indicates if the device is started
DeviceExtension->DeviceStarted = FALSE;
DeviceExtension->StopDeviceRequested = FALSE;
//
// Free device descriptor structure
//
if (DeviceExtension->UsbDeviceDescriptor != NULL)
{
SmartcardDebug( DEBUG_DRIVER,
("%s!StopDevice: freeing UsbDeviceDescriptor\n",DRIVER_NAME,NTStatus));
ExFreePool(DeviceExtension->UsbDeviceDescriptor);
DeviceExtension->UsbDeviceDescriptor = NULL;
}
//
// Free up the UsbInterface structure
//
if (DeviceExtension->UsbInterface != NULL)
{
SmartcardDebug( DEBUG_DRIVER,
("%s!StopDevice: freeing UsbInterface\n",DRIVER_NAME,NTStatus));
ExFreePool(DeviceExtension->UsbInterface);
DeviceExtension->UsbInterface = NULL;
}
// free up the USB config discriptor
if (DeviceExtension->UsbConfigurationDescriptor != NULL)
{
SmartcardDebug( DEBUG_DRIVER,
("%s!StopDevice: freeing UsbConfiguration\n",DRIVER_NAME,NTStatus));
ExFreePool(DeviceExtension->UsbConfigurationDescriptor);
DeviceExtension->UsbConfigurationDescriptor = NULL;
}
SmartcardDebug( DEBUG_TRACE,
("%s!StopDevice: Exit %lx\n",DRIVER_NAME,NTStatus));
return NTStatus;
}
/*****************************************************************************
Routine Description:
Used as a general purpose completion routine so it can signal an event,
passed as the Context, when the next lower driver is done with the input Irp.
This routine is used by both PnP and Power Management logic.
Even though this routine does nothing but set an event, it must be defined and
prototyped as a completetion routine for use as such
Arguments:
DeviceObject - Pointer to the device object for the class device.
Irp - Irp completed.
Context - Driver defined context, in this case a pointer to an event.
Return Value:
The function value is the final NTStatus from the operation.
*****************************************************************************/
NTSTATUS CMUSB_IrpCompletionRoutine(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Context
)
{
PKEVENT event = Context;
// Set the input event
KeSetEvent(event,
1, // Priority increment for waiting thread.
FALSE); // Flag this call is not immediately followed by wait.
// This routine must return STATUS_MORE_PROCESSING_REQUIRED because we have not yet called
// IoFreeIrp() on this IRP.
return STATUS_MORE_PROCESSING_REQUIRED;
}
/*****************************************************************************
Routine Description:
This is our FDO's dispatch table function for IRP_MJ_POWER.
It processes the Power IRPs sent to the PDO for this device.
For every power IRP, drivers must call PoStartNextPowerIrp and use PoCallDriver
to pass the IRP all the way down the driver stack to the underlying PDO.
Arguments:
DeviceObject - pointer to our device object (FDO)
Irp - pointer to an I/O Request Packet
Return Value:
NT NTStatus code
*****************************************************************************/
NTSTATUS CMUSB_ProcessPowerIrp(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
{
PIO_STACK_LOCATION irpStack;
NTSTATUS NTStatus = STATUS_SUCCESS;
PDEVICE_EXTENSION DeviceExtension;
BOOLEAN fGoingToD0 = FALSE;
POWER_STATE sysPowerState, desiredDevicePowerState;
KEVENT event;
SmartcardDebug(DEBUG_TRACE,
("%s!ProcessPowerIrp Enter\n",DRIVER_NAME));
DeviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
irpStack = IoGetCurrentIrpStackLocation (Irp);
CMUSB_IncrementIoCount(DeviceObject);
switch (irpStack->MinorFunction)
{
// ----------------
// IRP_MN_WAIT_WAKE
// ----------------
case IRP_MN_WAIT_WAKE:
// A driver sends IRP_MN_WAIT_WAKE to indicate that the system should
// wait for its device to signal a wake event. The exact nature of the event
// is device-dependent.
// Drivers send this IRP for two reasons:
// 1) To allow a device to wake the system
// 2) To wake a device that has been put into a sleep state to save power
// but still must be able to communicate with its driver under certain circumstances.
// When a wake event occurs, the driver completes the IRP and returns
// STATUS_SUCCESS. If the device is sleeping when the event occurs,
// the driver must first wake up the device before completing the IRP.
// In a completion routine, the driver calls PoRequestPowerIrp to send a
// PowerDeviceD0 request. When the device has powered up, the driver can
// handle the IRP_MN_WAIT_WAKE request.
SmartcardDebug( DEBUG_DRIVER,
("%s!IRP_MN_WAIT_WAKE received\n",DRIVER_NAME));
// DeviceExtension->DeviceCapabilities.DeviceWake specifies the lowest device power state (least powered)
// from which the device can signal a wake event
DeviceExtension->PowerDownLevel = DeviceExtension->DeviceCapabilities.DeviceWake;
if ( ( PowerDeviceD0 == DeviceExtension->CurrentDevicePowerState ) ||
( DeviceExtension->DeviceCapabilities.DeviceWake > DeviceExtension->CurrentDevicePowerState ) )
{
// STATUS_INVALID_DEVICE_STATE is returned if the device in the PowerD0 state
// or a state below which it can support waking, or if the SystemWake state
// is below a state which can be supported. A pending IRP_MN_WAIT_WAKE will complete
// with this error if the device's state is changed to be incompatible with the wake
// request.
// If a driver fails this IRP, it should complete the IRP immediately without
// passing the IRP to the next-lower driver.
NTStatus = STATUS_INVALID_DEVICE_STATE;
Irp->IoStatus.Status = NTStatus;
IoCompleteRequest (Irp,IO_NO_INCREMENT );
SmartcardDebug( DEBUG_DRIVER,
("%s!ProcessPowerIrp Exit %lx\n",DRIVER_NAME,NTStatus));
CMUSB_DecrementIoCount(DeviceObject);
return NTStatus;
}
// flag we're enabled for wakeup
DeviceExtension->EnabledForWakeup = TRUE;
// init an event for our completion routine to signal when PDO is done with this Irp
KeInitializeEvent(&event, NotificationEvent, FALSE);
// If not failing outright, pass this on to our PDO for further handling
IoCopyCurrentIrpStackLocationToNext(Irp);
// Set a completion routine so it can signal our event when
// the PDO is done with the Irp
IoSetCompletionRoutine(Irp,
CMUSB_IrpCompletionRoutine,
&event, // pass the event to the completion routine as the Context
TRUE, // invoke on success
TRUE, // invoke on error
TRUE); // invoke on cancellation
PoStartNextPowerIrp(Irp);
NTStatus = PoCallDriver(DeviceExtension->TopOfStackDeviceObject,
Irp);
// if PDO is not done yet, wait for the event to be set in our completion routine
if (NTStatus == STATUS_PENDING)
{
// wait for irp to complete
NTSTATUS waitStatus = KeWaitForSingleObject(&event,
Suspended,
KernelMode,
FALSE,
NULL);
SmartcardDebug( DEBUG_DRIVER,
("%s!waiting for PDO to finish IRP_MN_WAIT_WAKE completed\n",DRIVER_NAME));
}
// now tell the device to actually wake up
CMUSB_SelfSuspendOrActivate( DeviceObject, FALSE );
// flag we're done with wakeup irp
DeviceExtension->EnabledForWakeup = FALSE;
CMUSB_DecrementIoCount(DeviceObject);
break;
// ------------------
// IRP_MN_SET_POWER
// ------------------
case IRP_MN_SET_POWER:
// The system power policy manager sends this IRP to set the system power state.
// A device power policy manager sends this IRP to set the device power state for a device.
// Set Irp->IoStatus.Status to STATUS_SUCCESS to indicate that the device
// has entered the requested state. Drivers cannot fail this IRP.
SmartcardDebug( DEBUG_DRIVER,
("%s!IRP_MN_SET_POWER\n",DRIVER_NAME));
switch (irpStack->Parameters.Power.Type)
{
// +++++++++++++++++++
// SystemPowerState
// +++++++++++++++++++
case SystemPowerState:
// Get input system power state
sysPowerState.SystemState = irpStack->Parameters.Power.State.SystemState;
SmartcardDebug( DEBUG_DRIVER,
("%s!SystemPowerState = %s\n",DRIVER_NAME,
CMUSB_StringForSysState( sysPowerState.SystemState)));
// If system is in working state always set our device to D0
// regardless of the wait state or system-to-device state power map
if (sysPowerState.SystemState == PowerSystemWorking)
{
desiredDevicePowerState.DeviceState = PowerDeviceD0;
SmartcardDebug( DEBUG_DRIVER,
("%s!PowerSystemWorking, will set D0, not use state map\n",DRIVER_NAME));
}
else
{
// set to corresponding system state if IRP_MN_WAIT_WAKE pending
if ( DeviceExtension->EnabledForWakeup ) // got a WAIT_WAKE IRP pending?
{
// Find the device power state equivalent to the given system state.
// We get this info from the DEVICE_CAPABILITIES struct in our device
// extension (initialized in CMUSB_PnPAddDevice() )
desiredDevicePowerState.DeviceState =
DeviceExtension->DeviceCapabilities.DeviceState[ sysPowerState.SystemState ];
SmartcardDebug(DEBUG_DRIVER,
("%s!IRP_MN_WAIT_WAKE pending, will use state map\n",DRIVER_NAME));
}
else
{
// if no wait pending and the system's not in working state, just turn off
desiredDevicePowerState.DeviceState = PowerDeviceD3;
SmartcardDebug(DEBUG_DRIVER,
("%s!Not EnabledForWakeup and the system's not in working state,\n settting PowerDeviceD3 (off)\n",DRIVER_NAME));
}
if (sysPowerState.SystemState == PowerSystemShutdown)
{
// power down the card for saftey reasons
if (DeviceExtension->SmartcardExtension.ReaderExtension->ulOldCardState == POWERED)
{
// we have to wait for the mutex before
KeWaitForSingleObject(&DeviceExtension->SmartcardExtension.ReaderExtension->CardManIOMutex,
Executive,
KernelMode,
FALSE,
NULL);
CMUSB_PowerOffCard(&DeviceExtension->SmartcardExtension);
KeReleaseMutex(&DeviceExtension->SmartcardExtension.ReaderExtension->CardManIOMutex,
FALSE);
}
}
}
//
// We've determined the desired device state; are we already in this state?
//
SmartcardDebug(DEBUG_DRIVER,
("%s!desiredDevicePowerState = %s\n",DRIVER_NAME,CMUSB_StringForDevState(desiredDevicePowerState.DeviceState)));
if (desiredDevicePowerState.DeviceState != DeviceExtension->CurrentDevicePowerState)
{
CMUSB_IncrementIoCount(DeviceObject);
// No, request that we be put into this state
// by requesting a new Power Irp from the Pnp manager
DeviceExtension->PowerIrp = Irp;
IoMarkIrpPending(Irp);
NTStatus = PoRequestPowerIrp(DeviceExtension->PhysicalDeviceObject,
IRP_MN_SET_POWER,
desiredDevicePowerState,
// completion routine will pass the Irp down to the PDO
CMUSB_PoRequestCompletion,
DeviceObject,
NULL);
}
else
{
// Yes, just pass it on to PDO (Physical Device Object)
IoCopyCurrentIrpStackLocationToNext(Irp);
PoStartNextPowerIrp(Irp);
NTStatus = PoCallDriver(DeviceExtension->TopOfStackDeviceObject,Irp);
CMUSB_DecrementIoCount(DeviceObject);
}
break;
// ++++++++++++++++++
// DevicePowerState
// ++++++++++++++++++
case DevicePowerState:
// For requests to D1, D2, or D3 ( sleep or off states ),
// sets DeviceExtension->CurrentDevicePowerState to DeviceState immediately.
// This enables any code checking state to consider us as sleeping or off
// already, as this will imminently become our state.
SmartcardDebug(DEBUG_DRIVER,
("%s!DevicePowerState = %s\n",DRIVER_NAME,
CMUSB_StringForDevState(irpStack->Parameters.Power.State.DeviceState)));
// For requests to DeviceState D0 ( fully on ), sets fGoingToD0 flag TRUE
// to flag that we must set a completion routine and update
// DeviceExtension->CurrentDevicePowerState there.
// In the case of powering up to fully on, we really want to make sure
// the process is completed before updating our CurrentDevicePowerState,
// so no IO will be attempted or accepted before we're really ready.
fGoingToD0 = CMUSB_SetDevicePowerState(DeviceObject,
irpStack->Parameters.Power.State.DeviceState); // returns TRUE for D0
IoCopyCurrentIrpStackLocationToNext(Irp);
if (fGoingToD0 == TRUE)
{
SmartcardDebug( DEBUG_DRIVER,("%s!going to D0\n",DRIVER_NAME));
IoSetCompletionRoutine(Irp,
CMUSB_PowerIrp_Complete,
// Always pass FDO to completion routine as its Context;
// This is because the DriverObject passed by the system to the routine
// is the Physical Device Object ( PDO ) not the Functional Device Object ( FDO )
DeviceObject,
TRUE, // invoke on success
TRUE, // invoke on error
TRUE); // invoke on cancellation of the Irp
}
PoStartNextPowerIrp(Irp);
NTStatus = PoCallDriver(DeviceExtension->TopOfStackDeviceObject,
Irp);
if (fGoingToD0 == FALSE) // completion routine will decrement
CMUSB_DecrementIoCount(DeviceObject);
break;
} /* case irpStack->Parameters.Power.Type */
break; /* IRP_MN_SET_POWER */
// ------------------
// IRP_MN_QUERY_POWER
// ------------------
case IRP_MN_QUERY_POWER:
//
// A power policy manager sends this IRP to determine whether it can change
// the system or device power state, typically to go to sleep.
//
SmartcardDebug(DEBUG_DRIVER,
("%s!IRP_MN_QUERY_POWER received\n",DRIVER_NAME));
switch (irpStack->Parameters.Power.Type)
{
// +++++++++++++++++++
// SystemPowerState
// +++++++++++++++++++
case SystemPowerState:
SmartcardDebug( DEBUG_DRIVER,
("%s!SystemPowerState = %s\n",DRIVER_NAME,
CMUSB_StringForSysState(irpStack->Parameters.Power.State.SystemState)));
break;
// ++++++++++++++++++
// DevicePowerState
// ++++++++++++++++++
case DevicePowerState:
// For requests to D1, D2, or D3 ( sleep or off states ),
// sets DeviceExtension->CurrentDevicePowerState to DeviceState immediately.
// This enables any code checking state to consider us as sleeping or off
// already, as this will imminently become our state.
SmartcardDebug(DEBUG_DRIVER,
("%s!DevicePowerState = %s\n",DRIVER_NAME,
CMUSB_StringForDevState(irpStack->Parameters.Power.State.DeviceState)));
break;
}
// we do nothing special here, just let the PDO handle it
IoCopyCurrentIrpStackLocationToNext(Irp);
PoStartNextPowerIrp(Irp);
NTStatus = PoCallDriver(DeviceExtension->TopOfStackDeviceObject,
Irp);
CMUSB_DecrementIoCount(DeviceObject);
break; /* IRP_MN_QUERY_POWER */
default:
SmartcardDebug(DEBUG_DRIVER,
("%s!unknown POWER IRP received\n",DRIVER_NAME));
//
// All unhandled power messages are passed on to the PDO
//
IoCopyCurrentIrpStackLocationToNext(Irp);
PoStartNextPowerIrp(Irp);
NTStatus = PoCallDriver(DeviceExtension->TopOfStackDeviceObject, Irp);
CMUSB_DecrementIoCount(DeviceObject);
} /* irpStack->MinorFunction */
SmartcardDebug( DEBUG_TRACE,
("%s!ProcessPowerIrp Exit %lx\n",DRIVER_NAME,NTStatus));
return NTStatus;
}
/*****************************************************************************
Routine Description:
This is the completion routine set in a call to PoRequestPowerIrp()
that was made in CMUSB_ProcessPowerIrp() in response to receiving
an IRP_MN_SET_POWER of type 'SystemPowerState' when the device was
not in a compatible device power state. In this case, a pointer to
the IRP_MN_SET_POWER Irp is saved into the FDO device extension
(DeviceExtension->PowerIrp), and then a call must be
made to PoRequestPowerIrp() to put the device into a proper power state,
and this routine is set as the completion routine.
We decrement our pending io count and pass the saved IRP_MN_SET_POWER Irp
on to the next driver
Arguments:
DeviceObject - Pointer to the device object for the class device.
Note that we must get our own device object from the Context
Context - Driver defined context, in this case our own functional device object ( FDO )
Return Value:
The function value is the final NTStatus from the operation.
*****************************************************************************/
NTSTATUS CMUSB_PoRequestCompletion(
IN PDEVICE_OBJECT DeviceObject,
IN UCHAR MinorFunction,
IN POWER_STATE PowerState,
IN PVOID Context,
IN PIO_STATUS_BLOCK IoStatus
)
{
PIRP irp;
PDEVICE_EXTENSION DeviceExtension;
PDEVICE_OBJECT deviceObject = Context;
NTSTATUS NTStatus;
SmartcardDebug(DEBUG_TRACE,("%s!PoRequestCompletion Enter\n",DRIVER_NAME));
DeviceExtension = deviceObject->DeviceExtension;
// Get the Irp we saved for later processing in CMUSB_ProcessPowerIrp()
// when we decided to request the Power Irp that this routine
// is the completion routine for.
irp = DeviceExtension->PowerIrp;
// We will return the NTStatus set by the PDO for the power request we're completing
NTStatus = IoStatus->Status;
// we should not be in the midst of handling a self-generated power irp
CMUSB_ASSERT( !DeviceExtension->SelfPowerIrp );
// we must pass down to the next driver in the stack
IoCopyCurrentIrpStackLocationToNext(irp);
// Calling PoStartNextPowerIrp() indicates that the driver is finished
// with the previous power IRP, if any, and is ready to handle the next power IRP.
// It must be called for every power IRP.Although power IRPs are completed only once,
// typically by the lowest-level driver for a device, PoStartNextPowerIrp must be called
// for every stack location. Drivers must call PoStartNextPowerIrp while the current IRP
// stack location points to the current driver. Therefore, this routine must be called
// before IoCompleteRequest, IoSkipCurrentStackLocation, and PoCallDriver.
PoStartNextPowerIrp(irp);
// PoCallDriver is used to pass any power IRPs to the PDO instead of IoCallDriver.
// When passing a power IRP down to a lower-level driver, the caller should use
// IoSkipCurrentIrpStackLocation or IoCopyCurrentIrpStackLocationToNext to copy the IRP to
// the next stack location, then call PoCallDriver. Use IoCopyCurrentIrpStackLocationToNext
// if processing the IRP requires setting a completion routine, or IoSkipCurrentStackLocation
// if no completion routine is needed.
PoCallDriver(DeviceExtension->TopOfStackDeviceObject,irp);
CMUSB_DecrementIoCount(deviceObject);
DeviceExtension->PowerIrp = NULL;
SmartcardDebug(DEBUG_TRACE,("%s!PoRequestCompletion Exit %lx\n",DRIVER_NAME,NTStatus));
return NTStatus;
}
/*****************************************************************************
Routine Description:
This routine is called when An IRP_MN_SET_POWER of type 'DevicePowerState'
has been received by CMUSB_ProcessPowerIrp(), and that routine has determined
1) the request is for full powerup ( to PowerDeviceD0 ), and
2) We are not already in that state
A call is then made to PoRequestPowerIrp() with this routine set as the completion routine.
Arguments:
DeviceObject - Pointer to the device object for the class device.
Irp - Irp completed.
Context - Driver defined context.
Return Value:
The function value is the final NTStatus from the operation.
*****************************************************************************/
NTSTATUS CMUSB_PowerIrp_Complete(
IN PDEVICE_OBJECT NullDeviceObject,
IN PIRP Irp,
IN PVOID Context
)
{
NTSTATUS NTStatus = STATUS_SUCCESS;
PDEVICE_OBJECT deviceObject;
PIO_STACK_LOCATION irpStack;
PDEVICE_EXTENSION DeviceExtension;
SmartcardDebug(DEBUG_TRACE,("%s!PowerIrp_Complete Enter\n",DRIVER_NAME));
deviceObject = (PDEVICE_OBJECT) Context;
DeviceExtension = (PDEVICE_EXTENSION) deviceObject->DeviceExtension;
// if there was a card in the reader set the state to unknown,
// because we dont know if the card instered is the same as before power down
if (DeviceExtension->SmartcardExtension.ReaderExtension->ulNewCardState == INSERTED ||
DeviceExtension->SmartcardExtension.ReaderExtension->ulNewCardState == POWERED )
{
DeviceExtension->SmartcardExtension.ReaderExtension->ulOldCardState = UNKNOWN;
DeviceExtension->SmartcardExtension.ReaderExtension->ulNewCardState = UNKNOWN;
}
KeSetEvent(&DeviceExtension->CanRunUpdateThread, 0, FALSE);
// If the lower driver returned PENDING, mark our stack location as pending also.
if (Irp->PendingReturned == TRUE)
{
IoMarkIrpPending(Irp);
}
irpStack = IoGetCurrentIrpStackLocation (Irp);
// We can assert that we're a device powerup-to D0 request,
// because that was the only type of request we set a completion routine
// for in the first place
CMUSB_ASSERT(irpStack->MajorFunction == IRP_MJ_POWER);
CMUSB_ASSERT(irpStack->MinorFunction == IRP_MN_SET_POWER);
CMUSB_ASSERT(irpStack->Parameters.Power.Type==DevicePowerState);
CMUSB_ASSERT(irpStack->Parameters.Power.State.DeviceState==PowerDeviceD0);
// Now that we know we've let the lower drivers do what was needed to power up,
// we can set our device extension flags accordingly
DeviceExtension->CurrentDevicePowerState = PowerDeviceD0;
Irp->IoStatus.Status = NTStatus;
CMUSB_DecrementIoCount(deviceObject);
KeSetEvent(&DeviceExtension->ReaderEnabled, 0, FALSE);
SmartcardDebug(DEBUG_TRACE,("%s!PowerIrp_Complete Exit %lx\n",DRIVER_NAME,NTStatus));
return NTStatus;
}
/*****************************************************************************
Routine Description:
Called on CMUSB_PnPAddDevice() to power down until needed (i.e., till a pipe is actually opened).
Called on CMUSB_Create() to power up device to D0 before opening 1st pipe.
Called on CMUSB_Close() to power down device if this is the last pipe.
Arguments:
DeviceObject - Pointer to the device object
fSuspend; TRUE to Suspend, FALSE to acivate.
Return Value:
If the operation is not attemtped, SUCCESS is returned.
If the operation is attemtped, the value is the final NTStatus from the operation.
*****************************************************************************/
NTSTATUS CMUSB_SelfSuspendOrActivate(
IN PDEVICE_OBJECT DeviceObject,
IN BOOLEAN fSuspend
)
{
NTSTATUS NTStatus = STATUS_SUCCESS;
POWER_STATE PowerState;
PDEVICE_EXTENSION DeviceExtension;
DeviceExtension = DeviceObject->DeviceExtension;
SmartcardDebug( DEBUG_TRACE,("%s!SelfSuspendOrActivate: Enter, fSuspend = %d\n",DRIVER_NAME,fSuspend));
// Can't accept request if:
// 1) device is removed,
// 2) has never been started,
// 3) is stopped,
// 4) has a remove request pending,
// 5) has a stop device pending
if (CMUSB_CanAcceptIoRequests( DeviceObject ) == FALSE)
{
NTStatus = STATUS_DELETE_PENDING;
SmartcardDebug( DEBUG_TRACE,("%s!SelfSuspendOrActivate: ABORTING\n",DRIVER_NAME));
return NTStatus;
}
// don't do anything if any System-generated Device Pnp irps are pending
if ( DeviceExtension->PowerIrp != NULL)
{
SmartcardDebug( DEBUG_TRACE,("%s!SelfSuspendOrActivate: Exit, refusing on pending DeviceExtension->PowerIrp 0x%x\n",DRIVER_NAME,DeviceExtension->PowerIrp));
return NTStatus;
}
// don't do anything if any self-generated Device Pnp irps are pending
if ( DeviceExtension->SelfPowerIrp == TRUE)
{
SmartcardDebug( DEBUG_TRACE,("%s!SelfSuspendOrActivate: Exit, refusing on pending DeviceExtension->SelfPowerIrp\n",DRIVER_NAME));
return NTStatus;
}
// dont do anything if registry CurrentControlSet\Services\CMUSB\Parameters\PowerDownLevel
// has been set to zero, PowerDeviceD0 ( 1 ), or a bogus high value
if ( ( DeviceExtension->PowerDownLevel == PowerDeviceD0 ) ||
( DeviceExtension->PowerDownLevel == PowerDeviceUnspecified) ||
( DeviceExtension->PowerDownLevel >= PowerDeviceMaximum ) )
{
SmartcardDebug( DEBUG_TRACE,("%s!SelfSuspendOrActivate: Exit, refusing on DeviceExtension->PowerDownLevel == %d\n",DRIVER_NAME,DeviceExtension->PowerDownLevel));
return NTStatus;
}
if ( fSuspend == TRUE)
PowerState.DeviceState = DeviceExtension->PowerDownLevel;
else
PowerState.DeviceState = PowerDeviceD0; // power up all the way; we're probably just about to do some IO
NTStatus = CMUSB_SelfRequestPowerIrp( DeviceObject, PowerState );
SmartcardDebug( DEBUG_TRACE,("%s!SelfSuspendOrActivate: Exit, NTStatus 0x%x on setting dev state %s\n",DRIVER_NAME,NTStatus, CMUSB_StringForDevState(PowerState.DeviceState ) ));
return NTStatus;
}
/*****************************************************************************
Routine Description:
This routine is called by CMUSB_SelfSuspendOrActivate() to
actually make the system request for a powerdown/up to PowerState.
It first checks to see if we are already in Powerstate and immediately
returns SUCCESS with no further processing if so
Arguments:
DeviceObject - Pointer to the device object
PowerState. power state requested, e.g PowerDeviceD0.
Return Value:
The function value is the final NTStatus from the operation.
*****************************************************************************/
NTSTATUS CMUSB_SelfRequestPowerIrp(
IN PDEVICE_OBJECT DeviceObject,
IN POWER_STATE PowerState
)
{
NTSTATUS NTStatus = STATUS_SUCCESS;
NTSTATUS waitStatus;
PDEVICE_EXTENSION DeviceExtension;
PIRP pIrp = NULL;
SmartcardDebug(DEBUG_TRACE,
("%s!SelfRequestPowerIrp: request power irp to state %s\n",DRIVER_NAME));
DeviceExtension = DeviceObject->DeviceExtension;
// This should have been reset in completion routine
CMUSB_ASSERT( !DeviceExtension->SelfPowerIrp );
if ( DeviceExtension->CurrentDevicePowerState == PowerState.DeviceState )
return STATUS_SUCCESS; // nothing to do
SmartcardDebug(DEBUG_DRIVER,
("%s!SelfRequestPowerIrp: request power irp to state %s\n",DRIVER_NAME,
CMUSB_StringForDevState( PowerState.DeviceState )));
CMUSB_IncrementIoCount(DeviceObject);
// flag we're handling a self-generated power irp
DeviceExtension->SelfPowerIrp = TRUE;
// actually request the Irp
NTStatus = PoRequestPowerIrp(DeviceExtension->PhysicalDeviceObject,
IRP_MN_SET_POWER,
PowerState,
CMUSB_PoSelfRequestCompletion,
DeviceObject,
NULL);
if ( NTStatus == STATUS_PENDING )
{
// NTStatus pending is the return code we wanted
// We only need to wait for completion if we're powering up
if ( (ULONG) PowerState.DeviceState < DeviceExtension->PowerDownLevel )
{
waitStatus = KeWaitForSingleObject(&DeviceExtension->SelfRequestedPowerIrpEvent,
Suspended,
KernelMode,
FALSE,
NULL);
}
NTStatus = STATUS_SUCCESS;
DeviceExtension->SelfPowerIrp = FALSE;
}
else
{
// The return NTStatus was not STATUS_PENDING; any other codes must be considered in error here;
// i.e., it is not possible to get a STATUS_SUCCESS or any other non-error return from this call;
}
SmartcardDebug(DEBUG_TRACE,
("%s!SelfRequestPowerIrp: Exit %lx\n",DRIVER_NAME,NTStatus));
return NTStatus;
}
/*****************************************************************************
Routine Description:
This routine is called when the driver completes a self-originated power IRP
that was generated by a call to CMUSB_SelfSuspendOrActivate().
We power down whenever the last pipe is closed and power up when the first pipe is opened.
For power-up , we set an event in our FDO extension to signal this IRP done
so the power request can be treated as a synchronous call.
We need to know the device is powered up before opening the first pipe, for example.
For power-down, we do not set the event, as no caller waits for powerdown complete.
Arguments:
DeviceObject - Pointer to the device object for the class device. ( Physical Device Object )
Context - Driver defined context, in this case our FDO ( functional device object )
Return Value:
The function value is the final NTStatus from the operation.
*****************************************************************************/
NTSTATUS CMUSB_PoSelfRequestCompletion(
IN PDEVICE_OBJECT DeviceObject,
IN UCHAR MinorFunction,
IN POWER_STATE PowerState,
IN PVOID Context,
IN PIO_STATUS_BLOCK IoStatus
)
{
PDEVICE_OBJECT deviceObject = Context;
PDEVICE_EXTENSION DeviceExtension = deviceObject->DeviceExtension;
NTSTATUS NTStatus = IoStatus->Status;
// we should not be in the midst of handling a system-generated power irp
CMUSB_ASSERT( NULL == DeviceExtension->PowerIrp );
// We only need to set the event if we're powering up;
// No caller waits on power down complete
if ( (ULONG) PowerState.DeviceState < DeviceExtension->PowerDownLevel )
{
// Trigger Self-requested power irp completed event;
// The caller is waiting for completion
KeSetEvent(&DeviceExtension->SelfRequestedPowerIrpEvent, 1, FALSE);
}
CMUSB_DecrementIoCount(deviceObject);
return NTStatus;
}
/*****************************************************************************
Routine Description:
This routine is called when An IRP_MN_SET_POWER of type 'DevicePowerState'
has been received by CMUSB_ProcessPowerIrp().
Arguments:
DeviceObject - Pointer to the device object for the class device.
DeviceState - Device specific power state to set the device in to.
Return Value:
For requests to DeviceState D0 ( fully on ), returns TRUE to signal caller
that we must set a completion routine and finish there.
*****************************************************************************/
BOOLEAN CMUSB_SetDevicePowerState(
IN PDEVICE_OBJECT DeviceObject,
IN DEVICE_POWER_STATE DeviceState
)
{
NTSTATUS NTStatus = STATUS_SUCCESS;
PDEVICE_EXTENSION DeviceExtension;
BOOLEAN fRes = FALSE;
SmartcardDebug(DEBUG_TRACE,("%s!SetDevicePowerState Enter\n",DRIVER_NAME));
DeviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
switch (DeviceState)
{
case PowerDeviceD3:
SmartcardDebug(DEBUG_DRIVER,
("%s!SetDevicePowerState PowerDeviceD3 \n",DRIVER_NAME));
DeviceExtension->CurrentDevicePowerState = DeviceState;
KeClearEvent(&DeviceExtension->ReaderEnabled);
CMUSB_StopCardTracking(DeviceObject);
break;
case PowerDeviceD1:
case PowerDeviceD2:
SmartcardDebug(DEBUG_DRIVER,
("%s!SetDevicePowerState PowerDeviceD1/2 \n",DRIVER_NAME));
//
// power states D1,D2 translate to USB suspend
DeviceExtension->CurrentDevicePowerState = DeviceState;
break;
case PowerDeviceD0:
SmartcardDebug(DEBUG_DRIVER,
("%s!SetDevicePowerState PowerDeviceD0 \n",DRIVER_NAME));
// We'll need to finish the rest in the completion routine;
// signal caller we're going to D0 and will need to set a completion routine
fRes = TRUE;
// Caller will pass on to PDO ( Physical Device object )
//
// start update thread be signal that it should not run now
// this thread should be started in completion rourine
// but there we have a wrong IRQL for creating a thread
//
KeClearEvent(&DeviceExtension->CanRunUpdateThread);
NTStatus = CMUSB_StartCardTracking(DeviceObject);
break;
default:
SmartcardDebug(DEBUG_DRIVER,
("%s!SetDevicePowerState Inalid device power state \n",DRIVER_NAME));
}
SmartcardDebug(DEBUG_TRACE,
("%s!SetDevicePowerState Exit\n",DRIVER_NAME));
return fRes;
}
/*****************************************************************************
Routine Description:
This routine generates an internal IRP from this driver to the PDO
to obtain information on the Physical Device Object's capabilities.
We are most interested in learning which system power states
are to be mapped to which device power states for honoring IRP_MJ_SET_POWER Irps.
This is a blocking call which waits for the IRP completion routine
to set an event on finishing.
Arguments:
DeviceObject - Physical DeviceObject for this USB controller.
Return Value:
NTSTATUS value from the IoCallDriver() call.
*****************************************************************************/
NTSTATUS CMUSB_QueryCapabilities(
IN PDEVICE_OBJECT PdoDeviceObject,
IN PDEVICE_CAPABILITIES DeviceCapabilities
)
{
PIO_STACK_LOCATION nextStack;
PIRP irp;
NTSTATUS NTStatus;
KEVENT event;
// This is a DDK-defined DBG-only macro that ASSERTS we are not running pageable code
// at higher than APC_LEVEL.
PAGED_CODE();
// Build an IRP for us to generate an internal query request to the PDO
irp = IoAllocateIrp(PdoDeviceObject->StackSize, FALSE);
if (irp == NULL)
{
return STATUS_INSUFFICIENT_RESOURCES;
}
//
// Preinit the device capability structures appropriately.
//
RtlZeroMemory( DeviceCapabilities, sizeof(DEVICE_CAPABILITIES) );
DeviceCapabilities->Size = sizeof(DEVICE_CAPABILITIES);
DeviceCapabilities->Version = 1;
DeviceCapabilities->Address = -1;
DeviceCapabilities->UINumber = -1;
// IoGetNextIrpStackLocation gives a higher level driver access to the next-lower
// driver's I/O stack location in an IRP so the caller can set it up for the lower driver.
nextStack = IoGetNextIrpStackLocation(irp);
CMUSB_ASSERT(nextStack != NULL);
nextStack->MajorFunction= IRP_MJ_PNP;
nextStack->MinorFunction= IRP_MN_QUERY_CAPABILITIES;
// init an event to tell us when the completion routine's been called
KeInitializeEvent(&event, NotificationEvent, FALSE);
// Set a completion routine so it can signal our event when
// the next lower driver is done with the Irp
IoSetCompletionRoutine(irp,
CMUSB_IrpCompletionRoutine,
&event, // pass the event as Context to completion routine
TRUE, // invoke on success
TRUE, // invoke on error
TRUE); // invoke on cancellation of the Irp
// set our pointer to the DEVICE_CAPABILITIES struct
nextStack->Parameters.DeviceCapabilities.Capabilities = DeviceCapabilities;
// preset the irp to report not supported
irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
NTStatus = IoCallDriver(PdoDeviceObject,
irp);
if (NTStatus == STATUS_PENDING)
{
// wait for irp to complete
KeWaitForSingleObject(&event,
Suspended,
KernelMode,
FALSE,
NULL);
NTStatus = irp->IoStatus.Status;
}
IoFreeIrp(irp);
return NTStatus;
}
/*****************************************************************************
Routine Description:
Installable driver initialization entry point.
This entry point is called directly by the I/O system.
Arguments:
Return Value:
*****************************************************************************/
NTSTATUS DriverEntry(
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath
)
{
NTSTATUS NTStatus = STATUS_SUCCESS;
PDEVICE_OBJECT deviceObject = NULL;
BOOLEAN fRes;
ULONG ulIndex;
//#if DBG
// SmartcardSetDebugLevel(DEBUG_ALL);
//#endif
SmartcardDebug(DEBUG_TRACE,
("%s!DriverEntry: Enter - %s %s\n",DRIVER_NAME,__DATE__,__TIME__));
//
// Create dispatch points for create, close, unload
DriverObject->MajorFunction[IRP_MJ_CREATE] = CMUSB_CreateClose;
DriverObject->MajorFunction[IRP_MJ_CLOSE] = CMUSB_CreateClose;
DriverObject->MajorFunction[IRP_MJ_CLEANUP] = CMUSB_Cleanup;
DriverObject->DriverUnload = CMUSB_Unload;
// User mode DeviceIoControl() calls will be routed here
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = CMUSB_ProcessIOCTL;
// routines for handling system PNP and power management requests
DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = CMUSB_ProcessSysControlIrp;
DriverObject->MajorFunction[IRP_MJ_PNP] = CMUSB_ProcessPnPIrp;
DriverObject->MajorFunction[IRP_MJ_POWER] = CMUSB_ProcessPowerIrp;
// The Functional Device Object (FDO) will not be created for PNP devices until
// this routine is called upon device plug-in.
DriverObject->DriverExtension->AddDevice = CMUSB_PnPAddDevice;
for (ulIndex = 0;ulIndex < MAXIMUM_OEM_NAMES;ulIndex++)
{
OemName[ulIndex].Buffer = OemNameBuffer[ulIndex];
OemName[ulIndex].MaximumLength = sizeof(OemNameBuffer[ulIndex]);
}
SmartcardDebug(DEBUG_TRACE,
("%s!DriverEntry: Exit\n",DRIVER_NAME));
return NTStatus;
}
/*****************************************************************************
Routine Description:
Main dispatch table routine for IRP_MJ_SYSTEM_CONTROL
We basically just pass these down to the PDO
Arguments:
DeviceObject - pointer to FDO device object
Irp - pointer to an I/O Request Packet
Return Value:
Status returned from lower driver
*****************************************************************************/
NTSTATUS CMUSB_ProcessSysControlIrp(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
{
PIO_STACK_LOCATION irpStack;
PDEVICE_EXTENSION DeviceExtension;
NTSTATUS NTStatus = STATUS_SUCCESS;
NTSTATUS waitStatus;
PDEVICE_OBJECT stackDeviceObject;
//
// Get a pointer to the current location in the Irp. This is where
// the function codes and parameters are located.
//
irpStack = IoGetCurrentIrpStackLocation (Irp);
//
// Get a pointer to the device extension
//
DeviceExtension = DeviceObject->DeviceExtension;
stackDeviceObject = DeviceExtension->TopOfStackDeviceObject;
CMUSB_IncrementIoCount(DeviceObject);
CMUSB_ASSERT( IRP_MJ_SYSTEM_CONTROL == irpStack->MajorFunction );
IoCopyCurrentIrpStackLocationToNext(Irp);
NTStatus = IoCallDriver(stackDeviceObject,
Irp);
CMUSB_DecrementIoCount(DeviceObject);
return NTStatus;
}
/*****************************************************************************
Routine Description:
Free all the allocated resources, etc.
Arguments:
DriverObject - pointer to a driver object
Return Value:
*****************************************************************************/
VOID CMUSB_Unload(
IN PDRIVER_OBJECT DriverObject
)
{
SmartcardDebug(DEBUG_TRACE,
("%s!Unload enter\n",DRIVER_NAME));
//
// Free any global resources allocated
// in DriverEntry.
// We have few or none because for a PNP device, almost all
// allocation is done in PnpAddDevice() and all freeing
// while handling IRP_MN_REMOVE_DEVICE:
//
SmartcardDebug(DEBUG_TRACE,
("%s!Unload exit\n",DRIVER_NAME));
}
/*****************************************************************************
Routine Description:
Trys to read the reader name from the registry
Arguments:
DriverObject context of call
SmartcardExtension ptr to smartcard extension
Return Value:
none
******************************************************************************/
NTSTATUS CMUSB_SetVendorAndIfdName(
IN PDEVICE_OBJECT PhysicalDeviceObject,
IN PSMARTCARD_EXTENSION SmartcardExtension
)
{
RTL_QUERY_REGISTRY_TABLE parameters[3];
UNICODE_STRING vendorNameU;
ANSI_STRING vendorNameA;
UNICODE_STRING ifdTypeU;
ANSI_STRING ifdTypeA;
HANDLE regKey = NULL;
ULONG ulIndex;
ULONG ulInstance;
CHAR strBuffer[64];
USHORT usStrLength;
RtlZeroMemory (parameters, sizeof(parameters));
RtlZeroMemory (&vendorNameU, sizeof(vendorNameU));
RtlZeroMemory (&vendorNameA, sizeof(vendorNameA));
RtlZeroMemory (&ifdTypeU, sizeof(ifdTypeU));
RtlZeroMemory (&ifdTypeA, sizeof(ifdTypeA));
try
{
//
// 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,
&regKey) != STATUS_SUCCESS)
{
SmartcardDebug(DEBUG_ERROR,
("%s!SetVendorAndIfdName: IoOpenDeviceRegistryKey failed\n",DRIVER_NAME));
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)
{
SmartcardDebug(DEBUG_ERROR,
("%s!SetVendorAndIfdName: RtlQueryRegistryValues failed\n",DRIVER_NAME));
leave;
}
if (RtlUnicodeStringToAnsiString(&vendorNameA,&vendorNameU,TRUE) != STATUS_SUCCESS)
{
SmartcardDebug(DEBUG_ERROR,
("%s!SetVendorAndIfdName: RtlUnicodeStringToAnsiString failed\n",DRIVER_NAME));
leave;
}
if (RtlUnicodeStringToAnsiString(&ifdTypeA,&ifdTypeU,TRUE) != STATUS_SUCCESS)
{
SmartcardDebug(DEBUG_ERROR,
("%s!SetVendorAndIfdName: RtlUnicodeStringToAnsiString failed\n",DRIVER_NAME));
leave;
}
if (vendorNameA.Length == 0 ||
vendorNameA.Length > MAXIMUM_ATTR_STRING_LENGTH ||
ifdTypeA.Length == 0 ||
ifdTypeA.Length > MAXIMUM_ATTR_STRING_LENGTH)
{
SmartcardDebug(DEBUG_ERROR,
("%s!SetVendorAndIfdName: vendor name or ifdtype not found or to long\n",DRIVER_NAME));
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;
SmartcardDebug(DEBUG_DRIVER,
("%s!SetVendorAndIfdName: overwritting vendor name and ifdtype\n",DRIVER_NAME));
}
finally
{
if (vendorNameU.Buffer != NULL)
{
RtlFreeUnicodeString(&vendorNameU);
}
if (vendorNameA.Buffer != NULL)
{
RtlFreeAnsiString(&vendorNameA);
}
if (ifdTypeU.Buffer != NULL)
{
RtlFreeUnicodeString(&ifdTypeU);
}
if (ifdTypeA.Buffer != NULL)
{
RtlFreeAnsiString(&ifdTypeA);
}
if (regKey != NULL)
{
ZwClose (regKey);
}
}
// correct the unit number
ifdTypeA.Buffer=strBuffer;
ifdTypeA.MaximumLength=sizeof(strBuffer);
usStrLength = (SmartcardExtension->VendorAttr.IfdType.Length < ifdTypeA.MaximumLength) ? SmartcardExtension->VendorAttr.IfdType.Length : ifdTypeA.MaximumLength;
RtlCopyMemory(ifdTypeA.Buffer,
SmartcardExtension->VendorAttr.IfdType.Buffer,
usStrLength);
ifdTypeA.Length = usStrLength;
ulIndex=0;
while (ulIndex < MAXIMUM_OEM_NAMES &&
OemName[ulIndex].Length > 0 &&
RtlCompareMemory (ifdTypeA.Buffer, OemName[ulIndex].Buffer, OemName[ulIndex].Length) != OemName[ulIndex].Length)
{
ulIndex++;
}
if (ulIndex == MAXIMUM_OEM_NAMES)
{
// maximum number of OEM names reached
return STATUS_INSUFFICIENT_RESOURCES;
}
if (OemName[ulIndex].Length == 0)
{
// new OEM reader name
usStrLength = (ifdTypeA.Length < OemName[ulIndex].MaximumLength) ? ifdTypeA.Length : OemName[ulIndex].MaximumLength;
RtlCopyMemory(OemName[ulIndex].Buffer,
ifdTypeA.Buffer,
usStrLength);
OemName[ulIndex].Length = usStrLength;
}
for (ulInstance = 0;ulInstance < MAXIMUM_USB_READERS;ulInstance++)
{
if (OemDeviceSlot[ulIndex][ulInstance] == FALSE)
{
OemDeviceSlot[ulIndex][ulInstance] = TRUE;
break;
}
}
if (ulInstance == MAXIMUM_USB_READERS)
{
return STATUS_INSUFFICIENT_RESOURCES;
}
SmartcardExtension->VendorAttr.UnitNo = ulInstance;
SmartcardExtension->ReaderExtension->ulOemDeviceInstance = ulInstance;
SmartcardExtension->ReaderExtension->ulOemNameIndex = ulIndex;
return STATUS_SUCCESS;
}
/*****************************************************************************
Routine Description:
Creates a Functional DeviceObject
Arguments:
DriverObject - pointer to the driver object for device
DeviceObject - pointer to DeviceObject pointer to return
created device object.
Instance - instance of the device create.
Return Value:
STATUS_SUCCESS if successful,
STATUS_UNSUCCESSFUL otherwise
*****************************************************************************/
NTSTATUS CMUSB_CreateDeviceObject(
IN PDRIVER_OBJECT DriverObject,
IN PDEVICE_OBJECT PhysicalDeviceObject,
IN PDEVICE_OBJECT *DeviceObject
)
{
UNICODE_STRING deviceNameUnicodeString;
UNICODE_STRING Tmp;
NTSTATUS NTStatus = STATUS_SUCCESS;
ULONG deviceInstance;
PDEVICE_EXTENSION DeviceExtension;
PREADER_EXTENSION readerExtension;
PSMARTCARD_EXTENSION SmartcardExtension;
WCHAR Buffer[64];
SmartcardDebug(DEBUG_TRACE,
("%s!CreateDeviceObject: Enter\n",DRIVER_NAME));
for ( deviceInstance = 0;deviceInstance < MAXIMUM_USB_READERS;deviceInstance++ )
{
if (DeviceSlot[deviceInstance] == FALSE)
{
DeviceSlot[deviceInstance] = TRUE;
break;
}
}
if (deviceInstance == MAXIMUM_USB_READERS)
{
return STATUS_INSUFFICIENT_RESOURCES;
}
//
// construct the device name
//
deviceNameUnicodeString.Buffer = Buffer;
deviceNameUnicodeString.MaximumLength = sizeof(Buffer);
deviceNameUnicodeString.Length = 0;
RtlInitUnicodeString(&Tmp,CARDMAN_USB_DEVICE_NAME);
RtlCopyUnicodeString(&deviceNameUnicodeString,&Tmp);
Tmp.Buffer = deviceNameUnicodeString.Buffer + deviceNameUnicodeString.Length / sizeof(WCHAR);
Tmp.MaximumLength = 2 * sizeof(WCHAR);
Tmp.Length = 0;
RtlIntegerToUnicodeString(deviceInstance,10,&Tmp);
deviceNameUnicodeString.Length = (USHORT)( deviceNameUnicodeString.Length+Tmp.Length);
// Create the device object
NTStatus = IoCreateDevice(DriverObject,
sizeof(DEVICE_EXTENSION),
&deviceNameUnicodeString,
FILE_DEVICE_SMARTCARD,
0,
TRUE,
DeviceObject);
if (NTStatus != STATUS_SUCCESS)
{
return NTStatus;
}
// ----------------------------------------------
// initialize device extension
// ----------------------------------------------
DeviceExtension = (*DeviceObject)->DeviceExtension;
DeviceExtension->DeviceInstance = deviceInstance;
SmartcardExtension = &DeviceExtension->SmartcardExtension;
// Used for reading from pipe 1
KeInitializeEvent(&DeviceExtension->ReadP1Completed,
NotificationEvent,
FALSE);
// Used to keep track of open close calls
KeInitializeEvent(&DeviceExtension->RemoveEvent,
NotificationEvent,
TRUE);
KeInitializeSpinLock(&DeviceExtension->SpinLock);
// this event is triggered when self-requested power irps complete
KeInitializeEvent(&DeviceExtension->SelfRequestedPowerIrpEvent, NotificationEvent, FALSE);
// this event is triggered when there is no pending io (pending io count == 1 )
KeInitializeEvent(&DeviceExtension->NoPendingIoEvent, NotificationEvent, FALSE);
// Used for update thread notification after hibernation
KeInitializeEvent(&DeviceExtension->CanRunUpdateThread,
NotificationEvent,
TRUE);
// Blocks IOControls during hibernation
KeInitializeEvent(&DeviceExtension->ReaderEnabled,
NotificationEvent,
TRUE);
// ----------------------------------------------
// create reader extension
// ----------------------------------------------
SmartcardExtension->ReaderExtension = ExAllocatePool(NonPagedPool,
sizeof(READER_EXTENSION));
if (SmartcardExtension->ReaderExtension == NULL)
{
return STATUS_INSUFFICIENT_RESOURCES;
}
readerExtension = SmartcardExtension->ReaderExtension;
RtlZeroMemory(readerExtension, sizeof(READER_EXTENSION));
// ----------------------------------------------
// initialize timers
// ----------------------------------------------
KeInitializeTimer(&SmartcardExtension->ReaderExtension->WaitTimer);
KeInitializeTimer(&SmartcardExtension->ReaderExtension->P1Timer);
// ----------------------------------------------
// initialize mutex
// ----------------------------------------------
KeInitializeMutex(&SmartcardExtension->ReaderExtension->CardManIOMutex,0L);
// ----------------------------------------------
// create smartcard extension
// ----------------------------------------------
// write the version of the lib we use to the smartcard extension
SmartcardExtension->Version = SMCLIB_VERSION;
SmartcardExtension->SmartcardRequest.BufferSize = CMUSB_BUFFER_SIZE;
SmartcardExtension->SmartcardReply.BufferSize = CMUSB_BUFFER_SIZE;
//
// Now let the lib allocate the buffer for data transmission
// We can either tell the lib how big the buffer should be
// by assigning a value to BufferSize or let the lib
// allocate the default size
//
NTStatus = SmartcardInitialize(SmartcardExtension);
if (NTStatus != STATUS_SUCCESS)
{
// free reader extension
ExFreePool(DeviceExtension->SmartcardExtension.ReaderExtension);
SmartcardExtension->ReaderExtension = NULL;
return NTStatus;
}
// ----------------------------------------------
// initialize smartcard extension
// ----------------------------------------------
// Save deviceObject
SmartcardExtension->OsData->DeviceObject = *DeviceObject;
// Set up call back functions
SmartcardExtension->ReaderFunction[RDF_TRANSMIT] = CMUSB_Transmit;
SmartcardExtension->ReaderFunction[RDF_SET_PROTOCOL] = CMUSB_SetProtocol;
SmartcardExtension->ReaderFunction[RDF_CARD_POWER] = CMUSB_CardPower;
SmartcardExtension->ReaderFunction[RDF_CARD_TRACKING] = CMUSB_CardTracking;
SmartcardExtension->ReaderFunction[RDF_IOCTL_VENDOR] = CMUSB_IoCtlVendor;
SmartcardExtension->ReaderExtension->ulDeviceInstance = deviceInstance;
CMUSB_InitializeSmartcardExtension(SmartcardExtension);
// try to overwrite with registry values
NTStatus = CMUSB_SetVendorAndIfdName(PhysicalDeviceObject, SmartcardExtension);
if (NTStatus != STATUS_SUCCESS)
{
// free reader extension
ExFreePool(DeviceExtension->SmartcardExtension.ReaderExtension);
SmartcardExtension->ReaderExtension = NULL;
return NTStatus;
}
// W2000 is till now the only OS which supports WDM version 1.10
// So check this to determine if we have an Plug&Play able resource manager
DeviceExtension->fPnPResourceManager = IoIsWdmVersionAvailable (1,10);
SmartcardDebug(DEBUG_DRIVER,
("%s!CreateDeviceObject: fPnPManager=%ld\n",DRIVER_NAME,DeviceExtension->fPnPResourceManager));
if (DeviceExtension->fPnPResourceManager == TRUE)
{
if (DeviceExtension->PnPDeviceName.Buffer == NULL)
{
// register our new device
NTStatus = IoRegisterDeviceInterface(PhysicalDeviceObject,
&SmartCardReaderGuid,
NULL,
&DeviceExtension->PnPDeviceName);
SmartcardDebug(DEBUG_DRIVER,
("%s!CreateDeviceObject: PnPDeviceName.Buffer = %lx\n",DRIVER_NAME,
DeviceExtension->PnPDeviceName.Buffer));
SmartcardDebug(DEBUG_DRIVER,
("%s!CreateDeviceObject: PnPDeviceName.BufferLength = %lx\n",DRIVER_NAME,
DeviceExtension->PnPDeviceName.Length));
SmartcardDebug(DEBUG_DRIVER,
("%s!CreateDeviceObject: IoRegisterDeviceInterface returned=%lx\n",DRIVER_NAME,NTStatus));
}
else
{
SmartcardDebug(DEBUG_DRIVER,
("%s!CreateDeviceObject: Interface already exists\n",DRIVER_NAME));
}
}
else
{
// ----------------------------------------------
// create symbolic link
// ----------------------------------------------
NTStatus = SmartcardCreateLink(&DeviceExtension->DosDeviceName,&deviceNameUnicodeString);
SmartcardDebug(DEBUG_DRIVER,
("%s!CreateDeviceObject: SmartcardCreateLink returned=%lx\n",DRIVER_NAME,NTStatus));
}
if (NTStatus != STATUS_SUCCESS)
{
ExFreePool(DeviceExtension->SmartcardExtension.ReaderExtension);
SmartcardExtension->ReaderExtension = NULL;
SmartcardExit(&DeviceExtension->SmartcardExtension);
IoDeleteDevice(*DeviceObject);
}
SmartcardDebug(DEBUG_TRACE,
("%s!CreateDeviceObject: Exit %lx\n",DRIVER_NAME,NTStatus));
return NTStatus;
}
/*****************************************************************************
Routine Description:
Passes a URB to the USBD class driver
The client device driver passes USB request block (URB) structures
to the class driver as a parameter in an IRP with Irp->MajorFunction
set to IRP_MJ_INTERNAL_DEVICE_CONTROL and the next IRP stack location
Parameters.DeviceIoControl.IoControlCode field set to
IOCTL_INTERNAL_USB_SUBMIT_URB.
Arguments:
DeviceObject - pointer to the physical device object (PDO)
Urb - pointer to an already-formatted Urb request block
Return Value:
STATUS_SUCCESS if successful,
STATUS_UNSUCCESSFUL otherwise
*****************************************************************************/
NTSTATUS
CMUSB_CallUSBD(
IN PDEVICE_OBJECT DeviceObject,
IN PURB Urb
)
{
NTSTATUS NTStatus = STATUS_SUCCESS;
NTSTATUS DebugStatus;
PDEVICE_EXTENSION DeviceExtension;
PIRP irp;
KEVENT event;
IO_STATUS_BLOCK ioStatus;
PIO_STACK_LOCATION nextStack;
DeviceExtension = DeviceObject->DeviceExtension;
//
// issue a synchronous request
//
KeInitializeEvent(&event, NotificationEvent, FALSE);
irp = IoBuildDeviceIoControlRequest(IOCTL_INTERNAL_USB_SUBMIT_URB,
DeviceExtension->TopOfStackDeviceObject, //Points to the next-lower driver's device object
NULL, // optional input bufer; none needed here
0, // input buffer len if used
NULL, // optional output bufer; none needed here
0, // output buffer len if used
TRUE, // If InternalDeviceControl is TRUE the target driver's Dispatch
// outine for IRP_MJ_INTERNAL_DEVICE_CONTROL or IRP_MJ_SCSI
// is called; otherwise, the Dispatch routine for
// IRP_MJ_DEVICE_CONTROL is called.
&event, // event to be signalled on completion
&ioStatus); // Specifies an I/O NTStatus block to be set when the request is completed the lower driver.
if (irp == NULL)
{
NTStatus = STATUS_INSUFFICIENT_RESOURCES;
goto ExitCallUSBD;
}
//
// Call the class driver to perform the operation. If the returned NTStatus
// is PENDING, wait for the request to complete.
//
nextStack = IoGetNextIrpStackLocation(irp);
CMUSB_ASSERT(nextStack != NULL);
//
// pass the URB to the USB driver stack
//
nextStack->Parameters.Others.Argument1 = Urb;
NTStatus = IoCallDriver(DeviceExtension->TopOfStackDeviceObject, irp);
if (NTStatus == STATUS_PENDING)
{
DebugStatus = KeWaitForSingleObject(&event,
Suspended,
KernelMode,
FALSE,
NULL);
}
else
{
ioStatus.Status = NTStatus;
}
/*
SmartcardDebug( DEBUG_TRACE,("CMUSB_CallUSBD() URB NTStatus = %x NTStatus = %x irp NTStatus %x\n",
Urb->UrbHeader.Status, NTStatus, ioStatus.Status));
*/
//
// USBD maps the error code for us
//
NTStatus = ioStatus.Status;
ExitCallUSBD:
return NTStatus;
}
/*****************************************************************************
Routine Description:
Initializes a given instance of the device on the USB and
selects and saves the configuration.
Arguments:
DeviceObject - pointer to the physical device object for this instance of the 82930
device.
Return Value:
NT NTStatus code
*****************************************************************************/
NTSTATUS
CMUSB_ConfigureDevice(
IN PDEVICE_OBJECT DeviceObject
)
{
PDEVICE_EXTENSION DeviceExtension;
NTSTATUS NTStatus;
PURB urb;
ULONG siz;
DeviceExtension = DeviceObject->DeviceExtension;
CMUSB_ASSERT( DeviceExtension->UsbConfigurationDescriptor == NULL );
urb = ExAllocatePool(NonPagedPool,
sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST));
if (urb == NULL)
return STATUS_INSUFFICIENT_RESOURCES;
// When USB_CONFIGURATION_DESCRIPTOR_TYPE is specified for DescriptorType
// in a call to UsbBuildGetDescriptorRequest(),
// all interface, endpoint, class-specific, and vendor-specific descriptors
// for the configuration also are retrieved.
// The caller must allocate a buffer large enough to hold all of this
// information or the data is truncated without error.
// Therefore the 'siz' set below is just a 'good guess', and we may have to retry
siz = sizeof(USB_CONFIGURATION_DESCRIPTOR) + 512;
// We will break out of this 'retry loop' when UsbBuildGetDescriptorRequest()
// has a big enough DeviceExtension->UsbConfigurationDescriptor buffer not to truncate
while ( 1 )
{
DeviceExtension->UsbConfigurationDescriptor = ExAllocatePool(NonPagedPool, siz);
if (DeviceExtension->UsbConfigurationDescriptor == NULL)
{
ExFreePool(urb);
return STATUS_INSUFFICIENT_RESOURCES;
}
UsbBuildGetDescriptorRequest(urb,
(USHORT) sizeof (struct _URB_CONTROL_DESCRIPTOR_REQUEST),
USB_CONFIGURATION_DESCRIPTOR_TYPE,
0,
0,
DeviceExtension->UsbConfigurationDescriptor,
NULL,
siz,
NULL);
NTStatus = CMUSB_CallUSBD(DeviceObject, urb);
//
// if we got some data see if it was enough.
// NOTE: we may get an error in URB because of buffer overrun
if (urb->UrbControlDescriptorRequest.TransferBufferLength>0 &&
DeviceExtension->UsbConfigurationDescriptor->wTotalLength > siz)
{
siz = DeviceExtension->UsbConfigurationDescriptor->wTotalLength;
ExFreePool(DeviceExtension->UsbConfigurationDescriptor);
DeviceExtension->UsbConfigurationDescriptor = NULL;
}
else
{
break; // we got it on the first try
}
} // end, while (retry loop )
ExFreePool(urb);
CMUSB_ASSERT( DeviceExtension->UsbConfigurationDescriptor );
//
// We have the configuration descriptor for the configuration we want.
// Now we issue the select configuration command to get
// the pipes associated with this configuration.
//
NTStatus = CMUSB_SelectInterface(DeviceObject,
DeviceExtension->UsbConfigurationDescriptor);
return NTStatus;
}
/*****************************************************************************
Routine Description:
Initializes an CardMan USB
This minidriver only supports one interface with one endpoint
Arguments:
DeviceObject - pointer to the device object for this instance of the
CardMan USB device
ConfigurationDescriptor - pointer to the USB configuration
descriptor containing the interface and endpoint
descriptors.
Return Value:
NT NTStatus code
*****************************************************************************/
NTSTATUS
CMUSB_SelectInterface(
IN PDEVICE_OBJECT DeviceObject,
IN PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor
)
{
PDEVICE_EXTENSION DeviceExtension;
NTSTATUS NTStatus;
PURB urb = NULL;
ULONG i;
PUSB_INTERFACE_DESCRIPTOR interfaceDescriptor = NULL;
PUSBD_INTERFACE_INFORMATION Interface = NULL;
USHORT siz;
DeviceExtension = DeviceObject->DeviceExtension;
//
// CMUSB driver only supports one interface, we must parse
// the configuration descriptor for the interface
// and remember the pipes.
//
urb = USBD_CreateConfigurationRequest(ConfigurationDescriptor, &siz);
if (urb != NULL)
{
//
// USBD_ParseConfigurationDescriptorEx searches a given configuration
// descriptor and returns a pointer to an interface that matches the
// given search criteria. We only support one interface on this device
//
interfaceDescriptor =
USBD_ParseConfigurationDescriptorEx(ConfigurationDescriptor,
ConfigurationDescriptor, //search from start of config descriptro
-1, // interface number not a criteria; we only support one interface
-1, // not interested in alternate setting here either
-1, // interface class not a criteria
-1, // interface subclass not a criteria
-1 // interface protocol not a criteria
);
if (interfaceDescriptor == NULL)
{
ExFreePool(urb);
return STATUS_INSUFFICIENT_RESOURCES;
}
Interface = &urb->UrbSelectConfiguration.Interface;
for (i=0; i< Interface->NumberOfPipes; i++)
{
//
// perform any pipe initialization here
//
Interface->Pipes[i].MaximumTransferSize = 1000;
Interface->Pipes[i].PipeFlags = 0;
}
UsbBuildSelectConfigurationRequest(urb,
(USHORT) siz,
ConfigurationDescriptor);
NTStatus = CMUSB_CallUSBD(DeviceObject, urb);
DeviceExtension->UsbConfigurationHandle =
urb->UrbSelectConfiguration.ConfigurationHandle;
}
else
{
NTStatus = STATUS_INSUFFICIENT_RESOURCES;
}
if (NT_SUCCESS(NTStatus))
{
//
// Save the configuration handle for this device
//
DeviceExtension->UsbConfigurationHandle =
urb->UrbSelectConfiguration.ConfigurationHandle;
DeviceExtension->UsbInterface = ExAllocatePool(NonPagedPool,
Interface->Length);
if (DeviceExtension->UsbInterface != NULL)
{
ULONG j;
//
// save a copy of the interface information returned
//
RtlCopyMemory(DeviceExtension->UsbInterface, Interface, Interface->Length);
//
// Dump the interface to the debugger
//
SmartcardDebug( DEBUG_DRIVER,("%s!SelectInterface: ---------\n",
DRIVER_NAME));
SmartcardDebug( DEBUG_DRIVER,("%s!SelectInterface: NumberOfPipes 0x%x\n",
DRIVER_NAME,
DeviceExtension->UsbInterface->NumberOfPipes));
SmartcardDebug( DEBUG_DRIVER,("%s!SelectInterface: Length 0x%x\n",
DRIVER_NAME,
DeviceExtension->UsbInterface->Length));
SmartcardDebug( DEBUG_DRIVER,("%s!SelectInterface: Alt Setting 0x%x\n",
DRIVER_NAME,
DeviceExtension->UsbInterface->AlternateSetting));
SmartcardDebug( DEBUG_DRIVER,("%s!SelectInterface: Interface Number 0x%x\n",
DRIVER_NAME,
DeviceExtension->UsbInterface->InterfaceNumber));
SmartcardDebug( DEBUG_DRIVER,("%s!SelectInterface: Class, subclass, protocol 0x%x 0x%x 0x%x\n",
DRIVER_NAME,
DeviceExtension->UsbInterface->Class,
DeviceExtension->UsbInterface->SubClass,
DeviceExtension->UsbInterface->Protocol));
// Dump the pipe info
for (j=0; j<Interface->NumberOfPipes; j++)
{
PUSBD_PIPE_INFORMATION pipeInformation;
pipeInformation = &DeviceExtension->UsbInterface->Pipes[j];
pipeInformation->MaximumTransferSize = 256;
pipeInformation->PipeFlags = TRUE;
SmartcardDebug( DEBUG_DRIVER,("%s!SelectInterface: ---------\n",
DRIVER_NAME));
SmartcardDebug( DEBUG_DRIVER,("%s!SelectInterface: PipeType 0x%x\n",
DRIVER_NAME,
pipeInformation->PipeType));
SmartcardDebug( DEBUG_DRIVER,("%s!SelectInterface: EndpointAddress 0x%x\n",
DRIVER_NAME,
pipeInformation->EndpointAddress));
SmartcardDebug( DEBUG_DRIVER,("%s!SelectInterface: MaxPacketSize 0x%x\n",
DRIVER_NAME,
pipeInformation->MaximumPacketSize));
SmartcardDebug( DEBUG_DRIVER,("%s!SelectInterface: Interval 0x%x\n",
DRIVER_NAME,
pipeInformation->Interval));
SmartcardDebug( DEBUG_DRIVER,("%s!SelectInterface: Handle 0x%x\n",
DRIVER_NAME,
pipeInformation->PipeHandle));
SmartcardDebug( DEBUG_DRIVER,("%s!SelectInterface: MaximumTransferSize 0x%x\n",
DRIVER_NAME,
pipeInformation->MaximumTransferSize));
}
SmartcardDebug( DEBUG_DRIVER,("%s!SelectInterface: ---------\n",
DRIVER_NAME));
}
}
if (urb != NULL)
{
ExFreePool(urb);
}
return NTStatus;
}
/*****************************************************************************
Routine Description:
Reset a given USB pipe.
NOTES:
This will reset the host to Data0 and should also reset the device to Data0
Arguments:
Ptrs to our FDO and a USBD_PIPE_INFORMATION struct
Return Value:
NT NTStatus code
*****************************************************************************/
NTSTATUS
CMUSB_ResetPipe(
IN PDEVICE_OBJECT DeviceObject,
IN PUSBD_PIPE_INFORMATION PipeInfo
)
{
NTSTATUS NTStatus;
PURB urb;
PDEVICE_EXTENSION DeviceExtension;
DeviceExtension = DeviceObject->DeviceExtension;
SmartcardDebug(
DEBUG_TRACE,
( "%s!ResetPipe : Enter\n",
DRIVER_NAME)
);
urb = ExAllocatePool(NonPagedPool,
sizeof(struct _URB_PIPE_REQUEST));
if (urb != NULL)
{
urb->UrbHeader.Length = (USHORT) sizeof (struct _URB_PIPE_REQUEST);
urb->UrbHeader.Function = URB_FUNCTION_RESET_PIPE;
urb->UrbPipeRequest.PipeHandle =
PipeInfo->PipeHandle;
NTStatus = CMUSB_CallUSBD(DeviceObject, urb);
ExFreePool(urb);
}
else
{
NTStatus = STATUS_INSUFFICIENT_RESOURCES;
}
SmartcardDebug(
DEBUG_TRACE,
( "%s!ResetPipe : Exit %lx\n",
DRIVER_NAME,NTStatus)
);
return NTStatus;
}
/*****************************************************************************
Routine Description:
We keep a pending IO count ( extension->PendingIoCount ) in the device extension.
The first increment of this count is done on adding the device.
Subsequently, the count is incremented for each new IRP received and
decremented when each IRP is completed or passed on.
Transition to 'one' therefore indicates no IO is pending and signals
DeviceExtension->NoPendingIoEvent. This is needed for processing
IRP_MN_QUERY_REMOVE_DEVICE
Transition to 'zero' signals an event ( DeviceExtension->RemoveEvent )
to enable device removal. This is used in processing for IRP_MN_REMOVE_DEVICE
Arguments:
DeviceObject -- ptr to our FDO
Return Value:
DeviceExtension->PendingIoCount
*****************************************************************************/
VOID
CMUSB_DecrementIoCount(
IN PDEVICE_OBJECT DeviceObject
)
{
LONG ioCount;
PDEVICE_EXTENSION DeviceExtension;
DeviceExtension = DeviceObject->DeviceExtension;
/*
SmartcardDebug( DEBUG_TRACE,
("%s!DecrementIoCount: Enter (PendingIoCount=%x)\n",
DRIVER_NAME,
DeviceExtension->PendingIoCount
)
);
*/
ioCount = InterlockedDecrement(&DeviceExtension->PendingIoCount);
if (ioCount==1)
{
// trigger no pending io
/*
SmartcardDebug( DEBUG_TRACE,
("%s!DecrementIoCount: setting NoPendingIoEvent\n",
DRIVER_NAME
)
);
*/
KeSetEvent(&DeviceExtension->NoPendingIoEvent,
1,
FALSE);
}
if (ioCount==0)
{
// trigger remove-device event
SmartcardDebug( DEBUG_DRIVER,
("%s!DecrementIoCount: setting RemoveEvent\n",
DRIVER_NAME
)
);
KeSetEvent(&DeviceExtension->RemoveEvent,
1,
FALSE);
}
/*
SmartcardDebug( DEBUG_TRACE,
("%s!DecrementIoCount: Exit (PendingIoCount=%x)\n",
DRIVER_NAME,
DeviceExtension->PendingIoCount
)
);
*/
return ;
}
/*****************************************************************************
Routine Description:
We keep a pending IO count ( extension->PendingIoCount ) in the device extension.
The first increment of this count is done on adding the device.
Subsequently, the count is incremented for each new IRP received and
decremented when each IRP is completed or passed on.
Arguments:
DeviceObject -- ptr to our FDO
Return Value:
None
*****************************************************************************/
VOID
CMUSB_IncrementIoCount(
IN PDEVICE_OBJECT DeviceObject
)
{
PDEVICE_EXTENSION DeviceExtension;
DeviceExtension = DeviceObject->DeviceExtension;
/*
SmartcardDebug( DEBUG_TRACE,
("%s!IncrementIoCount: Enter (PendingIoCount=%x)\n",
DRIVER_NAME,
DeviceExtension->PendingIoCount
)
);
*/
InterlockedIncrement(&DeviceExtension->PendingIoCount);
/*
SmartcardDebug( DEBUG_TRACE,
("%s!IncrementIoCount: Exit (PendingIoCount=%x)\n",
DRIVER_NAME,
DeviceExtension->PendingIoCount
)
);
*/
}
/*****************************************************************************
Routine Description:
Dispatch table handler for IRP_MJ_DEVICE_CONTROL;
Handle DeviceIoControl() calls from User mode
Arguments:
DeviceObject - pointer to the FDO for this instance of the 82930 device.
Return Value:
NT NTStatus code
*****************************************************************************/
NTSTATUS
CMUSB_ProcessIOCTL(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
{
NTSTATUS NTStatus;
PDEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
PIO_STACK_LOCATION irpSL;
irpSL = IoGetCurrentIrpStackLocation(Irp);
#if DBG
switch (irpSL->Parameters.DeviceIoControl.IoControlCode)
{
case IOCTL_SMARTCARD_EJECT:
SmartcardDebug(DEBUG_IOCTL,
("%s!ProcessIOCTL: %s\n", DRIVER_NAME, "IOCTL_SMARTCARD_EJECT"));
break;
case IOCTL_SMARTCARD_GET_ATTRIBUTE:
SmartcardDebug(DEBUG_IOCTL,
("%s!ProcessIOCTL: %s\n", DRIVER_NAME, "IOCTL_SMARTCARD_GET_ATTRIBUTE"));
break;
case IOCTL_SMARTCARD_GET_LAST_ERROR:
SmartcardDebug(DEBUG_IOCTL,
("%s!ProcessIOCTL: %s\n", DRIVER_NAME, "IOCTL_SMARTCARD_GET_LAST_ERROR"));
break;
case IOCTL_SMARTCARD_GET_STATE:
SmartcardDebug(DEBUG_IOCTL,
("%s!ProcessIOCTL: %s\n", DRIVER_NAME, "IOCTL_SMARTCARD_GET_STATE"));
break;
case IOCTL_SMARTCARD_IS_ABSENT:
SmartcardDebug(DEBUG_IOCTL,
("%s!ProcessIOCTL: %s\n", DRIVER_NAME, "IOCTL_SMARTCARD_IS_ABSENT"));
break;
case IOCTL_SMARTCARD_IS_PRESENT:
SmartcardDebug(DEBUG_IOCTL,
("%s!ProcessIOCTL: %s\n", DRIVER_NAME, "IOCTL_SMARTCARD_IS_PRESENT"));
break;
case IOCTL_SMARTCARD_POWER:
SmartcardDebug(DEBUG_IOCTL,
("%s!ProcessIOCTL: %s\n", DRIVER_NAME, "IOCTL_SMARTCARD_POWER"));
break;
case IOCTL_SMARTCARD_SET_ATTRIBUTE:
SmartcardDebug(DEBUG_IOCTL,
("%s!ProcessIOCTL: %s\n", DRIVER_NAME, "IOCTL_SMARTCARD_SET_ATTRIBUTE"));
break;
case IOCTL_SMARTCARD_SET_PROTOCOL:
SmartcardDebug(DEBUG_IOCTL,
("%s!ProcessIOCTL: %s\n", DRIVER_NAME, "IOCTL_SMARTCARD_SET_PROTOCOL"));
break;
case IOCTL_SMARTCARD_SWALLOW:
SmartcardDebug(DEBUG_IOCTL,
("%s!ProcessIOCTL: %s\n", DRIVER_NAME, "IOCTL_SMARTCARD_SWALLOW"));
break;
case IOCTL_SMARTCARD_TRANSMIT:
SmartcardDebug(DEBUG_IOCTL,
("%s!ProcessIOCTL: %s\n", DRIVER_NAME, "IOCTL_SMARTCARD_TRANSMIT"));
break;
default:
SmartcardDebug(DEBUG_IOCTL,
("%s!ProcessIOCTL: %s\n", DRIVER_NAME, "Vendor specific or unexpected IOCTL"));
break;
}
#endif
CMUSB_IncrementIoCount(DeviceObject);
NTStatus = KeWaitForSingleObject(&DeviceExtension->ReaderEnabled,
Executive,
KernelMode,
FALSE,
NULL);
ASSERT(NTStatus == STATUS_SUCCESS);
// Can't accept a new io request if:
// 1) device is removed,
// 2) has never been started,
// 3) is stopped,
// 4) has a remove request pending,
// 5) has a stop device pending
if (CMUSB_CanAcceptIoRequests( DeviceObject ) == FALSE )
{
NTStatus = STATUS_DELETE_PENDING;
Irp->IoStatus.Status = NTStatus;
Irp->IoStatus.Information = 0;
IoCompleteRequest( Irp, IO_NO_INCREMENT );
CMUSB_DecrementIoCount(DeviceObject);
return NTStatus;
}
NTStatus = SmartcardAcquireRemoveLock(&DeviceExtension->SmartcardExtension);
if (NTStatus != STATUS_SUCCESS)
{
// the device has been removed. Fail the call
Irp->IoStatus.Information = 0;
Irp->IoStatus.Status = STATUS_DELETE_PENDING;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_DELETE_PENDING;
}
KeWaitForSingleObject(&DeviceExtension->SmartcardExtension.ReaderExtension->CardManIOMutex,
Executive,
KernelMode,
FALSE,
NULL);
NTStatus = CMUSB_UpdateCurrentState (DeviceObject);
NTStatus = SmartcardDeviceControl(&DeviceExtension->SmartcardExtension,Irp);
KeReleaseMutex(&DeviceExtension->SmartcardExtension.ReaderExtension->CardManIOMutex,
FALSE);
SmartcardReleaseRemoveLock(&DeviceExtension->SmartcardExtension);
CMUSB_DecrementIoCount(DeviceObject);
return NTStatus;
}
/*****************************************************************************
Routine Description:
Arguments:
Return Value:
*****************************************************************************/
NTSTATUS
CMUSB_ReadP0(
IN PDEVICE_OBJECT DeviceObject
)
{
PURB urb = NULL;
NTSTATUS NTStatus;
ULONG i;
PDEVICE_EXTENSION DeviceExtension;
PSMARTCARD_EXTENSION SmartcardExtension;
DeviceExtension = DeviceObject->DeviceExtension;
SmartcardExtension = &DeviceExtension->SmartcardExtension;
/*
SmartcardDebug(DEBUG_TRACE,
("%s!ReadP0: Enter\n",
DRIVER_NAME)
);
*/
urb = ExAllocatePool(NonPagedPool, sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST));
if (urb != NULL)
{
RtlZeroMemory(urb, sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST));
UsbBuildVendorRequest(urb,
URB_FUNCTION_VENDOR_ENDPOINT,
(USHORT)sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST),
USBD_TRANSFER_DIRECTION_IN,
0,
0,
0,
0,
SmartcardExtension->SmartcardReply.Buffer,
NULL,
SmartcardExtension->SmartcardReply.BufferLength,
NULL);
NTStatus = CMUSB_CallUSBD(DeviceObject,urb);
if (NTStatus == STATUS_SUCCESS)
{
SmartcardExtension->SmartcardReply.BufferLength = urb->UrbControlVendorClassRequest.TransferBufferLength;
#if DBG
SmartcardDebug(DEBUG_PROTOCOL,
("%s!<==[P0] ",
DRIVER_NAME),
)
for (i=0;i<SmartcardExtension->SmartcardReply.BufferLength;i++)
{
SmartcardDebug(DEBUG_PROTOCOL,
("%x ",
SmartcardExtension->SmartcardReply.Buffer[i]
)
);
}
SmartcardDebug(DEBUG_PROTOCOL,("\n"));
#endif
}
ExFreePool(urb);
}
else
{
NTStatus = STATUS_INSUFFICIENT_RESOURCES;
}
/*
SmartcardDebug(DEBUG_TRACE,
("%s!ReadP0 Exit %lx\n",
DRIVER_NAME,
NTStatus)
);
*/
return NTStatus;
}
/*****************************************************************************
Routine Description:
Write data through the control pipe to the CardMan USB
Arguments:
Return Value:
NT NTStatus code
*****************************************************************************/
NTSTATUS
CMUSB_WriteP0(
IN PDEVICE_OBJECT DeviceObject,
IN UCHAR bRequest,
IN UCHAR bValueLo,
IN UCHAR bValueHi,
IN UCHAR bIndexLo,
IN UCHAR bIndexHi
)
{
PURB urb = NULL;
NTSTATUS NTStatus = STATUS_UNSUCCESSFUL;
USHORT usValue;
USHORT usIndex;
ULONG length;
PDEVICE_EXTENSION DeviceExtension;
PSMARTCARD_EXTENSION SmartcardExtension;
ULONG ulBytesToWrite;
ULONG i;
DeviceExtension = DeviceObject->DeviceExtension;
SmartcardExtension = &DeviceExtension->SmartcardExtension;
/*
SmartcardDebug(DEBUG_TRACE,
("%s!WriteP0: Enter\n",
DRIVER_NAME)
);
*/
#if DBG
SmartcardDebug(DEBUG_PROTOCOL,
("%s!==>[P0] ",DRIVER_NAME));
for (i=0;i< SmartcardExtension->SmartcardRequest.BufferLength;i++)
{
SmartcardDebug(DEBUG_PROTOCOL,
("%x ",SmartcardExtension->SmartcardRequest.Buffer[i]));
}
SmartcardDebug(DEBUG_PROTOCOL,
("(%ld)\n",SmartcardExtension->SmartcardRequest.BufferLength));
#endif
/*
SmartcardDebug(DEBUG_TRACE,
("%s!ulBytesToWrite = %ld\n",
DRIVER_NAME,SmartcardExtension->SmartcardRequest.BufferLength)
);
*/
ulBytesToWrite = SmartcardExtension->SmartcardRequest.BufferLength;
urb = ExAllocatePool(NonPagedPool, sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST));
if (urb != NULL)
{
RtlZeroMemory(urb, sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST));
usValue = bValueHi * 256 + bValueLo;
usIndex = bIndexHi * 256 + bIndexLo;
if (ulBytesToWrite != 0)
{
UsbBuildVendorRequest (urb,
URB_FUNCTION_VENDOR_ENDPOINT,
(USHORT)sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST),
0,
0,
bRequest,
usValue,
usIndex,
SmartcardExtension->SmartcardRequest.Buffer,
NULL,
ulBytesToWrite,
NULL);
}
else
{
UsbBuildVendorRequest (urb,
URB_FUNCTION_VENDOR_ENDPOINT,
(USHORT)sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST),
0,
0,
bRequest,
usValue,
usIndex,
NULL,
NULL,
0L,
NULL);
}
NTStatus = CMUSB_CallUSBD(DeviceObject,urb);
ExFreePool(urb);
}
if (NTStatus != STATUS_SUCCESS)
{
SmartcardDebug(DEBUG_PROTOCOL,
("%s!WriteP0: Error on exit %lx\n",DRIVER_NAME,NTStatus));
}
return NTStatus;
}
/*****************************************************************************
/*++
Routine Description:
Called as part of sudden device removal handling.
Cancels any pending transfers for all open pipes.
If any pipes are still open, call USBD with URB_FUNCTION_ABORT_PIPE
Also marks the pipe 'closed' in our saved configuration info.
Arguments:
Ptrs to our FDO
Return Value:
NT NTStatus code
*****************************************************************************/
NTSTATUS
CMUSB_AbortPipes(
IN PDEVICE_OBJECT DeviceObject
)
{
NTSTATUS NTStatus = STATUS_SUCCESS;
PURB urb;
PDEVICE_EXTENSION DeviceExtension;
PUSBD_INTERFACE_INFORMATION interface;
PUSBD_PIPE_INFORMATION PipeInfo;
SmartcardDebug(DEBUG_TRACE,
( "%s!AbortPipes: Enter\n",DRIVER_NAME));
DeviceExtension = DeviceObject->DeviceExtension;
interface = DeviceExtension->UsbInterface;
PipeInfo = &interface->Pipes[0];
if (PipeInfo->PipeFlags == TRUE) // we set this if open, clear if closed
{
urb = ExAllocatePool(NonPagedPool,sizeof(struct _URB_PIPE_REQUEST));
if (urb != NULL)
{
urb->UrbHeader.Length = (USHORT) sizeof (struct _URB_PIPE_REQUEST);
urb->UrbHeader.Function = URB_FUNCTION_ABORT_PIPE;
urb->UrbPipeRequest.PipeHandle = PipeInfo->PipeHandle;
NTStatus = CMUSB_CallUSBD(DeviceObject, urb);
ExFreePool(urb);
}
else
{
NTStatus = STATUS_INSUFFICIENT_RESOURCES;
SmartcardDebug(DEBUG_ERROR,
("%s!AbortPipes: ExAllocatePool failed\n",DRIVER_NAME));
}
if (NTStatus == STATUS_SUCCESS)
{
PipeInfo->PipeFlags = FALSE; // mark the pipe 'closed'
}
} // end, if pipe open
SmartcardDebug(DEBUG_TRACE,
("%s!AbortPipes: Exit %lx\n",DRIVER_NAME,NTStatus));
return NTStatus;
}
/*****************************************************************************
Routine Description:
Check device extension NTStatus flags;
Can't accept a new io request if device:
1) is removed,
2) has never been started,
3) is stopped,
4) has a remove request pending, or
5) has a stop device pending
Arguments:
DeviceObject - pointer to the device object for this instance of the 82930
device.
Return Value:
return TRUE if can accept new io requests, else FALSE
*****************************************************************************/
BOOLEAN
CMUSB_CanAcceptIoRequests(
IN PDEVICE_OBJECT DeviceObject
)
{
PDEVICE_EXTENSION DeviceExtension;
BOOLEAN fCan = FALSE;
DeviceExtension = DeviceObject->DeviceExtension;
//flag set when processing IRP_MN_REMOVE_DEVICE
if ( DeviceExtension->DeviceRemoved == FALSE &&
// device must be started( enabled )
DeviceExtension->DeviceStarted == TRUE &&
// flag set when driver has answered success to IRP_MN_QUERY_REMOVE_DEVICE
DeviceExtension->RemoveDeviceRequested == FALSE&&
//flag set when processing IRP_MN_SURPRISE_REMOVAL
DeviceExtension->DeviceSurpriseRemoval == FALSE&&
// flag set when driver has answered success to IRP_MN_QUERY_STOP_DEVICE
DeviceExtension->StopDeviceRequested == FALSE)
{
fCan = TRUE;
}
#if DBG
if (fCan == FALSE)
SmartcardDebug(DEBUG_DRIVER,
("%s!CanAcceptIoRequests: return FALSE \n",DRIVER_NAME));
#endif
return fCan;
}
/*****************************************************************************
* History:
* $Log: scusbwdm.c $
* Revision 1.9 2001/01/17 12:36:06 WFrischauf
* No comment given
*
* Revision 1.8 2000/09/25 13:38:23 WFrischauf
* No comment given
*
* Revision 1.7 2000/08/24 09:04:39 TBruendl
* No comment given
*
* Revision 1.6 2000/08/16 08:25:23 TBruendl
* warning :uninitialized memory removed
*
* Revision 1.5 2000/07/24 11:35:01 WFrischauf
* No comment given
*
* Revision 1.1 2000/07/20 11:50:16 WFrischauf
* No comment given
*
*
******************************************************************************/