SCIENCE PARK

デバドラ講座

【 デバドラ講座22 : デバイスオブジェクト 】

ドライバはAddDeviceで最初に各デバイスを表すデバイスオブジェクトを1つ以上生成します。デバイスオブジェクトには以下の3つがあります。

1. PDO (Physical Device Object)
バス上に接続されているデバイスを示すオブジェクトです。バスドライバまたはPnPマネージャがバス上で検出されたすべてのバスについてPDOを作成します。
2. FDO (Functional Device Object)
デバイスドライバが制御するデバイスを示すオブジェクトです。I/Oマネージャはこのオブジェクトによりデバイスを認識します。IoCreateDevice関数によって作られたオブジェクトです。
3. Filter DO (Filter Device object)
フィルタドライバが制御するデバイスを示すオブジェクトです。フィルタドライバはFDOの上位にも下位にもアタッチすることができます。

AddDeviceルーチンでは、生成したFDOがPDOにアタッチする必要があります。AddDevice関数のプロトコルは次のようになっています。

NTSTATUS Bus_AddDevice(
    IN PDRIVER_OBJECT DriverObject,                       //ドライバオブジェクトのポインタ
    IN PDEVICE_OBJECT PhysicalDeviceObject); //下位物理デバイスオブジェクトのポインタ

ここのドライバオブジェクトはDriverEntryに渡されたドライバオブジェクトと同じです。下位物理デバイスオブジェクト(PDO)はPnPマネージャにより生成されたオブジェクトです。このオブジェクトは1階層だけのドライバにも存在します。AddDeviceルーチン内のIoCreateDevice関数によりFDOが作られます。生成されたFDOとPDOはアタッチする必要があります。次にFDOがPDOにアタッチする関数のプロトコルを示します。

PDEVICE_OBJECT IoAttachDeviceToDeviceStack(
    IN PDEVICE_OBJECT SourceDevice,        //FDOのポインタ
    IN PDEVICE_OBJECT TargetDevice);        //PDOのポインタ

この関数はアタッチした実際の下位デバイスのポインタを返します。ドライバの中でこのオブジェクトを使うので、このオブジェクトを保存する必要があります。PDOとFDOの関係を図1に示します。

図1:PDOとFDOの関係
図1:PDOとFDOの関係

デバイスオブジェクトはドライバオブジェクトと同じように、システム内で構造体として管理されています。ドライバオブジェクトは、ドキュメントに記載されているフィールドにのみアクセスすることができます。次にデバイスオブジェクトの構造体の一部を示します。

typedef struct _DEVICE_OBJECT {
    PDRIVER_OBJECT     DriverObject;
    PDEVICE_OBJECT     NextDevice;
    PIRP                             CurrentIrp;
    ULONG                        Flags;
    ULONG                        Characteristics;
    PVOID                          DeviceExtension;
    DEVICE_TYPE             DeviceType;
    CCHAR                        StackSize;
    ULONG                        AlignmentRequirement;
//ドキュメントに明記されていないフィールドが続きます
} DEVICE_OBJECT;

デバイスオブジェクトを作成する際、デバイスエクステンションのサイズを決める必要があります。デバイスエクステンションはドライバ開発者が独自に設けることができるデバイスに関する情報の構造体です。例えば、PortIOドライバでは次のようなデバイスエクステンションが定義されています。

typedef struct _LOCAL_DEVICE_INFO {
    PVOID            PortBase;                     // base port address
    ULONG           PortCount;                    // Count of I/O addresses used.
    ULONG    PortMemoryType;             //HalTranslateBusAddress Memory Type
    PDEVICE_OBJECT     DeviceObject;   // The Gpd device object.
    PDEVICE_OBJECT NextLowerDriver;  // The top of the stack
    BOOLEAN     Started;                             //Start Flag
    BOOLEAN     Removed;                          //Removed Flag
    BOOLEAN     PortWasMapped;             // If TRUE, we have to unmap on unload 
    BOOLEAN         Filler [1];            //bug fix
    IO_REMOVE_LOCK    RemoveLock;                    
} LOCAL_DEVICE_INFO, *PLOCAL_DEVICE_INFO;

デバイスエクステンションは開発者自身が状況に応じて設けるので、ドキュメント化されていない場合ソースコードから真意を理解するのは難しくなります。デバイスエクステンションを定義する場合、ドキュメントを書くことがとても大切です。デバイスオブジェクトとデバイスエクステンションは非ページメモリに作成されます。

ドライバがアンロードされる際、PnPディスパッチルーチンのマイナー関数[IRP_MN_REMOVE_DEVICE]によってデバイスオブジェクトは削除されます。

参考資料

「NTドライバプログラミング」
Peter G. Viscarola、W. Anthony Mason著 久保雅俊、三浦秀朗訳 サイエンスパーク株式会社 監修
「Windows NTデバイスドライバプログラミング」
アート・ベーカー著 WinProgDDK ML和訳プロジェクト訳
「WDMデバイスドライバプログラミング完全ガイド」上
Edword N. Dekker, Jpseph M. Newcomer著 株式会社クイック訳
「WDMデバイスドライバ」
Chris Cant著 エクストランス株式会社訳 サイエンスパーク株式会社 監修
page up