IOCTL_ACPI_ENUM_CHILDREN 要求を送信する
ドライバーは通常、2 つの IOCTL_ACPI_ENUM_CHILDREN 要求のシーケンスを使用して、要求が送信されたデバイスの名前空間内の対象オブジェクトを列挙します。 ドライバーは、オブジェクトのパスと名前を格納するために必要なドライバー割り当て出力バッファーのサイズを取得する最初の要求を送信します。 ドライバーは、ドライバーによって割り当てられた出力バッファー内のオブジェクトのパスと名前を返す 2 番目の要求を送信します。
次のコード例は、2 つの同期 IOCTL_ACPI_ENUM_CHILDREN 要求のシーケンスを送信して、要求が送信される親デバイスのすべての子デバイスを再帰的に列挙する方法を示しています。 このコードは、次の一連の操作を実行して、最初の要求を処理します。
最初の要求の入力バッファーを設定します。 入力バッファーは ACPI_ENUM_CHILDREN_INPUT_BUFFER 構造体で Signature は ENUM_CHILDREN_INPUT_BUFFER_SIGNATURE に設定され、Flags は ENUM_CHILDREN_MULTILEVEL に設定されています。
最初の要求の出力バッファーを設定します。 出力バッファーは、ACPI_ENUM_CHILDREN_OUTPUT_BUFFER 構造体に設定されています。 この出力バッファーには ACPI_ENUM_CHILD 構造体が 1 つだけ含まれており、デバイス名を返すには十分なサイズではありません。
呼び出し元が指定した SendDownStreamIrp 関数 を呼び出して、最初の要求を親デバイスに同期的に送信します。
ACPI ドライバーが戻り値の状態を STATUS_BUFFER_OVERFLOW に設定するかどうかを確認します。 別の状態が返された場合は、エラーが発生し、コードが終了したことを示します。
ACPI ドライバーが Signature メンバーを ACPI_ENUM_CHILDREN_OUTPUT_BUFFER_SIGNATURE に設定し、NumberOfChildren を sizeof(ACPI_ENUM_CHILDREN_OUTPUT_BUFFER) 以上の値に設定しているか確認します。 両方が true の場合、NumberOfChildren の値は、要求された子オブジェクト名を格納するために必要な出力バッファーのサイズ (バイト単位) です。
コード例は、出力バッファーの必要なサイズを取得した後、次の一連の操作を実行して 2 番目の要求を処理します。これによって、要求された子オブジェクトのパスと名前を返します。
必要なサイズの出力バッファーをバイト単位で割り当てます。
ドライバーが指定した SendDownStreamIrp 関数を呼び出して、2 番目の要求を親デバイスに同期的に送信します。
ACPI ドライバーが Signature メンバーを ACPI_ENUM_CHILDREN_OUTPUT_BUFFER_SIGNATURE に設定し、NumberOfChildren を 1 つ以上に設定して (少なくとも 1 つのオブジェクトのパスと名前が返されたことを示す)、IO_STATUS_BLOCK の Information メンバーを出力バッファーの割り当てサイズに設定することを確認します。
出力バッファー内の子オブジェクト名の配列を処理します。
#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.
}