From e169c139642fb4c682ec12a409725508dbefa520 Mon Sep 17 00:00:00 2001 From: Kay Sievers Date: Tue, 15 Apr 2008 14:34:35 -0700 Subject: serial: fix platform driver hotplug/coldplug Since 43cc71eed1250755986da4c0f9898f9a635cb3bf, the platform modalias is prefixed with "platform:". Add MODULE_ALIAS() to the hotpluggable serial platform drivers, to re-enable auto loading. NOTE that Kconfig for some of these drivers doesn't allow modular builds, and thus doesn't match the driver source's unload support. Presumably their unload code is buggy and/or weakly tested... [dbrownell@users.sourceforge.net: more drivers, registration fixes] Signed-off-by: Kay Sievers Signed-off-by: David Brownell Acked-by: Peter Korsgaard Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/serial/atmel_serial.c | 1 + drivers/serial/bfin_5xx.c | 2 ++ drivers/serial/imx.c | 2 ++ drivers/serial/mcf.c | 1 + drivers/serial/mpc52xx_uart.c | 2 ++ drivers/serial/mpsc.c | 2 ++ drivers/serial/netx-serial.c | 2 ++ drivers/serial/pnx8xxx_uart.c | 1 + drivers/serial/pxa.c | 3 ++- drivers/serial/s3c2410.c | 4 ++++ drivers/serial/sa1100.c | 2 ++ drivers/serial/sc26xx.c | 2 ++ drivers/serial/sh-sci.c | 1 + drivers/serial/uartlite.c | 3 +++ drivers/serial/vr41xx_siu.c | 3 +++ 15 files changed, 30 insertions(+), 1 deletion(-) (limited to 'drivers/serial') diff --git a/drivers/serial/atmel_serial.c b/drivers/serial/atmel_serial.c index 430997e33fc..55492fa095a 100644 --- a/drivers/serial/atmel_serial.c +++ b/drivers/serial/atmel_serial.c @@ -1577,3 +1577,4 @@ module_exit(atmel_serial_exit); MODULE_AUTHOR("Rick Bronson"); MODULE_DESCRIPTION("Atmel AT91 / AT32 serial port driver"); MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:atmel_usart"); diff --git a/drivers/serial/bfin_5xx.c b/drivers/serial/bfin_5xx.c index 0aa345b9a38..46bb47f37b9 100644 --- a/drivers/serial/bfin_5xx.c +++ b/drivers/serial/bfin_5xx.c @@ -1243,6 +1243,7 @@ static struct platform_driver bfin_serial_driver = { .resume = bfin_serial_resume, .driver = { .name = "bfin-uart", + .owner = THIS_MODULE, }, }; @@ -1301,3 +1302,4 @@ MODULE_AUTHOR("Aubrey.Li "); MODULE_DESCRIPTION("Blackfin generic serial port driver"); MODULE_LICENSE("GPL"); MODULE_ALIAS_CHARDEV_MAJOR(BFIN_SERIAL_MAJOR); +MODULE_ALIAS("platform:bfin-uart"); diff --git a/drivers/serial/imx.c b/drivers/serial/imx.c index 56af1f566a4..16ba9ac7a56 100644 --- a/drivers/serial/imx.c +++ b/drivers/serial/imx.c @@ -1090,6 +1090,7 @@ static struct platform_driver serial_imx_driver = { .resume = serial_imx_resume, .driver = { .name = "imx-uart", + .owner = THIS_MODULE, }, }; @@ -1124,3 +1125,4 @@ module_exit(imx_serial_exit); MODULE_AUTHOR("Sascha Hauer"); MODULE_DESCRIPTION("IMX generic serial port driver"); MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:imx-uart"); diff --git a/drivers/serial/mcf.c b/drivers/serial/mcf.c index e76fc72c9b3..7e164e0cd21 100644 --- a/drivers/serial/mcf.c +++ b/drivers/serial/mcf.c @@ -649,5 +649,6 @@ module_exit(mcf_exit); MODULE_AUTHOR("Greg Ungerer "); MODULE_DESCRIPTION("Freescale ColdFire UART driver"); MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:mcfuart"); /****************************************************************************/ diff --git a/drivers/serial/mpc52xx_uart.c b/drivers/serial/mpc52xx_uart.c index a638f23c6c6..d93b3578c5e 100644 --- a/drivers/serial/mpc52xx_uart.c +++ b/drivers/serial/mpc52xx_uart.c @@ -1188,6 +1188,8 @@ mpc52xx_uart_resume(struct platform_device *dev) } #endif +/* work with hotplug and coldplug */ +MODULE_ALIAS("platform:mpc52xx-psc"); static struct platform_driver mpc52xx_uart_platform_driver = { .probe = mpc52xx_uart_probe, diff --git a/drivers/serial/mpsc.c b/drivers/serial/mpsc.c index cb3a9196774..e8819c43f57 100644 --- a/drivers/serial/mpsc.c +++ b/drivers/serial/mpsc.c @@ -1964,6 +1964,7 @@ static struct platform_driver mpsc_driver = { .remove = mpsc_drv_remove, .driver = { .name = MPSC_CTLR_NAME, + .owner = THIS_MODULE, }, }; @@ -2007,3 +2008,4 @@ MODULE_DESCRIPTION("Generic Marvell MPSC serial/UART driver $Revision: 1.00 $"); MODULE_VERSION(MPSC_VERSION); MODULE_LICENSE("GPL"); MODULE_ALIAS_CHARDEV_MAJOR(MPSC_MAJOR); +MODULE_ALIAS("platform:" MPSC_CTLR_NAME); diff --git a/drivers/serial/netx-serial.c b/drivers/serial/netx-serial.c index b56f7db4503..3123ffeac8a 100644 --- a/drivers/serial/netx-serial.c +++ b/drivers/serial/netx-serial.c @@ -713,6 +713,7 @@ static struct platform_driver serial_netx_driver = { .driver = { .name = DRIVER_NAME, + .owner = THIS_MODULE, }, }; @@ -745,3 +746,4 @@ module_exit(netx_serial_exit); MODULE_AUTHOR("Sascha Hauer"); MODULE_DESCRIPTION("NetX serial port driver"); MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:" DRIVER_NAME); diff --git a/drivers/serial/pnx8xxx_uart.c b/drivers/serial/pnx8xxx_uart.c index 8d01c59e8d0..d0e5a79ea63 100644 --- a/drivers/serial/pnx8xxx_uart.c +++ b/drivers/serial/pnx8xxx_uart.c @@ -850,3 +850,4 @@ MODULE_AUTHOR("Embedded Alley Solutions, Inc."); MODULE_DESCRIPTION("PNX8XXX SoCs serial port driver"); MODULE_LICENSE("GPL"); MODULE_ALIAS_CHARDEV_MAJOR(SERIAL_PNX8XXX_MAJOR); +MODULE_ALIAS("platform:pnx8xxx-uart"); diff --git a/drivers/serial/pxa.c b/drivers/serial/pxa.c index 352fcb8926a..b4f7ffb7688 100644 --- a/drivers/serial/pxa.c +++ b/drivers/serial/pxa.c @@ -833,6 +833,7 @@ static struct platform_driver serial_pxa_driver = { .resume = serial_pxa_resume, .driver = { .name = "pxa2xx-uart", + .owner = THIS_MODULE, }, }; @@ -861,4 +862,4 @@ module_init(serial_pxa_init); module_exit(serial_pxa_exit); MODULE_LICENSE("GPL"); - +MODULE_ALIAS("platform:pxa2xx-uart"); diff --git a/drivers/serial/s3c2410.c b/drivers/serial/s3c2410.c index 45de1936603..4ffa2585429 100644 --- a/drivers/serial/s3c2410.c +++ b/drivers/serial/s3c2410.c @@ -1935,3 +1935,7 @@ console_initcall(s3c24xx_serial_initconsole); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Ben Dooks "); MODULE_DESCRIPTION("Samsung S3C2410/S3C2440/S3C2412 Serial port driver"); +MODULE_ALIAS("platform:s3c2400-uart"); +MODULE_ALIAS("platform:s3c2410-uart"); +MODULE_ALIAS("platform:s3c2412-uart"); +MODULE_ALIAS("platform:s3c2440-uart"); diff --git a/drivers/serial/sa1100.c b/drivers/serial/sa1100.c index 58a83c27e14..67b2338913c 100644 --- a/drivers/serial/sa1100.c +++ b/drivers/serial/sa1100.c @@ -884,6 +884,7 @@ static struct platform_driver sa11x0_serial_driver = { .resume = sa1100_serial_resume, .driver = { .name = "sa11x0-uart", + .owner = THIS_MODULE, }, }; @@ -917,3 +918,4 @@ MODULE_AUTHOR("Deep Blue Solutions Ltd"); MODULE_DESCRIPTION("SA1100 generic serial port driver $Revision: 1.50 $"); MODULE_LICENSE("GPL"); MODULE_ALIAS_CHARDEV_MAJOR(SERIAL_SA1100_MAJOR); +MODULE_ALIAS("platform:sa11x0-uart"); diff --git a/drivers/serial/sc26xx.c b/drivers/serial/sc26xx.c index a350b6d2a18..ae2a9e2df77 100644 --- a/drivers/serial/sc26xx.c +++ b/drivers/serial/sc26xx.c @@ -732,6 +732,7 @@ static struct platform_driver sc26xx_driver = { .remove = __devexit_p(sc26xx_driver_remove), .driver = { .name = "SC26xx", + .owner = THIS_MODULE, }, }; @@ -753,3 +754,4 @@ MODULE_AUTHOR("Thomas Bogendörfer"); MODULE_DESCRIPTION("SC681/SC2692 serial driver"); MODULE_VERSION("1.0"); MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:SC26xx"); diff --git a/drivers/serial/sh-sci.c b/drivers/serial/sh-sci.c index 9d244d1644e..eff593080d4 100644 --- a/drivers/serial/sh-sci.c +++ b/drivers/serial/sh-sci.c @@ -1552,3 +1552,4 @@ module_init(sci_init); module_exit(sci_exit); MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:sh-sci"); diff --git a/drivers/serial/uartlite.c b/drivers/serial/uartlite.c index 4e06ab6bcb6..b565d5a3749 100644 --- a/drivers/serial/uartlite.c +++ b/drivers/serial/uartlite.c @@ -561,6 +561,9 @@ static int __devexit ulite_remove(struct platform_device *pdev) return ulite_release(&pdev->dev); } +/* work with hotplug and coldplug */ +MODULE_ALIAS("platform:uartlite"); + static struct platform_driver ulite_platform_driver = { .probe = ulite_probe, .remove = __devexit_p(ulite_remove), diff --git a/drivers/serial/vr41xx_siu.c b/drivers/serial/vr41xx_siu.c index 6fd51b0022c..98ab649c1ff 100644 --- a/drivers/serial/vr41xx_siu.c +++ b/drivers/serial/vr41xx_siu.c @@ -960,3 +960,6 @@ static void __exit vr41xx_siu_exit(void) module_init(vr41xx_siu_init); module_exit(vr41xx_siu_exit); + +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:SIU"); -- cgit v1.2.3-70-g09d2 From f2d937f3bf00665ccf048b3b6616ef95859b0945 Mon Sep 17 00:00:00 2001 From: Jason Wessel Date: Thu, 17 Apr 2008 20:05:37 +0200 Subject: consoles: polling support, kgdboc polled console handling support, to access a console in an irq-less way while in debug or irq context. absolutely zero impact as long as CONFIG_CONSOLE_POLL is disabled. (which is the default) [ jan.kiszka@siemens.com: lots of cleanups ] [ mingo@elte.hu: redesign, splitups, cleanups. ] Signed-off-by: Jason Wessel Signed-off-by: Ingo Molnar Signed-off-by: Jan Kiszka Reviewed-by: Thomas Gleixner --- drivers/char/tty_io.c | 47 +++++++++++++ drivers/serial/8250.c | 58 +++++++++++++++ drivers/serial/Kconfig | 3 + drivers/serial/Makefile | 1 + drivers/serial/kgdboc.c | 163 +++++++++++++++++++++++++++++++++++++++++++ drivers/serial/serial_core.c | 72 ++++++++++++++++++- include/linux/serial_core.h | 4 ++ include/linux/tty_driver.h | 12 ++++ 8 files changed, 357 insertions(+), 3 deletions(-) create mode 100644 drivers/serial/kgdboc.c (limited to 'drivers/serial') diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c index 613ec816ce6..4d3c7018f0c 100644 --- a/drivers/char/tty_io.c +++ b/drivers/char/tty_io.c @@ -1155,6 +1155,48 @@ static struct tty_driver *get_tty_driver(dev_t device, int *index) return NULL; } +#ifdef CONFIG_CONSOLE_POLL + +/** + * tty_find_polling_driver - find device of a polled tty + * @name: name string to match + * @line: pointer to resulting tty line nr + * + * This routine returns a tty driver structure, given a name + * and the condition that the tty driver is capable of polled + * operation. + */ +struct tty_driver *tty_find_polling_driver(char *name, int *line) +{ + struct tty_driver *p, *res = NULL; + int tty_line = 0; + char *str; + + mutex_lock(&tty_mutex); + /* Search through the tty devices to look for a match */ + list_for_each_entry(p, &tty_drivers, tty_drivers) { + str = name + strlen(p->name); + tty_line = simple_strtoul(str, &str, 10); + if (*str == ',') + str++; + if (*str == '\0') + str = 0; + + if (tty_line >= 0 && tty_line <= p->num && p->poll_init && + !p->poll_init(p, tty_line, str)) { + + res = p; + *line = tty_line; + break; + } + } + mutex_unlock(&tty_mutex); + + return res; +} +EXPORT_SYMBOL_GPL(tty_find_polling_driver); +#endif + /** * tty_check_change - check for POSIX terminal changes * @tty: tty to check @@ -3850,6 +3892,11 @@ void tty_set_operations(struct tty_driver *driver, driver->write_proc = op->write_proc; driver->tiocmget = op->tiocmget; driver->tiocmset = op->tiocmset; +#ifdef CONFIG_CONSOLE_POLL + driver->poll_init = op->poll_init; + driver->poll_get_char = op->poll_get_char; + driver->poll_put_char = op->poll_put_char; +#endif } diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c index 77f7a7f0646..96a585e1cee 100644 --- a/drivers/serial/8250.c +++ b/drivers/serial/8250.c @@ -1740,6 +1740,60 @@ static inline void wait_for_xmitr(struct uart_8250_port *up, int bits) } } +#ifdef CONFIG_CONSOLE_POLL +/* + * Console polling routines for writing and reading from the uart while + * in an interrupt or debug context. + */ + +static int serial8250_get_poll_char(struct uart_port *port) +{ + struct uart_8250_port *up = (struct uart_8250_port *)port; + unsigned char lsr = serial_inp(up, UART_LSR); + + while (!(lsr & UART_LSR_DR)) + lsr = serial_inp(up, UART_LSR); + + return serial_inp(up, UART_RX); +} + + +static void serial8250_put_poll_char(struct uart_port *port, + unsigned char c) +{ + unsigned int ier; + struct uart_8250_port *up = (struct uart_8250_port *)port; + + /* + * First save the IER then disable the interrupts + */ + ier = serial_in(up, UART_IER); + if (up->capabilities & UART_CAP_UUE) + serial_out(up, UART_IER, UART_IER_UUE); + else + serial_out(up, UART_IER, 0); + + wait_for_xmitr(up, BOTH_EMPTY); + /* + * Send the character out. + * If a LF, also do CR... + */ + serial_out(up, UART_TX, c); + if (c == 10) { + wait_for_xmitr(up, BOTH_EMPTY); + serial_out(up, UART_TX, 13); + } + + /* + * Finally, wait for transmitter to become empty + * and restore the IER + */ + wait_for_xmitr(up, BOTH_EMPTY); + serial_out(up, UART_IER, ier); +} + +#endif /* CONFIG_CONSOLE_POLL */ + static int serial8250_startup(struct uart_port *port) { struct uart_8250_port *up = (struct uart_8250_port *)port; @@ -2386,6 +2440,10 @@ static struct uart_ops serial8250_pops = { .request_port = serial8250_request_port, .config_port = serial8250_config_port, .verify_port = serial8250_verify_port, +#ifdef CONFIG_CONSOLE_POLL + .poll_get_char = serial8250_get_poll_char, + .poll_put_char = serial8250_put_poll_char, +#endif }; static struct uart_8250_port serial8250_ports[UART_NR]; diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index cf627cd1b4c..f7cd9504d81 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -961,6 +961,9 @@ config SERIAL_CORE config SERIAL_CORE_CONSOLE bool +config CONSOLE_POLL + bool + config SERIAL_68328 bool "68328 serial support" depends on M68328 || M68EZ328 || M68VZ328 diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile index 640cfe44a56..3cbea549472 100644 --- a/drivers/serial/Makefile +++ b/drivers/serial/Makefile @@ -66,4 +66,5 @@ obj-$(CONFIG_SERIAL_UARTLITE) += uartlite.o obj-$(CONFIG_SERIAL_NETX) += netx-serial.o obj-$(CONFIG_SERIAL_OF_PLATFORM) += of_serial.o obj-$(CONFIG_SERIAL_KS8695) += serial_ks8695.o +obj-$(CONFIG_KGDB_SERIAL_CONSOLE) += kgdboc.o obj-$(CONFIG_SERIAL_QE) += ucc_uart.o diff --git a/drivers/serial/kgdboc.c b/drivers/serial/kgdboc.c new file mode 100644 index 00000000000..34183079160 --- /dev/null +++ b/drivers/serial/kgdboc.c @@ -0,0 +1,163 @@ +/* + * Based on the same principle as kgdboe using the NETPOLL api, this + * driver uses a console polling api to implement a gdb serial inteface + * which is multiplexed on a console port. + * + * Maintainer: Jason Wessel + * + * 2007-2008 (c) Jason Wessel - Wind River Systems, Inc. + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ +#include +#include +#include +#include + +#define MAX_CONFIG_LEN 40 + +static struct kgdb_io kgdboc_io_ops; + +/* -1 = init not run yet, 0 = unconfigured, 1 = configured. */ +static int configured = -1; + +static char config[MAX_CONFIG_LEN]; +static struct kparam_string kps = { + .string = config, + .maxlen = MAX_CONFIG_LEN, +}; + +static struct tty_driver *kgdb_tty_driver; +static int kgdb_tty_line; + +static int kgdboc_option_setup(char *opt) +{ + if (strlen(opt) > MAX_CONFIG_LEN) { + printk(KERN_ERR "kgdboc: config string too long\n"); + return -ENOSPC; + } + strcpy(config, opt); + + return 0; +} + +__setup("kgdboc=", kgdboc_option_setup); + +static int configure_kgdboc(void) +{ + struct tty_driver *p; + int tty_line = 0; + int err; + + err = kgdboc_option_setup(config); + if (err || !strlen(config) || isspace(config[0])) + goto noconfig; + + err = -ENODEV; + + p = tty_find_polling_driver(config, &tty_line); + if (!p) + goto noconfig; + + kgdb_tty_driver = p; + kgdb_tty_line = tty_line; + + err = kgdb_register_io_module(&kgdboc_io_ops); + if (err) + goto noconfig; + + configured = 1; + + return 0; + +noconfig: + config[0] = 0; + configured = 0; + + return err; +} + +static int __init init_kgdboc(void) +{ + /* Already configured? */ + if (configured == 1) + return 0; + + return configure_kgdboc(); +} + +static void cleanup_kgdboc(void) +{ + if (configured == 1) + kgdb_unregister_io_module(&kgdboc_io_ops); +} + +static int kgdboc_get_char(void) +{ + return kgdb_tty_driver->poll_get_char(kgdb_tty_driver, kgdb_tty_line); +} + +static void kgdboc_put_char(u8 chr) +{ + kgdb_tty_driver->poll_put_char(kgdb_tty_driver, kgdb_tty_line, chr); +} + +static int param_set_kgdboc_var(const char *kmessage, struct kernel_param *kp) +{ + if (strlen(kmessage) >= MAX_CONFIG_LEN) { + printk(KERN_ERR "kgdboc: config string too long\n"); + return -ENOSPC; + } + + /* Only copy in the string if the init function has not run yet */ + if (configured < 0) { + strcpy(config, kmessage); + return 0; + } + + if (kgdb_connected) { + printk(KERN_ERR + "kgdboc: Cannot reconfigure while KGDB is connected.\n"); + + return -EBUSY; + } + + strcpy(config, kmessage); + + if (configured == 1) + cleanup_kgdboc(); + + /* Go and configure with the new params. */ + return configure_kgdboc(); +} + +static void kgdboc_pre_exp_handler(void) +{ + /* Increment the module count when the debugger is active */ + if (!kgdb_connected) + try_module_get(THIS_MODULE); +} + +static void kgdboc_post_exp_handler(void) +{ + /* decrement the module count when the debugger detaches */ + if (!kgdb_connected) + module_put(THIS_MODULE); +} + +static struct kgdb_io kgdboc_io_ops = { + .name = "kgdboc", + .read_char = kgdboc_get_char, + .write_char = kgdboc_put_char, + .pre_exception = kgdboc_pre_exp_handler, + .post_exception = kgdboc_post_exp_handler, +}; + +module_init(init_kgdboc); +module_exit(cleanup_kgdboc); +module_param_call(kgdboc, param_set_kgdboc_var, param_get_string, &kps, 0644); +MODULE_PARM_DESC(kgdboc, "[,baud]"); +MODULE_DESCRIPTION("KGDB Console TTY Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/serial/serial_core.c b/drivers/serial/serial_core.c index 0f5a17987cc..4d7eecbead9 100644 --- a/drivers/serial/serial_core.c +++ b/drivers/serial/serial_core.c @@ -1827,7 +1827,7 @@ uart_get_console(struct uart_port *ports, int nr, struct console *co) * options. The format of the string is , * eg: 115200n8r */ -void __init +void uart_parse_options(char *options, int *baud, int *parity, int *bits, int *flow) { char *s = options; @@ -1842,6 +1842,7 @@ uart_parse_options(char *options, int *baud, int *parity, int *bits, int *flow) if (*s) *flow = *s; } +EXPORT_SYMBOL_GPL(uart_parse_options); struct baud_rates { unsigned int rate; @@ -1872,7 +1873,7 @@ static const struct baud_rates baud_rates[] = { * @bits: number of data bits * @flow: flow control character - 'r' (rts) */ -int __init +int uart_set_options(struct uart_port *port, struct console *co, int baud, int parity, int bits, int flow) { @@ -1924,10 +1925,16 @@ uart_set_options(struct uart_port *port, struct console *co, port->mctrl |= TIOCM_DTR; port->ops->set_termios(port, &termios, &dummy); - co->cflag = termios.c_cflag; + /* + * 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 */ static void uart_change_pm(struct uart_state *state, int pm_state) @@ -2182,6 +2189,60 @@ uart_configure_port(struct uart_driver *drv, struct uart_state *state, } } +#ifdef CONFIG_CONSOLE_POLL + +static int uart_poll_init(struct tty_driver *driver, int line, char *options) +{ + struct uart_driver *drv = driver->driver_state; + struct uart_state *state = drv->state + line; + struct uart_port *port; + int baud = 9600; + int bits = 8; + int parity = 'n'; + int flow = 'n'; + + if (!state || !state->port) + return -1; + + port = state->port; + if (!(port->ops->poll_get_char && port->ops->poll_put_char)) + return -1; + + if (options) { + uart_parse_options(options, &baud, &parity, &bits, &flow); + return uart_set_options(port, NULL, baud, parity, bits, flow); + } + + return 0; +} + +static int uart_poll_get_char(struct tty_driver *driver, int line) +{ + struct uart_driver *drv = driver->driver_state; + struct uart_state *state = drv->state + line; + struct uart_port *port; + + if (!state || !state->port) + return -1; + + port = state->port; + return port->ops->poll_get_char(port); +} + +static void uart_poll_put_char(struct tty_driver *driver, int line, char ch) +{ + struct uart_driver *drv = driver->driver_state; + struct uart_state *state = drv->state + line; + struct uart_port *port; + + if (!state || !state->port) + return; + + port = state->port; + port->ops->poll_put_char(port, ch); +} +#endif + static const struct tty_operations uart_ops = { .open = uart_open, .close = uart_close, @@ -2206,6 +2267,11 @@ static const struct tty_operations uart_ops = { #endif .tiocmget = uart_tiocmget, .tiocmset = uart_tiocmset, +#ifdef CONFIG_CONSOLE_POLL + .poll_init = uart_poll_init, + .poll_get_char = uart_poll_get_char, + .poll_put_char = uart_poll_put_char, +#endif }; /** diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h index 289942fc665..7cb094a8245 100644 --- a/include/linux/serial_core.h +++ b/include/linux/serial_core.h @@ -213,6 +213,10 @@ struct uart_ops { void (*config_port)(struct uart_port *, int); int (*verify_port)(struct uart_port *, struct serial_struct *); int (*ioctl)(struct uart_port *, unsigned int, unsigned long); +#ifdef CONFIG_CONSOLE_POLL + void (*poll_put_char)(struct uart_port *, unsigned char); + int (*poll_get_char)(struct uart_port *); +#endif }; #define UART_CONFIG_TYPE (1 << 0) diff --git a/include/linux/tty_driver.h b/include/linux/tty_driver.h index 85c95cd39bc..21f69aca450 100644 --- a/include/linux/tty_driver.h +++ b/include/linux/tty_driver.h @@ -125,6 +125,7 @@ #include struct tty_struct; +struct tty_driver; struct tty_operations { int (*open)(struct tty_struct * tty, struct file * filp); @@ -157,6 +158,11 @@ struct tty_operations { int (*tiocmget)(struct tty_struct *tty, struct file *file); int (*tiocmset)(struct tty_struct *tty, struct file *file, unsigned int set, unsigned int clear); +#ifdef CONFIG_CONSOLE_POLL + int (*poll_init)(struct tty_driver *driver, int line, char *options); + int (*poll_get_char)(struct tty_driver *driver, int line); + void (*poll_put_char)(struct tty_driver *driver, int line, char ch); +#endif }; struct tty_driver { @@ -220,6 +226,11 @@ struct tty_driver { int (*tiocmget)(struct tty_struct *tty, struct file *file); int (*tiocmset)(struct tty_struct *tty, struct file *file, unsigned int set, unsigned int clear); +#ifdef CONFIG_CONSOLE_POLL + int (*poll_init)(struct tty_driver *driver, int line, char *options); + int (*poll_get_char)(struct tty_driver *driver, int line); + void (*poll_put_char)(struct tty_driver *driver, int line, char ch); +#endif struct list_head tty_drivers; }; @@ -230,6 +241,7 @@ struct tty_driver *alloc_tty_driver(int lines); void put_tty_driver(struct tty_driver *driver); void tty_set_operations(struct tty_driver *driver, const struct tty_operations *op); +extern struct tty_driver *tty_find_polling_driver(char *name, int *line); /* tty driver magic number */ #define TTY_DRIVER_MAGIC 0x5402 -- cgit v1.2.3-70-g09d2 From c191e5ad6b3fd8cc84b2b6d62c02fcd6837c8a8f Mon Sep 17 00:00:00 2001 From: Jason Wessel Date: Fri, 15 Feb 2008 14:55:52 -0600 Subject: kgdb: fix kgdboc dynamic module configuration Fix the run time configuration of kgdboc such that it does not default to 9600 baud if you use the "echo" command to configure the sysfs module paramater. Signed-off-by: Jason Wessel Signed-off-by: Ingo Molnar --- drivers/serial/kgdboc.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers/serial') diff --git a/drivers/serial/kgdboc.c b/drivers/serial/kgdboc.c index 34183079160..9cf03327386 100644 --- a/drivers/serial/kgdboc.c +++ b/drivers/serial/kgdboc.c @@ -106,7 +106,9 @@ static void kgdboc_put_char(u8 chr) static int param_set_kgdboc_var(const char *kmessage, struct kernel_param *kp) { - if (strlen(kmessage) >= MAX_CONFIG_LEN) { + int len = strlen(kmessage); + + if (len >= MAX_CONFIG_LEN) { printk(KERN_ERR "kgdboc: config string too long\n"); return -ENOSPC; } @@ -125,6 +127,9 @@ static int param_set_kgdboc_var(const char *kmessage, struct kernel_param *kp) } strcpy(config, kmessage); + /* Chop out \n char as a result of echo */ + if (config[len - 1] == '\n') + config[len - 1] = '\0'; if (configured == 1) cleanup_kgdboc(); -- cgit v1.2.3-70-g09d2 From 84b5ae15216aa3ea0314f395536ef9829af21e14 Mon Sep 17 00:00:00 2001 From: Jason Wessel Date: Wed, 20 Feb 2008 13:33:39 -0600 Subject: kgdb: kgdboc pl011 I/O module Implement the serial polling hooks for the pl011 uart for use with kgdboc. This patch was specifically tested on the ARM Versatile AB reference platform. [ mingo@elte.hu: minor cleanups. ] Signed-off-by: Jason Wessel Signed-off-by: Ingo Molnar Signed-off-by: Thomas Gleixner --- drivers/serial/amba-pl011.c | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) (limited to 'drivers/serial') diff --git a/drivers/serial/amba-pl011.c b/drivers/serial/amba-pl011.c index 40604a09292..08adc1de4a7 100644 --- a/drivers/serial/amba-pl011.c +++ b/drivers/serial/amba-pl011.c @@ -314,6 +314,32 @@ static void pl011_break_ctl(struct uart_port *port, int break_state) spin_unlock_irqrestore(&uap->port.lock, flags); } +#ifdef CONFIG_CONSOLE_POLL +static int pl010_get_poll_char(struct uart_port *port) +{ + struct uart_amba_port *uap = (struct uart_amba_port *)port; + unsigned int status; + + do { + status = readw(uap->port.membase + UART01x_FR); + } while (status & UART01x_FR_RXFE); + + return readw(uap->port.membase + UART01x_DR); +} + +static void pl010_put_poll_char(struct uart_port *port, + unsigned char ch) +{ + struct uart_amba_port *uap = (struct uart_amba_port *)port; + + while (readw(uap->port.membase + UART01x_FR) & UART01x_FR_TXFF) + barrier(); + + writew(ch, uap->port.membase + UART01x_DR); +} + +#endif /* CONFIG_CONSOLE_POLL */ + static int pl011_startup(struct uart_port *port) { struct uart_amba_port *uap = (struct uart_amba_port *)port; @@ -572,6 +598,10 @@ static struct uart_ops amba_pl011_pops = { .request_port = pl010_request_port, .config_port = pl010_config_port, .verify_port = pl010_verify_port, +#ifdef CONFIG_CONSOLE_POLL + .poll_get_char = pl010_get_poll_char, + .poll_put_char = pl010_put_poll_char, +#endif }; static struct uart_amba_port *amba_ports[UART_NR]; -- cgit v1.2.3-70-g09d2 From 4a1b5502d426df09b9ba1cbcc74fd09702a74cd8 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Fri, 7 Mar 2008 15:51:16 -0800 Subject: kgdb: Kconfig fix ERROR: "uart_parse_options" [drivers/serial/serial_core.ko] undefined! Cc: Jason Wessel Signed-off-by: Andrew Morton Signed-off-by: Ingo Molnar --- drivers/serial/serial_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/serial') diff --git a/drivers/serial/serial_core.c b/drivers/serial/serial_core.c index 4d7eecbead9..c32c1ca75f6 100644 --- a/drivers/serial/serial_core.c +++ b/drivers/serial/serial_core.c @@ -1771,7 +1771,7 @@ static int uart_read_proc(char *page, char **start, off_t off, } #endif -#ifdef CONFIG_SERIAL_CORE_CONSOLE +#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 -- cgit v1.2.3-70-g09d2