summaryrefslogtreecommitdiffstats
path: root/drivers/tty
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/tty')
-rw-r--r--drivers/tty/Makefile2
-rw-r--r--drivers/tty/hvc/hvc_iucv.c2
-rw-r--r--drivers/tty/n_tty.c12
-rw-r--r--drivers/tty/serial/8250/Kconfig5
-rw-r--r--drivers/tty/serial/Kconfig13
-rw-r--r--drivers/tty/serial/altera_uart.c1
-rw-r--r--drivers/tty/serial/amba-pl011.c11
-rw-r--r--drivers/tty/serial/cpm_uart/cpm_uart_core.c4
-rw-r--r--drivers/tty/serial/imx.c40
-rw-r--r--drivers/tty/serial/mpc52xx_uart.c421
-rw-r--r--drivers/tty/serial/of_serial.c4
-rw-r--r--drivers/tty/serial/omap-serial.c34
-rw-r--r--drivers/tty/serial/samsung.c8
-rw-r--r--drivers/tty/serial/sc26xx.c5
-rw-r--r--drivers/tty/serial/serial_core.c6
-rw-r--r--drivers/tty/serial/sirfsoc_uart.c5
-rw-r--r--drivers/tty/serial/sunhv.c6
-rw-r--r--drivers/tty/serial/sunsab.c6
-rw-r--r--drivers/tty/serial/sunsu.c8
-rw-r--r--drivers/tty/serial/sunzilog.c6
-rw-r--r--drivers/tty/serial/ucc_uart.c9
-rw-r--r--drivers/tty/serial/vt8500_serial.c2
-rw-r--r--drivers/tty/serial/xilinx_uartps.c36
-rw-r--r--drivers/tty/sysrq.c2
-rw-r--r--drivers/tty/tty_ldsem.c453
-rw-r--r--drivers/tty/vt/vt.c117
26 files changed, 954 insertions, 264 deletions
diff --git a/drivers/tty/Makefile b/drivers/tty/Makefile
index 6b78399bc7c9..58ad1c05b7f8 100644
--- a/drivers/tty/Makefile
+++ b/drivers/tty/Makefile
@@ -1,5 +1,5 @@
obj-$(CONFIG_TTY) += tty_io.o n_tty.o tty_ioctl.o tty_ldisc.o \
- tty_buffer.o tty_port.o tty_mutex.o
+ tty_buffer.o tty_port.o tty_mutex.o tty_ldsem.o
obj-$(CONFIG_LEGACY_PTYS) += pty.o
obj-$(CONFIG_UNIX98_PTYS) += pty.o
obj-$(CONFIG_AUDIT) += tty_audit.o
diff --git a/drivers/tty/hvc/hvc_iucv.c b/drivers/tty/hvc/hvc_iucv.c
index b6f7d52f7c35..9d47f50c2755 100644
--- a/drivers/tty/hvc/hvc_iucv.c
+++ b/drivers/tty/hvc/hvc_iucv.c
@@ -1328,7 +1328,7 @@ out_error:
*/
static int __init hvc_iucv_config(char *val)
{
- return strict_strtoul(val, 10, &hvc_iucv_devices);
+ return kstrtoul(val, 10, &hvc_iucv_devices);
}
diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c
index 6c7fe90ad72d..cdcdb0ea061a 100644
--- a/drivers/tty/n_tty.c
+++ b/drivers/tty/n_tty.c
@@ -647,8 +647,7 @@ static void process_echoes(struct tty_struct *tty)
if (no_space_left)
break;
} else {
- if (O_OPOST(tty) &&
- !(test_bit(TTY_HW_COOK_OUT, &tty->flags))) {
+ if (O_OPOST(tty)) {
int retval = do_output_char(c, tty, space);
if (retval < 0)
break;
@@ -1516,12 +1515,7 @@ static void n_tty_set_termios(struct tty_struct *tty, struct ktermios *old)
wake_up_interruptible(&tty->read_wait);
ldata->icanon = (L_ICANON(tty) != 0);
- if (test_bit(TTY_HW_COOK_IN, &tty->flags)) {
- ldata->raw = 1;
- ldata->real_raw = 1;
- n_tty_set_room(tty);
- return;
- }
+
if (I_ISTRIP(tty) || I_IUCLC(tty) || I_IGNCR(tty) ||
I_ICRNL(tty) || I_INLCR(tty) || L_ICANON(tty) ||
I_IXON(tty) || L_ISIG(tty) || L_ECHO(tty) ||
@@ -2045,7 +2039,7 @@ static ssize_t n_tty_write(struct tty_struct *tty, struct file *file,
retval = -EIO;
break;
}
- if (O_OPOST(tty) && !(test_bit(TTY_HW_COOK_OUT, &tty->flags))) {
+ if (O_OPOST(tty)) {
while (nr > 0) {
ssize_t num = process_output_block(tty, b, nr);
if (num < 0) {
diff --git a/drivers/tty/serial/8250/Kconfig b/drivers/tty/serial/8250/Kconfig
index 80fe91e64a52..a1ba94d64885 100644
--- a/drivers/tty/serial/8250/Kconfig
+++ b/drivers/tty/serial/8250/Kconfig
@@ -12,9 +12,8 @@ config SERIAL_8250
here are those that are setting up dedicated Ethernet WWW/FTP
servers, or users that have one of the various bus mice instead of a
serial mouse and don't intend to use their machine's standard serial
- port for anything. (Note that the Cyclades and Stallion multi
- serial port drivers do not need this driver built in for them to
- work.)
+ port for anything. (Note that the Cyclades multi serial port driver
+ does not need this driver built in for it to work.)
To compile this driver as a module, choose M here: the
module will be called 8250.
diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
index 7e7006fd404e..95e66acca165 100644
--- a/drivers/tty/serial/Kconfig
+++ b/drivers/tty/serial/Kconfig
@@ -551,7 +551,7 @@ config BFIN_UART3_CTSRTS
Enable hardware flow control in the driver.
config SERIAL_IMX
- bool "IMX serial port support"
+ tristate "IMX serial port support"
depends on ARCH_MXC
select SERIAL_CORE
select RATIONAL
@@ -561,22 +561,21 @@ config SERIAL_IMX
config SERIAL_IMX_CONSOLE
bool "Console on IMX serial port"
- depends on SERIAL_IMX
+ depends on SERIAL_IMX=y
select SERIAL_CORE_CONSOLE
help
- If you have enabled the serial port on the Motorola IMX
+ If you have enabled the serial port on the Freescale IMX
CPU you can make it the console by answering Y to this option.
Even if you say Y here, the currently visible virtual console
(/dev/tty0) will still be used as the system console by default, but
you can alter that using a kernel command line option such as
- "console=ttySA0". (Try "man bootparam" or see the documentation of
- your boot loader (lilo or loadlin) about how to pass options to the
- kernel at boot time.)
+ "console=ttymxc0". (Try "man bootparam" or see the documentation of
+ your bootloader about how to pass options to the kernel at boot time.)
config SERIAL_UARTLITE
tristate "Xilinx uartlite serial port support"
- depends on PPC32 || MICROBLAZE || MFD_TIMBERDALE
+ depends on PPC32 || MICROBLAZE || MFD_TIMBERDALE || ARCH_ZYNQ
select SERIAL_CORE
help
Say Y here if you want to use the Xilinx uartlite serial controller.
diff --git a/drivers/tty/serial/altera_uart.c b/drivers/tty/serial/altera_uart.c
index 13471dd95793..1d46966e2a65 100644
--- a/drivers/tty/serial/altera_uart.c
+++ b/drivers/tty/serial/altera_uart.c
@@ -604,7 +604,6 @@ static int altera_uart_remove(struct platform_device *pdev)
if (port) {
uart_remove_one_port(&altera_uart_driver, port);
- platform_set_drvdata(pdev, NULL);
port->mapbase = 0;
}
diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c
index e2774f9ecd59..ad41319d1d9b 100644
--- a/drivers/tty/serial/amba-pl011.c
+++ b/drivers/tty/serial/amba-pl011.c
@@ -79,13 +79,12 @@ struct vendor_data {
bool dma_threshold;
bool cts_event_workaround;
- unsigned int (*get_fifosize)(unsigned int periphid);
+ unsigned int (*get_fifosize)(struct amba_device *dev);
};
-static unsigned int get_fifosize_arm(unsigned int periphid)
+static unsigned int get_fifosize_arm(struct amba_device *dev)
{
- unsigned int rev = (periphid >> 20) & 0xf;
- return rev < 3 ? 16 : 32;
+ return amba_rev(dev) < 3 ? 16 : 32;
}
static struct vendor_data vendor_arm = {
@@ -98,7 +97,7 @@ static struct vendor_data vendor_arm = {
.get_fifosize = get_fifosize_arm,
};
-static unsigned int get_fifosize_st(unsigned int periphid)
+static unsigned int get_fifosize_st(struct amba_device *dev)
{
return 64;
}
@@ -2157,7 +2156,7 @@ static int pl011_probe(struct amba_device *dev, const struct amba_id *id)
uap->lcrh_rx = vendor->lcrh_rx;
uap->lcrh_tx = vendor->lcrh_tx;
uap->old_cr = 0;
- uap->fifosize = vendor->get_fifosize(dev->periphid);
+ uap->fifosize = vendor->get_fifosize(dev);
uap->port.dev = &dev->dev;
uap->port.mapbase = dev->res.start;
uap->port.membase = base;
diff --git a/drivers/tty/serial/cpm_uart/cpm_uart_core.c b/drivers/tty/serial/cpm_uart/cpm_uart_core.c
index 97f4e1858649..f7672cae5321 100644
--- a/drivers/tty/serial/cpm_uart/cpm_uart_core.c
+++ b/drivers/tty/serial/cpm_uart/cpm_uart_core.c
@@ -1384,7 +1384,7 @@ static int cpm_uart_probe(struct platform_device *ofdev)
if (index >= UART_NR)
return -ENODEV;
- dev_set_drvdata(&ofdev->dev, pinfo);
+ platform_set_drvdata(ofdev, pinfo);
/* initialize the device pointer for the port */
pinfo->port.dev = &ofdev->dev;
@@ -1398,7 +1398,7 @@ static int cpm_uart_probe(struct platform_device *ofdev)
static int cpm_uart_remove(struct platform_device *ofdev)
{
- struct uart_cpm_port *pinfo = dev_get_drvdata(&ofdev->dev);
+ struct uart_cpm_port *pinfo = platform_get_drvdata(ofdev);
return uart_remove_one_port(&cpm_reg, &pinfo->port);
}
diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c
index 8cdfbd365892..7a761f7c9781 100644
--- a/drivers/tty/serial/imx.c
+++ b/drivers/tty/serial/imx.c
@@ -201,6 +201,7 @@ struct imx_port {
unsigned int old_status;
int txirq, rxirq, rtsirq;
unsigned int have_rtscts:1;
+ unsigned int dte_mode:1;
unsigned int use_irda:1;
unsigned int irda_inv_rx:1;
unsigned int irda_inv_tx:1;
@@ -271,6 +272,7 @@ static inline int is_imx21_uart(struct imx_port *sport)
/*
* Save and restore functions for UCR1, UCR2 and UCR3 registers
*/
+#if defined(CONFIG_CONSOLE_POLL) || defined(CONFIG_SERIAL_IMX_CONSOLE)
static void imx_port_ucrs_save(struct uart_port *port,
struct imx_port_ucrs *ucr)
{
@@ -288,6 +290,7 @@ static void imx_port_ucrs_restore(struct uart_port *port,
writel(ucr->ucr2, port->membase + UCR2);
writel(ucr->ucr3, port->membase + UCR3);
}
+#endif
/*
* Handle any change of modem status signal since we were last called.
@@ -449,6 +452,13 @@ static void imx_start_tx(struct uart_port *port)
temp &= ~(UCR1_RRDYEN);
writel(temp, sport->port.membase + UCR1);
}
+ /* Clear any pending ORE flag before enabling interrupt */
+ temp = readl(sport->port.membase + USR2);
+ writel(temp | USR2_ORE, sport->port.membase + USR2);
+
+ temp = readl(sport->port.membase + UCR4);
+ temp |= UCR4_OREN;
+ writel(temp, sport->port.membase + UCR4);
temp = readl(sport->port.membase + UCR1);
writel(temp | UCR1_TXMPTYEN, sport->port.membase + UCR1);
@@ -582,6 +592,7 @@ static irqreturn_t imx_int(int irq, void *dev_id)
{
struct imx_port *sport = dev_id;
unsigned int sts;
+ unsigned int sts2;
sts = readl(sport->port.membase + USR1);
@@ -598,6 +609,13 @@ static irqreturn_t imx_int(int irq, void *dev_id)
if (sts & USR1_AWAKE)
writel(USR1_AWAKE, sport->port.membase + USR1);
+ sts2 = readl(sport->port.membase + USR2);
+ if (sts2 & USR2_ORE) {
+ dev_err(sport->port.dev, "Rx FIFO overrun\n");
+ sport->port.icount.overrun++;
+ writel(sts2 | USR2_ORE, sport->port.membase + USR2);
+ }
+
return IRQ_HANDLED;
}
@@ -684,6 +702,14 @@ static int imx_startup(struct uart_port *port)
int retval;
unsigned long flags, temp;
+ retval = clk_prepare_enable(sport->clk_per);
+ if (retval)
+ goto error_out1;
+
+ retval = clk_prepare_enable(sport->clk_ipg);
+ if (retval)
+ goto error_out1;
+
imx_setup_ufcr(sport, 0);
/* disable the DREN bit (Data Ready interrupt enable) before
@@ -871,6 +897,9 @@ static void imx_shutdown(struct uart_port *port)
writel(temp, sport->port.membase + UCR1);
spin_unlock_irqrestore(&sport->port.lock, flags);
+
+ clk_disable_unprepare(sport->clk_per);
+ clk_disable_unprepare(sport->clk_ipg);
}
static void
@@ -1007,6 +1036,8 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios,
ufcr = readl(sport->port.membase + UFCR);
ufcr = (ufcr & (~UFCR_RFDIV)) | UFCR_RFDIV_REG(div);
+ if (sport->dte_mode)
+ ufcr |= UFCR_DCEDTE;
writel(ufcr, sport->port.membase + UFCR);
writel(num, sport->port.membase + UBIR);
@@ -1431,6 +1462,9 @@ static int serial_imx_probe_dt(struct imx_port *sport,
if (of_get_property(np, "fsl,irda-mode", NULL))
sport->use_irda = 1;
+ if (of_get_property(np, "fsl,dte-mode", NULL))
+ sport->dte_mode = 1;
+
sport->devdata = of_id->data;
return 0;
@@ -1544,6 +1578,9 @@ static int serial_imx_probe(struct platform_device *pdev)
goto deinit;
platform_set_drvdata(pdev, sport);
+ clk_disable_unprepare(sport->clk_per);
+ clk_disable_unprepare(sport->clk_ipg);
+
return 0;
deinit:
if (pdata && pdata->exit)
@@ -1565,9 +1602,6 @@ static int serial_imx_remove(struct platform_device *pdev)
uart_remove_one_port(&imx_reg, &sport->port);
- clk_disable_unprepare(sport->clk_per);
- clk_disable_unprepare(sport->clk_ipg);
-
if (pdata && pdata->exit)
pdata->exit(pdev);
diff --git a/drivers/tty/serial/mpc52xx_uart.c b/drivers/tty/serial/mpc52xx_uart.c
index f51b280f3bf2..9ba194590a80 100644
--- a/drivers/tty/serial/mpc52xx_uart.c
+++ b/drivers/tty/serial/mpc52xx_uart.c
@@ -84,16 +84,6 @@ static void mpc52xx_uart_of_enumerate(void);
static irqreturn_t mpc52xx_uart_int(int irq, void *dev_id);
static irqreturn_t mpc5xxx_uart_process_int(struct uart_port *port);
-
-/* Simple macro to test if a port is console or not. This one is taken
- * for serial_core.c and maybe should be moved to serial_core.h ? */
-#ifdef CONFIG_SERIAL_CORE_CONSOLE
-#define uart_console(port) \
- ((port)->cons && (port)->cons->index == (port)->line)
-#else
-#define uart_console(port) (0)
-#endif
-
/* ======================================================================== */
/* PSC fifo operations for isolating differences between 52xx and 512x */
/* ======================================================================== */
@@ -122,6 +112,15 @@ struct psc_ops {
void (*fifoc_uninit)(void);
void (*get_irq)(struct uart_port *, struct device_node *);
irqreturn_t (*handle_irq)(struct uart_port *port);
+ u16 (*get_status)(struct uart_port *port);
+ u8 (*get_ipcr)(struct uart_port *port);
+ void (*command)(struct uart_port *port, u8 cmd);
+ void (*set_mode)(struct uart_port *port, u8 mr1, u8 mr2);
+ void (*set_rts)(struct uart_port *port, int state);
+ void (*enable_ms)(struct uart_port *port);
+ void (*set_sicr)(struct uart_port *port, u32 val);
+ void (*set_imr)(struct uart_port *port, u16 val);
+ u8 (*get_mr1)(struct uart_port *port);
};
/* setting the prescaler and divisor reg is common for all chips */
@@ -134,6 +133,65 @@ static inline void mpc52xx_set_divisor(struct mpc52xx_psc __iomem *psc,
out_8(&psc->ctlr, divisor & 0xff);
}
+static u16 mpc52xx_psc_get_status(struct uart_port *port)
+{
+ return in_be16(&PSC(port)->mpc52xx_psc_status);
+}
+
+static u8 mpc52xx_psc_get_ipcr(struct uart_port *port)
+{
+ return in_8(&PSC(port)->mpc52xx_psc_ipcr);
+}
+
+static void mpc52xx_psc_command(struct uart_port *port, u8 cmd)
+{
+ out_8(&PSC(port)->command, cmd);
+}
+
+static void mpc52xx_psc_set_mode(struct uart_port *port, u8 mr1, u8 mr2)
+{
+ out_8(&PSC(port)->command, MPC52xx_PSC_SEL_MODE_REG_1);
+ out_8(&PSC(port)->mode, mr1);
+ out_8(&PSC(port)->mode, mr2);
+}
+
+static void mpc52xx_psc_set_rts(struct uart_port *port, int state)
+{
+ if (state)
+ out_8(&PSC(port)->op1, MPC52xx_PSC_OP_RTS);
+ else
+ out_8(&PSC(port)->op0, MPC52xx_PSC_OP_RTS);
+}
+
+static void mpc52xx_psc_enable_ms(struct uart_port *port)
+{
+ struct mpc52xx_psc __iomem *psc = PSC(port);
+
+ /* clear D_*-bits by reading them */
+ in_8(&psc->mpc52xx_psc_ipcr);
+ /* enable CTS and DCD as IPC interrupts */
+ out_8(&psc->mpc52xx_psc_acr, MPC52xx_PSC_IEC_CTS | MPC52xx_PSC_IEC_DCD);
+
+ port->read_status_mask |= MPC52xx_PSC_IMR_IPC;
+ out_be16(&psc->mpc52xx_psc_imr, port->read_status_mask);
+}
+
+static void mpc52xx_psc_set_sicr(struct uart_port *port, u32 val)
+{
+ out_be32(&PSC(port)->sicr, val);
+}
+
+static void mpc52xx_psc_set_imr(struct uart_port *port, u16 val)
+{
+ out_be16(&PSC(port)->mpc52xx_psc_imr, val);
+}
+
+static u8 mpc52xx_psc_get_mr1(struct uart_port *port)
+{
+ out_8(&PSC(port)->command, MPC52xx_PSC_SEL_MODE_REG_1);
+ return in_8(&PSC(port)->mode);
+}
+
#ifdef CONFIG_PPC_MPC52xx
#define FIFO_52xx(port) ((struct mpc52xx_psc_fifo __iomem *)(PSC(port)+1))
static void mpc52xx_psc_fifo_init(struct uart_port *port)
@@ -304,6 +362,15 @@ static struct psc_ops mpc52xx_psc_ops = {
.set_baudrate = mpc5200_psc_set_baudrate,
.get_irq = mpc52xx_psc_get_irq,
.handle_irq = mpc52xx_psc_handle_irq,
+ .get_status = mpc52xx_psc_get_status,
+ .get_ipcr = mpc52xx_psc_get_ipcr,
+ .command = mpc52xx_psc_command,
+ .set_mode = mpc52xx_psc_set_mode,
+ .set_rts = mpc52xx_psc_set_rts,
+ .enable_ms = mpc52xx_psc_enable_ms,
+ .set_sicr = mpc52xx_psc_set_sicr,
+ .set_imr = mpc52xx_psc_set_imr,
+ .get_mr1 = mpc52xx_psc_get_mr1,
};
static struct psc_ops mpc5200b_psc_ops = {
@@ -325,6 +392,15 @@ static struct psc_ops mpc5200b_psc_ops = {
.set_baudrate = mpc5200b_psc_set_baudrate,
.get_irq = mpc52xx_psc_get_irq,
.handle_irq = mpc52xx_psc_handle_irq,
+ .get_status = mpc52xx_psc_get_status,
+ .get_ipcr = mpc52xx_psc_get_ipcr,
+ .command = mpc52xx_psc_command,
+ .set_mode = mpc52xx_psc_set_mode,
+ .set_rts = mpc52xx_psc_set_rts,
+ .enable_ms = mpc52xx_psc_enable_ms,
+ .set_sicr = mpc52xx_psc_set_sicr,
+ .set_imr = mpc52xx_psc_set_imr,
+ .get_mr1 = mpc52xx_psc_get_mr1,
};
#endif /* CONFIG_MPC52xx */
@@ -572,6 +648,246 @@ static void mpc512x_psc_get_irq(struct uart_port *port, struct device_node *np)
port->irqflags = IRQF_SHARED;
port->irq = psc_fifoc_irq;
}
+#endif
+
+#ifdef CONFIG_PPC_MPC512x
+
+#define PSC_5125(port) ((struct mpc5125_psc __iomem *)((port)->membase))
+#define FIFO_5125(port) ((struct mpc512x_psc_fifo __iomem *)(PSC_5125(port)+1))
+
+static void mpc5125_psc_fifo_init(struct uart_port *port)
+{
+ /* /32 prescaler */
+ out_8(&PSC_5125(port)->mpc52xx_psc_clock_select, 0xdd);
+
+ out_be32(&FIFO_5125(port)->txcmd, MPC512x_PSC_FIFO_RESET_SLICE);
+ out_be32(&FIFO_5125(port)->txcmd, MPC512x_PSC_FIFO_ENABLE_SLICE);
+ out_be32(&FIFO_5125(port)->txalarm, 1);
+ out_be32(&FIFO_5125(port)->tximr, 0);
+
+ out_be32(&FIFO_5125(port)->rxcmd, MPC512x_PSC_FIFO_RESET_SLICE);
+ out_be32(&FIFO_5125(port)->rxcmd, MPC512x_PSC_FIFO_ENABLE_SLICE);
+ out_be32(&FIFO_5125(port)->rxalarm, 1);
+ out_be32(&FIFO_5125(port)->rximr, 0);
+
+ out_be32(&FIFO_5125(port)->tximr, MPC512x_PSC_FIFO_ALARM);
+ out_be32(&FIFO_5125(port)->rximr, MPC512x_PSC_FIFO_ALARM);
+}
+
+static int mpc5125_psc_raw_rx_rdy(struct uart_port *port)
+{
+ return !(in_be32(&FIFO_5125(port)->rxsr) & MPC512x_PSC_FIFO_EMPTY);
+}
+
+static int mpc5125_psc_raw_tx_rdy(struct uart_port *port)
+{
+ return !(in_be32(&FIFO_5125(port)->txsr) & MPC512x_PSC_FIFO_FULL);
+}
+
+static int mpc5125_psc_rx_rdy(struct uart_port *port)
+{
+ return in_be32(&FIFO_5125(port)->rxsr) &
+ in_be32(&FIFO_5125(port)->rximr) & MPC512x_PSC_FIFO_ALARM;
+}
+
+static int mpc5125_psc_tx_rdy(struct uart_port *port)
+{
+ return in_be32(&FIFO_5125(port)->txsr) &
+ in_be32(&FIFO_5125(port)->tximr) & MPC512x_PSC_FIFO_ALARM;
+}
+
+static int mpc5125_psc_tx_empty(struct uart_port *port)
+{
+ return in_be32(&FIFO_5125(port)->txsr) & MPC512x_PSC_FIFO_EMPTY;
+}
+
+static void mpc5125_psc_stop_rx(struct uart_port *port)
+{
+ unsigned long rx_fifo_imr;
+
+ rx_fifo_imr = in_be32(&FIFO_5125(port)->rximr);
+ rx_fifo_imr &= ~MPC512x_PSC_FIFO_ALARM;
+ out_be32(&FIFO_5125(port)->rximr, rx_fifo_imr);
+}
+
+static void mpc5125_psc_start_tx(struct uart_port *port)
+{
+ unsigned long tx_fifo_imr;
+
+ tx_fifo_imr = in_be32(&FIFO_5125(port)->tximr);
+ tx_fifo_imr |= MPC512x_PSC_FIFO_ALARM;
+ out_be32(&FIFO_5125(port)->tximr, tx_fifo_imr);
+}
+
+static void mpc5125_psc_stop_tx(struct uart_port *port)
+{
+ unsigned long tx_fifo_imr;
+
+ tx_fifo_imr = in_be32(&FIFO_5125(port)->tximr);
+ tx_fifo_imr &= ~MPC512x_PSC_FIFO_ALARM;
+ out_be32(&FIFO_5125(port)->tximr, tx_fifo_imr);
+}
+
+static void mpc5125_psc_rx_clr_irq(struct uart_port *port)
+{
+ out_be32(&FIFO_5125(port)->rxisr, in_be32(&FIFO_5125(port)->rxisr));
+}
+
+static void mpc5125_psc_tx_clr_irq(struct uart_port *port)
+{
+ out_be32(&FIFO_5125(port)->txisr, in_be32(&FIFO_5125(port)->txisr));
+}
+
+static void mpc5125_psc_write_char(struct uart_port *port, unsigned char c)
+{
+ out_8(&FIFO_5125(port)->txdata_8, c);
+}
+
+static unsigned char mpc5125_psc_read_char(struct uart_port *port)
+{
+ return in_8(&FIFO_5125(port)->rxdata_8);
+}
+
+static void mpc5125_psc_cw_disable_ints(struct uart_port *port)
+{
+ port->read_status_mask =
+ in_be32(&FIFO_5125(port)->tximr) << 16 |
+ in_be32(&FIFO_5125(port)->rximr);
+ out_be32(&FIFO_5125(port)->tximr, 0);
+ out_be32(&FIFO_5125(port)->rximr, 0);
+}
+
+static void mpc5125_psc_cw_restore_ints(struct uart_port *port)
+{
+ out_be32(&FIFO_5125(port)->tximr,
+ (port->read_status_mask >> 16) & 0x7f);
+ out_be32(&FIFO_5125(port)->rximr, port->read_status_mask & 0x7f);
+}
+
+static inline void mpc5125_set_divisor(struct mpc5125_psc __iomem *psc,
+ u8 prescaler, unsigned int divisor)
+{
+ /* select prescaler */
+ out_8(&psc->mpc52xx_psc_clock_select, prescaler);
+ out_8(&psc->ctur, divisor >> 8);
+ out_8(&psc->ctlr, divisor & 0xff);
+}
+
+static unsigned int mpc5125_psc_set_baudrate(struct uart_port *port,
+ struct ktermios *new,
+ struct ktermios *old)
+{
+ unsigned int baud;
+ unsigned int divisor;
+
+ /*
+ * Calculate with a /16 prescaler here.
+ */
+
+ /* uartclk contains the ips freq */
+ baud = uart_get_baud_rate(port, new, old,
+ port->uartclk / (16 * 0xffff) + 1,
+ port->uartclk / 16);
+ divisor = (port->uartclk + 8 * baud) / (16 * baud);
+
+ /* enable the /16 prescaler and set the divisor */
+ mpc5125_set_divisor(PSC_5125(port), 0xdd, divisor);
+ return baud;
+}
+
+/*
+ * MPC5125 have compatible PSC FIFO Controller.
+ * Special init not needed.
+ */
+static u16 mpc5125_psc_get_status(struct uart_port *port)
+{
+ return in_be16(&PSC_5125(port)->mpc52xx_psc_status);
+}
+
+static u8 mpc5125_psc_get_ipcr(struct uart_port *port)
+{
+ return in_8(&PSC_5125(port)->mpc52xx_psc_ipcr);
+}
+
+static void mpc5125_psc_command(struct uart_port *port, u8 cmd)
+{
+ out_8(&PSC_5125(port)->command, cmd);
+}
+
+static void mpc5125_psc_set_mode(struct uart_port *port, u8 mr1, u8 mr2)
+{
+ out_8(&PSC_5125(port)->mr1, mr1);
+ out_8(&PSC_5125(port)->mr2, mr2);
+}
+
+static void mpc5125_psc_set_rts(struct uart_port *port, int state)
+{
+ if (state & TIOCM_RTS)
+ out_8(&PSC_5125(port)->op1, MPC52xx_PSC_OP_RTS);
+ else
+ out_8(&PSC_5125(port)->op0, MPC52xx_PSC_OP_RTS);
+}
+
+static void mpc5125_psc_enable_ms(struct uart_port *port)
+{
+ struct mpc5125_psc __iomem *psc = PSC_5125(port);
+
+ /* clear D_*-bits by reading them */
+ in_8(&psc->mpc52xx_psc_ipcr);
+ /* enable CTS and DCD as IPC interrupts */
+ out_8(&psc->mpc52xx_psc_acr, MPC52xx_PSC_IEC_CTS | MPC52xx_PSC_IEC_DCD);
+
+ port->read_status_mask |= MPC52xx_PSC_IMR_IPC;
+ out_be16(&psc->mpc52xx_psc_imr, port->read_status_mask);
+}
+
+static void mpc5125_psc_set_sicr(struct uart_port *port, u32 val)
+{
+ out_be32(&PSC_5125(port)->sicr, val);
+}
+
+static void mpc5125_psc_set_imr(struct uart_port *port, u16 val)
+{
+ out_be16(&PSC_5125(port)->mpc52xx_psc_imr, val);
+}
+
+static u8 mpc5125_psc_get_mr1(struct uart_port *port)
+{
+ return in_8(&PSC_5125(port)->mr1);
+}
+
+static struct psc_ops mpc5125_psc_ops = {
+ .fifo_init = mpc5125_psc_fifo_init,
+ .raw_rx_rdy = mpc5125_psc_raw_rx_rdy,
+ .raw_tx_rdy = mpc5125_psc_raw_tx_rdy,
+ .rx_rdy = mpc5125_psc_rx_rdy,
+ .tx_rdy = mpc5125_psc_tx_rdy,
+ .tx_empty = mpc5125_psc_tx_empty,
+ .stop_rx = mpc5125_psc_stop_rx,
+ .start_tx = mpc5125_psc_start_tx,
+ .stop_tx = mpc5125_psc_stop_tx,
+ .rx_clr_irq = mpc5125_psc_rx_clr_irq,
+ .tx_clr_irq = mpc5125_psc_tx_clr_irq,
+ .write_char = mpc5125_psc_write_char,
+ .read_char = mpc5125_psc_read_char,
+ .cw_disable_ints = mpc5125_psc_cw_disable_ints,
+ .cw_restore_ints = mpc5125_psc_cw_restore_ints,
+ .set_baudrate = mpc5125_psc_set_baudrate,
+ .clock = mpc512x_psc_clock,
+ .fifoc_init = mpc512x_psc_fifoc_init,
+ .fifoc_uninit = mpc512x_psc_fifoc_uninit,
+ .get_irq = mpc512x_psc_get_irq,
+ .handle_irq = mpc512x_psc_handle_irq,
+ .get_status = mpc5125_psc_get_status,
+ .get_ipcr = mpc5125_psc_get_ipcr,
+ .command = mpc5125_psc_command,
+ .set_mode = mpc5125_psc_set_mode,
+ .set_rts = mpc5125_psc_set_rts,
+ .enable_ms = mpc5125_psc_enable_ms,
+ .set_sicr = mpc5125_psc_set_sicr,
+ .set_imr = mpc5125_psc_set_imr,
+ .get_mr1 = mpc5125_psc_get_mr1,
+};
static struct psc_ops mpc512x_psc_ops = {
.fifo_init = mpc512x_psc_fifo_init,
@@ -595,8 +911,18 @@ static struct psc_ops mpc512x_psc_ops = {
.fifoc_uninit = mpc512x_psc_fifoc_uninit,
.get_irq = mpc512x_psc_get_irq,
.handle_irq = mpc512x_psc_handle_irq,
+ .get_status = mpc52xx_psc_get_status,
+ .get_ipcr = mpc52xx_psc_get_ipcr,
+ .command = mpc52xx_psc_command,
+ .set_mode = mpc52xx_psc_set_mode,
+ .set_rts = mpc52xx_psc_set_rts,
+ .enable_ms = mpc52xx_psc_enable_ms,
+ .set_sicr = mpc52xx_psc_set_sicr,
+ .set_imr = mpc52xx_psc_set_imr,
+ .get_mr1 = mpc52xx_psc_get_mr1,
};
-#endif
+#endif /* CONFIG_PPC_MPC512x */
+
static const struct psc_ops *psc_ops;
@@ -613,17 +939,14 @@ mpc52xx_uart_tx_empty(struct uart_port *port)
static void
mpc52xx_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
{
- if (mctrl & TIOCM_RTS)
- out_8(&PSC(port)->op1, MPC52xx_PSC_OP_RTS);
- else
- out_8(&PSC(port)->op0, MPC52xx_PSC_OP_RTS);
+ psc_ops->set_rts(port, mctrl & TIOCM_RTS);
}
static unsigned int
mpc52xx_uart_get_mctrl(struct uart_port *port)
{
unsigned int ret = TIOCM_DSR;
- u8 status = in_8(&PSC(port)->mpc52xx_psc_ipcr);
+ u8 status = psc_ops->get_ipcr(port);
if (!(status & MPC52xx_PSC_CTS))
ret |= TIOCM_CTS;
@@ -673,15 +996,7 @@ mpc52xx_uart_stop_rx(struct uart_port *port)
static void
mpc52xx_uart_enable_ms(struct uart_port *port)
{
- struct mpc52xx_psc __iomem *psc = PSC(port);
-
- /* clear D_*-bits by reading them */
- in_8(&psc->mpc52xx_psc_ipcr);
- /* enable CTS and DCD as IPC interrupts */
- out_8(&psc->mpc52xx_psc_acr, MPC52xx_PSC_IEC_CTS | MPC52xx_PSC_IEC_DCD);
-
- port->read_status_mask |= MPC52xx_PSC_IMR_IPC;
- out_be16(&psc->mpc52xx_psc_imr, port->read_status_mask);
+ psc_ops->enable_ms(port);
}
static void
@@ -691,9 +1006,9 @@ mpc52xx_uart_break_ctl(struct uart_port *port, int ctl)
spin_lock_irqsave(&port->lock, flags);
if (ctl == -1)
- out_8(&PSC(port)->command, MPC52xx_PSC_START_BRK);
+ psc_ops->command(port, MPC52xx_PSC_START_BRK);
else
- out_8(&PSC(port)->command, MPC52xx_PSC_STOP_BRK);
+ psc_ops->command(port, MPC52xx_PSC_STOP_BRK);
spin_unlock_irqrestore(&port->lock, flags);
}
@@ -701,7 +1016,6 @@ mpc52xx_uart_break_ctl(struct uart_port *port, int ctl)
static int
mpc52xx_uart_startup(struct uart_port *port)
{
- struct mpc52xx_psc __iomem *psc = PSC(port);
int ret;
if (psc_ops->clock) {
@@ -717,15 +1031,15 @@ mpc52xx_uart_startup(struct uart_port *port)
return ret;
/* Reset/activate the port, clear and enable interrupts */
- out_8(&psc->command, MPC52xx_PSC_RST_RX);
- out_8(&psc->command, MPC52xx_PSC_RST_TX);
+ psc_ops->command(port, MPC52xx_PSC_RST_RX);
+ psc_ops->command(port, MPC52xx_PSC_RST_TX);
- out_be32(&psc->sicr, 0); /* UART mode DCD ignored */
+ psc_ops->set_sicr(port, 0); /* UART mode DCD ignored */
psc_ops->fifo_init(port);
- out_8(&psc->command, MPC52xx_PSC_TX_ENABLE);
- out_8(&psc->command, MPC52xx_PSC_RX_ENABLE);
+ psc_ops->command(port, MPC52xx_PSC_TX_ENABLE);
+ psc_ops->command(port, MPC52xx_PSC_RX_ENABLE);
return 0;
}
@@ -733,15 +1047,13 @@ mpc52xx_uart_startup(struct uart_port *port)
static void
mpc52xx_uart_shutdown(struct uart_port *port)
{
- struct mpc52xx_psc __iomem *psc = PSC(port);
-
/* Shut down the port. Leave TX active if on a console port */
- out_8(&psc->command, MPC52xx_PSC_RST_RX);
+ psc_ops->command(port, MPC52xx_PSC_RST_RX);
if (!uart_console(port))
- out_8(&psc->command, MPC52xx_PSC_RST_TX);
+ psc_ops->command(port, MPC52xx_PSC_RST_TX);
port->read_status_mask = 0;
- out_be16(&psc->mpc52xx_psc_imr, port->read_status_mask);
+ psc_ops->set_imr(port, port->read_status_mask);
if (psc_ops->clock)
psc_ops->clock(port, 0);
@@ -754,7 +1066,6 @@ static void
mpc52xx_uart_set_termios(struct uart_port *port, struct ktermios *new,
struct ktermios *old)
{
- struct mpc52xx_psc __iomem *psc = PSC(port);
unsigned long flags;
unsigned char mr1, mr2;
unsigned int j;
@@ -818,13 +1129,11 @@ mpc52xx_uart_set_termios(struct uart_port *port, struct ktermios *new,
"Some chars may have been lost.\n");
/* Reset the TX & RX */
- out_8(&psc->command, MPC52xx_PSC_RST_RX);
- out_8(&psc->command, MPC52xx_PSC_RST_TX);
+ psc_ops->command(port, MPC52xx_PSC_RST_RX);
+ psc_ops->command(port, MPC52xx_PSC_RST_TX);
/* Send new mode settings */
- out_8(&psc->command, MPC52xx_PSC_SEL_MODE_REG_1);
- out_8(&psc->mode, mr1);
- out_8(&psc->mode, mr2);
+ psc_ops->set_mode(port, mr1, mr2);
baud = psc_ops->set_baudrate(port, new, old);
/* Update the per-port timeout */
@@ -834,8 +1143,8 @@ mpc52xx_uart_set_termios(struct uart_port *port, struct ktermios *new,
mpc52xx_uart_enable_ms(port);
/* Reenable TX & RX */
- out_8(&psc->command, MPC52xx_PSC_TX_ENABLE);
- out_8(&psc->command, MPC52xx_PSC_RX_ENABLE);
+ psc_ops->command(port, MPC52xx_PSC_TX_ENABLE);
+ psc_ops->command(port, MPC52xx_PSC_RX_ENABLE);
/* We're all set, release the lock */
spin_unlock_irqrestore(&port->lock, flags);
@@ -963,7 +1272,7 @@ mpc52xx_uart_int_rx_chars(struct uart_port *port)
flag = TTY_NORMAL;
port->icount.rx++;
- status = in_be16(&PSC(port)->mpc52xx_psc_status);
+ status = psc_ops->get_status(port);
if (status & (MPC52xx_PSC_SR_PE |
MPC52xx_PSC_SR_FE |
@@ -983,7 +1292,7 @@ mpc52xx_uart_int_rx_chars(struct uart_port *port)
}
/* Clear error condition */
- out_8(&PSC(port)->command, MPC52xx_PSC_RST_ERR_STAT);
+ psc_ops->command(port, MPC52xx_PSC_RST_ERR_STAT);
}
tty_insert_flip_char(tport, ch, flag);
@@ -1066,7 +1375,7 @@ mpc5xxx_uart_process_int(struct uart_port *port)
if (psc_ops->tx_rdy(port))
keepgoing |= mpc52xx_uart_int_tx_chars(port);
- status = in_8(&PSC(port)->mpc52xx_psc_ipcr);
+ status = psc_ops->get_ipcr(port);
if (status & MPC52xx_PSC_D_DCD)
uart_handle_dcd_change(port, !(status & MPC52xx_PSC_DCD));
@@ -1107,14 +1416,12 @@ static void __init
mpc52xx_console_get_options(struct uart_port *port,
int *baud, int *parity, int *bits, int *flow)
{
- struct mpc52xx_psc __iomem *psc = PSC(port);
unsigned char mr1;
pr_debug("mpc52xx_console_get_options(port=%p)\n", port);
/* Read the mode registers */
- out_8(&psc->command, MPC52xx_PSC_SEL_MODE_REG_1);
- mr1 = in_8(&psc->mode);
+ mr1 = psc_ops->get_mr1(port);
/* CT{U,L}R are write-only ! */
*baud = CONFIG_SERIAL_MPC52xx_CONSOLE_BAUD;
@@ -1304,6 +1611,7 @@ static struct of_device_id mpc52xx_uart_of_match[] = {
#endif
#ifdef CONFIG_PPC_MPC512x
{ .compatible = "fsl,mpc5121-psc-uart", .data = &mpc512x_psc_ops, },
+ { .compatible = "fsl,mpc5125-psc-uart", .data = &mpc5125_psc_ops, },
#endif
{},
};
@@ -1372,15 +1680,14 @@ static int mpc52xx_uart_of_probe(struct platform_device *op)
if (ret)
return ret;
- dev_set_drvdata(&op->dev, (void *)port);
+ platform_set_drvdata(op, (void *)port);
return 0;
}
static int
mpc52xx_uart_of_remove(struct platform_device *op)
{
- struct uart_port *port = dev_get_drvdata(&op->dev);
- dev_set_drvdata(&op->dev, NULL);
+ struct uart_port *port = platform_get_drvdata(op);
if (port)
uart_remove_one_port(&mpc52xx_uart_driver, port);
@@ -1392,7 +1699,7 @@ mpc52xx_uart_of_remove(struct platform_device *op)
static int
mpc52xx_uart_of_suspend(struct platform_device *op, pm_message_t state)
{
- struct uart_port *port = (struct uart_port *) dev_get_drvdata(&op->dev);
+ struct uart_port *port = (struct uart_port *) platform_get_drvdata(op);
if (port)
uart_suspend_port(&mpc52xx_uart_driver, port);
@@ -1403,7 +1710,7 @@ mpc52xx_uart_of_suspend(struct platform_device *op, pm_message_t state)
static int
mpc52xx_uart_of_resume(struct platform_device *op)
{
- struct uart_port *port = (struct uart_port *) dev_get_drvdata(&op->dev);
+ struct uart_port *port = (struct uart_port *) platform_get_drvdata(op);
if (port)
uart_resume_port(&mpc52xx_uart_driver, port);
diff --git a/drivers/tty/serial/of_serial.c b/drivers/tty/serial/of_serial.c
index 39c7ea4cb14f..2caf9c6f6149 100644
--- a/drivers/tty/serial/of_serial.c
+++ b/drivers/tty/serial/of_serial.c
@@ -204,7 +204,7 @@ static int of_platform_serial_probe(struct platform_device *ofdev)
info->type = port_type;
info->line = ret;
- dev_set_drvdata(&ofdev->dev, info);
+ platform_set_drvdata(ofdev, info);
return 0;
out:
kfree(info);
@@ -217,7 +217,7 @@ out:
*/
static int of_platform_serial_remove(struct platform_device *ofdev)
{
- struct of_serial_info *info = dev_get_drvdata(&ofdev->dev);
+ struct of_serial_info *info = platform_get_drvdata(ofdev);
switch (info->type) {
#ifdef CONFIG_SERIAL_8250
case PORT_8250 ... PORT_MAX_8250:
diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c
index f0b9f6b52b32..156b5aaed95b 100644
--- a/drivers/tty/serial/omap-serial.c
+++ b/drivers/tty/serial/omap-serial.c
@@ -161,6 +161,7 @@ struct uart_omap_port {
u32 calc_latency;
struct work_struct qos_work;
struct pinctrl *pins;
+ bool is_suspending;
};
#define to_uart_omap_port(p) ((container_of((p), struct uart_omap_port, port)))
@@ -1289,6 +1290,22 @@ static struct uart_driver serial_omap_reg = {
};
#ifdef CONFIG_PM_SLEEP
+static int serial_omap_prepare(struct device *dev)
+{
+ struct uart_omap_port *up = dev_get_drvdata(dev);
+
+ up->is_suspending = true;
+
+ return 0;
+}
+
+static void serial_omap_complete(struct device *dev)
+{
+ struct uart_omap_port *up = dev_get_drvdata(dev);
+
+ up->is_suspending = false;
+}
+
static int serial_omap_suspend(struct device *dev)
{
struct uart_omap_port *up = dev_get_drvdata(dev);
@@ -1307,7 +1324,10 @@ static int serial_omap_resume(struct device *dev)
return 0;
}
-#endif
+#else
+#define serial_omap_prepare NULL
+#define serial_omap_complete NULL
+#endif /* CONFIG_PM_SLEEP */
static void omap_serial_fill_features_erratas(struct uart_omap_port *up)
{
@@ -1596,6 +1616,16 @@ static int serial_omap_runtime_suspend(struct device *dev)
if (!up)
return -EINVAL;
+ /*
+ * When using 'no_console_suspend', the console UART must not be
+ * suspended. Since driver suspend is managed by runtime suspend,
+ * preventing runtime suspend (by returning error) will keep device
+ * active during suspend.
+ */
+ if (up->is_suspending && !console_suspend_enabled &&
+ uart_console(&up->port))
+ return -EBUSY;
+
if (!pdata)
return 0;
@@ -1643,6 +1673,8 @@ static const struct dev_pm_ops serial_omap_dev_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(serial_omap_suspend, serial_omap_resume)
SET_RUNTIME_PM_OPS(serial_omap_runtime_suspend,
serial_omap_runtime_resume, NULL)
+ .prepare = serial_omap_prepare,
+ .complete = serial_omap_complete,
};
#if defined(CONFIG_OF)
diff --git a/drivers/tty/serial/samsung.c b/drivers/tty/serial/samsung.c
index 0c8a9fa2be6c..81ebc86a9e23 100644
--- a/drivers/tty/serial/samsung.c
+++ b/drivers/tty/serial/samsung.c
@@ -1811,7 +1811,13 @@ static int __init s3c24xx_serial_modinit(void)
return ret;
}
- return platform_driver_register(&samsung_serial_driver);
+ ret = platform_driver_register(&samsung_serial_driver);
+ if (ret < 0) {
+ pr_err("Failed to register platform driver\n");
+ uart_unregister_driver(&s3c24xx_uart_drv);
+ }
+
+ return ret;
}
static void __exit s3c24xx_serial_modexit(void)
diff --git a/drivers/tty/serial/sc26xx.c b/drivers/tty/serial/sc26xx.c
index c9735680762d..4b1434d53e9d 100644
--- a/drivers/tty/serial/sc26xx.c
+++ b/drivers/tty/serial/sc26xx.c
@@ -696,7 +696,7 @@ static int sc26xx_probe(struct platform_device *dev)
if (err)
goto out_remove_ports;
- dev_set_drvdata(&dev->dev, up);
+ platform_set_drvdata(dev, up);
return 0;
out_remove_ports:
@@ -716,7 +716,7 @@ out_free_port:
static int __exit sc26xx_driver_remove(struct platform_device *dev)
{
- struct uart_sc26xx_port *up = dev_get_drvdata(&dev->dev);
+ struct uart_sc26xx_port *up = platform_get_drvdata(dev);
free_irq(up->port[0].irq, up);
@@ -728,7 +728,6 @@ static int __exit sc26xx_driver_remove(struct platform_device *dev)
kfree(up);
sc26xx_port = NULL;
- dev_set_drvdata(&dev->dev, NULL);
return 0;
}
diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c
index f87dbfd32770..28cdd2829139 100644
--- a/drivers/tty/serial/serial_core.c
+++ b/drivers/tty/serial/serial_core.c
@@ -50,12 +50,6 @@ static struct lock_class_key port_lock_key;
#define HIGH_BITS_OFFSET ((sizeof(long)-sizeof(int))*8)
-#ifdef CONFIG_SERIAL_CORE_CONSOLE
-#define uart_console(port) ((port)->cons && (port)->cons->index == (port)->line)
-#else
-#define uart_console(port) (0)
-#endif
-
static void uart_change_speed(struct tty_struct *tty, struct uart_state *state,
struct ktermios *old_termios);
static void uart_wait_until_sent(struct tty_struct *tty, int timeout);
diff --git a/drivers/tty/serial/sirfsoc_uart.c b/drivers/tty/serial/sirfsoc_uart.c
index 03465b673945..1fd564b8194b 100644
--- a/drivers/tty/serial/sirfsoc_uart.c
+++ b/drivers/tty/serial/sirfsoc_uart.c
@@ -687,9 +687,10 @@ int sirfsoc_uart_probe(struct platform_device *pdev)
if (sirfport->hw_flow_ctrl) {
sirfport->p = pinctrl_get_select_default(&pdev->dev);
- ret = IS_ERR(sirfport->p);
- if (ret)
+ if (IS_ERR(sirfport->p)) {
+ ret = PTR_ERR(sirfport->p);
goto err;
+ }
}
sirfport->clk = clk_get(&pdev->dev, NULL);
diff --git a/drivers/tty/serial/sunhv.c b/drivers/tty/serial/sunhv.c
index ba60708053e0..cf86e729532b 100644
--- a/drivers/tty/serial/sunhv.c
+++ b/drivers/tty/serial/sunhv.c
@@ -577,7 +577,7 @@ static int hv_probe(struct platform_device *op)
if (err)
goto out_remove_port;
- dev_set_drvdata(&op->dev, port);
+ platform_set_drvdata(op, port);
return 0;
@@ -601,7 +601,7 @@ out_free_port:
static int hv_remove(struct platform_device *dev)
{
- struct uart_port *port = dev_get_drvdata(&dev->dev);
+ struct uart_port *port = platform_get_drvdata(dev);
free_irq(port->irq, port);
@@ -612,8 +612,6 @@ static int hv_remove(struct platform_device *dev)
kfree(port);
sunhv_port = NULL;
- dev_set_drvdata(&dev->dev, NULL);
-
return 0;
}
diff --git a/drivers/tty/serial/sunsab.c b/drivers/tty/serial/sunsab.c
index a422c8b55a47..5d6136b2a04a 100644
--- a/drivers/tty/serial/sunsab.c
+++ b/drivers/tty/serial/sunsab.c
@@ -1037,7 +1037,7 @@ static int sab_probe(struct platform_device *op)
if (err)
goto out3;
- dev_set_drvdata(&op->dev, &up[0]);
+ platform_set_drvdata(op, &up[0]);
inst++;
@@ -1059,7 +1059,7 @@ out:
static int sab_remove(struct platform_device *op)
{
- struct uart_sunsab_port *up = dev_get_drvdata(&op->dev);
+ struct uart_sunsab_port *up = platform_get_drvdata(op);
uart_remove_one_port(&sunsab_reg, &up[1].port);
uart_remove_one_port(&sunsab_reg, &up[0].port);
@@ -1070,8 +1070,6 @@ static int sab_remove(struct platform_device *op)
up[0].port.membase,
sizeof(union sab82532_async_regs));
- dev_set_drvdata(&op->dev, NULL);
-
return 0;
}
diff --git a/drivers/tty/serial/sunsu.c b/drivers/tty/serial/sunsu.c
index 0d8465728473..699cc1b5f6aa 100644
--- a/drivers/tty/serial/sunsu.c
+++ b/drivers/tty/serial/sunsu.c
@@ -1454,7 +1454,7 @@ static int su_probe(struct platform_device *op)
kfree(up);
return err;
}
- dev_set_drvdata(&op->dev, up);
+ platform_set_drvdata(op, up);
nr_inst++;
@@ -1483,7 +1483,7 @@ static int su_probe(struct platform_device *op)
if (err)
goto out_unmap;
- dev_set_drvdata(&op->dev, up);
+ platform_set_drvdata(op, up);
nr_inst++;
@@ -1496,7 +1496,7 @@ out_unmap:
static int su_remove(struct platform_device *op)
{
- struct uart_sunsu_port *up = dev_get_drvdata(&op->dev);
+ struct uart_sunsu_port *up = platform_get_drvdata(op);
bool kbdms = false;
if (up->su_type == SU_PORT_MS ||
@@ -1516,8 +1516,6 @@ static int su_remove(struct platform_device *op)
if (kbdms)
kfree(up);
- dev_set_drvdata(&op->dev, NULL);
-
return 0;
}
diff --git a/drivers/tty/serial/sunzilog.c b/drivers/tty/serial/sunzilog.c
index 813ef8eb8eff..135a15203532 100644
--- a/drivers/tty/serial/sunzilog.c
+++ b/drivers/tty/serial/sunzilog.c
@@ -1495,7 +1495,7 @@ static int zs_probe(struct platform_device *op)
kbm_inst++;
}
- dev_set_drvdata(&op->dev, &up[0]);
+ platform_set_drvdata(op, &up[0]);
return 0;
}
@@ -1512,7 +1512,7 @@ static void zs_remove_one(struct uart_sunzilog_port *up)
static int zs_remove(struct platform_device *op)
{
- struct uart_sunzilog_port *up = dev_get_drvdata(&op->dev);
+ struct uart_sunzilog_port *up = platform_get_drvdata(op);
struct zilog_layout __iomem *regs;
zs_remove_one(&up[0]);
@@ -1521,8 +1521,6 @@ static int zs_remove(struct platform_device *op)
regs = sunzilog_chip_regs[up[0].port.line / 2];
of_iounmap(&op->resource[0], regs, sizeof(struct zilog_layout));
- dev_set_drvdata(&op->dev, NULL);
-
return 0;
}
diff --git a/drivers/tty/serial/ucc_uart.c b/drivers/tty/serial/ucc_uart.c
index 7355303dad99..88317482b81f 100644
--- a/drivers/tty/serial/ucc_uart.c
+++ b/drivers/tty/serial/ucc_uart.c
@@ -1451,7 +1451,7 @@ static int ucc_uart_probe(struct platform_device *ofdev)
goto out_np;
}
- dev_set_drvdata(&ofdev->dev, qe_port);
+ platform_set_drvdata(ofdev, qe_port);
dev_info(&ofdev->dev, "UCC%u assigned to /dev/ttyQE%u\n",
qe_port->ucc_num + 1, qe_port->port.line);
@@ -1471,13 +1471,12 @@ out_free:
static int ucc_uart_remove(struct platform_device *ofdev)
{
- struct uart_qe_port *qe_port = dev_get_drvdata(&ofdev->dev);
+ struct uart_qe_port *qe_port = platform_get_drvdata(ofdev);
dev_info(&ofdev->dev, "removing /dev/ttyQE%u\n", qe_port->port.line);
uart_remove_one_port(&ucc_uart_driver, &qe_port->port);
- dev_set_drvdata(&ofdev->dev, NULL);
kfree(qe_port);
return 0;
@@ -1518,9 +1517,11 @@ static int __init ucc_uart_init(void)
}
ret = platform_driver_register(&ucc_uart_of_driver);
- if (ret)
+ if (ret) {
printk(KERN_ERR
"ucc-uart: could not register platform driver\n");
+ uart_unregister_driver(&ucc_uart_driver);
+ }
return ret;
}
diff --git a/drivers/tty/serial/vt8500_serial.c b/drivers/tty/serial/vt8500_serial.c
index 1a8bc2275ea4..48af43de3467 100644
--- a/drivers/tty/serial/vt8500_serial.c
+++ b/drivers/tty/serial/vt8500_serial.c
@@ -648,7 +648,7 @@ static struct platform_driver vt8500_platform_driver = {
.driver = {
.name = "vt8500_serial",
.owner = THIS_MODULE,
- .of_match_table = of_match_ptr(wmt_dt_ids),
+ .of_match_table = wmt_dt_ids,
},
};
diff --git a/drivers/tty/serial/xilinx_uartps.c b/drivers/tty/serial/xilinx_uartps.c
index 4e5c77834c50..6c9174530422 100644
--- a/drivers/tty/serial/xilinx_uartps.c
+++ b/drivers/tty/serial/xilinx_uartps.c
@@ -974,12 +974,11 @@ static int xuartps_probe(struct platform_device *pdev)
port->dev = &pdev->dev;
port->uartclk = clk_get_rate(clk);
port->private_data = clk;
- dev_set_drvdata(&pdev->dev, port);
+ platform_set_drvdata(pdev, port);
rc = uart_add_one_port(&xuartps_uart_driver, port);
if (rc) {
dev_err(&pdev->dev,
"uart_add_one_port() failed; err=%i\n", rc);
- dev_set_drvdata(&pdev->dev, NULL);
return rc;
}
return 0;
@@ -994,46 +993,17 @@ static int xuartps_probe(struct platform_device *pdev)
**/
static int xuartps_remove(struct platform_device *pdev)
{
- struct uart_port *port = dev_get_drvdata(&pdev->dev);
+ struct uart_port *port = platform_get_drvdata(pdev);
struct clk *clk = port->private_data;
int rc;
/* Remove the xuartps port from the serial core */
rc = uart_remove_one_port(&xuartps_uart_driver, port);
- dev_set_drvdata(&pdev->dev, NULL);
port->mapbase = 0;
clk_disable_unprepare(clk);
return rc;
}
-/**
- * xuartps_suspend - suspend event
- * @pdev: Pointer to the platform device structure
- * @state: State of the device
- *
- * Returns 0
- **/
-static int xuartps_suspend(struct platform_device *pdev, pm_message_t state)
-{
- /* Call the API provided in serial_core.c file which handles
- * the suspend.
- */
- uart_suspend_port(&xuartps_uart_driver, &xuartps_port[pdev->id]);
- return 0;
-}
-
-/**
- * xuartps_resume - Resume after a previous suspend
- * @pdev: Pointer to the platform device structure
- *
- * Returns 0
- **/
-static int xuartps_resume(struct platform_device *pdev)
-{
- uart_resume_port(&xuartps_uart_driver, &xuartps_port[pdev->id]);
- return 0;
-}
-
/* Match table for of_platform binding */
static struct of_device_id xuartps_of_match[] = {
{ .compatible = "xlnx,xuartps", },
@@ -1044,8 +1014,6 @@ MODULE_DEVICE_TABLE(of, xuartps_of_match);
static struct platform_driver xuartps_platform_driver = {
.probe = xuartps_probe, /* Probe method */
.remove = xuartps_remove, /* Detach method */
- .suspend = xuartps_suspend, /* Suspend */
- .resume = xuartps_resume, /* Resume after a suspend */
.driver = {
.owner = THIS_MODULE,
.name = XUARTPS_NAME, /* Driver name */
diff --git a/drivers/tty/sysrq.c b/drivers/tty/sysrq.c
index b51c15408ff3..5f68f2cfdfd0 100644
--- a/drivers/tty/sysrq.c
+++ b/drivers/tty/sysrq.c
@@ -932,7 +932,7 @@ static int sysrq_reset_seq_param_set(const char *buffer,
unsigned long val;
int error;
- error = strict_strtoul(buffer, 0, &val);
+ error = kstrtoul(buffer, 0, &val);
if (error < 0)
return error;
diff --git a/drivers/tty/tty_ldsem.c b/drivers/tty/tty_ldsem.c
new file mode 100644
index 000000000000..22fad8ad5ac2
--- /dev/null
+++ b/drivers/tty/tty_ldsem.c
@@ -0,0 +1,453 @@
+/*
+ * Ldisc rw semaphore
+ *
+ * The ldisc semaphore is semantically a rw_semaphore but which enforces
+ * an alternate policy, namely:
+ * 1) Supports lock wait timeouts
+ * 2) Write waiter has priority
+ * 3) Downgrading is not supported
+ *
+ * Implementation notes:
+ * 1) Upper half of semaphore count is a wait count (differs from rwsem
+ * in that rwsem normalizes the upper half to the wait bias)
+ * 2) Lacks overflow checking
+ *
+ * The generic counting was copied and modified from include/asm-generic/rwsem.h
+ * by Paul Mackerras <paulus@samba.org>.
+ *
+ * The scheduling policy was copied and modified from lib/rwsem.c
+ * Written by David Howells (dhowells@redhat.com).
+ *
+ * This implementation incorporates the write lock stealing work of
+ * Michel Lespinasse <walken@google.com>.
+ *
+ * Copyright (C) 2013 Peter Hurley <peter@hurleysoftware.com>
+ *
+ * This file may be redistributed under the terms of the GNU General Public
+ * License v2.
+ */
+
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <linux/atomic.h>
+#include <linux/tty.h>
+#include <linux/sched.h>
+
+
+#ifdef CONFIG_DEBUG_LOCK_ALLOC
+# define __acq(l, s, t, r, c, n, i) \
+ lock_acquire(&(l)->dep_map, s, t, r, c, n, i)
+# define __rel(l, n, i) \
+ lock_release(&(l)->dep_map, n, i)
+# ifdef CONFIG_PROVE_LOCKING
+# define lockdep_acquire(l, s, t, i) __acq(l, s, t, 0, 2, NULL, i)
+# define lockdep_acquire_nest(l, s, t, n, i) __acq(l, s, t, 0, 2, n, i)
+# define lockdep_acquire_read(l, s, t, i) __acq(l, s, t, 1, 2, NULL, i)
+# define lockdep_release(l, n, i) __rel(l, n, i)
+# else
+# define lockdep_acquire(l, s, t, i) __acq(l, s, t, 0, 1, NULL, i)
+# define lockdep_acquire_nest(l, s, t, n, i) __acq(l, s, t, 0, 1, n, i)
+# define lockdep_acquire_read(l, s, t, i) __acq(l, s, t, 1, 1, NULL, i)
+# define lockdep_release(l, n, i) __rel(l, n, i)
+# endif
+#else
+# define lockdep_acquire(l, s, t, i) do { } while (0)
+# define lockdep_acquire_nest(l, s, t, n, i) do { } while (0)
+# define lockdep_acquire_read(l, s, t, i) do { } while (0)
+# define lockdep_release(l, n, i) do { } while (0)
+#endif
+
+#ifdef CONFIG_LOCK_STAT
+# define lock_stat(_lock, stat) lock_##stat(&(_lock)->dep_map, _RET_IP_)
+#else
+# define lock_stat(_lock, stat) do { } while (0)
+#endif
+
+
+#if BITS_PER_LONG == 64
+# define LDSEM_ACTIVE_MASK 0xffffffffL
+#else
+# define LDSEM_ACTIVE_MASK 0x0000ffffL
+#endif
+
+#define LDSEM_UNLOCKED 0L
+#define LDSEM_ACTIVE_BIAS 1L
+#define LDSEM_WAIT_BIAS (-LDSEM_ACTIVE_MASK-1)
+#define LDSEM_READ_BIAS LDSEM_ACTIVE_BIAS
+#define LDSEM_WRITE_BIAS (LDSEM_WAIT_BIAS + LDSEM_ACTIVE_BIAS)
+
+struct ldsem_waiter {
+ struct list_head list;
+ struct task_struct *task;
+};
+
+static inline long ldsem_atomic_update(long delta, struct ld_semaphore *sem)
+{
+ return atomic_long_add_return(delta, (atomic_long_t *)&sem->count);
+}
+
+static inline int ldsem_cmpxchg(long *old, long new, struct ld_semaphore *sem)
+{
+ long tmp = *old;
+ *old = atomic_long_cmpxchg(&sem->count, *old, new);
+ return *old == tmp;
+}
+
+/*
+ * Initialize an ldsem:
+ */
+void __init_ldsem(struct ld_semaphore *sem, const char *name,
+ struct lock_class_key *key)
+{
+#ifdef CONFIG_DEBUG_LOCK_ALLOC
+ /*
+ * Make sure we are not reinitializing a held semaphore:
+ */
+ debug_check_no_locks_freed((void *)sem, sizeof(*sem));
+ lockdep_init_map(&sem->dep_map, name, key, 0);
+#endif
+ sem->count = LDSEM_UNLOCKED;
+ sem->wait_readers = 0;
+ raw_spin_lock_init(&sem->wait_lock);
+ INIT_LIST_HEAD(&sem->read_wait);
+ INIT_LIST_HEAD(&sem->write_wait);
+}
+
+static void __ldsem_wake_readers(struct ld_semaphore *sem)
+{
+ struct ldsem_waiter *waiter, *next;
+ struct task_struct *tsk;
+ long adjust, count;
+
+ /* Try to grant read locks to all readers on the read wait list.
+ * Note the 'active part' of the count is incremented by
+ * the number of readers before waking any processes up.
+ */
+ adjust = sem->wait_readers * (LDSEM_ACTIVE_BIAS - LDSEM_WAIT_BIAS);
+ count = ldsem_atomic_update(adjust, sem);
+ do {
+ if (count > 0)
+ break;
+ if (ldsem_cmpxchg(&count, count - adjust, sem))
+ return;
+ } while (1);
+
+ list_for_each_entry_safe(waiter, next, &sem->read_wait, list) {
+ tsk = waiter->task;
+ smp_mb();
+ waiter->task = NULL;
+ wake_up_process(tsk);
+ put_task_struct(tsk);
+ }
+ INIT_LIST_HEAD(&sem->read_wait);
+ sem->wait_readers = 0;
+}
+
+static inline int writer_trylock(struct ld_semaphore *sem)
+{
+ /* only wake this writer if the active part of the count can be
+ * transitioned from 0 -> 1
+ */
+ long count = ldsem_atomic_update(LDSEM_ACTIVE_BIAS, sem);
+ do {
+ if ((count & LDSEM_ACTIVE_MASK) == LDSEM_ACTIVE_BIAS)
+ return 1;
+ if (ldsem_cmpxchg(&count, count - LDSEM_ACTIVE_BIAS, sem))
+ return 0;
+ } while (1);
+}
+
+static void __ldsem_wake_writer(struct ld_semaphore *sem)
+{
+ struct ldsem_waiter *waiter;
+
+ waiter = list_entry(sem->write_wait.next, struct ldsem_waiter, list);
+ wake_up_process(waiter->task);
+}
+
+/*
+ * handle the lock release when processes blocked on it that can now run
+ * - if we come here from up_xxxx(), then:
+ * - the 'active part' of count (&0x0000ffff) reached 0 (but may have changed)
+ * - the 'waiting part' of count (&0xffff0000) is -ve (and will still be so)
+ * - the spinlock must be held by the caller
+ * - woken process blocks are discarded from the list after having task zeroed
+ */
+static void __ldsem_wake(struct ld_semaphore *sem)
+{
+ if (!list_empty(&sem->write_wait))
+ __ldsem_wake_writer(sem);
+ else if (!list_empty(&sem->read_wait))
+ __ldsem_wake_readers(sem);
+}
+
+static void ldsem_wake(struct ld_semaphore *sem)
+{
+ unsigned long flags;
+
+ raw_spin_lock_irqsave(&sem->wait_lock, flags);
+ __ldsem_wake(sem);
+ raw_spin_unlock_irqrestore(&sem->wait_lock, flags);
+}
+
+/*
+ * wait for the read lock to be granted
+ */
+static struct ld_semaphore __sched *
+down_read_failed(struct ld_semaphore *sem, long count, long timeout)
+{
+ struct ldsem_waiter waiter;
+ struct task_struct *tsk = current;
+ long adjust = -LDSEM_ACTIVE_BIAS + LDSEM_WAIT_BIAS;
+
+ /* set up my own style of waitqueue */
+ raw_spin_lock_irq(&sem->wait_lock);
+
+ /* Try to reverse the lock attempt but if the count has changed
+ * so that reversing fails, check if there are are no waiters,
+ * and early-out if not */
+ do {
+ if (ldsem_cmpxchg(&count, count + adjust, sem))
+ break;
+ if (count > 0) {
+ raw_spin_unlock_irq(&sem->wait_lock);
+ return sem;
+ }
+ } while (1);
+
+ list_add_tail(&waiter.list, &sem->read_wait);
+ sem->wait_readers++;
+
+ waiter.task = tsk;
+ get_task_struct(tsk);
+
+ /* if there are no active locks, wake the new lock owner(s) */
+ if ((count & LDSEM_ACTIVE_MASK) == 0)
+ __ldsem_wake(sem);
+
+ raw_spin_unlock_irq(&sem->wait_lock);
+
+ /* wait to be given the lock */
+ for (;;) {
+ set_task_state(tsk, TASK_UNINTERRUPTIBLE);
+
+ if (!waiter.task)
+ break;
+ if (!timeout)
+ break;
+ timeout = schedule_timeout(timeout);
+ }
+
+ __set_task_state(tsk, TASK_RUNNING);
+
+ if (!timeout) {
+ /* lock timed out but check if this task was just
+ * granted lock ownership - if so, pretend there
+ * was no timeout; otherwise, cleanup lock wait */
+ raw_spin_lock_irq(&sem->wait_lock);
+ if (waiter.task) {
+ ldsem_atomic_update(-LDSEM_WAIT_BIAS, sem);
+ list_del(&waiter.list);
+ raw_spin_unlock_irq(&sem->wait_lock);
+ put_task_struct(waiter.task);
+ return NULL;
+ }
+ raw_spin_unlock_irq(&sem->wait_lock);
+ }
+
+ return sem;
+}
+
+/*
+ * wait for the write lock to be granted
+ */
+static struct ld_semaphore __sched *
+down_write_failed(struct ld_semaphore *sem, long count, long timeout)
+{
+ struct ldsem_waiter waiter;
+ struct task_struct *tsk = current;
+ long adjust = -LDSEM_ACTIVE_BIAS;
+ int locked = 0;
+
+ /* set up my own style of waitqueue */
+ raw_spin_lock_irq(&sem->wait_lock);
+
+ /* Try to reverse the lock attempt but if the count has changed
+ * so that reversing fails, check if the lock is now owned,
+ * and early-out if so */
+ do {
+ if (ldsem_cmpxchg(&count, count + adjust, sem))
+ break;
+ if ((count & LDSEM_ACTIVE_MASK) == LDSEM_ACTIVE_BIAS) {
+ raw_spin_unlock_irq(&sem->wait_lock);
+ return sem;
+ }
+ } while (1);
+
+ list_add_tail(&waiter.list, &sem->write_wait);
+
+ waiter.task = tsk;
+
+ set_task_state(tsk, TASK_UNINTERRUPTIBLE);
+ for (;;) {
+ if (!timeout)
+ break;
+ raw_spin_unlock_irq(&sem->wait_lock);
+ timeout = schedule_timeout(timeout);
+ raw_spin_lock_irq(&sem->wait_lock);
+ set_task_state(tsk, TASK_UNINTERRUPTIBLE);
+ if ((locked = writer_trylock(sem)))
+ break;
+ }
+
+ if (!locked)
+ ldsem_atomic_update(-LDSEM_WAIT_BIAS, sem);
+ list_del(&waiter.list);
+ raw_spin_unlock_irq(&sem->wait_lock);
+
+ __set_task_state(tsk, TASK_RUNNING);
+
+ /* lock wait may have timed out */
+ if (!locked)
+ return NULL;
+ return sem;
+}
+
+
+
+static inline int __ldsem_down_read_nested(struct ld_semaphore *sem,
+ int subclass, long timeout)
+{
+ long count;
+
+ lockdep_acquire_read(sem, subclass, 0, _RET_IP_);
+
+ count = ldsem_atomic_update(LDSEM_READ_BIAS, sem);
+ if (count <= 0) {
+ lock_stat(sem, contended);
+ if (!down_read_failed(sem, count, timeout)) {
+ lockdep_release(sem, 1, _RET_IP_);
+ return 0;
+ }
+ }
+ lock_stat(sem, acquired);
+ return 1;
+}
+
+static inline int __ldsem_down_write_nested(struct ld_semaphore *sem,
+ int subclass, long timeout)
+{
+ long count;
+
+ lockdep_acquire(sem, subclass, 0, _RET_IP_);
+
+ count = ldsem_atomic_update(LDSEM_WRITE_BIAS, sem);
+ if ((count & LDSEM_ACTIVE_MASK) != LDSEM_ACTIVE_BIAS) {
+ lock_stat(sem, contended);
+ if (!down_write_failed(sem, count, timeout)) {
+ lockdep_release(sem, 1, _RET_IP_);
+ return 0;
+ }
+ }
+ lock_stat(sem, acquired);
+ return 1;
+}
+
+
+/*
+ * lock for reading -- returns 1 if successful, 0 if timed out
+ */
+int __sched ldsem_down_read(struct ld_semaphore *sem, long timeout)
+{
+ might_sleep();
+ return __ldsem_down_read_nested(sem, 0, timeout);
+}
+
+/*
+ * trylock for reading -- returns 1 if successful, 0 if contention
+ */
+int ldsem_down_read_trylock(struct ld_semaphore *sem)
+{
+ long count = sem->count;
+
+ while (count >= 0) {
+ if (ldsem_cmpxchg(&count, count + LDSEM_READ_BIAS, sem)) {
+ lockdep_acquire_read(sem, 0, 1, _RET_IP_);
+ lock_stat(sem, acquired);
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/*
+ * lock for writing -- returns 1 if successful, 0 if timed out
+ */
+int __sched ldsem_down_write(struct ld_semaphore *sem, long timeout)
+{
+ might_sleep();
+ return __ldsem_down_write_nested(sem, 0, timeout);
+}
+
+/*
+ * trylock for writing -- returns 1 if successful, 0 if contention
+ */
+int ldsem_down_write_trylock(struct ld_semaphore *sem)
+{
+ long count = sem->count;
+
+ while ((count & LDSEM_ACTIVE_MASK) == 0) {
+ if (ldsem_cmpxchg(&count, count + LDSEM_WRITE_BIAS, sem)) {
+ lockdep_acquire(sem, 0, 1, _RET_IP_);
+ lock_stat(sem, acquired);
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/*
+ * release a read lock
+ */
+void ldsem_up_read(struct ld_semaphore *sem)
+{
+ long count;
+
+ lockdep_release(sem, 1, _RET_IP_);
+
+ count = ldsem_atomic_update(-LDSEM_READ_BIAS, sem);
+ if (count < 0 && (count & LDSEM_ACTIVE_MASK) == 0)
+ ldsem_wake(sem);
+}
+
+/*
+ * release a write lock
+ */
+void ldsem_up_write(struct ld_semaphore *sem)
+{
+ long count;
+
+ lockdep_release(sem, 1, _RET_IP_);
+
+ count = ldsem_atomic_update(-LDSEM_WRITE_BIAS, sem);
+ if (count < 0)
+ ldsem_wake(sem);
+}
+
+
+#ifdef CONFIG_DEBUG_LOCK_ALLOC
+
+int ldsem_down_read_nested(struct ld_semaphore *sem, int subclass, long timeout)
+{
+ might_sleep();
+ return __ldsem_down_read_nested(sem, subclass, timeout);
+}
+
+int ldsem_down_write_nested(struct ld_semaphore *sem, int subclass,
+ long timeout)
+{
+ might_sleep();
+ return __ldsem_down_write_nested(sem, subclass, timeout);
+}
+
+#endif
diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c
index 740202d8a5c4..c677829baa8b 100644
--- a/drivers/tty/vt/vt.c
+++ b/drivers/tty/vt/vt.c
@@ -3086,17 +3086,6 @@ err:
};
-static int bind_con_driver(const struct consw *csw, int first, int last,
- int deflt)
-{
- int ret;
-
- console_lock();
- ret = do_bind_con_driver(csw, first, last, deflt);
- console_unlock();
- return ret;
-}
-
#ifdef CONFIG_VT_HW_CONSOLE_BINDING
static int con_is_graphics(const struct consw *csw, int first, int last)
{
@@ -3114,34 +3103,6 @@ static int con_is_graphics(const struct consw *csw, int first, int last)
return retval;
}
-/**
- * unbind_con_driver - unbind a console driver
- * @csw: pointer to console driver to unregister
- * @first: first in range of consoles that @csw should be unbound from
- * @last: last in range of consoles that @csw should be unbound from
- * @deflt: should next bound console driver be default after @csw is unbound?
- *
- * To unbind a driver from all possible consoles, pass 0 as @first and
- * %MAX_NR_CONSOLES as @last.
- *
- * @deflt controls whether the console that ends up replacing @csw should be
- * the default console.
- *
- * RETURNS:
- * -ENODEV if @csw isn't a registered console driver or can't be unregistered
- * or 0 on success.
- */
-int unbind_con_driver(const struct consw *csw, int first, int last, int deflt)
-{
- int retval;
-
- console_lock();
- retval = do_unbind_con_driver(csw, first, last, deflt);
- console_unlock();
- return retval;
-}
-EXPORT_SYMBOL(unbind_con_driver);
-
/* unlocked version of unbind_con_driver() */
int do_unbind_con_driver(const struct consw *csw, int first, int last, int deflt)
{
@@ -3262,8 +3223,11 @@ static int vt_bind(struct con_driver *con)
if (first == 0 && last == MAX_NR_CONSOLES -1)
deflt = 1;
- if (first != -1)
- bind_con_driver(csw, first, last, deflt);
+ if (first != -1) {
+ console_lock();
+ do_bind_con_driver(csw, first, last, deflt);
+ console_unlock();
+ }
first = -1;
last = -1;
@@ -3301,8 +3265,11 @@ static int vt_unbind(struct con_driver *con)
if (first == 0 && last == MAX_NR_CONSOLES -1)
deflt = 1;
- if (first != -1)
- unbind_con_driver(csw, first, last, deflt);
+ if (first != -1) {
+ console_lock();
+ do_unbind_con_driver(csw, first, last, deflt);
+ console_unlock();
+ }
first = -1;
last = -1;
@@ -3574,29 +3541,9 @@ err:
return retval;
}
-/**
- * register_con_driver - register console driver to console layer
- * @csw: console driver
- * @first: the first console to take over, minimum value is 0
- * @last: the last console to take over, maximum value is MAX_NR_CONSOLES -1
- *
- * DESCRIPTION: This function registers a console driver which can later
- * bind to a range of consoles specified by @first and @last. It will
- * also initialize the console driver by calling con_startup().
- */
-int register_con_driver(const struct consw *csw, int first, int last)
-{
- int retval;
-
- console_lock();
- retval = do_register_con_driver(csw, first, last);
- console_unlock();
- return retval;
-}
-EXPORT_SYMBOL(register_con_driver);
/**
- * unregister_con_driver - unregister console driver from console layer
+ * do_unregister_con_driver - unregister console driver from console layer
* @csw: console driver
*
* DESCRIPTION: All drivers that registers to the console layer must
@@ -3606,17 +3553,6 @@ EXPORT_SYMBOL(register_con_driver);
*
* The driver must unbind first prior to unregistration.
*/
-int unregister_con_driver(const struct consw *csw)
-{
- int retval;
-
- console_lock();
- retval = do_unregister_con_driver(csw);
- console_unlock();
- return retval;
-}
-EXPORT_SYMBOL(unregister_con_driver);
-
int do_unregister_con_driver(const struct consw *csw)
{
int i, retval = -ENODEV;
@@ -3654,7 +3590,7 @@ EXPORT_SYMBOL_GPL(do_unregister_con_driver);
* when a driver wants to take over some existing consoles
* and become default driver for newly opened ones.
*
- * take_over_console is basically a register followed by unbind
+ * do_take_over_console is basically a register followed by unbind
*/
int do_take_over_console(const struct consw *csw, int first, int last, int deflt)
{
@@ -3675,30 +3611,6 @@ int do_take_over_console(const struct consw *csw, int first, int last, int deflt
}
EXPORT_SYMBOL_GPL(do_take_over_console);
-/*
- * If we support more console drivers, this function is used
- * when a driver wants to take over some existing consoles
- * and become default driver for newly opened ones.
- *
- * take_over_console is basically a register followed by unbind
- */
-int take_over_console(const struct consw *csw, int first, int last, int deflt)
-{
- int err;
-
- err = register_con_driver(csw, first, last);
- /*
- * If we get an busy error we still want to bind the console driver
- * and return success, as we may have unbound the console driver
- * but not unregistered it.
- */
- if (err == -EBUSY)
- err = 0;
- if (!err)
- bind_con_driver(csw, first, last, deflt);
-
- return err;
-}
/*
* give_up_console is a wrapper to unregister_con_driver. It will only
@@ -3706,7 +3618,9 @@ int take_over_console(const struct consw *csw, int first, int last, int deflt)
*/
void give_up_console(const struct consw *csw)
{
- unregister_con_driver(csw);
+ console_lock();
+ do_unregister_con_driver(csw);
+ console_unlock();
}
static int __init vtconsole_class_init(void)
@@ -4262,6 +4176,5 @@ EXPORT_SYMBOL(console_blanked);
EXPORT_SYMBOL(vc_cons);
EXPORT_SYMBOL(global_cursor_default);
#ifndef VT_SINGLE_DRIVER
-EXPORT_SYMBOL(take_over_console);
EXPORT_SYMBOL(give_up_console);
#endif