]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/omap/uarti8250.c
pc, pc64: warn when running out of conf.mem[] entries in meminit()
[plan9front.git] / sys / src / 9 / omap / uarti8250.c
1 /*
2  * omap35 8250-like UART
3  *
4  * we ignore the first 2 uarts on the omap35 (see below) and use the
5  * third one but call it 0.
6  */
7
8 #include "u.h"
9 #include "../port/lib.h"
10 #include "mem.h"
11 #include "dat.h"
12 #include "fns.h"
13
14 enum {                                  /* registers */
15         Rbr             = 0,            /* Receiver Buffer (RO) */
16         Thr             = 0,            /* Transmitter Holding (WO) */
17         Ier             = 1,            /* Interrupt Enable */
18         Iir             = 2,            /* Interrupt Identification (RO) */
19         Fcr             = 2,            /* FIFO Control (WO) */
20         Lcr             = 3,            /* Line Control */
21         Mcr             = 4,            /* Modem Control */
22         Lsr             = 5,            /* Line Status */
23         Msr             = 6,            /* Modem Status */
24         Scr             = 7,            /* Scratch Pad */
25         Mdr             = 8,            /* Mode Def'n (omap rw) */
26 //      Usr             = 31,           /* Uart Status Register; missing in omap? */
27         Dll             = 0,            /* Divisor Latch LSB */
28         Dlm             = 1,            /* Divisor Latch MSB */
29 };
30
31 enum {                                  /* Usr */
32         Busy            = 0x01,
33 };
34
35 enum {                                  /* Ier */
36         Erda            = 0x01,         /* Enable Received Data Available */
37         Ethre           = 0x02,         /* Enable Thr Empty */
38         Erls            = 0x04,         /* Enable Receiver Line Status */
39         Ems             = 0x08,         /* Enable Modem Status */
40 };
41
42 enum {                                  /* Iir */
43         Ims             = 0x00,         /* Ms interrupt */
44         Ip              = 0x01,         /* Interrupt Pending (not) */
45         Ithre           = 0x02,         /* Thr Empty */
46         Irda            = 0x04,         /* Received Data Available */
47         Irls            = 0x06,         /* Receiver Line Status */
48         Ictoi           = 0x0C,         /* Character Time-out Indication */
49         IirMASK         = 0x3F,
50         Ifena           = 0xC0,         /* FIFOs enabled */
51 };
52
53 enum {                                  /* Fcr */
54         FIFOena         = 0x01,         /* FIFO enable */
55         FIFOrclr        = 0x02,         /* clear Rx FIFO */
56         FIFOtclr        = 0x04,         /* clear Tx FIFO */
57 //      FIFOdma         = 0x08,
58         FIFO1           = 0x00,         /* Rx FIFO trigger level 1 byte */
59         FIFO4           = 0x40,         /*      4 bytes */
60         FIFO8           = 0x80,         /*      8 bytes */
61         FIFO14          = 0xC0,         /*      14 bytes */
62 };
63
64 enum {                                  /* Lcr */
65         Wls5            = 0x00,         /* Word Length Select 5 bits/byte */
66         Wls6            = 0x01,         /*      6 bits/byte */
67         Wls7            = 0x02,         /*      7 bits/byte */
68         Wls8            = 0x03,         /*      8 bits/byte */
69         WlsMASK         = 0x03,
70         Stb             = 0x04,         /* 2 stop bits */
71         Pen             = 0x08,         /* Parity Enable */
72         Eps             = 0x10,         /* Even Parity Select */
73         Stp             = 0x20,         /* Stick Parity */
74         Brk             = 0x40,         /* Break */
75         Dlab            = 0x80,         /* Divisor Latch Access Bit */
76 };
77
78 enum {                                  /* Mcr */
79         Dtr             = 0x01,         /* Data Terminal Ready */
80         Rts             = 0x02,         /* Ready To Send */
81         Out1            = 0x04,         /* no longer in use */
82 //      Ie              = 0x08,         /* IRQ Enable (cd_sts_ch on omap) */
83         Dm              = 0x10,         /* Diagnostic Mode loopback */
84 };
85
86 enum {                                  /* Lsr */
87         Dr              = 0x01,         /* Data Ready */
88         Oe              = 0x02,         /* Overrun Error */
89         Pe              = 0x04,         /* Parity Error */
90         Fe              = 0x08,         /* Framing Error */
91         Bi              = 0x10,         /* Break Interrupt */
92         Thre            = 0x20,         /* Thr Empty */
93         Temt            = 0x40,         /* Transmitter Empty */
94         FIFOerr         = 0x80,         /* error in receiver FIFO */
95 };
96
97 enum {                                  /* Msr */
98         Dcts            = 0x01,         /* Delta Cts */
99         Ddsr            = 0x02,         /* Delta Dsr */
100         Teri            = 0x04,         /* Trailing Edge of Ri */
101         Ddcd            = 0x08,         /* Delta Dcd */
102         Cts             = 0x10,         /* Clear To Send */
103         Dsr             = 0x20,         /* Data Set Ready */
104         Ri              = 0x40,         /* Ring Indicator */
105         Dcd             = 0x80,         /* Carrier Detect */
106 };
107
108 enum {                                  /* Mdr */
109         Modemask        = 7,
110         Modeuart        = 0,
111 };
112
113
114 typedef struct Ctlr {
115         u32int* io;
116         int     irq;
117         int     tbdf;
118         int     iena;
119         int     poll;
120
121         uchar   sticky[Scr+1];
122
123         Lock;
124         int     hasfifo;
125         int     checkfifo;
126         int     fena;
127 } Ctlr;
128
129 extern PhysUart i8250physuart;
130
131 static Ctlr i8250ctlr[] = {
132 {       .io     = (u32int*)PHYSCONS,            /* UART3 in TI terminology */
133         .irq    = 74,
134         .tbdf   = -1,
135         .poll   = 0, },
136
137 /* these exist, but I don't think they're connected to anything external */
138 //{     .io     = (u32int*)PHYSUART0,
139 //      .irq    = 72,
140 //      .tbdf   = -1,
141 //      .poll   = 0, },
142 //
143 //{     .io     = (u32int*)PHYSUART1,
144 //      .irq    = 73,
145 //      .tbdf   = -1,
146 //      .poll   = 0, },
147 };
148
149 static Uart i8250uart[] = {
150 {       .regs   = &i8250ctlr[0], /* not [2] */
151         .name   = "COM3",
152         .freq   = 3686000,      /* Not used, we use the global i8250freq */
153         .phys   = &i8250physuart,
154         .console= 1,
155         .next   = nil, },
156
157 /* these exist, but I don't think they're connected to anything external */
158 //{     .regs   = &i8250ctlr[0],
159 //      .name   = "COM1",
160 //      .freq   = 3686000,      /* Not used, we use the global i8250freq */
161 //      .phys   = &i8250physuart,
162 //      .special= 0,
163 //      .next   = &i8250uart[1], },
164 //
165 //{     .regs   = &i8250ctlr[1],
166 //      .name   = "COM2",
167 //      .freq   = 3686000,      /* Not used, we use the global i8250freq */
168 //      .phys   = &i8250physuart,
169 //      .special= 0,
170 //      .next   = &i8250uart[2], },
171 };
172
173 #define csr8r(c, r)     ((c)->io[r])
174 #define csr8w(c, r, v)  ((c)->io[r] = (c)->sticky[r] | (v), coherence())
175 #define csr8o(c, r, v)  ((c)->io[r] = (v), coherence())
176
177 static long
178 i8250status(Uart* uart, void* buf, long n, long offset)
179 {
180         char *p;
181         Ctlr *ctlr;
182         uchar ier, lcr, mcr, msr;
183
184         ctlr = uart->regs;
185         p = malloc(READSTR);
186         mcr = ctlr->sticky[Mcr];
187         msr = csr8r(ctlr, Msr);
188         ier = ctlr->sticky[Ier];
189         lcr = ctlr->sticky[Lcr];
190         snprint(p, READSTR,
191                 "b%d c%d d%d e%d l%d m%d p%c r%d s%d i%d\n"
192                 "dev(%d) type(%d) framing(%d) overruns(%d) "
193                 "berr(%d) serr(%d)%s%s%s%s\n",
194
195                 uart->baud,
196                 uart->hup_dcd,
197                 (msr & Dsr) != 0,
198                 uart->hup_dsr,
199                 (lcr & WlsMASK) + 5,
200                 (ier & Ems) != 0,
201                 (lcr & Pen) ? ((lcr & Eps) ? 'e': 'o'): 'n',
202                 (mcr & Rts) != 0,
203                 (lcr & Stb) ? 2: 1,
204                 ctlr->fena,
205
206                 uart->dev,
207                 uart->type,
208                 uart->ferr,
209                 uart->oerr,
210                 uart->berr,
211                 uart->serr,
212                 (msr & Cts) ? " cts": "",
213                 (msr & Dsr) ? " dsr": "",
214                 (msr & Dcd) ? " dcd": "",
215                 (msr & Ri) ? " ring": ""
216         );
217         n = readstr(offset, buf, n, p);
218         free(p);
219
220         return n;
221 }
222
223 static void
224 i8250fifo(Uart* uart, int level)
225 {
226         Ctlr *ctlr;
227
228         ctlr = uart->regs;
229         if(ctlr->hasfifo == 0)
230                 return;
231
232         /*
233          * Changing the FIFOena bit in Fcr flushes data
234          * from both receive and transmit FIFOs; there's
235          * no easy way to guarantee not losing data on
236          * the receive side, but it's possible to wait until
237          * the transmitter is really empty.
238          */
239         ilock(ctlr);
240         while(!(csr8r(ctlr, Lsr) & Temt))
241                 ;
242
243         /*
244          * Set the trigger level, default is the max.
245          * value.
246          * Some UARTs require FIFOena to be set before
247          * other bits can take effect, so set it twice.
248          */
249         ctlr->fena = level;
250         switch(level){
251         case 0:
252                 break;
253         case 1:
254                 level = FIFO1|FIFOena;
255                 break;
256         case 4:
257                 level = FIFO4|FIFOena;
258                 break;
259         case 8:
260                 level = FIFO8|FIFOena;
261                 break;
262         default:
263                 level = FIFO14|FIFOena;
264                 break;
265         }
266         csr8w(ctlr, Fcr, level);
267         csr8w(ctlr, Fcr, level);
268         iunlock(ctlr);
269 }
270
271 static void
272 i8250dtr(Uart* uart, int on)
273 {
274         Ctlr *ctlr;
275
276         /*
277          * Toggle DTR.
278          */
279         ctlr = uart->regs;
280         if(on)
281                 ctlr->sticky[Mcr] |= Dtr;
282         else
283                 ctlr->sticky[Mcr] &= ~Dtr;
284         csr8w(ctlr, Mcr, 0);
285 }
286
287 static void
288 i8250rts(Uart* uart, int on)
289 {
290         Ctlr *ctlr;
291
292         /*
293          * Toggle RTS.
294          */
295         ctlr = uart->regs;
296         if(on)
297                 ctlr->sticky[Mcr] |= Rts;
298         else
299                 ctlr->sticky[Mcr] &= ~Rts;
300         csr8w(ctlr, Mcr, 0);
301 }
302
303 static void
304 i8250modemctl(Uart* uart, int on)
305 {
306         Ctlr *ctlr;
307
308         ctlr = uart->regs;
309         ilock(&uart->tlock);
310         if(on){
311                 ctlr->sticky[Ier] |= Ems;
312                 csr8w(ctlr, Ier, 0);
313                 uart->modem = 1;
314                 uart->cts = csr8r(ctlr, Msr) & Cts;
315         }
316         else{
317                 ctlr->sticky[Ier] &= ~Ems;
318                 csr8w(ctlr, Ier, 0);
319                 uart->modem = 0;
320                 uart->cts = 1;
321         }
322         iunlock(&uart->tlock);
323
324         /* modem needs fifo */
325         (*uart->phys->fifo)(uart, on);
326 }
327
328 static int
329 i8250parity(Uart* uart, int parity)
330 {
331         int lcr;
332         Ctlr *ctlr;
333
334         ctlr = uart->regs;
335         lcr = ctlr->sticky[Lcr] & ~(Eps|Pen);
336
337         switch(parity){
338         case 'e':
339                 lcr |= Eps|Pen;
340                 break;
341         case 'o':
342                 lcr |= Pen;
343                 break;
344         case 'n':
345                 break;
346         default:
347                 return -1;
348         }
349         ctlr->sticky[Lcr] = lcr;
350         csr8w(ctlr, Lcr, 0);
351
352         uart->parity = parity;
353
354         return 0;
355 }
356
357 static int
358 i8250stop(Uart* uart, int stop)
359 {
360         int lcr;
361         Ctlr *ctlr;
362
363         ctlr = uart->regs;
364         lcr = ctlr->sticky[Lcr] & ~Stb;
365
366         switch(stop){
367         case 1:
368                 break;
369         case 2:
370                 lcr |= Stb;
371                 break;
372         default:
373                 return -1;
374         }
375         ctlr->sticky[Lcr] = lcr;
376         csr8w(ctlr, Lcr, 0);
377
378         uart->stop = stop;
379
380         return 0;
381 }
382
383 static int
384 i8250bits(Uart* uart, int bits)
385 {
386         int lcr;
387         Ctlr *ctlr;
388
389         ctlr = uart->regs;
390         lcr = ctlr->sticky[Lcr] & ~WlsMASK;
391
392         switch(bits){
393         case 5:
394                 lcr |= Wls5;
395                 break;
396         case 6:
397                 lcr |= Wls6;
398                 break;
399         case 7:
400                 lcr |= Wls7;
401                 break;
402         case 8:
403                 lcr |= Wls8;
404                 break;
405         default:
406                 return -1;
407         }
408         ctlr->sticky[Lcr] = lcr;
409         csr8w(ctlr, Lcr, 0);
410
411         uart->bits = bits;
412
413         return 0;
414 }
415
416 static int
417 i8250baud(Uart* uart, int baud)
418 {
419 #ifdef notdef                           /* don't change the speed */
420         ulong bgc;
421         Ctlr *ctlr;
422         extern int i8250freq;   /* In the config file */
423
424         /*
425          * Set the Baud rate by calculating and setting the Baud rate
426          * Generator Constant. This will work with fairly non-standard
427          * Baud rates.
428          */
429         if(i8250freq == 0 || baud <= 0)
430                 return -1;
431         bgc = (i8250freq+8*baud-1)/(16*baud);
432
433         ctlr = uart->regs;
434         while(csr8r(ctlr, Usr) & Busy)
435                 delay(1);
436         csr8w(ctlr, Lcr, Dlab);         /* begin kludge */
437         csr8o(ctlr, Dlm, bgc>>8);
438         csr8o(ctlr, Dll, bgc);
439         csr8w(ctlr, Lcr, 0);
440 #endif
441         uart->baud = baud;
442         return 0;
443 }
444
445 static void
446 i8250break(Uart* uart, int ms)
447 {
448         Ctlr *ctlr;
449
450         if (up == nil)
451                 panic("i8250break: nil up");
452         /*
453          * Send a break.
454          */
455         if(ms <= 0)
456                 ms = 200;
457
458         ctlr = uart->regs;
459         csr8w(ctlr, Lcr, Brk);
460         tsleep(&up->sleep, return0, 0, ms);
461         csr8w(ctlr, Lcr, 0);
462 }
463
464 static void
465 emptyoutstage(Uart *uart, int n)
466 {
467         _uartputs((char *)uart->op, n);
468         uart->op = uart->oe = uart->ostage;
469 }
470
471 static void
472 i8250kick(Uart* uart)
473 {
474         int i;
475         Ctlr *ctlr;
476
477         if(/* uart->cts == 0 || */ uart->blocked)
478                 return;
479
480         if(!normalprint) {                      /* early */
481                 if (uart->op < uart->oe)
482                         emptyoutstage(uart, uart->oe - uart->op);
483                 while ((i = uartstageoutput(uart)) > 0)
484                         emptyoutstage(uart, i);
485                 return;
486         }
487
488         /* nothing more to send? then disable xmit intr */
489         ctlr = uart->regs;
490         if (uart->op >= uart->oe && qlen(uart->oq) == 0 &&
491             csr8r(ctlr, Lsr) & Temt) {
492                 ctlr->sticky[Ier] &= ~Ethre;
493                 csr8w(ctlr, Ier, 0);
494                 return;
495         }
496
497         /*
498          *  128 here is an arbitrary limit to make sure
499          *  we don't stay in this loop too long.  If the
500          *  chip's output queue is longer than 128, too
501          *  bad -- presotto
502          */
503         for(i = 0; i < 128; i++){
504                 if(!(csr8r(ctlr, Lsr) & Thre))
505                         break;
506                 if(uart->op >= uart->oe && uartstageoutput(uart) == 0)
507                         break;
508                 csr8o(ctlr, Thr, *uart->op++);          /* start tx */
509                 ctlr->sticky[Ier] |= Ethre;
510                 csr8w(ctlr, Ier, 0);                    /* intr when done */
511         }
512 }
513
514 void
515 serialkick(void)
516 {
517         uartkick(&i8250uart[CONSOLE]);
518 }
519
520 static void
521 i8250interrupt(Ureg*, void* arg)
522 {
523         Ctlr *ctlr;
524         Uart *uart;
525         int iir, lsr, old, r;
526
527         uart = arg;
528         ctlr = uart->regs;
529         for(iir = csr8r(ctlr, Iir); !(iir & Ip); iir = csr8r(ctlr, Iir)){
530                 switch(iir & IirMASK){
531                 case Ims:               /* Ms interrupt */
532                         r = csr8r(ctlr, Msr);
533                         if(r & Dcts){
534                                 ilock(&uart->tlock);
535                                 old = uart->cts;
536                                 uart->cts = r & Cts;
537                                 if(old == 0 && uart->cts)
538                                         uart->ctsbackoff = 2;
539                                 iunlock(&uart->tlock);
540                         }
541                         if(r & Ddsr){
542                                 old = r & Dsr;
543                                 if(uart->hup_dsr && uart->dsr && !old)
544                                         uart->dohup = 1;
545                                 uart->dsr = old;
546                         }
547                         if(r & Ddcd){
548                                 old = r & Dcd;
549                                 if(uart->hup_dcd && uart->dcd && !old)
550                                         uart->dohup = 1;
551                                 uart->dcd = old;
552                         }
553                         break;
554                 case Ithre:             /* Thr Empty */
555                         uartkick(uart);
556                         break;
557                 case Irda:              /* Received Data Available */
558                 case Irls:              /* Receiver Line Status */
559                 case Ictoi:             /* Character Time-out Indication */
560                         /*
561                          * Consume any received data.
562                          * If the received byte came in with a break,
563                          * parity or framing error, throw it away;
564                          * overrun is an indication that something has
565                          * already been tossed.
566                          */
567                         while((lsr = csr8r(ctlr, Lsr)) & Dr){
568                                 if(lsr & (FIFOerr|Oe))
569                                         uart->oerr++;
570                                 if(lsr & Pe)
571                                         uart->perr++;
572                                 if(lsr & Fe)
573                                         uart->ferr++;
574                                 r = csr8r(ctlr, Rbr);
575                                 if(!(lsr & (Bi|Fe|Pe)))
576                                         uartrecv(uart, r);
577                         }
578                         break;
579
580                 default:
581                         iprint("weird uart interrupt type %#2.2uX\n", iir);
582                         break;
583                 }
584         }
585 }
586
587 static void
588 i8250disable(Uart* uart)
589 {
590         Ctlr *ctlr;
591
592         /*
593          * Turn off DTR and RTS, disable interrupts and fifos.
594          */
595         (*uart->phys->dtr)(uart, 0);
596         (*uart->phys->rts)(uart, 0);
597         (*uart->phys->fifo)(uart, 0);
598
599         ctlr = uart->regs;
600         ctlr->sticky[Ier] = 0;
601         csr8w(ctlr, Ier, 0);
602
603         if(ctlr->iena != 0){
604                 if(irqdisable(ctlr->irq, i8250interrupt, uart, uart->name) == 0)
605                         ctlr->iena = 0;
606         }
607 }
608
609 static void
610 i8250enable(Uart* uart, int ie)
611 {
612         int mode;
613         Ctlr *ctlr;
614
615         if (up == nil)
616                 return;                         /* too soon */
617
618         ctlr = uart->regs;
619
620         /* omap only: set uart/irda/cir mode to uart */
621         mode = csr8r(ctlr, Mdr);
622         csr8o(ctlr, Mdr, (mode & ~Modemask) | Modeuart);
623
624         ctlr->sticky[Lcr] = Wls8;               /* no parity */
625         csr8w(ctlr, Lcr, 0);
626
627         /*
628          * Check if there is a FIFO.
629          * Changing the FIFOena bit in Fcr flushes data
630          * from both receive and transmit FIFOs; there's
631          * no easy way to guarantee not losing data on
632          * the receive side, but it's possible to wait until
633          * the transmitter is really empty.
634          * Also, reading the Iir outwith i8250interrupt()
635          * can be dangerous, but this should only happen
636          * once, before interrupts are enabled.
637          */
638         ilock(ctlr);
639         if(!ctlr->checkfifo){
640                 /*
641                  * Wait until the transmitter is really empty.
642                  */
643                 while(!(csr8r(ctlr, Lsr) & Temt))
644                         ;
645                 csr8w(ctlr, Fcr, FIFOena);
646                 if(csr8r(ctlr, Iir) & Ifena)
647                         ctlr->hasfifo = 1;
648                 csr8w(ctlr, Fcr, 0);
649                 ctlr->checkfifo = 1;
650         }
651         iunlock(ctlr);
652
653         /*
654          * Enable interrupts and turn on DTR and RTS.
655          * Be careful if this is called to set up a polled serial line
656          * early on not to try to enable interrupts as interrupt-
657          * -enabling mechanisms might not be set up yet.
658          */
659         if(ie){
660                 if(ctlr->iena == 0 && !ctlr->poll){
661                         irqenable(ctlr->irq, i8250interrupt, uart, uart->name);
662                         ctlr->iena = 1;
663                 }
664                 ctlr->sticky[Ier] = Erda;
665 //              ctlr->sticky[Mcr] |= Ie;                /* not on omap */
666                 ctlr->sticky[Mcr] = 0;
667         }
668         else{
669                 ctlr->sticky[Ier] = 0;
670                 ctlr->sticky[Mcr] = 0;
671         }
672         csr8w(ctlr, Ier, 0);
673         csr8w(ctlr, Mcr, 0);
674
675         (*uart->phys->dtr)(uart, 1);
676         (*uart->phys->rts)(uart, 1);
677
678         /*
679          * During startup, the i8259 interrupt controller is reset.
680          * This may result in a lost interrupt from the i8250 uart.
681          * The i8250 thinks the interrupt is still outstanding and does not
682          * generate any further interrupts. The workaround is to call the
683          * interrupt handler to clear any pending interrupt events.
684          * Note: this must be done after setting Ier.
685          */
686         if(ie)
687                 i8250interrupt(nil, uart);
688 }
689
690 static Uart*
691 i8250pnp(void)
692 {
693         return i8250uart;
694 }
695
696 static int
697 i8250getc(Uart* uart)
698 {
699         Ctlr *ctlr;
700
701         ctlr = uart->regs;
702         while(!(csr8r(ctlr, Lsr) & Dr))
703                 delay(1);
704         return csr8r(ctlr, Rbr);
705 }
706
707 static void
708 i8250putc(Uart* uart, int c)
709 {
710         int i;
711         Ctlr *ctlr;
712
713         if (!normalprint) {             /* too early; use brute force */
714                 int s = splhi();
715
716                 while (!(((ulong *)PHYSCONS)[Lsr] & Thre))
717                         ;
718                 ((ulong *)PHYSCONS)[Thr] = c;
719                 coherence();
720                 splx(s);
721                 return;
722         }
723
724         ctlr = uart->regs;
725         for(i = 0; !(csr8r(ctlr, Lsr) & Thre) && i < 128; i++)
726                 delay(1);
727         csr8o(ctlr, Thr, (uchar)c);
728         for(i = 0; !(csr8r(ctlr, Lsr) & Thre) && i < 128; i++)
729                 delay(1);
730 }
731
732 void
733 serialputc(int c)
734 {
735         i8250putc(&i8250uart[CONSOLE], c);
736 }
737
738 void
739 serialputs(char* s, int n)
740 {
741         _uartputs(s, n);
742 }
743
744 #ifdef notdef
745 static void
746 i8250poll(Uart* uart)
747 {
748         Ctlr *ctlr;
749
750         /*
751          * If PhysUart has a non-nil .poll member, this
752          * routine will be called from the uartclock timer.
753          * If the Ctlr .poll member is non-zero, when the
754          * Uart is enabled interrupts will not be enabled
755          * and the result is polled input and output.
756          * Not very useful here, but ports to new hardware
757          * or simulators can use this to get serial I/O
758          * without setting up the interrupt mechanism.
759          */
760         ctlr = uart->regs;
761         if(ctlr->iena || !ctlr->poll)
762                 return;
763         i8250interrupt(nil, uart);
764 }
765 #endif
766
767 PhysUart i8250physuart = {
768         .name           = "i8250",
769         .pnp            = i8250pnp,
770         .enable         = i8250enable,
771         .disable        = i8250disable,
772         .kick           = i8250kick,
773         .dobreak        = i8250break,
774         .baud           = i8250baud,
775         .bits           = i8250bits,
776         .stop           = i8250stop,
777         .parity         = i8250parity,
778         .modemctl       = i8250modemctl,
779         .rts            = i8250rts,
780         .dtr            = i8250dtr,
781         .status         = i8250status,
782         .fifo           = i8250fifo,
783         .getc           = i8250getc,
784         .putc           = i8250putc,
785 //      .poll           = i8250poll,            /* only in 9k, not 9 */
786 };
787
788 static void
789 i8250dumpregs(Ctlr* ctlr)
790 {
791         int dlm, dll;
792         int _uartprint(char*, ...);
793
794         csr8w(ctlr, Lcr, Dlab);
795         dlm = csr8r(ctlr, Dlm);
796         dll = csr8r(ctlr, Dll);
797         csr8w(ctlr, Lcr, 0);
798
799         _uartprint("dlm %#ux dll %#ux\n", dlm, dll);
800 }
801
802 Uart*   uartenable(Uart *p);
803
804 /* must call this from a process's context */
805 int
806 i8250console(void)
807 {
808         Uart *uart = &i8250uart[CONSOLE];
809
810         if (up == nil)
811                 return -1;                      /* too early */
812
813         if(uartenable(uart) != nil /* && uart->console */){
814                 // iprint("i8250console: enabling console uart\n");
815                 serialoq = uart->oq;
816                 uart->opens++;
817                 consuart = uart;
818         }
819         uartctl(uart, "b115200 l8 pn r1 s1 i1");
820         return 0;
821 }
822
823 void
824 _uartputs(char* s, int n)
825 {
826         char *e;
827
828         for(e = s+n; s < e; s++){
829                 if(*s == '\n')
830                         i8250putc(&i8250uart[CONSOLE], '\r');
831                 i8250putc(&i8250uart[CONSOLE], *s);
832         }
833 }
834
835 int
836 _uartprint(char* fmt, ...)
837 {
838         int n;
839         va_list arg;
840         char buf[PRINTSIZE];
841
842         va_start(arg, fmt);
843         n = vseprint(buf, buf+sizeof(buf), fmt, arg) - buf;
844         va_end(arg);
845         _uartputs(buf, n);
846
847         return n;
848 }