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)40void 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)59void 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)68void Serial_Interrupt(void *arg) 69 { 70 kprintf("Serial interrupt!\n"); 71 } 72 Serial_HasData()73bool Serial_HasData() 74 { 75 return (inb(base + UART_OFFSET_LSR) & 0x01) != 0; 76 } 77 Serial_Getc()78char 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)87void 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)102void Serial_Puts(const char *str) 103 { 104 const char *p = str; 105 while (*p != '\0') 106 Serial_Putc(*p++); 107 } 108 109