* デバイスドライバってどうやって作るの?
-(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]]