2006年8月の日記


2006/08/27

#1 連射ドライバの開発(9)

ドライバ側の全機能の実装完了。今回はアプリからのIOCTLでレジストリの設定値を再読み込みするようにした。でも、いまだにブルースクリーン(DRIVER_LEFT_LOCKED_PAGES_IN_PROCESS)の原因が分からず。READ要求をキャンセルしたりしたときになるのはともかく、普通に動いてる最中にもこれが出るのが謎。ブルースクリーン自体はカーネル本体の処理なので、デバッガをつないでみたけど大した情報は得られない。READのキャンセル処理、IRP_MJ_CLEANUPの処理、ファイルオブジェクトの管理などが怪しそうなので、ここを見直す予定。

2006/08/24

#1 連射ドライバの開発(8)

今回はデバイス接続時にレジストリから設定値を読んで、ボタンごとに連射周期を変えられるようにした。大変だったのがUnicodeの取り扱い。レジストリのアクセスのためにUnicodeが必須なんだけど、これがひたすらめんどくさい。当初は文字を探して処理をしようと思ってたんだけど、DDKの標準関数で簡単にできる範囲だと、char用のstrcpyとstrcatとstrlen相当の処理ぐらいが限界(それぞれ、RtlStringCbCopyW, RtlStringCbCatW, RtlStringCbLengthWが相当)。charと違って1バイトずつ比較しても比較できないので、検索も大変。なので、このあたりのAPIだけでできる範囲で実装した。関連して苦労したのが、UNICODE_STRING型の取り扱い。DDKのヘルプを見るとRtlInitUnicodeString()で初期化しないといけないみたいなんだけど、このとき指定できるSourceStringは、WCHAR hoge[10]みたいにコンパイル時に固定で確保した領域に対しては、UNICODE_STRINGの最大バッファサイズが期待通り設定されない。どうしようかと思ったけど、多分隠しマクロであるRtlInitEmptyUnicodeString()を使えばいい(ntddk.hやwdm.hに定義されてる)。

2006/08/19

#1 連射ドライバの開発(7)

連射部分の基本機能が動くようになった。ボタンごとにカーネルタイマーを作って動かしてる(最終的にはボタンごとに速度を変えられるようにするつもりなので)。最初は2秒周期で開発してたけど、試しに20ms周期でON→OFF→ONするようにして動かしてみた。jstestを使って測定してみると、こんな感じ。大体毎秒30回ぐらい。とはいっても、VMwareの仮想マシン上だったり、デバッグ用シリアルポート出力が有効のままだったり、マルチCPU用の排他制御をしてなかったりと、まだパフォーマンスに影響を与える要素は多いので最終的にはどうなるか不明。ただ、現状でもボタンのON/OFFが切り替わった瞬間にユーザ空間から読みに来てなくて通知できてないってことも結構起きてるので、ドライバ側でできる処理はほぼ限界の気がする。

ちなみに、現状の制限事項は、全ボタン連射速度固定、全ボタン連射有効(無効にできない)、何もしてないのにブルースクリーンになることがある、パッドをつないだままサスペンドやOS終了しようとすると必ずブルースクリーンになる、マルチCPU非対応(多分ブルースクリーンで落ちる)、ってとこかな。要するに全く使い物にはならないし、少なくとも自分が普段使ってる環境には絶対インストールしたくない。

しかし、当初はたかがちょっと機能をいじるだけのフィルタドライバだと思ってなめてかかってたけど、ここに到達するまででもかなりドライバ開発の知識が必要だった。この先はユーザ空間とのやり取りの部分の開発が中心になると思うけど、それでもまだ知識は不足気味。

2006/08/18

#1 連射ドライバの開発(6)

ボタンの入力値の取得方法が分かった。IRP_MJ_READ がユーザ空間から送り込まれてきたとき、ターゲットドライバのディスパッチルーチンで完了ルーチンを設定しとく。そうするとHIDクラスドライバのIRP完了ルーチンのあとにターゲットドライバの完了ルーチンにくるんだけど、このときのMDLにInputReportのデータが入ってる。サイズはcurrentIrpStack->Parameters.Read.Lengthで、カーネルモードの仮想アドレスはMmGetMdlVirtualAddress(Irp->MdlAddress)で取得可能。で、memcpyが使えればいいんだけど、使えないよね?まぁ、とりあえず今使ってるパッドは5バイトだからループを回して1バイトずつコピーしとくか、と思ったけど、RtlCopyMemory()でいけるみたいだ。これで、ボタンを入れ替えたり反転したりするドライバは作れるレベルに到達。コンパネのゲームパッドの画面を開いてる感じでは、IRP_MJ_READは定期的に来るわけではなく、ボタン状態に変化があったときだけ来てるようだ。IRP完了を受けるとすぐに次のMJ_READを発行してるっぽい。

