summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/console/console.txt28
-rw-r--r--arch/alpha/kernel/console.c4
-rw-r--r--arch/alpha/kernel/process.c4
-rw-r--r--arch/mips/pci/pci-bcm1480.c4
-rw-r--r--arch/mips/pci/pci-sb1250.c4
-rw-r--r--arch/parisc/kernel/setup.c2
-rw-r--r--drivers/tty/Makefile2
-rw-r--r--drivers/tty/n_tty.c12
-rw-r--r--drivers/tty/serial/altera_uart.c1
-rw-r--r--drivers/tty/serial/amba-pl011.c11
-rw-r--r--drivers/tty/serial/imx.c15
-rw-r--r--drivers/tty/serial/mpc52xx_uart.c10
-rw-r--r--drivers/tty/serial/omap-serial.c34
-rw-r--r--drivers/tty/serial/serial_core.c6
-rw-r--r--drivers/tty/serial/xilinx_uartps.c30
-rw-r--r--drivers/tty/tty_ldsem.c453
-rw-r--r--drivers/tty/vt/vt.c117
-rw-r--r--drivers/usb/misc/sisusbvga/sisusb_con.c18
-rw-r--r--drivers/video/console/fbcon.c35
-rw-r--r--drivers/video/console/mdacon.c8
-rw-r--r--drivers/video/console/newport_con.c9
-rw-r--r--drivers/video/console/sticon.c6
-rw-r--r--include/linux/console.h3
-rw-r--r--include/linux/serial_core.h7
-rw-r--r--include/linux/tty.h2
-rw-r--r--include/linux/tty_ldisc.h46
-rw-r--r--include/linux/vt_kern.h2
27 files changed, 637 insertions, 236 deletions
diff --git a/Documentation/console/console.txt b/Documentation/console/console.txt
index 926cf1b..f93810d 100644
--- a/Documentation/console/console.txt
+++ b/Documentation/console/console.txt
@@ -12,20 +12,20 @@ The second type has to be explicitly loaded and unloaded. This will be called
any time with each driver sharing the console with other drivers including
the system driver. However, modular drivers cannot take over the console
that is currently occupied by another modular driver. (Exception: Drivers that
-call take_over_console() will succeed in the takeover regardless of the type
+call do_take_over_console() will succeed in the takeover regardless of the type
of driver occupying the consoles.) They can only take over the console that is
occupied by the system driver. In the same token, if the modular driver is
released by the console, the system driver will take over.
Modular drivers, from the programmer's point of view, has to call:
- take_over_console() - load and bind driver to console layer
- give_up_console() - unbind and unload driver
+ do_take_over_console() - load and bind driver to console layer
+ give_up_console() - unload driver, it will only work if driver is fully unbond
In newer kernels, the following are also available:
- register_con_driver()
- unregister_con_driver()
+ do_register_con_driver()
+ do_unregister_con_driver()
If sysfs is enabled, the contents of /sys/class/vtconsole can be
examined. This shows the console backends currently registered by the
@@ -94,12 +94,12 @@ for more details).
Notes for developers:
=====================
-take_over_console() is now broken up into:
+do_take_over_console() is now broken up into:
- register_con_driver()
- bind_con_driver() - private function
+ do_register_con_driver()
+ do_bind_con_driver() - private function
-give_up_console() is a wrapper to unregister_con_driver(), and a driver must
+give_up_console() is a wrapper to do_unregister_con_driver(), and a driver must
be fully unbound for this call to succeed. con_is_bound() will check if the
driver is bound or not.
@@ -109,10 +109,10 @@ Guidelines for console driver writers:
In order for binding to and unbinding from the console to properly work,
console drivers must follow these guidelines:
-1. All drivers, except system drivers, must call either register_con_driver()
- or take_over_console(). register_con_driver() will just add the driver to
+1. All drivers, except system drivers, must call either do_register_con_driver()
+ or do_take_over_console(). do_register_con_driver() will just add the driver to
the console's internal list. It won't take over the
- console. take_over_console(), as it name implies, will also take over (or
+ console. do_take_over_console(), as it name implies, will also take over (or
bind to) the console.
2. All resources allocated during con->con_init() must be released in
@@ -128,10 +128,10 @@ console drivers must follow these guidelines:
rebind the driver to the console arrives.
4. Upon exit of the driver, ensure that the driver is totally unbound. If the
- condition is satisfied, then the driver must call unregister_con_driver()
+ condition is satisfied, then the driver must call do_unregister_con_driver()
or give_up_console().
-5. unregister_con_driver() can also be called on conditions which make it
+5. do_unregister_con_driver() can also be called on conditions which make it
impossible for the driver to service console requests. This can happen
with the framebuffer console that suddenly lost all of its drivers.
diff --git a/arch/alpha/kernel/console.c b/arch/alpha/kernel/console.c
index da711e3..6a61dee 100644
--- a/arch/alpha/kernel/console.c
+++ b/arch/alpha/kernel/console.c
@@ -61,7 +61,9 @@ locate_and_init_vga(void *(*sel_func)(void *, void *))
/* Set the VGA hose and init the new console. */
pci_vga_hose = hose;
- take_over_console(&vga_con, 0, MAX_NR_CONSOLES-1, 1);
+ console_lock();
+ do_take_over_console(&vga_con, 0, MAX_NR_CONSOLES-1, 1);
+ console_unlock();
}
void __init
diff --git a/arch/alpha/kernel/process.c b/arch/alpha/kernel/process.c
index ab80a80..f2360a7 100644
--- a/arch/alpha/kernel/process.c
+++ b/arch/alpha/kernel/process.c
@@ -117,7 +117,9 @@ common_shutdown_1(void *generic_ptr)
if (in_interrupt())
irq_exit();
/* This has the effect of resetting the VGA video origin. */
- take_over_console(&dummy_con, 0, MAX_NR_CONSOLES-1, 1);
+ console_lock();
+ do_take_over_console(&dummy_con, 0, MAX_NR_CONSOLES-1, 1);
+ console_unlock();
#endif
pci_restore_srm_config();
set_hae(srm_hae);
diff --git a/arch/mips/pci/pci-bcm1480.c b/arch/mips/pci/pci-bcm1480.c
index e2e69e1..44dd5aa 100644
--- a/arch/mips/pci/pci-bcm1480.c
+++ b/arch/mips/pci/pci-bcm1480.c
@@ -257,7 +257,9 @@ static int __init bcm1480_pcibios_init(void)
register_pci_controller(&bcm1480_controller);
#ifdef CONFIG_VGA_CONSOLE
- take_over_console(&vga_con, 0, MAX_NR_CONSOLES-1, 1);
+ console_lock();
+ do_take_over_console(&vga_con, 0, MAX_NR_CONSOLES-1, 1);
+ console_unlock();
#endif
return 0;
}
diff --git a/arch/mips/pci/pci-sb1250.c b/arch/mips/pci/pci-sb1250.c
index cdefcc4..fc634ae 100644
--- a/arch/mips/pci/pci-sb1250.c
+++ b/arch/mips/pci/pci-sb1250.c
@@ -283,7 +283,9 @@ static int __init sb1250_pcibios_init(void)
register_pci_controller(&sb1250_controller);
#ifdef CONFIG_VGA_CONSOLE
- take_over_console(&vga_con, 0, MAX_NR_CONSOLES - 1, 1);
+ console_lock();
+ do_take_over_console(&vga_con, 0, MAX_NR_CONSOLES - 1, 1);
+ console_unlock();
#endif
return 0;
}
diff --git a/arch/parisc/kernel/setup.c b/arch/parisc/kernel/setup.c
index 76b63e7..60c1ae6 100644
--- a/arch/parisc/kernel/setup.c
+++ b/arch/parisc/kernel/setup.c
@@ -155,7 +155,7 @@ void __init setup_arch(char **cmdline_p)
#endif
#if defined(CONFIG_VT) && defined(CONFIG_DUMMY_CONSOLE)
- conswitchp = &dummy_con; /* we use take_over_console() later ! */
+ conswitchp = &dummy_con; /* we use do_take_over_console() later ! */
#endif
}
diff --git a/drivers/tty/Makefile b/drivers/tty/Makefile
index 6b78399..58ad1c0 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/n_tty.c b/drivers/tty/n_tty.c
index 6c7fe90..cdcdb0e 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/altera_uart.c b/drivers/tty/serial/altera_uart.c
index 13471dd..1d46966 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 e2774f9..ad41319 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/imx.c b/drivers/tty/serial/imx.c
index 147c9e1..72bc1db 100644
--- a/drivers/tty/serial/imx.c
+++ b/drivers/tty/serial/imx.c
@@ -449,6 +449,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 +589,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 +606,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;
}
diff --git a/drivers/tty/serial/mpc52xx_uart.c b/drivers/tty/serial/mpc52xx_uart.c
index f51b280..510fa98 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 */
/* ======================================================================== */
diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c
index f0b9f6b..393a8eb 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_prepare NULL
+#endif /* CONFIG_PM_SLEEP */
static void omap_serial_fill_features_erratas(struct uart_omap_port *up)
{
@@ -1593,6 +1613,16 @@ static int serial_omap_runtime_suspend(struct device *dev)
struct uart_omap_port *up = dev_get_drvdata(dev);
struct omap_uart_port_info *pdata = dev->platform_data;
+ /*
+ * 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 (!up)
return -EINVAL;
@@ -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/serial_core.c b/drivers/tty/serial/serial_core.c
index f87dbfd..28cdd28 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/xilinx_uartps.c b/drivers/tty/serial/xilinx_uartps.c
index 4e5c778..b5f655d 100644
--- a/drivers/tty/serial/xilinx_uartps.c
+++ b/drivers/tty/serial/xilinx_uartps.c
@@ -1006,34 +1006,6 @@ static int xuartps_remove(struct platform_device *pdev)
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 +1016,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/tty_ldsem.c b/drivers/tty/tty_ldsem.c
new file mode 100644
index 0000000..22fad8a
--- /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 740202d..c677829 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
diff --git a/drivers/usb/misc/sisusbvga/sisusb_con.c b/drivers/usb/misc/sisusbvga/sisusb_con.c
index 411e605..a638c4e 100644
--- a/drivers/usb/misc/sisusbvga/sisusb_con.c
+++ b/drivers/usb/misc/sisusbvga/sisusb_con.c
@@ -208,7 +208,7 @@ sisusbcon_init(struct vc_data *c, int init)
struct sisusb_usb_data *sisusb;
int cols, rows;
- /* This is called by take_over_console(),
+ /* This is called by do_take_over_console(),
* ie by us/under our control. It is
* only called after text mode and fonts
* are set up/restored.
@@ -273,7 +273,7 @@ sisusbcon_deinit(struct vc_data *c)
struct sisusb_usb_data *sisusb;
int i;
- /* This is called by take_over_console()
+ /* This is called by do_take_over_console()
* and others, ie not under our control.
*/
@@ -1490,8 +1490,9 @@ sisusb_console_init(struct sisusb_usb_data *sisusb, int first, int last)
mutex_unlock(&sisusb->lock);
/* Now grab the desired console(s) */
- ret = take_over_console(&sisusb_con, first - 1, last - 1, 0);
-
+ console_lock();
+ ret = do_take_over_console(&sisusb_con, first - 1, last - 1, 0);
+ console_unlock();
if (!ret)
sisusb->haveconsole = 1;
else {
@@ -1535,11 +1536,14 @@ sisusb_console_exit(struct sisusb_usb_data *sisusb)
if (sisusb->haveconsole) {
for (i = 0; i < MAX_NR_CONSOLES; i++)
- if (sisusb->havethisconsole[i])
- take_over_console(&sisusb_dummy_con, i, i, 0);
+ if (sisusb->havethisconsole[i]) {
+ console_lock();
+ do_take_over_console(&sisusb_dummy_con, i, i, 0);
+ console_unlock();
/* At this point, con_deinit for all our
- * consoles is executed by take_over_console().
+ * consoles is executed by do_take_over_console().
*/
+ }
sisusb->haveconsole = 0;
}
diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c
index a92783e..d55b337 100644
--- a/drivers/video/console/fbcon.c
+++ b/drivers/video/console/fbcon.c
@@ -556,34 +556,6 @@ static int do_fbcon_takeover(int show_logo)
return err;
}
-static int fbcon_takeover(int show_logo)
-{
- int err, i;
-
- if (!num_registered_fb)
- return -ENODEV;
-
- if (!show_logo)
- logo_shown = FBCON_LOGO_DONTSHOW;
-
- for (i = first_fb_vc; i <= last_fb_vc; i++)
- con2fb_map[i] = info_idx;
-
- err = take_over_console(&fb_con, first_fb_vc, last_fb_vc,
- fbcon_is_default);
-
- if (err) {
- for (i = first_fb_vc; i <= last_fb_vc; i++) {
- con2fb_map[i] = -1;
- }
- info_idx = -1;
- } else {
- fbcon_has_console_bind = 1;
- }
-
- return err;
-}
-
#ifdef MODULE
static void fbcon_prepare_logo(struct vc_data *vc, struct fb_info *info,
int cols, int rows, int new_cols, int new_rows)
@@ -901,7 +873,7 @@ static int set_con2fb_map(int unit, int newidx, int user)
/*
* Low Level Operations
*/
-/* NOTE: fbcon cannot be __init: it may be called from take_over_console later */
+/* NOTE: fbcon cannot be __init: it may be called from do_take_over_console later */
static int var_to_display(struct display *disp,
struct fb_var_screeninfo *var,
struct fb_info *info)
@@ -3543,8 +3515,9 @@ static void fbcon_start(void)
}
}
+ do_fbcon_takeover(0);
console_unlock();
- fbcon_takeover(0);
+
}
}
@@ -3648,8 +3621,8 @@ static void __exit fb_console_exit(void)
fbcon_deinit_device();
device_destroy(fb_class, MKDEV(0, 0));
fbcon_exit();
+ do_unregister_con_driver(&fb_con);
console_unlock();
- unregister_con_driver(&fb_con);
}
module_exit(fb_console_exit);
diff --git a/drivers/video/console/mdacon.c b/drivers/video/console/mdacon.c
index 0b67866..296e945 100644
--- a/drivers/video/console/mdacon.c
+++ b/drivers/video/console/mdacon.c
@@ -585,10 +585,14 @@ static const struct consw mda_con = {
int __init mda_console_init(void)
{
+ int err;
+
if (mda_first_vc > mda_last_vc)
return 1;
-
- return take_over_console(&mda_con, mda_first_vc-1, mda_last_vc-1, 0);
+ console_lock();
+ err = do_take_over_console(&mda_con, mda_first_vc-1, mda_last_vc-1, 0);
+ console_unlock();
+ return err;
}
static void __exit mda_console_exit(void)
diff --git a/drivers/video/console/newport_con.c b/drivers/video/console/newport_con.c
index b05afd0..a6ab929 100644
--- a/drivers/video/console/newport_con.c
+++ b/drivers/video/console/newport_con.c
@@ -297,7 +297,7 @@ static void newport_exit(void)
newport_set_def_font(i, NULL);
}
-/* Can't be __init, take_over_console may call it later */
+/* Can't be __init, do_take_over_console may call it later */
static const char *newport_startup(void)
{
int i;
@@ -746,6 +746,7 @@ static int newport_probe(struct gio_device *dev,
const struct gio_device_id *id)
{
unsigned long newport_addr;
+ int err;
if (!dev->resource.start)
return -EINVAL;
@@ -759,8 +760,10 @@ static int newport_probe(struct gio_device *dev,
npregs = (struct newport_regs *)/* ioremap cannot fail */
ioremap(newport_addr, sizeof(struct newport_regs));
-
- return take_over_console(&newport_con, 0, MAX_NR_CONSOLES - 1, 1);
+ console_lock();
+ err = do_take_over_console(&newport_con, 0, MAX_NR_CONSOLES - 1, 1);
+ console_unlock();
+ return err;
}
static void newport_remove(struct gio_device *dev)
diff --git a/drivers/video/console/sticon.c b/drivers/video/console/sticon.c
index 491c1c1..5f65ca3 100644
--- a/drivers/video/console/sticon.c
+++ b/drivers/video/console/sticon.c
@@ -372,6 +372,7 @@ static const struct consw sti_con = {
static int __init sticonsole_init(void)
{
+ int err;
/* already initialized ? */
if (sticon_sti)
return 0;
@@ -382,7 +383,10 @@ static int __init sticonsole_init(void)
if (conswitchp == &dummy_con) {
printk(KERN_INFO "sticon: Initializing STI text console.\n");
- return take_over_console(&sti_con, 0, MAX_NR_CONSOLES - 1, 1);
+ console_lock();
+ err = do_take_over_console(&sti_con, 0, MAX_NR_CONSOLES - 1, 1);
+ console_unlock();
+ return err;
}
return 0;
}
diff --git a/include/linux/console.h b/include/linux/console.h
index 73bab0f..7571a16 100644
--- a/include/linux/console.h
+++ b/include/linux/console.h
@@ -75,10 +75,7 @@ extern const struct consw newport_con; /* SGI Newport console */
extern const struct consw prom_con; /* SPARC PROM console */
int con_is_bound(const struct consw *csw);
-int register_con_driver(const struct consw *csw, int first, int last);
-int unregister_con_driver(const struct consw *csw);
int do_unregister_con_driver(const struct consw *csw);
-int take_over_console(const struct consw *sw, int first, int last, int deflt);
int do_take_over_console(const struct consw *sw, int first, int last, int deflt);
void give_up_console(const struct consw *sw);
#ifdef CONFIG_HW_CONSOLE
diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h
index 87d4bbc..b98291a 100644
--- a/include/linux/serial_core.h
+++ b/include/linux/serial_core.h
@@ -31,6 +31,13 @@
#include <linux/sysrq.h>
#include <uapi/linux/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
+
struct uart_port;
struct serial_struct;
struct device;
diff --git a/include/linux/tty.h b/include/linux/tty.h
index 8780bd2..82ab69b 100644
--- a/include/linux/tty.h
+++ b/include/linux/tty.h
@@ -309,8 +309,6 @@ struct tty_file_private {
#define TTY_LDISC 9 /* Line discipline attached */
#define TTY_LDISC_CHANGING 10 /* Line discipline changing */
#define TTY_LDISC_OPEN 11 /* Line discipline is open */
-#define TTY_HW_COOK_OUT 14 /* Hardware can do output cooking */
-#define TTY_HW_COOK_IN 15 /* Hardware can do input cooking */
#define TTY_PTY_LOCK 16 /* pty private */
#define TTY_NO_WRITE_SPLIT 17 /* Preserve write boundaries to driver */
#define TTY_HUPPED 18 /* Post driver->hangup() */
diff --git a/include/linux/tty_ldisc.h b/include/linux/tty_ldisc.h
index 58390c7..7b24bbd 100644
--- a/include/linux/tty_ldisc.h
+++ b/include/linux/tty_ldisc.h
@@ -110,6 +110,52 @@
#include <linux/wait.h>
#include <linux/wait.h>
+
+/*
+ * the semaphore definition
+ */
+struct ld_semaphore {
+ long count;
+ raw_spinlock_t wait_lock;
+ unsigned int wait_readers;
+ struct list_head read_wait;
+ struct list_head write_wait;
+#ifdef CONFIG_DEBUG_LOCK_ALLOC
+ struct lockdep_map dep_map;
+#endif
+};
+
+extern void __init_ldsem(struct ld_semaphore *sem, const char *name,
+ struct lock_class_key *key);
+
+#define init_ldsem(sem) \
+do { \
+ static struct lock_class_key __key; \
+ \
+ __init_ldsem((sem), #sem, &__key); \
+} while (0)
+
+
+extern int ldsem_down_read(struct ld_semaphore *sem, long timeout);
+extern int ldsem_down_read_trylock(struct ld_semaphore *sem);
+extern int ldsem_down_write(struct ld_semaphore *sem, long timeout);
+extern int ldsem_down_write_trylock(struct ld_semaphore *sem);
+extern void ldsem_up_read(struct ld_semaphore *sem);
+extern void ldsem_up_write(struct ld_semaphore *sem);
+
+#ifdef CONFIG_DEBUG_LOCK_ALLOC
+extern int ldsem_down_read_nested(struct ld_semaphore *sem, int subclass,
+ long timeout);
+extern int ldsem_down_write_nested(struct ld_semaphore *sem, int subclass,
+ long timeout);
+#else
+# define ldsem_down_read_nested(sem, subclass, timeout) \
+ ldsem_down_read(sem, timeout)
+# define ldsem_down_write_nested(sem, subclass, timeout) \
+ ldsem_down_write(sem, timeout)
+#endif
+
+
struct tty_ldisc_ops {
int magic;
char *name;
diff --git a/include/linux/vt_kern.h b/include/linux/vt_kern.h
index 0d33fca..8d76342 100644
--- a/include/linux/vt_kern.h
+++ b/include/linux/vt_kern.h
@@ -133,8 +133,6 @@ void change_console(struct vc_data *new_vc);
void reset_vc(struct vc_data *vc);
extern int do_unbind_con_driver(const struct consw *csw, int first, int last,
int deflt);
-extern int unbind_con_driver(const struct consw *csw, int first, int last,
- int deflt);
int vty_init(const struct file_operations *console_fops);
static inline bool vt_force_oops_output(struct vc_data *vc)