Condividi tramite


Invio di una richiesta di IOCTL_ACPI_ENUM_CHILDREN

Un driver usa in genere una sequenza di due richieste di IOCTL_ACPI_ENUM_CHILDREN per enumerare gli oggetti di interesse nello spazio dei nomi del dispositivo a cui viene inviata la richiesta. Il driver invia la prima richiesta per ottenere le dimensioni di un buffer di output allocato dal driver necessario per contenere il percorso e il nome degli oggetti. Il driver invia la seconda richiesta per restituire il percorso e il nome degli oggetti in un buffer di output allocato dal driver.

Nell'esempio di codice seguente viene illustrato come inviare una sequenza di due richieste sincrone IOCTL_ACPI_ENUM_CHILDREN per enumerare in modo ricorsivo tutti i dispositivi figlio del dispositivo padre a cui vengono inviate le richieste. Il codice esegue la sequenza di operazioni seguente per gestire la prima richiesta:

  1. Imposta il buffer di input per la prima richiesta. Il buffer di input è una struttura di ACPI_ENUM_CHILDREN_INPUT_BUFFER con Signature impostata su ENUM_CHILDREN_INPUT_BUFFER_SIGNATURE e Flag impostati su ENUM_CHILDREN_MULTILEVEL.

  2. Imposta il buffer di output per la prima richiesta. Il buffer di output è impostato su una struttura ACPI_ENUM_CHILDREN_OUTPUT_BUFFER . Questo buffer di output contiene solo una struttura ACPI_ENUM_CHILD che non è abbastanza grande per restituire un nome di un dispositivo.

  3. Chiama una funzione SendDownStreamIrp fornita dal chiamante per inviare la prima richiesta in modo sincrono al dispositivo padre.

  4. Verifica se il driver ACPI imposta lo stato restituito su STATUS_BUFFER_OVERFLOW. Se è stato restituito un altro stato, questo indica un errore e il codice termina.

  5. Verifica che il driver ACPI imposta il membro Signature su ACPI_ENUM_CHILDREN_OUTPUT_BUFFER_SIGNATURE e imposta NumberOfChildren su un valore maggiore o uguale alla dimensioneof(ACPI_ENUM_CHILDREN_OUTPUT_BUFFER). Se entrambi sono true, il valore di NumberOfChildren è la dimensione, in byte, del buffer di output necessario per contenere i nomi degli oggetti figlio richiesti.

Dopo che il codice di esempio ottiene le dimensioni necessarie del buffer di output, esegue la sequenza di operazioni seguente per gestire la seconda richiesta, che restituisce il percorso e il nome degli oggetti figlio richiesti:

  1. Alloca un buffer di output delle dimensioni necessarie, in byte.

  2. Chiama la funzione SendDownStreamIrp fornita dal driver per inviare la seconda richiesta in modo sincrono al dispositivo padre.

  3. Verifica che il driver ACPI imposta il membro Signature su ACPI_ENUM_CHILDREN_OUTPUT_BUFFER_SIGNATURE, imposta NumberOfChildren su uno o più (indicante che il percorso e il nome di almeno un oggetto è stato restituito) e imposta il membro Informazioni del IO_STATUS_BLOCK sulla dimensione allocata del buffer di output.

  4. Elabora la matrice di nomi di oggetti figlio nel buffer di output.

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