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 <[email protected]> --- 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 _______________________________________________ Grub-devel mailing list [email protected] https://lists.gnu.org/mailman/listinfo/grub-devel