それにしても、WinDbgは使いにくいなぁ。コマンドがさっぱりわかんないので毎回ヘルプを調べないといけないのはともかく、なんで変数の構造体の中身を名前で追っていけないんだよ。gdbが使えれば簡単に追っていけるのになぁ。

ターゲットドライバでやるべきことが明確になったので、ようやく設計に着手。

#2 虫刺され

気がついたら右腕だけに4箇所も虫刺されの跡が。なんで右腕だけ狙われるんだ。

2006/08/16

#1 特定疾患の継続申請

なんでお役所ってこうも融通利かないかなぁ。特定疾患の自己負担額は前年の所得と世帯の中心生計者かどうかで変わるんだけど、「証明の提出の無い場合は区分Gになります」(区分G:一番負担額が高い)って書いてあって、はっきり言って普通に働いてる人だと区分Gになるぐらいのラインなので、どうせ出してもGだから出さなくてもいいのか、と思って継続申請のときに出さなかった。ところが、後で電話がかかってきて出さないなら代わりに出さない旨の用紙を出してもらわないといけないと言われた。で、用紙を送ってもらってよく見てみると、「区分Gかつ非生計中心者」になることに了解します、って内容が書かれてる。一人世帯なんだから非生計中心者になりようがないだろ。それにそんなこと最初の申請用紙に書いてなかったのに。しょうがないのでまた保健所に行ってきた。来年からはおとなしく最初から所得証明も出そうと思った。

2006/08/12

#1 連射ドライバの開発(5)

ついに悪影響を与えずにHIDデバイス上位へのフィルタドライバ組み込みに成功。コンパネのGamepadのプロパティで動作するようになった。前回、一部のDEVICE_CONTROLでエラーが出てたのは相変わらずなので、多分放置しといても問題なさそう。コンパネのテスト画面を開いてるときにOPEN→CLOSEが頻繁に繰り返されてるのも変わらない。これまでうまくいかなかった原因は、

pdo->Flags |= DO_BUFFERED_IO;

ってのがIoCreateDeviceの後に入っててフラグ強制ONしてたため。多分HIDの情報はバッファされないんだろうな。正しい処理は、IoAttachDeviceToDeviceStack()で得た下位デバイスのFlagsの該当フラグを反映させること。もうひとつ、IoInitializeRemoveLock()を呼ばずにIoAcquireRemoveLock()とIoReleaseRemoveLock()を呼び出してブルースクリーンになってたのでこれも修正。

まだ電源関連の通知とかは処理してないので、パッド接続したままサスペンドしたり再起動するとブルーバックになるけど、これはとりあえず後回し。

HIDデバイス用のフィルタドライバの情報は全くといっていいほど見つからないので、ここまでのまとめ。まず、WDMデバイスドライバWDMプログラミングは手元にほしい。(1)普通のデバイスはAddDeviceルーチンでIoCreateDevice()とかの初期化処理をするけど、HIDデバイスではPnPの通知の中で行う必要がある(HIDデバイス全ての面倒を見るのではなく、特定のデバイスのみを対象にするため)。WDMデバイスドライバの23-4 カーネルモードのHIDクライアントの項目参照。IoRegisterPlugPlayNotification()でコールバック設定をしとけばOK。

(2)DriverEntryでAddDeviceへの関数ポインタを設定しないこと。たぶんHIDフィルタドライバではデフォルトの処理が走ってくれたほうが都合がいい。

(3)これ以外は普通のフィルタドライバと同じ。WDMプログラミングなんかを参考に。

(4)infでインストール用のファイルを作る場合、ClassはHID、LoadOrderGroupは"PnP Filter"にすればいい。inf以外の方法は不明。

これでようやくスタート地点に立てた感じ。

2006/08/02

#1 BBSのブロック強化

最近、毎日のようにBBSに宣伝書き込みが。毎日消すのもめんどくさいので、NGワードを設定できるようにスクリプトを改造。これで多少はマシになるか。


count: [an error occurred while processing this directive]

ごみ的ページ。のインデックスに戻る