1 #include "devices/serial.h"
3 #include "devices/16550a.h"
4 #include "devices/intq.h"
5 #include "devices/timer.h"
6 #include "threads/io.h"
7 #include "threads/interrupt.h"
8 #include "threads/synch.h"
9 #include "threads/thread.h"
11 /* Transmission mode. */
12 static enum { UNINIT, POLL, QUEUE } mode;
14 /* Data to be transmitted. */
15 static struct intq txq;
17 static void set_serial (int bps, int bits, enum parity_type parity, int stop);
18 static void write_ier (void);
19 static intr_handler_func serial_interrupt;
21 /* Initializes the serial port device for polling mode.
22 Polling mode busy-waits for the serial port to become free
23 before writing to it. It's slow, but until interrupts have
24 been initialized it's all we can do. */
26 serial_init_poll (void)
28 ASSERT (mode == UNINIT);
29 outb (IER_REG, 0); /* Turn off all interrupts. */
30 outb (FCR_REG, 0); /* Disable FIFO. */
31 set_serial (9600, 8, NONE, 1); /* 9600 bps, N-8-1. */
32 outb (MCR_REG, 8); /* Turn on OUT2 output line. */
36 /* Initializes the serial port device for queued interrupt-driven
37 I/O. With interrupt-driven I/O we don't waste CPU time
38 waiting for the serial device to become ready. */
40 serial_init_queue (void)
42 ASSERT (mode == POLL);
43 intq_init (&txq, "serial xmit");
44 intr_register (0x20 + 4, 0, INTR_OFF, serial_interrupt, "serial");
48 /* Sends BYTE to the serial port. */
50 serial_putc (uint8_t byte)
52 if (mode == POLL || intr_context ())
54 /* Poll the serial port until it's ready for a byte, and
56 while ((inb (LSR_REG) & LSR_THRE) == 0)
62 /* Lock the queue, add a byte, and update the interrupt
65 intq_putc (&txq, byte);
71 /* Configures the serial port for BPS bits per second, BITS bits
72 per byte, the given PARITY, and STOP stop bits. */
74 set_serial (int bps, int bits, enum parity_type parity, int stop)
76 int baud_base = 1843200 / 16; /* Base rate of 16550A. */
77 uint16_t divisor = baud_base / bps; /* Clock rate divisor. */
80 outb (LCR_REG, make_lcr (bits, parity, stop, false, true));
83 outb (LS_REG, divisor & 0xff);
84 outb (MS_REG, divisor >> 8);
87 outb (LCR_REG, make_lcr (bits, parity, stop, false, false));
90 /* Update interrupt enable register.
91 If our transmit queue is empty, turn off transmit interrupt. */
95 outb (IER_REG, intq_empty (&txq) ? 0 : IER_XMIT);
98 /* Serial interrupt handler.
99 As long as we have a byte to transmit,
100 and the hardware is ready to accept a byte for transmission,
102 Then update interrupt enable register based on queue
105 serial_interrupt (struct intr_frame *f UNUSED)
107 while (!intq_empty (&txq) && (inb (LSR_REG) & LSR_THRE) != 0)
108 outb (THR_REG, intq_getc (&txq));