Posts filed under 'BSP'

OS の部分アップデート方策~その2(2/2)

前回のエントリでは、ファイルシステム用の永続記憶域を使った部分アップデートの方法を紹介しました。今回は、ROM イメージを複数に分割する方式の部分アップデートについて紹介します。

最初に断っておきますが、この方法は、WinCE/WEC の OS Design のコンフィグレーションでは対応できません。カーネル移植レイヤ(OAL)とブートローダのカスタマイズが必要です。

■複数の ROM イメージ(Multiple Region)
ROM イメージを複数に分割する仕組みは、もともと、WinCE/WEC のカーネルと Platform Builder 内蔵の ROM イメージ生成コマンド(makeimg.exe, romimage.exe)に組み込まれています。ただし、それを有効にするためには、OAL とブートローダが、複数に分割された ROM イメージに対応する必要があるのです。この対応は、必須ではないため、全ての BSP が対応しているわけではありません。対応していない BSP の場合は、OAL とブートローダの実装にカスタマイズを加えなければいけない、というわけです。

複数に分割された ROM イメージに対応した OAL とブートローダは、それぞれ、次の機能を持ちます。

・OAL
 ブートローダが Flash メモリなどから RAM にロードした(XIP の場合は、NOR Flash 上の)、複数に分割された ROM イメージのリストを、カーネルに伝える。この通知は、OAL の初期化時に(つまり、OEMInit() の中で)OEMRomChain を構築することで行う。

・ブートローダ
 Flash メモリなどから、複数に分割された ROM イメージを RAM へロードする(XIP の場合は、ロードしない)。また、ROM イメージをホスト(開発用 PC)から転送された時は、分割された ROM イメージを各々認識し、それらを、Flash メモリなどに書き込む。

ここで、「分割された ROM イメージ」というのは、ROM イメージファイルを単純に分割したものでは、ありません。「分割された ROM イメージ」の一つ一つは、それぞれが ROM イメージのヘッダを持っていて、個別の ROM イメージとなっています。これらを、region と呼びます。どのように region を構成するのかは、config.bib で設定します。makeimg.exe は、config.bib で複数の region が設定されていれば、それに従って、region ごとに ROM イメージファイル(.bin)を生成するのです。

複数の region を WinCE/WEC カーネルに認識させるために、OAL は、初期化時に region のリストを構築します。このリストが、上で述べた OEMRomChain です。OEMRomChain は、ROMChain_t 構造体のリストで、カーネルのスタートアップルーチンによって、スタートアップルーチンが所属する ROM イメージを指すように初期化されます。つまり、デフォルトでは、region が一つだけとなります。その後、スタートアップルーチンが OAL の OEMInit() を呼び出し、OEMInit() が、OEMRomChain に複数の region を登録する(OEMRomChain を初期化し直す)というわけです。

より正確には、OEMInit() が OEMRomChain をどう構築するかは、OAL における OEMInit() の実装次第です。カーネルのスタートアップルーチンは、OEMInit() を呼び出した後、OEMRomChain の内容をチェックして、自身が所属する region が登録されていない場合には、自身が所属する region を OEMRomChain の末尾に連結します。

ROMChain_t 構造体の説明は、WinCE 6.0/WEC 7 のリファレンスの、次のページをご覧ください:

 OEMRomChain
 http://msdn.microsoft.com/en-US/library/ee479246(v=WinEmbedded.60).aspx
 http://msdn.microsoft.com/en-US/library/ee479246.aspx

■Region ごとの部分アップデート
複数の ROM イメージ(Multiple Region)を使うと、部分アップデートする対象(アプリケーションなど)を収録した ROM イメージと、OS 本体を収録した ROM イメージを分けることができます。そして、ブートローダが対応していれば、アップデートしたい ROM イメージ(region)だけをブートローダへ転送し、書き換えることができます。これが、ROM イメージファイルを複数に分割する方式の部分アップデートです。

この方法の利点は、次の通りです:

・永続記憶域上にルートファイルシステムを構築する必要がないため、より耐障害性が高い。
・OS イメージ中の全てのファイルを、アップデートすることが可能。

ここで、「OS イメージ中の全てのファイルをアップデート可能」というのは、ROM イメージの Region 間で shadowing が作用することによるものです。つまり、二つの region に同じファイルが収録されている場合、上述した OEMRomChain のリストにおいて、より先頭に近い方の region 内のファイルが優先され、その後ろにある region 内のファイルが隠されるのです。

OEMRomChain の region 間での shadowin は、前回紹介した、ルートファイルシステム上のファイルによる ROM イメージ内のファイルの shadowing の仕組みと、本質的には同じものです。どちらも、FSD Manager と、カーネルのローダーによって実現されています。前回、カーネルのローダーが、OpenExecutable() から OpenFileFromFilesys() と OpenFileFromROM() を呼び出し、先に呼び出す OpenFileFromFilesys() で executable ファイル(.exe または .dll)が見つかれば、そちらを優先する、と説明しました。実は、OEMRomChain に複数の region が登録されている場合、OpenFileFromROM() は、OEMRomChain のリスト(つまり、region のリスト)を先頭から順に辿り、最初に見つかったファイルをオープンします。従って、よりリストの先頭に近い region 内のファイルが優先される、というわけです。

たとえば、OS 本体を収録した region(※この region に、カーネルのスタートアップルーチンが含まれます)と部分アップデートする対象を収録した region の二つがある場合について考えましょう。OEMRomChain のリストを構築する際、OS 本体を収録した region がリストの末尾要素となり、部分アップデートする対象を収録した region がリストの先頭要素となるようにすれば、両者に同じファイルが存在する場合、部分アップデート対象を収録した region 内のファイルが優先されます。このため、OS 本体を収録した region に収録したデバイスドライバなどをアップデートする際に、その region を書き換える代わりに、部分アップデート用の region の ROM イメージにアップデートしたいファイルを追加して、部分アップデート用の region だけを書き換える、という方策が可能です。

OS 本体を収録した region のサイズが、部分アップデートする対象を収録した region のサイズよりも、ずっと大きければ、小さい方の region(つまり、部分アップデートする対象を収録した region)の方を書き換える方が、より小さなコストで済みます。

部分アップデート用に、複数の ROM イメージ、つまり region の分割を行う方策としては、region を二つに分ける以外に、次のように、四つの region を設定する方策も考えられます(どちらかといえば、極端な例ですが):

 - NK: OS 本体を収録
 - EXT: デバイス固有(BSP 固有)のデバイスドライバやアプリケーションなどを収録
 - UNK: NK region 内のファイルの更新版を収録する(※出荷時は空)
 - UEXT: EXT region 内のファイルの更新版を収録する(※出荷時は空)

このように region を設定すれば、OS 本体(WinCE/WEC のカーネル及び、標準のデバイスドライバやアプリケーション、API の DLL など)と、デバイス(あなたが開発する製品)固有のドライバやアプリケーションを、それぞれ独立してアップデートできます。OS 本体用の ROM イメージと、デバイス固有の ROM イメージは、全体的なアップデートが必要となれば、各々の region(NK, EXT)を書き換えればよいですし、特定のファイルだけをアップデートしたい場合は、各々の部分アップデート用の region(UNK, UEXT)を書き換えればよい、というわけです。

WinCE/WEC は、月例アップデートが公開されます。もし、出荷後に重要な修正がリリースされた場合は、その修正を、出荷済みの製品の OS に反映しなければならないこともあるでしょう。そのような場合に、上の例のような region 分割を設定しておくと、OS 本体の ROM イメージを全て書き換えなくても、修正が加わった .dll や .exe を収録した、部分アップデートの ROM イメージを作り(そのイメージサイズは、OS 本体の ROM イメージに比べて、非常に小さいでしょう)、対応する region を書き換えることでアップデートできます。なお、部分アップデートを繰り返す場合、部分アップデートの ROM イメージには、最新のアップデート対象の .exe や .dll に加えて、以前の部分アップデートの際に収録した .exe や .dll も収録しなければならないことに注意して下さい。そうしなければ、部分アップデートした際に、以前の部分アップデートの内容が消えてしまうからです。

ところで、もし、部分アップデートを繰り返した結果、アップデート対象のファイルが累積して、部分アップデートの ROM イメージが大きくなった場合は、古い部分アップデート内容を破棄して、全体をアップデートする必要が生じる場合も、あると思います。つまり、上の例で言うと、UNK または UEXT region に収録するファイルが増えた場合は、それらの region を空にして、代わりに、NK または EXT region を作り直し、そちらを書き換える必要が生じるでしょう。もちろん、どのように region を分割し、部分アップデートを行うかということは、ケースバイケースですよね。

■Region 分割の手順
ここまでで、ROM イメージを複数に分割する方式の部分アップデートについて、その仕組みと、部分アップデートの方策について説明しました。残りは、実際の手順です。

複数の region に分割した ROM イメージを作成する手順の例は、WinCE 6.0 のリファレンスに載っています。現時点では、WEC 7 のリファレンスには対応するページが見当たりません。

 How to Create a Run-Time Image with Multiple XIP Regions
 http://msdn.microsoft.com/en-US/library/ee482739.aspx

このページでは、CEPC の場合の手順が載っていますが、他のボード(デバイス)の場合も、基本的には同じです。必要な作業を簡単にまとめると、次の通りです:

・config.bib ファイルの MEMORY セクションの記述を書き換える。その際、環境変数 IMGMULTIBIN に対する条件分岐を書き加えて、複数 region 対応するかどうかを、環境変数(IMGMULTIBIN)の設定有無で切り換えできるようにすると便利。
 複数 region 対応用の MEMORY セクションには、NK の他に定義する region を、RAMIMAGE 型の memory region として設定する。また、それらの region の連結内容を記録するための CHAIN region を、RESERVED の memory region として設定する。
 http://msdn.microsoft.com/en-US/library/ee482800.aspx (Modifying the Binary Image Builder Files)

