diff options
| author | Greg Kroah-Hartman <gregkh@suse.de> | 2009-07-31 21:31:30 -0700 |
|---|---|---|
| committer | Greg Kroah-Hartman <gregkh@suse.de> | 2009-07-31 21:31:30 -0700 |
| commit | 288dff4528481dae00119111ac38ba4dfee2cb03 (patch) | |
| tree | 6dd4614e328555f68a1ae9ecf167f17cb09c85f1 /tty.work | |
| parent | 2f6934c1a5b93267d2793111f6565a69a5bbb514 (diff) | |
| download | patches-288dff4528481dae00119111ac38ba4dfee2cb03.tar.gz | |
add tty and serial patches to queue
Diffstat (limited to 'tty.work')
| -rw-r--r-- | tty.work/serial-core-port-wait | 230 | ||||
| -rw-r--r-- | tty.work/serial-extract-portops | 99 | ||||
| -rw-r--r-- | tty.work/serial-f81216-helper | 365 | ||||
| -rw-r--r-- | tty.work/serial-use-port-hangup | 37 | ||||
| -rw-r--r-- | tty.work/serial-use-tty-close | 102 | ||||
| -rw-r--r-- | tty.work/tty-usb-cleanup-open | 211 |
6 files changed, 1044 insertions, 0 deletions
diff --git a/tty.work/serial-core-port-wait b/tty.work/serial-core-port-wait new file mode 100644 index 00000000000000..99813a98358ac7 --- /dev/null +++ b/tty.work/serial-core-port-wait @@ -0,0 +1,230 @@ +serial_core: use the tty_port wait_until_ready + +From: Alan Cox <alan@linux.intel.com> + +This subtly changes the locking. Our count and other fields become locked +by the tty_port (which is the correct behaviour). + +The mutex behaviour on open that serial had is actually very useful so we +propogate that into the tty_port core code. + +Signed-off-by: Alan Cox <alan@linux.intel.com> +--- + + drivers/char/tty_port.c | 41 ++++++++++++++++++- + drivers/serial/serial_core.c | 91 ++---------------------------------------- + include/linux/tty.h | 2 + + 3 files changed, 45 insertions(+), 89 deletions(-) + + +diff --git a/drivers/char/tty_port.c b/drivers/char/tty_port.c +index 0293d25..61b09bd 100644 +--- a/drivers/char/tty_port.c ++++ b/drivers/char/tty_port.c +@@ -180,7 +180,7 @@ void tty_port_lower_dtr_rts(struct tty_port *port) + EXPORT_SYMBOL(tty_port_lower_dtr_rts); + + /** +- * tty_port_block_til_ready - Waiting logic for tty open ++ * __tty_port_block_til_ready - Waiting logic for tty open + * @port: the tty port being opened + * @tty: the tty device being bound + * @filp: the file pointer of the opener +@@ -197,9 +197,12 @@ EXPORT_SYMBOL(tty_port_lower_dtr_rts); + * do carrier detect and the dtr_rts method if it supports software + * management of these lines. Note that the dtr/rts raise is done each + * iteration as a hangup may have previously dropped them while we wait. ++ * ++ * Called with the port mutex held. See tty_port_block_til_ready for ++ * normal uses. + */ + +-int tty_port_block_til_ready(struct tty_port *port, ++int __tty_port_block_til_ready(struct tty_port *port, + struct tty_struct *tty, struct file *filp) + { + int do_clocal = 0, retval; +@@ -265,7 +268,9 @@ int tty_port_block_til_ready(struct tty_port *port, + retval = -ERESTARTSYS; + break; + } ++ mutex_unlock(&port->mutex); + schedule(); ++ mutex_lock(&port->mutex); + } + finish_wait(&port->open_wait, &wait); + +@@ -281,6 +286,38 @@ int tty_port_block_til_ready(struct tty_port *port, + return retval; + + } ++EXPORT_SYMBOL(__tty_port_block_til_ready); ++ ++/** ++ * tty_port_block_til_ready - Waiting logic for tty open ++ * @port: the tty port being opened ++ * @tty: the tty device being bound ++ * @filp: the file pointer of the opener ++ * ++ * Implement the core POSIX/SuS tty behaviour when opening a tty device. ++ * Handles: ++ * - hangup (both before and during) ++ * - non blocking open ++ * - rts/dtr/dcd ++ * - signals ++ * - port flags and counts ++ * ++ * The passed tty_port must implement the carrier_raised method if it can ++ * do carrier detect and the dtr_rts method if it supports software ++ * management of these lines. Note that the dtr/rts raise is done each ++ * iteration as a hangup may have previously dropped them while we wait. ++ */ ++ ++int tty_port_block_til_ready(struct tty_port *port, ++ struct tty_struct *tty, struct file *filp) ++{ ++ int retval; ++ mutex_lock(&port->mutex); ++ retval = __tty_port_block_til_ready(port, tty, filp); ++ mutex_unlock(&port->mutex); ++ return retval; ++} ++ + EXPORT_SYMBOL(tty_port_block_til_ready); + + int tty_port_close_start(struct tty_port *port, struct tty_struct *tty, struct file *filp) +diff --git a/drivers/serial/serial_core.c b/drivers/serial/serial_core.c +index 6d2290d..b1d4b91 100644 +--- a/drivers/serial/serial_core.c ++++ b/drivers/serial/serial_core.c +@@ -1452,86 +1452,6 @@ static int uart_carrier_raised(struct tty_port *port) + return 0; + } + +-/* +- * Block the open until the port is ready. We must be called with +- * the per-port semaphore held. +- */ +-static int +-uart_block_til_ready(struct file *filp, struct uart_state *state) +-{ +- DECLARE_WAITQUEUE(wait, current); +- struct tty_port *port = &state->port; +- +- port->blocked_open++; +- port->count--; +- +- add_wait_queue(&port->open_wait, &wait); +- while (1) { +- set_current_state(TASK_INTERRUPTIBLE); +- +- /* +- * If we have been hung up, tell userspace/restart open. +- */ +- if (tty_hung_up_p(filp) || port->tty == NULL) +- break; +- +- /* +- * If the port has been closed, tell userspace/restart open. +- */ +- if (!(port->flags & ASYNC_INITIALIZED)) +- break; +- +- /* +- * If non-blocking mode is set, or CLOCAL mode is set, +- * we don't want to wait for the modem status lines to +- * indicate that the port is ready. +- * +- * Also, if the port is not enabled/configured, we want +- * to allow the open to succeed here. Note that we will +- * have set TTY_IO_ERROR for a non-existant port. +- */ +- if ((filp->f_flags & O_NONBLOCK) || +- (port->tty->termios->c_cflag & CLOCAL) || +- (port->tty->flags & (1 << TTY_IO_ERROR))) +- break; +- +- /* +- * Set DTR to allow modem to know we're waiting. Do +- * not set RTS here - we want to make sure we catch +- * the data from the modem. +- */ +- if (port->tty->termios->c_cflag & CBAUD) +- tty_port_raise_dtr_rts(port); +- +- /* +- * and wait for the carrier to indicate that the +- * modem is ready for us. +- */ +- +- if (tty_port_carrier_raised(port)) +- break; +- +- mutex_unlock(&port->mutex); +- schedule(); +- mutex_lock(&port->mutex); +- +- if (signal_pending(current)) +- break; +- } +- set_current_state(TASK_RUNNING); +- remove_wait_queue(&port->open_wait, &wait); +- +- port->count++; +- port->blocked_open--; +- +- if (signal_pending(current)) +- return -ERESTARTSYS; +- +- if (!port->tty || tty_hung_up_p(filp)) +- return -EAGAIN; +- +- return 0; +-} + + static struct uart_state *uart_get(struct uart_driver *drv, int line) + { +@@ -1590,7 +1510,7 @@ static int uart_open(struct tty_struct *tty, struct file *filp) + goto fail; + + /* +- * We take the semaphore inside uart_get to guarantee that we won't ++ * We take the mutex inside uart_get to guarantee that we won't + * be re-entered while allocating the state structure, or while we + * request any IRQs that the driver may need. This also has the nice + * side-effect that it delays the action of uart_hangup, so we can +@@ -1640,18 +1560,15 @@ static int uart_open(struct tty_struct *tty, struct file *filp) + * If we succeeded, wait until the port is ready. + */ + if (retval == 0) +- retval = uart_block_til_ready(filp, state); ++ retval = tty_port_block_til_ready(port, tty, filp); + mutex_unlock(&port->mutex); + + /* + * If this is the first open to succeed, adjust things to suit. + */ +- if (retval == 0 && !(port->flags & ASYNC_NORMAL_ACTIVE)) { +- set_bit(ASYNCB_NORMAL_ACTIVE, &port->flags); +- ++ if (retval == 0 && ++ !test_and_set_bit(ASYNCB_NORMAL_ACTIVE, &port->flags)) + uart_update_termios(state); +- } +- + fail: + return retval; + } +diff --git a/include/linux/tty.h b/include/linux/tty.h +index 65a7549..7163493 100644 +--- a/include/linux/tty.h ++++ b/include/linux/tty.h +@@ -458,6 +458,8 @@ extern int tty_port_carrier_raised(struct tty_port *port); + extern void tty_port_raise_dtr_rts(struct tty_port *port); + extern void tty_port_lower_dtr_rts(struct tty_port *port); + extern void tty_port_hangup(struct tty_port *port); ++extern int __tty_port_block_til_ready(struct tty_port *port, ++ struct tty_struct *tty, struct file *filp); + extern int tty_port_block_til_ready(struct tty_port *port, + struct tty_struct *tty, struct file *filp); + extern int tty_port_close_start(struct tty_port *port, diff --git a/tty.work/serial-extract-portops b/tty.work/serial-extract-portops new file mode 100644 index 00000000000000..24e0f589bddc17 --- /dev/null +++ b/tty.work/serial-extract-portops @@ -0,0 +1,99 @@ +serial: extract carrier operations + +From: Alan Cox <alan@linux.intel.com> + +The switch to using the tty port helpers needs some functions separated out +and provided as tty port helpers. Do the split but don't yet switch to the +tty_port logic so that we can bisect bugs better + +Signed-off-by; Alan Cox <alan@linux.intel.com> +--- + + drivers/serial/serial_core.c | 39 +++++++++++++++++++++++++++++++-------- + 1 files changed, 31 insertions(+), 8 deletions(-) + + +diff --git a/drivers/serial/serial_core.c b/drivers/serial/serial_core.c +index 2514d00..285c051 100644 +--- a/drivers/serial/serial_core.c ++++ b/drivers/serial/serial_core.c +@@ -1473,6 +1473,28 @@ static void uart_update_termios(struct uart_state *state) + } + } + ++static void uart_raise_dtr_rts(struct tty_port *port, int up) ++{ ++ struct uart_state *state = container_of(port, struct uart_state, port); ++ struct uart_port *uport = state->uart_port; ++ uart_set_mctrl(uport, up ? TIOCM_DTR : 0); ++} ++ ++static int uart_carrier_raised(struct tty_port *port) ++{ ++ struct uart_state *state = container_of(port, struct uart_state, port); ++ struct uart_port *uport = state->uart_port; ++ unsigned int mctrl; ++ ++ spin_lock_irq(&uport->lock); ++ uport->ops->enable_ms(uport); ++ mctrl = uport->ops->get_mctrl(uport); ++ spin_unlock_irq(&uport->lock); ++ if (mctrl & TIOCM_CAR) ++ return 1; ++ return 0; ++} ++ + /* + * Block the open until the port is ready. We must be called with + * the per-port semaphore held. +@@ -1481,9 +1503,7 @@ static int + uart_block_til_ready(struct file *filp, struct uart_state *state) + { + DECLARE_WAITQUEUE(wait, current); +- struct uart_port *uport = state->uart_port; + struct tty_port *port = &state->port; +- unsigned int mctrl; + + port->blocked_open++; + port->count--; +@@ -1524,17 +1544,14 @@ uart_block_til_ready(struct file *filp, struct uart_state *state) + * the data from the modem. + */ + if (port->tty->termios->c_cflag & CBAUD) +- uart_set_mctrl(uport, TIOCM_DTR); ++ tty_port_raise_dtr_rts(port); + + /* + * and wait for the carrier to indicate that the + * modem is ready for us. + */ +- spin_lock_irq(&uport->lock); +- uport->ops->enable_ms(uport); +- mctrl = uport->ops->get_mctrl(uport); +- spin_unlock_irq(&uport->lock); +- if (mctrl & TIOCM_CAR) ++ ++ if (tty_port_carrier_raised(port)) + break; + + mutex_unlock(&port->mutex); +@@ -2326,6 +2343,11 @@ static const struct tty_operations uart_ops = { + #endif + }; + ++static const struct tty_port_operations uart_port_ops = { ++ .carrier_raised = uart_carrier_raised, ++ .dtr_rts = uart_raise_dtr_rts, ++}; ++ + /** + * uart_register_driver - register a driver with the uart core layer + * @drv: low level driver structure +@@ -2383,6 +2405,7 @@ int uart_register_driver(struct uart_driver *drv) + struct tty_port *port = &state->port; + + tty_port_init(port); ++ port->ops = &uart_port_ops; + port->close_delay = 500; /* .5 seconds */ + port->closing_wait = 30000; /* 30 seconds */ + tasklet_init(&state->tlet, uart_tasklet_action, diff --git a/tty.work/serial-f81216-helper b/tty.work/serial-f81216-helper new file mode 100644 index 00000000000000..f9179852abd761 --- /dev/null +++ b/tty.work/serial-f81216-helper @@ -0,0 +1,365 @@ +serial: Add a helper driver for the F81216 + +From: Bruno <bonbons67@internet.lu> + +This is a helper driver to restore the F81216 SuperIO hardware on systems +where the BIOS gets it wrong. + +See http://bugzilla.kernel.org/attachment.cgi?id=21784 + +[Added region request/handling alan@linux.intel.com] + +Signed-off-by: Alan Cox <alan@linux.intel.com> +--- + + drivers/serial/8250_f81216.c | 311 +++++++++++++++++++++++++++++++++++++++++++ + drivers/serial/Kconfig | 11 + + drivers/serial/Makefile | 1 + 3 files changed, 323 insertions(+) + create mode 100644 drivers/serial/8250_f81216.c + + +--- /dev/null ++++ b/drivers/serial/8250_f81216.c +@@ -0,0 +1,311 @@ ++/* ++ * linux/drivers/serial/8250_f81216.c ++ * ++ * Copyright (C) 2009 Bruno Prémont <bonbons@linux-vserver.org>. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++#include <linux/module.h> ++#include <linux/init.h> ++#include <linux/serial_8250.h> ++#include <linux/platform_device.h> ++#include <asm/io.h> ++ ++static int io_base = 0x4e; ++static int config_key = 0x77; ++ ++struct f81216_uart_state { ++ __u16 io_port; ++ __u8 enabled; ++ __u8 irq_channel; ++ __u8 clk_select; ++}; ++struct f81216_state { ++ __u8 clk_source; ++ struct f81216_uart_state uart[4]; ++}; ++ ++static struct platform_device *f81216_device; ++ ++#define LDN 0x07 /* Register: Logical device select */ ++#define DEVICE_ID 0x20 /* Register: Device ID (2 bytes) */ ++#define VENDOR_ID 0x23 /* Register: Vendor ID (2 bytes) */ ++#define CLK_SRC 0x25 /* Register: Clock source select */ ++#define LDN_ENABLE 0x30 /* Register: Device enable */ ++#define LDN_IOPORT 0x60 /* Register: I/O Port select (2 bytes) */ ++#define LDN_IRQCHAN 0x70 /* Register: IRQ Channel select */ ++#define LDN_CLK 0xf0 /* Register: Clock select */ ++ ++#define F81216_DEVICE_ID 0x0208 ++#define F81216_VENDOR_ID 0x1934 ++ ++static int superio_inb(int reg) ++{ ++ outb(reg, io_base); ++ return inb(io_base+1); ++} ++ ++static int superio_inw(int reg) ++{ ++ int val; ++ outb(reg++, io_base); ++ val = inb(io_base+1) << 8; ++ outb(reg, io_base); ++ val |= inb(io_base+1); ++ return val; ++} ++ ++static void superio_outb(int val, int reg) ++{ ++ outb(reg, io_base); ++ outb(val, io_base+1); ++} ++ ++static void superio_outw(int val, int reg) ++{ ++ outb(reg++, io_base); ++ outb((val >> 8) & 0xff, io_base+1); ++ outb(reg, io_base); ++ outb(val & 0xff, io_base+1); ++} ++ ++static void superio_enter(void) ++{ ++ outb(config_key, io_base); ++ outb(config_key, io_base); ++} ++ ++static void superio_exit(void) ++{ ++ outb(0xaa, io_base); ++} ++ ++static int f81216_suspend(struct platform_device *dev, pm_message_t state) ++{ ++ struct f81216_state *data = platform_get_drvdata(dev); ++ int i; ++ ++ if (!data) ++ return -ENOMEM; ++ ++ superio_enter(); ++ data->clk_source = superio_inb(CLK_SRC); ++ dev_printk(KERN_DEBUG, &dev->dev, "Chip status: clk=%x\n", ++ data->clk_source); ++ for (i = 0; i < 4; i++) { ++ superio_outb(i, LDN); ++ data->uart[i].enabled = superio_inb(LDN_ENABLE); ++ data->uart[i].io_port = superio_inw(LDN_IOPORT); ++ data->uart[i].irq_channel = superio_inb(LDN_IRQCHAN); ++ data->uart[i].clk_select = superio_inb(LDN_CLK); ++ dev_printk(KERN_DEBUG, &dev->dev, "UART %d status: ioport=%x," ++ " irqchan=%x, clk=%x, enable=%x\n", i, ++ data->uart[i].io_port, ++ data->uart[i].irq_channel, ++ data->uart[i].clk_select, ++ data->uart[i].enabled); ++ } ++ superio_exit(); ++ return 0; ++} ++ ++static int f81216_suspend_late(struct platform_device *dev, pm_message_t state) ++{ ++ int i; ++ ++ superio_enter(); ++ dev_printk(KERN_DEBUG, &dev->dev, "Chip status: clk=%x\n", ++ superio_inb(CLK_SRC)); ++ for (i = 0; i < 4; i++) { ++ superio_outb(i, LDN); ++ dev_printk(KERN_DEBUG, &dev->dev, "UART %d status: ioport=%x," ++ " irqchan=%x, clk=%x, enable=%x\n", i, ++ superio_inw(LDN_IOPORT), ++ superio_inb(LDN_IRQCHAN), ++ superio_inb(LDN_CLK), ++ superio_inb(LDN_ENABLE)); ++ } ++ superio_exit(); ++ return 0; ++} ++ ++static void f81216_restoreb(struct platform_device *dev, int ldn, int offset, ++ int value) ++{ ++ int v = superio_inb(offset); ++ if (v == value) ++ return; ++ ++ if (ldn >= 0) ++ dev_printk(KERN_DEBUG, &dev->dev, "restoring device %d config " ++ "at offset %x (was %x, writing %x)\n", ++ ldn, offset, v, value); ++ else ++ dev_printk(KERN_DEBUG, &dev->dev, "restoring global config " ++ "at offset %x (was %x, writing %x)\n", ++ offset, v, value); ++ superio_outb(value, offset); ++} ++ ++static void f81216_restorew(struct platform_device *dev, int ldn, int offset, ++ int value) ++{ ++ int v = superio_inw(offset); ++ if (v == value) ++ return; ++ ++ if (ldn >= 0) ++ dev_printk(KERN_DEBUG, &dev->dev, "restoring device %d config " ++ "at offset %x (was %x, writing %x)\n", ++ ldn, offset, v, value); ++ else ++ dev_printk(KERN_DEBUG, &dev->dev, "restoring global config " ++ "at offset %x (was %x, writing %x)\n", ++ offset, v, value); ++ superio_outw(value, offset); ++} ++ ++static int f81216_resume_early(struct platform_device *dev) ++{ ++ int i; ++ ++ superio_enter(); ++ dev_printk(KERN_DEBUG, &dev->dev, "Chip status: clk=%x\n", ++ superio_inb(CLK_SRC)); ++ for (i = 0; i < 4; i++) { ++ superio_outb(i, LDN); ++ dev_printk(KERN_DEBUG, &dev->dev, "UART %d status: ioport=%x," ++ " irqchan=%x, clk=%x, enable=%x\n", i, ++ superio_inw(LDN_IOPORT), ++ superio_inb(LDN_IRQCHAN), ++ superio_inb(LDN_CLK), ++ superio_inb(LDN_ENABLE)); ++ } ++ superio_exit(); ++ return 0; ++} ++ ++static int f81216_resume(struct platform_device *dev) ++{ ++ struct f81216_state *data = platform_get_drvdata(dev); ++ int i; ++ ++ superio_enter(); ++ f81216_restoreb(dev, -1, CLK_SRC, data->clk_source); ++ for (i = 0; i < 4; i++) { ++ superio_outb(i, LDN); ++ f81216_restoreb(dev, i, LDN_CLK, data->uart[i].clk_select); ++ f81216_restorew(dev, i, LDN_IOPORT, data->uart[i].io_port); ++ f81216_restoreb(dev, i, LDN_IRQCHAN, data->uart[i].irq_channel); ++ f81216_restoreb(dev, i, LDN_ENABLE, data->uart[i].enabled); ++ } ++ superio_exit(); ++ return 0; ++} ++ ++static struct platform_driver f81216_driver = { ++ .suspend = f81216_suspend, ++ .suspend_late = f81216_suspend_late, ++ .resume_early = f81216_resume_early, ++ .resume = f81216_resume, ++ .driver = { ++ .name = "f81216", ++ .owner = THIS_MODULE, ++ } ++}; ++ ++static int __init f81216_init(void) ++{ ++ int port, i, ret; ++ struct resource res = { ++ .start = io_base, ++ .end = io_base + 0x01, ++ .name = "f81216", ++ .flags = IORESOURCE_IO ++ }; ++ ++ if (io_base != 0x2e && io_base != 0x4e) ++ return EINVAL; ++ if (config_key != 0x77 && config_key != 0xa0 && config_key != 0x87 && ++ config_key != 0x67) ++ return EINVAL; ++ if (request_region(io_base, 2, "f81216 probe") == 0) ++ return -EBUSY; ++ /* determine existance of Fintek 81216 chip */ ++ superio_enter(); ++ if (superio_inw(DEVICE_ID) != F81216_DEVICE_ID) ++ goto out; ++ if (superio_inw(VENDOR_ID) != F81216_VENDOR_ID) ++ goto out; ++ ++ /* count enabled ports - to be extended to register our UARTs */ ++ for (i = port = 0; i < 4; i++) { ++ superio_outb(i, LDN); ++ if (superio_inb(LDN_ENABLE) == 0x01) ++ port++; ++ } ++ superio_exit(); ++ release_region(io_base, 2); ++ ++ printk(KERN_INFO "f81216: Found chip with %d UART ports enabled\n", ++ port); ++ ++ ret = platform_driver_register(&f81216_driver); ++ if (ret) ++ return ret; ++ ++ f81216_device = platform_device_alloc("f81216", -1); ++ if (f81216_device) { ++ platform_set_drvdata(f81216_device, kzalloc(sizeof(struct f81216_state), GFP_KERNEL)); ++ if (!platform_get_drvdata(f81216_device)) ++ ret = -ENOMEM; ++ } else ++ ret = -ENOMEM; ++ if (ret) ++ goto fail_platform_device_alloc; ++ ++ ret = platform_device_add_resources(f81216_device, &res, 1); ++ if (ret) ++ goto fail_platform_device_add; ++ ++ ret = platform_device_add(f81216_device); ++ if (ret) ++ goto fail_platform_device_add; ++ ++ return 0; ++ ++fail_platform_device_add: ++ platform_device_put(f81216_device); ++ ++fail_platform_device_alloc: ++ platform_driver_unregister(&f81216_driver); ++ return ret; ++ ++out: ++ superio_exit(); ++ release_region(io_base, 2); ++ return -ENODEV; ++} ++ ++static void __exit f81216_exit(void) ++{ ++ platform_device_unregister(f81216_device); ++ platform_driver_unregister(&f81216_driver); ++} ++ ++module_init(f81216_init); ++module_exit(f81216_exit); ++ ++module_param(io_base, uint, 0444); ++MODULE_PARM_DESC(io_base, "Configuration IO port [0x4e (default) or 0x2e]"); ++ ++module_param(config_key, uint, 0444); ++MODULE_PARM_DESC(config_key, "Configuration entry key [0x77 (default), " ++ "0xa0, 0x87 or 0x67]"); ++ ++MODULE_AUTHOR("Bruno Prémont"); ++MODULE_DESCRIPTION("8250 serial probe module for F81216 based ports" ++ " (e.g. IEI Kino 690S1)"); ++MODULE_LICENSE("GPL"); +--- a/drivers/serial/Kconfig ++++ b/drivers/serial/Kconfig +@@ -266,6 +266,17 @@ config SERIAL_8250_AU1X00 + say Y to this option. The driver can handle up to 4 serial ports, + depending on the SOC. If unsure, say N. + ++config SERIAL_8250_F81216 ++ tristate "Manage suspend and restore of F81216 devices" ++ depends on SERIAL_8250 != n ++ help ++ Say Y here if you have a board such as the IEI Kino 69OS1 with an ++ F81216 SuperIO chip which requires Linux to restore the serial port ++ configuration when you suspend and resume. If unsure, say N. ++ ++ To compile this driver as a module, choose M here: the module ++ will be called 8250_f81216. ++ + config SERIAL_8250_RM9K + bool "Support for MIPS RM9xxx integrated serial port" + depends on SERIAL_8250 != n && SERIAL_RM9000 +--- a/drivers/serial/Makefile ++++ b/drivers/serial/Makefile +@@ -28,6 +28,7 @@ obj-$(CONFIG_SERIAL_8250_BOCA) += 8250_b + obj-$(CONFIG_SERIAL_8250_EXAR_ST16C554) += 8250_exar_st16c554.o + obj-$(CONFIG_SERIAL_8250_HUB6) += 8250_hub6.o + obj-$(CONFIG_SERIAL_8250_MCA) += 8250_mca.o ++obj-$(CONFIG_SERIAL_8250_F81216) += 8250_f81216.o + obj-$(CONFIG_SERIAL_AMBA_PL010) += amba-pl010.o + obj-$(CONFIG_SERIAL_AMBA_PL011) += amba-pl011.o + obj-$(CONFIG_SERIAL_CLPS711X) += clps711x.o diff --git a/tty.work/serial-use-port-hangup b/tty.work/serial-use-port-hangup new file mode 100644 index 00000000000000..7609ba68ae2180 --- /dev/null +++ b/tty.work/serial-use-port-hangup @@ -0,0 +1,37 @@ +serial: use tty_port_hangup + +From: Alan Cox <alan@linux.intel.com> + +We can now move the uart hangup code to use the core tty port code. + +Signed-off-by: Alan Cox <alan@linux.intel.com> +--- + + drivers/serial/serial_core.c | 7 +------ + 1 files changed, 1 insertions(+), 6 deletions(-) + + +diff --git a/drivers/serial/serial_core.c b/drivers/serial/serial_core.c +index 285c051..4e646c4 100644 +--- a/drivers/serial/serial_core.c ++++ b/drivers/serial/serial_core.c +@@ -1422,18 +1422,13 @@ static void uart_hangup(struct tty_struct *tty) + struct uart_state *state = tty->driver_data; + struct tty_port *port = &state->port; + +- BUG_ON(!kernel_locked()); + pr_debug("uart_hangup(%d)\n", state->uart_port->line); + + mutex_lock(&port->mutex); + if (port->flags & ASYNC_NORMAL_ACTIVE) { + uart_flush_buffer(tty); + uart_shutdown(state); +- port->count = 0; +- clear_bit(ASYNCB_NORMAL_ACTIVE, &port->flags); +- tty_port_tty_set(port, NULL); +- wake_up_interruptible(&port->open_wait); +- wake_up_interruptible(&port->delta_msr_wait); ++ tty_port_hangup(port); + } + mutex_unlock(&port->mutex); + } diff --git a/tty.work/serial-use-tty-close b/tty.work/serial-use-tty-close new file mode 100644 index 00000000000000..8161e25945a4ad --- /dev/null +++ b/tty.work/serial-use-tty-close @@ -0,0 +1,102 @@ +serial: use tty_port_close + +From: Alan Cox <alan@linux.intel.com> + +We can now move to the closing helper but can't yet use the open helper + +Signed-off-by: Alan Cox <alan@linux.intel.com> +--- + + drivers/serial/serial_core.c | 60 ++++++++---------------------------------- + 1 files changed, 11 insertions(+), 49 deletions(-) + + +diff --git a/drivers/serial/serial_core.c b/drivers/serial/serial_core.c +index 4e646c4..6d2290d 100644 +--- a/drivers/serial/serial_core.c ++++ b/drivers/serial/serial_core.c +@@ -1277,48 +1277,20 @@ static void uart_close(struct tty_struct *tty, struct file *filp) + + mutex_lock(&port->mutex); + +- if (tty_hung_up_p(filp)) ++ /* FIXME: We can also migrate to drain_delay here */ ++ if (tty_port_close_start(port, tty, filp) == 0) + goto done; + +- if ((tty->count == 1) && (port->count != 1)) { +- /* +- * Uh, oh. tty->count is 1, which means that the tty +- * structure will be freed. port->count should always +- * be one in these conditions. If it's greater than +- * one, we've got real problems, since it means the +- * serial port won't be shutdown. +- */ +- printk(KERN_ERR "uart_close: bad serial port count; tty->count is 1, " +- "port->count is %d\n", port->count); +- port->count = 1; +- } +- if (--port->count < 0) { +- printk(KERN_ERR "uart_close: bad serial port count for %s: %d\n", +- tty->name, port->count); +- port->count = 0; +- } +- if (port->count) +- goto done; +- +- /* +- * Now we wait for the transmit buffer to clear; and we notify +- * the line discipline to only process XON/XOFF characters by +- * setting tty->closing. +- */ +- tty->closing = 1; +- +- if (port->closing_wait != ASYNC_CLOSING_WAIT_NONE) +- tty_wait_until_sent(tty, msecs_to_jiffies(port->closing_wait)); +- + /* + * At this point, we stop accepting input. To do this, we +- * disable the receive line status interrupts. ++ * disable the receive line status interrupts. This logic probably ++ * ultimately belongs in the tty port layer + */ + if (port->flags & ASYNC_INITIALIZED) { + unsigned long flags; +- spin_lock_irqsave(&port->lock, flags); ++ spin_lock_irqsave(&uport->lock, flags); + uport->ops->stop_rx(uport); +- spin_unlock_irqrestore(&port->lock, flags); ++ spin_unlock_irqrestore(&uport->lock, flags); + /* + * Before we drop DTR, make sure the UART transmitter + * has completely drained; this is especially +@@ -1330,24 +1302,14 @@ static void uart_close(struct tty_struct *tty, struct file *filp) + uart_shutdown(state); + uart_flush_buffer(tty); + +- tty_ldisc_flush(tty); +- +- tty->closing = 0; ++ tty_port_close_end(port, tty); + tty_port_tty_set(port, NULL); + +- if (port->blocked_open) { +- if (port->close_delay) +- msleep_interruptible(port->close_delay); +- } else if (!uart_console(uport)) { +- uart_change_pm(state, 3); +- } +- +- /* +- * Wake up anyone trying to open this port. ++ /* No users waiting - drop the power state ++ FIXME: should be core tty port code ? + */ +- clear_bit(ASYNCB_NORMAL_ACTIVE, &port->flags); +- wake_up_interruptible(&port->open_wait); +- ++ if(port->blocked_open == 0 && !uart_console(uport)) ++ uart_change_pm(state, 3); + done: + mutex_unlock(&port->mutex); + } diff --git a/tty.work/tty-usb-cleanup-open b/tty.work/tty-usb-cleanup-open new file mode 100644 index 00000000000000..ae36e9c3bdc8d4 --- /dev/null +++ b/tty.work/tty-usb-cleanup-open @@ -0,0 +1,211 @@ +tty: clean up the USB open paths + +From: Alan Cox <alan@linux.intel.com> + +Extract the first time init logic and make it a helper which does its own +clean up + +Remove the clean up we can just let ->shutdown handle when the device is +freed up + +Signed-off-by: Alan Cox <alan@linux.intel.com> +--- + + drivers/usb/serial/usb-serial.c | 126 +++++++++++++++++++++------------------- + 1 file changed, 68 insertions(+), 58 deletions(-) + + +--- a/drivers/usb/serial/usb-serial.c ++++ b/drivers/usb/serial/usb-serial.c +@@ -179,7 +179,59 @@ void usb_serial_put(struct usb_serial *s + /***************************************************************************** + * Driver tty interface functions + *****************************************************************************/ +-static int serial_open (struct tty_struct *tty, struct file *filp) ++ ++/** ++ * serial_activate - activate a USB serial port ++ * @tty: the tty being activated ++ * @port: the USB port being activated ++ * @filp: File handle ++ * ++ * Called to activate a USB serial port. The caller must hold port->mutex ++ * ++ * On exit either ++ * The port is activated and ASYNC_INITIALIZED is set ++ * - a module reference is held ++ * - an autopm reference is held ++ * or ++ * An error occurred ++ * - all references taken are dropped ++ */ ++ ++static int serial_activate(struct tty_struct *tty, struct usb_serial_port *port) ++{ ++ struct usb_serial *serial = port->serial; ++ int retval; ++ /* lock this module before we call it ++ * this may fail, which means we must bail out, ++ * safe because we are called with BKL held */ ++ if (!try_module_get(serial->type->driver.owner)) ++ return -ENODEV; ++ ++ mutex_lock(&serial->disc_mutex); ++ if (serial->disconnected) ++ retval = -ENODEV; ++ else ++ retval = usb_autopm_get_interface(serial->interface); ++ if (retval) ++ goto bailout_module_put; ++ ++ /* only call the device specific open if this ++ * is the first time the port is opened */ ++ retval = serial->type->open(tty, port); ++ if (retval) ++ goto bailout_interface_put; ++ mutex_unlock(&serial->disc_mutex); ++ set_bit(ASYNCB_INITIALIZED, &port->port.flags); ++ return 0; ++bailout_interface_put: ++ usb_autopm_put_interface(serial->interface); ++bailout_module_put: ++ module_put(serial->type->driver.owner); ++ mutex_unlock(&serial->disc_mutex); ++ return retval; ++} ++ ++static int serial_open(struct tty_struct *tty, struct file *filp) + { + struct usb_serial *serial; + struct usb_serial_port *port; +@@ -189,12 +241,11 @@ static int serial_open (struct tty_struc + + dbg("%s", __func__); + ++ tty->driver_data = NULL; + /* get the serial object associated with this tty pointer */ + serial = usb_serial_get_by_index(tty->index); +- if (!serial) { +- tty->driver_data = NULL; ++ if (!serial) + return -ENODEV; +- } + + mutex_lock(&serial->disc_mutex); + portNumber = tty->index - serial->minor; +@@ -226,53 +277,17 @@ static int serial_open (struct tty_struc + /* If the console is attached, the device is already open */ + if (port->port.count == 1 && !port->console) { + first = 1; +- /* lock this module before we call it +- * this may fail, which means we must bail out, +- * safe because we are called with BKL held */ +- if (!try_module_get(serial->type->driver.owner)) { +- retval = -ENODEV; +- goto bailout_mutex_unlock; +- } +- +- mutex_lock(&serial->disc_mutex); +- if (serial->disconnected) +- retval = -ENODEV; +- else +- retval = usb_autopm_get_interface(serial->interface); +- if (retval) +- goto bailout_module_put; +- +- /* only call the device specific open if this +- * is the first time the port is opened */ +- retval = serial->type->open(tty, port); +- if (retval) +- goto bailout_interface_put; +- mutex_unlock(&serial->disc_mutex); +- set_bit(ASYNCB_INITIALIZED, &port->port.flags); ++ retval = serial_activate(tty, port); + } + mutex_unlock(&port->mutex); + /* Now do the correct tty layer semantics */ + retval = tty_port_block_til_ready(&port->port, tty, filp); +- if (retval == 0) { +- if (!first) +- usb_serial_put(serial); +- return 0; +- } +- mutex_lock(&port->mutex); +- if (first == 0) +- goto bailout_mutex_unlock; +- /* Undo the initial port actions */ +- mutex_lock(&serial->disc_mutex); +-bailout_interface_put: +- usb_autopm_put_interface(serial->interface); +-bailout_module_put: +- mutex_unlock(&serial->disc_mutex); +- module_put(serial->type->driver.owner); +-bailout_mutex_unlock: +- port->port.count = 0; +- tty->driver_data = NULL; +- tty_port_tty_set(&port->port, NULL); +- mutex_unlock(&port->mutex); ++ if (!first) ++ usb_serial_put(serial); ++ /* Close will do any needed cleaning up and serial_do_free will ++ finish the job */ ++ return retval; ++ + bailout_port_put: + put_device(&port->dev); + bailout_serial_put: +@@ -281,7 +296,7 @@ bailout_serial_put: + } + + /** +- * serial_do_down - shut down hardware ++ * serial_shutdown - shut down hardware + * @port: port to shut down + * + * Shut down a USB port unless it is the console. We never shut down the +@@ -289,8 +304,10 @@ bailout_serial_put: + * + * Don't free any resources at this point + */ +-static void serial_do_down(struct usb_serial_port *port) ++static void serial_shutdown(struct tty_port *tport) + { ++ struct usb_serial_port *port = container_of(tport, ++ struct usb_serial_port, port); + struct usb_serial_driver *drv = port->serial->type; + + /* The console is magical, do not hang up the console hardware +@@ -341,24 +358,16 @@ static void serial_do_free(struct tty_st + static void serial_close(struct tty_struct *tty, struct file *filp) + { + struct usb_serial_port *port = tty->driver_data; +- + if (!port) + return; + + dbg("%s - port %d", __func__, port->number); +- +- if (tty_port_close_start(&port->port, tty, filp) == 0) +- return; +- serial_do_down(port); +- tty_port_close_end(&port->port, tty); +- tty_port_tty_set(&port->port, NULL); +- ++ tty_port_close(&port->port, tty, filp); + } + + static void serial_hangup(struct tty_struct *tty) + { + struct usb_serial_port *port = tty->driver_data; +- serial_do_down(port); + tty_port_hangup(&port->port); + /* We must not free port yet - the USB serial layer depends on it's + continued existence */ +@@ -713,6 +722,7 @@ static void serial_dtr_rts(struct tty_po + static const struct tty_port_operations serial_port_ops = { + .carrier_raised = serial_carrier_raised, + .dtr_rts = serial_dtr_rts, ++ .shutdown = serial_shutdown, + }; + + /** |
