共用方式為


傳送IOCTL_ACPI_ENUM_CHILDREN要求

驅動程式通常會使用兩個 IOCTL_ACPI_ENUM_CHILDREN 要求序列來列舉要求傳送至該要求之裝置命名空間中感興趣的物件。 驅動程式會傳送第一個要求,以取得包含物件路徑和名稱所需的驅動程式配置輸出緩衝區大小。 驅動程式會傳送第二個要求,以傳回驅動程式配置輸出緩衝區中物件的路徑和名稱。

下列程式碼範例示範如何傳送兩個同步IOCTL_ACPI_ENUM_CHILDREN要求序列,以遞迴方式列舉傳送要求之父裝置的所有子裝置。 程式碼會執行下列作業順序來處理第一個要求:

  1. 設定第一個要求的輸入緩衝區。 輸入緩衝區是 ACPI_ENUM_CHILDREN_INPUT_BUFFER 結構, 簽章 設定為 ENUM_CHILDREN_INPUT_BUFFER_SIGNATURE, 而 Flags 設定為 ENUM_CHILDREN_MULTILEVEL。

  2. 設定第一個要求的輸出緩衝區。 輸出緩衝區會設定為 ACPI_ENUM_CHILDREN_OUTPUT_BUFFER 結構。 此輸出緩衝區只包含一個 ACPI_ENUM_CHILD 結構,這個結構不夠大,無法傳回裝置的名稱。

  3. 呼叫呼叫端提供的 SendDownStreamIrp 函式 ,以同步方式將第一個要求傳送至父裝置。

  4. 檢查 ACPI 驅動程式是否將傳回狀態設定為 STATUS_BUFFER_OVERFLOW。 如果傳回另一個狀態,這表示發生錯誤,而且程式碼會終止。

  5. 檢查 ACPI 驅動程式是否將 Signature 成員設定為 ACPI_ENUM_CHILDREN_OUTPUT_BUFFER_SIGNATURE,並將 NumberOfChildren 設定為大於或等於 sizeof (ACPI_ENUM_CHILDREN_OUTPUT_BUFFER) 的值。 如果兩者都是 true, NumberOfChildren 的值是包含所要求子物件名稱所需的輸出緩衝區大小,以位元組為單位。

在範例程式碼取得所需的輸出緩衝區大小之後,它會執行下列作業順序來處理第二個要求,以傳回所要求子物件的路徑和名稱:

  1. 以位元組為單位,配置所需大小的輸出緩衝區。

  2. 呼叫驅動程式提供的 SendDownStreamIrp 函式,以同步方式將第二個要求傳送至父裝置。

  3. 檢查 ACPI 驅動程式是否將Signature成員設定為 ACPI_ENUM_CHILDREN_OUTPUT_BUFFER_SIGNATURE、將NumberOfChildren設定為一或多個 (指出至少傳回一個物件的路徑和名稱) ,並將IO_STATUS_BLOCK的資訊成員設定為輸出緩衝區配置的大小。

  4. 處理輸出緩衝區中子物件名稱的陣列。

#define MY_TAG 'gTyM'   // Pool tag for memory allocation

 ACPI_ENUM_CHILDREN_INPUT_BUFFER  inputBuffer;
    ACPI_ENUM_CHILDREN_OUTPUT_BUFFER outputSizeBuffer = { 0 };
    ACPI_ENUM_CHILDREN_OUTPUT_BUFFER outputBuffer = { 0 };
    ULONG                            bufferSize;
 PACPI_ENUM_CHILD                 childObject = NULL;
 ULONG                            index;

    NTSTATUS                         status;

    ASSERT( ReturnStatus != NULL );
    *ReturnStatus = 0x0;

    // Fill in the input data
    inputBuffer.Signature = ACPI_ENUM_CHILDREN_INPUT_BUFFER_SIGNATURE;
    inputBuffer.Flags = ENUM_CHILDREN_MULTILEVEL;

    // Send the request along
    status = SendDownStreamIrp(
       Pdo,
 IOCTL_ACPI_ENUM_CHILDREN,
       &inputBuffer,
       sizeof(inputBuffer),
       &outputSizeBuffer,
       sizeof(outputSizeBuffer)
       );

 if (Status != STATUS_BUFFER_OVERFLOW) {
        // There should be at least one child device (that is the device itself)
        // Return error return status
    }

    // Verify the data
    // NOTE: The NumberOfChildren returned by ACPI actually contains the required size
 // when the status returned is STATUS_BUFFER_OVERFLOW 

    if ((outputSizeBuffer.Signature != ACPI_ENUM_CHILDREN_OUTPUT_BUFFER_SIGNATURE) ||
       (outputSizeBuffer.NumberOfChildren < sizeof(ACPI_ENUM_CHILDREN_OUTPUT_BUFFER)))
    {
        return STATUS_ACPI_INVALID_DATA;
    }

    //
    // Allocate a buffer to hold all the child devices
    //
    bufferSize = outputSizeBuffer.NumberOfChildren;
    outputBuffer = (PACPI_ENUM_CHILDREN_OUTPUT_BUFFER)
 ExAllocatePoolWithTag(PagedPool, bufferSize, MY_TAG);

    if (outputBuffer == NULL){
        return STATUS_INSUFFICIENT_RESOURCES;
    }

    RtlZeroMemory(outputBuffer, bufferSize);

    // Allocate a new IRP with the new output buffer
    // Send another request together with the new output buffer
    status = SendDownStreamIrp(
       Pdo,
 IOCTL_ACPI_ENUM_CHILDREN,
       &inputBuffer,
       sizeof(inputBuffer),
       &outputBuffer,
       bufferSize
       );

    // Verify the data
    if ((outputBuffer->Signature != ACPI_ENUM_CHILDREN_OUTPUT_BUFFER_SIGNATURE) ||
        (outputBuffer->NumberOfChildren == 0) ||
        (IoStatusBlock.Information != bufferSize)) {
        return STATUS_ACPI_INVALID_DATA;
    }

    // Skip the first child device because ACPI returns the device itself 
 // as the first child device
    childObject = &(outputBuffer->Children[0]);

    for (index = 1; index < outputBuffer->NumberOfChildren; ++index) {

        // Proceed to the next ACPI child device. 
        childObject = ACPI_ENUM_CHILD_NEXT(childObject);

        //  Process each child device.
 
 
 
    }