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:
Linus Torvalds 2013-04-29 12:16:17 -07:00
commit 507ffe4f38
92 changed files with 1678 additions and 1619 deletions

View file

@ -33,6 +33,10 @@ Optional properties:
RTAS and should not be registered. RTAS and should not be registered.
- no-loopback-test: set to indicate that the port does not implements loopback - no-loopback-test: set to indicate that the port does not implements loopback
test mode 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: Example:

View file

@ -123,6 +123,11 @@ static struct clk s3c2440_clk_ac97 = {
.ctrlbit = S3C2440_CLKCON_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) static unsigned long s3c2440_fclk_n_getrate(struct clk *clk)
{ {
unsigned long ucon0, ucon1, ucon2, divisor; unsigned long ucon0, ucon1, ucon2, divisor;

View file

@ -239,6 +239,11 @@ void __init s3c24xx_init_io(struct map_desc *mach_desc, int size)
/* Serial port registrations */ /* 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[] = { static struct resource s3c2410_uart0_resource[] = {
[0] = DEFINE_RES_MEM(S3C2410_PA_UART0, SZ_16K), [0] = DEFINE_RES_MEM(S3C2410_PA_UART0, SZ_16K),
[1] = DEFINE_RES_NAMED(IRQ_S3CUART_RX0, \ [1] = DEFINE_RES_NAMED(IRQ_S3CUART_RX0, \

View file

@ -1,281 +1 @@
/* arch/arm/plat-samsung/include/plat/regs-serial.h #include <linux/serial_s3c.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 */

View file

@ -142,8 +142,7 @@ static void transmit_chars(struct tty_struct *tty, struct serial_state *info,
goto out; goto out;
} }
if (info->xmit.head == info->xmit.tail || tty->stopped || if (info->xmit.head == info->xmit.tail || tty->stopped) {
tty->hw_stopped) {
#ifdef SIMSERIAL_DEBUG #ifdef SIMSERIAL_DEBUG
printk("transmit_chars: head=%d, tail=%d, stopped=%d\n", printk("transmit_chars: head=%d, tail=%d, stopped=%d\n",
info->xmit.head, info->xmit.tail, tty->stopped); 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; struct serial_state *info = tty->driver_data;
if (info->xmit.head == info->xmit.tail || tty->stopped || if (info->xmit.head == info->xmit.tail || tty->stopped ||
tty->hw_stopped || !info->xmit.buf) !info->xmit.buf)
return; return;
transmit_chars(tty, info, NULL); 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 * Hey, we transmit directly from here in our case
*/ */
if (CIRC_CNT(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE) && if (CIRC_CNT(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE) &&
!tty->stopped && !tty->hw_stopped) !tty->stopped)
transmit_chars(tty, info, NULL); transmit_chars(tty, info, NULL);
return ret; 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)) #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 * This routine will shutdown a serial port; interrupts are disabled, and
* DTR is dropped if the hangup on close termio flag is on. * 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, .throttle = rs_throttle,
.unthrottle = rs_unthrottle, .unthrottle = rs_unthrottle,
.send_xchar = rs_send_xchar, .send_xchar = rs_send_xchar,
.set_termios = rs_set_termios,
.hangup = rs_hangup, .hangup = rs_hangup,
.proc_fops = &rs_proc_fops, .proc_fops = &rs_proc_fops,
}; };

View file

@ -568,11 +568,7 @@ void chan_interrupt(struct line *line, int irq)
reactivate_fd(chan->fd, irq); reactivate_fd(chan->fd, irq);
if (err == -EIO) { if (err == -EIO) {
if (chan->primary) { if (chan->primary) {
struct tty_struct *tty = tty_port_tty_get(&line->port); tty_port_tty_hangup(&line->port, false);
if (tty != NULL) {
tty_hangup(tty);
tty_kref_put(tty);
}
if (line->chan_out != chan) if (line->chan_out != chan)
close_one_chan(line->chan_out, 1); close_one_chan(line->chan_out, 1);
} }

View file

@ -248,7 +248,6 @@ static irqreturn_t line_write_interrupt(int irq, void *data)
{ {
struct chan *chan = data; struct chan *chan = data;
struct line *line = chan->line; struct line *line = chan->line;
struct tty_struct *tty;
int err; int err;
/* /*
@ -267,12 +266,7 @@ static irqreturn_t line_write_interrupt(int irq, void *data)
} }
spin_unlock(&line->lock); spin_unlock(&line->lock);
tty = tty_port_tty_get(&line->port); tty_port_tty_wakeup(&line->port);
if (tty == NULL)
return IRQ_NONE;
tty_wakeup(tty);
tty_kref_put(tty);
return IRQ_HANDLED; return IRQ_HANDLED;
} }

View file

@ -569,7 +569,6 @@ static void capi_recv_message(struct capi20_appl *ap, struct sk_buff *skb)
{ {
struct capidev *cdev = ap->private; struct capidev *cdev = ap->private;
#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE #ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
struct tty_struct *tty;
struct capiminor *mp; struct capiminor *mp;
u16 datahandle; u16 datahandle;
struct capincci *np; 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)); CAPIMSG_U16(skb->data, CAPIMSG_BASELEN + 4 + 2));
kfree_skb(skb); kfree_skb(skb);
capiminor_del_ack(mp, datahandle); capiminor_del_ack(mp, datahandle);
tty = tty_port_tty_get(&mp->port); tty_port_tty_wakeup(&mp->port);
if (tty) {
tty_wakeup(tty);
tty_kref_put(tty);
}
handle_minor_send(mp); handle_minor_send(mp);
} else { } else {

View file

@ -487,12 +487,8 @@ static const struct tty_operations if_ops = {
static void if_wake(unsigned long data) static void if_wake(unsigned long data)
{ {
struct cardstate *cs = (struct cardstate *)data; struct cardstate *cs = (struct cardstate *)data;
struct tty_struct *tty = tty_port_tty_get(&cs->port);
if (tty) { tty_port_tty_wakeup(&cs->port);
tty_wakeup(tty);
tty_kref_put(tty);
}
} }
/*** interface to common ***/ /*** interface to common ***/

View file

@ -1472,9 +1472,6 @@ isdn_tty_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
tty->termios.c_ospeed == old_termios->c_ospeed) tty->termios.c_ospeed == old_termios->c_ospeed)
return; return;
isdn_tty_change_speed(info); isdn_tty_change_speed(info);
if ((old_termios->c_cflag & CRTSCTS) &&
!(tty->termios.c_cflag & CRTSCTS))
tty->hw_stopped = 0;
} }
} }

View file

@ -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) static void sdio_uart_port_remove(struct sdio_uart_port *port)
{ {
struct sdio_func *func; struct sdio_func *func;
struct tty_struct *tty;
BUG_ON(sdio_uart_table[port->index] != port); 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); sdio_claim_host(func);
port->func = NULL; port->func = NULL;
mutex_unlock(&port->func_lock); mutex_unlock(&port->func_lock);
tty = tty_port_tty_get(&port->port);
/* tty_hangup is async so is this safe as is ?? */ /* tty_hangup is async so is this safe as is ?? */
if (tty) { tty_port_tty_hangup(&port->port, false);
tty_hangup(tty);
tty_kref_put(tty);
}
mutex_unlock(&port->port.mutex); mutex_unlock(&port->port.mutex);
sdio_release_irq(func); sdio_release_irq(func);
sdio_disable_func(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); wake_up_interruptible(&port->port.open_wait);
else { else {
/* DCD drop - hang up if tty attached */ /* DCD drop - hang up if tty attached */
tty = tty_port_tty_get(&port->port); tty_port_tty_hangup(&port->port, false);
if (tty) {
tty_hangup(tty);
tty_kref_put(tty);
}
} }
} }
if (status & UART_MSR_DCTS) { if (status & UART_MSR_DCTS) {

View file

@ -88,11 +88,9 @@ static inline void update_tty_status(struct ser_device *ser)
{ {
ser->tty_status = ser->tty_status =
ser->tty->stopped << 5 | ser->tty->stopped << 5 |
ser->tty->hw_stopped << 4 |
ser->tty->flow_stopped << 3 | ser->tty->flow_stopped << 3 |
ser->tty->packet << 2 | ser->tty->packet << 2 |
ser->tty->port->low_latency << 1 | ser->tty->port->low_latency << 1;
ser->tty->warned;
} }
static inline void debugfs_init(struct ser_device *ser, struct tty_struct *tty) static inline void debugfs_init(struct ser_device *ser, struct tty_struct *tty)
{ {

View file

@ -314,7 +314,7 @@ ppp_asynctty_ioctl(struct tty_struct *tty, struct file *file,
/* flush our buffers and the serial port's buffer */ /* flush our buffers and the serial port's buffer */
if (arg == TCIOFLUSH || arg == TCOFLUSH) if (arg == TCIOFLUSH || arg == TCOFLUSH)
ppp_async_flush_output(ap); ppp_async_flush_output(ap);
err = tty_perform_flush(tty, arg); err = n_tty_ioctl_helper(tty, file, cmd, arg);
break; break;
case FIONREAD: case FIONREAD:

View file

@ -355,7 +355,7 @@ ppp_synctty_ioctl(struct tty_struct *tty, struct file *file,
/* flush our buffers and the serial port's buffer */ /* flush our buffers and the serial port's buffer */
if (arg == TCIOFLUSH || arg == TCOFLUSH) if (arg == TCIOFLUSH || arg == TCOFLUSH)
ppp_sync_flush_output(ap); ppp_sync_flush_output(ap);
err = tty_perform_flush(tty, arg); err = n_tty_ioctl_helper(tty, file, cmd, arg);
break; break;
case FIONREAD: case FIONREAD:

View file

@ -1925,7 +1925,6 @@ static void hso_std_serial_write_bulk_callback(struct urb *urb)
{ {
struct hso_serial *serial = urb->context; struct hso_serial *serial = urb->context;
int status = urb->status; int status = urb->status;
struct tty_struct *tty;
/* sanity check */ /* sanity check */
if (!serial) { if (!serial) {
@ -1941,11 +1940,7 @@ static void hso_std_serial_write_bulk_callback(struct urb *urb)
return; return;
} }
hso_put_activity(serial->parent); hso_put_activity(serial->parent);
tty = tty_port_tty_get(&serial->port); tty_port_tty_wakeup(&serial->port);
if (tty) {
tty_wakeup(tty);
tty_kref_put(tty);
}
hso_kick_transmit(serial); hso_kick_transmit(serial);
D1(" "); D1(" ");
@ -2008,12 +2003,8 @@ static void ctrl_callback(struct urb *urb)
put_rxbuf_data_and_resubmit_ctrl_urb(serial); put_rxbuf_data_and_resubmit_ctrl_urb(serial);
spin_unlock(&serial->serial_lock); spin_unlock(&serial->serial_lock);
} else { } else {
struct tty_struct *tty = tty_port_tty_get(&serial->port);
hso_put_activity(serial->parent); hso_put_activity(serial->parent);
if (tty) { tty_port_tty_wakeup(&serial->port);
tty_wakeup(tty);
tty_kref_put(tty);
}
/* response to a write command */ /* response to a write command */
hso_kick_transmit(serial); 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) static void hso_free_interface(struct usb_interface *interface)
{ {
struct hso_serial *hso_dev; struct hso_serial *hso_dev;
struct tty_struct *tty;
int i; int i;
for (i = 0; i < HSO_SERIAL_TTY_MINORS; i++) { for (i = 0; i < HSO_SERIAL_TTY_MINORS; i++) {
if (serial_table[i] && if (serial_table[i] &&
(serial_table[i]->interface == interface)) { (serial_table[i]->interface == interface)) {
hso_dev = dev2ser(serial_table[i]); hso_dev = dev2ser(serial_table[i]);
tty = tty_port_tty_get(&hso_dev->port); tty_port_tty_hangup(&hso_dev->port, false);
if (tty) {
tty_hangup(tty);
tty_kref_put(tty);
}
mutex_lock(&hso_dev->parent->mutex); mutex_lock(&hso_dev->parent->mutex);
hso_dev->parent->usb_gone = 1; hso_dev->parent->usb_gone = 1;
mutex_unlock(&hso_dev->parent->mutex); mutex_unlock(&hso_dev->parent->mutex);

View file

@ -107,7 +107,6 @@ sclp_tty_write_room (struct tty_struct *tty)
static void static void
sclp_ttybuf_callback(struct sclp_buffer *buffer, int rc) sclp_ttybuf_callback(struct sclp_buffer *buffer, int rc)
{ {
struct tty_struct *tty;
unsigned long flags; unsigned long flags;
void *page; void *page;
@ -125,12 +124,8 @@ sclp_ttybuf_callback(struct sclp_buffer *buffer, int rc)
struct sclp_buffer, list); struct sclp_buffer, list);
spin_unlock_irqrestore(&sclp_tty_lock, flags); spin_unlock_irqrestore(&sclp_tty_lock, flags);
} while (buffer && sclp_emit_buffer(buffer, sclp_ttybuf_callback)); } 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); tty_port_tty_wakeup(&sclp_port);
if (tty != NULL) {
tty_wakeup(tty);
tty_kref_put(tty);
}
} }
static inline void static inline void

View file

@ -114,7 +114,6 @@ static struct sclp_register sclp_vt220_register = {
static void static void
sclp_vt220_process_queue(struct sclp_vt220_request *request) sclp_vt220_process_queue(struct sclp_vt220_request *request)
{ {
struct tty_struct *tty;
unsigned long flags; unsigned long flags;
void *page; void *page;
@ -139,12 +138,7 @@ sclp_vt220_process_queue(struct sclp_vt220_request *request)
} while (__sclp_vt220_emit(request)); } while (__sclp_vt220_emit(request));
if (request == NULL && sclp_vt220_flush_later) if (request == NULL && sclp_vt220_flush_later)
sclp_vt220_emit_current(); sclp_vt220_emit_current();
/* Check if the tty needs a wake up call */ tty_port_tty_wakeup(&sclp_vt220_port);
tty = tty_port_tty_get(&sclp_vt220_port);
if (tty) {
tty_wakeup(tty);
tty_kref_put(tty);
}
} }
#define SCLP_BUFFER_MAX_RETRY 1 #define SCLP_BUFFER_MAX_RETRY 1

View file

@ -744,7 +744,6 @@ static void fwtty_tx_complete(struct fw_card *card, int rcode,
struct fwtty_transaction *txn) struct fwtty_transaction *txn)
{ {
struct fwtty_port *port = txn->port; struct fwtty_port *port = txn->port;
struct tty_struct *tty;
int len; int len;
fwtty_dbg(port, "rcode: %d", rcode); 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; port->stats.dropped += txn->dma_pended.len;
} }
if (len < WAKEUP_CHARS) { if (len < WAKEUP_CHARS)
tty = tty_port_tty_get(&port->port); tty_port_tty_wakeup(&port->port);
if (tty) {
tty_wakeup(tty);
tty_kref_put(tty);
}
}
} }
static int fwtty_tx(struct fwtty_port *port, bool drain) static int fwtty_tx(struct fwtty_port *port, bool drain)

View file

@ -264,7 +264,6 @@ static void ProcessRxChar(struct usb_serial_port *port, unsigned char data)
static void qt_write_bulk_callback(struct urb *urb) static void qt_write_bulk_callback(struct urb *urb)
{ {
struct tty_struct *tty;
int status; int status;
struct quatech_port *quatech_port; struct quatech_port *quatech_port;
@ -278,11 +277,7 @@ static void qt_write_bulk_callback(struct urb *urb)
quatech_port = urb->context; quatech_port = urb->context;
tty = tty_port_tty_get(&quatech_port->port->port); tty_port_tty_wakeup(&quatech_port->port->port);
if (tty)
tty_wakeup(tty);
tty_kref_put(tty);
} }
static void qt_interrupt_callback(struct urb *urb) static void qt_interrupt_callback(struct urb *urb)

View file

@ -1798,19 +1798,7 @@ static struct platform_driver amiga_serial_driver = {
}, },
}; };
static int __init amiga_serial_init(void) module_platform_driver_probe(amiga_serial_driver, amiga_serial_probe);
{
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);
#if defined(CONFIG_SERIAL_CONSOLE) && !defined(MODULE) #if defined(CONFIG_SERIAL_CONSOLE) && !defined(MODULE)

View file

@ -1124,14 +1124,8 @@ static void cyz_handle_cmd(struct cyclades_card *cinfo)
readl(&info->u.cyz.ch_ctrl->rs_status); readl(&info->u.cyz.ch_ctrl->rs_status);
if (dcd & C_RS_DCD) if (dcd & C_RS_DCD)
wake_up_interruptible(&info->port.open_wait); wake_up_interruptible(&info->port.open_wait);
else { else
struct tty_struct *tty; tty_port_tty_hangup(&info->port, false);
tty = tty_port_tty_get(&info->port);
if (tty) {
tty_hangup(tty);
tty_kref_put(tty);
}
}
} }
break; break;
case C_CM_MCTS: case C_CM_MCTS:

View file

@ -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) static irqreturn_t ehv_bc_tty_tx_isr(int irq, void *data)
{ {
struct ehv_bc_data *bc = data; struct ehv_bc_data *bc = data;
struct tty_struct *ttys = tty_port_tty_get(&bc->port);
ehv_bc_tx_dequeue(bc); ehv_bc_tx_dequeue(bc);
if (ttys) { tty_port_tty_wakeup(&bc->port);
tty_wakeup(ttys);
tty_kref_put(ttys);
}
return IRQ_HANDLED; return IRQ_HANDLED;
} }

View file

@ -861,7 +861,6 @@ static void hvsi_write_worker(struct work_struct *work)
{ {
struct hvsi_struct *hp = struct hvsi_struct *hp =
container_of(work, struct hvsi_struct, writer.work); container_of(work, struct hvsi_struct, writer.work);
struct tty_struct *tty;
unsigned long flags; unsigned long flags;
#ifdef DEBUG #ifdef DEBUG
static long start_j = 0; static long start_j = 0;
@ -895,11 +894,7 @@ static void hvsi_write_worker(struct work_struct *work)
start_j = 0; start_j = 0;
#endif /* DEBUG */ #endif /* DEBUG */
wake_up_all(&hp->emptyq); wake_up_all(&hp->emptyq);
tty = tty_port_tty_get(&hp->port); tty_port_tty_wakeup(&hp->port);
if (tty) {
tty_wakeup(tty);
tty_kref_put(tty);
}
} }
out: out:

View file

