Enviando uma solicitação de IOCTL_ACPI_ENUM_CHILDREN
Um driver normalmente usa uma sequência de duas solicitações IOCTL_ACPI_ENUM_CHILDREN para enumerar os objetos de interesse no namespace do dispositivo para o qual a solicitação é enviada. O driver envia a primeira solicitação para obter o tamanho de um buffer de saída alocado pelo driver necessário para conter o caminho e o nome dos objetos. O driver envia a segunda solicitação para retornar o caminho e o nome dos objetos em um buffer de saída alocado pelo driver.
O exemplo de código a seguir mostra como enviar uma sequência de duas solicitações de IOCTL_ACPI_ENUM_CHILDREN síncronas para enumerar recursivamente todos os dispositivos filho do dispositivo pai para os quais as solicitações são enviadas. O código executa a seguinte sequência de operações para lidar com a primeira solicitação:
Define o buffer de entrada para a primeira solicitação. O buffer de entrada é uma estrutura ACPI_ENUM_CHILDREN_INPUT_BUFFER com Assinatura definida como ENUM_CHILDREN_INPUT_BUFFER_SIGNATURE e Sinalizadores definidos como ENUM_CHILDREN_MULTILEVEL.
Define o buffer de saída para a primeira solicitação. O buffer de saída é definido como uma estrutura de ACPI_ENUM_CHILDREN_OUTPUT_BUFFER . Esse buffer de saída contém apenas uma estrutura ACPI_ENUM_CHILD que não é grande o suficiente para retornar um nome de um dispositivo.
Chama uma função SendDownStreamIrp fornecida pelo chamador para enviar a primeira solicitação de forma síncrona para o dispositivo pai.
Verifica se o driver ACPI definiu a status de retorno como STATUS_BUFFER_OVERFLOW. Se outra status foi retornada, isso indica que ocorreu um erro e o código é encerrado.
Verifica se o driver ACPI definiu o membro Signature como ACPI_ENUM_CHILDREN_OUTPUT_BUFFER_SIGNATURE e define NumberOfChildren como um valor maior ou igual ao sizeof(ACPI_ENUM_CHILDREN_OUTPUT_BUFFER). Se ambos forem verdadeiros, o valor de NumberOfChildren será o tamanho, em bytes, do buffer de saída necessário para conter os nomes de objeto filho solicitados.
Depois que o código de exemplo obtém o tamanho necessário do buffer de saída, ele executa a seguinte sequência de operações para lidar com a segunda solicitação, que retorna o caminho e o nome dos objetos filho solicitados:
Aloca um buffer de saída do tamanho necessário, em bytes.
Chama a função SendDownStreamIrp fornecida pelo driver para enviar a segunda solicitação de forma síncrona para o dispositivo pai.
Verifica se o driver ACPI definiu o membro Signature como ACPI_ENUM_CHILDREN_OUTPUT_BUFFER_SIGNATURE, define NumberOfChildren como um ou mais (indicando que o caminho e o nome de pelo menos um objeto foram retornados) e define o membro Information do IO_STATUS_BLOCK para o tamanho alocado do buffer de saída.
Processa a matriz de nomes de objeto filho no buffer de saída.
#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.
}