patch-2.1.66 linux/drivers/char/tty_io.c

Next file: linux/drivers/char/tty_ioctl.c
Previous file: linux/drivers/char/serial.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.1.65/linux/drivers/char/tty_io.c linux/drivers/char/tty_io.c
@@ -366,14 +366,18 @@
 	NULL		/* hung_up_tty_fasync */
 };
 
-void do_tty_hangup(struct tty_struct * tty, struct file_operations *fops)
+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();
+	
 	check_tty_count(tty, "do_tty_hangup");
 	for (filp = inuse_filps; filp; filp = filp->f_next) {
 		if (filp->private_data != tty)
@@ -387,7 +391,7 @@
 		if (filp->f_op != &tty_fops)
 			continue;
 		tty_fasync(filp, 0);
-		filp->f_op = fops;
+		filp->f_op = &hung_up_tty_fops;
 	}
 	
 	if (tty->ldisc.flush_buffer)
@@ -404,6 +408,8 @@
 	 * Shutdown the current line discipline, and reset it to
 	 * N_TTY.
 	 */
+	if (tty->driver.flags & TTY_DRIVER_RESET_TERMIOS)
+		*tty->termios = tty->driver.init_termios;
 	if (tty->ldisc.num != ldiscs[N_TTY].num) {
 		if (tty->ldisc.close)
 			(tty->ldisc.close)(tty);
@@ -435,10 +441,9 @@
 	tty->session = 0;
 	tty->pgrp = -1;
 	tty->ctrl_status = 0;
-	if (tty->driver.flags & TTY_DRIVER_RESET_TERMIOS)
-		*tty->termios = tty->driver.init_termios;
 	if (tty->driver.hangup)
 		(tty->driver.hangup)(tty);
+	restore_flags(flags);
 }
 
 void tty_hangup(struct tty_struct * tty)
@@ -446,7 +451,7 @@
 #ifdef TTY_DEBUG_HANGUP
 	printk("%s hangup...\n", tty_name(tty));
 #endif
-	do_tty_hangup(tty, &hung_up_tty_fops);
+	queue_task(&tty->tq_hangup, &tq_timer);
 }
 
 void tty_vhangup(struct tty_struct * tty)
@@ -454,7 +459,7 @@
 #ifdef TTY_DEBUG_HANGUP
 	printk("%s vhangup...\n", tty_name(tty));
 #endif
-	do_tty_hangup(tty, &hung_up_tty_fops);
+	do_tty_hangup((void *) tty);
 }
 
 int tty_hung_up_p(struct file * filp)
@@ -1490,15 +1495,26 @@
 {
 	int retval, ldisc;
 
-	retval = tty_check_change(tty);
-	if (retval)
-		return retval;
 	retval = get_user(ldisc, arg);
 	if (retval)
 		return retval;
 	return tty_set_ldisc(tty, ldisc);
 }
 
+static int send_break(struct tty_struct *tty, int duration)
+{
+	current->state = TASK_INTERRUPTIBLE;
+	current->timeout = jiffies + duration;
+
+	tty->driver.break_ctl(tty, -1);
+	if (!signal_pending(current))
+		schedule();
+	tty->driver.break_ctl(tty, 0);
+	if (signal_pending(current))
+		return -EINTR;
+	return 0;
+}
+
 /*
  * Split this up, as gcc can choke on it otherwise..
  */
@@ -1506,6 +1522,7 @@
 		     unsigned int cmd, unsigned long arg)
 {
 	struct tty_struct *tty, *real_tty;
+	int retval;
 	
 	tty = (struct tty_struct *)file->private_data;
 	if (tty_paranoia_check(tty, inode->i_rdev, "tty_ioctl"))
@@ -1516,6 +1533,46 @@
 	    tty->driver.subtype == PTY_TYPE_MASTER)
 		real_tty = tty->link;
 
