Windows XP デバイスドライバプログラミング[入門と実践]

サポートページ

この記事を読むのに必要な時間:およそ 0.5 分

ダウンロード

付録CD-ROMの修正

補足情報(2007/1/25までに掲載されたもの)に沿って修正を施したファイルを,以下からダウンロードできます(「list」「project」フォルダのみ。「usbtest」「baseproject」「usbtest」「testfile」については,CD-ROM収録のものをそのままお使いください)。

補足情報

リスト3-17(P.256~P.257)のUSB_IsochronousTransfer関数について

本関数では引数packetsに転送パケット数を設定するようになっていますが,これは8の倍数で設定する必要があります。

「4-5-2 ターゲットPCへのデバイスドライバのインストール」でusbstor.infが見つからない場合について

Windows XPの場合,usbstor.infが存在するINFフォルダは,通常の設定ではユーザーからは見えないようになっています。これを表示するためには,以下のようにします。

日本語版の場合
  1. エクススプローラを起動する
  2. 「ツール」から「フォルダオプション」を選択する
  3. フォルダオプションの画面にある「表示」というタブを選択する
  4. 「ファイルとフォルダの表示」という部分にある「すべてのファイルとフォルダを表示する」にチェックを入れる
  5. 「OK」をクリックする

英語版の場合

  1. エクスプローラを起動する
  2. 「 Tools 」から「 Folder Options 」を選択する
  3. Folder Optionsの画面にある「View」というタブを選択する
  4. 「Hidden files and folders」という部分にある「Show hidden files and folders」にチェックを入れる
  5. "Hide protected operating system files[Recommanded]"という項目がチェックされているのであれば,それを解除する
  6. 「OK」をクリックする

usbccgp.sysが介在した際の,マルチインターフェースデバイスに対する初期化処理

Windows XP SP2などで,usbccgp.sys(注1)が介在した場合のマルチインターフェースデバイスに関しては,INFファイルおよび初期化処理の記述に注意が必要です。

注1:複数の機能を持ったデバイスと,複数のドライバとを関連付けて管理するイメージのドライバ。

また,インターフェースディスクリプタを複数持つデバイスのドライバを開発されている方は,本書の内容だけでなく,以下の点にも配慮が必要となります。

INFファイル

VIDとPIDのほかに,MIという識別子を追加する必要があります。MI_xxの“xx”には,IADのbFirstInterfaceフィールドの値を指定します(下記の例では00)。

[Manufacturer_Name]

%DeviceDesc%=hamada_multi_if, USB\VID_ffff&PID_0000&MI_00

初期化コード 初期化の手順は,以下のようになります。
  1. USBD_ParseConfigurationDescriptorExで処理を行うインターフェースディスクリプタをすべて検索して,インターフェースリスト構造体に付加する。
  2. USBD_CreateConfigurationRequestExでURBを作成し,IoCallDriverでコンフィギュレーションを行う。また,この結果得られる(URB)->UrbSelectConfiguration.ConfigurationHandleをメモする。
  3. UsbBuildSelectInterfaceRequest(詳細はDDKヘルプを参照)でURBを作成して,さらに以下の設定を行う。

(URB)->UrbSelectInterface.Interface.Length =

GET_SELECT_INTERFACE_REQUEST_SIZE(x); // x=エンドポイントの数

  • また,必要ならば,エンドポイントごとの最大転送バイト数(MaximumTransferSize)の設定もここで行う。
  • IoCallDriverでインターフェースを選択する。

お詫びと訂正(正誤表)

本書の以下の部分に誤りがありました。ここに訂正するとともに,ご迷惑をおかけしたことを深くお詫び申し上げます。

P.リスト1-12(P.83~P.84)

[Strings]セクションの下から2行目の記述が,一部間違っています。正しくは以下のとおりです(第2刷にて修正済み)。

USB\VID_0644&PID_0000.DeviceDesc="USB Test Device Driver"
USB\VID_0474&PID_0700.DeviceDesc="USB Test Device Driver"

また,このファイルで実際に動作をしない場合,"Class=USB"の下に,以下の記述を追加してください。多くの場合はこの記述がなくても動作しますが,本来は記述が必要となります。

ClassGUID={36fc9e60-c465-11cf-8056-444553540000}

P.図1-41およびリスト1-16(P.121~125)

システムパワー制御(電源管理)に関して,図1-41ではIoSkipCurrentIrpStackLocationでI/Oスタックロケーションを設定するように説明しておりますが,リスト1-16(P.125)ではIoCopyCurrentIrpStackLocationとなっています。実際の動作には影響ありませんが,図とリストの整合性をとるために,リストの該当箇所はIoSkipCurrentIrpStackLocationに読み替えてください。

なお,第4章のリスト4-63(P.441~445)にも同様の処理があります(第2刷にて修正済み)。

P.142

6行目付近の説明で参照しているリスト番号が異なります。

リスト1-11
リスト1-1

P.図1-45(P.142)

A(アクセスコード)の説明とTypeの説明が入れ替わっていました。また,ビットの定義も一部異なっていました。正しくは以下のようになります(第2刷にて修正済み)。

