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

Next file: linux/drivers/net/dummy.c
Previous file: linux/drivers/char/psaux.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v1.3.25/linux/drivers/char/tty_io.c linux/drivers/char/tty_io.c
@@ -35,6 +35,9 @@
  *
  * Rewrote canonical mode and added more termios flags.
  * 	-- [email protected] (J. Cowley), 13Jan94
+ *
+ * Reorganized FASYNC support so mouse code can share it.
+ *	-- [email protected], 9Sep95
  */
 
 #include <linux/types.h>
@@ -1217,16 +1220,17 @@
 	return 0;
 }
 
-static int tty_fasync(struct inode * inode, struct file * filp, int on)
+/*
+ * fasync_helper() is used by some character device drivers (mainly mice)
+ * to set up the fasync queue. It returns negative on error, 0 if it did
+ * no changes and positive if it added/deleted the entry.
+ */
+int fasync_helper(struct inode * inode, struct file * filp, int on, struct fasync_struct **fapp)
 {
-	struct tty_struct * tty;
-	struct fasync_struct *fa, *prev;
-
-	tty = (struct tty_struct *)filp->private_data;
-	if (tty_paranoia_check(tty, inode->i_rdev, "tty_fasync"))
-		return 0;
+	struct fasync_struct *fa, **fp;
+	unsigned long flags;
 
-	for (fa = tty->fasync, prev = 0; fa; prev= fa, fa = fa->fa_next) {
+	for (fp = fapp; (fa = *fp) != NULL; fp = &fa->fa_next) {
 		if (fa->fa_file == filp)
 			break;
 	}
@@ -1239,8 +1243,37 @@
 			return -ENOMEM;
 		fa->magic = FASYNC_MAGIC;
 		fa->fa_file = filp;
-		fa->fa_next = tty->fasync;
-		tty->fasync = fa;
+		save_flags(flags);
+		cli();
+		fa->fa_next = *fapp;
+		*fapp = fa;
+		restore_flags(flags);
+		return 1;
+	}
+	if (!fa)
+		return 0;
+	save_flags(flags);
+	cli();
+	*fp = fa->fa_next;
+	restore_flags(flags);
+	kfree(fa);
+	return 1;
+}
+
+static int tty_fasync(struct inode * inode, struct file * filp, int on)
+{
+	struct tty_struct * tty;
+	int retval;
+
+	tty = (struct tty_struct *)filp->private_data;
+	if (tty_paranoia_check(tty, inode->i_rdev, "tty_fasync"))
+		return 0;
+	
+	retval = fasync_helper(inode, filp, on, &tty->fasync);
+	if (retval <= 0)
+		return retval;
+
+	if (on) {
 		if (!tty->read_wait)
 			tty->minimum_to_wake = 1;
 		if (filp->f_owner == 0) {
@@ -1250,17 +1283,10 @@
 				filp->f_owner = current->pid;
 		}
 	} else {
-		if (!fa)
-			return 0;
-		if (prev)
-			prev->fa_next = fa->fa_next;
-		else
-			tty->fasync = fa->fa_next;
-		kfree_s(fa, sizeof(struct fasync_struct));
 		if (!tty->fasync && !tty->read_wait)
 			tty->minimum_to_wake = N_TTY_BUF_SIZE;
 	}
-	return 0;	
+	return 0;
 }
 
 #if 0

FUNET's LINUX-ADM group, [email protected]
TCL-scripts by Sam Shen, [email protected] with Sam's (original) version
of this