・platform.bib ファイルの MODULES または FILES セクションに、NK 以外の region に収録するファイルを記述する。
 BSP 固有のデバイスドライバやアプリケーションなどを、NK 以外の region に収録する場合は、環境変数 IMGMULTIBIN に対する条件分岐を書き加えて、複数 region 対応の場合のみ、当該 region(「Region ごとの部分アップデート」で示した例で言えば、EXT region)を指定する。
 http://msdn.microsoft.com/en-US/library/ee482800.aspx (Modifying the Binary Image Builder Files)

・OS イメージをビルドする。

・ビルドしてできた .bin ファイルのうち、chain.bib を、Platform Builder から WinCE/WEC デバイスへ転送するファイルとして設定する。
 デバイスへ転送するファイルは、Platform Builder のプロパティダイアログで設定できる。Platform Builder の「プロジェクト」 > 「プロパティ」メニューで、プロジェクトのプロパティダイアログを開き、左側にあるツリービューから、「構成プロパティ」 > 「全般」を選択して表示される画面の、「デバッガ用のターゲットファイル名」というラベルのドロップダウンリストで、転送したい .bin ファイルを選択する。
 http://msdn.microsoft.com/en-US/library/ee482967.aspx (Building the Run-Time Image and Opening a Workspace with Multiple XIP Regions)

以上が、複数の region に分割した ROM イメージを作成して、WinCE/WEC デバイスのブートローダへ転送するために、Platform Builder で行う手順です。なお、上の最後のページ(“Building the Run-Time Image and Opening a Workspace with Multiple XIP Regions”)の説明では、複数に分割した ROM イメージを全て転送する場合、xip.bin を指定すると書かれていますが、これは、うまくいきません。xip.bin ではなく、CAHIN region の内容を収録した chain.bin を指定して下さい。

xip.bin は、全ての region の内容を一つに連結したファイルなのですが、WinCE 6.0 付属のブートローダのライブラリ(blcommon)の実装は、この構造に対応していないように思われます。xip.bin が、残りの .bin ファイルの内容を単純に連結した内容になっており、その結果、blcommon ライブラリでは、先頭の region しか認識されないのです。blcommon ライブラリのソースを読むと、ROM イメージのヘッダに記すマジックナンバーの値として、xip.bin 専用の値が定義されていたような形跡があるのですが、その値(X000FF)が設定されている場合、blcommon ライブラリは、エラーメッセージを出力して停止するように実装されています。

■OAL とブートローダのカスタマイズ
さて、今回の最初の方で、複数に分割した ROM イメージに対応するには、OAL とブートローダのカスタマイズが必要だと述べました。複数に分割した ROM イメージに対応している OAL とブートローダが、それぞれ、どのような働きをするのかについても、ごく簡単に説明しました。OAL とブートローダに対するカスタマイズの内容について、最後に、もう少しだけ補足します。

・OAL のカスタマイズ
 OEMInit() 中で、OEMRomChain を構築しなければならないことは、既に述べました。このことは、次のページに書かれています。

 Booting an Image with Multiple XIP Regions
 http://msdn.microsoft.com/en-US/library/ee483010.aspx

 しかし、このページの説明だけでは、あっさりし過ぎていて、具体的にどうすればよいのか、分かりません。OEMRomChain を構築する例は、x86 用の BSP 共通ソースをご覧になるのが良いでしょう。このソースは、次の場所にあります:

 %_WINCEROOT%/PLATFORM/COMMON/src/x86/COMMON/startup/oeminit.c

 oeminit.c の中にある、x86InitRomChain() が、OEMRomChain を構築する関数です。なお、x86InitRomChain() では、OEMRomChain という名前の変数の値を設定していますが、実は、OEMRomChain はマクロで、その実体は、OEMGLOBAL 構造体のメンバ pROMChain なのです。

 OEMGLOBAL
 http://msdn.microsoft.com/en-us/library/ee478176(v=WinEmbedded.60).aspx  
 http://msdn.microsoft.com/en-us/library/ee478176.aspx

 OEMRomChain を定義したヘッダファイルは、次の場所にあります:

 %_WINCEROOT%/PUBLIC/COMMON/OAK/INC/bcoemglobal.h

 OEMRomChain を構築する処理では、region の連結内容を記録した CHAIN region と、各 regionの ROM イメージヘッダ内容をアクセスする必要がありますが、それらは、以下のヘッダファイルで定義されています:

 %_WINCEROOT%/PUBLIC/COMMON/OAK/INC/romldr.h
 %_WINCEROOT%/PUBLIC/COMMON/OAK/INC/pehdr.h

 CHAIN region の構造については、次のページでも説明されています:

 XIP Chain
 http://msdn.microsoft.com/en-us/library/ee482877.aspx

