You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1482 lines
44 KiB
1482 lines
44 KiB
/*++
|
|
|
|
Copyright (c) 1996-2001 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
GENUSB.C
|
|
|
|
Abstract:
|
|
|
|
This source file contains the DriverEntry() and AddDevice() entry points
|
|
for the GENUSB driver and the dispatch routines which handle:
|
|
|
|
IRP_MJ_POWER
|
|
IRP_MJ_SYSTEM_CONTROL
|
|
IRP_MJ_PNP
|
|
|
|
Environment:
|
|
|
|
kernel mode
|
|
|
|
Revision History:
|
|
|
|
Sep 2001 : Copied from USBMASS
|
|
|
|
--*/
|
|
|
|
//*****************************************************************************
|
|
// I N C L U D E S
|
|
//*****************************************************************************
|
|
|
|
#include <initguid.h>
|
|
#include "genusb.h"
|
|
|
|
|
|
//*****************************************************************************
|
|
// L O C A L F U N C T I O N P R O T O T Y P E S
|
|
//*****************************************************************************
|
|
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text(PAGE, DriverEntry)
|
|
#pragma alloc_text(PAGE, GenUSB_Unload)
|
|
#pragma alloc_text(PAGE, GenUSB_AddDevice)
|
|
#pragma alloc_text(PAGE, GenUSB_QueryParams)
|
|
#pragma alloc_text(PAGE, GenUSB_Pnp)
|
|
#pragma alloc_text(PAGE, GenUSB_StartDevice)
|
|
#pragma alloc_text(PAGE, GenUSB_StopDevice)
|
|
#pragma alloc_text(PAGE, GenUSB_RemoveDevice)
|
|
#pragma alloc_text(PAGE, GenUSB_QueryStopRemoveDevice)
|
|
#pragma alloc_text(PAGE, GenUSB_CancelStopRemoveDevice)
|
|
#pragma alloc_text(PAGE, GenUSB_SetDeviceInterface)
|
|
#pragma alloc_text(PAGE, GenUSB_SyncPassDownIrp)
|
|
#pragma alloc_text(PAGE, GenUSB_SyncSendUsbRequest)
|
|
#pragma alloc_text(PAGE, GenUSB_SetDIRegValues)
|
|
#pragma alloc_text(PAGE, GenUSB_SystemControl)
|
|
#pragma alloc_text(PAGE, GenUSB_Power)
|
|
#pragma alloc_text(PAGE, GenUSB_SetPower)
|
|
#if 0
|
|
#pragma alloc_text(PAGE, GenUSB_AbortPipe)
|
|
#endif
|
|
#endif
|
|
|
|
|
|
|
|
//******************************************************************************
|
|
//
|
|
// DriverEntry()
|
|
//
|
|
//******************************************************************************
|
|
|
|
NTSTATUS
|
|
DriverEntry (
|
|
IN PDRIVER_OBJECT DriverObject,
|
|
IN PUNICODE_STRING RegistryPath
|
|
)
|
|
{
|
|
PAGED_CODE();
|
|
|
|
// Query the registry for global parameters
|
|
GenUSB_QueryGlobalParams();
|
|
|
|
DBGPRINT(2, ("enter: DriverEntry\n"));
|
|
|
|
DBGFBRK(DBGF_BRK_DRIVERENTRY);
|
|
|
|
//
|
|
// Initialize the Driver Object with the driver's entry points
|
|
//
|
|
|
|
//
|
|
// GENUSB.C
|
|
//
|
|
DriverObject->DriverUnload = GenUSB_Unload;
|
|
DriverObject->DriverExtension->AddDevice = GenUSB_AddDevice;
|
|
|
|
//
|
|
// OCRW.C
|
|
//
|
|
DriverObject->MajorFunction[IRP_MJ_CREATE] = GenUSB_Create;
|
|
DriverObject->MajorFunction[IRP_MJ_CLOSE] = GenUSB_Close;
|
|
DriverObject->MajorFunction[IRP_MJ_READ] = GenUSB_Read;
|
|
DriverObject->MajorFunction[IRP_MJ_WRITE] = GenUSB_Write;
|
|
|
|
//
|
|
// DEVIOCTL.C
|
|
//
|
|
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = GenUSB_DeviceControl;
|
|
|
|
//
|
|
// GENUSB.C
|
|
//
|
|
DriverObject->MajorFunction[IRP_MJ_PNP] = GenUSB_Pnp;
|
|
DriverObject->MajorFunction[IRP_MJ_POWER] = GenUSB_Power;
|
|
DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = GenUSB_SystemControl;
|
|
|
|
DBGPRINT(2, ("exit: DriverEntry\n"));
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
//******************************************************************************
|
|
//
|
|
// GenUSB_Unload()
|
|
//
|
|
//******************************************************************************
|
|
|
|
VOID
|
|
GenUSB_Unload (
|
|
IN PDRIVER_OBJECT DriverObject
|
|
)
|
|
{
|
|
DEVICE_EXTENSION deviceExtension;
|
|
|
|
PAGED_CODE();
|
|
|
|
DBGPRINT(2, ("enter: GenUSB_Unload\n"));
|
|
|
|
DBGFBRK(DBGF_BRK_UNLOAD);
|
|
|
|
DBGPRINT(2, ("exit: GenUSB_Unload\n"));
|
|
}
|
|
|
|
//******************************************************************************
|
|
//
|
|
// GenUSB_AddDevice()
|
|
//
|
|
//******************************************************************************
|
|
|
|
NTSTATUS
|
|
GenUSB_AddDevice (
|
|
IN PDRIVER_OBJECT DriverObject,
|
|
IN PDEVICE_OBJECT PhysicalDeviceObject
|
|
)
|
|
{
|
|
PDEVICE_OBJECT deviceObject;
|
|
PDEVICE_EXTENSION fdoDeviceExtension;
|
|
NTSTATUS ntStatus;
|
|
|
|
PAGED_CODE();
|
|
|
|
DBGPRINT(2, ("enter: GenUSB_AddDevice\n"));
|
|
|
|
DBGFBRK(DBGF_BRK_ADDDEVICE);
|
|
|
|
// Create the FDO
|
|
//
|
|
ntStatus = IoCreateDevice(DriverObject,
|
|
sizeof(DEVICE_EXTENSION),
|
|
NULL,
|
|
FILE_DEVICE_UNKNOWN,
|
|
0,
|
|
FALSE,
|
|
&deviceObject);
|
|
|
|
if (!NT_SUCCESS(ntStatus))
|
|
{
|
|
return ntStatus;
|
|
}
|
|
|
|
fdoDeviceExtension = deviceObject->DeviceExtension;
|
|
|
|
LOGENTRY(fdoDeviceExtension, 'ADDD', DriverObject, PhysicalDeviceObject, 0);
|
|
|
|
// Set all DeviceExtension pointers to NULL and all variable to zero
|
|
RtlZeroMemory(fdoDeviceExtension, sizeof(DEVICE_EXTENSION));
|
|
|
|
// Store a back point to the DeviceObject for this DeviceExtension
|
|
fdoDeviceExtension->Self = deviceObject;
|
|
|
|
// Remember our PDO
|
|
fdoDeviceExtension->PhysicalDeviceObject = PhysicalDeviceObject;
|
|
|
|
// Attach the FDO we created to the top of the PDO stack
|
|
fdoDeviceExtension->StackDeviceObject =
|
|
IoAttachDeviceToDeviceStack(deviceObject, PhysicalDeviceObject);
|
|
|
|
LOGINIT (fdoDeviceExtension);
|
|
|
|
IoInitializeRemoveLock (&fdoDeviceExtension->RemoveLock,
|
|
POOL_TAG,
|
|
0,
|
|
0);
|
|
|
|
// Set the initial system and device power states
|
|
fdoDeviceExtension->SystemPowerState = PowerSystemWorking;
|
|
fdoDeviceExtension->DevicePowerState = PowerDeviceD0;
|
|
|
|
// Initialize the spinlock which protects the PDO DeviceFlags
|
|
KeInitializeSpinLock(&fdoDeviceExtension->SpinLock);
|
|
ExInitializeFastMutex(&fdoDeviceExtension->ConfigMutex);
|
|
|
|
fdoDeviceExtension->OpenedCount = 0;
|
|
|
|
GenUSB_QueryParams(deviceObject);
|
|
|
|
fdoDeviceExtension->ReadInterface = -1;
|
|
fdoDeviceExtension->ReadPipe = -1;
|
|
fdoDeviceExtension->WriteInterface = -1;
|
|
fdoDeviceExtension->ReadPipe = -1;
|
|
|
|
IoInitializeTimer (deviceObject, GenUSB_Timer, NULL);
|
|
|
|
deviceObject->Flags |= DO_DIRECT_IO;
|
|
deviceObject->Flags |= DO_POWER_PAGABLE;
|
|
deviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
|
|
|
|
DBGPRINT(2, ("exit: GenUSB_AddDevice\n"));
|
|
|
|
LOGENTRY(fdoDeviceExtension,
|
|
'addd',
|
|
deviceObject,
|
|
fdoDeviceExtension,
|
|
fdoDeviceExtension->StackDeviceObject);
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
//******************************************************************************
|
|
//
|
|
// GenUSB_QueryParams()
|
|
//
|
|
// This is called at AddDevice() time when the FDO is being created to query
|
|
// device parameters from the registry.
|
|
//
|
|
//******************************************************************************
|
|
|
|
VOID
|
|
GenUSB_QueryParams (
|
|
IN PDEVICE_OBJECT DeviceObject
|
|
)
|
|
{
|
|
PDEVICE_EXTENSION deviceExtension;
|
|
RTL_QUERY_REGISTRY_TABLE paramTable[3];
|
|
HANDLE handle;
|
|
NTSTATUS status;
|
|
ULONG defaultReadPipe;
|
|
ULONG defaultWritePipe;
|
|
|
|
PAGED_CODE();
|
|
|
|
DBGPRINT(2, ("enter: GenUSB_QueryFdoParams\n"));
|
|
|
|
deviceExtension = DeviceObject->DeviceExtension;
|
|
|
|
// Set the default value in case the registry key does not exist.
|
|
defaultReadPipe = 0;
|
|
defaultWritePipe = 0;
|
|
|
|
status = IoOpenDeviceRegistryKey(
|
|
deviceExtension->PhysicalDeviceObject,
|
|
PLUGPLAY_REGKEY_DRIVER,
|
|
STANDARD_RIGHTS_ALL,
|
|
&handle);
|
|
|
|
if (NT_SUCCESS(status))
|
|
{
|
|
RtlZeroMemory (¶mTable[0], sizeof(paramTable));
|
|
|
|
paramTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
|
|
paramTable[0].Name = REGKEY_DEFAULT_READ_PIPE;
|
|
paramTable[0].EntryContext = &defaultReadPipe;
|
|
paramTable[0].DefaultType = REG_DWORD;
|
|
paramTable[0].DefaultData = &defaultReadPipe;
|
|
paramTable[0].DefaultLength = sizeof(ULONG);
|
|
|
|
paramTable[1].Flags = RTL_QUERY_REGISTRY_DIRECT;
|
|
paramTable[1].Name = REGKEY_DEFAULT_WRITE_PIPE;
|
|
paramTable[1].EntryContext = &defaultWritePipe;
|
|
paramTable[1].DefaultType = REG_DWORD;
|
|
paramTable[1].DefaultData = &defaultWritePipe;
|
|
paramTable[1].DefaultLength = sizeof(ULONG);
|
|
|
|
RtlQueryRegistryValues(RTL_REGISTRY_HANDLE,
|
|
(PCWSTR)handle,
|
|
¶mTable[0],
|
|
NULL, // Context
|
|
NULL); // Environment
|
|
|
|
ZwClose(handle);
|
|
}
|
|
|
|
|
|
// deviceExtension->DefaultReadPipe = defaultReadPipe;
|
|
// deviceExtension->DefaultWritePipe = defaultWritePipe;
|
|
|
|
DBGPRINT(2, ("DefaultReadPipe %08X\n", defaultReadPipe));
|
|
DBGPRINT(2, ("DefaultWritePipe %08X\n", defaultWritePipe));
|
|
|
|
DBGPRINT(2, ("exit: GenUSB_QueryFdoParams\n"));
|
|
}
|
|
|
|
|
|
//******************************************************************************
|
|
//
|
|
// GenUSB_Pnp()
|
|
//
|
|
// Dispatch routine which handles IRP_MJ_PNP
|
|
//
|
|
//******************************************************************************
|
|
|
|
NTSTATUS
|
|
GenUSB_Pnp (
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
)
|
|
{
|
|
PDEVICE_EXTENSION deviceExtension;
|
|
PIO_STACK_LOCATION irpStack;
|
|
NTSTATUS status;
|
|
|
|
PAGED_CODE();
|
|
|
|
deviceExtension = DeviceObject->DeviceExtension;
|
|
|
|
status = IoAcquireRemoveLock (&deviceExtension->RemoveLock, Irp);
|
|
if (!NT_SUCCESS(status)) {
|
|
Irp->IoStatus.Status = status;
|
|
IoCompleteRequest (Irp, IO_NO_INCREMENT);
|
|
return status;
|
|
}
|
|
|
|
irpStack = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
DBGPRINT(2, ("enter: GenUSB_Pnp %s\n",
|
|
PnPMinorFunctionString(irpStack->MinorFunction)));
|
|
|
|
LOGENTRY(deviceExtension, 'PNP ', DeviceObject, Irp, irpStack->MinorFunction);
|
|
|
|
switch (irpStack->MinorFunction) {
|
|
case IRP_MN_START_DEVICE:
|
|
status = GenUSB_StartDevice(DeviceObject, Irp);
|
|
IoReleaseRemoveLock (&deviceExtension->RemoveLock, Irp);
|
|
break;
|
|
|
|
case IRP_MN_REMOVE_DEVICE:
|
|
status = GenUSB_RemoveDevice(DeviceObject, Irp);
|
|
break;
|
|
|
|
case IRP_MN_QUERY_STOP_DEVICE:
|
|
case IRP_MN_QUERY_REMOVE_DEVICE:
|
|
status = GenUSB_QueryStopRemoveDevice(DeviceObject, Irp);
|
|
IoReleaseRemoveLock (&deviceExtension->RemoveLock, Irp);
|
|
break;
|
|
|
|
case IRP_MN_CANCEL_STOP_DEVICE:
|
|
case IRP_MN_CANCEL_REMOVE_DEVICE:
|
|
status = GenUSB_CancelStopRemoveDevice(DeviceObject, Irp);
|
|
IoReleaseRemoveLock (&deviceExtension->RemoveLock, Irp);
|
|
break;
|
|
|
|
case IRP_MN_STOP_DEVICE:
|
|
status = GenUSB_StopDevice(DeviceObject, Irp);
|
|
IoReleaseRemoveLock (&deviceExtension->RemoveLock, Irp);
|
|
break;
|
|
|
|
case IRP_MN_SURPRISE_REMOVAL:
|
|
//
|
|
// The documentation says to set the status before passing the
|
|
// Irp down the stack
|
|
//
|
|
Irp->IoStatus.Status = STATUS_SUCCESS;
|
|
|
|
// nothing else special yet, just fall through to default
|
|
|
|
default:
|
|
//
|
|
// Pass the request down to the next lower driver
|
|
//
|
|
IoSkipCurrentIrpStackLocation(Irp);
|
|
status = IoCallDriver(deviceExtension->StackDeviceObject, Irp);
|
|
IoReleaseRemoveLock (&deviceExtension->RemoveLock, Irp);
|
|
break;
|
|
}
|
|
|
|
DBGPRINT(2, ("exit: GenUSB_Pnp %08X\n", status));
|
|
|
|
LOGENTRY(deviceExtension, 'pnp ', status, 0, 0);
|
|
|
|
return status;
|
|
}
|
|
|
|
//******************************************************************************
|
|
//
|
|
// GenUSB_StartDevice()
|
|
//
|
|
// This routine handles IRP_MJ_PNP, IRP_MN_START_DEVICE for the FDO
|
|
//
|
|
// The PnP Manager sends this IRP at IRQL PASSIVE_LEVEL in the context of a
|
|
// system thread.
|
|
//
|
|
// This IRP must be handled first by the underlying bus driver for a device
|
|
// and then by each higher driver in the device stack.
|
|
//
|
|
//******************************************************************************
|
|
|
|
NTSTATUS
|
|
GenUSB_StartDevice (
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
)
|
|
{
|
|
PDEVICE_EXTENSION deviceExtension;
|
|
NTSTATUS status;
|
|
|
|
PAGED_CODE();
|
|
|
|
DBGPRINT(2, ("enter: GenUSB_StartDevice\n"));
|
|
|
|
DBGFBRK(DBGF_BRK_STARTDEVICE);
|
|
|
|
deviceExtension = DeviceObject->DeviceExtension;
|
|
|
|
LOGENTRY(deviceExtension, 'STRT', DeviceObject, Irp, 0);
|
|
|
|
if (deviceExtension->IsStarted)
|
|
{
|
|
status = STATUS_SUCCESS;
|
|
goto GenUSB_StartDeviceDone;
|
|
}
|
|
|
|
// Pass IRP_MN_START_DEVICE Irp down the stack first before we do anything.
|
|
status = GenUSB_SyncPassDownIrp(DeviceObject, Irp);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
DBGPRINT(1, ("Lower driver failed IRP_MN_START_DEVICE\n"));
|
|
LOGENTRY(deviceExtension, 'STRF', DeviceObject, Irp, status);
|
|
goto GenUSB_StartDeviceDone;
|
|
}
|
|
|
|
// If this is the first time the device as been started, retrieve the
|
|
// Device and Configuration Descriptors from the device.
|
|
if (deviceExtension->DeviceDescriptor == NULL) {
|
|
|
|
status = GenUSB_GetDescriptors(DeviceObject);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
goto GenUSB_StartDeviceDone;
|
|
}
|
|
// Create the interface but do not set it yet.
|
|
GenUSB_SetDeviceInterface (deviceExtension, TRUE, FALSE);
|
|
// Set up the registry values for the clients
|
|
GenUSB_SetDIRegValues (deviceExtension);
|
|
// Set up the device Interface.
|
|
GenUSB_SetDeviceInterface (deviceExtension, FALSE, TRUE);
|
|
}
|
|
else
|
|
{
|
|
ExAcquireFastMutex (&deviceExtension->ConfigMutex);
|
|
if (NULL != deviceExtension->ConfigurationHandle)
|
|
{
|
|
IoStartTimer (DeviceObject);
|
|
}
|
|
ExReleaseFastMutex (&deviceExtension->ConfigMutex);
|
|
}
|
|
|
|
|
|
deviceExtension->IsStarted = TRUE;
|
|
|
|
GenUSB_StartDeviceDone:
|
|
|
|
// Must complete request since completion routine returned
|
|
// STATUS_MORE_PROCESSING_REQUIRED
|
|
Irp->IoStatus.Status = status;
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
|
|
DBGPRINT(2, ("exit: GenUSB_FdoStartDevice %08X\n", status));
|
|
|
|
LOGENTRY(deviceExtension, 'strt', status, 0, 0);
|
|
|
|
return status;
|
|
}
|
|
//******************************************************************************
|
|
//
|
|
// GenUSB_SetDeviceInterface()
|
|
//
|
|
// This routine is called at START_DEVICE time to publish a device interface
|
|
// GUID so that the user mode LIB can find the FDOs.
|
|
//
|
|
//******************************************************************************
|
|
NTSTATUS
|
|
GenUSB_SetDeviceInterface (
|
|
IN PDEVICE_EXTENSION DeviceExtension,
|
|
IN BOOLEAN Create,
|
|
IN BOOLEAN Set
|
|
)
|
|
{
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
|
|
PAGED_CODE();
|
|
|
|
if (Create || Set)
|
|
{
|
|
if (Create)
|
|
{
|
|
ASSERT (NULL == DeviceExtension->DevInterfaceLinkName.Buffer);
|
|
status = IoRegisterDeviceInterface (
|
|
DeviceExtension->PhysicalDeviceObject,
|
|
(LPGUID)&GUID_DEVINTERFACE_GENUSB,
|
|
NULL,
|
|
&DeviceExtension->DevInterfaceLinkName);
|
|
}
|
|
if (NT_SUCCESS(status) && Set)
|
|
{
|
|
status = IoSetDeviceInterfaceState (
|
|
&DeviceExtension->DevInterfaceLinkName,
|
|
TRUE);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ASSERT (NULL != DeviceExtension->DevInterfaceLinkName.Buffer);
|
|
status = IoSetDeviceInterfaceState(
|
|
&DeviceExtension->DevInterfaceLinkName,
|
|
FALSE);
|
|
|
|
RtlFreeUnicodeString (&DeviceExtension->DevInterfaceLinkName);
|
|
}
|
|
return status;
|
|
}
|
|
|
|
|
|
//******************************************************************************
|
|
//
|
|
// GenUSB_SyncCompletionRoutine()
|
|
//
|
|
// Completion routine used by GenUSB_SyncPassDownIrp and
|
|
// GenUSB_SyncSendUsbRequest
|
|
//
|
|
// If the Irp is one we allocated ourself, DeviceObject is NULL.
|
|
//
|
|
//******************************************************************************
|
|
|
|
NTSTATUS
|
|
GenUSB_SyncCompletionRoutine (
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp,
|
|
IN PVOID Context
|
|
)
|
|
{
|
|
PDEVICE_EXTENSION deviceExtension;
|
|
|
|
KeSetEvent((PKEVENT)Context, IO_NO_INCREMENT, FALSE);
|
|
|
|
return STATUS_MORE_PROCESSING_REQUIRED;
|
|
}
|
|
|
|
//******************************************************************************
|
|
//
|
|
// GenUSB_SyncPassDownIrp()
|
|
//
|
|
//******************************************************************************
|
|
|
|
NTSTATUS
|
|
GenUSB_SyncPassDownIrp (
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
)
|
|
{
|
|
PDEVICE_EXTENSION deviceExtension;
|
|
NTSTATUS status;
|
|
KEVENT localevent;
|
|
|
|
PAGED_CODE();
|
|
|
|
DBGPRINT(2, ("enter: GenUSB_SyncPassDownIrp\n"));
|
|
|
|
deviceExtension = DeviceObject->DeviceExtension;
|
|
|
|
// Initialize the event we'll wait on
|
|
KeInitializeEvent(&localevent, SynchronizationEvent, FALSE);
|
|
|
|
// Copy down Irp params for the next driver
|
|
IoCopyCurrentIrpStackLocationToNext(Irp);
|
|
|
|
// Set the completion routine, which will signal the event
|
|
IoSetCompletionRoutine(Irp,
|
|
GenUSB_SyncCompletionRoutine,
|
|
&localevent,
|
|
TRUE, // InvokeOnSuccess
|
|
TRUE, // InvokeOnError
|
|
TRUE); // InvokeOnCancel
|
|
|
|
// Pass the Irp down the stack
|
|
status = IoCallDriver(deviceExtension->StackDeviceObject, Irp);
|
|
|
|
KeWaitForSingleObject(&localevent,
|
|
Executive,
|
|
KernelMode,
|
|
FALSE,
|
|
NULL);
|
|
|
|
status = Irp->IoStatus.Status;
|
|
|
|
DBGPRINT(2, ("exit: GenUSB_SyncPassDownIrp %08X\n", status));
|
|
return status;
|
|
}
|
|
|
|
//******************************************************************************
|
|
//
|
|
// GenUSB_SyncSendUsbRequest()
|
|
//
|
|
// Must be called at IRQL PASSIVE_LEVEL
|
|
//
|
|
//******************************************************************************
|
|
|
|
NTSTATUS
|
|
GenUSB_SyncSendUsbRequest (
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PURB Urb
|
|
)
|
|
{
|
|
PDEVICE_EXTENSION deviceExtension;
|
|
KEVENT localevent;
|
|
PIRP irp;
|
|
PIO_STACK_LOCATION nextStack;
|
|
NTSTATUS status;
|
|
|
|
PAGED_CODE();
|
|
|
|
DBGPRINT(3, ("enter: GenUSB_SyncSendUsbRequest\n"));
|
|
|
|
deviceExtension = DeviceObject->DeviceExtension;
|
|
|
|
// Initialize the event we'll wait on
|
|
KeInitializeEvent(&localevent, SynchronizationEvent, FALSE);
|
|
|
|
// Allocate the Irp
|
|
irp = IoAllocateIrp(deviceExtension->StackDeviceObject->StackSize, FALSE);
|
|
|
|
LOGENTRY(deviceExtension, 'SSUR', DeviceObject, irp, Urb);
|
|
|
|
if (NULL == irp)
|
|
{
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
// Set the Irp parameters
|
|
//
|
|
nextStack = IoGetNextIrpStackLocation(irp);
|
|
|
|
nextStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
|
|
|
|
nextStack->Parameters.DeviceIoControl.IoControlCode =
|
|
IOCTL_INTERNAL_USB_SUBMIT_URB;
|
|
|
|
nextStack->Parameters.Others.Argument1 = Urb;
|
|
|
|
// Set the completion routine, which will signal the event
|
|
IoSetCompletionRoutine(irp,
|
|
GenUSB_SyncCompletionRoutine,
|
|
&localevent,
|
|
TRUE, // InvokeOnSuccess
|
|
TRUE, // InvokeOnError
|
|
TRUE); // InvokeOnCancel
|
|
|
|
|
|
|
|
// Pass the Irp & Urb down the stack
|
|
status = IoCallDriver (deviceExtension->StackDeviceObject, irp);
|
|
|
|
// If the request is pending, block until it completes
|
|
if (status == STATUS_PENDING)
|
|
{
|
|
LARGE_INTEGER timeout;
|
|
|
|
// Specify a timeout of 5 seconds to wait for this call to complete.
|
|
//
|
|
timeout.QuadPart = -10000 * 5000;
|
|
|
|
status = KeWaitForSingleObject(&localevent,
|
|
Executive,
|
|
KernelMode,
|
|
FALSE,
|
|
&timeout);
|
|
|
|
if (status == STATUS_TIMEOUT)
|
|
{
|
|
status = STATUS_IO_TIMEOUT;
|
|
|
|
// Cancel the Irp we just sent.
|
|
IoCancelIrp(irp);
|
|
|
|
// And wait until the cancel completes
|
|
KeWaitForSingleObject(&localevent,
|
|
Executive,
|
|
KernelMode,
|
|
FALSE,
|
|
NULL);
|
|
}
|
|
else
|
|
{
|
|
status = irp->IoStatus.Status;
|
|
}
|
|
}
|
|
|
|
// Done with the Irp, now free it.
|
|
IoFreeIrp(irp);
|
|
|
|
LOGENTRY(deviceExtension, 'ssur', status, Urb, Urb->UrbHeader.Status);
|
|
|
|
DBGPRINT(3, ("exit: GenUSB_SyncSendUsbRequest %08X\n", status));
|
|
|
|
return status;
|
|
}
|
|
|
|
//******************************************************************************
|
|
//
|
|
// GenUSB_QueryStopRemoveDevice()
|
|
//
|
|
// This routine handles IRP_MJ_PNP, IRP_MN_QUERY_STOP_DEVICE and
|
|
// IRP_MN_QUERY_REMOVE_DEVICE for the FDO.
|
|
//
|
|
// The PnP Manager sends this IRP at IRQL PASSIVE_LEVEL in the context of a
|
|
// system thread.
|
|
//
|
|
// This IRP is handled first by the driver at the top of the device stack and
|
|
// then by each lower driver in the attachment chain.
|
|
//
|
|
//******************************************************************************
|
|
|
|
NTSTATUS
|
|
GenUSB_QueryStopRemoveDevice (
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
)
|
|
{
|
|
PDEVICE_EXTENSION deviceExtension;
|
|
NTSTATUS status;
|
|
|
|
PAGED_CODE();
|
|
|
|
DBGPRINT(2, ("enter: GenUSB_QueryStopRemoveDevice\n"));
|
|
DBGFBRK(DBGF_BRK_QUERYSTOPDEVICE);
|
|
|
|
deviceExtension = DeviceObject->DeviceExtension;
|
|
|
|
LOGENTRY(deviceExtension, 'QSRD', Irp, 0, 0);
|
|
|
|
//
|
|
// Notification that we are about to stop or be removed, but we don't care
|
|
// Pass the IRP_MN_QUERY_STOP/REMOVE_DEVICE Irp down the stack.
|
|
//
|
|
IoSkipCurrentIrpStackLocation(Irp);
|
|
|
|
status = IoCallDriver(deviceExtension->StackDeviceObject, Irp);
|
|
|
|
DBGPRINT(2, ("exit: GenUSB_FdoQueryStopRemoveDevice %08X\n", status));
|
|
|
|
LOGENTRY(deviceExtension, 'qsrd', Irp, 0, status);
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
//******************************************************************************
|
|
//
|
|
// GenUSB_FdoCancelStopRemoveDevice()
|
|
//
|
|
// This routine handles IRP_MJ_PNP, IRP_MN_CANCEL_STOP_DEVICE and
|
|
// IRP_MN_CANCEL_REMOVE_DEVICE for the FDO.
|
|
//
|
|
// The PnP Manager sends this IRP at IRQL PASSIVE_LEVEL in the context of a
|
|
// system thread.
|
|
//
|
|
// This IRP must be handled first by the underlying bus driver for a device
|
|
// and then by each higher driver in the device stack.
|
|
//
|
|
//******************************************************************************
|
|
|
|
NTSTATUS
|
|
GenUSB_CancelStopRemoveDevice (
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
)
|
|
{
|
|
PDEVICE_EXTENSION deviceExtension;
|
|
NTSTATUS status;
|
|
|
|
PAGED_CODE();
|
|
DBGPRINT(2, ("enter: GenUSB_FdoCancelStopRemoveDevice\n"));
|
|
DBGFBRK(DBGF_BRK_CANCELSTOPDEVICE);
|
|
|
|
deviceExtension = DeviceObject->DeviceExtension;
|
|
|
|
LOGENTRY(deviceExtension, 'CSRD', DeviceObject, Irp, 0);
|
|
|
|
// The documentation says to set the status before passing the Irp down
|
|
Irp->IoStatus.Status = STATUS_SUCCESS;
|
|
|
|
//
|
|
// Notification that the attempt to stop or be removed, is cancelled
|
|
// but we don't care
|
|
// Pass the IRP_MN_CANCEL_STOP/REMOVE_DEVICE Irp down the stack.
|
|
//
|
|
IoSkipCurrentIrpStackLocation(Irp);
|
|
|
|
status = IoCallDriver(deviceExtension->StackDeviceObject, Irp);
|
|
|
|
DBGPRINT(2, ("exit: GenUSB_FdoQueryStopRemoveDevice %08X\n", status));
|
|
|
|
LOGENTRY(deviceExtension, 'qsrd', Irp, 0, status);
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
//******************************************************************************
|
|
//
|
|
// GenUSB_FdoStopDevice()
|
|
//
|
|
// This routine handles IRP_MJ_PNP, IRP_MN_STOP_DEVICE for the FDO
|
|
//
|
|
// The PnP Manager sends this IRP at IRQL PASSIVE_LEVEL in the context of a
|
|
// system thread.
|
|
//
|
|
// The PnP Manager only sends this IRP if a prior IRP_MN_QUERY_STOP_DEVICE
|
|
// completed successfully.
|
|
//
|
|
// This IRP is handled first by the driver at the top of the device stack and
|
|
// then by each lower driver in the attachment chain.
|
|
//
|
|
// A driver must set Irp->IoStatus.Status to STATUS_SUCCESS. A driver must
|
|
// not fail this IRP. If a driver cannot release the device's hardware
|
|
// resources, it can fail a query-stop IRP, but once it succeeds the query-stop
|
|
// request it must succeed the stop request.
|
|
//
|
|
//******************************************************************************
|
|
|
|
NTSTATUS
|
|
GenUSB_StopDevice (
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
)
|
|
{
|
|
PDEVICE_EXTENSION deviceExtension;
|
|
NTSTATUS status;
|
|
|
|
PAGED_CODE();
|
|
|
|
DBGPRINT(2, ("enter: GenUSB_FdoStopDevice\n"));
|
|
|
|
DBGFBRK(DBGF_BRK_STOPDEVICE);
|
|
|
|
deviceExtension = DeviceObject->DeviceExtension;
|
|
|
|
LOGENTRY(deviceExtension, 'STOP', Irp, 0, 0);
|
|
|
|
// Release the device resources allocated during IRP_MN_START_DEVICE
|
|
|
|
// Stop the timeout timer
|
|
IoStopTimer(DeviceObject);
|
|
|
|
// The documentation says to set the status before passing the
|
|
// Irp down the stack
|
|
Irp->IoStatus.Status = STATUS_SUCCESS;
|
|
|
|
// Pass the IRP_MN_STOP_DEVICE Irp down the stack.
|
|
//
|
|
IoSkipCurrentIrpStackLocation(Irp);
|
|
|
|
status = IoCallDriver(deviceExtension->StackDeviceObject, Irp);
|
|
|
|
DBGPRINT(2, ("exit: GenUSB_FdoStopDevice %08X\n", status));
|
|
|
|
LOGENTRY(deviceExtension, 'stop', 0, 0, status);
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
//******************************************************************************
|
|
//
|
|
// GenUSB_RemoveDevice()
|
|
//
|
|
// This routine handles IRP_MJ_PNP, IRP_MN_REMOVE_DEVICE for the FDO
|
|
//
|
|
// The PnP Manager sends this IRP at IRQL PASSIVE_LEVEL in the context of a
|
|
// system thread.
|
|
//
|
|
// This IRP is handled first by the driver at the top of the device stack and
|
|
// then by each lower driver in the attachment chain.
|
|
//
|
|
// A driver must set Irp->IoStatus.Status to STATUS_SUCCESS. Drivers must not
|
|
// fail this IRP.
|
|
//
|
|
//******************************************************************************
|
|
|
|
NTSTATUS
|
|
GenUSB_RemoveDevice (
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
)
|
|
{
|
|
PDEVICE_EXTENSION deviceExtension;
|
|
NTSTATUS status;
|
|
|
|
PAGED_CODE();
|
|
|
|
DBGPRINT(2, ("enter: GenUSB_FdoRemoveDevice\n"));
|
|
|
|
DBGFBRK(DBGF_BRK_REMOVEDEVICE);
|
|
|
|
deviceExtension = DeviceObject->DeviceExtension;
|
|
|
|
IoReleaseRemoveLockAndWait (&deviceExtension->RemoveLock, Irp);
|
|
|
|
// Free everything that was allocated during IRP_MN_START_DEVICE
|
|
|
|
// The configuration should have been desected in the close,
|
|
// which we should have received even in a surprise remove case.
|
|
//
|
|
// GenUSB_DeselectConfiguration (deviceExtension, FALSE);
|
|
//
|
|
|
|
LOGUNINIT(deviceExtension);
|
|
|
|
ASSERT (NULL == deviceExtension->ConfigurationHandle);
|
|
|
|
if (deviceExtension->DeviceDescriptor != NULL)
|
|
{
|
|
ExFreePool(deviceExtension->DeviceDescriptor);
|
|
}
|
|
|
|
if (deviceExtension->ConfigurationDescriptor != NULL)
|
|
{
|
|
ExFreePool(deviceExtension->ConfigurationDescriptor);
|
|
}
|
|
|
|
if (deviceExtension->SerialNumber != NULL)
|
|
{
|
|
ExFreePool(deviceExtension->SerialNumber);
|
|
}
|
|
|
|
// The documentation says to set the status before passing the Irp down
|
|
Irp->IoStatus.Status = STATUS_SUCCESS;
|
|
|
|
// Pass the IRP_MN_REMOVE_DEVICE Irp down the stack.
|
|
IoSkipCurrentIrpStackLocation(Irp);
|
|
|
|
status = IoCallDriver(deviceExtension->StackDeviceObject, Irp);
|
|
|
|
LOGENTRY(deviceExtension, 'rem3', DeviceObject, 0, 0);
|
|
|
|
// Free everything that was allocated during AddDevice
|
|
IoDetachDevice(deviceExtension->StackDeviceObject);
|
|
|
|
IoDeleteDevice(DeviceObject);
|
|
|
|
DBGPRINT(2, ("exit: GenUSB_FdoRemoveDevice %08X\n", status));
|
|
return status;
|
|
}
|
|
|
|
NTSTATUS
|
|
GenUSB_SetDIRegValues (
|
|
IN PDEVICE_EXTENSION DeviceExtension
|
|
)
|
|
{
|
|
NTSTATUS status;
|
|
HANDLE key;
|
|
UNICODE_STRING name;
|
|
ULONG value = 0xf00d;
|
|
|
|
RtlInitUnicodeString (&name, L"PlaceHolder");
|
|
|
|
status = IoOpenDeviceInterfaceRegistryKey (
|
|
&DeviceExtension->DevInterfaceLinkName,
|
|
STANDARD_RIGHTS_ALL,
|
|
&key);
|
|
|
|
if (!NT_SUCCESS (status))
|
|
{
|
|
ASSERT (NT_SUCCESS (status));
|
|
return status;
|
|
}
|
|
|
|
status = ZwSetValueKey (
|
|
key,
|
|
&name,
|
|
0,
|
|
REG_DWORD,
|
|
&value,
|
|
sizeof (value));
|
|
|
|
if (!NT_SUCCESS (status))
|
|
{
|
|
ASSERT (NT_SUCCESS (status));
|
|
return status;
|
|
}
|
|
|
|
|
|
//
|
|
// Write in the class code and subcodes.
|
|
//
|
|
ASSERT (DeviceExtension->DeviceDescriptor);
|
|
RtlInitUnicodeString (&name, GENUSB_REG_STRING_DEVICE_CLASS);
|
|
value = DeviceExtension->DeviceDescriptor->bDeviceClass;
|
|
status = ZwSetValueKey (
|
|
key,
|
|
&name,
|
|
0,
|
|
REG_DWORD,
|
|
&value,
|
|
sizeof (value));
|
|
|
|
ASSERT (NT_SUCCESS (status));
|
|
|
|
RtlInitUnicodeString (&name, GENUSB_REG_STRING_DEVICE_SUB_CLASS);
|
|
value = DeviceExtension->DeviceDescriptor->bDeviceSubClass;
|
|
status = ZwSetValueKey (
|
|
key,
|
|
&name,
|
|
0,
|
|
REG_DWORD,
|
|
&value,
|
|
sizeof (value));
|
|
ASSERT (NT_SUCCESS (status));
|
|
|
|
RtlInitUnicodeString (&name, GENUSB_REG_STRING_DEVICE_PROTOCOL);
|
|
value = DeviceExtension->DeviceDescriptor->bDeviceProtocol;
|
|
status = ZwSetValueKey (
|
|
key,
|
|
&name,
|
|
0,
|
|
REG_DWORD,
|
|
&value,
|
|
sizeof (value));
|
|
ASSERT (NT_SUCCESS (status));
|
|
|
|
RtlInitUnicodeString (&name, GENUSB_REG_STRING_VID);
|
|
value = DeviceExtension->DeviceDescriptor->idVendor;
|
|
status = ZwSetValueKey (
|
|
key,
|
|
&name,
|
|
0,
|
|
REG_DWORD,
|
|
&value,
|
|
sizeof (value));
|
|
ASSERT (NT_SUCCESS (status));
|
|
|
|
RtlInitUnicodeString (&name, GENUSB_REG_STRING_PID);
|
|
value = DeviceExtension->DeviceDescriptor->idProduct;
|
|
status = ZwSetValueKey (
|
|
key,
|
|
&name,
|
|
0,
|
|
REG_DWORD,
|
|
&value,
|
|
sizeof (value));
|
|
ASSERT (NT_SUCCESS (status));
|
|
|
|
RtlInitUnicodeString (&name, GENUSB_REG_STRING_REV);
|
|
value = DeviceExtension->DeviceDescriptor->bcdDevice;
|
|
status = ZwSetValueKey (
|
|
key,
|
|
&name,
|
|
0,
|
|
REG_DWORD,
|
|
&value,
|
|
sizeof (value));
|
|
ASSERT (NT_SUCCESS (status));
|
|
|
|
ZwClose (key);
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
//******************************************************************************
|
|
//
|
|
// GenUSB_Power()
|
|
//
|
|
// Dispatch routine which handles IRP_MJ_POWER
|
|
//
|
|
//******************************************************************************
|
|
|
|
NTSTATUS
|
|
GenUSB_Power (
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
)
|
|
{
|
|
PDEVICE_EXTENSION deviceExtension;
|
|
PIO_STACK_LOCATION irpStack;
|
|
NTSTATUS status;
|
|
|
|
PAGED_CODE();
|
|
|
|
deviceExtension = DeviceObject->DeviceExtension;
|
|
|
|
irpStack = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
DBGPRINT(2, ("enter: GenUSB_Power %08X %08X %s\n",
|
|
DeviceObject,
|
|
Irp,
|
|
PowerMinorFunctionString(irpStack->MinorFunction)));
|
|
|
|
LOGENTRY(deviceExtension, 'PWR_',
|
|
Irp,
|
|
deviceExtension->DevicePowerState,
|
|
irpStack->MinorFunction);
|
|
|
|
if (irpStack->MinorFunction == IRP_MN_SET_POWER)
|
|
{
|
|
LOGENTRY(deviceExtension, 'PWRs',
|
|
irpStack->Parameters.Power.Type,
|
|
irpStack->Parameters.Power.State.SystemState,
|
|
irpStack->Parameters.Power.ShutdownType);
|
|
|
|
DBGPRINT(2, ("%s IRP_MN_SET_POWER %s\n",
|
|
(irpStack->Parameters.Power.Type == SystemPowerState) ?
|
|
"System" : "Device",
|
|
(irpStack->Parameters.Power.Type == SystemPowerState) ?
|
|
PowerSystemStateString(irpStack->Parameters.Power.State.SystemState) :
|
|
PowerDeviceStateString(irpStack->Parameters.Power.State.DeviceState)));
|
|
}
|
|
|
|
if (irpStack->MinorFunction == IRP_MN_SET_POWER)
|
|
{
|
|
//
|
|
// Handle powering the FDO down and up...
|
|
//
|
|
status = GenUSB_SetPower(deviceExtension, Irp);
|
|
}
|
|
else
|
|
{
|
|
// No special processing for IRP_MN_QUERY_POWER, IRP_MN_WAIT_WAKE,
|
|
// or IRP_MN_POWER_SEQUENCE at this time. Just pass the request
|
|
// down to the next lower driver now.
|
|
//
|
|
PoStartNextPowerIrp(Irp);
|
|
|
|
IoSkipCurrentIrpStackLocation(Irp);
|
|
|
|
status = PoCallDriver(deviceExtension->StackDeviceObject, Irp);
|
|
}
|
|
|
|
DBGPRINT(2, ("exit: GenUSB_Power %08X\n", status));
|
|
|
|
LOGENTRY(deviceExtension, 'powr', status, 0, 0);
|
|
|
|
return status;
|
|
}
|
|
|
|
//******************************************************************************
|
|
//
|
|
// GenUSB_FdoSetPower()
|
|
//
|
|
// Dispatch routine which handles IRP_MJ_POWER, IRP_MN_SET_POWER for the FDO
|
|
//
|
|
//******************************************************************************
|
|
|
|
NTSTATUS
|
|
GenUSB_SetPower (
|
|
PDEVICE_EXTENSION DeviceExtension,
|
|
IN PIRP Irp
|
|
)
|
|
{
|
|
PIO_STACK_LOCATION irpStack;
|
|
POWER_STATE_TYPE powerType;
|
|
POWER_STATE powerState;
|
|
POWER_STATE oldState;
|
|
POWER_STATE newState;
|
|
NTSTATUS status;
|
|
|
|
PAGED_CODE();
|
|
|
|
//
|
|
// Get our Irp parameters
|
|
//
|
|
irpStack = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
powerType = irpStack->Parameters.Power.Type;
|
|
powerState = irpStack->Parameters.Power.State;
|
|
|
|
LOGENTRY(DeviceExtension, 'FDSP', Irp, powerType, powerState.SystemState);
|
|
|
|
switch (powerType)
|
|
{
|
|
case SystemPowerState:
|
|
// Remember the current system state.
|
|
//
|
|
DeviceExtension->SystemPowerState = powerState.SystemState;
|
|
|
|
// Map the new system state to a new device state
|
|
//
|
|
if (powerState.SystemState != PowerSystemWorking)
|
|
{
|
|
newState.DeviceState = PowerDeviceD3;
|
|
}
|
|
else
|
|
{
|
|
newState.DeviceState = PowerDeviceD0;
|
|
}
|
|
|
|
// If the new device state is different than the current device
|
|
// state, request a device state power Irp.
|
|
//
|
|
if (DeviceExtension->DevicePowerState != newState.DeviceState)
|
|
{
|
|
DBGPRINT(2, ("Requesting power Irp %08X %08X from %s to %s\n",
|
|
DeviceExtension, Irp,
|
|
PowerDeviceStateString(DeviceExtension->DevicePowerState),
|
|
PowerDeviceStateString(newState.DeviceState)));
|
|
|
|
ASSERT(DeviceExtension->CurrentPowerIrp == NULL);
|
|
|
|
DeviceExtension->CurrentPowerIrp = Irp;
|
|
|
|
status = PoRequestPowerIrp(DeviceExtension->PhysicalDeviceObject,
|
|
IRP_MN_SET_POWER,
|
|
newState,
|
|
GenUSB_SetPowerCompletion,
|
|
DeviceExtension,
|
|
NULL);
|
|
|
|
}
|
|
break;
|
|
|
|
case DevicePowerState:
|
|
|
|
DBGPRINT(2, ("Received power Irp %08X %08X from %s to %s\n",
|
|
DeviceExtension, Irp,
|
|
PowerDeviceStateString(DeviceExtension->DevicePowerState),
|
|
PowerDeviceStateString(powerState.DeviceState)));
|
|
|
|
//
|
|
// Update the current device state.
|
|
//
|
|
oldState.DeviceState = DeviceExtension->DevicePowerState;
|
|
|
|
if (oldState.DeviceState == PowerDeviceD0 &&
|
|
powerState.DeviceState > PowerDeviceD0)
|
|
{
|
|
//
|
|
// DeviceState is checked on devicecontrol, read and write, but is
|
|
// only set here and in the completion routine
|
|
// GenUSB_SetPowerD0Completion
|
|
//
|
|
DeviceExtension->DevicePowerState = powerState.DeviceState;
|
|
|
|
//
|
|
// After talking extensively with JD, he tells me that I do not need
|
|
// to queue requests for power downs or query stop. If that is the
|
|
// case then even if the device power state isn't PowerDeviceD0 we
|
|
// can still allow trasfers. This, of course, is a property of the
|
|
// brand new port driver that went into XP.
|
|
//
|
|
// Also we shouldn't need to queue our current request.
|
|
// Instead we will just let the transfers fail.
|
|
//
|
|
// The app will see the failures returned with the appropriate
|
|
// status codes so that they can do the right thing.
|
|
//
|
|
|
|
PoStartNextPowerIrp (Irp);
|
|
IoSkipCurrentIrpStackLocation (Irp);
|
|
status = PoCallDriver(DeviceExtension->StackDeviceObject, Irp);
|
|
|
|
}
|
|
else if (oldState.DeviceState > PowerDeviceD0 &&
|
|
powerState.DeviceState == PowerDeviceD0)
|
|
{
|
|
//
|
|
// Since we didn't have to do anything for powering down
|
|
// We likewise need to do nothing for powering back up.
|
|
//
|
|
|
|
IoCopyCurrentIrpStackLocationToNext (Irp);
|
|
|
|
IoSetCompletionRoutine (Irp,
|
|
GenUSB_SetPowerD0Completion,
|
|
NULL, // no context
|
|
TRUE,
|
|
TRUE,
|
|
TRUE);
|
|
|
|
status = PoCallDriver(DeviceExtension->StackDeviceObject, Irp);
|
|
}
|
|
}
|
|
|
|
DBGPRINT(2, ("exit: GenUSB_FdoSetPower %08X\n", status));
|
|
|
|
LOGENTRY(DeviceExtension, 'fdsp', status, 0, 0);
|
|
|
|
return status;
|
|
}
|
|
|
|
//******************************************************************************
|
|
//
|
|
// GenUSB_SetPowerCompletion()
|
|
//
|
|
// Completion routine for PoRequestPowerIrp() in GenUSB_FdoSetPower.
|
|
//
|
|
// The purpose of this routine is to block passing down the SystemPowerState
|
|
// Irp until the requested DevicePowerState Irp completes.
|
|
//
|
|
//******************************************************************************
|
|
|
|
VOID
|
|
GenUSB_SetPowerCompletion(
|
|
IN PDEVICE_OBJECT PdoDeviceObject,
|
|
IN UCHAR MinorFunction,
|
|
IN POWER_STATE PowerState,
|
|
IN PVOID Context,
|
|
IN PIO_STATUS_BLOCK IoStatus
|
|
)
|
|
{
|
|
PDEVICE_EXTENSION deviceExtension;
|
|
PIRP irp;
|
|
|
|
deviceExtension = (PDEVICE_EXTENSION) Context;
|
|
|
|
ASSERT(deviceExtension->CurrentPowerIrp != NULL);
|
|
|
|
irp = deviceExtension->CurrentPowerIrp;
|
|
|
|
deviceExtension->CurrentPowerIrp = NULL;
|
|
|
|
#if DBG
|
|
{
|
|
PIO_STACK_LOCATION irpStack;
|
|
SYSTEM_POWER_STATE systemState;
|
|
|
|
irpStack = IoGetCurrentIrpStackLocation(irp);
|
|
|
|
systemState = irpStack->Parameters.Power.State.SystemState;
|
|
|
|
DBGPRINT(2, ("GenUSB_SetPowerCompletion %08X %08X %s %08X\n",
|
|
deviceExtension, irp,
|
|
PowerSystemStateString(systemState),
|
|
IoStatus->Status));
|
|
|
|
LOGENTRY(deviceExtension, 'fspc', 0, systemState, IoStatus->Status);
|
|
}
|
|
#endif
|
|
|
|
// The requested DevicePowerState Irp has completed.
|
|
// Now pass down the SystemPowerState Irp which requested the
|
|
// DevicePowerState Irp.
|
|
|
|
PoStartNextPowerIrp(irp);
|
|
|
|
IoCopyCurrentIrpStackLocationToNext(irp);
|
|
|
|
// Mark the Irp pending since GenUSB_FdoSetPower() would have
|
|
// originally returned STATUS_PENDING after calling PoRequestPowerIrp().
|
|
IoMarkIrpPending(irp);
|
|
|
|
PoCallDriver(deviceExtension->StackDeviceObject, irp);
|
|
}
|
|
|
|
//******************************************************************************
|
|
//
|
|
// GenUSB_SetPowerD0Completion()
|
|
//
|
|
// Completion routine used by GenUSB_FdoSetPower when passing down a
|
|
// IRP_MN_SET_POWER DevicePowerState PowerDeviceD0 Irp for the FDO.
|
|
//
|
|
// The purpose of this routine is to delay unblocking the device queue
|
|
// until after the DevicePowerState PowerDeviceD0 Irp completes.
|
|
//
|
|
//******************************************************************************
|
|
|
|
NTSTATUS
|
|
GenUSB_SetPowerD0Completion (
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp,
|
|
IN PVOID NotUsed
|
|
)
|
|
{
|
|
|
|
PDEVICE_EXTENSION deviceExtension;
|
|
PIO_STACK_LOCATION irpStack;
|
|
DEVICE_POWER_STATE deviceState;
|
|
KIRQL irql;
|
|
NTSTATUS status;
|
|
|
|
deviceExtension = DeviceObject->DeviceExtension;
|
|
|
|
irpStack = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
ASSERT(PowerDeviceD0 == irpStack->Parameters.Power.State.DeviceState);
|
|
ASSERT(deviceExtension->DevicePowerState != PowerDeviceD0);
|
|
deviceState=deviceExtension->DevicePowerState;
|
|
|
|
//
|
|
// DeviceState is checked on devicecontrol, read, and write, but is only
|
|
// set here, and in the power down code of GenUSB_SetPower.
|
|
//
|
|
deviceExtension->DevicePowerState = PowerDeviceD0;
|
|
|
|
status = Irp->IoStatus.Status;
|
|
|
|
DBGPRINT(2, ("GenUSB_FdoSetPowerD0Completion %08X %08X %s %08X\n",
|
|
DeviceObject, Irp,
|
|
PowerDeviceStateString(deviceState),
|
|
status));
|
|
|
|
LOGENTRY(deviceExtension, 'fs0c', DeviceObject, deviceState, status);
|
|
|
|
// Powering up. Unblock the device queue which was left blocked
|
|
// after GenUSB_StartIo() passed down the power down Irp.
|
|
|
|
PoStartNextPowerIrp(Irp);
|
|
|
|
return status;
|
|
}
|
|
|
|
//******************************************************************************
|
|
//
|
|
// GenUSB_SystemControl()
|
|
//
|
|
// Dispatch routine which handles IRP_MJ_SYSTEM_CONTROL
|
|
//
|
|
//******************************************************************************
|
|
|
|
NTSTATUS
|
|
GenUSB_SystemControl (
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
)
|
|
{
|
|
PDEVICE_EXTENSION deviceExtension;
|
|
PIO_STACK_LOCATION irpStack;
|
|
NTSTATUS ntStatus;
|
|
|
|
PAGED_CODE();
|
|
|
|
deviceExtension = DeviceObject->DeviceExtension;
|
|
|
|
irpStack = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
DBGPRINT(2, ("enter: GenUSB_SystemControl %2X\n", irpStack->MinorFunction));
|
|
|
|
LOGENTRY(deviceExtension, 'SYSC', DeviceObject, Irp, irpStack->MinorFunction);
|
|
|
|
switch (irpStack->MinorFunction)
|
|
{
|
|
//
|
|
// XXXXX Need to handle any of these?
|
|
//
|
|
|
|
default:
|
|
//
|
|
// Pass the request down to the next lower driver
|
|
//
|
|
IoSkipCurrentIrpStackLocation(Irp);
|
|
|
|
ntStatus = IoCallDriver(deviceExtension->StackDeviceObject, Irp);
|
|
break;
|
|
}
|
|
|
|
DBGPRINT(2, ("exit: GenUSB_SystemControl %08X\n", ntStatus));
|
|
|
|
LOGENTRY(deviceExtension, 'sysc', ntStatus, 0, 0);
|
|
|
|
return ntStatus;
|
|
}
|
|
|