diff options
Diffstat (limited to 'drivers/char/tty_io.c')
-rw-r--r-- | drivers/char/tty_io.c | 111 |
1 files changed, 74 insertions, 37 deletions
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c index bf2e642c4..a26ce1311 100644 --- a/drivers/char/tty_io.c +++ b/drivers/char/tty_io.c @@ -65,6 +65,7 @@ #include <linux/sched.h> #include <linux/interrupt.h> #include <linux/tty.h> +#include <linux/tty_driver.h> #include <linux/tty_flip.h> #include <linux/devpts_fs.h> #include <linux/file.h> @@ -80,6 +81,7 @@ #include <linux/proc_fs.h> #endif #include <linux/init.h> +#include <linux/smp_lock.h> #include <asm/uaccess.h> #include <asm/system.h> @@ -107,6 +109,10 @@ struct termios tty_std_termios; /* for the benefit of tty drivers */ struct tty_driver *tty_drivers = NULL; /* 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 */ +#endif + /* * redirect is the pseudo-tty that console output * is redirected to if asked by TIOCCONS. @@ -123,6 +129,10 @@ static int tty_release(struct inode *, struct file *); static int tty_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigned long arg); static int tty_fasync(struct file * filp, int on); +#ifdef CONFIG_8xx +extern long console_8xx_init(void); +extern int rs_8xx_init(void); +#endif /* CONFIG_8xx */ #ifndef MIN #define MIN(a,b) ((a) < (b) ? (a) : (b)) @@ -367,17 +377,24 @@ static struct file_operations hung_up_tty_fops = { NULL /* hung_up_tty_fasync */ }; +/* + * This can be called through the "tq_scheduler" + * task-list. That is process synchronous, but + * doesn't hold any locks, so we need to make + * sure we have the appropriate locks for what + * we're doing.. + */ void do_tty_hangup(void *data) { struct tty_struct *tty = (struct tty_struct *) data; struct file * filp; struct task_struct *p; - unsigned long flags; if (!tty) return; - - save_flags(flags); cli(); + + /* inuse_filps is protected by the single kernel lock */ + lock_kernel(); check_tty_count(tty, "do_tty_hangup"); for (filp = inuse_filps; filp; filp = filp->f_next) { @@ -396,13 +413,21 @@ void do_tty_hangup(void *data) filp->f_op = &hung_up_tty_fops; } - if (tty->ldisc.flush_buffer) - tty->ldisc.flush_buffer(tty); - if (tty->driver.flush_buffer) - tty->driver.flush_buffer(tty); - if ((test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags)) && - tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup)(tty); + /* FIXME! What are the locking issues here? This may me overdoing things.. */ + { + unsigned long flags; + + save_flags(flags); cli(); + if (tty->ldisc.flush_buffer) + tty->ldisc.flush_buffer(tty); + if (tty->driver.flush_buffer) + tty->driver.flush_buffer(tty); + if ((test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags)) && + tty->ldisc.write_wakeup) + (tty->ldisc.write_wakeup)(tty); + restore_flags(flags); + } + wake_up_interruptible(&tty->write_wait); wake_up_interruptible(&tty->read_wait); @@ -445,7 +470,7 @@ void do_tty_hangup(void *data) tty->ctrl_status = 0; if (tty->driver.hangup) (tty->driver.hangup)(tty); - restore_flags(flags); + unlock_kernel(); } void tty_hangup(struct tty_struct * tty) @@ -455,7 +480,7 @@ void tty_hangup(struct tty_struct * tty) printk("%s hangup...\n", tty_name(tty, buf)); #endif - queue_task(&tty->tq_hangup, &tq_timer); + queue_task(&tty->tq_hangup, &tq_scheduler); } void tty_vhangup(struct tty_struct * tty) @@ -629,7 +654,7 @@ static inline ssize_t do_tty_write( ret = -ERESTARTSYS; if (signal_pending(current)) break; - if (need_resched) + if (current->need_resched) schedule(); } if (written) { @@ -1022,6 +1047,10 @@ static void release_dev(struct file * filp) } } #endif + + if (tty->driver.close) + tty->driver.close(tty, filp); + /* * Sanity check: if tty->count is going to zero, there shouldn't be * any waiters on tty->read_wait or tty->write_wait. We test the @@ -1079,9 +1108,6 @@ static void release_dev(struct file * filp) * block, so it's safe to proceed with closing. */ - if (tty->driver.close) - tty->driver.close(tty, filp); - if (pty_master) { if (--o_tty->count < 0) { printk("release_dev: bad pty slave count (%d) for %s\n", @@ -1153,6 +1179,7 @@ static void release_dev(struct file * filp) * Make sure that the tty's task queue isn't activated. */ run_task_queue(&tq_timer); + run_task_queue(&tq_scheduler); /* * The release_mem function takes care of the details of clearing @@ -1208,34 +1235,32 @@ retry_open: device = c->device(c); noctty = 1; } +#ifdef CONFIG_UNIX98_PTYS if (device == PTMX_DEV) { /* find a free pty. */ - struct tty_driver *driver = tty_drivers; - int minor, line; - - /* find the pty driver */ - for (driver=tty_drivers; driver; driver=driver->next) - if (driver->major == PTY_MASTER_MAJOR) - break; - if (!driver) return -ENODEV; - - /* find a minor device that is not in use. */ - for (minor=driver->minor_start; - minor<driver->minor_start+driver->num; - minor++) { - device = MKDEV(driver->major, minor); - retval = init_dev(device, &tty); - if (retval==0) break; /* success! */ + int major, minor; + struct tty_driver *driver; + + /* find a device that is not in use. */ + retval = -1; + for ( major = 0 ; major < UNIX98_NR_MAJORS ; major++ ) { + driver = &ptm_driver[major]; + for (minor = driver->minor_start ; + minor < driver->minor_start + driver->num ; + minor++) { + device = MKDEV(driver->major, minor); + if (!init_dev(device, &tty)) goto ptmx_found; /* ok! */ + } } - if (minor==driver->minor_start+driver->num) /* no success */ - return -EIO; /* no free ptys */ - + return -EIO; /* no free ptys */ + ptmx_found: set_bit(TTY_PTY_LOCK, &tty->flags); /* LOCK THE SLAVE */ - line = minor - driver->minor_start; - devpts_pty_new(line, MKDEV(driver->other->major, line+driver->other->minor_start)); + minor -= driver->minor_start; + devpts_pty_new(driver->other->name_base + minor, MKDEV(driver->other->major, minor + driver->other->minor_start)); noctty = 1; goto init_dev_done; } +#endif retval = init_dev(device, &tty); if (retval) @@ -1962,7 +1987,11 @@ long console_init(long kmem_start, long kmem_end) memcpy(tty_std_termios.c_cc, INIT_C_CC, NCCS); tty_std_termios.c_iflag = ICRNL | IXON; tty_std_termios.c_oflag = OPOST | ONLCR; +#if CONFIG_COBALT_SERIAL + tty_std_termios.c_cflag = B115200 | CS8 | CREAD | HUPCL; +#else tty_std_termios.c_cflag = B38400 | CS8 | CREAD | HUPCL; +#endif tty_std_termios.c_lflag = ISIG | ICANON | ECHO | ECHOE | ECHOK | ECHOCTL | ECHOKE | IEXTEN; @@ -2046,14 +2075,19 @@ __initfunc(int tty_init(void)) if (tty_register_driver(&dev_console_driver)) panic("Couldn't register /dev/tty0 driver\n"); +#ifndef CONFIG_COBALT_MICRO_SERVER kbd_init(); #endif +#endif #ifdef CONFIG_ESPSERIAL /* init ESP before rs, so rs doesn't see the port */ espserial_init(); #endif #ifdef CONFIG_SERIAL rs_init(); #endif +#ifdef CONFIG_MAC_SERIAL + macserial_init(); +#endif #ifdef CONFIG_ROCKETPORT rp_init(); #endif @@ -2078,6 +2112,9 @@ __initfunc(int tty_init(void)) #ifdef CONFIG_SPECIALIX specialix_init(); #endif +#ifdef CONFIG_8xx + rs_8xx_init(); +#endif /* CONFIG_8xx */ pty_init(); #ifdef CONFIG_VT vcs_init(); |