@ -1732,8 +1732,7 @@ void ipwireless_hardware_free(struct ipw_hardware *hw)
flush_work(&hw->work_rx); flush_work(&hw->work_rx);
for (i = 0; i < NL_NUM_OF_ADDRESSES; i++) 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++) for (i = 0; i < NL_NUM_OF_PRIORITIES; i++)
list_for_each_entry_safe(tp, tq, &hw->tx_queue[i], queue) { list_for_each_entry_safe(tp, tq, &hw->tx_queue[i], queue) {

View file

@ -913,16 +913,12 @@ static void moxa_board_deinit(struct moxa_board_conf *brd)
/* pci hot-un-plug support */ /* pci hot-un-plug support */
for (a = 0; a < brd->numPorts; a++) for (a = 0; a < brd->numPorts; a++)
if (brd->ports[a].port.flags & ASYNC_INITIALIZED) { if (brd->ports[a].port.flags & ASYNC_INITIALIZED)
struct tty_struct *tty = tty_port_tty_get( tty_port_tty_hangup(&brd->ports[a].port, false);
&brd->ports[a].port);
if (tty) {
tty_hangup(tty);
tty_kref_put(tty);
}
}
for (a = 0; a < MAX_PORTS_PER_BOARD; a++) for (a = 0; a < MAX_PORTS_PER_BOARD; a++)
tty_port_destroy(&brd->ports[a].port); tty_port_destroy(&brd->ports[a].port);
while (1) { while (1) {
opened = 0; opened = 0;
for (a = 0; a < brd->numPorts; a++) 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) static void moxa_new_dcdstate(struct moxa_port *p, u8 dcd)
{ {
struct tty_struct *tty;
unsigned long flags; unsigned long flags;
dcd = !!dcd; dcd = !!dcd;
@ -1373,10 +1368,8 @@ static void moxa_new_dcdstate(struct moxa_port *p, u8 dcd)
if (dcd != p->DCDState) { if (dcd != p->DCDState) {
p->DCDState = dcd; p->DCDState = dcd;
spin_unlock_irqrestore(&p->port.lock, flags); spin_unlock_irqrestore(&p->port.lock, flags);
tty = tty_port_tty_get(&p->port); if (!dcd)
if (tty && !C_CLOCAL(tty) && !dcd) tty_port_tty_hangup(&p->port, true);
tty_hangup(tty);
tty_kref_put(tty);
} }
else else
spin_unlock_irqrestore(&p->port.lock, flags); spin_unlock_irqrestore(&p->port.lock, flags);

View file

@ -1084,6 +1084,10 @@ static void mxser_close(struct tty_struct *tty, struct file *filp)
mutex_lock(&port->mutex); mutex_lock(&port->mutex);
mxser_close_port(port); mxser_close_port(port);
mxser_flush_buffer(tty); 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); mxser_shutdown_port(port);
clear_bit(ASYNCB_INITIALIZED, &port->flags); clear_bit(ASYNCB_INITIALIZED, &port->flags);
mutex_unlock(&port->mutex); mutex_unlock(&port->mutex);

View file

@ -1418,11 +1418,7 @@ static void gsm_dlci_close(struct gsm_dlci *dlci)
pr_debug("DLCI %d goes closed.\n", dlci->addr); pr_debug("DLCI %d goes closed.\n", dlci->addr);
dlci->state = DLCI_CLOSED; dlci->state = DLCI_CLOSED;
if (dlci->addr != 0) { if (dlci->addr != 0) {
struct tty_struct *tty = tty_port_tty_get(&dlci->port); tty_port_tty_hangup(&dlci->port, false);
if (tty) {
tty_hangup(tty);
tty_kref_put(tty);
}
kfifo_reset(dlci->fifo); kfifo_reset(dlci->fifo);
} else } else
dlci->gsm->dead = 1; 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) if (tty_port_close_start(&dlci->port, tty, filp) == 0)
goto out; goto out;
gsm_dlci_begin_close(dlci); 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_close_end(&dlci->port, tty);
tty_port_tty_set(&dlci->port, NULL); tty_port_tty_set(&dlci->port, NULL);
out: out:

View file

@ -153,6 +153,12 @@ static void n_tty_set_room(struct tty_struct *tty)
if (left && !old_left) { if (left && !old_left) {
WARN_RATELIMIT(tty->port->itty == NULL, WARN_RATELIMIT(tty->port->itty == NULL,
"scheduling with invalid itty\n"); "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); 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); 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 * reset_buffer_flags - reset buffer state
* @tty: terminal to reset * @tty: terminal to reset
* *
* Reset the read buffer counters, clear the flags, * Reset the read buffer counters and clear the flags.
* and make sure the driver is unthrottled. Called * Called from n_tty_open() and n_tty_flush_buffer().
* from n_tty_open() and n_tty_flush_buffer().
* *
* Locking: tty_read_lock for read fields. * 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; unsigned long flags;
raw_spin_lock_irqsave(&ldata->read_lock, 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; ldata->canon_head = ldata->canon_data = ldata->erasing = 0;
bitmap_zero(ldata->read_flags, N_TTY_BUF_SIZE); bitmap_zero(ldata->read_flags, N_TTY_BUF_SIZE);
n_tty_set_room(tty);
} }
/** static void n_tty_packet_mode_flush(struct tty_struct *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)
{ {
unsigned long flags; unsigned long flags;
/* clear everything and unthrottle the driver */
reset_buffer_flags(tty);
if (!tty->link)
return;
spin_lock_irqsave(&tty->ctrl_lock, flags); spin_lock_irqsave(&tty->ctrl_lock, flags);
if (tty->link->packet) { 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); 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 * n_tty_chars_in_buffer - report available bytes
* @tty: tty device * @tty: tty device
@ -1032,23 +1023,19 @@ static void eraser(unsigned char c, struct tty_struct *tty)
* isig - handle the ISIG optio * isig - handle the ISIG optio
* @sig: signal * @sig: signal
* @tty: terminal * @tty: terminal
* @flush: force flush
* *
* Called when a signal is being sent due to terminal input. This * Called when a signal is being sent due to terminal input.
* may caus terminal flushing to take place according to the termios * Called from the driver receive_buf path so serialized.
* settings and character used. 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) struct pid *tty_pgrp = tty_get_pgrp(tty);
kill_pgrp(tty->pgrp, sig, 1); if (tty_pgrp) {
if (flush || !L_NOFLSH(tty)) { kill_pgrp(tty_pgrp, sig, 1);
n_tty_flush_buffer(tty); put_pid(tty_pgrp);
tty_driver_flush_buffer(tty);
} }
} }
@ -1069,7 +1056,11 @@ static inline void n_tty_receive_break(struct tty_struct *tty)
if (I_IGNBRK(tty)) if (I_IGNBRK(tty))
return; return;
if (I_BRKINT(tty)) { 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; return;
} }
if (I_PARMRK(tty)) { if (I_PARMRK(tty)) {
@ -1236,11 +1227,6 @@ static inline void n_tty_receive_char(struct tty_struct *tty, unsigned char c)
signal = SIGTSTP; signal = SIGTSTP;
if (c == SUSP_CHAR(tty)) { if (c == SUSP_CHAR(tty)) {
send_signal: 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)) { if (!L_NOFLSH(tty)) {
n_tty_flush_buffer(tty); n_tty_flush_buffer(tty);
tty_driver_flush_buffer(tty); tty_driver_flush_buffer(tty);
@ -1251,8 +1237,7 @@ static inline void n_tty_receive_char(struct tty_struct *tty, unsigned char c)
echo_char(c, tty); echo_char(c, tty);
process_echoes(tty); process_echoes(tty);
} }
if (tty->pgrp) isig(signal, tty);
kill_pgrp(tty->pgrp, signal, 1);
return; 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 * mode. We don't want to throttle the driver if we're in
* canonical mode and don't have a newline yet! * canonical mode and don't have a newline yet!
*/ */
if (tty->receive_room < TTY_THRESHOLD_THROTTLE) while (1) {
tty_throttle(tty); tty_set_flow_change(tty, TTY_THROTTLE_SAFE);
if (tty->receive_room >= TTY_THRESHOLD_THROTTLE)
/* FIXME: there is a tiny race here if the receive room check runs break;
before the other work executes and empties the buffer (upping if (!tty_throttle_safe(tty))
the receiving room and unthrottling. We then throttle and get break;
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 */ __tty_set_flow_change(tty, 0);
} }
int is_ignored(int sig) 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; 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->read_buf);
kfree(ldata->echo_buf); kfree(ldata->echo_buf);
kfree(ldata); kfree(ldata);
@ -1645,12 +1632,14 @@ static int n_tty_open(struct tty_struct *tty)
goto err_free_bufs; goto err_free_bufs;
tty->disc_data = ldata; tty->disc_data = ldata;
reset_buffer_flags(tty); reset_buffer_flags(tty->disc_data);
tty_unthrottle(tty);
ldata->column = 0; ldata->column = 0;
n_tty_set_termios(tty, NULL);
tty->minimum_to_wake = 1; tty->minimum_to_wake = 1;
tty->closing = 0; 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; return 0;
err_free_bufs: 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 * and if appropriate send any needed signals and return a negative
* error code if action should be taken. * error code if action should be taken.
* *
* FIXME: * Locking: redirected write test is safe
* Locking: None - redirected write test is safe, testing * current->signal->tty check is safe
* current->signal should possibly lock current->sighand * ctrl_lock to safely reference tty->pgrp
* pgrp locking ?
*/ */
static int job_control(struct tty_struct *tty, struct file *file) 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 /* NOTE: not yet done after every sleep pending a thorough
check of the logic of this change. -- jlc */ check of the logic of this change. -- jlc */
/* don't stop on /dev/console */ /* don't stop on /dev/console */
if (file->f_op->write != redirected_tty_write && if (file->f_op->write == redirected_tty_write ||
current->signal->tty == tty) { current->signal->tty != tty)
if (!tty->pgrp) return 0;
printk(KERN_ERR "n_tty_read: no tty->pgrp!\n");
else if (task_pgrp(current) != tty->pgrp) { spin_lock_irq(&tty->ctrl_lock);
if (is_ignored(SIGTTIN) || if (!tty->pgrp)
is_current_pgrp_orphaned()) printk(KERN_ERR "n_tty_read: no tty->pgrp!\n");
return -EIO; else if (task_pgrp(current) != tty->pgrp) {
kill_pgrp(task_pgrp(current), SIGTTIN, 1); spin_unlock_irq(&tty->ctrl_lock);
set_thread_flag(TIF_SIGPENDING); if (is_ignored(SIGTTIN) || is_current_pgrp_orphaned())
return -ERESTARTSYS; return -EIO;
} kill_pgrp(task_pgrp(current), SIGTTIN, 1);
set_thread_flag(TIF_SIGPENDING);
return -ERESTARTSYS;
} }
spin_unlock_irq(&tty->ctrl_lock);
return 0; return 0;
} }
@ -1959,10 +1950,17 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file,
* longer than TTY_THRESHOLD_UNTHROTTLE in canonical mode, * longer than TTY_THRESHOLD_UNTHROTTLE in canonical mode,
* we won't get any more characters. * 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); n_tty_set_room(tty);
check_unthrottle(tty); if (!tty_unthrottle_safe(tty))
break;
} }
__tty_set_flow_change(tty, 0);
if (b - buf >= minimum) if (b - buf >= minimum)
break; break;

View file

@ -791,7 +791,6 @@ static int send_data(enum port_type index, struct nozomi *dc)
const u8 toggle = port->toggle_ul; const u8 toggle = port->toggle_ul;
void __iomem *addr = port->ul_addr[toggle]; void __iomem *addr = port->ul_addr[toggle];
const u32 ul_size = port->ul_size[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 */ /* Get data from tty and place in buf for now */
size = kfifo_out(&port->fifo_ul, dc->send_buf, 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) { if (size == 0) {
DBG4("No more data to send, disable link:"); DBG4("No more data to send, disable link:");
tty_kref_put(tty);
return 0; 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, (u32 *) &size, 4);
write_mem32(addr + 4, (u32 *) dc->send_buf, size); write_mem32(addr + 4, (u32 *) dc->send_buf, size);
if (tty) tty_port_tty_wakeup(&port->port);
tty_wakeup(tty);
tty_kref_put(tty);
return 1; return 1;
} }
@ -1505,12 +1501,9 @@ static void tty_exit(struct nozomi *dc)
DBG1(" "); DBG1(" ");
for (i = 0; i < MAX_PORT; ++i) { for (i = 0; i < MAX_PORT; ++i)
struct tty_struct *tty = tty_port_tty_get(&dc->port[i].port); tty_port_tty_hangup(&dc->port[i].port, false);
if (tty && list_empty(&tty->hangup_work.entry))
tty_hangup(tty);
tty_kref_put(tty);
}
/* Racy below - surely should wait for scheduled work to be done or /* Racy below - surely should wait for scheduled work to be done or
complete off a hangup method ? */ complete off a hangup method ? */
while (dc->open_ttys) while (dc->open_ttys)

View file

@ -405,15 +405,8 @@ static int pty_common_install(struct tty_driver *driver, struct tty_struct *tty,
return retval; 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) static void pty_cleanup(struct tty_struct *tty)
{ {
tty->port->itty = NULL;
tty_port_put(tty->port); 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 = { static const struct tty_operations ptm_unix98_ops = {
.lookup = ptm_unix98_lookup, .lookup = ptm_unix98_lookup,
.install = pty_unix98_install, .install = pty_unix98_install,

View file

@ -449,7 +449,7 @@ static void rp_do_transmit(struct r_port *info)
/* Loop sending data to FIFO until done or FIFO full */ /* Loop sending data to FIFO until done or FIFO full */
while (1) { while (1) {
if (tty->stopped || tty->hw_stopped) if (tty->stopped)
break; break;
c = min(info->xmit_fifo_room, info->xmit_cnt); c = min(info->xmit_fifo_room, info->xmit_cnt);
c = min(c, XMIT_BUF_SIZE - info->xmit_tail); 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"); (ChanStatus & CD_ACT) ? "on" : "off");
#endif #endif
if (!(ChanStatus & CD_ACT) && info->cd_status) { if (!(ChanStatus & CD_ACT) && info->cd_status) {
struct tty_struct *tty;
#ifdef ROCKET_DEBUG_HANGUP #ifdef ROCKET_DEBUG_HANGUP
printk(KERN_INFO "CD drop, calling hangup.\n"); printk(KERN_INFO "CD drop, calling hangup.\n");
#endif #endif
tty = tty_port_tty_get(&info->port); tty_port_tty_hangup(&info->port, false);
if (tty) {
tty_hangup(tty);
tty_kref_put(tty);
}
} }
info->cd_status = (ChanStatus & CD_ACT) ? 1 : 0; info->cd_status = (ChanStatus & CD_ACT) ? 1 : 0;
wake_up_interruptible(&info->port.open_wait); 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 */ /* Handle transition away from B0 status */
if (!(old_termios->c_cflag & CBAUD) && (tty->termios.c_cflag & CBAUD)) { 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); sSetDTR(cp);
} }
if ((old_termios->c_cflag & CRTSCTS) && !(tty->termios.c_cflag & CRTSCTS)) { if ((old_termios->c_cflag & CRTSCTS) && !(tty->termios.c_cflag & CRTSCTS))
tty->hw_stopped = 0;
rp_start(tty); rp_start(tty);
}
} }
static int rp_break(struct tty_struct *tty, int break_state) 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); spin_lock_irqsave(&info->slock, flags);
cp = &info->channel; 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); 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_buf[info->xmit_head++] = ch;
info->xmit_head &= XMIT_BUF_SIZE - 1; info->xmit_head &= XMIT_BUF_SIZE - 1;
info->xmit_cnt++; info->xmit_cnt++;
@ -1619,14 +1611,14 @@ static int rp_write(struct tty_struct *tty,
#endif #endif
cp = &info->channel; 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); info->xmit_fifo_room = TXFIFO_SIZE - sGetTxCnt(cp);
/* /*
* If the write queue for the port is empty, and there is FIFO space, stuff bytes * 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. * 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); c = min(count, info->xmit_fifo_room);
b = buf; b = buf;
@ -1674,7 +1666,7 @@ static int rp_write(struct tty_struct *tty,
retval += c; 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]); set_bit((info->aiop * 8) + info->chan, (void *) &xmit_flags[info->board]);
end: end:
@ -2527,6 +2519,7 @@ static int sInitController(CONTROLLER_T * CtlP, int CtlNum, ByteIO_t MudbacIO,
return (CtlP->NumAiop); return (CtlP->NumAiop);
} }
#ifdef CONFIG_PCI
/*************************************************************************** /***************************************************************************
Function: sPCIInitController Function: sPCIInitController
Purpose: Initialization of controller global registers and controller Purpose: Initialization of controller global registers and controller
@ -2647,6 +2640,26 @@ static int sPCIInitController(CONTROLLER_T * CtlP, int CtlNum,
return (CtlP->NumAiop); 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 Function: sReadAiopID
Purpose: Read the AIOP idenfication number directly from an AIOP. 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 */ 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 */ /* Returns the line number given the controller (board), aiop and channel number */
static unsigned char GetLineNumber(int ctrl, int aiop, int ch) static unsigned char GetLineNumber(int ctrl, int aiop, int ch)
{ {

View file

@ -630,8 +630,7 @@ static void rs_flush_chars(struct tty_struct *tty)
/* Enable transmitter */ /* Enable transmitter */
local_irq_save(flags); local_irq_save(flags);
if (info->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped || if (info->xmit_cnt <= 0 || tty->stopped || !info->xmit_buf) {
!info->xmit_buf) {
local_irq_restore(flags); local_irq_restore(flags);
return; return;
} }
@ -697,7 +696,7 @@ static int rs_write(struct tty_struct * tty,
total += c; total += c;
} }
if (info->xmit_cnt && !tty->stopped && !tty->hw_stopped) { if (info->xmit_cnt && !tty->stopped) {
/* Enable transmitter */ /* Enable transmitter */
local_irq_disable(); local_irq_disable();
#ifndef USE_INTS #ifndef USE_INTS
@ -978,10 +977,8 @@ static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
change_speed(info, tty); change_speed(info, tty);
if ((old_termios->c_cflag & CRTSCTS) && if ((old_termios->c_cflag & CRTSCTS) &&
!(tty->termios.c_cflag & CRTSCTS)) { !(tty->termios.c_cflag & CRTSCTS))
tty->hw_stopped = 0;
rs_start(tty); rs_start(tty);
}
} }

View file

@ -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. * is cleared, the machine locks up with endless interrupts.
*/ */
#define ALPHA_KLUDGE_MCR (UART_MCR_OUT2 | UART_MCR_OUT1) #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 #else
#define ALPHA_KLUDGE_MCR 0 #define ALPHA_KLUDGE_MCR 0
#endif #endif

View file

@ -2755,7 +2755,7 @@ static void __init serial8250_isa_init_ports(void)
if (nr_uarts > UART_NR) if (nr_uarts > UART_NR)
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_8250_port *up = &serial8250_ports[i];
struct uart_port *port = &up->port; 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 * if so, search for the first available port that does have
* console support. * console support.
*/ */
if (co->index >= nr_uarts) if (co->index >= UART_NR)
co->index = 0; co->index = 0;
port = &serial8250_ports[co->index].port; port = &serial8250_ports[co->index].port;
if (!port->iobase && !port->membase) if (!port->iobase && !port->membase)
@ -2957,7 +2957,7 @@ int serial8250_find_port(struct uart_port *p)
int line; int line;
struct uart_port *port; struct uart_port *port;
for (line = 0; line < nr_uarts; line++) { for (line = 0; line < UART_NR; line++) {
port = &serial8250_ports[line].port; port = &serial8250_ports[line].port;
if (uart_match_port(p, port)) if (uart_match_port(p, port))
return line; return line;
@ -3110,7 +3110,7 @@ static int serial8250_remove(struct platform_device *dev)
{ {
int i; int i;
for (i = 0; i < nr_uarts; i++) { for (i = 0; i < UART_NR; i++) {
struct uart_8250_port *up = &serial8250_ports[i]; struct uart_8250_port *up = &serial8250_ports[i];
if (up->port.dev == &dev->dev) 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. * 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)) if (uart_match_port(&serial8250_ports[i].port, port))
return &serial8250_ports[i]; 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 * free entry. We look for one which hasn't been previously
* used (indicated by zero iobase). * 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 && if (serial8250_ports[i].port.type == PORT_UNKNOWN &&
serial8250_ports[i].port.iobase == 0) serial8250_ports[i].port.iobase == 0)
return &serial8250_ports[i]; 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 * That also failed. Last resort is to find any entry which
* doesn't have a real port associated with it. * 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) if (serial8250_ports[i].port.type == PORT_UNKNOWN)
return &serial8250_ports[i]; 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->tx_loadsz = up->tx_loadsz;
uart->capabilities = up->capabilities; 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) if (up->port.dev)
uart->port.dev = up->port.dev; uart->port.dev = up->port.dev;

View file

@ -33,10 +33,8 @@ static void __dma_tx_complete(void *param)
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
uart_write_wakeup(&p->port); 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); serial8250_tx_dma(p);
uart_write_wakeup(&p->port);
}
} }
static void __dma_rx_complete(void *param) 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 circ_buf *xmit = &p->port.state->xmit;
struct dma_async_tx_descriptor *desc; struct dma_async_tx_descriptor *desc;
if (dma->tx_running) if (uart_tx_stopped(&p->port) || dma->tx_running ||
return -EBUSY; uart_circ_empty(xmit))
return 0;
dma->tx_size = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE); 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, desc = dmaengine_prep_slave_single(dma->txchan,
dma->tx_addr + xmit->tail, 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; struct dma_tx_state state;
int dma_status; int dma_status;
/* dma_status = dmaengine_tx_status(dma->rxchan, dma->rx_cookie, &state);
* If RCVR FIFO trigger level was not reached, complete the transfer and
* let 8250.c copy the remaining data. switch (iir & 0x3f) {
*/ case UART_IIR_RLSI:
if ((iir & 0x3f) == UART_IIR_RX_TIMEOUT) { /* 8250_core handles errors and break interrupts */
dma_status = dmaengine_tx_status(dma->rxchan, dma->rx_cookie, return -EIO;
&state); 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) { if (dma_status == DMA_IN_PROGRESS) {
dmaengine_pause(dma->rxchan); dmaengine_pause(dma->rxchan);
__dma_rx_complete(p); __dma_rx_complete(p);
} }
return -ETIMEDOUT; return -ETIMEDOUT;
default:
break;
} }
if (dma_status)
return 0;
desc = dmaengine_prep_slave_single(dma->rxchan, dma->rx_addr, desc = dmaengine_prep_slave_single(dma->rxchan, dma->rx_addr,
dma->rx_size, DMA_DEV_TO_MEM, dma->rx_size, DMA_DEV_TO_MEM,
DMA_PREP_INTERRUPT | DMA_CTRL_ACK); 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; struct uart_8250_dma *dma = p->dma;
dma_cap_mask_t mask; dma_cap_mask_t mask;
dma->rxconf.src_addr = p->port.mapbase + UART_RX; /* Default slave configuration parameters */
dma->txconf.dst_addr = p->port.mapbase + UART_TX; 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_zero(mask);
dma_cap_set(DMA_SLAVE, mask); dma_cap_set(DMA_SLAVE, mask);
/* Get a channel for RX */ /* 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) if (!dma->rxchan)
return -ENODEV; return -ENODEV;
dmaengine_slave_config(dma->rxchan, &dma->rxconf); dmaengine_slave_config(dma->rxchan, &dma->rxconf);
/* Get a channel for TX */ /* 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) { if (!dma->txchan) {
dma_release_channel(dma->rxchan); dma_release_channel(dma->rxchan);
return -ENODEV; return -ENODEV;

View file

@ -26,6 +26,8 @@
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/acpi.h> #include <linux/acpi.h>
#include <linux/clk.h>
#include <linux/pm_runtime.h>
#include "8250.h" #include "8250.h"
@ -34,9 +36,6 @@
#define DW_UART_CPR 0xf4 /* Component Parameter Register */ #define DW_UART_CPR 0xf4 /* Component Parameter Register */
#define DW_UART_UCV 0xf8 /* UART Component Version */ #define DW_UART_UCV 0xf8 /* UART Component Version */
/* Intel Low Power Subsystem specific */
#define LPSS_PRV_CLOCK_PARAMS 0x800
/* Component Parameter Register bits */ /* Component Parameter Register bits */
#define DW_UART_CPR_ABP_DATA_WIDTH (3 << 0) #define DW_UART_CPR_ABP_DATA_WIDTH (3 << 0)
#define DW_UART_CPR_AFCE_MODE (1 << 4) #define DW_UART_CPR_AFCE_MODE (1 << 4)
@ -55,8 +54,9 @@
struct dw8250_data { struct dw8250_data {
int last_lcr; int last_lcr;
int line; int line;
struct clk *clk;
}; };
static void dw8250_serial_out(struct uart_port *p, int offset, int value) 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; 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) static int dw8250_probe_of(struct uart_port *p)
{ {
struct device_node *np = p->dev->of_node; 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)) if (!of_property_read_u32(np, "reg-shift", &val))
p->regshift = 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)) { 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; return -EINVAL;
} }
p->uartclk = val; p->uartclk = val;
@ -146,67 +163,10 @@ static int dw8250_probe_of(struct uart_port *p)
} }
#ifdef CONFIG_ACPI #ifdef CONFIG_ACPI
static bool dw8250_acpi_dma_filter(struct dma_chan *chan, void *parm) static int dw8250_probe_acpi(struct uart_8250_port *up)
{
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)
{ {
const struct acpi_device_id *id; const struct acpi_device_id *id;
acpi_status status; struct uart_port *p = &up->port;
u32 reg;
id = acpi_match_device(p->dev->driver->acpi_match_table, p->dev); id = acpi_match_device(p->dev->driver->acpi_match_table, p->dev);
if (!id) if (!id)
@ -216,26 +176,21 @@ static int dw8250_probe_acpi(struct uart_port *p)
p->serial_in = dw8250_serial_in32; p->serial_in = dw8250_serial_in32;
p->serial_out = dw8250_serial_out32; p->serial_out = dw8250_serial_out32;
p->regshift = 2; p->regshift = 2;
p->uartclk = (unsigned int)id->driver_data;
status = acpi_walk_resources(ACPI_HANDLE(p->dev), METHOD_NAME__CRS, if (!p->uartclk)
dw8250_acpi_walk_resource, p); p->uartclk = (unsigned int)id->driver_data;
if (ACPI_FAILURE(status)) {
dev_err_ratelimited(p->dev, "%s failed \"%s\"\n", __func__,
acpi_format_exception(status));
return -ENODEV;
}
/* Fix Haswell issue where the clocks do not get enabled */ up->dma = devm_kzalloc(p->dev, sizeof(*up->dma), GFP_KERNEL);
if (!strcmp(id->id, "INT33C4") || !strcmp(id->id, "INT33C5")) { if (!up->dma)
reg = readl(p->membase + LPSS_PRV_CLOCK_PARAMS); return -ENOMEM;
writel(reg | 1, p->membase + LPSS_PRV_CLOCK_PARAMS);
} up->dma->rxconf.src_maxburst = p->fifosize / 4;
up->dma->txconf.dst_maxburst = p->fifosize / 4;
return 0; return 0;
} }
#else #else
static inline int dw8250_probe_acpi(struct uart_port *p) static inline int dw8250_probe_acpi(struct uart_8250_port *up)
{ {
return -ENODEV; return -ENODEV;
} }
@ -266,7 +221,11 @@ static void dw8250_setup_port(struct uart_8250_port *up)
p->flags |= UPF_FIXED_TYPE; p->flags |= UPF_FIXED_TYPE;
p->fifosize = DW_UART_CPR_FIFO_SIZE(reg); p->fifosize = DW_UART_CPR_FIFO_SIZE(reg);
up->tx_loadsz = p->fifosize; 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) 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.mapbase = regs->start;
uart.port.irq = irq->start; uart.port.irq = irq->start;
uart.port.handle_irq = dw8250_handle_irq; uart.port.handle_irq = dw8250_handle_irq;
uart.port.pm = dw8250_do_pm;
uart.port.type = PORT_8250; uart.port.type = PORT_8250;
uart.port.flags = UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF | UPF_FIXED_PORT; uart.port.flags = UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF | UPF_FIXED_PORT;
uart.port.dev = &pdev->dev; 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) if (!uart.port.membase)
return -ENOMEM; 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.iotype = UPIO_MEM;
uart.port.serial_in = dw8250_serial_in; uart.port.serial_in = dw8250_serial_in;
uart.port.serial_out = dw8250_serial_out; uart.port.serial_out = dw8250_serial_out;
uart.port.private_data = data;
dw8250_setup_port(&uart); dw8250_setup_port(&uart);
@ -305,25 +277,22 @@ static int dw8250_probe(struct platform_device *pdev)
if (err) if (err)
return err; return err;
} else if (ACPI_HANDLE(&pdev->dev)) { } else if (ACPI_HANDLE(&pdev->dev)) {
err = dw8250_probe_acpi(&uart.port); err = dw8250_probe_acpi(&uart);
if (err) if (err)
return err; return err;
} else { } else {
return -ENODEV; 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); data->line = serial8250_register_8250_port(&uart);
if (data->line < 0) if (data->line < 0)
return data->line; return data->line;
platform_set_drvdata(pdev, data); platform_set_drvdata(pdev, data);
pm_runtime_set_active(&pdev->dev);
pm_runtime_enable(&pdev->dev);
return 0; return 0;
} }
@ -331,34 +300,64 @@ static int dw8250_remove(struct platform_device *pdev)
{ {
struct dw8250_data *data = platform_get_drvdata(pdev); struct dw8250_data *data = platform_get_drvdata(pdev);
pm_runtime_get_sync(&pdev->dev);
serial8250_unregister_port(data->line); 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; return 0;
} }
#ifdef CONFIG_PM #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); serial8250_suspend_port(data->line);
return 0; 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); serial8250_resume_port(data->line);
return 0; return 0;
} }
#else
#define dw8250_suspend NULL
#define dw8250_resume NULL
#endif /* CONFIG_PM */ #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[] = { static const struct of_device_id dw8250_of_match[] = {
{ .compatible = "snps,dw-apb-uart" }, { .compatible = "snps,dw-apb-uart" },
{ /* Sentinel */ } { /* Sentinel */ }
@ -366,8 +365,8 @@ static const struct of_device_id dw8250_of_match[] = {
MODULE_DEVICE_TABLE(of, dw8250_of_match); MODULE_DEVICE_TABLE(of, dw8250_of_match);
static const struct acpi_device_id dw8250_acpi_match[] = { static const struct acpi_device_id dw8250_acpi_match[] = {
{ "INT33C4", 100000000 }, { "INT33C4", 0 },
{ "INT33C5", 100000000 }, { "INT33C5", 0 },
{ }, { },
}; };
MODULE_DEVICE_TABLE(acpi, dw8250_acpi_match); MODULE_DEVICE_TABLE(acpi, dw8250_acpi_match);
@ -376,13 +375,12 @@ static struct platform_driver dw8250_platform_driver = {
.driver = { .driver = {
.name = "dw-apb-uart", .name = "dw-apb-uart",
.owner = THIS_MODULE, .owner = THIS_MODULE,
.pm = &dw8250_pm_ops,
.of_match_table = dw8250_of_match, .of_match_table = dw8250_of_match,
.acpi_match_table = ACPI_PTR(dw8250_acpi_match), .acpi_match_table = ACPI_PTR(dw8250_acpi_match),
}, },
.probe = dw8250_probe, .probe = dw8250_probe,
.remove = dw8250_remove, .remove = dw8250_remove,
.suspend = dw8250_suspend,
.resume = dw8250_resume,
}; };
module_platform_driver(dw8250_platform_driver); module_platform_driver(dw8250_platform_driver);

