您的位置:首页 > 其它

how to Register for Notification in ACPI | 如何注册一个ACPI 通知

2016-07-13 19:23 661 查看
A kernel-mode driver can handle events from a device by registering for notifications with the ACPI driver.
This is done by registering a callback routine with the ACPI driver.
This callback routine is invoked when an AMLNotify operation is called by the device.
所以,我们注册了 ACPI 通知,就能够收到 AML(ACPI Machine Language)调用的Notify 时触发的通知。

那如何注册呢?

微软的ACPI Driver Interface inWindows Vista有提到:

A driver can register a callback routine for device notifications by calling theRegisterForDeviceNotifications
routine,
which passes a pointer to the driver’s context and a pointer to the driver’scallback routine. After that, every time AML code executes aNotifyoperation
that has a notification code 0x80 or above, the registered callbackroutine is called. The callback routine acts as an event handler for thespecified events.
To register for device notifications:
1.   Sendan IRP_MN_QUERY_INTERFACErequest to the ACPI driver to get the currently loaded ACPI driver’s directinterfaces.
2.   CallAcpiInterfaces.RegisterForDeviceNotifications, passingin a pointer to the device
context returned in step 1 and a pointer to thecallback routine.

Example Code

The following block of sample codeoutlines how to obtain a reference to the direct call routines. It sends an IRP_MN_QUERY_INTERFACE request to theACPI driver to get the currently-loaded
ACPI driver’s direct interfaces:
NTSTATUS
GetAcpiInterfaces(
IN PDEVICE_OBJECT Pdo,
OUT PACPI_INTERFACE_STANDARD2 AcpiInterfaces
)
/*
Routine Description:
Call ACPI driver to get the direct-call interfaces. It does
this the first time it is called, no more.
Arguments:
None.
Return Value:
Status
*/
{
NTSTATUS Status = STATUS_SUCCESS;
PIRP Irp;
PIO_STACK_LOCATION IrpSp;

// Only need to do this once
if (!LowerPdo) {
LowerPdo = IoGetAttachedDeviceReference (Pdo);

// Allocate an IRP for below Irp = IoAllocateIrp
// (LowerPdo->StackSize, FALSE); // Get stack size from
// PDO
.
.
.
IrpSp = IoGetNextIrpStackLocation(Irp);
//
// Use QUERY_INTERFACE to get the address of the direct-
// call ACPI interfaces.
//
IrpSp->MajorFunction = IRP_MJ_PNP;
IrpSp->MinorFunction = IRP_MN_QUERY_INTERFACE;
IrpSp->Parameters.QueryInterface.InterfaceType=(LPGUID)
&GUID_ACPI_INTERFACE_STANDARD2;
IrpSp->Parameters.QueryInterface.Version = 1;
IrpSp->Parameters.QueryInterface.Size = sizeof (AcpiInterfaces);
IrpSp->Parameters.QueryInterface.Interface = (PINTERFACE) &AcpiInterfaces;
IrpSp->Parameters.QueryInterface.InterfaceSpecificData = NULL;
IoSetCompletionRoutine(Irp,AbcdDriverSynchronousRequest,NULL,FALSE, FALSE);
Status = IoCallDriver (LowerPdo, Irp);
IoFreeIrp (Irp);
}
return Status;
}



于是写了如下代码:

PS 加载ACPI类型的驱动中,由于在一个device stack中,这样直接把IRP发给下层设备就行了,

NTSTATUS
XxxAddDevice(
__in struct _DRIVER_OBJECT *DriverObject,
__in struct _DEVICE_OBJECT *PhysicalDeviceObject
)
{
.
.
.

status = STATUS_SUCCESS;

DebugPrint(("AddDevice: %p to %p->%p \n",fdo,fdoData->NextLowerDO,PhysicalDeviceObject));
DebugPrint(("DeviceObject Flag = 0x%08x\n",fdo->Flags));
DebugPrint(("DevicePnPState = %d\n", fdoData->DevicePnPState));
{
//PACPI_INTERFACE_STANDARD2 pInterface =
//  ExAllocatePool(PagedPool, sizeof(ACPI_INTERFACE_STANDARD2));
ACPI_INTERFACE_STANDARD Interfaces = {0};
if (&Interfaces == NULL)
{
goto FuncEnd;
}
//RtlFillMemory(pInterface, sizeof(ACPI_INTERFACE_STANDARD2), 0x00);
status = GetAcpiInterfaces(fdo, &Interfaces);
if (!NT_SUCCESS(status))
{
DebugPrint(("GetAcpiInterfaces Failed\n"));
}
else
{
DebugPrint(("******GetAcpiInterfaces Succeed\n"));
DebugPrint(("******ACPI_INTERFACE_STANDARD2 Version == %d\n", Interfaces.Version));
DebugPrint(("******AcpiInterface.RegisterForDeviceNotifications Address == %x\n",
Interfaces.RegisterForDeviceNotifications));
//Interfaces.InterfaceReference(Interfaces.Context);
}

if (Interfaces.RegisterForDeviceNotifications != NULL)
{
status = Interfaces.RegisterForDeviceNotifications(
Interfaces.Context,
ACPIDeviceNotifyHandler,
fdoData);
if (!NT_SUCCESS(status))
{
DebugPrint(("RegisterForDeviceNotifications Failed\n"));
}
else
{
DebugPrint(("RegisterForDeviceNotifications Succeed\n"));
}
}
//Free Memory
//ExFreePool(pInterface);

//      PDEVICE_OBJECT target = fdoData->NextLowerDO;
//      RegisterACPINotifyEvent(target, fdoData);
status = STATUS_SUCCESS;
}

FuncEnd:

return status;
}

NTSTATUS
GetAcpiInterfaces(
IN PDEVICE_OBJECT   Pdo,
OUT PACPI_INTERFACE_STANDARD AcpiInterfaces
)
{
NTSTATUS                Status = STATUS_NOT_SUPPORTED;
PIRP                    Irp;
PIO_STACK_LOCATION      IrpSp;
PDEVICE_OBJECT          LowerPdo = NULL;

KEVENT event;
DebugPrint(("Enter GetAcpiInterfaces...\n"));
KeInitializeEvent(&event, NotificationEvent, FALSE);
// Only need to do this once
if (!LowerPdo)
{
LowerPdo = IoGetAttachedDeviceReference(Pdo);

// Allocate an IRP for below Irp = IoAllocateIrp
// (LowerPdo->StackSize, FALSE);    // Get stack size from
// PDO
Irp = IoAllocateIrp(LowerPdo->StackSize, FALSE);
if (Irp == NULL)
{
DebugPrint(("IoAllocateIrp Failed...\n"));
Status = STATUS_UNSUCCESSFUL;
return Status;
}
IrpSp = IoGetNextIrpStackLocation(Irp);
//
// Use QUERY_INTERFACE to get the address of the direct-
// call ACPI interfaces.
//
IrpSp->MajorFunction = IRP_MJ_PNP;
IrpSp->MinorFunction = IRP_MN_QUERY_INTERFACE;
IrpSp->Parameters.QueryInterface.InterfaceType = (LPGUID)&GUID_ACPI_INTERFACE_STANDARD;
IrpSp->Parameters.QueryInterface.Version = 1;
IrpSp->Parameters.QueryInterface.Size = sizeof(ACPI_INTERFACE_STANDARD);
IrpSp->Parameters.QueryInterface.Interface = (PINTERFACE)AcpiInterfaces;
IrpSp->Parameters.QueryInterface.InterfaceSpecificData = NULL;
IoSetCompletionRoutine(Irp, ACPIDriverSynchronousRequest, &event, TRUE, TRUE, TRUE);
DebugPrint(("******Before IoCallDriver.Status == %08X\n", Status));
Status = IoCallDriver(LowerPdo, Irp);
DebugPrint(("******IoCallDriver.Status == %08X\n",Status));
//Wait for complete
if (Status == STATUS_PENDING)
{
DebugPrint(("KeWaitForSingleObject QueryInterface...\n"));
Status = KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
DebugPrint(("KeWaitForSingleObject.Status == %08X\n", Status));
DebugPrint(("pNewIrp->IoStatus.Status == %08X\n", Irp->IoStatus.Status));
}

//IoFreeIrp(Irp);
}
return Status;
}


但是AcpiInterfaces.RegisterForDeviceNotifications返回的是空,一调用就会BSOD。。心中玩吗奔腾。。。。。。。。。
什么鬼,微软在骗人?
找个各方资料都不能解决。。

最后发现是我安装驱动的方式不对。。
手动在设备管理器中安装驱动后查看device stack,驱动安装在\Driver\PnpManager上
使用Dpinst.exe /f 去安装就能安装在 \Driver\ACPI 上面。

然后就看到了胜利的log,欧耶!

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: