* デバイスドライバってどうやって作るの? -(by [[K]], 2008.03.21) -発展課題のページ(全部読む前にここを読むのは混乱するのでおすすめじゃないです) --このページは子ページです。親ページはこちら → [[advance/driver]] ---- -このページではキーボードのデバイスドライバを作っています。 *** keydrv.c -これがキーボードドライバのプログラムになります。アプリのようにOSとは別にmakeします。 #include "apilib.h" #include "dpilib.h" #define PIC0_OCW2 0x00a0 #define PORT_KEYDAT 0x0060 void irq01_driver(void); static int my_fifo; void HariMain(void) { int stack_irq[16 * 1024 / 4]; /* とりあえず割り込み処理用のスタック 16KB */ int keydata, keycode, key_shift = 0, key_leds; static char keytable0[0x80] = { 0, 0, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '^', 0x08, 0, 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '@', '[', 0x0a, 0, 'A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', ';', ':', 0, 0, ']', 'Z', 'X', 'C', 'V', 'B', 'N', 'M', ',', '.', '/', 0, '*', 0, ' ', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '7', '8', '9', '-', '4', '5', '6', '+', '1', '2', '3', '0', '.', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x5c, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x5c, 0, 0 }; static char keytable1[0x80] = { 0, 0, '!', 0x22, '#', '$', '%', '&', 0x27, '(', ')', '~', '=', '~', 0x08, 0, 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '`', '{', 0x0a, 0, 'A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', '+', '*', 0, 0, '}', 'Z', 'X', 'C', 'V', 'B', 'N', 'M', '<', '>', '?', 0, '*', 0, ' ', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '7', '8', '9', '-', '4', '5', '6', '+', '1', '2', '3', '0', '.', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '_', 0, 0, 0, 0, 0, 0, 0, 0, 0, '|', 0, 0 }; my_fifo = dpi_get_myfifo(); dpi_setdriver(0x01, &irq01_driver, stack_irq); key_leds = 0; /* 本当はこれもDPIを作ってOSに初期値を教えてもらうほうがいい 現状は手抜き */ dpi_sendkey(key_leds + 0xf0); /* 念のために Lock LED に反映させる */ for (;;) { keydata = api_getkey(1); /* FIFOからデータが来るまで待つ */ keycode = 0; if (keydata < 0x80) { if (key_shift == 0) { keycode = keytable0[i]; } else { keycode = keytable1[i]; } } if ('A' <= keycode && keycode <= 'Z') { /* 入力文字がアルファベット */ if (((key_leds & 4) == 0 && key_shift == 0) || ((key_leds & 4) != 0 && key_shift != 0)) { keycode += 0x20; /* 大文字を小文字に変換 */ } } if (keycode != 0) { dpi_sendkey(keycode); } if (keydata == 0x0f) { /* Tab */ dpi_sendkey(0xf8); } if (keydata == 0x2a) { /* 左シフト ON */ key_shift |= 1; } if (keydata == 0x36) { /* 右シフト ON */ key_shift |= 2; } if (keydata == 0xaa) { /* 左シフト OFF */ key_shift &= ~1; } if (keydata == 0xb6) { /* 右シフト OFF */ key_shift &= ~2; } if (keydata == 0x3a) { /* CapsLock */ key_leds ^= 4; dpi_sendkey(key_leds + 0xf0); } if (keydata == 0x45) { /* NumLock */ key_leds ^= 2; dpi_sendkey(key_leds + 0xf0); } if (keydata == 0x46) { /* ScrollLock */ key_leds ^= 1; dpi_sendkey(key_leds + 0xf0); } ... まだ書き途中 if (keydata == 0x3b && key_shift != 0) { /* Shift+F1 */ dpi_sendkey(0xf9); } if (keydata == 0x3c && key_shift != 0) { /* Shift+F2 */ dpi_sendkey(0xfa); } if (keydata == 0x57) { /* F11 */ dpi_sendkey(0xfb); } if (keydata == 0xfa) { /* キーボードがデータを無事に受け取った */ dpi_sendkey(0xfc); } if (keydata == 0xfe) { /* キーボードがデータを無事に受け取れなかった */ dpi_sendkey(0xfd); } } } void irq01_driver(void) { int keydata; io_out8(PIC0_OCW2, 0x61); /* IRQ-01受付完了をPICに通知 */ keydata = io_in8(PORT_KEYDAT); dpi_fifoput(myfifo, keydata); api_end(); /* なんとこれで割り込み処理を終わる(start_appで起動しているせい) */ } -dpi_で始まる関数はapi関数みたいな感じでアセンブラで作ってください。いちいち書かなくても分かるだろうと思うので省略します。 -ドライバを作るときに気をつけること: --irq01_driver()は割り込みが起きたときのタスク上で実行されるので、task = task_now();の結果が自分自身ではない。だからtask->ds_baseやtask->consも他のタスクでの値になっている。だから使えないと思うべきだ。そういうわけでAPI/DPIがどれでも使えるというわけではない。結局I/O命令で必要なデータを取って、それをmyfifoに送るくらいしかできない。 --HariMain()からならAPIも好きなだけ問題なく呼べる。 //--task_now()を改造すればこの問題は解決できる。多分そういう例もそのうちadvanceでやると思う。 * こめんと欄 -コメントは親ページへ → [[advance/driver]]