diff options
Diffstat (limited to 'kernel/uart.c')
-rw-r--r-- | kernel/uart.c | 92 |
1 files changed, 92 insertions, 0 deletions
diff --git a/kernel/uart.c b/kernel/uart.c new file mode 100644 index 0000000..3a5cdc4 --- /dev/null +++ b/kernel/uart.c @@ -0,0 +1,92 @@ +// +// low-level driver routines for 16550a UART. +// + +#include "types.h" +#include "param.h" +#include "memlayout.h" +#include "riscv.h" +#include "spinlock.h" +#include "proc.h" +#include "defs.h" + +// the UART control registers are memory-mapped +// at address UART0. this macro returns the +// address of one of the registers. +#define Reg(reg) ((volatile unsigned char *)(UART0 + reg)) + +// the UART control registers. +// some have different meanings for +// read vs write. +// http://byterunner.com/16550.html +#define RHR 0 // receive holding register (for input bytes) +#define THR 0 // transmit holding register (for output bytes) +#define IER 1 // interrupt enable register +#define FCR 2 // FIFO control register +#define ISR 2 // interrupt status register +#define LCR 3 // line control register +#define LSR 5 // line status register + +#define ReadReg(reg) (*(Reg(reg))) +#define WriteReg(reg, v) (*(Reg(reg)) = (v)) + +void +uartinit(void) +{ + // disable interrupts. + WriteReg(IER, 0x00); + + // special mode to set baud rate. + WriteReg(LCR, 0x80); + + // LSB for baud rate of 38.4K. + WriteReg(0, 0x03); + + // MSB for baud rate of 38.4K. + WriteReg(1, 0x00); + + // leave set-baud mode, + // and set word length to 8 bits, no parity. + WriteReg(LCR, 0x03); + + // reset and enable FIFOs. + WriteReg(FCR, 0x07); + + // enable receive interrupts. + WriteReg(IER, 0x01); +} + +// write one output character to the UART. +void +uartputc(int c) +{ + // wait for Transmit Holding Empty to be set in LSR. + while((ReadReg(LSR) & (1 << 5)) == 0) + ; + WriteReg(THR, c); +} + +// read one input character from the UART. +// return -1 if none is waiting. +int +uartgetc(void) +{ + if(ReadReg(LSR) & 0x01){ + // input data is ready. + return ReadReg(RHR); + } else { + return -1; + } +} + +// trap.c calls here when the uart interrupts. +void +uartintr(void) +{ + while(1){ + int c = uartgetc(); + if(c == -1) + break; + consoleintr(c); + } +} |