Freigeben über


Senden einer IOCTL_ACPI_ENUM_CHILDREN-Anforderung

Ein Treiber verwendet in der Regel eine Sequenz von zwei IOCTL_ACPI_ENUM_CHILDREN Anforderungen, um die interessanten Objekte im Namespace des Geräts aufzulisten, an das die Anforderung gesendet wird. Der Treiber sendet die erste Anforderung, um die Größe eines vom Treiber zugewiesenen Ausgabepuffers abzurufen, der erforderlich ist, um den Pfad und den Namen der Objekte zu enthalten. Der Treiber sendet die zweite Anforderung, um den Pfad und den Namen der Objekte in einem vom Treiber zugewiesenen Ausgabepuffer zurückzugeben.

Das folgende Codebeispiel zeigt, wie eine Sequenz von zwei synchronen IOCTL_ACPI_ENUM_CHILDREN Anforderungen gesendet wird, um alle untergeordneten Geräte des übergeordneten Geräts, an das die Anforderungen gesendet werden, rekursiv aufzulisten. Der Code führt die folgenden Vorgänge aus, um die erste Anforderung zu behandeln:

  1. Legt den Eingabepuffer für die erste Anforderung fest. Der Eingabepuffer ist eine ACPI_ENUM_CHILDREN_INPUT_BUFFER-Struktur , wobei Signatur auf ENUM_CHILDREN_INPUT_BUFFER_SIGNATURE und Flags auf ENUM_CHILDREN_MULTILEVEL festgelegt ist.

  2. Legt den Ausgabepuffer für die erste Anforderung fest. Der Ausgabepuffer ist auf eine ACPI_ENUM_CHILDREN_OUTPUT_BUFFER-Struktur festgelegt. Dieser Ausgabepuffer enthält nur eine ACPI_ENUM_CHILD Struktur, die nicht groß genug ist, um einen Gerätenamen zurückzugeben.

  3. Ruft eine vom Aufrufer bereitgestellte SendDownStreamIrp-Funktion auf, um die erste Anforderung synchron an das übergeordnete Gerät zu senden.

  4. Überprüft, ob der ACPI-Treiber die Rückgabe status auf STATUS_BUFFER_OVERFLOW festgelegt hat. Wenn ein weiterer status zurückgegeben wurde, weist dies auf einen Fehler hin, und der Code wird beendet.

  5. Überprüft, ob der ACPI-Treiber den Signature-Member auf ACPI_ENUM_CHILDREN_OUTPUT_BUFFER_SIGNATURE festgelegt hat, und legt NumberOfChildren auf einen Wert fest, der größer oder gleich dem sizeof(ACPI_ENUM_CHILDREN_OUTPUT_BUFFER ist). Wenn beide true sind, ist der Wert von NumberOfChildren die Größe des Ausgabepuffers in Bytes, die erforderlich ist, um die angeforderten untergeordneten Objektnamen zu enthalten.

Nachdem der Beispielcode die erforderliche Größe des Ausgabepuffers abgerufen hat, führt er die folgende Abfolge von Vorgängen aus, um die zweite Anforderung zu behandeln, die den Pfad und den Namen der angeforderten untergeordneten Objekte zurückgibt:

  1. Ordnet einen Ausgabepuffer der erforderlichen Größe in Bytes zu.

  2. Ruft die vom Treiber bereitgestellte SendDownStreamIrp-Funktion auf, um die zweite Anforderung synchron an das übergeordnete Gerät zu senden.

  3. Überprüft, ob der ACPI-Treiber den Signature-Member auf ACPI_ENUM_CHILDREN_OUTPUT_BUFFER_SIGNATURE festgelegt hat, legt NumberOfChildren auf einen oder mehrere fest (was angibt, dass der Pfad und der Name von mindestens einem Objekt zurückgegeben wurden), und legt den Informationsmember des IO_STATUS_BLOCK auf die zugeordnete Größe des Ausgabepuffers fest.

  4. Verarbeitet das Array der untergeordneten Objektnamen im Ausgabepuffer.

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