Cómo obtener la configuración de conexión de un dispositivo

Si el controlador del controlador SPB registra una función de devolución de llamada EvtSpbTargetConnect , la extensión del marco SPB (SpbCx) llama a esta función cuando un cliente (controlador periférico) del controlador envía una solicitud de IRP_MJ_CREATE para abrir una conexión lógica a un dispositivo de destino en el bus. En respuesta a la devolución de llamada EvtSpbTargetConnect , el controlador del controlador SPB debe llamar al método SpbTargetGetConnectionParameters para obtener la configuración de conexión del dispositivo de destino. El controlador del controlador SPB almacena esta configuración y las usa más adelante para acceder al dispositivo en respuesta a las solicitudes de E/S del cliente.

Por ejemplo, la configuración de conexión de un dispositivo de destino en un bus I2C incluye la dirección del bus del dispositivo, el ancho de dirección (7 o 10 bits) y la frecuencia del reloj del bus que se usará durante los accesos del dispositivo. El controlador del controlador I2C usa estas opciones para configurar el controlador para acceder al dispositivo a través del bus I2C.

Un controlador SPB llama a SpbTargetGetConnectionParameters para obtener un puntero a un descriptor de conexión de bus serie que describe la conexión de un dispositivo de destino a un bus serie de tipo I2C o SPI. Este descriptor contiene información de conexión común a ambos tipos de bus serie y va seguida de información específica del bus serie al que está conectado el dispositivo. Para obtener más información sobre el formato de este descriptor, vea la especificación ACPI 5.0.

En el ejemplo de código siguiente, un controlador I2C define una estructura de PNP_I2C_SERIAL_BUS_DESCRIPTOR . Esta estructura representa un descriptor de conexión de bus serie I2C, que es el término que la especificación ACPI 5.0 usa para describir un descriptor de conexión de bus serie seguido de la configuración de conexión específica del bus I2C. El primer miembro de la estructura PNP_I2C_SERIAL_BUS_DESCRIPTOR , SerialBusDescriptor, es una estructura PNP_SERIAL_BUS_DESCRIPTOR que representa el descriptor de conexión de bus serie. Los miembros ConnectionSpeed y SlaveAddress contienen la configuración de conexión específica de I2C.

#include <reshub.h>
#include <pshpack1.h>  

//
// See the ACPI 5.0 spec, section 6.4.3.8.2.1 (I2C Serial Bus Connection Descriptor).  
//
typedef struct _PNP_I2C_SERIAL_BUS_DESCRIPTOR {  
    PNP_SERIAL_BUS_DESCRIPTOR SerialBusDescriptor;  
    ULONG ConnectionSpeed;  
    USHORT SlaveAddress;  
    // Followed by optional vendor-specific data.
    // Followed by name of serial bus controller.
} PNP_I2C_SERIAL_BUS_DESCRIPTOR, *PPNP_I2C_SERIAL_BUS_DESCRIPTOR;  
  
#include <poppack.h>

El archivo de encabezado reshub.h define la estructura PNP_SERIAL_BUS_DESCRIPTOR . Los archivos de encabezado pshpack1.h y poppack.h controlan el modo de alineación de la estructura usado por el compilador.

Un descriptor de conexión de bus serie I2C es una estructura de datos empaquetada en la que los campos adyacentes se alinean con los límites de bytes más cercanos, sin espacios intermedios. Como resultado, un valor entero de 16 bits en este descriptor podría comenzar en un límite de bytes impar. En el ejemplo de código anterior, pshpack1.h se incluye para indicar al compilador que empaqueta los miembros de la estructura adyacentes y poppack.h indica al compilador que reanude la alineación de la estructura predeterminada.

El miembro ConnectionSpeed de la estructura de PNP_I2C_SERIAL_BUS_DESCRIPTOR especifica la frecuencia, en Hertz, en la que se va a reloj el bus I2C durante los accesos del dispositivo de destino. El miembro SlaveAddress es la dirección del bus del dispositivo de destino. Para algunos controladores de controlador I2C, el miembro SlaveAddress puede ir seguido de datos opcionales específicos del proveedor, pero este dato no lo usa el controlador en este ejemplo de código y, por lo tanto, no forma parte de la definición de la estructura.

En el ejemplo de código siguiente, el controlador I2C del ejemplo anterior implementa una GetTargetSettings rutina que llama a SpbTargetGetConnectionParameters para obtener la configuración de conexión de un dispositivo de destino en el bus I2C. El parámetro de entrada de destino de esta rutina es un identificador para el dispositivo de destino. El parámetro de salida Settings es un puntero a una estructura de SPB_CONNECTION_PARAMETERS asignada por el controlador en la que la rutina escribe un conjunto de parámetros de conexión. Estos parámetros incluyen un puntero a la configuración de conexión solicitada.

