APC8750にNetBSD/evbarmを移植するための記録 9/22
ということで、落ち着いてLinuxのソースをあさる。シリアルのソースはarch/armの下ではなくdrivers/serialの下にあった。
なんてこった。一か所においてほしいもんだ。
https://github.com/apc-io/apc-8750/blob/master/kernel/drivers/serial/serial_wmt.c
非常に長い。
が、初期化しているところできっと割り込みをONにしているのだろうから、それっぽいところを探す。
IERにビットを立てるのでierをORしている奴を探せばよい。
いかにも初期化している関数を発見。
static int wmt_startup(struct uart_port *port)の1601行目から。
デバッグルーチンにちゃんと入ってくれる。が、割り込みコントローラからはUARTのどの割り込みが入ったかわからない。
いよいよ、割り込みコントローラからcomドライバに制御を移す時が来たといえる。
irq_handlerに入ったら嬉しそうにデバッグ文を出していたが、それ以降を見なければならない。
RPIのsys/arch/arm/broadcom/bcm2835_intr.c#bcm2835_irq_handlerを見ると構造としては、自身(MD)のbcm2835_pic_find_pending_irqsを呼び、そのあとにpic_do_pending_intsを読んでいる。
おなじみgeminiのsys/arch/arm/gemini/gemini_icu.c#find_pending_irqsを見てみる。
なので、この関数は、未処理の割り込みをレジスタから読み込み、picに印をつけておく。と想像できる。
sys/arch/arm/pic/pic.c#pic_mark_pending_sourcesを見てみよう。
そのあと、なにやらループを回している。
ん?ffs()とはなんだろう。と調べると、おどろきの common/lib/libc/arch/arm/string/ffs.Sである。Find First Set bitのことであろう。
つまり、pendingに立っているビットの数ぶんループ処理をしているようだ。
ちょっとまてよ、pendingでループを回したということは、pendingには複数のビットが立っていることが前提なんだな。そういえば、さっきMDのblockを呼んでいたけれども、それは、現時点で未処理の割り込みは「すべて」ブロックせよということか。
ははぁ、block, unblockの引数が、IRQの数字ではなくビットで渡っていた理由はそれか。複数ある未処理の割り込みをblock/unblockに渡すためにビットを使っていたのだな。irq_baseの存在理由もわかった気がする。割込みの数を32個単位で管理するためのベース、というわけだな。
そう考えると、以下の5ビットシフトも納得がいく。
で、最初にirq_baseをもとに割込みの配列をipendingとして取り出して、引き数のpendingとorをとって保存。この保存行為が関数名のmarkってことなんだろうかね。
そのあと、さっきのループを回してipl_maskを作って、picの構造体にorで保存(mark)しているってことなんだろうね。
適当に実装したblock/unblockは、ビットが一つしかたっていない前提で作っていたから、一つの割り込みしかOn/Offできないので、ちゃんと複数ビットをみてすべてのOn/Offをしないとダメですね。
ふーむ。つーことで、find_pending_irqsはipl_maskを返せばよいってことか。
で、さっきほったらかしていた、
そういえば、以前icuを全部ダンプしたときに、eth0とpmc_wakeupの二つの割り込みが同時に上がってきていた際に、そういうレジスタがあった。こいつがそのまま使えるってことだな。
まてよ、APCはgeminiと違って、割り込みが64個あるので、二つのレジスタを両方調べにゃいかんはずだな。
似たようなicuのソースないかなということで、find_pending_irqsを検索してみると、sys/arch/arm/omap/omap2_icu.c#omap_irq_handlerで
ふーむ。orで重ねりゃいいのかな。
sys/arch/arm/marvell/kirkwood.c#kirkwood_find_pending_irqsがかなり似ている。
二つのレジスタからpendingを読んできて、それのORをとっている。
irq_handlerはRPIほぼそのままでよかった。
よくかんがえたら、RPIは複雑なことやっているなぁ。最初に参考にするには難しすぎる。geminiわかりやすいわ。
ということで、動かしてみる。
ちゃんと、pic.cのpic_do_pending_ints(I32_bit, oldipl, frame);に入って、pic_dispatchでis->is_funcの関数ポインタを呼び出してくれればオッケー。
なのだが、wmt_tmrのattachメッセージを出したところで止まる。
デバッグメッセージをあちこちに埋め込んで、block/unblockが期待通りに動いているかを見たりする。
unblockの前にblockが呼ばれていたりして不可解な現象に遭遇する。
それはそうか、unblockのレジスタ操作をした瞬間に割り込み処理に飛べばblock処理が動き、blockのログを出した後unblockに復帰してunblockのログを出すのだから。unblockに入った瞬間にログを出せば、それなりの順序性でログを出す。割り込み処理は脳みそ使うなぁ。
動かしていると、すかっとrootデバイスを聞くところまで進んだり、wmt_tmrのattachで止まったりする。
もしかして、キーをバシバシ叩いていれば割り込みが入ってattachで止まっているんじゃないかなと思い、何度か試行してみる。
確かにそれっぽいぞ。
もしやと思って、pic_dispatchの手前にログを埋め込んで、バシバシしながら起動。おぉ、pic_dicpatchまで動いているではないか。
ということは、
comintr()にログを仕込む。確かに実行されている!
が、だんまりである。
comintrは長いので、ばらばらとログを埋めて再実行。なんかしらんが、無限ループにはまっている。
今さらだが、よくよく考えてみると、comドライバのレジスタとwmt_uartのレジスタは全然違っているような気がする。
たしかに、IERなどの名前は同じものがあるのだが、レジスタの並びであるとか、comにはないIrDAのレジスタがあったりと。
そもそも16550Aコンパチだというのは、誰が言ったのだ? たしかにcomドライバで文字は出たけれど、たまたまシリアル出力のためのTXレジスタがどちらも先頭アドレスにあって、たまたま出ているだけなのではないのか?
というか、16550Aコンパチと思い込んだのは自分の早とちりではないか。
そう思って、Linuxのコードとcomドライバのコードを見比べると、レジスタの使いっぷりが全然違う。別物だろうこれは。
おいちょっとまて、これってシリアルコンソールドライバを全部自分で作らないとダメなのか? matchとattachぐらい書けば、あとはcomドライバで面倒見てくれると思っていたから、ここまで頑張れたのに。
シリアルコンソールドライバを自前実装している奴らは、1,000行とか2,000行とかあるんだけど。
自前シリアルコンソールドライバを見つけては絶望していたのだが、sys/arch/arm/s3c2xx0/sscom.c#1850を眺めていて気になるコメントが。
なんか、cngetc, cnputc, cnpollcとattach/detachだけでよさそう。んー、つまりこれは割り込みベースじゃなくって、ポーリングベースで動かすためのミニマムセットなのか?
まてよ、この名前ってどっかでみたぞ。これってcomドライバにもあった。というか、出力ルーチンでタイムアウトを削ったのってcnputcじゃなかったっけ?
もしかすると、割り込みベースでコンソールを動かすことをあきらめたら、俺でも実装できるんじゃ? cnputcはもうあるようなもの(レジスタに値書き込むだけ)だし、ビジーループで待てば、文字も詰まらないはず?
ふーむ。方針を変更して、FIFOだのDMAだの難しいことはやらず、ポーリングベースで動かせるんだろうか?
じゃぁ、sys/dev/cons.c#cngetcを読んでいるところを調べてみるか。
なんだ、実態は同じところにあるsys/dev/cons.c#cngetsnじゃないか。これは、複数文字をgetcするってことだよな。じゃぁ、cngetsnはどこから呼ばれているのかな。
init_mainで/sbin/initって入力するところとroot device, dump device, file systemきいてくるところだけだ。そこだけポーリングモードで入力できても、だめじゃん。
やっぱり、ぜんぶシリアルコンソールドライバを作らないといけないのか。
まぁ、でもすこしでも入力が動くと楽しそうだから、まずはcnシリーズを作ってみましょうか。
なんてこった。一か所においてほしいもんだ。
https://github.com/apc-io/apc-8750/blob/master/kernel/drivers/serial/serial_wmt.c
非常に長い。
が、初期化しているところできっと割り込みをONにしているのだろうから、それっぽいところを探す。
IERにビットを立てるのでierをORしている奴を探せばよい。
いかにも初期化している関数を発見。
static int wmt_startup(struct uart_port *port)の1601行目から。
/*
* Enable RX FIFO almost full, timeout, and overrun interrupts.
*/
uart->urier = URIER_ERXFAF | URIER_ERXFF | URIER_ERXTOUT | URIER_EPER | URIER_EFER | URIER_ERXDOVR;
きっとここだろう。URIERシリーズはarch/arm/mach-wmt/include/mach/wmt_uart.hにある。/* * UART Interrupt Enable Register Bit Definitions */ #define URIER_ETXDE BIT0 /* Enable for TX data register empty */ #define URIER_ERXDF BIT1 /* Enable for RX data register full */ #define URIER_ETXFAE BIT2 /* Enable for TX FIFO almost full */ #define URIER_ETXFE BIT3 /* Enable for TX FIFO full */ #define URIER_ERXFAF BIT4 /* Enable for RX FIFO almost full */ #define URIER_ERXFF BIT5 /* Enable for RX FIFO full */ #define URIER_ETXDUDR BIT6 /* Enable for TX underrun */ #define URIER_ERXDOVR BIT7 /* Enable for RX overrun */ #define URIER_EPER BIT8 /* Enable for parity error */ #define URIER_EFER BIT9 /* Enable for frame error */ #define URIER_EMODM BIT10 /* Enable for modem control signal */ #define URIER_ERXTOUT BIT11 /* Enable for receive time out */ #define URIER_EBK BIT12 /* Enable for break signal done */ /* Bit[13:31] are reserved. */これで、Linuxで立てているbitがわかったので、これを真似することに。
デバッグルーチンにちゃんと入ってくれる。が、割り込みコントローラからはUARTのどの割り込みが入ったかわからない。
いよいよ、割り込みコントローラからcomドライバに制御を移す時が来たといえる。
irq_handlerに入ったら嬉しそうにデバッグ文を出していたが、それ以降を見なければならない。
RPIのsys/arch/arm/broadcom/bcm2835_intr.c#bcm2835_irq_handlerを見ると構造としては、自身(MD)のbcm2835_pic_find_pending_irqsを呼び、そのあとにpic_do_pending_intsを読んでいる。
155 void
156 bcm2835_irq_handler(void *frame)
157 {
158 struct cpu_info * const ci = curcpu();
159 const int oldipl = ci->ci_cpl;
160 const uint32_t oldipl_mask = __BIT(oldipl);
161 int ipl_mask = 0;
162
163 ci->ci_data.cpu_nintr++;
164
165 bcm2835_barrier();
166 ipl_mask = bcm2835_pic_find_pending_irqs(&bcm2835_pic);
167
168 /*
169 * Record the pending_ipls and deliver them if we can.
170 */
171 if ((ipl_mask & ~oldipl_mask) > oldipl_mask)
172 pic_do_pending_ints(I32_bit, oldipl, frame);
173 }
pic_do_pending_intsはsys/arch/arm/pic/pic.c#pic_do_pending_intsにあるので、まずはbrm2835_pic_find_pending_irqは何をするのか読み解かねばならない。が、さっぱりわからない。
194 /*
195 * Called with interrupts disabled
196 */
197 static int
198 bcm2835_pic_find_pending_irqs(struct pic_softc *pic)
199 {
200 int ipl = 0;
201 uint32_t bpending, gpu0irq, gpu1irq, armirq;
202
203 bcm2835_barrier();
204 bpending = read_bcm2835reg(BCM2835_INTC_IRQBPENDING);
205 if (bpending == 0)
206 return 0;
207
208 armirq = bpending & BCM2835_INTBIT_ARM;
209 gpu0irq = bpending & BCM2835_INTBIT_GPU0;
210 gpu1irq = bpending & BCM2835_INTBIT_GPU1;
211
212 if (armirq) {
213 ipl |= pic_mark_pending_sources(pic, BCM2835_INT_BASICBASE,
214 armirq);
215
216 }
217
218 if (gpu0irq || (bpending & BCM2835_INTBIT_PENDING1)) {
219 uint32_t pending1;
220
221 pending1 = read_bcm2835reg(BCM2835_INTC_IRQ1PENDING);
222 ipl |= pic_mark_pending_sources(pic, BCM2835_INT_GPU0BASE,
223 pending1);
224 }
225 if (gpu1irq || (bpending & BCM2835_INTBIT_PENDING2)) {
226 uint32_t pending2;
227
228 pending2 = read_bcm2835reg(BCM2835_INTC_IRQ2PENDING);
229 ipl |= pic_mark_pending_sources(pic, BCM2835_INT_GPU1BASE,
230 pending2);
231 }
232
233 return ipl;
234 }
ということで、ほかのpicを使っている実装を見てみることにした。おなじみgeminiのsys/arch/arm/gemini/gemini_icu.c#find_pending_irqsを見てみる。
154 /*
155 * Called with interrupts disabled
156 */
157 static int
158 find_pending_irqs(struct geminiicu_softc *sc)
159 {
160 uint32_t pending = INTC_READ(sc, GEMINI_ICU_IRQ_STATUS);
161
162 KASSERT((sc->sc_enabled_mask & pending) == pending);
163
164 if (pending == 0)
165 return 0;
166
167 return pic_mark_pending_sources(&sc->sc_pic, 0, pending);
168 }
おぉ、なんかあっさりしているぞ。- なんかレジスタを読む。結果が0なら0を返す。
- pic_mark_pending_sourceを返す
なので、この関数は、未処理の割り込みをレジスタから読み込み、picに印をつけておく。と想像できる。
sys/arch/arm/pic/pic.c#pic_mark_pending_sourcesを見てみよう。
191 uint32_t
192 pic_mark_pending_sources(struct pic_softc *pic, size_t irq_base,
193 uint32_t pending)
194 {
195 struct intrsource ** const isbase = &pic->pic_sources[irq_base];
196 struct intrsource *is;
197 volatile uint32_t *ipending = &pic->pic_pending_irqs[irq_base >> 5];
198 uint32_t ipl_mask = 0;
199
200 if (pending == 0)
201 return ipl_mask;
202
203 KASSERT((irq_base & 31) == 0);
204
205 (*pic->pic_ops->pic_block_irqs)(pic, irq_base, pending);
206
207 atomic_or_32(ipending, pending);
208 while (pending != 0) {
209 int n = ffs(pending);
210 if (n-- == 0)
211 break;
212 is = isbase[n];
213 KASSERT(is != NULL);
214 KASSERT(irq_base <= is->is_irq && is->is_irq < irq_base + 32);
215 pending &= ~__BIT(n);
216 ipl_mask |= __BIT(is->is_ipl);
217 }
218
219 atomic_or_32(&pic->pic_pending_ipls, ipl_mask);
220 atomic_or_32(&pic_pending_ipls, ipl_mask);
221 atomic_or_32(&pic_pending_pics, __BIT(pic->pic_id));
222
223 return ipl_mask;
224 }
これも難しいな。なんか、
205 (*pic->pic_ops->pic_block_irqs)(pic, irq_base, pending);
でMDのblockルーチンを読んでいる。これはきっと当該割り込みをOFF(ブロック)するということだろう。そのあと、なにやらループを回している。
ん?ffs()とはなんだろう。と調べると、おどろきの common/lib/libc/arch/arm/string/ffs.Sである。Find First Set bitのことであろう。
つまり、pendingに立っているビットの数ぶんループ処理をしているようだ。
- pendingに立っているビットを見つける(nとする)
- 割込みnの割り込みソース(is)を取得
- pendingに立っているビットをクリア
- ipl_maskにis->is_iplを立てる
43 /* Interrupt priority "levels". */
44 #define IPL_NONE 0 /* nothing */
45 #define IPL_SOFTCLOCK 1 /* clock */
46 #define IPL_SOFTBIO 2 /* block I/O */
47 #define IPL_SOFTNET 3 /* software network interrupt */
48 #define IPL_SOFTSERIAL 4 /* software serial interrupt */
49 #define IPL_VM 5 /* memory allocation */
50 #define IPL_SCHED 6 /* clock interrupt */
51 #define IPL_HIGH 7 /* everything */
52
53 #define NIPL 8
なので、ipl_maskにはそれぞれのIPLに応じたビットを立てるのがこの関数の役目である。ちょっとまてよ、pendingでループを回したということは、pendingには複数のビットが立っていることが前提なんだな。そういえば、さっきMDのblockを呼んでいたけれども、それは、現時点で未処理の割り込みは「すべて」ブロックせよということか。
ははぁ、block, unblockの引数が、IRQの数字ではなくビットで渡っていた理由はそれか。複数ある未処理の割り込みをblock/unblockに渡すためにビットを使っていたのだな。irq_baseの存在理由もわかった気がする。割込みの数を32個単位で管理するためのベース、というわけだな。
そう考えると、以下の5ビットシフトも納得がいく。
197 volatile uint32_t *ipending = &pic->pic_pending_irqs[irq_base >> 5];
pic->pic_pending_irqsは32個単位で管理されている割り込みの配列(ビットだけど)というわけね。で、最初にirq_baseをもとに割込みの配列をipendingとして取り出して、引き数のpendingとorをとって保存。この保存行為が関数名のmarkってことなんだろうかね。
そのあと、さっきのループを回してipl_maskを作って、picの構造体にorで保存(mark)しているってことなんだろうね。
適当に実装したblock/unblockは、ビットが一つしかたっていない前提で作っていたから、一つの割り込みしかOn/Offできないので、ちゃんと複数ビットをみてすべてのOn/Offをしないとダメですね。
ふーむ。つーことで、find_pending_irqsはipl_maskを返せばよいってことか。
で、さっきほったらかしていた、
- なんかレジスタから読む
そういえば、以前icuを全部ダンプしたときに、eth0とpmc_wakeupの二つの割り込みが同時に上がってきていた際に、そういうレジスタがあった。こいつがそのまま使えるってことだな。
まてよ、APCはgeminiと違って、割り込みが64個あるので、二つのレジスタを両方調べにゃいかんはずだな。
似たようなicuのソースないかなということで、find_pending_irqsを検索してみると、sys/arch/arm/omap/omap2_icu.c#omap_irq_handlerで
145 ipl_mask |= find_pending_irqs(sc, 0);
...
147 ipl_mask |= find_pending_irqs(sc, 1);
...
149 ipl_mask |= find_pending_irqs(sc, 2);
みたいにorで重ねていたりする。ふーむ。orで重ねりゃいいのかな。
sys/arch/arm/marvell/kirkwood.c#kirkwood_find_pending_irqsがかなり似ている。
二つのレジスタからpendingを読んできて、それのORをとっている。
181 kirkwood_find_pending_irqs(void)
182 {
183 int ipl = 0;
184
185 uint32_t causelow = read_mlmbreg(KIRKWOOD_MLMB_MICLR);
186 uint32_t pendinglow = read_mlmbreg(KIRKWOOD_MLMB_MIRQIMLR);
187
188 pendinglow &= causelow;
189 if (pendinglow != 0)
190 ipl |= pic_mark_pending_sources(&kirkwood_pic, 0, pendinglow);
191
192 if ((causelow & (1 << KIRKWOOD_IRQ_HIGH)) == (1 << KIRKWOOD_IRQ_HIGH)) {
193 uint32_t causehigh = read_mlmbreg(KIRKWOOD_MLMB_MICHR);
194 uint32_t pendinghigh = read_mlmbreg(KIRKWOOD_MLMB_MIRQIMHR);
195 pendinghigh &= causehigh;
196 ipl |= pic_mark_pending_sources(&kirkwood_pic, 32, pendinghigh);
197 }
198
199 return ipl;
200 }
APCだと、causeとか関係なくとれちゃいそう。こんなのでどうだろう。
/*
* Called with interrupts disabled
*/
static int
wm8750_pic_find_pending_irqs(struct pic_softc *pic)
{
int ipl = 0;
uint32_t pending_l = read_icureg(ICIS_L);
uint32_t pending_h = read_icureg(ICIS_H);
ipl |= pic_mark_pending_sources(pic, 0, pending_l);
ipl |= pic_mark_pending_sources(pic, 32, pending_h);
return ipl;
}
block/unblockの複数ビット対応も、すごいすなおにループを回す実装をしてみた。
static void
wm8750_pic_unblock_irqs(struct pic_softc *pic, size_t irqbase,
uint32_t irq_mask)
{
uint32_t reg = 0xFFFFFFFF;
uint32_t irq_num = 9999;
int i;
for (i = 0; i < 32; i++) {
if (irq_mask & (1<<i)) {
irq_num = irqbase + i;
reg = read_ic0((irq_num/4)*4);
reg |= ((INTC_ENABLE) << ((irq_num % 4) * 8));
write_ic0((irqbase/4)*4, reg);
}
}
aprint_normal("icu: unblock: irqbase=0x%08x, irqmask=0x%08x, irq_num=%d, reg=0x%08x\n",
(int)irqbase, irq_mask, irq_num, reg);
}
static void
wm8750_pic_block_irqs(struct pic_softc *pic, size_t irqbase,
uint32_t irq_mask)
{
uint32_t reg=9999, irq_num=0xFFFFFFFF;
int i;
/* print_regs(); */
for (i = 0; i < 32; i++) {
if (irq_mask == (1<<i)) {
irq_num = irqbase + i;
reg = read_ic0((irq_num/4)*4);
reg &= ~((INTC_ENABLE) << ((irq_num % 4)*8));
write_ic0((irqbase/4)*4, reg);
}
}
aprint_normal("icu: block: irqbase=0x%08x, irqmask=0x%08x, irq_num=%d, reg=0x%08x\n",
(int)irqbase, irq_mask, irq_num, reg);
}
よくかんがえたら、ffs()をつかったり、read_4/write_4ではなくread_1/write_1を使ったほうが素直な気がしてきた。後から直そうか。irq_handlerはRPIほぼそのままでよかった。
よくかんがえたら、RPIは複雑なことやっているなぁ。最初に参考にするには難しすぎる。geminiわかりやすいわ。
ということで、動かしてみる。
ちゃんと、pic.cのpic_do_pending_ints(I32_bit, oldipl, frame);に入って、pic_dispatchでis->is_funcの関数ポインタを呼び出してくれればオッケー。
なのだが、wmt_tmrのattachメッセージを出したところで止まる。
デバッグメッセージをあちこちに埋め込んで、block/unblockが期待通りに動いているかを見たりする。
unblockの前にblockが呼ばれていたりして不可解な現象に遭遇する。
それはそうか、unblockのレジスタ操作をした瞬間に割り込み処理に飛べばblock処理が動き、blockのログを出した後unblockに復帰してunblockのログを出すのだから。unblockに入った瞬間にログを出せば、それなりの順序性でログを出す。割り込み処理は脳みそ使うなぁ。
動かしていると、すかっとrootデバイスを聞くところまで進んだり、wmt_tmrのattachで止まったりする。
もしかして、キーをバシバシ叩いていれば割り込みが入ってattachで止まっているんじゃないかなと思い、何度か試行してみる。
確かにそれっぽいぞ。
もしやと思って、pic_dispatchの手前にログを埋め込んで、バシバシしながら起動。おぉ、pic_dicpatchまで動いているではないか。
ということは、
264 rv = (*is->is_func)(is->is_arg);
の部分が実行され、関数ポインタis->is_funcであるcomintr、つまりcomドライバの割り込みルーチンに飛んでいるということでは!comintr()にログを仕込む。確かに実行されている!
が、だんまりである。
comintrは長いので、ばらばらとログを埋めて再実行。なんかしらんが、無限ループにはまっている。
今さらだが、よくよく考えてみると、comドライバのレジスタとwmt_uartのレジスタは全然違っているような気がする。
たしかに、IERなどの名前は同じものがあるのだが、レジスタの並びであるとか、comにはないIrDAのレジスタがあったりと。
そもそも16550Aコンパチだというのは、誰が言ったのだ? たしかにcomドライバで文字は出たけれど、たまたまシリアル出力のためのTXレジスタがどちらも先頭アドレスにあって、たまたま出ているだけなのではないのか?
というか、16550Aコンパチと思い込んだのは自分の早とちりではないか。
そう思って、Linuxのコードとcomドライバのコードを見比べると、レジスタの使いっぷりが全然違う。別物だろうこれは。
おいちょっとまて、これってシリアルコンソールドライバを全部自分で作らないとダメなのか? matchとattachぐらい書けば、あとはcomドライバで面倒見てくれると思っていたから、ここまで頑張れたのに。
シリアルコンソールドライバを自前実装している奴らは、1,000行とか2,000行とかあるんだけど。
自前シリアルコンソールドライバを見つけては絶望していたのだが、sys/arch/arm/s3c2xx0/sscom.c#1850を眺めていて気になるコメントが。
1850 /* 1851 * Following are all routines needed for SSCOM to act as console 1852 */ん? 以下はコンソールとして動かすのに必要なすべてのルーチンである、と言っている?
なんか、cngetc, cnputc, cnpollcとattach/detachだけでよさそう。んー、つまりこれは割り込みベースじゃなくって、ポーリングベースで動かすためのミニマムセットなのか?
まてよ、この名前ってどっかでみたぞ。これってcomドライバにもあった。というか、出力ルーチンでタイムアウトを削ったのってcnputcじゃなかったっけ?
もしかすると、割り込みベースでコンソールを動かすことをあきらめたら、俺でも実装できるんじゃ? cnputcはもうあるようなもの(レジスタに値書き込むだけ)だし、ビジーループで待てば、文字も詰まらないはず?
ふーむ。方針を変更して、FIFOだのDMAだの難しいことはやらず、ポーリングベースで動かせるんだろうか?
じゃぁ、sys/dev/cons.c#cngetcを読んでいるところを調べてみるか。
なんだ、実態は同じところにあるsys/dev/cons.c#cngetsnじゃないか。これは、複数文字をgetcするってことだよな。じゃぁ、cngetsnはどこから呼ばれているのかな。
init_mainで/sbin/initって入力するところとroot device, dump device, file systemきいてくるところだけだ。そこだけポーリングモードで入力できても、だめじゃん。
やっぱり、ぜんぶシリアルコンソールドライバを作らないといけないのか。
まぁ、でもすこしでも入力が動くと楽しそうだから、まずはcnシリーズを作ってみましょうか。
コメント(0件)
- TB-URL http://www.tokuda.net/diary/0834/tb/