summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/LINKS.TODO4
-rw-r--r--src/kernel.c2
-rw-r--r--src/serial.c127
-rw-r--r--src/serial.h8
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 );