summaryrefslogtreecommitdiff
path: root/src/kernel/serial.c
diff options
context:
space:
mode:
authorAndreas Baumann <mail@andreasbaumann.cc>2017-06-10 21:26:24 +0200
committerAndreas Baumann <mail@andreasbaumann.cc>2017-06-10 21:26:24 +0200
commitd6d1bdfefafff50b7b6d15d218c0a188570be541 (patch)
tree15ee8de727d0be5d126efda146b2879de0a72773 /src/kernel/serial.c
parenteea5bf4b859eb56c5772c58ca54937a90a10e7ee (diff)
downloadabaos-d6d1bdfefafff50b7b6d15d218c0a188570be541.tar.gz
abaos-d6d1bdfefafff50b7b6d15d218c0a188570be541.tar.bz2
some big renames into subdirs of aspects
updated README removed size_t in sys/types.h and sys/types.h itself, size_t is in stddef.h
Diffstat (limited to 'src/kernel/serial.c')
-rw-r--r--src/kernel/serial.c121
1 files changed, 121 insertions, 0 deletions
diff --git a/src/kernel/serial.c b/src/kernel/serial.c
new file mode 100644
index 0000000..c5a6d95
--- /dev/null
+++ b/src/kernel/serial.c
@@ -0,0 +1,121 @@
+#include "serial.h"
+#include "string.h"
+#include "stdlib.h"
+
+// 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_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_line_status );
+ } while( ( status & LSR_THRE ) == 0 );
+
+ port8_write( &serial->port_transmit, c );
+}
+
+void serial_put_string( serial_t *serial, const char *s )
+{
+ for( size_t i = 0; i < strlen( s ); i++ ) {
+ serial_put_char( serial, s[i] );
+ }
+}
+
+void serial_put_newline( serial_t *serial )
+{
+ serial_put_char( serial, '\r' );
+ serial_put_char( serial, '\n' );
+}