トップ 追記

L-CardAおぼえがき


            What's new

_ 2004/01/11: What's new 追加.

_ 2004/01/11: デバイスドライバ関連統合.

_ 2004/01/11: L-CardAの設定にftpdの自動起動の設定方法を追記.

_ 2004/01/11: 情報源に書籍を追加.

_ 2004/01/11: デバイスドライバ関連でシンプルなI/Oドライバ公開.


            デバイスドライバ関連

_ I/Oポート

<CD-ROOT>/monitor/src/L-CardA/vr4181a.hに以下のような記述を発見.これを元にGPIOをたたけば良いのだろうか?

#define VR4181A_INTCS_BASE      0xaa000000
#define INTCS(a)                (VR4181A_INTCS_BASE+(a))
  :
#define VR4181A_GPMODE0         INTCS(0x00b300)

下のあやしいファイルを探訪中,<CD-ROOT>/linux/include/asm-mips/vr41xx/toadkk-tcs8000.hにI/Oアドレス空間の定義を発見.このファイルをincludeしてドライバを書けば良いらしい.

対応表
拡張バス1ピンNo. VR4181A信号名 レジスタ名 I/Oアドレス
51〜65(奇数) GPIO40〜47 GPMODE5 0x00b30a
52〜66(偶数) GPIO0〜7 GPMODE0 0x00b300
67,69 GPIO48,49 GPMODE6 0x00b30c
68,70 GPIO8,9 GPMODE1 0x00b302

_ あやしいファイル一覧

<CD-ROOT>/linux/以下でTCS8000用の修正が入っていると思われるファイルの一覧

$ find . -type f -exec grep -q TCS8000 {} \; -print
./arch/mips/config-shared.in
./arch/mips/kernel/head.S
./arch/mips/kernel/setup.c
./arch/mips/Makefile
./arch/mips/vr41xx/common/bcu.c
./arch/mips/vr41xx/common/giu.c
./arch/mips/vr41xx/common/icu.c
./arch/mips/vr41xx/common/Makefile
./arch/mips/vr41xx/common/reset.c
./arch/mips/vr41xx/common/serial.c
./arch/mips/vr41xx/toadkk-tcs8000/init.c
./config
./drivers/mtd/maps/vr4181a-flash.c
./drivers/net/ne.c
./drivers/pcmcia/vr4181a_busops.c
./drivers/pcmcia/vr4181a_generic.c
./drivers/pcmcia/vr4181a_generic.c.XXX
./include/asm-mips/bootinfo.h
./include/asm-mips/serial.h
./include/asm-mips/vr41xx/toadkk-tcs8000.h
./include/asm-mips/vr41xx/vr4181a_pcmcia.h
./include/asm-mips/vr41xx/vr41xx.h
$ find . -type f -exec grep -q tcs8000_setup {} \; -print
./arch/mips/boot/vmlinux.binary
./arch/mips/kernel/setup.c
./arch/mips/vr41xx/toadkk-tcs8000/setup.c

arch/mips/vr41xx/common/giu.cがビンゴのような気がするが...

_ ドライバの作成

とりあえず備忘として。

  1. デバイスドライバを書く
    • GPMODEでモード設定
    • GPINENで入出力設定
    • GPDATAで読み書き
  2. デバイスファイルの作成
    mount -o rw,remount /
    mknod /dev/gpio0 c 100 0
      
  3. ドライバのロード
    /sbin/insmod ./tcs_gpio.o
      
  4. テスト
    echo -n "ABCD" > /dev/gpio0
      

これでLEDが無事点滅

◇ 注意点

コンパイル時のオプションをちゃんと指定しないと、デバイスのロード時に

insmod: Relocation overflow of type 4 for printk
などと文句をいわれる。Software Design 2003/7の記事を参考に以下のようなMakefileを作成。
CC = mipsel-linux-gcc
LD = mipsel-linux-ld
SHELL = sh
KERNELDIR = /usr/src/mipsel-linux
 
include $(KERNELDIR)/.config
 