+	/*
+	 * Break handling by driver
+	 */
+	if (!tty->driver.break_ctl) {
+		switch(cmd) {
+		case TIOCSBRK:
+		case TIOCCBRK:
+			return tty->driver.ioctl(tty, file, cmd, arg);
+			
+		/* These two ioctl's always return success; even if */
+		/* the driver doesn't support them. */
+		case TCSBRK:
+		case TCSBRKP:			
+			retval = tty->driver.ioctl(tty, file, cmd, arg);
+			if (retval == -ENOIOCTLCMD)
+				retval = 0;
+			return retval;
+		}
+	}
+
+	/*
+	 * Factor out some common prep work
+	 */
+	switch (cmd) {
+	case TIOCSETD:
+	case TIOCSBRK:
+	case TIOCCBRK:
+	case TCSBRK:
+	case TCSBRKP:			
+		retval = tty_check_change(tty);
+		if (retval)
+			return retval;
+		if (cmd != TIOCCBRK) {
+			tty_wait_until_sent(tty, 0);
+			if (signal_pending(current))
+				return -EINTR;
+		}
+		break;
+	}
+
 	switch (cmd) {
 		case TIOCSTI:
 			return tiocsti(tty, (char *)arg);
@@ -1556,6 +1613,28 @@
 #endif
 		case TIOCTTYGSTRUCT:
 			return tiocttygstruct(tty, (struct tty_struct *) arg);
+
+		/*
+		 * Break handling
+		 */
+		case TIOCSBRK:	/* Turn break on, unconditionally */
+			tty->driver.break_ctl(tty, -1);
+			return 0;
+			
+		case TIOCCBRK:	/* Turn break off, unconditionally */
+			tty->driver.break_ctl(tty, 0);
+			return 0;
+		case TCSBRK:   /* SVID version: non-zero arg --> no break */
+			/*
+			 * XXX is the above comment correct, or the
+			 * code below correct?  Is this ioctl used at
+			 * all by anyone?
+			 */
+			if (!arg)
+				return send_break(tty, HZ/4);
+			return 0;
+		case TCSBRKP:	/* support for POSIX tcsendbreak() */	
+			return send_break(tty, arg ? arg*(HZ/10) : HZ/4);
 	}
 	if (tty->driver.ioctl) {
 		int retval = (tty->driver.ioctl)(tty, file, cmd, arg);
@@ -1630,13 +1709,14 @@
 	unsigned char	*cp;
 	char		*fp;
 	int		count;
+	unsigned long flags;
 
 	if (tty->flip.buf_num) {
 		cp = tty->flip.char_buf + TTY_FLIPBUF_SIZE;
 		fp = tty->flip.flag_buf + TTY_FLIPBUF_SIZE;
 		tty->flip.buf_num = 0;
 
-		cli();
+		save_flags(flags); cli();
 		tty->flip.char_buf_ptr = tty->flip.char_buf;
 		tty->flip.flag_buf_ptr = tty->flip.flag_buf;
 	} else {
@@ -1644,22 +1724,57 @@
 		fp = tty->flip.flag_buf;
 		tty->flip.buf_num = 1;
 
-		cli();
+		save_flags(flags); cli();
 		tty->flip.char_buf_ptr = tty->flip.char_buf + TTY_FLIPBUF_SIZE;
 		tty->flip.flag_buf_ptr = tty->flip.flag_buf + TTY_FLIPBUF_SIZE;
 	}
 	count = tty->flip.count;
 	tty->flip.count = 0;
-	sti();
+	restore_flags(flags);
 	
-#if 0
-	if (count > tty->max_flip_cnt)
-		tty->max_flip_cnt = count;
-#endif
 	tty->ldisc.receive_buf(tty, cp, fp, count);
 }
 
 /*
+ * Routine which returns the baud rate of the tty
+ */
+
+/*
+ * This is used to figure out the divisor speeds and the timeouts
+ */
+static int baud_table[] = {
+	0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
+	9600, 19200, 38400, 57600, 115200, 230400, 460800, 0 };
+
+int tty_get_baud_rate(struct tty_struct *tty)
+{
+	unsigned int cflag, i;
+
+	cflag = tty->termios->c_cflag;
+
+	i = cflag & CBAUD;
+	if (i & CBAUDEX) {
+		i &= ~CBAUDEX;
+		if (i < 1 || i > 4) 
+			tty->termios->c_cflag &= ~CBAUDEX;
+		else
+			i += 15;
+	}
+	if (i==15 && tty->alt_speed)
+		return(tty->alt_speed);
+	
+	return baud_table[i];
+}
+
+void tty_flip_buffer_push(struct tty_struct *tty)
+{
+	if (tty->low_latency)
+		flush_to_ldisc((void *) tty);
+	else
+		queue_task(&tty->flip.tqueue, &tq_timer);
+}
+
+/*
  * This subroutine initializes a tty structure.
  */
 static void initialize_tty_struct(struct tty_struct *tty)
@@ -1673,6 +1788,8 @@
 	tty->flip.tqueue.routine = flush_to_ldisc;
 	tty->flip.tqueue.data = tty;
 	tty->flip.pty_sem = MUTEX;
+	tty->tq_hangup.routine = do_tty_hangup;
+	tty->tq_hangup.data = tty;
 }
 
 /*

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov