diff options
Diffstat (limited to 'drivers/tty/n_hdlc.c')
| -rw-r--r-- | drivers/tty/n_hdlc.c | 106 | 
1 files changed, 49 insertions, 57 deletions
diff --git a/drivers/tty/n_hdlc.c b/drivers/tty/n_hdlc.c index 47d32281032..644ddb841d9 100644 --- a/drivers/tty/n_hdlc.c +++ b/drivers/tty/n_hdlc.c @@ -97,13 +97,11 @@  #include <linux/slab.h>  #include <linux/tty.h>  #include <linux/errno.h> -#include <linux/smp_lock.h>  #include <linux/string.h>	/* used in new tty drivers */  #include <linux/signal.h>	/* used in new tty drivers */  #include <linux/if.h>  #include <linux/bitops.h> -#include <asm/system.h>  #include <asm/termios.h>  #include <asm/uaccess.h> @@ -418,7 +416,7 @@ static void n_hdlc_send_frames(struct n_hdlc *n_hdlc, struct tty_struct *tty)  				__FILE__,__LINE__,tbuf,tbuf->count);  		/* Send the next block of data to device */ -		tty->flags |= (1 << TTY_DO_WRITE_WAKEUP); +		set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);  		actual = tty->ops->write(tty, tbuf->buf, tbuf->count);  		/* rollback was possible and has been done */ @@ -460,7 +458,7 @@ static void n_hdlc_send_frames(struct n_hdlc *n_hdlc, struct tty_struct *tty)  	}  	if (!tbuf) -		tty->flags  &= ~(1 << TTY_DO_WRITE_WAKEUP); +		clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);  	/* Clear the re-entry flag */  	spin_lock_irqsave(&n_hdlc->tx_buf_list.spinlock, flags); @@ -492,7 +490,7 @@ static void n_hdlc_tty_wakeup(struct tty_struct *tty)  		return;  	if (tty != n_hdlc->tty) { -		tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP); +		clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);  		return;  	} @@ -581,8 +579,9 @@ static ssize_t n_hdlc_tty_read(struct tty_struct *tty, struct file *file,  			   __u8 __user *buf, size_t nr)  {  	struct n_hdlc *n_hdlc = tty2n_hdlc(tty); -	int ret; +	int ret = 0;  	struct n_hdlc_buf *rbuf; +	DECLARE_WAITQUEUE(wait, current);  	if (debuglevel >= DEBUG_LEVEL_INFO)	  		printk("%s(%d)n_hdlc_tty_read() called\n",__FILE__,__LINE__); @@ -598,57 +597,55 @@ static ssize_t n_hdlc_tty_read(struct tty_struct *tty, struct file *file,  		return -EFAULT;  	} -	tty_lock(); +	add_wait_queue(&tty->read_wait, &wait);  	for (;;) {  		if (test_bit(TTY_OTHER_CLOSED, &tty->flags)) { -			tty_unlock(); -			return -EIO; +			ret = -EIO; +			break;  		} +		if (tty_hung_up_p(file)) +			break; -		n_hdlc = tty2n_hdlc (tty); -		if (!n_hdlc || n_hdlc->magic != HDLC_MAGIC || -			 tty != n_hdlc->tty) { -			tty_unlock(); -			return 0; -		} +		set_current_state(TASK_INTERRUPTIBLE);  		rbuf = n_hdlc_buf_get(&n_hdlc->rx_buf_list); -		if (rbuf) +		if (rbuf) { +			if (rbuf->count > nr) { +				/* too large for caller's buffer */ +				ret = -EOVERFLOW; +			} else { +				if (copy_to_user(buf, rbuf->buf, rbuf->count)) +					ret = -EFAULT; +				else +					ret = rbuf->count; +			} + +			if (n_hdlc->rx_free_buf_list.count > +			    DEFAULT_RX_BUF_COUNT) +				kfree(rbuf); +			else +				n_hdlc_buf_put(&n_hdlc->rx_free_buf_list, rbuf);  			break; +		}  		/* no data */  		if (file->f_flags & O_NONBLOCK) { -			tty_unlock(); -			return -EAGAIN; +			ret = -EAGAIN; +			break;  		} -			 -		interruptible_sleep_on (&tty->read_wait); + +		schedule(); +  		if (signal_pending(current)) { -			tty_unlock(); -			return -EINTR; +			ret = -EINTR; +			break;  		}  	} -		 -	if (rbuf->count > nr) -		/* frame too large for caller's buffer (discard frame) */ -		ret = -EOVERFLOW; -	else { -		/* Copy the data to the caller's buffer */ -		if (copy_to_user(buf, rbuf->buf, rbuf->count)) -			ret = -EFAULT; -		else -			ret = rbuf->count; -	} -	 -	/* return HDLC buffer to free list unless the free list */ -	/* count has exceeded the default value, in which case the */ -	/* buffer is freed back to the OS to conserve memory */ -	if (n_hdlc->rx_free_buf_list.count > DEFAULT_RX_BUF_COUNT) -		kfree(rbuf); -	else	 -		n_hdlc_buf_put(&n_hdlc->rx_free_buf_list,rbuf); -	tty_unlock(); + +	remove_wait_queue(&tty->read_wait, &wait); +	__set_current_state(TASK_RUNNING); +  	return ret;  }	/* end of n_hdlc_tty_read() */ @@ -691,14 +688,15 @@ static ssize_t n_hdlc_tty_write(struct tty_struct *tty, struct file *file,  		count = maxframe;  	} -	tty_lock(); -  	add_wait_queue(&tty->write_wait, &wait); -	set_current_state(TASK_INTERRUPTIBLE); + +	for (;;) { +		set_current_state(TASK_INTERRUPTIBLE); -	/* Allocate transmit buffer */ -	/* sleep until transmit buffer available */		 -	while (!(tbuf = n_hdlc_buf_get(&n_hdlc->tx_free_buf_list))) { +		tbuf = n_hdlc_buf_get(&n_hdlc->tx_free_buf_list); +		if (tbuf) +			break; +  		if (file->f_flags & O_NONBLOCK) {  			error = -EAGAIN;  			break; @@ -719,7 +717,7 @@ static ssize_t n_hdlc_tty_write(struct tty_struct *tty, struct file *file,  		}  	} -	set_current_state(TASK_RUNNING); +	__set_current_state(TASK_RUNNING);  	remove_wait_queue(&tty->write_wait, &wait);  	if (!error) {		 @@ -731,7 +729,7 @@ static ssize_t n_hdlc_tty_write(struct tty_struct *tty, struct file *file,  		n_hdlc_buf_put(&n_hdlc->tx_buf_list,tbuf);  		n_hdlc_send_frames(n_hdlc,tty);  	} -	tty_unlock(); +  	return error;  }	/* end of n_hdlc_tty_write() */ @@ -850,13 +848,11 @@ static struct n_hdlc *n_hdlc_alloc(void)  {  	struct n_hdlc_buf *buf;  	int i; -	struct n_hdlc *n_hdlc = kmalloc(sizeof(*n_hdlc), GFP_KERNEL); +	struct n_hdlc *n_hdlc = kzalloc(sizeof(*n_hdlc), GFP_KERNEL);  	if (!n_hdlc)  		return NULL; -	memset(n_hdlc, 0, sizeof(*n_hdlc)); -  	n_hdlc_buf_list_init(&n_hdlc->rx_free_buf_list);  	n_hdlc_buf_list_init(&n_hdlc->tx_free_buf_list);  	n_hdlc_buf_list_init(&n_hdlc->rx_buf_list); @@ -954,8 +950,6 @@ static char hdlc_register_ok[] __initdata =  	KERN_INFO "N_HDLC line discipline registered.\n";  static char hdlc_register_fail[] __initdata =  	KERN_ERR "error registering line discipline: %d\n"; -static char hdlc_init_fail[] __initdata = -	KERN_INFO "N_HDLC: init failure %d\n";  static int __init n_hdlc_init(void)  { @@ -975,8 +969,6 @@ static int __init n_hdlc_init(void)  	else  		printk(hdlc_register_fail, status); -	if (status) -		printk(hdlc_init_fail, status);  	return status;  }	/* end of init_module() */  | 
