none
デバイスドライバを再接続時のエラー(コード38)の原因 RRS feed

  • 質問

  • デバイスドライバを再接続したときのエラーで皆さんのお知恵を拝借できればと思います。

    機器をUSB端子につなげた後、一度抜き、再び差し込むと使用できなくなります。
    (抜く前までは使えます)
    エラー発生時の状態:
    「デバイスマネージャ」のデバイス上に!マークが表示され、「デバイスの状態」は
    「このハードウェアのデバイスドライバーの前のインスタンスがまだメモリ内にあるので、デバイスドライバーを読込むことができません。(コード38)」
    となってしまいます。

    WindowsVista/XPでは問題なく(問題なく見えているだけかもしれませんが)、Windows7のみの現象です。
    Windows7になってから機器のクラス(スマートカード)の上位にフィルタドライバが追加されました。
    その為、エラーの判断も変わったのかもしれません。

    状況:
    ・機器を抜いたときのドライバの処理(IRP_MN_REMOVE_DEVICEなど)で、エラーで返しているところはありません。
    ・一度アンロードもされています(Unloadが呼ばれます)。
    ・再び差し込んだときに、DriverEntryが呼ばれた後、Unloadが呼ばれます。(AddDeviceは来ません)

    ドライバ構成:
    上位 Win7で追加されたドライバ
       機器のドライバ1
       機器のドライバ2
    下位 USBドライバスタック


    この現象の原因についてご助言をいただければ幸いです。

    ドライバのインスタンスがまだメモリ内にあるような状態とは、下のような状態と考えています。
    ・メモリリーク(ExFreePool処理抜け)
    ・IoDeleteDeviceエラー(処理抜け)
    ・IoDetachDeviceエラー(処理抜け)
    ・IRPがPENDINGのまま完了していない。
    ・IoFreeWorkItem処理忘れ
    ・RemoveLockの解除忘れ
    ・SmartcardExit忘れ(スマートカードクラスのため)
    ・IoSetDeviceInterfaceStateでFalseし忘れ
    他に必要な項目はありますでしょうか?

    この他、参考になる情報等ありましたらご助言よろしくお願いします。

    長文で失礼しました。


    DriverDeveloper
    • 移動 Mike Wang (MSCS) 2012年10月2日 12:48 (移動元:Windows デバイスドライバー開発)
    2011年7月27日 4:44

