hatena by 917mMF

VIEWS: 173 PAGES: 38

									連射ドライバの開発

     maki
自己紹介
HANDLE maki
  = EmbeddedSoftwareEngineer
    (組み込みソフトウェアエンジニア);
   ↑ error C2018: 文字 '0x81' は認識できません。
web/blog
   はてな
       http://d.hatena.ne.jp/firewood/
   twitter
       http://twitter.com/hotpepsi/
   ソフトウェア置き場
       http://www.d9.dion.ne.jp/~nejimaki/arch/
       HTTP proxy(yappa)ほか小物
開発の動機
   弟に頼まれた
    「こいつで連射
    できるようにして
    くれ」

「わかった(mjs
k」
               JOP-U234 \1,330
ジョイパッド(ジョイステック)
   USBで標準化されている
       HID(Human Interface Device)クラス
       追加ドライバ不要(Windows 98以降)
       DirectX(DirectInput)でサポート
   入出力
       ボタン
       軸(デジタルまたはアナログの方向検出)
       振動
既存の連射機能
   ジョイパッド自体が連射機能を持つもの
       JOYBALL(HAL研究所)
   連射機能だけ付加するハードウェア
       連射まんまミーヤ!
   付属のドライバで連射機能を付与するもの
       ELECOM製JC-PSxxx
           他社製品では使用不可能
           多機能だがCore2Duo機だとBSoD
既存の連射ソフトウェア
   HID入力を連射させるもの
       どうやら汎用のものは存在しない
   JoyToKeyが最もメジャー
       ジョイパッド→キー入力変換
       連射も可能
           ただし連射されるのはキー入力


        → とりあえず作ってみることに
連射するということ
   押しっぱなし or 押してないのに入力発生
    → 擬似入力を発生させる必要がある
   キーボードやマウスの場合
       SendInputで擬似的に発生可能
   HIDにはお手軽関数がない

    → いわゆる「フック」をすればいい
フック=入出力の横取り
ユーザーアプリケーション                                 ユ
                                             ー
                                             ザ
                            dinput.dllを横取り   ー
                            (APIフック)         空
DirectInput(dinput.dll)                      間




                                             ← →
                          hidclass.sysを横取り
                                             カ
  HIDクラスドライバ              (フィルタドライバ)
                                             ー
  (hidclass.sys)                             ネ
                             ↑ 今回はこれ         ル
ぐぐる
   同好の士を発見 (T-MZさん)
ソースをもらう
   HIDまわりはぐぐっても情報が出てこない
       HidP_GetButtonCapsの使い方とか
       カーネルとユーザー空間でほぼ同じ関数が用
        意されている
   工数の80%を削減(当社比)
できたー
   連射速度を測定するソフトも作成
   Windows2000上で32打/secを達成

                       2.0TM
                         ↑
                      2 高橋名人
ドライバ開発
   ここから本題
ドライバの世代 (framework)
   NTドライバ
       NTなのにold type
   WDM(Windows Driver Model)
       Windows 98で導入
   KMDF(Kernel Mode Driver Framework)
       WDMより簡単にドライバが書ける…らしい
   UMDF(User Mode Driver Framework)
       ユーザーモードのデバイスドライバ
ドライバの種類
   Bus driver
       PCIバスやUSBのドライバ
   Class driver
       HIDやビデオキャプチャなど、基本機能を提供
   Function driver
       個別のデバイスに対応したドライバ
   Filter driver
       必要な機能だけを実装したドライバ
ドライバの種類(2)
   Display driver
       XPDM(Windows XP Display Driver Model)
       WDDM(Windows Vista Display Driver
        Model)
   Mirror driver
       ディスプレイの出力を転送するためのドライバ
   File System Driver(FSD)
       NTFS、FAT、CDFS
driver layers




                                         User
                                         ←

                                         →




                                         Kernel
                        filter
                        driver    FiDO

   NT       driver     function
                        driver    FDO
  driver    object
                         bus
                        driver    PDO


    HAL(Hardware Abstraction Layer)
difficulty levels
   very difficult
       display driver
       file system driver
   difficult
       mirror driver
       FSD filter driver
   not difficult
       I/O filter driver
連射ドライバの場合
   「HID準拠ゲームコントローラ」
       挿すとデバイスマネージャに表示され、抜くと
        消える
           Plug&Playに対応している=WDM
       ジョイパッドのFDO
   WDM形式のフィルタドライバを作成する必
    要がある
用意するもの
   WDK(Windows Driver Kit)
       またはWindows DDK(旧バージョン)
       これでアプリ開発もできます
   Debugging Tools for Windows
       WinDbg
   VMware
       または落ちてもいいマシン
最も簡単なフィルタドライバ
   kbfiltr
       DDK/WDKのキーボード用のサンプル
       infファイルも付属
   moufiltr
       DDK/WDKのマウス用のサンプル
   ただしWDMではない
WDMドライバ
   toaster
       DDK/WDKにあるサンプル
       toasterという架空のバスのドライバ一式
   firefly
       DDK/WDKにあるサンプル
       マウスのフィルタドライバの例
WDMに対応させる
   AddDeviceエントリを追加
       デバイスが追加されたときに呼び出される
       NTドライバの場合はシステムの開始時か、あ
        るいは相当の処理を自前で行っていた
   Plug & Play要求に対応させる
   Power management要求に対応させる

    → ひながたがあると改造で何とかなる
infファイル
   やっかいなしろもの
   とりあえず版として、標準のドライバを置き
    換える(サンプルがそうなっている)
   「元のドライバ+フィルタドライバをインス
    トールせよ」という指示内容になっているた
    め、結果的にフィルタドライバを追加するこ
    とができる
   現状だとアンインストールができない
連射部分
   ユーザーランド側から常にpollingしている
    ことが判明
       自前でタイマーを用意しなくてよい
   通常は読み取り要求をデバイスに送信し、
    読み取り完了を待ち、返答する
   読み取り完了を横取りし、ボタンが押され
    たままであれば状態をトグルさせて返すこ
    とで連射を実現することにした
連射部分のソース
NTSTATUS GPAF_ReadHandler(PDEVICE_EXTENSION extension, PIRP Irp,
     PIO_STACK_LOCATION IrpStack ) {
   PAGED_CODE();
   IoCopyCurrentIrpStackLocationToNext( Irp );
   IoSetCompletionRoutine(Irp, ReadCompleteCallback, NULL, TRUE, TRUE, TRUE);
   IoMarkIrpPending( Irp );
   IoCallDriver( extension->NextLowerDriver, Irp );
   return STATUS_PENDING;
}
static NTSTATUS ReadCompleteCallback(PDEVICE_OBJECT DeviceObject, PIRP Irp,
     PVOID Context ) {
   PDEVICE_EXTENSION extension = GetDeviceExtension(DeviceObject);
   GPAF_ToggleButtons( extension, Irp );
   IoReleaseRemoveLock( &extension->RemoveLock, Irp );
   if ( Irp->PendingReturned ) {
       IoMarkIrpPending( Irp );
   }
   return Irp->IoStatus.Status;
}
連射の制御
   IOCTLを追加(ボタンの配置変更と連射速度)
NTSTATUS GPAF_IoCtlHandler(PDEVICE_EXTENSION extension, PIRP Irp,
   PIO_STACK_LOCATION IrpStack ) {
  NTSTATUS status;
  int input_len = IrpStack->Parameters.DeviceIoControl.InputBufferLength;
  PAGED_CODE();
  switch ( IrpStack->Parameters.DeviceIoControl.IoControlCode ) {
     case IOCTL_GPAF_SET_BUTTON:
         { IOCTL_GPAF_SET_BUTTON_PARAM *param =
            (IOCTL_GPAF_SET_BUTTON_PARAM *)Irp-
   >AssociatedIrp.SystemBuffer;
         extension->ButtonMap[param->number] = param->remap;
         extension->AutoFireRate[param->number] = (1 << param->rate) - 1;
         status = STATUS_SUCCESS; }
         break;
連射の設定アプリケーション
   IOCTLを発行するアプリケーションを用意
あとはひたすらデバッグ
   コーディングより時間がかかる
       なぜ動かないのかさっぱりわからない
       止まったらいちいち再起動
DbgPrint
   カーネルで使えるデバッグ出力
   Win32APIのOutputDebugStringと同じI/F
       SysInternalsのDbgViewが使える
       ドライバだけでなく、アプリケーションのデバッ
        グ出力も見えてしまう
   XPでDbgPrintExが追加された
   Vistaではモジュールとレベルを適切に設
    定して出力する必要がある
可変出力
typedef NTSTATUS DBG_PRINT_EX(ULONG, ULONG, PCCH, ...);
void my_dbg_print(const char *message, ...) {
   static DBG_PRINT_EX *_DbgPrintEx = NULL;
   UCHAR buffer[4000];
   va_list params;
   if ( IoIsWdmVersionAvailable( 1, 0x20 ) ) { // Windows XP and later
       RtlInitUnicodeString( &Name, L"DbgPrintEx" );
       _DbgPrintEx = MmGetSystemRoutineAddress( &Name );
   }
   va_start( params, message);
   RtlStringCbVPrintfA(buffer, sizeof(buffer), message, params);
   va_end( params );
   if ( _DbgPrintEx != NULL ) {
       _DbgPrintEx( DPFLTR_DEFAULT_ID, DPFLTR_ERROR_LEVEL, "%s", buffer );
   } else {
       DbgPrint( "%s", buffer );
   }
}
ターゲット側の設定変更
   boot.iniを編集してデバッグモードにする
       multi(0)disk(0)rdisk(0)partition(1)\WINNT="Windows 2000 Professional"
        /fastdetect /debug /debugport=com1 /baudrate=38400
VMwareのシリアルポート
   名前つきパイプに接続
WinDbgの設定
   VMwareがnamed pipeのサーバ側なので、
    仮想マシンを起動してからWinDbgを起動
    する
デバッグモードで起動
DbgPrintの問題点
   デバッガを接続していると出力が完了する
    までにmsオーダーで時間がかかるため、
    それによる副作用が心配
   VMwareから接続時、休止状態にするとデ
    バッガとの接続が切れてしまう
DbgPrintの代替
   デバッグ出力をIOCTL経由にしてみた
そんなわけで
   まだデバッグ終わってません

								
To top