View file

@ -29,6 +29,7 @@
* and hooked into this driver. * and hooked into this driver.
*/ */
#if defined(CONFIG_SERIAL_AMBA_PL011_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) #if defined(CONFIG_SERIAL_AMBA_PL011_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
#define SUPPORT_SYSRQ #define SUPPORT_SYSRQ
#endif #endif
@ -72,32 +73,44 @@
/* There is by now at least one vendor with differing details, so handle it */ /* There is by now at least one vendor with differing details, so handle it */
struct vendor_data { struct vendor_data {
unsigned int ifls; unsigned int ifls;
unsigned int fifosize;
unsigned int lcrh_tx; unsigned int lcrh_tx;
unsigned int lcrh_rx; unsigned int lcrh_rx;
bool oversampling; bool oversampling;
bool dma_threshold; bool dma_threshold;
bool cts_event_workaround; 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 = { static struct vendor_data vendor_arm = {
.ifls = UART011_IFLS_RX4_8|UART011_IFLS_TX4_8, .ifls = UART011_IFLS_RX4_8|UART011_IFLS_TX4_8,
.fifosize = 16,
.lcrh_tx = UART011_LCRH, .lcrh_tx = UART011_LCRH,
.lcrh_rx = UART011_LCRH, .lcrh_rx = UART011_LCRH,
.oversampling = false, .oversampling = false,
.dma_threshold = false, .dma_threshold = false,
.cts_event_workaround = 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 = { static struct vendor_data vendor_st = {
.ifls = UART011_IFLS_RX_HALF|UART011_IFLS_TX_HALF, .ifls = UART011_IFLS_RX_HALF|UART011_IFLS_TX_HALF,
.fifosize = 64,
.lcrh_tx = ST_UART011_LCRH_TX, .lcrh_tx = ST_UART011_LCRH_TX,
.lcrh_rx = ST_UART011_LCRH_RX, .lcrh_rx = ST_UART011_LCRH_RX,
.oversampling = true, .oversampling = true,
.dma_threshold = true, .dma_threshold = true,
.cts_event_workaround = true, .cts_event_workaround = true,
.get_fifosize = get_fifosize_st,
}; };
static struct uart_amba_port *amba_ports[UART_NR]; static struct uart_amba_port *amba_ports[UART_NR];
@ -117,6 +130,12 @@ struct pl011_dmarx_data {
struct pl011_sgbuf sgbuf_b; struct pl011_sgbuf sgbuf_b;
dma_cookie_t cookie; dma_cookie_t cookie;
bool running; 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 { 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, static int pl011_sgbuf_init(struct dma_chan *chan, struct pl011_sgbuf *sg,
enum dma_data_direction dir) 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) if (!sg->buf)
return -ENOMEM; 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; return 0;
} }
@ -240,8 +261,9 @@ static void pl011_sgbuf_free(struct dma_chan *chan, struct pl011_sgbuf *sg,
enum dma_data_direction dir) enum dma_data_direction dir)
{ {
if (sg->buf) { if (sg->buf) {
dma_unmap_sg(chan->device->dev, &sg->sg, 1, dir); dma_free_coherent(chan->device->dev,
kfree(sg->buf); 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); dmaengine_slave_config(chan, &rx_conf);
uap->dmarx.chan = chan; 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", dev_info(uap->port.dev, "DMA channel RX %s\n",
dma_chan_name(uap->dmarx.chan)); 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 tty_port *port = &uap->port.state->port;
struct pl011_sgbuf *sgbuf = use_buf_b ? struct pl011_sgbuf *sgbuf = use_buf_b ?
&uap->dmarx.sgbuf_b : &uap->dmarx.sgbuf_a; &uap->dmarx.sgbuf_b : &uap->dmarx.sgbuf_a;
struct device *dev = uap->dmarx.chan->device->dev;
int dma_count = 0; int dma_count = 0;
u32 fifotaken = 0; /* only used for vdbg() */ 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) { 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. * 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 * Note that tty_insert_flip_buf() tries to take as many chars
* as it can. * as it can.
*/ */
dma_count = tty_insert_flip_string(port, sgbuf->buf, pending); dma_count = tty_insert_flip_string(port, sgbuf->buf + dmataken,
pending);
/* Return buffer to device */
dma_sync_sg_for_device(dev, &sgbuf->sg, 1, DMA_FROM_DEVICE);
uap->port.icount.rx += dma_count; uap->port.icount.rx += dma_count;
if (dma_count < pending) 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"); "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 * Only continue with trying to read the FIFO if all DMA chars have
* been taken first. * 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); 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) static void pl011_dma_startup(struct uart_amba_port *uap)
{ {
int ret; int ret;
@ -927,6 +1033,16 @@ static void pl011_dma_startup(struct uart_amba_port *uap)
if (pl011_dma_rx_trigger_dma(uap)) if (pl011_dma_rx_trigger_dma(uap))
dev_dbg(uap->port.dev, "could not trigger initial " dev_dbg(uap->port.dev, "could not trigger initial "
"RX DMA job, fall back to interrupt mode\n"); "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 */ /* 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_a, DMA_FROM_DEVICE);
pl011_sgbuf_free(uap->dmarx.chan, &uap->dmarx.sgbuf_b, 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; 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; return uap->using_rx_dma && uap->dmarx.running;
} }
#else #else
/* Blank functions if the DMA engine is not available */ /* Blank functions if the DMA engine is not available */
static inline void pl011_dma_probe(struct uart_amba_port *uap) 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 " dev_dbg(uap->port.dev, "could not trigger RX DMA job "
"fall back to interrupt mode again\n"); "fall back to interrupt mode again\n");
uap->im |= UART011_RXIM; uap->im |= UART011_RXIM;
} else } else {
uap->im &= ~UART011_RXIM; 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); writew(uap->im, uap->port.membase + UART011_IMSC);
} }
spin_lock(&uap->port.lock); spin_lock(&uap->port.lock);
@ -1164,7 +1293,6 @@ static irqreturn_t pl011_int(int irq, void *dev_id)
unsigned int dummy_read; unsigned int dummy_read;
spin_lock_irqsave(&uap->port.lock, flags); spin_lock_irqsave(&uap->port.lock, flags);
status = readw(uap->port.membase + UART011_MIS); status = readw(uap->port.membase + UART011_MIS);
if (status) { if (status) {
do { do {
@ -1551,6 +1679,13 @@ pl011_set_termios(struct uart_port *port, struct ktermios *termios,
*/ */
baud = uart_get_baud_rate(port, termios, old, 0, baud = uart_get_baud_rate(port, termios, old, 0,
port->uartclk / clkdiv); 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) if (baud > port->uartclk/16)
quot = DIV_ROUND_CLOSEST(port->uartclk * 8, baud); 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_rx = vendor->lcrh_rx;
uap->lcrh_tx = vendor->lcrh_tx; uap->lcrh_tx = vendor->lcrh_tx;
uap->old_cr = 0; uap->old_cr = 0;
uap->fifosize = vendor->fifosize; uap->fifosize = vendor->get_fifosize(dev->periphid);
uap->port.dev = &dev->dev; uap->port.dev = &dev->dev;
uap->port.mapbase = dev->res.start; uap->port.mapbase = dev->res.start;
uap->port.membase = base; uap->port.membase = base;

View file

@ -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 * Driver internal routine, used by both tty(serial core) as well as tx-isr
* -Called under spinlock in either cases * -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 * = by uart_start( ) before calling us
* = tx_ist checks that too before calling * = tx_ist checks that too before calling
*/ */

View file

@ -1011,24 +1011,6 @@ static int bfin_serial_poll_get_char(struct uart_port *port)
} }
#endif #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 = { static struct uart_ops bfin_serial_pops = {
.tx_empty = bfin_serial_tx_empty, .tx_empty = bfin_serial_tx_empty,
.set_mctrl = bfin_serial_set_mctrl, .set_mctrl = bfin_serial_set_mctrl,
@ -1047,11 +1029,6 @@ static struct uart_ops bfin_serial_pops = {
.request_port = bfin_serial_request_port, .request_port = bfin_serial_request_port,
.config_port = bfin_serial_config_port, .config_port = bfin_serial_config_port,
.verify_port = bfin_serial_verify_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 #ifdef CONFIG_CONSOLE_POLL
.poll_put_char = bfin_serial_poll_put_char, .poll_put_char = bfin_serial_poll_put_char,
.poll_get_char = bfin_serial_poll_get_char, .poll_get_char = bfin_serial_poll_get_char,

View file

@ -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 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 */ #define DEF_RX 0x20 /* or SERIAL_CTRL_W >> 8 */
/* Default value of tx_ctrl register: has txd(bit 7)=1 (idle) as default */ /* Default value of tx_ctrl register: has txd(bit 7)=1 (idle) as default */
#define DEF_TX 0x80 /* or SERIAL_CTRL_B */ #define DEF_TX 0x80 /* or SERIAL_CTRL_B */
@ -246,7 +245,6 @@ static struct e100_serial rs_table[] = {
.ifirstadr = R_DMA_CH7_FIRST, .ifirstadr = R_DMA_CH7_FIRST,
.icmdadr = R_DMA_CH7_CMD, .icmdadr = R_DMA_CH7_CMD,
.idescradr = R_DMA_CH7_DESCR, .idescradr = R_DMA_CH7_DESCR,
.flags = STD_FLAGS,
.rx_ctrl = DEF_RX, .rx_ctrl = DEF_RX,
.tx_ctrl = DEF_TX, .tx_ctrl = DEF_TX,
.iseteop = 2, .iseteop = 2,
@ -300,7 +298,6 @@ static struct e100_serial rs_table[] = {
.ifirstadr = R_DMA_CH9_FIRST, .ifirstadr = R_DMA_CH9_FIRST,
.icmdadr = R_DMA_CH9_CMD, .icmdadr = R_DMA_CH9_CMD,
.idescradr = R_DMA_CH9_DESCR, .idescradr = R_DMA_CH9_DESCR,
.flags = STD_FLAGS,
.rx_ctrl = DEF_RX, .rx_ctrl = DEF_RX,
.tx_ctrl = DEF_TX, .tx_ctrl = DEF_TX,
.iseteop = 3, .iseteop = 3,
@ -356,7 +353,6 @@ static struct e100_serial rs_table[] = {
.ifirstadr = R_DMA_CH3_FIRST, .ifirstadr = R_DMA_CH3_FIRST,
.icmdadr = R_DMA_CH3_CMD, .icmdadr = R_DMA_CH3_CMD,
.idescradr = R_DMA_CH3_DESCR, .idescradr = R_DMA_CH3_DESCR,
.flags = STD_FLAGS,
.rx_ctrl = DEF_RX, .rx_ctrl = DEF_RX,
.tx_ctrl = DEF_TX, .tx_ctrl = DEF_TX,
.iseteop = 0, .iseteop = 0,
@ -410,7 +406,6 @@ static struct e100_serial rs_table[] = {
.ifirstadr = R_DMA_CH5_FIRST, .ifirstadr = R_DMA_CH5_FIRST,
.icmdadr = R_DMA_CH5_CMD, .icmdadr = R_DMA_CH5_CMD,
.idescradr = R_DMA_CH5_DESCR, .idescradr = R_DMA_CH5_DESCR,
.flags = STD_FLAGS,
.rx_ctrl = DEF_RX, .rx_ctrl = DEF_RX,
.tx_ctrl = DEF_TX, .tx_ctrl = DEF_TX,
.iseteop = 1, .iseteop = 1,
@ -2263,8 +2258,7 @@ TODO: The break will be delayed until an F or V character is received.
*/ */
static static void handle_ser_rx_interrupt_no_dma(struct e100_serial *info)
struct e100_serial * handle_ser_rx_interrupt_no_dma(struct e100_serial *info)
{ {
unsigned long data_read; unsigned long data_read;
@ -2370,10 +2364,9 @@ struct e100_serial * handle_ser_rx_interrupt_no_dma(struct e100_serial *info)
} }
tty_flip_buffer_push(&info->port); 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; unsigned char rstat;
@ -2382,7 +2375,8 @@ static struct e100_serial* handle_ser_rx_interrupt(struct e100_serial *info)
#endif #endif
/* DEBUG_LOG(info->line, "ser_interrupt stat %03X\n", rstat | (i << 8)); */ /* DEBUG_LOG(info->line, "ser_interrupt stat %03X\n", rstat | (i << 8)); */
if (!info->uses_dma_in) { if (!info->uses_dma_in) {
return handle_ser_rx_interrupt_no_dma(info); handle_ser_rx_interrupt_no_dma(info);
return;
} }
/* DMA is used */ /* DMA is used */
rstat = info->ioport[REG_STATUS]; 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 */ /* Restarting the DMA never hurts */
*info->icmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, restart); *info->icmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, restart);
START_FLUSH_FAST_TIMER(info, "ser_int"); START_FLUSH_FAST_TIMER(info, "ser_int");
return info;
} /* handle_ser_rx_interrupt */ } /* handle_ser_rx_interrupt */
static void handle_ser_tx_interrupt(struct e100_serial *info) 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 */ /* Normal char-by-char interrupt */
if (info->xmit.head == info->xmit.tail if (info->xmit.head == info->xmit.tail
|| info->port.tty->stopped || info->port.tty->stopped) {
|| info->port.tty->hw_stopped) {
DFLOW(DEBUG_LOG(info->line, "tx_int: stopped %i\n", DFLOW(DEBUG_LOG(info->line, "tx_int: stopped %i\n",
info->port.tty->stopped)); info->port.tty->stopped));
e100_disable_serial_tx_ready_irq(info); e100_disable_serial_tx_ready_irq(info);
@ -2722,7 +2714,7 @@ startup(struct e100_serial * info)
/* if it was already initialized, skip this */ /* if it was already initialized, skip this */
if (info->flags & ASYNC_INITIALIZED) { if (info->port.flags & ASYNC_INITIALIZED) {
local_irq_restore(flags); local_irq_restore(flags);
free_page(xmit_page); free_page(xmit_page);
return 0; return 0;
@ -2847,7 +2839,7 @@ startup(struct e100_serial * info)
#endif /* CONFIG_SVINTO_SIM */ #endif /* CONFIG_SVINTO_SIM */
info->flags |= ASYNC_INITIALIZED; info->port.flags |= ASYNC_INITIALIZED;
local_irq_restore(flags); local_irq_restore(flags);
return 0; return 0;
@ -2892,7 +2884,7 @@ shutdown(struct e100_serial * info)
#endif /* CONFIG_SVINTO_SIM */ #endif /* CONFIG_SVINTO_SIM */
if (!(info->flags & ASYNC_INITIALIZED)) if (!(info->port.flags & ASYNC_INITIALIZED))
return; return;
#ifdef SERIAL_DEBUG_OPEN #ifdef SERIAL_DEBUG_OPEN
@ -2923,7 +2915,7 @@ shutdown(struct e100_serial * info)
if (info->port.tty) if (info->port.tty)
set_bit(TTY_IO_ERROR, &info->port.tty->flags); set_bit(TTY_IO_ERROR, &info->port.tty->flags);
info->flags &= ~ASYNC_INITIALIZED; info->port.flags &= ~ASYNC_INITIALIZED;
local_irq_restore(flags); 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 */ /* possibly, the tx/rx should be disabled first to do this safely */
/* change baud-rate and write it to the hardware */ /* 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 */ /* Special baudrate */
u32 mask = 0xFF << (info->line*8); /* Each port has 8 bits */ u32 mask = 0xFF << (info->line*8); /* Each port has 8 bits */
unsigned long alt_source = unsigned long alt_source =
@ -3098,7 +3090,6 @@ rs_flush_chars(struct tty_struct *tty)
if (info->tr_running || if (info->tr_running ||
info->xmit.head == info->xmit.tail || info->xmit.head == info->xmit.tail ||
tty->stopped || tty->stopped ||
tty->hw_stopped ||
!info->xmit.buf) !info->xmit.buf)
return; return;
@ -3176,7 +3167,6 @@ static int rs_raw_write(struct tty_struct *tty,
if (info->xmit.head != info->xmit.tail && if (info->xmit.head != info->xmit.tail &&
!tty->stopped && !tty->stopped &&
!tty->hw_stopped &&
!info->tr_running) { !info->tr_running) {
start_transmit(info); start_transmit(info);
} }
@ -3400,10 +3390,10 @@ get_serial_info(struct e100_serial * info,
tmp.line = info->line; tmp.line = info->line;
tmp.port = (int)info->ioport; tmp.port = (int)info->ioport;
tmp.irq = info->irq; tmp.irq = info->irq;
tmp.flags = info->flags; tmp.flags = info->port.flags;
tmp.baud_base = info->baud_base; tmp.baud_base = info->baud_base;
tmp.close_delay = info->close_delay; tmp.close_delay = info->port.close_delay;
tmp.closing_wait = info->closing_wait; tmp.closing_wait = info->port.closing_wait;
tmp.custom_divisor = info->custom_divisor; tmp.custom_divisor = info->custom_divisor;
if (copy_to_user(retinfo, &tmp, sizeof(*retinfo))) if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
return -EFAULT; return -EFAULT;
@ -3425,16 +3415,16 @@ set_serial_info(struct e100_serial *info,
if (!capable(CAP_SYS_ADMIN)) { if (!capable(CAP_SYS_ADMIN)) {
if ((new_serial.type != info->type) || 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) != ((new_serial.flags & ~ASYNC_USR_MASK) !=
(info->flags & ~ASYNC_USR_MASK))) (info->port.flags & ~ASYNC_USR_MASK)))
return -EPERM; return -EPERM;
info->flags = ((info->flags & ~ASYNC_USR_MASK) | info->port.flags = ((info->port.flags & ~ASYNC_USR_MASK) |
(new_serial.flags & ASYNC_USR_MASK)); (new_serial.flags & ASYNC_USR_MASK));
goto check_and_exit; goto check_and_exit;
} }
if (info->count > 1) if (info->port.count > 1)
return -EBUSY; return -EBUSY;
/* /*
@ -3443,16 +3433,16 @@ set_serial_info(struct e100_serial *info,
*/ */
info->baud_base = new_serial.baud_base; 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)); (new_serial.flags & ASYNC_FLAGS));
info->custom_divisor = new_serial.custom_divisor; info->custom_divisor = new_serial.custom_divisor;
info->type = new_serial.type; info->type = new_serial.type;
info->close_delay = new_serial.close_delay; info->port.close_delay = new_serial.close_delay;
info->closing_wait = new_serial.closing_wait; info->port.closing_wait = new_serial.closing_wait;
info->port.low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0; info->port.low_latency = (info->port.flags & ASYNC_LOW_LATENCY) ? 1 : 0;
check_and_exit: check_and_exit:
if (info->flags & ASYNC_INITIALIZED) { if (info->port.flags & ASYNC_INITIALIZED) {
change_speed(info); change_speed(info);
} else } else
retval = startup(info); retval = startup(info);
@ -3733,10 +3723,8 @@ rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
/* Handle turning off CRTSCTS */ /* Handle turning off CRTSCTS */
if ((old_termios->c_cflag & CRTSCTS) && if ((old_termios->c_cflag & CRTSCTS) &&
!(tty->termios.c_cflag & CRTSCTS)) { !(tty->termios.c_cflag & CRTSCTS))
tty->hw_stopped = 0;
rs_start(tty); 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, printk("[%d] rs_close ttyS%d, count = %d\n", current->pid,
info->line, info->count); info->line, info->count);
#endif #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 * Uh, oh. tty->count is 1, which means that the tty
* structure will be freed. Info->count should always * structure will be freed. Info->count should always
@ -3782,32 +3770,32 @@ rs_close(struct tty_struct *tty, struct file * filp)
*/ */
printk(KERN_ERR printk(KERN_ERR
"rs_close: bad serial port count; tty->count is 1, " "rs_close: bad serial port count; tty->count is 1, "
"info->count is %d\n", info->count); "info->count is %d\n", info->port.count);
info->count = 1; 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", printk(KERN_ERR "rs_close: bad serial port count for ttyS%d: %d\n",
info->line, info->count); info->line, info->port.count);
info->count = 0; info->port.count = 0;
} }
if (info->count) { if (info->port.count) {
local_irq_restore(flags); local_irq_restore(flags);
return; return;
} }
info->flags |= ASYNC_CLOSING; info->port.flags |= ASYNC_CLOSING;
/* /*
* Save the termios structure, since this port may have * Save the termios structure, since this port may have
* separate termios for callout and dialin. * separate termios for callout and dialin.
*/ */
if (info->flags & ASYNC_NORMAL_ACTIVE) if (info->port.flags & ASYNC_NORMAL_ACTIVE)
info->normal_termios = tty->termios; info->normal_termios = tty->termios;
/* /*
* Now we wait for the transmit buffer to clear; and we notify * Now we wait for the transmit buffer to clear; and we notify
* the line discipline to only process XON/XOFF characters. * the line discipline to only process XON/XOFF characters.
*/ */
tty->closing = 1; tty->closing = 1;
if (info->closing_wait != ASYNC_CLOSING_WAIT_NONE) if (info->port.closing_wait != ASYNC_CLOSING_WAIT_NONE)
tty_wait_until_sent(tty, info->closing_wait); tty_wait_until_sent(tty, info->port.closing_wait);
/* /*
* At this point we stop accepting input. To do this, we * At this point we stop accepting input. To do this, we
* disable the serial receiver and the DMA receive interrupt. * 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(info);
e100_disable_rx_irq(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 * Before we drop DTR, make sure the UART transmitter
* has completely drained; this is especially * has completely drained; this is especially
@ -3836,13 +3824,13 @@ rs_close(struct tty_struct *tty, struct file * filp)
tty->closing = 0; tty->closing = 0;
info->event = 0; info->event = 0;
info->port.tty = NULL; info->port.tty = NULL;
if (info->blocked_open) { if (info->port.blocked_open) {
if (info->close_delay) if (info->port.close_delay)
schedule_timeout_interruptible(info->close_delay); schedule_timeout_interruptible(info->port.close_delay);
wake_up_interruptible(&info->open_wait); wake_up_interruptible(&info->port.open_wait);
} }
info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING); info->port.flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
wake_up_interruptible(&info->close_wait); wake_up_interruptible(&info->port.close_wait);
local_irq_restore(flags); local_irq_restore(flags);
/* port closed */ /* port closed */
@ -3935,10 +3923,10 @@ rs_hangup(struct tty_struct *tty)
rs_flush_buffer(tty); rs_flush_buffer(tty);
shutdown(info); shutdown(info);
info->event = 0; info->event = 0;
info->count = 0; info->port.count = 0;
info->flags &= ~ASYNC_NORMAL_ACTIVE; info->port.flags &= ~ASYNC_NORMAL_ACTIVE;
info->port.tty = NULL; 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. * until it's done, and then try again.
*/ */
if (tty_hung_up_p(filp) || if (tty_hung_up_p(filp) ||
(info->flags & ASYNC_CLOSING)) { (info->port.flags & ASYNC_CLOSING)) {
wait_event_interruptible_tty(tty, info->close_wait, wait_event_interruptible_tty(tty, info->port.close_wait,
!(info->flags & ASYNC_CLOSING)); !(info->port.flags & ASYNC_CLOSING));
#ifdef SERIAL_DO_RESTART #ifdef SERIAL_DO_RESTART
if (info->flags & ASYNC_HUP_NOTIFY) if (info->port.flags & ASYNC_HUP_NOTIFY)
return -EAGAIN; return -EAGAIN;
else else
return -ERESTARTSYS; return -ERESTARTSYS;
@ -3979,7 +3967,7 @@ block_til_ready(struct tty_struct *tty, struct file * filp,
*/ */
if ((filp->f_flags & O_NONBLOCK) || if ((filp->f_flags & O_NONBLOCK) ||
(tty->flags & (1 << TTY_IO_ERROR))) { (tty->flags & (1 << TTY_IO_ERROR))) {
info->flags |= ASYNC_NORMAL_ACTIVE; info->port.flags |= ASYNC_NORMAL_ACTIVE;
return 0; 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 * Block waiting for the carrier detect and the line to become
* free (i.e., not in use by the callout). While we are in * 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 * rs_close() knows when to free things. We restore it upon
* exit, either normal or abnormal. * exit, either normal or abnormal.
*/ */
retval = 0; retval = 0;
add_wait_queue(&info->open_wait, &wait); add_wait_queue(&info->port.open_wait, &wait);
#ifdef SERIAL_DEBUG_OPEN #ifdef SERIAL_DEBUG_OPEN
printk("block_til_ready before block: ttyS%d, count = %d\n", printk("block_til_ready before block: ttyS%d, count = %d\n",
info->line, info->count); info->line, info->port.count);
#endif #endif
local_irq_save(flags); local_irq_save(flags);
if (!tty_hung_up_p(filp)) { if (!tty_hung_up_p(filp)) {
extra_count++; extra_count++;
info->count--; info->port.count--;
} }
local_irq_restore(flags); local_irq_restore(flags);
info->blocked_open++; info->port.blocked_open++;
while (1) { while (1) {
local_irq_save(flags); local_irq_save(flags);
/* assert RTS and DTR */ /* assert RTS and DTR */
@ -4015,9 +4003,9 @@ block_til_ready(struct tty_struct *tty, struct file * filp,
local_irq_restore(flags); local_irq_restore(flags);
set_current_state(TASK_INTERRUPTIBLE); set_current_state(TASK_INTERRUPTIBLE);
if (tty_hung_up_p(filp) || if (tty_hung_up_p(filp) ||
!(info->flags & ASYNC_INITIALIZED)) { !(info->port.flags & ASYNC_INITIALIZED)) {
#ifdef SERIAL_DO_RESTART #ifdef SERIAL_DO_RESTART
if (info->flags & ASYNC_HUP_NOTIFY) if (info->port.flags & ASYNC_HUP_NOTIFY)
retval = -EAGAIN; retval = -EAGAIN;
else else
retval = -ERESTARTSYS; retval = -ERESTARTSYS;
@ -4026,7 +4014,7 @@ block_til_ready(struct tty_struct *tty, struct file * filp,
#endif #endif
break; break;
} }
if (!(info->flags & ASYNC_CLOSING) && do_clocal) if (!(info->port.flags & ASYNC_CLOSING) && do_clocal)
/* && (do_clocal || DCD_IS_ASSERTED) */ /* && (do_clocal || DCD_IS_ASSERTED) */
break; break;
if (signal_pending(current)) { if (signal_pending(current)) {
@ -4035,24 +4023,24 @@ block_til_ready(struct tty_struct *tty, struct file * filp,
} }
#ifdef SERIAL_DEBUG_OPEN #ifdef SERIAL_DEBUG_OPEN
printk("block_til_ready blocking: ttyS%d, count = %d\n", printk("block_til_ready blocking: ttyS%d, count = %d\n",
info->line, info->count); info->line, info->port.count);
#endif #endif
tty_unlock(tty); tty_unlock(tty);
schedule(); schedule();
tty_lock(tty); tty_lock(tty);
} }
set_current_state(TASK_RUNNING); set_current_state(TASK_RUNNING);
remove_wait_queue(&info->open_wait, &wait); remove_wait_queue(&info->port.open_wait, &wait);
if (extra_count) if (extra_count)
info->count++; info->port.count++;
info->blocked_open--; info->port.blocked_open--;
#ifdef SERIAL_DEBUG_OPEN #ifdef SERIAL_DEBUG_OPEN
printk("block_til_ready after blocking: ttyS%d, count = %d\n", printk("block_til_ready after blocking: ttyS%d, count = %d\n",
info->line, info->count); info->line, info->port.count);
#endif #endif
if (retval) if (retval)
return retval; return retval;
info->flags |= ASYNC_NORMAL_ACTIVE; info->port.flags |= ASYNC_NORMAL_ACTIVE;
return 0; return 0;
} }
@ -4086,24 +4074,24 @@ rs_open(struct tty_struct *tty, struct file * filp)
#ifdef SERIAL_DEBUG_OPEN #ifdef SERIAL_DEBUG_OPEN
printk("[%d] rs_open %s, count = %d\n", current->pid, tty->name, printk("[%d] rs_open %s, count = %d\n", current->pid, tty->name,
info->count); info->port.count);
#endif #endif
info->count++; info->port.count++;
tty->driver_data = info; tty->driver_data = info;
info->port.tty = tty; 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 the port is in the middle of closing, bail out now
*/ */
if (tty_hung_up_p(filp) || if (tty_hung_up_p(filp) ||
(info->flags & ASYNC_CLOSING)) { (info->port.flags & ASYNC_CLOSING)) {
wait_event_interruptible_tty(tty, info->close_wait, wait_event_interruptible_tty(tty, info->port.close_wait,
!(info->flags & ASYNC_CLOSING)); !(info->port.flags & ASYNC_CLOSING));
#ifdef SERIAL_DO_RESTART #ifdef SERIAL_DO_RESTART
return ((info->flags & ASYNC_HUP_NOTIFY) ? return ((info->port.flags & ASYNC_HUP_NOTIFY) ?
-EAGAIN : -ERESTARTSYS); -EAGAIN : -ERESTARTSYS);
#else #else
return -EAGAIN; 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 DMA is enabled try to allocate the irq's.
*/ */
if (info->count == 1) { if (info->port.count == 1) {
allocated_resources = 1; allocated_resources = 1;
if (info->dma_in_enabled) { if (info->dma_in_enabled) {
if (request_irq(info->dma_in_irq_nbr, if (request_irq(info->dma_in_irq_nbr,
@ -4186,7 +4174,7 @@ rs_open(struct tty_struct *tty, struct file * filp)
if (allocated_resources) if (allocated_resources)
deinit_port(info); deinit_port(info);
/* FIXME Decrease count info->count here too? */ /* FIXME Decrease count info->port.count here too? */
return retval; return retval;
} }
@ -4203,7 +4191,7 @@ rs_open(struct tty_struct *tty, struct file * filp)
return retval; 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; tty->termios = info->normal_termios;
change_speed(info); 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) if (info->port.tty->stopped)
seq_printf(m, " stopped:%i", seq_printf(m, " stopped:%i",
(int)info->port.tty->stopped); (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->forced_eop = 0;
info->baud_base = DEF_BAUD_BASE; info->baud_base = DEF_BAUD_BASE;
info->custom_divisor = 0; info->custom_divisor = 0;
info->flags = 0;
info->close_delay = 5*HZ/10;
info->closing_wait = 30*HZ;
info->x_char = 0; info->x_char = 0;
info->event = 0; info->event = 0;
info->count = 0;
info->blocked_open = 0;
info->normal_termios = driver->init_termios; info->normal_termios = driver->init_termios;
init_waitqueue_head(&info->open_wait);
init_waitqueue_head(&info->close_wait);
info->xmit.buf = NULL; info->xmit.buf = NULL;
info->xmit.tail = info->xmit.head = 0; info->xmit.tail = info->xmit.head = 0;
info->first_recv_buffer = info->last_recv_buffer = NULL; info->first_recv_buffer = info->last_recv_buffer = NULL;

View file

@ -53,8 +53,6 @@ struct e100_serial {
volatile u8 *icmdadr; /* adr to R_DMA_CHx_CMD */ volatile u8 *icmdadr; /* adr to R_DMA_CHx_CMD */
volatile u32 *idescradr; /* adr to R_DMA_CHx_DESCR */ 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 rx_ctrl; /* shadow for R_SERIALx_REC_CTRL */
u8 tx_ctrl; /* shadow for R_SERIALx_TR_CTRL */ u8 tx_ctrl; /* shadow for R_SERIALx_TR_CTRL */
u8 iseteop; /* bit number for R_SET_EOP for the input dma */ 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 */ 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 x_char; /* xon/xoff character */
int close_delay;
unsigned short closing_wait;
unsigned short closing_wait2;
unsigned long event; unsigned long event;
unsigned long last_active;
int line; int line;
int type; /* PORT_ETRAX */ int type; /* PORT_ETRAX */
int count; /* # of fd on device */
int blocked_open; /* # of blocked opens */
struct circ_buf xmit; struct circ_buf xmit;
struct etrax_recv_buffer *first_recv_buffer; struct etrax_recv_buffer *first_recv_buffer;
struct etrax_recv_buffer *last_recv_buffer; struct etrax_recv_buffer *last_recv_buffer;
@ -110,9 +99,6 @@ struct e100_serial {
struct work_struct work; struct work_struct work;
struct async_icount icount; /* error-statistics etc.*/ struct async_icount icount; /* error-statistics etc.*/
struct ktermios normal_termios; 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 char_time_usec; /* The time for 1 char, in usecs */
unsigned long flush_time_usec; /* How often we should flush */ unsigned long flush_time_usec; /* How often we should flush */

View file

@ -1415,8 +1415,7 @@ static int icom_alloc_adapter(struct icom_adapter
struct icom_adapter *cur_adapter_entry; struct icom_adapter *cur_adapter_entry;
struct list_head *tmp; struct list_head *tmp;
icom_adapter = (struct icom_adapter *) icom_adapter = kzalloc(sizeof(struct icom_adapter), GFP_KERNEL);
kzalloc(sizeof(struct icom_adapter), GFP_KERNEL);
if (!icom_adapter) { if (!icom_adapter) {
return -ENOMEM; return -ENOMEM;

View file

@ -269,23 +269,6 @@ static void mrdy_assert(struct ifx_spi_device *ifx_dev)
mrdy_set_high(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 * ifx_spi_timeout - SPI timeout
* @arg: our SPI device * @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; struct ifx_spi_device *ifx_dev = (struct ifx_spi_device *)arg;
dev_warn(&ifx_dev->spi_dev->dev, "*** SPI Timeout ***"); 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); mrdy_set_low(ifx_dev);
clear_bit(IFX_SPI_STATE_TIMER_PENDING, &ifx_dev->flags); 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; 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_spi_prepare_tx_buffer - prepare transmit frame
* @ifx_dev: our SPI device * @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; tx_count += temp_count;
if (temp_count == queue_length) if (temp_count == queue_length)
/* poke port to get more data */ /* 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 */ else /* more data in port, use next SPI message */
ifx_dev->spi_more = 1; 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) static void ifx_spi_complete(void *ctx)
{ {
struct ifx_spi_device *ifx_dev = ctx; struct ifx_spi_device *ifx_dev = ctx;
struct tty_struct *tty;
struct tty_ldisc *ldisc = NULL;
int length; int length;
int actual_length; int actual_length;
unsigned char more; unsigned char more;
@ -762,15 +724,7 @@ static void ifx_spi_complete(void *ctx)
*/ */
ifx_spi_power_state_clear(ifx_dev, ifx_spi_power_state_clear(ifx_dev,
IFX_SPI_POWER_DATA_PENDING); IFX_SPI_POWER_DATA_PENDING);
tty = tty_port_tty_get(&ifx_dev->tty_port); tty_port_tty_wakeup(&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);
}
} }
} }
} }
@ -962,7 +916,7 @@ static irqreturn_t ifx_spi_reset_interrupt(int irq, void *dev)
set_bit(MR_INPROGRESS, &ifx_dev->mdm_reset_state); set_bit(MR_INPROGRESS, &ifx_dev->mdm_reset_state);
if (!solreset) { if (!solreset) {
/* unsolicited reset */ /* unsolicited reset */
ifx_spi_ttyhangup(ifx_dev); tty_port_tty_hangup(&ifx_dev->tty_port, false);
} }
} else { } else {
/* exited reset */ /* exited reset */
@ -1324,30 +1278,6 @@ static void ifx_spi_spi_shutdown(struct spi_device *spi)
* no hardware to save state for * 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 * ifx_spi_pm_suspend - suspend modem on system suspend
* @dev: device being suspended * @dev: device being suspended
@ -1437,8 +1367,6 @@ static struct spi_driver ifx_spi_driver = {
.probe = ifx_spi_spi_probe, .probe = ifx_spi_spi_probe,
.shutdown = ifx_spi_spi_shutdown, .shutdown = ifx_spi_spi_shutdown,
.remove = ifx_spi_spi_remove, .remove = ifx_spi_spi_remove,
.suspend = ifx_spi_spi_suspend,
.resume = ifx_spi_spi_resume,
.id_table = ifx_id_table .id_table = ifx_id_table
}; };

View file

@ -596,12 +596,6 @@ void jsm_input(struct jsm_channel *ch)
jsm_dbg(READ, &ch->ch_bd->pci_dev, "start 2\n"); 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); len = tty_buffer_request_room(port, data_len);
n = len; n = len;

View file

@ -778,7 +778,7 @@ static int max3100_probe(struct spi_device *spi)
max3100s[i]->spi = spi; max3100s[i]->spi = spi;
max3100s[i]->irq = spi->irq; max3100s[i]->irq = spi->irq;
spin_lock_init(&max3100s[i]->conf_lock); 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; pdata = spi->dev.platform_data;
max3100s[i]->crystal = pdata->crystal; max3100s[i]->crystal = pdata->crystal;
max3100s[i]->loopback = pdata->loopback; 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) 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; int i;
mutex_lock(&max3100s_lock); mutex_lock(&max3100s_lock);
@ -849,11 +849,11 @@ static int max3100_remove(struct spi_device *spi)
return 0; 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__); 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; 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__); dev_dbg(&s->spi->dev, "%s\n", __func__);
@ -894,21 +894,21 @@ static int max3100_resume(struct spi_device *spi)
return 0; return 0;
} }
static SIMPLE_DEV_PM_OPS(max3100_pm_ops, max3100_suspend, max3100_resume);
#define MAX3100_PM_OPS (&max3100_pm_ops)
#else #else
#define max3100_suspend NULL #define MAX3100_PM_OPS NULL
#define max3100_resume NULL
#endif #endif
static struct spi_driver max3100_driver = { static struct spi_driver max3100_driver = {
.driver = { .driver = {
.name = "max3100", .name = "max3100",
.owner = THIS_MODULE, .owner = THIS_MODULE,
.pm = MAX3100_PM_OPS,
}, },
.probe = max3100_probe, .probe = max3100_probe,
.remove = max3100_remove, .remove = max3100_remove,
.suspend = max3100_suspend,
.resume = max3100_resume,
}; };
module_spi_driver(max3100_driver); module_spi_driver(max3100_driver);

View file

@ -881,12 +881,14 @@ static struct uart_ops max310x_ops = {
.verify_port = max310x_verify_port, .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; 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); 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; 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) if (s->pdata->suspend)
s->pdata->suspend(0); s->pdata->suspend(0);
@ -928,6 +930,13 @@ static int max310x_resume(struct spi_device *spi)
return uart_resume_port(&s->uart, &s->port); 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 #ifdef CONFIG_GPIOLIB
static int max310x_gpio_get(struct gpio_chip *chip, unsigned offset) static int max310x_gpio_get(struct gpio_chip *chip, unsigned offset)
{ {
@ -1242,11 +1251,10 @@ static struct spi_driver max310x_driver = {
.driver = { .driver = {
.name = "max310x", .name = "max310x",
.owner = THIS_MODULE, .owner = THIS_MODULE,
.pm = MAX310X_PM_OPS,
}, },
.probe = max310x_probe, .probe = max310x_probe,
.remove = max310x_remove, .remove = max310x_remove,
.suspend = max310x_suspend,
.resume = max310x_resume,
.id_table = max310x_id_table, .id_table = max310x_id_table,
}; };
module_spi_driver(max310x_driver); module_spi_driver(max310x_driver);

View file

@ -743,9 +743,10 @@ static struct uart_driver serial_m3110_reg = {
.cons = &serial_m3110_console, .cons = &serial_m3110_console,
}; };
#ifdef CONFIG_PM #ifdef CONFIG_PM_SLEEP
static int serial_m3110_suspend(struct spi_device *spi, pm_message_t state) static int serial_m3110_suspend(struct device *dev)
{ {
struct spi_device *spi = to_spi_device(dev);
struct uart_max3110 *max = spi_get_drvdata(spi); struct uart_max3110 *max = spi_get_drvdata(spi);
disable_irq(max->irq); disable_irq(max->irq);
@ -754,8 +755,9 @@ static int serial_m3110_suspend(struct spi_device *spi, pm_message_t state)
return 0; 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); struct uart_max3110 *max = spi_get_drvdata(spi);
max3110_out(max, max->cur_conf); max3110_out(max, max->cur_conf);
@ -763,9 +765,13 @@ static int serial_m3110_resume(struct spi_device *spi)
enable_irq(max->irq); enable_irq(max->irq);
return 0; 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 #else
#define serial_m3110_suspend NULL #define SERIAL_M3110_PM_OPS NULL
#define serial_m3110_resume NULL
#endif #endif
static int serial_m3110_probe(struct spi_device *spi) static int serial_m3110_probe(struct spi_device *spi)
@ -872,11 +878,10 @@ static struct spi_driver uart_max3110_driver = {
.driver = { .driver = {
.name = "spi_max3111", .name = "spi_max3111",
.owner = THIS_MODULE, .owner = THIS_MODULE,
.pm = SERIAL_M3110_PM_OPS,
}, },
.probe = serial_m3110_probe, .probe = serial_m3110_probe,
.remove = serial_m3110_remove, .remove = serial_m3110_remove,
.suspend = serial_m3110_suspend,
.resume = serial_m3110_resume,
}; };
static int __init serial_m3110_init(void) static int __init serial_m3110_init(void)

View file

@ -907,7 +907,6 @@ static void msm_hs_dmov_rx_callback(struct msm_dmov_cmd *cmd_ptr,
unsigned int error_f = 0; unsigned int error_f = 0;
unsigned long flags; unsigned long flags;
unsigned int flush; unsigned int flush;
struct tty_struct *tty;
struct tty_port *port; struct tty_port *port;
struct uart_port *uport; struct uart_port *uport;
struct msm_hs_port *msm_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); clk_enable(msm_uport->clk);
port = &uport->state->port; port = &uport->state->port;
tty = port->tty;
msm_hs_write(uport, UARTDM_CR_ADDR, STALE_EVENT_DISABLE); msm_hs_write(uport, UARTDM_CR_ADDR, STALE_EVENT_DISABLE);

View file

@ -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) 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 i, res = 0;
int n = tty->index;
const char *name = NULL; const char *name = NULL;
struct smd_tty_info *info = smd_tty + n;
for (i = 0; i < smd_tty_channels_len; i++) { 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; name = smd_tty_channels[i].name;
break; 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) static void smd_tty_port_shutdown(struct tty_port *tport)
{ {
struct smd_tty_info *info; struct smd_tty_info *info = container_of(tport, struct smd_tty_info,
struct tty_struct *tty = tty_port_tty_get(tport); port);
info = tty->driver_data;
if (info->ch) { if (info->ch) {
smd_close(info->ch); smd_close(info->ch);
info->ch = 0; info->ch = 0;
} }
tty->driver_data = 0;
tty_kref_put(tty);
} }
static int smd_tty_open(struct tty_struct *tty, struct file *f) static int smd_tty_open(struct tty_struct *tty, struct file *f)

View file

@ -883,7 +883,7 @@ auart_console_write(struct console *co, const char *str, unsigned int count)
unsigned int old_ctrl0, old_ctrl2; unsigned int old_ctrl0, old_ctrl2;
unsigned int to = 1000; unsigned int to = 1000;
if (co->index > MXS_AUART_PORTS || co->index < 0) if (co->index >= MXS_AUART_PORTS || co->index < 0)
return; return;
s = auart_port[co->index]; s = auart_port[co->index];
@ -1103,7 +1103,7 @@ static int mxs_auart_probe(struct platform_device *pdev)
s->port.fifosize = 16; s->port.fifosize = 16;
s->port.uartclk = clk_get_rate(s->clk); s->port.uartclk = clk_get_rate(s->clk);
s->port.type = PORT_IMX; s->port.type = PORT_IMX;
s->port.dev = s->dev = get_device(&pdev->dev); s->port.dev = s->dev = &pdev->dev;
s->ctrl = 0; s->ctrl = 0;
@ -1134,7 +1134,6 @@ static int mxs_auart_probe(struct platform_device *pdev)
auart_port[pdev->id] = NULL; auart_port[pdev->id] = NULL;
free_irq(s->irq, s); free_irq(s->irq, s);
out_free_clk: out_free_clk:
put_device(s->dev);
clk_put(s->clk); clk_put(s->clk);
out_free: out_free:
kfree(s); kfree(s);
@ -1150,7 +1149,6 @@ static int mxs_auart_remove(struct platform_device *pdev)
auart_port[pdev->id] = NULL; auart_port[pdev->id] = NULL;
put_device(s->dev);
clk_put(s->clk); clk_put(s->clk);
free_irq(s->irq, s); free_irq(s->irq, s);
kfree(s); kfree(s);

View file

@ -14,7 +14,6 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/serial_core.h> #include <linux/serial_core.h>
#include <linux/serial_8250.h>
#include <linux/serial_reg.h> #include <linux/serial_reg.h>
#include <linux/of_address.h> #include <linux/of_address.h>
#include <linux/of_irq.h> #include <linux/of_irq.h>
@ -22,6 +21,8 @@
#include <linux/nwpserial.h> #include <linux/nwpserial.h>
#include <linux/clk.h> #include <linux/clk.h>
#include "8250/8250.h"
struct of_serial_info { struct of_serial_info {
struct clk *clk; struct clk *clk;
int type; 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) if (of_property_read_u32(np, "reg-shift", &prop) == 0)
port->regshift = prop; 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->irq = irq_of_parse_and_map(np, 0);
port->iotype = UPIO_MEM; port->iotype = UPIO_MEM;
if (of_property_read_u32(np, "reg-io-width", &prop) == 0) { 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 #ifdef CONFIG_SERIAL_8250
case PORT_8250 ... PORT_MAX_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; struct uart_8250_port port8250;
memset(&port8250, 0, sizeof(port8250)); memset(&port8250, 0, sizeof(port8250));
port8250.port = port; 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); ret = serial8250_register_8250_port(&port8250);
break; break;
} }

View file

@ -1493,29 +1493,6 @@ static int pch_uart_verify_port(struct uart_port *port,
return 0; 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 * 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) static void pch_console_putchar(struct uart_port *port, int ch)
{ {
struct eg20t_port *priv = struct eg20t_port *priv =
@ -1655,7 +1710,7 @@ static struct console pch_console = {
#define PCH_CONSOLE (&pch_console) #define PCH_CONSOLE (&pch_console)
#else #else
#define PCH_CONSOLE NULL #define PCH_CONSOLE NULL
#endif #endif /* CONFIG_SERIAL_PCH_UART_CONSOLE */
static struct uart_driver pch_uart_driver = { static struct uart_driver pch_uart_driver = {
.owner = THIS_MODULE, .owner = THIS_MODULE,

View file

@ -39,6 +39,7 @@
#include <linux/tty_flip.h> #include <linux/tty_flip.h>
#include <linux/serial_core.h> #include <linux/serial_core.h>
#include <linux/serial.h> #include <linux/serial.h>
#include <linux/serial_s3c.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/cpufreq.h> #include <linux/cpufreq.h>
@ -46,10 +47,9 @@
#include <asm/irq.h> #include <asm/irq.h>
#include <mach/hardware.h> #ifdef CONFIG_SAMSUNG_CLOCK
#include <plat/regs-serial.h>
#include <plat/clock.h> #include <plat/clock.h>
#endif
#include "samsung.h" #include "samsung.h"
@ -446,6 +446,8 @@ static void s3c24xx_serial_shutdown(struct uart_port *port)
/* Clear pending interrupts and mask all interrupts */ /* Clear pending interrupts and mask all interrupts */
if (s3c24xx_serial_has_interrupt_mask(port)) { if (s3c24xx_serial_has_interrupt_mask(port)) {
free_irq(port->irq, ourport);
wr_regl(port, S3C64XX_UINTP, 0xf); wr_regl(port, S3C64XX_UINTP, 0xf);
wr_regl(port, S3C64XX_UINTM, 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", dbg("s3c64xx_serial_startup: port=%p (%08lx,%p)\n",
port->mapbase, port->membase); port->mapbase, port->membase);
wr_regl(port, S3C64XX_UINTM, 0xf);
ret = request_irq(port->irq, s3c64xx_serial_handle_irq, IRQF_SHARED, ret = request_irq(port->irq, s3c64xx_serial_handle_irq, IRQF_SHARED,
s3c24xx_serial_portname(port), ourport); s3c24xx_serial_portname(port), ourport);
if (ret) { if (ret) {
@ -894,7 +898,7 @@ console_initcall(s3c24xx_serial_console_init);
#define S3C24XX_SERIAL_CONSOLE NULL #define S3C24XX_SERIAL_CONSOLE NULL
#endif #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 int s3c24xx_serial_get_poll_char(struct uart_port *port);
static void s3c24xx_serial_put_poll_char(struct uart_port *port, static void s3c24xx_serial_put_poll_char(struct uart_port *port,
unsigned char c); unsigned char c);
@ -918,7 +922,7 @@ static struct uart_ops s3c24xx_serial_ops = {
.request_port = s3c24xx_serial_request_port, .request_port = s3c24xx_serial_request_port,
.config_port = s3c24xx_serial_config_port, .config_port = s3c24xx_serial_config_port,
.verify_port = s3c24xx_serial_verify_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_get_char = s3c24xx_serial_get_poll_char,
.poll_put_char = s3c24xx_serial_put_poll_char, .poll_put_char = s3c24xx_serial_put_poll_char,
#endif #endif
@ -1179,6 +1183,7 @@ static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport,
return 0; return 0;
} }
#ifdef CONFIG_SAMSUNG_CLOCK
static ssize_t s3c24xx_serial_show_clksrc(struct device *dev, static ssize_t s3c24xx_serial_show_clksrc(struct device *dev,
struct device_attribute *attr, struct device_attribute *attr,
char *buf) 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); static DEVICE_ATTR(clock_source, S_IRUGO, s3c24xx_serial_show_clksrc, NULL);
#endif
/* Device driver serial port probe */ /* 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); uart_add_one_port(&s3c24xx_uart_drv, &ourport->port);
platform_set_drvdata(pdev, &ourport->port); platform_set_drvdata(pdev, &ourport->port);
#ifdef CONFIG_SAMSUNG_CLOCK
ret = device_create_file(&pdev->dev, &dev_attr_clock_source); ret = device_create_file(&pdev->dev, &dev_attr_clock_source);
if (ret < 0) if (ret < 0)
dev_err(&pdev->dev, "failed to add clock source attr.\n"); dev_err(&pdev->dev, "failed to add clock source attr.\n");
#endif
ret = s3c24xx_serial_cpufreq_register(ourport); ret = s3c24xx_serial_cpufreq_register(ourport);
if (ret < 0) if (ret < 0)
@ -1272,7 +1279,9 @@ static int s3c24xx_serial_remove(struct platform_device *dev)
if (port) { if (port) {
s3c24xx_serial_cpufreq_deregister(to_ourport(port)); s3c24xx_serial_cpufreq_deregister(to_ourport(port));
#ifdef CONFIG_SAMSUNG_CLOCK
device_remove_file(&dev->dev, &dev_attr_clock_source); device_remove_file(&dev->dev, &dev_attr_clock_source);
#endif
uart_remove_one_port(&s3c24xx_uart_drv, port); uart_remove_one_port(&s3c24xx_uart_drv, port);
} }
@ -1307,9 +1316,29 @@ static int s3c24xx_serial_resume(struct device *dev)
return 0; 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 = { static const struct dev_pm_ops s3c24xx_serial_pm_ops = {
.suspend = s3c24xx_serial_suspend, .suspend = s3c24xx_serial_suspend,
.resume = s3c24xx_serial_resume, .resume = s3c24xx_serial_resume,
.resume_noirq = s3c24xx_serial_resume_noirq,
}; };
#define SERIAL_SAMSUNG_PM_OPS (&s3c24xx_serial_pm_ops) #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; 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 #ifdef CONFIG_CONSOLE_POLL
/* /*
* Console polling routines for writing and reading from the uart while * 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 char c)
{ {
unsigned int ufcon = rd_regl(cons_uart, S3C2410_UFCON); 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)) while (!s3c24xx_serial_console_txrdy(port, ufcon))
cpu_relax(); cpu_relax();
@ -1377,6 +1418,12 @@ static void
s3c24xx_serial_console_putchar(struct uart_port *port, int ch) s3c24xx_serial_console_putchar(struct uart_port *port, int ch)
{ {
unsigned int ufcon = rd_regl(cons_uart, S3C2410_UFCON); 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)) while (!s3c24xx_serial_console_txrdy(port, ufcon))
barrier(); barrier();
wr_regb(cons_uart, S3C2410_UTXH, ch); 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", "registers: ulcon=%08x, ucon=%08x, ubdriv=%08x\n",
port, ulcon, ucon, ubrdiv); port, ulcon, ucon, ubrdiv);
if ((ucon & 0xf) != 0) { if (s3c24xx_port_configured(ucon)) {
/* consider the serial port configured if the tx/rx mode set */
switch (ulcon & S3C2410_LCON_CSMASK) { switch (ulcon & S3C2410_LCON_CSMASK) {
case S3C2410_LCON_CS5: case S3C2410_LCON_CS5:
*bits = 5; *bits = 5;

View file

@ -76,7 +76,9 @@ struct s3c24xx_uart_port {
#define wr_regb(port, reg, val) __raw_writeb(val, portaddr(port, reg)) #define wr_regb(port, reg, val) __raw_writeb(val, portaddr(port, reg))
#define wr_regl(port, reg, val) __raw_writel(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 *); extern void printascii(const char *);

View file

@ -27,6 +27,7 @@
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/platform_data/serial-sccnxp.h> #include <linux/platform_data/serial-sccnxp.h>
#include <linux/regulator/consumer.h>
#define SCCNXP_NAME "uart-sccnxp" #define SCCNXP_NAME "uart-sccnxp"
#define SCCNXP_MAJOR 204 #define SCCNXP_MAJOR 204
@ -131,6 +132,8 @@ struct sccnxp_port {
struct timer_list timer; struct timer_list timer;
struct sccnxp_pdata pdata; struct sccnxp_pdata pdata;
struct regulator *regulator;
}; };
static inline u8 sccnxp_raw_read(void __iomem *base, u8 reg, u8 shift) 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; return -EADDRNOTAVAIL;
} }
dev_set_name(&pdev->dev, SCCNXP_NAME);
s = devm_kzalloc(&pdev->dev, sizeof(struct sccnxp_port), GFP_KERNEL); s = devm_kzalloc(&pdev->dev, sizeof(struct sccnxp_port), GFP_KERNEL);
if (!s) { if (!s) {
dev_err(&pdev->dev, "Error allocating port structure\n"); dev_err(&pdev->dev, "Error allocating port structure\n");
@ -918,6 +919,16 @@ static int sccnxp_probe(struct platform_device *pdev)
goto err_out; 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); membase = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(membase)) { if (IS_ERR(membase)) {
ret = PTR_ERR(membase); ret = PTR_ERR(membase);
@ -967,10 +978,6 @@ static int sccnxp_probe(struct platform_device *pdev)
s->imr = 0; s->imr = 0;
sccnxp_write(&s->port[0], SCCNXP_IMR_REG, 0); sccnxp_write(&s->port[0], SCCNXP_IMR_REG, 0);
/* Board specific configure */
if (s->pdata.init)
s->pdata.init();
if (!s->poll) { if (!s->poll) {
ret = devm_request_threaded_irq(&pdev->dev, s->irq, NULL, ret = devm_request_threaded_irq(&pdev->dev, s->irq, NULL,
sccnxp_ist, sccnxp_ist,
@ -1011,8 +1018,8 @@ static int sccnxp_remove(struct platform_device *pdev)
uart_unregister_driver(&s->uart); uart_unregister_driver(&s->uart);
platform_set_drvdata(pdev, NULL); platform_set_drvdata(pdev, NULL);
if (s->pdata.exit) if (!IS_ERR(s->regulator))
s->pdata.exit(); return regulator_disable(s->regulator);
return 0; return 0;
} }

View file

@ -26,6 +26,7 @@
#include <linux/dmaengine.h> #include <linux/dmaengine.h>
#include <linux/dma-mapping.h> #include <linux/dma-mapping.h>
#include <linux/dmapool.h> #include <linux/dmapool.h>
#include <linux/err.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/irq.h> #include <linux/irq.h>
#include <linux/module.h> #include <linux/module.h>
@ -1301,11 +1302,9 @@ static int tegra_uart_probe(struct platform_device *pdev)
} }
u->mapbase = resource->start; u->mapbase = resource->start;
u->membase = devm_request_and_ioremap(&pdev->dev, resource); u->membase = devm_ioremap_resource(&pdev->dev, resource);
if (!u->membase) { if (IS_ERR(u->membase))
dev_err(&pdev->dev, "memregion/iomap address req failed\n"); return PTR_ERR(u->membase);
return -EADDRNOTAVAIL;
}
tup->uart_clk = devm_clk_get(&pdev->dev, NULL); tup->uart_clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(tup->uart_clk)) { if (IS_ERR(tup->uart_clk)) {

View file

@ -1941,6 +1941,8 @@ int uart_suspend_port(struct uart_driver *drv, struct uart_port *uport)
mutex_unlock(&port->mutex); mutex_unlock(&port->mutex);
return 0; return 0;
} }
put_device(tty_dev);
if (console_suspend_enabled || !uart_console(uport)) if (console_suspend_enabled || !uart_console(uport))
uport->suspended = 1; uport->suspended = 1;
@ -2006,9 +2008,11 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *uport)
disable_irq_wake(uport->irq); disable_irq_wake(uport->irq);
uport->irq_wake = 0; uport->irq_wake = 0;
} }
put_device(tty_dev);
mutex_unlock(&port->mutex); mutex_unlock(&port->mutex);
return 0; return 0;
} }
put_device(tty_dev);
uport->suspended = 0; uport->suspended = 0;
/* /*

View file

@ -15,8 +15,6 @@
defined(CONFIG_CPU_SUBTYPE_SH7720) || \ defined(CONFIG_CPU_SUBTYPE_SH7720) || \
defined(CONFIG_CPU_SUBTYPE_SH7721) || \ defined(CONFIG_CPU_SUBTYPE_SH7721) || \
defined(CONFIG_ARCH_SH73A0) || \ defined(CONFIG_ARCH_SH73A0) || \
defined(CONFIG_ARCH_SH7367) || \
defined(CONFIG_ARCH_SH7377) || \
defined(CONFIG_ARCH_SH7372) || \ defined(CONFIG_ARCH_SH7372) || \
defined(CONFIG_ARCH_R8A7740) defined(CONFIG_ARCH_R8A7740)

View file

@ -758,7 +758,7 @@ static struct of_device_id sirfsoc_uart_ids[] = {
{ .compatible = "sirf,marco-uart", }, { .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 = { static struct platform_driver sirfsoc_uart_driver = {
.probe = sirfsoc_uart_probe, .probe = sirfsoc_uart_probe,

View file

@ -203,7 +203,7 @@ receive_chars(struct uart_sunsab_port *up,
flag = TTY_FRAME; flag = TTY_FRAME;
} }
if (uart_handle_sysrq_char(&up->port, ch)) if (uart_handle_sysrq_char(&up->port, ch) || !port)
continue; continue;
if ((stat->sreg.isr0 & (up->port.ignore_status_mask & 0xff)) == 0 && if ((stat->sreg.isr0 & (up->port.ignore_status_mask & 0xff)) == 0 &&

View file

@ -388,7 +388,7 @@ sunzilog_receive_chars(struct uart_sunzilog_port *up,
else if (r1 & CRC_ERR) else if (r1 & CRC_ERR)
flag = TTY_FRAME; flag = TTY_FRAME;
} }
if (uart_handle_sysrq_char(&up->port, ch)) if (uart_handle_sysrq_char(&up->port, ch) || !port)
continue; continue;
if (up->port.ignore_status_mask == 0xff || if (up->port.ignore_status_mask == 0xff ||

View file

@ -35,6 +35,7 @@
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/err.h>
/* /*
* UART Register offsets * UART Register offsets
@ -585,9 +586,9 @@ static int vt8500_serial_probe(struct platform_device *pdev)
if (!vt8500_port) if (!vt8500_port)
return -ENOMEM; return -ENOMEM;
vt8500_port->uart.membase = devm_request_and_ioremap(&pdev->dev, mmres); vt8500_port->uart.membase = devm_ioremap_resource(&pdev->dev, mmres);
if (!vt8500_port->uart.membase) if (IS_ERR(vt8500_port->uart.membase))
return -EADDRNOTAVAIL; return PTR_ERR(vt8500_port->uart.membase);
vt8500_port->clk = of_clk_get(pdev->dev.of_node, 0); vt8500_port->clk = of_clk_get(pdev->dev.of_node, 0);
if (IS_ERR(vt8500_port->clk)) { if (IS_ERR(vt8500_port->clk)) {

View file

@ -585,9 +585,6 @@ static int xuartps_startup(struct uart_port *port)
xuartps_writel(XUARTPS_IXR_TXEMPTY | XUARTPS_IXR_PARITY | xuartps_writel(XUARTPS_IXR_TXEMPTY | XUARTPS_IXR_PARITY |
XUARTPS_IXR_FRAMING | XUARTPS_IXR_OVERRUN | XUARTPS_IXR_FRAMING | XUARTPS_IXR_OVERRUN |
XUARTPS_IXR_RXTRIG | XUARTPS_IXR_TOUT, XUARTPS_IER_OFFSET); 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; return retval;
} }

View file

@ -1058,9 +1058,6 @@ static void mgsl_bh_handler(struct work_struct *work)
container_of(work, struct mgsl_struct, task); container_of(work, struct mgsl_struct, task);
int action; int action;
if (!info)
return;
if ( debug_level >= DEBUG_LEVEL_BH ) if ( debug_level >= DEBUG_LEVEL_BH )
printk( "%s(%d):mgsl_bh_handler(%s) entry\n", printk( "%s(%d):mgsl_bh_handler(%s) entry\n",
__FILE__,__LINE__,info->device_name); __FILE__,__LINE__,info->device_name);
@ -3311,7 +3308,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
port->blocked_open++; port->blocked_open++;
while (1) { while (1) {
if (tty->termios.c_cflag & CBAUD) if (C_BAUD(tty) && test_bit(ASYNCB_INITIALIZED, &port->flags))
tty_port_raise_dtr_rts(port); tty_port_raise_dtr_rts(port);
set_current_state(TASK_INTERRUPTIBLE); set_current_state(TASK_INTERRUPTIBLE);

View file

@ -3308,7 +3308,7 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp,
port->blocked_open++; port->blocked_open++;
while (1) { while (1) {
if ((tty->termios.c_cflag & CBAUD)) if (C_BAUD(tty) && test_bit(ASYNCB_INITIALIZED, &port->flags))
tty_port_raise_dtr_rts(port); tty_port_raise_dtr_rts(port);
set_current_state(TASK_INTERRUPTIBLE); set_current_state(TASK_INTERRUPTIBLE);

View file

@ -3329,7 +3329,7 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp,
port->blocked_open++; port->blocked_open++;
while (1) { while (1) {
if (tty->termios.c_cflag & CBAUD) if (C_BAUD(tty) && test_bit(ASYNCB_INITIALIZED, &port->flags))
tty_port_raise_dtr_rts(port); tty_port_raise_dtr_rts(port);
set_current_state(TASK_INTERRUPTIBLE); set_current_state(TASK_INTERRUPTIBLE);

View file

@ -101,7 +101,7 @@ static void sysrq_handle_SAK(int key)
} }
static struct sysrq_key_op sysrq_SAK_op = { static struct sysrq_key_op sysrq_SAK_op = {
.handler = sysrq_handle_SAK, .handler = sysrq_handle_SAK,
.help_msg = "saK", .help_msg = "sak(k)",
.action_msg = "SAK", .action_msg = "SAK",
.enable_mask = SYSRQ_ENABLE_KEYBOARD, .enable_mask = SYSRQ_ENABLE_KEYBOARD,
}; };
@ -117,7 +117,7 @@ static void sysrq_handle_unraw(int key)
static struct sysrq_key_op sysrq_unraw_op = { static struct sysrq_key_op sysrq_unraw_op = {
.handler = sysrq_handle_unraw, .handler = sysrq_handle_unraw,
.help_msg = "unRaw", .help_msg = "unraw(r)",
.action_msg = "Keyboard mode set to system default", .action_msg = "Keyboard mode set to system default",
.enable_mask = SYSRQ_ENABLE_KEYBOARD, .enable_mask = SYSRQ_ENABLE_KEYBOARD,
}; };
@ -135,7 +135,7 @@ static void sysrq_handle_crash(int key)
} }
static struct sysrq_key_op sysrq_crash_op = { static struct sysrq_key_op sysrq_crash_op = {
.handler = sysrq_handle_crash, .handler = sysrq_handle_crash,
.help_msg = "Crash", .help_msg = "crash(c)",
.action_msg = "Trigger a crash", .action_msg = "Trigger a crash",
.enable_mask = SYSRQ_ENABLE_DUMP, .enable_mask = SYSRQ_ENABLE_DUMP,
}; };
@ -148,7 +148,7 @@ static void sysrq_handle_reboot(int key)
} }
static struct sysrq_key_op sysrq_reboot_op = { static struct sysrq_key_op sysrq_reboot_op = {
.handler = sysrq_handle_reboot, .handler = sysrq_handle_reboot,
.help_msg = "reBoot", .help_msg = "reboot(b)",
.action_msg = "Resetting", .action_msg = "Resetting",
.enable_mask = SYSRQ_ENABLE_BOOT, .enable_mask = SYSRQ_ENABLE_BOOT,
}; };
@ -159,7 +159,7 @@ static void sysrq_handle_sync(int key)
} }
static struct sysrq_key_op sysrq_sync_op = { static struct sysrq_key_op sysrq_sync_op = {
.handler = sysrq_handle_sync, .handler = sysrq_handle_sync,
.help_msg = "Sync", .help_msg = "sync(s)",
.action_msg = "Emergency Sync", .action_msg = "Emergency Sync",
.enable_mask = SYSRQ_ENABLE_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 = { static struct sysrq_key_op sysrq_show_timers_op = {
.handler = sysrq_handle_show_timers, .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)", .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 = { static struct sysrq_key_op sysrq_mountro_op = {
.handler = sysrq_handle_mountro, .handler = sysrq_handle_mountro,
.help_msg = "Unmount", .help_msg = "unmount(u)",
.action_msg = "Emergency Remount R/O", .action_msg = "Emergency Remount R/O",
.enable_mask = SYSRQ_ENABLE_REMOUNT, .enable_mask = SYSRQ_ENABLE_REMOUNT,
}; };
@ -194,7 +194,7 @@ static void sysrq_handle_showlocks(int key)
static struct sysrq_key_op sysrq_showlocks_op = { static struct sysrq_key_op sysrq_showlocks_op = {
.handler = sysrq_handle_showlocks, .handler = sysrq_handle_showlocks,
.help_msg = "show-all-locks(D)", .help_msg = "show-all-locks(d)",
.action_msg = "Show Locks Held", .action_msg = "Show Locks Held",
}; };
#else #else
@ -245,7 +245,7 @@ static void sysrq_handle_showallcpus(int key)
static struct sysrq_key_op sysrq_showallcpus_op = { static struct sysrq_key_op sysrq_showallcpus_op = {
.handler = sysrq_handle_showallcpus, .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", .action_msg = "Show backtrace of all active CPUs",
.enable_mask = SYSRQ_ENABLE_DUMP, .enable_mask = SYSRQ_ENABLE_DUMP,
}; };
@ -260,7 +260,7 @@ static void sysrq_handle_showregs(int key)
} }
static struct sysrq_key_op sysrq_showregs_op = { static struct sysrq_key_op sysrq_showregs_op = {
.handler = sysrq_handle_showregs, .handler = sysrq_handle_showregs,
.help_msg = "show-registers(P)", .help_msg = "show-registers(p)",
.action_msg = "Show Regs", .action_msg = "Show Regs",
.enable_mask = SYSRQ_ENABLE_DUMP, .enable_mask = SYSRQ_ENABLE_DUMP,
}; };
@ -271,7 +271,7 @@ static void sysrq_handle_showstate(int key)
} }
static struct sysrq_key_op sysrq_showstate_op = { static struct sysrq_key_op sysrq_showstate_op = {
.handler = sysrq_handle_showstate, .handler = sysrq_handle_showstate,
.help_msg = "show-task-states(T)", .help_msg = "show-task-states(t)",
.action_msg = "Show State", .action_msg = "Show State",
.enable_mask = SYSRQ_ENABLE_DUMP, .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 = { static struct sysrq_key_op sysrq_showstate_blocked_op = {
.handler = sysrq_handle_showstate_blocked, .handler = sysrq_handle_showstate_blocked,
.help_msg = "show-blocked-tasks(W)", .help_msg = "show-blocked-tasks(w)",
.action_msg = "Show Blocked State", .action_msg = "Show Blocked State",
.enable_mask = SYSRQ_ENABLE_DUMP, .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 = { static struct sysrq_key_op sysrq_ftrace_dump_op = {
.handler = sysrq_ftrace_dump, .handler = sysrq_ftrace_dump,
.help_msg = "dump-ftrace-buffer(Z)", .help_msg = "dump-ftrace-buffer(z)",
.action_msg = "Dump ftrace buffer", .action_msg = "Dump ftrace buffer",
.enable_mask = SYSRQ_ENABLE_DUMP, .enable_mask = SYSRQ_ENABLE_DUMP,
}; };
@ -310,7 +310,7 @@ static void sysrq_handle_showmem(int key)
} }
static struct sysrq_key_op sysrq_showmem_op = { static struct sysrq_key_op sysrq_showmem_op = {
.handler = sysrq_handle_showmem, .handler = sysrq_handle_showmem,
.help_msg = "show-memory-usage(M)", .help_msg = "show-memory-usage(m)",
.action_msg = "Show Memory", .action_msg = "Show Memory",
.enable_mask = SYSRQ_ENABLE_DUMP, .enable_mask = SYSRQ_ENABLE_DUMP,
}; };
@ -341,7 +341,7 @@ static void sysrq_handle_term(int key)
} }
static struct sysrq_key_op sysrq_term_op = { static struct sysrq_key_op sysrq_term_op = {
.handler = sysrq_handle_term, .handler = sysrq_handle_term,
.help_msg = "terminate-all-tasks(E)", .help_msg = "terminate-all-tasks(e)",
.action_msg = "Terminate All Tasks", .action_msg = "Terminate All Tasks",
.enable_mask = SYSRQ_ENABLE_SIGNAL, .enable_mask = SYSRQ_ENABLE_SIGNAL,
}; };
@ -360,7 +360,7 @@ static void sysrq_handle_moom(int key)
} }
static struct sysrq_key_op sysrq_moom_op = { static struct sysrq_key_op sysrq_moom_op = {
.handler = sysrq_handle_moom, .handler = sysrq_handle_moom,
.help_msg = "memory-full-oom-kill(F)", .help_msg = "memory-full-oom-kill(f)",
.action_msg = "Manual OOM execution", .action_msg = "Manual OOM execution",
.enable_mask = SYSRQ_ENABLE_SIGNAL, .enable_mask = SYSRQ_ENABLE_SIGNAL,
}; };
@ -372,7 +372,7 @@ static void sysrq_handle_thaw(int key)
} }
static struct sysrq_key_op sysrq_thaw_op = { static struct sysrq_key_op sysrq_thaw_op = {
.handler = sysrq_handle_thaw, .handler = sysrq_handle_thaw,
.help_msg = "thaw-filesystems(J)", .help_msg = "thaw-filesystems(j)",
.action_msg = "Emergency Thaw of all frozen filesystems", .action_msg = "Emergency Thaw of all frozen filesystems",
.enable_mask = SYSRQ_ENABLE_SIGNAL, .enable_mask = SYSRQ_ENABLE_SIGNAL,
}; };
@ -385,7 +385,7 @@ static void sysrq_handle_kill(int key)
} }
static struct sysrq_key_op sysrq_kill_op = { static struct sysrq_key_op sysrq_kill_op = {
.handler = sysrq_handle_kill, .handler = sysrq_handle_kill,
.help_msg = "kill-all-tasks(I)", .help_msg = "kill-all-tasks(i)",
.action_msg = "Kill All Tasks", .action_msg = "Kill All Tasks",
.enable_mask = SYSRQ_ENABLE_SIGNAL, .enable_mask = SYSRQ_ENABLE_SIGNAL,
}; };
@ -396,7 +396,7 @@ static void sysrq_handle_unrt(int key)
} }
static struct sysrq_key_op sysrq_unrt_op = { static struct sysrq_key_op sysrq_unrt_op = {
.handler = sysrq_handle_unrt, .handler = sysrq_handle_unrt,
.help_msg = "nice-all-RT-tasks(N)", .help_msg = "nice-all-RT-tasks(n)",
.action_msg = "Nice All RT Tasks", .action_msg = "Nice All RT Tasks",
.enable_mask = SYSRQ_ENABLE_RTNICE, .enable_mask = SYSRQ_ENABLE_RTNICE,
}; };

View file

@ -449,11 +449,6 @@ static void flush_to_ldisc(struct work_struct *work)
tty_buffer_free(port, head); tty_buffer_free(port, head);
continue; 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) if (!tty->receive_room)
break; break;
if (count > tty->receive_room) 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, disc->ops->receive_buf(tty, char_buf,
flag_buf, count); flag_buf, count);
spin_lock_irqsave(&buf->lock, flags); 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); 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); spin_unlock_irqrestore(&buf->lock, flags);
tty_ldisc_deref(disc); tty_ldisc_deref(disc);

View file

@ -532,6 +532,60 @@ void tty_wakeup(struct tty_struct *tty)
EXPORT_SYMBOL_GPL(tty_wakeup); 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 * __tty_hangup - actual handler for hangup events
* @work: tty device * @work: tty device
@ -554,15 +608,13 @@ EXPORT_SYMBOL_GPL(tty_wakeup);
* tasklist_lock to walk task list for hangup event * tasklist_lock to walk task list for hangup event
* ->siglock to protect ->signal/->sighand * ->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 *cons_filp = NULL;
struct file *filp, *f = NULL; struct file *filp, *f = NULL;
struct task_struct *p;
struct tty_file_private *priv; struct tty_file_private *priv;
int closecount = 0, n; int closecount = 0, n;
unsigned long flags; int refs;
int refs = 0;
if (!tty) if (!tty)
return; return;
@ -599,39 +651,18 @@ static void __tty_hangup(struct tty_struct *tty)
} }
spin_unlock(&tty_files_lock); 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 * it drops BTM and thus races with reopen
* we protect the race by TTY_HUPPING * we protect the race by TTY_HUPPING
*/ */
tty_ldisc_hangup(tty); tty_ldisc_hangup(tty);
read_lock(&tasklist_lock); spin_lock_irq(&tty->ctrl_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);
clear_bit(TTY_THROTTLED, &tty->flags); clear_bit(TTY_THROTTLED, &tty->flags);
clear_bit(TTY_PUSH, &tty->flags); clear_bit(TTY_PUSH, &tty->flags);
clear_bit(TTY_DO_WRITE_WAKEUP, &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->session = NULL;
tty->pgrp = NULL; tty->pgrp = NULL;
tty->ctrl_status = 0; tty->ctrl_status = 0;
spin_unlock_irqrestore(&tty->ctrl_lock, flags); spin_unlock_irq(&tty->ctrl_lock);
/* Account for the p->signal references we killed */
while (refs--)
tty_kref_put(tty);
/* /*
* If one of the devices matches a console pointer, we * 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); set_bit(TTY_HUPPED, &tty->flags);
clear_bit(TTY_HUPPING, &tty->flags); clear_bit(TTY_HUPPING, &tty->flags);
tty_ldisc_enable(tty);
tty_unlock(tty); tty_unlock(tty);
@ -679,7 +705,7 @@ static void do_tty_hangup(struct work_struct *work)
struct tty_struct *tty = struct tty_struct *tty =
container_of(work, struct tty_struct, hangup_work); 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)); printk(KERN_DEBUG "%s vhangup...\n", tty_name(tty, buf));
#endif #endif
__tty_hangup(tty); __tty_hangup(tty, 0);
} }
EXPORT_SYMBOL(tty_vhangup); 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 * tty_hung_up_p - was tty hung up
* @filp: file pointer of tty * @filp: file pointer of tty
@ -797,18 +844,18 @@ void disassociate_ctty(int on_exit)
tty = get_current_tty(); tty = get_current_tty();
if (tty) { if (tty) {
struct pid *tty_pgrp = get_pid(tty->pgrp); if (on_exit && tty->driver->type != TTY_DRIVER_TYPE_PTY) {
if (on_exit) { tty_vhangup_session(tty);
if (tty->driver->type != TTY_DRIVER_TYPE_PTY) } else {
tty_vhangup(tty); 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); 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) { } else if (on_exit) {
struct pid *old_pgrp; struct pid *old_pgrp;
spin_lock_irq(&current->sighand->siglock); spin_lock_irq(&current->sighand->siglock);
@ -1358,9 +1405,7 @@ static int tty_reopen(struct tty_struct *tty)
} }
tty->count++; tty->count++;
mutex_lock(&tty->ldisc_mutex);
WARN_ON(!test_bit(TTY_LDISC, &tty->flags)); WARN_ON(!test_bit(TTY_LDISC, &tty->flags));
mutex_unlock(&tty->ldisc_mutex);
return 0; return 0;
} }
@ -1477,6 +1522,17 @@ void tty_free_termios(struct tty_struct *tty)
} }
EXPORT_SYMBOL(tty_free_termios); 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 * 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_free_termios(tty);
tty_driver_remove_tty(tty->driver, tty); tty_driver_remove_tty(tty->driver, tty);
tty->port->itty = NULL; tty->port->itty = NULL;
cancel_work_sync(&tty->port->buf.work);
if (tty->link) if (tty->link)
tty_kref_put(tty->link); tty_kref_put(tty->link);
@ -1791,12 +1848,21 @@ int tty_release(struct inode *inode, struct file *filp)
return 0; return 0;
#ifdef TTY_DEBUG_HANGUP #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 #endif
/* /*
* Ask the line discipline code to release its structures * Ask the line discipline code to release its structures
*/ */
tty_ldisc_release(tty, o_tty); 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 release_tty function takes care of the details of clearing
* the slots and preserving the termios structure. The tty_unlock_pair * the slots and preserving the termios structure. The tty_unlock_pair

View file

@ -106,6 +106,7 @@ void tty_throttle(struct tty_struct *tty)
if (!test_and_set_bit(TTY_THROTTLED, &tty->flags) && if (!test_and_set_bit(TTY_THROTTLED, &tty->flags) &&
tty->ops->throttle) tty->ops->throttle)
tty->ops->throttle(tty); tty->ops->throttle(tty);
tty->flow_change = 0;
mutex_unlock(&tty->termios_mutex); mutex_unlock(&tty->termios_mutex);
} }
EXPORT_SYMBOL(tty_throttle); EXPORT_SYMBOL(tty_throttle);
@ -129,10 +130,73 @@ void tty_unthrottle(struct tty_struct *tty)
if (test_and_clear_bit(TTY_THROTTLED, &tty->flags) && if (test_and_clear_bit(TTY_THROTTLED, &tty->flags) &&
tty->ops->unthrottle) tty->ops->unthrottle)
tty->ops->unthrottle(tty); tty->ops->unthrottle(tty);
tty->flow_change = 0;
mutex_unlock(&tty->termios_mutex); mutex_unlock(&tty->termios_mutex);
} }
EXPORT_SYMBOL(tty_unthrottle); 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_wait_until_sent - wait for I/O to finish
* @tty: tty we are waiting for * @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); 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 * tty_termios_copy_hw - copy hardware settings
* @new: New termios * @new: New termios
@ -1086,14 +1122,12 @@ int tty_mode_ioctl(struct tty_struct *tty, struct file *file,
} }
EXPORT_SYMBOL_GPL(tty_mode_ioctl); 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) { switch (arg) {
case TCIFLUSH: case TCIFLUSH:
if (ld && ld->ops->flush_buffer) { 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); tty_driver_flush_buffer(tty);
break; break;
default: default:
tty_ldisc_deref(ld);
return -EINVAL; return -EINVAL;
} }
tty_ldisc_deref(ld);
return 0; 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); EXPORT_SYMBOL_GPL(tty_perform_flush);
int n_tty_ioctl_helper(struct tty_struct *tty, struct file *file, 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; return 0;
case TCFLSH: case TCFLSH:
return tty_perform_flush(tty, arg); return __tty_perform_flush(tty, arg);
default: default:
/* Try the mode commands */ /* Try the mode commands */
return tty_mode_ioctl(tty, file, cmd, arg); return tty_mode_ioctl(tty, file, cmd, arg);

View file

@ -20,6 +20,17 @@
#include <linux/uaccess.h> #include <linux/uaccess.h>
#include <linux/ratelimit.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 * This guards the refcounted line discipline lists. The lock
* must be taken with irqs off because there are hangup path * 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 */ /* Line disc dispatch table */
static struct tty_ldisc_ops *tty_ldiscs[NR_LDISCS]; 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 * tty_register_ldisc - install a line discipline
* @disc: ldisc number * @disc: ldisc number
@ -206,6 +179,29 @@ static struct tty_ldisc *tty_ldisc_get(int disc)
return ld; 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) static void *tty_ldiscs_seq_start(struct seq_file *m, loff_t *pos)
{ {
return (*pos < NR_LDISCS) ? pos : NULL; return (*pos < NR_LDISCS) ? pos : NULL;
@ -254,24 +250,6 @@ const struct file_operations tty_ldiscs_proc_fops = {
.release = seq_release, .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_ldisc_try - internal helper
* @tty: the tty * @tty: the tty
@ -289,10 +267,13 @@ static struct tty_ldisc *tty_ldisc_try(struct tty_struct *tty)
unsigned long flags; unsigned long flags;
struct tty_ldisc *ld; struct tty_ldisc *ld;
/* FIXME: this allows reference acquire after TTY_LDISC is cleared */
raw_spin_lock_irqsave(&tty_ldisc_lock, flags); raw_spin_lock_irqsave(&tty_ldisc_lock, flags);
ld = NULL; ld = NULL;
if (test_bit(TTY_LDISC, &tty->flags)) if (test_bit(TTY_LDISC, &tty->flags) && tty->ldisc) {
ld = get_ldisc(tty->ldisc); ld = tty->ldisc;
atomic_inc(&ld->users);
}
raw_spin_unlock_irqrestore(&tty_ldisc_lock, flags); raw_spin_unlock_irqrestore(&tty_ldisc_lock, flags);
return ld; return ld;
} }
@ -352,15 +333,24 @@ EXPORT_SYMBOL_GPL(tty_ldisc_ref);
void tty_ldisc_deref(struct tty_ldisc *ld) 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); 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_ldisc_enable - allow ldisc use
* @tty: terminal to activate ldisc on * @tty: terminal to activate ldisc on
@ -373,8 +363,9 @@ static inline void tty_ldisc_put(struct tty_ldisc *ld)
* Clearing directly is allowed. * 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); set_bit(TTY_LDISC, &tty->flags);
clear_bit(TTY_LDISC_CHANGING, &tty->flags); clear_bit(TTY_LDISC_CHANGING, &tty->flags);
wake_up(&tty_ldisc_wait); 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 */ /* There is an outstanding reference here so this is safe */
old = tty_ldisc_get(old->ops->num); old = tty_ldisc_get(old->ops->num);
WARN_ON(IS_ERR(old)); WARN_ON(IS_ERR(old));
tty_ldisc_assign(tty, old); tty->ldisc = old;
tty_set_termios_ldisc(tty, old->ops->num); tty_set_termios_ldisc(tty, old->ops->num);
if (tty_ldisc_open(tty, old) < 0) { if (tty_ldisc_open(tty, old) < 0) {
tty_ldisc_put(old); 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); new_ldisc = tty_ldisc_get(N_TTY);
if (IS_ERR(new_ldisc)) if (IS_ERR(new_ldisc))
panic("n_tty: get"); panic("n_tty: get");
tty_ldisc_assign(tty, new_ldisc); tty->ldisc = new_ldisc;
tty_set_termios_ldisc(tty, N_TTY); tty_set_termios_ldisc(tty, N_TTY);
r = tty_ldisc_open(tty, new_ldisc); r = tty_ldisc_open(tty, new_ldisc);
if (r < 0) 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_ldisc_wait_idle - wait for the ldisc to become idle
* @tty: tty to wait for * @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; 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_set_ldisc - set line discipline
* @tty: the terminal to set * @tty: the terminal to set
@ -563,7 +600,6 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
{ {
int retval; int retval;
struct tty_ldisc *o_ldisc, *new_ldisc; struct tty_ldisc *o_ldisc, *new_ldisc;
int work, o_work = 0;
struct tty_struct *o_tty; struct tty_struct *o_tty;
new_ldisc = tty_ldisc_get(ldisc); new_ldisc = tty_ldisc_get(ldisc);
@ -589,15 +625,6 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
return 0; 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); 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. * parallel to the change and re-referencing the tty.
*/ */
work = tty_ldisc_halt(tty); retval = tty_ldisc_halt(tty, o_tty, 5 * HZ);
if (o_tty)
o_work = tty_ldisc_halt(o_tty);
/* /*
* 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. * We must drop the mutex here in case a hangup is also in process.
*/ */
mutex_unlock(&tty->ldisc_mutex); mutex_unlock(&tty->ldisc_mutex);
tty_ldisc_flush_works(tty); flush_work(&tty->hangup_work);
retval = tty_ldisc_wait_idle(tty, 5 * HZ);
tty_lock(tty); tty_lock(tty);
mutex_lock(&tty->ldisc_mutex); 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); tty_ldisc_close(tty, o_ldisc);
/* Now set up the new line discipline. */ /* Now set up the new line discipline. */
tty_ldisc_assign(tty, new_ldisc); tty->ldisc = new_ldisc;
tty_set_termios_ldisc(tty, ldisc); tty_set_termios_ldisc(tty, ldisc);
retval = tty_ldisc_open(tty, new_ldisc); retval = tty_ldisc_open(tty, new_ldisc);
@ -705,10 +728,10 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
/* Restart the work queue in case no characters kick it off. Safe if /* Restart the work queue in case no characters kick it off. Safe if
already running */ already running */
if (work) schedule_work(&tty->port->buf.work);
schedule_work(&tty->port->buf.work); if (o_tty)
if (o_work)
schedule_work(&o_tty->port->buf.work); schedule_work(&o_tty->port->buf.work);
mutex_unlock(&tty->ldisc_mutex); mutex_unlock(&tty->ldisc_mutex);
tty_unlock(tty); tty_unlock(tty);
return retval; 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_close(tty, tty->ldisc);
tty_ldisc_put(tty->ldisc); tty_ldisc_put(tty->ldisc);
tty->ldisc = NULL;
/* /*
* Switch the line discipline back * Switch the line discipline back
*/ */
tty_ldisc_assign(tty, ld); tty->ldisc = ld;
tty_set_termios_ldisc(tty, ldisc); tty_set_termios_ldisc(tty, ldisc);
return 0; return 0;
@ -780,6 +802,8 @@ void tty_ldisc_hangup(struct tty_struct *tty)
int reset = tty->driver->flags & TTY_DRIVER_RESET_TERMIOS; int reset = tty->driver->flags & TTY_DRIVER_RESET_TERMIOS;
int err = 0; int err = 0;
tty_ldisc_debug(tty, "closing ldisc: %p\n", tty->ldisc);
/* /*
* FIXME! What are the locking issues here? This may me overdoing * FIXME! What are the locking issues here? This may me overdoing
* things... This question is especially important now that we've * 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); mutex_lock(&tty->ldisc_mutex);
/* if (tty_ldisc_hangup_halt(tty)) {
* 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;
}
/* 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 (reset == 0) {
if (!tty_ldisc_reinit(tty, tty->termios.c_line)) if (!tty_ldisc_reinit(tty, tty->termios.c_line))
@ -864,6 +860,8 @@ void tty_ldisc_hangup(struct tty_struct *tty)
mutex_unlock(&tty->ldisc_mutex); mutex_unlock(&tty->ldisc_mutex);
if (reset) if (reset)
tty_reset_termios(tty); 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) 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); mutex_lock(&tty->ldisc_mutex);
/* /*
* Now kill off the ldisc * 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) void tty_ldisc_release(struct tty_struct *tty, struct tty_struct *o_tty)
{ {
/* /*
* Prevent flush_to_ldisc() from rescheduling the work for later. Then * Shutdown this line discipline. As this is the final close,
* kill any delayed work. As this is the final close it does not * it does not race with the set_ldisc code path.
* race with the set_ldisc code path.
*/ */
tty_ldisc_halt(tty); tty_ldisc_debug(tty, "closing ldisc: %p\n", tty->ldisc);
if (o_tty)
tty_ldisc_halt(o_tty);
tty_ldisc_flush_works(tty); tty_ldisc_halt(tty, o_tty, MAX_SCHEDULE_TIMEOUT);
if (o_tty)
tty_ldisc_flush_works(o_tty);
tty_lock_pair(tty, o_tty); tty_lock_pair(tty, o_tty);
/* This will need doing differently if we need to lock */ /* 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); tty_unlock_pair(tty, o_tty);
/* And the memory resources remaining (buffers, termios) will be /* And the memory resources remaining (buffers, termios) will be
disposed of when the kref hits zero */ 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); struct tty_ldisc *ld = tty_ldisc_get(N_TTY);
if (IS_ERR(ld)) if (IS_ERR(ld))
panic("n_tty: init_tty"); 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) void tty_ldisc_deinit(struct tty_struct *tty)
{ {
put_ldisc(tty->ldisc); tty_ldisc_put(tty->ldisc);
tty_ldisc_assign(tty, NULL); tty->ldisc = NULL;
} }
void tty_ldisc_begin(void) void tty_ldisc_begin(void)

