X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Fdevices%2Fserial.c;h=d92a87ce1540be2af42940622491a4a28be078c2;hb=615bf3b3d2a8573ed6fb9ddc0055745e163ac999;hp=d1a4eca21295f003b2d1aa0acaff936a3f14a161;hpb=f8c3387bc9d7f7280c3b6f3626826e21ca584af0;p=pintos-anon diff --git a/src/devices/serial.c b/src/devices/serial.c index d1a4eca..d92a87c 100644 --- a/src/devices/serial.c +++ b/src/devices/serial.c @@ -1,20 +1,54 @@ #include "devices/serial.h" #include -#include "devices/16550a.h" #include "devices/intq.h" #include "devices/timer.h" #include "threads/io.h" #include "threads/interrupt.h" #include "threads/synch.h" #include "threads/thread.h" - + +/* Register definitions for the 16550A UART used in PCs. + The 16550A has a lot more going on than shown here, but this + is all we need. + + Refer to [PC16650D] for hardware information. */ + +/* I/O port base address for the first serial port. */ +#define IO_BASE 0x3f8 + +/* DLAB=0 registers. */ +#define RBR_REG (IO_BASE + 0) /* Receiver Buffer Reg. (read-only). */ +#define THR_REG (IO_BASE + 0) /* Transmitter Holding Reg. (write-only). */ +#define IER_REG (IO_BASE + 1) /* Interrupt Enable Reg. (read-only). */ +#define FCR_REG (IO_BASE + 2) /* FIFO Control Reg. (write-only). */ +#define LCR_REG (IO_BASE + 3) /* Line Control Register. */ +#define MCR_REG (IO_BASE + 4) /* MODEM Control Register. */ +#define LSR_REG (IO_BASE + 5) /* Line Status Register (read-only). */ + +/* DLAB=1 registers. */ +#define LS_REG (IO_BASE + 0) /* Divisor Latch (LSB). */ +#define MS_REG (IO_BASE + 1) /* Divisor Latch (MSB). */ + +/* Interrupt Enable Register bits. */ +#define IER_XMIT 0x02 /* Interrupt when transmit finishes. */ + +/* Line Control Register bits. */ +#define LCR_N81 0x03 /* No parity, 8 data bits, 1 stop bit. */ +#define LCR_DLAB 0x80 /* Divisor Latch Access Bit (DLAB). */ + +/* MODEM Control Register. */ +#define MCR_OUT2 0x08 /* Output line 2. */ + +/* Line Status Register. */ +#define LSR_THRE 0x20 /* THR Empty. */ + /* Transmission mode. */ static enum { UNINIT, POLL, QUEUE } mode; /* Data to be transmitted. */ static struct intq txq; -static void set_serial (int bps, int bits, enum parity_type parity, int stop); +static void set_serial (int bps); static void putc_poll (uint8_t); static void write_ier (void); static intr_handler_func serial_interrupt; @@ -29,9 +63,9 @@ serial_init_poll (void) ASSERT (mode == UNINIT); outb (IER_REG, 0); /* Turn off all interrupts. */ outb (FCR_REG, 0); /* Disable FIFO. */ - set_serial (9600, 8, NONE, 1); /* 9600 bps, N-8-1. */ - outb (MCR_REG, 8); /* Turn on OUT2 output line. */ - intq_init (&txq, "serial xmit"); + set_serial (115200); /* 115.2 kbps, N-8-1. */ + outb (MCR_REG, MCR_OUT2); /* Turn on OUT2 output line. */ + intq_init (&txq); mode = POLL; } @@ -42,7 +76,7 @@ void serial_init_queue (void) { ASSERT (mode == POLL); - intr_register (0x20 + 4, 0, INTR_OFF, serial_interrupt, "serial"); + intr_register_ext (0x20 + 4, serial_interrupt, "serial"); mode = QUEUE; } @@ -89,24 +123,25 @@ serial_flush (void) putc_poll (intq_getc (&txq)); intr_set_level (old_level); } - -/* Configures the serial port for BPS bits per second, BITS bits - per byte, the given PARITY, and STOP stop bits. */ + +/* Configures the serial port for BPS bits per second. */ static void -set_serial (int bps, int bits, enum parity_type parity, int stop) +set_serial (int bps) { int baud_base = 1843200 / 16; /* Base rate of 16550A. */ uint16_t divisor = baud_base / bps; /* Clock rate divisor. */ + ASSERT (bps >= 300 && bps <= 115200); + /* Enable DLAB. */ - outb (LCR_REG, make_lcr (bits, parity, stop, false, true)); + outb (LCR_REG, LCR_N81 | LCR_DLAB); /* Set baud rate. */ outb (LS_REG, divisor & 0xff); outb (MS_REG, divisor >> 8); /* Reset DLAB. */ - outb (LCR_REG, make_lcr (bits, parity, stop, false, false)); + outb (LCR_REG, LCR_N81); } /* Update interrupt enable register. @@ -117,7 +152,6 @@ write_ier (void) outb (IER_REG, intq_empty (&txq) ? 0 : IER_XMIT); } - /* Polls the serial port until it's ready, and then transmits BYTE. */ static void