265 lines
5.9 KiB
C
265 lines
5.9 KiB
C
/*++
|
||
|
||
Copyright (c) 1996 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
acpintfy.c
|
||
|
||
Abstract:
|
||
|
||
This modules contains code to deal with notifying interested parties
|
||
of events
|
||
|
||
Author:
|
||
|
||
Jason Clark
|
||
Ken Reneris
|
||
|
||
Environment:
|
||
|
||
NT Kernel Model Driver only
|
||
Some changes are required to work in win9x model
|
||
|
||
--*/
|
||
#include "pch.h"
|
||
|
||
//
|
||
// For handler installation
|
||
//
|
||
KSPIN_LOCK NotifyHandlerLock;
|
||
|
||
NTSTATUS
|
||
ACPIRegisterForDeviceNotifications (
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PDEVICE_NOTIFY_CALLBACK DeviceNotify,
|
||
IN PVOID Context
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Registers the DeviceNotify function as the function to receive device notify
|
||
callbacks
|
||
|
||
Arguments:
|
||
|
||
DeviceObject - The device object to register a notification handler for
|
||
DeviceNotify - The handle for device specific notifications
|
||
|
||
Return Value
|
||
|
||
Returns status
|
||
|
||
--*/
|
||
{
|
||
PACPI_POWER_INFO node;
|
||
PVOID previous;
|
||
KIRQL oldIrql;
|
||
NTSTATUS status;
|
||
|
||
|
||
//
|
||
// Find the Node associated with this device object (or DevNode)
|
||
// Note: that for NT, the context field is the DeviceExtension of the
|
||
// DeviceObject, since this is what is stored within the ACPI Name Space
|
||
// object
|
||
//
|
||
node = OSPowerFindPowerInfoByContext( DeviceObject );
|
||
if (node == NULL) {
|
||
|
||
return STATUS_NO_SUCH_DEVICE;
|
||
|
||
}
|
||
|
||
//
|
||
// Apply the handler
|
||
//
|
||
KeAcquireSpinLock (&NotifyHandlerLock, &oldIrql);
|
||
|
||
if (node->DeviceNotifyHandler != NULL) {
|
||
|
||
//
|
||
// A handler already present
|
||
//
|
||
status = STATUS_UNSUCCESSFUL;
|
||
|
||
} else {
|
||
|
||
node->DeviceNotifyHandler = DeviceNotify;
|
||
node->HandlerContext = Context;
|
||
status = STATUS_SUCCESS;
|
||
|
||
}
|
||
|
||
KeReleaseSpinLock (&NotifyHandlerLock, oldIrql);
|
||
|
||
return status;
|
||
}
|
||
|
||
|
||
VOID
|
||
ACPIUnregisterForDeviceNotifications (
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PDEVICE_NOTIFY_CALLBACK DeviceNotify
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Disconnects a handler from device notify event.
|
||
|
||
Arguments:
|
||
|
||
DeviceObject - The device object to register a notification handler for
|
||
|
||
DeviceNotify - The handle for device specific notifications
|
||
|
||
Return Value
|
||
|
||
None
|
||
|
||
--*/
|
||
{
|
||
PACPI_POWER_INFO node;
|
||
PVOID previous;
|
||
KIRQL oldIrql;
|
||
NTSTATUS status;
|
||
|
||
|
||
//
|
||
// Find the Node associated with this device object (or DevNode)
|
||
// Note: that for NT, the context field is the DeviceExtension of the
|
||
// DeviceObject, since this is what is stored within the ACPI Name Space
|
||
// object
|
||
//
|
||
node = OSPowerFindPowerInfoByContext( DeviceObject );
|
||
if (node == NULL) {
|
||
ASSERTMSG("ACPIUnregisterForDeviceNotifications failed. "\
|
||
"Can't find ACPI_POWER_INFO for DeviceObject", FALSE);
|
||
return;
|
||
}
|
||
|
||
//
|
||
// Attempt to remove the handler/context from the node
|
||
//
|
||
KeAcquireSpinLock (&NotifyHandlerLock, &oldIrql);
|
||
|
||
if (node->DeviceNotifyHandler != DeviceNotify) {
|
||
|
||
//
|
||
// Handler does not match
|
||
//
|
||
ASSERTMSG("ACPIUnregisterForDeviceNotifications failed. "\
|
||
"Handler doesn't match.", FALSE);
|
||
|
||
} else {
|
||
|
||
node->DeviceNotifyHandler = NULL;
|
||
node->HandlerContext = NULL;
|
||
|
||
}
|
||
|
||
KeReleaseSpinLock (&NotifyHandlerLock, oldIrql);
|
||
|
||
return;
|
||
}
|
||
|
||
|
||
NTSTATUS EXPORT
|
||
NotifyHandler (
|
||
ULONG dwEventType,
|
||
ULONG dwEventData,
|
||
PNSOBJ pnsObj,
|
||
ULONG dwParam,
|
||
PFNAA CompletionCallback,
|
||
PVOID CallbackContext
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
The master ACPI notify handler.
|
||
|
||
The design philosophy here is that ACPI should process all notify requests
|
||
that *ONLY* it can handle, namely, DeviceCheck, DeviceEject, and DeviceWake,
|
||
and let *all* other notifies get handled by the driver associated with the
|
||
object. The other driver will also get told about the ACPI handled events,
|
||
but that is only as an FYI, the driver shouldn't do anything...
|
||
|
||
Arguments:
|
||
|
||
dwEventType - The type of event that occured (this is EVTYPE_NOTIFY)
|
||
dwEventData - The event code
|
||
pnsObj - The name space object that was notified
|
||
dwParam - The event code
|
||
|
||
Return Value
|
||
|
||
NTSTATUS
|
||
|
||
--*/
|
||
{
|
||
PACPI_POWER_INFO node;
|
||
KIRQL oldIrql;
|
||
PDEVICE_NOTIFY_CALLBACK notifyHandler;
|
||
PVOID notifyHandlerContext;
|
||
|
||
ASSERT (dwEventType == EVTYPE_NOTIFY);
|
||
|
||
ACPIPrint( (
|
||
ACPI_PRINT_DPC,
|
||
"ACPINotifyHandler: Notify on %x value %x, object type %x\n",
|
||
pnsObj,
|
||
dwEventData,
|
||
NSGETOBJTYPE(pnsObj)
|
||
) );
|
||
|
||
//
|
||
// Any events which must be handled by ACPI and is common to all device
|
||
// object types is handled here
|
||
//
|
||
switch (dwEventData) {
|
||
case OPEVENT_DEVICE_ENUM:
|
||
OSNotifyDeviceEnum( pnsObj );
|
||
break;
|
||
case OPEVENT_DEVICE_CHECK:
|
||
OSNotifyDeviceCheck( pnsObj );
|
||
break;
|
||
case OPEVENT_DEVICE_WAKE:
|
||
OSNotifyDeviceWake( pnsObj );
|
||
break;
|
||
case OPEVENT_DEVICE_EJECT:
|
||
OSNotifyDeviceEject( pnsObj );
|
||
break;
|
||
}
|
||
|
||
//
|
||
// Look for handle for this node and dispatch it
|
||
//
|
||
node = OSPowerFindPowerInfo(pnsObj);
|
||
if (node) {
|
||
|
||
//
|
||
// Get handler address/context with mutex
|
||
//
|
||
KeAcquireSpinLock (&NotifyHandlerLock, &oldIrql);
|
||
|
||
notifyHandler = node->DeviceNotifyHandler;
|
||
notifyHandlerContext = node->HandlerContext;
|
||
|
||
KeReleaseSpinLock (&NotifyHandlerLock, oldIrql);
|
||
|
||
//
|
||
// If we got something, dispatch it
|
||
//
|
||
if (notifyHandler) {
|
||
|
||
notifyHandler (notifyHandlerContext, dwEventData);
|
||
|
||
}
|
||
|
||
}
|
||
return (STATUS_SUCCESS);
|
||
}
|