IOCTL_ACPI_ENUM_CHILDREN 요청 보내기

드라이버는 일반적으로 두 개의 IOCTL_ACPI_ENUM_CHILDREN 요청 시퀀스를 사용하여 요청이 전송되는 디바이스의 네임스페이스에 관심 있는 개체를 열거합니다. 드라이버는 첫 번째 요청을 전송하여 개체의 경로와 이름을 포함하는 데 필요한 드라이버 할당 출력 버퍼의 크기를 가져옵니다. 드라이버는 드라이버 할당 출력 버퍼에 있는 개체의 경로와 이름을 반환하는 두 번째 요청을 보냅니다.

다음 코드 예제에서는 두 개의 동기 IOCTL_ACPI_ENUM_CHILDREN 요청 시퀀스를 전송하여 요청이 전송되는 부모 디바이스의 모든 자식 디바이스를 재귀적으로 열거하는 방법을 보여 줍니다. 코드는 첫 번째 요청을 처리하기 위해 다음 작업 시퀀스를 수행합니다.

  1. 첫 번째 요청에 대한 입력 버퍼를 설정합니다. 입력 버퍼는 서명ENUM_CHILDREN_INPUT_BUFFER_SIGNATURE 설정되고 플래그가 ENUM_CHILDREN_MULTILEVEL 설정된 ACPI_ENUM_CHILDREN_INPUT_BUFFER 구조체입니다.

  2. 첫 번째 요청에 대한 출력 버퍼를 설정합니다. 출력 버퍼는 ACPI_ENUM_CHILDREN_OUTPUT_BUFFER 구조체로 설정됩니다. 이 출력 버퍼에는 디바이스 이름을 반환할 만큼 크지 않은 하나의 ACPI_ENUM_CHILD 구조만 포함됩니다.

  3. 호출자가 제공한 SendDownStreamIrp 함수 를 호출하여 첫 번째 요청을 부모 디바이스에 동기적으로 보냅니다.

  4. ACPI 드라이버가 반환 상태 STATUS_BUFFER_OVERFLOW 설정했는지 확인합니다. 다른 상태 반환된 경우 오류가 발생하고 코드가 종료됨을 나타냅니다.

  5. ACPI 드라이버가 서명 멤버를 ACPI_ENUM_CHILDREN_OUTPUT_BUFFER_SIGNATURE 설정하고 NumberOfChildrensizeof(ACPI_ENUM_CHILDREN_OUTPUT_BUFFER)보다 크거나 같은 값으로 설정하는지 확인합니다. 둘 다 true이면 NumberOfChildren 값은 요청된 자식 개체 이름을 포함하는 데 필요한 출력 버퍼의 크기(바이트)입니다.

예제 코드는 출력 버퍼의 필요한 크기를 가져온 후 요청된 자식 개체의 경로와 이름을 반환하는 두 번째 요청을 처리하기 위해 다음 작업 시퀀스를 수행합니다.

  1. 필요한 크기의 출력 버퍼(바이트)를 할당합니다.

  2. 드라이버 제공 SendDownStreamIrp 함수를 호출하여 두 번째 요청을 부모 디바이스에 동기적으로 보냅니다.

  3. ACPI 드라이버가 서명 멤버를 ACPI_ENUM_CHILDREN_OUTPUT_BUFFER_SIGNATURE 설정하고, NumberOfChildren를 하나 이상으로 설정하고(하나 이상의 개체의 경로와 이름이 반환되었음을 나타낸) IO_STATUS_BLOCK정보 멤버를 출력 버퍼의 할당된 크기로 설정합니다.

  4. 출력 버퍼에서 자식 개체 이름의 배열을 처리합니다.

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