View file

@ -132,6 +132,7 @@ EXPORT_SYMBOL(tty_port_free_xmit_buf);
*/ */
void tty_port_destroy(struct tty_port *port) void tty_port_destroy(struct tty_port *port)
{ {
cancel_work_sync(&port->buf.work);
tty_buffer_free_all(port); tty_buffer_free_all(port);
} }
EXPORT_SYMBOL(tty_port_destroy); 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); 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); mutex_lock(&port->mutex);
if (port->ops->shutdown && !port->console && if (port->console)
test_and_clear_bit(ASYNCB_INITIALIZED, &port->flags)) 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); port->ops->shutdown(port);
}
out:
mutex_unlock(&port->mutex); 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) void tty_port_hangup(struct tty_port *port)
{ {
struct tty_struct *tty;
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&port->lock, flags); spin_lock_irqsave(&port->lock, flags);
port->count = 0; port->count = 0;
port->flags &= ~ASYNC_NORMAL_ACTIVE; port->flags &= ~ASYNC_NORMAL_ACTIVE;
if (port->tty) { tty = port->tty;
set_bit(TTY_IO_ERROR, &port->tty->flags); if (tty)
tty_kref_put(port->tty); set_bit(TTY_IO_ERROR, &tty->flags);
}
port->tty = NULL; port->tty = NULL;
spin_unlock_irqrestore(&port->lock, flags); 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->open_wait);
wake_up_interruptible(&port->delta_msr_wait); wake_up_interruptible(&port->delta_msr_wait);
tty_port_shutdown(port);
} }
EXPORT_SYMBOL(tty_port_hangup); 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 * tty_port_carrier_raised - carrier raised check
* @port: tty port * @port: tty port
@ -350,7 +397,7 @@ int tty_port_block_til_ready(struct tty_port *port,
while (1) { while (1) {
/* Indicate we are open */ /* 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); tty_port_raise_dtr_rts(port);
prepare_to_wait(&port->open_wait, &wait, TASK_INTERRUPTIBLE); 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); 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, int tty_port_close_start(struct tty_port *port,
struct tty_struct *tty, struct file *filp) 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); set_bit(ASYNCB_CLOSING, &port->flags);
tty->closing = 1; tty->closing = 1;
spin_unlock_irqrestore(&port->lock, flags); 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) if (test_bit(ASYNCB_INITIALIZED, &port->flags)) {
timeout = max_t(long, /* Don't block on a stalled port, just pull the chain */
(HZ * 10 * port->drain_delay) / bps, HZ / 10); if (tty->flow_stopped)
else tty_driver_flush_buffer(tty);
timeout = 2 * HZ; if (port->closing_wait != ASYNC_CLOSING_WAIT_NONE)
schedule_timeout_interruptible(timeout); tty_wait_until_sent_from_close(tty, port->closing_wait);
if (port->drain_delay)
tty_port_drain_delay(port, tty);
} }
/* Flush the ldisc buffering */ /* Flush the ldisc buffering */
tty_ldisc_flush(tty); 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 /* Don't call port->drop for the last reference. Callers will want
to drop the last active reference in ->shutdown() or the tty to drop the last active reference in ->shutdown() or the tty
shutdown path */ 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) if (tty_port_close_start(port, tty, filp) == 0)
return; return;
tty_port_shutdown(port); tty_port_shutdown(port, tty);
set_bit(TTY_IO_ERROR, &tty->flags); set_bit(TTY_IO_ERROR, &tty->flags);
tty_port_close_end(port, tty); tty_port_close_end(port, tty);
tty_port_tty_set(port, NULL); tty_port_tty_set(port, NULL);

