[PATCH 00/80] TTY updates for 2.6.28 - Kernel

This is a discussion on [PATCH 00/80] TTY updates for 2.6.28 - Kernel ; The big thrust of this is krefs. The tty and tty drivers are now kref accounted and this allows some of the locking to be simplified. The pty special casing has been mostly pushed into the pty layer and the ...

+ Reply to Thread
Page 1 of 4 1 2 3 ... LastLast
Results 1 to 20 of 70

Thread: [PATCH 00/80] TTY updates for 2.6.28

  1. [PATCH 00/80] TTY updates for 2.6.28

    The big thrust of this is krefs. The tty and tty drivers are now kref accounted
    and this allows some of the locking to be simplified. The pty special casing
    has been mostly pushed into the pty layer and the open paths simplified so we
    are close to disposing of the BKL on open/close.

    Also fix a pile of bugs found in the tty layer during this process and in
    driver code.

    Finally we add the basics of termiox (the standard Unix termios extension) as
    bits of it are now needed by people wanting things like non-standard handshake.

    Resynched against the current git tree as of this morning.

    Signed-off-by: Alan Cox


    ---

    Adrian Bunk (1):
    coldfire: scheduled SERIAL_COLDFIRE removal

    Akinobu Mita (1):
    ip2: avoid add_timer with pending timer

    Alan Cox (46):
    tty: rename the remaining oddly named n_tty functions
    fs3270: Correct error returns
    fs3270: remove extra locks
    applicom: Fix an unchecked user ioctl range and an error return
    tty: Minor tidyups and document fixes for n_tty
    tty: Remove lots of NULL checks
    tty: fix up gigaset a bit
    tty: some ICANON magic is in the wrong places
    tty: simplify ktermios allocation
    pty: simplify unix98 allocation
    pty: Fix allocation failure double free
    pty: Coding style and polish
    tty: extract the pty init time special cases
    tty: Finish fixing up the init_dev interface to use ERR_PTR
    tty: More driver operations
    tty: kref the tty driver object
    tty: Clean up the tty_init_dev changes further
    tty: Remove more special casing and out of place code
    tty: shutdown method
    vt: remove bogus lock dropping
    pty: If the administrator creates a device for a ptmx slave we should not error
    tty: Fix abusers of current->sighand->tty
    tty: Redo current tty locking
    tty: the vhangup syscall is racy
    mxser: Switch to kref tty
    stallion: Use krefs
    tty: kref usage for isicom and moxa
    tty: usb-serial krefs
    tty: Move tty_write_message out of kernel/printk
    tty: Make get_current_tty use a kref
    tty: compare the tty winsize
    tty: Termios locking - sort out real_tty confusions and lock reads
    tty: Add termiox
    tty: ipw need reworking
    tty: Cris has a nice RS485 ioctl so we should steal it
    tty: use krefs to protect driver module counts
    tty: Add a kref count
    pps: Reserve a line discipline number for PPS
    tty: Split tty_port into its own file
    tty: split the buffering from tty_io
    uml: small cleanups and note bugs to be dealt with by uml authors...
    tty: move tioclinux from a special case
    serial_8250: pci_enable_device fail is not fully handled
    ftdi: A few errors are err() that should be debug which causes much spewage
    nozomi: Fix close on error
    epca: call tty_port_init

    Andrew Morton (1):
    serial-make-uart_ports-ioport-unsigned-long-fix

    David Miller (2):
    serial: allow 8250 to be used on sparc
    serial: Make uart_port's ioport "unsigned long".

    David S. Miller (1):
    serial: fix device name reporting when minor space is shared between drivers

    Graf Yang (1):
    Blackfin Serial Driver: Fix bug - ircp fails on sir over Blackfin UART

    Jason Wessel (2):
    tty: tty_io.c shadows sparse fix
    usb: fix pl2303 initialization

    Jiri Slaby (6):
    ip2, init/deinit cleanup
    ip2, fix sparse warnings
    ip2, cleanup globals
    Char: merge ip2main and ip2base
    Char: sx, fix io unmapping
    Char: cyclades. remove bogus iomap

    Julia Lawall (2):
    drivers/char/hvc_console.c: adjust call to put_tty_driver
    drivers/serial/crisv10.c: add missing put_tty_driver

    Mike Frysinger (3):
    Blackfin Serial Driver: move common variables out of serial headers and into the serial driver
    Blackfin Serial Driver: trim trailing whitespace -- no functional changes
    Blackfin Serial Driver: use __initdata for data, not __init

    Miloslav Trmac (1):
    audit: Handle embedded NUL in TTY input auditing

    Scott Ashcroft (1):
    Fix oti6858 debug level

    Sonic Zhang (4):
    Blackfin Serial Driver: Fix bug - request UART2/3 peripheral mapped interrupts in PIO mode
    Blackfin Serial Driver: Fix bug - Don't call tx_stop in tx_transfer.
    Blackfin Serial Driver: Remove useless stop
    Blackfin Serial Driver: Fix bug - should suspend/resume/remove all uart ports.

    Stephen Rothwell (1):
    tty: Fallout from tty-move-canon-specials

    Sukadev Bhattiprolu (6):
    Simplify devpts_pty_kill
    Simplify devpts_pty_new()
    Simplify devpts_get_tty()
    Add an instance parameter devpts interfaces
    Move tty lookup/reopen to caller
    tty: Move parts of tty_init_dev into new functions

    \\\"Will Newton\\\ (1):
    8250: remove a few inlines of dubious value


    Documentation/feature-removal-schedule.txt | 8
    arch/blackfin/kernel/bfin_dma_5xx.c | 13
    .../mach-bf527/include/mach/bfin_serial_5xx.h | 6
    .../mach-bf533/include/mach/bfin_serial_5xx.h | 4
    .../mach-bf537/include/mach/bfin_serial_5xx.h | 6
    .../mach-bf548/include/mach/bfin_serial_5xx.h | 6
    .../mach-bf561/include/mach/bfin_serial_5xx.h | 4
    arch/sparc/include/asm/serial.h | 6
    arch/um/drivers/line.c | 2
    drivers/bluetooth/hci_ldisc.c | 2
    drivers/char/Kconfig | 4
    drivers/char/Makefile | 2
    drivers/char/amiserial.c | 6
    drivers/char/applicom.c | 6
    drivers/char/cyclades.c | 21
    drivers/char/epca.c | 5
    drivers/char/generic_serial.c | 21
    drivers/char/hvc_console.c | 4
    drivers/char/ip2/Makefile | 2
    drivers/char/ip2/i2ellis.c | 32
    drivers/char/ip2/i2ellis.h | 2
    drivers/char/ip2/ip2base.c | 108 -
    drivers/char/ip2/ip2main.c | 550 +++---
    drivers/char/isicom.c | 61 -
    drivers/char/istallion.c | 113 +
    drivers/char/moxa.c | 61 -
    drivers/char/mxser.c | 193 +-
    drivers/char/n_hdlc.c | 2
    drivers/char/n_r3964.c | 8
    drivers/char/n_tty.c | 125 +
    drivers/char/nozomi.c | 5
    drivers/char/pcmcia/ipwireless/tty.c | 19
    drivers/char/pty.c | 335 +++
    drivers/char/stallion.c | 139 +
    drivers/char/sx.c | 4
    drivers/char/tty_audit.c | 2
    drivers/char/tty_buffer.c | 511 +++++
    drivers/char/tty_io.c | 1380 ++++----------
    drivers/char/tty_ioctl.c | 212 ++
    drivers/char/tty_port.c | 96 +
    drivers/char/vt.c | 84 -
    drivers/char/vt_ioctl.c | 2
    drivers/isdn/capi/capi.c | 2
    drivers/isdn/gigaset/ser-gigaset.c | 27
    drivers/net/wan/Kconfig | 2
    drivers/s390/char/fs3270.c | 17
    drivers/serial/8250.c | 52 -
    drivers/serial/8250_pci.c | 4
    drivers/serial/Kconfig | 17
    drivers/serial/Makefile | 16
    drivers/serial/bfin_5xx.c | 123 +
    drivers/serial/crisv10.c | 5
    drivers/serial/mcfserial.c | 1965 --------------------
    drivers/serial/mcfserial.h | 74 -
    drivers/serial/serial_core.c | 12
    drivers/usb/serial/aircable.c | 15
    drivers/usb/serial/belkin_sa.c | 3
    drivers/usb/serial/console.c | 8
    drivers/usb/serial/cyberjack.c | 3
    drivers/usb/serial/cypress_m8.c | 5
    drivers/usb/serial/digi_acceleport.c | 19
    drivers/usb/serial/empeg.c | 8
    drivers/usb/serial/ftdi_sio.c | 25
    drivers/usb/serial/garmin_gps.c | 3
    drivers/usb/serial/generic.c | 3
    drivers/usb/serial/io_edgeport.c | 43
    drivers/usb/serial/io_ti.c | 26
    drivers/usb/serial/ipaq.c | 3
    drivers/usb/serial/ipw.c | 3
    drivers/usb/serial/ir-usb.c | 3
    drivers/usb/serial/iuu_phoenix.c | 3
    drivers/usb/serial/keyspan.c | 77 -
    drivers/usb/serial/keyspan_pda.c | 16
    drivers/usb/serial/kl5kusb105.c | 3
    drivers/usb/serial/kobil_sct.c | 3
    drivers/usb/serial/mct_u232.c | 6
    drivers/usb/serial/mos7720.c | 36
    drivers/usb/serial/mos7840.c | 7
    drivers/usb/serial/navman.c | 3
    drivers/usb/serial/omninet.c | 10
    drivers/usb/serial/option.c | 18
    drivers/usb/serial/oti6858.c | 7
    drivers/usb/serial/pl2303.c | 15
    drivers/usb/serial/safe_serial.c | 11
    drivers/usb/serial/sierra.c | 16
    drivers/usb/serial/spcp8x5.c | 3
    drivers/usb/serial/ti_usb_3410_5052.c | 44
    drivers/usb/serial/usb-serial.c | 24
    drivers/usb/serial/visor.c | 18
    drivers/usb/serial/whiteheat.c | 8
    fs/devpts/inode.c | 66 -
    fs/dquot.c | 6
    fs/open.c | 3
    include/asm-x86/ioctls.h | 6
    include/linux/devpts_fs.h | 31
    include/linux/serial.h | 16
    include/linux/serial_core.h | 2
    include/linux/termios.h | 15
    include/linux/tty.h | 45
    include/linux/tty_driver.h | 56 +
    include/linux/vt_kern.h | 2
    kernel/acct.c | 2
    kernel/auditsc.c | 9
    kernel/fork.c | 5
    kernel/printk.c | 16
    kernel/sys.c | 4
    security/selinux/hooks.c | 3
    107 files changed, 2877 insertions(+), 4396 deletions(-)
    create mode 100644 arch/sparc/include/asm/serial.h
    delete mode 100644 drivers/char/ip2/ip2base.c
    create mode 100644 drivers/char/tty_buffer.c
    create mode 100644 drivers/char/tty_port.c
    delete mode 100644 drivers/serial/mcfserial.c
    delete mode 100644 drivers/serial/mcfserial.h

    --
    Signature
    --
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

  2. [PATCH 10/80] Blackfin Serial Driver: Fix bug - Don't call tx_stop in tx_transfer.

    From: Sonic Zhang

    Disable irq and return immediately.

    Signed-off-by: Sonic Zhang
    Signed-off-by: Bryan Wu
    Signed-off-by: Alan Cox
    ---

    drivers/serial/bfin_5xx.c | 6 +++++-
    1 files changed, 5 insertions(+), 1 deletions(-)


    diff --git a/drivers/serial/bfin_5xx.c b/drivers/serial/bfin_5xx.c
    index 8d2d757..5e20f50 100644
    --- a/drivers/serial/bfin_5xx.c
    +++ b/drivers/serial/bfin_5xx.c
    @@ -301,7 +301,11 @@ static void bfin_serial_tx_chars(struct bfin_serial_port *uart)
    bfin_serial_mctrl_check(uart);

    if (uart_circ_empty(xmit) || uart_tx_stopped(&uart->port)) {
    - bfin_serial_stop_tx(&uart->port);
    +#ifdef CONFIG_BF54x
    + /* Clear TFI bit */
    + UART_PUT_LSR(uart, TFI);
    +#endif
    + UART_CLEAR_IER(uart, ETBEI);
    return;
    }


    --
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

  3. [PATCH 11/80] Blackfin Serial Driver: Fix bug - ircp fails on sir over Blackfin UART

    From: Graf Yang

    We now use the sir_dev/irtty_sir/uart/bfin_serial drivers framework
    to monitor the TX status.

    Signed-off-by: Graf Yang
    Signed-off-by: Bryan Wu
    Signed-off-by: Alan Cox
    ---

    .../mach-bf527/include/mach/bfin_serial_5xx.h | 3 +++
    .../mach-bf533/include/mach/bfin_serial_5xx.h | 2 ++
    .../mach-bf537/include/mach/bfin_serial_5xx.h | 3 +++
    .../mach-bf548/include/mach/bfin_serial_5xx.h | 3 +++
    .../mach-bf561/include/mach/bfin_serial_5xx.h | 2 ++
    drivers/serial/bfin_5xx.c | 4 ++++
    6 files changed, 17 insertions(+), 0 deletions(-)


    diff --git a/arch/blackfin/mach-bf527/include/mach/bfin_serial_5xx.h b/arch/blackfin/mach-bf527/include/mach/bfin_serial_5xx.h
    index a23d047..75722d6 100644
    --- a/arch/blackfin/mach-bf527/include/mach/bfin_serial_5xx.h
    +++ b/arch/blackfin/mach-bf527/include/mach/bfin_serial_5xx.h
    @@ -78,6 +78,9 @@
    # define CONFIG_UART1_RTS_PIN -1
    # endif
    #endif
    +
    +#define BFIN_UART_TX_FIFO_SIZE 2
    +
    /*
    * The pin configuration is different from schematic
    */
    diff --git a/arch/blackfin/mach-bf533/include/mach/bfin_serial_5xx.h b/arch/blackfin/mach-bf533/include/mach/bfin_serial_5xx.h
    index 20471cd..815bfe5 100644
    --- a/arch/blackfin/mach-bf533/include/mach/bfin_serial_5xx.h
    +++ b/arch/blackfin/mach-bf533/include/mach/bfin_serial_5xx.h
    @@ -69,6 +69,8 @@
    # endif
    #endif

    +#define BFIN_UART_TX_FIFO_SIZE 2
    +
    struct bfin_serial_port {
    struct uart_port port;
    unsigned int old_status;
    diff --git a/arch/blackfin/mach-bf537/include/mach/bfin_serial_5xx.h b/arch/blackfin/mach-bf537/include/mach/bfin_serial_5xx.h
    index 08dfe30..b3f87e1 100644
    --- a/arch/blackfin/mach-bf537/include/mach/bfin_serial_5xx.h
    +++ b/arch/blackfin/mach-bf537/include/mach/bfin_serial_5xx.h
    @@ -78,6 +78,9 @@
    # define CONFIG_UART1_RTS_PIN -1
    # endif
    #endif
    +
    +#define BFIN_UART_TX_FIFO_SIZE 2
    +
    /*
    * The pin configuration is different from schematic
    */
    diff --git a/arch/blackfin/mach-bf548/include/mach/bfin_serial_5xx.h b/arch/blackfin/mach-bf548/include/mach/bfin_serial_5xx.h
    index 76976b1..e4cf35e 100644
    --- a/arch/blackfin/mach-bf548/include/mach/bfin_serial_5xx.h
    +++ b/arch/blackfin/mach-bf548/include/mach/bfin_serial_5xx.h
    @@ -82,6 +82,9 @@
    # define CONFIG_UART1_RTS_PIN -1
    # endif
    #endif
    +
    +#define BFIN_UART_TX_FIFO_SIZE 2
    +
    /*
    * The pin configuration is different from schematic
    */
    diff --git a/arch/blackfin/mach-bf561/include/mach/bfin_serial_5xx.h b/arch/blackfin/mach-bf561/include/mach/bfin_serial_5xx.h
    index 6cddca4..e0ce0c1 100644
    --- a/arch/blackfin/mach-bf561/include/mach/bfin_serial_5xx.h
    +++ b/arch/blackfin/mach-bf561/include/mach/bfin_serial_5xx.h
    @@ -69,6 +69,8 @@
    # endif
    #endif

    +#define BFIN_UART_TX_FIFO_SIZE 2
    +
    struct bfin_serial_port {
    struct uart_port port;
    unsigned int old_status;
    diff --git a/drivers/serial/bfin_5xx.c b/drivers/serial/bfin_5xx.c
    index 5e20f50..a5cf0e7 100644
    --- a/drivers/serial/bfin_5xx.c
    +++ b/drivers/serial/bfin_5xx.c
    @@ -761,6 +761,9 @@ bfin_serial_set_termios(struct uart_port *port, struct ktermios *termios,
    val |= UCEN;
    UART_PUT_GCTL(uart, val);

    + /* Port speed changed, update the per-port timeout. */
    + uart_update_timeout(port, termios->c_cflag, baud);
    +
    spin_unlock_irqrestore(&uart->port.lock, flags);
    }

    @@ -865,6 +868,7 @@ static void __init bfin_serial_init_ports(void)

    for (i = 0; i < nr_active_ports; i++) {
    bfin_serial_ports[i].port.uartclk = get_sclk();
    + bfin_serial_ports[i].port.fifosize = BFIN_UART_TX_FIFO_SIZE;
    bfin_serial_ports[i].port.ops = &bfin_serial_pops;
    bfin_serial_ports[i].port.line = i;
    bfin_serial_ports[i].port.iotype = UPIO_MEM;

    --
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

  4. [PATCH 03/80] coldfire: scheduled SERIAL_COLDFIRE removal

    From: Adrian Bunk

    This patch contains the scheduled removal of the obsolete
    SERIAL_COLDFIRE driver.

    Signed-off-by: Adrian Bunk
    Signed-off-by: Alan Cox
    ---

    Documentation/feature-removal-schedule.txt | 8
    drivers/serial/Kconfig | 16
    drivers/serial/Makefile | 1
    drivers/serial/mcfserial.c | 1965 ----------------------------
    drivers/serial/mcfserial.h | 74 -
    5 files changed, 2 insertions(+), 2062 deletions(-)
    delete mode 100644 drivers/serial/mcfserial.c
    delete mode 100644 drivers/serial/mcfserial.h


    diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt
    index 3d2d0c2..cc8093c 100644
    --- a/Documentation/feature-removal-schedule.txt
    +++ b/Documentation/feature-removal-schedule.txt
    @@ -287,14 +287,6 @@ Who: Glauber Costa

    ---------------------------

    -What: old style serial driver for ColdFire (CONFIG_SERIAL_COLDFIRE)
    -When: 2.6.28
    -Why: This driver still uses the old interface and has been replaced
    - by CONFIG_SERIAL_MCF.
    -Who: Sebastian Siewior
    -
    ----------------------------
    -
    What: /sys/o2cb symlink
    When: January 2010
    Why: /sys/fs/o2cb is the proper location for this information - /sys/o2cb
    diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
    index 77cb342..0db2045 100644
    --- a/drivers/serial/Kconfig
    +++ b/drivers/serial/Kconfig
    @@ -994,24 +994,12 @@ config SERIAL_68328_RTS_CTS
    bool "Support RTS/CTS on 68328 serial port"
    depends on SERIAL_68328

    -config SERIAL_COLDFIRE
    - bool "ColdFire serial support (DEPRECATED)"
    - depends on COLDFIRE
    - help
    - This driver supports the built-in serial ports of the Motorola ColdFire
    - family of CPUs.
    - This driver is deprecated because it supports only the old interface
    - for serial drivers and features like magic keys are not working.
    - Please switch to the new style driver because this driver will be
    - removed soon.
    -
    config SERIAL_MCF
    - bool "Coldfire serial support (new style driver)"
    + bool "Coldfire serial support"
    depends on COLDFIRE
    select SERIAL_CORE
    help
    - This new serial driver supports the Freescale Coldfire serial ports
    - using the new serial driver subsystem.
    + This serial driver supports the Freescale Coldfire serial ports.

    config SERIAL_MCF_BAUDRATE
    int "Default baudrate for Coldfire serial ports"
    diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile
    index 7e7383e..1462eb3 100644
    --- a/drivers/serial/Makefile
    +++ b/drivers/serial/Makefile
    @@ -40,7 +40,6 @@ obj-$(CONFIG_SERIAL_SUNSAB) += sunsab.o
    obj-$(CONFIG_SERIAL_MUX) += mux.o
    obj-$(CONFIG_SERIAL_68328) += 68328serial.o
    obj-$(CONFIG_SERIAL_68360) += 68360serial.o
    -obj-$(CONFIG_SERIAL_COLDFIRE) += mcfserial.o
    obj-$(CONFIG_SERIAL_MCF) += mcf.o
    obj-$(CONFIG_SERIAL_PMACZILOG) += pmac_zilog.o
    obj-$(CONFIG_SERIAL_LH7A40X) += serial_lh7a40x.o
    diff --git a/drivers/serial/mcfserial.c b/drivers/serial/mcfserial.c
    deleted file mode 100644
    index fbe3835..0000000
    --- a/drivers/serial/mcfserial.c
    +++ /dev/null
    @@ -1,1965 +0,0 @@
    -#warning This driver is deprecated. Check Kconfig for details.
    -/*
    - * mcfserial.c -- serial driver for ColdFire internal UARTS.
    - *
    - * Copyright (C) 1999-2003 Greg Ungerer
    - * Copyright (c) 2000-2001 Lineo, Inc.
    - * Copyright (C) 2001-2002 SnapGear Inc.
    - *
    - * Based on code from 68332serial.c which was:
    - *
    - * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
    - * Copyright (C) 1998 TSHG
    - * Copyright (c) 1999 Rt-Control Inc.
    - *
    - * Changes:
    - * 08/07/2003 Daniele Bellucci
    - * some cleanups in mcfrs_write.
    - *
    - */
    -
    -#include
    -#include
    -#include
    -#include
    -#include
    -#include
    -#include
    -#include
    -#include
    -#include
    -#include
    -#include
    -#include
    -#include
    -#include
    -#include
    -#include
    -#include
    -#include
    -
    -#include
    -#include
    -#include
    -#include
    -#include
    -#include
    -#include
    -#include
    -#include
    -#include "mcfserial.h"
    -
    -struct timer_list mcfrs_timer_struct;
    -
    -/*
    - * Default console baud rate, we use this as the default
    - * for all ports so init can just open /dev/console and
    - * keep going. Perhaps one day the cflag settings for the
    - * console can be used instead.
    - */
    -#if defined(CONFIG_HW_FEITH)
    -#define CONSOLE_BAUD_RATE 38400
    -#define DEFAULT_CBAUD B38400
    -#elif defined(CONFIG_MOD5272) || defined(CONFIG_M5208EVB) || \
    - defined(CONFIG_M5329EVB) || defined(CONFIG_GILBARCO)
    -#define CONSOLE_BAUD_RATE 115200
    -#define DEFAULT_CBAUD B115200
    -#elif defined(CONFIG_ARNEWSH) || defined(CONFIG_FREESCALE) || \
    - defined(CONFIG_senTec) || defined(CONFIG_SNEHA) || defined(CONFIG_AVNET)
    -#define CONSOLE_BAUD_RATE 19200
    -#define DEFAULT_CBAUD B19200
    -#endif
    -
    -#ifndef CONSOLE_BAUD_RATE
    -#define CONSOLE_BAUD_RATE 9600
    -#define DEFAULT_CBAUD B9600
    -#endif
    -
    -int mcfrs_console_inited = 0;
    -int mcfrs_console_port = -1;
    -int mcfrs_console_baud = CONSOLE_BAUD_RATE;
    -int mcfrs_console_cbaud = DEFAULT_CBAUD;
    -
    -/*
    - * Driver data structures.
    - */
    -static struct tty_driver *mcfrs_serial_driver;
    -
    -/* number of characters left in xmit buffer before we ask for more */
    -#define WAKEUP_CHARS 256
    -
    -/* Debugging...
    - */
    -#undef SERIAL_DEBUG_OPEN
    -#undef SERIAL_DEBUG_FLOW
    -
    -#if defined(CONFIG_M523x) || defined(CONFIG_M527x) || defined(CONFIG_M528x) || \
    - defined(CONFIG_M520x) || defined(CONFIG_M532x)
    -#define IRQBASE (MCFINT_VECBASE+MCFINT_UART0)
    -#else
    -#define IRQBASE 73
    -#endif
    -
    -/*
    - * Configuration table, UARTs to look for at startup.
    - */
    -static struct mcf_serial mcfrs_table[] = {
    - { /* ttyS0 */
    - .magic = 0,
    - .addr = (volatile unsigned char *) (MCF_MBAR+MCFUART_BASE1),
    - .irq = IRQBASE,
    - .flags = ASYNC_BOOT_AUTOCONF,
    - },
    -#ifdef MCFUART_BASE2
    - { /* ttyS1 */
    - .magic = 0,
    - .addr = (volatile unsigned char *) (MCF_MBAR+MCFUART_BASE2),
    - .irq = IRQBASE+1,
    - .flags = ASYNC_BOOT_AUTOCONF,
    - },
    -#endif
    -#ifdef MCFUART_BASE3
    - { /* ttyS2 */
    - .magic = 0,
    - .addr = (volatile unsigned char *) (MCF_MBAR+MCFUART_BASE3),
    - .irq = IRQBASE+2,
    - .flags = ASYNC_BOOT_AUTOCONF,
    - },
    -#endif
    -#ifdef MCFUART_BASE4
    - { /* ttyS3 */
    - .magic = 0,
    - .addr = (volatile unsigned char *) (MCF_MBAR+MCFUART_BASE4),
    - .irq = IRQBASE+3,
    - .flags = ASYNC_BOOT_AUTOCONF,
    - },
    -#endif
    -};
    -
    -
    -#define NR_PORTS (sizeof(mcfrs_table) / sizeof(struct mcf_serial))
    -
    -/*
    - * This is used to figure out the divisor speeds and the timeouts.
    - */
    -static int mcfrs_baud_table[] = {
    - 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
    - 9600, 19200, 38400, 57600, 115200, 230400, 460800, 0
    -};
    -#define MCFRS_BAUD_TABLE_SIZE \
    - (sizeof(mcfrs_baud_table)/sizeof(mcfrs_baud_table[0]))
    -
    -
    -#ifdef CONFIG_MAGIC_SYSRQ
    -/*
    - * Magic system request keys. Used for debugging...
    - */
    -extern int magic_sysrq_key(int ch);
    -#endif
    -
    -
    -/*
    - * Forware declarations...
    - */
    -static void mcfrs_change_speed(struct mcf_serial *info);
    -static void mcfrs_wait_until_sent(struct tty_struct *tty, int timeout);
    -
    -
    -static inline int serial_paranoia_check(struct mcf_serial *info,
    - char *name, const char *routine)
    -{
    -#ifdef SERIAL_PARANOIA_CHECK
    - static const char badmagic[] =
    - "MCFRS(warning): bad magic number for serial struct %s in %s\n";
    - static const char badinfo[] =
    - "MCFRS(warning): null mcf_serial for %s in %s\n";
    -
    - if (!info) {
    - printk(badinfo, name, routine);
    - return 1;
    - }
    - if (info->magic != SERIAL_MAGIC) {
    - printk(badmagic, name, routine);
    - return 1;
    - }
    -#endif
    - return 0;
    -}
    -
    -/*
    - * Sets or clears DTR and RTS on the requested line.
    - */
    -static void mcfrs_setsignals(struct mcf_serial *info, int dtr, int rts)
    -{
    - volatile unsigned char *uartp;
    - unsigned long flags;
    -
    -#if 0
    - printk("%s(%d): mcfrs_setsignals(info=%x,dtr=%d,rts=%d)\n",
    - __FILE__, __LINE__, info, dtr, rts);
    -#endif
    -
    - local_irq_save(flags);
    - if (dtr >= 0) {
    -#ifdef MCFPP_DTR0
    - if (info->line)
    - mcf_setppdata(MCFPP_DTR1, (dtr ? 0 : MCFPP_DTR1));
    - else
    - mcf_setppdata(MCFPP_DTR0, (dtr ? 0 : MCFPP_DTR0));
    -#endif
    - }
    - if (rts >= 0) {
    - uartp = info->addr;
    - if (rts) {
    - info->sigs |= TIOCM_RTS;
    - uartp[MCFUART_UOP1] = MCFUART_UOP_RTS;
    - } else {
    - info->sigs &= ~TIOCM_RTS;
    - uartp[MCFUART_UOP0] = MCFUART_UOP_RTS;
    - }
    - }
    - local_irq_restore(flags);
    - return;
    -}
    -
    -/*
    - * Gets values of serial signals.
    - */
    -static int mcfrs_getsignals(struct mcf_serial *info)
    -{
    - volatile unsigned char *uartp;
    - unsigned long flags;
    - int sigs;
    -#if defined(CONFIG_NETtel) && defined(CONFIG_M5307)
    - unsigned short ppdata;
    -#endif
    -
    -#if 0
    - printk("%s(%d): mcfrs_getsignals(info=%x)\n", __FILE__, __LINE__);
    -#endif
    -
    - local_irq_save(flags);
    - uartp = info->addr;
    - sigs = (uartp[MCFUART_UIPR] & MCFUART_UIPR_CTS) ? 0 : TIOCM_CTS;
    - sigs |= (info->sigs & TIOCM_RTS);
    -
    -#ifdef MCFPP_DCD0
    -{
    - unsigned int ppdata;
    - ppdata = mcf_getppdata();
    - if (info->line == 0) {
    - sigs |= (ppdata & MCFPP_DCD0) ? 0 : TIOCM_CD;
    - sigs |= (ppdata & MCFPP_DTR0) ? 0 : TIOCM_DTR;
    - } else if (info->line == 1) {
    - sigs |= (ppdata & MCFPP_DCD1) ? 0 : TIOCM_CD;
    - sigs |= (ppdata & MCFPP_DTR1) ? 0 : TIOCM_DTR;
    - }
    -}
    -#endif
    -
    - local_irq_restore(flags);
    - return(sigs);
    -}
    -
    -/*
    - * ------------------------------------------------------------
    - * mcfrs_stop() and mcfrs_start()
    - *
    - * This routines are called before setting or resetting tty->stopped.
    - * They enable or disable transmitter interrupts, as necessary.
    - * ------------------------------------------------------------
    - */
    -static void mcfrs_stop(struct tty_struct *tty)
    -{
    - volatile unsigned char *uartp;
    - struct mcf_serial *info = (struct mcf_serial *)tty->driver_data;
    - unsigned long flags;
    -
    - if (serial_paranoia_check(info, tty->name, "mcfrs_stop"))
    - return;
    -
    - local_irq_save(flags);
    - uartp = info->addr;
    - info->imr &= ~MCFUART_UIR_TXREADY;
    - uartp[MCFUART_UIMR] = info->imr;
    - local_irq_restore(flags);
    -}
    -
    -static void mcfrs_start(struct tty_struct *tty)
    -{
    - volatile unsigned char *uartp;
    - struct mcf_serial *info = (struct mcf_serial *)tty->driver_data;
    - unsigned long flags;
    -
    - if (serial_paranoia_check(info, tty->name, "mcfrs_start"))
    - return;
    -
    - local_irq_save(flags);
    - if (info->xmit_cnt && info->xmit_buf) {
    - uartp = info->addr;
    - info->imr |= MCFUART_UIR_TXREADY;
    - uartp[MCFUART_UIMR] = info->imr;
    - }
    - local_irq_restore(flags);
    -}
    -
    -/*
    - * ----------------------------------------------------------------------
    - *
    - * Here starts the interrupt handling routines. All of the following
    - * subroutines are declared as inline and are folded into
    - * mcfrs_interrupt(). They were separated out for readability's sake.
    - *
    - * Note: mcfrs_interrupt() is a "fast" interrupt, which means that it
    - * runs with interrupts turned off. People who may want to modify
    - * mcfrs_interrupt() should try to keep the interrupt handler as fast as
    - * possible. After you are done making modifications, it is not a bad
    - * idea to do:
    - *
    - * gcc -S -DKERNEL -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer serial.c
    - *
    - * and look at the resulting assemble code in serial.s.
    - *
    - * - Ted Ts'o (tytso@mit.edu), 7-Mar-93
    - * -----------------------------------------------------------------------
    - */
    -
    -static inline void receive_chars(struct mcf_serial *info)
    -{
    - volatile unsigned char *uartp;
    - struct tty_struct *tty = info->port.tty;
    - unsigned char status, ch, flag;
    -
    - if (!tty)
    - return;
    -
    - uartp = info->addr;
    -
    - while ((status = uartp[MCFUART_USR]) & MCFUART_USR_RXREADY) {
    - ch = uartp[MCFUART_URB];
    - info->stats.rx++;
    -
    -#ifdef CONFIG_MAGIC_SYSRQ
    - if (mcfrs_console_inited && (info->line == mcfrs_console_port)) {
    - if (magic_sysrq_key(ch))
    - continue;
    - }
    -#endif
    -
    - flag = TTY_NORMAL;
    - if (status & MCFUART_USR_RXERR) {
    - uartp[MCFUART_UCR] = MCFUART_UCR_CMDRESETERR;
    - if (status & MCFUART_USR_RXBREAK) {
    - info->stats.rxbreak++;
    - flag = TTY_BREAK;
    - } else if (status & MCFUART_USR_RXPARITY) {
    - info->stats.rxparity++;
    - flag = TTY_PARITY;
    - } else if (status & MCFUART_USR_RXOVERRUN) {
    - info->stats.rxoverrun++;
    - flag = TTY_OVERRUN;
    - } else if (status & MCFUART_USR_RXFRAMING) {
    - info->stats.rxframing++;
    - flag = TTY_FRAME;
    - }
    - }
    - tty_insert_flip_char(tty, ch, flag);
    - }
    - tty_schedule_flip(tty);
    - return;
    -}
    -
    -static inline void transmit_chars(struct mcf_serial *info)
    -{
    - volatile unsigned char *uartp;
    -
    - uartp = info->addr;
    -
    - if (info->x_char) {
    - /* Send special char - probably flow control */
    - uartp[MCFUART_UTB] = info->x_char;
    - info->x_char = 0;
    - info->stats.tx++;
    - }
    -
    - if ((info->xmit_cnt <= 0) || info->port.tty->stopped) {
    - info->imr &= ~MCFUART_UIR_TXREADY;
    - uartp[MCFUART_UIMR] = info->imr;
    - return;
    - }
    -
    - while (uartp[MCFUART_USR] & MCFUART_USR_TXREADY) {
    - uartp[MCFUART_UTB] = info->xmit_buf[info->xmit_tail++];
    - info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1);
    - info->stats.tx++;
    - if (--info->xmit_cnt <= 0)
    - break;
    - }
    -
    - if (info->xmit_cnt < WAKEUP_CHARS)
    - schedule_work(&info->tqueue);
    - return;
    -}
    -
    -/*
    - * This is the serial driver's generic interrupt routine
    - */
    -irqreturn_t mcfrs_interrupt(int irq, void *dev_id)
    -{
    - struct mcf_serial *info;
    - unsigned char isr;
    -
    - info = &mcfrs_table[(irq - IRQBASE)];
    - isr = info->addr[MCFUART_UISR] & info->imr;
    -
    - if (isr & MCFUART_UIR_RXREADY)
    - receive_chars(info);
    - if (isr & MCFUART_UIR_TXREADY)
    - transmit_chars(info);
    - return IRQ_HANDLED;
    -}
    -
    -/*
    - * -------------------------------------------------------------------
    - * Here ends the serial interrupt routines.
    - * -------------------------------------------------------------------
    - */
    -
    -static void mcfrs_offintr(struct work_struct *work)
    -{
    - struct mcf_serial *info = container_of(work, struct mcf_serial, tqueue);
    - struct tty_struct *tty = info->port.tty;
    -
    - if (tty)
    - tty_wakeup(tty);
    -}
    -
    -
    -/*
    - * Change of state on a DCD line.
    - */
    -void mcfrs_modem_change(struct mcf_serial *info, int dcd)
    -{
    - if (info->count == 0)
    - return;
    -
    - if (info->flags & ASYNC_CHECK_CD) {
    - if (dcd)
    - wake_up_interruptible(&info->open_wait);
    - else
    - schedule_work(&info->tqueue_hangup);
    - }
    -}
    -
    -
    -#ifdef MCFPP_DCD0
    -
    -unsigned short mcfrs_ppstatus;
    -
    -/*
    - * This subroutine is called when the RS_TIMER goes off. It is used
    - * to monitor the state of the DCD lines - since they have no edge
    - * sensors and interrupt generators.
    - */
    -static void mcfrs_timer(void)
    -{
    - unsigned int ppstatus, dcdval, i;
    -
    - ppstatus = mcf_getppdata() & (MCFPP_DCD0 | MCFPP_DCD1);
    -
    - if (ppstatus != mcfrs_ppstatus) {
    - for (i = 0; (i < 2); i++) {
    - dcdval = (i ? MCFPP_DCD1 : MCFPP_DCD0);
    - if ((ppstatus & dcdval) != (mcfrs_ppstatus & dcdval)) {
    - mcfrs_modem_change(&mcfrs_table[i],
    - ((ppstatus & dcdval) ? 0 : 1));
    - }
    - }
    - }
    - mcfrs_ppstatus = ppstatus;
    -
    - /* Re-arm timer */
    - mcfrs_timer_struct.expires = jiffies + HZ/25;
    - add_timer(&mcfrs_timer_struct);
    -}
    -
    -#endif /* MCFPP_DCD0 */
    -
    -
    -/*
    - * This routine is called from the scheduler tqueue when the interrupt
    - * routine has signalled that a hangup has occurred. The path of
    - * hangup processing is:
    - *
    - * serial interrupt routine -> (scheduler tqueue) ->
    - * do_serial_hangup() -> tty->hangup() -> mcfrs_hangup()
    - *
    - */
    -static void do_serial_hangup(struct work_struct *work)
    -{
    - struct mcf_serial *info = container_of(work, struct mcf_serial, tqueue_hangup);
    - struct tty_struct *tty = info->port.tty;
    -
    - if (tty)
    - tty_hangup(tty);
    -}
    -
    -static int startup(struct mcf_serial * info)
    -{
    - volatile unsigned char *uartp;
    - unsigned long flags;
    -
    - if (info->flags & ASYNC_INITIALIZED)
    - return 0;
    -
    - if (!info->xmit_buf) {
    - info->xmit_buf = (unsigned char *) __get_free_page(GFP_KERNEL);
    - if (!info->xmit_buf)
    - return -ENOMEM;
    - }
    -
    - local_irq_save(flags);
    -
    -#ifdef SERIAL_DEBUG_OPEN
    - printk("starting up ttyS%d (irq %d)...\n", info->line, info->irq);
    -#endif
    -
    - /*
    - * Reset UART, get it into known state...
    - */
    - uartp = info->addr;
    - uartp[MCFUART_UCR] = MCFUART_UCR_CMDRESETRX; /* reset RX */
    - uartp[MCFUART_UCR] = MCFUART_UCR_CMDRESETTX; /* reset TX */
    - mcfrs_setsignals(info, 1, 1);
    -
    - if (info->port.tty)
    - clear_bit(TTY_IO_ERROR, &info->port.tty->flags);
    - info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
    -
    - /*
    - * and set the speed of the serial port
    - */
    - mcfrs_change_speed(info);
    -
    - /*
    - * Lastly enable the UART transmitter and receiver, and
    - * interrupt enables.
    - */
    - info->imr = MCFUART_UIR_RXREADY;
    - uartp[MCFUART_UCR] = MCFUART_UCR_RXENABLE | MCFUART_UCR_TXENABLE;
    - uartp[MCFUART_UIMR] = info->imr;
    -
    - info->flags |= ASYNC_INITIALIZED;
    - local_irq_restore(flags);
    - return 0;
    -}
    -
    -/*
    - * 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 mcf_serial * info)
    -{
    - volatile unsigned char *uartp;
    - unsigned long flags;
    -
    - if (!(info->flags & ASYNC_INITIALIZED))
    - return;
    -
    -#ifdef SERIAL_DEBUG_OPEN
    - printk("Shutting down serial port %d (irq %d)....\n", info->line,
    - info->irq);
    -#endif
    -
    - local_irq_save(flags);
    -
    - uartp = info->addr;
    - uartp[MCFUART_UIMR] = 0; /* mask all interrupts */
    - uartp[MCFUART_UCR] = MCFUART_UCR_CMDRESETRX; /* reset RX */
    - uartp[MCFUART_UCR] = MCFUART_UCR_CMDRESETTX; /* reset TX */
    -
    - if (!info->port.tty || (info->port.tty->termios->c_cflag & HUPCL))
    - mcfrs_setsignals(info, 0, 0);
    -
    - if (info->xmit_buf) {
    - free_page((unsigned long) info->xmit_buf);
    - info->xmit_buf = 0;
    - }
    -
    - if (info->port.tty)
    - set_bit(TTY_IO_ERROR, &info->port.tty->flags);
    -
    - info->flags &= ~ASYNC_INITIALIZED;
    - local_irq_restore(flags);
    -}
    -
    -
    -/*
    - * This routine is called to set the UART divisor registers to match
    - * the specified baud rate for a serial port.
    - */
    -static void mcfrs_change_speed(struct mcf_serial *info)
    -{
    - volatile unsigned char *uartp;
    - unsigned int baudclk, cflag;
    - unsigned long flags;
    - unsigned char mr1, mr2;
    - int i;
    -#ifdef CONFIG_M5272
    - unsigned int fraction;
    -#endif
    -
    - if (!info->port.tty || !info->port.tty->termios)
    - return;
    - cflag = info->port.tty->termios->c_cflag;
    - if (info->addr == 0)
    - return;
    -
    -#if 0
    - printk("%s(%d): mcfrs_change_speed()\n", __FILE__, __LINE__);
    -#endif
    -
    - i = cflag & CBAUD;
    - if (i & CBAUDEX) {
    - i &= ~CBAUDEX;
    - if (i < 1 || i > 4)
    - info->port.tty->termios->c_cflag &= ~CBAUDEX;
    - else
    - i += 15;
    - }
    - if (i == 0) {
    - mcfrs_setsignals(info, 0, -1);
    - return;
    - }
    -
    - /* compute the baudrate clock */
    -#ifdef CONFIG_M5272
    - /*
    - * For the MCF5272, also compute the baudrate fraction.
    - */
    - baudclk = (MCF_BUSCLK / mcfrs_baud_table[i]) / 32;
    - fraction = MCF_BUSCLK - (baudclk * 32 * mcfrs_baud_table[i]);
    - fraction *= 16;
    - fraction /= (32 * mcfrs_baud_table[i]);
    -#else
    - baudclk = ((MCF_BUSCLK / mcfrs_baud_table[i]) + 16) / 32;
    -#endif
    -
    - info->baud = mcfrs_baud_table[i];
    -
    - mr1 = MCFUART_MR1_RXIRQRDY | MCFUART_MR1_RXERRCHAR;
    - mr2 = 0;
    -
    - switch (cflag & CSIZE) {
    - case CS5: mr1 |= MCFUART_MR1_CS5; break;
    - case CS6: mr1 |= MCFUART_MR1_CS6; break;
    - case CS7: mr1 |= MCFUART_MR1_CS7; break;
    - case CS8:
    - default: mr1 |= MCFUART_MR1_CS8; break;
    - }
    -
    - if (cflag & PARENB) {
    - if (cflag & CMSPAR) {
    - if (cflag & PARODD)
    - mr1 |= MCFUART_MR1_PARITYMARK;
    - else
    - mr1 |= MCFUART_MR1_PARITYSPACE;
    - } else {
    - if (cflag & PARODD)
    - mr1 |= MCFUART_MR1_PARITYODD;
    - else
    - mr1 |= MCFUART_MR1_PARITYEVEN;
    - }
    - } else {
    - mr1 |= MCFUART_MR1_PARITYNONE;
    - }
    -
    - if (cflag & CSTOPB)
    - mr2 |= MCFUART_MR2_STOP2;
    - else
    - mr2 |= MCFUART_MR2_STOP1;
    -
    - if (cflag & CRTSCTS) {
    - mr1 |= MCFUART_MR1_RXRTS;
    - mr2 |= MCFUART_MR2_TXCTS;
    - }
    -
    - if (cflag & CLOCAL)
    - info->flags &= ~ASYNC_CHECK_CD;
    - else
    - info->flags |= ASYNC_CHECK_CD;
    -
    - uartp = info->addr;
    -
    - local_irq_save(flags);
    -#if 0
    - printk("%s(%d): mr1=%x mr2=%x baudclk=%x\n", __FILE__, __LINE__,
    - mr1, mr2, baudclk);
    -#endif
    - /*
    - Note: pg 12-16 of MCF5206e User's Manual states that a
    - software reset should be performed prior to changing
    - UMR1,2, UCSR, UACR, bit 7
    - */
    - uartp[MCFUART_UCR] = MCFUART_UCR_CMDRESETRX; /* reset RX */
    - uartp[MCFUART_UCR] = MCFUART_UCR_CMDRESETTX; /* reset TX */
    - uartp[MCFUART_UCR] = MCFUART_UCR_CMDRESETMRPTR; /* reset MR pointer */
    - uartp[MCFUART_UMR] = mr1;
    - uartp[MCFUART_UMR] = mr2;
    - uartp[MCFUART_UBG1] = (baudclk & 0xff00) >> 8; /* set msb byte */
    - uartp[MCFUART_UBG2] = (baudclk & 0xff); /* set lsb byte */
    -#ifdef CONFIG_M5272
    - uartp[MCFUART_UFPD] = (fraction & 0xf); /* set fraction */
    -#endif
    - uartp[MCFUART_UCSR] = MCFUART_UCSR_RXCLKTIMER | MCFUART_UCSR_TXCLKTIMER;
    - uartp[MCFUART_UCR] = MCFUART_UCR_RXENABLE | MCFUART_UCR_TXENABLE;
    - mcfrs_setsignals(info, 1, -1);
    - local_irq_restore(flags);
    - return;
    -}
    -
    -static void mcfrs_flush_chars(struct tty_struct *tty)
    -{
    - volatile unsigned char *uartp;
    - struct mcf_serial *info = (struct mcf_serial *)tty->driver_data;
    - unsigned long flags;
    -
    - if (serial_paranoia_check(info, tty->name, "mcfrs_flush_chars"))
    - return;
    -
    - uartp = (volatile unsigned char *) info->addr;
    -
    - /*
    - * re-enable receiver interrupt
    - */
    - local_irq_save(flags);
    - if ((!(info->imr & MCFUART_UIR_RXREADY)) &&
    - (info->flags & ASYNC_INITIALIZED) ) {
    - info->imr |= MCFUART_UIR_RXREADY;
    - uartp[MCFUART_UIMR] = info->imr;
    - }
    - local_irq_restore(flags);
    -
    - if (info->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped ||
    - !info->xmit_buf)
    - return;
    -
    - /* Enable transmitter */
    - local_irq_save(flags);
    - info->imr |= MCFUART_UIR_TXREADY;
    - uartp[MCFUART_UIMR] = info->imr;
    - local_irq_restore(flags);
    -}
    -
    -static int mcfrs_write(struct tty_struct * tty,
    - const unsigned char *buf, int count)
    -{
    - volatile unsigned char *uartp;
    - struct mcf_serial *info = (struct mcf_serial *)tty->driver_data;
    - unsigned long flags;
    - int c, total = 0;
    -
    -#if 0
    - printk("%s(%d): mcfrs_write(tty=%x,buf=%x,count=%d)\n",
    - __FILE__, __LINE__, (int)tty, (int)buf, count);
    -#endif
    -
    - if (serial_paranoia_check(info, tty->name, "mcfrs_write"))
    - return 0;
    -
    - if (!tty || !info->xmit_buf)
    - return 0;
    -
    - local_save_flags(flags);
    - while (1) {
    - local_irq_disable();
    - c = min(count, (int) min(((int)SERIAL_XMIT_SIZE) - info->xmit_cnt - 1,
    - ((int)SERIAL_XMIT_SIZE) - info->xmit_head));
    - local_irq_restore(flags);
    -
    - if (c <= 0)
    - break;
    -
    - memcpy(info->xmit_buf + info->xmit_head, buf, c);
    -
    - local_irq_disable();
    - info->xmit_head = (info->xmit_head + c) & (SERIAL_XMIT_SIZE-1);
    - info->xmit_cnt += c;
    - local_irq_restore(flags);
    -
    - buf += c;
    - count -= c;
    - total += c;
    - }
    -
    - local_irq_disable();
    - uartp = info->addr;
    - info->imr |= MCFUART_UIR_TXREADY;
    - uartp[MCFUART_UIMR] = info->imr;
    - local_irq_restore(flags);
    -
    - return total;
    -}
    -
    -static int mcfrs_write_room(struct tty_struct *tty)
    -{
    - struct mcf_serial *info = (struct mcf_serial *)tty->driver_data;
    - int ret;
    -
    - if (serial_paranoia_check(info, tty->name, "mcfrs_write_room"))
    - return 0;
    - ret = SERIAL_XMIT_SIZE - info->xmit_cnt - 1;
    - if (ret < 0)
    - ret = 0;
    - return ret;
    -}
    -
    -static int mcfrs_chars_in_buffer(struct tty_struct *tty)
    -{
    - struct mcf_serial *info = (struct mcf_serial *)tty->driver_data;
    -
    - if (serial_paranoia_check(info, tty->name, "mcfrs_chars_in_buffer"))
    - return 0;
    - return info->xmit_cnt;
    -}
    -
    -static void mcfrs_flush_buffer(struct tty_struct *tty)
    -{
    - struct mcf_serial *info = (struct mcf_serial *)tty->driver_data;
    - unsigned long flags;
    -
    - if (serial_paranoia_check(info, tty->name, "mcfrs_flush_buffer"))
    - return;
    -
    - local_irq_save(flags);
    - info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
    - local_irq_restore(flags);
    -
    - tty_wakeup(tty);
    -}
    -
    -/*
    - * ------------------------------------------------------------
    - * mcfrs_throttle()
    - *
    - * This routine is called by the upper-layer tty layer to signal that
    - * incoming characters should be throttled.
    - * ------------------------------------------------------------
    - */
    -static void mcfrs_throttle(struct tty_struct * tty)
    -{
    - struct mcf_serial *info = (struct mcf_serial *)tty->driver_data;
    -#ifdef SERIAL_DEBUG_THROTTLE
    - char buf[64];
    -
    - printk("throttle %s: %d....\n", tty_name(tty, buf),
    - tty->ldisc.chars_in_buffer(tty));
    -#endif
    -
    - if (serial_paranoia_check(info, tty->name, "mcfrs_throttle"))
    - return;
    -
    - if (I_IXOFF(tty))
    - info->x_char = STOP_CHAR(tty);
    -
    - /* Turn off RTS line (do this atomic) */
    -}
    -
    -static void mcfrs_unthrottle(struct tty_struct * tty)
    -{
    - struct mcf_serial *info = (struct mcf_serial *)tty->driver_data;
    -#ifdef SERIAL_DEBUG_THROTTLE
    - char buf[64];
    -
    - printk("unthrottle %s: %d....\n", tty_name(tty, buf),
    - tty->ldisc.chars_in_buffer(tty));
    -#endif
    -
    - if (serial_paranoia_check(info, tty->name, "mcfrs_unthrottle"))
    - return;
    -
    - if (I_IXOFF(tty)) {
    - if (info->x_char)
    - info->x_char = 0;
    - else
    - info->x_char = START_CHAR(tty);
    - }
    -
    - /* Assert RTS line (do this atomic) */
    -}
    -
    -/*
    - * ------------------------------------------------------------
    - * mcfrs_ioctl() and friends
    - * ------------------------------------------------------------
    - */
    -
    -static int get_serial_info(struct mcf_serial * info,
    - struct serial_struct * retinfo)
    -{
    - struct serial_struct tmp;
    -
    - if (!retinfo)
    - return -EFAULT;
    - memset(&tmp, 0, sizeof(tmp));
    - tmp.type = info->type;
    - tmp.line = info->line;
    - tmp.port = (unsigned int) info->addr;
    - tmp.irq = info->irq;
    - tmp.flags = info->flags;
    - tmp.baud_base = info->baud_base;
    - tmp.close_delay = info->close_delay;
    - tmp.closing_wait = info->closing_wait;
    - tmp.custom_divisor = info->custom_divisor;
    - return copy_to_user(retinfo,&tmp,sizeof(*retinfo)) ? -EFAULT : 0;
    -}
    -
    -static int set_serial_info(struct mcf_serial * info,
    - struct serial_struct * new_info)
    -{
    - struct serial_struct new_serial;
    - struct mcf_serial old_info;
    - int retval = 0;
    -
    - if (!new_info)
    - return -EFAULT;
    - if (copy_from_user(&new_serial,new_info,sizeof(new_serial)))
    - return -EFAULT;
    - old_info = *info;
    -
    - if (!capable(CAP_SYS_ADMIN)) {
    - if ((new_serial.baud_base != info->baud_base) ||
    - (new_serial.type != info->type) ||
    - (new_serial.close_delay != info->close_delay) ||
    - ((new_serial.flags & ~ASYNC_USR_MASK) !=
    - (info->flags & ~ASYNC_USR_MASK)))
    - return -EPERM;
    - info->flags = ((info->flags & ~ASYNC_USR_MASK) |
    - (new_serial.flags & ASYNC_USR_MASK));
    - info->custom_divisor = new_serial.custom_divisor;
    - goto check_and_exit;
    - }
    -
    - if (info->count > 1)
    - return -EBUSY;
    -
    - /*
    - * OK, past this point, all the error checking has been done.
    - * At this point, we start making changes.....
    - */
    -
    - info->baud_base = new_serial.baud_base;
    - info->flags = ((info->flags & ~ASYNC_FLAGS) |
    - (new_serial.flags & ASYNC_FLAGS));
    - info->type = new_serial.type;
    - info->close_delay = new_serial.close_delay;
    - info->closing_wait = new_serial.closing_wait;
    -
    -check_and_exit:
    - retval = startup(info);
    - return retval;
    -}
    -
    -/*
    - * get_lsr_info - get line status register info
    - *
    - * Purpose: Let user call ioctl() to get info when the UART physically
    - * is emptied. On bus types like RS485, the transmitter must
    - * release the bus after transmitting. This must be done when
    - * the transmit shift register is empty, not be done when the
    - * transmit holding register is empty. This functionality
    - * allows an RS485 driver to be written in user space.
    - */
    -static int get_lsr_info(struct mcf_serial * info, unsigned int *value)
    -{
    - volatile unsigned char *uartp;
    - unsigned long flags;
    - unsigned char status;
    -
    - local_irq_save(flags);
    - uartp = info->addr;
    - status = (uartp[MCFUART_USR] & MCFUART_USR_TXEMPTY) ? TIOCSER_TEMT : 0;
    - local_irq_restore(flags);
    -
    - return put_user(status,value);
    -}
    -
    -/*
    - * This routine sends a break character out the serial port.
    - */
    -static void send_break( struct mcf_serial * info, int duration)
    -{
    - volatile unsigned char *uartp;
    - unsigned long flags;
    -
    - if (!info->addr)
    - return;
    - set_current_state(TASK_INTERRUPTIBLE);
    - uartp = info->addr;
    -
    - local_irq_save(flags);
    - uartp[MCFUART_UCR] = MCFUART_UCR_CMDBREAKSTART;
    - schedule_timeout(duration);
    - uartp[MCFUART_UCR] = MCFUART_UCR_CMDBREAKSTOP;
    - local_irq_restore(flags);
    -}
    -
    -static int mcfrs_tiocmget(struct tty_struct *tty, struct file *file)
    -{
    - struct mcf_serial * info = (struct mcf_serial *)tty->driver_data;
    -
    - if (serial_paranoia_check(info, tty->name, "mcfrs_ioctl"))
    - return -ENODEV;
    - if (tty->flags & (1 << TTY_IO_ERROR))
    - return -EIO;
    -
    - return mcfrs_getsignals(info);
    -}
    -
    -static int mcfrs_tiocmset(struct tty_struct *tty, struct file *file,
    - unsigned int set, unsigned int clear)
    -{
    - struct mcf_serial * info = (struct mcf_serial *)tty->driver_data;
    - int rts = -1, dtr = -1;
    -
    - if (serial_paranoia_check(info, tty->name, "mcfrs_ioctl"))
    - return -ENODEV;
    - if (tty->flags & (1 << TTY_IO_ERROR))
    - return -EIO;
    -
    - if (set & TIOCM_RTS)
    - rts = 1;
    - if (set & TIOCM_DTR)
    - dtr = 1;
    - if (clear & TIOCM_RTS)
    - rts = 0;
    - if (clear & TIOCM_DTR)
    - dtr = 0;
    -
    - mcfrs_setsignals(info, dtr, rts);
    -
    - return 0;
    -}
    -
    -static int mcfrs_ioctl(struct tty_struct *tty, struct file * file,
    - unsigned int cmd, unsigned long arg)
    -{
    - struct mcf_serial * info = (struct mcf_serial *)tty->driver_data;
    - int retval, error;
    -
    - if (serial_paranoia_check(info, tty->name, "mcfrs_ioctl"))
    - return -ENODEV;
    -
    - if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
    - (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGWILD) &&
    - (cmd != TIOCSERSWILD) && (cmd != TIOCSERGSTRUCT)) {
    - if (tty->flags & (1 << TTY_IO_ERROR))
    - return -EIO;
    - }
    -
    - switch (cmd) {
    - case TCSBRK: /* SVID version: non-zero arg --> no break */
    - retval = tty_check_change(tty);
    - if (retval)
    - return retval;
    - tty_wait_until_sent(tty, 0);
    - if (!arg)
    - send_break(info, HZ/4); /* 1/4 second */
    - return 0;
    - case TCSBRKP: /* support for POSIX tcsendbreak() */
    - retval = tty_check_change(tty);
    - if (retval)
    - return retval;
    - tty_wait_until_sent(tty, 0);
    - send_break(info, arg ? arg*(HZ/10) : HZ/4);
    - return 0;
    - case TIOCGSERIAL:
    - if (access_ok(VERIFY_WRITE, (void *) arg,
    - sizeof(struct serial_struct)))
    - return get_serial_info(info,
    - (struct serial_struct *) arg);
    - return -EFAULT;
    - case TIOCSSERIAL:
    - return set_serial_info(info,
    - (struct serial_struct *) arg);
    - case TIOCSERGETLSR: /* Get line status register */
    - if (access_ok(VERIFY_WRITE, (void *) arg,
    - sizeof(unsigned int)))
    - return get_lsr_info(info, (unsigned int *) arg);
    - return -EFAULT;
    - case TIOCSERGSTRUCT:
    - error = copy_to_user((struct mcf_serial *) arg,
    - info, sizeof(struct mcf_serial));
    - if (error)
    - return -EFAULT;
    - return 0;
    -
    -#ifdef TIOCSET422
    - case TIOCSET422: {
    - unsigned int val;
    - get_user(val, (unsigned int *) arg);
    - mcf_setpa(MCFPP_PA11, (val ? 0 : MCFPP_PA11));
    - break;
    - }
    - case TIOCGET422: {
    - unsigned int val;
    - val = (mcf_getpa() & MCFPP_PA11) ? 0 : 1;
    - put_user(val, (unsigned int *) arg);
    - break;
    - }
    -#endif
    -
    - default:
    - return -ENOIOCTLCMD;
    - }
    - return 0;
    -}
    -
    -static void mcfrs_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
    -{
    - struct mcf_serial *info = (struct mcf_serial *)tty->driver_data;
    -
    - if (tty->termios->c_cflag == old_termios->c_cflag)
    - return;
    -
    - mcfrs_change_speed(info);
    -
    - if ((old_termios->c_cflag & CRTSCTS) &&
    - !(tty->termios->c_cflag & CRTSCTS)) {
    - tty->hw_stopped = 0;
    - mcfrs_setsignals(info, -1, 1);
    -#if 0
    - mcfrs_start(tty);
    -#endif
    - }
    -}
    -
    -/*
    - * ------------------------------------------------------------
    - * mcfrs_close()
    - *
    - * This routine is called when the serial port gets closed. First, we
    - * wait for the last remaining data to be sent. Then, we unlink its
    - * S structure from the interrupt chain if necessary, and we free
    - * that IRQ if nothing is left in the chain.
    - * ------------------------------------------------------------
    - */
    -static void mcfrs_close(struct tty_struct *tty, struct file * filp)
    -{
    - volatile unsigned char *uartp;
    - struct mcf_serial *info = (struct mcf_serial *)tty->driver_data;
    - unsigned long flags;
    -
    - if (!info || serial_paranoia_check(info, tty->name, "mcfrs_close"))
    - return;
    -
    - local_irq_save(flags);
    -
    - if (tty_hung_up_p(filp)) {
    - local_irq_restore(flags);
    - return;
    - }
    -
    -#ifdef SERIAL_DEBUG_OPEN
    - printk("mcfrs_close ttyS%d, count = %d\n", info->line, info->count);
    -#endif
    - if ((tty->count == 1) && (info->count != 1)) {
    - /*
    - * Uh, oh. tty->count is 1, which means that the tty
    - * 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("MCFRS: bad serial port count; tty->count is 1, "
    - "info->count is %d\n", info->count);
    - info->count = 1;
    - }
    - if (--info->count < 0) {
    - printk("MCFRS: bad serial port count for ttyS%d: %d\n",
    - info->line, info->count);
    - info->count = 0;
    - }
    - if (info->count) {
    - local_irq_restore(flags);
    - return;
    - }
    - info->flags |= ASYNC_CLOSING;
    -
    - /*
    - * Now we wait for the transmit buffer to clear; and we notify
    - * the line discipline to only process XON/XOFF characters.
    - */
    - tty->closing = 1;
    - if (info->closing_wait != ASYNC_CLOSING_WAIT_NONE)
    - tty_wait_until_sent(tty, info->closing_wait);
    -
    - /*
    - * At this point we stop accepting input. To do this, we
    - * disable the receive line status interrupts, and tell the
    - * interrupt driver to stop checking the data ready bit in the
    - * line status register.
    - */
    - info->imr &= ~MCFUART_UIR_RXREADY;
    - uartp = info->addr;
    - uartp[MCFUART_UIMR] = info->imr;
    -
    -#if 0
    - /* FIXME: do we need to keep this enabled for console?? */
    - if (mcfrs_console_inited && (mcfrs_console_port == info->line)) {
    - /* Do not disable the UART */ ;
    - } else
    -#endif
    - shutdown(info);
    - mcfrs_flush_buffer(tty);
    - tty_ldisc_flush(tty);
    -
    - tty->closing = 0;
    - info->event = 0;
    - info->port.tty = NULL;
    -#if 0
    - if (tty->ldisc.num != ldiscs[N_TTY].num) {
    - if (tty->ldisc.close)
    - (tty->ldisc.close)(tty);
    - tty->ldisc = ldiscs[N_TTY];
    - tty->termios->c_line = N_TTY;
    - if (tty->ldisc.open)
    - (tty->ldisc.open)(tty);
    - }
    -#endif
    - if (info->blocked_open) {
    - if (info->close_delay) {
    - msleep_interruptible(jiffies_to_msecs(info->close_delay));
    - }
    - wake_up_interruptible(&info->open_wait);
    - }
    - info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
    - wake_up_interruptible(&info->close_wait);
    - local_irq_restore(flags);
    -}
    -
    -/*
    - * mcfrs_wait_until_sent() --- wait until the transmitter is empty
    - */
    -static void
    -mcfrs_wait_until_sent(struct tty_struct *tty, int timeout)
    -{
    -#ifdef CONFIG_M5272
    -#define MCF5272_FIFO_SIZE 25 /* fifo size + shift reg */
    -
    - struct mcf_serial * info = (struct mcf_serial *)tty->driver_data;
    - volatile unsigned char *uartp;
    - unsigned long orig_jiffies, fifo_time, char_time, fifo_cnt;
    -
    - if (serial_paranoia_check(info, tty->name, "mcfrs_wait_until_sent"))
    - return;
    -
    - orig_jiffies = jiffies;
    -
    - /*
    - * Set the check interval to be 1/5 of the approximate time
    - * to send the entire fifo, and make it at least 1. The check
    - * interval should also be less than the timeout.
    - *
    - * Note: we have to use pretty tight timings here to satisfy
    - * the NIST-PCTS.
    - */
    - lock_kernel();
    -
    - fifo_time = (MCF5272_FIFO_SIZE * HZ * 10) / info->baud;
    - char_time = fifo_time / 5;
    - if (char_time == 0)
    - char_time = 1;
    - if (timeout && timeout < char_time)
    - char_time = timeout;
    -
    - /*
    - * Clamp the timeout period at 2 * the time to empty the
    - * fifo. Just to be safe, set the minimum at .5 seconds.
    - */
    - fifo_time *= 2;
    - if (fifo_time < (HZ/2))
    - fifo_time = HZ/2;
    - if (!timeout || timeout > fifo_time)
    - timeout = fifo_time;
    -
    - /*
    - * Account for the number of bytes in the UART
    - * transmitter FIFO plus any byte being shifted out.
    - */
    - uartp = (volatile unsigned char *) info->addr;
    - for (; {
    - fifo_cnt = (uartp[MCFUART_UTF] & MCFUART_UTF_TXB);
    - if ((uartp[MCFUART_USR] & (MCFUART_USR_TXREADY|
    - MCFUART_USR_TXEMPTY)) ==
    - MCFUART_USR_TXREADY)
    - fifo_cnt++;
    - if (fifo_cnt == 0)
    - break;
    - msleep_interruptible(jiffies_to_msecs(char_time));
    - if (signal_pending(current))
    - break;
    - if (timeout && time_after(jiffies, orig_jiffies + timeout))
    - break;
    - }
    - unlock_kernel();
    -#else
    - /*
    - * For the other coldfire models, assume all data has been sent
    - */
    -#endif
    -}
    -
    -/*
    - * mcfrs_hangup() --- called by tty_hangup() when a hangup is signaled.
    - */
    -void mcfrs_hangup(struct tty_struct *tty)
    -{
    - struct mcf_serial * info = (struct mcf_serial *)tty->driver_data;
    -
    - if (serial_paranoia_check(info, tty->name, "mcfrs_hangup"))
    - return;
    -
    - mcfrs_flush_buffer(tty);
    - shutdown(info);
    - info->event = 0;
    - info->count = 0;
    - info->flags &= ~ASYNC_NORMAL_ACTIVE;
    - info->port.tty = NULL;
    - wake_up_interruptible(&info->open_wait);
    -}
    -
    -/*
    - * ------------------------------------------------------------
    - * mcfrs_open() and friends
    - * ------------------------------------------------------------
    - */
    -static int block_til_ready(struct tty_struct *tty, struct file * filp,
    - struct mcf_serial *info)
    -{
    - DECLARE_WAITQUEUE(wait, current);
    - int retval;
    - int do_clocal = 0;
    -
    - /*
    - * If the device is in the middle of being closed, then block
    - * until it's done, and then try again.
    - */
    - if (info->flags & ASYNC_CLOSING) {
    - interruptible_sleep_on(&info->close_wait);
    -#ifdef SERIAL_DO_RESTART
    - if (info->flags & ASYNC_HUP_NOTIFY)
    - return -EAGAIN;
    - else
    - return -ERESTARTSYS;
    -#else
    - return -EAGAIN;
    -#endif
    - }
    -
    - /*
    - * If non-blocking mode is set, or the port is not enabled,
    - * then make the check up front and then exit.
    - */
    - if ((filp->f_flags & O_NONBLOCK) ||
    - (tty->flags & (1 << TTY_IO_ERROR))) {
    - info->flags |= ASYNC_NORMAL_ACTIVE;
    - return 0;
    - }
    -
    - if (tty->termios->c_cflag & CLOCAL)
    - do_clocal = 1;
    -
    - /*
    - * Block waiting for the carrier detect and the line to become
    - * free (i.e., not in use by the callout). While we are in
    - * this loop, info->count is dropped by one, so that
    - * mcfrs_close() knows when to free things. We restore it upon
    - * exit, either normal or abnormal.
    - */
    - retval = 0;
    - add_wait_queue(&info->open_wait, &wait);
    -#ifdef SERIAL_DEBUG_OPEN
    - printk("block_til_ready before block: ttyS%d, count = %d\n",
    - info->line, info->count);
    -#endif
    - info->count--;
    - info->blocked_open++;
    - while (1) {
    - local_irq_disable();
    - mcfrs_setsignals(info, 1, 1);
    - local_irq_enable();
    - current->state = TASK_INTERRUPTIBLE;
    - if (tty_hung_up_p(filp) ||
    - !(info->flags & ASYNC_INITIALIZED)) {
    -#ifdef SERIAL_DO_RESTART
    - if (info->flags & ASYNC_HUP_NOTIFY)
    - retval = -EAGAIN;
    - else
    - retval = -ERESTARTSYS;
    -#else
    - retval = -EAGAIN;
    -#endif
    - break;
    - }
    - if (!(info->flags & ASYNC_CLOSING) &&
    - (do_clocal || (mcfrs_getsignals(info) & TIOCM_CD)))
    - break;
    - if (signal_pending(current)) {
    - retval = -ERESTARTSYS;
    - break;
    - }
    -#ifdef SERIAL_DEBUG_OPEN
    - printk("block_til_ready blocking: ttyS%d, count = %d\n",
    - info->line, info->count);
    -#endif
    - schedule();
    - }
    - current->state = TASK_RUNNING;
    - remove_wait_queue(&info->open_wait, &wait);
    - if (!tty_hung_up_p(filp))
    - info->count++;
    - info->blocked_open--;
    -#ifdef SERIAL_DEBUG_OPEN
    - printk("block_til_ready after blocking: ttyS%d, count = %d\n",
    - info->line, info->count);
    -#endif
    - if (retval)
    - return retval;
    - info->flags |= ASYNC_NORMAL_ACTIVE;
    - return 0;
    -}
    -
    -/*
    - * This routine is called whenever a serial port is opened. It
    - * enables interrupts for a serial port, linking in its structure into
    - * the IRQ chain. It also performs the serial-specific
    - * initialization for the tty structure.
    - */
    -int mcfrs_open(struct tty_struct *tty, struct file * filp)
    -{
    - struct mcf_serial *info;
    - int retval, line;
    -
    - line = tty->index;
    - if ((line < 0) || (line >= NR_PORTS))
    - return -ENODEV;
    - info = mcfrs_table + line;
    - if (serial_paranoia_check(info, tty->name, "mcfrs_open"))
    - return -ENODEV;
    -#ifdef SERIAL_DEBUG_OPEN
    - printk("mcfrs_open %s, count = %d\n", tty->name, info->count);
    -#endif
    - info->count++;
    - tty->driver_data = info;
    - info->port.tty = tty;
    -
    - /*
    - * Start up serial port
    - */
    - retval = startup(info);
    - if (retval)
    - return retval;
    -
    - retval = block_til_ready(tty, filp, info);
    - if (retval) {
    -#ifdef SERIAL_DEBUG_OPEN
    - printk("mcfrs_open returning after block_til_ready with %d\n",
    - retval);
    -#endif
    - return retval;
    - }
    -
    -#ifdef SERIAL_DEBUG_OPEN
    - printk("mcfrs_open %s successful...\n", tty->name);
    -#endif
    - return 0;
    -}
    -
    -/*
    - * Based on the line number set up the internal interrupt stuff.
    - */
    -static void mcfrs_irqinit(struct mcf_serial *info)
    -{
    -#if defined(CONFIG_M5272)
    - volatile unsigned long *icrp;
    - volatile unsigned long *portp;
    - volatile unsigned char *uartp;
    -
    - uartp = info->addr;
    - icrp = (volatile unsigned long *) (MCF_MBAR + MCFSIM_ICR2);
    -
    - switch (info->line) {
    - case 0:
    - *icrp = 0xe0000000;
    - break;
    - case 1:
    - *icrp = 0x0e000000;
    - break;
    - default:
    - printk("MCFRS: don't know how to handle UART %d interrupt?\n",
    - info->line);
    - return;
    - }
    -
    - /* Enable the output lines for the serial ports */
    - portp = (volatile unsigned long *) (MCF_MBAR + MCFSIM_PBCNT);
    - *portp = (*portp & ~0x000000ff) | 0x00000055;
    - portp = (volatile unsigned long *) (MCF_MBAR + MCFSIM_PDCNT);
    - *portp = (*portp & ~0x000003fc) | 0x000002a8;
    -#elif defined(CONFIG_M523x) || defined(CONFIG_M527x) || defined(CONFIG_M528x)
    - volatile unsigned char *icrp, *uartp;
    - volatile unsigned long *imrp;
    -
    - uartp = info->addr;
    -
    - icrp = (volatile unsigned char *) (MCF_MBAR + MCFICM_INTC0 +
    - MCFINTC_ICR0 + MCFINT_UART0 + info->line);
    - *icrp = 0x30 + info->line; /* level 6, line based priority */
    -
    - imrp = (volatile unsigned long *) (MCF_MBAR + MCFICM_INTC0 +
    - MCFINTC_IMRL);
    - *imrp &= ~((1 << (info->irq - MCFINT_VECBASE)) | 1);
    -#if defined(CONFIG_M527x)
    - {
    - /*
    - * External Pin Mask Setting & Enable External Pin for Interface
    - * mrcbis@aliceposta.it
    - */
    - u16 *serpin_enable_mask;
    - serpin_enable_mask = (u16 *) (MCF_IPSBAR + MCF_GPIO_PAR_UART);
    - if (info->line == 0)
    - *serpin_enable_mask |= UART0_ENABLE_MASK;
    - else if (info->line == 1)
    - *serpin_enable_mask |= UART1_ENABLE_MASK;
    - else if (info->line == 2)
    - *serpin_enable_mask |= UART2_ENABLE_MASK;
    - }
    -#endif
    -#if defined(CONFIG_M528x)
    - /* make sure PUAPAR is set for UART0 and UART1 */
    - if (info->line < 2) {
    - volatile unsigned char *portp = (volatile unsigned char *) (MCF_MBAR + MCF5282_GPIO_PUAPAR);
    - *portp |= (0x03 << (info->line * 2));
    - }
    -#endif
    -#elif defined(CONFIG_M520x)
    - volatile unsigned char *icrp, *uartp;
    - volatile unsigned long *imrp;
    -
    - uartp = info->addr;
    -
    - icrp = (volatile unsigned char *) (MCF_MBAR + MCFICM_INTC0 +
    - MCFINTC_ICR0 + MCFINT_UART0 + info->line);
    - *icrp = 0x03;
    -
    - imrp = (volatile unsigned long *) (MCF_MBAR + MCFICM_INTC0 +
    - MCFINTC_IMRL);
    - *imrp &= ~((1 << (info->irq - MCFINT_VECBASE)) | 1);
    - if (info->line < 2) {
    - unsigned short *uart_par;
    - uart_par = (unsigned short *)(MCF_IPSBAR + MCF_GPIO_PAR_UART);
    - if (info->line == 0)
    - *uart_par |= MCF_GPIO_PAR_UART_PAR_UTXD0
    - | MCF_GPIO_PAR_UART_PAR_URXD0;
    - else if (info->line == 1)
    - *uart_par |= MCF_GPIO_PAR_UART_PAR_UTXD1
    - | MCF_GPIO_PAR_UART_PAR_URXD1;
    - } else if (info->line == 2) {
    - unsigned char *feci2c_par;
    - feci2c_par = (unsigned char *)(MCF_IPSBAR + MCF_GPIO_PAR_FECI2C);
    - *feci2c_par &= ~0x0F;
    - *feci2c_par |= MCF_GPIO_PAR_FECI2C_PAR_SCL_UTXD2
    - | MCF_GPIO_PAR_FECI2C_PAR_SDA_URXD2;
    - }
    -#elif defined(CONFIG_M532x)
    - volatile unsigned char *uartp;
    - uartp = info->addr;
    - switch (info->line) {
    - case 0:
    - MCF_INTC0_ICR26 = 0x3;
    - MCF_INTC0_CIMR = 26;
    - /* GPIO initialization */
    - MCF_GPIO_PAR_UART |= 0x000F;
    - break;
    - case 1:
    - MCF_INTC0_ICR27 = 0x3;
    - MCF_INTC0_CIMR = 27;
    - /* GPIO initialization */
    - MCF_GPIO_PAR_UART |= 0x0FF0;
    - break;
    - case 2:
    - MCF_INTC0_ICR28 = 0x3;
    - MCF_INTC0_CIMR = 28;
    - /* GPIOs also must be initalized, depends on board */
    - break;
    - }
    -#else
    - volatile unsigned char *icrp, *uartp;
    -
    - switch (info->line) {
    - case 0:
    - icrp = (volatile unsigned char *) (MCF_MBAR + MCFSIM_UART1ICR);
    - *icrp = /*MCFSIM_ICR_AUTOVEC |*/ MCFSIM_ICR_LEVEL6 |
    - MCFSIM_ICR_PRI1;
    - mcf_setimr(mcf_getimr() & ~MCFSIM_IMR_UART1);
    - break;
    - case 1:
    - icrp = (volatile unsigned char *) (MCF_MBAR + MCFSIM_UART2ICR);
    - *icrp = /*MCFSIM_ICR_AUTOVEC |*/ MCFSIM_ICR_LEVEL6 |
    - MCFSIM_ICR_PRI2;
    - mcf_setimr(mcf_getimr() & ~MCFSIM_IMR_UART2);
    - break;
    - default:
    - printk("MCFRS: don't know how to handle UART %d interrupt?\n",
    - info->line);
    - return;
    - }
    -
    - uartp = info->addr;
    - uartp[MCFUART_UIVR] = info->irq;
    -#endif
    -
    - /* Clear mask, so no surprise interrupts. */
    - uartp[MCFUART_UIMR] = 0;
    -
    - if (request_irq(info->irq, mcfrs_interrupt, IRQF_DISABLED,
    - "ColdFire UART", NULL)) {
    - printk("MCFRS: Unable to attach ColdFire UART %d interrupt "
    - "vector=%d\n", info->line, info->irq);
    - }
    -
    - return;
    -}
    -
    -
    -char *mcfrs_drivername = "ColdFire internal UART serial driver version 1.00\n";
    -
    -
    -/*
    - * Serial stats reporting...
    - */
    -int mcfrs_readproc(char *page, char **start, off_t off, int count,
    - int *eof, void *data)
    -{
    - struct mcf_serial *info;
    - char str[20];
    - int len, sigs, i;
    -
    - len = sprintf(page, mcfrs_drivername);
    - for (i = 0; (i < NR_PORTS); i++) {
    - info = &mcfrs_table[i];
    - len += sprintf((page + len), "%d: port:%x irq=%d baud:%d ",
    - i, (unsigned int) info->addr, info->irq, info->baud);
    - if (info->stats.rx || info->stats.tx)
    - len += sprintf((page + len), "tx:%d rx:%d ",
    - info->stats.tx, info->stats.rx);
    - if (info->stats.rxframing)
    - len += sprintf((page + len), "fe:%d ",
    - info->stats.rxframing);
    - if (info->stats.rxparity)
    - len += sprintf((page + len), "pe:%d ",
    - info->stats.rxparity);
    - if (info->stats.rxbreak)
    - len += sprintf((page + len), "brk:%d ",
    - info->stats.rxbreak);
    - if (info->stats.rxoverrun)
    - len += sprintf((page + len), "oe:%d ",
    - info->stats.rxoverrun);
    -
    - str[0] = str[1] = 0;
    - if ((sigs = mcfrs_getsignals(info))) {
    - if (sigs & TIOCM_RTS)
    - strcat(str, "|RTS");
    - if (sigs & TIOCM_CTS)
    - strcat(str, "|CTS");
    - if (sigs & TIOCM_DTR)
    - strcat(str, "|DTR");
    - if (sigs & TIOCM_CD)
    - strcat(str, "|CD");
    - }
    -
    - len += sprintf((page + len), "%s\n", &str[1]);
    - }
    -
    - return(len);
    -}
    -
    -
    -/* Finally, routines used to initialize the serial driver. */
    -
    -static void show_serial_version(void)
    -{
    - printk(mcfrs_drivername);
    -}
    -
    -static const struct tty_operations mcfrs_ops = {
    - .open = mcfrs_open,
    - .close = mcfrs_close,
    - .write = mcfrs_write,
    - .flush_chars = mcfrs_flush_chars,
    - .write_room = mcfrs_write_room,
    - .chars_in_buffer = mcfrs_chars_in_buffer,
    - .flush_buffer = mcfrs_flush_buffer,
    - .ioctl = mcfrs_ioctl,
    - .throttle = mcfrs_throttle,
    - .unthrottle = mcfrs_unthrottle,
    - .set_termios = mcfrs_set_termios,
    - .stop = mcfrs_stop,
    - .start = mcfrs_start,
    - .hangup = mcfrs_hangup,
    - .read_proc = mcfrs_readproc,
    - .wait_until_sent = mcfrs_wait_until_sent,
    - .tiocmget = mcfrs_tiocmget,
    - .tiocmset = mcfrs_tiocmset,
    -};
    -
    -/* mcfrs_init inits the driver */
    -static int __init
    -mcfrs_init(void)
    -{
    - struct mcf_serial *info;
    - unsigned long flags;
    - int i;
    -
    - /* Setup base handler, and timer table. */
    -#ifdef MCFPP_DCD0
    - init_timer(&mcfrs_timer_struct);
    - mcfrs_timer_struct.function = mcfrs_timer;
    - mcfrs_timer_struct.data = 0;
    - mcfrs_timer_struct.expires = jiffies + HZ/25;
    - add_timer(&mcfrs_timer_struct);
    - mcfrs_ppstatus = mcf_getppdata() & (MCFPP_DCD0 | MCFPP_DCD1);
    -#endif
    - mcfrs_serial_driver = alloc_tty_driver(NR_PORTS);
    - if (!mcfrs_serial_driver)
    - return -ENOMEM;
    -
    - show_serial_version();
    -
    - /* Initialize the tty_driver structure */
    - mcfrs_serial_driver->owner = THIS_MODULE;
    - mcfrs_serial_driver->name = "ttyS";
    - mcfrs_serial_driver->driver_name = "mcfserial";
    - mcfrs_serial_driver->major = TTY_MAJOR;
    - mcfrs_serial_driver->minor_start = 64;
    - mcfrs_serial_driver->type = TTY_DRIVER_TYPE_SERIAL;
    - mcfrs_serial_driver->subtype = SERIAL_TYPE_NORMAL;
    - mcfrs_serial_driver->init_termios = tty_std_termios;
    -
    - mcfrs_serial_driver->init_termios.c_cflag =
    - mcfrs_console_cbaud | CS8 | CREAD | HUPCL | CLOCAL;
    - mcfrs_serial_driver->flags = TTY_DRIVER_REAL_RAW;
    -
    - tty_set_operations(mcfrs_serial_driver, &mcfrs_ops);
    -
    - if (tty_register_driver(mcfrs_serial_driver)) {
    - printk("MCFRS: Couldn't register serial driver\n");
    - put_tty_driver(mcfrs_serial_driver);
    - return(-EBUSY);
    - }
    -
    - local_irq_save(flags);
    -
    - /*
    - * Configure all the attached serial ports.
    - */
    - for (i = 0, info = mcfrs_table; (i < NR_PORTS); i++, info++) {
    - info->magic = SERIAL_MAGIC;
    - info->line = i;
    - info->port.tty = NULL;
    - info->custom_divisor = 16;
    - info->close_delay = 50;
    - info->closing_wait = 3000;
    - info->x_char = 0;
    - info->event = 0;
    - info->count = 0;
    - info->blocked_open = 0;
    - INIT_WORK(&info->tqueue, mcfrs_offintr);
    - INIT_WORK(&info->tqueue_hangup, do_serial_hangup);
    - init_waitqueue_head(&info->open_wait);
    - init_waitqueue_head(&info->close_wait);
    -
    - info->imr = 0;
    - mcfrs_setsignals(info, 0, 0);
    - mcfrs_irqinit(info);
    -
    - printk("ttyS%d at 0x%04x (irq = %d)", info->line,
    - (unsigned int) info->addr, info->irq);
    - printk(" is a builtin ColdFire UART\n");
    - }
    -
    - local_irq_restore(flags);
    - return 0;
    -}
    -
    -module_init(mcfrs_init);
    -
    -/************************************************** **************************/
    -/* Serial Console */
    -/************************************************** **************************/
    -
    -/*
    - * Quick and dirty UART initialization, for console output.
    - */
    -
    -void mcfrs_init_console(void)
    -{
    - volatile unsigned char *uartp;
    - unsigned int clk;
    -
    - /*
    - * Reset UART, get it into known state...
    - */
    - uartp = (volatile unsigned char *) (MCF_MBAR +
    - (mcfrs_console_port ? MCFUART_BASE2 : MCFUART_BASE1));
    -
    - uartp[MCFUART_UCR] = MCFUART_UCR_CMDRESETRX; /* reset RX */
    - uartp[MCFUART_UCR] = MCFUART_UCR_CMDRESETTX; /* reset TX */
    - uartp[MCFUART_UCR] = MCFUART_UCR_CMDRESETMRPTR; /* reset MR pointer */
    -
    - /*
    - * Set port for defined baud , 8 data bits, 1 stop bit, no parity.
    - */
    - uartp[MCFUART_UMR] = MCFUART_MR1_PARITYNONE | MCFUART_MR1_CS8;
    - uartp[MCFUART_UMR] = MCFUART_MR2_STOP1;
    -
    -#ifdef CONFIG_M5272
    -{
    - /*
    - * For the MCF5272, also compute the baudrate fraction.
    - */
    - int fraction = MCF_BUSCLK - (clk * 32 * mcfrs_console_baud);
    - fraction *= 16;
    - fraction /= (32 * mcfrs_console_baud);
    - uartp[MCFUART_UFPD] = (fraction & 0xf); /* set fraction */
    - clk = (MCF_BUSCLK / mcfrs_console_baud) / 32;
    -}
    -#else
    - clk = ((MCF_BUSCLK / mcfrs_console_baud) + 16) / 32; /* set baud */
    -#endif
    -
    - uartp[MCFUART_UBG1] = (clk & 0xff00) >> 8; /* set msb baud */
    - uartp[MCFUART_UBG2] = (clk & 0xff); /* set lsb baud */
    - uartp[MCFUART_UCSR] = MCFUART_UCSR_RXCLKTIMER | MCFUART_UCSR_TXCLKTIMER;
    - uartp[MCFUART_UCR] = MCFUART_UCR_RXENABLE | MCFUART_UCR_TXENABLE;
    -
    - mcfrs_console_inited++;
    - return;
    -}
    -
    -
    -/*
    - * Setup for console. Argument comes from the boot command line.
    - */
    -
    -int mcfrs_console_setup(struct console *cp, char *arg)
    -{
    - int i, n = CONSOLE_BAUD_RATE;
    -
    - if (!cp)
    - return(-1);
    -
    - if (!strncmp(cp->name, "ttyS", 4))
    - mcfrs_console_port = cp->index;
    - else if (!strncmp(cp->name, "cua", 3))
    - mcfrs_console_port = cp->index;
    - else
    - return(-1);
    -
    - if (arg)
    - n = simple_strtoul(arg,NULL,0);
    - for (i = 0; i < MCFRS_BAUD_TABLE_SIZE; i++)
    - if (mcfrs_baud_table[i] == n)
    - break;
    - if (i < MCFRS_BAUD_TABLE_SIZE) {
    - mcfrs_console_baud = n;
    - mcfrs_console_cbaud = 0;
    - if (i > 15) {
    - mcfrs_console_cbaud |= CBAUDEX;
    - i -= 15;
    - }
    - mcfrs_console_cbaud |= i;
    - }
    - mcfrs_init_console(); /* make sure baud rate changes */
    - return(0);
    -}
    -
    -
    -static struct tty_driver *mcfrs_console_device(struct console *c, int *index)
    -{
    - *index = c->index;
    - return mcfrs_serial_driver;
    -}
    -
    -
    -/*
    - * Output a single character, using UART polled mode.
    - * This is used for console output.
    - */
    -
    -int mcfrs_put_char(char ch)
    -{
    - volatile unsigned char *uartp;
    - unsigned long flags;
    - int i;
    -
    - uartp = (volatile unsigned char *) (MCF_MBAR +
    - (mcfrs_console_port ? MCFUART_BASE2 : MCFUART_BASE1));
    -
    - local_irq_save(flags);
    - for (i = 0; (i < 0x10000); i++) {
    - if (uartp[MCFUART_USR] & MCFUART_USR_TXREADY)
    - break;
    - }
    - if (i < 0x10000) {
    - uartp[MCFUART_UTB] = ch;
    - for (i = 0; (i < 0x10000); i++)
    - if (uartp[MCFUART_USR] & MCFUART_USR_TXEMPTY)
    - break;
    - }
    - if (i >= 0x10000)
    - mcfrs_init_console(); /* try and get it back */
    - local_irq_restore(flags);
    -
    - return 1;
    -}
    -
    -
    -/*
    - * rs_console_write is registered for printk output.
    - */
    -
    -void mcfrs_console_write(struct console *cp, const char *p, unsigned len)
    -{
    - if (!mcfrs_console_inited)
    - mcfrs_init_console();
    - while (len-- > 0) {
    - if (*p == '\n')
    - mcfrs_put_char('\r');
    - mcfrs_put_char(*p++);
    - }
    -}
    -
    -/*
    - * declare our consoles
    - */
    -
    -struct console mcfrs_console = {
    - .name = "ttyS",
    - .write = mcfrs_console_write,
    - .device = mcfrs_console_device,
    - .setup = mcfrs_console_setup,
    - .flags = CON_PRINTBUFFER,
    - .index = -1,
    -};
    -
    -static int __init mcfrs_console_init(void)
    -{
    - register_console(&mcfrs_console);
    - return 0;
    -}
    -
    -console_initcall(mcfrs_console_init);
    -
    -/************************************************** **************************/
    diff --git a/drivers/serial/mcfserial.h b/drivers/serial/mcfserial.h
    deleted file mode 100644
    index 56420e2..0000000
    --- a/drivers/serial/mcfserial.h
    +++ /dev/null
    @@ -1,74 +0,0 @@
    -/*
    - * mcfserial.c -- serial driver for ColdFire internal UARTS.
    - *
    - * Copyright (c) 1999 Greg Ungerer
    - * Copyright (c) 2000-2001 Lineo, Inc.
    - * Copyright (c) 2002 SnapGear Inc.,
    - *
    - * Based on code from 68332serial.c which was:
    - *
    - * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
    - * Copyright (C) 1998 TSHG
    - * Copyright (c) 1999 Rt-Control Inc.
    - */
    -#ifndef _MCF_SERIAL_H
    -#define _MCF_SERIAL_H
    -
    -#include
    -
    -#ifdef __KERNEL__
    -
    -/*
    - * Define a local serial stats structure.
    - */
    -
    -struct mcf_stats {
    - unsigned int rx;
    - unsigned int tx;
    - unsigned int rxbreak;
    - unsigned int rxframing;
    - unsigned int rxparity;
    - unsigned int rxoverrun;
    -};
    -
    -
    -/*
    - * This is our internal structure for each serial port's state.
    - * Each serial port has one of these structures associated with it.
    - */
    -
    -struct mcf_serial {
    - int magic;
    - volatile unsigned char *addr; /* UART memory address */
    - int irq;
    - int flags; /* defined in tty.h */
    - int type; /* UART type */
    - struct tty_struct *tty;
    - unsigned char imr; /* Software imr register */
    - unsigned int baud;
    - int sigs;
    - int custom_divisor;
    - int x_char; /* xon/xoff character */
    - int baud_base;
    - int close_delay;
    - unsigned short closing_wait;
    - unsigned short closing_wait2;
    - unsigned long event;
    - int line;
    - int count; /* # of fd on device */
    - int blocked_open; /* # of blocked opens */
    - unsigned char *xmit_buf;
    - int xmit_head;
    - int xmit_tail;
    - int xmit_cnt;
    - struct mcf_stats stats;
    - struct work_struct tqueue;
    - struct work_struct tqueue_hangup;
    - wait_queue_head_t open_wait;
    - wait_queue_head_t close_wait;
    -
    -};
    -
    -#endif /* __KERNEL__ */
    -
    -#endif /* _MCF_SERIAL_H */

    --
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

  5. [PATCH 09/80] Blackfin Serial Driver: Remove useless stop

    From: Sonic Zhang

    Signed-off-by: Sonic Zhang
    Signed-off-by: Bryan Wu
    Signed-off-by: Alan Cox
    ---

    drivers/serial/bfin_5xx.c | 3 ---
    1 files changed, 0 insertions(+), 3 deletions(-)


    diff --git a/drivers/serial/bfin_5xx.c b/drivers/serial/bfin_5xx.c
    index 382fb8d..8d2d757 100644
    --- a/drivers/serial/bfin_5xx.c
    +++ b/drivers/serial/bfin_5xx.c
    @@ -320,9 +320,6 @@ static void bfin_serial_tx_chars(struct bfin_serial_port *uart)

    if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
    uart_write_wakeup(&uart->port);
    -
    - if (uart_circ_empty(xmit))
    - bfin_serial_stop_tx(&uart->port);
    }

    static irqreturn_t bfin_serial_rx_int(int irq, void *dev_id)

    --
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

  6. [PATCH 37/80] tty: Cris has a nice RS485 ioctl so we should steal it

    From: Alan Cox

    JP Tosoni observed:

    "About a RS485 ioctl: could you consider the attached files which are
    already in the Linux kernel (in include/asm-cris). They define a
    TIOCSERSETRS485 (ioctl.h), and the data structure (rs485.h)
    with allows to specify timings. Sounds just like what we want ?"

    and he's right: sort of. Rework the structure to use flag bits and make the
    time delay a fixed sized field so we don't get 32/64bit problems. Add the ioctls
    to x86 so that people know what to add to their platform of choice.

    Signed-off-by: Alan Cox
    ---

    include/asm-x86/ioctls.h | 2 ++
    include/linux/serial.h | 16 ++++++++++++++++
    2 files changed, 18 insertions(+), 0 deletions(-)


    diff --git a/include/asm-x86/ioctls.h b/include/asm-x86/ioctls.h
    index 3366035..1a8ac45 100644
    --- a/include/asm-x86/ioctls.h
    +++ b/include/asm-x86/ioctls.h
    @@ -51,6 +51,8 @@
    #define TCSETS2 _IOW('T', 0x2B, struct termios2)
    #define TCSETSW2 _IOW('T', 0x2C, struct termios2)
    #define TCSETSF2 _IOW('T', 0x2D, struct termios2)
    +#define TIOCGRS485 0x542E
    +#define TIOCSRS485 0x542F
    #define TIOCGPTN _IOR('T', 0x30, unsigned int)
    /* Get Pty Number (of pty-mux device) */
    #define TIOCSPTLCK _IOW('T', 0x31, int) /* Lock/unlock Pty */
    diff --git a/include/linux/serial.h b/include/linux/serial.h
    index deb7143..1ea8d92 100644
    --- a/include/linux/serial.h
    +++ b/include/linux/serial.h
    @@ -173,6 +173,22 @@ struct serial_icounter_struct {
    int reserved[9];
    };

    +/*
    + * Serial interface for controlling RS485 settings on chips with suitable
    + * support. Set with TIOCSRS485 and get with TIOCGRS485 if supported by your
    + * platform. The set function returns the new state, with any unsupported bits
    + * reverted appropriately.
    + */
    +
    +struct serial_rs485 {
    + __u32 flags; /* RS485 feature flags */
    +#define SER_RS485_ENABLED (1 << 0)
    +#define SER_RS485_RTS_ON_SEND (1 << 1)
    +#define SER_RS485_RTS_AFTER_SEND (1 << 2)
    + __u32 delay_rts_before_send; /* Milliseconds */
    + __u32 padding[6]; /* Memory is cheap, new structs
    + are a royal PITA .. */
    +};

    #ifdef __KERNEL__
    #include

    --
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

  7. [PATCH 27/80] serial_8250: pci_enable_device fail is not fully handled

    From: Alan Cox

    talking about leaks - I noticed that the 'check return of
    pci_enable_dev()' in the 8250 pci resume function finally made it in
    pite my objections against it (causing stuff in higher levels to leak).

    Signed-off-by: Alan Cox
    ---

    drivers/serial/8250_pci.c | 4 ++--
    1 files changed, 2 insertions(+), 2 deletions(-)


    diff --git a/drivers/serial/8250_pci.c b/drivers/serial/8250_pci.c
    index c2f2393..c014ffb 100644
    --- a/drivers/serial/8250_pci.c
    +++ b/drivers/serial/8250_pci.c
    @@ -2041,9 +2041,9 @@ static int pciserial_resume_one(struct pci_dev *dev)
    * The device may have been disabled. Re-enable it.
    */
    err = pci_enable_device(dev);
    + /* FIXME: We cannot simply error out here */
    if (err)
    - return err;
    -
    + printk(KERN_ERR "pciserial: Unable to re-enable ports, trying to continue.\n");
    pciserial_resume_ports(priv);
    }
    return 0;

    --
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

  8. [PATCH 22/80] serial: Make uart_port's ioport "unsigned long".

    From: David Miller

    Otherwise the top 32-bits of the resource value get chopped
    off on 64-bit systems, and the resulting I/O accesses go to
    random places.

    Thanks to testing and debugging by Josip Rodin, which helped
    track this down.

    Signed-off-by: David S. Miller
    Signed-off-by: Alan Cox
    ---

    include/linux/serial_core.h | 2 +-
    1 files changed, 1 insertions(+), 1 deletions(-)


    diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h
    index 3b2f6c0..e27f216 100644
    --- a/include/linux/serial_core.h
    +++ b/include/linux/serial_core.h
    @@ -241,7 +241,7 @@ typedef unsigned int __bitwise__ upf_t;

    struct uart_port {
    spinlock_t lock; /* port lock */
    - unsigned int iobase; /* in/out[bwl] */
    + unsigned long iobase; /* in/out[bwl] */
    unsigned char __iomem *membase; /* read/write[bwl] */
    unsigned int irq; /* irq number */
    unsigned int uartclk; /* base uart clock */

    --
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

  9. [PATCH 24/80] serial-make-uart_ports-ioport-unsigned-long-fix

    From: Andrew Morton

    Signed-off-by: Andrew Morton
    Signed-off-by: Alan Cox
    ---

    drivers/serial/serial_core.c | 5 ++---
    1 files changed, 2 insertions(+), 3 deletions(-)


    diff --git a/drivers/serial/serial_core.c b/drivers/serial/serial_core.c
    index f977c98..308588e 100644
    --- a/drivers/serial/serial_core.c
    +++ b/drivers/serial/serial_core.c
    @@ -2154,12 +2154,11 @@ uart_report_port(struct uart_driver *drv, struct uart_port *port)

    switch (port->iotype) {
    case UPIO_PORT:
    - snprintf(address, sizeof(address),
    - "I/O 0x%x", port->iobase);
    + snprintf(address, sizeof(address), "I/O 0x%lx", port->iobase);
    break;
    case UPIO_HUB6:
    snprintf(address, sizeof(address),
    - "I/O 0x%x offset 0x%x", port->iobase, port->hub6);
    + "I/O 0x%lx offset 0x%x", port->iobase, port->hub6);
    break;
    case UPIO_MEM:
    case UPIO_MEM32:

    --
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

  10. [PATCH 28/80] 8250: remove a few inlines of dubious value

    From: \\\"Will Newton\\\"

    Remove some inlines from various functions that are called once, are too
    big to inline, or are called only from slow path code. This saves around
    300 bytes of code for me.

    Signed-off-by: Will Newton
    Signed-off-by: Andrew Morton
    Signed-off-by: Alan Cox
    ---

    drivers/serial/8250.c | 9 ++++-----
    1 files changed, 4 insertions(+), 5 deletions(-)


    diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c
    index 9ccc563..ed593c4 100644
    --- a/drivers/serial/8250.c
    +++ b/drivers/serial/8250.c
    @@ -536,7 +536,7 @@ static unsigned int serial_icr_read(struct uart_8250_port *up, int offset)
    /*
    * FIFO support.
    */
    -static inline void serial8250_clear_fifos(struct uart_8250_port *p)
    +static void serial8250_clear_fifos(struct uart_8250_port *p)
    {
    if (p->capabilities & UART_CAP_FIFO) {
    serial_outp(p, UART_FCR, UART_FCR_ENABLE_FIFO);
    @@ -551,7 +551,7 @@ static inline void serial8250_clear_fifos(struct uart_8250_port *p)
    * capability" bit enabled. Note that on XR16C850s, we need to
    * reset LCR to write to IER.
    */
    -static inline void serial8250_set_sleep(struct uart_8250_port *p, int sleep)
    +static void serial8250_set_sleep(struct uart_8250_port *p, int sleep)
    {
    if (p->capabilities & UART_CAP_SLEEP) {
    if (p->capabilities & UART_CAP_EFR) {
    @@ -1424,8 +1424,7 @@ static unsigned int check_modem_status(struct uart_8250_port *up)
    /*
    * This handles the interrupt from one port.
    */
    -static inline void
    -serial8250_handle_port(struct uart_8250_port *up)
    +static void serial8250_handle_port(struct uart_8250_port *up)
    {
    unsigned int status;
    unsigned long flags;
    @@ -1719,7 +1718,7 @@ static void serial8250_break_ctl(struct uart_port *port, int break_state)
    /*
    * Wait for transmitter & holding register to empty
    */
    -static inline void wait_for_xmitr(struct uart_8250_port *up, int bits)
    +static void wait_for_xmitr(struct uart_8250_port *up, int bits)
    {
    unsigned int status, tmout = 10000;


    --
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

  11. [PATCH 38/80] tty: ipw need reworking

    From: Alan Cox

    This came in via another tree and unfortunately is rather broken on
    the tty side. Comment the apparent locking problems for someone who knows
    the driver to look at.

    Fix the termios and other ioctl handling. The driver was calling the wrong
    methods for what it wanted to do but the right ones existed so its a simple
    fix up.

    Signed-off-by: Alan Cox
    ---

    drivers/char/pcmcia/ipwireless/tty.c | 19 ++++++++++---------
    1 files changed, 10 insertions(+), 9 deletions(-)


    diff --git a/drivers/char/pcmcia/ipwireless/tty.c b/drivers/char/pcmcia/ipwireless/tty.c
    index 3a23e76..569f2f7 100644
    --- a/drivers/char/pcmcia/ipwireless/tty.c
    +++ b/drivers/char/pcmcia/ipwireless/tty.c
    @@ -276,6 +276,7 @@ static int ipw_write_room(struct tty_struct *linux_tty)
    struct ipw_tty *tty = linux_tty->driver_data;
    int room;

    + /* FIXME: Exactly how is the tty object locked here .. */
    if (!tty)
    return -ENODEV;

    @@ -397,6 +398,7 @@ static int set_control_lines(struct ipw_tty *tty, unsigned int set,
    static int ipw_tiocmget(struct tty_struct *linux_tty, struct file *file)
    {
    struct ipw_tty *tty = linux_tty->driver_data;
    + /* FIXME: Exactly how is the tty object locked here .. */

    if (!tty)
    return -ENODEV;
    @@ -412,6 +414,7 @@ ipw_tiocmset(struct tty_struct *linux_tty, struct file *file,
    unsigned int set, unsigned int clear)
    {
    struct ipw_tty *tty = linux_tty->driver_data;
    + /* FIXME: Exactly how is the tty object locked here .. */

    if (!tty)
    return -ENODEV;
    @@ -433,6 +436,8 @@ static int ipw_ioctl(struct tty_struct *linux_tty, struct file *file,
    if (!tty->open_count)
    return -EINVAL;

    + /* FIXME: Exactly how is the tty object locked here .. */
    +
    switch (cmd) {
    case TIOCGSERIAL:
    return ipwireless_get_serial_info(tty, (void __user *) arg);
    @@ -467,13 +472,6 @@ static int ipw_ioctl(struct tty_struct *linux_tty, struct file *file,
    }
    return 0;

    - case TCGETS:
    - case TCGETA:
    - return n_tty_ioctl(linux_tty, file, cmd, arg);
    -
    - case TCFLSH:
    - return n_tty_ioctl(linux_tty, file, cmd, arg);
    -
    case FIONREAD:
    {
    int val = 0;
    @@ -482,10 +480,11 @@ static int ipw_ioctl(struct tty_struct *linux_tty, struct file *file,
    return -EFAULT;
    }
    return 0;
    + case TCFLSH:
    + return tty_perform_flush(linux_tty, arg);
    }
    }
    -
    - return -ENOIOCTLCMD;
    + return tty_mode_ioctl(linux_tty, file, cmd , arg);
    }

    static int add_tty(dev_node_t *nodesp, int j,
    @@ -588,6 +587,8 @@ void ipwireless_tty_free(struct ipw_tty *tty)
    tty_hangup(ttyj->linux_tty);
    /* Wait till the tty_hangup has completed */
    flush_scheduled_work();
    + /* FIXME: Exactly how is the tty object locked here
    + against a parallel ioctl etc */
    mutex_lock(&ttyj->ipw_tty_mutex);
    }
    while (ttyj->open_count)

    --
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

  12. [PATCH 40/80] tty: Termios locking - sort out real_tty confusions and lock reads

    From: Alan Cox

    This moves us towards sanity and should mean our termios locking is now
    complete and comprehensive.

    Signed-off-by: Alan Cox
    ---

    drivers/char/tty_io.c | 2 +-
    drivers/char/tty_ioctl.c | 58 ++++++++++++++++++++++++++++++----------------
    2 files changed, 39 insertions(+), 21 deletions(-)


    diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
    index fa162c9..ac53d7f 100644
    --- a/drivers/char/tty_io.c
    +++ b/drivers/char/tty_io.c
    @@ -2605,7 +2605,7 @@ long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
    case TIOCSTI:
    return tiocsti(tty, p);
    case TIOCGWINSZ:
    - return tiocgwinsz(tty, p);
    + return tiocgwinsz(real_tty, p);
    case TIOCSWINSZ:
    return tiocswinsz(tty, real_tty, p);
    case TIOCCONS:
    diff --git a/drivers/char/tty_ioctl.c b/drivers/char/tty_ioctl.c
    index 93bfa1d..3067085 100644
    --- a/drivers/char/tty_ioctl.c
    +++ b/drivers/char/tty_ioctl.c
    @@ -893,6 +893,7 @@ int tty_mode_ioctl(struct tty_struct *tty, struct file *file,
    {
    struct tty_struct *real_tty;
    void __user *p = (void __user *)arg;
    + int ret = 0;

    if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
    tty->driver->subtype == PTY_TYPE_MASTER)
    @@ -928,18 +929,24 @@ int tty_mode_ioctl(struct tty_struct *tty, struct file *file,
    return set_termios(real_tty, p, TERMIOS_OLD);
    #ifndef TCGETS2
    case TCGETS:
    + mutex_lock(&real_tty->termios_mutex);
    if (kernel_termios_to_user_termios((struct termios __user *)arg, real_tty->termios))
    - return -EFAULT;
    - return 0;
    + ret = -EFAULT;
    + mutex_unlock(&real_tty->termios_mutex);
    + return ret;
    #else
    case TCGETS:
    + mutex_lock(&real_tty->termios_mutex);
    if (kernel_termios_to_user_termios_1((struct termios __user *)arg, real_tty->termios))
    - return -EFAULT;
    - return 0;
    + ret = -EFAULT;
    + mutex_unlock(&real_tty->termios_mutex);
    + return ret;
    case TCGETS2:
    + mutex_lock(&real_tty->termios_mutex);
    if (kernel_termios_to_user_termios((struct termios2 __user *)arg, real_tty->termios))
    - return -EFAULT;
    - return 0;
    + ret = -EFAULT;
    + mutex_unlock(&real_tty->termios_mutex);
    + return ret;
    case TCSETSF2:
    return set_termios(real_tty, p, TERMIOS_FLUSH | TERMIOS_WAIT);
    case TCSETSW2:
    @@ -957,36 +964,46 @@ int tty_mode_ioctl(struct tty_struct *tty, struct file *file,
    return set_termios(real_tty, p, TERMIOS_TERMIO);
    #ifndef TCGETS2
    case TIOCGLCKTRMIOS:
    + mutex_lock(&real_tty->termios_mutex);
    if (kernel_termios_to_user_termios((struct termios __user *)arg, real_tty->termios_locked))
    - return -EFAULT;
    - return 0;
    + ret = -EFAULT;
    + mutex_unlock(&real_tty->termios_mutex);
    + return ret;
    case TIOCSLCKTRMIOS:
    if (!capable(CAP_SYS_ADMIN))
    return -EPERM;
    + mutex_lock(&real_tty->termios_mutex);
    if (user_termios_to_kernel_termios(real_tty->termios_locked,
    (struct termios __user *) arg))
    - return -EFAULT;
    - return 0;
    + ret = -EFAULT;
    + mutex_unlock(&real_tty->termios_mutex);
    + return ret;
    #else
    case TIOCGLCKTRMIOS:
    + mutex_lock(&real_tty->termios_mutex);
    if (kernel_termios_to_user_termios_1((struct termios __user *)arg, real_tty->termios_locked))
    - return -EFAULT;
    - return 0;
    + ret = -EFAULT;
    + mutex_unlock(&real_tty->termios_mutex);
    + return ret;
    case TIOCSLCKTRMIOS:
    if (!capable(CAP_SYS_ADMIN))
    - return -EPERM;
    + ret = -EPERM;
    + mutex_lock(&real_tty->termios_mutex);
    if (user_termios_to_kernel_termios_1(real_tty->termios_locked,
    (struct termios __user *) arg))
    - return -EFAULT;
    - return 0;
    + ret = -EFAULT;
    + mutex_unlock(&real_tty->termios_mutex);
    + return ret;
    #endif
    #ifdef TCGETX
    case TCGETX:
    if (real_tty->termiox == NULL)
    return -EINVAL;
    + mutex_lock(&real_tty->termios_mutex);
    if (copy_to_user(p, real_tty->termiox, sizeof(struct termiox)))
    - return -EFAULT;
    - return 0;
    + ret = -EFAULT;
    + mutex_unlock(&real_tty->termios_mutex);
    + return ret;
    case TCSETX:
    return set_termiox(real_tty, p, 0);
    case TCSETXW:
    @@ -995,10 +1012,11 @@ int tty_mode_ioctl(struct tty_struct *tty, struct file *file,
    return set_termiox(real_tty, p, TERMIOS_FLUSH);
    #endif
    case TIOCGSOFTCAR:
    - /* FIXME: for correctness we may need to take the termios
    - lock here - review */
    - return put_user(C_CLOCAL(real_tty) ? 1 : 0,
    + mutex_lock(&real_tty->termios_mutex);
    + ret = put_user(C_CLOCAL(real_tty) ? 1 : 0,
    (int __user *)arg);
    + mutex_unlock(&real_tty->termios_mutex);
    + return ret;
    case TIOCSSOFTCAR:
    if (get_user(arg, (unsigned int __user *) arg))
    return -EFAULT;

    --
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

  13. [PATCH 32/80] tty: split the buffering from tty_io

    From: Alan Cox

    The two are basically independent chunks of code so lets split them up for
    readability and sanity. It also makes the API boundaries much clearer.

    Signed-off-by: Alan Cox
    ---

    drivers/char/Makefile | 2
    drivers/char/tty_buffer.c | 511 +++++++++++++++++++++++++++++++++++++++++++++
    drivers/char/tty_io.c | 502 --------------------------------------------
    include/linux/tty.h | 3
    4 files changed, 515 insertions(+), 503 deletions(-)
    create mode 100644 drivers/char/tty_buffer.c


    diff --git a/drivers/char/Makefile b/drivers/char/Makefile
    index 6850f6d..77ea41b 100644
    --- a/drivers/char/Makefile
    +++ b/drivers/char/Makefile
    @@ -7,7 +7,7 @@
    #
    FONTMAPFILE = cp437.uni

    -obj-y += mem.o random.o tty_io.o n_tty.o tty_ioctl.o tty_ldisc.o
    +obj-y += mem.o random.o tty_io.o n_tty.o tty_ioctl.o tty_ldisc.o tty_buffer.o

    obj-$(CONFIG_LEGACY_PTYS) += pty.o
    obj-$(CONFIG_UNIX98_PTYS) += pty.o
    diff --git a/drivers/char/tty_buffer.c b/drivers/char/tty_buffer.c
    new file mode 100644
    index 0000000..810ee25
    --- /dev/null
    +++ b/drivers/char/tty_buffer.c
    @@ -0,0 +1,511 @@
    +/*
    + * Tty buffer allocation management
    + */
    +
    +#include
    +#include
    +#include
    +#include
    +#include
    +#include
    +#include
    +#include
    +#include
    +#include
    +#include
    +#include
    +#include
    +#include
    +
    +/**
    + * tty_buffer_free_all - free buffers used by a tty
    + * @tty: tty to free from
    + *
    + * Remove all the buffers pending on a tty whether queued with data
    + * or in the free ring. Must be called when the tty is no longer in use
    + *
    + * Locking: none
    + */
    +
    +void tty_buffer_free_all(struct tty_struct *tty)
    +{
    + struct tty_buffer *thead;
    + while ((thead = tty->buf.head) != NULL) {
    + tty->buf.head = thead->next;
    + kfree(thead);
    + }
    + while ((thead = tty->buf.free) != NULL) {
    + tty->buf.free = thead->next;
    + kfree(thead);
    + }
    + tty->buf.tail = NULL;
    + tty->buf.memory_used = 0;
    +}
    +
    +/**
    + * tty_buffer_alloc - allocate a tty buffer
    + * @tty: tty device
    + * @size: desired size (characters)
    + *
    + * Allocate a new tty buffer to hold the desired number of characters.
    + * Return NULL if out of memory or the allocation would exceed the
    + * per device queue
    + *
    + * Locking: Caller must hold tty->buf.lock
    + */
    +
    +static struct tty_buffer *tty_buffer_alloc(struct tty_struct *tty, size_t size)
    +{
    + struct tty_buffer *p;
    +
    + if (tty->buf.memory_used + size > 65536)
    + return NULL;
    + p = kmalloc(sizeof(struct tty_buffer) + 2 * size, GFP_ATOMIC);
    + if (p == NULL)
    + return NULL;
    + p->used = 0;
    + p->size = size;
    + p->next = NULL;
    + p->commit = 0;
    + p->read = 0;
    + p->char_buf_ptr = (char *)(p->data);
    + p->flag_buf_ptr = (unsigned char *)p->char_buf_ptr + size;
    + tty->buf.memory_used += size;
    + return p;
    +}
    +
    +/**
    + * tty_buffer_free - free a tty buffer
    + * @tty: tty owning the buffer
    + * @b: the buffer to free
    + *
    + * Free a tty buffer, or add it to the free list according to our
    + * internal strategy
    + *
    + * Locking: Caller must hold tty->buf.lock
    + */
    +
    +static void tty_buffer_free(struct tty_struct *tty, struct tty_buffer *b)
    +{
    + /* Dumb strategy for now - should keep some stats */
    + tty->buf.memory_used -= b->size;
    + WARN_ON(tty->buf.memory_used < 0);
    +
    + if (b->size >= 512)
    + kfree(b);
    + else {
    + b->next = tty->buf.free;
    + tty->buf.free = b;
    + }
    +}
    +
    +/**
    + * __tty_buffer_flush - flush full tty buffers
    + * @tty: tty to flush
    + *
    + * flush all the buffers containing receive data. Caller must
    + * hold the buffer lock and must have ensured no parallel flush to
    + * ldisc is running.
    + *
    + * Locking: Caller must hold tty->buf.lock
    + */
    +
    +static void __tty_buffer_flush(struct tty_struct *tty)
    +{
    + struct tty_buffer *thead;
    +
    + while ((thead = tty->buf.head) != NULL) {
    + tty->buf.head = thead->next;
    + tty_buffer_free(tty, thead);
    + }
    + tty->buf.tail = NULL;
    +}
    +
    +/**
    + * tty_buffer_flush - flush full tty buffers
    + * @tty: tty to flush
    + *
    + * flush all the buffers containing receive data. If the buffer is
    + * being processed by flush_to_ldisc then we defer the processing
    + * to that function
    + *
    + * Locking: none
    + */
    +
    +void tty_buffer_flush(struct tty_struct *tty)
    +{
    + unsigned long flags;
    + spin_lock_irqsave(&tty->buf.lock, flags);
    +
    + /* If the data is being pushed to the tty layer then we can't
    + process it here. Instead set a flag and the flush_to_ldisc
    + path will process the flush request before it exits */
    + if (test_bit(TTY_FLUSHING, &tty->flags)) {
    + set_bit(TTY_FLUSHPENDING, &tty->flags);
    + spin_unlock_irqrestore(&tty->buf.lock, flags);
    + wait_event(tty->read_wait,
    + test_bit(TTY_FLUSHPENDING, &tty->flags) == 0);
    + return;
    + } else
    + __tty_buffer_flush(tty);
    + spin_unlock_irqrestore(&tty->buf.lock, flags);
    +}
    +
    +/**
    + * tty_buffer_find - find a free tty buffer
    + * @tty: tty owning the buffer
    + * @size: characters wanted
    + *
    + * Locate an existing suitable tty buffer or if we are lacking one then
    + * allocate a new one. We round our buffers off in 256 character chunks
    + * to get better allocation behaviour.
    + *
    + * Locking: Caller must hold tty->buf.lock
    + */
    +
    +static struct tty_buffer *tty_buffer_find(struct tty_struct *tty, size_t size)
    +{
    + struct tty_buffer **tbh = &tty->buf.free;
    + while ((*tbh) != NULL) {
    + struct tty_buffer *t = *tbh;
    + if (t->size >= size) {
    + *tbh = t->next;
    + t->next = NULL;
    + t->used = 0;
    + t->commit = 0;
    + t->read = 0;
    + tty->buf.memory_used += t->size;
    + return t;
    + }
    + tbh = &((*tbh)->next);
    + }
    + /* Round the buffer size out */
    + size = (size + 0xFF) & ~0xFF;
    + return tty_buffer_alloc(tty, size);
    + /* Should possibly check if this fails for the largest buffer we
    + have queued and recycle that ? */
    +}
    +
    +/**
    + * tty_buffer_request_room - grow tty buffer if needed
    + * @tty: tty structure
    + * @size: size desired
    + *
    + * Make at least size bytes of linear space available for the tty
    + * buffer. If we fail return the size we managed to find.
    + *
    + * Locking: Takes tty->buf.lock
    + */
    +int tty_buffer_request_room(struct tty_struct *tty, size_t size)
    +{
    + struct tty_buffer *b, *n;
    + int left;
    + unsigned long flags;
    +
    + spin_lock_irqsave(&tty->buf.lock, flags);
    +
    + /* OPTIMISATION: We could keep a per tty "zero" sized buffer to
    + remove this conditional if its worth it. This would be invisible
    + to the callers */
    + if ((b = tty->buf.tail) != NULL)
    + left = b->size - b->used;
    + else
    + left = 0;
    +
    + if (left < size) {
    + /* This is the slow path - looking for new buffers to use */
    + if ((n = tty_buffer_find(tty, size)) != NULL) {
    + if (b != NULL) {
    + b->next = n;
    + b->commit = b->used;
    + } else
    + tty->buf.head = n;
    + tty->buf.tail = n;
    + } else
    + size = left;
    + }
    +
    + spin_unlock_irqrestore(&tty->buf.lock, flags);
    + return size;
    +}
    +EXPORT_SYMBOL_GPL(tty_buffer_request_room);
    +
    +/**
    + * tty_insert_flip_string - Add characters to the tty buffer
    + * @tty: tty structure
    + * @chars: characters
    + * @size: size
    + *
    + * Queue a series of bytes to the tty buffering. All the characters
    + * passed are marked as without error. Returns the number added.
    + *
    + * Locking: Called functions may take tty->buf.lock
    + */
    +
    +int tty_insert_flip_string(struct tty_struct *tty, const unsigned char *chars,
    + size_t size)
    +{
    + int copied = 0;
    + do {
    + int space = tty_buffer_request_room(tty, size - copied);
    + struct tty_buffer *tb = tty->buf.tail;
    + /* If there is no space then tb may be NULL */
    + if (unlikely(space == 0))
    + break;
    + memcpy(tb->char_buf_ptr + tb->used, chars, space);
    + memset(tb->flag_buf_ptr + tb->used, TTY_NORMAL, space);
    + tb->used += space;
    + copied += space;
    + chars += space;
    + /* There is a small chance that we need to split the data over
    + several buffers. If this is the case we must loop */
    + } while (unlikely(size > copied));
    + return copied;
    +}
    +EXPORT_SYMBOL(tty_insert_flip_string);
    +
    +/**
    + * tty_insert_flip_string_flags - Add characters to the tty buffer
    + * @tty: tty structure
    + * @chars: characters
    + * @flags: flag bytes
    + * @size: size
    + *
    + * Queue a series of bytes to the tty buffering. For each character
    + * the flags array indicates the status of the character. Returns the
    + * number added.
    + *
    + * Locking: Called functions may take tty->buf.lock
    + */
    +
    +int tty_insert_flip_string_flags(struct tty_struct *tty,
    + const unsigned char *chars, const char *flags, size_t size)
    +{
    + int copied = 0;
    + do {
    + int space = tty_buffer_request_room(tty, size - copied);
    + struct tty_buffer *tb = tty->buf.tail;
    + /* If there is no space then tb may be NULL */
    + if (unlikely(space == 0))
    + break;
    + memcpy(tb->char_buf_ptr + tb->used, chars, space);
    + memcpy(tb->flag_buf_ptr + tb->used, flags, space);
    + tb->used += space;
    + copied += space;
    + chars += space;
    + flags += space;
    + /* There is a small chance that we need to split the data over
    + several buffers. If this is the case we must loop */
    + } while (unlikely(size > copied));
    + return copied;
    +}
    +EXPORT_SYMBOL(tty_insert_flip_string_flags);
    +
    +/**
    + * tty_schedule_flip - push characters to ldisc
    + * @tty: tty to push from
    + *
    + * Takes any pending buffers and transfers their ownership to the
    + * ldisc side of the queue. It then schedules those characters for
    + * processing by the line discipline.
    + *
    + * Locking: Takes tty->buf.lock
    + */
    +
    +void tty_schedule_flip(struct tty_struct *tty)
    +{
    + unsigned long flags;
    + spin_lock_irqsave(&tty->buf.lock, flags);
    + if (tty->buf.tail != NULL)
    + tty->buf.tail->commit = tty->buf.tail->used;
    + spin_unlock_irqrestore(&tty->buf.lock, flags);
    + schedule_delayed_work(&tty->buf.work, 1);
    +}
    +EXPORT_SYMBOL(tty_schedule_flip);
    +
    +/**
    + * tty_prepare_flip_string - make room for characters
    + * @tty: tty
    + * @chars: return pointer for character write area
    + * @size: desired size
    + *
    + * Prepare a block of space in the buffer for data. Returns the length
    + * available and buffer pointer to the space which is now allocated and
    + * accounted for as ready for normal characters. This is used for drivers
    + * that need their own block copy routines into the buffer. There is no
    + * guarantee the buffer is a DMA target!
    + *
    + * Locking: May call functions taking tty->buf.lock
    + */
    +
    +int tty_prepare_flip_string(struct tty_struct *tty, unsigned char **chars,
    + size_t size)
    +{
    + int space = tty_buffer_request_room(tty, size);
    + if (likely(space)) {
    + struct tty_buffer *tb = tty->buf.tail;
    + *chars = tb->char_buf_ptr + tb->used;
    + memset(tb->flag_buf_ptr + tb->used, TTY_NORMAL, space);
    + tb->used += space;
    + }
    + return space;
    +}
    +EXPORT_SYMBOL_GPL(tty_prepare_flip_string);
    +
    +/**
    + * tty_prepare_flip_string_flags - make room for characters
    + * @tty: tty
    + * @chars: return pointer for character write area
    + * @flags: return pointer for status flag write area
    + * @size: desired size
    + *
    + * Prepare a block of space in the buffer for data. Returns the length
    + * available and buffer pointer to the space which is now allocated and
    + * accounted for as ready for characters. This is used for drivers
    + * that need their own block copy routines into the buffer. There is no
    + * guarantee the buffer is a DMA target!
    + *
    + * Locking: May call functions taking tty->buf.lock
    + */
    +
    +int tty_prepare_flip_string_flags(struct tty_struct *tty,
    + unsigned char **chars, char **flags, size_t size)
    +{
    + int space = tty_buffer_request_room(tty, size);
    + if (likely(space)) {
    + struct tty_buffer *tb = tty->buf.tail;
    + *chars = tb->char_buf_ptr + tb->used;
    + *flags = tb->flag_buf_ptr + tb->used;
    + tb->used += space;
    + }
    + return space;
    +}
    +EXPORT_SYMBOL_GPL(tty_prepare_flip_string_flags);
    +
    +
    +
    +/**
    + * flush_to_ldisc
    + * @work: tty structure passed from work queue.
    + *
    + * This routine is called out of the software interrupt to flush data
    + * from the buffer chain to the line discipline.
    + *
    + * Locking: holds tty->buf.lock to guard buffer list. Drops the lock
    + * while invoking the line discipline receive_buf method. The
    + * receive_buf method is single threaded for each tty instance.
    + */
    +
    +static void flush_to_ldisc(struct work_struct *work)
    +{
    + struct tty_struct *tty =
    + container_of(work, struct tty_struct, buf.work.work);
    + unsigned long flags;
    + struct tty_ldisc *disc;
    + struct tty_buffer *tbuf, *head;
    + char *char_buf;
    + unsigned char *flag_buf;
    +
    + disc = tty_ldisc_ref(tty);
    + if (disc == NULL) /* !TTY_LDISC */
    + return;
    +
    + spin_lock_irqsave(&tty->buf.lock, flags);
    + /* So we know a flush is running */
    + set_bit(TTY_FLUSHING, &tty->flags);
    + head = tty->buf.head;
    + if (head != NULL) {
    + tty->buf.head = NULL;
    + for (; {
    + int count = head->commit - head->read;
    + if (!count) {
    + if (head->next == NULL)
    + break;
    + tbuf = head;
    + head = head->next;
    + tty_buffer_free(tty, tbuf);
    + continue;
    + }
    + /* Ldisc or user is trying to flush the buffers
    + we are feeding to the ldisc, stop feeding the
    + line discipline as we want to empty the queue */
    + if (test_bit(TTY_FLUSHPENDING, &tty->flags))
    + break;
    + if (!tty->receive_room) {
    + schedule_delayed_work(&tty->buf.work, 1);
    + break;
    + }
    + if (count > tty->receive_room)
    + count = tty->receive_room;
    + char_buf = head->char_buf_ptr + head->read;
    + flag_buf = head->flag_buf_ptr + head->read;
    + head->read += count;
    + spin_unlock_irqrestore(&tty->buf.lock, flags);
    + disc->ops->receive_buf(tty, char_buf,
    + flag_buf, count);
    + spin_lock_irqsave(&tty->buf.lock, flags);
    + }
    + /* Restore the queue head */
    + tty->buf.head = head;
    + }
    + /* We may have a deferred request to flush the input buffer,
    + if so pull the chain under the lock and empty the queue */
    + if (test_bit(TTY_FLUSHPENDING, &tty->flags)) {
    + __tty_buffer_flush(tty);
    + clear_bit(TTY_FLUSHPENDING, &tty->flags);
    + wake_up(&tty->read_wait);
    + }
    + clear_bit(TTY_FLUSHING, &tty->flags);
    + spin_unlock_irqrestore(&tty->buf.lock, flags);
    +
    + tty_ldisc_deref(disc);
    +}
    +
    +/**
    + * tty_flip_buffer_push - terminal
    + * @tty: tty to push
    + *
    + * Queue a push of the terminal flip buffers to the line discipline. This
    + * function must not be called from IRQ context if tty->low_latency is set.
    + *
    + * In the event of the queue being busy for flipping the work will be
    + * held off and retried later.
    + *
    + * Locking: tty buffer lock. Driver locks in low latency mode.
    + */
    +
    +void tty_flip_buffer_push(struct tty_struct *tty)
    +{
    + unsigned long flags;
    + spin_lock_irqsave(&tty->buf.lock, flags);
    + if (tty->buf.tail != NULL)
    + tty->buf.tail->commit = tty->buf.tail->used;
    + spin_unlock_irqrestore(&tty->buf.lock, flags);
    +
    + if (tty->low_latency)
    + flush_to_ldisc(&tty->buf.work.work);
    + else
    + schedule_delayed_work(&tty->buf.work, 1);
    +}
    +EXPORT_SYMBOL(tty_flip_buffer_push);
    +
    +/**
    + * tty_buffer_init - prepare a tty buffer structure
    + * @tty: tty to initialise
    + *
    + * Set up the initial state of the buffer management for a tty device.
    + * Must be called before the other tty buffer functions are used.
    + *
    + * Locking: none
    + */
    +
    +void tty_buffer_init(struct tty_struct *tty)
    +{
    + spin_lock_init(&tty->buf.lock);
    + tty->buf.head = NULL;
    + tty->buf.tail = NULL;
    + tty->buf.free = NULL;
    + tty->buf.memory_used = 0;
    + INIT_DELAYED_WORK(&tty->buf.work, flush_to_ldisc);
    +}
    +
    diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
    index 2f05728..3a72693 100644
    --- a/drivers/char/tty_io.c
    +++ b/drivers/char/tty_io.c
    @@ -176,8 +176,6 @@ static struct tty_struct *alloc_tty_struct(void)
    return kzalloc(sizeof(struct tty_struct), GFP_KERNEL);
    }

    -static void tty_buffer_free_all(struct tty_struct *);
    -
    /**
    * free_tty_struct - free a disused tty
    * @tty: tty struct to free
    @@ -263,398 +261,6 @@ static int check_tty_count(struct tty_struct *tty, const char *routine)
    return 0;
    }

    -/*
    - * Tty buffer allocation management
    - */
    -
    -/**
    - * tty_buffer_free_all - free buffers used by a tty
    - * @tty: tty to free from
    - *
    - * Remove all the buffers pending on a tty whether queued with data
    - * or in the free ring. Must be called when the tty is no longer in use
    - *
    - * Locking: none
    - */
    -
    -static void tty_buffer_free_all(struct tty_struct *tty)
    -{
    - struct tty_buffer *thead;
    - while ((thead = tty->buf.head) != NULL) {
    - tty->buf.head = thead->next;
    - kfree(thead);
    - }
    - while ((thead = tty->buf.free) != NULL) {
    - tty->buf.free = thead->next;
    - kfree(thead);
    - }
    - tty->buf.tail = NULL;
    - tty->buf.memory_used = 0;
    -}
    -
    -/**
    - * tty_buffer_init - prepare a tty buffer structure
    - * @tty: tty to initialise
    - *
    - * Set up the initial state of the buffer management for a tty device.
    - * Must be called before the other tty buffer functions are used.
    - *
    - * Locking: none
    - */
    -
    -static void tty_buffer_init(struct tty_struct *tty)
    -{
    - spin_lock_init(&tty->buf.lock);
    - tty->buf.head = NULL;
    - tty->buf.tail = NULL;
    - tty->buf.free = NULL;
    - tty->buf.memory_used = 0;
    -}
    -
    -/**
    - * tty_buffer_alloc - allocate a tty buffer
    - * @tty: tty device
    - * @size: desired size (characters)
    - *
    - * Allocate a new tty buffer to hold the desired number of characters.
    - * Return NULL if out of memory or the allocation would exceed the
    - * per device queue
    - *
    - * Locking: Caller must hold tty->buf.lock
    - */
    -
    -static struct tty_buffer *tty_buffer_alloc(struct tty_struct *tty, size_t size)
    -{
    - struct tty_buffer *p;
    -
    - if (tty->buf.memory_used + size > 65536)
    - return NULL;
    - p = kmalloc(sizeof(struct tty_buffer) + 2 * size, GFP_ATOMIC);
    - if (p == NULL)
    - return NULL;
    - p->used = 0;
    - p->size = size;
    - p->next = NULL;
    - p->commit = 0;
    - p->read = 0;
    - p->char_buf_ptr = (char *)(p->data);
    - p->flag_buf_ptr = (unsigned char *)p->char_buf_ptr + size;
    - tty->buf.memory_used += size;
    - return p;
    -}
    -
    -/**
    - * tty_buffer_free - free a tty buffer
    - * @tty: tty owning the buffer
    - * @b: the buffer to free
    - *
    - * Free a tty buffer, or add it to the free list according to our
    - * internal strategy
    - *
    - * Locking: Caller must hold tty->buf.lock
    - */
    -
    -static void tty_buffer_free(struct tty_struct *tty, struct tty_buffer *b)
    -{
    - /* Dumb strategy for now - should keep some stats */
    - tty->buf.memory_used -= b->size;
    - WARN_ON(tty->buf.memory_used < 0);
    -
    - if (b->size >= 512)
    - kfree(b);
    - else {
    - b->next = tty->buf.free;
    - tty->buf.free = b;
    - }
    -}
    -
    -/**
    - * __tty_buffer_flush - flush full tty buffers
    - * @tty: tty to flush
    - *
    - * flush all the buffers containing receive data. Caller must
    - * hold the buffer lock and must have ensured no parallel flush to
    - * ldisc is running.
    - *
    - * Locking: Caller must hold tty->buf.lock
    - */
    -
    -static void __tty_buffer_flush(struct tty_struct *tty)
    -{
    - struct tty_buffer *thead;
    -
    - while ((thead = tty->buf.head) != NULL) {
    - tty->buf.head = thead->next;
    - tty_buffer_free(tty, thead);
    - }
    - tty->buf.tail = NULL;
    -}
    -
    -/**
    - * tty_buffer_flush - flush full tty buffers
    - * @tty: tty to flush
    - *
    - * flush all the buffers containing receive data. If the buffer is
    - * being processed by flush_to_ldisc then we defer the processing
    - * to that function
    - *
    - * Locking: none
    - */
    -
    -static void tty_buffer_flush(struct tty_struct *tty)
    -{
    - unsigned long flags;
    - spin_lock_irqsave(&tty->buf.lock, flags);
    -
    - /* If the data is being pushed to the tty layer then we can't
    - process it here. Instead set a flag and the flush_to_ldisc
    - path will process the flush request before it exits */
    - if (test_bit(TTY_FLUSHING, &tty->flags)) {
    - set_bit(TTY_FLUSHPENDING, &tty->flags);
    - spin_unlock_irqrestore(&tty->buf.lock, flags);
    - wait_event(tty->read_wait,
    - test_bit(TTY_FLUSHPENDING, &tty->flags) == 0);
    - return;
    - } else
    - __tty_buffer_flush(tty);
    - spin_unlock_irqrestore(&tty->buf.lock, flags);
    -}
    -
    -/**
    - * tty_buffer_find - find a free tty buffer
    - * @tty: tty owning the buffer
    - * @size: characters wanted
    - *
    - * Locate an existing suitable tty buffer or if we are lacking one then
    - * allocate a new one. We round our buffers off in 256 character chunks
    - * to get better allocation behaviour.
    - *
    - * Locking: Caller must hold tty->buf.lock
    - */
    -
    -static struct tty_buffer *tty_buffer_find(struct tty_struct *tty, size_t size)
    -{
    - struct tty_buffer **tbh = &tty->buf.free;
    - while ((*tbh) != NULL) {
    - struct tty_buffer *t = *tbh;
    - if (t->size >= size) {
    - *tbh = t->next;
    - t->next = NULL;
    - t->used = 0;
    - t->commit = 0;
    - t->read = 0;
    - tty->buf.memory_used += t->size;
    - return t;
    - }
    - tbh = &((*tbh)->next);
    - }
    - /* Round the buffer size out */
    - size = (size + 0xFF) & ~0xFF;
    - return tty_buffer_alloc(tty, size);
    - /* Should possibly check if this fails for the largest buffer we
    - have queued and recycle that ? */
    -}
    -
    -/**
    - * tty_buffer_request_room - grow tty buffer if needed
    - * @tty: tty structure
    - * @size: size desired
    - *
    - * Make at least size bytes of linear space available for the tty
    - * buffer. If we fail return the size we managed to find.
    - *
    - * Locking: Takes tty->buf.lock
    - */
    -int tty_buffer_request_room(struct tty_struct *tty, size_t size)
    -{
    - struct tty_buffer *b, *n;
    - int left;
    - unsigned long flags;
    -
    - spin_lock_irqsave(&tty->buf.lock, flags);
    -
    - /* OPTIMISATION: We could keep a per tty "zero" sized buffer to
    - remove this conditional if its worth it. This would be invisible
    - to the callers */
    - if ((b = tty->buf.tail) != NULL)
    - left = b->size - b->used;
    - else
    - left = 0;
    -
    - if (left < size) {
    - /* This is the slow path - looking for new buffers to use */
    - if ((n = tty_buffer_find(tty, size)) != NULL) {
    - if (b != NULL) {
    - b->next = n;
    - b->commit = b->used;
    - } else
    - tty->buf.head = n;
    - tty->buf.tail = n;
    - } else
    - size = left;
    - }
    -
    - spin_unlock_irqrestore(&tty->buf.lock, flags);
    - return size;
    -}
    -EXPORT_SYMBOL_GPL(tty_buffer_request_room);
    -
    -/**
    - * tty_insert_flip_string - Add characters to the tty buffer
    - * @tty: tty structure
    - * @chars: characters
    - * @size: size
    - *
    - * Queue a series of bytes to the tty buffering. All the characters
    - * passed are marked as without error. Returns the number added.
    - *
    - * Locking: Called functions may take tty->buf.lock
    - */
    -
    -int tty_insert_flip_string(struct tty_struct *tty, const unsigned char *chars,
    - size_t size)
    -{
    - int copied = 0;
    - do {
    - int space = tty_buffer_request_room(tty, size - copied);
    - struct tty_buffer *tb = tty->buf.tail;
    - /* If there is no space then tb may be NULL */
    - if (unlikely(space == 0))
    - break;
    - memcpy(tb->char_buf_ptr + tb->used, chars, space);
    - memset(tb->flag_buf_ptr + tb->used, TTY_NORMAL, space);
    - tb->used += space;
    - copied += space;
    - chars += space;
    - /* There is a small chance that we need to split the data over
    - several buffers. If this is the case we must loop */
    - } while (unlikely(size > copied));
    - return copied;
    -}
    -EXPORT_SYMBOL(tty_insert_flip_string);
    -
    -/**
    - * tty_insert_flip_string_flags - Add characters to the tty buffer
    - * @tty: tty structure
    - * @chars: characters
    - * @flags: flag bytes
    - * @size: size
    - *
    - * Queue a series of bytes to the tty buffering. For each character
    - * the flags array indicates the status of the character. Returns the
    - * number added.
    - *
    - * Locking: Called functions may take tty->buf.lock
    - */
    -
    -int tty_insert_flip_string_flags(struct tty_struct *tty,
    - const unsigned char *chars, const char *flags, size_t size)
    -{
    - int copied = 0;
    - do {
    - int space = tty_buffer_request_room(tty, size - copied);
    - struct tty_buffer *tb = tty->buf.tail;
    - /* If there is no space then tb may be NULL */
    - if (unlikely(space == 0))
    - break;
    - memcpy(tb->char_buf_ptr + tb->used, chars, space);
    - memcpy(tb->flag_buf_ptr + tb->used, flags, space);
    - tb->used += space;
    - copied += space;
    - chars += space;
    - flags += space;
    - /* There is a small chance that we need to split the data over
    - several buffers. If this is the case we must loop */
    - } while (unlikely(size > copied));
    - return copied;
    -}
    -EXPORT_SYMBOL(tty_insert_flip_string_flags);
    -
    -/**
    - * tty_schedule_flip - push characters to ldisc
    - * @tty: tty to push from
    - *
    - * Takes any pending buffers and transfers their ownership to the
    - * ldisc side of the queue. It then schedules those characters for
    - * processing by the line discipline.
    - *
    - * Locking: Takes tty->buf.lock
    - */
    -
    -void tty_schedule_flip(struct tty_struct *tty)
    -{
    - unsigned long flags;
    - spin_lock_irqsave(&tty->buf.lock, flags);
    - if (tty->buf.tail != NULL)
    - tty->buf.tail->commit = tty->buf.tail->used;
    - spin_unlock_irqrestore(&tty->buf.lock, flags);
    - schedule_delayed_work(&tty->buf.work, 1);
    -}
    -EXPORT_SYMBOL(tty_schedule_flip);
    -
    -/**
    - * tty_prepare_flip_string - make room for characters
    - * @tty: tty
    - * @chars: return pointer for character write area
    - * @size: desired size
    - *
    - * Prepare a block of space in the buffer for data. Returns the length
    - * available and buffer pointer to the space which is now allocated and
    - * accounted for as ready for normal characters. This is used for drivers
    - * that need their own block copy routines into the buffer. There is no
    - * guarantee the buffer is a DMA target!
    - *
    - * Locking: May call functions taking tty->buf.lock
    - */
    -
    -int tty_prepare_flip_string(struct tty_struct *tty, unsigned char **chars,
    - size_t size)
    -{
    - int space = tty_buffer_request_room(tty, size);
    - if (likely(space)) {
    - struct tty_buffer *tb = tty->buf.tail;
    - *chars = tb->char_buf_ptr + tb->used;
    - memset(tb->flag_buf_ptr + tb->used, TTY_NORMAL, space);
    - tb->used += space;
    - }
    - return space;
    -}
    -
    -EXPORT_SYMBOL_GPL(tty_prepare_flip_string);
    -
    -/**
    - * tty_prepare_flip_string_flags - make room for characters
    - * @tty: tty
    - * @chars: return pointer for character write area
    - * @flags: return pointer for status flag write area
    - * @size: desired size
    - *
    - * Prepare a block of space in the buffer for data. Returns the length
    - * available and buffer pointer to the space which is now allocated and
    - * accounted for as ready for characters. This is used for drivers
    - * that need their own block copy routines into the buffer. There is no
    - * guarantee the buffer is a DMA target!
    - *
    - * Locking: May call functions taking tty->buf.lock
    - */
    -
    -int tty_prepare_flip_string_flags(struct tty_struct *tty,
    - unsigned char **chars, char **flags, size_t size)
    -{
    - int space = tty_buffer_request_room(tty, size);
    - if (likely(space)) {
    - struct tty_buffer *tb = tty->buf.tail;
    - *chars = tb->char_buf_ptr + tb->used;
    - *flags = tb->flag_buf_ptr + tb->used;
    - tb->used += space;
    - }
    - return space;
    -}
    -
    -EXPORT_SYMBOL_GPL(tty_prepare_flip_string_flags);
    -
    -
    -
    /**
    * get_tty_driver - find device of a tty
    * @dev_t: device identifier
    @@ -3216,113 +2822,6 @@ void do_SAK(struct tty_struct *tty)
    EXPORT_SYMBOL(do_SAK);

    /**
    - * flush_to_ldisc
    - * @work: tty structure passed from work queue.
    - *
    - * This routine is called out of the software interrupt to flush data
    - * from the buffer chain to the line discipline.
    - *
    - * Locking: holds tty->buf.lock to guard buffer list. Drops the lock
    - * while invoking the line discipline receive_buf method. The
    - * receive_buf method is single threaded for each tty instance.
    - */
    -
    -static void flush_to_ldisc(struct work_struct *work)
    -{
    - struct tty_struct *tty =
    - container_of(work, struct tty_struct, buf.work.work);
    - unsigned long flags;
    - struct tty_ldisc *disc;
    - struct tty_buffer *tbuf, *head;
    - char *char_buf;
    - unsigned char *flag_buf;
    -
    - disc = tty_ldisc_ref(tty);
    - if (disc == NULL) /* !TTY_LDISC */
    - return;
    -
    - spin_lock_irqsave(&tty->buf.lock, flags);
    - /* So we know a flush is running */
    - set_bit(TTY_FLUSHING, &tty->flags);
    - head = tty->buf.head;
    - if (head != NULL) {
    - tty->buf.head = NULL;
    - for (; {
    - int count = head->commit - head->read;
    - if (!count) {
    - if (head->next == NULL)
    - break;
    - tbuf = head;
    - head = head->next;
    - tty_buffer_free(tty, tbuf);
    - continue;
    - }
    - /* Ldisc or user is trying to flush the buffers
    - we are feeding to the ldisc, stop feeding the
    - line discipline as we want to empty the queue */
    - if (test_bit(TTY_FLUSHPENDING, &tty->flags))
    - break;
    - if (!tty->receive_room) {
    - schedule_delayed_work(&tty->buf.work, 1);
    - break;
    - }
    - if (count > tty->receive_room)
    - count = tty->receive_room;
    - char_buf = head->char_buf_ptr + head->read;
    - flag_buf = head->flag_buf_ptr + head->read;
    - head->read += count;
    - spin_unlock_irqrestore(&tty->buf.lock, flags);
    - disc->ops->receive_buf(tty, char_buf,
    - flag_buf, count);
    - spin_lock_irqsave(&tty->buf.lock, flags);
    - }
    - /* Restore the queue head */
    - tty->buf.head = head;
    - }
    - /* We may have a deferred request to flush the input buffer,
    - if so pull the chain under the lock and empty the queue */
    - if (test_bit(TTY_FLUSHPENDING, &tty->flags)) {
    - __tty_buffer_flush(tty);
    - clear_bit(TTY_FLUSHPENDING, &tty->flags);
    - wake_up(&tty->read_wait);
    - }
    - clear_bit(TTY_FLUSHING, &tty->flags);
    - spin_unlock_irqrestore(&tty->buf.lock, flags);
    -
    - tty_ldisc_deref(disc);
    -}
    -
    -/**
    - * tty_flip_buffer_push - terminal
    - * @tty: tty to push
    - *
    - * Queue a push of the terminal flip buffers to the line discipline. This
    - * function must not be called from IRQ context if tty->low_latency is set.
    - *
    - * In the event of the queue being busy for flipping the work will be
    - * held off and retried later.
    - *
    - * Locking: tty buffer lock. Driver locks in low latency mode.
    - */
    -
    -void tty_flip_buffer_push(struct tty_struct *tty)
    -{
    - unsigned long flags;
    - spin_lock_irqsave(&tty->buf.lock, flags);
    - if (tty->buf.tail != NULL)
    - tty->buf.tail->commit = tty->buf.tail->used;
    - spin_unlock_irqrestore(&tty->buf.lock, flags);
    -
    - if (tty->low_latency)
    - flush_to_ldisc(&tty->buf.work.work);
    - else
    - schedule_delayed_work(&tty->buf.work, 1);
    -}
    -
    -EXPORT_SYMBOL(tty_flip_buffer_push);
    -
    -
    -/**
    * initialize_tty_struct
    * @tty: tty to initialize
    *
    @@ -3342,7 +2841,6 @@ static void initialize_tty_struct(struct tty_struct *tty)
    tty->overrun_time = jiffies;
    tty->buf.head = tty->buf.tail = NULL;
    tty_buffer_init(tty);
    - INIT_DELAYED_WORK(&tty->buf.work, flush_to_ldisc);
    mutex_init(&tty->termios_mutex);
    init_waitqueue_head(&tty->write_wait);
    init_waitqueue_head(&tty->read_wait);
    diff --git a/include/linux/tty.h b/include/linux/tty.h
    index 0cbec74..7271c62 100644
    --- a/include/linux/tty.h
    +++ b/include/linux/tty.h
    @@ -347,6 +347,9 @@ extern void __do_SAK(struct tty_struct *tty);
    extern void disassociate_ctty(int priv);
    extern void no_tty(void);
    extern void tty_flip_buffer_push(struct tty_struct *tty);
    +extern void tty_buffer_free_all(struct tty_struct *tty);
    +extern void tty_buffer_flush(struct tty_struct *tty);
    +extern void tty_buffer_init(struct tty_struct *tty);
    extern speed_t tty_get_baud_rate(struct tty_struct *tty);
    extern speed_t tty_termios_baud_rate(struct ktermios *termios);
    extern speed_t tty_termios_input_baud_rate(struct ktermios *termios);

    --
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

  14. [PATCH 35/80] tty: Add a kref count

    From: Alan Cox

    Introduce a kref to the tty structure and use it to protect the tty->signal
    tty references. For now we don't introduce it for anything else.

    Signed-off-by: Alan Cox
    ---

    drivers/char/tty_io.c | 54 ++++++++++++++++++++++++++++++++++++++++++++-----
    include/linux/tty.h | 18 ++++++++++++++++
    kernel/fork.c | 5 ++++-
    kernel/sys.c | 4 +---
    4 files changed, 71 insertions(+), 10 deletions(-)


    diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
    index 7323168..310e070 100644
    --- a/drivers/char/tty_io.c
    +++ b/drivers/char/tty_io.c
    @@ -559,6 +559,7 @@ static void do_tty_hangup(struct work_struct *work)
    struct tty_ldisc *ld;
    int closecount = 0, n;
    unsigned long flags;
    + int refs = 0;

    if (!tty)
    return;
    @@ -625,8 +626,12 @@ static void do_tty_hangup(struct work_struct *work)
    if (tty->session) {
    do_each_pid_task(tty->session, PIDTYPE_SID, p) {
    spin_lock_irq(&p->sighand->siglock);
    - if (p->signal->tty == tty)
    + if (p->signal->tty == tty) {
    p->signal->tty = NULL;
    + /* We defer the dereferences outside fo
    + the tasklist lock */
    + refs++;
    + }
    if (!p->signal->leader) {
    spin_unlock_irq(&p->sighand->siglock);
    continue;
    @@ -652,6 +657,10 @@ static void do_tty_hangup(struct work_struct *work)
    tty->ctrl_status = 0;
    spin_unlock_irqrestore(&tty->ctrl_lock, flags);

    + /* Account for the p->signal references we killed */
    + while (refs--)
    + tty_kref_put(tty);
    +
    /*
    * If one of the devices matches a console pointer, we
    * cannot just call hangup() because that will cause
    @@ -1424,6 +1433,7 @@ release_mem_out:

    /**
    * release_one_tty - release tty structure memory
    + * @kref: kref of tty we are obliterating
    *
    * Releases memory associated with a tty structure, and clears out the
    * driver table slots. This function is called when a device is no longer
    @@ -1433,17 +1443,19 @@ release_mem_out:
    * tty_mutex - sometimes only
    * takes the file list lock internally when working on the list
    * of ttys that the driver keeps.
    - * FIXME: should we require tty_mutex is held here ??
    */
    -static void release_one_tty(struct tty_struct *tty, int idx)
    +static void release_one_tty(struct kref *kref)
    {
    + struct tty_struct *tty = container_of(kref, struct tty_struct, kref);
    int devpts = tty->driver->flags & TTY_DRIVER_DEVPTS_MEM;
    struct ktermios *tp;
    + int idx = tty->index;

    if (!devpts)
    tty->driver->ttys[idx] = NULL;

    if (tty->driver->flags & TTY_DRIVER_RESET_TERMIOS) {
    + /* FIXME: Locking on ->termios array */
    tp = tty->termios;
    if (!devpts)
    tty->driver->termios[idx] = NULL;
    @@ -1457,6 +1469,7 @@ static void release_one_tty(struct tty_struct *tty, int idx)


    tty->magic = 0;
    + /* FIXME: locking on tty->driver->refcount */
    tty->driver->refcount--;

    file_list_lock();
    @@ -1467,6 +1480,21 @@ static void release_one_tty(struct tty_struct *tty, int idx)
    }

    /**
    + * tty_kref_put - release a tty kref
    + * @tty: tty device
    + *
    + * Release a reference to a tty device and if need be let the kref
    + * layer destruct the object for us
    + */
    +
    +void tty_kref_put(struct tty_struct *tty)
    +{
    + if (tty)
    + kref_put(&tty->kref, release_one_tty);
    +}
    +EXPORT_SYMBOL(tty_kref_put);
    +
    +/**
    * release_tty - release tty structure memory
    *
    * Release both @tty and a possible linked partner (think pty pair),
    @@ -1477,14 +1505,20 @@ static void release_one_tty(struct tty_struct *tty, int idx)
    * takes the file list lock internally when working on the list
    * of ttys that the driver keeps.
    * FIXME: should we require tty_mutex is held here ??
    + *
    + * FIXME: We want to defer the module put of the driver to the
    + * destructor.
    */
    static void release_tty(struct tty_struct *tty, int idx)
    {
    struct tty_driver *driver = tty->driver;

    + /* This should always be true but check for the moment */
    + WARN_ON(tty->index != idx);
    +
    if (tty->link)
    - release_one_tty(tty->link, idx);
    - release_one_tty(tty, idx);
    + tty_kref_put(tty->link);
    + tty_kref_put(tty);
    module_put(driver->owner);
    }

    @@ -2798,6 +2832,7 @@ EXPORT_SYMBOL(do_SAK);
    static void initialize_tty_struct(struct tty_struct *tty)
    {
    memset(tty, 0, sizeof(struct tty_struct));
    + kref_init(&tty->kref);
    tty->magic = TTY_MAGIC;
    tty_ldisc_init(tty);
    tty->session = NULL;
    @@ -3053,9 +3088,12 @@ EXPORT_SYMBOL(tty_devnum);

    void proc_clear_tty(struct task_struct *p)
    {
    + struct tty_struct *tty;
    spin_lock_irq(&p->sighand->siglock);
    + tty = p->signal->tty;
    p->signal->tty = NULL;
    spin_unlock_irq(&p->sighand->siglock);
    + tty_kref_put(tty);
    }

    /* Called under the sighand lock */
    @@ -3071,9 +3109,13 @@ static void __proc_set_tty(struct task_struct *tsk, struct tty_struct *tty)
    tty->pgrp = get_pid(task_pgrp(tsk));
    spin_unlock_irqrestore(&tty->ctrl_lock, flags);
    tty->session = get_pid(task_session(tsk));
    + if (tsk->signal->tty) {
    + printk(KERN_DEBUG "tty not NULL!!\n");
    + tty_kref_put(tsk->signal->tty);
    + }
    }
    put_pid(tsk->signal->tty_old_pgrp);
    - tsk->signal->tty = tty;
    + tsk->signal->tty = tty_kref_get(tty);
    tsk->signal->tty_old_pgrp = NULL;
    }

    diff --git a/include/linux/tty.h b/include/linux/tty.h
    index e3612c3..b6e6c26 100644
    --- a/include/linux/tty.h
    +++ b/include/linux/tty.h
    @@ -209,6 +209,7 @@ struct tty_operations;

    struct tty_struct {
    int magic;
    + struct kref kref;
    struct tty_driver *driver;
    const struct tty_operations *ops;
    int index;
    @@ -311,6 +312,23 @@ extern int kmsg_redirect;
    extern void console_init(void);
    extern int vcs_init(void);

    +/**
    + * tty_kref_get - get a tty reference
    + * @tty: tty device
    + *
    + * Return a new reference to a tty object. The caller must hold
    + * sufficient locks/counts to ensure that their existing reference cannot
    + * go away
    + */
    +
    +extern inline struct tty_struct *tty_kref_get(struct tty_struct *tty)
    +{
    + if (tty)
    + kref_get(&tty->kref);
    + return tty;
    +}
    +extern void tty_kref_put(struct tty_struct *tty);
    +
    extern int tty_paranoia_check(struct tty_struct *tty, struct inode *inode,
    const char *routine);
    extern char *tty_name(struct tty_struct *tty, char *buf);
    diff --git a/kernel/fork.c b/kernel/fork.c
    index 7ce2ebe..30de644 100644
    --- a/kernel/fork.c
    +++ b/kernel/fork.c
    @@ -802,6 +802,7 @@ static int copy_signal(unsigned long clone_flags, struct task_struct *tsk)

    sig->leader = 0; /* session leadership doesn't inherit */
    sig->tty_old_pgrp = NULL;
    + sig->tty = NULL;

    sig->utime = sig->stime = sig->cutime = sig->cstime = cputime_zero;
    sig->gtime = cputime_zero;
    @@ -838,6 +839,7 @@ static int copy_signal(unsigned long clone_flags, struct task_struct *tsk)
    void __cleanup_signal(struct signal_struct *sig)
    {
    exit_thread_group_keys(sig);
    + tty_kref_put(sig->tty);
    kmem_cache_free(signal_cachep, sig);
    }

    @@ -1227,7 +1229,8 @@ static struct task_struct *copy_process(unsigned long clone_flags,
    p->nsproxy->pid_ns->child_reaper = p;

    p->signal->leader_pid = pid;
    - p->signal->tty = current->signal->tty;
    + tty_kref_put(p->signal->tty);
    + p->signal->tty = tty_kref_get(current->signal->tty);
    set_task_pgrp(p, task_pgrp_nr(current));
    set_task_session(p, task_session_nr(current));
    attach_pid(p, PIDTYPE_PGID, task_pgrp(current));
    diff --git a/kernel/sys.c b/kernel/sys.c
    index 038a7bc..234d945 100644
    --- a/kernel/sys.c
    +++ b/kernel/sys.c
    @@ -1060,9 +1060,7 @@ asmlinkage long sys_setsid(void)
    group_leader->signal->leader = 1;
    __set_special_pids(sid);

    - spin_lock(&group_leader->sighand->siglock);
    - group_leader->signal->tty = NULL;
    - spin_unlock(&group_leader->sighand->siglock);
    + proc_clear_tty(group_leader);

    err = session;
    out:

    --
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

  15. [PATCH 20/80] ip2: avoid add_timer with pending timer

    From: Akinobu Mita

    add_timer() is not suppose to be called when the timer is pending.
    ip2 driver attempts to avoid that condition by setting and resetting
    a flag (TimerOn) in timer function. But there is some gap between
    add_timer() and setting TimerOn.

    This patch fix this problem by using mod_timer() and remove TimerOn
    which has been unnecessary by this change.

    Signed-off-by: Akinobu Mita
    Signed-off-by: Jiri Slaby
    Signed-off-by: Alan Cox
    ---

    drivers/char/ip2/ip2main.c | 19 ++++---------------
    1 files changed, 4 insertions(+), 15 deletions(-)


    diff --git a/drivers/char/ip2/ip2main.c b/drivers/char/ip2/ip2main.c
    index 39269d1..66f52a2 100644
    --- a/drivers/char/ip2/ip2main.c
    +++ b/drivers/char/ip2/ip2main.c
    @@ -249,7 +249,6 @@ static unsigned long bh_counter;
    */
    #define POLL_TIMEOUT (jiffies + 1)
    static DEFINE_TIMER(PollTimer, ip2_poll, 0, 0);
    -static char TimerOn;

    #ifdef IP2DEBUG_TRACE
    /* Trace (debug) buffer data */
    @@ -374,11 +373,7 @@ static void __exit ip2_cleanup_module(void)
    int err;
    int i;

    - /* Stop poll timer if we had one. */
    - if (TimerOn) {
    - del_timer(&PollTimer);
    - TimerOn = 0;
    - }
    + del_timer_sync(&PollTimer);

    /* Reset the boards we have. */
    for (i = 0; i < IP2_MAX_BOARDS; i++)
    @@ -774,10 +769,8 @@ static int __init ip2_loadmain(void)
    }
    if (ip2config.irq[i] == CIR_POLL) {
    retry:
    - if (!TimerOn) {
    - PollTimer.expires = POLL_TIMEOUT;
    - add_timer(&PollTimer);
    - TimerOn = 1;
    + if (!timer_pending(&PollTimer)) {
    + mod_timer(&PollTimer, POLL_TIMEOUT);
    printk(KERN_INFO "IP2: polling\n");
    }
    } else {
    @@ -1283,16 +1276,12 @@ ip2_poll(unsigned long arg)
    {
    ip2trace (ITRC_NO_PORT, ITRC_INTR, 100, 0 );

    - TimerOn = 0; // it's the truth but not checked in service
    -
    // Just polled boards, IRQ = 0 will hit all non-interrupt boards.
    // It will NOT poll boards handled by hard interrupts.
    // The issue of queued BH interrupts is handled in ip2_interrupt().
    ip2_polled_interrupt();

    - PollTimer.expires = POLL_TIMEOUT;
    - add_timer( &PollTimer );
    - TimerOn = 1;
    + mod_timer(&PollTimer, POLL_TIMEOUT);

    ip2trace (ITRC_NO_PORT, ITRC_INTR, ITRC_RETURN, 0 );
    }

    --
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

  16. [PATCH 21/80] audit: Handle embedded NUL in TTY input auditing

    From: Miloslav Trmac

    Data read from a TTY can contain an embedded NUL byte (e.g. after
    pressing Ctrl-2, or sent to a PTY). After the previous patch, the data
    would be logged only up to the first NUL.

    This patch modifies the AUDIT_TTY record to always use the hexadecimal
    format, which does not terminate at the first NUL byte. The vast
    majority of recorded TTY input data will contain either ' ' or '\n', so
    the hexadecimal format would have been used anyway.

    Signed-off-by: Miloslav Trmac
    Signed-off-by: Alan Cox
    ---

    drivers/char/tty_audit.c | 2 +-
    1 files changed, 1 insertions(+), 1 deletions(-)


    diff --git a/drivers/char/tty_audit.c b/drivers/char/tty_audit.c
    index 3582f43..5787249 100644
    --- a/drivers/char/tty_audit.c
    +++ b/drivers/char/tty_audit.c
    @@ -93,7 +93,7 @@ static void tty_audit_buf_push(struct task_struct *tsk, uid_t loginuid,
    get_task_comm(name, tsk);
    audit_log_untrustedstring(ab, name);
    audit_log_format(ab, " data=");
    - audit_log_n_untrustedstring(ab, buf->data, buf->valid);
    + audit_log_n_hex(ab, buf->data, buf->valid);
    audit_log_end(ab);
    }
    buf->valid = 0;

    --
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

  17. [PATCH 31/80] uml: small cleanups and note bugs to be dealt with by uml authors...

    From: Alan Cox

    Signed-off-by: Alan Cox
    ---

    arch/um/drivers/line.c | 2 ++
    1 files changed, 2 insertions(+), 0 deletions(-)


    diff --git a/arch/um/drivers/line.c b/arch/um/drivers/line.c
    index d741f35..14a102e 100644
    --- a/arch/um/drivers/line.c
    +++ b/arch/um/drivers/line.c
    @@ -275,6 +275,8 @@ int line_ioctl(struct tty_struct *tty, struct file * file,
    case TIOCGLTC:
    case TIOCSLTC:
    #endif
    + /* Note: these are out of date as we now have TCGETS2 etc but this
    + whole lot should probably go away */
    case TCGETS:
    case TCSETSF:
    case TCSETSW:

    --
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

  18. [PATCH 39/80] tty: Add termiox

    From: Alan Cox

    We need a way to describe the various additional modes and flow control
    features that random weird hardware shows up and software such as wine
    wants to emulate as Windows supports them.

    TCGETX/TCSETX and the termiox ioctl are a SYS5 extension that we might as
    well adopt. This patches adds the structures and the basic ioctl interfaces
    when the TCGETX etc defines are added for an architecture. Drivers wishing
    to use this stuff need to add new methods.

    Signed-off-by: Alan Cox
    ---

    drivers/char/tty_ioctl.c | 58 ++++++++++++++++++++++++++++++++++++++++++++
    include/asm-x86/ioctls.h | 4 +++
    include/linux/termios.h | 15 +++++++++++
    include/linux/tty.h | 1 +
    include/linux/tty_driver.h | 9 +++++++
    5 files changed, 87 insertions(+), 0 deletions(-)


    diff --git a/drivers/char/tty_ioctl.c b/drivers/char/tty_ioctl.c
    index bf34e45..93bfa1d 100644
    --- a/drivers/char/tty_ioctl.c
    +++ b/drivers/char/tty_ioctl.c
    @@ -579,6 +579,50 @@ static int get_termio(struct tty_struct *tty, struct termio __user *termio)
    return 0;
    }

    +
    +#ifdef TCGETX
    +
    +/**
    + * set_termiox - set termiox fields if possible
    + * @tty: terminal
    + * @arg: termiox structure from user
    + * @opt: option flags for ioctl type
    + *
    + * Implement the device calling points for the SYS5 termiox ioctl
    + * interface in Linux
    + */
    +
    +static int set_termiox(struct tty_struct *tty, void __user *arg, int opt)
    +{
    + struct termiox tnew;
    + struct tty_ldisc *ld;
    +
    + if (tty->termiox == NULL)
    + return -EINVAL;
    + if (copy_from_user(&tnew, arg, sizeof(struct termiox)))
    + return -EFAULT;
    +
    + ld = tty_ldisc_ref(tty);
    + if (ld != NULL) {
    + if ((opt & TERMIOS_FLUSH) && ld->ops->flush_buffer)
    + ld->ops->flush_buffer(tty);
    + tty_ldisc_deref(ld);
    + }
    + if (opt & TERMIOS_WAIT) {
    + tty_wait_until_sent(tty, 0);
    + if (signal_pending(current))
    + return -EINTR;
    + }
    +
    + mutex_lock(&tty->termios_mutex);
    + if (tty->ops->set_termiox)
    + tty->ops->set_termiox(tty, &tnew);
    + mutex_unlock(&tty->termios_mutex);
    + return 0;
    +}
    +
    +#endif
    +
    static unsigned long inq_canon(struct tty_struct *tty)
    {
    int nr, head, tail;
    @@ -936,6 +980,20 @@ int tty_mode_ioctl(struct tty_struct *tty, struct file *file,
    return -EFAULT;
    return 0;
    #endif
    +#ifdef TCGETX
    + case TCGETX:
    + if (real_tty->termiox == NULL)
    + return -EINVAL;
    + if (copy_to_user(p, real_tty->termiox, sizeof(struct termiox)))
    + return -EFAULT;
    + return 0;
    + case TCSETX:
    + return set_termiox(real_tty, p, 0);
    + case TCSETXW:
    + return set_termiox(real_tty, p, TERMIOS_WAIT);
    + case TCSETXF:
    + return set_termiox(real_tty, p, TERMIOS_FLUSH);
    +#endif
    case TIOCGSOFTCAR:
    /* FIXME: for correctness we may need to take the termios
    lock here - review */
    diff --git a/include/asm-x86/ioctls.h b/include/asm-x86/ioctls.h
    index 1a8ac45..06752a6 100644
    --- a/include/asm-x86/ioctls.h
    +++ b/include/asm-x86/ioctls.h
    @@ -56,6 +56,10 @@
    #define TIOCGPTN _IOR('T', 0x30, unsigned int)
    /* Get Pty Number (of pty-mux device) */
    #define TIOCSPTLCK _IOW('T', 0x31, int) /* Lock/unlock Pty */
    +#define TCGETX 0x5432 /* SYS5 TCGETX compatibility */
    +#define TCSETX 0x5433
    +#define TCSETXF 0x5434
    +#define TCSETXW 0x5435

    #define FIONCLEX 0x5450
    #define FIOCLEX 0x5451
    diff --git a/include/linux/termios.h b/include/linux/termios.h
    index 4786628..2acd0c1 100644
    --- a/include/linux/termios.h
    +++ b/include/linux/termios.h
    @@ -4,4 +4,19 @@
    #include
    #include

    +#define NFF 5
    +
    +struct termiox
    +{
    + __u16 x_hflag;
    + __u16 x_cflag;
    + __u16 x_rflag[NFF];
    + __u16 x_sflag;
    +};
    +
    +#define RTSXOFF 0x0001 /* RTS flow control on input */
    +#define CTSXON 0x0002 /* CTS flow control on output */
    +#define DTRXOFF 0x0004 /* DTR flow control on input */
    +#define DSRXON 0x0008 /* DCD flow control on output */
    +
    #endif
    diff --git a/include/linux/tty.h b/include/linux/tty.h
    index b6e6c26..b64d10b 100644
    --- a/include/linux/tty.h
    +++ b/include/linux/tty.h
    @@ -219,6 +219,7 @@ struct tty_struct {
    spinlock_t ctrl_lock;
    /* Termios values are protected by the termios mutex */
    struct ktermios *termios, *termios_locked;
    + struct termiox *termiox; /* May be NULL for unsupported */
    char name[64];
    struct pid *pgrp; /* Protected by ctrl lock */
    struct pid *session;
    diff --git a/include/linux/tty_driver.h b/include/linux/tty_driver.h
    index 16d2794..ac6e58e 100644
    --- a/include/linux/tty_driver.h
    +++ b/include/linux/tty_driver.h
    @@ -180,6 +180,14 @@
    * not force errors here if they are not resizable objects (eg a serial
    * line). See tty_do_resize() if you need to wrap the standard method
    * in your own logic - the usual case.
    + *
    + * void (*set_termiox)(struct tty_struct *tty, struct termiox *new);
    + *
    + * Called when the device receives a termiox based ioctl. Passes down
    + * the requested data from user space. This method will not be invoked
    + * unless the tty also has a valid tty->termiox pointer.
    + *
    + * Optional: Called under the termios lock
    */

    #include
    @@ -220,6 +228,7 @@ struct tty_operations {
    unsigned int set, unsigned int clear);
    int (*resize)(struct tty_struct *tty, struct tty_struct *real_tty,
    struct winsize *ws);
    + int (*set_termiox)(struct tty_struct *tty, struct termiox *tnew);
    #ifdef CONFIG_CONSOLE_POLL
    int (*poll_init)(struct tty_driver *driver, int line, char *options);
    int (*poll_get_char)(struct tty_driver *driver, int line);

    --
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

  19. [PATCH 30/80] tty: move tioclinux from a special case

    From: Alan Cox

    Right now we have ifdefs and hooks in the core ioctl handler for TIOCLINUX
    and then test if its a console. This is brain dead. Instead call the
    tioclinux helper from the relevant driver ioctl methods.

    Signed-off-by: Alan Cox
    ---

    drivers/char/tty_io.c | 4 ----
    drivers/char/vt.c | 2 --
    drivers/char/vt_ioctl.c | 2 ++
    3 files changed, 2 insertions(+), 6 deletions(-)


    diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
    index e4dce87..2f05728 100644
    --- a/drivers/char/tty_io.c
    +++ b/drivers/char/tty_io.c
    @@ -3026,10 +3026,6 @@ long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
    return put_user(tty->ldisc.ops->num, (int __user *)p);
    case TIOCSETD:
    return tiocsetd(tty, p);
    -#ifdef CONFIG_VT
    - case TIOCLINUX:
    - return tioclinux(tty, arg);
    -#endif
    /*
    * Break handling
    */
    diff --git a/drivers/char/vt.c b/drivers/char/vt.c
    index 60359c3..05ca1c5 100644
    --- a/drivers/char/vt.c
    +++ b/drivers/char/vt.c
    @@ -2583,8 +2583,6 @@ int tioclinux(struct tty_struct *tty, unsigned long arg)
    int lines;
    int ret;

    - if (tty->driver->type != TTY_DRIVER_TYPE_CONSOLE)
    - return -EINVAL;
    if (current->signal->tty != tty && !capable(CAP_SYS_ADMIN))
    return -EPERM;
    if (get_user(type, p))
    diff --git a/drivers/char/vt_ioctl.c b/drivers/char/vt_ioctl.c
    index c904e9a..8944ce5 100644
    --- a/drivers/char/vt_ioctl.c
    +++ b/drivers/char/vt_ioctl.c
    @@ -395,6 +395,8 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,

    kbd = kbd_table + console;
    switch (cmd) {
    + case TIOCLINUX:
    + return tioclinux(tty, arg);
    case KIOCSOUND:
    if (!perm)
    goto eperm;

    --
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

  20. [PATCH 29/80] serial: allow 8250 to be used on sparc

    From: David Miller

    This requires three changes:

    1) Remove !SPARC restriction in Kconfig.

    2) Move Sparc specific serial drivers before 8250, so that serial
    console devices don't change names on us, even if 8250 finds
    devices.

    3) Since the Sparc specific serial drivers try to use the
    same major/minor device namespace as 8250, some coordination
    is necessary. Use the sunserial_*() layer routines to allocate
    minor number space within TTY_MAJOR when CONFIG_SPARC.

    This has no effect on other platforms.

    Thanks to Josip Rodin for bringing up this issue and testing
    plus debugging various revisions of this patch.

    Signed-off-by: David S. Miller
    Signed-off-by: Andrew Morton
    Signed-off-by: Alan Cox
    ---

    arch/sparc/include/asm/serial.h | 6 ++++++
    drivers/serial/8250.c | 21 +++++++++++++++++----
    drivers/serial/Kconfig | 1 -
    drivers/serial/Makefile | 15 ++++++++++-----
    4 files changed, 33 insertions(+), 10 deletions(-)
    create mode 100644 arch/sparc/include/asm/serial.h


    diff --git a/arch/sparc/include/asm/serial.h b/arch/sparc/include/asm/serial.h
    new file mode 100644
    index 0000000..f90d61c
    --- /dev/null
    +++ b/arch/sparc/include/asm/serial.h
    @@ -0,0 +1,6 @@
    +#ifndef __SPARC_SERIAL_H
    +#define __SPARC_SERIAL_H
    +
    +#define BASE_BAUD ( 1843200 / 16 )
    +
    +#endif /* __SPARC_SERIAL_H */
    diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c
    index ed593c4..db2cdc1 100644
    --- a/drivers/serial/8250.c
    +++ b/drivers/serial/8250.c
    @@ -44,6 +44,10 @@

    #include "8250.h"

    +#ifdef CONFIG_SPARC
    +#include "suncore.h"
    +#endif
    +
    /*
    * Configuration:
    * share_irqs - whether we pass IRQF_SHARED to request_irq(). This option
    @@ -2676,7 +2680,6 @@ static struct uart_driver serial8250_reg = {
    .dev_name = "ttyS",
    .major = TTY_MAJOR,
    .minor = 64,
    - .nr = UART_NR,
    .cons = SERIAL8250_CONSOLE,
    };

    @@ -2958,10 +2961,12 @@ static int __init serial8250_init(void)
    "%d ports, IRQ sharing %sabled\n", nr_uarts,
    share_irqs ? "en" : "dis");

    - for (i = 0; i < NR_IRQS; i++)
    - spin_lock_init(&irq_lists[i].lock);
    -
    +#ifdef CONFIG_SPARC
    + ret = sunserial_register_minors(&serial8250_reg, UART_NR);
    +#else
    + serial8250_reg.nr = UART_NR;
    ret = uart_register_driver(&serial8250_reg);
    +#endif
    if (ret)
    goto out;

    @@ -2986,7 +2991,11 @@ static int __init serial8250_init(void)
    put_dev:
    platform_device_put(serial8250_isa_devs);
    unreg_uart_drv:
    +#ifdef CONFIG_SPARC
    + sunserial_unregister_minors(&serial8250_reg, UART_NR);
    +#else
    uart_unregister_driver(&serial8250_reg);
    +#endif
    out:
    return ret;
    }
    @@ -3005,7 +3014,11 @@ static void __exit serial8250_exit(void)
    platform_driver_unregister(&serial8250_isa_driver);
    platform_device_unregister(isa_dev);

    +#ifdef CONFIG_SPARC
    + sunserial_unregister_minors(&serial8250_reg, UART_NR);
    +#else
    uart_unregister_driver(&serial8250_reg);
    +#endif
    }

    module_init(serial8250_init);
    diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
    index 0db2045..31786b3 100644
    --- a/drivers/serial/Kconfig
    +++ b/drivers/serial/Kconfig
    @@ -9,7 +9,6 @@ menu "Serial drivers"
    # The new 8250/16550 serial drivers
    config SERIAL_8250
    tristate "8250/16550 and compatible serial support"
    - depends on (BROKEN || !SPARC)
    select SERIAL_CORE
    ---help---
    This selects whether you want to include the driver for the standard
    diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile
    index 1462eb3..0c17c8d 100644
    --- a/drivers/serial/Makefile
    +++ b/drivers/serial/Makefile
    @@ -4,6 +4,16 @@

    obj-$(CONFIG_SERIAL_CORE) += serial_core.o
    obj-$(CONFIG_SERIAL_21285) += 21285.o
    +
    +# These Sparc drivers have to appear before others such as 8250
    +# which share ttySx minor node space. Otherwise console device
    +# names change and other unplesantries.
    +obj-$(CONFIG_SERIAL_SUNCORE) += suncore.o
    +obj-$(CONFIG_SERIAL_SUNHV) += sunhv.o
    +obj-$(CONFIG_SERIAL_SUNZILOG) += sunzilog.o
    +obj-$(CONFIG_SERIAL_SUNSU) += sunsu.o
    +obj-$(CONFIG_SERIAL_SUNSAB) += sunsab.o
    +
    obj-$(CONFIG_SERIAL_8250) += 8250.o
    obj-$(CONFIG_SERIAL_8250_PNP) += 8250_pnp.o
    obj-$(CONFIG_SERIAL_8250_GSC) += 8250_gsc.o
    @@ -31,12 +41,7 @@ obj-$(CONFIG_SERIAL_S3C2400) += s3c2400.o
    obj-$(CONFIG_SERIAL_S3C2410) += s3c2410.o
    obj-$(CONFIG_SERIAL_S3C2412) += s3c2412.o
    obj-$(CONFIG_SERIAL_S3C2440) += s3c2440.o
    -obj-$(CONFIG_SERIAL_SUNCORE) += suncore.o
    -obj-$(CONFIG_SERIAL_SUNHV) += sunhv.o
    -obj-$(CONFIG_SERIAL_SUNZILOG) += sunzilog.o
    obj-$(CONFIG_SERIAL_IP22_ZILOG) += ip22zilog.o
    -obj-$(CONFIG_SERIAL_SUNSU) += sunsu.o
    -obj-$(CONFIG_SERIAL_SUNSAB) += sunsab.o
    obj-$(CONFIG_SERIAL_MUX) += mux.o
    obj-$(CONFIG_SERIAL_68328) += 68328serial.o
    obj-$(CONFIG_SERIAL_68360) += 68360serial.o

    --
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

+ Reply to Thread
Page 1 of 4 1 2 3 ... LastLast