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