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