2529 lines
72 KiB
C
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;
|
|
}
|
|
|