WindowsXPでパラレルポートを自分の物に!WarmPollの回避方法
WinXPのデバイスドライバparport.sysのソースを読んで、WarmPoll機能の回避方法を考えてみました。
WarmPoll機能が動いていると、パラレルポートの制御信号などが勝手にアクセスされてしまって、自分で作ったハードウェアなどに誤った信号を出力してしまうからです。
そこで、parport.sysのソースを読んで解析した結果を、次の図に載せます。ちょっと流れ意訳しているので、微妙に違うかもしれませんが。
このWarmPoll機能は、parport.sysというデバイスドライバが起動しはじめたところから始まります。
つまり、WindowsXPの起動とともに、WarmPollは潜伏を始めると考えていいでしょう。
parport.sysの起動時にはPptFfoStartDevice()という関数が呼ばれます。
PptFfoStartDevice()関数の中では、システムレジストリ
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Parport\Parameters
を読んで、DisableWarmPollというキーがゼロ以外になっていれば、WarmPoll機能は起動されません。
したがって、レジストリにDisableWarmPoll=dword:00000001を書く、というのも一つの解決方法です。
もし、DisableWarmPollが設定されていないと、PptFfoStartDevice関数はWarmPoll用にスレッドを作成します。
そして、そのスレッドが開始します。
まず、規定の時間、待ちます。
もし、バッテリ駆動であれば、WarmPoll機能は作動せず、スレッドはループを繰り返します。
ノートPCならバッテリ駆動にするというのも、解決策の一つではないかと思います。
そして、PptTryAllocatePort()という関数を呼び出して、ポートのアクセス権を取得しようとします。
ここで、アクセス権が獲得できなければ、パラレルポートへの出力は発生しません。
次に、GetStatus()という関数を呼び出します。
この関数で、パラレルポートが接続されていないとか、ケーブルがない、と判断されれば、パラレルポートへの出力は発生しません。
もし、何かがありそうだ、ということになれば、P4ReadRawIeee1284DeviceId()という関数を呼び出します。
この、P4ReadRawIeee1284DeviceId()が、勝手にパラレルポートへアクセスして悪さを引き起こしていると考えられます。
つまり、GetStatus()で何かがある、と判断されれば、P4ReadRawIeee1284DeviceId()を呼び出して悪さをするわけです。システムが暖まったころにポーリングを始めるので、WarmPollというのではないかなと推定されます。
このP4ReadRawIeee1284DeviceIdが呼ばれないようにするためには、バッテリ駆動にするか、TimeToTerminateThreadという値を設定するか、パラレルポートのアクセス権をWarmPollに獲得されないようにするのがよいでしょう。TimeToTerminateThreadは10回失敗すればセットされますが、10回失敗するまでには1分程度かかります。
したがって、「パラレルポートのアクセス権を獲得させない」というのが、最も正解に近いのではないかと思います。
WarmPollが起動するための関数、GetStatus()では何を調べているのか、
P4ReadRawIeee1284DeviceId()は何をしているのか、
そして、WarmPollにパラレルポートのアクセス権を獲得させないようにするには、どうすればよいか、ということは次回に書きます。
| 固定リンク
コメント
WindowsXPが出たとき、私もこの問題に引っかかりました。
XPが何やらポーリングしているようだ、というのは容易に予想がついたので、
正規の手順でパラレルポートをOPENすればポーリングは止まるだろうと考えました。
つまり、CreateFile("LPT1",...)するということです。
しかし、これでは普通のパラレルポートとしてしかアクセスできないので、
私の場合はParport.sysの上にフィルタドライバを乗っけることにして、
そしてDeviceIoControl()でカスタムなオペレーションを定義し、
独自にパラレルポートのDMA転送や割り込みを制御しました。
ちょっとトリッキーかも知れませんが、そういうアプローチもある、ということで参考になれば・・・
投稿: Morizzo | 2006.02.04 15:23
>私の場合はParport.sysの上にフィルタドライバを乗っけることにして、
>そしてDeviceIoControl()でカスタムなオペレーションを定義し、
トリッキーじゃないと思います。
それが正当なやりかただと思います。
いろいろと調べて、parport.sysの中のIOCTL_INTERNAL_GET_PARALLEL_PORT_INFOをInternal IOCTLで呼び出して、TryAllocateのアドレスを調べて呼び出せばよい、というのがわかってきたので、その具体的な手順を考えているところです。
投稿: なひたふ | 2006.02.04 15:39