From 64731d077e23be2261eb644eb523df4b9e3a2f21 Mon Sep 17 00:00:00 2001 From: sbosse Date: Mon, 9 Dec 2024 20:42:06 +0100 Subject: [PATCH] Mon 9 Dec 20:40:44 CET 2024 --- kernel/serial.c | 84 +++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 68 insertions(+), 16 deletions(-) diff --git a/kernel/serial.c b/kernel/serial.c index b01c2de..feec21e 100644 --- a/kernel/serial.c +++ b/kernel/serial.c @@ -4,13 +4,16 @@ 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 +/* Derived from: https://wiki.osdev.org/Serial_Ports#Example_Code + For more info: + https://wiki.osdev.org/Serial_Ports + http://www.webcitation.org/5ugQv5JOw + TODO: Interrupt support; polling IO is not a good idea for carbon free air +*/ #include "kernel/types.h" #include "ioports.h" +#include "interrupt.h" #include "string.h" #include "device.h" @@ -33,11 +36,13 @@ See the file LICENSE for details. #define SERIAL_FCR 2 #define SERIAL_FIFO_ENABLE (0x01 << 0) -#define SERIAL_FIFO_CLEAR_RECIEVER (0x01 << 1) +#define SERIAL_FIFO_CLEAR_RECEIVER (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_TRIGGER_LEVEL0 (0x00 << 6) // 1 byte in FIFO +#define SERIAL_TRIGGER_LEVEL1 (0x01 << 6) // 4 bytes +#define SERIAL_TRIGGER_LEVEL2 (0x10 << 6) // 8 bytes +#define SERIAL_TRIGGER_LEVEL3 (0x11 << 6) // 14 bytes #define SERIAL_LCR 3 #define SERIAL_CHARLEN_START (0x01 << 0) @@ -58,11 +63,21 @@ See the file LICENSE for details. #define SERIAL_SCRATCH 7 +// units 0,1,2,3 static const int serial_ports[4] = { COM1, COM2, COM3, COM4 }; +static const int serial_ports_irq[4] = { 4, 3, 4, 3 }; -static void serial_init_port(int port) +static void serial_interrupt(int i, int intr_code) { - //Disable iterrupts + printf("serial_interrupt %d %d\n",i,intr_code); +} + + + +static void serial_init_port(int unit) +{ + int port = serial_ports[unit]; + //Disable interrupts outb(0x00, port + SERIAL_IRQ_ENABLE); //Enable DLAB(set baud rate divisor) outb(SERIAL_DLAB_ENABLE, port + SERIAL_LCR); @@ -73,11 +88,20 @@ static void serial_init_port(int port) //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); + outb(SERIAL_FIFO_ENABLE | SERIAL_FIFO_CLEAR_RECEIVER | SERIAL_FIFO_CLEAR_TRANSMITTER | SERIAL_TRIGGER_LEVEL0 , port + SERIAL_FCR); //IRQs enabled, RTS / DSR set outb(SERIAL_DATA_TERMINAL_READY | SERIAL_REQUEST_TO_SEND | SERIAL_AUX_OUT2, port + SERIAL_MCR); + + // setup interrupt support + interrupt_register(serial_ports_irq[unit], serial_interrupt); + interrupt_enable(serial_ports_irq[unit]); + // + received data available + outb(0x01, port + SERIAL_IRQ_ENABLE); + + printf("[COM%d] serial_init_port %x: ready.\n",unit,port); } + static int serial_received(int port) { return inb(port + SERIAL_LSR) & SERIAL_DATA_AVAILABLE; @@ -93,12 +117,23 @@ static int is_valid_port(uint8_t port_no) return port_no < sizeof(serial_ports) / sizeof(int); } -char serial_read(uint8_t port_no) +int serial_read(uint8_t port_no) { if(!is_valid_port(port_no)) return -1; while(serial_received(serial_ports[port_no]) == 0); + printf("[COM%d]\n",port_no); + return inb(serial_ports[port_no]); +} + +int serial_read_nonblock(uint8_t port_no) +{ + if(!is_valid_port(port_no)) + return -1; + + if (serial_received(serial_ports[port_no]) == 0) return -1; + printf("[COM%d]\n",port_no); return inb(serial_ports[port_no]); } @@ -115,7 +150,9 @@ int serial_write(uint8_t port_no, char a) 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]); + // TODO probing for real hardware + // reinit, second time (first time in serial_init, but needed to register the device) + serial_init_port(unit); *blocksize = 1; *nblocks = 0; strcpy(info,"serial"); @@ -124,10 +161,24 @@ int serial_device_probe( int unit, int *blocksize, int *nblocks, char *info ) int serial_device_read( int unit, void *data, int length, int offset ) { - int i; + int i,byte; char *cdata = data; for(i=0;i