windows-nt/Source/XPSP1/NT/drivers/wdm/devbay/dbclass/usbhubf.c
2020-09-26 16:20:57 +08:00

743 lines
17 KiB
C

/*++
Copyright (c) 1998 Microsoft Corporation
Module Name:
USBHUBF.C
Abstract:
Environment:
kernel mode only
Notes:
Revision History:
--*/
#include <wdm.h>
#include "stdarg.h"
#include "stdio.h"
#include "dbci.h"
#include "dbclass.h"
#include "dbfilter.h"
#include "usbioctl.h"
//
// Registry keys
//
#define DBCLASS_HUB_IS_ACPI_DBC 0x00000001
#define DBCLASS_HUB_IS_USB_DBC 0x00000002
extern LONG DBCLASS_AcpiDBCHubParentPort;
NTSTATUS
DBCLASS_UsbhubQBusRelationsComplete(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Context
)
/*++
Routine Description:
Arguments:
DeviceObject - a pointer to the device object
Irp - a pointer to the irp
Context - NULL ptr
Return Value:
STATUS_SUCCESS
--*/
{
PDEVICE_RELATIONS deviceRelations;
ULONG i;
PDEVICE_OBJECT busFilterMdo = Context;
PDEVICE_EXTENSION deviceExtension;
PDEVICE_OBJECT mdoUSB;
PDBC_CONTEXT dbcContext;
deviceExtension = busFilterMdo->DeviceExtension;
deviceRelations = (PDEVICE_RELATIONS) Irp->IoStatus.Information;
LOGENTRY(LOG_MISC, 'UQBR', busFilterMdo, 0, deviceRelations);
if (deviceRelations == NULL) {
LOGENTRY(LOG_MISC, 'UQBn', busFilterMdo, 0, deviceRelations);
return STATUS_SUCCESS;
}
// try to find the DBC controller associated with this hub
//
// Since the filter is loaded for every hub we need to see
// if this hub is part of a DBC subsystem
dbcContext = deviceExtension->DbcContext;
if (dbcContext == NULL) {
DBCLASS_KdPrint((1, "'>QBR USB, HUB NOT DBC\n"));
// no context means the hub is not part of DBC
LOGENTRY(LOG_MISC, 'hQBi', 0, 0, 0);
return STATUS_SUCCESS;
}
for (i=0; i< deviceRelations->Count; i++) {
DBCLASS_KdPrint((1, "'>QBR USB PDO[%d] %x\n", i,
deviceRelations->Objects[i]));
LOGENTRY(LOG_MISC, 'QBRd', deviceRelations->Objects[i], i, 0);
// hub is returning a PDO, see if we know
// about it
mdoUSB = DBCLASS_FindDevicePdo(deviceRelations->Objects[i]);
if (mdoUSB) {
// we know about this one,
// see if we can link it to a controller
PDEVICE_EXTENSION mdoUSBDeviceExtension;
mdoUSBDeviceExtension = mdoUSB->DeviceExtension;
mdoUSBDeviceExtension->DbcContext = dbcContext;
} else {
PDEVICE_OBJECT deviceFilterObject;
NTSTATUS ntStatus;
// don't know about it,
// create an MDO for this device
ntStatus = DBCLASS_CreateDeviceFilterObject(
deviceExtension->DriverObject,
&deviceFilterObject,
deviceRelations->Objects[i],
dbcContext,
DB_FDO_USB_DEVICE);
DBCLASS_KdPrint((1, "'>>QBR attaching to USB PDO[%d] %x\n", i,
deviceRelations->Objects[i]));
DBCLASS_KdPrint((1, "'(dbfilter)(bus)(USB) Create DO %x for USB PDO\n", deviceFilterObject));
}
}
return STATUS_SUCCESS;
}
NTSTATUS
DBCLASS_UsbhubBusFilterDispatch(
PDEVICE_OBJECT DeviceObject,
PIRP Irp,
PBOOLEAN Handled
)
/*++
Routine Description:
This is a call to the root hub PDO
Arguments:
DeviceObject - Device bay Filter FDO
Return Value:
NTSTATUS
--*/
{
PIO_STACK_LOCATION irpStack;
NTSTATUS ntStatus;
PDEVICE_EXTENSION deviceExtension;
deviceExtension = DeviceObject->DeviceExtension;
ntStatus = Irp->IoStatus.Status;
*Handled = FALSE;
irpStack = IoGetCurrentIrpStackLocation (Irp);
LOGENTRY(LOG_MISC, 'HBf>', 0, DeviceObject, Irp);
DBCLASS_ASSERT(deviceExtension->FdoType == DB_FDO_USBHUB_BUS);
DBCLASS_KdPrint((2, "'(dbfilter)(bus)(USB)IRP_MJ_ (%08X) IRP_MN_ (%08X)\n",
irpStack->MajorFunction, irpStack->MinorFunction));
switch (irpStack->MajorFunction) {
case IRP_MJ_PNP:
switch (irpStack->MinorFunction) {
case IRP_MN_START_DEVICE:
DBCLASS_KdPrint((1, "'(dbfilter)(bus)(USB)IRP_MN_START_DEVICE\n"));
break;
case IRP_MN_STOP_DEVICE:
DBCLASS_KdPrint((1, "'(dbfilter)(bus)(USB)IRP_MN_STOP_DEVICE\n"));
break;
case IRP_MN_REMOVE_DEVICE:
DBCLASS_KdPrint((1, "'(dbfilter)(bus)(USB)IRP_MN_REMOVE_DEVICE\n"));
// detach from the usbhub FDO and delete our
// MDO
DBCLASS_RemoveBusFilterMDOFromList(DeviceObject);
IoDetachDevice(deviceExtension->TopOfStackDeviceObject);
IoDeleteDevice (DeviceObject);
DBCLASS_KdPrint((1, "'REMOVE DB Filter on USB HUB\n"));
break;
case IRP_MN_QUERY_DEVICE_RELATIONS:
DBCLASS_KdPrint((1, "'(dbfilter)(bus)(USB)IRP_MN_QUERY_DEVICE_RELATIONS\n"));
//#if DBG
// DBCLASS_Get1394BayPortMapping(deviceExtension->DbcContext);
//#endif
//
// do the check for USB hubs that are part of a DBC
//
//
// Ask the hub if it has a DBC hanging on it
//
if (deviceExtension->DbcContext == NULL &&
DBCLASS_IsHubPartOfUSB_DBC(DeviceObject)) {
deviceExtension->DbcContext =
DBCLASS_FindControllerUSB(deviceExtension->DriverObject,
DeviceObject,
deviceExtension->PhysicalDeviceObject);
}
*Handled = TRUE;
if (irpStack->Parameters.QueryDeviceRelations.Type == BusRelations) {
DBCLASS_KdPrint((1,"'>>QBR USB BUS\n"));
IoCopyCurrentIrpStackLocationToNext(Irp);
// Set up a completion routine to handle marking the IRP.
IoSetCompletionRoutine(Irp,
DBCLASS_UsbhubQBusRelationsComplete,
DeviceObject,
TRUE,
TRUE,
TRUE);
} else {
IoSkipCurrentIrpStackLocation(Irp)
}
// Now Pass down the IRP
ntStatus = IoCallDriver(deviceExtension->TopOfStackDeviceObject, Irp);
break;
} /* irpStack->MinorFunction */
break;
} /* irpStack->MajorFunction */
LOGENTRY(LOG_MISC, 'HBf<', 0, DeviceObject, 0);
return ntStatus;
}
ULONG
DBCLASS_IsHubPartOf_DBC(
PDEVICE_OBJECT DeviceObject
)
/*++
Routine Description:
This call reads a registry key that tells us if this usb hub is part
of a device bay controller
Arguments:
DeviceObject - Device bay Filter FDO
Return Value:
NTSTATUS
--*/
{
ULONG flags = 0;
NTSTATUS ntStatus;
PDEVICE_EXTENSION deviceExtension;
PAGED_CODE();
deviceExtension = DeviceObject->DeviceExtension;
ntStatus = DBCLASS_GetRegistryKeyValueForPdo(
deviceExtension->PhysicalDeviceObject,
FALSE,
IS_DEVICE_BAY_KEY,
sizeof(IS_DEVICE_BAY_KEY),
&flags,
sizeof(flags));
DBCLASS_KdPrint((2, "'GetRegistryKeyValueForPdo ntStatus = %x flags = %x\n",
ntStatus, flags));
return flags;
}
BOOLEAN
DBCLASS_IsHubPartOfACPI_DBC(
PDEVICE_OBJECT DeviceObject
)
/*++
Routine Description:
This is a call to a usb hub PDO
Arguments:
DeviceObject - Device bay Filter FDO
Return Value:
NTSTATUS
--*/
{
BOOLEAN isDB;
ULONG flags;
// see if it is an acpiDBC, if so mark it in
// the registry
if (DBCLASS_AcpiDBCHubParentPort != -1) {
PDEVICE_EXTENSION deviceExtension;
deviceExtension = DeviceObject->DeviceExtension;
DBCLASS_CheckForAcpiDeviceBayHubs(
deviceExtension->PhysicalDeviceObject,
(ULONG) DBCLASS_AcpiDBCHubParentPort);
}
flags = DBCLASS_IsHubPartOf_DBC(DeviceObject);
isDB = (BOOLEAN) flags & DBCLASS_HUB_IS_ACPI_DBC;
#ifdef DBG
if (isDB) {
DBCLASS_KdPrint((1, "'*** USBHUB for ACPI DBC Found\n"));
BRK_ON_TRAP();
}
#endif
return isDB;
}
BOOLEAN
DBCLASS_IsHubPartOfUSB_DBC(
PDEVICE_OBJECT DeviceObject
)
/*++
Routine Description:
This is a call to a usb hub PDO
Arguments:
DeviceObject - Device bay Filter FDO
Return Value:
NTSTATUS
--*/
{
BOOLEAN isDB;
ULONG flags;
flags = DBCLASS_IsHubPartOf_DBC(DeviceObject);
isDB = (BOOLEAN) flags & DBCLASS_HUB_IS_USB_DBC;
#ifdef DBG
if (isDB) {
DBCLASS_KdPrint((1, "'USBHUB for USB DBC Found!\n"));
BRK_ON_TRAP();
}
#endif
return isDB;
}
NTSTATUS
DBCLASS_GetHubDBCGuid(
PDEVICE_OBJECT DeviceObject,
PUCHAR DbcGuid
)
/*++
Routine Description:
This is a call to the root hub PDO
Arguments:
DeviceObject - Device bay Filter FDO
Return Value:
NTSTATUS
--*/
{
NTSTATUS ntStatus;
PDEVICE_EXTENSION deviceExtension;
PAGED_CODE();
deviceExtension = DeviceObject->DeviceExtension;
ntStatus = DBCLASS_GetRegistryKeyValueForPdo(
deviceExtension->PhysicalDeviceObject,
FALSE,
DBC_GUID_KEY,
sizeof(DBC_GUID_KEY),
DbcGuid,
8);
DBCLASS_KdPrint((2, "'GetRegistryKeyValueForPdo ntStatus = %x \n",
ntStatus));
#if DBG
DBCLASS_KdPrint((1, "'DBC GUID FOR HUB\n"));
DBCLASS_KdPrintGuid(1, DbcGuid);
#endif
return ntStatus;
}
NTSTATUS
DBCLASS_SyncGetUsbInfo(
IN PDEVICE_OBJECT DeviceObject,
IN PDEVICE_OBJECT *ParentDeviceObject,
IN PDEVICE_OBJECT *RootHubPdo,
IN PULONG PortNumber
)
/* ++
*
* Routine Description:
*
* Arguments:
*
* Return Value:
*
* NTSTATUS
*
* -- */
{
NTSTATUS ntStatus, status;
PIRP irp;
KEVENT event;
IO_STATUS_BLOCK ioStatus;
PIO_STACK_LOCATION nextStack;
PAGED_CODE();
//
// issue a synchronous request to the Hub Pdo
//
KeInitializeEvent(&event, NotificationEvent, FALSE);
irp = IoBuildDeviceIoControlRequest( IOCTL_INTERNAL_USB_GET_PARENT_HUB_INFO,
DeviceObject,
NULL,
0,
NULL,
0,
TRUE, // INTERNAL
&event,
&ioStatus);
if (NULL == irp) {
TRAP();
return STATUS_INSUFFICIENT_RESOURCES;
}
nextStack = IoGetNextIrpStackLocation(irp);
nextStack->Parameters.Others.Argument1 = ParentDeviceObject;
nextStack->Parameters.Others.Argument2 = PortNumber;
nextStack->Parameters.Others.Argument4 = RootHubPdo;
ntStatus = IoCallDriver(DeviceObject, irp);
if (ntStatus == STATUS_PENDING) {
status = KeWaitForSingleObject(&event,
Suspended,
KernelMode,
FALSE,
NULL);
} else {
ioStatus.Status = ntStatus;
}
ntStatus = ioStatus.Status;
DBCLASS_KdPrint((0, "'>>USB-PDO-INFO((%08X)) Parent = (%08X) Port = %d status = %x\n",
DeviceObject, *ParentDeviceObject, *PortNumber, ntStatus));
return ntStatus;
}
USHORT
DBCLASS_GetBayForUSBPdo(
PDBC_CONTEXT DbcContext,
PDEVICE_OBJECT PdoUSB
)
/*++
Routine Description:
given a USB PDO figure out wich bay it is associated with
Arguments:
Return Value:
zero if not a device bay PDO.
--*/
{
USHORT bay = 0;
NTSTATUS ntStatus;
PDEVICE_OBJECT parent = NULL, rootHubPdo = NULL;
ULONG portNumber = 0xFFFFFFFF;
PAGED_CODE();
// find out what port this PDO is in
ntStatus = DBCLASS_SyncGetUsbInfo(PdoUSB,
&parent,
&rootHubPdo,
&portNumber);
if (NT_SUCCESS(ntStatus)) {
for (bay=1; bay <=NUMBER_OF_BAYS(DbcContext); bay++) {
DBCLASS_KdPrint((2, "'bay[%d]-> port %d, hub (%08X)\n",
bay,
DbcContext->BayInformation[bay].UsbHubPort,
DbcContext->BayInformation[bay].UsbHubPdo));
if (DbcContext->BayInformation[bay].UsbHubPort == portNumber
/*&&
DbcContext->BayInformation[bay].UsbHubPdo == parent */) {
break;
}
}
}
if (!bay || bay > NUMBER_OF_BAYS(DbcContext)) {
bay = 0;
DBCLASS_KdPrint((2, "'No bay->port mapping for USB PDO\n"));
}
return bay;
}
NTSTATUS
DBCLASS_SetupUSB_DBC(
PDBC_CONTEXT DbcContext
)
/*++
Routine Description:
given a USB DbcContext, write the appropriate keys
to the registry
Arguments:
Return Value:
NTSTATUS
--*/
{
NTSTATUS ntStatus = STATUS_SUCCESS;
ULONG flags = DBCLASS_HUB_IS_USB_DBC;
PDEVICE_OBJECT parentHubPdo = NULL, rootHubPdo = NULL;
ULONG portNumber;
// get the parent hub info
ntStatus = DBCLASS_SyncGetUsbInfo(
DbcContext->ControllerPdo,
&parentHubPdo,
&rootHubPdo,
&portNumber);
// set the keys
if (NT_SUCCESS(ntStatus)) {
ntStatus = DBCLASS_SetRegistryKeyValueForPdo(
parentHubPdo,
FALSE,
REG_DWORD,
IS_DEVICE_BAY_KEY,
sizeof(IS_DEVICE_BAY_KEY),
&flags,
sizeof(flags));
}
if (NT_SUCCESS(ntStatus)) {
ntStatus = DBCLASS_SetRegistryKeyValueForPdo(
parentHubPdo,
FALSE,
REG_BINARY,
DBC_GUID_KEY,
sizeof(DBC_GUID_KEY),
&DbcContext->SubsystemDescriptor.guid1394Link[0],
8);
}
return ntStatus;
}
NTSTATUS
DBCLASS_CheckForAcpiDeviceBayHubs(
PDEVICE_OBJECT HubPdo,
ULONG AcpiDBCHubParentPort
)
/*++
Routine Description:
Check to see if this device object
is for a hub that is part of an ACPI DBC
Arguments:
AcpiDBCHubParentPort
0 = acpi hub is root otherwise upstream port on root
hub the ACPI hub is connected to
Return Value:
NTSTATUS
--*/
{
PDEVICE_OBJECT parentHubPdo = NULL, rootHubPdo = NULL;
ULONG portNumber = 0;
BOOLEAN writeKeys = FALSE;
NTSTATUS ntStatus;
// get the root hub PDO
ntStatus = DBCLASS_SyncGetUsbInfo(
HubPdo,
&parentHubPdo,
&rootHubPdo,
&portNumber);
// failure indicates this is root
if (!NT_SUCCESS(ntStatus)) {
ntStatus = STATUS_SUCCESS;
rootHubPdo = HubPdo;
}
if (NT_SUCCESS(ntStatus)) {
DBCLASS_KdPrint((1, "'>**Check Hub: RHPDO = %x, parentPDO %x, port %d\n",
rootHubPdo,
parentHubPdo,
portNumber));
// is this the root hub?
if (HubPdo == rootHubPdo) {
// Yes
if (AcpiDBCHubParentPort == 0) {
// root hub is acpi hub
writeKeys = TRUE;
}
} else {
// is the parent the root hub?
if (parentHubPdo == rootHubPdo) {
// Yes
if (AcpiDBCHubParentPort == portNumber) {
// root hub ius acpi hub
writeKeys = TRUE;
}
}
}
}
if (writeKeys) {
ULONG flags;
flags = DBCLASS_HUB_IS_ACPI_DBC;
DBCLASS_SetRegistryKeyValueForPdo(
HubPdo,
FALSE,
REG_DWORD,
IS_DEVICE_BAY_KEY,
sizeof(IS_DEVICE_BAY_KEY),
&flags,
sizeof(flags));
// DBCLASS_SetRegistryKeyValueForPdo(
// HubPdo,
// FALSE,
// REG_BINARY,
// DBC_GUID_KEY,
// sizeof(DBC_GUID_KEY),
// &DbcContext->SubsystemDescriptor.guid1394Link[0],
// 8);
}
return ntStatus;
}