#define I2C_SERIAL_BUS_TYPE 0x01
#define I2C_SERIAL_BUS_SPECIFIC_FLAG_10BIT_ADDRESS 0x0001

typedef enum _I2C_ADDRESS_MODE
{
    AddressMode7Bit,
    AddressMode10Bit
} I2C_ADDRESS_MODE, *PI2C_ADDRESS_MODE;
  
typedef struct _I2C_TARGET_SETTINGS
{
    ULONG  ClockFrequency;
    ULONG  Address;
    I2C_ADDRESS_MODE  AddressMode;
} I2C_TARGET_SETTINGS, *PI2C_TARGET_SETTINGS;

NTSTATUS
GetTargetSettings(_In_ SPBTARGET Target, _Out_ PI2C_TARGET_SETTINGS Settings)
{
    PRH_QUERY_CONNECTION_PROPERTIES_OUTPUT_BUFFER Connection = NULL;
    SPB_CONNECTION_PARAMETERS Params;

    SPB_CONNECTION_PARAMETERS_INIT(&Params);
    SpbTargetGetConnectionParameters(Target, &Params);
    Connection = (PRH_QUERY_CONNECTION_PROPERTIES_OUTPUT_BUFFER)Params.ConnectionParameters;
    if (Connection->PropertiesLength < sizeof(PNP_SERIAL_BUS_DESCRIPTOR))
    {
        return STATUS_INVALID_PARAMETER;
    }

    PPNP_SERIAL_BUS_DESCRIPTOR Descriptor;

    Descriptor = (PPNP_SERIAL_BUS_DESCRIPTOR)Connection->ConnectionProperties;
    if (Descriptor->Tag != SERIAL_BUS_DESCRIPTOR ||
        Descriptor->SerialBusType != I2C_SERIAL_BUS_TYPE)
    {
        return STATUS_INVALID_PARAMETER;
    }

    PPNP_I2C_SERIAL_BUS_DESCRIPTOR I2CDescriptor;
    USHORT I2CFlags;

    I2CDescriptor = (PPNP_I2C_SERIAL_BUS_DESCRIPTOR)Connection->ConnectionProperties;
    Settings->Address = (ULONG)I2CDescriptor->SlaveAddress;
    I2CFlags = I2CDescriptor->SerialBusDescriptor.TypeSpecificFlags;
    Settings->AddressMode = 
                ((I2CFlags & I2C_SERIAL_BUS_SPECIFIC_FLAG_10BIT_ADDRESS) == 0) ? AddressMode7Bit : AddressMode10Bit;

    Settings->ClockFrequency = I2CDescriptor->ConnectionSpeed;

    return STATUS_SUCCESS;
}

En el ejemplo de código anterior, SpbTargetGetConnectionParameters escribe los parámetros de conexión en la estructura asignada por Params el controlador. El miembro ConnectionParameters de Params apunta a una estructura de RH_QUERY_CONNECTION_PROPERTIES_OUTPUT_BUFFER (definida en reshub.h), cuyo miembro ConnectionProperties es el primer byte del descriptor de conexión de bus serie; los bytes restantes de este descriptor siguen inmediatamente al miembro ConnectionProperties . El búfer al que apunta el miembro ConnectionParameters de Params es lo suficientemente grande como para contener la estructura de RH_QUERY_CONNECTION_PROPERTIES_OUTPUT_BUFFER más los bytes descriptores que siguen esta estructura.

La rutina implementada por GetTargetSettings el controlador en el ejemplo de código anterior realiza las comprobaciones de parámetros siguientes en los parámetros de conexión recibidos de SpbTargetGetConnectionParameters:

  • Comprueba que el tamaño del descriptor de conexión de bus serie contenido en la estructura RH_QUERY_CONNECTION_PROPERTIES_OUTPUT_BUFFER es al menos sizeof(PNP_SERIAL_BUS_DESCRIPTOR).
  • Comprueba que el primer byte del descriptor de conexión de bus serie está establecido en SERIAL_BUS_DESCRIPTOR (valor constante 0x8e), según lo requiera la especificación ACPI 5.0.
  • Comprueba que el tipo de bus serie del descriptor de conexión de bus serie está establecido en I2C_SERIAL_BUS_TYPE (valor constante 0x01), que identifica el tipo de bus serie como I2C.

Al final del ejemplo de código anterior, la estructura *Settings contiene la configuración de conexión (dirección de bus, ancho de dirección y frecuencia del reloj del bus) para el dispositivo de destino. El controlador del controlador I2C usa estas opciones de conexión para configurar el controlador para acceder al dispositivo.