#include #include #include #include #include #include #include //right now, this program is simply for debuging. //Later in development, we will hook it up to a TTY, impliment FCS, etc #define VIDEO_BUFFER PHYS_TO_VIRT(0xb8000) #define MAX_LOOPBACK_ATTEMPTS 20 #define KLOG_COM1 0 #define KLOG_COM2 1 #define KLOG_COM3 2 #define KLOG_COM4 3 #define KLOG_SCREEN 4 static int debug_output = KLOG_SCREEN; #define SERIAL_THR 0 //transmitter holding buffer #define SERIAL_RBR 1 //receiving holding buffer #define SERIAL_DLL 0 //divisor latch low byte #define SERIAL_DLH 1 //divisor latch high byte #define SERIAL_FCR 2 #define SERIAL_IIR 2 #define SERIAL_LCR 3 #define SERIAL_MCR 4 #define SERIAL_LSR 5 #define SERIAL_MSR 6 #define SERIAL_SR 7 #define COM1 0x3f8 #define COM2 0x2f8 #define COM3 0x3e8 #define COM4 0x2e8 uint16_t serial_ports[4] = {COM1, COM2, COM3, COM4}; /** enum com_ports { COM1 = 0x3f8, COM2 = 0x2f8, COM3 = 0x3e8, COM4 = 0x2e8 }; **/ static bool detect_serial(uint16_t port) { outb(port + SERIAL_FCR, 0xe7); outb(port + SERIAL_SR, 0xba); if((inb(port + SERIAL_IIR) & (1 << 6)) && (inb(port + SERIAL_SR) == 0xba)) { outb_wait(port + 1, 0x00); outb_wait(port + 2, 0x00); outb_wait(port + 3, 0x80); outb_wait(port + 0, 0x01); outb_wait(port + 1, 0x00); outb_wait(port + 3, 0x03); outb_wait(port + 2, 0xc7); outb_wait(port + 4, 0x0b); outb_wait(port + 4, 0x1e); uint8_t loopback_byte; for(int attempts = 0; attempts < MAX_LOOPBACK_ATTEMPTS; attempts++) { outb_wait(port + 0, 0xae); loopback_byte = inb(port); if(loopback_byte == 0xae) break; } if(loopback_byte != 0xae) { //you better delete this once you get tty drivers working... int a = 0 / 0; } outb_wait(port + 4, 0x0f); return true; } return false; } //this function is going to be teleted after ttys work. //but, for now, if a serial port is detected, it'll set debug_output to 0-3 (com port #). //debug_output == 4 is for screen output. void init_klog() { for(unsigned int p = 0; p < (sizeof(serial_ports) / sizeof(uint16_t)); p++) { if(detect_serial(serial_ports[p])) { debug_output = p; return; } } debug_output = KLOG_SCREEN; _putchar('\n'); } void _putchar_serial(uint16_t port, char msg) { while(!(inb(port + 5) & 0x20)); //wait for transmit to be done outb_wait(port, msg); } static unsigned int on_char = 0; static unsigned int on_line = 0; void clear_screen() { char *screen_buffer = (void *)VIDEO_BUFFER; for(unsigned int i = 0; i <= (80 * 25); i++) screen_buffer[i * 2] = ' '; on_char = 0; on_line = 0; } void next_line() { if(on_line >= 25) { on_line = 0; clear_screen(); } else { on_line++; } on_char = 0; } void move_cursor(unsigned int x, unsigned int y) { on_char = x; on_line = y; } void _putchar_screen(char msg) { if(on_char >= 80) { next_line(); } else if(msg == '\n') { next_line(); return; } *(char *)((uint64_t)VIDEO_BUFFER + ((on_line * 160) + (on_char * 2))) = msg; on_char++; } void _putchar(char character) { if(debug_output < (sizeof(serial_ports) / sizeof(uint16_t))) { _putchar_serial(serial_ports[debug_output], character); } else { _putchar_screen(character); } } /** * Set the value "0xE7" to the FCR to test the status of the FIFO flags. Read the value of the IIR to test for what flags actually got set. If Bit 6 is set Then If Bit 7 is set Then If Bit 5 is set Then UART is 16750 (64 bit fifo) Else UART is 16550A (idk why this matters, 16 bit fifo) End If Else UART is 16550 (16 bit fifo) End If Else you know the chip doesn't use FIFO, so we need to check the scratch register Set some arbitrary value like 0x2A to the Scratch Register. If the arbitrary value comes back identical UART is 16450 (idk why this matters, 1 byte at a time) Else UART is 8250 (one byte at a time) End If End If #define UART_16750 0 #define UART_16550A 1 #define UART_16550 2 #define UART_16450 3 #define UART_8250 4 #define KLOG_COM1 0 #define KLOG_COM2 1 #define KLOG_COM3 2 #define KLOG_COM4 3 #define KLOG_SCREEN 4 * 5 // 5 leaves enough space for com ports **/