patch-2.4.0-test3 linux/drivers/char/n_hdlc.c

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

diff -u --recursive --new-file v2.4.0-test2/linux/drivers/char/n_hdlc.c linux/drivers/char/n_hdlc.c
@@ -9,7 +9,7 @@
  *	Al Longyear <longyear@netcom.com>, Paul Mackerras <Paul.Mackerras@cs.anu.edu.au>
  *
  * Original release 01/11/99
- * ==FILEDATE 19991217==
+ * ==FILEDATE 20000706==
  *
  * This code is released under the GNU General Public License (GPL)
  *
@@ -78,7 +78,7 @@
  */
 
 #define HDLC_MAGIC 0x239e
-#define HDLC_VERSION "1.13"
+#define HDLC_VERSION "1.16"
 
 #include <linux/version.h>
 #include <linux/config.h>
@@ -239,6 +239,7 @@
 	/* Queues for select() functionality */
 	wait_queue_head_t read_wait;
 	wait_queue_head_t write_wait;
+	wait_queue_head_t poll_wait;
 
 	int		tbusy;		/* reentrancy flag for tx wakeup code */
 	int		woke_up;
@@ -317,6 +318,7 @@
 		
 	/* Ensure that the n_hdlcd process is not hanging on select()/poll() */
 	wake_up_interruptible (&n_hdlc->read_wait);
+	wake_up_interruptible (&n_hdlc->poll_wait);
 	wake_up_interruptible (&n_hdlc->write_wait);
 
 	if (tty != NULL && tty->disc_data == n_hdlc)
@@ -463,9 +465,10 @@
 	register int actual;
 	unsigned long flags;
 	N_HDLC_BUF *tbuf;
-	
+
 	if (debuglevel >= DEBUG_LEVEL_INFO)	
 		printk("%s(%d)n_hdlc_send_frames() called\n",__FILE__,__LINE__);
+ check_again:
 		
 	save_flags(flags);
 	cli ();
@@ -475,6 +478,7 @@
 		return;
 	}
 	n_hdlc->tbusy = 1;
+	n_hdlc->woke_up = 0;
 	restore_flags(flags);
 
 	/* get current transmit buffer or get new transmit */
@@ -490,7 +494,6 @@
 				__FILE__,__LINE__,tbuf,tbuf->count);
 			
 		/* Send the next block of data to device */
-		n_hdlc->woke_up = 0;
 		tty->flags |= (1 << TTY_DO_WRITE_WAKEUP);
 		actual = tty->driver.write(tty, 0, tbuf->buf, tbuf->count);
 		    
@@ -512,6 +515,7 @@
 			
 			/* wait up sleeping writers */
 			wake_up_interruptible(&n_hdlc->write_wait);
+			wake_up_interruptible(&n_hdlc->poll_wait);
 	
 			/* get next pending transmit buffer */
 			tbuf = n_hdlc_buf_get(&n_hdlc->tx_buf_list);
@@ -521,11 +525,6 @@
 					__FILE__,__LINE__,tbuf);
 					
 			/* buffer not accepted by driver */
-			
-			/* check if wake up code called since last write call */
-			if (n_hdlc->woke_up)
-				continue;
-				
 			/* set this buffer as pending buffer */
 			n_hdlc->tbuf = tbuf;
 			break;
@@ -541,6 +540,9 @@
 	n_hdlc->tbusy = 0;
 	restore_flags(flags);
 	
+        if (n_hdlc->woke_up)
+	  goto check_again;
+
 	if (debuglevel >= DEBUG_LEVEL_INFO)	
 		printk("%s(%d)n_hdlc_send_frames() exit\n",__FILE__,__LINE__);
 		
@@ -568,11 +570,8 @@
 		tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
 		return;
 	}
-	
-	if (!n_hdlc->tbuf)
-		tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
-	else
-		n_hdlc_send_frames (n_hdlc, tty);
+
+	n_hdlc_send_frames (n_hdlc, tty);
 		
 }	/* end of n_hdlc_tty_wakeup() */
 
@@ -659,11 +658,12 @@
 	
 	/* wake up any blocked reads and perform async signalling */
 	wake_up_interruptible (&n_hdlc->read_wait);
