From: Waldemar Kozaczuk <[email protected]>
Committer: Waldemar Kozaczuk <[email protected]>
Branch: master

serial console: refactor common logic to allow re-use when implementing mmio 
version

This patch extracts generic logic of serial console into a base class
isa-serial-basee. The specializations like isa-serial
(and mmio-isa-serial in later patch) implement relevant static methods
- read_byte() and write_byte() to provide specific way of
reading and writing a byte.

Signed-off-by: Waldemar Kozaczuk <[email protected]>
Message-Id: <[email protected]>

---
diff --git a/Makefile b/Makefile
--- a/Makefile
+++ b/Makefile
@@ -776,6 +776,7 @@ drivers += drivers/line-discipline.o
 drivers += drivers/clock.o
 drivers += drivers/clock-common.o
 drivers += drivers/clockevent.o
+drivers += drivers/isa-serial-base.o
 drivers += core/elf.o
 drivers += drivers/random.o
 drivers += drivers/zfs.o
diff --git a/drivers/isa-serial-base.cc b/drivers/isa-serial-base.cc
--- a/drivers/isa-serial-base.cc
+++ b/drivers/isa-serial-base.cc
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2020 Waldemar Kozaczuk.
+ *
+ * This work is open source software, licensed under the terms of the
+ * BSD license as described in the LICENSE file in the top-level directory.
+ */
+
+#include "isa-serial-base.hh"
+
+namespace console {
+
+// UART registers, offsets to ioport:
+enum regs {
+    IER = 1,    // Interrupt Enable Register
+    FCR = 2,    // FIFO Control Register
+    LCR = 3,    // Line Control Register
+    MCR = 4,    // Modem Control Register
+    LSR = 5,    // Line Control Register
+    MSR = 6,    // Modem Status Register
+    SCR = 7,    // Scratch Register
+    DLL = 0,    // Divisor Latch LSB Register
+    DLM = 1,    // Divisor Latch MSB Register
+};
+
+enum lcr {
+    // When bit 7 (DLAB) of LCR is set to 1, the two registers 0 and 1
+    // change their meaning and become two bytes controlling the baud rate
+    DLAB     = 0x80,    // Divisor Latch Access Bit in LCR register
+    LEN_8BIT = 3,
+};
+
+// Various bits of the Line Status Register
+enum lsr {
+    RECEIVE_DATA_READY  = 0x1,
+    OVERRUN             = 0x2,
+    PARITY_ERROR        = 0x4,
+    FRAME_ERROR         = 0x8,
+    BREAK_INTERRUPT     = 0x10,
+    TRANSMIT_HOLD_EMPTY = 0x20,
+    TRANSMIT_EMPTY      = 0x40,
+    FIFO_ERROR          = 0x80,
+};
+
+// Various bits of the Modem Control Register
+enum mcr {
+    DTR                 = 0x1,
+    RTS                 = 0x2,
+    AUX_OUTPUT_1        = 0x4,
+    AUX_OUTPUT_2        = 0x8,
+    LOOPBACK_MODE       = 0x16,
+};
+
+void isa_serial_console_base::common_early_init()
+{
+    // Set the UART speed to to 115,200 bps, This is done by writing 1,0 to
+    // Divisor Latch registers, but to access these we need to temporarily
+    // set the Divisor Latch Access Bit (DLAB) on the LSR register, because
+    // the UART has fewer ports than registers...
+    write_byte(lcr::LEN_8BIT | lcr::DLAB, regs::LCR);
+    write_byte(1, regs::DLL);
+    write_byte(0, regs::DLM);
+    write_byte(lcr::LEN_8BIT, regs::LCR);
+
+    //  interrupt threshold
+    write_byte(0, regs::FCR);
+
+    // disable interrupts
+    write_byte(0, regs::IER);
+
+    // Most physical UARTs need the MCR AUX_OUTPUT_2 bit set to 1 for
+    // interrupts to be generated. QEMU doesn't bother checking this
+    // bit, but interestingly VMWare does, so we must set it.
+    write_byte(mcr::AUX_OUTPUT_2, regs::MCR);
+}
+
+void isa_serial_console_base::write(const char *str, size_t len)
+{
+    while (len-- > 0)
+        putchar(*str++);
+}
+
+bool isa_serial_console_base::input_ready()
+{
+    u8 val = read_byte(regs::LSR);
+    // On VMWare hosts without a serial port, this register always
+    // returns 0xff.  Just ignore it instead of spinning incessantly.
+    return (val != 0xff && (val & lsr::RECEIVE_DATA_READY));
+}
+
+char isa_serial_console_base::readch()
+{
+    u8 val;
+    char letter;
+
+    do {
+        val = read_byte(regs::LSR);
+    } while (!(val & (lsr::RECEIVE_DATA_READY | lsr::OVERRUN | 
lsr::PARITY_ERROR | lsr::FRAME_ERROR)));
+
+    letter = read_byte(0);
+
+    return letter;
+}
+
+void isa_serial_console_base::putchar(const char ch)
+{
+    u8 val;
+
+    do {
+        val = read_byte(regs::LSR);
+    } while (!(val & lsr::TRANSMIT_HOLD_EMPTY));
+
+    write_byte(ch, 0);
+}
+
+void isa_serial_console_base::enable_interrupt()
+{
+    // enable interrupts
+    write_byte(1, regs::IER);
+}
+
+}
diff --git a/drivers/isa-serial-base.hh b/drivers/isa-serial-base.hh
--- a/drivers/isa-serial-base.hh
+++ b/drivers/isa-serial-base.hh
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2020 Waldemar Kozaczuk.
+ *
+ * This work is open source software, licensed under the terms of the
+ * BSD license as described in the LICENSE file in the top-level directory.
+ */
+
+#ifndef DRIVERS_ISA_SERIAL_BASE_HH
+#define DRIVERS_ISA_SERIAL_BASE_HH
+
+#include "console-driver.hh"
+#include <osv/pci.hh>
+#include <osv/sched.hh>
+#include <osv/interrupt.hh>
+
+namespace console {
+
+class isa_serial_console_base : public console_driver {
+public:
+    virtual void write(const char *str, size_t len);
+    virtual void flush() {}
+    virtual bool input_ready() override;
+    virtual char readch();
+protected:
+    static void common_early_init();
+    static u8 read_byte(int);
+    static void write_byte(u8, int);
+    void enable_interrupt();
+private:
+    void putchar(const char ch);
+};
+}
+
+#endif
diff --git a/drivers/isa-serial.cc b/drivers/isa-serial.cc
--- a/drivers/isa-serial.cc
+++ b/drivers/isa-serial.cc
@@ -9,113 +9,17 @@
 
 namespace console {
 
-// UART registers, offsets to ioport:
-enum regs {
-    IER = 1,    // Interrupt Enable Register
-    FCR = 2,    // FIFO Control Register
-    LCR = 3,    // Line Control Register
-    MCR = 4,    // Modem Control Register
-    LSR = 5,    // Line Control Register
-    MSR = 6,    // Modem Status Register
-    SCR = 7,    // Scratch Register
-    DLL = 0,    // Divisor Latch LSB Register
-    DLM = 1,    // Divisor Latch MSB Register
+u8 isa_serial_console_base::read_byte(int reg) {
+    return pci::inb(isa_serial_console::ioport + reg);
 };
 
-enum lcr {
-    // When bit 7 (DLAB) of LCR is set to 1, the two registers 0 and 1
-    // change their meaning and become two bytes controlling the baud rate
-    DLAB     = 0x80,    // Divisor Latch Access Bit in LCR register
-    LEN_8BIT = 3,
-};
-
-// Various bits of the Line Status Register
-enum lsr {
-    RECEIVE_DATA_READY  = 0x1,
-    OVERRUN             = 0x2,
-    PARITY_ERROR        = 0x4,
-    FRAME_ERROR         = 0x8,
-    BREAK_INTERRUPT     = 0x10,
-    TRANSMIT_HOLD_EMPTY = 0x20,
-    TRANSMIT_EMPTY      = 0x40,
-    FIFO_ERROR          = 0x80,
-};
-
-// Various bits of the Modem Control Register
-enum mcr {
-    DTR                 = 0x1,
-    RTS                 = 0x2,
-    AUX_OUTPUT_1        = 0x4,
-    AUX_OUTPUT_2        = 0x8,
-    LOOPBACK_MODE       = 0x16,
+void isa_serial_console_base::write_byte(u8 val, int reg) {
+    pci::outb(val, isa_serial_console::ioport + reg);
 };
 
 void isa_serial_console::early_init()
 {
-    // Set the UART speed to to 115,200 bps, This is done by writing 1,0 to
-    // Divisor Latch registers, but to access these we need to temporarily
-    // set the Divisor Latch Access Bit (DLAB) on the LSR register, because
-    // the UART has fewer ports than registers...
-    pci::outb(lcr::LEN_8BIT | lcr::DLAB, ioport + regs::LCR);
-    pci::outb(1, ioport + regs::DLL);
-    pci::outb(0, ioport + regs::DLM);
-    pci::outb(lcr::LEN_8BIT, ioport + regs::LCR);
-
-    //  interrupt threshold
-    pci::outb(0, ioport + regs::FCR);
-
-    // disable interrupts
-    pci::outb(0, ioport + regs::IER);
-
-    // Most physical UARTs need the MCR AUX_OUTPUT_2 bit set to 1 for
-    // interrupts to be generated. QEMU doesn't bother checking this
-    // bit, but interestingly VMWare does, so we must set it.
-    pci::outb(mcr::AUX_OUTPUT_2, ioport + regs::MCR);
-}
-
-void isa_serial_console::write(const char *str, size_t len)
-{
-    while (len-- > 0)
-        putchar(*str++);
-}
-
-bool isa_serial_console::input_ready()
-{
-    u8 val = pci::inb(ioport + regs::LSR);
-    // On VMWare hosts without a serial port, this register always
-    // returns 0xff.  Just ignore it instead of spinning incessantly.
-    return (val != 0xff && (val & lsr::RECEIVE_DATA_READY));
-}
-
-char isa_serial_console::readch()
-{
-    u8 val;
-    char letter;
-
-    do {
-        val = pci::inb(ioport + regs::LSR);
-    } while (!(val & (lsr::RECEIVE_DATA_READY | lsr::OVERRUN | 
lsr::PARITY_ERROR | lsr::FRAME_ERROR)));
-
-    letter = pci::inb(ioport);
-
-    return letter;
-}
-
-void isa_serial_console::putchar(const char ch)
-{
-    u8 val;
-
-    do {
-        val = pci::inb(ioport + regs::LSR);
-    } while (!(val & lsr::TRANSMIT_HOLD_EMPTY));
-
-    pci::outb(ch, ioport);
-}
-
-void isa_serial_console::enable_interrupt()
-{
-    // enable interrupts
-    pci::outb(1, ioport + regs::IER);
+    common_early_init();
 }
 
 void isa_serial_console::dev_start() {
diff --git a/drivers/isa-serial.hh b/drivers/isa-serial.hh
--- a/drivers/isa-serial.hh
+++ b/drivers/isa-serial.hh
@@ -8,30 +8,19 @@
 #ifndef DRIVERS_ISA_SERIAL_HH
 #define DRIVERS_ISA_SERIAL_HH
 
-#include "console-driver.hh"
-#include <osv/pci.hh>
-#include <osv/sched.hh>
-#include <osv/interrupt.hh>
+#include "isa-serial-base.hh"
 
 namespace console {
 
-class isa_serial_console : public console_driver {
+class isa_serial_console : public isa_serial_console_base {
 public:
     static void early_init();
-    virtual void write(const char *str, size_t len);
-    virtual void flush() {}
-    virtual bool input_ready() override;
-    virtual char readch();
+    static const u16 ioport = 0x3f8;
 private:
     std::unique_ptr<gsi_edge_interrupt> _irq;
-    static const u16 ioport = 0x3f8;
-
     virtual void dev_start();
-    void enable_interrupt();
-    static void putchar(const char ch);
     virtual const char *thread_name() { return "isa-serial-input"; }
 };
-
 }
 
 #endif

-- 
You received this message because you are subscribed to the Google Groups "OSv 
Development" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/osv-dev/000000000000a2f00a05a8c47356%40google.com.

Reply via email to