/*++ Copyright (c) 1990-2000 Microsoft Corporation Module Name: pnp.c Abstract: This is the pnp portion of the video port driver. Environment: kernel mode only Revision History: --*/ #include "videoprt.h" #pragma alloc_text(PAGE,pVideoPortSendIrpToLowerDevice) #pragma alloc_text(PAGE,pVideoPortPowerCallDownIrpStack) #pragma alloc_text(PAGE,pVideoPortHibernateNotify) #pragma alloc_text(PAGE,pVideoPortPnpDispatch) #pragma alloc_text(PAGE,pVideoPortPowerDispatch) #pragma alloc_text(PAGE,InitializePowerStruct) NTSTATUS VpSetEventCompletion( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PKEVENT Event ) { KeSetEvent(Event, IO_NO_INCREMENT, FALSE); return STATUS_MORE_PROCESSING_REQUIRED; } NTSTATUS pVideoPortSendIrpToLowerDevice( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) /*++ Routine Description: This routine will forward the start request to the next lower device and block until it's completion. Arguments: DeviceObject - the device to which the start request was issued. Irp - the start request Return Value: status --*/ { PFDO_EXTENSION fdoExtension = DeviceObject->DeviceExtension; PKEVENT event; NTSTATUS status; event = ExAllocatePoolWithTag(NonPagedPool, sizeof(KEVENT), VP_TAG); if (event == NULL) { return STATUS_INSUFFICIENT_RESOURCES; } KeInitializeEvent(event, SynchronizationEvent, FALSE); IoCopyCurrentIrpStackLocationToNext(Irp); IoSetCompletionRoutine(Irp, VpSetEventCompletion, event, TRUE, TRUE, TRUE); status = IoCallDriver(fdoExtension->AttachedDeviceObject, Irp); if(status == STATUS_PENDING) { KeWaitForSingleObject(event, Executive, KernelMode, FALSE, NULL); status = Irp->IoStatus.Status; } ExFreePool(event); return status; } NTSTATUS pVideoPortCompleteWithMoreProcessingRequired( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PKEVENT Event ) /*++ Routine Description: This routine is used as a completion routine when an IRP is passed down the stack but more processing must be done on the way back up. The effect of using this as a completion routine is that the IRP will not be destroyed in IoCompleteRequest as called by the lower level object. Arguments: DeviceObject - Supplies the device object Irp - Supplies the IRP_MN_START_DEVICE irp. Event - Caller will wait on this event if STATUS_PENDING was returned. Return Value: STATUS_MORE_PROCESSING_REQUIRED --*/ { // // In case someone somewhere returned STATUS_PENDING, set // the Event our caller may be waiting on. // KeSetEvent(Event, 0, FALSE); return STATUS_MORE_PROCESSING_REQUIRED; } NTSTATUS pVideoPortPowerCallDownIrpStack( PDEVICE_OBJECT AttachedDeviceObject, PIRP Irp ) /*++ Description: Pass the IRP to the next device object in the device stack. This routine is used when more processing is required at this level on this IRP on the way back up. Note: Waits for completion. Arguments: DeviceObject - the Fdo Irp - the request Return Value: Returns the result from calling the next level. --*/ { KEVENT event; NTSTATUS status; // // Initialize the event to wait on. // KeInitializeEvent(&event, SynchronizationEvent, FALSE); // // Copy the stack location and set the completion routine. // IoCopyCurrentIrpStackLocationToNext(Irp); IoSetCompletionRoutine(Irp, pVideoPortCompleteWithMoreProcessingRequired, &event, TRUE, TRUE, TRUE ); // // Call the next driver in the chain. // status = PoCallDriver(AttachedDeviceObject, Irp); if (status == STATUS_PENDING) { // // Wait for it. // // (peterj: in theory this shouldn't actually happen). // // Also, the completion routine does not allow the IRP to // actually complete so we can still get status from the IRP. // KeWaitForSingleObject( &event, Executive, KernelMode, FALSE, NULL ); status = Irp->IoStatus.Status; } return status; } VOID pVideoPortHibernateNotify( IN PDEVICE_OBJECT Pdo, BOOLEAN IsVideoObject ) /*++ Routine Description: Sends a DEVICE_USAGE_NOTIFICATION irp to our parent PDO that indicates we are on the hibernate path. Arguments: Pdo - Supplies our PDO Return Value: None. --*/ { KEVENT Event; PIRP Irp; IO_STATUS_BLOCK IoStatusBlock; PIO_STACK_LOCATION irpSp; NTSTATUS status; PDEVICE_OBJECT targetDevice = Pdo ; // // If the PDO is ourselves, the target device is actually the top of // the device stack. // if (IsVideoObject) { targetDevice = IoGetAttachedDeviceReference (Pdo) ; } KeInitializeEvent(&Event, SynchronizationEvent, FALSE); Irp = IoBuildSynchronousFsdRequest(IRP_MJ_PNP, targetDevice, NULL, 0, NULL, &Event, &IoStatusBlock); if (Irp != NULL) { Irp->IoStatus.Status = STATUS_NOT_SUPPORTED ; irpSp = IoGetNextIrpStackLocation(Irp); irpSp->MajorFunction = IRP_MJ_PNP; irpSp->MinorFunction = IRP_MN_DEVICE_USAGE_NOTIFICATION; irpSp->Parameters.UsageNotification.InPath = TRUE; irpSp->Parameters.UsageNotification.Type = DeviceUsageTypeHibernation; status = IoCallDriver(targetDevice, Irp); if (status == STATUS_PENDING) { KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL); } } // // Make sure to deref if the object was referenced when the top of // the stack was obtained. // if (IsVideoObject) { ObDereferenceObject (targetDevice) ; } } ULONG VpGetDeviceAddress( IN PDEVICE_OBJECT DeviceObject ) /*++ Routine Description: This routine will get the address of a device (ie. slot number). Arguments: DeviceObject - Object for which to retrieve the address Returns: The address of the given device. --*/ { KEVENT Event; PIRP QueryIrp = NULL; IO_STATUS_BLOCK IoStatusBlock; PIO_STACK_LOCATION NextStack; NTSTATUS Status; DEVICE_CAPABILITIES Capabilities; PFDO_EXTENSION FdoExtension = DeviceObject->DeviceExtension; RtlZeroMemory(&Capabilities, sizeof(DEVICE_CAPABILITIES)); Capabilities.Size = sizeof(DEVICE_CAPABILITIES); Capabilities.Version = 1; Capabilities.Address = Capabilities.UINumber = (ULONG) -1; KeInitializeEvent(&Event, SynchronizationEvent, FALSE); QueryIrp = IoBuildSynchronousFsdRequest(IRP_MJ_FLUSH_BUFFERS, FdoExtension->AttachedDeviceObject, NULL, 0, NULL, &Event, &IoStatusBlock); if (QueryIrp == NULL) { return STATUS_INSUFFICIENT_RESOURCES; } QueryIrp->IoStatus.Status = IoStatusBlock.Status = STATUS_NOT_SUPPORTED; NextStack = IoGetNextIrpStackLocation(QueryIrp); // // Set up for a QueryInterface Irp. // NextStack->MajorFunction = IRP_MJ_PNP; NextStack->MinorFunction = IRP_MN_QUERY_CAPABILITIES; NextStack->Parameters.DeviceCapabilities.Capabilities = &Capabilities; Status = IoCallDriver(FdoExtension->AttachedDeviceObject, QueryIrp); if (Status == STATUS_PENDING) { KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL); Status = IoStatusBlock.Status; } ASSERT(NT_SUCCESS(Status)); return (Capabilities.Address >> 16) | ((Capabilities.Address & 0x7) << 5); } NTSTATUS pVideoPortPnpDispatch( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) /*++ Routine Description: This routine is the PnP dispatch routine for the video port driver. It accepts an I/O Request Packet, transforms it to a video Request Packet, and forwards it to the appropriate miniport dispatch routine. Upon returning, it completes the request and return the appropriate status value. Arguments: DeviceObject - Pointer to the device object of the miniport driver to which the request must be sent. Irp - Pointer to the request packet representing the I/O request. Return Value: The function value os the status of the operation. --*/ { PDEVICE_SPECIFIC_EXTENSION DoSpecificExtension; PFDO_EXTENSION combinedExtension; PFDO_EXTENSION fdoExtension; PCHILD_PDO_EXTENSION pdoExtension = NULL; PIO_STACK_LOCATION irpStack; PVOID ioBuffer; ULONG inputBufferLength; ULONG outputBufferLength; PSTATUS_BLOCK statusBlock; NTSTATUS finalStatus; ULONG ioControlCode; BOOLEAN RemoveLockReleased = FALSE; PIO_REMOVE_LOCK pRemoveLock; PCHILD_PDO_EXTENSION childDeviceExtension; NTSTATUS RemoveLockStatus; PBACKLIGHT_STATUS pVpBacklightStatus = &VpBacklightStatus; PDEVICE_OBJECT AttachedDevice = NULL; ULONG ulACPIMethodParam1; BOOLEAN bSetBacklight = FALSE; // // Get a pointer to the current location in the Irp. This is where // the function codes and parameters are located. // irpStack = IoGetCurrentIrpStackLocation(Irp); // // Get the pointer to the status buffer. // Assume SUCCESS for now. // statusBlock = (PSTATUS_BLOCK) &Irp->IoStatus; // // Get pointer to the port driver's device extension. // combinedExtension = DeviceObject->DeviceExtension; if (IS_PDO(DeviceObject->DeviceExtension)) { pdoExtension = DeviceObject->DeviceExtension; fdoExtension = pdoExtension->pFdoExtension; childDeviceExtension = (PCHILD_PDO_EXTENSION) DeviceObject->DeviceExtension; pRemoveLock = &childDeviceExtension->RemoveLock; } else if (IS_FDO(DeviceObject->DeviceExtension)) { fdoExtension = DeviceObject->DeviceExtension; DoSpecificExtension = (PDEVICE_SPECIFIC_EXTENSION)(fdoExtension + 1); pRemoveLock = &fdoExtension->RemoveLock; } else { DoSpecificExtension = DeviceObject->DeviceExtension; fdoExtension = DoSpecificExtension->pFdoExtension; combinedExtension = fdoExtension; pVideoDebugPrint((2, "Pnp/Power irp's not supported by secondary DO\n")); statusBlock->Status = STATUS_NOT_SUPPORTED; goto Complete_Irp; } // // Get the requestor mode. // combinedExtension->CurrentIrpRequestorMode = Irp->RequestorMode; #if REMOVE_LOCK_ENABLED RemoveLockStatus = IoAcquireRemoveLock(pRemoveLock, Irp); if (NT_SUCCESS(RemoveLockStatus) == FALSE) { ASSERT(FALSE); Irp->IoStatus.Information = 0; Irp->IoStatus.Status = RemoveLockStatus; IoCompleteRequest(Irp, IO_VIDEO_INCREMENT); return RemoveLockStatus; } #endif // // Handle IRPs for the PDO. Only PNP IRPs should be going to // that device. // if (IS_PDO(combinedExtension)) { ASSERT(irpStack->MajorFunction == IRP_MJ_PNP); pVideoDebugPrint((2, "VIDEO_TYPE_PDO : IRP_MJ_PNP: ")); switch (irpStack->MinorFunction) { case IRP_MN_CANCEL_STOP_DEVICE: pVideoDebugPrint((2, "IRP_MN_CANCEL_STOP_DEVICE\n")); statusBlock->Status = STATUS_SUCCESS; break; case IRP_MN_DEVICE_USAGE_NOTIFICATION: pVideoDebugPrint((2, "IRP_MN_DEVICE_USAGE_NOTIFICATION\n")); statusBlock->Status = STATUS_SUCCESS; break; case IRP_MN_QUERY_PNP_DEVICE_STATE: pVideoDebugPrint((2, "IRP_MN_QUERY_PNP_DEVICE_STATE\n")) ; statusBlock->Status = STATUS_SUCCESS; break; case IRP_MN_QUERY_CAPABILITIES: pVideoDebugPrint((2, "IRP_MN_QUERY_CAPABILITIES\n")); statusBlock->Status = pVideoPnPCapabilities(childDeviceExtension, irpStack->Parameters.DeviceCapabilities.Capabilities); break; case IRP_MN_QUERY_ID: pVideoDebugPrint((2, "IRP_MN_QUERY_ID\n")); statusBlock->Status = pVideoPnPQueryId(DeviceObject, irpStack->Parameters.QueryId.IdType, (PWSTR *)&(Irp->IoStatus.Information)); break; case IRP_MN_QUERY_RESOURCE_REQUIREMENTS: pVideoDebugPrint((2, "IRP_MN_QUERY_RESOURCE_REQUIREMENTS\n")); statusBlock->Status = pVideoPnPResourceRequirements(childDeviceExtension, (PCM_RESOURCE_LIST * )&(Irp->IoStatus.Information)); break; case IRP_MN_QUERY_DEVICE_RELATIONS: pVideoDebugPrint((2, "IRP_MN_QUERY_DEVICE_RELATIONS\n")); if (irpStack->Parameters.QueryDeviceRelations.Type == TargetDeviceRelation) { PDEVICE_RELATIONS DeviceRelationsBuffer; PDEVICE_RELATIONS *pDeviceRelations; pDeviceRelations = (PDEVICE_RELATIONS *) &statusBlock->Information; if (*pDeviceRelations) { // // The caller supplied a device relation structure. // However, we do not know if it is big enough, so // free it and allocate our own. // ExFreePool(*pDeviceRelations); *pDeviceRelations = NULL; } DeviceRelationsBuffer = ExAllocatePoolWithTag(PagedPool | POOL_COLD_ALLOCATION, sizeof(DEVICE_RELATIONS), VP_TAG); if (DeviceRelationsBuffer) { DeviceRelationsBuffer->Count = 1; DeviceRelationsBuffer->Objects[0] = DeviceObject; *pDeviceRelations = DeviceRelationsBuffer; ObReferenceObject(DeviceObject); statusBlock->Status = STATUS_SUCCESS; } else { statusBlock->Status = STATUS_INSUFFICIENT_RESOURCES; } } break; case IRP_MN_QUERY_DEVICE_TEXT: pVideoDebugPrint((2, "IRP_MN_QUERY_DEVICE_TEXT\n")); statusBlock->Status = pVideoPortQueryDeviceText(DeviceObject, irpStack->Parameters.QueryDeviceText.DeviceTextType, (PWSTR *)&Irp->IoStatus.Information); break; case IRP_MN_QUERY_INTERFACE: pVideoDebugPrint((2, "IRP_MN_QUERY_INTERFACE\n")); if ((childDeviceExtension->pFdoExtension->HwQueryInterface) && (childDeviceExtension->pFdoExtension->HwDeviceExtension)) { VP_STATUS status; status = childDeviceExtension->pFdoExtension->HwQueryInterface( childDeviceExtension->pFdoExtension->HwDeviceExtension, (PQUERY_INTERFACE) &irpStack->Parameters.QueryInterface); if (status == 0) { statusBlock->Status = STATUS_SUCCESS; } } break; case IRP_MN_SURPRISE_REMOVAL: case IRP_MN_QUERY_REMOVE_DEVICE: case IRP_MN_QUERY_STOP_DEVICE: case IRP_MN_STOP_DEVICE: pVideoDebugPrint((2, "IRP_MN_SURPRISE_REMOVAL/IRP_MN_QUERY_REMOVE_DEVICE/IRP_MN_QUERY_STOP_DEVICE/IRP_MN_STOP_DEVICE\n")); if (childDeviceExtension->VideoChildDescriptor->Type == Monitor) { if (irpStack->MinorFunction == IRP_MN_SURPRISE_REMOVAL) { KeWaitForSingleObject (&LCDPanelMutex, Executive, KernelMode, FALSE, (PTIME)NULL); if (LCDPanelDevice == DeviceObject) { LCDPanelDevice = NULL; } KeReleaseMutex (&LCDPanelMutex, FALSE); } } statusBlock->Status = STATUS_SUCCESS; break; case IRP_MN_CANCEL_REMOVE_DEVICE: pVideoDebugPrint((2, "IRP_MN_CANCEL_REMOVE_DEVICE\n")); statusBlock->Status = STATUS_SUCCESS; break; case IRP_MN_REMOVE_DEVICE: pVideoDebugPrint((2, "IRP_MN_REMOVE_DEVICE\n")); // // Check the see if this is the LCD Panel. If it is, set the LCD // panel device object to NULL. If not, leave it alone. // KeWaitForSingleObject (&LCDPanelMutex, Executive, KernelMode, FALSE, (PTIME)NULL); if (LCDPanelDevice == DeviceObject) { LCDPanelDevice = NULL; } KeReleaseMutex(&LCDPanelMutex, FALSE); #if REMOVE_LOCK_ENABLED IoReleaseRemoveLockAndWait(pRemoveLock, Irp); RemoveLockReleased = TRUE; #endif // // If this is one of our child pdo's, then // clean it up. // statusBlock->Status = pVideoPortCleanUpChildList(childDeviceExtension->pFdoExtension, DeviceObject); break; case IRP_MN_START_DEVICE: { UCHAR nextMiniport = FALSE; PVIDEO_PORT_DRIVER_EXTENSION DriverObjectExtension; pVideoDebugPrint((2, "IRP_MN_START_DEVICE\n")); // // For a non-card device, just return success // if (childDeviceExtension->VideoChildDescriptor) { // // Once the monitor device is started, create an interface for it. // if (childDeviceExtension->VideoChildDescriptor->Type == Monitor) { statusBlock->Status = STATUS_SUCCESS; // // If the monitor is attached to the video adapter on the hibernation // path then we want to send notification to the system that the // monitor is on the hibernation path as well. // if (fdoExtension->OnHibernationPath == TRUE) { pVideoPortHibernateNotify (DeviceObject, TRUE); } // // If this is the LCD Panel, update the global to indicate as // much. // if (childDeviceExtension->ChildUId == 0x110) { KeWaitForSingleObject (&LCDPanelMutex, Executive, KernelMode, FALSE, (PTIME)NULL); LCDPanelDevice = DeviceObject; KeReleaseMutex(&LCDPanelMutex, FALSE); // // If the new backlight control interface is implemented, // set the backlight brightness level. // if ((pVpBacklightStatus->bNewAPISupported == TRUE) && (pVpBacklightStatus->bACBrightnessKnown == TRUE) && (VpRunningOnAC == TRUE)) { ulACPIMethodParam1= (ULONG) pVpBacklightStatus->ucACBrightness; bSetBacklight = TRUE; } if ((pVpBacklightStatus->bNewAPISupported == TRUE) && (pVpBacklightStatus->bDCBrightnessKnown == TRUE) && (VpRunningOnAC == FALSE)) { ulACPIMethodParam1= (ULONG) pVpBacklightStatus->ucDCBrightness; bSetBacklight = TRUE; } if ((bSetBacklight) && (LCDPanelDevice)) { AttachedDevice = IoGetAttachedDeviceReference(LCDPanelDevice); // Not checking status here deliberately, as we're not failing // this IRP if this call fails. if (AttachedDevice) { pVideoPortACPIIoctl( AttachedDevice, (ULONG) ('MCB_'), &ulACPIMethodParam1, NULL, 0, NULL); ObDereferenceObject(AttachedDevice); } } } } else if (childDeviceExtension->VideoChildDescriptor->Type == Other) { statusBlock->Status = STATUS_SUCCESS; } } else { ASSERT(FALSE); // // Secondary video cards are handle here. // DriverObjectExtension = (PVIDEO_PORT_DRIVER_EXTENSION) IoGetDriverObjectExtension( DeviceObject->DriverObject, DeviceObject->DriverObject); } } break; default: pVideoDebugPrint((2, "PNP minor function %x not supported!\n", irpStack->MinorFunction )); statusBlock->Status = STATUS_NOT_SUPPORTED; break; } } else { ASSERT(IS_FDO(fdoExtension)); ASSERT(irpStack->MajorFunction == IRP_MJ_PNP); pVideoDebugPrint((2, "VIDEO_TYPE_FDO : IRP_MJ_PNP: ")); switch (irpStack->MinorFunction) { case IRP_MN_QUERY_STOP_DEVICE: pVideoDebugPrint((2, "IRP_MN_QUERY_STOP_DEVICE\n")); statusBlock->Status = STATUS_UNSUCCESSFUL; break; case IRP_MN_FILTER_RESOURCE_REQUIREMENTS: { PVIDEO_PORT_DRIVER_EXTENSION DriverObjectExtension; PIO_RESOURCE_REQUIREMENTS_LIST requirements; ULONG Length; pVideoDebugPrint((2, "IRP_MN_QUERY_RESOURCE_REQUIREMENTS\n")); DriverObjectExtension = (PVIDEO_PORT_DRIVER_EXTENSION) IoGetDriverObjectExtension( DeviceObject->DriverObject, DeviceObject->DriverObject); // // We must first pass the Irp down to the PDO. // pVideoPortSendIrpToLowerDevice(DeviceObject, Irp); // // Determine the bus type and bus number // IoGetDeviceProperty(fdoExtension->PhysicalDeviceObject, DevicePropertyLegacyBusType, sizeof(fdoExtension->AdapterInterfaceType), &fdoExtension->AdapterInterfaceType, &Length); IoGetDeviceProperty(fdoExtension->PhysicalDeviceObject, DevicePropertyBusNumber, sizeof(fdoExtension->SystemIoBusNumber), &fdoExtension->SystemIoBusNumber, &Length); // // Get bus interface so we can use Get/SetBusData. // fdoExtension->ValidBusInterface = NT_SUCCESS(VpGetBusInterface(fdoExtension)); requirements = irpStack->Parameters.FilterResourceRequirements.IoResourceRequirementList; if (requirements) { // // Append any legacy resources decoded by the device. // if (DriverObjectExtension->HwInitData.HwInitDataSize > FIELD_OFFSET(VIDEO_HW_INITIALIZATION_DATA, HwLegacyResourceCount)) { if( requirements->InterfaceType == PCIBus ) { PCI_COMMON_CONFIG ConfigSpace; VideoPortGetBusData((PVOID)((ULONG_PTR)(fdoExtension) + sizeof(FDO_EXTENSION) + sizeof(DEVICE_SPECIFIC_EXTENSION)), PCIConfiguration, 0, &ConfigSpace, 0, PCI_COMMON_HDR_LENGTH); if (((ConfigSpace.BaseClass == PCI_CLASS_PRE_20) && (ConfigSpace.SubClass == PCI_SUBCLASS_PRE_20_VGA)) || ((ConfigSpace.BaseClass == PCI_CLASS_DISPLAY_CTLR) && (ConfigSpace.SubClass == PCI_SUBCLASS_VID_VGA_CTLR))) { if (pVideoPortGetVgaStatusPci((PVOID)((ULONG_PTR)(fdoExtension) + sizeof(FDO_EXTENSION) + sizeof(DEVICE_SPECIFIC_EXTENSION)))) { if (DriverObjectExtension->HwInitData.HwInitDataSize > FIELD_OFFSET(VIDEO_HW_INITIALIZATION_DATA, HwGetLegacyResources)) { if (DriverObjectExtension->HwInitData.HwGetLegacyResources) { // // If the miniport supplied a HwGetLegacyResources routine // it wasn't able to give us a list of resources at // DriverEntry time. We'll give it a vendor/device id now // and see if it can give us a list of resources. // DriverObjectExtension->HwInitData.HwGetLegacyResources( ConfigSpace.VendorID, ConfigSpace.DeviceID, &DriverObjectExtension->HwInitData.HwLegacyResourceList, &DriverObjectExtension->HwInitData.HwLegacyResourceCount ); } } if (DriverObjectExtension->HwInitData.HwLegacyResourceList) { if (VgaHwDeviceExtension) { ULONG Count; PVIDEO_ACCESS_RANGE AccessRange; Count = DriverObjectExtension->HwInitData.HwLegacyResourceCount; AccessRange = DriverObjectExtension->HwInitData.HwLegacyResourceList; // // Mark VGA resources as shared if the vga driver is // already loaded. Otherwise the PnP driver won't // be able to start. // while (Count--) { if (VpIsVgaResource(AccessRange)) { AccessRange->RangeShareable = TRUE; } AccessRange++; } } VpAppendToRequirementsList( DeviceObject, &requirements, DriverObjectExtension->HwInitData.HwLegacyResourceCount, DriverObjectExtension->HwInitData.HwLegacyResourceList); } else { // // The driver didn't specify legacy resources, but we // know that it is a VGA, so add in the vga resources. // pVideoDebugPrint((1, "VGA device didn't specify legacy resources.\n")); DriverObjectExtension->HwInitData.HwLegacyResourceCount = NUM_VGA_LEGACY_RESOURCES; DriverObjectExtension->HwInitData.HwLegacyResourceList = VgaLegacyResources; VpAppendToRequirementsList( DeviceObject, &requirements, NUM_VGA_LEGACY_RESOURCES, VgaLegacyResources); } } } } } // // Now if there is an interrupt in the list, but // the miniport didn't register an ISR, then // release our claim on the interrupt. // if (!DriverObjectExtension->HwInitData.HwInterrupt) { PIO_RESOURCE_LIST resourceList; ULONG i; // // Scan the IO_RESOURCE_REQUIREMENTS_LIST for an // interrupt. // resourceList = requirements->List; for (i=0; iCount; i++) { if (resourceList->Descriptors[i].Type == CmResourceTypeInterrupt) { // // We found an interrupt resource swap with last // element in list, and decrement structure size and // list count. // resourceList->Descriptors[i].Type = CmResourceTypeNull; pVideoDebugPrint((1, "Removing Int from requirements list.\n")); } } } } else { pVideoDebugPrint((0, "We expected a list of resources!\n")); ASSERT(FALSE); } statusBlock->Information = (ULONG_PTR) requirements; statusBlock->Status = STATUS_SUCCESS; } break; case IRP_MN_START_DEVICE: { PVIDEO_PORT_DRIVER_EXTENSION DriverObjectExtension; PCM_RESOURCE_LIST allocatedResources; PCM_RESOURCE_LIST translatedResources; UCHAR nextMiniport = FALSE; ULONG RawListSize; ULONG TranslatedListSize; pVideoDebugPrint((2, "IRP_MN_START_DEVICE\n")); // // Retrieve the data we cached away during VideoPortInitialize. // DriverObjectExtension = (PVIDEO_PORT_DRIVER_EXTENSION) IoGetDriverObjectExtension( DeviceObject->DriverObject, DeviceObject->DriverObject); ASSERT(DriverObjectExtension); // // Grab the allocated resource the system gave us. // allocatedResources = irpStack->Parameters.StartDevice.AllocatedResources; translatedResources = irpStack->Parameters.StartDevice.AllocatedResourcesTranslated; // // Filter out any resources that we added to the list // before passing the irp on to PCI. // if (DriverObjectExtension->HwInitData.HwInitDataSize > FIELD_OFFSET(VIDEO_HW_INITIALIZATION_DATA, HwLegacyResourceCount)) { if (DriverObjectExtension->HwInitData.HwLegacyResourceList) { if (allocatedResources) { irpStack->Parameters.StartDevice.AllocatedResources = VpRemoveFromResourceList( allocatedResources, DriverObjectExtension->HwInitData.HwLegacyResourceCount, DriverObjectExtension->HwInitData.HwLegacyResourceList); } if ((irpStack->Parameters.StartDevice.AllocatedResources != allocatedResources) && translatedResources) { irpStack->Parameters.StartDevice.AllocatedResourcesTranslated = VpRemoveFromResourceList( translatedResources, DriverObjectExtension->HwInitData.HwLegacyResourceCount, DriverObjectExtension->HwInitData.HwLegacyResourceList); } } } // // The first thing we need to do is send the START_DEVICE // irp on to our parent. // pVideoPortSendIrpToLowerDevice(DeviceObject, Irp); // // Restore the original resources. // if (irpStack->Parameters.StartDevice.AllocatedResources != allocatedResources) { ExFreePool(irpStack->Parameters.StartDevice.AllocatedResources); irpStack->Parameters.StartDevice.AllocatedResources = allocatedResources; } if (irpStack->Parameters.StartDevice.AllocatedResourcesTranslated != translatedResources) { ExFreePool(irpStack->Parameters.StartDevice.AllocatedResourcesTranslated); irpStack->Parameters.StartDevice.AllocatedResourcesTranslated = translatedResources; } if (allocatedResources) { ASSERT(translatedResources); // // Cache assigned and translated resources. // RawListSize = GetCmResourceListSize(allocatedResources); TranslatedListSize = GetCmResourceListSize(translatedResources); ASSERT(RawListSize == TranslatedListSize); fdoExtension->RawResources = ExAllocatePoolWithTag(PagedPool | POOL_COLD_ALLOCATION, RawListSize + TranslatedListSize, VP_TAG); fdoExtension->TranslatedResources = (PCM_RESOURCE_LIST) ((PUCHAR)fdoExtension->RawResources + RawListSize); if (fdoExtension->RawResources == NULL) { statusBlock->Status = STATUS_INSUFFICIENT_RESOURCES; break; } memcpy(fdoExtension->RawResources, allocatedResources, RawListSize); memcpy(fdoExtension->TranslatedResources, translatedResources, TranslatedListSize); } // // Get slot/function number // fdoExtension->SlotNumber = VpGetDeviceAddress(DeviceObject); // // Store the allocatedResources. This will allow us to // assign these resources when VideoPortGetAccessRanges // routines are called. // // NOTE: We do not actually have to copy the data, because // we are going to call FindAdapter in the context // of this function. So, this data will be intact // until we complete. // if ((allocatedResources != NULL) && (translatedResources != NULL)) { ULONG Count; PCM_PARTIAL_RESOURCE_DESCRIPTOR InterruptDesc; Count = 0; InterruptDesc = RtlUnpackPartialDesc(CmResourceTypeInterrupt, translatedResources, &Count); fdoExtension->AllocatedResources = allocatedResources; fdoExtension->SystemIoBusNumber = allocatedResources->List->BusNumber; fdoExtension->AdapterInterfaceType = allocatedResources->List->InterfaceType; // // Tuck away the giblets we need for PnP interrupt support! // if (InterruptDesc) { fdoExtension->InterruptVector = InterruptDesc->u.Interrupt.Vector; fdoExtension->InterruptIrql = (KIRQL)InterruptDesc->u.Interrupt.Level; fdoExtension->InterruptAffinity = InterruptDesc->u.Interrupt.Affinity; } } ACQUIRE_DEVICE_LOCK (combinedExtension); if (VideoPortFindAdapter(DeviceObject->DriverObject, (PVOID)&(DriverObjectExtension->RegistryPath), &(DriverObjectExtension->HwInitData), NULL, DeviceObject, &nextMiniport) == NO_ERROR) { if (nextMiniport == TRUE) { pVideoDebugPrint((1, "VIDEOPRT: The Again parameter is ignored for PnP drivers.\n")); } statusBlock->Status = STATUS_SUCCESS; // // Only put the VGA device on the hibernation path. All other // devices should be allowed to turn off during hibernation or // shutdown. // // Note: This may change in the future if we decide to keep non-VGA // device (e.g. UGA primary display) on. // if (DeviceObject == DeviceOwningVga) { pVideoPortHibernateNotify(fdoExtension->AttachedDeviceObject, FALSE); fdoExtension->OnHibernationPath = TRUE; } // // If the system is already up and running, lets call // HwInitialize now. This will allow us to enumerate // children. // if (VpSystemInitialized) { VpEnableDisplay(fdoExtension, FALSE); if (fdoExtension->HwInitialize(fdoExtension->HwDeviceExtension)) { fdoExtension->HwInitStatus = HwInitSucceeded; } else { fdoExtension->HwInitStatus = HwInitFailed; } VpEnableDisplay(fdoExtension, TRUE); } // // Indicate that resources have been assigned to this device // so that a legacy driver can't acquire resources for the // same device. // AddToResourceList(fdoExtension->SystemIoBusNumber, fdoExtension->SlotNumber); } else { statusBlock->Status = STATUS_UNSUCCESSFUL; if (fdoExtension->RawResources) { ExFreePool(fdoExtension->RawResources); } } RELEASE_DEVICE_LOCK (combinedExtension); // // Do ACPI specific stuff // if (NT_SUCCESS(pVideoPortQueryACPIInterface(DoSpecificExtension))) { DoSpecificExtension->bACPI = TRUE; } } break; case IRP_MN_QUERY_ID: pVideoDebugPrint((2, "IRP_MN_QUERYID with DeviceObject %p\n", DeviceObject)); // // Return the Hardware ID returned by the video miniport driver // if it is provided. // if (irpStack->Parameters.QueryId.IdType == BusQueryHardwareIDs) { VIDEO_CHILD_TYPE ChildType; VIDEO_CHILD_ENUM_INFO childEnumInfo; ULONG uId; ULONG unused; PUCHAR nameBuffer; nameBuffer = ExAllocatePoolWithTag(PagedPool | POOL_COLD_ALLOCATION, EDID_BUFFER_SIZE, VP_TAG); if (nameBuffer) { RtlZeroMemory(nameBuffer, EDID_BUFFER_SIZE); childEnumInfo.Size = sizeof(VIDEO_CHILD_ENUM_INFO); childEnumInfo.ChildDescriptorSize = EDID_BUFFER_SIZE; childEnumInfo.ChildIndex = DISPLAY_ADAPTER_HW_ID; childEnumInfo.ACPIHwId = 0; childEnumInfo.ChildHwDeviceExtension = NULL; ACQUIRE_DEVICE_LOCK (combinedExtension); if (fdoExtension->HwGetVideoChildDescriptor( fdoExtension->HwDeviceExtension, &childEnumInfo, &ChildType, nameBuffer, &uId, &unused) == ERROR_MORE_DATA) { statusBlock->Information = (ULONG_PTR) nameBuffer; statusBlock->Status = STATUS_SUCCESS; } RELEASE_DEVICE_LOCK (combinedExtension); } } goto CallNextDriver; case IRP_MN_QUERY_DEVICE_RELATIONS: pVideoDebugPrint((2, "IRP_MN_QUERY_DEVICE_RELATIONS with DeviceObject\n")); pVideoDebugPrint((2, "\t\t DeviceObject %p, Type = ", DeviceObject)); if (irpStack->Parameters.QueryDeviceRelations.Type == BusRelations) { pVideoDebugPrint((2, "BusRelations\n")); ACQUIRE_DEVICE_LOCK (combinedExtension); // // Disable VGA driver during the setup. Enumeration code // in the miniport can touch VGA registers. // if (VpSetupTypeAtBoot != SETUPTYPE_NONE) VpEnableDisplay(fdoExtension, FALSE); statusBlock->Status = pVideoPortEnumerateChildren(DeviceObject, Irp); // // Renable VGA driver back during the setup. // if (VpSetupTypeAtBoot != SETUPTYPE_NONE) VpEnableDisplay(fdoExtension, TRUE); RELEASE_DEVICE_LOCK (combinedExtension); if (!NT_SUCCESS(statusBlock->Status)) { goto Complete_Irp; } } goto CallNextDriver; case IRP_MN_QUERY_REMOVE_DEVICE: pVideoDebugPrint((2, "IRP_MN_QUERY_REMOVE_DEVICE\n")); statusBlock->Status = STATUS_UNSUCCESSFUL; break; case IRP_MN_CANCEL_REMOVE_DEVICE: pVideoDebugPrint((2, "IRP_MN_CANCEL_REMOVE_DEVICE\n")); statusBlock->Status = STATUS_SUCCESS; goto CallNextDriver; case IRP_MN_REMOVE_DEVICE: pVideoDebugPrint((2, "IRP_MN_REMOVE_DEVICE\n")); VpDisableAdapterInterface(fdoExtension); pVideoPortSendIrpToLowerDevice(DeviceObject, Irp); #if REMOVE_LOCK_ENABLED IoReleaseRemoveLockAndWait(pRemoveLock, Irp); RemoveLockReleased = TRUE; #endif // // If we are attached to another device, remove the attachment // if (fdoExtension->AttachedDeviceObject) { IoDetachDevice(fdoExtension->AttachedDeviceObject); } // // Remove the DeviceObject // IoDeleteDevice(DeviceObject); statusBlock->Status = STATUS_SUCCESS; break; case IRP_MN_QUERY_INTERFACE: // // Normally I would only expect to get this IRP heading for // an PDO. However, AndrewGo wants to be able to send down // these IRP's and he only has an FDO. Instead of forcing // him to get a PDO somehow, we'll just handle the irp for // a FDO as well. // pVideoDebugPrint((2, "IRP_MN_QUERY_INTERFACE\n")); ACQUIRE_DEVICE_LOCK (combinedExtension); if ((fdoExtension->HwQueryInterface) && (fdoExtension->HwDeviceExtension) && (NO_ERROR == fdoExtension->HwQueryInterface( fdoExtension->HwDeviceExtension, (PQUERY_INTERFACE) &irpStack->Parameters.QueryInterface))) { statusBlock->Status = STATUS_SUCCESS; } else if (!NT_SUCCESS(statusBlock->Status)) { // // The miniport didn't handle the QueryInterface request, see // if its an interface the videoprt supports. // PQUERY_INTERFACE qi = (PQUERY_INTERFACE) &irpStack->Parameters.QueryInterface; // // If we are responding to a known private GUID, expose // the known GUID interface ourselves. Otherwise, pass // on to the miniport driver. // if (IsEqualGUID(qi->InterfaceType, &GUID_AGP_INTERFACE)) { PAGP_INTERFACE AgpInterface = (PAGP_INTERFACE)qi->Interface; AgpInterface->Size = sizeof(AGP_INTERFACE); AgpInterface->Version = AGP_INTERFACE_VERSION; AgpInterface->Context = fdoExtension->HwDeviceExtension; if (VideoPortGetAgpServices(fdoExtension->HwDeviceExtension, &AgpInterface->AgpServices)) { statusBlock->Status = STATUS_SUCCESS; } } } RELEASE_DEVICE_LOCK (combinedExtension); goto CallNextDriver; case IRP_MN_QUERY_PNP_DEVICE_STATE: statusBlock->Status = STATUS_SUCCESS; goto CallNextDriver; default: pVideoDebugPrint((2, "PNP minor function %x not supported - forwarding \n", irpStack->MinorFunction )); goto CallNextDriver; } } Complete_Irp: // // save the final status so we can return it after the IRP is completed. // finalStatus = statusBlock->Status; #if REMOVE_LOCK_ENABLED if (RemoveLockReleased == FALSE) { IoReleaseRemoveLock(pRemoveLock, Irp); } #endif IoCompleteRequest(Irp, IO_VIDEO_INCREMENT); return finalStatus; CallNextDriver: // // Call the next driver in the chain. // IoCopyCurrentIrpStackLocationToNext(Irp); finalStatus = IoCallDriver(fdoExtension->AttachedDeviceObject, Irp); #if REMOVE_LOCK_ENABLED if (RemoveLockReleased == FALSE) { IoReleaseRemoveLock(pRemoveLock, Irp); } #endif return finalStatus; } VOID InitializePowerStruct( IN PIRP Irp, OUT PVIDEO_POWER_MANAGEMENT vpPower, OUT BOOLEAN *bWakeUp ) /*++ Routine Description: This routine initializes the power management structure we'll pass down to the miniport. Arguments: DeviceObject - The device object for the device. Irp - The irp we are handling vpPower - A pointer to the power structure we are initializing. Returns: none. --*/ { PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp); if (bWakeUp) *bWakeUp = FALSE; // // Setup for call to the miniport. // vpPower->Length = sizeof(VIDEO_POWER_MANAGEMENT); vpPower->DPMSVersion = 0; vpPower->PowerState = irpStack->Parameters.Power.State.DeviceState; // // Special case hibernation. // if (irpStack->Parameters.Power.ShutdownType == PowerActionHibernate) { // // This indicates waking from Hibernation. // if (irpStack->Parameters.Power.State.DeviceState == PowerDeviceD0) { if (bWakeUp) { *bWakeUp = TRUE; } } else { vpPower->PowerState = VideoPowerHibernate; } } else if ((irpStack->Parameters.Power.ShutdownType >= PowerActionShutdown) && (irpStack->Parameters.Power.ShutdownType < PowerActionWarmEject)) { // // Special case shutdown - force VideoPowerShutdown. // // All video adapters must disable interrupts else they may fire an interrupt // when the bridge is disabled or when the machine reboots missing #RST on // PCI bus causing an interrupt storm. // // Devices on hibernation path must stay on, the miniport driver must ensure // this. // vpPower->PowerState = VideoPowerShutdown; } } NTSTATUS pVideoPortPowerDispatch( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) /*++ Routine Description: This routine is a system-defined dispatch routine that handles all I/O request packets (IRPs) specifically for power. Currently that list entails: IRP_MJ_POWER: IRP_MN_SET_POWER IRP_MN_QUERY_POWER This routine will process the IRPs as a bus driver for the monitor and child device objects and will process the IRPs as a function driver for the adapter device object. Arguments: DeviceObject - Points to the DEVICE_OBJECT that this request is targeting. Irp - Points to the IRP for this request. Return Value: A NTSTATUS value indicating the success or failure of the operation. --*/ { PFDO_EXTENSION fdoExtension; PCHILD_PDO_EXTENSION pdoExtension = NULL; PDEVICE_SPECIFIC_EXTENSION DoSpecificExtension; PIO_STACK_LOCATION irpStack; ULONG deviceId; VP_STATUS vpStatus; VIDEO_POWER_MANAGEMENT vpPowerMgmt; POWER_STATE powerState; KEVENT event; POWER_BLOCK context; BOOLEAN bDisplayAdapter; BOOLEAN bMonitor; BOOLEAN bShutdown; NTSTATUS finalStatus = STATUS_SOME_NOT_MAPPED; PBACKLIGHT_STATUS pVpBacklightStatus = &VpBacklightStatus; PDEVICE_OBJECT AttachedDevice = NULL; ULONG ulACPIMethodParam1; BOOLEAN bSetBacklight = FALSE; PAGED_CODE(); // // Get pointer to the port driver's device extension. // if (IS_PDO(DeviceObject->DeviceExtension)) { pVideoDebugPrint((2, "VideoPortPowerDispatch: IS_PDO == TRUE (child device)\n")); pdoExtension = DeviceObject->DeviceExtension; fdoExtension = pdoExtension->pFdoExtension; bDisplayAdapter = FALSE; if (pdoExtension->VideoChildDescriptor->Type == Monitor) { bMonitor = TRUE; } else { bMonitor = FALSE; } } else if (IS_FDO(DeviceObject->DeviceExtension)) { pVideoDebugPrint((2, "VideoPortPowerDispatch: IS_FDO == TRUE (video adapter)\n")); fdoExtension = DeviceObject->DeviceExtension; DoSpecificExtension = (PDEVICE_SPECIFIC_EXTENSION)(fdoExtension + 1); bDisplayAdapter = TRUE; bMonitor = FALSE; } else { // // This case should never happen, if we got here something went terribly wrong. // pVideoDebugPrint((0, "VideoPortPowerDispatch: IRP not supported by secondary DeviceObject\n")); ASSERT(FALSE); // // Since this should never happen we don't really need this code here. // We're keeping it for now just in case of impossible happening. // PoStartNextPowerIrp(Irp); finalStatus = Irp->IoStatus.Status; IoCompleteRequest(Irp, IO_NO_INCREMENT); return finalStatus; } // // Make sure that FindAdapter has succeeded. This ensures // that in the situation where a power IRP is sent before the // device is started, no attempt to process it is made. // if (bDisplayAdapter) { if ((fdoExtension->Flags & FINDADAPTER_SUCCEEDED) == 0) { pVideoDebugPrint ((1, "VideoPortPowerDispatch: Ignoring S IRP\n")); PoStartNextPowerIrp(Irp); IoSkipCurrentIrpStackLocation (Irp); return PoCallDriver(fdoExtension->AttachedDeviceObject, Irp); } } // // Initialize the event that is used to synchronize the IRP // completions. Also initialize the power context structure. // KeInitializeEvent(&event, SynchronizationEvent, FALSE); context.Event = &event; // // Obtain information about the specific request. // irpStack = IoGetCurrentIrpStackLocation(Irp); // // Check if this is a shutdown. // if ((irpStack->Parameters.Power.ShutdownType >= PowerActionShutdown) && (irpStack->Parameters.Power.ShutdownType < PowerActionWarmEject)) { bShutdown = TRUE; } else { bShutdown = FALSE; } // // Set device id. // deviceId = bDisplayAdapter ? DISPLAY_ADAPTER_HW_ID : pdoExtension->ChildUId; // // Begin the switch for handling power IRPs // switch (irpStack->MinorFunction) { case IRP_MN_QUERY_POWER: // // Is this a system or device power IRP? // if (irpStack->Parameters.Power.Type == SystemPowerState) { pVideoDebugPrint((2, "VideoPortPowerDispatch: System query power IRP\n")); pVideoDebugPrint((2, "VideoPortPowerDispatch: Device object = %p\n", DeviceObject)); pVideoDebugPrint((2, "VideoPortPowerDispatch: Requested state = %d\n", irpStack->Parameters.Power.State.SystemState)); // // This is a system power IRP. The objective here is to // quickly determine if we can safely support a proposed // transition to the requested system power state. // if (!pVideoPortMapStoD(DeviceObject->DeviceExtension, irpStack->Parameters.Power.State.SystemState, &powerState.DeviceState)) { pVideoDebugPrint((0, "VideoPortPowerDispatch: Couldn't get S->D mapping\n")); finalStatus = STATUS_UNSUCCESSFUL; break; } // // Mark the IRP as pending now as unless there is a failure, // this IRP will be returned with status_pending. // IoMarkIrpPending(Irp); // // Request the power IRP and go. // finalStatus = PoRequestPowerIrp(DeviceObject, IRP_MN_QUERY_POWER, powerState, pVideoPortPowerIrpComplete, Irp, NULL); } else { pVideoDebugPrint((2, "VideoPortPowerDispatch: Device query power IRP\n")); pVideoDebugPrint((2, "VideoPortPowerDispatch: Device object = %p\n", DeviceObject)); pVideoDebugPrint((2, "VideoPortPowerDispatch: Requested state = %d\n", irpStack->Parameters.Power.State.DeviceState)); InitializePowerStruct(Irp, &vpPowerMgmt, NULL); // // For OEMs like Toshiba, they want alway map sleep state to D3 due to a // legal patent issue. The patent prohibit them from using more than one // sleep state. // if (bMonitor && fdoExtension->OverrideMonitorPower && (vpPowerMgmt.PowerState >= VideoPowerStandBy) && (vpPowerMgmt.PowerState < VideoPowerOff)) { vpPowerMgmt.PowerState = VideoPowerOff; } // // Call the miniport. No need to acquire the miniport lock as // power IRP's are serial. // ACQUIRE_DEVICE_LOCK(fdoExtension); vpStatus = fdoExtension->HwGetPowerState(fdoExtension->HwDeviceExtension, deviceId, &vpPowerMgmt); RELEASE_DEVICE_LOCK(fdoExtension); if (vpStatus != NO_ERROR) { pVideoDebugPrint((1, "VideoPortPowerDispatch: Mini refused state %d\n", vpPowerMgmt.PowerState)); // // If this is the shutdown ignore miniport. We should never ever get // here, since shutdown IRPs are unconditional, i.e. we're getting only // set requests, which are by definition unfailable, but this is just in // case power folks change their minds. // if (bShutdown) { pVideoDebugPrint ((1, "VideoPortPowerDispatch: Ignoring miniport - forcing shutdown\n")); finalStatus = STATUS_SUCCESS; } else { finalStatus = STATUS_DEVICE_POWER_FAILURE; } } else { finalStatus = STATUS_SUCCESS; } } // // End processing for IRP_MN_QUERY_POWER. Indicate to the system that // the next PowerIrp can be sent. // break; case IRP_MN_SET_POWER: if (irpStack->Parameters.Power.Type == SystemPowerState) { pVideoDebugPrint((2, "VideoPortPowerDispatch: System set power IRP\n")) ; pVideoDebugPrint((2, "VideoPortPowerDispatch: Device object = %p\n", DeviceObject)) ; pVideoDebugPrint((2, "VideoPortPowerDispatch: Requested state = %d\n", irpStack->Parameters.Power.State.SystemState)) ; // // Special case: // // The power guys decided they don't want us to send a D3 set power irp for our devices // down the stack if we are going to leave the device on during the shutdown. // We want to notify miniport driver but we're not going to request D3 irp. // // Note: We handle calls to miniport here for all devices on hibernation path at the // shutdown (pdo and fdo) since we don't want to get out of order calls. // if (bShutdown && fdoExtension->OnHibernationPath) { // // Call the miniport if device is on now. // powerState.DeviceState = bDisplayAdapter ? fdoExtension->DevicePowerState: pdoExtension->DevicePowerState; if (powerState.DeviceState == PowerDeviceD0) { vpPowerMgmt.Length = sizeof(VIDEO_POWER_MANAGEMENT); vpPowerMgmt.DPMSVersion = 0; vpPowerMgmt.PowerState = VideoPowerShutdown; pVideoDebugPrint((2, "VideoPortPowerDispatch: HwSetPowerState for video power state %d\n", vpPowerMgmt.PowerState)); ACQUIRE_DEVICE_LOCK(fdoExtension); vpStatus = fdoExtension->HwSetPowerState(fdoExtension->HwDeviceExtension, deviceId, &vpPowerMgmt); RELEASE_DEVICE_LOCK(fdoExtension); if (vpStatus != NO_ERROR) { pVideoDebugPrint((0, "VideoPortPowerDispatch: ERROR IN MINIPORT!\n")); pVideoDebugPrint((0, "VideoPortPowerDispatch: Miniport cannot refuse set power request\n")); // // Don't assert here for now - not all miniport drivers handle VideoPowerShutdown. // } } finalStatus = STATUS_SUCCESS; break; } // // If this is a S0 request for the monitor, ignore it (this is // so the monitor doesn't power up too early) // if (bMonitor && (irpStack->Parameters.Power.State.SystemState == PowerSystemWorking)) { finalStatus = STATUS_SUCCESS; break; } // // Get the device power state that matches the system power // state. // if (!pVideoPortMapStoD(DeviceObject->DeviceExtension, irpStack->Parameters.Power.State.SystemState, &powerState.DeviceState)) { pVideoDebugPrint((0, "VideoPortPowerDispatch: Couldn't get S->D mapping\n")); pVideoDebugPrint((0, "VideoPortPowerDispatch: Can't fail the set!!!\n")); if (irpStack->Parameters.Power.State.SystemState < PowerSystemSleeping1) { powerState.DeviceState = PowerDeviceD0; } else { powerState.DeviceState = PowerDeviceD3; } } // // Request a power IRP for a device power state. // IoMarkIrpPending(Irp); finalStatus = PoRequestPowerIrp(DeviceObject, IRP_MN_SET_POWER, powerState, pVideoPortPowerIrpComplete, Irp, NULL); } else { BOOLEAN bWakeUp; pVideoDebugPrint((2, "VideoPortPowerDispatch: Device set power IRP\n")) ; pVideoDebugPrint((2, "VideoPortPowerDispatch: Device object = %p\n", DeviceObject)) ; pVideoDebugPrint((2, "VideoPortPowerDispatch: Requested state = %d\n", irpStack->Parameters.Power.State.DeviceState)) ; // // This is a set power request (device request). Here the // processing becomes a little more complex. The general // behavior is to just quickly tell the miniport to set // the requested power state and get out. However, in the // case of a hibernation request we will pass a special // code to the miniport telling it that this is hibernation. // It should save state, but NOT (repeat) NOT power off the // device. // InitializePowerStruct(Irp, &vpPowerMgmt, &bWakeUp); powerState.DeviceState = bDisplayAdapter ? fdoExtension->DevicePowerState: pdoExtension->DevicePowerState; // // Make sure not to power up the monitor if the override for // LCD panels is on. // if (bMonitor && pdoExtension->PowerOverride && (irpStack->Parameters.Power.State.DeviceState < powerState.DeviceState)) { finalStatus = STATUS_SUCCESS; break; } // // If this is going to a more powered state. (i.e. waking up) // Send the IRP down the stack and then continue processing. // Since videoport is the bus driver for the monitors, // power down without sending the IRP to the device stack. // if (bDisplayAdapter && (irpStack->Parameters.Power.State.DeviceState < powerState.DeviceState)) { pVideoDebugPrint ((1, "VideoPortPowerDispatch: PowerUp\n")); context.Event = &event; IoCopyCurrentIrpStackLocationToNext (Irp); IoSetCompletionRoutine(Irp, pVideoPortPowerUpComplete, &context, TRUE, TRUE, TRUE); finalStatus = PoCallDriver(fdoExtension->AttachedDeviceObject, Irp); if (!NT_SUCCESS(finalStatus) || finalStatus == STATUS_PENDING) { if (finalStatus != STATUS_PENDING) { pVideoDebugPrint((0, "VideoPortPowerDispatch: Someone under us FAILED a set power???\n")) ; ASSERT(FALSE); break; } else { KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL); } } else { context.Status = finalStatus; } finalStatus = STATUS_ALREADY_DISCONNECTED; // // End processing if the call to power up failed. // if (!NT_SUCCESS(context.Status)) { pVideoDebugPrint ((0, "VideoPortPowerDispatch: Someone under us FAILED a powerup\n")) ; break ; } } // // For OEMs like Toshiba, they want alway map sleep state to D3 due to a // legal patent issue. The patent prohibit them from using more than one // sleep state. // if (bMonitor && fdoExtension->OverrideMonitorPower && (vpPowerMgmt.PowerState >= VideoPowerStandBy) && (vpPowerMgmt.PowerState < VideoPowerOff)) { vpPowerMgmt.PowerState = VideoPowerOff; } if ((deviceId == 0x110) && (vpPowerMgmt.PowerState == VideoPowerOn)) { // // If the new backlight control interface is implemented, // set the backlight brightness level. // if ((pVpBacklightStatus->bNewAPISupported == TRUE) && (pVpBacklightStatus->bACBrightnessKnown == TRUE) && (VpRunningOnAC == TRUE)) { ulACPIMethodParam1= (ULONG) pVpBacklightStatus->ucACBrightness; bSetBacklight = TRUE; } if ((pVpBacklightStatus->bNewAPISupported == TRUE) && (pVpBacklightStatus->bDCBrightnessKnown == TRUE) && (VpRunningOnAC == FALSE)) { ulACPIMethodParam1= (ULONG) pVpBacklightStatus->ucDCBrightness; bSetBacklight = TRUE; } if ((bSetBacklight) && (LCDPanelDevice)) { AttachedDevice = IoGetAttachedDeviceReference(LCDPanelDevice); // Not checking status here deliberately, as we're not failing // this IRP if this call fails. if (AttachedDevice) { pVideoPortACPIIoctl( AttachedDevice, (ULONG) ('MCB_'), &ulACPIMethodParam1, NULL, 0, NULL); ObDereferenceObject(AttachedDevice); } } } // // Call the miniport. // pVideoDebugPrint((2, "VideoPortPowerDispatch: HwSetPowerState for video power state %d\n", vpPowerMgmt.PowerState)); ACQUIRE_DEVICE_LOCK(fdoExtension); vpStatus = fdoExtension->HwSetPowerState(fdoExtension->HwDeviceExtension, deviceId, &vpPowerMgmt); RELEASE_DEVICE_LOCK(fdoExtension); if (vpStatus != NO_ERROR) { pVideoDebugPrint((0, "VideoPortPowerDispatch: ERROR IN MINIPORT!\n")); pVideoDebugPrint((0, "VideoPortPowerDispatch: Miniport cannot refuse set power request\n")); // // Don't assert if shutdown - not all miniport drivers handle VideoPowerShutdown. // This code executes for devices not on the hibernation path during the shutdown. // if (!bShutdown) { ASSERT(FALSE); } } // // Set the power state to let the system know that the power // state has been changed for the device. // PoSetPowerState(DeviceObject, DevicePowerState, irpStack->Parameters.Power.State); if (bDisplayAdapter) { fdoExtension->DevicePowerState = irpStack->Parameters.Power.State.DeviceState; } else { pdoExtension->DevicePowerState = irpStack->Parameters.Power.State.DeviceState; } // // Do some ACPI related stuff. // if (bDisplayAdapter && DoSpecificExtension->bACPI && (fdoExtension->DevicePowerState == PowerDeviceD0)) { // // If we received a Notify before SetPowerState, delay the action until now. // if (DoSpecificExtension->CachedEventID) { pVideoPortACPIEventCallback(DoSpecificExtension, DoSpecificExtension->CachedEventID); } else if (bWakeUp) { // // On waking up from Hibernation, we simulate a notify(VGA, 0x90). // This will also set _DOS(0). Some machines don't keep _DOS value, // So we have to set the value on waking up. // pVideoPortACPIEventCallback(DoSpecificExtension, 0x90); } } // // Set the final status if the IRP has not been passed down. // If the IRP has not been passed down yet, finalStatus is set // when it is passed down. // if (!bDisplayAdapter) { // // All PDO's must have STATUS_SUCCESS as a SET_POWER IRP // cannot fail. // finalStatus = STATUS_SUCCESS; } } break; default: // // Pass down requests we don't handle if this is an fdo, complete // the irp if it is a pdo. // if (bDisplayAdapter) { PoStartNextPowerIrp(Irp); IoSkipCurrentIrpStackLocation(Irp); return PoCallDriver(fdoExtension->AttachedDeviceObject, Irp); } else { PoStartNextPowerIrp(Irp); finalStatus = Irp->IoStatus.Status; IoCompleteRequest(Irp, IO_NO_INCREMENT); return finalStatus; } } // // If status pending then just bail out of this routine // without completing anything as there is still an power // IRP outstanding. The completion routine takes care of // ensuring that the IRP is completed. // if (finalStatus != STATUS_PENDING) { // // Alert the system that the driver is ready for the next power IRP. // PoStartNextPowerIrp(Irp); // // All processing has been finished. Complete the IRP and get out. // if (bDisplayAdapter) { // // FDO Irps need to be sent to the bus driver. This path // indicates that it is an FDO Irp that has not already been // sent to the bus driver. (The only way it would have already // been sent is if this is an FDO power-up). // if (NT_SUCCESS(finalStatus)) { pVideoDebugPrint((1, "VideoPortPowerDispatch: Non-powerup FDO\n")); IoSkipCurrentIrpStackLocation (Irp); return PoCallDriver(fdoExtension->AttachedDeviceObject, Irp); } else if (finalStatus == STATUS_ALREADY_DISCONNECTED) { pVideoDebugPrint((2, "VideoPortPowerDispatch: Power iostatus modified, IRP already sent\n")); finalStatus = context.Status; } pVideoDebugPrint((2, "VideoPortPowerDispatch: Power fell through bDisplayAdapter\n")) ; } pVideoDebugPrint((1, "VideoPortPowerDispatch: Power completed with %x\n", finalStatus)); Irp->IoStatus.Status = finalStatus; IoCompleteRequest(Irp, IO_NO_INCREMENT); } return finalStatus; } BOOLEAN pVideoPortMapStoD( IN PVOID DeviceExtension, IN SYSTEM_POWER_STATE SystemState, OUT PDEVICE_POWER_STATE DeviceState ) /*++ Routine Description: This routine takes a system power state from a system power IRP and maps it to the correct D state for the device based on what is stored in its device extension. Arguments: DeviceExtension - Points to either the FDO or PDO device extension. SystemState - The system power state being requested. DeviceState - A pointer to the location to store the device state. Return Value: TRUE if successsful, FALSE otherwise. --*/ { PFDO_EXTENSION combinedExtension = ((PFDO_EXTENSION)(DeviceExtension)); if (combinedExtension->IsMappingReady != TRUE) { // // The mapping from system states to device states has not // happened yet. Package up a request to do this and send it // to the parent device stack. // PIRP irp; KEVENT event; PDEVICE_CAPABILITIES parentCapabilities; IO_STATUS_BLOCK statusBlock; PIO_STACK_LOCATION stackLocation; NTSTATUS status; UCHAR count; PDEVICE_OBJECT targetDevice; pVideoDebugPrint((1, "VideoPrt: No mapping ready. Creating mapping.\n")); if (IS_FDO(combinedExtension)) { targetDevice = combinedExtension->AttachedDeviceObject; } else { targetDevice = combinedExtension->pFdoExtension->AttachedDeviceObject; } // // Allocate memory for the device capabilities structure and // zero the memory. // parentCapabilities = ExAllocatePoolWithTag(PagedPool | POOL_COLD_ALLOCATION, sizeof (DEVICE_CAPABILITIES), VP_TAG); if (parentCapabilities == NULL) { pVideoDebugPrint((0, "VideoPrt: Couldn't get memory for cap run.\n")); return FALSE; } RtlZeroMemory(parentCapabilities, sizeof (DEVICE_CAPABILITIES)); parentCapabilities->Size = sizeof (DEVICE_CAPABILITIES) ; parentCapabilities->Version = 1 ; parentCapabilities->Address = -1 ; parentCapabilities->UINumber = -1 ; // // Prepare the IRP request. // KeInitializeEvent(&event, SynchronizationEvent, FALSE); irp = IoBuildSynchronousFsdRequest(IRP_MJ_PNP, targetDevice, NULL, 0, NULL, &event, &statusBlock); if (irp == NULL) { pVideoDebugPrint((0, "VideoPrt: Couldn't get IRP for cap run.\n")); ExFreePool(parentCapabilities); return FALSE; } irp->IoStatus.Status = STATUS_NOT_SUPPORTED; stackLocation = IoGetNextIrpStackLocation(irp); stackLocation->MajorFunction = IRP_MJ_PNP; stackLocation->MinorFunction = IRP_MN_QUERY_CAPABILITIES; stackLocation->Parameters.DeviceCapabilities.Capabilities = parentCapabilities; status = IoCallDriver (targetDevice, irp); if (status == STATUS_PENDING) { KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL); } if (!(NT_SUCCESS(statusBlock.Status))) { pVideoDebugPrint ((0, "VideoPrt: Couldn't get parent caps.\n")); } else { for (count = PowerSystemUnspecified; count < PowerSystemMaximum; count++) { #if DBG static PUCHAR SystemState[] = {"PowerSystemUnspecified", "PowerSystemWorking", "PowerSystemSleeping1", "PowerSystemSleeping2", "PowerSystemSleeping3", "PowerSystemHibernate", "PowerSystemShutdown", "PowerSystemMaximum"}; static PUCHAR DeviceState[] = {"PowerDeviceUnspecified", "PowerDeviceD0", "PowerDeviceD1", "PowerDeviceD2", "PowerDeviceD3", "PowerDeviceMaximum"}; #endif combinedExtension->DeviceMapping[count] = parentCapabilities->DeviceState[count]; #if DBG pVideoDebugPrint((1, "Mapping %s = %s\n", SystemState[count], DeviceState[combinedExtension->DeviceMapping[count]])); #endif } // // For monitor devices, make sure to map not to D0 for any sleep state. // if (IS_PDO(combinedExtension) && (((PCHILD_PDO_EXTENSION)(DeviceExtension))->VideoChildDescriptor->Type == Monitor)) { for (count = PowerSystemSleeping1; count <= PowerSystemSleeping3; count++) { if ((combinedExtension->DeviceMapping[count] == PowerDeviceD0) || (combinedExtension->pFdoExtension->OverrideMonitorPower)) { pVideoDebugPrint((1, "Override sleep %d to D3\n", count)) ; combinedExtension->DeviceMapping[count] = PowerDeviceD3 ; } } } } ExFreePool(parentCapabilities); if (!NT_SUCCESS(statusBlock.Status)) { return FALSE; } combinedExtension->IsMappingReady = TRUE ; } // // Return the mapping now. // *DeviceState = combinedExtension->DeviceMapping[SystemState]; return TRUE; } VOID pVideoPortPowerIrpComplete( IN PDEVICE_OBJECT DeviceObject, IN UCHAR MinorFunction, IN POWER_STATE PowerState, IN PVOID Context, IN PIO_STATUS_BLOCK IoStatus ) /*++ Routine Description: This is a power management IRP completion routine that is set each time video requests a device power IRP in response to a system power IRP. Arguments: DeviceObject - Points to the device object that initiated the IRP MinorFunction - Specified the minor function code of the completed IRP PowerState - Specifies the power state passed to PoRequestPowerIrp Context - Specifies the IRP that was pended waiting for this completion routine to fire IoStatus - Points to the IoStatus block in the completed IRP Return Value: None. --*/ { PFDO_EXTENSION fdoExtension = DeviceObject->DeviceExtension ; PIRP irp = (PIRP) Context ; if (Context == NULL) { // // This is the fall through case. Since we have no IRP this // is just a place holder since callers of PoRequestPowerIrp // must specify a completion routine. // return; } // // Set the status in the IRP // irp->IoStatus.Status = IoStatus->Status; pVideoDebugPrint((2, "VideoPrt: Power completion Irp status: %X\n", IoStatus->Status)); // // Indicate to the system that videoprt is ready for the next // power IRP. // PoStartNextPowerIrp(irp); // // If this is an FDO, then pass the IRP down to the bus driver. // if (IS_FDO((PFDO_EXTENSION)(DeviceObject->DeviceExtension)) && NT_SUCCESS(IoStatus->Status)) { pVideoDebugPrint((2, "VideoPrt: Completion passing down.\n")); IoSkipCurrentIrpStackLocation(irp); PoCallDriver(fdoExtension->AttachedDeviceObject, irp); } else { pVideoDebugPrint((2, "VideoPrt: Completion not passing down.\n")); IoCompleteRequest(irp, IO_NO_INCREMENT); } } NTSTATUS pVideoPortPowerUpComplete( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context ) /*++ Routine Description: This is an IRP completion routine that is set when a IRP must be passed down the device stack before videoport acts on it. (A power up case. The bus must be powered before the device.) Arguments: DeviceObject - Points to the device object of the owner of the completion routine Irp - Points to the IRP being completed Context - Specifies a videoport-defined context of POWER_BLOCK Return Value: Always returns STATUS_MORE_PROCESSING_REQUIRED to stop further completion of the IRP. --*/ { PPOWER_BLOCK block = (PPOWER_BLOCK)Context; block->Status = Irp->IoStatus.Status; KeSetEvent(block->Event, IO_NO_INCREMENT, FALSE); return STATUS_MORE_PROCESSING_REQUIRED; } PCM_PARTIAL_RESOURCE_DESCRIPTOR RtlUnpackPartialDesc( IN UCHAR Type, IN PCM_RESOURCE_LIST ResList, IN OUT PULONG Count ) /*++ Routine Description: Pulls out a pointer to the partial descriptor you're interested in Arguments: Type - CmResourceTypePort, ... ResList - The list to search Count - Points to the index of the partial descriptor you're looking for, gets incremented if found, i.e., start with *Count = 0, then subsequent calls will find next partial, make sense? Return Value: Pointer to the partial descriptor if found, otherwise NULL --*/ { ULONG i, j, hit; hit = 0; for (i = 0; i < ResList->Count; i++) { for (j = 0; j < ResList->List[i].PartialResourceList.Count; j++) { if (ResList->List[i].PartialResourceList.PartialDescriptors[j].Type == Type) { if (hit == *Count) { (*Count)++; return &ResList->List[i].PartialResourceList.PartialDescriptors[j]; } else { hit++; } } } } return NULL; } NTSTATUS pVideoPortSystemControl( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) /*++ Routine Description: This routine handles SystemControl Irps. Arguments: DeviceObject - The device object. Irp - The system control Irp. Returns: Status Notes: This function will simply complete the irp if we are handling for the PDO, or send the irp down if the device object is an FDO. --*/ { NTSTATUS status; if (IS_PDO(DeviceObject->DeviceExtension)) { status = Irp->IoStatus.Status; IoCompleteRequest(Irp, IO_NO_INCREMENT); } else { PFDO_EXTENSION fdoExtension = (PFDO_EXTENSION)DeviceObject->DeviceExtension; IoCopyCurrentIrpStackLocationToNext(Irp); status = IoCallDriver(fdoExtension->AttachedDeviceObject, Irp); } return status; }