|
|
/*++
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; }
|