tty: Remove more special casing and out of place code

Carry on pushing code out of tty_io when it belongs to other drivers. I'm
not 100% happy with some of this and it will be worth revisiting some of the
exports later when the restructuring work is done.

Signed-off-by: Alan Cox <alan@redhat.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
Alan Cox 2008-10-13 10:41:42 +01:00 committed by Linus Torvalds
parent feebed6515
commit d81ed10307
6 changed files with 195 additions and 156 deletions

View file

@ -23,6 +23,7 @@
#include <linux/mm.h> #include <linux/mm.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/sysctl.h> #include <linux/sysctl.h>
#include <linux/device.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <asm/system.h> #include <asm/system.h>
@ -332,6 +333,8 @@ int pty_limit = NR_UNIX98_PTY_DEFAULT;
static int pty_limit_min = 0; static int pty_limit_min = 0;
static int pty_limit_max = NR_UNIX98_PTY_MAX; static int pty_limit_max = NR_UNIX98_PTY_MAX;
static struct cdev ptmx_cdev;
static struct ctl_table pty_table[] = { static struct ctl_table pty_table[] = {
{ {
.ctl_name = PTY_MAX, .ctl_name = PTY_MAX,
@ -408,6 +411,70 @@ static const struct tty_operations ptm_unix98_ops = {
.shutdown = pty_shutdown .shutdown = pty_shutdown
}; };
/**
* ptmx_open - open a unix 98 pty master
* @inode: inode of device file
* @filp: file pointer to tty
*
* Allocate a unix98 pty master device from the ptmx driver.
*
* Locking: tty_mutex protects the init_dev work. tty->count should
* protect the rest.
* allocated_ptys_lock handles the list of free pty numbers
*/
static int __ptmx_open(struct inode *inode, struct file *filp)
{
struct tty_struct *tty;
int retval;
int index;
nonseekable_open(inode, filp);
/* find a device that is not in use. */
index = devpts_new_index();
if (index < 0)
return index;
mutex_lock(&tty_mutex);
retval = tty_init_dev(ptm_driver, index, &tty, 1);
mutex_unlock(&tty_mutex);
if (retval)
goto out;
set_bit(TTY_PTY_LOCK, &tty->flags); /* LOCK THE SLAVE */
filp->private_data = tty;
file_move(filp, &tty->tty_files);
retval = devpts_pty_new(tty->link);
if (retval)
goto out1;
retval = ptm_driver->ops->open(tty, filp);
if (!retval)
return 0;
out1:
tty_release_dev(filp);
return retval;
out:
devpts_kill_index(index);
return retval;
}
static int ptmx_open(struct inode *inode, struct file *filp)
{
int ret;
lock_kernel();
ret = __ptmx_open(inode, filp);
unlock_kernel();
return ret;
}
static struct file_operations ptmx_fops;
static void __init unix98_pty_init(void) static void __init unix98_pty_init(void)
{ {
ptm_driver = alloc_tty_driver(NR_UNIX98_PTY_MAX); ptm_driver = alloc_tty_driver(NR_UNIX98_PTY_MAX);
@ -459,7 +526,18 @@ static void __init unix98_pty_init(void)
pty_table[1].data = &ptm_driver->refcount; pty_table[1].data = &ptm_driver->refcount;
register_sysctl_table(pty_root_table); register_sysctl_table(pty_root_table);
/* Now create the /dev/ptmx special device */
tty_default_fops(&ptmx_fops);
ptmx_fops.open = ptmx_open;
cdev_init(&ptmx_cdev, &ptmx_fops);
if (cdev_add(&ptmx_cdev, MKDEV(TTYAUX_MAJOR, 2), 1) ||
register_chrdev_region(MKDEV(TTYAUX_MAJOR, 2), 1, "/dev/ptmx") < 0)
panic("Couldn't register /dev/ptmx driver\n");
device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 2), NULL, "ptmx");
} }
#else #else
static inline void unix98_pty_init(void) { } static inline void unix98_pty_init(void) { }
#endif #endif

View file

@ -49,7 +49,7 @@
* implement CONFIG_VT and generalize console device interface. * implement CONFIG_VT and generalize console device interface.
* -- Marko Kohtala <Marko.Kohtala@hut.fi>, March 97 * -- Marko Kohtala <Marko.Kohtala@hut.fi>, March 97
* *
* Rewrote init_dev and release_dev to eliminate races. * Rewrote tty_init_dev and tty_release_dev to eliminate races.
* -- Bill Hawes <whawes@star.net>, June 97 * -- Bill Hawes <whawes@star.net>, June 97
* *
* Added devfs support. * Added devfs support.
@ -136,11 +136,6 @@ LIST_HEAD(tty_drivers); /* linked list of tty drivers */
DEFINE_MUTEX(tty_mutex); DEFINE_MUTEX(tty_mutex);
EXPORT_SYMBOL(tty_mutex); EXPORT_SYMBOL(tty_mutex);
#ifdef CONFIG_UNIX98_PTYS
extern struct tty_driver *ptm_driver; /* Unix98 pty masters; for /dev/ptmx */
static int ptmx_open(struct inode *, struct file *);
#endif
static void initialize_tty_struct(struct tty_struct *tty); static void initialize_tty_struct(struct tty_struct *tty);
static ssize_t tty_read(struct file *, char __user *, size_t, loff_t *); static ssize_t tty_read(struct file *, char __user *, size_t, loff_t *);
@ -425,20 +420,6 @@ static const struct file_operations tty_fops = {
.fasync = tty_fasync, .fasync = tty_fasync,
}; };
#ifdef CONFIG_UNIX98_PTYS
static const struct file_operations ptmx_fops = {
.llseek = no_llseek,
.read = tty_read,
.write = tty_write,
.poll = tty_poll,
.unlocked_ioctl = tty_ioctl,
.compat_ioctl = tty_compat_ioctl,
.open = ptmx_open,
.release = tty_release,
.fasync = tty_fasync,
};
#endif
static const struct file_operations console_fops = { static const struct file_operations console_fops = {
.llseek = no_llseek, .llseek = no_llseek,
.read = tty_read, .read = tty_read,
@ -1224,7 +1205,7 @@ static void tty_line_name(struct tty_driver *driver, int index, char *p)
} }
/** /**
* init_dev - initialise a tty device * tty_init_dev - initialise a tty device
* @driver: tty driver we are opening a device on * @driver: tty driver we are opening a device on
* @idx: device index * @idx: device index
* @ret_tty: returned tty structure * @ret_tty: returned tty structure
@ -1248,7 +1229,7 @@ static void tty_line_name(struct tty_driver *driver, int index, char *p)
* relaxed for the (most common) case of reopening a tty. * relaxed for the (most common) case of reopening a tty.
*/ */
static int init_dev(struct tty_driver *driver, int idx, int tty_init_dev(struct tty_driver *driver, int idx,
struct tty_struct **ret_tty, int first_ok) struct tty_struct **ret_tty, int first_ok)
{ {
struct tty_struct *tty, *o_tty; struct tty_struct *tty, *o_tty;
@ -1269,8 +1250,8 @@ static int init_dev(struct tty_driver *driver, int idx,
goto end_init; goto end_init;
} }
/* /*
* It's safe from now on because init_dev() is called with * It's safe from now on because tty_init_dev() is called with
* tty_mutex held and release_dev() won't change tty->count * tty_mutex held and tty_release_dev() won't change tty->count
* or tty->flags without having to grab tty_mutex * or tty->flags without having to grab tty_mutex
*/ */
if (tty && driver->subtype == PTY_TYPE_MASTER) if (tty && driver->subtype == PTY_TYPE_MASTER)
@ -1449,7 +1430,7 @@ fast_track:
/* FIXME */ /* FIXME */
if (!test_bit(TTY_LDISC, &tty->flags)) if (!test_bit(TTY_LDISC, &tty->flags))
printk(KERN_ERR "init_dev but no ldisc\n"); printk(KERN_ERR "tty_init_dev but no ldisc\n");
success: success:
*ret_tty = tty; *ret_tty = tty;
@ -1476,7 +1457,7 @@ fail_no_mem:
/* call the tty release_tty routine to clean out this slot */ /* call the tty release_tty routine to clean out this slot */
release_mem_out: release_mem_out:
if (printk_ratelimit()) if (printk_ratelimit())
printk(KERN_INFO "init_dev: ldisc open failed, " printk(KERN_INFO "tty_init_dev: ldisc open failed, "
"clearing slot %d\n", idx); "clearing slot %d\n", idx);
release_tty(tty, idx); release_tty(tty, idx);
goto end_init; goto end_init;
@ -1587,7 +1568,7 @@ static void release_tty(struct tty_struct *tty, int idx)
* WSH 09/09/97: rewritten to avoid some nasty race conditions that could * WSH 09/09/97: rewritten to avoid some nasty race conditions that could
* lead to double frees or releasing memory still in use. * lead to double frees or releasing memory still in use.
*/ */
static void release_dev(struct file *filp) void tty_release_dev(struct file *filp)
{ {
struct tty_struct *tty, *o_tty; struct tty_struct *tty, *o_tty;
int pty_master, tty_closing, o_tty_closing, do_sleep; int pty_master, tty_closing, o_tty_closing, do_sleep;
@ -1597,10 +1578,10 @@ static void release_dev(struct file *filp)
tty = (struct tty_struct *)filp->private_data; tty = (struct tty_struct *)filp->private_data;
if (tty_paranoia_check(tty, filp->f_path.dentry->d_inode, if (tty_paranoia_check(tty, filp->f_path.dentry->d_inode,
"release_dev")) "tty_release_dev"))
return; return;
check_tty_count(tty, "release_dev"); check_tty_count(tty, "tty_release_dev");
tty_fasync(-1, filp, 0); tty_fasync(-1, filp, 0);
@ -1612,24 +1593,24 @@ static void release_dev(struct file *filp)
#ifdef TTY_PARANOIA_CHECK #ifdef TTY_PARANOIA_CHECK
if (idx < 0 || idx >= tty->driver->num) { if (idx < 0 || idx >= tty->driver->num) {
printk(KERN_DEBUG "release_dev: bad idx when trying to " printk(KERN_DEBUG "tty_release_dev: bad idx when trying to "
"free (%s)\n", tty->name); "free (%s)\n", tty->name);
return; return;
} }
if (!(tty->driver->flags & TTY_DRIVER_DEVPTS_MEM)) { if (!(tty->driver->flags & TTY_DRIVER_DEVPTS_MEM)) {
if (tty != tty->driver->ttys[idx]) { if (tty != tty->driver->ttys[idx]) {
printk(KERN_DEBUG "release_dev: driver.table[%d] not tty " printk(KERN_DEBUG "tty_release_dev: driver.table[%d] not tty "
"for (%s)\n", idx, tty->name); "for (%s)\n", idx, tty->name);
return; return;
} }
if (tty->termios != tty->driver->termios[idx]) { if (tty->termios != tty->driver->termios[idx]) {
printk(KERN_DEBUG "release_dev: driver.termios[%d] not termios " printk(KERN_DEBUG "tty_release_dev: driver.termios[%d] not termios "
"for (%s)\n", "for (%s)\n",
idx, tty->name); idx, tty->name);
return; return;
} }
if (tty->termios_locked != tty->driver->termios_locked[idx]) { if (tty->termios_locked != tty->driver->termios_locked[idx]) {
printk(KERN_DEBUG "release_dev: driver.termios_locked[%d] not " printk(KERN_DEBUG "tty_release_dev: driver.termios_locked[%d] not "
"termios_locked for (%s)\n", "termios_locked for (%s)\n",
idx, tty->name); idx, tty->name);
return; return;
@ -1638,7 +1619,7 @@ static void release_dev(struct file *filp)
#endif #endif
#ifdef TTY_DEBUG_HANGUP #ifdef TTY_DEBUG_HANGUP
printk(KERN_DEBUG "release_dev of %s (tty count=%d)...", printk(KERN_DEBUG "tty_release_dev of %s (tty count=%d)...",
tty_name(tty, buf), tty->count); tty_name(tty, buf), tty->count);
#endif #endif
@ -1646,26 +1627,26 @@ static void release_dev(struct file *filp)
if (tty->driver->other && if (tty->driver->other &&
!(tty->driver->flags & TTY_DRIVER_DEVPTS_MEM)) { !(tty->driver->flags & TTY_DRIVER_DEVPTS_MEM)) {
if (o_tty != tty->driver->other->ttys[idx]) { if (o_tty != tty->driver->other->ttys[idx]) {
printk(KERN_DEBUG "release_dev: other->table[%d] " printk(KERN_DEBUG "tty_release_dev: other->table[%d] "
"not o_tty for (%s)\n", "not o_tty for (%s)\n",
idx, tty->name); idx, tty->name);
return; return;
} }
if (o_tty->termios != tty->driver->other->termios[idx]) { if (o_tty->termios != tty->driver->other->termios[idx]) {
printk(KERN_DEBUG "release_dev: other->termios[%d] " printk(KERN_DEBUG "tty_release_dev: other->termios[%d] "
"not o_termios for (%s)\n", "not o_termios for (%s)\n",
idx, tty->name); idx, tty->name);
return; return;
} }
if (o_tty->termios_locked != if (o_tty->termios_locked !=
tty->driver->other->termios_locked[idx]) { tty->driver->other->termios_locked[idx]) {
printk(KERN_DEBUG "release_dev: other->termios_locked[" printk(KERN_DEBUG "tty_release_dev: other->termios_locked["
"%d] not o_termios_locked for (%s)\n", "%d] not o_termios_locked for (%s)\n",
idx, tty->name); idx, tty->name);
return; return;
} }
if (o_tty->link != tty) { if (o_tty->link != tty) {
printk(KERN_DEBUG "release_dev: bad pty pointers\n"); printk(KERN_DEBUG "tty_release_dev: bad pty pointers\n");
return; return;
} }
} }
@ -1723,7 +1704,7 @@ static void release_dev(struct file *filp)
if (!do_sleep) if (!do_sleep)
break; break;
printk(KERN_WARNING "release_dev: %s: read/write wait queue " printk(KERN_WARNING "tty_release_dev: %s: read/write wait queue "
"active!\n", tty_name(tty, buf)); "active!\n", tty_name(tty, buf));
mutex_unlock(&tty_mutex); mutex_unlock(&tty_mutex);
schedule(); schedule();
@ -1736,14 +1717,14 @@ static void release_dev(struct file *filp)
*/ */
if (pty_master) { if (pty_master) {
if (--o_tty->count < 0) { if (--o_tty->count < 0) {
printk(KERN_WARNING "release_dev: bad pty slave count " printk(KERN_WARNING "tty_release_dev: bad pty slave count "
"(%d) for %s\n", "(%d) for %s\n",
o_tty->count, tty_name(o_tty, buf)); o_tty->count, tty_name(o_tty, buf));
o_tty->count = 0; o_tty->count = 0;
} }
} }
if (--tty->count < 0) { if (--tty->count < 0) {
printk(KERN_WARNING "release_dev: bad tty->count (%d) for %s\n", printk(KERN_WARNING "tty_release_dev: bad tty->count (%d) for %s\n",
tty->count, tty_name(tty, buf)); tty->count, tty_name(tty, buf));
tty->count = 0; tty->count = 0;
} }
@ -1825,7 +1806,7 @@ static void release_dev(struct file *filp)
* The termios state of a pty is reset on first open so that * The termios state of a pty is reset on first open so that
* settings don't persist across reuse. * settings don't persist across reuse.
* *
* Locking: tty_mutex protects tty, get_tty_driver and init_dev work. * Locking: tty_mutex protects tty, get_tty_driver and tty_init_dev work.
* tty->count should protect the rest. * tty->count should protect the rest.
* ->siglock protects ->signal/->sighand * ->siglock protects ->signal/->sighand
*/ */
@ -1889,7 +1870,7 @@ retry_open:
return -ENODEV; return -ENODEV;
} }
got_driver: got_driver:
retval = init_dev(driver, index, &tty, 0); retval = tty_init_dev(driver, index, &tty, 0);
mutex_unlock(&tty_mutex); mutex_unlock(&tty_mutex);
if (retval) if (retval)
return retval; return retval;
@ -1920,7 +1901,7 @@ got_driver:
printk(KERN_DEBUG "error %d in opening %s...", retval, printk(KERN_DEBUG "error %d in opening %s...", retval,
tty->name); tty->name);
#endif #endif
release_dev(filp); tty_release_dev(filp);
if (retval != -ERESTARTSYS) if (retval != -ERESTARTSYS)
return retval; return retval;
if (signal_pending(current)) if (signal_pending(current))
@ -1959,69 +1940,6 @@ static int tty_open(struct inode *inode, struct file *filp)
#ifdef CONFIG_UNIX98_PTYS
/**
* ptmx_open - open a unix 98 pty master
* @inode: inode of device file
* @filp: file pointer to tty
*
* Allocate a unix98 pty master device from the ptmx driver.
*
* Locking: tty_mutex protects theinit_dev work. tty->count should
* protect the rest.
* allocated_ptys_lock handles the list of free pty numbers
*/
static int __ptmx_open(struct inode *inode, struct file *filp)
{
struct tty_struct *tty;
int retval;
int index;
nonseekable_open(inode, filp);
/* find a device that is not in use. */
index = devpts_new_index();
if (index < 0)
return index;
mutex_lock(&tty_mutex);
retval = init_dev(ptm_driver, index, &tty, 1);
mutex_unlock(&tty_mutex);
if (retval)
goto out;
set_bit(TTY_PTY_LOCK, &tty->flags); /* LOCK THE SLAVE */
filp->private_data = tty;
file_move(filp, &tty->tty_files);
retval = devpts_pty_new(tty->link);
if (retval)
goto out1;
check_tty_count(tty, "ptmx_open");
retval = ptm_driver->ops->open(tty, filp);
if (!retval)
return 0;
out1:
release_dev(filp);
return retval;
out:
devpts_kill_index(index);
return retval;
}
static int ptmx_open(struct inode *inode, struct file *filp)
{
int ret;
lock_kernel();
ret = __ptmx_open(inode, filp);
unlock_kernel();
return ret;
}
#endif
/** /**
* tty_release - vfs callback for close * tty_release - vfs callback for close
@ -2032,13 +1950,13 @@ static int ptmx_open(struct inode *inode, struct file *filp)
* this tty. There may however be several such references. * this tty. There may however be several such references.
* *
* Locking: * Locking:
* Takes bkl. See release_dev * Takes bkl. See tty_release_dev
*/ */
static int tty_release(struct inode *inode, struct file *filp) static int tty_release(struct inode *inode, struct file *filp)
{ {
lock_kernel(); lock_kernel();
release_dev(filp); tty_release_dev(filp);
unlock_kernel(); unlock_kernel();
return 0; return 0;
} }
@ -2932,7 +2850,7 @@ int tty_put_char(struct tty_struct *tty, unsigned char ch)
EXPORT_SYMBOL_GPL(tty_put_char); EXPORT_SYMBOL_GPL(tty_put_char);
static struct class *tty_class; struct class *tty_class;
/** /**
* tty_register_device - register a tty device * tty_register_device - register a tty device
@ -3197,6 +3115,11 @@ struct tty_struct *get_current_tty(void)
} }
EXPORT_SYMBOL_GPL(get_current_tty); EXPORT_SYMBOL_GPL(get_current_tty);
void tty_default_fops(struct file_operations *fops)
{
*fops = tty_fops;
}
/* /*
* Initialize the console device. This is called *early*, so * Initialize the console device. This is called *early*, so
* we can't necessarily depend on lots of kernel help here. * we can't necessarily depend on lots of kernel help here.
@ -3234,12 +3157,6 @@ postcore_initcall(tty_class_init);
/* 3/2004 jmc: why do these devices exist? */ /* 3/2004 jmc: why do these devices exist? */
static struct cdev tty_cdev, console_cdev; static struct cdev tty_cdev, console_cdev;
#ifdef CONFIG_UNIX98_PTYS
static struct cdev ptmx_cdev;
#endif
#ifdef CONFIG_VT
static struct cdev vc0_cdev;
#endif
/* /*
* Ok, now we can initialize the rest of the tty devices and can count * Ok, now we can initialize the rest of the tty devices and can count
@ -3251,32 +3168,18 @@ static int __init tty_init(void)
if (cdev_add(&tty_cdev, MKDEV(TTYAUX_MAJOR, 0), 1) || if (cdev_add(&tty_cdev, MKDEV(TTYAUX_MAJOR, 0), 1) ||
register_chrdev_region(MKDEV(TTYAUX_MAJOR, 0), 1, "/dev/tty") < 0) register_chrdev_region(MKDEV(TTYAUX_MAJOR, 0), 1, "/dev/tty") < 0)
panic("Couldn't register /dev/tty driver\n"); panic("Couldn't register /dev/tty driver\n");
device_create_drvdata(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 0), NULL, device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 0), NULL,
"tty"); "tty");
cdev_init(&console_cdev, &console_fops); cdev_init(&console_cdev, &console_fops);
if (cdev_add(&console_cdev, MKDEV(TTYAUX_MAJOR, 1), 1) || if (cdev_add(&console_cdev, MKDEV(TTYAUX_MAJOR, 1), 1) ||
register_chrdev_region(MKDEV(TTYAUX_MAJOR, 1), 1, "/dev/console") < 0) register_chrdev_region(MKDEV(TTYAUX_MAJOR, 1), 1, "/dev/console") < 0)
panic("Couldn't register /dev/console driver\n"); panic("Couldn't register /dev/console driver\n");
device_create_drvdata(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 1), NULL, device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 1), NULL,
"console"); "console");
#ifdef CONFIG_UNIX98_PTYS
cdev_init(&ptmx_cdev, &ptmx_fops);
if (cdev_add(&ptmx_cdev, MKDEV(TTYAUX_MAJOR, 2), 1) ||
register_chrdev_region(MKDEV(TTYAUX_MAJOR, 2), 1, "/dev/ptmx") < 0)
panic("Couldn't register /dev/ptmx driver\n");
device_create_drvdata(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 2), NULL, "ptmx");
#endif
#ifdef CONFIG_VT #ifdef CONFIG_VT
cdev_init(&vc0_cdev, &console_fops); vty_init(&console_fops);
if (cdev_add(&vc0_cdev, MKDEV(TTY_MAJOR, 0), 1) ||
register_chrdev_region(MKDEV(TTY_MAJOR, 0), 1, "/dev/vc/0") < 0)
panic("Couldn't register /dev/tty0 driver\n");
device_create_drvdata(tty_class, NULL, MKDEV(TTY_MAJOR, 0), NULL, "tty0");
vty_init();
#endif #endif
return 0; return 0;
} }

View file

@ -40,6 +40,15 @@
#define TERMIOS_OLD 8 #define TERMIOS_OLD 8
/**
* tty_chars_in_buffer - characters pending
* @tty: terminal
*
* Return the number of bytes of data in the device private
* output queue. If no private method is supplied there is assumed
* to be no queue on the device.
*/
int tty_chars_in_buffer(struct tty_struct *tty) int tty_chars_in_buffer(struct tty_struct *tty)
{ {
if (tty->ops->chars_in_buffer) if (tty->ops->chars_in_buffer)
@ -47,26 +56,49 @@ int tty_chars_in_buffer(struct tty_struct *tty)
else else
return 0; return 0;
} }
EXPORT_SYMBOL(tty_chars_in_buffer); EXPORT_SYMBOL(tty_chars_in_buffer);
/**
* tty_write_room - write queue space
* @tty: terminal
*
* Return the number of bytes that can be queued to this device
* at the present time. The result should be treated as a guarantee
* and the driver cannot offer a value it later shrinks by more than
* the number of bytes written. If no method is provided 2K is always
* returned and data may be lost as there will be no flow control.
*/
int tty_write_room(struct tty_struct *tty) int tty_write_room(struct tty_struct *tty)
{ {
if (tty->ops->write_room) if (tty->ops->write_room)
return tty->ops->write_room(tty); return tty->ops->write_room(tty);
return 2048; return 2048;
} }
EXPORT_SYMBOL(tty_write_room); EXPORT_SYMBOL(tty_write_room);
/**
* tty_driver_flush_buffer - discard internal buffer
* @tty: terminal
*
* Discard the internal output buffer for this device. If no method
* is provided then either the buffer cannot be hardware flushed or
* there is no buffer driver side.
*/
void tty_driver_flush_buffer(struct tty_struct *tty) void tty_driver_flush_buffer(struct tty_struct *tty)
{ {
if (tty->ops->flush_buffer) if (tty->ops->flush_buffer)
tty->ops->flush_buffer(tty); tty->ops->flush_buffer(tty);
} }
EXPORT_SYMBOL(tty_driver_flush_buffer); EXPORT_SYMBOL(tty_driver_flush_buffer);
/**
* tty_throttle - flow control
* @tty: terminal
*
* Indicate that a tty should stop transmitting data down the stack.
*/
void tty_throttle(struct tty_struct *tty) void tty_throttle(struct tty_struct *tty)
{ {
/* check TTY_THROTTLED first so it indicates our state */ /* check TTY_THROTTLED first so it indicates our state */
@ -76,6 +108,13 @@ void tty_throttle(struct tty_struct *tty)
} }
EXPORT_SYMBOL(tty_throttle); EXPORT_SYMBOL(tty_throttle);
/**
* tty_unthrottle - flow control
* @tty: terminal
*
* Indicate that a tty may continue transmitting data down the stack.
*/
void tty_unthrottle(struct tty_struct *tty) void tty_unthrottle(struct tty_struct *tty)
{ {
if (test_and_clear_bit(TTY_THROTTLED, &tty->flags) && if (test_and_clear_bit(TTY_THROTTLED, &tty->flags) &&
@ -112,6 +151,11 @@ void tty_wait_until_sent(struct tty_struct *tty, long timeout)
} }
EXPORT_SYMBOL(tty_wait_until_sent); EXPORT_SYMBOL(tty_wait_until_sent);
/*
* Termios Helper Methods
*/
static void unset_locked_termios(struct ktermios *termios, static void unset_locked_termios(struct ktermios *termios,
struct ktermios *old, struct ktermios *old,
struct ktermios *locked) struct ktermios *locked)
@ -346,6 +390,16 @@ void tty_termios_encode_baud_rate(struct ktermios *termios,
} }
EXPORT_SYMBOL_GPL(tty_termios_encode_baud_rate); EXPORT_SYMBOL_GPL(tty_termios_encode_baud_rate);
/**
* tty_encode_baud_rate - set baud rate of the tty
* @ibaud: input baud rate
* @obad: output baud rate
*
* Update the current termios data for the tty with the new speed
* settings. The caller must hold the termios_mutex for the tty in
* question.
*/
void tty_encode_baud_rate(struct tty_struct *tty, speed_t ibaud, speed_t obaud) void tty_encode_baud_rate(struct tty_struct *tty, speed_t ibaud, speed_t obaud)
{ {
tty_termios_encode_baud_rate(tty->termios, ibaud, obaud); tty_termios_encode_baud_rate(tty->termios, ibaud, obaud);
@ -430,7 +484,7 @@ EXPORT_SYMBOL(tty_termios_hw_change);
* is a bit of layering violation here with n_tty in terms of the * is a bit of layering violation here with n_tty in terms of the
* internal knowledge of this function. * internal knowledge of this function.
* *
* Locking: termios_sem * Locking: termios_mutex
*/ */
static void change_termios(struct tty_struct *tty, struct ktermios *new_termios) static void change_termios(struct tty_struct *tty, struct ktermios *new_termios)
@ -508,7 +562,7 @@ static void change_termios(struct tty_struct *tty, struct ktermios *new_termios)
* functions before using change_termios to do the actual changes. * functions before using change_termios to do the actual changes.
* *
* Locking: * Locking:
* Called functions take ldisc and termios_sem locks * Called functions take ldisc and termios_mutex locks
*/ */
static int set_termios(struct tty_struct *tty, void __user *arg, int opt) static int set_termios(struct tty_struct *tty, void __user *arg, int opt)
@ -715,7 +769,7 @@ static void set_sgflags(struct ktermios *termios, int flags)
* Updates a terminal from the legacy BSD style terminal information * Updates a terminal from the legacy BSD style terminal information
* structure. * structure.
* *
* Locking: termios_sem * Locking: termios_mutex
*/ */
static int set_sgttyb(struct tty_struct *tty, struct sgttyb __user *sgttyb) static int set_sgttyb(struct tty_struct *tty, struct sgttyb __user *sgttyb)

View file

@ -100,10 +100,10 @@
#include <linux/font.h> #include <linux/font.h>
#include <linux/bitops.h> #include <linux/bitops.h>
#include <linux/notifier.h> #include <linux/notifier.h>
#include <linux/device.h>
#include <asm/io.h> #include <linux/io.h>
#include <asm/system.h> #include <asm/system.h>
#include <asm/uaccess.h> #include <linux/uaccess.h>
#define MAX_NR_CON_DRIVER 16 #define MAX_NR_CON_DRIVER 16
@ -2352,8 +2352,6 @@ rescan_last_byte:
FLUSH FLUSH
console_conditional_schedule(); console_conditional_schedule();
release_console_sem(); release_console_sem();
out:
notify_update(vc); notify_update(vc);
return n; return n;
#undef FLUSH #undef FLUSH
@ -2784,13 +2782,6 @@ static int con_open(struct tty_struct *tty, struct file *filp)
return ret; return ret;
} }
/*
* We take tty_mutex in here to prevent another thread from coming in via init_dev
* and taking a ref against the tty while we're in the process of forgetting
* about it and cleaning things up.
*
* This is because vcs_remove_sysfs() can sleep and will drop the BKL.
*/
static void con_close(struct tty_struct *tty, struct file *filp) static void con_close(struct tty_struct *tty, struct file *filp)
{ {
/* Nothing to do - we defer to shutdown */ /* Nothing to do - we defer to shutdown */
@ -2932,8 +2923,16 @@ static const struct tty_operations con_ops = {
.shutdown = con_shutdown .shutdown = con_shutdown
}; };
int __init vty_init(void) static struct cdev vc0_cdev;
int __init vty_init(const struct file_operations *console_fops)
{ {
cdev_init(&vc0_cdev, console_fops);
if (cdev_add(&vc0_cdev, MKDEV(TTY_MAJOR, 0), 1) ||
register_chrdev_region(MKDEV(TTY_MAJOR, 0), 1, "/dev/vc/0") < 0)
panic("Couldn't register /dev/tty0 driver\n");
device_create(tty_class, NULL, MKDEV(TTY_MAJOR, 0), NULL, "tty0");
vcs_init(); vcs_init();
console_driver = alloc_tty_driver(MAX_NR_CONSOLES); console_driver = alloc_tty_driver(MAX_NR_CONSOLES);
@ -2952,7 +2951,6 @@ int __init vty_init(void)
tty_set_operations(console_driver, &con_ops); tty_set_operations(console_driver, &con_ops);
if (tty_register_driver(console_driver)) if (tty_register_driver(console_driver))
panic("Couldn't register console driver\n"); panic("Couldn't register console driver\n");
kbd_init(); kbd_init();
console_map_init(); console_map_init();
#ifdef CONFIG_PROM_CONSOLE #ifdef CONFIG_PROM_CONSOLE
@ -3446,7 +3444,7 @@ int register_con_driver(const struct consw *csw, int first, int last)
if (retval) if (retval)
goto err; goto err;
con_driver->dev = device_create_drvdata(vtconsole_class, NULL, con_driver->dev = device_create(vtconsole_class, NULL,
MKDEV(0, con_driver->node), MKDEV(0, con_driver->node),
NULL, "vtcon%i", NULL, "vtcon%i",
con_driver->node); con_driver->node);
@ -3557,7 +3555,7 @@ static int __init vtconsole_class_init(void)
struct con_driver *con = &registered_con_driver[i]; struct con_driver *con = &registered_con_driver[i];
if (con->con && !con->dev) { if (con->con && !con->dev) {
con->dev = device_create_drvdata(vtconsole_class, NULL, con->dev = device_create(vtconsole_class, NULL,
MKDEV(0, con->node), MKDEV(0, con->node),
NULL, "vtcon%i", NULL, "vtcon%i",
con->node); con->node);

View file

@ -314,6 +314,8 @@ extern int kmsg_redirect;
extern void console_init(void); extern void console_init(void);
extern int vcs_init(void); extern int vcs_init(void);
extern struct class *tty_class;
/** /**
* tty_kref_get - get a tty reference * tty_kref_get - get a tty reference
* @tty: tty device * @tty: tty device
@ -398,6 +400,10 @@ extern int tty_perform_flush(struct tty_struct *tty, unsigned long arg);
extern dev_t tty_devnum(struct tty_struct *tty); extern dev_t tty_devnum(struct tty_struct *tty);
extern void proc_clear_tty(struct task_struct *p); extern void proc_clear_tty(struct task_struct *p);
extern struct tty_struct *get_current_tty(void); extern struct tty_struct *get_current_tty(void);
extern void tty_default_fops(struct file_operations *fops);
extern int tty_init_dev(struct tty_driver *driver, int idx,
struct tty_struct **ret_tty, int first_ok);
extern void tty_release_dev(struct file *filp);
extern struct mutex tty_mutex; extern struct mutex tty_mutex;

View file

@ -96,7 +96,7 @@ void change_console(struct vc_data *new_vc);
void reset_vc(struct vc_data *vc); void reset_vc(struct vc_data *vc);
extern int unbind_con_driver(const struct consw *csw, int first, int last, extern int unbind_con_driver(const struct consw *csw, int first, int last,
int deflt); int deflt);
int vty_init(void); int vty_init(const struct file_operations *console_fops);
/* /*
* vc_screen.c shares this temporary buffer with the console write code so that * vc_screen.c shares this temporary buffer with the console write code so that