デバイスの接続設定を取得する方法

SPB コントローラー ドライバーが EvtSpbTargetConnect コールバック関数を登録する場合、SPB フレームワーク拡張機能 (SpbCx) は、コントローラーのクライアント (周辺機器ドライバー) がバス上のターゲット デバイスへ論理接続を開く IRP_MJ_CREATE 要求を送信するときに、この関数を呼び出します。 EvtSpbTargetConnect コールバックに応答して、SPB コントローラー ドライバーは SpbTargetGetConnectionParameters メソッドを呼び出して、ターゲット デバイスの接続設定を取得する必要があります。 SPB コントローラー ドライバーは、これらの設定を格納し、後でクライアントからの I/O 要求に応答してデバイスにアクセスするのに使用します。

たとえば、I2C バス上のターゲット デバイスの接続設定には、デバイスのバス アドレス、アドレス幅 (7 または 10 ビット)、デバイスのアクセス時に使用するバス クロック周波数が含まれます。 I2C コントローラー ドライバーは、これらの設定を使用して、I2C バス経由でデバイスにアクセスするようにコントローラーを構成します。

SPB コントローラー ドライバーは、SpbTargetGetConnectionParameters を呼び出して、I2C または SPI 型のシリアル バスへのターゲット デバイス接続を記述するシリアル バス接続記述子へのポインターを取得します。 この記述子には、両方のシリアル バスの種類に共通の接続情報が含まれており、その後に、デバイスが接続されているシリアル バスに固有の情報が続きます。 この記述子の形式の詳細については、ACPI 5.0 の仕様 を参照してください。

次のコード例では、I2C コント ローラー ドライバーは、PNP_I2C_Standard Edition RIAL_BUS_DESCRIPTOR 構造体を定義します。 この構造体は、I2C シリアル バス接続記述子 を表しますが、ACPI 5.0 仕様が I2C バスに固有の接続設定を行った後に続くシリアル バス接続記述子を記述するために使用する用語です。 PNP_I2C_SERIAL_BUS_DESCRIPTOR 構造体の最初のメンバーである SerialBusDescriptor は、シリアル バス接続記述子を表す PNP_SERIAL_BUS_DESCRIPTOR 構造体です。 ConnectionSpeed メンバーと SlaveAddress メンバーには、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>

reshub.h ヘッダー ファイルは、PNP_SERIAL_BUS_DESCRIPTOR 構造体を定義します。 pshpack1.h ヘッダー ファイルと poppack.h ヘッダー ファイルは、コンパイラで使用される構造体配置モードを制御します。

I2C シリアル バス接続記述子は、隣接するフィールドが最も近いバイトの境界に配置され、ギャップを埋めることなくパックされたデータ構造です。 その結果、この記述子の 16 ビット整数値が奇数バイト境界で開始される可能性があります。 前のコード例では、隣接する構造体メンバーをパックするようにコンパイラに指示するための pshpack1.h が含まれており、poppack.h は既定の構造体の配置を再開するようにコンパイラに指示します。

PNP_I2C_SERIAL_BUS_DESCRIPTOR 構造体の ConnectionSpeed メンバーは、ターゲット デバイスへのアクセス中に I2C バスをクロックする周波数を Hertz で指定します。 SlaveAddress メンバーは、ターゲット デバイスのバス アドレスです。 一部の I2C コントローラー ドライバーでは、SlaveAddress メンバーの後にオプションのベンダー固有データが続く場合がありますが、このデータはこのコード例ではドライバーによって使用されないため、構造体定義の一部ではありません。

次のコード例では、前の例の I2C コントローラー ドライバーは、SpbTargetGetConnectionParameters を呼び出して I2C バス上のターゲット デバイスの接続設定を取得する GetTargetSettings ルーチンを実装しています。 このルーチンへの Target 入力パラメーターは、ターゲット デバイスへのハンドルです。 Settings 出力パラメーターは、ルーチンが接続パラメーターのセットを書き込むドライバーによって割り当てられた SPB_CONNECTION_PARAMETERS 構造体へのポインターです。 これらのパラメーターには、要求された接続設定へのポインターが含まれます。

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

前のコード例では、 SpbTargetGetConnectionParameters がドライバー割り当て Params 構造体に接続パラメーターを書き込みます。 ParamsConnectionParameters メンバーは、ConnectionProperties メンバーがシリアル バス接続記述子の最初のバイトである RH_QUERY_CONNECTION_PROPERTIES_OUTPUT_BUFFER 構造体 (reshub.h で定義) を指します。この記述子の残りのバイトは、ConnectionProperties メンバーの直後にあります。 ParamsConnectionParameters メンバーが指すバッファーは、RH_QUERY_CONNECTION_PROPERTIES_OUTPUT_BUFFER 構造体と、この構造体に続く記述子バイトを格納するのに十分な大きさです。

前のコード例のドライバー実装 GetTargetSettings ルーチンは、SpbTargetGetConnectionParameters から受信した接続パラメーターに対して、次のパラメーター チェックを実行します。

  • RH_QUERY_CONNECTION_PROPERTIES_OUTPUT_BUFFER 構造体に含まれるシリアル バス接続記述子のサイズが、少なくとも sizeof(PNP_SERIAL_BUS_DESCRIPTOR) であることを確認します。
  • ACPI 5.0 仕様で必要に応じて、シリアル バス接続記述子の最初のバイトが SERIAL_BUS_DESCRIPTOR (定数値0x8e) に設定されていることを確認します。
  • シリアル バス接続記述子のシリアル バスの種類が I2C_SERIAL_BUS_TYPE (定数値0x01) に設定されていることを確認します。これにより、シリアル バスの種類が I2C として識別されます。

前のコード例の最後にある *Settings 構造体には、ターゲット デバイスの接続設定 (バス アドレス、アドレス幅、バス クロック周波数) が含まれています。 I2C コントローラー ドライバーは、これらの接続設定を使用して、デバイスにアクセスするようにコントローラーを構成します。