From 01583e527be792eaf8ffe1c0544da2c8746db5c8 Mon Sep 17 00:00:00 2001 From: sbosse Date: Mon, 14 Oct 2024 23:07:43 +0200 Subject: [PATCH] Mon 14 Oct 23:06:38 CEST 2024 --- kernel/serial.c | 162 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 162 insertions(+) create mode 100644 kernel/serial.c diff --git a/kernel/serial.c b/kernel/serial.c new file mode 100644 index 0000000..b01c2de --- /dev/null +++ b/kernel/serial.c @@ -0,0 +1,162 @@ +/* +Copyright (C) 2016-2019 The University of Notre Dame +This software is distributed under the GNU General Public License. +See the file LICENSE for details. +*/ + +// Derived from: https://wiki.osdev.org/Serial_Ports#Example_Code +// For more info: +// https://wiki.osdev.org/Serial_Ports +// http://www.webcitation.org/5ugQv5JOw + +#include "kernel/types.h" +#include "ioports.h" +#include "string.h" +#include "device.h" + +#define COM1 0x3f8 +#define COM2 0x2F8 +#define COM3 0x3E8 +#define COM4 0x2E8 + +#define SERIAL_DATA 0 // If DLAB disabled in LCR + +#define SERIAL_IRQ_ENABLE 1 // If DLAB disabled in LCR +#define SERIAL_IRQ_DATA_AVAILABILE (0x01 << 0) +#define SERIAL_IRQ_TRASMITTER_EMPTY (0x01 << 1) +#define SERIAL_IRQ_ERROR (0x01 << 2) +#define SERIAL_IRQ_STATUS_CHANGE (0x01 << 3) + +#define SERIAL_DIVISOR_LO 0 // If DLAB enabled in LCR + +#define SERIAL_DIVISOR_HI 1 // If DLAB enabled in LCR + +#define SERIAL_FCR 2 +#define SERIAL_FIFO_ENABLE (0x01 << 0) +#define SERIAL_FIFO_CLEAR_RECIEVER (0x01 << 1) +#define SERIAL_FIFO_CLEAR_TRANSMITTER (0x01 << 2) +#define SERIAL_FIFO_DMA_MODE (0x01 << 3) +#define SERIAL_TRIGGER_LEVEL0 (0x01 << 6) +#define SERIAL_TRIGGER_LEVEL1 (0x01 << 7) + +#define SERIAL_LCR 3 +#define SERIAL_CHARLEN_START (0x01 << 0) +#define SERIAL_STOP_BITS (0x01 << 2) +#define SERIAL_DLAB_ENABLE (0x01 << 3) + +#define SERIAL_MCR 4 +#define SERIAL_DATA_TERMINAL_READY (0x01 << 0) +#define SERIAL_REQUEST_TO_SEND (0x01 << 1) +#define SERIAL_AUX_OUT1 (0x01 << 2) +#define SERIAL_AUX_OUT2 (0x01 << 3) + +#define SERIAL_LSR 5 +#define SERIAL_DATA_AVAILABLE (0x01 << 0) +#define SERIAL_TRANSMIT_EMPTY (0x01 << 5) + +#define SERIAL_MSR 6 + +#define SERIAL_SCRATCH 7 + +static const int serial_ports[4] = { COM1, COM2, COM3, COM4 }; + +static void serial_init_port(int port) +{ + //Disable iterrupts + outb(0x00, port + SERIAL_IRQ_ENABLE); + //Enable DLAB(set baud rate divisor) + outb(SERIAL_DLAB_ENABLE, port + SERIAL_LCR); + //Set divisor to 3(lo byte) 38400 baud + outb(0x03, port + SERIAL_DIVISOR_LO); + //(hi byte) + outb(0x00, port + SERIAL_DIVISOR_HI); + //8 bits, no parity, one stop bit + outb(SERIAL_CHARLEN_START * 3, port + SERIAL_LCR); + //Enable FIFO, clear them, with 14 - byte threshold + outb(SERIAL_FIFO_ENABLE | SERIAL_FIFO_CLEAR_RECIEVER | SERIAL_FIFO_CLEAR_TRANSMITTER | SERIAL_TRIGGER_LEVEL0 | SERIAL_TRIGGER_LEVEL1, port + SERIAL_FCR); + //IRQs enabled, RTS / DSR set + outb(SERIAL_DATA_TERMINAL_READY | SERIAL_REQUEST_TO_SEND | SERIAL_AUX_OUT2, port + SERIAL_MCR); +} + +static int serial_received(int port) +{ + return inb(port + SERIAL_LSR) & SERIAL_DATA_AVAILABLE; +} + +static int is_transmit_empty(int port) +{ + return inb(port + SERIAL_LSR) & SERIAL_TRANSMIT_EMPTY; +} + +static int is_valid_port(uint8_t port_no) +{ + return port_no < sizeof(serial_ports) / sizeof(int); +} + +char serial_read(uint8_t port_no) +{ + if(!is_valid_port(port_no)) + return -1; + + while(serial_received(serial_ports[port_no]) == 0); + return inb(serial_ports[port_no]); +} + +int serial_write(uint8_t port_no, char a) +{ + if(!is_valid_port(port_no)) + return -1; + + while(is_transmit_empty(serial_ports[port_no]) == 0); + outb(a, serial_ports[port_no]); + return 0; +} + +int serial_device_probe( int unit, int *blocksize, int *nblocks, char *info ) +{ + if(unit<0 || unit>3) return 0; + serial_init_port(serial_ports[unit]); + *blocksize = 1; + *nblocks = 0; + strcpy(info,"serial"); + return 1; +} + +int serial_device_read( int unit, void *data, int length, int offset ) +{ + int i; + char *cdata = data; + for(i=0;i