grub-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH 1/3] serial: Add abstractions to ns8250 driver


From: Matthias Lange
Subject: [PATCH 1/3] serial: Add abstractions to ns8250 driver
Date: Wed, 22 Feb 2017 11:09:25 +0100

The current implementation of the ns8250 serial driver is closely
tied to use IO ports. In order to support other ns8250 compatible
UART implementations in the future, a set of abstractions for
register/IO port access is needed.

This change introduces two things. Firstly it adds two functions to
the grub_serial_driver structure that a driver can implement to
abstract access to the UART hardware. Secondly it introduces a
grub_serial_board structure to encapsulate properties of the
specific UART hardware.

Further this change adapts the ns8250 serial driver to use the new
set of available abstractions.

Signed-off-by: Matthias Lange <address@hidden>
---
 grub-core/term/ns8250.c | 51 ++++++++++++++++++++++++++++++++-----------------
 include/grub/serial.h   |  9 +++++++++
 2 files changed, 42 insertions(+), 18 deletions(-)

diff --git a/grub-core/term/ns8250.c b/grub-core/term/ns8250.c
index 39809d0..acc05eb 100644
--- a/grub-core/term/ns8250.c
+++ b/grub-core/term/ns8250.c
@@ -44,17 +44,28 @@ static int dead_ports = 0;
 #define DEFAULT_BASE_CLOCK 115200
 #endif
 
+static inline unsigned char
+io_port_read (struct grub_serial_port *port, grub_addr_t reg)
+{
+  return grub_inb (port->port + reg);
+}
+
+static inline void
+io_port_write (struct grub_serial_port *port, unsigned char value, grub_addr_t 
reg)
+{
+  grub_outb (value, port->port + reg);
+}
 
 /* Convert speed to divisor.  */
 static unsigned short