・ブートローダのカスタマイズ
 ブートローダのカスタマイズについては、次のページをご覧ください。

 Adding Support for Multiple-BIN Image Notification
 http://msdn.microsoft.com/en-US/library/ee479207.aspx

 OEMMultiBINNotify
 http://msdn.microsoft.com/en-US/library/ee478943(v=WinEmbedded.60).aspx
 http://msdn.microsoft.com/en-US/library/ee478943.aspx

 OEMMultiBINNotify() を実装すると共に、CHAIN region の内容および他の region をホストから受け取って Flash メモリなどに書き込む動作、および、region が一つだけ転送された場合(部分アップデートの場合)に、それを正しい場所へ書き込む機能を実装しなければいけません。さらに、ブート動作では、Flash メモリなどに書き込んだ、CHAIN region と他の全ての region を RAM へロードする処理(XIP の場合は、ロードしない)を実装する必要があります。

Add comment 2012/01/13 koga

CESYSGEN 条件文での ‘Component’ 名

WinCE のビルドシステムでは、.bib ファイルや .reg ファイルなどで、@CESYSGEN IF … @CESYSGEN ENDIF という構文を使って、条件指定を記述できます。たとえば、WinCE のカタログ項目で「SD バス ドライバー」が選択されたら、BSP 固有の SD ホストコントローラのドライバが OS Design へ組み込まれるようにするには、BSP の platform.bib において、次のように記述します:

; @CESYSGEN IF CE_MODULES_SDBUS2
    <SD ホストドライバ名>.dll       $(_FLATRELEASEDIR)\<SD ホストドライバ名>.dll            NK  SHK
; @CESYSGEN ENDIF CE_MODULES_SDBUS2


ここで、条件指定に使っている ‘CE_MODULES_SDBUS2′ という変数名は、どうやって決まるのでしょうか?カタログ項目「SD バス ドライバー」の Sysgen 変数(システム生成変数)は ‘SYSGEN_SDBUS’ ですから、Sysgen 変数の名前を使っているわけでは、ありません。今回は、この条件指定に使う変数名について調べてみて分かったことを記します。

まず、WinCE のリファレンスの CESYSG 条件文に対する説明は、次のページです:

 http://msdn.microsoft.com/en-US/library/ee478869(v=WinEmbedded.60).aspx (Preprocessing Using Cesysgen Conditionals)

このページでは、CESYSGEN 条件文で指定する変数名(’Component’ 名)について、次のように説明しています。

・対応するものが module の場合は、<OS tree name>_MODULES_<module_name>。

・対応するものが component の場合は、<module_name>_<component_name>。

ただし、この説明では、’module’ と ‘component’ について具体的な説明がなく、また、<OS tree name>, <module_name>, <component_name> について、説明されていません。これらについては、%_WINCEROOT%/PUBLIC/ 配下の .bat ファイルに記述された、ビルド用の変数設定を見るのが確実だと思います。

たとえば、カタログ項目「SD バス ドライバー」の例でいえば、プロパティの「モジュール」が sdbus2.dll ですが、’sdbus2′ をキーにして %_WINCEROOT%/PUBLIC/ 配下の .bat ファイルを検索すると、%_WINCEROOT%/PUBLIC/CEBASE/OAK/MISC/winceos.bat がヒットします。ヒットするのは、以下の行です:

        set CE_MODULES=%CE_MODULES% sdbus2


ここで、CE_MODULES というビルド変数は、%_WINCEROOT%/PUBLIC/common/CESYSGEN/makefile で参照されており、ターゲット ‘preproc’ の依存ファイルリストの一部として記述されています。つまり、ビルドの preproc ステージで、CE_MODULES にセットされたターゲット群が、依存ファイルとしてビルドされるというわけです。

さて、上で述べた、CESYSGEN 条件文で指定する Component 名の ‘module’/'component’ は、このビルド変数の名前の末尾が ‘_MODULES’ と ‘_COMPONENTS’ のどちらなのか、に対応するようです。sdbus2 の場合は、CE_MODULES というビルド変数の値の一部としてセットされますので、’module’ です。そして、Component 名は、ビルド変数の名前に ‘_’ と、.dll/.exe の名前(つまり、当該 module/component のビルドターゲット名)を大文字にしたものを連結した形式となるようです。sdbus2 の場合は、CE_MODULES_SDBUS2 ですね。

Component 名が ‘component’ の場合の例は、pmif です。pmif は、%_WINCEROOT%/PUBLIC/CEBASE/OAK/MISC/winceos.bat の中で、次のように DEVICE_COMPONENTS というビルド変数の値の一部としてセットされます。

          set DEVICE_COMPONENTS=%DEVICE_COMPONENTS% pmif


