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/