mydus01
謝辞
ワンセグ関係でいろいろ貢献されましたMobileHackerz様、DUS-01の仕様の詳細を公開いただいたhwhack様その他色々な情報を公開いただいた皆様、デバイスドライバ、SDK、2008Expressおよび詳細な文書を無料で公開していただいたMicrosoft様に感謝いたします。
これはなに
DUS-01ドライバです。主な特徴は以下のとうりです。
- 複数台対応(ただし、テストは2台までしか行っていません。3台以上もいけるはず。)
(32ビットでしか動作しないと思います。64ビット対応するには,ISO_PACKET_STATUS構造体x4+188x4=0x320としてストリーム取得用のバッファを作成しているので、そこを64ビット時のサイズにしてやればよいかも。)
目的
24時間ワンセグ野郎発案者がDUS-01の複数台対応に貢献するため。
わかっている不具合
DUS-01に付属しているソフトで視聴中にDUS-01を抜くとフリーズします。必ず「ハードウェアの安全な取り外し」を利用して安全に取り外せるようにしてからDUS-01を抜いてください。
オリジナルとの差異
- ファームウェアアップグレード出来ません。
- アイソクロナス転送はパケット数4、パケットサイズ188でしか行ないません。データの受け渡しは0x320サイズのバッファ決めうちです。
- 動画再生中にDUS-01を抜くとフリーズします。
- その他気づいていない際差異があるかも
開発環境
- Windows XP Home Edition
- Hard
- DELL INSPIRON 2200
- CPU: Celeron(R) M 1.40GHz
- Memory: 512M
- WDK 6001.18001
- Dbgview
ライセンス
GNU Lesser General Public License です。
この配布物によって受けるいかなる不具合にたいしていかなる保障もしません。自己責任でご利用ください。
この文書も同じライセンスとします。
行ったチェック
ツールによる確認は行っておりません。
不具合を確認できなかったテスト
- ブルースクリーンが、試用している範囲で発生しない。
- DiTUNE付属の動画再生機能で、チャンネル変更、視聴ができる。
- 視聴中にノートの蓋を閉じてスリープ状態にし、蓋を開けて起こした後、操作することで視聴可能
- DiTUNEで再生していないときにDUS-01を引きぬいても、フリーズ、ブルースクリーンが発生しない。
- 2台目のファイルハンドルが作成されたこと。(3台以上同時利用はテストしていません。)
- 2台ほぼ同時に違うチャンネルのパケット取得(20000パケット)、再生テスト。パッチをあてたmplayerで再生、再生に問題ない程度しかパケットドロップが無いことを確認。
- 20000パケットを取得し、パッチをあてたmplayerで再生、再生に問題ない程度しかパケットドロップが無いことを確認。
- パッチをあてたmplayerにデータを流し、リアルタイム再生できることを確認(20000パケット分)
3台以上の同時利用はテストしていませんが、上手く動作する可能性が高いと思います。
不具合を確認したテスト
- DiTUNEで動画再生中にDUS-01を引き抜くとフリーズする。またその際、変更してあまり時間のたっていないファイルが破損することがあった。
D0Exitにpipeリセット、データ待ちのRequestの完了、URBパケットをリセット可能にしてみる等を行ってみましたが、うまく行きません。(これらのコードは現在のソースには含まれていません。)どこでフリーズしているかも特定していません。
デバイスインターフェイス
GUIDベースの取得方法および、より簡易にインターフェイスを取得できるよう、シンボリックリンクを作成しています。
1台目から"\\\\.\\ISDBT","\\\\.\\ISDBT-1","\\\\.\\ISDBT-2"...という名前になっています。
"\\\\.\\ISDBT"はDiTUNEが使用している名前です。
アプリソフトからの利用方法
inc\public.hにインターフェイスが記載されています。
Isochronous転送関係は入力データに無関係にパケットサイズ、パケット数、バッファサイズが4,188,0x320にしています。エンドポイントも3に固定になっています。
DiTUNE付属のアプリで試聴できているので、基本的に同じコントロールが可能と思います。
2台目以降のファイルハンドルは"\\\\.\\ISDBT-1","\\\\.\\ISDBT-2"...になる用にしています。テストは2台までしか確認していません。
各DUS-01のファイルハンドルはGUIDを利用した方法でも可能です。
DiTUNE付属のアプリで動画が見れるので、同じ様な手順でIOCTLすれば利用できます。
コンパイルインストールの手順概要
バイナリは配布していないため、開発環境を入手、コンパイルインストールという手順になります。
ソースゲット、WDK入手インストール -> コンパイル -> インストール
- WDK 6001.18001を入手
- WDKとWLKの入手方法 に無料で入手できる手順が記載されています。 Microsoft Connect Web サイトに登録することでダウンロードできます。WDF coinstallerも必要になるのでダウンロードします。
- mydus01-version.zipをダウンロードし、展開する。
- Windows Driver Kits -> Wdk 6001.18001 -> Build Environments -> WindowsXP の中のFree buildを実行します。
- 立ち上がったプロンプトでmydus-01-version.zipを展開したフォルダまで移動します。(cd 等のコマンドを利用してください。)
- nmakeを実行してmydus01.sysを作成します。 うまく行けばobjfre_wxp_x86/i386フォルダが作成されmydus01.sysがそこに作成されます。
infファイルの作成をサボったため、以下の手順でKernel-Mode Driver Frameworkをインストールする必要があります。すでにインストールされている場合、この手順は不要です。
- WDF 1.7 co-installerの入手
- コンパイル準備 のWDKの入手方法と同じく WDKとWLKの入手方法 で、WDF coinstallerもダウンロードできます。これに WdfCoInstaller01007.dllが含まれていますのでダウンロードします。
- Kernel-Mode Driver Frameworのインストール
- WdfCoInstaller01007.dllはcabタイプのアーカイブですので展開し、"Microsoft Kernel-Mode Driver Framework Install-v1.7-Win2k-WinXP-Win2k3.exe"を実行しててKernel-Mode Driver Frameworkをインストールします。
WDKに付属のサンプルのkmdfフォルダーのどれかを作成してインストールするとKernel-Mode Driver Frameworkもインストールされます。こちらの方法だとアーカイブを展開する必要はありません。 (infファイルを用意して今回のドライバと同時にインストールするのが本来の方法です。)
インストール
邪道な方法でISDBT.sysを上書きしてインストールします。元のファイルはISDBT.sys.orgと言う名前で残します。これはinfファイルを作成するのが面倒だからです。 下の手順にしたがわずinfファイルを用意してインストールした方が良いでしょう。
作業は管理者権限がないと実行できません。
コンパイル方法 で示した方法でコンパイルし、mydus01.sysを作成後以下の手順を行ってください。
- mydus-01-version.zipを展開したディレクトリのINSTDRIVER.batを実行します。これはISDBT.sysをISDBT.sys.orgでバックアップし、mydus01.sysでISDBT.sysを上書きします。
- コピーできたか簡易確認します。CHECKSIZE.batを実行するとシステムのISDBT.sysのサイズ、mydus01.sysのサイズ、バックアップしたISDBT.sys.orgのサイズがdirコマンドで表示されます。うまくコピーできたときは上2つのサイズが同じになっています。
XPには自動でシステムを元に戻す機能がついているらしいので、システムの最新バックアップをコピーした状態で作成します。(これでドライバが復元されるかどうかは知りません。不必要と思われる場合は実行不要です。)
以下の手順で元に戻らなくなると思いますが確認していません。
ちなみにこのしたの作業は私は行なっていません。
- スタート->プログラム->アクセサリ->システムツール->システムの復元 を起動して復元ポイントを作成します。(ここで復元するを選ぶと元のドライバに戻される可能性があります。)
- スタート->マイコンピュータWINDOWSフォルダのあるディスク(一般にはCドライブ)を右クリックし、出てくるメニューのプロパティを選択します。「全般」タブの中の「ディスクのクリーンアップ」を押します。新しく開いたウインドウの「詳細オプションタブ」を選択します。3つ「クリーンアップ」ボタンがありますが、一番下の「システム復元」の部分のボタンを押します。これで最新の復元ポイントのみを残して古い復元ポイントが消去されます。
アンインストール
mydus01-version.zipを展開したディレクトリにあるUNINSTDRIVER.batを実行します。これでバックアップファイルISDBT.sys.orgをISDBT.sysにコピーします。
この後、インストール手順の3と4を実行したほうが良いかもしれません。
感想
マイクロソフトのソフト、文書の無償提供量質共に格段に良くなっているのに驚きました。日本語の本無しでもWDK添付の文書、サンプルのおかげで目的をほぼ達成することができました。
Linuxに完全移行してから10年近くですが、Windowsの利用時間が増えるかもしれません。
その他) ワンセグ用mplayerのコンパイル
このドライバからクリーンなTSファイルは出てこないのですが、このパッチをあてたmplayerだとTSをmp4に変換せずに生を再生できるので方法を紹介します。
- msys、mingwをインストール(インストール方法はネットで検索してください)
- zlibをダウンロード、コンパイル、インストール
- http://www.mplayerhq.hu/MPlayer/contrib/win32/dx7headers.tgz を入手して展開しmingwのインクルードディレクトリに入れます。
- mplayer-1.0r2のソースをダウンロード、アーカイブに含まれるワンセグ用のパッチ( mplayer1.0rc2_oneseg_.patch,mplayer.ad_faad.c.patch) をあててコンパイル。パッチはmplayerのソースを展開し、そのディレクトリに入って以下のコマンドを実行
patch -p1 < パッチファイル
- mplayerをコンパイル
http://www.mplayerhq.hu/MPlayer/contrib/win32/MPlayer-MinGW-Howto.txt に3までの手順が詳しく記載されています。(dx7headers.tgzのURLは上のURLに変更されています。)
再生はmplayer xxx.tsで生TSを再生できます。二ヶ国語放送は右と左ででますので、スピーカ出力でどちらを聞くか選べます。
不具合としては、コマーシャルや番組切り替え時にデータ不連続が発生すると再生できなくなることがあります。不連続発生後のデータのみをmplayerにあたえることで再生できます。
mydus01.cの主な関数の概要
- EvtDeviceAdd
- このルーチンでWdfDeviceCreateSymbolicLink関数でファイルハンドル名にシンボリックリンク(1台目から"\\\\.\\ISDBT","\\\\.\\ISDBT-1","\\\\.\\ISDBT-2"...)をはっています。アプリ側で他のドライバとの名前衝突をより避けるためにはこの名前を利用せずに、GUIDを利用したファイルハンドル取得方法を利用た方が良い。
- EvtIoDeviceControl
- IOCTL関係の処理を行なっています。
- EvtRequestBulkWriteCompletionRoutine
- Asyncバルク書き込み完了用ルーチン
- EvtRequestBulkReadCompletionRoutine
- Asyncバルク読み込み完了用ルーチン
- StartAsyncISOTransfer
- 連続的にIsochronous転送を行なうルーチン
- AsyncISOTransfer
- 個々のIsochronous転送リクエスト作成ルーチン
- AsyncISOTransferCompletionRoutine
- Isochronous転送完了処理用ルーチン
- setUpUrb
- Isochronous用URBのデータ作成するルーチン
- CreateUrb_Buffer
- 連続Isochronous転送を行なう用URBとBufferのメモリ確保、初期データセット
- waitFillingData
- 連続Isochronous転送のデータがバッファにたまるまで待つルーチン
- endRequest
- waitFillingDataで待ったあとRequestを完了させるルーチン
作業履歴
醜いソースなので、以下を参考に見ていただければ、多少はソースが理解いただけるかも。
- デバイスドライバを作成するツールの入手
- 昔はDDKと呼ばれていたが現在はWDKと言う名称。最新版は登録することで無料で入手可能。WinDbgがデバッガだが高機能で使うのが難しそうだったので、日本語サイトでしったDbgviewをインストール。その他多数のソフトをダウンロードインストール。
- WinUSBで何ができるか確認
- USBのユーザースペース開発はWinUSBというもので可能であることを知る。確認したところDUS-01で必要なisochronous転送に対応していない。
- Isochronous転送できるドライバのタイプ確認
- カーネルタイプのみが可能である事を確認
- ネットでの情報収集
- ほとんど有用な情報を得ることはできなかった。WDKに付属している例と文書がもっとも優れた情報源であることを確認した。
- WDK添付の文書を読む
- 途中で疲れてくる。WDFが最新のデバイスドライバのフレームワークであることを知る。そして、それを利用すれば劇的にコード量が減ることを知る。
- WDKに含まれるサンプルを調べる
- USBに関するサンプルを見て、必要なインターフェイスを確認。
- 実際にコンパイルしてみる
- Hello Worldを書いてコンパイル。こうなると動かしてみたい。
- devconでデバイスドライバのインストールができると勘違い
- devconではできない?らしい。でも有用な機能を確認。
- 動かしてみる
- 見てるだけではよくわからないため。Hello Worldを書いて動かしてみる。なぜか動かないWdfCoInstaller01007.dllでWdfのKMDFがインストールされていなかったのが原因。
- 楽なテスト方法を発見
- ドライバ訂正→ドライバファイルを新しいファイルで上書き→USBデバイス抜き差しで再起動なしで新しいドライバのテストが可能であることを確認。(でもブルースクリーンになる可能性が高いので画期的とまではいきませんが、かなり楽になりました。)
- WinDbgを使おうとする
- 途中で断念。1台でも利用可能らしいが、2台利用が通常らしい。
- 機能追加テストの繰り返し
- 小さな機能を足しながら、テスト。メモリ不正使用のブルースクリーンの嵐
- バルク転送機能追加
- バルク転送でDUS-01のバージョン、シリアル番号等の取得を行う。
- Isochronous転送用の関数の調査
- 後はIsochronous転送だけなので、Isochronous転送のインターフェイス関数を確認するため、サンプルを見て、予想している高水準のインターフェイス関数が無く、urbと呼ばれるもので転送する必要があることを知る。
- Isochronous転送に成功
- DUS-01のパケットはパケット数4,パケットサイズ188bytesと調べていたので、それに合うパケットを送信してデータの取得に成功する。
- ストリーム連続取得テスト
- IOCTLがきてから、Isochronous転送用のurbを作成して転送する様にプログラムし、簡易ストリームゲットするテストプログラムでデータを取得し、かなりパケット落ちしていることに気づく。
- URBのASAPフラグ
- ネットで検索するとurbのASAPフラグを立てて転送するとパケット落ちしやすいとの記述を見つけて、フレームナンバーを調べて開始フレームナンバーを指定するように変更し、簡易プログラムでパケット落ちがほとんどなくなった。
- mplayer
- ワンセグ用にパッチをあてたmplayerでリアルタイム再生を試みるが、現在のマシンでは正常に再生できなかった。
- DiTUNE用のIOCTL
- IOCTLは独自インターフェイスだったが、公開されているソフトのソースからこれらの番号を得て、DiTUNEでも動作する様に改造、DiTUNEソフトを立ち上げるも、フレームドロップが原因と思われる不具合で正常に再生できない。
- 性能向上1
- ソフトの軽量化をはかりISOTの部分を軽量化、しかしフレームドロップは減るものの安定再生できない。
- 元のURBを調査
- 元のドライバのURBを調べるが、不利と思われるASAPを利用していることを確認。データ取得のバッファを2つ持っており交互に利用している模様。ASAPの方が良いかと変更するとより悪い結果になる。
- 性能向上2
- urb様のメモリを先に確保する様に改造するも、かなり改善されるが、正常に再生できない。
- libusb-win32に浮気
- ダウンロードしてヘッダを見るとisochronous用の関数を発見。多分できると思われる。しかし、簡単なソフトを作成してみると、ISOのレスポンスが悪く、見切りをつける。
- 性能向上3(空振り)
- IOCTLの種類がバッファタイプであることに気づき、ダイレクトタイプに変更するが、DiTUNEで利用している番号はすでにダイレクトタイプであった。
- 性能向上4(空振り)
- タイマで定期的にデータを取得するようにしようとしたが、タイマの間隔が16.6msec程度までしか小さくできず、これではデータ取りこぼしが多発しそうなので、この案を廃棄。
- 性能向上5
- データ転送用のバッファをたくさん用意してそこに順次転送していくようにし、IOCTLでのデータ読み出しはバッファからの転送のみにした。バッファにデータが無いときはエラーをかえす様にした。バッファの数はBNUMで決めている。
- 手直し1
- DiTUNEで再生できなくなった。ドライバのデバッグ用のデータから、バッファにデータが無いときにエラーを出すと、最初から手順をやりなおし、ストリームデータを取らない仕様らしい。
- 手直し2
- バッファにデータが無いときにSleepさせようとするが、ドキュメントにカーネルドライバで利用できるコマンドにそれに該当するコマンドを見つけだせない。仕方が無いので、WDFに付属のタイマー(WdfTimer)を利用してまたせることにした。(ループで待たせると処理が重くなるので)
- 初めてのまともな再生
- 初めてまともにDiTUNEのソフトで動画を再生できた。しかし、タイマーが16.6msec程度であることや、データが準備できたら、アプリにデータを送りたいと考え、さらに改造。WdfCollectionオブジェクトにデータまちのRequestをためて、データが来たら、その待ちがあるか確認するように改造。
- 色々テスト
- 再生中にいきなりDUS-01を抜くとフリーズ。URBのRequestをキャンセル可能にしていないのが原因かも。ノートを閉じてスリープにしてから復帰後、停止再生を押せば再生可能。
- 駄目
- 突然抜きに対応するためURBのRequestをキャンセル可能にしてテストするも駄目。URB関係のParent ObjectをUsbDeviceからDeviceに変更したけどやはり駄目。D0Exitでpipeをリセットしてみたけど駄目。
- 再度mplayerで再生できるかテスト
- パッチをあてたmplayerにデータを流し、リアルタイム再生できることを確認(20000パケット分) オプションは -tsprobe 65536 -cache 2048 - をつけた。