pmif は、対応するカタログ項目が選択された場合に、DeviceManager (devmgr.dll) にリンクされるライブラリ(pmif.lib)に対するビルドターゲットです。CESYSGEN 条件文の変数名は、Component 名が ‘component’ の場合、ビルド変数の名前から末尾の ‘_COMPONENTS’ を削って、’_’ とビルドターゲット名を大文字にしたものを連結した形式となるようです。つまり、pmif に対しては、DEVICE_PMIF となります。DEVICE_PMIF は、たとえば %_WINCEROOT%/PUBLIC/common/OAK/FILES/common.bib で参照されており、common.bib には次の行があります:

; @CESYSGEN IF DEVICE_PMIF
   pm.dll       $(_FLATRELEASEDIR)\pm.dll                      NK  SHMK
; @CESYSGEN ENDIF


ちなみに、pmif に対応するカタログ項目は、「電源管理 (完全)」(Sysgen 変数:SYSGEN_PM)と「電源管理 (最小)」(Sysgen 変数:SYSGEN_PMSTUBS)です。これらのカタログ項目が、どちらも選択されていない場合は、pmif.lib が devmgr.dll にリンクされません。pmif が DEVICE_COMPONENTS の値の一部にセットされることにより、devmgr.dll のリンクライブラリに pmif.lib が追加される様子は、%_WINCEROOT%/PUBLIC/common/CESYSGEN/makefile をご覧ください。

さらに補足すると、pmif.lib のソースは、WinCE のカーネルソースの一部となっており、%_WINCEROOT%/PRIVATE/winceos/COREOS/device/pmif/ に配置されています。

さて、CESYSGEN 条件文で指定する Component 名の命名規約の説明における、’module’ と ‘component’ の違いは、上で述べた実例を振り返ると、おそらく、次のような使い分けなのだと思います:

・module
 ビルドターゲットが、.dll または .exe、つまり、executable であるもの。

・component
 ビルドターゲットが、.lib などの、ビルドの中間生成ファイルであるもの。

また、module については、Platform Builder のカタログ項目ビューで対応する項目のプロパティを見ると、「モジュール」という項目があり、component については、そうではない、ということも言えそうです。

module と component の概念については、WinCE のリファレンスの、次のページにも記述があります:

 http://msdn.microsoft.com/en-US/library/ee482113(v=WinEmbedded.60).aspx (Windows Embedded CE Modules and Components)

このページの説明には、component は、module の構成要素であり、module によっては、(コンフィグレーションにより組込むかどうかを切り替えできる)オプションの component を含む、と書かれています。上で述べた解釈は、この説明にも合っていると思います。

蛇足ですが、.bat ファイルにおける、OS Design に module を含める記述の例(ビルド変数 XXX_MODULES の設定例)が、WinCE のリファレンスの次のページに載っています:

 http://msdn.microsoft.com/en-US/library/ee478860(v=WinEmbedded.60).aspx (Cesysgen Batch File)

Add comment 2011/08/14 koga

Armadillo-440 用 WEC7 BSP 無償版をリリース

アットマークテクノ社の i.MX25 プロセッサ搭載ボード Armadillo-440 用の、Windows Embedded Compact 7 の BSP 無償版をリリースしました:

http://www.stprec.co.jp/news/20100917.html

お気軽に御利用下さい。

Add comment 2010/09/21 koga

Armadiilo-440 用 WinCE 6.0 BSP の修正版リリース

Armadillo-440 用 WinCE 6.0 BSP (Lilas-am440-6) の修正第一版をリリースしました。修正内容は、以下の通りです:

    ディスプレイコントロールパネルの、バックライト設定の調節が適切でない不具合を修正。
    Ethernet ドライバが、link up/link down を正しく通知しない不具合を修正。
    ブートローダ(EBoot)において、OS イメージの NOR Flash書き込み速度が遅かったのを改善。

無償版(Basic Version)の最新版は、ここからダウンロードできます。お気軽にご利用下さい。

1 comment 2010/08/18 koga

OSC Hokkaido 2010でWinCEを展示

6/26(土)に、札幌市産業振興センターで開催される「オープンソースカンファレンス北海道(OSC Hokkaido)2010」で、アットマークテクノ社の Armadillo-440 に弊社で移植した WinCE 6.0 R3 を展示します。この Armadillo-440 移植版は、5/12-14 に開催された ESEC 2010 において、アットマークテクノ社のブースで展示して頂いたものの完成版となる予定です。

当日までには、アットマークテクノ社の Armadillo サイトにて、評価用のデモ版 OS イメージを公開する予定です。また、弊社 Web サイトにおいて、Armadillo-440 用の BSP (”Lilas-am440-6″) の無償評価版も公開する予定です。いましばらくお待ち下さい。

なお、6/26 の OSC Hokkaido 2010 では、.NET Micro Framework のセミナーも担当します。こちらは、事前登録が必要ですので、ご興味のある方は、早めの登録をお願いします。トップページにてユーザ登録のうえ、トップページの「セミナー事前登録の方法」に記載の手順で事前登録して下さいませ。

Add comment 2010/05/18 koga

“Windows Embedded” 組み込みセミナー(札幌編)

