[PATCH v2 4/5] serial: split generic UART driver helper functions into a separate file
Nicolas Pitre
nicolas.pitre at linaro.org
Sat Apr 1 15:21:18 PDT 2017
This contains code that is common between serial_core.c and the
minitty code to come. Mainly helper functions used by UART drivers.
Signed-off-by: Nicolas Pitre <nico at linaro.org>
---
drivers/tty/serial/Makefile | 2 +-
drivers/tty/serial/serial_core.c | 419 +------------------------------------
drivers/tty/serial/serial_lib.c | 440 +++++++++++++++++++++++++++++++++++++++
include/linux/serial_core.h | 1 +
4 files changed, 443 insertions(+), 419 deletions(-)
create mode 100644 drivers/tty/serial/serial_lib.c
diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile
index 53c03e0051..073afd10c5 100644
--- a/drivers/tty/serial/Makefile
+++ b/drivers/tty/serial/Makefile
@@ -2,7 +2,7 @@
# Makefile for the kernel serial device drivers.
#
-obj-$(CONFIG_SERIAL_CORE) += serial_core.o
+obj-$(CONFIG_SERIAL_CORE) += serial_core.o serial_lib.o
obj-$(CONFIG_SERIAL_EARLYCON) += earlycon.o
obj-$(CONFIG_SERIAL_EARLYCON_ARM_SEMIHOST) += earlycon-arm-semihost.o
diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c
index 3fe5689497..20214e1d87 100644
--- a/drivers/tty/serial/serial_core.c
+++ b/drivers/tty/serial/serial_core.c
@@ -44,12 +44,6 @@
*/
static DEFINE_MUTEX(port_mutex);
-/*
- * lockdep: port->lock is initialized in two places, but we
- * want only one lock-class:
- */
-static struct lock_class_key port_lock_key;
-
#define HIGH_BITS_OFFSET ((sizeof(long)-sizeof(int))*8)
static void uart_change_speed(struct tty_struct *tty, struct uart_state *state,
@@ -293,183 +287,6 @@ static void uart_shutdown(struct tty_struct *tty, struct uart_state *state)
}
}
-/**
- * uart_update_timeout - update per-port FIFO timeout.
- * @port: uart_port structure describing the port
- * @cflag: termios cflag value
- * @baud: speed of the port
- *
- * Set the port FIFO timeout value. The @cflag value should
- * reflect the actual hardware settings.
- */
-void
-uart_update_timeout(struct uart_port *port, unsigned int cflag,
- unsigned int baud)
-{
- unsigned int bits;
-
- /* byte size and parity */
- switch (cflag & CSIZE) {
- case CS5:
- bits = 7;
- break;
- case CS6:
- bits = 8;
- break;
- case CS7:
- bits = 9;
- break;
- default:
- bits = 10;
- break; /* CS8 */
- }
-
- if (cflag & CSTOPB)
- bits++;
- if (cflag & PARENB)
- bits++;
-
- /*
- * The total number of bits to be transmitted in the fifo.
- */
- bits = bits * port->fifosize;
-
- /*
- * Figure the timeout to send the above number of bits.
- * Add .02 seconds of slop
- */
- port->timeout = (HZ * bits) / baud + HZ/50;
-}
-
-EXPORT_SYMBOL(uart_update_timeout);
-
-/**
- * uart_get_baud_rate - return baud rate for a particular port
- * @port: uart_port structure describing the port in question.
- * @termios: desired termios settings.
- * @old: old termios (or NULL)
- * @min: minimum acceptable baud rate
- * @max: maximum acceptable baud rate
- *
- * Decode the termios structure into a numeric baud rate,
- * taking account of the magic 38400 baud rate (with spd_*
- * flags), and mapping the %B0 rate to 9600 baud.
- *
- * If the new baud rate is invalid, try the old termios setting.
- * If it's still invalid, we try 9600 baud.
- *
- * Update the @termios structure to reflect the baud rate
- * we're actually going to be using. Don't do this for the case
- * where B0 is requested ("hang up").
- */
-unsigned int
-uart_get_baud_rate(struct uart_port *port, struct ktermios *termios,
- struct ktermios *old, unsigned int min, unsigned int max)
-{
- unsigned int try;
- unsigned int baud;
- unsigned int altbaud;
- int hung_up = 0;
- upf_t flags = port->flags & UPF_SPD_MASK;
-
- switch (flags) {
- case UPF_SPD_HI:
- altbaud = 57600;
- break;
- case UPF_SPD_VHI:
- altbaud = 115200;
- break;
- case UPF_SPD_SHI:
- altbaud = 230400;
- break;
- case UPF_SPD_WARP:
- altbaud = 460800;
- break;
- default:
- altbaud = 38400;
- break;
- }
-
- for (try = 0; try < 2; try++) {
- baud = tty_termios_baud_rate(termios);
-
- /*
- * The spd_hi, spd_vhi, spd_shi, spd_warp kludge...
- * Die! Die! Die!
- */
- if (try == 0 && baud == 38400)
- baud = altbaud;
-
- /*
- * Special case: B0 rate.
- */
- if (baud == 0) {
- hung_up = 1;
- baud = 9600;
- }
-
- if (baud >= min && baud <= max)
- return baud;
-
- /*
- * Oops, the quotient was zero. Try again with
- * the old baud rate if possible.
- */
- termios->c_cflag &= ~CBAUD;
- if (old) {
- baud = tty_termios_baud_rate(old);
- if (!hung_up)
- tty_termios_encode_baud_rate(termios,
- baud, baud);
- old = NULL;
- continue;
- }
-
- /*
- * As a last resort, if the range cannot be met then clip to
- * the nearest chip supported rate.
- */
- if (!hung_up) {
- if (baud <= min)
- tty_termios_encode_baud_rate(termios,
- min + 1, min + 1);
- else
- tty_termios_encode_baud_rate(termios,
- max - 1, max - 1);
- }
- }
- /* Should never happen */
- WARN_ON(1);
- return 0;
-}
-
-EXPORT_SYMBOL(uart_get_baud_rate);
-
-/**
- * uart_get_divisor - return uart clock divisor
- * @port: uart_port structure describing the port.
- * @baud: desired baud rate
- *
- * Calculate the uart clock divisor for the port.
- */
-unsigned int
-uart_get_divisor(struct uart_port *port, unsigned int baud)
-{
- unsigned int quot;
-
- /*
- * Old custom speed handling.
- */
- if (baud == 38400 && (port->flags & UPF_SPD_MASK) == UPF_SPD_CUST)
- quot = port->custom_divisor;
- else
- quot = DIV_ROUND_CLOSEST(port->uartclk, 16 * baud);
-
- return quot;
-}
-
-EXPORT_SYMBOL(uart_get_divisor);
-
/* Caller holds port mutex */
static void uart_change_speed(struct tty_struct *tty, struct uart_state *state,
struct ktermios *old_termios)
@@ -1837,207 +1654,6 @@ static const struct file_operations uart_proc_fops = {
};
#endif
-#if defined(CONFIG_SERIAL_CORE_CONSOLE) || defined(CONFIG_CONSOLE_POLL)
-/**
- * uart_console_write - write a console message to a serial port
- * @port: the port to write the message
- * @s: array of characters
- * @count: number of characters in string to write
- * @putchar: function to write character to port
- */
-void uart_console_write(struct uart_port *port, const char *s,
- unsigned int count,
- void (*putchar)(struct uart_port *, int))
-{
- unsigned int i;
-
- for (i = 0; i < count; i++, s++) {
- if (*s == '\n')
- putchar(port, '\r');
- putchar(port, *s);
- }
-}
-EXPORT_SYMBOL_GPL(uart_console_write);
-
-/*
- * Check whether an invalid uart number has been specified, and
- * if so, search for the first available port that does have
- * console support.
- */
-struct uart_port * __init
-uart_get_console(struct uart_port *ports, int nr, struct console *co)
-{
- int idx = co->index;
-
- if (idx < 0 || idx >= nr || (ports[idx].iobase == 0 &&
- ports[idx].membase == NULL))
- for (idx = 0; idx < nr; idx++)
- if (ports[idx].iobase != 0 ||
- ports[idx].membase != NULL)
- break;
-
- co->index = idx;
-
- return ports + idx;
-}
-
-/**
- * uart_parse_earlycon - Parse earlycon options
- * @p: ptr to 2nd field (ie., just beyond '<name>,')
- * @iotype: ptr for decoded iotype (out)
- * @addr: ptr for decoded mapbase/iobase (out)
- * @options: ptr for <options> field; NULL if not present (out)
- *
- * Decodes earlycon kernel command line parameters of the form
- * earlycon=<name>,io|mmio|mmio16|mmio32|mmio32be|mmio32native,<addr>,<options>
- * console=<name>,io|mmio|mmio16|mmio32|mmio32be|mmio32native,<addr>,<options>
- *
- * The optional form
- * earlycon=<name>,0x<addr>,<options>
- * console=<name>,0x<addr>,<options>
- * is also accepted; the returned @iotype will be UPIO_MEM.
- *
- * Returns 0 on success or -EINVAL on failure
- */
-int uart_parse_earlycon(char *p, unsigned char *iotype, resource_size_t *addr,
- char **options)
-{
- if (strncmp(p, "mmio,", 5) == 0) {
- *iotype = UPIO_MEM;
- p += 5;
- } else if (strncmp(p, "mmio16,", 7) == 0) {
- *iotype = UPIO_MEM16;
- p += 7;
- } else if (strncmp(p, "mmio32,", 7) == 0) {
- *iotype = UPIO_MEM32;
- p += 7;
- } else if (strncmp(p, "mmio32be,", 9) == 0) {
- *iotype = UPIO_MEM32BE;
- p += 9;
- } else if (strncmp(p, "mmio32native,", 13) == 0) {
- *iotype = IS_ENABLED(CONFIG_CPU_BIG_ENDIAN) ?
- UPIO_MEM32BE : UPIO_MEM32;
- p += 13;
- } else if (strncmp(p, "io,", 3) == 0) {
- *iotype = UPIO_PORT;
- p += 3;
- } else if (strncmp(p, "0x", 2) == 0) {
- *iotype = UPIO_MEM;
- } else {
- return -EINVAL;
- }
-
- /*
- * Before you replace it with kstrtoull(), think about options separator
- * (',') it will not tolerate
- */
- *addr = simple_strtoull(p, NULL, 0);
- p = strchr(p, ',');
- if (p)
- p++;
-
- *options = p;
- return 0;
-}
-EXPORT_SYMBOL_GPL(uart_parse_earlycon);
-
-/**
- * uart_parse_options - Parse serial port baud/parity/bits/flow control.
- * @options: pointer to option string
- * @baud: pointer to an 'int' variable for the baud rate.
- * @parity: pointer to an 'int' variable for the parity.
- * @bits: pointer to an 'int' variable for the number of data bits.
- * @flow: pointer to an 'int' variable for the flow control character.
- *
- * uart_parse_options decodes a string containing the serial console
- * options. The format of the string is <baud><parity><bits><flow>,
- * eg: 115200n8r
- */
-void
-uart_parse_options(char *options, int *baud, int *parity, int *bits, int *flow)
-{
- char *s = options;
-
- *baud = simple_strtoul(s, NULL, 10);
- while (*s >= '0' && *s <= '9')
- s++;
- if (*s)
- *parity = *s++;
- if (*s)
- *bits = *s++ - '0';
- if (*s)
- *flow = *s;
-}
-EXPORT_SYMBOL_GPL(uart_parse_options);
-
-/**
- * uart_set_options - setup the serial console parameters
- * @port: pointer to the serial ports uart_port structure
- * @co: console pointer
- * @baud: baud rate
- * @parity: parity character - 'n' (none), 'o' (odd), 'e' (even)
- * @bits: number of data bits
- * @flow: flow control character - 'r' (rts)
- */
-int
-uart_set_options(struct uart_port *port, struct console *co,
- int baud, int parity, int bits, int flow)
-{
- struct ktermios termios;
- static struct ktermios dummy;
-
- /*
- * Ensure that the serial console lock is initialised
- * early.
- * If this port is a console, then the spinlock is already
- * initialised.
- */
- if (!(uart_console(port) && (port->cons->flags & CON_ENABLED))) {
- spin_lock_init(&port->lock);
- lockdep_set_class(&port->lock, &port_lock_key);
- }
-
- memset(&termios, 0, sizeof(struct ktermios));
-
- termios.c_cflag |= CREAD | HUPCL | CLOCAL;
- tty_termios_encode_baud_rate(&termios, baud, baud);
-
- if (bits == 7)
- termios.c_cflag |= CS7;
- else
- termios.c_cflag |= CS8;
-
- switch (parity) {
- case 'o': case 'O':
- termios.c_cflag |= PARODD;
- /*fall through*/
- case 'e': case 'E':
- termios.c_cflag |= PARENB;
- break;
- }
-
- if (flow == 'r')
- termios.c_cflag |= CRTSCTS;
-
- /*
- * some uarts on other side don't support no flow control.
- * So we set * DTR in host uart to make them happy
- */
- port->mctrl |= TIOCM_DTR;
-
- port->ops->set_termios(port, &termios, &dummy);
- /*
- * Allow the setting of the UART parameters with a NULL console
- * too:
- */
- if (co)
- co->cflag = termios.c_cflag;
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(uart_set_options);
-#endif /* CONFIG_SERIAL_CORE_CONSOLE */
-
/**
* uart_change_pm - set power state of the port
*
@@ -2751,15 +2367,8 @@ int uart_add_one_port(struct uart_driver *drv, struct uart_port *uport)
state->pm_state = UART_PM_STATE_UNDEFINED;
uport->cons = drv->cons;
uport->minor = drv->tty_driver->minor_start + uport->line;
+ uart_port_lock_init(uport);
- /*
- * If this port is a console, then the spinlock is already
- * initialised.
- */
- if (!(uart_console(uport) && (uport->cons->flags & CON_ENABLED))) {
- spin_lock_init(&uport->lock);
- lockdep_set_class(&uport->lock, &port_lock_key);
- }
if (uport->cons && uport->dev)
of_console_check(uport->dev->of_node, uport->cons->name, uport->line);
@@ -2885,32 +2494,6 @@ int uart_remove_one_port(struct uart_driver *drv, struct uart_port *uport)
return ret;
}
-/*
- * Are the two ports equivalent?
- */
-int uart_match_port(struct uart_port *port1, struct uart_port *port2)
-{
- if (port1->iotype != port2->iotype)
- return 0;
-
- switch (port1->iotype) {
- case UPIO_PORT:
- return (port1->iobase == port2->iobase);
- case UPIO_HUB6:
- return (port1->iobase == port2->iobase) &&
- (port1->hub6 == port2->hub6);
- case UPIO_MEM:
- case UPIO_MEM16:
- case UPIO_MEM32:
- case UPIO_MEM32BE:
- case UPIO_AU:
- case UPIO_TSI:
- return (port1->mapbase == port2->mapbase);
- }
- return 0;
-}
-EXPORT_SYMBOL(uart_match_port);
-
/**
* uart_handle_dcd_change - handle a change of carrier detect state
* @uport: uart_port structure for the open port
diff --git a/drivers/tty/serial/serial_lib.c b/drivers/tty/serial/serial_lib.c
new file mode 100644
index 0000000000..c3f521b401
--- /dev/null
+++ b/drivers/tty/serial/serial_lib.c
@@ -0,0 +1,440 @@
+/*
+ * Common support functions for serial port drivers
+ *
+ * Copyright 1999 ARM Limited
+ * Copyright (C) 2000-2001 Deep Blue Solutions Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/export.h>
+#include <linux/tty.h>
+#include <linux/console.h>
+#include <linux/serial_core.h>
+#include <linux/spinlock.h>
+
+/*
+ * lockdep: port->lock is initialized in two places, but we
+ * want only one lock-class:
+ */
+static struct lock_class_key port_lock_key;
+
+void uart_port_lock_init(struct uart_port *port)
+{
+ /*
+ * If this port is a console, then the spinlock is already
+ * initialised.
+ */
+ if (!(uart_console(port) && (port->cons->flags & CON_ENABLED))) {
+ spin_lock_init(&port->lock);
+ lockdep_set_class(&port->lock, &port_lock_key);
+ }
+}
+
+/**
+ * uart_update_timeout - update per-port FIFO timeout.
+ * @port: uart_port structure describing the port
+ * @cflag: termios cflag value
+ * @baud: speed of the port
+ *
+ * Set the port FIFO timeout value. The @cflag value should
+ * reflect the actual hardware settings.
+ */
+void
+uart_update_timeout(struct uart_port *port, unsigned int cflag,
+ unsigned int baud)
+{
+ unsigned int bits;
+
+ /* byte size and parity */
+ switch (cflag & CSIZE) {
+ case CS5:
+ bits = 7;
+ break;
+ case CS6:
+ bits = 8;
+ break;
+ case CS7:
+ bits = 9;
+ break;
+ default:
+ bits = 10;
+ break; /* CS8 */
+ }
+
+ if (cflag & CSTOPB)
+ bits++;
+ if (cflag & PARENB)
+ bits++;
+
+ /*
+ * The total number of bits to be transmitted in the fifo.
+ */
+ bits = bits * port->fifosize;
+
+ /*
+ * Figure the timeout to send the above number of bits.
+ * Add .02 seconds of slop
+ */
+ port->timeout = (HZ * bits) / baud + HZ/50;
+}
+EXPORT_SYMBOL(uart_update_timeout);
+
+/**
+ * uart_get_baud_rate - return baud rate for a particular port
+ * @port: uart_port structure describing the port in question.
+ * @termios: desired termios settings.
+ * @old: old termios (or NULL)
+ * @min: minimum acceptable baud rate
+ * @max: maximum acceptable baud rate
+ *
+ * Decode the termios structure into a numeric baud rate,
+ * taking account of the magic 38400 baud rate (with spd_*
+ * flags), and mapping the %B0 rate to 9600 baud.
+ *
+ * If the new baud rate is invalid, try the old termios setting.
+ * If it's still invalid, we try 9600 baud.
+ *
+ * Update the @termios structure to reflect the baud rate
+ * we're actually going to be using. Don't do this for the case
+ * where B0 is requested ("hang up").
+ */
+unsigned int
+uart_get_baud_rate(struct uart_port *port, struct ktermios *termios,
+ struct ktermios *old, unsigned int min, unsigned int max)
+{
+ unsigned int try;
+ unsigned int baud;
+ unsigned int altbaud;
+ int hung_up = 0;
+ upf_t flags = port->flags & UPF_SPD_MASK;
+
+ switch (flags) {
+ case UPF_SPD_HI:
+ altbaud = 57600;
+ break;
+ case UPF_SPD_VHI:
+ altbaud = 115200;
+ break;
+ case UPF_SPD_SHI:
+ altbaud = 230400;
+ break;
+ case UPF_SPD_WARP:
+ altbaud = 460800;
+ break;
+ default:
+ altbaud = 38400;
+ break;
+ }
+
+ for (try = 0; try < 2; try++) {
+ baud = tty_termios_baud_rate(termios);
+
+ /*
+ * The spd_hi, spd_vhi, spd_shi, spd_warp kludge...
+ * Die! Die! Die!
+ */
+ if (try == 0 && baud == 38400)
+ baud = altbaud;
+
+ /*
+ * Special case: B0 rate.
+ */
+ if (baud == 0) {
+ hung_up = 1;
+ baud = 9600;
+ }
+
+ if (baud >= min && baud <= max)
+ return baud;
+
+ /*
+ * Oops, the quotient was zero. Try again with
+ * the old baud rate if possible.
+ */
+ termios->c_cflag &= ~CBAUD;
+ if (old) {
+ baud = tty_termios_baud_rate(old);
+ if (!hung_up)
+ tty_termios_encode_baud_rate(termios,
+ baud, baud);
+ old = NULL;
+ continue;
+ }
+
+ /*
+ * As a last resort, if the range cannot be met then clip to
+ * the nearest chip supported rate.
+ */
+ if (!hung_up) {
+ if (baud <= min)
+ tty_termios_encode_baud_rate(termios,
+ min + 1, min + 1);
+ else
+ tty_termios_encode_baud_rate(termios,
+ max - 1, max - 1);
+ }
+ }
+ /* Should never happen */
+ WARN_ON(1);
+ return 0;
+}
+EXPORT_SYMBOL(uart_get_baud_rate);
+
+/**
+ * uart_get_divisor - return uart clock divisor
+ * @port: uart_port structure describing the port.
+ * @baud: desired baud rate
+ *
+ * Calculate the uart clock divisor for the port.
+ */
+unsigned int
+uart_get_divisor(struct uart_port *port, unsigned int baud)
+{
+ unsigned int quot;
+
+ /*
+ * Old custom speed handling.
+ */
+ if (baud == 38400 && (port->flags & UPF_SPD_MASK) == UPF_SPD_CUST)
+ quot = port->custom_divisor;
+ else
+ quot = DIV_ROUND_CLOSEST(port->uartclk, 16 * baud);
+
+ return quot;
+}
+EXPORT_SYMBOL(uart_get_divisor);
+
+#if defined(CONFIG_SERIAL_CORE_CONSOLE) || defined(CONFIG_CONSOLE_POLL)
+/**
+ * uart_console_write - write a console message to a serial port
+ * @port: the port to write the message
+ * @s: array of characters
+ * @count: number of characters in string to write
+ * @putchar: function to write character to port
+ */
+void uart_console_write(struct uart_port *port, const char *s,
+ unsigned int count,
+ void (*putchar)(struct uart_port *, int))
+{
+ unsigned int i;
+
+ for (i = 0; i < count; i++, s++) {
+ if (*s == '\n')
+ putchar(port, '\r');
+ putchar(port, *s);
+ }
+}
+EXPORT_SYMBOL_GPL(uart_console_write);
+
+/*
+ * Check whether an invalid uart number has been specified, and
+ * if so, search for the first available port that does have
+ * console support.
+ */
+struct uart_port * __init
+uart_get_console(struct uart_port *ports, int nr, struct console *co)
+{
+ int idx = co->index;
+
+ if (idx < 0 || idx >= nr || (ports[idx].iobase == 0 &&
+ ports[idx].membase == NULL))
+ for (idx = 0; idx < nr; idx++)
+ if (ports[idx].iobase != 0 ||
+ ports[idx].membase != NULL)
+ break;
+
+ co->index = idx;
+
+ return ports + idx;
+}
+
+/**
+ * uart_parse_earlycon - Parse earlycon options
+ * @p: ptr to 2nd field (ie., just beyond '<name>,')
+ * @iotype: ptr for decoded iotype (out)
+ * @addr: ptr for decoded mapbase/iobase (out)
+ * @options: ptr for <options> field; NULL if not present (out)
+ *
+ * Decodes earlycon kernel command line parameters of the form
+ * earlycon=<name>,io|mmio|mmio16|mmio32|mmio32be|mmio32native,<addr>,<options>
+ * console=<name>,io|mmio|mmio16|mmio32|mmio32be|mmio32native,<addr>,<options>
+ *
+ * The optional form
+ * earlycon=<name>,0x<addr>,<options>
+ * console=<name>,0x<addr>,<options>
+ * is also accepted; the returned @iotype will be UPIO_MEM.
+ *
+ * Returns 0 on success or -EINVAL on failure
+ */
+int uart_parse_earlycon(char *p, unsigned char *iotype, resource_size_t *addr,
+ char **options)
+{
+ if (strncmp(p, "mmio,", 5) == 0) {
+ *iotype = UPIO_MEM;
+ p += 5;
+ } else if (strncmp(p, "mmio16,", 7) == 0) {
+ *iotype = UPIO_MEM16;
+ p += 7;
+ } else if (strncmp(p, "mmio32,", 7) == 0) {
+ *iotype = UPIO_MEM32;
+ p += 7;
+ } else if (strncmp(p, "mmio32be,", 9) == 0) {
+ *iotype = UPIO_MEM32BE;
+ p += 9;
+ } else if (strncmp(p, "mmio32native,", 13) == 0) {
+ *iotype = IS_ENABLED(CONFIG_CPU_BIG_ENDIAN) ?
+ UPIO_MEM32BE : UPIO_MEM32;
+ p += 13;
+ } else if (strncmp(p, "io,", 3) == 0) {
+ *iotype = UPIO_PORT;
+ p += 3;
+ } else if (strncmp(p, "0x", 2) == 0) {
+ *iotype = UPIO_MEM;
+ } else {
+ return -EINVAL;
+ }
+
+ /*
+ * Before you replace it with kstrtoull(), think about options separator
+ * (',') it will not tolerate
+ */
+ *addr = simple_strtoull(p, NULL, 0);
+ p = strchr(p, ',');
+ if (p)
+ p++;
+
+ *options = p;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(uart_parse_earlycon);
+
+/**
+ * uart_parse_options - Parse serial port baud/parity/bits/flow control.
+ * @options: pointer to option string
+ * @baud: pointer to an 'int' variable for the baud rate.
+ * @parity: pointer to an 'int' variable for the parity.
+ * @bits: pointer to an 'int' variable for the number of data bits.
+ * @flow: pointer to an 'int' variable for the flow control character.
+ *
+ * uart_parse_options decodes a string containing the serial console
+ * options. The format of the string is <baud><parity><bits><flow>,
+ * eg: 115200n8r
+ */
+void
+uart_parse_options(char *options, int *baud, int *parity, int *bits, int *flow)
+{
+ char *s = options;
+
+ *baud = simple_strtoul(s, NULL, 10);
+ while (*s >= '0' && *s <= '9')
+ s++;
+ if (*s)
+ *parity = *s++;
+ if (*s)
+ *bits = *s++ - '0';
+ if (*s)
+ *flow = *s;
+}
+EXPORT_SYMBOL_GPL(uart_parse_options);
+
+/**
+ * uart_set_options - setup the serial console parameters
+ * @port: pointer to the serial ports uart_port structure
+ * @co: console pointer
+ * @baud: baud rate
+ * @parity: parity character - 'n' (none), 'o' (odd), 'e' (even)
+ * @bits: number of data bits
+ * @flow: flow control character - 'r' (rts)
+ */
+int
+uart_set_options(struct uart_port *port, struct console *co,
+ int baud, int parity, int bits, int flow)
+{
+ struct ktermios termios;
+ static struct ktermios dummy;
+
+ /*
+ * Ensure that the serial console lock is initialised
+ * early.
+ */
+ uart_port_lock_init(port);
+
+ memset(&termios, 0, sizeof(struct ktermios));
+
+ termios.c_cflag |= CREAD | HUPCL | CLOCAL;
+ tty_termios_encode_baud_rate(&termios, baud, baud);
+
+ if (bits == 7)
+ termios.c_cflag |= CS7;
+ else
+ termios.c_cflag |= CS8;
+
+ switch (parity) {
+ case 'o': case 'O':
+ termios.c_cflag |= PARODD;
+ /*fall through*/
+ case 'e': case 'E':
+ termios.c_cflag |= PARENB;
+ break;
+ }
+
+ if (flow == 'r')
+ termios.c_cflag |= CRTSCTS;
+
+ /*
+ * some uarts on other side don't support no flow control.
+ * So we set * DTR in host uart to make them happy
+ */
+ port->mctrl |= TIOCM_DTR;
+
+ port->ops->set_termios(port, &termios, &dummy);
+ /*
+ * Allow the setting of the UART parameters with a NULL console
+ * too:
+ */
+ if (co)
+ co->cflag = termios.c_cflag;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(uart_set_options);
+#endif /* CONFIG_SERIAL_CORE_CONSOLE */
+
+/*
+ * Are the two ports equivalent?
+ */
+int uart_match_port(struct uart_port *port1, struct uart_port *port2)
+{
+ if (port1->iotype != port2->iotype)
+ return 0;
+
+ switch (port1->iotype) {
+ case UPIO_PORT:
+ return (port1->iobase == port2->iobase);
+ case UPIO_HUB6:
+ return (port1->iobase == port2->iobase) &&
+ (port1->hub6 == port2->hub6);
+ case UPIO_MEM:
+ case UPIO_MEM16:
+ case UPIO_MEM32:
+ case UPIO_MEM32BE:
+ case UPIO_AU:
+ case UPIO_TSI:
+ return (port1->mapbase == port2->mapbase);
+ }
+ return 0;
+}
+EXPORT_SYMBOL(uart_match_port);
diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h
index 58484fb35c..505b51db59 100644
--- a/include/linux/serial_core.h
+++ b/include/linux/serial_core.h
@@ -402,6 +402,7 @@ void uart_unregister_driver(struct uart_driver *uart);
int uart_add_one_port(struct uart_driver *reg, struct uart_port *port);
int uart_remove_one_port(struct uart_driver *reg, struct uart_port *port);
int uart_match_port(struct uart_port *port1, struct uart_port *port2);
+void uart_port_lock_init(struct uart_port *port);
/*
* Power Management
--
2.9.3
More information about the linux-arm-kernel
mailing list