From 2b62442bfd1bcd70e7d0cc78343b5d14b691e23c Mon Sep 17 00:00:00 2001 From: Andreas Baumann Date: Wed, 7 Jun 2017 19:09:22 +0200 Subject: some cleanup in serial console initialization --- doc/LINKS.TODO | 4 ++ src/kernel.c | 2 - src/serial.c | 127 ++++++++++++++++++++++++++++++++++++++++++++------------- src/serial.h | 8 +++- 4 files changed, 108 insertions(+), 33 deletions(-) diff --git a/doc/LINKS.TODO b/doc/LINKS.TODO index 463d524..3104275 100644 --- a/doc/LINKS.TODO +++ b/doc/LINKS.TODO @@ -60,3 +60,7 @@ http://www.ics.uci.edu/~harris/ics216/pci/PCI_22.pdf assembly: NASM FASM + +serial: +http://wiki.osdev.org/Serial_Ports +http://www.sci.muni.cz/docs/pc/serport.txt diff --git a/src/kernel.c b/src/kernel.c index 9a33644..1e99e33 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -38,8 +38,6 @@ void entry( void ) console_t console; console_init( &console ); console_add_vga_output( &console, &vga ); -// TODO: breaks on real hardware, we need proper interrupt handling -// and driver implementation as for the mouse and the keyboard console_add_serial_output( &console, &serial ); // initialize the early console of the kernel diff --git a/src/serial.c b/src/serial.c index 4aeaab2..75cc243 100644 --- a/src/serial.c +++ b/src/serial.c @@ -2,22 +2,115 @@ #include "string.h" #include "stdlib.h" +#define MODEMCONTROL 4 +#define MODEMSTATUS 6 +#define SCRATCH 7 + + + +// COM1 - I/O ports +#define COM1_PORT_BASE 0x3F8 + +// RDR - Receive buffer register (on port read, if DLAB=0) +// THR - Transmitter holding register (on port write, if DLAB=0) +// DL - Divisor Latch (on port write, LSB, if DLAB=1) +#define COM1_TRANSMIT_PORT COM1_PORT_BASE + +// IER - Interrupt Enable Register (if DLAB=0) +// DL - Divisor Latch (on port write, MSB, if DLAB=1) +#define COM1_INTERRUPT_ENABLE_PORT COM1_PORT_BASE + 1 + +// IIR - Interrupt Identification Register (on read) +// FCR - FIFO Control Register (write only) +#define COM1_FIFO_CONTROL_PORT COM1_PORT_BASE + 2 + +// LCR - Line Control Register +#define COM1_LCR_PORT COM1_PORT_BASE + 3 + +// MCR - Modem Control Register +#define COM1_MCR_PORT COM1_PORT_BASE + 4 + +// LSR - Line Status Register +#define COM1_LSR_PORT COM1_PORT_BASE + 5 + +// IER - Interrupt Enable Register +#define IER_ENABLE_IRQ_DATA_READY 0x01 +#define IER_ENABLE_IRQ_WRITE_READY 0x02 +#define IER_ENABLE_IRQ_STATUS 0x04 +#define IER_ENABLE_IRQ_MODEM_STATUS 0x08 + +// LSR - Line Status Register +#define LSR_THRE 0x20 // Transmitter Holding Register Empty + +// LCR - Line Control Register +#define LCR_DATA_BITS_5 0x00 +#define LCR_DATA_BITS_6 0x01 +#define LCR_DATA_BITS_7 0x02 +#define LCR_DATA_BITS_8 0x03 +#define LCR_ONE_STOPBIT 0x00 +#define LCR_TWO_STOPBITS 0x04 +#define LCR_PARITY_ENABLE 0x08 +#define LCR_PARITY_EVEN 0x10 +#define LCR_PARITY_STICKY 0x20 +#define LCR_SET_BREAK 0x40 +#define LCR_DLAB_ENABLE 0x80 // DLAB=1/0, baud rate DL register selector + +// MCR - Modem Control Register +#define MCR_DTR_LOW 0x01 +#define MCR_DTR_RTS_LOW 0x02 +#define MCR_DTS_OUT2_LOW 0x04 +#define MCR_LOCAL_LOOPBACK 0x08 + +// baud rate helpers (division of 115200 by divisor results in baud rate) +#define BAUD_RATE_DIVISOR_115200 1 +#define BAUD_RATE_DIVISOR_57600 2 +#define BAUD_RATE_DIVISOR_38400 3 +#define BAUD_RATE_DIVISOR_19200 6 +#define BAUD_RATE_DIVISOR_14400 8 +#define BAUD_RATE_DIVISOR_9600 12 +#define BAUD_RATE_DIVISOR_4800 24 +#define BAUD_RATE_DIVISOR_2400 48 +#define BAUD_RATE_DIVISOR_1200 96 +#define BAUD_RATE_DIVISOR_300 384 + void serial_init( serial_t *serial ) { memset( serial, 0, sizeof( serial_t ) ); - port8_init( &serial->port_3F8, 0x3F8 ); - port8_init( &serial->port_3FD, 0x3FD ); + port8_init( &serial->port_transmit, COM1_TRANSMIT_PORT ); + port8_init( &serial->port_interrupt_enable, COM1_INTERRUPT_ENABLE_PORT ); + port8_init( &serial->port_fifo_control, COM1_FIFO_CONTROL_PORT ); + port8_init( &serial->port_line_control, COM1_LCR_PORT ); + port8_init( &serial->port_modem_control, COM1_MCR_PORT ); + port8_init( &serial->port_line_status, COM1_LSR_PORT ); + + // disable all interrupts + port8_write( &serial->port_interrupt_enable, 0x00 ); + + // set baud rate, enable DLAB so we can access the DL registers + port8_write( &serial->port_line_control, + LCR_DATA_BITS_8 | LCR_DLAB_ENABLE ); + port8_write( &serial->port_transmit, BAUD_RATE_DIVISOR_9600 ); + port8_write( &serial->port_interrupt_enable, 0 ); + port8_write( &serial->port_line_control, + LCR_DATA_BITS_8 ); + + // disable FIFO (16550+ only, TODO: probe?) + port8_write( &serial->port_fifo_control, 0x00 ); + + // No loopback + // TODO: more? + port8_write( &serial->port_modem_control, 0x00 ); } void serial_put_char( serial_t *serial, const char c ) { uint8_t status; do { - status = port8_read( &serial->port_3FD ); - } while( ( status & 0x20 ) == 0 ); + status = port8_read( &serial->port_line_status ); + } while( ( status & LSR_THRE ) == 0 ); - port8_write( &serial->port_3F8, c ); + port8_write( &serial->port_transmit, c ); } void serial_put_string( serial_t *serial, const char *s ) @@ -31,27 +124,3 @@ void serial_put_newline( serial_t *serial ) { serial_put_char( serial, '\n' ); } - - //~ outb(0x3FB, 0x83); /* DLAB = 1 */ - //~ outb(0x3F8, 0x0C); /* 9600 Baud */ - //~ outb(0x3F9, 0x00); - //~ outb(0x3FB, 0x03); /* DLAB = 0 */ - //~ outb(0x3F9, 0x00); /* keine Interrupts auslösen */ - //~ outb(0x3FA, 0x00); /* FIFOs deaktiviert (8250, 16450) */ - //~ outb(0x3FC, 0x00); /* Loopback deaktivieren, Aux1 & Aux2 deaktivieren */ - - //~ outb(0xe9, c); - //~ outb(0x3f8, c); - //~ while ((inb(0x3fd) & 0x20) == 0) asm("nop"); - -//~ int is_transmit_empty() { - //~ return inb(PORT + 5) & 0x20; -//~ } - -//~ void write_serial(char a) { - //~ while (is_transmit_empty() == 0); - - - //~ outb(PORT,a); -//~ } - diff --git a/src/serial.h b/src/serial.h index 9afef12..b30fe55 100644 --- a/src/serial.h +++ b/src/serial.h @@ -4,8 +4,12 @@ #include "port.h" typedef struct { - port8_t port_3F8; - port8_t port_3FD; + port8_t port_transmit; + port8_t port_interrupt_enable; + port8_t port_fifo_control; + port8_t port_line_control; + port8_t port_modem_control; + port8_t port_line_status; } serial_t; void serial_init( serial_t *serial ); -- cgit v1.2.3-54-g00ecf