すべての返信

  • 参考になるかどうか分かりませんが。。。

    Device Manager でのエラーがコード 38 とのことですが、これは以下のエラー メッセージに対応していると思います。

    ------------------------------------------------------------------
    CM_PROB_DRIVER_FAILED_PRIOR_UNLOAD

    http://msdn.microsoft.com/en-us/library/ff538922(v=vs.85).aspx
    ------------------------------------------------------------------

    ですので、Hiro2000 さんが推測されているように、デバイスの削除処理に問題があるのだと思います。

    実は私も以前、USB デバイスの再接続時に Code 38 (CM_PROB_DRIVER_FAILED_PRIOR_UNLOAD) が発生する問題に遭遇したことがあります。
    (スマートカード クラスではありませんでしたが。)

    その時の問題は、IRP_MN_SURPRISE_REMOVAL にありました。
    他社製品のドライバも絡む原因だったので、あまり詳しくは書けないのですが、IRP_MN_SURPRISE_REMOVAL での処理に問題がある場合も、Code 38 のエラーが発生するようです。

    USB 接続などの Hot-plug Deivce に対する物理的な取り外しを行った場合、通常 IRP_MN_REMOVE_DEVICE の直前に IRP_MN_SURPRISE_REMOVAL が来るはずだと思います。
    (ただし IRP_MN_SURPRISE_REMOVAL は必ず来る訳ではないはずなので、ご注意ください。)
    IRP_MN_SURPRISE_REMOVAL は IRP_MN_REMOVE_DEVICE と似たような通知ですが、Minor Code が異なるので、当然イコールではありません。

    私が遭遇した時の問題では、私のドライバの下位にアタッチしていた他社ドライバが、IRP_MN_SURPRISE_REMOVAL で IoDetachDevice() および IoDeleteDevice() をコールしてしまっていることが原因でした。
    下位ドライバが IRP_MN_SURPRISE_REMOVAL で IoDetachDevice() / IoDeleteDevice() コールを行ってしまうと、それ以降に発行される IRP_MN_REMOVE_DEVICE がデバイス スタック最上位のドライバに正しく通知されてこなくなるため、正常にデバイス スタックの解除およびデバイス オブジェクトの削除が行われず、その結果再接続時に Code 38 のエラーを引き起こす。。。という流れだったと記憶しています。(昔のことなので、ちょっとあやふやかも。)
    IRP_MN_SURPRISE_REMOVAL におけるこの制限に関しては、以下のサイトに情報が公開されています。

    ------------------------------------------------------------------
    Handling an IRP_MN_SURPRISE_REMOVAL Request

    http://msdn.microsoft.com/en-us/library/ff546699(v=VS.85).aspx

    ....

    9. Leave the device object attached to the device stack.
    Do not detach and delete the device object until the subsequent IRP_MN_REMOVE_DEVICE request.

    ....
    ------------------------------------------------------------------

    ですので、まずは IRP_MN_SURPRISE_REMOVAL での実装を確認されてみてはいかがでしょうか?

    2011年7月27日 11:59
  • ご返答ありがとうございます。
    コード38に遭遇した方の例とても参考になります。

    IRP_MN_REMOVE_DEVICEでの解放忘ればかりに目が行っていましたが、
    それまでのアプローチ(IRP_MN_SURPRISE_REMOVAL等)の影響も考えられますね。
    ご助言ありがとうございます。

    まず、IoDetachDeviceとIoDeleteDeviceは、IRP_MN_REMOVE_DEVICEで行って
    いることは確認しました。
    他にも、関係しそうなところを調査してみます。

    逆にコード38を発生させようと、WindowsXPでリソースの解放をしないなどして
    試していますが、STOPエラーや無視され正常に動いたりとなかなかコード38を
    発生させられません。どういう判断をしているのでしょうね。

    デバイス削除時の処理の確認のほか、いろいろ試してみるしか方法はないようです。

    2011年7月28日 4:51
  • 参考(になるかどうかわからない)情報ですが。。。

    メモリ リークなどリソース解放に起因する問題との切り分けを検証したいのであれば、Driver Verifier (verifier.exe) を使えばすぐに判別できると思います。
    Driver Verifier の使用方法については、マイクロソフトの方が下記ブログで分かりやすく解説されているので、そちらを参考にされるとよいと思います。

    ------------------------------------------------------------------
    ドライバー検証ツール

    http://blogs.msdn.com/b/jpwdkblog/archive/2009/04/07/9535962.aspx
    ------------------------------------------------------------------

    Driver Verifier でエラーが検出されなかったら。。。。おそらくリソース解放に起因する問題ではないということになると思いますので、その場合は WDK に同梱されている pnpdtest ツールでの検証をお勧めします。
    WinDBG をカーネル デバッグ モードでターゲット PC に接続して pnpdtest ツールを実行すると、このテスト ツールの専用フィルタ ドライバ (pnpfiltr.sys) がデバッガ上にログを出力してくれます。
    (個人的には、このログはデバッグ解析においてかなり有効な情報であると感じています。)
    なので、問題が発生しない XP / Vista 環境と、問題が発生する 7 環境でそれぞれデバッグ ログを採取し、異なる結果となる起点がどの IRP にあるのかを見つけ出せれば、以降の調査に役立つと思います。

    すでにこれらツールをご使用されている場合は、ご容赦ください。

    2011年7月28日 8:15
  • 急な出張が入りご返答が遅れ申し訳ありません。

    WinXP DDKのVERIFIERをWinXP上で再度実行し確認しましたが、特に問題なさそうです。

    環境を揃え、Win7上で最新のWDKを使ってやってみます。

    PnP Driver Test Toolは使ったこと有りますが、pnpdtestツールは使ったことありません。

    こちらも最近のWDKのツールのようですね。

    ドキュメントなどは、最新版に目を通しましたが、WDKのツールも新しいものを使ってやってみます。

    デバイスをUSBから抜取った時のIRPは、WinXPとWin7で全く同じものが同じタイミングできていることは

    ドライバにログ出力文をいれ、DbgView(デバックログ表示ツール)で確認しました。

    またそのときのステータスなども同じでした。

    ドライバが同じ動きなのに、Win7ではインスタンスがまだ残っていると判断されるので、

    もともとリーソースの解放ができていないのにWinXPでは検知されなかっただけと推測しています。

    いろいろ解析のための情報をありがとうございます。

     

    2011年8月2日 5:58