傳送IOCTL_ACPI_ENUM_CHILDREN要求
驅動程式通常會使用兩個 IOCTL_ACPI_ENUM_CHILDREN 要求序列來列舉要求傳送至該要求之裝置命名空間中感興趣的物件。 驅動程式會傳送第一個要求,以取得包含物件路徑和名稱所需的驅動程式配置輸出緩衝區大小。 驅動程式會傳送第二個要求,以傳回驅動程式配置輸出緩衝區中物件的路徑和名稱。
下列程式碼範例示範如何傳送兩個同步IOCTL_ACPI_ENUM_CHILDREN要求序列,以遞迴方式列舉傳送要求之父裝置的所有子裝置。 程式碼會執行下列作業順序來處理第一個要求:
設定第一個要求的輸入緩衝區。 輸入緩衝區是 ACPI_ENUM_CHILDREN_INPUT_BUFFER 結構, 簽章 設定為 ENUM_CHILDREN_INPUT_BUFFER_SIGNATURE, 而 Flags 設定為 ENUM_CHILDREN_MULTILEVEL。
設定第一個要求的輸出緩衝區。 輸出緩衝區會設定為 ACPI_ENUM_CHILDREN_OUTPUT_BUFFER 結構。 此輸出緩衝區只包含一個 ACPI_ENUM_CHILD 結構,這個結構不夠大,無法傳回裝置的名稱。
呼叫呼叫端提供的 SendDownStreamIrp 函式 ,以同步方式將第一個要求傳送至父裝置。
檢查 ACPI 驅動程式是否將傳回狀態設定為 STATUS_BUFFER_OVERFLOW。 如果傳回另一個狀態,這表示發生錯誤,而且程式碼會終止。
檢查 ACPI 驅動程式是否將 Signature 成員設定為 ACPI_ENUM_CHILDREN_OUTPUT_BUFFER_SIGNATURE,並將 NumberOfChildren 設定為大於或等於 sizeof (ACPI_ENUM_CHILDREN_OUTPUT_BUFFER) 的值。 如果兩者都是 true, NumberOfChildren 的值是包含所要求子物件名稱所需的輸出緩衝區大小,以位元組為單位。
在範例程式碼取得所需的輸出緩衝區大小之後,它會執行下列作業順序來處理第二個要求,以傳回所要求子物件的路徑和名稱:
以位元組為單位,配置所需大小的輸出緩衝區。
呼叫驅動程式提供的 SendDownStreamIrp 函式,以同步方式將第二個要求傳送至父裝置。
檢查 ACPI 驅動程式是否將Signature成員設定為 ACPI_ENUM_CHILDREN_OUTPUT_BUFFER_SIGNATURE、將NumberOfChildren設定為一或多個 (指出至少傳回一個物件的路徑和名稱) ,並將IO_STATUS_BLOCK的資訊成員設定為輸出緩衝區配置的大小。
處理輸出緩衝區中子物件名稱的陣列。
#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.
}