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.
1971 lines
59 KiB
1971 lines
59 KiB
/*++
|
|
|
|
Copyright (c) 1996-1998 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
I82930.C
|
|
|
|
Abstract:
|
|
|
|
This source file contains the DriverEntry() and AddDevice() entry points
|
|
for the I82930 driver and the dispatch routines which handle:
|
|
|
|
IRP_MJ_POWER
|
|
IRP_MJ_SYSTEM_CONTROL
|
|
IRP_MJ_PNP
|
|
|
|
Environment:
|
|
|
|
kernel mode
|
|
|
|
Revision History:
|
|
|
|
06-01-98 : started rewrite
|
|
|
|
--*/
|
|
|
|
//*****************************************************************************
|
|
// I N C L U D E S
|
|
//*****************************************************************************
|
|
|
|
#include <wdm.h>
|
|
#include <usbdi.h>
|
|
#include <usbdlib.h>
|
|
|
|
#include <initguid.h>
|
|
|
|
#include "i82930.h"
|
|
#include "ioctl.h"
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text(PAGE, DriverEntry)
|
|
#pragma alloc_text(PAGE, I82930_Unload)
|
|
#pragma alloc_text(PAGE, I82930_AddDevice)
|
|
#pragma alloc_text(PAGE, I82930_Power)
|
|
#pragma alloc_text(PAGE, I82930_SystemControl)
|
|
#pragma alloc_text(PAGE, I82930_Pnp)
|
|
#pragma alloc_text(PAGE, I82930_StartDevice)
|
|
#pragma alloc_text(PAGE, I82930_StopDevice)
|
|
#pragma alloc_text(PAGE, I82930_RemoveDevice)
|
|
#pragma alloc_text(PAGE, I82930_QueryStopRemoveDevice)
|
|
#pragma alloc_text(PAGE, I82930_CancelStopRemoveDevice)
|
|
#pragma alloc_text(PAGE, I82930_QueryCapabilities)
|
|
#pragma alloc_text(PAGE, I82930_SyncPassDownIrp)
|
|
#pragma alloc_text(PAGE, I82930_SyncSendUsbRequest)
|
|
#pragma alloc_text(PAGE, I82930_GetDescriptor)
|
|
#pragma alloc_text(PAGE, I82930_SelectConfiguration)
|
|
#pragma alloc_text(PAGE, I82930_UnConfigure)
|
|
#endif
|
|
|
|
//******************************************************************************
|
|
//
|
|
// DriverEntry()
|
|
//
|
|
//******************************************************************************
|
|
|
|
NTSTATUS
|
|
DriverEntry (
|
|
IN PDRIVER_OBJECT DriverObject,
|
|
IN PUNICODE_STRING RegistryPath
|
|
)
|
|
{
|
|
#if DBG
|
|
// Query the registry for global parameters
|
|
//
|
|
I82930_QueryGlobalParams();
|
|
#endif
|
|
|
|
DBGPRINT(2, ("enter: DriverEntry\n"));
|
|
|
|
DBGFBRK(DBGF_BRK_DRIVERENTRY);
|
|
|
|
LOGINIT();
|
|
|
|
//
|
|
// Initialize the Driver Object with the driver's entry points
|
|
//
|
|
|
|
//
|
|
// I82930.C
|
|
//
|
|
DriverObject->DriverUnload = I82930_Unload;
|
|
DriverObject->DriverExtension->AddDevice = I82930_AddDevice;
|
|
|
|
//
|
|
// OCRW.C
|
|
//
|
|
DriverObject->MajorFunction[IRP_MJ_CREATE] = I82930_Create;
|
|
DriverObject->MajorFunction[IRP_MJ_CLOSE] = I82930_Close;
|
|
DriverObject->MajorFunction[IRP_MJ_READ] = I82930_ReadWrite;
|
|
DriverObject->MajorFunction[IRP_MJ_WRITE] = I82930_ReadWrite;
|
|
|
|
//
|
|
// IOCTL.C
|
|
//
|
|
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = I82930_DeviceControl;
|
|
|
|
//
|
|
// I82930.C
|
|
//
|
|
DriverObject->MajorFunction[IRP_MJ_POWER] = I82930_Power;
|
|
DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = I82930_SystemControl;
|
|
DriverObject->MajorFunction[IRP_MJ_PNP] = I82930_Pnp;
|
|
|
|
DBGPRINT(2, ("exit: DriverEntry\n"));
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
//******************************************************************************
|
|
//
|
|
// I82930_Unload()
|
|
//
|
|
//******************************************************************************
|
|
|
|
VOID
|
|
I82930_Unload (
|
|
IN PDRIVER_OBJECT DriverObject
|
|
)
|
|
{
|
|
DBGPRINT(2, ("enter: I82930_Unload\n"));
|
|
|
|
LOGENTRY('UNLD', DriverObject, 0, 0);
|
|
|
|
DBGFBRK(DBGF_BRK_UNLOAD);
|
|
|
|
LOGUNINIT();
|
|
|
|
DBGPRINT(2, ("exit: I82930_Unload\n"));
|
|
}
|
|
|
|
//******************************************************************************
|
|
//
|
|
// I82930_AddDevice()
|
|
//
|
|
//******************************************************************************
|
|
|
|
NTSTATUS
|
|
I82930_AddDevice (
|
|
IN PDRIVER_OBJECT DriverObject,
|
|
IN PDEVICE_OBJECT PhysicalDeviceObject
|
|
)
|
|
{
|
|
NTSTATUS ntStatus;
|
|
PDEVICE_OBJECT deviceObject;
|
|
PDEVICE_EXTENSION deviceExtension;
|
|
|
|
DBGPRINT(2, ("enter: I82930_AddDevice\n"));
|
|
|
|
LOGENTRY('ADDD', DriverObject, PhysicalDeviceObject, 0);
|
|
|
|
DBGFBRK(DBGF_BRK_ADDDEVICE);
|
|
|
|
// Create the FDO
|
|
//
|
|
ntStatus = IoCreateDevice(DriverObject,
|
|
sizeof(DEVICE_EXTENSION),
|
|
NULL,
|
|
FILE_DEVICE_UNKNOWN,
|
|
FILE_AUTOGENERATED_DEVICE_NAME,
|
|
FALSE,
|
|
&deviceObject);
|
|
|
|
if (!NT_SUCCESS(ntStatus))
|
|
{
|
|
return ntStatus;
|
|
}
|
|
|
|
// Initialize the DeviceExtension
|
|
//
|
|
deviceExtension = deviceObject->DeviceExtension;
|
|
|
|
// Set all DeviceExtension pointers to NULL and all variable to zero
|
|
//
|
|
RtlZeroMemory(deviceExtension, sizeof(DEVICE_EXTENSION));
|
|
|
|
// Remember our PDO
|
|
//
|
|
deviceExtension->PhysicalDeviceObject = PhysicalDeviceObject;
|
|
|
|
// Attach the FDO we created to the top of the PDO stack
|
|
//
|
|
deviceExtension->StackDeviceObject = IoAttachDeviceToDeviceStack(
|
|
deviceObject,
|
|
PhysicalDeviceObject);
|
|
|
|
// Initialize to one in AddDevice, decrement by one in REMOVE_DEVICE
|
|
//
|
|
deviceExtension->OpenCount = 1;
|
|
|
|
// Initialize the event which is set when OpenCount is decremented to zero.
|
|
//
|
|
KeInitializeEvent(&deviceExtension->RemoveEvent,
|
|
SynchronizationEvent,
|
|
FALSE);
|
|
|
|
// Set the initial system and device power states
|
|
//
|
|
deviceExtension->SystemPowerState = PowerSystemWorking;
|
|
deviceExtension->DevicePowerState = PowerDeviceD0;
|
|
|
|
deviceObject->Flags |= DO_DIRECT_IO;
|
|
deviceObject->Flags |= DO_POWER_PAGABLE;
|
|
deviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
|
|
|
|
DBGPRINT(2, ("exit: I82930_AddDevice\n"));
|
|
|
|
LOGENTRY('addd', deviceObject, deviceExtension, deviceExtension->StackDeviceObject);
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
//******************************************************************************
|
|
//
|
|
// I82930_Power()
|
|
//
|
|
// Dispatch routine which handles IRP_MJ_POWER
|
|
//
|
|
//******************************************************************************
|
|
|
|
NTSTATUS
|
|
I82930_Power (
|
|
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: I82930_Power %08X %s\n",
|
|
DeviceObject,
|
|
PowerMinorFunctionString(irpStack->MinorFunction)));
|
|
|
|
LOGENTRY('POWR', DeviceObject, Irp, irpStack->MinorFunction);
|
|
|
|
if (irpStack->MinorFunction == IRP_MN_SET_POWER)
|
|
{
|
|
DBGPRINT(2, ("IRP_MN_SET_POWER %s\n",
|
|
(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...
|
|
//
|
|
ntStatus = I82930_FdoSetPower(DeviceObject,
|
|
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);
|
|
|
|
ntStatus = PoCallDriver(deviceExtension->StackDeviceObject,
|
|
Irp);
|
|
}
|
|
|
|
DBGPRINT(2, ("exit: I82930_Power %08X\n", ntStatus));
|
|
|
|
LOGENTRY('powr', ntStatus, 0, 0);
|
|
|
|
return ntStatus;
|
|
}
|
|
|
|
//******************************************************************************
|
|
//
|
|
// I82930_FdoSetPower()
|
|
//
|
|
// Dispatch routine which handles IRP_MJ_POWER, IRP_MN_SET_POWER for the FDO
|
|
//
|
|
//******************************************************************************
|
|
|
|
NTSTATUS
|
|
I82930_FdoSetPower (
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
)
|
|
{
|
|
PDEVICE_EXTENSION deviceExtension;
|
|
PIO_STACK_LOCATION irpStack;
|
|
POWER_STATE_TYPE powerType;
|
|
POWER_STATE powerState;
|
|
POWER_STATE newState;
|
|
BOOLEAN passRequest;
|
|
NTSTATUS ntStatus;
|
|
|
|
PAGED_CODE();
|
|
|
|
deviceExtension = DeviceObject->DeviceExtension;
|
|
|
|
// Get our Irp parameters
|
|
//
|
|
irpStack = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
powerType = irpStack->Parameters.Power.Type;
|
|
|
|
powerState = irpStack->Parameters.Power.State;
|
|
|
|
DBGPRINT(2, ("enter: I82930_FdoSetPower %08X %s\n",
|
|
DeviceObject,
|
|
(powerType == SystemPowerState) ?
|
|
PowerSystemStateString(powerState.SystemState) :
|
|
PowerDeviceStateString(powerState.DeviceState)));
|
|
|
|
LOGENTRY('FDSP', DeviceObject, Irp, irpStack->MinorFunction);
|
|
|
|
// Pass the request down here, unless we request a device state power
|
|
// Irp, in which case we pass the request down in our completion routine.
|
|
//
|
|
passRequest = TRUE;
|
|
|
|
if (powerType == 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",
|
|
DeviceObject, Irp,
|
|
PowerDeviceStateString(deviceExtension->DevicePowerState),
|
|
PowerDeviceStateString(newState.DeviceState)));
|
|
|
|
ASSERT(deviceExtension->CurrentPowerIrp == NULL);
|
|
|
|
deviceExtension->CurrentPowerIrp = Irp;
|
|
|
|
ntStatus = PoRequestPowerIrp(deviceExtension->PhysicalDeviceObject,
|
|
IRP_MN_SET_POWER,
|
|
newState,
|
|
I82930_FdoSetPowerCompletion,
|
|
DeviceObject,
|
|
NULL);
|
|
|
|
passRequest = FALSE;
|
|
}
|
|
}
|
|
else if (powerType == DevicePowerState)
|
|
{
|
|
POWER_STATE oldState;
|
|
|
|
DBGPRINT(2, ("Received power Irp %08X %08X from %s to %s\n",
|
|
DeviceObject, Irp,
|
|
PowerDeviceStateString(deviceExtension->DevicePowerState),
|
|
PowerDeviceStateString(powerState.DeviceState)));
|
|
|
|
// Update the current device state.
|
|
//
|
|
oldState.DeviceState = deviceExtension->DevicePowerState;
|
|
deviceExtension->DevicePowerState = powerState.DeviceState;
|
|
|
|
if (oldState.DeviceState == PowerDeviceD0 &&
|
|
powerState.DeviceState > PowerDeviceD0)
|
|
{
|
|
// Powering down.
|
|
|
|
DBGPRINT(2, ("FDO Powering Down\n"));
|
|
|
|
LOGENTRY('PWRD', DeviceObject, Irp, 0);
|
|
}
|
|
else if (oldState.DeviceState > PowerDeviceD0 &&
|
|
powerState.DeviceState == PowerDeviceD0)
|
|
{
|
|
DBGPRINT(2, ("PDO Powering Up\n"));
|
|
|
|
LOGENTRY('PWRU', DeviceObject, Irp, 0);
|
|
}
|
|
}
|
|
|
|
if (passRequest)
|
|
{
|
|
//
|
|
// Pass the request down to the next lower driver
|
|
//
|
|
PoStartNextPowerIrp(Irp);
|
|
|
|
IoSkipCurrentIrpStackLocation(Irp);
|
|
|
|
ntStatus = PoCallDriver(deviceExtension->StackDeviceObject,
|
|
Irp);
|
|
}
|
|
|
|
DBGPRINT(2, ("exit: I82930_FdoSetPower %08X\n", ntStatus));
|
|
|
|
LOGENTRY('fdsp', ntStatus, 0, 0);
|
|
|
|
return ntStatus;
|
|
}
|
|
|
|
//******************************************************************************
|
|
//
|
|
// I82930_FdoSetPowerCompletion()
|
|
//
|
|
// Completion routine for PoRequestPowerIrp() in I82930_FdoSetPower.
|
|
//
|
|
// The purpose of this routine is to block passing down the SystemPowerState
|
|
// Irp until the requested DevicePowerState Irp completes.
|
|
//
|
|
//******************************************************************************
|
|
|
|
VOID
|
|
I82930_FdoSetPowerCompletion(
|
|
IN PDEVICE_OBJECT PdoDeviceObject,
|
|
IN UCHAR MinorFunction,
|
|
IN POWER_STATE PowerState,
|
|
IN PVOID Context,
|
|
IN PIO_STATUS_BLOCK IoStatus
|
|
)
|
|
{
|
|
PDEVICE_OBJECT fdoDeviceObject;
|
|
PDEVICE_EXTENSION deviceExtension;
|
|
PIRP irp;
|
|
NTSTATUS ntStatus;
|
|
|
|
fdoDeviceObject = (PDEVICE_OBJECT)Context;
|
|
|
|
deviceExtension = fdoDeviceObject->DeviceExtension;
|
|
|
|
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;
|
|
|
|
ntStatus = IoStatus->Status;
|
|
|
|
DBGPRINT(2, ("I82930_FdoSetPowerCompletion %08X %08X %s %08X\n",
|
|
fdoDeviceObject, irp,
|
|
PowerSystemStateString(systemState),
|
|
ntStatus));
|
|
|
|
LOGENTRY('fspc', fdoDeviceObject, systemState, ntStatus);
|
|
}
|
|
#endif
|
|
|
|
// The requested DevicePowerState Irp has completed.
|
|
// Now pass down the SystemPowerState Irp which requested the
|
|
// DevicePowerState Irp.
|
|
|
|
PoStartNextPowerIrp(irp);
|
|
|
|
IoSkipCurrentIrpStackLocation(irp);
|
|
|
|
ntStatus = PoCallDriver(deviceExtension->StackDeviceObject,
|
|
irp);
|
|
}
|
|
|
|
//******************************************************************************
|
|
//
|
|
// I82930_SystemControl()
|
|
//
|
|
// Dispatch routine which handles IRP_MJ_SYSTEM_CONTROL
|
|
//
|
|
//******************************************************************************
|
|
|
|
NTSTATUS
|
|
I82930_SystemControl (
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
)
|
|
{
|
|
NTSTATUS ntStatus;
|
|
PDEVICE_EXTENSION deviceExtension;
|
|
PIO_STACK_LOCATION irpStack;
|
|
|
|
deviceExtension = DeviceObject->DeviceExtension;
|
|
|
|
irpStack = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
DBGPRINT(2, ("enter: I82930_SystemControl %2X\n", irpStack->MinorFunction));
|
|
|
|
LOGENTRY('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: I82930_SystemControl %08X\n", ntStatus));
|
|
|
|
LOGENTRY('sysc', ntStatus, 0, 0);
|
|
|
|
return ntStatus;
|
|
}
|
|
|
|
//******************************************************************************
|
|
//
|
|
// I82930_Pnp()
|
|
//
|
|
// Dispatch routine which handles IRP_MJ_PNP
|
|
//
|
|
//******************************************************************************
|
|
|
|
NTSTATUS
|
|
I82930_Pnp (
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
)
|
|
{
|
|
NTSTATUS ntStatus;
|
|
PDEVICE_EXTENSION deviceExtension;
|
|
PIO_STACK_LOCATION irpStack;
|
|
|
|
deviceExtension = DeviceObject->DeviceExtension;
|
|
|
|
irpStack = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
DBGPRINT(2, ("enter: I82930_Pnp %s\n",
|
|
PnPMinorFunctionString(irpStack->MinorFunction)));
|
|
|
|
LOGENTRY('PNP ', DeviceObject, Irp, irpStack->MinorFunction);
|
|
|
|
switch (irpStack->MinorFunction)
|
|
{
|
|
case IRP_MN_START_DEVICE:
|
|
ntStatus = I82930_StartDevice(DeviceObject, Irp);
|
|
break;
|
|
|
|
case IRP_MN_STOP_DEVICE:
|
|
ntStatus = I82930_StopDevice(DeviceObject, Irp);
|
|
break;
|
|
|
|
case IRP_MN_REMOVE_DEVICE:
|
|
ntStatus = I82930_RemoveDevice(DeviceObject, Irp);
|
|
break;
|
|
|
|
case IRP_MN_QUERY_STOP_DEVICE:
|
|
case IRP_MN_QUERY_REMOVE_DEVICE:
|
|
ntStatus = I82930_QueryStopRemoveDevice(DeviceObject, Irp);
|
|
break;
|
|
|
|
case IRP_MN_CANCEL_STOP_DEVICE:
|
|
case IRP_MN_CANCEL_REMOVE_DEVICE:
|
|
ntStatus = I82930_CancelStopRemoveDevice(DeviceObject, Irp);
|
|
break;
|
|
|
|
case IRP_MN_QUERY_CAPABILITIES:
|
|
ntStatus = I82930_QueryCapabilities(DeviceObject, Irp);
|
|
break;
|
|
|
|
case IRP_MN_SURPRISE_REMOVAL:
|
|
// nothing special yet, just fall through to default
|
|
|
|
default:
|
|
//
|
|
// Pass the request down to the next lower driver
|
|
//
|
|
IoSkipCurrentIrpStackLocation(Irp);
|
|
|
|
ntStatus = IoCallDriver(deviceExtension->StackDeviceObject,
|
|
Irp);
|
|
break;
|
|
}
|
|
|
|
DBGPRINT(2, ("exit: I82930_Pnp %08X\n", ntStatus));
|
|
|
|
LOGENTRY('pnp ', ntStatus, 0, 0);
|
|
|
|
return ntStatus;
|
|
}
|
|
|
|
|
|
//******************************************************************************
|
|
//
|
|
// I82930_StartDevice()
|
|
//
|
|
// This routine handles IRP_MJ_PNP, IRP_MN_START_DEVICE
|
|
//
|
|
// 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.
|
|
//
|
|
// Device specific actions:
|
|
// Retrieve the Device Descriptor from device (first time only)
|
|
// Retrieve the Configuration Descriptor from device (first time only)
|
|
// Configure the device (every time)
|
|
// Create the SymbolicLink name (first time only)
|
|
// Enable the SymbolicLink name (every time)
|
|
//
|
|
//******************************************************************************
|
|
|
|
NTSTATUS
|
|
I82930_StartDevice (
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
)
|
|
{
|
|
PDEVICE_EXTENSION deviceExtension;
|
|
PUCHAR descriptor;
|
|
ULONG descriptorLength;
|
|
NTSTATUS ntStatus;
|
|
|
|
DBGPRINT(2, ("enter: I82930_StartDevice\n"));
|
|
|
|
DBGFBRK(DBGF_BRK_STARTDEVICE);
|
|
|
|
LOGENTRY('STRT', DeviceObject, Irp, 0);
|
|
|
|
deviceExtension = DeviceObject->DeviceExtension;
|
|
|
|
// Pass IRP_MN_START_DEVICE Irp down the stack first before we do anything.
|
|
//
|
|
ntStatus = I82930_SyncPassDownIrp(DeviceObject,
|
|
Irp,
|
|
TRUE);
|
|
if (!NT_SUCCESS(ntStatus))
|
|
{
|
|
DBGPRINT(1, ("Lower driver failed IRP_MN_START_DEVICE\n"));
|
|
goto I82930_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)
|
|
{
|
|
//
|
|
// Get Device Descriptor
|
|
//
|
|
ntStatus = I82930_GetDescriptor(DeviceObject,
|
|
USB_RECIPIENT_DEVICE,
|
|
USB_DEVICE_DESCRIPTOR_TYPE,
|
|
0, // Index
|
|
0, // LanguageId
|
|
2, // RetryCount
|
|
sizeof(USB_DEVICE_DESCRIPTOR),
|
|
&descriptor);
|
|
|
|
if (!NT_SUCCESS(ntStatus))
|
|
{
|
|
DBGPRINT(1, ("Get Device Descriptor failed\n"));
|
|
Irp->IoStatus.Status = ntStatus;
|
|
goto I82930_StartDeviceDone;
|
|
}
|
|
|
|
deviceExtension->DeviceDescriptor = (PUSB_DEVICE_DESCRIPTOR)descriptor;
|
|
|
|
//
|
|
// Get Configuration Descriptor (just the Configuration Descriptor)
|
|
//
|
|
ntStatus = I82930_GetDescriptor(DeviceObject,
|
|
USB_RECIPIENT_DEVICE,
|
|
USB_CONFIGURATION_DESCRIPTOR_TYPE,
|
|
0, // Index
|
|
0, // LanguageId
|
|
2, // RetryCount
|
|
sizeof(USB_CONFIGURATION_DESCRIPTOR),
|
|
&descriptor);
|
|
|
|
if (!NT_SUCCESS(ntStatus))
|
|
{
|
|
DBGPRINT(1, ("Get Configuration Descriptor failed (1)\n"));
|
|
Irp->IoStatus.Status = ntStatus;
|
|
goto I82930_StartDeviceDone;
|
|
}
|
|
|
|
descriptorLength = ((PUSB_CONFIGURATION_DESCRIPTOR)descriptor)->wTotalLength;
|
|
|
|
ExFreePool(descriptor);
|
|
|
|
if (descriptorLength < sizeof(USB_CONFIGURATION_DESCRIPTOR))
|
|
{
|
|
ntStatus = STATUS_DEVICE_DATA_ERROR;
|
|
DBGPRINT(1, ("Get Configuration Descriptor failed (2)\n"));
|
|
Irp->IoStatus.Status = ntStatus;
|
|
goto I82930_StartDeviceDone;
|
|
}
|
|
|
|
//
|
|
// Get Configuration Descriptor (and Interface and Endpoint Descriptors)
|
|
//
|
|
ntStatus = I82930_GetDescriptor(DeviceObject,
|
|
USB_RECIPIENT_DEVICE,
|
|
USB_CONFIGURATION_DESCRIPTOR_TYPE,
|
|
0, // Index
|
|
0, // LanguageId
|
|
2, // RetryCount
|
|
descriptorLength,
|
|
&descriptor);
|
|
|
|
if (!NT_SUCCESS(ntStatus))
|
|
{
|
|
DBGPRINT(1, ("Get Configuration Descriptor failed (3)\n"));
|
|
Irp->IoStatus.Status = ntStatus;
|
|
goto I82930_StartDeviceDone;
|
|
}
|
|
|
|
deviceExtension->ConfigurationDescriptor = (PUSB_CONFIGURATION_DESCRIPTOR)descriptor;
|
|
|
|
#if DBG
|
|
DumpDeviceDesc(deviceExtension->DeviceDescriptor);
|
|
DumpConfigDesc(deviceExtension->ConfigurationDescriptor);
|
|
#endif
|
|
}
|
|
|
|
// Now configure the device
|
|
//
|
|
ntStatus = I82930_SelectConfiguration(DeviceObject);
|
|
|
|
if (!NT_SUCCESS(ntStatus))
|
|
{
|
|
DBGPRINT(1, ("Configure device failed\n"));
|
|
Irp->IoStatus.Status = ntStatus;
|
|
goto I82930_StartDeviceDone;
|
|
}
|
|
|
|
// Create the SymbolicLink name if necessary
|
|
//
|
|
if (deviceExtension->SymbolicLinkName.Buffer == NULL)
|
|
{
|
|
ntStatus = IoRegisterDeviceInterface(
|
|
deviceExtension->PhysicalDeviceObject,
|
|
(LPGUID)&GUID_CLASS_I82930,
|
|
NULL,
|
|
&deviceExtension->SymbolicLinkName);
|
|
|
|
if (!NT_SUCCESS(ntStatus))
|
|
{
|
|
DBGPRINT(1, ("IoRegisterDeviceInterface failed\n"));
|
|
Irp->IoStatus.Status = ntStatus;
|
|
goto I82930_StartDeviceDone;
|
|
}
|
|
}
|
|
|
|
// All set for user requests at this point
|
|
//
|
|
deviceExtension->AcceptingRequests = TRUE;
|
|
|
|
// Enable the SymbolicLink name
|
|
//
|
|
ntStatus = IoSetDeviceInterfaceState(
|
|
&deviceExtension->SymbolicLinkName,
|
|
TRUE);
|
|
|
|
if (!NT_SUCCESS(ntStatus))
|
|
{
|
|
DBGPRINT(1, ("IoSetDeviceInterfaceState failed\n"));
|
|
Irp->IoStatus.Status = ntStatus;
|
|
goto I82930_StartDeviceDone;
|
|
}
|
|
|
|
I82930_StartDeviceDone:
|
|
|
|
// Must complete request since completion routine returned
|
|
// STATUS_MORE_PROCESSING_REQUIRED
|
|
//
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
|
|
DBGPRINT(2, ("exit: I82930_StartDevice %08X\n", ntStatus));
|
|
|
|
LOGENTRY('strt', ntStatus, 0, 0);
|
|
|
|
return ntStatus;
|
|
}
|
|
|
|
//******************************************************************************
|
|
//
|
|
// I82930_StopDevice()
|
|
//
|
|
// This routine handles IRP_MJ_PNP, IRP_MN_STOP_DEVICE
|
|
//
|
|
// 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
|
|
I82930_StopDevice (
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
)
|
|
{
|
|
PDEVICE_EXTENSION deviceExtension;
|
|
NTSTATUS ntStatus;
|
|
|
|
DBGPRINT(2, ("enter: I82930_StopDevice\n"));
|
|
|
|
LOGENTRY('STOP', DeviceObject, Irp, 0);
|
|
|
|
DBGFBRK(DBGF_BRK_STOPDEVICE);
|
|
|
|
deviceExtension = DeviceObject->DeviceExtension;
|
|
|
|
// Release the device resources allocated during IRP_MN_START_DEVICE
|
|
//
|
|
|
|
// Unconfigure the device
|
|
//
|
|
ntStatus = I82930_UnConfigure(DeviceObject);
|
|
|
|
// Pass the IRP_MN_STOP_DEVICE Irp down the stack.
|
|
//
|
|
IoSkipCurrentIrpStackLocation(Irp);
|
|
|
|
ntStatus = IoCallDriver(deviceExtension->StackDeviceObject,
|
|
Irp);
|
|
|
|
DBGPRINT(2, ("exit: I82930_StopDevice %08X\n", ntStatus));
|
|
|
|
LOGENTRY('stop', ntStatus, 0, 0);
|
|
|
|
return ntStatus;
|
|
}
|
|
|
|
//******************************************************************************
|
|
//
|
|
// I82930_RemoveDevice()
|
|
//
|
|
// This routine handles IRP_MJ_PNP, IRP_MN_REMOVE_DEVICE
|
|
//
|
|
// 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
|
|
I82930_RemoveDevice (
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
)
|
|
{
|
|
PDEVICE_EXTENSION deviceExtension;
|
|
NTSTATUS ntStatus;
|
|
|
|
DBGPRINT(2, ("enter: I82930_RemoveDevice\n"));
|
|
|
|
LOGENTRY('REMV', DeviceObject, Irp, 0);
|
|
|
|
DBGFBRK(DBGF_BRK_REMOVEDEVICE);
|
|
|
|
deviceExtension = DeviceObject->DeviceExtension;
|
|
|
|
// Disable and free the SymbolicLink name if necessary
|
|
//
|
|
if (deviceExtension->SymbolicLinkName.Buffer != NULL)
|
|
{
|
|
ntStatus = IoSetDeviceInterfaceState(
|
|
&deviceExtension->SymbolicLinkName,
|
|
FALSE);
|
|
|
|
RtlFreeUnicodeString(&deviceExtension->SymbolicLinkName);
|
|
}
|
|
|
|
// No more user requests at this point
|
|
//
|
|
deviceExtension->AcceptingRequests = FALSE;
|
|
|
|
// Abort any requests that may be lingering on any of the endpoints.
|
|
//
|
|
if (deviceExtension->InterfaceInfo != NULL)
|
|
{
|
|
ULONG pipeIndex;
|
|
ULONG numPipes;
|
|
|
|
numPipes = deviceExtension->InterfaceInfo->NumberOfPipes;
|
|
|
|
for (pipeIndex = 0; pipeIndex < numPipes; pipeIndex++)
|
|
{
|
|
I82930_AbortPipe(DeviceObject,
|
|
&deviceExtension->PipeList[pipeIndex]);
|
|
}
|
|
}
|
|
|
|
// Decrement by one to match the initial one in AddDevice
|
|
//
|
|
DECREMENT_OPEN_COUNT(deviceExtension);
|
|
|
|
LOGENTRY('rem1', DeviceObject, 0, 0);
|
|
|
|
// Wait for all pending requests to complete
|
|
//
|
|
KeWaitForSingleObject(&deviceExtension->RemoveEvent,
|
|
Executive,
|
|
KernelMode,
|
|
FALSE,
|
|
NULL);
|
|
|
|
LOGENTRY('rem2', DeviceObject, 0, 0);
|
|
|
|
// Free everything that was allocated during IRP_MN_START_DEVICE
|
|
//
|
|
|
|
if (deviceExtension->DeviceDescriptor != NULL)
|
|
{
|
|
ExFreePool(deviceExtension->DeviceDescriptor);
|
|
}
|
|
|
|
if (deviceExtension->ConfigurationDescriptor != NULL)
|
|
{
|
|
ExFreePool(deviceExtension->ConfigurationDescriptor);
|
|
}
|
|
|
|
if (deviceExtension->InterfaceInfo != NULL)
|
|
{
|
|
ExFreePool(deviceExtension->InterfaceInfo);
|
|
}
|
|
|
|
// 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);
|
|
|
|
ntStatus = IoCallDriver(deviceExtension->StackDeviceObject,
|
|
Irp);
|
|
|
|
LOGENTRY('rem3', DeviceObject, 0, 0);
|
|
|
|
// Free everything that was allocated during AddDevice
|
|
//
|
|
IoDetachDevice(deviceExtension->StackDeviceObject);
|
|
|
|
IoDeleteDevice(DeviceObject);
|
|
|
|
DBGPRINT(2, ("exit: I82930_RemoveDevice %08X\n", ntStatus));
|
|
|
|
LOGENTRY('remv', ntStatus, 0, 0);
|
|
|
|
return ntStatus;
|
|
}
|
|
|
|
//******************************************************************************
|
|
//
|
|
// I82930_QueryStopRemoveDevice()
|
|
//
|
|
// This routine handles IRP_MJ_PNP, IRP_MN_QUERY_STOP_DEVICE and
|
|
// IRP_MN_QUERY_REMOVE_DEVICE.
|
|
//
|
|
// 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
|
|
I82930_QueryStopRemoveDevice (
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
)
|
|
{
|
|
PDEVICE_EXTENSION deviceExtension;
|
|
NTSTATUS ntStatus;
|
|
|
|
DBGPRINT(2, ("enter: I82930_QueryStopRemoveDevice\n"));
|
|
|
|
LOGENTRY('QSRD', DeviceObject, Irp, 0);
|
|
|
|
DBGFBRK(DBGF_BRK_QUERYSTOPDEVICE);
|
|
|
|
deviceExtension = DeviceObject->DeviceExtension;
|
|
|
|
// Disable the SymbolicLink name
|
|
//
|
|
ntStatus = IoSetDeviceInterfaceState(
|
|
&deviceExtension->SymbolicLinkName,
|
|
FALSE);
|
|
|
|
// No more user requests at this point
|
|
//
|
|
deviceExtension->AcceptingRequests = FALSE;
|
|
|
|
// If there are no opens, OK to STOP or REMOVE
|
|
//
|
|
if (deviceExtension->OpenCount == 1)
|
|
{
|
|
LOGENTRY('qsr1', 0, 0, 0);
|
|
|
|
// The documentation says to set the status before passing the Irp down
|
|
//
|
|
Irp->IoStatus.Status = STATUS_SUCCESS;
|
|
|
|
// Pass the IRP_MN_QUERY_STOP/REMOVE_DEVICE Irp down the stack.
|
|
//
|
|
IoSkipCurrentIrpStackLocation(Irp);
|
|
|
|
ntStatus = IoCallDriver(deviceExtension->StackDeviceObject,
|
|
Irp);
|
|
|
|
}
|
|
else
|
|
{
|
|
LOGENTRY('qsr2', deviceExtension->OpenCount, 0, 0);
|
|
|
|
ntStatus = STATUS_DEVICE_BUSY;
|
|
|
|
Irp->IoStatus.Status = ntStatus;
|
|
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
}
|
|
|
|
DBGPRINT(2, ("exit: I82930_QueryStopRemoveDevice %08X\n", ntStatus));
|
|
|
|
LOGENTRY('qsrd', ntStatus, 0, 0);
|
|
|
|
return ntStatus;
|
|
}
|
|
|
|
//******************************************************************************
|
|
//
|
|
// I82930_CancelStopRemoveDevice()
|
|
//
|
|
// This routine handles IRP_MJ_PNP, IRP_MN_CANCEL_STOP_DEVICE and
|
|
// IRP_MN_CANCEL_REMOVE_DEVICE.
|
|
//
|
|
// 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
|
|
I82930_CancelStopRemoveDevice (
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
)
|
|
{
|
|
PDEVICE_EXTENSION deviceExtension;
|
|
NTSTATUS ntStatus;
|
|
|
|
DBGPRINT(2, ("enter: I82930_CancelStopRemoveDevice\n"));
|
|
|
|
LOGENTRY('CSRD', DeviceObject, Irp, 0);
|
|
|
|
DBGFBRK(DBGF_BRK_CANCELSTOPDEVICE);
|
|
|
|
deviceExtension = DeviceObject->DeviceExtension;
|
|
|
|
// Pass the IRP_MN_CANCEL_STOP/REMOVE_DEVICE Irp down the stack first.
|
|
//
|
|
ntStatus = I82930_SyncPassDownIrp(DeviceObject,
|
|
Irp,
|
|
TRUE);
|
|
if (!NT_SUCCESS(ntStatus))
|
|
{
|
|
DBGPRINT(1, ("Lower driver failed IRP_MN_CANCEL_STOP/REMOVE_DEVICE\n"));
|
|
goto I82930_CancelStopRemoveDeviceDone;
|
|
}
|
|
|
|
// All set for user requests at this point
|
|
//
|
|
deviceExtension->AcceptingRequests = TRUE;
|
|
|
|
// Enable the SymbolicLink name
|
|
//
|
|
ntStatus = IoSetDeviceInterfaceState(
|
|
&deviceExtension->SymbolicLinkName,
|
|
TRUE);
|
|
|
|
if (!NT_SUCCESS(ntStatus))
|
|
{
|
|
DBGPRINT(1, ("IoSetDeviceInterfaceState failed\n"));
|
|
Irp->IoStatus.Status = ntStatus;
|
|
goto I82930_CancelStopRemoveDeviceDone;
|
|
}
|
|
|
|
I82930_CancelStopRemoveDeviceDone:
|
|
|
|
// Must complete request since completion routine returned
|
|
// STATUS_MORE_PROCESSING_REQUIRED
|
|
//
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
|
|
DBGPRINT(2, ("exit: I82930_CancelStopRemoveDevice %08X\n", ntStatus));
|
|
|
|
LOGENTRY('csrd', ntStatus, 0, 0);
|
|
|
|
return ntStatus;
|
|
}
|
|
|
|
//******************************************************************************
|
|
//
|
|
// I82930_QueryCapabilities()
|
|
//
|
|
// This routine handles IRP_MJ_PNP, IRP_MN_QUERY_CAPABILITIES.
|
|
//
|
|
// The PnP Manager sends this IRP at IRQL PASSIVE_LEVEL in the context of a
|
|
// an arbitrary thread.
|
|
//
|
|
//******************************************************************************
|
|
|
|
NTSTATUS
|
|
I82930_QueryCapabilities (
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
)
|
|
{
|
|
PIO_STACK_LOCATION irpStack;
|
|
PDEVICE_CAPABILITIES deviceCapabilities;
|
|
NTSTATUS ntStatus;
|
|
|
|
PAGED_CODE();
|
|
|
|
DBGPRINT(2, ("enter: I82930_QueryCapabilities\n"));
|
|
|
|
LOGENTRY('FQCP', DeviceObject, Irp, 0);
|
|
|
|
irpStack = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
deviceCapabilities = irpStack->Parameters.DeviceCapabilities.Capabilities;
|
|
|
|
// Pass IRP_MN_QUERY_CAPABILITIES Irp down the stack first before we do
|
|
// anything.
|
|
//
|
|
ntStatus = I82930_SyncPassDownIrp(DeviceObject,
|
|
Irp,
|
|
TRUE);
|
|
if (!NT_SUCCESS(ntStatus))
|
|
{
|
|
DBGPRINT(1, ("Lower driver failed IRP_MN_QUERY_CAPABILITIES\n"));
|
|
}
|
|
else
|
|
{
|
|
deviceCapabilities->SurpriseRemovalOK = TRUE;
|
|
}
|
|
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
|
|
DBGPRINT(2, ("exit: I82930_QueryCapabilities %08X\n", ntStatus));
|
|
|
|
LOGENTRY('fqcp', ntStatus, 0, 0);
|
|
|
|
return ntStatus;
|
|
}
|
|
|
|
//******************************************************************************
|
|
//
|
|
// I82930_SyncPassDownIrp()
|
|
//
|
|
//******************************************************************************
|
|
|
|
NTSTATUS
|
|
I82930_SyncPassDownIrp (
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp,
|
|
IN BOOLEAN CopyToNext
|
|
)
|
|
{
|
|
PDEVICE_EXTENSION deviceExtension;
|
|
NTSTATUS ntStatus;
|
|
KEVENT localevent;
|
|
|
|
DBGPRINT(2, ("enter: I82930_SyncPassDownIrp\n"));
|
|
|
|
deviceExtension = DeviceObject->DeviceExtension;
|
|
|
|
// Initialize the event we'll wait on
|
|
//
|
|
KeInitializeEvent(&localevent,
|
|
SynchronizationEvent,
|
|
FALSE);
|
|
|
|
if (CopyToNext)
|
|
{
|
|
// Next Stack Location not set up, copy Current Stack Location
|
|
// to the Next Stack Location.
|
|
//
|
|
IoCopyCurrentIrpStackLocationToNext(Irp);
|
|
}
|
|
|
|
// Set the completion routine, which will signal the event
|
|
//
|
|
IoSetCompletionRoutine(Irp,
|
|
I82930_SyncCompletionRoutine,
|
|
&localevent,
|
|
TRUE, // InvokeOnSuccess
|
|
TRUE, // InvokeOnError
|
|
TRUE); // InvokeOnCancel
|
|
|
|
// Pass the Irp down the stack
|
|
//
|
|
ntStatus = IoCallDriver(deviceExtension->StackDeviceObject,
|
|
Irp);
|
|
|
|
// If the request is pending, block until it completes
|
|
//
|
|
if (ntStatus == STATUS_PENDING)
|
|
{
|
|
KeWaitForSingleObject(&localevent,
|
|
Executive,
|
|
KernelMode,
|
|
FALSE,
|
|
NULL);
|
|
|
|
ntStatus = Irp->IoStatus.Status;
|
|
}
|
|
|
|
DBGPRINT(2, ("exit: I82930_SyncPassDownIrp %08X\n", ntStatus));
|
|
|
|
return ntStatus;
|
|
}
|
|
|
|
//******************************************************************************
|
|
//
|
|
// I82930_SyncCompletionRoutine()
|
|
//
|
|
// Completion routine used by I82930_SyncPassDownIrp and
|
|
// I82930_SyncSendUsbRequest
|
|
//
|
|
// If the Irp is one we allocated ourself, DeviceObject is NULL unless we
|
|
// allocated a stack location for ourself and initialized the DeviceObject
|
|
// pointer in our stack location.
|
|
//
|
|
//******************************************************************************
|
|
|
|
NTSTATUS
|
|
I82930_SyncCompletionRoutine (
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp,
|
|
IN PVOID Context
|
|
)
|
|
{
|
|
PKEVENT kevent;
|
|
|
|
LOGENTRY('SCR ', DeviceObject, Irp, Irp->IoStatus.Status);
|
|
|
|
kevent = (PKEVENT)Context;
|
|
|
|
KeSetEvent(kevent,
|
|
IO_NO_INCREMENT,
|
|
FALSE);
|
|
|
|
return STATUS_MORE_PROCESSING_REQUIRED;
|
|
}
|
|
|
|
//******************************************************************************
|
|
//
|
|
// I82930_SyncSendUsbRequest()
|
|
//
|
|
// Must be called at IRQL <= DISPATCH_LEVEL
|
|
//
|
|
//******************************************************************************
|
|
|
|
NTSTATUS
|
|
I82930_SyncSendUsbRequest (
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PURB Urb
|
|
)
|
|
{
|
|
PDEVICE_EXTENSION deviceExtension;
|
|
KEVENT localevent;
|
|
PIRP irp;
|
|
PIO_STACK_LOCATION nextStack;
|
|
NTSTATUS ntStatus;
|
|
|
|
DBGPRINT(3, ("enter: I82930_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('SSUR', DeviceObject, irp, Urb);
|
|
|
|
if (irp == NULL)
|
|
{
|
|
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,
|
|
I82930_SyncCompletionRoutine,
|
|
&localevent,
|
|
TRUE, // InvokeOnSuccess
|
|
TRUE, // InvokeOnError
|
|
TRUE); // InvokeOnCancel
|
|
|
|
|
|
|
|
// Pass the Irp & Urb down the stack
|
|
//
|
|
ntStatus = IoCallDriver(deviceExtension->StackDeviceObject,
|
|
irp);
|
|
|
|
// If the request is pending, block until it completes
|
|
//
|
|
if (ntStatus == STATUS_PENDING)
|
|
{
|
|
LARGE_INTEGER timeout;
|
|
|
|
// Specify a timeout of 5 seconds to wait for this call to complete.
|
|
//
|
|
timeout.QuadPart = -10000 * 5000;
|
|
|
|
ntStatus = KeWaitForSingleObject(&localevent,
|
|
Executive,
|
|
KernelMode,
|
|
FALSE,
|
|
&timeout);
|
|
|
|
if (ntStatus == STATUS_TIMEOUT)
|
|
{
|
|
ntStatus = STATUS_IO_TIMEOUT;
|
|
|
|
// Cancel the Irp we just sent.
|
|
//
|
|
IoCancelIrp(irp);
|
|
|
|
// And wait until the cancel completes
|
|
//
|
|
KeWaitForSingleObject(&localevent,
|
|
Executive,
|
|
KernelMode,
|
|
FALSE,
|
|
NULL);
|
|
}
|
|
else
|
|
{
|
|
ntStatus = irp->IoStatus.Status;
|
|
}
|
|
}
|
|
|
|
// Done with the Irp, now free it.
|
|
//
|
|
IoFreeIrp(irp);
|
|
|
|
LOGENTRY('ssur', ntStatus, Urb, Urb->UrbHeader.Status);
|
|
|
|
DBGPRINT(3, ("exit: I82930_SyncSendUsbRequest %08X\n", ntStatus));
|
|
|
|
return ntStatus;
|
|
}
|
|
|
|
//******************************************************************************
|
|
//
|
|
// I82930_GetDescriptor()
|
|
//
|
|
// Must be called at IRQL <= DISPATCH_LEVEL
|
|
//
|
|
//******************************************************************************
|
|
|
|
NTSTATUS
|
|
I82930_GetDescriptor (
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN UCHAR Recipient,
|
|
IN UCHAR DescriptorType,
|
|
IN UCHAR Index,
|
|
IN USHORT LanguageId,
|
|
IN ULONG RetryCount,
|
|
IN ULONG DescriptorLength,
|
|
OUT PUCHAR *Descriptor
|
|
)
|
|
{
|
|
USHORT function;
|
|
PURB urb;
|
|
NTSTATUS ntStatus;
|
|
|
|
DBGPRINT(2, ("enter: I82930_GetDescriptor\n"));
|
|
|
|
// Set the URB function based on Recipient {Device, Interface, Endpoint}
|
|
//
|
|
switch (Recipient)
|
|
{
|
|
case USB_RECIPIENT_DEVICE:
|
|
function = URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE;
|
|
break;
|
|
case USB_RECIPIENT_INTERFACE:
|
|
function = URB_FUNCTION_GET_DESCRIPTOR_FROM_INTERFACE;
|
|
break;
|
|
case USB_RECIPIENT_ENDPOINT:
|
|
function = URB_FUNCTION_GET_DESCRIPTOR_FROM_ENDPOINT;
|
|
break;
|
|
default:
|
|
*Descriptor = NULL;
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
// Allocate a descriptor buffer
|
|
//
|
|
*Descriptor = ExAllocatePoolWithTag(NonPagedPool,
|
|
DescriptorLength,
|
|
POOL_TAG);
|
|
|
|
if (*Descriptor != NULL)
|
|
{
|
|
// Allocate a URB for the Get Descriptor request
|
|
//
|
|
urb = ExAllocatePoolWithTag(NonPagedPool,
|
|
sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST),
|
|
POOL_TAG);
|
|
|
|
if (urb != NULL)
|
|
{
|
|
do
|
|
{
|
|
// Initialize the URB
|
|
//
|
|
urb->UrbHeader.Function = function;
|
|
urb->UrbHeader.Length = sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST);
|
|
urb->UrbControlDescriptorRequest.TransferBufferLength = DescriptorLength;
|
|
urb->UrbControlDescriptorRequest.TransferBuffer = *Descriptor;
|
|
urb->UrbControlDescriptorRequest.TransferBufferMDL = NULL;
|
|
urb->UrbControlDescriptorRequest.UrbLink = NULL;
|
|
urb->UrbControlDescriptorRequest.DescriptorType = DescriptorType;
|
|
urb->UrbControlDescriptorRequest.Index = Index;
|
|
urb->UrbControlDescriptorRequest.LanguageId = LanguageId;
|
|
|
|
// Send the URB down the stack
|
|
//
|
|
ntStatus = I82930_SyncSendUsbRequest(DeviceObject,
|
|
urb);
|
|
|
|
if (NT_SUCCESS(ntStatus))
|
|
{
|
|
// No error, make sure the length and type are correct
|
|
//
|
|
if ((DescriptorLength ==
|
|
urb->UrbControlDescriptorRequest.TransferBufferLength) &&
|
|
(DescriptorType ==
|
|
((PUSB_COMMON_DESCRIPTOR)*Descriptor)->bDescriptorType))
|
|
{
|
|
// The length and type are correct, all done
|
|
//
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
// No error, but the length or type is incorrect
|
|
//
|
|
ntStatus = STATUS_DEVICE_DATA_ERROR;
|
|
}
|
|
}
|
|
|
|
} while (RetryCount-- > 0);
|
|
|
|
ExFreePool(urb);
|
|
}
|
|
else
|
|
{
|
|
// Failed to allocate the URB
|
|
//
|
|
ExFreePool(*Descriptor);
|
|
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Failed to allocate the descriptor buffer
|
|
//
|
|
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
if (!NT_SUCCESS(ntStatus))
|
|
{
|
|
*Descriptor = NULL;
|
|
}
|
|
|
|
DBGPRINT(2, ("exit: I82930_GetDescriptor %08X\n", ntStatus));
|
|
|
|
return ntStatus;
|
|
}
|
|
|
|
//******************************************************************************
|
|
//
|
|
// I82930_SelectConfiguration()
|
|
//
|
|
// Must be called at IRQL <= DISPATCH_LEVEL
|
|
//
|
|
//******************************************************************************
|
|
|
|
NTSTATUS
|
|
I82930_SelectConfiguration (
|
|
IN PDEVICE_OBJECT DeviceObject
|
|
)
|
|
{
|
|
NTSTATUS ntStatus;
|
|
PURB urb;
|
|
ULONG i;
|
|
PDEVICE_EXTENSION deviceExtension;
|
|
PUSB_CONFIGURATION_DESCRIPTOR configurationDescriptor;
|
|
PUSBD_INTERFACE_LIST_ENTRY interfaceList;
|
|
PUSB_INTERFACE_DESCRIPTOR interfaceDescriptor;
|
|
PUSBD_INTERFACE_INFORMATION interfaceInfo;
|
|
|
|
DBGPRINT(2, ("enter: I82930_SelectConfiguration\n"));
|
|
|
|
LOGENTRY('SCON', DeviceObject, 0, 0);
|
|
|
|
deviceExtension = DeviceObject->DeviceExtension;
|
|
configurationDescriptor = deviceExtension->ConfigurationDescriptor;
|
|
|
|
|
|
// Allocate storage for an Inteface List to use as an input/output
|
|
// parameter to USBD_CreateConfigurationRequestEx().
|
|
//
|
|
interfaceList = ExAllocatePool(
|
|
PagedPool,
|
|
sizeof(USBD_INTERFACE_LIST_ENTRY) * 2
|
|
);
|
|
|
|
if (interfaceList)
|
|
{
|
|
// Parse the ConfigurationDescriptor (including all Interface and
|
|
// Endpoint Descriptors) and locate a Interface Descriptor which
|
|
// matches the InterfaceNumber, AlternateSetting, InterfaceClass,
|
|
// InterfaceSubClass, and InterfaceProtocol parameters. In our case
|
|
// we just grab the first Interface Descriptor from the Configuration
|
|
// Descriptor.
|
|
//
|
|
interfaceDescriptor = USBD_ParseConfigurationDescriptorEx(
|
|
configurationDescriptor,
|
|
configurationDescriptor,
|
|
-1, // InterfaceNumber, don't care
|
|
-1, // AlternateSetting, don't care
|
|
-1, // InterfaceClass, don't care
|
|
-1, // InterfaceSubClass, don't care
|
|
-1 // InterfaceProtocol, don't care
|
|
);
|
|
|
|
if (interfaceDescriptor)
|
|
{
|
|
// Add the single Interface Descriptor we care about to the
|
|
// interface list, then terminate the list.
|
|
//
|
|
interfaceList[0].InterfaceDescriptor = interfaceDescriptor;
|
|
interfaceList[1].InterfaceDescriptor = NULL;
|
|
|
|
// Create a SELECT_CONFIGURATION URB, turning the Interface
|
|
// Descriptors in the interfaceList into USBD_INTERFACE_INFORMATION
|
|
// structures in the URB.
|
|
//
|
|
urb = USBD_CreateConfigurationRequestEx(
|
|
configurationDescriptor,
|
|
interfaceList
|
|
);
|
|
|
|
if (urb)
|
|
{
|
|
interfaceInfo = &urb->UrbSelectConfiguration.Interface;
|
|
|
|
// Override the USBD_DEFAULT_MAXIMUM_TRANSFER_SIZE
|
|
// for all pipes.
|
|
//
|
|
for (i = 0; i < interfaceInfo->NumberOfPipes; i++)
|
|
{
|
|
interfaceInfo->Pipes[i].MaximumTransferSize = 0x10000;
|
|
}
|
|
|
|
// Now issue the USB request to set the Configuration
|
|
//
|
|
ntStatus = I82930_SyncSendUsbRequest(DeviceObject,
|
|
urb);
|
|
|
|
if (NT_SUCCESS(ntStatus))
|
|
{
|
|
// Save the configuration handle for this device in
|
|
// the Device Extension.
|
|
//
|
|
deviceExtension->ConfigurationHandle =
|
|
urb->UrbSelectConfiguration.ConfigurationHandle;
|
|
|
|
// Save a copy of the interface information returned
|
|
// by the SELECT_CONFIGURATION request in the Device
|
|
// Extension. This gives us a list of PIPE_INFORMATION
|
|
// structures for each pipe opened in this configuration.
|
|
//
|
|
ASSERT(deviceExtension->InterfaceInfo == NULL);
|
|
|
|
deviceExtension->InterfaceInfo = ExAllocatePool(
|
|
PagedPool,
|
|
interfaceInfo->Length
|
|
);
|
|
|
|
if (deviceExtension->InterfaceInfo)
|
|
{
|
|
ULONG pipeIndex;
|
|
ULONG numPipes;
|
|
|
|
RtlCopyMemory(
|
|
deviceExtension->InterfaceInfo,
|
|
interfaceInfo,
|
|
interfaceInfo->Length
|
|
);
|
|
|
|
// Initialize the PipeList array pointers back into the
|
|
// InterfaceInfo.
|
|
//
|
|
numPipes = deviceExtension->InterfaceInfo->NumberOfPipes;
|
|
|
|
for (pipeIndex = 0; pipeIndex < numPipes; pipeIndex++)
|
|
{
|
|
deviceExtension->PipeList[pipeIndex].PipeIndex =
|
|
(UCHAR)pipeIndex;
|
|
|
|
deviceExtension->PipeList[pipeIndex].PipeInfo =
|
|
&deviceExtension->InterfaceInfo->Pipes[pipeIndex];
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Could not allocate a copy of interface information
|
|
//
|
|
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
}
|
|
|
|
// Done with the URB
|
|
//
|
|
ExFreePool(urb);
|
|
}
|
|
else
|
|
{
|
|
// Could not allocate urb
|
|
//
|
|
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Did not parse an Interface Descriptor out of the Configuration
|
|
// Descriptor, the Configuration Descriptor must be bad.
|
|
//
|
|
ntStatus = STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
// Done with the interface list
|
|
//
|
|
ExFreePool(interfaceList);
|
|
}
|
|
else
|
|
{
|
|
// Could not allocate Interface List
|
|
//
|
|
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
DBGPRINT(2, ("exit: I82930_SelectConfiguration %08X\n", ntStatus));
|
|
|
|
LOGENTRY('scon', ntStatus, 0, 0);
|
|
|
|
return ntStatus;
|
|
}
|
|
|
|
//******************************************************************************
|
|
//
|
|
// I82930_UnConfigure()
|
|
//
|
|
// Must be called at IRQL <= DISPATCH_LEVEL
|
|
//
|
|
//******************************************************************************
|
|
|
|
NTSTATUS
|
|
I82930_UnConfigure (
|
|
IN PDEVICE_OBJECT DeviceObject
|
|
)
|
|
{
|
|
PDEVICE_EXTENSION deviceExtension;
|
|
NTSTATUS ntStatus;
|
|
PURB urb;
|
|
ULONG ulSize;
|
|
|
|
DBGPRINT(2, ("enter: I82930_UnConfigure\n"));
|
|
|
|
LOGENTRY('UCON', DeviceObject, 0, 0);
|
|
|
|
deviceExtension = DeviceObject->DeviceExtension;
|
|
|
|
// Allocate a URB for the SELECT_CONFIGURATION request. As we are
|
|
// unconfiguring the device, the request needs no pipe and interface
|
|
// information structures.
|
|
//
|
|
ulSize = sizeof(struct _URB_SELECT_CONFIGURATION) -
|
|
sizeof(USBD_INTERFACE_INFORMATION);
|
|
|
|
urb = ExAllocatePool(
|
|
NonPagedPool,
|
|
ulSize
|
|
);
|
|
|
|
if (urb)
|
|
{
|
|
// Initialize the URB. A NULL Configuration Descriptor indicates
|
|
// that the device should be unconfigured.
|
|
//
|
|
UsbBuildSelectConfigurationRequest(
|
|
urb,
|
|
(USHORT)ulSize,
|
|
NULL
|
|
);
|
|
|
|
// Now issue the USB request to set the Configuration
|
|
//
|
|
ntStatus = I82930_SyncSendUsbRequest(DeviceObject,
|
|
urb);
|
|
|
|
// Done with the URB now.
|
|
//
|
|
ExFreePool(urb);
|
|
|
|
// The device is no longer configured.
|
|
//
|
|
deviceExtension->ConfigurationHandle = 0;
|
|
|
|
if (deviceExtension->InterfaceInfo != NULL)
|
|
{
|
|
ExFreePool(deviceExtension->InterfaceInfo);
|
|
|
|
deviceExtension->InterfaceInfo = NULL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Could not allocate the URB.
|
|
//
|
|
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
DBGPRINT(2, ("exit: I82930_UnConfigure %08X\n", ntStatus));
|
|
|
|
LOGENTRY('ucon', ntStatus, 0, 0);
|
|
|
|
return ntStatus;
|
|
}
|
|
|
|
//******************************************************************************
|
|
//
|
|
// I82930_SelectAlternateInterface()
|
|
//
|
|
// Must be called at IRQL <= DISPATCH_LEVEL
|
|
//
|
|
//******************************************************************************
|
|
|
|
NTSTATUS
|
|
I82930_SelectAlternateInterface (
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN UCHAR AlternateSetting
|
|
)
|
|
{
|
|
NTSTATUS ntStatus;
|
|
USHORT urbSize;
|
|
PURB urb;
|
|
ULONG i;
|
|
PDEVICE_EXTENSION deviceExtension;
|
|
PUSB_CONFIGURATION_DESCRIPTOR configurationDescriptor;
|
|
PUSB_INTERFACE_DESCRIPTOR interfaceDescriptor;
|
|
PUSBD_INTERFACE_INFORMATION interfaceInfo;
|
|
|
|
DBGPRINT(2, ("enter: I82930_SelectAlternateInterface\n"));
|
|
|
|
LOGENTRY('SALT', DeviceObject, 0, 0);
|
|
|
|
deviceExtension = DeviceObject->DeviceExtension;
|
|
configurationDescriptor = deviceExtension->ConfigurationDescriptor;
|
|
|
|
interfaceDescriptor = USBD_ParseConfigurationDescriptorEx(
|
|
configurationDescriptor,
|
|
configurationDescriptor,
|
|
-1, // InterfaceNumber, don't care
|
|
AlternateSetting,
|
|
-1, // InterfaceClass, don't care
|
|
-1, // InterfaceSubClass, don't care
|
|
-1 // InterfaceProtocol, don't care
|
|
);
|
|
|
|
if (interfaceDescriptor != NULL)
|
|
{
|
|
urbSize = GET_SELECT_INTERFACE_REQUEST_SIZE(interfaceDescriptor->bNumEndpoints);
|
|
|
|
urb = ExAllocatePoolWithTag(NonPagedPool,
|
|
urbSize,
|
|
POOL_TAG);
|
|
|
|
if (urb != NULL)
|
|
{
|
|
RtlZeroMemory(urb, urbSize);
|
|
|
|
urb->UrbHeader.Length = urbSize;
|
|
|
|
urb->UrbHeader.Function = URB_FUNCTION_SELECT_INTERFACE;
|
|
|
|
urb->UrbSelectInterface.ConfigurationHandle =
|
|
deviceExtension->ConfigurationHandle;
|
|
|
|
interfaceInfo = &urb->UrbSelectInterface.Interface;
|
|
|
|
interfaceInfo->Length = GET_USBD_INTERFACE_SIZE(interfaceDescriptor->bNumEndpoints);
|
|
|
|
interfaceInfo->InterfaceNumber = interfaceDescriptor->bInterfaceNumber;
|
|
|
|
interfaceInfo->AlternateSetting = AlternateSetting;
|
|
|
|
for (i = 0; i < interfaceDescriptor->bNumEndpoints; i++)
|
|
{
|
|
interfaceInfo->Pipes[i].MaximumTransferSize = 0x10000;
|
|
}
|
|
|
|
// Now issue the USB request to select the alternate interface
|
|
//
|
|
ntStatus = I82930_SyncSendUsbRequest(DeviceObject,
|
|
urb);
|
|
|
|
if (NT_SUCCESS(ntStatus))
|
|
{
|
|
if (deviceExtension->InterfaceInfo != NULL)
|
|
{
|
|
ExFreePool(deviceExtension->InterfaceInfo);
|
|
|
|
deviceExtension->InterfaceInfo = NULL;
|
|
}
|
|
|
|
// Save a copy of the interface information returned
|
|
// by the SELECT_INTERFACE request in the Device
|
|
// Extension. This gives us a list of PIPE_INFORMATION
|
|
// structures for each pipe opened in this configuration.
|
|
//
|
|
deviceExtension->InterfaceInfo = ExAllocatePool(
|
|
PagedPool,
|
|
interfaceInfo->Length
|
|
);
|
|
|
|
if (deviceExtension->InterfaceInfo)
|
|
{
|
|
ULONG pipeIndex;
|
|
ULONG numPipes;
|
|
|
|
RtlCopyMemory(deviceExtension->InterfaceInfo,
|
|
interfaceInfo,
|
|
interfaceInfo->Length
|
|
);
|
|
|
|
// Initialize the PipeList array pointers back into the
|
|
// InterfaceInfo.
|
|
//
|
|
numPipes = deviceExtension->InterfaceInfo->NumberOfPipes;
|
|
|
|
for (pipeIndex = 0; pipeIndex < numPipes; pipeIndex++)
|
|
{
|
|
deviceExtension->PipeList[pipeIndex].PipeIndex =
|
|
(UCHAR)pipeIndex;
|
|
|
|
deviceExtension->PipeList[pipeIndex].PipeInfo =
|
|
&deviceExtension->InterfaceInfo->Pipes[pipeIndex];
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Could not allocate a copy of interface information
|
|
//
|
|
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
}
|
|
|
|
// Done with the URB
|
|
//
|
|
ExFreePool(urb);
|
|
}
|
|
else
|
|
{
|
|
// Could not allocate urb
|
|
//
|
|
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Bad AlternateSetting
|
|
//
|
|
ntStatus = STATUS_INVALID_PARAMETER;
|
|
|
|
}
|
|
|
|
DBGPRINT(2, ("exit: I82930_SelectAlternateInterface %08X\n", ntStatus));
|
|
|
|
LOGENTRY('salt', ntStatus, 0, 0);
|
|
|
|
return ntStatus;
|
|
}
|