2067 lines
50 KiB
C
2067 lines
50 KiB
C
/*++
|
||
|
||
Copyright (c) 1998 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
acpidock.c
|
||
|
||
Abstract:
|
||
|
||
This module handles docking issues for ACPI.
|
||
|
||
For each dock, we create a node off the root of ACPI called a "profile
|
||
provider". This node represents that individual dock. We do this so
|
||
that the OS can determine the current or upcoming hardware profile
|
||
without having to start that portion of the tree which leads down to
|
||
the dock. Also, as multiple simulataneous docks are supported via ACPI,
|
||
we make them all children of the root so that the OS can pick up the
|
||
hardware profile in just one pass.
|
||
|
||
Author:
|
||
|
||
Adrian J. Oney (AdriaO)
|
||
|
||
Environment:
|
||
|
||
Kernel mode only.
|
||
|
||
Revision History:
|
||
|
||
20-Jan-98 Initial Revision
|
||
|
||
--*/
|
||
|
||
#include "pch.h"
|
||
#include "amlreg.h"
|
||
#include <stdio.h>
|
||
|
||
#ifdef ALLOC_PRAGMA
|
||
#pragma alloc_text(PAGE,ACPIDockIrpStartDevice)
|
||
#pragma alloc_text(PAGE,ACPIDockIrpQueryCapabilities)
|
||
#pragma alloc_text(PAGE,ACPIDockIrpQueryDeviceRelations)
|
||
#pragma alloc_text(PAGE,ACPIDockIrpEject)
|
||
#pragma alloc_text(PAGE,ACPIDockIrpQueryID)
|
||
#pragma alloc_text(PAGE,ACPIDockIrpSetLock)
|
||
#pragma alloc_text(PAGE,ACPIDockIrpQueryEjectRelations)
|
||
#pragma alloc_text(PAGE,ACPIDockIrpQueryInterface)
|
||
#pragma alloc_text(PAGE,ACPIDockIrpQueryPnpDeviceState)
|
||
#pragma alloc_text(PAGE,ACPIDockIntfReference)
|
||
#pragma alloc_text(PAGE,ACPIDockIntfDereference)
|
||
#pragma alloc_text(PAGE,ACPIDockIntfSetMode)
|
||
#pragma alloc_text(PAGE,ACPIDockIntfUpdateDeparture)
|
||
#endif
|
||
|
||
|
||
PDEVICE_EXTENSION
|
||
ACPIDockFindCorrespondingDock(
|
||
IN PDEVICE_EXTENSION DeviceExtension
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine takes a pointer to an ACPI object an returns the dock extension
|
||
that matches it.
|
||
|
||
Argument Description:
|
||
|
||
DeviceExtension - The device for which we want the dock
|
||
|
||
Return Value:
|
||
|
||
NULL or the matching extension for the profile provider
|
||
|
||
--*/
|
||
{
|
||
PDEVICE_EXTENSION rootChildExtension = NULL ;
|
||
EXTENSIONLIST_ENUMDATA eled ;
|
||
|
||
ACPIExtListSetupEnum(
|
||
&eled,
|
||
&(RootDeviceExtension->ChildDeviceList),
|
||
&AcpiDeviceTreeLock,
|
||
SiblingDeviceList,
|
||
WALKSCHEME_HOLD_SPINLOCK
|
||
) ;
|
||
|
||
for(rootChildExtension = ACPIExtListStartEnum(&eled);
|
||
ACPIExtListTestElement(&eled, TRUE) ;
|
||
rootChildExtension = ACPIExtListEnumNext(&eled)) {
|
||
|
||
if (!rootChildExtension) {
|
||
|
||
ACPIExtListExitEnumEarly(&eled);
|
||
break;
|
||
|
||
}
|
||
|
||
if (!(rootChildExtension->Flags & DEV_PROP_DOCK)) {
|
||
|
||
continue;
|
||
|
||
}
|
||
|
||
if (rootChildExtension->Dock.CorrospondingAcpiDevice ==
|
||
DeviceExtension) {
|
||
|
||
ACPIExtListExitEnumEarly(&eled) ;
|
||
break;
|
||
|
||
}
|
||
|
||
}
|
||
|
||
//
|
||
// Done
|
||
//
|
||
return rootChildExtension;
|
||
}
|
||
|
||
NTSTATUS
|
||
ACPIDockGetDockObject(
|
||
IN PNSOBJ AcpiObject,
|
||
OUT PNSOBJ *dckObject
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine gets the _DCK method object if the device has one
|
||
|
||
Arguments:
|
||
|
||
The ACPI Object to test.
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS (failure if _DCK method does not exist)
|
||
|
||
--*/
|
||
{
|
||
return AMLIGetNameSpaceObject(
|
||
"_DCK",
|
||
AcpiObject,
|
||
dckObject,
|
||
NSF_LOCAL_SCOPE
|
||
);
|
||
}
|
||
|
||
NTSTATUS
|
||
ACPIDockIrpEject(
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Arguments:
|
||
|
||
DeviceObject - The device to get the capabilities for
|
||
Irp - The request to the device to tell it to stop
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS
|
||
|
||
--*/
|
||
{
|
||
PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation( Irp );
|
||
UCHAR minorFunction = irpStack->MinorFunction;
|
||
PDEVICE_EXTENSION deviceExtension = ACPIInternalGetDeviceExtension(DeviceObject);
|
||
PDEVICE_EXTENSION dockDeviceExtension;
|
||
PNSOBJ ej0Object;
|
||
NTSTATUS status;
|
||
ULONG i, ignoredPerSpec ;
|
||
|
||
PAGED_CODE();
|
||
|
||
//
|
||
// The dock may have failed _DCK on a start, in which case we have kept
|
||
// it around for the explicit purpose of ejecting it. Now we make the dock
|
||
// go away.
|
||
//
|
||
ACPIInternalUpdateFlags(
|
||
&(deviceExtension->Flags),
|
||
DEV_CAP_UNATTACHED_DOCK,
|
||
TRUE
|
||
);
|
||
|
||
//
|
||
// lets get the corrosponding dock node for this device
|
||
//
|
||
dockDeviceExtension = deviceExtension->Dock.CorrospondingAcpiDevice ;
|
||
|
||
if (!dockDeviceExtension) {
|
||
|
||
//
|
||
// Invalid name space object <bad>
|
||
//
|
||
ACPIDevPrint( (
|
||
ACPI_PRINT_FAILURE,
|
||
deviceExtension,
|
||
"(0x%08lx): ACPIDockIrpEject: no corresponding extension!!\n",
|
||
Irp
|
||
) );
|
||
ASSERT(0);
|
||
|
||
//
|
||
// Mark the irp as very bad...
|
||
//
|
||
Irp->IoStatus.Status = STATUS_UNSUCCESSFUL ;
|
||
IoCompleteRequest( Irp, IO_NO_INCREMENT );
|
||
return STATUS_UNSUCCESSFUL;
|
||
|
||
}
|
||
|
||
if (deviceExtension->Dock.ProfileDepartureStyle == PDS_UPDATE_ON_EJECT) {
|
||
|
||
//
|
||
// On the Compaq Armada 7800, we switch UARTs during an undock, thus we
|
||
// lose the debugger com port programming.
|
||
//
|
||
KdDisableDebugger();
|
||
|
||
if (deviceExtension->Dock.IsolationState != IS_ISOLATED) {
|
||
|
||
status = ACPIGetIntegerEvalIntegerSync(
|
||
dockDeviceExtension,
|
||
PACKED_DCK,
|
||
0,
|
||
&ignoredPerSpec
|
||
);
|
||
|
||
deviceExtension->Dock.IsolationState = IS_ISOLATED;
|
||
}
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
|
||
KdEnableDebugger();
|
||
|
||
Irp->IoStatus.Status = status ;
|
||
IoCompleteRequest( Irp, IO_NO_INCREMENT );
|
||
return status ;
|
||
}
|
||
}
|
||
|
||
ej0Object = ACPIAmliGetNamedChild(
|
||
dockDeviceExtension->AcpiObject,
|
||
PACKED_EJ0
|
||
);
|
||
|
||
if (ej0Object != NULL) {
|
||
|
||
status = ACPIGetNothingEvalIntegerSync(
|
||
dockDeviceExtension,
|
||
PACKED_EJ0,
|
||
1
|
||
);
|
||
|
||
} else {
|
||
|
||
status = STATUS_OBJECT_NAME_NOT_FOUND;
|
||
|
||
}
|
||
|
||
if (deviceExtension->Dock.ProfileDepartureStyle == PDS_UPDATE_ON_EJECT) {
|
||
|
||
KdEnableDebugger() ;
|
||
}
|
||
|
||
//
|
||
// The dock may have failed _DCK on a start, in which case we have kept
|
||
// it around for the explicit purpose of ejecting it. Now we make the dock
|
||
// go away.
|
||
//
|
||
ACPIInternalUpdateFlags(
|
||
&(deviceExtension->Flags),
|
||
DEV_CAP_UNATTACHED_DOCK,
|
||
TRUE
|
||
);
|
||
|
||
if (NT_SUCCESS(status)) {
|
||
|
||
//
|
||
// Get the currrent device status
|
||
//
|
||
status = ACPIGetDevicePresenceSync(
|
||
deviceExtension,
|
||
(PVOID *) &i,
|
||
NULL
|
||
);
|
||
if (NT_SUCCESS(status) &&
|
||
!(deviceExtension->Flags & DEV_TYPE_NOT_PRESENT)) {
|
||
|
||
ACPIDevPrint( (
|
||
ACPI_PRINT_FAILURE,
|
||
deviceExtension,
|
||
"(0x%08lx): ACPIDockIrpEjectDevice: "
|
||
"dock is still listed as present after _DCK/_EJx!\n",
|
||
Irp
|
||
) );
|
||
|
||
//
|
||
// The device did not go away. Let us fail this
|
||
//
|
||
status = STATUS_UNSUCCESSFUL ;
|
||
|
||
}
|
||
}
|
||
|
||
Irp->IoStatus.Status = status;
|
||
IoCompleteRequest( Irp, IO_NO_INCREMENT );
|
||
|
||
return status ;
|
||
}
|
||
|
||
NTSTATUS
|
||
ACPIDockIrpQueryCapabilities(
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This handles a request to get the capabilities of a device.
|
||
|
||
Arguments:
|
||
|
||
DeviceObject - The device to get the capabilities for
|
||
Irp - The request to the device to tell it to stop
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS status ;
|
||
PDEVICE_EXTENSION deviceExtension = ACPIInternalGetDeviceExtension(DeviceObject);
|
||
PDEVICE_EXTENSION dockDeviceExtension;
|
||
PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation( Irp );
|
||
UCHAR minorFunction = irpStack->MinorFunction;
|
||
PDEVICE_CAPABILITIES capabilities;
|
||
PNSOBJ acpiObject ;
|
||
|
||
PAGED_CODE();
|
||
|
||
//
|
||
// Grab a pointer to the capabilities
|
||
//
|
||
capabilities = irpStack->Parameters.DeviceCapabilities.Capabilities;
|
||
|
||
dockDeviceExtension = deviceExtension->Dock.CorrospondingAcpiDevice ;
|
||
|
||
if (!dockDeviceExtension) {
|
||
|
||
ACPIDevPrint( (
|
||
ACPI_PRINT_FAILURE,
|
||
deviceExtension,
|
||
"(0x%08lx): ACPIDockIrpQueryCapabilities: "
|
||
"no corresponding extension!!\n",
|
||
Irp
|
||
) );
|
||
ASSERT(0) ;
|
||
Irp->IoStatus.Status = STATUS_UNSUCCESSFUL ;
|
||
IoCompleteRequest( Irp, IO_NO_INCREMENT );
|
||
return STATUS_UNSUCCESSFUL;
|
||
|
||
}
|
||
|
||
acpiObject = dockDeviceExtension->AcpiObject ;
|
||
|
||
//
|
||
// Set the current flags for the capabilities
|
||
//
|
||
capabilities->SilentInstall = TRUE;
|
||
capabilities->RawDeviceOK = TRUE;
|
||
capabilities->DockDevice = TRUE;
|
||
capabilities->Removable = TRUE;
|
||
capabilities->UniqueID = TRUE;
|
||
|
||
if (ACPIAmliGetNamedChild( acpiObject, PACKED_EJ0)) {
|
||
|
||
capabilities->EjectSupported = TRUE;
|
||
}
|
||
|
||
if (ACPIAmliGetNamedChild( acpiObject, PACKED_EJ1) ||
|
||
ACPIAmliGetNamedChild( acpiObject, PACKED_EJ2) ||
|
||
ACPIAmliGetNamedChild( acpiObject, PACKED_EJ3) ||
|
||
ACPIAmliGetNamedChild( acpiObject, PACKED_EJ4)) {
|
||
|
||
capabilities->WarmEjectSupported = TRUE;
|
||
}
|
||
|
||
//
|
||
// An object of this name signifies the node is lockable
|
||
//
|
||
#if !defined(ACPI_INTERNAL_LOCKING)
|
||
if (ACPIAmliGetNamedChild( acpiObject, PACKED_LCK) != NULL) {
|
||
|
||
capabilities->LockSupported = TRUE;
|
||
|
||
}
|
||
#endif
|
||
|
||
//
|
||
// Internally record the power capabilities
|
||
//
|
||
status = ACPISystemPowerQueryDeviceCapabilities(
|
||
deviceExtension,
|
||
capabilities
|
||
);
|
||
|
||
//
|
||
// Round down S1-S3 to D3. This will ensure we reexamine the _STA after
|
||
// resume from sleep (note that we won't actually be playing with the docks
|
||
// power methods, so this is safe)
|
||
//
|
||
capabilities->DeviceState[PowerSystemSleeping1] = PowerDeviceD3;
|
||
capabilities->DeviceState[PowerSystemSleeping2] = PowerDeviceD3;
|
||
capabilities->DeviceState[PowerSystemSleeping3] = PowerDeviceD3;
|
||
|
||
//
|
||
// We can do this slimy-like because we don't have any Wake bits or
|
||
// anything else fancy.
|
||
//
|
||
IoCopyDeviceCapabilitiesMapping(
|
||
capabilities,
|
||
deviceExtension->PowerInfo.DevicePowerMatrix
|
||
);
|
||
|
||
//
|
||
// Now update our power matrix.
|
||
//
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
|
||
ACPIDevPrint( (
|
||
ACPI_PRINT_CRITICAL,
|
||
deviceExtension,
|
||
" - Could query device capabilities - %08lx",
|
||
status
|
||
) );
|
||
}
|
||
|
||
ACPIDevPrint( (
|
||
ACPI_PRINT_IRP,
|
||
deviceExtension,
|
||
"(0x%08lx): %s = 0x%08lx\n",
|
||
Irp,
|
||
ACPIDebugGetIrpText(IRP_MJ_PNP, minorFunction),
|
||
status
|
||
) );
|
||
|
||
Irp->IoStatus.Status = status;
|
||
IoCompleteRequest( Irp, IO_NO_INCREMENT );
|
||
|
||
return status;
|
||
}
|
||
|
||
NTSTATUS
|
||
ACPIDockIrpQueryDeviceRelations(
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This handles a request to query device relations. Since profile providers
|
||
never have children, we only need to fix up the eject relations
|
||
appropriately
|
||
|
||
Arguments:
|
||
|
||
DeviceObject - The device to get the capabilities for
|
||
Irp - The request to the device to tell it to stop
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS status = STATUS_NOT_SUPPORTED;
|
||
PDEVICE_EXTENSION deviceExtension = ACPIInternalGetDeviceExtension(DeviceObject);
|
||
PDEVICE_RELATIONS deviceRelations = (PDEVICE_RELATIONS) Irp->IoStatus.Information;
|
||
PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation( Irp );
|
||
UCHAR minorFunction = irpStack->MinorFunction;
|
||
|
||
PAGED_CODE();
|
||
|
||
switch(irpStack->Parameters.QueryDeviceRelations.Type) {
|
||
|
||
case BusRelations:
|
||
break ;
|
||
|
||
case TargetDeviceRelation:
|
||
|
||
status = ACPIBusIrpQueryTargetRelation(
|
||
DeviceObject,
|
||
Irp,
|
||
&deviceRelations
|
||
);
|
||
break ;
|
||
|
||
case EjectionRelations:
|
||
|
||
status = ACPIDockIrpQueryEjectRelations(
|
||
DeviceObject,
|
||
Irp,
|
||
&deviceRelations
|
||
);
|
||
break ;
|
||
|
||
default:
|
||
|
||
ACPIDevPrint( (
|
||
ACPI_PRINT_IRP,
|
||
deviceExtension,
|
||
"(0x%08lx): %s - Unhandled Type %d\n",
|
||
Irp,
|
||
ACPIDebugGetIrpText(IRP_MJ_PNP, minorFunction),
|
||
irpStack->Parameters.QueryDeviceRelations.Type
|
||
) );
|
||
break ;
|
||
}
|
||
|
||
//
|
||
// If we succeeds, then we can always write to the irp
|
||
//
|
||
if (NT_SUCCESS(status)) {
|
||
|
||
Irp->IoStatus.Status = status;
|
||
Irp->IoStatus.Information = (ULONG_PTR) deviceRelations;
|
||
|
||
} else if ((status != STATUS_NOT_SUPPORTED) && (deviceRelations == NULL)) {
|
||
|
||
//
|
||
// If we haven't succeed the irp, then we can also fail it, but only
|
||
// if nothing else has been added.
|
||
//
|
||
Irp->IoStatus.Status = status;
|
||
Irp->IoStatus.Information = (ULONG_PTR) NULL;
|
||
|
||
} else {
|
||
|
||
//
|
||
// Grab our status from what is already present
|
||
//
|
||
status = Irp->IoStatus.Status;
|
||
}
|
||
|
||
//
|
||
// Done with the irp
|
||
//
|
||
IoCompleteRequest( Irp, IO_NO_INCREMENT );
|
||
|
||
//
|
||
// Done
|
||
//
|
||
ACPIDevPrint( (
|
||
ACPI_PRINT_IRP,
|
||
deviceExtension,
|
||
"(0x%08lx): %s = 0x%08lx\n",
|
||
Irp,
|
||
ACPIDebugGetIrpText(IRP_MJ_PNP, minorFunction),
|
||
status
|
||
) );
|
||
return status;
|
||
}
|
||
|
||
NTSTATUS
|
||
ACPIDockIrpQueryEjectRelations(
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp,
|
||
IN OUT PDEVICE_RELATIONS *PdeviceRelations
|
||
)
|
||
{
|
||
PDEVICE_EXTENSION deviceExtension = ACPIInternalGetDeviceExtension(DeviceObject);
|
||
PDEVICE_EXTENSION dockDeviceExtension ;
|
||
PNSOBJ acpiObject = NULL;
|
||
NTSTATUS status ;
|
||
|
||
PAGED_CODE();
|
||
|
||
//
|
||
// lets get the corrosponding dock node for this device
|
||
//
|
||
dockDeviceExtension = deviceExtension->Dock.CorrospondingAcpiDevice ;
|
||
if (!dockDeviceExtension) {
|
||
|
||
//
|
||
// Invalid name space object <bad>
|
||
//
|
||
ACPIDevPrint( (
|
||
ACPI_PRINT_FAILURE,
|
||
deviceExtension,
|
||
"(0x%08lx): ACPIDockIrpQueryEjectRelations: "
|
||
"no corresponding extension!!\n",
|
||
Irp
|
||
) );
|
||
ASSERT(0) ;
|
||
return STATUS_UNSUCCESSFUL;
|
||
|
||
}
|
||
|
||
//
|
||
// lets look at the ACPIObject that we have so can see if it is valid...
|
||
//
|
||
acpiObject = dockDeviceExtension->AcpiObject;
|
||
if (acpiObject == NULL) {
|
||
|
||
//
|
||
// Invalid name space object <bad>
|
||
//
|
||
ACPIDevPrint( (
|
||
ACPI_PRINT_CRITICAL,
|
||
deviceExtension,
|
||
"(0x%08lx): ACPIDockIrpQueryEjectRelations: "
|
||
"invalid ACPIObject (0x%08lx)\n",
|
||
acpiObject
|
||
) );
|
||
return STATUS_INVALID_PARAMETER;
|
||
|
||
}
|
||
|
||
status = ACPIDetectEjectDevices(
|
||
dockDeviceExtension,
|
||
PdeviceRelations,
|
||
dockDeviceExtension
|
||
);
|
||
|
||
//
|
||
// If something went wrong...
|
||
//
|
||
if (!NT_SUCCESS(status)) {
|
||
|
||
//
|
||
// That's not nice..
|
||
//
|
||
ACPIDevPrint( (
|
||
ACPI_PRINT_CRITICAL,
|
||
deviceExtension,
|
||
"(0x%08lx): ACPIDockIrpQueryEjectRelations: enum 0x%08lx\n",
|
||
Irp,
|
||
status
|
||
) );
|
||
|
||
}
|
||
return status ;
|
||
}
|
||
|
||
NTSTATUS
|
||
ACPIDockIrpQueryID(
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is the dispatch point for the IRP_MN_QUERY_ID PNP
|
||
minor function
|
||
|
||
Note: This is what the returned strings from this function should look
|
||
like.
|
||
|
||
DeviceID = ACPI\DockDevice
|
||
InstanceID = ACPI object node ( CDCK, etc )
|
||
HardwareIDs = ACPI\DockDevice&_SB.DOCK, ACPI\DockDevice
|
||
|
||
Arguments:
|
||
|
||
DeviceObject - The object that we care about
|
||
Irp - The request in question
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS
|
||
|
||
--*/
|
||
{
|
||
BUS_QUERY_ID_TYPE type;
|
||
NTSTATUS status;
|
||
PDEVICE_EXTENSION deviceExtension = ACPIInternalGetDeviceExtension(DeviceObject);
|
||
PDEVICE_EXTENSION dockDeviceExtension;
|
||
PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation( Irp );
|
||
PNSOBJ acpiObject = deviceExtension->AcpiObject;
|
||
PUCHAR buffer;
|
||
UCHAR minorFunction = irpStack->MinorFunction;
|
||
UNICODE_STRING unicodeIdString;
|
||
PWCHAR serialID;
|
||
ULONG firstHardwareIDLength;
|
||
|
||
PAGED_CODE();
|
||
|
||
//
|
||
// Initilize the Unicode Structure
|
||
//
|
||
RtlZeroMemory( &unicodeIdString, sizeof(UNICODE_STRING) );
|
||
|
||
//
|
||
// What we do is based on the IdType of the Request...
|
||
//
|
||
type = irpStack->Parameters.QueryId.IdType;
|
||
switch (type) {
|
||
case BusQueryDeviceID:
|
||
|
||
//
|
||
// We pre-calculate this since it is so useful for debugging
|
||
//
|
||
status = ACPIInitUnicodeString(
|
||
&unicodeIdString,
|
||
deviceExtension->DeviceID
|
||
);
|
||
break;
|
||
|
||
case BusQueryDeviceSerialNumber:
|
||
|
||
//
|
||
// lets get the corrosponding dock node for this device
|
||
//
|
||
dockDeviceExtension = deviceExtension->Dock.CorrospondingAcpiDevice;
|
||
|
||
if (!dockDeviceExtension) {
|
||
|
||
//
|
||
// Invalid name space object <bad>
|
||
//
|
||
ACPIDevPrint( (
|
||
ACPI_PRINT_FAILURE,
|
||
deviceExtension,
|
||
"(0x%08lx): ACPIDockIrpQueryID: no corresponding extension!!\n",
|
||
Irp
|
||
) );
|
||
ASSERT(0);
|
||
|
||
//
|
||
// Mark the irp as very bad...
|
||
//
|
||
Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
|
||
IoCompleteRequest( Irp, IO_NO_INCREMENT );
|
||
return STATUS_UNSUCCESSFUL;
|
||
}
|
||
|
||
status = ACPIGetSerialIDWide(
|
||
dockDeviceExtension,
|
||
&serialID,
|
||
NULL
|
||
);
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
|
||
break;
|
||
}
|
||
|
||
//
|
||
// Return the Serial Number for the DockDevice
|
||
//
|
||
unicodeIdString.Buffer = serialID;
|
||
break;
|
||
|
||
case BusQueryInstanceID:
|
||
|
||
//
|
||
// We pre-calculate this since it is so useful for debugging
|
||
//
|
||
status = ACPIInitUnicodeString(
|
||
&unicodeIdString,
|
||
deviceExtension->InstanceID
|
||
);
|
||
|
||
break;
|
||
|
||
case BusQueryCompatibleIDs:
|
||
|
||
status = STATUS_NOT_SUPPORTED;
|
||
break;
|
||
|
||
case BusQueryHardwareIDs:
|
||
|
||
//
|
||
// Now set our identifier. In theory, the OS could use this
|
||
// string in any scenario, although in reality it will key off
|
||
// of the dock ID.
|
||
//
|
||
// Construct the MultiSz hardware ID list:
|
||
// ACPI\DockDevice&_SB.PCI0.DOCK
|
||
// ACPI\DockDevice
|
||
//
|
||
status = ACPIInitMultiString(
|
||
&unicodeIdString,
|
||
"ACPI\\DockDevice",
|
||
deviceExtension->InstanceID,
|
||
"ACPI\\DockDevice",
|
||
NULL
|
||
);
|
||
|
||
if (NT_SUCCESS(status)) {
|
||
|
||
//
|
||
// Replace first '\0' with '&'
|
||
//
|
||
firstHardwareIDLength = wcslen(unicodeIdString.Buffer);
|
||
unicodeIdString.Buffer[firstHardwareIDLength] = L'&';
|
||
}
|
||
|
||
break;
|
||
|
||
default:
|
||
|
||
ACPIDevPrint( (
|
||
ACPI_PRINT_IRP,
|
||
deviceExtension,
|
||
"(0x%08lx): %s - Unhandled Id %d\n",
|
||
Irp,
|
||
ACPIDebugGetIrpText(IRP_MJ_PNP, minorFunction),
|
||
type
|
||
) );
|
||
status = STATUS_NOT_SUPPORTED;
|
||
break;
|
||
|
||
} // switch
|
||
|
||
//
|
||
// Did we pass or did we fail?
|
||
//
|
||
if (NT_SUCCESS(status)) {
|
||
|
||
Irp->IoStatus.Information = (ULONG_PTR) unicodeIdString.Buffer;
|
||
|
||
} else {
|
||
|
||
Irp->IoStatus.Information = (ULONG_PTR) NULL;
|
||
|
||
}
|
||
|
||
Irp->IoStatus.Status = status;
|
||
IoCompleteRequest( Irp, IO_NO_INCREMENT );
|
||
|
||
ACPIDevPrint( (
|
||
ACPI_PRINT_IRP,
|
||
deviceExtension,
|
||
"(0x%08lx): %s(%d) = 0x%08lx\n",
|
||
Irp,
|
||
ACPIDebugGetIrpText(IRP_MJ_PNP, minorFunction),
|
||
type,
|
||
status
|
||
) );
|
||
return status;
|
||
}
|
||
|
||
NTSTATUS
|
||
ACPIDockIrpQueryInterface(
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is the dispatch point for the IRP_MN_QUERY_INTERFACE minor
|
||
function. The only reason we respond to this is so we can handle the
|
||
dock interface which is used to solve the removal ordering problem we won't
|
||
be fixing 5.0 (sigh).
|
||
|
||
Arguments:
|
||
|
||
DeviceObject - The object that we care about
|
||
Irp - The request in question
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS status;
|
||
PDEVICE_EXTENSION deviceExtension = ACPIInternalGetDeviceExtension(DeviceObject);
|
||
PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation( Irp );
|
||
UCHAR minorFunction = irpStack->MinorFunction;
|
||
LPGUID interfaceType;
|
||
|
||
PAGED_CODE();
|
||
|
||
status = Irp->IoStatus.Status;
|
||
interfaceType = (LPGUID) irpStack->Parameters.QueryInterface.InterfaceType;
|
||
|
||
if (CompareGuid(interfaceType, (PVOID) &GUID_DOCK_INTERFACE)) {
|
||
|
||
DOCK_INTERFACE dockInterface;
|
||
USHORT count;
|
||
|
||
//
|
||
// Only copy up to current size of the ACPI_INTERFACE structure
|
||
//
|
||
if (irpStack->Parameters.QueryInterface.Size > sizeof(DOCK_INTERFACE)) {
|
||
|
||
count = sizeof(DOCK_INTERFACE);
|
||
|
||
} else {
|
||
|
||
count = irpStack->Parameters.QueryInterface.Size;
|
||
|
||
}
|
||
|
||
//
|
||
// Build up the interface structure.
|
||
//
|
||
dockInterface.Size = count;
|
||
dockInterface.Version = DOCK_INTRF_STANDARD_VER;
|
||
dockInterface.Context = DeviceObject;
|
||
dockInterface.InterfaceReference = ACPIDockIntfReference;
|
||
dockInterface.InterfaceDereference = ACPIDockIntfDereference;
|
||
dockInterface.ProfileDepartureSetMode = ACPIDockIntfSetMode;
|
||
dockInterface.ProfileDepartureUpdate = ACPIDockIntfUpdateDeparture;
|
||
|
||
//
|
||
// Give it a reference
|
||
//
|
||
dockInterface.InterfaceReference(dockInterface.Context);
|
||
|
||
//
|
||
// Hand back the interface
|
||
//
|
||
RtlCopyMemory(
|
||
(PDOCK_INTERFACE) irpStack->Parameters.QueryInterface.Interface,
|
||
&dockInterface,
|
||
count
|
||
);
|
||
|
||
//
|
||
// We're done with this irp
|
||
//
|
||
Irp->IoStatus.Status = status = STATUS_SUCCESS;
|
||
}
|
||
|
||
IoCompleteRequest( Irp, IO_NO_INCREMENT );
|
||
|
||
ACPIDevPrint( (
|
||
ACPI_PRINT_IRP,
|
||
deviceExtension,
|
||
"(0x%08lx): %s = 0x%08lx\n",
|
||
Irp,
|
||
ACPIDebugGetIrpText(IRP_MJ_PNP, minorFunction),
|
||
status
|
||
) );
|
||
return status;
|
||
}
|
||
|
||
NTSTATUS
|
||
ACPIDockIrpQueryPnpDeviceState(
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is the dispatch point for the IRP_MN_QUERY_PNP_DEVICE_STATE
|
||
minor function. The only reason we respond to this is so we can set the
|
||
PNP_DEVICE_DONT_DISPLAY_IN_UI flag (we are a raw PDO that does not need
|
||
to be visible)
|
||
|
||
Arguments:
|
||
|
||
DeviceObject - The object that we care about
|
||
Irp - The request in question
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS status = STATUS_SUCCESS;
|
||
PDEVICE_EXTENSION deviceExtension = ACPIInternalGetDeviceExtension(DeviceObject);
|
||
PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation( Irp );
|
||
UCHAR minorFunction = irpStack->MinorFunction;
|
||
|
||
PAGED_CODE();
|
||
|
||
Irp->IoStatus.Information |= PNP_DEVICE_DONT_DISPLAY_IN_UI ;
|
||
|
||
Irp->IoStatus.Status = status;
|
||
IoCompleteRequest( Irp, IO_NO_INCREMENT );
|
||
|
||
ACPIDevPrint( (
|
||
ACPI_PRINT_IRP,
|
||
deviceExtension,
|
||
"(0x%08lx): %s = 0x%08lx\n",
|
||
Irp,
|
||
ACPIDebugGetIrpText(IRP_MJ_PNP, minorFunction),
|
||
status
|
||
) );
|
||
return status;
|
||
}
|
||
|
||
NTSTATUS
|
||
ACPIDockIrpQueryPower(
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routines tells the system what PNP state the device is in
|
||
|
||
Arguments:
|
||
|
||
DeviceObject - The device whose state we want to know
|
||
Irp - The request
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS status;
|
||
PDEVICE_EXTENSION deviceExtension = ACPIInternalGetDeviceExtension(DeviceObject);
|
||
PDEVICE_EXTENSION dockDeviceExtension ;
|
||
PIO_STACK_LOCATION irpSp;
|
||
PNSOBJ acpiObject, ejectObject ;
|
||
SYSTEM_POWER_STATE systemState;
|
||
ULONG packedEJx ;
|
||
|
||
dockDeviceExtension = deviceExtension->Dock.CorrospondingAcpiDevice ;
|
||
|
||
if (!dockDeviceExtension) {
|
||
|
||
ACPIDevPrint( (
|
||
ACPI_PRINT_FAILURE,
|
||
deviceExtension,
|
||
"(0x%08lx): ACPIDockIrpQueryPower - "
|
||
"no corresponding extension!!\n",
|
||
Irp
|
||
) );
|
||
ASSERT(0) ;
|
||
return ACPIDispatchPowerIrpSuccess( DeviceObject, Irp );
|
||
}
|
||
|
||
//
|
||
// Get the Current stack location to determine if we are a system
|
||
// irp or a device irp. We ignore device irps here.
|
||
//
|
||
irpSp = IoGetCurrentIrpStackLocation(Irp);
|
||
if (irpSp->Parameters.Power.Type != SystemPowerState) {
|
||
|
||
//
|
||
// We don't handle this irp
|
||
//
|
||
return ACPIDispatchPowerIrpSuccess( DeviceObject, Irp );
|
||
}
|
||
|
||
if (irpSp->Parameters.Power.ShutdownType != PowerActionWarmEject) {
|
||
|
||
//
|
||
// No eject work - complete the IRP.
|
||
//
|
||
return ACPIDispatchPowerIrpSuccess( DeviceObject, Irp );
|
||
}
|
||
|
||
//
|
||
// Restrict power states to those supported.
|
||
//
|
||
acpiObject = dockDeviceExtension->AcpiObject;
|
||
|
||
//
|
||
// What system state are we looking at?
|
||
//
|
||
systemState = irpSp->Parameters.Power.State.SystemState;
|
||
|
||
switch (irpSp->Parameters.Power.State.SystemState) {
|
||
|
||
case PowerSystemSleeping1:
|
||
packedEJx = PACKED_EJ1;
|
||
break;
|
||
case PowerSystemSleeping2:
|
||
packedEJx = PACKED_EJ2;
|
||
break;
|
||
case PowerSystemSleeping3:
|
||
packedEJx = PACKED_EJ3;
|
||
break;
|
||
case PowerSystemHibernate:
|
||
packedEJx = PACKED_EJ4;
|
||
break;
|
||
case PowerSystemWorking:
|
||
case PowerSystemShutdown:
|
||
default:
|
||
packedEJx = 0;
|
||
break;
|
||
}
|
||
|
||
if (packedEJx) {
|
||
|
||
ejectObject = ACPIAmliGetNamedChild( acpiObject, packedEJx);
|
||
if (ejectObject == NULL) {
|
||
|
||
//
|
||
// Fail the request, as we cannot eject in this case.
|
||
//
|
||
PoStartNextPowerIrp( Irp );
|
||
Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
|
||
IoCompleteRequest( Irp, IO_NO_INCREMENT );
|
||
return STATUS_UNSUCCESSFUL;
|
||
}
|
||
}
|
||
|
||
return ACPIDispatchPowerIrpSuccess( DeviceObject, Irp );
|
||
}
|
||
|
||
NTSTATUS
|
||
ACPIDockIrpRemoveDevice(
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is called when we need to remove the device. Note that we only
|
||
delete ourselves if we have been undocked (ie, our hardware is gone)
|
||
|
||
Arguments:
|
||
|
||
DeviceObject - The dock device to "remove"
|
||
Irp - The request to the device to tell it to go away
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS
|
||
|
||
--*/
|
||
{
|
||
LONG oldReferenceCount;
|
||
KIRQL oldIrql;
|
||
NTSTATUS status = STATUS_SUCCESS;
|
||
PDEVICE_EXTENSION deviceExtension = ACPIInternalGetDeviceExtension(DeviceObject);
|
||
PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation( Irp );
|
||
UCHAR minorFunction = irpStack->MinorFunction;
|
||
ULONG i, ignoredPerSpec;
|
||
|
||
if (!(deviceExtension->Flags & DEV_MASK_NOT_PRESENT)) {
|
||
|
||
//
|
||
// If the device is still physically present, so must the PDO be.
|
||
// This case is essentially a stop. Mark the request as complete...
|
||
//
|
||
Irp->IoStatus.Status = status;
|
||
IoCompleteRequest( Irp, IO_NO_INCREMENT );
|
||
return status;
|
||
}
|
||
|
||
if (deviceExtension->DeviceState == Removed) {
|
||
|
||
Irp->IoStatus.Status = STATUS_NO_SUCH_DEVICE;
|
||
IoCompleteRequest( Irp, IO_NO_INCREMENT );
|
||
return STATUS_NO_SUCH_DEVICE;
|
||
}
|
||
|
||
if (deviceExtension->Dock.ProfileDepartureStyle == PDS_UPDATE_ON_REMOVE) {
|
||
|
||
PDEVICE_EXTENSION dockDeviceExtension;
|
||
|
||
//
|
||
// lets get the corrosponding dock node for this device
|
||
//
|
||
dockDeviceExtension = deviceExtension->Dock.CorrospondingAcpiDevice ;
|
||
|
||
//
|
||
// On the Compaq Armada 7800, we switch UARTs during an undock, thus we
|
||
// lose the debugger com port programming.
|
||
//
|
||
if (deviceExtension->Dock.IsolationState != IS_ISOLATED) {
|
||
|
||
KdDisableDebugger();
|
||
|
||
status = ACPIGetIntegerEvalIntegerSync(
|
||
dockDeviceExtension,
|
||
PACKED_DCK,
|
||
0,
|
||
&ignoredPerSpec
|
||
);
|
||
|
||
KdEnableDebugger();
|
||
}
|
||
}
|
||
|
||
//
|
||
// The device is gone. Let the isolation state reflect that.
|
||
//
|
||
deviceExtension->Dock.IsolationState = IS_UNKNOWN;
|
||
|
||
//
|
||
// Set the device state as removed
|
||
//
|
||
deviceExtension->DeviceState = Removed;
|
||
|
||
//
|
||
// Complete the request
|
||
//
|
||
Irp->IoStatus.Status = STATUS_SUCCESS;
|
||
Irp->IoStatus.Information = (ULONG_PTR) NULL;
|
||
IoCompleteRequest( Irp, IO_NO_INCREMENT );
|
||
|
||
//
|
||
// Done
|
||
//
|
||
ACPIDevPrint( (
|
||
ACPI_PRINT_IRP,
|
||
deviceExtension,
|
||
"(0x%08lx): %s = 0x%08lx\n",
|
||
Irp,
|
||
ACPIDebugGetIrpText(IRP_MJ_PNP, minorFunction),
|
||
STATUS_SUCCESS
|
||
) );
|
||
|
||
//
|
||
// Update the device extension
|
||
//
|
||
KeAcquireSpinLock( &AcpiDeviceTreeLock, &oldIrql );
|
||
|
||
ASSERT(!(deviceExtension->Flags&DEV_TYPE_FILTER)) ;
|
||
|
||
//
|
||
// Step one is to zero out the things that we no longer care about
|
||
//
|
||
deviceExtension->TargetDeviceObject = NULL;
|
||
deviceExtension->PhysicalDeviceObject = NULL;
|
||
deviceExtension->DeviceObject = NULL;
|
||
|
||
//
|
||
// Mark the node as being fresh and untouched
|
||
//
|
||
ACPIInternalUpdateFlags( &(deviceExtension->Flags), DEV_MASK_TYPE, TRUE );
|
||
ACPIInternalUpdateFlags( &(deviceExtension->Flags), DEV_TYPE_NOT_FOUND, FALSE );
|
||
ACPIInternalUpdateFlags( &(deviceExtension->Flags), DEV_TYPE_REMOVED, FALSE );
|
||
|
||
//
|
||
// The reference count should have value > 0
|
||
//
|
||
oldReferenceCount = InterlockedDecrement(
|
||
&(deviceExtension->ReferenceCount)
|
||
);
|
||
|
||
ASSERT(oldReferenceCount >= 0) ;
|
||
|
||
if ( oldReferenceCount == 0) {
|
||
|
||
//
|
||
// Delete the extension
|
||
//
|
||
ACPIInitDeleteDeviceExtension( deviceExtension );
|
||
|
||
}
|
||
|
||
//
|
||
// Done with the lock
|
||
//
|
||
KeReleaseSpinLock( &AcpiDeviceTreeLock, oldIrql );
|
||
|
||
//
|
||
// Delete the device
|
||
//
|
||
IoDeleteDevice( DeviceObject );
|
||
|
||
//
|
||
// Done
|
||
//
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
NTSTATUS
|
||
ACPIDockIrpSetLock(
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Arguments:
|
||
|
||
DeviceObject - The device to set the lock state for
|
||
Irp - The request to the device to tell it to lock
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS status;
|
||
|
||
PAGED_CODE();
|
||
|
||
//
|
||
// We aren't a real device, so we don't do locking.
|
||
//
|
||
status = Irp->IoStatus.Status ;
|
||
IoCompleteRequest( Irp, IO_NO_INCREMENT );
|
||
|
||
return status ;
|
||
}
|
||
|
||
NTSTATUS
|
||
ACPIDockIrpStartDevice(
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This handles a request to start the device
|
||
|
||
Arguments:
|
||
|
||
DeviceObject - The device to start
|
||
Irp - The request to the device to tell it to start
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS status = STATUS_SUCCESS;
|
||
PDEVICE_EXTENSION deviceExtension = ACPIInternalGetDeviceExtension(DeviceObject);
|
||
PDEVICE_EXTENSION dockDeviceExtension;
|
||
PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation( Irp );
|
||
UCHAR minorFunction = irpStack->MinorFunction;
|
||
ULONG dockResult;
|
||
ULONG dockStatus;
|
||
|
||
PAGED_CODE();
|
||
|
||
dockDeviceExtension = deviceExtension->Dock.CorrospondingAcpiDevice ;
|
||
|
||
if (!dockDeviceExtension) {
|
||
|
||
ACPIDevPrint( (
|
||
ACPI_PRINT_FAILURE,
|
||
deviceExtension,
|
||
"(0x%08lx): ACPIDockIrpStartDevice - "
|
||
"no corresponding extension!!\n",
|
||
Irp
|
||
) );
|
||
ASSERT(0) ;
|
||
Irp->IoStatus.Status = STATUS_UNSUCCESSFUL ;
|
||
IoCompleteRequest( Irp, IO_NO_INCREMENT );
|
||
return STATUS_UNSUCCESSFUL;
|
||
|
||
}
|
||
|
||
if (deviceExtension->Dock.IsolationState == IS_ISOLATED) {
|
||
|
||
KdDisableDebugger();
|
||
|
||
//
|
||
// Note: the way that this is structured is that we get
|
||
// the _DCK value first, and if that succeeds, then we
|
||
// get the device presence. If that also succeeds, then
|
||
// we try to process the two. If either fail, we don't
|
||
// do any work
|
||
//
|
||
status = ACPIGetIntegerEvalIntegerSync(
|
||
dockDeviceExtension,
|
||
PACKED_DCK,
|
||
1,
|
||
&dockResult
|
||
);
|
||
|
||
if (NT_SUCCESS(status)) {
|
||
|
||
//
|
||
// Get the device presence
|
||
//
|
||
status = ACPIGetDevicePresenceSync(
|
||
dockDeviceExtension,
|
||
(PVOID *) &dockStatus,
|
||
NULL
|
||
);
|
||
|
||
}
|
||
|
||
KdEnableDebugger();
|
||
|
||
if (NT_SUCCESS(status)) {
|
||
|
||
if (dockDeviceExtension->Flags & DEV_TYPE_NOT_PRESENT) {
|
||
|
||
if (dockResult != 0) {
|
||
|
||
ACPIDevPrint( (
|
||
ACPI_PRINT_FAILURE,
|
||
deviceExtension,
|
||
"(0x%08lx): ACPIDockIrpStartDevice: "
|
||
"Not present, but _DCK = %08lx\n",
|
||
Irp,
|
||
dockResult
|
||
) );
|
||
|
||
} else {
|
||
|
||
ACPIDevPrint( (
|
||
ACPI_PRINT_FAILURE,
|
||
deviceExtension,
|
||
"(0x%08lx): ACPIDockIrpStartDevice: _DCK = 0\n",
|
||
Irp
|
||
) );
|
||
|
||
}
|
||
status = STATUS_UNSUCCESSFUL ;
|
||
|
||
} else {
|
||
|
||
if (dockResult != 1) {
|
||
|
||
ACPIDevPrint( (
|
||
ACPI_PRINT_FAILURE,
|
||
deviceExtension,
|
||
"(0x%08lx): ACPIDockIrpStartDevice: _DCK = 0\n",
|
||
Irp
|
||
) );
|
||
|
||
} else {
|
||
|
||
ACPIDevPrint( (
|
||
ACPI_PRINT_IRP,
|
||
deviceExtension,
|
||
"(0x%08lx): ACPIDockIrpStartDevice = 0x%08lx\n",
|
||
Irp,
|
||
status
|
||
) );
|
||
|
||
}
|
||
}
|
||
}
|
||
|
||
//
|
||
// We are done. The ACPI implementers guide says we don't need to
|
||
// enumerate the entire tree here as the _DCK method should have
|
||
// notified the appropriate branches of the tree if the docking event
|
||
// was successful. Unfortunately Win2K behavior was to enumerate the
|
||
// entire tree. Specifically, it would drain starts before enums. Since
|
||
// the profile provider appeared at the top of the tree, the dock would
|
||
// start and then the enum that found it would proceed and find the
|
||
// hardware. To maintain this pseudo-behavior we queue an enum here
|
||
// (bletch.)
|
||
//
|
||
IoInvalidateDeviceRelations(
|
||
RootDeviceExtension->PhysicalDeviceObject,
|
||
BusRelations
|
||
);
|
||
|
||
//
|
||
// Now we remove the unattached dock flag, but only if we succeeded
|
||
// start. If we cleared it in the failure case, we couldn't eject the
|
||
// dock that may be physically attached. Note that this also means we
|
||
// *must* try to eject the dock after start failure! The proper code for
|
||
// this is part of the kernel.
|
||
//
|
||
if (NT_SUCCESS(status)) {
|
||
|
||
ACPIInternalUpdateFlags(
|
||
&(deviceExtension->Flags),
|
||
DEV_CAP_UNATTACHED_DOCK,
|
||
TRUE
|
||
);
|
||
}
|
||
}
|
||
|
||
if (NT_SUCCESS(status)) {
|
||
|
||
deviceExtension->Dock.IsolationState = IS_ISOLATION_DROPPED;
|
||
deviceExtension->DeviceState = Started;
|
||
}
|
||
|
||
Irp->IoStatus.Status = status;
|
||
IoCompleteRequest( Irp, IO_NO_INCREMENT );
|
||
|
||
return status;
|
||
}
|
||
|
||
BOOLEAN
|
||
ACPIDockIsDockDevice(
|
||
IN PNSOBJ AcpiObject
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine will tell the caller whether the given device is a dock.
|
||
|
||
Arguments:
|
||
|
||
The ACPI Object to test.
|
||
|
||
Return Value:
|
||
|
||
BOOLEAN (true iff dock)
|
||
|
||
--*/
|
||
{
|
||
PNSOBJ dckMethodObject ;
|
||
|
||
//
|
||
// ACPI dock devices are identified via _DCK methods.
|
||
//
|
||
return (NT_SUCCESS(ACPIDockGetDockObject(AcpiObject, &dckMethodObject))) ;
|
||
}
|
||
|
||
NTSTATUS
|
||
ACPIDockIrpSetPower(
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine handles request to set the power state for a Physical
|
||
Device object
|
||
|
||
Arguments:
|
||
|
||
DeviceObject - The PDO target of the request
|
||
Irp - The request
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS status;
|
||
PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation( Irp );
|
||
UCHAR minorFunction = irpSp->MinorFunction;
|
||
|
||
if (irpSp->Parameters.Power.Type != SystemPowerState) {
|
||
|
||
return ACPIDockIrpSetDevicePower(DeviceObject, Irp);
|
||
|
||
} else {
|
||
|
||
return ACPIDockIrpSetSystemPower(DeviceObject, Irp);
|
||
}
|
||
}
|
||
|
||
NTSTATUS
|
||
ACPIDockIrpSetDevicePower(
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine handles device power request for a dock PDO
|
||
|
||
Arguments:
|
||
|
||
DeviceObject - The PDO target
|
||
Irp - The request
|
||
IrpStack - The current request
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS status;
|
||
PDEVICE_EXTENSION deviceExtension;
|
||
|
||
//
|
||
// Get the device extension
|
||
//
|
||
deviceExtension = ACPIInternalGetDeviceExtension( DeviceObject );
|
||
|
||
//
|
||
// We are going to do some work on the irp, so mark it as being
|
||
// successfull for now
|
||
//
|
||
Irp->IoStatus.Status = STATUS_SUCCESS;
|
||
|
||
//
|
||
// Mark the irp as pending
|
||
//
|
||
IoMarkIrpPending( Irp );
|
||
|
||
//
|
||
// We might queue up the irp, so this counts as a completion routine.
|
||
// Which means we need to incr the ref count
|
||
//
|
||
InterlockedIncrement( &deviceExtension->OutstandingIrpCount );
|
||
|
||
//
|
||
// Queue the irp up. Note that we will *always* call the completion
|
||
// routine, so we don't really care what was returned directly by
|
||
// this call --- the callback gets a chance to execute.
|
||
//
|
||
status = ACPIDeviceIrpDeviceRequest(
|
||
DeviceObject,
|
||
Irp,
|
||
ACPIDeviceIrpCompleteRequest
|
||
);
|
||
|
||
//
|
||
// Did we return STATUS_MORE_PROCESSING_REQUIRED (which we used
|
||
// if we overload STATUS_PENDING)
|
||
//
|
||
if (status == STATUS_MORE_PROCESSING_REQUIRED) {
|
||
|
||
status = STATUS_PENDING;
|
||
|
||
}
|
||
|
||
//
|
||
// Note: We called the completion routine, which should have completed
|
||
// the IRP with the same STATUS code as is being returned here (okay, if
|
||
// it is STATUS_PENDING, obviously we haven't completed the IRP, but that
|
||
// is okay).
|
||
//
|
||
return status;
|
||
}
|
||
|
||
NTSTATUS
|
||
ACPIDockIrpSetSystemPower(
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine handles request to set the system power state for a Physical
|
||
Device object. Here we initiate warm ejects and act as a power policy
|
||
manager for ourselves.
|
||
|
||
Arguments:
|
||
|
||
DeviceObject - The PDO target of the request
|
||
Irp - The request
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS status;
|
||
PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation( Irp );
|
||
UCHAR minorFunction = irpSp->MinorFunction;
|
||
PDEVICE_EXTENSION deviceExtension = ACPIInternalGetDeviceExtension(DeviceObject);
|
||
PDEVICE_EXTENSION dockDeviceExtension;
|
||
SYSTEM_POWER_STATE systemState;
|
||
DEVICE_POWER_STATE deviceState;
|
||
POWER_STATE powerState;
|
||
|
||
//
|
||
// Get the device extension
|
||
//
|
||
deviceExtension = ACPIInternalGetDeviceExtension( DeviceObject );
|
||
|
||
//
|
||
// Grab these two values. They are required for further calculations
|
||
//
|
||
systemState= irpSp->Parameters.Power.State.SystemState;
|
||
deviceState = deviceExtension->PowerInfo.DevicePowerMatrix[systemState];
|
||
|
||
dockDeviceExtension = deviceExtension->Dock.CorrospondingAcpiDevice ;
|
||
|
||
if (!dockDeviceExtension) {
|
||
|
||
ACPIDevPrint( (
|
||
ACPI_PRINT_FAILURE,
|
||
deviceExtension,
|
||
"(0x%08lx): ACPIDockIrpSetPower - "
|
||
"no corresponding extension!!\n",
|
||
Irp
|
||
) );
|
||
ASSERT(0) ;
|
||
return ACPIDispatchPowerIrpFailure( DeviceObject, Irp );
|
||
}
|
||
|
||
if (irpSp->Parameters.Power.ShutdownType == PowerActionWarmEject) {
|
||
|
||
//
|
||
// We are going to do some work on the irp, so mark it as being
|
||
// successful for now
|
||
//
|
||
Irp->IoStatus.Status = STATUS_SUCCESS;
|
||
|
||
//
|
||
// Mark the irp as pending
|
||
//
|
||
IoMarkIrpPending( Irp );
|
||
|
||
//
|
||
// We might queue up the irp, so this counts as a completion routine.
|
||
// Which means we need to incr the ref count
|
||
//
|
||
InterlockedIncrement( &dockDeviceExtension->OutstandingIrpCount );
|
||
|
||
ACPIDevPrint( (
|
||
ACPI_PRINT_REMOVE,
|
||
deviceExtension,
|
||
"(0x%08lx) ACPIBusIrpSetSystemPower: Eject from S%d!\n",
|
||
Irp,
|
||
systemState - PowerSystemWorking
|
||
) );
|
||
|
||
//
|
||
// Request the warm eject
|
||
//
|
||
status = ACPIDeviceIrpWarmEjectRequest(
|
||
dockDeviceExtension,
|
||
Irp,
|
||
ACPIDeviceIrpCompleteRequest,
|
||
(BOOLEAN) (deviceExtension->Dock.ProfileDepartureStyle == PDS_UPDATE_ON_EJECT)
|
||
);
|
||
|
||
//
|
||
// If we got back STATUS_MORE_PROCESSING_REQUIRED, then that is
|
||
// just an alias for STATUS_PENDING, so we make that change now
|
||
//
|
||
if (status == STATUS_MORE_PROCESSING_REQUIRED) {
|
||
|
||
status = STATUS_PENDING;
|
||
|
||
}
|
||
|
||
return status;
|
||
}
|
||
|
||
//
|
||
// Look at the device extension and determine if we need to send a
|
||
// D-irp in respond. The rule is that if the device is RAW driven or
|
||
// the current D state of the device is numerically lower then the
|
||
// known D state for the given S state, then we should send the request
|
||
//
|
||
ASSERT(deviceExtension->Flags & DEV_CAP_RAW);
|
||
|
||
if ( (deviceExtension->PowerInfo.PowerState == deviceState) ) {
|
||
|
||
return ACPIDispatchPowerIrpSuccess( DeviceObject, Irp );
|
||
|
||
} // if
|
||
|
||
ACPIDevPrint( (
|
||
ACPI_PRINT_REMOVE,
|
||
deviceExtension,
|
||
"(0x%08lx) ACPIDockIrpSetSystemPower: send D%d irp!\n",
|
||
Irp,
|
||
deviceState - PowerDeviceD0
|
||
) );
|
||
|
||
//
|
||
// We are going to do some work on the irp, so mark it as being
|
||
// successfull for now
|
||
//
|
||
Irp->IoStatus.Status = STATUS_SUCCESS;
|
||
|
||
//
|
||
// Mark the irp as pending
|
||
//
|
||
IoMarkIrpPending( Irp );
|
||
|
||
//
|
||
// We might queue up the irp, so this counts as a completion routine.
|
||
// Which means we need to incr the ref count
|
||
//
|
||
InterlockedIncrement( &deviceExtension->OutstandingIrpCount );
|
||
|
||
//
|
||
// We need to actually use a PowerState to send the request down, not
|
||
// a device state
|
||
//
|
||
powerState.DeviceState = deviceState;
|
||
|
||
//
|
||
// Make the request
|
||
//
|
||
PoRequestPowerIrp(
|
||
DeviceObject,
|
||
IRP_MN_SET_POWER,
|
||
powerState,
|
||
ACPIDockIrpSetSystemPowerComplete,
|
||
Irp,
|
||
NULL
|
||
);
|
||
|
||
//
|
||
// Always return pending
|
||
//
|
||
return STATUS_PENDING;
|
||
}
|
||
|
||
NTSTATUS
|
||
ACPIDockIrpSetSystemPowerComplete(
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN UCHAR MinorFunction,
|
||
IN POWER_STATE PowerState,
|
||
IN PVOID Context,
|
||
IN PIO_STATUS_BLOCK IoStatus
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is called when the created D-irp has been sent throughout
|
||
the stack
|
||
|
||
Arguments:
|
||
|
||
DeviceObject - The device that received the request
|
||
MinorFunction - The function that was requested of the device
|
||
PowerState - The power state the device was sent to
|
||
Context - The original system irp
|
||
IoStatus - The result of the request
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS
|
||
|
||
--*/
|
||
{
|
||
PIRP irp = (PIRP) Context;
|
||
PDEVICE_EXTENSION deviceExtension;
|
||
|
||
//
|
||
// Get the device extension
|
||
//
|
||
deviceExtension = ACPIInternalGetDeviceExtension( DeviceObject );
|
||
|
||
//
|
||
// Make sure that we have cleared the information field
|
||
//
|
||
irp->IoStatus.Information = 0;
|
||
|
||
//
|
||
// Call this wrapper function so that we don't have to duplicated code
|
||
//
|
||
ACPIDeviceIrpCompleteRequest(
|
||
deviceExtension,
|
||
(PVOID) irp,
|
||
IoStatus->Status
|
||
);
|
||
|
||
//
|
||
// Done
|
||
//
|
||
return IoStatus->Status;
|
||
}
|
||
|
||
VOID
|
||
ACPIDockIntfReference(
|
||
IN PVOID Context
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine increments the reference count for the dock interface
|
||
|
||
Arguments:
|
||
|
||
Context - The device object this interface was taken out against
|
||
|
||
Return Value:
|
||
|
||
None
|
||
|
||
--*/
|
||
{
|
||
PDEVICE_OBJECT deviceObject = (PDEVICE_OBJECT) Context;
|
||
PDEVICE_EXTENSION deviceExtension = ACPIInternalGetDeviceExtension(deviceObject);
|
||
|
||
PAGED_CODE();
|
||
|
||
ObReferenceObject(deviceObject);
|
||
InterlockedIncrement(&deviceExtension->ReferenceCount);
|
||
|
||
if (!(deviceExtension->Flags & DEV_TYPE_SURPRISE_REMOVED)) {
|
||
|
||
InterlockedIncrement(&deviceExtension->Dock.InterfaceReferenceCount);
|
||
}
|
||
}
|
||
|
||
VOID
|
||
ACPIDockIntfDereference(
|
||
IN PVOID Context
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine decrements the reference count for the dock interface
|
||
|
||
Arguments:
|
||
|
||
Context - The device object this interface was taken out against
|
||
|
||
Return Value:
|
||
|
||
None
|
||
|
||
--*/
|
||
{
|
||
PDEVICE_OBJECT deviceObject = (PDEVICE_OBJECT) Context;
|
||
PDEVICE_EXTENSION deviceExtension = ACPIInternalGetDeviceExtension(deviceObject);
|
||
ULONG oldReferenceCount;
|
||
|
||
PAGED_CODE();
|
||
|
||
if (!(deviceExtension->Flags & DEV_TYPE_SURPRISE_REMOVED)) {
|
||
|
||
oldReferenceCount = InterlockedDecrement(
|
||
&deviceExtension->Dock.InterfaceReferenceCount
|
||
);
|
||
|
||
if (oldReferenceCount == 0) {
|
||
|
||
//
|
||
// Revert back to the default used in buildsrc.c
|
||
//
|
||
deviceExtension->Dock.ProfileDepartureStyle = PDS_UPDATE_ON_EJECT;
|
||
}
|
||
}
|
||
|
||
oldReferenceCount = InterlockedDecrement(&deviceExtension->ReferenceCount);
|
||
|
||
if (oldReferenceCount == 0) {
|
||
|
||
//
|
||
// Delete the extension
|
||
//
|
||
ACPIInitDeleteDeviceExtension(deviceExtension);
|
||
}
|
||
|
||
ObDereferenceObject(deviceObject);
|
||
}
|
||
|
||
NTSTATUS
|
||
ACPIDockIntfSetMode(
|
||
IN PVOID Context,
|
||
IN PROFILE_DEPARTURE_STYLE Style
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine sets the manner in which profiles will be updated
|
||
|
||
Arguments:
|
||
|
||
Context - The device object this interface was taken out against
|
||
Style - PDS_UPDATE_ON_REMOVE, PDS_UPDATE_ON_EJECT,
|
||
PDS_UPDATE_ON_INTERFACE, or PDS_UPDATE_DEFAULT
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS
|
||
|
||
--*/
|
||
{
|
||
PDEVICE_OBJECT deviceObject = (PDEVICE_OBJECT) Context;
|
||
PDEVICE_EXTENSION deviceExtension = ACPIInternalGetDeviceExtension(deviceObject);
|
||
|
||
PAGED_CODE();
|
||
|
||
if (deviceExtension->Flags & DEV_TYPE_SURPRISE_REMOVED) {
|
||
|
||
return STATUS_NO_SUCH_DEVICE;
|
||
}
|
||
|
||
deviceExtension->Dock.ProfileDepartureStyle =
|
||
(Style == PDS_UPDATE_DEFAULT) ? PDS_UPDATE_ON_EJECT : Style;
|
||
|
||
ASSERT(deviceExtension->Dock.InterfaceReferenceCount);
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
NTSTATUS
|
||
ACPIDockIntfUpdateDeparture(
|
||
IN PVOID Context
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine initiates the hardware profile change portion of an undock
|
||
|
||
Arguments:
|
||
|
||
Context - The device object this interface was taken out against
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS
|
||
|
||
--*/
|
||
{
|
||
PDEVICE_OBJECT deviceObject = (PDEVICE_OBJECT) Context;
|
||
PDEVICE_EXTENSION deviceExtension = ACPIInternalGetDeviceExtension(deviceObject);
|
||
NTSTATUS status;
|
||
ULONG ignoredPerSpec;
|
||
PDEVICE_EXTENSION dockDeviceExtension;
|
||
|
||
PAGED_CODE();
|
||
|
||
if (deviceExtension->Flags & DEV_TYPE_SURPRISE_REMOVED) {
|
||
|
||
return STATUS_NO_SUCH_DEVICE;
|
||
}
|
||
|
||
ASSERT(deviceExtension->Dock.InterfaceReferenceCount);
|
||
ASSERT(deviceExtension->Dock.ProfileDepartureStyle == PDS_UPDATE_ON_INTERFACE);
|
||
|
||
if (deviceExtension->Dock.ProfileDepartureStyle != PDS_UPDATE_ON_INTERFACE) {
|
||
|
||
//
|
||
// Can't do this, we may already have updated our profile!
|
||
//
|
||
return STATUS_INVALID_DEVICE_REQUEST;
|
||
}
|
||
|
||
//
|
||
// lets get the corrosponding dock node for this device
|
||
//
|
||
dockDeviceExtension = deviceExtension->Dock.CorrospondingAcpiDevice ;
|
||
|
||
//
|
||
// On the Compaq Armada 7800, we switch UARTs during an undock, thus we
|
||
// lose the debugger com port programming.
|
||
//
|
||
if (deviceExtension->Dock.IsolationState != IS_ISOLATED) {
|
||
|
||
KdDisableDebugger();
|
||
|
||
status = ACPIGetIntegerEvalIntegerSync(
|
||
dockDeviceExtension,
|
||
PACKED_DCK,
|
||
0,
|
||
&ignoredPerSpec
|
||
);
|
||
|
||
KdEnableDebugger();
|
||
|
||
deviceExtension->Dock.IsolationState = IS_ISOLATED;
|
||
}
|
||
else{
|
||
|
||
status = STATUS_SUCCESS;
|
||
}
|
||
|
||
return status;
|
||
}
|
||
|