View file

@ -194,8 +194,7 @@ static void set_inverse_transl(struct vc_data *conp, struct uni_pagedir *p, int
q = p->inverse_translations[i]; q = p->inverse_translations[i];
if (!q) { if (!q) {
q = p->inverse_translations[i] = (unsigned char *) q = p->inverse_translations[i] = kmalloc(MAX_GLYPH, GFP_KERNEL);
kmalloc(MAX_GLYPH, GFP_KERNEL);
if (!q) return; if (!q) return;
} }
memset(q, 0, MAX_GLYPH); memset(q, 0, MAX_GLYPH);

View file

@ -292,7 +292,6 @@ static void acm_ctrl_irq(struct urb *urb)
{ {
struct acm *acm = urb->context; struct acm *acm = urb->context;
struct usb_cdc_notification *dr = urb->transfer_buffer; struct usb_cdc_notification *dr = urb->transfer_buffer;
struct tty_struct *tty;
unsigned char *data; unsigned char *data;
int newctrl; int newctrl;
int retval; int retval;
@ -327,17 +326,12 @@ static void acm_ctrl_irq(struct urb *urb)
break; break;
case USB_CDC_NOTIFY_SERIAL_STATE: case USB_CDC_NOTIFY_SERIAL_STATE:
tty = tty_port_tty_get(&acm->port);
newctrl = get_unaligned_le16(data); newctrl = get_unaligned_le16(data);
if (tty) { if (!acm->clocal && (acm->ctrlin & ~newctrl & ACM_CTRL_DCD)) {
if (!acm->clocal && dev_dbg(&acm->control->dev, "%s - calling hangup\n",
(acm->ctrlin & ~newctrl & ACM_CTRL_DCD)) { __func__);
dev_dbg(&acm->control->dev, tty_port_tty_hangup(&acm->port, false);
"%s - calling hangup\n", __func__);
tty_hangup(tty);
}
tty_kref_put(tty);
} }
acm->ctrlin = newctrl; acm->ctrlin = newctrl;
@ -475,15 +469,10 @@ static void acm_write_bulk(struct urb *urb)
static void acm_softint(struct work_struct *work) static void acm_softint(struct work_struct *work)
{ {
struct acm *acm = container_of(work, struct acm, work); struct acm *acm = container_of(work, struct acm, work);
struct tty_struct *tty;
dev_vdbg(&acm->data->dev, "%s\n", __func__); dev_vdbg(&acm->data->dev, "%s\n", __func__);
tty = tty_port_tty_get(&acm->port); tty_port_tty_wakeup(&acm->port);
if (!tty)
return;
tty_wakeup(tty);
tty_kref_put(tty);
} }
/* /*
@ -1519,15 +1508,9 @@ static int acm_resume(struct usb_interface *intf)
static int acm_reset_resume(struct usb_interface *intf) static int acm_reset_resume(struct usb_interface *intf)
{ {
struct acm *acm = usb_get_intfdata(intf); struct acm *acm = usb_get_intfdata(intf);
struct tty_struct *tty;
if (test_bit(ASYNCB_INITIALIZED, &acm->port.flags)) { if (test_bit(ASYNCB_INITIALIZED, &acm->port.flags))
tty = tty_port_tty_get(&acm->port); tty_port_tty_hangup(&acm->port, false);
if (tty) {
tty_hangup(tty);
tty_kref_put(tty);
}
}
return acm_resume(intf); return acm_resume(intf);
} }

View file

@ -210,7 +210,6 @@ struct digi_port {
/* Local Function Declarations */ /* Local Function Declarations */
static void digi_wakeup_write(struct usb_serial_port *port);
static void digi_wakeup_write_lock(struct work_struct *work); static void digi_wakeup_write_lock(struct work_struct *work);
static int digi_write_oob_command(struct usb_serial_port *port, static int digi_write_oob_command(struct usb_serial_port *port,
unsigned char *buf, int count, int interruptible); unsigned char *buf, int count, int interruptible);
@ -374,20 +373,10 @@ static void digi_wakeup_write_lock(struct work_struct *work)
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&priv->dp_port_lock, 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); 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 * Digi Write OOB Command
* *
@ -1044,7 +1033,7 @@ static void digi_write_bulk_callback(struct urb *urb)
} }
} }
/* wake up processes sleeping on writes immediately */ /* 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 */ /* also queue up a wakeup at scheduler time, in case we */
/* lost the race in write_chan(). */ /* lost the race in write_chan(). */
schedule_work(&priv->dp_wakeup_work); 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 */ /* port must be open to use tty struct */
if (rts) { if (rts) {
tty->hw_stopped = 0; tty->hw_stopped = 0;
digi_wakeup_write(port); tty_port_tty_wakeup(&port->port);
} }
} else { } else {
priv->dp_modem_signals &= ~TIOCM_CTS; priv->dp_modem_signals &= ~TIOCM_CTS;

View file

@ -564,7 +564,6 @@ static void edge_interrupt_callback(struct urb *urb)
struct device *dev; struct device *dev;
struct edgeport_port *edge_port; struct edgeport_port *edge_port;
struct usb_serial_port *port; struct usb_serial_port *port;
struct tty_struct *tty;
unsigned char *data = urb->transfer_buffer; unsigned char *data = urb->transfer_buffer;
int length = urb->actual_length; int length = urb->actual_length;
int bytes_avail; int bytes_avail;
@ -643,12 +642,7 @@ static void edge_interrupt_callback(struct urb *urb)
/* tell the tty driver that something /* tell the tty driver that something
has changed */ has changed */
tty = tty_port_tty_get( tty_port_tty_wakeup(&edge_port->port->port);
&edge_port->port->port);
if (tty) {
tty_wakeup(tty);
tty_kref_put(tty);
}
/* Since we have more credit, check /* Since we have more credit, check
if more data can be sent */ if more data can be sent */
send_more_port_data(edge_serial, 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) static void edge_bulk_out_data_callback(struct urb *urb)
{ {
struct edgeport_port *edge_port = urb->context; struct edgeport_port *edge_port = urb->context;
struct tty_struct *tty;
int status = urb->status; int status = urb->status;
if (status) { if (status) {
@ -746,14 +739,8 @@ static void edge_bulk_out_data_callback(struct urb *urb)
__func__, status); __func__, status);
} }
tty = tty_port_tty_get(&edge_port->port->port); if (edge_port->open)
tty_port_tty_wakeup(&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);
/* Release the Write URB */ /* Release the Write URB */
edge_port->write_in_progress = false; 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) static void edge_bulk_out_cmd_callback(struct urb *urb)
{ {
struct edgeport_port *edge_port = urb->context; struct edgeport_port *edge_port = urb->context;
struct tty_struct *tty;
int status = urb->status; int status = urb->status;
atomic_dec(&CmdUrbs); atomic_dec(&CmdUrbs);
@ -793,13 +779,9 @@ static void edge_bulk_out_cmd_callback(struct urb *urb)
return; return;
} }
/* Get pointer to tty */
tty = tty_port_tty_get(&edge_port->port->port);
/* tell the tty driver that something has changed */ /* tell the tty driver that something has changed */
if (tty && edge_port->open) if (edge_port->open)
tty_wakeup(tty); tty_port_tty_wakeup(&edge_port->port->port);
tty_kref_put(tty);
/* we have completed the command */ /* we have completed the command */
edge_port->commandPending = false; edge_port->commandPending = false;

