windows-nt/Source/XPSP1/NT/drivers/wdm/usb/driver/usbdiag/usbdiag.c
2020-09-26 16:20:57 +08:00

2529 lines
72 KiB
C

/*++
Copyright (c) 1996 Microsoft Corporation
Module Name:
usbdiag.c
Abstract:
USB device driver for Intel/Microsoft USB diagnostic apps
Environment:
kernel mode only
Notes:
THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
PURPOSE.
Copyright (c) 1996 Microsoft Corporation. All Rights Reserved.
Revision History:
5-4-96 : created
7-21-97 : Todd Carpenter adds Chap11 IOCTL's
--*/
#define DRIVER
#include "wdm.h"
#include "stdarg.h"
#include "stdio.h"
#pragma pack (push,1)
#include "usb100.h"
#include "usbdi.h"
#include "usbdlib.h"
#include "usbioctl.h"
#pragma pack (pop) //disable 1-byte alignment
#include "opaque.h"
#pragma pack (push,1)
#include "ioctl.h"
#include "chap9drv.h"
#include "USBDIAG.h"
#pragma pack (pop) //disable 1-byte alignment
PDEVICE_OBJECT USBDIAG_GlobalDeviceObject = NULL;
ULONG USBDIAG_NextDeviceNumber = 0;
ULONG USBDIAG_NumberDevices = 0;
ULONG gulMemoryAllocated = 0;
USBD_VERSION_INFORMATION gVersionInformation;
/* UCHAR *SystemPowerStateString[] = {
"PowerSystemUnspecified",
"PowerSystemWorking",
"PowerSystemSleeping1",
"PowerSystemSleeping2",
"PowerSystemSleeping3",
"PowerSystemHibernate",
"PowerSystemShutdown",
"PowerSystemMaximum"
};
UCHAR *DevicePowerStateString[] = {
"PowerDeviceUnspecified",
"PowerDeviceD0",
"PowerDeviceD1",
"PowerDeviceD2",
"PowerDeviceD3",
"PowerDeviceMaximum"
}; */
//
// Global pointer to Driver Object
//
PDRIVER_OBJECT USBDIAG_DriverObject;
#define REMOTE_WAKEUP 0x20
#ifdef PAGE_CODE
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, USBD_SubmitSynchronousURB)
#pragma alloc_text(PAGE, USBD_CloseEndpoint)
#endif
#endif
NTSTATUS
DriverEntry(
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath
)
/*++
Routine Description:
Installable driver initialization entry point.
This entry point is called directly by the I/O system.
Arguments:
DriverObject - pointer to the driver object
RegistryPath - pointer to a unicode string representing the path
to driver-specific key in the registry
Return Value:
STATUS_SUCCESS if successful,
STATUS_UNSUCCESSFUL otherwise
--*/
{
NTSTATUS ntStatus = STATUS_SUCCESS;
//PDEVICE_OBJECT deviceObject = NULL;
DbgPrint("USBDIAG.SYS: entering (USBDIAG) DriverEntry\n");
DbgPrint("USBDIAG.SYS: USBDIAG Driver Build Date/Time: %s %s\n",
__DATE__, __TIME__);
USBDIAG_DriverObject = DriverObject;
//
// Create dispatch points for device control, create, close.
//
DriverObject->MajorFunction[IRP_MJ_PNP] = USBDIAG_PnP;
DriverObject->MajorFunction[IRP_MJ_POWER] = USBDIAG_Power;
DriverObject->MajorFunction[IRP_MJ_CREATE] =
DriverObject->MajorFunction[IRP_MJ_CLOSE] = USBDIAG_Dispatch;
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = USBDIAG_ProcessIOCTL;
DriverObject->MajorFunction[IRP_MJ_WRITE] = NULL;
DriverObject->MajorFunction[IRP_MJ_READ] = NULL;
DriverObject->DriverUnload = USBDIAG_Unload;
DriverObject->DriverExtension->AddDevice = USBDIAG_PnPAddDevice;
DbgPrint ("'USBDIAG.SYS: exiting (USBDIAG) DriverEntry (%x)\n", ntStatus);
// determine the os version and store in a global.
USBD_GetUSBDIVersion(&gVersionInformation);
return ntStatus;
}
NTSTATUS
USBDIAG_Dispatch(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
/*++
Routine Description:
Process the IRPs sent to this device.
Arguments:
DeviceObject - pointer to a device object
Irp - pointer to an I/O Request Packet
Return Value:
--*/
{
PIO_STACK_LOCATION irpStack;
NTSTATUS ntStatus;
PDEVICE_EXTENSION globalDeviceExtension;
//USBDIAG_KdPrint(("USBDIAG.SYS: enter USBDIAG_Dispatch\n"));
//
// Default return status unless overridden later
//
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = 0;
//
// Get a pointer to the current location in the Irp. This is where
// the function codes and parameters are located.
//
irpStack = IoGetCurrentIrpStackLocation (Irp);
switch (irpStack->MajorFunction) {
case IRP_MJ_CREATE:
//USBDIAG_KdPrint(("USBDIAG.SYS: IRP_MJ_CREATE\n"));
ASSERT(USBDIAG_GlobalDeviceObject != NULL);
globalDeviceExtension = USBDIAG_GlobalDeviceObject->DeviceExtension;
globalDeviceExtension->OpenFRC++;
break;
case IRP_MJ_CLOSE:
//USBDIAG_KdPrint(("USBDIAG.SYS: IRP_MJ_CLOSE\n"));
ASSERT(USBDIAG_GlobalDeviceObject != NULL);
globalDeviceExtension = USBDIAG_GlobalDeviceObject->DeviceExtension;
globalDeviceExtension->OpenFRC--;
break;
default:
Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
break;
} /* case MajorFunction */
ntStatus = Irp->IoStatus.Status;
IoCompleteRequest (Irp, IO_NO_INCREMENT);
//USBDIAG_KdPrint(("USBDIAG.SYS: Exit USBDIAG_Dispatch %x\n", ntStatus));
return ntStatus;
}
NTSTATUS
USBDIAG_PnP(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
/*++
Routine Description:
Process the PnP IRPs sent to this device.
Arguments:
DeviceObject - pointer to a device object
Irp - pointer to an I/O Request Packet
Return Value:
--*/
{
NTSTATUS ntStatus;
PIO_STACK_LOCATION irpStack;
PDEVICE_EXTENSION deviceExtension;
PDEVICE_EXTENSION globalDeviceExtension;
PDEVICE_LIST_ENTRY device, foundDevice;
BOOLEAN passDownIrp;
//USBDIAG_KdPrint(("USBDIAG.SYS: enter USBDIAG_PnP\n"));
//
// Default to passing down all Irps unless overridden later.
//
passDownIrp = TRUE;
//
// Get a pointer to the current location in the Irp. This is where
// the function codes and parameters are located.
//
irpStack = IoGetCurrentIrpStackLocation (Irp);
//
// Get a pointer to the device extension
//
deviceExtension = DeviceObject->DeviceExtension;
ASSERT (deviceExtension != NULL);
//
// Get a pointer to the global device extension
//
globalDeviceExtension = USBDIAG_GlobalDeviceObject->DeviceExtension;
//
// Switch on the PnP minor function
//
switch (irpStack->MinorFunction) {
case IRP_MN_START_DEVICE:
//USBDIAG_KdPrint(("USBDIAG.SYS: IRP_MN_START_DEVICE\n"));
ntStatus = USBDIAG_PassDownIrp(DeviceObject, Irp);
USBDIAG_KdPrint (("Back from passing down IRP_MN_START_DEVICE; status: %#X\n",
ntStatus));
if (NT_SUCCESS(ntStatus))
{
// Now we can begin our configuration actions on the device
//
ntStatus = USBDIAG_StartDevice(DeviceObject);
}
passDownIrp = FALSE;
break;
case IRP_MN_QUERY_CAPABILITIES: // 0x09
USBDIAG_KdPrint (("*********************************\n"));
USBDIAG_KdPrint (("IRP_MN_QUERY_CAPABILITIES\n"));
passDownIrp = FALSE;
IoCopyCurrentIrpStackLocationToNext(Irp);
IoSetCompletionRoutine(Irp,
USBDIAG_QueryCapabilitiesCompletionRoutine,
DeviceObject,
TRUE,
TRUE,
TRUE);
ntStatus = IoCallDriver(deviceExtension->StackDeviceObject, Irp);
break;
case IRP_MN_STOP_DEVICE:
//USBDIAG_KdPrint(("USBDIAG.SYS: IRP_MN_STOP_DEVICE\n"));
ntStatus = USBDIAG_StopDevice(DeviceObject);
break;
case IRP_MN_REMOVE_DEVICE:
{
int i = 1;
//USBDIAG_KdPrint(("USBDIAG.SYS: IRP_MN_REMOVE_DEVICE\n"));
ntStatus = USBDIAG_StopDevice(DeviceObject);
// remove all downstream devices
for (i = 1; i <= MAX_DOWNSTREAM_DEVICES; i++)
{
if (deviceExtension->DeviceData[i])
{
USBDIAG_KdPrint(("IRP_MN_REMOVE_DEVICE: Removing device on downstream port %d\n", i));
USBDIAG_RemoveDownstreamDevice(deviceExtension->DeviceData[i],
deviceExtension->StackDeviceObject);
}
}
USBDIAG_KdPrint(("Done removing downstream devices\n"));
//
// Remove this device object from our list
//
device = globalDeviceExtension->DeviceList;
USBDIAG_KdPrint(("USBDIAG.SYS: IRP_MN_REMOVE_DEVICE devobj = %x dev = %x\n",
DeviceObject, device));
ASSERT(device != NULL);
if (device->DeviceObject == DeviceObject) {
//
// DeviceObject is the first one on the list. Delete from the
// list by setting the head of the list to point to the next
// one on the list.
//
globalDeviceExtension->DeviceList = device->Next;
USBDIAG_ExFreePool(device);
} else {
//
// DeviceObject is not the first one on the list. Walk the
// list and find it.
//
while (device->Next) {
if (device->Next->DeviceObject == DeviceObject) {
//
// DeviceObject is the next one on the list, remember
// the next one and delete it by setting the next one
// to the next next one.
//
foundDevice = device->Next;
device->Next = foundDevice->Next;
USBDIAG_ExFreePool(foundDevice);
break;
}
device = device->Next;
}
}
//USBDIAG_KdPrint(("USBDIAG.SYS: Detaching stack device object...%X\n",
//deviceExtension->StackDeviceObject));
IoDetachDevice(deviceExtension->StackDeviceObject);
//
// Pass the REMOVE_DEVICE Irp down now after detaching and
// removing the device instead of later.
//
passDownIrp = FALSE;
IoSkipCurrentIrpStackLocation (Irp);
ntStatus = IoCallDriver(deviceExtension->StackDeviceObject, Irp);
//USBDIAG_KdPrint(("USBDIAG.SYS: Deleting device object...%X\n", DeviceObject));
IoDeleteDevice(DeviceObject);
USBDIAG_NumberDevices--;
//
// Free the GlobalDeviceObject if this was the last real
// DeviceObject. XXXXX Take a careful look at what the
// hell this routine is all about.
//
USBDIAG_RemoveGlobalDeviceObject();
}
break;
default:
//USBDIAG_KdPrint(("USBDIAG.SYS: PnP IOCTL not handled: (%#X)\n",
//irpStack->MinorFunction));
break;
}
if (passDownIrp)
{
//
// Pass the PnP Irp down the stack
//
IoSkipCurrentIrpStackLocation (Irp);
ntStatus = IoCallDriver(deviceExtension->StackDeviceObject,
Irp);
}
//USBDIAG_KdPrint(("USBDIAG.SYS: Exit USBDIAG_PnP %x\n", ntStatus));
return ntStatus;
}
NTSTATUS
USBDIAG_PassDownIrp (
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
{
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
KEVENT localevent;
NTSTATUS ntStatus;
PAGED_CODE();
// 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,
USBDIAG_GenericCompletionRoutine,
&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;
}
return ntStatus;
}
NTSTATUS
USBDIAG_GenericCompletionRoutine(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Context
)
{
PKEVENT kevent;
kevent = (PKEVENT)Context;
KeSetEvent(kevent, IO_NO_INCREMENT,FALSE);
return STATUS_MORE_PROCESSING_REQUIRED;
}
VOID
USBDIAG_Unload(
IN PDRIVER_OBJECT DriverObject
)
/*++
Routine Description:
Free all the allocated resources, etc.
Arguments:
DriverObject - pointer to a driver object
Return Value:
--*/
{
DbgPrint ("USBDIAG.SYS: enter USBDIAG_Unload\n");
//
// Free any global resources allocated
// in DriverEntry
//
// free the global deviceobject here
USBDIAG_RemoveGlobalDeviceObject();
DbgPrint ("USBDIAG.SYS: exit USBDIAG_Unload\n");
}
NTSTATUS
USBDIAG_StartDevice(
IN PDEVICE_OBJECT DeviceObject
)
/*++
Routine Description:
Initializes a given instance of the device on the USB.
Arguments:
DeviceObject - pointer to the device object for this instance of a
UTB
Return Value:
NT status code
--*/
{
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
NTSTATUS ntStatus;
PUSB_DEVICE_DESCRIPTOR deviceDescriptor = NULL;
PURB urb;
ULONG siz;
//USBDIAG_KdPrint(("USBDIAG.SYS: enter USBDIAG_StartDevice\n"));
//
// Fetch the device descriptor for the device
//
urb = USBDIAG_ExAllocatePool(NonPagedPool,
sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST));
if (urb)
{
siz = sizeof(USB_DEVICE_DESCRIPTOR);
deviceDescriptor = USBDIAG_ExAllocatePool(NonPagedPool, siz);
if (deviceDescriptor)
{
UsbBuildGetDescriptorRequest(urb,
(USHORT) sizeof (struct _URB_CONTROL_DESCRIPTOR_REQUEST),
USB_DEVICE_DESCRIPTOR_TYPE,
0,
0,
deviceDescriptor,
NULL,
siz,
NULL);
ntStatus = USBDIAG_CallUSBD(DeviceObject, urb);
if (NT_SUCCESS(ntStatus))
{
//USBDIAG_KdPrint(("USBDIAG.SYS: Device Descriptor = %x, len %x\n",
//deviceDescriptor,
//urb->UrbControlDescriptorRequest.TransferBufferLength));
//USBDIAG_KdPrint(("USBDIAG.SYS: USB Device Descriptor:\n"));
//USBDIAG_KdPrint(("USBDIAG.SYS: -------------------------\n"));
//USBDIAG_KdPrint(("USBDIAG.SYS: bLength %d\n", deviceDescriptor->bLength));
//USBDIAG_KdPrint(("USBDIAG.SYS: bDescriptorType 0x%x\n", deviceDescriptor->bDescriptorType));
//USBDIAG_KdPrint(("USBDIAG.SYS: bcdUSB 0x%x\n", deviceDescriptor->bcdUSB));
//USBDIAG_KdPrint(("USBDIAG.SYS: bDeviceClass 0x%x\n", deviceDescriptor->bDeviceClass));
//USBDIAG_KdPrint(("USBDIAG.SYS: bDeviceSubClass 0x%x\n", deviceDescriptor->bDeviceSubClass));
//USBDIAG_KdPrint(("USBDIAG.SYS: bDeviceProtocol 0x%x\n", deviceDescriptor->bDeviceProtocol));
//USBDIAG_KdPrint(("USBDIAG.SYS: bMaxPacketSize0 0x%x\n", deviceDescriptor->bMaxPacketSize0));
//USBDIAG_KdPrint(("USBDIAG.SYS: idVendor 0x%x\n", deviceDescriptor->idVendor));
//USBDIAG_KdPrint(("USBDIAG.SYS: idProduct 0x%x\n", deviceDescriptor->idProduct));
//USBDIAG_KdPrint(("USBDIAG.SYS: bcdDevice 0x%x\n", deviceDescriptor->bcdDevice));
//USBDIAG_KdPrint(("USBDIAG.SYS: iManufacturer 0x%x\n", deviceDescriptor->iManufacturer));
//USBDIAG_KdPrint(("USBDIAG.SYS: iProduct 0x%x\n", deviceDescriptor->iProduct));
//USBDIAG_KdPrint(("USBDIAG.SYS: iSerialNumber 0x%x\n", deviceDescriptor->iSerialNumber));
//USBDIAG_KdPrint(("USBDIAG.SYS: bNumConfigurations 0x%x\n", deviceDescriptor->bNumConfigurations));
}
}
else
{
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
}
if (NT_SUCCESS(ntStatus))
{
deviceExtension->pDeviceDescriptor = deviceDescriptor;
deviceExtension->Stopped = FALSE;
}
else if (deviceDescriptor)
{
USBDIAG_ExFreePool(deviceDescriptor);
}
USBDIAG_ExFreePool(urb);
}
else
{
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
}
//USBDIAG_KdPrint(("USBDIAG.SYS: exit USBDIAG_StartDevice (%x)\n", ntStatus));
return ntStatus;
}
NTSTATUS
USBDIAG_QueryCapabilitiesCompletionRoutine(
IN PDEVICE_OBJECT NullDeviceObject,
IN PIRP Irp,
IN PVOID Context
)
{
PDEVICE_OBJECT deviceObject = (PDEVICE_OBJECT) Context;
PDEVICE_EXTENSION deviceExtension = deviceObject->DeviceExtension;
NTSTATUS ntStatus = STATUS_SUCCESS;
PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation (Irp);
ULONG ulPowerLevel;
USBDIAG_KdPrint(("enter USBDIAG_QueryCapabilitiesCompletionRoutine (Irp->IoStatus.Status = 0x%x)\n", Irp->IoStatus.Status));
// If the lower driver returned PENDING, mark our stack location as pending also.
if (Irp->PendingReturned)
{
IoMarkIrpPending(Irp);
}
ASSERT(irpStack->MajorFunction == IRP_MJ_PNP);
ASSERT(irpStack->MinorFunction == IRP_MN_QUERY_CAPABILITIES);
irpStack = IoGetCurrentIrpStackLocation (Irp);
USBDIAG_KdPrint(("sizeof(DEVICE_CAPABILITIES) = %d (0x%x)\n",sizeof(DEVICE_CAPABILITIES),sizeof(DEVICE_CAPABILITIES)));
// this is for Win2k
irpStack->Parameters.DeviceCapabilities.Capabilities->SurpriseRemovalOK = TRUE;
irpStack->Parameters.DeviceCapabilities.Capabilities->Removable = TRUE;
RtlCopyMemory(&deviceExtension->DeviceCapabilities,
irpStack->Parameters.DeviceCapabilities.Capabilities,
sizeof(DEVICE_CAPABILITIES));
// print out capabilities info
USBDIAG_KdPrint(("************ Device Capabilites ************\n"));
USBDIAG_KdPrint(("SystemWake = 0x%x\n", deviceExtension->DeviceCapabilities.SystemWake));
USBDIAG_KdPrint(("DeviceWake = 0x%x\n", deviceExtension->DeviceCapabilities.DeviceWake));
// USBDIAG_KdPrint(("SystemWake = %s\n",
// SystemPowerStateString[deviceExtension->DeviceCapabilities.SystemWake]));
// USBDIAG_KdPrint(("DeviceWake = %s\n",
// DevicePowerStateString[deviceExtension->DeviceCapabilities.DeviceWake]));
USBDIAG_KdPrint(("Device Address: 0x%x\n", deviceExtension->DeviceCapabilities.Address));
for (ulPowerLevel=PowerSystemUnspecified; ulPowerLevel< PowerSystemMaximum; ulPowerLevel++)
{
// USBDIAG_KdPrint(("Dev State Map: sys st %s = dev st %s\n",
// SystemPowerStateString[ulPowerLevel],
// DevicePowerStateString[deviceExtension->DeviceCapabilities.DeviceState[ulPowerLevel]] ));
}
Irp->IoStatus.Status = STATUS_SUCCESS;
return ntStatus;
}
NTSTATUS
USBDIAG_StopDevice(
IN PDEVICE_OBJECT DeviceObject
)
/*++
Routine Description:
Stops a given instance of a UTB device on the 82930.
Arguments:
DeviceObject - pointer to the device object for this instance of a 82930
Return Value:
NT status code
--*/
{
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
NTSTATUS ntStatus = STATUS_SUCCESS;
//USBDIAG_KdPrint(("USBDIAG.SYS: enter USBDIAG_StopDevice\n"));
if (deviceExtension->Stopped != TRUE)
{
ntStatus = USBDIAG_CancelAllIrps(deviceExtension);
//
// if we are already stopped then just exit
//
if (deviceExtension->pDeviceDescriptor)
{
USBDIAG_ExFreePool(deviceExtension->pDeviceDescriptor);
deviceExtension->pDeviceDescriptor = NULL;
}
deviceExtension->Stopped = TRUE;
}
//USBDIAG_KdPrint(("USBDIAG.SYS: exit USBDIAG_StopDevice (%x)\n", ntStatus));
return ntStatus;
}
NTSTATUS
USBDIAG_PnPAddDevice(
IN PDRIVER_OBJECT DriverObject,
IN OUT PDEVICE_OBJECT PhysicalDeviceObject
)
/*++
Routine Description:
This routine is called to create a new instance of the device
Arguments:
DriverObject - pointer to the driver object for this instance of USBDIAG
PhysicalDeviceObject - pointer to device object created by the bus
Return Value:
STATUS_SUCCESS if successful,
STATUS_UNSUCCESSFUL otherwise
--*/
{
NTSTATUS ntStatus = STATUS_SUCCESS;
PDEVICE_OBJECT deviceObject = NULL;
PDEVICE_EXTENSION deviceExtension, globalDeviceExtension = NULL;
// PDEVICE_OBJECT tempdeviceObject = NULL;
USBDIAG_KdPrint(("USBDIAG.SYS: enter USBDIAG_PnPAddDevice\n"));
//
// Are we given the physical device object?
//
if (PhysicalDeviceObject) {
if (USBDIAG_GlobalDeviceObject == NULL) {
//USBDIAG_KdPrint(("USBDIAG.SYS: PnPAddDevice Creating Global Device Object\n"));
ntStatus =
USBDIAG_CreateDeviceObject(DriverObject, &USBDIAG_GlobalDeviceObject, TRUE);
if (NT_SUCCESS(ntStatus)) {
globalDeviceExtension = USBDIAG_GlobalDeviceObject->DeviceExtension;
USBDIAG_GlobalDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
globalDeviceExtension->DeviceList = NULL;
globalDeviceExtension->OpenFRC = 0;
}
}
else
{
globalDeviceExtension = USBDIAG_GlobalDeviceObject->DeviceExtension;
}
//
// create our funtional device object (FDO)
//
if (NT_SUCCESS(ntStatus))
{
//USBDIAG_KdPrint(("USBDIAG.SYS: PnPAddDevice creating new USB device object\n"));
ntStatus = USBDIAG_CreateDeviceObject(DriverObject, &deviceObject, FALSE);
if (NT_SUCCESS(ntStatus))
{
//USBDIAG_KdPrint(("USBDIAG.SYS: PnPAddDevice DONE creating new USB device object\n"));
}//if
}
if (NT_SUCCESS(ntStatus))
{
PDEVICE_LIST_ENTRY device;
deviceExtension = deviceObject->DeviceExtension;
RtlZeroMemory(deviceExtension->DeviceData, MAX_DOWNSTREAM_DEVICES * sizeof(PUSBD_DEVICE_DATA));
// We support buffered I/O only
deviceObject->Flags |= DO_BUFFERED_IO;
//
// remember the Physical device Object
//
deviceExtension->PhysicalDeviceObject=PhysicalDeviceObject;
//
// Attach to the PDO
//
//USBDIAG_KdPrint(("USBDIAG.SYS: PnPAddDevice attaching device to Stack.\n"));
//
// The stackdeviceobject is what we use to send Urbs down the stack
//
deviceExtension->StackDeviceObject =
IoAttachDeviceToDeviceStack(deviceObject, PhysicalDeviceObject);
RtlZeroMemory(deviceExtension->DeviceData, MAX_DOWNSTREAM_DEVICES * sizeof(PUSBD_DEVICE_DATA));
if ((deviceExtension->StackDeviceObject) != NULL)
{
//passed the IoAttachDeviceToDeviceStack call
//USBDIAG_KdPrint(("USBDIAG.SYS: PnPAddDevice successfully attached device to stack\n"));
USBDIAG_KdPrint(("USBDIAG.SYS: PnPAddDevice stackDevObj: %X\n",deviceExtension->StackDeviceObject));
USBDIAG_KdPrint(("USBDIAG.SYS: Saving in deviceExtension 0x%x.\n",
deviceExtension));
if (gVersionInformation.USBDI_Version >= USBD_WIN98_SE_VERSION) // Win98 SE, Win2K and beyond
{
device = USBDIAG_ExAllocatePool(NonPagedPool, sizeof(DEVICE_LIST_ENTRY));
if (device)
{
PDEVICE_OBJECT RootHubPdo = NULL;
PDEVICE_OBJECT TopOfHcdStackDeviceObject = NULL;
ASSERT(globalDeviceExtension != NULL);
device->Next = globalDeviceExtension->DeviceList;
globalDeviceExtension->DeviceList = device;
device->DeviceNumber = USBDIAG_NextDeviceNumber++;
device->PhysicalDeviceObject = PhysicalDeviceObject;
device->DeviceObject = deviceObject;
KeInitializeEvent(&deviceExtension->WaitWakeEvent, SynchronizationEvent, FALSE);
// Get the RootHubPdo & TopOfHcdStackDeviceObject
ntStatus = USBDIAG_SyncGetRootHubPdo(deviceExtension->StackDeviceObject,
PhysicalDeviceObject,
&RootHubPdo,
&TopOfHcdStackDeviceObject);
if (NT_SUCCESS(ntStatus))
{
ASSERT(RootHubPdo);
deviceExtension->RootHubPdo = RootHubPdo;
//ASSERT(TopOfHcdStackDeviceObject);
//deviceExtension->TopOfHcdStackDeviceObject = TopOfHcdStackDeviceObject;
}
else
{
ASSERT(FALSE);
deviceExtension->RootHubPdo = NULL;
deviceExtension->TopOfHcdStackDeviceObject = NULL;
}
ntStatus = STATUS_SUCCESS;
} //if device allocate was successful
}
}//if attach device was successful
else
{
ntStatus = STATUS_NO_SUCH_DEVICE;
//USBDIAG_KdPrint(("USBDIAG.SYS: PnPAddDevice FAILED attaching device to stack\n"));
} //else attach failed
}// if successfully created device object
}
else
{
//
// Given no physical device object, therefore asked to do detection.
// This is a dream on as all USB controller are PCI devices.
//
ntStatus = STATUS_NO_MORE_ENTRIES;
}//else no PDO given
//USBDIAG_KdPrint(("USBDIAG.SYS: exit USBDIAG_PnPAddDevice (%x)\n", ntStatus));
if(NT_SUCCESS(ntStatus))
USBDIAG_NumberDevices++;
return ntStatus;
}
NTSTATUS
USBDIAG_CreateDeviceObject(
IN PDRIVER_OBJECT DriverObject,
IN PDEVICE_OBJECT *DeviceObject,
BOOLEAN Global
)
/*++
Routine Description:
Creates a Functional DeviceObject for the diag driver
Arguments:
DriverObject - pointer to the driver object for device
DeviceObject - pointer to DeviceObject pointer to return
created device object.
Global - create the global device object and symbolic link.
Return Value:
STATUS_SUCCESS if successful,
STATUS_UNSUCCESSFUL otherwise
--*/
{
NTSTATUS ntStatus;
WCHAR deviceLinkBuffer[] = L"\\DosDevices\\USBDIAG";
UNICODE_STRING deviceLinkUnicodeString;
WCHAR deviceNameBuffer[] = L"\\Device\\USBDIAG";
UNICODE_STRING deviceNameUnicodeString;
PDEVICE_EXTENSION deviceExtension;
STRING deviceName;
//USBDIAG_KdPrint(("USBDIAG.SYS: enter USBDIAG_CreateDeviceObject\n"));
//
// fix up device names based on Instance
//
//USBDIAG_KdPrint(("USBDIAG.SYS: USBDIAG_CreateDeviceObject InitUnicode String\n"));
RtlInitUnicodeString (&deviceNameUnicodeString,
deviceNameBuffer);
//USBDIAG_KdPrint(("USBDIAG.SYS: USBDIAG_CreateDeviceObject Convert unicode to ansi\n"));
//Print out the unicode string
deviceName.Buffer = NULL;
ntStatus = RtlUnicodeStringToAnsiString (&deviceName,
&deviceNameUnicodeString,
TRUE);
if (NT_SUCCESS(ntStatus)) {
//USBDIAG_KdPrint(("USBDIAG.SYS: Create Device Name (%s)\n", deviceName.Buffer));
RtlFreeAnsiString (&deviceName);
if (!NT_SUCCESS(ntStatus)) {
//USBDIAG_KdPrint(("USBDIAG.SYS: Failed freeing ansi string!\n"));
}//if not successful ntstatus
} else {
//USBDIAG_KdPrint(("USBDIAG.SYS: Unicode to Ansi str failed w/ ntStatus: 0x%x\n",ntStatus));
}
//USBDIAG_KdPrint(("USBDIAG.SYS: USBDIAG_CreateDeviceObject IOCreateDevice \n"));
ntStatus = IoCreateDevice (DriverObject,
sizeof (DEVICE_EXTENSION),
Global ? &deviceNameUnicodeString : NULL,
FILE_DEVICE_UNKNOWN,
0,
FALSE,
DeviceObject);
if (NT_SUCCESS(ntStatus)) {
//
// Initialize our device extension
//
deviceExtension = (PDEVICE_EXTENSION) ((*DeviceObject)->DeviceExtension);
if (Global)
{
RtlInitUnicodeString (&deviceLinkUnicodeString,
deviceLinkBuffer);
//USBDIAG_KdPrint(("USBDIAG.SYS: Global: Create DosDevice name (%s)\n", deviceLinkBuffer));
ntStatus = IoCreateSymbolicLink (&deviceLinkUnicodeString,
&deviceNameUnicodeString);
RtlCopyMemory(deviceExtension->DeviceLinkNameBuffer,
deviceLinkBuffer,
sizeof(deviceLinkBuffer));
}//if Global
else
{
deviceExtension->Stopped = TRUE;
(*DeviceObject)->Flags |= DO_POWER_PAGABLE;
(*DeviceObject)->Flags &= ~DO_DEVICE_INITIALIZING;
}//else
//Setup the ptr to the device extension for this device & init the Irp field (for now)
//deviceExtension->IrpHead = NULL;
InitializeListHead(&deviceExtension->ListHead);
KeInitializeSpinLock(&deviceExtension->SpinLock);
KeInitializeEvent(&deviceExtension->CancelEvent, NotificationEvent, FALSE);
// this event is triggered when self-requested power irps complete
//KeInitializeEvent(&deviceExtension->SelfRequestedPowerIrpEvent, NotificationEvent, FALSE);
deviceExtension->SelfRequestedPowerIrpEvent = NULL;
// initialize original power level as fully on
deviceExtension->CurrentDeviceState.DeviceState = PowerDeviceD0;
deviceExtension->CurrentSystemState.SystemState = PowerSystemWorking;
deviceExtension->WaitWakeIrp = NULL;
deviceExtension->InterruptIrp = NULL;
}//if ntsuccess
//USBDIAG_KdPrint(("USBDIAG.SYS: exit USBDIAG_CreateDeviceObject (%x)\n", ntStatus));
return ntStatus;
}
NTSTATUS
USBDIAG_CallUSBD(
IN PDEVICE_OBJECT DeviceObject,
IN PURB Urb
)
/*++
Routine Description:
Passes a URB to the USBD class driver
Arguments:
DeviceObject - pointer to the device object for this instance of an 82930
Urb - pointer to Urb request block
Return Value:
STATUS_SUCCESS if successful,
STATUS_UNSUCCESSFUL otherwise
--*/
{
NTSTATUS ntStatus, status = STATUS_SUCCESS;
PDEVICE_EXTENSION deviceExtension;
PIRP irp;
KEVENT event;
IO_STATUS_BLOCK ioStatus;
PIO_STACK_LOCATION nextStack;
//USBDIAG_KdPrint(("USBDIAG.SYS: enter USBDIAG_CallUSBD\n"));
deviceExtension = DeviceObject->DeviceExtension;
//
// issue a synchronous request
//
KeInitializeEvent(&event, NotificationEvent, FALSE);
irp = IoBuildDeviceIoControlRequest(
IOCTL_INTERNAL_USB_SUBMIT_URB,
deviceExtension->StackDeviceObject,
NULL,
0,
NULL,
0,
TRUE, /* INTERNAL */
&event,
&ioStatus);
//
// Call the class driver to perform the operation. If the returned status
// is PENDING, wait for the request to complete.
//
nextStack = IoGetNextIrpStackLocation(irp);
ASSERT(nextStack != NULL);
//
// pass the URB to the USB driver stack
//
nextStack->Parameters.Others.Argument1 = Urb;
//USBDIAG_KdPrint(("USBDIAG.SYS: calling USBD\n"));
ntStatus = IoCallDriver(deviceExtension->StackDeviceObject,
irp);
//USBDIAG_KdPrint(("USBDIAG.SYS: return from IoCallDriver USBD %x\n", ntStatus));
{
KIRQL irql;
irql = KeGetCurrentIrql();
ASSERT(irql <= PASSIVE_LEVEL);
}
if (ntStatus == STATUS_PENDING) {
//USBDIAG_KdPrint(("USBDIAG.SYS: Wait for single object\n"));
status = KeWaitForSingleObject(
&event,
Suspended,
KernelMode,
FALSE,
NULL);
//USBDIAG_KdPrint(("USBDIAG.SYS: Wait for single object, returned %x\n", status));
} else {
ioStatus.Status = ntStatus;
}
//USBDIAG_KdPrint(("USBDIAG.SYS: URB status = %x status = %x irp status %x\n",
// Urb->UrbHeader.Status, status, ioStatus.Status));
//
// USBD maps the error code for us
//
ntStatus = ioStatus.Status;
//USBDIAG_KdPrint(("USBDIAG.SYS: exit USBDIAG_CallUSBD (%x)\n", ntStatus));
return ntStatus;
}
NTSTATUS
USBDIAG_RemoveGlobalDeviceObject(
)
/*++
Routine Description:
Arguments:
Return Value:
STATUS_SUCCESS if successful,
STATUS_UNSUCCESSFUL otherwise
--*/
{
NTSTATUS ntStatus = STATUS_SUCCESS;
PDEVICE_EXTENSION globalDeviceExtension;
UNICODE_STRING deviceLinkUnicodeString;
KIRQL irql;
//USBDIAG_KdPrint(("USBDIAG.SYS: enter USBDIAG_RemoveGlobalDeviceObjec\n"));
irql = KeGetCurrentIrql();
ASSERT(irql <= PASSIVE_LEVEL);
if (USBDIAG_GlobalDeviceObject != NULL) {
globalDeviceExtension = USBDIAG_GlobalDeviceObject->DeviceExtension;
//USBDIAG_KdPrint(("USBDIAG.SYS: USBDIAG_RemoveGlobalDeviceObject open frc = %x, list = %x\n",
//globalDeviceExtension->OpenFRC,
//globalDeviceExtension->DeviceList));
if ( globalDeviceExtension->DeviceList == NULL &&
globalDeviceExtension->OpenFRC == 0) {
//USBDIAG_KdPrint(("USBDIAG.SYS: Deleting global device object\n"));
// delete our global device object once we have no more devices
RtlInitUnicodeString (&deviceLinkUnicodeString,
globalDeviceExtension->DeviceLinkNameBuffer);
//USBDIAG_KdPrint(("USBDIAG.SYS: Deleting Symbolic Link (UnicodeStr) at addr %X\n",
//&deviceLinkUnicodeString));
ntStatus = IoDeleteSymbolicLink(&deviceLinkUnicodeString);
if (NT_SUCCESS(ntStatus)) {
//USBDIAG_KdPrint(("USBDIAG.SYS: Deleting Global Device Object at addr %X\n",
// USBDIAG_GlobalDeviceObject));
IoDeleteDevice( USBDIAG_GlobalDeviceObject );
USBDIAG_GlobalDeviceObject = NULL;
//USBDIAG_KdPrint(("USBDIAG.SYS: Successfully Deleted Global Device Object\n"));
}
}
}
return ntStatus;
}
#define MEM_SIGNATURE ((ULONG) 'CLLA')
#define MEM_FREED_SIGNATURE ((ULONG) 'EERF')
PVOID
USBDIAG_ExAllocatePool(
IN POOL_TYPE PoolType,
IN ULONG NumberOfBytes
)
{
PULONG pMem;
// allocate memory plus a little extra for our own use
pMem = ExAllocatePool(PoolType, NumberOfBytes + (2 * sizeof(ULONG)));
// see if we actually allocated any memory
if(pMem)
{
// store number of bytes allocated at start of memory allocated
*pMem++ = NumberOfBytes;
// now we are pointing at the memory allocated for caller
// put signature word at end
// get new pointer that points to end of buffer - ULONG
pMem = (PULONG) (((PUCHAR) pMem) + NumberOfBytes);
// write signature
*pMem = MEM_SIGNATURE;
// get back pointer to return to caller
pMem = (PULONG) (((PUCHAR) pMem) - NumberOfBytes);
gulMemoryAllocated += NumberOfBytes;
//USBDIAG_KdPrint(("USBDIAG_ExAllocatePool: bytes allocated: %d\n", gulMemoryAllocated));
}
return (PVOID) pMem;
}
VOID
USBDIAG_ExFreePool(
IN PVOID P
)
{
PULONG pTmp = (PULONG) P;
ULONG buffSize;
//PULONG pSav=pTmp;
// point at size ULONG at start of buffer, and address to free
pTmp--;
// get the size of memory allocated by caller
buffSize = *pTmp;
// point at signature and make sure it's O.K.
((PCHAR) P) += buffSize;
if(*((PULONG) P) == MEM_SIGNATURE)
{
// let's go ahead and get rid of signature in case we get called
// with this pointer again and memory is still paged in
*((PULONG) P) = MEM_FREED_SIGNATURE;
// free real pointer
ExFreePool(pTmp);
gulMemoryAllocated -= buffSize;
//USBDIAG_KdPrint(("USBDIAG_ExFreePool: bytes allocated: %d\n", gulMemoryAllocated));
}
else {
TRAP();
}//else
}
NTSTATUS
USBDIAG_ResetParentPort(
IN PDEVICE_OBJECT DeviceObject
)
/*++
Routine Description:
Reset the our parent port
Arguments:
Return Value:
STATUS_SUCCESS if successful,
STATUS_UNSUCCESSFUL otherwise
--*/
{
NTSTATUS ntStatus, status = STATUS_SUCCESS;
PIRP irp;
KEVENT event;
IO_STATUS_BLOCK ioStatus;
PIO_STACK_LOCATION nextStack;
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;//USBDIAG_GlobalDeviceObject->DeviceExtension;
USBDIAG_KdPrint(("enter USBDIAG_ResetParentPort\n"));
ASSERT(deviceExtension);
ASSERT(deviceExtension->StackDeviceObject);
if (!deviceExtension->StackDeviceObject)
return STATUS_UNSUCCESSFUL;
//
// issue a synchronous request
//
KeInitializeEvent(&event, NotificationEvent, FALSE);
irp = IoBuildDeviceIoControlRequest(
IOCTL_INTERNAL_USB_RESET_PORT,
deviceExtension->StackDeviceObject,
NULL,
0,
NULL,
0,
TRUE, /* INTERNAL */
&event,
&ioStatus);
//
// Call the class driver to perform the operation. If the returned status
// is PENDING, wait for the request to complete.
//
nextStack = IoGetNextIrpStackLocation(irp);
ASSERT(nextStack != NULL);
USBDIAG_KdPrint(("USBDIAG_ResetParentPort() calling USBD enable port api\n"));
ntStatus = IoCallDriver(deviceExtension->StackDeviceObject,
irp);
USBDIAG_KdPrint(("USBDIAG_ResetParentPort() return from IoCallDriver USBD %x\n", ntStatus));
if (ntStatus == STATUS_PENDING)
{
USBDIAG_KdPrint(("USBDIAG_ResetParentPort() Wait for single object\n"));
status = KeWaitForSingleObject(
&event,
Suspended,
KernelMode,
FALSE,
NULL);
USBDIAG_KdPrint(("USBDIAG_ResetParentPort() Wait for single object, returned %x\n", status));
}
else
{
ioStatus.Status = ntStatus;
}
//
// USBD maps the error code for us
//
ntStatus = ioStatus.Status;
USBDIAG_KdPrint(("Exit USBDIAG_ResetPort (%x)\n", ntStatus));
return ntStatus;
}
// *************************************
PWCHAR
GetString(PWCHAR pwc, BOOLEAN MultiSZ);
// **************************************************************************
// **************************************************************************
// downstream manipulation routines
NTSTATUS
USBDIAG_RemoveDownstreamDevice(
IN PUSBD_DEVICE_DATA DeviceData,
IN PDEVICE_OBJECT DeviceObject
)
{
NTSTATUS ntStatus = STATUS_SUCCESS;
PUSBD_PIPE defaultPipe = &DeviceData->DefaultPipe;
//USBDIAG_KdPrint(("- USBDIAG_RemoveDownstreamDevice calling USBD_CloseEndpoint -\n"));
ntStatus = USBD_CloseEndpoint(DeviceData,
DeviceObject,
defaultPipe,
NULL);
DeviceData = NULL;
return ntStatus;
}
NTSTATUS
USBDIAG_Chap11SetConfiguration(
IN PUSBD_DEVICE_DATA DeviceData,
IN PDEVICE_OBJECT DeviceObject
)
{
NTSTATUS ntStatus = STATUS_SUCCESS;
ASSERT(DeviceObject);
USBDIAG_KdPrint(("USBDIAG_Chap11SetConfiguration: DeviceData 0x%x (& 0x%x), DeviceObject 0x%x\n",
*DeviceData,
DeviceData,
DeviceObject));
ntStatus = USBD_SendCommand(DeviceData,
DeviceObject,
STANDARD_COMMAND_SET_CONFIGURATION,
0x01, // wValue = 1
0, // wIndex = 0
0, // wLength = 0
NULL,
0,
NULL,
NULL);
return ntStatus;
}
NTSTATUS
USBDIAG_Chap11EnableRemoteWakeup(
IN PUSBD_DEVICE_DATA DeviceData,
IN PDEVICE_OBJECT DeviceObject
)
{
NTSTATUS ntStatus = STATUS_SUCCESS;
ASSERT(DeviceData);
USBDIAG_KdPrint(("USBDIAG_Chap11EnableRemoteWakeup: DeviceData 0x%x (& 0x%x), DeviceObject 0x%x\n",
*DeviceData,
DeviceData,
DeviceObject));
ntStatus = USBD_SendCommand(DeviceData,
DeviceObject,
STANDARD_COMMAND_SET_DEVICE_FEATURE,
0x01, // wValue = 2 for rwu
0, // wIndex = 0
0, // wLength = 0
NULL,
0,
NULL,
NULL);
return ntStatus;
}
NTSTATUS
USBDIAG_Chap11SendPacketDownstream(
IN PUSBD_DEVICE_DATA DeviceData,
IN PDEVICE_OBJECT DeviceObject,
IN PREQ_SEND_PACKET_DOWNSTREAM pSendPacketDownstream
)
{
NTSTATUS ntStatus = STATUS_SUCCESS;
PCHAP11_SETUP_PACKET pSetupPacket = &pSendPacketDownstream->SetupPacket;
PUCHAR pucTempBuffer = NULL;
if (pSetupPacket->wLength)
{
pucTempBuffer = ExAllocatePool(NonPagedPool, pSetupPacket->wLength);
if (!pucTempBuffer)
return STATUS_INSUFFICIENT_RESOURCES;
}
ASSERT(DeviceData);
ntStatus = USBD_SendCommand(DeviceData,
DeviceObject,
pSetupPacket->wRequest,
pSetupPacket->wValue,
pSetupPacket->wIndex,
pSetupPacket->wLength,
pucTempBuffer,
pSetupPacket->wLength,
&pSendPacketDownstream->dwBytes,
&pSendPacketDownstream->ulUrbStatus);
if (NT_SUCCESS(ntStatus) && pSetupPacket->wLength && pSendPacketDownstream->pucBuffer)
{
RtlCopyMemory(pSendPacketDownstream->pucBuffer, pucTempBuffer, pSendPacketDownstream->dwBytes);
}
if (pSetupPacket->wLength && pSendPacketDownstream->pucBuffer && pucTempBuffer)
{
ExFreePool(pucTempBuffer);
pucTempBuffer = NULL;
}
return ntStatus;
}
NTSTATUS
USBDIAG_CreateInitDownstreamDevice(
PREQ_ENUMERATE_DOWNSTREAM_DEVICE pEnumerate,
PDEVICE_EXTENSION deviceExtension
)
{
NTSTATUS ntStatus = STATUS_SUCCESS;
UCHAR ucPortNumber = pEnumerate->ucPortNumber;
PUSBD_DEVICE_DATA DeviceData = NULL;
BOOLEAN bLowSpeed = pEnumerate->bLowSpeed;
ULONG MaxPacketSize0 = 8;
ULONG DeviceHackFlags;
PUSB_DEVICE_DESCRIPTOR deviceDescriptor = NULL;
ULONG deviceDescriptorLength = 0;
PUSB_CONFIGURATION_DESCRIPTOR configDescriptor = NULL;
ULONG configDescriptorLength = 0;
if (deviceExtension->DeviceData[ucPortNumber])
return STATUS_SUCCESS;
USBDIAG_KdPrint(("***************************************************\n"));
USBDIAG_KdPrint(("USBDIAG.SYS: REQ_FUNCTION_CHAP11_CREATE_USBD_DEVICE\n"));
USBDIAG_KdPrint(("- Downstream device:\n"));
USBDIAG_KdPrint(("- Port: %d\n", pEnumerate->ucPortNumber));
USBDIAG_KdPrint(("- Lowspeed: %d\n", pEnumerate->bLowSpeed));
if (!deviceExtension->RootHubPdo)
return STATUS_INVALID_PARAMETER;
ntStatus = USBD_CreateDevice(&DeviceData,
deviceExtension->RootHubPdo,
bLowSpeed,
MaxPacketSize0,
&DeviceHackFlags);
USBDIAG_KdPrint(("* After USBD_CreateDevice, DeviceData = 0x%x\n", DeviceData));
if (NT_SUCCESS(ntStatus))
{
ASSERT(DeviceData);
//USBDIAG_KdPrint(("deviceExtension->DeviceData[%d] = 0x%x\n", deviceExtension->DeviceData[ucPortNumber]));
deviceDescriptorLength = sizeof(USB_DEVICE_DESCRIPTOR);
deviceDescriptor = ExAllocatePool(NonPagedPool, deviceDescriptorLength);
if (!deviceDescriptor)
{
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
}
else
{
configDescriptorLength = 0xFF;
configDescriptor = ExAllocatePool(NonPagedPool, configDescriptorLength);
}
if (!configDescriptor)
{
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
}
}
if (NT_SUCCESS(ntStatus))
{
USBDIAG_KdPrint(("== Chap9Control calling USBD_InitializeDevice ==\n"));
ntStatus = USBD_InitializeDevice(DeviceData,
deviceExtension->RootHubPdo,
deviceDescriptor,
deviceDescriptorLength,
configDescriptor,
configDescriptorLength);
}
if (NT_SUCCESS(ntStatus))
{
deviceExtension->DeviceData[ucPortNumber] = DeviceData;
USBDIAG_KdPrint(("SAVING...\n"));
USBDIAG_KdPrint(("PortNumber: %d\n", ucPortNumber));
USBDIAG_KdPrint(("DeviceData: 0x%x\n", DeviceData));
if (configDescriptor)
{
deviceExtension->DownstreamConfigDescriptor[ucPortNumber] = configDescriptor;
}
else
{
USBDIAG_KdPrint(("configDescriptor after USBD_InitializeDevice is NULL\n!"));
}
//USBDIAG_KdPrint(("deviceExtension->DeviceData[%d]: 0x%x\n",
//ucPortNumber,
//deviceExtension->DeviceData[ucPortNumber]));
//USBDIAG_KdPrint(("deviceExtension: 0x%x\n", deviceExtension));
//USBDIAG_KdPrint(("deviceExtension->DeviceData: 0x%x\n",
//deviceExtension->DeviceData));
//USBDIAG_KdPrint(("&deviceExtension->DeviceData[0]: 0x%x\n",
//&deviceExtension->DeviceData[0]));
//USBDIAG_KdPrint(("&deviceExtension->DeviceData[%d]: 0x%x\n",
//ucPortNumber,
//&deviceExtension->DeviceData[ucPortNumber]));
}
if (!deviceExtension->DeviceData[ucPortNumber])
{
USBDIAG_KdPrint(("Attempt to create/init downstream device FAILED!\n"));
ntStatus = STATUS_UNSUCCESSFUL;
}
return ntStatus;
}
NTSTATUS
USBDIAG_SetCfgEnableRWu(
PDEVICE_EXTENSION deviceExtension,
PREQ_ENUMERATE_DOWNSTREAM_DEVICE pEnumerate
)
{
UCHAR ucPortNumber = pEnumerate->ucPortNumber;
PUSBD_DEVICE_DATA DeviceData = deviceExtension->DeviceData[ucPortNumber];
NTSTATUS ntStatus = STATUS_INVALID_PARAMETER;
PUSB_CONFIGURATION_DESCRIPTOR configDescriptor = deviceExtension->DownstreamConfigDescriptor[ucPortNumber];
USBDIAG_KdPrint(("*************************************************\n"));
USBDIAG_KdPrint(("USBDIAG.SYS: REQ_FUNCTION_CHAP11_INIT_USBD_DEVICE\n"));
USBDIAG_KdPrint(("PortNumber: %d\n", ucPortNumber));
USBDIAG_KdPrint(("DeviceData: 0x%x\n", DeviceData));
USBDIAG_KdPrint(("deviceExtension->DeviceData[%d]: 0x%x\n",
ucPortNumber,
deviceExtension->DeviceData[ucPortNumber]));
ASSERT(deviceExtension->RootHubPdo);
ASSERT(DeviceData);
USBDIAG_KdPrint(("- Chap9Control calling USBDIAG_Chap11SetConfiguration -\n"));
if (DeviceData)
{
ntStatus = USBDIAG_Chap11SetConfiguration(DeviceData,
deviceExtension->RootHubPdo);
USBDIAG_KdPrint(("Set Config On Downstream Device On Port %d %s\n",
ucPortNumber,
NT_SUCCESS(ntStatus) ? "Passed" : "FAILED"));
if (NT_SUCCESS(ntStatus))
{
if (configDescriptor->bmAttributes & REMOTE_WAKEUP)
{
USBDIAG_KdPrint((" Chap9Control calling USBDIAG_Chap11EnableRemoteWakeup -\n"));
ntStatus = USBDIAG_Chap11EnableRemoteWakeup(DeviceData,
//deviceExtension->StackDeviceObject);
deviceExtension->RootHubPdo);
USBDIAG_KdPrint(("Enable RWu On Downstream Device On Port %d %s\n",
ucPortNumber,
NT_SUCCESS(ntStatus) ? "Passed" : "FAILED"));
}
}
}
return ntStatus;
}
NTSTATUS
USBD_SendCommand(
IN PUSBD_DEVICE_DATA DeviceData,
IN PDEVICE_OBJECT DeviceObject,
IN USHORT RequestCode,
IN USHORT WValue,
IN USHORT WIndex,
IN USHORT WLength,
IN PVOID Buffer,
IN ULONG BufferLength,
OUT PULONG BytesReturned,
OUT USBD_STATUS *UsbStatus
)
/*++
Routine Description:
Send a standard USB command on the default pipe.
Arguments:
DeviceData - ptr to USBD device structure the command will be sent to
DeviceObject -
RequestCode -
WValue - wValue for setup packet
WIndex - wIndex for setup packet
WLength - wLength for setup packet
Buffer - Input/Output Buffer for command
BufferLength - Length of Input/Output buffer.
BytesReturned - pointer to ulong to copy number of bytes
returned (optional)
UsbStatus - USBD status code returned in the URB.
Return Value:
STATUS_SUCCESS if successful,
STATUS_UNSUCCESSFUL otherwise
--*/
{
NTSTATUS ntStatus;
PHCD_URB urb = NULL;
PUSBD_PIPE defaultPipe = &(DeviceData->DefaultPipe);
PUSB_STANDARD_SETUP_PACKET setupPacket;
PUSBD_EXTENSION deviceExtension;
PAGED_CODE();
//USBDIAG_KdPrint(("enter USBD_SendCommand\n"));
ASSERT_DEVICE(DeviceData);
deviceExtension = DeviceObject->DeviceExtension;
if (deviceExtension->DeviceHackFlags &
USBD_DEVHACK_SLOW_ENUMERATION) {
//
// if noncomplience switch is on in the
// registry we'll pause here to give the
// device a chance to respond.
//
LARGE_INTEGER deltaTime;
deltaTime.QuadPart = 100 * -10000;
(VOID) KeDelayExecutionThread(KernelMode,
FALSE,
&deltaTime);
}
urb = ExAllocatePool(NonPagedPool,
sizeof(struct _URB_CONTROL_TRANSFER));
if (!urb) {
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
} else {
urb->UrbHeader.Length = sizeof(struct _URB_CONTROL_TRANSFER);
urb->UrbHeader.Function = URB_FUNCTION_CONTROL_TRANSFER;
setupPacket = (PUSB_STANDARD_SETUP_PACKET)
urb->HcdUrbCommonTransfer.Extension.u.SetupPacket;
setupPacket->RequestCode = RequestCode;
setupPacket->wValue = WValue;
setupPacket->wIndex = WIndex;
setupPacket->wLength = WLength;
urb->HcdUrbCommonTransfer.hca.HcdEndpoint = defaultPipe->HcdEndpoint;
urb->HcdUrbCommonTransfer.TransferFlags = USBD_SHORT_TRANSFER_OK;
// USBD is responsible for setting the transfer direction
//
// TRANSFER direction is implied in the command
if (RequestCode & USB_DEVICE_TO_HOST)
USBD_SET_TRANSFER_DIRECTION_IN(urb->HcdUrbCommonTransfer.TransferFlags);
else
USBD_SET_TRANSFER_DIRECTION_OUT(urb->HcdUrbCommonTransfer.TransferFlags);
urb->HcdUrbCommonTransfer.TransferBufferLength = BufferLength;
urb->HcdUrbCommonTransfer.TransferBuffer = Buffer;
urb->HcdUrbCommonTransfer.TransferBufferMDL = NULL;
urb->HcdUrbCommonTransfer.UrbLink = NULL;
//USBDIAG_KdPrint(("SendCommand cmd = 0x%x buffer = 0x%x length = 0x%x direction = 0x%x\n",
//setupPacket->RequestCode,
//urb->HcdUrbCommonTransfer.TransferBuffer,
//urb->HcdUrbCommonTransfer.TransferBufferLength,
//urb->HcdUrbCommonTransfer.TransferFlags
//));
ntStatus = USBD_SubmitSynchronousURB((PURB)urb, DeviceObject, DeviceData);
if (BytesReturned) {
*BytesReturned = urb->HcdUrbCommonTransfer.TransferBufferLength;
}
if (UsbStatus) {
*UsbStatus = urb->HcdUrbCommonTransfer.Status;
}
// free the transfer URB
ExFreePool(urb);
}
//USBDIAG_KdPrint(("exit USBD_SendCommand 0x%x\n", ntStatus));
return ntStatus;
}
NTSTATUS
USBD_CloseEndpoint(
IN PUSBD_DEVICE_DATA DeviceData,
IN PDEVICE_OBJECT DeviceObject,
IN PUSBD_PIPE PipeHandle,
IN OUT USBD_STATUS *UsbStatus
)
/*++
Routine Description:
Close an Endpoint
Arguments:
DeviceData - ptr to USBD device data structure.
DeviceObject - USBD device object.
PipeHandle - USBD pipe handle associated with the endpoint.
Return Value:
STATUS_SUCCESS if successful,
STATUS_UNSUCCESSFUL otherwise
--*/
{
NTSTATUS ntStatus;
PHCD_URB urb;
PUSBD_EXTENSION deviceExtension;
PAGED_CODE();
//USBDIAG_KdPrint(("enter USBD_CloseEndpoint\n"));
ASSERT_DEVICE(DeviceData);
deviceExtension = DeviceObject->DeviceExtension;
urb = ExAllocatePool(NonPagedPool,
sizeof(struct _URB_HCD_CLOSE_ENDPOINT));
if (!urb) {
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
} else {
urb->UrbHeader.Length = sizeof(struct _URB_HCD_CLOSE_ENDPOINT);
urb->UrbHeader.Function = URB_FUNCTION_HCD_CLOSE_ENDPOINT;
urb->HcdUrbCloseEndpoint.HcdEndpoint = PipeHandle->HcdEndpoint;
//
// Serialize Close Endpoint requests
//
ntStatus = USBD_SubmitSynchronousURB((PURB) urb, DeviceObject,
DeviceData);
if (UsbStatus)
*UsbStatus = urb->UrbHeader.Status;
ExFreePool(urb);
}
//USBDIAG_KdPrint(("exit USBD_CloseEndpoint 0x%x\n", ntStatus));
return ntStatus;
}
// downstream manipulation routines done
// **************************************************************************
// **************************************************************************
NTSTATUS
USBDIAG_WaitForWakeup(
PDEVICE_EXTENSION deviceExtension
)
{
NTSTATUS ntStatus;
USBDIAG_KdPrint(("'USBDIAG_WaitForWakeup: Waiting for Wait/Wake completion event\n"));
USBDIAG_KdPrint(("Waiting for WaitWakeEvent...\n"));
ntStatus = KeWaitForSingleObject(&deviceExtension->WaitWakeEvent,
Suspended,
KernelMode,
FALSE,
NULL);
USBDIAG_KdPrint(("'WaitWakeEvent Signalled, Clearing ...\n"));
KeClearEvent(&deviceExtension->WaitWakeEvent);
return ntStatus;
}
PWCHAR
GetString(PWCHAR pwc, BOOLEAN MultiSZ)
{
PWCHAR psz, p;
SIZE_T Size;
PAGED_CODE();
psz=pwc;
while (*psz!='\0' || (MultiSZ && *(psz+1)!='\0')) {
psz++;
}
Size=(psz-pwc+1+(MultiSZ ? 1: 0))*sizeof(*pwc);
// We use pool here because these pointers are passed
// to the PnP code who is responsible for freeing them
if ((p=ExAllocatePool(PagedPool, Size))!=NULL) {
RtlCopyMemory(p, pwc, Size);
}
return(p);
}
#if DBG
ULONG USBD_Debug_Trace_Level =
#ifdef MAX_DEBUG
9;
#else
#ifdef NTKERN
1;
#else
0;
#endif /* NTKERN */
#endif /* MAX_DEBUG */
#endif /* DBG */
#ifdef DEBUG_LOG
struct USBD_LOG_ENTRY {
CHAR le_name[4]; // Identifying string
ULONG le_info1; // entry specific info
ULONG le_info2; // entry specific info
ULONG le_info3; // entry specific info
}; /* USBD_LOG_ENTRY */
struct USBD_LOG_ENTRY *LStart = 0; // No log yet
struct USBD_LOG_ENTRY *LPtr;
struct USBD_LOG_ENTRY *LEnd;
#endif /* DEBUG_LOG */
#if DBG
ULONG
_cdecl
USBD_KdPrintX(
PCH Format,
...
)
{
va_list list;
int i;
int arg[5];
if (USBD_Debug_Trace_Level == 1) {
DbgPrint("USBD: ");
} else {
DbgPrint("'USBD: ");
}
va_start(list, Format);
for (i=0; i<4; i++)
arg[i] = va_arg(list, int);
DbgPrint(Format, arg[0], arg[1], arg[2], arg[3]);
return 0;
}
VOID
USBD_Warning(
PUSBD_DEVICE_DATA DeviceData,
PUCHAR Message,
BOOLEAN DebugBreak
)
{
DbgPrint("USBD: Warning ****************************************************************\n");
if (DeviceData) {
DbgPrint("Device PID %04.4x, VID %04.4x\n",
DeviceData->DeviceDescriptor.idProduct,
DeviceData->DeviceDescriptor.idVendor);
}
DbgPrint("%s", Message);
DbgPrint("******************************************************************************\n");
// if (DebugBreak) {
// DBGBREAK();
// }
}
VOID
USBD_Assert(
IN PVOID FailedAssertion,
IN PVOID FileName,
IN ULONG LineNumber,
IN PCHAR Message
)
/*++
Routine Description:
Debug Assert function.
Arguments:
DeviceObject - pointer to a device object
Irp - pointer to an I/O Request Packet
Return Value:
--*/
{
#ifdef NTKERN
// this makes the compiler generate a ret
ULONG stop = 1;
assert_loop:
#endif
// just call the NT assert function and stop
// in the debugger.
RtlAssert( FailedAssertion, FileName, LineNumber, Message );
// loop here to prevent users from going past
// are assert before we can look at it
#ifdef NTKERN
DBGBREAK();
if (stop) {
goto assert_loop;
}
#endif
return;
}
#endif /* DBG */
#define DEADMAN_TIMER
#define DEADMAN_TIMEOUT 5000 //timeout in ms
//use a 5 second timeout
typedef struct _USBD_DEADMAN_TIMER {
PIRP Irp;
KTIMER TimeoutTimer;
KDPC TimeoutDpc;
} USBD_DEADMAN_TIMER, *PUSBD_DEADMAN_TIMER;
NTSTATUS
USBD_SubmitSynchronousURB(
IN PURB Urb,
IN PDEVICE_OBJECT DeviceObject,
IN PUSBD_DEVICE_DATA DeviceData
)
/*++
Routine Description:
Submit a Urb to HCD synchronously
Arguments:
Urb - Urb to submit
DeviceObject USBD device object
Return Value:
STATUS_SUCCESS if successful,
STATUS_UNSUCCESSFUL otherwise
--*/
{
NTSTATUS ntStatus = STATUS_SUCCESS, status;
PIRP irp;
KEVENT event;
IO_STATUS_BLOCK ioStatus;
PIO_STACK_LOCATION nextStack;
//#ifdef DEADMAN_TIMER
#if 0
BOOLEAN haveTimer = FALSE;
PUSBD_DEADMAN_TIMER timer;
#endif /* DEADMAN_TIMER */
PAGED_CODE();
//USBDIAG_KdPrint(("enter USBD_SubmitSynchronousURB\n"));
ASSERT_DEVICE(DeviceData);
irp = IoBuildDeviceIoControlRequest(
IOCTL_INTERNAL_USB_SUBMIT_URB,
HCD_DEVICE_OBJECT(DeviceObject),
NULL,
0,
NULL,
0,
TRUE, /* INTERNAL */
&event,
&ioStatus);
//
// Call the hc driver to perform the operation. If the returned status
// is PENDING, wait for the request to complete.
//
KeInitializeEvent(&event, NotificationEvent, FALSE);
nextStack = IoGetNextIrpStackLocation(irp);
ASSERT(nextStack != NULL);
nextStack->Parameters.Others.Argument1 = Urb;
//
// initialize flags field
// for internal request
//
Urb->UrbHeader.UsbdFlags = 0;
//
// Init the Irp field for transfers
//
switch(Urb->UrbHeader.Function) {
case URB_FUNCTION_CONTROL_TRANSFER:
case URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER:
HC_URB(Urb)->HcdUrbCommonTransfer.hca.HcdIrp = irp;
if (HC_URB(Urb)->HcdUrbCommonTransfer.TransferBufferMDL == NULL &&
HC_URB(Urb)->HcdUrbCommonTransfer.TransferBufferLength != 0) {
if ((HC_URB(Urb)->HcdUrbCommonTransfer.TransferBufferMDL =
IoAllocateMdl(HC_URB(Urb)->HcdUrbCommonTransfer.TransferBuffer,
HC_URB(Urb)->HcdUrbCommonTransfer.TransferBufferLength,
FALSE,
FALSE,
NULL)) == NULL)
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
else {
Urb->UrbHeader.UsbdFlags |= USBD_REQUEST_MDL_ALLOCATED;
MmBuildMdlForNonPagedPool(HC_URB(Urb)->HcdUrbCommonTransfer.TransferBufferMDL);
}
}
break;
}
//USBDIAG_KdPrint(("USBD_SubmitSynchronousURB: calling HCD with URB\n"));
if (NT_SUCCESS(ntStatus)) {
// set the renter bit on the URB function code
Urb->UrbHeader.Function |= 0x2000;
ntStatus = IoCallDriver(HCD_DEVICE_OBJECT(DeviceObject),
irp);
}
//USBDIAG_KdPrint(("ntStatus from IoCallDriver = 0x%x\n", ntStatus));
status = STATUS_SUCCESS;
if (ntStatus == STATUS_PENDING) {
//#ifdef DEADMAN_TIMER
#if 0
LARGE_INTEGER dueTime;
timer = ExAllocatePool(NonPagedPool, sizeof(USBD_DEADMAN_TIMER));
if (timer) {
timer->Irp = irp;
KeInitializeTimer(&timer->TimeoutTimer);
KeInitializeDpc(&timer->TimeoutDpc,
USBD_SyncUrbTimeoutDPC,
timer);
dueTime.QuadPart = -10000 * DEADMAN_TIMEOUT;
KeSetTimer(&timer->TimeoutTimer,
dueTime,
&timer->TimeoutDpc);
haveTimer = TRUE;
}
#endif /* DEADMAN_TIMER */
status = KeWaitForSingleObject(
&event,
Suspended,
KernelMode,
FALSE,
NULL);
ntStatus = ioStatus.Status;
} else {
ioStatus.Status = ntStatus;
}
//#ifdef DEADMAN_TIMER
#if 0
//
// remove our timeoutDPC from the queue
//
if (haveTimer) {
KeCancelTimer(&timer->TimeoutTimer);
ExFreePool(timer);
}
#endif /* DEADMAN_TIMER */
// NOTE:
// mapping is handled by completion routine
// called by HCD
//USBDIAG_KdPrint(("Leave Synch URB urb status = 0x%x ntStatus = 0x%x\n", Urb->UrbHeader.Status, ntStatus));
return ntStatus;
}
NTSTATUS
USBDIAG_SyncGetRootHubPdo(
IN PDEVICE_OBJECT StackDeviceObject,
IN PDEVICE_OBJECT PhysicalDeviceObject,
IN OUT PDEVICE_OBJECT *RootHubPdo,
IN OUT PDEVICE_OBJECT *TopOfHcdStackDeviceObject
)
{
NTSTATUS ntStatus, status;
PIRP irp;
KEVENT event;
IO_STATUS_BLOCK ioStatus;
PIO_STACK_LOCATION nextStack;
PAGED_CODE();
USBDIAG_KdPrint(("enter USBDIAG_SyncGetRootHubPdo\n"));
//
// issue a synchronous request to the RootHubBdo
//
KeInitializeEvent(&event, NotificationEvent, FALSE);
//USBDIAG_KdPrint(("USBDIAG_SyncGetRootHubPdo: ioctl code: 0x%x\n", IOCTL_INTERNAL_USB_GET_PARENT_HUB_INFO));
irp = IoBuildDeviceIoControlRequest(IOCTL_INTERNAL_USB_GET_PARENT_HUB_INFO,
//StackDeviceObject, //PhysicalDeviceObject,
PhysicalDeviceObject,
NULL,
0,
NULL,
0,
TRUE, // INTERNAL
&event,
&ioStatus);
if (NULL == irp) {
USBDIAG_KdPrint(("USBUSBDIAG_SyncGetRootHubPdo build Irp failed\n"));
return STATUS_INSUFFICIENT_RESOURCES;
}
//
// Call the class driver to perform the operation. If the returned
// status
// is PENDING, wait for the request to complete.
//
nextStack = IoGetNextIrpStackLocation(irp);
//nextStack = IoGetCurrentIrpStackLocation(irp);
//
// pass the URB to the USBD 'class driver'
//
nextStack->Parameters.Others.Argument1 = NULL;
nextStack->Parameters.Others.Argument2 = NULL;
//nextStack->Parameters.Others.Argument3 = NULL;
nextStack->Parameters.Others.Argument4 = RootHubPdo;
// _asm int 3
ntStatus = IoCallDriver(PhysicalDeviceObject, irp);
USBDIAG_KdPrint(("return from IoCallDriver USBD %x\n", ntStatus));
if (ntStatus == STATUS_PENDING)
{
USBDIAG_KdPrint(("Wait for single object\n"));
status = KeWaitForSingleObject(&event,
Suspended,
KernelMode,
FALSE,
NULL);
USBDIAG_KdPrint(("Wait for single object, returned %x\n", status));
} else {
ioStatus.Status = ntStatus;
}
ntStatus = ioStatus.Status;
USBDIAG_KdPrint(("exit USBDIAG_SyncGetRootHubPdo with ntStatus: 0x%x)\n", ntStatus));
return ntStatus;
}
//#ifdef DEADMAN_TIMER
#if 0
VOID
USBD_SyncUrbTimeoutDPC(
IN PKDPC Dpc,
IN PVOID DeferredContext,
IN PVOID SystemArgument1,
IN PVOID SystemArgument2
)
/*++
Routine Description:
This routine runs at DISPATCH_LEVEL IRQL.
Arguments:
Dpc - Pointer to the DPC object.
DeferredContext -
SystemArgument1 - not used.
SystemArgument2 - not used.
Return Value:
None.
--*/
{
PUSBD_DEADMAN_TIMER timer;
#if DBG
BOOLEAN status;
#endif
timer = DeferredContext;
#if DBG
status =
#endif
IoCancelIrp(timer->Irp);
#if DBG
USBD_ASSERT(status == TRUE);
#endif
}
#endif /* DEADMAN_TIMER */
NTSTATUS
USBD_SetPdoRegistryParameter (
IN PDEVICE_OBJECT PhysicalDeviceObject,
IN PWCHAR KeyName,
IN ULONG KeyNameLength,
IN PVOID Data,
IN ULONG DataLength,
IN ULONG KeyType,
IN ULONG DevInstKeyType
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
NTSTATUS ntStatus;
HANDLE handle;
UNICODE_STRING keyNameUnicodeString;
PAGED_CODE();
RtlInitUnicodeString(&keyNameUnicodeString, KeyName);
ntStatus=IoOpenDeviceRegistryKey(PhysicalDeviceObject,
DevInstKeyType,
STANDARD_RIGHTS_ALL,
&handle);
if (NT_SUCCESS(ntStatus)) {
USBD_SetRegistryKeyValue(handle,
&keyNameUnicodeString,
Data,
DataLength,
KeyType);
ZwClose(handle);
}
//USBDIAG_KdPrint((" RtlQueryRegistryValues status 0x%x\n"));
return ntStatus;
}
NTSTATUS
USBD_SetRegistryKeyValue (
IN HANDLE Handle,
IN PUNICODE_STRING KeyNameUnicodeString,
IN PVOID Data,
IN ULONG DataLength,
IN ULONG KeyType
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
NTSTATUS ntStatus = STATUS_INSUFFICIENT_RESOURCES;
PAGED_CODE();
//
// Create the key or open it, as appropriate based on the caller's
// wishes.
//
ntStatus = ZwSetValueKey(Handle,
KeyNameUnicodeString,
0,
KeyType,
Data,
DataLength);
//USBDIAG_KdPrint((" ZwSetKeyValue = 0x%x\n", ntStatus));
return ntStatus;
}