12/17(木)に、JR 札幌駅隣接の JR タワーにあるマイクロソフト北海道支社で、「”Windows Embedded” 組み込みセミナー」が開催されます。この無料セミナーは、5または7つのセッションで構成される予定ですが、二番目のセッションを担当することになりました。

僕が担当するセッションのタイトルは、「Armadillo-500 で広がる Windows Embedded CE 6.0 の開発」です。

参加登録の受け付けが始まっていますので、Windows Embedded CE や、その他の Windows Embedded 製品での開発に興味がある方は、是非いらして下さい。定員は40名、全セッションの終了後には、無料で参加できる懇親会も予定されています。各セッションの内容は、
 http://www.microsoft.com/windowsembedded/ja-jp/news/events/embedded_kumikomi_Seminar.mspx#sapporo
をどうぞ。参加登録は、
 http://msevents.microsoft.com/CUI/EventDetail.aspx?EventID=1032435447&Culture=ja-JP
です。

Add comment 2009/11/27 koga

Lilas-am500-6 v1.1.0

昨日(2009/08/25)の夕方、Armadillo-500 用の Windows Embedded CE 6.0 BSP の無償版をアップデートしました。ダウンロードページは
 http://www.stprec.co.jp/downloads/lilas-am500-6.html
です。

今回の版で、Ethernet ドライバを正式対応しました。無償版では、Ethernet コントローラ(SMSC LAN911x)の DMA 転送機能に対応していませんが、ソースコードを提供していますので、ご自分で DMA 転送対応を追加して頂くことも可能です。

Add comment 2009/08/27 koga

USB キーボードと kbdmouse.dll

WinCE の OS イメージに USB キーボードのサポートを追加する場合、何が必要なのでしょうか?USB ホストコントローラのドライバと、USB HID キーボードのドライバを追加すれば OK、というのは、残念ながら間違いです。

USB マウスの場合は、USB ホストコントローラのドライバと USB HID マウスのドライバを OS イメージに追加すれば使えるようになりますが、キーボードの場合は、若干事情が異なります。その違いは、入力処理の複雑さにおける、マウスとキーボードの違いに由来しています。具体的には、キーボード配列(キーボードレイアウト)に対する処理が必要なために、同じ USB HID ドライバであっても、キーボードの方が、マウスよりもドライバの構成が複雑なのです。

両者の違いを知るには、ソースを見るのが手っ取り早いやり方です。USB HID のマウスとキーボードのドライバは、それぞれ、以下のディレクトリ配下にソースがあります:

 ・USB HID マウス
 <WINCE600>/PUBLIC/COMMON/OAK/DRIVERS/USB/CLASS/HID/CLIENTS/MOUHID/

 ・USB HID キーボード
 <WINCE600>/PUBLIC/COMMON/OAK/DRIVERS/USB/CLASS/HID/CLIENTS/KBDHID/

ドライバのバイナリは、マウスが mouhid.dll、キーボードが kbdhid.dll です。お手元に、USB のマウスとキーボードが使える OS イメージ(nk.bin)があれば、それを Platform Builder で開き、内容を見てみて下さい。mouhid.dll と kbdhid.dll が入っているはずです。

さて、mouhid.dll と kbdhid.dll を確認した際に、注意深い人なら、kbdmouse.dll という DLL があることに気付くでしょう。ファイル名からすると、キーボードとマウスの面倒を見るドライバのようですが、実は、このドライバが、キーボード配列に対する処理を行うドライバなのです。

kbdmouse.dll について見る前に、mouhid.dll と kbdhid.dll のソースに話しを戻しましょう。これら二つのドライバの複雑さの違いは、ソースのサイズを比べてみても分かります。MOUHID/ ディレクトリ配下のソースと KBDHID/ ディレクトリ配下のソースのサイズを比べれば、KBDHID/ ディレクトリ配下のソースの方が大きいですし、バイナリのサイズも、kbdhid.dll の方が mouhid.dll よりも大きくなっています。また、これらのドライバが DLL として export している関数を比べても、kbdhid.dll の方が多いことが分かります。MOUHID/mouhid.def と、KBDHID/kbdhid.def の内容を見比べてみて下さい。

mouhid.def の方は、export するシンボルとして、HID クライアントドライバとしての、次の二つの関数が書かれています:
 HIDDeviceAttach
 HIDDeviceNotifications

一方、kbdhid.def の方には、これら二つに加え、ストリームインタフェースドライバの六つの関数が書かれています:
 HIDDeviceAttach
 HIDDeviceNotifications
 KBD_Init
 KBD_PreDeinit
 KBD_Deinit
 KBD_Open
 KBD_Close
 KBD_IOControl

mouhid.dll と kbdhid.dll は、どちらも内部にスレッドを持ち、自身が制御する USB デバイス(マウスやキーボード)から、インタラプト転送でデータを読み出し、読み出したデータを処理して GWES に通知する、という構造です。全体の構造の大枠は違わないのですが、kbdhid.dll の方が、export している関数の個数を見ても分かるように、より複雑です。