View file

@ -378,7 +378,6 @@ static void usa26_instat_callback(struct urb *urb)
struct usb_serial *serial; struct usb_serial *serial;
struct usb_serial_port *port; struct usb_serial_port *port;
struct keyspan_port_private *p_priv; struct keyspan_port_private *p_priv;
struct tty_struct *tty;
int old_dcd_state, err; int old_dcd_state, err;
int status = urb->status; 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->dcd_state = ((msg->gpia_dcd) ? 1 : 0);
p_priv->ri_state = ((msg->ri) ? 1 : 0); p_priv->ri_state = ((msg->ri) ? 1 : 0);
if (old_dcd_state != p_priv->dcd_state) { if (old_dcd_state != p_priv->dcd_state)
tty = tty_port_tty_get(&port->port); tty_port_tty_hangup(&port->port, true);
if (tty && !C_CLOCAL(tty))
tty_hangup(tty);
tty_kref_put(tty);
}
/* Resubmit urb so we continue receiving */ /* Resubmit urb so we continue receiving */
err = usb_submit_urb(urb, GFP_ATOMIC); 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 *serial;
struct usb_serial_port *port; struct usb_serial_port *port;
struct keyspan_port_private *p_priv; struct keyspan_port_private *p_priv;
struct tty_struct *tty;
int old_dcd_state; int old_dcd_state;
int status = urb->status; 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->dcd_state = ((msg->dcd) ? 1 : 0);
p_priv->ri_state = ((msg->ri) ? 1 : 0); p_priv->ri_state = ((msg->ri) ? 1 : 0);
if (old_dcd_state != p_priv->dcd_state && old_dcd_state) { if (old_dcd_state != p_priv->dcd_state && old_dcd_state)
tty = tty_port_tty_get(&port->port); tty_port_tty_hangup(&port->port, true);
if (tty && !C_CLOCAL(tty))
tty_hangup(tty);
tty_kref_put(tty);
}
/* Resubmit urb so we continue receiving */ /* Resubmit urb so we continue receiving */
err = usb_submit_urb(urb, GFP_ATOMIC); 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->dcd_state = ((msg->dcd) ? 1 : 0);
p_priv->ri_state = ((msg->ri) ? 1 : 0); p_priv->ri_state = ((msg->ri) ? 1 : 0);
if (old_dcd_state != p_priv->dcd_state && old_dcd_state) { if (old_dcd_state != p_priv->dcd_state && old_dcd_state)
struct tty_struct *tty = tty_port_tty_get(&port->port); tty_port_tty_hangup(&port->port, true);
if (tty && !C_CLOCAL(tty))
tty_hangup(tty);
tty_kref_put(tty);
}
/* Resubmit urb so we continue receiving */ /* Resubmit urb so we continue receiving */
err = usb_submit_urb(urb, GFP_ATOMIC); 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 *serial;
struct usb_serial_port *port; struct usb_serial_port *port;
struct keyspan_port_private *p_priv; struct keyspan_port_private *p_priv;
struct tty_struct *tty;
int old_dcd_state, err; int old_dcd_state, err;
int status = urb->status; 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->dcd_state = ((msg->dcd) ? 1 : 0);
p_priv->ri_state = ((msg->ri) ? 1 : 0); p_priv->ri_state = ((msg->ri) ? 1 : 0);
if (old_dcd_state != p_priv->dcd_state && old_dcd_state) { if (old_dcd_state != p_priv->dcd_state && old_dcd_state)
tty = tty_port_tty_get(&port->port); tty_port_tty_hangup(&port->port, true);
if (tty && !C_CLOCAL(tty))
tty_hangup(tty);
tty_kref_put(tty);
}
/* Resubmit urb so we continue receiving */ /* Resubmit urb so we continue receiving */
err = usb_submit_urb(urb, GFP_ATOMIC); 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->cts_state = ((msg->hskia_cts) ? 1 : 0);
p_priv->dcd_state = ((msg->gpia_dcd) ? 1 : 0); p_priv->dcd_state = ((msg->gpia_dcd) ? 1 : 0);
if (old_dcd_state != p_priv->dcd_state && old_dcd_state) { if (old_dcd_state != p_priv->dcd_state && old_dcd_state)
struct tty_struct *tty = tty_port_tty_get(&port->port); tty_port_tty_hangup(&port->port, true);
if (tty && !C_CLOCAL(tty))
tty_hangup(tty);
tty_kref_put(tty);
}
/* Resubmit urb so we continue receiving */ /* Resubmit urb so we continue receiving */
err = usb_submit_urb(urb, GFP_ATOMIC); err = usb_submit_urb(urb, GFP_ATOMIC);

View file

@ -104,10 +104,8 @@ static void keyspan_pda_wakeup_write(struct work_struct *work)
struct keyspan_pda_private *priv = struct keyspan_pda_private *priv =
container_of(work, struct keyspan_pda_private, wakeup_work); container_of(work, struct keyspan_pda_private, wakeup_work);
struct usb_serial_port *port = priv->port; struct usb_serial_port *port = priv->port;
struct tty_struct *tty = tty_port_tty_get(&port->port);
if (tty) tty_port_tty_wakeup(&port->port);
tty_wakeup(tty);
tty_kref_put(tty);
} }
static void keyspan_pda_request_unthrottle(struct work_struct *work) static void keyspan_pda_request_unthrottle(struct work_struct *work)

View file

@ -932,7 +932,6 @@ static void mos7720_bulk_in_callback(struct urb *urb)
static void mos7720_bulk_out_data_callback(struct urb *urb) static void mos7720_bulk_out_data_callback(struct urb *urb)
{ {
struct moschip_port *mos7720_port; struct moschip_port *mos7720_port;
struct tty_struct *tty;
int status = urb->status; int status = urb->status;
if (status) { if (status) {
@ -946,11 +945,8 @@ static void mos7720_bulk_out_data_callback(struct urb *urb)
return ; return ;
} }
tty = tty_port_tty_get(&mos7720_port->port->port); if (mos7720_port->open)
tty_port_tty_wakeup(&mos7720_port->port->port);
if (tty && mos7720_port->open)
tty_wakeup(tty);
tty_kref_put(tty);
} }
/* /*

View file

@ -816,7 +816,6 @@ static void mos7840_bulk_out_data_callback(struct urb *urb)
{ {
struct moschip_port *mos7840_port; struct moschip_port *mos7840_port;
struct usb_serial_port *port; struct usb_serial_port *port;
struct tty_struct *tty;
int status = urb->status; int status = urb->status;
int i; int i;
@ -839,10 +838,8 @@ static void mos7840_bulk_out_data_callback(struct urb *urb)
if (mos7840_port_paranoia_check(port, __func__)) if (mos7840_port_paranoia_check(port, __func__))
return; return;
tty = tty_port_tty_get(&port->port); if (mos7840_port->open)
if (tty && mos7840_port->open) tty_port_tty_wakeup(&port->port);
tty_wakeup(tty);
tty_kref_put(tty);
} }

View file

@ -1537,13 +1537,8 @@ static void option_instat_callback(struct urb *urb)
portdata->dsr_state = ((signals & 0x02) ? 1 : 0); portdata->dsr_state = ((signals & 0x02) ? 1 : 0);
portdata->ri_state = ((signals & 0x08) ? 1 : 0); portdata->ri_state = ((signals & 0x08) ? 1 : 0);
if (old_dcd_state && !portdata->dcd_state) { if (old_dcd_state && !portdata->dcd_state)
struct tty_struct *tty = tty_port_tty_hangup(&port->port, true);
tty_port_tty_get(&port->port);
if (tty && !C_CLOCAL(tty))
tty_hangup(tty);
tty_kref_put(tty);
}
} else { } else {
dev_dbg(dev, "%s: type %x req %x\n", __func__, dev_dbg(dev, "%s: type %x req %x\n", __func__,
req_pkt->bRequestType, req_pkt->bRequest); req_pkt->bRequestType, req_pkt->bRequest);

View file

@ -116,7 +116,6 @@ struct qt2_serial_private {
}; };
struct qt2_port_private { struct qt2_port_private {
bool is_open;
u8 device_port; u8 device_port;
spinlock_t urb_lock; spinlock_t urb_lock;
@ -397,7 +396,6 @@ static int qt2_open(struct tty_struct *tty, struct usb_serial_port *port)
return status; return status;
} }
port_priv->is_open = true;
port_priv->device_port = (u8) device_port; port_priv->device_port = (u8) device_port;
if (tty) if (tty)
@ -417,8 +415,6 @@ static void qt2_close(struct usb_serial_port *port)
serial = port->serial; serial = port->serial;
port_priv = usb_get_serial_port_data(port); port_priv = usb_get_serial_port_data(port);
port_priv->is_open = false;
spin_lock_irqsave(&port_priv->urb_lock, flags); spin_lock_irqsave(&port_priv->urb_lock, flags);
usb_kill_urb(port_priv->write_urb); usb_kill_urb(port_priv->write_urb);
port_priv->urb_in_use = false; port_priv->urb_in_use = false;
@ -664,9 +660,7 @@ void qt2_process_read_urb(struct urb *urb)
__func__); __func__);
break; break;
} }
tty_flip_buffer_push(&port->port);
if (port_priv->is_open)
tty_flip_buffer_push(&port->port);
newport = *(ch + 3); newport = *(ch + 3);
@ -709,8 +703,7 @@ void qt2_process_read_urb(struct urb *urb)
tty_insert_flip_string(&port->port, ch, 1); 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) 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); 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; val = (break_state == -1) ? 1 : 0;
status = qt2_control_msg(port->serial->dev, QT2_BREAK_CONTROL, status = qt2_control_msg(port->serial->dev, QT2_BREAK_CONTROL,

View file

@ -628,7 +628,6 @@ static void sierra_instat_callback(struct urb *urb)
unsigned char signals = *((unsigned char *) unsigned char signals = *((unsigned char *)
urb->transfer_buffer + urb->transfer_buffer +
sizeof(struct usb_ctrlrequest)); sizeof(struct usb_ctrlrequest));
struct tty_struct *tty;
dev_dbg(&port->dev, "%s: signal x%x\n", __func__, dev_dbg(&port->dev, "%s: signal x%x\n", __func__,
signals); signals);
@ -639,11 +638,8 @@ static void sierra_instat_callback(struct urb *urb)
portdata->dsr_state = ((signals & 0x02) ? 1 : 0); portdata->dsr_state = ((signals & 0x02) ? 1 : 0);
portdata->ri_state = ((signals & 0x08) ? 1 : 0); portdata->ri_state = ((signals & 0x08) ? 1 : 0);
tty = tty_port_tty_get(&port->port); if (old_dcd_state && !portdata->dcd_state)
if (tty && !C_CLOCAL(tty) && tty_port_tty_hangup(&port->port, true);
old_dcd_state && !portdata->dcd_state)
tty_hangup(tty);
tty_kref_put(tty);
} else { } else {
dev_dbg(&port->dev, "%s: type %x req %x\n", dev_dbg(&port->dev, "%s: type %x req %x\n",
__func__, req_pkt->bRequestType, __func__, req_pkt->bRequestType,

View file

@ -1229,7 +1229,6 @@ static void ti_send(struct ti_port *tport)
{ {
int count, result; int count, result;
struct usb_serial_port *port = tport->tp_port; struct usb_serial_port *port = tport->tp_port;
struct tty_struct *tty = tty_port_tty_get(&port->port); /* FIXME */
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&tport->tp_lock, 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 */ /* more room in the buffer for new writes, wakeup */
if (tty) tty_port_tty_wakeup(&port->port);
tty_wakeup(tty);
tty_kref_put(tty);
wake_up_interruptible(&tport->tp_write_wait); wake_up_interruptible(&tport->tp_write_wait);
return; return;
unlock: unlock:
spin_unlock_irqrestore(&tport->tp_lock, flags); spin_unlock_irqrestore(&tport->tp_lock, flags);
tty_kref_put(tty);
return; return;
} }