D15-14 Aデバイス側で指定するアプリケーションが持っていなければならないアクセス権。以下から選択する
FILE_ANY_ACCESSいつでもアクセス可能
FILE_READ_DATA読み出し可能
FILE_WRITE_DATA書き込み可能
FILE_READ_DATA | FILE_WRITE_DATA読み書き可能
D1-0 Type転送タイプ。以下から選択する
METHOD_BUFFEREDSystemBufferを作成する(バッファードI/O)
METHOD_IN_DIRECT入力用のMDLを作成(ダイレクトI/O)
METHOD_OUT_DIRECT出力用のMDLを作成(ダイレクトI/O)
METHOD_NEITHER特に新しくバッファなどを作成しない

P.図2-5(P.155)

1.PIDの値が間違っているものがあります。正しくは以下のとおりです。(第2刷にて修正済み)

OUT(トークンパケットの部分)

0xA5
0xE1

SETUP(トークンパケットの部分)
0x20
0x2D

NAK(ハンドシェークパケットの部分)
0XA5
0xA5

2. データパケットの最後のCRCが“CRC5”となっていますが,データパケットの最後のCRCは16bit長となります。

3. SYNCフィールドの長さですが,ハイスピードモードの場合には32bit長となります。

P.表2-11(P.177)

コンフィグレーションディスクリプタに関する記述に誤りがあります。正しくは以下のとおりです(第2刷にて修正済み)。

bmAttributesのD7ビットは0にする
bmAttributesのD7ビットは1にする

また,bIntervalの内容に誤りがあります。正しくは以下のとおりです。

単位はミリ秒
単位は125μS(1マイクロフレーム長)

P.表2-12(P.187),表2-13,表2-16(P.192)

インターフェースディスクリプタの設定内容の表記に誤りがあります。

正しくは以下のとおりです(“bDevice”の部分が“bInterface”となります)(第3刷にて修正済み)。

bDeviceClass
bInterfaceClass

bDeviceSubClass
bInterfaceSubClass

bDeviceProtocol
bInterfaceProtocol

同様に,表2-13のキャプションは「bInterfaceSubClassの仕様」となります。

P.187およびP.192の本文についても,“bDevice”を“bInterface”と読み替えてください(第3刷にて修正済み)。

P.リスト3-17(P256~P257)

コードの記述のうち,以下の部分が間違っています。

また,内部変数としてULONG UrbSizeを宣言する必要があります。

ULONG usbFlags
ULONG urbFlags

urb = (PURB) ExAllocatePool(NonPagedPool, UrbSize);
urb = (PURB) ExAllocatePool(NonPagedPool, UrbSize); RtlZeroMemory(urb, UrbSize); // クリアを行わないとIoCallDriverの実行でエラーになる場合がある。

誤(第1刷) urb->UrbIsochronousTransfer.Hdr.Length = length;
誤(第2刷) urb->UrbIsochronousTransfer.Hdr.Length = UrbSize;
urb->UrbIsochronousTransfer.Hdr.Length = (USHORT)UrbSize;

urb->UrbIsochronousTransfer.Flags
urb->UrbIsochronousTransfer.TransferFlags

USBD_START_ISO_TRANSFERASAP
USBD_START_ISO_TRANSFER_ASAP

USB_CallUSBD(DeviceObject,&urb);
USB_CallUSBD(DeviceObject,urb);

ntStatus=urb.UrbHeader
ntStatus=urb->UrbHeader

P.リスト3-21(P.267)

25行目付近のコメント内で参照しているリスト番号が異なります。

詳細はリスト3-14
詳細はリスト3-17

P.337

4-7-3「AddDevice関数のコーディング」の2行目付近で参照しているリスト番号が異なります。

リスト1-15
リスト1-13

P.表4-5(P.337)

引数の説明の中で,ポインタと長さの説明が逆になっていました。

LPVOID lpInBuffer    パソコン→デバイスへのデータ長

DWORD nInBufferSize   パソコン→デバイスへのデータ

LPVOID lpOutBuffer   デバイス→パソコンへのデータ長

DWORD nOutBufferSize  デバイス→パソコンへのデータ

LPVOID lpInBuffer    パソコン→デバイスへのデータ

DWORD nInBufferSize   パソコン→デバイスへのデータ長

LPVOID lpOutBuffer   デバイス→パソコンへのデータ

DWORD nOutBufferSize  デバイス→パソコンへのデータ長

P.charポインタに関する記述について(第4,第5章)

本書中のソースコード内にて,ポインタを指定する際に不要な"&"を記述している箇所があります。ただし,"&"が記述されたままでも実際の動作に影響ありません。

なお,具体的な箇所は以下のとおりです。

リスト4-27(P.383~384)

(LPVOID)&buffer,
(LPVOID)buffer,

リスト4-33(P.392~393)