さて、kbdhid.dll が、HID クライアントの関数に加え、ストリームインタフェースドライバの関数を export しているのは、実は、他のドライバから呼び出されるためです。その他のドライバというのが、上で出てきた、kbdmouse.dll なのです。この kbdmouse.dll のソースがどこにあるのかというのは、おそらく、WinCE のソースディレクトリを眺めてみても分からないでしょう。kbdhid.dll や mouhid.dll であれば、DLL の名前と同じディレクトリがありますから、比較的分かりやすいのですが、kbdmouse.dll は、対応するディレクトリが見当たりません。それもそのはず、この DLL は、OS イメージのビルド時に、他の DLL をコピーして作られるのです。

どうやって kbdmouse.dll が生成されるのかは、platform.bib を見て下さい。次のような記述が見つかるでしょう:

; @CESYSGEN IF CE_MODULES_KEYBD || CE_MODULES_POINTER
#if ! (defined BSP_NOKEYBD && defined BSP_NOMOUSE)
#if ! (defined IMGPPC || defined IMGTPC)
IF LOCALE=0411 !
IF LOCALE=0412 !
IF BSP_KEYBD_NOP
; @CESYSGEN IF CE_MODULES_NOPKEYBOARD
kbdmouse.dll        $(_FLATRELEASEDIR)\KbdNopUs.dll         NK SHK
; @CESYSGEN ENDIF CE_MODULES_NOPKEYBOARD
ENDIF   ; BSP_KEYBD_NOP

ENDIF   ; LOCALE != 0412
ENDIF   ; LOCALE != 0411
IF LOCALE=0411
IF BSP_KEYBD_JPN1
IF BSP_KEYBD_NOP
; @CESYSGEN IF CE_MODULES_NOPKEYBOARD
kbdmouse.dll        $(_FLATRELEASEDIR)\KbdNopJpn1.dll       NK SHK
; @CESYSGEN ENDIF CE_MODULES_NOPKEYBOARD
ENDIF   ; BSP_KEYBD_NOP

これは、デバイスエミュレータの platform.bib から抜き出したものですが、カタログ項目の選択により、KbdNopUs.dll や KbdNopJpn1.dll など、複数存在する DLL のうちのどれかをコピーして、kbdmouse.dll が生成されることが分かります。コピー元の DLL は、名前の末尾が ‘Us’ や ‘Jpn1′ など、言語/国を識別する文字列になっていますが、これらの DLL は、キーボードから入力された scan code を virtual key code に変換する処理を実装しています。言語設定ごとのキーボード配列を、個々の DLL に埋め込み、どの DLL を kbdmouse.dll にするかで、キーボード配列を切り替える、というわけです。

キーボード配列に関する仕組みについては、WinCE のリファレンスで、キーボードドライバの “Layout Manager” の項を参照して下さい:
 http://msdn.microsoft.com/en-us/library/aa927162.aspx

キーボードドライバについて、長々と書きましたが、最初の問題に戻りましょう。USB キーボードのサポートを追加するには、USB Host コントローラのドライバと、USB HID キーボードのドライバ(kbdhid.dll)を追加するだけでは不足。では、何が必要か、という問題です。正解は、kbdmouse.dll でした。では、kbdmouse.dll を追加しないと、何が起きるのでしょう?

kbdmouse.dll が OS イメージに含められていないと、USB キーボードを USB ポートに繋いでも、キーボードとして認識されるものの、キーボードをタイプしても、文字入力されません。USB キーボードから scan code が入力されても、kbdmouse.dll が存在しないために virtual key code に変換できず、GWES がキーイベントを発生させることが出来ないからです。

kbdhid.dll のソースを見ると、keybd_event() を呼び出している箇所があるのですが(kbdhid.cpp の KeyboardEvent() です)、keybd_event() の第一引数に渡す virtual key code の値は、MapVirtualKey() を呼び出して scan code から変換したものを使っています。ここで、kbdmouse.dll が存在しないと、MapVirtualKey() が呼び出された際、GWES が virtual key code への変換を行えず、MapVirtualKey() が 0 を返します。この結果、keybd_event() の第一引数が 0、つまり不正な値になるので(※virtual key code の値は、[1..254] の範囲の値でなければいけません)、キーイベントが発生しません。

キーボードドライバ(kbdmouse.dll)による MapVirtualKey() の機能の実装については、WinCE のリファレンスで、キーボードドライバの “Keyboard Driver MDD Functions” の項を参照して下さい。PFN_KEYBD_DRIVER_MAP_VIRTUAL_KEY が、MapVirtualKey() に対して、キーボードドライバの MDD(Model Device Driver) レイヤが実装する関数です:
 http://msdn.microsoft.com/en-us/library/aa927863.aspx

この関数を実装したソースファイルは、
 <WINCE600>/PUBLIC/COMMON/OAK/DRIVERS/KEYBD/LAYMGR/
