From 4f670845ff9ab6c48bcb5f7bf4d4ef6dc3c3064b Mon Sep 17 00:00:00 2001 From: manuel Date: Tue, 27 Mar 2012 11:51:08 +0200 Subject: reorganize file structure to match the upstream requirements --- pintos-progos/devices/serial.c | 228 ----------------------------------------- 1 file changed, 228 deletions(-) delete mode 100644 pintos-progos/devices/serial.c (limited to 'pintos-progos/devices/serial.c') diff --git a/pintos-progos/devices/serial.c b/pintos-progos/devices/serial.c deleted file mode 100644 index df770a7..0000000 --- a/pintos-progos/devices/serial.c +++ /dev/null @@ -1,228 +0,0 @@ -#include "devices/serial.h" -#include -#include "devices/input.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.. */ - -/* DLAB=1 registers. */ -#define LS_REG (IO_BASE + 0) /* Divisor Latch (LSB). */ -#define MS_REG (IO_BASE + 1) /* Divisor Latch (MSB). */ - -/* DLAB-insensitive registers. */ -#define IIR_REG (IO_BASE + 2) /* Interrupt Identification 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). */ - -/* Interrupt Enable Register bits. */ -#define IER_RECV 0x01 /* Interrupt when data received. */ -#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_DR 0x01 /* Data Ready: received data byte is in RBR. */ -#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); -static void putc_poll (uint8_t); -static void write_ier (void); -static intr_handler_func serial_interrupt; - -/* Initializes the serial port device for polling mode. - Polling mode busy-waits for the serial port to become free - before writing to it. It's slow, but until interrupts have - been initialized it's all we can do. */ -static void -init_poll (void) -{ - ASSERT (mode == UNINIT); - outb (IER_REG, 0); /* Turn off all interrupts. */ - outb (FCR_REG, 0); /* Disable FIFO. */ - set_serial (9600); /* 9.6 kbps, N-8-1. */ - outb (MCR_REG, MCR_OUT2); /* Required to enable interrupts. */ - intq_init (&txq); - mode = POLL; -} - -/* Initializes the serial port device for queued interrupt-driven - I/O. With interrupt-driven I/O we don't waste CPU time - waiting for the serial device to become ready. */ -void -serial_init_queue (void) -{ - enum intr_level old_level; - - if (mode == UNINIT) - init_poll (); - ASSERT (mode == POLL); - - intr_register_ext (0x20 + 4, serial_interrupt, "serial"); - mode = QUEUE; - old_level = intr_disable (); - write_ier (); - intr_set_level (old_level); -} - -/* Sends BYTE to the serial port. */ -void -serial_putc (uint8_t byte) -{ - enum intr_level old_level = intr_disable (); - - if (mode != QUEUE) - { - /* If we're not set up for interrupt-driven I/O yet, - use dumb polling to transmit a byte. */ - if (mode == UNINIT) - init_poll (); - putc_poll (byte); - } - else - { - /* Otherwise, queue a byte and update the interrupt enable - register. */ - if (old_level == INTR_OFF && intq_full (&txq)) - { - /* Interrupts are off and the transmit queue is full. - If we wanted to wait for the queue to empty, - we'd have to reenable interrupts. - That's impolite, so we'll send a character via - polling instead. */ - putc_poll (intq_getc (&txq)); - } - - intq_putc (&txq, byte); - write_ier (); - } - - intr_set_level (old_level); -} - -/* Flushes anything in the serial buffer out the port in polling - mode. */ -void -serial_flush (void) -{ - enum intr_level old_level = intr_disable (); - while (!intq_empty (&txq)) - putc_poll (intq_getc (&txq)); - intr_set_level (old_level); -} - -/* The fullness of the input buffer may have changed. Reassess - whether we should block receive interrupts. - Called by the input buffer routines when characters are added - to or removed from the buffer. */ -void -serial_notify (void) -{ - ASSERT (intr_get_level () == INTR_OFF); - if (mode == QUEUE) - write_ier (); -} - -/* Configures the serial port for BPS bits per second. */ -static void -set_serial (int bps) -{ - int base_rate = 1843200 / 16; /* Base rate of 16550A, in Hz. */ - uint16_t divisor = base_rate / bps; /* Clock rate divisor. */ - - ASSERT (bps >= 300 && bps <= 115200); - - /* Enable DLAB. */ - outb (LCR_REG, LCR_N81 | LCR_DLAB); - - /* Set data rate. */ - outb (LS_REG, divisor & 0xff); - outb (MS_REG, divisor >> 8); - - /* Reset DLAB. */ - outb (LCR_REG, LCR_N81); -} - -/* Update interrupt enable register. */ -static void -write_ier (void) -{ - uint8_t ier = 0; - - ASSERT (intr_get_level () == INTR_OFF); - - /* Enable transmit interrupt if we have any characters to - transmit. */ - if (!intq_empty (&txq)) - ier |= IER_XMIT; - - /* Enable receive interrupt if we have room to store any - characters we receive. */ - if (!input_full ()) - ier |= IER_RECV; - - outb (IER_REG, ier); -} - -/* Polls the serial port until it's ready, - and then transmits BYTE. */ -static void -putc_poll (uint8_t byte) -{ - ASSERT (intr_get_level () == INTR_OFF); - - while ((inb (LSR_REG) & LSR_THRE) == 0) - continue; - outb (THR_REG, byte); -} - -/* Serial interrupt handler. */ -static void -serial_interrupt (struct intr_frame *f UNUSED) -{ - /* Inquire about interrupt in UART. Without this, we can - occasionally miss an interrupt running under QEMU. */ - inb (IIR_REG); - - /* As long as we have room to receive a byte, and the hardware - has a byte for us, receive a byte. */ - while (!input_full () && (inb (LSR_REG) & LSR_DR) != 0) - input_putc (inb (RBR_REG)); - - /* As long as we have a byte to transmit, and the hardware is - ready to accept a byte for transmission, transmit a byte. */ - while (!intq_empty (&txq) && (inb (LSR_REG) & LSR_THRE) != 0) - outb (THR_REG, intq_getc (&txq)); - - /* Update interrupt enable register based on queue status. */ - write_ier (); -} -- cgit v1.2.3