if (! WriteFile(hUsbTest,&buffer,5,&nBytes,NULL) ) {

if (! WriteFile(hUsbTest,buffer,5,&nBytes,NULL) ) {

リスト4-40(P.408~410)

・InquiryTest関数
if (!SendAtapiCommandPacket((PUCHAR)&atapi,36)) {
if (!SendAtapiCommandPacket((PUCHAR)atapi,36)) {

if (!ReadFile(hUsbTest,&buffer,36,&nBytes,NULL) ) {
if (!ReadFile(hUsbTest,buffer,36,&nBytes,NULL) ) {

・BulkOnlyCSWRead関数
return ReadFile(hUsbTest,&buffer,13,&nBytes,NULL);
return ReadFile(hUsbTest,buffer,13,&nBytes,NULL);

リスト4-43(P.415)

if (!SendAtapiCommandPacket((PUCHAR)&atapi,8)) {
if (!SendAtapiCommandPacket((PUCHAR)atapi,8)) {

if (!ReadFile(hUsbTest,&buffer,8,&nBytes,NULL) ) {

if (!ReadFile(hUsbTest,buffer,8,&nBytes,NULL) ) {

リスト5-9(P.469)

(LPVOID)&ConfigurationDescriptor,
(LPVOID)ConfigurationDescriptor,

リスト5-25(P.485~486)

UsbStorageDevice->SendAtapiRequestPacket((PVOID)&atapi,
UsbStorageDevice->SendAtapiRequestPacket((PVOID)atapi,

UsbStorageDevice->TransferData(TRUE,36,&InquiryData,NULL);
UsbStorageDevice->TransferData(TRUE,36,InquiryData,NULL);

memcpy(&product,&InquiryData[16],16);
memcpy(product,&InquiryData[16],16);

DumpData((PCHAR)&InquiryData,36);

DumpData((PCHAR)InquiryData,36);

リスト5-29(P.492

(PVOID)&AtapiRequest->AtapiRequestPacket,

(PVOID)AtapiRequest->AtapiRequestPacket,

リスト5-35(P.497~499)

m_ClassCode = (CHAR *)&buffer;

m_ClassCode = (CHAR *)buffer;

m_SubClassCode = (CHAR *)&buffer;
m_SubClassCode = (CHAR *)buffer;

m_ProtocolCode = (CHAR *)&buffer;

m_ProtocolCode = (CHAR *)buffer;

m_DeviceSpeed = (CHAR *)&buffer;

m_DeviceSpeed = (CHAR *)buffer;

m_ConsoleEditor = (CHAR *)&buffer;
m_ConsoleEditor = (CHAR *)buffer;

m_ConsoleEditor = (CHAR *)&buffer;
m_ConsoleEditor = (CHAR *)buffer;

リスト5-36(P.499~500)

&RecvCapacityData);
RecvCapacityData);

リスト5-37(P.501~502)

m_RequestSenseASC = (CHAR *)&EditBoxData;
m_RequestSenseASC = (CHAR *)EditBoxData;

m_RequestSenseASCQ = (CHAR *)&EditBoxData;
m_RequestSenseASCQ = (CHAR *)EditBoxData;

リスト5-40(P.507~509)

memset(&buffer,0,128);
memset(buffer,0,128);

m_AtapiPacket = (CHAR *)&buffer;

m_AtapiPacket = (CHAR *)buffer;

P.4-8-2「USBデバイスの初期化処理の実装」

本書のコードでは,USB_StartDevice関数で確保した,deviceExtension->ConfigurationAllDescriptorを解放していません。そのため,これを解放する,以下のようなコードを追加する必要があります。

※USB_DispatchPnp関数のIRP_MN_REMOVE_DEVICE処理

IoDeleteDeviceの前に,以下のコードを追加する

:
// コンフィギュレーションディスクリプタのために
// 確保したメモリを解放する
if (deviceExtension->ConfigurationAllDescriptor) 
ExFreePool(deviceExtension->ConfigurationAllDescriptor);
// デバイスオブジェクトを削除する
IoDeleteDevice (DeviceObject);
:

P.リスト5-1(P.480)

リストの名前が異なります。

CCBIStorageDeviceクラスのヘッダ
CBulkOnlyStorageDeviceクラスのヘッダ

P.リストA-1(P.663)ObDereferenceObjectの引数

ObDereferenceObjectの引数はオブジェクトへのポインタなので,「&」は必要ありません。以下のように修正してください(第3刷にて修正済み)。

ObDereferenceObject(&ThreadObjectPointer);
ObDereferenceObject(ThreadObjectPointer);

誤(第1刷) urb->UrbIsochronousTransfer.Hdr.Length = length;
誤(第2刷) urb->UrbIsochronousTransfer.Hdr.Length = UrbSize;
urb->UrbIsochronousTransfer.Hdr.Length = (USHORT)UrbSize;

urb->UrbIsochronousTransfer.Flags
urb->UrbIsochronousTransfer.TransferFlags

USBD_START_ISO_TRANSFERASAP
USBD_START_ISO_TRANSFER_ASAP

USB_CallUSBD(DeviceObject,&urb);
USB_CallUSBD(DeviceObject,urb);

ntStatus=urb.UrbHeader
ntStatus=urb->UrbHeader