-serial_get_divisor (const struct grub_serial_port *port __attribute__ 
((unused)),
+serial_get_divisor (const struct grub_serial_port *port,
                    const struct grub_serial_config *config)
 {
   grub_uint32_t base_clock;
   grub_uint32_t divisor;
   grub_uint32_t actual_speed, error;
 
-  base_clock = config->base_clock ? (config->base_clock >> 4) : 
DEFAULT_BASE_CLOCK;
+  base_clock = config->base_clock ? (config->base_clock >> 4) : 
port->board.base_baud;
 
   divisor = (base_clock + (config->speed / 2)) / config->speed;
   if (config->speed == 0)
@@ -94,43 +105,43 @@ do_real_config (struct grub_serial_port *port)
   divisor = serial_get_divisor (port, &port->config);
 
   /* Turn off the interrupt.  */
-  grub_outb (0, port->port + UART_IER);
+  port->driver->reg_write (port, 0, UART_IER);
 
   /* Set DLAB.  */
-  grub_outb (UART_DLAB, port->port + UART_LCR);
+  port->driver->reg_write (port, UART_DLAB, UART_LCR);
 
   /* Set the baud rate.  */
-  grub_outb (divisor & 0xFF, port->port + UART_DLL);
-  grub_outb (divisor >> 8, port->port + UART_DLH);
+  port->driver->reg_write (port, divisor & 0xFF, UART_DLL);
+  port->driver->reg_write (port, divisor >> 8, UART_DLH);
 
   /* Set the line status.  */
   status |= (parities[port->config.parity]
             | (port->config.word_len - 5)
             | stop_bits[port->config.stop_bits]);
-  grub_outb (status, port->port + UART_LCR);
+  port->driver->reg_write (port, status, UART_LCR);
 
   if (port->config.rtscts)
     {
       /* Enable the FIFO.  */
-      grub_outb (UART_ENABLE_FIFO_TRIGGER1, port->port + UART_FCR);
+      port->driver->reg_write (port, UART_ENABLE_FIFO_TRIGGER1, UART_FCR);
 
       /* Turn on DTR and RTS.  */
-      grub_outb (UART_ENABLE_DTRRTS, port->port + UART_MCR);
+      port->driver->reg_write (port, UART_ENABLE_DTRRTS, UART_MCR);
     }
   else
     {
       /* Enable the FIFO.  */
-      grub_outb (UART_ENABLE_FIFO_TRIGGER14, port->port + UART_FCR);
+      port->driver->reg_write (port, UART_ENABLE_FIFO_TRIGGER14, UART_FCR);
 
       /* Turn on DTR, RTS, and OUT2.  */
-      grub_outb (UART_ENABLE_DTRRTS | UART_ENABLE_OUT2, port->port + UART_MCR);
+      port->driver->reg_write (port, UART_ENABLE_DTRRTS | UART_ENABLE_OUT2, 
UART_MCR);
     }
 
   /* Drain the input buffer.  */
   endtime = grub_get_time_ms () + 1000;
-  while (grub_inb (port->port + UART_LSR) & UART_DATA_READY)
+  while (port->driver->reg_read (port, UART_LSR) & UART_DATA_READY)
     {
-      grub_inb (port->port + UART_RX);
+      port->driver->reg_read (port, UART_RX);
       if (grub_get_time_ms () > endtime)
        {
          port->broken = 1;
@@ -146,8 +157,8 @@ static int
 serial_hw_fetch (struct grub_serial_port *port)
 {
   do_real_config (port);
-  if (grub_inb (port->port + UART_LSR) & UART_DATA_READY)
-    return grub_inb (port->port + UART_RX);
+  if (port->driver->reg_read (port, UART_LSR) & UART_DATA_READY)
+    return port->driver->reg_read (port, UART_RX);
 
   return -1;
 }
@@ -167,7 +178,7 @@ serial_hw_put (struct grub_serial_port *port, const int c)
   else
     endtime = grub_get_time_ms () + 200;
   /* Wait until the transmitter holding register is empty.  */
-  while ((grub_inb (port->port + UART_LSR) & UART_EMPTY_TRANSMITTER) == 0)
+  while ((port->driver->reg_read (port, UART_LSR) & UART_EMPTY_TRANSMITTER) == 
0)
     {
       if (grub_get_time_ms () > endtime)
        {
@@ -180,7 +191,7 @@ serial_hw_put (struct grub_serial_port *port, const int c)
   if (port->broken)
     port->broken--;
 
-  grub_outb (c, port->port + UART_TX);
+  port->driver->reg_write (port, c, UART_TX);
 }
 
 /* Initialize a serial device. PORT is the port number for a serial device.
@@ -228,7 +239,9 @@ struct grub_serial_driver grub_ns8250_driver =
   {
     .configure = serial_hw_configure,
     .fetch = serial_hw_fetch,
-    .put = serial_hw_put
+    .put = serial_hw_put,
+    .reg_read = io_port_read,
+    .reg_write = io_port_write,
   };
 
 static char com_names[GRUB_SERIAL_PORT_NUM][20];
@@ -260,6 +273,7 @@ grub_ns8250_init (void)
        com_ports[i].name = com_names[i];
        com_ports[i].driver = &grub_ns8250_driver;
        com_ports[i].port = serial_hw_io_addr[i];
+        com_ports[i].board.base_baud = DEFAULT_BASE_CLOCK;
        err = grub_serial_config_defaults (&com_ports[i]);
        if (err)
          grub_print_error ();
@@ -312,6 +326,7 @@ grub_serial_ns8250_add_port (grub_port_t port)
   p->driver = &grub_ns8250_driver;
   grub_serial_config_defaults (p);
   p->port = port;
+  p->board.base_baud = DEFAULT_BASE_CLOCK;
   grub_serial_register (p);  
 
   return p->name;
diff --git a/include/grub/serial.h b/include/grub/serial.h
index 67379de..82d127e 100644
--- a/include/grub/serial.h
+++ b/include/grub/serial.h
@@ -43,6 +43,9 @@ struct grub_serial_driver
                           struct grub_serial_config *config);
   int (*fetch) (struct grub_serial_port *port);
   void (*put) (struct grub_serial_port *port, const int c);
+  void (*reg_write) (struct grub_serial_port *port, unsigned char value,
+                     grub_addr_t reg);
+  unsigned char (*reg_read) (struct grub_serial_port *port, grub_addr_t reg);
   void (*fini) (struct grub_serial_port *port);
 };
 
@@ -71,6 +74,11 @@ struct grub_serial_config
   int rtscts;
 };
 
+struct grub_serial_board
+{
+  unsigned base_baud;
+};
+
 struct grub_serial_port
 {
   struct grub_serial_port *next;
@@ -80,6 +88,7 @@ struct grub_serial_port
   struct grub_serial_config config;
   int configured;
   int broken;
+  struct grub_serial_board board;
 
   /* This should be void *data but since serial is useful as an early console
      when malloc isn't available it's a union.
-- 
2.7.4




reply via email to

[Prev in Thread] Current Thread [Next in Thread]