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]; ...@@ -52,16 +52,16 @@ static struct pty_struct pty_state[NR_PTYS];
#ifdef CONFIG_UNIX98_PTYS #ifdef CONFIG_UNIX98_PTYS
/* These are global because they are accessed in tty_io.c */ /* These are global because they are accessed in tty_io.c */
struct tty_driver ptm_driver[UNIX98_NR_MAJORS]; struct tty_driver ptm_driver;
struct tty_driver pts_driver[UNIX98_NR_MAJORS]; struct tty_driver pts_driver;
static struct tty_struct *ptm_table[UNIX98_NR_MAJORS][NR_PTYS]; 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[UNIX98_NR_MAJORS*NR_PTYS];
static struct termios *ptm_termios_locked[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 tty_struct *pts_table[UNIX98_NR_MAJORS*NR_PTYS];
static struct termios *pts_termios[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 termios *pts_termios_locked[UNIX98_NR_MAJORS*NR_PTYS];
static struct pty_struct ptm_state[UNIX98_NR_MAJORS][NR_PTYS]; static struct pty_struct ptm_state[UNIX98_NR_MAJORS*NR_PTYS];
#endif #endif
static void pty_close(struct tty_struct * tty, struct file * filp) 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) ...@@ -87,12 +87,8 @@ static void pty_close(struct tty_struct * tty, struct file * filp)
if (tty->driver->subtype == PTY_TYPE_MASTER) { if (tty->driver->subtype == PTY_TYPE_MASTER) {
set_bit(TTY_OTHER_CLOSED, &tty->flags); set_bit(TTY_OTHER_CLOSED, &tty->flags);
#ifdef CONFIG_UNIX98_PTYS #ifdef CONFIG_UNIX98_PTYS
{ if (tty->driver == &ptm_driver)
unsigned int major = MAJOR(tty->device) - UNIX98_PTY_MASTER_MAJOR; devpts_pty_kill(tty->index);
if ( major < UNIX98_NR_MAJORS ) {
devpts_pty_kill( tty->index + tty->driver->name_base );
}
}
#endif #endif
tty_vhangup(tty->link); tty_vhangup(tty->link);
} }
...@@ -237,7 +233,7 @@ static int pty_chars_in_buffer(struct tty_struct *tty) ...@@ -237,7 +233,7 @@ static int pty_chars_in_buffer(struct tty_struct *tty)
#ifdef CONFIG_UNIX98_PTYS #ifdef CONFIG_UNIX98_PTYS
static int pty_get_device_number(struct tty_struct *tty, unsigned int *value) 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); return put_user(result, value);
} }
#endif #endif
...@@ -312,8 +308,6 @@ static int pty_open(struct tty_struct *tty, struct file * filp) ...@@ -312,8 +308,6 @@ static int pty_open(struct tty_struct *tty, struct file * filp)
if (!tty || !tty->link) if (!tty || !tty->link)
goto out; goto out;
line = tty->index; line = tty->index;
if ((line < 0) || (line >= NR_PTYS))
goto out;
pty = (struct pty_struct *)(tty->driver->driver_state) + line; pty = (struct pty_struct *)(tty->driver->driver_state) + line;
tty->driver_data = pty; tty->driver_data = pty;
...@@ -424,49 +418,41 @@ int __init pty_init(void) ...@@ -424,49 +418,41 @@ int __init pty_init(void)
#ifdef CONFIG_UNIX98_PTYS #ifdef CONFIG_UNIX98_PTYS
devfs_mk_dir("pts"); devfs_mk_dir("pts");
printk("pty: %d Unix98 ptys configured\n", UNIX98_NR_MAJORS*NR_PTYS); printk("pty: %d Unix98 ptys configured\n", UNIX98_NR_MAJORS*NR_PTYS);
for ( i = 0 ; i < UNIX98_NR_MAJORS ; i++ ) { ptm_driver = pty_driver;
int j; ptm_driver.name = "ptm";
ptm_driver.proc_entry = 0;
ptm_driver[i] = pty_driver; ptm_driver.major = UNIX98_PTY_MASTER_MAJOR;
ptm_driver[i].name = "ptm"; ptm_driver.minor_start = 0;
ptm_driver[i].proc_entry = 0; ptm_driver.num = UNIX98_NR_MAJORS * NR_PTYS;
ptm_driver[i].major = UNIX98_PTY_MASTER_MAJOR+i; ptm_driver.other = &pts_driver;
ptm_driver[i].minor_start = 0; ptm_driver.flags |= TTY_DRIVER_NO_DEVFS;
ptm_driver[i].name_base = i*NR_PTYS; ptm_driver.table = ptm_table;
ptm_driver[i].num = NR_PTYS; ptm_driver.termios = ptm_termios;
ptm_driver[i].other = &pts_driver[i]; ptm_driver.termios_locked = ptm_termios_locked;
ptm_driver[i].flags |= TTY_DRIVER_NO_DEVFS; ptm_driver.driver_state = ptm_state;
ptm_driver[i].table = ptm_table[i];
ptm_driver[i].termios = ptm_termios[i]; for (i = 0; i < UNIX98_NR_MAJORS*NR_PTYS; i++)
ptm_driver[i].termios_locked = ptm_termios_locked[i]; init_waitqueue_head(&ptm_state[i].open_wait);
ptm_driver[i].driver_state = ptm_state[i];
pts_driver = pty_slave_driver;
for (j = 0; j < NR_PTYS; j++) pts_driver.name = "pts";
init_waitqueue_head(&ptm_state[i][j].open_wait); pts_driver.proc_entry = 0;
pts_driver.major = UNIX98_PTY_SLAVE_MAJOR;
pts_driver[i] = pty_slave_driver; pts_driver.minor_start = 0;
pts_driver[i].name = "pts"; pts_driver.num = UNIX98_NR_MAJORS * NR_PTYS;
pts_driver[i].proc_entry = 0; pts_driver.other = &ptm_driver;
pts_driver[i].major = UNIX98_PTY_SLAVE_MAJOR+i; pts_driver.flags |= TTY_DRIVER_NO_DEVFS;
pts_driver[i].minor_start = 0; pts_driver.table = pts_table;
pts_driver[i].name_base = i*NR_PTYS; pts_driver.termios = pts_termios;
pts_driver[i].num = ptm_driver[i].num; pts_driver.termios_locked = pts_termios_locked;
pts_driver[i].flags |= TTY_DRIVER_NO_DEVFS; pts_driver.driver_state = ptm_state;
pts_driver[i].other = &ptm_driver[i];
pts_driver[i].table = pts_table[i]; ptm_driver.ioctl = pty_unix98_ioctl;
pts_driver[i].termios = pts_termios[i];
pts_driver[i].termios_locked = pts_termios_locked[i]; if (tty_register_driver(&ptm_driver))
pts_driver[i].driver_state = ptm_state[i]; panic("Couldn't register Unix98 ptm driver");
if (tty_register_driver(&pts_driver))
ptm_driver[i].ioctl = pty_unix98_ioctl; panic("Couldn't register Unix98 pts driver");
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);
}
#endif #endif
return 0; return 0;
} }
...@@ -126,8 +126,8 @@ LIST_HEAD(tty_drivers); /* linked list of tty drivers */ ...@@ -126,8 +126,8 @@ LIST_HEAD(tty_drivers); /* linked list of tty drivers */
struct tty_ldisc ldiscs[NR_LDISCS]; /* line disc dispatch table */ struct tty_ldisc ldiscs[NR_LDISCS]; /* line disc dispatch table */
#ifdef CONFIG_UNIX98_PTYS #ifdef CONFIG_UNIX98_PTYS
extern struct tty_driver ptm_driver[]; /* Unix98 pty masters; 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 */ extern struct tty_driver pts_driver; /* Unix98 pty slaves; for /dev/ptmx */
#endif #endif
extern void disable_early_printk(void); extern void disable_early_printk(void);
...@@ -313,21 +313,15 @@ static int tty_set_ldisc(struct tty_struct *tty, int ldisc) ...@@ -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 * 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; struct tty_driver *p;
minor = minor(device);
major = major(device);
list_for_each_entry(p, &tty_drivers, tty_drivers) { list_for_each_entry(p, &tty_drivers, tty_drivers) {
if (p->major != major) dev_t base = MKDEV(p->major, p->minor_start);
continue; if (device < base || device >= base + p->num)
if (minor < p->minor_start)
continue;
if (minor >= p->minor_start + p->num)
continue; continue;
*index = device - base;
return p; return p;
} }
return NULL; return NULL;
...@@ -1345,32 +1339,24 @@ static int tty_open(struct inode * inode, struct file * filp) ...@@ -1345,32 +1339,24 @@ static int tty_open(struct inode * inode, struct file * filp)
if (IS_PTMX_DEV(device)) { if (IS_PTMX_DEV(device)) {
#ifdef CONFIG_UNIX98_PTYS #ifdef CONFIG_UNIX98_PTYS
/* find a free pty. */
int major;
/* find a device that is not in use. */ /* find a device that is not in use. */
retval = -1; retval = -1;
for (major = 0 ; major < UNIX98_NR_MAJORS ; major++) { driver = &ptm_driver;
driver = &ptm_driver[major]; for (index = 0; index < driver->num ; index++)
for (index = 0; index < driver->num ; index++) if (!init_dev(driver, index, &tty))
if (!init_dev(driver, index, &tty)) goto ptmx_found; /* ok! */
goto ptmx_found; /* ok! */
}
}
return -EIO; /* no free ptys */ return -EIO; /* no free ptys */
ptmx_found: ptmx_found:
set_bit(TTY_PTY_LOCK, &tty->flags); /* LOCK THE SLAVE */ 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; noctty = 1;
#else #else
return -ENODEV; return -ENODEV;
#endif /* CONFIG_UNIX_98_PTYS */ #endif /* CONFIG_UNIX_98_PTYS */
} else { } else {
driver = get_tty_driver(device); driver = get_tty_driver(kdev_t_to_nr(device), &index);
if (!driver) if (!driver)
return -ENODEV; return -ENODEV;
index = minor(device) - driver->minor_start;
retval = init_dev(driver, index, &tty); retval = init_dev(driver, index, &tty);
if (retval) if (retval)
...@@ -2094,21 +2080,18 @@ static void tty_default_put_char(struct tty_struct *tty, unsigned char ch) ...@@ -2094,21 +2080,18 @@ static void tty_default_put_char(struct tty_struct *tty, unsigned char ch)
#ifdef CONFIG_DEVFS_FS #ifdef CONFIG_DEVFS_FS
static void tty_register_devfs(struct tty_driver *driver, unsigned index) static void tty_register_devfs(struct tty_driver *driver, unsigned index)
{ {
umode_t mode = S_IFCHR | S_IRUSR | S_IWUSR; dev_t dev = MKDEV(driver->major, driver->minor_start) + index;
unsigned minor = driver->minor_start + index;
kdev_t dev = mk_kdev(driver->major, minor);
char buf[32]; char buf[32];
if ((minor < driver->minor_start) || if (index >= driver->num) {
(minor >= driver->minor_start + driver->num)) { printk(KERN_ERR "Attempt to register invalid tty line number "
printk(KERN_ERR "Attempt to register invalid minor number " "with devfs (%d).\n", index);
"with devfs (%d:%d).\n", (int)driver->major,(int)minor);
return; return;
} }
tty_line_name(driver, index, buf); tty_line_name(driver, index, buf);
devfs_register(NULL, buf, 0, driver->major, minor, mode, devfs_register(NULL, buf, 0, MAJOR(dev), MINOR(dev),
&tty_fops, NULL); S_IFCHR | S_IRUSR | S_IWUSR, &tty_fops, NULL);
} }
static void tty_unregister_devfs(struct tty_driver *driver, int index) 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) ...@@ -2138,6 +2121,53 @@ void tty_unregister_device(struct tty_driver *driver, unsigned index)
EXPORT_SYMBOL(tty_register_device); EXPORT_SYMBOL(tty_register_device);
EXPORT_SYMBOL(tty_unregister_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. * Called by a tty driver to register itself.
*/ */
...@@ -2149,12 +2179,16 @@ int tty_register_driver(struct tty_driver *driver) ...@@ -2149,12 +2179,16 @@ int tty_register_driver(struct tty_driver *driver)
if (driver->flags & TTY_DRIVER_INSTALLED) if (driver->flags & TTY_DRIVER_INSTALLED)
return 0; 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); driver->num, driver->name, &tty_fops);
if (error > 0)
driver->major = error;
} else {
error = get_range(driver);
}
if (error < 0) if (error < 0)
return error; return error;
else if(driver->major == 0)
driver->major = error;
if (!driver->put_char) if (!driver->put_char)
driver->put_char = tty_default_put_char; driver->put_char = tty_default_put_char;
...@@ -2174,16 +2208,13 @@ int tty_register_driver(struct tty_driver *driver) ...@@ -2174,16 +2208,13 @@ int tty_register_driver(struct tty_driver *driver)
*/ */
int tty_unregister_driver(struct tty_driver *driver) int tty_unregister_driver(struct tty_driver *driver)
{ {
int retval, i; int i;
struct termios *tp; struct termios *tp;
if (*driver->refcount) if (*driver->refcount)
return -EBUSY; return -EBUSY;
retval = unregister_chrdev_region(driver->major, driver->minor_start, put_range(driver);
driver->num, driver->name);
if (retval)
return retval;
list_del(&driver->tty_drivers); list_del(&driver->tty_drivers);
......
...@@ -1182,7 +1182,6 @@ tty3215_init(void) ...@@ -1182,7 +1182,6 @@ tty3215_init(void)
tty3215_driver.owner = THIS_MODULE; tty3215_driver.owner = THIS_MODULE;
tty3215_driver.driver_name = "tty3215"; tty3215_driver.driver_name = "tty3215";
tty3215_driver.name = "ttyS"; tty3215_driver.name = "ttyS";
tty3215_driver.name_base = 0;
tty3215_driver.major = TTY_MAJOR; tty3215_driver.major = TTY_MAJOR;
tty3215_driver.minor_start = 64; tty3215_driver.minor_start = 64;
tty3215_driver.num = NR_3215; tty3215_driver.num = NR_3215;
......
...@@ -761,7 +761,6 @@ sclp_tty_init(void) ...@@ -761,7 +761,6 @@ sclp_tty_init(void)
sclp_tty_driver.owner = THIS_MODULE; sclp_tty_driver.owner = THIS_MODULE;
sclp_tty_driver.driver_name = "sclp_line"; sclp_tty_driver.driver_name = "sclp_line";
sclp_tty_driver.name = "ttyS"; sclp_tty_driver.name = "ttyS";
sclp_tty_driver.name_base = 0;
sclp_tty_driver.major = TTY_MAJOR; sclp_tty_driver.major = TTY_MAJOR;
sclp_tty_driver.minor_start = 64; sclp_tty_driver.minor_start = 64;
sclp_tty_driver.num = 1; sclp_tty_driver.num = 1;
......
...@@ -29,39 +29,18 @@ static struct proc_dir_entry *proc_tty_ldisc, *proc_tty_driver; ...@@ -29,39 +29,18 @@ static struct proc_dir_entry *proc_tty_ldisc, *proc_tty_driver;
/* /*
* This is the handler for /proc/tty/drivers * 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, "%-20s ", p->driver_name ? p->driver_name : "unknown");
seq_printf(m, "/dev/%-8s ", p->name); seq_printf(m, "/dev/%-8s ", p->name);
if (p->num > 1) { if (p->num > 1) {
char range[20]; char range[20];
sprintf(range, "%d-%d", p->minor_start, sprintf(range, "%d-%d", MINOR(from),
p->minor_start + p->num - 1); MINOR(from) + num - 1);
seq_printf(m, "%3d %7s ", p->major, range); seq_printf(m, "%3d %7s ", MAJOR(from), range);
} else { } else {
seq_printf(m, "%3d %7d ", p->major, p->minor_start); seq_printf(m, "%3d %7d ", MAJOR(from), MINOR(from));
} }
switch (p->type) { switch (p->type) {
case TTY_DRIVER_TYPE_SYSTEM: case TTY_DRIVER_TYPE_SYSTEM:
...@@ -93,6 +72,41 @@ static int show_tty_driver(struct seq_file *m, void *v) ...@@ -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_printf(m, "type:%d.%d", p->type, p->subtype);
} }
seq_putc(m, '\n'); 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; 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