Отправка запроса IOCTL_ACPI_ENUM_CHILDREN
Драйвер обычно использует последовательность из двух запросов IOCTL_ACPI_ENUM_CHILDREN для перечисления объектов, представляющих интерес, в пространстве имен устройства, на которое отправляется запрос. Драйвер отправляет первый запрос на получение размера выделенного драйвером выходного буфера, необходимого для хранения пути и имени объектов. Драйвер отправляет второй запрос на возврат пути и имени объектов в выделенном драйвером выходном буфере.
В следующем примере кода показано, как отправить последовательность из двух синхронных запросов IOCTL_ACPI_ENUM_CHILDREN для рекурсивного перечисления всех дочерних устройств родительского устройства, на которое отправляются запросы. Код выполняет следующую последовательность операций для обработки первого запроса:
Задает входной буфер для первого запроса. Входной буфер представляет собой структуру ACPI_ENUM_CHILDREN_INPUT_BUFFER с параметром "Подпись " в ENUM_CHILDREN_INPUT_BUFFER_SIGNATURE, а для флагов — значение 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 значение одного или нескольких (указывает, что возвращен путь и имя хотя бы одного объекта), а также задает для элемента InformationIO_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.
}