bootloader/boot/sricon.c

185 lines
4.0 KiB
C

// Serial console
#include <u.h>
#include "dat.h"
#include "fn.h"
/*
* 8250 UART and compatibles.
*/
enum {
Uart0 = 0x3F8, /* COM1 */
Uart0IRQ = 4,
Uart1 = 0x2F8, /* COM2 */
Uart1IRQ = 3,
UartFREQ = 1843200, /* 1.8432 MHz */
};
/* I/O ports */
enum {
Rbr = 0, /* Receiver Buffer (RO) */
Thr = 0, /* Transmitter Holding (WO) */
Ier = 1, /* Interrupt Enable */
Iir = 2, /* Interrupt Identification (RO) */
Fcr = 2, /* FIFO Control (WO) */
Lcr = 3, /* Line Control */
Mcr = 4, /* Modem Control */
Lsr = 5, /* Line Status */
Msr = 6, /* Modem Status */
Scr = 7, /* Scratch Pad */
Dll = 0, /* Divisor Latch Low */
Dlh = 1, /* Divisor Latch High */
};
/* Interrupt Enable Registe */
enum { /* Ier */
Erda = 0x01, /* Enable Received Data Available */
Ethre = 0x02, /* Enable Thr Empty */
Erls = 0x04, /* Enable Receiver Line Status */
Ems = 0x08, /* Enable Modem Status */
};
/* Interrupt Identification Register */
enum { /* Iir */
Ims = 0x00, /* Ms interrupt */
Ip = 0x01, /* Interrupt Pending (not) */
Ithre = 0x02, /* Thr Empty */
Irda = 0x04, /* Received Data Available */
Irls = 0x06, /* Receiver Line Status */
Ictoi = 0x0C, /* Character Time-out Indication */
IirMASK = 0x3F,
Ifena = 0xC0, /* FIFOs enabled */
};
/* FIFO Control Registe */
enum { /* Fcr */
FIFOena = 0x01, /* FIFO enable */
FIFOrclr= 0x02, /* clear Rx FIFO */
FIFOtclr= 0x04, /* clear Tx FIFO */
FIFO1 = 0x00, /* Rx FIFO trigger level 1 byte */
FIFO4 = 0x40, /* 4 bytes */
FIFO8 = 0x80, /* 8 bytes */
FIFO14 = 0xC0, /* 14 bytes */
};
/* Line Control Registe */
enum { /* Lcr */
Wls5 = 0x00, /* Word Length Select 5 bits/byte */
Wls6 = 0x01, /* 6 bits/byte */
Wls7 = 0x02, /* 7 bits/byte */
Wls8 = 0x03, /* 8 bits/byte */
WlsMASK = 0x03,
Stb = 0x04, /* 2 stop bits */
Pen = 0x08, /* Parity Enable */
Eps = 0x10, /* Even Parity Select */
Stp = 0x20, /* Stick Parity */
Brk = 0x40, /* Break */
Dlab = 0x80, /* Divisor Latch Access Bit */
};
/* Modem Control Register */
enum { /* Mcr */
Dtr = 0x01, /* Data Terminal Ready */
Rts = 0x02, /* Ready To Send */
Out1 = 0x04, /* no longer in use */
Ie = 0x08, /* IRQ Enable */
Dm = 0x10, /* Diagnostic Mode loopback */
};
/* Line Status Register */
enum { /* Lsr */
Dr = 0x01, /* Data Ready */
Oe = 0x02, /* Overrun Error */
Pe = 0x04, /* Parity Error */
Fe = 0x08, /* Framing Error */
Bi = 0x10, /* Break Interrupt */
Thre = 0x20, /* Thr Empty */
Temt = 0x40, /* Tramsmitter Empty */
FIFOerr = 0x80, /* error in receiver FIFO */
};
/* Modem Status Register */
enum { /* Msr */
Dcts = 0x01, /* Delta Cts */
Ddsr = 0x02, /* Delta Dsr */
Teri = 0x04, /* Trailing Edge of Ri */
Ddcd = 0x08, /* Delta Dcd */
Cts = 0x10, /* Clear To Send */
Dsr = 0x20, /* Data Set Ready */
Ri = 0x40, /* Ring Indicator */
Dcd = 0x80, /* Data Set Ready */
};
static int setbaud(int dev, int baud);
// probe serial console
// https://stanislavs.org/helppc/int_11.html
// https://wiki.osdev.org/Serial_Ports
int
comprobe(ConDev *d)
{
register int n;
__asm volatile("int $0x31" : "=a" (n):: "%ecx", "%edx", "cc");
n >>= 9;
n &= 0b111;
if(n == 0)
return 0;
for(int i = 0; i < n; ++i)
print("Found com %d\n", i);
d->pri = 0;
d->dev = makedev(8, 0);
return n;
}
// init serial consone
void
cominit(ConDev *d)
{
long t = getsecs() + 1;
outb(Uart0+Ier, 0);
setbaud(d->dev, 9600);
outb(Uart0+Mcr, Dtr|Rts);
outb(Uart0+Fcr, FIFOena|FIFOrclr|FIFOtclr|FIFO1);
inb(Uart0+Iir); // check fifo
// wait
for(ulong i = 1; ((i % 1000)!=0) && getsecs() < t; ++i)
;
// drain input buffer
while(inb(Uart0+Lsr) & Dr)
inb(Uart0+Rbr);
}
static int
setbaud(int dev, int baud)
{
int port = Uart0;
ulong div;
if(baud <= 0)
return -1;
/* Divisor = 115200/baud */
div = (UartFREQ+8*baud-1)/(16*baud);
outb(port+Lcr, Dlab);
outb(port+Dlh, div>>8);
outb(port+Dll, div);
outb(port+Lcr, Wls8);
return 0;
}
int
comgetc(int dev)
{
while((inb(Uart0+Lsr) & Dr) == 0)
;
return inb(Uart0+Rbr) & 0xff;
}
void
computc(int dev, int c)
{
while((inb(Uart0+Lsr) & Thre) == 0)
;
outb(Uart0+Thr, c);
}