2007年12月22日土曜日

NetBSDでWatchdog timerを使う(for ALIX) (3)

なんだかデバイスドライバ作成講座みたいになってきて、UNIX系雑誌の原稿を書いているみたいな気分になってきた。まあいいか。もし変なところとか、質問があったらコメントしてもらえれば対応できることもあるかもしれない、ところが雑誌とは違うと納得することにした。あと、タイマのデバイスドライバは操作する場所もすくないし、滅多なことで変なこともおこらないので入門用としてはちょうどいいネタかもしれないので、一度書いておくとあとあと便利かも。

とりあえず、今回の話は手元にCS5536のデータブックを置いておくと少しはわかるかもしれない。650ページもあるドキュメントであんまり画面上で参照したい大きさじゃない。昔みたいに印刷物でくばってくれないかなあ、とこのデバイスを触っている最中よく思った。MFGPTの仕様はあちこちに分散されているけど、今回一番必要になるのは制御用のレジスタマップと書き込むべき内容が書いてある「6.17 Multi-Function General Purpose Timer Register Descriptions」(p527)あたりだ。タイマにしてはできることが多いのでたくさん設定できることがあるけれど、今回つかうのは

  • 6.17.2.4 MFGPT[x] Setup (MFGPT[x]_SETUP) (p522)
  • 6.17.2.3 MFGPT[x] Up Counter (MFGPT[x]_CNT) (p521)
  • 6.17.2.2 MFGPT[x] Comparator 2 (MFGPT[x]_CMP2) (p520)
の3つだけ。上から、タイマのカウンターの動作設定、カウンターの値、カウンターの上限値をそれぞれ設定するレジスタになる。
6.17.2.4をじーっと眺めると、MFGPT0_SETUPレジスタのビット構造の図がある。
このレジスタは16bitで各ビットの値を設定するとタイマのカウンタの動作を定義できる。注意しないといけないのは、いくつかのビットは最初の一回しか書き込みできない点で、それ以降はそのビットへの変更は反映されない。たとえば、bit0-3のMFGPT_SCALEはカウンタのプリスケーラーの値を設定するビットフィールドだが一度設定すると途中でプリスケーラーの値を変更できない(らしい)。MFGPT_CLKSELはカウンタのクロックを32KHzか14.328MHzか選択するために使うがこれも同様に最初に設定したら変更できない。
Watchdogタイマはms単位ではあまり使わないだろうということと、比較的長い周期が設定できたほうがいいだろう、という判断でCLKSELでは32KHzを、プリスケーラは32K分周を選択することにした。つまり32KHzを32K分周するためカウンタは1Hzで駆動される。プログラムも簡単になるし、16ビットカウンタの最大値の65535秒=約18.2時間までの長周期を設定できる、ようになる。

初期設定は、glxpcib_attach()の中で行う。レジスタの値を変更するためには、PCIのアドレス空間をアクセスできるようにしておかないといけない、GPIOの時と同様にbus_space_map()を使ってio handleを取得しておく。該当部分のコードはこんな感じ。

/* Attach the watchdog timer */
wdtbase = rdmsr(MSR_LBAR_MFGPT) & 0xffff;
if (bus_space_map(sc->sc_iot, wdtbase, 64, 0, &sc->sc_ioh)) {
aprint_error("%s: can't map memory space for WDT",
sc->sc_dev.dv_xname);
} else {
mutex_init(&sc->sc_mtx, MUTEX_DEFAULT, IPL_HIGH);
bus_space_write_2(sc->sc_iot, sc->sc_ioh,
AMD5536_MFGPT0_SETUP,
AMD5536_MFGPT_CNT_EN | AMD5536_MFGPT_CMP2EV |
AMD5536_MFGPT_CMP2 | AMD5536_MFGPT_DIV_MASK);

ここでは、IO空間をマップしてから、MFGPT0_SETUPレジスタに「カウンタを動かす+フルカウンタになったらリセットをする+入力クロック=32KHz+プリスケーラー=32K」を設定するところまでが含まれている。
その後は、

sc->sc_smw.smw_name = "cs5536wdt";
sc->sc_smw.smw_cookie = sc;
sc->sc_smw.smw_setmode = glxpcib_wdog_setmode;
sc->sc_smw.smw_tickle = glxpcib_wdog_tickle;
sc->sc_smw.smw_period = 32;
aprint_normal("%s: watchdog", sc->sc_dev.dv_xname);
wdt = 1;
}
/* Register Watchdog timer to SMW */
if (wdt) {
if (sysmon_wdog_register(&sc->sc_smw) != 0)
aprint_error("%s: can not register wdog\n",
sc->sc_dev.dv_xname);
}

sysmonのフレームワークに必要な設定(smw構造体にいろいろと書く)をして、sysmon_wdog_register()でMFGPT0タイマをsysmonのwatchdogタイマとして登録すれば、attach処理は完了する。

あとは、sysmonのwdogフレームワークがMFGPT0タイマを制御するための制御関数を記述すれば完了である。記述していないうちは、関数ポインタとしてNULLをいれておけば、カーネルの作成して連携部分のチェックまではできるはず。実際に開発しているときは、周りだけ作って中身がない状態から、すこしづつ中身を埋めていってつくっていた。

次は、watchdogタイマとしてMFGPTを動かすため操作関数について書いてみる予定。

1 件のコメント:

sexy11 さんのコメント...

情趣用品,情趣用品,情趣用品,情趣用品,情趣用品,情趣用品,情趣,情趣,情趣,情趣,情趣,情趣,情趣用品,情趣用品,情趣,情趣,A片,A片,情色,A片,A片,情色,A片,A片,情趣用品,A片,情趣用品,A片,情趣用品,a片,情趣用品

A片,A片,AV女優,色情,成人,做愛,情色,AIO,視訊聊天室,SEX,聊天室,自拍,AV,情色,成人,情色,aio,sex,成人,情色

免費A片,美女視訊,情色交友,免費AV,色情網站,辣妹視訊,美女交友,色情影片,成人影片,成人網站,H漫,18成人,成人圖片,成人漫畫,情色網,日本A片,免費A片下載,性愛

情色文學,色情A片,A片下載,色情遊戲,色情影片,色情聊天室,情色電影,免費視訊,免費視訊聊天,免費視訊聊天室,一葉情貼圖片區,情色視訊,免費成人影片,視訊交友,視訊聊天,言情小說,愛情小說,AV片,A漫,AVDVD,情色論壇,視訊美女,AV成人網,成人交友,成人電影,成人貼圖,成人小說,成人文章,成人圖片區,成人遊戲,愛情公寓,情色貼圖,色情小說,情色小說,成人論壇


免費A片,日本A片,A片下載,線上A片,成人電影,嘟嘟成人網,成人貼圖,成人交友,成人圖片,18成人,成人小說,成人圖片區,微風成人區,成人文章,成人影城

A片,A片,A片下載,做愛,成人電影,.18成人,日本A片,情色小說,情色電影,成人影城,自拍,情色論壇,成人論壇,情色貼圖,情色,免費A片,成人,成人網站,成人圖片,AV女優,成人光碟,色情,色情影片,免費A片下載,SEX,AV,色情網站,本土自拍,性愛,成人影片,情色文學,成人文章,成人圖片區,成人貼圖