[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