diff options
Diffstat (limited to 'drivers')
52 files changed, 1756 insertions, 1775 deletions
diff --git a/drivers/isdn/i4l/isdn_common.c b/drivers/isdn/i4l/isdn_common.c index d9f5524593f..8c610fa6782 100644 --- a/drivers/isdn/i4l/isdn_common.c +++ b/drivers/isdn/i4l/isdn_common.c @@ -46,7 +46,6 @@ static DEFINE_MUTEX(isdn_mutex);  static char *isdn_revision = "$Revision: 1.1.2.3 $";  extern char *isdn_net_revision; -extern char *isdn_tty_revision;  #ifdef CONFIG_ISDN_PPP  extern char *isdn_ppp_revision;  #else @@ -2327,8 +2326,6 @@ static int __init isdn_init(void)  		dev->chanmap[i] = -1;  		dev->m_idx[i] = -1;  		strcpy(dev->num[i], "???"); -		init_waitqueue_head(&dev->mdm.info[i].open_wait); -		init_waitqueue_head(&dev->mdm.info[i].close_wait);  	}  	if (register_chrdev(ISDN_MAJOR, "isdn", &isdn_fops)) {  		printk(KERN_WARNING "isdn: Could not register control devices\n"); @@ -2353,8 +2350,6 @@ static int __init isdn_init(void)  	strcpy(tmprev, isdn_revision);  	printk(KERN_NOTICE "ISDN subsystem Rev: %s/", isdn_getrev(tmprev)); -	strcpy(tmprev, isdn_tty_revision); -	printk("%s/", isdn_getrev(tmprev));  	strcpy(tmprev, isdn_net_revision);  	printk("%s/", isdn_getrev(tmprev));  	strcpy(tmprev, isdn_ppp_revision); diff --git a/drivers/isdn/i4l/isdn_tty.c b/drivers/isdn/i4l/isdn_tty.c index 3831abdbc66..7bc50670d7d 100644 --- a/drivers/isdn/i4l/isdn_tty.c +++ b/drivers/isdn/i4l/isdn_tty.c @@ -1,5 +1,4 @@ -/* $Id: isdn_tty.c,v 1.1.2.3 2004/02/10 01:07:13 keil Exp $ - * +/*   * Linux ISDN subsystem, tty functions and AT-command emulator (linklevel).   *   * Copyright 1994-1999  by Fritz Elfert (fritz@isdn4linux.de) @@ -12,6 +11,7 @@  #undef ISDN_TTY_STAT_DEBUG  #include <linux/isdn.h> +#include <linux/serial.h> /* ASYNC_* flags */  #include <linux/slab.h>  #include <linux/delay.h>  #include <linux/mutex.h> @@ -48,9 +48,6 @@ static int bit2si[8] =  static int si2bit[8] =  {4, 1, 4, 4, 4, 4, 4, 4}; -char *isdn_tty_revision = "$Revision: 1.1.2.3 $"; - -  /* isdn_tty_try_read() is called from within isdn_tty_rcv_skb()   * to stuff incoming data directly into a tty's flip-buffer. This   * is done to speed up tty-receiving if the receive-queue is empty. @@ -68,49 +65,54 @@ isdn_tty_try_read(modem_info *info, struct sk_buff *skb)  	struct tty_struct *tty;  	char last; -	if (info->online) { -		if ((tty = info->tty)) { -			if (info->mcr & UART_MCR_RTS) { -				len = skb->len +	if (!info->online) +		return 0; + +	tty = info->port.tty; +	if (!tty) +		return 0; + +	if (!(info->mcr & UART_MCR_RTS)) +		return 0; + +	len = skb->len  #ifdef CONFIG_ISDN_AUDIO -					+ ISDN_AUDIO_SKB_DLECOUNT(skb) +		+ ISDN_AUDIO_SKB_DLECOUNT(skb)  #endif -					; +		; + +	c = tty_buffer_request_room(tty, len); +	if (c < len) +		return 0; -				c = tty_buffer_request_room(tty, len); -				if (c >= len) {  #ifdef CONFIG_ISDN_AUDIO -					if (ISDN_AUDIO_SKB_DLECOUNT(skb)) { -						int l = skb->len; -						unsigned char *dp = skb->data; -						while (--l) { -							if (*dp == DLE) -								tty_insert_flip_char(tty, DLE, 0); -							tty_insert_flip_char(tty, *dp++, 0); -						} -						if (*dp == DLE) -							tty_insert_flip_char(tty, DLE, 0); -						last = *dp; -					} else { +	if (ISDN_AUDIO_SKB_DLECOUNT(skb)) { +		int l = skb->len; +		unsigned char *dp = skb->data; +		while (--l) { +			if (*dp == DLE) +				tty_insert_flip_char(tty, DLE, 0); +			tty_insert_flip_char(tty, *dp++, 0); +		} +		if (*dp == DLE) +			tty_insert_flip_char(tty, DLE, 0); +		last = *dp; +	} else {  #endif -						if (len > 1) -							tty_insert_flip_string(tty, skb->data, len - 1); -						last = skb->data[len - 1]; +		if (len > 1) +			tty_insert_flip_string(tty, skb->data, len - 1); +		last = skb->data[len - 1];  #ifdef CONFIG_ISDN_AUDIO -					} -#endif -					if (info->emu.mdmreg[REG_CPPP] & BIT_CPPP) -						tty_insert_flip_char(tty, last, 0xFF); -					else -						tty_insert_flip_char(tty, last, TTY_NORMAL); -					tty_flip_buffer_push(tty); -					kfree_skb(skb); -					return 1; -				} -			} -		}  	} -	return 0; +#endif +	if (info->emu.mdmreg[REG_CPPP] & BIT_CPPP) +		tty_insert_flip_char(tty, last, 0xFF); +	else +		tty_insert_flip_char(tty, last, TTY_NORMAL); +	tty_flip_buffer_push(tty); +	kfree_skb(skb); + +	return 1;  }  /* isdn_tty_readmodem() is called periodically from within timer-interrupt. @@ -128,35 +130,39 @@ isdn_tty_readmodem(void)  	modem_info *info;  	for (i = 0; i < ISDN_MAX_CHANNELS; i++) { -		if ((midx = dev->m_idx[i]) >= 0) { -			info = &dev->mdm.info[midx]; -			if (info->online) { -				r = 0; +		midx = dev->m_idx[i]; +		if (midx < 0) +			continue; + +		info = &dev->mdm.info[midx]; +		if (!info->online) +			continue; + +		r = 0;  #ifdef CONFIG_ISDN_AUDIO -				isdn_audio_eval_dtmf(info); -				if ((info->vonline & 1) && (info->emu.vpar[1])) -					isdn_audio_eval_silence(info); +		isdn_audio_eval_dtmf(info); +		if ((info->vonline & 1) && (info->emu.vpar[1])) +			isdn_audio_eval_silence(info);  #endif -				if ((tty = info->tty)) { -					if (info->mcr & UART_MCR_RTS) { -						/* CISCO AsyncPPP Hack */ -						if (!(info->emu.mdmreg[REG_CPPP] & BIT_CPPP)) -							r = isdn_readbchan_tty(info->isdn_driver, info->isdn_channel, tty, 0); -						else -							r = isdn_readbchan_tty(info->isdn_driver, info->isdn_channel, tty, 1); -						if (r) -							tty_flip_buffer_push(tty); -					} else -						r = 1; -				} else -					r = 1; -				if (r) { -					info->rcvsched = 0; -					resched = 1; -				} else -					info->rcvsched = 1; -			} -		} +		tty = info->port.tty; +		if (tty) { +			if (info->mcr & UART_MCR_RTS) { +				/* CISCO AsyncPPP Hack */ +				if (!(info->emu.mdmreg[REG_CPPP] & BIT_CPPP)) +					r = isdn_readbchan_tty(info->isdn_driver, info->isdn_channel, tty, 0); +				else +					r = isdn_readbchan_tty(info->isdn_driver, info->isdn_channel, tty, 1); +				if (r) +					tty_flip_buffer_push(tty); +			} else +				r = 1; +		} else +			r = 1; +		if (r) { +			info->rcvsched = 0; +			resched = 1; +		} else +			info->rcvsched = 1;  	}  	if (!resched)  		isdn_timer_ctrl(ISDN_TIMER_MODEMREAD, 0); @@ -294,7 +300,7 @@ isdn_tty_tint(modem_info *info)  	len = skb->len;  	if ((slen = isdn_writebuf_skb_stub(info->isdn_driver,  					   info->isdn_channel, 1, skb)) == len) { -		struct tty_struct *tty = info->tty; +		struct tty_struct *tty = info->port.tty;  		info->send_outstanding++;  		info->msr &= ~UART_MSR_CTS;  		info->lsr &= ~UART_LSR_TEMT; @@ -327,7 +333,7 @@ isdn_tty_countDLE(unsigned char *buf, int len)  static int  isdn_tty_handleDLEdown(modem_info *info, atemu *m, int len)  { -	unsigned char *p = &info->xmit_buf[info->xmit_count]; +	unsigned char *p = &info->port.xmit_buf[info->xmit_count];  	int count = 0;  	while (len > 0) { @@ -471,7 +477,7 @@ isdn_tty_senddown(modem_info *info)  		return;  	}  	skb_reserve(skb, skb_res); -	memcpy(skb_put(skb, buflen), info->xmit_buf, buflen); +	memcpy(skb_put(skb, buflen), info->port.xmit_buf, buflen);  	info->xmit_count = 0;  #ifdef CONFIG_ISDN_AUDIO  	if (info->vonline & 2) { @@ -699,7 +705,7 @@ isdn_tty_modem_hup(modem_info *info, int local)  	printk(KERN_DEBUG "Mhup ttyI%d\n", info->line);  #endif  	info->rcvsched = 0; -	isdn_tty_flush_buffer(info->tty); +	isdn_tty_flush_buffer(info->port.tty);  	if (info->online) {  		info->last_lhup = local;  		info->online = 0; @@ -997,20 +1003,21 @@ isdn_tty_paranoia_check(modem_info *info, char *name, const char *routine)  static void  isdn_tty_change_speed(modem_info *info)  { +	struct tty_port *port = &info->port;  	uint cflag,  		cval,  		quot;  	int i; -	if (!info->tty || !info->tty->termios) +	if (!port->tty || !port->tty->termios)  		return; -	cflag = info->tty->termios->c_cflag; +	cflag = port->tty->termios->c_cflag;  	quot = i = cflag & CBAUD;  	if (i & CBAUDEX) {  		i &= ~CBAUDEX;  		if (i < 1 || i > 2) -			info->tty->termios->c_cflag &= ~CBAUDEX; +			port->tty->termios->c_cflag &= ~CBAUDEX;  		else  			i += 15;  	} @@ -1040,20 +1047,20 @@ isdn_tty_change_speed(modem_info *info)  	/* CTS flow control flag and modem status interrupts */  	if (cflag & CRTSCTS) { -		info->flags |= ISDN_ASYNC_CTS_FLOW; +		port->flags |= ASYNC_CTS_FLOW;  	} else -		info->flags &= ~ISDN_ASYNC_CTS_FLOW; +		port->flags &= ~ASYNC_CTS_FLOW;  	if (cflag & CLOCAL) -		info->flags &= ~ISDN_ASYNC_CHECK_CD; +		port->flags &= ~ASYNC_CHECK_CD;  	else { -		info->flags |= ISDN_ASYNC_CHECK_CD; +		port->flags |= ASYNC_CHECK_CD;  	}  }  static int  isdn_tty_startup(modem_info *info)  { -	if (info->flags & ISDN_ASYNC_INITIALIZED) +	if (info->port.flags & ASYNC_INITIALIZED)  		return 0;  	isdn_lock_drivers();  #ifdef ISDN_DEBUG_MODEM_OPEN @@ -1063,14 +1070,14 @@ isdn_tty_startup(modem_info *info)  	 * Now, initialize the UART  	 */  	info->mcr = UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2; -	if (info->tty) -		clear_bit(TTY_IO_ERROR, &info->tty->flags); +	if (info->port.tty) +		clear_bit(TTY_IO_ERROR, &info->port.tty->flags);  	/*  	 * and set the speed of the serial port  	 */  	isdn_tty_change_speed(info); -	info->flags |= ISDN_ASYNC_INITIALIZED; +	info->port.flags |= ASYNC_INITIALIZED;  	info->msr |= (UART_MSR_DSR | UART_MSR_CTS);  	info->send_outstanding = 0;  	return 0; @@ -1083,14 +1090,14 @@ isdn_tty_startup(modem_info *info)  static void  isdn_tty_shutdown(modem_info *info)  { -	if (!(info->flags & ISDN_ASYNC_INITIALIZED)) +	if (!(info->port.flags & ASYNC_INITIALIZED))  		return;  #ifdef ISDN_DEBUG_MODEM_OPEN  	printk(KERN_DEBUG "Shutting down isdnmodem port %d ....\n", info->line);  #endif  	isdn_unlock_drivers();  	info->msr &= ~UART_MSR_RI; -	if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) { +	if (!info->port.tty || (info->port.tty->termios->c_cflag & HUPCL)) {  		info->mcr &= ~(UART_MCR_DTR | UART_MCR_RTS);  		if (info->emu.mdmreg[REG_DTRHUP] & BIT_DTRHUP) {  			isdn_tty_modem_reset_regs(info, 0); @@ -1100,10 +1107,10 @@ isdn_tty_shutdown(modem_info *info)  			isdn_tty_modem_hup(info, 1);  		}  	} -	if (info->tty) -		set_bit(TTY_IO_ERROR, &info->tty->flags); +	if (info->port.tty) +		set_bit(TTY_IO_ERROR, &info->port.tty->flags); -	info->flags &= ~ISDN_ASYNC_INITIALIZED; +	info->port.flags &= ~ASYNC_INITIALIZED;  }  /* isdn_tty_write() is the main send-routine. It is called from the upper @@ -1146,7 +1153,7 @@ isdn_tty_write(struct tty_struct *tty, const u_char *buf, int count)  				isdn_tty_check_esc(buf, m->mdmreg[REG_ESC], c,  						   &(m->pluscount),  						   &(m->lastplus)); -			memcpy(&(info->xmit_buf[info->xmit_count]), buf, c); +			memcpy(&info->port.xmit_buf[info->xmit_count], buf, c);  #ifdef CONFIG_ISDN_AUDIO  			if (info->vonline) {  				int cc = isdn_tty_handleDLEdown(info, m, c); @@ -1478,107 +1485,6 @@ isdn_tty_set_termios(struct tty_struct *tty, struct ktermios *old_termios)   * isdn_tty_open() and friends   * ------------------------------------------------------------   */ -static int -isdn_tty_block_til_ready(struct tty_struct *tty, struct file *filp, modem_info *info) -{ -	DECLARE_WAITQUEUE(wait, NULL); -	int do_clocal = 0; -	int retval; - -	/* -	 * If the device is in the middle of being closed, then block -	 * until it's done, and then try again. -	 */ -	if (tty_hung_up_p(filp) || -	    (info->flags & ISDN_ASYNC_CLOSING)) { -		if (info->flags & ISDN_ASYNC_CLOSING) -			interruptible_sleep_on(&info->close_wait); -#ifdef MODEM_DO_RESTART -		if (info->flags & ISDN_ASYNC_HUP_NOTIFY) -			return -EAGAIN; -		else -			return -ERESTARTSYS; -#else -		return -EAGAIN; -#endif -	} -	/* -	 * If non-blocking mode is set, then make the check up front -	 * and then exit. -	 */ -	if ((filp->f_flags & O_NONBLOCK) || -	    (tty->flags & (1 << TTY_IO_ERROR))) { -		if (info->flags & ISDN_ASYNC_CALLOUT_ACTIVE) -			return -EBUSY; -		info->flags |= ISDN_ASYNC_NORMAL_ACTIVE; -		return 0; -	} -	if (info->flags & ISDN_ASYNC_CALLOUT_ACTIVE) { -		if (info->normal_termios.c_cflag & CLOCAL) -			do_clocal = 1; -	} else { -		if (tty->termios->c_cflag & CLOCAL) -			do_clocal = 1; -	} -	/* -	 * Block waiting for the carrier detect and the line to become -	 * free (i.e., not in use by the callout).  While we are in -	 * this loop, info->count is dropped by one, so that -	 * isdn_tty_close() knows when to free things.  We restore it upon -	 * exit, either normal or abnormal. -	 */ -	retval = 0; -	add_wait_queue(&info->open_wait, &wait); -#ifdef ISDN_DEBUG_MODEM_OPEN -	printk(KERN_DEBUG "isdn_tty_block_til_ready before block: ttyi%d, count = %d\n", -	       info->line, info->count); -#endif -	if (!(tty_hung_up_p(filp))) -		info->count--; -	info->blocked_open++; -	while (1) { -		set_current_state(TASK_INTERRUPTIBLE); -		if (tty_hung_up_p(filp) || -		    !(info->flags & ISDN_ASYNC_INITIALIZED)) { -#ifdef MODEM_DO_RESTART -			if (info->flags & ISDN_ASYNC_HUP_NOTIFY) -				retval = -EAGAIN; -			else -				retval = -ERESTARTSYS; -#else -			retval = -EAGAIN; -#endif -			break; -		} -		if (!(info->flags & ISDN_ASYNC_CALLOUT_ACTIVE) && -		    !(info->flags & ISDN_ASYNC_CLOSING) && -		    (do_clocal || (info->msr & UART_MSR_DCD))) { -			break; -		} -		if (signal_pending(current)) { -			retval = -ERESTARTSYS; -			break; -		} -#ifdef ISDN_DEBUG_MODEM_OPEN -		printk(KERN_DEBUG "isdn_tty_block_til_ready blocking: ttyi%d, count = %d\n", -		       info->line, info->count); -#endif -		schedule(); -	} -	current->state = TASK_RUNNING; -	remove_wait_queue(&info->open_wait, &wait); -	if (!tty_hung_up_p(filp)) -		info->count++; -	info->blocked_open--; -#ifdef ISDN_DEBUG_MODEM_OPEN -	printk(KERN_DEBUG "isdn_tty_block_til_ready after blocking: ttyi%d, count = %d\n", -	       info->line, info->count); -#endif -	if (retval) -		return retval; -	info->flags |= ISDN_ASYNC_NORMAL_ACTIVE; -	return 0; -}  /*   * This routine is called whenever a serial port is opened.  It @@ -1589,23 +1495,22 @@ isdn_tty_block_til_ready(struct tty_struct *tty, struct file *filp, modem_info *  static int  isdn_tty_open(struct tty_struct *tty, struct file *filp)  { +	struct tty_port *port;  	modem_info *info;  	int retval;  	info = &dev->mdm.info[tty->index];  	if (isdn_tty_paranoia_check(info, tty->name, "isdn_tty_open"))  		return -ENODEV; -	if (!try_module_get(info->owner)) { -		printk(KERN_WARNING "%s: cannot reserve module\n", __func__); -		return -ENODEV; -	} +	port = &info->port;  #ifdef ISDN_DEBUG_MODEM_OPEN  	printk(KERN_DEBUG "isdn_tty_open %s, count = %d\n", tty->name, -	       info->count); +	       port->count);  #endif -	info->count++; +	port->count++;  	tty->driver_data = info; -	info->tty = tty; +	port->tty = tty; +	tty->port = port;  	/*  	 * Start up serial port  	 */ @@ -1614,15 +1519,13 @@ isdn_tty_open(struct tty_struct *tty, struct file *filp)  #ifdef ISDN_DEBUG_MODEM_OPEN  		printk(KERN_DEBUG "isdn_tty_open return after startup\n");  #endif -		module_put(info->owner);  		return retval;  	} -	retval = isdn_tty_block_til_ready(tty, filp, info); +	retval = tty_port_block_til_ready(port, tty, filp);  	if (retval) {  #ifdef ISDN_DEBUG_MODEM_OPEN  		printk(KERN_DEBUG "isdn_tty_open return after isdn_tty_block_til_ready \n");  #endif -		module_put(info->owner);  		return retval;  	}  #ifdef ISDN_DEBUG_MODEM_OPEN @@ -1639,6 +1542,7 @@ static void  isdn_tty_close(struct tty_struct *tty, struct file *filp)  {  	modem_info *info = (modem_info *) tty->driver_data; +	struct tty_port *port = &info->port;  	ulong timeout;  	if (!info || isdn_tty_paranoia_check(info, tty->name, "isdn_tty_close")) @@ -1649,7 +1553,7 @@ isdn_tty_close(struct tty_struct *tty, struct file *filp)  #endif  		return;  	} -	if ((tty->count == 1) && (info->count != 1)) { +	if ((tty->count == 1) && (port->count != 1)) {  		/*  		 * Uh, oh.  tty->count is 1, which means that the tty  		 * structure will be freed.  Info->count should always @@ -1658,30 +1562,21 @@ isdn_tty_close(struct tty_struct *tty, struct file *filp)  		 * serial port won't be shutdown.  		 */  		printk(KERN_ERR "isdn_tty_close: bad port count; tty->count is 1, " -		       "info->count is %d\n", info->count); -		info->count = 1; +		       "info->count is %d\n", port->count); +		port->count = 1;  	} -	if (--info->count < 0) { +	if (--port->count < 0) {  		printk(KERN_ERR "isdn_tty_close: bad port count for ttyi%d: %d\n", -		       info->line, info->count); -		info->count = 0; +		       info->line, port->count); +		port->count = 0;  	} -	if (info->count) { +	if (port->count) {  #ifdef ISDN_DEBUG_MODEM_OPEN  		printk(KERN_DEBUG "isdn_tty_close after info->count != 0\n");  #endif -		module_put(info->owner);  		return;  	} -	info->flags |= ISDN_ASYNC_CLOSING; -	/* -	 * Save the termios structure, since this port may have -	 * separate termios for callout and dialin. -	 */ -	if (info->flags & ISDN_ASYNC_NORMAL_ACTIVE) -		info->normal_termios = *tty->termios; -	if (info->flags & ISDN_ASYNC_CALLOUT_ACTIVE) -		info->callout_termios = *tty->termios; +	port->flags |= ASYNC_CLOSING;  	tty->closing = 1;  	/* @@ -1690,7 +1585,7 @@ isdn_tty_close(struct tty_struct *tty, struct file *filp)  	 * interrupt driver to stop checking the data ready bit in the  	 * line status register.  	 */ -	if (info->flags & ISDN_ASYNC_INITIALIZED) { +	if (port->flags & ASYNC_INITIALIZED) {  		tty_wait_until_sent_from_close(tty, 3000);	/* 30 seconds timeout */  		/*  		 * Before we drop DTR, make sure the UART transmitter @@ -1708,16 +1603,10 @@ isdn_tty_close(struct tty_struct *tty, struct file *filp)  	isdn_tty_shutdown(info);  	isdn_tty_flush_buffer(tty);  	tty_ldisc_flush(tty); -	info->tty = NULL; +	port->tty = NULL;  	info->ncarrier = 0; -	tty->closing = 0; -	module_put(info->owner); -	if (info->blocked_open) { -		msleep_interruptible(500); -		wake_up_interruptible(&info->open_wait); -	} -	info->flags &= ~(ISDN_ASYNC_NORMAL_ACTIVE | ISDN_ASYNC_CLOSING); -	wake_up_interruptible(&info->close_wait); + +	tty_port_close_end(port, tty);  #ifdef ISDN_DEBUG_MODEM_OPEN  	printk(KERN_DEBUG "isdn_tty_close normal exit\n");  #endif @@ -1730,14 +1619,15 @@ static void  isdn_tty_hangup(struct tty_struct *tty)  {  	modem_info *info = (modem_info *) tty->driver_data; +	struct tty_port *port = &info->port;  	if (isdn_tty_paranoia_check(info, tty->name, "isdn_tty_hangup"))  		return;  	isdn_tty_shutdown(info); -	info->count = 0; -	info->flags &= ~(ISDN_ASYNC_NORMAL_ACTIVE | ISDN_ASYNC_CALLOUT_ACTIVE); -	info->tty = NULL; -	wake_up_interruptible(&info->open_wait); +	port->count = 0; +	port->flags &= ~ASYNC_NORMAL_ACTIVE; +	port->tty = NULL; +	wake_up_interruptible(&port->open_wait);  }  /* This routine initializes all emulator-data. @@ -1864,6 +1754,16 @@ static const struct tty_operations modem_ops = {  	.tiocmset = isdn_tty_tiocmset,  }; +static int isdn_tty_carrier_raised(struct tty_port *port) +{ +	modem_info *info = container_of(port, modem_info, port); +	return info->msr & UART_MSR_DCD; +} + +static const struct tty_port_operations isdn_tty_port_ops = { +	.carrier_raised = isdn_tty_carrier_raised, +}; +  int  isdn_tty_modem_init(void)  { @@ -1899,9 +1799,8 @@ isdn_tty_modem_init(void)  			goto err_unregister;  		}  #endif -#ifdef MODULE -		info->owner = THIS_MODULE; -#endif +		tty_port_init(&info->port); +		info->port.ops = &isdn_tty_port_ops;  		spin_lock_init(&info->readlock);  		sprintf(info->last_cause, "0000");  		sprintf(info->last_num, "none"); @@ -1913,12 +1812,7 @@ isdn_tty_modem_init(void)  		isdn_tty_modem_reset_regs(info, 1);  		info->magic = ISDN_ASYNC_MAGIC;  		info->line = i; -		info->tty = NULL;  		info->x_char = 0; -		info->count = 0; -		info->blocked_open = 0; -		init_waitqueue_head(&info->open_wait); -		init_waitqueue_head(&info->close_wait);  		info->isdn_driver = -1;  		info->isdn_channel = -1;  		info->drv_index = -1; @@ -1930,13 +1824,15 @@ isdn_tty_modem_init(void)  #ifdef CONFIG_ISDN_AUDIO  		skb_queue_head_init(&info->dtmf_queue);  #endif -		if (!(info->xmit_buf = kmalloc(ISDN_SERIAL_XMIT_MAX + 5, GFP_KERNEL))) { +		info->port.xmit_buf = kmalloc(ISDN_SERIAL_XMIT_MAX + 5, +				GFP_KERNEL); +		if (!info->port.xmit_buf) {  			printk(KERN_ERR "Could not allocate modem xmit-buffer\n");  			retval = -ENOMEM;  			goto err_unregister;  		}  		/* Make room for T.70 header */ -		info->xmit_buf += 4; +		info->port.xmit_buf += 4;  	}  	return 0;  err_unregister: @@ -1945,7 +1841,7 @@ err_unregister:  #ifdef CONFIG_ISDN_TTY_FAX  		kfree(info->fax);  #endif -		kfree(info->xmit_buf - 4); +		kfree(info->port.xmit_buf - 4);  	}  	tty_unregister_driver(m->tty_modem);  err: @@ -1966,7 +1862,7 @@ isdn_tty_exit(void)  #ifdef CONFIG_ISDN_TTY_FAX  		kfree(info->fax);  #endif -		kfree(info->xmit_buf - 4); +		kfree(info->port.xmit_buf - 4);  	}  	tty_unregister_driver(dev->mdm.tty_modem);  	put_tty_driver(dev->mdm.tty_modem); @@ -2068,7 +1964,7 @@ isdn_tty_find_icall(int di, int ch, setup_parm *setup)  	for (i = 0; i < ISDN_MAX_CHANNELS; i++) {  		modem_info *info = &dev->mdm.info[i]; -		if (info->count == 0) +		if (info->port.count == 0)  			continue;  		if ((info->emu.mdmreg[REG_SI1] & si2bit[si1]) &&  /* SI1 is matching */  		    (info->emu.mdmreg[REG_SI2] == si2))	{         /* SI2 is matching */ @@ -2076,12 +1972,12 @@ isdn_tty_find_icall(int di, int ch, setup_parm *setup)  #ifdef ISDN_DEBUG_MODEM_ICALL  			printk(KERN_DEBUG "m_fi: match1 wret=%d\n", wret);  			printk(KERN_DEBUG "m_fi: idx=%d flags=%08lx drv=%d ch=%d usg=%d\n", idx, -			       info->flags, info->isdn_driver, info->isdn_channel, -			       dev->usage[idx]); +			       info->port.flags, info->isdn_driver, +			       info->isdn_channel, dev->usage[idx]);  #endif  			if (  #ifndef FIX_FILE_TRANSFER -				(info->flags & ISDN_ASYNC_NORMAL_ACTIVE) && +				(info->port.flags & ASYNC_NORMAL_ACTIVE) &&  #endif  				(info->isdn_driver == -1) &&  				(info->isdn_channel == -1) && @@ -2120,8 +2016,7 @@ isdn_tty_find_icall(int di, int ch, setup_parm *setup)  	return (wret == 2) ? 3 : 0;  } -#define TTY_IS_ACTIVE(info)						\ -	(info->flags & (ISDN_ASYNC_NORMAL_ACTIVE | ISDN_ASYNC_CALLOUT_ACTIVE)) +#define TTY_IS_ACTIVE(info)	(info->port.flags & ASYNC_NORMAL_ACTIVE)  int  isdn_tty_stat_callback(int i, isdn_ctrl *c) @@ -2212,9 +2107,9 @@ isdn_tty_stat_callback(int i, isdn_ctrl *c)  			 * for incoming call of this device when  			 * DCD follow the state of incoming carrier  			 */ -			if (info->blocked_open && +			if (info->port.blocked_open &&  			    (info->emu.mdmreg[REG_DCD] & BIT_DCD)) { -				wake_up_interruptible(&info->open_wait); +				wake_up_interruptible(&info->port.open_wait);  			}  			/* Schedule CONNECT-Message to any tty @@ -2222,7 +2117,8 @@ isdn_tty_stat_callback(int i, isdn_ctrl *c)  			 * set DCD-bit of its modem-status.  			 */  			if (TTY_IS_ACTIVE(info) || -			    (info->blocked_open && (info->emu.mdmreg[REG_DCD] & BIT_DCD))) { +			    (info->port.blocked_open && +			     (info->emu.mdmreg[REG_DCD] & BIT_DCD))) {  				info->msr |= UART_MSR_DCD;  				info->emu.charge = 0;  				if (info->dialing & 0xf) @@ -2339,8 +2235,8 @@ isdn_tty_at_cout(char *msg, modem_info *info)  	l = strlen(msg);  	spin_lock_irqsave(&info->readlock, flags); -	tty = info->tty; -	if ((info->flags & ISDN_ASYNC_CLOSING) || (!tty)) { +	tty = info->port.tty; +	if ((info->port.flags & ASYNC_CLOSING) || (!tty)) {  		spin_unlock_irqrestore(&info->readlock, flags);  		return;  	} @@ -2490,15 +2386,15 @@ isdn_tty_modem_result(int code, modem_info *info)  	case RESULT_NO_CARRIER:  #ifdef ISDN_DEBUG_MODEM_HUP  		printk(KERN_DEBUG "modem_result: NO CARRIER %d %d\n", -		       (info->flags & ISDN_ASYNC_CLOSING), -		       (!info->tty)); +		       (info->port.flags & ASYNC_CLOSING), +		       (!info->port.tty));  #endif  		m->mdmreg[REG_RINGCNT] = 0;  		del_timer(&info->nc_timer);  		info->ncarrier = 0; -		if ((info->flags & ISDN_ASYNC_CLOSING) || (!info->tty)) { +		if ((info->port.flags & ASYNC_CLOSING) || (!info->port.tty))  			return; -		} +  #ifdef CONFIG_ISDN_AUDIO  		if (info->vonline & 1) {  #ifdef ISDN_DEBUG_MODEM_VOICE @@ -2629,14 +2525,11 @@ isdn_tty_modem_result(int code, modem_info *info)  		}  	}  	if (code == RESULT_NO_CARRIER) { -		if ((info->flags & ISDN_ASYNC_CLOSING) || (!info->tty)) { +		if ((info->port.flags & ASYNC_CLOSING) || (!info->port.tty))  			return; -		} -		if ((info->flags & ISDN_ASYNC_CHECK_CD) && -		    (!((info->flags & ISDN_ASYNC_CALLOUT_ACTIVE) && -		       (info->flags & ISDN_ASYNC_CALLOUT_NOHUP)))) { -			tty_hangup(info->tty); -		} + +		if (info->port.flags & ASYNC_CHECK_CD) +			tty_hangup(info->port.tty);  	}  } @@ -3803,19 +3696,19 @@ isdn_tty_modem_escape(void)  	int midx;  	for (i = 0; i < ISDN_MAX_CHANNELS; i++) -		if (USG_MODEM(dev->usage[i])) -			if ((midx = dev->m_idx[i]) >= 0) { -				modem_info *info = &dev->mdm.info[midx]; -				if (info->online) { -					ton = 1; -					if ((info->emu.pluscount == 3) && -					    time_after(jiffies , info->emu.lastplus + PLUSWAIT2)) { -						info->emu.pluscount = 0; -						info->online = 0; -						isdn_tty_modem_result(RESULT_OK, info); -					} +		if (USG_MODEM(dev->usage[i]) && (midx = dev->m_idx[i]) >= 0) { +			modem_info *info = &dev->mdm.info[midx]; +			if (info->online) { +				ton = 1; +				if ((info->emu.pluscount == 3) && +				    time_after(jiffies, +					    info->emu.lastplus + PLUSWAIT2)) { +					info->emu.pluscount = 0; +					info->online = 0; +					isdn_tty_modem_result(RESULT_OK, info);  				}  			} +		}  	isdn_timer_ctrl(ISDN_TIMER_MODEMPLUS, ton);  } @@ -3873,15 +3766,14 @@ isdn_tty_carrier_timeout(void)  	for (i = 0; i < ISDN_MAX_CHANNELS; i++) {  		modem_info *info = &dev->mdm.info[i]; -		if (info->dialing) { -			if (info->emu.carrierwait++ > info->emu.mdmreg[REG_WAITC]) { -				info->dialing = 0; -				isdn_tty_modem_result(RESULT_NO_CARRIER, info); -				isdn_tty_modem_hup(info, 1); -			} -			else -				ton = 1; -		} +		if (!info->dialing) +			continue; +		if (info->emu.carrierwait++ > info->emu.mdmreg[REG_WAITC]) { +			info->dialing = 0; +			isdn_tty_modem_result(RESULT_NO_CARRIER, info); +			isdn_tty_modem_hup(info, 1); +		} else +			ton = 1;  	}  	isdn_timer_ctrl(ISDN_TIMER_CARRIER, ton);  } diff --git a/drivers/net/usb/hso.c b/drivers/net/usb/hso.c index 042c1a99520..62f30b46fa4 100644 --- a/drivers/net/usb/hso.c +++ b/drivers/net/usb/hso.c @@ -106,13 +106,6 @@  #define MAX_RX_URBS			2 -static inline struct hso_serial *get_serial_by_tty(struct tty_struct *tty) -{ -	if (tty) -		return tty->driver_data; -	return NULL; -} -  /*****************************************************************************/  /* Debugging functions                                                       */  /*****************************************************************************/ @@ -255,9 +248,8 @@ struct hso_serial {  	u8 dtr_state;  	unsigned tx_urb_used:1; +	struct tty_port port;  	/* from usb_serial_port */ -	struct tty_struct *tty; -	int open_count;  	spinlock_t serial_lock;  	int (*write_data) (struct hso_serial *serial); @@ -1114,7 +1106,7 @@ static void hso_init_termios(struct ktermios *termios)  static void _hso_serial_set_termios(struct tty_struct *tty,  				    struct ktermios *old)  { -	struct hso_serial *serial = get_serial_by_tty(tty); +	struct hso_serial *serial = tty->driver_data;  	struct ktermios *termios;  	if (!serial) { @@ -1190,7 +1182,7 @@ static void put_rxbuf_data_and_resubmit_ctrl_urb(struct hso_serial *serial)  	struct urb *urb;  	urb = serial->rx_urb[0]; -	if (serial->open_count > 0) { +	if (serial->port.count > 0) {  		count = put_rxbuf_data(urb, serial);  		if (count == -1)  			return; @@ -1226,7 +1218,7 @@ static void hso_std_serial_read_bulk_callback(struct urb *urb)  	DUMP1(urb->transfer_buffer, urb->actual_length);  	/* Anyone listening? */ -	if (serial->open_count == 0) +	if (serial->port.count == 0)  		return;  	if (status == 0) { @@ -1268,7 +1260,7 @@ static void hso_unthrottle_tasklet(struct hso_serial *serial)  static	void hso_unthrottle(struct tty_struct *tty)  { -	struct hso_serial *serial = get_serial_by_tty(tty); +	struct hso_serial *serial = tty->driver_data;  	tasklet_hi_schedule(&serial->unthrottle_tasklet);  } @@ -1304,15 +1296,12 @@ static int hso_serial_open(struct tty_struct *tty, struct file *filp)  	kref_get(&serial->parent->ref);  	/* setup */ -	spin_lock_irq(&serial->serial_lock);  	tty->driver_data = serial; -	tty_kref_put(serial->tty); -	serial->tty = tty_kref_get(tty); -	spin_unlock_irq(&serial->serial_lock); +	tty_port_tty_set(&serial->port, tty);  	/* check for port already opened, if not set the termios */ -	serial->open_count++; -	if (serial->open_count == 1) { +	serial->port.count++; +	if (serial->port.count == 1) {  		serial->rx_state = RX_IDLE;  		/* Force default termio settings */  		_hso_serial_set_termios(tty, NULL); @@ -1324,7 +1313,7 @@ static int hso_serial_open(struct tty_struct *tty, struct file *filp)  		result = hso_start_serial_device(serial->parent, GFP_KERNEL);  		if (result) {  			hso_stop_serial_device(serial->parent); -			serial->open_count--; +			serial->port.count--;  			kref_put(&serial->parent->ref, hso_serial_ref_free);  		}  	} else { @@ -1361,17 +1350,11 @@ static void hso_serial_close(struct tty_struct *tty, struct file *filp)  	/* reset the rts and dtr */  	/* do the actual close */ -	serial->open_count--; +	serial->port.count--; -	if (serial->open_count <= 0) { -		serial->open_count = 0; -		spin_lock_irq(&serial->serial_lock); -		if (serial->tty == tty) { -			serial->tty->driver_data = NULL; -			serial->tty = NULL; -			tty_kref_put(tty); -		} -		spin_unlock_irq(&serial->serial_lock); +	if (serial->port.count <= 0) { +		serial->port.count = 0; +		tty_port_tty_set(&serial->port, NULL);  		if (!usb_gone)  			hso_stop_serial_device(serial->parent);  		tasklet_kill(&serial->unthrottle_tasklet); @@ -1390,7 +1373,7 @@ static void hso_serial_close(struct tty_struct *tty, struct file *filp)  static int hso_serial_write(struct tty_struct *tty, const unsigned char *buf,  			    int count)  { -	struct hso_serial *serial = get_serial_by_tty(tty); +	struct hso_serial *serial = tty->driver_data;  	int space, tx_bytes;  	unsigned long flags; @@ -1422,7 +1405,7 @@ out:  /* how much room is there for writing */  static int hso_serial_write_room(struct tty_struct *tty)  { -	struct hso_serial *serial = get_serial_by_tty(tty); +	struct hso_serial *serial = tty->driver_data;  	int room;  	unsigned long flags; @@ -1437,7 +1420,7 @@ static int hso_serial_write_room(struct tty_struct *tty)  /* setup the term */  static void hso_serial_set_termios(struct tty_struct *tty, struct ktermios *old)  { -	struct hso_serial *serial = get_serial_by_tty(tty); +	struct hso_serial *serial = tty->driver_data;  	unsigned long flags;  	if (old) @@ -1446,7 +1429,7 @@ static void hso_serial_set_termios(struct tty_struct *tty, struct ktermios *old)  	/* the actual setup */  	spin_lock_irqsave(&serial->serial_lock, flags); -	if (serial->open_count) +	if (serial->port.count)  		_hso_serial_set_termios(tty, old);  	else  		tty->termios = old; @@ -1458,7 +1441,7 @@ static void hso_serial_set_termios(struct tty_struct *tty, struct ktermios *old)  /* how many characters in the buffer */  static int hso_serial_chars_in_buffer(struct tty_struct *tty)  { -	struct hso_serial *serial = get_serial_by_tty(tty); +	struct hso_serial *serial = tty->driver_data;  	int chars;  	unsigned long flags; @@ -1629,7 +1612,7 @@ static int hso_get_count(struct tty_struct *tty,  		  struct serial_icounter_struct *icount)  {  	struct uart_icount cnow; -	struct hso_serial *serial = get_serial_by_tty(tty); +	struct hso_serial *serial = tty->driver_data;  	struct hso_tiocmget  *tiocmget = serial->tiocmget;  	memset(icount, 0, sizeof(struct serial_icounter_struct)); @@ -1659,7 +1642,7 @@ static int hso_get_count(struct tty_struct *tty,  static int hso_serial_tiocmget(struct tty_struct *tty)  {  	int retval; -	struct hso_serial *serial = get_serial_by_tty(tty); +	struct hso_serial *serial = tty->driver_data;  	struct hso_tiocmget  *tiocmget;  	u16 UART_state_bitmap; @@ -1693,7 +1676,7 @@ static int hso_serial_tiocmset(struct tty_struct *tty,  	int val = 0;  	unsigned long flags;  	int if_num; -	struct hso_serial *serial = get_serial_by_tty(tty); +	struct hso_serial *serial = tty->driver_data;  	/* sanity check */  	if (!serial) { @@ -1733,7 +1716,7 @@ static int hso_serial_tiocmset(struct tty_struct *tty,  static int hso_serial_ioctl(struct tty_struct *tty,  			    unsigned int cmd, unsigned long arg)  { -	struct hso_serial *serial =  get_serial_by_tty(tty); +	struct hso_serial *serial = tty->driver_data;  	int ret = 0;  	D4("IOCTL cmd: %d, arg: %ld", cmd, arg); @@ -1905,7 +1888,7 @@ static void intr_callback(struct urb *urb)  				D1("Pending read interrupt on port %d\n", i);  				spin_lock(&serial->serial_lock);  				if (serial->rx_state == RX_IDLE && -					serial->open_count > 0) { +					serial->port.count > 0) {  					/* Setup and send a ctrl req read on  					 * port i */  					if (!serial->rx_urb_filled[0]) { @@ -1954,14 +1937,13 @@ static void hso_std_serial_write_bulk_callback(struct urb *urb)  	spin_lock(&serial->serial_lock);  	serial->tx_urb_used = 0; -	tty = tty_kref_get(serial->tty);  	spin_unlock(&serial->serial_lock);  	if (status) {  		handle_usb_error(status, __func__, serial->parent); -		tty_kref_put(tty);  		return;  	}  	hso_put_activity(serial->parent); +	tty = tty_port_tty_get(&serial->port);  	if (tty) {  		tty_wakeup(tty);  		tty_kref_put(tty); @@ -2001,7 +1983,6 @@ static void ctrl_callback(struct urb *urb)  	struct hso_serial *serial = urb->context;  	struct usb_ctrlrequest *req;  	int status = urb->status; -	struct tty_struct *tty;  	/* sanity check */  	if (!serial) @@ -2009,11 +1990,9 @@ static void ctrl_callback(struct urb *urb)  	spin_lock(&serial->serial_lock);  	serial->tx_urb_used = 0; -	tty = tty_kref_get(serial->tty);  	spin_unlock(&serial->serial_lock);  	if (status) {  		handle_usb_error(status, __func__, serial->parent); -		tty_kref_put(tty);  		return;  	} @@ -2031,13 +2010,15 @@ static void ctrl_callback(struct urb *urb)  		put_rxbuf_data_and_resubmit_ctrl_urb(serial);  		spin_unlock(&serial->serial_lock);  	} else { +		struct tty_struct *tty = tty_port_tty_get(&serial->port);  		hso_put_activity(serial->parent); -		if (tty) +		if (tty) {  			tty_wakeup(tty); +			tty_kref_put(tty); +		}  		/* response to a write command */  		hso_kick_transmit(serial);  	} -	tty_kref_put(tty);  }  /* handle RX data for serial port */ @@ -2053,8 +2034,7 @@ static int put_rxbuf_data(struct urb *urb, struct hso_serial *serial)  		return -2;  	} -	/* All callers to put_rxbuf_data hold serial_lock */ -	tty = tty_kref_get(serial->tty); +	tty = tty_port_tty_get(&serial->port);  	/* Push data to tty */  	if (tty) { @@ -2074,12 +2054,12 @@ static int put_rxbuf_data(struct urb *urb, struct hso_serial *serial)  			write_length_remaining -= curr_write_len;  			tty_flip_buffer_push(tty);  		} +		tty_kref_put(tty);  	}  	if (write_length_remaining == 0) {  		serial->curr_rx_urb_offset = 0;  		serial->rx_urb_filled[hso_urb_to_index(serial, urb)] = 0;  	} -	tty_kref_put(tty);  	return write_length_remaining;  } @@ -2320,6 +2300,7 @@ static int hso_serial_common_create(struct hso_serial *serial, int num_urbs,  	serial->minor = minor;  	serial->magic = HSO_SERIAL_MAGIC;  	spin_lock_init(&serial->serial_lock); +	tty_port_init(&serial->port);  	serial->num_rx_urbs = num_urbs;  	/* RX, allocate urb and initialize */ @@ -3098,7 +3079,7 @@ static int hso_resume(struct usb_interface *iface)  	/* Start all serial ports */  	for (i = 0; i < HSO_SERIAL_TTY_MINORS; i++) {  		if (serial_table[i] && (serial_table[i]->interface == iface)) { -			if (dev2ser(serial_table[i])->open_count) { +			if (dev2ser(serial_table[i])->port.count) {  				result =  				    hso_start_serial_device(serial_table[i], GFP_NOIO);  				hso_kick_transmit(dev2ser(serial_table[i])); @@ -3172,13 +3153,12 @@ static void hso_free_interface(struct usb_interface *interface)  		if (serial_table[i] &&  		    (serial_table[i]->interface == interface)) {  			hso_dev = dev2ser(serial_table[i]); -			spin_lock_irq(&hso_dev->serial_lock); -			tty = tty_kref_get(hso_dev->tty); -			spin_unlock_irq(&hso_dev->serial_lock); -			if (tty) +			tty = tty_port_tty_get(&hso_dev->port); +			if (tty) {  				tty_hangup(tty); +				tty_kref_put(tty); +			}  			mutex_lock(&hso_dev->parent->mutex); -			tty_kref_put(tty);  			hso_dev->parent->usb_gone = 1;  			mutex_unlock(&hso_dev->parent->mutex);  			kref_put(&serial_table[i]->ref, hso_serial_ref_free); @@ -3313,7 +3293,6 @@ static int __init hso_init(void)  		return -ENOMEM;  	/* fill in all needed values */ -	tty_drv->magic = TTY_DRIVER_MAGIC;  	tty_drv->driver_name = driver_name;  	tty_drv->name = tty_filename; @@ -3334,7 +3313,7 @@ static int __init hso_init(void)  	if (result) {  		printk(KERN_ERR "%s - tty_register_driver failed(%d)\n",  			__func__, result); -		return result; +		goto err_free_tty;  	}  	/* register this module as an usb driver */ @@ -3342,13 +3321,16 @@ static int __init hso_init(void)  	if (result) {  		printk(KERN_ERR "Could not register hso driver? error: %d\n",  			result); -		/* cleanup serial interface */ -		tty_unregister_driver(tty_drv); -		return result; +		goto err_unreg_tty;  	}  	/* done */  	return 0; +err_unreg_tty: +	tty_unregister_driver(tty_drv); +err_free_tty: +	put_tty_driver(tty_drv); +	return result;  }  static void __exit hso_exit(void) @@ -3356,6 +3338,7 @@ static void __exit hso_exit(void)  	printk(KERN_INFO "hso: unloaded\n");  	tty_unregister_driver(tty_drv); +	put_tty_driver(tty_drv);  	/* deregister the usb driver */  	usb_deregister(&hso_driver);  } diff --git a/drivers/s390/char/con3215.c b/drivers/s390/char/con3215.c index 4f9f1dcc155..6c0116d48c7 100644 --- a/drivers/s390/char/con3215.c +++ b/drivers/s390/char/con3215.c @@ -20,6 +20,7 @@  #include <linux/interrupt.h>  #include <linux/err.h>  #include <linux/reboot.h> +#include <linux/serial.h> /* ASYNC_* flags */  #include <linux/slab.h>  #include <asm/ccwdev.h>  #include <asm/cio.h> @@ -44,14 +45,11 @@  #define RAW3215_TIMEOUT	    HZ/10     /* time for delayed output */  #define RAW3215_FIXED	    1	      /* 3215 console device is not be freed */ -#define RAW3215_ACTIVE	    2	      /* set if the device is in use */  #define RAW3215_WORKING	    4	      /* set if a request is being worked on */  #define RAW3215_THROTTLED   8	      /* set if reading is disabled */  #define RAW3215_STOPPED	    16	      /* set if writing is disabled */ -#define RAW3215_CLOSING	    32	      /* set while in close process */  #define RAW3215_TIMER_RUNS  64	      /* set if the output delay timer is on */  #define RAW3215_FLUSHING    128	      /* set to flush buffer (no delay) */ -#define RAW3215_FROZEN	    256	      /* set if 3215 is frozen for suspend */  #define TAB_STOP_SIZE	    8	      /* tab stop size */ @@ -76,6 +74,7 @@ struct raw3215_req {  } __attribute__ ((aligned(8)));  struct raw3215_info { +	struct tty_port port;  	struct ccw_device *cdev;      /* device for tty driver */  	spinlock_t *lock;	      /* pointer to irq lock */  	int flags;		      /* state flags */ @@ -84,7 +83,6 @@ struct raw3215_info {  	int head;		      /* first free byte in output buffer */  	int count;		      /* number of bytes in output buffer */  	int written;		      /* number of bytes in write requests */ -	struct tty_struct *tty;	      /* pointer to tty structure if present */  	struct raw3215_req *queued_read; /* pointer to queued read requests */  	struct raw3215_req *queued_write;/* pointer to queued write requests */  	struct tasklet_struct tlet;   /* tasklet to invoke tty_wakeup */ @@ -293,7 +291,7 @@ static void raw3215_timeout(unsigned long __data)  	if (raw->flags & RAW3215_TIMER_RUNS) {  		del_timer(&raw->timer);  		raw->flags &= ~RAW3215_TIMER_RUNS; -		if (!(raw->flags & RAW3215_FROZEN)) { +		if (!(raw->port.flags & ASYNC_SUSPENDED)) {  			raw3215_mk_write_req(raw);  			raw3215_start_io(raw);  		} @@ -309,7 +307,8 @@ static void raw3215_timeout(unsigned long __data)   */  static inline void raw3215_try_io(struct raw3215_info *raw)  { -	if (!(raw->flags & RAW3215_ACTIVE) || (raw->flags & RAW3215_FROZEN)) +	if (!(raw->port.flags & ASYNC_INITIALIZED) || +			(raw->port.flags & ASYNC_SUSPENDED))  		return;  	if (raw->queued_read != NULL)  		raw3215_start_io(raw); @@ -324,10 +323,7 @@ static inline void raw3215_try_io(struct raw3215_info *raw)  			}  		} else if (!(raw->flags & RAW3215_TIMER_RUNS)) {  			/* delay small writes */ -			init_timer(&raw->timer);  			raw->timer.expires = RAW3215_TIMEOUT + jiffies; -			raw->timer.data = (unsigned long) raw; -			raw->timer.function = raw3215_timeout;  			add_timer(&raw->timer);  			raw->flags |= RAW3215_TIMER_RUNS;  		} @@ -340,17 +336,21 @@ static inline void raw3215_try_io(struct raw3215_info *raw)  static void raw3215_wakeup(unsigned long data)  {  	struct raw3215_info *raw = (struct raw3215_info *) data; -	tty_wakeup(raw->tty); +	struct tty_struct *tty; + +	tty = tty_port_tty_get(&raw->port); +	tty_wakeup(tty); +	tty_kref_put(tty);  }  /*   * Try to start the next IO and wake up processes waiting on the tty.   */ -static void raw3215_next_io(struct raw3215_info *raw) +static void raw3215_next_io(struct raw3215_info *raw, struct tty_struct *tty)  {  	raw3215_mk_write_req(raw);  	raw3215_try_io(raw); -	if (raw->tty && RAW3215_BUFFER_SIZE - raw->count >= RAW3215_MIN_SPACE) +	if (tty && RAW3215_BUFFER_SIZE - raw->count >= RAW3215_MIN_SPACE)  		tasklet_schedule(&raw->tlet);  } @@ -368,10 +368,11 @@ static void raw3215_irq(struct ccw_device *cdev, unsigned long intparm,  	raw = dev_get_drvdata(&cdev->dev);  	req = (struct raw3215_req *) intparm; +	tty = tty_port_tty_get(&raw->port);  	cstat = irb->scsw.cmd.cstat;  	dstat = irb->scsw.cmd.dstat;  	if (cstat != 0) -		raw3215_next_io(raw); +		raw3215_next_io(raw, tty);  	if (dstat & 0x01) { /* we got a unit exception */  		dstat &= ~0x01;	 /* we can ignore it */  	} @@ -381,13 +382,13 @@ static void raw3215_irq(struct ccw_device *cdev, unsigned long intparm,  			break;  		/* Attention interrupt, someone hit the enter key */  		raw3215_mk_read_req(raw); -		raw3215_next_io(raw); +		raw3215_next_io(raw, tty);  		break;  	case 0x08:  	case 0x0C:  		/* Channel end interrupt. */  		if ((raw = req->info) == NULL) -			return;		     /* That shouldn't happen ... */ +			goto put_tty;	     /* That shouldn't happen ... */  		if (req->type == RAW3215_READ) {  			/* store residual count, then wait for device end */  			req->residual = irb->scsw.cmd.count; @@ -397,11 +398,10 @@ static void raw3215_irq(struct ccw_device *cdev, unsigned long intparm,  	case 0x04:  		/* Device end interrupt. */  		if ((raw = req->info) == NULL) -			return;		     /* That shouldn't happen ... */ -		if (req->type == RAW3215_READ && raw->tty != NULL) { +			goto put_tty;	     /* That shouldn't happen ... */ +		if (req->type == RAW3215_READ && tty != NULL) {  			unsigned int cchar; -			tty = raw->tty;  			count = 160 - req->residual;  			EBCASC(raw->inbuf, count);  			cchar = ctrlchar_handle(raw->inbuf, count, tty); @@ -411,7 +411,7 @@ static void raw3215_irq(struct ccw_device *cdev, unsigned long intparm,  			case CTRLCHAR_CTRL:  				tty_insert_flip_char(tty, cchar, TTY_NORMAL); -				tty_flip_buffer_push(raw->tty); +				tty_flip_buffer_push(tty);  				break;  			case CTRLCHAR_NONE: @@ -424,7 +424,7 @@ static void raw3215_irq(struct ccw_device *cdev, unsigned long intparm,  				} else  					count -= 2;  				tty_insert_flip_string(tty, raw->inbuf, count); -				tty_flip_buffer_push(raw->tty); +				tty_flip_buffer_push(tty);  				break;  			}  		} else if (req->type == RAW3215_WRITE) { @@ -439,7 +439,7 @@ static void raw3215_irq(struct ccw_device *cdev, unsigned long intparm,  		    raw->queued_read == NULL) {  			wake_up_interruptible(&raw->empty_wait);  		} -		raw3215_next_io(raw); +		raw3215_next_io(raw, tty);  		break;  	default:  		/* Strange interrupt, I'll do my best to clean up */ @@ -451,9 +451,10 @@ static void raw3215_irq(struct ccw_device *cdev, unsigned long intparm,  			raw->flags &= ~RAW3215_WORKING;  			raw3215_free_req(req);  		} -		raw3215_next_io(raw); +		raw3215_next_io(raw, tty);  	} -	return; +put_tty: +	tty_kref_put(tty);  }  /* @@ -487,7 +488,7 @@ static void raw3215_make_room(struct raw3215_info *raw, unsigned int length)  		/* While console is frozen for suspend we have no other  		 * choice but to drop message from the buffer to make  		 * room for even more messages. */ -		if (raw->flags & RAW3215_FROZEN) { +		if (raw->port.flags & ASYNC_SUSPENDED) {  			raw3215_drop_line(raw);  			continue;  		} @@ -609,10 +610,10 @@ static int raw3215_startup(struct raw3215_info *raw)  {  	unsigned long flags; -	if (raw->flags & RAW3215_ACTIVE) +	if (raw->port.flags & ASYNC_INITIALIZED)  		return 0;  	raw->line_pos = 0; -	raw->flags |= RAW3215_ACTIVE; +	raw->port.flags |= ASYNC_INITIALIZED;  	spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags);  	raw3215_try_io(raw);  	spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags); @@ -628,14 +629,15 @@ static void raw3215_shutdown(struct raw3215_info *raw)  	DECLARE_WAITQUEUE(wait, current);  	unsigned long flags; -	if (!(raw->flags & RAW3215_ACTIVE) || (raw->flags & RAW3215_FIXED)) +	if (!(raw->port.flags & ASYNC_INITIALIZED) || +			(raw->flags & RAW3215_FIXED))  		return;  	/* Wait for outstanding requests, then free irq */  	spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags);  	if ((raw->flags & RAW3215_WORKING) ||  	    raw->queued_write != NULL ||  	    raw->queued_read != NULL) { -		raw->flags |= RAW3215_CLOSING; +		raw->port.flags |= ASYNC_CLOSING;  		add_wait_queue(&raw->empty_wait, &wait);  		set_current_state(TASK_INTERRUPTIBLE);  		spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags); @@ -643,11 +645,41 @@ static void raw3215_shutdown(struct raw3215_info *raw)  		spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags);  		remove_wait_queue(&raw->empty_wait, &wait);  		set_current_state(TASK_RUNNING); -		raw->flags &= ~(RAW3215_ACTIVE | RAW3215_CLOSING); +		raw->port.flags &= ~(ASYNC_INITIALIZED | ASYNC_CLOSING);  	}  	spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags);  } +static struct raw3215_info *raw3215_alloc_info(void) +{ +	struct raw3215_info *info; + +	info = kzalloc(sizeof(struct raw3215_info), GFP_KERNEL | GFP_DMA); +	if (!info) +		return NULL; + +	info->buffer = kzalloc(RAW3215_BUFFER_SIZE, GFP_KERNEL | GFP_DMA); +	info->inbuf = kzalloc(RAW3215_INBUF_SIZE, GFP_KERNEL | GFP_DMA); +	if (!info->buffer || !info->inbuf) { +		kfree(info); +		return NULL; +	} + +	setup_timer(&info->timer, raw3215_timeout, (unsigned long)info); +	init_waitqueue_head(&info->empty_wait); +	tasklet_init(&info->tlet, raw3215_wakeup, (unsigned long)info); +	tty_port_init(&info->port); + +	return info; +} + +static void raw3215_free_info(struct raw3215_info *raw) +{ +	kfree(raw->inbuf); +	kfree(raw->buffer); +	kfree(raw); +} +  static int raw3215_probe (struct ccw_device *cdev)  {  	struct raw3215_info *raw; @@ -656,11 +688,15 @@ static int raw3215_probe (struct ccw_device *cdev)  	/* Console is special. */  	if (raw3215[0] && (raw3215[0] == dev_get_drvdata(&cdev->dev)))  		return 0; -	raw = kmalloc(sizeof(struct raw3215_info) + -		      RAW3215_INBUF_SIZE, GFP_KERNEL|GFP_DMA); + +	raw = raw3215_alloc_info();  	if (raw == NULL)  		return -ENOMEM; +	raw->cdev = cdev; +	dev_set_drvdata(&cdev->dev, raw); +	cdev->handler = raw3215_irq; +  	spin_lock(&raw3215_device_lock);  	for (line = 0; line < NR_3215; line++) {  		if (!raw3215[line]) { @@ -670,28 +706,10 @@ static int raw3215_probe (struct ccw_device *cdev)  	}  	spin_unlock(&raw3215_device_lock);  	if (line == NR_3215) { -		kfree(raw); +		raw3215_free_info(raw);  		return -ENODEV;  	} -	raw->cdev = cdev; -	raw->inbuf = (char *) raw + sizeof(struct raw3215_info); -	memset(raw, 0, sizeof(struct raw3215_info)); -	raw->buffer = kmalloc(RAW3215_BUFFER_SIZE, -				       GFP_KERNEL|GFP_DMA); -	if (raw->buffer == NULL) { -		spin_lock(&raw3215_device_lock); -		raw3215[line] = NULL; -		spin_unlock(&raw3215_device_lock); -		kfree(raw); -		return -ENOMEM; -	} -	init_waitqueue_head(&raw->empty_wait); -	tasklet_init(&raw->tlet, raw3215_wakeup, (unsigned long) raw); - -	dev_set_drvdata(&cdev->dev, raw); -	cdev->handler = raw3215_irq; -  	return 0;  } @@ -703,8 +721,7 @@ static void raw3215_remove (struct ccw_device *cdev)  	raw = dev_get_drvdata(&cdev->dev);  	if (raw) {  		dev_set_drvdata(&cdev->dev, NULL); -		kfree(raw->buffer); -		kfree(raw); +		raw3215_free_info(raw);  	}  } @@ -741,7 +758,7 @@ static int raw3215_pm_stop(struct ccw_device *cdev)  	raw = dev_get_drvdata(&cdev->dev);  	spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags);  	raw3215_make_room(raw, RAW3215_BUFFER_SIZE); -	raw->flags |= RAW3215_FROZEN; +	raw->port.flags |= ASYNC_SUSPENDED;  	spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags);  	return 0;  } @@ -754,7 +771,7 @@ static int raw3215_pm_start(struct ccw_device *cdev)  	/* Allow I/O again and flush output buffer. */  	raw = dev_get_drvdata(&cdev->dev);  	spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags); -	raw->flags &= ~RAW3215_FROZEN; +	raw->port.flags &= ~ASYNC_SUSPENDED;  	raw->flags |= RAW3215_FLUSHING;  	raw3215_try_io(raw);  	raw->flags &= ~RAW3215_FLUSHING; @@ -827,7 +844,7 @@ static void con3215_flush(void)  	unsigned long flags;  	raw = raw3215[0];  /* console 3215 is the first one */ -	if (raw->flags & RAW3215_FROZEN) +	if (raw->port.flags & ASYNC_SUSPENDED)  		/* The console is still frozen for suspend. */  		if (ccw_device_force_console())  			/* Forcing didn't work, no panic message .. */ @@ -897,23 +914,16 @@ static int __init con3215_init(void)  	if (IS_ERR(cdev))  		return -ENODEV; -	raw3215[0] = raw = (struct raw3215_info *) -		kzalloc(sizeof(struct raw3215_info), GFP_KERNEL | GFP_DMA); -	raw->buffer = kzalloc(RAW3215_BUFFER_SIZE, GFP_KERNEL | GFP_DMA); -	raw->inbuf = kzalloc(RAW3215_INBUF_SIZE, GFP_KERNEL | GFP_DMA); +	raw3215[0] = raw = raw3215_alloc_info();  	raw->cdev = cdev;  	dev_set_drvdata(&cdev->dev, raw);  	cdev->handler = raw3215_irq;  	raw->flags |= RAW3215_FIXED; -	init_waitqueue_head(&raw->empty_wait); -	tasklet_init(&raw->tlet, raw3215_wakeup, (unsigned long) raw);  	/* Request the console irq */  	if (raw3215_startup(raw) != 0) { -		kfree(raw->inbuf); -		kfree(raw->buffer); -		kfree(raw); +		raw3215_free_info(raw);  		raw3215[0] = NULL;  		return -ENODEV;  	} @@ -940,7 +950,7 @@ static int tty3215_open(struct tty_struct *tty, struct file * filp)  		return -ENODEV;  	tty->driver_data = raw; -	raw->tty = tty; +	tty_port_tty_set(&raw->port, tty);  	tty->low_latency = 0;  /* don't use bottom half for pushing chars */  	/* @@ -971,7 +981,7 @@ static void tty3215_close(struct tty_struct *tty, struct file * filp)  	raw3215_shutdown(raw);  	tasklet_kill(&raw->tlet);  	tty->closing = 0; -	raw->tty = NULL; +	tty_port_tty_set(&raw->port, NULL);  }  /* diff --git a/drivers/s390/char/keyboard.c b/drivers/s390/char/keyboard.c index 80658819248..7ef9cfdc17d 100644 --- a/drivers/s390/char/keyboard.c +++ b/drivers/s390/char/keyboard.c @@ -199,7 +199,7 @@ handle_diacr(struct kbd_data *kbd, unsigned int ch)  	if (ch == ' ' || ch == d)  		return d; -	kbd_put_queue(kbd->tty, d); +	kbd_put_queue(kbd->port, d);  	return ch;  } @@ -221,7 +221,7 @@ k_self(struct kbd_data *kbd, unsigned char value)  {  	if (kbd->diacr)  		value = handle_diacr(kbd, value); -	kbd_put_queue(kbd->tty, value); +	kbd_put_queue(kbd->port, value);  }  /* @@ -239,7 +239,7 @@ static void  k_fn(struct kbd_data *kbd, unsigned char value)  {  	if (kbd->func_table[value]) -		kbd_puts_queue(kbd->tty, kbd->func_table[value]); +		kbd_puts_queue(kbd->port, kbd->func_table[value]);  }  static void @@ -257,20 +257,20 @@ k_spec(struct kbd_data *kbd, unsigned char value)   * but we need only 16 bits here   */  static void -to_utf8(struct tty_struct *tty, ushort c)  +to_utf8(struct tty_port *port, ushort c)  {  	if (c < 0x80)  		/*  0******* */ -		kbd_put_queue(tty, c); +		kbd_put_queue(port, c);  	else if (c < 0x800) {  		/* 110***** 10****** */ -		kbd_put_queue(tty, 0xc0 | (c >> 6)); -		kbd_put_queue(tty, 0x80 | (c & 0x3f)); +		kbd_put_queue(port, 0xc0 | (c >> 6)); +		kbd_put_queue(port, 0x80 | (c & 0x3f));  	} else {  		/* 1110**** 10****** 10****** */ -		kbd_put_queue(tty, 0xe0 | (c >> 12)); -		kbd_put_queue(tty, 0x80 | ((c >> 6) & 0x3f)); -		kbd_put_queue(tty, 0x80 | (c & 0x3f)); +		kbd_put_queue(port, 0xe0 | (c >> 12)); +		kbd_put_queue(port, 0x80 | ((c >> 6) & 0x3f)); +		kbd_put_queue(port, 0x80 | (c & 0x3f));  	}  } @@ -283,7 +283,7 @@ kbd_keycode(struct kbd_data *kbd, unsigned int keycode)  	unsigned short keysym;  	unsigned char type, value; -	if (!kbd || !kbd->tty) +	if (!kbd)  		return;  	if (keycode >= 384) @@ -323,7 +323,7 @@ kbd_keycode(struct kbd_data *kbd, unsigned int keycode)  #endif  		(*k_handler[type])(kbd, value);  	} else -		to_utf8(kbd->tty, keysym); +		to_utf8(kbd->port, keysym);  }  /* @@ -457,6 +457,7 @@ do_kdgkb_ioctl(struct kbd_data *kbd, struct kbsentry __user *u_kbs,  int kbd_ioctl(struct kbd_data *kbd, unsigned int cmd, unsigned long arg)  { +	struct tty_struct *tty;  	void __user *argp;  	unsigned int ct;  	int perm; @@ -467,7 +468,10 @@ int kbd_ioctl(struct kbd_data *kbd, unsigned int cmd, unsigned long arg)  	 * To have permissions to do most of the vt ioctls, we either have  	 * to be the owner of the tty, or have CAP_SYS_TTY_CONFIG.  	 */ -	perm = current->signal->tty == kbd->tty || capable(CAP_SYS_TTY_CONFIG); +	tty = tty_port_tty_get(kbd->port); +	/* FIXME this test is pretty racy */ +	perm = current->signal->tty == tty || capable(CAP_SYS_TTY_CONFIG); +	tty_kref_put(tty);  	switch (cmd) {  	case KDGKBTYPE:  		return put_user(KB_101, (char __user *)argp); diff --git a/drivers/s390/char/keyboard.h b/drivers/s390/char/keyboard.h index 7e736aaeae6..f682f4e4968 100644 --- a/drivers/s390/char/keyboard.h +++ b/drivers/s390/char/keyboard.h @@ -21,7 +21,7 @@ typedef void (fn_handler_fn)(struct kbd_data *);   */  struct kbd_data { -	struct tty_struct *tty; +	struct tty_port *port;  	unsigned short **key_maps;  	char **func_table;  	fn_handler_fn **fn_handler; @@ -42,16 +42,24 @@ int kbd_ioctl(struct kbd_data *, unsigned int, unsigned long);   * Helper Functions.   */  static inline void -kbd_put_queue(struct tty_struct *tty, int ch) +kbd_put_queue(struct tty_port *port, int ch)  { +	struct tty_struct *tty = tty_port_tty_get(port); +	if (!tty) +		return;  	tty_insert_flip_char(tty, ch, 0);  	tty_schedule_flip(tty); +	tty_kref_put(tty);  }  static inline void -kbd_puts_queue(struct tty_struct *tty, char *cp) +kbd_puts_queue(struct tty_port *port, char *cp)  { +	struct tty_struct *tty = tty_port_tty_get(port); +	if (!tty) +		return;  	while (*cp)  		tty_insert_flip_char(tty, *cp++, 0);  	tty_schedule_flip(tty); +	tty_kref_put(tty);  } diff --git a/drivers/s390/char/sclp_tty.c b/drivers/s390/char/sclp_tty.c index 40a9d69c898..e66a75b3822 100644 --- a/drivers/s390/char/sclp_tty.c +++ b/drivers/s390/char/sclp_tty.c @@ -48,7 +48,7 @@ static struct sclp_buffer *sclp_ttybuf;  /* Timer for delayed output of console messages. */  static struct timer_list sclp_tty_timer; -static struct tty_struct *sclp_tty; +static struct tty_port sclp_port;  static unsigned char sclp_tty_chars[SCLP_TTY_BUF_SIZE];  static unsigned short int sclp_tty_chars_count; @@ -64,7 +64,7 @@ static int sclp_tty_columns = 80;  static int  sclp_tty_open(struct tty_struct *tty, struct file *filp)  { -	sclp_tty = tty; +	tty_port_tty_set(&sclp_port, tty);  	tty->driver_data = NULL;  	tty->low_latency = 0;  	return 0; @@ -76,7 +76,7 @@ sclp_tty_close(struct tty_struct *tty, struct file *filp)  {  	if (tty->count > 1)  		return; -	sclp_tty = NULL; +	tty_port_tty_set(&sclp_port, NULL);  }  /* @@ -108,6 +108,7 @@ sclp_tty_write_room (struct tty_struct *tty)  static void  sclp_ttybuf_callback(struct sclp_buffer *buffer, int rc)  { +	struct tty_struct *tty;  	unsigned long flags;  	void *page; @@ -126,8 +127,10 @@ sclp_ttybuf_callback(struct sclp_buffer *buffer, int rc)  		spin_unlock_irqrestore(&sclp_tty_lock, flags);  	} while (buffer && sclp_emit_buffer(buffer, sclp_ttybuf_callback));  	/* check if the tty needs a wake up call */ -	if (sclp_tty != NULL) { -		tty_wakeup(sclp_tty); +	tty = tty_port_tty_get(&sclp_port); +	if (tty != NULL) { +		tty_wakeup(tty); +		tty_kref_put(tty);  	}  } @@ -326,21 +329,22 @@ sclp_tty_flush_buffer(struct tty_struct *tty)  static void  sclp_tty_input(unsigned char* buf, unsigned int count)  { +	struct tty_struct *tty = tty_port_tty_get(&sclp_port);  	unsigned int cchar;  	/*  	 * If this tty driver is currently closed  	 * then throw the received input away.  	 */ -	if (sclp_tty == NULL) +	if (tty == NULL)  		return; -	cchar = ctrlchar_handle(buf, count, sclp_tty); +	cchar = ctrlchar_handle(buf, count, tty);  	switch (cchar & CTRLCHAR_MASK) {  	case CTRLCHAR_SYSRQ:  		break;  	case CTRLCHAR_CTRL: -		tty_insert_flip_char(sclp_tty, cchar, TTY_NORMAL); -		tty_flip_buffer_push(sclp_tty); +		tty_insert_flip_char(tty, cchar, TTY_NORMAL); +		tty_flip_buffer_push(tty);  		break;  	case CTRLCHAR_NONE:  		/* send (normal) input to line discipline */ @@ -348,13 +352,14 @@ sclp_tty_input(unsigned char* buf, unsigned int count)  		    (strncmp((const char *) buf + count - 2, "^n", 2) &&  		     strncmp((const char *) buf + count - 2, "\252n", 2))) {  			/* add the auto \n */ -			tty_insert_flip_string(sclp_tty, buf, count); -			tty_insert_flip_char(sclp_tty, '\n', TTY_NORMAL); +			tty_insert_flip_string(tty, buf, count); +			tty_insert_flip_char(tty, '\n', TTY_NORMAL);  		} else -			tty_insert_flip_string(sclp_tty, buf, count - 2); -		tty_flip_buffer_push(sclp_tty); +			tty_insert_flip_string(tty, buf, count - 2); +		tty_flip_buffer_push(tty);  		break;  	} +	tty_kref_put(tty);  }  /* @@ -543,7 +548,7 @@ sclp_tty_init(void)  		sclp_tty_tolower = 1;  	}  	sclp_tty_chars_count = 0; -	sclp_tty = NULL; +	tty_port_init(&sclp_port);  	rc = sclp_register(&sclp_input_event);  	if (rc) { diff --git a/drivers/s390/char/sclp_vt220.c b/drivers/s390/char/sclp_vt220.c index b635472ae66..edfc0fd73dc 100644 --- a/drivers/s390/char/sclp_vt220.c +++ b/drivers/s390/char/sclp_vt220.c @@ -34,7 +34,6 @@  #define SCLP_VT220_DEVICE_NAME		"ttysclp"  #define SCLP_VT220_CONSOLE_NAME		"ttyS"  #define SCLP_VT220_CONSOLE_INDEX	1	/* console=ttyS1 */ -#define SCLP_VT220_BUF_SIZE		80  /* Representation of a single write request */  struct sclp_vt220_request { @@ -56,8 +55,7 @@ struct sclp_vt220_sccb {  /* Structures and data needed to register tty driver */  static struct tty_driver *sclp_vt220_driver; -/* The tty_struct that the kernel associated with us */ -static struct tty_struct *sclp_vt220_tty; +static struct tty_port sclp_vt220_port;  /* Lock to protect internal data from concurrent access */  static spinlock_t sclp_vt220_lock; @@ -116,6 +114,7 @@ static struct sclp_register sclp_vt220_register = {  static void  sclp_vt220_process_queue(struct sclp_vt220_request *request)  { +	struct tty_struct *tty;  	unsigned long flags;  	void *page; @@ -141,8 +140,10 @@ sclp_vt220_process_queue(struct sclp_vt220_request *request)  	if (request == NULL && sclp_vt220_flush_later)  		sclp_vt220_emit_current();  	/* Check if the tty needs a wake up call */ -	if (sclp_vt220_tty != NULL) { -		tty_wakeup(sclp_vt220_tty); +	tty = tty_port_tty_get(&sclp_vt220_port); +	if (tty) { +		tty_wakeup(tty); +		tty_kref_put(tty);  	}  } @@ -460,11 +461,12 @@ sclp_vt220_write(struct tty_struct *tty, const unsigned char *buf, int count)  static void  sclp_vt220_receiver_fn(struct evbuf_header *evbuf)  { +	struct tty_struct *tty = tty_port_tty_get(&sclp_vt220_port);  	char *buffer;  	unsigned int count;  	/* Ignore input if device is not open */ -	if (sclp_vt220_tty == NULL) +	if (tty == NULL)  		return;  	buffer = (char *) ((addr_t) evbuf + sizeof(struct evbuf_header)); @@ -478,10 +480,11 @@ sclp_vt220_receiver_fn(struct evbuf_header *evbuf)  		/* Send input to line discipline */  		buffer++;  		count--; -		tty_insert_flip_string(sclp_vt220_tty, buffer, count); -		tty_flip_buffer_push(sclp_vt220_tty); +		tty_insert_flip_string(tty, buffer, count); +		tty_flip_buffer_push(tty);  		break;  	} +	tty_kref_put(tty);  }  /* @@ -491,10 +494,7 @@ static int  sclp_vt220_open(struct tty_struct *tty, struct file *filp)  {  	if (tty->count == 1) { -		sclp_vt220_tty = tty; -		tty->driver_data = kmalloc(SCLP_VT220_BUF_SIZE, GFP_KERNEL); -		if (tty->driver_data == NULL) -			return -ENOMEM; +		tty_port_tty_set(&sclp_vt220_port, tty);  		tty->low_latency = 0;  		if (!tty->winsize.ws_row && !tty->winsize.ws_col) {  			tty->winsize.ws_row = 24; @@ -510,11 +510,8 @@ sclp_vt220_open(struct tty_struct *tty, struct file *filp)  static void  sclp_vt220_close(struct tty_struct *tty, struct file *filp)  { -	if (tty->count == 1) { -		sclp_vt220_tty = NULL; -		kfree(tty->driver_data); -		tty->driver_data = NULL; -	} +	if (tty->count == 1) +		tty_port_tty_set(&sclp_vt220_port, NULL);  }  /* @@ -635,9 +632,9 @@ static int __init __sclp_vt220_init(int num_pages)  	INIT_LIST_HEAD(&sclp_vt220_empty);  	INIT_LIST_HEAD(&sclp_vt220_outqueue);  	init_timer(&sclp_vt220_timer); +	tty_port_init(&sclp_vt220_port);  	sclp_vt220_current_request = NULL;  	sclp_vt220_buffered_chars = 0; -	sclp_vt220_tty = NULL;  	sclp_vt220_flush_later = 0;  	/* Allocate pages for output buffering */ diff --git a/drivers/s390/char/tty3270.c b/drivers/s390/char/tty3270.c index b43445a55cb..10ec690197c 100644 --- a/drivers/s390/char/tty3270.c +++ b/drivers/s390/char/tty3270.c @@ -61,7 +61,7 @@ struct tty3270_line {   */  struct tty3270 {  	struct raw3270_view view; -	struct tty_struct *tty;		/* Pointer to tty structure */ +	struct tty_port port;  	void **freemem_pages;		/* Array of pages used for freemem. */  	struct list_head freemem;	/* List of free memory for strings. */ @@ -324,9 +324,8 @@ tty3270_blank_line(struct tty3270 *tp)  static void  tty3270_write_callback(struct raw3270_request *rq, void *data)  { -	struct tty3270 *tp; +	struct tty3270 *tp = container_of(rq->view, struct tty3270, view); -	tp = (struct tty3270 *) rq->view;  	if (rq->rc != 0) {  		/* Write wasn't successful. Refresh all. */  		tp->update_flags = TTY_UPDATE_ALL; @@ -450,10 +449,9 @@ tty3270_rcl_add(struct tty3270 *tp, char *input, int len)  static void  tty3270_rcl_backward(struct kbd_data *kbd)  { -	struct tty3270 *tp; +	struct tty3270 *tp = container_of(kbd->port, struct tty3270, port);  	struct string *s; -	tp = kbd->tty->driver_data;  	spin_lock_bh(&tp->view.lock);  	if (tp->inattr == TF_INPUT) {  		if (tp->rcl_walk && tp->rcl_walk->prev != &tp->rcl_lines) @@ -478,9 +476,8 @@ tty3270_rcl_backward(struct kbd_data *kbd)  static void  tty3270_exit_tty(struct kbd_data *kbd)  { -	struct tty3270 *tp; +	struct tty3270 *tp = container_of(kbd->port, struct tty3270, port); -	tp = kbd->tty->driver_data;  	raw3270_deactivate_view(&tp->view);  } @@ -490,10 +487,9 @@ tty3270_exit_tty(struct kbd_data *kbd)  static void  tty3270_scroll_forward(struct kbd_data *kbd)  { -	struct tty3270 *tp; +	struct tty3270 *tp = container_of(kbd->port, struct tty3270, port);  	int nr_up; -	tp = kbd->tty->driver_data;  	spin_lock_bh(&tp->view.lock);  	nr_up = tp->nr_up - tp->view.rows + 2;  	if (nr_up < 0) @@ -513,10 +509,9 @@ tty3270_scroll_forward(struct kbd_data *kbd)  static void  tty3270_scroll_backward(struct kbd_data *kbd)  { -	struct tty3270 *tp; +	struct tty3270 *tp = container_of(kbd->port, struct tty3270, port);  	int nr_up; -	tp = kbd->tty->driver_data;  	spin_lock_bh(&tp->view.lock);  	nr_up = tp->nr_up + tp->view.rows - 2;  	if (nr_up + tp->view.rows - 2 > tp->nr_lines) @@ -537,11 +532,10 @@ static void  tty3270_read_tasklet(struct raw3270_request *rrq)  {  	static char kreset_data = TW_KR; -	struct tty3270 *tp; +	struct tty3270 *tp = container_of(rrq->view, struct tty3270, view);  	char *input;  	int len; -	tp = (struct tty3270 *) rrq->view;  	spin_lock_bh(&tp->view.lock);  	/*  	 * Two AID keys are special: For 0x7d (enter) the input line @@ -577,13 +571,10 @@ tty3270_read_tasklet(struct raw3270_request *rrq)  	raw3270_request_add_data(tp->kreset, &kreset_data, 1);  	raw3270_start(&tp->view, tp->kreset); -	/* Emit input string. */ -	if (tp->tty) { -		while (len-- > 0) -			kbd_keycode(tp->kbd, *input++); -		/* Emit keycode for AID byte. */ -		kbd_keycode(tp->kbd, 256 + tp->input->string[0]); -	} +	while (len-- > 0) +		kbd_keycode(tp->kbd, *input++); +	/* Emit keycode for AID byte. */ +	kbd_keycode(tp->kbd, 256 + tp->input->string[0]);  	raw3270_request_reset(rrq);  	xchg(&tp->read, rrq); @@ -596,9 +587,10 @@ tty3270_read_tasklet(struct raw3270_request *rrq)  static void  tty3270_read_callback(struct raw3270_request *rq, void *data)  { +	struct tty3270 *tp = container_of(rq->view, struct tty3270, view);  	raw3270_get_view(rq->view);  	/* Schedule tasklet to pass input to tty. */ -	tasklet_schedule(&((struct tty3270 *) rq->view)->readlet); +	tasklet_schedule(&tp->readlet);  }  /* @@ -635,9 +627,8 @@ tty3270_issue_read(struct tty3270 *tp, int lock)  static int  tty3270_activate(struct raw3270_view *view)  { -	struct tty3270 *tp; +	struct tty3270 *tp = container_of(view, struct tty3270, view); -	tp = (struct tty3270 *) view;  	tp->update_flags = TTY_UPDATE_ALL;  	tty3270_set_timer(tp, 1);  	return 0; @@ -646,9 +637,8 @@ tty3270_activate(struct raw3270_view *view)  static void  tty3270_deactivate(struct raw3270_view *view)  { -	struct tty3270 *tp; +	struct tty3270 *tp = container_of(view, struct tty3270, view); -	tp = (struct tty3270 *) view;  	del_timer(&tp->timer);  } @@ -690,6 +680,17 @@ tty3270_alloc_view(void)  	if (!tp->freemem_pages)  		goto out_tp;  	INIT_LIST_HEAD(&tp->freemem); +	INIT_LIST_HEAD(&tp->lines); +	INIT_LIST_HEAD(&tp->update); +	INIT_LIST_HEAD(&tp->rcl_lines); +	tp->rcl_max = 20; +	tty_port_init(&tp->port); +	setup_timer(&tp->timer, (void (*)(unsigned long)) tty3270_update, +		    (unsigned long) tp); +	tasklet_init(&tp->readlet, +		     (void (*)(unsigned long)) tty3270_read_tasklet, +		     (unsigned long) tp->read); +  	for (pages = 0; pages < TTY3270_STRING_PAGES; pages++) {  		tp->freemem_pages[pages] = (void *)  			__get_free_pages(GFP_KERNEL|GFP_DMA, 0); @@ -794,16 +795,15 @@ tty3270_free_screen(struct tty3270 *tp)  static void  tty3270_release(struct raw3270_view *view)  { -	struct tty3270 *tp; -	struct tty_struct *tty; +	struct tty3270 *tp = container_of(view, struct tty3270, view); +	struct tty_struct *tty = tty_port_tty_get(&tp->port); -	tp = (struct tty3270 *) view; -	tty = tp->tty;  	if (tty) {  		tty->driver_data = NULL; -		tp->tty = tp->kbd->tty = NULL; +		tty_port_tty_set(&tp->port, NULL);  		tty_hangup(tty);  		raw3270_put_view(&tp->view); +		tty_kref_put(tty);  	}  } @@ -813,8 +813,9 @@ tty3270_release(struct raw3270_view *view)  static void  tty3270_free(struct raw3270_view *view)  { -	tty3270_free_screen((struct tty3270 *) view); -	tty3270_free_view((struct tty3270 *) view); +	struct tty3270 *tp = container_of(view, struct tty3270, view); +	tty3270_free_screen(tp); +	tty3270_free_view(tp);  }  /* @@ -823,14 +824,13 @@ tty3270_free(struct raw3270_view *view)  static void  tty3270_del_views(void)  { -	struct tty3270 *tp;  	int i;  	for (i = 0; i < tty3270_max_index; i++) { -		tp = (struct tty3270 *) +		struct raw3270_view *view =  			raw3270_find_view(&tty3270_fn, i + RAW3270_FIRSTMINOR); -		if (!IS_ERR(tp)) -			raw3270_del_view(&tp->view); +		if (!IS_ERR(view)) +			raw3270_del_view(view);  	}  } @@ -848,22 +848,23 @@ static struct raw3270_fn tty3270_fn = {  static int  tty3270_open(struct tty_struct *tty, struct file * filp)  { +	struct raw3270_view *view;  	struct tty3270 *tp;  	int i, rc;  	if (tty->count > 1)  		return 0;  	/* Check if the tty3270 is already there. */ -	tp = (struct tty3270 *) -		raw3270_find_view(&tty3270_fn, +	view = raw3270_find_view(&tty3270_fn,  				  tty->index + RAW3270_FIRSTMINOR); -	if (!IS_ERR(tp)) { +	if (!IS_ERR(view)) { +		tp = container_of(view, struct tty3270, view);  		tty->driver_data = tp;  		tty->winsize.ws_row = tp->view.rows - 2;  		tty->winsize.ws_col = tp->view.cols;  		tty->low_latency = 0; -		tp->tty = tty; -		tp->kbd->tty = tty; +		/* why to reassign? */ +		tty_port_tty_set(&tp->port, tty);  		tp->inattr = TF_INPUT;  		return 0;  	} @@ -871,7 +872,7 @@ tty3270_open(struct tty_struct *tty, struct file * filp)  		tty3270_max_index = tty->index + 1;  	/* Quick exit if there is no device for tty->index. */ -	if (PTR_ERR(tp) == -ENODEV) +	if (PTR_ERR(view) == -ENODEV)  		return -ENODEV;  	/* Allocate tty3270 structure on first open. */ @@ -879,16 +880,6 @@ tty3270_open(struct tty_struct *tty, struct file * filp)  	if (IS_ERR(tp))  		return PTR_ERR(tp); -	INIT_LIST_HEAD(&tp->lines); -	INIT_LIST_HEAD(&tp->update); -	INIT_LIST_HEAD(&tp->rcl_lines); -	tp->rcl_max = 20; -	setup_timer(&tp->timer, (void (*)(unsigned long)) tty3270_update, -		    (unsigned long) tp); -	tasklet_init(&tp->readlet,  -		     (void (*)(unsigned long)) tty3270_read_tasklet, -		     (unsigned long) tp->read); -  	rc = raw3270_add_view(&tp->view, &tty3270_fn,  			      tty->index + RAW3270_FIRSTMINOR);  	if (rc) { @@ -903,7 +894,7 @@ tty3270_open(struct tty_struct *tty, struct file * filp)  		return rc;  	} -	tp->tty = tty; +	tty_port_tty_set(&tp->port, tty);  	tty->low_latency = 0;  	tty->driver_data = tp;  	tty->winsize.ws_row = tp->view.rows - 2; @@ -917,7 +908,7 @@ tty3270_open(struct tty_struct *tty, struct file * filp)  	for (i = 0; i < tp->view.rows - 2; i++)  		tty3270_blank_line(tp); -	tp->kbd->tty = tty; +	tp->kbd->port = &tp->port;  	tp->kbd->fn_handler[KVAL(K_INCRCONSOLE)] = tty3270_exit_tty;  	tp->kbd->fn_handler[KVAL(K_SCROLLBACK)] = tty3270_scroll_backward;  	tp->kbd->fn_handler[KVAL(K_SCROLLFORW)] = tty3270_scroll_forward; @@ -935,14 +926,13 @@ tty3270_open(struct tty_struct *tty, struct file * filp)  static void  tty3270_close(struct tty_struct *tty, struct file * filp)  { -	struct tty3270 *tp; +	struct tty3270 *tp = tty->driver_data;  	if (tty->count > 1)  		return; -	tp = (struct tty3270 *) tty->driver_data;  	if (tp) {  		tty->driver_data = NULL; -		tp->tty = tp->kbd->tty = NULL; +		tty_port_tty_set(&tp->port, NULL);  		raw3270_put_view(&tp->view);  	}  } @@ -1391,7 +1381,7 @@ tty3270_escape_sequence(struct tty3270 *tp, char ch)  			tty3270_lf(tp);  			break;  		case 'Z':		/* Respond ID. */ -			kbd_puts_queue(tp->tty, "\033[?6c"); +			kbd_puts_queue(&tp->port, "\033[?6c");  			break;  		case '7':		/* Save cursor position. */  			tp->saved_cx = tp->cx; @@ -1437,11 +1427,11 @@ tty3270_escape_sequence(struct tty3270 *tp, char ch)  	tp->esc_state = ESnormal;  	if (ch == 'n' && !tp->esc_ques) {  		if (tp->esc_par[0] == 5)		/* Status report. */ -			kbd_puts_queue(tp->tty, "\033[0n"); +			kbd_puts_queue(&tp->port, "\033[0n");  		else if (tp->esc_par[0] == 6) {	/* Cursor report. */  			char buf[40];  			sprintf(buf, "\033[%d;%dR", tp->cy + 1, tp->cx + 1); -			kbd_puts_queue(tp->tty, buf); +			kbd_puts_queue(&tp->port, buf);  		}  		return;  	} @@ -1513,12 +1503,13 @@ tty3270_escape_sequence(struct tty3270 *tp, char ch)   * String write routine for 3270 ttys   */  static void -tty3270_do_write(struct tty3270 *tp, const unsigned char *buf, int count) +tty3270_do_write(struct tty3270 *tp, struct tty_struct *tty, +		const unsigned char *buf, int count)  {  	int i_msg, i;  	spin_lock_bh(&tp->view.lock); -	for (i_msg = 0; !tp->tty->stopped && i_msg < count; i_msg++) { +	for (i_msg = 0; !tty->stopped && i_msg < count; i_msg++) {  		if (tp->esc_state != 0) {  			/* Continue escape sequence. */  			tty3270_escape_sequence(tp, buf[i_msg]); @@ -1595,10 +1586,10 @@ tty3270_write(struct tty_struct * tty,  	if (!tp)  		return 0;  	if (tp->char_count > 0) { -		tty3270_do_write(tp, tp->char_buf, tp->char_count); +		tty3270_do_write(tp, tty, tp->char_buf, tp->char_count);  		tp->char_count = 0;  	} -	tty3270_do_write(tp, buf, count); +	tty3270_do_write(tp, tty, buf, count);  	return count;  } @@ -1629,7 +1620,7 @@ tty3270_flush_chars(struct tty_struct *tty)  	if (!tp)  		return;  	if (tp->char_count > 0) { -		tty3270_do_write(tp, tp->char_buf, tp->char_count); +		tty3270_do_write(tp, tty, tp->char_buf, tp->char_count);  		tp->char_count = 0;  	}  } diff --git a/drivers/staging/serial/68360serial.c b/drivers/staging/serial/68360serial.c index daf0b1d0dc2..23ee50e25e4 100644 --- a/drivers/staging/serial/68360serial.c +++ b/drivers/staging/serial/68360serial.c @@ -1859,9 +1859,9 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,  		printk("block_til_ready blocking: ttys%d, count = %d\n",  		       info->line, state->count);  #endif -		tty_unlock(); +		tty_unlock(tty);  		schedule(); -		tty_lock(); +		tty_lock(tty);  	}  	current->state = TASK_RUNNING;  	remove_wait_queue(&info->open_wait, &wait); diff --git a/drivers/tty/amiserial.c b/drivers/tty/amiserial.c index 6cc4358f68c..35819e31262 100644 --- a/drivers/tty/amiserial.c +++ b/drivers/tty/amiserial.c @@ -1033,7 +1033,7 @@ static int get_serial_info(struct tty_struct *tty, struct serial_state *state,  	if (!retinfo)  		return -EFAULT;  	memset(&tmp, 0, sizeof(tmp)); -	tty_lock(); +	tty_lock(tty);  	tmp.line = tty->index;  	tmp.port = state->port;  	tmp.flags = state->tport.flags; @@ -1042,7 +1042,7 @@ static int get_serial_info(struct tty_struct *tty, struct serial_state *state,  	tmp.close_delay = state->tport.close_delay;  	tmp.closing_wait = state->tport.closing_wait;  	tmp.custom_divisor = state->custom_divisor; -	tty_unlock(); +	tty_unlock(tty);  	if (copy_to_user(retinfo,&tmp,sizeof(*retinfo)))  		return -EFAULT;  	return 0; @@ -1059,12 +1059,12 @@ static int set_serial_info(struct tty_struct *tty, struct serial_state *state,  	if (copy_from_user(&new_serial,new_info,sizeof(new_serial)))  		return -EFAULT; -	tty_lock(); +	tty_lock(tty);  	change_spd = ((new_serial.flags ^ port->flags) & ASYNC_SPD_MASK) ||  		new_serial.custom_divisor != state->custom_divisor;  	if (new_serial.irq || new_serial.port != state->port ||  			new_serial.xmit_fifo_size != state->xmit_fifo_size) { -		tty_unlock(); +		tty_unlock(tty);  		return -EINVAL;  	} @@ -1074,7 +1074,7 @@ static int set_serial_info(struct tty_struct *tty, struct serial_state *state,  		    (new_serial.xmit_fifo_size != state->xmit_fifo_size) ||  		    ((new_serial.flags & ~ASYNC_USR_MASK) !=  		     (port->flags & ~ASYNC_USR_MASK))) { -			tty_unlock(); +			tty_unlock(tty);  			return -EPERM;  		}  		port->flags = ((port->flags & ~ASYNC_USR_MASK) | @@ -1084,7 +1084,7 @@ static int set_serial_info(struct tty_struct *tty, struct serial_state *state,  	}  	if (new_serial.baud_base < 9600) { -		tty_unlock(); +		tty_unlock(tty);  		return -EINVAL;  	} @@ -1116,7 +1116,7 @@ check_and_exit:  		}  	} else  		retval = startup(tty, state); -	tty_unlock(); +	tty_unlock(tty);  	return retval;  } diff --git a/drivers/tty/bfin_jtag_comm.c b/drivers/tty/bfin_jtag_comm.c index 946f799861f..61fc74fe174 100644 --- a/drivers/tty/bfin_jtag_comm.c +++ b/drivers/tty/bfin_jtag_comm.c @@ -62,9 +62,7 @@ static inline uint32_t bfin_write_emudat_chars(char a, char b, char c, char d)  static struct tty_driver *bfin_jc_driver;  static struct task_struct *bfin_jc_kthread; -static struct tty_struct * volatile bfin_jc_tty; -static unsigned long bfin_jc_count; -static DEFINE_MUTEX(bfin_jc_tty_mutex); +static struct tty_port port;  static volatile struct circ_buf bfin_jc_write_buf;  static int @@ -73,18 +71,21 @@ bfin_jc_emudat_manager(void *arg)  	uint32_t inbound_len = 0, outbound_len = 0;  	while (!kthread_should_stop()) { +		struct tty_struct *tty = tty_port_tty_get(&port);  		/* no one left to give data to, so sleep */ -		if (bfin_jc_tty == NULL && circ_empty(&bfin_jc_write_buf)) { +		if (tty == NULL && circ_empty(&bfin_jc_write_buf)) {  			pr_debug("waiting for readers\n");  			__set_current_state(TASK_UNINTERRUPTIBLE);  			schedule();  			__set_current_state(TASK_RUNNING); +			continue;  		}  		/* no data available, so just chill */  		if (!(bfin_read_DBGSTAT() & EMUDIF) && circ_empty(&bfin_jc_write_buf)) {  			pr_debug("waiting for data (in_len = %i) (circ: %i %i)\n",  				inbound_len, bfin_jc_write_buf.tail, bfin_jc_write_buf.head); +			tty_kref_put(tty);  			if (inbound_len)  				schedule();  			else @@ -94,9 +95,6 @@ bfin_jc_emudat_manager(void *arg)  		/* if incoming data is ready, eat it */  		if (bfin_read_DBGSTAT() & EMUDIF) { -			struct tty_struct *tty; -			mutex_lock(&bfin_jc_tty_mutex); -			tty = (struct tty_struct *)bfin_jc_tty;  			if (tty != NULL) {  				uint32_t emudat = bfin_read_emudat();  				if (inbound_len == 0) { @@ -110,7 +108,6 @@ bfin_jc_emudat_manager(void *arg)  					tty_flip_buffer_push(tty);  				}  			} -			mutex_unlock(&bfin_jc_tty_mutex);  		}  		/* if outgoing data is ready, post it */ @@ -120,7 +117,6 @@ bfin_jc_emudat_manager(void *arg)  				bfin_write_emudat(outbound_len);  				pr_debug("outgoing length: 0x%08x\n", outbound_len);  			} else { -				struct tty_struct *tty;  				int tail = bfin_jc_write_buf.tail;  				size_t ate = (4 <= outbound_len ? 4 : outbound_len);  				uint32_t emudat = @@ -132,14 +128,12 @@ bfin_jc_emudat_manager(void *arg)  				);  				bfin_jc_write_buf.tail += ate;  				outbound_len -= ate; -				mutex_lock(&bfin_jc_tty_mutex); -				tty = (struct tty_struct *)bfin_jc_tty;  				if (tty)  					tty_wakeup(tty); -				mutex_unlock(&bfin_jc_tty_mutex);  				pr_debug("  outgoing data: 0x%08x (pushing %zu)\n", emudat, ate);  			}  		} +		tty_kref_put(tty);  	}  	__set_current_state(TASK_RUNNING); @@ -149,24 +143,28 @@ bfin_jc_emudat_manager(void *arg)  static int  bfin_jc_open(struct tty_struct *tty, struct file *filp)  { -	mutex_lock(&bfin_jc_tty_mutex); -	pr_debug("open %lu\n", bfin_jc_count); -	++bfin_jc_count; -	bfin_jc_tty = tty; +	unsigned long flags; + +	spin_lock_irqsave(&port.lock, flags); +	port.count++; +	spin_unlock_irqrestore(&port.lock, flags); +	tty_port_tty_set(&port, tty);  	wake_up_process(bfin_jc_kthread); -	mutex_unlock(&bfin_jc_tty_mutex);  	return 0;  }  static void  bfin_jc_close(struct tty_struct *tty, struct file *filp)  { -	mutex_lock(&bfin_jc_tty_mutex); -	pr_debug("close %lu\n", bfin_jc_count); -	if (--bfin_jc_count == 0) -		bfin_jc_tty = NULL; +	unsigned long flags; +	bool last; + +	spin_lock_irqsave(&port.lock, flags); +	last = --port.count == 0; +	spin_unlock_irqrestore(&port.lock, flags); +	if (last) +		tty_port_tty_set(&port, NULL);  	wake_up_process(bfin_jc_kthread); -	mutex_unlock(&bfin_jc_tty_mutex);  }  /* XXX: we dont handle the put_char() case where we must handle count = 1 */ @@ -242,6 +240,8 @@ static int __init bfin_jc_init(void)  {  	int ret; +	tty_port_init(&port); +  	bfin_jc_kthread = kthread_create(bfin_jc_emudat_manager, NULL, DRV_NAME);  	if (IS_ERR(bfin_jc_kthread))  		return PTR_ERR(bfin_jc_kthread); diff --git a/drivers/tty/cyclades.c b/drivers/tty/cyclades.c index e61cabdd69d..6984e1a2686 100644 --- a/drivers/tty/cyclades.c +++ b/drivers/tty/cyclades.c @@ -1599,7 +1599,7 @@ static int cy_open(struct tty_struct *tty, struct file *filp)  	 * If the port is the middle of closing, bail out now  	 */  	if (tty_hung_up_p(filp) || (info->port.flags & ASYNC_CLOSING)) { -		wait_event_interruptible_tty(info->port.close_wait, +		wait_event_interruptible_tty(tty, info->port.close_wait,  				!(info->port.flags & ASYNC_CLOSING));  		return (info->port.flags & ASYNC_HUP_NOTIFY) ? -EAGAIN: -ERESTARTSYS;  	} diff --git a/drivers/tty/hvc/hvc_console.c b/drivers/tty/hvc/hvc_console.c index 8880adf5fc6..2d691eb7c40 100644 --- a/drivers/tty/hvc/hvc_console.c +++ b/drivers/tty/hvc/hvc_console.c @@ -107,7 +107,7 @@ static struct hvc_struct *hvc_get_by_index(int index)  	list_for_each_entry(hp, &hvc_structs, next) {  		spin_lock_irqsave(&hp->lock, flags);  		if (hp->index == index) { -			kref_get(&hp->kref); +			tty_port_get(&hp->port);  			spin_unlock_irqrestore(&hp->lock, flags);  			spin_unlock(&hvc_structs_lock);  			return hp; @@ -229,9 +229,9 @@ static int __init hvc_console_init(void)  console_initcall(hvc_console_init);  /* callback when the kboject ref count reaches zero. */ -static void destroy_hvc_struct(struct kref *kref) +static void hvc_port_destruct(struct tty_port *port)  { -	struct hvc_struct *hp = container_of(kref, struct hvc_struct, kref); +	struct hvc_struct *hp = container_of(port, struct hvc_struct, port);  	unsigned long flags;  	spin_lock(&hvc_structs_lock); @@ -264,7 +264,7 @@ int hvc_instantiate(uint32_t vtermno, int index, const struct hv_ops *ops)  	/* make sure no no tty has been registered in this index */  	hp = hvc_get_by_index(index);  	if (hp) { -		kref_put(&hp->kref, destroy_hvc_struct); +		tty_port_put(&hp->port);  		return -1;  	} @@ -313,20 +313,17 @@ static int hvc_open(struct tty_struct *tty, struct file * filp)  	if (!(hp = hvc_get_by_index(tty->index)))  		return -ENODEV; -	spin_lock_irqsave(&hp->lock, flags); +	spin_lock_irqsave(&hp->port.lock, flags);  	/* Check and then increment for fast path open. */ -	if (hp->count++ > 0) { -		tty_kref_get(tty); -		spin_unlock_irqrestore(&hp->lock, flags); +	if (hp->port.count++ > 0) { +		spin_unlock_irqrestore(&hp->port.lock, flags);  		hvc_kick();  		return 0;  	} /* else count == 0 */ +	spin_unlock_irqrestore(&hp->port.lock, flags);  	tty->driver_data = hp; - -	hp->tty = tty_kref_get(tty); - -	spin_unlock_irqrestore(&hp->lock, flags); +	tty_port_tty_set(&hp->port, tty);  	if (hp->ops->notifier_add)  		rc = hp->ops->notifier_add(hp, hp->data); @@ -338,12 +335,9 @@ static int hvc_open(struct tty_struct *tty, struct file * filp)  	 * tty fields and return the kref reference.  	 */  	if (rc) { -		spin_lock_irqsave(&hp->lock, flags); -		hp->tty = NULL; -		spin_unlock_irqrestore(&hp->lock, flags); -		tty_kref_put(tty); +		tty_port_tty_set(&hp->port, NULL);  		tty->driver_data = NULL; -		kref_put(&hp->kref, destroy_hvc_struct); +		tty_port_put(&hp->port);  		printk(KERN_ERR "hvc_open: request_irq failed with rc %d.\n", rc);  	}  	/* Force wakeup of the polling thread */ @@ -370,12 +364,12 @@ static void hvc_close(struct tty_struct *tty, struct file * filp)  	hp = tty->driver_data; -	spin_lock_irqsave(&hp->lock, flags); +	spin_lock_irqsave(&hp->port.lock, flags); -	if (--hp->count == 0) { +	if (--hp->port.count == 0) { +		spin_unlock_irqrestore(&hp->port.lock, flags);  		/* We are done with the tty pointer now. */ -		hp->tty = NULL; -		spin_unlock_irqrestore(&hp->lock, flags); +		tty_port_tty_set(&hp->port, NULL);  		if (hp->ops->notifier_del)  			hp->ops->notifier_del(hp, hp->data); @@ -390,14 +384,13 @@ static void hvc_close(struct tty_struct *tty, struct file * filp)  		 */  		tty_wait_until_sent_from_close(tty, HVC_CLOSE_WAIT);  	} else { -		if (hp->count < 0) +		if (hp->port.count < 0)  			printk(KERN_ERR "hvc_close %X: oops, count is %d\n", -				hp->vtermno, hp->count); -		spin_unlock_irqrestore(&hp->lock, flags); +				hp->vtermno, hp->port.count); +		spin_unlock_irqrestore(&hp->port.lock, flags);  	} -	tty_kref_put(tty); -	kref_put(&hp->kref, destroy_hvc_struct); +	tty_port_put(&hp->port);  }  static void hvc_hangup(struct tty_struct *tty) @@ -412,32 +405,31 @@ static void hvc_hangup(struct tty_struct *tty)  	/* cancel pending tty resize work */  	cancel_work_sync(&hp->tty_resize); -	spin_lock_irqsave(&hp->lock, flags); +	spin_lock_irqsave(&hp->port.lock, flags);  	/*  	 * The N_TTY line discipline has problems such that in a close vs  	 * open->hangup case this can be called after the final close so prevent  	 * that from happening for now.  	 */ -	if (hp->count <= 0) { -		spin_unlock_irqrestore(&hp->lock, flags); +	if (hp->port.count <= 0) { +		spin_unlock_irqrestore(&hp->port.lock, flags);  		return;  	} -	temp_open_count = hp->count; -	hp->count = 0; -	hp->n_outbuf = 0; -	hp->tty = NULL; +	temp_open_count = hp->port.count; +	hp->port.count = 0; +	spin_unlock_irqrestore(&hp->port.lock, flags); +	tty_port_tty_set(&hp->port, NULL); -	spin_unlock_irqrestore(&hp->lock, flags); +	hp->n_outbuf = 0;  	if (hp->ops->notifier_hangup)  		hp->ops->notifier_hangup(hp, hp->data);  	while(temp_open_count) {  		--temp_open_count; -		tty_kref_put(tty); -		kref_put(&hp->kref, destroy_hvc_struct); +		tty_port_put(&hp->port);  	}  } @@ -478,7 +470,8 @@ static int hvc_write(struct tty_struct *tty, const unsigned char *buf, int count  	if (!hp)  		return -EPIPE; -	if (hp->count <= 0) +	/* FIXME what's this (unprotected) check for? */ +	if (hp->port.count <= 0)  		return -EIO;  	spin_lock_irqsave(&hp->lock, flags); @@ -526,13 +519,12 @@ static void hvc_set_winsz(struct work_struct *work)  	hp = container_of(work, struct hvc_struct, tty_resize); -	spin_lock_irqsave(&hp->lock, hvc_flags); -	if (!hp->tty) { -		spin_unlock_irqrestore(&hp->lock, hvc_flags); +	tty = tty_port_tty_get(&hp->port); +	if (!tty)  		return; -	} -	ws  = hp->ws; -	tty = tty_kref_get(hp->tty); + +	spin_lock_irqsave(&hp->lock, hvc_flags); +	ws = hp->ws;  	spin_unlock_irqrestore(&hp->lock, hvc_flags);  	tty_do_resize(tty, &ws); @@ -601,7 +593,7 @@ int hvc_poll(struct hvc_struct *hp)  	}  	/* No tty attached, just skip */ -	tty = tty_kref_get(hp->tty); +	tty = tty_port_tty_get(&hp->port);  	if (tty == NULL)  		goto bail; @@ -681,8 +673,7 @@ int hvc_poll(struct hvc_struct *hp)  		tty_flip_buffer_push(tty);  	} -	if (tty) -		tty_kref_put(tty); +	tty_kref_put(tty);  	return poll_mask;  } @@ -817,6 +808,10 @@ static const struct tty_operations hvc_ops = {  #endif  }; +static const struct tty_port_operations hvc_port_ops = { +	.destruct = hvc_port_destruct, +}; +  struct hvc_struct *hvc_alloc(uint32_t vtermno, int data,  			     const struct hv_ops *ops,  			     int outbuf_size) @@ -842,7 +837,8 @@ struct hvc_struct *hvc_alloc(uint32_t vtermno, int data,  	hp->outbuf_size = outbuf_size;  	hp->outbuf = &((char *)hp)[ALIGN(sizeof(*hp), sizeof(long))]; -	kref_init(&hp->kref); +	tty_port_init(&hp->port); +	hp->port.ops = &hvc_port_ops;  	INIT_WORK(&hp->tty_resize, hvc_set_winsz);  	spin_lock_init(&hp->lock); @@ -875,9 +871,9 @@ int hvc_remove(struct hvc_struct *hp)  	unsigned long flags;  	struct tty_struct *tty; -	spin_lock_irqsave(&hp->lock, flags); -	tty = tty_kref_get(hp->tty); +	tty = tty_port_tty_get(&hp->port); +	spin_lock_irqsave(&hp->lock, flags);  	if (hp->index < MAX_NR_HVC_CONSOLES)  		vtermnos[hp->index] = -1; @@ -891,7 +887,7 @@ int hvc_remove(struct hvc_struct *hp)  	 * kref cause it to be removed, which will probably be the tty_vhangup  	 * below.  	 */ -	kref_put(&hp->kref, destroy_hvc_struct); +	tty_port_put(&hp->port);  	/*  	 * This function call will auto chain call hvc_hangup. diff --git a/drivers/tty/hvc/hvc_console.h b/drivers/tty/hvc/hvc_console.h index c335a1492a5..674d23cb919 100644 --- a/drivers/tty/hvc/hvc_console.h +++ b/drivers/tty/hvc/hvc_console.h @@ -46,10 +46,9 @@  #define HVC_ALLOC_TTY_ADAPTERS	8  struct hvc_struct { +	struct tty_port port;  	spinlock_t lock;  	int index; -	struct tty_struct *tty; -	int count;  	int do_wakeup;  	char *outbuf;  	int outbuf_size; @@ -61,7 +60,6 @@ struct hvc_struct {  	struct winsize ws;  	struct work_struct tty_resize;  	struct list_head next; -	struct kref kref; /* ref count & hvc_struct lifetime */  };  /* implemented by a low level driver */ diff --git a/drivers/tty/hvc/hvc_xen.c b/drivers/tty/hvc/hvc_xen.c index 83d5c88e716..d3d91dae065 100644 --- a/drivers/tty/hvc/hvc_xen.c +++ b/drivers/tty/hvc/hvc_xen.c @@ -430,9 +430,9 @@ static int __devinit xencons_probe(struct xenbus_device *dev,  	if (devid == 0)  		return -ENODEV; -	info = kzalloc(sizeof(struct xencons_info), GFP_KERNEL | __GFP_ZERO); +	info = kzalloc(sizeof(struct xencons_info), GFP_KERNEL);  	if (!info) -		goto error_nomem; +		return -ENOMEM;  	dev_set_drvdata(&dev->dev, info);  	info->xbdev = dev;  	info->vtermno = xenbus_devid_to_vtermno(devid); diff --git a/drivers/tty/hvc/hvcs.c b/drivers/tty/hvc/hvcs.c index 3436436fe2d..d56788c8397 100644 --- a/drivers/tty/hvc/hvcs.c +++ b/drivers/tty/hvc/hvcs.c @@ -261,6 +261,7 @@ static DEFINE_SPINLOCK(hvcs_pi_lock);  /* One vty-server per hvcs_struct */  struct hvcs_struct { +	struct tty_port port;  	spinlock_t lock;  	/* @@ -269,9 +270,6 @@ struct hvcs_struct {  	 */  	unsigned int index; -	struct tty_struct *tty; -	int open_count; -  	/*  	 * Used to tell the driver kernel_thread what operations need to take  	 * place upon this hvcs_struct instance. @@ -290,12 +288,11 @@ struct hvcs_struct {  	int chars_in_buffer;  	/* -	 * Any variable below the kref is valid before a tty is connected and +	 * Any variable below is valid before a tty is connected and  	 * stays valid after the tty is disconnected.  These shouldn't be  	 * whacked until the kobject refcount reaches zero though some entries  	 * may be changed via sysfs initiatives.  	 */ -	struct kref kref; /* ref count & hvcs_struct lifetime */  	int connected; /* is the vty-server currently connected to a vty? */  	uint32_t p_unit_address; /* partner unit address */  	uint32_t p_partition_ID; /* partner partition ID */ @@ -304,9 +301,6 @@ struct hvcs_struct {  	struct vio_dev *vdev;  }; -/* Required to back map a kref to its containing object */ -#define from_kref(k) container_of(k, struct hvcs_struct, kref) -  static LIST_HEAD(hvcs_structs);  static DEFINE_SPINLOCK(hvcs_structs_lock);  static DEFINE_MUTEX(hvcs_init_mutex); @@ -422,7 +416,7 @@ static ssize_t hvcs_vterm_state_store(struct device *dev, struct device_attribut  	spin_lock_irqsave(&hvcsd->lock, flags); -	if (hvcsd->open_count > 0) { +	if (hvcsd->port.count > 0) {  		spin_unlock_irqrestore(&hvcsd->lock, flags);  		printk(KERN_INFO "HVCS: vterm state unchanged.  "  				"The hvcs device node is still in use.\n"); @@ -564,7 +558,7 @@ static irqreturn_t hvcs_handle_interrupt(int irq, void *dev_instance)  static void hvcs_try_write(struct hvcs_struct *hvcsd)  {  	uint32_t unit_address = hvcsd->vdev->unit_address; -	struct tty_struct *tty = hvcsd->tty; +	struct tty_struct *tty = hvcsd->port.tty;  	int sent;  	if (hvcsd->todo_mask & HVCS_TRY_WRITE) { @@ -602,7 +596,7 @@ static int hvcs_io(struct hvcs_struct *hvcsd)  	spin_lock_irqsave(&hvcsd->lock, flags);  	unit_address = hvcsd->vdev->unit_address; -	tty = hvcsd->tty; +	tty = hvcsd->port.tty;  	hvcs_try_write(hvcsd); @@ -701,10 +695,9 @@ static void hvcs_return_index(int index)  		hvcs_index_list[index] = -1;  } -/* callback when the kref ref count reaches zero */ -static void destroy_hvcs_struct(struct kref *kref) +static void hvcs_destruct_port(struct tty_port *p)  { -	struct hvcs_struct *hvcsd = from_kref(kref); +	struct hvcs_struct *hvcsd = container_of(p, struct hvcs_struct, port);  	struct vio_dev *vdev;  	unsigned long flags; @@ -741,6 +734,10 @@ static void destroy_hvcs_struct(struct kref *kref)  	kfree(hvcsd);  } +static const struct tty_port_operations hvcs_port_ops = { +	.destruct = hvcs_destruct_port, +}; +  static int hvcs_get_index(void)  {  	int i; @@ -789,10 +786,9 @@ static int __devinit hvcs_probe(  	if (!hvcsd)  		return -ENODEV; - +	tty_port_init(&hvcsd->port); +	hvcsd->port.ops = &hvcs_port_ops;  	spin_lock_init(&hvcsd->lock); -	/* Automatically incs the refcount the first time */ -	kref_init(&hvcsd->kref);  	hvcsd->vdev = dev;  	dev_set_drvdata(&dev->dev, hvcsd); @@ -852,7 +848,7 @@ static int __devexit hvcs_remove(struct vio_dev *dev)  	spin_lock_irqsave(&hvcsd->lock, flags); -	tty = hvcsd->tty; +	tty = hvcsd->port.tty;  	spin_unlock_irqrestore(&hvcsd->lock, flags); @@ -860,7 +856,7 @@ static int __devexit hvcs_remove(struct vio_dev *dev)  	 * Let the last holder of this object cause it to be removed, which  	 * would probably be tty_hangup below.  	 */ -	kref_put(&hvcsd->kref, destroy_hvcs_struct); +	tty_port_put(&hvcsd->port);  	/*  	 * The hangup is a scheduled function which will auto chain call @@ -1094,7 +1090,7 @@ static struct hvcs_struct *hvcs_get_by_index(int index)  	list_for_each_entry(hvcsd, &hvcs_structs, next) {  		spin_lock_irqsave(&hvcsd->lock, flags);  		if (hvcsd->index == index) { -			kref_get(&hvcsd->kref); +			tty_port_get(&hvcsd->port);  			spin_unlock_irqrestore(&hvcsd->lock, flags);  			spin_unlock(&hvcs_structs_lock);  			return hvcsd; @@ -1138,8 +1134,8 @@ static int hvcs_open(struct tty_struct *tty, struct file *filp)  		if ((retval = hvcs_partner_connect(hvcsd)))  			goto error_release; -	hvcsd->open_count = 1; -	hvcsd->tty = tty; +	hvcsd->port.count = 1; +	hvcsd->port.tty = tty;  	tty->driver_data = hvcsd;  	memset(&hvcsd->buffer[0], 0x00, HVCS_BUFF_LEN); @@ -1160,7 +1156,7 @@ static int hvcs_open(struct tty_struct *tty, struct file *filp)  	 * and will grab the spinlock and free the connection if it fails.  	 */  	if (((rc = hvcs_enable_device(hvcsd, unit_address, irq, vdev)))) { -		kref_put(&hvcsd->kref, destroy_hvcs_struct); +		tty_port_put(&hvcsd->port);  		printk(KERN_WARNING "HVCS: enable device failed.\n");  		return rc;  	} @@ -1171,8 +1167,8 @@ fast_open:  	hvcsd = tty->driver_data;  	spin_lock_irqsave(&hvcsd->lock, flags); -	kref_get(&hvcsd->kref); -	hvcsd->open_count++; +	tty_port_get(&hvcsd->port); +	hvcsd->port.count++;  	hvcsd->todo_mask |= HVCS_SCHED_READ;  	spin_unlock_irqrestore(&hvcsd->lock, flags); @@ -1186,7 +1182,7 @@ open_success:  error_release:  	spin_unlock_irqrestore(&hvcsd->lock, flags); -	kref_put(&hvcsd->kref, destroy_hvcs_struct); +	tty_port_put(&hvcsd->port);  	printk(KERN_WARNING "HVCS: partner connect failed.\n");  	return retval; @@ -1216,7 +1212,7 @@ static void hvcs_close(struct tty_struct *tty, struct file *filp)  	hvcsd = tty->driver_data;  	spin_lock_irqsave(&hvcsd->lock, flags); -	if (--hvcsd->open_count == 0) { +	if (--hvcsd->port.count == 0) {  		vio_disable_interrupts(hvcsd->vdev); @@ -1225,7 +1221,7 @@ static void hvcs_close(struct tty_struct *tty, struct file *filp)  		 * execute any operations on the TTY even though it is obligated  		 * to deliver any pending I/O to the hypervisor.  		 */ -		hvcsd->tty = NULL; +		hvcsd->port.tty = NULL;  		irq = hvcsd->vdev->irq;  		spin_unlock_irqrestore(&hvcsd->lock, flags); @@ -1240,16 +1236,16 @@ static void hvcs_close(struct tty_struct *tty, struct file *filp)  		tty->driver_data = NULL;  		free_irq(irq, hvcsd); -		kref_put(&hvcsd->kref, destroy_hvcs_struct); +		tty_port_put(&hvcsd->port);  		return; -	} else if (hvcsd->open_count < 0) { +	} else if (hvcsd->port.count < 0) {  		printk(KERN_ERR "HVCS: vty-server@%X open_count: %d"  				" is missmanaged.\n", -		hvcsd->vdev->unit_address, hvcsd->open_count); +		hvcsd->vdev->unit_address, hvcsd->port.count);  	}  	spin_unlock_irqrestore(&hvcsd->lock, flags); -	kref_put(&hvcsd->kref, destroy_hvcs_struct); +	tty_port_put(&hvcsd->port);  }  static void hvcs_hangup(struct tty_struct * tty) @@ -1261,7 +1257,7 @@ static void hvcs_hangup(struct tty_struct * tty)  	spin_lock_irqsave(&hvcsd->lock, flags);  	/* Preserve this so that we know how many kref refs to put */ -	temp_open_count = hvcsd->open_count; +	temp_open_count = hvcsd->port.count;  	/*  	 * Don't kref put inside the spinlock because the destruction @@ -1273,10 +1269,10 @@ static void hvcs_hangup(struct tty_struct * tty)  	hvcsd->todo_mask = 0;  	/* I don't think the tty needs the hvcs_struct pointer after a hangup */ -	hvcsd->tty->driver_data = NULL; -	hvcsd->tty = NULL; +	tty->driver_data = NULL; +	hvcsd->port.tty = NULL; -	hvcsd->open_count = 0; +	hvcsd->port.count = 0;  	/* This will drop any buffered data on the floor which is OK in a hangup  	 * scenario. */ @@ -1301,7 +1297,7 @@ static void hvcs_hangup(struct tty_struct * tty)  		 * NOTE:  If this hangup was signaled from user space then the  		 * final put will never happen.  		 */ -		kref_put(&hvcsd->kref, destroy_hvcs_struct); +		tty_port_put(&hvcsd->port);  	}  } @@ -1347,7 +1343,7 @@ static int hvcs_write(struct tty_struct *tty,  	 * the middle of a write operation?  This is a crummy place to do this  	 * but we want to keep it all in the spinlock.  	 */ -	if (hvcsd->open_count <= 0) { +	if (hvcsd->port.count <= 0) {  		spin_unlock_irqrestore(&hvcsd->lock, flags);  		return -ENODEV;  	} @@ -1421,7 +1417,7 @@ static int hvcs_write_room(struct tty_struct *tty)  {  	struct hvcs_struct *hvcsd = tty->driver_data; -	if (!hvcsd || hvcsd->open_count <= 0) +	if (!hvcsd || hvcsd->port.count <= 0)  		return 0;  	return HVCS_BUFF_LEN - hvcsd->chars_in_buffer; diff --git a/drivers/tty/hvc/hvsi.c b/drivers/tty/hvc/hvsi.c index a7488b74864..6f5bc49c441 100644 --- a/drivers/tty/hvc/hvsi.c +++ b/drivers/tty/hvc/hvsi.c @@ -69,14 +69,13 @@  #define __ALIGNED__	__attribute__((__aligned__(sizeof(long))))  struct hvsi_struct { +	struct tty_port port;  	struct delayed_work writer;  	struct work_struct handshaker;  	wait_queue_head_t emptyq; /* woken when outbuf is emptied */  	wait_queue_head_t stateq; /* woken when HVSI state changes */  	spinlock_t lock;  	int index; -	struct tty_struct *tty; -	int count;  	uint8_t throttle_buf[128];  	uint8_t outbuf[N_OUTBUF]; /* to implement write_room and chars_in_buffer */  	/* inbuf is for packet reassembly. leave a little room for leftovers. */ @@ -237,7 +236,7 @@ static int hvsi_read(struct hvsi_struct *hp, char *buf, int count)  }  static void hvsi_recv_control(struct hvsi_struct *hp, uint8_t *packet, -	struct tty_struct **to_hangup, struct hvsi_struct **to_handshake) +	struct tty_struct *tty, struct hvsi_struct **to_handshake)  {  	struct hvsi_control *header = (struct hvsi_control *)packet; @@ -247,9 +246,8 @@ static void hvsi_recv_control(struct hvsi_struct *hp, uint8_t *packet,  				/* CD went away; no more connection */  				pr_debug("hvsi%i: CD dropped\n", hp->index);  				hp->mctrl &= TIOCM_CD; -				/* If userland hasn't done an open(2) yet, hp->tty is NULL. */ -				if (hp->tty && !(hp->tty->flags & CLOCAL)) -					*to_hangup = hp->tty; +				if (tty && !C_CLOCAL(tty)) +					tty_hangup(tty);  			}  			break;  		case VSV_CLOSE_PROTOCOL: @@ -331,7 +329,8 @@ static void hvsi_recv_query(struct hvsi_struct *hp, uint8_t *packet)  	}  } -static void hvsi_insert_chars(struct hvsi_struct *hp, const char *buf, int len) +static void hvsi_insert_chars(struct hvsi_struct *hp, struct tty_struct *tty, +		const char *buf, int len)  {  	int i; @@ -347,7 +346,7 @@ static void hvsi_insert_chars(struct hvsi_struct *hp, const char *buf, int len)  			continue;  		}  #endif /* CONFIG_MAGIC_SYSRQ */ -		tty_insert_flip_char(hp->tty, c, 0); +		tty_insert_flip_char(tty, c, 0);  	}  } @@ -360,7 +359,7 @@ static void hvsi_insert_chars(struct hvsi_struct *hp, const char *buf, int len)   * revisited.   */  #define TTY_THRESHOLD_THROTTLE 128 -static struct tty_struct *hvsi_recv_data(struct hvsi_struct *hp, +static bool hvsi_recv_data(struct hvsi_struct *hp, struct tty_struct *tty,  		const uint8_t *packet)  {  	const struct hvsi_header *header = (const struct hvsi_header *)packet; @@ -371,14 +370,14 @@ static struct tty_struct *hvsi_recv_data(struct hvsi_struct *hp,  	pr_debug("queueing %i chars '%.*s'\n", datalen, datalen, data);  	if (datalen == 0) -		return NULL; +		return false;  	if (overflow > 0) {  		pr_debug("%s: got >TTY_THRESHOLD_THROTTLE bytes\n", __func__);  		datalen = TTY_THRESHOLD_THROTTLE;  	} -	hvsi_insert_chars(hp, data, datalen); +	hvsi_insert_chars(hp, tty, data, datalen);  	if (overflow > 0) {  		/* @@ -390,7 +389,7 @@ static struct tty_struct *hvsi_recv_data(struct hvsi_struct *hp,  		hp->n_throttle = overflow;  	} -	return hp->tty; +	return true;  }  /* @@ -399,14 +398,13 @@ static struct tty_struct *hvsi_recv_data(struct hvsi_struct *hp,   * machine during console handshaking (in which case tty = NULL and we ignore   * incoming data).   */ -static int hvsi_load_chunk(struct hvsi_struct *hp, struct tty_struct **flip, -		struct tty_struct **hangup, struct hvsi_struct **handshake) +static int hvsi_load_chunk(struct hvsi_struct *hp, struct tty_struct *tty, +		struct hvsi_struct **handshake)  {  	uint8_t *packet = hp->inbuf;  	int chunklen; +	bool flip = false; -	*flip = NULL; -	*hangup = NULL;  	*handshake = NULL;  	chunklen = hvsi_read(hp, hp->inbuf_end, HVSI_MAX_READ); @@ -440,12 +438,12 @@ static int hvsi_load_chunk(struct hvsi_struct *hp, struct tty_struct **flip,  			case VS_DATA_PACKET_HEADER:  				if (!is_open(hp))  					break; -				if (hp->tty == NULL) +				if (tty == NULL)  					break; /* no tty buffer to put data in */ -				*flip = hvsi_recv_data(hp, packet); +				flip = hvsi_recv_data(hp, tty, packet);  				break;  			case VS_CONTROL_PACKET_HEADER: -				hvsi_recv_control(hp, packet, hangup, handshake); +				hvsi_recv_control(hp, packet, tty, handshake);  				break;  			case VS_QUERY_RESPONSE_PACKET_HEADER:  				hvsi_recv_response(hp, packet); @@ -462,28 +460,26 @@ static int hvsi_load_chunk(struct hvsi_struct *hp, struct tty_struct **flip,  		packet += len_packet(packet); -		if (*hangup || *handshake) { -			pr_debug("%s: hangup or handshake\n", __func__); -			/* -			 * we need to send the hangup now before receiving any more data. -			 * If we get "data, hangup, data", we can't deliver the second -			 * data before the hangup. -			 */ +		if (*handshake) { +			pr_debug("%s: handshake\n", __func__);  			break;  		}  	}  	compact_inbuf(hp, packet); +	if (flip) +		tty_flip_buffer_push(tty); +  	return 1;  } -static void hvsi_send_overflow(struct hvsi_struct *hp) +static void hvsi_send_overflow(struct hvsi_struct *hp, struct tty_struct *tty)  {  	pr_debug("%s: delivering %i bytes overflow\n", __func__,  			hp->n_throttle); -	hvsi_insert_chars(hp, hp->throttle_buf, hp->n_throttle); +	hvsi_insert_chars(hp, tty, hp->throttle_buf, hp->n_throttle);  	hp->n_throttle = 0;  } @@ -494,35 +490,20 @@ static void hvsi_send_overflow(struct hvsi_struct *hp)  static irqreturn_t hvsi_interrupt(int irq, void *arg)  {  	struct hvsi_struct *hp = (struct hvsi_struct *)arg; -	struct tty_struct *flip; -	struct tty_struct *hangup;  	struct hvsi_struct *handshake; +	struct tty_struct *tty;  	unsigned long flags;  	int again = 1;  	pr_debug("%s\n", __func__); +	tty = tty_port_tty_get(&hp->port); +  	while (again) {  		spin_lock_irqsave(&hp->lock, flags); -		again = hvsi_load_chunk(hp, &flip, &hangup, &handshake); +		again = hvsi_load_chunk(hp, tty, &handshake);  		spin_unlock_irqrestore(&hp->lock, flags); -		/* -		 * we have to call tty_flip_buffer_push() and tty_hangup() outside our -		 * spinlock. But we also have to keep going until we've read all the -		 * available data. -		 */ - -		if (flip) { -			/* there was data put in the tty flip buffer */ -			tty_flip_buffer_push(flip); -			flip = NULL; -		} - -		if (hangup) { -			tty_hangup(hangup); -		} -  		if (handshake) {  			pr_debug("hvsi%i: attempting re-handshake\n", handshake->index);  			schedule_work(&handshake->handshaker); @@ -530,18 +511,15 @@ static irqreturn_t hvsi_interrupt(int irq, void *arg)  	}  	spin_lock_irqsave(&hp->lock, flags); -	if (hp->tty && hp->n_throttle -			&& (!test_bit(TTY_THROTTLED, &hp->tty->flags))) { -		/* we weren't hung up and we weren't throttled, so we can deliver the -		 * rest now */ -		flip = hp->tty; -		hvsi_send_overflow(hp); +	if (tty && hp->n_throttle && !test_bit(TTY_THROTTLED, &tty->flags)) { +		/* we weren't hung up and we weren't throttled, so we can +		 * deliver the rest now */ +		hvsi_send_overflow(hp, tty); +		tty_flip_buffer_push(tty);  	}  	spin_unlock_irqrestore(&hp->lock, flags); -	if (flip) { -		tty_flip_buffer_push(flip); -	} +	tty_kref_put(tty);  	return IRQ_HANDLED;  } @@ -749,9 +727,9 @@ static int hvsi_open(struct tty_struct *tty, struct file *filp)  	if (hp->state == HVSI_FSP_DIED)  		return -EIO; +	tty_port_tty_set(&hp->port, tty);  	spin_lock_irqsave(&hp->lock, flags); -	hp->tty = tty; -	hp->count++; +	hp->port.count++;  	atomic_set(&hp->seqno, 0);  	h_vio_signal(hp->vtermno, VIO_IRQ_ENABLE);  	spin_unlock_irqrestore(&hp->lock, flags); @@ -808,8 +786,8 @@ static void hvsi_close(struct tty_struct *tty, struct file *filp)  	spin_lock_irqsave(&hp->lock, flags); -	if (--hp->count == 0) { -		hp->tty = NULL; +	if (--hp->port.count == 0) { +		tty_port_tty_set(&hp->port, NULL);  		hp->inbuf_end = hp->inbuf; /* discard remaining partial packets */  		/* only close down connection if it is not the console */ @@ -841,9 +819,9 @@ static void hvsi_close(struct tty_struct *tty, struct file *filp)  			spin_lock_irqsave(&hp->lock, flags);  		} -	} else if (hp->count < 0) +	} else if (hp->port.count < 0)  		printk(KERN_ERR "hvsi_close %lu: oops, count is %d\n", -		       hp - hvsi_ports, hp->count); +		       hp - hvsi_ports, hp->port.count);  	spin_unlock_irqrestore(&hp->lock, flags);  } @@ -855,12 +833,11 @@ static void hvsi_hangup(struct tty_struct *tty)  	pr_debug("%s\n", __func__); -	spin_lock_irqsave(&hp->lock, flags); +	tty_port_tty_set(&hp->port, NULL); -	hp->count = 0; +	spin_lock_irqsave(&hp->lock, flags); +	hp->port.count = 0;  	hp->n_outbuf = 0; -	hp->tty = NULL; -  	spin_unlock_irqrestore(&hp->lock, flags);  } @@ -888,6 +865,7 @@ static void hvsi_write_worker(struct work_struct *work)  {  	struct hvsi_struct *hp =  		container_of(work, struct hvsi_struct, writer.work); +	struct tty_struct *tty;  	unsigned long flags;  #ifdef DEBUG  	static long start_j = 0; @@ -921,7 +899,11 @@ static void hvsi_write_worker(struct work_struct *work)  		start_j = 0;  #endif /* DEBUG */  		wake_up_all(&hp->emptyq); -		tty_wakeup(hp->tty); +		tty = tty_port_tty_get(&hp->port); +		if (tty) { +			tty_wakeup(tty); +			tty_kref_put(tty); +		}  	}  out: @@ -966,8 +948,8 @@ static int hvsi_write(struct tty_struct *tty,  	 * and hvsi_write_worker will be scheduled. subsequent hvsi_write() calls  	 * will see there is no room in outbuf and return.  	 */ -	while ((count > 0) && (hvsi_write_room(hp->tty) > 0)) { -		int chunksize = min(count, hvsi_write_room(hp->tty)); +	while ((count > 0) && (hvsi_write_room(tty) > 0)) { +		int chunksize = min(count, hvsi_write_room(tty));  		BUG_ON(hp->n_outbuf < 0);  		memcpy(hp->outbuf + hp->n_outbuf, source, chunksize); @@ -1014,19 +996,16 @@ static void hvsi_unthrottle(struct tty_struct *tty)  {  	struct hvsi_struct *hp = tty->driver_data;  	unsigned long flags; -	int shouldflip = 0;  	pr_debug("%s\n", __func__);  	spin_lock_irqsave(&hp->lock, flags);  	if (hp->n_throttle) { -		hvsi_send_overflow(hp); -		shouldflip = 1; +		hvsi_send_overflow(hp, tty); +		tty_flip_buffer_push(tty);  	}  	spin_unlock_irqrestore(&hp->lock, flags); -	if (shouldflip) -		tty_flip_buffer_push(hp->tty);  	h_vio_signal(hp->vtermno, VIO_IRQ_ENABLE);  } @@ -1228,6 +1207,7 @@ static int __init hvsi_console_init(void)  		init_waitqueue_head(&hp->emptyq);  		init_waitqueue_head(&hp->stateq);  		spin_lock_init(&hp->lock); +		tty_port_init(&hp->port);  		hp->index = hvsi_count;  		hp->inbuf_end = hp->inbuf;  		hp->state = HVSI_CLOSED; diff --git a/drivers/tty/hvc/hvsi_lib.c b/drivers/tty/hvc/hvsi_lib.c index 6f4dd83d869..59c135dd5d2 100644 --- a/drivers/tty/hvc/hvsi_lib.c +++ b/drivers/tty/hvc/hvsi_lib.c @@ -377,7 +377,7 @@ int hvsilib_open(struct hvsi_priv *pv, struct hvc_struct *hp)  	pr_devel("HVSI@%x: open !\n", pv->termno);  	/* Keep track of the tty data structure */ -	pv->tty = tty_kref_get(hp->tty); +	pv->tty = tty_port_tty_get(&hp->port);  	hvsilib_establish(pv); diff --git a/drivers/tty/ipwireless/tty.c b/drivers/tty/ipwireless/tty.c index 4daf962f705..f8b5fa0093a 100644 --- a/drivers/tty/ipwireless/tty.c +++ b/drivers/tty/ipwireless/tty.c @@ -44,14 +44,13 @@  #define TTYTYPE_RAS_RAW  (2)  struct ipw_tty { +	struct tty_port port;  	int index;  	struct ipw_hardware *hardware;  	unsigned int channel_idx;  	unsigned int secondary_channel_idx;  	int tty_type;  	struct ipw_network *network; -	struct tty_struct *linux_tty; -	int open_count;  	unsigned int control_lines;  	struct mutex ipw_tty_mutex;  	int tx_bytes_queued; @@ -73,23 +72,6 @@ static char *tty_type_name(int tty_type)  	return channel_names[tty_type];  } -static void report_registering(struct ipw_tty *tty) -{ -	char *iftype = tty_type_name(tty->tty_type); - -	printk(KERN_INFO IPWIRELESS_PCCARD_NAME -	       ": registering %s device ttyIPWp%d\n", iftype, tty->index); -} - -static void report_deregistering(struct ipw_tty *tty) -{ -	char *iftype = tty_type_name(tty->tty_type); - -	printk(KERN_INFO IPWIRELESS_PCCARD_NAME -	       ": deregistering %s device ttyIPWp%d\n", iftype, -	       tty->index); -} -  static struct ipw_tty *get_tty(int index)  {  	/* @@ -117,12 +99,12 @@ static int ipw_open(struct tty_struct *linux_tty, struct file *filp)  		mutex_unlock(&tty->ipw_tty_mutex);  		return -ENODEV;  	} -	if (tty->open_count == 0) +	if (tty->port.count == 0)  		tty->tx_bytes_queued = 0; -	tty->open_count++; +	tty->port.count++; -	tty->linux_tty = linux_tty; +	tty->port.tty = linux_tty;  	linux_tty->driver_data = tty;  	linux_tty->low_latency = 1; @@ -136,13 +118,13 @@ static int ipw_open(struct tty_struct *linux_tty, struct file *filp)  static void do_ipw_close(struct ipw_tty *tty)  { -	tty->open_count--; +	tty->port.count--; -	if (tty->open_count == 0) { -		struct tty_struct *linux_tty = tty->linux_tty; +	if (tty->port.count == 0) { +		struct tty_struct *linux_tty = tty->port.tty;  		if (linux_tty != NULL) { -			tty->linux_tty = NULL; +			tty->port.tty = NULL;  			linux_tty->driver_data = NULL;  			if (tty->tty_type == TTYTYPE_MODEM) @@ -159,7 +141,7 @@ static void ipw_hangup(struct tty_struct *linux_tty)  		return;  	mutex_lock(&tty->ipw_tty_mutex); -	if (tty->open_count == 0) { +	if (tty->port.count == 0) {  		mutex_unlock(&tty->ipw_tty_mutex);  		return;  	} @@ -182,13 +164,13 @@ void ipwireless_tty_received(struct ipw_tty *tty, unsigned char *data,  	int work = 0;  	mutex_lock(&tty->ipw_tty_mutex); -	linux_tty = tty->linux_tty; +	linux_tty = tty->port.tty;  	if (linux_tty == NULL) {  		mutex_unlock(&tty->ipw_tty_mutex);  		return;  	} -	if (!tty->open_count) { +	if (!tty->port.count) {  		mutex_unlock(&tty->ipw_tty_mutex);  		return;  	} @@ -230,7 +212,7 @@ static int ipw_write(struct tty_struct *linux_tty,  		return -ENODEV;  	mutex_lock(&tty->ipw_tty_mutex); -	if (!tty->open_count) { +	if (!tty->port.count) {  		mutex_unlock(&tty->ipw_tty_mutex);  		return -EINVAL;  	} @@ -270,7 +252,7 @@ static int ipw_write_room(struct tty_struct *linux_tty)  	if (!tty)  		return -ENODEV; -	if (!tty->open_count) +	if (!tty->port.count)  		return -EINVAL;  	room = IPWIRELESS_TX_QUEUE_SIZE - tty->tx_bytes_queued; @@ -312,7 +294,7 @@ static int ipw_chars_in_buffer(struct tty_struct *linux_tty)  	if (!tty)  		return 0; -	if (!tty->open_count) +	if (!tty->port.count)  		return 0;  	return tty->tx_bytes_queued; @@ -393,7 +375,7 @@ static int ipw_tiocmget(struct tty_struct *linux_tty)  	if (!tty)  		return -ENODEV; -	if (!tty->open_count) +	if (!tty->port.count)  		return -EINVAL;  	return get_control_lines(tty); @@ -409,7 +391,7 @@ ipw_tiocmset(struct tty_struct *linux_tty,  	if (!tty)  		return -ENODEV; -	if (!tty->open_count) +	if (!tty->port.count)  		return -EINVAL;  	return set_control_lines(tty, set, clear); @@ -423,7 +405,7 @@ static int ipw_ioctl(struct tty_struct *linux_tty,  	if (!tty)  		return -ENODEV; -	if (!tty->open_count) +	if (!tty->port.count)  		return -EINVAL;  	/* FIXME: Exactly how is the tty object locked here .. */ @@ -492,6 +474,7 @@ static int add_tty(int j,  	ttys[j]->network = network;  	ttys[j]->tty_type = tty_type;  	mutex_init(&ttys[j]->ipw_tty_mutex); +	tty_port_init(&ttys[j]->port);  	tty_register_device(ipw_tty_driver, j, NULL);  	ipwireless_associate_network_tty(network, channel_idx, ttys[j]); @@ -500,8 +483,12 @@ static int add_tty(int j,  		ipwireless_associate_network_tty(network,  						 secondary_channel_idx,  						 ttys[j]); -	if (get_tty(j) == ttys[j]) -		report_registering(ttys[j]); +	/* check if we provide raw device (if loopback is enabled) */ +	if (get_tty(j)) +		printk(KERN_INFO IPWIRELESS_PCCARD_NAME +		       ": registering %s device ttyIPWp%d\n", +		       tty_type_name(tty_type), j); +  	return 0;  } @@ -560,19 +547,21 @@ void ipwireless_tty_free(struct ipw_tty *tty)  		if (ttyj) {  			mutex_lock(&ttyj->ipw_tty_mutex); -			if (get_tty(j) == ttyj) -				report_deregistering(ttyj); +			if (get_tty(j)) +				printk(KERN_INFO IPWIRELESS_PCCARD_NAME +				       ": deregistering %s device ttyIPWp%d\n", +				       tty_type_name(ttyj->tty_type), j);  			ttyj->closing = 1; -			if (ttyj->linux_tty != NULL) { +			if (ttyj->port.tty != NULL) {  				mutex_unlock(&ttyj->ipw_tty_mutex); -				tty_hangup(ttyj->linux_tty); -				/* Wait till the tty_hangup has completed */ -				flush_work_sync(&ttyj->linux_tty->hangup_work); +				tty_vhangup(ttyj->port.tty);  				/* FIXME: Exactly how is the tty object locked here  				   against a parallel ioctl etc */ +				/* FIXME2: hangup does not mean all processes +				 * are gone */  				mutex_lock(&ttyj->ipw_tty_mutex);  			} -			while (ttyj->open_count) +			while (ttyj->port.count)  				do_ipw_close(ttyj);  			ipwireless_disassociate_network_ttys(network,  							     ttyj->channel_idx); @@ -661,8 +650,8 @@ ipwireless_tty_notify_control_line_change(struct ipw_tty *tty,  	 */  	if ((old_control_lines & IPW_CONTROL_LINE_DCD)  			&& !(tty->control_lines & IPW_CONTROL_LINE_DCD) -			&& tty->linux_tty) { -		tty_hangup(tty->linux_tty); +			&& tty->port.tty) { +		tty_hangup(tty->port.tty);  	}  } diff --git a/drivers/tty/mxser.c b/drivers/tty/mxser.c index c6f372dd562..90cc680c4f0 100644 --- a/drivers/tty/mxser.c +++ b/drivers/tty/mxser.c @@ -2326,7 +2326,7 @@ static const struct tty_operations mxser_ops = {  	.get_icount = mxser_get_icount,  }; -struct tty_port_operations mxser_port_ops = { +static struct tty_port_operations mxser_port_ops = {  	.carrier_raised = mxser_carrier_raised,  	.dtr_rts = mxser_dtr_rts,  	.activate = mxser_activate, diff --git a/drivers/tty/n_r3964.c b/drivers/tty/n_r3964.c index 5c6c31459a2..656ad93bbc9 100644 --- a/drivers/tty/n_r3964.c +++ b/drivers/tty/n_r3964.c @@ -1065,7 +1065,8 @@ static ssize_t r3964_read(struct tty_struct *tty, struct file *file,  	TRACE_L("read()"); -	tty_lock(); +	/* FIXME: should use a private lock */ +	tty_lock(tty);  	pClient = findClient(pInfo, task_pid(current));  	if (pClient) { @@ -1077,7 +1078,7 @@ static ssize_t r3964_read(struct tty_struct *tty, struct file *file,  				goto unlock;  			}  			/* block until there is a message: */ -			wait_event_interruptible_tty(pInfo->read_wait, +			wait_event_interruptible_tty(tty, pInfo->read_wait,  					(pMsg = remove_msg(pInfo, pClient)));  		} @@ -1107,7 +1108,7 @@ static ssize_t r3964_read(struct tty_struct *tty, struct file *file,  	}  	ret = -EPERM;  unlock: -	tty_unlock(); +	tty_unlock(tty);  	return ret;  } @@ -1156,7 +1157,7 @@ static ssize_t r3964_write(struct tty_struct *tty, struct file *file,  	pHeader->locks = 0;  	pHeader->owner = NULL; -	tty_lock(); +	tty_lock(tty);  	pClient = findClient(pInfo, task_pid(current));  	if (pClient) { @@ -1175,7 +1176,7 @@ static ssize_t r3964_write(struct tty_struct *tty, struct file *file,  	add_tx_queue(pInfo, pHeader);  	trigger_transmit(pInfo); -	tty_unlock(); +	tty_unlock(tty);  	return 0;  } diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c index 94b6eda87af..ee1c268f5f9 100644 --- a/drivers/tty/n_tty.c +++ b/drivers/tty/n_tty.c @@ -1630,6 +1630,7 @@ static int copy_from_read_buf(struct tty_struct *tty,  	int retval;  	size_t n;  	unsigned long flags; +	bool is_eof;  	retval = 0;  	spin_lock_irqsave(&tty->read_lock, flags); @@ -1639,15 +1640,15 @@ static int copy_from_read_buf(struct tty_struct *tty,  	if (n) {  		retval = copy_to_user(*b, &tty->read_buf[tty->read_tail], n);  		n -= retval; +		is_eof = n == 1 && +			tty->read_buf[tty->read_tail] == EOF_CHAR(tty);  		tty_audit_add_data(tty, &tty->read_buf[tty->read_tail], n);  		spin_lock_irqsave(&tty->read_lock, flags);  		tty->read_tail = (tty->read_tail + n) & (N_TTY_BUF_SIZE-1);  		tty->read_cnt -= n;  		/* Turn single EOF into zero-length read */ -		if (L_EXTPROC(tty) && tty->icanon && n == 1) { -			if (!tty->read_cnt && (*b)[n-1] == EOF_CHAR(tty)) -				n--; -		} +		if (L_EXTPROC(tty) && tty->icanon && is_eof && !tty->read_cnt) +			n = 0;  		spin_unlock_irqrestore(&tty->read_lock, flags);  		*b += n;  		*nr -= n; diff --git a/drivers/tty/pty.c b/drivers/tty/pty.c index eeae7fafe9a..59af3945ea8 100644 --- a/drivers/tty/pty.c +++ b/drivers/tty/pty.c @@ -26,11 +26,13 @@  #include <linux/bitops.h>  #include <linux/devpts_fs.h>  #include <linux/slab.h> +#include <linux/mutex.h>  #ifdef CONFIG_UNIX98_PTYS  static struct tty_driver *ptm_driver;  static struct tty_driver *pts_driver; +static DEFINE_MUTEX(devpts_mutex);  #endif  static void pty_close(struct tty_struct *tty, struct file *filp) @@ -45,6 +47,7 @@ static void pty_close(struct tty_struct *tty, struct file *filp)  	wake_up_interruptible(&tty->read_wait);  	wake_up_interruptible(&tty->write_wait);  	tty->packet = 0; +	/* Review - krefs on tty_link ?? */  	if (!tty->link)  		return;  	tty->link->packet = 0; @@ -54,12 +57,15 @@ static void pty_close(struct tty_struct *tty, struct file *filp)  	if (tty->driver->subtype == PTY_TYPE_MASTER) {  		set_bit(TTY_OTHER_CLOSED, &tty->flags);  #ifdef CONFIG_UNIX98_PTYS -		if (tty->driver == ptm_driver) +		if (tty->driver == ptm_driver) { +		        mutex_lock(&devpts_mutex);  			devpts_pty_kill(tty->link); +		        mutex_unlock(&devpts_mutex); +		}  #endif -		tty_unlock(); +		tty_unlock(tty);  		tty_vhangup(tty->link); -		tty_lock(); +		tty_lock(tty);  	}  } @@ -475,13 +481,17 @@ static struct tty_struct *ptm_unix98_lookup(struct tty_driver *driver,   *	@idx: tty index   *   *	Look up a pty master device. Called under the tty_mutex for now. - *	This provides our locking. + *	This provides our locking for the tty pointer.   */  static struct tty_struct *pts_unix98_lookup(struct tty_driver *driver,  		struct inode *pts_inode, int idx)  { -	struct tty_struct *tty = devpts_get_tty(pts_inode, idx); +	struct tty_struct *tty; + +	mutex_lock(&devpts_mutex); +	tty = devpts_get_tty(pts_inode, idx); +	mutex_unlock(&devpts_mutex);  	/* Master must be open before slave */  	if (!tty)  		return ERR_PTR(-EIO); @@ -613,24 +623,29 @@ static int ptmx_open(struct inode *inode, struct file *filp)  		return retval;  	/* find a device that is not in use. */ -	tty_lock(); +	mutex_lock(&devpts_mutex);  	index = devpts_new_index(inode); -	tty_unlock();  	if (index < 0) {  		retval = index;  		goto err_file;  	} +	mutex_unlock(&devpts_mutex); +  	mutex_lock(&tty_mutex); -	tty_lock(); +	mutex_lock(&devpts_mutex);  	tty = tty_init_dev(ptm_driver, index); -	mutex_unlock(&tty_mutex);  	if (IS_ERR(tty)) {  		retval = PTR_ERR(tty);  		goto out;  	} +	/* The tty returned here is locked so we can safely +	   drop the mutex */ +	mutex_unlock(&devpts_mutex); +	mutex_unlock(&tty_mutex); +  	set_bit(TTY_PTY_LOCK, &tty->flags); /* LOCK THE SLAVE */  	tty_add_file(tty, filp); @@ -643,16 +658,17 @@ static int ptmx_open(struct inode *inode, struct file *filp)  	if (retval)  		goto err_release; -	tty_unlock(); +	tty_unlock(tty);  	return 0;  err_release: -	tty_unlock(); +	tty_unlock(tty);  	tty_release(inode, filp);  	return retval;  out: +	mutex_unlock(&tty_mutex);  	devpts_kill_index(inode, index); -	tty_unlock();  err_file: +        mutex_unlock(&devpts_mutex);  	tty_free_file(filp);  	return retval;  } diff --git a/drivers/tty/serial/68328serial.c b/drivers/tty/serial/68328serial.c index 5ce782529d6..3ed20e435e5 100644 --- a/drivers/tty/serial/68328serial.c +++ b/drivers/tty/serial/68328serial.c @@ -17,6 +17,7 @@  #include <asm/dbg.h>  #include <linux/module.h>  #include <linux/errno.h> +#include <linux/serial.h>  #include <linux/signal.h>  #include <linux/sched.h>  #include <linux/timer.h> @@ -56,8 +57,6 @@  #endif /* CONFIG_M68VZ328 */  #endif /* CONFIG_M68EZ328 */ -#include "68328serial.h" -  /* Turn off usage of real serial interrupt code, to "support" Copilot */  #ifdef CONFIG_XCOPILOT_BUGS  #undef USE_INTS @@ -65,33 +64,82 @@  #define USE_INTS  #endif -static struct m68k_serial m68k_soft[NR_PORTS]; +/* + * I believe this is the optimal setting that reduces the number of interrupts. + * At high speeds the output might become a little "bursted" (use USTCNT_TXHE + * if that bothers you), but in most cases it will not, since we try to + * transmit characters every time rs_interrupt is called. Thus, quite often + * you'll see that a receive interrupt occures before the transmit one. + *                                  -- Vladimir Gurevich + */ +#define USTCNT_TX_INTR_MASK (USTCNT_TXEE) -static unsigned int uart_irqs[NR_PORTS] = UART_IRQ_DEFNS; +/* + * 68328 and 68EZ328 UARTS are a little bit different. EZ328 has special + * "Old data interrupt" which occures whenever the data stay in the FIFO + * longer than 30 bits time. This allows us to use FIFO without compromising + * latency. '328 does not have this feature and without the real  328-based + * board I would assume that RXRE is the safest setting. + * + * For EZ328 I use RXHE (Half empty) interrupt to reduce the number of + * interrupts. RXFE (receive queue full) causes the system to lose data + * at least at 115200 baud + * + * If your board is busy doing other stuff, you might consider to use + * RXRE (data ready intrrupt) instead. + * + * The other option is to make these INTR masks run-time configurable, so + * that people can dynamically adapt them according to the current usage. + *                                  -- Vladimir Gurevich + */ -/* multiple ports are contiguous in memory */ -m68328_uart *uart_addr = (m68328_uart *)USTCNT_ADDR; +/* (es) */ +#if defined(CONFIG_M68EZ328) || defined(CONFIG_M68VZ328) +#define USTCNT_RX_INTR_MASK (USTCNT_RXHE | USTCNT_ODEN) +#elif defined(CONFIG_M68328) +#define USTCNT_RX_INTR_MASK (USTCNT_RXRE) +#else +#error Please, define the Rx interrupt events for your CPU +#endif +/* (/es) */ -struct tty_struct m68k_ttys; -struct m68k_serial *m68k_consinfo = 0; +/* + * This is our internal structure for each serial port's state. + */ +struct m68k_serial { +	struct tty_port		tport; +	char			is_cons;	/* Is this our console. */ +	int			magic; +	int			baud_base; +	int			port; +	int			irq; +	int			type;		/* UART type */ +	int			custom_divisor; +	int			x_char;		/* xon/xoff character */ +	int			line; +	unsigned char		*xmit_buf; +	int			xmit_head; +	int			xmit_tail; +	int			xmit_cnt; +}; -#define M68K_CLOCK (16667000) /* FIXME: 16MHz is likely wrong */ +#define SERIAL_MAGIC 0x5301 -struct tty_driver *serial_driver; +/* + * Define the number of ports supported and their irqs. + */ +#define NR_PORTS 1 -/* number of characters left in xmit buffer before we ask for more */ -#define WAKEUP_CHARS 256 +static struct m68k_serial m68k_soft[NR_PORTS]; -/* Debugging... DEBUG_INTR is bad to use when one of the zs - * lines is your console ;( - */ -#undef SERIAL_DEBUG_INTR -#undef SERIAL_DEBUG_OPEN -#undef SERIAL_DEBUG_FLOW +static unsigned int uart_irqs[NR_PORTS] = { UART_IRQ_NUM }; -#define RS_ISR_PASS_LIMIT 256 +/* multiple ports are contiguous in memory */ +m68328_uart *uart_addr = (m68328_uart *)USTCNT_ADDR; + +struct tty_driver *serial_driver; -static void change_speed(struct m68k_serial *info); +static void change_speed(struct m68k_serial *info, struct tty_struct *tty);  /*   *	Setup for console. Argument comes from the boot command line. @@ -143,17 +191,6 @@ static int baud_table[] = {  	0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,  	9600, 19200, 38400, 57600, 115200, 0 }; -/* Sets or clears DTR/RTS on the requested line */ -static inline void m68k_rtsdtr(struct m68k_serial *ss, int set) -{ -	if (set) { -		/* set the RTS/CTS line */ -	} else { -		/* clear it */ -	} -	return; -} -  /* Utility routines */  static inline int get_baud(struct m68k_serial *ss)  { @@ -189,7 +226,8 @@ static void rs_stop(struct tty_struct *tty)  static int rs_put_char(char ch)  { -        int flags, loops = 0; +	unsigned long flags; +	int loops = 0;          local_irq_save(flags); @@ -224,28 +262,9 @@ static void rs_start(struct tty_struct *tty)  	local_irq_restore(flags);  } -/* Drop into either the boot monitor or kadb upon receiving a break - * from keyboard/console input. - */ -static void batten_down_hatches(void) -{ -	/* Drop into the debugger */ -} - -static void status_handle(struct m68k_serial *info, unsigned short status) +static void receive_chars(struct m68k_serial *info, struct tty_struct *tty, +		unsigned short rx)  { -	/* If this is console input and this is a -	 * 'break asserted' status change interrupt -	 * see if we can drop into the debugger -	 */ -	if((status & URX_BREAK) && info->break_abort) -		batten_down_hatches(); -	return; -} - -static void receive_chars(struct m68k_serial *info, unsigned short rx) -{ -	struct tty_struct *tty = info->tty;  	m68328_uart *uart = &uart_addr[info->line];  	unsigned char ch, flag; @@ -259,7 +278,6 @@ static void receive_chars(struct m68k_serial *info, unsigned short rx)  		if(info->is_cons) {  			if(URX_BREAK & rx) { /* whee, break received */ -				status_handle(info, rx);  				return;  #ifdef CONFIG_MAGIC_SYSRQ  			} else if (ch == 0x10) { /* ^P */ @@ -280,16 +298,13 @@ static void receive_chars(struct m68k_serial *info, unsigned short rx)  		flag = TTY_NORMAL; -		if(rx & URX_PARITY_ERROR) { +		if (rx & URX_PARITY_ERROR)  			flag = TTY_PARITY; -			status_handle(info, rx); -		} else if(rx & URX_OVRUN) { +		else if (rx & URX_OVRUN)  			flag = TTY_OVERRUN; -			status_handle(info, rx); -		} else if(rx & URX_FRAME_ERROR) { +		else if (rx & URX_FRAME_ERROR)  			flag = TTY_FRAME; -			status_handle(info, rx); -		} +  		tty_insert_flip_char(tty, ch, flag);  #ifndef CONFIG_XCOPILOT_BUGS  	} while((rx = uart->urx.w) & URX_DATA_READY); @@ -301,7 +316,7 @@ clear_and_exit:  	return;  } -static void transmit_chars(struct m68k_serial *info) +static void transmit_chars(struct m68k_serial *info, struct tty_struct *tty)  {  	m68328_uart *uart = &uart_addr[info->line]; @@ -312,7 +327,7 @@ static void transmit_chars(struct m68k_serial *info)  		goto clear_and_return;  	} -	if((info->xmit_cnt <= 0) || info->tty->stopped) { +	if ((info->xmit_cnt <= 0) || !tty || tty->stopped) {  		/* That's peculiar... TX ints off */  		uart->ustcnt &= ~USTCNT_TX_INTR_MASK;  		goto clear_and_return; @@ -340,6 +355,7 @@ clear_and_return:  irqreturn_t rs_interrupt(int irq, void *dev_id)  {  	struct m68k_serial *info = dev_id; +	struct tty_struct *tty = tty_port_tty_get(&info->tport);  	m68328_uart *uart;  	unsigned short rx;  	unsigned short tx; @@ -350,20 +366,24 @@ irqreturn_t rs_interrupt(int irq, void *dev_id)  #ifdef USE_INTS  	tx = uart->utx.w; -	if (rx & URX_DATA_READY) receive_chars(info, rx); -	if (tx & UTX_TX_AVAIL)   transmit_chars(info); +	if (rx & URX_DATA_READY) +		receive_chars(info, tty, rx); +	if (tx & UTX_TX_AVAIL) +		transmit_chars(info, tty);  #else -	receive_chars(info, rx);		 +	receive_chars(info, tty, rx);  #endif +	tty_kref_put(tty); +  	return IRQ_HANDLED;  } -static int startup(struct m68k_serial * info) +static int startup(struct m68k_serial *info, struct tty_struct *tty)  {  	m68328_uart *uart = &uart_addr[info->line];  	unsigned long flags; -	if (info->flags & S_INITIALIZED) +	if (info->tport.flags & ASYNC_INITIALIZED)  		return 0;  	if (!info->xmit_buf) { @@ -380,7 +400,6 @@ static int startup(struct m68k_serial * info)  	 */  	uart->ustcnt = USTCNT_UEN; -	info->xmit_fifo_size = 1;  	uart->ustcnt = USTCNT_UEN | USTCNT_RXEN | USTCNT_TXEN;  	(void)uart->urx.w; @@ -394,17 +413,17 @@ static int startup(struct m68k_serial * info)  	uart->ustcnt = USTCNT_UEN | USTCNT_RXEN | USTCNT_RX_INTR_MASK;  #endif -	if (info->tty) -		clear_bit(TTY_IO_ERROR, &info->tty->flags); +	if (tty) +		clear_bit(TTY_IO_ERROR, &tty->flags);  	info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;  	/*  	 * and set the speed of the serial port  	 */ -	change_speed(info); +	change_speed(info, tty); -	info->flags |= S_INITIALIZED; +	info->tport.flags |= ASYNC_INITIALIZED;  	local_irq_restore(flags);  	return 0;  } @@ -413,13 +432,13 @@ static int startup(struct m68k_serial * info)   * This routine will shutdown a serial port; interrupts are disabled, and   * DTR is dropped if the hangup on close termio flag is on.   */ -static void shutdown(struct m68k_serial * info) +static void shutdown(struct m68k_serial *info, struct tty_struct *tty)  {  	m68328_uart *uart = &uart_addr[info->line];  	unsigned long	flags;  	uart->ustcnt = 0; /* All off! */ -	if (!(info->flags & S_INITIALIZED)) +	if (!(info->tport.flags & ASYNC_INITIALIZED))  		return;  	local_irq_save(flags); @@ -429,10 +448,10 @@ static void shutdown(struct m68k_serial * info)  		info->xmit_buf = 0;  	} -	if (info->tty) -		set_bit(TTY_IO_ERROR, &info->tty->flags); +	if (tty) +		set_bit(TTY_IO_ERROR, &tty->flags); -	info->flags &= ~S_INITIALIZED; +	info->tport.flags &= ~ASYNC_INITIALIZED;  	local_irq_restore(flags);  } @@ -488,7 +507,7 @@ struct {   * This routine is called to set the UART divisor registers to match   * the specified baud rate for a serial port.   */ -static void change_speed(struct m68k_serial *info) +static void change_speed(struct m68k_serial *info, struct tty_struct *tty)  {  	m68328_uart *uart = &uart_addr[info->line];  	unsigned short port; @@ -496,9 +515,7 @@ static void change_speed(struct m68k_serial *info)  	unsigned cflag;  	int	i; -	if (!info->tty || !info->tty->termios) -		return; -	cflag = info->tty->termios->c_cflag; +	cflag = tty->termios->c_cflag;  	if (!(port = info->port))  		return; @@ -510,7 +527,6 @@ static void change_speed(struct m68k_serial *info)                  i = (i & ~CBAUDEX) + B38400;          } -	info->baud = baud_table[i];  	uart->ubaud = PUT_FIELD(UBAUD_DIVIDE,    hw_baud_table[i].divisor) |   		PUT_FIELD(UBAUD_PRESCALER, hw_baud_table[i].prescale); @@ -807,10 +823,10 @@ static int get_serial_info(struct m68k_serial * info,  	tmp.line = info->line;  	tmp.port = info->port;  	tmp.irq = info->irq; -	tmp.flags = info->flags; +	tmp.flags = info->tport.flags;  	tmp.baud_base = info->baud_base; -	tmp.close_delay = info->close_delay; -	tmp.closing_wait = info->closing_wait; +	tmp.close_delay = info->tport.close_delay; +	tmp.closing_wait = info->tport.closing_wait;  	tmp.custom_divisor = info->custom_divisor;  	if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))  		return -EFAULT; @@ -818,9 +834,10 @@ static int get_serial_info(struct m68k_serial * info,  	return 0;  } -static int set_serial_info(struct m68k_serial * info, +static int set_serial_info(struct m68k_serial *info, struct tty_struct *tty,  			   struct serial_struct * new_info)  { +	struct tty_port *port = &info->tport;  	struct serial_struct new_serial;  	struct m68k_serial old_info;  	int 			retval = 0; @@ -834,17 +851,17 @@ static int set_serial_info(struct m68k_serial * info,  	if (!capable(CAP_SYS_ADMIN)) {  		if ((new_serial.baud_base != info->baud_base) ||  		    (new_serial.type != info->type) || -		    (new_serial.close_delay != info->close_delay) || -		    ((new_serial.flags & ~S_USR_MASK) != -		     (info->flags & ~S_USR_MASK))) +		    (new_serial.close_delay != port->close_delay) || +		    ((new_serial.flags & ~ASYNC_USR_MASK) != +		     (port->flags & ~ASYNC_USR_MASK)))  			return -EPERM; -		info->flags = ((info->flags & ~S_USR_MASK) | -			       (new_serial.flags & S_USR_MASK)); +		port->flags = ((port->flags & ~ASYNC_USR_MASK) | +			       (new_serial.flags & ASYNC_USR_MASK));  		info->custom_divisor = new_serial.custom_divisor;  		goto check_and_exit;  	} -	if (info->count > 1) +	if (port->count > 1)  		return -EBUSY;  	/* @@ -853,14 +870,14 @@ static int set_serial_info(struct m68k_serial * info,  	 */  	info->baud_base = new_serial.baud_base; -	info->flags = ((info->flags & ~S_FLAGS) | -			(new_serial.flags & S_FLAGS)); +	port->flags = ((port->flags & ~ASYNC_FLAGS) | +			(new_serial.flags & ASYNC_FLAGS));  	info->type = new_serial.type; -	info->close_delay = new_serial.close_delay; -	info->closing_wait = new_serial.closing_wait; +	port->close_delay = new_serial.close_delay; +	port->closing_wait = new_serial.closing_wait;  check_and_exit: -	retval = startup(info); +	retval = startup(info, tty);  	return retval;  } @@ -946,7 +963,7 @@ static int rs_ioctl(struct tty_struct *tty,  			return get_serial_info(info,  				       (struct serial_struct *) arg);  		case TIOCSSERIAL: -			return set_serial_info(info, +			return set_serial_info(info, tty,  					       (struct serial_struct *) arg);  		case TIOCSERGETLSR: /* Get line status register */  			return get_lsr_info(info, (unsigned int *) arg); @@ -965,7 +982,7 @@ static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios)  {  	struct m68k_serial *info = (struct m68k_serial *)tty->driver_data; -	change_speed(info); +	change_speed(info, tty);  	if ((old_termios->c_cflag & CRTSCTS) &&  	    !(tty->termios->c_cflag & CRTSCTS)) { @@ -988,6 +1005,7 @@ static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios)  static void rs_close(struct tty_struct *tty, struct file * filp)  {  	struct m68k_serial * info = (struct m68k_serial *)tty->driver_data; +	struct tty_port *port = &info->tport;  	m68328_uart *uart = &uart_addr[info->line];  	unsigned long flags; @@ -1001,7 +1019,7 @@ static void rs_close(struct tty_struct *tty, struct file * filp)  		return;  	} -	if ((tty->count == 1) && (info->count != 1)) { +	if ((tty->count == 1) && (port->count != 1)) {  		/*  		 * Uh, oh.  tty->count is 1, which means that the tty  		 * structure will be freed.  Info->count should always @@ -1010,26 +1028,26 @@ static void rs_close(struct tty_struct *tty, struct file * filp)  		 * serial port won't be shutdown.  		 */  		printk("rs_close: bad serial port count; tty->count is 1, " -		       "info->count is %d\n", info->count); -		info->count = 1; +		       "port->count is %d\n", port->count); +		port->count = 1;  	} -	if (--info->count < 0) { +	if (--port->count < 0) {  		printk("rs_close: bad serial port count for ttyS%d: %d\n", -		       info->line, info->count); -		info->count = 0; +		       info->line, port->count); +		port->count = 0;  	} -	if (info->count) { +	if (port->count) {  		local_irq_restore(flags);  		return;  	} -	info->flags |= S_CLOSING; +	port->flags |= ASYNC_CLOSING;  	/*  	 * Now we wait for the transmit buffer to clear; and we notify   	 * the line discipline to only process XON/XOFF characters.  	 */  	tty->closing = 1; -	if (info->closing_wait != S_CLOSING_WAIT_NONE) -		tty_wait_until_sent(tty, info->closing_wait); +	if (port->closing_wait != ASYNC_CLOSING_WAIT_NONE) +		tty_wait_until_sent(tty, port->closing_wait);  	/*  	 * At this point we stop accepting input.  To do this, we  	 * disable the receive line status interrupts, and tell the @@ -1040,13 +1058,12 @@ static void rs_close(struct tty_struct *tty, struct file * filp)  	uart->ustcnt &= ~USTCNT_RXEN;  	uart->ustcnt &= ~(USTCNT_RXEN | USTCNT_RX_INTR_MASK); -	shutdown(info); +	shutdown(info, tty);  	rs_flush_buffer(tty);  	tty_ldisc_flush(tty);  	tty->closing = 0; -	info->event = 0; -	info->tty = NULL; +	tty_port_tty_set(&info->tport, NULL);  #warning "This is not and has never been valid so fix it"	  #if 0  	if (tty->ldisc.num != ldiscs[N_TTY].num) { @@ -1058,14 +1075,13 @@ static void rs_close(struct tty_struct *tty, struct file * filp)  			(tty->ldisc.open)(tty);  	}  #endif	 -	if (info->blocked_open) { -		if (info->close_delay) { -			msleep_interruptible(jiffies_to_msecs(info->close_delay)); -		} -		wake_up_interruptible(&info->open_wait); +	if (port->blocked_open) { +		if (port->close_delay) +			msleep_interruptible(jiffies_to_msecs(port->close_delay)); +		wake_up_interruptible(&port->open_wait);  	} -	info->flags &= ~(S_NORMAL_ACTIVE|S_CLOSING); -	wake_up_interruptible(&info->close_wait); +	port->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING); +	wake_up_interruptible(&port->close_wait);  	local_irq_restore(flags);  } @@ -1080,107 +1096,14 @@ void rs_hangup(struct tty_struct *tty)  		return;  	rs_flush_buffer(tty); -	shutdown(info); -	info->event = 0; -	info->count = 0; -	info->flags &= ~S_NORMAL_ACTIVE; -	info->tty = NULL; -	wake_up_interruptible(&info->open_wait); +	shutdown(info, tty); +	info->tport.count = 0; +	info->tport.flags &= ~ASYNC_NORMAL_ACTIVE; +	tty_port_tty_set(&info->tport, NULL); +	wake_up_interruptible(&info->tport.open_wait);  }  /* - * ------------------------------------------------------------ - * rs_open() and friends - * ------------------------------------------------------------ - */ -static int block_til_ready(struct tty_struct *tty, struct file * filp, -			   struct m68k_serial *info) -{ -	DECLARE_WAITQUEUE(wait, current); -	int		retval; -	int		do_clocal = 0; - -	/* -	 * If the device is in the middle of being closed, then block -	 * until it's done, and then try again. -	 */ -	if (info->flags & S_CLOSING) { -		interruptible_sleep_on(&info->close_wait); -#ifdef SERIAL_DO_RESTART -		if (info->flags & S_HUP_NOTIFY) -			return -EAGAIN; -		else -			return -ERESTARTSYS; -#else -		return -EAGAIN; -#endif -	} -	 -	/* -	 * If non-blocking mode is set, or the port is not enabled, -	 * then make the check up front and then exit. -	 */ -	if ((filp->f_flags & O_NONBLOCK) || -	    (tty->flags & (1 << TTY_IO_ERROR))) { -		info->flags |= S_NORMAL_ACTIVE; -		return 0; -	} - -	if (tty->termios->c_cflag & CLOCAL) -		do_clocal = 1; - -	/* -	 * Block waiting for the carrier detect and the line to become -	 * free (i.e., not in use by the callout).  While we are in -	 * this loop, info->count is dropped by one, so that -	 * rs_close() knows when to free things.  We restore it upon -	 * exit, either normal or abnormal. -	 */ -	retval = 0; -	add_wait_queue(&info->open_wait, &wait); - -	info->count--; -	info->blocked_open++; -	while (1) { -		local_irq_disable(); -		m68k_rtsdtr(info, 1); -		local_irq_enable(); -		current->state = TASK_INTERRUPTIBLE; -		if (tty_hung_up_p(filp) || -		    !(info->flags & S_INITIALIZED)) { -#ifdef SERIAL_DO_RESTART -			if (info->flags & S_HUP_NOTIFY) -				retval = -EAGAIN; -			else -				retval = -ERESTARTSYS;	 -#else -			retval = -EAGAIN; -#endif -			break; -		} -		if (!(info->flags & S_CLOSING) && do_clocal) -			break; -                if (signal_pending(current)) { -			retval = -ERESTARTSYS; -			break; -		} -		tty_unlock(); -		schedule(); -		tty_lock(); -	} -	current->state = TASK_RUNNING; -	remove_wait_queue(&info->open_wait, &wait); -	if (!tty_hung_up_p(filp)) -		info->count++; -	info->blocked_open--; - -	if (retval) -		return retval; -	info->flags |= S_NORMAL_ACTIVE; -	return 0; -}	 - -/*   * This routine is called whenever a serial port is opened.  It   * enables interrupts for a serial port, linking in its S structure into   * the IRQ chain.   It also performs the serial-specific @@ -1196,18 +1119,18 @@ int rs_open(struct tty_struct *tty, struct file * filp)  	if (serial_paranoia_check(info, tty->name, "rs_open"))  		return -ENODEV; -	info->count++; +	info->tport.count++;  	tty->driver_data = info; -	info->tty = tty; +	tty_port_tty_set(&info->tport, tty);  	/*  	 * Start up serial port  	 */ -	retval = startup(info); +	retval = startup(info, tty);  	if (retval)  		return retval; -	return block_til_ready(tty, filp, info); +	return tty_port_block_til_ready(&info->tport, tty, filp);  }  /* Finally, routines used to initialize the serial driver. */ @@ -1235,11 +1158,15 @@ static const struct tty_operations rs_ops = {  	.set_ldisc = rs_set_ldisc,  }; +static const struct tty_port_operations rs_port_ops = { +}; +  /* rs_init inits the driver */  static int __init  rs68328_init(void)  { -	int flags, i; +	unsigned long flags; +	int i;  	struct m68k_serial *info;  	serial_driver = alloc_tty_driver(NR_PORTS); @@ -1273,19 +1200,13 @@ rs68328_init(void)  	for(i=0;i<NR_PORTS;i++) {  	    info = &m68k_soft[i]; +	    tty_port_init(&info->tport); +	    info->tport.ops = &rs_port_ops;  	    info->magic = SERIAL_MAGIC;  	    info->port = (int) &uart_addr[i]; -	    info->tty = NULL;  	    info->irq = uart_irqs[i];  	    info->custom_divisor = 16; -	    info->close_delay = 50; -	    info->closing_wait = 3000;  	    info->x_char = 0; -	    info->event = 0; -	    info->count = 0; -	    info->blocked_open = 0; -	    init_waitqueue_head(&info->open_wait); -	    init_waitqueue_head(&info->close_wait);  	    info->line = i;  	    info->is_cons = 1; /* Means shortcuts work */ diff --git a/drivers/tty/serial/68328serial.h b/drivers/tty/serial/68328serial.h deleted file mode 100644 index 3d2faabd766..00000000000 --- a/drivers/tty/serial/68328serial.h +++ /dev/null @@ -1,186 +0,0 @@ -/* 68328serial.h: Definitions for the mc68328 serial driver. - * - * Copyright (C) 1995       David S. Miller    <davem@caip.rutgers.edu> - * Copyright (C) 1998       Kenneth Albanowski <kjahds@kjahds.com> - * Copyright (C) 1998, 1999 D. Jeff Dionne     <jeff@uclinux.org> - * Copyright (C) 1999       Vladimir Gurevich  <vgurevic@cisco.com> - * - * VZ Support/Fixes             Evan Stawnyczy <e@lineo.ca> - */ - -#ifndef _MC683XX_SERIAL_H -#define _MC683XX_SERIAL_H - - -struct serial_struct { -	int	type; -	int	line; -	int	port; -	int	irq; -	int	flags; -	int	xmit_fifo_size; -	int	custom_divisor; -	int	baud_base; -	unsigned short	close_delay; -	char	reserved_char[2]; -	int	hub6;  /* FIXME: We don't have AT&T Hub6 boards! */ -	unsigned short	closing_wait; /* time to wait before closing */ -	unsigned short	closing_wait2; /* no longer used... */ -	int	reserved[4]; -}; - -/* - * For the close wait times, 0 means wait forever for serial port to - * flush its output.  65535 means don't wait at all. - */ -#define S_CLOSING_WAIT_INF	0 -#define S_CLOSING_WAIT_NONE	65535 - -/* - * Definitions for S_struct (and serial_struct) flags field - */ -#define S_HUP_NOTIFY 0x0001 /* Notify getty on hangups and closes  -				   on the callout port */ -#define S_FOURPORT  0x0002	/* Set OU1, OUT2 per AST Fourport settings */ -#define S_SAK	0x0004	/* Secure Attention Key (Orange book) */ -#define S_SPLIT_TERMIOS 0x0008 /* Separate termios for dialin/callout */ - -#define S_SPD_MASK	0x0030 -#define S_SPD_HI	0x0010	/* Use 56000 instead of 38400 bps */ - -#define S_SPD_VHI	0x0020  /* Use 115200 instead of 38400 bps */ -#define S_SPD_CUST	0x0030  /* Use user-specified divisor */ - -#define S_SKIP_TEST	0x0040 /* Skip UART test during autoconfiguration */ -#define S_AUTO_IRQ  0x0080 /* Do automatic IRQ during autoconfiguration */ -#define S_SESSION_LOCKOUT 0x0100 /* Lock out cua opens based on session */ -#define S_PGRP_LOCKOUT    0x0200 /* Lock out cua opens based on pgrp */ -#define S_CALLOUT_NOHUP   0x0400 /* Don't do hangups for cua device */ - -#define S_FLAGS	0x0FFF	/* Possible legal S flags */ -#define S_USR_MASK 0x0430	/* Legal flags that non-privileged -				 * users can set or reset */ - -/* Internal flags used only by kernel/chr_drv/serial.c */ -#define S_INITIALIZED	0x80000000 /* Serial port was initialized */ -#define S_CALLOUT_ACTIVE	0x40000000 /* Call out device is active */ -#define S_NORMAL_ACTIVE	0x20000000 /* Normal device is active */ -#define S_BOOT_AUTOCONF	0x10000000 /* Autoconfigure port on bootup */ -#define S_CLOSING		0x08000000 /* Serial port is closing */ -#define S_CTS_FLOW		0x04000000 /* Do CTS flow control */ -#define S_CHECK_CD		0x02000000 /* i.e., CLOCAL */ - -/* Software state per channel */ - -#ifdef __KERNEL__ - -/* - * I believe this is the optimal setting that reduces the number of interrupts. - * At high speeds the output might become a little "bursted" (use USTCNT_TXHE - * if that bothers you), but in most cases it will not, since we try to  - * transmit characters every time rs_interrupt is called. Thus, quite often - * you'll see that a receive interrupt occures before the transmit one. - *                                  -- Vladimir Gurevich - */ -#define USTCNT_TX_INTR_MASK (USTCNT_TXEE) - -/* - * 68328 and 68EZ328 UARTS are a little bit different. EZ328 has special - * "Old data interrupt" which occures whenever the data stay in the FIFO - * longer than 30 bits time. This allows us to use FIFO without compromising - * latency. '328 does not have this feature and without the real  328-based - * board I would assume that RXRE is the safest setting. - * - * For EZ328 I use RXHE (Half empty) interrupt to reduce the number of - * interrupts. RXFE (receive queue full) causes the system to lose data - * at least at 115200 baud - * - * If your board is busy doing other stuff, you might consider to use - * RXRE (data ready intrrupt) instead. - * - * The other option is to make these INTR masks run-time configurable, so - * that people can dynamically adapt them according to the current usage. - *                                  -- Vladimir Gurevich - */ - -/* (es) */ -#if defined(CONFIG_M68EZ328) || defined(CONFIG_M68VZ328) -#define USTCNT_RX_INTR_MASK (USTCNT_RXHE | USTCNT_ODEN) -#elif defined(CONFIG_M68328) -#define USTCNT_RX_INTR_MASK (USTCNT_RXRE) -#else -#error Please, define the Rx interrupt events for your CPU -#endif -/* (/es) */ - -/* - * This is our internal structure for each serial port's state. - *  - * Many fields are paralleled by the structure used by the serial_struct - * structure. - * - * For definitions of the flags field, see tty.h - */ - -struct m68k_serial { -	char soft_carrier;  /* Use soft carrier on this channel */ -	char break_abort;   /* Is serial console in, so process brk/abrt */ -	char is_cons;       /* Is this our console. */ - -	/* We need to know the current clock divisor -	 * to read the bps rate the chip has currently -	 * loaded. -	 */ -	unsigned char clk_divisor;  /* May be 1, 16, 32, or 64 */ -	int baud; -	int			magic; -	int			baud_base; -	int			port; -	int			irq; -	int			flags; 		/* defined in tty.h */ -	int			type; 		/* UART type */ -	struct tty_struct 	*tty; -	int			read_status_mask; -	int			ignore_status_mask; -	int			timeout; -	int			xmit_fifo_size; -	int			custom_divisor; -	int			x_char;	/* xon/xoff character */ -	int			close_delay; -	unsigned short		closing_wait; -	unsigned short		closing_wait2; -	unsigned long		event; -	unsigned long		last_active; -	int			line; -	int			count;	    /* # of fd on device */ -	int			blocked_open; /* # of blocked opens */ -	unsigned char 		*xmit_buf; -	int			xmit_head; -	int			xmit_tail; -	int			xmit_cnt; -	wait_queue_head_t	open_wait; -	wait_queue_head_t	close_wait; -}; - - -#define SERIAL_MAGIC 0x5301 - -/* - * The size of the serial xmit buffer is 1 page, or 4096 bytes - */ -#define SERIAL_XMIT_SIZE 4096 - -/* - * Events are used to schedule things to happen at timer-interrupt - * time, instead of at rs interrupt time. - */ -#define RS_EVENT_WRITE_WAKEUP	0 - -/*  - * Define the number of ports supported and their irqs. - */ -#define NR_PORTS 1 -#define UART_IRQ_DEFNS {UART_IRQ_NUM} - -#endif /* __KERNEL__ */ -#endif /* !(_MC683XX_SERIAL_H) */ diff --git a/drivers/tty/serial/8250/8250.c b/drivers/tty/serial/8250/8250.c index 5c27f7e6c9f..47d061b9ad4 100644 --- a/drivers/tty/serial/8250/8250.c +++ b/drivers/tty/serial/8250/8250.c @@ -284,7 +284,20 @@ static const struct serial8250_config uart_config[] = {  	},  }; -#if defined(CONFIG_MIPS_ALCHEMY) +/* Uart divisor latch read */ +static int default_serial_dl_read(struct uart_8250_port *up) +{ +	return serial_in(up, UART_DLL) | serial_in(up, UART_DLM) << 8; +} + +/* Uart divisor latch write */ +static void default_serial_dl_write(struct uart_8250_port *up, int value) +{ +	serial_out(up, UART_DLL, value & 0xff); +	serial_out(up, UART_DLM, value >> 8 & 0xff); +} + +#ifdef CONFIG_MIPS_ALCHEMY  /* Au1x00 UART hardware has a weird register layout */  static const u8 au_io_in_map[] = { @@ -305,22 +318,32 @@ static const u8 au_io_out_map[] = {  	[UART_MCR] = 6,  }; -/* sane hardware needs no mapping */ -static inline int map_8250_in_reg(struct uart_port *p, int offset) +static unsigned int au_serial_in(struct uart_port *p, int offset)  { -	if (p->iotype != UPIO_AU) -		return offset; -	return au_io_in_map[offset]; +	offset = au_io_in_map[offset] << p->regshift; +	return __raw_readl(p->membase + offset);  } -static inline int map_8250_out_reg(struct uart_port *p, int offset) +static void au_serial_out(struct uart_port *p, int offset, int value)  { -	if (p->iotype != UPIO_AU) -		return offset; -	return au_io_out_map[offset]; +	offset = au_io_out_map[offset] << p->regshift; +	__raw_writel(value, p->membase + offset);  } -#elif defined(CONFIG_SERIAL_8250_RM9K) +/* Au1x00 haven't got a standard divisor latch */ +static int au_serial_dl_read(struct uart_8250_port *up) +{ +	return __raw_readl(up->port.membase + 0x28); +} + +static void au_serial_dl_write(struct uart_8250_port *up, int value) +{ +	__raw_writel(value, up->port.membase + 0x28); +} + +#endif + +#ifdef CONFIG_SERIAL_8250_RM9K  static const u8  	regmap_in[8] = { @@ -344,87 +367,79 @@ static const u8  		[UART_SCR]	= 0x2c  	}; -static inline int map_8250_in_reg(struct uart_port *p, int offset) +static unsigned int rm9k_serial_in(struct uart_port *p, int offset)  { -	if (p->iotype != UPIO_RM9000) -		return offset; -	return regmap_in[offset]; +	offset = regmap_in[offset] << p->regshift; +	return readl(p->membase + offset);  } -static inline int map_8250_out_reg(struct uart_port *p, int offset) +static void rm9k_serial_out(struct uart_port *p, int offset, int value)  { -	if (p->iotype != UPIO_RM9000) -		return offset; -	return regmap_out[offset]; +	offset = regmap_out[offset] << p->regshift; +	writel(value, p->membase + offset);  } -#else +static int rm9k_serial_dl_read(struct uart_8250_port *up) +{ +	return ((__raw_readl(up->port.membase + 0x10) << 8) | +		(__raw_readl(up->port.membase + 0x08) & 0xff)) & 0xffff; +} -/* sane hardware needs no mapping */ -#define map_8250_in_reg(up, offset) (offset) -#define map_8250_out_reg(up, offset) (offset) +static void rm9k_serial_dl_write(struct uart_8250_port *up, int value) +{ +	__raw_writel(value, up->port.membase + 0x08); +	__raw_writel(value >> 8, up->port.membase + 0x10); +}  #endif  static unsigned int hub6_serial_in(struct uart_port *p, int offset)  { -	offset = map_8250_in_reg(p, offset) << p->regshift; +	offset = offset << p->regshift;  	outb(p->hub6 - 1 + offset, p->iobase);  	return inb(p->iobase + 1);  }  static void hub6_serial_out(struct uart_port *p, int offset, int value)  { -	offset = map_8250_out_reg(p, offset) << p->regshift; +	offset = offset << p->regshift;  	outb(p->hub6 - 1 + offset, p->iobase);  	outb(value, p->iobase + 1);  }  static unsigned int mem_serial_in(struct uart_port *p, int offset)  { -	offset = map_8250_in_reg(p, offset) << p->regshift; +	offset = offset << p->regshift;  	return readb(p->membase + offset);  }  static void mem_serial_out(struct uart_port *p, int offset, int value)  { -	offset = map_8250_out_reg(p, offset) << p->regshift; +	offset = offset << p->regshift;  	writeb(value, p->membase + offset);  }  static void mem32_serial_out(struct uart_port *p, int offset, int value)  { -	offset = map_8250_out_reg(p, offset) << p->regshift; +	offset = offset << p->regshift;  	writel(value, p->membase + offset);  }  static unsigned int mem32_serial_in(struct uart_port *p, int offset)  { -	offset = map_8250_in_reg(p, offset) << p->regshift; +	offset = offset << p->regshift;  	return readl(p->membase + offset);  } -static unsigned int au_serial_in(struct uart_port *p, int offset) -{ -	offset = map_8250_in_reg(p, offset) << p->regshift; -	return __raw_readl(p->membase + offset); -} - -static void au_serial_out(struct uart_port *p, int offset, int value) -{ -	offset = map_8250_out_reg(p, offset) << p->regshift; -	__raw_writel(value, p->membase + offset); -} -  static unsigned int io_serial_in(struct uart_port *p, int offset)  { -	offset = map_8250_in_reg(p, offset) << p->regshift; +	offset = offset << p->regshift;  	return inb(p->iobase + offset);  }  static void io_serial_out(struct uart_port *p, int offset, int value)  { -	offset = map_8250_out_reg(p, offset) << p->regshift; +	offset = offset << p->regshift;  	outb(value, p->iobase + offset);  } @@ -434,6 +449,10 @@ static void set_io_from_upio(struct uart_port *p)  {  	struct uart_8250_port *up =  		container_of(p, struct uart_8250_port, port); + +	up->dl_read = default_serial_dl_read; +	up->dl_write = default_serial_dl_write; +  	switch (p->iotype) {  	case UPIO_HUB6:  		p->serial_in = hub6_serial_in; @@ -445,16 +464,28 @@ static void set_io_from_upio(struct uart_port *p)  		p->serial_out = mem_serial_out;  		break; -	case UPIO_RM9000:  	case UPIO_MEM32:  		p->serial_in = mem32_serial_in;  		p->serial_out = mem32_serial_out;  		break; +#ifdef CONFIG_SERIAL_8250_RM9K +	case UPIO_RM9000: +		p->serial_in = rm9k_serial_in; +		p->serial_out = rm9k_serial_out; +		up->dl_read = rm9k_serial_dl_read; +		up->dl_write = rm9k_serial_dl_write; +		break; +#endif + +#ifdef CONFIG_MIPS_ALCHEMY  	case UPIO_AU:  		p->serial_in = au_serial_in;  		p->serial_out = au_serial_out; +		up->dl_read = au_serial_dl_read; +		up->dl_write = au_serial_dl_write;  		break; +#endif  	default:  		p->serial_in = io_serial_in; @@ -481,59 +512,6 @@ serial_port_out_sync(struct uart_port *p, int offset, int value)  	}  } -/* Uart divisor latch read */ -static inline int _serial_dl_read(struct uart_8250_port *up) -{ -	return serial_in(up, UART_DLL) | serial_in(up, UART_DLM) << 8; -} - -/* Uart divisor latch write */ -static inline void _serial_dl_write(struct uart_8250_port *up, int value) -{ -	serial_out(up, UART_DLL, value & 0xff); -	serial_out(up, UART_DLM, value >> 8 & 0xff); -} - -#if defined(CONFIG_MIPS_ALCHEMY) -/* Au1x00 haven't got a standard divisor latch */ -static int serial_dl_read(struct uart_8250_port *up) -{ -	if (up->port.iotype == UPIO_AU) -		return __raw_readl(up->port.membase + 0x28); -	else -		return _serial_dl_read(up); -} - -static void serial_dl_write(struct uart_8250_port *up, int value) -{ -	if (up->port.iotype == UPIO_AU) -		__raw_writel(value, up->port.membase + 0x28); -	else -		_serial_dl_write(up, value); -} -#elif defined(CONFIG_SERIAL_8250_RM9K) -static int serial_dl_read(struct uart_8250_port *up) -{ -	return	(up->port.iotype == UPIO_RM9000) ? -		(((__raw_readl(up->port.membase + 0x10) << 8) | -		(__raw_readl(up->port.membase + 0x08) & 0xff)) & 0xffff) : -		_serial_dl_read(up); -} - -static void serial_dl_write(struct uart_8250_port *up, int value) -{ -	if (up->port.iotype == UPIO_RM9000) { -		__raw_writel(value, up->port.membase + 0x08); -		__raw_writel(value >> 8, up->port.membase + 0x10); -	} else { -		_serial_dl_write(up, value); -	} -} -#else -#define serial_dl_read(up) _serial_dl_read(up) -#define serial_dl_write(up, value) _serial_dl_write(up, value) -#endif -  /*   * For the 16C950   */ @@ -568,6 +546,16 @@ static void serial8250_clear_fifos(struct uart_8250_port *p)  	}  } +void serial8250_clear_and_reinit_fifos(struct uart_8250_port *p) +{ +	unsigned char fcr; + +	serial8250_clear_fifos(p); +	fcr = uart_config[p->port.type].fcr; +	serial_out(p, UART_FCR, fcr); +} +EXPORT_SYMBOL_GPL(serial8250_clear_and_reinit_fifos); +  /*   * IER sleep support.  UARTs which have EFRs need the "extended   * capability" bit enabled.  Note that on XR16C850s, we need to @@ -1332,27 +1320,6 @@ static void serial8250_enable_ms(struct uart_port *port)  }  /* - * Clear the Tegra rx fifo after a break - * - * FIXME: This needs to become a port specific callback once we have a - * framework for this - */ -static void clear_rx_fifo(struct uart_8250_port *up) -{ -	unsigned int status, tmout = 10000; -	do { -		status = serial_in(up, UART_LSR); -		if (status & (UART_LSR_FIFOE | UART_LSR_BRK_ERROR_BITS)) -			status = serial_in(up, UART_RX); -		else -			break; -		if (--tmout == 0) -			break; -		udelay(1); -	} while (1); -} - -/*   * serial8250_rx_chars: processes according to the passed in LSR   * value, and returns the remaining LSR bits not handled   * by this Rx routine. @@ -1386,20 +1353,10 @@ serial8250_rx_chars(struct uart_8250_port *up, unsigned char lsr)  		up->lsr_saved_flags = 0;  		if (unlikely(lsr & UART_LSR_BRK_ERROR_BITS)) { -			/* -			 * For statistics only -			 */  			if (lsr & UART_LSR_BI) {  				lsr &= ~(UART_LSR_FE | UART_LSR_PE);  				port->icount.brk++;  				/* -				 * If tegra port then clear the rx fifo to -				 * accept another break/character. -				 */ -				if (port->type == PORT_TEGRA) -					clear_rx_fifo(up); - -				/*  				 * We do the SysRQ and SAK checking  				 * here because otherwise the break  				 * may get masked by ignore_status_mask @@ -2280,10 +2237,11 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios,  		quot++;  	if (up->capabilities & UART_CAP_FIFO && port->fifosize > 1) { -		if (baud < 2400) -			fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1; -		else -			fcr = uart_config[port->type].fcr; +		fcr = uart_config[port->type].fcr; +		if (baud < 2400) { +			fcr &= ~UART_FCR_TRIGGER_MASK; +			fcr |= UART_FCR_TRIGGER_1; +		}  	}  	/* @@ -3037,6 +2995,7 @@ static int __devinit serial8250_probe(struct platform_device *dev)  		port.serial_in		= p->serial_in;  		port.serial_out		= p->serial_out;  		port.handle_irq		= p->handle_irq; +		port.handle_break	= p->handle_break;  		port.set_termios	= p->set_termios;  		port.pm			= p->pm;  		port.dev		= &dev->dev; @@ -3153,7 +3112,7 @@ static struct uart_8250_port *serial8250_find_match_or_unused(struct uart_port *  }  /** - *	serial8250_register_port - register a serial port + *	serial8250_register_8250_port - register a serial port   *	@port: serial port template   *   *	Configure the serial port specified by the request. If the @@ -3165,50 +3124,56 @@ static struct uart_8250_port *serial8250_find_match_or_unused(struct uart_port *   *   *	On success the port is ready to use and the line number is returned.   */ -int serial8250_register_port(struct uart_port *port) +int serial8250_register_8250_port(struct uart_8250_port *up)  {  	struct uart_8250_port *uart;  	int ret = -ENOSPC; -	if (port->uartclk == 0) +	if (up->port.uartclk == 0)  		return -EINVAL;  	mutex_lock(&serial_mutex); -	uart = serial8250_find_match_or_unused(port); +	uart = serial8250_find_match_or_unused(&up->port);  	if (uart) {  		uart_remove_one_port(&serial8250_reg, &uart->port); -		uart->port.iobase       = port->iobase; -		uart->port.membase      = port->membase; -		uart->port.irq          = port->irq; -		uart->port.irqflags     = port->irqflags; -		uart->port.uartclk      = port->uartclk; -		uart->port.fifosize     = port->fifosize; -		uart->port.regshift     = port->regshift; -		uart->port.iotype       = port->iotype; -		uart->port.flags        = port->flags | UPF_BOOT_AUTOCONF; -		uart->port.mapbase      = port->mapbase; -		uart->port.private_data = port->private_data; -		if (port->dev) -			uart->port.dev = port->dev; +		uart->port.iobase       = up->port.iobase; +		uart->port.membase      = up->port.membase; +		uart->port.irq          = up->port.irq; +		uart->port.irqflags     = up->port.irqflags; +		uart->port.uartclk      = up->port.uartclk; +		uart->port.fifosize     = up->port.fifosize; +		uart->port.regshift     = up->port.regshift; +		uart->port.iotype       = up->port.iotype; +		uart->port.flags        = up->port.flags | UPF_BOOT_AUTOCONF; +		uart->port.mapbase      = up->port.mapbase; +		uart->port.private_data = up->port.private_data; +		if (up->port.dev) +			uart->port.dev = up->port.dev; -		if (port->flags & UPF_FIXED_TYPE) -			serial8250_init_fixed_type_port(uart, port->type); +		if (up->port.flags & UPF_FIXED_TYPE) +			serial8250_init_fixed_type_port(uart, up->port.type);  		set_io_from_upio(&uart->port);  		/* Possibly override default I/O functions.  */ -		if (port->serial_in) -			uart->port.serial_in = port->serial_in; -		if (port->serial_out) -			uart->port.serial_out = port->serial_out; -		if (port->handle_irq) -			uart->port.handle_irq = port->handle_irq; +		if (up->port.serial_in) +			uart->port.serial_in = up->port.serial_in; +		if (up->port.serial_out) +			uart->port.serial_out = up->port.serial_out; +		if (up->port.handle_irq) +			uart->port.handle_irq = up->port.handle_irq;  		/*  Possibly override set_termios call */ -		if (port->set_termios) -			uart->port.set_termios = port->set_termios; -		if (port->pm) -			uart->port.pm = port->pm; +		if (up->port.set_termios) +			uart->port.set_termios = up->port.set_termios; +		if (up->port.pm) +			uart->port.pm = up->port.pm; +		if (up->port.handle_break) +			uart->port.handle_break = up->port.handle_break; +		if (up->dl_read) +			uart->dl_read = up->dl_read; +		if (up->dl_write) +			uart->dl_write = up->dl_write;  		if (serial8250_isa_config != NULL)  			serial8250_isa_config(0, &uart->port, @@ -3222,6 +3187,29 @@ int serial8250_register_port(struct uart_port *port)  	return ret;  } +EXPORT_SYMBOL(serial8250_register_8250_port); + +/** + *	serial8250_register_port - register a serial port + *	@port: serial port template + * + *	Configure the serial port specified by the request. If the + *	port exists and is in use, it is hung up and unregistered + *	first. + * + *	The port is then probed and if necessary the IRQ is autodetected + *	If this fails an error is returned. + * + *	On success the port is ready to use and the line number is returned. + */ +int serial8250_register_port(struct uart_port *port) +{ +	struct uart_8250_port up; + +	memset(&up, 0, sizeof(up)); +	memcpy(&up.port, port, sizeof(*port)); +	return serial8250_register_8250_port(&up); +}  EXPORT_SYMBOL(serial8250_register_port);  /** diff --git a/drivers/tty/serial/8250/8250.h b/drivers/tty/serial/8250/8250.h index 2868a1da254..f9719d167c8 100644 --- a/drivers/tty/serial/8250/8250.h +++ b/drivers/tty/serial/8250/8250.h @@ -37,6 +37,10 @@ struct uart_8250_port {  	unsigned char		lsr_saved_flags;  #define MSR_SAVE_FLAGS UART_MSR_ANY_DELTA  	unsigned char		msr_saved_flags; + +	/* 8250 specific callbacks */ +	int			(*dl_read)(struct uart_8250_port *); +	void			(*dl_write)(struct uart_8250_port *, int);  };  struct old_serial_port { @@ -96,6 +100,18 @@ static inline void serial_out(struct uart_8250_port *up, int offset, int value)  	up->port.serial_out(&up->port, offset, value);  } +void serial8250_clear_and_reinit_fifos(struct uart_8250_port *p); + +static inline int serial_dl_read(struct uart_8250_port *up) +{ +	return up->dl_read(up); +} + +static inline void serial_dl_write(struct uart_8250_port *up, int value) +{ +	up->dl_write(up, value); +} +  #if defined(__alpha__) && !defined(CONFIG_PCI)  /*   * Digital did something really horribly wrong with the OUT1 and OUT2 diff --git a/drivers/tty/serial/8250/8250_em.c b/drivers/tty/serial/8250/8250_em.c new file mode 100644 index 00000000000..3a0363e7f3a --- /dev/null +++ b/drivers/tty/serial/8250/8250_em.c @@ -0,0 +1,186 @@ +/* + * Renesas Emma Mobile 8250 driver + * + *  Copyright (C) 2012 Magnus Damm + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA + */ + +#include <linux/device.h> +#include <linux/init.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/serial_8250.h> +#include <linux/serial_core.h> +#include <linux/serial_reg.h> +#include <linux/platform_device.h> +#include <linux/clk.h> +#include <linux/slab.h> + +#include "8250.h" + +#define UART_DLL_EM 9 +#define UART_DLM_EM 10 + +struct serial8250_em_priv { +	struct clk *sclk; +	int line; +}; + +static void serial8250_em_serial_out(struct uart_port *p, int offset, int value) +{ +	switch (offset) { +	case UART_TX: /* TX @ 0x00 */ +		writeb(value, p->membase); +		break; +	case UART_FCR: /* FCR @ 0x0c (+1) */ +	case UART_LCR: /* LCR @ 0x10 (+1) */ +	case UART_MCR: /* MCR @ 0x14 (+1) */ +	case UART_SCR: /* SCR @ 0x20 (+1) */ +		writel(value, p->membase + ((offset + 1) << 2)); +		break; +	case UART_IER: /* IER @ 0x04 */ +		value &= 0x0f; /* only 4 valid bits - not Xscale */ +		/* fall-through */ +	case UART_DLL_EM: /* DLL @ 0x24 (+9) */ +	case UART_DLM_EM: /* DLM @ 0x28 (+9) */ +		writel(value, p->membase + (offset << 2)); +	} +} + +static unsigned int serial8250_em_serial_in(struct uart_port *p, int offset) +{ +	switch (offset) { +	case UART_RX: /* RX @ 0x00 */ +		return readb(p->membase); +	case UART_MCR: /* MCR @ 0x14 (+1) */ +	case UART_LSR: /* LSR @ 0x18 (+1) */ +	case UART_MSR: /* MSR @ 0x1c (+1) */ +	case UART_SCR: /* SCR @ 0x20 (+1) */ +		return readl(p->membase + ((offset + 1) << 2)); +	case UART_IER: /* IER @ 0x04 */ +	case UART_IIR: /* IIR @ 0x08 */ +	case UART_DLL_EM: /* DLL @ 0x24 (+9) */ +	case UART_DLM_EM: /* DLM @ 0x28 (+9) */ +		return readl(p->membase + (offset << 2)); +	} +	return 0; +} + +static int serial8250_em_serial_dl_read(struct uart_8250_port *up) +{ +	return serial_in(up, UART_DLL_EM) | serial_in(up, UART_DLM_EM) << 8; +} + +static void serial8250_em_serial_dl_write(struct uart_8250_port *up, int value) +{ +	serial_out(up, UART_DLL_EM, value & 0xff); +	serial_out(up, UART_DLM_EM, value >> 8 & 0xff); +} + +static int __devinit serial8250_em_probe(struct platform_device *pdev) +{ +	struct resource *regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); +	struct resource *irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); +	struct serial8250_em_priv *priv; +	struct uart_8250_port up; +	int ret = -EINVAL; + +	if (!regs || !irq) { +		dev_err(&pdev->dev, "missing registers or irq\n"); +		goto err0; +	} + +	priv = kzalloc(sizeof(*priv), GFP_KERNEL); +	if (!priv) { +		dev_err(&pdev->dev, "unable to allocate private data\n"); +		ret = -ENOMEM; +		goto err0; +	} + +	priv->sclk = clk_get(&pdev->dev, "sclk"); +	if (IS_ERR(priv->sclk)) { +		dev_err(&pdev->dev, "unable to get clock\n"); +		ret = PTR_ERR(priv->sclk); +		goto err1; +	} + +	memset(&up, 0, sizeof(up)); +	up.port.mapbase = regs->start; +	up.port.irq = irq->start; +	up.port.type = PORT_UNKNOWN; +	up.port.flags = UPF_BOOT_AUTOCONF | UPF_FIXED_PORT | UPF_IOREMAP; +	up.port.dev = &pdev->dev; +	up.port.private_data = priv; + +	clk_enable(priv->sclk); +	up.port.uartclk = clk_get_rate(priv->sclk); + +	up.port.iotype = UPIO_MEM32; +	up.port.serial_in = serial8250_em_serial_in; +	up.port.serial_out = serial8250_em_serial_out; +	up.dl_read = serial8250_em_serial_dl_read; +	up.dl_write = serial8250_em_serial_dl_write; + +	ret = serial8250_register_8250_port(&up); +	if (ret < 0) { +		dev_err(&pdev->dev, "unable to register 8250 port\n"); +		goto err2; +	} + +	priv->line = ret; +	platform_set_drvdata(pdev, priv); +	return 0; + + err2: +	clk_disable(priv->sclk); +	clk_put(priv->sclk); + err1: +	kfree(priv); + err0: +	return ret; +} + +static int __devexit serial8250_em_remove(struct platform_device *pdev) +{ +	struct serial8250_em_priv *priv = platform_get_drvdata(pdev); + +	serial8250_unregister_port(priv->line); +	clk_disable(priv->sclk); +	clk_put(priv->sclk); +	kfree(priv); +	return 0; +} + +static const struct of_device_id serial8250_em_dt_ids[] __devinitconst = { +	{ .compatible = "renesas,em-uart", }, +	{}, +}; +MODULE_DEVICE_TABLE(of, serial8250_em_dt_ids); + +static struct platform_driver serial8250_em_platform_driver = { +	.driver = { +		.name		= "serial8250-em", +		.of_match_table = serial8250_em_dt_ids, +		.owner		= THIS_MODULE, +	}, +	.probe			= serial8250_em_probe, +	.remove			= __devexit_p(serial8250_em_remove), +}; + +module_platform_driver(serial8250_em_platform_driver); + +MODULE_AUTHOR("Magnus Damm"); +MODULE_DESCRIPTION("Renesas Emma Mobile 8250 Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c index 858dca865d6..28e7c7cce89 100644 --- a/drivers/tty/serial/8250/8250_pci.c +++ b/drivers/tty/serial/8250/8250_pci.c @@ -17,6 +17,7 @@  #include <linux/slab.h>  #include <linux/delay.h>  #include <linux/tty.h> +#include <linux/serial_reg.h>  #include <linux/serial_core.h>  #include <linux/8250_pci.h>  #include <linux/bitops.h> @@ -1092,11 +1093,49 @@ static int skip_tx_en_setup(struct serial_private *priv,  	return pci_default_setup(priv, board, port, idx);  } +static void kt_handle_break(struct uart_port *p) +{ +	struct uart_8250_port *up = +		container_of(p, struct uart_8250_port, port); +	/* +	 * On receipt of a BI, serial device in Intel ME (Intel +	 * management engine) needs to have its fifos cleared for sane +	 * SOL (Serial Over Lan) output. +	 */ +	serial8250_clear_and_reinit_fifos(up); +} + +static unsigned int kt_serial_in(struct uart_port *p, int offset) +{ +	struct uart_8250_port *up = +		container_of(p, struct uart_8250_port, port); +	unsigned int val; + +	/* +	 * When the Intel ME (management engine) gets reset its serial +	 * port registers could return 0 momentarily.  Functions like +	 * serial8250_console_write, read and save the IER, perform +	 * some operation and then restore it.  In order to avoid +	 * setting IER register inadvertently to 0, if the value read +	 * is 0, double check with ier value in uart_8250_port and use +	 * that instead.  up->ier should be the same value as what is +	 * currently configured. +	 */ +	val = inb(p->iobase + offset); +	if (offset == UART_IER) { +		if (val == 0) +			val = up->ier; +	} +	return val; +} +  static int kt_serial_setup(struct serial_private *priv,  			   const struct pciserial_board *board,  			   struct uart_port *port, int idx)  {  	port->flags |= UPF_BUG_THRE; +	port->serial_in = kt_serial_in; +	port->handle_break = kt_handle_break;  	return skip_tx_en_setup(priv, board, port, idx);  } @@ -1609,54 +1648,72 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {  	{  		.vendor         = PCI_VENDOR_ID_INTEL,  		.device         = 0x8811, +		.subvendor	= PCI_ANY_ID, +		.subdevice	= PCI_ANY_ID,  		.init		= pci_eg20t_init,  		.setup		= pci_default_setup,  	},  	{  		.vendor         = PCI_VENDOR_ID_INTEL,  		.device         = 0x8812, +		.subvendor	= PCI_ANY_ID, +		.subdevice	= PCI_ANY_ID,  		.init		= pci_eg20t_init,  		.setup		= pci_default_setup,  	},  	{  		.vendor         = PCI_VENDOR_ID_INTEL,  		.device         = 0x8813, +		.subvendor	= PCI_ANY_ID, +		.subdevice	= PCI_ANY_ID,  		.init		= pci_eg20t_init,  		.setup		= pci_default_setup,  	},  	{  		.vendor         = PCI_VENDOR_ID_INTEL,  		.device         = 0x8814, +		.subvendor	= PCI_ANY_ID, +		.subdevice	= PCI_ANY_ID,  		.init		= pci_eg20t_init,  		.setup		= pci_default_setup,  	},  	{  		.vendor         = 0x10DB,  		.device         = 0x8027, +		.subvendor	= PCI_ANY_ID, +		.subdevice	= PCI_ANY_ID,  		.init		= pci_eg20t_init,  		.setup		= pci_default_setup,  	},  	{  		.vendor         = 0x10DB,  		.device         = 0x8028, +		.subvendor	= PCI_ANY_ID, +		.subdevice	= PCI_ANY_ID,  		.init		= pci_eg20t_init,  		.setup		= pci_default_setup,  	},  	{  		.vendor         = 0x10DB,  		.device         = 0x8029, +		.subvendor	= PCI_ANY_ID, +		.subdevice	= PCI_ANY_ID,  		.init		= pci_eg20t_init,  		.setup		= pci_default_setup,  	},  	{  		.vendor         = 0x10DB,  		.device         = 0x800C, +		.subvendor	= PCI_ANY_ID, +		.subdevice	= PCI_ANY_ID,  		.init		= pci_eg20t_init,  		.setup		= pci_default_setup,  	},  	{  		.vendor         = 0x10DB,  		.device         = 0x800D, +		.subvendor	= PCI_ANY_ID, +		.subdevice	= PCI_ANY_ID,  		.init		= pci_eg20t_init,  		.setup		= pci_default_setup,  	}, @@ -2775,6 +2832,12 @@ void pciserial_suspend_ports(struct serial_private *priv)  	for (i = 0; i < priv->nr; i++)  		if (priv->line[i] >= 0)  			serial8250_suspend_port(priv->line[i]); + +	/* +	 * Ensure that every init quirk is properly torn down +	 */ +	if (priv->quirk->exit) +		priv->quirk->exit(priv->dev);  }  EXPORT_SYMBOL_GPL(pciserial_suspend_ports); diff --git a/drivers/tty/serial/8250/Kconfig b/drivers/tty/serial/8250/Kconfig index 591f8018e7d..8bc7ecbf6be 100644 --- a/drivers/tty/serial/8250/Kconfig +++ b/drivers/tty/serial/8250/Kconfig @@ -278,3 +278,11 @@ config SERIAL_8250_DW  	help  	  Selecting this option will enable handling of the extra features  	  present in the Synopsys DesignWare APB UART. + +config SERIAL_8250_EM +	tristate "Support for Emma Mobile intergrated serial port" +	depends on SERIAL_8250 && ARM && HAVE_CLK +	help +	  Selecting this option will add support for the integrated serial +	  port hardware found on the Emma Mobile line of processors. +	  If unsure, say N. diff --git a/drivers/tty/serial/8250/Makefile b/drivers/tty/serial/8250/Makefile index 867bba73890..3f35eacdf67 100644 --- a/drivers/tty/serial/8250/Makefile +++ b/drivers/tty/serial/8250/Makefile @@ -18,3 +18,4 @@ obj-$(CONFIG_SERIAL_8250_HUB6)		+= 8250_hub6.o  obj-$(CONFIG_SERIAL_8250_MCA)		+= 8250_mca.o  obj-$(CONFIG_SERIAL_8250_FSL)		+= 8250_fsl.o  obj-$(CONFIG_SERIAL_8250_DW)		+= 8250_dw.o +obj-$(CONFIG_SERIAL_8250_EM)		+= 8250_em.o diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c index 062ef8c2b3c..4ad721fb840 100644 --- a/drivers/tty/serial/amba-pl011.c +++ b/drivers/tty/serial/amba-pl011.c @@ -68,30 +68,6 @@  #define UART_DR_ERROR		(UART011_DR_OE|UART011_DR_BE|UART011_DR_PE|UART011_DR_FE)  #define UART_DUMMY_DR_RX	(1 << 16) - -#define UART_WA_SAVE_NR 14 - -static void pl011_lockup_wa(unsigned long data); -static const u32 uart_wa_reg[UART_WA_SAVE_NR] = { -	ST_UART011_DMAWM, -	ST_UART011_TIMEOUT, -	ST_UART011_LCRH_RX, -	UART011_IBRD, -	UART011_FBRD, -	ST_UART011_LCRH_TX, -	UART011_IFLS, -	ST_UART011_XFCR, -	ST_UART011_XON1, -	ST_UART011_XON2, -	ST_UART011_XOFF1, -	ST_UART011_XOFF2, -	UART011_CR, -	UART011_IMSC -}; - -static u32 uart_wa_regdata[UART_WA_SAVE_NR]; -static DECLARE_TASKLET(pl011_lockup_tlet, pl011_lockup_wa, 0); -  /* There is by now at least one vendor with differing details, so handle it */  struct vendor_data {  	unsigned int		ifls; @@ -101,6 +77,7 @@ struct vendor_data {  	bool			oversampling;  	bool			interrupt_may_hang;   /* vendor-specific */  	bool			dma_threshold; +	bool			cts_event_workaround;  };  static struct vendor_data vendor_arm = { @@ -110,6 +87,7 @@ static struct vendor_data vendor_arm = {  	.lcrh_rx		= UART011_LCRH,  	.oversampling		= false,  	.dma_threshold		= false, +	.cts_event_workaround	= false,  };  static struct vendor_data vendor_st = { @@ -120,6 +98,7 @@ static struct vendor_data vendor_st = {  	.oversampling		= true,  	.interrupt_may_hang	= true,  	.dma_threshold		= true, +	.cts_event_workaround	= true,  };  static struct uart_amba_port *amba_ports[UART_NR]; @@ -1055,69 +1034,6 @@ static inline bool pl011_dma_rx_running(struct uart_amba_port *uap)  #define pl011_dma_flush_buffer	NULL  #endif - -/* - * pl011_lockup_wa - * This workaround aims to break the deadlock situation - * when after long transfer over uart in hardware flow - * control, uart interrupt registers cannot be cleared. - * Hence uart transfer gets blocked. - * - * It is seen that during such deadlock condition ICR - * don't get cleared even on multiple write. This leads - * pass_counter to decrease and finally reach zero. This - * can be taken as trigger point to run this UART_BT_WA. - * - */ -static void pl011_lockup_wa(unsigned long data) -{ -	struct uart_amba_port *uap = amba_ports[0]; -	void __iomem *base = uap->port.membase; -	struct circ_buf *xmit = &uap->port.state->xmit; -	struct tty_struct *tty = uap->port.state->port.tty; -	int buf_empty_retries = 200; -	int loop; - -	/* Stop HCI layer from submitting data for tx */ -	tty->hw_stopped = 1; -	while (!uart_circ_empty(xmit)) { -		if (buf_empty_retries-- == 0) -			break; -		udelay(100); -	} - -	/* Backup registers */ -	for (loop = 0; loop < UART_WA_SAVE_NR; loop++) -		uart_wa_regdata[loop] = readl(base + uart_wa_reg[loop]); - -	/* Disable UART so that FIFO data is flushed out */ -	writew(0x00, uap->port.membase + UART011_CR); - -	/* Soft reset UART module */ -	if (uap->port.dev->platform_data) { -		struct amba_pl011_data *plat; - -		plat = uap->port.dev->platform_data; -		if (plat->reset) -			plat->reset(); -	} - -	/* Restore registers */ -	for (loop = 0; loop < UART_WA_SAVE_NR; loop++) -		writew(uart_wa_regdata[loop] , -				uap->port.membase + uart_wa_reg[loop]); - -	/* Initialise the old status of the modem signals */ -	uap->old_status = readw(uap->port.membase + UART01x_FR) & -		UART01x_FR_MODEM_ANY; - -	if (readl(base + UART011_MIS) & 0x2) -		printk(KERN_EMERG "UART_BT_WA: ***FAILED***\n"); - -	/* Start Tx/Rx */ -	tty->hw_stopped = 0; -} -  static void pl011_stop_tx(struct uart_port *port)  {  	struct uart_amba_port *uap = (struct uart_amba_port *)port; @@ -1246,12 +1162,26 @@ static irqreturn_t pl011_int(int irq, void *dev_id)  	unsigned long flags;  	unsigned int status, pass_counter = AMBA_ISR_PASS_LIMIT;  	int handled = 0; +	unsigned int dummy_read;  	spin_lock_irqsave(&uap->port.lock, flags);  	status = readw(uap->port.membase + UART011_MIS);  	if (status) {  		do { +			if (uap->vendor->cts_event_workaround) { +				/* workaround to make sure that all bits are unlocked.. */ +				writew(0x00, uap->port.membase + UART011_ICR); + +				/* +				 * WA: introduce 26ns(1 uart clk) delay before W1C; +				 * single apb access will incur 2 pclk(133.12Mhz) delay, +				 * so add 2 dummy reads +				 */ +				dummy_read = readw(uap->port.membase + UART011_ICR); +				dummy_read = readw(uap->port.membase + UART011_ICR); +			} +  			writew(status & ~(UART011_TXIS|UART011_RTIS|  					  UART011_RXIS),  			       uap->port.membase + UART011_ICR); @@ -1268,11 +1198,8 @@ static irqreturn_t pl011_int(int irq, void *dev_id)  			if (status & UART011_TXIS)  				pl011_tx_chars(uap); -			if (pass_counter-- == 0) { -				if (uap->interrupt_may_hang) -					tasklet_schedule(&pl011_lockup_tlet); +			if (pass_counter-- == 0)  				break; -			}  			status = readw(uap->port.membase + UART011_MIS);  		} while (status != 0); diff --git a/drivers/tty/serial/bfin_uart.c b/drivers/tty/serial/bfin_uart.c index 5832fdef11e..bd97db23985 100644 --- a/drivers/tty/serial/bfin_uart.c +++ b/drivers/tty/serial/bfin_uart.c @@ -1,7 +1,7 @@  /*   * Blackfin On-Chip Serial Driver   * - * Copyright 2006-2010 Analog Devices Inc. + * Copyright 2006-2011 Analog Devices Inc.   *   * Enter bugs at http://blackfin.uclinux.org/   * @@ -35,10 +35,6 @@  #include <asm/portmux.h>  #include <asm/cacheflush.h>  #include <asm/dma.h> - -#define port_membase(uart)     (((struct bfin_serial_port *)(uart))->port.membase) -#define get_lsr_cache(uart)    (((struct bfin_serial_port *)(uart))->lsr) -#define put_lsr_cache(uart, v) (((struct bfin_serial_port *)(uart))->lsr = (v))  #include <asm/bfin_serial.h>  #ifdef CONFIG_SERIAL_BFIN_MODULE @@ -166,7 +162,7 @@ static void bfin_serial_stop_tx(struct uart_port *port)  	uart->tx_count = 0;  	uart->tx_done = 1;  #else -#ifdef CONFIG_BF54x +#if defined(CONFIG_BF54x) || defined(CONFIG_BF60x)  	/* Clear TFI bit */  	UART_PUT_LSR(uart, TFI);  #endif @@ -337,7 +333,7 @@ static void bfin_serial_tx_chars(struct bfin_serial_port *uart)  	struct circ_buf *xmit = &uart->port.state->xmit;  	if (uart_circ_empty(xmit) || uart_tx_stopped(&uart->port)) { -#ifdef CONFIG_BF54x +#if defined(CONFIG_BF54x) || defined(CONFIG_BF60x)  		/* Clear TFI bit */  		UART_PUT_LSR(uart, TFI);  #endif @@ -536,7 +532,7 @@ static irqreturn_t bfin_serial_dma_tx_int(int irq, void *dev_id)  		 */  		UART_CLEAR_IER(uart, ETBEI);  		uart->port.icount.tx += uart->tx_count; -		if (!uart_circ_empty(xmit)) { +		if (!(xmit->tail == 0 && xmit->head == 0)) {  			xmit->tail = (xmit->tail + uart->tx_count) & (UART_XMIT_SIZE - 1);  			if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) @@ -553,7 +549,7 @@ static irqreturn_t bfin_serial_dma_tx_int(int irq, void *dev_id)  static irqreturn_t bfin_serial_dma_rx_int(int irq, void *dev_id)  {  	struct bfin_serial_port *uart = dev_id; -	unsigned short irqstat; +	unsigned int irqstat;  	int x_pos, pos;  	spin_lock(&uart->rx_lock); @@ -586,7 +582,7 @@ static irqreturn_t bfin_serial_dma_rx_int(int irq, void *dev_id)  static unsigned int bfin_serial_tx_empty(struct uart_port *port)  {  	struct bfin_serial_port *uart = (struct bfin_serial_port *)port; -	unsigned short lsr; +	unsigned int lsr;  	lsr = UART_GET_LSR(uart);  	if (lsr & TEMT) @@ -598,7 +594,7 @@ static unsigned int bfin_serial_tx_empty(struct uart_port *port)  static void bfin_serial_break_ctl(struct uart_port *port, int break_state)  {  	struct bfin_serial_port *uart = (struct bfin_serial_port *)port; -	u16 lcr = UART_GET_LCR(uart); +	u32 lcr = UART_GET_LCR(uart);  	if (break_state)  		lcr |= SB;  	else @@ -745,7 +741,7 @@ static int bfin_serial_startup(struct uart_port *port)  		}  		/* CTS RTS PINs are negative assertive. */ -		UART_PUT_MCR(uart, ACTS); +		UART_PUT_MCR(uart, UART_GET_MCR(uart) | ACTS);  		UART_SET_IER(uart, EDSSI);  	}  #endif @@ -803,7 +799,7 @@ bfin_serial_set_termios(struct uart_port *port, struct ktermios *termios,  	struct bfin_serial_port *uart = (struct bfin_serial_port *)port;  	unsigned long flags;  	unsigned int baud, quot; -	unsigned short val, ier, lcr = 0; +	unsigned int ier, lcr = 0;  	switch (termios->c_cflag & CSIZE) {  	case CS8: @@ -875,26 +871,23 @@ bfin_serial_set_termios(struct uart_port *port, struct ktermios *termios,  	/* Disable UART */  	ier = UART_GET_IER(uart); +	UART_PUT_GCTL(uart, UART_GET_GCTL(uart) & ~UCEN);  	UART_DISABLE_INTS(uart); -	/* Set DLAB in LCR to Access DLL and DLH */ +	/* Set DLAB in LCR to Access CLK */  	UART_SET_DLAB(uart); -	UART_PUT_DLL(uart, quot & 0xFF); -	UART_PUT_DLH(uart, (quot >> 8) & 0xFF); +	UART_PUT_CLK(uart, quot);  	SSYNC();  	/* Clear DLAB in LCR to Access THR RBR IER */  	UART_CLEAR_DLAB(uart); -	UART_PUT_LCR(uart, lcr); +	UART_PUT_LCR(uart, (UART_GET_LCR(uart) & ~LCR_MASK) | lcr);  	/* Enable UART */  	UART_ENABLE_INTS(uart, ier); - -	val = UART_GET_GCTL(uart); -	val |= UCEN; -	UART_PUT_GCTL(uart, val); +	UART_PUT_GCTL(uart, UART_GET_GCTL(uart) | UCEN);  	/* Port speed changed, update the per-port timeout. */  	uart_update_timeout(port, termios->c_cflag, baud); @@ -954,17 +947,17 @@ bfin_serial_verify_port(struct uart_port *port, struct serial_struct *ser)  static void bfin_serial_set_ldisc(struct uart_port *port, int ld)  {  	struct bfin_serial_port *uart = (struct bfin_serial_port *)port; -	unsigned short val; +	unsigned int val;  	switch (ld) {  	case N_IRDA:  		val = UART_GET_GCTL(uart); -		val |= (IREN | RPOLC); +		val |= (UMOD_IRDA | RPOLC);  		UART_PUT_GCTL(uart, val);  		break;  	default:  		val = UART_GET_GCTL(uart); -		val &= ~(IREN | RPOLC); +		val &= ~(UMOD_MASK | RPOLC);  		UART_PUT_GCTL(uart, val);  	}  } @@ -972,13 +965,13 @@ static void bfin_serial_set_ldisc(struct uart_port *port, int ld)  static void bfin_serial_reset_irda(struct uart_port *port)  {  	struct bfin_serial_port *uart = (struct bfin_serial_port *)port; -	unsigned short val; +	unsigned int val;  	val = UART_GET_GCTL(uart); -	val &= ~(IREN | RPOLC); +	val &= ~(UMOD_MASK | RPOLC);  	UART_PUT_GCTL(uart, val);  	SSYNC(); -	val |= (IREN | RPOLC); +	val |= (UMOD_IRDA | RPOLC);  	UART_PUT_GCTL(uart, val);  	SSYNC();  } @@ -1070,12 +1063,12 @@ static void __init  bfin_serial_console_get_options(struct bfin_serial_port *uart, int *baud,  			   int *parity, int *bits)  { -	unsigned short status; +	unsigned int status;  	status = UART_GET_IER(uart) & (ERBFI | ETBEI);  	if (status == (ERBFI | ETBEI)) {  		/* ok, the port was enabled */ -		u16 lcr, dlh, dll; +		u32 lcr, clk;  		lcr = UART_GET_LCR(uart); @@ -1086,30 +1079,17 @@ bfin_serial_console_get_options(struct bfin_serial_port *uart, int *baud,  			else  				*parity = 'o';  		} -		switch (lcr & 0x03) { -		case 0: -			*bits = 5; -			break; -		case 1: -			*bits = 6; -			break; -		case 2: -			*bits = 7; -			break; -		case 3: -			*bits = 8; -			break; -		} -		/* Set DLAB in LCR to Access DLL and DLH */ +		*bits = ((lcr & WLS_MASK) >> WLS_OFFSET) + 5; + +		/* Set DLAB in LCR to Access CLK */  		UART_SET_DLAB(uart); -		dll = UART_GET_DLL(uart); -		dlh = UART_GET_DLH(uart); +		clk = UART_GET_CLK(uart);  		/* Clear DLAB in LCR to Access THR RBR IER */  		UART_CLEAR_DLAB(uart); -		*baud = get_sclk() / (16*(dll | dlh << 8)); +		*baud = get_sclk() / (16*clk);  	}  	pr_debug("%s:baud = %d, parity = %c, bits= %d\n", __func__, *baud, *parity, *bits);  } diff --git a/drivers/tty/serial/crisv10.c b/drivers/tty/serial/crisv10.c index 5b07c0c3a10..7264d4d2671 100644 --- a/drivers/tty/serial/crisv10.c +++ b/drivers/tty/serial/crisv10.c @@ -952,19 +952,6 @@ static const struct control_pins e100_modem_pins[NR_PORTS] =  /* Input */  #define E100_DSR_GET(info) ((*e100_modem_pins[(info)->line].dsr_port) & e100_modem_pins[(info)->line].dsr_mask) - -/* - * tmp_buf is used as a temporary buffer by serial_write.  We need to - * lock it in case the memcpy_fromfs blocks while swapping in a page, - * and some other program tries to do a serial write at the same time. - * Since the lock will only come under contention when the system is - * swapping and available memory is low, it makes sense to share one - * buffer across all the serial ports, since it significantly saves - * memory if large numbers of serial ports are open. - */ -static unsigned char *tmp_buf; -static DEFINE_MUTEX(tmp_buf_mutex); -  /* Calculate the chartime depending on baudrate, numbor of bits etc. */  static void update_char_time(struct e100_serial * info)  { @@ -3150,7 +3137,7 @@ static int rs_raw_write(struct tty_struct *tty,  	/* first some sanity checks */ -	if (!tty || !info->xmit.buf || !tmp_buf) +	if (!tty || !info->xmit.buf)  		return 0;  #ifdef SERIAL_DEBUG_DATA @@ -3989,7 +3976,7 @@ block_til_ready(struct tty_struct *tty, struct file * filp,  	 */  	if (tty_hung_up_p(filp) ||  	    (info->flags & ASYNC_CLOSING)) { -		wait_event_interruptible_tty(info->close_wait, +		wait_event_interruptible_tty(tty, info->close_wait,  			!(info->flags & ASYNC_CLOSING));  #ifdef SERIAL_DO_RESTART  		if (info->flags & ASYNC_HUP_NOTIFY) @@ -4065,9 +4052,9 @@ block_til_ready(struct tty_struct *tty, struct file * filp,  		printk("block_til_ready blocking: ttyS%d, count = %d\n",  		       info->line, info->count);  #endif -		tty_unlock(); +		tty_unlock(tty);  		schedule(); -		tty_lock(); +		tty_lock(tty);  	}  	set_current_state(TASK_RUNNING);  	remove_wait_queue(&info->open_wait, &wait); @@ -4106,7 +4093,6 @@ rs_open(struct tty_struct *tty, struct file * filp)  {  	struct e100_serial	*info;  	int 			retval; -	unsigned long           page;  	int                     allocated_resources = 0;  	info = rs_table + tty->index; @@ -4124,23 +4110,12 @@ rs_open(struct tty_struct *tty, struct file * filp)  	tty->low_latency = !!(info->flags & ASYNC_LOW_LATENCY); -	if (!tmp_buf) { -		page = get_zeroed_page(GFP_KERNEL); -		if (!page) { -			return -ENOMEM; -		} -		if (tmp_buf) -			free_page(page); -		else -			tmp_buf = (unsigned char *) page; -	} -  	/*  	 * If the port is in the middle of closing, bail out now  	 */  	if (tty_hung_up_p(filp) ||  	    (info->flags & ASYNC_CLOSING)) { -		wait_event_interruptible_tty(info->close_wait, +		wait_event_interruptible_tty(tty, info->close_wait,  			!(info->flags & ASYNC_CLOSING));  #ifdef SERIAL_DO_RESTART  		return ((info->flags & ASYNC_HUP_NOTIFY) ? @@ -4487,6 +4462,7 @@ static int __init rs_init(void)  				info->enabled = 0;  			}  		} +		tty_port_init(&info->port);  		info->uses_dma_in = 0;  		info->uses_dma_out = 0;  		info->line = i; diff --git a/drivers/tty/serial/mxs-auart.c b/drivers/tty/serial/mxs-auart.c index 7081600bede..ec56d8397aa 100644 --- a/drivers/tty/serial/mxs-auart.c +++ b/drivers/tty/serial/mxs-auart.c @@ -370,6 +370,8 @@ static void mxs_auart_settermios(struct uart_port *u,  	writel(ctrl, u->membase + AUART_LINECTRL);  	writel(ctrl2, u->membase + AUART_CTRL2); + +	uart_update_timeout(u, termios->c_cflag, baud);  }  static irqreturn_t mxs_auart_irq_handle(int irq, void *context) diff --git a/drivers/tty/serial/of_serial.c b/drivers/tty/serial/of_serial.c index e8c9cee07d0..5410c063726 100644 --- a/drivers/tty/serial/of_serial.c +++ b/drivers/tty/serial/of_serial.c @@ -12,10 +12,13 @@  #include <linux/init.h>  #include <linux/module.h>  #include <linux/slab.h> +#include <linux/delay.h>  #include <linux/serial_core.h>  #include <linux/serial_8250.h> +#include <linux/serial_reg.h>  #include <linux/of_address.h>  #include <linux/of_irq.h> +#include <linux/of_serial.h>  #include <linux/of_platform.h>  #include <linux/nwpserial.h> @@ -24,6 +27,26 @@ struct of_serial_info {  	int line;  }; +#ifdef CONFIG_ARCH_TEGRA +void tegra_serial_handle_break(struct uart_port *p) +{ +	unsigned int status, tmout = 10000; + +	do { +		status = p->serial_in(p, UART_LSR); +		if (status & (UART_LSR_FIFOE | UART_LSR_BRK_ERROR_BITS)) +			status = p->serial_in(p, UART_RX); +		else +			break; +		if (--tmout == 0) +			break; +		udelay(1); +	} while (1); +} +/* FIXME remove this export when tegra finishes conversion to open firmware */ +EXPORT_SYMBOL_GPL(tegra_serial_handle_break); +#endif +  /*   * Fill a struct uart_port for a given device node   */ @@ -84,6 +107,9 @@ static int __devinit of_platform_serial_setup(struct platform_device *ofdev,  		| UPF_FIXED_PORT | UPF_FIXED_TYPE;  	port->dev = &ofdev->dev; +	if (type == PORT_TEGRA) +		port->handle_break = tegra_serial_handle_break; +  	return 0;  } diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c index d00b38eb268..d3cda0cb2df 100644 --- a/drivers/tty/serial/omap-serial.c +++ b/drivers/tty/serial/omap-serial.c @@ -44,6 +44,13 @@  #include <plat/dmtimer.h>  #include <plat/omap-serial.h> +#define UART_BUILD_REVISION(x, y)	(((x) << 8) | (y)) + +#define OMAP_UART_REV_42 0x0402 +#define OMAP_UART_REV_46 0x0406 +#define OMAP_UART_REV_52 0x0502 +#define OMAP_UART_REV_63 0x0603 +  #define DEFAULT_CLK_SPEED 48000000 /* 48Mhz*/  /* SCR register bitmasks */ @@ -53,6 +60,17 @@  #define OMAP_UART_FCR_RX_FIFO_TRIG_SHIFT		6  #define OMAP_UART_FCR_RX_FIFO_TRIG_MASK			(0x3 << 6) +/* MVR register bitmasks */ +#define OMAP_UART_MVR_SCHEME_SHIFT	30 + +#define OMAP_UART_LEGACY_MVR_MAJ_MASK	0xf0 +#define OMAP_UART_LEGACY_MVR_MAJ_SHIFT	4 +#define OMAP_UART_LEGACY_MVR_MIN_MASK	0x0f + +#define OMAP_UART_MVR_MAJ_MASK		0x700 +#define OMAP_UART_MVR_MAJ_SHIFT		8 +#define OMAP_UART_MVR_MIN_MASK		0x3f +  static struct uart_omap_port *ui[OMAP_MAX_HSUART_PORTS];  /* Forward declaration of functions */ @@ -1346,6 +1364,59 @@ static void uart_tx_dma_callback(int lch, u16 ch_status, void *data)  	return;  } +static void omap_serial_fill_features_erratas(struct uart_omap_port *up) +{ +	u32 mvr, scheme; +	u16 revision, major, minor; + +	mvr = serial_in(up, UART_OMAP_MVER); + +	/* Check revision register scheme */ +	scheme = mvr >> OMAP_UART_MVR_SCHEME_SHIFT; + +	switch (scheme) { +	case 0: /* Legacy Scheme: OMAP2/3 */ +		/* MINOR_REV[0:4], MAJOR_REV[4:7] */ +		major = (mvr & OMAP_UART_LEGACY_MVR_MAJ_MASK) >> +					OMAP_UART_LEGACY_MVR_MAJ_SHIFT; +		minor = (mvr & OMAP_UART_LEGACY_MVR_MIN_MASK); +		break; +	case 1: +		/* New Scheme: OMAP4+ */ +		/* MINOR_REV[0:5], MAJOR_REV[8:10] */ +		major = (mvr & OMAP_UART_MVR_MAJ_MASK) >> +					OMAP_UART_MVR_MAJ_SHIFT; +		minor = (mvr & OMAP_UART_MVR_MIN_MASK); +		break; +	default: +		dev_warn(&up->pdev->dev, +			"Unknown %s revision, defaulting to highest\n", +			up->name); +		/* highest possible revision */ +		major = 0xff; +		minor = 0xff; +	} + +	/* normalize revision for the driver */ +	revision = UART_BUILD_REVISION(major, minor); + +	switch (revision) { +	case OMAP_UART_REV_46: +		up->errata |= (UART_ERRATA_i202_MDR1_ACCESS | +				UART_ERRATA_i291_DMA_FORCEIDLE); +		break; +	case OMAP_UART_REV_52: +		up->errata |= (UART_ERRATA_i202_MDR1_ACCESS | +				UART_ERRATA_i291_DMA_FORCEIDLE); +		break; +	case OMAP_UART_REV_63: +		up->errata |= UART_ERRATA_i202_MDR1_ACCESS; +		break; +	default: +		break; +	} +} +  static struct omap_uart_port_info *of_get_uart_port_info(struct device *dev)  {  	struct omap_uart_port_info *omap_up_info; @@ -1439,7 +1510,6 @@ static int serial_omap_probe(struct platform_device *pdev)  						"%d\n", DEFAULT_CLK_SPEED);  	}  	up->uart_dma.uart_base = mem->start; -	up->errata = omap_up_info->errata;  	if (omap_up_info->dma_enabled) {  		up->uart_dma.uart_dma_tx = dma_tx->start; @@ -1469,6 +1539,8 @@ static int serial_omap_probe(struct platform_device *pdev)  	pm_runtime_enable(&pdev->dev);  	pm_runtime_get_sync(&pdev->dev); +	omap_serial_fill_features_erratas(up); +  	ui[up->port.line] = up;  	serial_omap_add_console_port(up); diff --git a/drivers/tty/serial/pch_uart.c b/drivers/tty/serial/pch_uart.c index c2816f49480..4fdec6a6b75 100644 --- a/drivers/tty/serial/pch_uart.c +++ b/drivers/tty/serial/pch_uart.c @@ -39,6 +39,7 @@ enum {  	PCH_UART_HANDLED_RX_ERR_INT_SHIFT,  	PCH_UART_HANDLED_RX_TRG_INT_SHIFT,  	PCH_UART_HANDLED_MS_INT_SHIFT, +	PCH_UART_HANDLED_LS_INT_SHIFT,  };  enum { @@ -63,6 +64,8 @@ enum {  					PCH_UART_HANDLED_RX_TRG_INT_SHIFT)<<1))  #define PCH_UART_HANDLED_MS_INT	(1<<((PCH_UART_HANDLED_MS_INT_SHIFT)<<1)) +#define PCH_UART_HANDLED_LS_INT	(1<<((PCH_UART_HANDLED_LS_INT_SHIFT)<<1)) +  #define PCH_UART_RBR		0x00  #define PCH_UART_THR		0x00 @@ -229,7 +232,6 @@ struct eg20t_port {  	int start_tx;  	int start_rx;  	int tx_empty; -	int int_dis_flag;  	int trigger;  	int trigger_level;  	struct pch_uart_buffer rxbuf; @@ -237,7 +239,6 @@ struct eg20t_port {  	unsigned int fcr;  	unsigned int mcr;  	unsigned int use_dma; -	unsigned int use_dma_flag;  	struct dma_async_tx_descriptor	*desc_tx;  	struct dma_async_tx_descriptor	*desc_rx;  	struct pch_dma_slave		param_tx; @@ -560,14 +561,10 @@ static int pch_uart_hal_read(struct eg20t_port *priv, unsigned char *buf,  	return i;  } -static unsigned int pch_uart_hal_get_iid(struct eg20t_port *priv) +static unsigned char pch_uart_hal_get_iid(struct eg20t_port *priv)  { -	unsigned int iir; -	int ret; - -	iir = ioread8(priv->membase + UART_IIR); -	ret = (iir & (PCH_UART_IIR_IID | PCH_UART_IIR_TOI | PCH_UART_IIR_IP)); -	return ret; +	return ioread8(priv->membase + UART_IIR) &\ +		      (PCH_UART_IIR_IID | PCH_UART_IIR_TOI | PCH_UART_IIR_IP);  }  static u8 pch_uart_hal_get_line_status(struct eg20t_port *priv) @@ -666,10 +663,13 @@ static void pch_free_dma(struct uart_port *port)  		dma_release_channel(priv->chan_rx);  		priv->chan_rx = NULL;  	} -	if (sg_dma_address(&priv->sg_rx)) -		dma_free_coherent(port->dev, port->fifosize, -				  sg_virt(&priv->sg_rx), -				  sg_dma_address(&priv->sg_rx)); + +	if (priv->rx_buf_dma) { +		dma_free_coherent(port->dev, port->fifosize, priv->rx_buf_virt, +				  priv->rx_buf_dma); +		priv->rx_buf_virt = NULL; +		priv->rx_buf_dma = 0; +	}  	return;  } @@ -1053,12 +1053,17 @@ static irqreturn_t pch_uart_interrupt(int irq, void *dev_id)  	unsigned int handled;  	u8 lsr;  	int ret = 0; -	unsigned int iid; +	unsigned char iid;  	unsigned long flags; +	int next = 1; +	u8 msr;  	spin_lock_irqsave(&priv->port.lock, flags);  	handled = 0; -	while ((iid = pch_uart_hal_get_iid(priv)) > 1) { +	while (next) { +		iid = pch_uart_hal_get_iid(priv); +		if (iid & PCH_UART_IIR_IP) /* No Interrupt */ +			break;  		switch (iid) {  		case PCH_UART_IID_RLS:	/* Receiver Line Status */  			lsr = pch_uart_hal_get_line_status(priv); @@ -1066,6 +1071,8 @@ static irqreturn_t pch_uart_interrupt(int irq, void *dev_id)  						UART_LSR_PE | UART_LSR_OE)) {  				pch_uart_err_ir(priv, lsr);  				ret = PCH_UART_HANDLED_RX_ERR_INT; +			} else { +				ret = PCH_UART_HANDLED_LS_INT;  			}  			break;  		case PCH_UART_IID_RDR:	/* Received Data Ready */ @@ -1092,20 +1099,22 @@ static irqreturn_t pch_uart_interrupt(int irq, void *dev_id)  				ret = handle_tx(priv);  			break;  		case PCH_UART_IID_MS:	/* Modem Status */ -			ret = PCH_UART_HANDLED_MS_INT; +			msr = pch_uart_hal_get_modem(priv); +			next = 0; /* MS ir prioirty is the lowest. So, MS ir +				     means final interrupt */ +			if ((msr & UART_MSR_ANY_DELTA) == 0) +				break; +			ret |= PCH_UART_HANDLED_MS_INT;  			break;  		default:	/* Never junp to this label */ -			dev_err(priv->port.dev, "%s:iid=%d (%lu)\n", __func__, +			dev_err(priv->port.dev, "%s:iid=%02x (%lu)\n", __func__,  				iid, jiffies);  			ret = -1; +			next = 0;  			break;  		}  		handled |= (unsigned int)ret;  	} -	if (handled == 0 && iid <= 1) { -		if (priv->int_dis_flag) -			priv->int_dis_flag = 0; -	}  	spin_unlock_irqrestore(&priv->port.lock, flags);  	return IRQ_RETVAL(handled); @@ -1200,7 +1209,6 @@ static void pch_uart_stop_rx(struct uart_port *port)  	priv = container_of(port, struct eg20t_port, port);  	priv->start_rx = 0;  	pch_uart_hal_disable_interrupt(priv, PCH_UART_HAL_RX_INT); -	priv->int_dis_flag = 1;  }  /* Enable the modem status interrupts. */ @@ -1447,7 +1455,6 @@ static int pch_uart_verify_port(struct uart_port *port,  			__func__);  		return -EOPNOTSUPP;  #endif -		priv->use_dma_flag = 1;  		dev_info(priv->port.dev, "PCH UART : Use DMA Mode\n");  		if (!priv->use_dma)  			pch_request_dma(port); diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index 9c4c05b2825..246b823c1b2 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -2282,6 +2282,7 @@ void uart_unregister_driver(struct uart_driver *drv)  	tty_unregister_driver(p);  	put_tty_driver(p);  	kfree(drv->state); +	drv->state = NULL;  	drv->tty_driver = NULL;  } diff --git a/drivers/tty/synclink.c b/drivers/tty/synclink.c index 593d40ad0a6..5ed0daae656 100644 --- a/drivers/tty/synclink.c +++ b/drivers/tty/synclink.c @@ -3338,9 +3338,9 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,  			printk("%s(%d):block_til_ready blocking on %s count=%d\n",  				 __FILE__,__LINE__, tty->driver->name, port->count ); -		tty_unlock(); +		tty_unlock(tty);  		schedule(); -		tty_lock(); +		tty_lock(tty);  	}  	set_current_state(TASK_RUNNING); diff --git a/drivers/tty/synclink_gt.c b/drivers/tty/synclink_gt.c index aa1debf97cc..45b43f11ca3 100644 --- a/drivers/tty/synclink_gt.c +++ b/drivers/tty/synclink_gt.c @@ -3336,9 +3336,9 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp,  		}  		DBGINFO(("%s block_til_ready wait\n", tty->driver->name)); -		tty_unlock(); +		tty_unlock(tty);  		schedule(); -		tty_lock(); +		tty_lock(tty);  	}  	set_current_state(TASK_RUNNING); diff --git a/drivers/tty/synclinkmp.c b/drivers/tty/synclinkmp.c index a3dddc12d2f..4a1e4f07765 100644 --- a/drivers/tty/synclinkmp.c +++ b/drivers/tty/synclinkmp.c @@ -3357,9 +3357,9 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp,  			printk("%s(%d):%s block_til_ready() count=%d\n",  				 __FILE__,__LINE__, tty->driver->name, port->count ); -		tty_unlock(); +		tty_unlock(tty);  		schedule(); -		tty_lock(); +		tty_lock(tty);  	}  	set_current_state(TASK_RUNNING); diff --git a/drivers/tty/tty_buffer.c b/drivers/tty/tty_buffer.c index 6c9b7cd6778..91e326ffe7d 100644 --- a/drivers/tty/tty_buffer.c +++ b/drivers/tty/tty_buffer.c @@ -185,25 +185,19 @@ static struct tty_buffer *tty_buffer_find(struct tty_struct *tty, size_t size)  	/* Should possibly check if this fails for the largest buffer we  	   have queued and recycle that ? */  } -  /** - *	tty_buffer_request_room		-	grow tty buffer if needed + *	__tty_buffer_request_room		-	grow tty buffer if needed   *	@tty: tty structure   *	@size: size desired   *   *	Make at least size bytes of linear space available for the tty   *	buffer. If we fail return the size we managed to find. - * - *	Locking: Takes tty->buf.lock + *      Locking: Caller must hold tty->buf.lock   */ -int tty_buffer_request_room(struct tty_struct *tty, size_t size) +static int __tty_buffer_request_room(struct tty_struct *tty, size_t size)  {  	struct tty_buffer *b, *n;  	int left; -	unsigned long flags; - -	spin_lock_irqsave(&tty->buf.lock, flags); -  	/* OPTIMISATION: We could keep a per tty "zero" sized buffer to  	   remove this conditional if its worth it. This would be invisible  	   to the callers */ @@ -225,9 +219,30 @@ int tty_buffer_request_room(struct tty_struct *tty, size_t size)  			size = left;  	} -	spin_unlock_irqrestore(&tty->buf.lock, flags);  	return size;  } + + +/** + *	tty_buffer_request_room		-	grow tty buffer if needed + *	@tty: tty structure + *	@size: size desired + * + *	Make at least size bytes of linear space available for the tty + *	buffer. If we fail return the size we managed to find. + * + *	Locking: Takes tty->buf.lock + */ +int tty_buffer_request_room(struct tty_struct *tty, size_t size) +{ +	unsigned long flags; +	int length; + +	spin_lock_irqsave(&tty->buf.lock, flags); +	length = __tty_buffer_request_room(tty, size); +	spin_unlock_irqrestore(&tty->buf.lock, flags); +	return length; +}  EXPORT_SYMBOL_GPL(tty_buffer_request_room);  /** @@ -249,14 +264,22 @@ int tty_insert_flip_string_fixed_flag(struct tty_struct *tty,  	int copied = 0;  	do {  		int goal = min_t(size_t, size - copied, TTY_BUFFER_PAGE); -		int space = tty_buffer_request_room(tty, goal); -		struct tty_buffer *tb = tty->buf.tail; +		int space; +		unsigned long flags; +		struct tty_buffer *tb; + +		spin_lock_irqsave(&tty->buf.lock, flags); +		space = __tty_buffer_request_room(tty, goal); +		tb = tty->buf.tail;  		/* If there is no space then tb may be NULL */ -		if (unlikely(space == 0)) +		if (unlikely(space == 0)) { +			spin_unlock_irqrestore(&tty->buf.lock, flags);  			break; +		}  		memcpy(tb->char_buf_ptr + tb->used, chars, space);  		memset(tb->flag_buf_ptr + tb->used, flag, space);  		tb->used += space; +		spin_unlock_irqrestore(&tty->buf.lock, flags);  		copied += space;  		chars += space;  		/* There is a small chance that we need to split the data over @@ -286,14 +309,22 @@ int tty_insert_flip_string_flags(struct tty_struct *tty,  	int copied = 0;  	do {  		int goal = min_t(size_t, size - copied, TTY_BUFFER_PAGE); -		int space = tty_buffer_request_room(tty, goal); -		struct tty_buffer *tb = tty->buf.tail; +		int space; +		unsigned long __flags; +		struct tty_buffer *tb; + +		spin_lock_irqsave(&tty->buf.lock, __flags); +		space = __tty_buffer_request_room(tty, goal); +		tb = tty->buf.tail;  		/* If there is no space then tb may be NULL */ -		if (unlikely(space == 0)) +		if (unlikely(space == 0)) { +			spin_unlock_irqrestore(&tty->buf.lock, __flags);  			break; +		}  		memcpy(tb->char_buf_ptr + tb->used, chars, space);  		memcpy(tb->flag_buf_ptr + tb->used, flags, space);  		tb->used += space; +		spin_unlock_irqrestore(&tty->buf.lock, __flags);  		copied += space;  		chars += space;  		flags += space; @@ -344,13 +375,20 @@ EXPORT_SYMBOL(tty_schedule_flip);  int tty_prepare_flip_string(struct tty_struct *tty, unsigned char **chars,  								size_t size)  { -	int space = tty_buffer_request_room(tty, size); +	int space; +	unsigned long flags; +	struct tty_buffer *tb; + +	spin_lock_irqsave(&tty->buf.lock, flags); +	space = __tty_buffer_request_room(tty, size); + +	tb = tty->buf.tail;  	if (likely(space)) { -		struct tty_buffer *tb = tty->buf.tail;  		*chars = tb->char_buf_ptr + tb->used;  		memset(tb->flag_buf_ptr + tb->used, TTY_NORMAL, space);  		tb->used += space;  	} +	spin_unlock_irqrestore(&tty->buf.lock, flags);  	return space;  }  EXPORT_SYMBOL_GPL(tty_prepare_flip_string); @@ -374,13 +412,20 @@ EXPORT_SYMBOL_GPL(tty_prepare_flip_string);  int tty_prepare_flip_string_flags(struct tty_struct *tty,  			unsigned char **chars, char **flags, size_t size)  { -	int space = tty_buffer_request_room(tty, size); +	int space; +	unsigned long __flags; +	struct tty_buffer *tb; + +	spin_lock_irqsave(&tty->buf.lock, __flags); +	space = __tty_buffer_request_room(tty, size); + +	tb = tty->buf.tail;  	if (likely(space)) { -		struct tty_buffer *tb = tty->buf.tail;  		*chars = tb->char_buf_ptr + tb->used;  		*flags = tb->flag_buf_ptr + tb->used;  		tb->used += space;  	} +	spin_unlock_irqrestore(&tty->buf.lock, __flags);  	return space;  }  EXPORT_SYMBOL_GPL(tty_prepare_flip_string_flags); diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index d939bd705c7..9e930c009bf 100644 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c @@ -185,6 +185,7 @@ void free_tty_struct(struct tty_struct *tty)  		put_device(tty->dev);  	kfree(tty->write_buf);  	tty_buffer_free_all(tty); +	tty->magic = 0xDEADDEAD;  	kfree(tty);  } @@ -573,7 +574,7 @@ void __tty_hangup(struct tty_struct *tty)  	}  	spin_unlock(&redirect_lock); -	tty_lock(); +	tty_lock(tty);  	/* some functions below drop BTM, so we need this bit */  	set_bit(TTY_HUPPING, &tty->flags); @@ -666,7 +667,7 @@ void __tty_hangup(struct tty_struct *tty)  	clear_bit(TTY_HUPPING, &tty->flags);  	tty_ldisc_enable(tty); -	tty_unlock(); +	tty_unlock(tty);  	if (f)  		fput(f); @@ -855,10 +856,11 @@ void disassociate_ctty(int on_exit)   */  void no_tty(void)  { +	/* FIXME: Review locking here. The tty_lock never covered any race +	   between a new association and proc_clear_tty but possible we need +	   to protect against this anyway */  	struct task_struct *tsk = current; -	tty_lock();  	disassociate_ctty(0); -	tty_unlock();  	proc_clear_tty(tsk);  } @@ -1102,12 +1104,12 @@ void tty_write_message(struct tty_struct *tty, char *msg)  {  	if (tty) {  		mutex_lock(&tty->atomic_write_lock); -		tty_lock(); +		tty_lock(tty);  		if (tty->ops->write && !test_bit(TTY_CLOSING, &tty->flags)) { -			tty_unlock(); +			tty_unlock(tty);  			tty->ops->write(tty, msg, strlen(msg));  		} else -			tty_unlock(); +			tty_unlock(tty);  		tty_write_unlock(tty);  	}  	return; @@ -1402,6 +1404,7 @@ struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx)  	}  	initialize_tty_struct(tty, driver, idx); +	tty_lock(tty);  	retval = tty_driver_install_tty(driver, tty);  	if (retval < 0)  		goto err_deinit_tty; @@ -1414,9 +1417,11 @@ struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx)  	retval = tty_ldisc_setup(tty, tty->link);  	if (retval)  		goto err_release_tty; +	/* Return the tty locked so that it cannot vanish under the caller */  	return tty;  err_deinit_tty: +	tty_unlock(tty);  	deinitialize_tty_struct(tty);  	free_tty_struct(tty);  err_module_put: @@ -1425,6 +1430,7 @@ err_module_put:  	/* call the tty release_tty routine to clean out this slot */  err_release_tty: +	tty_unlock(tty);  	printk_ratelimited(KERN_INFO "tty_init_dev: ldisc open failed, "  				 "clearing slot %d\n", idx);  	release_tty(tty, idx); @@ -1627,7 +1633,7 @@ int tty_release(struct inode *inode, struct file *filp)  	if (tty_paranoia_check(tty, inode, __func__))  		return 0; -	tty_lock(); +	tty_lock(tty);  	check_tty_count(tty, __func__);  	__tty_fasync(-1, filp, 0); @@ -1636,10 +1642,11 @@ int tty_release(struct inode *inode, struct file *filp)  	pty_master = (tty->driver->type == TTY_DRIVER_TYPE_PTY &&  		      tty->driver->subtype == PTY_TYPE_MASTER);  	devpts = (tty->driver->flags & TTY_DRIVER_DEVPTS_MEM) != 0; +	/* Review: parallel close */  	o_tty = tty->link;  	if (tty_release_checks(tty, o_tty, idx)) { -		tty_unlock(); +		tty_unlock(tty);  		return 0;  	} @@ -1651,7 +1658,7 @@ int tty_release(struct inode *inode, struct file *filp)  	if (tty->ops->close)  		tty->ops->close(tty, filp); -	tty_unlock(); +	tty_unlock(tty);  	/*  	 * 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 @@ -1674,7 +1681,7 @@ int tty_release(struct inode *inode, struct file *filp)  		   opens on /dev/tty */  		mutex_lock(&tty_mutex); -		tty_lock(); +		tty_lock_pair(tty, o_tty);  		tty_closing = tty->count <= 1;  		o_tty_closing = o_tty &&  			(o_tty->count <= (pty_master ? 1 : 0)); @@ -1705,7 +1712,7 @@ int tty_release(struct inode *inode, struct file *filp)  		printk(KERN_WARNING "%s: %s: read/write wait queue active!\n",  				__func__, tty_name(tty, buf)); -		tty_unlock(); +		tty_unlock_pair(tty, o_tty);  		mutex_unlock(&tty_mutex);  		schedule();  	} @@ -1768,7 +1775,7 @@ int tty_release(struct inode *inode, struct file *filp)  	/* check whether both sides are closing ... */  	if (!tty_closing || (o_tty && !o_tty_closing)) { -		tty_unlock(); +		tty_unlock_pair(tty, o_tty);  		return 0;  	} @@ -1781,14 +1788,16 @@ int tty_release(struct inode *inode, struct file *filp)  	tty_ldisc_release(tty, o_tty);  	/*  	 * The release_tty function takes care of the details of clearing -	 * the slots and preserving the termios structure. +	 * the slots and preserving the termios structure. The tty_unlock_pair +	 * should be safe as we keep a kref while the tty is locked (so the +	 * unlock never unlocks a freed tty).  	 */  	release_tty(tty, idx); +	tty_unlock_pair(tty, o_tty);  	/* Make this pty number available for reallocation */  	if (devpts)  		devpts_kill_index(inode, idx); -	tty_unlock();  	return 0;  } @@ -1800,6 +1809,9 @@ int tty_release(struct inode *inode, struct file *filp)   *   *	We cannot return driver and index like for the other nodes because   *	devpts will not work then. It expects inodes to be from devpts FS. + * + *	We need to move to returning a refcounted object from all the lookup + *	paths including this one.   */  static struct tty_struct *tty_open_current_tty(dev_t device, struct file *filp)  { @@ -1816,6 +1828,7 @@ static struct tty_struct *tty_open_current_tty(dev_t device, struct file *filp)  	/* noctty = 1; */  	tty_kref_put(tty);  	/* FIXME: we put a reference and return a TTY! */ +	/* This is only safe because the caller holds tty_mutex */  	return tty;  } @@ -1888,6 +1901,9 @@ static struct tty_driver *tty_lookup_driver(dev_t device, struct file *filp,   *	Locking: tty_mutex protects tty, tty_lookup_driver and tty_init_dev.   *		 tty->count should protect the rest.   *		 ->siglock protects ->signal/->sighand + * + *	Note: the tty_unlock/lock cases without a ref are only safe due to + *	tty_mutex   */  static int tty_open(struct inode *inode, struct file *filp) @@ -1911,8 +1927,7 @@ retry_open:  	retval = 0;  	mutex_lock(&tty_mutex); -	tty_lock(); - +	/* This is protected by the tty_mutex */  	tty = tty_open_current_tty(device, filp);  	if (IS_ERR(tty)) {  		retval = PTR_ERR(tty); @@ -1933,17 +1948,19 @@ retry_open:  	}  	if (tty) { +		tty_lock(tty);  		retval = tty_reopen(tty); -		if (retval) +		if (retval < 0) { +			tty_unlock(tty);  			tty = ERR_PTR(retval); -	} else +		} +	} else	/* Returns with the tty_lock held for now */  		tty = tty_init_dev(driver, index);  	mutex_unlock(&tty_mutex);  	if (driver)  		tty_driver_kref_put(driver);  	if (IS_ERR(tty)) { -		tty_unlock();  		retval = PTR_ERR(tty);  		goto err_file;  	} @@ -1972,7 +1989,7 @@ retry_open:  		printk(KERN_DEBUG "%s: error %d in opening %s...\n", __func__,  				retval, tty->name);  #endif -		tty_unlock(); /* need to call tty_release without BTM */ +		tty_unlock(tty); /* need to call tty_release without BTM */  		tty_release(inode, filp);  		if (retval != -ERESTARTSYS)  			return retval; @@ -1984,17 +2001,15 @@ retry_open:  		/*  		 * Need to reset f_op in case a hangup happened.  		 */ -		tty_lock();  		if (filp->f_op == &hung_up_tty_fops)  			filp->f_op = &tty_fops; -		tty_unlock();  		goto retry_open;  	} -	tty_unlock(); +	tty_unlock(tty);  	mutex_lock(&tty_mutex); -	tty_lock(); +	tty_lock(tty);  	spin_lock_irq(¤t->sighand->siglock);  	if (!noctty &&  	    current->signal->leader && @@ -2002,11 +2017,10 @@ retry_open:  	    tty->session == NULL)  		__proc_set_tty(current, tty);  	spin_unlock_irq(¤t->sighand->siglock); -	tty_unlock(); +	tty_unlock(tty);  	mutex_unlock(&tty_mutex);  	return 0;  err_unlock: -	tty_unlock();  	mutex_unlock(&tty_mutex);  	/* after locks to avoid deadlock */  	if (!IS_ERR_OR_NULL(driver)) @@ -2089,10 +2103,13 @@ out:  static int tty_fasync(int fd, struct file *filp, int on)  { +	struct tty_struct *tty = file_tty(filp);  	int retval; -	tty_lock(); + +	tty_lock(tty);  	retval = __tty_fasync(fd, filp, on); -	tty_unlock(); +	tty_unlock(tty); +  	return retval;  } @@ -2929,6 +2946,7 @@ void initialize_tty_struct(struct tty_struct *tty,  	tty->pgrp = NULL;  	tty->overrun_time = jiffies;  	tty_buffer_init(tty); +	mutex_init(&tty->legacy_mutex);  	mutex_init(&tty->termios_mutex);  	mutex_init(&tty->ldisc_mutex);  	init_waitqueue_head(&tty->write_wait); diff --git a/drivers/tty/tty_ldisc.c b/drivers/tty/tty_ldisc.c index 24b95db75d8..173a9000a6c 100644 --- a/drivers/tty/tty_ldisc.c +++ b/drivers/tty/tty_ldisc.c @@ -28,7 +28,6 @@  static DEFINE_SPINLOCK(tty_ldisc_lock);  static DECLARE_WAIT_QUEUE_HEAD(tty_ldisc_wait); -static DECLARE_WAIT_QUEUE_HEAD(tty_ldisc_idle);  /* Line disc dispatch table */  static struct tty_ldisc_ops *tty_ldiscs[NR_LDISCS]; @@ -65,7 +64,7 @@ static void put_ldisc(struct tty_ldisc *ld)  		return;  	}  	local_irq_restore(flags); -	wake_up(&tty_ldisc_idle); +	wake_up(&ld->wq_idle);  }  /** @@ -200,6 +199,8 @@ static struct tty_ldisc *tty_ldisc_get(int disc)  	ld->ops = ldops;  	atomic_set(&ld->users, 1); +	init_waitqueue_head(&ld->wq_idle); +  	return ld;  } @@ -538,7 +539,7 @@ static void tty_ldisc_flush_works(struct tty_struct *tty)  static int tty_ldisc_wait_idle(struct tty_struct *tty, long timeout)  {  	long ret; -	ret = wait_event_timeout(tty_ldisc_idle, +	ret = wait_event_timeout(tty->ldisc->wq_idle,  			atomic_read(&tty->ldisc->users) == 1, timeout);  	return ret > 0 ? 0 : -EBUSY;  } @@ -567,7 +568,7 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)  	if (IS_ERR(new_ldisc))  		return PTR_ERR(new_ldisc); -	tty_lock(); +	tty_lock(tty);  	/*  	 *	We need to look at the tty locking here for pty/tty pairs  	 *	when both sides try to change in parallel. @@ -581,12 +582,12 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)  	 */  	if (tty->ldisc->ops->num == ldisc) { -		tty_unlock(); +		tty_unlock(tty);  		tty_ldisc_put(new_ldisc);  		return 0;  	} -	tty_unlock(); +	tty_unlock(tty);  	/*  	 *	Problem: What do we do if this blocks ?  	 *	We could deadlock here @@ -594,7 +595,7 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)  	tty_wait_until_sent(tty, 0); -	tty_lock(); +	tty_lock(tty);  	mutex_lock(&tty->ldisc_mutex);  	/* @@ -604,10 +605,10 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)  	while (test_bit(TTY_LDISC_CHANGING, &tty->flags)) {  		mutex_unlock(&tty->ldisc_mutex); -		tty_unlock(); +		tty_unlock(tty);  		wait_event(tty_ldisc_wait,  			test_bit(TTY_LDISC_CHANGING, &tty->flags) == 0); -		tty_lock(); +		tty_lock(tty);  		mutex_lock(&tty->ldisc_mutex);  	} @@ -622,7 +623,7 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)  	o_ldisc = tty->ldisc; -	tty_unlock(); +	tty_unlock(tty);  	/*  	 *	Make sure we don't change while someone holds a  	 *	reference to the line discipline. The TTY_LDISC bit @@ -649,7 +650,7 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)  	retval = tty_ldisc_wait_idle(tty, 5 * HZ); -	tty_lock(); +	tty_lock(tty);  	mutex_lock(&tty->ldisc_mutex);  	/* handle wait idle failure locked */ @@ -664,7 +665,7 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)  		clear_bit(TTY_LDISC_CHANGING, &tty->flags);  		mutex_unlock(&tty->ldisc_mutex);  		tty_ldisc_put(new_ldisc); -		tty_unlock(); +		tty_unlock(tty);  		return -EIO;  	} @@ -707,7 +708,7 @@ enable:  	if (o_work)  		schedule_work(&o_tty->buf.work);  	mutex_unlock(&tty->ldisc_mutex); -	tty_unlock(); +	tty_unlock(tty);  	return retval;  } @@ -815,11 +816,11 @@ void tty_ldisc_hangup(struct tty_struct *tty)  	 * need to wait for another function taking the BTM  	 */  	clear_bit(TTY_LDISC, &tty->flags); -	tty_unlock(); +	tty_unlock(tty);  	cancel_work_sync(&tty->buf.work);  	mutex_unlock(&tty->ldisc_mutex);  retry: -	tty_lock(); +	tty_lock(tty);  	mutex_lock(&tty->ldisc_mutex);  	/* At this point we have a closed ldisc and we want to @@ -830,7 +831,7 @@ retry:  		if (atomic_read(&tty->ldisc->users) != 1) {  			char cur_n[TASK_COMM_LEN], tty_n[64];  			long timeout = 3 * HZ; -			tty_unlock(); +			tty_unlock(tty);  			while (tty_ldisc_wait_idle(tty, timeout) == -EBUSY) {  				timeout = MAX_SCHEDULE_TIMEOUT; @@ -911,10 +912,10 @@ void tty_ldisc_release(struct tty_struct *tty, struct tty_struct *o_tty)  	 * race with the set_ldisc code path.  	 */ -	tty_unlock(); +	tty_unlock(tty);  	tty_ldisc_halt(tty);  	tty_ldisc_flush_works(tty); -	tty_lock(); +	tty_lock(tty);  	mutex_lock(&tty->ldisc_mutex);  	/* diff --git a/drivers/tty/tty_mutex.c b/drivers/tty/tty_mutex.c index 9ff986c32a2..69adc80c98c 100644 --- a/drivers/tty/tty_mutex.c +++ b/drivers/tty/tty_mutex.c @@ -4,29 +4,59 @@  #include <linux/semaphore.h>  #include <linux/sched.h> -/* - * The 'big tty mutex' - * - * This mutex is taken and released by tty_lock() and tty_unlock(), - * replacing the older big kernel lock. - * It can no longer be taken recursively, and does not get - * released implicitly while sleeping. - * - * Don't use in new code. - */ -static DEFINE_MUTEX(big_tty_mutex); +/* Legacy tty mutex glue */  /*   * Getting the big tty mutex.   */ -void __lockfunc tty_lock(void) + +void __lockfunc tty_lock(struct tty_struct *tty)  { -	mutex_lock(&big_tty_mutex); +	if (tty->magic != TTY_MAGIC) { +		printk(KERN_ERR "L Bad %p\n", tty); +		WARN_ON(1); +		return; +	} +	tty_kref_get(tty); +	mutex_lock(&tty->legacy_mutex);  }  EXPORT_SYMBOL(tty_lock); -void __lockfunc tty_unlock(void) +void __lockfunc tty_unlock(struct tty_struct *tty)  { -	mutex_unlock(&big_tty_mutex); +	if (tty->magic != TTY_MAGIC) { +		printk(KERN_ERR "U Bad %p\n", tty); +		WARN_ON(1); +		return; +	} +	mutex_unlock(&tty->legacy_mutex); +	tty_kref_put(tty);  }  EXPORT_SYMBOL(tty_unlock); + +/* + * Getting the big tty mutex for a pair of ttys with lock ordering + * On a non pty/tty pair tty2 can be NULL which is just fine. + */ +void __lockfunc tty_lock_pair(struct tty_struct *tty, +					struct tty_struct *tty2) +{ +	if (tty < tty2) { +		tty_lock(tty); +		tty_lock(tty2); +	} else { +		if (tty2 && tty2 != tty) +			tty_lock(tty2); +		tty_lock(tty); +	} +} +EXPORT_SYMBOL(tty_lock_pair); + +void __lockfunc tty_unlock_pair(struct tty_struct *tty, +						struct tty_struct *tty2) +{ +	tty_unlock(tty); +	if (tty2 && tty2 != tty) +		tty_unlock(tty2); +} +EXPORT_SYMBOL(tty_unlock_pair); diff --git a/drivers/tty/tty_port.c b/drivers/tty/tty_port.c index bf6e238146a..d9cca95a545 100644 --- a/drivers/tty/tty_port.c +++ b/drivers/tty/tty_port.c @@ -230,7 +230,7 @@ int tty_port_block_til_ready(struct tty_port *port,  	/* block if port is in the process of being closed */  	if (tty_hung_up_p(filp) || port->flags & ASYNC_CLOSING) { -		wait_event_interruptible_tty(port->close_wait, +		wait_event_interruptible_tty(tty, port->close_wait,  				!(port->flags & ASYNC_CLOSING));  		if (port->flags & ASYNC_HUP_NOTIFY)  			return -EAGAIN; @@ -296,9 +296,9 @@ int tty_port_block_til_ready(struct tty_port *port,  			retval = -ERESTARTSYS;  			break;  		} -		tty_unlock(); +		tty_unlock(tty);  		schedule(); -		tty_lock(); +		tty_lock(tty);  	}  	finish_wait(&port->open_wait, &wait); diff --git a/drivers/tty/vt/consolemap.c b/drivers/tty/vt/consolemap.c index 8308fc7cdc2..2aaa0c22840 100644 --- a/drivers/tty/vt/consolemap.c +++ b/drivers/tty/vt/consolemap.c @@ -19,6 +19,7 @@  #include <linux/init.h>  #include <linux/tty.h>  #include <asm/uaccess.h> +#include <linux/console.h>  #include <linux/consolemap.h>  #include <linux/vt_kern.h> @@ -312,6 +313,7 @@ int con_set_trans_old(unsigned char __user * arg)  	if (!access_ok(VERIFY_READ, arg, E_TABSZ))  		return -EFAULT; +	console_lock();  	for (i=0; i<E_TABSZ ; i++) {  		unsigned char uc;  		__get_user(uc, arg+i); @@ -319,6 +321,7 @@ int con_set_trans_old(unsigned char __user * arg)  	}  	update_user_maps(); +	console_unlock();  	return 0;  } @@ -330,11 +333,13 @@ int con_get_trans_old(unsigned char __user * arg)  	if (!access_ok(VERIFY_WRITE, arg, E_TABSZ))  		return -EFAULT; +	console_lock();  	for (i=0; i<E_TABSZ ; i++) -	  { -	    ch = conv_uni_to_pc(vc_cons[fg_console].d, p[i]); -	    __put_user((ch & ~0xff) ? 0 : ch, arg+i); -	  } +	{ +		ch = conv_uni_to_pc(vc_cons[fg_console].d, p[i]); +		__put_user((ch & ~0xff) ? 0 : ch, arg+i); +	} +	console_unlock();  	return 0;  } @@ -346,6 +351,7 @@ int con_set_trans_new(ushort __user * arg)  	if (!access_ok(VERIFY_READ, arg, E_TABSZ*sizeof(unsigned short)))  		return -EFAULT; +	console_lock();  	for (i=0; i<E_TABSZ ; i++) {  		unsigned short us;  		__get_user(us, arg+i); @@ -353,6 +359,7 @@ int con_set_trans_new(ushort __user * arg)  	}  	update_user_maps(); +	console_unlock();  	return 0;  } @@ -364,8 +371,10 @@ int con_get_trans_new(ushort __user * arg)  	if (!access_ok(VERIFY_WRITE, arg, E_TABSZ*sizeof(unsigned short)))  		return -EFAULT; +	console_lock();  	for (i=0; i<E_TABSZ ; i++)  	  __put_user(p[i], arg+i); +	console_unlock();  	return 0;  } @@ -407,6 +416,7 @@ static void con_release_unimap(struct uni_pagedir *p)  	}  } +/* Caller must hold the console lock */  void con_free_unimap(struct vc_data *vc)  {  	struct uni_pagedir *p; @@ -487,17 +497,21 @@ con_insert_unipair(struct uni_pagedir *p, u_short unicode, u_short fontpos)  	return 0;  } -/* ui is a leftover from using a hashtable, but might be used again */ -int con_clear_unimap(struct vc_data *vc, struct unimapinit *ui) +/* ui is a leftover from using a hashtable, but might be used again +   Caller must hold the lock */ +static int con_do_clear_unimap(struct vc_data *vc, struct unimapinit *ui)  {  	struct uni_pagedir *p, *q; -   +  	p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc; -	if (p && p->readonly) return -EIO; +	if (p && p->readonly) +		return -EIO; +  	if (!p || --p->refcount) {  		q = kzalloc(sizeof(*p), GFP_KERNEL);  		if (!q) { -			if (p) p->refcount++; +			if (p) +				p->refcount++;  			return -ENOMEM;  		}  		q->refcount=1; @@ -511,23 +525,43 @@ int con_clear_unimap(struct vc_data *vc, struct unimapinit *ui)  	return 0;  } +int con_clear_unimap(struct vc_data *vc, struct unimapinit *ui) +{ +	int ret; +	console_lock(); +	ret = con_do_clear_unimap(vc, ui); +	console_unlock(); +	return ret; +} +	  int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list)  {  	int err = 0, err1, i;  	struct uni_pagedir *p, *q; +	console_lock(); +  	/* Save original vc_unipagdir_loc in case we allocate a new one */  	p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc; -	if (p->readonly) return -EIO; +	if (p->readonly) { +		console_unlock(); +		return -EIO; +	} -	if (!ct) return 0; +	if (!ct) { +		console_unlock(); +		return 0; +	}  	if (p->refcount > 1) {  		int j, k;  		u16 **p1, *p2, l; -		err1 = con_clear_unimap(vc, NULL); -		if (err1) return err1; +		err1 = con_do_clear_unimap(vc, NULL); +		if (err1) { +			console_unlock(); +			return err1; +		}  		/*  		 * Since refcount was > 1, con_clear_unimap() allocated a @@ -558,7 +592,8 @@ int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list)  						*vc->vc_uni_pagedir_loc = (unsigned long)p;  						con_release_unimap(q);  						kfree(q); -						return err1; +						console_unlock(); +						return err1;   					}  				}  			} else { @@ -592,21 +627,30 @@ int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list)  	/*  	 * Merge with fontmaps of any other virtual consoles.  	 */ -	if (con_unify_unimap(vc, p)) +	if (con_unify_unimap(vc, p)) { +		console_unlock();  		return err; +	}  	for (i = 0; i <= 3; i++)  		set_inverse_transl(vc, p, i); /* Update inverse translations */  	set_inverse_trans_unicode(vc, p); -   + +	console_unlock();  	return err;  } -/* Loads the unimap for the hardware font, as defined in uni_hash.tbl. -   The representation used was the most compact I could come up -   with.  This routine is executed at sys_setup time, and when the -   PIO_FONTRESET ioctl is called. */ - +/** + *	con_set_default_unimap	-	set default unicode map + *	@vc: the console we are updating + * + *	Loads the unimap for the hardware font, as defined in uni_hash.tbl. + *	The representation used was the most compact I could come up + *	with.  This routine is executed at video setup, and when the + *	PIO_FONTRESET ioctl is called.  + * + *	The caller must hold the console lock + */  int con_set_default_unimap(struct vc_data *vc)  {  	int i, j, err = 0, err1; @@ -617,6 +661,7 @@ int con_set_default_unimap(struct vc_data *vc)  		p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;  		if (p == dflt)  			return 0; +  		dflt->refcount++;  		*vc->vc_uni_pagedir_loc = (unsigned long)dflt;  		if (p && !--p->refcount) { @@ -628,8 +673,9 @@ int con_set_default_unimap(struct vc_data *vc)  	/* The default font is always 256 characters */ -	err = con_clear_unimap(vc, NULL); -	if (err) return err; +	err = con_do_clear_unimap(vc, NULL); +	if (err) +		return err;  	p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;  	q = dfont_unitable; @@ -654,6 +700,13 @@ int con_set_default_unimap(struct vc_data *vc)  }  EXPORT_SYMBOL(con_set_default_unimap); +/** + *	con_copy_unimap		-	copy unimap between two vts + *	@dst_vc: target + *	@src_vt: source + * + *	The caller must hold the console lock when invoking this method + */  int con_copy_unimap(struct vc_data *dst_vc, struct vc_data *src_vc)  {  	struct uni_pagedir *q; @@ -668,13 +721,23 @@ int con_copy_unimap(struct vc_data *dst_vc, struct vc_data *src_vc)  	*dst_vc->vc_uni_pagedir_loc = (long)q;  	return 0;  } +EXPORT_SYMBOL(con_copy_unimap); +/** + *	con_get_unimap		-	get the unicode map + *	@vc: the console to read from + * + *	Read the console unicode data for this console. Called from the ioctl + *	handlers. + */  int con_get_unimap(struct vc_data *vc, ushort ct, ushort __user *uct, struct unipair __user *list)  {  	int i, j, k, ect;  	u16 **p1, *p2;  	struct uni_pagedir *p; +	console_lock(); +  	ect = 0;  	if (*vc->vc_uni_pagedir_loc) {  		p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc; @@ -694,22 +757,19 @@ int con_get_unimap(struct vc_data *vc, ushort ct, ushort __user *uct, struct uni  				}  	}  	__put_user(ect, uct); +	console_unlock();  	return ((ect <= ct) ? 0 : -ENOMEM);  } -void con_protect_unimap(struct vc_data *vc, int rdonly) -{ -	struct uni_pagedir *p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc; -	 -	if (p) -		p->readonly = rdonly; -} -  /*   * Always use USER_MAP. These functions are used by the keyboard,   * which shouldn't be affected by G0/G1 switching, etc.   * If the user map still contains default values, i.e. the   * direct-to-font mapping, then assume user is using Latin1. + * + * FIXME: at some point we need to decide if we want to lock the table + * update element itself via the keyboard_event_lock for consistency with the + * keyboard driver as well as the consoles   */  /* may be called during an interrupt */  u32 conv_8bit_to_uni(unsigned char c) @@ -777,4 +837,3 @@ console_map_init(void)  			con_set_default_unimap(vc_cons[i].d);  } -EXPORT_SYMBOL(con_copy_unimap); diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index 2156188db4a..84cbf298c09 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -3892,36 +3892,6 @@ static void set_palette(struct vc_data *vc)  		vc->vc_sw->con_set_palette(vc, color_table);  } -static int set_get_cmap(unsigned char __user *arg, int set) -{ -    int i, j, k; - -    WARN_CONSOLE_UNLOCKED(); - -    for (i = 0; i < 16; i++) -	if (set) { -	    get_user(default_red[i], arg++); -	    get_user(default_grn[i], arg++); -	    get_user(default_blu[i], arg++); -	} else { -	    put_user(default_red[i], arg++); -	    put_user(default_grn[i], arg++); -	    put_user(default_blu[i], arg++); -	} -    if (set) { -	for (i = 0; i < MAX_NR_CONSOLES; i++) -	    if (vc_cons_allocated(i)) { -		for (j = k = 0; j < 16; j++) { -		    vc_cons[i].d->vc_palette[k++] = default_red[j]; -		    vc_cons[i].d->vc_palette[k++] = default_grn[j]; -		    vc_cons[i].d->vc_palette[k++] = default_blu[j]; -		} -		set_palette(vc_cons[i].d); -	    } -    } -    return 0; -} -  /*   * Load palette into the DAC registers. arg points to a colour   * map, 3 bytes per colour, 16 colours, range from 0 to 255. @@ -3929,24 +3899,50 @@ static int set_get_cmap(unsigned char __user *arg, int set)  int con_set_cmap(unsigned char __user *arg)  { -	int rc; +	int i, j, k; +	unsigned char colormap[3*16]; + +	if (copy_from_user(colormap, arg, sizeof(colormap))) +		return -EFAULT;  	console_lock(); -	rc = set_get_cmap (arg,1); +	for (i = k = 0; i < 16; i++) { +		default_red[i] = colormap[k++]; +		default_grn[i] = colormap[k++]; +		default_blu[i] = colormap[k++]; +	} +	for (i = 0; i < MAX_NR_CONSOLES; i++) { +		if (!vc_cons_allocated(i)) +			continue; +		for (j = k = 0; j < 16; j++) { +			vc_cons[i].d->vc_palette[k++] = default_red[j]; +			vc_cons[i].d->vc_palette[k++] = default_grn[j]; +			vc_cons[i].d->vc_palette[k++] = default_blu[j]; +		} +		set_palette(vc_cons[i].d); +	}  	console_unlock(); -	return rc; +	return 0;  }  int con_get_cmap(unsigned char __user *arg)  { -	int rc; +	int i, k; +	unsigned char colormap[3*16];  	console_lock(); -	rc = set_get_cmap (arg,0); +	for (i = k = 0; i < 16; i++) { +		colormap[k++] = default_red[i]; +		colormap[k++] = default_grn[i]; +		colormap[k++] = default_blu[i]; +	}  	console_unlock(); -	return rc; +	if (copy_to_user(arg, colormap, sizeof(colormap))) +		return -EFAULT; + +	return 0;  }  void reset_palette(struct vc_data *vc) diff --git a/drivers/tty/vt/vt_ioctl.c b/drivers/tty/vt/vt_ioctl.c index ede2ef18d2f..64618547be1 100644 --- a/drivers/tty/vt/vt_ioctl.c +++ b/drivers/tty/vt/vt_ioctl.c @@ -910,7 +910,9 @@ int vt_ioctl(struct tty_struct *tty,  		ret = con_font_op(vc_cons[fg_console].d, &op);  		if (ret)  			break; +		console_lock();  		con_set_default_unimap(vc_cons[fg_console].d); +		console_unlock();  		break;  		}  #endif @@ -934,33 +936,23 @@ int vt_ioctl(struct tty_struct *tty,  	case PIO_SCRNMAP:  		if (!perm)  			ret = -EPERM; -		else { -			tty_lock(); +		else  			ret = con_set_trans_old(up); -			tty_unlock(); -		}  		break;  	case GIO_SCRNMAP: -		tty_lock();  		ret = con_get_trans_old(up); -		tty_unlock();  		break;  	case PIO_UNISCRNMAP:  		if (!perm)  			ret = -EPERM; -		else { -			tty_lock(); +		else  			ret = con_set_trans_new(up); -			tty_unlock(); -		}  		break;  	case GIO_UNISCRNMAP: -		tty_lock();  		ret = con_get_trans_new(up); -		tty_unlock();  		break;  	case PIO_UNIMAPCLR: @@ -970,19 +962,14 @@ int vt_ioctl(struct tty_struct *tty,  		ret = copy_from_user(&ui, up, sizeof(struct unimapinit));  		if (ret)  			ret = -EFAULT; -		else { -			tty_lock(); +		else  			con_clear_unimap(vc, &ui); -			tty_unlock(); -		}  		break;  	      }  	case PIO_UNIMAP:  	case GIO_UNIMAP: -		tty_lock();  		ret = do_unimap_ioctl(cmd, up, perm, vc); -		tty_unlock();  		break;  	case VT_LOCKSWITCH: @@ -1196,9 +1183,7 @@ long vt_compat_ioctl(struct tty_struct *tty,  	case PIO_UNIMAP:  	case GIO_UNIMAP: -		tty_lock();  		ret = compat_unimap_ioctl(cmd, up, perm, vc); -		tty_unlock();  		break;  	/* diff --git a/drivers/usb/gadget/u_serial.c b/drivers/usb/gadget/u_serial.c index 380a87f6e56..15a42c8c194 100644 --- a/drivers/usb/gadget/u_serial.c +++ b/drivers/usb/gadget/u_serial.c @@ -94,17 +94,14 @@ struct gs_buf {   * (and thus for each /dev/ node).   */  struct gs_port { +	struct tty_port		port;  	spinlock_t		port_lock;	/* guard port_* access */  	struct gserial		*port_usb; -	struct tty_struct	*port_tty; -	unsigned		open_count;  	bool			openclose;	/* open/close in progress */  	u8			port_num; -	wait_queue_head_t	close_wait;	/* wait for last close */ -  	struct list_head	read_pool;  	int read_started;  	int read_allocated; @@ -412,8 +409,8 @@ __acquires(&port->port_lock)  			break;  	} -	if (do_tty_wake && port->port_tty) -		tty_wakeup(port->port_tty); +	if (do_tty_wake && port->port.tty) +		tty_wakeup(port->port.tty);  	return status;  } @@ -435,7 +432,7 @@ __acquires(&port->port_lock)  		struct tty_struct	*tty;  		/* no more rx if closed */ -		tty = port->port_tty; +		tty = port->port.tty;  		if (!tty)  			break; @@ -488,7 +485,7 @@ static void gs_rx_push(unsigned long _port)  	/* hand any queued data to the tty */  	spin_lock_irq(&port->port_lock); -	tty = port->port_tty; +	tty = port->port.tty;  	while (!list_empty(queue)) {  		struct usb_request	*req; @@ -699,7 +696,7 @@ static int gs_start_io(struct gs_port *port)  	/* unblock any pending writes into our circular buffer */  	if (started) { -		tty_wakeup(port->port_tty); +		tty_wakeup(port->port.tty);  	} else {  		gs_free_requests(ep, head, &port->read_allocated);  		gs_free_requests(port->port_usb->in, &port->write_pool, @@ -734,9 +731,9 @@ static int gs_open(struct tty_struct *tty, struct file *file)  			spin_lock_irq(&port->port_lock);  			/* already open?  Great. */ -			if (port->open_count) { +			if (port->port.count) {  				status = 0; -				port->open_count++; +				port->port.count++;  			/* currently opening/closing? wait ... */  			} else if (port->openclose) { @@ -793,9 +790,9 @@ static int gs_open(struct tty_struct *tty, struct file *file)  	/* REVISIT maybe wait for "carrier detect" */  	tty->driver_data = port; -	port->port_tty = tty; +	port->port.tty = tty; -	port->open_count = 1; +	port->port.count = 1;  	port->openclose = false;  	/* if connected, start the I/O stream */ @@ -837,11 +834,11 @@ static void gs_close(struct tty_struct *tty, struct file *file)  	spin_lock_irq(&port->port_lock); -	if (port->open_count != 1) { -		if (port->open_count == 0) +	if (port->port.count != 1) { +		if (port->port.count == 0)  			WARN_ON(1);  		else -			--port->open_count; +			--port->port.count;  		goto exit;  	} @@ -851,7 +848,7 @@ static void gs_close(struct tty_struct *tty, struct file *file)  	 * and sleep if necessary  	 */  	port->openclose = true; -	port->open_count = 0; +	port->port.count = 0;  	gser = port->port_usb;  	if (gser && gser->disconnect) @@ -879,14 +876,14 @@ static void gs_close(struct tty_struct *tty, struct file *file)  		gs_buf_clear(&port->port_write_buf);  	tty->driver_data = NULL; -	port->port_tty = NULL; +	port->port.tty = NULL;  	port->openclose = false;  	pr_debug("gs_close: ttyGS%d (%p,%p) done!\n",  			port->port_num, tty, file); -	wake_up_interruptible(&port->close_wait); +	wake_up_interruptible(&port->port.close_wait);  exit:  	spin_unlock_irq(&port->port_lock);  } @@ -1034,8 +1031,8 @@ gs_port_alloc(unsigned port_num, struct usb_cdc_line_coding *coding)  	if (port == NULL)  		return -ENOMEM; +	tty_port_init(&port->port);  	spin_lock_init(&port->port_lock); -	init_waitqueue_head(&port->close_wait);  	init_waitqueue_head(&port->drain_wait);  	tasklet_init(&port->push, gs_rx_push, (unsigned long) port); @@ -1155,7 +1152,7 @@ static int gs_closed(struct gs_port *port)  	int cond;  	spin_lock_irq(&port->port_lock); -	cond = (port->open_count == 0) && !port->openclose; +	cond = (port->port.count == 0) && !port->openclose;  	spin_unlock_irq(&port->port_lock);  	return cond;  } @@ -1194,7 +1191,7 @@ void gserial_cleanup(void)  		tasklet_kill(&port->push);  		/* wait for old opens to finish */ -		wait_event(port->close_wait, gs_closed(port)); +		wait_event(port->port.close_wait, gs_closed(port));  		WARN_ON(port->port_usb != NULL); @@ -1268,7 +1265,7 @@ int gserial_connect(struct gserial *gser, u8 port_num)  	/* if it's already open, start I/O ... and notify the serial  	 * protocol about open/close status (connect/disconnect).  	 */ -	if (port->open_count) { +	if (port->port.count) {  		pr_debug("gserial_connect: start ttyGS%d\n", port->port_num);  		gs_start_io(port);  		if (gser->connect) @@ -1315,10 +1312,10 @@ void gserial_disconnect(struct gserial *gser)  	port->port_usb = NULL;  	gser->ioport = NULL; -	if (port->open_count > 0 || port->openclose) { +	if (port->port.count > 0 || port->openclose) {  		wake_up_interruptible(&port->drain_wait); -		if (port->port_tty) -			tty_hangup(port->port_tty); +		if (port->port.tty) +			tty_hangup(port->port.tty);  	}  	spin_unlock_irqrestore(&port->port_lock, flags); @@ -1331,7 +1328,7 @@ void gserial_disconnect(struct gserial *gser)  	/* finally, free any unused/unusable I/O buffers */  	spin_lock_irqsave(&port->port_lock, flags); -	if (port->open_count == 0 && !port->openclose) +	if (port->port.count == 0 && !port->openclose)  		gs_buf_free(&port->port_write_buf);  	gs_free_requests(gser->out, &port->read_pool, NULL);  	gs_free_requests(gser->out, &port->read_queue, NULL);  |