1 
2 #include <stdbool.h>
3 #include <stdint.h>
4 
5 #include <sys/kassert.h>
6 #include <sys/irq.h>
7 
8 #include "ioport.h"
9 #include "sercons.h"
10 
11 #define COM1_BASE		0x3F8
12 #define COM2_BASE		0x2F8
13 #define COM3_BASE		0x3E8
14 #define COM4_BASE		0x2E8
15 
16 #define COM1_IRQ		4
17 #define COM2_IRQ		3
18 #define COM3_IRQ		4
19 #define COM4_IRQ		3
20 
21 // Inputs
22 #define UART_OFFSET_DATA	0   /* Data Register */
23 #define UART_OFFSET_IER		1   /* Interrupt Enable Register */
24 #define UART_OFFSET_IIR		2   /* Interrupt Identification & FIFO Control */
25 #define UART_OFFSET_LCR		3   /* Line Control Register */
26 #define UART_LCR_DLAB		0x80
27 #define UART_LCR_8N1		0x03
28 #define UART_OFFSET_MCR		4   /* Modem Control Register */
29 #define UART_OFFSET_LSR		5   /* Line Status Register */
30 #define UART_OFFSET_MSR		6   /* Modem Status Register */
31 #define UART_OFFSET_SR		7   /* Scratch Register */
32 
33 #define UART_OFFSET_DIVLO	0   /* Divisors DLAB == 1 */
34 #define UART_OFFSET_DIVHI	1
35 
36 static IRQHandler handler;
37 static uint16_t base;
38 static uint8_t irq;
39 
Serial_Init(void)40 void Serial_Init(void)
41 {
42     base = COM1_BASE;
43     irq = COM1_IRQ;
44 
45     // Disable interrupts
46     outb(base + UART_OFFSET_IER, 0);
47 
48     // Enable DLAB
49     outb(base + UART_OFFSET_LCR, UART_LCR_DLAB);
50     outb(base + UART_OFFSET_DIVLO, 1); // 115200 Baud
51     outb(base + UART_OFFSET_DIVLO, 0);
52     outb(base + UART_OFFSET_LCR, UART_LCR_8N1);
53 
54     // Enable interrupts
55     outb(base + UART_OFFSET_IIR, 0xC7);
56     outb(base + UART_OFFSET_MCR, 0x0B);
57 }
58 
Serial_LateInit(void)59 void Serial_LateInit(void)
60 {
61     handler.irq = irq;
62     handler.cb = &Serial_Interrupt;
63     handler.arg = NULL;
64 
65     IRQ_Register(irq, &handler);
66 }
67 
Serial_Interrupt(void * arg)68 void Serial_Interrupt(void *arg)
69 {
70     kprintf("Serial interrupt!\n");
71 }
72 
Serial_HasData()73 bool Serial_HasData()
74 {
75     return (inb(base + UART_OFFSET_LSR) & 0x01) != 0;
76 }
77 
Serial_Getc()78 char Serial_Getc()
79 {
80     while ((inb(base + UART_OFFSET_LSR) & 0x01) == 0)
81     {
82 	// Timeout!
83     }
84     return inb(base + UART_OFFSET_DATA);
85 }
86 
Serial_Putc(char ch)87 void Serial_Putc(char ch)
88 {
89     while ((inb(base + UART_OFFSET_LSR) & 0x20) == 0)
90     {
91 	// Timeout!
92     }
93     outb(base + UART_OFFSET_DATA, ch);
94 
95     if (ch == '\b') {
96 	Serial_Putc(0x1B);
97 	Serial_Putc('[');
98 	Serial_Putc('P');
99     }
100 }
101 
Serial_Puts(const char * str)102 void Serial_Puts(const char *str)
103 {
104     const char *p = str;
105     while (*p != '\0')
106 	Serial_Putc(*p++);
107 }
108 
109