You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2066 lines
52 KiB
2066 lines
52 KiB
/*++
|
|
|
|
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;
|
|
}
|
|
|