Compartilhar via


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:

  1. 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.

  2. 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.

  3. Chama uma função SendDownStreamIrp fornecida pelo chamador para enviar a primeira solicitação de forma síncrona para o dispositivo pai.

  4. 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.

  5. 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:

  1. Aloca um buffer de saída do tamanho necessário, em bytes.

  2. Chama a função SendDownStreamIrp fornecida pelo driver para enviar a segunda solicitação de forma síncrona para o dispositivo pai.

  3. 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.

  4. 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.
 
 
 
    }