Compartir a través de


Envío de una solicitud de IOCTL_ACPI_ENUM_CHILDREN

Normalmente, un controlador usa una secuencia de dos solicitudes de IOCTL_ACPI_ENUM_CHILDREN para enumerar los objetos de interés en el espacio de nombres del dispositivo al que se envía la solicitud. El controlador envía la primera solicitud para obtener el tamaño de un búfer de salida asignado por el controlador necesario para contener la ruta de acceso y el nombre de los objetos. El controlador envía la segunda solicitud para devolver la ruta de acceso y el nombre de los objetos en un búfer de salida asignado por el controlador.

En el ejemplo de código siguiente se muestra cómo enviar una secuencia de dos solicitudes de IOCTL_ACPI_ENUM_CHILDREN sincrónicas para enumerar de forma recursiva todos los dispositivos secundarios del dispositivo primario al que se envían las solicitudes. El código realiza la siguiente secuencia de operaciones para controlar la primera solicitud:

  1. Establece el búfer de entrada para la primera solicitud. El búfer de entrada es una estructura de ACPI_ENUM_CHILDREN_INPUT_BUFFER con Signature establecido en ENUM_CHILDREN_INPUT_BUFFER_SIGNATURE y Flags establecido en ENUM_CHILDREN_MULTILEVEL.

  2. Establece el búfer de salida para la primera solicitud. El búfer de salida se establece en una estructura ACPI_ENUM_CHILDREN_OUTPUT_BUFFER . Este búfer de salida contiene solo una estructura ACPI_ENUM_CHILD que no es lo suficientemente grande como para devolver un nombre de un dispositivo.

  3. Llama a una función SendDownStreamIrp proporcionada por el autor de la llamada para enviar la primera solicitud de forma sincrónica al dispositivo primario.

  4. Comprueba si el controlador ACPI establece el estado devuelto en STATUS_BUFFER_OVERFLOW. Si se devolvió otro estado, esto indica un error y el código finaliza.

  5. Comprueba que el controlador ACPI establezca el miembro Signature en ACPI_ENUM_CHILDREN_OUTPUT_BUFFER_SIGNATURE y establezca NumberOfChildren en un valor mayor o igual que sizeof(ACPI_ENUM_CHILDREN_OUTPUT_BUFFER). Si ambos son true, el valor de NumberOfChildren es el tamaño, en bytes, del búfer de salida necesario para contener los nombres de objeto secundarios solicitados.

Después de que el código de ejemplo obtenga el tamaño necesario del búfer de salida, realiza la siguiente secuencia de operaciones para controlar la segunda solicitud, que devuelve la ruta de acceso y el nombre de los objetos secundarios solicitados:

  1. Asigna un búfer de salida del tamaño necesario, en bytes.

  2. Llama a la función SendDownStreamIrp proporcionada por el controlador para enviar la segunda solicitud de forma sincrónica al dispositivo primario.

  3. Comprueba que el controlador ACPI establezca el miembro Signature en ACPI_ENUM_CHILDREN_OUTPUT_BUFFER_SIGNATURE, establezca NumberOfChildren en uno o varios (lo que indica que se devolvió la ruta de acceso y el nombre de al menos un objeto) y establece el miembro Information del IO_STATUS_BLOCK en el tamaño asignado del búfer de salida.

  4. Procesa la matriz de nombres de objeto secundarios en el búfer de salida.

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