にある laymgr.cpp です。お手元に、USB キーボードを使える WinCE 6.0 の開発ボードがあれば、カーネルデバッガで追跡してみるのも面白いでしょう。laymgr.cpp で実装されている KeybdDriverMapVirtualKey() に、カーネルデバッガでブレークポイントをセットして、USB キーボードのキーをタイプしてみて下さい。kbdhid.cpp の GenerateKeyInfo() が MapVirtualKey() を呼び出し、その結果、GWES を経由して KeybdDriverMapVirtualKey() が呼び出されるのが分かるでしょう。

ちなみに、KbdNopUs.dll が export するシンボルを定義しているのは、
 <WINCE600>/PUBLIC/COMMON/OAK/DRIVERS/KEYBD/DLL/KBDNOP/
にある kbdnop.def です。このファイルに、 KeybdDriverMapVirtualKey も書かれています。

だいぶ長くなってしまいましたが、最後に、もう一つおまけです。WinCE のリファレンスには、HID キーボードのドライバが、キーボードの LED の点灯制御を行うために必要な手順の説明があります(”Adding Keyboard LED Support to the HID Keyboard Driver”):
 http://msdn.microsoft.com/en-us/library/aa918138.aspx

ターゲットボードにキーボード相当のハードウェアが搭載されておらず、キーボードを使うには USB キーボードを繋ぐしかなく、そして、USB キーボードは一つしか繋がない、という場合には(※一般的には、それが普通でしょう)、KbdNopUs.dll などの、WinCE 付属のキーボードドライバを kbdmouse.dll として OS イメージに組み込めば十分です。

しかし、たとえば、ターゲットボードにキーパッドが搭載されており(※評価ボードの場合だと、そういうことがありますね)、キーパッドでも文字入力できて、Caps Lock キーや Num Lock キー機能も使える場合には、そのボードに USB キーボードを繋げた際、ボード搭載のキーパッドと外付けの USB キーボードとの間で、Caps Lock や Num Lock の状態を同期させなければいけません。そのような場合には、上で説明されている処理を実装する必要がある、というわけです。その場合は、WinCE 付属のキーボードドライバをそのまま使うのではなく、自前で実装しなければいけません。たぶん、
 <WINCE600>/PUBLIC/COMMON/OAK/DRIVERS/KEYBD/LAYMGR/
にある LayoutManager.lib のソースと、
 <WINCE600>/PUBLIC/COMMON/OAK/DRIVERS/KEYBD/HIDIOCTL/
にある hidioctl.{cpp,h} を別の場所にコピーしたうえで、laymgr.cpp を改変して使うことになるでしょう。そして、改変版の LayoutManager.lib を組み込んだ自前のキーボードドライバをビルドして、その DLL を kbdmouse.dll として OS イメージに組み込む、というわけです。

Add comment 2009/07/10 koga

Lilas-am500-6

一昨日(2009/07/07)の夜、弊社で開発した Windows Embedded CE 6.0 の BSP の無償版を公開しました。ターゲットボードは、アットマークテクノ社Armadillo-500 開発セットで、BSP の製品名は “Lilas-am500-6″ です(※”Lilas” は、「リラ」と発音します)。今回公開した無償版が “Basic Version” で、別途、有償版の “Comfort Version” を準備中です。詳細は、弊社のニュースページをご覧ください:
 http://www.stprec.co.jp/news/20090707.html

Lilas-am500-6 Basic Version の初版リリースでは、Ethernet ドライバが動作していないので、Ethernet ポートを必ず一つは備えている Armadillo の魅力を、十分に活かすことができません。また、OS イメージのビルド手順や、ビルドした OS イメージを Armadillo-500 のオンボード Flash に書き込む手順を説明した資料も付けていませんので、できるだけ早急に、対応を追加します。

なお、Basic Version のディスプレイドライバは、DirectDraw や Direct 3D Mobile に対応しておらず、Armadillo-500 に搭載されている Freescale 社の i.MX31/i.MX31L プロセッサが持つグラフィクス処理能力を活かしきれていません。DirectDraw や Direct 3D Mobile に対応したディスプレイドライバは、有償版となります。ただし、「Windows Embedded CE 6.0 の開発環境を入手していないが、どんな感じなのか、とりあえず Armadillo-500 で動かしてみたい」という方のために、デモ用のビルド済み OS イメージを配布できないか、検討中です。もし、デモ用のビルド済み OS イメージを配布できることになった場合には、DrectDraw 対応のディスプレイドライバも含めてみたいと考えています。

ともあれ、まだまだやることが残っていますので、引き続き開発を継続し、品質を向上させていきます。

Add comment 2009/07/09 koga


Categories

Links

Posts by Authors

Recent Posts

Calendar

2012年5月
« 4月    
 12345
6789101112
13141516171819
20212223242526
2728293031  

Posts by Month

Posts by Category

Meta