一般的なデバイスドライバ
デバイスドライバについて
今回はSH7706LSRのLinux上での割り込みを扱います。割り込みはハードウェア資源なので,
デバイスドライバもユーザプログラムと同様のソフトウェアですが,
Linuxカーネルのバージョンアップによって,
Linuxデバイスドライバにはいくつもの種類があり,
対象ハードウェアについて
デバイスドライバの対象とするハードウェアは,
スイッチはプルアップになっているため,
汎用LEDはSH7706プロセッサのSCP4
ハードウェアアクセスについて
デバイスドライバはLinuxカーネルの一部分なのでI/
Linuxはもともとインテルi80386プロセッサのプロテクトモードを活用するためのソフトウェアが出発点となっているので,
そのため,
また,
#define PORT_PGDR 0xa400012cUL
#define PORT_SCDR 0xa4000136UL
汎用スイッチと汎用LEDのデバイスドライバ
デバイスドライバの入力仕様は,
汎用スイッチと汎用LEDのデバイスドライバのソースコードはリスト1となります。
リスト1
01: #include <linux/module.h>
02: #include <linux/init.h>
03: #include <linux/device.h>
04: #include <linux/ctype.h>
05: #include <linux/poll.h>
06: #include <asm/io.h>
07:
08: #define PORT_PGDR 0xa400012cUL
09: #define PORT_SCDR 0xa4000136UL
10:
11: static int leddev_major;
12:
13: static ssize_t led_read(struct file * file, char __user * buf, size_t count, loff_t * ppos) {
14: ssize_t n;
15: char c;
16:
17: for(n = 0;n < count;n++) {
18: if(ctrl_inb(PORT_PGDR) & 0x10) {
19: c = '0';
20: } else {
21: c = '1';
22: }
23: copy_to_user(buf + n, &c, 1);
24: }
25: return count;
26: }
27:
28: static ssize_t led_write(struct file * file, const char __user * buf, size_t count, loff_t * ppos) {
29: ssize_t n;
30: char c;
31:
32: for(n = 0;n < count;n++) {
33: copy_from_user(&c, buf + n, 1);
34: if(c == '1') {
35: ctrl_outb(ctrl_inb(PORT_SCDR) | 0x10, PORT_SCDR);
36: }
37: if(c == '0') {
38: ctrl_outb(ctrl_inb(PORT_SCDR) & ~0x10, PORT_SCDR);
39: }
40: }
41: return count;
42: }
43:
44: static const struct file_operations led_fops = {
45: .owner = THIS_MODULE,
46: .read = led_read,
47: .write = led_write,
48: };
49:
50: #define CHRDEV "leddev"
51: static int __init leddev_init (void) {
52: leddev_major = register_chrdev(0, CHRDEV, &led_fops);
53: printk(KERN_INFO "LED/SW Device Driver\n");
54: return 0;
55: }
56:
57: static void __exit leddev_cleanup (void) {
58: unregister_chrdev(leddev_major, CHRDEV);
59: printk(KERN_INFO "LED/SW Device Driver Exit\n");
60: }
61:
62: module_init(leddev_init);
63: module_exit(leddev_cleanup);
64:
65: MODULE_LICENSE("GPL");
通常のユーザプログラムとLinuxとの呼び出しインターフェースはmain関数となりますが,
初期化関数と終了関数の名称は任意でかまいません。初期化関数では対象となるハードウェアの初期化やキャラクタ型デバイスドライバの登録を行います。今回はハードウェアの初期化は不要なので,
register_
終了関数では対象となるハードウェアの停止処理やキャラクタ型デバイスドライバの登録解除を行い,
汎用スイッチと汎用LEDのデバイスドライバでは入力と出力のみを行うので,
ここで気をつけなければいけない点は,