/*++ Copyright (c) 1998 Microsoft Corporation Module Name: USBHUBF.C Abstract: Environment: kernel mode only Notes: Revision History: --*/ #include #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; }