mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-24 04:34:08 +08:00
TTY/Serial driver update for 3.10-rc1
Here's the big tty/serial driver merge request for 3.10-rc1 Once again, Jiri has a number of TTY driver fixes and cleanups, and Peter Hurley came through with a bunch of ldisc fixes that resolve a number of reported issues. There are some other serial driver cleanups as well. All of these have been in the linux-next tree for a while. Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> -----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.19 (GNU/Linux) iEYEABECAAYFAlF+nSMACgkQMUfUDdst+ymy9QCfRmYn0MC0W+Q1D3Spz87gVsuo cqEAniu1BEkYZpjAz7ZlIN07Ao0jbQOR =Osu/ -----END PGP SIGNATURE----- Merge tag 'tty-3.10-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty Pull tty/serial driver update from Greg Kroah-Hartman: "Here's the big tty/serial driver merge request for 3.10-rc1 Once again, Jiri has a number of TTY driver fixes and cleanups, and Peter Hurley came through with a bunch of ldisc fixes that resolve a number of reported issues. There are some other serial driver cleanups as well. All of these have been in the linux-next tree for a while" * tag 'tty-3.10-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty: (117 commits) tty/serial/sirf: fix MODULE_DEVICE_TABLE serial: mxs: drop superfluous {get|put}_device serial: mxs: fix buffer overflow ARM: PL011: add support for extended FIFO-size of PL011-r1p5 serial_core.c: add put_device() after device_find_child() tty: Fix unsafe bit ops in tty_throttle_safe/unthrottle_safe serial: sccnxp: Replace pdata.init/exit with regulator API serial: sccnxp: Do not override device name TTY: pty, fix compilation warning TTY: rocket, fix compilation warning TTY: ircomm: fix DTR being raised on hang up TTY: synclinkmp: fix DTR being raised on hang up TTY: synclink_gt: fix DTR being raised on hang up TTY: synclink: fix DTR being raised on hang up serial: 8250_dw: Fix the stub for dw8250_probe_acpi() serial: 8250_dw: Convert to devm_ioremap() serial: 8250_dw: Set port capabilities based on CPR register serial: 8250_dw: Let ACPI code extract the DMA client info serial: 8250_dw: Support clk framework also with ACPI serial: 8250_dw: Enable runtime PM ...
This commit is contained in:
commit
507ffe4f38
@ -33,6 +33,10 @@ Optional properties:
|
||||
RTAS and should not be registered.
|
||||
- no-loopback-test: set to indicate that the port does not implements loopback
|
||||
test mode
|
||||
- fifo-size: the fifo size of the UART.
|
||||
- auto-flow-control: one way to enable automatic flow control support. The
|
||||
driver is allowed to detect support for the capability even without this
|
||||
property.
|
||||
|
||||
Example:
|
||||
|
||||
|
@ -123,6 +123,11 @@ static struct clk s3c2440_clk_ac97 = {
|
||||
.ctrlbit = S3C2440_CLKCON_AC97,
|
||||
};
|
||||
|
||||
#define S3C24XX_VA_UART0 (S3C_VA_UART)
|
||||
#define S3C24XX_VA_UART1 (S3C_VA_UART + 0x4000 )
|
||||
#define S3C24XX_VA_UART2 (S3C_VA_UART + 0x8000 )
|
||||
#define S3C24XX_VA_UART3 (S3C_VA_UART + 0xC000 )
|
||||
|
||||
static unsigned long s3c2440_fclk_n_getrate(struct clk *clk)
|
||||
{
|
||||
unsigned long ucon0, ucon1, ucon2, divisor;
|
||||
|
@ -239,6 +239,11 @@ void __init s3c24xx_init_io(struct map_desc *mach_desc, int size)
|
||||
|
||||
/* Serial port registrations */
|
||||
|
||||
#define S3C2410_PA_UART0 (S3C24XX_PA_UART)
|
||||
#define S3C2410_PA_UART1 (S3C24XX_PA_UART + 0x4000 )
|
||||
#define S3C2410_PA_UART2 (S3C24XX_PA_UART + 0x8000 )
|
||||
#define S3C2443_PA_UART3 (S3C24XX_PA_UART + 0xC000 )
|
||||
|
||||
static struct resource s3c2410_uart0_resource[] = {
|
||||
[0] = DEFINE_RES_MEM(S3C2410_PA_UART0, SZ_16K),
|
||||
[1] = DEFINE_RES_NAMED(IRQ_S3CUART_RX0, \
|
||||
|
@ -1,281 +1 @@
|
||||
/* arch/arm/plat-samsung/include/plat/regs-serial.h
|
||||
*
|
||||
* From linux/include/asm-arm/hardware/serial_s3c2410.h
|
||||
*
|
||||
* Internal header file for Samsung S3C2410 serial ports (UART0-2)
|
||||
*
|
||||
* Copyright (C) 2002 Shane Nay (shane@minirl.com)
|
||||
*
|
||||
* Additional defines, Copyright 2003 Simtec Electronics (linux@simtec.co.uk)
|
||||
*
|
||||
* Adapted from:
|
||||
*
|
||||
* Internal header file for MX1ADS serial ports (UART1 & 2)
|
||||
*
|
||||
* Copyright (C) 2002 Shane Nay (shane@minirl.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef __ASM_ARM_REGS_SERIAL_H
|
||||
#define __ASM_ARM_REGS_SERIAL_H
|
||||
|
||||
#define S3C24XX_VA_UART0 (S3C_VA_UART)
|
||||
#define S3C24XX_VA_UART1 (S3C_VA_UART + 0x4000 )
|
||||
#define S3C24XX_VA_UART2 (S3C_VA_UART + 0x8000 )
|
||||
#define S3C24XX_VA_UART3 (S3C_VA_UART + 0xC000 )
|
||||
|
||||
#define S3C2410_PA_UART0 (S3C24XX_PA_UART)
|
||||
#define S3C2410_PA_UART1 (S3C24XX_PA_UART + 0x4000 )
|
||||
#define S3C2410_PA_UART2 (S3C24XX_PA_UART + 0x8000 )
|
||||
#define S3C2443_PA_UART3 (S3C24XX_PA_UART + 0xC000 )
|
||||
|
||||
#define S3C2410_URXH (0x24)
|
||||
#define S3C2410_UTXH (0x20)
|
||||
#define S3C2410_ULCON (0x00)
|
||||
#define S3C2410_UCON (0x04)
|
||||
#define S3C2410_UFCON (0x08)
|
||||
#define S3C2410_UMCON (0x0C)
|
||||
#define S3C2410_UBRDIV (0x28)
|
||||
#define S3C2410_UTRSTAT (0x10)
|
||||
#define S3C2410_UERSTAT (0x14)
|
||||
#define S3C2410_UFSTAT (0x18)
|
||||
#define S3C2410_UMSTAT (0x1C)
|
||||
|
||||
#define S3C2410_LCON_CFGMASK ((0xF<<3)|(0x3))
|
||||
|
||||
#define S3C2410_LCON_CS5 (0x0)
|
||||
#define S3C2410_LCON_CS6 (0x1)
|
||||
#define S3C2410_LCON_CS7 (0x2)
|
||||
#define S3C2410_LCON_CS8 (0x3)
|
||||
#define S3C2410_LCON_CSMASK (0x3)
|
||||
|
||||
#define S3C2410_LCON_PNONE (0x0)
|
||||
#define S3C2410_LCON_PEVEN (0x5 << 3)
|
||||
#define S3C2410_LCON_PODD (0x4 << 3)
|
||||
#define S3C2410_LCON_PMASK (0x7 << 3)
|
||||
|
||||
#define S3C2410_LCON_STOPB (1<<2)
|
||||
#define S3C2410_LCON_IRM (1<<6)
|
||||
|
||||
#define S3C2440_UCON_CLKMASK (3<<10)
|
||||
#define S3C2440_UCON_CLKSHIFT (10)
|
||||
#define S3C2440_UCON_PCLK (0<<10)
|
||||
#define S3C2440_UCON_UCLK (1<<10)
|
||||
#define S3C2440_UCON_PCLK2 (2<<10)
|
||||
#define S3C2440_UCON_FCLK (3<<10)
|
||||
#define S3C2443_UCON_EPLL (3<<10)
|
||||
|
||||
#define S3C6400_UCON_CLKMASK (3<<10)
|
||||
#define S3C6400_UCON_CLKSHIFT (10)
|
||||
#define S3C6400_UCON_PCLK (0<<10)
|
||||
#define S3C6400_UCON_PCLK2 (2<<10)
|
||||
#define S3C6400_UCON_UCLK0 (1<<10)
|
||||
#define S3C6400_UCON_UCLK1 (3<<10)
|
||||
|
||||
#define S3C2440_UCON2_FCLK_EN (1<<15)
|
||||
#define S3C2440_UCON0_DIVMASK (15 << 12)
|
||||
#define S3C2440_UCON1_DIVMASK (15 << 12)
|
||||
#define S3C2440_UCON2_DIVMASK (7 << 12)
|
||||
#define S3C2440_UCON_DIVSHIFT (12)
|
||||
|
||||
#define S3C2412_UCON_CLKMASK (3<<10)
|
||||
#define S3C2412_UCON_CLKSHIFT (10)
|
||||
#define S3C2412_UCON_UCLK (1<<10)
|
||||
#define S3C2412_UCON_USYSCLK (3<<10)
|
||||
#define S3C2412_UCON_PCLK (0<<10)
|
||||
#define S3C2412_UCON_PCLK2 (2<<10)
|
||||
|
||||
#define S3C2410_UCON_CLKMASK (1 << 10)
|
||||
#define S3C2410_UCON_CLKSHIFT (10)
|
||||
#define S3C2410_UCON_UCLK (1<<10)
|
||||
#define S3C2410_UCON_SBREAK (1<<4)
|
||||
|
||||
#define S3C2410_UCON_TXILEVEL (1<<9)
|
||||
#define S3C2410_UCON_RXILEVEL (1<<8)
|
||||
#define S3C2410_UCON_TXIRQMODE (1<<2)
|
||||
#define S3C2410_UCON_RXIRQMODE (1<<0)
|
||||
#define S3C2410_UCON_RXFIFO_TOI (1<<7)
|
||||
#define S3C2443_UCON_RXERR_IRQEN (1<<6)
|
||||
#define S3C2443_UCON_LOOPBACK (1<<5)
|
||||
|
||||
#define S3C2410_UCON_DEFAULT (S3C2410_UCON_TXILEVEL | \
|
||||
S3C2410_UCON_RXILEVEL | \
|
||||
S3C2410_UCON_TXIRQMODE | \
|
||||
S3C2410_UCON_RXIRQMODE | \
|
||||
S3C2410_UCON_RXFIFO_TOI)
|
||||
|
||||
#define S3C2410_UFCON_FIFOMODE (1<<0)
|
||||
#define S3C2410_UFCON_TXTRIG0 (0<<6)
|
||||
#define S3C2410_UFCON_RXTRIG8 (1<<4)
|
||||
#define S3C2410_UFCON_RXTRIG12 (2<<4)
|
||||
|
||||
/* S3C2440 FIFO trigger levels */
|
||||
#define S3C2440_UFCON_RXTRIG1 (0<<4)
|
||||
#define S3C2440_UFCON_RXTRIG8 (1<<4)
|
||||
#define S3C2440_UFCON_RXTRIG16 (2<<4)
|
||||
#define S3C2440_UFCON_RXTRIG32 (3<<4)
|
||||
|
||||
#define S3C2440_UFCON_TXTRIG0 (0<<6)
|
||||
#define S3C2440_UFCON_TXTRIG16 (1<<6)
|
||||
#define S3C2440_UFCON_TXTRIG32 (2<<6)
|
||||
#define S3C2440_UFCON_TXTRIG48 (3<<6)
|
||||
|
||||
#define S3C2410_UFCON_RESETBOTH (3<<1)
|
||||
#define S3C2410_UFCON_RESETTX (1<<2)
|
||||
#define S3C2410_UFCON_RESETRX (1<<1)
|
||||
|
||||
#define S3C2410_UFCON_DEFAULT (S3C2410_UFCON_FIFOMODE | \
|
||||
S3C2410_UFCON_TXTRIG0 | \
|
||||
S3C2410_UFCON_RXTRIG8 )
|
||||
|
||||
#define S3C2410_UMCOM_AFC (1<<4)
|
||||
#define S3C2410_UMCOM_RTS_LOW (1<<0)
|
||||
|
||||
#define S3C2412_UMCON_AFC_63 (0<<5) /* same as s3c2443 */
|
||||
#define S3C2412_UMCON_AFC_56 (1<<5)
|
||||
#define S3C2412_UMCON_AFC_48 (2<<5)
|
||||
#define S3C2412_UMCON_AFC_40 (3<<5)
|
||||
#define S3C2412_UMCON_AFC_32 (4<<5)
|
||||
#define S3C2412_UMCON_AFC_24 (5<<5)
|
||||
#define S3C2412_UMCON_AFC_16 (6<<5)
|
||||
#define S3C2412_UMCON_AFC_8 (7<<5)
|
||||
|
||||
#define S3C2410_UFSTAT_TXFULL (1<<9)
|
||||
#define S3C2410_UFSTAT_RXFULL (1<<8)
|
||||
#define S3C2410_UFSTAT_TXMASK (15<<4)
|
||||
#define S3C2410_UFSTAT_TXSHIFT (4)
|
||||
#define S3C2410_UFSTAT_RXMASK (15<<0)
|
||||
#define S3C2410_UFSTAT_RXSHIFT (0)
|
||||
|
||||
/* UFSTAT S3C2443 same as S3C2440 */
|
||||
#define S3C2440_UFSTAT_TXFULL (1<<14)
|
||||
#define S3C2440_UFSTAT_RXFULL (1<<6)
|
||||
#define S3C2440_UFSTAT_TXSHIFT (8)
|
||||
#define S3C2440_UFSTAT_RXSHIFT (0)
|
||||
#define S3C2440_UFSTAT_TXMASK (63<<8)
|
||||
#define S3C2440_UFSTAT_RXMASK (63)
|
||||
|
||||
#define S3C2410_UTRSTAT_TXE (1<<2)
|
||||
#define S3C2410_UTRSTAT_TXFE (1<<1)
|
||||
#define S3C2410_UTRSTAT_RXDR (1<<0)
|
||||
|
||||
#define S3C2410_UERSTAT_OVERRUN (1<<0)
|
||||
#define S3C2410_UERSTAT_FRAME (1<<2)
|
||||
#define S3C2410_UERSTAT_BREAK (1<<3)
|
||||
#define S3C2443_UERSTAT_PARITY (1<<1)
|
||||
|
||||
#define S3C2410_UERSTAT_ANY (S3C2410_UERSTAT_OVERRUN | \
|
||||
S3C2410_UERSTAT_FRAME | \
|
||||
S3C2410_UERSTAT_BREAK)
|
||||
|
||||
#define S3C2410_UMSTAT_CTS (1<<0)
|
||||
#define S3C2410_UMSTAT_DeltaCTS (1<<2)
|
||||
|
||||
#define S3C2443_DIVSLOT (0x2C)
|
||||
|
||||
/* S3C64XX interrupt registers. */
|
||||
#define S3C64XX_UINTP 0x30
|
||||
#define S3C64XX_UINTSP 0x34
|
||||
#define S3C64XX_UINTM 0x38
|
||||
|
||||
#define S3C64XX_UINTM_RXD (0)
|
||||
#define S3C64XX_UINTM_TXD (2)
|
||||
#define S3C64XX_UINTM_RXD_MSK (1 << S3C64XX_UINTM_RXD)
|
||||
#define S3C64XX_UINTM_TXD_MSK (1 << S3C64XX_UINTM_TXD)
|
||||
|
||||
/* Following are specific to S5PV210 */
|
||||
#define S5PV210_UCON_CLKMASK (1<<10)
|
||||
#define S5PV210_UCON_CLKSHIFT (10)
|
||||
#define S5PV210_UCON_PCLK (0<<10)
|
||||
#define S5PV210_UCON_UCLK (1<<10)
|
||||
|
||||
#define S5PV210_UFCON_TXTRIG0 (0<<8)
|
||||
#define S5PV210_UFCON_TXTRIG4 (1<<8)
|
||||
#define S5PV210_UFCON_TXTRIG8 (2<<8)
|
||||
#define S5PV210_UFCON_TXTRIG16 (3<<8)
|
||||
#define S5PV210_UFCON_TXTRIG32 (4<<8)
|
||||
#define S5PV210_UFCON_TXTRIG64 (5<<8)
|
||||
#define S5PV210_UFCON_TXTRIG128 (6<<8)
|
||||
#define S5PV210_UFCON_TXTRIG256 (7<<8)
|
||||
|
||||
#define S5PV210_UFCON_RXTRIG1 (0<<4)
|
||||
#define S5PV210_UFCON_RXTRIG4 (1<<4)
|
||||
#define S5PV210_UFCON_RXTRIG8 (2<<4)
|
||||
#define S5PV210_UFCON_RXTRIG16 (3<<4)
|
||||
#define S5PV210_UFCON_RXTRIG32 (4<<4)
|
||||
#define S5PV210_UFCON_RXTRIG64 (5<<4)
|
||||
#define S5PV210_UFCON_RXTRIG128 (6<<4)
|
||||
#define S5PV210_UFCON_RXTRIG256 (7<<4)
|
||||
|
||||
#define S5PV210_UFSTAT_TXFULL (1<<24)
|
||||
#define S5PV210_UFSTAT_RXFULL (1<<8)
|
||||
#define S5PV210_UFSTAT_TXMASK (255<<16)
|
||||
#define S5PV210_UFSTAT_TXSHIFT (16)
|
||||
#define S5PV210_UFSTAT_RXMASK (255<<0)
|
||||
#define S5PV210_UFSTAT_RXSHIFT (0)
|
||||
|
||||
#define S3C2410_UCON_CLKSEL0 (1 << 0)
|
||||
#define S3C2410_UCON_CLKSEL1 (1 << 1)
|
||||
#define S3C2410_UCON_CLKSEL2 (1 << 2)
|
||||
#define S3C2410_UCON_CLKSEL3 (1 << 3)
|
||||
|
||||
/* Default values for s5pv210 UCON and UFCON uart registers */
|
||||
#define S5PV210_UCON_DEFAULT (S3C2410_UCON_TXILEVEL | \
|
||||
S3C2410_UCON_RXILEVEL | \
|
||||
S3C2410_UCON_TXIRQMODE | \
|
||||
S3C2410_UCON_RXIRQMODE | \
|
||||
S3C2410_UCON_RXFIFO_TOI | \
|
||||
S3C2443_UCON_RXERR_IRQEN)
|
||||
|
||||
#define S5PV210_UFCON_DEFAULT (S3C2410_UFCON_FIFOMODE | \
|
||||
S5PV210_UFCON_TXTRIG4 | \
|
||||
S5PV210_UFCON_RXTRIG4)
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
|
||||
/* configuration structure for per-machine configurations for the
|
||||
* serial port
|
||||
*
|
||||
* the pointer is setup by the machine specific initialisation from the
|
||||
* arch/arm/mach-s3c2410/ directory.
|
||||
*/
|
||||
|
||||
struct s3c2410_uartcfg {
|
||||
unsigned char hwport; /* hardware port number */
|
||||
unsigned char unused;
|
||||
unsigned short flags;
|
||||
upf_t uart_flags; /* default uart flags */
|
||||
unsigned int clk_sel;
|
||||
|
||||
unsigned int has_fracval;
|
||||
|
||||
unsigned long ucon; /* value of ucon for port */
|
||||
unsigned long ulcon; /* value of ulcon for port */
|
||||
unsigned long ufcon; /* value of ufcon for port */
|
||||
};
|
||||
|
||||
/* s3c24xx_uart_devs
|
||||
*
|
||||
* this is exported from the core as we cannot use driver_register(),
|
||||
* or platform_add_device() before the console_initcall()
|
||||
*/
|
||||
|
||||
extern struct platform_device *s3c24xx_uart_devs[4];
|
||||
|
||||
#endif /* __ASSEMBLY__ */
|
||||
|
||||
#endif /* __ASM_ARM_REGS_SERIAL_H */
|
||||
|
||||
#include <linux/serial_s3c.h>
|
||||
|
@ -142,8 +142,7 @@ static void transmit_chars(struct tty_struct *tty, struct serial_state *info,
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (info->xmit.head == info->xmit.tail || tty->stopped ||
|
||||
tty->hw_stopped) {
|
||||
if (info->xmit.head == info->xmit.tail || tty->stopped) {
|
||||
#ifdef SIMSERIAL_DEBUG
|
||||
printk("transmit_chars: head=%d, tail=%d, stopped=%d\n",
|
||||
info->xmit.head, info->xmit.tail, tty->stopped);
|
||||
@ -181,7 +180,7 @@ static void rs_flush_chars(struct tty_struct *tty)
|
||||
struct serial_state *info = tty->driver_data;
|
||||
|
||||
if (info->xmit.head == info->xmit.tail || tty->stopped ||
|
||||
tty->hw_stopped || !info->xmit.buf)
|
||||
!info->xmit.buf)
|
||||
return;
|
||||
|
||||
transmit_chars(tty, info, NULL);
|
||||
@ -217,7 +216,7 @@ static int rs_write(struct tty_struct * tty,
|
||||
* Hey, we transmit directly from here in our case
|
||||
*/
|
||||
if (CIRC_CNT(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE) &&
|
||||
!tty->stopped && !tty->hw_stopped)
|
||||
!tty->stopped)
|
||||
transmit_chars(tty, info, NULL);
|
||||
|
||||
return ret;
|
||||
@ -325,14 +324,6 @@ static int rs_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg)
|
||||
|
||||
#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
|
||||
|
||||
static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
|
||||
{
|
||||
/* Handle turning off CRTSCTS */
|
||||
if ((old_termios->c_cflag & CRTSCTS) &&
|
||||
!(tty->termios.c_cflag & CRTSCTS)) {
|
||||
tty->hw_stopped = 0;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* This routine will shutdown a serial port; interrupts are disabled, and
|
||||
* DTR is dropped if the hangup on close termio flag is on.
|
||||
@ -481,7 +472,6 @@ static const struct tty_operations hp_ops = {
|
||||
.throttle = rs_throttle,
|
||||
.unthrottle = rs_unthrottle,
|
||||
.send_xchar = rs_send_xchar,
|
||||
.set_termios = rs_set_termios,
|
||||
.hangup = rs_hangup,
|
||||
.proc_fops = &rs_proc_fops,
|
||||
};
|
||||
|
@ -568,11 +568,7 @@ void chan_interrupt(struct line *line, int irq)
|
||||
reactivate_fd(chan->fd, irq);
|
||||
if (err == -EIO) {
|
||||
if (chan->primary) {
|
||||
struct tty_struct *tty = tty_port_tty_get(&line->port);
|
||||
if (tty != NULL) {
|
||||
tty_hangup(tty);
|
||||
tty_kref_put(tty);
|
||||
}
|
||||
tty_port_tty_hangup(&line->port, false);
|
||||
if (line->chan_out != chan)
|
||||
close_one_chan(line->chan_out, 1);
|
||||
}
|
||||
|
@ -248,7 +248,6 @@ static irqreturn_t line_write_interrupt(int irq, void *data)
|
||||
{
|
||||
struct chan *chan = data;
|
||||
struct line *line = chan->line;
|
||||
struct tty_struct *tty;
|
||||
int err;
|
||||
|
||||
/*
|
||||
@ -267,12 +266,7 @@ static irqreturn_t line_write_interrupt(int irq, void *data)
|
||||
}
|
||||
spin_unlock(&line->lock);
|
||||
|
||||
tty = tty_port_tty_get(&line->port);
|
||||
if (tty == NULL)
|
||||
return IRQ_NONE;
|
||||
|
||||
tty_wakeup(tty);
|
||||
tty_kref_put(tty);
|
||||
tty_port_tty_wakeup(&line->port);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
@ -569,7 +569,6 @@ static void capi_recv_message(struct capi20_appl *ap, struct sk_buff *skb)
|
||||
{
|
||||
struct capidev *cdev = ap->private;
|
||||
#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
|
||||
struct tty_struct *tty;
|
||||
struct capiminor *mp;
|
||||
u16 datahandle;
|
||||
struct capincci *np;
|
||||
@ -627,11 +626,7 @@ static void capi_recv_message(struct capi20_appl *ap, struct sk_buff *skb)
|
||||
CAPIMSG_U16(skb->data, CAPIMSG_BASELEN + 4 + 2));
|
||||
kfree_skb(skb);
|
||||
capiminor_del_ack(mp, datahandle);
|
||||
tty = tty_port_tty_get(&mp->port);
|
||||
if (tty) {
|
||||
tty_wakeup(tty);
|
||||
tty_kref_put(tty);
|
||||
}
|
||||
tty_port_tty_wakeup(&mp->port);
|
||||
handle_minor_send(mp);
|
||||
|
||||
} else {
|
||||
|
@ -487,12 +487,8 @@ static const struct tty_operations if_ops = {
|
||||
static void if_wake(unsigned long data)
|
||||
{
|
||||
struct cardstate *cs = (struct cardstate *)data;
|
||||
struct tty_struct *tty = tty_port_tty_get(&cs->port);
|
||||
|
||||
if (tty) {
|
||||
tty_wakeup(tty);
|
||||
tty_kref_put(tty);
|
||||
}
|
||||
tty_port_tty_wakeup(&cs->port);
|
||||
}
|
||||
|
||||
/*** interface to common ***/
|
||||
|
@ -1472,9 +1472,6 @@ isdn_tty_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
|
||||
tty->termios.c_ospeed == old_termios->c_ospeed)
|
||||
return;
|
||||
isdn_tty_change_speed(info);
|
||||
if ((old_termios->c_cflag & CRTSCTS) &&
|
||||
!(tty->termios.c_cflag & CRTSCTS))
|
||||
tty->hw_stopped = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -134,7 +134,6 @@ static void sdio_uart_port_put(struct sdio_uart_port *port)
|
||||
static void sdio_uart_port_remove(struct sdio_uart_port *port)
|
||||
{
|
||||
struct sdio_func *func;
|
||||
struct tty_struct *tty;
|
||||
|
||||
BUG_ON(sdio_uart_table[port->index] != port);
|
||||
|
||||
@ -155,12 +154,8 @@ static void sdio_uart_port_remove(struct sdio_uart_port *port)
|
||||
sdio_claim_host(func);
|
||||
port->func = NULL;
|
||||
mutex_unlock(&port->func_lock);
|
||||
tty = tty_port_tty_get(&port->port);
|
||||
/* tty_hangup is async so is this safe as is ?? */
|
||||
if (tty) {
|
||||
tty_hangup(tty);
|
||||
tty_kref_put(tty);
|
||||
}
|
||||
tty_port_tty_hangup(&port->port, false);
|
||||
mutex_unlock(&port->port.mutex);
|
||||
sdio_release_irq(func);
|
||||
sdio_disable_func(func);
|
||||
@ -492,11 +487,7 @@ static void sdio_uart_check_modem_status(struct sdio_uart_port *port)
|
||||
wake_up_interruptible(&port->port.open_wait);
|
||||
else {
|
||||
/* DCD drop - hang up if tty attached */
|
||||
tty = tty_port_tty_get(&port->port);
|
||||
if (tty) {
|
||||
tty_hangup(tty);
|
||||
tty_kref_put(tty);
|
||||
}
|
||||
tty_port_tty_hangup(&port->port, false);
|
||||
}
|
||||
}
|
||||
if (status & UART_MSR_DCTS) {
|
||||
|
@ -88,11 +88,9 @@ static inline void update_tty_status(struct ser_device *ser)
|
||||
{
|
||||
ser->tty_status =
|
||||
ser->tty->stopped << 5 |
|
||||
ser->tty->hw_stopped << 4 |
|
||||
ser->tty->flow_stopped << 3 |
|
||||
ser->tty->packet << 2 |
|
||||
ser->tty->port->low_latency << 1 |
|
||||
ser->tty->warned;
|
||||
ser->tty->port->low_latency << 1;
|
||||
}
|
||||
static inline void debugfs_init(struct ser_device *ser, struct tty_struct *tty)
|
||||
{
|
||||
|
@ -314,7 +314,7 @@ ppp_asynctty_ioctl(struct tty_struct *tty, struct file *file,
|
||||
/* flush our buffers and the serial port's buffer */
|
||||
if (arg == TCIOFLUSH || arg == TCOFLUSH)
|
||||
ppp_async_flush_output(ap);
|
||||
err = tty_perform_flush(tty, arg);
|
||||
err = n_tty_ioctl_helper(tty, file, cmd, arg);
|
||||
break;
|
||||
|
||||
case FIONREAD:
|
||||
|
@ -355,7 +355,7 @@ ppp_synctty_ioctl(struct tty_struct *tty, struct file *file,
|
||||
/* flush our buffers and the serial port's buffer */
|
||||
if (arg == TCIOFLUSH || arg == TCOFLUSH)
|
||||
ppp_sync_flush_output(ap);
|
||||
err = tty_perform_flush(tty, arg);
|
||||
err = n_tty_ioctl_helper(tty, file, cmd, arg);
|
||||
break;
|
||||
|
||||
case FIONREAD:
|
||||
|
@ -1925,7 +1925,6 @@ static void hso_std_serial_write_bulk_callback(struct urb *urb)
|
||||
{
|
||||
struct hso_serial *serial = urb->context;
|
||||
int status = urb->status;
|
||||
struct tty_struct *tty;
|
||||
|
||||
/* sanity check */
|
||||
if (!serial) {
|
||||
@ -1941,11 +1940,7 @@ static void hso_std_serial_write_bulk_callback(struct urb *urb)
|
||||
return;
|
||||
}
|
||||
hso_put_activity(serial->parent);
|
||||
tty = tty_port_tty_get(&serial->port);
|
||||
if (tty) {
|
||||
tty_wakeup(tty);
|
||||
tty_kref_put(tty);
|
||||
}
|
||||
tty_port_tty_wakeup(&serial->port);
|
||||
hso_kick_transmit(serial);
|
||||
|
||||
D1(" ");
|
||||
@ -2008,12 +2003,8 @@ static void ctrl_callback(struct urb *urb)
|
||||
put_rxbuf_data_and_resubmit_ctrl_urb(serial);
|
||||
spin_unlock(&serial->serial_lock);
|
||||
} else {
|
||||
struct tty_struct *tty = tty_port_tty_get(&serial->port);
|
||||
hso_put_activity(serial->parent);
|
||||
if (tty) {
|
||||
tty_wakeup(tty);
|
||||
tty_kref_put(tty);
|
||||
}
|
||||
tty_port_tty_wakeup(&serial->port);
|
||||
/* response to a write command */
|
||||
hso_kick_transmit(serial);
|
||||
}
|
||||
@ -3133,18 +3124,13 @@ static void hso_serial_ref_free(struct kref *ref)
|
||||
static void hso_free_interface(struct usb_interface *interface)
|
||||
{
|
||||
struct hso_serial *hso_dev;
|
||||
struct tty_struct *tty;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < HSO_SERIAL_TTY_MINORS; i++) {
|
||||
if (serial_table[i] &&
|
||||
(serial_table[i]->interface == interface)) {
|
||||
hso_dev = dev2ser(serial_table[i]);
|
||||
tty = tty_port_tty_get(&hso_dev->port);
|
||||
if (tty) {
|
||||
tty_hangup(tty);
|
||||
tty_kref_put(tty);
|
||||
}
|
||||
tty_port_tty_hangup(&hso_dev->port, false);
|
||||
mutex_lock(&hso_dev->parent->mutex);
|
||||
hso_dev->parent->usb_gone = 1;
|
||||
mutex_unlock(&hso_dev->parent->mutex);
|
||||
|
@ -107,7 +107,6 @@ sclp_tty_write_room (struct tty_struct *tty)
|
||||
static void
|
||||
sclp_ttybuf_callback(struct sclp_buffer *buffer, int rc)
|
||||
{
|
||||
struct tty_struct *tty;
|
||||
unsigned long flags;
|
||||
void *page;
|
||||
|
||||
@ -125,12 +124,8 @@ sclp_ttybuf_callback(struct sclp_buffer *buffer, int rc)
|
||||
struct sclp_buffer, list);
|
||||
spin_unlock_irqrestore(&sclp_tty_lock, flags);
|
||||
} while (buffer && sclp_emit_buffer(buffer, sclp_ttybuf_callback));
|
||||
/* check if the tty needs a wake up call */
|
||||
tty = tty_port_tty_get(&sclp_port);
|
||||
if (tty != NULL) {
|
||||
tty_wakeup(tty);
|
||||
tty_kref_put(tty);
|
||||
}
|
||||
|
||||
tty_port_tty_wakeup(&sclp_port);
|
||||
}
|
||||
|
||||
static inline void
|
||||
|
@ -114,7 +114,6 @@ static struct sclp_register sclp_vt220_register = {
|
||||
static void
|
||||
sclp_vt220_process_queue(struct sclp_vt220_request *request)
|
||||
{
|
||||
struct tty_struct *tty;
|
||||
unsigned long flags;
|
||||
void *page;
|
||||
|
||||
@ -139,12 +138,7 @@ sclp_vt220_process_queue(struct sclp_vt220_request *request)
|
||||
} while (__sclp_vt220_emit(request));
|
||||
if (request == NULL && sclp_vt220_flush_later)
|
||||
sclp_vt220_emit_current();
|
||||
/* Check if the tty needs a wake up call */
|
||||
tty = tty_port_tty_get(&sclp_vt220_port);
|
||||
if (tty) {
|
||||
tty_wakeup(tty);
|
||||
tty_kref_put(tty);
|
||||
}
|
||||
tty_port_tty_wakeup(&sclp_vt220_port);
|
||||
}
|
||||
|
||||
#define SCLP_BUFFER_MAX_RETRY 1
|
||||
|
@ -744,7 +744,6 @@ static void fwtty_tx_complete(struct fw_card *card, int rcode,
|
||||
struct fwtty_transaction *txn)
|
||||
{
|
||||
struct fwtty_port *port = txn->port;
|
||||
struct tty_struct *tty;
|
||||
int len;
|
||||
|
||||
fwtty_dbg(port, "rcode: %d", rcode);
|
||||
@ -769,13 +768,8 @@ static void fwtty_tx_complete(struct fw_card *card, int rcode,
|
||||
port->stats.dropped += txn->dma_pended.len;
|
||||
}
|
||||
|
||||
if (len < WAKEUP_CHARS) {
|
||||
tty = tty_port_tty_get(&port->port);
|
||||
if (tty) {
|
||||
tty_wakeup(tty);
|
||||
tty_kref_put(tty);
|
||||
}
|
||||
}
|
||||
if (len < WAKEUP_CHARS)
|
||||
tty_port_tty_wakeup(&port->port);
|
||||
}
|
||||
|
||||
static int fwtty_tx(struct fwtty_port *port, bool drain)
|
||||
|
@ -264,7 +264,6 @@ static void ProcessRxChar(struct usb_serial_port *port, unsigned char data)
|
||||
|
||||
static void qt_write_bulk_callback(struct urb *urb)
|
||||
{
|
||||
struct tty_struct *tty;
|
||||
int status;
|
||||
struct quatech_port *quatech_port;
|
||||
|
||||
@ -278,11 +277,7 @@ static void qt_write_bulk_callback(struct urb *urb)
|
||||
|
||||
quatech_port = urb->context;
|
||||
|
||||
tty = tty_port_tty_get(&quatech_port->port->port);
|
||||
|
||||
if (tty)
|
||||
tty_wakeup(tty);
|
||||
tty_kref_put(tty);
|
||||
tty_port_tty_wakeup(&quatech_port->port->port);
|
||||
}
|
||||
|
||||
static void qt_interrupt_callback(struct urb *urb)
|
||||
|
@ -1798,19 +1798,7 @@ static struct platform_driver amiga_serial_driver = {
|
||||
},
|
||||
};
|
||||
|
||||
static int __init amiga_serial_init(void)
|
||||
{
|
||||
return platform_driver_probe(&amiga_serial_driver, amiga_serial_probe);
|
||||
}
|
||||
|
||||
module_init(amiga_serial_init);
|
||||
|
||||
static void __exit amiga_serial_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&amiga_serial_driver);
|
||||
}
|
||||
|
||||
module_exit(amiga_serial_exit);
|
||||
module_platform_driver_probe(amiga_serial_driver, amiga_serial_probe);
|
||||
|
||||
|
||||
#if defined(CONFIG_SERIAL_CONSOLE) && !defined(MODULE)
|
||||
|
@ -1124,14 +1124,8 @@ static void cyz_handle_cmd(struct cyclades_card *cinfo)
|
||||
readl(&info->u.cyz.ch_ctrl->rs_status);
|
||||
if (dcd & C_RS_DCD)
|
||||
wake_up_interruptible(&info->port.open_wait);
|
||||
else {
|
||||
struct tty_struct *tty;
|
||||
tty = tty_port_tty_get(&info->port);
|
||||
if (tty) {
|
||||
tty_hangup(tty);
|
||||
tty_kref_put(tty);
|
||||
}
|
||||
}
|
||||
else
|
||||
tty_port_tty_hangup(&info->port, false);
|
||||
}
|
||||
break;
|
||||
case C_CM_MCTS:
|
||||
|
@ -472,13 +472,9 @@ static void ehv_bc_tx_dequeue(struct ehv_bc_data *bc)
|
||||
static irqreturn_t ehv_bc_tty_tx_isr(int irq, void *data)
|
||||
{
|
||||
struct ehv_bc_data *bc = data;
|
||||
struct tty_struct *ttys = tty_port_tty_get(&bc->port);
|
||||
|
||||
ehv_bc_tx_dequeue(bc);
|
||||
if (ttys) {
|
||||
tty_wakeup(ttys);
|
||||
tty_kref_put(ttys);
|
||||
}
|
||||
tty_port_tty_wakeup(&bc->port);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
@ -861,7 +861,6 @@ static void hvsi_write_worker(struct work_struct *work)
|
||||
{
|
||||
struct hvsi_struct *hp =
|
||||
container_of(work, struct hvsi_struct, writer.work);
|
||||
struct tty_struct *tty;
|
||||
unsigned long flags;
|
||||
#ifdef DEBUG
|
||||
static long start_j = 0;
|
||||
@ -895,11 +894,7 @@ static void hvsi_write_worker(struct work_struct *work)
|
||||
start_j = 0;
|
||||
#endif /* DEBUG */
|
||||
wake_up_all(&hp->emptyq);
|
||||
tty = tty_port_tty_get(&hp->port);
|
||||
if (tty) {
|
||||
tty_wakeup(tty);
|
||||
tty_kref_put(tty);
|
||||
}
|
||||
tty_port_tty_wakeup(&hp->port);
|
||||
}
|
||||
|
||||
out:
|
||||
|
@ -1732,8 +1732,7 @@ void ipwireless_hardware_free(struct ipw_hardware *hw)
|
||||
flush_work(&hw->work_rx);
|
||||
|
||||
for (i = 0; i < NL_NUM_OF_ADDRESSES; i++)
|
||||
if (hw->packet_assembler[i] != NULL)
|
||||
kfree(hw->packet_assembler[i]);
|
||||
kfree(hw->packet_assembler[i]);
|
||||
|
||||
for (i = 0; i < NL_NUM_OF_PRIORITIES; i++)
|
||||
list_for_each_entry_safe(tp, tq, &hw->tx_queue[i], queue) {
|
||||
|
@ -913,16 +913,12 @@ static void moxa_board_deinit(struct moxa_board_conf *brd)
|
||||
|
||||
/* pci hot-un-plug support */
|
||||
for (a = 0; a < brd->numPorts; a++)
|
||||
if (brd->ports[a].port.flags & ASYNC_INITIALIZED) {
|
||||
struct tty_struct *tty = tty_port_tty_get(
|
||||
&brd->ports[a].port);
|
||||
if (tty) {
|
||||
tty_hangup(tty);
|
||||
tty_kref_put(tty);
|
||||
}
|
||||
}
|
||||
if (brd->ports[a].port.flags & ASYNC_INITIALIZED)
|
||||
tty_port_tty_hangup(&brd->ports[a].port, false);
|
||||
|
||||
for (a = 0; a < MAX_PORTS_PER_BOARD; a++)
|
||||
tty_port_destroy(&brd->ports[a].port);
|
||||
|
||||
while (1) {
|
||||
opened = 0;
|
||||
for (a = 0; a < brd->numPorts; a++)
|
||||
@ -1365,7 +1361,6 @@ static void moxa_hangup(struct tty_struct *tty)
|
||||
|
||||
static void moxa_new_dcdstate(struct moxa_port *p, u8 dcd)
|
||||
{
|
||||
struct tty_struct *tty;
|
||||
unsigned long flags;
|
||||
dcd = !!dcd;
|
||||
|
||||
@ -1373,10 +1368,8 @@ static void moxa_new_dcdstate(struct moxa_port *p, u8 dcd)
|
||||
if (dcd != p->DCDState) {
|
||||
p->DCDState = dcd;
|
||||
spin_unlock_irqrestore(&p->port.lock, flags);
|
||||
tty = tty_port_tty_get(&p->port);
|
||||
if (tty && !C_CLOCAL(tty) && !dcd)
|
||||
tty_hangup(tty);
|
||||
tty_kref_put(tty);
|
||||
if (!dcd)
|
||||
tty_port_tty_hangup(&p->port, true);
|
||||
}
|
||||
else
|
||||
spin_unlock_irqrestore(&p->port.lock, flags);
|
||||
|
@ -1084,6 +1084,10 @@ static void mxser_close(struct tty_struct *tty, struct file *filp)
|
||||
mutex_lock(&port->mutex);
|
||||
mxser_close_port(port);
|
||||
mxser_flush_buffer(tty);
|
||||
if (test_bit(ASYNCB_INITIALIZED, &port->flags)) {
|
||||
if (C_HUPCL(tty))
|
||||
tty_port_lower_dtr_rts(port);
|
||||
}
|
||||
mxser_shutdown_port(port);
|
||||
clear_bit(ASYNCB_INITIALIZED, &port->flags);
|
||||
mutex_unlock(&port->mutex);
|
||||
|
@ -1418,11 +1418,7 @@ static void gsm_dlci_close(struct gsm_dlci *dlci)
|
||||
pr_debug("DLCI %d goes closed.\n", dlci->addr);
|
||||
dlci->state = DLCI_CLOSED;
|
||||
if (dlci->addr != 0) {
|
||||
struct tty_struct *tty = tty_port_tty_get(&dlci->port);
|
||||
if (tty) {
|
||||
tty_hangup(tty);
|
||||
tty_kref_put(tty);
|
||||
}
|
||||
tty_port_tty_hangup(&dlci->port, false);
|
||||
kfifo_reset(dlci->fifo);
|
||||
} else
|
||||
dlci->gsm->dead = 1;
|
||||
@ -2968,6 +2964,10 @@ static void gsmtty_close(struct tty_struct *tty, struct file *filp)
|
||||
if (tty_port_close_start(&dlci->port, tty, filp) == 0)
|
||||
goto out;
|
||||
gsm_dlci_begin_close(dlci);
|
||||
if (test_bit(ASYNCB_INITIALIZED, &dlci->port.flags)) {
|
||||
if (C_HUPCL(tty))
|
||||
tty_port_lower_dtr_rts(&dlci->port);
|
||||
}
|
||||
tty_port_close_end(&dlci->port, tty);
|
||||
tty_port_tty_set(&dlci->port, NULL);
|
||||
out:
|
||||
|
@ -153,6 +153,12 @@ static void n_tty_set_room(struct tty_struct *tty)
|
||||
if (left && !old_left) {
|
||||
WARN_RATELIMIT(tty->port->itty == NULL,
|
||||
"scheduling with invalid itty\n");
|
||||
/* see if ldisc has been killed - if so, this means that
|
||||
* even though the ldisc has been halted and ->buf.work
|
||||
* cancelled, ->buf.work is about to be rescheduled
|
||||
*/
|
||||
WARN_RATELIMIT(test_bit(TTY_LDISC_HALTED, &tty->flags),
|
||||
"scheduling buffer work for halted ldisc\n");
|
||||
schedule_work(&tty->port->buf.work);
|
||||
}
|
||||
}
|
||||
@ -188,35 +194,18 @@ static void put_tty_queue(unsigned char c, struct n_tty_data *ldata)
|
||||
raw_spin_unlock_irqrestore(&ldata->read_lock, flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* check_unthrottle - allow new receive data
|
||||
* @tty; tty device
|
||||
*
|
||||
* Check whether to call the driver unthrottle functions
|
||||
*
|
||||
* Can sleep, may be called under the atomic_read_lock mutex but
|
||||
* this is not guaranteed.
|
||||
*/
|
||||
static void check_unthrottle(struct tty_struct *tty)
|
||||
{
|
||||
if (tty->count)
|
||||
tty_unthrottle(tty);
|
||||
}
|
||||
|
||||
/**
|
||||
* reset_buffer_flags - reset buffer state
|
||||
* @tty: terminal to reset
|
||||
*
|
||||
* Reset the read buffer counters, clear the flags,
|
||||
* and make sure the driver is unthrottled. Called
|
||||
* from n_tty_open() and n_tty_flush_buffer().
|
||||
* Reset the read buffer counters and clear the flags.
|
||||
* Called from n_tty_open() and n_tty_flush_buffer().
|
||||
*
|
||||
* Locking: tty_read_lock for read fields.
|
||||
*/
|
||||
|
||||
static void reset_buffer_flags(struct tty_struct *tty)
|
||||
static void reset_buffer_flags(struct n_tty_data *ldata)
|
||||
{
|
||||
struct n_tty_data *ldata = tty->disc_data;
|
||||
unsigned long flags;
|
||||
|
||||
raw_spin_lock_irqsave(&ldata->read_lock, flags);
|
||||
@ -229,29 +218,11 @@ static void reset_buffer_flags(struct tty_struct *tty)
|
||||
|
||||
ldata->canon_head = ldata->canon_data = ldata->erasing = 0;
|
||||
bitmap_zero(ldata->read_flags, N_TTY_BUF_SIZE);
|
||||
n_tty_set_room(tty);
|
||||
}
|
||||
|
||||
/**
|
||||
* n_tty_flush_buffer - clean input queue
|
||||
* @tty: terminal device
|
||||
*
|
||||
* Flush the input buffer. Called when the line discipline is
|
||||
* being closed, when the tty layer wants the buffer flushed (eg
|
||||
* at hangup) or when the N_TTY line discipline internally has to
|
||||
* clean the pending queue (for example some signals).
|
||||
*
|
||||
* Locking: ctrl_lock, read_lock.
|
||||
*/
|
||||
|
||||
static void n_tty_flush_buffer(struct tty_struct *tty)
|
||||
static void n_tty_packet_mode_flush(struct tty_struct *tty)
|
||||
{
|
||||
unsigned long flags;
|
||||
/* clear everything and unthrottle the driver */
|
||||
reset_buffer_flags(tty);
|
||||
|
||||
if (!tty->link)
|
||||
return;
|
||||
|
||||
spin_lock_irqsave(&tty->ctrl_lock, flags);
|
||||
if (tty->link->packet) {
|
||||
@ -261,6 +232,26 @@ static void n_tty_flush_buffer(struct tty_struct *tty)
|
||||
spin_unlock_irqrestore(&tty->ctrl_lock, flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* n_tty_flush_buffer - clean input queue
|
||||
* @tty: terminal device
|
||||
*
|
||||
* Flush the input buffer. Called when the tty layer wants the
|
||||
* buffer flushed (eg at hangup) or when the N_TTY line discipline
|
||||
* internally has to clean the pending queue (for example some signals).
|
||||
*
|
||||
* Locking: ctrl_lock, read_lock.
|
||||
*/
|
||||
|
||||
static void n_tty_flush_buffer(struct tty_struct *tty)
|
||||
{
|
||||
reset_buffer_flags(tty->disc_data);
|
||||
n_tty_set_room(tty);
|
||||
|
||||
if (tty->link)
|
||||
n_tty_packet_mode_flush(tty);
|
||||
}
|
||||
|
||||
/**
|
||||
* n_tty_chars_in_buffer - report available bytes
|
||||
* @tty: tty device
|
||||
@ -1032,23 +1023,19 @@ static void eraser(unsigned char c, struct tty_struct *tty)
|
||||
* isig - handle the ISIG optio
|
||||
* @sig: signal
|
||||
* @tty: terminal
|
||||
* @flush: force flush
|
||||
*
|
||||
* Called when a signal is being sent due to terminal input. This
|
||||
* may caus terminal flushing to take place according to the termios
|
||||
* settings and character used. Called from the driver receive_buf
|
||||
* path so serialized.
|
||||
* Called when a signal is being sent due to terminal input.
|
||||
* Called from the driver receive_buf path so serialized.
|
||||
*
|
||||
* Locking: ctrl_lock, read_lock (both via flush buffer)
|
||||
* Locking: ctrl_lock
|
||||
*/
|
||||
|
||||
static inline void isig(int sig, struct tty_struct *tty, int flush)
|
||||
static inline void isig(int sig, struct tty_struct *tty)
|
||||
{
|
||||
if (tty->pgrp)
|
||||
kill_pgrp(tty->pgrp, sig, 1);
|
||||
if (flush || !L_NOFLSH(tty)) {
|
||||
n_tty_flush_buffer(tty);
|
||||
tty_driver_flush_buffer(tty);
|
||||
struct pid *tty_pgrp = tty_get_pgrp(tty);
|
||||
if (tty_pgrp) {
|
||||
kill_pgrp(tty_pgrp, sig, 1);
|
||||
put_pid(tty_pgrp);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1069,7 +1056,11 @@ static inline void n_tty_receive_break(struct tty_struct *tty)
|
||||
if (I_IGNBRK(tty))
|
||||
return;
|
||||
if (I_BRKINT(tty)) {
|
||||
isig(SIGINT, tty, 1);
|
||||
isig(SIGINT, tty);
|
||||
if (!L_NOFLSH(tty)) {
|
||||
n_tty_flush_buffer(tty);
|
||||
tty_driver_flush_buffer(tty);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (I_PARMRK(tty)) {
|
||||
@ -1236,11 +1227,6 @@ static inline void n_tty_receive_char(struct tty_struct *tty, unsigned char c)
|
||||
signal = SIGTSTP;
|
||||
if (c == SUSP_CHAR(tty)) {
|
||||
send_signal:
|
||||
/*
|
||||
* Note that we do not use isig() here because we want
|
||||
* the order to be:
|
||||
* 1) flush, 2) echo, 3) signal
|
||||
*/
|
||||
if (!L_NOFLSH(tty)) {
|
||||
n_tty_flush_buffer(tty);
|
||||
tty_driver_flush_buffer(tty);
|
||||
@ -1251,8 +1237,7 @@ send_signal:
|
||||
echo_char(c, tty);
|
||||
process_echoes(tty);
|
||||
}
|
||||
if (tty->pgrp)
|
||||
kill_pgrp(tty->pgrp, signal, 1);
|
||||
isig(signal, tty);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -1483,14 +1468,14 @@ static void n_tty_receive_buf(struct tty_struct *tty, const unsigned char *cp,
|
||||
* mode. We don't want to throttle the driver if we're in
|
||||
* canonical mode and don't have a newline yet!
|
||||
*/
|
||||
if (tty->receive_room < TTY_THRESHOLD_THROTTLE)
|
||||
tty_throttle(tty);
|
||||
|
||||
/* FIXME: there is a tiny race here if the receive room check runs
|
||||
before the other work executes and empties the buffer (upping
|
||||
the receiving room and unthrottling. We then throttle and get
|
||||
stuck. This has been observed and traced down by Vincent Pillet/
|
||||
We need to address this when we sort out out the rx path locking */
|
||||
while (1) {
|
||||
tty_set_flow_change(tty, TTY_THROTTLE_SAFE);
|
||||
if (tty->receive_room >= TTY_THRESHOLD_THROTTLE)
|
||||
break;
|
||||
if (!tty_throttle_safe(tty))
|
||||
break;
|
||||
}
|
||||
__tty_set_flow_change(tty, 0);
|
||||
}
|
||||
|
||||
int is_ignored(int sig)
|
||||
@ -1607,7 +1592,9 @@ static void n_tty_close(struct tty_struct *tty)
|
||||
{
|
||||
struct n_tty_data *ldata = tty->disc_data;
|
||||
|
||||
n_tty_flush_buffer(tty);
|
||||
if (tty->link)
|
||||
n_tty_packet_mode_flush(tty);
|
||||
|
||||
kfree(ldata->read_buf);
|
||||
kfree(ldata->echo_buf);
|
||||
kfree(ldata);
|
||||
@ -1645,12 +1632,14 @@ static int n_tty_open(struct tty_struct *tty)
|
||||
goto err_free_bufs;
|
||||
|
||||
tty->disc_data = ldata;
|
||||
reset_buffer_flags(tty);
|
||||
tty_unthrottle(tty);
|
||||
reset_buffer_flags(tty->disc_data);
|
||||
ldata->column = 0;
|
||||
n_tty_set_termios(tty, NULL);
|
||||
tty->minimum_to_wake = 1;
|
||||
tty->closing = 0;
|
||||
/* indicate buffer work may resume */
|
||||
clear_bit(TTY_LDISC_HALTED, &tty->flags);
|
||||
n_tty_set_termios(tty, NULL);
|
||||
tty_unthrottle(tty);
|
||||
|
||||
return 0;
|
||||
err_free_bufs:
|
||||
@ -1740,10 +1729,9 @@ extern ssize_t redirected_tty_write(struct file *, const char __user *,
|
||||
* and if appropriate send any needed signals and return a negative
|
||||
* error code if action should be taken.
|
||||
*
|
||||
* FIXME:
|
||||
* Locking: None - redirected write test is safe, testing
|
||||
* current->signal should possibly lock current->sighand
|
||||
* pgrp locking ?
|
||||
* Locking: redirected write test is safe
|
||||
* current->signal->tty check is safe
|
||||
* ctrl_lock to safely reference tty->pgrp
|
||||
*/
|
||||
|
||||
static int job_control(struct tty_struct *tty, struct file *file)
|
||||
@ -1753,19 +1741,22 @@ static int job_control(struct tty_struct *tty, struct file *file)
|
||||
/* NOTE: not yet done after every sleep pending a thorough
|
||||
check of the logic of this change. -- jlc */
|
||||
/* don't stop on /dev/console */
|
||||
if (file->f_op->write != redirected_tty_write &&
|
||||
current->signal->tty == tty) {
|
||||
if (!tty->pgrp)
|
||||
printk(KERN_ERR "n_tty_read: no tty->pgrp!\n");
|
||||
else if (task_pgrp(current) != tty->pgrp) {
|
||||
if (is_ignored(SIGTTIN) ||
|
||||
is_current_pgrp_orphaned())
|
||||
return -EIO;
|
||||
kill_pgrp(task_pgrp(current), SIGTTIN, 1);
|
||||
set_thread_flag(TIF_SIGPENDING);
|
||||
return -ERESTARTSYS;
|
||||
}
|
||||
if (file->f_op->write == redirected_tty_write ||
|
||||
current->signal->tty != tty)
|
||||
return 0;
|
||||
|
||||
spin_lock_irq(&tty->ctrl_lock);
|
||||
if (!tty->pgrp)
|
||||
printk(KERN_ERR "n_tty_read: no tty->pgrp!\n");
|
||||
else if (task_pgrp(current) != tty->pgrp) {
|
||||
spin_unlock_irq(&tty->ctrl_lock);
|
||||
if (is_ignored(SIGTTIN) || is_current_pgrp_orphaned())
|
||||
return -EIO;
|
||||
kill_pgrp(task_pgrp(current), SIGTTIN, 1);
|
||||
set_thread_flag(TIF_SIGPENDING);
|
||||
return -ERESTARTSYS;
|
||||
}
|
||||
spin_unlock_irq(&tty->ctrl_lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1959,10 +1950,17 @@ do_it_again:
|
||||
* longer than TTY_THRESHOLD_UNTHROTTLE in canonical mode,
|
||||
* we won't get any more characters.
|
||||
*/
|
||||
if (n_tty_chars_in_buffer(tty) <= TTY_THRESHOLD_UNTHROTTLE) {
|
||||
while (1) {
|
||||
tty_set_flow_change(tty, TTY_UNTHROTTLE_SAFE);
|
||||
if (n_tty_chars_in_buffer(tty) > TTY_THRESHOLD_UNTHROTTLE)
|
||||
break;
|
||||
if (!tty->count)
|
||||
break;
|
||||
n_tty_set_room(tty);
|
||||
check_unthrottle(tty);
|
||||
if (!tty_unthrottle_safe(tty))
|
||||
break;
|
||||
}
|
||||
__tty_set_flow_change(tty, 0);
|
||||
|
||||
if (b - buf >= minimum)
|
||||
break;
|
||||
|
@ -791,7 +791,6 @@ static int send_data(enum port_type index, struct nozomi *dc)
|
||||
const u8 toggle = port->toggle_ul;
|
||||
void __iomem *addr = port->ul_addr[toggle];
|
||||
const u32 ul_size = port->ul_size[toggle];
|
||||
struct tty_struct *tty = tty_port_tty_get(&port->port);
|
||||
|
||||
/* Get data from tty and place in buf for now */
|
||||
size = kfifo_out(&port->fifo_ul, dc->send_buf,
|
||||
@ -799,7 +798,6 @@ static int send_data(enum port_type index, struct nozomi *dc)
|
||||
|
||||
if (size == 0) {
|
||||
DBG4("No more data to send, disable link:");
|
||||
tty_kref_put(tty);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -809,10 +807,8 @@ static int send_data(enum port_type index, struct nozomi *dc)
|
||||
write_mem32(addr, (u32 *) &size, 4);
|
||||
write_mem32(addr + 4, (u32 *) dc->send_buf, size);
|
||||
|
||||
if (tty)
|
||||
tty_wakeup(tty);
|
||||
tty_port_tty_wakeup(&port->port);
|
||||
|
||||
tty_kref_put(tty);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -1505,12 +1501,9 @@ static void tty_exit(struct nozomi *dc)
|
||||
|
||||
DBG1(" ");
|
||||
|
||||
for (i = 0; i < MAX_PORT; ++i) {
|
||||
struct tty_struct *tty = tty_port_tty_get(&dc->port[i].port);
|
||||
if (tty && list_empty(&tty->hangup_work.entry))
|
||||
tty_hangup(tty);
|
||||
tty_kref_put(tty);
|
||||
}
|
||||
for (i = 0; i < MAX_PORT; ++i)
|
||||
tty_port_tty_hangup(&dc->port[i].port, false);
|
||||
|
||||
/* Racy below - surely should wait for scheduled work to be done or
|
||||
complete off a hangup method ? */
|
||||
while (dc->open_ttys)
|
||||
|
@ -405,15 +405,8 @@ err:
|
||||
return retval;
|
||||
}
|
||||
|
||||
/* this is called once with whichever end is closed last */
|
||||
static void pty_unix98_shutdown(struct tty_struct *tty)
|
||||
{
|
||||
devpts_kill_index(tty->driver_data, tty->index);
|
||||
}
|
||||
|
||||
static void pty_cleanup(struct tty_struct *tty)
|
||||
{
|
||||
tty->port->itty = NULL;
|
||||
tty_port_put(tty->port);
|
||||
}
|
||||
|
||||
@ -627,6 +620,12 @@ static void pty_unix98_remove(struct tty_driver *driver, struct tty_struct *tty)
|
||||
{
|
||||
}
|
||||
|
||||
/* this is called once with whichever end is closed last */
|
||||
static void pty_unix98_shutdown(struct tty_struct *tty)
|
||||
{
|
||||
devpts_kill_index(tty->driver_data, tty->index);
|
||||
}
|
||||
|
||||
static const struct tty_operations ptm_unix98_ops = {
|
||||
.lookup = ptm_unix98_lookup,
|
||||
.install = pty_unix98_install,
|
||||
|
@ -449,7 +449,7 @@ static void rp_do_transmit(struct r_port *info)
|
||||
|
||||
/* Loop sending data to FIFO until done or FIFO full */
|
||||
while (1) {
|
||||
if (tty->stopped || tty->hw_stopped)
|
||||
if (tty->stopped)
|
||||
break;
|
||||
c = min(info->xmit_fifo_room, info->xmit_cnt);
|
||||
c = min(c, XMIT_BUF_SIZE - info->xmit_tail);
|
||||
@ -521,15 +521,10 @@ static void rp_handle_port(struct r_port *info)
|
||||
(ChanStatus & CD_ACT) ? "on" : "off");
|
||||
#endif
|
||||
if (!(ChanStatus & CD_ACT) && info->cd_status) {
|
||||
struct tty_struct *tty;
|
||||
#ifdef ROCKET_DEBUG_HANGUP
|
||||
printk(KERN_INFO "CD drop, calling hangup.\n");
|
||||
#endif
|
||||
tty = tty_port_tty_get(&info->port);
|
||||
if (tty) {
|
||||
tty_hangup(tty);
|
||||
tty_kref_put(tty);
|
||||
}
|
||||
tty_port_tty_hangup(&info->port, false);
|
||||
}
|
||||
info->cd_status = (ChanStatus & CD_ACT) ? 1 : 0;
|
||||
wake_up_interruptible(&info->port.open_wait);
|
||||
@ -1111,15 +1106,12 @@ static void rp_set_termios(struct tty_struct *tty,
|
||||
|
||||
/* Handle transition away from B0 status */
|
||||
if (!(old_termios->c_cflag & CBAUD) && (tty->termios.c_cflag & CBAUD)) {
|
||||
if (!tty->hw_stopped || !(tty->termios.c_cflag & CRTSCTS))
|
||||
sSetRTS(cp);
|
||||
sSetRTS(cp);
|
||||
sSetDTR(cp);
|
||||
}
|
||||
|
||||
if ((old_termios->c_cflag & CRTSCTS) && !(tty->termios.c_cflag & CRTSCTS)) {
|
||||
tty->hw_stopped = 0;
|
||||
if ((old_termios->c_cflag & CRTSCTS) && !(tty->termios.c_cflag & CRTSCTS))
|
||||
rp_start(tty);
|
||||
}
|
||||
}
|
||||
|
||||
static int rp_break(struct tty_struct *tty, int break_state)
|
||||
@ -1575,10 +1567,10 @@ static int rp_put_char(struct tty_struct *tty, unsigned char ch)
|
||||
spin_lock_irqsave(&info->slock, flags);
|
||||
cp = &info->channel;
|
||||
|
||||
if (!tty->stopped && !tty->hw_stopped && info->xmit_fifo_room == 0)
|
||||
if (!tty->stopped && info->xmit_fifo_room == 0)
|
||||
info->xmit_fifo_room = TXFIFO_SIZE - sGetTxCnt(cp);
|
||||
|
||||
if (tty->stopped || tty->hw_stopped || info->xmit_fifo_room == 0 || info->xmit_cnt != 0) {
|
||||
if (tty->stopped || info->xmit_fifo_room == 0 || info->xmit_cnt != 0) {
|
||||
info->xmit_buf[info->xmit_head++] = ch;
|
||||
info->xmit_head &= XMIT_BUF_SIZE - 1;
|
||||
info->xmit_cnt++;
|
||||
@ -1619,14 +1611,14 @@ static int rp_write(struct tty_struct *tty,
|
||||
#endif
|
||||
cp = &info->channel;
|
||||
|
||||
if (!tty->stopped && !tty->hw_stopped && info->xmit_fifo_room < count)
|
||||
if (!tty->stopped && info->xmit_fifo_room < count)
|
||||
info->xmit_fifo_room = TXFIFO_SIZE - sGetTxCnt(cp);
|
||||
|
||||
/*
|
||||
* If the write queue for the port is empty, and there is FIFO space, stuff bytes
|
||||
* into FIFO. Use the write queue for temp storage.
|
||||
*/
|
||||
if (!tty->stopped && !tty->hw_stopped && info->xmit_cnt == 0 && info->xmit_fifo_room > 0) {
|
||||
if (!tty->stopped && info->xmit_cnt == 0 && info->xmit_fifo_room > 0) {
|
||||
c = min(count, info->xmit_fifo_room);
|
||||
b = buf;
|
||||
|
||||
@ -1674,7 +1666,7 @@ static int rp_write(struct tty_struct *tty,
|
||||
retval += c;
|
||||
}
|
||||
|
||||
if ((retval > 0) && !tty->stopped && !tty->hw_stopped)
|
||||
if ((retval > 0) && !tty->stopped)
|
||||
set_bit((info->aiop * 8) + info->chan, (void *) &xmit_flags[info->board]);
|
||||
|
||||
end:
|
||||
@ -2527,6 +2519,7 @@ static int sInitController(CONTROLLER_T * CtlP, int CtlNum, ByteIO_t MudbacIO,
|
||||
return (CtlP->NumAiop);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PCI
|
||||
/***************************************************************************
|
||||
Function: sPCIInitController
|
||||
Purpose: Initialization of controller global registers and controller
|
||||
@ -2647,6 +2640,26 @@ static int sPCIInitController(CONTROLLER_T * CtlP, int CtlNum,
|
||||
return (CtlP->NumAiop);
|
||||
}
|
||||
|
||||
/* Resets the speaker controller on RocketModem II and III devices */
|
||||
static void rmSpeakerReset(CONTROLLER_T * CtlP, unsigned long model)
|
||||
{
|
||||
ByteIO_t addr;
|
||||
|
||||
/* RocketModem II speaker control is at the 8th port location of offset 0x40 */
|
||||
if ((model == MODEL_RP4M) || (model == MODEL_RP6M)) {
|
||||
addr = CtlP->AiopIO[0] + 0x4F;
|
||||
sOutB(addr, 0);
|
||||
}
|
||||
|
||||
/* RocketModem III speaker control is at the 1st port location of offset 0x80 */
|
||||
if ((model == MODEL_UPCI_RM3_8PORT)
|
||||
|| (model == MODEL_UPCI_RM3_4PORT)) {
|
||||
addr = CtlP->AiopIO[0] + 0x88;
|
||||
sOutB(addr, 0);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/***************************************************************************
|
||||
Function: sReadAiopID
|
||||
Purpose: Read the AIOP idenfication number directly from an AIOP.
|
||||
@ -3136,25 +3149,6 @@ static void sPCIModemReset(CONTROLLER_T * CtlP, int chan, int on)
|
||||
sOutB(addr + chan, 0); /* apply or remove reset */
|
||||
}
|
||||
|
||||
/* Resets the speaker controller on RocketModem II and III devices */
|
||||
static void rmSpeakerReset(CONTROLLER_T * CtlP, unsigned long model)
|
||||
{
|
||||
ByteIO_t addr;
|
||||
|
||||
/* RocketModem II speaker control is at the 8th port location of offset 0x40 */
|
||||
if ((model == MODEL_RP4M) || (model == MODEL_RP6M)) {
|
||||
addr = CtlP->AiopIO[0] + 0x4F;
|
||||
sOutB(addr, 0);
|
||||
}
|
||||
|
||||
/* RocketModem III speaker control is at the 1st port location of offset 0x80 */
|
||||
if ((model == MODEL_UPCI_RM3_8PORT)
|
||||
|| (model == MODEL_UPCI_RM3_4PORT)) {
|
||||
addr = CtlP->AiopIO[0] + 0x88;
|
||||
sOutB(addr, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/* Returns the line number given the controller (board), aiop and channel number */
|
||||
static unsigned char GetLineNumber(int ctrl, int aiop, int ch)
|
||||
{
|
||||
|
@ -630,8 +630,7 @@ static void rs_flush_chars(struct tty_struct *tty)
|
||||
/* Enable transmitter */
|
||||
local_irq_save(flags);
|
||||
|
||||
if (info->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped ||
|
||||
!info->xmit_buf) {
|
||||
if (info->xmit_cnt <= 0 || tty->stopped || !info->xmit_buf) {
|
||||
local_irq_restore(flags);
|
||||
return;
|
||||
}
|
||||
@ -697,7 +696,7 @@ static int rs_write(struct tty_struct * tty,
|
||||
total += c;
|
||||
}
|
||||
|
||||
if (info->xmit_cnt && !tty->stopped && !tty->hw_stopped) {
|
||||
if (info->xmit_cnt && !tty->stopped) {
|
||||
/* Enable transmitter */
|
||||
local_irq_disable();
|
||||
#ifndef USE_INTS
|
||||
@ -978,10 +977,8 @@ static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
|
||||
change_speed(info, tty);
|
||||
|
||||
if ((old_termios->c_cflag & CRTSCTS) &&
|
||||
!(tty->termios.c_cflag & CRTSCTS)) {
|
||||
tty->hw_stopped = 0;
|
||||
!(tty->termios.c_cflag & CRTSCTS))
|
||||
rs_start(tty);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@ -117,13 +117,6 @@ static inline void serial_dl_write(struct uart_8250_port *up, int value)
|
||||
* is cleared, the machine locks up with endless interrupts.
|
||||
*/
|
||||
#define ALPHA_KLUDGE_MCR (UART_MCR_OUT2 | UART_MCR_OUT1)
|
||||
#elif defined(CONFIG_SBC8560)
|
||||
/*
|
||||
* WindRiver did something similarly broken on their SBC8560 board. The
|
||||
* UART tristates its IRQ output while OUT2 is clear, but they pulled
|
||||
* the interrupt line _up_ instead of down, so if we register the IRQ
|
||||
* while the UART is in that state, we die in an IRQ storm. */
|
||||
#define ALPHA_KLUDGE_MCR (UART_MCR_OUT2)
|
||||
#else
|
||||
#define ALPHA_KLUDGE_MCR 0
|
||||
#endif
|
||||
|
@ -2755,7 +2755,7 @@ static void __init serial8250_isa_init_ports(void)
|
||||
if (nr_uarts > UART_NR)
|
||||
nr_uarts = UART_NR;
|
||||
|
||||
for (i = 0; i < nr_uarts; i++) {
|
||||
for (i = 0; i < UART_NR; i++) {
|
||||
struct uart_8250_port *up = &serial8250_ports[i];
|
||||
struct uart_port *port = &up->port;
|
||||
|
||||
@ -2916,7 +2916,7 @@ static int __init serial8250_console_setup(struct console *co, char *options)
|
||||
* if so, search for the first available port that does have
|
||||
* console support.
|
||||
*/
|
||||
if (co->index >= nr_uarts)
|
||||
if (co->index >= UART_NR)
|
||||
co->index = 0;
|
||||
port = &serial8250_ports[co->index].port;
|
||||
if (!port->iobase && !port->membase)
|
||||
@ -2957,7 +2957,7 @@ int serial8250_find_port(struct uart_port *p)
|
||||
int line;
|
||||
struct uart_port *port;
|
||||
|
||||
for (line = 0; line < nr_uarts; line++) {
|
||||
for (line = 0; line < UART_NR; line++) {
|
||||
port = &serial8250_ports[line].port;
|
||||
if (uart_match_port(p, port))
|
||||
return line;
|
||||
@ -3110,7 +3110,7 @@ static int serial8250_remove(struct platform_device *dev)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < nr_uarts; i++) {
|
||||
for (i = 0; i < UART_NR; i++) {
|
||||
struct uart_8250_port *up = &serial8250_ports[i];
|
||||
|
||||
if (up->port.dev == &dev->dev)
|
||||
@ -3178,7 +3178,7 @@ static struct uart_8250_port *serial8250_find_match_or_unused(struct uart_port *
|
||||
/*
|
||||
* First, find a port entry which matches.
|
||||
*/
|
||||
for (i = 0; i < nr_uarts; i++)
|
||||
for (i = 0; i < UART_NR; i++)
|
||||
if (uart_match_port(&serial8250_ports[i].port, port))
|
||||
return &serial8250_ports[i];
|
||||
|
||||
@ -3187,7 +3187,7 @@ static struct uart_8250_port *serial8250_find_match_or_unused(struct uart_port *
|
||||
* free entry. We look for one which hasn't been previously
|
||||
* used (indicated by zero iobase).
|
||||
*/
|
||||
for (i = 0; i < nr_uarts; i++)
|
||||
for (i = 0; i < UART_NR; i++)
|
||||
if (serial8250_ports[i].port.type == PORT_UNKNOWN &&
|
||||
serial8250_ports[i].port.iobase == 0)
|
||||
return &serial8250_ports[i];
|
||||
@ -3196,7 +3196,7 @@ static struct uart_8250_port *serial8250_find_match_or_unused(struct uart_port *
|
||||
* That also failed. Last resort is to find any entry which
|
||||
* doesn't have a real port associated with it.
|
||||
*/
|
||||
for (i = 0; i < nr_uarts; i++)
|
||||
for (i = 0; i < UART_NR; i++)
|
||||
if (serial8250_ports[i].port.type == PORT_UNKNOWN)
|
||||
return &serial8250_ports[i];
|
||||
|
||||
@ -3247,6 +3247,10 @@ int serial8250_register_8250_port(struct uart_8250_port *up)
|
||||
uart->tx_loadsz = up->tx_loadsz;
|
||||
uart->capabilities = up->capabilities;
|
||||
|
||||
/* Take tx_loadsz from fifosize if it wasn't set separately */
|
||||
if (uart->port.fifosize && !uart->tx_loadsz)
|
||||
uart->tx_loadsz = uart->port.fifosize;
|
||||
|
||||
if (up->port.dev)
|
||||
uart->port.dev = up->port.dev;
|
||||
|
||||
|
@ -33,10 +33,8 @@ static void __dma_tx_complete(void *param)
|
||||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
uart_write_wakeup(&p->port);
|
||||
|
||||
if (!uart_circ_empty(xmit) && !uart_tx_stopped(&p->port)) {
|
||||
if (!uart_circ_empty(xmit) && !uart_tx_stopped(&p->port))
|
||||
serial8250_tx_dma(p);
|
||||
uart_write_wakeup(&p->port);
|
||||
}
|
||||
}
|
||||
|
||||
static void __dma_rx_complete(void *param)
|
||||
@ -67,12 +65,11 @@ int serial8250_tx_dma(struct uart_8250_port *p)
|
||||
struct circ_buf *xmit = &p->port.state->xmit;
|
||||
struct dma_async_tx_descriptor *desc;
|
||||
|
||||
if (dma->tx_running)
|
||||
return -EBUSY;
|
||||
if (uart_tx_stopped(&p->port) || dma->tx_running ||
|
||||
uart_circ_empty(xmit))
|
||||
return 0;
|
||||
|
||||
dma->tx_size = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE);
|
||||
if (!dma->tx_size)
|
||||
return -EINVAL;
|
||||
|
||||
desc = dmaengine_prep_slave_single(dma->txchan,
|
||||
dma->tx_addr + xmit->tail,
|
||||
@ -104,20 +101,29 @@ int serial8250_rx_dma(struct uart_8250_port *p, unsigned int iir)
|
||||
struct dma_tx_state state;
|
||||
int dma_status;
|
||||
|
||||
/*
|
||||
* If RCVR FIFO trigger level was not reached, complete the transfer and
|
||||
* let 8250.c copy the remaining data.
|
||||
*/
|
||||
if ((iir & 0x3f) == UART_IIR_RX_TIMEOUT) {
|
||||
dma_status = dmaengine_tx_status(dma->rxchan, dma->rx_cookie,
|
||||
&state);
|
||||
dma_status = dmaengine_tx_status(dma->rxchan, dma->rx_cookie, &state);
|
||||
|
||||
switch (iir & 0x3f) {
|
||||
case UART_IIR_RLSI:
|
||||
/* 8250_core handles errors and break interrupts */
|
||||
return -EIO;
|
||||
case UART_IIR_RX_TIMEOUT:
|
||||
/*
|
||||
* If RCVR FIFO trigger level was not reached, complete the
|
||||
* transfer and let 8250_core copy the remaining data.
|
||||
*/
|
||||
if (dma_status == DMA_IN_PROGRESS) {
|
||||
dmaengine_pause(dma->rxchan);
|
||||
__dma_rx_complete(p);
|
||||
}
|
||||
return -ETIMEDOUT;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (dma_status)
|
||||
return 0;
|
||||
|
||||
desc = dmaengine_prep_slave_single(dma->rxchan, dma->rx_addr,
|
||||
dma->rx_size, DMA_DEV_TO_MEM,
|
||||
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
|
||||
@ -143,21 +149,31 @@ int serial8250_request_dma(struct uart_8250_port *p)
|
||||
struct uart_8250_dma *dma = p->dma;
|
||||
dma_cap_mask_t mask;
|
||||
|
||||
dma->rxconf.src_addr = p->port.mapbase + UART_RX;
|
||||
dma->txconf.dst_addr = p->port.mapbase + UART_TX;
|
||||
/* Default slave configuration parameters */
|
||||
dma->rxconf.direction = DMA_DEV_TO_MEM;
|
||||
dma->rxconf.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
|
||||
dma->rxconf.src_addr = p->port.mapbase + UART_RX;
|
||||
|
||||
dma->txconf.direction = DMA_MEM_TO_DEV;
|
||||
dma->txconf.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
|
||||
dma->txconf.dst_addr = p->port.mapbase + UART_TX;
|
||||
|
||||
dma_cap_zero(mask);
|
||||
dma_cap_set(DMA_SLAVE, mask);
|
||||
|
||||
/* Get a channel for RX */
|
||||
dma->rxchan = dma_request_channel(mask, dma->fn, dma->rx_param);
|
||||
dma->rxchan = dma_request_slave_channel_compat(mask,
|
||||
dma->fn, dma->rx_param,
|
||||
p->port.dev, "rx");
|
||||
if (!dma->rxchan)
|
||||
return -ENODEV;
|
||||
|
||||
dmaengine_slave_config(dma->rxchan, &dma->rxconf);
|
||||
|
||||
/* Get a channel for TX */
|
||||
dma->txchan = dma_request_channel(mask, dma->fn, dma->tx_param);
|
||||
dma->txchan = dma_request_slave_channel_compat(mask,
|
||||
dma->fn, dma->tx_param,
|
||||
p->port.dev, "tx");
|
||||
if (!dma->txchan) {
|
||||
dma_release_channel(dma->rxchan);
|
||||
return -ENODEV;
|
||||
|
@ -26,6 +26,8 @@
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
|
||||
#include "8250.h"
|
||||
|
||||
@ -34,9 +36,6 @@
|
||||
#define DW_UART_CPR 0xf4 /* Component Parameter Register */
|
||||
#define DW_UART_UCV 0xf8 /* UART Component Version */
|
||||
|
||||
/* Intel Low Power Subsystem specific */
|
||||
#define LPSS_PRV_CLOCK_PARAMS 0x800
|
||||
|
||||
/* Component Parameter Register bits */
|
||||
#define DW_UART_CPR_ABP_DATA_WIDTH (3 << 0)
|
||||
#define DW_UART_CPR_AFCE_MODE (1 << 4)
|
||||
@ -55,8 +54,9 @@
|
||||
|
||||
|
||||
struct dw8250_data {
|
||||
int last_lcr;
|
||||
int line;
|
||||
int last_lcr;
|
||||
int line;
|
||||
struct clk *clk;
|
||||
};
|
||||
|
||||
static void dw8250_serial_out(struct uart_port *p, int offset, int value)
|
||||
@ -113,6 +113,18 @@ static int dw8250_handle_irq(struct uart_port *p)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
dw8250_do_pm(struct uart_port *port, unsigned int state, unsigned int old)
|
||||
{
|
||||
if (!state)
|
||||
pm_runtime_get_sync(port->dev);
|
||||
|
||||
serial8250_do_pm(port, state, old);
|
||||
|
||||
if (state)
|
||||
pm_runtime_put_sync_suspend(port->dev);
|
||||
}
|
||||
|
||||
static int dw8250_probe_of(struct uart_port *p)
|
||||
{
|
||||
struct device_node *np = p->dev->of_node;
|
||||
@ -136,8 +148,13 @@ static int dw8250_probe_of(struct uart_port *p)
|
||||
if (!of_property_read_u32(np, "reg-shift", &val))
|
||||
p->regshift = val;
|
||||
|
||||
/* clock got configured through clk api, all done */
|
||||
if (p->uartclk)
|
||||
return 0;
|
||||
|
||||
/* try to find out clock frequency from DT as fallback */
|
||||
if (of_property_read_u32(np, "clock-frequency", &val)) {
|
||||
dev_err(p->dev, "no clock-frequency property set\n");
|
||||
dev_err(p->dev, "clk or clock-frequency not defined\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
p->uartclk = val;
|
||||
@ -146,67 +163,10 @@ static int dw8250_probe_of(struct uart_port *p)
|
||||
}
|
||||
|
||||
#ifdef CONFIG_ACPI
|
||||
static bool dw8250_acpi_dma_filter(struct dma_chan *chan, void *parm)
|
||||
{
|
||||
return chan->chan_id == *(int *)parm;
|
||||
}
|
||||
|
||||
static acpi_status
|
||||
dw8250_acpi_walk_resource(struct acpi_resource *res, void *data)
|
||||
{
|
||||
struct uart_port *p = data;
|
||||
struct uart_8250_port *port;
|
||||
struct uart_8250_dma *dma;
|
||||
struct acpi_resource_fixed_dma *fixed_dma;
|
||||
struct dma_slave_config *slave;
|
||||
|
||||
port = container_of(p, struct uart_8250_port, port);
|
||||
|
||||
switch (res->type) {
|
||||
case ACPI_RESOURCE_TYPE_FIXED_DMA:
|
||||
fixed_dma = &res->data.fixed_dma;
|
||||
|
||||
/* TX comes first */
|
||||
if (!port->dma) {
|
||||
dma = devm_kzalloc(p->dev, sizeof(*dma), GFP_KERNEL);
|
||||
if (!dma)
|
||||
return AE_NO_MEMORY;
|
||||
|
||||
port->dma = dma;
|
||||
slave = &dma->txconf;
|
||||
|
||||
slave->direction = DMA_MEM_TO_DEV;
|
||||
slave->dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
|
||||
slave->slave_id = fixed_dma->request_lines;
|
||||
slave->dst_maxburst = port->tx_loadsz / 4;
|
||||
|
||||
dma->tx_chan_id = fixed_dma->channels;
|
||||
dma->tx_param = &dma->tx_chan_id;
|
||||
dma->fn = dw8250_acpi_dma_filter;
|
||||
} else {
|
||||
dma = port->dma;
|
||||
slave = &dma->rxconf;
|
||||
|
||||
slave->direction = DMA_DEV_TO_MEM;
|
||||
slave->src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
|
||||
slave->slave_id = fixed_dma->request_lines;
|
||||
slave->src_maxburst = p->fifosize / 4;
|
||||
|
||||
dma->rx_chan_id = fixed_dma->channels;
|
||||
dma->rx_param = &dma->rx_chan_id;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return AE_OK;
|
||||
}
|
||||
|
||||
static int dw8250_probe_acpi(struct uart_port *p)
|
||||
static int dw8250_probe_acpi(struct uart_8250_port *up)
|
||||
{
|
||||
const struct acpi_device_id *id;
|
||||
acpi_status status;
|
||||
u32 reg;
|
||||
struct uart_port *p = &up->port;
|
||||
|
||||
id = acpi_match_device(p->dev->driver->acpi_match_table, p->dev);
|
||||
if (!id)
|
||||
@ -216,26 +176,21 @@ static int dw8250_probe_acpi(struct uart_port *p)
|
||||
p->serial_in = dw8250_serial_in32;
|
||||
p->serial_out = dw8250_serial_out32;
|
||||
p->regshift = 2;
|
||||
p->uartclk = (unsigned int)id->driver_data;
|
||||
|
||||
status = acpi_walk_resources(ACPI_HANDLE(p->dev), METHOD_NAME__CRS,
|
||||
dw8250_acpi_walk_resource, p);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
dev_err_ratelimited(p->dev, "%s failed \"%s\"\n", __func__,
|
||||
acpi_format_exception(status));
|
||||
return -ENODEV;
|
||||
}
|
||||
if (!p->uartclk)
|
||||
p->uartclk = (unsigned int)id->driver_data;
|
||||
|
||||
/* Fix Haswell issue where the clocks do not get enabled */
|
||||
if (!strcmp(id->id, "INT33C4") || !strcmp(id->id, "INT33C5")) {
|
||||
reg = readl(p->membase + LPSS_PRV_CLOCK_PARAMS);
|
||||
writel(reg | 1, p->membase + LPSS_PRV_CLOCK_PARAMS);
|
||||
}
|
||||
up->dma = devm_kzalloc(p->dev, sizeof(*up->dma), GFP_KERNEL);
|
||||
if (!up->dma)
|
||||
return -ENOMEM;
|
||||
|
||||
up->dma->rxconf.src_maxburst = p->fifosize / 4;
|
||||
up->dma->txconf.dst_maxburst = p->fifosize / 4;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
static inline int dw8250_probe_acpi(struct uart_port *p)
|
||||
static inline int dw8250_probe_acpi(struct uart_8250_port *up)
|
||||
{
|
||||
return -ENODEV;
|
||||
}
|
||||
@ -266,7 +221,11 @@ static void dw8250_setup_port(struct uart_8250_port *up)
|
||||
p->flags |= UPF_FIXED_TYPE;
|
||||
p->fifosize = DW_UART_CPR_FIFO_SIZE(reg);
|
||||
up->tx_loadsz = p->fifosize;
|
||||
up->capabilities = UART_CAP_FIFO;
|
||||
}
|
||||
|
||||
if (reg & DW_UART_CPR_AFCE_MODE)
|
||||
up->capabilities |= UART_CAP_AFE;
|
||||
}
|
||||
|
||||
static int dw8250_probe(struct platform_device *pdev)
|
||||
@ -286,17 +245,30 @@ static int dw8250_probe(struct platform_device *pdev)
|
||||
uart.port.mapbase = regs->start;
|
||||
uart.port.irq = irq->start;
|
||||
uart.port.handle_irq = dw8250_handle_irq;
|
||||
uart.port.pm = dw8250_do_pm;
|
||||
uart.port.type = PORT_8250;
|
||||
uart.port.flags = UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF | UPF_FIXED_PORT;
|
||||
uart.port.dev = &pdev->dev;
|
||||
|
||||
uart.port.membase = ioremap(regs->start, resource_size(regs));
|
||||
uart.port.membase = devm_ioremap(&pdev->dev, regs->start,
|
||||
resource_size(regs));
|
||||
if (!uart.port.membase)
|
||||
return -ENOMEM;
|
||||
|
||||
data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
data->clk = devm_clk_get(&pdev->dev, NULL);
|
||||
if (!IS_ERR(data->clk)) {
|
||||
clk_prepare_enable(data->clk);
|
||||
uart.port.uartclk = clk_get_rate(data->clk);
|
||||
}
|
||||
|
||||
uart.port.iotype = UPIO_MEM;
|
||||
uart.port.serial_in = dw8250_serial_in;
|
||||
uart.port.serial_out = dw8250_serial_out;
|
||||
uart.port.private_data = data;
|
||||
|
||||
dw8250_setup_port(&uart);
|
||||
|
||||
@ -305,25 +277,22 @@ static int dw8250_probe(struct platform_device *pdev)
|
||||
if (err)
|
||||
return err;
|
||||
} else if (ACPI_HANDLE(&pdev->dev)) {
|
||||
err = dw8250_probe_acpi(&uart.port);
|
||||
err = dw8250_probe_acpi(&uart);
|
||||
if (err)
|
||||
return err;
|
||||
} else {
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
uart.port.private_data = data;
|
||||
|
||||
data->line = serial8250_register_8250_port(&uart);
|
||||
if (data->line < 0)
|
||||
return data->line;
|
||||
|
||||
platform_set_drvdata(pdev, data);
|
||||
|
||||
pm_runtime_set_active(&pdev->dev);
|
||||
pm_runtime_enable(&pdev->dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -331,34 +300,64 @@ static int dw8250_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct dw8250_data *data = platform_get_drvdata(pdev);
|
||||
|
||||
pm_runtime_get_sync(&pdev->dev);
|
||||
|
||||
serial8250_unregister_port(data->line);
|
||||
|
||||
if (!IS_ERR(data->clk))
|
||||
clk_disable_unprepare(data->clk);
|
||||
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
pm_runtime_put_noidle(&pdev->dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int dw8250_suspend(struct platform_device *pdev, pm_message_t state)
|
||||
static int dw8250_suspend(struct device *dev)
|
||||
{
|
||||
struct dw8250_data *data = platform_get_drvdata(pdev);
|
||||
struct dw8250_data *data = dev_get_drvdata(dev);
|
||||
|
||||
serial8250_suspend_port(data->line);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dw8250_resume(struct platform_device *pdev)
|
||||
static int dw8250_resume(struct device *dev)
|
||||
{
|
||||
struct dw8250_data *data = platform_get_drvdata(pdev);
|
||||
struct dw8250_data *data = dev_get_drvdata(dev);
|
||||
|
||||
serial8250_resume_port(data->line);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
#define dw8250_suspend NULL
|
||||
#define dw8250_resume NULL
|
||||
#endif /* CONFIG_PM */
|
||||
|
||||
#ifdef CONFIG_PM_RUNTIME
|
||||
static int dw8250_runtime_suspend(struct device *dev)
|
||||
{
|
||||
struct dw8250_data *data = dev_get_drvdata(dev);
|
||||
|
||||
clk_disable_unprepare(data->clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dw8250_runtime_resume(struct device *dev)
|
||||
{
|
||||
struct dw8250_data *data = dev_get_drvdata(dev);
|
||||
|
||||
clk_prepare_enable(data->clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static const struct dev_pm_ops dw8250_pm_ops = {
|
||||
SET_SYSTEM_SLEEP_PM_OPS(dw8250_suspend, dw8250_resume)
|
||||
SET_RUNTIME_PM_OPS(dw8250_runtime_suspend, dw8250_runtime_resume, NULL)
|
||||
};
|
||||
|
||||
static const struct of_device_id dw8250_of_match[] = {
|
||||
{ .compatible = "snps,dw-apb-uart" },
|
||||
{ /* Sentinel */ }
|
||||
@ -366,8 +365,8 @@ static const struct of_device_id dw8250_of_match[] = {
|
||||
MODULE_DEVICE_TABLE(of, dw8250_of_match);
|
||||
|
||||
static const struct acpi_device_id dw8250_acpi_match[] = {
|
||||
{ "INT33C4", 100000000 },
|
||||
{ "INT33C5", 100000000 },
|
||||
{ "INT33C4", 0 },
|
||||
{ "INT33C5", 0 },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(acpi, dw8250_acpi_match);
|
||||
@ -376,13 +375,12 @@ static struct platform_driver dw8250_platform_driver = {
|
||||
.driver = {
|
||||
.name = "dw-apb-uart",
|
||||
.owner = THIS_MODULE,
|
||||
.pm = &dw8250_pm_ops,
|
||||
.of_match_table = dw8250_of_match,
|
||||
.acpi_match_table = ACPI_PTR(dw8250_acpi_match),
|
||||
},
|
||||
.probe = dw8250_probe,
|
||||
.remove = dw8250_remove,
|
||||
.suspend = dw8250_suspend,
|
||||
.resume = dw8250_resume,
|
||||
};
|
||||
|
||||
module_platform_driver(dw8250_platform_driver);
|
||||
|
@ -29,6 +29,7 @@
|
||||
* and hooked into this driver.
|
||||
*/
|
||||
|
||||
|
||||
#if defined(CONFIG_SERIAL_AMBA_PL011_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
|
||||
#define SUPPORT_SYSRQ
|
||||
#endif
|
||||
@ -72,32 +73,44 @@
|
||||
/* There is by now at least one vendor with differing details, so handle it */
|
||||
struct vendor_data {
|
||||
unsigned int ifls;
|
||||
unsigned int fifosize;
|
||||
unsigned int lcrh_tx;
|
||||
unsigned int lcrh_rx;
|
||||
bool oversampling;
|
||||
bool dma_threshold;
|
||||
bool cts_event_workaround;
|
||||
|
||||
unsigned int (*get_fifosize)(unsigned int periphid);
|
||||
};
|
||||
|
||||
static unsigned int get_fifosize_arm(unsigned int periphid)
|
||||
{
|
||||
unsigned int rev = (periphid >> 20) & 0xf;
|
||||
return rev < 3 ? 16 : 32;
|
||||
}
|
||||
|
||||
static struct vendor_data vendor_arm = {
|
||||
.ifls = UART011_IFLS_RX4_8|UART011_IFLS_TX4_8,
|
||||
.fifosize = 16,
|
||||
.lcrh_tx = UART011_LCRH,
|
||||
.lcrh_rx = UART011_LCRH,
|
||||
.oversampling = false,
|
||||
.dma_threshold = false,
|
||||
.cts_event_workaround = false,
|
||||
.get_fifosize = get_fifosize_arm,
|
||||
};
|
||||
|
||||
static unsigned int get_fifosize_st(unsigned int periphid)
|
||||
{
|
||||
return 64;
|
||||
}
|
||||
|
||||
static struct vendor_data vendor_st = {
|
||||
.ifls = UART011_IFLS_RX_HALF|UART011_IFLS_TX_HALF,
|
||||
.fifosize = 64,
|
||||
.lcrh_tx = ST_UART011_LCRH_TX,
|
||||
.lcrh_rx = ST_UART011_LCRH_RX,
|
||||
.oversampling = true,
|
||||
.dma_threshold = true,
|
||||
.cts_event_workaround = true,
|
||||
.get_fifosize = get_fifosize_st,
|
||||
};
|
||||
|
||||
static struct uart_amba_port *amba_ports[UART_NR];
|
||||
@ -117,6 +130,12 @@ struct pl011_dmarx_data {
|
||||
struct pl011_sgbuf sgbuf_b;
|
||||
dma_cookie_t cookie;
|
||||
bool running;
|
||||
struct timer_list timer;
|
||||
unsigned int last_residue;
|
||||
unsigned long last_jiffies;
|
||||
bool auto_poll_rate;
|
||||
unsigned int poll_rate;
|
||||
unsigned int poll_timeout;
|
||||
};
|
||||
|
||||
struct pl011_dmatx_data {
|
||||
@ -223,16 +242,18 @@ static int pl011_fifo_to_tty(struct uart_amba_port *uap)
|
||||
static int pl011_sgbuf_init(struct dma_chan *chan, struct pl011_sgbuf *sg,
|
||||
enum dma_data_direction dir)
|
||||
{
|
||||
sg->buf = kmalloc(PL011_DMA_BUFFER_SIZE, GFP_KERNEL);
|
||||
dma_addr_t dma_addr;
|
||||
|
||||
sg->buf = dma_alloc_coherent(chan->device->dev,
|
||||
PL011_DMA_BUFFER_SIZE, &dma_addr, GFP_KERNEL);
|
||||
if (!sg->buf)
|
||||
return -ENOMEM;
|
||||
|
||||
sg_init_one(&sg->sg, sg->buf, PL011_DMA_BUFFER_SIZE);
|
||||
sg_init_table(&sg->sg, 1);
|
||||
sg_set_page(&sg->sg, phys_to_page(dma_addr),
|
||||
PL011_DMA_BUFFER_SIZE, offset_in_page(dma_addr));
|
||||
sg_dma_address(&sg->sg) = dma_addr;
|
||||
|
||||
if (dma_map_sg(chan->device->dev, &sg->sg, 1, dir) != 1) {
|
||||
kfree(sg->buf);
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -240,8 +261,9 @@ static void pl011_sgbuf_free(struct dma_chan *chan, struct pl011_sgbuf *sg,
|
||||
enum dma_data_direction dir)
|
||||
{
|
||||
if (sg->buf) {
|
||||
dma_unmap_sg(chan->device->dev, &sg->sg, 1, dir);
|
||||
kfree(sg->buf);
|
||||
dma_free_coherent(chan->device->dev,
|
||||
PL011_DMA_BUFFER_SIZE, sg->buf,
|
||||
sg_dma_address(&sg->sg));
|
||||
}
|
||||
}
|
||||
|
||||
@ -300,6 +322,29 @@ static void pl011_dma_probe_initcall(struct uart_amba_port *uap)
|
||||
dmaengine_slave_config(chan, &rx_conf);
|
||||
uap->dmarx.chan = chan;
|
||||
|
||||
if (plat->dma_rx_poll_enable) {
|
||||
/* Set poll rate if specified. */
|
||||
if (plat->dma_rx_poll_rate) {
|
||||
uap->dmarx.auto_poll_rate = false;
|
||||
uap->dmarx.poll_rate = plat->dma_rx_poll_rate;
|
||||
} else {
|
||||
/*
|
||||
* 100 ms defaults to poll rate if not
|
||||
* specified. This will be adjusted with
|
||||
* the baud rate at set_termios.
|
||||
*/
|
||||
uap->dmarx.auto_poll_rate = true;
|
||||
uap->dmarx.poll_rate = 100;
|
||||
}
|
||||
/* 3 secs defaults poll_timeout if not specified. */
|
||||
if (plat->dma_rx_poll_timeout)
|
||||
uap->dmarx.poll_timeout =
|
||||
plat->dma_rx_poll_timeout;
|
||||
else
|
||||
uap->dmarx.poll_timeout = 3000;
|
||||
} else
|
||||
uap->dmarx.auto_poll_rate = false;
|
||||
|
||||
dev_info(uap->port.dev, "DMA channel RX %s\n",
|
||||
dma_chan_name(uap->dmarx.chan));
|
||||
}
|
||||
@ -701,24 +746,30 @@ static void pl011_dma_rx_chars(struct uart_amba_port *uap,
|
||||
struct tty_port *port = &uap->port.state->port;
|
||||
struct pl011_sgbuf *sgbuf = use_buf_b ?
|
||||
&uap->dmarx.sgbuf_b : &uap->dmarx.sgbuf_a;
|
||||
struct device *dev = uap->dmarx.chan->device->dev;
|
||||
int dma_count = 0;
|
||||
u32 fifotaken = 0; /* only used for vdbg() */
|
||||
|
||||
/* Pick everything from the DMA first */
|
||||
struct pl011_dmarx_data *dmarx = &uap->dmarx;
|
||||
int dmataken = 0;
|
||||
|
||||
if (uap->dmarx.poll_rate) {
|
||||
/* The data can be taken by polling */
|
||||
dmataken = sgbuf->sg.length - dmarx->last_residue;
|
||||
/* Recalculate the pending size */
|
||||
if (pending >= dmataken)
|
||||
pending -= dmataken;
|
||||
}
|
||||
|
||||
/* Pick the remain data from the DMA */
|
||||
if (pending) {
|
||||
/* Sync in buffer */
|
||||
dma_sync_sg_for_cpu(dev, &sgbuf->sg, 1, DMA_FROM_DEVICE);
|
||||
|
||||
/*
|
||||
* First take all chars in the DMA pipe, then look in the FIFO.
|
||||
* Note that tty_insert_flip_buf() tries to take as many chars
|
||||
* as it can.
|
||||
*/
|
||||
dma_count = tty_insert_flip_string(port, sgbuf->buf, pending);
|
||||
|
||||
/* Return buffer to device */
|
||||
dma_sync_sg_for_device(dev, &sgbuf->sg, 1, DMA_FROM_DEVICE);
|
||||
dma_count = tty_insert_flip_string(port, sgbuf->buf + dmataken,
|
||||
pending);
|
||||
|
||||
uap->port.icount.rx += dma_count;
|
||||
if (dma_count < pending)
|
||||
@ -726,6 +777,10 @@ static void pl011_dma_rx_chars(struct uart_amba_port *uap,
|
||||
"couldn't insert all characters (TTY is full?)\n");
|
||||
}
|
||||
|
||||
/* Reset the last_residue for Rx DMA poll */
|
||||
if (uap->dmarx.poll_rate)
|
||||
dmarx->last_residue = sgbuf->sg.length;
|
||||
|
||||
/*
|
||||
* Only continue with trying to read the FIFO if all DMA chars have
|
||||
* been taken first.
|
||||
@ -865,6 +920,57 @@ static inline void pl011_dma_rx_stop(struct uart_amba_port *uap)
|
||||
writew(uap->dmacr, uap->port.membase + UART011_DMACR);
|
||||
}
|
||||
|
||||
/*
|
||||
* Timer handler for Rx DMA polling.
|
||||
* Every polling, It checks the residue in the dma buffer and transfer
|
||||
* data to the tty. Also, last_residue is updated for the next polling.
|
||||
*/
|
||||
static void pl011_dma_rx_poll(unsigned long args)
|
||||
{
|
||||
struct uart_amba_port *uap = (struct uart_amba_port *)args;
|
||||
struct tty_port *port = &uap->port.state->port;
|
||||
struct pl011_dmarx_data *dmarx = &uap->dmarx;
|
||||
struct dma_chan *rxchan = uap->dmarx.chan;
|
||||
unsigned long flags = 0;
|
||||
unsigned int dmataken = 0;
|
||||
unsigned int size = 0;
|
||||
struct pl011_sgbuf *sgbuf;
|
||||
int dma_count;
|
||||
struct dma_tx_state state;
|
||||
|
||||
sgbuf = dmarx->use_buf_b ? &uap->dmarx.sgbuf_b : &uap->dmarx.sgbuf_a;
|
||||
rxchan->device->device_tx_status(rxchan, dmarx->cookie, &state);
|
||||
if (likely(state.residue < dmarx->last_residue)) {
|
||||
dmataken = sgbuf->sg.length - dmarx->last_residue;
|
||||
size = dmarx->last_residue - state.residue;
|
||||
dma_count = tty_insert_flip_string(port, sgbuf->buf + dmataken,
|
||||
size);
|
||||
if (dma_count == size)
|
||||
dmarx->last_residue = state.residue;
|
||||
dmarx->last_jiffies = jiffies;
|
||||
}
|
||||
tty_flip_buffer_push(port);
|
||||
|
||||
/*
|
||||
* If no data is received in poll_timeout, the driver will fall back
|
||||
* to interrupt mode. We will retrigger DMA at the first interrupt.
|
||||
*/
|
||||
if (jiffies_to_msecs(jiffies - dmarx->last_jiffies)
|
||||
> uap->dmarx.poll_timeout) {
|
||||
|
||||
spin_lock_irqsave(&uap->port.lock, flags);
|
||||
pl011_dma_rx_stop(uap);
|
||||
spin_unlock_irqrestore(&uap->port.lock, flags);
|
||||
|
||||
uap->dmarx.running = false;
|
||||
dmaengine_terminate_all(rxchan);
|
||||
del_timer(&uap->dmarx.timer);
|
||||
} else {
|
||||
mod_timer(&uap->dmarx.timer,
|
||||
jiffies + msecs_to_jiffies(uap->dmarx.poll_rate));
|
||||
}
|
||||
}
|
||||
|
||||
static void pl011_dma_startup(struct uart_amba_port *uap)
|
||||
{
|
||||
int ret;
|
||||
@ -927,6 +1033,16 @@ skip_rx:
|
||||
if (pl011_dma_rx_trigger_dma(uap))
|
||||
dev_dbg(uap->port.dev, "could not trigger initial "
|
||||
"RX DMA job, fall back to interrupt mode\n");
|
||||
if (uap->dmarx.poll_rate) {
|
||||
init_timer(&(uap->dmarx.timer));
|
||||
uap->dmarx.timer.function = pl011_dma_rx_poll;
|
||||
uap->dmarx.timer.data = (unsigned long)uap;
|
||||
mod_timer(&uap->dmarx.timer,
|
||||
jiffies +
|
||||
msecs_to_jiffies(uap->dmarx.poll_rate));
|
||||
uap->dmarx.last_residue = PL011_DMA_BUFFER_SIZE;
|
||||
uap->dmarx.last_jiffies = jiffies;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -962,6 +1078,8 @@ static void pl011_dma_shutdown(struct uart_amba_port *uap)
|
||||
/* Clean up the RX DMA */
|
||||
pl011_sgbuf_free(uap->dmarx.chan, &uap->dmarx.sgbuf_a, DMA_FROM_DEVICE);
|
||||
pl011_sgbuf_free(uap->dmarx.chan, &uap->dmarx.sgbuf_b, DMA_FROM_DEVICE);
|
||||
if (uap->dmarx.poll_rate)
|
||||
del_timer_sync(&uap->dmarx.timer);
|
||||
uap->using_rx_dma = false;
|
||||
}
|
||||
}
|
||||
@ -976,7 +1094,6 @@ static inline bool pl011_dma_rx_running(struct uart_amba_port *uap)
|
||||
return uap->using_rx_dma && uap->dmarx.running;
|
||||
}
|
||||
|
||||
|
||||
#else
|
||||
/* Blank functions if the DMA engine is not available */
|
||||
static inline void pl011_dma_probe(struct uart_amba_port *uap)
|
||||
@ -1088,8 +1205,20 @@ static void pl011_rx_chars(struct uart_amba_port *uap)
|
||||
dev_dbg(uap->port.dev, "could not trigger RX DMA job "
|
||||
"fall back to interrupt mode again\n");
|
||||
uap->im |= UART011_RXIM;
|
||||
} else
|
||||
} else {
|
||||
uap->im &= ~UART011_RXIM;
|
||||
#ifdef CONFIG_DMA_ENGINE
|
||||
/* Start Rx DMA poll */
|
||||
if (uap->dmarx.poll_rate) {
|
||||
uap->dmarx.last_jiffies = jiffies;
|
||||
uap->dmarx.last_residue = PL011_DMA_BUFFER_SIZE;
|
||||
mod_timer(&uap->dmarx.timer,
|
||||
jiffies +
|
||||
msecs_to_jiffies(uap->dmarx.poll_rate));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
writew(uap->im, uap->port.membase + UART011_IMSC);
|
||||
}
|
||||
spin_lock(&uap->port.lock);
|
||||
@ -1164,7 +1293,6 @@ static irqreturn_t pl011_int(int irq, void *dev_id)
|
||||
unsigned int dummy_read;
|
||||
|
||||
spin_lock_irqsave(&uap->port.lock, flags);
|
||||
|
||||
status = readw(uap->port.membase + UART011_MIS);
|
||||
if (status) {
|
||||
do {
|
||||
@ -1551,6 +1679,13 @@ pl011_set_termios(struct uart_port *port, struct ktermios *termios,
|
||||
*/
|
||||
baud = uart_get_baud_rate(port, termios, old, 0,
|
||||
port->uartclk / clkdiv);
|
||||
#ifdef CONFIG_DMA_ENGINE
|
||||
/*
|
||||
* Adjust RX DMA polling rate with baud rate if not specified.
|
||||
*/
|
||||
if (uap->dmarx.auto_poll_rate)
|
||||
uap->dmarx.poll_rate = DIV_ROUND_UP(10000000, baud);
|
||||
#endif
|
||||
|
||||
if (baud > port->uartclk/16)
|
||||
quot = DIV_ROUND_CLOSEST(port->uartclk * 8, baud);
|
||||
@ -2010,7 +2145,7 @@ static int pl011_probe(struct amba_device *dev, const struct amba_id *id)
|
||||
uap->lcrh_rx = vendor->lcrh_rx;
|
||||
uap->lcrh_tx = vendor->lcrh_tx;
|
||||
uap->old_cr = 0;
|
||||
uap->fifosize = vendor->fifosize;
|
||||
uap->fifosize = vendor->get_fifosize(dev->periphid);
|
||||
uap->port.dev = &dev->dev;
|
||||
uap->port.mapbase = dev->res.start;
|
||||
uap->port.membase = base;
|
||||
|
@ -162,7 +162,7 @@ static unsigned int arc_serial_tx_empty(struct uart_port *port)
|
||||
/*
|
||||
* Driver internal routine, used by both tty(serial core) as well as tx-isr
|
||||
* -Called under spinlock in either cases
|
||||
* -also tty->stopped / tty->hw_stopped has already been checked
|
||||
* -also tty->stopped has already been checked
|
||||
* = by uart_start( ) before calling us
|
||||
* = tx_ist checks that too before calling
|
||||
*/
|
||||
|
@ -1011,24 +1011,6 @@ static int bfin_serial_poll_get_char(struct uart_port *port)
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_KGDB_SERIAL_CONSOLE) || \
|
||||
defined(CONFIG_KGDB_SERIAL_CONSOLE_MODULE)
|
||||
static void bfin_kgdboc_port_shutdown(struct uart_port *port)
|
||||
{
|
||||
if (kgdboc_break_enabled) {
|
||||
kgdboc_break_enabled = 0;
|
||||
bfin_serial_shutdown(port);
|
||||
}
|
||||
}
|
||||
|
||||
static int bfin_kgdboc_port_startup(struct uart_port *port)
|
||||
{
|
||||
kgdboc_port_line = port->line;
|
||||
kgdboc_break_enabled = !bfin_serial_startup(port);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static struct uart_ops bfin_serial_pops = {
|
||||
.tx_empty = bfin_serial_tx_empty,
|
||||
.set_mctrl = bfin_serial_set_mctrl,
|
||||
@ -1047,11 +1029,6 @@ static struct uart_ops bfin_serial_pops = {
|
||||
.request_port = bfin_serial_request_port,
|
||||
.config_port = bfin_serial_config_port,
|
||||
.verify_port = bfin_serial_verify_port,
|
||||
#if defined(CONFIG_KGDB_SERIAL_CONSOLE) || \
|
||||
defined(CONFIG_KGDB_SERIAL_CONSOLE_MODULE)
|
||||
.kgdboc_port_startup = bfin_kgdboc_port_startup,
|
||||
.kgdboc_port_shutdown = bfin_kgdboc_port_shutdown,
|
||||
#endif
|
||||
#ifdef CONFIG_CONSOLE_POLL
|
||||
.poll_put_char = bfin_serial_poll_put_char,
|
||||
.poll_get_char = bfin_serial_poll_get_char,
|
||||
|
@ -169,7 +169,6 @@ static int get_lsr_info(struct e100_serial *info, unsigned int *value);
|
||||
|
||||
|
||||
#define DEF_BAUD 115200 /* 115.2 kbit/s */
|
||||
#define STD_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST)
|
||||
#define DEF_RX 0x20 /* or SERIAL_CTRL_W >> 8 */
|
||||
/* Default value of tx_ctrl register: has txd(bit 7)=1 (idle) as default */
|
||||
#define DEF_TX 0x80 /* or SERIAL_CTRL_B */
|
||||
@ -246,7 +245,6 @@ static struct e100_serial rs_table[] = {
|
||||
.ifirstadr = R_DMA_CH7_FIRST,
|
||||
.icmdadr = R_DMA_CH7_CMD,
|
||||
.idescradr = R_DMA_CH7_DESCR,
|
||||
.flags = STD_FLAGS,
|
||||
.rx_ctrl = DEF_RX,
|
||||
.tx_ctrl = DEF_TX,
|
||||
.iseteop = 2,
|
||||
@ -300,7 +298,6 @@ static struct e100_serial rs_table[] = {
|
||||
.ifirstadr = R_DMA_CH9_FIRST,
|
||||
.icmdadr = R_DMA_CH9_CMD,
|
||||
.idescradr = R_DMA_CH9_DESCR,
|
||||
.flags = STD_FLAGS,
|
||||
.rx_ctrl = DEF_RX,
|
||||
.tx_ctrl = DEF_TX,
|
||||
.iseteop = 3,
|
||||
@ -356,7 +353,6 @@ static struct e100_serial rs_table[] = {
|
||||
.ifirstadr = R_DMA_CH3_FIRST,
|
||||
.icmdadr = R_DMA_CH3_CMD,
|
||||
.idescradr = R_DMA_CH3_DESCR,
|
||||
.flags = STD_FLAGS,
|
||||
.rx_ctrl = DEF_RX,
|
||||
.tx_ctrl = DEF_TX,
|
||||
.iseteop = 0,
|
||||
@ -410,7 +406,6 @@ static struct e100_serial rs_table[] = {
|
||||
.ifirstadr = R_DMA_CH5_FIRST,
|
||||
.icmdadr = R_DMA_CH5_CMD,
|
||||
.idescradr = R_DMA_CH5_DESCR,
|
||||
.flags = STD_FLAGS,
|
||||
.rx_ctrl = DEF_RX,
|
||||
.tx_ctrl = DEF_TX,
|
||||
.iseteop = 1,
|
||||
@ -2263,8 +2258,7 @@ TODO: The break will be delayed until an F or V character is received.
|
||||
|
||||
*/
|
||||
|
||||
static
|
||||
struct e100_serial * handle_ser_rx_interrupt_no_dma(struct e100_serial *info)
|
||||
static void handle_ser_rx_interrupt_no_dma(struct e100_serial *info)
|
||||
{
|
||||
unsigned long data_read;
|
||||
|
||||
@ -2370,10 +2364,9 @@ more_data:
|
||||
}
|
||||
|
||||
tty_flip_buffer_push(&info->port);
|
||||
return info;
|
||||
}
|
||||
|
||||
static struct e100_serial* handle_ser_rx_interrupt(struct e100_serial *info)
|
||||
static void handle_ser_rx_interrupt(struct e100_serial *info)
|
||||
{
|
||||
unsigned char rstat;
|
||||
|
||||
@ -2382,7 +2375,8 @@ static struct e100_serial* handle_ser_rx_interrupt(struct e100_serial *info)
|
||||
#endif
|
||||
/* DEBUG_LOG(info->line, "ser_interrupt stat %03X\n", rstat | (i << 8)); */
|
||||
if (!info->uses_dma_in) {
|
||||
return handle_ser_rx_interrupt_no_dma(info);
|
||||
handle_ser_rx_interrupt_no_dma(info);
|
||||
return;
|
||||
}
|
||||
/* DMA is used */
|
||||
rstat = info->ioport[REG_STATUS];
|
||||
@ -2489,7 +2483,6 @@ static struct e100_serial* handle_ser_rx_interrupt(struct e100_serial *info)
|
||||
/* Restarting the DMA never hurts */
|
||||
*info->icmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, restart);
|
||||
START_FLUSH_FAST_TIMER(info, "ser_int");
|
||||
return info;
|
||||
} /* handle_ser_rx_interrupt */
|
||||
|
||||
static void handle_ser_tx_interrupt(struct e100_serial *info)
|
||||
@ -2534,8 +2527,7 @@ static void handle_ser_tx_interrupt(struct e100_serial *info)
|
||||
}
|
||||
/* Normal char-by-char interrupt */
|
||||
if (info->xmit.head == info->xmit.tail
|
||||
|| info->port.tty->stopped
|
||||
|| info->port.tty->hw_stopped) {
|
||||
|| info->port.tty->stopped) {
|
||||
DFLOW(DEBUG_LOG(info->line, "tx_int: stopped %i\n",
|
||||
info->port.tty->stopped));
|
||||
e100_disable_serial_tx_ready_irq(info);
|
||||
@ -2722,7 +2714,7 @@ startup(struct e100_serial * info)
|
||||
|
||||
/* if it was already initialized, skip this */
|
||||
|
||||
if (info->flags & ASYNC_INITIALIZED) {
|
||||
if (info->port.flags & ASYNC_INITIALIZED) {
|
||||
local_irq_restore(flags);
|
||||
free_page(xmit_page);
|
||||
return 0;
|
||||
@ -2847,7 +2839,7 @@ startup(struct e100_serial * info)
|
||||
|
||||
#endif /* CONFIG_SVINTO_SIM */
|
||||
|
||||
info->flags |= ASYNC_INITIALIZED;
|
||||
info->port.flags |= ASYNC_INITIALIZED;
|
||||
|
||||
local_irq_restore(flags);
|
||||
return 0;
|
||||
@ -2892,7 +2884,7 @@ shutdown(struct e100_serial * info)
|
||||
|
||||
#endif /* CONFIG_SVINTO_SIM */
|
||||
|
||||
if (!(info->flags & ASYNC_INITIALIZED))
|
||||
if (!(info->port.flags & ASYNC_INITIALIZED))
|
||||
return;
|
||||
|
||||
#ifdef SERIAL_DEBUG_OPEN
|
||||
@ -2923,7 +2915,7 @@ shutdown(struct e100_serial * info)
|
||||
if (info->port.tty)
|
||||
set_bit(TTY_IO_ERROR, &info->port.tty->flags);
|
||||
|
||||
info->flags &= ~ASYNC_INITIALIZED;
|
||||
info->port.flags &= ~ASYNC_INITIALIZED;
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
|
||||
@ -2948,7 +2940,7 @@ change_speed(struct e100_serial *info)
|
||||
/* possibly, the tx/rx should be disabled first to do this safely */
|
||||
|
||||
/* change baud-rate and write it to the hardware */
|
||||
if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST) {
|
||||
if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST) {
|
||||
/* Special baudrate */
|
||||
u32 mask = 0xFF << (info->line*8); /* Each port has 8 bits */
|
||||
unsigned long alt_source =
|
||||
@ -3098,7 +3090,6 @@ rs_flush_chars(struct tty_struct *tty)
|
||||
if (info->tr_running ||
|
||||
info->xmit.head == info->xmit.tail ||
|
||||
tty->stopped ||
|
||||
tty->hw_stopped ||
|
||||
!info->xmit.buf)
|
||||
return;
|
||||
|
||||
@ -3176,7 +3167,6 @@ static int rs_raw_write(struct tty_struct *tty,
|
||||
|
||||
if (info->xmit.head != info->xmit.tail &&
|
||||
!tty->stopped &&
|
||||
!tty->hw_stopped &&
|
||||
!info->tr_running) {
|
||||
start_transmit(info);
|
||||
}
|
||||
@ -3400,10 +3390,10 @@ get_serial_info(struct e100_serial * info,
|
||||
tmp.line = info->line;
|
||||
tmp.port = (int)info->ioport;
|
||||
tmp.irq = info->irq;
|
||||
tmp.flags = info->flags;
|
||||
tmp.flags = info->port.flags;
|
||||
tmp.baud_base = info->baud_base;
|
||||
tmp.close_delay = info->close_delay;
|
||||
tmp.closing_wait = info->closing_wait;
|
||||
tmp.close_delay = info->port.close_delay;
|
||||
tmp.closing_wait = info->port.closing_wait;
|
||||
tmp.custom_divisor = info->custom_divisor;
|
||||
if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
|
||||
return -EFAULT;
|
||||
@ -3425,16 +3415,16 @@ set_serial_info(struct e100_serial *info,
|
||||
|
||||
if (!capable(CAP_SYS_ADMIN)) {
|
||||
if ((new_serial.type != info->type) ||
|
||||
(new_serial.close_delay != info->close_delay) ||
|
||||
(new_serial.close_delay != info->port.close_delay) ||
|
||||
((new_serial.flags & ~ASYNC_USR_MASK) !=
|
||||
(info->flags & ~ASYNC_USR_MASK)))
|
||||
(info->port.flags & ~ASYNC_USR_MASK)))
|
||||
return -EPERM;
|
||||
info->flags = ((info->flags & ~ASYNC_USR_MASK) |
|
||||
info->port.flags = ((info->port.flags & ~ASYNC_USR_MASK) |
|
||||
(new_serial.flags & ASYNC_USR_MASK));
|
||||
goto check_and_exit;
|
||||
}
|
||||
|
||||
if (info->count > 1)
|
||||
if (info->port.count > 1)
|
||||
return -EBUSY;
|
||||
|
||||
/*
|
||||
@ -3443,16 +3433,16 @@ set_serial_info(struct e100_serial *info,
|
||||
*/
|
||||
|
||||
info->baud_base = new_serial.baud_base;
|
||||
info->flags = ((info->flags & ~ASYNC_FLAGS) |
|
||||
info->port.flags = ((info->port.flags & ~ASYNC_FLAGS) |
|
||||
(new_serial.flags & ASYNC_FLAGS));
|
||||
info->custom_divisor = new_serial.custom_divisor;
|
||||
info->type = new_serial.type;
|
||||
info->close_delay = new_serial.close_delay;
|
||||
info->closing_wait = new_serial.closing_wait;
|
||||
info->port.low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
|
||||
info->port.close_delay = new_serial.close_delay;
|
||||
info->port.closing_wait = new_serial.closing_wait;
|
||||
info->port.low_latency = (info->port.flags & ASYNC_LOW_LATENCY) ? 1 : 0;
|
||||
|
||||
check_and_exit:
|
||||
if (info->flags & ASYNC_INITIALIZED) {
|
||||
if (info->port.flags & ASYNC_INITIALIZED) {
|
||||
change_speed(info);
|
||||
} else
|
||||
retval = startup(info);
|
||||
@ -3733,10 +3723,8 @@ rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
|
||||
|
||||
/* Handle turning off CRTSCTS */
|
||||
if ((old_termios->c_cflag & CRTSCTS) &&
|
||||
!(tty->termios.c_cflag & CRTSCTS)) {
|
||||
tty->hw_stopped = 0;
|
||||
!(tty->termios.c_cflag & CRTSCTS))
|
||||
rs_start(tty);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -3772,7 +3760,7 @@ rs_close(struct tty_struct *tty, struct file * filp)
|
||||
printk("[%d] rs_close ttyS%d, count = %d\n", current->pid,
|
||||
info->line, info->count);
|
||||
#endif
|
||||
if ((tty->count == 1) && (info->count != 1)) {
|
||||
if ((tty->count == 1) && (info->port.count != 1)) {
|
||||
/*
|
||||
* Uh, oh. tty->count is 1, which means that the tty
|
||||
* structure will be freed. Info->count should always
|
||||
@ -3782,32 +3770,32 @@ rs_close(struct tty_struct *tty, struct file * filp)
|
||||
*/
|
||||
printk(KERN_ERR
|
||||
"rs_close: bad serial port count; tty->count is 1, "
|
||||
"info->count is %d\n", info->count);
|
||||
info->count = 1;
|
||||
"info->count is %d\n", info->port.count);
|
||||
info->port.count = 1;
|
||||
}
|
||||
if (--info->count < 0) {
|
||||
if (--info->port.count < 0) {
|
||||
printk(KERN_ERR "rs_close: bad serial port count for ttyS%d: %d\n",
|
||||
info->line, info->count);
|
||||
info->count = 0;
|
||||
info->line, info->port.count);
|
||||
info->port.count = 0;
|
||||
}
|
||||
if (info->count) {
|
||||
if (info->port.count) {
|
||||
local_irq_restore(flags);
|
||||
return;
|
||||
}
|
||||
info->flags |= ASYNC_CLOSING;
|
||||
info->port.flags |= ASYNC_CLOSING;
|
||||
/*
|
||||
* Save the termios structure, since this port may have
|
||||
* separate termios for callout and dialin.
|
||||
*/
|
||||
if (info->flags & ASYNC_NORMAL_ACTIVE)
|
||||
if (info->port.flags & ASYNC_NORMAL_ACTIVE)
|
||||
info->normal_termios = tty->termios;
|
||||
/*
|
||||
* 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);
|
||||
if (info->port.closing_wait != ASYNC_CLOSING_WAIT_NONE)
|
||||
tty_wait_until_sent(tty, info->port.closing_wait);
|
||||
/*
|
||||
* At this point we stop accepting input. To do this, we
|
||||
* disable the serial receiver and the DMA receive interrupt.
|
||||
@ -3820,7 +3808,7 @@ rs_close(struct tty_struct *tty, struct file * filp)
|
||||
e100_disable_rx(info);
|
||||
e100_disable_rx_irq(info);
|
||||
|
||||
if (info->flags & ASYNC_INITIALIZED) {
|
||||
if (info->port.flags & ASYNC_INITIALIZED) {
|
||||
/*
|
||||
* Before we drop DTR, make sure the UART transmitter
|
||||
* has completely drained; this is especially
|
||||
@ -3836,13 +3824,13 @@ rs_close(struct tty_struct *tty, struct file * filp)
|
||||
tty->closing = 0;
|
||||
info->event = 0;
|
||||
info->port.tty = NULL;
|
||||
if (info->blocked_open) {
|
||||
if (info->close_delay)
|
||||
schedule_timeout_interruptible(info->close_delay);
|
||||
wake_up_interruptible(&info->open_wait);
|
||||
if (info->port.blocked_open) {
|
||||
if (info->port.close_delay)
|
||||
schedule_timeout_interruptible(info->port.close_delay);
|
||||
wake_up_interruptible(&info->port.open_wait);
|
||||
}
|
||||
info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
|
||||
wake_up_interruptible(&info->close_wait);
|
||||
info->port.flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
|
||||
wake_up_interruptible(&info->port.close_wait);
|
||||
local_irq_restore(flags);
|
||||
|
||||
/* port closed */
|
||||
@ -3935,10 +3923,10 @@ rs_hangup(struct tty_struct *tty)
|
||||
rs_flush_buffer(tty);
|
||||
shutdown(info);
|
||||
info->event = 0;
|
||||
info->count = 0;
|
||||
info->flags &= ~ASYNC_NORMAL_ACTIVE;
|
||||
info->port.count = 0;
|
||||
info->port.flags &= ~ASYNC_NORMAL_ACTIVE;
|
||||
info->port.tty = NULL;
|
||||
wake_up_interruptible(&info->open_wait);
|
||||
wake_up_interruptible(&info->port.open_wait);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -3960,11 +3948,11 @@ block_til_ready(struct tty_struct *tty, struct file * filp,
|
||||
* until it's done, and then try again.
|
||||
*/
|
||||
if (tty_hung_up_p(filp) ||
|
||||
(info->flags & ASYNC_CLOSING)) {
|
||||
wait_event_interruptible_tty(tty, info->close_wait,
|
||||
!(info->flags & ASYNC_CLOSING));
|
||||
(info->port.flags & ASYNC_CLOSING)) {
|
||||
wait_event_interruptible_tty(tty, info->port.close_wait,
|
||||
!(info->port.flags & ASYNC_CLOSING));
|
||||
#ifdef SERIAL_DO_RESTART
|
||||
if (info->flags & ASYNC_HUP_NOTIFY)
|
||||
if (info->port.flags & ASYNC_HUP_NOTIFY)
|
||||
return -EAGAIN;
|
||||
else
|
||||
return -ERESTARTSYS;
|
||||
@ -3979,7 +3967,7 @@ block_til_ready(struct tty_struct *tty, struct file * filp,
|
||||
*/
|
||||
if ((filp->f_flags & O_NONBLOCK) ||
|
||||
(tty->flags & (1 << TTY_IO_ERROR))) {
|
||||
info->flags |= ASYNC_NORMAL_ACTIVE;
|
||||
info->port.flags |= ASYNC_NORMAL_ACTIVE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -3990,23 +3978,23 @@ block_til_ready(struct tty_struct *tty, struct file * filp,
|
||||
/*
|
||||
* Block waiting for the carrier detect and the line to become
|
||||
* free (i.e., not in use by the callout). While we are in
|
||||
* this loop, info->count is dropped by one, so that
|
||||
* this loop, info->port.count is dropped by one, so that
|
||||
* rs_close() knows when to free things. We restore it upon
|
||||
* exit, either normal or abnormal.
|
||||
*/
|
||||
retval = 0;
|
||||
add_wait_queue(&info->open_wait, &wait);
|
||||
add_wait_queue(&info->port.open_wait, &wait);
|
||||
#ifdef SERIAL_DEBUG_OPEN
|
||||
printk("block_til_ready before block: ttyS%d, count = %d\n",
|
||||
info->line, info->count);
|
||||
info->line, info->port.count);
|
||||
#endif
|
||||
local_irq_save(flags);
|
||||
if (!tty_hung_up_p(filp)) {
|
||||
extra_count++;
|
||||
info->count--;
|
||||
info->port.count--;
|
||||
}
|
||||
local_irq_restore(flags);
|
||||
info->blocked_open++;
|
||||
info->port.blocked_open++;
|
||||
while (1) {
|
||||
local_irq_save(flags);
|
||||
/* assert RTS and DTR */
|
||||
@ -4015,9 +4003,9 @@ block_til_ready(struct tty_struct *tty, struct file * filp,
|
||||
local_irq_restore(flags);
|
||||
set_current_state(TASK_INTERRUPTIBLE);
|
||||
if (tty_hung_up_p(filp) ||
|
||||
!(info->flags & ASYNC_INITIALIZED)) {
|
||||
!(info->port.flags & ASYNC_INITIALIZED)) {
|
||||
#ifdef SERIAL_DO_RESTART
|
||||
if (info->flags & ASYNC_HUP_NOTIFY)
|
||||
if (info->port.flags & ASYNC_HUP_NOTIFY)
|
||||
retval = -EAGAIN;
|
||||
else
|
||||
retval = -ERESTARTSYS;
|
||||
@ -4026,7 +4014,7 @@ block_til_ready(struct tty_struct *tty, struct file * filp,
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
if (!(info->flags & ASYNC_CLOSING) && do_clocal)
|
||||
if (!(info->port.flags & ASYNC_CLOSING) && do_clocal)
|
||||
/* && (do_clocal || DCD_IS_ASSERTED) */
|
||||
break;
|
||||
if (signal_pending(current)) {
|
||||
@ -4035,24 +4023,24 @@ block_til_ready(struct tty_struct *tty, struct file * filp,
|
||||
}
|
||||
#ifdef SERIAL_DEBUG_OPEN
|
||||
printk("block_til_ready blocking: ttyS%d, count = %d\n",
|
||||
info->line, info->count);
|
||||
info->line, info->port.count);
|
||||
#endif
|
||||
tty_unlock(tty);
|
||||
schedule();
|
||||
tty_lock(tty);
|
||||
}
|
||||
set_current_state(TASK_RUNNING);
|
||||
remove_wait_queue(&info->open_wait, &wait);
|
||||
remove_wait_queue(&info->port.open_wait, &wait);
|
||||
if (extra_count)
|
||||
info->count++;
|
||||
info->blocked_open--;
|
||||
info->port.count++;
|
||||
info->port.blocked_open--;
|
||||
#ifdef SERIAL_DEBUG_OPEN
|
||||
printk("block_til_ready after blocking: ttyS%d, count = %d\n",
|
||||
info->line, info->count);
|
||||
info->line, info->port.count);
|
||||
#endif
|
||||
if (retval)
|
||||
return retval;
|
||||
info->flags |= ASYNC_NORMAL_ACTIVE;
|
||||
info->port.flags |= ASYNC_NORMAL_ACTIVE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -4086,24 +4074,24 @@ rs_open(struct tty_struct *tty, struct file * filp)
|
||||
|
||||
#ifdef SERIAL_DEBUG_OPEN
|
||||
printk("[%d] rs_open %s, count = %d\n", current->pid, tty->name,
|
||||
info->count);
|
||||
info->port.count);
|
||||
#endif
|
||||
|
||||
info->count++;
|
||||
info->port.count++;
|
||||
tty->driver_data = info;
|
||||
info->port.tty = tty;
|
||||
|
||||
info->port.low_latency = !!(info->flags & ASYNC_LOW_LATENCY);
|
||||
info->port.low_latency = !!(info->port.flags & ASYNC_LOW_LATENCY);
|
||||
|
||||
/*
|
||||
* If the port is in the middle of closing, bail out now
|
||||
*/
|
||||
if (tty_hung_up_p(filp) ||
|
||||
(info->flags & ASYNC_CLOSING)) {
|
||||
wait_event_interruptible_tty(tty, info->close_wait,
|
||||
!(info->flags & ASYNC_CLOSING));
|
||||
(info->port.flags & ASYNC_CLOSING)) {
|
||||
wait_event_interruptible_tty(tty, info->port.close_wait,
|
||||
!(info->port.flags & ASYNC_CLOSING));
|
||||
#ifdef SERIAL_DO_RESTART
|
||||
return ((info->flags & ASYNC_HUP_NOTIFY) ?
|
||||
return ((info->port.flags & ASYNC_HUP_NOTIFY) ?
|
||||
-EAGAIN : -ERESTARTSYS);
|
||||
#else
|
||||
return -EAGAIN;
|
||||
@ -4113,7 +4101,7 @@ rs_open(struct tty_struct *tty, struct file * filp)
|
||||
/*
|
||||
* If DMA is enabled try to allocate the irq's.
|
||||
*/
|
||||
if (info->count == 1) {
|
||||
if (info->port.count == 1) {
|
||||
allocated_resources = 1;
|
||||
if (info->dma_in_enabled) {
|
||||
if (request_irq(info->dma_in_irq_nbr,
|
||||
@ -4186,7 +4174,7 @@ rs_open(struct tty_struct *tty, struct file * filp)
|
||||
if (allocated_resources)
|
||||
deinit_port(info);
|
||||
|
||||
/* FIXME Decrease count info->count here too? */
|
||||
/* FIXME Decrease count info->port.count here too? */
|
||||
return retval;
|
||||
}
|
||||
|
||||
@ -4203,7 +4191,7 @@ rs_open(struct tty_struct *tty, struct file * filp)
|
||||
return retval;
|
||||
}
|
||||
|
||||
if ((info->count == 1) && (info->flags & ASYNC_SPLIT_TERMIOS)) {
|
||||
if ((info->port.count == 1) && (info->port.flags & ASYNC_SPLIT_TERMIOS)) {
|
||||
tty->termios = info->normal_termios;
|
||||
change_speed(info);
|
||||
}
|
||||
@ -4256,9 +4244,6 @@ static void seq_line_info(struct seq_file *m, struct e100_serial *info)
|
||||
if (info->port.tty->stopped)
|
||||
seq_printf(m, " stopped:%i",
|
||||
(int)info->port.tty->stopped);
|
||||
if (info->port.tty->hw_stopped)
|
||||
seq_printf(m, " hw_stopped:%i",
|
||||
(int)info->port.tty->hw_stopped);
|
||||
}
|
||||
|
||||
{
|
||||
@ -4455,16 +4440,9 @@ static int __init rs_init(void)
|
||||
info->forced_eop = 0;
|
||||
info->baud_base = DEF_BAUD_BASE;
|
||||
info->custom_divisor = 0;
|
||||
info->flags = 0;
|
||||
info->close_delay = 5*HZ/10;
|
||||
info->closing_wait = 30*HZ;
|
||||
info->x_char = 0;
|
||||
info->event = 0;
|
||||
info->count = 0;
|
||||
info->blocked_open = 0;
|
||||
info->normal_termios = driver->init_termios;
|
||||
init_waitqueue_head(&info->open_wait);
|
||||
init_waitqueue_head(&info->close_wait);
|
||||
info->xmit.buf = NULL;
|
||||
info->xmit.tail = info->xmit.head = 0;
|
||||
info->first_recv_buffer = info->last_recv_buffer = NULL;
|
||||
|
@ -53,8 +53,6 @@ struct e100_serial {
|
||||
volatile u8 *icmdadr; /* adr to R_DMA_CHx_CMD */
|
||||
volatile u32 *idescradr; /* adr to R_DMA_CHx_DESCR */
|
||||
|
||||
int flags; /* defined in tty.h */
|
||||
|
||||
u8 rx_ctrl; /* shadow for R_SERIALx_REC_CTRL */
|
||||
u8 tx_ctrl; /* shadow for R_SERIALx_TR_CTRL */
|
||||
u8 iseteop; /* bit number for R_SET_EOP for the input dma */
|
||||
@ -88,19 +86,10 @@ struct e100_serial {
|
||||
|
||||
volatile int tr_running; /* 1 if output is running */
|
||||
|
||||
struct tty_struct *tty;
|
||||
int read_status_mask;
|
||||
int ignore_status_mask;
|
||||
int x_char; /* xon/xoff character */
|
||||
int close_delay;
|
||||
unsigned short closing_wait;
|
||||
unsigned short closing_wait2;
|
||||
unsigned long event;
|
||||
unsigned long last_active;
|
||||
int line;
|
||||
int type; /* PORT_ETRAX */
|
||||
int count; /* # of fd on device */
|
||||
int blocked_open; /* # of blocked opens */
|
||||
struct circ_buf xmit;
|
||||
struct etrax_recv_buffer *first_recv_buffer;
|
||||
struct etrax_recv_buffer *last_recv_buffer;
|
||||
@ -110,9 +99,6 @@ struct e100_serial {
|
||||
struct work_struct work;
|
||||
struct async_icount icount; /* error-statistics etc.*/
|
||||
struct ktermios normal_termios;
|
||||
struct ktermios callout_termios;
|
||||
wait_queue_head_t open_wait;
|
||||
wait_queue_head_t close_wait;
|
||||
|
||||
unsigned long char_time_usec; /* The time for 1 char, in usecs */
|
||||
unsigned long flush_time_usec; /* How often we should flush */
|
||||
|
@ -1415,8 +1415,7 @@ static int icom_alloc_adapter(struct icom_adapter
|
||||
struct icom_adapter *cur_adapter_entry;
|
||||
struct list_head *tmp;
|
||||
|
||||
icom_adapter = (struct icom_adapter *)
|
||||
kzalloc(sizeof(struct icom_adapter), GFP_KERNEL);
|
||||
icom_adapter = kzalloc(sizeof(struct icom_adapter), GFP_KERNEL);
|
||||
|
||||
if (!icom_adapter) {
|
||||
return -ENOMEM;
|
||||
|
@ -269,23 +269,6 @@ static void mrdy_assert(struct ifx_spi_device *ifx_dev)
|
||||
mrdy_set_high(ifx_dev);
|
||||
}
|
||||
|
||||
/**
|
||||
* ifx_spi_hangup - hang up an IFX device
|
||||
* @ifx_dev: our SPI device
|
||||
*
|
||||
* Hang up the tty attached to the IFX device if one is currently
|
||||
* open. If not take no action
|
||||
*/
|
||||
static void ifx_spi_ttyhangup(struct ifx_spi_device *ifx_dev)
|
||||
{
|
||||
struct tty_port *pport = &ifx_dev->tty_port;
|
||||
struct tty_struct *tty = tty_port_tty_get(pport);
|
||||
if (tty) {
|
||||
tty_hangup(tty);
|
||||
tty_kref_put(tty);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* ifx_spi_timeout - SPI timeout
|
||||
* @arg: our SPI device
|
||||
@ -298,7 +281,7 @@ static void ifx_spi_timeout(unsigned long arg)
|
||||
struct ifx_spi_device *ifx_dev = (struct ifx_spi_device *)arg;
|
||||
|
||||
dev_warn(&ifx_dev->spi_dev->dev, "*** SPI Timeout ***");
|
||||
ifx_spi_ttyhangup(ifx_dev);
|
||||
tty_port_tty_hangup(&ifx_dev->tty_port, false);
|
||||
mrdy_set_low(ifx_dev);
|
||||
clear_bit(IFX_SPI_STATE_TIMER_PENDING, &ifx_dev->flags);
|
||||
}
|
||||
@ -442,25 +425,6 @@ static void ifx_spi_setup_spi_header(unsigned char *txbuffer, int tx_count,
|
||||
txbuffer[1] |= (more << IFX_SPI_MORE_BIT) & IFX_SPI_MORE_MASK;
|
||||
}
|
||||
|
||||
/**
|
||||
* ifx_spi_wakeup_serial - SPI space made
|
||||
* @port_data: our SPI device
|
||||
*
|
||||
* We have emptied the FIFO enough that we want to get more data
|
||||
* queued into it. Poke the line discipline via tty_wakeup so that
|
||||
* it will feed us more bits
|
||||
*/
|
||||
static void ifx_spi_wakeup_serial(struct ifx_spi_device *ifx_dev)
|
||||
{
|
||||
struct tty_struct *tty;
|
||||
|
||||
tty = tty_port_tty_get(&ifx_dev->tty_port);
|
||||
if (!tty)
|
||||
return;
|
||||
tty_wakeup(tty);
|
||||
tty_kref_put(tty);
|
||||
}
|
||||
|
||||
/**
|
||||
* ifx_spi_prepare_tx_buffer - prepare transmit frame
|
||||
* @ifx_dev: our SPI device
|
||||
@ -506,7 +470,7 @@ static int ifx_spi_prepare_tx_buffer(struct ifx_spi_device *ifx_dev)
|
||||
tx_count += temp_count;
|
||||
if (temp_count == queue_length)
|
||||
/* poke port to get more data */
|
||||
ifx_spi_wakeup_serial(ifx_dev);
|
||||
tty_port_tty_wakeup(&ifx_dev->tty_port);
|
||||
else /* more data in port, use next SPI message */
|
||||
ifx_dev->spi_more = 1;
|
||||
}
|
||||
@ -683,8 +647,6 @@ static void ifx_spi_insert_flip_string(struct ifx_spi_device *ifx_dev,
|
||||
static void ifx_spi_complete(void *ctx)
|
||||
{
|
||||
struct ifx_spi_device *ifx_dev = ctx;
|
||||
struct tty_struct *tty;
|
||||
struct tty_ldisc *ldisc = NULL;
|
||||
int length;
|
||||
int actual_length;
|
||||
unsigned char more;
|
||||
@ -762,15 +724,7 @@ complete_exit:
|
||||
*/
|
||||
ifx_spi_power_state_clear(ifx_dev,
|
||||
IFX_SPI_POWER_DATA_PENDING);
|
||||
tty = tty_port_tty_get(&ifx_dev->tty_port);
|
||||
if (tty) {
|
||||
ldisc = tty_ldisc_ref(tty);
|
||||
if (ldisc) {
|
||||
ldisc->ops->write_wakeup(tty);
|
||||
tty_ldisc_deref(ldisc);
|
||||
}
|
||||
tty_kref_put(tty);
|
||||
}
|
||||
tty_port_tty_wakeup(&ifx_dev->tty_port);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -962,7 +916,7 @@ static irqreturn_t ifx_spi_reset_interrupt(int irq, void *dev)
|
||||
set_bit(MR_INPROGRESS, &ifx_dev->mdm_reset_state);
|
||||
if (!solreset) {
|
||||
/* unsolicited reset */
|
||||
ifx_spi_ttyhangup(ifx_dev);
|
||||
tty_port_tty_hangup(&ifx_dev->tty_port, false);
|
||||
}
|
||||
} else {
|
||||
/* exited reset */
|
||||
@ -1324,30 +1278,6 @@ static void ifx_spi_spi_shutdown(struct spi_device *spi)
|
||||
* no hardware to save state for
|
||||
*/
|
||||
|
||||
/**
|
||||
* ifx_spi_spi_suspend - suspend SPI on system suspend
|
||||
* @dev: device being suspended
|
||||
*
|
||||
* Suspend the SPI side. No action needed on Intel MID platforms, may
|
||||
* need extending for other systems.
|
||||
*/
|
||||
static int ifx_spi_spi_suspend(struct spi_device *spi, pm_message_t msg)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* ifx_spi_spi_resume - resume SPI side on system resume
|
||||
* @dev: device being suspended
|
||||
*
|
||||
* Suspend the SPI side. No action needed on Intel MID platforms, may
|
||||
* need extending for other systems.
|
||||
*/
|
||||
static int ifx_spi_spi_resume(struct spi_device *spi)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* ifx_spi_pm_suspend - suspend modem on system suspend
|
||||
* @dev: device being suspended
|
||||
@ -1437,8 +1367,6 @@ static struct spi_driver ifx_spi_driver = {
|
||||
.probe = ifx_spi_spi_probe,
|
||||
.shutdown = ifx_spi_spi_shutdown,
|
||||
.remove = ifx_spi_spi_remove,
|
||||
.suspend = ifx_spi_spi_suspend,
|
||||
.resume = ifx_spi_spi_resume,
|
||||
.id_table = ifx_id_table
|
||||
};
|
||||
|
||||
|
@ -596,12 +596,6 @@ void jsm_input(struct jsm_channel *ch)
|
||||
|
||||
jsm_dbg(READ, &ch->ch_bd->pci_dev, "start 2\n");
|
||||
|
||||
if (data_len <= 0) {
|
||||
spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
|
||||
jsm_dbg(READ, &ch->ch_bd->pci_dev, "jsm_input 1\n");
|
||||
return;
|
||||
}
|
||||
|
||||
len = tty_buffer_request_room(port, data_len);
|
||||
n = len;
|
||||
|
||||
|
@ -778,7 +778,7 @@ static int max3100_probe(struct spi_device *spi)
|
||||
max3100s[i]->spi = spi;
|
||||
max3100s[i]->irq = spi->irq;
|
||||
spin_lock_init(&max3100s[i]->conf_lock);
|
||||
dev_set_drvdata(&spi->dev, max3100s[i]);
|
||||
spi_set_drvdata(spi, max3100s[i]);
|
||||
pdata = spi->dev.platform_data;
|
||||
max3100s[i]->crystal = pdata->crystal;
|
||||
max3100s[i]->loopback = pdata->loopback;
|
||||
@ -819,7 +819,7 @@ static int max3100_probe(struct spi_device *spi)
|
||||
|
||||
static int max3100_remove(struct spi_device *spi)
|
||||
{
|
||||
struct max3100_port *s = dev_get_drvdata(&spi->dev);
|
||||
struct max3100_port *s = spi_get_drvdata(spi);
|
||||
int i;
|
||||
|
||||
mutex_lock(&max3100s_lock);
|
||||
@ -849,11 +849,11 @@ static int max3100_remove(struct spi_device *spi)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
|
||||
static int max3100_suspend(struct spi_device *spi, pm_message_t state)
|
||||
static int max3100_suspend(struct device *dev)
|
||||
{
|
||||
struct max3100_port *s = dev_get_drvdata(&spi->dev);
|
||||
struct max3100_port *s = dev_get_drvdata(dev);
|
||||
|
||||
dev_dbg(&s->spi->dev, "%s\n", __func__);
|
||||
|
||||
@ -874,9 +874,9 @@ static int max3100_suspend(struct spi_device *spi, pm_message_t state)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int max3100_resume(struct spi_device *spi)
|
||||
static int max3100_resume(struct device *dev)
|
||||
{
|
||||
struct max3100_port *s = dev_get_drvdata(&spi->dev);
|
||||
struct max3100_port *s = dev_get_drvdata(dev);
|
||||
|
||||
dev_dbg(&s->spi->dev, "%s\n", __func__);
|
||||
|
||||
@ -894,21 +894,21 @@ static int max3100_resume(struct spi_device *spi)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(max3100_pm_ops, max3100_suspend, max3100_resume);
|
||||
#define MAX3100_PM_OPS (&max3100_pm_ops)
|
||||
|
||||
#else
|
||||
#define max3100_suspend NULL
|
||||
#define max3100_resume NULL
|
||||
#define MAX3100_PM_OPS NULL
|
||||
#endif
|
||||
|
||||
static struct spi_driver max3100_driver = {
|
||||
.driver = {
|
||||
.name = "max3100",
|
||||
.owner = THIS_MODULE,
|
||||
.pm = MAX3100_PM_OPS,
|
||||
},
|
||||
|
||||
.probe = max3100_probe,
|
||||
.remove = max3100_remove,
|
||||
.suspend = max3100_suspend,
|
||||
.resume = max3100_resume,
|
||||
};
|
||||
|
||||
module_spi_driver(max3100_driver);
|
||||
|
@ -881,12 +881,14 @@ static struct uart_ops max310x_ops = {
|
||||
.verify_port = max310x_verify_port,
|
||||
};
|
||||
|
||||
static int max310x_suspend(struct spi_device *spi, pm_message_t state)
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
|
||||
static int max310x_suspend(struct device *dev)
|
||||
{
|
||||
int ret;
|
||||
struct max310x_port *s = dev_get_drvdata(&spi->dev);
|
||||
struct max310x_port *s = dev_get_drvdata(dev);
|
||||
|
||||
dev_dbg(&spi->dev, "Suspend\n");
|
||||
dev_dbg(dev, "Suspend\n");
|
||||
|
||||
ret = uart_suspend_port(&s->uart, &s->port);
|
||||
|
||||
@ -905,11 +907,11 @@ static int max310x_suspend(struct spi_device *spi, pm_message_t state)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int max310x_resume(struct spi_device *spi)
|
||||
static int max310x_resume(struct device *dev)
|
||||
{
|
||||
struct max310x_port *s = dev_get_drvdata(&spi->dev);
|
||||
struct max310x_port *s = dev_get_drvdata(dev);
|
||||
|
||||
dev_dbg(&spi->dev, "Resume\n");
|
||||
dev_dbg(dev, "Resume\n");
|
||||
|
||||
if (s->pdata->suspend)
|
||||
s->pdata->suspend(0);
|
||||
@ -928,6 +930,13 @@ static int max310x_resume(struct spi_device *spi)
|
||||
return uart_resume_port(&s->uart, &s->port);
|
||||
}
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(max310x_pm_ops, max310x_suspend, max310x_resume);
|
||||
#define MAX310X_PM_OPS (&max310x_pm_ops)
|
||||
|
||||
#else
|
||||
#define MAX310X_PM_OPS NULL
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_GPIOLIB
|
||||
static int max310x_gpio_get(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
@ -1242,11 +1251,10 @@ static struct spi_driver max310x_driver = {
|
||||
.driver = {
|
||||
.name = "max310x",
|
||||
.owner = THIS_MODULE,
|
||||
.pm = MAX310X_PM_OPS,
|
||||
},
|
||||
.probe = max310x_probe,
|
||||
.remove = max310x_remove,
|
||||
.suspend = max310x_suspend,
|
||||
.resume = max310x_resume,
|
||||
.id_table = max310x_id_table,
|
||||
};
|
||||
module_spi_driver(max310x_driver);
|
||||
|
@ -743,9 +743,10 @@ static struct uart_driver serial_m3110_reg = {
|
||||
.cons = &serial_m3110_console,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int serial_m3110_suspend(struct spi_device *spi, pm_message_t state)
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int serial_m3110_suspend(struct device *dev)
|
||||
{
|
||||
struct spi_device *spi = to_spi_device(dev);
|
||||
struct uart_max3110 *max = spi_get_drvdata(spi);
|
||||
|
||||
disable_irq(max->irq);
|
||||
@ -754,8 +755,9 @@ static int serial_m3110_suspend(struct spi_device *spi, pm_message_t state)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int serial_m3110_resume(struct spi_device *spi)
|
||||
static int serial_m3110_resume(struct device *dev)
|
||||
{
|
||||
struct spi_device *spi = to_spi_device(dev);
|
||||
struct uart_max3110 *max = spi_get_drvdata(spi);
|
||||
|
||||
max3110_out(max, max->cur_conf);
|
||||
@ -763,9 +765,13 @@ static int serial_m3110_resume(struct spi_device *spi)
|
||||
enable_irq(max->irq);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(serial_m3110_pm_ops, serial_m3110_suspend,
|
||||
serial_m3110_resume);
|
||||
#define SERIAL_M3110_PM_OPS (&serial_m3110_pm_ops)
|
||||
|
||||
#else
|
||||
#define serial_m3110_suspend NULL
|
||||
#define serial_m3110_resume NULL
|
||||
#define SERIAL_M3110_PM_OPS NULL
|
||||
#endif
|
||||
|
||||
static int serial_m3110_probe(struct spi_device *spi)
|
||||
@ -872,11 +878,10 @@ static struct spi_driver uart_max3110_driver = {
|
||||
.driver = {
|
||||
.name = "spi_max3111",
|
||||
.owner = THIS_MODULE,
|
||||
.pm = SERIAL_M3110_PM_OPS,
|
||||
},
|
||||
.probe = serial_m3110_probe,
|
||||
.remove = serial_m3110_remove,
|
||||
.suspend = serial_m3110_suspend,
|
||||
.resume = serial_m3110_resume,
|
||||
};
|
||||
|
||||
static int __init serial_m3110_init(void)
|
||||
|
@ -907,7 +907,6 @@ static void msm_hs_dmov_rx_callback(struct msm_dmov_cmd *cmd_ptr,
|
||||
unsigned int error_f = 0;
|
||||
unsigned long flags;
|
||||
unsigned int flush;
|
||||
struct tty_struct *tty;
|
||||
struct tty_port *port;
|
||||
struct uart_port *uport;
|
||||
struct msm_hs_port *msm_uport;
|
||||
@ -919,7 +918,6 @@ static void msm_hs_dmov_rx_callback(struct msm_dmov_cmd *cmd_ptr,
|
||||
clk_enable(msm_uport->clk);
|
||||
|
||||
port = &uport->state->port;
|
||||
tty = port->tty;
|
||||
|
||||
msm_hs_write(uport, UARTDM_CR_ADDR, STALE_EVENT_DISABLE);
|
||||
|
||||
|
@ -90,13 +90,13 @@ static void smd_tty_notify(void *priv, unsigned event)
|
||||
|
||||
static int smd_tty_port_activate(struct tty_port *tport, struct tty_struct *tty)
|
||||
{
|
||||
struct smd_tty_info *info = container_of(tport, struct smd_tty_info,
|
||||
port);
|
||||
int i, res = 0;
|
||||
int n = tty->index;
|
||||
const char *name = NULL;
|
||||
struct smd_tty_info *info = smd_tty + n;
|
||||
|
||||
for (i = 0; i < smd_tty_channels_len; i++) {
|
||||
if (smd_tty_channels[i].id == n) {
|
||||
if (smd_tty_channels[i].id == tty->index) {
|
||||
name = smd_tty_channels[i].name;
|
||||
break;
|
||||
}
|
||||
@ -117,17 +117,13 @@ static int smd_tty_port_activate(struct tty_port *tport, struct tty_struct *tty)
|
||||
|
||||
static void smd_tty_port_shutdown(struct tty_port *tport)
|
||||
{
|
||||
struct smd_tty_info *info;
|
||||
struct tty_struct *tty = tty_port_tty_get(tport);
|
||||
struct smd_tty_info *info = container_of(tport, struct smd_tty_info,
|
||||
port);
|
||||
|
||||
info = tty->driver_data;
|
||||
if (info->ch) {
|
||||
smd_close(info->ch);
|
||||
info->ch = 0;
|
||||
}
|
||||
|
||||
tty->driver_data = 0;
|
||||
tty_kref_put(tty);
|
||||
}
|
||||
|
||||
static int smd_tty_open(struct tty_struct *tty, struct file *f)
|
||||
|
@ -883,7 +883,7 @@ auart_console_write(struct console *co, const char *str, unsigned int count)
|
||||
unsigned int old_ctrl0, old_ctrl2;
|
||||
unsigned int to = 1000;
|
||||
|
||||
if (co->index > MXS_AUART_PORTS || co->index < 0)
|
||||
if (co->index >= MXS_AUART_PORTS || co->index < 0)
|
||||
return;
|
||||
|
||||
s = auart_port[co->index];
|
||||
@ -1103,7 +1103,7 @@ static int mxs_auart_probe(struct platform_device *pdev)
|
||||
s->port.fifosize = 16;
|
||||
s->port.uartclk = clk_get_rate(s->clk);
|
||||
s->port.type = PORT_IMX;
|
||||
s->port.dev = s->dev = get_device(&pdev->dev);
|
||||
s->port.dev = s->dev = &pdev->dev;
|
||||
|
||||
s->ctrl = 0;
|
||||
|
||||
@ -1134,7 +1134,6 @@ out_free_irq:
|
||||
auart_port[pdev->id] = NULL;
|
||||
free_irq(s->irq, s);
|
||||
out_free_clk:
|
||||
put_device(s->dev);
|
||||
clk_put(s->clk);
|
||||
out_free:
|
||||
kfree(s);
|
||||
@ -1150,7 +1149,6 @@ static int mxs_auart_remove(struct platform_device *pdev)
|
||||
|
||||
auart_port[pdev->id] = NULL;
|
||||
|
||||
put_device(s->dev);
|
||||
clk_put(s->clk);
|
||||
free_irq(s->irq, s);
|
||||
kfree(s);
|
||||
|
@ -14,7 +14,6 @@
|
||||
#include <linux/slab.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/serial_core.h>
|
||||
#include <linux/serial_8250.h>
|
||||
#include <linux/serial_reg.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_irq.h>
|
||||
@ -22,6 +21,8 @@
|
||||
#include <linux/nwpserial.h>
|
||||
#include <linux/clk.h>
|
||||
|
||||
#include "8250/8250.h"
|
||||
|
||||
struct of_serial_info {
|
||||
struct clk *clk;
|
||||
int type;
|
||||
@ -97,6 +98,10 @@ static int of_platform_serial_setup(struct platform_device *ofdev,
|
||||
if (of_property_read_u32(np, "reg-shift", &prop) == 0)
|
||||
port->regshift = prop;
|
||||
|
||||
/* Check for fifo size */
|
||||
if (of_property_read_u32(np, "fifo-size", &prop) == 0)
|
||||
port->fifosize = prop;
|
||||
|
||||
port->irq = irq_of_parse_and_map(np, 0);
|
||||
port->iotype = UPIO_MEM;
|
||||
if (of_property_read_u32(np, "reg-io-width", &prop) == 0) {
|
||||
@ -167,11 +172,17 @@ static int of_platform_serial_probe(struct platform_device *ofdev)
|
||||
#ifdef CONFIG_SERIAL_8250
|
||||
case PORT_8250 ... PORT_MAX_8250:
|
||||
{
|
||||
/* For now the of bindings don't support the extra
|
||||
8250 specific bits */
|
||||
struct uart_8250_port port8250;
|
||||
memset(&port8250, 0, sizeof(port8250));
|
||||
port8250.port = port;
|
||||
|
||||
if (port.fifosize)
|
||||
port8250.capabilities = UART_CAP_FIFO;
|
||||
|
||||
if (of_property_read_bool(ofdev->dev.of_node,
|
||||
"auto-flow-control"))
|
||||
port8250.capabilities |= UART_CAP_AFE;
|
||||
|
||||
ret = serial8250_register_8250_port(&port8250);
|
||||
break;
|
||||
}
|
||||
|
@ -1493,29 +1493,6 @@ static int pch_uart_verify_port(struct uart_port *port,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct uart_ops pch_uart_ops = {
|
||||
.tx_empty = pch_uart_tx_empty,
|
||||
.set_mctrl = pch_uart_set_mctrl,
|
||||
.get_mctrl = pch_uart_get_mctrl,
|
||||
.stop_tx = pch_uart_stop_tx,
|
||||
.start_tx = pch_uart_start_tx,
|
||||
.stop_rx = pch_uart_stop_rx,
|
||||
.enable_ms = pch_uart_enable_ms,
|
||||
.break_ctl = pch_uart_break_ctl,
|
||||
.startup = pch_uart_startup,
|
||||
.shutdown = pch_uart_shutdown,
|
||||
.set_termios = pch_uart_set_termios,
|
||||
/* .pm = pch_uart_pm, Not supported yet */
|
||||
/* .set_wake = pch_uart_set_wake, Not supported yet */
|
||||
.type = pch_uart_type,
|
||||
.release_port = pch_uart_release_port,
|
||||
.request_port = pch_uart_request_port,
|
||||
.config_port = pch_uart_config_port,
|
||||
.verify_port = pch_uart_verify_port
|
||||
};
|
||||
|
||||
#ifdef CONFIG_SERIAL_PCH_UART_CONSOLE
|
||||
|
||||
/*
|
||||
* Wait for transmitter & holding register to empty
|
||||
*/
|
||||
@ -1547,6 +1524,84 @@ static void wait_for_xmitr(struct eg20t_port *up, int bits)
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CONSOLE_POLL
|
||||
/*
|
||||
* Console polling routines for communicate via uart while
|
||||
* in an interrupt or debug context.
|
||||
*/
|
||||
static int pch_uart_get_poll_char(struct uart_port *port)
|
||||
{
|
||||
struct eg20t_port *priv =
|
||||
container_of(port, struct eg20t_port, port);
|
||||
u8 lsr = ioread8(priv->membase + UART_LSR);
|
||||
|
||||
if (!(lsr & UART_LSR_DR))
|
||||
return NO_POLL_CHAR;
|
||||
|
||||
return ioread8(priv->membase + PCH_UART_RBR);
|
||||
}
|
||||
|
||||
|
||||
static void pch_uart_put_poll_char(struct uart_port *port,
|
||||
unsigned char c)
|
||||
{
|
||||
unsigned int ier;
|
||||
struct eg20t_port *priv =
|
||||
container_of(port, struct eg20t_port, port);
|
||||
|
||||
/*
|
||||
* First save the IER then disable the interrupts
|
||||
*/
|
||||
ier = ioread8(priv->membase + UART_IER);
|
||||
pch_uart_hal_disable_interrupt(priv, PCH_UART_HAL_ALL_INT);
|
||||
|
||||
wait_for_xmitr(priv, UART_LSR_THRE);
|
||||
/*
|
||||
* Send the character out.
|
||||
* If a LF, also do CR...
|
||||
*/
|
||||
iowrite8(c, priv->membase + PCH_UART_THR);
|
||||
if (c == 10) {
|
||||
wait_for_xmitr(priv, UART_LSR_THRE);
|
||||
iowrite8(13, priv->membase + PCH_UART_THR);
|
||||
}
|
||||
|
||||
/*
|
||||
* Finally, wait for transmitter to become empty
|
||||
* and restore the IER
|
||||
*/
|
||||
wait_for_xmitr(priv, BOTH_EMPTY);
|
||||
iowrite8(ier, priv->membase + UART_IER);
|
||||
}
|
||||
#endif /* CONFIG_CONSOLE_POLL */
|
||||
|
||||
static struct uart_ops pch_uart_ops = {
|
||||
.tx_empty = pch_uart_tx_empty,
|
||||
.set_mctrl = pch_uart_set_mctrl,
|
||||
.get_mctrl = pch_uart_get_mctrl,
|
||||
.stop_tx = pch_uart_stop_tx,
|
||||
.start_tx = pch_uart_start_tx,
|
||||
.stop_rx = pch_uart_stop_rx,
|
||||
.enable_ms = pch_uart_enable_ms,
|
||||
.break_ctl = pch_uart_break_ctl,
|
||||
.startup = pch_uart_startup,
|
||||
.shutdown = pch_uart_shutdown,
|
||||
.set_termios = pch_uart_set_termios,
|
||||
/* .pm = pch_uart_pm, Not supported yet */
|
||||
/* .set_wake = pch_uart_set_wake, Not supported yet */
|
||||
.type = pch_uart_type,
|
||||
.release_port = pch_uart_release_port,
|
||||
.request_port = pch_uart_request_port,
|
||||
.config_port = pch_uart_config_port,
|
||||
.verify_port = pch_uart_verify_port,
|
||||
#ifdef CONFIG_CONSOLE_POLL
|
||||
.poll_get_char = pch_uart_get_poll_char,
|
||||
.poll_put_char = pch_uart_put_poll_char,
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifdef CONFIG_SERIAL_PCH_UART_CONSOLE
|
||||
|
||||
static void pch_console_putchar(struct uart_port *port, int ch)
|
||||
{
|
||||
struct eg20t_port *priv =
|
||||
@ -1655,7 +1710,7 @@ static struct console pch_console = {
|
||||
#define PCH_CONSOLE (&pch_console)
|
||||
#else
|
||||
#define PCH_CONSOLE NULL
|
||||
#endif
|
||||
#endif /* CONFIG_SERIAL_PCH_UART_CONSOLE */
|
||||
|
||||
static struct uart_driver pch_uart_driver = {
|
||||
.owner = THIS_MODULE,
|
||||
|
@ -39,6 +39,7 @@
|
||||
#include <linux/tty_flip.h>
|
||||
#include <linux/serial_core.h>
|
||||
#include <linux/serial.h>
|
||||
#include <linux/serial_s3c.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/cpufreq.h>
|
||||
@ -46,10 +47,9 @@
|
||||
|
||||
#include <asm/irq.h>
|
||||
|
||||
#include <mach/hardware.h>
|
||||
|
||||
#include <plat/regs-serial.h>
|
||||
#ifdef CONFIG_SAMSUNG_CLOCK
|
||||
#include <plat/clock.h>
|
||||
#endif
|
||||
|
||||
#include "samsung.h"
|
||||
|
||||
@ -446,6 +446,8 @@ static void s3c24xx_serial_shutdown(struct uart_port *port)
|
||||
|
||||
/* Clear pending interrupts and mask all interrupts */
|
||||
if (s3c24xx_serial_has_interrupt_mask(port)) {
|
||||
free_irq(port->irq, ourport);
|
||||
|
||||
wr_regl(port, S3C64XX_UINTP, 0xf);
|
||||
wr_regl(port, S3C64XX_UINTM, 0xf);
|
||||
}
|
||||
@ -505,6 +507,8 @@ static int s3c64xx_serial_startup(struct uart_port *port)
|
||||
dbg("s3c64xx_serial_startup: port=%p (%08lx,%p)\n",
|
||||
port->mapbase, port->membase);
|
||||
|
||||
wr_regl(port, S3C64XX_UINTM, 0xf);
|
||||
|
||||
ret = request_irq(port->irq, s3c64xx_serial_handle_irq, IRQF_SHARED,
|
||||
s3c24xx_serial_portname(port), ourport);
|
||||
if (ret) {
|
||||
@ -894,7 +898,7 @@ console_initcall(s3c24xx_serial_console_init);
|
||||
#define S3C24XX_SERIAL_CONSOLE NULL
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_CONSOLE_POLL
|
||||
#if defined(CONFIG_SERIAL_SAMSUNG_CONSOLE) && defined(CONFIG_CONSOLE_POLL)
|
||||
static int s3c24xx_serial_get_poll_char(struct uart_port *port);
|
||||
static void s3c24xx_serial_put_poll_char(struct uart_port *port,
|
||||
unsigned char c);
|
||||
@ -918,7 +922,7 @@ static struct uart_ops s3c24xx_serial_ops = {
|
||||
.request_port = s3c24xx_serial_request_port,
|
||||
.config_port = s3c24xx_serial_config_port,
|
||||
.verify_port = s3c24xx_serial_verify_port,
|
||||
#ifdef CONFIG_CONSOLE_POLL
|
||||
#if defined(CONFIG_SERIAL_SAMSUNG_CONSOLE) && defined(CONFIG_CONSOLE_POLL)
|
||||
.poll_get_char = s3c24xx_serial_get_poll_char,
|
||||
.poll_put_char = s3c24xx_serial_put_poll_char,
|
||||
#endif
|
||||
@ -1179,6 +1183,7 @@ static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport,
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SAMSUNG_CLOCK
|
||||
static ssize_t s3c24xx_serial_show_clksrc(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
@ -1194,7 +1199,7 @@ static ssize_t s3c24xx_serial_show_clksrc(struct device *dev,
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(clock_source, S_IRUGO, s3c24xx_serial_show_clksrc, NULL);
|
||||
|
||||
#endif
|
||||
|
||||
/* Device driver serial port probe */
|
||||
|
||||
@ -1252,9 +1257,11 @@ static int s3c24xx_serial_probe(struct platform_device *pdev)
|
||||
uart_add_one_port(&s3c24xx_uart_drv, &ourport->port);
|
||||
platform_set_drvdata(pdev, &ourport->port);
|
||||
|
||||
#ifdef CONFIG_SAMSUNG_CLOCK
|
||||
ret = device_create_file(&pdev->dev, &dev_attr_clock_source);
|
||||
if (ret < 0)
|
||||
dev_err(&pdev->dev, "failed to add clock source attr.\n");
|
||||
#endif
|
||||
|
||||
ret = s3c24xx_serial_cpufreq_register(ourport);
|
||||
if (ret < 0)
|
||||
@ -1272,7 +1279,9 @@ static int s3c24xx_serial_remove(struct platform_device *dev)
|
||||
|
||||
if (port) {
|
||||
s3c24xx_serial_cpufreq_deregister(to_ourport(port));
|
||||
#ifdef CONFIG_SAMSUNG_CLOCK
|
||||
device_remove_file(&dev->dev, &dev_attr_clock_source);
|
||||
#endif
|
||||
uart_remove_one_port(&s3c24xx_uart_drv, port);
|
||||
}
|
||||
|
||||
@ -1307,9 +1316,29 @@ static int s3c24xx_serial_resume(struct device *dev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int s3c24xx_serial_resume_noirq(struct device *dev)
|
||||
{
|
||||
struct uart_port *port = s3c24xx_dev_to_port(dev);
|
||||
|
||||
if (port) {
|
||||
/* restore IRQ mask */
|
||||
if (s3c24xx_serial_has_interrupt_mask(port)) {
|
||||
unsigned int uintm = 0xf;
|
||||
if (tx_enabled(port))
|
||||
uintm &= ~S3C64XX_UINTM_TXD_MSK;
|
||||
if (rx_enabled(port))
|
||||
uintm &= ~S3C64XX_UINTM_RXD_MSK;
|
||||
wr_regl(port, S3C64XX_UINTM, uintm);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops s3c24xx_serial_pm_ops = {
|
||||
.suspend = s3c24xx_serial_suspend,
|
||||
.resume = s3c24xx_serial_resume,
|
||||
.resume_noirq = s3c24xx_serial_resume_noirq,
|
||||
};
|
||||
#define SERIAL_SAMSUNG_PM_OPS (&s3c24xx_serial_pm_ops)
|
||||
|
||||
@ -1343,6 +1372,13 @@ s3c24xx_serial_console_txrdy(struct uart_port *port, unsigned int ufcon)
|
||||
return (utrstat & S3C2410_UTRSTAT_TXE) ? 1 : 0;
|
||||
}
|
||||
|
||||
static bool
|
||||
s3c24xx_port_configured(unsigned int ucon)
|
||||
{
|
||||
/* consider the serial port configured if the tx/rx mode set */
|
||||
return (ucon & 0xf) != 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CONSOLE_POLL
|
||||
/*
|
||||
* Console polling routines for writing and reading from the uart while
|
||||
@ -1365,6 +1401,11 @@ static void s3c24xx_serial_put_poll_char(struct uart_port *port,
|
||||
unsigned char c)
|
||||
{
|
||||
unsigned int ufcon = rd_regl(cons_uart, S3C2410_UFCON);
|
||||
unsigned int ucon = rd_regl(cons_uart, S3C2410_UCON);
|
||||
|
||||
/* not possible to xmit on unconfigured port */
|
||||
if (!s3c24xx_port_configured(ucon))
|
||||
return;
|
||||
|
||||
while (!s3c24xx_serial_console_txrdy(port, ufcon))
|
||||
cpu_relax();
|
||||
@ -1377,6 +1418,12 @@ static void
|
||||
s3c24xx_serial_console_putchar(struct uart_port *port, int ch)
|
||||
{
|
||||
unsigned int ufcon = rd_regl(cons_uart, S3C2410_UFCON);
|
||||
unsigned int ucon = rd_regl(cons_uart, S3C2410_UCON);
|
||||
|
||||
/* not possible to xmit on unconfigured port */
|
||||
if (!s3c24xx_port_configured(ucon))
|
||||
return;
|
||||
|
||||
while (!s3c24xx_serial_console_txrdy(port, ufcon))
|
||||
barrier();
|
||||
wr_regb(cons_uart, S3C2410_UTXH, ch);
|
||||
@ -1409,9 +1456,7 @@ s3c24xx_serial_get_options(struct uart_port *port, int *baud,
|
||||
"registers: ulcon=%08x, ucon=%08x, ubdriv=%08x\n",
|
||||
port, ulcon, ucon, ubrdiv);
|
||||
|
||||
if ((ucon & 0xf) != 0) {
|
||||
/* consider the serial port configured if the tx/rx mode set */
|
||||
|
||||
if (s3c24xx_port_configured(ucon)) {
|
||||
switch (ulcon & S3C2410_LCON_CSMASK) {
|
||||
case S3C2410_LCON_CS5:
|
||||
*bits = 5;
|
||||
|
@ -76,7 +76,9 @@ struct s3c24xx_uart_port {
|
||||
#define wr_regb(port, reg, val) __raw_writeb(val, portaddr(port, reg))
|
||||
#define wr_regl(port, reg, val) __raw_writel(val, portaddr(port, reg))
|
||||
|
||||
#ifdef CONFIG_SERIAL_SAMSUNG_DEBUG
|
||||
#if defined(CONFIG_SERIAL_SAMSUNG_DEBUG) && \
|
||||
defined(CONFIG_DEBUG_LL) && \
|
||||
!defined(MODULE)
|
||||
|
||||
extern void printascii(const char *);
|
||||
|
||||
|
@ -27,6 +27,7 @@
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/platform_data/serial-sccnxp.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
|
||||
#define SCCNXP_NAME "uart-sccnxp"
|
||||
#define SCCNXP_MAJOR 204
|
||||
@ -131,6 +132,8 @@ struct sccnxp_port {
|
||||
struct timer_list timer;
|
||||
|
||||
struct sccnxp_pdata pdata;
|
||||
|
||||
struct regulator *regulator;
|
||||
};
|
||||
|
||||
static inline u8 sccnxp_raw_read(void __iomem *base, u8 reg, u8 shift)
|
||||
@ -789,8 +792,6 @@ static int sccnxp_probe(struct platform_device *pdev)
|
||||
return -EADDRNOTAVAIL;
|
||||
}
|
||||
|
||||
dev_set_name(&pdev->dev, SCCNXP_NAME);
|
||||
|
||||
s = devm_kzalloc(&pdev->dev, sizeof(struct sccnxp_port), GFP_KERNEL);
|
||||
if (!s) {
|
||||
dev_err(&pdev->dev, "Error allocating port structure\n");
|
||||
@ -918,6 +919,16 @@ static int sccnxp_probe(struct platform_device *pdev)
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
s->regulator = devm_regulator_get(&pdev->dev, "VCC");
|
||||
if (!IS_ERR(s->regulator)) {
|
||||
ret = regulator_enable(s->regulator);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev,
|
||||
"Failed to enable regulator: %i\n", ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
membase = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (IS_ERR(membase)) {
|
||||
ret = PTR_ERR(membase);
|
||||
@ -967,10 +978,6 @@ static int sccnxp_probe(struct platform_device *pdev)
|
||||
s->imr = 0;
|
||||
sccnxp_write(&s->port[0], SCCNXP_IMR_REG, 0);
|
||||
|
||||
/* Board specific configure */
|
||||
if (s->pdata.init)
|
||||
s->pdata.init();
|
||||
|
||||
if (!s->poll) {
|
||||
ret = devm_request_threaded_irq(&pdev->dev, s->irq, NULL,
|
||||
sccnxp_ist,
|
||||
@ -1011,8 +1018,8 @@ static int sccnxp_remove(struct platform_device *pdev)
|
||||
uart_unregister_driver(&s->uart);
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
|
||||
if (s->pdata.exit)
|
||||
s->pdata.exit();
|
||||
if (!IS_ERR(s->regulator))
|
||||
return regulator_disable(s->regulator);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include <linux/dmaengine.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/dmapool.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/module.h>
|
||||
@ -1301,11 +1302,9 @@ static int tegra_uart_probe(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
u->mapbase = resource->start;
|
||||
u->membase = devm_request_and_ioremap(&pdev->dev, resource);
|
||||
if (!u->membase) {
|
||||
dev_err(&pdev->dev, "memregion/iomap address req failed\n");
|
||||
return -EADDRNOTAVAIL;
|
||||
}
|
||||
u->membase = devm_ioremap_resource(&pdev->dev, resource);
|
||||
if (IS_ERR(u->membase))
|
||||
return PTR_ERR(u->membase);
|
||||
|
||||
tup->uart_clk = devm_clk_get(&pdev->dev, NULL);
|
||||
if (IS_ERR(tup->uart_clk)) {
|
||||
|
@ -1941,6 +1941,8 @@ int uart_suspend_port(struct uart_driver *drv, struct uart_port *uport)
|
||||
mutex_unlock(&port->mutex);
|
||||
return 0;
|
||||
}
|
||||
put_device(tty_dev);
|
||||
|
||||
if (console_suspend_enabled || !uart_console(uport))
|
||||
uport->suspended = 1;
|
||||
|
||||
@ -2006,9 +2008,11 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *uport)
|
||||
disable_irq_wake(uport->irq);
|
||||
uport->irq_wake = 0;
|
||||
}
|
||||
put_device(tty_dev);
|
||||
mutex_unlock(&port->mutex);
|
||||
return 0;
|
||||
}
|
||||
put_device(tty_dev);
|
||||
uport->suspended = 0;
|
||||
|
||||
/*
|
||||
|
@ -15,8 +15,6 @@
|
||||
defined(CONFIG_CPU_SUBTYPE_SH7720) || \
|
||||
defined(CONFIG_CPU_SUBTYPE_SH7721) || \
|
||||
defined(CONFIG_ARCH_SH73A0) || \
|
||||
defined(CONFIG_ARCH_SH7367) || \
|
||||
defined(CONFIG_ARCH_SH7377) || \
|
||||
defined(CONFIG_ARCH_SH7372) || \
|
||||
defined(CONFIG_ARCH_R8A7740)
|
||||
|
||||
|
@ -758,7 +758,7 @@ static struct of_device_id sirfsoc_uart_ids[] = {
|
||||
{ .compatible = "sirf,marco-uart", },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, sirfsoc_serial_of_match);
|
||||
MODULE_DEVICE_TABLE(of, sirfsoc_uart_ids);
|
||||
|
||||
static struct platform_driver sirfsoc_uart_driver = {
|
||||
.probe = sirfsoc_uart_probe,
|
||||
|
@ -203,7 +203,7 @@ receive_chars(struct uart_sunsab_port *up,
|
||||
flag = TTY_FRAME;
|
||||
}
|
||||
|
||||
if (uart_handle_sysrq_char(&up->port, ch))
|
||||
if (uart_handle_sysrq_char(&up->port, ch) || !port)
|
||||
continue;
|
||||
|
||||
if ((stat->sreg.isr0 & (up->port.ignore_status_mask & 0xff)) == 0 &&
|
||||
|
@ -388,7 +388,7 @@ sunzilog_receive_chars(struct uart_sunzilog_port *up,
|
||||
else if (r1 & CRC_ERR)
|
||||
flag = TTY_FRAME;
|
||||
}
|
||||
if (uart_handle_sysrq_char(&up->port, ch))
|
||||
if (uart_handle_sysrq_char(&up->port, ch) || !port)
|
||||
continue;
|
||||
|
||||
if (up->port.ignore_status_mask == 0xff ||
|
||||
|
@ -35,6 +35,7 @@
|
||||
#include <linux/clk.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/err.h>
|
||||
|
||||
/*
|
||||
* UART Register offsets
|
||||
@ -585,9 +586,9 @@ static int vt8500_serial_probe(struct platform_device *pdev)
|
||||
if (!vt8500_port)
|
||||
return -ENOMEM;
|
||||
|
||||
vt8500_port->uart.membase = devm_request_and_ioremap(&pdev->dev, mmres);
|
||||
if (!vt8500_port->uart.membase)
|
||||
return -EADDRNOTAVAIL;
|
||||
vt8500_port->uart.membase = devm_ioremap_resource(&pdev->dev, mmres);
|
||||
if (IS_ERR(vt8500_port->uart.membase))
|
||||
return PTR_ERR(vt8500_port->uart.membase);
|
||||
|
||||
vt8500_port->clk = of_clk_get(pdev->dev.of_node, 0);
|
||||
if (IS_ERR(vt8500_port->clk)) {
|
||||
|
@ -585,9 +585,6 @@ static int xuartps_startup(struct uart_port *port)
|
||||
xuartps_writel(XUARTPS_IXR_TXEMPTY | XUARTPS_IXR_PARITY |
|
||||
XUARTPS_IXR_FRAMING | XUARTPS_IXR_OVERRUN |
|
||||
XUARTPS_IXR_RXTRIG | XUARTPS_IXR_TOUT, XUARTPS_IER_OFFSET);
|
||||
xuartps_writel(~(XUARTPS_IXR_TXEMPTY | XUARTPS_IXR_PARITY |
|
||||
XUARTPS_IXR_FRAMING | XUARTPS_IXR_OVERRUN |
|
||||
XUARTPS_IXR_RXTRIG | XUARTPS_IXR_TOUT), XUARTPS_IDR_OFFSET);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
@ -1058,9 +1058,6 @@ static void mgsl_bh_handler(struct work_struct *work)
|
||||
container_of(work, struct mgsl_struct, task);
|
||||
int action;
|
||||
|
||||
if (!info)
|
||||
return;
|
||||
|
||||
if ( debug_level >= DEBUG_LEVEL_BH )
|
||||
printk( "%s(%d):mgsl_bh_handler(%s) entry\n",
|
||||
__FILE__,__LINE__,info->device_name);
|
||||
@ -3311,7 +3308,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
|
||||
port->blocked_open++;
|
||||
|
||||
while (1) {
|
||||
if (tty->termios.c_cflag & CBAUD)
|
||||
if (C_BAUD(tty) && test_bit(ASYNCB_INITIALIZED, &port->flags))
|
||||
tty_port_raise_dtr_rts(port);
|
||||
|
||||
set_current_state(TASK_INTERRUPTIBLE);
|
||||
|
@ -3308,7 +3308,7 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp,
|
||||
port->blocked_open++;
|
||||
|
||||
while (1) {
|
||||
if ((tty->termios.c_cflag & CBAUD))
|
||||
if (C_BAUD(tty) && test_bit(ASYNCB_INITIALIZED, &port->flags))
|
||||
tty_port_raise_dtr_rts(port);
|
||||
|
||||
set_current_state(TASK_INTERRUPTIBLE);
|
||||
|
@ -3329,7 +3329,7 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp,
|
||||
port->blocked_open++;
|
||||
|
||||
while (1) {
|
||||
if (tty->termios.c_cflag & CBAUD)
|
||||
if (C_BAUD(tty) && test_bit(ASYNCB_INITIALIZED, &port->flags))
|
||||
tty_port_raise_dtr_rts(port);
|
||||
|
||||
set_current_state(TASK_INTERRUPTIBLE);
|
||||
|
@ -101,7 +101,7 @@ static void sysrq_handle_SAK(int key)
|
||||
}
|
||||
static struct sysrq_key_op sysrq_SAK_op = {
|
||||
.handler = sysrq_handle_SAK,
|
||||
.help_msg = "saK",
|
||||
.help_msg = "sak(k)",
|
||||
.action_msg = "SAK",
|
||||
.enable_mask = SYSRQ_ENABLE_KEYBOARD,
|
||||
};
|
||||
@ -117,7 +117,7 @@ static void sysrq_handle_unraw(int key)
|
||||
|
||||
static struct sysrq_key_op sysrq_unraw_op = {
|
||||
.handler = sysrq_handle_unraw,
|
||||
.help_msg = "unRaw",
|
||||
.help_msg = "unraw(r)",
|
||||
.action_msg = "Keyboard mode set to system default",
|
||||
.enable_mask = SYSRQ_ENABLE_KEYBOARD,
|
||||
};
|
||||
@ -135,7 +135,7 @@ static void sysrq_handle_crash(int key)
|
||||
}
|
||||
static struct sysrq_key_op sysrq_crash_op = {
|
||||
.handler = sysrq_handle_crash,
|
||||
.help_msg = "Crash",
|
||||
.help_msg = "crash(c)",
|
||||
.action_msg = "Trigger a crash",
|
||||
.enable_mask = SYSRQ_ENABLE_DUMP,
|
||||
};
|
||||
@ -148,7 +148,7 @@ static void sysrq_handle_reboot(int key)
|
||||
}
|
||||
static struct sysrq_key_op sysrq_reboot_op = {
|
||||
.handler = sysrq_handle_reboot,
|
||||
.help_msg = "reBoot",
|
||||
.help_msg = "reboot(b)",
|
||||
.action_msg = "Resetting",
|
||||
.enable_mask = SYSRQ_ENABLE_BOOT,
|
||||
};
|
||||
@ -159,7 +159,7 @@ static void sysrq_handle_sync(int key)
|
||||
}
|
||||
static struct sysrq_key_op sysrq_sync_op = {
|
||||
.handler = sysrq_handle_sync,
|
||||
.help_msg = "Sync",
|
||||
.help_msg = "sync(s)",
|
||||
.action_msg = "Emergency Sync",
|
||||
.enable_mask = SYSRQ_ENABLE_SYNC,
|
||||
};
|
||||
@ -171,7 +171,7 @@ static void sysrq_handle_show_timers(int key)
|
||||
|
||||
static struct sysrq_key_op sysrq_show_timers_op = {
|
||||
.handler = sysrq_handle_show_timers,
|
||||
.help_msg = "show-all-timers(Q)",
|
||||
.help_msg = "show-all-timers(q)",
|
||||
.action_msg = "Show clockevent devices & pending hrtimers (no others)",
|
||||
};
|
||||
|
||||
@ -181,7 +181,7 @@ static void sysrq_handle_mountro(int key)
|
||||
}
|
||||
static struct sysrq_key_op sysrq_mountro_op = {
|
||||
.handler = sysrq_handle_mountro,
|
||||
.help_msg = "Unmount",
|
||||
.help_msg = "unmount(u)",
|
||||
.action_msg = "Emergency Remount R/O",
|
||||
.enable_mask = SYSRQ_ENABLE_REMOUNT,
|
||||
};
|
||||
@ -194,7 +194,7 @@ static void sysrq_handle_showlocks(int key)
|
||||
|
||||
static struct sysrq_key_op sysrq_showlocks_op = {
|
||||
.handler = sysrq_handle_showlocks,
|
||||
.help_msg = "show-all-locks(D)",
|
||||
.help_msg = "show-all-locks(d)",
|
||||
.action_msg = "Show Locks Held",
|
||||
};
|
||||
#else
|
||||
@ -245,7 +245,7 @@ static void sysrq_handle_showallcpus(int key)
|
||||
|
||||
static struct sysrq_key_op sysrq_showallcpus_op = {
|
||||
.handler = sysrq_handle_showallcpus,
|
||||
.help_msg = "show-backtrace-all-active-cpus(L)",
|
||||
.help_msg = "show-backtrace-all-active-cpus(l)",
|
||||
.action_msg = "Show backtrace of all active CPUs",
|
||||
.enable_mask = SYSRQ_ENABLE_DUMP,
|
||||
};
|
||||
@ -260,7 +260,7 @@ static void sysrq_handle_showregs(int key)
|
||||
}
|
||||
static struct sysrq_key_op sysrq_showregs_op = {
|
||||
.handler = sysrq_handle_showregs,
|
||||
.help_msg = "show-registers(P)",
|
||||
.help_msg = "show-registers(p)",
|
||||
.action_msg = "Show Regs",
|
||||
.enable_mask = SYSRQ_ENABLE_DUMP,
|
||||
};
|
||||
@ -271,7 +271,7 @@ static void sysrq_handle_showstate(int key)
|
||||
}
|
||||
static struct sysrq_key_op sysrq_showstate_op = {
|
||||
.handler = sysrq_handle_showstate,
|
||||
.help_msg = "show-task-states(T)",
|
||||
.help_msg = "show-task-states(t)",
|
||||
.action_msg = "Show State",
|
||||
.enable_mask = SYSRQ_ENABLE_DUMP,
|
||||
};
|
||||
@ -282,7 +282,7 @@ static void sysrq_handle_showstate_blocked(int key)
|
||||
}
|
||||
static struct sysrq_key_op sysrq_showstate_blocked_op = {
|
||||
.handler = sysrq_handle_showstate_blocked,
|
||||
.help_msg = "show-blocked-tasks(W)",
|
||||
.help_msg = "show-blocked-tasks(w)",
|
||||
.action_msg = "Show Blocked State",
|
||||
.enable_mask = SYSRQ_ENABLE_DUMP,
|
||||
};
|
||||
@ -296,7 +296,7 @@ static void sysrq_ftrace_dump(int key)
|
||||
}
|
||||
static struct sysrq_key_op sysrq_ftrace_dump_op = {
|
||||
.handler = sysrq_ftrace_dump,
|
||||
.help_msg = "dump-ftrace-buffer(Z)",
|
||||
.help_msg = "dump-ftrace-buffer(z)",
|
||||
.action_msg = "Dump ftrace buffer",
|
||||
.enable_mask = SYSRQ_ENABLE_DUMP,
|
||||
};
|
||||
@ -310,7 +310,7 @@ static void sysrq_handle_showmem(int key)
|
||||
}
|
||||
static struct sysrq_key_op sysrq_showmem_op = {
|
||||
.handler = sysrq_handle_showmem,
|
||||
.help_msg = "show-memory-usage(M)",
|
||||
.help_msg = "show-memory-usage(m)",
|
||||
.action_msg = "Show Memory",
|
||||
.enable_mask = SYSRQ_ENABLE_DUMP,
|
||||
};
|
||||
@ -341,7 +341,7 @@ static void sysrq_handle_term(int key)
|
||||
}
|
||||
static struct sysrq_key_op sysrq_term_op = {
|
||||
.handler = sysrq_handle_term,
|
||||
.help_msg = "terminate-all-tasks(E)",
|
||||
.help_msg = "terminate-all-tasks(e)",
|
||||
.action_msg = "Terminate All Tasks",
|
||||
.enable_mask = SYSRQ_ENABLE_SIGNAL,
|
||||
};
|
||||
@ -360,7 +360,7 @@ static void sysrq_handle_moom(int key)
|
||||
}
|
||||
static struct sysrq_key_op sysrq_moom_op = {
|
||||
.handler = sysrq_handle_moom,
|
||||
.help_msg = "memory-full-oom-kill(F)",
|
||||
.help_msg = "memory-full-oom-kill(f)",
|
||||
.action_msg = "Manual OOM execution",
|
||||
.enable_mask = SYSRQ_ENABLE_SIGNAL,
|
||||
};
|
||||
@ -372,7 +372,7 @@ static void sysrq_handle_thaw(int key)
|
||||
}
|
||||
static struct sysrq_key_op sysrq_thaw_op = {
|
||||
.handler = sysrq_handle_thaw,
|
||||
.help_msg = "thaw-filesystems(J)",
|
||||
.help_msg = "thaw-filesystems(j)",
|
||||
.action_msg = "Emergency Thaw of all frozen filesystems",
|
||||
.enable_mask = SYSRQ_ENABLE_SIGNAL,
|
||||
};
|
||||
@ -385,7 +385,7 @@ static void sysrq_handle_kill(int key)
|
||||
}
|
||||
static struct sysrq_key_op sysrq_kill_op = {
|
||||
.handler = sysrq_handle_kill,
|
||||
.help_msg = "kill-all-tasks(I)",
|
||||
.help_msg = "kill-all-tasks(i)",
|
||||
.action_msg = "Kill All Tasks",
|
||||
.enable_mask = SYSRQ_ENABLE_SIGNAL,
|
||||
};
|
||||
@ -396,7 +396,7 @@ static void sysrq_handle_unrt(int key)
|
||||
}
|
||||
static struct sysrq_key_op sysrq_unrt_op = {
|
||||
.handler = sysrq_handle_unrt,
|
||||
.help_msg = "nice-all-RT-tasks(N)",
|
||||
.help_msg = "nice-all-RT-tasks(n)",
|
||||
.action_msg = "Nice All RT Tasks",
|
||||
.enable_mask = SYSRQ_ENABLE_RTNICE,
|
||||
};
|
||||
|
@ -449,11 +449,6 @@ static void flush_to_ldisc(struct work_struct *work)
|
||||
tty_buffer_free(port, head);
|
||||
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(TTYP_FLUSHPENDING, &port->iflags))
|
||||
break;
|
||||
if (!tty->receive_room)
|
||||
break;
|
||||
if (count > tty->receive_room)
|
||||
@ -465,17 +460,20 @@ static void flush_to_ldisc(struct work_struct *work)
|
||||
disc->ops->receive_buf(tty, char_buf,
|
||||
flag_buf, count);
|
||||
spin_lock_irqsave(&buf->lock, flags);
|
||||
/* Ldisc or user is trying to flush the buffers.
|
||||
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(TTYP_FLUSHPENDING, &port->iflags)) {
|
||||
__tty_buffer_flush(port);
|
||||
clear_bit(TTYP_FLUSHPENDING, &port->iflags);
|
||||
wake_up(&tty->read_wait);
|
||||
break;
|
||||
}
|
||||
}
|
||||
clear_bit(TTYP_FLUSHING, &port->iflags);
|
||||
}
|
||||
|
||||
/* 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(TTYP_FLUSHPENDING, &port->iflags)) {
|
||||
__tty_buffer_flush(port);
|
||||
clear_bit(TTYP_FLUSHPENDING, &port->iflags);
|
||||
wake_up(&tty->read_wait);
|
||||
}
|
||||
spin_unlock_irqrestore(&buf->lock, flags);
|
||||
|
||||
tty_ldisc_deref(disc);
|
||||
|
@ -532,6 +532,60 @@ void tty_wakeup(struct tty_struct *tty)
|
||||
|
||||
EXPORT_SYMBOL_GPL(tty_wakeup);
|
||||
|
||||
/**
|
||||
* tty_signal_session_leader - sends SIGHUP to session leader
|
||||
* @tty controlling tty
|
||||
* @exit_session if non-zero, signal all foreground group processes
|
||||
*
|
||||
* Send SIGHUP and SIGCONT to the session leader and its process group.
|
||||
* Optionally, signal all processes in the foreground process group.
|
||||
*
|
||||
* Returns the number of processes in the session with this tty
|
||||
* as their controlling terminal. This value is used to drop
|
||||
* tty references for those processes.
|
||||
*/
|
||||
static int tty_signal_session_leader(struct tty_struct *tty, int exit_session)
|
||||
{
|
||||
struct task_struct *p;
|
||||
int refs = 0;
|
||||
struct pid *tty_pgrp = NULL;
|
||||
|
||||
read_lock(&tasklist_lock);
|
||||
if (tty->session) {
|
||||
do_each_pid_task(tty->session, PIDTYPE_SID, p) {
|
||||
spin_lock_irq(&p->sighand->siglock);
|
||||
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;
|
||||
}
|
||||
__group_send_sig_info(SIGHUP, SEND_SIG_PRIV, p);
|
||||
__group_send_sig_info(SIGCONT, SEND_SIG_PRIV, p);
|
||||
put_pid(p->signal->tty_old_pgrp); /* A noop */
|
||||
spin_lock(&tty->ctrl_lock);
|
||||
tty_pgrp = get_pid(tty->pgrp);
|
||||
if (tty->pgrp)
|
||||
p->signal->tty_old_pgrp = get_pid(tty->pgrp);
|
||||
spin_unlock(&tty->ctrl_lock);
|
||||
spin_unlock_irq(&p->sighand->siglock);
|
||||
} while_each_pid_task(tty->session, PIDTYPE_SID, p);
|
||||
}
|
||||
read_unlock(&tasklist_lock);
|
||||
|
||||
if (tty_pgrp) {
|
||||
if (exit_session)
|
||||
kill_pgrp(tty_pgrp, SIGHUP, exit_session);
|
||||
put_pid(tty_pgrp);
|
||||
}
|
||||
|
||||
return refs;
|
||||
}
|
||||
|
||||
/**
|
||||
* __tty_hangup - actual handler for hangup events
|
||||
* @work: tty device
|
||||
@ -554,15 +608,13 @@ EXPORT_SYMBOL_GPL(tty_wakeup);
|
||||
* tasklist_lock to walk task list for hangup event
|
||||
* ->siglock to protect ->signal/->sighand
|
||||
*/
|
||||
static void __tty_hangup(struct tty_struct *tty)
|
||||
static void __tty_hangup(struct tty_struct *tty, int exit_session)
|
||||
{
|
||||
struct file *cons_filp = NULL;
|
||||
struct file *filp, *f = NULL;
|
||||
struct task_struct *p;
|
||||
struct tty_file_private *priv;
|
||||
int closecount = 0, n;
|
||||
unsigned long flags;
|
||||
int refs = 0;
|
||||
int refs;
|
||||
|
||||
if (!tty)
|
||||
return;
|
||||
@ -599,39 +651,18 @@ static void __tty_hangup(struct tty_struct *tty)
|
||||
}
|
||||
spin_unlock(&tty_files_lock);
|
||||
|
||||
refs = tty_signal_session_leader(tty, exit_session);
|
||||
/* Account for the p->signal references we killed */
|
||||
while (refs--)
|
||||
tty_kref_put(tty);
|
||||
|
||||
/*
|
||||
* it drops BTM and thus races with reopen
|
||||
* we protect the race by TTY_HUPPING
|
||||
*/
|
||||
tty_ldisc_hangup(tty);
|
||||
|
||||
read_lock(&tasklist_lock);
|
||||
if (tty->session) {
|
||||
do_each_pid_task(tty->session, PIDTYPE_SID, p) {
|
||||
spin_lock_irq(&p->sighand->siglock);
|
||||
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;
|
||||
}
|
||||
__group_send_sig_info(SIGHUP, SEND_SIG_PRIV, p);
|
||||
__group_send_sig_info(SIGCONT, SEND_SIG_PRIV, p);
|
||||
put_pid(p->signal->tty_old_pgrp); /* A noop */
|
||||
spin_lock_irqsave(&tty->ctrl_lock, flags);
|
||||
if (tty->pgrp)
|
||||
p->signal->tty_old_pgrp = get_pid(tty->pgrp);
|
||||
spin_unlock_irqrestore(&tty->ctrl_lock, flags);
|
||||
spin_unlock_irq(&p->sighand->siglock);
|
||||
} while_each_pid_task(tty->session, PIDTYPE_SID, p);
|
||||
}
|
||||
read_unlock(&tasklist_lock);
|
||||
|
||||
spin_lock_irqsave(&tty->ctrl_lock, flags);
|
||||
spin_lock_irq(&tty->ctrl_lock);
|
||||
clear_bit(TTY_THROTTLED, &tty->flags);
|
||||
clear_bit(TTY_PUSH, &tty->flags);
|
||||
clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
|
||||
@ -640,11 +671,7 @@ static void __tty_hangup(struct tty_struct *tty)
|
||||
tty->session = NULL;
|
||||
tty->pgrp = NULL;
|
||||
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);
|
||||
spin_unlock_irq(&tty->ctrl_lock);
|
||||
|
||||
/*
|
||||
* If one of the devices matches a console pointer, we
|
||||
@ -666,7 +693,6 @@ static void __tty_hangup(struct tty_struct *tty)
|
||||
*/
|
||||
set_bit(TTY_HUPPED, &tty->flags);
|
||||
clear_bit(TTY_HUPPING, &tty->flags);
|
||||
tty_ldisc_enable(tty);
|
||||
|
||||
tty_unlock(tty);
|
||||
|
||||
@ -679,7 +705,7 @@ static void do_tty_hangup(struct work_struct *work)
|
||||
struct tty_struct *tty =
|
||||
container_of(work, struct tty_struct, hangup_work);
|
||||
|
||||
__tty_hangup(tty);
|
||||
__tty_hangup(tty, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -717,7 +743,7 @@ void tty_vhangup(struct tty_struct *tty)
|
||||
|
||||
printk(KERN_DEBUG "%s vhangup...\n", tty_name(tty, buf));
|
||||
#endif
|
||||
__tty_hangup(tty);
|
||||
__tty_hangup(tty, 0);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(tty_vhangup);
|
||||
@ -740,6 +766,27 @@ void tty_vhangup_self(void)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* tty_vhangup_session - hangup session leader exit
|
||||
* @tty: tty to hangup
|
||||
*
|
||||
* The session leader is exiting and hanging up its controlling terminal.
|
||||
* Every process in the foreground process group is signalled SIGHUP.
|
||||
*
|
||||
* We do this synchronously so that when the syscall returns the process
|
||||
* is complete. That guarantee is necessary for security reasons.
|
||||
*/
|
||||
|
||||
static void tty_vhangup_session(struct tty_struct *tty)
|
||||
{
|
||||
#ifdef TTY_DEBUG_HANGUP
|
||||
char buf[64];
|
||||
|
||||
printk(KERN_DEBUG "%s vhangup session...\n", tty_name(tty, buf));
|
||||
#endif
|
||||
__tty_hangup(tty, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* tty_hung_up_p - was tty hung up
|
||||
* @filp: file pointer of tty
|
||||
@ -797,18 +844,18 @@ void disassociate_ctty(int on_exit)
|
||||
|
||||
tty = get_current_tty();
|
||||
if (tty) {
|
||||
struct pid *tty_pgrp = get_pid(tty->pgrp);
|
||||
if (on_exit) {
|
||||
if (tty->driver->type != TTY_DRIVER_TYPE_PTY)
|
||||
tty_vhangup(tty);
|
||||
if (on_exit && tty->driver->type != TTY_DRIVER_TYPE_PTY) {
|
||||
tty_vhangup_session(tty);
|
||||
} else {
|
||||
struct pid *tty_pgrp = tty_get_pgrp(tty);
|
||||
if (tty_pgrp) {
|
||||
kill_pgrp(tty_pgrp, SIGHUP, on_exit);
|
||||
kill_pgrp(tty_pgrp, SIGCONT, on_exit);
|
||||
put_pid(tty_pgrp);
|
||||
}
|
||||
}
|
||||
tty_kref_put(tty);
|
||||
if (tty_pgrp) {
|
||||
kill_pgrp(tty_pgrp, SIGHUP, on_exit);
|
||||
if (!on_exit)
|
||||
kill_pgrp(tty_pgrp, SIGCONT, on_exit);
|
||||
put_pid(tty_pgrp);
|
||||
}
|
||||
|
||||
} else if (on_exit) {
|
||||
struct pid *old_pgrp;
|
||||
spin_lock_irq(¤t->sighand->siglock);
|
||||
@ -1358,9 +1405,7 @@ static int tty_reopen(struct tty_struct *tty)
|
||||
}
|
||||
tty->count++;
|
||||
|
||||
mutex_lock(&tty->ldisc_mutex);
|
||||
WARN_ON(!test_bit(TTY_LDISC, &tty->flags));
|
||||
mutex_unlock(&tty->ldisc_mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -1477,6 +1522,17 @@ void tty_free_termios(struct tty_struct *tty)
|
||||
}
|
||||
EXPORT_SYMBOL(tty_free_termios);
|
||||
|
||||
/**
|
||||
* tty_flush_works - flush all works of a tty
|
||||
* @tty: tty device to flush works for
|
||||
*
|
||||
* Sync flush all works belonging to @tty.
|
||||
*/
|
||||
static void tty_flush_works(struct tty_struct *tty)
|
||||
{
|
||||
flush_work(&tty->SAK_work);
|
||||
flush_work(&tty->hangup_work);
|
||||
}
|
||||
|
||||
/**
|
||||
* release_one_tty - release tty structure memory
|
||||
@ -1562,6 +1618,7 @@ static void release_tty(struct tty_struct *tty, int idx)
|
||||
tty_free_termios(tty);
|
||||
tty_driver_remove_tty(tty->driver, tty);
|
||||
tty->port->itty = NULL;
|
||||
cancel_work_sync(&tty->port->buf.work);
|
||||
|
||||
if (tty->link)
|
||||
tty_kref_put(tty->link);
|
||||
@ -1791,12 +1848,21 @@ int tty_release(struct inode *inode, struct file *filp)
|
||||
return 0;
|
||||
|
||||
#ifdef TTY_DEBUG_HANGUP
|
||||
printk(KERN_DEBUG "%s: freeing tty structure...\n", __func__);
|
||||
printk(KERN_DEBUG "%s: %s: final close\n", __func__, tty_name(tty, buf));
|
||||
#endif
|
||||
/*
|
||||
* Ask the line discipline code to release its structures
|
||||
*/
|
||||
tty_ldisc_release(tty, o_tty);
|
||||
|
||||
/* Wait for pending work before tty destruction commmences */
|
||||
tty_flush_works(tty);
|
||||
if (o_tty)
|
||||
tty_flush_works(o_tty);
|
||||
|
||||
#ifdef TTY_DEBUG_HANGUP
|
||||
printk(KERN_DEBUG "%s: %s: freeing structure...\n", __func__, tty_name(tty, buf));
|
||||
#endif
|
||||
/*
|
||||
* The release_tty function takes care of the details of clearing
|
||||
* the slots and preserving the termios structure. The tty_unlock_pair
|
||||
|
@ -106,6 +106,7 @@ void tty_throttle(struct tty_struct *tty)
|
||||
if (!test_and_set_bit(TTY_THROTTLED, &tty->flags) &&
|
||||
tty->ops->throttle)
|
||||
tty->ops->throttle(tty);
|
||||
tty->flow_change = 0;
|
||||
mutex_unlock(&tty->termios_mutex);
|
||||
}
|
||||
EXPORT_SYMBOL(tty_throttle);
|
||||
@ -129,10 +130,73 @@ void tty_unthrottle(struct tty_struct *tty)
|
||||
if (test_and_clear_bit(TTY_THROTTLED, &tty->flags) &&
|
||||
tty->ops->unthrottle)
|
||||
tty->ops->unthrottle(tty);
|
||||
tty->flow_change = 0;
|
||||
mutex_unlock(&tty->termios_mutex);
|
||||
}
|
||||
EXPORT_SYMBOL(tty_unthrottle);
|
||||
|
||||
/**
|
||||
* tty_throttle_safe - flow control
|
||||
* @tty: terminal
|
||||
*
|
||||
* Similar to tty_throttle() but will only attempt throttle
|
||||
* if tty->flow_change is TTY_THROTTLE_SAFE. Prevents an accidental
|
||||
* throttle due to race conditions when throttling is conditional
|
||||
* on factors evaluated prior to throttling.
|
||||
*
|
||||
* Returns 0 if tty is throttled (or was already throttled)
|
||||
*/
|
||||
|
||||
int tty_throttle_safe(struct tty_struct *tty)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
mutex_lock(&tty->termios_mutex);
|
||||
if (!test_bit(TTY_THROTTLED, &tty->flags)) {
|
||||
if (tty->flow_change != TTY_THROTTLE_SAFE)
|
||||
ret = 1;
|
||||
else {
|
||||
set_bit(TTY_THROTTLED, &tty->flags);
|
||||
if (tty->ops->throttle)
|
||||
tty->ops->throttle(tty);
|
||||
}
|
||||
}
|
||||
mutex_unlock(&tty->termios_mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* tty_unthrottle_safe - flow control
|
||||
* @tty: terminal
|
||||
*
|
||||
* Similar to tty_unthrottle() but will only attempt unthrottle
|
||||
* if tty->flow_change is TTY_UNTHROTTLE_SAFE. Prevents an accidental
|
||||
* unthrottle due to race conditions when unthrottling is conditional
|
||||
* on factors evaluated prior to unthrottling.
|
||||
*
|
||||
* Returns 0 if tty is unthrottled (or was already unthrottled)
|
||||
*/
|
||||
|
||||
int tty_unthrottle_safe(struct tty_struct *tty)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
mutex_lock(&tty->termios_mutex);
|
||||
if (test_bit(TTY_THROTTLED, &tty->flags)) {
|
||||
if (tty->flow_change != TTY_UNTHROTTLE_SAFE)
|
||||
ret = 1;
|
||||
else {
|
||||
clear_bit(TTY_THROTTLED, &tty->flags);
|
||||
if (tty->ops->unthrottle)
|
||||
tty->ops->unthrottle(tty);
|
||||
}
|
||||
}
|
||||
mutex_unlock(&tty->termios_mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* tty_wait_until_sent - wait for I/O to finish
|
||||
* @tty: tty we are waiting for
|
||||
@ -414,34 +478,6 @@ void tty_encode_baud_rate(struct tty_struct *tty, speed_t ibaud, speed_t obaud)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(tty_encode_baud_rate);
|
||||
|
||||
/**
|
||||
* tty_get_baud_rate - get tty bit rates
|
||||
* @tty: tty to query
|
||||
*
|
||||
* Returns the baud rate as an integer for this terminal. The
|
||||
* termios lock must be held by the caller and the terminal bit
|
||||
* flags may be updated.
|
||||
*
|
||||
* Locking: none
|
||||
*/
|
||||
|
||||
speed_t tty_get_baud_rate(struct tty_struct *tty)
|
||||
{
|
||||
speed_t baud = tty_termios_baud_rate(&tty->termios);
|
||||
|
||||
if (baud == 38400 && tty->alt_speed) {
|
||||
if (!tty->warned) {
|
||||
printk(KERN_WARNING "Use of setserial/setrocket to "
|
||||
"set SPD_* flags is deprecated\n");
|
||||
tty->warned = 1;
|
||||
}
|
||||
baud = tty->alt_speed;
|
||||
}
|
||||
|
||||
return baud;
|
||||
}
|
||||
EXPORT_SYMBOL(tty_get_baud_rate);
|
||||
|
||||
/**
|
||||
* tty_termios_copy_hw - copy hardware settings
|
||||
* @new: New termios
|
||||
@ -1086,14 +1122,12 @@ int tty_mode_ioctl(struct tty_struct *tty, struct file *file,
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(tty_mode_ioctl);
|
||||
|
||||
int tty_perform_flush(struct tty_struct *tty, unsigned long arg)
|
||||
{
|
||||
struct tty_ldisc *ld;
|
||||
int retval = tty_check_change(tty);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
ld = tty_ldisc_ref_wait(tty);
|
||||
/* Caller guarantees ldisc reference is held */
|
||||
static int __tty_perform_flush(struct tty_struct *tty, unsigned long arg)
|
||||
{
|
||||
struct tty_ldisc *ld = tty->ldisc;
|
||||
|
||||
switch (arg) {
|
||||
case TCIFLUSH:
|
||||
if (ld && ld->ops->flush_buffer) {
|
||||
@ -1111,12 +1145,24 @@ int tty_perform_flush(struct tty_struct *tty, unsigned long arg)
|
||||
tty_driver_flush_buffer(tty);
|
||||
break;
|
||||
default:
|
||||
tty_ldisc_deref(ld);
|
||||
return -EINVAL;
|
||||
}
|
||||
tty_ldisc_deref(ld);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tty_perform_flush(struct tty_struct *tty, unsigned long arg)
|
||||
{
|
||||
struct tty_ldisc *ld;
|
||||
int retval = tty_check_change(tty);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
ld = tty_ldisc_ref_wait(tty);
|
||||
retval = __tty_perform_flush(tty, arg);
|
||||
if (ld)
|
||||
tty_ldisc_deref(ld);
|
||||
return retval;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(tty_perform_flush);
|
||||
|
||||
int n_tty_ioctl_helper(struct tty_struct *tty, struct file *file,
|
||||
@ -1155,7 +1201,7 @@ int n_tty_ioctl_helper(struct tty_struct *tty, struct file *file,
|
||||
}
|
||||
return 0;
|
||||
case TCFLSH:
|
||||
return tty_perform_flush(tty, arg);
|
||||
return __tty_perform_flush(tty, arg);
|
||||
default:
|
||||
/* Try the mode commands */
|
||||
return tty_mode_ioctl(tty, file, cmd, arg);
|
||||
|
@ -20,6 +20,17 @@
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/ratelimit.h>
|
||||
|
||||
#undef LDISC_DEBUG_HANGUP
|
||||
|
||||
#ifdef LDISC_DEBUG_HANGUP
|
||||
#define tty_ldisc_debug(tty, f, args...) ({ \
|
||||
char __b[64]; \
|
||||
printk(KERN_DEBUG "%s: %s: " f, __func__, tty_name(tty, __b), ##args); \
|
||||
})
|
||||
#else
|
||||
#define tty_ldisc_debug(tty, f, args...)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* This guards the refcounted line discipline lists. The lock
|
||||
* must be taken with irqs off because there are hangup path
|
||||
@ -31,44 +42,6 @@ static DECLARE_WAIT_QUEUE_HEAD(tty_ldisc_wait);
|
||||
/* Line disc dispatch table */
|
||||
static struct tty_ldisc_ops *tty_ldiscs[NR_LDISCS];
|
||||
|
||||
static inline struct tty_ldisc *get_ldisc(struct tty_ldisc *ld)
|
||||
{
|
||||
if (ld)
|
||||
atomic_inc(&ld->users);
|
||||
return ld;
|
||||
}
|
||||
|
||||
static void put_ldisc(struct tty_ldisc *ld)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
if (WARN_ON_ONCE(!ld))
|
||||
return;
|
||||
|
||||
/*
|
||||
* If this is the last user, free the ldisc, and
|
||||
* release the ldisc ops.
|
||||
*
|
||||
* We really want an "atomic_dec_and_raw_lock_irqsave()",
|
||||
* but we don't have it, so this does it by hand.
|
||||
*/
|
||||
raw_spin_lock_irqsave(&tty_ldisc_lock, flags);
|
||||
if (atomic_dec_and_test(&ld->users)) {
|
||||
struct tty_ldisc_ops *ldo = ld->ops;
|
||||
|
||||
ldo->refcount--;
|
||||
module_put(ldo->owner);
|
||||
raw_spin_unlock_irqrestore(&tty_ldisc_lock, flags);
|
||||
|
||||
kfree(ld);
|
||||
return;
|
||||
}
|
||||
raw_spin_unlock_irqrestore(&tty_ldisc_lock, flags);
|
||||
|
||||
if (waitqueue_active(&ld->wq_idle))
|
||||
wake_up(&ld->wq_idle);
|
||||
}
|
||||
|
||||
/**
|
||||
* tty_register_ldisc - install a line discipline
|
||||
* @disc: ldisc number
|
||||
@ -206,6 +179,29 @@ static struct tty_ldisc *tty_ldisc_get(int disc)
|
||||
return ld;
|
||||
}
|
||||
|
||||
/**
|
||||
* tty_ldisc_put - release the ldisc
|
||||
*
|
||||
* Complement of tty_ldisc_get().
|
||||
*/
|
||||
static inline void tty_ldisc_put(struct tty_ldisc *ld)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
if (WARN_ON_ONCE(!ld))
|
||||
return;
|
||||
|
||||
raw_spin_lock_irqsave(&tty_ldisc_lock, flags);
|
||||
|
||||
/* unreleased reader reference(s) will cause this WARN */
|
||||
WARN_ON(!atomic_dec_and_test(&ld->users));
|
||||
|
||||
ld->ops->refcount--;
|
||||
module_put(ld->ops->owner);
|
||||
kfree(ld);
|
||||
raw_spin_unlock_irqrestore(&tty_ldisc_lock, flags);
|
||||
}
|
||||
|
||||
static void *tty_ldiscs_seq_start(struct seq_file *m, loff_t *pos)
|
||||
{
|
||||
return (*pos < NR_LDISCS) ? pos : NULL;
|
||||
@ -254,24 +250,6 @@ const struct file_operations tty_ldiscs_proc_fops = {
|
||||
.release = seq_release,
|
||||
};
|
||||
|
||||
/**
|
||||
* tty_ldisc_assign - set ldisc on a tty
|
||||
* @tty: tty to assign
|
||||
* @ld: line discipline
|
||||
*
|
||||
* Install an instance of a line discipline into a tty structure. The
|
||||
* ldisc must have a reference count above zero to ensure it remains.
|
||||
* The tty instance refcount starts at zero.
|
||||
*
|
||||
* Locking:
|
||||
* Caller must hold references
|
||||
*/
|
||||
|
||||
static void tty_ldisc_assign(struct tty_struct *tty, struct tty_ldisc *ld)
|
||||
{
|
||||
tty->ldisc = ld;
|
||||
}
|
||||
|
||||
/**
|
||||
* tty_ldisc_try - internal helper
|
||||
* @tty: the tty
|
||||
@ -289,10 +267,13 @@ static struct tty_ldisc *tty_ldisc_try(struct tty_struct *tty)
|
||||
unsigned long flags;
|
||||
struct tty_ldisc *ld;
|
||||
|
||||
/* FIXME: this allows reference acquire after TTY_LDISC is cleared */
|
||||
raw_spin_lock_irqsave(&tty_ldisc_lock, flags);
|
||||
ld = NULL;
|
||||
if (test_bit(TTY_LDISC, &tty->flags))
|
||||
ld = get_ldisc(tty->ldisc);
|
||||
if (test_bit(TTY_LDISC, &tty->flags) && tty->ldisc) {
|
||||
ld = tty->ldisc;
|
||||
atomic_inc(&ld->users);
|
||||
}
|
||||
raw_spin_unlock_irqrestore(&tty_ldisc_lock, flags);
|
||||
return ld;
|
||||
}
|
||||
@ -352,15 +333,24 @@ EXPORT_SYMBOL_GPL(tty_ldisc_ref);
|
||||
|
||||
void tty_ldisc_deref(struct tty_ldisc *ld)
|
||||
{
|
||||
put_ldisc(ld);
|
||||
unsigned long flags;
|
||||
|
||||
if (WARN_ON_ONCE(!ld))
|
||||
return;
|
||||
|
||||
raw_spin_lock_irqsave(&tty_ldisc_lock, flags);
|
||||
/*
|
||||
* WARNs if one-too-many reader references were released
|
||||
* - the last reference must be released with tty_ldisc_put
|
||||
*/
|
||||
WARN_ON(atomic_dec_and_test(&ld->users));
|
||||
raw_spin_unlock_irqrestore(&tty_ldisc_lock, flags);
|
||||
|
||||
if (waitqueue_active(&ld->wq_idle))
|
||||
wake_up(&ld->wq_idle);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(tty_ldisc_deref);
|
||||
|
||||
static inline void tty_ldisc_put(struct tty_ldisc *ld)
|
||||
{
|
||||
put_ldisc(ld);
|
||||
}
|
||||
|
||||
/**
|
||||
* tty_ldisc_enable - allow ldisc use
|
||||
* @tty: terminal to activate ldisc on
|
||||
@ -373,8 +363,9 @@ static inline void tty_ldisc_put(struct tty_ldisc *ld)
|
||||
* Clearing directly is allowed.
|
||||
*/
|
||||
|
||||
void tty_ldisc_enable(struct tty_struct *tty)
|
||||
static void tty_ldisc_enable(struct tty_struct *tty)
|
||||
{
|
||||
clear_bit(TTY_LDISC_HALTED, &tty->flags);
|
||||
set_bit(TTY_LDISC, &tty->flags);
|
||||
clear_bit(TTY_LDISC_CHANGING, &tty->flags);
|
||||
wake_up(&tty_ldisc_wait);
|
||||
@ -479,7 +470,7 @@ static void tty_ldisc_restore(struct tty_struct *tty, struct tty_ldisc *old)
|
||||
/* There is an outstanding reference here so this is safe */
|
||||
old = tty_ldisc_get(old->ops->num);
|
||||
WARN_ON(IS_ERR(old));
|
||||
tty_ldisc_assign(tty, old);
|
||||
tty->ldisc = old;
|
||||
tty_set_termios_ldisc(tty, old->ops->num);
|
||||
if (tty_ldisc_open(tty, old) < 0) {
|
||||
tty_ldisc_put(old);
|
||||
@ -487,7 +478,7 @@ static void tty_ldisc_restore(struct tty_struct *tty, struct tty_ldisc *old)
|
||||
new_ldisc = tty_ldisc_get(N_TTY);
|
||||
if (IS_ERR(new_ldisc))
|
||||
panic("n_tty: get");
|
||||
tty_ldisc_assign(tty, new_ldisc);
|
||||
tty->ldisc = new_ldisc;
|
||||
tty_set_termios_ldisc(tty, N_TTY);
|
||||
r = tty_ldisc_open(tty, new_ldisc);
|
||||
if (r < 0)
|
||||
@ -497,39 +488,6 @@ static void tty_ldisc_restore(struct tty_struct *tty, struct tty_ldisc *old)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* tty_ldisc_halt - shut down the line discipline
|
||||
* @tty: tty device
|
||||
*
|
||||
* Shut down the line discipline and work queue for this tty device.
|
||||
* The TTY_LDISC flag being cleared ensures no further references can
|
||||
* be obtained while the delayed work queue halt ensures that no more
|
||||
* data is fed to the ldisc.
|
||||
*
|
||||
* You need to do a 'flush_scheduled_work()' (outside the ldisc_mutex)
|
||||
* in order to make sure any currently executing ldisc work is also
|
||||
* flushed.
|
||||
*/
|
||||
|
||||
static int tty_ldisc_halt(struct tty_struct *tty)
|
||||
{
|
||||
clear_bit(TTY_LDISC, &tty->flags);
|
||||
return cancel_work_sync(&tty->port->buf.work);
|
||||
}
|
||||
|
||||
/**
|
||||
* tty_ldisc_flush_works - flush all works of a tty
|
||||
* @tty: tty device to flush works for
|
||||
*
|
||||
* Sync flush all works belonging to @tty.
|
||||
*/
|
||||
static void tty_ldisc_flush_works(struct tty_struct *tty)
|
||||
{
|
||||
flush_work(&tty->hangup_work);
|
||||
flush_work(&tty->SAK_work);
|
||||
flush_work(&tty->port->buf.work);
|
||||
}
|
||||
|
||||
/**
|
||||
* tty_ldisc_wait_idle - wait for the ldisc to become idle
|
||||
* @tty: tty to wait for
|
||||
@ -546,6 +504,85 @@ static int tty_ldisc_wait_idle(struct tty_struct *tty, long timeout)
|
||||
return ret > 0 ? 0 : -EBUSY;
|
||||
}
|
||||
|
||||
/**
|
||||
* tty_ldisc_halt - shut down the line discipline
|
||||
* @tty: tty device
|
||||
* @o_tty: paired pty device (can be NULL)
|
||||
* @timeout: # of jiffies to wait for ldisc refs to be released
|
||||
*
|
||||
* Shut down the line discipline and work queue for this tty device and
|
||||
* its paired pty (if exists). Clearing the TTY_LDISC flag ensures
|
||||
* no further references can be obtained, while waiting for existing
|
||||
* references to be released ensures no more data is fed to the ldisc.
|
||||
*
|
||||
* You need to do a 'flush_scheduled_work()' (outside the ldisc_mutex)
|
||||
* in order to make sure any currently executing ldisc work is also
|
||||
* flushed.
|
||||
*/
|
||||
|
||||
static int tty_ldisc_halt(struct tty_struct *tty, struct tty_struct *o_tty,
|
||||
long timeout)
|
||||
{
|
||||
int retval;
|
||||
|
||||
clear_bit(TTY_LDISC, &tty->flags);
|
||||
if (o_tty)
|
||||
clear_bit(TTY_LDISC, &o_tty->flags);
|
||||
|
||||
retval = tty_ldisc_wait_idle(tty, timeout);
|
||||
if (!retval && o_tty)
|
||||
retval = tty_ldisc_wait_idle(o_tty, timeout);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
set_bit(TTY_LDISC_HALTED, &tty->flags);
|
||||
if (o_tty)
|
||||
set_bit(TTY_LDISC_HALTED, &o_tty->flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* tty_ldisc_hangup_halt - halt the line discipline for hangup
|
||||
* @tty: tty being hung up
|
||||
*
|
||||
* Shut down the line discipline and work queue for the tty device
|
||||
* being hungup. Clear the TTY_LDISC flag to ensure no further
|
||||
* references can be obtained and wait for remaining references to be
|
||||
* released to ensure no more data is fed to this ldisc.
|
||||
* Caller must hold legacy and ->ldisc_mutex.
|
||||
*
|
||||
* NB: tty_set_ldisc() is prevented from changing the ldisc concurrently
|
||||
* with this function by checking the TTY_HUPPING flag.
|
||||
*/
|
||||
static bool tty_ldisc_hangup_halt(struct tty_struct *tty)
|
||||
{
|
||||
char cur_n[TASK_COMM_LEN], tty_n[64];
|
||||
long timeout = 3 * HZ;
|
||||
|
||||
clear_bit(TTY_LDISC, &tty->flags);
|
||||
|
||||
if (tty->ldisc) { /* Not yet closed */
|
||||
tty_unlock(tty);
|
||||
|
||||
while (tty_ldisc_wait_idle(tty, timeout) == -EBUSY) {
|
||||
timeout = MAX_SCHEDULE_TIMEOUT;
|
||||
printk_ratelimited(KERN_WARNING
|
||||
"%s: waiting (%s) for %s took too long, but we keep waiting...\n",
|
||||
__func__, get_task_comm(cur_n, current),
|
||||
tty_name(tty, tty_n));
|
||||
}
|
||||
|
||||
set_bit(TTY_LDISC_HALTED, &tty->flags);
|
||||
|
||||
/* must reacquire both locks and preserve lock order */
|
||||
mutex_unlock(&tty->ldisc_mutex);
|
||||
tty_lock(tty);
|
||||
mutex_lock(&tty->ldisc_mutex);
|
||||
}
|
||||
return !!tty->ldisc;
|
||||
}
|
||||
|
||||
/**
|
||||
* tty_set_ldisc - set line discipline
|
||||
* @tty: the terminal to set
|
||||
@ -563,7 +600,6 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
|
||||
{
|
||||
int retval;
|
||||
struct tty_ldisc *o_ldisc, *new_ldisc;
|
||||
int work, o_work = 0;
|
||||
struct tty_struct *o_tty;
|
||||
|
||||
new_ldisc = tty_ldisc_get(ldisc);
|
||||
@ -589,15 +625,6 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
|
||||
return 0;
|
||||
}
|
||||
|
||||
tty_unlock(tty);
|
||||
/*
|
||||
* Problem: What do we do if this blocks ?
|
||||
* We could deadlock here
|
||||
*/
|
||||
|
||||
tty_wait_until_sent(tty, 0);
|
||||
|
||||
tty_lock(tty);
|
||||
mutex_lock(&tty->ldisc_mutex);
|
||||
|
||||
/*
|
||||
@ -637,20 +664,16 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
|
||||
* parallel to the change and re-referencing the tty.
|
||||
*/
|
||||
|
||||
work = tty_ldisc_halt(tty);
|
||||
if (o_tty)
|
||||
o_work = tty_ldisc_halt(o_tty);
|
||||
retval = tty_ldisc_halt(tty, o_tty, 5 * HZ);
|
||||
|
||||
/*
|
||||
* Wait for ->hangup_work and ->buf.work handlers to terminate.
|
||||
* Wait for hangup to complete, if pending.
|
||||
* We must drop the mutex here in case a hangup is also in process.
|
||||
*/
|
||||
|
||||
mutex_unlock(&tty->ldisc_mutex);
|
||||
|
||||
tty_ldisc_flush_works(tty);
|
||||
|
||||
retval = tty_ldisc_wait_idle(tty, 5 * HZ);
|
||||
flush_work(&tty->hangup_work);
|
||||
|
||||
tty_lock(tty);
|
||||
mutex_lock(&tty->ldisc_mutex);
|
||||
@ -675,7 +698,7 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
|
||||
tty_ldisc_close(tty, o_ldisc);
|
||||
|
||||
/* Now set up the new line discipline. */
|
||||
tty_ldisc_assign(tty, new_ldisc);
|
||||
tty->ldisc = new_ldisc;
|
||||
tty_set_termios_ldisc(tty, ldisc);
|
||||
|
||||
retval = tty_ldisc_open(tty, new_ldisc);
|
||||
@ -705,10 +728,10 @@ enable:
|
||||
|
||||
/* Restart the work queue in case no characters kick it off. Safe if
|
||||
already running */
|
||||
if (work)
|
||||
schedule_work(&tty->port->buf.work);
|
||||
if (o_work)
|
||||
schedule_work(&tty->port->buf.work);
|
||||
if (o_tty)
|
||||
schedule_work(&o_tty->port->buf.work);
|
||||
|
||||
mutex_unlock(&tty->ldisc_mutex);
|
||||
tty_unlock(tty);
|
||||
return retval;
|
||||
@ -749,11 +772,10 @@ static int tty_ldisc_reinit(struct tty_struct *tty, int ldisc)
|
||||
|
||||
tty_ldisc_close(tty, tty->ldisc);
|
||||
tty_ldisc_put(tty->ldisc);
|
||||
tty->ldisc = NULL;
|
||||
/*
|
||||
* Switch the line discipline back
|
||||
*/
|
||||
tty_ldisc_assign(tty, ld);
|
||||
tty->ldisc = ld;
|
||||
tty_set_termios_ldisc(tty, ldisc);
|
||||
|
||||
return 0;
|
||||
@ -780,6 +802,8 @@ void tty_ldisc_hangup(struct tty_struct *tty)
|
||||
int reset = tty->driver->flags & TTY_DRIVER_RESET_TERMIOS;
|
||||
int err = 0;
|
||||
|
||||
tty_ldisc_debug(tty, "closing ldisc: %p\n", tty->ldisc);
|
||||
|
||||
/*
|
||||
* FIXME! What are the locking issues here? This may me overdoing
|
||||
* things... This question is especially important now that we've
|
||||
@ -812,40 +836,12 @@ void tty_ldisc_hangup(struct tty_struct *tty)
|
||||
*/
|
||||
mutex_lock(&tty->ldisc_mutex);
|
||||
|
||||
/*
|
||||
* this is like tty_ldisc_halt, but we need to give up
|
||||
* the BTM before calling cancel_work_sync, which may
|
||||
* need to wait for another function taking the BTM
|
||||
*/
|
||||
clear_bit(TTY_LDISC, &tty->flags);
|
||||
tty_unlock(tty);
|
||||
cancel_work_sync(&tty->port->buf.work);
|
||||
mutex_unlock(&tty->ldisc_mutex);
|
||||
retry:
|
||||
tty_lock(tty);
|
||||
mutex_lock(&tty->ldisc_mutex);
|
||||
|
||||
/* At this point we have a closed ldisc and we want to
|
||||
reopen it. We could defer this to the next open but
|
||||
it means auditing a lot of other paths so this is
|
||||
a FIXME */
|
||||
if (tty->ldisc) { /* Not yet closed */
|
||||
if (atomic_read(&tty->ldisc->users) != 1) {
|
||||
char cur_n[TASK_COMM_LEN], tty_n[64];
|
||||
long timeout = 3 * HZ;
|
||||
tty_unlock(tty);
|
||||
|
||||
while (tty_ldisc_wait_idle(tty, timeout) == -EBUSY) {
|
||||
timeout = MAX_SCHEDULE_TIMEOUT;
|
||||
printk_ratelimited(KERN_WARNING
|
||||
"%s: waiting (%s) for %s took too long, but we keep waiting...\n",
|
||||
__func__, get_task_comm(cur_n, current),
|
||||
tty_name(tty, tty_n));
|
||||
}
|
||||
mutex_unlock(&tty->ldisc_mutex);
|
||||
goto retry;
|
||||
}
|
||||
if (tty_ldisc_hangup_halt(tty)) {
|
||||
|
||||
/* At this point we have a halted ldisc; we want to close it and
|
||||
reopen a new ldisc. We could defer the reopen to the next
|
||||
open but it means auditing a lot of other paths so this is
|
||||
a FIXME */
|
||||
if (reset == 0) {
|
||||
|
||||
if (!tty_ldisc_reinit(tty, tty->termios.c_line))
|
||||
@ -864,6 +860,8 @@ retry:
|
||||
mutex_unlock(&tty->ldisc_mutex);
|
||||
if (reset)
|
||||
tty_reset_termios(tty);
|
||||
|
||||
tty_ldisc_debug(tty, "re-opened ldisc: %p\n", tty->ldisc);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -899,11 +897,6 @@ int tty_ldisc_setup(struct tty_struct *tty, struct tty_struct *o_tty)
|
||||
|
||||
static void tty_ldisc_kill(struct tty_struct *tty)
|
||||
{
|
||||
/* There cannot be users from userspace now. But there still might be
|
||||
* drivers holding a reference via tty_ldisc_ref. Do not steal them the
|
||||
* ldisc until they are done. */
|
||||
tty_ldisc_wait_idle(tty, MAX_SCHEDULE_TIMEOUT);
|
||||
|
||||
mutex_lock(&tty->ldisc_mutex);
|
||||
/*
|
||||
* Now kill off the ldisc
|
||||
@ -931,18 +924,13 @@ static void tty_ldisc_kill(struct tty_struct *tty)
|
||||
void tty_ldisc_release(struct tty_struct *tty, struct tty_struct *o_tty)
|
||||
{
|
||||
/*
|
||||
* Prevent flush_to_ldisc() from rescheduling the work for later. Then
|
||||
* kill any delayed work. As this is the final close it does not
|
||||
* race with the set_ldisc code path.
|
||||
* Shutdown this line discipline. As this is the final close,
|
||||
* it does not race with the set_ldisc code path.
|
||||
*/
|
||||
|
||||
tty_ldisc_halt(tty);
|
||||
if (o_tty)
|
||||
tty_ldisc_halt(o_tty);
|
||||
tty_ldisc_debug(tty, "closing ldisc: %p\n", tty->ldisc);
|
||||
|
||||
tty_ldisc_flush_works(tty);
|
||||
if (o_tty)
|
||||
tty_ldisc_flush_works(o_tty);
|
||||
tty_ldisc_halt(tty, o_tty, MAX_SCHEDULE_TIMEOUT);
|
||||
|
||||
tty_lock_pair(tty, o_tty);
|
||||
/* This will need doing differently if we need to lock */
|
||||
@ -953,6 +941,8 @@ void tty_ldisc_release(struct tty_struct *tty, struct tty_struct *o_tty)
|
||||
tty_unlock_pair(tty, o_tty);
|
||||
/* And the memory resources remaining (buffers, termios) will be
|
||||
disposed of when the kref hits zero */
|
||||
|
||||
tty_ldisc_debug(tty, "ldisc closed\n");
|
||||
}
|
||||
|
||||
/**
|
||||
@ -968,7 +958,7 @@ void tty_ldisc_init(struct tty_struct *tty)
|
||||
struct tty_ldisc *ld = tty_ldisc_get(N_TTY);
|
||||
if (IS_ERR(ld))
|
||||
panic("n_tty: init_tty");
|
||||
tty_ldisc_assign(tty, ld);
|
||||
tty->ldisc = ld;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -980,8 +970,8 @@ void tty_ldisc_init(struct tty_struct *tty)
|
||||
*/
|
||||
void tty_ldisc_deinit(struct tty_struct *tty)
|
||||
{
|
||||
put_ldisc(tty->ldisc);
|
||||
tty_ldisc_assign(tty, NULL);
|
||||
tty_ldisc_put(tty->ldisc);
|
||||
tty->ldisc = NULL;
|
||||
}
|
||||
|
||||
void tty_ldisc_begin(void)
|
||||
|
@ -132,6 +132,7 @@ EXPORT_SYMBOL(tty_port_free_xmit_buf);
|
||||
*/
|
||||
void tty_port_destroy(struct tty_port *port)
|
||||
{
|
||||
cancel_work_sync(&port->buf.work);
|
||||
tty_buffer_free_all(port);
|
||||
}
|
||||
EXPORT_SYMBOL(tty_port_destroy);
|
||||
@ -196,12 +197,24 @@ void tty_port_tty_set(struct tty_port *port, struct tty_struct *tty)
|
||||
}
|
||||
EXPORT_SYMBOL(tty_port_tty_set);
|
||||
|
||||
static void tty_port_shutdown(struct tty_port *port)
|
||||
static void tty_port_shutdown(struct tty_port *port, struct tty_struct *tty)
|
||||
{
|
||||
mutex_lock(&port->mutex);
|
||||
if (port->ops->shutdown && !port->console &&
|
||||
test_and_clear_bit(ASYNCB_INITIALIZED, &port->flags))
|
||||
if (port->console)
|
||||
goto out;
|
||||
|
||||
if (test_and_clear_bit(ASYNCB_INITIALIZED, &port->flags)) {
|
||||
/*
|
||||
* Drop DTR/RTS if HUPCL is set. This causes any attached
|
||||
* modem to hang up the line.
|
||||
*/
|
||||
if (tty && C_HUPCL(tty))
|
||||
tty_port_lower_dtr_rts(port);
|
||||
|
||||
if (port->ops->shutdown)
|
||||
port->ops->shutdown(port);
|
||||
}
|
||||
out:
|
||||
mutex_unlock(&port->mutex);
|
||||
}
|
||||
|
||||
@ -215,23 +228,57 @@ static void tty_port_shutdown(struct tty_port *port)
|
||||
|
||||
void tty_port_hangup(struct tty_port *port)
|
||||
{
|
||||
struct tty_struct *tty;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
port->count = 0;
|
||||
port->flags &= ~ASYNC_NORMAL_ACTIVE;
|
||||
if (port->tty) {
|
||||
set_bit(TTY_IO_ERROR, &port->tty->flags);
|
||||
tty_kref_put(port->tty);
|
||||
}
|
||||
tty = port->tty;
|
||||
if (tty)
|
||||
set_bit(TTY_IO_ERROR, &tty->flags);
|
||||
port->tty = NULL;
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
tty_port_shutdown(port, tty);
|
||||
tty_kref_put(tty);
|
||||
wake_up_interruptible(&port->open_wait);
|
||||
wake_up_interruptible(&port->delta_msr_wait);
|
||||
tty_port_shutdown(port);
|
||||
}
|
||||
EXPORT_SYMBOL(tty_port_hangup);
|
||||
|
||||
/**
|
||||
* tty_port_tty_hangup - helper to hang up a tty
|
||||
*
|
||||
* @port: tty port
|
||||
* @check_clocal: hang only ttys with CLOCAL unset?
|
||||
*/
|
||||
void tty_port_tty_hangup(struct tty_port *port, bool check_clocal)
|
||||
{
|
||||
struct tty_struct *tty = tty_port_tty_get(port);
|
||||
|
||||
if (tty && (!check_clocal || !C_CLOCAL(tty))) {
|
||||
tty_hangup(tty);
|
||||
tty_kref_put(tty);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(tty_port_tty_hangup);
|
||||
|
||||
/**
|
||||
* tty_port_tty_wakeup - helper to wake up a tty
|
||||
*
|
||||
* @port: tty port
|
||||
*/
|
||||
void tty_port_tty_wakeup(struct tty_port *port)
|
||||
{
|
||||
struct tty_struct *tty = tty_port_tty_get(port);
|
||||
|
||||
if (tty) {
|
||||
tty_wakeup(tty);
|
||||
tty_kref_put(tty);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(tty_port_tty_wakeup);
|
||||
|
||||
/**
|
||||
* tty_port_carrier_raised - carrier raised check
|
||||
* @port: tty port
|
||||
@ -350,7 +397,7 @@ int tty_port_block_til_ready(struct tty_port *port,
|
||||
|
||||
while (1) {
|
||||
/* Indicate we are open */
|
||||
if (tty->termios.c_cflag & CBAUD)
|
||||
if (C_BAUD(tty) && test_bit(ASYNCB_INITIALIZED, &port->flags))
|
||||
tty_port_raise_dtr_rts(port);
|
||||
|
||||
prepare_to_wait(&port->open_wait, &wait, TASK_INTERRUPTIBLE);
|
||||
@ -395,6 +442,20 @@ int tty_port_block_til_ready(struct tty_port *port,
|
||||
}
|
||||
EXPORT_SYMBOL(tty_port_block_til_ready);
|
||||
|
||||
static void tty_port_drain_delay(struct tty_port *port, struct tty_struct *tty)
|
||||
{
|
||||
unsigned int bps = tty_get_baud_rate(tty);
|
||||
long timeout;
|
||||
|
||||
if (bps > 1200) {
|
||||
timeout = (HZ * 10 * port->drain_delay) / bps;
|
||||
timeout = max_t(long, timeout, HZ / 10);
|
||||
} else {
|
||||
timeout = 2 * HZ;
|
||||
}
|
||||
schedule_timeout_interruptible(timeout);
|
||||
}
|
||||
|
||||
int tty_port_close_start(struct tty_port *port,
|
||||
struct tty_struct *tty, struct file *filp)
|
||||
{
|
||||
@ -427,31 +488,19 @@ int tty_port_close_start(struct tty_port *port,
|
||||
set_bit(ASYNCB_CLOSING, &port->flags);
|
||||
tty->closing = 1;
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
/* Don't block on a stalled port, just pull the chain */
|
||||
if (tty->flow_stopped)
|
||||
tty_driver_flush_buffer(tty);
|
||||
if (test_bit(ASYNCB_INITIALIZED, &port->flags) &&
|
||||
port->closing_wait != ASYNC_CLOSING_WAIT_NONE)
|
||||
tty_wait_until_sent_from_close(tty, port->closing_wait);
|
||||
if (port->drain_delay) {
|
||||
unsigned int bps = tty_get_baud_rate(tty);
|
||||
long timeout;
|
||||
|
||||
if (bps > 1200)
|
||||
timeout = max_t(long,
|
||||
(HZ * 10 * port->drain_delay) / bps, HZ / 10);
|
||||
else
|
||||
timeout = 2 * HZ;
|
||||
schedule_timeout_interruptible(timeout);
|
||||
if (test_bit(ASYNCB_INITIALIZED, &port->flags)) {
|
||||
/* Don't block on a stalled port, just pull the chain */
|
||||
if (tty->flow_stopped)
|
||||
tty_driver_flush_buffer(tty);
|
||||
if (port->closing_wait != ASYNC_CLOSING_WAIT_NONE)
|
||||
tty_wait_until_sent_from_close(tty, port->closing_wait);
|
||||
if (port->drain_delay)
|
||||
tty_port_drain_delay(port, tty);
|
||||
}
|
||||
/* Flush the ldisc buffering */
|
||||
tty_ldisc_flush(tty);
|
||||
|
||||
/* Drop DTR/RTS if HUPCL is set. This causes any attached modem to
|
||||
hang up the line */
|
||||
if (tty->termios.c_cflag & HUPCL)
|
||||
tty_port_lower_dtr_rts(port);
|
||||
|
||||
/* Don't call port->drop for the last reference. Callers will want
|
||||
to drop the last active reference in ->shutdown() or the tty
|
||||
shutdown path */
|
||||
@ -486,7 +535,7 @@ void tty_port_close(struct tty_port *port, struct tty_struct *tty,
|
||||
{
|
||||
if (tty_port_close_start(port, tty, filp) == 0)
|
||||
return;
|
||||
tty_port_shutdown(port);
|
||||
tty_port_shutdown(port, tty);
|
||||
set_bit(TTY_IO_ERROR, &tty->flags);
|
||||
tty_port_close_end(port, tty);
|
||||
tty_port_tty_set(port, NULL);
|
||||
|
@ -194,8 +194,7 @@ static void set_inverse_transl(struct vc_data *conp, struct uni_pagedir *p, int
|
||||
q = p->inverse_translations[i];
|
||||
|
||||
if (!q) {
|
||||
q = p->inverse_translations[i] = (unsigned char *)
|
||||
kmalloc(MAX_GLYPH, GFP_KERNEL);
|
||||
q = p->inverse_translations[i] = kmalloc(MAX_GLYPH, GFP_KERNEL);
|
||||
if (!q) return;
|
||||
}
|
||||
memset(q, 0, MAX_GLYPH);
|
||||
|
@ -292,7 +292,6 @@ static void acm_ctrl_irq(struct urb *urb)
|
||||
{
|
||||
struct acm *acm = urb->context;
|
||||
struct usb_cdc_notification *dr = urb->transfer_buffer;
|
||||
struct tty_struct *tty;
|
||||
unsigned char *data;
|
||||
int newctrl;
|
||||
int retval;
|
||||
@ -327,17 +326,12 @@ static void acm_ctrl_irq(struct urb *urb)
|
||||
break;
|
||||
|
||||
case USB_CDC_NOTIFY_SERIAL_STATE:
|
||||
tty = tty_port_tty_get(&acm->port);
|
||||
newctrl = get_unaligned_le16(data);
|
||||
|
||||
if (tty) {
|
||||
if (!acm->clocal &&
|
||||
(acm->ctrlin & ~newctrl & ACM_CTRL_DCD)) {
|
||||
dev_dbg(&acm->control->dev,
|
||||
"%s - calling hangup\n", __func__);
|
||||
tty_hangup(tty);
|
||||
}
|
||||
tty_kref_put(tty);
|
||||
if (!acm->clocal && (acm->ctrlin & ~newctrl & ACM_CTRL_DCD)) {
|
||||
dev_dbg(&acm->control->dev, "%s - calling hangup\n",
|
||||
__func__);
|
||||
tty_port_tty_hangup(&acm->port, false);
|
||||
}
|
||||
|
||||
acm->ctrlin = newctrl;
|
||||
@ -475,15 +469,10 @@ static void acm_write_bulk(struct urb *urb)
|
||||
static void acm_softint(struct work_struct *work)
|
||||
{
|
||||
struct acm *acm = container_of(work, struct acm, work);
|
||||
struct tty_struct *tty;
|
||||
|
||||
dev_vdbg(&acm->data->dev, "%s\n", __func__);
|
||||
|
||||
tty = tty_port_tty_get(&acm->port);
|
||||
if (!tty)
|
||||
return;
|
||||
tty_wakeup(tty);
|
||||
tty_kref_put(tty);
|
||||
tty_port_tty_wakeup(&acm->port);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1519,15 +1508,9 @@ err_out:
|
||||
static int acm_reset_resume(struct usb_interface *intf)
|
||||
{
|
||||
struct acm *acm = usb_get_intfdata(intf);
|
||||
struct tty_struct *tty;
|
||||
|
||||
if (test_bit(ASYNCB_INITIALIZED, &acm->port.flags)) {
|
||||
tty = tty_port_tty_get(&acm->port);
|
||||
if (tty) {
|
||||
tty_hangup(tty);
|
||||
tty_kref_put(tty);
|
||||
}
|
||||
}
|
||||
if (test_bit(ASYNCB_INITIALIZED, &acm->port.flags))
|
||||
tty_port_tty_hangup(&acm->port, false);
|
||||
|
||||
return acm_resume(intf);
|
||||
}
|
||||
|
@ -210,7 +210,6 @@ struct digi_port {
|
||||
|
||||
/* Local Function Declarations */
|
||||
|
||||
static void digi_wakeup_write(struct usb_serial_port *port);
|
||||
static void digi_wakeup_write_lock(struct work_struct *work);
|
||||
static int digi_write_oob_command(struct usb_serial_port *port,
|
||||
unsigned char *buf, int count, int interruptible);
|
||||
@ -374,20 +373,10 @@ static void digi_wakeup_write_lock(struct work_struct *work)
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&priv->dp_port_lock, flags);
|
||||
digi_wakeup_write(port);
|
||||
tty_port_tty_wakeup(&port->port);
|
||||
spin_unlock_irqrestore(&priv->dp_port_lock, flags);
|
||||
}
|
||||
|
||||
static void digi_wakeup_write(struct usb_serial_port *port)
|
||||
{
|
||||
struct tty_struct *tty = tty_port_tty_get(&port->port);
|
||||
if (tty) {
|
||||
tty_wakeup(tty);
|
||||
tty_kref_put(tty);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Digi Write OOB Command
|
||||
*
|
||||
@ -1044,7 +1033,7 @@ static void digi_write_bulk_callback(struct urb *urb)
|
||||
}
|
||||
}
|
||||
/* wake up processes sleeping on writes immediately */
|
||||
digi_wakeup_write(port);
|
||||
tty_port_tty_wakeup(&port->port);
|
||||
/* also queue up a wakeup at scheduler time, in case we */
|
||||
/* lost the race in write_chan(). */
|
||||
schedule_work(&priv->dp_wakeup_work);
|
||||
@ -1522,7 +1511,7 @@ static int digi_read_oob_callback(struct urb *urb)
|
||||
/* port must be open to use tty struct */
|
||||
if (rts) {
|
||||
tty->hw_stopped = 0;
|
||||
digi_wakeup_write(port);
|
||||
tty_port_tty_wakeup(&port->port);
|
||||
}
|
||||
} else {
|
||||
priv->dp_modem_signals &= ~TIOCM_CTS;
|
||||
|
@ -564,7 +564,6 @@ static void edge_interrupt_callback(struct urb *urb)
|
||||
struct device *dev;
|
||||
struct edgeport_port *edge_port;
|
||||
struct usb_serial_port *port;
|
||||
struct tty_struct *tty;
|
||||
unsigned char *data = urb->transfer_buffer;
|
||||
int length = urb->actual_length;
|
||||
int bytes_avail;
|
||||
@ -643,12 +642,7 @@ static void edge_interrupt_callback(struct urb *urb)
|
||||
|
||||
/* tell the tty driver that something
|
||||
has changed */
|
||||
tty = tty_port_tty_get(
|
||||
&edge_port->port->port);
|
||||
if (tty) {
|
||||
tty_wakeup(tty);
|
||||
tty_kref_put(tty);
|
||||
}
|
||||
tty_port_tty_wakeup(&edge_port->port->port);
|
||||
/* Since we have more credit, check
|
||||
if more data can be sent */
|
||||
send_more_port_data(edge_serial,
|
||||
@ -737,7 +731,6 @@ static void edge_bulk_in_callback(struct urb *urb)
|
||||
static void edge_bulk_out_data_callback(struct urb *urb)
|
||||
{
|
||||
struct edgeport_port *edge_port = urb->context;
|
||||
struct tty_struct *tty;
|
||||
int status = urb->status;
|
||||
|
||||
if (status) {
|
||||
@ -746,14 +739,8 @@ static void edge_bulk_out_data_callback(struct urb *urb)
|
||||
__func__, status);
|
||||
}
|
||||
|
||||
tty = tty_port_tty_get(&edge_port->port->port);
|
||||
|
||||
if (tty && edge_port->open) {
|
||||
/* let the tty driver wakeup if it has a special
|
||||
write_wakeup function */
|
||||
tty_wakeup(tty);
|
||||
}
|
||||
tty_kref_put(tty);
|
||||
if (edge_port->open)
|
||||
tty_port_tty_wakeup(&edge_port->port->port);
|
||||
|
||||
/* Release the Write URB */
|
||||
edge_port->write_in_progress = false;
|
||||
@ -772,7 +759,6 @@ static void edge_bulk_out_data_callback(struct urb *urb)
|
||||
static void edge_bulk_out_cmd_callback(struct urb *urb)
|
||||
{
|
||||
struct edgeport_port *edge_port = urb->context;
|
||||
struct tty_struct *tty;
|
||||
int status = urb->status;
|
||||
|
||||
atomic_dec(&CmdUrbs);
|
||||
@ -793,13 +779,9 @@ static void edge_bulk_out_cmd_callback(struct urb *urb)
|
||||
return;
|
||||
}
|
||||
|
||||
/* Get pointer to tty */
|
||||
tty = tty_port_tty_get(&edge_port->port->port);
|
||||
|
||||
/* tell the tty driver that something has changed */
|
||||
if (tty && edge_port->open)
|
||||
tty_wakeup(tty);
|
||||
tty_kref_put(tty);
|
||||
if (edge_port->open)
|
||||
tty_port_tty_wakeup(&edge_port->port->port);
|
||||
|
||||
/* we have completed the command */
|
||||
edge_port->commandPending = false;
|
||||
|
@ -378,7 +378,6 @@ static void usa26_instat_callback(struct urb *urb)
|
||||
struct usb_serial *serial;
|
||||
struct usb_serial_port *port;
|
||||
struct keyspan_port_private *p_priv;
|
||||
struct tty_struct *tty;
|
||||
int old_dcd_state, err;
|
||||
int status = urb->status;
|
||||
|
||||
@ -421,12 +420,8 @@ static void usa26_instat_callback(struct urb *urb)
|
||||
p_priv->dcd_state = ((msg->gpia_dcd) ? 1 : 0);
|
||||
p_priv->ri_state = ((msg->ri) ? 1 : 0);
|
||||
|
||||
if (old_dcd_state != p_priv->dcd_state) {
|
||||
tty = tty_port_tty_get(&port->port);
|
||||
if (tty && !C_CLOCAL(tty))
|
||||
tty_hangup(tty);
|
||||
tty_kref_put(tty);
|
||||
}
|
||||
if (old_dcd_state != p_priv->dcd_state)
|
||||
tty_port_tty_hangup(&port->port, true);
|
||||
|
||||
/* Resubmit urb so we continue receiving */
|
||||
err = usb_submit_urb(urb, GFP_ATOMIC);
|
||||
@ -510,7 +505,6 @@ static void usa28_instat_callback(struct urb *urb)
|
||||
struct usb_serial *serial;
|
||||
struct usb_serial_port *port;
|
||||
struct keyspan_port_private *p_priv;
|
||||
struct tty_struct *tty;
|
||||
int old_dcd_state;
|
||||
int status = urb->status;
|
||||
|
||||
@ -551,12 +545,8 @@ static void usa28_instat_callback(struct urb *urb)
|
||||
p_priv->dcd_state = ((msg->dcd) ? 1 : 0);
|
||||
p_priv->ri_state = ((msg->ri) ? 1 : 0);
|
||||
|
||||
if (old_dcd_state != p_priv->dcd_state && old_dcd_state) {
|
||||
tty = tty_port_tty_get(&port->port);
|
||||
if (tty && !C_CLOCAL(tty))
|
||||
tty_hangup(tty);
|
||||
tty_kref_put(tty);
|
||||
}
|
||||
if (old_dcd_state != p_priv->dcd_state && old_dcd_state)
|
||||
tty_port_tty_hangup(&port->port, true);
|
||||
|
||||
/* Resubmit urb so we continue receiving */
|
||||
err = usb_submit_urb(urb, GFP_ATOMIC);
|
||||
@ -642,12 +632,8 @@ static void usa49_instat_callback(struct urb *urb)
|
||||
p_priv->dcd_state = ((msg->dcd) ? 1 : 0);
|
||||
p_priv->ri_state = ((msg->ri) ? 1 : 0);
|
||||
|
||||
if (old_dcd_state != p_priv->dcd_state && old_dcd_state) {
|
||||
struct tty_struct *tty = tty_port_tty_get(&port->port);
|
||||
if (tty && !C_CLOCAL(tty))
|
||||
tty_hangup(tty);
|
||||
tty_kref_put(tty);
|
||||
}
|
||||
if (old_dcd_state != p_priv->dcd_state && old_dcd_state)
|
||||
tty_port_tty_hangup(&port->port, true);
|
||||
|
||||
/* Resubmit urb so we continue receiving */
|
||||
err = usb_submit_urb(urb, GFP_ATOMIC);
|
||||
@ -851,7 +837,6 @@ static void usa90_instat_callback(struct urb *urb)
|
||||
struct usb_serial *serial;
|
||||
struct usb_serial_port *port;
|
||||
struct keyspan_port_private *p_priv;
|
||||
struct tty_struct *tty;
|
||||
int old_dcd_state, err;
|
||||
int status = urb->status;
|
||||
|
||||
@ -880,12 +865,8 @@ static void usa90_instat_callback(struct urb *urb)
|
||||
p_priv->dcd_state = ((msg->dcd) ? 1 : 0);
|
||||
p_priv->ri_state = ((msg->ri) ? 1 : 0);
|
||||
|
||||
if (old_dcd_state != p_priv->dcd_state && old_dcd_state) {
|
||||
tty = tty_port_tty_get(&port->port);
|
||||
if (tty && !C_CLOCAL(tty))
|
||||
tty_hangup(tty);
|
||||
tty_kref_put(tty);
|
||||
}
|
||||
if (old_dcd_state != p_priv->dcd_state && old_dcd_state)
|
||||
tty_port_tty_hangup(&port->port, true);
|
||||
|
||||
/* Resubmit urb so we continue receiving */
|
||||
err = usb_submit_urb(urb, GFP_ATOMIC);
|
||||
@ -953,12 +934,8 @@ static void usa67_instat_callback(struct urb *urb)
|
||||
p_priv->cts_state = ((msg->hskia_cts) ? 1 : 0);
|
||||
p_priv->dcd_state = ((msg->gpia_dcd) ? 1 : 0);
|
||||
|
||||
if (old_dcd_state != p_priv->dcd_state && old_dcd_state) {
|
||||
struct tty_struct *tty = tty_port_tty_get(&port->port);
|
||||
if (tty && !C_CLOCAL(tty))
|
||||
tty_hangup(tty);
|
||||
tty_kref_put(tty);
|
||||
}
|
||||
if (old_dcd_state != p_priv->dcd_state && old_dcd_state)
|
||||
tty_port_tty_hangup(&port->port, true);
|
||||
|
||||
/* Resubmit urb so we continue receiving */
|
||||
err = usb_submit_urb(urb, GFP_ATOMIC);
|
||||
|
@ -104,10 +104,8 @@ static void keyspan_pda_wakeup_write(struct work_struct *work)
|
||||
struct keyspan_pda_private *priv =
|
||||
container_of(work, struct keyspan_pda_private, wakeup_work);
|
||||
struct usb_serial_port *port = priv->port;
|
||||
struct tty_struct *tty = tty_port_tty_get(&port->port);
|
||||
if (tty)
|
||||
tty_wakeup(tty);
|
||||
tty_kref_put(tty);
|
||||
|
||||
tty_port_tty_wakeup(&port->port);
|
||||
}
|
||||
|
||||
static void keyspan_pda_request_unthrottle(struct work_struct *work)
|
||||
|
@ -932,7 +932,6 @@ static void mos7720_bulk_in_callback(struct urb *urb)
|
||||
static void mos7720_bulk_out_data_callback(struct urb *urb)
|
||||
{
|
||||
struct moschip_port *mos7720_port;
|
||||
struct tty_struct *tty;
|
||||
int status = urb->status;
|
||||
|
||||
if (status) {
|
||||
@ -946,11 +945,8 @@ static void mos7720_bulk_out_data_callback(struct urb *urb)
|
||||
return ;
|
||||
}
|
||||
|
||||
tty = tty_port_tty_get(&mos7720_port->port->port);
|
||||
|
||||
if (tty && mos7720_port->open)
|
||||
tty_wakeup(tty);
|
||||
tty_kref_put(tty);
|
||||
if (mos7720_port->open)
|
||||
tty_port_tty_wakeup(&mos7720_port->port->port);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -816,7 +816,6 @@ static void mos7840_bulk_out_data_callback(struct urb *urb)
|
||||
{
|
||||
struct moschip_port *mos7840_port;
|
||||
struct usb_serial_port *port;
|
||||
struct tty_struct *tty;
|
||||
int status = urb->status;
|
||||
int i;
|
||||
|
||||
@ -839,10 +838,8 @@ static void mos7840_bulk_out_data_callback(struct urb *urb)
|
||||
if (mos7840_port_paranoia_check(port, __func__))
|
||||
return;
|
||||
|
||||
tty = tty_port_tty_get(&port->port);
|
||||
if (tty && mos7840_port->open)
|
||||
tty_wakeup(tty);
|
||||
tty_kref_put(tty);
|
||||
if (mos7840_port->open)
|
||||
tty_port_tty_wakeup(&port->port);
|
||||
|
||||
}
|
||||
|
||||
|
@ -1537,13 +1537,8 @@ static void option_instat_callback(struct urb *urb)
|
||||
portdata->dsr_state = ((signals & 0x02) ? 1 : 0);
|
||||
portdata->ri_state = ((signals & 0x08) ? 1 : 0);
|
||||
|
||||
if (old_dcd_state && !portdata->dcd_state) {
|
||||
struct tty_struct *tty =
|
||||
tty_port_tty_get(&port->port);
|
||||
if (tty && !C_CLOCAL(tty))
|
||||
tty_hangup(tty);
|
||||
tty_kref_put(tty);
|
||||
}
|
||||
if (old_dcd_state && !portdata->dcd_state)
|
||||
tty_port_tty_hangup(&port->port, true);
|
||||
} else {
|
||||
dev_dbg(dev, "%s: type %x req %x\n", __func__,
|
||||
req_pkt->bRequestType, req_pkt->bRequest);
|
||||
|
@ -116,7 +116,6 @@ struct qt2_serial_private {
|
||||
};
|
||||
|
||||
struct qt2_port_private {
|
||||
bool is_open;
|
||||
u8 device_port;
|
||||
|
||||
spinlock_t urb_lock;
|
||||
@ -397,7 +396,6 @@ static int qt2_open(struct tty_struct *tty, struct usb_serial_port *port)
|
||||
return status;
|
||||
}
|
||||
|
||||
port_priv->is_open = true;
|
||||
port_priv->device_port = (u8) device_port;
|
||||
|
||||
if (tty)
|
||||
@ -417,8 +415,6 @@ static void qt2_close(struct usb_serial_port *port)
|
||||
serial = port->serial;
|
||||
port_priv = usb_get_serial_port_data(port);
|
||||
|
||||
port_priv->is_open = false;
|
||||
|
||||
spin_lock_irqsave(&port_priv->urb_lock, flags);
|
||||
usb_kill_urb(port_priv->write_urb);
|
||||
port_priv->urb_in_use = false;
|
||||
@ -664,9 +660,7 @@ void qt2_process_read_urb(struct urb *urb)
|
||||
__func__);
|
||||
break;
|
||||
}
|
||||
|
||||
if (port_priv->is_open)
|
||||
tty_flip_buffer_push(&port->port);
|
||||
tty_flip_buffer_push(&port->port);
|
||||
|
||||
newport = *(ch + 3);
|
||||
|
||||
@ -709,8 +703,7 @@ void qt2_process_read_urb(struct urb *urb)
|
||||
tty_insert_flip_string(&port->port, ch, 1);
|
||||
}
|
||||
|
||||
if (port_priv->is_open)
|
||||
tty_flip_buffer_push(&port->port);
|
||||
tty_flip_buffer_push(&port->port);
|
||||
}
|
||||
|
||||
static void qt2_write_bulk_callback(struct urb *urb)
|
||||
@ -910,12 +903,6 @@ static void qt2_break_ctl(struct tty_struct *tty, int break_state)
|
||||
|
||||
port_priv = usb_get_serial_port_data(port);
|
||||
|
||||
if (!port_priv->is_open) {
|
||||
dev_err(&port->dev,
|
||||
"%s - port is not open\n", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
val = (break_state == -1) ? 1 : 0;
|
||||
|
||||
status = qt2_control_msg(port->serial->dev, QT2_BREAK_CONTROL,
|
||||
|
@ -628,7 +628,6 @@ static void sierra_instat_callback(struct urb *urb)
|
||||
unsigned char signals = *((unsigned char *)
|
||||
urb->transfer_buffer +
|
||||
sizeof(struct usb_ctrlrequest));
|
||||
struct tty_struct *tty;
|
||||
|
||||
dev_dbg(&port->dev, "%s: signal x%x\n", __func__,
|
||||
signals);
|
||||
@ -639,11 +638,8 @@ static void sierra_instat_callback(struct urb *urb)
|
||||
portdata->dsr_state = ((signals & 0x02) ? 1 : 0);
|
||||
portdata->ri_state = ((signals & 0x08) ? 1 : 0);
|
||||
|
||||
tty = tty_port_tty_get(&port->port);
|
||||
if (tty && !C_CLOCAL(tty) &&
|
||||
old_dcd_state && !portdata->dcd_state)
|
||||
tty_hangup(tty);
|
||||
tty_kref_put(tty);
|
||||
if (old_dcd_state && !portdata->dcd_state)
|
||||
tty_port_tty_hangup(&port->port, true);
|
||||
} else {
|
||||
dev_dbg(&port->dev, "%s: type %x req %x\n",
|
||||
__func__, req_pkt->bRequestType,
|
||||
|
@ -1229,7 +1229,6 @@ static void ti_send(struct ti_port *tport)
|
||||
{
|
||||
int count, result;
|
||||
struct usb_serial_port *port = tport->tp_port;
|
||||
struct tty_struct *tty = tty_port_tty_get(&port->port); /* FIXME */
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&tport->tp_lock, flags);
|
||||
@ -1270,14 +1269,12 @@ static void ti_send(struct ti_port *tport)
|
||||
}
|
||||
|
||||
/* more room in the buffer for new writes, wakeup */
|
||||
if (tty)
|
||||
tty_wakeup(tty);
|
||||
tty_kref_put(tty);
|
||||
tty_port_tty_wakeup(&port->port);
|
||||
|
||||
wake_up_interruptible(&tport->tp_write_wait);
|
||||
return;
|
||||
unlock:
|
||||
spin_unlock_irqrestore(&tport->tp_lock, flags);
|
||||
tty_kref_put(tty);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -542,16 +542,8 @@ static void usb_serial_port_work(struct work_struct *work)
|
||||
{
|
||||
struct usb_serial_port *port =
|
||||
container_of(work, struct usb_serial_port, work);
|
||||
struct tty_struct *tty;
|
||||
|
||||
tty = tty_port_tty_get(&port->port);
|
||||
if (!tty)
|
||||
return;
|
||||
|
||||
dev_dbg(tty->dev, "%s - port %d\n", __func__, port->number);
|
||||
|
||||
tty_wakeup(tty);
|
||||
tty_kref_put(tty);
|
||||
tty_port_tty_wakeup(&port->port);
|
||||
}
|
||||
|
||||
static void kill_traffic(struct usb_serial_port *port)
|
||||
|
@ -203,6 +203,9 @@ struct amba_pl011_data {
|
||||
bool (*dma_filter)(struct dma_chan *chan, void *filter_param);
|
||||
void *dma_rx_param;
|
||||
void *dma_tx_param;
|
||||
bool dma_rx_poll_enable;
|
||||
unsigned int dma_rx_poll_rate;
|
||||
unsigned int dma_rx_poll_timeout;
|
||||
void (*init) (void);
|
||||
void (*exit) (void);
|
||||
};
|
||||
|
@ -86,10 +86,6 @@ struct sccnxp_pdata {
|
||||
const u32 mctrl_cfg[SCCNXP_MAX_UARTS];
|
||||
/* Timer value for polling mode (usecs) */
|
||||
const unsigned int poll_time_us;
|
||||
/* Called during startup */
|
||||
void (*init)(void);
|
||||
/* Called before finish */
|
||||
void (*exit)(void);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
260
include/linux/serial_s3c.h
Normal file
260
include/linux/serial_s3c.h
Normal file
@ -0,0 +1,260 @@
|
||||
/*
|
||||
* Internal header file for Samsung S3C2410 serial ports (UART0-2)
|
||||
*
|
||||
* Copyright (C) 2002 Shane Nay (shane@minirl.com)
|
||||
*
|
||||
* Additional defines, Copyright 2003 Simtec Electronics (linux@simtec.co.uk)
|
||||
*
|
||||
* Adapted from:
|
||||
*
|
||||
* Internal header file for MX1ADS serial ports (UART1 & 2)
|
||||
*
|
||||
* Copyright (C) 2002 Shane Nay (shane@minirl.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef __ASM_ARM_REGS_SERIAL_H
|
||||
#define __ASM_ARM_REGS_SERIAL_H
|
||||
|
||||
#define S3C2410_URXH (0x24)
|
||||
#define S3C2410_UTXH (0x20)
|
||||
#define S3C2410_ULCON (0x00)
|
||||
#define S3C2410_UCON (0x04)
|
||||
#define S3C2410_UFCON (0x08)
|
||||
#define S3C2410_UMCON (0x0C)
|
||||
#define S3C2410_UBRDIV (0x28)
|
||||
#define S3C2410_UTRSTAT (0x10)
|
||||
#define S3C2410_UERSTAT (0x14)
|
||||
#define S3C2410_UFSTAT (0x18)
|
||||
#define S3C2410_UMSTAT (0x1C)
|
||||
|
||||
#define S3C2410_LCON_CFGMASK ((0xF<<3)|(0x3))
|
||||
|
||||
#define S3C2410_LCON_CS5 (0x0)
|
||||
#define S3C2410_LCON_CS6 (0x1)
|
||||
#define S3C2410_LCON_CS7 (0x2)
|
||||
#define S3C2410_LCON_CS8 (0x3)
|
||||
#define S3C2410_LCON_CSMASK (0x3)
|
||||
|
||||
#define S3C2410_LCON_PNONE (0x0)
|
||||
#define S3C2410_LCON_PEVEN (0x5 << 3)
|
||||
#define S3C2410_LCON_PODD (0x4 << 3)
|
||||
#define S3C2410_LCON_PMASK (0x7 << 3)
|
||||
|
||||
#define S3C2410_LCON_STOPB (1<<2)
|
||||
#define S3C2410_LCON_IRM (1<<6)
|
||||
|
||||
#define S3C2440_UCON_CLKMASK (3<<10)
|
||||
#define S3C2440_UCON_CLKSHIFT (10)
|
||||
#define S3C2440_UCON_PCLK (0<<10)
|
||||
#define S3C2440_UCON_UCLK (1<<10)
|
||||
#define S3C2440_UCON_PCLK2 (2<<10)
|
||||
#define S3C2440_UCON_FCLK (3<<10)
|
||||
#define S3C2443_UCON_EPLL (3<<10)
|
||||
|
||||
#define S3C6400_UCON_CLKMASK (3<<10)
|
||||
#define S3C6400_UCON_CLKSHIFT (10)
|
||||
#define S3C6400_UCON_PCLK (0<<10)
|
||||
#define S3C6400_UCON_PCLK2 (2<<10)
|
||||
#define S3C6400_UCON_UCLK0 (1<<10)
|
||||
#define S3C6400_UCON_UCLK1 (3<<10)
|
||||
|
||||
#define S3C2440_UCON2_FCLK_EN (1<<15)
|
||||
#define S3C2440_UCON0_DIVMASK (15 << 12)
|
||||
#define S3C2440_UCON1_DIVMASK (15 << 12)
|
||||
#define S3C2440_UCON2_DIVMASK (7 << 12)
|
||||
#define S3C2440_UCON_DIVSHIFT (12)
|
||||
|
||||
#define S3C2412_UCON_CLKMASK (3<<10)
|
||||
#define S3C2412_UCON_CLKSHIFT (10)
|
||||
#define S3C2412_UCON_UCLK (1<<10)
|
||||
#define S3C2412_UCON_USYSCLK (3<<10)
|
||||
#define S3C2412_UCON_PCLK (0<<10)
|
||||
#define S3C2412_UCON_PCLK2 (2<<10)
|
||||
|
||||
#define S3C2410_UCON_CLKMASK (1 << 10)
|
||||
#define S3C2410_UCON_CLKSHIFT (10)
|
||||
#define S3C2410_UCON_UCLK (1<<10)
|
||||
#define S3C2410_UCON_SBREAK (1<<4)
|
||||
|
||||
#define S3C2410_UCON_TXILEVEL (1<<9)
|
||||
#define S3C2410_UCON_RXILEVEL (1<<8)
|
||||
#define S3C2410_UCON_TXIRQMODE (1<<2)
|
||||
#define S3C2410_UCON_RXIRQMODE (1<<0)
|
||||
#define S3C2410_UCON_RXFIFO_TOI (1<<7)
|
||||
#define S3C2443_UCON_RXERR_IRQEN (1<<6)
|
||||
#define S3C2443_UCON_LOOPBACK (1<<5)
|
||||
|
||||
#define S3C2410_UCON_DEFAULT (S3C2410_UCON_TXILEVEL | \
|
||||
S3C2410_UCON_RXILEVEL | \
|
||||
S3C2410_UCON_TXIRQMODE | \
|
||||
S3C2410_UCON_RXIRQMODE | \
|
||||
S3C2410_UCON_RXFIFO_TOI)
|
||||
|
||||
#define S3C2410_UFCON_FIFOMODE (1<<0)
|
||||
#define S3C2410_UFCON_TXTRIG0 (0<<6)
|
||||
#define S3C2410_UFCON_RXTRIG8 (1<<4)
|
||||
#define S3C2410_UFCON_RXTRIG12 (2<<4)
|
||||
|
||||
/* S3C2440 FIFO trigger levels */
|
||||
#define S3C2440_UFCON_RXTRIG1 (0<<4)
|
||||
#define S3C2440_UFCON_RXTRIG8 (1<<4)
|
||||
#define S3C2440_UFCON_RXTRIG16 (2<<4)
|
||||
#define S3C2440_UFCON_RXTRIG32 (3<<4)
|
||||
|
||||
#define S3C2440_UFCON_TXTRIG0 (0<<6)
|
||||
#define S3C2440_UFCON_TXTRIG16 (1<<6)
|
||||
#define S3C2440_UFCON_TXTRIG32 (2<<6)
|
||||
#define S3C2440_UFCON_TXTRIG48 (3<<6)
|
||||
|
||||
#define S3C2410_UFCON_RESETBOTH (3<<1)
|
||||
#define S3C2410_UFCON_RESETTX (1<<2)
|
||||
#define S3C2410_UFCON_RESETRX (1<<1)
|
||||
|
||||
#define S3C2410_UFCON_DEFAULT (S3C2410_UFCON_FIFOMODE | \
|
||||
S3C2410_UFCON_TXTRIG0 | \
|
||||
S3C2410_UFCON_RXTRIG8 )
|
||||
|
||||
#define S3C2410_UMCOM_AFC (1<<4)
|
||||
#define S3C2410_UMCOM_RTS_LOW (1<<0)
|
||||
|
||||
#define S3C2412_UMCON_AFC_63 (0<<5) /* same as s3c2443 */
|
||||
#define S3C2412_UMCON_AFC_56 (1<<5)
|
||||
#define S3C2412_UMCON_AFC_48 (2<<5)
|
||||
#define S3C2412_UMCON_AFC_40 (3<<5)
|
||||
#define S3C2412_UMCON_AFC_32 (4<<5)
|
||||
#define S3C2412_UMCON_AFC_24 (5<<5)
|
||||
#define S3C2412_UMCON_AFC_16 (6<<5)
|
||||
#define S3C2412_UMCON_AFC_8 (7<<5)
|
||||
|
||||
#define S3C2410_UFSTAT_TXFULL (1<<9)
|
||||
#define S3C2410_UFSTAT_RXFULL (1<<8)
|
||||
#define S3C2410_UFSTAT_TXMASK (15<<4)
|
||||
#define S3C2410_UFSTAT_TXSHIFT (4)
|
||||
#define S3C2410_UFSTAT_RXMASK (15<<0)
|
||||
#define S3C2410_UFSTAT_RXSHIFT (0)
|
||||
|
||||
/* UFSTAT S3C2443 same as S3C2440 */
|
||||
#define S3C2440_UFSTAT_TXFULL (1<<14)
|
||||
#define S3C2440_UFSTAT_RXFULL (1<<6)
|
||||
#define S3C2440_UFSTAT_TXSHIFT (8)
|
||||
#define S3C2440_UFSTAT_RXSHIFT (0)
|
||||
#define S3C2440_UFSTAT_TXMASK (63<<8)
|
||||
#define S3C2440_UFSTAT_RXMASK (63)
|
||||
|
||||
#define S3C2410_UTRSTAT_TXE (1<<2)
|
||||
#define S3C2410_UTRSTAT_TXFE (1<<1)
|
||||
#define S3C2410_UTRSTAT_RXDR (1<<0)
|
||||
|
||||
#define S3C2410_UERSTAT_OVERRUN (1<<0)
|
||||
#define S3C2410_UERSTAT_FRAME (1<<2)
|
||||
#define S3C2410_UERSTAT_BREAK (1<<3)
|
||||
#define S3C2443_UERSTAT_PARITY (1<<1)
|
||||
|
||||
#define S3C2410_UERSTAT_ANY (S3C2410_UERSTAT_OVERRUN | \
|
||||
S3C2410_UERSTAT_FRAME | \
|
||||
S3C2410_UERSTAT_BREAK)
|
||||
|
||||
#define S3C2410_UMSTAT_CTS (1<<0)
|
||||
#define S3C2410_UMSTAT_DeltaCTS (1<<2)
|
||||
|
||||
#define S3C2443_DIVSLOT (0x2C)
|
||||
|
||||
/* S3C64XX interrupt registers. */
|
||||
#define S3C64XX_UINTP 0x30
|
||||
#define S3C64XX_UINTSP 0x34
|
||||
#define S3C64XX_UINTM 0x38
|
||||
|
||||
#define S3C64XX_UINTM_RXD (0)
|
||||
#define S3C64XX_UINTM_TXD (2)
|
||||
#define S3C64XX_UINTM_RXD_MSK (1 << S3C64XX_UINTM_RXD)
|
||||
#define S3C64XX_UINTM_TXD_MSK (1 << S3C64XX_UINTM_TXD)
|
||||
|
||||
/* Following are specific to S5PV210 */
|
||||
#define S5PV210_UCON_CLKMASK (1<<10)
|
||||
#define S5PV210_UCON_CLKSHIFT (10)
|
||||
#define S5PV210_UCON_PCLK (0<<10)
|
||||
#define S5PV210_UCON_UCLK (1<<10)
|
||||
|
||||
#define S5PV210_UFCON_TXTRIG0 (0<<8)
|
||||
#define S5PV210_UFCON_TXTRIG4 (1<<8)
|
||||
#define S5PV210_UFCON_TXTRIG8 (2<<8)
|
||||
#define S5PV210_UFCON_TXTRIG16 (3<<8)
|
||||
#define S5PV210_UFCON_TXTRIG32 (4<<8)
|
||||
#define S5PV210_UFCON_TXTRIG64 (5<<8)
|
||||
#define S5PV210_UFCON_TXTRIG128 (6<<8)
|
||||
#define S5PV210_UFCON_TXTRIG256 (7<<8)
|
||||
|
||||
#define S5PV210_UFCON_RXTRIG1 (0<<4)
|
||||
#define S5PV210_UFCON_RXTRIG4 (1<<4)
|
||||
#define S5PV210_UFCON_RXTRIG8 (2<<4)
|
||||
#define S5PV210_UFCON_RXTRIG16 (3<<4)
|
||||
#define S5PV210_UFCON_RXTRIG32 (4<<4)
|
||||
#define S5PV210_UFCON_RXTRIG64 (5<<4)
|
||||
#define S5PV210_UFCON_RXTRIG128 (6<<4)
|
||||
#define S5PV210_UFCON_RXTRIG256 (7<<4)
|
||||
|
||||
#define S5PV210_UFSTAT_TXFULL (1<<24)
|
||||
#define S5PV210_UFSTAT_RXFULL (1<<8)
|
||||
#define S5PV210_UFSTAT_TXMASK (255<<16)
|
||||
#define S5PV210_UFSTAT_TXSHIFT (16)
|
||||
#define S5PV210_UFSTAT_RXMASK (255<<0)
|
||||
#define S5PV210_UFSTAT_RXSHIFT (0)
|
||||
|
||||
#define S3C2410_UCON_CLKSEL0 (1 << 0)
|
||||
#define S3C2410_UCON_CLKSEL1 (1 << 1)
|
||||
#define S3C2410_UCON_CLKSEL2 (1 << 2)
|
||||
#define S3C2410_UCON_CLKSEL3 (1 << 3)
|
||||
|
||||
/* Default values for s5pv210 UCON and UFCON uart registers */
|
||||
#define S5PV210_UCON_DEFAULT (S3C2410_UCON_TXILEVEL | \
|
||||
S3C2410_UCON_RXILEVEL | \
|
||||
S3C2410_UCON_TXIRQMODE | \
|
||||
S3C2410_UCON_RXIRQMODE | \
|
||||
S3C2410_UCON_RXFIFO_TOI | \
|
||||
S3C2443_UCON_RXERR_IRQEN)
|
||||
|
||||
#define S5PV210_UFCON_DEFAULT (S3C2410_UFCON_FIFOMODE | \
|
||||
S5PV210_UFCON_TXTRIG4 | \
|
||||
S5PV210_UFCON_RXTRIG4)
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
|
||||
/* configuration structure for per-machine configurations for the
|
||||
* serial port
|
||||
*
|
||||
* the pointer is setup by the machine specific initialisation from the
|
||||
* arch/arm/mach-s3c2410/ directory.
|
||||
*/
|
||||
|
||||
struct s3c2410_uartcfg {
|
||||
unsigned char hwport; /* hardware port number */
|
||||
unsigned char unused;
|
||||
unsigned short flags;
|
||||
upf_t uart_flags; /* default uart flags */
|
||||
unsigned int clk_sel;
|
||||
|
||||
unsigned int has_fracval;
|
||||
|
||||
unsigned long ucon; /* value of ucon for port */
|
||||
unsigned long ulcon; /* value of ulcon for port */
|
||||
unsigned long ufcon; /* value of ufcon for port */
|
||||
};
|
||||
|
||||
#endif /* __ASSEMBLY__ */
|
||||
|
||||
#endif /* __ASM_ARM_REGS_SERIAL_H */
|
||||
|
@ -255,9 +255,9 @@ struct tty_struct {
|
||||
int count;
|
||||
struct winsize winsize; /* termios mutex */
|
||||
unsigned char stopped:1, hw_stopped:1, flow_stopped:1, packet:1;
|
||||
unsigned char warned:1;
|
||||
unsigned char ctrl_status; /* ctrl_lock */
|
||||
unsigned int receive_room; /* Bytes free for queue */
|
||||
int flow_change;
|
||||
|
||||
struct tty_struct *link;
|
||||
struct fasync_struct *fasync;
|
||||
@ -315,9 +315,25 @@ struct tty_file_private {
|
||||
#define TTY_NO_WRITE_SPLIT 17 /* Preserve write boundaries to driver */
|
||||
#define TTY_HUPPED 18 /* Post driver->hangup() */
|
||||
#define TTY_HUPPING 21 /* ->hangup() in progress */
|
||||
#define TTY_LDISC_HALTED 22 /* Line discipline is halted */
|
||||
|
||||
#define TTY_WRITE_FLUSH(tty) tty_write_flush((tty))
|
||||
|
||||
/* Values for tty->flow_change */
|
||||
#define TTY_THROTTLE_SAFE 1
|
||||
#define TTY_UNTHROTTLE_SAFE 2
|
||||
|
||||
static inline void __tty_set_flow_change(struct tty_struct *tty, int val)
|
||||
{
|
||||
tty->flow_change = val;
|
||||
}
|
||||
|
||||
static inline void tty_set_flow_change(struct tty_struct *tty, int val)
|
||||
{
|
||||
tty->flow_change = val;
|
||||
smp_mb();
|
||||
}
|
||||
|
||||
#ifdef CONFIG_TTY
|
||||
extern void console_init(void);
|
||||
extern void tty_kref_put(struct tty_struct *tty);
|
||||
@ -400,6 +416,8 @@ extern int tty_write_room(struct tty_struct *tty);
|
||||
extern void tty_driver_flush_buffer(struct tty_struct *tty);
|
||||
extern void tty_throttle(struct tty_struct *tty);
|
||||
extern void tty_unthrottle(struct tty_struct *tty);
|
||||
extern int tty_throttle_safe(struct tty_struct *tty);
|
||||
extern int tty_unthrottle_safe(struct tty_struct *tty);
|
||||
extern int tty_do_resize(struct tty_struct *tty, struct winsize *ws);
|
||||
extern void tty_driver_remove_tty(struct tty_driver *driver,
|
||||
struct tty_struct *tty);
|
||||
@ -419,13 +437,28 @@ extern void tty_flush_to_ldisc(struct tty_struct *tty);
|
||||
extern void tty_buffer_free_all(struct tty_port *port);
|
||||
extern void tty_buffer_flush(struct tty_struct *tty);
|
||||
extern void tty_buffer_init(struct tty_port *port);
|
||||
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);
|
||||
extern void tty_termios_encode_baud_rate(struct ktermios *termios,
|
||||
speed_t ibaud, speed_t obaud);
|
||||
extern void tty_encode_baud_rate(struct tty_struct *tty,
|
||||
speed_t ibaud, speed_t obaud);
|
||||
|
||||
/**
|
||||
* tty_get_baud_rate - get tty bit rates
|
||||
* @tty: tty to query
|
||||
*
|
||||
* Returns the baud rate as an integer for this terminal. The
|
||||
* termios lock must be held by the caller and the terminal bit
|
||||
* flags may be updated.
|
||||
*
|
||||
* Locking: none
|
||||
*/
|
||||
static inline speed_t tty_get_baud_rate(struct tty_struct *tty)
|
||||
{
|
||||
return tty_termios_baud_rate(&tty->termios);
|
||||
}
|
||||
|
||||
extern void tty_termios_copy_hw(struct ktermios *new, struct ktermios *old);
|
||||
extern int tty_termios_hw_change(struct ktermios *a, struct ktermios *b);
|
||||
extern int tty_set_termios(struct tty_struct *tty, struct ktermios *kt);
|
||||
@ -502,6 +535,8 @@ extern int tty_port_carrier_raised(struct tty_port *port);
|
||||
extern void tty_port_raise_dtr_rts(struct tty_port *port);
|
||||
extern void tty_port_lower_dtr_rts(struct tty_port *port);
|
||||
extern void tty_port_hangup(struct tty_port *port);
|
||||
extern void tty_port_tty_hangup(struct tty_port *port, bool check_clocal);
|
||||
extern void tty_port_tty_wakeup(struct tty_port *port);
|
||||
extern int tty_port_block_til_ready(struct tty_port *port,
|
||||
struct tty_struct *tty, struct file *filp);
|
||||
extern int tty_port_close_start(struct tty_port *port,
|
||||
@ -526,8 +561,6 @@ extern void tty_ldisc_release(struct tty_struct *tty, struct tty_struct *o_tty);
|
||||
extern void tty_ldisc_init(struct tty_struct *tty);
|
||||
extern void tty_ldisc_deinit(struct tty_struct *tty);
|
||||
extern void tty_ldisc_begin(void);
|
||||
/* This last one is just for the tty layer internals and shouldn't be used elsewhere */
|
||||
extern void tty_ldisc_enable(struct tty_struct *tty);
|
||||
|
||||
|
||||
/* n_tty.c */
|
||||
|
@ -9,89 +9,89 @@
|
||||
*
|
||||
* int (*open)(struct tty_struct *);
|
||||
*
|
||||
* This function is called when the line discipline is associated
|
||||
* with the tty. The line discipline can use this as an
|
||||
* opportunity to initialize any state needed by the ldisc routines.
|
||||
*
|
||||
* This function is called when the line discipline is associated
|
||||
* with the tty. The line discipline can use this as an
|
||||
* opportunity to initialize any state needed by the ldisc routines.
|
||||
*
|
||||
* void (*close)(struct tty_struct *);
|
||||
*
|
||||
* This function is called when the line discipline is being
|
||||
* shutdown, either because the tty is being closed or because
|
||||
* the tty is being changed to use a new line discipline
|
||||
*
|
||||
* shutdown, either because the tty is being closed or because
|
||||
* the tty is being changed to use a new line discipline
|
||||
*
|
||||
* void (*flush_buffer)(struct tty_struct *tty);
|
||||
*
|
||||
* This function instructs the line discipline to clear its
|
||||
* buffers of any input characters it may have queued to be
|
||||
* delivered to the user mode process.
|
||||
*
|
||||
* This function instructs the line discipline to clear its
|
||||
* buffers of any input characters it may have queued to be
|
||||
* delivered to the user mode process.
|
||||
*
|
||||
* ssize_t (*chars_in_buffer)(struct tty_struct *tty);
|
||||
*
|
||||
* This function returns the number of input characters the line
|
||||
* This function returns the number of input characters the line
|
||||
* discipline may have queued up to be delivered to the user mode
|
||||
* process.
|
||||
*
|
||||
*
|
||||
* ssize_t (*read)(struct tty_struct * tty, struct file * file,
|
||||
* unsigned char * buf, size_t nr);
|
||||
*
|
||||
* This function is called when the user requests to read from
|
||||
* the tty. The line discipline will return whatever characters
|
||||
* it has buffered up for the user. If this function is not
|
||||
* defined, the user will receive an EIO error.
|
||||
*
|
||||
* ssize_t (*write)(struct tty_struct * tty, struct file * file,
|
||||
* const unsigned char * buf, size_t nr);
|
||||
* This function is called when the user requests to read from
|
||||
* the tty. The line discipline will return whatever characters
|
||||
* it has buffered up for the user. If this function is not
|
||||
* defined, the user will receive an EIO error.
|
||||
*
|
||||
* ssize_t (*write)(struct tty_struct * tty, struct file * file,
|
||||
* const unsigned char * buf, size_t nr);
|
||||
*
|
||||
* This function is called when the user requests to write to the
|
||||
* tty. The line discipline will deliver the characters to the
|
||||
* low-level tty device for transmission, optionally performing
|
||||
* some processing on the characters first. If this function is
|
||||
* not defined, the user will receive an EIO error.
|
||||
*
|
||||
* This function is called when the user requests to write to the
|
||||
* tty. The line discipline will deliver the characters to the
|
||||
* low-level tty device for transmission, optionally performing
|
||||
* some processing on the characters first. If this function is
|
||||
* not defined, the user will receive an EIO error.
|
||||
*
|
||||
* int (*ioctl)(struct tty_struct * tty, struct file * file,
|
||||
* unsigned int cmd, unsigned long arg);
|
||||
* unsigned int cmd, unsigned long arg);
|
||||
*
|
||||
* This function is called when the user requests an ioctl which
|
||||
* is not handled by the tty layer or the low-level tty driver.
|
||||
* It is intended for ioctls which affect line discpline
|
||||
* operation. Note that the search order for ioctls is (1) tty
|
||||
* layer, (2) tty low-level driver, (3) line discpline. So a
|
||||
* low-level driver can "grab" an ioctl request before the line
|
||||
* discpline has a chance to see it.
|
||||
*
|
||||
* long (*compat_ioctl)(struct tty_struct * tty, struct file * file,
|
||||
* unsigned int cmd, unsigned long arg);
|
||||
* is not handled by the tty layer or the low-level tty driver.
|
||||
* It is intended for ioctls which affect line discpline
|
||||
* operation. Note that the search order for ioctls is (1) tty
|
||||
* layer, (2) tty low-level driver, (3) line discpline. So a
|
||||
* low-level driver can "grab" an ioctl request before the line
|
||||
* discpline has a chance to see it.
|
||||
*
|
||||
* Process ioctl calls from 32-bit process on 64-bit system
|
||||
* long (*compat_ioctl)(struct tty_struct * tty, struct file * file,
|
||||
* unsigned int cmd, unsigned long arg);
|
||||
*
|
||||
* Process ioctl calls from 32-bit process on 64-bit system
|
||||
*
|
||||
* void (*set_termios)(struct tty_struct *tty, struct ktermios * old);
|
||||
*
|
||||
* This function notifies the line discpline that a change has
|
||||
* been made to the termios structure.
|
||||
*
|
||||
* int (*poll)(struct tty_struct * tty, struct file * file,
|
||||
* poll_table *wait);
|
||||
* This function notifies the line discpline that a change has
|
||||
* been made to the termios structure.
|
||||
*
|
||||
* This function is called when a user attempts to select/poll on a
|
||||
* tty device. It is solely the responsibility of the line
|
||||
* discipline to handle poll requests.
|
||||
* int (*poll)(struct tty_struct * tty, struct file * file,
|
||||
* poll_table *wait);
|
||||
*
|
||||
* This function is called when a user attempts to select/poll on a
|
||||
* tty device. It is solely the responsibility of the line
|
||||
* discipline to handle poll requests.
|
||||
*
|
||||
* void (*receive_buf)(struct tty_struct *, const unsigned char *cp,
|
||||
* char *fp, int count);
|
||||
* char *fp, int count);
|
||||
*
|
||||
* This function is called by the low-level tty driver to send
|
||||
* characters received by the hardware to the line discpline for
|
||||
* processing. <cp> is a pointer to the buffer of input
|
||||
* character received by the device. <fp> is a pointer to a
|
||||
* pointer of flag bytes which indicate whether a character was
|
||||
* received with a parity error, etc.
|
||||
*
|
||||
* This function is called by the low-level tty driver to send
|
||||
* characters received by the hardware to the line discpline for
|
||||
* processing. <cp> is a pointer to the buffer of input
|
||||
* character received by the device. <fp> is a pointer to a
|
||||
* pointer of flag bytes which indicate whether a character was
|
||||
* received with a parity error, etc.
|
||||
*
|
||||
* void (*write_wakeup)(struct tty_struct *);
|
||||
*
|
||||
* This function is called by the low-level tty driver to signal
|
||||
* that line discpline should try to send more characters to the
|
||||
* low-level driver for transmission. If the line discpline does
|
||||
* not have any more data to send, it can just return.
|
||||
* This function is called by the low-level tty driver to signal
|
||||
* that line discpline should try to send more characters to the
|
||||
* low-level driver for transmission. If the line discpline does
|
||||
* not have any more data to send, it can just return.
|
||||
*
|
||||
* int (*hangup)(struct tty_struct *)
|
||||
*
|
||||
@ -115,7 +115,7 @@ struct tty_ldisc_ops {
|
||||
char *name;
|
||||
int num;
|
||||
int flags;
|
||||
|
||||
|
||||
/*
|
||||
* The following routines are called from above.
|
||||
*/
|
||||
@ -123,19 +123,19 @@ struct tty_ldisc_ops {
|
||||
void (*close)(struct tty_struct *);
|
||||
void (*flush_buffer)(struct tty_struct *tty);
|
||||
ssize_t (*chars_in_buffer)(struct tty_struct *tty);
|
||||
ssize_t (*read)(struct tty_struct * tty, struct file * file,
|
||||
unsigned char __user * buf, size_t nr);
|
||||
ssize_t (*write)(struct tty_struct * tty, struct file * file,
|
||||
const unsigned char * buf, size_t nr);
|
||||
int (*ioctl)(struct tty_struct * tty, struct file * file,
|
||||
ssize_t (*read)(struct tty_struct *tty, struct file *file,
|
||||
unsigned char __user *buf, size_t nr);
|
||||
ssize_t (*write)(struct tty_struct *tty, struct file *file,
|
||||
const unsigned char *buf, size_t nr);
|
||||
int (*ioctl)(struct tty_struct *tty, struct file *file,
|
||||
unsigned int cmd, unsigned long arg);
|
||||
long (*compat_ioctl)(struct tty_struct * tty, struct file * file,
|
||||
long (*compat_ioctl)(struct tty_struct *tty, struct file *file,
|
||||
unsigned int cmd, unsigned long arg);
|
||||
void (*set_termios)(struct tty_struct *tty, struct ktermios * old);
|
||||
void (*set_termios)(struct tty_struct *tty, struct ktermios *old);
|
||||
unsigned int (*poll)(struct tty_struct *, struct file *,
|
||||
struct poll_table_struct *);
|
||||
int (*hangup)(struct tty_struct *tty);
|
||||
|
||||
|
||||
/*
|
||||
* The following routines are called from below.
|
||||
*/
|
||||
@ -145,7 +145,7 @@ struct tty_ldisc_ops {
|
||||
void (*dcd_change)(struct tty_struct *, unsigned int);
|
||||
|
||||
struct module *owner;
|
||||
|
||||
|
||||
int refcount;
|
||||
};
|
||||
|
||||
|
@ -328,7 +328,7 @@ static int ircomm_tty_block_til_ready(struct ircomm_tty_cb *self,
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
|
||||
while (1) {
|
||||
if (tty->termios.c_cflag & CBAUD)
|
||||
if (C_BAUD(tty) && test_bit(ASYNCB_INITIALIZED, &port->flags))
|
||||
tty_port_raise_dtr_rts(port);
|
||||
|
||||
set_current_state(TASK_INTERRUPTIBLE);
|
||||
|
@ -997,12 +997,8 @@ static int ircomm_tty_state_ready(struct ircomm_tty_cb *self,
|
||||
self->settings.dce = IRCOMM_DELTA_CD;
|
||||
ircomm_tty_check_modem_status(self);
|
||||
} else {
|
||||
struct tty_struct *tty = tty_port_tty_get(&self->port);
|
||||
IRDA_DEBUG(0, "%s(), hanging up!\n", __func__ );
|
||||
if (tty) {
|
||||
tty_hangup(tty);
|
||||
tty_kref_put(tty);
|
||||
}
|
||||
tty_port_tty_hangup(&self->port, false);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
Loading…
Reference in New Issue
Block a user