From a448f0d817d39fd791493cab307c278fd1eb5b33 Mon Sep 17 00:00:00 2001 From: Alexander Viro Date: Wed, 23 Apr 2003 04:19:54 -0700 Subject: [PATCH] [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) --- drivers/char/pty.c | 110 ++++++++++++++------------------ drivers/char/tty_io.c | 117 ++++++++++++++++++++++------------- drivers/s390/char/con3215.c | 1 - drivers/s390/char/sclp_tty.c | 1 - fs/proc/proc_tty.c | 68 ++++++++++++-------- 5 files changed, 163 insertions(+), 134 deletions(-) diff --git a/drivers/char/pty.c b/drivers/char/pty.c index e58858146d698..bb9286be8fe71 100644 --- a/drivers/char/pty.c +++ b/drivers/char/pty.c @@ -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; } diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c index 8298988afaf50..b82dd71948b8b 100644 --- a/drivers/char/tty_io.c +++ b/drivers/char/tty_io.c @@ -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 @@ retry_open: 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); diff --git a/drivers/s390/char/con3215.c b/drivers/s390/char/con3215.c index b3cddeebbbf7c..a719b1a11f53c 100644 --- a/drivers/s390/char/con3215.c +++ b/drivers/s390/char/con3215.c @@ -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; diff --git a/drivers/s390/char/sclp_tty.c b/drivers/s390/char/sclp_tty.c index 6aa8bc8dc896c..d700ede517cdf 100644 --- a/drivers/s390/char/sclp_tty.c +++ b/drivers/s390/char/sclp_tty.c @@ -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; diff --git a/fs/proc/proc_tty.c b/fs/proc/proc_tty.c index 6ecda65c652e2..fcc47362c1925 100644 --- a/fs/proc/proc_tty.c +++ b/fs/proc/proc_tty.c @@ -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; } -- 2.53.0