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

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,欧耶!

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 8
    评论
笔记本的风扇控制 ---------------------------------------- 09 November 2006. Summary of changes for version 20061109: 1) ACPI CA Core Subsystem: Optimized the Load ASL operator in the case where the source operand is an operation region. Simply map the operation region memory, instead of performing a bytewise read. (Region must be of type SystemMemory, see below.) Fixed the Load ASL operator for the case where the source operand is a region field. A buffer object is also allowed as the source operand. BZ 480 Fixed a problem where the Load ASL operator allowed the source operand to be an operation region of any type. It is now restricted to regions of type SystemMemory, as per the ACPI specification. BZ 481 Additional cleanup and optimizations for the new Table Manager code. AcpiEnable will now fail if all of the required ACPI tables are not loaded (FADT, FACS, DSDT). BZ 477 Added #pragma pack(8/4) to acobject.h to ensure that the structures in this header are always compiled as aligned. The ACPI_OPERAND_OBJECT has been manually optimized to be aligned and will not work if it is byte-packed. Example Code and Data Size: These are the sizes for the OS- independent acpica.lib produced by the Microsoft Visual C++ 6.0 32- bit compiler. The debug version of the code includes the debug output trace mechanism and has a much larger code and data size. Previous Release: Non-Debug Version: 78.1K Code, 17.1K Data, 95.2K Total Debug Version: 155.4K Code, 63.1K Data, 218.5K Total Current Release: Non-Debug Version: 77.9K Code, 17.0K Data, 94.9K Total Debug Version: 155.2K Code, 63.1K Data, 218.3K Total 2) iASL Compiler/Disassembler and Tools: Fixed a problem where the presence of the _OSI predefined control method within complex expressions could cause an internal compiler error. AcpiExec: Implemented full region support for multiple address spaces. SpaceId is now part of the REGION object. BZ 429 ---------------------------------------- 11 Oc
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Leen

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值