View file

@ -542,16 +542,8 @@ static void usb_serial_port_work(struct work_struct *work)
{ {
struct usb_serial_port *port = struct usb_serial_port *port =
container_of(work, struct usb_serial_port, work); container_of(work, struct usb_serial_port, work);
struct tty_struct *tty;
tty = tty_port_tty_get(&port->port); tty_port_tty_wakeup(&port->port);
if (!tty)
return;
dev_dbg(tty->dev, "%s - port %d\n", __func__, port->number);
tty_wakeup(tty);
tty_kref_put(tty);
} }
static void kill_traffic(struct usb_serial_port *port) static void kill_traffic(struct usb_serial_port *port)

View file

@ -203,6 +203,9 @@ struct amba_pl011_data {
bool (*dma_filter)(struct dma_chan *chan, void *filter_param); bool (*dma_filter)(struct dma_chan *chan, void *filter_param);
void *dma_rx_param; void *dma_rx_param;
void *dma_tx_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 (*init) (void);
void (*exit) (void); void (*exit) (void);
}; };

View file

@ -86,10 +86,6 @@ struct sccnxp_pdata {
const u32 mctrl_cfg[SCCNXP_MAX_UARTS]; const u32 mctrl_cfg[SCCNXP_MAX_UARTS];
/* Timer value for polling mode (usecs) */ /* Timer value for polling mode (usecs) */
const unsigned int poll_time_us; const unsigned int poll_time_us;
/* Called during startup */
void (*init)(void);
/* Called before finish */
void (*exit)(void);
}; };
#endif #endif

260
include/linux/serial_s3c.h Normal file
View 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 */

View file

@ -255,9 +255,9 @@ struct tty_struct {
int count; int count;
struct winsize winsize; /* termios mutex */ struct winsize winsize; /* termios mutex */
unsigned char stopped:1, hw_stopped:1, flow_stopped:1, packet:1; unsigned char stopped:1, hw_stopped:1, flow_stopped:1, packet:1;
unsigned char warned:1;
unsigned char ctrl_status; /* ctrl_lock */ unsigned char ctrl_status; /* ctrl_lock */
unsigned int receive_room; /* Bytes free for queue */ unsigned int receive_room; /* Bytes free for queue */
int flow_change;
struct tty_struct *link; struct tty_struct *link;
struct fasync_struct *fasync; 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_NO_WRITE_SPLIT 17 /* Preserve write boundaries to driver */
#define TTY_HUPPED 18 /* Post driver->hangup() */ #define TTY_HUPPED 18 /* Post driver->hangup() */
#define TTY_HUPPING 21 /* ->hangup() in progress */ #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)) #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 #ifdef CONFIG_TTY
extern void console_init(void); extern void console_init(void);
extern void tty_kref_put(struct tty_struct *tty); 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_driver_flush_buffer(struct tty_struct *tty);
extern void tty_throttle(struct tty_struct *tty); extern void tty_throttle(struct tty_struct *tty);
extern void tty_unthrottle(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 int tty_do_resize(struct tty_struct *tty, struct winsize *ws);
extern void tty_driver_remove_tty(struct tty_driver *driver, extern void tty_driver_remove_tty(struct tty_driver *driver,
struct tty_struct *tty); 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_free_all(struct tty_port *port);
extern void tty_buffer_flush(struct tty_struct *tty); extern void tty_buffer_flush(struct tty_struct *tty);
extern void tty_buffer_init(struct tty_port *port); 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_baud_rate(struct ktermios *termios);
extern speed_t tty_termios_input_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, extern void tty_termios_encode_baud_rate(struct ktermios *termios,
speed_t ibaud, speed_t obaud); speed_t ibaud, speed_t obaud);
extern void tty_encode_baud_rate(struct tty_struct *tty, extern void tty_encode_baud_rate(struct tty_struct *tty,
speed_t ibaud, speed_t obaud); 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 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_termios_hw_change(struct ktermios *a, struct ktermios *b);
extern int tty_set_termios(struct tty_struct *tty, struct ktermios *kt); 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_raise_dtr_rts(struct tty_port *port);
extern void tty_port_lower_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_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, extern int tty_port_block_til_ready(struct tty_port *port,
struct tty_struct *tty, struct file *filp); struct tty_struct *tty, struct file *filp);
extern int tty_port_close_start(struct tty_port *port, 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_init(struct tty_struct *tty);
extern void tty_ldisc_deinit(struct tty_struct *tty); extern void tty_ldisc_deinit(struct tty_struct *tty);
extern void tty_ldisc_begin(void); 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 */ /* n_tty.c */

View file

@ -9,89 +9,89 @@
* *
* int (*open)(struct tty_struct *); * int (*open)(struct tty_struct *);
* *
* This function is called when the line discipline is associated * This function is called when the line discipline is associated
* with the tty. The line discipline can use this as an * with the tty. The line discipline can use this as an
* opportunity to initialize any state needed by the ldisc routines. * opportunity to initialize any state needed by the ldisc routines.
* *
* void (*close)(struct tty_struct *); * void (*close)(struct tty_struct *);
* *
* This function is called when the line discipline is being * This function is called when the line discipline is being
* shutdown, either because the tty is being closed or because * shutdown, either because the tty is being closed or because
* the tty is being changed to use a new line discipline * the tty is being changed to use a new line discipline
* *
* void (*flush_buffer)(struct tty_struct *tty); * void (*flush_buffer)(struct tty_struct *tty);
* *
* This function instructs the line discipline to clear its * This function instructs the line discipline to clear its
* buffers of any input characters it may have queued to be * buffers of any input characters it may have queued to be
* delivered to the user mode process. * delivered to the user mode process.
* *
* ssize_t (*chars_in_buffer)(struct tty_struct *tty); * 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 * discipline may have queued up to be delivered to the user mode
* process. * process.
* *
* ssize_t (*read)(struct tty_struct * tty, struct file * file, * ssize_t (*read)(struct tty_struct * tty, struct file * file,
* unsigned char * buf, size_t nr); * unsigned char * buf, size_t nr);
* *
* This function is called when the user requests to read from * This function is called when the user requests to read from
* the tty. The line discipline will return whatever characters * the tty. The line discipline will return whatever characters
* it has buffered up for the user. If this function is not * it has buffered up for the user. If this function is not
* defined, the user will receive an EIO error. * defined, the user will receive an EIO error.
* *
* ssize_t (*write)(struct tty_struct * tty, struct file * file, * ssize_t (*write)(struct tty_struct * tty, struct file * file,
* const unsigned char * buf, size_t nr); * 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, * 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 * This function is called when the user requests an ioctl which
* is not handled by the tty layer or the low-level tty driver. * is not handled by the tty layer or the low-level tty driver.
* It is intended for ioctls which affect line discpline * It is intended for ioctls which affect line discpline
* operation. Note that the search order for ioctls is (1) tty * operation. Note that the search order for ioctls is (1) tty
* layer, (2) tty low-level driver, (3) line discpline. So a * layer, (2) tty low-level driver, (3) line discpline. So a
* low-level driver can "grab" an ioctl request before the line * low-level driver can "grab" an ioctl request before the line
* discpline has a chance to see it. * discpline has a chance to see it.
*
* 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 * 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); * void (*set_termios)(struct tty_struct *tty, struct ktermios * old);
* *
* This function notifies the line discpline that a change has * This function notifies the line discpline that a change has
* been made to the termios structure. * been made to the termios structure.
*
* 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 * int (*poll)(struct tty_struct * tty, struct file * file,
* tty device. It is solely the responsibility of the line * poll_table *wait);
* discipline to handle poll requests. *
* 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, * 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 *); * void (*write_wakeup)(struct tty_struct *);
* *
* This function is called by the low-level tty driver to signal * This function is called by the low-level tty driver to signal
* that line discpline should try to send more characters to the * that line discpline should try to send more characters to the
* low-level driver for transmission. If the line discpline does * low-level driver for transmission. If the line discpline does
* not have any more data to send, it can just return. * not have any more data to send, it can just return.
* *
* int (*hangup)(struct tty_struct *) * int (*hangup)(struct tty_struct *)
* *
@ -115,7 +115,7 @@ struct tty_ldisc_ops {
char *name; char *name;
int num; int num;
int flags; int flags;
/* /*
* The following routines are called from above. * The following routines are called from above.
*/ */
@ -123,19 +123,19 @@ struct tty_ldisc_ops {
void (*close)(struct tty_struct *); void (*close)(struct tty_struct *);
void (*flush_buffer)(struct tty_struct *tty); void (*flush_buffer)(struct tty_struct *tty);
ssize_t (*chars_in_buffer)(struct tty_struct *tty); ssize_t (*chars_in_buffer)(struct tty_struct *tty);
ssize_t (*read)(struct tty_struct * tty, struct file * file, ssize_t (*read)(struct tty_struct *tty, struct file *file,
unsigned char __user * buf, size_t nr); unsigned char __user *buf, size_t nr);
ssize_t (*write)(struct tty_struct * tty, struct file * file, ssize_t (*write)(struct tty_struct *tty, struct file *file,
const unsigned char * buf, size_t nr); const unsigned char *buf, size_t nr);
int (*ioctl)(struct tty_struct * tty, struct file * file, int (*ioctl)(struct tty_struct *tty, struct file *file,
unsigned int cmd, unsigned long arg); 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); 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 *, unsigned int (*poll)(struct tty_struct *, struct file *,
struct poll_table_struct *); struct poll_table_struct *);
int (*hangup)(struct tty_struct *tty); int (*hangup)(struct tty_struct *tty);
/* /*
* The following routines are called from below. * The following routines are called from below.
*/ */
@ -145,7 +145,7 @@ struct tty_ldisc_ops {
void (*dcd_change)(struct tty_struct *, unsigned int); void (*dcd_change)(struct tty_struct *, unsigned int);
struct module *owner; struct module *owner;
int refcount; int refcount;
}; };

View file

@ -328,7 +328,7 @@ static int ircomm_tty_block_til_ready(struct ircomm_tty_cb *self,
spin_unlock_irqrestore(&port->lock, flags); spin_unlock_irqrestore(&port->lock, flags);
while (1) { while (1) {
if (tty->termios.c_cflag & CBAUD) if (C_BAUD(tty) && test_bit(ASYNCB_INITIALIZED, &port->flags))
tty_port_raise_dtr_rts(port); tty_port_raise_dtr_rts(port);
set_current_state(TASK_INTERRUPTIBLE); set_current_state(TASK_INTERRUPTIBLE);

View file

@ -997,12 +997,8 @@ static int ircomm_tty_state_ready(struct ircomm_tty_cb *self,
self->settings.dce = IRCOMM_DELTA_CD; self->settings.dce = IRCOMM_DELTA_CD;
ircomm_tty_check_modem_status(self); ircomm_tty_check_modem_status(self);
} else { } else {
struct tty_struct *tty = tty_port_tty_get(&self->port);
IRDA_DEBUG(0, "%s(), hanging up!\n", __func__ ); IRDA_DEBUG(0, "%s(), hanging up!\n", __func__ );
if (tty) { tty_port_tty_hangup(&self->port, false);
tty_hangup(tty);
tty_kref_put(tty);
}
} }
break; break;
default: default: