|
このページは「24環境」の情報です 第19回 ウォッチドックタイマードライバ(CAT709) †海老原祐太郎
2004/1/16
今回はSH7709S CPU内蔵のウォッチドックタイマーのドライバを実装します。 SH7709Sのハードウェア仕様は †はじめにSH7709S CPUの内蔵ウォッチドックタイマーの仕様を確認してみます。 周辺クロックφP=29.4912MHz 29,4912MHz / 4096 = 7200Hz 7200Hz = 138.888uSec 138.888uSec x 256 = 35.555328msec 最大時間でも35.55msecでリセット動作となりますのでこのままでは短すぎます。 WDTドライバ仕様 †今回作成するドライバの設計仕様は以下のとおりとします。
コンパイル方法 †コンパイル方法は第16回 デバイスドライバ入門編(CAT709) 、第17回 cross-tools for REDHAT9と同じです。 基本的にはデバイスドライバの開発は開発機で行います。 説明するよりもコードを載せたほうが早いので、コードを載せます。 /* * Sh7709wdt.c * for linux-2.4 kernel * written by Y.Ebihara * version 0.10 2004.1.16 */ #define MODULE #define __KERNEL__ #include <linux/module.h> #include <linux/fs.h> #include <linux/timer.h> #include <asm/io.h> #include <asm/uaccess.h> #include <asm/semaphore.h> #define DEFAULT_MAJOR_NUM 244 #define DEFAULT_MINOR_NUM 0 #define DEVNAME "sh7709wdt" /* REGISTERS */ #define WTCNT 0xffffff84 #define WTCSR 0xffffff86 /* global var */ static volatile int wdt_countdown=0; // static struct semaphore sh7709wdt_sem1; static struct timer_list tl; /* -------------------------------------------------------- */ /* タイマーハンドラ(10msec毎に呼ばれる(はず) */ /* -------------------------------------------------------- */ void sh7709wdt_timer_handler(unsigned long unused){ if(wdt_countdown > 0){ ctrl_outw(0x5a00,WTCNT); // wdtゼロクリア(ここから33.555328msec後にwdtタイムアウト) wdt_countdown--; } init_timer(&tl); tl.expires=jiffies+HZ/100; tl.data=0; tl.function=sh7709wdt_timer_handler; add_timer(&tl); return; } /* -------------------------------------------------------- */ /* file operation method */ /* キャラクター型デバイスドライバ */ /* -------------------------------------------------------- */ static int sh7709wdt_open(struct inode *inode, struct file *filp){ int minor; // マイナー番号取得マクロ minor=MINOR(inode->i_rdev); if(minor != DEFAULT_MINOR_NUM){ printk("<1>" DEVNAME " open() error"); return -ENODEV; } filp->private_data = (void*)minor; MOD_INC_USE_COUNT; return 0; } static int sh7709wdt_close(struct inode *inode, struct file *filp){ MOD_DEC_USE_COUNT; return 0; } static int sh7709wdt_write(struct file *filp, const char *user_buf,size_t count,loff_t *ppos){ char c; copy_from_user(&c,user_buf,1); // '0'〜'9'以外は受け付けません if(c<'0' || c>'9') return -EINVAL; // '0'が書き込まれたらWDTディセーブル if(c=='0'){ ctrl_outw(0x5a00,WTCNT); // wdtゼロクリア ctrl_outw(0xa547,WTCSR); //WDTディセーブル,PowerOnReset動作,プリスケーラ4096 printk("<1>" DEVNAME " wdt disabled\n"); return count; } // '0'〜'9'だった場合は if((ctrl_inb(WTCSR) & 0x80) == 0){ // WDTが初期化されていなかったら // WDTの初期化を行う ctrl_outw(0x5a00,WTCNT); // wdtゼロクリア ctrl_outw(0xa5c7,WTCSR); //WDTイネーブル,PowerOnReset動作,プリスケーラ4096 printk("<1>" DEVNAME " wdt enabled\n"); } // 100倍(というかHZ倍)した値をwdt_countdownに格納 wdt_countdown = (c-'0')*HZ; return count; } static int sh7709wdt_read(struct file *filp, char *user_buf,size_t count,loff_t *ppos){ char buffer[16]; int len; len = sprintf(buffer,"%d\n",wdt_countdown); copy_to_user(user_buf,buffer,len); return len; } static struct file_operations sh7709wdt_fops = { owner:THIS_MODULE, // おまじない open:sh7709wdt_open, // open read:sh7709wdt_read, // read write:sh7709wdt_write, // read release:sh7709wdt_close // close }; /* -------------------------------------------------------- */ /* driver module load / unload */ /* -------------------------------------------------------- */ static int init_module(void){ printk("<1>sh7709wdt hello majorno=%d\n",DEFAULT_MAJOR_NUM); if(register_chrdev(DEFAULT_MAJOR_NUM,DEVNAME,&sh7709wdt_fops) != 0){ printk("<1>sh7709wdt register fail\n"); return -1; } init_timer(&tl); tl.expires=jiffies+1; tl.data=0; tl.function=sh7709wdt_timer_handler; add_timer(&tl); return 0; } static void cleanup_module(void){ printk("<1>sh7709wdt goodby\n"); unregister_chrdev(DEFAULT_MAJOR_NUM,DEVNAME); del_timer(&tl); } MODULE_LICENSE("GPL"); Makefileは以下のようになります。 KERNEL=/home/ebihara/cat709-root-dir/usr/src/linux CFLAGS=-O2 -I${KERNEL}/include CC=sh3-linux-gcc all:sh7709wdt.o clean: rm *.o # rmの前にはTABを入れてね コンパイルは make するだけです。 $ make $ file sh7709wdt.o sh7709wdt.o: ELF 32-bit LSB relocatable, Hitachi SH, version 1 (SYSV), not stripped デバイスドライバのロードと実行 †以下の作業は CAT709 で行います。 ドライバを組み込む # insmod /NFSマウント/開発機のどこかのディレクトリ/sh7709wdt.o sh7709wdt hello majorno=244 組み込まれたか確認する # lsmod Module Size Used by Not tainted sh7709wdt 1568 0 (unused) ← 組み込まれた ds 6332 0 (unused) sh3_ss 3212 3 pcmcia_core 34880 0 [ds sh3_ss] メジャー番号を調べる # cat /proc/devices Character devices: 1 mem 2 pty 3 ttyp 4 ttyS 5 cua 10 misc 90 mtd 108 ppp 128 ptm 136 pts 162 raw 204 ttySC 205 cusc 244 sh7709wdt ←244番に登録された 254 pcmcia そうしたらデバイスファイルも作ります。 # rommode rw メジャー番号244, マイナー番号0 # mknod /dev/sh7709wdt c 244 0 # rommode ro シェルから使ってみます # echo 9 > /dev/sh7709wdt ← 9を書き込んだ sh7709wdt wdt enabled ← WDTがイネーブルになった # ← 9秒待ってみる 9秒後にリセット SH IPL+g version 0.11, Copyright (C) 2001 Free Software Foundation, Inc. build Jun 20 2003 17:46:44 This software comes with ABSOLUTELY NO WARRANTY; for details type `w'. This is free software, and you are welcome to redistribute it under certain conditions; type `l' for details. RTC clock is 2004/01/16 20:40:40 mac addr:00:03:82:02:00:7c > 当然9秒以内に'9'を書き込んだ場合はそこから9秒以内にまた'9'を書き込んでください。 組 込 み †ドライバの動作検証ができたのでCAT709に保存します。 以下の作業は CAT709で行います。 # rommode rw # mkdir /lib/modules/2.4.21/kernel/drivers/misc # cp sh7709wdt.o /lib/modules/2.4.21/kernel/drivers/misc # depmod -a # vi /etc/modules 1行追加する sh7709wdt # rommode ro /etc/modules ファイルにモジュール名を追加しておくと、 ユーザープログラムからの利用例 †ユーザープログラムからの利用例のサンプルプログラムを載せます。 #include <stdio.h> #include <fcntl.h> #define DEVICE "/dev/sh7709wdt" int main(){ int fd; int i; char wdt_limit='5'; // 5秒の意味 fd=open(DEVICE,O_RDWR); if(fd<0){ perror(""); return 1; } for(i=0; i<10; i++){ // wdtのクリア write(fd,&wdt_limit,1); // write(fd,転送元アドレス,転送バイト数) // i秒待つ printf("sleep(%d)\n",i); sleep(i); } } 実行例 # ./a.out sh7709wdt wdt enabled sleep(0) sleep(1) sleep(2) sleep(3) sleep(4) sleep(5) sleep(6) SH IPL+g version 0.11, Copyright (C) 2001 Free Software Foundation, Inc. build Jun 20 2003 17:46:44 This software comes with ABSOLUTELY NO WARRANTY; for details type `w'. This is free software, and you are welcome to redistribute it under certain conditions; type `l' for details. RTC clock is 2004/01/16 20:54:58 mac addr:00:03:82:02:00:7c > 詳しくは †ここで取り上げたのはlinuxデバイスドライバの一番簡単な例です。 |