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

6202 lines
167 KiB
C

/*++
Copyright (c) 1995 Microsoft Corporation
Module Name:
SERVICE.C
Abstract:
Services exported by USBD
Environment:
kernel mode only
Notes:
Revision History:
09-29-95 : created
--*/
#include "wdm.h"
#include <windef.h>
#include <unknown.h>
#ifdef DRM_SUPPORT
#include <ks.h>
#include <ksmedia.h>
#include <drmk.h>
#include <ksdrmhlp.h>
#endif
#include "stdarg.h"
#include "stdio.h"
#include <initguid.h>
#include <wdmguid.h>
#include "usbdi.h" //public data structures
#include "hcdi.h"
#include "usbd.h" //private data strutures
#include "usbdlib.h"
#define USBD
#include "usbdlibi.h"
#undef USBD
NTSTATUS
DllUnload(
VOID
);
NTSTATUS
DllInitialize(
PUNICODE_STRING RegistryPath
);
NTSTATUS
USBD_GetDeviceInformation(
IN PUSB_NODE_CONNECTION_INFORMATION DeviceInformation,
IN ULONG DeviceInformationLength,
IN PUSBD_DEVICE_DATA DeviceData
);
ULONG
USBD_AllocateDeviceName(
PUNICODE_STRING DeviceNameUnicodeString
);
VOID
USBD_FreeDeviceName(
ULONG DeviceNameHandle
);
NTSTATUS
USBD_RegisterHostController(
IN PDEVICE_OBJECT PnPBusDeviceObject,
IN PDEVICE_OBJECT HcdDeviceObject,
IN PDEVICE_OBJECT HcdTopOfStackDeviceObject,
IN PDRIVER_OBJECT HcdDriverObject,
IN HCD_DEFFERED_START_FUNCTION *HcdDeferredStartDevice,
IN HCD_SET_DEVICE_POWER_STATE *HcdSetDevicePowerState,
IN HCD_GET_CURRENT_FRAME *HcdGetCurrentFrame,
IN HCD_GET_CONSUMED_BW *HcdGetConsumedBW,
IN HCD_SUBMIT_ISO_URB *HcdSubmitIsoUrb,
// this parameter is only needed until we resolve device naming
// issues with PNP
IN ULONG HcdDeviceNameHandle
);
NTSTATUS
USBD_InitializeDevice(
IN PUSBD_DEVICE_DATA DeviceData,
IN PDEVICE_OBJECT DeviceObject,
IN OUT PUSB_DEVICE_DESCRIPTOR DeviceDescriptor,
IN ULONG DeviceDescriptorLength,
IN OUT PUSB_CONFIGURATION_DESCRIPTOR ConfigDescriptor,
IN ULONG ConfigDescriptorLength
);
NTSTATUS
USBD_RemoveDevice(
IN PUSBD_DEVICE_DATA DeviceData,
IN PDEVICE_OBJECT DeviceObject,
IN UCHAR Flags
);
PURB
USBD_CreateConfigurationRequestEx(
IN PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor,
IN PUSBD_INTERFACE_LIST_ENTRY InterfaceList
);
PUSB_INTERFACE_DESCRIPTOR
USBD_ParseConfigurationDescriptorEx(
IN PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor,
IN PVOID StartPosition,
IN LONG InterfaceNumber,
IN LONG AlternateSetting,
IN LONG InterfaceClass,
IN LONG InterfaceSubClass,
IN LONG InterfaceProtocol
);
VOID
USBD_WaitDeviceMutex(
PDEVICE_OBJECT RootHubPDO
);
VOID
USBD_FreeDeviceMutex(
PDEVICE_OBJECT RootHubPDO
);
PUSB_COMMON_DESCRIPTOR
USBD_ParseDescriptors(
IN PVOID DescriptorBuffer,
IN ULONG TotalLength,
IN PVOID StartPosition,
IN LONG DescriptorType
);
PUSB_INTERFACE_DESCRIPTOR
USBD_ParseConfigurationDescriptor(
IN PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor,
IN UCHAR InterfaceNumber,
IN UCHAR AlternateSetting
);
PURB
USBD_CreateConfigurationRequest(
IN PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor,
IN OUT PUSHORT Siz
);
NTSTATUS
USBD_GetDeviceName(
IN PDEVICE_OBJECT DeviceObject,
IN OUT PUNICODE_STRING DeviceNameUnicodeString
);
VOID
USBD_RhDelayedSetPowerD0Worker(
IN PVOID Context);
PWCHAR
GetString(PWCHAR pwc, BOOLEAN MultiSZ);
NTSTATUS
USBD_GetBusInterface(
IN PDEVICE_OBJECT RootHubPdo,
IN PIRP Irp
);
#ifdef PAGE_CODE
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, DllUnload)
#pragma alloc_text(PAGE, DllInitialize)
#pragma alloc_text(PAGE, USBD_GetDeviceInformation)
#pragma alloc_text(PAGE, USBD_AllocateDeviceName)
#pragma alloc_text(PAGE, USBD_GetDeviceName)
#pragma alloc_text(PAGE, GetString)
#pragma alloc_text(PAGE, USBD_FreeDeviceName)
#pragma alloc_text(PAGE, USBD_RegisterHostController)
#pragma alloc_text(PAGE, USBD_CreateDevice)
#pragma alloc_text(PAGE, USBD_RemoveDevice)
#pragma alloc_text(PAGE, USBD_InitializeDevice)
#pragma alloc_text(PAGE, USBD_CreateConfigurationRequestEx)
#pragma alloc_text(PAGE, USBD_ParseDescriptors)
#pragma alloc_text(PAGE, USBD_ParseConfigurationDescriptorEx)
#pragma alloc_text(PAGE, USBD_ParseConfigurationDescriptor)
#pragma alloc_text(PAGE, USBD_CreateConfigurationRequest)
#pragma alloc_text(PAGE, USBD_WaitDeviceMutex)
#pragma alloc_text(PAGE, USBD_FreeDeviceMutex)
#pragma alloc_text(PAGE, USBD_InternalGetInterfaceLength)
#pragma alloc_text(PAGE, USBD_RhDelayedSetPowerD0Worker)
#ifdef DRM_SUPPORT
#pragma alloc_text(PAGE, USBD_FdoSetContentId)
#endif
#endif
#endif
/*
********************************************************************************
* DllUnload
********************************************************************************
*
* We need this routine so that the driver can get unloaded when all
* references have been dropped by the minidriver.
*
*/
NTSTATUS
DllUnload (VOID)
{
PAGED_CODE();
USBD_KdPrint(1, (" DllUnload\n"));
return STATUS_SUCCESS;
}
/*
********************************************************************************
* DllInitialize
********************************************************************************
*
* This routine called instead of DriverEntry since we're loaded as a DLL.
*
*/
NTSTATUS
DllInitialize (PUNICODE_STRING RegistryPath)
{
PAGED_CODE();
USBD_KdPrint(1, (" DllInitialize\n"));
return STATUS_SUCCESS;
}
ULONG
USBD_CalculateUsbBandwidth(
ULONG MaxPacketSize,
UCHAR EndpointType,
BOOLEAN LowSpeed
)
/*++
Routine Description:
Arguments:
Return Value:
banwidth consumed in bits/ms, returns 0 for bulk
and control endpoints
--*/
{
ULONG bw;
//
// control, iso, bulk, interrupt
//
ULONG overhead[4] = {
0,
USB_ISO_OVERHEAD_BYTES,
0,
USB_INTERRUPT_OVERHEAD_BYTES
};
USBD_ASSERT(EndpointType<4);
//
// Calculate bandwidth for endpoint. We will use the
// approximation: (overhead bytes plus MaxPacket bytes)
// times 8 bits/byte times worst case bitstuffing overhead.
// This gives bit times, for low speed endpoints we multiply
// by 8 again to convert to full speed bits.
//
//
// Figure out how many bits are required for the transfer.
// (multiply by 7/6 because, in the worst case you might
// have a bit-stuff every six bits requiring 7 bit times to
// transmit 6 bits of data.)
//
// overhead(bytes) * maxpacket(bytes/ms) * 8
// (bits/byte) * bitstuff(7/6) = bits/ms
bw = ((overhead[EndpointType]+MaxPacketSize) * 8 * 7) / 6;
// return zero for control or bulk
if (!overhead[EndpointType]) {
bw = 0;
}
if (LowSpeed) {
bw *= 8;
}
return bw;
}
//
// These APIS replace USBD_CreateConfigurationRequest,
// USBD_ParseConfigurationDescriptor
PURB
USBD_CreateConfigurationRequestEx(
IN PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor,
IN PUSBD_INTERFACE_LIST_ENTRY InterfaceList
)
/*++
Routine Description:
Arguments:
Return Value:
Pointer to initailized select_configuration urb.
--*/
{
PURB urb = NULL;
ULONG numInterfaces, numPipes;
PUSBD_INTERFACE_LIST_ENTRY interfaceList;
USHORT siz;
PAGED_CODE();
//
// Our mission here is to construct a URB of the proper
// size and format for a select_configuration request.
//
// This function uses the configurstion descritor as a
// reference and builds a URB with interface_information
// structures for each interface requested in the interface
// list passed in
//
// NOTE: the config descriptor may contain interfaces that
// the caller does not specify in the list -- in this case
// the other interfaces will be ignored.
//
USBD_KdPrint(3, ("'USBD_CreateConfigurationRequestEx list = %x\n",
InterfaceList));
//
// first figure out how many interfaces we are dealing with
//
interfaceList = InterfaceList;
numInterfaces = 0;
numPipes = 0;
while (interfaceList->InterfaceDescriptor) {
numInterfaces++;
numPipes+=interfaceList->InterfaceDescriptor->bNumEndpoints;
interfaceList++;
}
siz = (USHORT) GET_SELECT_CONFIGURATION_REQUEST_SIZE(numInterfaces,
numPipes);
urb = ExAllocatePoolWithTag(NonPagedPool, siz, USBD_TAG);
if (urb) {
PUSBD_INTERFACE_INFORMATION iface;
//
// now all we have to do is initialize the urb
//
RtlZeroMemory(urb, siz);
iface = &urb->UrbSelectConfiguration.Interface;
interfaceList = InterfaceList;
while (interfaceList->InterfaceDescriptor) {
PUSB_INTERFACE_DESCRIPTOR interfaceDescriptor =
interfaceList->InterfaceDescriptor;
LONG j;
iface->InterfaceNumber =
interfaceDescriptor->bInterfaceNumber;
iface->AlternateSetting =
interfaceDescriptor->bAlternateSetting;
iface->NumberOfPipes =
interfaceDescriptor->bNumEndpoints;
for (j=0; j<interfaceDescriptor->bNumEndpoints; j++) {
iface->Pipes[j].MaximumTransferSize =
USBD_DEFAULT_MAXIMUM_TRANSFER_SIZE;
iface->Pipes[j].PipeFlags = 0;
}
iface->Length =
(USHORT) GET_USBD_INTERFACE_SIZE(
interfaceDescriptor->bNumEndpoints);
USBD_ASSERT(((PUCHAR) iface) + iface->Length <=
((PUCHAR) urb) + siz);
interfaceList->Interface = iface;
interfaceList++;
iface = (PUSBD_INTERFACE_INFORMATION) ((PUCHAR) iface +
iface->Length);
USBD_KdPrint(3, ("'next interface = %x\n", iface));
}
urb->UrbHeader.Length = siz;
urb->UrbHeader.Function = URB_FUNCTION_SELECT_CONFIGURATION;
urb->UrbSelectConfiguration.ConfigurationDescriptor =
ConfigurationDescriptor;
}
#if DBG
interfaceList = InterfaceList;
while (interfaceList->InterfaceDescriptor) {
USBD_KdPrint(3, ("'InterfaceList, Interface = %x\n",
interfaceList->Interface));
USBD_KdPrint(3, ("'InterfaceList, InterfaceDescriptor = %x\n",
interfaceList->InterfaceDescriptor));
interfaceList++;
}
USBD_KdPrint(3, ("'urb = %x\n", urb));
#endif
return urb;
}
PUSB_COMMON_DESCRIPTOR
USBD_ParseDescriptors(
IN PVOID DescriptorBuffer,
IN ULONG TotalLength,
IN PVOID StartPosition,
IN LONG DescriptorType
)
/*++
Routine Description:
Parses a group of standard USB configuration descriptors (returned
from a device) for a specific descriptor type.
Arguments:
DescriptorBuffer - pointer to a block of contiguous USB desscriptors
TotalLength - size in bytes of the Descriptor buffer
StartPosition - starting position in the buffer to begin parsing,
this must point to the begining of a USB descriptor.
DescriptorType - USB descritor type to locate.
Return Value:
pointer to a usb descriptor with a DescriptorType field matching the
input parameter or NULL if not found.
--*/
{
PUCHAR pch = (PUCHAR) StartPosition, end;
PUSB_COMMON_DESCRIPTOR usbDescriptor, foundUsbDescriptor = NULL;
PAGED_CODE();
end = ((PUCHAR) (DescriptorBuffer)) + TotalLength;
while (pch < end) {
// see if we are pointing at an interface
// if not skip over the other junk
usbDescriptor = (PUSB_COMMON_DESCRIPTOR) pch;
if (usbDescriptor->bDescriptorType ==
DescriptorType) {
foundUsbDescriptor = usbDescriptor;
break;
}
// note we still stop in debug because the
// device passed us bad data, the following
// test will prevent us from hanging
if (usbDescriptor->bLength == 0) {
USBD_KdTrap((
"USB driver passed in bad data!\n-->you have a broken device or driver\n-->hit g to cointinue\n"));
break;
}
pch += usbDescriptor->bLength;
}
USBD_KdPrint(3, ("'USBD_ParseDescriptors %x\n", foundUsbDescriptor));
return foundUsbDescriptor;
}
PUSB_INTERFACE_DESCRIPTOR
USBD_ParseConfigurationDescriptorEx(
IN PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor,
IN PVOID StartPosition,
IN LONG InterfaceNumber,
IN LONG AlternateSetting,
IN LONG InterfaceClass,
IN LONG InterfaceSubClass,
IN LONG InterfaceProtocol
)
/*++
Routine Description:
Parses a standard USB configuration descriptor (returned from a device)
for a specific interface, alternate setting class subclass or protocol
codes
Arguments:
ConfigurationDescriptor -
StartPosition -
InterfaceNumber -
AlternateSetting
InterfaceClass -
InterfaceSubClass -
InterfaceProtocol -
Return Value:
NT status code.
--*/
{
PUSB_INTERFACE_DESCRIPTOR foundInterfaceDescriptor = NULL;
PUSB_INTERFACE_DESCRIPTOR interfaceDescriptor;
PAGED_CODE();
USBD_KdPrint(3, ("'USBD_ParseConfigurationDescriptorEx\n"));
ASSERT(ConfigurationDescriptor->bDescriptorType
== USB_CONFIGURATION_DESCRIPTOR_TYPE);
//
// we walk the table of descriptors looking for an
// interface descriptor with parameters matching those
// passed in.
//
do {
//
// Search for descriptor type 'interface'
//
interfaceDescriptor = (PUSB_INTERFACE_DESCRIPTOR)
USBD_ParseDescriptors(ConfigurationDescriptor,
ConfigurationDescriptor->wTotalLength,
StartPosition,
USB_INTERFACE_DESCRIPTOR_TYPE);
//
// do we have a match?
//
if (interfaceDescriptor != NULL) {
foundInterfaceDescriptor =
interfaceDescriptor;
if (InterfaceNumber != -1 &&
interfaceDescriptor->bInterfaceNumber != InterfaceNumber) {
foundInterfaceDescriptor = NULL;
}
if (AlternateSetting != -1 &&
interfaceDescriptor->bAlternateSetting != AlternateSetting) {
foundInterfaceDescriptor = NULL;
}
if (InterfaceClass != -1 &&
interfaceDescriptor->bInterfaceClass != InterfaceClass) {
foundInterfaceDescriptor = NULL;
}
if (InterfaceSubClass != -1 &&
interfaceDescriptor->bInterfaceSubClass !=
InterfaceSubClass) {
foundInterfaceDescriptor = NULL;
}
if (InterfaceProtocol != -1 &&
interfaceDescriptor->bInterfaceProtocol !=
InterfaceProtocol) {
foundInterfaceDescriptor = NULL;
}
StartPosition =
((PUCHAR)interfaceDescriptor) + interfaceDescriptor->bLength;
}
if (foundInterfaceDescriptor) {
break;
}
} while (interfaceDescriptor != NULL);
return (foundInterfaceDescriptor);
}
PUSB_INTERFACE_DESCRIPTOR
USBD_ParseConfigurationDescriptor(
IN PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor,
IN UCHAR InterfaceNumber,
IN UCHAR AlternateSetting
)
/*++
Routine Description:
Arguments:
Return Value:
interface descriptor or NULL.
--*/
{
PAGED_CODE();
return USBD_ParseConfigurationDescriptorEx(
ConfigurationDescriptor,
ConfigurationDescriptor,
InterfaceNumber,
AlternateSetting,
-1,
-1,
-1);
}
PURB
USBD_CreateConfigurationRequest(
IN PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor,
IN OUT PUSHORT Siz
)
/*++
Routine Description:
Arguments:
Return Value:
Pointer to initailized select_configuration urb.
--*/
{
PURB urb = NULL;
PUSB_INTERFACE_DESCRIPTOR interfaceDescriptor;
PUSBD_INTERFACE_LIST_ENTRY interfaceList, tmp;
LONG numberOfInterfaces, interfaceNumber, i;
PAGED_CODE();
USBD_KdPrint(3, ("' enter USBD_CreateConfigurationRequest cd = %x\n",
ConfigurationDescriptor));
//
// build a request structure and call the new api
//
numberOfInterfaces = ConfigurationDescriptor->bNumInterfaces;
tmp = interfaceList =
ExAllocatePoolWithTag(PagedPool, sizeof(USBD_INTERFACE_LIST_ENTRY) *
(numberOfInterfaces+1), USBD_TAG);
//
// just grab the first alt setting we find for each interface
//
i = interfaceNumber = 0;
while (i< numberOfInterfaces) {
interfaceDescriptor = USBD_ParseConfigurationDescriptorEx(
ConfigurationDescriptor,
ConfigurationDescriptor,
interfaceNumber,
0, // assume alt setting zero here
-1,
-1,
-1);
USBD_ASSERT(interfaceDescriptor != NULL);
if (interfaceDescriptor) {
interfaceList->InterfaceDescriptor =
interfaceDescriptor;
interfaceList++;
i++;
} else {
// could not find the requested interface descriptor
// bail, we will prorblay crash somewhere in the
// client driver.
goto USBD_CreateConfigurationRequest_Done;
}
interfaceNumber++;
}
//
// terminate the list
//
interfaceList->InterfaceDescriptor = NULL;
urb = USBD_CreateConfigurationRequestEx(ConfigurationDescriptor,
tmp);
USBD_CreateConfigurationRequest_Done:
ExFreePool(tmp);
if (urb) {
*Siz = urb->UrbHeader.Length;
}
return urb;
}
ULONG
USBD_InternalGetInterfaceLength(
IN PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor,
IN PUCHAR End
)
/*++
Routine Description:
Initialize the configuration handle structure.
Arguments:
InterfaceDescriptor - pointer to usb interface descriptor
followed by endpoint descriptors
Return Value:
Length of the interface plus endpoint descriptors and class specific
descriptors in bytes.
--*/
{
PUCHAR pch = (PUCHAR) InterfaceDescriptor;
ULONG i, numEndpoints;
PUSB_ENDPOINT_DESCRIPTOR endpointDescriptor;
PUSB_COMMON_DESCRIPTOR usbDescriptor;
PAGED_CODE();
ASSERT(InterfaceDescriptor->bDescriptorType ==
USB_INTERFACE_DESCRIPTOR_TYPE);
i = InterfaceDescriptor->bLength;
numEndpoints = InterfaceDescriptor->bNumEndpoints;
// advance to the first endpoint
pch += i;
while (numEndpoints) {
usbDescriptor = (PUSB_COMMON_DESCRIPTOR) pch;
while (usbDescriptor->bDescriptorType !=
USB_ENDPOINT_DESCRIPTOR_TYPE) {
i += usbDescriptor->bLength;
pch += usbDescriptor->bLength;
usbDescriptor = (PUSB_COMMON_DESCRIPTOR) pch;
if (pch >= End || usbDescriptor->bLength == 0) {
USBD_Warning(NULL,
"Bad USB descriptors in USBD_InternalGetInterfaceLength, fail.\n",
FALSE);
// If descriptors are bad, don't index past the end of the
// buffer. Return 0 as the interface length and the caller
// should then be able to handle this appropriately.
i = 0;
goto GetInterfaceLength_exit;
}
}
endpointDescriptor = (PUSB_ENDPOINT_DESCRIPTOR) pch;
ASSERT(endpointDescriptor->bDescriptorType ==
USB_ENDPOINT_DESCRIPTOR_TYPE);
i += endpointDescriptor->bLength;
pch += endpointDescriptor->bLength;
numEndpoints--;
}
while (pch < End) {
// see if we are pointing at an interface
// if not skip over the other junk
usbDescriptor = (PUSB_COMMON_DESCRIPTOR) pch;
if (usbDescriptor->bDescriptorType ==
USB_INTERFACE_DESCRIPTOR_TYPE) {
break;
}
USBD_ASSERT(usbDescriptor->bLength != 0);
i += usbDescriptor->bLength;
pch += usbDescriptor->bLength;
}
GetInterfaceLength_exit:
USBD_KdPrint(3, ("'USBD_GetInterfaceLength %x\n", i));
return i;
}
ULONG
USBD_GetInterfaceLength(
IN PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor,
IN PUCHAR BufferEnd
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
return USBD_InternalGetInterfaceLength(InterfaceDescriptor, BufferEnd);
}
NTSTATUS
USBD_GetPdoRegistryParameter(
IN PDEVICE_OBJECT PhysicalDeviceObject,
IN OUT PVOID Parameter,
IN ULONG ParameterLength,
IN PWCHAR KeyName,
IN ULONG KeyNameLength
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
NTSTATUS ntStatus;
HANDLE handle;
PAGED_CODE();
ntStatus=IoOpenDeviceRegistryKey(PhysicalDeviceObject,
PLUGPLAY_REGKEY_DRIVER,
STANDARD_RIGHTS_ALL,
&handle);
if (NT_SUCCESS(ntStatus)) {
ntStatus = USBD_GetRegistryKeyValue(handle,
KeyName,
KeyNameLength,
Parameter,
ParameterLength);
ZwClose(handle);
}
return ntStatus;
}
VOID
USBD_GetUSBDIVersion(
PUSBD_VERSION_INFORMATION VersionInformation
)
{
if (VersionInformation != NULL) {
VersionInformation->USBDI_Version = USBDI_VERSION;
VersionInformation->Supported_USB_Version = 0x100;
}
}
#ifdef USBD_DRIVER // USBPORT supercedes most of USBD, so we will remove
// the obsolete code by compiling it only if
// USBD_DRIVER is set.
//#if DBG
//VOID
//USBD_IoCompleteRequest(
// IN PIRP Irp,
// IN CCHAR PriorityBoost
// )
//{
// KIRQL irql;
// KeRaiseIrql(DISPATCH_LEVEL, &irql);
// IoCompleteRequest(Irp, PriorityBoost);
// KeLowerIrql(irql);
//}
//#endif
// this code is here to support the old API
// once we eliminate this service it can be removed
NTSTATUS
USBD_GetDeviceInformationX(
IN PUSB_NODE_CONNECTION_INFORMATION DeviceInformation,
IN ULONG DeviceInformationLength,
IN PUSBD_DEVICE_DATA DeviceData
)
/*++
Routine Description:
Returns information about a device given the handle
Arguments:
Return Value:
NT status code
--*/
{
ULONG need;
NTSTATUS ntStatus = STATUS_SUCCESS;
PUSBD_CONFIG configHandle;
ULONG i,j,k;
PAGED_CODE();
DeviceInformation->DeviceAddress = DeviceData->DeviceAddress;
DeviceInformation->LowSpeed = DeviceData->LowSpeed;
configHandle = DeviceData->ConfigurationHandle;
DeviceInformation->NumberOfOpenPipes = 0;
DeviceInformation->CurrentConfigurationValue = 0;
// get the pipe information
if (configHandle) {
DeviceInformation->CurrentConfigurationValue =
configHandle->ConfigurationDescriptor->bConfigurationValue;
for (i=0;
i< configHandle->ConfigurationDescriptor->bNumInterfaces;
i++) {
DeviceInformation->NumberOfOpenPipes +=
configHandle->InterfaceHandle[i]->
InterfaceInformation->NumberOfPipes;
}
need = DeviceInformation->NumberOfOpenPipes * sizeof(USB_PIPE_INFO) +
sizeof(USB_NODE_CONNECTION_INFORMATION);
if (need > DeviceInformationLength) {
ntStatus = STATUS_BUFFER_TOO_SMALL;
} else {
j=0;
for (i=0;
i<configHandle->ConfigurationDescriptor->bNumInterfaces;
i++) {
PUSBD_INTERFACE interfaceHandle =
configHandle->InterfaceHandle[i];
for (k=0;
k<interfaceHandle->InterfaceInformation->NumberOfPipes;
k++, j++) {
DeviceInformation->PipeList[j].ScheduleOffset =
interfaceHandle->PipeHandle[k].ScheduleOffset;
RtlCopyMemory(&DeviceInformation->PipeList[j].
EndpointDescriptor,
&interfaceHandle->PipeHandle[k].
EndpointDescriptor,
sizeof(USB_ENDPOINT_DESCRIPTOR));
}
}
}
}
return ntStatus;
}
NTSTATUS
USBD_GetDeviceInformation(
IN PUSB_NODE_CONNECTION_INFORMATION DeviceInformation,
IN ULONG DeviceInformationLength,
IN PUSBD_DEVICE_DATA DeviceData
)
{
USBD_KdPrint(0,
(" WARNING: Driver using obsolete service enrty point (USBD_GetDeviceInformation) - get JD\n"));
return USBD_GetDeviceInformationX(
DeviceInformation,
DeviceInformationLength,
DeviceData);
}
PWCHAR
GetString(PWCHAR pwc, BOOLEAN MultiSZ)
{
PWCHAR psz, p;
ULONG Size;
PAGED_CODE();
psz=pwc;
while (*psz!='\0' || (MultiSZ && *(psz+1)!='\0')) {
psz++;
}
Size=(ULONG)(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=ExAllocatePoolWithTag(PagedPool, Size, USBD_TAG))!=NULL) {
RtlCopyMemory(p, pwc, Size);
}
return(p);
}
NTSTATUS
USBD_GetDeviceName(
IN PDEVICE_OBJECT DeviceObject,
IN OUT PUNICODE_STRING DeviceNameUnicodeString
)
/*++
Routine Description:
Returns the device name for the give instance of the HCD
Arguments:
DeviceObject -
DeviceNameUnicodeString - ptr to unicode string to initialize
with device name.
Return Value:
NT status code
--*/
{
ULONG ulActualSize;
NTSTATUS ntStatus;
PAGED_CODE();
ntStatus=IoGetDeviceProperty(DeviceObject,
DevicePropertyPhysicalDeviceObjectName,
0,
NULL,
&ulActualSize);
if (ntStatus == STATUS_BUFFER_TOO_SMALL) {
DeviceNameUnicodeString->Length=
(USHORT)(ulActualSize-sizeof(UNICODE_NULL));
DeviceNameUnicodeString->MaximumLength=
(USHORT)ulActualSize;
DeviceNameUnicodeString->Buffer=
ExAllocatePoolWithTag(PagedPool, ulActualSize, USBD_TAG);
if (!DeviceNameUnicodeString->Buffer) {
ntStatus=STATUS_INSUFFICIENT_RESOURCES;
} else {
ntStatus =
IoGetDeviceProperty(DeviceObject,
DevicePropertyPhysicalDeviceObjectName,
ulActualSize,
DeviceNameUnicodeString->Buffer,
&ulActualSize);
if (!NT_SUCCESS(ntStatus)) {
ExFreePool(DeviceNameUnicodeString->Buffer);
}
}
} else {
ntStatus=STATUS_INSUFFICIENT_RESOURCES;
}
return(ntStatus);
}
//
// These functions go away when the PnP naming stuff is fixed
//
UCHAR Instance = 0;
ULONG
USBD_AllocateDeviceName(
PUNICODE_STRING DeviceNameUnicodeString
)
/*++
Routine Description:
Arguments:
Return Value:
None
--*/
{
ULONG bit, i = 0;
PWCHAR deviceNameBuffer;
WCHAR nameBuffer[] = L"\\Device\\HCD0";
//
// first find a free instance value
//
PAGED_CODE();
deviceNameBuffer =
ExAllocatePoolWithTag(NonPagedPool, sizeof(nameBuffer), USBD_TAG);
if (deviceNameBuffer) {
RtlCopyMemory(deviceNameBuffer, nameBuffer, sizeof(nameBuffer));
//
// grab the first free instance
//
bit = 1;
for (i=0; i<8; i++) {
if ((Instance & bit) == 0) {
Instance |= bit;
break;
}
bit = bit <<1;
}
deviceNameBuffer[11] = (WCHAR)('0'+ i);
}
RtlInitUnicodeString(DeviceNameUnicodeString,
deviceNameBuffer);
return i;
}
VOID
USBD_FreeDeviceName(
ULONG DeviceNameHandle
)
/*++
Routine Description:
Arguments:
Return Value:
None
--*/
{
ULONG bit;
PAGED_CODE();
bit = 1;
bit <<= DeviceNameHandle;
Instance &= ~bit;
}
NTSTATUS
USBD_RegisterHostController(
IN PDEVICE_OBJECT PhysicalDeviceObject,
IN PDEVICE_OBJECT HcdDeviceObject,
IN PDEVICE_OBJECT HcdTopOfPdoStackDeviceObject,
IN PDRIVER_OBJECT HcdDriverObject,
IN HCD_DEFFERED_START_FUNCTION *HcdDeferredStartDevice,
IN HCD_SET_DEVICE_POWER_STATE *HcdSetDevicePowerState,
IN HCD_GET_CURRENT_FRAME *HcdGetCurrentFrame,
IN HCD_GET_CONSUMED_BW *HcdGetConsumedBW,
IN HCD_SUBMIT_ISO_URB *HcdSubmitIsoUrb,
// this parameter is only needed until we resolve device naming
// issues with PNP
IN ULONG HcdDeviceNameHandle
)
/*++
Routine Description:
Function is called by HCDs to register with the class driver
Arguments:
PhysicalDeviceObject -
Physical device object representing this bus, this is
the PDO created by PCI and pssed to the HCDs AddDevice
handler.
HcdDeviceObject -
Functional device object (FDO) created by the HCD to manage
the bus
HcdTopOfPdoStackDeviceObject -
device object of for the top of the HCD stack, value returne
from IoAttachDeviceToDeviceStack
Return Value:
--*/
{
NTSTATUS ntStatus = STATUS_SUCCESS;
PDEVICE_OBJECT deviceObject = NULL;
PUSBD_EXTENSION deviceExtension;
UNICODE_STRING localDeviceNameUnicodeString;
PUNICODE_STRING deviceNameUnicodeString;
ULONG complienceFlags = 0;
ULONG diagnosticFlags = 0;
ULONG i;
PAGED_CODE();
USBD_KdPrint(3, ("'enter USBD_RegisterHostController\n"));
ASSERT((sizeof(USBD_EXTENSION) % 4) == 0);
// initialize our device extension, we share the device object
// with the HCD.
deviceExtension = HcdDeviceObject->DeviceExtension;
//#ifdef NTKERN
//
// currently on NTKERN supports the ioclt to get the device name
//
//
// get the device name from the PDO
//
#ifdef USE_PNP_NAME
ntStatus = USBD_GetDeviceName(PnPBusDeviceObject,
&localDeviceNameUnicodeString);
deviceNameUnicodeString = &localDeviceNameUnicodeString;
#else
//
// Big workaround for broken naming of device objects in NTKERN
//
// we would like to use the device name for the PDO but this does not
// work with NTKERN.
//
//
// build device name from handle passed in
//
{
WCHAR nameBuffer[] = L"\\Device\\HCD0";
PWCHAR deviceNameBuffer;
nameBuffer[11] = (WCHAR) ('0'+HcdDeviceNameHandle);
deviceNameBuffer = ExAllocatePoolWithTag(
NonPagedPool,
sizeof(nameBuffer),
USBD_TAG);
if (deviceNameBuffer) {
RtlCopyMemory(deviceNameBuffer, nameBuffer, sizeof(nameBuffer));
} else {
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
}
RtlInitUnicodeString(&localDeviceNameUnicodeString,
deviceNameBuffer);
}
#pragma message ("warning: using workaround for bugs in ntkern")
#endif //USE_PNP_NAME
deviceNameUnicodeString = &localDeviceNameUnicodeString;
if (NT_SUCCESS(ntStatus) && deviceNameUnicodeString) {
//
// got the device name, now create a symbolic
// link for the host HCD/Roothub stack
//
//
// use hardcoded value of HCDn for now until
// we have a we to get these names from user mode
//
WCHAR deviceLinkBuffer[] = L"\\DosDevices\\HCD0";
WCHAR *buffer;
deviceLinkBuffer[15] = (WCHAR)('0'+ HcdDeviceNameHandle);
buffer =
ExAllocatePoolWithTag(PagedPool, sizeof(deviceLinkBuffer), USBD_TAG);
if (buffer) {
RtlCopyMemory(buffer,
deviceLinkBuffer,
sizeof(deviceLinkBuffer));
RtlInitUnicodeString(&deviceExtension->DeviceLinkUnicodeString,
buffer);
ntStatus =
IoCreateSymbolicLink(
&deviceExtension->DeviceLinkUnicodeString,
deviceNameUnicodeString);
USBD_KdPrint(3, ("'IoCreateSymbolicLink for HCD returned 0x%x\n",
ntStatus));
// write the symbolic name to the registry
{
WCHAR hcdNameKey[] = L"SymbolicName";
USBD_SetPdoRegistryParameter (
PhysicalDeviceObject,
&hcdNameKey[0],
sizeof(hcdNameKey),
&deviceExtension->DeviceLinkUnicodeString.Buffer[0],
deviceExtension->DeviceLinkUnicodeString.Length,
REG_SZ,
PLUGPLAY_REGKEY_DEVICE);
}
} else {
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
}
RtlFreeUnicodeString(deviceNameUnicodeString);
}
//#endif
InitializeUsbDeviceMutex(deviceExtension);
deviceExtension->Length = sizeof(USBD_EXTENSION);
// Always start with the default address (0) assigned.
// Address array has one bit for every address 0..127
deviceExtension->AddressList[0] = 1;
deviceExtension->AddressList[1] =
deviceExtension->AddressList[2] =
deviceExtension->AddressList[3] = 0;
deviceExtension->FrameLengthControlOwner = NULL;
deviceExtension->RootHubPDO = NULL;
deviceExtension->DriverObject = HcdDriverObject;
deviceExtension->TrueDeviceExtension = deviceExtension;
deviceExtension->RootHubDeviceState = PowerDeviceD0;
// initial HC device state is OFF until we get a start
deviceExtension->HcCurrentDevicePowerState = PowerDeviceD3;
KeInitializeSpinLock(&deviceExtension->WaitWakeSpin);
KeInitializeSpinLock(&deviceExtension->RootHubPowerSpin);
deviceExtension->RootHubPowerDeviceObject = NULL;
deviceExtension->RootHubPowerIrp = NULL;
deviceExtension->IdleNotificationIrp = NULL;
deviceExtension->IsPIIX3or4 = FALSE;
deviceExtension->WakeSupported = FALSE;
for (i=PowerSystemUnspecified; i< PowerSystemMaximum; i++) {
deviceExtension->
RootHubDeviceCapabilities.DeviceState[i] = PowerDeviceD3;
}
//#ifndef WAIT_WAKE
// #pragma message ("warning: using workaround for bugs in ntkern")
// deviceExtension->HcWakeFlags |= HC_ENABLED_FOR_WAKEUP;
//#endif
//
// intially we are the top of the stack
//
deviceExtension->HcdTopOfStackDeviceObject =
deviceExtension->HcdDeviceObject =
HcdDeviceObject;
deviceExtension->HcdPhysicalDeviceObject = PhysicalDeviceObject;
// remember the top of the PdoStack
deviceExtension->HcdTopOfPdoStackDeviceObject =
HcdTopOfPdoStackDeviceObject;
deviceExtension->HcdDeferredStartDevice =
HcdDeferredStartDevice;
deviceExtension->HcdSetDevicePowerState =
HcdSetDevicePowerState;
deviceExtension->HcdGetCurrentFrame =
HcdGetCurrentFrame;
deviceExtension->HcdGetConsumedBW =
HcdGetConsumedBW;
deviceExtension->HcdSubmitIsoUrb =
HcdSubmitIsoUrb;
// read params from registry for diagnostic mode and
// support for non-compliant devices
USBD_GetPdoRegistryParameters(PhysicalDeviceObject,
&complienceFlags,
&diagnosticFlags,
&deviceExtension->DeviceHackFlags);
USBD_GetGlobalRegistryParameters(PhysicalDeviceObject,
&complienceFlags,
&diagnosticFlags,
&deviceExtension->DeviceHackFlags);
deviceExtension->DiagnosticMode = (BOOLEAN) diagnosticFlags;
deviceExtension->DiagIgnoreHubs = FALSE;
if (complienceFlags) {
// support non-com means turn on all hacks
deviceExtension->DeviceHackFlags = -1;
}
#if DBG
if (deviceExtension->DeviceHackFlags) {
USBD_KdPrint(1, ("Using DeviceHackFlags (%x)\n",
deviceExtension->DeviceHackFlags));
}
//
// trap if we detect any special flags set
//
if (deviceExtension->DiagnosticMode ||
complienceFlags) {
if (deviceExtension->DiagnosticMode) {
USBD_Warning(NULL,
"The USB stack is in diagnostic mode\n",
FALSE);
if (deviceExtension->DiagIgnoreHubs) {
USBD_Warning(NULL,
"The USB stack ignoring HUBs in diag mode\n",
FALSE);
}
}
if (complienceFlags) {
USBD_Warning(NULL,
"Support for non-compliant devices is enabled\n",
FALSE);
}
}
#endif
USBD_KdPrint(3, ("'exit USBD_RegisterHostController ext = 0x%x (0x%x)\n",
deviceExtension, ntStatus));
return ntStatus;
}
NTSTATUS
USBD_CreateDeviceX(
IN OUT PUSBD_DEVICE_DATA *DeviceData,
IN PDEVICE_OBJECT DeviceObject,
IN BOOLEAN DeviceIsLowSpeed,
IN ULONG MaxPacketSize_Endpoint0,
IN OUT PULONG DeviceHackFlags
)
/*++
Routine Description:
Service exported for use by the hub driver
Called for each new device on the USB bus, this function sets
up the internal data structures we need to keep track of the
device and assigns it an address.
Arguments:
DeviceData - ptr to return the ptr to the new device structure
created by this routine
DeviceObject - USBD device object for the USB bus this device is on.
DeviceIsLowSpeed - indicates if a device is low speed
MaxPacketSize_Endpoint0 (*OPTIONAL*) indicates the default max packet
size to use when opening endpiint 0.
NonCompliantDevice (*OPTIONAL*) pointer to boolean flag, set to true
if support for non-compliant usb devices is enabled.
Return Value:
NT status code.
--*/
{
NTSTATUS ntStatus;
PUSBD_DEVICE_DATA deviceData;
PUSBD_PIPE defaultPipe;
PUSBD_EXTENSION deviceExtension;
ULONG bytesReturned = 0;
PUCHAR data = NULL;
PAGED_CODE();
USBD_KdPrint(3, ("'enter USBD_CreateDevice\n"));
*DeviceData = NULL;
deviceExtension = GET_DEVICE_EXTENSION(DeviceObject);
//USBD_WaitForUsbDeviceMutex(deviceExtension);
//
// this flag tells the hub driver to do a reset port before calling
// initialize_device
//
if (DeviceHackFlags) {
*DeviceHackFlags = deviceExtension->DeviceHackFlags;
}
//
// Allocate a USBD_DEVICE_DATA structure
//
deviceData = *DeviceData = GETHEAP(NonPagedPool,
sizeof(USBD_DEVICE_DATA));
// buffer for our descriptor
data = GETHEAP(NonPagedPool,
USB_DEFAULT_MAX_PACKET);
if (deviceData != NULL && data != NULL) {
//
// Initialize some fields in the device structure
//
deviceData->ConfigurationHandle = NULL;
deviceData->DeviceAddress = USB_DEFAULT_DEVICE_ADDRESS;
deviceData->LowSpeed = DeviceIsLowSpeed;
deviceData->AcceptingRequests = TRUE;
deviceData->Sig = SIG_DEVICE;
// **
// We need to talk to the device, first we open the default pipe
// using the defined max packet size (defined by USB spec as 8
// bytes until device receives the GET_DESCRIPTOR (device) command).
// We set the address get the device descriptor then close the pipe
// and re-open it with the correct max packet size.
// **
//
// open the default pipe for the device
//
defaultPipe = &deviceData->DefaultPipe;
defaultPipe->HcdEndpoint = NULL; //default pipe is closed
//
// setup the endpoint descriptor for the default pipe
//
defaultPipe->UsbdPipeFlags = 0;
defaultPipe->EndpointDescriptor.bLength =
sizeof(USB_ENDPOINT_DESCRIPTOR);
defaultPipe->EndpointDescriptor.bDescriptorType =
USB_ENDPOINT_DESCRIPTOR_TYPE;
defaultPipe->EndpointDescriptor.bEndpointAddress =
USB_DEFAULT_ENDPOINT_ADDRESS;
defaultPipe->EndpointDescriptor.bmAttributes =
USB_ENDPOINT_TYPE_CONTROL;
defaultPipe->EndpointDescriptor.wMaxPacketSize =
USB_DEFAULT_MAX_PACKET;
defaultPipe->EndpointDescriptor.bInterval = 0;
//
// probably won't be moving more that 4k on the default pipe
//
defaultPipe->MaxTransferSize = USBD_DEFAULT_MAXIMUM_TRANSFER_SIZE;
ntStatus = USBD_OpenEndpoint(deviceData,
DeviceObject,
defaultPipe,
NULL,
TRUE);
if (NT_SUCCESS(ntStatus)) {
//
// Configure the default pipe for this device and assign the
// device an address
//
// NOTE: if this operation fails it means that we have a device
// that will respond to the default endpoint and we can't change
// it.
// we have no choice but to disable the port on the hub this
// device is attached to.
//
//
// Get information about the device
//
ntStatus =
USBD_SendCommand(deviceData,
DeviceObject,
STANDARD_COMMAND_GET_DESCRIPTOR,
USB_DESCRIPTOR_MAKE_TYPE_AND_INDEX(
USB_DEVICE_DESCRIPTOR_TYPE, 0),
0,
USB_DEFAULT_MAX_PACKET,
data,
//(PUCHAR) &deviceData->DeviceDescriptor,
USB_DEFAULT_MAX_PACKET,
&bytesReturned,
NULL);
// NOTE:
// at this point we only have the first 8 bytes of the
// device descriptor.
}
//
// if we got at least the first 8 bytes of the
// descriptor then we are OK
//
RtlCopyMemory(&deviceData->DeviceDescriptor,
data,
sizeof(deviceData->DeviceDescriptor));
if (bytesReturned == 8 && !NT_SUCCESS(ntStatus)) {
USBD_KdPrint(3,
("'Error returned from get device descriptor -- ignored\n"));
ntStatus = STATUS_SUCCESS;
}
// validate the max packet value and descriptor
if (NT_SUCCESS(ntStatus) &&
(bytesReturned < 8 ||
deviceData->DeviceDescriptor.bMaxPacketSize0 == 0)) {
ntStatus = STATUS_DEVICE_DATA_ERROR;
}
if (!NT_SUCCESS(ntStatus)) {
//
// something went wrong, if we assigned any resources to
// the default pipe then we free them before we get out.
//
// we need to signal to the parent hub that this
// port is to be be disabled we will do this by
// returning an error.
if (defaultPipe->HcdEndpoint != NULL) {
USBD_CloseEndpoint(deviceData,
DeviceObject,
defaultPipe,
NULL);
defaultPipe->HcdEndpoint = NULL; //default pipe is closed
}
RETHEAP(deviceData);
//
// return a null ptr on error
//
*DeviceData = NULL;
}
} else {
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
if (deviceData != NULL) {
RETHEAP(deviceData);
}
*DeviceData = NULL;
}
if (data != NULL) {
RETHEAP(data);
}
//USBD_ReleaseUsbDeviceMutex(deviceExtension);
USBD_KdPrint(3, ("'exit USBD_CreateDevice 0x%x\n", ntStatus));
return ntStatus;
}
NTSTATUS
USBD_CreateDevice(
IN OUT PUSBD_DEVICE_DATA *DeviceData,
IN PDEVICE_OBJECT DeviceObject,
IN BOOLEAN DeviceIsLowSpeed,
IN ULONG MaxPacketSize_Endpoint0,
IN OUT PULONG DeviceHackFlags
)
{
USBD_KdPrint(0,
("'WARNING: Driver using obsolete service enrty point (USBD_CreateDevice) - get JD\n"));
return USBD_CreateDeviceX(
DeviceData,
DeviceObject,
DeviceIsLowSpeed,
MaxPacketSize_Endpoint0,
DeviceHackFlags
);
}
NTSTATUS
USBD_RemoveDeviceX(
IN PUSBD_DEVICE_DATA DeviceData,
IN PDEVICE_OBJECT DeviceObject,
IN UCHAR Flags
)
/*++
Routine Description:
Service exported for use by the hub driver
Called for each device on the USB bus that needs to be removed.
This routine frees the device handle and the address assigned
to the device.
This function should be called after the driver has been notified
that the device has been removed.
Arguments:
DeviceData - ptr to device data structure created by class driver
in USBD_CreateDevice.
DeviceObject - USBD device object for the USB bus this device is on.
Return Value:
NT status code.
--*/
{
NTSTATUS ntStatus = STATUS_SUCCESS;
PUSBD_EXTENSION deviceExtension;
PUSBD_PIPE defaultPipe;
USBD_STATUS usbdStatus;
BOOLEAN keepDeviceData;
PAGED_CODE();
USBD_KdPrint(3, ("'enter USBD_RemoveDevice\n"));
if (!DeviceData || !DeviceObject) {
USBD_KdPrint(1, ("'NULL parameter passed to USBD_RemoveDevice\n"));
return STATUS_INVALID_PARAMETER;
}
if (DeviceData->Sig != SIG_DEVICE) {
USBD_KdPrint(1, ("'Bad DeviceData parameter passed to USBD_RemoveDevice\n"));
return STATUS_INVALID_PARAMETER;
}
if (Flags & USBD_MARK_DEVICE_BUSY) {
DeviceData->AcceptingRequests = FALSE;
return STATUS_SUCCESS;
}
keepDeviceData = Flags & USBD_KEEP_DEVICE_DATA;
deviceExtension = GET_DEVICE_EXTENSION(DeviceObject);
USBD_WaitForUsbDeviceMutex(deviceExtension);
//
// make sure and clean up any open pipe handles
// the device may have
//
ASSERT_DEVICE(DeviceData);
DeviceData->AcceptingRequests = FALSE;
if (DeviceData->ConfigurationHandle) {
ntStatus = USBD_InternalCloseConfiguration(DeviceData,
DeviceObject,
&usbdStatus,
TRUE,
keepDeviceData);
#if DBG
if (!NT_SUCCESS(ntStatus) ||
!USBD_SUCCESS(usbdStatus)) {
USBD_KdTrap(
("'error %x usberr %x occurred during RemoveDevice\n",
ntStatus, usbdStatus));
}
#endif
}
defaultPipe = &DeviceData->DefaultPipe;
if (defaultPipe->HcdEndpoint != NULL) {
USBD_STATUS usbdStatus;
USBD_InternalCloseDefaultPipe(DeviceData,
DeviceObject,
&usbdStatus,
TRUE);
// USBD_CloseEndpoint(DeviceData,
// DeviceObject,
// defaultPipe,
// NULL);
//
// defaultPipe->HcdEndpoint = NULL; //default pipe is closed
}
if (DeviceData->DeviceAddress != USB_DEFAULT_DEVICE_ADDRESS) {
USBD_FreeUsbAddress(DeviceObject, DeviceData->DeviceAddress);
}
if (!keepDeviceData) {
// zap the signature
DeviceData->Sig = 0;
RETHEAP(DeviceData);
}
USBD_ReleaseUsbDeviceMutex(deviceExtension);
USBD_KdPrint(3, ("'exit USBD_RemoveDevice\n"));
return ntStatus;
}
NTSTATUS
USBD_RemoveDevice(
IN PUSBD_DEVICE_DATA DeviceData,
IN PDEVICE_OBJECT DeviceObject,
IN UCHAR Flags
)
{
USBD_KdPrint(0,
("'WARNING: Driver using obsolete service enrty point (USBD_RemoveDevice) - get JD\n"));
return USBD_RemoveDeviceX(
DeviceData,
DeviceObject,
Flags);
}
NTSTATUS
USBD_InitializeDeviceX(
IN PUSBD_DEVICE_DATA DeviceData,
IN PDEVICE_OBJECT DeviceObject,
IN OUT PUSB_DEVICE_DESCRIPTOR DeviceDescriptor,
IN ULONG DeviceDescriptorLength,
IN OUT PUSB_CONFIGURATION_DESCRIPTOR ConfigDescriptor,
IN ULONG ConfigDescriptorLength
)
/*++
Routine Description:
Service exported for use by the hub driver
Called for each device on the USB bus that needs to be initialized.
This routine allocates an address and assigns it to the device.
NOTE: on entry the the device descriptor in DeviceData is expected to
contain at least the first 8 bytes of the device descriptor, this
information is used to open the default pipe.
On Error the DeviceData structure is freed.
Arguments:
DeviceData - ptr to device data structure created by class driver
from a call to USBD_CreateDevice.
DeviceObject - USBD device object for the USB bus this device is on.
DeviceDescriptor -
DeviceDescriptorLength -
Return Value:
NT status code.
--*/
{
NTSTATUS ntStatus = STATUS_SUCCESS;
PUSBD_PIPE defaultPipe;
USHORT address;
PUSBD_EXTENSION deviceExtension;
PAGED_CODE();
USBD_KdPrint(3, ("'enter USBD_InitializeDevice\n"));
deviceExtension = GET_DEVICE_EXTENSION(DeviceObject);
//USBD_WaitForUsbDeviceMutex(deviceExtension);
USBD_ASSERT(DeviceData != NULL);
defaultPipe = &DeviceData->DefaultPipe;
//
// Assign Address to the device
//
address = USBD_AllocateUsbAddress(DeviceObject);
USBD_KdPrint(3, ("'SetAddress, assigning 0x%x address\n", address));
if (NT_SUCCESS(ntStatus)) {
ntStatus = USBD_SendCommand(DeviceData,
DeviceObject,
STANDARD_COMMAND_SET_ADDRESS,
address,
0,
0,
NULL,
0,
NULL,
NULL);
DeviceData->DeviceAddress = address;
}
//
// done with addressing process...
//
// close and re-open the pipe utilizing the
// true max packet size for the defalt pipe
// and the address we assigned to the device.
//
USBD_CloseEndpoint(DeviceData,
DeviceObject,
defaultPipe,
NULL);
defaultPipe->HcdEndpoint = NULL; //default pipe is closed
if (NT_SUCCESS(ntStatus)) {
{
LARGE_INTEGER deltaTime;
// 10ms delay to allow devices to respond after
// the setaddress command
deltaTime.QuadPart = -100000;
(VOID) KeDelayExecutionThread(KernelMode,
FALSE,
&deltaTime);
}
// if we succesfully set the address then
// go ahead and re-open the pipe.
defaultPipe->EndpointDescriptor.wMaxPacketSize =
DeviceData->DeviceDescriptor.bMaxPacketSize0;
if (NT_SUCCESS(ntStatus)) {
ntStatus = USBD_OpenEndpoint(DeviceData,
DeviceObject,
defaultPipe,
NULL,
TRUE);
}
//
// Fetch the device descriptor again, this time
// get the whole thing.
//
if (NT_SUCCESS(ntStatus)) {
ULONG bytesReturned;
ntStatus =
USBD_SendCommand(DeviceData,
DeviceObject,
STANDARD_COMMAND_GET_DESCRIPTOR,
USB_DESCRIPTOR_MAKE_TYPE_AND_INDEX(
USB_DEVICE_DESCRIPTOR_TYPE, 0),
0,
sizeof(DeviceData->DeviceDescriptor),
(PUCHAR) &DeviceData->DeviceDescriptor,
sizeof(DeviceData->DeviceDescriptor),
&bytesReturned,
NULL);
if (NT_SUCCESS(ntStatus) &&
bytesReturned < sizeof(DeviceData->DeviceDescriptor)) {
ntStatus = STATUS_DEVICE_DATA_ERROR;
}
}
//
// Fetch the configuration descriptor for the user as well
// so we can see how many interfaces there are in the configuration.
// If this is a multiple interface device we might want to load
// the standard mulitple interface parent driver instead of the
// diagnostic driver.
//
// The 9 byte configuration descriptor is cached in the DeviceData
// used by USBD_BusGetUsbDescriptors() later instead of bothering
// the device with another Get Descriptor request again real soon.
// Some devices don't take too well to being bothered with back to
// back Get Descriptor requests for only the 9 byte header, especially
// on OHCI host controllers.
if (NT_SUCCESS(ntStatus)) {
ULONG bytesReturned;
ntStatus =
USBD_SendCommand(DeviceData,
DeviceObject,
STANDARD_COMMAND_GET_DESCRIPTOR,
USB_DESCRIPTOR_MAKE_TYPE_AND_INDEX(
USB_CONFIGURATION_DESCRIPTOR_TYPE, 0),
0,
sizeof(DeviceData->ConfigDescriptor),
(PUCHAR) &DeviceData->ConfigDescriptor,
sizeof(DeviceData->ConfigDescriptor),
&bytesReturned,
NULL);
if (NT_SUCCESS(ntStatus) &&
bytesReturned < sizeof(DeviceData->ConfigDescriptor)) {
ntStatus = STATUS_DEVICE_DATA_ERROR;
}
}
}
if (NT_SUCCESS(ntStatus)) {
//
// Return copies of the device and the config descriptors to the caller
//
if (deviceExtension->DiagnosticMode &&
!(deviceExtension->DiagIgnoreHubs &&
(DeviceData->DeviceDescriptor.bDeviceClass == 0x09)))
{
if (DeviceData->ConfigDescriptor.bNumInterfaces > 1){
/*
* This is a COMPOSITE device.
* Alter idProduct slightly so that diagnostic driver
* doesn't load for the parent device.
* The Generic Parent driver will see this and
* set the vid/pid for children to FFFF/FFFF
*/
DeviceData->DeviceDescriptor.idVendor = 0xFFFF;
DeviceData->DeviceDescriptor.idProduct = 0xFFFE;
}
else {
DeviceData->DeviceDescriptor.idVendor = 0xFFFF;
DeviceData->DeviceDescriptor.idProduct = 0xFFFF;
}
DeviceData->DeviceDescriptor.bDeviceClass = 0;
DeviceData->DeviceDescriptor.bDeviceSubClass = 0;
}
if (DeviceDescriptor) {
RtlCopyMemory(DeviceDescriptor,
&DeviceData->DeviceDescriptor,
DeviceDescriptorLength);
}
if (ConfigDescriptor) {
RtlCopyMemory(ConfigDescriptor,
&DeviceData->ConfigDescriptor,
ConfigDescriptorLength);
}
} else {
//
// something went wrong, if we assigned any resources to
// the default pipe then we free them before we get out.
//
// we need to signal to the parent hub that this
// port is to be be disabled we will do this by
// returning an error.
if (defaultPipe->HcdEndpoint != NULL) {
USBD_CloseEndpoint(DeviceData,
DeviceObject,
defaultPipe,
NULL);
defaultPipe->HcdEndpoint = NULL; //default pipe is closed
}
if (DeviceData->DeviceAddress != USB_DEFAULT_DEVICE_ADDRESS) {
USBD_FreeUsbAddress(DeviceObject, DeviceData->DeviceAddress);
}
RETHEAP(DeviceData);
}
//USBD_ReleaseUsbDeviceMutex(deviceExtension);
USBD_KdPrint(3, ("'exit USBD_InitializeDevice 0x%x\n", ntStatus));
return ntStatus;
}
NTSTATUS
USBD_InitializeDevice(
IN PUSBD_DEVICE_DATA DeviceData,
IN PDEVICE_OBJECT DeviceObject,
IN OUT PUSB_DEVICE_DESCRIPTOR DeviceDescriptor,
IN ULONG DeviceDescriptorLength,
IN OUT PUSB_CONFIGURATION_DESCRIPTOR ConfigDescriptor,
IN ULONG ConfigDescriptorLength
)
{
USBD_KdPrint(0,
("'WARNING: Driver using obsolete service enrty point (USBD_InitializeDevice) - get JD\n"));
return USBD_InitializeDeviceX(
DeviceData,
DeviceObject,
DeviceDescriptor,
DeviceDescriptorLength,
ConfigDescriptor,
ConfigDescriptorLength);
}
BOOLEAN
USBD_Dispatch(
PDEVICE_OBJECT DeviceObject,
PIRP Irp,
PDEVICE_OBJECT *HcdDeviceObject,
NTSTATUS *NtStatus
)
/*++
Routine Description:
Entry point called by HCD to allow USBD to process requests first. Since
the root hub (PDO) and the Hos cOntroller FDO share the same dispatch
routine. The HCD calls this function to allow USBD to handle Irps passed
to the PDO for the root hub.
Arguments:
Return Value:
FALSE = Irp completed by USBD
TRUE = Irp needs completion by HCD
--*/
{
BOOLEAN irpNeedsCompletion = TRUE;
PUSBD_EXTENSION deviceExtension;
BOOLEAN forPDO = FALSE;
PIO_STACK_LOCATION irpStack;
USBD_KdPrint(3, ("'enter USBD_Dispatch\n"));
irpStack = IoGetCurrentIrpStackLocation (Irp);
deviceExtension = DeviceObject->DeviceExtension;
//
// apparently the following is valid on NT:
// remove rh PDO
// remove hcd FDO
// remove rh PDO
// we have a special flag to force failure of any PnP IRPs
// in case this happens
//
if (deviceExtension->Flags & USBDFLAG_PDO_REMOVED &&
irpStack->MajorFunction == IRP_MJ_PNP &&
deviceExtension->TrueDeviceExtension != deviceExtension) {
irpNeedsCompletion = FALSE;
USBD_KdPrint(0, ("'Warning: PNP irp for RH PDO received after HCD removed\n"));
*NtStatus =
Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
USBD_IoCompleteRequest (Irp,
IO_NO_INCREMENT);
return irpNeedsCompletion;
}
if (deviceExtension->TrueDeviceExtension != deviceExtension) {
// This request is for a PDO we created for the
// root hub
deviceExtension = deviceExtension->TrueDeviceExtension;
forPDO = TRUE;
}
//
// extract the host controller FDO and return it.
//
*HcdDeviceObject = deviceExtension->HcdDeviceObject;
if (forPDO) {
irpNeedsCompletion = FALSE;
*NtStatus = USBD_PdoDispatch(DeviceObject,
Irp,
deviceExtension,
&irpNeedsCompletion);
} else {
*NtStatus = USBD_FdoDispatch(DeviceObject,
Irp,
deviceExtension,
&irpNeedsCompletion);
}
//
// this flag tells the HCD if they should handle the Irp.
//
return irpNeedsCompletion;
}
VOID
USBD_RhDelayedSetPowerD0Worker(
IN PVOID Context)
/* ++
*
* Description:
*
* Work item scheduled to handle a delayed Set Power D0 IRP for the root hub.
*
*
* Arguments:
*
* Return:
*
* -- */
{
PUSBD_RH_DELAYED_SET_POWER_D0_WORK_ITEM workItemSetPowerD0;
NTSTATUS ntStatus = STATUS_SUCCESS;
PUSBD_EXTENSION deviceExtension = NULL;
PDEVICE_OBJECT rootHubPowerDeviceObject = NULL;
PIRP rootHubPowerIrp = NULL;
PIO_STACK_LOCATION irpStack;
PAGED_CODE();
workItemSetPowerD0 = Context;
deviceExtension = workItemSetPowerD0->DeviceExtension;
rootHubPowerDeviceObject = workItemSetPowerD0->DeviceObject;
rootHubPowerIrp = workItemSetPowerD0->Irp;
ExFreePool(Context);
irpStack = IoGetCurrentIrpStackLocation(rootHubPowerIrp);
ntStatus = deviceExtension->RootHubPower(
deviceExtension->HcdDeviceObject,
rootHubPowerIrp);
// notify after we go on
PoSetPowerState(rootHubPowerDeviceObject,
DevicePowerState,
irpStack->Parameters.Power.State);
//
// keep track of the power state for this PDO
//
deviceExtension->RootHubDeviceState =
irpStack->Parameters.Power.State.DeviceState;
USBD_CompleteIdleNotification(deviceExtension);
rootHubPowerIrp->IoStatus.Status = ntStatus;
PoStartNextPowerIrp(rootHubPowerIrp);
USBD_IoCompleteRequest(rootHubPowerIrp, IO_NO_INCREMENT);
}
VOID
USBD_CompleteIdleNotification(
IN PUSBD_EXTENSION DeviceExtension
)
{
NTSTATUS status;
KIRQL irql;
PIRP irp = NULL;
IoAcquireCancelSpinLock(&irql);
irp = DeviceExtension->IdleNotificationIrp;
DeviceExtension->IdleNotificationIrp = NULL;
if (irp && (irp->Cancel)) {
irp = NULL;
}
if (irp) {
IoSetCancelRoutine(irp, NULL);
}
IoReleaseCancelSpinLock(irql);
if (irp) {
irp->IoStatus.Status = STATUS_SUCCESS;
IoCompleteRequest(irp, IO_NO_INCREMENT);
}
}
NTSTATUS
USBD_HcPoRequestD0Completion(
IN PDEVICE_OBJECT DeviceObject,
IN UCHAR MinorFunction,
IN POWER_STATE PowerState,
IN PVOID Context,
IN PIO_STATUS_BLOCK IoStatus
)
/*++
Routine Description:
Arguments:
DeviceObject - Pointer to the device object for the class device.
Irp - Irp completed.
Context - Driver defined context.
Return Value:
The function value is the final status from the operation.
--*/
{
PUSBD_RH_DELAYED_SET_POWER_D0_WORK_ITEM workItemSetPowerD0;
NTSTATUS ntStatus;
PUSBD_EXTENSION deviceExtension = Context;
KIRQL irql;
PIRP pendingWakeIrp;
PDEVICE_OBJECT rootHubPowerDeviceObject = NULL;
PIRP rootHubPowerIrp = NULL;
ntStatus = IoStatus->Status;
USBD_KdPrint(1, ("USBD_HcPoRequestD0Completion, status = %x\n", ntStatus));
KeAcquireSpinLock(&deviceExtension->RootHubPowerSpin,
&irql);
deviceExtension->Flags &= ~USBDFLAG_HCD_D0_COMPLETE_PENDING;
if (deviceExtension->Flags & USBDFLAG_RH_DELAY_SET_D0) {
deviceExtension->Flags &= ~USBDFLAG_RH_DELAY_SET_D0;
rootHubPowerDeviceObject = deviceExtension->RootHubPowerDeviceObject;
deviceExtension->RootHubPowerDeviceObject = NULL;
rootHubPowerIrp = deviceExtension->RootHubPowerIrp;
deviceExtension->RootHubPowerIrp = NULL;
}
KeReleaseSpinLock(&deviceExtension->RootHubPowerSpin,
irql);
// Power up the RootHub now if we delayed it waiting for the HC set D0
// to complete.
if (rootHubPowerIrp) {
//
// Schedule a work item to process this.
//
workItemSetPowerD0 =
ExAllocatePoolWithTag(NonPagedPool,
sizeof(USBD_RH_DELAYED_SET_POWER_D0_WORK_ITEM),
USBD_TAG);
if (workItemSetPowerD0) {
workItemSetPowerD0->DeviceExtension = deviceExtension;
workItemSetPowerD0->DeviceObject = rootHubPowerDeviceObject;
workItemSetPowerD0->Irp = rootHubPowerIrp;
ExInitializeWorkItem(&workItemSetPowerD0->WorkQueueItem,
USBD_RhDelayedSetPowerD0Worker,
workItemSetPowerD0);
ExQueueWorkItem(&workItemSetPowerD0->WorkQueueItem,
DelayedWorkQueue);
}
}
//
// no wakeup irp pending
//
// The only race condition we our concerned about is if
// the wait wake irp is completed while another is submitted.
// the WaitWake spinlock protects us in this case
KeAcquireSpinLock(&deviceExtension->WaitWakeSpin,
&irql);
pendingWakeIrp = deviceExtension->PendingWakeIrp;
deviceExtension->PendingWakeIrp = NULL;
deviceExtension->HcWakeFlags &= ~HC_ENABLED_FOR_WAKEUP;
KeReleaseSpinLock(&deviceExtension->WaitWakeSpin,
irql);
// we just keep the irp pending until it is canceled
//
// this means that the HC was the source of
// a wakeup ie a usbd device generated resume
// signalling on the bus
//
// complete the root hub wakeup irp here
if (pendingWakeIrp != NULL) {
IoAcquireCancelSpinLock(&irql);
if (pendingWakeIrp->Cancel) {
IoReleaseCancelSpinLock(irql);
} else {
IoSetCancelRoutine(pendingWakeIrp, NULL);
IoReleaseCancelSpinLock(irql);
// status of this Irp?
pendingWakeIrp->IoStatus = *IoStatus;
USBD_IoCompleteRequest(pendingWakeIrp, IO_NO_INCREMENT);
}
}
return ntStatus;
}
NTSTATUS
USBD_HcWaitWakeIrpCompletion(
IN PDEVICE_OBJECT DeviceObject,
IN UCHAR MinorFunction,
IN POWER_STATE DeviceState,
IN PVOID Context,
IN PIO_STATUS_BLOCK IoStatus
)
/*++
Routine Description:
Called when a wake irp completes for a hub
Arguments:
DeviceObject - Pointer to the device object for the class device.
Irp - Irp completed.
Context - Driver defined context.
Return Value:
The function value is the final status from the operation.
--*/
{
NTSTATUS ntStatus = IoStatus->Status;
PUSBD_EXTENSION deviceExtension = Context;
PIRP irp;
KIRQL irql;
PIRP pendingWakeIrp;
POWER_STATE powerState;
BOOLEAN bSubmitNewWakeIrp = FALSE;
ntStatus = IoStatus->Status;
USBD_KdPrint(1, ("WaitWake completion from HC %x\n", ntStatus));
// Clear HcWakeIrp pointer now, otherwise we might try to cancel it in
// USBD_WaitWakeCancel if it is called before our set D0 completes where
// we used to clear HcWakeIrp.
//
// We are still protected from untimely submittal of a new HcWakeIrp
// because this cannot happen until the PendingWakeIrp pointer (for
// the RootHub) is cleared.
KeAcquireSpinLock(&deviceExtension->WaitWakeSpin,
&irql);
// no irp pending in the HC
deviceExtension->HcWakeFlags &= ~HC_WAKE_PENDING;
deviceExtension->HcWakeIrp = NULL;
KeReleaseSpinLock(&deviceExtension->WaitWakeSpin,
irql);
if (NT_SUCCESS(ntStatus)) {
ntStatus = STATUS_MORE_PROCESSING_REQUIRED;
powerState.DeviceState = PowerDeviceD0;
ntStatus = PoRequestPowerIrp(deviceExtension->
HcdPhysicalDeviceObject,
IRP_MN_SET_POWER,
powerState,
USBD_HcPoRequestD0Completion,
deviceExtension,
&irp);
USBD_KdPrint(1, ("NTSTATUS return code from HC set D0 request %x, IRP: %x\n", ntStatus, irp));
ASSERT(ntStatus == STATUS_PENDING);
if (ntStatus == STATUS_PENDING) {
deviceExtension->Flags |= USBDFLAG_HCD_D0_COMPLETE_PENDING;
}
} else {
// The only race condition we our concerned about is if
// the wait wake irp is completed wile another is submitted.
// the WaitWake spinlock protects us in this case
KeAcquireSpinLock(&deviceExtension->WaitWakeSpin,
&irql);
pendingWakeIrp = deviceExtension->PendingWakeIrp;
deviceExtension->PendingWakeIrp = NULL;
deviceExtension->HcWakeFlags &= ~HC_ENABLED_FOR_WAKEUP;
KeReleaseSpinLock(&deviceExtension->WaitWakeSpin,
irql);
//
// Complete the root hub wakeup irp here.
//
if (pendingWakeIrp != NULL) {
IoAcquireCancelSpinLock(&irql);
if (pendingWakeIrp->Cancel) {
IoReleaseCancelSpinLock(irql);
} else {
IoSetCancelRoutine(pendingWakeIrp, NULL);
IoReleaseCancelSpinLock(irql);
// status of this Irp?
pendingWakeIrp->IoStatus = *IoStatus;
USBD_IoCompleteRequest(pendingWakeIrp, IO_NO_INCREMENT);
}
}
}
KeAcquireSpinLock(&deviceExtension->WaitWakeSpin,
&irql);
bSubmitNewWakeIrp =
(deviceExtension->Flags & USBDFLAG_NEED_NEW_HCWAKEIRP) ? 1 : 0;
deviceExtension->Flags &= ~USBDFLAG_NEED_NEW_HCWAKEIRP;
KeReleaseSpinLock(&deviceExtension->WaitWakeSpin,
irql);
if (bSubmitNewWakeIrp) {
USBD_SubmitWaitWakeIrpToHC(deviceExtension);
}
return ntStatus;
}
NTSTATUS
USBD_SubmitWaitWakeIrpToHC(
IN PUSBD_EXTENSION DeviceExtension
)
/*++
Routine Description:
called when a child Pdo is enabled for wakeup, this
function allocates a wait wake irp and passes it to
the parents PDO.
Arguments:
Return Value:
--*/
{
PIRP irp;
NTSTATUS ntStatus;
POWER_STATE powerState;
KIRQL irql;
PIRP hcWakeIrp;
KeAcquireSpinLock(&DeviceExtension->WaitWakeSpin,
&irql);
hcWakeIrp = DeviceExtension->HcWakeIrp;
if (hcWakeIrp && hcWakeIrp->Cancel &&
!(DeviceExtension->Flags & USBDFLAG_NEED_NEW_HCWAKEIRP)) {
DeviceExtension->Flags |= USBDFLAG_NEED_NEW_HCWAKEIRP;
KeReleaseSpinLock(&DeviceExtension->WaitWakeSpin,
irql);
// If we allow a new WW IRP to be posted for the HC now, it will be
// completed with an error because the previous one has not been
// completed/canceled yet. So we set a flag that tells the HC WW IRP
// completion routine that it needs to submit the WW IRP for the HC.
USBD_KdPrint(1, (" HC will be re-enabled for wakeup when old WW IRP completes.\n"));
return STATUS_PENDING;
} else {
KeReleaseSpinLock(&DeviceExtension->WaitWakeSpin,
irql);
}
USBD_ASSERT(DeviceExtension->HcWakeIrp == NULL);
// call top of HC driver stack
DeviceExtension->HcWakeFlags |= HC_WAKE_PENDING;
powerState.DeviceState = DeviceExtension->HcDeviceCapabilities.SystemWake;
USBD_KdPrint(1, ("Submitting IRP_MN_WAIT_WAKE to HC, powerState: %x\n",
DeviceExtension->HcDeviceCapabilities.SystemWake));
ntStatus = PoRequestPowerIrp(DeviceExtension->
HcdPhysicalDeviceObject,
IRP_MN_WAIT_WAKE,
powerState,
USBD_HcWaitWakeIrpCompletion,
DeviceExtension,
&irp);
if (DeviceExtension->HcWakeFlags & HC_WAKE_PENDING) {
DeviceExtension->HcWakeIrp = irp;
USBD_KdPrint(1, (" HC enabled for wakeup\n"));
}
USBD_ASSERT(ntStatus == STATUS_PENDING);
return ntStatus;
}
VOID
USBD_WaitWakeCancel(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
/*++
Routine Description:
Arguments:
Return Value:
NT status code.
--*/
{
PUSBD_EXTENSION deviceExtension;
KIRQL irql;
USBD_KdPrint(3, ("'WaitWake Irp %x cancelled\n", Irp));
USBD_ASSERT(Irp->Cancel == TRUE);
deviceExtension = (PUSBD_EXTENSION)
Irp->IoStatus.Information;
USBD_ASSERT(deviceExtension != NULL);
Irp->IoStatus.Status = STATUS_CANCELLED;
Irp->IoStatus.Information = 0;
IoReleaseCancelSpinLock(Irp->CancelIrql);
KeAcquireSpinLock(&deviceExtension->WaitWakeSpin,
&irql);
deviceExtension->PendingWakeIrp = NULL;
deviceExtension->HcWakeFlags &= ~HC_ENABLED_FOR_WAKEUP;
// see if we need to cancel a wake irp
// in the HC
if (deviceExtension->HcWakeIrp) {
PIRP irp;
irp = deviceExtension->HcWakeIrp;
KeReleaseSpinLock(&deviceExtension->WaitWakeSpin,
irql);
USBD_KdPrint(1, (" Canceling Wake Irp (%x) on HC PDO\n", irp));
IoCancelIrp(irp);
} else {
KeReleaseSpinLock(&deviceExtension->WaitWakeSpin,
irql);
}
USBD_IoCompleteRequest (Irp,
IO_NO_INCREMENT);
}
NTSTATUS
USBD_PdoPower(
PDEVICE_OBJECT DeviceObject,
PIRP Irp,
PUSBD_EXTENSION DeviceExtension
)
/*++
Routine Description:
Disptach routine for Power Irps sent to the PDO for the root hub.
NOTE:
irps sent to the PDO are always completed by the bus driver
Arguments:
DeviceObject - Pdo for the root hub
Return Value:
None
--*/
{
PIO_STACK_LOCATION irpStack;
NTSTATUS ntStatus;
KIRQL irql;
PDRIVER_CANCEL oldCancel;
PDEVICE_CAPABILITIES hcDeviceCapabilities;
PIRP irp, waitWakeIrp = NULL, idleIrp = NULL;
POWER_STATE powerState;
USBD_KdPrint(3, ("'enter USBD_PdoPower\n"));
PAGED_CODE();
irpStack = IoGetCurrentIrpStackLocation (Irp);
ASSERT(irpStack->MajorFunction == IRP_MJ_POWER);
switch (irpStack->MinorFunction) {
case IRP_MN_SET_POWER:
USBD_KdPrint(3, ("'IRP_MN_SET_POWER root hub PDO\n"));
switch (irpStack->Parameters.Power.Type) {
case SystemPowerState:
{
//
// since the fdo driver for the root hub pdo is our own
// hub driver and it is well behaved, we don't expect to see
// a system message where the power state is still undefined
//
//
// we just complete this with success
//
ntStatus = STATUS_SUCCESS;
USBD_KdPrint(1,
("IRP_MJ_POWER RH pdo(%x) MN_SET_POWER(SystemPowerState S%x) status = %x complt\n",
DeviceObject,
irpStack->Parameters.Power.State.SystemState - 1,
ntStatus));
if (irpStack->Parameters.Power.State.SystemState >=
PowerSystemShutdown) {
USBD_KdPrint(1, ("Shutdown Detected for Root Hub PDO\n",
DeviceObject, ntStatus));
}
}
break;
case DevicePowerState:
USBD_KdPrint(1,
("IRP_MJ_POWER RH pdo(%x) MN_SET_POWER(DevicePowerState D%x) from (D%x)\n",
DeviceObject,
irpStack->Parameters.Power.State.DeviceState - 1,
DeviceExtension->RootHubDeviceState - 1));
if (irpStack->Parameters.Power.State.DeviceState ==
PowerDeviceD0) {
KeAcquireSpinLock(&DeviceExtension->RootHubPowerSpin,
&irql);
// Don't power up root hub yet if the HC is not at D0.
if (DeviceExtension->HcCurrentDevicePowerState == PowerDeviceD0 &&
!(DeviceExtension->Flags & USBDFLAG_HCD_D0_COMPLETE_PENDING)) {
KeReleaseSpinLock(&DeviceExtension->RootHubPowerSpin,
irql);
ntStatus =
DeviceExtension->RootHubPower(
DeviceExtension->HcdDeviceObject,
Irp);
// notify after we go on
PoSetPowerState(DeviceObject,
DevicePowerState,
irpStack->Parameters.Power.State);
USBD_CompleteIdleNotification(DeviceExtension);
} else if (!(DeviceExtension->Flags & USBDFLAG_RH_DELAY_SET_D0)) {
DeviceExtension->Flags |= USBDFLAG_RH_DELAY_SET_D0;
ASSERT(DeviceExtension->RootHubPowerDeviceObject == NULL);
ASSERT(DeviceExtension->RootHubPowerIrp == NULL);
DeviceExtension->RootHubPowerDeviceObject = DeviceObject;
DeviceExtension->RootHubPowerIrp = Irp;
KeReleaseSpinLock(&DeviceExtension->RootHubPowerSpin,
irql);
USBD_KdPrint(1, ("'USBD_PdoPower, not powering up RootHub yet because HC is not at D0.\n"));
KeAcquireSpinLock(&DeviceExtension->WaitWakeSpin,
&irql);
// see if we need to cancel a wake irp
// in the HC
if (DeviceExtension->HcWakeIrp) {
PIRP hcwakeirp;
hcwakeirp = DeviceExtension->HcWakeIrp;
KeReleaseSpinLock(&DeviceExtension->WaitWakeSpin,
irql);
USBD_KdPrint(1, ("USBD_PdoPower, Set D0: Canceling Wake Irp (%x) on HC PDO\n", hcwakeirp));
IoCancelIrp(hcwakeirp);
} else {
KeReleaseSpinLock(&DeviceExtension->WaitWakeSpin,
irql);
}
// Set the HC to D0 now.
powerState.DeviceState = PowerDeviceD0;
ntStatus = PoRequestPowerIrp(DeviceExtension->
HcdPhysicalDeviceObject,
IRP_MN_SET_POWER,
powerState,
USBD_HcPoRequestD0Completion,
DeviceExtension,
&irp);
USBD_KdPrint(1, ("NTSTATUS return code from HC set D0 request %x, IRP: %x\n", ntStatus, irp));
ASSERT(ntStatus == STATUS_PENDING);
goto USBD_PdoPower_Done;
} else {
KeReleaseSpinLock(&DeviceExtension->RootHubPowerSpin,
irql);
// Root Hub set D0 is already pending, just complete this
// IRP with STATUS_SUCCESS.
ntStatus = STATUS_SUCCESS;
}
} else {
//
// Complete the Wait Wake Irp if we are going to D3.
//
// We take the cancel spinlock here to ensure our cancel routine does
// not complete the Irp for us.
//
if (irpStack->Parameters.Power.State.DeviceState == PowerDeviceD3) {
IoAcquireCancelSpinLock(&irql);
if (DeviceExtension->IdleNotificationIrp) {
idleIrp = DeviceExtension->IdleNotificationIrp;
DeviceExtension->IdleNotificationIrp = NULL;
if (idleIrp->Cancel) {
idleIrp = NULL;
}
if (idleIrp) {
IoSetCancelRoutine(idleIrp, NULL);
}
}
if (DeviceExtension->PendingWakeIrp) {
waitWakeIrp = DeviceExtension->PendingWakeIrp;
DeviceExtension->PendingWakeIrp = NULL;
DeviceExtension->HcWakeFlags &= ~HC_ENABLED_FOR_WAKEUP;
// irp can no longer be cancelled
if (waitWakeIrp->Cancel || IoSetCancelRoutine(waitWakeIrp, NULL) == NULL) {
waitWakeIrp = NULL;
}
}
IoReleaseCancelSpinLock(irql);
if (idleIrp) {
idleIrp->IoStatus.Status = STATUS_POWER_STATE_INVALID;
IoCompleteRequest(idleIrp, IO_NO_INCREMENT);
}
if (waitWakeIrp) {
waitWakeIrp->IoStatus.Status = STATUS_POWER_STATE_INVALID;
PoStartNextPowerIrp(waitWakeIrp);
USBD_IoCompleteRequest(waitWakeIrp, IO_NO_INCREMENT);
}
}
// notify before we go off
PoSetPowerState(DeviceObject,
DevicePowerState,
irpStack->Parameters.Power.State);
ntStatus =
DeviceExtension->RootHubPower(
DeviceExtension->HcdDeviceObject,
Irp);
}
//
// keep track of the power state for this PDO
//
DeviceExtension->RootHubDeviceState =
irpStack->Parameters.Power.State.DeviceState;
USBD_KdPrint(1,
("Setting RH pdo(%x) to D%d, status = %x complt\n",
DeviceObject,
DeviceExtension->RootHubDeviceState-1,
ntStatus));
break;
default:
USBD_KdTrap(("unknown system power message \n"));
ntStatus = Irp->IoStatus.Status;
}
break;
case IRP_MN_QUERY_POWER:
ntStatus = STATUS_SUCCESS;
USBD_KdPrint(1,
("IRP_MJ_POWER RH pdo(%x) MN_QUERY_POWER, status = %x complt\n",
DeviceObject, ntStatus));
break;
case IRP_MN_WAIT_WAKE:
//
// enabling the root hub for remote wakeup,
// we need to enable the HC for remote wakeup
// by posting a wakeup irp to the HC PDO.
//
// Technically the owner of the PDO for the
// HC should know if the HC signalled wakeup.
//
// make a wake irp and post it to the HCs PDO
KeAcquireSpinLock(&DeviceExtension->WaitWakeSpin,
&irql);
if (DeviceExtension->PendingWakeIrp) {
TEST_TRAP();
ntStatus = STATUS_DEVICE_BUSY;
KeReleaseSpinLock(&DeviceExtension->WaitWakeSpin, irql);
} else {
USBD_KdPrint(1, (" IRP_MJ_POWER RH pdo(%x) MN_WAIT_WAKE, pending\n",
DeviceObject));
//
// Since the host controller has only one child we don't need
// to keep track of the various PDO WaitWakes, and we can turn
// around and send it directly to the HC.
//
// Normally we would have to track the multiple children, but
// not today.
//
oldCancel = IoSetCancelRoutine(Irp, USBD_WaitWakeCancel);
ASSERT (NULL == oldCancel);
if (Irp->Cancel) {
//
// This IRP has aready been cancelled, so complete it now.
// we must clear the cancel routine before completing the IRP.
// We must release the spinlock before calling outside the
// driver.
//
IoSetCancelRoutine (Irp, NULL);
KeReleaseSpinLock(&DeviceExtension->WaitWakeSpin, irql);
ntStatus = Irp->IoStatus.Status = STATUS_CANCELLED;
} else {
//
// Keep it.
//
IoMarkIrpPending(Irp);
DeviceExtension->PendingWakeIrp = Irp;
DeviceExtension->HcWakeFlags |= HC_ENABLED_FOR_WAKEUP;
Irp->IoStatus.Information = (ULONG_PTR) DeviceExtension;
hcDeviceCapabilities = &DeviceExtension->HcDeviceCapabilities;
if (hcDeviceCapabilities->SystemWake != PowerSystemUnspecified) {
// If we are going to submit a new WW IRP to the HC below,
// then clear this flag so that we don't submit one in
// USBD_HcWaitWakeIrpCompletion.
DeviceExtension->Flags &= ~USBDFLAG_NEED_NEW_HCWAKEIRP;
}
KeReleaseSpinLock(&DeviceExtension->WaitWakeSpin, irql);
if (hcDeviceCapabilities->SystemWake != PowerSystemUnspecified) {
USBD_SubmitWaitWakeIrpToHC(DeviceExtension);
}
ntStatus = STATUS_PENDING;
goto USBD_PdoPower_Done;
}
}
USBD_KdPrint(1,
(" IRP_MJ_POWER RH pdo(%x) MN_WAIT_WAKE, status = %x complt\n",
DeviceObject, ntStatus));
break;
default:
// unknown POWER messages for the PDO created
// for the root hub
ntStatus = Irp->IoStatus.Status;
USBD_KdPrint(1, (" IRP_MJ_POWER RH pdo(%x) MN_[%d], status = %x\n",
DeviceObject, irpStack->MinorFunction, ntStatus));
}
Irp->IoStatus.Status = ntStatus;
PoStartNextPowerIrp(Irp);
USBD_IoCompleteRequest (Irp, IO_NO_INCREMENT);
USBD_PdoPower_Done:
return ntStatus;
}
NTSTATUS
USBD_PdoPnP(
PDEVICE_OBJECT DeviceObject,
PIRP Irp,
PUSBD_EXTENSION DeviceExtension
)
/*++
Routine Description:
Disptach routine for PnP Irps sent to the PDO for the root hub.
NOTE:
irps sent to the PDO are always completed by the bus driver
Arguments:
DeviceObject - Pdo for the root hub
Return Value:
None
--*/
{
PIO_STACK_LOCATION irpStack;
PDEVICE_CAPABILITIES DeviceCapabilities;
NTSTATUS ntStatus;
KIRQL irql;
PIRP idleIrp = NULL;
PIRP waitWakeIrp = NULL;
USBD_KdPrint(3, ("'enter USBD_PdoPnP\n"));
irpStack = IoGetCurrentIrpStackLocation (Irp);
ASSERT(irpStack->MajorFunction == IRP_MJ_PNP);
// PNP messages for the PDO created for the root hub
switch (irpStack->MinorFunction) {
case IRP_MN_START_DEVICE:
{
PUSBD_DEVICE_DATA deviceData;
USBD_KdPrint(1, (" Starting Root hub PDO %x\n",
DeviceObject));
// If there is no RootHubPDO, fail this start.
if (!DeviceExtension->RootHubPDO) {
ntStatus = STATUS_UNSUCCESSFUL;
break;
}
//
// create the root hub on the bus
//
ntStatus = USBD_CreateDeviceX(&deviceData,
DeviceObject,
FALSE, // Not a low speed device
8, // Roothub max endpoint
// packet size
NULL);
if (NT_SUCCESS(ntStatus)) {
ntStatus = USBD_InitializeDeviceX(deviceData,
DeviceObject,
NULL,
0,
NULL,
0);
}
//
// create a symbolic link for the root hub PDO
//
if (NT_SUCCESS(ntStatus)) {
DeviceExtension->RootHubDeviceData = deviceData;
USBD_SymbolicLink(TRUE, DeviceExtension);
}
}
break;
case IRP_MN_REMOVE_DEVICE:
USBD_KdPrint(1,
(" Root Hub PDO (%x) is being removed\n",
DeviceObject));
IoAcquireCancelSpinLock(&irql);
if (DeviceExtension->IdleNotificationIrp) {
idleIrp = DeviceExtension->IdleNotificationIrp;
DeviceExtension->IdleNotificationIrp = NULL;
if (idleIrp->Cancel) {
idleIrp = NULL;
}
if (idleIrp) {
IoSetCancelRoutine(idleIrp, NULL);
}
}
if (DeviceExtension->PendingWakeIrp) {
waitWakeIrp = DeviceExtension->PendingWakeIrp;
DeviceExtension->PendingWakeIrp = NULL;
DeviceExtension->HcWakeFlags &= ~HC_ENABLED_FOR_WAKEUP;
// irp can no longer be cancelled
if (waitWakeIrp->Cancel || IoSetCancelRoutine(waitWakeIrp, NULL) == NULL) {
waitWakeIrp = NULL;
}
}
IoReleaseCancelSpinLock(irql);
if (idleIrp) {
idleIrp->IoStatus.Status = STATUS_CANCELLED;
IoCompleteRequest(idleIrp, IO_NO_INCREMENT);
}
if (waitWakeIrp) {
waitWakeIrp->IoStatus.Status = STATUS_CANCELLED;
PoStartNextPowerIrp(waitWakeIrp);
USBD_IoCompleteRequest(waitWakeIrp, IO_NO_INCREMENT);
}
if (DeviceExtension->RootHubDeviceData) {
USBD_RemoveDeviceX(DeviceExtension->RootHubDeviceData,
DeviceObject,
0);
DeviceExtension->RootHubDeviceData = NULL;
USBD_SymbolicLink(FALSE, DeviceExtension);
}
//
// Ounce the removed flag is set all Irps sent to the
// PDO will be failed.
// since the HCD sets the RootHubPDO to NULL when its FDO
// is removed and this remove should happen first we should
// never see RootHubPDO == NULL
//
DeviceExtension->Flags |= USBDFLAG_PDO_REMOVED;
USBD_ASSERT(DeviceExtension->RootHubPDO != NULL);
ntStatus = STATUS_SUCCESS;
break;
case IRP_MN_STOP_DEVICE:
USBD_KdPrint(1,
(" Root Hub PDO %x is being stopped\n",
DeviceObject));
//
// Complete the Wait Wake Irp if we are stopping.
//
// We take the cancel spinlock here to ensure our cancel routine does
// not complete the Irp for us.
//
IoAcquireCancelSpinLock(&irql);
if (DeviceExtension->IdleNotificationIrp) {
idleIrp = DeviceExtension->IdleNotificationIrp;
DeviceExtension->IdleNotificationIrp = NULL;
if (idleIrp->Cancel) {
idleIrp = NULL;
}
if (idleIrp) {
IoSetCancelRoutine(idleIrp, NULL);
}
}
if (DeviceExtension->PendingWakeIrp) {
waitWakeIrp = DeviceExtension->PendingWakeIrp;
DeviceExtension->PendingWakeIrp = NULL;
DeviceExtension->HcWakeFlags &= ~HC_ENABLED_FOR_WAKEUP;
// irp can no longer be cancelled
if (waitWakeIrp->Cancel || IoSetCancelRoutine(waitWakeIrp, NULL) == NULL) {
waitWakeIrp = NULL;
}
}
IoReleaseCancelSpinLock(irql);
if (idleIrp) {
idleIrp->IoStatus.Status = STATUS_CANCELLED;
IoCompleteRequest(idleIrp, IO_NO_INCREMENT);
}
if (waitWakeIrp) {
waitWakeIrp->IoStatus.Status = STATUS_CANCELLED;
PoStartNextPowerIrp(waitWakeIrp);
USBD_IoCompleteRequest(waitWakeIrp, IO_NO_INCREMENT);
}
//
// remove the device from the bus,
// this will allow us to re-open the
// root hub endpoints (ie HC looks for address 1)
// if start failed we will have no DeviceData
if (DeviceExtension->RootHubDeviceData ) {
USBD_RemoveDeviceX(DeviceExtension->RootHubDeviceData,
DeviceObject,
0);
DeviceExtension->RootHubDeviceData = NULL;
USBD_SymbolicLink(FALSE, DeviceExtension);
}
USBD_ASSERT(DeviceExtension->AddressList[0] == 1);
USBD_ASSERT(DeviceExtension->AddressList[1] == 0);
USBD_ASSERT(DeviceExtension->AddressList[2] == 0);
USBD_ASSERT(DeviceExtension->AddressList[3] == 0);
ntStatus = STATUS_SUCCESS;
break;
case IRP_MN_QUERY_PNP_DEVICE_STATE:
ntStatus = STATUS_SUCCESS;
break;
case IRP_MN_QUERY_CAPABILITIES:
//
// Handle query caps for the root hub PDO
//
USBD_KdPrint(3, ("'IRP_MN_QUERY_CAPABILITIES\n"));
//
// Get the packet.
//
DeviceCapabilities=
irpStack->Parameters.DeviceCapabilities.Capabilities;
//
// The power state capabilities for the root
// hub should be the same as those of host
// controller, these were passed to USBD by
// the HCD when it registered.
//
RtlCopyMemory(DeviceCapabilities,
&DeviceExtension->RootHubDeviceCapabilities,
sizeof(*DeviceCapabilities));
//
// override these fields and
// set the root hub capabilities.
//
DeviceCapabilities->Removable=FALSE; // root hub is not removable
DeviceCapabilities->UniqueID=FALSE;
DeviceCapabilities->Address = 0;
DeviceCapabilities->UINumber = 0;
ntStatus = STATUS_SUCCESS;
break;
case IRP_MN_QUERY_ID:
USBD_KdPrint(3, ("'IOCTL_BUS_QUERY_ID\n"));
ntStatus = STATUS_SUCCESS;
switch (irpStack->Parameters.QueryId.IdType) {
case BusQueryDeviceID:
Irp->IoStatus.Information=
(ULONG_PTR)GetString(L"USB\\ROOT_HUB", FALSE);
break;
case BusQueryHardwareIDs:
Irp->IoStatus.Information=
(ULONG_PTR)GetString(L"USB\\ROOT_HUB\0USB\\OTHER_ID\0", TRUE);
break;
case BusQueryCompatibleIDs:
Irp->IoStatus.Information=0;
break;
case BusQueryInstanceID:
//
// The root HUB is instanced solely by the controller's id.
// Hence the UniqueDeviceId above.
//
Irp->IoStatus.Information=0;
break;
default:
ntStatus = Irp->IoStatus.Status;
break;
}
break;
case IRP_MN_QUERY_REMOVE_DEVICE:
case IRP_MN_QUERY_STOP_DEVICE:
case IRP_MN_CANCEL_STOP_DEVICE:
ntStatus = STATUS_SUCCESS;
break;
case IRP_MN_QUERY_INTERFACE:
ntStatus = USBD_GetBusInterface(DeviceExtension->RootHubPDO,
Irp);
break;
case IRP_MN_QUERY_BUS_INFORMATION:
{
// return the standard USB GUID
PPNP_BUS_INFORMATION busInfo;
busInfo = ExAllocatePoolWithTag(PagedPool,
sizeof(PNP_BUS_INFORMATION),
USBD_TAG);
if (busInfo == NULL) {
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
} else {
busInfo->BusTypeGuid = GUID_BUS_TYPE_USB;
busInfo->LegacyBusType = PNPBus;
busInfo->BusNumber = 0;
Irp->IoStatus.Information = (ULONG_PTR) busInfo;
ntStatus = STATUS_SUCCESS;
}
}
break;
case IRP_MN_QUERY_DEVICE_RELATIONS:
USBD_KdPrint(1,
(" IRP_MN_QUERY_DEVICE_RELATIONS (PDO) %x %x\n",
DeviceObject,
irpStack->Parameters.QueryDeviceRelations.Type));
if (irpStack->Parameters.QueryDeviceRelations.Type ==
TargetDeviceRelation) {
PDEVICE_RELATIONS deviceRelations = NULL;
deviceRelations =
ExAllocatePoolWithTag(PagedPool, sizeof(*deviceRelations),
USBD_TAG);
if (deviceRelations == NULL) {
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
} else if (DeviceExtension->RootHubPDO == NULL) {
deviceRelations->Count = 0;
ntStatus = STATUS_SUCCESS;
} else {
deviceRelations->Count = 1;
ObReferenceObject(DeviceExtension->RootHubPDO);
deviceRelations->Objects[0] =
DeviceExtension->RootHubPDO;
ntStatus = STATUS_SUCCESS;
}
Irp->IoStatus.Information=(ULONG_PTR) deviceRelations;
USBD_KdPrint(1, (" TargetDeviceRelation to Root Hub PDO - complt\n"));
} else {
ntStatus = Irp->IoStatus.Status;
}
break;
default:
USBD_KdPrint(1, (" PnP IOCTL(%d) to root hub PDO not handled\n",
irpStack->MinorFunction));
ntStatus = Irp->IoStatus.Status;
} /* switch, PNP minor function */
Irp->IoStatus.Status = ntStatus;
USBD_IoCompleteRequest (Irp,
IO_NO_INCREMENT);
return ntStatus;
}
NTSTATUS
USBD_DeferPoRequestCompletion(
IN PDEVICE_OBJECT DeviceObject,
IN UCHAR MinorFunction,
IN POWER_STATE DeviceState,
IN PVOID Context,
IN PIO_STATUS_BLOCK IoStatus
)
/*++
Routine Description:
This routine is called when the port driver completes an IRP.
Arguments:
DeviceObject - Pointer to the device object for the class device.
SetState - TRUE for set, FALSE for query.
DevicePowerState - The Dx that we are in/tagetted.
Context - Driver defined context, in this case the original power Irp.
IoStatus - The status of the IRP.
Return Value:
The function value is the final status from the operation.
--*/
{
PIRP irp;
PUSBD_EXTENSION deviceExtension = Context;
NTSTATUS ntStatus = IoStatus->Status;
irp = deviceExtension->PowerIrp;
IoCopyCurrentIrpStackLocationToNext(irp);
PoStartNextPowerIrp(irp);
PoCallDriver(deviceExtension->HcdTopOfPdoStackDeviceObject,
irp);
return ntStatus;
}
VOID
USBD_IdleNotificationCancelRoutine(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
/*++
Routine Description:
Arguments:
DeviceObject -
Irp - Power Irp.
Return Value:
--*/
{
PUSBD_EXTENSION deviceExtension;
deviceExtension = DeviceObject->DeviceExtension;
deviceExtension->IdleNotificationIrp = NULL;
IoReleaseCancelSpinLock(Irp->CancelIrql);
Irp->IoStatus.Status = STATUS_CANCELLED;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
}
NTSTATUS
USBD_IdleNotificationRequest(
IN PUSBD_EXTENSION DeviceExtension,
IN PIRP Irp
)
/* ++
*
* Description:
*
* This function handles a request by a USB client driver (in this case
* USBHUB) to tell us that the device wants to idle (selective suspend).
*
* Arguments:
*
* DeviceExtension - the PDO extension
* Irp - the request packet
*
* Return:
*
* NTSTATUS
*
* -- */
{
PUSB_IDLE_CALLBACK_INFO idleCallbackInfo;
NTSTATUS ntStatus = STATUS_PENDING;
KIRQL irql;
PIRP idleIrp;
IoAcquireCancelSpinLock(&irql);
if (DeviceExtension->IdleNotificationIrp != NULL) {
IoReleaseCancelSpinLock(irql);
Irp->IoStatus.Status = STATUS_DEVICE_BUSY;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
ntStatus = STATUS_DEVICE_BUSY;
goto USBD_IdleNotificationRequestDone;
} else if (Irp->Cancel) {
IoReleaseCancelSpinLock(irql);
Irp->IoStatus.Status = STATUS_DEVICE_BUSY;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
ntStatus = STATUS_CANCELLED;
goto USBD_IdleNotificationRequestDone;
}
idleCallbackInfo = (PUSB_IDLE_CALLBACK_INFO)
IoGetCurrentIrpStackLocation(Irp)->\
Parameters.DeviceIoControl.Type3InputBuffer;
USBD_ASSERT(idleCallbackInfo && idleCallbackInfo->IdleCallback);
if (!idleCallbackInfo || !idleCallbackInfo->IdleCallback) {
IoReleaseCancelSpinLock(irql);
Irp->IoStatus.Status = STATUS_NO_CALLBACK_ACTIVE;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
ntStatus = STATUS_NO_CALLBACK_ACTIVE;
goto USBD_IdleNotificationRequestDone;
}
DeviceExtension->IdleNotificationIrp = Irp;
IoSetCancelRoutine(Irp, USBD_IdleNotificationCancelRoutine);
IoReleaseCancelSpinLock(irql);
//
// Call the idle function now.
//
if (idleCallbackInfo && idleCallbackInfo->IdleCallback) {
// Here we actually call the driver's callback routine,
// telling the driver that it is OK to suspend their
// device now.
idleCallbackInfo->IdleCallback(idleCallbackInfo->IdleContext);
}
USBD_IdleNotificationRequestDone:
return ntStatus;
}
NTSTATUS
USBD_PdoDispatch(
PDEVICE_OBJECT DeviceObject,
PIRP Irp,
PUSBD_EXTENSION DeviceExtension,
PBOOLEAN IrpNeedsCompletion
)
/*++
Routine Description:
Disptach routine for Irps sent to the PDO for the root hub.
NOTE:
irps sent to the PDO are always completed by the bus driver
Arguments:
Return Value:
None
--*/
{
PIO_STACK_LOCATION irpStack;
NTSTATUS ntStatus;
USBD_KdPrint(3, ("'enter USBD_PdoDispatch\n"));
*IrpNeedsCompletion = FALSE;
irpStack = IoGetCurrentIrpStackLocation (Irp);
switch (irpStack->MajorFunction) {
case IRP_MJ_INTERNAL_DEVICE_CONTROL:
switch(irpStack->Parameters.DeviceIoControl.IoControlCode) {
case IOCTL_INTERNAL_USB_GET_HUB_COUNT:
USBD_KdPrint(3, ("'IOCTL_INTERNAL_USB_GET_HUB_COUNT\n"));
{
PULONG count;
//
// bump the count and complete the Irp
//
count = irpStack->Parameters.Others.Argument1;
ASSERT(count != NULL);
(*count)++;
ntStatus = STATUS_SUCCESS;
}
break;
case IOCTL_INTERNAL_USB_GET_BUS_INFO:
{
PUSB_BUS_NOTIFICATION busInfo;
USBD_KdPrint(0,
("'WARNING: Driver using obsolete IOCTL (IOCTL_INTERNAL_USB_GET_BUS_INFO) - get JD\n"));
busInfo = irpStack->Parameters.Others.Argument1;
// bw in bit times (bits/ms)
busInfo->TotalBandwidth = 12000;
busInfo->ConsumedBandwidth =
DeviceExtension->HcdGetConsumedBW(
DeviceExtension->HcdDeviceObject);
busInfo->ControllerNameLength =
DeviceExtension->DeviceLinkUnicodeString.Length;
}
ntStatus = STATUS_SUCCESS;
break;
case IOCTL_INTERNAL_USB_GET_CONTROLLER_NAME:
{
PUSB_HUB_NAME name;
ULONG length;
USBD_KdPrint(1, ("'IOCTL_INTERNAL_USB_GET_CONTROLLER_NAME\n"));
name = (PUSB_HUB_NAME) irpStack->Parameters.Others.Argument1;
length = PtrToUlong( irpStack->Parameters.Others.Argument2 );
USBD_KdPrint(1, ("'length = %d %x\n", length, &DeviceExtension->DeviceLinkUnicodeString));
name->ActualLength = DeviceExtension->DeviceLinkUnicodeString.Length;
if (length > DeviceExtension->DeviceLinkUnicodeString.Length) {
length = DeviceExtension->DeviceLinkUnicodeString.Length;
}
RtlCopyMemory(&name->HubName[0],
&DeviceExtension->DeviceLinkUnicodeString.Buffer[0],
length);
}
ntStatus = STATUS_SUCCESS;
break;
case IOCTL_INTERNAL_USB_GET_ROOTHUB_PDO:
USBD_KdPrint(3, ("'IOCTL_INTERNAL_USB_GET_ROOTHUB_PDO\n"));
{
PDEVICE_OBJECT *rootHubPdo, *hcdTopOfStackDeviceObject;
rootHubPdo = irpStack->Parameters.Others.Argument1;
hcdTopOfStackDeviceObject =
irpStack->Parameters.Others.Argument2;
ASSERT(hcdTopOfStackDeviceObject != NULL);
ASSERT(rootHubPdo != NULL);
*rootHubPdo = DeviceExtension->RootHubPDO;
*hcdTopOfStackDeviceObject =
DeviceExtension->HcdTopOfStackDeviceObject;
ntStatus = STATUS_SUCCESS;
}
break;
case IOCTL_INTERNAL_USB_GET_HUB_NAME:
USBD_KdPrint(3, ("'IOCTL_INTERNAL_USB_GET_HUB_NAME\n"));
ntStatus = USBD_GetHubName(DeviceExtension, Irp);
break;
case IOCTL_INTERNAL_USB_SUBMIT_URB:
USBD_KdPrint(3,
("'IOCTL_INTERNAL_USB_SUBMIT_URB to root hub PDO\n"));
// pass these along to the bus
IoCopyCurrentIrpStackLocationToNext(Irp);
ntStatus = IoCallDriver(DeviceExtension->HcdDeviceObject, Irp);
// this is a special case -- we tell the HCD not to complete it
// because he will see it agian passed to his FDO
//
// the only code to pass thru this case should be urb requests
// submitted to the root hub.
goto USBD_PdoDispatch_Done;
break;
case IOCTL_INTERNAL_USB_SUBMIT_IDLE_NOTIFICATION:
if (DeviceExtension->IsPIIX3or4 && !DeviceExtension->WakeSupported) {
USBD_KdPrint(1, ("'Idle request, HC can NOT idle, fail.\n"));
ntStatus = STATUS_NOT_SUPPORTED;
} else {
USBD_KdPrint(1, ("'Idle request, HC can idle.\n"));
ntStatus = USBD_IdleNotificationRequest(DeviceExtension, Irp);
goto USBD_PdoDispatch_Done; // Don't complete the IRP.
}
break;
default:
ntStatus = STATUS_INVALID_PARAMETER;
USBD_KdPrint(1,
("Warning: Invalid IRP_MJ_INTERNAL_DEVICE_CONTROL passed to USBD\n"));
} // switch, ioControlCode
break;
case IRP_MJ_PNP:
// thie function will complete request if needed
ntStatus = USBD_PdoPnP(DeviceObject,
Irp,
DeviceExtension);
goto USBD_PdoDispatch_Done;
break;
case IRP_MJ_POWER:
// thie function will complete request if needed
ntStatus = USBD_PdoPower(DeviceObject,
Irp,
DeviceExtension);
goto USBD_PdoDispatch_Done;
break;
case IRP_MJ_SYSTEM_CONTROL:
USBD_KdPrint(3, ("'HC PDO IRP_MJ_SYSTEM_CONTROL\n"));
default:
ntStatus = STATUS_NOT_SUPPORTED;
} /* switch, irpStack->MajorFunction */
Irp->IoStatus.Status = ntStatus;
USBD_IoCompleteRequest (Irp,
IO_NO_INCREMENT);
USBD_PdoDispatch_Done:
USBD_KdPrint(3, ("'exit USBD_PdoDispatch, ntStatus = %x\n", ntStatus));
return ntStatus;
}
NTSTATUS
USBD_PnPIrp_Complete(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Context
)
/*++
Routine Description:
This routine is called when the port driver completes an IRP.
Arguments:
DeviceObject - Pointer to the device object for the class device.
Irp - Irp completed.
Context - Driver defined context.
Return Value:
The function value is the final status from the operation.
--*/
{
NTSTATUS ntStatus = STATUS_SUCCESS;
NTSTATUS irpStatus;
PIO_STACK_LOCATION irpStack;
PUSBD_EXTENSION deviceExtension;
USBD_KdPrint(3, ("'enter USBD_PnPIrp_Complete\n"));
deviceExtension = (PUSBD_EXTENSION) Context;
irpStack = IoGetCurrentIrpStackLocation (Irp);
irpStatus = Irp->IoStatus.Status;
USBD_ASSERT(irpStack->MajorFunction == IRP_MJ_PNP);
USBD_ASSERT(irpStack->MinorFunction == IRP_MN_START_DEVICE);
USBD_KdPrint(3, ("'IRP_MN_START_DEVICE (fdo), completion routine\n"));
// signal the start device dispatch to finsh
KeSetEvent(&deviceExtension->PnpStartEvent,
1,
FALSE);
// defer completion
ntStatus = STATUS_MORE_PROCESSING_REQUIRED;
USBD_KdPrint(3, ("'exit USBD_PnPIrp_Complete %x\n", irpStatus));
return ntStatus;
}
NTSTATUS
USBD_FdoPower(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PUSBD_EXTENSION DeviceExtension,
IN PBOOLEAN IrpNeedsCompletion
)
/*++
Routine Description:
Process the Power IRPs sent to the FDO for the host controller.
Power States for the USB host controller
D0 - On.
D1/D2 - Suspend.
D3 - Off.
Arguments:
DeviceObject - pointer to a hcd device object (FDO)
Irp - pointer to an I/O Request Packet
Return Value:
NT status code
--*/
{
PIO_STACK_LOCATION irpStack;
NTSTATUS ntStatus = STATUS_SUCCESS;
BOOLEAN hookIt = FALSE;
BOOLEAN biosHandback = FALSE;
KIRQL irql;
USBD_KdPrint(3, ("'HC FDO IRP_MJ_POWER\n"));
irpStack = IoGetCurrentIrpStackLocation (Irp);
*IrpNeedsCompletion = FALSE;
switch (irpStack->MinorFunction) {
case IRP_MN_WAIT_WAKE:
USBD_KdPrint(3, ("'IRP_MN_WAIT_WAKE\n"));
//
// someone is enabling us for wakeup
//
// pass this on to our PDO
goto USBD_FdoPowerPassIrp;
break;
case IRP_MN_SET_POWER:
{
switch (irpStack->Parameters.Power.Type) {
case SystemPowerState:
{
POWER_STATE powerState;
USBD_KdPrint(1,
(" IRP_MJ_POWER HC fdo(%x) MN_SET_POWER(SystemPowerState S%x)\n",
DeviceObject, irpStack->Parameters.Power.State.SystemState - 1));
switch (irpStack->Parameters.Power.State.SystemState) {
case PowerSystemWorking:
//
// go to 'ON'
//
powerState.DeviceState = PowerDeviceD0;
break;
case PowerSystemShutdown:
//
// Shutdown -- if we need to hand contol back to HC
// then we finish here
//
USBD_KdPrint(1, (" Shutdown HC Detected\n"));
// flag should only be true if we
// shutdown to DOS (ie Win98)
ntStatus =
DeviceExtension->HcdSetDevicePowerState(
DeviceObject,
Irp,
0);
biosHandback = TRUE;
DeviceExtension->Flags |= USBDFLAG_HCD_SHUTDOWN;
powerState.DeviceState = PowerDeviceD3;
break;
case PowerSystemHibernate:
USBD_KdPrint(1, (" Hibernate HC Detected\n"));
powerState.DeviceState = PowerDeviceD3;
break;
case PowerSystemSleeping1:
case PowerSystemSleeping2:
case PowerSystemSleeping3:
//
// Let HCD know there is a suspend coming.
//
USBD_KdPrint(1, (" Suspend HC Detected\n"));
ntStatus =
DeviceExtension->HcdSetDevicePowerState(
DeviceObject,
Irp,
0);
// Fall through
default:
//
// our policy is to enter D3 unless we are enabled for
// remote wakeup
//
if (DeviceExtension->HcWakeFlags & HC_ENABLED_FOR_WAKEUP) {
SYSTEM_POWER_STATE requestedSystemState;
requestedSystemState =
irpStack->Parameters.Power.State.SystemState;
//
// based on the system power state
// request a setting to the appropriate
// Dx state.
//
powerState.DeviceState =
DeviceExtension->HcDeviceCapabilities.DeviceState[
requestedSystemState];
USBD_KdPrint(1, (" Requested HC State before fixup is S%x -> D%d\n",
requestedSystemState - 1,
powerState.DeviceState - 1));
//
// This table is created by PDO of the PCI driver and
// describes what the PCI driver can do for us.
// It is entirely possible that when the controller is in
// the D3 state that we can wake the system.
//
// It is also entirely possible that this table might not
// support a D state at the current S state.
//
// All of the usb children support a D state for every S
// state. (We patched it up just that way when we gave
// the capablilities to our PDO child. However, the host
// controller might not have one. So if this is
// unsupported, then we need to change it do D3.
//
if (requestedSystemState > DeviceExtension->HcDeviceCapabilities.SystemWake &&
PowerDeviceUnspecified == powerState.DeviceState) {
powerState.DeviceState = PowerDeviceD3;
} else {
USBD_ASSERT(powerState.DeviceState != PowerDeviceUnspecified);
}
} else {
//
// wakeup not enabled, just go in to the 'OFF' state.
//
USBD_KdPrint(1, ("HC not enabled for wakeup, goto D3.\n"));
powerState.DeviceState = PowerDeviceD3;
}
} //irpStack->Parameters.Power.State.SystemState
USBD_KdPrint(1,
(" Requested HC State after fixup is D%d\n", powerState.DeviceState-1));
//
// are we already in this state?
//
//
// Note: if we get a D3 request before we are started
// we don't need to pass the irp down to turn us off
// we consider the controller initially off until we
// get start.
//
if (!biosHandback &&
powerState.DeviceState !=
DeviceExtension->HcCurrentDevicePowerState) {
if (powerState.DeviceState == PowerDeviceD0) {
KeAcquireSpinLock(&DeviceExtension->WaitWakeSpin,
&irql);
// see if we need to cancel a wake irp
// in the HC
if (DeviceExtension->HcWakeIrp) {
PIRP hcwakeirp;
hcwakeirp = DeviceExtension->HcWakeIrp;
KeReleaseSpinLock(&DeviceExtension->WaitWakeSpin,
irql);
USBD_KdPrint(1, ("USBD_FdoPower, Set D0: Canceling Wake Irp (%x) on HC PDO\n", hcwakeirp));
IoCancelIrp(hcwakeirp);
} else {
KeReleaseSpinLock(&DeviceExtension->WaitWakeSpin,
irql);
}
}
// No,
// now allocate another irp and use PoCallDriver
// to send it to ourselves
IoMarkIrpPending(Irp);
DeviceExtension->PowerIrp = Irp;
USBD_KdPrint(1,
(" Requesting HC State is D%d\n", powerState.DeviceState-1));
ntStatus =
PoRequestPowerIrp(DeviceExtension->
HcdPhysicalDeviceObject,
IRP_MN_SET_POWER,
powerState,
USBD_DeferPoRequestCompletion,
DeviceExtension,
NULL);
USBD_KdPrint(3, ("'PoRequestPowerIrp returned %x\n",
ntStatus));
} else {
//
// now complete the original request
//
IoCopyCurrentIrpStackLocationToNext(Irp);
PoStartNextPowerIrp(Irp);
ntStatus =
PoCallDriver(DeviceExtension->HcdTopOfPdoStackDeviceObject,
Irp);
}
}
break;
case DevicePowerState:
USBD_KdPrint(1,
(" IRP_MJ_POWER HC fdo(%x) MN_SET_POWER(DevicePowerState D%x)\n",
DeviceObject,
irpStack->Parameters.Power.State.DeviceState - 1));
//
// Copy parameters now in case the HcdSetDevicePowerState
// function sets a completion routine.
//
IoCopyCurrentIrpStackLocationToNext(Irp);
// If the HC is already in the requested power state
// then don't call the HcdSetDevicePowerState function.
// NOTE:
// if the HC is not started the power state should be D3
// we will ignore any requests from the OS to put
// it in any other state
#if DBG
if (!(DeviceExtension->Flags & USBDFLAG_HCD_STARTED) &&
irpStack->Parameters.Power.State.DeviceState == PowerDeviceD0) {
USBD_KdPrint(1,
(" OS requesting to power up a STOPPED device\n"));
}
#endif
if (DeviceExtension->HcCurrentDevicePowerState !=
irpStack->Parameters.Power.State.DeviceState &&
(DeviceExtension->Flags & USBDFLAG_HCD_STARTED)) {
ntStatus =
DeviceExtension->HcdSetDevicePowerState(
DeviceObject,
Irp,
irpStack->Parameters.Power.State.DeviceState);
DeviceExtension->HcCurrentDevicePowerState =
irpStack->Parameters.Power.State.DeviceState;
}
PoStartNextPowerIrp(Irp);
ntStatus =
PoCallDriver(DeviceExtension->HcdTopOfPdoStackDeviceObject,
Irp);
break;
} /* case irpStack->Parameters.Power.Type */
}
break; /* IRP_MN_SET_POWER */
case IRP_MN_QUERY_POWER:
USBD_KdPrint(1,
(" IRP_MJ_POWER HC fdo(%x) MN_QUERY_POWER\n",
DeviceObject));
// IrpAssert: Set IRP status before passing this IRP down.
Irp->IoStatus.Status = STATUS_SUCCESS;
//
// according to busdd QUERY_POWER messages are not
// sent down the driver stack
//
IoCopyCurrentIrpStackLocationToNext(Irp);
PoStartNextPowerIrp(Irp);
ntStatus =
PoCallDriver(DeviceExtension->HcdTopOfPdoStackDeviceObject,
Irp);
break; /* IRP_MN_QUERY_POWER */
default:
USBD_FdoPowerPassIrp:
USBD_KdPrint(1,
(" IRP_MJ_POWER fdo(%x) MN_%d\n",
DeviceObject, irpStack->MinorFunction));
//
// All unhandled PnP messages are passed on to the PDO
//
IoCopyCurrentIrpStackLocationToNext(Irp);
//
// All PNP_POWER POWER messages get passed to TopOfStackDeviceObject
// and some are handled in the completion routine
//
// pass on to our PDO
PoStartNextPowerIrp(Irp);
ntStatus =
PoCallDriver(DeviceExtension->HcdTopOfPdoStackDeviceObject,
Irp);
} /* irpStack->MinorFunction */
USBD_KdPrint(3, ("'exit USBD_FdoPower 0x%x\n", ntStatus));
return ntStatus;
}
NTSTATUS
USBD_GetHubName(
PUSBD_EXTENSION DeviceExtension,
PIRP Irp
)
{
PUNICODE_STRING deviceNameUnicodeString;
NTSTATUS status = STATUS_SUCCESS;
PUSB_ROOT_HUB_NAME outputBuffer;
ULONG outputBufferLength;
PIO_STACK_LOCATION irpStack;
irpStack = IoGetCurrentIrpStackLocation (Irp);
outputBufferLength =
irpStack->Parameters.DeviceIoControl.OutputBufferLength;
outputBuffer = Irp->AssociatedIrp.SystemBuffer;
deviceNameUnicodeString =
&DeviceExtension->RootHubSymbolicLinkName;
if (NT_SUCCESS(status)) {
//
// make sure there is enough room for the length,
// string and the NULL
//
ULONG length, offset=0;
WCHAR *pwch;
// assuming the string is \n\name strip of '\n\' where
// n is zero or more chars
pwch = &deviceNameUnicodeString->Buffer[0];
// Under NT, if the controller is banged out in DeviceManager,
// this will be NULL.
if (!pwch) {
status = STATUS_UNSUCCESSFUL;
goto USBD_GetHubNameExit;
}
USBD_ASSERT(*pwch == '\\');
if (*pwch == '\\') {
pwch++;
while (*pwch != '\\' && *pwch) {
pwch++;
}
USBD_ASSERT(*pwch == '\\');
if (*pwch == '\\') {
pwch++;
}
offset = (ULONG)((PUCHAR)pwch -
(PUCHAR)&deviceNameUnicodeString->Buffer[0]);
}
length = deviceNameUnicodeString->Length - offset;
RtlZeroMemory(outputBuffer, outputBufferLength);
if (outputBufferLength >= length +
sizeof(USB_ROOT_HUB_NAME)) {
RtlCopyMemory(&outputBuffer->RootHubName[0],
&deviceNameUnicodeString->Buffer[offset/2],
length);
Irp->IoStatus.Information = length+
sizeof(USB_ROOT_HUB_NAME);
outputBuffer->ActualLength = (ULONG)Irp->IoStatus.Information;
status = STATUS_SUCCESS;
} else {
if (outputBufferLength >= sizeof(USB_ROOT_HUB_NAME)) {
outputBuffer->ActualLength =
length + sizeof(USB_ROOT_HUB_NAME);
Irp->IoStatus.Information =
sizeof(ULONG);
status = STATUS_SUCCESS;
} else {
status = STATUS_BUFFER_TOO_SMALL;
}
}
}
USBD_GetHubNameExit:
return status;
}
#ifdef DRM_SUPPORT
/*****************************************************************************
* USBC_FdoSetContentId
*****************************************************************************
*
*/
NTSTATUS
USBD_FdoSetContentId
(
IN PIRP irp,
IN PKSP_DRMAUDIOSTREAM_CONTENTID pKsProperty,
IN PKSDRMAUDIOSTREAM_CONTENTID pvData
)
{
USBD_PIPE_HANDLE hPipe;
NTSTATUS status;
PAGED_CODE();
ASSERT(irp);
ASSERT(pKsProperty);
ASSERT(pvData);
status = STATUS_SUCCESS;
hPipe = pKsProperty->Context;
// ContentId = pvData->ContentId;
ASSERT(USBD_ValidatePipe(hPipe));
// If this driver sents content anywhere, then it should advise DRM. E.g.:
// status = pKsProperty->DrmForwardContentToDeviceObject(ContentId, DeviceObject, Context);
return status;
}
#endif
NTSTATUS
USBD_FdoDispatch(
PDEVICE_OBJECT DeviceObject,
PIRP Irp,
PUSBD_EXTENSION DeviceExtension,
PBOOLEAN IrpNeedsCompletion
)
/*++
Routine Description:
Disptach routine for Irps sent to the FDO for the host controller. some
Irps re handled by USBD, most are handled by the host controller driver.
Arguments:
Return Value:
None
--*/
{
PIO_STACK_LOCATION irpStack;
PDEVICE_RELATIONS DeviceRelations = NULL;
NTSTATUS ntStatus = STATUS_SUCCESS;
PURB urb;
KIRQL irql;
USBD_KdPrint(3, ("'enter USBD_FdoDispatch\n"));
irpStack = IoGetCurrentIrpStackLocation (Irp);
switch (irpStack->MajorFunction) {
case IRP_MJ_DEVICE_CONTROL:
USBD_KdPrint(3, ("'IRP_MJ_DEVICE_CONTROL\n"));
switch (irpStack->Parameters.DeviceIoControl.IoControlCode) {
#ifdef DRM_SUPPORT
case IOCTL_KS_PROPERTY:
USBD_KdPrint(1, ("'IOCTL_KS_PROPERTY\n"));
ntStatus = KsPropertyHandleDrmSetContentId(Irp, USBD_FdoSetContentId);
Irp->IoStatus.Status = ntStatus;
if (NT_SUCCESS(ntStatus) || (STATUS_PROPSET_NOT_FOUND == ntStatus)) {
*IrpNeedsCompletion = TRUE;
} else {
*IrpNeedsCompletion = FALSE;
USBD_IoCompleteRequest(Irp, IO_NO_INCREMENT);
}
break;
#endif
case IOCTL_USB_DIAGNOSTIC_MODE_ON:
DeviceExtension->DiagnosticMode = TRUE;
*IrpNeedsCompletion = FALSE;
USBD_KdPrint(1, ("'IOCTL_USB_DIAGNOSTIC_MODE_ON\n"));
ntStatus =
Irp->IoStatus.Status = STATUS_SUCCESS;
USBD_IoCompleteRequest (Irp,
IO_NO_INCREMENT);
break;
case IOCTL_USB_DIAGNOSTIC_MODE_OFF:
DeviceExtension->DiagnosticMode = FALSE;
*IrpNeedsCompletion = FALSE;
USBD_KdPrint(1, ("'IOCTL_USB_DIAGNOSTIC_MODE_OFF\n"));
ntStatus =
Irp->IoStatus.Status = STATUS_SUCCESS;
USBD_IoCompleteRequest (Irp,
IO_NO_INCREMENT);
break;
case IOCTL_USB_DIAG_IGNORE_HUBS_ON:
DeviceExtension->DiagIgnoreHubs = TRUE;
*IrpNeedsCompletion = FALSE;
USBD_KdPrint(1, ("'IOCTL_USB_DIAG_IGNORE_HUBS_ON\n"));
ntStatus =
Irp->IoStatus.Status = STATUS_SUCCESS;
USBD_IoCompleteRequest (Irp,
IO_NO_INCREMENT);
break;
case IOCTL_USB_DIAG_IGNORE_HUBS_OFF:
DeviceExtension->DiagIgnoreHubs = FALSE;
*IrpNeedsCompletion = FALSE;
USBD_KdPrint(1, ("'IOCTL_USB_DIAG_IGNORE_HUBS_OFF\n"));
ntStatus =
Irp->IoStatus.Status = STATUS_SUCCESS;
USBD_IoCompleteRequest (Irp,
IO_NO_INCREMENT);
break;
case IOCTL_GET_HCD_DRIVERKEY_NAME:
*IrpNeedsCompletion = FALSE;
USBD_KdPrint(3, ("'IOCTL_GET_HCD_DRIVERKEY_NAME\n"));
{
PIO_STACK_LOCATION ioStack;
PUSB_HCD_DRIVERKEY_NAME outputBuffer;
ULONG outputBufferLength, length;
ULONG adjustedDriverKeyNameSize;
//
// Get a pointer to the current location in the Irp. This is where
// the function codes and parameters are located.
//
ioStack = IoGetCurrentIrpStackLocation(Irp);
//
// Get the pointer to the input/output buffer and it's length
//
outputBufferLength = ioStack->Parameters.DeviceIoControl.OutputBufferLength;
outputBuffer = (PUSB_HCD_DRIVERKEY_NAME) Irp->AssociatedIrp.SystemBuffer;
Irp->IoStatus.Information = 0x0;
// find the PDO
if (outputBufferLength >= sizeof(USB_HCD_DRIVERKEY_NAME)) {
// we have the PDO, now attempt to
// get the devnode name and return it
// the size of the buffer up to, but not including, the
// DriverKeyName field
adjustedDriverKeyNameSize =
sizeof(USB_HCD_DRIVERKEY_NAME) -
sizeof(outputBuffer->DriverKeyName);
length = outputBufferLength - adjustedDriverKeyNameSize;
ntStatus = IoGetDeviceProperty(
DeviceExtension->HcdPhysicalDeviceObject,
DevicePropertyDriverKeyName,
length,
outputBuffer->DriverKeyName,
&length);
outputBuffer->ActualLength =
length + adjustedDriverKeyNameSize;
if (NT_SUCCESS(ntStatus)) {
// fill in information field with the length actually copied
if (outputBuffer->ActualLength > outputBufferLength) {
// we just copied as much as we could
Irp->IoStatus.Information = outputBufferLength;
} else {
// user buffer contains the whole thing
Irp->IoStatus.Information = outputBuffer->ActualLength;
}
}
else if (ntStatus == STATUS_BUFFER_TOO_SMALL) {
ntStatus = STATUS_SUCCESS;
outputBuffer->DriverKeyName[0] = L'\0';
Irp->IoStatus.Information = sizeof(USB_HCD_DRIVERKEY_NAME);
}
else {
// propagate the ntStatus value up
;
}
} else {
ntStatus = STATUS_BUFFER_TOO_SMALL;
}
Irp->IoStatus.Status = ntStatus;
USBD_IoCompleteRequest (Irp,
IO_NO_INCREMENT);
}
break;
case IOCTL_USB_GET_ROOT_HUB_NAME:
*IrpNeedsCompletion = FALSE;
USBD_KdPrint(3, ("'IOCTL_USB_GET_ROOT_HUB_NAME\n"));
ntStatus =
Irp->IoStatus.Status = USBD_GetHubName(DeviceExtension, Irp);
USBD_IoCompleteRequest (Irp,
IO_NO_INCREMENT);
break;
default:
USBD_KdPrint(3, ("'USBD not handling ioctl\n"));
ntStatus = Irp->IoStatus.Status;
*IrpNeedsCompletion = TRUE;
} // switch (irpStack->Parameters.DeviceIoControl.IoControlCode)
break; // IRP_MJ_DEVICE_CONTROL
case IRP_MJ_SYSTEM_CONTROL:
*IrpNeedsCompletion = FALSE;
USBD_KdPrint(3, ("'IRP_MJ_SYSTEM_CONTROL\n"));
IoCopyCurrentIrpStackLocationToNext(Irp);
ntStatus = IoCallDriver(
DeviceExtension->HcdTopOfPdoStackDeviceObject,
Irp);
break; // IRP_MJ_DEVICE_CONTROL
case IRP_MJ_INTERNAL_DEVICE_CONTROL:
switch(irpStack->Parameters.DeviceIoControl.IoControlCode) {
//
// This is where USBD pre-processes urbs passed to the
// host controller
//
case IOCTL_INTERNAL_USB_SUBMIT_URB:
USBD_KdPrint(3, ("'IOCTL_INTERNAL_USB_SUBMIT_URB\n"));
urb = irpStack->Parameters.Others.Argument1;
// The URB handler will mark the IRP pending if it
// has to pass it on, otherwise, we complete it here
// with the appropriate error
// a quick check of the function code will tell us if
// the urb if for HCD only
if ((urb->UrbHeader.Function & HCD_URB_FUNCTION) ||
(urb->UrbHeader.Function & HCD_NO_USBD_CALL)) {
// This is an HCD command, clear the renter bit
urb->UrbHeader.Function &= ~HCD_NO_USBD_CALL;
*IrpNeedsCompletion = TRUE;
} else {
ntStatus = USBD_ProcessURB(DeviceObject,
Irp,
urb,
IrpNeedsCompletion);
if (*IrpNeedsCompletion && NT_ERROR(ntStatus)) {
// the irp is marked pending
// but we have an error, reset
// the pending flag here so the HCD does
// not have to deal with this request
USBD_KdBreak(("Failing URB Request\n"));
*IrpNeedsCompletion = FALSE;
}
}
if (!*IrpNeedsCompletion) {
// USBD needs to complete the irp.
USBD_KdPrint(3, ("'USBD Completeing URB\n"));
Irp->IoStatus.Status = ntStatus;
USBD_IoCompleteRequest (Irp,
IO_NO_INCREMENT);
}
break;
case IOCTL_INTERNAL_USB_GET_BUSGUID_INFO:
{
// return the standard USB GUID
PPNP_BUS_INFORMATION busInfo;
*IrpNeedsCompletion = FALSE;
USBD_KdPrint(3, ("'IOCTL_INTERNAL_USB_GET_BUSGUID_INFO\n"));
busInfo = ExAllocatePoolWithTag(PagedPool,
sizeof(PNP_BUS_INFORMATION),
USBD_TAG);
if (busInfo == NULL) {
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
} else {
busInfo->BusTypeGuid = GUID_BUS_TYPE_USB;
busInfo->LegacyBusType = PNPBus;
busInfo->BusNumber = 0;
Irp->IoStatus.Information = (ULONG_PTR) busInfo;
ntStatus = STATUS_SUCCESS;
}
USBD_IoCompleteRequest (Irp,
IO_NO_INCREMENT);
}
break;
default:
USBD_KdPrint(3, ("'USBD not handling internal ioctl\n"));
ntStatus = Irp->IoStatus.Status;
*IrpNeedsCompletion = TRUE;
} // switch (irpStack->Parameters.DeviceIoControl.IoControlCode)
break; // IRP_MJ_INTERNAL_DEVICE_CONTROL
case IRP_MJ_PNP:
switch (irpStack->MinorFunction) {
case IRP_MN_QUERY_PNP_DEVICE_STATE:
// pass on to host controllers PDO
*IrpNeedsCompletion = FALSE;
IoCopyCurrentIrpStackLocationToNext(Irp);
ntStatus =
IoCallDriver(DeviceExtension->HcdTopOfPdoStackDeviceObject,
Irp);
break;
case IRP_MN_QUERY_DEVICE_RELATIONS:
{
PDEVICE_OBJECT deviceObject;
USBD_KdPrint(1,
(" IRP_MN_QUERY_DEVICE_RELATIONS %x %x\n",
DeviceObject,
irpStack->Parameters.QueryDeviceRelations.Type));
ntStatus = STATUS_SUCCESS;
switch(irpStack->Parameters.QueryDeviceRelations.Type) {
case BusRelations:
// Don't use GETHEAP since OS will free and doesn't know about
// the trick GETHEAP does.
DeviceRelations=ExAllocatePoolWithTag(PagedPool,
sizeof(*DeviceRelations),
USBD_TAG);
if (!DeviceRelations) {
ntStatus=STATUS_INSUFFICIENT_RESOURCES;
break;
}
if (!DeviceExtension->RootHubPDO) {
PUSBD_EXTENSION pdoDeviceExtension;
ULONG index = 0;
UNICODE_STRING rootHubPdoUnicodeString;
do {
ntStatus =
USBD_InternalMakePdoName(&rootHubPdoUnicodeString,
index);
if (NT_SUCCESS(ntStatus)) {
ntStatus =
IoCreateDevice(DeviceExtension->DriverObject,
sizeof(PVOID),
&rootHubPdoUnicodeString,
FILE_DEVICE_BUS_EXTENDER,
0,
FALSE,
&deviceObject);
if (!NT_SUCCESS(ntStatus)) {
RtlFreeUnicodeString(&rootHubPdoUnicodeString);
}
index++;
}
} while (ntStatus == STATUS_OBJECT_NAME_COLLISION);
//
// now create the root hub device and symbolic link
//
if (NT_SUCCESS(ntStatus)) {
deviceObject->Flags |= DO_POWER_PAGABLE;
pdoDeviceExtension = deviceObject->DeviceExtension;
DeviceExtension->RootHubPDO = deviceObject;
RtlFreeUnicodeString(&rootHubPdoUnicodeString);
USBD_KdPrint(3, ("'Create Root Hub stacksize = %d\n",
DeviceObject->StackSize));
deviceObject->StackSize = DeviceObject->StackSize;
pdoDeviceExtension->TrueDeviceExtension
= DeviceExtension;
pdoDeviceExtension->Flags = 0;
deviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
ntStatus = STATUS_SUCCESS;
} else {
//
// failing to create the root hub
//
TEST_TRAP();
if (DeviceRelations) {
RETHEAP(DeviceRelations);
}
break;
}
}
//
// We support only one device (the root hub).
//
DeviceRelations->Count=1;
DeviceRelations->Objects[0]=DeviceExtension->RootHubPDO;
ObReferenceObject(DeviceExtension->RootHubPDO);
Irp->IoStatus.Information=(ULONG_PTR)DeviceRelations;
*IrpNeedsCompletion = FALSE;
Irp->IoStatus.Status = ntStatus;
USBD_KdPrint(1,
(" IRP_MN_QUERY_DEVICE_RELATIONS %x pass on %x\n",
DeviceObject,
irpStack->Parameters.QueryDeviceRelations.Type));
// pass it on
IoCopyCurrentIrpStackLocationToNext(Irp);
ntStatus =
IoCallDriver(DeviceExtension->HcdTopOfPdoStackDeviceObject,
Irp);
break;
case TargetDeviceRelation:
//
// this one gets passed on
//
USBD_KdPrint(1,
(" IRP_MN_QUERY_DEVICE_RELATIONS %x, TargetDeviceRelation\n",
DeviceObject));
// this PnP irp not handled by us
ntStatus = Irp->IoStatus.Status;
*IrpNeedsCompletion = TRUE;
break;
default:
//
// some other kind of relations
// pass this on
//
USBD_KdPrint(1,
(" IRP_MN_QUERY_DEVICE_RELATIONS %x, other relations\n",
DeviceObject));
*IrpNeedsCompletion = FALSE;
// pass it on
IoCopyCurrentIrpStackLocationToNext(Irp);
ntStatus =
IoCallDriver(DeviceExtension->HcdTopOfPdoStackDeviceObject,
Irp);
} /* case irpStack->Parameters.QueryDeviceRelations.Type */
}
break;
case IRP_MN_START_DEVICE:
{
USBD_KdPrint(3, ("'IRP_MN_START_DEVICE (fdo)\n"));
*IrpNeedsCompletion = FALSE;
KeInitializeEvent(&DeviceExtension->PnpStartEvent,
NotificationEvent,
FALSE);
USBD_KdPrint(3, ("'Set PnPIrp Completion Routine\n"));
IoCopyCurrentIrpStackLocationToNext(Irp);
IoSetCompletionRoutine(Irp,
USBD_PnPIrp_Complete,
// always pass FDO to completeion routine
DeviceExtension,
TRUE,
TRUE,
TRUE);
// pass on to host controllers PDO
ntStatus =
IoCallDriver(DeviceExtension->HcdTopOfPdoStackDeviceObject,
Irp);
if (ntStatus == STATUS_PENDING) {
KeWaitForSingleObject(
&DeviceExtension->PnpStartEvent,
Suspended,
KernelMode,
FALSE,
NULL);
ntStatus = Irp->IoStatus.Status;
}
if (NT_SUCCESS(ntStatus)) {
//
// irp completed by owner of PDO now start the HC
//
ntStatus =
DeviceExtension->HcdDeferredStartDevice(
DeviceExtension->HcdDeviceObject,
Irp);
// HC is now 'ON'
if (NT_SUCCESS(ntStatus)) {
DeviceExtension->HcCurrentDevicePowerState = PowerDeviceD0;
DeviceExtension->Flags |=USBDFLAG_HCD_STARTED;
}
}
#if DBG
else {
USBD_KdPrint(1,
(" Warning: Controller failed to start %x\n", ntStatus));
}
#endif
//
// we must complete this irp since we defrerred completion
// with the completion routine.
USBD_IoCompleteRequest(Irp,
IO_NO_INCREMENT);
}
break;
// Ken says take this out
// case IRP_MN_SURPRISE_REMOVAL:
// TEST_TRAP();
case IRP_MN_REMOVE_DEVICE:
USBD_KdPrint(3,
("'IRP_MN_REMOVE_DEVICE (fdo), remove HCD sym link\n"));
if (DeviceExtension->DeviceLinkUnicodeString.Buffer) {
IoDeleteSymbolicLink(
&DeviceExtension->DeviceLinkUnicodeString);
RtlFreeUnicodeString(&DeviceExtension->DeviceLinkUnicodeString);
DeviceExtension->DeviceLinkUnicodeString.Buffer = NULL;
}
USBD_KdPrint(1,
("'IRP_MN_REMOVE_DEVICE (fdo), remove root hub PDO\n"));
// note: we may not have a root hub PDO when we
// get created
if (DeviceExtension->RootHubPDO != NULL) {
USBD_KdPrint(1,
("'Deleting root hub PDO now.\n"));
IoDeleteDevice(DeviceExtension->RootHubPDO);
}
DeviceExtension->RootHubPDO = NULL;
// Fall through
case IRP_MN_QUERY_CAPABILITIES:
case IRP_MN_QUERY_REMOVE_DEVICE:
case IRP_MN_CANCEL_REMOVE_DEVICE:
case IRP_MN_QUERY_STOP_DEVICE:
case IRP_MN_CANCEL_STOP_DEVICE:
//
// we do the default handling of the in USBD, that is
// return success.
// irpAssert expects these to be set to STATUS_SUCCESS
//
// note: these may also be handled by HC
// and HCD will pass the irp down to the PDO
//
ntStatus = Irp->IoStatus.Status = STATUS_SUCCESS;
*IrpNeedsCompletion = TRUE;
break;
case IRP_MN_STOP_DEVICE:
USBD_KdPrint(1,
("'IRP_MN_STOP_DEVICE (fdo)\n"));
KeAcquireSpinLock(&DeviceExtension->WaitWakeSpin,
&irql);
// see if we need to cancel a wake irp
// in the HC
if (DeviceExtension->HcWakeIrp) {
PIRP hcwakeirp;
hcwakeirp = DeviceExtension->HcWakeIrp;
KeReleaseSpinLock(&DeviceExtension->WaitWakeSpin,
irql);
USBD_KdPrint(1, ("USBD_FdoDispatch, MN_STOP: Canceling Wake Irp (%x) on HC PDO\n", hcwakeirp));
IoCancelIrp(hcwakeirp);
} else {
KeReleaseSpinLock(&DeviceExtension->WaitWakeSpin,
irql);
}
// note: HCD will pass the irp down to the PDO
ntStatus = Irp->IoStatus.Status;
*IrpNeedsCompletion = TRUE;
break;
default:
// PnP **
// message not handled, rule is that the
// status in the irp is not touched
//
// note: HCD will pass the irp down to the PDO
ntStatus = Irp->IoStatus.Status;
*IrpNeedsCompletion = TRUE;
} // switch (irpStack->MinorFunction)
break; // IRP_MJ_PNP
case IRP_MJ_POWER:
ntStatus = USBD_FdoPower(DeviceObject,
Irp,
DeviceExtension,
IrpNeedsCompletion);
break; // IRP_MJ_POWER
default:
//
// HCD irp not handled here
//
ntStatus = Irp->IoStatus.Status;
*IrpNeedsCompletion = TRUE;
} // switch (irpStack->MajorFunction)
return ntStatus;
}
VOID
USBD_CompleteRequest(
PIRP Irp,
CCHAR PriorityBoost
)
/*++
Routine Description:
Entry point called by HCD to complete an Irp.
Arguments:
Return Value:
NT status code.
--*/
{
PURB urb;
NTSTATUS ntStatus;
// USHORT function;
PHCD_URB hcdUrb;
PIO_STACK_LOCATION irpStack;
USBD_KdPrint(3, ("' enter USBD_CompleteRequest irp = %x\n", Irp));
irpStack = IoGetCurrentIrpStackLocation (Irp);
if (irpStack->MajorFunction != IRP_MJ_INTERNAL_DEVICE_CONTROL) {
goto USBD_CompleteRequest_Done;
}
urb = URB_FROM_IRP(Irp);
hcdUrb = (PHCD_URB) urb;
//
// Free any resources we allocated to handle this URB
//
while (hcdUrb) {
if (hcdUrb->UrbHeader.UsbdFlags & USBD_REQUEST_MDL_ALLOCATED) {
USBD_ASSERT(hcdUrb->HcdUrbCommonTransfer.TransferBufferMDL !=
NULL);
IoFreeMdl(hcdUrb->HcdUrbCommonTransfer.TransferBufferMDL);
}
if (hcdUrb->UrbHeader.UsbdFlags & USBD_REQUEST_IS_TRANSFER) {
hcdUrb = hcdUrb->HcdUrbCommonTransfer.UrbLink;
} else {
// only have linkage if this is a transfer.
break;
}
}
//
// If the irp completed with no error code but the URB has an
// error, map the error in the urb to an NT error code in the irp
// before the irp is completed.
//
// pass original status to USBD_MapError
ntStatus = Irp->IoStatus.Status;
// ntStatus now set to new 'mapped' error code
ntStatus = Irp->IoStatus.Status =
USBD_MapError_UrbToNT(urb, ntStatus);
USBD_KdPrint(3,
("' exit USBD_CompleteRequest URB STATUS = (0x%x) NT STATUS = (0x%x)\n",
urb->UrbHeader.Status, ntStatus));
USBD_CompleteRequest_Done:
USBD_IoCompleteRequest (Irp,
PriorityBoost);
return;
}
#if 0
__declspec(dllexport)
PUSBD_INTETRFACE_INFORMATION
USBD_GetInterfaceInformation(
IN PURB Urb,
IN UCHAR InterfaceNumber
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
PUSB_INTERFACE_INFORMATION foundInterface = NULL;
PUCHAR pch;
pch = &Urb->UrbSelectConfiguration.Interface;
while (pch - (PUCHAR)urb < Urb->SelectConfiguration.Length) {
interface = (PUSBD_INTERFACE_INFORMATION) pch;
if (interface->InterfaceNumber == InterfaceNumber) {
foundInterface = interface;
}
pch += interface->Length;
}
return foundInterface;
}
#endif
VOID
USBD_WaitDeviceMutex(
PDEVICE_OBJECT RootHubPDO
)
/*++
Routine Description:
Arguments:
Return Value:
interface descriptor or NULL.
--*/
{
PUSBD_EXTENSION deviceExtension;
PAGED_CODE();
deviceExtension = GET_DEVICE_EXTENSION(RootHubPDO);
USBD_WaitForUsbDeviceMutex(deviceExtension);
}
VOID
USBD_FreeDeviceMutex(
PDEVICE_OBJECT RootHubPDO
)
/*++
Routine Description:
Arguments:
Return Value:
interface descriptor or NULL.
--*/
{
PUSBD_EXTENSION deviceExtension;
PAGED_CODE();
deviceExtension = GET_DEVICE_EXTENSION(RootHubPDO);
USBD_ReleaseUsbDeviceMutex(deviceExtension);
}
//
// these apis are used to support the proprietary OEM
// no power suspend mode. (IBM APTIVA)
//
DEVICE_POWER_STATE
USBD_GetSuspendPowerState(
PDEVICE_OBJECT DeviceObject
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
PUSBD_EXTENSION deviceExtension;
deviceExtension = GET_DEVICE_EXTENSION(DeviceObject);
return deviceExtension->SuspendPowerState;
}
VOID
USBD_SetSuspendPowerState(
PDEVICE_OBJECT DeviceObject,
DEVICE_POWER_STATE SuspendPowerState
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
PUSBD_EXTENSION deviceExtension;
deviceExtension = GET_DEVICE_EXTENSION(DeviceObject);
deviceExtension->SuspendPowerState =
SuspendPowerState;
}
VOID
USBD_RegisterHcFilter(
PDEVICE_OBJECT DeviceObject,
PDEVICE_OBJECT FilterDeviceObject
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
PUSBD_EXTENSION deviceExtension;
deviceExtension = GET_DEVICE_EXTENSION(DeviceObject);
deviceExtension->HcdTopOfStackDeviceObject = FilterDeviceObject;
}
VOID
USBD_RegisterHcDeviceCapabilities(
PDEVICE_OBJECT DeviceObject,
PDEVICE_CAPABILITIES DeviceCapabilities,
ROOT_HUB_POWER_FUNCTION *RootHubPower
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
PUSBD_EXTENSION deviceExtension;
LONG i;
PDEVICE_CAPABILITIES rhDeviceCapabilities;
PDEVICE_CAPABILITIES hcDeviceCapabilities;
BOOLEAN bWakeSupported = FALSE;
deviceExtension = GET_DEVICE_EXTENSION(DeviceObject);
deviceExtension->RootHubPower = RootHubPower;
//
// HcDeviceCapabilities are set by the PDO below us and are unchanageable.
// RootHubDeviceCapabilities are howver set by us to describe the power
// properties of the root hub, and should therefore be set appropriately,
// but based on the power properities of our parent.
//
deviceExtension->RootHubDeviceCapabilities =
deviceExtension->HcDeviceCapabilities = *DeviceCapabilities;
rhDeviceCapabilities = &deviceExtension->RootHubDeviceCapabilities;
hcDeviceCapabilities = &deviceExtension->HcDeviceCapabilities;
//
// We can wake any device in on the USB bus so long as it is of D2 or better.
//
rhDeviceCapabilities->DeviceWake = PowerDeviceD2;
rhDeviceCapabilities->WakeFromD2 = TRUE;
rhDeviceCapabilities->WakeFromD1 = TRUE;
rhDeviceCapabilities->WakeFromD0 = TRUE;
rhDeviceCapabilities->DeviceD2 = TRUE;
rhDeviceCapabilities->DeviceD1 = TRUE;
//
// We cannot wake the system for any system sleeping state deeper than that
// of RootHubDeviceCapabilites->SystemWake, but if this value is
// unspecified, then we can set it to Working.
//
USBD_ASSERT(rhDeviceCapabilities->SystemWake >= PowerSystemUnspecified &&
rhDeviceCapabilities->SystemWake <= PowerSystemMaximum);
rhDeviceCapabilities->SystemWake =
(PowerSystemUnspecified == rhDeviceCapabilities->SystemWake) ?
PowerSystemWorking :
rhDeviceCapabilities->SystemWake;
rhDeviceCapabilities->DeviceState[PowerSystemWorking] = PowerDeviceD0;
//
// For all values between PowerSystemSleeping1 and rhDeviceCaps->SystemWake
// we need to modify the power table.
//
// As long as we have power to the host controller we can give power to
// our children devices.
//
for (i=PowerSystemSleeping1; i < PowerSystemMaximum; i++) {
if (i > rhDeviceCapabilities->SystemWake) {
//
// For values above rhDeviceCaps->SystemWake, even our host controller
// should be set to D3.
//
if (PowerDeviceUnspecified == rhDeviceCapabilities->DeviceState[i]) {
rhDeviceCapabilities->DeviceState[i] = PowerDeviceD3;
}
// We know that for the host controller (or more correctly, the USB
// bus), D3 is not necessarily "OFF". If DeviceWake for the host
// controller is greater than or equal to D3, then we know that the
// USB bus has power at D3. Since most of the USB stack assumes
// that D3 == "OFF", we don't want to allow it to go to a lower
// power level than D2 if the USB bus will still have power at D3.
// We do this by setting the root hub's device state to D2 in this
// case.
if (rhDeviceCapabilities->DeviceState[i] == PowerDeviceD3 &&
rhDeviceCapabilities->DeviceState[i] <= hcDeviceCapabilities->DeviceWake) {
rhDeviceCapabilities->DeviceState[i] = PowerDeviceD2;
}
} else {
//
// We have some power so we can support low power on our bus
//
rhDeviceCapabilities->DeviceState[i] = PowerDeviceD2;
}
}
#if DBG
USBD_KdPrint(1, (" >>>>>> RH DeviceCaps\n"));
USBD_KdPrint(1, (" SystemWake = (%d)\n", rhDeviceCapabilities->SystemWake));
USBD_KdPrint(1, (" DeviceWake = (D%d)\n",
rhDeviceCapabilities->DeviceWake-1));
for (i=PowerSystemUnspecified; i< PowerSystemHibernate; i++) {
USBD_KdPrint(1, (" Device State Map: sysstate %d = devstate 0x%x\n", i,
rhDeviceCapabilities->DeviceState[i]));
}
USBD_KdBreak(("'>>>>>> RH DeviceCaps\n"));
USBD_KdPrint(1, (" >>>>>> HC DeviceCaps\n"));
USBD_KdPrint(1, (" SystemWake = (%d)\n", hcDeviceCapabilities->SystemWake));
USBD_KdPrint(1, (" DeviceWake = (D%d)\n",
hcDeviceCapabilities->DeviceWake-1));
for (i=PowerSystemUnspecified; i< PowerSystemHibernate; i++) {
USBD_KdPrint(1, ("'Device State Map: sysstate %d = devstate 0x%x\n", i,
hcDeviceCapabilities->DeviceState[i]));
}
USBD_KdBreak((" >>>>>> HC DeviceCaps\n"));
#endif
// Spit out message on the debugger indicating whether the HC and RH
// will support wake, according to the mapping tables.
USBD_KdPrint(1, (" \n\tWake support summary for HC:\n\n"));
if (hcDeviceCapabilities->SystemWake <= PowerSystemWorking) {
USBD_KdPrint(1, (" USB controller can't wake machine because SystemWake does not support it.\n"));
} else {
for (i = PowerSystemSleeping1, bWakeSupported = FALSE; i <= hcDeviceCapabilities->SystemWake; i++) {
if (hcDeviceCapabilities->DeviceState[i] != PowerDeviceUnspecified &&
hcDeviceCapabilities->DeviceState[i] <= hcDeviceCapabilities->DeviceWake) {
bWakeSupported = TRUE;
USBD_KdPrint(1, (" USB controller can wake machine from S%x (maps to D%x).\n",
i - 1, hcDeviceCapabilities->DeviceState[i] - 1));
}
}
if (!bWakeSupported) {
USBD_KdPrint(1, (" USB controller can't wake machine because DeviceState table does not support it.\n"));
}
}
deviceExtension->WakeSupported = bWakeSupported;
USBD_KdPrint(1, (" Low System Power states mapped to USB suspend\n"));
}
NTSTATUS
USBD_InternalMakePdoName(
IN OUT PUNICODE_STRING PdoNameUnicodeString,
IN ULONG Index
)
/*++
Routine Description:
This service Creates a name for a PDO created by the HUB
Arguments:
Return Value:
--*/
{
PWCHAR nameBuffer = NULL;
WCHAR rootName[] = L"\\Device\\USBPDO-";
UNICODE_STRING idUnicodeString;
WCHAR buffer[32];
NTSTATUS ntStatus = STATUS_SUCCESS;
USHORT length;
length = sizeof(buffer)+sizeof(rootName);
//
// use ExAllocate because client will free it
//
nameBuffer = ExAllocatePoolWithTag(PagedPool, length, USBD_TAG);
if (nameBuffer) {
RtlCopyMemory(nameBuffer, rootName, sizeof(rootName));
RtlInitUnicodeString(PdoNameUnicodeString,
nameBuffer);
PdoNameUnicodeString->MaximumLength =
length;
RtlInitUnicodeString(&idUnicodeString,
&buffer[0]);
idUnicodeString.MaximumLength =
sizeof(buffer);
ntStatus = RtlIntegerToUnicodeString(
Index,
10,
&idUnicodeString);
if (NT_SUCCESS(ntStatus)) {
ntStatus = RtlAppendUnicodeStringToString(PdoNameUnicodeString,
&idUnicodeString);
}
USBD_KdPrint(3, ("'USBD_MakeNodeName string = %x\n",
PdoNameUnicodeString));
} else {
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
}
if (!NT_SUCCESS(ntStatus) && nameBuffer) {
ExFreePool(nameBuffer);
}
return ntStatus;
}
NTSTATUS
USBD_MakePdoName(
IN OUT PUNICODE_STRING PdoNameUnicodeString,
IN ULONG Index
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
return USBD_InternalMakePdoName(PdoNameUnicodeString, Index);
}
NTSTATUS
USBD_SymbolicLink(
BOOLEAN CreateFlag,
PUSBD_EXTENSION DeviceExtension
)
{
NTSTATUS ntStatus;
if (CreateFlag){
if (!DeviceExtension->RootHubPDO) {
ntStatus = STATUS_INVALID_DEVICE_REQUEST;
} else{
/*
* Create the symbolic link
*/
ntStatus = IoRegisterDeviceInterface(
DeviceExtension->RootHubPDO,
(LPGUID)&GUID_CLASS_USBHUB,
NULL,
&DeviceExtension->RootHubSymbolicLinkName);
}
if (NT_SUCCESS(ntStatus)) {
/*
* Now set the symbolic link for the association and store it..
*/
//ASSERT(ISPTR(pdoExt->name));
//
// (lonnym): Previously, the following call was being
// made with &DeviceExtension->RootHubPdoName passed as the
// second parameter.
// Code review this change, to see whether or not you still need
// to keep this information around.
//
// write the symbolic name to the registry
{
WCHAR hubNameKey[] = L"SymbolicName";
USBD_SetPdoRegistryParameter (
DeviceExtension->RootHubPDO,
&hubNameKey[0],
sizeof(hubNameKey),
&DeviceExtension->RootHubSymbolicLinkName.Buffer[0],
DeviceExtension->RootHubSymbolicLinkName.Length,
REG_SZ,
PLUGPLAY_REGKEY_DEVICE);
}
ntStatus =
IoSetDeviceInterfaceState(
&DeviceExtension->RootHubSymbolicLinkName, TRUE);
}
} else {
/*
* Disable the symbolic link
*/
ntStatus = IoSetDeviceInterfaceState(
&DeviceExtension->RootHubSymbolicLinkName, FALSE);
ExFreePool(DeviceExtension->RootHubSymbolicLinkName.Buffer);
DeviceExtension->RootHubSymbolicLinkName.Buffer = NULL;
}
return ntStatus;
}
NTSTATUS
USBD_RestoreDeviceX(
IN OUT PUSBD_DEVICE_DATA OldDeviceData,
IN OUT PUSBD_DEVICE_DATA NewDeviceData,
IN PDEVICE_OBJECT DeviceObject
)
/*++
Routine Description:
Service exported for use by the hub driver
Our goal here is to re-create the device and restore the configuration.
Arguments:
Return Value:
NT status code.
--*/
{
NTSTATUS ntStatus = STATUS_SUCCESS;
PUSBD_CONFIG configHandle;
USBD_STATUS usbdStatus;
USBD_KdPrint(3, ("'enter USBD_RestoreDevice \n"));
if (OldDeviceData == NULL ||
NewDeviceData == NULL) {
return STATUS_INVALID_PARAMETER;
}
configHandle = OldDeviceData->ConfigurationHandle;
if (RtlCompareMemory(&NewDeviceData->DeviceDescriptor,
&OldDeviceData->DeviceDescriptor,
sizeof(OldDeviceData->DeviceDescriptor)) ==
sizeof(OldDeviceData->DeviceDescriptor)) {
NewDeviceData->ConfigurationHandle = configHandle;
//
// all the config and interface information is still valid,
// we just need to restore the pipe handles
//
ntStatus =
USBD_InternalRestoreConfiguration(
NewDeviceData,
DeviceObject,
NewDeviceData->ConfigurationHandle);
} else {
//
// free up the old config
//
ntStatus = USBD_InternalCloseConfiguration(OldDeviceData,
DeviceObject,
&usbdStatus,
TRUE,
FALSE);
ntStatus = STATUS_UNSUCCESSFUL;
}
//
// free the old data regardless
//
RETHEAP(OldDeviceData);
USBD_KdPrint(3, ("'exit USBD_ReCreateDevice 0x%x\n", ntStatus));
return ntStatus;
}
NTSTATUS
USBD_RestoreDevice(
IN OUT PUSBD_DEVICE_DATA OldDeviceData,
IN OUT PUSBD_DEVICE_DATA NewDeviceData,
IN PDEVICE_OBJECT DeviceObject
)
/*++
Routine Description:
Service exported for use by the hub driver
Our goal here is to re-create the device and restore the configuration.
Arguments:
Return Value:
NT status code.
--*/
{
USBD_KdPrint(0,
("'WARNING: Driver using obsolete service enrty point (USBD_RestoreDevice) - get JD\n"));
return USBD_RestoreDeviceX(
OldDeviceData,
NewDeviceData,
DeviceObject);
}
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)) {
/*
RtlInitUnicodeString(&keyName, L"DeviceFoo");
ZwSetValueKey(handle,
&keyName,
0,
REG_DWORD,
ComplienceFlags,
sizeof(*ComplienceFlags));
*/
USBD_SetRegistryKeyValue(handle,
&keyNameUnicodeString,
Data,
DataLength,
KeyType);
ZwClose(handle);
}
USBD_KdPrint(3, ("' 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();
// InitializeObjectAttributes( &objectAttributes,
// KeyNameString,
// OBJ_CASE_INSENSITIVE,
// Handle,
// (PSECURITY_DESCRIPTOR) NULL );
//
// Create the key or open it, as appropriate based on the caller's
// wishes.
//
#if 0
ntStatus = ZwCreateKey( Handle,
DesiredAccess,
&objectAttributes,
0,
(PUNICODE_STRING) NULL,
REG_OPTION_VOLATILE,
&disposition );
#endif
ntStatus = ZwSetValueKey(Handle,
KeyNameUnicodeString,
0,
KeyType,
Data,
DataLength);
USBD_KdPrint(3, ("' ZwSetKeyValue = 0x%x\n", ntStatus));
return ntStatus;
}
NTSTATUS
USBD_QueryBusTime(
IN PDEVICE_OBJECT RootHubPdo,
IN PULONG CurrentFrame
)
/*++
Routine Description:
get the HCD current frame, callable at any IRQL
Arguments:
Return Value:
--*/
{
PUSBD_EXTENSION deviceExtension;
USBD_KdPrint(0,
("'WARNING: Driver using obsolete service enrty point (USBD_QueryBusTime) - get JD\n"));
deviceExtension = RootHubPdo->DeviceExtension;
deviceExtension = deviceExtension->TrueDeviceExtension;
return deviceExtension->HcdGetCurrentFrame(
deviceExtension->HcdDeviceObject,
CurrentFrame);
}
#else // USBD_DRIVER
// Obsolete functions that are still exported are stubbed out here.
ULONG
USBD_AllocateDeviceName(
PUNICODE_STRING DeviceNameUnicodeString
)
{
ULONG i = 0;
PAGED_CODE();
ASSERT(FALSE);
return i;
}
VOID
USBD_CompleteRequest(
PIRP Irp,
CCHAR PriorityBoost
)
{
ASSERT(FALSE);
return;
}
NTSTATUS
USBD_CreateDevice(
IN OUT PUSBD_DEVICE_DATA *DeviceData,
IN PDEVICE_OBJECT DeviceObject,
IN BOOLEAN DeviceIsLowSpeed,
IN ULONG MaxPacketSize_Endpoint0,
IN OUT PULONG DeviceHackFlags
)
{
USBD_KdPrint(0,
("'WARNING: Driver using obsolete service entry point (USBD_CreateDevice) - get JD\n"));
ASSERT(FALSE);
return STATUS_NOT_SUPPORTED;
}
BOOLEAN
USBD_Dispatch(
PDEVICE_OBJECT DeviceObject,
PIRP Irp,
PDEVICE_OBJECT *HcdDeviceObject,
NTSTATUS *NtStatus
)
{
BOOLEAN irpNeedsCompletion = TRUE;
ASSERT(FALSE);
return irpNeedsCompletion;
}
VOID
USBD_FreeDeviceMutex(
PDEVICE_OBJECT RootHubPDO
)
{
PAGED_CODE();
ASSERT(FALSE);
return;
}
VOID
USBD_FreeDeviceName(
ULONG DeviceNameHandle
)
{
PAGED_CODE();
ASSERT(FALSE);
return;
}
NTSTATUS
USBD_GetDeviceInformation(
IN PUSB_NODE_CONNECTION_INFORMATION DeviceInformation,
IN ULONG DeviceInformationLength,
IN PUSBD_DEVICE_DATA DeviceData
)
{
USBD_KdPrint(0,
(" WARNING: Driver using obsolete service enrty point (USBD_GetDeviceInformation) - get JD\n"));
ASSERT(FALSE);
return STATUS_NOT_SUPPORTED;
}
DEVICE_POWER_STATE
USBD_GetSuspendPowerState(
PDEVICE_OBJECT DeviceObject
)
{
ASSERT(FALSE);
return 0;
}
NTSTATUS
USBD_InitializeDevice(
IN PUSBD_DEVICE_DATA DeviceData,
IN PDEVICE_OBJECT DeviceObject,
IN OUT PUSB_DEVICE_DESCRIPTOR DeviceDescriptor,
IN ULONG DeviceDescriptorLength,
IN OUT PUSB_CONFIGURATION_DESCRIPTOR ConfigDescriptor,
IN ULONG ConfigDescriptorLength
)
{
USBD_KdPrint(0,
("'WARNING: Driver using obsolete service enrty point (USBD_InitializeDevice) - get JD\n"));
ASSERT(FALSE);
return STATUS_NOT_SUPPORTED;
}
NTSTATUS
USBD_MakePdoName(
IN OUT PUNICODE_STRING PdoNameUnicodeString,
IN ULONG Index
)
{
ASSERT(FALSE);
return STATUS_NOT_SUPPORTED;
}
NTSTATUS
USBD_QueryBusTime(
IN PDEVICE_OBJECT RootHubPdo,
IN PULONG CurrentFrame
)
{
USBD_KdPrint(0,
("'WARNING: Driver using obsolete service enrty point (USBD_QueryBusTime) - get JD\n"));
ASSERT(FALSE);
return STATUS_NOT_SUPPORTED;
}
VOID
USBD_RegisterHcDeviceCapabilities(
PDEVICE_OBJECT DeviceObject,
PDEVICE_CAPABILITIES DeviceCapabilities,
ROOT_HUB_POWER_FUNCTION *RootHubPower
)
{
ASSERT(FALSE);
return;
}
VOID
USBD_RegisterHcFilter(
PDEVICE_OBJECT DeviceObject,
PDEVICE_OBJECT FilterDeviceObject
)
{
ASSERT(FALSE);
}
NTSTATUS
USBD_RegisterHostController(
IN PDEVICE_OBJECT PhysicalDeviceObject,
IN PDEVICE_OBJECT HcdDeviceObject,
IN PDEVICE_OBJECT HcdTopOfPdoStackDeviceObject,
IN PDRIVER_OBJECT HcdDriverObject,
IN HCD_DEFFERED_START_FUNCTION *HcdDeferredStartDevice,
IN HCD_SET_DEVICE_POWER_STATE *HcdSetDevicePowerState,
IN HCD_GET_CURRENT_FRAME *HcdGetCurrentFrame,
IN HCD_GET_CONSUMED_BW *HcdGetConsumedBW,
IN HCD_SUBMIT_ISO_URB *HcdSubmitIsoUrb,
// this parameter is only needed until we resolve device naming
// issues with PNP
IN ULONG HcdDeviceNameHandle
)
{
PAGED_CODE();
ASSERT(FALSE);
return STATUS_NOT_SUPPORTED;
}
NTSTATUS
USBD_RemoveDevice(
IN PUSBD_DEVICE_DATA DeviceData,
IN PDEVICE_OBJECT DeviceObject,
IN UCHAR Flags
)
{
USBD_KdPrint(0,
("'WARNING: Driver using obsolete service enrty point (USBD_RemoveDevice) - get JD\n"));
ASSERT(FALSE);
return STATUS_NOT_SUPPORTED;
}
NTSTATUS
USBD_RestoreDevice(
IN OUT PUSBD_DEVICE_DATA OldDeviceData,
IN OUT PUSBD_DEVICE_DATA NewDeviceData,
IN PDEVICE_OBJECT DeviceObject
)
{
USBD_KdPrint(0,
("'WARNING: Driver using obsolete service enrty point (USBD_RestoreDevice) - get JD\n"));
ASSERT(FALSE);
return STATUS_NOT_SUPPORTED;
}
VOID
USBD_SetSuspendPowerState(
PDEVICE_OBJECT DeviceObject,
DEVICE_POWER_STATE SuspendPowerState
)
{
ASSERT(FALSE);
return;
}
VOID
USBD_WaitDeviceMutex(
PDEVICE_OBJECT RootHubPDO
)
{
ASSERT(FALSE);
return;
}
#endif // USBD_DRIVER