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