+	wake_up_interruptible (&n_hdlc->poll_wait);
 	if (n_hdlc->tty->fasync != NULL)
 #if LINUX_VERSION_CODE < VERSION(2,3,0) 
 		kill_fasync (n_hdlc->tty->fasync, SIGIO);
 #else
-		kill_fasync(&n_hdlc->tty->fasync, SIGIO, POLL_IN);
+		kill_fasync (&n_hdlc->tty->fasync, SIGIO, POLL_IN);
 #endif
 }	/* end of n_hdlc_tty_receive() */
 
@@ -788,34 +788,31 @@
 		count = maxframe;
 	}
 	
+	add_wait_queue(&n_hdlc->write_wait, &wait);
+	set_current_state(TASK_INTERRUPTIBLE);
+	
 	/* Allocate transmit buffer */
-	tbuf = n_hdlc_buf_get(&n_hdlc->tx_free_buf_list);
-	if (!tbuf) {
-		/* sleep until transmit buffer available */		
-		add_wait_queue(&n_hdlc->write_wait, &wait);
-		while (!tbuf) {
-			set_current_state(TASK_INTERRUPTIBLE);
-			schedule();
-
-			n_hdlc = tty2n_hdlc (tty);
-			if (!n_hdlc || n_hdlc->magic != HDLC_MAGIC || 
-			    tty != n_hdlc->tty) {
-				printk("n_hdlc_tty_write: %p invalid after wait!\n", n_hdlc);
-				error = -EIO;
-				break;
-			}
+	/* sleep until transmit buffer available */		
+	while (!(tbuf = n_hdlc_buf_get(&n_hdlc->tx_free_buf_list))) {
+		schedule();
 			
-			if (signal_pending(current)) {
-				error = -EINTR;
-				break;
-			}
+		n_hdlc = tty2n_hdlc (tty);
+		if (!n_hdlc || n_hdlc->magic != HDLC_MAGIC || 
+		    tty != n_hdlc->tty) {
+			printk("n_hdlc_tty_write: %p invalid after wait!\n", n_hdlc);
+			error = -EIO;
+			break;
+		}
 			
-			tbuf = n_hdlc_buf_get(&n_hdlc->tx_free_buf_list);
+		if (signal_pending(current)) {
+			error = -EINTR;
+			break;
 		}
-		set_current_state(TASK_RUNNING);
-		remove_wait_queue(&n_hdlc->write_wait, &wait);
 	}
 
+	set_current_state(TASK_RUNNING);
+	remove_wait_queue(&n_hdlc->write_wait, &wait);
+
 	if (!error) {		
 		/* Retrieve the user's buffer */
 		COPY_FROM_USER (error, tbuf->buf, data, count);
@@ -978,8 +975,6 @@
  * Return Value:
  * 
  * 	bit mask containing info on which ops will not block
- *
- * Note: Called without the kernel lock held. Which is fine.
  */
 static unsigned int n_hdlc_tty_poll (struct tty_struct *tty,
 	 struct file *filp, poll_table * wait)
@@ -994,11 +989,9 @@
 		/* queue current process into any wait queue that */
 		/* may awaken in the future (read and write) */
 #if LINUX_VERSION_CODE < VERSION(2,1,89)
-		poll_wait(&n_hdlc->read_wait, wait);
-		poll_wait(&n_hdlc->write_wait, wait);
+		poll_wait(&n_hdlc->poll_wait, wait);
 #else
-		poll_wait(filp, &n_hdlc->read_wait, wait);
-		poll_wait(filp, &n_hdlc->write_wait, wait);
+		poll_wait(filp, &n_hdlc->poll_wait, wait);
 #endif
 		/* set bits for operations that wont block */
 		if(n_hdlc->rx_buf_list.head)
@@ -1062,6 +1055,7 @@
 
 	n_hdlc->flags  = 0;
 	init_waitqueue_head(&n_hdlc->read_wait);
+	init_waitqueue_head(&n_hdlc->poll_wait);
 	init_waitqueue_head(&n_hdlc->write_wait);
 	
 	return n_hdlc;

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)