summaryrefslogtreecommitdiff
path: root/kernel/uart.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/uart.c')
-rw-r--r--kernel/uart.c92
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);
+ }
+}