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]>
---
 Makefile                                      |   1 +
 drivers/{isa-serial.cc => isa-serial-base.cc} |  47 ++++----
 drivers/{isa-serial.hh => isa-serial-base.hh} |  23 ++--
 drivers/isa-serial.cc                         | 106 +-----------------
 drivers/isa-serial.hh                         |  17 +--
 5 files changed, 40 insertions(+), 154 deletions(-)
 copy drivers/{isa-serial.cc => isa-serial-base.cc} (70%)
 copy drivers/{isa-serial.hh => isa-serial-base.hh} (54%)

diff --git a/Makefile b/Makefile
index 20ddf3b1..99923a34 100644
--- 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.cc b/drivers/isa-serial-base.cc
similarity index 70%
copy from drivers/isa-serial.cc
copy to drivers/isa-serial-base.cc
index b20b30f3..a8e30f0d 100644
--- a/drivers/isa-serial.cc
+++ b/drivers/isa-serial-base.cc
@@ -1,11 +1,11 @@
 /*
- * Copyright (C) 2013 Cloudius Systems, Ltd.
+ * 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.hh"
+#include "isa-serial-base.hh"
 
 namespace console {
 
@@ -50,77 +50,72 @@ enum mcr {
     LOOPBACK_MODE       = 0x16,
 };
 
-void isa_serial_console::early_init()
+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...
-    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);
+    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
-    pci::outb(0, ioport + regs::FCR);
+    write_byte(0, regs::FCR);
 
     // disable interrupts
-    pci::outb(0, ioport + regs::IER);
+    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.
-    pci::outb(mcr::AUX_OUTPUT_2, ioport + regs::MCR);
+    write_byte(mcr::AUX_OUTPUT_2, regs::MCR);
 }
 
-void isa_serial_console::write(const char *str, size_t len)
+void isa_serial_console_base::write(const char *str, size_t len)
 {
     while (len-- > 0)
         putchar(*str++);
 }
 
-bool isa_serial_console::input_ready()
+bool isa_serial_console_base::input_ready()
 {
-    u8 val = pci::inb(ioport + regs::LSR);
+    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::readch()
+char isa_serial_console_base::readch()
 {
     u8 val;
     char letter;
 
     do {
-        val = pci::inb(ioport + regs::LSR);
+        val = read_byte(regs::LSR);
     } while (!(val & (lsr::RECEIVE_DATA_READY | lsr::OVERRUN | 
lsr::PARITY_ERROR | lsr::FRAME_ERROR)));
 
-    letter = pci::inb(ioport);
+    letter = read_byte(0);
 
     return letter;
 }
 
-void isa_serial_console::putchar(const char ch)
+void isa_serial_console_base::putchar(const char ch)
 {
     u8 val;
 
     do {
-        val = pci::inb(ioport + regs::LSR);
+        val = read_byte(regs::LSR);
     } while (!(val & lsr::TRANSMIT_HOLD_EMPTY));
 
-    pci::outb(ch, ioport);
+    write_byte(ch, 0);
 }
 
-void isa_serial_console::enable_interrupt()
+void isa_serial_console_base::enable_interrupt()
 {
     // enable interrupts
-    pci::outb(1, ioport + regs::IER);
-}
-
-void isa_serial_console::dev_start() {
-    _irq.reset(new gsi_edge_interrupt(4, [&] { _thread->wake(); }));
-    enable_interrupt();
+    write_byte(1, regs::IER);
 }
 
 }
diff --git a/drivers/isa-serial.hh b/drivers/isa-serial-base.hh
similarity index 54%
copy from drivers/isa-serial.hh
copy to drivers/isa-serial-base.hh
index e31d125a..88055b43 100644
--- a/drivers/isa-serial.hh
+++ b/drivers/isa-serial-base.hh
@@ -1,12 +1,12 @@
 /*
- * Copyright (C) 2013 Cloudius Systems, Ltd.
+ * 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_HH
-#define DRIVERS_ISA_SERIAL_HH
+#ifndef DRIVERS_ISA_SERIAL_BASE_HH
+#define DRIVERS_ISA_SERIAL_BASE_HH
 
 #include "console-driver.hh"
 #include <osv/pci.hh>
@@ -15,23 +15,20 @@
 
 namespace console {
 
-class isa_serial_console : public console_driver {
+class isa_serial_console_base : public console_driver {
 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();
-private:
-    std::unique_ptr<gsi_edge_interrupt> _irq;
-    static const u16 ioport = 0x3f8;
-
-    virtual void dev_start();
+protected:
+    static void common_early_init();
+    static u8 read_byte(int);
+    static void write_byte(u8, int);
     void enable_interrupt();
-    static void putchar(const char ch);
-    virtual const char *thread_name() { return "isa-serial-input"; }
+private:
+    void putchar(const char ch);
 };
-
 }
 
 #endif
diff --git a/drivers/isa-serial.cc b/drivers/isa-serial.cc
index b20b30f3..5e2b8bbf 100644
--- 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
index e31d125a..d7908be2 100644
--- 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
-- 
2.25.1

-- 
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/20200622041353.24880-1-jwkozaczuk%40gmail.com.

Reply via email to