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 --- include/linux/tty.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'include') diff --git a/include/linux/tty.h b/include/linux/tty.h index 5dbb3cb05a82..d3ebd765b548 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 v1.2.3-59-g8ed1b 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 --- fs/devpts/inode.c | 34 ++++++++++++++++++++++++++++++---- include/linux/tty.h | 1 + 2 files changed, 31 insertions(+), 4 deletions(-) (limited to 'include') diff --git a/fs/devpts/inode.c b/fs/devpts/inode.c index c2c7317d5687..1c6f908e38ca 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[] = { @@ -54,6 +55,14 @@ static struct ctl_table pty_table[] = { .proc_handler = proc_dointvec_minmax, .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), @@ -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 d3ebd765b548..d40774188203 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 v1.2.3-59-g8ed1b From 3afbd89c9639c344300dcdd7d4e5e18dda559fd4 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König 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 --- .../devicetree/bindings/tty/serial/efm32-uart.txt | 14 + drivers/tty/serial/Kconfig | 13 + drivers/tty/serial/Makefile | 1 + drivers/tty/serial/efm32-uart.c | 830 +++++++++++++++++++++ include/linux/platform_data/efm32-uart.h | 18 + include/linux/serial_core.h | 2 + 6 files changed, 878 insertions(+) create mode 100644 Documentation/devicetree/bindings/tty/serial/efm32-uart.txt create mode 100644 drivers/tty/serial/efm32-uart.c create mode 100644 include/linux/platform_data/efm32-uart.h (limited to 'include') 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 000000000000..6588b6950a7f --- /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 aca2386c5ef1..6e24a8f5fd2a 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 f5b01f2ce525..1997ad4a39a6 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 000000000000..615e46470491 --- /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 000000000000..ed0e975b3c54 --- /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 c91ace70c21d..585bfd03d2ee 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 v1.2.3-59-g8ed1b 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 --- drivers/tty/tty_io.c | 30 +++++++++++++++--------------- include/linux/tty.h | 2 ++ 2 files changed, 17 insertions(+), 15 deletions(-) (limited to 'include') diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index fbcc14063804..44736f9e61d7 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 d40774188203..a91ff403b3bf 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 v1.2.3-59-g8ed1b 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 --- drivers/tty/serial/altera_uart.c | 23 ----------------------- include/linux/altera_uart.h | 4 ---- 2 files changed, 27 deletions(-) (limited to 'include') diff --git a/drivers/tty/serial/altera_uart.c b/drivers/tty/serial/altera_uart.c index 1d04c5037f25..217833e94b5b 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 a10a90791976..c022c82db7ca 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 v1.2.3-59-g8ed1b 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 --- MAINTAINERS | 2 +- drivers/tty/serial/8250/8250.c | 7 +++---- drivers/tty/serial/suncore.c | 2 +- drivers/tty/serial/suncore.h | 33 --------------------------------- drivers/tty/serial/sunhv.c | 3 +-- drivers/tty/serial/sunsab.c | 2 +- drivers/tty/serial/sunsu.c | 3 +-- drivers/tty/serial/sunzilog.c | 2 +- include/linux/sunserialcore.h | 33 +++++++++++++++++++++++++++++++++ 9 files changed, 42 insertions(+), 45 deletions(-) delete mode 100644 drivers/tty/serial/suncore.h create mode 100644 include/linux/sunserialcore.h (limited to 'include') diff --git a/MAINTAINERS b/MAINTAINERS index 9a648eb8e213..27c052cc8835 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 b423d0f962a2..917ab8452746 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 6381a0282ee7..6e4ac8db2d79 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 db2057936c31..000000000000 --- 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 c0b7246d7339..3ba5d285c2d0 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 b5fa2a57b9da..62dacd0ba526 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 ad0f8f5f6ea1..d3ca6da129fe 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 5a47d1b196d8..da4415842a43 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 000000000000..68e7430bb0fe --- /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 v1.2.3-59-g8ed1b 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 --- drivers/tty/vt/keyboard.c | 162 ++++++++++++++++++++++++++++++++++++++++++++++ drivers/tty/vt/vt_ioctl.c | 81 +---------------------- include/linux/vt_kern.h | 3 + 3 files changed, 168 insertions(+), 78 deletions(-) (limited to 'include') diff --git a/drivers/tty/vt/keyboard.c b/drivers/tty/vt/keyboard.c index a605549ee28f..bdf838dd3e44 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 65447c5f91d7..80af0f9bef5b 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 c2164fad0083..5d8726ad5729 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 v1.2.3-59-g8ed1b 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 --- drivers/accessibility/braille/braille_console.c | 9 +- drivers/staging/speakup/main.c | 8 +- drivers/tty/sysrq.c | 6 +- drivers/tty/vt/keyboard.c | 621 +++++++++++++++++++++++- drivers/tty/vt/selection.c | 9 +- drivers/tty/vt/vt.c | 27 +- drivers/tty/vt/vt_ioctl.c | 325 +------------ include/linux/kbd_kern.h | 7 +- include/linux/keyboard.h | 2 - include/linux/vt_kern.h | 23 + 10 files changed, 660 insertions(+), 377 deletions(-) (limited to 'include') diff --git a/drivers/accessibility/braille/braille_console.c b/drivers/accessibility/braille/braille_console.c index c339a0880e6e..d21167bfc865 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 c7b03f0ef2dd..92b34e29ad06 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 8db9125133b8..ecb8e2203ac8 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 898e359c5424..70d0593d3bc6 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 7a0a12ae5458..738e45a35131 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 e716839fab6e..ecdcc8a8f0ca 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 80af0f9bef5b..28ca0aa8664f 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 ec2d17bc1f1e..daf4a3a40ee0 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 33a63f62d57f..86e5214ae735 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 5d8726ad5729..e33d77f15bda 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 v1.2.3-59-g8ed1b 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 --- drivers/tty/tty_io.c | 5 +++-- include/linux/tty_driver.h | 5 ++++- 2 files changed, 7 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index f105ce5c8e6e..bd95cea3173b 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 5cf685086dd3..6e65493a5e6c 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 v1.2.3-59-g8ed1b 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 --- drivers/misc/pti.c | 1 - include/linux/tty_driver.h | 1 - 2 files changed, 2 deletions(-) (limited to 'include') diff --git a/drivers/misc/pti.c b/drivers/misc/pti.c index 471ff4c85cd8..9a35db3d27fc 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 6e65493a5e6c..e064f1704e20 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 v1.2.3-59-g8ed1b 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 --- include/linux/serial.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/include/linux/serial.h b/include/linux/serial.h index 3d86517fe7d5..441980ecc4e5 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 v1.2.3-59-g8ed1b 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 --- include/linux/tty_driver.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'include') diff --git a/include/linux/tty_driver.h b/include/linux/tty_driver.h index e064f1704e20..6e6dbb7447b6 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 v1.2.3-59-g8ed1b 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 --- include/linux/serialP.h | 6 ------ 1 file changed, 6 deletions(-) (limited to 'include') diff --git a/include/linux/serialP.h b/include/linux/serialP.h index e811a615f696..ec27b34bbbd6 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 v1.2.3-59-g8ed1b 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 --- arch/ia64/hp/sim/simserial.c | 10 +------- drivers/tty/amiserial.c | 6 ----- include/linux/serialP.h | 59 -------------------------------------------- 3 files changed, 1 insertion(+), 74 deletions(-) (limited to 'include') diff --git a/arch/ia64/hp/sim/simserial.c b/arch/ia64/hp/sim/simserial.c index 2a2fe0c56119..9890b58960a7 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 753286257554..c6d8913dd6f6 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 ec27b34bbbd6..c1acdb2c8584 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 v1.2.3-59-g8ed1b 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 --- arch/ia64/hp/sim/simserial.c | 2 -- drivers/tty/amiserial.c | 42 ++---------------------------------------- include/linux/serialP.h | 8 -------- 3 files changed, 2 insertions(+), 50 deletions(-) (limited to 'include') diff --git a/arch/ia64/hp/sim/simserial.c b/arch/ia64/hp/sim/simserial.c index 9890b58960a7..0d324e85379e 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 c6d8913dd6f6..d5fac8626988 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 { @@ -506,29 +495,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 @@ -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 c1acdb2c8584..beaf39f819d6 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 v1.2.3-59-g8ed1b 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 --- arch/ia64/hp/sim/simserial.c | 48 +++++++++++++++++++++----------------------- include/linux/serialP.h | 1 - 2 files changed, 23 insertions(+), 26 deletions(-) (limited to 'include') diff --git a/arch/ia64/hp/sim/simserial.c b/arch/ia64/hp/sim/simserial.c index 8f68972b015f..a08a53f033b4 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 beaf39f819d6..6741f57cc2ae 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 v1.2.3-59-g8ed1b 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 --- arch/ia64/hp/sim/simserial.c | 9 +++------ drivers/tty/amiserial.c | 19 ++++++++----------- include/linux/serialP.h | 5 ----- 3 files changed, 11 insertions(+), 22 deletions(-) (limited to 'include') diff --git a/arch/ia64/hp/sim/simserial.c b/arch/ia64/hp/sim/simserial.c index a08a53f033b4..d32b759b23f1 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 8556ca022dbc..5540216e64fd 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 6741f57cc2ae..6ce488c46589 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 v1.2.3-59-g8ed1b 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 --- arch/ia64/hp/sim/simserial.c | 64 +++++--------------------------------------- include/linux/serialP.h | 2 -- 2 files changed, 7 insertions(+), 59 deletions(-) (limited to 'include') diff --git a/arch/ia64/hp/sim/simserial.c b/arch/ia64/hp/sim/simserial.c index d32b759b23f1..c35552df035e 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 6ce488c46589..b8543f902453 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 v1.2.3-59-g8ed1b 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 --- arch/ia64/hp/sim/simserial.c | 160 +++++++++-------------- drivers/tty/amiserial.c | 301 +++++++++++++++++-------------------------- include/linux/serialP.h | 14 +- 3 files changed, 191 insertions(+), 284 deletions(-) (limited to 'include') diff --git a/arch/ia64/hp/sim/simserial.c b/arch/ia64/hp/sim/simserial.c index 8b5a1342e119..7b6e60e9167b 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 7607c6ebd39a..410e8e7e6bfe 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 b8543f902453..984f5ba8da4e 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 v1.2.3-59-g8ed1b 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 --- arch/ia64/hp/sim/simserial.c | 24 ++++++++--------- drivers/tty/amiserial.c | 63 ++++++++++++++++++++++---------------------- include/linux/serialP.h | 7 ++--- 3 files changed, 45 insertions(+), 49 deletions(-) (limited to 'include') diff --git a/arch/ia64/hp/sim/simserial.c b/arch/ia64/hp/sim/simserial.c index a76a27ed3de0..614c091b203f 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 5b87744748d5..71d3331d6e84 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 984f5ba8da4e..32d45b869cbc 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 v1.2.3-59-g8ed1b 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 --- arch/ia64/hp/sim/simserial.c | 5 +++-- drivers/tty/amiserial.c | 20 +++++++++----------- include/linux/serialP.h | 2 -- 3 files changed, 12 insertions(+), 15 deletions(-) (limited to 'include') diff --git a/arch/ia64/hp/sim/simserial.c b/arch/ia64/hp/sim/simserial.c index 614c091b203f..fb324b345e88 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 71d3331d6e84..06e3a0990c8b 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 32d45b869cbc..997edd008b92 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 v1.2.3-59-g8ed1b 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 --- arch/ia64/hp/sim/simserial.c | 24 ++++++++++++------------ drivers/tty/amiserial.c | 34 +++++++++++++++++----------------- include/linux/serialP.h | 1 - 3 files changed, 29 insertions(+), 30 deletions(-) (limited to 'include') diff --git a/arch/ia64/hp/sim/simserial.c b/arch/ia64/hp/sim/simserial.c index fb324b345e88..baa2b1ec00a0 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 06e3a0990c8b..8ad64a0f1251 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 997edd008b92..a6612b9c7e84 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 v1.2.3-59-g8ed1b 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 --- arch/ia64/hp/sim/simserial.c | 33 +++++------ drivers/tty/amiserial.c | 129 ++++++++++++++++++++++--------------------- include/linux/serialP.h | 1 - 3 files changed, 83 insertions(+), 80 deletions(-) (limited to 'include') diff --git a/arch/ia64/hp/sim/simserial.c b/arch/ia64/hp/sim/simserial.c index baa2b1ec00a0..c65c49d31e7f 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 8ad64a0f1251..7d798262d0c2 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 a6612b9c7e84..e5e8442c08d6 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 v1.2.3-59-g8ed1b 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 --- arch/ia64/hp/sim/simserial.c | 9 ++++++++- include/linux/serialP.h | 2 -- 2 files changed, 8 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/arch/ia64/hp/sim/simserial.c b/arch/ia64/hp/sim/simserial.c index 3698a2fe221d..120aad4d5362 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 e5e8442c08d6..9a04dec1589a 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 v1.2.3-59-g8ed1b 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 --- drivers/tty/amiserial.c | 23 ++++++++++------------- include/linux/serialP.h | 3 --- 2 files changed, 10 insertions(+), 16 deletions(-) (limited to 'include') diff --git a/drivers/tty/amiserial.c b/drivers/tty/amiserial.c index a9f5da64eef2..b182bccf3eab 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 9a04dec1589a..77afbdb134ae 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 v1.2.3-59-g8ed1b 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 --- drivers/tty/amiserial.c | 20 +++++++++++++++++++- include/linux/serialP.h | 49 ------------------------------------------------- 2 files changed, 19 insertions(+), 50 deletions(-) delete mode 100644 include/linux/serialP.h (limited to 'include') diff --git a/drivers/tty/amiserial.c b/drivers/tty/amiserial.c index b182bccf3eab..613d6a3908d3 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 77afbdb134ae..000000000000 --- 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 v1.2.3-59-g8ed1b 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 --- include/linux/serial_core.h | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'include') diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h index 585bfd03d2ee..f51bf2e70c69 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 v1.2.3-59-g8ed1b