summaryrefslogtreecommitdiffstats
path: root/drivers/char/tty_io.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/char/tty_io.c')
-rw-r--r--drivers/char/tty_io.c111
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();