From 593a27c4b212e2afdf772a1f8dcb894e91bda0fa Mon Sep 17 00:00:00 2001 From: Konstantin Khlebnikov Date: Thu, 5 Jan 2012 13:04:21 +0400 Subject: tty: cleanup prohibition of direct opening for unix98 pty master cleanup hack added in v2.6.27-3203-g15582d3 comment from that patch: : pty: If the administrator creates a device for a ptmx slave we should not error : : The open path for ptmx slaves is via the ptmx device. Opening them any : other way is not allowed. Vegard Nossum found that previously this was not : the case and mknod foo c 128 42; cat foo would produce nasty diagnostics : : Signed-off-by: Alan Cox : Signed-off-by: Linus Torvalds devpts_get_tty() returns non-null only for inodes on devpts, but there is no inodes for master-devices, /dev/ptmx (/dev/pts/ptmx) is the only way to open them. Thus we can completely forbid lookup for master-devices and eliminate that hack in tty_init_dev() because tty_open() will get EIO from tty_driver_lookup_tty(). Signed-off-by: Konstantin Khlebnikov Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/pty.c b/drivers/tty/pty.c index d8653ab..03147fa 100644 --- a/drivers/tty/pty.c +++ b/drivers/tty/pty.c @@ -515,10 +515,8 @@ static int pty_unix98_ioctl(struct tty_struct *tty, static struct tty_struct *ptm_unix98_lookup(struct tty_driver *driver, struct inode *ptm_inode, int idx) { - struct tty_struct *tty = devpts_get_tty(ptm_inode, idx); - if (tty) - tty = tty->link; - return tty; + /* Master must be open via /dev/ptmx */ + return ERR_PTR(-EIO); } /** @@ -677,7 +675,7 @@ static int ptmx_open(struct inode *inode, struct file *filp) mutex_lock(&tty_mutex); tty_lock(); - tty = tty_init_dev(ptm_driver, index, 1); + tty = tty_init_dev(ptm_driver, index); mutex_unlock(&tty_mutex); if (IS_ERR(tty)) { diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index e41b9bb..fbcc140 100644 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c @@ -1365,7 +1365,6 @@ static int tty_reopen(struct tty_struct *tty) * @driver: tty driver we are opening a device on * @idx: device index * @ret_tty: returned tty structure - * @first_ok: ok to open a new device (used by ptmx) * * Prepare a tty device. This may not be a "new" clean device but * could also be an active device. The pty drivers require special @@ -1385,18 +1384,11 @@ static int tty_reopen(struct tty_struct *tty) * relaxed for the (most common) case of reopening a tty. */ -struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx, - int first_ok) +struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx) { struct tty_struct *tty; int retval; - /* Check if pty master is being opened multiple times */ - if (driver->subtype == PTY_TYPE_MASTER && - (driver->flags & TTY_DRIVER_DEVPTS_MEM) && !first_ok) { - return ERR_PTR(-EIO); - } - /* * First time open is complex, especially for PTY devices. * This code guarantees that either everything succeeds and the @@ -1950,7 +1942,7 @@ retry_open: if (retval) tty = ERR_PTR(retval); } else - tty = tty_init_dev(driver, index, 0); + tty = tty_init_dev(driver, index); mutex_unlock(&tty_mutex); if (driver) diff --git a/include/linux/tty.h b/include/linux/tty.h index 5dbb3cb..d3ebd76 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h @@ -480,8 +480,7 @@ extern void free_tty_struct(struct tty_struct *tty); extern void initialize_tty_struct(struct tty_struct *tty, struct tty_driver *driver, int idx); extern void deinitialize_tty_struct(struct tty_struct *tty); -extern struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx, - int first_ok); +extern struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx); extern int tty_release(struct inode *inode, struct file *filp); extern int tty_init_termios(struct tty_struct *tty); -- cgit v0.10.2 From a4834c102f4a46808630cad1a545cb0706b3b0a2 Mon Sep 17 00:00:00 2001 From: Konstantin Khlebnikov Date: Thu, 5 Jan 2012 13:06:02 +0400 Subject: tty: move pty count limiting into devpts Let's move this stuff to the better place, where we can account pty right in tty-indexes managing code. Signed-off-by: Konstantin Khlebnikov Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/pty.c b/drivers/tty/pty.c index 03147fa..d505837 100644 --- a/drivers/tty/pty.c +++ b/drivers/tty/pty.c @@ -21,7 +21,6 @@ #include #include #include -#include #include #include #include @@ -439,55 +438,9 @@ static inline void legacy_pty_init(void) { } /* Unix98 devices */ #ifdef CONFIG_UNIX98_PTYS -/* - * sysctl support for setting limits on the number of Unix98 ptys allocated. - * Otherwise one can eat up all kernel memory by opening /dev/ptmx repeatedly. - */ -int pty_limit = NR_UNIX98_PTY_DEFAULT; -static int pty_limit_min; -static int pty_limit_max = NR_UNIX98_PTY_MAX; -static int pty_count; static struct cdev ptmx_cdev; -static struct ctl_table pty_table[] = { - { - .procname = "max", - .maxlen = sizeof(int), - .mode = 0644, - .data = &pty_limit, - .proc_handler = proc_dointvec_minmax, - .extra1 = &pty_limit_min, - .extra2 = &pty_limit_max, - }, { - .procname = "nr", - .maxlen = sizeof(int), - .mode = 0444, - .data = &pty_count, - .proc_handler = proc_dointvec, - }, - {} -}; - -static struct ctl_table pty_kern_table[] = { - { - .procname = "pty", - .mode = 0555, - .child = pty_table, - }, - {} -}; - -static struct ctl_table pty_root_table[] = { - { - .procname = "kernel", - .mode = 0555, - .child = pty_kern_table, - }, - {} -}; - - static int pty_unix98_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg) { @@ -587,7 +540,6 @@ static int pty_unix98_install(struct tty_driver *driver, struct tty_struct *tty) */ tty_driver_kref_get(driver); tty->count++; - pty_count++; return 0; err_free_mem: deinitialize_tty_struct(o_tty); @@ -601,7 +553,6 @@ err_free_tty: static void ptm_unix98_remove(struct tty_driver *driver, struct tty_struct *tty) { - pty_count--; } static void pts_unix98_remove(struct tty_driver *driver, struct tty_struct *tty) @@ -760,8 +711,6 @@ static void __init unix98_pty_init(void) if (tty_register_driver(pts_driver)) panic("Couldn't register Unix98 pts driver"); - register_sysctl_table(pty_root_table); - /* Now create the /dev/ptmx special device */ tty_default_fops(&ptmx_fops); ptmx_fops.open = ptmx_open; diff --git a/fs/devpts/inode.c b/fs/devpts/inode.c index c4e2a58..c2c7317 100644 --- a/fs/devpts/inode.c +++ b/fs/devpts/inode.c @@ -36,7 +36,52 @@ #define DEVPTS_DEFAULT_PTMX_MODE 0000 #define PTMX_MINOR 2 -extern int pty_limit; /* Config limit on Unix98 ptys */ +/* + * sysctl support for setting limits on the number of Unix98 ptys allocated. + * Otherwise one can eat up all kernel memory by opening /dev/ptmx repeatedly. + */ +static int pty_limit = NR_UNIX98_PTY_DEFAULT; +static int pty_limit_min; +static int pty_limit_max = NR_UNIX98_PTY_MAX; +static int pty_count; + +static struct ctl_table pty_table[] = { + { + .procname = "max", + .maxlen = sizeof(int), + .mode = 0644, + .data = &pty_limit, + .proc_handler = proc_dointvec_minmax, + .extra1 = &pty_limit_min, + .extra2 = &pty_limit_max, + }, { + .procname = "nr", + .maxlen = sizeof(int), + .mode = 0444, + .data = &pty_count, + .proc_handler = proc_dointvec, + }, + {} +}; + +static struct ctl_table pty_kern_table[] = { + { + .procname = "pty", + .mode = 0555, + .child = pty_table, + }, + {} +}; + +static struct ctl_table pty_root_table[] = { + { + .procname = "kernel", + .mode = 0555, + .child = pty_kern_table, + }, + {} +}; + static DEFINE_MUTEX(allocated_ptys_lock); static struct vfsmount *devpts_mnt; @@ -451,6 +496,7 @@ retry: mutex_unlock(&allocated_ptys_lock); return -EIO; } + pty_count++; mutex_unlock(&allocated_ptys_lock); return index; } @@ -462,6 +508,7 @@ void devpts_kill_index(struct inode *ptmx_inode, int idx) mutex_lock(&allocated_ptys_lock); ida_remove(&fsi->allocated_ptys, idx); + pty_count--; mutex_unlock(&allocated_ptys_lock); } @@ -558,11 +605,15 @@ void devpts_pty_kill(struct tty_struct *tty) static int __init init_devpts_fs(void) { int err = register_filesystem(&devpts_fs_type); + struct ctl_table_header *table; + if (!err) { + table = register_sysctl_table(pty_root_table); devpts_mnt = kern_mount(&devpts_fs_type); if (IS_ERR(devpts_mnt)) { err = PTR_ERR(devpts_mnt); unregister_filesystem(&devpts_fs_type); + unregister_sysctl_table(table); } } return err; -- cgit v0.10.2 From e9aba5158a80098447ff207a452a3418ae7ee386 Mon Sep 17 00:00:00 2001 From: Konstantin Khlebnikov Date: Thu, 5 Jan 2012 13:06:11 +0400 Subject: tty: rework pty count limiting After adding devpts multiple-insrances sysctl kernel.pty.max limit pty count for each devpts instance independently, while kernel.pty.nr shows total pty count. This patch restores sysctl kernel.pty.max as global limit (4096 by default), adds pty reseve for main devpts (mounted without "newinstance" argument), and new sysctl to tune it: kernel.pty.reserve (1024 by default) Also it adds devpts mount option "max=%d" to limit pty count for each devpts instance independently. (by default NR_UNIX98_PTY_MAX == 2^20) Thus devpts instances in containers cannot eat up all available pty even if we didn't set any limits, while with "max" argument we can adjust limits more precisely. Plus, now open("/dev/ptmx") return -ENOSPC in case lack of pty indexes, this is more informative than -EIO. Signed-off-by: Konstantin Khlebnikov Signed-off-by: Greg Kroah-Hartman diff --git a/fs/devpts/inode.c b/fs/devpts/inode.c index c2c7317..1c6f908 100644 --- a/fs/devpts/inode.c +++ b/fs/devpts/inode.c @@ -41,8 +41,9 @@ * Otherwise one can eat up all kernel memory by opening /dev/ptmx repeatedly. */ static int pty_limit = NR_UNIX98_PTY_DEFAULT; +static int pty_reserve = NR_UNIX98_PTY_RESERVE; static int pty_limit_min; -static int pty_limit_max = NR_UNIX98_PTY_MAX; +static int pty_limit_max = INT_MAX; static int pty_count; static struct ctl_table pty_table[] = { @@ -55,6 +56,14 @@ static struct ctl_table pty_table[] = { .extra1 = &pty_limit_min, .extra2 = &pty_limit_max, }, { + .procname = "reserve", + .maxlen = sizeof(int), + .mode = 0644, + .data = &pty_reserve, + .proc_handler = proc_dointvec_minmax, + .extra1 = &pty_limit_min, + .extra2 = &pty_limit_max, + }, { .procname = "nr", .maxlen = sizeof(int), .mode = 0444, @@ -94,10 +103,11 @@ struct pts_mount_opts { umode_t mode; umode_t ptmxmode; int newinstance; + int max; }; enum { - Opt_uid, Opt_gid, Opt_mode, Opt_ptmxmode, Opt_newinstance, + Opt_uid, Opt_gid, Opt_mode, Opt_ptmxmode, Opt_newinstance, Opt_max, Opt_err }; @@ -108,6 +118,7 @@ static const match_table_t tokens = { #ifdef CONFIG_DEVPTS_MULTIPLE_INSTANCES {Opt_ptmxmode, "ptmxmode=%o"}, {Opt_newinstance, "newinstance"}, + {Opt_max, "max=%d"}, #endif {Opt_err, NULL} }; @@ -154,6 +165,7 @@ static int parse_mount_options(char *data, int op, struct pts_mount_opts *opts) opts->gid = 0; opts->mode = DEVPTS_DEFAULT_MODE; opts->ptmxmode = DEVPTS_DEFAULT_PTMX_MODE; + opts->max = NR_UNIX98_PTY_MAX; /* newinstance makes sense only on initial mount */ if (op == PARSE_MOUNT) @@ -197,6 +209,12 @@ static int parse_mount_options(char *data, int op, struct pts_mount_opts *opts) if (op == PARSE_MOUNT) opts->newinstance = 1; break; + case Opt_max: + if (match_int(&args[0], &option) || + option < 0 || option > NR_UNIX98_PTY_MAX) + return -EINVAL; + opts->max = option; + break; #endif default: printk(KERN_ERR "devpts: called with bogus options\n"); @@ -303,6 +321,8 @@ static int devpts_show_options(struct seq_file *seq, struct dentry *root) seq_printf(seq, ",mode=%03o", opts->mode); #ifdef CONFIG_DEVPTS_MULTIPLE_INSTANCES seq_printf(seq, ",ptmxmode=%03o", opts->ptmxmode); + if (opts->max < NR_UNIX98_PTY_MAX) + seq_printf(seq, ",max=%d", opts->max); #endif return 0; @@ -483,6 +503,12 @@ retry: return -ENOMEM; mutex_lock(&allocated_ptys_lock); + if (pty_count >= pty_limit - + (fsi->mount_opts.newinstance ? pty_reserve : 0)) { + mutex_unlock(&allocated_ptys_lock); + return -ENOSPC; + } + ida_ret = ida_get_new(&fsi->allocated_ptys, &index); if (ida_ret < 0) { mutex_unlock(&allocated_ptys_lock); @@ -491,10 +517,10 @@ retry: return -EIO; } - if (index >= pty_limit) { + if (index >= fsi->mount_opts.max) { ida_remove(&fsi->allocated_ptys, index); mutex_unlock(&allocated_ptys_lock); - return -EIO; + return -ENOSPC; } pty_count++; mutex_unlock(&allocated_ptys_lock); diff --git a/include/linux/tty.h b/include/linux/tty.h index d3ebd76..d407741 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h @@ -52,6 +52,7 @@ * hardcoded at present.) */ #define NR_UNIX98_PTY_DEFAULT 4096 /* Default maximum for Unix98 ptys */ +#define NR_UNIX98_PTY_RESERVE 1024 /* Default reserve for main devpts */ #define NR_UNIX98_PTY_MAX (1 << MINORBITS) /* Absolute limit */ /* -- cgit v0.10.2 From 3afbd89c9639c344300dcdd7d4e5e18dda559fd4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 25 Jan 2012 09:05:04 +0100 Subject: serial/efm32: add new driver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Uwe Kleine-König Signed-off-by: Greg Kroah-Hartman diff --git a/Documentation/devicetree/bindings/tty/serial/efm32-uart.txt b/Documentation/devicetree/bindings/tty/serial/efm32-uart.txt new file mode 100644 index 0000000..6588b69 --- /dev/null +++ b/Documentation/devicetree/bindings/tty/serial/efm32-uart.txt @@ -0,0 +1,14 @@ +* Energymicro efm32 UART + +Required properties: +- compatible : Should be "efm32,uart" +- reg : Address and length of the register set +- interrupts : Should contain uart interrupt + +Example: + +uart@0x4000c400 { + compatible = "efm32,uart"; + reg = <0x4000c400 0x400>; + interrupts = <15>; +}; diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index aca2386..6e24a8f 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -1628,4 +1628,17 @@ config SERIAL_AR933X_NR_UARTS Set this to the number of serial ports you want the driver to support. +config SERIAL_EFM32_UART + tristate "EFM32 UART/USART port." + depends on ARCH_EFM32 + select SERIAL_CORE + help + This driver support the USART and UART ports on + Energy Micro's efm32 SoCs. + +config SERIAL_EFM32_UART_CONSOLE + bool "EFM32 UART/USART console support" + depends on SERIAL_EFM32_UART=y + select SERIAL_CORE_CONSOLE + endmenu diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile index f5b01f2..1997ad4 100644 --- a/drivers/tty/serial/Makefile +++ b/drivers/tty/serial/Makefile @@ -92,3 +92,4 @@ obj-$(CONFIG_SERIAL_LANTIQ) += lantiq.o obj-$(CONFIG_SERIAL_XILINX_PS_UART) += xilinx_uartps.o obj-$(CONFIG_SERIAL_SIRFSOC) += sirfsoc_uart.o obj-$(CONFIG_SERIAL_AR933X) += ar933x_uart.o +obj-$(CONFIG_SERIAL_EFM32_UART) += efm32-uart.o diff --git a/drivers/tty/serial/efm32-uart.c b/drivers/tty/serial/efm32-uart.c new file mode 100644 index 0000000..615e464 --- /dev/null +++ b/drivers/tty/serial/efm32-uart.c @@ -0,0 +1,830 @@ +#if defined(CONFIG_SERIAL_EFM32_UART_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) +#define SUPPORT_SYSRQ +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define DRIVER_NAME "efm32-uart" +#define DEV_NAME "ttyefm" + +#define UARTn_CTRL 0x00 +#define UARTn_CTRL_SYNC 0x0001 +#define UARTn_CTRL_TXBIL 0x1000 + +#define UARTn_FRAME 0x04 +#define UARTn_FRAME_DATABITS__MASK 0x000f +#define UARTn_FRAME_DATABITS(n) ((n) - 3) +#define UARTn_FRAME_PARITY_NONE 0x0000 +#define UARTn_FRAME_PARITY_EVEN 0x0200 +#define UARTn_FRAME_PARITY_ODD 0x0300 +#define UARTn_FRAME_STOPBITS_HALF 0x0000 +#define UARTn_FRAME_STOPBITS_ONE 0x1000 +#define UARTn_FRAME_STOPBITS_TWO 0x3000 + +#define UARTn_CMD 0x0c +#define UARTn_CMD_RXEN 0x0001 +#define UARTn_CMD_RXDIS 0x0002 +#define UARTn_CMD_TXEN 0x0004 +#define UARTn_CMD_TXDIS 0x0008 + +#define UARTn_STATUS 0x10 +#define UARTn_STATUS_TXENS 0x0002 +#define UARTn_STATUS_TXC 0x0020 +#define UARTn_STATUS_TXBL 0x0040 +#define UARTn_STATUS_RXDATAV 0x0080 + +#define UARTn_CLKDIV 0x14 + +#define UARTn_RXDATAX 0x18 +#define UARTn_RXDATAX_RXDATA__MASK 0x01ff +#define UARTn_RXDATAX_PERR 0x4000 +#define UARTn_RXDATAX_FERR 0x8000 +/* + * This is a software only flag used for ignore_status_mask and + * read_status_mask! It's used for breaks that the hardware doesn't report + * explicitly. + */ +#define SW_UARTn_RXDATAX_BERR 0x2000 + +#define UARTn_TXDATA 0x34 + +#define UARTn_IF 0x40 +#define UARTn_IF_TXC 0x0001 +#define UARTn_IF_TXBL 0x0002 +#define UARTn_IF_RXDATAV 0x0004 +#define UARTn_IF_RXOF 0x0010 + +#define UARTn_IFS 0x44 +#define UARTn_IFC 0x48 +#define UARTn_IEN 0x4c + +#define UARTn_ROUTE 0x54 +#define UARTn_ROUTE_LOCATION__MASK 0x0700 +#define UARTn_ROUTE_LOCATION(n) (((n) << 8) & UARTn_ROUTE_LOCATION__MASK) +#define UARTn_ROUTE_RXPEN 0x0001 +#define UARTn_ROUTE_TXPEN 0x0002 + +struct efm32_uart_port { + struct uart_port port; + unsigned int txirq; + struct clk *clk; +}; +#define to_efm_port(_port) container_of(_port, struct efm32_uart_port, port) +#define efm_debug(efm_port, format, arg...) \ + dev_dbg(efm_port->port.dev, format, ##arg) + +static void efm32_uart_write32(struct efm32_uart_port *efm_port, + u32 value, unsigned offset) +{ + writel_relaxed(value, efm_port->port.membase + offset); +} + +static u32 efm32_uart_read32(struct efm32_uart_port *efm_port, + unsigned offset) +{ + return readl_relaxed(efm_port->port.membase + offset); +} + +static unsigned int efm32_uart_tx_empty(struct uart_port *port) +{ + struct efm32_uart_port *efm_port = to_efm_port(port); + u32 status = efm32_uart_read32(efm_port, UARTn_STATUS); + + if (status & UARTn_STATUS_TXC) + return TIOCSER_TEMT; + else + return 0; +} + +static void efm32_uart_set_mctrl(struct uart_port *port, unsigned int mctrl) +{ + /* sorry, neither handshaking lines nor loop functionallity */ +} + +static unsigned int efm32_uart_get_mctrl(struct uart_port *port) +{ + /* sorry, no handshaking lines available */ + return TIOCM_CAR | TIOCM_CTS | TIOCM_DSR; +} + +static void efm32_uart_stop_tx(struct uart_port *port) +{ + struct efm32_uart_port *efm_port = to_efm_port(port); + u32 ien = efm32_uart_read32(efm_port, UARTn_IEN); + + efm32_uart_write32(efm_port, UARTn_CMD_TXDIS, UARTn_CMD); + ien &= ~(UARTn_IF_TXC | UARTn_IF_TXBL); + efm32_uart_write32(efm_port, ien, UARTn_IEN); +} + +static void efm32_uart_tx_chars(struct efm32_uart_port *efm_port) +{ + struct uart_port *port = &efm_port->port; + struct circ_buf *xmit = &port->state->xmit; + + while (efm32_uart_read32(efm_port, UARTn_STATUS) & + UARTn_STATUS_TXBL) { + if (port->x_char) { + port->icount.tx++; + efm32_uart_write32(efm_port, port->x_char, + UARTn_TXDATA); + port->x_char = 0; + continue; + } + if (!uart_circ_empty(xmit) && !uart_tx_stopped(port)) { + port->icount.tx++; + efm32_uart_write32(efm_port, xmit->buf[xmit->tail], + UARTn_TXDATA); + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); + } else + break; + } + + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(port); + + if (!port->x_char && uart_circ_empty(xmit) && + efm32_uart_read32(efm_port, UARTn_STATUS) & + UARTn_STATUS_TXC) + efm32_uart_stop_tx(port); +} + +static void efm32_uart_start_tx(struct uart_port *port) +{ + struct efm32_uart_port *efm_port = to_efm_port(port); + u32 ien; + + efm32_uart_write32(efm_port, + UARTn_IF_TXBL | UARTn_IF_TXC, UARTn_IFC); + ien = efm32_uart_read32(efm_port, UARTn_IEN); + efm32_uart_write32(efm_port, + ien | UARTn_IF_TXBL | UARTn_IF_TXC, UARTn_IEN); + efm32_uart_write32(efm_port, UARTn_CMD_TXEN, UARTn_CMD); + + efm32_uart_tx_chars(efm_port); +} + +static void efm32_uart_stop_rx(struct uart_port *port) +{ + struct efm32_uart_port *efm_port = to_efm_port(port); + + efm32_uart_write32(efm_port, UARTn_CMD_RXDIS, UARTn_CMD); +} + +static void efm32_uart_enable_ms(struct uart_port *port) +{ + /* no handshake lines, no modem status interrupts */ +} + +static void efm32_uart_break_ctl(struct uart_port *port, int ctl) +{ + /* not possible without fiddling with gpios */ +} + +static void efm32_uart_rx_chars(struct efm32_uart_port *efm_port, + struct tty_struct *tty) +{ + struct uart_port *port = &efm_port->port; + + while (efm32_uart_read32(efm_port, UARTn_STATUS) & + UARTn_STATUS_RXDATAV) { + u32 rxdata = efm32_uart_read32(efm_port, UARTn_RXDATAX); + int flag = 0; + + /* + * This is a reserved bit and I only saw it read as 0. But to be + * sure not to be confused too much by new devices adhere to the + * warning in the reference manual that reserverd bits might + * read as 1 in the future. + */ + rxdata &= ~SW_UARTn_RXDATAX_BERR; + + port->icount.rx++; + + if ((rxdata & UARTn_RXDATAX_FERR) && + !(rxdata & UARTn_RXDATAX_RXDATA__MASK)) { + rxdata |= SW_UARTn_RXDATAX_BERR; + port->icount.brk++; + if (uart_handle_break(port)) + continue; + } else if (rxdata & UARTn_RXDATAX_PERR) + port->icount.parity++; + else if (rxdata & UARTn_RXDATAX_FERR) + port->icount.frame++; + + rxdata &= port->read_status_mask; + + if (rxdata & SW_UARTn_RXDATAX_BERR) + flag = TTY_BREAK; + else if (rxdata & UARTn_RXDATAX_PERR) + flag = TTY_PARITY; + else if (rxdata & UARTn_RXDATAX_FERR) + flag = TTY_FRAME; + else if (uart_handle_sysrq_char(port, + rxdata & UARTn_RXDATAX_RXDATA__MASK)) + continue; + + if (tty && (rxdata & port->ignore_status_mask) == 0) + tty_insert_flip_char(tty, + rxdata & UARTn_RXDATAX_RXDATA__MASK, flag); + } +} + +static irqreturn_t efm32_uart_rxirq(int irq, void *data) +{ + struct efm32_uart_port *efm_port = data; + u32 irqflag = efm32_uart_read32(efm_port, UARTn_IF); + int handled = IRQ_NONE; + struct uart_port *port = &efm_port->port; + struct tty_struct *tty; + + spin_lock(&port->lock); + + tty = tty_kref_get(port->state->port.tty); + + if (irqflag & UARTn_IF_RXDATAV) { + efm32_uart_write32(efm_port, UARTn_IF_RXDATAV, UARTn_IFC); + efm32_uart_rx_chars(efm_port, tty); + + handled = IRQ_HANDLED; + } + + if (irqflag & UARTn_IF_RXOF) { + efm32_uart_write32(efm_port, UARTn_IF_RXOF, UARTn_IFC); + port->icount.overrun++; + if (tty) + tty_insert_flip_char(tty, 0, TTY_OVERRUN); + + handled = IRQ_HANDLED; + } + + if (tty) { + tty_flip_buffer_push(tty); + tty_kref_put(tty); + } + + spin_unlock(&port->lock); + + return handled; +} + +static irqreturn_t efm32_uart_txirq(int irq, void *data) +{ + struct efm32_uart_port *efm_port = data; + u32 irqflag = efm32_uart_read32(efm_port, UARTn_IF); + + /* TXBL doesn't need to be cleared */ + if (irqflag & UARTn_IF_TXC) + efm32_uart_write32(efm_port, UARTn_IF_TXC, UARTn_IFC); + + if (irqflag & (UARTn_IF_TXC | UARTn_IF_TXBL)) { + efm32_uart_tx_chars(efm_port); + return IRQ_HANDLED; + } else + return IRQ_NONE; +} + +static int efm32_uart_startup(struct uart_port *port) +{ + struct efm32_uart_port *efm_port = to_efm_port(port); + u32 location = 0; + struct efm32_uart_pdata *pdata = dev_get_platdata(port->dev); + int ret; + + if (pdata) + location = UARTn_ROUTE_LOCATION(pdata->location); + + ret = clk_enable(efm_port->clk); + if (ret) { + efm_debug(efm_port, "failed to enable clk\n"); + goto err_clk_enable; + } + port->uartclk = clk_get_rate(efm_port->clk); + + /* Enable pins at configured location */ + efm32_uart_write32(efm_port, location | UARTn_ROUTE_RXPEN | UARTn_ROUTE_TXPEN, + UARTn_ROUTE); + + ret = request_irq(port->irq, efm32_uart_rxirq, 0, + DRIVER_NAME, efm_port); + if (ret) { + efm_debug(efm_port, "failed to register rxirq\n"); + goto err_request_irq_rx; + } + + /* disable all irqs */ + efm32_uart_write32(efm_port, 0, UARTn_IEN); + + ret = request_irq(efm_port->txirq, efm32_uart_txirq, 0, + DRIVER_NAME, efm_port); + if (ret) { + efm_debug(efm_port, "failed to register txirq\n"); + free_irq(port->irq, efm_port); +err_request_irq_rx: + + clk_disable(efm_port->clk); + } else { + efm32_uart_write32(efm_port, + UARTn_IF_RXDATAV | UARTn_IF_RXOF, UARTn_IEN); + efm32_uart_write32(efm_port, UARTn_CMD_RXEN, UARTn_CMD); + } + +err_clk_enable: + return ret; +} + +static void efm32_uart_shutdown(struct uart_port *port) +{ + struct efm32_uart_port *efm_port = to_efm_port(port); + + efm32_uart_write32(efm_port, 0, UARTn_IEN); + free_irq(port->irq, efm_port); + + clk_disable(efm_port->clk); +} + +static void efm32_uart_set_termios(struct uart_port *port, + struct ktermios *new, struct ktermios *old) +{ + struct efm32_uart_port *efm_port = to_efm_port(port); + unsigned long flags; + unsigned baud; + u32 clkdiv; + u32 frame = 0; + + /* no modem control lines */ + new->c_cflag &= ~(CRTSCTS | CMSPAR); + + baud = uart_get_baud_rate(port, new, old, + DIV_ROUND_CLOSEST(port->uartclk, 16 * 8192), + DIV_ROUND_CLOSEST(port->uartclk, 16)); + + switch (new->c_cflag & CSIZE) { + case CS5: + frame |= UARTn_FRAME_DATABITS(5); + break; + case CS6: + frame |= UARTn_FRAME_DATABITS(6); + break; + case CS7: + frame |= UARTn_FRAME_DATABITS(7); + break; + case CS8: + frame |= UARTn_FRAME_DATABITS(8); + break; + } + + if (new->c_cflag & CSTOPB) + /* the receiver only verifies the first stop bit */ + frame |= UARTn_FRAME_STOPBITS_TWO; + else + frame |= UARTn_FRAME_STOPBITS_ONE; + + if (new->c_cflag & PARENB) { + if (new->c_cflag & PARODD) + frame |= UARTn_FRAME_PARITY_ODD; + else + frame |= UARTn_FRAME_PARITY_EVEN; + } else + frame |= UARTn_FRAME_PARITY_NONE; + + /* + * the 6 lowest bits of CLKDIV are dc, bit 6 has value 0.25. + * port->uartclk <= 14e6, so 4 * port->uartclk doesn't overflow. + */ + clkdiv = (DIV_ROUND_CLOSEST(4 * port->uartclk, 16 * baud) - 4) << 6; + + spin_lock_irqsave(&port->lock, flags); + + efm32_uart_write32(efm_port, + UARTn_CMD_TXDIS | UARTn_CMD_RXDIS, UARTn_CMD); + + port->read_status_mask = UARTn_RXDATAX_RXDATA__MASK; + if (new->c_iflag & INPCK) + port->read_status_mask |= + UARTn_RXDATAX_FERR | UARTn_RXDATAX_PERR; + if (new->c_iflag & (BRKINT | PARMRK)) + port->read_status_mask |= SW_UARTn_RXDATAX_BERR; + + port->ignore_status_mask = 0; + if (new->c_iflag & IGNPAR) + port->ignore_status_mask |= + UARTn_RXDATAX_FERR | UARTn_RXDATAX_PERR; + if (new->c_iflag & IGNBRK) + port->ignore_status_mask |= SW_UARTn_RXDATAX_BERR; + + uart_update_timeout(port, new->c_cflag, baud); + + efm32_uart_write32(efm_port, UARTn_CTRL_TXBIL, UARTn_CTRL); + efm32_uart_write32(efm_port, frame, UARTn_FRAME); + efm32_uart_write32(efm_port, clkdiv, UARTn_CLKDIV); + + efm32_uart_write32(efm_port, UARTn_CMD_TXEN | UARTn_CMD_RXEN, + UARTn_CMD); + + spin_unlock_irqrestore(&port->lock, flags); +} + +static const char *efm32_uart_type(struct uart_port *port) +{ + return port->type == PORT_EFMUART ? "efm32-uart" : NULL; +} + +static void efm32_uart_release_port(struct uart_port *port) +{ + struct efm32_uart_port *efm_port = to_efm_port(port); + + clk_unprepare(efm_port->clk); + clk_put(efm_port->clk); + iounmap(port->membase); +} + +static int efm32_uart_request_port(struct uart_port *port) +{ + struct efm32_uart_port *efm_port = to_efm_port(port); + int ret; + + port->membase = ioremap(port->mapbase, 60); + if (!efm_port->port.membase) { + ret = -ENOMEM; + efm_debug(efm_port, "failed to remap\n"); + goto err_ioremap; + } + + efm_port->clk = clk_get(port->dev, NULL); + if (IS_ERR(efm_port->clk)) { + ret = PTR_ERR(efm_port->clk); + efm_debug(efm_port, "failed to get clock\n"); + goto err_clk_get; + } + + ret = clk_prepare(efm_port->clk); + if (ret) { + clk_put(efm_port->clk); +err_clk_get: + + iounmap(port->membase); +err_ioremap: + return ret; + } + return 0; +} + +static void efm32_uart_config_port(struct uart_port *port, int type) +{ + if (type & UART_CONFIG_TYPE && + !efm32_uart_request_port(port)) + port->type = PORT_EFMUART; +} + +static int efm32_uart_verify_port(struct uart_port *port, + struct serial_struct *serinfo) +{ + int ret = 0; + + if (serinfo->type != PORT_UNKNOWN && serinfo->type != PORT_EFMUART) + ret = -EINVAL; + + return ret; +} + +static struct uart_ops efm32_uart_pops = { + .tx_empty = efm32_uart_tx_empty, + .set_mctrl = efm32_uart_set_mctrl, + .get_mctrl = efm32_uart_get_mctrl, + .stop_tx = efm32_uart_stop_tx, + .start_tx = efm32_uart_start_tx, + .stop_rx = efm32_uart_stop_rx, + .enable_ms = efm32_uart_enable_ms, + .break_ctl = efm32_uart_break_ctl, + .startup = efm32_uart_startup, + .shutdown = efm32_uart_shutdown, + .set_termios = efm32_uart_set_termios, + .type = efm32_uart_type, + .release_port = efm32_uart_release_port, + .request_port = efm32_uart_request_port, + .config_port = efm32_uart_config_port, + .verify_port = efm32_uart_verify_port, +}; + +static struct efm32_uart_port *efm32_uart_ports[5]; + +#ifdef CONFIG_SERIAL_EFM32_UART_CONSOLE +static void efm32_uart_console_putchar(struct uart_port *port, int ch) +{ + struct efm32_uart_port *efm_port = to_efm_port(port); + unsigned int timeout = 0x400; + u32 status; + + while (1) { + status = efm32_uart_read32(efm_port, UARTn_STATUS); + + if (status & UARTn_STATUS_TXBL) + break; + if (!timeout--) + return; + } + efm32_uart_write32(efm_port, ch, UARTn_TXDATA); +} + +static void efm32_uart_console_write(struct console *co, const char *s, + unsigned int count) +{ + struct efm32_uart_port *efm_port = efm32_uart_ports[co->index]; + u32 status = efm32_uart_read32(efm_port, UARTn_STATUS); + unsigned int timeout = 0x400; + + if (!(status & UARTn_STATUS_TXENS)) + efm32_uart_write32(efm_port, UARTn_CMD_TXEN, UARTn_CMD); + + uart_console_write(&efm_port->port, s, count, + efm32_uart_console_putchar); + + /* Wait for the transmitter to become empty */ + while (1) { + u32 status = efm32_uart_read32(efm_port, UARTn_STATUS); + if (status & UARTn_STATUS_TXC) + break; + if (!timeout--) + break; + } + + if (!(status & UARTn_STATUS_TXENS)) + efm32_uart_write32(efm_port, UARTn_CMD_TXDIS, UARTn_CMD); +} + +static void efm32_uart_console_get_options(struct efm32_uart_port *efm_port, + int *baud, int *parity, int *bits) +{ + u32 ctrl = efm32_uart_read32(efm_port, UARTn_CTRL); + u32 route, clkdiv, frame; + + if (ctrl & UARTn_CTRL_SYNC) + /* not operating in async mode */ + return; + + route = efm32_uart_read32(efm_port, UARTn_ROUTE); + if (!(route & UARTn_ROUTE_TXPEN)) + /* tx pin not routed */ + return; + + clkdiv = efm32_uart_read32(efm_port, UARTn_CLKDIV); + + *baud = DIV_ROUND_CLOSEST(4 * efm_port->port.uartclk, + 16 * (4 + (clkdiv >> 6))); + + frame = efm32_uart_read32(efm_port, UARTn_FRAME); + if (frame & UARTn_FRAME_PARITY_ODD) + *parity = 'o'; + else if (frame & UARTn_FRAME_PARITY_EVEN) + *parity = 'e'; + else + *parity = 'n'; + + *bits = (frame & UARTn_FRAME_DATABITS__MASK) - + UARTn_FRAME_DATABITS(4) + 4; + + efm_debug(efm_port, "get_opts: options=%d%c%d\n", + *baud, *parity, *bits); +} + +static int efm32_uart_console_setup(struct console *co, char *options) +{ + struct efm32_uart_port *efm_port; + int baud = 115200; + int bits = 8; + int parity = 'n'; + int flow = 'n'; + int ret; + + if (co->index < 0 || co->index >= ARRAY_SIZE(efm32_uart_ports)) { + unsigned i; + for (i = 0; i < ARRAY_SIZE(efm32_uart_ports); ++i) { + if (efm32_uart_ports[i]) { + pr_warn("efm32-console: fall back to console index %u (from %hhi)\n", + i, co->index); + co->index = i; + break; + } + } + } + + efm_port = efm32_uart_ports[co->index]; + if (!efm_port) { + pr_warn("efm32-console: No port at %d\n", co->index); + return -ENODEV; + } + + ret = clk_prepare(efm_port->clk); + if (ret) { + dev_warn(efm_port->port.dev, + "console: clk_prepare failed: %d\n", ret); + return ret; + } + + efm_port->port.uartclk = clk_get_rate(efm_port->clk); + + if (options) + uart_parse_options(options, &baud, &parity, &bits, &flow); + else + efm32_uart_console_get_options(efm_port, + &baud, &parity, &bits); + + return uart_set_options(&efm_port->port, co, baud, parity, bits, flow); +} + +static struct uart_driver efm32_uart_reg; + +static struct console efm32_uart_console = { + .name = DEV_NAME, + .write = efm32_uart_console_write, + .device = uart_console_device, + .setup = efm32_uart_console_setup, + .flags = CON_PRINTBUFFER, + .index = -1, + .data = &efm32_uart_reg, +}; + +#else +#define efm32_uart_console (*(struct console *)NULL) +#endif /* ifdef CONFIG_SERIAL_EFM32_UART_CONSOLE / else */ + +static struct uart_driver efm32_uart_reg = { + .owner = THIS_MODULE, + .driver_name = DRIVER_NAME, + .dev_name = DEV_NAME, + .nr = ARRAY_SIZE(efm32_uart_ports), + .cons = &efm32_uart_console, +}; + +static int efm32_uart_probe_dt(struct platform_device *pdev, + struct efm32_uart_port *efm_port) +{ + struct device_node *np = pdev->dev.of_node; + int ret; + + if (!np) + return 1; + + ret = of_alias_get_id(np, "serial"); + if (ret < 0) { + dev_err(&pdev->dev, "failed to get alias id: %d\n", ret); + return ret; + } else { + efm_port->port.line = ret; + return 0; + } + +} + +static int __devinit efm32_uart_probe(struct platform_device *pdev) +{ + struct efm32_uart_port *efm_port; + struct resource *res; + int ret; + + efm_port = kzalloc(sizeof(*efm_port), GFP_KERNEL); + if (!efm_port) { + dev_dbg(&pdev->dev, "failed to allocate private data\n"); + return -ENOMEM; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + ret = -ENODEV; + dev_dbg(&pdev->dev, "failed to determine base address\n"); + goto err_get_base; + } + + if (resource_size(res) < 60) { + ret = -EINVAL; + dev_dbg(&pdev->dev, "memory resource too small\n"); + goto err_too_small; + } + + ret = platform_get_irq(pdev, 0); + if (ret <= 0) { + dev_dbg(&pdev->dev, "failed to get rx irq\n"); + goto err_get_rxirq; + } + + efm_port->port.irq = ret; + + ret = platform_get_irq(pdev, 1); + if (ret <= 0) + ret = efm_port->port.irq + 1; + + efm_port->txirq = ret; + + efm_port->port.dev = &pdev->dev; + efm_port->port.mapbase = res->start; + efm_port->port.type = PORT_EFMUART; + efm_port->port.iotype = UPIO_MEM32; + efm_port->port.fifosize = 2; + efm_port->port.ops = &efm32_uart_pops; + efm_port->port.flags = UPF_BOOT_AUTOCONF; + + ret = efm32_uart_probe_dt(pdev, efm_port); + if (ret > 0) + /* not created by device tree */ + efm_port->port.line = pdev->id; + + if (efm_port->port.line >= 0 && + efm_port->port.line < ARRAY_SIZE(efm32_uart_ports)) + efm32_uart_ports[efm_port->port.line] = efm_port; + + ret = uart_add_one_port(&efm32_uart_reg, &efm_port->port); + if (ret) { + dev_dbg(&pdev->dev, "failed to add port: %d\n", ret); + + if (pdev->id >= 0 && pdev->id < ARRAY_SIZE(efm32_uart_ports)) + efm32_uart_ports[pdev->id] = NULL; +err_get_rxirq: +err_too_small: +err_get_base: + kfree(efm_port); + } else { + platform_set_drvdata(pdev, efm_port); + dev_dbg(&pdev->dev, "\\o/\n"); + } + + return ret; +} + +static int __devexit efm32_uart_remove(struct platform_device *pdev) +{ + struct efm32_uart_port *efm_port = platform_get_drvdata(pdev); + + platform_set_drvdata(pdev, NULL); + + uart_remove_one_port(&efm32_uart_reg, &efm_port->port); + + if (pdev->id >= 0 && pdev->id < ARRAY_SIZE(efm32_uart_ports)) + efm32_uart_ports[pdev->id] = NULL; + + kfree(efm_port); + + return 0; +} + +static struct of_device_id efm32_uart_dt_ids[] = { + { + .compatible = "efm32,uart", + }, { + /* sentinel */ + } +}; +MODULE_DEVICE_TABLE(of, efm32_uart_dt_ids); + +static struct platform_driver efm32_uart_driver = { + .probe = efm32_uart_probe, + .remove = __devexit_p(efm32_uart_remove), + + .driver = { + .name = DRIVER_NAME, + .owner = THIS_MODULE, + .of_match_table = efm32_uart_dt_ids, + }, +}; + +static int __init efm32_uart_init(void) +{ + int ret; + + ret = uart_register_driver(&efm32_uart_reg); + if (ret) + return ret; + + ret = platform_driver_register(&efm32_uart_driver); + if (ret) + uart_unregister_driver(&efm32_uart_reg); + + pr_info("EFM32 UART/USART driver\n"); + + return ret; +} +module_init(efm32_uart_init); + +static void __exit efm32_uart_exit(void) +{ + platform_driver_unregister(&efm32_uart_driver); + uart_unregister_driver(&efm32_uart_reg); +} + +MODULE_AUTHOR("Uwe Kleine-Koenig "); +MODULE_DESCRIPTION("EFM32 UART/USART driver"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:" DRIVER_NAME); diff --git a/include/linux/platform_data/efm32-uart.h b/include/linux/platform_data/efm32-uart.h new file mode 100644 index 0000000..ed0e975 --- /dev/null +++ b/include/linux/platform_data/efm32-uart.h @@ -0,0 +1,18 @@ +/* + * + * + */ +#ifndef __LINUX_PLATFORM_DATA_EFM32_UART_H__ +#define __LINUX_PLATFORM_DATA_EFM32_UART_H__ + +#include + +/** + * struct efm32_uart_pdata + * @location: pinmux location for the I/O pins (to be written to the ROUTE + * register) + */ +struct efm32_uart_pdata { + u8 location; +}; +#endif /* ifndef __LINUX_PLATFORM_DATA_EFM32_UART_H__ */ diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h index c91ace7..585bfd0 100644 --- a/include/linux/serial_core.h +++ b/include/linux/serial_core.h @@ -210,6 +210,8 @@ /* Atheros AR933X SoC */ #define PORT_AR933X 99 +/* Energy Micro efm32 SoC */ +#define PORT_EFMUART 100 #ifdef __KERNEL__ -- cgit v0.10.2 From d4e33fac2408d37f7b52e80ca2a89f9fb482914f Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Thu, 26 Jan 2012 17:44:09 +0000 Subject: serial: Kill off NO_IRQ We transform the offenders into a test of irq <= 0 which will be ok while the ARM people get their platform sorted. Once that is done (or in a while if they don't do it anyway) then we will change them all to !irq checks. For arch specific drivers that are already using NO_IRQ = 0 we just test against zero so we don't need to re-review them later. Signed-off-by: Alan Cox Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/hvc/hvc_beat.c b/drivers/tty/hvc/hvc_beat.c index 5fe4631..1560d23 100644 --- a/drivers/tty/hvc/hvc_beat.c +++ b/drivers/tty/hvc/hvc_beat.c @@ -113,7 +113,7 @@ static int __init hvc_beat_init(void) if (!firmware_has_feature(FW_FEATURE_BEAT)) return -ENODEV; - hp = hvc_alloc(0, NO_IRQ, &hvc_beat_get_put_ops, 16); + hp = hvc_alloc(0, 0, &hvc_beat_get_put_ops, 16); if (IS_ERR(hp)) return PTR_ERR(hp); hvc_beat_dev = hp; diff --git a/drivers/tty/hvc/hvc_rtas.c b/drivers/tty/hvc/hvc_rtas.c index 61c4a61..0069bb8 100644 --- a/drivers/tty/hvc/hvc_rtas.c +++ b/drivers/tty/hvc/hvc_rtas.c @@ -94,7 +94,7 @@ static int __init hvc_rtas_init(void) /* Allocate an hvc_struct for the console device we instantiated * earlier. Save off hp so that we can return it on exit */ - hp = hvc_alloc(hvc_rtas_cookie, NO_IRQ, &hvc_rtas_get_put_ops, 16); + hp = hvc_alloc(hvc_rtas_cookie, 0, &hvc_rtas_get_put_ops, 16); if (IS_ERR(hp)) return PTR_ERR(hp); diff --git a/drivers/tty/hvc/hvc_udbg.c b/drivers/tty/hvc/hvc_udbg.c index b0957e6..4c9b13e 100644 --- a/drivers/tty/hvc/hvc_udbg.c +++ b/drivers/tty/hvc/hvc_udbg.c @@ -69,7 +69,7 @@ static int __init hvc_udbg_init(void) BUG_ON(hvc_udbg_dev); - hp = hvc_alloc(0, NO_IRQ, &hvc_udbg_ops, 16); + hp = hvc_alloc(0, 0, &hvc_udbg_ops, 16); if (IS_ERR(hp)) return PTR_ERR(hp); diff --git a/drivers/tty/hvc/hvc_xen.c b/drivers/tty/hvc/hvc_xen.c index 52fdf60..a1b0a75 100644 --- a/drivers/tty/hvc/hvc_xen.c +++ b/drivers/tty/hvc/hvc_xen.c @@ -176,7 +176,7 @@ static int __init xen_hvc_init(void) xencons_irq = bind_evtchn_to_irq(xen_start_info->console.domU.evtchn); } if (xencons_irq < 0) - xencons_irq = 0; /* NO_IRQ */ + xencons_irq = 0; else irq_set_noprobe(xencons_irq); diff --git a/drivers/tty/hvc/hvcs.c b/drivers/tty/hvc/hvcs.c index b9040be..df7e7a0 100644 --- a/drivers/tty/hvc/hvcs.c +++ b/drivers/tty/hvc/hvcs.c @@ -1203,7 +1203,7 @@ static void hvcs_close(struct tty_struct *tty, struct file *filp) { struct hvcs_struct *hvcsd; unsigned long flags; - int irq = NO_IRQ; + int irq; /* * Is someone trying to close the file associated with this device after @@ -1264,7 +1264,7 @@ static void hvcs_hangup(struct tty_struct * tty) struct hvcs_struct *hvcsd = tty->driver_data; unsigned long flags; int temp_open_count; - int irq = NO_IRQ; + int irq; spin_lock_irqsave(&hvcsd->lock, flags); /* Preserve this so that we know how many kref refs to put */ diff --git a/drivers/tty/hvc/hvsi.c b/drivers/tty/hvc/hvsi.c index cdfa3e0..1b5f28b 100644 --- a/drivers/tty/hvc/hvsi.c +++ b/drivers/tty/hvc/hvsi.c @@ -1237,7 +1237,7 @@ static int __init hvsi_console_init(void) hp->state = HVSI_CLOSED; hp->vtermno = *vtermno; hp->virq = irq_create_mapping(NULL, irq[0]); - if (hp->virq == NO_IRQ) { + if (hp->virq == 0) { printk(KERN_ERR "%s: couldn't create irq mapping for 0x%x\n", __func__, irq[0]); continue; diff --git a/drivers/tty/serial/21285.c b/drivers/tty/serial/21285.c index 1b37626..f899996 100644 --- a/drivers/tty/serial/21285.c +++ b/drivers/tty/serial/21285.c @@ -331,7 +331,7 @@ static int serial21285_verify_port(struct uart_port *port, struct serial_struct int ret = 0; if (ser->type != PORT_UNKNOWN && ser->type != PORT_21285) ret = -EINVAL; - if (ser->irq != NO_IRQ) + if (ser->irq <= 0) ret = -EINVAL; if (ser->baud_base != port->uartclk / 16) ret = -EINVAL; @@ -360,7 +360,7 @@ static struct uart_ops serial21285_ops = { static struct uart_port serial21285_port = { .mapbase = 0x42000160, .iotype = UPIO_MEM, - .irq = NO_IRQ, + .irq = 0, .fifosize = 16, .ops = &serial21285_ops, .flags = UPF_BOOT_AUTOCONF, diff --git a/drivers/tty/serial/8250.c b/drivers/tty/serial/8250.c index 9f50c4e..b0eb961 100644 --- a/drivers/tty/serial/8250.c +++ b/drivers/tty/serial/8250.c @@ -86,13 +86,6 @@ static unsigned int skip_txen_test; /* force skip of txen test at init time */ #define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE) -/* - * We default to IRQ0 for the "no irq" hack. Some - * machine types want others as well - they're free - * to redefine this in their header file. - */ -#define is_real_interrupt(irq) ((irq) != 0) - #ifdef CONFIG_SERIAL_8250_DETECT_IRQ #define CONFIG_SERIAL_DETECT_IRQ 1 #endif @@ -1750,7 +1743,7 @@ static void serial8250_backup_timeout(unsigned long data) * Must disable interrupts or else we risk racing with the interrupt * based handler. */ - if (is_real_interrupt(up->port.irq)) { + if (up->port.irq) { ier = serial_in(up, UART_IER); serial_out(up, UART_IER, 0); } @@ -1775,7 +1768,7 @@ static void serial8250_backup_timeout(unsigned long data) if (!(iir & UART_IIR_NO_INT)) serial8250_tx_chars(up); - if (is_real_interrupt(up->port.irq)) + if (up->port.irq) serial_out(up, UART_IER, ier); spin_unlock_irqrestore(&up->port.lock, flags); @@ -2028,7 +2021,7 @@ static int serial8250_startup(struct uart_port *port) serial_outp(up, UART_LCR, 0); } - if (is_real_interrupt(up->port.irq)) { + if (up->port.irq) { unsigned char iir1; /* * Test for UARTs that do not reassert THRE when the @@ -2083,7 +2076,7 @@ static int serial8250_startup(struct uart_port *port) * hardware interrupt, we use a timer-based system. The original * driver used to do this with IRQ0. */ - if (!is_real_interrupt(up->port.irq)) { + if (!up->port.irq) { up->timer.data = (unsigned long)up; mod_timer(&up->timer, jiffies + uart_poll_timeout(port)); } else { @@ -2099,13 +2092,13 @@ static int serial8250_startup(struct uart_port *port) spin_lock_irqsave(&up->port.lock, flags); if (up->port.flags & UPF_FOURPORT) { - if (!is_real_interrupt(up->port.irq)) + if (!up->port.irq) up->port.mctrl |= TIOCM_OUT1; } else /* * Most PC uarts need OUT2 raised to enable interrupts. */ - if (is_real_interrupt(up->port.irq)) + if (up->port.irq) up->port.mctrl |= TIOCM_OUT2; serial8250_set_mctrl(&up->port, up->port.mctrl); @@ -2223,7 +2216,7 @@ static void serial8250_shutdown(struct uart_port *port) del_timer_sync(&up->timer); up->timer.function = serial8250_timeout; - if (is_real_interrupt(up->port.irq)) + if (up->port.irq) serial_unlink_irq_chain(up); } diff --git a/drivers/tty/serial/m32r_sio.c b/drivers/tty/serial/m32r_sio.c index 94a6792..e465dda 100644 --- a/drivers/tty/serial/m32r_sio.c +++ b/drivers/tty/serial/m32r_sio.c @@ -70,13 +70,6 @@ #define PASS_LIMIT 256 -/* - * We default to IRQ0 for the "no irq" hack. Some - * machine types want others as well - they're free - * to redefine this in their header file. - */ -#define is_real_interrupt(irq) ((irq) != 0) - #define BASE_BAUD 115200 /* Standard COM flags */ @@ -640,7 +633,7 @@ static int m32r_sio_startup(struct uart_port *port) * hardware interrupt, we use a timer-based system. The original * driver used to do this with IRQ0. */ - if (!is_real_interrupt(up->port.irq)) { + if (!up->port.irq) { unsigned int timeout = up->port.timeout; timeout = timeout > 6 ? (timeout / 2 - 2) : 1; @@ -687,7 +680,7 @@ static void m32r_sio_shutdown(struct uart_port *port) sio_init(); - if (!is_real_interrupt(up->port.irq)) + if (!up->port.irq) del_timer_sync(&up->timer); else serial_unlink_irq_chain(up); diff --git a/drivers/tty/serial/mpc52xx_uart.c b/drivers/tty/serial/mpc52xx_uart.c index 1093a88..e9a770d 100644 --- a/drivers/tty/serial/mpc52xx_uart.c +++ b/drivers/tty/serial/mpc52xx_uart.c @@ -507,7 +507,7 @@ static int __init mpc512x_psc_fifoc_init(void) psc_fifoc_irq = irq_of_parse_and_map(np, 0); of_node_put(np); - if (psc_fifoc_irq == NO_IRQ) { + if (psc_fifoc_irq == 0) { pr_err("%s: Can't get FIFOC irq\n", __func__); iounmap(psc_fifoc); return -ENODEV; @@ -1354,7 +1354,7 @@ static int __devinit mpc52xx_uart_of_probe(struct platform_device *op) } psc_ops->get_irq(port, op->dev.of_node); - if (port->irq == NO_IRQ) { + if (port->irq == 0) { dev_dbg(&op->dev, "Could not get irq\n"); return -EINVAL; } diff --git a/drivers/tty/serial/mux.c b/drivers/tty/serial/mux.c index 06f6aef..c61d950 100644 --- a/drivers/tty/serial/mux.c +++ b/drivers/tty/serial/mux.c @@ -499,7 +499,7 @@ static int __init mux_probe(struct parisc_device *dev) port->membase = ioremap_nocache(port->mapbase, MUX_LINE_OFFSET); port->iotype = UPIO_MEM; port->type = PORT_MUX; - port->irq = NO_IRQ; + port->irq = 0; port->uartclk = 0; port->fifosize = MUX_FIFO_SIZE; port->ops = &mux_pops; diff --git a/drivers/tty/serial/pmac_zilog.c b/drivers/tty/serial/pmac_zilog.c index e9c2dfe4..08ebe90 100644 --- a/drivers/tty/serial/pmac_zilog.c +++ b/drivers/tty/serial/pmac_zilog.c @@ -1506,7 +1506,7 @@ no_dma: * fixed up interrupt info, but we use the device-tree directly * here due to early probing so we need the fixup too. */ - if (uap->port.irq == NO_IRQ && + if (uap->port.irq == 0 && np->parent && np->parent->parent && of_device_is_compatible(np->parent->parent, "gatwick")) { /* IRQs on gatwick are offset by 64 */ diff --git a/drivers/tty/serial/sunzilog.c b/drivers/tty/serial/sunzilog.c index 8e916e7..5a47d1b 100644 --- a/drivers/tty/serial/sunzilog.c +++ b/drivers/tty/serial/sunzilog.c @@ -1397,7 +1397,7 @@ static void __devinit sunzilog_init_hw(struct uart_sunzilog_port *up) #endif } -static int zilog_irq = -1; +static int zilog_irq; static int __devinit zs_probe(struct platform_device *op) { @@ -1425,7 +1425,7 @@ static int __devinit zs_probe(struct platform_device *op) rp = sunzilog_chip_regs[inst]; - if (zilog_irq == -1) + if (!zilog_irq) zilog_irq = op->archdata.irqs[0]; up = &sunzilog_port_table[inst * 2]; @@ -1580,7 +1580,7 @@ static int __init sunzilog_init(void) if (err) goto out_unregister_uart; - if (zilog_irq != -1) { + if (!zilog_irq) { struct uart_sunzilog_port *up = sunzilog_irq_chain; err = request_irq(zilog_irq, sunzilog_interrupt, IRQF_SHARED, "zs", sunzilog_irq_chain); @@ -1621,7 +1621,7 @@ static void __exit sunzilog_exit(void) { platform_driver_unregister(&zs_driver); - if (zilog_irq != -1) { + if (!zilog_irq) { struct uart_sunzilog_port *up = sunzilog_irq_chain; /* Disable Interrupts */ @@ -1637,7 +1637,7 @@ static void __exit sunzilog_exit(void) } free_irq(zilog_irq, sunzilog_irq_chain); - zilog_irq = -1; + zilog_irq = 0; } if (sunzilog_reg.nr) { diff --git a/drivers/tty/serial/ucc_uart.c b/drivers/tty/serial/ucc_uart.c index 2ebe606..f99b0c9 100644 --- a/drivers/tty/serial/ucc_uart.c +++ b/drivers/tty/serial/ucc_uart.c @@ -1360,7 +1360,7 @@ static int ucc_uart_probe(struct platform_device *ofdev) } qe_port->port.irq = irq_of_parse_and_map(np, 0); - if (qe_port->port.irq == NO_IRQ) { + if (qe_port->port.irq == 0) { dev_err(&ofdev->dev, "could not map IRQ for UCC%u\n", qe_port->ucc_num + 1); ret = -EINVAL; diff --git a/drivers/tty/serial/vr41xx_siu.c b/drivers/tty/serial/vr41xx_siu.c index 83148e7..cf0d948 100644 --- a/drivers/tty/serial/vr41xx_siu.c +++ b/drivers/tty/serial/vr41xx_siu.c @@ -61,7 +61,7 @@ static struct uart_port siu_uart_ports[SIU_PORTS_MAX] = { [0 ... SIU_PORTS_MAX-1] = { .lock = __SPIN_LOCK_UNLOCKED(siu_uart_ports->lock), - .irq = -1, + .irq = 0, }, }; @@ -171,7 +171,7 @@ static inline unsigned int siu_check_type(struct uart_port *port) { if (port->line == 0) return PORT_VR41XX_SIU; - if (port->line == 1 && port->irq != -1) + if (port->line == 1 && port->irq) return PORT_VR41XX_DSIU; return PORT_UNKNOWN; -- cgit v0.10.2 From 5816269e4ee3db2bc2ad44afc89f4abe81c7aa26 Mon Sep 17 00:00:00 2001 From: Paul Walmsley Date: Wed, 25 Jan 2012 19:50:36 -0700 Subject: tty: serial: OMAP: use a 1-byte RX FIFO threshold in PIO mode In the (default) PIO mode, use a one-byte RX FIFO threshold. The OMAP UART IP blocks do not appear to be capable of waking the system under an RX timeout condition. Since the previous RX FIFO threshold was 16 bytes, this meant that omap-serial.c did not become aware of any received data until all those bytes arrived or until another UART interrupt occurred. This made the serial console and presumably other serial applications (GPS, serial Bluetooth) unusable or extremely slow. A 1-byte RX FIFO threshold also allows the MPU to enter a low-power consumption state while waiting for the FIFO to fill. This can be verified using the serial console by comparing the behavior when "0123456789abcde" is pasted in from another window, with the behavior when "0123456789abcdef" is pasted in. Since the former string is less than sixteen bytes long, the string is not echoed for some time, while the latter string is echoed immediately. DMA operation is unaffected by this patch. Thanks to Russell King - ARM Linux for some additional information on the standard behavior of the RX timeout event, which was used to improve this commit description. Signed-off-by: Paul Walmsley Cc: Tomi Valkeinen Cc: Govindraj Raja Cc: Alan Cox Cc: Russell King Reviewed-by: Kevin Hilman Tested-by: Kevin Hilman Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c index d192dcb..c9c9ba2 100644 --- a/drivers/tty/serial/omap-serial.c +++ b/drivers/tty/serial/omap-serial.c @@ -46,6 +46,13 @@ #define DEFAULT_CLK_SPEED 48000000 /* 48Mhz*/ +/* SCR register bitmasks */ +#define OMAP_UART_SCR_RX_TRIG_GRANU1_MASK (1 << 7) + +/* FCR register bitmasks */ +#define OMAP_UART_FCR_RX_FIFO_TRIG_SHIFT 6 +#define OMAP_UART_FCR_RX_FIFO_TRIG_MASK (0x3 << 6) + static struct uart_omap_port *ui[OMAP_MAX_HSUART_PORTS]; /* Forward declaration of functions */ @@ -811,14 +818,21 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios, up->mcr = serial_in(up, UART_MCR); serial_out(up, UART_MCR, up->mcr | UART_MCR_TCRTLR); /* FIFO ENABLE, DMA MODE */ - serial_out(up, UART_FCR, up->fcr); - serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); + + up->scr |= OMAP_UART_SCR_RX_TRIG_GRANU1_MASK; if (up->use_dma) { serial_out(up, UART_TI752_TLR, 0); - up->scr |= (UART_FCR_TRIGGER_4 | UART_FCR_TRIGGER_8); + up->scr |= UART_FCR_TRIGGER_4; + } else { + /* Set receive FIFO threshold to 1 byte */ + up->fcr &= ~OMAP_UART_FCR_RX_FIFO_TRIG_MASK; + up->fcr |= (0x1 << OMAP_UART_FCR_RX_FIFO_TRIG_SHIFT); } + serial_out(up, UART_FCR, up->fcr); + serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); + serial_out(up, UART_OMAP_SCR, up->scr); serial_out(up, UART_EFR, up->efr); -- cgit v0.10.2 From edbe5dbefe5b514d094558ab59c8dc7578e117dd Mon Sep 17 00:00:00 2001 From: Paul Walmsley Date: Wed, 25 Jan 2012 19:50:52 -0700 Subject: tty: serial: OMAP: block idle while the UART is transferring data in PIO mode Prevent OMAP UARTs from going idle while they are still transferring data in PIO mode. This works around an oversight in the OMAP UART hardware present in OMAP34xx and earlier: an idle UART won't send a wakeup when the TX FIFO threshold is reached. This causes long delays during data transmission when the MPU powerdomain enters a low-power mode. The MPU interrupt controller is not able to respond to interrupts when it's in a low-power state, so the TX buffer is not refilled until another wakeup event occurs. This fix changes the erratum i291 DMA idle workaround. Rather than toggling between force-idle and no-idle, it will toggle between smart-idle and no-idle. The important part of the workaround is the no-idle part, so this shouldn't result in any change in behavior. This fix should work on all OMAP UARTs. Future patches intended for the 3.4 merge window will make this workaround conditional on a "feature" flag, and will use the OMAP36xx+ TX event wakeup support. Thanks to Kevin Hilman for mentioning the erratum i291 workaround, which led to the development of this approach. Signed-off-by: Paul Walmsley Cc: Alan Cox Cc: Tomi Valkeinen Acked-by: Govindraj.R Reviewed-by: Kevin Hilman Tested-by: Kevin Hilman Signed-off-by: Greg Kroah-Hartman diff --git a/arch/arm/mach-omap2/serial.c b/arch/arm/mach-omap2/serial.c index 247d894..f590afc 100644 --- a/arch/arm/mach-omap2/serial.c +++ b/arch/arm/mach-omap2/serial.c @@ -107,18 +107,18 @@ static void omap_uart_set_noidle(struct platform_device *pdev) omap_hwmod_set_slave_idlemode(od->hwmods[0], HWMOD_IDLEMODE_NO); } -static void omap_uart_set_forceidle(struct platform_device *pdev) +static void omap_uart_set_smartidle(struct platform_device *pdev) { struct omap_device *od = to_omap_device(pdev); - omap_hwmod_set_slave_idlemode(od->hwmods[0], HWMOD_IDLEMODE_FORCE); + omap_hwmod_set_slave_idlemode(od->hwmods[0], HWMOD_IDLEMODE_SMART); } #else static void omap_uart_enable_wakeup(struct platform_device *pdev, bool enable) {} static void omap_uart_set_noidle(struct platform_device *pdev) {} -static void omap_uart_set_forceidle(struct platform_device *pdev) {} +static void omap_uart_set_smartidle(struct platform_device *pdev) {} #endif /* CONFIG_PM */ #ifdef CONFIG_OMAP_MUX @@ -349,7 +349,7 @@ void __init omap_serial_init_port(struct omap_board_data *bdata, omap_up.uartclk = OMAP24XX_BASE_BAUD * 16; omap_up.flags = UPF_BOOT_AUTOCONF; omap_up.get_context_loss_count = omap_pm_get_dev_context_loss_count; - omap_up.set_forceidle = omap_uart_set_forceidle; + omap_up.set_forceidle = omap_uart_set_smartidle; omap_up.set_noidle = omap_uart_set_noidle; omap_up.enable_wakeup = omap_uart_enable_wakeup; omap_up.dma_rx_buf_size = info->dma_rx_buf_size; diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c index c9c9ba2..11fa156 100644 --- a/drivers/tty/serial/omap-serial.c +++ b/drivers/tty/serial/omap-serial.c @@ -136,6 +136,7 @@ static void serial_omap_enable_ms(struct uart_port *port) static void serial_omap_stop_tx(struct uart_port *port) { struct uart_omap_port *up = (struct uart_omap_port *)port; + struct omap_uart_port_info *pdata = up->pdev->dev.platform_data; if (up->use_dma && up->uart_dma.tx_dma_channel != OMAP_UART_DMA_CH_FREE) { @@ -158,6 +159,9 @@ static void serial_omap_stop_tx(struct uart_port *port) serial_out(up, UART_IER, up->ier); } + if (!up->use_dma && pdata->set_forceidle) + pdata->set_forceidle(up->pdev); + pm_runtime_mark_last_busy(&up->pdev->dev); pm_runtime_put_autosuspend(&up->pdev->dev); } @@ -286,6 +290,7 @@ static inline void serial_omap_enable_ier_thri(struct uart_omap_port *up) static void serial_omap_start_tx(struct uart_port *port) { struct uart_omap_port *up = (struct uart_omap_port *)port; + struct omap_uart_port_info *pdata = up->pdev->dev.platform_data; struct circ_buf *xmit; unsigned int start; int ret = 0; @@ -293,6 +298,8 @@ static void serial_omap_start_tx(struct uart_port *port) if (!up->use_dma) { pm_runtime_get_sync(&up->pdev->dev); serial_omap_enable_ier_thri(up); + if (pdata->set_noidle) + pdata->set_noidle(up->pdev); pm_runtime_mark_last_busy(&up->pdev->dev); pm_runtime_put_autosuspend(&up->pdev->dev); return; -- cgit v0.10.2 From 6bbcbf22085e0b144899d6067e243dd26c0e7533 Mon Sep 17 00:00:00 2001 From: Paul Walmsley Date: Wed, 25 Jan 2012 19:50:56 -0700 Subject: tty: serial: omap-serial: wakeup latency constraint is in microseconds, not milliseconds The receive FIFO wakeup latency estimate in the omap-serial driver is three orders of magnitude too small. This effectively prevents the MPU from going to a low-power state when CONFIG_CPU_IDLE=y. This is a major power management regression and masks some other FIFO-related bugs in the driver. Fix by correcting the most egregious problem in the RX wakeup latency estimate. There are several other flaws in the estimator; these will be fixed by a separate patch series intended for 3.4. The difference in low-power states with this patch can be observed via debugfs in pm_debug/count. This estimate does not have any effect when CONFIG_CPU_IDLE=n. Signed-off-by: Paul Walmsley Cc: Tomi Valkeinen Cc: Alan Cox Acked-by: Govindraj.R Reviewed-by: Kevin Hilman Tested-by: Kevin Hilman Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c index 11fa156..72fa783 100644 --- a/drivers/tty/serial/omap-serial.c +++ b/drivers/tty/serial/omap-serial.c @@ -740,8 +740,7 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios, quot = serial_omap_get_divisor(port, baud); /* calculate wakeup latency constraint */ - up->calc_latency = (1000000 * up->port.fifosize) / - (1000 * baud / 8); + up->calc_latency = (USEC_PER_SEC * up->port.fifosize) / (baud / 8); up->latency = up->calc_latency; schedule_work(&up->qos_work); -- cgit v0.10.2 From 66d450e84ec656ec4b774c41cd8d46b3e48d51df Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 30 Jan 2012 21:14:28 +0100 Subject: TTY: provide tty_standard_install helper There are currently many cut&paste copies of what tty_driver_install_tty does when custom ->install method is not provided. Let's get rid of the copies and create a helper with this setup code. Signed-off-by: Jiri Slaby Cc: Havard Skinnemoen Acked-by: Alan Cox Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index fbcc140..44736f9 100644 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c @@ -1271,6 +1271,19 @@ int tty_init_termios(struct tty_struct *tty) } EXPORT_SYMBOL_GPL(tty_init_termios); +int tty_standard_install(struct tty_driver *driver, struct tty_struct *tty) +{ + int ret = tty_init_termios(tty); + if (ret) + return ret; + + tty_driver_kref_get(driver); + tty->count++; + driver->ttys[tty->index] = tty; + return 0; +} +EXPORT_SYMBOL_GPL(tty_standard_install); + /** * tty_driver_install_tty() - install a tty entry in the driver * @driver: the driver for the tty @@ -1286,21 +1299,8 @@ EXPORT_SYMBOL_GPL(tty_init_termios); static int tty_driver_install_tty(struct tty_driver *driver, struct tty_struct *tty) { - int idx = tty->index; - int ret; - - if (driver->ops->install) { - ret = driver->ops->install(driver, tty); - return ret; - } - - if (tty_init_termios(tty) == 0) { - tty_driver_kref_get(driver); - tty->count++; - driver->ttys[idx] = tty; - return 0; - } - return -ENOMEM; + return driver->ops->install ? driver->ops->install(driver, tty) : + tty_standard_install(driver, tty); } /** diff --git a/include/linux/tty.h b/include/linux/tty.h index d407741..a91ff40 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h @@ -484,6 +484,8 @@ extern void deinitialize_tty_struct(struct tty_struct *tty); extern struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx); extern int tty_release(struct inode *inode, struct file *filp); extern int tty_init_termios(struct tty_struct *tty); +extern int tty_standard_install(struct tty_driver *driver, + struct tty_struct *tty); extern struct tty_struct *tty_pair_get_tty(struct tty_struct *tty); extern struct tty_struct *tty_pair_get_pty(struct tty_struct *tty); -- cgit v0.10.2 From 76f82a7ab3a724791d184e74529e96ad6947a98f Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 30 Jan 2012 21:14:29 +0100 Subject: USB: serial, use tty_standard_install But before that we need to reorder the calls so that we don't need to lower the reference counts if usb_autopm_get_interface fails. Signed-off-by: Jiri Slaby Cc: Alan Cox Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index 611b206..1e30cc9 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c @@ -214,15 +214,14 @@ static int serial_install(struct tty_driver *driver, struct tty_struct *tty) if (!try_module_get(serial->type->driver.owner)) goto error_module_get; - /* perform the standard setup */ - retval = tty_init_termios(tty); - if (retval) - goto error_init_termios; - retval = usb_autopm_get_interface(serial->interface); if (retval) goto error_get_interface; + retval = tty_standard_install(driver, tty); + if (retval) + goto error_init_termios; + mutex_unlock(&serial->disc_mutex); /* allow the driver to update the settings */ @@ -231,14 +230,11 @@ static int serial_install(struct tty_driver *driver, struct tty_struct *tty) tty->driver_data = port; - /* Final install (we use the default method) */ - tty_driver_kref_get(driver); - tty->count++; - driver->ttys[idx] = tty; return retval; - error_get_interface: error_init_termios: + usb_autopm_put_interface(serial->interface); + error_get_interface: module_put(serial->type->driver.owner); error_module_get: error_no_port: -- cgit v0.10.2 From 81f5835eae424be646753ec5a044ed4db1fcc09a Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 30 Jan 2012 21:14:30 +0100 Subject: TTY: use tty_standard_install Use the helper in the rest of the tty drivers. This is a simple replacement. Signed-off-by: Jiri Slaby Acked-by: Alan Cox Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/isdn/capi/capi.c b/drivers/isdn/capi/capi.c index e44933d..94948be 100644 --- a/drivers/isdn/capi/capi.c +++ b/drivers/isdn/capi/capi.c @@ -1015,14 +1015,11 @@ capinc_tty_install(struct tty_driver *driver, struct tty_struct *tty) { int idx = tty->index; struct capiminor *mp = capiminor_get(idx); - int ret = tty_init_termios(tty); + int ret = tty_standard_install(driver, tty); - if (ret == 0) { - tty_driver_kref_get(driver); - tty->count++; + if (ret == 0) tty->driver_data = mp; - driver->ttys[idx] = tty; - } else + else capiminor_put(mp); return ret; } diff --git a/drivers/misc/pti.c b/drivers/misc/pti.c index 0b56e3f..471ff4c 100644 --- a/drivers/misc/pti.c +++ b/drivers/misc/pti.c @@ -481,13 +481,9 @@ static int pti_tty_install(struct tty_driver *driver, struct tty_struct *tty) { int idx = tty->index; struct pti_tty *pti_tty_data; - int ret = tty_init_termios(tty); + int ret = tty_standard_install(driver, tty); if (ret == 0) { - tty_driver_kref_get(driver); - tty->count++; - driver->ttys[idx] = tty; - pti_tty_data = kmalloc(sizeof(struct pti_tty), GFP_KERNEL); if (pti_tty_data == NULL) return -ENOMEM; diff --git a/drivers/mmc/card/sdio_uart.c b/drivers/mmc/card/sdio_uart.c index 2c151e1..bd4a67c 100644 --- a/drivers/mmc/card/sdio_uart.c +++ b/drivers/mmc/card/sdio_uart.c @@ -750,15 +750,12 @@ static int sdio_uart_install(struct tty_driver *driver, struct tty_struct *tty) { int idx = tty->index; struct sdio_uart_port *port = sdio_uart_port_get(idx); - int ret = tty_init_termios(tty); + int ret = tty_standard_install(driver, tty); - if (ret == 0) { - tty_driver_kref_get(driver); - tty->count++; + if (ret == 0) /* This is the ref sdio_uart_port get provided */ tty->driver_data = port; - driver->ttys[idx] = tty; - } else + else sdio_uart_port_put(port); return ret; } diff --git a/drivers/tty/nozomi.c b/drivers/tty/nozomi.c index fd347ff..580da78 100644 --- a/drivers/tty/nozomi.c +++ b/drivers/tty/nozomi.c @@ -1602,13 +1602,9 @@ static int ntty_install(struct tty_driver *driver, struct tty_struct *tty) int ret; if (!port || !dc || dc->state != NOZOMI_STATE_READY) return -ENODEV; - ret = tty_init_termios(tty); - if (ret == 0) { - tty_driver_kref_get(driver); - tty->count++; + ret = tty_standard_install(driver, tty); + if (ret == 0) tty->driver_data = port; - driver->ttys[tty->index] = tty; - } return ret; } -- cgit v0.10.2 From a50f724a432997321cabb6c9e665c28e34850f78 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 30 Jan 2012 21:14:31 +0100 Subject: TTY: pty, remove superfluous ptm test The code looks like: if (tty->driver->subtype == PTY_TYPE_MASTER) { ... if (tty->driver == ptm_driver) But the second if is superfluous because only the ptm_driver is of PTY_TYPE_MASTER subtype. Also we can remove the #if now because devpts_pty_kill is defined as an empty function for non-CONFIG_UNIX98_PTYS configs. Signed-off-by: Jiri Slaby Acked-by: Alan Cox Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/pty.c b/drivers/tty/pty.c index d505837..ddec9f3 100644 --- a/drivers/tty/pty.c +++ b/drivers/tty/pty.c @@ -54,10 +54,7 @@ static void pty_close(struct tty_struct *tty, struct file *filp) wake_up_interruptible(&tty->link->write_wait); if (tty->driver->subtype == PTY_TYPE_MASTER) { set_bit(TTY_OTHER_CLOSED, &tty->flags); -#ifdef CONFIG_UNIX98_PTYS - if (tty->driver == ptm_driver) - devpts_pty_kill(tty->link); -#endif + devpts_pty_kill(tty->link); tty_unlock(); tty_vhangup(tty->link); tty_lock(); -- cgit v0.10.2 From d3bda5298aad98c7a27678bdd0dd9d008ab9e685 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 30 Jan 2012 21:14:32 +0100 Subject: TTY: get rid of BTM around devpts_* devpts operations are protected by inode mutexes and dentry refcounting. There is no need to hold BTM. Signed-off-by: Jiri Slaby Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/pty.c b/drivers/tty/pty.c index ddec9f3..39afd04 100644 --- a/drivers/tty/pty.c +++ b/drivers/tty/pty.c @@ -54,8 +54,8 @@ static void pty_close(struct tty_struct *tty, struct file *filp) wake_up_interruptible(&tty->link->write_wait); if (tty->driver->subtype == PTY_TYPE_MASTER) { set_bit(TTY_OTHER_CLOSED, &tty->flags); - devpts_pty_kill(tty->link); tty_unlock(); + devpts_pty_kill(tty->link); tty_vhangup(tty->link); tty_lock(); } @@ -613,9 +613,7 @@ static int ptmx_open(struct inode *inode, struct file *filp) return retval; /* find a device that is not in use. */ - tty_lock(); index = devpts_new_index(inode); - tty_unlock(); if (index < 0) { retval = index; goto err_file; @@ -650,8 +648,8 @@ err_release: tty_release(inode, filp); return retval; out: - devpts_kill_index(inode, index); tty_unlock(); + devpts_kill_index(inode, index); err_file: tty_free_file(filp); return retval; diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index 44736f9..ea7ebe2 100644 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c @@ -1789,11 +1789,11 @@ int tty_release(struct inode *inode, struct file *filp) * the slots and preserving the termios structure. */ release_tty(tty, idx); + tty_unlock(); /* Make this pty number available for reallocation */ if (devpts) devpts_kill_index(inode, idx); - tty_unlock(); return 0; } -- cgit v0.10.2 From d011411ddb294e90511211a9edfc79da1c0465dc Mon Sep 17 00:00:00 2001 From: Feng Tang Date: Mon, 6 Feb 2012 17:24:43 +0800 Subject: serial: pch_uart: add debugfs hook for register dump This driver will be use as interfaces for multiple kinds of devices like Bluetooth/GPS etc, this debug hook will make driver debugging much easier. Signed-off-by: Feng Tang Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/pch_uart.c b/drivers/tty/serial/pch_uart.c index 17ae657..6d9ca293 100644 --- a/drivers/tty/serial/pch_uart.c +++ b/drivers/tty/serial/pch_uart.c @@ -29,6 +29,7 @@ #include #include +#include #include #include @@ -144,6 +145,8 @@ enum { #define PCH_UART_DLL 0x00 #define PCH_UART_DLM 0x01 +#define PCH_UART_BRCSR 0x0E + #define PCH_UART_IID_RLS (PCH_UART_IIR_REI) #define PCH_UART_IID_RDR (PCH_UART_IIR_RRI) #define PCH_UART_IID_RDR_TO (PCH_UART_IIR_RRI | PCH_UART_IIR_TOI) @@ -243,6 +246,8 @@ struct eg20t_port { int tx_dma_use; void *rx_buf_virt; dma_addr_t rx_buf_dma; + + struct dentry *debugfs; }; /** @@ -292,6 +297,73 @@ static const int trigger_level_64[4] = { 1, 16, 32, 56 }; static const int trigger_level_16[4] = { 1, 4, 8, 14 }; static const int trigger_level_1[4] = { 1, 1, 1, 1 }; +#ifdef CONFIG_DEBUG_FS + +#define PCH_REGS_BUFSIZE 1024 +static int pch_show_regs_open(struct inode *inode, struct file *file) +{ + file->private_data = inode->i_private; + return 0; +} + +static ssize_t port_show_regs(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct eg20t_port *priv = file->private_data; + char *buf; + u32 len = 0; + ssize_t ret; + unsigned char lcr; + + buf = kzalloc(PCH_REGS_BUFSIZE, GFP_KERNEL); + if (!buf) + return 0; + + len += snprintf(buf + len, PCH_REGS_BUFSIZE - len, + "PCH EG20T port[%d] regs:\n", priv->port.line); + + len += snprintf(buf + len, PCH_REGS_BUFSIZE - len, + "=================================\n"); + len += snprintf(buf + len, PCH_REGS_BUFSIZE - len, + "IER: \t0x%02x\n", ioread8(priv->membase + UART_IER)); + len += snprintf(buf + len, PCH_REGS_BUFSIZE - len, + "IIR: \t0x%02x\n", ioread8(priv->membase + UART_IIR)); + len += snprintf(buf + len, PCH_REGS_BUFSIZE - len, + "LCR: \t0x%02x\n", ioread8(priv->membase + UART_LCR)); + len += snprintf(buf + len, PCH_REGS_BUFSIZE - len, + "MCR: \t0x%02x\n", ioread8(priv->membase + UART_MCR)); + len += snprintf(buf + len, PCH_REGS_BUFSIZE - len, + "LSR: \t0x%02x\n", ioread8(priv->membase + UART_LSR)); + len += snprintf(buf + len, PCH_REGS_BUFSIZE - len, + "MSR: \t0x%02x\n", ioread8(priv->membase + UART_MSR)); + len += snprintf(buf + len, PCH_REGS_BUFSIZE - len, + "BRCSR: \t0x%02x\n", + ioread8(priv->membase + PCH_UART_BRCSR)); + + lcr = ioread8(priv->membase + UART_LCR); + iowrite8(PCH_UART_LCR_DLAB, priv->membase + UART_LCR); + len += snprintf(buf + len, PCH_REGS_BUFSIZE - len, + "DLL: \t0x%02x\n", ioread8(priv->membase + UART_DLL)); + len += snprintf(buf + len, PCH_REGS_BUFSIZE - len, + "DLM: \t0x%02x\n", ioread8(priv->membase + UART_DLM)); + iowrite8(lcr, priv->membase + UART_LCR); + + if (len > PCH_REGS_BUFSIZE) + len = PCH_REGS_BUFSIZE; + + ret = simple_read_from_buffer(user_buf, count, ppos, buf, len); + kfree(buf); + return ret; +} + +static const struct file_operations port_regs_ops = { + .owner = THIS_MODULE, + .open = pch_show_regs_open, + .read = port_show_regs, + .llseek = default_llseek, +}; +#endif /* CONFIG_DEBUG_FS */ + static void pch_uart_hal_request(struct pci_dev *pdev, int fifosize, int base_baud) { @@ -1554,6 +1626,7 @@ static struct eg20t_port *pch_uart_init_port(struct pci_dev *pdev, int port_type; struct pch_uart_driver_data *board; const char *board_name; + char name[32]; /* for debugfs file name */ board = &drv_dat[id->driver_data]; port_type = board->port_type; @@ -1623,6 +1696,12 @@ static struct eg20t_port *pch_uart_init_port(struct pci_dev *pdev, if (ret < 0) goto init_port_hal_free; +#ifdef CONFIG_DEBUG_FS + snprintf(name, sizeof(name), "uart%d_regs", board->line_no); + priv->debugfs = debugfs_create_file(name, S_IFREG | S_IRUGO, + NULL, priv, &port_regs_ops); +#endif + return priv; init_port_hal_free: @@ -1639,6 +1718,11 @@ init_port_alloc_err: static void pch_uart_exit_port(struct eg20t_port *priv) { + +#ifdef CONFIG_DEBUG_FS + if (priv->debugfs) + debugfs_remove(priv->debugfs); +#endif uart_remove_one_port(&pch_uart_driver, &priv->port); pci_set_drvdata(priv->pdev, NULL); free_page((unsigned long)priv->rxbuf.buf); -- cgit v0.10.2 From 30c6c6b5bf82d4f4a23235a0aa0657681d1c21f2 Mon Sep 17 00:00:00 2001 From: Feng Tang Date: Mon, 6 Feb 2012 17:24:44 +0800 Subject: serial: pch_uart: trivial cleanup by removing the get_msr() The short get_msr() has some unnecessary code and only used once, so merge it with its caller to make code cleaner. No functional change at all. Signed-off-by: Feng Tang Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/pch_uart.c b/drivers/tty/serial/pch_uart.c index 6d9ca293..811edcb 100644 --- a/drivers/tty/serial/pch_uart.c +++ b/drivers/tty/serial/pch_uart.c @@ -373,14 +373,6 @@ static void pch_uart_hal_request(struct pci_dev *pdev, int fifosize, priv->fcr = 0; } -static unsigned int get_msr(struct eg20t_port *priv, void __iomem *base) -{ - unsigned int msr = ioread8(base + UART_MSR); - priv->dmsr |= msr & PCH_UART_MSR_DELTA; - - return msr; -} - static void pch_uart_hal_enable_interrupt(struct eg20t_port *priv, unsigned int flag) { @@ -514,8 +506,9 @@ static int pch_uart_hal_set_fifo(struct eg20t_port *priv, static u8 pch_uart_hal_get_modem(struct eg20t_port *priv) { - priv->dmsr = 0; - return get_msr(priv, priv->membase); + unsigned int msr = ioread8(priv->membase + UART_MSR); + priv->dmsr = msr & PCH_UART_MSR_DELTA; + return (u8)msr; } static void pch_uart_hal_write(struct eg20t_port *priv, @@ -596,7 +589,7 @@ static int push_rx(struct eg20t_port *priv, const unsigned char *buf, static int pop_tx_x(struct eg20t_port *priv, unsigned char *buf) { - int ret; + int ret = 0; struct uart_port *port = &priv->port; if (port->x_char) { @@ -605,8 +598,6 @@ static int pop_tx_x(struct eg20t_port *priv, unsigned char *buf) buf[0] = port->x_char; port->x_char = 0; ret = 1; - } else { - ret = 0; } return ret; @@ -1104,14 +1095,12 @@ static irqreturn_t pch_uart_interrupt(int irq, void *dev_id) static unsigned int pch_uart_tx_empty(struct uart_port *port) { struct eg20t_port *priv; - int ret; + priv = container_of(port, struct eg20t_port, port); if (priv->tx_empty) - ret = TIOCSER_TEMT; + return TIOCSER_TEMT; else - ret = 0; - - return ret; + return 0; } /* Returns the current state of modem control inputs. */ @@ -1345,9 +1334,8 @@ static void pch_uart_set_termios(struct uart_port *port, else parity = PCH_UART_HAL_PARITY_EVEN; - } else { + } else parity = PCH_UART_HAL_PARITY_NONE; - } /* Only UART0 has auto hardware flow function */ if ((termios->c_cflag & CRTSCTS) && (priv->fifo_size == 256)) @@ -1519,7 +1507,6 @@ static void pch_console_write(struct console *co, const char *s, unsigned int count) { struct eg20t_port *priv; - unsigned long flags; u8 ier; int locked = 1; -- cgit v0.10.2 From 6f56d0f43656deb98c6366a133a75b5a7cf73a26 Mon Sep 17 00:00:00 2001 From: Feng Tang Date: Mon, 6 Feb 2012 17:24:45 +0800 Subject: serial: pch_uart: trivail cleanup by removing the pch_uart_hal_request() pch_uart_hal_request() has parameters which it never uses, also it is very short, so merge it with its caller to make code cleaner. No functional changes at all. Signed-off-by: Feng Tang Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/pch_uart.c b/drivers/tty/serial/pch_uart.c index 811edcb..aa4d07b 100644 --- a/drivers/tty/serial/pch_uart.c +++ b/drivers/tty/serial/pch_uart.c @@ -364,15 +364,6 @@ static const struct file_operations port_regs_ops = { }; #endif /* CONFIG_DEBUG_FS */ -static void pch_uart_hal_request(struct pci_dev *pdev, int fifosize, - int base_baud) -{ - struct eg20t_port *priv = pci_get_drvdata(pdev); - - priv->trigger_level = 1; - priv->fcr = 0; -} - static void pch_uart_hal_enable_interrupt(struct eg20t_port *priv, unsigned int flag) { @@ -1674,7 +1665,8 @@ static struct eg20t_port *pch_uart_init_port(struct pci_dev *pdev, spin_lock_init(&priv->port.lock); pci_set_drvdata(pdev, priv); - pch_uart_hal_request(pdev, fifosize, base_baud); + priv->trigger_level = 1; + priv->fcr = 0; #ifdef CONFIG_SERIAL_PCH_UART_CONSOLE pch_uart_ports[board->line_no] = priv; @@ -1717,9 +1709,7 @@ static void pch_uart_exit_port(struct eg20t_port *priv) static void pch_uart_pci_remove(struct pci_dev *pdev) { - struct eg20t_port *priv; - - priv = (struct eg20t_port *)pci_get_drvdata(pdev); + struct eg20t_port *priv = pci_get_drvdata(pdev); pci_disable_msi(pdev); -- cgit v0.10.2 From e502babe0a85226f2417b60a8710cf8192879180 Mon Sep 17 00:00:00 2001 From: Anton Vorontsov Date: Tue, 7 Feb 2012 10:49:39 +0400 Subject: sysrq: Fix possible race with exiting task sysrq should grab the tasklist lock, otherwise calling force_sig() is not safe, as it might race with exiting task, which ->sighand might be set to NULL already. Signed-off-by: Anton Vorontsov Acked-by: David Rientjes Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/sysrq.c b/drivers/tty/sysrq.c index 7867b7c..a1bcad7 100644 --- a/drivers/tty/sysrq.c +++ b/drivers/tty/sysrq.c @@ -322,11 +322,13 @@ static void send_sig_all(int sig) { struct task_struct *p; + read_lock(&tasklist_lock); for_each_process(p) { if (p->mm && !is_global_init(p)) /* Not swapper, init nor kernel thread */ force_sig(sig, p); } + read_unlock(&tasklist_lock); } static void sysrq_handle_term(int key) -- cgit v0.10.2 From d3a532a9c617106a0169232d40164ee35d0440b5 Mon Sep 17 00:00:00 2001 From: Anton Vorontsov Date: Tue, 7 Feb 2012 10:49:51 +0400 Subject: sysrq: Properly check for kernel threads There's a real possibility of killing kernel threads that might have issued use_mm(), so kthread's mm might become non-NULL. This patch fixes the issue by checking for PF_KTHREAD (just as get_task_mm()). Suggested-by: Oleg Nesterov Signed-off-by: Anton Vorontsov Acked-by: David Rientjes Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/sysrq.c b/drivers/tty/sysrq.c index a1bcad7..8db9125 100644 --- a/drivers/tty/sysrq.c +++ b/drivers/tty/sysrq.c @@ -324,9 +324,12 @@ static void send_sig_all(int sig) read_lock(&tasklist_lock); for_each_process(p) { - if (p->mm && !is_global_init(p)) - /* Not swapper, init nor kernel thread */ - force_sig(sig, p); + if (p->flags & PF_KTHREAD) + continue; + if (is_global_init(p)) + continue; + + force_sig(sig, p); } read_unlock(&tasklist_lock); } -- cgit v0.10.2 From 3f5dc70721af68b76ad544b0c61fea365d67c041 Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Wed, 8 Feb 2012 14:35:46 +0100 Subject: tty: serial: altera_uart: remove early_altera_uart_setup The function has no users inside the tree and the nios2 (out-of-mainline) port doesn't use it either (anymore). Signed-off-by: Tobias Klauser Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/altera_uart.c b/drivers/tty/serial/altera_uart.c index 1d04c50..217833e 100644 --- a/drivers/tty/serial/altera_uart.c +++ b/drivers/tty/serial/altera_uart.c @@ -403,29 +403,6 @@ static struct altera_uart altera_uart_ports[CONFIG_SERIAL_ALTERA_UART_MAXPORTS]; #if defined(CONFIG_SERIAL_ALTERA_UART_CONSOLE) -int __init early_altera_uart_setup(struct altera_uart_platform_uart *platp) -{ - struct uart_port *port; - int i; - - for (i = 0; i < CONFIG_SERIAL_ALTERA_UART_MAXPORTS && platp[i].mapbase; i++) { - port = &altera_uart_ports[i].port; - - port->line = i; - port->type = PORT_ALTERA_UART; - port->mapbase = platp[i].mapbase; - port->membase = ioremap(port->mapbase, ALTERA_UART_SIZE); - port->iotype = SERIAL_IO_MEM; - port->irq = platp[i].irq; - port->uartclk = platp[i].uartclk; - port->flags = UPF_BOOT_AUTOCONF; - port->ops = &altera_uart_ops; - port->private_data = platp; - } - - return 0; -} - static void altera_uart_console_putc(struct uart_port *port, const char c) { while (!(altera_uart_readl(port, ALTERA_UART_STATUS_REG) & diff --git a/include/linux/altera_uart.h b/include/linux/altera_uart.h index a10a907..c022c82 100644 --- a/include/linux/altera_uart.h +++ b/include/linux/altera_uart.h @@ -5,8 +5,6 @@ #ifndef __ALTUART_H #define __ALTUART_H -#include - struct altera_uart_platform_uart { unsigned long mapbase; /* Physical address base */ unsigned int irq; /* Interrupt vector */ @@ -14,6 +12,4 @@ struct altera_uart_platform_uart { unsigned int bus_shift; /* Bus shift (address stride) */ }; -int __init early_altera_uart_setup(struct altera_uart_platform_uart *platp); - #endif /* __ALTUART_H */ -- cgit v0.10.2 From 418a936e84e8f346da322c2e839992aa9df108d4 Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Wed, 8 Feb 2012 14:36:09 +0100 Subject: tty: serial: altera_uart: Add CONSOLE_POLL support This allows altera_uart to be used for KGDB debugging over serial line. Signed-off-by: Tobias Klauser Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile index 1997ad4..50d2790 100644 --- a/drivers/tty/serial/Makefile +++ b/drivers/tty/serial/Makefile @@ -75,12 +75,12 @@ obj-$(CONFIG_SERIAL_OF_PLATFORM) += of_serial.o obj-$(CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL) += nwpserial.o obj-$(CONFIG_SERIAL_KS8695) += serial_ks8695.o obj-$(CONFIG_SERIAL_OMAP) += omap-serial.o +obj-$(CONFIG_SERIAL_ALTERA_UART) += altera_uart.o obj-$(CONFIG_KGDB_SERIAL_CONSOLE) += kgdboc.o obj-$(CONFIG_SERIAL_QE) += ucc_uart.o obj-$(CONFIG_SERIAL_TIMBERDALE) += timbuart.o obj-$(CONFIG_SERIAL_GRLIB_GAISLER_APBUART) += apbuart.o obj-$(CONFIG_SERIAL_ALTERA_JTAGUART) += altera_jtaguart.o -obj-$(CONFIG_SERIAL_ALTERA_UART) += altera_uart.o obj-$(CONFIG_SERIAL_VT8500) += vt8500_serial.o obj-$(CONFIG_SERIAL_MRST_MAX3110) += mrst_max3110.o obj-$(CONFIG_SERIAL_MFD_HSU) += mfd.o diff --git a/drivers/tty/serial/altera_uart.c b/drivers/tty/serial/altera_uart.c index 217833e..e790375 100644 --- a/drivers/tty/serial/altera_uart.c +++ b/drivers/tty/serial/altera_uart.c @@ -377,6 +377,26 @@ static int altera_uart_verify_port(struct uart_port *port, return 0; } +#ifdef CONFIG_CONSOLE_POLL +static int altera_uart_poll_get_char(struct uart_port *port) +{ + while (!(altera_uart_readl(port, ALTERA_UART_STATUS_REG) & + ALTERA_UART_STATUS_RRDY_MSK)) + cpu_relax(); + + return altera_uart_readl(port, ALTERA_UART_RXDATA_REG); +} + +static void altera_uart_poll_put_char(struct uart_port *port, unsigned char c) +{ + while (!(altera_uart_readl(port, ALTERA_UART_STATUS_REG) & + ALTERA_UART_STATUS_TRDY_MSK)) + cpu_relax(); + + altera_uart_writel(port, c, ALTERA_UART_TXDATA_REG); +} +#endif + /* * Define the basic serial functions we support. */ @@ -397,6 +417,10 @@ static struct uart_ops altera_uart_ops = { .release_port = altera_uart_release_port, .config_port = altera_uart_config_port, .verify_port = altera_uart_verify_port, +#ifdef CONFIG_CONSOLE_POLL + .poll_get_char = altera_uart_poll_get_char, + .poll_put_char = altera_uart_poll_put_char, +#endif }; static struct altera_uart altera_uart_ports[CONFIG_SERIAL_ALTERA_UART_MAXPORTS]; -- cgit v0.10.2 From 6816383a09b5be8d35f14f4c25dedb64498e4959 Mon Sep 17 00:00:00 2001 From: Paul Gortmaker Date: Thu, 9 Feb 2012 18:48:19 -0500 Subject: tty: sparc: rename drivers/tty/serial/suncore.h -> include/linux/sunserialcore.h There are multiple users of this file from different source paths now, and rather than have ../ paths in include statements, just move the file to the linux header dir. Suggested-by: David S. Miller Signed-off-by: Paul Gortmaker Acked-by: David S. Miller Signed-off-by: Greg Kroah-Hartman diff --git a/MAINTAINERS b/MAINTAINERS index 9a648eb..27c052c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -6187,8 +6187,8 @@ L: sparclinux@vger.kernel.org T: git git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc-2.6.git T: git git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc-next-2.6.git S: Maintained +F: include/linux/sunserialcore.h F: drivers/tty/serial/suncore.c -F: drivers/tty/serial/suncore.h F: drivers/tty/serial/sunhv.c F: drivers/tty/serial/sunsab.c F: drivers/tty/serial/sunsab.h diff --git a/drivers/tty/serial/8250/8250.c b/drivers/tty/serial/8250/8250.c index b423d0f..917ab84 100644 --- a/drivers/tty/serial/8250/8250.c +++ b/drivers/tty/serial/8250/8250.c @@ -38,16 +38,15 @@ #include #include #include +#ifdef CONFIG_SPARC +#include +#endif #include #include #include "8250.h" -#ifdef CONFIG_SPARC -#include "../suncore.h" -#endif - /* * Configuration: * share_irqs - whether we pass IRQF_SHARED to request_irq(). This option diff --git a/drivers/tty/serial/suncore.c b/drivers/tty/serial/suncore.c index 6381a02..6e4ac8d 100644 --- a/drivers/tty/serial/suncore.c +++ b/drivers/tty/serial/suncore.c @@ -17,11 +17,11 @@ #include #include #include +#include #include #include -#include "suncore.h" static int sunserial_current_minor = 64; diff --git a/drivers/tty/serial/suncore.h b/drivers/tty/serial/suncore.h deleted file mode 100644 index db20579..0000000 --- a/drivers/tty/serial/suncore.h +++ /dev/null @@ -1,33 +0,0 @@ -/* suncore.h - * - * Generic SUN serial/kbd/ms layer. Based entirely - * upon drivers/sbus/char/sunserial.h which is: - * - * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) - * - * Port to new UART layer is: - * - * Copyright (C) 2002 David S. Miller (davem@redhat.com) - */ - -#ifndef _SERIAL_SUN_H -#define _SERIAL_SUN_H - -/* Serial keyboard defines for L1-A processing... */ -#define SUNKBD_RESET 0xff -#define SUNKBD_L1 0x01 -#define SUNKBD_UP 0x80 -#define SUNKBD_A 0x4d - -extern unsigned int suncore_mouse_baud_cflag_next(unsigned int, int *); -extern int suncore_mouse_baud_detection(unsigned char, int); - -extern int sunserial_register_minors(struct uart_driver *, int); -extern void sunserial_unregister_minors(struct uart_driver *, int); - -extern int sunserial_console_match(struct console *, struct device_node *, - struct uart_driver *, int, bool); -extern void sunserial_console_termios(struct console *, - struct device_node *); - -#endif /* !(_SERIAL_SUN_H) */ diff --git a/drivers/tty/serial/sunhv.c b/drivers/tty/serial/sunhv.c index c0b7246..3ba5d28 100644 --- a/drivers/tty/serial/sunhv.c +++ b/drivers/tty/serial/sunhv.c @@ -29,8 +29,7 @@ #endif #include - -#include "suncore.h" +#include #define CON_BREAK ((long)-1) #define CON_HUP ((long)-2) diff --git a/drivers/tty/serial/sunsab.c b/drivers/tty/serial/sunsab.c index b5fa2a5..62dacd0 100644 --- a/drivers/tty/serial/sunsab.c +++ b/drivers/tty/serial/sunsab.c @@ -43,8 +43,8 @@ #endif #include +#include -#include "suncore.h" #include "sunsab.h" struct uart_sunsab_port { diff --git a/drivers/tty/serial/sunsu.c b/drivers/tty/serial/sunsu.c index ad0f8f5..d3ca6da 100644 --- a/drivers/tty/serial/sunsu.c +++ b/drivers/tty/serial/sunsu.c @@ -47,8 +47,7 @@ #endif #include - -#include "suncore.h" +#include /* We are on a NS PC87303 clocked with 24.0 MHz, which results * in a UART clock of 1.8462 MHz. diff --git a/drivers/tty/serial/sunzilog.c b/drivers/tty/serial/sunzilog.c index 5a47d1b..da44158 100644 --- a/drivers/tty/serial/sunzilog.c +++ b/drivers/tty/serial/sunzilog.c @@ -43,8 +43,8 @@ #endif #include +#include -#include "suncore.h" #include "sunzilog.h" /* On 32-bit sparcs we need to delay after register accesses diff --git a/include/linux/sunserialcore.h b/include/linux/sunserialcore.h new file mode 100644 index 0000000..68e7430 --- /dev/null +++ b/include/linux/sunserialcore.h @@ -0,0 +1,33 @@ +/* sunserialcore.h + * + * Generic SUN serial/kbd/ms layer. Based entirely + * upon drivers/sbus/char/sunserial.h which is: + * + * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) + * + * Port to new UART layer is: + * + * Copyright (C) 2002 David S. Miller (davem@redhat.com) + */ + +#ifndef _SERIAL_SUN_H +#define _SERIAL_SUN_H + +/* Serial keyboard defines for L1-A processing... */ +#define SUNKBD_RESET 0xff +#define SUNKBD_L1 0x01 +#define SUNKBD_UP 0x80 +#define SUNKBD_A 0x4d + +extern unsigned int suncore_mouse_baud_cflag_next(unsigned int, int *); +extern int suncore_mouse_baud_detection(unsigned char, int); + +extern int sunserial_register_minors(struct uart_driver *, int); +extern void sunserial_unregister_minors(struct uart_driver *, int); + +extern int sunserial_console_match(struct console *, struct device_node *, + struct uart_driver *, int, bool); +extern void sunserial_console_termios(struct console *, + struct device_node *); + +#endif /* !(_SERIAL_SUN_H) */ -- cgit v0.10.2 From b7974deddc57307ddc9193d81e76ff818862d4e9 Mon Sep 17 00:00:00 2001 From: Danny Kukawka Date: Wed, 15 Feb 2012 18:55:41 +0100 Subject: tty/serial/mux.c: linux/tty.h included twice drivers/tty/serial/mux.c included 'linux/tty.h' twice, remove the duplicate. Signed-off-by: Danny Kukawka Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/mux.c b/drivers/tty/serial/mux.c index c61d950..7ea8a26 100644 --- a/drivers/tty/serial/mux.c +++ b/drivers/tty/serial/mux.c @@ -17,7 +17,6 @@ */ #include -#include #include #include #include -- cgit v0.10.2 From 90af6d208263d0f3541eee0525f093c248d88a42 Mon Sep 17 00:00:00 2001 From: Masanari Iida Date: Sat, 18 Feb 2012 19:49:47 +0900 Subject: serial: Fix typo in sn_console.c Correct spelling "receieve" to "receive" in drivers/tty/serial/sn_console.c Signed-off-by: Masanari Iida Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/sn_console.c b/drivers/tty/serial/sn_console.c index 238c7df..4e1b551 100644 --- a/drivers/tty/serial/sn_console.c +++ b/drivers/tty/serial/sn_console.c @@ -461,12 +461,12 @@ sn_receive_chars(struct sn_cons_port *port, unsigned long flags) struct tty_struct *tty; if (!port) { - printk(KERN_ERR "sn_receive_chars - port NULL so can't receieve\n"); + printk(KERN_ERR "sn_receive_chars - port NULL so can't receive\n"); return; } if (!port->sc_ops) { - printk(KERN_ERR "sn_receive_chars - port->sc_ops NULL so can't receieve\n"); + printk(KERN_ERR "sn_receive_chars - port->sc_ops NULL so can't receive\n"); return; } -- cgit v0.10.2 From 2ae73520940a8d5fe147c4c5de760be8824bfe17 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Mon, 20 Feb 2012 07:22:38 +1100 Subject: tty/powerpc: early udbg consoles can't be modules Fixes these build errors: ERROR: ".udbg_printf" [drivers/tty/ehv_bytechan.ko] undefined! ERROR: ".register_early_udbg_console" [drivers/tty/ehv_bytechan.ko] undefined! ERROR: "udbg_putc" [drivers/tty/ehv_bytechan.ko] undefined! Cc: Timur Tabi Signed-off-by: Stephen Rothwell Cc: stable Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/Kconfig b/drivers/tty/Kconfig index b3d1741..830cd62 100644 --- a/drivers/tty/Kconfig +++ b/drivers/tty/Kconfig @@ -365,7 +365,7 @@ config PPC_EPAPR_HV_BYTECHAN config PPC_EARLY_DEBUG_EHV_BC bool "Early console (udbg) support for ePAPR hypervisors" - depends on PPC_EPAPR_HV_BYTECHAN + depends on PPC_EPAPR_HV_BYTECHAN=y help Select this option to enable early console (a.k.a. "udbg") support via an ePAPR byte channel. You also need to choose the byte channel -- cgit v0.10.2 From b26469a8b139fba11d9336c1c117fafccfa9c7d5 Mon Sep 17 00:00:00 2001 From: Denis 'GNUtoo' Carikli Date: Thu, 23 Feb 2012 08:23:52 +0100 Subject: serial: samsung: fix s3c2442 platform data Without that fix machines having a s3c2442 CPU have something like that in dmesg: samsung-uart s3c2440-uart.0: could not find driver data samsung-uart s3c2440-uart.1: could not find driver data samsung-uart s3c2440-uart.2: could not find driver data And serial is never initialized. The previous log was obtained trough early printk on the gta02 machine. Signed-off-by: Denis 'GNUtoo' Carikli Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/samsung.c b/drivers/tty/serial/samsung.c index c55e5fb..de249d2 100644 --- a/drivers/tty/serial/samsung.c +++ b/drivers/tty/serial/samsung.c @@ -1507,7 +1507,7 @@ static struct s3c24xx_serial_drv_data s3c2412_serial_drv_data = { #endif #if defined(CONFIG_CPU_S3C2440) || defined(CONFIG_CPU_S3C2416) || \ - defined(CONFIG_CPU_S3C2443) + defined(CONFIG_CPU_S3C2443) || defined(CONFIG_CPU_S3C2442) static struct s3c24xx_serial_drv_data s3c2440_serial_drv_data = { .info = &(struct s3c24xx_uart_info) { .name = "Samsung S3C2440 UART", -- cgit v0.10.2 From 6dc01aa65306fe46b7ba38db51fad4ed81c23d00 Mon Sep 17 00:00:00 2001 From: Chanho Min Date: Mon, 20 Feb 2012 10:24:40 +0900 Subject: =?UTF-8?q?amba-pl011=E2=80=8B/dma:=20Add=20check=20for=20the=20re?= =?UTF-8?q?sidue=20in=20DMA=20callback?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In DMA-operated uart, I found that rx data can be taken by the UART interrupts during the DMA irq handler. pl011_int is occurred just before it goes inside spin_lock_irq. When it returns to the callback, DMA buffer already has been flushed. Then, pl011_dma_rx_chars gets invalid data. So I add check for the residue as the patch bellow. Signed-off-by: Chanho Min Acked-by: Linus Walleij Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c index 6800f5f..cc3ea06 100644 --- a/drivers/tty/serial/amba-pl011.c +++ b/drivers/tty/serial/amba-pl011.c @@ -827,7 +827,12 @@ static void pl011_dma_rx_callback(void *data) { struct uart_amba_port *uap = data; struct pl011_dmarx_data *dmarx = &uap->dmarx; + struct dma_chan *rxchan = dmarx->chan; bool lastbuf = dmarx->use_buf_b; + struct pl011_sgbuf *sgbuf = dmarx->use_buf_b ? + &dmarx->sgbuf_b : &dmarx->sgbuf_a; + size_t pending; + struct dma_tx_state state; int ret; /* @@ -838,11 +843,21 @@ static void pl011_dma_rx_callback(void *data) * we immediately trigger the next DMA job. */ spin_lock_irq(&uap->port.lock); + /* + * Rx data can be taken by the UART interrupts during + * the DMA irq handler. So we check the residue here. + */ + rxchan->device->device_tx_status(rxchan, dmarx->cookie, &state); + pending = sgbuf->sg.length - state.residue; + BUG_ON(pending > PL011_DMA_BUFFER_SIZE); + /* Then we terminate the transfer - we now know our residue */ + dmaengine_terminate_all(rxchan); + uap->dmarx.running = false; dmarx->use_buf_b = !lastbuf; ret = pl011_dma_rx_trigger_dma(uap); - pl011_dma_rx_chars(uap, PL011_DMA_BUFFER_SIZE, lastbuf, false); + pl011_dma_rx_chars(uap, pending, lastbuf, false); spin_unlock_irq(&uap->port.lock); /* * Do this check after we picked the DMA chars so we don't -- cgit v0.10.2 From 0ef1698e4d6282a1665207c40b115ec78fceda9b Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Fri, 24 Feb 2012 13:55:54 -0800 Subject: Revert "TTY: get rid of BTM around devpts_*" This reverts commit d3bda5298aad98c7a27678bdd0dd9d008ab9e685. Sasha reported that this causes problems, so revert it. Cc: Sasha Levin Cc: Jiri Slaby Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/pty.c b/drivers/tty/pty.c index 39afd04..ddec9f3 100644 --- a/drivers/tty/pty.c +++ b/drivers/tty/pty.c @@ -54,8 +54,8 @@ static void pty_close(struct tty_struct *tty, struct file *filp) wake_up_interruptible(&tty->link->write_wait); if (tty->driver->subtype == PTY_TYPE_MASTER) { set_bit(TTY_OTHER_CLOSED, &tty->flags); - tty_unlock(); devpts_pty_kill(tty->link); + tty_unlock(); tty_vhangup(tty->link); tty_lock(); } @@ -613,7 +613,9 @@ static int ptmx_open(struct inode *inode, struct file *filp) return retval; /* find a device that is not in use. */ + tty_lock(); index = devpts_new_index(inode); + tty_unlock(); if (index < 0) { retval = index; goto err_file; @@ -648,8 +650,8 @@ err_release: tty_release(inode, filp); return retval; out: - tty_unlock(); devpts_kill_index(inode, index); + tty_unlock(); err_file: tty_free_file(filp); return retval; diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index ea7ebe2..44736f9 100644 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c @@ -1789,11 +1789,11 @@ int tty_release(struct inode *inode, struct file *filp) * the slots and preserving the termios structure. */ release_tty(tty, idx); - tty_unlock(); /* Make this pty number available for reallocation */ if (devpts) devpts_kill_index(inode, idx); + tty_unlock(); return 0; } -- cgit v0.10.2 From ce1000ddca01c81684da844be4676eac50a70c2a Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Fri, 24 Feb 2012 13:56:36 -0800 Subject: Revert "TTY: pty, remove superfluous ptm test" This reverts commit a50f724a432997321cabb6c9e665c28e34850f78. Sasha reported that this causes problems, so revert it. Cc: Alan Cox Cc: Jiri Slaby Cc: Sasha Levin Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/pty.c b/drivers/tty/pty.c index ddec9f3..d505837 100644 --- a/drivers/tty/pty.c +++ b/drivers/tty/pty.c @@ -54,7 +54,10 @@ static void pty_close(struct tty_struct *tty, struct file *filp) wake_up_interruptible(&tty->link->write_wait); if (tty->driver->subtype == PTY_TYPE_MASTER) { set_bit(TTY_OTHER_CLOSED, &tty->flags); - devpts_pty_kill(tty->link); +#ifdef CONFIG_UNIX98_PTYS + if (tty->driver == ptm_driver) + devpts_pty_kill(tty->link); +#endif tty_unlock(); tty_vhangup(tty->link); tty_lock(); -- cgit v0.10.2 From 247ff8e610cb63c015de19191db9666754c2ed79 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Fri, 24 Feb 2012 12:47:11 +0000 Subject: vt: lock the accent table First step to debletcherising the vt console layer - pick a victim and fix the locking This is a nice simple object with its own rules so lets pick it out for treatment. The user of the table already has a lock so we will also use the same lock for updates. Signed-off-by: Alan Cox Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/vt/keyboard.c b/drivers/tty/vt/keyboard.c index a605549..bdf838d 100644 --- a/drivers/tty/vt/keyboard.c +++ b/drivers/tty/vt/keyboard.c @@ -1452,3 +1452,165 @@ int __init kbd_init(void) return 0; } + +/* Ioctl support code */ + +/** + * vt_do_diacrit - diacritical table updates + * @cmd: ioctl request + * @up: pointer to user data for ioctl + * @perm: permissions check computed by caller + * + * Update the diacritical tables atomically and safely. Lock them + * against simultaneous keypresses + */ +int vt_do_diacrit(unsigned int cmd, void __user *up, int perm) +{ + struct kbdiacrs __user *a = up; + unsigned long flags; + int asize; + int ret = 0; + + switch (cmd) { + case KDGKBDIACR: + { + struct kbdiacr *diacr; + int i; + + diacr = kmalloc(MAX_DIACR * sizeof(struct kbdiacr), + GFP_KERNEL); + if (diacr == NULL) + return -ENOMEM; + + /* Lock the diacriticals table, make a copy and then + copy it after we unlock */ + spin_lock_irqsave(&kbd_event_lock, flags); + + asize = accent_table_size; + for (i = 0; i < asize; i++) { + diacr[i].diacr = conv_uni_to_8bit( + accent_table[i].diacr); + diacr[i].base = conv_uni_to_8bit( + accent_table[i].base); + diacr[i].result = conv_uni_to_8bit( + accent_table[i].result); + } + spin_unlock_irqrestore(&kbd_event_lock, flags); + + if (put_user(asize, &a->kb_cnt)) + ret = -EFAULT; + else if (copy_to_user(a->kbdiacr, diacr, + asize * sizeof(struct kbdiacr))) + ret = -EFAULT; + kfree(diacr); + return ret; + } + case KDGKBDIACRUC: + { + struct kbdiacrsuc __user *a = up; + void *buf; + + buf = kmalloc(MAX_DIACR * sizeof(struct kbdiacruc), + GFP_KERNEL); + if (buf == NULL) + return -ENOMEM; + + /* Lock the diacriticals table, make a copy and then + copy it after we unlock */ + spin_lock_irqsave(&kbd_event_lock, flags); + + asize = accent_table_size; + memcpy(buf, accent_table, asize * sizeof(struct kbdiacruc)); + + spin_unlock_irqrestore(&kbd_event_lock, flags); + + if (put_user(asize, &a->kb_cnt)) + ret = -EFAULT; + else if (copy_to_user(a->kbdiacruc, buf, + asize*sizeof(struct kbdiacruc))) + ret = -EFAULT; + kfree(buf); + return ret; + } + + case KDSKBDIACR: + { + struct kbdiacrs __user *a = up; + struct kbdiacr *diacr = NULL; + unsigned int ct; + int i; + + if (!perm) + return -EPERM; + if (get_user(ct, &a->kb_cnt)) + return -EFAULT; + if (ct >= MAX_DIACR) + return -EINVAL; + + if (ct) { + diacr = kmalloc(sizeof(struct kbdiacr) * ct, + GFP_KERNEL); + if (diacr == NULL) + return -ENOMEM; + + if (copy_from_user(diacr, a->kbdiacr, + sizeof(struct kbdiacr) * ct)) { + kfree(diacr); + return -EFAULT; + } + } + + spin_lock_irqsave(&kbd_event_lock, flags); + accent_table_size = ct; + for (i = 0; i < ct; i++) { + accent_table[i].diacr = + conv_8bit_to_uni(diacr[i].diacr); + accent_table[i].base = + conv_8bit_to_uni(diacr[i].base); + accent_table[i].result = + conv_8bit_to_uni(diacr[i].result); + } + spin_unlock_irqrestore(&kbd_event_lock, flags); + kfree(diacr); + return 0; + } + + case KDSKBDIACRUC: + { + struct kbdiacrsuc __user *a = up; + unsigned int ct; + void *buf = NULL; + + if (!perm) + return -EPERM; + + if (get_user(ct, &a->kb_cnt)) + return -EFAULT; + + if (ct >= MAX_DIACR) + return -EINVAL; + + if (ct) { + buf = kmalloc(ct * sizeof(struct kbdiacruc), + GFP_KERNEL); + if (buf == NULL) + return -ENOMEM; + + if (copy_from_user(buf, a->kbdiacruc, + ct * sizeof(struct kbdiacruc))) { + kfree(buf); + return -EFAULT; + } + } + spin_lock_irqsave(&kbd_event_lock, flags); + if (ct) + memcpy(accent_table, buf, + ct * sizeof(struct kbdiacruc)); + accent_table_size = ct; + spin_unlock_irqrestore(&kbd_event_lock, flags); + kfree(buf); + return 0; + } + } + return ret; +} diff --git a/drivers/tty/vt/vt_ioctl.c b/drivers/tty/vt/vt_ioctl.c index 65447c5..80af0f9 100644 --- a/drivers/tty/vt/vt_ioctl.c +++ b/drivers/tty/vt/vt_ioctl.c @@ -753,89 +753,14 @@ int vt_ioctl(struct tty_struct *tty, ret = do_kdgkb_ioctl(cmd, up, perm); break; + /* Diacritical processing. Handled in keyboard.c as it has + to operate on the keyboard locks and structures */ case KDGKBDIACR: - { - struct kbdiacrs __user *a = up; - struct kbdiacr diacr; - int i; - - if (put_user(accent_table_size, &a->kb_cnt)) { - ret = -EFAULT; - break; - } - for (i = 0; i < accent_table_size; i++) { - diacr.diacr = conv_uni_to_8bit(accent_table[i].diacr); - diacr.base = conv_uni_to_8bit(accent_table[i].base); - diacr.result = conv_uni_to_8bit(accent_table[i].result); - if (copy_to_user(a->kbdiacr + i, &diacr, sizeof(struct kbdiacr))) { - ret = -EFAULT; - break; - } - } - break; - } case KDGKBDIACRUC: - { - struct kbdiacrsuc __user *a = up; - - if (put_user(accent_table_size, &a->kb_cnt)) - ret = -EFAULT; - else if (copy_to_user(a->kbdiacruc, accent_table, - accent_table_size*sizeof(struct kbdiacruc))) - ret = -EFAULT; - break; - } - case KDSKBDIACR: - { - struct kbdiacrs __user *a = up; - struct kbdiacr diacr; - unsigned int ct; - int i; - - if (!perm) - goto eperm; - if (get_user(ct,&a->kb_cnt)) { - ret = -EFAULT; - break; - } - if (ct >= MAX_DIACR) { - ret = -EINVAL; - break; - } - accent_table_size = ct; - for (i = 0; i < ct; i++) { - if (copy_from_user(&diacr, a->kbdiacr + i, sizeof(struct kbdiacr))) { - ret = -EFAULT; - break; - } - accent_table[i].diacr = conv_8bit_to_uni(diacr.diacr); - accent_table[i].base = conv_8bit_to_uni(diacr.base); - accent_table[i].result = conv_8bit_to_uni(diacr.result); - } - break; - } - case KDSKBDIACRUC: - { - struct kbdiacrsuc __user *a = up; - unsigned int ct; - - if (!perm) - goto eperm; - if (get_user(ct,&a->kb_cnt)) { - ret = -EFAULT; - break; - } - if (ct >= MAX_DIACR) { - ret = -EINVAL; - break; - } - accent_table_size = ct; - if (copy_from_user(accent_table, a->kbdiacruc, ct*sizeof(struct kbdiacruc))) - ret = -EFAULT; + ret = vt_do_diacrit(cmd, up, perm); break; - } /* the ioctls below read/set the flags usually shown in the leds */ /* don't use them - they will go away without warning */ diff --git a/include/linux/vt_kern.h b/include/linux/vt_kern.h index c2164fa..5d8726a 100644 --- a/include/linux/vt_kern.h +++ b/include/linux/vt_kern.h @@ -167,4 +167,7 @@ extern int unregister_vt_notifier(struct notifier_block *nb); extern void hide_boot_cursor(bool hide); +/* keyboard provided interfaces */ +extern int vt_do_diacrit(unsigned int cmd, void __user *up, int eperm); + #endif /* _VT_KERN_H */ -- cgit v0.10.2 From 6aeed479fdef85e6874c2d41cca9f121c294c536 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Fri, 24 Feb 2012 12:47:29 +0000 Subject: vt: tidy a few bits of checkpatch noise Signed-off-by: Alan Cox Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/vt/keyboard.c b/drivers/tty/vt/keyboard.c index bdf838d..0479114 100644 --- a/drivers/tty/vt/keyboard.c +++ b/drivers/tty/vt/keyboard.c @@ -55,8 +55,8 @@ extern void ctrl_alt_del(void); /* * Some laptops take the 789uiojklm,. keys as number pad when NumLock is on. * This seems a good reason to start with NumLock off. On HIL keyboards - * of PARISC machines however there is no NumLock key and everyone expects the keypad - * to be used for numbers. + * of PARISC machines however there is no NumLock key and everyone expects the + * keypad to be used for numbers. */ #if defined(CONFIG_PARISC) && (defined(CONFIG_KEYBOARD_HIL) || defined(CONFIG_KEYBOARD_HIL_OLD)) @@ -1404,14 +1404,14 @@ static void kbd_start(struct input_handle *handle) static const struct input_device_id kbd_ids[] = { { - .flags = INPUT_DEVICE_ID_MATCH_EVBIT, - .evbit = { BIT_MASK(EV_KEY) }, - }, + .flags = INPUT_DEVICE_ID_MATCH_EVBIT, + .evbit = { BIT_MASK(EV_KEY) }, + }, { - .flags = INPUT_DEVICE_ID_MATCH_EVBIT, - .evbit = { BIT_MASK(EV_SND) }, - }, + .flags = INPUT_DEVICE_ID_MATCH_EVBIT, + .evbit = { BIT_MASK(EV_SND) }, + }, { }, /* Terminating entry */ }; @@ -1433,7 +1433,7 @@ int __init kbd_init(void) int i; int error; - for (i = 0; i < MAX_NR_CONSOLES; i++) { + for (i = 0; i < MAX_NR_CONSOLES; i++) { kbd_table[i].ledflagstate = KBD_DEFLEDS; kbd_table[i].default_ledflagstate = KBD_DEFLEDS; kbd_table[i].ledmode = LED_SHOW_FLAGS; -- cgit v0.10.2 From 6623d64021469b0094bb070d3eb7d0e3f5e928af Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Mon, 27 Feb 2012 15:18:56 -0800 Subject: tty: keyboard.c: add uaccess.h to fix a build problem on sparc32 Reported-by: Stephen Rothwell Cc: Alan Cox Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/vt/keyboard.c b/drivers/tty/vt/keyboard.c index 0479114..898e359 100644 --- a/drivers/tty/vt/keyboard.c +++ b/drivers/tty/vt/keyboard.c @@ -41,6 +41,7 @@ #include #include #include +#include #include -- cgit v0.10.2 From 0fb8379dab9f97e4c56de8f9ea772c10eda27561 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 8 Mar 2012 10:45:55 -0800 Subject: tty: delete briq_panel.c driver This driver is broken, as reported by Jiri, and to quote Ben: Just remove the driver, I don't think anybody cares. so I'm doing just that here. Reported-by: Jiri Slaby Cc: Alan Cox Cc: Josh Boyer Cc: Benjamin Herrenschmidt Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig index 4364303..ee946865 100644 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig @@ -66,21 +66,6 @@ config TTY_PRINTK If unsure, say N. -config BRIQ_PANEL - tristate 'Total Impact briQ front panel driver' - depends on PPC_CHRP - ---help--- - The briQ is a small footprint CHRP computer with a frontpanel VFD, a - tristate led and two switches. It is the size of a CDROM drive. - - If you have such one and want anything showing on the VFD then you - must answer Y here. - - To compile this driver as a module, choose M here: the - module will be called briq_panel. - - It's safe to say N here. - config BFIN_OTP tristate "Blackfin On-Chip OTP Memory Support" depends on BLACKFIN && (BF51x || BF52x || BF54x) diff --git a/drivers/char/Makefile b/drivers/char/Makefile index 32762ba..0dc5d7c 100644 --- a/drivers/char/Makefile +++ b/drivers/char/Makefile @@ -16,7 +16,6 @@ obj-$(CONFIG_UV_MMTIMER) += uv_mmtimer.o obj-$(CONFIG_VIOTAPE) += viotape.o obj-$(CONFIG_IBM_BSR) += bsr.o obj-$(CONFIG_SGI_MBCS) += mbcs.o -obj-$(CONFIG_BRIQ_PANEL) += briq_panel.o obj-$(CONFIG_BFIN_OTP) += bfin-otp.o obj-$(CONFIG_PRINTER) += lp.o diff --git a/drivers/char/briq_panel.c b/drivers/char/briq_panel.c deleted file mode 100644 index 095ab90..0000000 --- a/drivers/char/briq_panel.c +++ /dev/null @@ -1,266 +0,0 @@ -/* - * Drivers for the Total Impact PPC based computer "BRIQ" - * by Dr. Karsten Jeppesen - * - */ - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#define BRIQ_PANEL_MINOR 156 -#define BRIQ_PANEL_VFD_IOPORT 0x0390 -#define BRIQ_PANEL_LED_IOPORT 0x0398 -#define BRIQ_PANEL_VER "1.1 (04/20/2002)" -#define BRIQ_PANEL_MSG0 "Loading Linux" - -static int vfd_is_open; -static unsigned char vfd[40]; -static int vfd_cursor; -static unsigned char ledpb, led; - -static void update_vfd(void) -{ - int i; - - /* cursor home */ - outb(0x02, BRIQ_PANEL_VFD_IOPORT); - for (i=0; i<20; i++) - outb(vfd[i], BRIQ_PANEL_VFD_IOPORT + 1); - - /* cursor to next line */ - outb(0xc0, BRIQ_PANEL_VFD_IOPORT); - for (i=20; i<40; i++) - outb(vfd[i], BRIQ_PANEL_VFD_IOPORT + 1); - -} - -static void set_led(char state) -{ - if (state == 'R') - led = 0x01; - else if (state == 'G') - led = 0x02; - else if (state == 'Y') - led = 0x03; - else if (state == 'X') - led = 0x00; - outb(led, BRIQ_PANEL_LED_IOPORT); -} - -static int briq_panel_open(struct inode *ino, struct file *filep) -{ - tty_lock(); - /* enforce single access, vfd_is_open is protected by BKL */ - if (vfd_is_open) { - tty_unlock(); - return -EBUSY; - } - vfd_is_open = 1; - - tty_unlock(); - return 0; -} - -static int briq_panel_release(struct inode *ino, struct file *filep) -{ - if (!vfd_is_open) - return -ENODEV; - - vfd_is_open = 0; - - return 0; -} - -static ssize_t briq_panel_read(struct file *file, char __user *buf, size_t count, - loff_t *ppos) -{ - unsigned short c; - unsigned char cp; - - if (!vfd_is_open) - return -ENODEV; - - c = (inb(BRIQ_PANEL_LED_IOPORT) & 0x000c) | (ledpb & 0x0003); - set_led(' '); - /* upper button released */ - if ((!(ledpb & 0x0004)) && (c & 0x0004)) { - cp = ' '; - ledpb = c; - if (copy_to_user(buf, &cp, 1)) - return -EFAULT; - return 1; - } - /* lower button released */ - else if ((!(ledpb & 0x0008)) && (c & 0x0008)) { - cp = '\r'; - ledpb = c; - if (copy_to_user(buf, &cp, 1)) - return -EFAULT; - return 1; - } else { - ledpb = c; - return 0; - } -} - -static void scroll_vfd( void ) -{ - int i; - - for (i=0; i<20; i++) { - vfd[i] = vfd[i+20]; - vfd[i+20] = ' '; - } - vfd_cursor = 20; -} - -static ssize_t briq_panel_write(struct file *file, const char __user *buf, size_t len, - loff_t *ppos) -{ - size_t indx = len; - int i, esc = 0; - - if (!vfd_is_open) - return -EBUSY; - - for (;;) { - char c; - if (!indx) - break; - if (get_user(c, buf)) - return -EFAULT; - if (esc) { - set_led(c); - esc = 0; - } else if (c == 27) { - esc = 1; - } else if (c == 12) { - /* do a form feed */ - for (i=0; i<40; i++) - vfd[i] = ' '; - vfd_cursor = 0; - } else if (c == 10) { - if (vfd_cursor < 20) - vfd_cursor = 20; - else if (vfd_cursor < 40) - vfd_cursor = 40; - else if (vfd_cursor < 60) - vfd_cursor = 60; - if (vfd_cursor > 59) - scroll_vfd(); - } else { - /* just a character */ - if (vfd_cursor > 39) - scroll_vfd(); - vfd[vfd_cursor++] = c; - } - indx--; - buf++; - } - update_vfd(); - - return len; -} - -static const struct file_operations briq_panel_fops = { - .owner = THIS_MODULE, - .read = briq_panel_read, - .write = briq_panel_write, - .open = briq_panel_open, - .release = briq_panel_release, - .llseek = noop_llseek, -}; - -static struct miscdevice briq_panel_miscdev = { - BRIQ_PANEL_MINOR, - "briq_panel", - &briq_panel_fops -}; - -static int __init briq_panel_init(void) -{ - struct device_node *root = of_find_node_by_path("/"); - const char *machine; - int i; - - machine = of_get_property(root, "model", NULL); - if (!machine || strncmp(machine, "TotalImpact,BRIQ-1", 18) != 0) { - of_node_put(root); - return -ENODEV; - } - of_node_put(root); - - printk(KERN_INFO - "briq_panel: v%s Dr. Karsten Jeppesen (kj@totalimpact.com)\n", - BRIQ_PANEL_VER); - - if (!request_region(BRIQ_PANEL_VFD_IOPORT, 4, "BRIQ Front Panel")) - return -EBUSY; - - if (!request_region(BRIQ_PANEL_LED_IOPORT, 2, "BRIQ Front Panel")) { - release_region(BRIQ_PANEL_VFD_IOPORT, 4); - return -EBUSY; - } - ledpb = inb(BRIQ_PANEL_LED_IOPORT) & 0x000c; - - if (misc_register(&briq_panel_miscdev) < 0) { - release_region(BRIQ_PANEL_VFD_IOPORT, 4); - release_region(BRIQ_PANEL_LED_IOPORT, 2); - return -EBUSY; - } - - outb(0x38, BRIQ_PANEL_VFD_IOPORT); /* Function set */ - outb(0x01, BRIQ_PANEL_VFD_IOPORT); /* Clear display */ - outb(0x0c, BRIQ_PANEL_VFD_IOPORT); /* Display on */ - outb(0x06, BRIQ_PANEL_VFD_IOPORT); /* Entry normal */ - for (i=0; i<40; i++) - vfd[i]=' '; -#ifndef MODULE - vfd[0] = 'L'; - vfd[1] = 'o'; - vfd[2] = 'a'; - vfd[3] = 'd'; - vfd[4] = 'i'; - vfd[5] = 'n'; - vfd[6] = 'g'; - vfd[7] = ' '; - vfd[8] = '.'; - vfd[9] = '.'; - vfd[10] = '.'; -#endif /* !MODULE */ - - update_vfd(); - - return 0; -} - -static void __exit briq_panel_exit(void) -{ - misc_deregister(&briq_panel_miscdev); - release_region(BRIQ_PANEL_VFD_IOPORT, 4); - release_region(BRIQ_PANEL_LED_IOPORT, 2); -} - -module_init(briq_panel_init); -module_exit(briq_panel_exit); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Karsten Jeppesen "); -MODULE_DESCRIPTION("Driver for the Total Impact briQ front panel"); -- cgit v0.10.2 From 079c9534a96da9a85a2a2f9715851050fbfbf749 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Tue, 28 Feb 2012 14:49:23 +0000 Subject: vt:tackle kbd_table Keyboard struct lifetime is easy, but the locking is not and is completely ignored by the existing code. Tackle this one head on - Make the kbd_table private so we can run down all direct users - Hoick the relevant ioctl handlers into the keyboard layer - Lock them with the keyboard lock so they don't change mid keypress - Add helpers for things like console stop/start so we isolate the poking around properly - Tweak the braille console so it still builds There are a couple of FIXME locking cases left for ioctls that are so hideous they should be addressed in a later patch. After this patch the kbd_table is private and all the keyboard jiggery pokery is in one place. This update fixes speakup and also a memory leak in the original. Signed-off-by: Alan Cox Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/accessibility/braille/braille_console.c b/drivers/accessibility/braille/braille_console.c index c339a08..d21167b 100644 --- a/drivers/accessibility/braille/braille_console.c +++ b/drivers/accessibility/braille/braille_console.c @@ -244,16 +244,13 @@ static int keyboard_notifier_call(struct notifier_block *blk, switch (val) { case KVAL(K_CAPS): - on_off = vc_kbd_led(kbd_table + fg_console, - VC_CAPSLOCK); + on_off = vt_get_leds(fg_console, VC_CAPSLOCK); break; case KVAL(K_NUM): - on_off = vc_kbd_led(kbd_table + fg_console, - VC_NUMLOCK); + on_off = vt_get_leds(fg_console, VC_NUMLOCK); break; case KVAL(K_HOLD): - on_off = vc_kbd_led(kbd_table + fg_console, - VC_SCROLLOCK); + on_off = vt_get_leds(fg_console, VC_SCROLLOCK); break; } if (on_off == 1) diff --git a/drivers/staging/speakup/main.c b/drivers/staging/speakup/main.c index c7b03f0..92b34e2 100644 --- a/drivers/staging/speakup/main.c +++ b/drivers/staging/speakup/main.c @@ -1731,15 +1731,15 @@ static void do_handle_spec(struct vc_data *vc, u_char value, char up_flag) switch (value) { case KVAL(K_CAPS): label = msg_get(MSG_KEYNAME_CAPSLOCK); - on_off = (vc_kbd_led(kbd_table + vc->vc_num, VC_CAPSLOCK)); + on_off = vt_get_leds(fg_console, VC_CAPSLOCK); break; case KVAL(K_NUM): label = msg_get(MSG_KEYNAME_NUMLOCK); - on_off = (vc_kbd_led(kbd_table + vc->vc_num, VC_NUMLOCK)); + on_off = vt_get_leds(fg_console, VC_NUMLOCK); break; case KVAL(K_HOLD): label = msg_get(MSG_KEYNAME_SCROLLLOCK); - on_off = (vc_kbd_led(kbd_table + vc->vc_num, VC_SCROLLOCK)); + on_off = vt_get_leds(fg_console, VC_SCROLLOCK); if (speakup_console[vc->vc_num]) speakup_console[vc->vc_num]->tty_stopped = on_off; break; @@ -2020,7 +2020,7 @@ speakup_key(struct vc_data *vc, int shift_state, int keycode, u_short keysym, if (type >= 0xf0) type -= 0xf0; if (type == KT_PAD - && (vc_kbd_led(kbd_table + fg_console, VC_NUMLOCK))) { + && (vt_get_leds(fg_console, VC_NUMLOCK))) { if (up_flag) { spk_keydown = 0; goto out; diff --git a/drivers/tty/sysrq.c b/drivers/tty/sysrq.c index 8db9125..ecb8e22 100644 --- a/drivers/tty/sysrq.c +++ b/drivers/tty/sysrq.c @@ -110,11 +110,9 @@ static struct sysrq_key_op sysrq_SAK_op = { #ifdef CONFIG_VT static void sysrq_handle_unraw(int key) { - struct kbd_struct *kbd = &kbd_table[fg_console]; - - if (kbd) - kbd->kbdmode = default_utf8 ? VC_UNICODE : VC_XLATE; + vt_reset_unicode(fg_console); } + static struct sysrq_key_op sysrq_unraw_op = { .handler = sysrq_handle_unraw, .help_msg = "unRaw", diff --git a/drivers/tty/vt/keyboard.c b/drivers/tty/vt/keyboard.c index 898e359..70d0593 100644 --- a/drivers/tty/vt/keyboard.c +++ b/drivers/tty/vt/keyboard.c @@ -68,8 +68,6 @@ extern void ctrl_alt_del(void); #define KBD_DEFLOCK 0 -void compute_shiftstate(void); - /* * Handler Tables. */ @@ -100,35 +98,29 @@ static fn_handler_fn *fn_handler[] = { FN_HANDLERS }; * Variables exported for vt_ioctl.c */ -/* maximum values each key_handler can handle */ -const int max_vals[] = { - 255, ARRAY_SIZE(func_table) - 1, ARRAY_SIZE(fn_handler) - 1, NR_PAD - 1, - NR_DEAD - 1, 255, 3, NR_SHIFT - 1, 255, NR_ASCII - 1, NR_LOCK - 1, - 255, NR_LOCK - 1, 255, NR_BRL - 1 -}; - -const int NR_TYPES = ARRAY_SIZE(max_vals); - -struct kbd_struct kbd_table[MAX_NR_CONSOLES]; -EXPORT_SYMBOL_GPL(kbd_table); -static struct kbd_struct *kbd = kbd_table; - struct vt_spawn_console vt_spawn_con = { .lock = __SPIN_LOCK_UNLOCKED(vt_spawn_con.lock), .pid = NULL, .sig = 0, }; -/* - * Variables exported for vt.c - */ - -int shift_state = 0; /* * Internal Data. */ +static struct kbd_struct kbd_table[MAX_NR_CONSOLES]; +static struct kbd_struct *kbd = kbd_table; + +/* maximum values each key_handler can handle */ +static const int max_vals[] = { + 255, ARRAY_SIZE(func_table) - 1, ARRAY_SIZE(fn_handler) - 1, NR_PAD - 1, + NR_DEAD - 1, 255, 3, NR_SHIFT - 1, 255, NR_ASCII - 1, NR_LOCK - 1, + 255, NR_LOCK - 1, 255, NR_BRL - 1 +}; + +static const int NR_TYPES = ARRAY_SIZE(max_vals); + static struct input_handler kbd_handler; static DEFINE_SPINLOCK(kbd_event_lock); static unsigned long key_down[BITS_TO_LONGS(KEY_CNT)]; /* keyboard key bitmap */ @@ -138,6 +130,8 @@ static int npadch = -1; /* -1 or number assembled on pad */ static unsigned int diacr; static char rep; /* flag telling character repeat */ +static int shift_state = 0; + static unsigned char ledstate = 0xff; /* undefined */ static unsigned char ledioctl; @@ -188,7 +182,7 @@ static int getkeycode_helper(struct input_handle *handle, void *data) return d->error == 0; /* stop as soon as we successfully get one */ } -int getkeycode(unsigned int scancode) +static int getkeycode(unsigned int scancode) { struct getset_keycode_data d = { .ke = { @@ -215,7 +209,7 @@ static int setkeycode_helper(struct input_handle *handle, void *data) return d->error == 0; /* stop as soon as we successfully set one */ } -int setkeycode(unsigned int scancode, unsigned int keycode) +static int setkeycode(unsigned int scancode, unsigned int keycode) { struct getset_keycode_data d = { .ke = { @@ -383,9 +377,11 @@ static void to_utf8(struct vc_data *vc, uint c) /* * Called after returning from RAW mode or when changing consoles - recompute * shift_down[] and shift_state from key_down[] maybe called when keymap is - * undefined, so that shiftkey release is seen + * undefined, so that shiftkey release is seen. The caller must hold the + * kbd_event_lock. */ -void compute_shiftstate(void) + +static void do_compute_shiftstate(void) { unsigned int i, j, k, sym, val; @@ -418,6 +414,15 @@ void compute_shiftstate(void) } } +/* We still have to export this method to vt.c */ +void compute_shiftstate(void) +{ + unsigned long flags; + spin_lock_irqsave(&kbd_event_lock, flags); + do_compute_shiftstate(); + spin_unlock_irqrestore(&kbd_event_lock, flags); +} + /* * We have a combining character DIACR here, followed by the character CH. * If the combination occurs in the table, return the corresponding value. @@ -637,7 +642,7 @@ static void fn_SAK(struct vc_data *vc) static void fn_null(struct vc_data *vc) { - compute_shiftstate(); + do_compute_shiftstate(); } /* @@ -990,6 +995,8 @@ unsigned char getledstate(void) void setledstate(struct kbd_struct *kbd, unsigned int led) { + unsigned long flags; + spin_lock_irqsave(&kbd_event_lock, flags); if (!(led & ~7)) { ledioctl = led; kbd->ledmode = LED_SHOW_IOCTL; @@ -997,6 +1004,7 @@ void setledstate(struct kbd_struct *kbd, unsigned int led) kbd->ledmode = LED_SHOW_FLAGS; set_leds(); + spin_unlock_irqrestore(&kbd_event_lock, flags); } static inline unsigned char getleds(void) @@ -1036,6 +1044,75 @@ static int kbd_update_leds_helper(struct input_handle *handle, void *data) return 0; } +/** + * vt_get_leds - helper for braille console + * @console: console to read + * @flag: flag we want to check + * + * Check the status of a keyboard led flag and report it back + */ +int vt_get_leds(int console, int flag) +{ + unsigned long flags; + struct kbd_struct * kbd = kbd_table + console; + int ret; + + spin_lock_irqsave(&kbd_event_lock, flags); + ret = vc_kbd_led(kbd, flag); + spin_unlock_irqrestore(&kbd_event_lock, flags); + + return ret; +} +EXPORT_SYMBOL_GPL(vt_get_leds); + +/** + * vt_set_led_state - set LED state of a console + * @console: console to set + * @leds: LED bits + * + * Set the LEDs on a console. This is a wrapper for the VT layer + * so that we can keep kbd knowledge internal + */ +void vt_set_led_state(int console, int leds) +{ + struct kbd_struct * kbd = kbd_table + console; + setledstate(kbd, leds); +} + +/** + * vt_kbd_con_start - Keyboard side of console start + * @console: console + * + * Handle console start. This is a wrapper for the VT layer + * so that we can keep kbd knowledge internal + */ +void vt_kbd_con_start(int console) +{ + struct kbd_struct * kbd = kbd_table + console; + unsigned long flags; + spin_lock_irqsave(&kbd_event_lock, flags); + clr_vc_kbd_led(kbd, VC_SCROLLOCK); + set_leds(); + spin_unlock_irqrestore(&kbd_event_lock, flags); +} + +/** + * vt_kbd_con_stop - Keyboard side of console stop + * @console: console + * + * Handle console stop. This is a wrapper for the VT layer + * so that we can keep kbd knowledge internal + */ +void vt_kbd_con_stop(int console) +{ + struct kbd_struct * kbd = kbd_table + console; + unsigned long flags; + spin_lock_irqsave(&kbd_event_lock, flags); + set_vc_kbd_led(kbd, VC_SCROLLOCK); + set_leds(); + spin_unlock_irqrestore(&kbd_event_lock, flags); +} + /* * This is the tasklet that updates LED state on all keyboards * attached to the box. The reason we use tasklet is that we @@ -1255,7 +1332,7 @@ static void kbd_keycode(unsigned int keycode, int down, int hw_raw) if (rc == NOTIFY_STOP || !key_map) { atomic_notifier_call_chain(&keyboard_notifier_list, KBD_UNBOUND_KEYCODE, ¶m); - compute_shiftstate(); + do_compute_shiftstate(); kbd->slockstate = 0; return; } @@ -1615,3 +1692,495 @@ int vt_do_diacrit(unsigned int cmd, void __user *up, int perm) } return ret; } + +/** + * vt_do_kdskbmode - set keyboard mode ioctl + * @console: the console to use + * @arg: the requested mode + * + * Update the keyboard mode bits while holding the correct locks. + * Return 0 for success or an error code. + */ +int vt_do_kdskbmode(int console, unsigned int arg) +{ + struct kbd_struct * kbd = kbd_table + console; + int ret = 0; + unsigned long flags; + + spin_lock_irqsave(&kbd_event_lock, flags); + switch(arg) { + case K_RAW: + kbd->kbdmode = VC_RAW; + break; + case K_MEDIUMRAW: + kbd->kbdmode = VC_MEDIUMRAW; + break; + case K_XLATE: + kbd->kbdmode = VC_XLATE; + do_compute_shiftstate(); + break; + case K_UNICODE: + kbd->kbdmode = VC_UNICODE; + do_compute_shiftstate(); + break; + case K_OFF: + kbd->kbdmode = VC_OFF; + break; + default: + ret = -EINVAL; + } + spin_unlock_irqrestore(&kbd_event_lock, flags); + return ret; +} + +/** + * vt_do_kdskbmeta - set keyboard meta state + * @console: the console to use + * @arg: the requested meta state + * + * Update the keyboard meta bits while holding the correct locks. + * Return 0 for success or an error code. + */ +int vt_do_kdskbmeta(int console, unsigned int arg) +{ + struct kbd_struct * kbd = kbd_table + console; + int ret = 0; + unsigned long flags; + + spin_lock_irqsave(&kbd_event_lock, flags); + switch(arg) { + case K_METABIT: + clr_vc_kbd_mode(kbd, VC_META); + break; + case K_ESCPREFIX: + set_vc_kbd_mode(kbd, VC_META); + break; + default: + ret = -EINVAL; + } + spin_unlock_irqrestore(&kbd_event_lock, flags); + return ret; +} + +int vt_do_kbkeycode_ioctl(int cmd, struct kbkeycode __user *user_kbkc, + int perm) +{ + struct kbkeycode tmp; + int kc = 0; + + if (copy_from_user(&tmp, user_kbkc, sizeof(struct kbkeycode))) + return -EFAULT; + switch (cmd) { + case KDGETKEYCODE: + kc = getkeycode(tmp.scancode); + if (kc >= 0) + kc = put_user(kc, &user_kbkc->keycode); + break; + case KDSETKEYCODE: + if (!perm) + return -EPERM; + kc = setkeycode(tmp.scancode, tmp.keycode); + break; + } + return kc; +} + +#define i (tmp.kb_index) +#define s (tmp.kb_table) +#define v (tmp.kb_value) + +int vt_do_kdsk_ioctl(int cmd, struct kbentry __user *user_kbe, int perm, + int console) +{ + struct kbd_struct * kbd = kbd_table + console; + struct kbentry tmp; + ushort *key_map, *new_map, val, ov; + unsigned long flags; + + if (copy_from_user(&tmp, user_kbe, sizeof(struct kbentry))) + return -EFAULT; + + if (!capable(CAP_SYS_TTY_CONFIG)) + perm = 0; + + switch (cmd) { + case KDGKBENT: + /* Ensure another thread doesn't free it under us */ + spin_lock_irqsave(&kbd_event_lock, flags); + key_map = key_maps[s]; + if (key_map) { + val = U(key_map[i]); + if (kbd->kbdmode != VC_UNICODE && KTYP(val) >= NR_TYPES) + val = K_HOLE; + } else + val = (i ? K_HOLE : K_NOSUCHMAP); + spin_unlock_irqrestore(&kbd_event_lock, flags); + return put_user(val, &user_kbe->kb_value); + case KDSKBENT: + if (!perm) + return -EPERM; + if (!i && v == K_NOSUCHMAP) { + spin_lock_irqsave(&kbd_event_lock, flags); + /* deallocate map */ + key_map = key_maps[s]; + if (s && key_map) { + key_maps[s] = NULL; + if (key_map[0] == U(K_ALLOCATED)) { + kfree(key_map); + keymap_count--; + } + } + spin_unlock_irqrestore(&kbd_event_lock, flags); + break; + } + + if (KTYP(v) < NR_TYPES) { + if (KVAL(v) > max_vals[KTYP(v)]) + return -EINVAL; + } else + if (kbd->kbdmode != VC_UNICODE) + return -EINVAL; + + /* ++Geert: non-PC keyboards may generate keycode zero */ +#if !defined(__mc68000__) && !defined(__powerpc__) + /* assignment to entry 0 only tests validity of args */ + if (!i) + break; +#endif + + new_map = kmalloc(sizeof(plain_map), GFP_KERNEL); + if (!new_map) + return -ENOMEM; + spin_lock_irqsave(&kbd_event_lock, flags); + key_map = key_maps[s]; + if (key_map == NULL) { + int j; + + if (keymap_count >= MAX_NR_OF_USER_KEYMAPS && + !capable(CAP_SYS_RESOURCE)) { + spin_unlock_irqrestore(&kbd_event_lock, flags); + kfree(new_map); + return -EPERM; + } + key_maps[s] = new_map; + key_map[0] = U(K_ALLOCATED); + for (j = 1; j < NR_KEYS; j++) + key_map[j] = U(K_HOLE); + keymap_count++; + } else + kfree(new_map); + + ov = U(key_map[i]); + if (v == ov) + goto out; + /* + * Attention Key. + */ + if (((ov == K_SAK) || (v == K_SAK)) && !capable(CAP_SYS_ADMIN)) { + spin_unlock_irqrestore(&kbd_event_lock, flags); + return -EPERM; + } + key_map[i] = U(v); + if (!s && (KTYP(ov) == KT_SHIFT || KTYP(v) == KT_SHIFT)) + do_compute_shiftstate(); +out: + spin_unlock_irqrestore(&kbd_event_lock, flags); + break; + } + return 0; +} +#undef i +#undef s +#undef v + +/* FIXME: This one needs untangling and locking */ +int vt_do_kdgkb_ioctl(int cmd, struct kbsentry __user *user_kdgkb, int perm) +{ + struct kbsentry *kbs; + char *p; + u_char *q; + u_char __user *up; + int sz; + int delta; + char *first_free, *fj, *fnw; + int i, j, k; + int ret; + + if (!capable(CAP_SYS_TTY_CONFIG)) + perm = 0; + + kbs = kmalloc(sizeof(*kbs), GFP_KERNEL); + if (!kbs) { + ret = -ENOMEM; + goto reterr; + } + + /* we mostly copy too much here (512bytes), but who cares ;) */ + if (copy_from_user(kbs, user_kdgkb, sizeof(struct kbsentry))) { + ret = -EFAULT; + goto reterr; + } + kbs->kb_string[sizeof(kbs->kb_string)-1] = '\0'; + i = kbs->kb_func; + + switch (cmd) { + case KDGKBSENT: + sz = sizeof(kbs->kb_string) - 1; /* sz should have been + a struct member */ + up = user_kdgkb->kb_string; + p = func_table[i]; + if(p) + for ( ; *p && sz; p++, sz--) + if (put_user(*p, up++)) { + ret = -EFAULT; + goto reterr; + } + if (put_user('\0', up)) { + ret = -EFAULT; + goto reterr; + } + kfree(kbs); + return ((p && *p) ? -EOVERFLOW : 0); + case KDSKBSENT: + if (!perm) { + ret = -EPERM; + goto reterr; + } + + q = func_table[i]; + first_free = funcbufptr + (funcbufsize - funcbufleft); + for (j = i+1; j < MAX_NR_FUNC && !func_table[j]; j++) + ; + if (j < MAX_NR_FUNC) + fj = func_table[j]; + else + fj = first_free; + + delta = (q ? -strlen(q) : 1) + strlen(kbs->kb_string); + if (delta <= funcbufleft) { /* it fits in current buf */ + if (j < MAX_NR_FUNC) { + memmove(fj + delta, fj, first_free - fj); + for (k = j; k < MAX_NR_FUNC; k++) + if (func_table[k]) + func_table[k] += delta; + } + if (!q) + func_table[i] = fj; + funcbufleft -= delta; + } else { /* allocate a larger buffer */ + sz = 256; + while (sz < funcbufsize - funcbufleft + delta) + sz <<= 1; + fnw = kmalloc(sz, GFP_KERNEL); + if(!fnw) { + ret = -ENOMEM; + goto reterr; + } + + if (!q) + func_table[i] = fj; + if (fj > funcbufptr) + memmove(fnw, funcbufptr, fj - funcbufptr); + for (k = 0; k < j; k++) + if (func_table[k]) + func_table[k] = fnw + (func_table[k] - funcbufptr); + + if (first_free > fj) { + memmove(fnw + (fj - funcbufptr) + delta, fj, first_free - fj); + for (k = j; k < MAX_NR_FUNC; k++) + if (func_table[k]) + func_table[k] = fnw + (func_table[k] - funcbufptr) + delta; + } + if (funcbufptr != func_buf) + kfree(funcbufptr); + funcbufptr = fnw; + funcbufleft = funcbufleft - delta + sz - funcbufsize; + funcbufsize = sz; + } + strcpy(func_table[i], kbs->kb_string); + break; + } + ret = 0; +reterr: + kfree(kbs); + return ret; +} + +int vt_do_kdskled(int console, int cmd, unsigned long arg, int perm) +{ + struct kbd_struct * kbd = kbd_table + console; + unsigned long flags; + unsigned char ucval; + + switch(cmd) { + /* the ioctls below read/set the flags usually shown in the leds */ + /* don't use them - they will go away without warning */ + case KDGKBLED: + spin_lock_irqsave(&kbd_event_lock, flags); + ucval = kbd->ledflagstate | (kbd->default_ledflagstate << 4); + spin_unlock_irqrestore(&kbd_event_lock, flags); + return put_user(ucval, (char __user *)arg); + + case KDSKBLED: + if (!perm) + return -EPERM; + if (arg & ~0x77) + return -EINVAL; + spin_lock_irqsave(&kbd_event_lock, flags); + kbd->ledflagstate = (arg & 7); + kbd->default_ledflagstate = ((arg >> 4) & 7); + set_leds(); + spin_unlock_irqrestore(&kbd_event_lock, flags); + break; + + /* the ioctls below only set the lights, not the functions */ + /* for those, see KDGKBLED and KDSKBLED above */ + case KDGETLED: + ucval = getledstate(); + return put_user(ucval, (char __user *)arg); + + case KDSETLED: + if (!perm) + return -EPERM; + setledstate(kbd, arg); + return 0; + } + return -ENOIOCTLCMD; +} + +int vt_do_kdgkbmode(int console) +{ + struct kbd_struct * kbd = kbd_table + console; + /* This is a spot read so needs no locking */ + switch (kbd->kbdmode) { + case VC_RAW: + return K_RAW; + case VC_MEDIUMRAW: + return K_MEDIUMRAW; + case VC_UNICODE: + return K_UNICODE; + case VC_OFF: + return K_OFF; + default: + return K_XLATE; + } +} + +/** + * vt_do_kdgkbmeta - report meta status + * @console: console to report + * + * Report the meta flag status of this console + */ +int vt_do_kdgkbmeta(int console) +{ + struct kbd_struct * kbd = kbd_table + console; + /* Again a spot read so no locking */ + return vc_kbd_mode(kbd, VC_META) ? K_ESCPREFIX : K_METABIT; +} + +/** + * vt_reset_unicode - reset the unicode status + * @console: console being reset + * + * Restore the unicode console state to its default + */ +void vt_reset_unicode(int console) +{ + unsigned long flags; + + spin_lock_irqsave(&kbd_event_lock, flags); + kbd_table[console].kbdmode = default_utf8 ? VC_UNICODE : VC_XLATE; + spin_unlock_irqrestore(&kbd_event_lock, flags); +} + +/** + * vt_get_shiftstate - shift bit state + * + * Report the shift bits from the keyboard state. We have to export + * this to support some oddities in the vt layer. + */ +int vt_get_shift_state(void) +{ + /* Don't lock as this is a transient report */ + return shift_state; +} + +/** + * vt_reset_keyboard - reset keyboard state + * @console: console to reset + * + * Reset the keyboard bits for a console as part of a general console + * reset event + */ +void vt_reset_keyboard(int console) +{ + struct kbd_struct * kbd = kbd_table + console; + unsigned long flags; + + spin_lock_irqsave(&kbd_event_lock, flags); + set_vc_kbd_mode(kbd, VC_REPEAT); + clr_vc_kbd_mode(kbd, VC_CKMODE); + clr_vc_kbd_mode(kbd, VC_APPLIC); + clr_vc_kbd_mode(kbd, VC_CRLF); + kbd->lockstate = 0; + kbd->slockstate = 0; + kbd->ledmode = LED_SHOW_FLAGS; + kbd->ledflagstate = kbd->default_ledflagstate; + /* do not do set_leds here because this causes an endless tasklet loop + when the keyboard hasn't been initialized yet */ + spin_unlock_irqrestore(&kbd_event_lock, flags); +} + +/** + * vt_get_kbd_mode_bit - read keyboard status bits + * @console: console to read from + * @bit: mode bit to read + * + * Report back a vt mode bit. We do this without locking so the + * caller must be sure that there are no synchronization needs + */ + +int vt_get_kbd_mode_bit(int console, int bit) +{ + struct kbd_struct * kbd = kbd_table + console; + return vc_kbd_mode(kbd, bit); +} + +/** + * vt_set_kbd_mode_bit - read keyboard status bits + * @console: console to read from + * @bit: mode bit to read + * + * Set a vt mode bit. We do this without locking so the + * caller must be sure that there are no synchronization needs + */ + +void vt_set_kbd_mode_bit(int console, int bit) +{ + struct kbd_struct * kbd = kbd_table + console; + unsigned long flags; + + spin_lock_irqsave(&kbd_event_lock, flags); + set_vc_kbd_mode(kbd, bit); + spin_unlock_irqrestore(&kbd_event_lock, flags); +} + +/** + * vt_clr_kbd_mode_bit - read keyboard status bits + * @console: console to read from + * @bit: mode bit to read + * + * Report back a vt mode bit. We do this without locking so the + * caller must be sure that there are no synchronization needs + */ + +void vt_clr_kbd_mode_bit(int console, int bit) +{ + struct kbd_struct * kbd = kbd_table + console; + unsigned long flags; + + spin_lock_irqsave(&kbd_event_lock, flags); + clr_vc_kbd_mode(kbd, bit); + spin_unlock_irqrestore(&kbd_event_lock, flags); +} diff --git a/drivers/tty/vt/selection.c b/drivers/tty/vt/selection.c index 7a0a12a..738e45a 100644 --- a/drivers/tty/vt/selection.c +++ b/drivers/tty/vt/selection.c @@ -30,6 +30,7 @@ extern void poke_blanked_console(void); +/* FIXME: all this needs locking */ /* Variables for selection control. */ /* Use a dynamic buffer, instead of static (Dec 1994) */ struct vc_data *sel_cons; /* must not be deallocated */ @@ -138,7 +139,7 @@ int set_selection(const struct tiocl_selection __user *sel, struct tty_struct *t char *bp, *obp; int i, ps, pe, multiplier; u16 c; - struct kbd_struct *kbd = kbd_table + fg_console; + int mode; poke_blanked_console(); @@ -182,7 +183,11 @@ int set_selection(const struct tiocl_selection __user *sel, struct tty_struct *t clear_selection(); sel_cons = vc_cons[fg_console].d; } - use_unicode = kbd && kbd->kbdmode == VC_UNICODE; + mode = vt_do_kdgkbmode(fg_console); + if (mode == K_UNICODE) + use_unicode = 1; + else + use_unicode = 0; switch (sel_mode) { diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index e716839..ecdcc8a 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -1028,9 +1028,9 @@ void vc_deallocate(unsigned int currcons) * VT102 emulator */ -#define set_kbd(vc, x) set_vc_kbd_mode(kbd_table + (vc)->vc_num, (x)) -#define clr_kbd(vc, x) clr_vc_kbd_mode(kbd_table + (vc)->vc_num, (x)) -#define is_kbd(vc, x) vc_kbd_mode(kbd_table + (vc)->vc_num, (x)) +#define set_kbd(vc, x) vt_set_kbd_mode_bit((vc)->vc_num, (x)) +#define clr_kbd(vc, x) vt_clr_kbd_mode_bit((vc)->vc_num, (x)) +#define is_kbd(vc, x) vt_get_kbd_mode_bit((vc)->vc_num, (x)) #define decarm VC_REPEAT #define decckm VC_CKMODE @@ -1652,16 +1652,7 @@ static void reset_terminal(struct vc_data *vc, int do_clear) vc->vc_deccm = global_cursor_default; vc->vc_decim = 0; - set_kbd(vc, decarm); - clr_kbd(vc, decckm); - clr_kbd(vc, kbdapplic); - clr_kbd(vc, lnm); - kbd_table[vc->vc_num].lockstate = 0; - kbd_table[vc->vc_num].slockstate = 0; - kbd_table[vc->vc_num].ledmode = LED_SHOW_FLAGS; - kbd_table[vc->vc_num].ledflagstate = kbd_table[vc->vc_num].default_ledflagstate; - /* do not do set_leds here because this causes an endless tasklet loop - when the keyboard hasn't been initialized yet */ + vt_reset_keyboard(vc->vc_num); vc->vc_cursor_type = cur_default; vc->vc_complement_mask = vc->vc_s_complement_mask; @@ -1979,7 +1970,7 @@ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, int c) case 'q': /* DECLL - but only 3 leds */ /* map 0,1,2,3 to 0,1,2,4 */ if (vc->vc_par[0] < 4) - setledstate(kbd_table + vc->vc_num, + vt_set_led_state(vc->vc_num, (vc->vc_par[0] < 3) ? vc->vc_par[0] : 4); return; case 'r': @@ -2642,7 +2633,7 @@ int tioclinux(struct tty_struct *tty, unsigned long arg) * kernel-internal variable; programs not closely * related to the kernel should not use this. */ - data = shift_state; + data = vt_get_shift_state(); ret = __put_user(data, p); break; case TIOCL_GETMOUSEREPORTING: @@ -2753,8 +2744,7 @@ static void con_stop(struct tty_struct *tty) console_num = tty->index; if (!vc_cons_allocated(console_num)) return; - set_vc_kbd_led(kbd_table + console_num, VC_SCROLLOCK); - set_leds(); + vt_kbd_con_stop(console_num); } /* @@ -2768,8 +2758,7 @@ static void con_start(struct tty_struct *tty) console_num = tty->index; if (!vc_cons_allocated(console_num)) return; - clr_vc_kbd_led(kbd_table + console_num, VC_SCROLLOCK); - set_leds(); + vt_kbd_con_start(console_num); } static void con_flush_chars(struct tty_struct *tty) diff --git a/drivers/tty/vt/vt_ioctl.c b/drivers/tty/vt/vt_ioctl.c index 80af0f9..28ca0aa 100644 --- a/drivers/tty/vt/vt_ioctl.c +++ b/drivers/tty/vt/vt_ioctl.c @@ -195,232 +195,7 @@ int vt_waitactive(int n) #define GPLAST 0x3df #define GPNUM (GPLAST - GPFIRST + 1) -#define i (tmp.kb_index) -#define s (tmp.kb_table) -#define v (tmp.kb_value) -static inline int -do_kdsk_ioctl(int cmd, struct kbentry __user *user_kbe, int perm, struct kbd_struct *kbd) -{ - struct kbentry tmp; - ushort *key_map, val, ov; - - if (copy_from_user(&tmp, user_kbe, sizeof(struct kbentry))) - return -EFAULT; - - if (!capable(CAP_SYS_TTY_CONFIG)) - perm = 0; - - switch (cmd) { - case KDGKBENT: - key_map = key_maps[s]; - if (key_map) { - val = U(key_map[i]); - if (kbd->kbdmode != VC_UNICODE && KTYP(val) >= NR_TYPES) - val = K_HOLE; - } else - val = (i ? K_HOLE : K_NOSUCHMAP); - return put_user(val, &user_kbe->kb_value); - case KDSKBENT: - if (!perm) - return -EPERM; - if (!i && v == K_NOSUCHMAP) { - /* deallocate map */ - key_map = key_maps[s]; - if (s && key_map) { - key_maps[s] = NULL; - if (key_map[0] == U(K_ALLOCATED)) { - kfree(key_map); - keymap_count--; - } - } - break; - } - - if (KTYP(v) < NR_TYPES) { - if (KVAL(v) > max_vals[KTYP(v)]) - return -EINVAL; - } else - if (kbd->kbdmode != VC_UNICODE) - return -EINVAL; - - /* ++Geert: non-PC keyboards may generate keycode zero */ -#if !defined(__mc68000__) && !defined(__powerpc__) - /* assignment to entry 0 only tests validity of args */ - if (!i) - break; -#endif - - if (!(key_map = key_maps[s])) { - int j; - - if (keymap_count >= MAX_NR_OF_USER_KEYMAPS && - !capable(CAP_SYS_RESOURCE)) - return -EPERM; - - key_map = kmalloc(sizeof(plain_map), - GFP_KERNEL); - if (!key_map) - return -ENOMEM; - key_maps[s] = key_map; - key_map[0] = U(K_ALLOCATED); - for (j = 1; j < NR_KEYS; j++) - key_map[j] = U(K_HOLE); - keymap_count++; - } - ov = U(key_map[i]); - if (v == ov) - break; /* nothing to do */ - /* - * Attention Key. - */ - if (((ov == K_SAK) || (v == K_SAK)) && !capable(CAP_SYS_ADMIN)) - return -EPERM; - key_map[i] = U(v); - if (!s && (KTYP(ov) == KT_SHIFT || KTYP(v) == KT_SHIFT)) - compute_shiftstate(); - break; - } - return 0; -} -#undef i -#undef s -#undef v - -static inline int -do_kbkeycode_ioctl(int cmd, struct kbkeycode __user *user_kbkc, int perm) -{ - struct kbkeycode tmp; - int kc = 0; - - if (copy_from_user(&tmp, user_kbkc, sizeof(struct kbkeycode))) - return -EFAULT; - switch (cmd) { - case KDGETKEYCODE: - kc = getkeycode(tmp.scancode); - if (kc >= 0) - kc = put_user(kc, &user_kbkc->keycode); - break; - case KDSETKEYCODE: - if (!perm) - return -EPERM; - kc = setkeycode(tmp.scancode, tmp.keycode); - break; - } - return kc; -} - -static inline int -do_kdgkb_ioctl(int cmd, struct kbsentry __user *user_kdgkb, int perm) -{ - struct kbsentry *kbs; - char *p; - u_char *q; - u_char __user *up; - int sz; - int delta; - char *first_free, *fj, *fnw; - int i, j, k; - int ret; - - if (!capable(CAP_SYS_TTY_CONFIG)) - perm = 0; - - kbs = kmalloc(sizeof(*kbs), GFP_KERNEL); - if (!kbs) { - ret = -ENOMEM; - goto reterr; - } - - /* we mostly copy too much here (512bytes), but who cares ;) */ - if (copy_from_user(kbs, user_kdgkb, sizeof(struct kbsentry))) { - ret = -EFAULT; - goto reterr; - } - kbs->kb_string[sizeof(kbs->kb_string)-1] = '\0'; - i = kbs->kb_func; - - switch (cmd) { - case KDGKBSENT: - sz = sizeof(kbs->kb_string) - 1; /* sz should have been - a struct member */ - up = user_kdgkb->kb_string; - p = func_table[i]; - if(p) - for ( ; *p && sz; p++, sz--) - if (put_user(*p, up++)) { - ret = -EFAULT; - goto reterr; - } - if (put_user('\0', up)) { - ret = -EFAULT; - goto reterr; - } - kfree(kbs); - return ((p && *p) ? -EOVERFLOW : 0); - case KDSKBSENT: - if (!perm) { - ret = -EPERM; - goto reterr; - } - q = func_table[i]; - first_free = funcbufptr + (funcbufsize - funcbufleft); - for (j = i+1; j < MAX_NR_FUNC && !func_table[j]; j++) - ; - if (j < MAX_NR_FUNC) - fj = func_table[j]; - else - fj = first_free; - - delta = (q ? -strlen(q) : 1) + strlen(kbs->kb_string); - if (delta <= funcbufleft) { /* it fits in current buf */ - if (j < MAX_NR_FUNC) { - memmove(fj + delta, fj, first_free - fj); - for (k = j; k < MAX_NR_FUNC; k++) - if (func_table[k]) - func_table[k] += delta; - } - if (!q) - func_table[i] = fj; - funcbufleft -= delta; - } else { /* allocate a larger buffer */ - sz = 256; - while (sz < funcbufsize - funcbufleft + delta) - sz <<= 1; - fnw = kmalloc(sz, GFP_KERNEL); - if(!fnw) { - ret = -ENOMEM; - goto reterr; - } - - if (!q) - func_table[i] = fj; - if (fj > funcbufptr) - memmove(fnw, funcbufptr, fj - funcbufptr); - for (k = 0; k < j; k++) - if (func_table[k]) - func_table[k] = fnw + (func_table[k] - funcbufptr); - - if (first_free > fj) { - memmove(fnw + (fj - funcbufptr) + delta, fj, first_free - fj); - for (k = j; k < MAX_NR_FUNC; k++) - if (func_table[k]) - func_table[k] = fnw + (func_table[k] - funcbufptr) + delta; - } - if (funcbufptr != func_buf) - kfree(funcbufptr); - funcbufptr = fnw; - funcbufleft = funcbufleft - delta + sz - funcbufsize; - funcbufsize = sz; - } - strcpy(func_table[i], kbs->kb_string); - break; - } - ret = 0; -reterr: - kfree(kbs); - return ret; -} static inline int do_fontx_ioctl(int cmd, struct consolefontdesc __user *user_cfd, int perm, struct console_font_op *op) @@ -497,7 +272,6 @@ int vt_ioctl(struct tty_struct *tty, { struct vc_data *vc = tty->driver_data; struct console_font_op op; /* used in multiple places here */ - struct kbd_struct * kbd; unsigned int console; unsigned char ucval; unsigned int uival; @@ -523,7 +297,6 @@ int vt_ioctl(struct tty_struct *tty, if (current->signal->tty == tty || capable(CAP_SYS_TTY_CONFIG)) perm = 1; - kbd = kbd_table + console; switch (cmd) { case TIOCLINUX: ret = tioclinux(tty, arg); @@ -565,7 +338,8 @@ int vt_ioctl(struct tty_struct *tty, * this is naive. */ ucval = KB_101; - goto setchar; + ret = put_user(ucval, (char __user *)arg); + break; /* * These cannot be implemented on any machine that implements @@ -670,68 +444,25 @@ int vt_ioctl(struct tty_struct *tty, case KDSKBMODE: if (!perm) goto eperm; - switch(arg) { - case K_RAW: - kbd->kbdmode = VC_RAW; - break; - case K_MEDIUMRAW: - kbd->kbdmode = VC_MEDIUMRAW; - break; - case K_XLATE: - kbd->kbdmode = VC_XLATE; - compute_shiftstate(); - break; - case K_UNICODE: - kbd->kbdmode = VC_UNICODE; - compute_shiftstate(); - break; - case K_OFF: - kbd->kbdmode = VC_OFF; - break; - default: - ret = -EINVAL; - goto out; - } - tty_ldisc_flush(tty); + ret = vt_do_kdskbmode(console, arg); + if (ret == 0) + tty_ldisc_flush(tty); break; case KDGKBMODE: - switch (kbd->kbdmode) { - case VC_RAW: - uival = K_RAW; - break; - case VC_MEDIUMRAW: - uival = K_MEDIUMRAW; - break; - case VC_UNICODE: - uival = K_UNICODE; - break; - case VC_OFF: - uival = K_OFF; - break; - default: - uival = K_XLATE; - break; - } - goto setint; + uival = vt_do_kdgkbmode(console); + ret = put_user(uival, (int __user *)arg); + break; /* this could be folded into KDSKBMODE, but for compatibility reasons it is not so easy to fold KDGKBMETA into KDGKBMODE */ case KDSKBMETA: - switch(arg) { - case K_METABIT: - clr_vc_kbd_mode(kbd, VC_META); - break; - case K_ESCPREFIX: - set_vc_kbd_mode(kbd, VC_META); - break; - default: - ret = -EINVAL; - } + ret = vt_do_kdskbmeta(console, arg); break; case KDGKBMETA: - uival = (vc_kbd_mode(kbd, VC_META) ? K_ESCPREFIX : K_METABIT); + /* FIXME: should review whether this is worth locking */ + uival = vt_do_kdgkbmeta(console); setint: ret = put_user(uival, (int __user *)arg); break; @@ -740,17 +471,17 @@ int vt_ioctl(struct tty_struct *tty, case KDSETKEYCODE: if(!capable(CAP_SYS_TTY_CONFIG)) perm = 0; - ret = do_kbkeycode_ioctl(cmd, up, perm); + ret = vt_do_kbkeycode_ioctl(cmd, up, perm); break; case KDGKBENT: case KDSKBENT: - ret = do_kdsk_ioctl(cmd, up, perm, kbd); + ret = vt_do_kdsk_ioctl(cmd, up, perm, console); break; case KDGKBSENT: case KDSKBSENT: - ret = do_kdgkb_ioctl(cmd, up, perm); + ret = vt_do_kdgkb_ioctl(cmd, up, perm); break; /* Diacritical processing. Handled in keyboard.c as it has @@ -765,33 +496,10 @@ int vt_ioctl(struct tty_struct *tty, /* the ioctls below read/set the flags usually shown in the leds */ /* don't use them - they will go away without warning */ case KDGKBLED: - ucval = kbd->ledflagstate | (kbd->default_ledflagstate << 4); - goto setchar; - case KDSKBLED: - if (!perm) - goto eperm; - if (arg & ~0x77) { - ret = -EINVAL; - break; - } - kbd->ledflagstate = (arg & 7); - kbd->default_ledflagstate = ((arg >> 4) & 7); - set_leds(); - break; - - /* the ioctls below only set the lights, not the functions */ - /* for those, see KDGKBLED and KDSKBLED above */ case KDGETLED: - ucval = getledstate(); - setchar: - ret = put_user(ucval, (char __user *)arg); - break; - case KDSETLED: - if (!perm) - goto eperm; - setledstate(kbd, arg); + ret = vt_do_kdskled(console, cmd, arg, perm); break; /* @@ -1286,7 +994,7 @@ eperm: void reset_vc(struct vc_data *vc) { vc->vc_mode = KD_TEXT; - kbd_table[vc->vc_num].kbdmode = default_utf8 ? VC_UNICODE : VC_XLATE; + vt_reset_unicode(vc->vc_num); vc->vt_mode.mode = VT_AUTO; vc->vt_mode.waitv = 0; vc->vt_mode.relsig = 0; @@ -1309,6 +1017,7 @@ void vc_SAK(struct work_struct *work) console_lock(); vc = vc_con->d; if (vc) { + /* FIXME: review tty ref counting */ tty = vc->port.tty; /* * SAK should also work in all raw modes and reset diff --git a/include/linux/kbd_kern.h b/include/linux/kbd_kern.h index ec2d17b..daf4a3a 100644 --- a/include/linux/kbd_kern.h +++ b/include/linux/kbd_kern.h @@ -7,8 +7,6 @@ extern struct tasklet_struct keyboard_tasklet; -extern int shift_state; - extern char *func_table[MAX_NR_FUNC]; extern char func_buf[]; extern char *funcbufptr; @@ -65,8 +63,6 @@ struct kbd_struct { #define VC_META 4 /* 0 - meta, 1 - meta=prefix with ESC */ }; -extern struct kbd_struct kbd_table[]; - extern int kbd_init(void); extern unsigned char getledstate(void); @@ -79,6 +75,7 @@ extern void (*kbd_ledfunc)(unsigned int led); extern int set_console(int nr); extern void schedule_console_callback(void); +/* FIXME: review locking for vt.c callers */ static inline void set_leds(void) { tasklet_schedule(&keyboard_tasklet); @@ -142,8 +139,6 @@ static inline void chg_vc_kbd_led(struct kbd_struct * kbd, int flag) struct console; -int getkeycode(unsigned int scancode); -int setkeycode(unsigned int scancode, unsigned int keycode); void compute_shiftstate(void); /* defkeymap.c */ diff --git a/include/linux/keyboard.h b/include/linux/keyboard.h index 33a63f6..86e5214 100644 --- a/include/linux/keyboard.h +++ b/include/linux/keyboard.h @@ -24,8 +24,6 @@ #ifdef __KERNEL__ struct notifier_block; -extern const int NR_TYPES; -extern const int max_vals[]; extern unsigned short *key_maps[MAX_NR_KEYMAPS]; extern unsigned short plain_map[NR_KEYS]; diff --git a/include/linux/vt_kern.h b/include/linux/vt_kern.h index 5d8726a..e33d77f 100644 --- a/include/linux/vt_kern.h +++ b/include/linux/vt_kern.h @@ -169,5 +169,28 @@ extern void hide_boot_cursor(bool hide); /* keyboard provided interfaces */ extern int vt_do_diacrit(unsigned int cmd, void __user *up, int eperm); +extern int vt_do_kdskbmode(int console, unsigned int arg); +extern int vt_do_kdskbmeta(int console, unsigned int arg); +extern int vt_do_kbkeycode_ioctl(int cmd, struct kbkeycode __user *user_kbkc, + int perm); +extern int vt_do_kdsk_ioctl(int cmd, struct kbentry __user *user_kbe, + int perm, int console); +extern int vt_do_kdgkb_ioctl(int cmd, struct kbsentry __user *user_kdgkb, + int perm); +extern int vt_do_kdskled(int console, int cmd, unsigned long arg, int perm); +extern int vt_do_kdgkbmode(int console); +extern int vt_do_kdgkbmeta(int console); +extern void vt_reset_unicode(int console); +extern int vt_get_shift_state(void); +extern void vt_reset_keyboard(int console); +extern int vt_get_leds(int console, int flag); +extern int vt_get_kbd_mode_bit(int console, int bit); +extern void vt_set_kbd_mode_bit(int console, int bit); +extern void vt_clr_kbd_mode_bit(int console, int bit); +extern void vt_set_led_state(int console, int leds); +extern void vt_set_led_state(int console, int leds); +extern void vt_kbd_con_start(int console); +extern void vt_kbd_con_stop(int console); + #endif /* _VT_KERN_H */ -- cgit v0.10.2 From a5f43138da9beddc46b00ec31d167143a7176683 Mon Sep 17 00:00:00 2001 From: "Cousson, Benoit" Date: Tue, 28 Feb 2012 18:22:12 +0100 Subject: tty: serial: OMAP: Fix oops due to NULL pdata in DT boot The following commit: be4b0281956c5cae4f63f31f11d07625a6988766 (tty: serial: OMAP: block idle while the UART is transferring data in PIO mode), is introducing an oops if OMAP is booted using device tree blob because the pdata will not be initialized. Check if pdata is set before de-referencing it. Signed-off-by: Benoit Cousson Reviewed-by: Paul Walmsley Cc: stable Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c index f809041..0121486 100644 --- a/drivers/tty/serial/omap-serial.c +++ b/drivers/tty/serial/omap-serial.c @@ -159,7 +159,7 @@ static void serial_omap_stop_tx(struct uart_port *port) serial_out(up, UART_IER, up->ier); } - if (!up->use_dma && pdata->set_forceidle) + if (!up->use_dma && pdata && pdata->set_forceidle) pdata->set_forceidle(up->pdev); pm_runtime_mark_last_busy(&up->pdev->dev); @@ -298,7 +298,7 @@ static void serial_omap_start_tx(struct uart_port *port) if (!up->use_dma) { pm_runtime_get_sync(&up->pdev->dev); serial_omap_enable_ier_thri(up); - if (pdata->set_noidle) + if (pdata && pdata->set_noidle) pdata->set_noidle(up->pdev); pm_runtime_mark_last_busy(&up->pdev->dev); pm_runtime_put_autosuspend(&up->pdev->dev); @@ -1613,7 +1613,7 @@ static int serial_omap_runtime_resume(struct device *dev) struct uart_omap_port *up = dev_get_drvdata(dev); struct omap_uart_port_info *pdata = dev->platform_data; - if (up) { + if (up && pdata) { if (pdata->get_context_loss_count) { u32 loss_cnt = pdata->get_context_loss_count(dev); -- cgit v0.10.2 From dbca36eab48ee48dfc60b8f41ffad54160ebdd09 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Mon, 5 Mar 2012 21:07:11 +0300 Subject: tty: cyclades: TIOCSERGETLSR should should store to a uint TIOCSERGETLSR should be saved in a uint so the cast here to unsigned long is a bug. Reported-by: Jiri Slaby Signed-off-by: Dan Carpenter Acked-by: Jiri Slaby Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/cyclades.c b/drivers/tty/cyclades.c index c9bf779..5575fee 100644 --- a/drivers/tty/cyclades.c +++ b/drivers/tty/cyclades.c @@ -2413,7 +2413,7 @@ static int get_lsr_info(struct cyclades_port *info, unsigned int __user *value) /* Not supported yet */ return -EINVAL; } - return put_user(result, (unsigned long __user *)value); + return put_user(result, value); } static int cy_tiocmget(struct tty_struct *tty) -- cgit v0.10.2 From edab558feba1e2826ae8d65506168d7ccea7aad9 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Fri, 2 Mar 2012 14:59:08 +0000 Subject: vt: sort out locking for font handling The font methods are console_lock covered. Unfortunately they don't extend the lock over all the needed tests. Signed-off-by: Alan Cox Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index ecdcc8a..ce2b823 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -3969,9 +3969,6 @@ static int con_font_get(struct vc_data *vc, struct console_font_op *op) int rc = -EINVAL; int c; - if (vc->vc_mode != KD_TEXT) - return -EINVAL; - if (op->data) { font.data = kmalloc(max_font_size, GFP_KERNEL); if (!font.data) @@ -3980,7 +3977,9 @@ static int con_font_get(struct vc_data *vc, struct console_font_op *op) font.data = NULL; console_lock(); - if (vc->vc_sw->con_font_get) + if (vc->vc_mode != KD_TEXT) + rc = -EINVAL; + else if (vc->vc_sw->con_font_get) rc = vc->vc_sw->con_font_get(vc, &font); else rc = -ENOSYS; @@ -4062,7 +4061,9 @@ static int con_font_set(struct vc_data *vc, struct console_font_op *op) if (IS_ERR(font.data)) return PTR_ERR(font.data); console_lock(); - if (vc->vc_sw->con_font_set) + if (vc->vc_mode != KD_TEXT) + rc = -EINVAL; + else if (vc->vc_sw->con_font_set) rc = vc->vc_sw->con_font_set(vc, &font, op->flags); else rc = -ENOSYS; @@ -4078,8 +4079,6 @@ static int con_font_default(struct vc_data *vc, struct console_font_op *op) char *s = name; int rc; - if (vc->vc_mode != KD_TEXT) - return -EINVAL; if (!op->data) s = NULL; @@ -4089,6 +4088,10 @@ static int con_font_default(struct vc_data *vc, struct console_font_op *op) name[MAX_FONT_NAME - 1] = 0; console_lock(); + if (vc->vc_mode != KD_TEXT) { + console_unlock(); + return -EINVAL; + } if (vc->vc_sw->con_font_default) rc = vc->vc_sw->con_font_default(vc, &font, s); else @@ -4106,11 +4109,11 @@ static int con_font_copy(struct vc_data *vc, struct console_font_op *op) int con = op->height; int rc; - if (vc->vc_mode != KD_TEXT) - return -EINVAL; console_lock(); - if (!vc->vc_sw->con_font_copy) + if (vc->vc_mode != KD_TEXT) + rc = -EINVAL; + else if (!vc->vc_sw->con_font_copy) rc = -ENOSYS; else if (con < 0 || !vc_cons_allocated(con)) rc = -ENOTTY; -- cgit v0.10.2 From 4001d7b7fc271052ebff43f327c26dc64806bbdf Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Fri, 2 Mar 2012 14:59:20 +0000 Subject: vt: push down the tty lock so we can see what is left to tackle At this point we have the tty_lock guarding a couple of oddities, plus the translation and unimap still. We also extend the console_lock in a couple of spots where coverage is wrong and switch vcs_open to use the right lock ! [Fixed the locking issue Jiri reported] Signed-off-by: Alan Cox Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/vt/vc_screen.c b/drivers/tty/vt/vc_screen.c index 7a367ff..fa7268a 100644 --- a/drivers/tty/vt/vc_screen.c +++ b/drivers/tty/vt/vc_screen.c @@ -608,10 +608,10 @@ vcs_open(struct inode *inode, struct file *filp) unsigned int currcons = iminor(inode) & 127; int ret = 0; - tty_lock(); + console_lock(); if(currcons && !vc_cons_allocated(currcons-1)) ret = -ENXIO; - tty_unlock(); + console_unlock(); return ret; } diff --git a/drivers/tty/vt/vt_ioctl.c b/drivers/tty/vt/vt_ioctl.c index 28ca0aa..e05094d 100644 --- a/drivers/tty/vt/vt_ioctl.c +++ b/drivers/tty/vt/vt_ioctl.c @@ -281,7 +281,6 @@ int vt_ioctl(struct tty_struct *tty, console = vc->vc_num; - tty_lock(); if (!vc_cons_allocated(console)) { /* impossible? */ ret = -ENOIOCTLCMD; @@ -299,16 +298,18 @@ int vt_ioctl(struct tty_struct *tty, switch (cmd) { case TIOCLINUX: + tty_lock(); ret = tioclinux(tty, arg); + tty_unlock(); break; case KIOCSOUND: if (!perm) - goto eperm; + return -EPERM; /* * The use of PIT_TICK_RATE is historic, it used to be * the platform-dependent CLOCK_TICK_RATE between 2.6.12 * and 2.6.36, which was a minor but unfortunate ABI - * change. + * change. kd_mksound is locked by the input layer. */ if (arg) arg = PIT_TICK_RATE / arg; @@ -317,7 +318,7 @@ int vt_ioctl(struct tty_struct *tty, case KDMKTONE: if (!perm) - goto eperm; + return -EPERM; { unsigned int ticks, count; @@ -335,7 +336,7 @@ int vt_ioctl(struct tty_struct *tty, case KDGKBTYPE: /* - * this is naive. + * this is naïve. */ ucval = KB_101; ret = put_user(ucval, (char __user *)arg); @@ -353,6 +354,8 @@ int vt_ioctl(struct tty_struct *tty, /* * KDADDIO and KDDELIO may be able to add ports beyond what * we reject here, but to be safe... + * + * These are locked internally via sys_ioperm */ if (arg < GPFIRST || arg > GPLAST) { ret = -EINVAL; @@ -375,7 +378,7 @@ int vt_ioctl(struct tty_struct *tty, struct kbd_repeat kbrep; if (!capable(CAP_SYS_TTY_CONFIG)) - goto eperm; + return -EPERM; if (copy_from_user(&kbrep, up, sizeof(struct kbd_repeat))) { ret = -EFAULT; @@ -399,7 +402,7 @@ int vt_ioctl(struct tty_struct *tty, * need to restore their engine state. --BenH */ if (!perm) - goto eperm; + return -EPERM; switch (arg) { case KD_GRAPHICS: break; @@ -412,6 +415,7 @@ int vt_ioctl(struct tty_struct *tty, ret = -EINVAL; goto out; } + /* FIXME: this needs the console lock extending */ if (vc->vc_mode == (unsigned char) arg) break; vc->vc_mode = (unsigned char) arg; @@ -443,7 +447,7 @@ int vt_ioctl(struct tty_struct *tty, case KDSKBMODE: if (!perm) - goto eperm; + return -EPERM; ret = vt_do_kdskbmode(console, arg); if (ret == 0) tty_ldisc_flush(tty); @@ -512,7 +516,7 @@ int vt_ioctl(struct tty_struct *tty, case KDSIGACCEPT: { if (!perm || !capable(CAP_KILL)) - goto eperm; + return -EPERM; if (!valid_signal(arg) || arg < 1 || arg == SIGKILL) ret = -EINVAL; else { @@ -530,7 +534,7 @@ int vt_ioctl(struct tty_struct *tty, struct vt_mode tmp; if (!perm) - goto eperm; + return -EPERM; if (copy_from_user(&tmp, up, sizeof(struct vt_mode))) { ret = -EFAULT; goto out; @@ -576,6 +580,7 @@ int vt_ioctl(struct tty_struct *tty, struct vt_stat __user *vtstat = up; unsigned short state, mask; + /* Review: FIXME: Console lock ? */ if (put_user(fg_console + 1, &vtstat->v_active)) ret = -EFAULT; else { @@ -593,6 +598,7 @@ int vt_ioctl(struct tty_struct *tty, * Returns the first available (non-opened) console. */ case VT_OPENQRY: + /* FIXME: locking ? - but then this is a stupid API */ for (i = 0; i < MAX_NR_CONSOLES; ++i) if (! VT_IS_IN_USE(i)) break; @@ -606,7 +612,7 @@ int vt_ioctl(struct tty_struct *tty, */ case VT_ACTIVATE: if (!perm) - goto eperm; + return -EPERM; if (arg == 0 || arg > MAX_NR_CONSOLES) ret = -ENXIO; else { @@ -625,7 +631,7 @@ int vt_ioctl(struct tty_struct *tty, struct vt_setactivate vsa; if (!perm) - goto eperm; + return -EPERM; if (copy_from_user(&vsa, (struct vt_setactivate __user *)arg, sizeof(struct vt_setactivate))) { @@ -653,6 +659,7 @@ int vt_ioctl(struct tty_struct *tty, if (ret) break; /* Commence switch and lock */ + /* Review set_console locks */ set_console(vsa.console); } break; @@ -663,11 +670,14 @@ int vt_ioctl(struct tty_struct *tty, */ case VT_WAITACTIVE: if (!perm) - goto eperm; + return -EPERM; if (arg == 0 || arg > MAX_NR_CONSOLES) ret = -ENXIO; - else + else { + tty_lock(); ret = vt_waitactive(arg); + tty_unlock(); + } break; /* @@ -682,16 +692,17 @@ int vt_ioctl(struct tty_struct *tty, */ case VT_RELDISP: if (!perm) - goto eperm; + return -EPERM; + console_lock(); if (vc->vt_mode.mode != VT_PROCESS) { + console_unlock(); ret = -EINVAL; break; } /* * Switching-from response */ - console_lock(); if (vc->vt_newvt >= 0) { if (arg == 0) /* @@ -768,7 +779,7 @@ int vt_ioctl(struct tty_struct *tty, ushort ll,cc; if (!perm) - goto eperm; + return -EPERM; if (get_user(ll, &vtsizes->v_rows) || get_user(cc, &vtsizes->v_cols)) ret = -EFAULT; @@ -779,6 +790,7 @@ int vt_ioctl(struct tty_struct *tty, if (vc) { vc->vc_resize_user = 1; + /* FIXME: review v tty lock */ vc_resize(vc_cons[i].d, cc, ll); } } @@ -792,7 +804,7 @@ int vt_ioctl(struct tty_struct *tty, struct vt_consize __user *vtconsize = up; ushort ll,cc,vlin,clin,vcol,ccol; if (!perm) - goto eperm; + return -EPERM; if (!access_ok(VERIFY_READ, vtconsize, sizeof(struct vt_consize))) { ret = -EFAULT; @@ -848,7 +860,7 @@ int vt_ioctl(struct tty_struct *tty, case PIO_FONT: { if (!perm) - goto eperm; + return -EPERM; op.op = KD_FONT_OP_SET; op.flags = KD_FONT_FLAG_OLD | KD_FONT_FLAG_DONT_RECALC; /* Compatibility */ op.width = 8; @@ -889,7 +901,7 @@ int vt_ioctl(struct tty_struct *tty, case PIO_FONTRESET: { if (!perm) - goto eperm; + return -EPERM; #ifdef BROKEN_GRAPHICS_PROGRAMS /* With BROKEN_GRAPHICS_PROGRAMS defined, the default @@ -915,7 +927,7 @@ int vt_ioctl(struct tty_struct *tty, break; } if (!perm && op.op != KD_FONT_OP_GET) - goto eperm; + return -EPERM; ret = con_font_op(vc, &op); if (ret) break; @@ -927,50 +939,65 @@ int vt_ioctl(struct tty_struct *tty, case PIO_SCRNMAP: if (!perm) ret = -EPERM; - else + else { + tty_lock(); ret = con_set_trans_old(up); + tty_unlock(); + } break; case GIO_SCRNMAP: + tty_lock(); ret = con_get_trans_old(up); + tty_unlock(); break; case PIO_UNISCRNMAP: if (!perm) ret = -EPERM; - else + else { + tty_lock(); ret = con_set_trans_new(up); + tty_unlock(); + } break; case GIO_UNISCRNMAP: + tty_lock(); ret = con_get_trans_new(up); + tty_unlock(); break; case PIO_UNIMAPCLR: { struct unimapinit ui; if (!perm) - goto eperm; + return -EPERM; ret = copy_from_user(&ui, up, sizeof(struct unimapinit)); if (ret) ret = -EFAULT; - else + else { + tty_lock(); con_clear_unimap(vc, &ui); + tty_unlock(); + } break; } case PIO_UNIMAP: case GIO_UNIMAP: + tty_lock(); ret = do_unimap_ioctl(cmd, up, perm, vc); + tty_unlock(); break; case VT_LOCKSWITCH: if (!capable(CAP_SYS_TTY_CONFIG)) - goto eperm; + return -EPERM; vt_dont_switch = 1; break; case VT_UNLOCKSWITCH: if (!capable(CAP_SYS_TTY_CONFIG)) - goto eperm; + return -EPERM; vt_dont_switch = 0; break; case VT_GETHIFONTMASK: @@ -984,11 +1011,7 @@ int vt_ioctl(struct tty_struct *tty, ret = -ENOIOCTLCMD; } out: - tty_unlock(); return ret; -eperm: - ret = -EPERM; - goto out; } void reset_vc(struct vc_data *vc) @@ -1150,8 +1173,6 @@ long vt_compat_ioctl(struct tty_struct *tty, console = vc->vc_num; - tty_lock(); - if (!vc_cons_allocated(console)) { /* impossible? */ ret = -ENOIOCTLCMD; goto out; @@ -1180,7 +1201,9 @@ long vt_compat_ioctl(struct tty_struct *tty, case PIO_UNIMAP: case GIO_UNIMAP: + tty_lock(); ret = compat_unimap_ioctl(cmd, up, perm, vc); + tty_unlock(); break; /* @@ -1217,11 +1240,9 @@ long vt_compat_ioctl(struct tty_struct *tty, goto fallback; } out: - tty_unlock(); return ret; fallback: - tty_unlock(); return vt_ioctl(tty, cmd, arg); } @@ -1407,6 +1428,7 @@ int vt_move_to_console(unsigned int vt, int alloc) return -EIO; } console_unlock(); + /* Review: I don't see why we need tty_lock here FIXME */ tty_lock(); if (vt_waitactive(vt + 1)) { pr_debug("Suspend: Can't switch VCs."); -- cgit v0.10.2 From 20f62579dccc84428554b914e24a312a6554f841 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Fri, 2 Mar 2012 14:59:37 +0000 Subject: vt: push down tioclinux cases Some of this ventures into selection which is still a complete lost cause. We are not making it any worse. It's completely busted anyway. Signed-off-by: Alan Cox Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/vt/selection.c b/drivers/tty/vt/selection.c index 738e45a..2a50916 100644 --- a/drivers/tty/vt/selection.c +++ b/drivers/tty/vt/selection.c @@ -75,7 +75,7 @@ clear_selection(void) { /* * User settable table: what characters are to be considered alphabetic? - * 256 bits + * 256 bits. FIXME: Needs a locking model. */ static u32 inwordLut[8]={ 0x00000000, /* control chars */ @@ -307,7 +307,8 @@ int set_selection(const struct tiocl_selection __user *sel, struct tty_struct *t * queue of the tty associated with the current console. * Invoked by ioctl(). * - * Locking: always called with BTM from vt_ioctl + * Locking: called without locks. Calls the ldisc wrongly with + * unsafe methods, */ int paste_selection(struct tty_struct *tty) { @@ -322,13 +323,12 @@ int paste_selection(struct tty_struct *tty) poke_blanked_console(); console_unlock(); + /* FIXME: wtf is this supposed to achieve ? */ ld = tty_ldisc_ref(tty); - if (!ld) { - tty_unlock(); + if (!ld) ld = tty_ldisc_ref_wait(tty); - tty_lock(); - } + /* FIXME: this is completely unsafe */ add_wait_queue(&vc->paste_wait, &wait); while (sel_buffer && sel_buffer_lth > pasted) { set_current_state(TASK_INTERRUPTIBLE); diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index ce2b823..ab7385e 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -2637,11 +2637,15 @@ int tioclinux(struct tty_struct *tty, unsigned long arg) ret = __put_user(data, p); break; case TIOCL_GETMOUSEREPORTING: + console_lock(); /* May be overkill */ data = mouse_reporting(); + console_unlock(); ret = __put_user(data, p); break; case TIOCL_SETVESABLANK: + console_lock(); ret = set_vesa_blanking(p); + console_unlock(); break; case TIOCL_GETKMSGREDIRECT: data = vt_get_kmsg_redirect(); @@ -2658,13 +2662,21 @@ int tioclinux(struct tty_struct *tty, unsigned long arg) } break; case TIOCL_GETFGCONSOLE: + /* No locking needed as this is a transiently + correct return anyway if the caller hasn't + disabled switching */ ret = fg_console; break; case TIOCL_SCROLLCONSOLE: if (get_user(lines, (s32 __user *)(p+4))) { ret = -EFAULT; } else { + /* Need the console lock here. Note that lots + of other calls need fixing before the lock + is actually useful ! */ + console_lock(); scrollfront(vc_cons[fg_console].d, lines); + console_unlock(); ret = 0; } break; diff --git a/drivers/tty/vt/vt_ioctl.c b/drivers/tty/vt/vt_ioctl.c index e05094d..c6720be 100644 --- a/drivers/tty/vt/vt_ioctl.c +++ b/drivers/tty/vt/vt_ioctl.c @@ -298,9 +298,7 @@ int vt_ioctl(struct tty_struct *tty, switch (cmd) { case TIOCLINUX: - tty_lock(); ret = tioclinux(tty, arg); - tty_unlock(); break; case KIOCSOUND: if (!perm) -- cgit v0.10.2 From 99cceb4e50cb67720e779f6611476bcb611af6b8 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Fri, 2 Mar 2012 14:59:49 +0000 Subject: vt: waitevent is self locked so drop the tty_lock Signed-off-by: Alan Cox Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/vt/vt_ioctl.c b/drivers/tty/vt/vt_ioctl.c index c6720be..ede2ef1 100644 --- a/drivers/tty/vt/vt_ioctl.c +++ b/drivers/tty/vt/vt_ioctl.c @@ -130,7 +130,7 @@ static void vt_event_wait(struct vt_event_wait *vw) list_add(&vw->list, &vt_events); spin_unlock_irqrestore(&vt_event_lock, flags); /* Wait for it to pass */ - wait_event_interruptible_tty(vt_event_waitqueue, vw->done); + wait_event_interruptible(vt_event_waitqueue, vw->done); /* Dequeue it */ spin_lock_irqsave(&vt_event_lock, flags); list_del(&vw->list); @@ -671,11 +671,8 @@ int vt_ioctl(struct tty_struct *tty, return -EPERM; if (arg == 0 || arg > MAX_NR_CONSOLES) ret = -ENXIO; - else { - tty_lock(); + else ret = vt_waitactive(arg); - tty_unlock(); - } break; /* @@ -1426,14 +1423,10 @@ int vt_move_to_console(unsigned int vt, int alloc) return -EIO; } console_unlock(); - /* Review: I don't see why we need tty_lock here FIXME */ - tty_lock(); if (vt_waitactive(vt + 1)) { pr_debug("Suspend: Can't switch VCs."); - tty_unlock(); return -EINTR; } - tty_unlock(); return prev; } -- cgit v0.10.2 From 5289475d1375017ab4288b276383e9684280876d Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Fri, 2 Mar 2012 15:00:02 +0000 Subject: vt: tackle the main part of the selection logic We leave the existing paste mess alone and just fix up the vt side of things. Signed-off-by: Alan Cox Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/vt/selection.c b/drivers/tty/vt/selection.c index 2a50916..8e9b4be 100644 --- a/drivers/tty/vt/selection.c +++ b/drivers/tty/vt/selection.c @@ -62,10 +62,14 @@ sel_pos(int n) use_unicode); } -/* remove the current selection highlight, if any, - from the console holding the selection. */ -void -clear_selection(void) { +/** + * clear_selection - remove current selection + * + * Remove the current selection highlight, if any from the console + * holding the selection. The caller must hold the console lock. + */ +void clear_selection(void) +{ highlight_pointer(-1); /* hide the pointer */ if (sel_start != -1) { highlight(sel_start, sel_end); @@ -75,7 +79,7 @@ clear_selection(void) { /* * User settable table: what characters are to be considered alphabetic? - * 256 bits. FIXME: Needs a locking model. + * 256 bits. Locked by the console lock. */ static u32 inwordLut[8]={ 0x00000000, /* control chars */ @@ -92,10 +96,20 @@ static inline int inword(const u16 c) { return c > 0xff || (( inwordLut[c>>5] >> (c & 0x1F) ) & 1); } -/* set inwordLut contents. Invoked by ioctl(). */ +/** + * set loadlut - load the LUT table + * @p: user table + * + * Load the LUT table from user space. The caller must hold the console + * lock. Make a temporary copy so a partial update doesn't make a mess. + */ int sel_loadlut(char __user *p) { - return copy_from_user(inwordLut, (u32 __user *)(p+4), 32) ? -EFAULT : 0; + u32 tmplut[8]; + if (copy_from_user(tmplut, (u32 __user *)(p+4), 32)) + return -EFAULT; + memcpy(inwordLut, tmplut, 32); + return 0; } /* does screen address p correspond to character at LH/RH edge of screen? */ @@ -131,7 +145,16 @@ static int store_utf8(u16 c, char *p) } } -/* set the current selection. Invoked by ioctl() or by kernel code. */ +/** + * set_selection - set the current selection. + * @sel: user selection info + * @tty: the console tty + * + * Invoked by the ioctl handle for the vt layer. + * + * The entire selection process is managed under the console_lock. It's + * a lot under the lock but its hardly a performance path + */ int set_selection(const struct tiocl_selection __user *sel, struct tty_struct *tty) { struct vc_data *vc = vc_cons[fg_console].d; diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index ab7385e..e5abcea 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -2623,7 +2623,9 @@ int tioclinux(struct tty_struct *tty, unsigned long arg) console_unlock(); break; case TIOCL_SELLOADLUT: + console_lock(); ret = sel_loadlut(p); + console_unlock(); break; case TIOCL_GETSHIFTSTATE: -- cgit v0.10.2 From f8a8c10f4a662dcf3cb621d7a3eba564c5963284 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 5 Mar 2012 14:51:48 +0100 Subject: USB: cdc-acm, use tty_standard_install This is a piece I missed the last time. Do not copy the functionality all over the tree. Instead, use the helper the tty layer provides us with. Signed-off-by: Jiri Slaby Acked-by: Oliver Neukum Acked-by: Alan Cox Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index 9543b19..11a1130 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -508,17 +508,12 @@ static int acm_tty_install(struct tty_driver *driver, struct tty_struct *tty) if (!acm) return -ENODEV; - retval = tty_init_termios(tty); + retval = tty_standard_install(driver, tty); if (retval) goto error_init_termios; tty->driver_data = acm; - /* Final install (we use the default method) */ - tty_driver_kref_get(driver); - tty->count++; - driver->ttys[tty->index] = tty; - return 0; error_init_termios: -- cgit v0.10.2 From a8fbc974c347a798fd0c6f0bffe7bf46b8c6dfb6 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 5 Mar 2012 14:51:49 +0100 Subject: TTY: tty_io, remove buffer re-assignments TTY buffer head and tail are initialized in tty_buffer_init. No need to do it once again in initialize_tty_struct where tty_buffer_init is called. Signed-off-by: Jiri Slaby Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index 44736f9..f105ce5 100644 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c @@ -2933,7 +2933,6 @@ void initialize_tty_struct(struct tty_struct *tty, tty->session = NULL; tty->pgrp = NULL; tty->overrun_time = jiffies; - tty->buf.head = tty->buf.tail = NULL; tty_buffer_init(tty); mutex_init(&tty->termios_mutex); mutex_init(&tty->ldisc_mutex); -- cgit v0.10.2 From 1a54a76d5171f3ffd89eb69f6f38d535724e3d05 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 5 Mar 2012 14:51:50 +0100 Subject: TTY: let alloc_tty_driver deduce the owner automatically Like the rest of the kernel, make a stub from alloc_tty_driver which calls __alloc_tty_driver with proper owner. This will save us one more assignment on the driver side. Also this fixes some drivers which didn't set the owner. This allowed user to remove the module from the system even though a tty from the driver is still open. Signed-off-by: Jiri Slaby Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index f105ce5..bd95cea 100644 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c @@ -3049,7 +3049,7 @@ void tty_unregister_device(struct tty_driver *driver, unsigned index) } EXPORT_SYMBOL(tty_unregister_device); -struct tty_driver *alloc_tty_driver(int lines) +struct tty_driver *__alloc_tty_driver(int lines, struct module *owner) { struct tty_driver *driver; @@ -3058,11 +3058,12 @@ struct tty_driver *alloc_tty_driver(int lines) kref_init(&driver->kref); driver->magic = TTY_DRIVER_MAGIC; driver->num = lines; + driver->owner = owner; /* later we'll move allocation of tables here */ } return driver; } -EXPORT_SYMBOL(alloc_tty_driver); +EXPORT_SYMBOL(__alloc_tty_driver); static void destruct_tty_driver(struct kref *kref) { diff --git a/include/linux/tty_driver.h b/include/linux/tty_driver.h index 5cf6850..6e65493 100644 --- a/include/linux/tty_driver.h +++ b/include/linux/tty_driver.h @@ -234,6 +234,7 @@ * if provided (otherwise EINVAL will be returned). */ +#include #include #include #include @@ -324,7 +325,7 @@ struct tty_driver { extern struct list_head tty_drivers; -extern struct tty_driver *alloc_tty_driver(int lines); +extern struct tty_driver *__alloc_tty_driver(int lines, struct module *owner); extern void put_tty_driver(struct tty_driver *driver); extern void tty_set_operations(struct tty_driver *driver, const struct tty_operations *op); @@ -332,6 +333,8 @@ extern struct tty_driver *tty_find_polling_driver(char *name, int *line); extern void tty_driver_kref_put(struct tty_driver *driver); +#define alloc_tty_driver(lines) __alloc_tty_driver(lines, THIS_MODULE) + static inline struct tty_driver *tty_driver_kref_get(struct tty_driver *d) { kref_get(&d->kref); -- cgit v0.10.2 From 87cab16beb882d3f9e61a2c0184fa7cf76de1f90 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 5 Mar 2012 14:51:51 +0100 Subject: TTY: remove minor_num from tty_driver It was added back in 2004 and never used for anything real. Remove the only assignment in the tree as well. Signed-off-by: Jiri Slaby Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/misc/pti.c b/drivers/misc/pti.c index 471ff4c..9a35db3 100644 --- a/drivers/misc/pti.c +++ b/drivers/misc/pti.c @@ -920,7 +920,6 @@ static int __init pti_init(void) pti_tty_driver->name = TTYNAME; pti_tty_driver->major = 0; pti_tty_driver->minor_start = PTITTY_MINOR_START; - pti_tty_driver->minor_num = PTITTY_MINOR_NUM; pti_tty_driver->num = PTITTY_MINOR_NUM; pti_tty_driver->type = TTY_DRIVER_TYPE_SYSTEM; pti_tty_driver->subtype = SYSTEM_TYPE_SYSCONS; diff --git a/include/linux/tty_driver.h b/include/linux/tty_driver.h index 6e65493..e064f17 100644 --- a/include/linux/tty_driver.h +++ b/include/linux/tty_driver.h @@ -299,7 +299,6 @@ struct tty_driver { int name_base; /* offset of printed name */ int major; /* major device number */ int minor_start; /* start of minor device number */ - int minor_num; /* number of *possible* devices */ int num; /* number of devices allocated */ short type; /* type of tty driver */ short subtype; /* subtype of tty driver */ -- cgit v0.10.2 From 2f16669d322e05171c9e1cfd94f402f7399bd2a3 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 5 Mar 2012 14:51:52 +0100 Subject: TTY: remove re-assignments to tty_driver members All num, magic and owner are set by alloc_tty_driver. No need to re-set them on each allocation site. pti driver sets something different to what it passes to alloc_tty_driver. It is not a bug, since we don't use the lines parameter in any way. Anyway this is fixed, and now we do the right thing. Signed-off-by: Jiri Slaby Acked-by: Tilman Schmidt Signed-off-by: Greg Kroah-Hartman diff --git a/arch/ia64/hp/sim/simserial.c b/arch/ia64/hp/sim/simserial.c index bff0824..f513dc0 100644 --- a/arch/ia64/hp/sim/simserial.c +++ b/arch/ia64/hp/sim/simserial.c @@ -928,7 +928,6 @@ simrs_init (void) /* Initialize the tty_driver structure */ - hp_simserial_driver->owner = THIS_MODULE; hp_simserial_driver->driver_name = "simserial"; hp_simserial_driver->name = "ttyS"; hp_simserial_driver->major = TTY_MAJOR; diff --git a/arch/m68k/emu/nfcon.c b/arch/m68k/emu/nfcon.c index ab20dc0..8db25e8 100644 --- a/arch/m68k/emu/nfcon.c +++ b/arch/m68k/emu/nfcon.c @@ -127,7 +127,6 @@ static int __init nfcon_init(void) if (!nfcon_tty_driver) return -ENOMEM; - nfcon_tty_driver->owner = THIS_MODULE; nfcon_tty_driver->driver_name = "nfcon"; nfcon_tty_driver->name = "nfcon"; nfcon_tty_driver->type = TTY_DRIVER_TYPE_SYSTEM; diff --git a/arch/xtensa/platforms/iss/console.c b/arch/xtensa/platforms/iss/console.c index 2c723e8..247e9d4 100644 --- a/arch/xtensa/platforms/iss/console.c +++ b/arch/xtensa/platforms/iss/console.c @@ -216,7 +216,6 @@ int __init rs_init(void) /* Initialize the tty_driver structure */ - serial_driver->owner = THIS_MODULE; serial_driver->driver_name = "iss_serial"; serial_driver->name = "ttyS"; serial_driver->major = TTY_MAJOR; diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c index 07f6a5a..c3bcb12 100644 --- a/drivers/char/pcmcia/synclink_cs.c +++ b/drivers/char/pcmcia/synclink_cs.c @@ -2836,7 +2836,6 @@ static int __init synclink_cs_init(void) /* Initialize the tty_driver structure */ - serial_driver->owner = THIS_MODULE; serial_driver->driver_name = "synclink_cs"; serial_driver->name = "ttySLP"; serial_driver->major = ttymajor; diff --git a/drivers/char/ttyprintk.c b/drivers/char/ttyprintk.c index eedd547..46b77ed 100644 --- a/drivers/char/ttyprintk.c +++ b/drivers/char/ttyprintk.c @@ -184,12 +184,10 @@ static int __init ttyprintk_init(void) if (!ttyprintk_driver) return ret; - ttyprintk_driver->owner = THIS_MODULE; ttyprintk_driver->driver_name = "ttyprintk"; ttyprintk_driver->name = "ttyprintk"; ttyprintk_driver->major = TTYAUX_MAJOR; ttyprintk_driver->minor_start = 3; - ttyprintk_driver->num = 1; ttyprintk_driver->type = TTY_DRIVER_TYPE_CONSOLE; ttyprintk_driver->init_termios = tty_std_termios; ttyprintk_driver->init_termios.c_oflag = OPOST | OCRNL | ONOCR | ONLRET; diff --git a/drivers/isdn/capi/capi.c b/drivers/isdn/capi/capi.c index 94948be..baf08eb 100644 --- a/drivers/isdn/capi/capi.c +++ b/drivers/isdn/capi/capi.c @@ -1287,7 +1287,6 @@ static int __init capinc_tty_init(void) kfree(capiminors); return -ENOMEM; } - drv->owner = THIS_MODULE; drv->driver_name = "capi_nc"; drv->name = "capi"; drv->major = 0; diff --git a/drivers/isdn/gigaset/interface.c b/drivers/isdn/gigaset/interface.c index ee0a549..648260b 100644 --- a/drivers/isdn/gigaset/interface.c +++ b/drivers/isdn/gigaset/interface.c @@ -669,17 +669,15 @@ EXPORT_SYMBOL_GPL(gigaset_if_receive); void gigaset_if_initdriver(struct gigaset_driver *drv, const char *procname, const char *devname) { - unsigned minors = drv->minors; int ret; struct tty_driver *tty; drv->have_tty = 0; - drv->tty = tty = alloc_tty_driver(minors); + drv->tty = tty = alloc_tty_driver(drv->minors); if (tty == NULL) goto enomem; - tty->magic = TTY_DRIVER_MAGIC, tty->type = TTY_DRIVER_TYPE_SERIAL, tty->subtype = SERIAL_TYPE_NORMAL, tty->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; @@ -687,9 +685,6 @@ void gigaset_if_initdriver(struct gigaset_driver *drv, const char *procname, tty->driver_name = procname; tty->name = devname; tty->minor_start = drv->minor; - tty->num = drv->minors; - - tty->owner = THIS_MODULE; tty->init_termios = tty_std_termios; tty->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; diff --git a/drivers/misc/pti.c b/drivers/misc/pti.c index 9a35db3..383133b 100644 --- a/drivers/misc/pti.c +++ b/drivers/misc/pti.c @@ -907,20 +907,17 @@ static int __init pti_init(void) /* First register module as tty device */ - pti_tty_driver = alloc_tty_driver(1); + pti_tty_driver = alloc_tty_driver(PTITTY_MINOR_NUM); if (pti_tty_driver == NULL) { pr_err("%s(%d): Memory allocation failed for ptiTTY driver\n", __func__, __LINE__); return -ENOMEM; } - pti_tty_driver->owner = THIS_MODULE; - pti_tty_driver->magic = TTY_DRIVER_MAGIC; pti_tty_driver->driver_name = DRIVERNAME; pti_tty_driver->name = TTYNAME; pti_tty_driver->major = 0; pti_tty_driver->minor_start = PTITTY_MINOR_START; - pti_tty_driver->num = PTITTY_MINOR_NUM; pti_tty_driver->type = TTY_DRIVER_TYPE_SYSTEM; pti_tty_driver->subtype = SYSTEM_TYPE_SYSCONS; pti_tty_driver->flags = TTY_DRIVER_REAL_RAW | diff --git a/drivers/mmc/card/sdio_uart.c b/drivers/mmc/card/sdio_uart.c index bd4a67c..5a2cbfa 100644 --- a/drivers/mmc/card/sdio_uart.c +++ b/drivers/mmc/card/sdio_uart.c @@ -1175,7 +1175,6 @@ static int __init sdio_uart_init(void) if (!tty_drv) return -ENOMEM; - tty_drv->owner = THIS_MODULE; tty_drv->driver_name = "sdio_uart"; tty_drv->name = "ttySDIO"; tty_drv->major = 0; /* dynamically allocated */ diff --git a/drivers/net/usb/hso.c b/drivers/net/usb/hso.c index 304fe78..a73090f4 100644 --- a/drivers/net/usb/hso.c +++ b/drivers/net/usb/hso.c @@ -3313,7 +3313,6 @@ static int __init hso_init(void) /* fill in all needed values */ tty_drv->magic = TTY_DRIVER_MAGIC; - tty_drv->owner = THIS_MODULE; tty_drv->driver_name = driver_name; tty_drv->name = tty_filename; @@ -3322,7 +3321,6 @@ static int __init hso_init(void) tty_drv->major = tty_major; tty_drv->minor_start = 0; - tty_drv->num = HSO_SERIAL_TTY_MINORS; tty_drv->type = TTY_DRIVER_TYPE_SERIAL; tty_drv->subtype = SERIAL_TYPE_NORMAL; tty_drv->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; diff --git a/drivers/s390/char/con3215.c b/drivers/s390/char/con3215.c index 934458a..fe916bf 100644 --- a/drivers/s390/char/con3215.c +++ b/drivers/s390/char/con3215.c @@ -1137,7 +1137,6 @@ static int __init tty3215_init(void) * proc_entry, set_termios, flush_buffer, set_ldisc, write_proc */ - driver->owner = THIS_MODULE; driver->driver_name = "tty3215"; driver->name = "ttyS"; driver->major = TTY_MAJOR; diff --git a/drivers/s390/char/sclp_tty.c b/drivers/s390/char/sclp_tty.c index a879c13..40a9d69 100644 --- a/drivers/s390/char/sclp_tty.c +++ b/drivers/s390/char/sclp_tty.c @@ -551,7 +551,6 @@ sclp_tty_init(void) return rc; } - driver->owner = THIS_MODULE; driver->driver_name = "sclp_line"; driver->name = "sclp_line"; driver->major = TTY_MAJOR; diff --git a/drivers/s390/char/sclp_vt220.c b/drivers/s390/char/sclp_vt220.c index 5d706e6..b635472 100644 --- a/drivers/s390/char/sclp_vt220.c +++ b/drivers/s390/char/sclp_vt220.c @@ -685,7 +685,6 @@ static int __init sclp_vt220_tty_init(void) if (rc) goto out_driver; - driver->owner = THIS_MODULE; driver->driver_name = SCLP_VT220_DRIVER_NAME; driver->name = SCLP_VT220_DEVICE_NAME; driver->major = SCLP_VT220_MAJOR; diff --git a/drivers/s390/char/tty3270.c b/drivers/s390/char/tty3270.c index 2db1482..b43445a 100644 --- a/drivers/s390/char/tty3270.c +++ b/drivers/s390/char/tty3270.c @@ -1784,7 +1784,6 @@ static int __init tty3270_init(void) * Entries in tty3270_driver that are NOT initialized: * proc_entry, set_termios, flush_buffer, set_ldisc, write_proc */ - driver->owner = THIS_MODULE; driver->driver_name = "ttyTUB"; driver->name = "ttyTUB"; driver->major = IBM_TTY3270_MAJOR; diff --git a/drivers/tty/amiserial.c b/drivers/tty/amiserial.c index b84c834..b42f00d 100644 --- a/drivers/tty/amiserial.c +++ b/drivers/tty/amiserial.c @@ -1974,7 +1974,6 @@ static int __init amiga_serial_probe(struct platform_device *pdev) /* Initialize the tty_driver structure */ - serial_driver->owner = THIS_MODULE; serial_driver->driver_name = "amiserial"; serial_driver->name = "ttyS"; serial_driver->major = TTY_MAJOR; diff --git a/drivers/tty/bfin_jtag_comm.c b/drivers/tty/bfin_jtag_comm.c index 3a99776..946f799 100644 --- a/drivers/tty/bfin_jtag_comm.c +++ b/drivers/tty/bfin_jtag_comm.c @@ -257,7 +257,6 @@ static int __init bfin_jc_init(void) if (!bfin_jc_driver) goto err_driver; - bfin_jc_driver->owner = THIS_MODULE; bfin_jc_driver->driver_name = DRV_NAME; bfin_jc_driver->name = DEV_NAME; bfin_jc_driver->type = TTY_DRIVER_TYPE_SERIAL; diff --git a/drivers/tty/cyclades.c b/drivers/tty/cyclades.c index 5575fee..bc7b5a5 100644 --- a/drivers/tty/cyclades.c +++ b/drivers/tty/cyclades.c @@ -4090,7 +4090,6 @@ static int __init cy_init(void) /* Initialize the tty_driver structure */ - cy_serial_driver->owner = THIS_MODULE; cy_serial_driver->driver_name = "cyclades"; cy_serial_driver->name = "ttyC"; cy_serial_driver->major = CYCLADES_MAJOR; diff --git a/drivers/tty/ehv_bytechan.c b/drivers/tty/ehv_bytechan.c index 1595dba..4813684 100644 --- a/drivers/tty/ehv_bytechan.c +++ b/drivers/tty/ehv_bytechan.c @@ -825,7 +825,6 @@ static int __init ehv_bc_init(void) goto error; } - ehv_bc_driver->owner = THIS_MODULE; ehv_bc_driver->driver_name = "ehv-bc"; ehv_bc_driver->name = ehv_bc_console.name; ehv_bc_driver->type = TTY_DRIVER_TYPE_CONSOLE; diff --git a/drivers/tty/hvc/hvc_console.c b/drivers/tty/hvc/hvc_console.c index b6b2d18..8880adf 100644 --- a/drivers/tty/hvc/hvc_console.c +++ b/drivers/tty/hvc/hvc_console.c @@ -917,7 +917,6 @@ static int hvc_init(void) goto out; } - drv->owner = THIS_MODULE; drv->driver_name = "hvc"; drv->name = "hvc"; drv->major = HVC_MAJOR; diff --git a/drivers/tty/hvc/hvcs.c b/drivers/tty/hvc/hvcs.c index df7e7a0..da0aa47 100644 --- a/drivers/tty/hvc/hvcs.c +++ b/drivers/tty/hvc/hvcs.c @@ -1499,8 +1499,6 @@ static int __devinit hvcs_initialize(void) goto index_fail; } - hvcs_tty_driver->owner = THIS_MODULE; - hvcs_tty_driver->driver_name = hvcs_driver_name; hvcs_tty_driver->name = hvcs_device_node; diff --git a/drivers/tty/hvc/hvsi.c b/drivers/tty/hvc/hvsi.c index 1b5f28b..60bc451 100644 --- a/drivers/tty/hvc/hvsi.c +++ b/drivers/tty/hvc/hvsi.c @@ -1088,7 +1088,6 @@ static int __init hvsi_init(void) if (!hvsi_driver) return -ENOMEM; - hvsi_driver->owner = THIS_MODULE; hvsi_driver->driver_name = "hvsi"; hvsi_driver->name = "hvsi"; hvsi_driver->major = HVSI_MAJOR; diff --git a/drivers/tty/ipwireless/tty.c b/drivers/tty/ipwireless/tty.c index ef92869..6990b3b 100644 --- a/drivers/tty/ipwireless/tty.c +++ b/drivers/tty/ipwireless/tty.c @@ -614,7 +614,6 @@ int ipwireless_tty_init(void) if (!ipw_tty_driver) return -ENOMEM; - ipw_tty_driver->owner = THIS_MODULE; ipw_tty_driver->driver_name = IPWIRELESS_PCCARD_NAME; ipw_tty_driver->name = "ttyIPWp"; ipw_tty_driver->major = 0; diff --git a/drivers/tty/isicom.c b/drivers/tty/isicom.c index e5c295a..b3a28b5 100644 --- a/drivers/tty/isicom.c +++ b/drivers/tty/isicom.c @@ -1678,7 +1678,6 @@ static int __init isicom_init(void) goto error; } - isicom_normal->owner = THIS_MODULE; isicom_normal->name = "ttyM"; isicom_normal->major = ISICOM_NMAJOR; isicom_normal->minor_start = 0; diff --git a/drivers/tty/moxa.c b/drivers/tty/moxa.c index d15a071..4a26323 100644 --- a/drivers/tty/moxa.c +++ b/drivers/tty/moxa.c @@ -1036,7 +1036,6 @@ static int __init moxa_init(void) if (!moxaDriver) return -ENOMEM; - moxaDriver->owner = THIS_MODULE; moxaDriver->name = "ttyMX"; moxaDriver->major = ttymajor; moxaDriver->minor_start = 0; diff --git a/drivers/tty/mxser.c b/drivers/tty/mxser.c index 8998d52..260d031 100644 --- a/drivers/tty/mxser.c +++ b/drivers/tty/mxser.c @@ -2658,12 +2658,9 @@ static int __init mxser_module_init(void) MXSER_VERSION); /* Initialize the tty_driver structure */ - mxvar_sdriver->owner = THIS_MODULE; - mxvar_sdriver->magic = TTY_DRIVER_MAGIC; mxvar_sdriver->name = "ttyMI"; mxvar_sdriver->major = ttymajor; mxvar_sdriver->minor_start = 0; - mxvar_sdriver->num = MXSER_PORTS + 1; mxvar_sdriver->type = TTY_DRIVER_TYPE_SERIAL; mxvar_sdriver->subtype = SERIAL_TYPE_NORMAL; mxvar_sdriver->init_termios = tty_std_termios; diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c index fc7bbba..c43b683 100644 --- a/drivers/tty/n_gsm.c +++ b/drivers/tty/n_gsm.c @@ -3120,7 +3120,6 @@ static int __init gsm_init(void) pr_err("gsm_init: tty allocation failed.\n"); return -EINVAL; } - gsm_tty_driver->owner = THIS_MODULE; gsm_tty_driver->driver_name = "gsmtty"; gsm_tty_driver->name = "gsmtty"; gsm_tty_driver->major = 0; /* Dynamic */ diff --git a/drivers/tty/nozomi.c b/drivers/tty/nozomi.c index 580da78..e7592f9 100644 --- a/drivers/tty/nozomi.c +++ b/drivers/tty/nozomi.c @@ -1916,7 +1916,6 @@ static __init int nozomi_init(void) if (!ntty_driver) return -ENOMEM; - ntty_driver->owner = THIS_MODULE; ntty_driver->driver_name = NOZOMI_NAME_TTY; ntty_driver->name = "noz"; ntty_driver->major = 0; diff --git a/drivers/tty/pty.c b/drivers/tty/pty.c index d505837..f96ecae 100644 --- a/drivers/tty/pty.c +++ b/drivers/tty/pty.c @@ -393,7 +393,6 @@ static void __init legacy_pty_init(void) if (!pty_slave_driver) panic("Couldn't allocate pty slave driver"); - pty_driver->owner = THIS_MODULE; pty_driver->driver_name = "pty_master"; pty_driver->name = "pty"; pty_driver->major = PTY_MASTER_MAJOR; @@ -411,7 +410,6 @@ static void __init legacy_pty_init(void) pty_driver->other = pty_slave_driver; tty_set_operations(pty_driver, &master_pty_ops_bsd); - pty_slave_driver->owner = THIS_MODULE; pty_slave_driver->driver_name = "pty_slave"; pty_slave_driver->name = "ttyp"; pty_slave_driver->major = PTY_SLAVE_MAJOR; @@ -671,7 +669,6 @@ static void __init unix98_pty_init(void) if (!pts_driver) panic("Couldn't allocate Unix98 pts driver"); - ptm_driver->owner = THIS_MODULE; ptm_driver->driver_name = "pty_master"; ptm_driver->name = "ptm"; ptm_driver->major = UNIX98_PTY_MASTER_MAJOR; @@ -690,7 +687,6 @@ static void __init unix98_pty_init(void) ptm_driver->other = pts_driver; tty_set_operations(ptm_driver, &ptm_unix98_ops); - pts_driver->owner = THIS_MODULE; pts_driver->driver_name = "pty_slave"; pts_driver->name = "pts"; pts_driver->major = UNIX98_PTY_SLAVE_MAJOR; diff --git a/drivers/tty/rocket.c b/drivers/tty/rocket.c index de88aa5..b088e1e 100644 --- a/drivers/tty/rocket.c +++ b/drivers/tty/rocket.c @@ -2277,7 +2277,6 @@ static int __init rp_init(void) * driver with the tty layer. */ - rocket_driver->owner = THIS_MODULE; rocket_driver->flags = TTY_DRIVER_DYNAMIC_DEV; rocket_driver->name = "ttyR"; rocket_driver->driver_name = "Comtrol RocketPort"; diff --git a/drivers/tty/serial/ifx6x60.c b/drivers/tty/serial/ifx6x60.c index 7e925e2..144cd39 100644 --- a/drivers/tty/serial/ifx6x60.c +++ b/drivers/tty/serial/ifx6x60.c @@ -1375,12 +1375,9 @@ static int __init ifx_spi_init(void) return -ENOMEM; } - tty_drv->magic = TTY_DRIVER_MAGIC; - tty_drv->owner = THIS_MODULE; tty_drv->driver_name = DRVNAME; tty_drv->name = TTYNAME; tty_drv->minor_start = IFX_SPI_TTY_ID; - tty_drv->num = 1; tty_drv->type = TTY_DRIVER_TYPE_SERIAL; tty_drv->subtype = SERIAL_TYPE_NORMAL; tty_drv->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; diff --git a/drivers/tty/serial/msm_smd_tty.c b/drivers/tty/serial/msm_smd_tty.c index 4f41dcd..b25e6ee 100644 --- a/drivers/tty/serial/msm_smd_tty.c +++ b/drivers/tty/serial/msm_smd_tty.c @@ -203,7 +203,6 @@ static int __init smd_tty_init(void) if (smd_tty_driver == 0) return -ENOMEM; - smd_tty_driver->owner = THIS_MODULE; smd_tty_driver->driver_name = "smd_tty_driver"; smd_tty_driver->name = "smd"; smd_tty_driver->major = 0; diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index 1305618..9c4c05b 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -2230,7 +2230,6 @@ int uart_register_driver(struct uart_driver *drv) drv->tty_driver = normal; - normal->owner = drv->owner; normal->driver_name = drv->driver_name; normal->name = drv->dev_name; normal->major = drv->major; diff --git a/drivers/tty/synclink.c b/drivers/tty/synclink.c index ff8017f..2b2988c 100644 --- a/drivers/tty/synclink.c +++ b/drivers/tty/synclink.c @@ -4333,7 +4333,6 @@ static int mgsl_init_tty(void) if (!serial_driver) return -ENOMEM; - serial_driver->owner = THIS_MODULE; serial_driver->driver_name = "synclink"; serial_driver->name = "ttySL"; serial_driver->major = ttymajor; diff --git a/drivers/tty/synclink_gt.c b/drivers/tty/synclink_gt.c index 18b48cd..a8b66be 100644 --- a/drivers/tty/synclink_gt.c +++ b/drivers/tty/synclink_gt.c @@ -3795,7 +3795,6 @@ static int __init slgt_init(void) /* Initialize the tty_driver structure */ - serial_driver->owner = THIS_MODULE; serial_driver->driver_name = tty_driver_name; serial_driver->name = tty_dev_prefix; serial_driver->major = ttymajor; diff --git a/drivers/tty/synclinkmp.c b/drivers/tty/synclinkmp.c index a7efe53..ddabb61 100644 --- a/drivers/tty/synclinkmp.c +++ b/drivers/tty/synclinkmp.c @@ -3977,7 +3977,6 @@ static int __init synclinkmp_init(void) /* Initialize the tty_driver structure */ - serial_driver->owner = THIS_MODULE; serial_driver->driver_name = "synclinkmp"; serial_driver->name = "ttySLM"; serial_driver->major = ttymajor; diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index e5abcea..84c4a7d 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -2994,7 +2994,7 @@ int __init vty_init(const struct file_operations *console_fops) console_driver = alloc_tty_driver(MAX_NR_CONSOLES); if (!console_driver) panic("Couldn't allocate console driver\n"); - console_driver->owner = THIS_MODULE; + console_driver->name = "tty"; console_driver->name_base = 1; console_driver->major = TTY_MAJOR; diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index 11a1130..6bb8472 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -1670,7 +1670,6 @@ static int __init acm_init(void) acm_tty_driver = alloc_tty_driver(ACM_TTY_MINORS); if (!acm_tty_driver) return -ENOMEM; - acm_tty_driver->owner = THIS_MODULE, acm_tty_driver->driver_name = "acm", acm_tty_driver->name = "ttyACM", acm_tty_driver->major = ACM_TTY_MAJOR, diff --git a/drivers/usb/gadget/u_serial.c b/drivers/usb/gadget/u_serial.c index 6597a68..490b01d 100644 --- a/drivers/usb/gadget/u_serial.c +++ b/drivers/usb/gadget/u_serial.c @@ -1087,7 +1087,6 @@ int __init gserial_setup(struct usb_gadget *g, unsigned count) if (!gs_tty_driver) return -ENOMEM; - gs_tty_driver->owner = THIS_MODULE; gs_tty_driver->driver_name = "g_serial"; gs_tty_driver->name = PREFIX; /* uses dynamically assigned dev_t values */ diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index 1e30cc9..d4e724d 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c @@ -1235,7 +1235,6 @@ static int __init usb_serial_init(void) goto exit_bus; } - usb_serial_tty_driver->owner = THIS_MODULE; usb_serial_tty_driver->driver_name = "usbserial"; usb_serial_tty_driver->name = "ttyUSB"; usb_serial_tty_driver->major = SERIAL_TTY_MAJOR; diff --git a/net/bluetooth/rfcomm/tty.c b/net/bluetooth/rfcomm/tty.c index a2d4f51..7adb03c 100644 --- a/net/bluetooth/rfcomm/tty.c +++ b/net/bluetooth/rfcomm/tty.c @@ -1157,7 +1157,6 @@ int __init rfcomm_init_ttys(void) if (!rfcomm_tty_driver) return -ENOMEM; - rfcomm_tty_driver->owner = THIS_MODULE; rfcomm_tty_driver->driver_name = "rfcomm"; rfcomm_tty_driver->name = "rfcomm"; rfcomm_tty_driver->major = RFCOMM_TTY_MAJOR; diff --git a/net/irda/ircomm/ircomm_tty.c b/net/irda/ircomm/ircomm_tty.c index 253695d..828f886 100644 --- a/net/irda/ircomm/ircomm_tty.c +++ b/net/irda/ircomm/ircomm_tty.c @@ -122,7 +122,6 @@ static int __init ircomm_tty_init(void) return -ENOMEM; } - driver->owner = THIS_MODULE; driver->driver_name = "ircomm"; driver->name = "ircomm"; driver->major = IRCOMM_TTY_MAJOR; -- cgit v0.10.2 From d4834267e81c8f08685e6ee55751551fa60f66e3 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 5 Mar 2012 14:51:53 +0100 Subject: TTY: simplify tty_driver_lookup_tty a bit Remove the useless local variable and return the value itself. Signed-off-by: Jiri Slaby Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index bd95cea..d0d3d1f 100644 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c @@ -1230,13 +1230,10 @@ static void tty_line_name(struct tty_driver *driver, int index, char *p) static struct tty_struct *tty_driver_lookup_tty(struct tty_driver *driver, struct inode *inode, int idx) { - struct tty_struct *tty; - if (driver->ops->lookup) return driver->ops->lookup(driver, inode, idx); - tty = driver->ttys[idx]; - return tty; + return driver->ttys[idx]; } /** -- cgit v0.10.2 From ecd166507f4218c9988d005feb04b7215f9df321 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 5 Mar 2012 14:51:54 +0100 Subject: TTY: remove tty driver re-set from tty_reopen This is from tty_reopen: struct tty_driver *driver = tty->driver; ... tty->driver = driver; and it doesn't make sense at all. The driver is intended to be set in initialize_tty_struct from tty_init_dev (initial open). So this set in tty_reopen is not needed. Signed-off-by: Jiri Slaby Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index d0d3d1f..dd8a938 100644 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c @@ -1348,7 +1348,6 @@ static int tty_reopen(struct tty_struct *tty) tty->link->count++; } tty->count++; - tty->driver = driver; /* N.B. why do this every time?? */ mutex_lock(&tty->ldisc_mutex); WARN_ON(!test_bit(TTY_LDISC, &tty->flags)); -- cgit v0.10.2 From 91cedcde1e5feede6c1e4c2086ec4f3c84c56d4f Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 5 Mar 2012 14:51:55 +0100 Subject: TTY: serial, simplify ASYNC_USR_MASK By using ASYNC_SPD_MASK instead of the single speed bits. Signed-off-by: Jiri Slaby Signed-off-by: Greg Kroah-Hartman diff --git a/include/linux/serial.h b/include/linux/serial.h index 3d86517..441980e 100644 --- a/include/linux/serial.h +++ b/include/linux/serial.h @@ -152,8 +152,8 @@ struct serial_uart_config { #define ASYNC_AUTOPROBE (1U << ASYNCB_AUTOPROBE) #define ASYNC_FLAGS ((1U << (ASYNCB_LAST_USER + 1)) - 1) -#define ASYNC_USR_MASK (ASYNC_SPD_HI|ASYNC_SPD_VHI| \ - ASYNC_CALLOUT_NOHUP|ASYNC_SPD_SHI|ASYNC_LOW_LATENCY) +#define ASYNC_USR_MASK (ASYNC_SPD_MASK|ASYNC_CALLOUT_NOHUP| \ + ASYNC_LOW_LATENCY) #define ASYNC_SPD_CUST (ASYNC_SPD_HI|ASYNC_SPD_VHI) #define ASYNC_SPD_WARP (ASYNC_SPD_HI|ASYNC_SPD_SHI) #define ASYNC_SPD_MASK (ASYNC_SPD_HI|ASYNC_SPD_VHI|ASYNC_SPD_SHI) -- cgit v0.10.2 From 26b23209c0ea5503824df60b8f218fb04b80cad0 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 5 Mar 2012 14:51:56 +0100 Subject: TTY: tty_driver, document tty->ops->shutdown limitation Note that tty->ops->shutdown is called from whatever context the user drops the last tty reference from. E.g. if one takes a reference in an ISR, tty close happens on other CPU and the final tty put is from the ISR, tty->ops->shutdown will be called from that hard irq context. We would have a problem in vt if we start using tty refcounting from other contexts than user there. It is because vt's shutdown uses mutexes. This is yet to be fixed. Signed-off-by: Jiri Slaby Reported-by: Al Viro Signed-off-by: Greg Kroah-Hartman diff --git a/include/linux/tty_driver.h b/include/linux/tty_driver.h index e064f17..6e6dbb7 100644 --- a/include/linux/tty_driver.h +++ b/include/linux/tty_driver.h @@ -50,6 +50,8 @@ * Note that tty_shutdown() is not called if ops->shutdown is defined. * This means one is responsible to take care of calling ops->remove (e.g. * via tty_driver_remove_tty) and releasing tty->termios. + * Note that this hook may be called from *all* the contexts where one + * uses tty refcounting (e.g. tty_port_tty_get). * * * void (*cleanup)(struct tty_struct * tty); -- cgit v0.10.2 From 5e88e6c4e8b044a1d275f1a599128b95046d2968 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 5 Mar 2012 14:51:57 +0100 Subject: ALPHA: srmcons, use timer functions It makes the code more readable. We move the setup to the allocation location because we need to initialize timers only once. Signed-off-by: Jiri Slaby Cc: Richard Henderson Cc: Ivan Kokshaysky Cc: Matt Turner Signed-off-by: Greg Kroah-Hartman diff --git a/arch/alpha/kernel/srmcons.c b/arch/alpha/kernel/srmcons.c index 783f4e5..f1fdf17 100644 --- a/arch/alpha/kernel/srmcons.c +++ b/arch/alpha/kernel/srmcons.c @@ -79,10 +79,8 @@ srmcons_receive_chars(unsigned long data) } spin_lock(&srmconsp->lock); - if (srmconsp->tty) { - srmconsp->timer.expires = jiffies + incr; - add_timer(&srmconsp->timer); - } + if (srmconsp->tty) + mod_timer(&srmconsp->timer, jiffies + incr); spin_unlock(&srmconsp->lock); local_irq_restore(flags); @@ -172,7 +170,8 @@ srmcons_get_private_struct(struct srmcons_private **ps) else { srmconsp->tty = NULL; spin_lock_init(&srmconsp->lock); - init_timer(&srmconsp->timer); + setup_timer(&srmconsp->timer, srmcons_receive_chars, + (unsigned long)srmconsp); } spin_unlock_irqrestore(&srmconsp_lock, flags); @@ -199,10 +198,7 @@ srmcons_open(struct tty_struct *tty, struct file *filp) tty->driver_data = srmconsp; srmconsp->tty = tty; - srmconsp->timer.function = srmcons_receive_chars; - srmconsp->timer.data = (unsigned long)srmconsp; - srmconsp->timer.expires = jiffies + 10; - add_timer(&srmconsp->timer); + mod_timer(&srmconsp->timer, jiffies + 10); } spin_unlock_irqrestore(&srmconsp->lock, flags); -- cgit v0.10.2 From ee024d494ab75426bc77e0c053700915f0a1a16d Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 5 Mar 2012 14:51:58 +0100 Subject: ALPHA: srmcons, fix racy singleton structure The test and the assignment were racy. Make it really a singleton. This is achieved by one global variable initialized at the module init. Signed-off-by: Jiri Slaby Cc: Richard Henderson Cc: Ivan Kokshaysky Cc: Matt Turner Signed-off-by: Greg Kroah-Hartman diff --git a/arch/alpha/kernel/srmcons.c b/arch/alpha/kernel/srmcons.c index f1fdf17..2c89ce5c 100644 --- a/arch/alpha/kernel/srmcons.c +++ b/arch/alpha/kernel/srmcons.c @@ -33,7 +33,7 @@ struct srmcons_private { struct tty_struct *tty; struct timer_list timer; spinlock_t lock; -}; +} srmcons_singleton; typedef union _srmcons_result { struct { @@ -154,43 +154,10 @@ srmcons_chars_in_buffer(struct tty_struct *tty) } static int -srmcons_get_private_struct(struct srmcons_private **ps) -{ - static struct srmcons_private *srmconsp = NULL; - static DEFINE_SPINLOCK(srmconsp_lock); - unsigned long flags; - int retval = 0; - - if (srmconsp == NULL) { - srmconsp = kmalloc(sizeof(*srmconsp), GFP_KERNEL); - spin_lock_irqsave(&srmconsp_lock, flags); - - if (srmconsp == NULL) - retval = -ENOMEM; - else { - srmconsp->tty = NULL; - spin_lock_init(&srmconsp->lock); - setup_timer(&srmconsp->timer, srmcons_receive_chars, - (unsigned long)srmconsp); - } - - spin_unlock_irqrestore(&srmconsp_lock, flags); - } - - *ps = srmconsp; - return retval; -} - -static int srmcons_open(struct tty_struct *tty, struct file *filp) { - struct srmcons_private *srmconsp; + struct srmcons_private *srmconsp = &srmcons_singleton; unsigned long flags; - int retval; - - retval = srmcons_get_private_struct(&srmconsp); - if (retval) - return retval; spin_lock_irqsave(&srmconsp->lock, flags); @@ -236,6 +203,9 @@ static const struct tty_operations srmcons_ops = { static int __init srmcons_init(void) { + spin_lock_init(&srmcons_singleton.lock); + setup_timer(&srmcons_singleton.timer, srmcons_receive_chars, + (unsigned long)&srmcons_singleton); if (srm_is_registered_console) { struct tty_driver *driver; int err; -- cgit v0.10.2 From 54089d4cdc89732e65f968209d10aae542482c0c Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 5 Mar 2012 14:51:59 +0100 Subject: TTY: srmcons, convert to use tty_port This is needed because the tty buffer will become a tty_port member later. That will help us to wipe out most of the races and checks for the tty pointer in hot paths. Signed-off-by: Jiri Slaby Cc: Richard Henderson Cc: Ivan Kokshaysky Cc: Matt Turner Signed-off-by: Greg Kroah-Hartman diff --git a/arch/alpha/kernel/srmcons.c b/arch/alpha/kernel/srmcons.c index 2c89ce5c..3ea8094 100644 --- a/arch/alpha/kernel/srmcons.c +++ b/arch/alpha/kernel/srmcons.c @@ -30,9 +30,8 @@ static int srm_is_registered_console = 0; #define MAX_SRM_CONSOLE_DEVICES 1 /* only support 1 console device */ struct srmcons_private { - struct tty_struct *tty; + struct tty_port port; struct timer_list timer; - spinlock_t lock; } srmcons_singleton; typedef union _srmcons_result { @@ -68,20 +67,21 @@ static void srmcons_receive_chars(unsigned long data) { struct srmcons_private *srmconsp = (struct srmcons_private *)data; + struct tty_port *port = &srmconsp->port; unsigned long flags; int incr = 10; local_irq_save(flags); if (spin_trylock(&srmcons_callback_lock)) { - if (!srmcons_do_receive_chars(srmconsp->tty)) + if (!srmcons_do_receive_chars(port->tty)) incr = 100; spin_unlock(&srmcons_callback_lock); } - spin_lock(&srmconsp->lock); - if (srmconsp->tty) + spin_lock(&port->lock); + if (port->tty) mod_timer(&srmconsp->timer, jiffies + incr); - spin_unlock(&srmconsp->lock); + spin_unlock(&port->lock); local_irq_restore(flags); } @@ -157,18 +157,19 @@ static int srmcons_open(struct tty_struct *tty, struct file *filp) { struct srmcons_private *srmconsp = &srmcons_singleton; + struct tty_port *port = &srmconsp->port; unsigned long flags; - spin_lock_irqsave(&srmconsp->lock, flags); + spin_lock_irqsave(&port->lock, flags); - if (!srmconsp->tty) { + if (!port->tty) { tty->driver_data = srmconsp; - - srmconsp->tty = tty; + tty->port = port; + port->tty = tty; /* XXX proper refcounting */ mod_timer(&srmconsp->timer, jiffies + 10); } - spin_unlock_irqrestore(&srmconsp->lock, flags); + spin_unlock_irqrestore(&port->lock, flags); return 0; } @@ -177,16 +178,17 @@ static void srmcons_close(struct tty_struct *tty, struct file *filp) { struct srmcons_private *srmconsp = tty->driver_data; + struct tty_port *port = &srmconsp->port; unsigned long flags; - spin_lock_irqsave(&srmconsp->lock, flags); + spin_lock_irqsave(&port->lock, flags); if (tty->count == 1) { - srmconsp->tty = NULL; + port->tty = NULL; del_timer(&srmconsp->timer); } - spin_unlock_irqrestore(&srmconsp->lock, flags); + spin_unlock_irqrestore(&port->lock, flags); } @@ -203,7 +205,7 @@ static const struct tty_operations srmcons_ops = { static int __init srmcons_init(void) { - spin_lock_init(&srmcons_singleton.lock); + tty_port_init(&srmcons_singleton.port); setup_timer(&srmcons_singleton.timer, srmcons_receive_chars, (unsigned long)&srmcons_singleton); if (srm_is_registered_console) { -- cgit v0.10.2 From 44a1bfd95d0a6c0096e79a883197596e1ce83cc3 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 5 Mar 2012 14:52:00 +0100 Subject: TTY: serialP, remove DECLARE_WAITQUEUE check The macro is always defined now. This was there only for historical reasons. Signed-off-by: Jiri Slaby Signed-off-by: Greg Kroah-Hartman diff --git a/include/linux/serialP.h b/include/linux/serialP.h index e811a61..ec27b34 100644 --- a/include/linux/serialP.h +++ b/include/linux/serialP.h @@ -79,15 +79,9 @@ struct async_struct { int io_type; struct work_struct work; struct tasklet_struct tlet; -#ifdef DECLARE_WAITQUEUE wait_queue_head_t open_wait; wait_queue_head_t close_wait; wait_queue_head_t delta_msr_wait; -#else - struct wait_queue *open_wait; - struct wait_queue *close_wait; - struct wait_queue *delta_msr_wait; -#endif struct async_struct *next_port; /* For the linked list */ struct async_struct *prev_port; }; -- cgit v0.10.2 From 410235fd4d20b8feaf8930a0575d23acc088aa87 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 5 Mar 2012 14:52:01 +0100 Subject: TTY: remove unneeded tty->index checks Checking if tty->index is in bounds is not needed. The tty has the index set in the initial open. This is done in get_tty_driver. And it can be only in interval <0,driver->num). So remove the tests which check exactly this interval. Some are left untouched as they check against the current backing device count. (Leaving apart that the check is racy in most of the cases.) Signed-off-by: Jiri Slaby Signed-off-by: Greg Kroah-Hartman diff --git a/arch/ia64/hp/sim/simserial.c b/arch/ia64/hp/sim/simserial.c index f513dc0..2a2fe0c 100644 --- a/arch/ia64/hp/sim/simserial.c +++ b/arch/ia64/hp/sim/simserial.c @@ -769,13 +769,10 @@ errout: static int rs_open(struct tty_struct *tty, struct file * filp) { struct async_struct *info; - int retval, line; + int retval; unsigned long page; - line = tty->index; - if ((line < 0) || (line >= NR_PORTS)) - return -ENODEV; - retval = get_async_struct(line, &info); + retval = get_async_struct(tty->index, &info); if (retval) return retval; tty->driver_data = info; @@ -920,7 +917,7 @@ simrs_init (void) if (!ia64_platform_is("hpsim")) return -ENODEV; - hp_simserial_driver = alloc_tty_driver(1); + hp_simserial_driver = alloc_tty_driver(NR_PORTS); if (!hp_simserial_driver) return -ENOMEM; diff --git a/arch/xtensa/platforms/iss/console.c b/arch/xtensa/platforms/iss/console.c index 247e9d4..19a802a 100644 --- a/arch/xtensa/platforms/iss/console.c +++ b/arch/xtensa/platforms/iss/console.c @@ -68,11 +68,6 @@ static void rs_poll(unsigned long); static int rs_open(struct tty_struct *tty, struct file * filp) { - int line = tty->index; - - if ((line < 0) || (line >= SERIAL_MAX_NUM_LINES)) - return -ENODEV; - spin_lock(&timer_lock); if (tty->count == 1) { @@ -101,6 +96,7 @@ static void rs_close(struct tty_struct *tty, struct file * filp) { spin_lock(&timer_lock); if (tty->count == 1) + /* this will cause a deadlock if the timer ticks right now */ del_timer_sync(&serial_timer); spin_unlock(&timer_lock); } @@ -210,7 +206,7 @@ static const struct tty_operations serial_ops = { int __init rs_init(void) { - serial_driver = alloc_tty_driver(1); + serial_driver = alloc_tty_driver(SERIAL_MAX_NUM_LINES); printk ("%s %s\n", serial_name, serial_version); diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c index c3bcb12..f6453df 100644 --- a/drivers/char/pcmcia/synclink_cs.c +++ b/drivers/char/pcmcia/synclink_cs.c @@ -2484,7 +2484,7 @@ static int mgslpc_open(struct tty_struct *tty, struct file * filp) /* verify range of specified line number */ line = tty->index; - if ((line < 0) || (line >= mgslpc_device_count)) { + if (line >= mgslpc_device_count) { printk("%s(%d):mgslpc_open with invalid line #%d.\n", __FILE__,__LINE__,line); return -ENODEV; diff --git a/drivers/isdn/capi/capi.c b/drivers/isdn/capi/capi.c index baf08eb..3a7905b 100644 --- a/drivers/isdn/capi/capi.c +++ b/drivers/isdn/capi/capi.c @@ -1013,8 +1013,7 @@ static const struct file_operations capi_fops = static int capinc_tty_install(struct tty_driver *driver, struct tty_struct *tty) { - int idx = tty->index; - struct capiminor *mp = capiminor_get(idx); + struct capiminor *mp = capiminor_get(tty->index); int ret = tty_standard_install(driver, tty); if (ret == 0) diff --git a/drivers/isdn/gigaset/common.c b/drivers/isdn/gigaset/common.c index db621db..ac0186e 100644 --- a/drivers/isdn/gigaset/common.c +++ b/drivers/isdn/gigaset/common.c @@ -1051,8 +1051,6 @@ static struct cardstate *gigaset_get_cs_by_minor(unsigned minor) struct cardstate *gigaset_get_cs_by_tty(struct tty_struct *tty) { - if (tty->index < 0 || tty->index >= tty->driver->num) - return NULL; return gigaset_get_cs_by_minor(tty->index + tty->driver->minor_start); } diff --git a/drivers/isdn/i4l/isdn_tty.c b/drivers/isdn/i4l/isdn_tty.c index 2c26b64..ac48401 100644 --- a/drivers/isdn/i4l/isdn_tty.c +++ b/drivers/isdn/i4l/isdn_tty.c @@ -1590,12 +1590,9 @@ static int isdn_tty_open(struct tty_struct *tty, struct file *filp) { modem_info *info; - int retval, line; + int retval; - line = tty->index; - if (line < 0 || line >= ISDN_MAX_CHANNELS) - return -ENODEV; - info = &dev->mdm.info[line]; + info = &dev->mdm.info[tty->index]; if (isdn_tty_paranoia_check(info, tty->name, "isdn_tty_open")) return -ENODEV; if (!try_module_get(info->owner)) { diff --git a/drivers/s390/char/con3215.c b/drivers/s390/char/con3215.c index fe916bf..ed23fec 100644 --- a/drivers/s390/char/con3215.c +++ b/drivers/s390/char/con3215.c @@ -926,13 +926,9 @@ console_initcall(con3215_init); static int tty3215_open(struct tty_struct *tty, struct file * filp) { struct raw3215_info *raw; - int retval, line; + int retval; - line = tty->index; - if ((line < 0) || (line >= NR_3215)) - return -ENODEV; - - raw = raw3215[line]; + raw = raw3215[tty->index]; if (raw == NULL) return -ENODEV; diff --git a/drivers/tty/amiserial.c b/drivers/tty/amiserial.c index b42f00d..7532862 100644 --- a/drivers/tty/amiserial.c +++ b/drivers/tty/amiserial.c @@ -1768,13 +1768,9 @@ static int get_async_struct(int line, struct async_struct **ret_info) static int rs_open(struct tty_struct *tty, struct file * filp) { struct async_struct *info; - int retval, line; + int retval; - line = tty->index; - if ((line < 0) || (line >= NR_PORTS)) { - return -ENODEV; - } - retval = get_async_struct(line, &info); + retval = get_async_struct(tty->index, &info); if (retval) { return retval; } @@ -1964,7 +1960,7 @@ static int __init amiga_serial_probe(struct platform_device *pdev) struct serial_state * state; int error; - serial_driver = alloc_tty_driver(1); + serial_driver = alloc_tty_driver(NR_PORTS); if (!serial_driver) return -ENOMEM; diff --git a/drivers/tty/cyclades.c b/drivers/tty/cyclades.c index bc7b5a5..e61cabd 100644 --- a/drivers/tty/cyclades.c +++ b/drivers/tty/cyclades.c @@ -1515,13 +1515,9 @@ static void cy_shutdown(struct cyclades_port *info, struct tty_struct *tty) static int cy_open(struct tty_struct *tty, struct file *filp) { struct cyclades_port *info; - unsigned int i, line; + unsigned int i, line = tty->index; int retval; - line = tty->index; - if (tty->index < 0 || NR_PORTS <= line) - return -ENODEV; - for (i = 0; i < NR_CARDS; i++) if (line < cy_card[i].first_line + cy_card[i].nports && line >= cy_card[i].first_line) diff --git a/drivers/tty/hvc/hvcs.c b/drivers/tty/hvc/hvcs.c index da0aa47..d237591 100644 --- a/drivers/tty/hvc/hvcs.c +++ b/drivers/tty/hvc/hvcs.c @@ -1090,27 +1090,23 @@ static int hvcs_enable_device(struct hvcs_struct *hvcsd, uint32_t unit_address, */ static struct hvcs_struct *hvcs_get_by_index(int index) { - struct hvcs_struct *hvcsd = NULL; + struct hvcs_struct *hvcsd; unsigned long flags; spin_lock(&hvcs_structs_lock); - /* We can immediately discard OOB requests */ - if (index >= 0 && index < HVCS_MAX_SERVER_ADAPTERS) { - list_for_each_entry(hvcsd, &hvcs_structs, next) { - spin_lock_irqsave(&hvcsd->lock, flags); - if (hvcsd->index == index) { - kref_get(&hvcsd->kref); - spin_unlock_irqrestore(&hvcsd->lock, flags); - spin_unlock(&hvcs_structs_lock); - return hvcsd; - } + list_for_each_entry(hvcsd, &hvcs_structs, next) { + spin_lock_irqsave(&hvcsd->lock, flags); + if (hvcsd->index == index) { + kref_get(&hvcsd->kref); spin_unlock_irqrestore(&hvcsd->lock, flags); + spin_unlock(&hvcs_structs_lock); + return hvcsd; } - hvcsd = NULL; + spin_unlock_irqrestore(&hvcsd->lock, flags); } - spin_unlock(&hvcs_structs_lock); - return hvcsd; + + return NULL; } /* diff --git a/drivers/tty/hvc/hvsi.c b/drivers/tty/hvc/hvsi.c index 60bc451..a7488b7 100644 --- a/drivers/tty/hvc/hvsi.c +++ b/drivers/tty/hvc/hvsi.c @@ -737,14 +737,11 @@ static int hvsi_open(struct tty_struct *tty, struct file *filp) { struct hvsi_struct *hp; unsigned long flags; - int line = tty->index; int ret; pr_debug("%s\n", __func__); - if (line < 0 || line >= hvsi_count) - return -ENODEV; - hp = &hvsi_ports[line]; + hp = &hvsi_ports[tty->index]; tty->driver_data = hp; diff --git a/drivers/tty/isicom.c b/drivers/tty/isicom.c index b3a28b5..03c1497 100644 --- a/drivers/tty/isicom.c +++ b/drivers/tty/isicom.c @@ -849,8 +849,6 @@ static struct tty_port *isicom_find_port(struct tty_struct *tty) unsigned int board; int line = tty->index; - if (line < 0 || line > PORT_COUNT-1) - return NULL; board = BOARD(line); card = &isi_card[board]; diff --git a/drivers/tty/mxser.c b/drivers/tty/mxser.c index 260d031..17ff377 100644 --- a/drivers/tty/mxser.c +++ b/drivers/tty/mxser.c @@ -1010,8 +1010,6 @@ static int mxser_open(struct tty_struct *tty, struct file *filp) line = tty->index; if (line == MXSER_PORTS) return 0; - if (line < 0 || line > MXSER_PORTS) - return -ENODEV; info = &mxser_boards[line / MXSER_PORTS_PER_BOARD].ports[line % MXSER_PORTS_PER_BOARD]; if (!info->ioaddr) return -ENODEV; diff --git a/drivers/tty/rocket.c b/drivers/tty/rocket.c index b088e1e..777d5f9 100644 --- a/drivers/tty/rocket.c +++ b/drivers/tty/rocket.c @@ -892,12 +892,12 @@ static int rp_open(struct tty_struct *tty, struct file *filp) { struct r_port *info; struct tty_port *port; - int line = 0, retval; + int retval; CHANNEL_t *cp; unsigned long page; - line = tty->index; - if (line < 0 || line >= MAX_RP_PORTS || ((info = rp_table[line]) == NULL)) + info = rp_table[tty->index]; + if (info == NULL) return -ENXIO; port = &info->port; diff --git a/drivers/tty/serial/68328serial.c b/drivers/tty/serial/68328serial.c index a88ef97..7398390 100644 --- a/drivers/tty/serial/68328serial.c +++ b/drivers/tty/serial/68328serial.c @@ -1190,14 +1190,9 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, int rs_open(struct tty_struct *tty, struct file * filp) { struct m68k_serial *info; - int retval, line; - - line = tty->index; - - if (line >= NR_PORTS || line < 0) /* we have exactly one */ - return -ENODEV; + int retval; - info = &m68k_soft[line]; + info = &m68k_soft[tty->index]; if (serial_paranoia_check(info, tty->name, "rs_open")) return -ENODEV; diff --git a/drivers/tty/serial/crisv10.c b/drivers/tty/serial/crisv10.c index 1dfba7b..23d7916 100644 --- a/drivers/tty/serial/crisv10.c +++ b/drivers/tty/serial/crisv10.c @@ -4105,20 +4105,11 @@ static int rs_open(struct tty_struct *tty, struct file * filp) { struct e100_serial *info; - int retval, line; + int retval; unsigned long page; int allocated_resources = 0; - /* find which port we want to open */ - line = tty->index; - - if (line < 0 || line >= NR_PORTS) - return -ENODEV; - - /* find the corresponding e100_serial struct in the table */ - info = rs_table + line; - - /* don't allow the opening of ports that are not enabled in the HW config */ + info = rs_table + tty->index; if (!info->enabled) return -ENODEV; @@ -4131,7 +4122,7 @@ rs_open(struct tty_struct *tty, struct file * filp) tty->driver_data = info; info->port.tty = tty; - info->port.tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0; + tty->low_latency = !!(info->flags & ASYNC_LOW_LATENCY); if (!tmp_buf) { page = get_zeroed_page(GFP_KERNEL); diff --git a/drivers/tty/synclink.c b/drivers/tty/synclink.c index 2b2988c..8e518da 100644 --- a/drivers/tty/synclink.c +++ b/drivers/tty/synclink.c @@ -3381,7 +3381,7 @@ static int mgsl_open(struct tty_struct *tty, struct file * filp) /* verify range of specified line number */ line = tty->index; - if ((line < 0) || (line >= mgsl_device_count)) { + if (line >= mgsl_device_count) { printk("%s(%d):mgsl_open with invalid line #%d.\n", __FILE__,__LINE__,line); return -ENODEV; diff --git a/drivers/tty/synclink_gt.c b/drivers/tty/synclink_gt.c index a8b66be..6bee490 100644 --- a/drivers/tty/synclink_gt.c +++ b/drivers/tty/synclink_gt.c @@ -654,7 +654,7 @@ static int open(struct tty_struct *tty, struct file *filp) unsigned long flags; line = tty->index; - if ((line < 0) || (line >= slgt_device_count)) { + if (line >= slgt_device_count) { DBGERR(("%s: open with invalid line #%d.\n", driver_name, line)); return -ENODEV; } diff --git a/drivers/tty/synclinkmp.c b/drivers/tty/synclinkmp.c index ddabb61..4fb6c4b 100644 --- a/drivers/tty/synclinkmp.c +++ b/drivers/tty/synclinkmp.c @@ -721,7 +721,7 @@ static int open(struct tty_struct *tty, struct file *filp) unsigned long flags; line = tty->index; - if ((line < 0) || (line >= synclinkmp_device_count)) { + if (line >= synclinkmp_device_count) { printk("%s(%d): open with invalid line #%d.\n", __FILE__,__LINE__,line); return -ENODEV; diff --git a/drivers/usb/gadget/u_serial.c b/drivers/usb/gadget/u_serial.c index 490b01d..6c23938 100644 --- a/drivers/usb/gadget/u_serial.c +++ b/drivers/usb/gadget/u_serial.c @@ -725,9 +725,6 @@ static int gs_open(struct tty_struct *tty, struct file *file) struct gs_port *port; int status; - if (port_num < 0 || port_num >= n_ports) - return -ENXIO; - do { mutex_lock(&ports[port_num].lock); port = ports[port_num].port; diff --git a/net/irda/ircomm/ircomm_tty.c b/net/irda/ircomm/ircomm_tty.c index 828f886..6b9d5a0 100644 --- a/net/irda/ircomm/ircomm_tty.c +++ b/net/irda/ircomm/ircomm_tty.c @@ -365,16 +365,12 @@ static int ircomm_tty_block_til_ready(struct ircomm_tty_cb *self, static int ircomm_tty_open(struct tty_struct *tty, struct file *filp) { struct ircomm_tty_cb *self; - unsigned int line; + unsigned int line = tty->index; unsigned long flags; int ret; IRDA_DEBUG(2, "%s()\n", __func__ ); - line = tty->index; - if (line >= IRCOMM_TTY_PORTS) - return -ENODEV; - /* Check if instance already exists */ self = hashbin_lock_find(ircomm_tty, line, NULL); if (!self) { -- cgit v0.10.2 From ecaa3bda65cefebfce11cc7be4b8d9203f5ce12c Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 5 Mar 2012 14:52:02 +0100 Subject: TTY: ipwireless, fix tty->index handling * do not test if tty->index is in bounds. It is always. * tty->index is not a minor! Fix that. >From now on, let's assume that the parameter of the function is tty index with base being zero. This makes also the code more readable. Factually, there is no real change as tty_driver->minor_start is zero, so the tests are equivalent. But it did not make sense. And if this had changed eventually, it would have caused troubles. Signed-off-by: Jiri Slaby Acked-by: Jiri Kosina Cc: David Sterba Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/ipwireless/tty.c b/drivers/tty/ipwireless/tty.c index 6990b3b..77ceaa9 100644 --- a/drivers/tty/ipwireless/tty.c +++ b/drivers/tty/ipwireless/tty.c @@ -90,33 +90,23 @@ static void report_deregistering(struct ipw_tty *tty) tty->index); } -static struct ipw_tty *get_tty(int minor) +static struct ipw_tty *get_tty(int index) { - if (minor < ipw_tty_driver->minor_start - || minor >= ipw_tty_driver->minor_start + - IPWIRELESS_PCMCIA_MINORS) + /* + * The 'ras_raw' channel is only available when 'loopback' mode + * is enabled. + * Number of minor starts with 16 (_RANGE * _RAS_RAW). + */ + if (!ipwireless_loopback && index >= + IPWIRELESS_PCMCIA_MINOR_RANGE * TTYTYPE_RAS_RAW) return NULL; - else { - int minor_offset = minor - ipw_tty_driver->minor_start; - - /* - * The 'ras_raw' channel is only available when 'loopback' mode - * is enabled. - * Number of minor starts with 16 (_RANGE * _RAS_RAW). - */ - if (!ipwireless_loopback && - minor_offset >= - IPWIRELESS_PCMCIA_MINOR_RANGE * TTYTYPE_RAS_RAW) - return NULL; - - return ttys[minor_offset]; - } + + return ttys[index]; } static int ipw_open(struct tty_struct *linux_tty, struct file *filp) { - int minor = linux_tty->index; - struct ipw_tty *tty = get_tty(minor); + struct ipw_tty *tty = get_tty(linux_tty->index); if (!tty) return -ENODEV; @@ -510,7 +500,7 @@ static int add_tty(int j, ipwireless_associate_network_tty(network, secondary_channel_idx, ttys[j]); - if (get_tty(j + ipw_tty_driver->minor_start) == ttys[j]) + if (get_tty(j) == ttys[j]) report_registering(ttys[j]); return 0; } @@ -570,7 +560,7 @@ void ipwireless_tty_free(struct ipw_tty *tty) if (ttyj) { mutex_lock(&ttyj->ipw_tty_mutex); - if (get_tty(j + ipw_tty_driver->minor_start) == ttyj) + if (get_tty(j) == ttyj) report_deregistering(ttyj); ttyj->closing = 1; if (ttyj->linux_tty != NULL) { -- cgit v0.10.2 From c2f128a1fed866dca94d52b3f0b1e40726e2352a Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 5 Mar 2012 14:52:03 +0100 Subject: NET: pc300, do not zero global variables They are in .bss which is initialized to zeros when the module is loaded/kernel booted. What a strange way to do the initialization once in the pci probe routine... Signed-off-by: Jiri Slaby Cc: netdev@vger.kernel.org Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/net/wan/pc300_drv.c b/drivers/net/wan/pc300_drv.c index 1eeedd6..a6dd00de 100644 --- a/drivers/net/wan/pc300_drv.c +++ b/drivers/net/wan/pc300_drv.c @@ -299,7 +299,6 @@ void cpc_tty_init(pc300dev_t * dev); void cpc_tty_unregister_service(pc300dev_t * pc300dev); void cpc_tty_receive(pc300dev_t * pc300dev); void cpc_tty_trigger_poll(pc300dev_t * pc300dev); -void cpc_tty_reset_var(void); #endif /************************/ @@ -3421,9 +3420,6 @@ cpc_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) if (first_time) { first_time = 0; show_version(); -#ifdef CONFIG_PC300_MLPPP - cpc_tty_reset_var(); -#endif } if ((err = pci_enable_device(pdev)) < 0) diff --git a/drivers/net/wan/pc300_tty.c b/drivers/net/wan/pc300_tty.c index d47d2cd..4709f42 100644 --- a/drivers/net/wan/pc300_tty.c +++ b/drivers/net/wan/pc300_tty.c @@ -139,7 +139,6 @@ void cpc_tty_init(pc300dev_t *dev); void cpc_tty_unregister_service(pc300dev_t *pc300dev); void cpc_tty_receive(pc300dev_t *pc300dev); void cpc_tty_trigger_poll(pc300dev_t *pc300dev); -void cpc_tty_reset_var(void); /* * PC300 TTY clear "signal" @@ -1078,20 +1077,3 @@ void cpc_tty_trigger_poll(pc300dev_t *pc300dev) } schedule_work(&(cpc_tty->tty_tx_work)); } - -/* - * PC300 TTY reset var routine - * This routine is called by pc300driver to init the TTY area. - */ - -void cpc_tty_reset_var(void) -{ - int i ; - - CPC_TTY_DBG("hdlcX-tty: reset variables\n"); - /* reset the tty_driver structure - serial_drv */ - memset(&serial_drv, 0, sizeof(struct tty_driver)); - for (i=0; i < CPC_TTY_NPORTS; i++){ - memset(&cpc_tty_area[i],0, sizeof(st_cpc_tty_area)); - } -} -- cgit v0.10.2 From ac4e016df4bf57cdb100170c5cc057a15a9c96bd Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 5 Mar 2012 14:52:04 +0100 Subject: NET: pc300, show version info from module init Again, no need to do that from the pci probe function. Hmm, I noticed this driver is marked as BROKEN. Won't touch it more, it has to be converted to dynamic tty driver allocation first. Perhaps it is time to move it to staging? Signed-off-by: Jiri Slaby Cc: netdev@vger.kernel.org Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/net/wan/pc300_drv.c b/drivers/net/wan/pc300_drv.c index a6dd00de..cb0f8d9 100644 --- a/drivers/net/wan/pc300_drv.c +++ b/drivers/net/wan/pc300_drv.c @@ -3231,7 +3231,7 @@ static void plx_init(pc300_t * card) } -static inline void show_version(void) +static void show_version(void) { char *rcsvers, *rcsdate, *tmp; @@ -3412,16 +3412,10 @@ static void cpc_init_card(pc300_t * card) static int __devinit cpc_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { - static int first_time = 1; int err, eeprom_outdated = 0; u16 device_id; pc300_t *card; - if (first_time) { - first_time = 0; - show_version(); - } - if ((err = pci_enable_device(pdev)) < 0) return err; @@ -3657,6 +3651,7 @@ static struct pci_driver cpc_driver = { static int __init cpc_init(void) { + show_version(); return pci_register_driver(&cpc_driver); } -- cgit v0.10.2 From 86e7e874635ea76fee8608646afcb103414c6e72 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 5 Mar 2012 14:52:05 +0100 Subject: XTENSA: iss/console, use setup_timer Use setup_timer instead of explicit assignments. Signed-off-by: Jiri Slaby Cc: Chris Zankel Signed-off-by: Greg Kroah-Hartman diff --git a/arch/xtensa/platforms/iss/console.c b/arch/xtensa/platforms/iss/console.c index 19a802a..01842e4 100644 --- a/arch/xtensa/platforms/iss/console.c +++ b/arch/xtensa/platforms/iss/console.c @@ -69,11 +69,8 @@ static void rs_poll(unsigned long); static int rs_open(struct tty_struct *tty, struct file * filp) { spin_lock(&timer_lock); - if (tty->count == 1) { - init_timer(&serial_timer); - serial_timer.data = (unsigned long) tty; - serial_timer.function = rs_poll; + setup_timer(&serial_timer, rs_poll, (unsigned long)tty); mod_timer(&serial_timer, jiffies + SERIAL_TIMER_VALUE); } spin_unlock(&timer_lock); -- cgit v0.10.2 From c9ddb1d6e29697029118377c1f4f9a4a148d755e Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 5 Mar 2012 14:52:06 +0100 Subject: XTENSA: iss/console, fix potential deadlock If the timer ticks while we are holding the spinlock, the system deadlocks. It is due to synchronous del_timer. So to fix that, use spinlocks that properly disable bottom halves. Signed-off-by: Jiri Slaby Cc: Chris Zankel Signed-off-by: Greg Kroah-Hartman diff --git a/arch/xtensa/platforms/iss/console.c b/arch/xtensa/platforms/iss/console.c index 01842e4..94ab8ec 100644 --- a/arch/xtensa/platforms/iss/console.c +++ b/arch/xtensa/platforms/iss/console.c @@ -91,11 +91,10 @@ static int rs_open(struct tty_struct *tty, struct file * filp) */ static void rs_close(struct tty_struct *tty, struct file * filp) { - spin_lock(&timer_lock); + spin_lock_bh(&timer_lock); if (tty->count == 1) - /* this will cause a deadlock if the timer ticks right now */ del_timer_sync(&serial_timer); - spin_unlock(&timer_lock); + spin_unlock_bh(&timer_lock); } -- cgit v0.10.2 From 885f8b0f8ab497b8520f95ff3c1bb7efb1c331ac Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 5 Mar 2012 14:52:07 +0100 Subject: TTY: iss/console, use tty_port Even though the port is not used for anything real there yet, this will change as tty buffers will be in tty_port in the near future. So the port will be needed in all drivers. Signed-off-by: Jiri Slaby Cc: Chris Zankel Signed-off-by: Greg Kroah-Hartman diff --git a/arch/xtensa/platforms/iss/console.c b/arch/xtensa/platforms/iss/console.c index 94ab8ec..d1a7861 100644 --- a/arch/xtensa/platforms/iss/console.c +++ b/arch/xtensa/platforms/iss/console.c @@ -37,6 +37,7 @@ #define SERIAL_TIMER_VALUE (20 * HZ) static struct tty_driver *serial_driver; +static struct tty_port serial_port; static struct timer_list serial_timer; static DEFINE_SPINLOCK(timer_lock); @@ -68,6 +69,7 @@ static void rs_poll(unsigned long); static int rs_open(struct tty_struct *tty, struct file * filp) { + tty->port = &serial_port; spin_lock(&timer_lock); if (tty->count == 1) { setup_timer(&serial_timer, rs_poll, (unsigned long)tty); @@ -202,6 +204,8 @@ static const struct tty_operations serial_ops = { int __init rs_init(void) { + tty_port_init(&serial_port); + serial_driver = alloc_tty_driver(SERIAL_MAX_NUM_LINES); printk ("%s %s\n", serial_name, serial_version); -- cgit v0.10.2 From 4da2405606d47ca767e0c6ba556f127cfa2181d0 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 5 Mar 2012 14:52:08 +0100 Subject: TTY: serial, use atomic_inc_return in ioc4_serial We want to know the value of the atomic variable in intr_connect after the increment. But atomic_inc doesn't, per definition, return the value. It is just a pure coincidence that ia64 defines atomic_inc as atomic_inc_return. So fix this mistake by using atomic_inc_return properly. Signed-off-by: Jiri Slaby Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/ioc4_serial.c b/drivers/tty/serial/ioc4_serial.c index 6b36c15..dfec69a 100644 --- a/drivers/tty/serial/ioc4_serial.c +++ b/drivers/tty/serial/ioc4_serial.c @@ -975,7 +975,7 @@ intr_connect(struct ioc4_soft *soft, int type, BUG_ON(!((type == IOC4_SIO_INTR_TYPE) || (type == IOC4_OTHER_INTR_TYPE))); - i = atomic_inc(&soft-> is_intr_type[type].is_num_intrs) - 1; + i = atomic_inc_return(&soft-> is_intr_type[type].is_num_intrs) - 1; BUG_ON(!(i < MAX_IOC4_INTR_ENTS || (printk("i %d\n", i), 0))); /* Save off the lower level interrupt handler */ -- cgit v0.10.2 From 8bc87dc999d57d7d2ab92ab203ff7e94e860d8fa Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 5 Mar 2012 14:52:09 +0100 Subject: TTY: serial, include pci.h in m32r_sio It uses pointers to pci_dev, but compiler complains it doesn't know it: In file included from .../m32r_sio.c:53: .../m32r_sio.h:21: warning: "struct pci_dev" declared inside parameter list .../m32r_sio.h:21: warning: its scope is only this definition or declaration, which is probably not what you want .../m32r_sio.h:22: warning: "struct pci_dev" declared inside parameter list Signed-off-by: Jiri Slaby Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/m32r_sio.h b/drivers/tty/serial/m32r_sio.h index e9b7e11..8129824 100644 --- a/drivers/tty/serial/m32r_sio.h +++ b/drivers/tty/serial/m32r_sio.h @@ -15,6 +15,7 @@ * (at your option) any later version. */ +#include struct m32r_sio_probe { struct module *owner; -- cgit v0.10.2 From 11ba8899f96066600a7adeee28baed7a4a8cb7eb Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 5 Mar 2012 14:52:10 +0100 Subject: TTY: remove serialP.h inclusion from some files All of them do not use the ugly interface defined in that header. Signed-off-by: Jiri Slaby Signed-off-by: Greg Kroah-Hartman diff --git a/arch/xtensa/platforms/iss/console.c b/arch/xtensa/platforms/iss/console.c index d1a7861..f9726f6 100644 --- a/arch/xtensa/platforms/iss/console.c +++ b/arch/xtensa/platforms/iss/console.c @@ -19,7 +19,6 @@ #include #include #include -#include #include #include diff --git a/drivers/tty/serial/ioc4_serial.c b/drivers/tty/serial/ioc4_serial.c index dfec69a..e16894f 100644 --- a/drivers/tty/serial/ioc4_serial.c +++ b/drivers/tty/serial/ioc4_serial.c @@ -16,7 +16,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/tty/serial/m32r_sio.c b/drivers/tty/serial/m32r_sio.c index e465dda..a070362 100644 --- a/drivers/tty/serial/m32r_sio.c +++ b/drivers/tty/serial/m32r_sio.c @@ -38,7 +38,6 @@ #include #include #include -#include #include #include -- cgit v0.10.2 From 3ee0017e03cd790ed1adaa97ef6f99aff3706ec2 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 5 Mar 2012 14:52:11 +0100 Subject: TTY: speakup, do not use serialP The structures there are going away. And speakup has enough troubles already. So define a structure similar to what 8250 does: old_serial_port. There define an array of speed, port base and so on needed for configuration. Then use this structure instead of serial_state defined in serialP.h. Signed-off-by: Jiri Slaby Cc: William Hubbs Cc: Chris Brannon Cc: Kirk Reiser Cc: Samuel Thibault Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/speakup/serialio.c b/drivers/staging/speakup/serialio.c index 7f3d87b..a97d3d5 100644 --- a/drivers/staging/speakup/serialio.c +++ b/drivers/staging/speakup/serialio.c @@ -8,21 +8,20 @@ static void start_serial_interrupt(int irq); -static struct serial_state rs_table[] = { +static const struct old_serial_port rs_table[] = { SERIAL_PORT_DFNS }; -static struct serial_state *serstate; +static const struct old_serial_port *serstate; static int timeouts; -struct serial_state *spk_serial_init(int index) +const struct old_serial_port *spk_serial_init(int index) { int baud = 9600, quot = 0; unsigned int cval = 0; int cflag = CREAD | HUPCL | CLOCAL | B9600 | CS8; - struct serial_state *ser = NULL; + const struct old_serial_port *ser = rs_table + index; int err; - ser = rs_table + index; /* Divisor, bytesize and parity */ quot = ser->baud_base / baud; cval = cflag & (CSIZE | CSTOPB); @@ -41,7 +40,7 @@ struct serial_state *spk_serial_init(int index) __release_region(&ioport_resource, ser->port, 8); err = synth_request_region(ser->port, 8); if (err) { - pr_warn("Unable to allocate port at %lx, errno %i", + pr_warn("Unable to allocate port at %x, errno %i", ser->port, err); return NULL; } diff --git a/drivers/staging/speakup/serialio.h b/drivers/staging/speakup/serialio.h index d785b1f..614271f 100644 --- a/drivers/staging/speakup/serialio.h +++ b/drivers/staging/speakup/serialio.h @@ -4,11 +4,22 @@ #include /* for rs_table, serial constants & serial_uart_config */ #include /* for more serial constants */ -#include /* for struct serial_state */ #ifndef __sparc__ #include #endif +/* + * this is cut&paste from 8250.h. Get rid of the structure, the definitions + * and this whole broken driver. + */ +struct old_serial_port { + unsigned int uart; /* unused */ + unsigned int baud_base; + unsigned int port; + unsigned int irq; + unsigned int flags; /* unused */ +}; + /* countdown values for serial timeouts in us */ #define SPK_SERIAL_TIMEOUT 100000 /* countdown values transmitter/dsr timeouts in us */ diff --git a/drivers/staging/speakup/spk_priv.h b/drivers/staging/speakup/spk_priv.h index 16ace4a..a47c5b7 100644 --- a/drivers/staging/speakup/spk_priv.h +++ b/drivers/staging/speakup/spk_priv.h @@ -44,7 +44,7 @@ #define KT_SPKUP 15 -extern struct serial_state *spk_serial_init(int index); +extern const struct old_serial_port *spk_serial_init(int index); extern void stop_serial_interrupt(void); extern int wait_for_xmitr(void); extern unsigned char spk_serial_in(void); diff --git a/drivers/staging/speakup/synth.c b/drivers/staging/speakup/synth.c index 2222d69..331eae7 100644 --- a/drivers/staging/speakup/synth.c +++ b/drivers/staging/speakup/synth.c @@ -34,7 +34,7 @@ static int do_synth_init(struct spk_synth *in_synth); int serial_synth_probe(struct spk_synth *synth) { - struct serial_state *ser; + const struct old_serial_port *ser; int failed = 0; if ((synth->ser >= SPK_LO_TTY) && (synth->ser <= SPK_HI_TTY)) { -- cgit v0.10.2 From 9c8efecc91c02056340ae19612315f3225e6dbe2 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 5 Mar 2012 14:52:12 +0100 Subject: TTY: serialP, remove unused material First, remove unused macro and rs_multiport_struct structure. Nobody uses them at all. Further, the 2 drivers (they are below) which use the rest of structures from serialP.h (async_struct and serial_state) do not use all the members. Remove the members: * which are unused or * which are only initialized and never used for something real. Everybody should avoid the structures with a looong distance. Finally, remove the ALPHA kludge MCR quirks. They are 1:1 copy from 8250.h. No need to redefine them here. The 2 promised users of the structures: arch/ia64/hp/sim/simserial.c drivers/tty/amiserial.c Signed-off-by: Jiri Slaby Cc: Geert Uytterhoeven Cc: Tony Luck Cc: Fenghua Yu Signed-off-by: Greg Kroah-Hartman diff --git a/arch/ia64/hp/sim/simserial.c b/arch/ia64/hp/sim/simserial.c index 2a2fe0c..9890b58 100644 --- a/arch/ia64/hp/sim/simserial.c +++ b/arch/ia64/hp/sim/simserial.c @@ -72,7 +72,7 @@ static char *serial_version = "0.6"; */ static struct serial_state rs_table[NR_PORTS]={ /* UART CLK PORT IRQ FLAGS */ - { 0, BASE_BAUD, 0x3F8, 0, STD_COM_FLAGS,0,PORT_16550 } /* ttyS0 */ + { BASE_BAUD, 0x3F8, 0, STD_COM_FLAGS, PORT_16550 } /* ttyS0 */ }; /* @@ -194,11 +194,6 @@ static irqreturn_t rs_interrupt_single(int irq, void *dev_id) * ------------------------------------------------------------------- */ -static void do_softint(struct work_struct *private_) -{ - printk(KERN_ERR "simserial: do_softint called\n"); -} - static int rs_put_char(struct tty_struct *tty, unsigned char ch) { struct async_struct *info = (struct async_struct *)tty->driver_data; @@ -641,13 +636,10 @@ static int get_async_struct(int line, struct async_struct **ret_info) } init_waitqueue_head(&info->open_wait); init_waitqueue_head(&info->close_wait); - init_waitqueue_head(&info->delta_msr_wait); - info->magic = SERIAL_MAGIC; info->port = sstate->port; info->flags = sstate->flags; info->xmit_fifo_size = sstate->xmit_fifo_size; info->line = line; - INIT_WORK(&info->work, do_softint); info->state = sstate; if (sstate->info) { kfree(info); diff --git a/drivers/tty/amiserial.c b/drivers/tty/amiserial.c index 7532862..c6d8913 100644 --- a/drivers/tty/amiserial.c +++ b/drivers/tty/amiserial.c @@ -473,7 +473,6 @@ static irqreturn_t ser_rx_int(int irq, void *dev_id) return IRQ_NONE; receive_chars(info); - info->last_active = jiffies; #ifdef SERIAL_DEBUG_INTR printk("end.\n"); #endif @@ -494,7 +493,6 @@ static irqreturn_t ser_tx_int(int irq, void *dev_id) return IRQ_NONE; transmit_chars(info); - info->last_active = jiffies; #ifdef SERIAL_DEBUG_INTR printk("end.\n"); #endif @@ -828,7 +826,6 @@ static void change_speed(struct async_struct *info, mb(); } - info->LCR = cval; /* Save LCR */ local_irq_restore(flags); } @@ -1743,7 +1740,6 @@ static int get_async_struct(int line, struct async_struct **ret_info) init_waitqueue_head(&info->close_wait); init_waitqueue_head(&info->delta_msr_wait); #endif - info->magic = SERIAL_MAGIC; info->port = sstate->port; info->flags = sstate->flags; info->xmit_fifo_size = sstate->xmit_fifo_size; @@ -1840,7 +1836,6 @@ static inline void line_info(struct seq_file *m, struct serial_state *state) if (!info) { info = &scr_info; /* This is just for serial_{in,out} */ - info->magic = SERIAL_MAGIC; info->flags = state->flags; info->quot = 0; info->tty = NULL; @@ -1987,7 +1982,6 @@ static int __init amiga_serial_probe(struct platform_device *pdev) goto fail_put_tty_driver; state = rs_table; - state->magic = SSTATE_MAGIC; state->port = (int)&custom.serdatr; /* Just to give it a value */ state->line = 0; state->custom_divisor = 0; diff --git a/include/linux/serialP.h b/include/linux/serialP.h index ec27b34..c1acdb2 100644 --- a/include/linux/serialP.h +++ b/include/linux/serialP.h @@ -26,32 +26,23 @@ #include struct serial_state { - int magic; int baud_base; unsigned long port; int irq; int flags; - int hub6; int type; int line; - int revision; /* Chip revision (950) */ int xmit_fifo_size; int custom_divisor; int count; - u8 *iomem_base; - u16 iomem_reg_shift; unsigned short close_delay; unsigned short closing_wait; /* time to wait before closing */ struct async_icount icount; - int io_type; struct async_struct *info; - struct pci_dev *dev; }; struct async_struct { - int magic; unsigned long port; - int hub6; int flags; int xmit_fifo_size; struct serial_state *state; @@ -63,21 +54,12 @@ struct async_struct { int x_char; /* xon/xoff character */ int close_delay; unsigned short closing_wait; - unsigned short closing_wait2; /* obsolete */ int IER; /* Interrupt Enable Register */ int MCR; /* Modem control register */ - int LCR; /* Line control register */ - int ACR; /* 16950 Additional Control Reg. */ unsigned long event; - unsigned long last_active; int line; int blocked_open; /* # of blocked opens */ struct circ_buf xmit; - spinlock_t xmit_lock; - u8 *iomem_base; - u16 iomem_reg_shift; - int io_type; - struct work_struct work; struct tasklet_struct tlet; wait_queue_head_t open_wait; wait_queue_head_t close_wait; @@ -86,51 +68,10 @@ struct async_struct { struct async_struct *prev_port; }; -#define CONFIGURED_SERIAL_PORT(info) ((info)->port || ((info)->iomem_base)) - -#define SERIAL_MAGIC 0x5301 -#define SSTATE_MAGIC 0x5302 - /* * Events are used to schedule things to happen at timer-interrupt * time, instead of at rs interrupt time. */ #define RS_EVENT_WRITE_WAKEUP 0 -/* - * Multiport serial configuration structure --- internal structure - */ -struct rs_multiport_struct { - int port1; - unsigned char mask1, match1; - int port2; - unsigned char mask2, match2; - int port3; - unsigned char mask3, match3; - int port4; - unsigned char mask4, match4; - int port_monitor; -}; - -#if defined(__alpha__) && !defined(CONFIG_PCI) -/* - * Digital did something really horribly wrong with the OUT1 and OUT2 - * lines on at least some ALPHA's. The failure mode is that if either - * is cleared, the machine locks up with endless interrupts. - * - * This is still used by arch/mips/au1000/common/serial.c for some weird - * reason (mips != alpha!) - */ -#define ALPHA_KLUDGE_MCR (UART_MCR_OUT2 | UART_MCR_OUT1) -#elif defined(CONFIG_SBC8560) -/* - * WindRiver did something similarly broken on their SBC8560 board. The - * UART tristates its IRQ output while OUT2 is clear, but they pulled - * the interrupt line _up_ instead of down, so if we register the IRQ - * while the UART is in that state, we die in an IRQ storm. */ -#define ALPHA_KLUDGE_MCR (UART_MCR_OUT2) -#else -#define ALPHA_KLUDGE_MCR 0 -#endif - #endif /* _LINUX_SERIAL_H */ -- cgit v0.10.2 From c5f0508b992ad081ba378a59b2404966f9f89429 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 5 Mar 2012 14:52:13 +0100 Subject: TTY: amiserial, remove tasklet for tty_wakeup tty_wakeup is safe to be called from all contexts. No need to schedule a tasklet for that. Let's call it directly like in other drivers. This allows us to kill another member of async_struct structure. (If we remove the dummy uses in simserial.) Signed-off-by: Jiri Slaby Cc: Geert Uytterhoeven Cc: Tony Luck Cc: Fenghua Yu Signed-off-by: Greg Kroah-Hartman diff --git a/arch/ia64/hp/sim/simserial.c b/arch/ia64/hp/sim/simserial.c index 9890b58..0d324e8 100644 --- a/arch/ia64/hp/sim/simserial.c +++ b/arch/ia64/hp/sim/simserial.c @@ -572,7 +572,6 @@ static void rs_close(struct tty_struct *tty, struct file * filp) shutdown(info); rs_flush_buffer(tty); tty_ldisc_flush(tty); - info->event = 0; info->tty = NULL; if (info->blocked_open) { if (info->close_delay) @@ -610,7 +609,6 @@ static void rs_hangup(struct tty_struct *tty) return; shutdown(info); - info->event = 0; state->count = 0; info->flags &= ~ASYNC_NORMAL_ACTIVE; info->tty = NULL; diff --git a/drivers/tty/amiserial.c b/drivers/tty/amiserial.c index c6d8913..d5fac86 100644 --- a/drivers/tty/amiserial.c +++ b/drivers/tty/amiserial.c @@ -231,17 +231,6 @@ static void rs_start(struct tty_struct *tty) * ----------------------------------------------------------------------- */ -/* - * This routine is used by the interrupt handler to schedule - * processing in the software interrupt portion of the driver. - */ -static void rs_sched_event(struct async_struct *info, - int event) -{ - info->event |= 1 << event; - tasklet_schedule(&info->tlet); -} - static void receive_chars(struct async_struct *info) { int status; @@ -359,7 +348,7 @@ static void transmit_chars(struct async_struct *info) if (CIRC_CNT(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE) < WAKEUP_CHARS) - rs_sched_event(info, RS_EVENT_WRITE_WAKEUP); + tty_wakeup(info->tty); #ifdef SERIAL_DEBUG_INTR printk("THRE..."); @@ -427,7 +416,7 @@ static void check_modem_status(struct async_struct *info) /* set a pending Tx Interrupt, transmitter should restart now */ custom.intreq = IF_SETCLR | IF_TBE; mb(); - rs_sched_event(info, RS_EVENT_WRITE_WAKEUP); + tty_wakeup(info->tty); return; } } else { @@ -507,29 +496,6 @@ static irqreturn_t ser_tx_int(int irq, void *dev_id) */ /* - * This routine is used to handle the "bottom half" processing for the - * serial driver, known also the "software interrupt" processing. - * This processing is done at the kernel interrupt level, after the - * rs_interrupt() has returned, BUT WITH INTERRUPTS TURNED ON. This - * is where time-consuming activities which can not be done in the - * interrupt driver proper are done; the interrupt driver schedules - * them using rs_sched_event(), and they get done here. - */ - -static void do_softint(unsigned long private_) -{ - struct async_struct *info = (struct async_struct *) private_; - struct tty_struct *tty; - - tty = info->tty; - if (!tty) - return; - - if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) - tty_wakeup(tty); -} - -/* * --------------------------------------------------------------- * Low level utility subroutines for the serial driver: routines to * figure out the appropriate timeout for an interrupt chain, routines @@ -1506,7 +1472,6 @@ static void rs_close(struct tty_struct *tty, struct file * filp) tty_ldisc_flush(tty); tty->closing = 0; - info->event = 0; info->tty = NULL; if (info->blocked_open) { if (info->close_delay) { @@ -1597,7 +1562,6 @@ static void rs_hangup(struct tty_struct *tty) rs_flush_buffer(tty); shutdown(info); - info->event = 0; state->count = 0; info->flags &= ~ASYNC_NORMAL_ACTIVE; info->tty = NULL; @@ -1744,7 +1708,6 @@ static int get_async_struct(int line, struct async_struct **ret_info) info->flags = sstate->flags; info->xmit_fifo_size = sstate->xmit_fifo_size; info->line = line; - tasklet_init(&info->tlet, do_softint, (unsigned long)info); info->state = sstate; if (sstate->info) { kfree(info); @@ -2050,7 +2013,6 @@ static int __exit amiga_serial_remove(struct platform_device *pdev) struct async_struct *info = state->info; /* printk("Unloading %s: version %s\n", serial_name, serial_version); */ - tasklet_kill(&info->tlet); if ((error = tty_unregister_driver(serial_driver))) printk("SERIAL: failed to unregister serial driver (%d)\n", error); diff --git a/include/linux/serialP.h b/include/linux/serialP.h index c1acdb2..beaf39f 100644 --- a/include/linux/serialP.h +++ b/include/linux/serialP.h @@ -56,11 +56,9 @@ struct async_struct { unsigned short closing_wait; int IER; /* Interrupt Enable Register */ int MCR; /* Modem control register */ - unsigned long event; int line; int blocked_open; /* # of blocked opens */ struct circ_buf xmit; - struct tasklet_struct tlet; wait_queue_head_t open_wait; wait_queue_head_t close_wait; wait_queue_head_t delta_msr_wait; @@ -68,10 +66,4 @@ struct async_struct { struct async_struct *prev_port; }; -/* - * Events are used to schedule things to happen at timer-interrupt - * time, instead of at rs interrupt time. - */ -#define RS_EVENT_WRITE_WAKEUP 0 - #endif /* _LINUX_SERIAL_H */ -- cgit v0.10.2 From fef21073af6f826510e41fc367df68383b63e1d2 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 5 Mar 2012 14:52:14 +0100 Subject: TTY: amiserial, use only one copy of async flags Huh, why would one want to store two copies of them? Get rid of the one from async_struct. That structure is going away as a whole soon. Signed-off-by: Jiri Slaby Cc: Geert Uytterhoeven Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/amiserial.c b/drivers/tty/amiserial.c index d5fac86..8556ca0 100644 --- a/drivers/tty/amiserial.c +++ b/drivers/tty/amiserial.c @@ -45,7 +45,7 @@ #if defined(MODULE) && defined(SERIAL_DEBUG_MCOUNT) #define DBG_CNT(s) printk("(%s): [%x] refc=%d, serc=%d, ttyc=%d -> %s\n", \ - tty->name, (info->flags), serial_driver->refcount,info->count,tty->count,s) + tty->name, (info->state->flags), serial_driver->refcount,info->count,tty->count,s) #else #define DBG_CNT(s) #endif @@ -297,7 +297,7 @@ static void receive_chars(struct async_struct *info) printk("handling break...."); #endif flag = TTY_BREAK; - if (info->flags & ASYNC_SAK) + if (info->state->flags & ASYNC_SAK) do_SAK(tty); } else if (status & UART_LSR_PE) flag = TTY_PARITY; @@ -378,7 +378,7 @@ static void check_modem_status(struct async_struct *info) if (dstatus & SER_DCD) { icount->dcd++; #ifdef CONFIG_HARD_PPS - if ((info->flags & ASYNC_HARDPPS_CD) && + if ((info->state->flags & ASYNC_HARDPPS_CD) && !(status & SER_DCD)) hardpps(); #endif @@ -388,7 +388,7 @@ static void check_modem_status(struct async_struct *info) wake_up_interruptible(&info->delta_msr_wait); } - if ((info->flags & ASYNC_CHECK_CD) && (dstatus & SER_DCD)) { + if ((info->state->flags & ASYNC_CHECK_CD) && (dstatus & SER_DCD)) { #if (defined(SERIAL_DEBUG_OPEN) || defined(SERIAL_DEBUG_INTR)) printk("ttyS%d CD now %s...", info->line, (!(status & SER_DCD)) ? "on" : "off"); @@ -403,7 +403,7 @@ static void check_modem_status(struct async_struct *info) tty_hangup(info->tty); } } - if (info->flags & ASYNC_CTS_FLOW) { + if (info->state->flags & ASYNC_CTS_FLOW) { if (info->tty->hw_stopped) { if (!(status & SER_CTS)) { #if (defined(SERIAL_DEBUG_INTR) || defined(SERIAL_DEBUG_FLOW)) @@ -516,7 +516,7 @@ static int startup(struct async_struct * info) local_irq_save(flags); - if (info->flags & ASYNC_INITIALIZED) { + if (info->state->flags & ASYNC_INITIALIZED) { free_page(page); goto errout; } @@ -569,13 +569,13 @@ static int startup(struct async_struct * info) * Set up the tty->alt_speed kludge */ if (info->tty) { - if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) + if ((info->state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) info->tty->alt_speed = 57600; - if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI) + if ((info->state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI) info->tty->alt_speed = 115200; - if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI) + if ((info->state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI) info->tty->alt_speed = 230400; - if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP) + if ((info->state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP) info->tty->alt_speed = 460800; } @@ -584,7 +584,7 @@ static int startup(struct async_struct * info) */ change_speed(info, NULL); - info->flags |= ASYNC_INITIALIZED; + info->state->flags |= ASYNC_INITIALIZED; local_irq_restore(flags); return 0; @@ -602,7 +602,7 @@ static void shutdown(struct async_struct * info) unsigned long flags; struct serial_state *state; - if (!(info->flags & ASYNC_INITIALIZED)) + if (!(info->state->flags & ASYNC_INITIALIZED)) return; state = info->state; @@ -646,7 +646,7 @@ static void shutdown(struct async_struct * info) if (info->tty) set_bit(TTY_IO_ERROR, &info->tty->flags); - info->flags &= ~ASYNC_INITIALIZED; + info->state->flags &= ~ASYNC_INITIALIZED; local_irq_restore(flags); } @@ -691,7 +691,7 @@ static void change_speed(struct async_struct *info, baud = 9600; /* B0 transition handled in rs_set_termios */ baud_base = info->state->baud_base; if (baud == 38400 && - ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST)) + ((info->state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST)) quot = info->state->custom_divisor; else { if (baud == 134) @@ -709,7 +709,7 @@ static void change_speed(struct async_struct *info, if (!baud) baud = 9600; if (baud == 38400 && - ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST)) + ((info->state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST)) quot = info->state->custom_divisor; else { if (baud == 134) @@ -728,17 +728,17 @@ static void change_speed(struct async_struct *info, /* CTS flow control flag and modem status interrupts */ info->IER &= ~UART_IER_MSI; - if (info->flags & ASYNC_HARDPPS_CD) + if (info->state->flags & ASYNC_HARDPPS_CD) info->IER |= UART_IER_MSI; if (cflag & CRTSCTS) { - info->flags |= ASYNC_CTS_FLOW; + info->state->flags |= ASYNC_CTS_FLOW; info->IER |= UART_IER_MSI; } else - info->flags &= ~ASYNC_CTS_FLOW; + info->state->flags &= ~ASYNC_CTS_FLOW; if (cflag & CLOCAL) - info->flags &= ~ASYNC_CHECK_CD; + info->state->flags &= ~ASYNC_CHECK_CD; else { - info->flags |= ASYNC_CHECK_CD; + info->state->flags |= ASYNC_CHECK_CD; info->IER |= UART_IER_MSI; } /* TBD: @@ -1080,8 +1080,6 @@ static int set_serial_info(struct async_struct * info, return -EPERM; state->flags = ((state->flags & ~ASYNC_USR_MASK) | (new_serial.flags & ASYNC_USR_MASK)); - info->flags = ((info->flags & ~ASYNC_USR_MASK) | - (new_serial.flags & ASYNC_USR_MASK)); state->custom_divisor = new_serial.custom_divisor; goto check_and_exit; } @@ -1099,15 +1097,13 @@ static int set_serial_info(struct async_struct * info, state->baud_base = new_serial.baud_base; state->flags = ((state->flags & ~ASYNC_FLAGS) | (new_serial.flags & ASYNC_FLAGS)); - info->flags = ((state->flags & ~ASYNC_INTERNAL_FLAGS) | - (info->flags & ASYNC_INTERNAL_FLAGS)); state->custom_divisor = new_serial.custom_divisor; state->close_delay = new_serial.close_delay * HZ/100; state->closing_wait = new_serial.closing_wait * HZ/100; - info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0; + info->tty->low_latency = (state->flags & ASYNC_LOW_LATENCY) ? 1 : 0; check_and_exit: - if (info->flags & ASYNC_INITIALIZED) { + if (state->flags & ASYNC_INITIALIZED) { if (((old_state.flags & ASYNC_SPD_MASK) != (state->flags & ASYNC_SPD_MASK)) || (old_state.custom_divisor != state->custom_divisor)) { @@ -1437,7 +1433,7 @@ static void rs_close(struct tty_struct *tty, struct file * filp) local_irq_restore(flags); return; } - info->flags |= ASYNC_CLOSING; + state->flags |= ASYNC_CLOSING; /* * Now we wait for the transmit buffer to clear; and we notify * the line discipline to only process XON/XOFF characters. @@ -1452,7 +1448,7 @@ static void rs_close(struct tty_struct *tty, struct file * filp) * line status register. */ info->read_status_mask &= ~UART_LSR_DR; - if (info->flags & ASYNC_INITIALIZED) { + if (state->flags & ASYNC_INITIALIZED) { /* disable receive interrupts */ custom.intena = IF_RBF; mb(); @@ -1479,7 +1475,7 @@ static void rs_close(struct tty_struct *tty, struct file * filp) } wake_up_interruptible(&info->open_wait); } - info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING); + state->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING); wake_up_interruptible(&info->close_wait); local_irq_restore(flags); } @@ -1563,7 +1559,7 @@ static void rs_hangup(struct tty_struct *tty) rs_flush_buffer(tty); shutdown(info); state->count = 0; - info->flags &= ~ASYNC_NORMAL_ACTIVE; + state->flags &= ~ASYNC_NORMAL_ACTIVE; info->tty = NULL; wake_up_interruptible(&info->open_wait); } @@ -1591,11 +1587,11 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, * until it's done, and then try again. */ if (tty_hung_up_p(filp) || - (info->flags & ASYNC_CLOSING)) { - if (info->flags & ASYNC_CLOSING) + (state->flags & ASYNC_CLOSING)) { + if (state->flags & ASYNC_CLOSING) interruptible_sleep_on(&info->close_wait); #ifdef SERIAL_DO_RESTART - return ((info->flags & ASYNC_HUP_NOTIFY) ? + return ((state->flags & ASYNC_HUP_NOTIFY) ? -EAGAIN : -ERESTARTSYS); #else return -EAGAIN; @@ -1608,7 +1604,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, */ if ((filp->f_flags & O_NONBLOCK) || (tty->flags & (1 << TTY_IO_ERROR))) { - info->flags |= ASYNC_NORMAL_ACTIVE; + state->flags |= ASYNC_NORMAL_ACTIVE; return 0; } @@ -1642,9 +1638,9 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, local_irq_restore(flags); set_current_state(TASK_INTERRUPTIBLE); if (tty_hung_up_p(filp) || - !(info->flags & ASYNC_INITIALIZED)) { + !(state->flags & ASYNC_INITIALIZED)) { #ifdef SERIAL_DO_RESTART - if (info->flags & ASYNC_HUP_NOTIFY) + if (state->flags & ASYNC_HUP_NOTIFY) retval = -EAGAIN; else retval = -ERESTARTSYS; @@ -1653,7 +1649,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, #endif break; } - if (!(info->flags & ASYNC_CLOSING) && + if (!(state->flags & ASYNC_CLOSING) && (do_clocal || (!(ciab.pra & SER_DCD)) )) break; if (signal_pending(current)) { @@ -1679,7 +1675,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, #endif if (retval) return retval; - info->flags |= ASYNC_NORMAL_ACTIVE; + state->flags |= ASYNC_NORMAL_ACTIVE; return 0; } @@ -1705,7 +1701,6 @@ static int get_async_struct(int line, struct async_struct **ret_info) init_waitqueue_head(&info->delta_msr_wait); #endif info->port = sstate->port; - info->flags = sstate->flags; info->xmit_fifo_size = sstate->xmit_fifo_size; info->line = line; info->state = sstate; @@ -1741,17 +1736,17 @@ static int rs_open(struct tty_struct *tty, struct file * filp) #ifdef SERIAL_DEBUG_OPEN printk("rs_open %s, count = %d\n", tty->name, info->state->count); #endif - info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0; + info->tty->low_latency = (info->state->flags & ASYNC_LOW_LATENCY) ? 1 : 0; /* * If the port is the middle of closing, bail out now */ if (tty_hung_up_p(filp) || - (info->flags & ASYNC_CLOSING)) { - if (info->flags & ASYNC_CLOSING) + (info->state->flags & ASYNC_CLOSING)) { + if (info->state->flags & ASYNC_CLOSING) interruptible_sleep_on(&info->close_wait); #ifdef SERIAL_DO_RESTART - return ((info->flags & ASYNC_HUP_NOTIFY) ? + return ((info->state->flags & ASYNC_HUP_NOTIFY) ? -EAGAIN : -ERESTARTSYS); #else return -EAGAIN; @@ -1799,7 +1794,6 @@ static inline void line_info(struct seq_file *m, struct serial_state *state) if (!info) { info = &scr_info; /* This is just for serial_{in,out} */ - info->flags = state->flags; info->quot = 0; info->tty = NULL; } -- cgit v0.10.2 From 0745d19abc492437e601c83281287d10202ee411 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Thu, 8 Mar 2012 21:01:16 +0100 Subject: hpsim, fix SAL handling in fw-emu The switch-cases of SAL_FREQ_BASE generate non-relocatable code. The same as for the ifs one level upper. This causes oopses early in boot because the kernel jumps to the hell instead of the offset in sal callback. So use ifs here for SAL_FREQ_BASE decision too. Isn't there any compiler directive or settings to solve that cleanly? Signed-off-by: Jiri Slaby Signed-off-by: Tony Luck Signed-off-by: Greg Kroah-Hartman diff --git a/arch/ia64/hp/sim/boot/fw-emu.c b/arch/ia64/hp/sim/boot/fw-emu.c index bf6d9d8..0216e28 100644 --- a/arch/ia64/hp/sim/boot/fw-emu.c +++ b/arch/ia64/hp/sim/boot/fw-emu.c @@ -160,28 +160,19 @@ sal_emulator (long index, unsigned long in1, unsigned long in2, */ status = 0; if (index == SAL_FREQ_BASE) { - switch (in1) { - case SAL_FREQ_BASE_PLATFORM: + if (in1 == SAL_FREQ_BASE_PLATFORM) r9 = 200000000; - break; - - case SAL_FREQ_BASE_INTERVAL_TIMER: + else if (in1 == SAL_FREQ_BASE_INTERVAL_TIMER) { /* * Is this supposed to be the cr.itc frequency * or something platform specific? The SAL * doc ain't exactly clear on this... */ r9 = 700000000; - break; - - case SAL_FREQ_BASE_REALTIME_CLOCK: + } else if (in1 == SAL_FREQ_BASE_REALTIME_CLOCK) r9 = 1; - break; - - default: + else status = -1; - break; - } } else if (index == SAL_SET_VECTORS) { ; } else if (index == SAL_GET_STATE_INFO) { -- cgit v0.10.2 From 035cfe5ac55d399169b7f61f7a111d3d7075190c Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Thu, 8 Mar 2012 21:01:17 +0100 Subject: simserial, include some headers And remove declarations which are already in the headers. Signed-off-by: Jiri Slaby Signed-off-by: Tony Luck Signed-off-by: Greg Kroah-Hartman diff --git a/arch/ia64/hp/sim/simserial.c b/arch/ia64/hp/sim/simserial.c index 0d324e8..35ae642 100644 --- a/arch/ia64/hp/sim/simserial.c +++ b/arch/ia64/hp/sim/simserial.c @@ -34,9 +34,12 @@ #include #include +#include #include #include +#include "hpsim_ssc.h" + #undef SIMSERIAL_DEBUG /* define this to get some debug information */ #define KEYBOARD_INTR 3 /* must match with simulator! */ @@ -45,11 +48,6 @@ #define IRQ_T(info) ((info->flags & ASYNC_SHARE_IRQ) ? IRQF_SHARED : IRQF_DISABLED) -#define SSC_GETCHAR 21 - -extern long ia64_ssc (long, long, long, long, int); -extern void ia64_ssc_connect_irq (long intr, long irq); - static char *serial_name = "SimSerial driver"; static char *serial_version = "0.6"; -- cgit v0.10.2 From 6efb6b77ff6fd512e9ef45b29f1940cb924cd7a6 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Thu, 8 Mar 2012 21:01:18 +0100 Subject: hpsim, initialize chip for assigned irqs Currently, when assign_irq_vector is called and the irq connected in the simulator, the irq is not ready. request_irq will return ENOSYS immediately. It is because the irq chip is unset. Hence set the chip properly to irq_type_hp_sim. And make sure this is done from both users of simulated interrupts. Also we have to set handler here, otherwise we end up in handle_bad_int resulting in spam in logs and no irqs handled. We use handle_simple_irq as these are SW interrupts that need no ACK or anything. Signed-off-by: Jiri Slaby Signed-off-by: Tony Luck Signed-off-by: Greg Kroah-Hartman diff --git a/arch/ia64/hp/sim/hpsim_irq.c b/arch/ia64/hp/sim/hpsim_irq.c index 4bd9a63..0aa70eb 100644 --- a/arch/ia64/hp/sim/hpsim_irq.c +++ b/arch/ia64/hp/sim/hpsim_irq.c @@ -10,6 +10,8 @@ #include #include +#include "hpsim_ssc.h" + static unsigned int hpsim_irq_startup(struct irq_data *data) { @@ -37,15 +39,37 @@ static struct irq_chip irq_type_hp_sim = { .irq_set_affinity = hpsim_set_affinity_noop, }; +static void hpsim_irq_set_chip(int irq) +{ + struct irq_chip *chip = irq_get_chip(irq); + + if (chip == &no_irq_chip) + irq_set_chip(irq, &irq_type_hp_sim); +} + +static void hpsim_connect_irq(int intr, int irq) +{ + ia64_ssc(intr, irq, 0, 0, SSC_CONNECT_INTERRUPT); +} + +int hpsim_get_irq(int intr) +{ + int irq = assign_irq_vector(AUTO_ASSIGN); + + if (irq >= 0) { + hpsim_irq_set_chip(irq); + irq_set_handler(irq, handle_simple_irq); + hpsim_connect_irq(intr, irq); + } + + return irq; +} + void __init hpsim_irq_init (void) { int i; - for_each_active_irq(i) { - struct irq_chip *chip = irq_get_chip(i); - - if (chip == &no_irq_chip) - irq_set_chip(i, &irq_type_hp_sim); - } + for_each_active_irq(i) + hpsim_irq_set_chip(i); } diff --git a/arch/ia64/hp/sim/hpsim_setup.c b/arch/ia64/hp/sim/hpsim_setup.c index f629e90..664a540 100644 --- a/arch/ia64/hp/sim/hpsim_setup.c +++ b/arch/ia64/hp/sim/hpsim_setup.c @@ -26,12 +26,6 @@ #include "hpsim_ssc.h" void -ia64_ssc_connect_irq (long intr, long irq) -{ - ia64_ssc(intr, irq, 0, 0, SSC_CONNECT_INTERRUPT); -} - -void ia64_ctl_trace (long on) { ia64_ssc(on, 0, 0, 0, SSC_CTL_TRACE); diff --git a/arch/ia64/hp/sim/simeth.c b/arch/ia64/hp/sim/simeth.c index 47afcc6..e343357 100644 --- a/arch/ia64/hp/sim/simeth.c +++ b/arch/ia64/hp/sim/simeth.c @@ -129,17 +129,6 @@ netdev_probe(char *name, unsigned char *ether) static inline int -netdev_connect(int irq) -{ - /* XXX Fix me - * this does not support multiple cards - * also no return value - */ - ia64_ssc_connect_irq(NETWORK_INTR, irq); - return 0; -} - -static inline int netdev_attach(int fd, int irq, unsigned int ipaddr) { /* this puts the host interface in the right mode (start interrupting) */ @@ -226,15 +215,13 @@ simeth_probe1(void) return err; } - if ((rc = assign_irq_vector(AUTO_ASSIGN)) < 0) - panic("%s: out of interrupt vectors!\n", __func__); - dev->irq = rc; - /* * attach the interrupt in the simulator, this does enable interrupts * until a netdev_attach() is called */ - netdev_connect(dev->irq); + if ((rc = hpsim_get_irq(NETWORK_INTR)) < 0) + panic("%s: out of interrupt vectors!\n", __func__); + dev->irq = rc; printk(KERN_INFO "%s: hosteth=%s simfd=%d, HwAddr", dev->name, simeth_device, local->simfd); diff --git a/arch/ia64/hp/sim/simserial.c b/arch/ia64/hp/sim/simserial.c index 35ae642..3a079de 100644 --- a/arch/ia64/hp/sim/simserial.c +++ b/arch/ia64/hp/sim/simserial.c @@ -933,11 +933,10 @@ simrs_init (void) if (state->type == PORT_UNKNOWN) continue; if (!state->irq) { - if ((rc = assign_irq_vector(AUTO_ASSIGN)) < 0) + if ((rc = hpsim_get_irq(KEYBOARD_INTR)) < 0) panic("%s: out of interrupt vectors!\n", __func__); state->irq = rc; - ia64_ssc_connect_irq(KEYBOARD_INTR, state->irq); } printk(KERN_INFO "ttyS%d at 0x%04lx (irq = %d) is a %s\n", diff --git a/arch/ia64/include/asm/hpsim.h b/arch/ia64/include/asm/hpsim.h index 892ab19..0fe5022 100644 --- a/arch/ia64/include/asm/hpsim.h +++ b/arch/ia64/include/asm/hpsim.h @@ -10,7 +10,7 @@ int simcons_register(void); struct tty_driver; extern struct tty_driver *hp_simserial_driver; -void ia64_ssc_connect_irq(long intr, long irq); +extern int hpsim_get_irq(int intr); void ia64_ctl_trace(long on); #endif -- cgit v0.10.2 From 9e12dd5fce1c676e709625bd2f55dc83664c3c93 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Thu, 8 Mar 2012 21:01:19 +0100 Subject: simserial, bail out when request_irq fails Without this, the code succeeds when the port is opened by root and we get unwanted interrupts storm on the first key stroke. Instead of that, tell the user we failed and that we won't continue. I suppose, the code was copied from the serial layer where we may want to change the irq number, so we must allow open even of the failing port. This is not the case for this driver at all. Signed-off-by: Jiri Slaby Signed-off-by: Tony Luck Signed-off-by: Greg Kroah-Hartman diff --git a/arch/ia64/hp/sim/simserial.c b/arch/ia64/hp/sim/simserial.c index 3a079de..8f68972 100644 --- a/arch/ia64/hp/sim/simserial.c +++ b/arch/ia64/hp/sim/simserial.c @@ -692,15 +692,8 @@ startup(struct async_struct *info) handler = rs_interrupt_single; retval = request_irq(state->irq, handler, IRQ_T(info), "simserial", NULL); - if (retval) { - if (capable(CAP_SYS_ADMIN)) { - if (info->tty) - set_bit(TTY_IO_ERROR, - &info->tty->flags); - retval = 0; - } + if (retval) goto errout; - } } /* -- cgit v0.10.2 From 979b6d89766ed573bca6a6e902193c4cad502909 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 5 Mar 2012 14:52:15 +0100 Subject: TTY: simserial, use only one copy of async flags The same as for amiserial. Use only one instance of the flags. Also remove them from async_struct now. Nobody else uses them. Signed-off-by: Jiri Slaby Cc: Tony Luck Cc: Fenghua Yu Signed-off-by: Greg Kroah-Hartman diff --git a/arch/ia64/hp/sim/simserial.c b/arch/ia64/hp/sim/simserial.c index 8f68972..a08a53f 100644 --- a/arch/ia64/hp/sim/simserial.c +++ b/arch/ia64/hp/sim/simserial.c @@ -46,7 +46,7 @@ #define NR_PORTS 1 /* only one port for now */ -#define IRQ_T(info) ((info->flags & ASYNC_SHARE_IRQ) ? IRQF_SHARED : IRQF_DISABLED) +#define IRQ_T(state) ((state->flags & ASYNC_SHARE_IRQ) ? IRQF_SHARED : IRQF_DISABLED) static char *serial_name = "SimSerial driver"; static char *serial_version = "0.6"; @@ -455,12 +455,11 @@ static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios) static void shutdown(struct async_struct * info) { unsigned long flags; - struct serial_state *state; + struct serial_state *state = info->state; int retval; - if (!(info->flags & ASYNC_INITIALIZED)) return; - - state = info->state; + if (!(state->flags & ASYNC_INITIALIZED)) + return; #ifdef SIMSERIAL_DEBUG printk("Shutting down serial port %d (irq %d)....", info->line, @@ -487,7 +486,8 @@ static void shutdown(struct async_struct * info) if (IRQ_ports[state->irq]) { free_irq(state->irq, NULL); retval = request_irq(state->irq, rs_interrupt_single, - IRQ_T(info), "serial", NULL); + IRQ_T(state), "serial", + NULL); if (retval) printk(KERN_ERR "serial shutdown: request_irq: error %d" @@ -503,7 +503,7 @@ static void shutdown(struct async_struct * info) if (info->tty) set_bit(TTY_IO_ERROR, &info->tty->flags); - info->flags &= ~ASYNC_INITIALIZED; + state->flags &= ~ASYNC_INITIALIZED; } local_irq_restore(flags); } @@ -560,7 +560,7 @@ static void rs_close(struct tty_struct *tty, struct file * filp) local_irq_restore(flags); return; } - info->flags |= ASYNC_CLOSING; + state->flags |= ASYNC_CLOSING; local_irq_restore(flags); /* @@ -576,7 +576,7 @@ static void rs_close(struct tty_struct *tty, struct file * filp) schedule_timeout_interruptible(info->close_delay); wake_up_interruptible(&info->open_wait); } - info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING); + state->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING); wake_up_interruptible(&info->close_wait); } @@ -600,15 +600,13 @@ static void rs_hangup(struct tty_struct *tty) printk("rs_hangup: called\n"); #endif - state = info->state; - rs_flush_buffer(tty); - if (info->flags & ASYNC_CLOSING) + if (state->flags & ASYNC_CLOSING) return; shutdown(info); state->count = 0; - info->flags &= ~ASYNC_NORMAL_ACTIVE; + state->flags &= ~ASYNC_NORMAL_ACTIVE; info->tty = NULL; wake_up_interruptible(&info->open_wait); } @@ -633,7 +631,6 @@ static int get_async_struct(int line, struct async_struct **ret_info) init_waitqueue_head(&info->open_wait); init_waitqueue_head(&info->close_wait); info->port = sstate->port; - info->flags = sstate->flags; info->xmit_fifo_size = sstate->xmit_fifo_size; info->line = line; info->state = sstate; @@ -661,7 +658,7 @@ startup(struct async_struct *info) local_irq_save(flags); - if (info->flags & ASYNC_INITIALIZED) { + if (state->flags & ASYNC_INITIALIZED) { free_page(page); goto errout; } @@ -691,7 +688,8 @@ startup(struct async_struct *info) } else handler = rs_interrupt_single; - retval = request_irq(state->irq, handler, IRQ_T(info), "simserial", NULL); + retval = request_irq(state->irq, handler, IRQ_T(state), + "simserial", NULL); if (retval) goto errout; } @@ -721,17 +719,17 @@ startup(struct async_struct *info) * Set up the tty->alt_speed kludge */ if (info->tty) { - if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) + if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) info->tty->alt_speed = 57600; - if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI) + if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI) info->tty->alt_speed = 115200; - if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI) + if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI) info->tty->alt_speed = 230400; - if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP) + if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP) info->tty->alt_speed = 460800; } - info->flags |= ASYNC_INITIALIZED; + state->flags |= ASYNC_INITIALIZED; local_irq_restore(flags); return 0; @@ -762,7 +760,7 @@ static int rs_open(struct tty_struct *tty, struct file * filp) #ifdef SIMSERIAL_DEBUG printk("rs_open %s, count = %d\n", tty->name, info->state->count); #endif - info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0; + info->tty->low_latency = (info->state->flags & ASYNC_LOW_LATENCY) ? 1 : 0; if (!tmp_buf) { page = get_zeroed_page(GFP_KERNEL); @@ -778,11 +776,11 @@ static int rs_open(struct tty_struct *tty, struct file * filp) * If the port is the middle of closing, bail out now */ if (tty_hung_up_p(filp) || - (info->flags & ASYNC_CLOSING)) { - if (info->flags & ASYNC_CLOSING) + (info->state->flags & ASYNC_CLOSING)) { + if (info->state->flags & ASYNC_CLOSING) interruptible_sleep_on(&info->close_wait); #ifdef SERIAL_DO_RESTART - return ((info->flags & ASYNC_HUP_NOTIFY) ? + return ((info->state->flags & ASYNC_HUP_NOTIFY) ? -EAGAIN : -ERESTARTSYS); #else return -EAGAIN; diff --git a/include/linux/serialP.h b/include/linux/serialP.h index beaf39f..6741f57 100644 --- a/include/linux/serialP.h +++ b/include/linux/serialP.h @@ -43,7 +43,6 @@ struct serial_state { struct async_struct { unsigned long port; - int flags; int xmit_fifo_size; struct serial_state *state; struct tty_struct *tty; -- cgit v0.10.2 From d852256389f1bcf506710ea5de77debde40013b9 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 5 Mar 2012 14:52:16 +0100 Subject: TTY: simserial/amiserial, use one instance of other members This means: * close_delay * closing_wait * line * port * xmit_fifo_size This actually fixes a bug in amiserial. It initializes one and uses the other of the close delays. Yes, duplicating structure members is evil. Signed-off-by: Jiri Slaby Cc: Geert Uytterhoeven Cc: Tony Luck Cc: Fenghua Yu Signed-off-by: Greg Kroah-Hartman diff --git a/arch/ia64/hp/sim/simserial.c b/arch/ia64/hp/sim/simserial.c index a08a53f..d32b759 100644 --- a/arch/ia64/hp/sim/simserial.c +++ b/arch/ia64/hp/sim/simserial.c @@ -553,7 +553,7 @@ static void rs_close(struct tty_struct *tty, struct file * filp) } if (--state->count < 0) { printk(KERN_ERR "rs_close: bad serial port count for ttys%d: %d\n", - info->line, state->count); + state->line, state->count); state->count = 0; } if (state->count) { @@ -572,8 +572,8 @@ static void rs_close(struct tty_struct *tty, struct file * filp) tty_ldisc_flush(tty); info->tty = NULL; if (info->blocked_open) { - if (info->close_delay) - schedule_timeout_interruptible(info->close_delay); + if (state->close_delay) + schedule_timeout_interruptible(state->close_delay); wake_up_interruptible(&info->open_wait); } state->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING); @@ -630,9 +630,6 @@ static int get_async_struct(int line, struct async_struct **ret_info) } init_waitqueue_head(&info->open_wait); init_waitqueue_head(&info->close_wait); - info->port = sstate->port; - info->xmit_fifo_size = sstate->xmit_fifo_size; - info->line = line; info->state = sstate; if (sstate->info) { kfree(info); diff --git a/drivers/tty/amiserial.c b/drivers/tty/amiserial.c index 8556ca0..5540216 100644 --- a/drivers/tty/amiserial.c +++ b/drivers/tty/amiserial.c @@ -723,7 +723,7 @@ static void change_speed(struct async_struct *info, if (!quot) quot = baud_base / 9600; info->quot = quot; - info->timeout = ((info->xmit_fifo_size*HZ*bits*quot) / baud_base); + info->timeout = ((info->state->xmit_fifo_size*HZ*bits*quot) / baud_base); info->timeout += HZ/50; /* Add .02 seconds of slop */ /* CTS flow control flag and modem status interrupts */ @@ -1425,7 +1425,7 @@ static void rs_close(struct tty_struct *tty, struct file * filp) } if (--state->count < 0) { printk("rs_close: bad serial port count for ttys%d: %d\n", - info->line, state->count); + state->line, state->count); state->count = 0; } if (state->count) { @@ -1439,8 +1439,8 @@ static void rs_close(struct tty_struct *tty, struct file * filp) * the line discipline to only process XON/XOFF characters. */ tty->closing = 1; - if (info->closing_wait != ASYNC_CLOSING_WAIT_NONE) - tty_wait_until_sent(tty, info->closing_wait); + if (state->closing_wait != ASYNC_CLOSING_WAIT_NONE) + tty_wait_until_sent(tty, state->closing_wait); /* * At this point we stop accepting input. To do this, we * disable the receive line status interrupts, and tell the @@ -1470,8 +1470,8 @@ static void rs_close(struct tty_struct *tty, struct file * filp) tty->closing = 0; info->tty = NULL; if (info->blocked_open) { - if (info->close_delay) { - msleep_interruptible(jiffies_to_msecs(info->close_delay)); + if (state->close_delay) { + msleep_interruptible(jiffies_to_msecs(state->close_delay)); } wake_up_interruptible(&info->open_wait); } @@ -1492,7 +1492,7 @@ static void rs_wait_until_sent(struct tty_struct *tty, int timeout) if (serial_paranoia_check(info, tty->name, "rs_wait_until_sent")) return; - if (info->xmit_fifo_size == 0) + if (info->state->xmit_fifo_size == 0) return; /* Just in case.... */ orig_jiffies = jiffies; @@ -1505,7 +1505,7 @@ static void rs_wait_until_sent(struct tty_struct *tty, int timeout) * Note: we have to use pretty tight timings here to satisfy * the NIST-PCTS. */ - char_time = (info->timeout - HZ/50) / info->xmit_fifo_size; + char_time = (info->timeout - HZ/50) / info->state->xmit_fifo_size; char_time = char_time / 5; if (char_time == 0) char_time = 1; @@ -1700,9 +1700,6 @@ static int get_async_struct(int line, struct async_struct **ret_info) init_waitqueue_head(&info->close_wait); init_waitqueue_head(&info->delta_msr_wait); #endif - info->port = sstate->port; - info->xmit_fifo_size = sstate->xmit_fifo_size; - info->line = line; info->state = sstate; if (sstate->info) { kfree(info); diff --git a/include/linux/serialP.h b/include/linux/serialP.h index 6741f57..6ce488c 100644 --- a/include/linux/serialP.h +++ b/include/linux/serialP.h @@ -42,8 +42,6 @@ struct serial_state { }; struct async_struct { - unsigned long port; - int xmit_fifo_size; struct serial_state *state; struct tty_struct *tty; int read_status_mask; @@ -51,11 +49,8 @@ struct async_struct { int timeout; int quot; int x_char; /* xon/xoff character */ - int close_delay; - unsigned short closing_wait; int IER; /* Interrupt Enable Register */ int MCR; /* Modem control register */ - int line; int blocked_open; /* # of blocked opens */ struct circ_buf xmit; wait_queue_head_t open_wait; -- cgit v0.10.2 From 964105b501071e8a0e9feb1d0e4b3e46508bc38e Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 5 Mar 2012 14:52:17 +0100 Subject: TTY: simserial, remove support of shared interrupts It never worked there. The ISR was never written for that kind of stuff. So remove all that crap with a hash of linked lists and pass the pointer directly to the ISR. BTW this answers the question there: * I don't know exactly why they don't use the dev_id opaque data * pointer instead of this extra lookup table -> Because they thought they will support more devices bound to a single interrupt w/o IRQF_SHARED. They would need exactly the hash there. What I don't understand is rebinding of the interrupt in the shutdown path. They perhaps meant to do just synchronize_irq? In any case, this is all gone and free_irq there properly. By removing the hash we save some bits (exactly NR_IRQS * 8 bytes of .bss and over a kilo of .text): before: text data bss dec hex filename 19600 320 8227 28147 6df3 ../a/ia64/arch/ia64/hp/sim/simserial.o after: text data bss dec hex filename 18568 320 28 18916 49e4 ../a/ia64/arch/ia64/hp/sim/simserial.o Note that a shared interrupt could not work too. request_irq requires data parameter to be non-NULL. So the whole IRQ_T exercise was pointless. Finally, this helps us remove another two members of async_struct :). Signed-off-by: Jiri Slaby Cc: Tony Luck Cc: Fenghua Yu Signed-off-by: Greg Kroah-Hartman diff --git a/arch/ia64/hp/sim/simserial.c b/arch/ia64/hp/sim/simserial.c index d32b759..c35552d 100644 --- a/arch/ia64/hp/sim/simserial.c +++ b/arch/ia64/hp/sim/simserial.c @@ -92,8 +92,6 @@ static struct serial_uart_config uart_config[] = { struct tty_driver *hp_simserial_driver; -static struct async_struct *IRQ_ports[NR_IRQS]; - static struct console *console; static unsigned char *tmp_buf; @@ -167,14 +165,9 @@ static void receive_chars(struct tty_struct *tty) */ static irqreturn_t rs_interrupt_single(int irq, void *dev_id) { - struct async_struct * info; + struct async_struct *info = dev_id; - /* - * I don't know exactly why they don't use the dev_id opaque data - * pointer instead of this extra lookup table - */ - info = IRQ_ports[irq]; - if (!info || !info->tty) { + if (!info->tty) { printk(KERN_INFO "simrs_interrupt_single: info|tty=0 info=%p problem\n", info); return IRQ_NONE; } @@ -456,7 +449,6 @@ static void shutdown(struct async_struct * info) { unsigned long flags; struct serial_state *state = info->state; - int retval; if (!(state->flags & ASYNC_INITIALIZED)) return; @@ -468,33 +460,8 @@ static void shutdown(struct async_struct * info) local_irq_save(flags); { - /* - * First unlink the serial port from the IRQ chain... - */ - if (info->next_port) - info->next_port->prev_port = info->prev_port; - if (info->prev_port) - info->prev_port->next_port = info->next_port; - else - IRQ_ports[state->irq] = info->next_port; - - /* - * Free the IRQ, if necessary - */ - if (state->irq && (!IRQ_ports[state->irq] || - !IRQ_ports[state->irq]->next_port)) { - if (IRQ_ports[state->irq]) { - free_irq(state->irq, NULL); - retval = request_irq(state->irq, rs_interrupt_single, - IRQ_T(state), "serial", - NULL); - - if (retval) - printk(KERN_ERR "serial shutdown: request_irq: error %d" - " Couldn't reacquire IRQ.\n", retval); - } else - free_irq(state->irq, NULL); - } + if (state->irq) + free_irq(state->irq, info); if (info->xmit.buf) { free_page((unsigned long) info->xmit.buf); @@ -645,7 +612,6 @@ startup(struct async_struct *info) { unsigned long flags; int retval=0; - irq_handler_t handler; struct serial_state *state= info->state; unsigned long page; @@ -677,29 +643,13 @@ startup(struct async_struct *info) /* * Allocate the IRQ if necessary */ - if (state->irq && (!IRQ_ports[state->irq] || - !IRQ_ports[state->irq]->next_port)) { - if (IRQ_ports[state->irq]) { - retval = -EBUSY; - goto errout; - } else - handler = rs_interrupt_single; - - retval = request_irq(state->irq, handler, IRQ_T(state), - "simserial", NULL); + if (state->irq) { + retval = request_irq(state->irq, rs_interrupt_single, + IRQ_T(state), "simserial", info); if (retval) goto errout; } - /* - * Insert serial port into IRQ chain. - */ - info->prev_port = NULL; - info->next_port = IRQ_ports[state->irq]; - if (info->next_port) - info->next_port->prev_port = info; - IRQ_ports[state->irq] = info; - if (info->tty) clear_bit(TTY_IO_ERROR, &info->tty->flags); info->xmit.head = info->xmit.tail = 0; diff --git a/include/linux/serialP.h b/include/linux/serialP.h index 6ce488c..b8543f9 100644 --- a/include/linux/serialP.h +++ b/include/linux/serialP.h @@ -56,8 +56,6 @@ struct async_struct { wait_queue_head_t open_wait; wait_queue_head_t close_wait; wait_queue_head_t delta_msr_wait; - struct async_struct *next_port; /* For the linked list */ - struct async_struct *prev_port; }; #endif /* _LINUX_SERIAL_H */ -- cgit v0.10.2 From 2f8c521a1d41faf96f729c76991eb4ad70294513 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 5 Mar 2012 14:52:18 +0100 Subject: TTY: simserial, remove IRQ_T We do not set ASYNC_SHARE_IRQ anywhere. And since IRQF_DISABLED is a noop, pass zero to request_irq directly instead of this ugly macro. Signed-off-by: Jiri Slaby Cc: Tony Luck Cc: Fenghua Yu Signed-off-by: Greg Kroah-Hartman diff --git a/arch/ia64/hp/sim/simserial.c b/arch/ia64/hp/sim/simserial.c index c35552d..8b5a134 100644 --- a/arch/ia64/hp/sim/simserial.c +++ b/arch/ia64/hp/sim/simserial.c @@ -46,8 +46,6 @@ #define NR_PORTS 1 /* only one port for now */ -#define IRQ_T(state) ((state->flags & ASYNC_SHARE_IRQ) ? IRQF_SHARED : IRQF_DISABLED) - static char *serial_name = "SimSerial driver"; static char *serial_version = "0.6"; @@ -644,8 +642,8 @@ startup(struct async_struct *info) * Allocate the IRQ if necessary */ if (state->irq) { - retval = request_irq(state->irq, rs_interrupt_single, - IRQ_T(state), "simserial", info); + retval = request_irq(state->irq, rs_interrupt_single, 0, + "simserial", info); if (retval) goto errout; } -- cgit v0.10.2 From 13c9062122a8d05e0881ca8bd9037d2e57e56860 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 5 Mar 2012 14:52:19 +0100 Subject: TTY: amiserial, remove IRQ_ports They used to work as a storage for 'info' pointer used in ISRs. They are not really needed. Just pass the pointer through request_irq to the handlers. It was set to NULL and tested in the ISRs, but we do not need the tests as we disable all the interrupts at the same places where NULL sets were. Signed-off-by: Jiri Slaby Cc: Geert Uytterhoeven Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/amiserial.c b/drivers/tty/amiserial.c index 5540216..7607c6e 100644 --- a/drivers/tty/amiserial.c +++ b/drivers/tty/amiserial.c @@ -100,8 +100,6 @@ static struct tty_driver *serial_driver; /* number of characters left in xmit buffer before we ask for more */ #define WAKEUP_CHARS 256 -static struct async_struct *IRQ_ports; - static unsigned char current_ctl_bits; static void change_speed(struct async_struct *info, struct ktermios *old); @@ -439,7 +437,7 @@ static void check_modem_status(struct async_struct *info) static irqreturn_t ser_vbl_int( int irq, void *data) { /* vbl is just a periodic interrupt we tie into to update modem status */ - struct async_struct * info = IRQ_ports; + struct async_struct *info = data; /* * TBD - is it better to unregister from this interrupt or to * ignore it if MSI is clear ? @@ -451,13 +449,13 @@ static irqreturn_t ser_vbl_int( int irq, void *data) static irqreturn_t ser_rx_int(int irq, void *dev_id) { - struct async_struct * info; + struct serial_state *state = dev_id; + struct async_struct *info = state->info; #ifdef SERIAL_DEBUG_INTR printk("ser_rx_int..."); #endif - info = IRQ_ports; if (!info || !info->tty) return IRQ_NONE; @@ -470,14 +468,14 @@ static irqreturn_t ser_rx_int(int irq, void *dev_id) static irqreturn_t ser_tx_int(int irq, void *dev_id) { - struct async_struct * info; + struct serial_state *state = dev_id; + struct async_struct *info = state->info; if (custom.serdatr & SDR_TBE) { #ifdef SERIAL_DEBUG_INTR printk("ser_tx_int..."); #endif - info = IRQ_ports; if (!info || !info->tty) return IRQ_NONE; @@ -554,8 +552,6 @@ static int startup(struct async_struct * info) /* remember current state of the DCD and CTS bits */ current_ctl_bits = ciab.pra & (SER_DCD | SER_CTS | SER_DSR); - IRQ_ports = info; - info->MCR = 0; if (info->tty->termios->c_cflag & CBAUD) info->MCR = SER_DTR | SER_RTS; @@ -619,8 +615,6 @@ static void shutdown(struct async_struct * info) */ wake_up_interruptible(&info->delta_msr_wait); - IRQ_ports = NULL; - /* * Free the IRQ, if necessary */ @@ -1913,8 +1907,6 @@ static int __init amiga_serial_probe(struct platform_device *pdev) if (!serial_driver) return -ENOMEM; - IRQ_ports = NULL; - show_serial_version(); /* Initialize the tty_driver structure */ -- cgit v0.10.2 From 916b765675b7044bd5895b7430a2aa2c63ea4545 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 5 Mar 2012 14:52:20 +0100 Subject: TTY: serialP, merge serial_state and async_struct This is the final step to get rid of the one of the structures. A further cleanup will follow. And I struct serial_state deserves cease to exist after a switch to tty_port too. While changing the lines, it removes also pointless tty->driver_data casts. Signed-off-by: Jiri Slaby Cc: Geert Uytterhoeven Cc: Tony Luck Cc: Fenghua Yu Signed-off-by: Greg Kroah-Hartman diff --git a/arch/ia64/hp/sim/simserial.c b/arch/ia64/hp/sim/simserial.c index 8b5a134..7b6e60e 100644 --- a/arch/ia64/hp/sim/simserial.c +++ b/arch/ia64/hp/sim/simserial.c @@ -163,7 +163,7 @@ static void receive_chars(struct tty_struct *tty) */ static irqreturn_t rs_interrupt_single(int irq, void *dev_id) { - struct async_struct *info = dev_id; + struct serial_state *info = dev_id; if (!info->tty) { printk(KERN_INFO "simrs_interrupt_single: info|tty=0 info=%p problem\n", info); @@ -185,7 +185,7 @@ static irqreturn_t rs_interrupt_single(int irq, void *dev_id) static int rs_put_char(struct tty_struct *tty, unsigned char ch) { - struct async_struct *info = (struct async_struct *)tty->driver_data; + struct serial_state *info = tty->driver_data; unsigned long flags; if (!tty || !info->xmit.buf) @@ -202,12 +202,11 @@ static int rs_put_char(struct tty_struct *tty, unsigned char ch) return 1; } -static void transmit_chars(struct async_struct *info, int *intr_done) +static void transmit_chars(struct serial_state *info, int *intr_done) { int count; unsigned long flags; - local_irq_save(flags); if (info->x_char) { @@ -215,7 +214,7 @@ static void transmit_chars(struct async_struct *info, int *intr_done) console->write(console, &c, 1); - info->state->icount.tx++; + info->icount.tx++; info->x_char = 0; goto out; @@ -256,7 +255,7 @@ out: static void rs_flush_chars(struct tty_struct *tty) { - struct async_struct *info = (struct async_struct *)tty->driver_data; + struct serial_state *info = tty->driver_data; if (info->xmit.head == info->xmit.tail || tty->stopped || tty->hw_stopped || !info->xmit.buf) @@ -269,8 +268,8 @@ static void rs_flush_chars(struct tty_struct *tty) static int rs_write(struct tty_struct * tty, const unsigned char *buf, int count) { + struct serial_state *info = tty->driver_data; int c, ret = 0; - struct async_struct *info = (struct async_struct *)tty->driver_data; unsigned long flags; if (!tty || !info->xmit.buf || !tmp_buf) return 0; @@ -303,21 +302,21 @@ static int rs_write(struct tty_struct * tty, static int rs_write_room(struct tty_struct *tty) { - struct async_struct *info = (struct async_struct *)tty->driver_data; + struct serial_state *info = tty->driver_data; return CIRC_SPACE(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE); } static int rs_chars_in_buffer(struct tty_struct *tty) { - struct async_struct *info = (struct async_struct *)tty->driver_data; + struct serial_state *info = tty->driver_data; return CIRC_CNT(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE); } static void rs_flush_buffer(struct tty_struct *tty) { - struct async_struct *info = (struct async_struct *)tty->driver_data; + struct serial_state *info = tty->driver_data; unsigned long flags; local_irq_save(flags); @@ -333,7 +332,7 @@ static void rs_flush_buffer(struct tty_struct *tty) */ static void rs_send_xchar(struct tty_struct *tty, char ch) { - struct async_struct *info = (struct async_struct *)tty->driver_data; + struct serial_state *info = tty->driver_data; info->x_char = ch; if (ch) { @@ -362,7 +361,7 @@ static void rs_throttle(struct tty_struct * tty) static void rs_unthrottle(struct tty_struct * tty) { - struct async_struct *info = (struct async_struct *)tty->driver_data; + struct serial_state *info = tty->driver_data; if (I_IXOFF(tty)) { if (info->x_char) @@ -443,23 +442,22 @@ static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios) * This routine will shutdown a serial port; interrupts are disabled, and * DTR is dropped if the hangup on close termio flag is on. */ -static void shutdown(struct async_struct * info) +static void shutdown(struct serial_state *info) { unsigned long flags; - struct serial_state *state = info->state; - if (!(state->flags & ASYNC_INITIALIZED)) + if (!(info->flags & ASYNC_INITIALIZED)) return; #ifdef SIMSERIAL_DEBUG - printk("Shutting down serial port %d (irq %d)....", info->line, - state->irq); + printk("Shutting down serial port %d (irq %d)...\n", info->line, + info->irq); #endif local_irq_save(flags); { - if (state->irq) - free_irq(state->irq, info); + if (info->irq) + free_irq(info->irq, info); if (info->xmit.buf) { free_page((unsigned long) info->xmit.buf); @@ -468,7 +466,7 @@ static void shutdown(struct async_struct * info) if (info->tty) set_bit(TTY_IO_ERROR, &info->tty->flags); - state->flags &= ~ASYNC_INITIALIZED; + info->flags &= ~ASYNC_INITIALIZED; } local_irq_restore(flags); } @@ -485,13 +483,11 @@ static void shutdown(struct async_struct * info) */ static void rs_close(struct tty_struct *tty, struct file * filp) { - struct async_struct * info = (struct async_struct *)tty->driver_data; - struct serial_state *state; + struct serial_state *info = tty->driver_data; unsigned long flags; - if (!info ) return; - - state = info->state; + if (!info) + return; local_irq_save(flags); if (tty_hung_up_p(filp)) { @@ -502,30 +498,30 @@ static void rs_close(struct tty_struct *tty, struct file * filp) return; } #ifdef SIMSERIAL_DEBUG - printk("rs_close ttys%d, count = %d\n", info->line, state->count); + printk("rs_close ttys%d, count = %d\n", info->line, info->count); #endif - if ((tty->count == 1) && (state->count != 1)) { + if ((tty->count == 1) && (info->count != 1)) { /* * Uh, oh. tty->count is 1, which means that the tty - * structure will be freed. state->count should always + * structure will be freed. info->count should always * be one in these conditions. If it's greater than * one, we've got real problems, since it means the * serial port won't be shutdown. */ printk(KERN_ERR "rs_close: bad serial port count; tty->count is 1, " - "state->count is %d\n", state->count); - state->count = 1; + "info->count is %d\n", info->count); + info->count = 1; } - if (--state->count < 0) { + if (--info->count < 0) { printk(KERN_ERR "rs_close: bad serial port count for ttys%d: %d\n", - state->line, state->count); - state->count = 0; + info->line, info->count); + info->count = 0; } - if (state->count) { + if (info->count) { local_irq_restore(flags); return; } - state->flags |= ASYNC_CLOSING; + info->flags |= ASYNC_CLOSING; local_irq_restore(flags); /* @@ -537,11 +533,11 @@ static void rs_close(struct tty_struct *tty, struct file * filp) tty_ldisc_flush(tty); info->tty = NULL; if (info->blocked_open) { - if (state->close_delay) - schedule_timeout_interruptible(state->close_delay); + if (info->close_delay) + schedule_timeout_interruptible(info->close_delay); wake_up_interruptible(&info->open_wait); } - state->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING); + info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING); wake_up_interruptible(&info->close_wait); } @@ -558,59 +554,28 @@ static void rs_wait_until_sent(struct tty_struct *tty, int timeout) */ static void rs_hangup(struct tty_struct *tty) { - struct async_struct * info = (struct async_struct *)tty->driver_data; - struct serial_state *state = info->state; + struct serial_state *info = tty->driver_data; #ifdef SIMSERIAL_DEBUG printk("rs_hangup: called\n"); #endif rs_flush_buffer(tty); - if (state->flags & ASYNC_CLOSING) + if (info->flags & ASYNC_CLOSING) return; shutdown(info); - state->count = 0; - state->flags &= ~ASYNC_NORMAL_ACTIVE; + info->count = 0; + info->flags &= ~ASYNC_NORMAL_ACTIVE; info->tty = NULL; wake_up_interruptible(&info->open_wait); } -static int get_async_struct(int line, struct async_struct **ret_info) -{ - struct async_struct *info; - struct serial_state *sstate; - - sstate = rs_table + line; - sstate->count++; - if (sstate->info) { - *ret_info = sstate->info; - return 0; - } - info = kzalloc(sizeof(struct async_struct), GFP_KERNEL); - if (!info) { - sstate->count--; - return -ENOMEM; - } - init_waitqueue_head(&info->open_wait); - init_waitqueue_head(&info->close_wait); - info->state = sstate; - if (sstate->info) { - kfree(info); - *ret_info = sstate->info; - return 0; - } - *ret_info = sstate->info = info; - return 0; -} - -static int -startup(struct async_struct *info) +static int startup(struct serial_state *state) { unsigned long flags; int retval=0; - struct serial_state *state= info->state; unsigned long page; page = get_zeroed_page(GFP_KERNEL); @@ -625,17 +590,18 @@ startup(struct async_struct *info) } if (!state->port || !state->type) { - if (info->tty) set_bit(TTY_IO_ERROR, &info->tty->flags); + if (state->tty) + set_bit(TTY_IO_ERROR, &state->tty->flags); free_page(page); goto errout; } - if (info->xmit.buf) + if (state->xmit.buf) free_page(page); else - info->xmit.buf = (unsigned char *) page; + state->xmit.buf = (unsigned char *) page; #ifdef SIMSERIAL_DEBUG - printk("startup: ttys%d (irq %d)...", info->line, state->irq); + printk("startup: ttys%d (irq %d)...", state->line, state->irq); #endif /* @@ -643,14 +609,15 @@ startup(struct async_struct *info) */ if (state->irq) { retval = request_irq(state->irq, rs_interrupt_single, 0, - "simserial", info); + "simserial", state); if (retval) goto errout; } - if (info->tty) clear_bit(TTY_IO_ERROR, &info->tty->flags); + if (state->tty) + clear_bit(TTY_IO_ERROR, &state->tty->flags); - info->xmit.head = info->xmit.tail = 0; + state->xmit.head = state->xmit.tail = 0; #if 0 /* @@ -663,15 +630,15 @@ startup(struct async_struct *info) /* * Set up the tty->alt_speed kludge */ - if (info->tty) { + if (state->tty) { if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) - info->tty->alt_speed = 57600; + state->tty->alt_speed = 57600; if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI) - info->tty->alt_speed = 115200; + state->tty->alt_speed = 115200; if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI) - info->tty->alt_speed = 230400; + state->tty->alt_speed = 230400; if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP) - info->tty->alt_speed = 460800; + state->tty->alt_speed = 460800; } state->flags |= ASYNC_INITIALIZED; @@ -692,20 +659,18 @@ errout: */ static int rs_open(struct tty_struct *tty, struct file * filp) { - struct async_struct *info; + struct serial_state *info = rs_table + tty->index; int retval; unsigned long page; - retval = get_async_struct(tty->index, &info); - if (retval) - return retval; - tty->driver_data = info; + info->count++; info->tty = tty; + tty->driver_data = info; #ifdef SIMSERIAL_DEBUG - printk("rs_open %s, count = %d\n", tty->name, info->state->count); + printk("rs_open %s, count = %d\n", tty->name, info->count); #endif - info->tty->low_latency = (info->state->flags & ASYNC_LOW_LATENCY) ? 1 : 0; + tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0; if (!tmp_buf) { page = get_zeroed_page(GFP_KERNEL); @@ -720,12 +685,11 @@ static int rs_open(struct tty_struct *tty, struct file * filp) /* * If the port is the middle of closing, bail out now */ - if (tty_hung_up_p(filp) || - (info->state->flags & ASYNC_CLOSING)) { - if (info->state->flags & ASYNC_CLOSING) + if (tty_hung_up_p(filp) || (info->flags & ASYNC_CLOSING)) { + if (info->flags & ASYNC_CLOSING) interruptible_sleep_on(&info->close_wait); #ifdef SERIAL_DO_RESTART - return ((info->state->flags & ASYNC_HUP_NOTIFY) ? + return ((info->flags & ASYNC_HUP_NOTIFY) ? -EAGAIN : -ERESTARTSYS); #else return -EAGAIN; @@ -865,6 +829,8 @@ simrs_init (void) * Let's have a little bit of fun ! */ for (i = 0, state = rs_table; i < NR_PORTS; i++,state++) { + init_waitqueue_head(&state->open_wait); + init_waitqueue_head(&state->close_wait); if (state->type == PORT_UNKNOWN) continue; diff --git a/drivers/tty/amiserial.c b/drivers/tty/amiserial.c index 7607c6e..410e8e7 100644 --- a/drivers/tty/amiserial.c +++ b/drivers/tty/amiserial.c @@ -45,7 +45,7 @@ #if defined(MODULE) && defined(SERIAL_DEBUG_MCOUNT) #define DBG_CNT(s) printk("(%s): [%x] refc=%d, serc=%d, ttyc=%d -> %s\n", \ - tty->name, (info->state->flags), serial_driver->refcount,info->count,tty->count,s) + tty->name, (info->flags), serial_driver->refcount,info->count,tty->count,s) #else #define DBG_CNT(s) #endif @@ -102,7 +102,7 @@ static struct tty_driver *serial_driver; static unsigned char current_ctl_bits; -static void change_speed(struct async_struct *info, struct ktermios *old); +static void change_speed(struct serial_state *info, struct ktermios *old); static void rs_wait_until_sent(struct tty_struct *tty, int timeout); @@ -115,7 +115,7 @@ static struct serial_state rs_table[1]; #define serial_isroot() (capable(CAP_SYS_ADMIN)) -static inline int serial_paranoia_check(struct async_struct *info, +static inline int serial_paranoia_check(struct serial_state *info, char *name, const char *routine) { #ifdef SERIAL_PARANOIA_CHECK @@ -168,7 +168,7 @@ static __inline__ void rtsdtr_ctrl(int bits) */ static void rs_stop(struct tty_struct *tty) { - struct async_struct *info = tty->driver_data; + struct serial_state *info = tty->driver_data; unsigned long flags; if (serial_paranoia_check(info, tty->name, "rs_stop")) @@ -188,7 +188,7 @@ static void rs_stop(struct tty_struct *tty) static void rs_start(struct tty_struct *tty) { - struct async_struct *info = tty->driver_data; + struct serial_state *info = tty->driver_data; unsigned long flags; if (serial_paranoia_check(info, tty->name, "rs_start")) @@ -229,7 +229,7 @@ static void rs_start(struct tty_struct *tty) * ----------------------------------------------------------------------- */ -static void receive_chars(struct async_struct *info) +static void receive_chars(struct serial_state *info) { int status; int serdatr; @@ -238,7 +238,7 @@ static void receive_chars(struct async_struct *info) struct async_icount *icount; int oe = 0; - icount = &info->state->icount; + icount = &info->icount; status = UART_LSR_DR; /* We obviously have a character! */ serdatr = custom.serdatr; @@ -295,7 +295,7 @@ static void receive_chars(struct async_struct *info) printk("handling break...."); #endif flag = TTY_BREAK; - if (info->state->flags & ASYNC_SAK) + if (info->flags & ASYNC_SAK) do_SAK(tty); } else if (status & UART_LSR_PE) flag = TTY_PARITY; @@ -318,14 +318,14 @@ out: return; } -static void transmit_chars(struct async_struct *info) +static void transmit_chars(struct serial_state *info) { custom.intreq = IF_TBE; mb(); if (info->x_char) { custom.serdat = info->x_char | 0x100; mb(); - info->state->icount.tx++; + info->icount.tx++; info->x_char = 0; return; } @@ -341,7 +341,7 @@ static void transmit_chars(struct async_struct *info) custom.serdat = info->xmit.buf[info->xmit.tail++] | 0x100; mb(); info->xmit.tail = info->xmit.tail & (SERIAL_XMIT_SIZE-1); - info->state->icount.tx++; + info->icount.tx++; if (CIRC_CNT(info->xmit.head, info->xmit.tail, @@ -358,7 +358,7 @@ static void transmit_chars(struct async_struct *info) } } -static void check_modem_status(struct async_struct *info) +static void check_modem_status(struct serial_state *info) { unsigned char status = ciab.pra & (SER_DCD | SER_CTS | SER_DSR); unsigned char dstatus; @@ -369,14 +369,14 @@ static void check_modem_status(struct async_struct *info) current_ctl_bits = status; if (dstatus) { - icount = &info->state->icount; + icount = &info->icount; /* update input line counters */ if (dstatus & SER_DSR) icount->dsr++; if (dstatus & SER_DCD) { icount->dcd++; #ifdef CONFIG_HARD_PPS - if ((info->state->flags & ASYNC_HARDPPS_CD) && + if ((info->flags & ASYNC_HARDPPS_CD) && !(status & SER_DCD)) hardpps(); #endif @@ -386,7 +386,7 @@ static void check_modem_status(struct async_struct *info) wake_up_interruptible(&info->delta_msr_wait); } - if ((info->state->flags & ASYNC_CHECK_CD) && (dstatus & SER_DCD)) { + if ((info->flags & ASYNC_CHECK_CD) && (dstatus & SER_DCD)) { #if (defined(SERIAL_DEBUG_OPEN) || defined(SERIAL_DEBUG_INTR)) printk("ttyS%d CD now %s...", info->line, (!(status & SER_DCD)) ? "on" : "off"); @@ -401,7 +401,7 @@ static void check_modem_status(struct async_struct *info) tty_hangup(info->tty); } } - if (info->state->flags & ASYNC_CTS_FLOW) { + if (info->flags & ASYNC_CTS_FLOW) { if (info->tty->hw_stopped) { if (!(status & SER_CTS)) { #if (defined(SERIAL_DEBUG_INTR) || defined(SERIAL_DEBUG_FLOW)) @@ -437,7 +437,7 @@ static void check_modem_status(struct async_struct *info) static irqreturn_t ser_vbl_int( int irq, void *data) { /* vbl is just a periodic interrupt we tie into to update modem status */ - struct async_struct *info = data; + struct serial_state *info = data; /* * TBD - is it better to unregister from this interrupt or to * ignore it if MSI is clear ? @@ -449,14 +449,13 @@ static irqreturn_t ser_vbl_int( int irq, void *data) static irqreturn_t ser_rx_int(int irq, void *dev_id) { - struct serial_state *state = dev_id; - struct async_struct *info = state->info; + struct serial_state *info = dev_id; #ifdef SERIAL_DEBUG_INTR printk("ser_rx_int..."); #endif - if (!info || !info->tty) + if (!info->tty) return IRQ_NONE; receive_chars(info); @@ -468,15 +467,14 @@ static irqreturn_t ser_rx_int(int irq, void *dev_id) static irqreturn_t ser_tx_int(int irq, void *dev_id) { - struct serial_state *state = dev_id; - struct async_struct *info = state->info; + struct serial_state *info = dev_id; if (custom.serdatr & SDR_TBE) { #ifdef SERIAL_DEBUG_INTR printk("ser_tx_int..."); #endif - if (!info || !info->tty) + if (!info->tty) return IRQ_NONE; transmit_chars(info); @@ -502,7 +500,7 @@ static irqreturn_t ser_tx_int(int irq, void *dev_id) * --------------------------------------------------------------- */ -static int startup(struct async_struct * info) +static int startup(struct serial_state *info) { unsigned long flags; int retval=0; @@ -514,7 +512,7 @@ static int startup(struct async_struct * info) local_irq_save(flags); - if (info->state->flags & ASYNC_INITIALIZED) { + if (info->flags & ASYNC_INITIALIZED) { free_page(page); goto errout; } @@ -565,13 +563,13 @@ static int startup(struct async_struct * info) * Set up the tty->alt_speed kludge */ if (info->tty) { - if ((info->state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) + if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) info->tty->alt_speed = 57600; - if ((info->state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI) + if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI) info->tty->alt_speed = 115200; - if ((info->state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI) + if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI) info->tty->alt_speed = 230400; - if ((info->state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP) + if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP) info->tty->alt_speed = 460800; } @@ -580,7 +578,7 @@ static int startup(struct async_struct * info) */ change_speed(info, NULL); - info->state->flags |= ASYNC_INITIALIZED; + info->flags |= ASYNC_INITIALIZED; local_irq_restore(flags); return 0; @@ -593,15 +591,15 @@ errout: * This routine will shutdown a serial port; interrupts are disabled, and * DTR is dropped if the hangup on close termio flag is on. */ -static void shutdown(struct async_struct * info) +static void shutdown(struct serial_state *info) { unsigned long flags; struct serial_state *state; - if (!(info->state->flags & ASYNC_INITIALIZED)) + if (!(info->flags & ASYNC_INITIALIZED)) return; - state = info->state; + state = info; #ifdef SERIAL_DEBUG_OPEN printk("Shutting down serial port %d ....\n", info->line); @@ -640,7 +638,7 @@ static void shutdown(struct async_struct * info) if (info->tty) set_bit(TTY_IO_ERROR, &info->tty->flags); - info->state->flags &= ~ASYNC_INITIALIZED; + info->flags &= ~ASYNC_INITIALIZED; local_irq_restore(flags); } @@ -649,7 +647,7 @@ static void shutdown(struct async_struct * info) * This routine is called to set the UART divisor registers to match * the specified baud rate for a serial port. */ -static void change_speed(struct async_struct *info, +static void change_speed(struct serial_state *info, struct ktermios *old_termios) { int quot = 0, baud_base, baud; @@ -683,10 +681,10 @@ static void change_speed(struct async_struct *info, baud = tty_get_baud_rate(info->tty); if (!baud) baud = 9600; /* B0 transition handled in rs_set_termios */ - baud_base = info->state->baud_base; + baud_base = info->baud_base; if (baud == 38400 && - ((info->state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST)) - quot = info->state->custom_divisor; + ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST)) + quot = info->custom_divisor; else { if (baud == 134) /* Special case since 134 is really 134.5 */ @@ -703,8 +701,8 @@ static void change_speed(struct async_struct *info, if (!baud) baud = 9600; if (baud == 38400 && - ((info->state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST)) - quot = info->state->custom_divisor; + ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST)) + quot = info->custom_divisor; else { if (baud == 134) /* Special case since 134 is really 134.5 */ @@ -717,22 +715,22 @@ static void change_speed(struct async_struct *info, if (!quot) quot = baud_base / 9600; info->quot = quot; - info->timeout = ((info->state->xmit_fifo_size*HZ*bits*quot) / baud_base); + info->timeout = ((info->xmit_fifo_size*HZ*bits*quot) / baud_base); info->timeout += HZ/50; /* Add .02 seconds of slop */ /* CTS flow control flag and modem status interrupts */ info->IER &= ~UART_IER_MSI; - if (info->state->flags & ASYNC_HARDPPS_CD) + if (info->flags & ASYNC_HARDPPS_CD) info->IER |= UART_IER_MSI; if (cflag & CRTSCTS) { - info->state->flags |= ASYNC_CTS_FLOW; + info->flags |= ASYNC_CTS_FLOW; info->IER |= UART_IER_MSI; } else - info->state->flags &= ~ASYNC_CTS_FLOW; + info->flags &= ~ASYNC_CTS_FLOW; if (cflag & CLOCAL) - info->state->flags &= ~ASYNC_CHECK_CD; + info->flags &= ~ASYNC_CHECK_CD; else { - info->state->flags |= ASYNC_CHECK_CD; + info->flags |= ASYNC_CHECK_CD; info->IER |= UART_IER_MSI; } /* TBD: @@ -791,7 +789,7 @@ static void change_speed(struct async_struct *info, static int rs_put_char(struct tty_struct *tty, unsigned char ch) { - struct async_struct *info; + struct serial_state *info; unsigned long flags; info = tty->driver_data; @@ -818,7 +816,7 @@ static int rs_put_char(struct tty_struct *tty, unsigned char ch) static void rs_flush_chars(struct tty_struct *tty) { - struct async_struct *info = tty->driver_data; + struct serial_state *info = tty->driver_data; unsigned long flags; if (serial_paranoia_check(info, tty->name, "rs_flush_chars")) @@ -843,11 +841,9 @@ static void rs_flush_chars(struct tty_struct *tty) static int rs_write(struct tty_struct * tty, const unsigned char *buf, int count) { int c, ret = 0; - struct async_struct *info; + struct serial_state *info = tty->driver_data; unsigned long flags; - info = tty->driver_data; - if (serial_paranoia_check(info, tty->name, "rs_write")) return 0; @@ -891,7 +887,7 @@ static int rs_write(struct tty_struct * tty, const unsigned char *buf, int count static int rs_write_room(struct tty_struct *tty) { - struct async_struct *info = tty->driver_data; + struct serial_state *info = tty->driver_data; if (serial_paranoia_check(info, tty->name, "rs_write_room")) return 0; @@ -900,7 +896,7 @@ static int rs_write_room(struct tty_struct *tty) static int rs_chars_in_buffer(struct tty_struct *tty) { - struct async_struct *info = tty->driver_data; + struct serial_state *info = tty->driver_data; if (serial_paranoia_check(info, tty->name, "rs_chars_in_buffer")) return 0; @@ -909,7 +905,7 @@ static int rs_chars_in_buffer(struct tty_struct *tty) static void rs_flush_buffer(struct tty_struct *tty) { - struct async_struct *info = tty->driver_data; + struct serial_state *info = tty->driver_data; unsigned long flags; if (serial_paranoia_check(info, tty->name, "rs_flush_buffer")) @@ -926,7 +922,7 @@ static void rs_flush_buffer(struct tty_struct *tty) */ static void rs_send_xchar(struct tty_struct *tty, char ch) { - struct async_struct *info = tty->driver_data; + struct serial_state *info = tty->driver_data; unsigned long flags; if (serial_paranoia_check(info, tty->name, "rs_send_char")) @@ -961,7 +957,7 @@ static void rs_send_xchar(struct tty_struct *tty, char ch) */ static void rs_throttle(struct tty_struct * tty) { - struct async_struct *info = tty->driver_data; + struct serial_state *info = tty->driver_data; unsigned long flags; #ifdef SERIAL_DEBUG_THROTTLE char buf[64]; @@ -986,7 +982,7 @@ static void rs_throttle(struct tty_struct * tty) static void rs_unthrottle(struct tty_struct * tty) { - struct async_struct *info = tty->driver_data; + struct serial_state *info = tty->driver_data; unsigned long flags; #ifdef SERIAL_DEBUG_THROTTLE char buf[64]; @@ -1017,11 +1013,10 @@ static void rs_unthrottle(struct tty_struct * tty) * ------------------------------------------------------------ */ -static int get_serial_info(struct async_struct * info, +static int get_serial_info(struct serial_state *state, struct serial_struct __user * retinfo) { struct serial_struct tmp; - struct serial_state *state = info->state; if (!retinfo) return -EFAULT; @@ -1043,11 +1038,11 @@ static int get_serial_info(struct async_struct * info, return 0; } -static int set_serial_info(struct async_struct * info, +static int set_serial_info(struct serial_state *state, struct serial_struct __user * new_info) { struct serial_struct new_serial; - struct serial_state old_state, *state; + struct serial_state old_state; unsigned int change_irq,change_port; int retval = 0; @@ -1055,7 +1050,6 @@ static int set_serial_info(struct async_struct * info, return -EFAULT; tty_lock(); - state = info->state; old_state = *state; change_irq = new_serial.irq != state->irq; @@ -1094,7 +1088,7 @@ static int set_serial_info(struct async_struct * info, state->custom_divisor = new_serial.custom_divisor; state->close_delay = new_serial.close_delay * HZ/100; state->closing_wait = new_serial.closing_wait * HZ/100; - info->tty->low_latency = (state->flags & ASYNC_LOW_LATENCY) ? 1 : 0; + state->tty->low_latency = (state->flags & ASYNC_LOW_LATENCY) ? 1 : 0; check_and_exit: if (state->flags & ASYNC_INITIALIZED) { @@ -1102,17 +1096,17 @@ check_and_exit: (state->flags & ASYNC_SPD_MASK)) || (old_state.custom_divisor != state->custom_divisor)) { if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) - info->tty->alt_speed = 57600; + state->tty->alt_speed = 57600; if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI) - info->tty->alt_speed = 115200; + state->tty->alt_speed = 115200; if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI) - info->tty->alt_speed = 230400; + state->tty->alt_speed = 230400; if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP) - info->tty->alt_speed = 460800; - change_speed(info, NULL); + state->tty->alt_speed = 460800; + change_speed(state, NULL); } } else - retval = startup(info); + retval = startup(state); tty_unlock(); return retval; } @@ -1128,7 +1122,7 @@ check_and_exit: * transmit holding register is empty. This functionality * allows an RS485 driver to be written in user space. */ -static int get_lsr_info(struct async_struct * info, unsigned int __user *value) +static int get_lsr_info(struct serial_state *info, unsigned int __user *value) { unsigned char status; unsigned int result; @@ -1147,7 +1141,7 @@ static int get_lsr_info(struct async_struct * info, unsigned int __user *value) static int rs_tiocmget(struct tty_struct *tty) { - struct async_struct * info = tty->driver_data; + struct serial_state *info = tty->driver_data; unsigned char control, status; unsigned long flags; @@ -1170,7 +1164,7 @@ static int rs_tiocmget(struct tty_struct *tty) static int rs_tiocmset(struct tty_struct *tty, unsigned int set, unsigned int clear) { - struct async_struct * info = tty->driver_data; + struct serial_state *info = tty->driver_data; unsigned long flags; if (serial_paranoia_check(info, tty->name, "rs_ioctl")) @@ -1197,7 +1191,7 @@ static int rs_tiocmset(struct tty_struct *tty, unsigned int set, */ static int rs_break(struct tty_struct *tty, int break_state) { - struct async_struct * info = tty->driver_data; + struct serial_state *info = tty->driver_data; unsigned long flags; if (serial_paranoia_check(info, tty->name, "rs_break")) @@ -1222,12 +1216,12 @@ static int rs_break(struct tty_struct *tty, int break_state) static int rs_get_icount(struct tty_struct *tty, struct serial_icounter_struct *icount) { - struct async_struct *info = tty->driver_data; + struct serial_state *info = tty->driver_data; struct async_icount cnow; unsigned long flags; local_irq_save(flags); - cnow = info->state->icount; + cnow = info->icount; local_irq_restore(flags); icount->cts = cnow.cts; icount->dsr = cnow.dsr; @@ -1247,7 +1241,7 @@ static int rs_get_icount(struct tty_struct *tty, static int rs_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg) { - struct async_struct * info = tty->driver_data; + struct serial_state *info = tty->driver_data; struct async_icount cprev, cnow; /* kernel counter temps */ void __user *argp = (void __user *)arg; unsigned long flags; @@ -1275,7 +1269,7 @@ static int rs_ioctl(struct tty_struct *tty, case TIOCSERGSTRUCT: if (copy_to_user(argp, - info, sizeof(struct async_struct))) + info, sizeof(struct serial_state))) return -EFAULT; return 0; @@ -1288,7 +1282,7 @@ static int rs_ioctl(struct tty_struct *tty, case TIOCMIWAIT: local_irq_save(flags); /* note the counters on entry */ - cprev = info->state->icount; + cprev = info->icount; local_irq_restore(flags); while (1) { interruptible_sleep_on(&info->delta_msr_wait); @@ -1296,7 +1290,7 @@ static int rs_ioctl(struct tty_struct *tty, if (signal_pending(current)) return -ERESTARTSYS; local_irq_save(flags); - cnow = info->state->icount; /* atomic copy */ + cnow = info->icount; /* atomic copy */ local_irq_restore(flags); if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr && cnow.dcd == cprev.dcd && cnow.cts == cprev.cts) @@ -1325,7 +1319,7 @@ static int rs_ioctl(struct tty_struct *tty, static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios) { - struct async_struct *info = tty->driver_data; + struct serial_state *info = tty->driver_data; unsigned long flags; unsigned int cflag = tty->termios->c_cflag; @@ -1385,15 +1379,12 @@ static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios) */ static void rs_close(struct tty_struct *tty, struct file * filp) { - struct async_struct * info = tty->driver_data; - struct serial_state *state; + struct serial_state *state = tty->driver_data; unsigned long flags; - if (!info || serial_paranoia_check(info, tty->name, "rs_close")) + if (!state || serial_paranoia_check(state, tty->name, "rs_close")) return; - state = info->state; - local_irq_save(flags); if (tty_hung_up_p(filp)) { @@ -1403,7 +1394,7 @@ static void rs_close(struct tty_struct *tty, struct file * filp) } #ifdef SERIAL_DEBUG_OPEN - printk("rs_close ttys%d, count = %d\n", info->line, state->count); + printk("rs_close ttys%d, count = %d\n", state->line, state->count); #endif if ((tty->count == 1) && (state->count != 1)) { /* @@ -1441,7 +1432,7 @@ static void rs_close(struct tty_struct *tty, struct file * filp) * interrupt driver to stop checking the data ready bit in the * line status register. */ - info->read_status_mask &= ~UART_LSR_DR; + state->read_status_mask &= ~UART_LSR_DR; if (state->flags & ASYNC_INITIALIZED) { /* disable receive interrupts */ custom.intena = IF_RBF; @@ -1455,22 +1446,22 @@ static void rs_close(struct tty_struct *tty, struct file * filp) * has completely drained; this is especially * important if there is a transmit FIFO! */ - rs_wait_until_sent(tty, info->timeout); + rs_wait_until_sent(tty, state->timeout); } - shutdown(info); + shutdown(state); rs_flush_buffer(tty); tty_ldisc_flush(tty); tty->closing = 0; - info->tty = NULL; - if (info->blocked_open) { + state->tty = NULL; + if (state->blocked_open) { if (state->close_delay) { msleep_interruptible(jiffies_to_msecs(state->close_delay)); } - wake_up_interruptible(&info->open_wait); + wake_up_interruptible(&state->open_wait); } state->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING); - wake_up_interruptible(&info->close_wait); + wake_up_interruptible(&state->close_wait); local_irq_restore(flags); } @@ -1479,14 +1470,14 @@ static void rs_close(struct tty_struct *tty, struct file * filp) */ static void rs_wait_until_sent(struct tty_struct *tty, int timeout) { - struct async_struct * info = tty->driver_data; + struct serial_state *info = tty->driver_data; unsigned long orig_jiffies, char_time; int lsr; if (serial_paranoia_check(info, tty->name, "rs_wait_until_sent")) return; - if (info->state->xmit_fifo_size == 0) + if (info->xmit_fifo_size == 0) return; /* Just in case.... */ orig_jiffies = jiffies; @@ -1499,7 +1490,7 @@ static void rs_wait_until_sent(struct tty_struct *tty, int timeout) * Note: we have to use pretty tight timings here to satisfy * the NIST-PCTS. */ - char_time = (info->timeout - HZ/50) / info->state->xmit_fifo_size; + char_time = (info->timeout - HZ/50) / info->xmit_fifo_size; char_time = char_time / 5; if (char_time == 0) char_time = 1; @@ -1542,18 +1533,15 @@ static void rs_wait_until_sent(struct tty_struct *tty, int timeout) */ static void rs_hangup(struct tty_struct *tty) { - struct async_struct * info = tty->driver_data; - struct serial_state *state = info->state; + struct serial_state *info = tty->driver_data; if (serial_paranoia_check(info, tty->name, "rs_hangup")) return; - state = info->state; - rs_flush_buffer(tty); shutdown(info); - state->count = 0; - state->flags &= ~ASYNC_NORMAL_ACTIVE; + info->count = 0; + info->flags &= ~ASYNC_NORMAL_ACTIVE; info->tty = NULL; wake_up_interruptible(&info->open_wait); } @@ -1564,14 +1552,13 @@ static void rs_hangup(struct tty_struct *tty) * ------------------------------------------------------------ */ static int block_til_ready(struct tty_struct *tty, struct file * filp, - struct async_struct *info) + struct serial_state *info) { #ifdef DECLARE_WAITQUEUE DECLARE_WAITQUEUE(wait, current); #else struct wait_queue wait = { current, NULL }; #endif - struct serial_state *state = info->state; int retval; int do_clocal = 0, extra_count = 0; unsigned long flags; @@ -1581,11 +1568,11 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, * until it's done, and then try again. */ if (tty_hung_up_p(filp) || - (state->flags & ASYNC_CLOSING)) { - if (state->flags & ASYNC_CLOSING) + (info->flags & ASYNC_CLOSING)) { + if (info->flags & ASYNC_CLOSING) interruptible_sleep_on(&info->close_wait); #ifdef SERIAL_DO_RESTART - return ((state->flags & ASYNC_HUP_NOTIFY) ? + return ((info->flags & ASYNC_HUP_NOTIFY) ? -EAGAIN : -ERESTARTSYS); #else return -EAGAIN; @@ -1598,7 +1585,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, */ if ((filp->f_flags & O_NONBLOCK) || (tty->flags & (1 << TTY_IO_ERROR))) { - state->flags |= ASYNC_NORMAL_ACTIVE; + info->flags |= ASYNC_NORMAL_ACTIVE; return 0; } @@ -1608,7 +1595,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, /* * Block waiting for the carrier detect and the line to become * free (i.e., not in use by the callout). While we are in - * this loop, state->count is dropped by one, so that + * this loop, info->count is dropped by one, so that * rs_close() knows when to free things. We restore it upon * exit, either normal or abnormal. */ @@ -1616,12 +1603,12 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, add_wait_queue(&info->open_wait, &wait); #ifdef SERIAL_DEBUG_OPEN printk("block_til_ready before block: ttys%d, count = %d\n", - state->line, state->count); + info->line, info->count); #endif local_irq_save(flags); if (!tty_hung_up_p(filp)) { extra_count = 1; - state->count--; + info->count--; } local_irq_restore(flags); info->blocked_open++; @@ -1632,9 +1619,9 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, local_irq_restore(flags); set_current_state(TASK_INTERRUPTIBLE); if (tty_hung_up_p(filp) || - !(state->flags & ASYNC_INITIALIZED)) { + !(info->flags & ASYNC_INITIALIZED)) { #ifdef SERIAL_DO_RESTART - if (state->flags & ASYNC_HUP_NOTIFY) + if (info->flags & ASYNC_HUP_NOTIFY) retval = -EAGAIN; else retval = -ERESTARTSYS; @@ -1643,7 +1630,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, #endif break; } - if (!(state->flags & ASYNC_CLOSING) && + if (!(info->flags & ASYNC_CLOSING) && (do_clocal || (!(ciab.pra & SER_DCD)) )) break; if (signal_pending(current)) { @@ -1652,7 +1639,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, } #ifdef SERIAL_DEBUG_OPEN printk("block_til_ready blocking: ttys%d, count = %d\n", - info->line, state->count); + info->line, info->count); #endif tty_unlock(); schedule(); @@ -1661,46 +1648,15 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, __set_current_state(TASK_RUNNING); remove_wait_queue(&info->open_wait, &wait); if (extra_count) - state->count++; + info->count++; info->blocked_open--; #ifdef SERIAL_DEBUG_OPEN printk("block_til_ready after blocking: ttys%d, count = %d\n", - info->line, state->count); + info->line, info->count); #endif if (retval) return retval; - state->flags |= ASYNC_NORMAL_ACTIVE; - return 0; -} - -static int get_async_struct(int line, struct async_struct **ret_info) -{ - struct async_struct *info; - struct serial_state *sstate; - - sstate = rs_table + line; - sstate->count++; - if (sstate->info) { - *ret_info = sstate->info; - return 0; - } - info = kzalloc(sizeof(struct async_struct), GFP_KERNEL); - if (!info) { - sstate->count--; - return -ENOMEM; - } -#ifdef DECLARE_WAITQUEUE - init_waitqueue_head(&info->open_wait); - init_waitqueue_head(&info->close_wait); - init_waitqueue_head(&info->delta_msr_wait); -#endif - info->state = sstate; - if (sstate->info) { - kfree(info); - *ret_info = sstate->info; - return 0; - } - *ret_info = sstate->info = info; + info->flags |= ASYNC_NORMAL_ACTIVE; return 0; } @@ -1712,32 +1668,29 @@ static int get_async_struct(int line, struct async_struct **ret_info) */ static int rs_open(struct tty_struct *tty, struct file * filp) { - struct async_struct *info; + struct serial_state *info = rs_table + tty->index; int retval; - retval = get_async_struct(tty->index, &info); - if (retval) { - return retval; - } - tty->driver_data = info; + info->count++; info->tty = tty; + tty->driver_data = info; if (serial_paranoia_check(info, tty->name, "rs_open")) return -ENODEV; #ifdef SERIAL_DEBUG_OPEN - printk("rs_open %s, count = %d\n", tty->name, info->state->count); + printk("rs_open %s, count = %d\n", tty->name, info->count); #endif - info->tty->low_latency = (info->state->flags & ASYNC_LOW_LATENCY) ? 1 : 0; + tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0; /* * If the port is the middle of closing, bail out now */ if (tty_hung_up_p(filp) || - (info->state->flags & ASYNC_CLOSING)) { - if (info->state->flags & ASYNC_CLOSING) + (info->flags & ASYNC_CLOSING)) { + if (info->flags & ASYNC_CLOSING) interruptible_sleep_on(&info->close_wait); #ifdef SERIAL_DO_RESTART - return ((info->state->flags & ASYNC_HUP_NOTIFY) ? + return ((info->flags & ASYNC_HUP_NOTIFY) ? -EAGAIN : -ERESTARTSYS); #else return -EAGAIN; @@ -1773,24 +1726,14 @@ static int rs_open(struct tty_struct *tty, struct file * filp) static inline void line_info(struct seq_file *m, struct serial_state *state) { - struct async_struct *info = state->info, scr_info; char stat_buf[30], control, status; unsigned long flags; seq_printf(m, "%d: uart:amiga_builtin",state->line); - /* - * Figure out the current RS-232 lines - */ - if (!info) { - info = &scr_info; /* This is just for serial_{in,out} */ - - info->quot = 0; - info->tty = NULL; - } local_irq_save(flags); status = ciab.pra; - control = info ? info->MCR : status; + control = (state->flags & ASYNC_INITIALIZED) ? state->MCR : status; local_irq_restore(flags); stat_buf[0] = 0; @@ -1806,9 +1749,8 @@ static inline void line_info(struct seq_file *m, struct serial_state *state) if(!(status & SER_DCD)) strcat(stat_buf, "|CD"); - if (info->quot) { - seq_printf(m, " baud:%d", state->baud_base / info->quot); - } + if (state->quot) + seq_printf(m, " baud:%d", state->baud_base / state->quot); seq_printf(m, " tx:%d rx:%d", state->icount.tx, state->icount.rx); @@ -1938,6 +1880,9 @@ static int __init amiga_serial_probe(struct platform_device *pdev) state->icount.rx = state->icount.tx = 0; state->icount.frame = state->icount.parity = 0; state->icount.overrun = state->icount.brk = 0; + init_waitqueue_head(&state->open_wait); + init_waitqueue_head(&state->close_wait); + init_waitqueue_head(&state->delta_msr_wait); printk(KERN_INFO "ttyS%d is the amiga builtin serial port\n", state->line); @@ -1993,7 +1938,6 @@ static int __exit amiga_serial_remove(struct platform_device *pdev) { int error; struct serial_state *state = platform_get_drvdata(pdev); - struct async_struct *info = state->info; /* printk("Unloading %s: version %s\n", serial_name, serial_version); */ if ((error = tty_unregister_driver(serial_driver))) @@ -2001,11 +1945,8 @@ static int __exit amiga_serial_remove(struct platform_device *pdev) error); put_tty_driver(serial_driver); - rs_table[0].info = NULL; - kfree(info); - - free_irq(IRQ_AMIGA_TBE, rs_table); - free_irq(IRQ_AMIGA_RBF, rs_table); + free_irq(IRQ_AMIGA_TBE, state); + free_irq(IRQ_AMIGA_RBF, state); platform_set_drvdata(pdev, NULL); diff --git a/include/linux/serialP.h b/include/linux/serialP.h index b8543f9..984f5ba 100644 --- a/include/linux/serialP.h +++ b/include/linux/serialP.h @@ -38,24 +38,24 @@ struct serial_state { unsigned short close_delay; unsigned short closing_wait; /* time to wait before closing */ struct async_icount icount; - struct async_struct *info; -}; -struct async_struct { - struct serial_state *state; - struct tty_struct *tty; + /* amiserial */ int read_status_mask; int ignore_status_mask; int timeout; int quot; - int x_char; /* xon/xoff character */ int IER; /* Interrupt Enable Register */ int MCR; /* Modem control register */ + wait_queue_head_t delta_msr_wait; + /* simserial */ + int x_char; /* xon/xoff character */ int blocked_open; /* # of blocked opens */ struct circ_buf xmit; wait_queue_head_t open_wait; wait_queue_head_t close_wait; - wait_queue_head_t delta_msr_wait; + struct tty_struct *tty; + /* /simserial */ + /* /amiserial */ }; #endif /* _LINUX_SERIAL_H */ -- cgit v0.10.2 From 0f9b9684db2d1369fe303de5729cbdc817265bec Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 5 Mar 2012 14:52:21 +0100 Subject: TTY: amiserial, simplify set_serial_info Do not copy whole serial_state. We only need to know whether the speed is to be changed. Hence store the info in advance and use it later. A simple bool is enough. Also remove reduntant assignments and move the tests directly to the 'if'. Signed-off-by: Jiri Slaby Cc: Geert Uytterhoeven Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/amiserial.c b/drivers/tty/amiserial.c index 410e8e7..165cd79 100644 --- a/drivers/tty/amiserial.c +++ b/drivers/tty/amiserial.c @@ -1042,21 +1042,19 @@ static int set_serial_info(struct serial_state *state, struct serial_struct __user * new_info) { struct serial_struct new_serial; - struct serial_state old_state; - unsigned int change_irq,change_port; + bool change_spd; int retval = 0; if (copy_from_user(&new_serial,new_info,sizeof(new_serial))) return -EFAULT; tty_lock(); - old_state = *state; - - change_irq = new_serial.irq != state->irq; - change_port = (new_serial.port != state->port); - if(change_irq || change_port || (new_serial.xmit_fifo_size != state->xmit_fifo_size)) { - tty_unlock(); - return -EINVAL; + change_spd = ((new_serial.flags ^ state->flags) & ASYNC_SPD_MASK) || + new_serial.custom_divisor != state->custom_divisor; + if (new_serial.irq != state->irq || new_serial.port != state->port || + new_serial.xmit_fifo_size != state->xmit_fifo_size) { + tty_unlock(); + return -EINVAL; } if (!serial_isroot()) { @@ -1092,9 +1090,7 @@ static int set_serial_info(struct serial_state *state, check_and_exit: if (state->flags & ASYNC_INITIALIZED) { - if (((old_state.flags & ASYNC_SPD_MASK) != - (state->flags & ASYNC_SPD_MASK)) || - (old_state.custom_divisor != state->custom_divisor)) { + if (change_spd) { if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) state->tty->alt_speed = 57600; if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI) -- cgit v0.10.2 From 588993dd8d99bdbd9a7296abe0c7964ecc874300 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 5 Mar 2012 14:52:22 +0100 Subject: TTY: amiserial, pass tty down to functions This avoids pain with tty refcounting and touching tty_port in the future. It allows us to remove some info->tty tests because the tty passed down to them can never be NULL. Signed-off-by: Jiri Slaby Cc: Geert Uytterhoeven Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/amiserial.c b/drivers/tty/amiserial.c index 165cd79..5b87744 100644 --- a/drivers/tty/amiserial.c +++ b/drivers/tty/amiserial.c @@ -102,7 +102,8 @@ static struct tty_driver *serial_driver; static unsigned char current_ctl_bits; -static void change_speed(struct serial_state *info, struct ktermios *old); +static void change_speed(struct tty_struct *tty, struct serial_state *info, + struct ktermios *old); static void rs_wait_until_sent(struct tty_struct *tty, int timeout); @@ -500,7 +501,7 @@ static irqreturn_t ser_tx_int(int irq, void *dev_id) * --------------------------------------------------------------- */ -static int startup(struct serial_state *info) +static int startup(struct tty_struct *tty, struct serial_state *info) { unsigned long flags; int retval=0; @@ -534,9 +535,7 @@ static int startup(struct serial_state *info) retval = request_irq(IRQ_AMIGA_VERTB, ser_vbl_int, 0, "serial status", info); if (retval) { if (serial_isroot()) { - if (info->tty) - set_bit(TTY_IO_ERROR, - &info->tty->flags); + set_bit(TTY_IO_ERROR, &tty->flags); retval = 0; } goto errout; @@ -551,32 +550,29 @@ static int startup(struct serial_state *info) current_ctl_bits = ciab.pra & (SER_DCD | SER_CTS | SER_DSR); info->MCR = 0; - if (info->tty->termios->c_cflag & CBAUD) + if (C_BAUD(tty)) info->MCR = SER_DTR | SER_RTS; rtsdtr_ctrl(info->MCR); - if (info->tty) - clear_bit(TTY_IO_ERROR, &info->tty->flags); + clear_bit(TTY_IO_ERROR, &tty->flags); info->xmit.head = info->xmit.tail = 0; /* * Set up the tty->alt_speed kludge */ - if (info->tty) { - if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) - info->tty->alt_speed = 57600; - if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI) - info->tty->alt_speed = 115200; - if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI) - info->tty->alt_speed = 230400; - if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP) - info->tty->alt_speed = 460800; - } + if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) + tty->alt_speed = 57600; + if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI) + tty->alt_speed = 115200; + if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI) + tty->alt_speed = 230400; + if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP) + tty->alt_speed = 460800; /* * and set the speed of the serial port */ - change_speed(info, NULL); + change_speed(tty, info, NULL); info->flags |= ASYNC_INITIALIZED; local_irq_restore(flags); @@ -591,7 +587,7 @@ errout: * This routine will shutdown a serial port; interrupts are disabled, and * DTR is dropped if the hangup on close termio flag is on. */ -static void shutdown(struct serial_state *info) +static void shutdown(struct tty_struct *tty, struct serial_state *info) { unsigned long flags; struct serial_state *state; @@ -631,12 +627,11 @@ static void shutdown(struct serial_state *info) custom.adkcon = AC_UARTBRK; mb(); - if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) + if (tty->termios->c_cflag & HUPCL) info->MCR &= ~(SER_DTR|SER_RTS); rtsdtr_ctrl(info->MCR); - if (info->tty) - set_bit(TTY_IO_ERROR, &info->tty->flags); + set_bit(TTY_IO_ERROR, &tty->flags); info->flags &= ~ASYNC_INITIALIZED; local_irq_restore(flags); @@ -647,7 +642,7 @@ static void shutdown(struct serial_state *info) * This routine is called to set the UART divisor registers to match * the specified baud rate for a serial port. */ -static void change_speed(struct serial_state *info, +static void change_speed(struct tty_struct *tty, struct serial_state *info, struct ktermios *old_termios) { int quot = 0, baud_base, baud; @@ -655,9 +650,7 @@ static void change_speed(struct serial_state *info, int bits; unsigned long flags; - if (!info->tty || !info->tty->termios) - return; - cflag = info->tty->termios->c_cflag; + cflag = tty->termios->c_cflag; /* Byte size is always 8 bits plus parity bit if requested */ @@ -678,7 +671,7 @@ static void change_speed(struct serial_state *info, #endif /* Determine divisor based on baud rate */ - baud = tty_get_baud_rate(info->tty); + baud = tty_get_baud_rate(tty); if (!baud) baud = 9600; /* B0 transition handled in rs_set_termios */ baud_base = info->baud_base; @@ -695,9 +688,9 @@ static void change_speed(struct serial_state *info, /* If the quotient is zero refuse the change */ if (!quot && old_termios) { /* FIXME: Will need updating for new tty in the end */ - info->tty->termios->c_cflag &= ~CBAUD; - info->tty->termios->c_cflag |= (old_termios->c_cflag & CBAUD); - baud = tty_get_baud_rate(info->tty); + tty->termios->c_cflag &= ~CBAUD; + tty->termios->c_cflag |= (old_termios->c_cflag & CBAUD); + baud = tty_get_baud_rate(tty); if (!baud) baud = 9600; if (baud == 38400 && @@ -742,24 +735,24 @@ static void change_speed(struct serial_state *info, */ info->read_status_mask = UART_LSR_OE | UART_LSR_DR; - if (I_INPCK(info->tty)) + if (I_INPCK(tty)) info->read_status_mask |= UART_LSR_FE | UART_LSR_PE; - if (I_BRKINT(info->tty) || I_PARMRK(info->tty)) + if (I_BRKINT(tty) || I_PARMRK(tty)) info->read_status_mask |= UART_LSR_BI; /* * Characters to ignore */ info->ignore_status_mask = 0; - if (I_IGNPAR(info->tty)) + if (I_IGNPAR(tty)) info->ignore_status_mask |= UART_LSR_PE | UART_LSR_FE; - if (I_IGNBRK(info->tty)) { + if (I_IGNBRK(tty)) { info->ignore_status_mask |= UART_LSR_BI; /* * If we're ignore parity and break indicators, ignore * overruns too. (For real raw support). */ - if (I_IGNPAR(info->tty)) + if (I_IGNPAR(tty)) info->ignore_status_mask |= UART_LSR_OE; } /* @@ -1038,7 +1031,7 @@ static int get_serial_info(struct serial_state *state, return 0; } -static int set_serial_info(struct serial_state *state, +static int set_serial_info(struct tty_struct *tty, struct serial_state *state, struct serial_struct __user * new_info) { struct serial_struct new_serial; @@ -1086,23 +1079,23 @@ static int set_serial_info(struct serial_state *state, state->custom_divisor = new_serial.custom_divisor; state->close_delay = new_serial.close_delay * HZ/100; state->closing_wait = new_serial.closing_wait * HZ/100; - state->tty->low_latency = (state->flags & ASYNC_LOW_LATENCY) ? 1 : 0; + tty->low_latency = (state->flags & ASYNC_LOW_LATENCY) ? 1 : 0; check_and_exit: if (state->flags & ASYNC_INITIALIZED) { if (change_spd) { if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) - state->tty->alt_speed = 57600; + tty->alt_speed = 57600; if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI) - state->tty->alt_speed = 115200; + tty->alt_speed = 115200; if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI) - state->tty->alt_speed = 230400; + tty->alt_speed = 230400; if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP) - state->tty->alt_speed = 460800; - change_speed(state, NULL); + tty->alt_speed = 460800; + change_speed(tty, state, NULL); } } else - retval = startup(state); + retval = startup(tty, state); tty_unlock(); return retval; } @@ -1256,7 +1249,7 @@ static int rs_ioctl(struct tty_struct *tty, case TIOCGSERIAL: return get_serial_info(info, argp); case TIOCSSERIAL: - return set_serial_info(info, argp); + return set_serial_info(tty, info, argp); case TIOCSERCONFIG: return 0; @@ -1319,7 +1312,7 @@ static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios) unsigned long flags; unsigned int cflag = tty->termios->c_cflag; - change_speed(info, old_termios); + change_speed(tty, info, old_termios); /* Handle transition to B0 status */ if ((old_termios->c_cflag & CBAUD) && @@ -1444,7 +1437,7 @@ static void rs_close(struct tty_struct *tty, struct file * filp) */ rs_wait_until_sent(tty, state->timeout); } - shutdown(state); + shutdown(tty, state); rs_flush_buffer(tty); tty_ldisc_flush(tty); @@ -1535,7 +1528,7 @@ static void rs_hangup(struct tty_struct *tty) return; rs_flush_buffer(tty); - shutdown(info); + shutdown(tty, info); info->count = 0; info->flags &= ~ASYNC_NORMAL_ACTIVE; info->tty = NULL; @@ -1696,7 +1689,7 @@ static int rs_open(struct tty_struct *tty, struct file * filp) /* * Start up serial port */ - retval = startup(info); + retval = startup(tty, info); if (retval) { return retval; } -- cgit v0.10.2 From 5e99d5458729b0eb763ca83a2fbb95f6276c4243 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 5 Mar 2012 14:52:23 +0100 Subject: TTY: simserial, pass tty down to functions This avoids pain with tty refcounting and touching tty_port in the future. It allows us to remove some state->tty tests because the tty passed down to them can never be NULL. Signed-off-by: Jiri Slaby Cc: Tony Luck Cc: Fenghua Yu Signed-off-by: Greg Kroah-Hartman diff --git a/arch/ia64/hp/sim/simserial.c b/arch/ia64/hp/sim/simserial.c index 7b6e60e..a76a27e 100644 --- a/arch/ia64/hp/sim/simserial.c +++ b/arch/ia64/hp/sim/simserial.c @@ -202,7 +202,8 @@ static int rs_put_char(struct tty_struct *tty, unsigned char ch) return 1; } -static void transmit_chars(struct serial_state *info, int *intr_done) +static void transmit_chars(struct tty_struct *tty, struct serial_state *info, + int *intr_done) { int count; unsigned long flags; @@ -220,10 +221,11 @@ static void transmit_chars(struct serial_state *info, int *intr_done) goto out; } - if (info->xmit.head == info->xmit.tail || info->tty->stopped || info->tty->hw_stopped) { + if (info->xmit.head == info->xmit.tail || tty->stopped || + tty->hw_stopped) { #ifdef SIMSERIAL_DEBUG printk("transmit_chars: head=%d, tail=%d, stopped=%d\n", - info->xmit.head, info->xmit.tail, info->tty->stopped); + info->xmit.head, info->xmit.tail, tty->stopped); #endif goto out; } @@ -261,7 +263,7 @@ static void rs_flush_chars(struct tty_struct *tty) !info->xmit.buf) return; - transmit_chars(info, NULL); + transmit_chars(tty, info, NULL); } @@ -295,7 +297,7 @@ static int rs_write(struct tty_struct * tty, */ if (CIRC_CNT(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE) && !tty->stopped && !tty->hw_stopped) { - transmit_chars(info, NULL); + transmit_chars(tty, info, NULL); } return ret; } @@ -340,7 +342,7 @@ static void rs_send_xchar(struct tty_struct *tty, char ch) * I guess we could call console->write() directly but * let's do that for now. */ - transmit_chars(info, NULL); + transmit_chars(tty, info, NULL); } } @@ -442,7 +444,7 @@ static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios) * This routine will shutdown a serial port; interrupts are disabled, and * DTR is dropped if the hangup on close termio flag is on. */ -static void shutdown(struct serial_state *info) +static void shutdown(struct tty_struct *tty, struct serial_state *info) { unsigned long flags; @@ -464,7 +466,7 @@ static void shutdown(struct serial_state *info) info->xmit.buf = NULL; } - if (info->tty) set_bit(TTY_IO_ERROR, &info->tty->flags); + set_bit(TTY_IO_ERROR, &tty->flags); info->flags &= ~ASYNC_INITIALIZED; } @@ -528,7 +530,7 @@ static void rs_close(struct tty_struct *tty, struct file * filp) * Now we wait for the transmit buffer to clear; and we notify * the line discipline to only process XON/XOFF characters. */ - shutdown(info); + shutdown(tty, info); rs_flush_buffer(tty); tty_ldisc_flush(tty); info->tty = NULL; @@ -563,7 +565,7 @@ static void rs_hangup(struct tty_struct *tty) rs_flush_buffer(tty); if (info->flags & ASYNC_CLOSING) return; - shutdown(info); + shutdown(tty, info); info->count = 0; info->flags &= ~ASYNC_NORMAL_ACTIVE; @@ -572,7 +574,7 @@ static void rs_hangup(struct tty_struct *tty) } -static int startup(struct serial_state *state) +static int startup(struct tty_struct *tty, struct serial_state *state) { unsigned long flags; int retval=0; @@ -590,8 +592,7 @@ static int startup(struct serial_state *state) } if (!state->port || !state->type) { - if (state->tty) - set_bit(TTY_IO_ERROR, &state->tty->flags); + set_bit(TTY_IO_ERROR, &tty->flags); free_page(page); goto errout; } @@ -614,8 +615,7 @@ static int startup(struct serial_state *state) goto errout; } - if (state->tty) - clear_bit(TTY_IO_ERROR, &state->tty->flags); + clear_bit(TTY_IO_ERROR, &tty->flags); state->xmit.head = state->xmit.tail = 0; @@ -630,16 +630,14 @@ static int startup(struct serial_state *state) /* * Set up the tty->alt_speed kludge */ - if (state->tty) { - if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) - state->tty->alt_speed = 57600; - if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI) - state->tty->alt_speed = 115200; - if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI) - state->tty->alt_speed = 230400; - if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP) - state->tty->alt_speed = 460800; - } + if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) + tty->alt_speed = 57600; + if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI) + tty->alt_speed = 115200; + if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI) + tty->alt_speed = 230400; + if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP) + tty->alt_speed = 460800; state->flags |= ASYNC_INITIALIZED; local_irq_restore(flags); @@ -699,7 +697,7 @@ static int rs_open(struct tty_struct *tty, struct file * filp) /* * Start up serial port */ - retval = startup(info); + retval = startup(tty, info); if (retval) { return retval; } -- cgit v0.10.2 From 87758791c99715433841f1c054b49166506513e4 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 5 Mar 2012 14:52:24 +0100 Subject: TTY: amiserial/simserial, use tty_port Add tty_port to serial_state and start using common tty port members from tty_port in amiserial and simserial. The rest will follow one by one. Signed-off-by: Jiri Slaby Cc: Geert Uytterhoeven Cc: Tony Luck Cc: Fenghua Yu Signed-off-by: Greg Kroah-Hartman diff --git a/arch/ia64/hp/sim/simserial.c b/arch/ia64/hp/sim/simserial.c index a76a27e..614c091 100644 --- a/arch/ia64/hp/sim/simserial.c +++ b/arch/ia64/hp/sim/simserial.c @@ -165,7 +165,7 @@ static irqreturn_t rs_interrupt_single(int irq, void *dev_id) { struct serial_state *info = dev_id; - if (!info->tty) { + if (!info->tport.tty) { printk(KERN_INFO "simrs_interrupt_single: info|tty=0 info=%p problem\n", info); return IRQ_NONE; } @@ -173,7 +173,7 @@ static irqreturn_t rs_interrupt_single(int irq, void *dev_id) * pretty simple in our case, because we only get interrupts * on inbound traffic */ - receive_chars(info->tty); + receive_chars(info->tport.tty); return IRQ_HANDLED; } @@ -533,14 +533,14 @@ static void rs_close(struct tty_struct *tty, struct file * filp) shutdown(tty, info); rs_flush_buffer(tty); tty_ldisc_flush(tty); - info->tty = NULL; - if (info->blocked_open) { + info->tport.tty = NULL; + if (info->tport.blocked_open) { if (info->close_delay) schedule_timeout_interruptible(info->close_delay); - wake_up_interruptible(&info->open_wait); + wake_up_interruptible(&info->tport.open_wait); } info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING); - wake_up_interruptible(&info->close_wait); + wake_up_interruptible(&info->tport.close_wait); } /* @@ -569,8 +569,8 @@ static void rs_hangup(struct tty_struct *tty) info->count = 0; info->flags &= ~ASYNC_NORMAL_ACTIVE; - info->tty = NULL; - wake_up_interruptible(&info->open_wait); + info->tport.tty = NULL; + wake_up_interruptible(&info->tport.open_wait); } @@ -662,8 +662,9 @@ static int rs_open(struct tty_struct *tty, struct file * filp) unsigned long page; info->count++; - info->tty = tty; + info->tport.tty = tty; tty->driver_data = info; + tty->port = &info->tport; #ifdef SIMSERIAL_DEBUG printk("rs_open %s, count = %d\n", tty->name, info->count); @@ -685,7 +686,7 @@ static int rs_open(struct tty_struct *tty, struct file * filp) */ if (tty_hung_up_p(filp) || (info->flags & ASYNC_CLOSING)) { if (info->flags & ASYNC_CLOSING) - interruptible_sleep_on(&info->close_wait); + interruptible_sleep_on(&info->tport.close_wait); #ifdef SERIAL_DO_RESTART return ((info->flags & ASYNC_HUP_NOTIFY) ? -EAGAIN : -ERESTARTSYS); @@ -827,8 +828,7 @@ simrs_init (void) * Let's have a little bit of fun ! */ for (i = 0, state = rs_table; i < NR_PORTS; i++,state++) { - init_waitqueue_head(&state->open_wait); - init_waitqueue_head(&state->close_wait); + tty_port_init(&state->tport); if (state->type == PORT_UNKNOWN) continue; diff --git a/drivers/tty/amiserial.c b/drivers/tty/amiserial.c index 5b87744..71d3331 100644 --- a/drivers/tty/amiserial.c +++ b/drivers/tty/amiserial.c @@ -234,7 +234,7 @@ static void receive_chars(struct serial_state *info) { int status; int serdatr; - struct tty_struct *tty = info->tty; + struct tty_struct *tty = info->tport.tty; unsigned char ch, flag; struct async_icount *icount; int oe = 0; @@ -331,8 +331,8 @@ static void transmit_chars(struct serial_state *info) return; } if (info->xmit.head == info->xmit.tail - || info->tty->stopped - || info->tty->hw_stopped) { + || info->tport.tty->stopped + || info->tport.tty->hw_stopped) { info->IER &= ~UART_IER_THRI; custom.intena = IF_TBE; mb(); @@ -347,7 +347,7 @@ static void transmit_chars(struct serial_state *info) if (CIRC_CNT(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE) < WAKEUP_CHARS) - tty_wakeup(info->tty); + tty_wakeup(info->tport.tty); #ifdef SERIAL_DEBUG_INTR printk("THRE..."); @@ -384,7 +384,7 @@ static void check_modem_status(struct serial_state *info) } if (dstatus & SER_CTS) icount->cts++; - wake_up_interruptible(&info->delta_msr_wait); + wake_up_interruptible(&info->tport.delta_msr_wait); } if ((info->flags & ASYNC_CHECK_CD) && (dstatus & SER_DCD)) { @@ -393,29 +393,29 @@ static void check_modem_status(struct serial_state *info) (!(status & SER_DCD)) ? "on" : "off"); #endif if (!(status & SER_DCD)) - wake_up_interruptible(&info->open_wait); + wake_up_interruptible(&info->tport.open_wait); else { #ifdef SERIAL_DEBUG_OPEN printk("doing serial hangup..."); #endif - if (info->tty) - tty_hangup(info->tty); + if (info->tport.tty) + tty_hangup(info->tport.tty); } } if (info->flags & ASYNC_CTS_FLOW) { - if (info->tty->hw_stopped) { + if (info->tport.tty->hw_stopped) { if (!(status & SER_CTS)) { #if (defined(SERIAL_DEBUG_INTR) || defined(SERIAL_DEBUG_FLOW)) printk("CTS tx start..."); #endif - info->tty->hw_stopped = 0; + info->tport.tty->hw_stopped = 0; info->IER |= UART_IER_THRI; custom.intena = IF_SETCLR | IF_TBE; mb(); /* set a pending Tx Interrupt, transmitter should restart now */ custom.intreq = IF_SETCLR | IF_TBE; mb(); - tty_wakeup(info->tty); + tty_wakeup(info->tport.tty); return; } } else { @@ -423,7 +423,7 @@ static void check_modem_status(struct serial_state *info) #if (defined(SERIAL_DEBUG_INTR) || defined(SERIAL_DEBUG_FLOW)) printk("CTS tx stop..."); #endif - info->tty->hw_stopped = 1; + info->tport.tty->hw_stopped = 1; info->IER &= ~UART_IER_THRI; /* disable Tx interrupt and remove any pending interrupts */ custom.intena = IF_TBE; @@ -456,7 +456,7 @@ static irqreturn_t ser_rx_int(int irq, void *dev_id) printk("ser_rx_int..."); #endif - if (!info->tty) + if (!info->tport.tty) return IRQ_NONE; receive_chars(info); @@ -475,7 +475,7 @@ static irqreturn_t ser_tx_int(int irq, void *dev_id) printk("ser_tx_int..."); #endif - if (!info->tty) + if (!info->tport.tty) return IRQ_NONE; transmit_chars(info); @@ -607,7 +607,7 @@ static void shutdown(struct tty_struct *tty, struct serial_state *info) * clear delta_msr_wait queue to avoid mem leaks: we may free the irq * here so the queue might never be waken up */ - wake_up_interruptible(&info->delta_msr_wait); + wake_up_interruptible(&info->tport.delta_msr_wait); /* * Free the IRQ, if necessary @@ -1274,7 +1274,7 @@ static int rs_ioctl(struct tty_struct *tty, cprev = info->icount; local_irq_restore(flags); while (1) { - interruptible_sleep_on(&info->delta_msr_wait); + interruptible_sleep_on(&info->tport.delta_msr_wait); /* see if a signal did it */ if (signal_pending(current)) return -ERESTARTSYS; @@ -1442,15 +1442,15 @@ static void rs_close(struct tty_struct *tty, struct file * filp) tty_ldisc_flush(tty); tty->closing = 0; - state->tty = NULL; - if (state->blocked_open) { + state->tport.tty = NULL; + if (state->tport.blocked_open) { if (state->close_delay) { msleep_interruptible(jiffies_to_msecs(state->close_delay)); } - wake_up_interruptible(&state->open_wait); + wake_up_interruptible(&state->tport.open_wait); } state->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING); - wake_up_interruptible(&state->close_wait); + wake_up_interruptible(&state->tport.close_wait); local_irq_restore(flags); } @@ -1531,8 +1531,8 @@ static void rs_hangup(struct tty_struct *tty) shutdown(tty, info); info->count = 0; info->flags &= ~ASYNC_NORMAL_ACTIVE; - info->tty = NULL; - wake_up_interruptible(&info->open_wait); + info->tport.tty = NULL; + wake_up_interruptible(&info->tport.open_wait); } /* @@ -1559,7 +1559,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, if (tty_hung_up_p(filp) || (info->flags & ASYNC_CLOSING)) { if (info->flags & ASYNC_CLOSING) - interruptible_sleep_on(&info->close_wait); + interruptible_sleep_on(&info->tport.close_wait); #ifdef SERIAL_DO_RESTART return ((info->flags & ASYNC_HUP_NOTIFY) ? -EAGAIN : -ERESTARTSYS); @@ -1589,7 +1589,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, * exit, either normal or abnormal. */ retval = 0; - add_wait_queue(&info->open_wait, &wait); + add_wait_queue(&info->tport.open_wait, &wait); #ifdef SERIAL_DEBUG_OPEN printk("block_til_ready before block: ttys%d, count = %d\n", info->line, info->count); @@ -1600,7 +1600,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, info->count--; } local_irq_restore(flags); - info->blocked_open++; + info->tport.blocked_open++; while (1) { local_irq_save(flags); if (tty->termios->c_cflag & CBAUD) @@ -1635,10 +1635,10 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, tty_lock(); } __set_current_state(TASK_RUNNING); - remove_wait_queue(&info->open_wait, &wait); + remove_wait_queue(&info->tport.open_wait, &wait); if (extra_count) info->count++; - info->blocked_open--; + info->tport.blocked_open--; #ifdef SERIAL_DEBUG_OPEN printk("block_til_ready after blocking: ttys%d, count = %d\n", info->line, info->count); @@ -1661,8 +1661,9 @@ static int rs_open(struct tty_struct *tty, struct file * filp) int retval; info->count++; - info->tty = tty; + info->tport.tty = tty; tty->driver_data = info; + tty->port = &info->tport; if (serial_paranoia_check(info, tty->name, "rs_open")) return -ENODEV; @@ -1677,7 +1678,7 @@ static int rs_open(struct tty_struct *tty, struct file * filp) if (tty_hung_up_p(filp) || (info->flags & ASYNC_CLOSING)) { if (info->flags & ASYNC_CLOSING) - interruptible_sleep_on(&info->close_wait); + interruptible_sleep_on(&info->tport.close_wait); #ifdef SERIAL_DO_RESTART return ((info->flags & ASYNC_HUP_NOTIFY) ? -EAGAIN : -ERESTARTSYS); @@ -1869,9 +1870,7 @@ static int __init amiga_serial_probe(struct platform_device *pdev) state->icount.rx = state->icount.tx = 0; state->icount.frame = state->icount.parity = 0; state->icount.overrun = state->icount.brk = 0; - init_waitqueue_head(&state->open_wait); - init_waitqueue_head(&state->close_wait); - init_waitqueue_head(&state->delta_msr_wait); + tty_port_init(&state->tport); printk(KERN_INFO "ttyS%d is the amiga builtin serial port\n", state->line); diff --git a/include/linux/serialP.h b/include/linux/serialP.h index 984f5ba..32d45b8 100644 --- a/include/linux/serialP.h +++ b/include/linux/serialP.h @@ -23,6 +23,7 @@ #include #include #include +#include #include struct serial_state { @@ -38,6 +39,7 @@ struct serial_state { unsigned short close_delay; unsigned short closing_wait; /* time to wait before closing */ struct async_icount icount; + struct tty_port tport; /* amiserial */ int read_status_mask; @@ -46,14 +48,9 @@ struct serial_state { int quot; int IER; /* Interrupt Enable Register */ int MCR; /* Modem control register */ - wait_queue_head_t delta_msr_wait; /* simserial */ int x_char; /* xon/xoff character */ - int blocked_open; /* # of blocked opens */ struct circ_buf xmit; - wait_queue_head_t open_wait; - wait_queue_head_t close_wait; - struct tty_struct *tty; /* /simserial */ /* /amiserial */ }; -- cgit v0.10.2 From 799be6ff2fd7294f428a9e68a7786490c862c1af Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 5 Mar 2012 14:52:25 +0100 Subject: TTY: amiserial/simserial, use close delays from tty_port Note that previously simserial set the delay to 0. So we preserve that. BUT, is it correct? Signed-off-by: Jiri Slaby Cc: Geert Uytterhoeven Cc: Tony Luck Cc: Fenghua Yu Signed-off-by: Greg Kroah-Hartman diff --git a/arch/ia64/hp/sim/simserial.c b/arch/ia64/hp/sim/simserial.c index 614c091..fb324b3 100644 --- a/arch/ia64/hp/sim/simserial.c +++ b/arch/ia64/hp/sim/simserial.c @@ -535,8 +535,8 @@ static void rs_close(struct tty_struct *tty, struct file * filp) tty_ldisc_flush(tty); info->tport.tty = NULL; if (info->tport.blocked_open) { - if (info->close_delay) - schedule_timeout_interruptible(info->close_delay); + if (info->tport.close_delay) + schedule_timeout_interruptible(info->tport.close_delay); wake_up_interruptible(&info->tport.open_wait); } info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING); @@ -829,6 +829,7 @@ simrs_init (void) */ for (i = 0, state = rs_table; i < NR_PORTS; i++,state++) { tty_port_init(&state->tport); + state->tport.close_delay = 0; /* XXX really 0? */ if (state->type == PORT_UNKNOWN) continue; diff --git a/drivers/tty/amiserial.c b/drivers/tty/amiserial.c index 71d3331..06e3a09 100644 --- a/drivers/tty/amiserial.c +++ b/drivers/tty/amiserial.c @@ -1022,8 +1022,8 @@ static int get_serial_info(struct serial_state *state, tmp.flags = state->flags; tmp.xmit_fifo_size = state->xmit_fifo_size; tmp.baud_base = state->baud_base; - tmp.close_delay = state->close_delay; - tmp.closing_wait = state->closing_wait; + tmp.close_delay = state->tport.close_delay; + tmp.closing_wait = state->tport.closing_wait; tmp.custom_divisor = state->custom_divisor; tty_unlock(); if (copy_to_user(retinfo,&tmp,sizeof(*retinfo))) @@ -1052,7 +1052,7 @@ static int set_serial_info(struct tty_struct *tty, struct serial_state *state, if (!serial_isroot()) { if ((new_serial.baud_base != state->baud_base) || - (new_serial.close_delay != state->close_delay) || + (new_serial.close_delay != state->tport.close_delay) || (new_serial.xmit_fifo_size != state->xmit_fifo_size) || ((new_serial.flags & ~ASYNC_USR_MASK) != (state->flags & ~ASYNC_USR_MASK))) @@ -1077,8 +1077,8 @@ static int set_serial_info(struct tty_struct *tty, struct serial_state *state, state->flags = ((state->flags & ~ASYNC_FLAGS) | (new_serial.flags & ASYNC_FLAGS)); state->custom_divisor = new_serial.custom_divisor; - state->close_delay = new_serial.close_delay * HZ/100; - state->closing_wait = new_serial.closing_wait * HZ/100; + state->tport.close_delay = new_serial.close_delay * HZ/100; + state->tport.closing_wait = new_serial.closing_wait * HZ/100; tty->low_latency = (state->flags & ASYNC_LOW_LATENCY) ? 1 : 0; check_and_exit: @@ -1413,8 +1413,8 @@ static void rs_close(struct tty_struct *tty, struct file * filp) * the line discipline to only process XON/XOFF characters. */ tty->closing = 1; - if (state->closing_wait != ASYNC_CLOSING_WAIT_NONE) - tty_wait_until_sent(tty, state->closing_wait); + if (state->tport.closing_wait != ASYNC_CLOSING_WAIT_NONE) + tty_wait_until_sent(tty, state->tport.closing_wait); /* * At this point we stop accepting input. To do this, we * disable the receive line status interrupts, and tell the @@ -1444,8 +1444,8 @@ static void rs_close(struct tty_struct *tty, struct file * filp) tty->closing = 0; state->tport.tty = NULL; if (state->tport.blocked_open) { - if (state->close_delay) { - msleep_interruptible(jiffies_to_msecs(state->close_delay)); + if (state->tport.close_delay) { + msleep_interruptible(jiffies_to_msecs(state->tport.close_delay)); } wake_up_interruptible(&state->tport.open_wait); } @@ -1863,8 +1863,6 @@ static int __init amiga_serial_probe(struct platform_device *pdev) state->port = (int)&custom.serdatr; /* Just to give it a value */ state->line = 0; state->custom_divisor = 0; - state->close_delay = 5*HZ/10; - state->closing_wait = 30*HZ; state->icount.cts = state->icount.dsr = state->icount.rng = state->icount.dcd = 0; state->icount.rx = state->icount.tx = 0; diff --git a/include/linux/serialP.h b/include/linux/serialP.h index 32d45b8..997edd0 100644 --- a/include/linux/serialP.h +++ b/include/linux/serialP.h @@ -36,8 +36,6 @@ struct serial_state { int xmit_fifo_size; int custom_divisor; int count; - unsigned short close_delay; - unsigned short closing_wait; /* time to wait before closing */ struct async_icount icount; struct tty_port tport; -- cgit v0.10.2 From 12c8035435fa16e3f6b18049bb1d7815c00a7a58 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 5 Mar 2012 14:52:26 +0100 Subject: TTY: amiserial/simserial, use count from tty_port Nothing special. Just remove count from serial_state and change all users to use tty_port. Signed-off-by: Jiri Slaby Cc: Geert Uytterhoeven Cc: Tony Luck Cc: Fenghua Yu Signed-off-by: Greg Kroah-Hartman diff --git a/arch/ia64/hp/sim/simserial.c b/arch/ia64/hp/sim/simserial.c index fb324b3..baa2b1e 100644 --- a/arch/ia64/hp/sim/simserial.c +++ b/arch/ia64/hp/sim/simserial.c @@ -500,26 +500,26 @@ static void rs_close(struct tty_struct *tty, struct file * filp) return; } #ifdef SIMSERIAL_DEBUG - printk("rs_close ttys%d, count = %d\n", info->line, info->count); + printk("rs_close ttys%d, count = %d\n", info->line, info->tport.count); #endif - if ((tty->count == 1) && (info->count != 1)) { + if ((tty->count == 1) && (info->tport.count != 1)) { /* * Uh, oh. tty->count is 1, which means that the tty - * structure will be freed. info->count should always + * structure will be freed. info->tport.count should always * be one in these conditions. If it's greater than * one, we've got real problems, since it means the * serial port won't be shutdown. */ printk(KERN_ERR "rs_close: bad serial port count; tty->count is 1, " - "info->count is %d\n", info->count); - info->count = 1; + "info->tport.count is %d\n", info->tport.count); + info->tport.count = 1; } - if (--info->count < 0) { + if (--info->tport.count < 0) { printk(KERN_ERR "rs_close: bad serial port count for ttys%d: %d\n", - info->line, info->count); - info->count = 0; + info->line, info->tport.count); + info->tport.count = 0; } - if (info->count) { + if (info->tport.count) { local_irq_restore(flags); return; } @@ -567,7 +567,7 @@ static void rs_hangup(struct tty_struct *tty) return; shutdown(tty, info); - info->count = 0; + info->tport.count = 0; info->flags &= ~ASYNC_NORMAL_ACTIVE; info->tport.tty = NULL; wake_up_interruptible(&info->tport.open_wait); @@ -661,13 +661,13 @@ static int rs_open(struct tty_struct *tty, struct file * filp) int retval; unsigned long page; - info->count++; + info->tport.count++; info->tport.tty = tty; tty->driver_data = info; tty->port = &info->tport; #ifdef SIMSERIAL_DEBUG - printk("rs_open %s, count = %d\n", tty->name, info->count); + printk("rs_open %s, count = %d\n", tty->name, info->tport.count); #endif tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0; diff --git a/drivers/tty/amiserial.c b/drivers/tty/amiserial.c index 06e3a09..8ad64a0 100644 --- a/drivers/tty/amiserial.c +++ b/drivers/tty/amiserial.c @@ -1383,26 +1383,26 @@ static void rs_close(struct tty_struct *tty, struct file * filp) } #ifdef SERIAL_DEBUG_OPEN - printk("rs_close ttys%d, count = %d\n", state->line, state->count); + printk("rs_close ttys%d, count = %d\n", state->line, state->tport.count); #endif - if ((tty->count == 1) && (state->count != 1)) { + if ((tty->count == 1) && (state->tport.count != 1)) { /* * Uh, oh. tty->count is 1, which means that the tty - * structure will be freed. state->count should always + * structure will be freed. state->tport.count should always * be one in these conditions. If it's greater than * one, we've got real problems, since it means the * serial port won't be shutdown. */ printk("rs_close: bad serial port count; tty->count is 1, " - "state->count is %d\n", state->count); - state->count = 1; + "state->tport.count is %d\n", state->tport.count); + state->tport.count = 1; } - if (--state->count < 0) { + if (--state->tport.count < 0) { printk("rs_close: bad serial port count for ttys%d: %d\n", - state->line, state->count); - state->count = 0; + state->line, state->tport.count); + state->tport.count = 0; } - if (state->count) { + if (state->tport.count) { DBG_CNT("before DEC-2"); local_irq_restore(flags); return; @@ -1529,7 +1529,7 @@ static void rs_hangup(struct tty_struct *tty) rs_flush_buffer(tty); shutdown(tty, info); - info->count = 0; + info->tport.count = 0; info->flags &= ~ASYNC_NORMAL_ACTIVE; info->tport.tty = NULL; wake_up_interruptible(&info->tport.open_wait); @@ -1584,7 +1584,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, /* * Block waiting for the carrier detect and the line to become * free (i.e., not in use by the callout). While we are in - * this loop, info->count is dropped by one, so that + * this loop, info->tport.count is dropped by one, so that * rs_close() knows when to free things. We restore it upon * exit, either normal or abnormal. */ @@ -1592,12 +1592,12 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, add_wait_queue(&info->tport.open_wait, &wait); #ifdef SERIAL_DEBUG_OPEN printk("block_til_ready before block: ttys%d, count = %d\n", - info->line, info->count); + info->line, info->tport.count); #endif local_irq_save(flags); if (!tty_hung_up_p(filp)) { extra_count = 1; - info->count--; + info->tport.count--; } local_irq_restore(flags); info->tport.blocked_open++; @@ -1628,7 +1628,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, } #ifdef SERIAL_DEBUG_OPEN printk("block_til_ready blocking: ttys%d, count = %d\n", - info->line, info->count); + info->line, info->tport.count); #endif tty_unlock(); schedule(); @@ -1637,11 +1637,11 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, __set_current_state(TASK_RUNNING); remove_wait_queue(&info->tport.open_wait, &wait); if (extra_count) - info->count++; + info->tport.count++; info->tport.blocked_open--; #ifdef SERIAL_DEBUG_OPEN printk("block_til_ready after blocking: ttys%d, count = %d\n", - info->line, info->count); + info->line, info->tport.count); #endif if (retval) return retval; @@ -1660,7 +1660,7 @@ static int rs_open(struct tty_struct *tty, struct file * filp) struct serial_state *info = rs_table + tty->index; int retval; - info->count++; + info->tport.count++; info->tport.tty = tty; tty->driver_data = info; tty->port = &info->tport; diff --git a/include/linux/serialP.h b/include/linux/serialP.h index 997edd0..a6612b9 100644 --- a/include/linux/serialP.h +++ b/include/linux/serialP.h @@ -35,7 +35,6 @@ struct serial_state { int line; int xmit_fifo_size; int custom_divisor; - int count; struct async_icount icount; struct tty_port tport; -- cgit v0.10.2 From 01bd730d92bd002adc3f3317d8e3328c629b436c Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 5 Mar 2012 14:52:27 +0100 Subject: TTY: amiserial/simserial, use flags from tty_port This changes flags' type to ulong which is appropriate for all the set/clear_bits performed in the drivers.. Signed-off-by: Jiri Slaby Cc: Geert Uytterhoeven Cc: Tony Luck Cc: Fenghua Yu Signed-off-by: Greg Kroah-Hartman diff --git a/arch/ia64/hp/sim/simserial.c b/arch/ia64/hp/sim/simserial.c index baa2b1e..c65c49d 100644 --- a/arch/ia64/hp/sim/simserial.c +++ b/arch/ia64/hp/sim/simserial.c @@ -448,7 +448,7 @@ static void shutdown(struct tty_struct *tty, struct serial_state *info) { unsigned long flags; - if (!(info->flags & ASYNC_INITIALIZED)) + if (!(info->tport.flags & ASYNC_INITIALIZED)) return; #ifdef SIMSERIAL_DEBUG @@ -468,7 +468,7 @@ static void shutdown(struct tty_struct *tty, struct serial_state *info) set_bit(TTY_IO_ERROR, &tty->flags); - info->flags &= ~ASYNC_INITIALIZED; + info->tport.flags &= ~ASYNC_INITIALIZED; } local_irq_restore(flags); } @@ -523,7 +523,7 @@ static void rs_close(struct tty_struct *tty, struct file * filp) local_irq_restore(flags); return; } - info->flags |= ASYNC_CLOSING; + info->tport.flags |= ASYNC_CLOSING; local_irq_restore(flags); /* @@ -539,7 +539,7 @@ static void rs_close(struct tty_struct *tty, struct file * filp) schedule_timeout_interruptible(info->tport.close_delay); wake_up_interruptible(&info->tport.open_wait); } - info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING); + info->tport.flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING); wake_up_interruptible(&info->tport.close_wait); } @@ -563,12 +563,12 @@ static void rs_hangup(struct tty_struct *tty) #endif rs_flush_buffer(tty); - if (info->flags & ASYNC_CLOSING) + if (info->tport.flags & ASYNC_CLOSING) return; shutdown(tty, info); info->tport.count = 0; - info->flags &= ~ASYNC_NORMAL_ACTIVE; + info->tport.flags &= ~ASYNC_NORMAL_ACTIVE; info->tport.tty = NULL; wake_up_interruptible(&info->tport.open_wait); } @@ -576,6 +576,7 @@ static void rs_hangup(struct tty_struct *tty) static int startup(struct tty_struct *tty, struct serial_state *state) { + struct tty_port *port = &state->tport; unsigned long flags; int retval=0; unsigned long page; @@ -586,7 +587,7 @@ static int startup(struct tty_struct *tty, struct serial_state *state) local_irq_save(flags); - if (state->flags & ASYNC_INITIALIZED) { + if (port->flags & ASYNC_INITIALIZED) { free_page(page); goto errout; } @@ -630,16 +631,16 @@ static int startup(struct tty_struct *tty, struct serial_state *state) /* * Set up the tty->alt_speed kludge */ - if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) + if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) tty->alt_speed = 57600; - if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI) + if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI) tty->alt_speed = 115200; - if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI) + if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI) tty->alt_speed = 230400; - if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP) + if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP) tty->alt_speed = 460800; - state->flags |= ASYNC_INITIALIZED; + port->flags |= ASYNC_INITIALIZED; local_irq_restore(flags); return 0; @@ -669,7 +670,7 @@ static int rs_open(struct tty_struct *tty, struct file * filp) #ifdef SIMSERIAL_DEBUG printk("rs_open %s, count = %d\n", tty->name, info->tport.count); #endif - tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0; + tty->low_latency = (info->tport.flags & ASYNC_LOW_LATENCY) ? 1 : 0; if (!tmp_buf) { page = get_zeroed_page(GFP_KERNEL); @@ -684,11 +685,11 @@ static int rs_open(struct tty_struct *tty, struct file * filp) /* * If the port is the middle of closing, bail out now */ - if (tty_hung_up_p(filp) || (info->flags & ASYNC_CLOSING)) { - if (info->flags & ASYNC_CLOSING) + if (tty_hung_up_p(filp) || (info->tport.flags & ASYNC_CLOSING)) { + if (info->tport.flags & ASYNC_CLOSING) interruptible_sleep_on(&info->tport.close_wait); #ifdef SERIAL_DO_RESTART - return ((info->flags & ASYNC_HUP_NOTIFY) ? + return ((info->tport.flags & ASYNC_HUP_NOTIFY) ? -EAGAIN : -ERESTARTSYS); #else return -EAGAIN; diff --git a/drivers/tty/amiserial.c b/drivers/tty/amiserial.c index 8ad64a0..7d79826 100644 --- a/drivers/tty/amiserial.c +++ b/drivers/tty/amiserial.c @@ -45,7 +45,7 @@ #if defined(MODULE) && defined(SERIAL_DEBUG_MCOUNT) #define DBG_CNT(s) printk("(%s): [%x] refc=%d, serc=%d, ttyc=%d -> %s\n", \ - tty->name, (info->flags), serial_driver->refcount,info->count,tty->count,s) + tty->name, (info->tport.flags), serial_driver->refcount,info->count,tty->count,s) #else #define DBG_CNT(s) #endif @@ -296,7 +296,7 @@ static void receive_chars(struct serial_state *info) printk("handling break...."); #endif flag = TTY_BREAK; - if (info->flags & ASYNC_SAK) + if (info->tport.flags & ASYNC_SAK) do_SAK(tty); } else if (status & UART_LSR_PE) flag = TTY_PARITY; @@ -377,7 +377,7 @@ static void check_modem_status(struct serial_state *info) if (dstatus & SER_DCD) { icount->dcd++; #ifdef CONFIG_HARD_PPS - if ((info->flags & ASYNC_HARDPPS_CD) && + if ((info->tport.flags & ASYNC_HARDPPS_CD) && !(status & SER_DCD)) hardpps(); #endif @@ -387,7 +387,7 @@ static void check_modem_status(struct serial_state *info) wake_up_interruptible(&info->tport.delta_msr_wait); } - if ((info->flags & ASYNC_CHECK_CD) && (dstatus & SER_DCD)) { + if ((info->tport.flags & ASYNC_CHECK_CD) && (dstatus & SER_DCD)) { #if (defined(SERIAL_DEBUG_OPEN) || defined(SERIAL_DEBUG_INTR)) printk("ttyS%d CD now %s...", info->line, (!(status & SER_DCD)) ? "on" : "off"); @@ -402,7 +402,7 @@ static void check_modem_status(struct serial_state *info) tty_hangup(info->tport.tty); } } - if (info->flags & ASYNC_CTS_FLOW) { + if (info->tport.flags & ASYNC_CTS_FLOW) { if (info->tport.tty->hw_stopped) { if (!(status & SER_CTS)) { #if (defined(SERIAL_DEBUG_INTR) || defined(SERIAL_DEBUG_FLOW)) @@ -503,6 +503,7 @@ static irqreturn_t ser_tx_int(int irq, void *dev_id) static int startup(struct tty_struct *tty, struct serial_state *info) { + struct tty_port *port = &info->tport; unsigned long flags; int retval=0; unsigned long page; @@ -513,7 +514,7 @@ static int startup(struct tty_struct *tty, struct serial_state *info) local_irq_save(flags); - if (info->flags & ASYNC_INITIALIZED) { + if (port->flags & ASYNC_INITIALIZED) { free_page(page); goto errout; } @@ -560,13 +561,13 @@ static int startup(struct tty_struct *tty, struct serial_state *info) /* * Set up the tty->alt_speed kludge */ - if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) + if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) tty->alt_speed = 57600; - if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI) + if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI) tty->alt_speed = 115200; - if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI) + if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI) tty->alt_speed = 230400; - if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP) + if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP) tty->alt_speed = 460800; /* @@ -574,7 +575,7 @@ static int startup(struct tty_struct *tty, struct serial_state *info) */ change_speed(tty, info, NULL); - info->flags |= ASYNC_INITIALIZED; + port->flags |= ASYNC_INITIALIZED; local_irq_restore(flags); return 0; @@ -592,7 +593,7 @@ static void shutdown(struct tty_struct *tty, struct serial_state *info) unsigned long flags; struct serial_state *state; - if (!(info->flags & ASYNC_INITIALIZED)) + if (!(info->tport.flags & ASYNC_INITIALIZED)) return; state = info; @@ -633,7 +634,7 @@ static void shutdown(struct tty_struct *tty, struct serial_state *info) set_bit(TTY_IO_ERROR, &tty->flags); - info->flags &= ~ASYNC_INITIALIZED; + info->tport.flags &= ~ASYNC_INITIALIZED; local_irq_restore(flags); } @@ -645,6 +646,7 @@ static void shutdown(struct tty_struct *tty, struct serial_state *info) static void change_speed(struct tty_struct *tty, struct serial_state *info, struct ktermios *old_termios) { + struct tty_port *port = &info->tport; int quot = 0, baud_base, baud; unsigned cflag, cval = 0; int bits; @@ -675,8 +677,7 @@ static void change_speed(struct tty_struct *tty, struct serial_state *info, if (!baud) baud = 9600; /* B0 transition handled in rs_set_termios */ baud_base = info->baud_base; - if (baud == 38400 && - ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST)) + if (baud == 38400 && (port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST) quot = info->custom_divisor; else { if (baud == 134) @@ -694,7 +695,7 @@ static void change_speed(struct tty_struct *tty, struct serial_state *info, if (!baud) baud = 9600; if (baud == 38400 && - ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST)) + (port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST) quot = info->custom_divisor; else { if (baud == 134) @@ -713,17 +714,17 @@ static void change_speed(struct tty_struct *tty, struct serial_state *info, /* CTS flow control flag and modem status interrupts */ info->IER &= ~UART_IER_MSI; - if (info->flags & ASYNC_HARDPPS_CD) + if (port->flags & ASYNC_HARDPPS_CD) info->IER |= UART_IER_MSI; if (cflag & CRTSCTS) { - info->flags |= ASYNC_CTS_FLOW; + port->flags |= ASYNC_CTS_FLOW; info->IER |= UART_IER_MSI; } else - info->flags &= ~ASYNC_CTS_FLOW; + port->flags &= ~ASYNC_CTS_FLOW; if (cflag & CLOCAL) - info->flags &= ~ASYNC_CHECK_CD; + port->flags &= ~ASYNC_CHECK_CD; else { - info->flags |= ASYNC_CHECK_CD; + port->flags |= ASYNC_CHECK_CD; info->IER |= UART_IER_MSI; } /* TBD: @@ -1019,7 +1020,7 @@ static int get_serial_info(struct serial_state *state, tmp.line = state->line; tmp.port = state->port; tmp.irq = state->irq; - tmp.flags = state->flags; + tmp.flags = state->tport.flags; tmp.xmit_fifo_size = state->xmit_fifo_size; tmp.baud_base = state->baud_base; tmp.close_delay = state->tport.close_delay; @@ -1034,6 +1035,7 @@ static int get_serial_info(struct serial_state *state, static int set_serial_info(struct tty_struct *tty, struct serial_state *state, struct serial_struct __user * new_info) { + struct tty_port *port = &state->tport; struct serial_struct new_serial; bool change_spd; int retval = 0; @@ -1042,7 +1044,7 @@ static int set_serial_info(struct tty_struct *tty, struct serial_state *state, return -EFAULT; tty_lock(); - change_spd = ((new_serial.flags ^ state->flags) & ASYNC_SPD_MASK) || + change_spd = ((new_serial.flags ^ port->flags) & ASYNC_SPD_MASK) || new_serial.custom_divisor != state->custom_divisor; if (new_serial.irq != state->irq || new_serial.port != state->port || new_serial.xmit_fifo_size != state->xmit_fifo_size) { @@ -1052,12 +1054,12 @@ static int set_serial_info(struct tty_struct *tty, struct serial_state *state, if (!serial_isroot()) { if ((new_serial.baud_base != state->baud_base) || - (new_serial.close_delay != state->tport.close_delay) || + (new_serial.close_delay != port->close_delay) || (new_serial.xmit_fifo_size != state->xmit_fifo_size) || ((new_serial.flags & ~ASYNC_USR_MASK) != - (state->flags & ~ASYNC_USR_MASK))) + (port->flags & ~ASYNC_USR_MASK))) return -EPERM; - state->flags = ((state->flags & ~ASYNC_USR_MASK) | + port->flags = ((port->flags & ~ASYNC_USR_MASK) | (new_serial.flags & ASYNC_USR_MASK)); state->custom_divisor = new_serial.custom_divisor; goto check_and_exit; @@ -1074,23 +1076,23 @@ static int set_serial_info(struct tty_struct *tty, struct serial_state *state, */ state->baud_base = new_serial.baud_base; - state->flags = ((state->flags & ~ASYNC_FLAGS) | + port->flags = ((port->flags & ~ASYNC_FLAGS) | (new_serial.flags & ASYNC_FLAGS)); state->custom_divisor = new_serial.custom_divisor; - state->tport.close_delay = new_serial.close_delay * HZ/100; - state->tport.closing_wait = new_serial.closing_wait * HZ/100; - tty->low_latency = (state->flags & ASYNC_LOW_LATENCY) ? 1 : 0; + port->close_delay = new_serial.close_delay * HZ/100; + port->closing_wait = new_serial.closing_wait * HZ/100; + tty->low_latency = (port->flags & ASYNC_LOW_LATENCY) ? 1 : 0; check_and_exit: - if (state->flags & ASYNC_INITIALIZED) { + if (port->flags & ASYNC_INITIALIZED) { if (change_spd) { - if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) + if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) tty->alt_speed = 57600; - if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI) + if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI) tty->alt_speed = 115200; - if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI) + if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI) tty->alt_speed = 230400; - if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP) + if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP) tty->alt_speed = 460800; change_speed(tty, state, NULL); } @@ -1407,7 +1409,7 @@ static void rs_close(struct tty_struct *tty, struct file * filp) local_irq_restore(flags); return; } - state->flags |= ASYNC_CLOSING; + state->tport.flags |= ASYNC_CLOSING; /* * Now we wait for the transmit buffer to clear; and we notify * the line discipline to only process XON/XOFF characters. @@ -1422,7 +1424,7 @@ static void rs_close(struct tty_struct *tty, struct file * filp) * line status register. */ state->read_status_mask &= ~UART_LSR_DR; - if (state->flags & ASYNC_INITIALIZED) { + if (state->tport.flags & ASYNC_INITIALIZED) { /* disable receive interrupts */ custom.intena = IF_RBF; mb(); @@ -1449,7 +1451,7 @@ static void rs_close(struct tty_struct *tty, struct file * filp) } wake_up_interruptible(&state->tport.open_wait); } - state->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING); + state->tport.flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING); wake_up_interruptible(&state->tport.close_wait); local_irq_restore(flags); } @@ -1530,7 +1532,7 @@ static void rs_hangup(struct tty_struct *tty) rs_flush_buffer(tty); shutdown(tty, info); info->tport.count = 0; - info->flags &= ~ASYNC_NORMAL_ACTIVE; + info->tport.flags &= ~ASYNC_NORMAL_ACTIVE; info->tport.tty = NULL; wake_up_interruptible(&info->tport.open_wait); } @@ -1548,6 +1550,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, #else struct wait_queue wait = { current, NULL }; #endif + struct tty_port *port = &info->tport; int retval; int do_clocal = 0, extra_count = 0; unsigned long flags; @@ -1557,11 +1560,11 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, * until it's done, and then try again. */ if (tty_hung_up_p(filp) || - (info->flags & ASYNC_CLOSING)) { - if (info->flags & ASYNC_CLOSING) - interruptible_sleep_on(&info->tport.close_wait); + (port->flags & ASYNC_CLOSING)) { + if (port->flags & ASYNC_CLOSING) + interruptible_sleep_on(&port->close_wait); #ifdef SERIAL_DO_RESTART - return ((info->flags & ASYNC_HUP_NOTIFY) ? + return ((port->flags & ASYNC_HUP_NOTIFY) ? -EAGAIN : -ERESTARTSYS); #else return -EAGAIN; @@ -1574,7 +1577,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, */ if ((filp->f_flags & O_NONBLOCK) || (tty->flags & (1 << TTY_IO_ERROR))) { - info->flags |= ASYNC_NORMAL_ACTIVE; + port->flags |= ASYNC_NORMAL_ACTIVE; return 0; } @@ -1584,23 +1587,23 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, /* * Block waiting for the carrier detect and the line to become * free (i.e., not in use by the callout). While we are in - * this loop, info->tport.count is dropped by one, so that + * this loop, port->count is dropped by one, so that * rs_close() knows when to free things. We restore it upon * exit, either normal or abnormal. */ retval = 0; - add_wait_queue(&info->tport.open_wait, &wait); + add_wait_queue(&port->open_wait, &wait); #ifdef SERIAL_DEBUG_OPEN printk("block_til_ready before block: ttys%d, count = %d\n", - info->line, info->tport.count); + info->line, port->count); #endif local_irq_save(flags); if (!tty_hung_up_p(filp)) { extra_count = 1; - info->tport.count--; + port->count--; } local_irq_restore(flags); - info->tport.blocked_open++; + port->blocked_open++; while (1) { local_irq_save(flags); if (tty->termios->c_cflag & CBAUD) @@ -1608,9 +1611,9 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, local_irq_restore(flags); set_current_state(TASK_INTERRUPTIBLE); if (tty_hung_up_p(filp) || - !(info->flags & ASYNC_INITIALIZED)) { + !(port->flags & ASYNC_INITIALIZED)) { #ifdef SERIAL_DO_RESTART - if (info->flags & ASYNC_HUP_NOTIFY) + if (port->flags & ASYNC_HUP_NOTIFY) retval = -EAGAIN; else retval = -ERESTARTSYS; @@ -1619,7 +1622,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, #endif break; } - if (!(info->flags & ASYNC_CLOSING) && + if (!(port->flags & ASYNC_CLOSING) && (do_clocal || (!(ciab.pra & SER_DCD)) )) break; if (signal_pending(current)) { @@ -1628,24 +1631,24 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, } #ifdef SERIAL_DEBUG_OPEN printk("block_til_ready blocking: ttys%d, count = %d\n", - info->line, info->tport.count); + info->line, port->count); #endif tty_unlock(); schedule(); tty_lock(); } __set_current_state(TASK_RUNNING); - remove_wait_queue(&info->tport.open_wait, &wait); + remove_wait_queue(&port->open_wait, &wait); if (extra_count) - info->tport.count++; - info->tport.blocked_open--; + port->count++; + port->blocked_open--; #ifdef SERIAL_DEBUG_OPEN printk("block_til_ready after blocking: ttys%d, count = %d\n", - info->line, info->tport.count); + info->line, port->count); #endif if (retval) return retval; - info->flags |= ASYNC_NORMAL_ACTIVE; + port->flags |= ASYNC_NORMAL_ACTIVE; return 0; } @@ -1670,17 +1673,17 @@ static int rs_open(struct tty_struct *tty, struct file * filp) #ifdef SERIAL_DEBUG_OPEN printk("rs_open %s, count = %d\n", tty->name, info->count); #endif - tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0; + tty->low_latency = (info->tport.flags & ASYNC_LOW_LATENCY) ? 1 : 0; /* * If the port is the middle of closing, bail out now */ if (tty_hung_up_p(filp) || - (info->flags & ASYNC_CLOSING)) { - if (info->flags & ASYNC_CLOSING) + (info->tport.flags & ASYNC_CLOSING)) { + if (info->tport.flags & ASYNC_CLOSING) interruptible_sleep_on(&info->tport.close_wait); #ifdef SERIAL_DO_RESTART - return ((info->flags & ASYNC_HUP_NOTIFY) ? + return ((info->tport.flags & ASYNC_HUP_NOTIFY) ? -EAGAIN : -ERESTARTSYS); #else return -EAGAIN; @@ -1723,7 +1726,7 @@ static inline void line_info(struct seq_file *m, struct serial_state *state) local_irq_save(flags); status = ciab.pra; - control = (state->flags & ASYNC_INITIALIZED) ? state->MCR : status; + control = (state->tport.flags & ASYNC_INITIALIZED) ? state->MCR : status; local_irq_restore(flags); stat_buf[0] = 0; diff --git a/include/linux/serialP.h b/include/linux/serialP.h index a6612b9..e5e8442 100644 --- a/include/linux/serialP.h +++ b/include/linux/serialP.h @@ -30,7 +30,6 @@ struct serial_state { int baud_base; unsigned long port; int irq; - int flags; int type; int line; int xmit_fifo_size; -- cgit v0.10.2 From fd2d7a6e60068779bc72029f867b51d3dc2fe0cc Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 5 Mar 2012 14:52:28 +0100 Subject: TTY: simserial, remove static initialization We do not use any of the preinitialized rs_state members for something real. So there is no need to initialize them. At the places we used them for printing, just print the values. And since only one port is supported, get rid of the loop. This simplifies simrs_init a heap. Thus we can handle fail paths in a standard way without panicing. Signed-off-by: Jiri Slaby Cc: Tony Luck Cc: Fenghua Yu Signed-off-by: Greg Kroah-Hartman diff --git a/arch/ia64/hp/sim/simserial.c b/arch/ia64/hp/sim/simserial.c index c65c49d..64ab004 100644 --- a/arch/ia64/hp/sim/simserial.c +++ b/arch/ia64/hp/sim/simserial.c @@ -49,44 +49,7 @@ static char *serial_name = "SimSerial driver"; static char *serial_version = "0.6"; -/* - * This has been extracted from asm/serial.h. We need one eventually but - * I don't know exactly what we're going to put in it so just fake one - * for now. - */ -#define BASE_BAUD ( 1843200 / 16 ) - -#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST) - -/* - * Most of the values here are meaningless to this particular driver. - * However some values must be preserved for the code (leveraged from serial.c - * to work correctly). - * port must not be 0 - * type must not be UNKNOWN - * So I picked arbitrary (guess from where?) values instead - */ -static struct serial_state rs_table[NR_PORTS]={ - /* UART CLK PORT IRQ FLAGS */ - { BASE_BAUD, 0x3F8, 0, STD_COM_FLAGS, PORT_16550 } /* ttyS0 */ -}; - -/* - * Just for the fun of it ! - */ -static struct serial_uart_config uart_config[] = { - { "unknown", 1, 0 }, - { "8250", 1, 0 }, - { "16450", 1, 0 }, - { "16550", 1, 0 }, - { "16550A", 16, UART_CLEAR_FIFO | UART_USE_FIFO }, - { "cirrus", 1, 0 }, - { "ST16650", 1, UART_CLEAR_FIFO | UART_STARTECH }, - { "ST16650V2", 32, UART_CLEAR_FIFO | UART_USE_FIFO | - UART_STARTECH }, - { "TI16750", 64, UART_CLEAR_FIFO | UART_USE_FIFO}, - { NULL, 0} -}; +static struct serial_state rs_table[NR_PORTS]; struct tty_driver *hp_simserial_driver; @@ -592,11 +555,6 @@ static int startup(struct tty_struct *tty, struct serial_state *state) goto errout; } - if (!state->port || !state->type) { - set_bit(TTY_IO_ERROR, &tty->flags); - free_page(page); - goto errout; - } if (state->xmit.buf) free_page(page); else @@ -725,9 +683,8 @@ static int rs_open(struct tty_struct *tty, struct file * filp) static inline void line_info(struct seq_file *m, struct serial_state *state) { - seq_printf(m, "%d: uart:%s port:%lX irq:%d\n", - state->line, uart_config[state->type].name, - state->port, state->irq); + seq_printf(m, "%d: uart:16550 port:3F8 irq:%d\n", + state->line, state->irq); } static int rs_proc_show(struct seq_file *m, void *v) @@ -796,11 +753,10 @@ static const struct tty_operations hp_ops = { /* * The serial driver boot-time initialization code! */ -static int __init -simrs_init (void) +static int __init simrs_init(void) { - int i, rc; - struct serial_state *state; + struct serial_state *state; + int retval; if (!ia64_platform_is("hpsim")) return -ENODEV; @@ -828,29 +784,33 @@ simrs_init (void) /* * Let's have a little bit of fun ! */ - for (i = 0, state = rs_table; i < NR_PORTS; i++,state++) { - tty_port_init(&state->tport); - state->tport.close_delay = 0; /* XXX really 0? */ + state = rs_table; + tty_port_init(&state->tport); + state->tport.close_delay = 0; /* XXX really 0? */ + + retval = hpsim_get_irq(KEYBOARD_INTR); + if (retval < 0) { + printk(KERN_ERR "%s: out of interrupt vectors!\n", + __func__); + goto err_free_tty; + } - if (state->type == PORT_UNKNOWN) continue; + state->irq = retval; - if (!state->irq) { - if ((rc = hpsim_get_irq(KEYBOARD_INTR)) < 0) - panic("%s: out of interrupt vectors!\n", - __func__); - state->irq = rc; - } + /* the port is imaginary */ + printk(KERN_INFO "ttyS%d at 0x03f8 (irq = %d) is a 16550\n", + state->line, state->irq); - printk(KERN_INFO "ttyS%d at 0x%04lx (irq = %d) is a %s\n", - state->line, - state->port, state->irq, - uart_config[state->type].name); + retval = tty_register_driver(hp_simserial_driver); + if (retval) { + printk(KERN_ERR "Couldn't register simserial driver\n"); + goto err_free_tty; } - if (tty_register_driver(hp_simserial_driver)) - panic("Couldn't register simserial driver\n"); - return 0; +err_free_tty: + put_tty_driver(hp_simserial_driver); + return retval; } #ifndef MODULE -- cgit v0.10.2 From d88405d44fd30fcbe77a9db540afd8823b30afdc Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 5 Mar 2012 14:52:29 +0100 Subject: TTY: simserial, remove tmp_buf It is totally unused. Signed-off-by: Jiri Slaby Cc: Tony Luck Cc: Fenghua Yu Signed-off-by: Greg Kroah-Hartman diff --git a/arch/ia64/hp/sim/simserial.c b/arch/ia64/hp/sim/simserial.c index 64ab004..45df0f4 100644 --- a/arch/ia64/hp/sim/simserial.c +++ b/arch/ia64/hp/sim/simserial.c @@ -55,8 +55,6 @@ struct tty_driver *hp_simserial_driver; static struct console *console; -static unsigned char *tmp_buf; - extern struct console *console_drivers; /* from kernel/printk.c */ /* @@ -237,7 +235,8 @@ static int rs_write(struct tty_struct * tty, int c, ret = 0; unsigned long flags; - if (!tty || !info->xmit.buf || !tmp_buf) return 0; + if (!tty || !info->xmit.buf) + return 0; local_irq_save(flags); while (1) { @@ -618,7 +617,6 @@ static int rs_open(struct tty_struct *tty, struct file * filp) { struct serial_state *info = rs_table + tty->index; int retval; - unsigned long page; info->tport.count++; info->tport.tty = tty; @@ -630,16 +628,6 @@ static int rs_open(struct tty_struct *tty, struct file * filp) #endif tty->low_latency = (info->tport.flags & ASYNC_LOW_LATENCY) ? 1 : 0; - if (!tmp_buf) { - page = get_zeroed_page(GFP_KERNEL); - if (!page) - return -ENOMEM; - if (tmp_buf) - free_page(page); - else - tmp_buf = (unsigned char *) page; - } - /* * If the port is the middle of closing, bail out now */ -- cgit v0.10.2 From 98e3a9e6dd99f1b8ac2a03b8b4942eec16ef911b Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 5 Mar 2012 14:52:30 +0100 Subject: TTY: simserial, stop using serial_state->{line,icount} * instead of line, use tty->index or an iterator * icount is not made public, only the tx path increments it Signed-off-by: Jiri Slaby Cc: Tony Luck Cc: Fenghua Yu Signed-off-by: Greg Kroah-Hartman diff --git a/arch/ia64/hp/sim/simserial.c b/arch/ia64/hp/sim/simserial.c index 45df0f4..3698a2f 100644 --- a/arch/ia64/hp/sim/simserial.c +++ b/arch/ia64/hp/sim/simserial.c @@ -176,7 +176,6 @@ static void transmit_chars(struct tty_struct *tty, struct serial_state *info, console->write(console, &c, 1); - info->icount.tx++; info->x_char = 0; goto out; @@ -478,7 +477,7 @@ static void rs_close(struct tty_struct *tty, struct file * filp) } if (--info->tport.count < 0) { printk(KERN_ERR "rs_close: bad serial port count for ttys%d: %d\n", - info->line, info->tport.count); + tty->index, info->tport.count); info->tport.count = 0; } if (info->tport.count) { @@ -669,19 +668,14 @@ static int rs_open(struct tty_struct *tty, struct file * filp) * /proc fs routines.... */ -static inline void line_info(struct seq_file *m, struct serial_state *state) -{ - seq_printf(m, "%d: uart:16550 port:3F8 irq:%d\n", - state->line, state->irq); -} - static int rs_proc_show(struct seq_file *m, void *v) { int i; seq_printf(m, "simserinfo:1.0 driver:%s\n", serial_version); for (i = 0; i < NR_PORTS; i++) - line_info(m, &rs_table[i]); + seq_printf(m, "%d: uart:16550 port:3F8 irq:%d\n", + i, rs_table[i].irq); return 0; } @@ -786,8 +780,7 @@ static int __init simrs_init(void) state->irq = retval; /* the port is imaginary */ - printk(KERN_INFO "ttyS%d at 0x03f8 (irq = %d) is a 16550\n", - state->line, state->irq); + printk(KERN_INFO "ttyS0 at 0x03f8 (irq = %d) is a 16550\n", state->irq); retval = tty_register_driver(hp_simserial_driver); if (retval) { -- cgit v0.10.2 From 3c4782dcd9b8d02e79f0f0bd1fe6e30a79790526 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 5 Mar 2012 14:52:31 +0100 Subject: TTY: simserial no longer needs serialP Let's do a spin-off of serial_state structure with only needed elements. And remove serialP crap from includes. Signed-off-by: Jiri Slaby Cc: Tony Luck Cc: Fenghua Yu Signed-off-by: Greg Kroah-Hartman diff --git a/arch/ia64/hp/sim/simserial.c b/arch/ia64/hp/sim/simserial.c index 3698a2f..120aad4 100644 --- a/arch/ia64/hp/sim/simserial.c +++ b/arch/ia64/hp/sim/simserial.c @@ -27,10 +27,10 @@ #include #include #include +#include #include #include #include -#include #include #include @@ -46,6 +46,13 @@ #define NR_PORTS 1 /* only one port for now */ +struct serial_state { + struct tty_port tport; + struct circ_buf xmit; + int irq; + int x_char; +}; + static char *serial_name = "SimSerial driver"; static char *serial_version = "0.6"; diff --git a/include/linux/serialP.h b/include/linux/serialP.h index e5e8442..9a04dec 100644 --- a/include/linux/serialP.h +++ b/include/linux/serialP.h @@ -44,10 +44,8 @@ struct serial_state { int quot; int IER; /* Interrupt Enable Register */ int MCR; /* Modem control register */ - /* simserial */ int x_char; /* xon/xoff character */ struct circ_buf xmit; - /* /simserial */ /* /amiserial */ }; -- cgit v0.10.2 From 7f32f8dd349bae106eccb0b9759c932875d6622e Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 5 Mar 2012 14:52:32 +0100 Subject: TTY: simserial, define local tty_port pointer And use it to make the code more readable. Since tport doesn't conflict with port anymore and there are not many tport accessors left, do also s/\/port/g. Signed-off-by: Jiri Slaby Cc: Tony Luck Cc: Fenghua Yu Signed-off-by: Greg Kroah-Hartman diff --git a/arch/ia64/hp/sim/simserial.c b/arch/ia64/hp/sim/simserial.c index 120aad4..909357e 100644 --- a/arch/ia64/hp/sim/simserial.c +++ b/arch/ia64/hp/sim/simserial.c @@ -47,7 +47,7 @@ #define NR_PORTS 1 /* only one port for now */ struct serial_state { - struct tty_port tport; + struct tty_port port; struct circ_buf xmit; int irq; int x_char; @@ -132,8 +132,9 @@ static void receive_chars(struct tty_struct *tty) static irqreturn_t rs_interrupt_single(int irq, void *dev_id) { struct serial_state *info = dev_id; + struct tty_struct *tty = info->port.tty; - if (!info->tport.tty) { + if (!tty) { printk(KERN_INFO "simrs_interrupt_single: info|tty=0 info=%p problem\n", info); return IRQ_NONE; } @@ -141,7 +142,7 @@ static irqreturn_t rs_interrupt_single(int irq, void *dev_id) * pretty simple in our case, because we only get interrupts * on inbound traffic */ - receive_chars(info->tport.tty); + receive_chars(tty); return IRQ_HANDLED; } @@ -416,7 +417,7 @@ static void shutdown(struct tty_struct *tty, struct serial_state *info) { unsigned long flags; - if (!(info->tport.flags & ASYNC_INITIALIZED)) + if (!(info->port.flags & ASYNC_INITIALIZED)) return; #ifdef SIMSERIAL_DEBUG @@ -436,7 +437,7 @@ static void shutdown(struct tty_struct *tty, struct serial_state *info) set_bit(TTY_IO_ERROR, &tty->flags); - info->tport.flags &= ~ASYNC_INITIALIZED; + info->port.flags &= ~ASYNC_INITIALIZED; } local_irq_restore(flags); } @@ -454,6 +455,7 @@ static void shutdown(struct tty_struct *tty, struct serial_state *info) static void rs_close(struct tty_struct *tty, struct file * filp) { struct serial_state *info = tty->driver_data; + struct tty_port *port = &info->port; unsigned long flags; if (!info) @@ -468,30 +470,30 @@ static void rs_close(struct tty_struct *tty, struct file * filp) return; } #ifdef SIMSERIAL_DEBUG - printk("rs_close ttys%d, count = %d\n", info->line, info->tport.count); + printk("rs_close ttys%d, count = %d\n", info->line, port->count); #endif - if ((tty->count == 1) && (info->tport.count != 1)) { + if ((tty->count == 1) && (port->count != 1)) { /* * Uh, oh. tty->count is 1, which means that the tty - * structure will be freed. info->tport.count should always + * structure will be freed. port->count should always * be one in these conditions. If it's greater than * one, we've got real problems, since it means the * serial port won't be shutdown. */ printk(KERN_ERR "rs_close: bad serial port count; tty->count is 1, " - "info->tport.count is %d\n", info->tport.count); - info->tport.count = 1; + "port->count is %d\n", port->count); + port->count = 1; } - if (--info->tport.count < 0) { + if (--port->count < 0) { printk(KERN_ERR "rs_close: bad serial port count for ttys%d: %d\n", - tty->index, info->tport.count); - info->tport.count = 0; + tty->index, port->count); + port->count = 0; } - if (info->tport.count) { + if (port->count) { local_irq_restore(flags); return; } - info->tport.flags |= ASYNC_CLOSING; + port->flags |= ASYNC_CLOSING; local_irq_restore(flags); /* @@ -501,14 +503,14 @@ static void rs_close(struct tty_struct *tty, struct file * filp) shutdown(tty, info); rs_flush_buffer(tty); tty_ldisc_flush(tty); - info->tport.tty = NULL; - if (info->tport.blocked_open) { - if (info->tport.close_delay) - schedule_timeout_interruptible(info->tport.close_delay); - wake_up_interruptible(&info->tport.open_wait); + port->tty = NULL; + if (port->blocked_open) { + if (port->close_delay) + schedule_timeout_interruptible(port->close_delay); + wake_up_interruptible(&port->open_wait); } - info->tport.flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING); - wake_up_interruptible(&info->tport.close_wait); + port->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING); + wake_up_interruptible(&port->close_wait); } /* @@ -525,26 +527,27 @@ static void rs_wait_until_sent(struct tty_struct *tty, int timeout) static void rs_hangup(struct tty_struct *tty) { struct serial_state *info = tty->driver_data; + struct tty_port *port = &info->port; #ifdef SIMSERIAL_DEBUG printk("rs_hangup: called\n"); #endif rs_flush_buffer(tty); - if (info->tport.flags & ASYNC_CLOSING) + if (port->flags & ASYNC_CLOSING) return; shutdown(tty, info); - info->tport.count = 0; - info->tport.flags &= ~ASYNC_NORMAL_ACTIVE; - info->tport.tty = NULL; - wake_up_interruptible(&info->tport.open_wait); + port->count = 0; + port->flags &= ~ASYNC_NORMAL_ACTIVE; + port->tty = NULL; + wake_up_interruptible(&port->open_wait); } static int startup(struct tty_struct *tty, struct serial_state *state) { - struct tty_port *port = &state->tport; + struct tty_port *port = &state->port; unsigned long flags; int retval=0; unsigned long page; @@ -622,26 +625,27 @@ errout: static int rs_open(struct tty_struct *tty, struct file * filp) { struct serial_state *info = rs_table + tty->index; - int retval; + struct tty_port *port = &info->port; + int retval; - info->tport.count++; - info->tport.tty = tty; + port->count++; + port->tty = tty; tty->driver_data = info; - tty->port = &info->tport; + tty->port = port; #ifdef SIMSERIAL_DEBUG - printk("rs_open %s, count = %d\n", tty->name, info->tport.count); + printk("rs_open %s, count = %d\n", tty->name, port->count); #endif - tty->low_latency = (info->tport.flags & ASYNC_LOW_LATENCY) ? 1 : 0; + tty->low_latency = (port->flags & ASYNC_LOW_LATENCY) ? 1 : 0; /* * If the port is the middle of closing, bail out now */ - if (tty_hung_up_p(filp) || (info->tport.flags & ASYNC_CLOSING)) { - if (info->tport.flags & ASYNC_CLOSING) - interruptible_sleep_on(&info->tport.close_wait); + if (tty_hung_up_p(filp) || (port->flags & ASYNC_CLOSING)) { + if (port->flags & ASYNC_CLOSING) + interruptible_sleep_on(&port->close_wait); #ifdef SERIAL_DO_RESTART - return ((info->tport.flags & ASYNC_HUP_NOTIFY) ? + return ((port->flags & ASYNC_HUP_NOTIFY) ? -EAGAIN : -ERESTARTSYS); #else return -EAGAIN; @@ -774,8 +778,8 @@ static int __init simrs_init(void) * Let's have a little bit of fun ! */ state = rs_table; - tty_port_init(&state->tport); - state->tport.close_delay = 0; /* XXX really 0? */ + tty_port_init(&state->port); + state->port.close_delay = 0; /* XXX really 0? */ retval = hpsim_get_irq(KEYBOARD_INTR); if (retval < 0) { -- cgit v0.10.2 From 2fcd5caf6d9dbf274ac7ef277f1cc541f1be9784 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 5 Mar 2012 14:52:33 +0100 Subject: TTY: simserial, remove some tty ops All ->start, ->stop and ->wait_until_sent are empty and need not be defined. The time to remove them is now. Signed-off-by: Jiri Slaby Cc: Tony Luck Cc: Fenghua Yu Signed-off-by: Greg Kroah-Hartman diff --git a/arch/ia64/hp/sim/simserial.c b/arch/ia64/hp/sim/simserial.c index 909357e..d173dba 100644 --- a/arch/ia64/hp/sim/simserial.c +++ b/arch/ia64/hp/sim/simserial.c @@ -64,32 +64,7 @@ static struct console *console; extern struct console *console_drivers; /* from kernel/printk.c */ -/* - * ------------------------------------------------------------ - * rs_stop() and rs_start() - * - * This routines are called before setting or resetting tty->stopped. - * They enable or disable transmitter interrupts, as necessary. - * ------------------------------------------------------------ - */ -static void rs_stop(struct tty_struct *tty) -{ -#ifdef SIMSERIAL_DEBUG - printk("rs_stop: tty->stopped=%d tty->hw_stopped=%d tty->flow_stopped=%d\n", - tty->stopped, tty->hw_stopped, tty->flow_stopped); -#endif - -} - -static void rs_start(struct tty_struct *tty) -{ -#ifdef SIMSERIAL_DEBUG - printk("rs_start: tty->stopped=%d tty->hw_stopped=%d tty->flow_stopped=%d\n", - tty->stopped, tty->hw_stopped, tty->flow_stopped); -#endif -} - -static void receive_chars(struct tty_struct *tty) +static void receive_chars(struct tty_struct *tty) { unsigned char ch; static unsigned char seen_esc = 0; @@ -406,7 +381,6 @@ static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios) if ((old_termios->c_cflag & CRTSCTS) && !(tty->termios->c_cflag & CRTSCTS)) { tty->hw_stopped = 0; - rs_start(tty); } } /* @@ -514,14 +488,6 @@ static void rs_close(struct tty_struct *tty, struct file * filp) } /* - * rs_wait_until_sent() --- wait until the transmitter is empty - */ -static void rs_wait_until_sent(struct tty_struct *tty, int timeout) -{ -} - - -/* * rs_hangup() --- called by tty_hangup() when a hangup is signaled. */ static void rs_hangup(struct tty_struct *tty) @@ -736,10 +702,7 @@ static const struct tty_operations hp_ops = { .unthrottle = rs_unthrottle, .send_xchar = rs_send_xchar, .set_termios = rs_set_termios, - .stop = rs_stop, - .start = rs_start, .hangup = rs_hangup, - .wait_until_sent = rs_wait_until_sent, .proc_fops = &rs_proc_fops, }; -- cgit v0.10.2 From 37343030458c0eea3f1093b09fc604d4f300eac7 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 5 Mar 2012 14:52:34 +0100 Subject: TTY: simserial, use tty_port_close_end The code is identical except locking. But added locks to protect counts do not hurt here. Rather the contrary. Signed-off-by: Jiri Slaby Cc: Tony Luck Cc: Fenghua Yu diff --git a/arch/ia64/hp/sim/simserial.c b/arch/ia64/hp/sim/simserial.c index d173dba..53db99a 100644 --- a/arch/ia64/hp/sim/simserial.c +++ b/arch/ia64/hp/sim/simserial.c @@ -478,13 +478,8 @@ static void rs_close(struct tty_struct *tty, struct file * filp) rs_flush_buffer(tty); tty_ldisc_flush(tty); port->tty = NULL; - if (port->blocked_open) { - if (port->close_delay) - schedule_timeout_interruptible(port->close_delay); - wake_up_interruptible(&port->open_wait); - } - port->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING); - wake_up_interruptible(&port->close_wait); + + tty_port_close_end(port, tty); } /* @@ -706,6 +701,9 @@ static const struct tty_operations hp_ops = { .proc_fops = &rs_proc_fops, }; +static const struct tty_port_operations hp_port_ops = { +}; + /* * The serial driver boot-time initialization code! */ @@ -742,6 +740,7 @@ static int __init simrs_init(void) */ state = rs_table; tty_port_init(&state->port); + state->port.ops = &hp_port_ops; state->port.close_delay = 0; /* XXX really 0? */ retval = hpsim_get_irq(KEYBOARD_INTR); -- cgit v0.10.2 From 78e74d778a9b3ed80bb73b65ab16f842f48aa287 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 5 Mar 2012 14:52:35 +0100 Subject: TTY: simserial, use tty_port_close_start I.e. remove more copied bloat. The only change is that we wait_until_sent now. Which is what we really should do. Signed-off-by: Jiri Slaby Cc: Tony Luck Cc: Fenghua Yu Signed-off-by: Greg Kroah-Hartman diff --git a/arch/ia64/hp/sim/simserial.c b/arch/ia64/hp/sim/simserial.c index 53db99a..2cd6d23 100644 --- a/arch/ia64/hp/sim/simserial.c +++ b/arch/ia64/hp/sim/simserial.c @@ -430,45 +430,12 @@ static void rs_close(struct tty_struct *tty, struct file * filp) { struct serial_state *info = tty->driver_data; struct tty_port *port = &info->port; - unsigned long flags; if (!info) return; - local_irq_save(flags); - if (tty_hung_up_p(filp)) { -#ifdef SIMSERIAL_DEBUG - printk("rs_close: hung_up\n"); -#endif - local_irq_restore(flags); - return; - } -#ifdef SIMSERIAL_DEBUG - printk("rs_close ttys%d, count = %d\n", info->line, port->count); -#endif - if ((tty->count == 1) && (port->count != 1)) { - /* - * Uh, oh. tty->count is 1, which means that the tty - * structure will be freed. port->count should always - * be one in these conditions. If it's greater than - * one, we've got real problems, since it means the - * serial port won't be shutdown. - */ - printk(KERN_ERR "rs_close: bad serial port count; tty->count is 1, " - "port->count is %d\n", port->count); - port->count = 1; - } - if (--port->count < 0) { - printk(KERN_ERR "rs_close: bad serial port count for ttys%d: %d\n", - tty->index, port->count); - port->count = 0; - } - if (port->count) { - local_irq_restore(flags); + if (tty_port_close_start(port, tty, filp) == 0) return; - } - port->flags |= ASYNC_CLOSING; - local_irq_restore(flags); /* * Now we wait for the transmit buffer to clear; and we notify @@ -476,7 +443,6 @@ static void rs_close(struct tty_struct *tty, struct file * filp) */ shutdown(tty, info); rs_flush_buffer(tty); - tty_ldisc_flush(tty); port->tty = NULL; tty_port_close_end(port, tty); -- cgit v0.10.2 From 3a5c24232463b4978acf8d8668becbf515d30a36 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 5 Mar 2012 14:52:36 +0100 Subject: TTY: simserial, properly refcount tty_port->tty So that we will not be surprised in the ISR anymore. Signed-off-by: Jiri Slaby Cc: Tony Luck Cc: Fenghua Yu Signed-off-by: Greg Kroah-Hartman diff --git a/arch/ia64/hp/sim/simserial.c b/arch/ia64/hp/sim/simserial.c index 2cd6d23..b3ec91c 100644 --- a/arch/ia64/hp/sim/simserial.c +++ b/arch/ia64/hp/sim/simserial.c @@ -107,7 +107,7 @@ static void receive_chars(struct tty_struct *tty) static irqreturn_t rs_interrupt_single(int irq, void *dev_id) { struct serial_state *info = dev_id; - struct tty_struct *tty = info->port.tty; + struct tty_struct *tty = tty_port_tty_get(&info->port); if (!tty) { printk(KERN_INFO "simrs_interrupt_single: info|tty=0 info=%p problem\n", info); @@ -118,6 +118,7 @@ static irqreturn_t rs_interrupt_single(int irq, void *dev_id) * on inbound traffic */ receive_chars(tty); + tty_kref_put(tty); return IRQ_HANDLED; } @@ -443,9 +444,9 @@ static void rs_close(struct tty_struct *tty, struct file * filp) */ shutdown(tty, info); rs_flush_buffer(tty); - port->tty = NULL; tty_port_close_end(port, tty); + tty_port_tty_set(port, NULL); } /* @@ -467,7 +468,7 @@ static void rs_hangup(struct tty_struct *tty) port->count = 0; port->flags &= ~ASYNC_NORMAL_ACTIVE; - port->tty = NULL; + tty_port_tty_set(port, NULL); wake_up_interruptible(&port->open_wait); } @@ -556,7 +557,7 @@ static int rs_open(struct tty_struct *tty, struct file * filp) int retval; port->count++; - port->tty = tty; + tty_port_tty_set(port, tty); tty->driver_data = info; tty->port = port; -- cgit v0.10.2 From 9aead90a7f5772fc74f733242d953688748b0ce4 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 5 Mar 2012 14:52:37 +0100 Subject: TTY: simserial, use tty_port_open So now we convert startup to be ->activate of tty_port. This means we no longer care about INITIALIZED and TTY_IO_ERROR flags. After we have ->activate much of the code may go as it duplicates what tty_port_open does. In this case tty_port_open adds block_til_ready to the path. But we do not define carrier hooks, so it is a noop. Signed-off-by: Jiri Slaby Cc: Tony Luck Cc: Fenghua Yu Signed-off-by: Greg Kroah-Hartman diff --git a/arch/ia64/hp/sim/simserial.c b/arch/ia64/hp/sim/simserial.c index b3ec91c..e9c5fb7 100644 --- a/arch/ia64/hp/sim/simserial.c +++ b/arch/ia64/hp/sim/simserial.c @@ -473,9 +473,10 @@ static void rs_hangup(struct tty_struct *tty) } -static int startup(struct tty_struct *tty, struct serial_state *state) +static int activate(struct tty_port *port, struct tty_struct *tty) { - struct tty_port *port = &state->port; + struct serial_state *state = container_of(port, struct serial_state, + port); unsigned long flags; int retval=0; unsigned long page; @@ -486,20 +487,11 @@ static int startup(struct tty_struct *tty, struct serial_state *state) local_irq_save(flags); - if (port->flags & ASYNC_INITIALIZED) { - free_page(page); - goto errout; - } - if (state->xmit.buf) free_page(page); else state->xmit.buf = (unsigned char *) page; -#ifdef SIMSERIAL_DEBUG - printk("startup: ttys%d (irq %d)...", state->line, state->irq); -#endif - /* * Allocate the IRQ if necessary */ @@ -510,18 +502,8 @@ static int startup(struct tty_struct *tty, struct serial_state *state) goto errout; } - clear_bit(TTY_IO_ERROR, &tty->flags); - state->xmit.head = state->xmit.tail = 0; -#if 0 - /* - * Set up serial timers... - */ - timer_table[RS_TIMER].expires = jiffies + 2*HZ/100; - timer_active |= 1 << RS_TIMER; -#endif - /* * Set up the tty->alt_speed kludge */ @@ -534,10 +516,6 @@ static int startup(struct tty_struct *tty, struct serial_state *state) if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP) tty->alt_speed = 460800; - port->flags |= ASYNC_INITIALIZED; - local_irq_restore(flags); - return 0; - errout: local_irq_restore(flags); return retval; @@ -554,41 +532,11 @@ static int rs_open(struct tty_struct *tty, struct file * filp) { struct serial_state *info = rs_table + tty->index; struct tty_port *port = &info->port; - int retval; - port->count++; - tty_port_tty_set(port, tty); tty->driver_data = info; - tty->port = port; - -#ifdef SIMSERIAL_DEBUG - printk("rs_open %s, count = %d\n", tty->name, port->count); -#endif tty->low_latency = (port->flags & ASYNC_LOW_LATENCY) ? 1 : 0; /* - * If the port is the middle of closing, bail out now - */ - if (tty_hung_up_p(filp) || (port->flags & ASYNC_CLOSING)) { - if (port->flags & ASYNC_CLOSING) - interruptible_sleep_on(&port->close_wait); -#ifdef SERIAL_DO_RESTART - return ((port->flags & ASYNC_HUP_NOTIFY) ? - -EAGAIN : -ERESTARTSYS); -#else - return -EAGAIN; -#endif - } - - /* - * Start up serial port - */ - retval = startup(tty, info); - if (retval) { - return retval; - } - - /* * figure out which console to use (should be one already) */ console = console_drivers; @@ -597,10 +545,7 @@ static int rs_open(struct tty_struct *tty, struct file * filp) console = console->next; } -#ifdef SIMSERIAL_DEBUG - printk("rs_open ttys%d successful\n", info->line); -#endif - return 0; + return tty_port_open(port, tty, filp); } /* @@ -669,6 +614,7 @@ static const struct tty_operations hp_ops = { }; static const struct tty_port_operations hp_port_ops = { + .activate = activate, }; /* -- cgit v0.10.2 From 458cd31a4c33ce489eb538193f801ac73ff4010b Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 5 Mar 2012 14:52:38 +0100 Subject: TTY: simserial, use tty_port_hangup Convert shutdown to be tty_port_operations->shutdown. Then we can use tty_port_hangup. (And we have to use tty_port_close.) This means we no longer touch ASYNC_INITIALIZED, TTY_IO_ERROR. Also we do not need to do any peculiar TTY logic in the file now. Signed-off-by: Jiri Slaby Cc: Tony Luck Cc: Fenghua Yu Signed-off-by: Greg Kroah-Hartman diff --git a/arch/ia64/hp/sim/simserial.c b/arch/ia64/hp/sim/simserial.c index e9c5fb7..323c932 100644 --- a/arch/ia64/hp/sim/simserial.c +++ b/arch/ia64/hp/sim/simserial.c @@ -388,17 +388,11 @@ static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios) * This routine will shutdown a serial port; interrupts are disabled, and * DTR is dropped if the hangup on close termio flag is on. */ -static void shutdown(struct tty_struct *tty, struct serial_state *info) +static void shutdown(struct tty_port *port) { - unsigned long flags; - - if (!(info->port.flags & ASYNC_INITIALIZED)) - return; - -#ifdef SIMSERIAL_DEBUG - printk("Shutting down serial port %d (irq %d)...\n", info->line, - info->irq); -#endif + struct serial_state *info = container_of(port, struct serial_state, + port); + unsigned long flags; local_irq_save(flags); { @@ -409,70 +403,25 @@ static void shutdown(struct tty_struct *tty, struct serial_state *info) free_page((unsigned long) info->xmit.buf); info->xmit.buf = NULL; } - - set_bit(TTY_IO_ERROR, &tty->flags); - - info->port.flags &= ~ASYNC_INITIALIZED; } local_irq_restore(flags); } -/* - * ------------------------------------------------------------ - * rs_close() - * - * This routine is called when the serial port gets closed. First, we - * wait for the last remaining data to be sent. Then, we unlink its - * async structure from the interrupt chain if necessary, and we free - * that IRQ if nothing is left in the chain. - * ------------------------------------------------------------ - */ static void rs_close(struct tty_struct *tty, struct file * filp) { struct serial_state *info = tty->driver_data; - struct tty_port *port = &info->port; - - if (!info) - return; - - if (tty_port_close_start(port, tty, filp) == 0) - return; - - /* - * Now we wait for the transmit buffer to clear; and we notify - * the line discipline to only process XON/XOFF characters. - */ - shutdown(tty, info); - rs_flush_buffer(tty); - tty_port_close_end(port, tty); - tty_port_tty_set(port, NULL); + tty_port_close(&info->port, tty, filp); } -/* - * rs_hangup() --- called by tty_hangup() when a hangup is signaled. - */ static void rs_hangup(struct tty_struct *tty) { struct serial_state *info = tty->driver_data; - struct tty_port *port = &info->port; - -#ifdef SIMSERIAL_DEBUG - printk("rs_hangup: called\n"); -#endif rs_flush_buffer(tty); - if (port->flags & ASYNC_CLOSING) - return; - shutdown(tty, info); - - port->count = 0; - port->flags &= ~ASYNC_NORMAL_ACTIVE; - tty_port_tty_set(port, NULL); - wake_up_interruptible(&port->open_wait); + tty_port_hangup(&info->port); } - static int activate(struct tty_port *port, struct tty_struct *tty) { struct serial_state *state = container_of(port, struct serial_state, @@ -615,6 +564,7 @@ static const struct tty_operations hp_ops = { static const struct tty_port_operations hp_port_ops = { .activate = activate, + .shutdown = shutdown, }; /* -- cgit v0.10.2 From adb636fe0845bf1b4dbcb546a1673f40a95062fd Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 5 Mar 2012 14:52:39 +0100 Subject: TTY: simserial, remove useless comments Or the obsolete ones like: "Let's have a little bit of fun" I have never had fun with software. For fun, one needs hard-ware. Signed-off-by: Jiri Slaby Cc: Tony Luck Cc: Fenghua Yu Signed-off-by: Greg Kroah-Hartman diff --git a/arch/ia64/hp/sim/simserial.c b/arch/ia64/hp/sim/simserial.c index 323c932..d8237c3 100644 --- a/arch/ia64/hp/sim/simserial.c +++ b/arch/ia64/hp/sim/simserial.c @@ -4,16 +4,11 @@ * This driver is mostly used for bringup purposes and will go away. * It has a strong dependency on the system console. All outputs * are rerouted to the same facility as the one used by printk which, in our - * case means sys_sim.c console (goes via the simulator). The code hereafter - * is completely leveraged from the serial.c driver. + * case means sys_sim.c console (goes via the simulator). * * Copyright (C) 1999-2000, 2002-2003 Hewlett-Packard Co * Stephane Eranian * David Mosberger-Tang - * - * 02/04/00 D. Mosberger Merged in serial.c bug fixes in rs_close(). - * 02/25/00 D. Mosberger Synced up with 2.3.99pre-5 version of serial.c. - * 07/30/02 D. Mosberger Replace sti()/cli() with explicit spinlocks & local irq masking */ #include @@ -441,9 +436,6 @@ static int activate(struct tty_port *port, struct tty_struct *tty) else state->xmit.buf = (unsigned char *) page; - /* - * Allocate the IRQ if necessary - */ if (state->irq) { retval = request_irq(state->irq, rs_interrupt_single, 0, "simserial", state); @@ -525,19 +517,6 @@ static const struct file_operations rs_proc_fops = { .release = single_release, }; -/* - * --------------------------------------------------------------------- - * rs_init() and friends - * - * rs_init() is called at boot-time to initialize the serial driver. - * --------------------------------------------------------------------- - */ - -/* - * This routine prints out the appropriate serial driver version - * number, and identifies which options were configured into this - * driver. - */ static inline void show_serial_version(void) { printk(KERN_INFO "%s version %s with", serial_name, serial_version); @@ -567,9 +546,6 @@ static const struct tty_port_operations hp_port_ops = { .shutdown = shutdown, }; -/* - * The serial driver boot-time initialization code! - */ static int __init simrs_init(void) { struct serial_state *state; @@ -598,9 +574,6 @@ static int __init simrs_init(void) hp_simserial_driver->flags = TTY_DRIVER_REAL_RAW; tty_set_operations(hp_simserial_driver, &hp_ops); - /* - * Let's have a little bit of fun ! - */ state = rs_table; tty_port_init(&state->port); state->port.ops = &hp_port_ops; -- cgit v0.10.2 From 8b916330567b0b788f35ded5d99a7ef7dc30b293 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 5 Mar 2012 14:52:40 +0100 Subject: TTY: simserial, fix includes Use headers from linux/* instead of asm/. Remove declaration of console_drivers, it's in linux/console.h already. Signed-off-by: Jiri Slaby Cc: Tony Luck Cc: Fenghua Yu Signed-off-by: Greg Kroah-Hartman diff --git a/arch/ia64/hp/sim/simserial.c b/arch/ia64/hp/sim/simserial.c index d8237c3..24d6ca0 100644 --- a/arch/ia64/hp/sim/simserial.c +++ b/arch/ia64/hp/sim/simserial.c @@ -24,14 +24,13 @@ #include #include #include +#include #include #include #include +#include -#include #include -#include -#include #include "hpsim_ssc.h" @@ -57,8 +56,6 @@ struct tty_driver *hp_simserial_driver; static struct console *console; -extern struct console *console_drivers; /* from kernel/printk.c */ - static void receive_chars(struct tty_struct *tty) { unsigned char ch; -- cgit v0.10.2 From f66279cd7d5cdf43686da0d9ed20378581b88d0f Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 5 Mar 2012 14:52:41 +0100 Subject: TTY: simserial, reindent some code Make the code to conform to the standard. Also make it readable. Signed-off-by: Jiri Slaby Cc: Tony Luck Cc: Fenghua Yu Signed-off-by: Greg Kroah-Hartman diff --git a/arch/ia64/hp/sim/simserial.c b/arch/ia64/hp/sim/simserial.c index 24d6ca0..516ad09 100644 --- a/arch/ia64/hp/sim/simserial.c +++ b/arch/ia64/hp/sim/simserial.c @@ -62,28 +62,25 @@ static void receive_chars(struct tty_struct *tty) static unsigned char seen_esc = 0; while ( (ch = ia64_ssc(0, 0, 0, 0, SSC_GETCHAR)) ) { - if ( ch == 27 && seen_esc == 0 ) { + if (ch == 27 && seen_esc == 0) { seen_esc = 1; continue; - } else { - if ( seen_esc==1 && ch == 'O' ) { - seen_esc = 2; - continue; - } else if ( seen_esc == 2 ) { - if ( ch == 'P' ) /* F1 */ - show_state(); + } else if (seen_esc == 1 && ch == 'O') { + seen_esc = 2; + continue; + } else if (seen_esc == 2) { + if (ch == 'P') /* F1 */ + show_state(); #ifdef CONFIG_MAGIC_SYSRQ - if ( ch == 'S' ) { /* F4 */ - do - ch = ia64_ssc(0, 0, 0, 0, - SSC_GETCHAR); - while (!ch); - handle_sysrq(ch); - } -#endif - seen_esc = 0; - continue; + if (ch == 'S') { /* F4 */ + do { + ch = ia64_ssc(0, 0, 0, 0, SSC_GETCHAR); + } while (!ch); + handle_sysrq(ch); } +#endif + seen_esc = 0; + continue; } seen_esc = 0; @@ -195,8 +192,8 @@ static void rs_flush_chars(struct tty_struct *tty) { struct serial_state *info = tty->driver_data; - if (info->xmit.head == info->xmit.tail || tty->stopped || tty->hw_stopped || - !info->xmit.buf) + if (info->xmit.head == info->xmit.tail || tty->stopped || + tty->hw_stopped || !info->xmit.buf) return; transmit_chars(tty, info, NULL); @@ -232,10 +229,10 @@ static int rs_write(struct tty_struct * tty, /* * Hey, we transmit directly from here in our case */ - if (CIRC_CNT(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE) - && !tty->stopped && !tty->hw_stopped) { + if (CIRC_CNT(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE) && + !tty->stopped && !tty->hw_stopped) transmit_chars(tty, info, NULL); - } + return ret; } @@ -293,7 +290,8 @@ static void rs_send_xchar(struct tty_struct *tty, char ch) */ static void rs_throttle(struct tty_struct * tty) { - if (I_IXOFF(tty)) rs_send_xchar(tty, STOP_CHAR(tty)); + if (I_IXOFF(tty)) + rs_send_xchar(tty, STOP_CHAR(tty)); printk(KERN_INFO "simrs_throttle called\n"); } @@ -322,48 +320,21 @@ static int rs_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg) } switch (cmd) { - case TIOCGSERIAL: - printk(KERN_INFO "simrs_ioctl TIOCGSERIAL called\n"); - return 0; - case TIOCSSERIAL: - printk(KERN_INFO "simrs_ioctl TIOCSSERIAL called\n"); - return 0; - case TIOCSERCONFIG: - printk(KERN_INFO "rs_ioctl: TIOCSERCONFIG called\n"); - return -EINVAL; - - case TIOCSERGETLSR: /* Get line status register */ - printk(KERN_INFO "rs_ioctl: TIOCSERGETLSR called\n"); - return -EINVAL; - - case TIOCSERGSTRUCT: - printk(KERN_INFO "rs_ioctl: TIOCSERGSTRUCT called\n"); -#if 0 - if (copy_to_user((struct async_struct *) arg, - info, sizeof(struct async_struct))) - return -EFAULT; -#endif - return 0; - - /* - * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change - * - mask passed in arg for lines of interest - * (use |'ed TIOCM_RNG/DSR/CD/CTS for masking) - * Caller should use TIOCGICOUNT to see which one it was - */ - case TIOCMIWAIT: - printk(KERN_INFO "rs_ioctl: TIOCMIWAIT: called\n"); - return 0; - case TIOCSERGWILD: - case TIOCSERSWILD: - /* "setserial -W" is called in Debian boot */ - printk (KERN_INFO "TIOCSER?WILD ioctl obsolete, ignored.\n"); - return 0; - - default: - return -ENOIOCTLCMD; - } - return 0; + case TIOCGSERIAL: + case TIOCSSERIAL: + case TIOCSERGSTRUCT: + case TIOCMIWAIT: + return 0; + case TIOCSERCONFIG: + case TIOCSERGETLSR: /* Get line status register */ + return -EINVAL; + case TIOCSERGWILD: + case TIOCSERSWILD: + /* "setserial -W" is called in Debian boot */ + printk (KERN_INFO "TIOCSER?WILD ioctl obsolete, ignored.\n"); + return 0; + } + return -ENOIOCTLCMD; } #define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK)) @@ -387,14 +358,12 @@ static void shutdown(struct tty_port *port) unsigned long flags; local_irq_save(flags); - { - if (info->irq) - free_irq(info->irq, info); + if (info->irq) + free_irq(info->irq, info); - if (info->xmit.buf) { - free_page((unsigned long) info->xmit.buf); - info->xmit.buf = NULL; - } + if (info->xmit.buf) { + free_page((unsigned long) info->xmit.buf); + info->xmit.buf = NULL; } local_irq_restore(flags); } @@ -418,9 +387,8 @@ static int activate(struct tty_port *port, struct tty_struct *tty) { struct serial_state *state = container_of(port, struct serial_state, port); - unsigned long flags; - int retval=0; - unsigned long page; + unsigned long flags, page; + int retval = 0; page = get_zeroed_page(GFP_KERNEL); if (!page) -- cgit v0.10.2 From 6e9ebcfa20b15f0ccdd4b5395a3c63f79c21fa57 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 5 Mar 2012 14:52:42 +0100 Subject: TTY: simserial, final cleanup * remove pointless checks (tty cannot be NULL at that points) * fix some printks (use __func__, print text directly w/o using global strings) * remove some empty lines This is the last patch for simserial. Overall, the driver is 400 lines shorter. Being now at 560 lines. It was tested using ski with a busybox userspace. Signed-off-by: Jiri Slaby Cc: Tony Luck Cc: Fenghua Yu Signed-off-by: Greg Kroah-Hartman diff --git a/arch/ia64/hp/sim/simserial.c b/arch/ia64/hp/sim/simserial.c index 516ad09..c34785d 100644 --- a/arch/ia64/hp/sim/simserial.c +++ b/arch/ia64/hp/sim/simserial.c @@ -47,9 +47,6 @@ struct serial_state { int x_char; }; -static char *serial_name = "SimSerial driver"; -static char *serial_version = "0.6"; - static struct serial_state rs_table[NR_PORTS]; struct tty_driver *hp_simserial_driver; @@ -99,7 +96,7 @@ static irqreturn_t rs_interrupt_single(int irq, void *dev_id) struct tty_struct *tty = tty_port_tty_get(&info->port); if (!tty) { - printk(KERN_INFO "simrs_interrupt_single: info|tty=0 info=%p problem\n", info); + printk(KERN_INFO "%s: tty=0 problem\n", __func__); return IRQ_NONE; } /* @@ -122,7 +119,7 @@ static int rs_put_char(struct tty_struct *tty, unsigned char ch) struct serial_state *info = tty->driver_data; unsigned long flags; - if (!tty || !info->xmit.buf) + if (!info->xmit.buf) return 0; local_irq_save(flags); @@ -199,7 +196,6 @@ static void rs_flush_chars(struct tty_struct *tty) transmit_chars(tty, info, NULL); } - static int rs_write(struct tty_struct * tty, const unsigned char *buf, int count) { @@ -207,7 +203,7 @@ static int rs_write(struct tty_struct * tty, int c, ret = 0; unsigned long flags; - if (!tty || !info->xmit.buf) + if (!info->xmit.buf) return 0; local_irq_save(flags); @@ -309,7 +305,6 @@ static void rs_unthrottle(struct tty_struct * tty) printk(KERN_INFO "simrs_unthrottle called\n"); } - static int rs_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg) { if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) && @@ -462,7 +457,7 @@ static int rs_proc_show(struct seq_file *m, void *v) { int i; - seq_printf(m, "simserinfo:1.0 driver:%s\n", serial_version); + seq_printf(m, "simserinfo:1.0\n"); for (i = 0; i < NR_PORTS; i++) seq_printf(m, "%d: uart:16550 port:3F8 irq:%d\n", i, rs_table[i].irq); @@ -482,12 +477,6 @@ static const struct file_operations rs_proc_fops = { .release = single_release, }; -static inline void show_serial_version(void) -{ - printk(KERN_INFO "%s version %s with", serial_name, serial_version); - printk(KERN_INFO " no serial options enabled\n"); -} - static const struct tty_operations hp_ops = { .open = rs_open, .close = rs_close, @@ -523,7 +512,7 @@ static int __init simrs_init(void) if (!hp_simserial_driver) return -ENOMEM; - show_serial_version(); + printk(KERN_INFO "SimSerial driver with no serial options enabled\n"); /* Initialize the tty_driver structure */ -- cgit v0.10.2 From 7188dc202a9bdc3c6552232e036be471b0c50406 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 5 Mar 2012 14:52:43 +0100 Subject: TTY: amiserial, define local tty_port pointer And use it to make the code more readable. Signed-off-by: Jiri Slaby Cc: Geert Uytterhoeven Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/amiserial.c b/drivers/tty/amiserial.c index 7d79826..a9f5da6 100644 --- a/drivers/tty/amiserial.c +++ b/drivers/tty/amiserial.c @@ -361,6 +361,7 @@ static void transmit_chars(struct serial_state *info) static void check_modem_status(struct serial_state *info) { + struct tty_port *port = &info->tport; unsigned char status = ciab.pra & (SER_DCD | SER_CTS | SER_DSR); unsigned char dstatus; struct async_icount *icount; @@ -377,45 +378,45 @@ static void check_modem_status(struct serial_state *info) if (dstatus & SER_DCD) { icount->dcd++; #ifdef CONFIG_HARD_PPS - if ((info->tport.flags & ASYNC_HARDPPS_CD) && + if ((port->flags & ASYNC_HARDPPS_CD) && !(status & SER_DCD)) hardpps(); #endif } if (dstatus & SER_CTS) icount->cts++; - wake_up_interruptible(&info->tport.delta_msr_wait); + wake_up_interruptible(&port->delta_msr_wait); } - if ((info->tport.flags & ASYNC_CHECK_CD) && (dstatus & SER_DCD)) { + if ((port->flags & ASYNC_CHECK_CD) && (dstatus & SER_DCD)) { #if (defined(SERIAL_DEBUG_OPEN) || defined(SERIAL_DEBUG_INTR)) printk("ttyS%d CD now %s...", info->line, (!(status & SER_DCD)) ? "on" : "off"); #endif if (!(status & SER_DCD)) - wake_up_interruptible(&info->tport.open_wait); + wake_up_interruptible(&port->open_wait); else { #ifdef SERIAL_DEBUG_OPEN printk("doing serial hangup..."); #endif - if (info->tport.tty) - tty_hangup(info->tport.tty); + if (port->tty) + tty_hangup(port->tty); } } - if (info->tport.flags & ASYNC_CTS_FLOW) { - if (info->tport.tty->hw_stopped) { + if (port->flags & ASYNC_CTS_FLOW) { + if (port->tty->hw_stopped) { if (!(status & SER_CTS)) { #if (defined(SERIAL_DEBUG_INTR) || defined(SERIAL_DEBUG_FLOW)) printk("CTS tx start..."); #endif - info->tport.tty->hw_stopped = 0; + port->tty->hw_stopped = 0; info->IER |= UART_IER_THRI; custom.intena = IF_SETCLR | IF_TBE; mb(); /* set a pending Tx Interrupt, transmitter should restart now */ custom.intreq = IF_SETCLR | IF_TBE; mb(); - tty_wakeup(info->tport.tty); + tty_wakeup(port->tty); return; } } else { @@ -423,7 +424,7 @@ static void check_modem_status(struct serial_state *info) #if (defined(SERIAL_DEBUG_INTR) || defined(SERIAL_DEBUG_FLOW)) printk("CTS tx stop..."); #endif - info->tport.tty->hw_stopped = 1; + port->tty->hw_stopped = 1; info->IER &= ~UART_IER_THRI; /* disable Tx interrupt and remove any pending interrupts */ custom.intena = IF_TBE; @@ -1371,6 +1372,7 @@ static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios) static void rs_close(struct tty_struct *tty, struct file * filp) { struct serial_state *state = tty->driver_data; + struct tty_port *port = &state->tport; unsigned long flags; if (!state || serial_paranoia_check(state, tty->name, "rs_close")) @@ -1385,38 +1387,38 @@ static void rs_close(struct tty_struct *tty, struct file * filp) } #ifdef SERIAL_DEBUG_OPEN - printk("rs_close ttys%d, count = %d\n", state->line, state->tport.count); + printk("rs_close ttys%d, count = %d\n", state->line, port->count); #endif - if ((tty->count == 1) && (state->tport.count != 1)) { + if ((tty->count == 1) && (port->count != 1)) { /* * Uh, oh. tty->count is 1, which means that the tty - * structure will be freed. state->tport.count should always + * structure will be freed. port->count should always * be one in these conditions. If it's greater than * one, we've got real problems, since it means the * serial port won't be shutdown. */ printk("rs_close: bad serial port count; tty->count is 1, " - "state->tport.count is %d\n", state->tport.count); - state->tport.count = 1; + "port->count is %d\n", state->tport.count); + port->count = 1; } - if (--state->tport.count < 0) { + if (--port->count < 0) { printk("rs_close: bad serial port count for ttys%d: %d\n", - state->line, state->tport.count); - state->tport.count = 0; + state->line, port->count); + port->count = 0; } - if (state->tport.count) { + if (port->count) { DBG_CNT("before DEC-2"); local_irq_restore(flags); return; } - state->tport.flags |= ASYNC_CLOSING; + port->flags |= ASYNC_CLOSING; /* * Now we wait for the transmit buffer to clear; and we notify * the line discipline to only process XON/XOFF characters. */ tty->closing = 1; - if (state->tport.closing_wait != ASYNC_CLOSING_WAIT_NONE) - tty_wait_until_sent(tty, state->tport.closing_wait); + if (port->closing_wait != ASYNC_CLOSING_WAIT_NONE) + tty_wait_until_sent(tty, port->closing_wait); /* * At this point we stop accepting input. To do this, we * disable the receive line status interrupts, and tell the @@ -1424,7 +1426,7 @@ static void rs_close(struct tty_struct *tty, struct file * filp) * line status register. */ state->read_status_mask &= ~UART_LSR_DR; - if (state->tport.flags & ASYNC_INITIALIZED) { + if (port->flags & ASYNC_INITIALIZED) { /* disable receive interrupts */ custom.intena = IF_RBF; mb(); @@ -1444,15 +1446,15 @@ static void rs_close(struct tty_struct *tty, struct file * filp) tty_ldisc_flush(tty); tty->closing = 0; - state->tport.tty = NULL; - if (state->tport.blocked_open) { - if (state->tport.close_delay) { - msleep_interruptible(jiffies_to_msecs(state->tport.close_delay)); + port->tty = NULL; + if (port->blocked_open) { + if (port->close_delay) { + msleep_interruptible(jiffies_to_msecs(port->close_delay)); } - wake_up_interruptible(&state->tport.open_wait); + wake_up_interruptible(&port->open_wait); } - state->tport.flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING); - wake_up_interruptible(&state->tport.close_wait); + port->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING); + wake_up_interruptible(&port->close_wait); local_irq_restore(flags); } @@ -1661,29 +1663,30 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, static int rs_open(struct tty_struct *tty, struct file * filp) { struct serial_state *info = rs_table + tty->index; + struct tty_port *port = &info->tport; int retval; - info->tport.count++; - info->tport.tty = tty; + port->count++; + port->tty = tty; tty->driver_data = info; - tty->port = &info->tport; + tty->port = port; if (serial_paranoia_check(info, tty->name, "rs_open")) return -ENODEV; #ifdef SERIAL_DEBUG_OPEN printk("rs_open %s, count = %d\n", tty->name, info->count); #endif - tty->low_latency = (info->tport.flags & ASYNC_LOW_LATENCY) ? 1 : 0; + tty->low_latency = (port->flags & ASYNC_LOW_LATENCY) ? 1 : 0; /* * If the port is the middle of closing, bail out now */ if (tty_hung_up_p(filp) || - (info->tport.flags & ASYNC_CLOSING)) { - if (info->tport.flags & ASYNC_CLOSING) - interruptible_sleep_on(&info->tport.close_wait); + (port->flags & ASYNC_CLOSING)) { + if (port->flags & ASYNC_CLOSING) + interruptible_sleep_on(&port->close_wait); #ifdef SERIAL_DO_RESTART - return ((info->tport.flags & ASYNC_HUP_NOTIFY) ? + return ((port->flags & ASYNC_HUP_NOTIFY) ? -EAGAIN : -ERESTARTSYS); #else return -EAGAIN; -- cgit v0.10.2 From ff169e5cbec29d33765687c7131673316011b328 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 5 Mar 2012 14:52:44 +0100 Subject: TTY: amiserial, stop using serial_state->{irq,type,line} * instead of line, use tty->index or iterator... * irq and type are left unset. So get rid of them. Signed-off-by: Jiri Slaby Cc: Geert Uytterhoeven Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/amiserial.c b/drivers/tty/amiserial.c index a9f5da6..b182bcc 100644 --- a/drivers/tty/amiserial.c +++ b/drivers/tty/amiserial.c @@ -1008,7 +1008,7 @@ static void rs_unthrottle(struct tty_struct * tty) * ------------------------------------------------------------ */ -static int get_serial_info(struct serial_state *state, +static int get_serial_info(struct tty_struct *tty, struct serial_state *state, struct serial_struct __user * retinfo) { struct serial_struct tmp; @@ -1017,10 +1017,8 @@ static int get_serial_info(struct serial_state *state, return -EFAULT; memset(&tmp, 0, sizeof(tmp)); tty_lock(); - tmp.type = state->type; - tmp.line = state->line; + tmp.line = tty->index; tmp.port = state->port; - tmp.irq = state->irq; tmp.flags = state->tport.flags; tmp.xmit_fifo_size = state->xmit_fifo_size; tmp.baud_base = state->baud_base; @@ -1047,7 +1045,7 @@ static int set_serial_info(struct tty_struct *tty, struct serial_state *state, tty_lock(); change_spd = ((new_serial.flags ^ port->flags) & ASYNC_SPD_MASK) || new_serial.custom_divisor != state->custom_divisor; - if (new_serial.irq != state->irq || new_serial.port != state->port || + if (new_serial.irq || new_serial.port != state->port || new_serial.xmit_fifo_size != state->xmit_fifo_size) { tty_unlock(); return -EINVAL; @@ -1250,7 +1248,7 @@ static int rs_ioctl(struct tty_struct *tty, switch (cmd) { case TIOCGSERIAL: - return get_serial_info(info, argp); + return get_serial_info(tty, info, argp); case TIOCSSERIAL: return set_serial_info(tty, info, argp); case TIOCSERCONFIG: @@ -1403,7 +1401,7 @@ static void rs_close(struct tty_struct *tty, struct file * filp) } if (--port->count < 0) { printk("rs_close: bad serial port count for ttys%d: %d\n", - state->line, port->count); + tty->index, port->count); port->count = 0; } if (port->count) { @@ -1720,12 +1718,13 @@ static int rs_open(struct tty_struct *tty, struct file * filp) * /proc fs routines.... */ -static inline void line_info(struct seq_file *m, struct serial_state *state) +static inline void line_info(struct seq_file *m, int line, + struct serial_state *state) { char stat_buf[30], control, status; unsigned long flags; - seq_printf(m, "%d: uart:amiga_builtin",state->line); + seq_printf(m, "%d: uart:amiga_builtin", line); local_irq_save(flags); status = ciab.pra; @@ -1771,7 +1770,7 @@ static inline void line_info(struct seq_file *m, struct serial_state *state) static int rs_proc_show(struct seq_file *m, void *v) { seq_printf(m, "serinfo:1.0 driver:%s\n", serial_version); - line_info(m, &rs_table[0]); + line_info(m, 0, &rs_table[0]); return 0; } @@ -1867,7 +1866,6 @@ static int __init amiga_serial_probe(struct platform_device *pdev) state = rs_table; state->port = (int)&custom.serdatr; /* Just to give it a value */ - state->line = 0; state->custom_divisor = 0; state->icount.cts = state->icount.dsr = state->icount.rng = state->icount.dcd = 0; @@ -1876,8 +1874,7 @@ static int __init amiga_serial_probe(struct platform_device *pdev) state->icount.overrun = state->icount.brk = 0; tty_port_init(&state->tport); - printk(KERN_INFO "ttyS%d is the amiga builtin serial port\n", - state->line); + printk(KERN_INFO "ttyS0 is the amiga builtin serial port\n"); /* Hardware set up */ diff --git a/include/linux/serialP.h b/include/linux/serialP.h index 9a04dec..77afbdb 100644 --- a/include/linux/serialP.h +++ b/include/linux/serialP.h @@ -29,9 +29,6 @@ struct serial_state { int baud_base; unsigned long port; - int irq; - int type; - int line; int xmit_fifo_size; int custom_divisor; struct async_icount icount; -- cgit v0.10.2 From 6fe18d26b1c33d5cb748f8694ee1a59dc5578da4 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 5 Mar 2012 14:52:45 +0100 Subject: TTY: amiserial no longer needs serialP amiserial is the last user of serialP.h. Let's move struct serial_state directly to amiserial and remove serialP crap from includes. Finally, remove the header from the tree completely. Signed-off-by: Jiri Slaby Cc: Geert Uytterhoeven Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/amiserial.c b/drivers/tty/amiserial.c index b182bcc..613d6a3 100644 --- a/drivers/tty/amiserial.c +++ b/drivers/tty/amiserial.c @@ -58,7 +58,6 @@ #include #include -#include #include static char *serial_version = "4.30"; @@ -70,6 +69,7 @@ static char *serial_version = "4.30"; #include #include #include +#include #include #include #include @@ -92,6 +92,24 @@ static char *serial_version = "4.30"; #include #include +struct serial_state { + struct tty_port tport; + struct circ_buf xmit; + struct async_icount icount; + + unsigned long port; + int baud_base; + int xmit_fifo_size; + int custom_divisor; + int read_status_mask; + int ignore_status_mask; + int timeout; + int quot; + int IER; /* Interrupt Enable Register */ + int MCR; /* Modem control register */ + int x_char; /* xon/xoff character */ +}; + #define custom amiga_custom static char *serial_name = "Amiga-builtin serial driver"; diff --git a/include/linux/serialP.h b/include/linux/serialP.h deleted file mode 100644 index 77afbdb..0000000 --- a/include/linux/serialP.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Private header file for the (dumb) serial driver - * - * Copyright (C) 1997 by Theodore Ts'o. - * - * Redistribution of this file is permitted under the terms of the GNU - * Public License (GPL) - */ - -#ifndef _LINUX_SERIALP_H -#define _LINUX_SERIALP_H - -/* - * This is our internal structure for each serial port's state. - * - * Many fields are paralleled by the structure used by the serial_struct - * structure. - * - * For definitions of the flags field, see tty.h - */ - -#include -#include -#include -#include -#include -#include - -struct serial_state { - int baud_base; - unsigned long port; - int xmit_fifo_size; - int custom_divisor; - struct async_icount icount; - struct tty_port tport; - - /* amiserial */ - int read_status_mask; - int ignore_status_mask; - int timeout; - int quot; - int IER; /* Interrupt Enable Register */ - int MCR; /* Modem control register */ - int x_char; /* xon/xoff character */ - struct circ_buf xmit; - /* /amiserial */ -}; - -#endif /* _LINUX_SERIAL_H */ -- cgit v0.10.2 From f1166604f58e842a0bb5a639d6728ce6e2250495 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 5 Mar 2012 14:52:46 +0100 Subject: TTY: amiserial, provide carrier helpers This is a preparation for a switch to tty_port_block_til_ready. We need amiga_carrier_raised and amiga_dtr_rts. The implementation is taken from startup, shutdown and current block_til_ready. Signed-off-by: Jiri Slaby Cc: Geert Uytterhoeven Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/amiserial.c b/drivers/tty/amiserial.c index 613d6a3..61d7461 100644 --- a/drivers/tty/amiserial.c +++ b/drivers/tty/amiserial.c @@ -1623,10 +1623,8 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, local_irq_restore(flags); port->blocked_open++; while (1) { - local_irq_save(flags); if (tty->termios->c_cflag & CBAUD) - rtsdtr_ctrl(SER_DTR|SER_RTS); - local_irq_restore(flags); + tty_port_raise_dtr_rts(port); set_current_state(TASK_INTERRUPTIBLE); if (tty_hung_up_p(filp) || !(port->flags & ASYNC_INITIALIZED)) { @@ -1641,7 +1639,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, break; } if (!(port->flags & ASYNC_CLOSING) && - (do_clocal || (!(ciab.pra & SER_DCD)) )) + (do_clocal || tty_port_carrier_raised(port))) break; if (signal_pending(current)) { retval = -ERESTARTSYS; @@ -1849,6 +1847,32 @@ static const struct tty_operations serial_ops = { .proc_fops = &rs_proc_fops, }; +static int amiga_carrier_raised(struct tty_port *port) +{ + return !(ciab.pra & SER_DCD); +} + +static void amiga_dtr_rts(struct tty_port *port, int raise) +{ + struct serial_state *info = container_of(port, struct serial_state, + tport); + unsigned long flags; + + if (raise) + info->MCR |= SER_DTR|SER_RTS; + else + info->MCR &= ~(SER_DTR|SER_RTS); + + local_irq_save(flags); + rtsdtr_ctrl(info->MCR); + local_irq_restore(flags); +} + +static const struct tty_port_operations amiga_port_ops = { + .carrier_raised = amiga_carrier_raised, + .dtr_rts = amiga_dtr_rts, +}; + /* * The serial driver boot-time initialization code! */ @@ -1891,6 +1915,7 @@ static int __init amiga_serial_probe(struct platform_device *pdev) state->icount.frame = state->icount.parity = 0; state->icount.overrun = state->icount.brk = 0; tty_port_init(&state->tport); + state->tport.ops = &amiga_port_ops; printk(KERN_INFO "ttyS0 is the amiga builtin serial port\n"); -- cgit v0.10.2 From 6e1aeb0379f47b51ad4d25e5e0d9648dbd50f0b9 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 5 Mar 2012 14:52:47 +0100 Subject: TTY: amiserial, use tty_port_block_til_ready Hmm, 150 lines of duplicated stuff is gone now. Signed-off-by: Jiri Slaby Cc: Geert Uytterhoeven Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/amiserial.c b/drivers/tty/amiserial.c index 61d7461..8cc8e15 100644 --- a/drivers/tty/amiserial.c +++ b/drivers/tty/amiserial.c @@ -1556,119 +1556,6 @@ static void rs_hangup(struct tty_struct *tty) } /* - * ------------------------------------------------------------ - * rs_open() and friends - * ------------------------------------------------------------ - */ -static int block_til_ready(struct tty_struct *tty, struct file * filp, - struct serial_state *info) -{ -#ifdef DECLARE_WAITQUEUE - DECLARE_WAITQUEUE(wait, current); -#else - struct wait_queue wait = { current, NULL }; -#endif - struct tty_port *port = &info->tport; - int retval; - int do_clocal = 0, extra_count = 0; - unsigned long flags; - - /* - * If the device is in the middle of being closed, then block - * until it's done, and then try again. - */ - if (tty_hung_up_p(filp) || - (port->flags & ASYNC_CLOSING)) { - if (port->flags & ASYNC_CLOSING) - interruptible_sleep_on(&port->close_wait); -#ifdef SERIAL_DO_RESTART - return ((port->flags & ASYNC_HUP_NOTIFY) ? - -EAGAIN : -ERESTARTSYS); -#else - return -EAGAIN; -#endif - } - - /* - * If non-blocking mode is set, or the port is not enabled, - * then make the check up front and then exit. - */ - if ((filp->f_flags & O_NONBLOCK) || - (tty->flags & (1 << TTY_IO_ERROR))) { - port->flags |= ASYNC_NORMAL_ACTIVE; - return 0; - } - - if (tty->termios->c_cflag & CLOCAL) - do_clocal = 1; - - /* - * Block waiting for the carrier detect and the line to become - * free (i.e., not in use by the callout). While we are in - * this loop, port->count is dropped by one, so that - * rs_close() knows when to free things. We restore it upon - * exit, either normal or abnormal. - */ - retval = 0; - add_wait_queue(&port->open_wait, &wait); -#ifdef SERIAL_DEBUG_OPEN - printk("block_til_ready before block: ttys%d, count = %d\n", - info->line, port->count); -#endif - local_irq_save(flags); - if (!tty_hung_up_p(filp)) { - extra_count = 1; - port->count--; - } - local_irq_restore(flags); - port->blocked_open++; - while (1) { - if (tty->termios->c_cflag & CBAUD) - tty_port_raise_dtr_rts(port); - set_current_state(TASK_INTERRUPTIBLE); - if (tty_hung_up_p(filp) || - !(port->flags & ASYNC_INITIALIZED)) { -#ifdef SERIAL_DO_RESTART - if (port->flags & ASYNC_HUP_NOTIFY) - retval = -EAGAIN; - else - retval = -ERESTARTSYS; -#else - retval = -EAGAIN; -#endif - break; - } - if (!(port->flags & ASYNC_CLOSING) && - (do_clocal || tty_port_carrier_raised(port))) - break; - if (signal_pending(current)) { - retval = -ERESTARTSYS; - break; - } -#ifdef SERIAL_DEBUG_OPEN - printk("block_til_ready blocking: ttys%d, count = %d\n", - info->line, port->count); -#endif - tty_unlock(); - schedule(); - tty_lock(); - } - __set_current_state(TASK_RUNNING); - remove_wait_queue(&port->open_wait, &wait); - if (extra_count) - port->count++; - port->blocked_open--; -#ifdef SERIAL_DEBUG_OPEN - printk("block_til_ready after blocking: ttys%d, count = %d\n", - info->line, port->count); -#endif - if (retval) - return retval; - port->flags |= ASYNC_NORMAL_ACTIVE; - return 0; -} - -/* * This routine is called whenever a serial port is opened. It * enables interrupts for a serial port, linking in its async structure into * the IRQ chain. It also performs the serial-specific @@ -1687,47 +1574,14 @@ static int rs_open(struct tty_struct *tty, struct file * filp) if (serial_paranoia_check(info, tty->name, "rs_open")) return -ENODEV; -#ifdef SERIAL_DEBUG_OPEN - printk("rs_open %s, count = %d\n", tty->name, info->count); -#endif tty->low_latency = (port->flags & ASYNC_LOW_LATENCY) ? 1 : 0; - /* - * If the port is the middle of closing, bail out now - */ - if (tty_hung_up_p(filp) || - (port->flags & ASYNC_CLOSING)) { - if (port->flags & ASYNC_CLOSING) - interruptible_sleep_on(&port->close_wait); -#ifdef SERIAL_DO_RESTART - return ((port->flags & ASYNC_HUP_NOTIFY) ? - -EAGAIN : -ERESTARTSYS); -#else - return -EAGAIN; -#endif - } - - /* - * Start up serial port - */ retval = startup(tty, info); if (retval) { return retval; } - retval = block_til_ready(tty, filp, info); - if (retval) { -#ifdef SERIAL_DEBUG_OPEN - printk("rs_open returning after block_til_ready with %d\n", - retval); -#endif - return retval; - } - -#ifdef SERIAL_DEBUG_OPEN - printk("rs_open %s successful...", tty->name); -#endif - return 0; + return tty_port_block_til_ready(port, tty, filp); } /* -- cgit v0.10.2 From b8edebe4b8b4ad5bd436cf9080b77b29e219029a Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 5 Mar 2012 14:52:48 +0100 Subject: TTY: amiserial, use tty_port_close_end Hmm, the code was sleeping with interrupts disabled. This was not good. Fix this by turning interrupts at an appropriate place. (The race is protected by CLOSING flag.) After the move, the code is identical to tty_port_close_end, so use it! Signed-off-by: Jiri Slaby Cc: Geert Uytterhoeven Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/amiserial.c b/drivers/tty/amiserial.c index 8cc8e15..9c8b199 100644 --- a/drivers/tty/amiserial.c +++ b/drivers/tty/amiserial.c @@ -1433,6 +1433,7 @@ static void rs_close(struct tty_struct *tty, struct file * filp) * the line discipline to only process XON/XOFF characters. */ tty->closing = 1; + local_irq_restore(flags); if (port->closing_wait != ASYNC_CLOSING_WAIT_NONE) tty_wait_until_sent(tty, port->closing_wait); /* @@ -1461,17 +1462,9 @@ static void rs_close(struct tty_struct *tty, struct file * filp) rs_flush_buffer(tty); tty_ldisc_flush(tty); - tty->closing = 0; port->tty = NULL; - if (port->blocked_open) { - if (port->close_delay) { - msleep_interruptible(jiffies_to_msecs(port->close_delay)); - } - wake_up_interruptible(&port->open_wait); - } - port->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING); - wake_up_interruptible(&port->close_wait); - local_irq_restore(flags); + + tty_port_close_end(port, tty); } /* -- cgit v0.10.2 From 9b937421e852cfa9992d6e1a1d814dcec8eb1ce3 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 5 Mar 2012 14:52:49 +0100 Subject: TTY: amiserial, use tty_port_close_start Again, no need to duplicate the code. Let's use the helper. Amiserial changes are only free of compilation errors. I have no access to the hardware. Signed-off-by: Jiri Slaby Cc: Geert Uytterhoeven Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/amiserial.c b/drivers/tty/amiserial.c index 9c8b199..afadcd43 100644 --- a/drivers/tty/amiserial.c +++ b/drivers/tty/amiserial.c @@ -1389,53 +1389,13 @@ static void rs_close(struct tty_struct *tty, struct file * filp) { struct serial_state *state = tty->driver_data; struct tty_port *port = &state->tport; - unsigned long flags; - if (!state || serial_paranoia_check(state, tty->name, "rs_close")) + if (serial_paranoia_check(state, tty->name, "rs_close")) return; - local_irq_save(flags); - - if (tty_hung_up_p(filp)) { - DBG_CNT("before DEC-hung"); - local_irq_restore(flags); + if (tty_port_close_start(port, tty, filp) == 0) return; - } -#ifdef SERIAL_DEBUG_OPEN - printk("rs_close ttys%d, count = %d\n", state->line, port->count); -#endif - if ((tty->count == 1) && (port->count != 1)) { - /* - * Uh, oh. tty->count is 1, which means that the tty - * structure will be freed. port->count should always - * be one in these conditions. If it's greater than - * one, we've got real problems, since it means the - * serial port won't be shutdown. - */ - printk("rs_close: bad serial port count; tty->count is 1, " - "port->count is %d\n", state->tport.count); - port->count = 1; - } - if (--port->count < 0) { - printk("rs_close: bad serial port count for ttys%d: %d\n", - tty->index, port->count); - port->count = 0; - } - if (port->count) { - DBG_CNT("before DEC-2"); - local_irq_restore(flags); - return; - } - port->flags |= ASYNC_CLOSING; - /* - * Now we wait for the transmit buffer to clear; and we notify - * the line discipline to only process XON/XOFF characters. - */ - tty->closing = 1; - local_irq_restore(flags); - if (port->closing_wait != ASYNC_CLOSING_WAIT_NONE) - tty_wait_until_sent(tty, port->closing_wait); /* * At this point we stop accepting input. To do this, we * disable the receive line status interrupts, and tell the -- cgit v0.10.2 From e380a81e34375a38f253b42394ef06ca3127559f Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 5 Mar 2012 14:52:50 +0100 Subject: TTY: pdc_cons, fix racy tty test The tty->count test in the timer was racy. Let's remove the test and properly delete the timer and wait for the body to finish using _sync version of del_timer. Signed-off-by: Jiri Slaby Cc: Kyle McMartin Cc: Helge Deller Cc: "James E.J. Bottomley" Signed-off-by: Greg Kroah-Hartman diff --git a/arch/parisc/kernel/pdc_cons.c b/arch/parisc/kernel/pdc_cons.c index fc770be..c1db65f 100644 --- a/arch/parisc/kernel/pdc_cons.c +++ b/arch/parisc/kernel/pdc_cons.c @@ -103,7 +103,7 @@ static int pdc_console_tty_open(struct tty_struct *tty, struct file *filp) static void pdc_console_tty_close(struct tty_struct *tty, struct file *filp) { if (!tty->count) - del_timer(&pdc_console_timer); + del_timer_sync(&pdc_console_timer); } static int pdc_console_tty_write(struct tty_struct *tty, const unsigned char *buf, int count) @@ -153,7 +153,7 @@ static void pdc_console_poll(unsigned long unused) if (count) tty_flip_buffer_push(tty); - if (tty->count && (pdc_cons.flags & CON_ENABLED)) + if (pdc_cons.flags & CON_ENABLED) mod_timer(&pdc_console_timer, jiffies + PDC_CONS_POLL_DELAY); } -- cgit v0.10.2 From 52b762f7a94c88e5a8aa2be67a06a6f01020cc82 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 5 Mar 2012 14:52:51 +0100 Subject: TTY: pdc_cons, fix open vs timer race The timer is initialized too late. tty->open may fire an invalid timer. So initialize the timer earlier using DEFINE_TIMER. Signed-off-by: Jiri Slaby Cc: Kyle McMartin Cc: Helge Deller Cc: "James E.J. Bottomley" Signed-off-by: Greg Kroah-Hartman diff --git a/arch/parisc/kernel/pdc_cons.c b/arch/parisc/kernel/pdc_cons.c index c1db65f..8ad0521 100644 --- a/arch/parisc/kernel/pdc_cons.c +++ b/arch/parisc/kernel/pdc_cons.c @@ -90,7 +90,8 @@ static int pdc_console_setup(struct console *co, char *options) #define PDC_CONS_POLL_DELAY (30 * HZ / 1000) -static struct timer_list pdc_console_timer; +static void pdc_console_poll(unsigned long unused); +static DEFINE_TIMER(pdc_console_timer, pdc_console_poll, 0, 0); static int pdc_console_tty_open(struct tty_struct *tty, struct file *filp) { @@ -205,10 +206,6 @@ static int __init pdc_console_tty_driver_init(void) pdc_console_tty_driver = drv; - /* No need to initialize the pdc_console_timer if tty isn't allocated */ - init_timer(&pdc_console_timer); - pdc_console_timer.function = pdc_console_poll; - return 0; } -- cgit v0.10.2 From 0b479d54ae7b79f62f09ef977c2228e579924d38 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 5 Mar 2012 14:52:52 +0100 Subject: TTY: pdc_cons, fix open vs pdc_console_tty_driver race Assign the pointer to pdc_console_tty_driver (a tty_driver) earlier. Otherwise the timer may dereference NULL. Signed-off-by: Jiri Slaby Cc: Kyle McMartin Cc: Helge Deller Cc: "James E.J. Bottomley" Signed-off-by: Greg Kroah-Hartman diff --git a/arch/parisc/kernel/pdc_cons.c b/arch/parisc/kernel/pdc_cons.c index 8ad0521..d14e20f 100644 --- a/arch/parisc/kernel/pdc_cons.c +++ b/arch/parisc/kernel/pdc_cons.c @@ -160,9 +160,7 @@ static void pdc_console_poll(unsigned long unused) static int __init pdc_console_tty_driver_init(void) { - int err; - struct tty_driver *drv; /* Check if the console driver is still registered. * It is unregistered if the pdc console was not selected as the @@ -184,28 +182,27 @@ static int __init pdc_console_tty_driver_init(void) printk(KERN_INFO "The PDC console driver is still registered, removing CON_BOOT flag\n"); pdc_cons.flags &= ~CON_BOOT; - drv = alloc_tty_driver(1); + pdc_console_tty_driver = alloc_tty_driver(1); - if (!drv) + if (!pdc_console_tty_driver) return -ENOMEM; - drv->driver_name = "pdc_cons"; - drv->name = "ttyB"; - drv->major = MUX_MAJOR; - drv->minor_start = 0; - drv->type = TTY_DRIVER_TYPE_SYSTEM; - drv->init_termios = tty_std_termios; - drv->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_RESET_TERMIOS; - tty_set_operations(drv, &pdc_console_tty_ops); - - err = tty_register_driver(drv); + pdc_console_tty_driver->driver_name = "pdc_cons"; + pdc_console_tty_driver->name = "ttyB"; + pdc_console_tty_driver->major = MUX_MAJOR; + pdc_console_tty_driver->minor_start = 0; + pdc_console_tty_driver->type = TTY_DRIVER_TYPE_SYSTEM; + pdc_console_tty_driver->init_termios = tty_std_termios; + pdc_console_tty_driver->flags = TTY_DRIVER_REAL_RAW | + TTY_DRIVER_RESET_TERMIOS; + tty_set_operations(pdc_console_tty_driver, &pdc_console_tty_ops); + + err = tty_register_driver(pdc_console_tty_driver); if (err) { printk(KERN_ERR "Unable to register the PDC console TTY driver\n"); return err; } - pdc_console_tty_driver = drv; - return 0; } -- cgit v0.10.2 From 5dd5bc40f3b6e0ccdaad948dbadc94ad0906cb25 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 5 Mar 2012 14:52:53 +0100 Subject: TTY: pdc_cons, use tty_port Instead of digging a tty out of the tty_driver struct, which is not defined to work, use tty_port properly. This includes proper tty refcounting even though there is no possible race currently. But we will need tty_port for tty buffers in the future anyway. Signed-off-by: Jiri Slaby Cc: Kyle McMartin Cc: Helge Deller Cc: "James E.J. Bottomley" Signed-off-by: Greg Kroah-Hartman diff --git a/arch/parisc/kernel/pdc_cons.c b/arch/parisc/kernel/pdc_cons.c index d14e20f..4f00459 100644 --- a/arch/parisc/kernel/pdc_cons.c +++ b/arch/parisc/kernel/pdc_cons.c @@ -92,10 +92,11 @@ static int pdc_console_setup(struct console *co, char *options) static void pdc_console_poll(unsigned long unused); static DEFINE_TIMER(pdc_console_timer, pdc_console_poll, 0, 0); +static struct tty_port tty_port; static int pdc_console_tty_open(struct tty_struct *tty, struct file *filp) { - + tty_port_tty_set(&tty_port, tty); mod_timer(&pdc_console_timer, jiffies + PDC_CONS_POLL_DELAY); return 0; @@ -103,8 +104,10 @@ static int pdc_console_tty_open(struct tty_struct *tty, struct file *filp) static void pdc_console_tty_close(struct tty_struct *tty, struct file *filp) { - if (!tty->count) + if (!tty->count) { del_timer_sync(&pdc_console_timer); + tty_port_tty_set(&tty_port, NULL); + } } static int pdc_console_tty_write(struct tty_struct *tty, const unsigned char *buf, int count) @@ -123,8 +126,6 @@ static int pdc_console_tty_chars_in_buffer(struct tty_struct *tty) return 0; /* no buffer */ } -static struct tty_driver *pdc_console_tty_driver; - static const struct tty_operations pdc_console_tty_ops = { .open = pdc_console_tty_open, .close = pdc_console_tty_close, @@ -135,10 +136,8 @@ static const struct tty_operations pdc_console_tty_ops = { static void pdc_console_poll(unsigned long unused) { - int data, count = 0; - - struct tty_struct *tty = pdc_console_tty_driver->ttys[0]; + struct tty_struct *tty = tty_port_tty_get(&tty_port); if (!tty) return; @@ -154,10 +153,14 @@ static void pdc_console_poll(unsigned long unused) if (count) tty_flip_buffer_push(tty); + tty_kref_put(tty); + if (pdc_cons.flags & CON_ENABLED) mod_timer(&pdc_console_timer, jiffies + PDC_CONS_POLL_DELAY); } +static struct tty_driver *pdc_console_tty_driver; + static int __init pdc_console_tty_driver_init(void) { int err; @@ -182,6 +185,8 @@ static int __init pdc_console_tty_driver_init(void) printk(KERN_INFO "The PDC console driver is still registered, removing CON_BOOT flag\n"); pdc_cons.flags &= ~CON_BOOT; + tty_port_init(&tty_port); + pdc_console_tty_driver = alloc_tty_driver(1); if (!pdc_console_tty_driver) -- cgit v0.10.2 From fc258f89405f63b379324d1f8388ae4810297997 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 5 Mar 2012 14:52:54 +0100 Subject: TTY: isdn/gigaset, do not set tty->driver_data to NULL Close the window in open where driver_data is reset to NULL on each open. It could cause other processes to get invalid retval from the tty->ops operations because of the checks all over the code. With this change we may do other cleanups. Now, the only valid check for tty->driver_data != NULL is in close. This can happen only if open fails at gigaset_get_cs_by_tty or try_module_get. The rest of checks in various tty->ops->* are invalid as driver_data cannot be NULL there. The same holds for cs->open_count. So remove them. Signed-off-by: Jiri Slaby Cc: Hansjoerg Lipp Cc: Tilman Schmidt Cc: gigaset307x-common@lists.sourceforge.net Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/isdn/gigaset/interface.c b/drivers/isdn/gigaset/interface.c index 648260b..8ff50b0 100644 --- a/drivers/isdn/gigaset/interface.c +++ b/drivers/isdn/gigaset/interface.c @@ -151,8 +151,6 @@ static int if_open(struct tty_struct *tty, struct file *filp) gig_dbg(DEBUG_IF, "%d+%d: %s()", tty->driver->minor_start, tty->index, __func__); - tty->driver_data = NULL; - cs = gigaset_get_cs_by_tty(tty); if (!cs || !try_module_get(cs->driver->owner)) return -ENODEV; @@ -178,12 +176,11 @@ static int if_open(struct tty_struct *tty, struct file *filp) static void if_close(struct tty_struct *tty, struct file *filp) { - struct cardstate *cs; + struct cardstate *cs = tty->driver_data; unsigned long flags; - cs = (struct cardstate *) tty->driver_data; - if (!cs) { - pr_err("%s: no cardstate\n", __func__); + if (!cs) { /* happens if we didn't find cs in open */ + printk(KERN_DEBUG "%s: no cardstate\n", __func__); return; } @@ -211,18 +208,12 @@ static void if_close(struct tty_struct *tty, struct file *filp) static int if_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg) { - struct cardstate *cs; + struct cardstate *cs = tty->driver_data; int retval = -ENODEV; int int_arg; unsigned char buf[6]; unsigned version[4]; - cs = (struct cardstate *) tty->driver_data; - if (!cs) { - pr_err("%s: no cardstate\n", __func__); - return -ENODEV; - } - gig_dbg(DEBUG_IF, "%u: %s(0x%x)", cs->minor_index, __func__, cmd); if (mutex_lock_interruptible(&cs->mutex)) @@ -231,9 +222,7 @@ static int if_ioctl(struct tty_struct *tty, if (!cs->connected) { gig_dbg(DEBUG_IF, "not connected"); retval = -ENODEV; - } else if (!cs->open_count) - dev_warn(cs->dev, "%s: device not opened\n", __func__); - else { + } else { retval = 0; switch (cmd) { case GIGASET_REDIR: @@ -285,15 +274,9 @@ static int if_ioctl(struct tty_struct *tty, static int if_tiocmget(struct tty_struct *tty) { - struct cardstate *cs; + struct cardstate *cs = tty->driver_data; int retval; - cs = (struct cardstate *) tty->driver_data; - if (!cs) { - pr_err("%s: no cardstate\n", __func__); - return -ENODEV; - } - gig_dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __func__); if (mutex_lock_interruptible(&cs->mutex)) @@ -309,16 +292,10 @@ static int if_tiocmget(struct tty_struct *tty) static int if_tiocmset(struct tty_struct *tty, unsigned int set, unsigned int clear) { - struct cardstate *cs; + struct cardstate *cs = tty->driver_data; int retval; unsigned mc; - cs = (struct cardstate *) tty->driver_data; - if (!cs) { - pr_err("%s: no cardstate\n", __func__); - return -ENODEV; - } - gig_dbg(DEBUG_IF, "%u: %s(0x%x, 0x%x)", cs->minor_index, __func__, set, clear); @@ -341,16 +318,10 @@ static int if_tiocmset(struct tty_struct *tty, static int if_write(struct tty_struct *tty, const unsigned char *buf, int count) { - struct cardstate *cs; + struct cardstate *cs = tty->driver_data; struct cmdbuf_t *cb; int retval; - cs = (struct cardstate *) tty->driver_data; - if (!cs) { - pr_err("%s: no cardstate\n", __func__); - return -ENODEV; - } - gig_dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __func__); if (mutex_lock_interruptible(&cs->mutex)) @@ -361,11 +332,6 @@ static int if_write(struct tty_struct *tty, const unsigned char *buf, int count) retval = -ENODEV; goto done; } - if (!cs->open_count) { - dev_warn(cs->dev, "%s: device not opened\n", __func__); - retval = -ENODEV; - goto done; - } if (cs->mstate != MS_LOCKED) { dev_warn(cs->dev, "can't write to unlocked device\n"); retval = -EBUSY; @@ -397,15 +363,9 @@ done: static int if_write_room(struct tty_struct *tty) { - struct cardstate *cs; + struct cardstate *cs = tty->driver_data; int retval = -ENODEV; - cs = (struct cardstate *) tty->driver_data; - if (!cs) { - pr_err("%s: no cardstate\n", __func__); - return -ENODEV; - } - gig_dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __func__); if (mutex_lock_interruptible(&cs->mutex)) @@ -414,9 +374,7 @@ static int if_write_room(struct tty_struct *tty) if (!cs->connected) { gig_dbg(DEBUG_IF, "not connected"); retval = -ENODEV; - } else if (!cs->open_count) - dev_warn(cs->dev, "%s: device not opened\n", __func__); - else if (cs->mstate != MS_LOCKED) { + } else if (cs->mstate != MS_LOCKED) { dev_warn(cs->dev, "can't write to unlocked device\n"); retval = -EBUSY; } else @@ -429,23 +387,15 @@ static int if_write_room(struct tty_struct *tty) static int if_chars_in_buffer(struct tty_struct *tty) { - struct cardstate *cs; + struct cardstate *cs = tty->driver_data; int retval = 0; - cs = (struct cardstate *) tty->driver_data; - if (!cs) { - pr_err("%s: no cardstate\n", __func__); - return 0; - } - gig_dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __func__); mutex_lock(&cs->mutex); if (!cs->connected) gig_dbg(DEBUG_IF, "not connected"); - else if (!cs->open_count) - dev_warn(cs->dev, "%s: device not opened\n", __func__); else if (cs->mstate != MS_LOCKED) dev_warn(cs->dev, "can't write to unlocked device\n"); else @@ -458,13 +408,7 @@ static int if_chars_in_buffer(struct tty_struct *tty) static void if_throttle(struct tty_struct *tty) { - struct cardstate *cs; - - cs = (struct cardstate *) tty->driver_data; - if (!cs) { - pr_err("%s: no cardstate\n", __func__); - return; - } + struct cardstate *cs = tty->driver_data; gig_dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __func__); @@ -472,8 +416,6 @@ static void if_throttle(struct tty_struct *tty) if (!cs->connected) gig_dbg(DEBUG_IF, "not connected"); /* nothing to do */ - else if (!cs->open_count) - dev_warn(cs->dev, "%s: device not opened\n", __func__); else gig_dbg(DEBUG_IF, "%s: not implemented\n", __func__); @@ -482,13 +424,7 @@ static void if_throttle(struct tty_struct *tty) static void if_unthrottle(struct tty_struct *tty) { - struct cardstate *cs; - - cs = (struct cardstate *) tty->driver_data; - if (!cs) { - pr_err("%s: no cardstate\n", __func__); - return; - } + struct cardstate *cs = tty->driver_data; gig_dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __func__); @@ -496,8 +432,6 @@ static void if_unthrottle(struct tty_struct *tty) if (!cs->connected) gig_dbg(DEBUG_IF, "not connected"); /* nothing to do */ - else if (!cs->open_count) - dev_warn(cs->dev, "%s: device not opened\n", __func__); else gig_dbg(DEBUG_IF, "%s: not implemented\n", __func__); @@ -506,18 +440,12 @@ static void if_unthrottle(struct tty_struct *tty) static void if_set_termios(struct tty_struct *tty, struct ktermios *old) { - struct cardstate *cs; + struct cardstate *cs = tty->driver_data; unsigned int iflag; unsigned int cflag; unsigned int old_cflag; unsigned int control_state, new_state; - cs = (struct cardstate *) tty->driver_data; - if (!cs) { - pr_err("%s: no cardstate\n", __func__); - return; - } - gig_dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __func__); mutex_lock(&cs->mutex); @@ -527,11 +455,6 @@ static void if_set_termios(struct tty_struct *tty, struct ktermios *old) goto out; } - if (!cs->open_count) { - dev_warn(cs->dev, "%s: device not opened\n", __func__); - goto out; - } - iflag = tty->termios->c_iflag; cflag = tty->termios->c_cflag; old_cflag = old ? old->c_cflag : cflag; -- cgit v0.10.2 From 48a7466f4dd0104d87a6d8dd0f25027be89c8453 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 5 Mar 2012 14:52:55 +0100 Subject: TTY: isdn/gigaset, use tty_port Let us port the code to use tty_port. We now use open_count and tty from there. This allows us also to use tty_port_tty_set with tty refcounting instead of hand-written locking and logic. Note that tty and open_count are no longer protected by cs->lock. It is protected by tty_port->lock. But since all the places where they were used are now switched to the helpers, we are fine. Signed-off-by: Jiri Slaby Cc: Hansjoerg Lipp Acked-by: Tilman Schmidt Cc: Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/isdn/gigaset/common.c b/drivers/isdn/gigaset/common.c index ac0186e..880f6ef 100644 --- a/drivers/isdn/gigaset/common.c +++ b/drivers/isdn/gigaset/common.c @@ -720,12 +720,11 @@ struct cardstate *gigaset_initcs(struct gigaset_driver *drv, int channels, tasklet_init(&cs->event_tasklet, gigaset_handle_event, (unsigned long) cs); + tty_port_init(&cs->port); cs->commands_pending = 0; cs->cur_at_seq = 0; cs->gotfwver = -1; - cs->open_count = 0; cs->dev = NULL; - cs->tty = NULL; cs->tty_dev = NULL; cs->cidmode = cidmode != 0; cs->tabnocid = gigaset_tab_nocid; diff --git a/drivers/isdn/gigaset/gigaset.h b/drivers/isdn/gigaset/gigaset.h index 212efaf..f877726 100644 --- a/drivers/isdn/gigaset/gigaset.h +++ b/drivers/isdn/gigaset/gigaset.h @@ -433,8 +433,7 @@ struct cardstate { spinlock_t cmdlock; unsigned curlen, cmdbytes; - unsigned open_count; - struct tty_struct *tty; + struct tty_port port; struct tasklet_struct if_wake_tasklet; unsigned control_state; diff --git a/drivers/isdn/gigaset/interface.c b/drivers/isdn/gigaset/interface.c index 8ff50b0..8f8814a 100644 --- a/drivers/isdn/gigaset/interface.c +++ b/drivers/isdn/gigaset/interface.c @@ -146,7 +146,6 @@ static const struct tty_operations if_ops = { static int if_open(struct tty_struct *tty, struct file *filp) { struct cardstate *cs; - unsigned long flags; gig_dbg(DEBUG_IF, "%d+%d: %s()", tty->driver->minor_start, tty->index, __func__); @@ -161,12 +160,10 @@ static int if_open(struct tty_struct *tty, struct file *filp) } tty->driver_data = cs; - ++cs->open_count; + ++cs->port.count; - if (cs->open_count == 1) { - spin_lock_irqsave(&cs->lock, flags); - cs->tty = tty; - spin_unlock_irqrestore(&cs->lock, flags); + if (cs->port.count == 1) { + tty_port_tty_set(&cs->port, tty); tty->low_latency = 1; } @@ -177,7 +174,6 @@ static int if_open(struct tty_struct *tty, struct file *filp) static void if_close(struct tty_struct *tty, struct file *filp) { struct cardstate *cs = tty->driver_data; - unsigned long flags; if (!cs) { /* happens if we didn't find cs in open */ printk(KERN_DEBUG "%s: no cardstate\n", __func__); @@ -190,15 +186,10 @@ static void if_close(struct tty_struct *tty, struct file *filp) if (!cs->connected) gig_dbg(DEBUG_IF, "not connected"); /* nothing to do */ - else if (!cs->open_count) + else if (!cs->port.count) dev_warn(cs->dev, "%s: device not opened\n", __func__); - else { - if (!--cs->open_count) { - spin_lock_irqsave(&cs->lock, flags); - cs->tty = NULL; - spin_unlock_irqrestore(&cs->lock, flags); - } - } + else if (!--cs->port.count) + tty_port_tty_set(&cs->port, NULL); mutex_unlock(&cs->mutex); @@ -511,10 +502,13 @@ out: /* wakeup tasklet for the write operation */ static void if_wake(unsigned long data) { - struct cardstate *cs = (struct cardstate *) data; + struct cardstate *cs = (struct cardstate *)data; + struct tty_struct *tty = tty_port_tty_get(&cs->port); - if (cs->tty) - tty_wakeup(cs->tty); + if (tty) { + tty_wakeup(tty); + tty_kref_put(tty); + } } /*** interface to common ***/ @@ -567,18 +561,16 @@ void gigaset_if_free(struct cardstate *cs) void gigaset_if_receive(struct cardstate *cs, unsigned char *buffer, size_t len) { - unsigned long flags; - struct tty_struct *tty; + struct tty_struct *tty = tty_port_tty_get(&cs->port); - spin_lock_irqsave(&cs->lock, flags); - tty = cs->tty; - if (tty == NULL) + if (tty == NULL) { gig_dbg(DEBUG_IF, "receive on closed device"); - else { - tty_insert_flip_string(tty, buffer, len); - tty_flip_buffer_push(tty); + return; } - spin_unlock_irqrestore(&cs->lock, flags); + + tty_insert_flip_string(tty, buffer, len); + tty_flip_buffer_push(tty); + tty_kref_put(tty); } EXPORT_SYMBOL_GPL(gigaset_if_receive); -- cgit v0.10.2 From 58112dfbfe02d803566a2c6c8bd97b5fa3c62cdc Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 7 Mar 2012 13:05:00 +0300 Subject: tty: moxa: fix bit test in moxa_start() This is supposed to be doing a shift before the comparison instead of just doing a bitwise AND directly. The current code means the start() just returns without doing anything. Signed-off-by: Dan Carpenter Acked-by: Jiri Slaby Cc: stable Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/moxa.c b/drivers/tty/moxa.c index 4a26323..8a8d044 100644 --- a/drivers/tty/moxa.c +++ b/drivers/tty/moxa.c @@ -1330,7 +1330,7 @@ static void moxa_start(struct tty_struct *tty) if (ch == NULL) return; - if (!(ch->statusflags & TXSTOPPED)) + if (!test_bit(TXSTOPPED, &ch->statusflags)) return; MoxaPortTxEnable(ch); -- cgit v0.10.2 From e0955acecf311f1079d2cc0d8c36b843b5db4ff6 Mon Sep 17 00:00:00 2001 From: Frank Benkert Date: Mon, 5 Mar 2012 16:14:29 +0100 Subject: mpc5200b/uart: select more tolerant uart prescaler on low baudrates In addition to the /32 prescaler, the MPC5200B supports a second baudrate prescaler /4 to reach higher baudrates. The current calculation (introduced with commit 0d1f22e4) in the kernel preferes this low prescaler as often as possible, but with some imprecise counterparts the communication on low baudrates fails. According a support-mail from freescale the low prescaler (/4) allows just 1% tolerance in bittiming in contrast to 4% of the high prescaler (/32). The prescaler not only affects the baudrate-calculation, but also the sampling of the bits on the wire. With this patch, we use the slightly less precise, but higher tolerant prescaler calculation on low baudrates up to (and including) 115200 baud and the more precise calculation above. Tested on a custom MPC5200B board with "fsl,mpc5200b-psc-uart". Calculation Examples with prescaler (PS) 4 and 32 and divisor (DIV) on various baudrates. Real stands for the real baudrate generated and Diff for the differences between: 50 Baud PS 32 DIV 0xa122 Real 50 Diff 0.00% 75 Baud PS 32 DIV 0x6b6c Real 75 Diff 0.00% 110 Baud PS 32 DIV 0x493e Real 110 Diff 0.00% 134 Baud PS 32 DIV 0x3c20 Real 133 Diff 0.75% 150 Baud PS 32 DIV 0x35b6 Real 150 Diff 0.00% 200 Baud PS 32 DIV 0x2849 Real 199 Diff 0.50% 300 Baud PS 4 DIV 0xd6d8 Real 300 Diff 0.00% PS 32 DIV 0x1adb Real 300 Diff 0.00% 600 Baud PS 4 DIV 0x6b6c Real 600 Diff 0.00% PS 32 DIV 0x0d6e Real 599 Diff 0.17% 1200 Baud PS 4 DIV 0x35b6 Real 1200 Diff 0.00% PS 32 DIV 0x06b7 Real 1199 Diff 0.08% 1800 Baud PS 4 DIV 0x23cf Real 1799 Diff 0.06% PS 32 DIV 0x047a Real 1799 Diff 0.06% 2400 Baud PS 4 DIV 0x1adb Real 2400 Diff 0.00% PS 32 DIV 0x035b Real 2401 Diff - 0.04% 4800 Baud PS 4 DIV 0x0d6e Real 4799 Diff 0.02% PS 32 DIV 0x01ae Real 4796 Diff 0.08% 9600 Baud PS 4 DIV 0x06b7 Real 9598 Diff 0.02% PS 32 DIV 0x00d7 Real 9593 Diff 0.07% 19200 Baud PS 4 DIV 0x035b Real 19208 Diff - 0.04% PS 32 DIV 0x006b Real 19275 Diff - 0.39% 38400 Baud PS 4 DIV 0x01ae Real 38372 Diff 0.07% PS 32 DIV 0x0036 Real 38194 Diff 0.54% 57600 Baud PS 4 DIV 0x011e Real 57692 Diff - 0.16% PS 32 DIV 0x0024 Real 57291 Diff 0.54% 76800 Baud PS 4 DIV 0x00d7 Real 76744 Diff 0.07% PS 32 DIV 0x001b Real 76388 Diff 0.54% 115200 Baud PS 4 DIV 0x008f Real 115384 Diff - 0.16% PS 32 DIV 0x0012 Real 114583 Diff 0.54% 153600 Baud PS 4 DIV 0x006b Real 154205 Diff - 0.39% PS 32 DIV 0x000d Real 158653 Diff - 3.29% 230400 Baud PS 4 DIV 0x0048 Real 229166 Diff 0.54% PS 32 DIV 0x0009 Real 229166 Diff 0.54% 307200 Baud PS 4 DIV 0x0036 Real 305555 Diff 0.54% PS 32 DIV 0x0007 Real 294642 Diff 4.09% 460800 Baud PS 4 DIV 0x0024 Real 458333 Diff 0.54% PS 32 DIV 0x0005 Real 412500 Diff 10.48% 500000 Baud PS 4 DIV 0x0021 Real 500000 Diff 0.00% PS 32 DIV 0x0004 Real 515625 Diff - 3.13% 576000 Baud PS 4 DIV 0x001d Real 568965 Diff 1.22% PS 32 DIV 0x0004 Real 515625 Diff 10.48% 614400 Baud PS 4 DIV 0x001b Real 611111 Diff 0.54% PS 32 DIV 0x0003 Real 687500 Diff -11.90% 921600 Baud PS 4 DIV 0x0012 Real 916666 Diff 0.54% PS 32 DIV 0x0002 Real 1031250 Diff -11.90% 1000000 Baud PS 4 DIV 0x0011 Real 970588 Diff 2.94% PS 32 DIV 0x0002 Real 1031250 Diff - 3.13% 1152000 Baud PS 4 DIV 0x000e Real 1178571 Diff - 2.31% PS 32 DIV 0x0002 Real 1031250 Diff 10.48% 1500000 Baud PS 4 DIV 0x000b Real 1500000 Diff 0.00% PS 32 DIV 0x0001 Real 2062500 Diff -37.50% 2000000 Baud PS 4 DIV 0x0008 Real 2062500 Diff - 3.13% PS 32 DIV 0x0001 Real 2062500 Diff - 3.13% 2500000 Baud PS 4 DIV 0x0007 Real 2357142 Diff 5.71% PS 32 DIV 0x0001 Real 2062500 Diff 17.50% 3000000 Baud PS 4 DIV 0x0006 Real 2750000 Diff 8.33% PS 32 DIV 0x0001 Real 2062500 Diff 31.25% 3500000 Baud PS 4 DIV 0x0005 Real 3300000 Diff 5.71% PS 32 DIV 0x0001 Real 2062500 Diff 41.07% 4000000 Baud PS 4 DIV 0x0004 Real 4125000 Diff - 3.13% PS 32 DIV 0x0001 Real 2062500 Diff 48.44% Signed-off-by: Frank Benkert Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/mpc52xx_uart.c b/drivers/tty/serial/mpc52xx_uart.c index e9a770d..bedac0d 100644 --- a/drivers/tty/serial/mpc52xx_uart.c +++ b/drivers/tty/serial/mpc52xx_uart.c @@ -262,8 +262,9 @@ static unsigned int mpc5200b_psc_set_baudrate(struct uart_port *port, port->uartclk / 4); divisor = (port->uartclk + 2 * baud) / (4 * baud); - /* select the proper prescaler and set the divisor */ - if (divisor > 0xffff) { + /* select the proper prescaler and set the divisor + * prefer high prescaler for more tolerance on low baudrates */ + if (divisor > 0xffff || baud <= 115200) { divisor = (divisor + 4) / 8; prescaler = 0xdd00; /* /32 */ } else -- cgit v0.10.2 From a8a3ec9df2158d217494c9dd8db8a099ef4fb921 Mon Sep 17 00:00:00 2001 From: Darren Hart Date: Fri, 9 Mar 2012 09:51:48 -0800 Subject: pch_uart: Use uartclk instead of base_baud The term "base baud" refers to the fastest baud rate the device can communicate at. This is clock/16. pch_uart is using base_baud as the clock itself. Rename the variables to be semantically correct. Signed-off-by: Darren Hart CC: Tomoya MORINAGA CC: Feng Tang CC: Alan Cox Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/pch_uart.c b/drivers/tty/serial/pch_uart.c index aa4d07b..5178213 100644 --- a/drivers/tty/serial/pch_uart.c +++ b/drivers/tty/serial/pch_uart.c @@ -206,7 +206,7 @@ enum { #define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE) -#define DEFAULT_BAUD_RATE 1843200 /* 1.8432MHz */ +#define DEFAULT_UARTCLK 1843200 /* 1.8432MHz */ struct pch_uart_buffer { unsigned char *buf; @@ -221,7 +221,7 @@ struct eg20t_port { unsigned int iobase; struct pci_dev *pdev; int fifo_size; - int base_baud; + int uartclk; int start_tx; int start_rx; int tx_empty; @@ -387,7 +387,7 @@ static int pch_uart_hal_set_line(struct eg20t_port *priv, int baud, unsigned int dll, dlm, lcr; int div; - div = DIV_ROUND_CLOSEST(priv->base_baud / 16, baud); + div = DIV_ROUND_CLOSEST(priv->uartclk / 16, baud); if (div < 0 || USHRT_MAX <= div) { dev_err(priv->port.dev, "Invalid Baud(div=0x%x)\n", div); return -EINVAL; @@ -1205,9 +1205,9 @@ static int pch_uart_startup(struct uart_port *port) priv->tx_empty = 1; if (port->uartclk) - priv->base_baud = port->uartclk; + priv->uartclk = port->uartclk; else - port->uartclk = priv->base_baud; + port->uartclk = priv->uartclk; pch_uart_hal_disable_interrupt(priv, PCH_UART_HAL_ALL_INT); ret = pch_uart_hal_set_line(priv, default_baud, @@ -1557,7 +1557,7 @@ static int __init pch_console_setup(struct console *co, char *options) return -ENODEV; /* setup uartclock */ - port->uartclk = DEFAULT_BAUD_RATE; + port->uartclk = DEFAULT_UARTCLK; if (options) uart_parse_options(options, &baud, &parity, &bits, &flow); @@ -1600,7 +1600,7 @@ static struct eg20t_port *pch_uart_init_port(struct pci_dev *pdev, unsigned int iobase; unsigned int mapbase; unsigned char *rxbuf; - int fifosize, base_baud; + int fifosize, uartclk; int port_type; struct pch_uart_driver_data *board; const char *board_name; @@ -1617,12 +1617,12 @@ static struct eg20t_port *pch_uart_init_port(struct pci_dev *pdev, if (!rxbuf) goto init_port_free_txbuf; - base_baud = DEFAULT_BAUD_RATE; + uartclk = DEFAULT_UARTCLK; /* quirk for CM-iTC board */ board_name = dmi_get_system_info(DMI_BOARD_NAME); if (board_name && strstr(board_name, "CM-iTC")) - base_baud = 192000000; /* 192.0MHz */ + uartclk = 192000000; /* 192.0MHz */ switch (port_type) { case PORT_UNKNOWN: @@ -1648,7 +1648,7 @@ static struct eg20t_port *pch_uart_init_port(struct pci_dev *pdev, priv->rxbuf.size = PAGE_SIZE; priv->fifo_size = fifosize; - priv->base_baud = base_baud; + priv->uartclk = uartclk; priv->port_type = PORT_MAX_8250 + port_type + 1; priv->port.dev = &pdev->dev; priv->port.iobase = iobase; -- cgit v0.10.2 From 077175f08e365629312ce32918e0c8047151763d Mon Sep 17 00:00:00 2001 From: Darren Hart Date: Fri, 9 Mar 2012 09:51:49 -0800 Subject: pch_uart: Add Fish River Island II uart clock quirks Add support for the Fish River Island II (FRI2) UART clock following the CM-iTC quirk handling mechanism. Depending on the firmware installed on the device, the FRI2 uses a 48MHz or a 64MHz UART clock. This is detected with DMI strings. Add similar UART clock quirk handling to the pch_console_setup() function to enable kernel messages on boards with non-standard UART clocks. Per Alan's suggestion, abstract out UART clock selection into pch_uart_get_uartclk() to avoid code duplication. Signed-off-by: Darren Hart CC: Tomoya MORINAGA CC: Feng Tang CC: Alan Cox Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/pch_uart.c b/drivers/tty/serial/pch_uart.c index 5178213..88a1be0 100644 --- a/drivers/tty/serial/pch_uart.c +++ b/drivers/tty/serial/pch_uart.c @@ -206,7 +206,10 @@ enum { #define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE) -#define DEFAULT_UARTCLK 1843200 /* 1.8432MHz */ +#define DEFAULT_UARTCLK 1843200 /* 1.8432 MHz */ +#define CMITC_UARTCLK 192000000 /* 192.0000 MHz */ +#define FRI2_64_UARTCLK 64000000 /* 64.0000 MHz */ +#define FRI2_48_UARTCLK 48000000 /* 48.0000 MHz */ struct pch_uart_buffer { unsigned char *buf; @@ -364,6 +367,26 @@ static const struct file_operations port_regs_ops = { }; #endif /* CONFIG_DEBUG_FS */ +/* Return UART clock, checking for board specific clocks. */ +static int pch_uart_get_uartclk(void) +{ + const char *cmp; + + cmp = dmi_get_system_info(DMI_BOARD_NAME); + if (cmp && strstr(cmp, "CM-iTC")) + return CMITC_UARTCLK; + + cmp = dmi_get_system_info(DMI_BIOS_VERSION); + if (cmp && strnstr(cmp, "FRI2", 4)) + return FRI2_64_UARTCLK; + + cmp = dmi_get_system_info(DMI_PRODUCT_NAME); + if (cmp && strstr(cmp, "Fish River Island II")) + return FRI2_48_UARTCLK; + + return DEFAULT_UARTCLK; +} + static void pch_uart_hal_enable_interrupt(struct eg20t_port *priv, unsigned int flag) { @@ -1556,8 +1579,7 @@ static int __init pch_console_setup(struct console *co, char *options) if (!port || (!port->iobase && !port->membase)) return -ENODEV; - /* setup uartclock */ - port->uartclk = DEFAULT_UARTCLK; + port->uartclk = pch_uart_get_uartclk(); if (options) uart_parse_options(options, &baud, &parity, &bits, &flow); @@ -1600,10 +1622,9 @@ static struct eg20t_port *pch_uart_init_port(struct pci_dev *pdev, unsigned int iobase; unsigned int mapbase; unsigned char *rxbuf; - int fifosize, uartclk; + int fifosize; int port_type; struct pch_uart_driver_data *board; - const char *board_name; char name[32]; /* for debugfs file name */ board = &drv_dat[id->driver_data]; @@ -1617,13 +1638,6 @@ static struct eg20t_port *pch_uart_init_port(struct pci_dev *pdev, if (!rxbuf) goto init_port_free_txbuf; - uartclk = DEFAULT_UARTCLK; - - /* quirk for CM-iTC board */ - board_name = dmi_get_system_info(DMI_BOARD_NAME); - if (board_name && strstr(board_name, "CM-iTC")) - uartclk = 192000000; /* 192.0MHz */ - switch (port_type) { case PORT_UNKNOWN: fifosize = 256; /* EG20T/ML7213: UART0 */ @@ -1648,7 +1662,7 @@ static struct eg20t_port *pch_uart_init_port(struct pci_dev *pdev, priv->rxbuf.size = PAGE_SIZE; priv->fifo_size = fifosize; - priv->uartclk = uartclk; + priv->uartclk = pch_uart_get_uartclk(); priv->port_type = PORT_MAX_8250 + port_type + 1; priv->port.dev = &pdev->dev; priv->port.iobase = iobase; -- cgit v0.10.2 From 2a44feb20bbe3db3b86bc5d976c8647cfda48588 Mon Sep 17 00:00:00 2001 From: Darren Hart Date: Fri, 9 Mar 2012 09:51:50 -0800 Subject: pch_uart: Add user_uartclk parameter For cases where boards with non-default clocks are not yet added to the kernel or when the clock varies across hardware revisions, it is useful to be able to specify the UART clock on the kernel command line. Add the user_uartclk parameter and prefer it, if set, to the default and board specific UART clock settings. Specify user_uartclock on the command-line with "pch_uart.user_uartclk=48000000". Signed-off-by: Darren Hart CC: Tomoya MORINAGA CC: Feng Tang CC: Alan Cox Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/pch_uart.c b/drivers/tty/serial/pch_uart.c index 88a1be0..46f6fbf 100644 --- a/drivers/tty/serial/pch_uart.c +++ b/drivers/tty/serial/pch_uart.c @@ -295,6 +295,7 @@ static struct pch_uart_driver_data drv_dat[] = { static struct eg20t_port *pch_uart_ports[PCH_UART_NR]; #endif static unsigned int default_baud = 9600; +static unsigned int user_uartclk = 0; static const int trigger_level_256[4] = { 1, 64, 128, 224 }; static const int trigger_level_64[4] = { 1, 16, 32, 56 }; static const int trigger_level_16[4] = { 1, 4, 8, 14 }; @@ -372,6 +373,9 @@ static int pch_uart_get_uartclk(void) { const char *cmp; + if (user_uartclk) + return user_uartclk; + cmp = dmi_get_system_info(DMI_BOARD_NAME); if (cmp && strstr(cmp, "CM-iTC")) return CMITC_UARTCLK; @@ -1860,3 +1864,4 @@ module_exit(pch_uart_module_exit); MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("Intel EG20T PCH UART PCI Driver"); module_param(default_baud, uint, S_IRUGO); +module_param(user_uartclk, uint, S_IRUGO); -- cgit v0.10.2 From 7ce9251d606780a53efc7dcdaa4518d93867c27f Mon Sep 17 00:00:00 2001 From: Darren Hart Date: Fri, 9 Mar 2012 09:51:51 -0800 Subject: pch_uart: Use existing default_baud in setup_console Rather than hardcode 9600, use the existing default_baud parameter (which also defaults to 9600). Signed-off-by: Darren Hart CC: Tomoya MORINAGA CC: Feng Tang CC: Alan Cox Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/pch_uart.c b/drivers/tty/serial/pch_uart.c index 46f6fbf..cca742b 100644 --- a/drivers/tty/serial/pch_uart.c +++ b/drivers/tty/serial/pch_uart.c @@ -1566,7 +1566,7 @@ pch_console_write(struct console *co, const char *s, unsigned int count) static int __init pch_console_setup(struct console *co, char *options) { struct uart_port *port; - int baud = 9600; + int baud = default_baud; int bits = 8; int parity = 'n'; int flow = 'n'; -- cgit v0.10.2 From a46f5533ecfc7bbdd646d84fdab8656031a715c6 Mon Sep 17 00:00:00 2001 From: Darren Hart Date: Fri, 9 Mar 2012 09:51:52 -0800 Subject: pch_uart: Add module parameter descriptions Document default_baud and user_uartclk module parameters. Signed-off-by: Darren Hart CC: Tomoya MORINAGA CC: Feng Tang CC: Alan Cox Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/pch_uart.c b/drivers/tty/serial/pch_uart.c index cca742b..332f2eb 100644 --- a/drivers/tty/serial/pch_uart.c +++ b/drivers/tty/serial/pch_uart.c @@ -1864,4 +1864,8 @@ module_exit(pch_uart_module_exit); MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("Intel EG20T PCH UART PCI Driver"); module_param(default_baud, uint, S_IRUGO); +MODULE_PARM_DESC(default_baud, + "Default BAUD for initial driver state and console (default 9600)"); module_param(user_uartclk, uint, S_IRUGO); +MODULE_PARM_DESC(user_uartclk, + "Override UART default or board specific UART clock"); -- cgit v0.10.2 From 0acf519f3f22450ae8f90cdb0f77b046fc731624 Mon Sep 17 00:00:00 2001 From: Paul Gortmaker Date: Thu, 8 Mar 2012 19:12:08 -0500 Subject: serial: delete last unused traces of pausing I/O in 8250 This is the last traces of pausing I/O that we had back some twenty years ago. Probably was only required for 8MHz ISA cards running "on the edge" at 12MHz. Anyway it hasn't been in use for years, so lets just bury it for good. Signed-off-by: Paul Gortmaker Acked-by: Alan Cox Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/8250/8250.c b/drivers/tty/serial/8250/8250.c index 917ab84..9674eac 100644 --- a/drivers/tty/serial/8250/8250.c +++ b/drivers/tty/serial/8250/8250.c @@ -486,26 +486,18 @@ serial_out_sync(struct uart_8250_port *up, int offset, int value) (up->port.serial_in(&(up)->port, (offset))) #define serial_out(up, offset, value) \ (up->port.serial_out(&(up)->port, (offset), (value))) -/* - * We used to support using pause I/O for certain machines. We - * haven't supported this for a while, but just in case it's badly - * needed for certain old 386 machines, I've left these #define's - * in.... - */ -#define serial_inp(up, offset) serial_in(up, offset) -#define serial_outp(up, offset, value) serial_out(up, offset, value) /* Uart divisor latch read */ static inline int _serial_dl_read(struct uart_8250_port *up) { - return serial_inp(up, UART_DLL) | serial_inp(up, UART_DLM) << 8; + return serial_in(up, UART_DLL) | serial_in(up, UART_DLM) << 8; } /* Uart divisor latch write */ static inline void _serial_dl_write(struct uart_8250_port *up, int value) { - serial_outp(up, UART_DLL, value & 0xff); - serial_outp(up, UART_DLM, value >> 8 & 0xff); + serial_out(up, UART_DLL, value & 0xff); + serial_out(up, UART_DLM, value >> 8 & 0xff); } #if defined(CONFIG_MIPS_ALCHEMY) @@ -575,10 +567,10 @@ static unsigned int serial_icr_read(struct uart_8250_port *up, int offset) static void serial8250_clear_fifos(struct uart_8250_port *p) { if (p->capabilities & UART_CAP_FIFO) { - serial_outp(p, UART_FCR, UART_FCR_ENABLE_FIFO); - serial_outp(p, UART_FCR, UART_FCR_ENABLE_FIFO | + serial_out(p, UART_FCR, UART_FCR_ENABLE_FIFO); + serial_out(p, UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT); - serial_outp(p, UART_FCR, 0); + serial_out(p, UART_FCR, 0); } } @@ -591,15 +583,15 @@ static void serial8250_set_sleep(struct uart_8250_port *p, int sleep) { if (p->capabilities & UART_CAP_SLEEP) { if (p->capabilities & UART_CAP_EFR) { - serial_outp(p, UART_LCR, UART_LCR_CONF_MODE_B); - serial_outp(p, UART_EFR, UART_EFR_ECB); - serial_outp(p, UART_LCR, 0); + serial_out(p, UART_LCR, UART_LCR_CONF_MODE_B); + serial_out(p, UART_EFR, UART_EFR_ECB); + serial_out(p, UART_LCR, 0); } - serial_outp(p, UART_IER, sleep ? UART_IERX_SLEEP : 0); + serial_out(p, UART_IER, sleep ? UART_IERX_SLEEP : 0); if (p->capabilities & UART_CAP_EFR) { - serial_outp(p, UART_LCR, UART_LCR_CONF_MODE_B); - serial_outp(p, UART_EFR, 0); - serial_outp(p, UART_LCR, 0); + serial_out(p, UART_LCR, UART_LCR_CONF_MODE_B); + serial_out(p, UART_EFR, 0); + serial_out(p, UART_LCR, 0); } } } @@ -614,12 +606,12 @@ static int __enable_rsa(struct uart_8250_port *up) unsigned char mode; int result; - mode = serial_inp(up, UART_RSA_MSR); + mode = serial_in(up, UART_RSA_MSR); result = mode & UART_RSA_MSR_FIFO; if (!result) { - serial_outp(up, UART_RSA_MSR, mode | UART_RSA_MSR_FIFO); - mode = serial_inp(up, UART_RSA_MSR); + serial_out(up, UART_RSA_MSR, mode | UART_RSA_MSR_FIFO); + mode = serial_in(up, UART_RSA_MSR); result = mode & UART_RSA_MSR_FIFO; } @@ -638,7 +630,7 @@ static void enable_rsa(struct uart_8250_port *up) spin_unlock_irq(&up->port.lock); } if (up->port.uartclk == SERIAL_RSA_BAUD_BASE * 16) - serial_outp(up, UART_RSA_FRR, 0); + serial_out(up, UART_RSA_FRR, 0); } } @@ -657,12 +649,12 @@ static void disable_rsa(struct uart_8250_port *up) up->port.uartclk == SERIAL_RSA_BAUD_BASE * 16) { spin_lock_irq(&up->port.lock); - mode = serial_inp(up, UART_RSA_MSR); + mode = serial_in(up, UART_RSA_MSR); result = !(mode & UART_RSA_MSR_FIFO); if (!result) { - serial_outp(up, UART_RSA_MSR, mode & ~UART_RSA_MSR_FIFO); - mode = serial_inp(up, UART_RSA_MSR); + serial_out(up, UART_RSA_MSR, mode & ~UART_RSA_MSR_FIFO); + mode = serial_in(up, UART_RSA_MSR); result = !(mode & UART_RSA_MSR_FIFO); } @@ -683,28 +675,28 @@ static int size_fifo(struct uart_8250_port *up) unsigned short old_dl; int count; - old_lcr = serial_inp(up, UART_LCR); - serial_outp(up, UART_LCR, 0); - old_fcr = serial_inp(up, UART_FCR); - old_mcr = serial_inp(up, UART_MCR); - serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO | + old_lcr = serial_in(up, UART_LCR); + serial_out(up, UART_LCR, 0); + old_fcr = serial_in(up, UART_FCR); + old_mcr = serial_in(up, UART_MCR); + serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT); - serial_outp(up, UART_MCR, UART_MCR_LOOP); - serial_outp(up, UART_LCR, UART_LCR_CONF_MODE_A); + serial_out(up, UART_MCR, UART_MCR_LOOP); + serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A); old_dl = serial_dl_read(up); serial_dl_write(up, 0x0001); - serial_outp(up, UART_LCR, 0x03); + serial_out(up, UART_LCR, 0x03); for (count = 0; count < 256; count++) - serial_outp(up, UART_TX, count); + serial_out(up, UART_TX, count); mdelay(20);/* FIXME - schedule_timeout */ - for (count = 0; (serial_inp(up, UART_LSR) & UART_LSR_DR) && + for (count = 0; (serial_in(up, UART_LSR) & UART_LSR_DR) && (count < 256); count++) - serial_inp(up, UART_RX); - serial_outp(up, UART_FCR, old_fcr); - serial_outp(up, UART_MCR, old_mcr); - serial_outp(up, UART_LCR, UART_LCR_CONF_MODE_A); + serial_in(up, UART_RX); + serial_out(up, UART_FCR, old_fcr); + serial_out(up, UART_MCR, old_mcr); + serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A); serial_dl_write(up, old_dl); - serial_outp(up, UART_LCR, old_lcr); + serial_out(up, UART_LCR, old_lcr); return count; } @@ -719,20 +711,20 @@ static unsigned int autoconfig_read_divisor_id(struct uart_8250_port *p) unsigned char old_dll, old_dlm, old_lcr; unsigned int id; - old_lcr = serial_inp(p, UART_LCR); - serial_outp(p, UART_LCR, UART_LCR_CONF_MODE_A); + old_lcr = serial_in(p, UART_LCR); + serial_out(p, UART_LCR, UART_LCR_CONF_MODE_A); - old_dll = serial_inp(p, UART_DLL); - old_dlm = serial_inp(p, UART_DLM); + old_dll = serial_in(p, UART_DLL); + old_dlm = serial_in(p, UART_DLM); - serial_outp(p, UART_DLL, 0); - serial_outp(p, UART_DLM, 0); + serial_out(p, UART_DLL, 0); + serial_out(p, UART_DLM, 0); - id = serial_inp(p, UART_DLL) | serial_inp(p, UART_DLM) << 8; + id = serial_in(p, UART_DLL) | serial_in(p, UART_DLM) << 8; - serial_outp(p, UART_DLL, old_dll); - serial_outp(p, UART_DLM, old_dlm); - serial_outp(p, UART_LCR, old_lcr); + serial_out(p, UART_DLL, old_dll); + serial_out(p, UART_DLM, old_dlm); + serial_out(p, UART_LCR, old_lcr); return id; } @@ -842,11 +834,11 @@ static void autoconfig_8250(struct uart_8250_port *up) up->port.type = PORT_8250; scratch = serial_in(up, UART_SCR); - serial_outp(up, UART_SCR, 0xa5); + serial_out(up, UART_SCR, 0xa5); status1 = serial_in(up, UART_SCR); - serial_outp(up, UART_SCR, 0x5a); + serial_out(up, UART_SCR, 0x5a); status2 = serial_in(up, UART_SCR); - serial_outp(up, UART_SCR, scratch); + serial_out(up, UART_SCR, scratch); if (status1 == 0xa5 && status2 == 0x5a) up->port.type = PORT_16450; @@ -877,7 +869,7 @@ static inline int ns16550a_goto_highspeed(struct uart_8250_port *up) } else { status &= ~0xB0; /* Disable LOCK, mask out PRESL[01] */ status |= 0x10; /* 1.625 divisor for baud_base --> 921600 */ - serial_outp(up, 0x04, status); + serial_out(up, 0x04, status); } return 1; } @@ -900,9 +892,9 @@ static void autoconfig_16550a(struct uart_8250_port *up) * Check for presence of the EFR when DLAB is set. * Only ST16C650V1 UARTs pass this test. */ - serial_outp(up, UART_LCR, UART_LCR_CONF_MODE_A); + serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A); if (serial_in(up, UART_EFR) == 0) { - serial_outp(up, UART_EFR, 0xA8); + serial_out(up, UART_EFR, 0xA8); if (serial_in(up, UART_EFR) != 0) { DEBUG_AUTOCONF("EFRv1 "); up->port.type = PORT_16650; @@ -910,7 +902,7 @@ static void autoconfig_16550a(struct uart_8250_port *up) } else { DEBUG_AUTOCONF("Motorola 8xxx DUART "); } - serial_outp(up, UART_EFR, 0); + serial_out(up, UART_EFR, 0); return; } @@ -918,7 +910,7 @@ static void autoconfig_16550a(struct uart_8250_port *up) * Maybe it requires 0xbf to be written to the LCR. * (other ST16C650V2 UARTs, TI16C752A, etc) */ - serial_outp(up, UART_LCR, UART_LCR_CONF_MODE_B); + serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); if (serial_in(up, UART_EFR) == 0 && !broken_efr(up)) { DEBUG_AUTOCONF("EFRv2 "); autoconfig_has_efr(up); @@ -932,23 +924,23 @@ static void autoconfig_16550a(struct uart_8250_port *up) * switch back to bank 2, read it from EXCR1 again and check * it's changed. If so, set baud_base in EXCR2 to 921600. -- dwmw2 */ - serial_outp(up, UART_LCR, 0); + serial_out(up, UART_LCR, 0); status1 = serial_in(up, UART_MCR); - serial_outp(up, UART_LCR, 0xE0); + serial_out(up, UART_LCR, 0xE0); status2 = serial_in(up, 0x02); /* EXCR1 */ if (!((status2 ^ status1) & UART_MCR_LOOP)) { - serial_outp(up, UART_LCR, 0); - serial_outp(up, UART_MCR, status1 ^ UART_MCR_LOOP); - serial_outp(up, UART_LCR, 0xE0); + serial_out(up, UART_LCR, 0); + serial_out(up, UART_MCR, status1 ^ UART_MCR_LOOP); + serial_out(up, UART_LCR, 0xE0); status2 = serial_in(up, 0x02); /* EXCR1 */ - serial_outp(up, UART_LCR, 0); - serial_outp(up, UART_MCR, status1); + serial_out(up, UART_LCR, 0); + serial_out(up, UART_MCR, status1); if ((status2 ^ status1) & UART_MCR_LOOP) { unsigned short quot; - serial_outp(up, UART_LCR, 0xE0); + serial_out(up, UART_LCR, 0xE0); quot = serial_dl_read(up); quot <<= 3; @@ -956,7 +948,7 @@ static void autoconfig_16550a(struct uart_8250_port *up) if (ns16550a_goto_highspeed(up)) serial_dl_write(up, quot); - serial_outp(up, UART_LCR, 0); + serial_out(up, UART_LCR, 0); up->port.uartclk = 921600*16; up->port.type = PORT_NS16550A; @@ -971,15 +963,15 @@ static void autoconfig_16550a(struct uart_8250_port *up) * Try setting it with and without DLAB set. Cheap clones * set bit 5 without DLAB set. */ - serial_outp(up, UART_LCR, 0); - serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR7_64BYTE); + serial_out(up, UART_LCR, 0); + serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR7_64BYTE); status1 = serial_in(up, UART_IIR) >> 5; - serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO); - serial_outp(up, UART_LCR, UART_LCR_CONF_MODE_A); - serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR7_64BYTE); + serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO); + serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A); + serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR7_64BYTE); status2 = serial_in(up, UART_IIR) >> 5; - serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO); - serial_outp(up, UART_LCR, 0); + serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO); + serial_out(up, UART_LCR, 0); DEBUG_AUTOCONF("iir1=%d iir2=%d ", status1, status2); @@ -998,13 +990,13 @@ static void autoconfig_16550a(struct uart_8250_port *up) * already a 1 and maybe locked there before we even start start. */ iersave = serial_in(up, UART_IER); - serial_outp(up, UART_IER, iersave & ~UART_IER_UUE); + serial_out(up, UART_IER, iersave & ~UART_IER_UUE); if (!(serial_in(up, UART_IER) & UART_IER_UUE)) { /* * OK it's in a known zero state, try writing and reading * without disturbing the current state of the other bits. */ - serial_outp(up, UART_IER, iersave | UART_IER_UUE); + serial_out(up, UART_IER, iersave | UART_IER_UUE); if (serial_in(up, UART_IER) & UART_IER_UUE) { /* * It's an Xscale. @@ -1022,7 +1014,7 @@ static void autoconfig_16550a(struct uart_8250_port *up) */ DEBUG_AUTOCONF("Couldn't force IER_UUE to 0 "); } - serial_outp(up, UART_IER, iersave); + serial_out(up, UART_IER, iersave); /* * Exar uarts have EFR in a weird location @@ -1084,8 +1076,8 @@ static void autoconfig(struct uart_8250_port *up, unsigned int probeflags) * Note: this is safe as long as MCR bit 4 is clear * and the device is in "PC" mode. */ - scratch = serial_inp(up, UART_IER); - serial_outp(up, UART_IER, 0); + scratch = serial_in(up, UART_IER); + serial_out(up, UART_IER, 0); #ifdef __i386__ outb(0xff, 0x080); #endif @@ -1093,13 +1085,13 @@ static void autoconfig(struct uart_8250_port *up, unsigned int probeflags) * Mask out IER[7:4] bits for test as some UARTs (e.g. TL * 16C754B) allow only to modify them if an EFR bit is set. */ - scratch2 = serial_inp(up, UART_IER) & 0x0f; - serial_outp(up, UART_IER, 0x0F); + scratch2 = serial_in(up, UART_IER) & 0x0f; + serial_out(up, UART_IER, 0x0F); #ifdef __i386__ outb(0, 0x080); #endif - scratch3 = serial_inp(up, UART_IER) & 0x0f; - serial_outp(up, UART_IER, scratch); + scratch3 = serial_in(up, UART_IER) & 0x0f; + serial_out(up, UART_IER, scratch); if (scratch2 != 0 || scratch3 != 0x0F) { /* * We failed; there's nothing here @@ -1123,9 +1115,9 @@ static void autoconfig(struct uart_8250_port *up, unsigned int probeflags) * that conflicts with COM 1-4 --- we hope! */ if (!(up->port.flags & UPF_SKIP_TEST)) { - serial_outp(up, UART_MCR, UART_MCR_LOOP | 0x0A); - status1 = serial_inp(up, UART_MSR) & 0xF0; - serial_outp(up, UART_MCR, save_mcr); + serial_out(up, UART_MCR, UART_MCR_LOOP | 0x0A); + status1 = serial_in(up, UART_MSR) & 0xF0; + serial_out(up, UART_MCR, save_mcr); if (status1 != 0x90) { DEBUG_AUTOCONF("LOOP test failed (%02x) ", status1); @@ -1142,11 +1134,11 @@ static void autoconfig(struct uart_8250_port *up, unsigned int probeflags) * We also initialise the EFR (if any) to zero for later. The * EFR occupies the same register location as the FCR and IIR. */ - serial_outp(up, UART_LCR, UART_LCR_CONF_MODE_B); - serial_outp(up, UART_EFR, 0); - serial_outp(up, UART_LCR, 0); + serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); + serial_out(up, UART_EFR, 0); + serial_out(up, UART_LCR, 0); - serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO); + serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO); scratch = serial_in(up, UART_IIR) >> 6; DEBUG_AUTOCONF("iir=%d ", scratch); @@ -1183,7 +1175,7 @@ static void autoconfig(struct uart_8250_port *up, unsigned int probeflags) } #endif - serial_outp(up, UART_LCR, save_lcr); + serial_out(up, UART_LCR, save_lcr); if (up->capabilities != uart_config[up->port.type].flags) { printk(KERN_WARNING @@ -1204,15 +1196,15 @@ static void autoconfig(struct uart_8250_port *up, unsigned int probeflags) */ #ifdef CONFIG_SERIAL_8250_RSA if (up->port.type == PORT_RSA) - serial_outp(up, UART_RSA_FRR, 0); + serial_out(up, UART_RSA_FRR, 0); #endif - serial_outp(up, UART_MCR, save_mcr); + serial_out(up, UART_MCR, save_mcr); serial8250_clear_fifos(up); serial_in(up, UART_RX); if (up->capabilities & UART_CAP_UUE) - serial_outp(up, UART_IER, UART_IER_UUE); + serial_out(up, UART_IER, UART_IER_UUE); else - serial_outp(up, UART_IER, 0); + serial_out(up, UART_IER, 0); out: spin_unlock_irqrestore(&up->port.lock, flags); @@ -1236,31 +1228,31 @@ static void autoconfig_irq(struct uart_8250_port *up) /* forget possible initially masked and pending IRQ */ probe_irq_off(probe_irq_on()); - save_mcr = serial_inp(up, UART_MCR); - save_ier = serial_inp(up, UART_IER); - serial_outp(up, UART_MCR, UART_MCR_OUT1 | UART_MCR_OUT2); + save_mcr = serial_in(up, UART_MCR); + save_ier = serial_in(up, UART_IER); + serial_out(up, UART_MCR, UART_MCR_OUT1 | UART_MCR_OUT2); irqs = probe_irq_on(); - serial_outp(up, UART_MCR, 0); + serial_out(up, UART_MCR, 0); udelay(10); if (up->port.flags & UPF_FOURPORT) { - serial_outp(up, UART_MCR, + serial_out(up, UART_MCR, UART_MCR_DTR | UART_MCR_RTS); } else { - serial_outp(up, UART_MCR, + serial_out(up, UART_MCR, UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2); } - serial_outp(up, UART_IER, 0x0f); /* enable all intrs */ - (void)serial_inp(up, UART_LSR); - (void)serial_inp(up, UART_RX); - (void)serial_inp(up, UART_IIR); - (void)serial_inp(up, UART_MSR); - serial_outp(up, UART_TX, 0xFF); + serial_out(up, UART_IER, 0x0f); /* enable all intrs */ + (void)serial_in(up, UART_LSR); + (void)serial_in(up, UART_RX); + (void)serial_in(up, UART_IIR); + (void)serial_in(up, UART_MSR); + serial_out(up, UART_TX, 0xFF); udelay(20); irq = probe_irq_off(irqs); - serial_outp(up, UART_MCR, save_mcr); - serial_outp(up, UART_IER, save_ier); + serial_out(up, UART_MCR, save_mcr); + serial_out(up, UART_IER, save_ier); if (up->port.flags & UPF_FOURPORT) outb_p(save_ICP, ICP); @@ -1380,7 +1372,7 @@ serial8250_rx_chars(struct uart_8250_port *up, unsigned char lsr) do { if (likely(lsr & UART_LSR_DR)) - ch = serial_inp(up, UART_RX); + ch = serial_in(up, UART_RX); else /* * Intel 82571 has a Serial Over Lan device that will @@ -1445,7 +1437,7 @@ serial8250_rx_chars(struct uart_8250_port *up, unsigned char lsr) uart_insert_char(&up->port, lsr, UART_LSR_OE, ch, flag); ignore_char: - lsr = serial_inp(up, UART_LSR); + lsr = serial_in(up, UART_LSR); } while ((lsr & (UART_LSR_DR | UART_LSR_BI)) && (max_count-- > 0)); spin_unlock(&up->port.lock); tty_flip_buffer_push(tty); @@ -1460,7 +1452,7 @@ void serial8250_tx_chars(struct uart_8250_port *up) int count; if (up->port.x_char) { - serial_outp(up, UART_TX, up->port.x_char); + serial_out(up, UART_TX, up->port.x_char); up->port.icount.tx++; up->port.x_char = 0; return; @@ -1532,7 +1524,7 @@ int serial8250_handle_irq(struct uart_port *port, unsigned int iir) spin_lock_irqsave(&up->port.lock, flags); - status = serial_inp(up, UART_LSR); + status = serial_in(up, UART_LSR); DEBUG_INTR("status = %x...", status); @@ -1894,12 +1886,12 @@ static int serial8250_get_poll_char(struct uart_port *port) { struct uart_8250_port *up = container_of(port, struct uart_8250_port, port); - unsigned char lsr = serial_inp(up, UART_LSR); + unsigned char lsr = serial_in(up, UART_LSR); if (!(lsr & UART_LSR_DR)) return NO_POLL_CHAR; - return serial_inp(up, UART_RX); + return serial_in(up, UART_RX); } @@ -1959,14 +1951,14 @@ static int serial8250_startup(struct uart_port *port) if (up->port.type == PORT_16C950) { /* Wake up and initialize UART */ up->acr = 0; - serial_outp(up, UART_LCR, UART_LCR_CONF_MODE_B); - serial_outp(up, UART_EFR, UART_EFR_ECB); - serial_outp(up, UART_IER, 0); - serial_outp(up, UART_LCR, 0); + serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); + serial_out(up, UART_EFR, UART_EFR_ECB); + serial_out(up, UART_IER, 0); + serial_out(up, UART_LCR, 0); serial_icr_write(up, UART_CSR, 0); /* Reset the UART */ - serial_outp(up, UART_LCR, UART_LCR_CONF_MODE_B); - serial_outp(up, UART_EFR, UART_EFR_ECB); - serial_outp(up, UART_LCR, 0); + serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); + serial_out(up, UART_EFR, UART_EFR_ECB); + serial_out(up, UART_LCR, 0); } #ifdef CONFIG_SERIAL_8250_RSA @@ -1986,10 +1978,10 @@ static int serial8250_startup(struct uart_port *port) /* * Clear the interrupt registers. */ - (void) serial_inp(up, UART_LSR); - (void) serial_inp(up, UART_RX); - (void) serial_inp(up, UART_IIR); - (void) serial_inp(up, UART_MSR); + (void) serial_in(up, UART_LSR); + (void) serial_in(up, UART_RX); + (void) serial_in(up, UART_IIR); + (void) serial_in(up, UART_MSR); /* * At this point, there's no way the LSR could still be 0xff; @@ -1997,7 +1989,7 @@ static int serial8250_startup(struct uart_port *port) * here. */ if (!(up->port.flags & UPF_BUGGY_UART) && - (serial_inp(up, UART_LSR) == 0xff)) { + (serial_in(up, UART_LSR) == 0xff)) { printk_ratelimited(KERN_INFO "ttyS%d: LSR safety check engaged!\n", serial_index(&up->port)); return -ENODEV; @@ -2009,15 +2001,15 @@ static int serial8250_startup(struct uart_port *port) if (up->port.type == PORT_16850) { unsigned char fctr; - serial_outp(up, UART_LCR, UART_LCR_CONF_MODE_B); + serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); - fctr = serial_inp(up, UART_FCTR) & ~(UART_FCTR_RX|UART_FCTR_TX); - serial_outp(up, UART_FCTR, fctr | UART_FCTR_TRGD | UART_FCTR_RX); - serial_outp(up, UART_TRG, UART_TRG_96); - serial_outp(up, UART_FCTR, fctr | UART_FCTR_TRGD | UART_FCTR_TX); - serial_outp(up, UART_TRG, UART_TRG_96); + fctr = serial_in(up, UART_FCTR) & ~(UART_FCTR_RX|UART_FCTR_TX); + serial_out(up, UART_FCTR, fctr | UART_FCTR_TRGD | UART_FCTR_RX); + serial_out(up, UART_TRG, UART_TRG_96); + serial_out(up, UART_FCTR, fctr | UART_FCTR_TRGD | UART_FCTR_TX); + serial_out(up, UART_TRG, UART_TRG_96); - serial_outp(up, UART_LCR, 0); + serial_out(up, UART_LCR, 0); } if (up->port.irq) { @@ -2087,7 +2079,7 @@ static int serial8250_startup(struct uart_port *port) /* * Now, initialize the UART */ - serial_outp(up, UART_LCR, UART_LCR_WLEN8); + serial_out(up, UART_LCR, UART_LCR_WLEN8); spin_lock_irqsave(&up->port.lock, flags); if (up->port.flags & UPF_FOURPORT) { @@ -2120,10 +2112,10 @@ static int serial8250_startup(struct uart_port *port) * Do a quick test to see if we receive an * interrupt when we enable the TX irq. */ - serial_outp(up, UART_IER, UART_IER_THRI); + serial_out(up, UART_IER, UART_IER_THRI); lsr = serial_in(up, UART_LSR); iir = serial_in(up, UART_IIR); - serial_outp(up, UART_IER, 0); + serial_out(up, UART_IER, 0); if (lsr & UART_LSR_TEMT && iir & UART_IIR_NO_INT) { if (!(up->bugs & UART_BUG_TXEN)) { @@ -2143,10 +2135,10 @@ dont_test_tx_en: * saved flags to avoid getting false values from polling * routines or the previous session. */ - serial_inp(up, UART_LSR); - serial_inp(up, UART_RX); - serial_inp(up, UART_IIR); - serial_inp(up, UART_MSR); + serial_in(up, UART_LSR); + serial_in(up, UART_RX); + serial_in(up, UART_IIR); + serial_in(up, UART_MSR); up->lsr_saved_flags = 0; up->msr_saved_flags = 0; @@ -2156,7 +2148,7 @@ dont_test_tx_en: * anyway, so we don't enable them here. */ up->ier = UART_IER_RLSI | UART_IER_RDI; - serial_outp(up, UART_IER, up->ier); + serial_out(up, UART_IER, up->ier); if (up->port.flags & UPF_FOURPORT) { unsigned int icp; @@ -2181,7 +2173,7 @@ static void serial8250_shutdown(struct uart_port *port) * Disable interrupts from this port */ up->ier = 0; - serial_outp(up, UART_IER, 0); + serial_out(up, UART_IER, 0); spin_lock_irqsave(&up->port.lock, flags); if (up->port.flags & UPF_FOURPORT) { @@ -2197,7 +2189,7 @@ static void serial8250_shutdown(struct uart_port *port) /* * Disable break condition and FIFOs */ - serial_out(up, UART_LCR, serial_inp(up, UART_LCR) & ~UART_LCR_SBC); + serial_out(up, UART_LCR, serial_in(up, UART_LCR) & ~UART_LCR_SBC); serial8250_clear_fifos(up); #ifdef CONFIG_SERIAL_8250_RSA @@ -2374,11 +2366,11 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios, if (termios->c_cflag & CRTSCTS) efr |= UART_EFR_CTS; - serial_outp(up, UART_LCR, UART_LCR_CONF_MODE_B); + serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); if (up->port.flags & UPF_EXAR_EFR) - serial_outp(up, UART_XR_EFR, efr); + serial_out(up, UART_XR_EFR, efr); else - serial_outp(up, UART_EFR, efr); + serial_out(up, UART_EFR, efr); } #ifdef CONFIG_ARCH_OMAP @@ -2394,9 +2386,9 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios, if (up->capabilities & UART_NATSEMI) { /* Switch to bank 2 not bank 1, to avoid resetting EXCR2 */ - serial_outp(up, UART_LCR, 0xe0); + serial_out(up, UART_LCR, 0xe0); } else { - serial_outp(up, UART_LCR, cval | UART_LCR_DLAB);/* set DLAB */ + serial_out(up, UART_LCR, cval | UART_LCR_DLAB);/* set DLAB */ } serial_dl_write(up, quot); @@ -2406,16 +2398,16 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios, * is written without DLAB set, this mode will be disabled. */ if (up->port.type == PORT_16750) - serial_outp(up, UART_FCR, fcr); + serial_out(up, UART_FCR, fcr); - serial_outp(up, UART_LCR, cval); /* reset DLAB */ + serial_out(up, UART_LCR, cval); /* reset DLAB */ up->lcr = cval; /* Save LCR */ if (up->port.type != PORT_16750) { if (fcr & UART_FCR_ENABLE_FIFO) { /* emulated UARTs (Lucent Venus 167x) need two steps */ - serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO); + serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO); } - serial_outp(up, UART_FCR, fcr); /* set fcr */ + serial_out(up, UART_FCR, fcr); /* set fcr */ } serial8250_set_mctrl(&up->port, up->port.mctrl); spin_unlock_irqrestore(&up->port.lock, flags); @@ -2997,11 +2989,11 @@ void serial8250_resume_port(int line) if (up->capabilities & UART_NATSEMI) { /* Ensure it's still in high speed mode */ - serial_outp(up, UART_LCR, 0xE0); + serial_out(up, UART_LCR, 0xE0); ns16550a_goto_highspeed(up); - serial_outp(up, UART_LCR, 0); + serial_out(up, UART_LCR, 0); up->port.uartclk = 921600*16; } uart_resume_port(&serial8250_reg, &up->port); -- cgit v0.10.2 From 3f0ab32753b49ae7afc5b69e3f23152d92aa1f85 Mon Sep 17 00:00:00 2001 From: Paul Gortmaker Date: Thu, 8 Mar 2012 19:12:09 -0500 Subject: serial: make 8250's serial_in shareable to other drivers. Currently 8250.c has serial_in and serial_out as shortcuts to doing the port I/O. They are implemented as macros a ways down in the file. This isn't by accident, but is implicitly required, so cpp doesn't mangle other instances of the common string "serial_in", as it exists as a field in the port struct itself. The above mangling avoidance violates the principle of least surprise, and it also prevents the shortcuts from being relocated up to the top of file, or into 8250.h -- either being a better location than the current one. Move them to 8250.h so other 8250-like drivers can also use the shortcuts, and in the process, make the conflicting names go away by using static inlines instead of macros. The object file size remains unchanged with this modification. Signed-off-by: Paul Gortmaker Acked-by: Alan Cox Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/8250/8250.c b/drivers/tty/serial/8250/8250.c index 9674eac..4009e24 100644 --- a/drivers/tty/serial/8250/8250.c +++ b/drivers/tty/serial/8250/8250.c @@ -482,11 +482,6 @@ serial_out_sync(struct uart_8250_port *up, int offset, int value) } } -#define serial_in(up, offset) \ - (up->port.serial_in(&(up)->port, (offset))) -#define serial_out(up, offset, value) \ - (up->port.serial_out(&(up)->port, (offset), (value))) - /* Uart divisor latch read */ static inline int _serial_dl_read(struct uart_8250_port *up) { diff --git a/drivers/tty/serial/8250/8250.h b/drivers/tty/serial/8250/8250.h index ae027be..2868a1d 100644 --- a/drivers/tty/serial/8250/8250.h +++ b/drivers/tty/serial/8250/8250.h @@ -86,6 +86,16 @@ struct serial8250_config { #define SERIAL8250_SHARE_IRQS 0 #endif +static inline int serial_in(struct uart_8250_port *up, int offset) +{ + return up->port.serial_in(&up->port, offset); +} + +static inline void serial_out(struct uart_8250_port *up, int offset, int value) +{ + up->port.serial_out(&up->port, offset, value); +} + #if defined(__alpha__) && !defined(CONFIG_PCI) /* * Digital did something really horribly wrong with the OUT1 and OUT2 -- cgit v0.10.2 From 0d263a264c4b8376ccf33248f6fac873310e5e05 Mon Sep 17 00:00:00 2001 From: Paul Gortmaker Date: Thu, 8 Mar 2012 19:12:10 -0500 Subject: serial: delete useless void casts in 8250.c These might have worked some magic with an ancient gcc back in 1992, but "objdump --disassemble" on gcc 4.6 on x86-64 shows identical output before and after this commit. Send the casts and their hysterical rasins to the bitbucket. Signed-off-by: Paul Gortmaker Acked-by: Alan Cox Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/8250/8250.c b/drivers/tty/serial/8250/8250.c index 4009e24..6a71716 100644 --- a/drivers/tty/serial/8250/8250.c +++ b/drivers/tty/serial/8250/8250.c @@ -1218,7 +1218,7 @@ static void autoconfig_irq(struct uart_8250_port *up) ICP = (up->port.iobase & 0xfe0) | 0x1f; save_ICP = inb_p(ICP); outb_p(0x80, ICP); - (void) inb_p(ICP); + inb_p(ICP); } /* forget possible initially masked and pending IRQ */ @@ -1238,10 +1238,10 @@ static void autoconfig_irq(struct uart_8250_port *up) UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2); } serial_out(up, UART_IER, 0x0f); /* enable all intrs */ - (void)serial_in(up, UART_LSR); - (void)serial_in(up, UART_RX); - (void)serial_in(up, UART_IIR); - (void)serial_in(up, UART_MSR); + serial_in(up, UART_LSR); + serial_in(up, UART_RX); + serial_in(up, UART_IIR); + serial_in(up, UART_MSR); serial_out(up, UART_TX, 0xFF); udelay(20); irq = probe_irq_off(irqs); @@ -1973,10 +1973,10 @@ static int serial8250_startup(struct uart_port *port) /* * Clear the interrupt registers. */ - (void) serial_in(up, UART_LSR); - (void) serial_in(up, UART_RX); - (void) serial_in(up, UART_IIR); - (void) serial_in(up, UART_MSR); + serial_in(up, UART_LSR); + serial_in(up, UART_RX); + serial_in(up, UART_IIR); + serial_in(up, UART_MSR); /* * At this point, there's no way the LSR could still be 0xff; @@ -2152,7 +2152,7 @@ dont_test_tx_en: */ icp = (up->port.iobase & 0xfe0) | 0x01f; outb_p(0x80, icp); - (void) inb_p(icp); + inb_p(icp); } return 0; @@ -2198,7 +2198,7 @@ static void serial8250_shutdown(struct uart_port *port) * Read data port to reset things, and then unlink from * the IRQ chain. */ - (void) serial_in(up, UART_RX); + serial_in(up, UART_RX); del_timer_sync(&up->timer); up->timer.function = serial8250_timeout; -- cgit v0.10.2 From dfe42443ea1d30c98db59b7b1f914bc147d31336 Mon Sep 17 00:00:00 2001 From: Paul Gortmaker Date: Thu, 8 Mar 2012 19:12:11 -0500 Subject: serial: reduce number of indirections in 8250 code The serial_8250_port struct contains within a serial_port struct and many times one or the other, or both are in scope within functions via a passed in arg, or via container_of. However there are a lot of cases where we have access directly to the port pointer, but yet go through the parent 8250_port structure instead to get it. These should just use the port struct directly. Similarly there are cases where it makes sense (from a code cleanliness point of view) to declare a local for the port struct, so we aren't going through the parent 8250_port struct repeatedly to get to it. We get a small reduction in text size, but it appears that gcc was smart enough to internally be doing most of this already, so the readability improvement is the larger gain. Signed-off-by: Paul Gortmaker Acked-by: Alan Cox Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/8250/8250.c b/drivers/tty/serial/8250/8250.c index 6a71716..a0d114d 100644 --- a/drivers/tty/serial/8250/8250.c +++ b/drivers/tty/serial/8250/8250.c @@ -1040,24 +1040,25 @@ static void autoconfig(struct uart_8250_port *up, unsigned int probeflags) { unsigned char status1, scratch, scratch2, scratch3; unsigned char save_lcr, save_mcr; + struct uart_port *port = &up->port; unsigned long flags; - if (!up->port.iobase && !up->port.mapbase && !up->port.membase) + if (!port->iobase && !port->mapbase && !port->membase) return; DEBUG_AUTOCONF("ttyS%d: autoconf (0x%04lx, 0x%p): ", - serial_index(&up->port), up->port.iobase, up->port.membase); + serial_index(port), port->iobase, port->membase); /* * We really do need global IRQs disabled here - we're going to * be frobbing the chips IRQ enable register to see if it exists. */ - spin_lock_irqsave(&up->port.lock, flags); + spin_lock_irqsave(&port->lock, flags); up->capabilities = 0; up->bugs = 0; - if (!(up->port.flags & UPF_BUGGY_UART)) { + if (!(port->flags & UPF_BUGGY_UART)) { /* * Do a simple existence test first; if we fail this, * there's no point trying anything else. @@ -1109,7 +1110,7 @@ static void autoconfig(struct uart_8250_port *up, unsigned int probeflags) * manufacturer would be stupid enough to design a board * that conflicts with COM 1-4 --- we hope! */ - if (!(up->port.flags & UPF_SKIP_TEST)) { + if (!(port->flags & UPF_SKIP_TEST)) { serial_out(up, UART_MCR, UART_MCR_LOOP | 0x0A); status1 = serial_in(up, UART_MSR) & 0xF0; serial_out(up, UART_MCR, save_mcr); @@ -1143,10 +1144,10 @@ static void autoconfig(struct uart_8250_port *up, unsigned int probeflags) autoconfig_8250(up); break; case 1: - up->port.type = PORT_UNKNOWN; + port->type = PORT_UNKNOWN; break; case 2: - up->port.type = PORT_16550; + port->type = PORT_16550; break; case 3: autoconfig_16550a(up); @@ -1157,13 +1158,12 @@ static void autoconfig(struct uart_8250_port *up, unsigned int probeflags) /* * Only probe for RSA ports if we got the region. */ - if (up->port.type == PORT_16550A && probeflags & PROBE_RSA) { + if (port->type == PORT_16550A && probeflags & PROBE_RSA) { int i; for (i = 0 ; i < probe_rsa_count; ++i) { - if (probe_rsa[i] == up->port.iobase && - __enable_rsa(up)) { - up->port.type = PORT_RSA; + if (probe_rsa[i] == port->iobase && __enable_rsa(up)) { + port->type = PORT_RSA; break; } } @@ -1172,25 +1172,25 @@ static void autoconfig(struct uart_8250_port *up, unsigned int probeflags) serial_out(up, UART_LCR, save_lcr); - if (up->capabilities != uart_config[up->port.type].flags) { + if (up->capabilities != uart_config[port->type].flags) { printk(KERN_WARNING "ttyS%d: detected caps %08x should be %08x\n", - serial_index(&up->port), up->capabilities, - uart_config[up->port.type].flags); + serial_index(port), up->capabilities, + uart_config[port->type].flags); } - up->port.fifosize = uart_config[up->port.type].fifo_size; - up->capabilities = uart_config[up->port.type].flags; - up->tx_loadsz = uart_config[up->port.type].tx_loadsz; + port->fifosize = uart_config[up->port.type].fifo_size; + up->capabilities = uart_config[port->type].flags; + up->tx_loadsz = uart_config[port->type].tx_loadsz; - if (up->port.type == PORT_UNKNOWN) + if (port->type == PORT_UNKNOWN) goto out; /* * Reset the UART. */ #ifdef CONFIG_SERIAL_8250_RSA - if (up->port.type == PORT_RSA) + if (port->type == PORT_RSA) serial_out(up, UART_RSA_FRR, 0); #endif serial_out(up, UART_MCR, save_mcr); @@ -1202,20 +1202,21 @@ static void autoconfig(struct uart_8250_port *up, unsigned int probeflags) serial_out(up, UART_IER, 0); out: - spin_unlock_irqrestore(&up->port.lock, flags); - DEBUG_AUTOCONF("type=%s\n", uart_config[up->port.type].name); + spin_unlock_irqrestore(&port->lock, flags); + DEBUG_AUTOCONF("type=%s\n", uart_config[port->type].name); } static void autoconfig_irq(struct uart_8250_port *up) { + struct uart_port *port = &up->port; unsigned char save_mcr, save_ier; unsigned char save_ICP = 0; unsigned int ICP = 0; unsigned long irqs; int irq; - if (up->port.flags & UPF_FOURPORT) { - ICP = (up->port.iobase & 0xfe0) | 0x1f; + if (port->flags & UPF_FOURPORT) { + ICP = (port->iobase & 0xfe0) | 0x1f; save_ICP = inb_p(ICP); outb_p(0x80, ICP); inb_p(ICP); @@ -1230,7 +1231,7 @@ static void autoconfig_irq(struct uart_8250_port *up) irqs = probe_irq_on(); serial_out(up, UART_MCR, 0); udelay(10); - if (up->port.flags & UPF_FOURPORT) { + if (port->flags & UPF_FOURPORT) { serial_out(up, UART_MCR, UART_MCR_DTR | UART_MCR_RTS); } else { @@ -1249,10 +1250,10 @@ static void autoconfig_irq(struct uart_8250_port *up) serial_out(up, UART_MCR, save_mcr); serial_out(up, UART_IER, save_ier); - if (up->port.flags & UPF_FOURPORT) + if (port->flags & UPF_FOURPORT) outb_p(save_ICP, ICP); - up->port.irq = (irq > 0) ? irq : 0; + port->irq = (irq > 0) ? irq : 0; } static inline void __stop_tx(struct uart_8250_port *p) @@ -1273,7 +1274,7 @@ static void serial8250_stop_tx(struct uart_port *port) /* * We really want to stop the transmitter from sending. */ - if (up->port.type == PORT_16C950) { + if (port->type == PORT_16C950) { up->acr |= UART_ACR_TXDIS; serial_icr_write(up, UART_ACR, up->acr); } @@ -1292,7 +1293,7 @@ static void serial8250_start_tx(struct uart_port *port) unsigned char lsr; lsr = serial_in(up, UART_LSR); up->lsr_saved_flags |= lsr & LSR_SAVE_FLAGS; - if ((up->port.type == PORT_RM9000) ? + if ((port->type == PORT_RM9000) ? (lsr & UART_LSR_THRE) : (lsr & UART_LSR_TEMT)) serial8250_tx_chars(up); @@ -1302,7 +1303,7 @@ static void serial8250_start_tx(struct uart_port *port) /* * Re-enable the transmitter if we disabled it. */ - if (up->port.type == PORT_16C950 && up->acr & UART_ACR_TXDIS) { + if (port->type == PORT_16C950 && up->acr & UART_ACR_TXDIS) { up->acr &= ~UART_ACR_TXDIS; serial_icr_write(up, UART_ACR, up->acr); } @@ -1360,7 +1361,8 @@ static void clear_rx_fifo(struct uart_8250_port *up) unsigned char serial8250_rx_chars(struct uart_8250_port *up, unsigned char lsr) { - struct tty_struct *tty = up->port.state->port.tty; + struct uart_port *port = &up->port; + struct tty_struct *tty = port->state->port.tty; unsigned char ch; int max_count = 256; char flag; @@ -1379,7 +1381,7 @@ serial8250_rx_chars(struct uart_8250_port *up, unsigned char lsr) ch = 0; flag = TTY_NORMAL; - up->port.icount.rx++; + port->icount.rx++; lsr |= up->lsr_saved_flags; up->lsr_saved_flags = 0; @@ -1390,12 +1392,12 @@ serial8250_rx_chars(struct uart_8250_port *up, unsigned char lsr) */ if (lsr & UART_LSR_BI) { lsr &= ~(UART_LSR_FE | UART_LSR_PE); - up->port.icount.brk++; + port->icount.brk++; /* * If tegra port then clear the rx fifo to * accept another break/character. */ - if (up->port.type == PORT_TEGRA) + if (port->type == PORT_TEGRA) clear_rx_fifo(up); /* @@ -1404,19 +1406,19 @@ serial8250_rx_chars(struct uart_8250_port *up, unsigned char lsr) * may get masked by ignore_status_mask * or read_status_mask. */ - if (uart_handle_break(&up->port)) + if (uart_handle_break(port)) goto ignore_char; } else if (lsr & UART_LSR_PE) - up->port.icount.parity++; + port->icount.parity++; else if (lsr & UART_LSR_FE) - up->port.icount.frame++; + port->icount.frame++; if (lsr & UART_LSR_OE) - up->port.icount.overrun++; + port->icount.overrun++; /* * Mask off conditions which should be ignored. */ - lsr &= up->port.read_status_mask; + lsr &= port->read_status_mask; if (lsr & UART_LSR_BI) { DEBUG_INTR("handling break...."); @@ -1426,34 +1428,35 @@ serial8250_rx_chars(struct uart_8250_port *up, unsigned char lsr) else if (lsr & UART_LSR_FE) flag = TTY_FRAME; } - if (uart_handle_sysrq_char(&up->port, ch)) + if (uart_handle_sysrq_char(port, ch)) goto ignore_char; - uart_insert_char(&up->port, lsr, UART_LSR_OE, ch, flag); + uart_insert_char(port, lsr, UART_LSR_OE, ch, flag); ignore_char: lsr = serial_in(up, UART_LSR); } while ((lsr & (UART_LSR_DR | UART_LSR_BI)) && (max_count-- > 0)); - spin_unlock(&up->port.lock); + spin_unlock(&port->lock); tty_flip_buffer_push(tty); - spin_lock(&up->port.lock); + spin_lock(&port->lock); return lsr; } EXPORT_SYMBOL_GPL(serial8250_rx_chars); void serial8250_tx_chars(struct uart_8250_port *up) { - struct circ_buf *xmit = &up->port.state->xmit; + struct uart_port *port = &up->port; + struct circ_buf *xmit = &port->state->xmit; int count; - if (up->port.x_char) { - serial_out(up, UART_TX, up->port.x_char); - up->port.icount.tx++; - up->port.x_char = 0; + if (port->x_char) { + serial_out(up, UART_TX, port->x_char); + port->icount.tx++; + port->x_char = 0; return; } - if (uart_tx_stopped(&up->port)) { - serial8250_stop_tx(&up->port); + if (uart_tx_stopped(port)) { + serial8250_stop_tx(port); return; } if (uart_circ_empty(xmit)) { @@ -1465,13 +1468,13 @@ void serial8250_tx_chars(struct uart_8250_port *up) do { serial_out(up, UART_TX, xmit->buf[xmit->tail]); xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - up->port.icount.tx++; + port->icount.tx++; if (uart_circ_empty(xmit)) break; } while (--count > 0); if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(&up->port); + uart_write_wakeup(port); DEBUG_INTR("THRE..."); @@ -1482,22 +1485,23 @@ EXPORT_SYMBOL_GPL(serial8250_tx_chars); unsigned int serial8250_modem_status(struct uart_8250_port *up) { + struct uart_port *port = &up->port; unsigned int status = serial_in(up, UART_MSR); status |= up->msr_saved_flags; up->msr_saved_flags = 0; if (status & UART_MSR_ANY_DELTA && up->ier & UART_IER_MSI && - up->port.state != NULL) { + port->state != NULL) { if (status & UART_MSR_TERI) - up->port.icount.rng++; + port->icount.rng++; if (status & UART_MSR_DDSR) - up->port.icount.dsr++; + port->icount.dsr++; if (status & UART_MSR_DDCD) - uart_handle_dcd_change(&up->port, status & UART_MSR_DCD); + uart_handle_dcd_change(port, status & UART_MSR_DCD); if (status & UART_MSR_DCTS) - uart_handle_cts_change(&up->port, status & UART_MSR_CTS); + uart_handle_cts_change(port, status & UART_MSR_CTS); - wake_up_interruptible(&up->port.state->port.delta_msr_wait); + wake_up_interruptible(&port->state->port.delta_msr_wait); } return status; @@ -1517,7 +1521,7 @@ int serial8250_handle_irq(struct uart_port *port, unsigned int iir) if (iir & UART_IIR_NO_INT) return 0; - spin_lock_irqsave(&up->port.lock, flags); + spin_lock_irqsave(&port->lock, flags); status = serial_in(up, UART_LSR); @@ -1529,7 +1533,7 @@ int serial8250_handle_irq(struct uart_port *port, unsigned int iir) if (status & UART_LSR_THRE) serial8250_tx_chars(up); - spin_unlock_irqrestore(&up->port.lock, flags); + spin_unlock_irqrestore(&port->lock, flags); return 1; } EXPORT_SYMBOL_GPL(serial8250_handle_irq); @@ -1771,10 +1775,10 @@ static unsigned int serial8250_tx_empty(struct uart_port *port) unsigned long flags; unsigned int lsr; - spin_lock_irqsave(&up->port.lock, flags); + spin_lock_irqsave(&port->lock, flags); lsr = serial_in(up, UART_LSR); up->lsr_saved_flags |= lsr & LSR_SAVE_FLAGS; - spin_unlock_irqrestore(&up->port.lock, flags); + spin_unlock_irqrestore(&port->lock, flags); return (lsr & BOTH_EMPTY) == BOTH_EMPTY ? TIOCSER_TEMT : 0; } @@ -1828,13 +1832,13 @@ static void serial8250_break_ctl(struct uart_port *port, int break_state) container_of(port, struct uart_8250_port, port); unsigned long flags; - spin_lock_irqsave(&up->port.lock, flags); + spin_lock_irqsave(&port->lock, flags); if (break_state == -1) up->lcr |= UART_LCR_SBC; else up->lcr &= ~UART_LCR_SBC; serial_out(up, UART_LCR, up->lcr); - spin_unlock_irqrestore(&up->port.lock, flags); + spin_unlock_irqrestore(&port->lock, flags); } /* @@ -1935,15 +1939,15 @@ static int serial8250_startup(struct uart_port *port) unsigned char lsr, iir; int retval; - up->port.fifosize = uart_config[up->port.type].fifo_size; + port->fifosize = uart_config[up->port.type].fifo_size; up->tx_loadsz = uart_config[up->port.type].tx_loadsz; up->capabilities = uart_config[up->port.type].flags; up->mcr = 0; - if (up->port.iotype != up->cur_iotype) + if (port->iotype != up->cur_iotype) set_io_from_upio(port); - if (up->port.type == PORT_16C950) { + if (port->type == PORT_16C950) { /* Wake up and initialize UART */ up->acr = 0; serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); @@ -1983,17 +1987,17 @@ static int serial8250_startup(struct uart_port *port) * if it is, then bail out, because there's likely no UART * here. */ - if (!(up->port.flags & UPF_BUGGY_UART) && + if (!(port->flags & UPF_BUGGY_UART) && (serial_in(up, UART_LSR) == 0xff)) { printk_ratelimited(KERN_INFO "ttyS%d: LSR safety check engaged!\n", - serial_index(&up->port)); + serial_index(port)); return -ENODEV; } /* * For a XR16C850, we need to set the trigger levels */ - if (up->port.type == PORT_16850) { + if (port->type == PORT_16850) { unsigned char fctr; serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); @@ -2007,7 +2011,7 @@ static int serial8250_startup(struct uart_port *port) serial_out(up, UART_LCR, 0); } - if (up->port.irq) { + if (port->irq) { unsigned char iir1; /* * Test for UARTs that do not reassert THRE when the @@ -2017,9 +2021,9 @@ static int serial8250_startup(struct uart_port *port) * the interrupt is enabled. Delays are necessary to * allow register changes to become visible. */ - spin_lock_irqsave(&up->port.lock, flags); + spin_lock_irqsave(&port->lock, flags); if (up->port.irqflags & IRQF_SHARED) - disable_irq_nosync(up->port.irq); + disable_irq_nosync(port->irq); wait_for_xmitr(up, UART_LSR_THRE); serial_out_sync(up, UART_IER, UART_IER_THRI); @@ -2031,9 +2035,9 @@ static int serial8250_startup(struct uart_port *port) iir = serial_in(up, UART_IIR); serial_out(up, UART_IER, 0); - if (up->port.irqflags & IRQF_SHARED) - enable_irq(up->port.irq); - spin_unlock_irqrestore(&up->port.lock, flags); + if (port->irqflags & IRQF_SHARED) + enable_irq(port->irq); + spin_unlock_irqrestore(&port->lock, flags); /* * If the interrupt is not reasserted, setup a timer to @@ -2062,7 +2066,7 @@ static int serial8250_startup(struct uart_port *port) * hardware interrupt, we use a timer-based system. The original * driver used to do this with IRQ0. */ - if (!up->port.irq) { + if (!port->irq) { up->timer.data = (unsigned long)up; mod_timer(&up->timer, jiffies + uart_poll_timeout(port)); } else { @@ -2076,7 +2080,7 @@ static int serial8250_startup(struct uart_port *port) */ serial_out(up, UART_LCR, UART_LCR_WLEN8); - spin_lock_irqsave(&up->port.lock, flags); + spin_lock_irqsave(&port->lock, flags); if (up->port.flags & UPF_FOURPORT) { if (!up->port.irq) up->port.mctrl |= TIOCM_OUT1; @@ -2084,10 +2088,10 @@ static int serial8250_startup(struct uart_port *port) /* * Most PC uarts need OUT2 raised to enable interrupts. */ - if (up->port.irq) + if (port->irq) up->port.mctrl |= TIOCM_OUT2; - serial8250_set_mctrl(&up->port, up->port.mctrl); + serial8250_set_mctrl(port, port->mctrl); /* Serial over Lan (SoL) hack: Intel 8257x Gigabit ethernet chips have a @@ -2123,7 +2127,7 @@ static int serial8250_startup(struct uart_port *port) } dont_test_tx_en: - spin_unlock_irqrestore(&up->port.lock, flags); + spin_unlock_irqrestore(&port->lock, flags); /* * Clear the interrupt registers again for luck, and clear the @@ -2145,12 +2149,12 @@ dont_test_tx_en: up->ier = UART_IER_RLSI | UART_IER_RDI; serial_out(up, UART_IER, up->ier); - if (up->port.flags & UPF_FOURPORT) { + if (port->flags & UPF_FOURPORT) { unsigned int icp; /* * Enable interrupts on the AST Fourport board */ - icp = (up->port.iobase & 0xfe0) | 0x01f; + icp = (port->iobase & 0xfe0) | 0x01f; outb_p(0x80, icp); inb_p(icp); } @@ -2170,16 +2174,16 @@ static void serial8250_shutdown(struct uart_port *port) up->ier = 0; serial_out(up, UART_IER, 0); - spin_lock_irqsave(&up->port.lock, flags); - if (up->port.flags & UPF_FOURPORT) { + spin_lock_irqsave(&port->lock, flags); + if (port->flags & UPF_FOURPORT) { /* reset interrupts on the AST Fourport board */ - inb((up->port.iobase & 0xfe0) | 0x1f); - up->port.mctrl |= TIOCM_OUT1; + inb((port->iobase & 0xfe0) | 0x1f); + port->mctrl |= TIOCM_OUT1; } else - up->port.mctrl &= ~TIOCM_OUT2; + port->mctrl &= ~TIOCM_OUT2; - serial8250_set_mctrl(&up->port, up->port.mctrl); - spin_unlock_irqrestore(&up->port.lock, flags); + serial8250_set_mctrl(port, port->mctrl); + spin_unlock_irqrestore(&port->lock, flags); /* * Disable break condition and FIFOs @@ -2202,7 +2206,7 @@ static void serial8250_shutdown(struct uart_port *port) del_timer_sync(&up->timer); up->timer.function = serial8250_timeout; - if (up->port.irq) + if (port->irq) serial_unlink_irq_chain(up); } @@ -2277,11 +2281,11 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios, if (up->bugs & UART_BUG_QUOT && (quot & 0xff) == 0) quot++; - if (up->capabilities & UART_CAP_FIFO && up->port.fifosize > 1) { + if (up->capabilities & UART_CAP_FIFO && port->fifosize > 1) { if (baud < 2400) fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1; else - fcr = uart_config[up->port.type].fcr; + fcr = uart_config[port->type].fcr; } /* @@ -2292,7 +2296,7 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios, * have sufficient FIFO entries for the latency of the remote * UART to respond. IOW, at least 32 bytes of FIFO. */ - if (up->capabilities & UART_CAP_AFE && up->port.fifosize >= 32) { + if (up->capabilities & UART_CAP_AFE && port->fifosize >= 32) { up->mcr &= ~UART_MCR_AFE; if (termios->c_cflag & CRTSCTS) up->mcr |= UART_MCR_AFE; @@ -2302,40 +2306,40 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios, * Ok, we're now changing the port state. Do it with * interrupts disabled. */ - spin_lock_irqsave(&up->port.lock, flags); + spin_lock_irqsave(&port->lock, flags); /* * Update the per-port timeout. */ uart_update_timeout(port, termios->c_cflag, baud); - up->port.read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR; + port->read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR; if (termios->c_iflag & INPCK) - up->port.read_status_mask |= UART_LSR_FE | UART_LSR_PE; + port->read_status_mask |= UART_LSR_FE | UART_LSR_PE; if (termios->c_iflag & (BRKINT | PARMRK)) - up->port.read_status_mask |= UART_LSR_BI; + port->read_status_mask |= UART_LSR_BI; /* * Characteres to ignore */ - up->port.ignore_status_mask = 0; + port->ignore_status_mask = 0; if (termios->c_iflag & IGNPAR) - up->port.ignore_status_mask |= UART_LSR_PE | UART_LSR_FE; + port->ignore_status_mask |= UART_LSR_PE | UART_LSR_FE; if (termios->c_iflag & IGNBRK) { - up->port.ignore_status_mask |= UART_LSR_BI; + port->ignore_status_mask |= UART_LSR_BI; /* * If we're ignoring parity and break indicators, * ignore overruns too (for real raw support). */ if (termios->c_iflag & IGNPAR) - up->port.ignore_status_mask |= UART_LSR_OE; + port->ignore_status_mask |= UART_LSR_OE; } /* * ignore all characters if CREAD is not set */ if ((termios->c_cflag & CREAD) == 0) - up->port.ignore_status_mask |= UART_LSR_DR; + port->ignore_status_mask |= UART_LSR_DR; /* * CTS flow control flag and modem status interrupts @@ -2362,7 +2366,7 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios, efr |= UART_EFR_CTS; serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); - if (up->port.flags & UPF_EXAR_EFR) + if (port->flags & UPF_EXAR_EFR) serial_out(up, UART_XR_EFR, efr); else serial_out(up, UART_EFR, efr); @@ -2392,20 +2396,20 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios, * LCR DLAB must be set to enable 64-byte FIFO mode. If the FCR * is written without DLAB set, this mode will be disabled. */ - if (up->port.type == PORT_16750) + if (port->type == PORT_16750) serial_out(up, UART_FCR, fcr); serial_out(up, UART_LCR, cval); /* reset DLAB */ up->lcr = cval; /* Save LCR */ - if (up->port.type != PORT_16750) { + if (port->type != PORT_16750) { if (fcr & UART_FCR_ENABLE_FIFO) { /* emulated UARTs (Lucent Venus 167x) need two steps */ serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO); } serial_out(up, UART_FCR, fcr); /* set fcr */ } - serial8250_set_mctrl(&up->port, up->port.mctrl); - spin_unlock_irqrestore(&up->port.lock, flags); + serial8250_set_mctrl(port, port->mctrl); + spin_unlock_irqrestore(&port->lock, flags); /* Don't rewrite B0 */ if (tty_termios_baud_rate(termios)) tty_termios_encode_baud_rate(termios, baud, baud); @@ -2470,26 +2474,26 @@ static unsigned int serial8250_port_size(struct uart_8250_port *pt) static int serial8250_request_std_resource(struct uart_8250_port *up) { unsigned int size = serial8250_port_size(up); + struct uart_port *port = &up->port; int ret = 0; - switch (up->port.iotype) { + switch (port->iotype) { case UPIO_AU: case UPIO_TSI: case UPIO_MEM32: case UPIO_MEM: - if (!up->port.mapbase) + if (!port->mapbase) break; - if (!request_mem_region(up->port.mapbase, size, "serial")) { + if (!request_mem_region(port->mapbase, size, "serial")) { ret = -EBUSY; break; } - if (up->port.flags & UPF_IOREMAP) { - up->port.membase = ioremap_nocache(up->port.mapbase, - size); - if (!up->port.membase) { - release_mem_region(up->port.mapbase, size); + if (port->flags & UPF_IOREMAP) { + port->membase = ioremap_nocache(port->mapbase, size); + if (!port->membase) { + release_mem_region(port->mapbase, size); ret = -ENOMEM; } } @@ -2497,7 +2501,7 @@ static int serial8250_request_std_resource(struct uart_8250_port *up) case UPIO_HUB6: case UPIO_PORT: - if (!request_region(up->port.iobase, size, "serial")) + if (!request_region(port->iobase, size, "serial")) ret = -EBUSY; break; } @@ -2507,26 +2511,27 @@ static int serial8250_request_std_resource(struct uart_8250_port *up) static void serial8250_release_std_resource(struct uart_8250_port *up) { unsigned int size = serial8250_port_size(up); + struct uart_port *port = &up->port; - switch (up->port.iotype) { + switch (port->iotype) { case UPIO_AU: case UPIO_TSI: case UPIO_MEM32: case UPIO_MEM: - if (!up->port.mapbase) + if (!port->mapbase) break; - if (up->port.flags & UPF_IOREMAP) { - iounmap(up->port.membase); - up->port.membase = NULL; + if (port->flags & UPF_IOREMAP) { + iounmap(port->membase); + port->membase = NULL; } - release_mem_region(up->port.mapbase, size); + release_mem_region(port->mapbase, size); break; case UPIO_HUB6: case UPIO_PORT: - release_region(up->port.iobase, size); + release_region(port->iobase, size); break; } } @@ -2535,12 +2540,13 @@ static int serial8250_request_rsa_resource(struct uart_8250_port *up) { unsigned long start = UART_RSA_BASE << up->port.regshift; unsigned int size = 8 << up->port.regshift; + struct uart_port *port = &up->port; int ret = -EINVAL; - switch (up->port.iotype) { + switch (port->iotype) { case UPIO_HUB6: case UPIO_PORT: - start += up->port.iobase; + start += port->iobase; if (request_region(start, size, "serial-rsa")) ret = 0; else @@ -2555,11 +2561,12 @@ static void serial8250_release_rsa_resource(struct uart_8250_port *up) { unsigned long offset = UART_RSA_BASE << up->port.regshift; unsigned int size = 8 << up->port.regshift; + struct uart_port *port = &up->port; - switch (up->port.iotype) { + switch (port->iotype) { case UPIO_HUB6: case UPIO_PORT: - release_region(up->port.iobase + offset, size); + release_region(port->iobase + offset, size); break; } } @@ -2570,7 +2577,7 @@ static void serial8250_release_port(struct uart_port *port) container_of(port, struct uart_8250_port, port); serial8250_release_std_resource(up); - if (up->port.type == PORT_RSA) + if (port->type == PORT_RSA) serial8250_release_rsa_resource(up); } @@ -2581,7 +2588,7 @@ static int serial8250_request_port(struct uart_port *port) int ret = 0; ret = serial8250_request_std_resource(up); - if (ret == 0 && up->port.type == PORT_RSA) { + if (ret == 0 && port->type == PORT_RSA) { ret = serial8250_request_rsa_resource(up); if (ret < 0) serial8250_release_std_resource(up); @@ -2609,22 +2616,22 @@ static void serial8250_config_port(struct uart_port *port, int flags) if (ret < 0) probeflags &= ~PROBE_RSA; - if (up->port.iotype != up->cur_iotype) + if (port->iotype != up->cur_iotype) set_io_from_upio(port); if (flags & UART_CONFIG_TYPE) autoconfig(up, probeflags); /* if access method is AU, it is a 16550 with a quirk */ - if (up->port.type == PORT_16550A && up->port.iotype == UPIO_AU) + if (port->type == PORT_16550A && port->iotype == UPIO_AU) up->bugs |= UART_BUG_NOMSR; - if (up->port.type != PORT_UNKNOWN && flags & UART_CONFIG_IRQ) + if (port->type != PORT_UNKNOWN && flags & UART_CONFIG_IRQ) autoconfig_irq(up); - if (up->port.type != PORT_RSA && probeflags & PROBE_RSA) + if (port->type != PORT_RSA && probeflags & PROBE_RSA) serial8250_release_rsa_resource(up); - if (up->port.type == PORT_UNKNOWN) + if (port->type == PORT_UNKNOWN) serial8250_release_std_resource(up); } @@ -2698,9 +2705,10 @@ static void __init serial8250_isa_init_ports(void) for (i = 0; i < nr_uarts; i++) { struct uart_8250_port *up = &serial8250_ports[i]; + struct uart_port *port = &up->port; - up->port.line = i; - spin_lock_init(&up->port.lock); + port->line = i; + spin_lock_init(&port->lock); init_timer(&up->timer); up->timer.function = serial8250_timeout; @@ -2711,7 +2719,7 @@ static void __init serial8250_isa_init_ports(void) up->mcr_mask = ~ALPHA_KLUDGE_MCR; up->mcr_force = ALPHA_KLUDGE_MCR; - up->port.ops = &serial8250_pops; + port->ops = &serial8250_pops; } if (share_irqs) @@ -2720,17 +2728,19 @@ static void __init serial8250_isa_init_ports(void) for (i = 0, up = serial8250_ports; i < ARRAY_SIZE(old_serial_port) && i < nr_uarts; i++, up++) { - up->port.iobase = old_serial_port[i].port; - up->port.irq = irq_canonicalize(old_serial_port[i].irq); - up->port.irqflags = old_serial_port[i].irqflags; - up->port.uartclk = old_serial_port[i].baud_base * 16; - up->port.flags = old_serial_port[i].flags; - up->port.hub6 = old_serial_port[i].hub6; - up->port.membase = old_serial_port[i].iomem_base; - up->port.iotype = old_serial_port[i].io_type; - up->port.regshift = old_serial_port[i].iomem_reg_shift; - set_io_from_upio(&up->port); - up->port.irqflags |= irqflag; + struct uart_port *port = &up->port; + + port->iobase = old_serial_port[i].port; + port->irq = irq_canonicalize(old_serial_port[i].irq); + port->irqflags = old_serial_port[i].irqflags; + port->uartclk = old_serial_port[i].baud_base * 16; + port->flags = old_serial_port[i].flags; + port->hub6 = old_serial_port[i].hub6; + port->membase = old_serial_port[i].iomem_base; + port->iotype = old_serial_port[i].io_type; + port->regshift = old_serial_port[i].iomem_reg_shift; + set_io_from_upio(port); + port->irqflags |= irqflag; if (serial8250_isa_config != NULL) serial8250_isa_config(i, &up->port, &up->capabilities); @@ -2791,6 +2801,7 @@ static void serial8250_console_write(struct console *co, const char *s, unsigned int count) { struct uart_8250_port *up = &serial8250_ports[co->index]; + struct uart_port *port = &up->port; unsigned long flags; unsigned int ier; int locked = 1; @@ -2798,13 +2809,13 @@ serial8250_console_write(struct console *co, const char *s, unsigned int count) touch_nmi_watchdog(); local_irq_save(flags); - if (up->port.sysrq) { + if (port->sysrq) { /* serial8250_handle_irq() already took the lock */ locked = 0; } else if (oops_in_progress) { - locked = spin_trylock(&up->port.lock); + locked = spin_trylock(&port->lock); } else - spin_lock(&up->port.lock); + spin_lock(&port->lock); /* * First save the IER then disable the interrupts @@ -2816,7 +2827,7 @@ serial8250_console_write(struct console *co, const char *s, unsigned int count) else serial_out(up, UART_IER, 0); - uart_console_write(&up->port, s, count, serial8250_console_putchar); + uart_console_write(port, s, count, serial8250_console_putchar); /* * Finally, wait for transmitter to become empty @@ -2836,7 +2847,7 @@ serial8250_console_write(struct console *co, const char *s, unsigned int count) serial8250_modem_status(up); if (locked) - spin_unlock(&up->port.lock); + spin_unlock(&port->lock); local_irq_restore(flags); } @@ -2981,6 +2992,7 @@ void serial8250_suspend_port(int line) void serial8250_resume_port(int line) { struct uart_8250_port *up = &serial8250_ports[line]; + struct uart_port *port = &up->port; if (up->capabilities & UART_NATSEMI) { /* Ensure it's still in high speed mode */ @@ -2989,9 +3001,9 @@ void serial8250_resume_port(int line) ns16550a_goto_highspeed(up); serial_out(up, UART_LCR, 0); - up->port.uartclk = 921600*16; + port->uartclk = 921600*16; } - uart_resume_port(&serial8250_reg, &up->port); + uart_resume_port(&serial8250_reg, port); } /* -- cgit v0.10.2 From 927353a75602dd97144352f53177e18093fdd198 Mon Sep 17 00:00:00 2001 From: Paul Gortmaker Date: Thu, 8 Mar 2012 19:12:12 -0500 Subject: serial: introduce generic port in/out helpers Looking at the existing serial drivers (esp. the 8250 derived variants) we see a common trend. They create a hardware specific port struct, which in turn contains a generic serial_port struct. The other trend, is that they all create some sort of shortcut to go through the hardware specific struct, to the serial_port struct, which has the basic in/out operations within. Looking for the serial_in and serial_out in several drivers shows this. Rather than let this continue, lets create a generic set of similar helper wrappers that can be used on a struct port, so we can eliminate bouncing out through hardware specific struct pointers just to come back into struct port where possible. Signed-off-by: Paul Gortmaker Acked-by: Alan Cox Signed-off-by: Greg Kroah-Hartman diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h index 585bfd0..f51bf2e 100644 --- a/include/linux/serial_core.h +++ b/include/linux/serial_core.h @@ -383,6 +383,16 @@ struct uart_port { void *private_data; /* generic platform data pointer */ }; +static inline int serial_port_in(struct uart_port *up, int offset) +{ + return up->serial_in(up, offset); +} + +static inline void serial_port_out(struct uart_port *up, int offset, int value) +{ + up->serial_out(up, offset, value); +} + /* * This is the state information which is persistent across opens. */ -- cgit v0.10.2 From 4fd996a14660f56a6fd92ce7c8fb167d262c994f Mon Sep 17 00:00:00 2001 From: Paul Gortmaker Date: Thu, 8 Mar 2012 19:12:13 -0500 Subject: serial: use serial_port_in/out vs serial_in/out in 8250 The serial_in and serial_out helpers are expecting to operate on an 8250_port struct. These in turn go after the contained normal port struct which actually has the actual in/out accessors. But what is happening in some cases, is that a function is passed in a port struct, and it runs container_of to get the 8250_port struct, and then it uses serial_in/out helpers on that. But when you do, it goes full circle, since it jumps back inside the 8250_port to find the contained port struct (which we already knew!). So, if we are operating in a scope where we know the struct port, then use the serial_port_in/out helpers and avoid the bouncing around. If we don't have the struct port handy, and it isn't worth making a local for it, then just leave things as-is which uses the serial_in/out helpers that will resolve the 8250_port onto the struct port. Mostly, gcc figures this out on its own -- so this doesn't bring to the table any revolutionary runtime delta. However, it is somewhat misleading to always hammer away on 8250 structs, when the actual underlying property isn't at all 8250 specific -- and this change makes that clear. Signed-off-by: Paul Gortmaker Acked-by: Alan Cox Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/8250/8250.c b/drivers/tty/serial/8250/8250.c index a0d114d..7898295 100644 --- a/drivers/tty/serial/8250/8250.c +++ b/drivers/tty/serial/8250/8250.c @@ -1287,7 +1287,7 @@ static void serial8250_start_tx(struct uart_port *port) if (!(up->ier & UART_IER_THRI)) { up->ier |= UART_IER_THRI; - serial_out(up, UART_IER, up->ier); + serial_port_out(port, UART_IER, up->ier); if (up->bugs & UART_BUG_TXEN) { unsigned char lsr; @@ -1316,7 +1316,7 @@ static void serial8250_stop_rx(struct uart_port *port) up->ier &= ~UART_IER_RLSI; up->port.read_status_mask &= ~UART_LSR_DR; - serial_out(up, UART_IER, up->ier); + serial_port_out(port, UART_IER, up->ier); } static void serial8250_enable_ms(struct uart_port *port) @@ -1329,7 +1329,7 @@ static void serial8250_enable_ms(struct uart_port *port) return; up->ier |= UART_IER_MSI; - serial_out(up, UART_IER, up->ier); + serial_port_out(port, UART_IER, up->ier); } /* @@ -1523,7 +1523,7 @@ int serial8250_handle_irq(struct uart_port *port, unsigned int iir) spin_lock_irqsave(&port->lock, flags); - status = serial_in(up, UART_LSR); + status = serial_port_in(port, UART_LSR); DEBUG_INTR("status = %x...", status); @@ -1540,9 +1540,7 @@ EXPORT_SYMBOL_GPL(serial8250_handle_irq); static int serial8250_default_handle_irq(struct uart_port *port) { - struct uart_8250_port *up = - container_of(port, struct uart_8250_port, port); - unsigned int iir = serial_in(up, UART_IIR); + unsigned int iir = serial_port_in(port, UART_IIR); return serial8250_handle_irq(port, iir); } @@ -1776,7 +1774,7 @@ static unsigned int serial8250_tx_empty(struct uart_port *port) unsigned int lsr; spin_lock_irqsave(&port->lock, flags); - lsr = serial_in(up, UART_LSR); + lsr = serial_port_in(port, UART_LSR); up->lsr_saved_flags |= lsr & LSR_SAVE_FLAGS; spin_unlock_irqrestore(&port->lock, flags); @@ -1823,7 +1821,7 @@ static void serial8250_set_mctrl(struct uart_port *port, unsigned int mctrl) mcr = (mcr & up->mcr_mask) | up->mcr_force | up->mcr; - serial_out(up, UART_MCR, mcr); + serial_port_out(port, UART_MCR, mcr); } static void serial8250_break_ctl(struct uart_port *port, int break_state) @@ -1837,7 +1835,7 @@ static void serial8250_break_ctl(struct uart_port *port, int break_state) up->lcr |= UART_LCR_SBC; else up->lcr &= ~UART_LCR_SBC; - serial_out(up, UART_LCR, up->lcr); + serial_port_out(port, UART_LCR, up->lcr); spin_unlock_irqrestore(&port->lock, flags); } @@ -1883,14 +1881,12 @@ static void wait_for_xmitr(struct uart_8250_port *up, int bits) static int serial8250_get_poll_char(struct uart_port *port) { - struct uart_8250_port *up = - container_of(port, struct uart_8250_port, port); - unsigned char lsr = serial_in(up, UART_LSR); + unsigned char lsr = serial_port_in(port, UART_LSR); if (!(lsr & UART_LSR_DR)) return NO_POLL_CHAR; - return serial_in(up, UART_RX); + return serial_port_in(port, UART_RX); } @@ -1904,21 +1900,21 @@ static void serial8250_put_poll_char(struct uart_port *port, /* * First save the IER then disable the interrupts */ - ier = serial_in(up, UART_IER); + ier = serial_port_in(port, UART_IER); if (up->capabilities & UART_CAP_UUE) - serial_out(up, UART_IER, UART_IER_UUE); + serial_port_out(port, UART_IER, UART_IER_UUE); else - serial_out(up, UART_IER, 0); + serial_port_out(port, 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); + serial_port_out(port, UART_TX, c); if (c == 10) { wait_for_xmitr(up, BOTH_EMPTY); - serial_out(up, UART_TX, 13); + serial_port_out(port, UART_TX, 13); } /* @@ -1926,7 +1922,7 @@ static void serial8250_put_poll_char(struct uart_port *port, * and restore the IER */ wait_for_xmitr(up, BOTH_EMPTY); - serial_out(up, UART_IER, ier); + serial_port_out(port, UART_IER, ier); } #endif /* CONFIG_CONSOLE_POLL */ @@ -1950,14 +1946,14 @@ static int serial8250_startup(struct uart_port *port) if (port->type == PORT_16C950) { /* Wake up and initialize UART */ up->acr = 0; - serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); - serial_out(up, UART_EFR, UART_EFR_ECB); - serial_out(up, UART_IER, 0); - serial_out(up, UART_LCR, 0); + serial_port_out(port, UART_LCR, UART_LCR_CONF_MODE_B); + serial_port_out(port, UART_EFR, UART_EFR_ECB); + serial_port_out(port, UART_IER, 0); + serial_port_out(port, UART_LCR, 0); serial_icr_write(up, UART_CSR, 0); /* Reset the UART */ - serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); - serial_out(up, UART_EFR, UART_EFR_ECB); - serial_out(up, UART_LCR, 0); + serial_port_out(port, UART_LCR, UART_LCR_CONF_MODE_B); + serial_port_out(port, UART_EFR, UART_EFR_ECB); + serial_port_out(port, UART_LCR, 0); } #ifdef CONFIG_SERIAL_8250_RSA @@ -1977,10 +1973,10 @@ static int serial8250_startup(struct uart_port *port) /* * Clear the interrupt registers. */ - serial_in(up, UART_LSR); - serial_in(up, UART_RX); - serial_in(up, UART_IIR); - serial_in(up, UART_MSR); + serial_port_in(port, UART_LSR); + serial_port_in(port, UART_RX); + serial_port_in(port, UART_IIR); + serial_port_in(port, UART_MSR); /* * At this point, there's no way the LSR could still be 0xff; @@ -1988,7 +1984,7 @@ static int serial8250_startup(struct uart_port *port) * here. */ if (!(port->flags & UPF_BUGGY_UART) && - (serial_in(up, UART_LSR) == 0xff)) { + (serial_port_in(port, UART_LSR) == 0xff)) { printk_ratelimited(KERN_INFO "ttyS%d: LSR safety check engaged!\n", serial_index(port)); return -ENODEV; @@ -2003,12 +1999,14 @@ static int serial8250_startup(struct uart_port *port) serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); fctr = serial_in(up, UART_FCTR) & ~(UART_FCTR_RX|UART_FCTR_TX); - serial_out(up, UART_FCTR, fctr | UART_FCTR_TRGD | UART_FCTR_RX); - serial_out(up, UART_TRG, UART_TRG_96); - serial_out(up, UART_FCTR, fctr | UART_FCTR_TRGD | UART_FCTR_TX); - serial_out(up, UART_TRG, UART_TRG_96); + serial_port_out(port, UART_FCTR, + fctr | UART_FCTR_TRGD | UART_FCTR_RX); + serial_port_out(port, UART_TRG, UART_TRG_96); + serial_port_out(port, UART_FCTR, + fctr | UART_FCTR_TRGD | UART_FCTR_TX); + serial_port_out(port, UART_TRG, UART_TRG_96); - serial_out(up, UART_LCR, 0); + serial_port_out(port, UART_LCR, 0); } if (port->irq) { @@ -2028,12 +2026,12 @@ static int serial8250_startup(struct uart_port *port) wait_for_xmitr(up, UART_LSR_THRE); serial_out_sync(up, UART_IER, UART_IER_THRI); udelay(1); /* allow THRE to set */ - iir1 = serial_in(up, UART_IIR); - serial_out(up, UART_IER, 0); + iir1 = serial_port_in(port, UART_IIR); + serial_port_out(port, UART_IER, 0); serial_out_sync(up, UART_IER, UART_IER_THRI); udelay(1); /* allow a working UART time to re-assert THRE */ - iir = serial_in(up, UART_IIR); - serial_out(up, UART_IER, 0); + iir = serial_port_in(port, UART_IIR); + serial_port_out(port, UART_IER, 0); if (port->irqflags & IRQF_SHARED) enable_irq(port->irq); @@ -2078,7 +2076,7 @@ static int serial8250_startup(struct uart_port *port) /* * Now, initialize the UART */ - serial_out(up, UART_LCR, UART_LCR_WLEN8); + serial_port_out(port, UART_LCR, UART_LCR_WLEN8); spin_lock_irqsave(&port->lock, flags); if (up->port.flags & UPF_FOURPORT) { @@ -2111,10 +2109,10 @@ static int serial8250_startup(struct uart_port *port) * Do a quick test to see if we receive an * interrupt when we enable the TX irq. */ - serial_out(up, UART_IER, UART_IER_THRI); - lsr = serial_in(up, UART_LSR); - iir = serial_in(up, UART_IIR); - serial_out(up, UART_IER, 0); + serial_port_out(port, UART_IER, UART_IER_THRI); + lsr = serial_port_in(port, UART_LSR); + iir = serial_port_in(port, UART_IIR); + serial_port_out(port, UART_IER, 0); if (lsr & UART_LSR_TEMT && iir & UART_IIR_NO_INT) { if (!(up->bugs & UART_BUG_TXEN)) { @@ -2134,10 +2132,10 @@ dont_test_tx_en: * saved flags to avoid getting false values from polling * routines or the previous session. */ - serial_in(up, UART_LSR); - serial_in(up, UART_RX); - serial_in(up, UART_IIR); - serial_in(up, UART_MSR); + serial_port_in(port, UART_LSR); + serial_port_in(port, UART_RX); + serial_port_in(port, UART_IIR); + serial_port_in(port, UART_MSR); up->lsr_saved_flags = 0; up->msr_saved_flags = 0; @@ -2147,7 +2145,7 @@ dont_test_tx_en: * anyway, so we don't enable them here. */ up->ier = UART_IER_RLSI | UART_IER_RDI; - serial_out(up, UART_IER, up->ier); + serial_port_out(port, UART_IER, up->ier); if (port->flags & UPF_FOURPORT) { unsigned int icp; @@ -2172,7 +2170,7 @@ static void serial8250_shutdown(struct uart_port *port) * Disable interrupts from this port */ up->ier = 0; - serial_out(up, UART_IER, 0); + serial_port_out(port, UART_IER, 0); spin_lock_irqsave(&port->lock, flags); if (port->flags & UPF_FOURPORT) { @@ -2188,7 +2186,8 @@ static void serial8250_shutdown(struct uart_port *port) /* * Disable break condition and FIFOs */ - serial_out(up, UART_LCR, serial_in(up, UART_LCR) & ~UART_LCR_SBC); + serial_port_out(port, UART_LCR, + serial_port_in(port, UART_LCR) & ~UART_LCR_SBC); serial8250_clear_fifos(up); #ifdef CONFIG_SERIAL_8250_RSA @@ -2202,7 +2201,7 @@ static void serial8250_shutdown(struct uart_port *port) * Read data port to reset things, and then unlink from * the IRQ chain. */ - serial_in(up, UART_RX); + serial_port_in(port, UART_RX); del_timer_sync(&up->timer); up->timer.function = serial8250_timeout; @@ -2353,7 +2352,7 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios, if (up->capabilities & UART_CAP_RTOIE) up->ier |= UART_IER_RTOIE; - serial_out(up, UART_IER, up->ier); + serial_port_out(port, UART_IER, up->ier); if (up->capabilities & UART_CAP_EFR) { unsigned char efr = 0; @@ -2365,11 +2364,11 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios, if (termios->c_cflag & CRTSCTS) efr |= UART_EFR_CTS; - serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); + serial_port_out(port, UART_LCR, UART_LCR_CONF_MODE_B); if (port->flags & UPF_EXAR_EFR) - serial_out(up, UART_XR_EFR, efr); + serial_port_out(port, UART_XR_EFR, efr); else - serial_out(up, UART_EFR, efr); + serial_port_out(port, UART_EFR, efr); } #ifdef CONFIG_ARCH_OMAP @@ -2377,18 +2376,20 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios, if (cpu_is_omap1510() && is_omap_port(up)) { if (baud == 115200) { quot = 1; - serial_out(up, UART_OMAP_OSC_12M_SEL, 1); + serial_port_out(port, UART_OMAP_OSC_12M_SEL, 1); } else - serial_out(up, UART_OMAP_OSC_12M_SEL, 0); + serial_port_out(port, UART_OMAP_OSC_12M_SEL, 0); } #endif - if (up->capabilities & UART_NATSEMI) { - /* Switch to bank 2 not bank 1, to avoid resetting EXCR2 */ - serial_out(up, UART_LCR, 0xe0); - } else { - serial_out(up, UART_LCR, cval | UART_LCR_DLAB);/* set DLAB */ - } + /* + * For NatSemi, switch to bank 2 not bank 1, to avoid resetting EXCR2, + * otherwise just set DLAB + */ + if (up->capabilities & UART_NATSEMI) + serial_port_out(port, UART_LCR, 0xe0); + else + serial_port_out(port, UART_LCR, cval | UART_LCR_DLAB); serial_dl_write(up, quot); @@ -2397,16 +2398,15 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios, * is written without DLAB set, this mode will be disabled. */ if (port->type == PORT_16750) - serial_out(up, UART_FCR, fcr); + serial_port_out(port, UART_FCR, fcr); - serial_out(up, UART_LCR, cval); /* reset DLAB */ + serial_port_out(port, UART_LCR, cval); /* reset DLAB */ up->lcr = cval; /* Save LCR */ if (port->type != PORT_16750) { - if (fcr & UART_FCR_ENABLE_FIFO) { - /* emulated UARTs (Lucent Venus 167x) need two steps */ - serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO); - } - serial_out(up, UART_FCR, fcr); /* set fcr */ + /* emulated UARTs (Lucent Venus 167x) need two steps */ + if (fcr & UART_FCR_ENABLE_FIFO) + serial_port_out(port, UART_FCR, UART_FCR_ENABLE_FIFO); + serial_port_out(port, UART_FCR, fcr); /* set fcr */ } serial8250_set_mctrl(port, port->mctrl); spin_unlock_irqrestore(&port->lock, flags); @@ -2788,7 +2788,7 @@ static void serial8250_console_putchar(struct uart_port *port, int ch) container_of(port, struct uart_8250_port, port); wait_for_xmitr(up, UART_LSR_THRE); - serial_out(up, UART_TX, ch); + serial_port_out(port, UART_TX, ch); } /* @@ -2820,12 +2820,12 @@ serial8250_console_write(struct console *co, const char *s, unsigned int count) /* * First save the IER then disable the interrupts */ - ier = serial_in(up, UART_IER); + ier = serial_port_in(port, UART_IER); if (up->capabilities & UART_CAP_UUE) - serial_out(up, UART_IER, UART_IER_UUE); + serial_port_out(port, UART_IER, UART_IER_UUE); else - serial_out(up, UART_IER, 0); + serial_port_out(port, UART_IER, 0); uart_console_write(port, s, count, serial8250_console_putchar); @@ -2834,7 +2834,7 @@ serial8250_console_write(struct console *co, const char *s, unsigned int count) * and restore the IER */ wait_for_xmitr(up, BOTH_EMPTY); - serial_out(up, UART_IER, ier); + serial_port_out(port, UART_IER, ier); /* * The receive handling will happen properly because the @@ -2996,11 +2996,11 @@ void serial8250_resume_port(int line) if (up->capabilities & UART_NATSEMI) { /* Ensure it's still in high speed mode */ - serial_out(up, UART_LCR, 0xE0); + serial_port_out(port, UART_LCR, 0xE0); ns16550a_goto_highspeed(up); - serial_out(up, UART_LCR, 0); + serial_port_out(port, UART_LCR, 0); port->uartclk = 921600*16; } uart_resume_port(&serial8250_reg, port); -- cgit v0.10.2 From 55e4016dd055e262e4b078b81c80b55386ead0f4 Mon Sep 17 00:00:00 2001 From: Paul Gortmaker Date: Thu, 8 Mar 2012 19:12:14 -0500 Subject: serial: remove back and forth conversions in serial_out_sync The two callers to serial_out_sync() have a struct port right there in scope, but then pass in a struct 8250_port which then is locally resolved back to a struct port. Delete the needless back and forth and just pass in the struct port directly. Rename the function to have "_port" in its name, so the name <--> args relationship is consistent with the other serial_in/out vs serial_port_in/out function classes. Signed-off-by: Paul Gortmaker Acked-by: Alan Cox Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/8250/8250.c b/drivers/tty/serial/8250/8250.c index 7898295..5b149b4 100644 --- a/drivers/tty/serial/8250/8250.c +++ b/drivers/tty/serial/8250/8250.c @@ -467,9 +467,8 @@ static void set_io_from_upio(struct uart_port *p) } static void -serial_out_sync(struct uart_8250_port *up, int offset, int value) +serial_port_out_sync(struct uart_port *p, int offset, int value) { - struct uart_port *p = &up->port; switch (p->iotype) { case UPIO_MEM: case UPIO_MEM32: @@ -2024,11 +2023,11 @@ static int serial8250_startup(struct uart_port *port) disable_irq_nosync(port->irq); wait_for_xmitr(up, UART_LSR_THRE); - serial_out_sync(up, UART_IER, UART_IER_THRI); + serial_port_out_sync(port, UART_IER, UART_IER_THRI); udelay(1); /* allow THRE to set */ iir1 = serial_port_in(port, UART_IIR); serial_port_out(port, UART_IER, 0); - serial_out_sync(up, UART_IER, UART_IER_THRI); + serial_port_out_sync(port, UART_IER, UART_IER_THRI); udelay(1); /* allow a working UART time to re-assert THRE */ iir = serial_port_in(port, UART_IIR); serial_port_out(port, UART_IER, 0); -- cgit v0.10.2 From 9abac8537c2cf435b251ca61e632d6a70a84077e Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Sun, 11 Mar 2012 15:02:38 +0100 Subject: tty: serial: vt8500: fix annotations for probe/remove Fixes: WARNING: drivers/tty/serial/built-in.o(.data+0x30): Section mismatch in reference from the variable vt8500_platform_driver to the function .init.text:vt8500_serial_probe() The variable vt8500_platform_driver references the function __init vt8500_serial_probe() And mark the remove pointer while we are here. Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/vt8500_serial.c b/drivers/tty/serial/vt8500_serial.c index 026cb9e..2be006f 100644 --- a/drivers/tty/serial/vt8500_serial.c +++ b/drivers/tty/serial/vt8500_serial.c @@ -544,7 +544,7 @@ static struct uart_driver vt8500_uart_driver = { .cons = VT8500_CONSOLE, }; -static int __init vt8500_serial_probe(struct platform_device *pdev) +static int __devinit vt8500_serial_probe(struct platform_device *pdev) { struct vt8500_port *vt8500_port; struct resource *mmres, *irqres; @@ -605,7 +605,7 @@ static int __devexit vt8500_serial_remove(struct platform_device *pdev) static struct platform_driver vt8500_platform_driver = { .probe = vt8500_serial_probe, - .remove = vt8500_serial_remove, + .remove = __devexit_p(vt8500_serial_remove), .driver = { .name = "vt8500_serial", .owner = THIS_MODULE, -- cgit v0.10.2 From 82896210aa3c59eaa4f78f7ba2f5f947601dd8f8 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Sat, 10 Mar 2012 11:59:23 +0300 Subject: vt: NULL dereference in vt_do_kdsk_ioctl() We forgot to set the "key_map" variable here, so it's still NULL. This was introduced recently in 079c9534a9 "vt:tackle kbd_table". Signed-off-by: Dan Carpenter Signed-off-by: Jiri Slaby Acked-by: Alan Cox Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/vt/keyboard.c b/drivers/tty/vt/keyboard.c index 70d0593..86dd1e3 100644 --- a/drivers/tty/vt/keyboard.c +++ b/drivers/tty/vt/keyboard.c @@ -1863,6 +1863,7 @@ int vt_do_kdsk_ioctl(int cmd, struct kbentry __user *user_kbe, int perm, return -EPERM; } key_maps[s] = new_map; + key_map = new_map; key_map[0] = U(K_ALLOCATED); for (j = 1; j < NR_KEYS; j++) key_map[j] = U(K_HOLE); -- cgit v0.10.2 From 60f4b002ab209525c2b818703291ac9a14890e17 Mon Sep 17 00:00:00 2001 From: Sonic Zhang Date: Tue, 13 Mar 2012 15:51:55 +0800 Subject: serial: bfin-uart: Don't access tty circular buffer in TX DMA interrupt after it is reset. When kernel reboot, tty circular buffer is reset before last TX DMA interrupt is called, while the buffer tail is updated in TX DMA interrupt handler. So, don't update the buffer tail if it is reset. Signed-off-by: Sonic Zhang Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/bfin_uart.c b/drivers/tty/serial/bfin_uart.c index 26953bf..5832fde 100644 --- a/drivers/tty/serial/bfin_uart.c +++ b/drivers/tty/serial/bfin_uart.c @@ -535,11 +535,13 @@ static irqreturn_t bfin_serial_dma_tx_int(int irq, void *dev_id) * when start a new tx. */ UART_CLEAR_IER(uart, ETBEI); - xmit->tail = (xmit->tail + uart->tx_count) & (UART_XMIT_SIZE - 1); uart->port.icount.tx += uart->tx_count; + if (!uart_circ_empty(xmit)) { + xmit->tail = (xmit->tail + uart->tx_count) & (UART_XMIT_SIZE - 1); - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(&uart->port); + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(&uart->port); + } bfin_serial_dma_tx_chars(uart); } -- cgit v0.10.2 From 9b96fbacda34079dea0638ee1e92c56286f6114a Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Tue, 13 Mar 2012 13:27:23 +0100 Subject: serial: PL011: clear pending interrupts Chanho Min reported that when the boot loader transfers control to the kernel, there may be pending interrupts causing the UART to lock up in an eternal loop trying to pick tokens from the FIFO (since the RX interrupt flag indicates there are tokens) while in practice there are no tokens - in fact there is only a pending IRQ flag. This patch address the issue with a combination of two patches suggested by Russell King that clears and mask all interrupts at probe() and clears any pending error and RX interrupts at port startup time. We suspect the spurious interrupts are a side-effect of switching the UART from FIFO to non-FIFO mode. Cc: Shreshtha Kumar Sahu Reported-by: Chanho Min Suggested-by: Russell King Signed-off-by: Linus Walleij Reviewed-by: Jong-Sung Kim Cc: stable Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c index cc3ea06..20d795d 100644 --- a/drivers/tty/serial/amba-pl011.c +++ b/drivers/tty/serial/amba-pl011.c @@ -1396,6 +1396,10 @@ static int pl011_startup(struct uart_port *port) uap->port.uartclk = clk_get_rate(uap->clk); + /* Clear pending error and receive interrupts */ + writew(UART011_OEIS | UART011_BEIS | UART011_PEIS | UART011_FEIS | + UART011_RTIS | UART011_RXIS, uap->port.membase + UART011_ICR); + /* * Allocate the IRQ */ @@ -1432,10 +1436,6 @@ static int pl011_startup(struct uart_port *port) cr |= UART01x_CR_UARTEN | UART011_CR_RXE | UART011_CR_TXE; writew(cr, uap->port.membase + UART011_CR); - /* Clear pending error interrupts */ - writew(UART011_OEIS | UART011_BEIS | UART011_PEIS | UART011_FEIS, - uap->port.membase + UART011_ICR); - /* * initialise the old status of the modem signals */ @@ -1450,6 +1450,9 @@ static int pl011_startup(struct uart_port *port) * as well. */ spin_lock_irq(&uap->port.lock); + /* Clear out any spuriously appearing RX interrupts */ + writew(UART011_RTIS | UART011_RXIS, + uap->port.membase + UART011_ICR); uap->im = UART011_RTIM; if (!pl011_dma_rx_running(uap)) uap->im |= UART011_RXIM; @@ -1942,6 +1945,10 @@ static int pl011_probe(struct amba_device *dev, const struct amba_id *id) goto unmap; } + /* Ensure interrupts from this UART are masked and cleared */ + writew(0, uap->port.membase + UART011_IMSC); + writew(0xffff, uap->port.membase + UART011_ICR); + uap->vendor = vendor; uap->lcrh_rx = vendor->lcrh_rx; uap->lcrh_tx = vendor->lcrh_tx; -- cgit v0.10.2 From 4a4c61b7ce26bfc9d49ea4bd121d52114bad9f99 Mon Sep 17 00:00:00 2001 From: Liz Clark Date: Thu, 15 Mar 2012 10:33:29 -0700 Subject: TTY: Wrong unicode value copied in con_set_unimap() Bugzilla 40012: PIO_UNIMAP bug: error updating Unicode-to-font map https://bugzilla.kernel.org/show_bug.cgi?id=40012 The unicode font map for the virtual console is a 32x32x64 table which allocates rows dynamically as entries are added. The unicode value increases sequentially and should count all entries even in empty rows. The defect is when copying the unicode font map in con_set_unimap(), the unicode value is not incremented properly. The wrong unicode value is entered in the new font map. Signed-off-by: Liz Clark Cc: stable Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/vt/consolemap.c b/drivers/tty/vt/consolemap.c index a0f3d6c..8308fc7 100644 --- a/drivers/tty/vt/consolemap.c +++ b/drivers/tty/vt/consolemap.c @@ -516,6 +516,7 @@ int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list) int err = 0, err1, i; struct uni_pagedir *p, *q; + /* Save original vc_unipagdir_loc in case we allocate a new one */ p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc; if (p->readonly) return -EIO; @@ -528,26 +529,57 @@ int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list) err1 = con_clear_unimap(vc, NULL); if (err1) return err1; + /* + * Since refcount was > 1, con_clear_unimap() allocated a + * a new uni_pagedir for this vc. Re: p != q + */ q = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc; - for (i = 0, l = 0; i < 32; i++) + + /* + * uni_pgdir is a 32*32*64 table with rows allocated + * when its first entry is added. The unicode value must + * still be incremented for empty rows. We are copying + * entries from "p" (old) to "q" (new). + */ + l = 0; /* unicode value */ + for (i = 0; i < 32; i++) if ((p1 = p->uni_pgdir[i])) for (j = 0; j < 32; j++) - if ((p2 = p1[j])) + if ((p2 = p1[j])) { for (k = 0; k < 64; k++, l++) if (p2[k] != 0xffff) { + /* + * Found one, copy entry for unicode + * l with fontpos value p2[k]. + */ err1 = con_insert_unipair(q, l, p2[k]); if (err1) { p->refcount++; *vc->vc_uni_pagedir_loc = (unsigned long)p; con_release_unimap(q); kfree(q); - return err1; + return err1; } - } - p = q; - } else if (p == dflt) + } + } else { + /* Account for row of 64 empty entries */ + l += 64; + } + else + /* Account for empty table */ + l += 32 * 64; + + /* + * Finished copying font table, set vc_uni_pagedir to new table + */ + p = q; + } else if (p == dflt) { dflt = NULL; - + } + + /* + * Insert user specified unicode pairs into new table. + */ while (ct--) { unsigned short unicode, fontpos; __get_user(unicode, &list->unicode); @@ -557,11 +589,14 @@ int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list) list++; } + /* + * Merge with fontmaps of any other virtual consoles. + */ if (con_unify_unimap(vc, p)) return err; for (i = 0; i <= 3; i++) - set_inverse_transl(vc, p, i); /* Update all inverse translations */ + set_inverse_transl(vc, p, i); /* Update inverse translations */ set_inverse_trans_unicode(vc, p); return err; -- cgit v0.10.2 From fb8ebec00b04f921ea1614a7303f1a8e5e9e47c5 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Thu, 15 Mar 2012 19:15:15 +0100 Subject: serial: pxa: add clk_prepare/clk_unprepare calls This patch adds clk_prepare/clk_unprepare calls to the serial/pxa driver by using the helper functions clk_prepare_enable and clk_disable_unprepare. Signed-off-by: Philipp Zabel Cc: Haojian Zhuang Cc: Eric Miao Cc: Alan Cox Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/pxa.c b/drivers/tty/serial/pxa.c index 5c8e3bb..e2fd3d8 100644 --- a/drivers/tty/serial/pxa.c +++ b/drivers/tty/serial/pxa.c @@ -579,9 +579,9 @@ serial_pxa_pm(struct uart_port *port, unsigned int state, struct uart_pxa_port *up = (struct uart_pxa_port *)port; if (!state) - clk_enable(up->clk); + clk_prepare_enable(up->clk); else - clk_disable(up->clk); + clk_disable_unprepare(up->clk); } static void serial_pxa_release_port(struct uart_port *port) @@ -668,7 +668,7 @@ serial_pxa_console_write(struct console *co, const char *s, unsigned int count) struct uart_pxa_port *up = serial_pxa_ports[co->index]; unsigned int ier; - clk_enable(up->clk); + clk_prepare_enable(up->clk); /* * First save the IER then disable the interrupts @@ -685,7 +685,7 @@ serial_pxa_console_write(struct console *co, const char *s, unsigned int count) wait_for_xmitr(up); serial_out(up, UART_IER, ier); - clk_disable(up->clk); + clk_disable_unprepare(up->clk); } static int __init -- cgit v0.10.2