IOCTL_ACPI_ENUM_CHILDREN 요청 보내기
드라이버는 일반적으로 두 개의 IOCTL_ACPI_ENUM_CHILDREN 요청 시퀀스를 사용하여 요청이 전송되는 디바이스의 네임스페이스에 관심 있는 개체를 열거합니다. 드라이버는 첫 번째 요청을 전송하여 개체의 경로와 이름을 포함하는 데 필요한 드라이버 할당 출력 버퍼의 크기를 가져옵니다. 드라이버는 드라이버 할당 출력 버퍼에 있는 개체의 경로와 이름을 반환하는 두 번째 요청을 보냅니다.
다음 코드 예제에서는 두 개의 동기 IOCTL_ACPI_ENUM_CHILDREN 요청 시퀀스를 전송하여 요청이 전송되는 부모 디바이스의 모든 자식 디바이스를 재귀적으로 열거하는 방법을 보여 줍니다. 코드는 첫 번째 요청을 처리하기 위해 다음 작업 시퀀스를 수행합니다.
첫 번째 요청에 대한 입력 버퍼를 설정합니다. 입력 버퍼는 서명이 ENUM_CHILDREN_INPUT_BUFFER_SIGNATURE 설정되고 플래그가 ENUM_CHILDREN_MULTILEVEL 설정된 ACPI_ENUM_CHILDREN_INPUT_BUFFER 구조체입니다.
첫 번째 요청에 대한 출력 버퍼를 설정합니다. 출력 버퍼는 ACPI_ENUM_CHILDREN_OUTPUT_BUFFER 구조체로 설정됩니다. 이 출력 버퍼에는 디바이스 이름을 반환할 만큼 크지 않은 하나의 ACPI_ENUM_CHILD 구조만 포함됩니다.
호출자가 제공한 SendDownStreamIrp 함수 를 호출하여 첫 번째 요청을 부모 디바이스에 동기적으로 보냅니다.
ACPI 드라이버가 반환 상태 STATUS_BUFFER_OVERFLOW 설정했는지 확인합니다. 다른 상태 반환된 경우 오류가 발생하고 코드가 종료됨을 나타냅니다.
ACPI 드라이버가 서명 멤버를 ACPI_ENUM_CHILDREN_OUTPUT_BUFFER_SIGNATURE 설정하고 NumberOfChildren 를 sizeof(ACPI_ENUM_CHILDREN_OUTPUT_BUFFER)보다 크거나 같은 값으로 설정하는지 확인합니다. 둘 다 true이면 NumberOfChildren 값은 요청된 자식 개체 이름을 포함하는 데 필요한 출력 버퍼의 크기(바이트)입니다.
예제 코드는 출력 버퍼의 필요한 크기를 가져온 후 요청된 자식 개체의 경로와 이름을 반환하는 두 번째 요청을 처리하기 위해 다음 작업 시퀀스를 수행합니다.
필요한 크기의 출력 버퍼(바이트)를 할당합니다.
드라이버 제공 SendDownStreamIrp 함수를 호출하여 두 번째 요청을 부모 디바이스에 동기적으로 보냅니다.
ACPI 드라이버가 서명 멤버를 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.
}