Commit a448f0d8 authored by Alexander Viro's avatar Alexander Viro Committed by Christoph Hellwig

[PATCH] tty cleanups (12/12)

	* we allow tty_driver to cover more than 256 devices
	* pty.c cleaned up - now we only one driver for UNIX98 masters and
only one driver for UNIX98 slaves, so a lot of ugliness can be killed.
	* get_tty_driver() became an analog of get_gendisk() - it does
a lookup by device number and gives (pointer to tty_driver,index).
	* registration/unregistration of tty_driver updated
	* /proc/tty/drivers code updated (now one structure can be responsible
for several lines)
parent 2b4107a8
......@@ -52,16 +52,16 @@ static struct pty_struct pty_state[NR_PTYS];
#ifdef CONFIG_UNIX98_PTYS
/* These are global because they are accessed in tty_io.c */
struct tty_driver ptm_driver[UNIX98_NR_MAJORS];
struct tty_driver pts_driver[UNIX98_NR_MAJORS];
static struct tty_struct *ptm_table[UNIX98_NR_MAJORS][NR_PTYS];
static struct termios *ptm_termios[UNIX98_NR_MAJORS][NR_PTYS];
static struct termios *ptm_termios_locked[UNIX98_NR_MAJORS][NR_PTYS];
static struct tty_struct *pts_table[UNIX98_NR_MAJORS][NR_PTYS];
static struct termios *pts_termios[UNIX98_NR_MAJORS][NR_PTYS];
static struct termios *pts_termios_locked[UNIX98_NR_MAJORS][NR_PTYS];
static struct pty_struct ptm_state[UNIX98_NR_MAJORS][NR_PTYS];
struct tty_driver ptm_driver;
struct tty_driver pts_driver;
static struct tty_struct *ptm_table[UNIX98_NR_MAJORS*NR_PTYS];
static struct termios *ptm_termios[UNIX98_NR_MAJORS*NR_PTYS];
static struct termios *ptm_termios_locked[UNIX98_NR_MAJORS*NR_PTYS];
static struct tty_struct *pts_table[UNIX98_NR_MAJORS*NR_PTYS];
static struct termios *pts_termios[UNIX98_NR_MAJORS*NR_PTYS];
static struct termios *pts_termios_locked[UNIX98_NR_MAJORS*NR_PTYS];
static struct pty_struct ptm_state[UNIX98_NR_MAJORS*NR_PTYS];
#endif
static void pty_close(struct tty_struct * tty, struct file * filp)
......@@ -87,12 +87,8 @@ static void pty_close(struct tty_struct * tty, struct file * filp)
if (tty->driver->subtype == PTY_TYPE_MASTER) {
set_bit(TTY_OTHER_CLOSED, &tty->flags);
#ifdef CONFIG_UNIX98_PTYS
{
unsigned int major = MAJOR(tty->device) - UNIX98_PTY_MASTER_MAJOR;
if ( major < UNIX98_NR_MAJORS ) {
devpts_pty_kill( tty->index + tty->driver->name_base );
}
}
if (tty->driver == &ptm_driver)
devpts_pty_kill(tty->index);
#endif
tty_vhangup(tty->link);
}
......@@ -237,7 +233,7 @@ static int pty_chars_in_buffer(struct tty_struct *tty)
#ifdef CONFIG_UNIX98_PTYS
static int pty_get_device_number(struct tty_struct *tty, unsigned int *value)
{
unsigned int result = tty->index + tty->driver->name_base;
unsigned int result = tty->index;
return put_user(result, value);
}
#endif
......@@ -312,8 +308,6 @@ static int pty_open(struct tty_struct *tty, struct file * filp)
if (!tty || !tty->link)
goto out;
line = tty->index;
if ((line < 0) || (line >= NR_PTYS))
goto out;
pty = (struct pty_struct *)(tty->driver->driver_state) + line;
tty->driver_data = pty;
......@@ -424,49 +418,41 @@ int __init pty_init(void)
#ifdef CONFIG_UNIX98_PTYS
devfs_mk_dir("pts");
printk("pty: %d Unix98 ptys configured\n", UNIX98_NR_MAJORS*NR_PTYS);
for ( i = 0 ; i < UNIX98_NR_MAJORS ; i++ ) {
int j;
ptm_driver[i] = pty_driver;
ptm_driver[i].name = "ptm";
ptm_driver[i].proc_entry = 0;
ptm_driver[i].major = UNIX98_PTY_MASTER_MAJOR+i;
ptm_driver[i].minor_start = 0;
ptm_driver[i].name_base = i*NR_PTYS;
ptm_driver[i].num = NR_PTYS;
ptm_driver[i].other = &pts_driver[i];
ptm_driver[i].flags |= TTY_DRIVER_NO_DEVFS;
ptm_driver[i].table = ptm_table[i];
ptm_driver[i].termios = ptm_termios[i];
ptm_driver[i].termios_locked = ptm_termios_locked[i];
ptm_driver[i].driver_state = ptm_state[i];
for (j = 0; j < NR_PTYS; j++)
init_waitqueue_head(&ptm_state[i][j].open_wait);
pts_driver[i] = pty_slave_driver;
pts_driver[i].name = "pts";
pts_driver[i].proc_entry = 0;
pts_driver[i].major = UNIX98_PTY_SLAVE_MAJOR+i;
pts_driver[i].minor_start = 0;
pts_driver[i].name_base = i*NR_PTYS;
pts_driver[i].num = ptm_driver[i].num;
pts_driver[i].flags |= TTY_DRIVER_NO_DEVFS;
pts_driver[i].other = &ptm_driver[i];
pts_driver[i].table = pts_table[i];
pts_driver[i].termios = pts_termios[i];
pts_driver[i].termios_locked = pts_termios_locked[i];
pts_driver[i].driver_state = ptm_state[i];
ptm_driver[i].ioctl = pty_unix98_ioctl;
if (tty_register_driver(&ptm_driver[i]))
panic("Couldn't register Unix98 ptm driver major %d",
ptm_driver[i].major);
if (tty_register_driver(&pts_driver[i]))
panic("Couldn't register Unix98 pts driver major %d",
pts_driver[i].major);
}
ptm_driver = pty_driver;
ptm_driver.name = "ptm";
ptm_driver.proc_entry = 0;
ptm_driver.major = UNIX98_PTY_MASTER_MAJOR;
ptm_driver.minor_start = 0;
ptm_driver.num = UNIX98_NR_MAJORS * NR_PTYS;
ptm_driver.other = &pts_driver;
ptm_driver.flags |= TTY_DRIVER_NO_DEVFS;
ptm_driver.table = ptm_table;
ptm_driver.termios = ptm_termios;
ptm_driver.termios_locked = ptm_termios_locked;
ptm_driver.driver_state = ptm_state;
for (i = 0; i < UNIX98_NR_MAJORS*NR_PTYS; i++)
init_waitqueue_head(&ptm_state[i].open_wait);
pts_driver = pty_slave_driver;
pts_driver.name = "pts";
pts_driver.proc_entry = 0;
pts_driver.major = UNIX98_PTY_SLAVE_MAJOR;
pts_driver.minor_start = 0;
pts_driver.num = UNIX98_NR_MAJORS * NR_PTYS;
pts_driver.other = &ptm_driver;
pts_driver.flags |= TTY_DRIVER_NO_DEVFS;
pts_driver.table = pts_table;
pts_driver.termios = pts_termios;
pts_driver.termios_locked = pts_termios_locked;
pts_driver.driver_state = ptm_state;
ptm_driver.ioctl = pty_unix98_ioctl;
if (tty_register_driver(&ptm_driver))
panic("Couldn't register Unix98 ptm driver");
if (tty_register_driver(&pts_driver))
panic("Couldn't register Unix98 pts driver");
#endif
return 0;
}
......@@ -126,8 +126,8 @@ LIST_HEAD(tty_drivers); /* linked list of tty drivers */
struct tty_ldisc ldiscs[NR_LDISCS]; /* line disc dispatch table */
#ifdef CONFIG_UNIX98_PTYS
extern struct tty_driver ptm_driver[]; /* Unix98 pty masters; for /dev/ptmx */
extern struct tty_driver pts_driver[]; /* Unix98 pty slaves; for /dev/ptmx */
extern struct tty_driver ptm_driver; /* Unix98 pty masters; for /dev/ptmx */
extern struct tty_driver pts_driver; /* Unix98 pty slaves; for /dev/ptmx */
#endif
extern void disable_early_printk(void);
......@@ -313,21 +313,15 @@ static int tty_set_ldisc(struct tty_struct *tty, int ldisc)
/*
* This routine returns a tty driver structure, given a device number
*/
struct tty_driver *get_tty_driver(kdev_t device)
struct tty_driver *get_tty_driver(dev_t device, int *index)
{
int major, minor;
struct tty_driver *p;
minor = minor(device);
major = major(device);
list_for_each_entry(p, &tty_drivers, tty_drivers) {
if (p->major != major)
continue;
if (minor < p->minor_start)
continue;
if (minor >= p->minor_start + p->num)
dev_t base = MKDEV(p->major, p->minor_start);
if (device < base || device >= base + p->num)
continue;
*index = device - base;
return p;
}
return NULL;
......@@ -1345,32 +1339,24 @@ static int tty_open(struct inode * inode, struct file * filp)
if (IS_PTMX_DEV(device)) {
#ifdef CONFIG_UNIX98_PTYS
/* find a free pty. */
int major;
/* find a device that is not in use. */
retval = -1;
for (major = 0 ; major < UNIX98_NR_MAJORS ; major++) {
driver = &ptm_driver[major];
for (index = 0; index < driver->num ; index++)
if (!init_dev(driver, index, &tty))
goto ptmx_found; /* ok! */
}
}
driver = &ptm_driver;
for (index = 0; index < driver->num ; index++)
if (!init_dev(driver, index, &tty))
goto ptmx_found; /* ok! */
return -EIO; /* no free ptys */
ptmx_found:
set_bit(TTY_PTY_LOCK, &tty->flags); /* LOCK THE SLAVE */
devpts_pty_new(driver->other->name_base + index, MKDEV(driver->other->major, index + driver->other->minor_start));
devpts_pty_new(index, MKDEV(pts_driver.major, pts_driver.minor_start) + index);
noctty = 1;
#else
return -ENODEV;
#endif /* CONFIG_UNIX_98_PTYS */
} else {
driver = get_tty_driver(device);
driver = get_tty_driver(kdev_t_to_nr(device), &index);
if (!driver)
return -ENODEV;
index = minor(device) - driver->minor_start;
retval = init_dev(driver, index, &tty);
if (retval)
......@@ -2094,21 +2080,18 @@ static void tty_default_put_char(struct tty_struct *tty, unsigned char ch)
#ifdef CONFIG_DEVFS_FS
static void tty_register_devfs(struct tty_driver *driver, unsigned index)
{
umode_t mode = S_IFCHR | S_IRUSR | S_IWUSR;
unsigned minor = driver->minor_start + index;
kdev_t dev = mk_kdev(driver->major, minor);
dev_t dev = MKDEV(driver->major, driver->minor_start) + index;
char buf[32];
if ((minor < driver->minor_start) ||
(minor >= driver->minor_start + driver->num)) {
printk(KERN_ERR "Attempt to register invalid minor number "
"with devfs (%d:%d).\n", (int)driver->major,(int)minor);
if (index >= driver->num) {
printk(KERN_ERR "Attempt to register invalid tty line number "
"with devfs (%d).\n", index);
return;
}
tty_line_name(driver, index, buf);
devfs_register(NULL, buf, 0, driver->major, minor, mode,
&tty_fops, NULL);
devfs_register(NULL, buf, 0, MAJOR(dev), MINOR(dev),
S_IFCHR | S_IRUSR | S_IWUSR, &tty_fops, NULL);
}
static void tty_unregister_devfs(struct tty_driver *driver, int index)
......@@ -2138,6 +2121,53 @@ void tty_unregister_device(struct tty_driver *driver, unsigned index)
EXPORT_SYMBOL(tty_register_device);
EXPORT_SYMBOL(tty_unregister_device);
/* that should be handled by register_chrdev_region() */
static int get_range(struct tty_driver *driver)
{
dev_t from = MKDEV(driver->major, driver->minor_start);
dev_t to = from + driver->num;
dev_t n, next;
int error = 0;
for (n = from; MAJOR(n) < MAJOR(to); n = next) {
next = MKDEV(MAJOR(n)+1, 0);
error = register_chrdev_region(MAJOR(n), MINOR(n),
next - n, driver->name, &tty_fops);
if (error)
goto fail;
}
if (n != to)
error = register_chrdev_region(MAJOR(n), MINOR(n),
to - n, driver->name, &tty_fops);
if (!error)
return 0;
fail:
to = n;
for (n = from; MAJOR(n) < MAJOR(to); n = next) {
next = MKDEV(MAJOR(n)+1, 0);
unregister_chrdev_region(MAJOR(n), MINOR(n),
next - n, driver->name);
}
return error;
}
/* that should be handled by unregister_chrdev_region() */
static void put_range(struct tty_driver *driver)
{
dev_t from = MKDEV(driver->major, driver->minor_start);
dev_t to = from + driver->num;
dev_t n, next;
for (n = from; MAJOR(n) < MAJOR(to); n = next) {
next = MKDEV(MAJOR(n)+1, 0);
unregister_chrdev_region(MAJOR(n), MINOR(n),
next - n, driver->name);
}
if (n != to)
unregister_chrdev_region(MAJOR(n), MINOR(n),
to - n, driver->name);
}
/*
* Called by a tty driver to register itself.
*/
......@@ -2149,12 +2179,16 @@ int tty_register_driver(struct tty_driver *driver)
if (driver->flags & TTY_DRIVER_INSTALLED)
return 0;
error = register_chrdev_region(driver->major, driver->minor_start,
if (!driver->major) {
error = register_chrdev_region(0, driver->minor_start,
driver->num, driver->name, &tty_fops);
if (error > 0)
driver->major = error;
} else {
error = get_range(driver);
}
if (error < 0)
return error;
else if(driver->major == 0)
driver->major = error;
if (!driver->put_char)
driver->put_char = tty_default_put_char;
......@@ -2174,16 +2208,13 @@ int tty_register_driver(struct tty_driver *driver)
*/
int tty_unregister_driver(struct tty_driver *driver)
{
int retval, i;
int i;
struct termios *tp;
if (*driver->refcount)
return -EBUSY;
retval = unregister_chrdev_region(driver->major, driver->minor_start,
driver->num, driver->name);
if (retval)
return retval;
put_range(driver);
list_del(&driver->tty_drivers);
......
......@@ -1182,7 +1182,6 @@ tty3215_init(void)
tty3215_driver.owner = THIS_MODULE;
tty3215_driver.driver_name = "tty3215";
tty3215_driver.name = "ttyS";
tty3215_driver.name_base = 0;
tty3215_driver.major = TTY_MAJOR;
tty3215_driver.minor_start = 64;
tty3215_driver.num = NR_3215;
......
......@@ -761,7 +761,6 @@ sclp_tty_init(void)
sclp_tty_driver.owner = THIS_MODULE;
sclp_tty_driver.driver_name = "sclp_line";
sclp_tty_driver.name = "ttyS";
sclp_tty_driver.name_base = 0;
sclp_tty_driver.major = TTY_MAJOR;
sclp_tty_driver.minor_start = 64;
sclp_tty_driver.num = 1;
......
......@@ -29,39 +29,18 @@ static struct proc_dir_entry *proc_tty_ldisc, *proc_tty_driver;
/*
* This is the handler for /proc/tty/drivers
*/
static int show_tty_driver(struct seq_file *m, void *v)
static void show_tty_range(struct seq_file *m, struct tty_driver *p,
dev_t from, int num)
{
struct tty_driver *p = v;
if (&p->tty_drivers == tty_drivers.next) {
/* pseudo-drivers first */
seq_printf(m, "%-20s /dev/%-8s ", "/dev/tty", "tty");
seq_printf(m, "%3d %7d ", TTYAUX_MAJOR, 0);
seq_printf(m, "system:/dev/tty\n");
seq_printf(m, "%-20s /dev/%-8s ", "/dev/console", "console");
seq_printf(m, "%3d %7d ", TTYAUX_MAJOR, 1);
seq_printf(m, "system:console\n");
#ifdef CONFIG_UNIX98_PTYS
seq_printf(m, "%-20s /dev/%-8s ", "/dev/ptmx", "ptmx");
seq_printf(m, "%3d %7d ", TTYAUX_MAJOR, 2);
seq_printf(m, "system\n");
#endif
#ifdef CONFIG_VT
seq_printf(m, "%-20s /dev/%-8s ", "/dev/vc/0", "vc/0");
seq_printf(m, "%3d %7d ", TTY_MAJOR, 0);
seq_printf(m, "system:vtmaster\n");
#endif
}
seq_printf(m, "%-20s ", p->driver_name ? p->driver_name : "unknown");
seq_printf(m, "/dev/%-8s ", p->name);
if (p->num > 1) {
char range[20];
sprintf(range, "%d-%d", p->minor_start,
p->minor_start + p->num - 1);
seq_printf(m, "%3d %7s ", p->major, range);
sprintf(range, "%d-%d", MINOR(from),
MINOR(from) + num - 1);
seq_printf(m, "%3d %7s ", MAJOR(from), range);
} else {
seq_printf(m, "%3d %7d ", p->major, p->minor_start);
seq_printf(m, "%3d %7d ", MAJOR(from), MINOR(from));
}
switch (p->type) {
case TTY_DRIVER_TYPE_SYSTEM:
......@@ -93,6 +72,41 @@ static int show_tty_driver(struct seq_file *m, void *v)
seq_printf(m, "type:%d.%d", p->type, p->subtype);
}
seq_putc(m, '\n');
}
static int show_tty_driver(struct seq_file *m, void *v)
{
struct tty_driver *p = v;
dev_t from = MKDEV(p->major, p->minor_start);
dev_t to = from + p->num;
if (&p->tty_drivers == tty_drivers.next) {
/* pseudo-drivers first */
seq_printf(m, "%-20s /dev/%-8s ", "/dev/tty", "tty");
seq_printf(m, "%3d %7d ", TTYAUX_MAJOR, 0);
seq_printf(m, "system:/dev/tty\n");
seq_printf(m, "%-20s /dev/%-8s ", "/dev/console", "console");
seq_printf(m, "%3d %7d ", TTYAUX_MAJOR, 1);
seq_printf(m, "system:console\n");
#ifdef CONFIG_UNIX98_PTYS
seq_printf(m, "%-20s /dev/%-8s ", "/dev/ptmx", "ptmx");
seq_printf(m, "%3d %7d ", TTYAUX_MAJOR, 2);
seq_printf(m, "system\n");
#endif
#ifdef CONFIG_VT
seq_printf(m, "%-20s /dev/%-8s ", "/dev/vc/0", "vc/0");
seq_printf(m, "%3d %7d ", TTY_MAJOR, 0);
seq_printf(m, "system:vtmaster\n");
#endif
}
while (MAJOR(from) < MAJOR(to)) {
dev_t next = MKDEV(MAJOR(from)+1, 0);
show_tty_range(m, p, from, next - from);
from = next;
}
if (from != to)
show_tty_range(m, p, from, to - from);
return 0;
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment