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