CFLAGS = -D__KERNEL__ -DMODULE -DLINUX -DEXPORT_SYMTAB -DCONFIG_PROC_FS
CFLAGS += -mno-abicalls -fno-pic -mtune=r4600 -mips2 -mlong-calls
CFLAGS += -I$(KERNELDIR)/include -O2 -pipe -Wall
 
all: module.o tcs_gpio.o
 
clean:
        rm -f *.o

Invalid Text

_ <%=ul_tlink 0, 'シンプルなI/Oドライバ'%>

L-CardAのGI[1-8]を8ビットの入力,GO[1-8]を8ビットの出力に見立てたシンプルなデバイスドライバです.東亜DKKのTCS-8000開発キット上のLEDを点滅させることが出来ます.入力用のスイッチ回路部分は自作する必要があります.上のサブタイトルからソースのtarボールがダウンロードできます.

ライセンス

今回の配布物にはライセンスの記述がありませんが,これは,ライセンスも含めてどう扱おうと自由であるという意思表示だと思って下さい.これはあくまで現時点での判断であり,ここで公開するドライバに,今後もずっとライセンスを付けないという意味ではありません.

ファイル構成

tarボールを展開すると,以下のようなファイル郡が作成されます.

[tcsgpio]
 + Makecile              ドライバのmakefile
 + tcsgpio.h             ドライバのヘッダファイル
 + tcsgpio.c             ドライバ本体
 + rc.gpio               ドライバの追加・削除用スクリプト
 + [user-sample]
    + Makefile           サンプルアプリケーションのmakefile
    + io.c               io サンプル
    + k2000.c            LED 点滅サンプル

コンパイル

tcsgpioディレクトリで make を実行することにより,tcsgpio.oという名前のデバイスドライバモジュールが作成されます.また,user-sampleディレクトリで make を実行すると,サンプルプログラムが作成されます.

使い方

まず,コンパイルしたtcsgpio.oをL-CardAにコピーします.次にinsmodコマンドを使ってモジュールをロードします.

# /sbin/insmod ./tcsgpio.o

insmodコマンドが無事終了したら,デバイス用のスペシャルファイルを作成します.このドライバはデバイス番号の動的な割り当てを使っているので,まず,デバイス番号を調べます.

# cat /proc/devices | sed 's/ tcsgpio//p;/^.*/d'
253                          <- tcsgpio には253番が割り当てられている
# mount -o rw,remount /
# mknod /dev/gpio0 c 253 0   <- メジャー番号 253, マイナー番号 0,デバイスファイル名は/dev/gpio0.
# chown root:admin /dev/gpio0
# chmod g+w /dev/gpio0

これで準備は完了です.

サンプルプログラム「io」

GI[1-8]の状態を読み込んで,標準出力およびGO[1-8]に出力するプログラムです.GI[1-8]に接続したスイッチを切り替えた後に実行すると,その状態に合わせてGO[1-8]に接続されたLED等を明滅させることが出来ます.

サンプルプログラム「k2000」

LEDを点滅させるプログラムです.実行すると単純なパターンでの点滅を永遠に繰り返します.

以上


            情報源

_ 個人

_ 書籍

  • LINUXデバイスドライバ 第2版,オライリー・ジャパン,ISBN4-87311-081-5

    定番

  • TECH I 技術者のためのUNIX系OS入門,CQ出版社,ISBN4-7898-3316-X

    2.2.xでの実装なので,オライリーの本と付き合わせて適宜読み替える.

  • 組み込みOS新時代突入,Software Design 2003年7月号,技術評論社

    L-CardAのハードと,USBを使ったデバイスドライバの作成方についての解説.

  • VR4181A ユーザーズ・マニュアル ハードウェア編,NEC

    必要な部分だけ拾い読み.

  • TCS-8000シリーズ ハードウェア・マニュアル

    必要な情報がコンパクトにまとまっていて良い.東亜DKKの開発キット付属のCD-ROMに収録されている.


            開発環境の構築

_ インストール作業

Let's NoteにVine Linux 2.6r1(日経Linux2003年6月号付属)をインストール.ホスト名は「fengr」.

* 起動画面: Enter(グラフィカルモード)
* Language Selection: Japanese
* キーボード
   モデル:Japanese 106-key
   レイアウト: U.S. English
* マウス: 2 button Mouse (PS/2)
* ようこそ: 次へ
* インストールの種類:インストール.ラップトップ
* ディスクパーティション設定:インストーラが自動的...
* 自動パーティション設定:システムのすべてのパーティションを削除
* ディスクの設定: 次へ
* ブートローダの設定: 次へ
* ネットワークの設定: 次へ
* 追加言語サポート:English追加
* タイムゾーン: 次へ
* アカウントの設定:個人アカウント追加
* パッケージグループの選択: 次へ
* グラフィカルインターフェースの設定: 次へ
* 起動ディスクの作成: 省略
* モニタの設定: Laptop 1024 x 768
* X設定のカスタマイズ: 次へ

_ パッケージの更新

# apt-get update        # package list を取ってくる
# apt-get udgrade      # 実際に更新する

_ 開発環境のセットアップ

Software Design 2003年7月号 pp. 147-148を参考に作業を進める.

  1. CD-ROMをホームの下にコピー.
    % cd
    % mkdir L-Card
    % cd L-Card
    % cd /mnt/cdrom
    % tar cf - . | tar xvfC - ~/L-Card
  2. 開発環境のインストール
    % cd ~/L-Card/toolchains/RPMS
    % su
    # rpm -ivh *.rpm
  3. カーネルのビルド
    # cd ~hs/L-Card/linux
    # mkdir /usr/src/mipsel-linux
    # cp -r * /usr/src/mipsel-linux
    # cd /usr/src/mipsel-linux
    # cp config .config
    # make menuconfig
        何も変更せずにExitしてセーブだけする.
    # make dep clean vmlinux

_ 個人環境の整備

  • ~/.bash_profileに追加.
    addpath $HOME/bin
    addpath /sbin
    addpath /usr/sbin
    
  • ~/.xsession作成(後でchmod +xする)
    #!/bin/sh
    xmodmap ${HOME}/.xmodmaprc
    if [ -x /etc/X11/xinit/Xclients ]; then
        exec "/etc/X11/xinit/Xclients"
    fi
    
  • ~/.xmodmaprc作成
    remove Lock = Caps_Lock            (Caps_LockをCtrlに)
    remove Control = Control_L
    keysym Caps_Lock = Control_L
    add Control = Control_L
    keycode 49 = Escape                   (半角/全角をEscに)
    keycode 123 = grave asciitilde        (「\」を「`」に)
    
 

            L-CardAの設定

_ パスワードの設定.

telnetで接続し,パスワードを変更.

% telnet 192.168.0.5
$ su
# mount -o rw,remount /
# passwd admin
# sync;sync;sync
# mount -o ro,remount /
# sync;sync;sync
# poweroff                               (フラッシュROMなので念のため)

poweroffやhaltコマンドを実行するとtelnetは出来なくなるがpingは通るので,シングルユーザやモニタモードに落ちるわけではないようだ.ちょっと不安.
フラッシュROMがちゃんと書き換えられていることを確認するため,コンセントを抜いてから挿しなおし,telnetでパスワードを聞かれるか確認.

_ IPアドレスの変更

% telnet 192.168.0.5
$ su
# mount -o rw,remount /
# vi /etc/config
    NET_IPを変更
# sync;sync;sync
# mount -o ro,remount /
# sync;sync;sync
# poweroff                               (フラッシュROMなので念のため)

これでようやく名前付きのホストとしてネットワークに参加.「loni」と命名.この時点で接続不能問題は解消.原因はルータ(FreeBSD)のproxyarp.

_ ftpdの起動設定

やり取りするファイルが増えてきたのでftpdを起動.ホストによるアクセス制限が出来ないみたい.

  1. / ファイルシステムを書き込み許可モードでリマウント
    # mount -o rw,remount /
    
  2. /etc/ftpusers を編集し,adminでログイン可能にする.
    # vi /etc/ftpusers
      (admin を削除)
    # sync; sync; sync;
    
  3. 起動時にftpdが立ち上がるようにする.
    # vi /etc/config
    FTPD = yes
    
  4. 再起動,確認
    # sync; sync; sync
    # mount -o ro,remount /
    # reboot
    

起動後,ftpでログインできたら成功.


            コンパクトフラッシュ(CF)の準備

_ ファイルシステムの構築

CF(TDK製32MB)をfengrのPCカードスロットに差し込む.dmesgのログは以下の通り.

hdc: TDK TC_H, CFA DISK drive
ide1 at 0x100-0x107,0x10e on irq 3
ide-floppy driver 0.99.newide
hdc: task_no_data_intr: status=0x51 { DriveReady SeekComplete Error }
hdc: task_no_data_intr: error=0x04 { DriveStatusError }
hdc: 62592 sectors (32 MB) w/1KiB Cache, CHS=489/4/32
 hdc: hdc1
ide_cs: hdc: Vcc = 3.3, Vpp = 0.0

上記ログよりこのカードが「hdc」として認識されていることがわかるので,fdiskコマンドを使ってLinuxパーティションを作成.

# fdisk /dev/hdc
 
コマンド (m でヘルプ): m
コマンドの動作
   a   ブート可能フラグをつける
   b   bsd ディスクラベルを編集する
   c   dos 互換フラグをつける
   d   領域を削除する
   l   既知の領域タイプをリスト表示する
   m   このメニューを表示する
   n   新たに領域を作成する
   o   新たに空の DOS 領域テーブルを作成する
   p   領域テーブルを表示する
   q   変更を保存せずに終了する
   s   空の Sun ディスクラベルを作成する
   t   領域のシステム ID を変更する
   u   表示/項目ユニットを変更する
   v   領域テーブルを照合する
   w   テーブルをディスクに書き込み、終了する
   x   特別な機能 (エキスパート専用)
 
コマンド (m でヘルプ): p
 
ディスク /dev/hdc: ヘッド 4, セクタ 32, シリンダ 489
ユニット = シリンダ数 of 128 * 512 バイト
 
 デバイス ブート   始点      終点  ブロック   ID  システム
/dev/hdc1             1       489     31295+   4  FAT16 <32M
 
コマンド (m でヘルプ): d
領域番号 (1-4): 1
 
コマンド (m でヘルプ): n
コマンドアクション
   e   拡張
   p   基本領域 (1-4)
p
領域番号 (1-4): 1
最初 シリンダ (1-489, 初期値 1): 
初期値 1 を使います
終点 シリンダ または +サイズ または +サイズM または +サイズK (1-489, 初期値 489): 
初期値 489 を使います
 
コマンド (m でヘルプ): w
領域テーブルは交換されました!
 
ioctl() を呼び出して領域テーブルを再読込みします。
ディスクを同期させます。

※: cfdiskコマンドというのもあり,そっちのほうが分かりやすい.

_ ファイルシステムの作成

fdiskを使ってパーティション情報を確認する.

# fdisk -l /dev/hdc
 
ディスク /dev/hdc: ヘッド 4, セクタ 32, シリンダ 489
ユニット = シリンダ数 of 128 * 512 バイト
 
 デバイス ブート   始点      終点  ブロック   ID  システム
/dev/hdc1             1       489     31280   83  Linux

上記の結果より,作成したパーティションの名前が「/dev/hdc1」であることが分かるので,mke2fsコマンドを使ってCF上にファイルシステムを構築.
引数に指定されたファイルシステムを初期化する危険なコマンドなので,デバイス(今回の場合,/dev/hdc1)を間違えないこと.

# mke2fs /dev/hdc1
mke2fs 1.29 (24-Sep-2002)
Filesystem label=
OS type: Linux
Block size=1024 (log=0)
Fragment size=1024 (log=0)
7840 inodes, 31280 blocks
1564 blocks (5.00%) reserved for the super user
First data block=1
4 block groups
8192 blocks per group, 8192 fragments per group
1960 inodes per group
Superblock backups stored on blocks: 
        8193, 24577
 
Writing inode tables: done                            
Writing superblocks and filesystem accounting information: done
 
This filesystem will be automatically checked every 39 mounts or
180 days, whichever comes first.  Use tune2fs -c or -i to override.

_ ファイルシステムのチェック

作成したファイルシステムをマウント.

# mkdir /mnt/cf
# mount /dev/hdc1 /mnt/cf
# chmod 775 /mnt/cf              (グループ書き込み可にする)

簡単なプログラムを作ってコンパイルし,CFカードにコピー.

% vi hello.c
% mipsel-linux-gcc -o hello hello.c
% cp hello /mnt/cf
% su
# sync;sync;sync
# umount /mnt/cf

_ 利用

fengrからCFカードを抜きloniに挿す.

loni# tail -f /var/log/messages
 :
cardmgr[42]: socket 0: Anonymous Memory
cardmgr[42]: executing: 'modprobe memory_cs'
cardmgr[42]: + insmod: memory_cs.o: no module by that name found
cardmgr[42]: modprobe exited with status 1
cardmgr[42]: module /lib/modules/2.4.19-rc1/pcmcia/memory_cs.o not available
cardmgr[42]: get dev info on socket 0 failed: Resource temporarily unavailable

というログを残して認識失敗./lib/modules/2.4.19-rc1/pcmcia/memory_cs.oが無いと言っているようなので,確認.

loni# ls /lib/modules/2.4.19-rc1/pcmcia/
pcnet_cs.o   serial_cs.o

確かに無い.fengrのソースツリーを探してみる.

fengr# cd /usr/src/mipsel-linux/
fengr# find . -name \*memory_cs\* -print

無い.fengrの中を探すと/lib/modules/2.2.20-0vl10/pcmcia/の下にあった. 一方loniには/lib/modules/2.2.20-*というディレクトリはない.マニュアルを読むと日立製のメモリカードでは動作しないとあるので,OEMなのかな.手元にもう一枚あったPrincetonのカードを挿すと,同じログで,

hdc: Hitachi ATA Card, CFA DISK drive

と出るのでほぼ確定.手元にはこれ以上カードが無いのであきらめる.

_ SanDiskで再挑戦

SanDiskの64MBを購入して再挑戦.まずはloniに挿してみる.

loni# tail -f /var/log/messages
 :
cardmgr[42]: socket 0: ATA/IDE Fixed Disk
cardmgr[42]: executing: 'modprobe ide-cs'
cardmgr[42]: + Using /lib/modules/2.4.19-rc1/kernel/drivers/ide/ide-cs.o
cardmgr[42]: executing: 'modprobe ide-disk'
cardmgr[42]: + Using /lib/modules/2.4.19-rc1/kernel/drivers/ide/ide-disk.o
klogd: Trying to free nonexistent resource 2000000-b200000f>
klogd: hda: SanDisk SDCFB-64, ATA DISK drive
klogd: ide0 at 0xb2000000-0xb2000007,0xb200000e on irq 25
klogd: hda: 125440 sectors (64 MB) w/1KiB Cache, CHS=490/8/32
klogd: Partition check:
klogd:  hda1
klogd: ide_cs: hda: Vcc = 3.3, Vpp = 0.0
cardmgr[42]: executing: './ide start hda'

というわけで,認識成功\(^o^)/.fengrに挿し直し,上記手順を見ながら再び初期化(手順は省略).
fengrでファイルをコピーした後,loniに再び挿してマウント

loni# mount /dev/hda1 /mnt/flash

ファイルを確認し,テスト.

loni# ls /mnt/flash
hello       lost+found
loni# /mnt/flash/hello 
Hello, world!

感無量.


            動作確認作業

_ ウェブサーバからのバイナリ転送

ウェブサーバに実行ファイルをコピー

fengr% scp hello webserver:public_html/

loniにログインしwgetを使って実行ファイルを取得.

loni# cd /mnt/rw
loni# wget http://webserver/~hs/hello
hello                100% |*****************************|  8516       00:00 ETA

実行ビットを立ててテスト.

loni# chmod +x hello
loni# ./hello
Hello, world!

とりあえずfengr上の開発環境はうまく構築できた模様.fengrとloniだけで開発できるような体制にしないといけないが,apacheやanon ftpサーバ立ち上げるのもなぁ.


トップ 追記