diff options
77 files changed, 1191 insertions, 1149 deletions
diff --git a/Documentation/devicetree/bindings/tty/serial/of-serial.txt b/Documentation/devicetree/bindings/tty/serial/of-serial.txt index 8f01cb190f2..1928a3e83cd 100644 --- a/Documentation/devicetree/bindings/tty/serial/of-serial.txt +++ b/Documentation/devicetree/bindings/tty/serial/of-serial.txt @@ -33,6 +33,10 @@ Optional properties:    RTAS and should not be registered.  - no-loopback-test: set to indicate that the port does not implements loopback    test mode +- fifo-size: the fifo size of the UART. +- auto-flow-control: one way to enable automatic flow control support. The +  driver is allowed to detect support for the capability even without this +  property.  Example: diff --git a/arch/ia64/hp/sim/simserial.c b/arch/ia64/hp/sim/simserial.c index da2f319fb71..e70cadec7ce 100644 --- a/arch/ia64/hp/sim/simserial.c +++ b/arch/ia64/hp/sim/simserial.c @@ -142,8 +142,7 @@ static void transmit_chars(struct tty_struct *tty, struct serial_state *info,  		goto out;  	} -	if (info->xmit.head == info->xmit.tail || tty->stopped || -			tty->hw_stopped) { +	if (info->xmit.head == info->xmit.tail || tty->stopped) {  #ifdef SIMSERIAL_DEBUG  		printk("transmit_chars: head=%d, tail=%d, stopped=%d\n",  		       info->xmit.head, info->xmit.tail, tty->stopped); @@ -181,7 +180,7 @@ static void rs_flush_chars(struct tty_struct *tty)  	struct serial_state *info = tty->driver_data;  	if (info->xmit.head == info->xmit.tail || tty->stopped || -			tty->hw_stopped || !info->xmit.buf) +			!info->xmit.buf)  		return;  	transmit_chars(tty, info, NULL); @@ -217,7 +216,7 @@ static int rs_write(struct tty_struct * tty,  	 * Hey, we transmit directly from here in our case  	 */  	if (CIRC_CNT(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE) && -			!tty->stopped && !tty->hw_stopped) +			!tty->stopped)  		transmit_chars(tty, info, NULL);  	return ret; @@ -325,14 +324,6 @@ static int rs_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg)  #define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK)) -static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios) -{ -	/* Handle turning off CRTSCTS */ -	if ((old_termios->c_cflag & CRTSCTS) && -	    !(tty->termios.c_cflag & CRTSCTS)) { -		tty->hw_stopped = 0; -	} -}  /*   * This routine will shutdown a serial port; interrupts are disabled, and   * DTR is dropped if the hangup on close termio flag is on. @@ -481,7 +472,6 @@ static const struct tty_operations hp_ops = {  	.throttle = rs_throttle,  	.unthrottle = rs_unthrottle,  	.send_xchar = rs_send_xchar, -	.set_termios = rs_set_termios,  	.hangup = rs_hangup,  	.proc_fops = &rs_proc_fops,  }; diff --git a/arch/um/drivers/chan_kern.c b/arch/um/drivers/chan_kern.c index 80b47cb71e0..acbe6c67afb 100644 --- a/arch/um/drivers/chan_kern.c +++ b/arch/um/drivers/chan_kern.c @@ -568,11 +568,7 @@ void chan_interrupt(struct line *line, int irq)  		reactivate_fd(chan->fd, irq);  	if (err == -EIO) {  		if (chan->primary) { -			struct tty_struct *tty = tty_port_tty_get(&line->port); -			if (tty != NULL) { -				tty_hangup(tty); -				tty_kref_put(tty); -			} +			tty_port_tty_hangup(&line->port, false);  			if (line->chan_out != chan)  				close_one_chan(line->chan_out, 1);  		} diff --git a/arch/um/drivers/line.c b/arch/um/drivers/line.c index be541cf69fd..8035145f043 100644 --- a/arch/um/drivers/line.c +++ b/arch/um/drivers/line.c @@ -248,7 +248,6 @@ static irqreturn_t line_write_interrupt(int irq, void *data)  {  	struct chan *chan = data;  	struct line *line = chan->line; -	struct tty_struct *tty;  	int err;  	/* @@ -267,12 +266,7 @@ static irqreturn_t line_write_interrupt(int irq, void *data)  	}  	spin_unlock(&line->lock); -	tty = tty_port_tty_get(&line->port); -	if (tty == NULL) -		return IRQ_NONE; - -	tty_wakeup(tty); -	tty_kref_put(tty); +	tty_port_tty_wakeup(&line->port);  	return IRQ_HANDLED;  } diff --git a/drivers/isdn/capi/capi.c b/drivers/isdn/capi/capi.c index 89562a845f6..ac6f72b455d 100644 --- a/drivers/isdn/capi/capi.c +++ b/drivers/isdn/capi/capi.c @@ -569,7 +569,6 @@ static void capi_recv_message(struct capi20_appl *ap, struct sk_buff *skb)  {  	struct capidev *cdev = ap->private;  #ifdef CONFIG_ISDN_CAPI_MIDDLEWARE -	struct tty_struct *tty;  	struct capiminor *mp;  	u16 datahandle;  	struct capincci *np; @@ -627,11 +626,7 @@ static void capi_recv_message(struct capi20_appl *ap, struct sk_buff *skb)  			 CAPIMSG_U16(skb->data, CAPIMSG_BASELEN + 4 + 2));  		kfree_skb(skb);  		capiminor_del_ack(mp, datahandle); -		tty = tty_port_tty_get(&mp->port); -		if (tty) { -			tty_wakeup(tty); -			tty_kref_put(tty); -		} +		tty_port_tty_wakeup(&mp->port);  		handle_minor_send(mp);  	} else { diff --git a/drivers/isdn/gigaset/interface.c b/drivers/isdn/gigaset/interface.c index e2b539675b6..600c79b030c 100644 --- a/drivers/isdn/gigaset/interface.c +++ b/drivers/isdn/gigaset/interface.c @@ -487,12 +487,8 @@ static const struct tty_operations if_ops = {  static void if_wake(unsigned long data)  {  	struct cardstate *cs = (struct cardstate *)data; -	struct tty_struct *tty = tty_port_tty_get(&cs->port); -	if (tty) { -		tty_wakeup(tty); -		tty_kref_put(tty); -	} +	tty_port_tty_wakeup(&cs->port);  }  /*** interface to common ***/ diff --git a/drivers/isdn/i4l/isdn_tty.c b/drivers/isdn/i4l/isdn_tty.c index ebaebdf30f9..b72afd81a7b 100644 --- a/drivers/isdn/i4l/isdn_tty.c +++ b/drivers/isdn/i4l/isdn_tty.c @@ -1472,9 +1472,6 @@ isdn_tty_set_termios(struct tty_struct *tty, struct ktermios *old_termios)  		    tty->termios.c_ospeed == old_termios->c_ospeed)  			return;  		isdn_tty_change_speed(info); -		if ((old_termios->c_cflag & CRTSCTS) && -		    !(tty->termios.c_cflag & CRTSCTS)) -			tty->hw_stopped = 0;  	}  } diff --git a/drivers/mmc/card/sdio_uart.c b/drivers/mmc/card/sdio_uart.c index c931dfe6a59..f093cea0d06 100644 --- a/drivers/mmc/card/sdio_uart.c +++ b/drivers/mmc/card/sdio_uart.c @@ -134,7 +134,6 @@ static void sdio_uart_port_put(struct sdio_uart_port *port)  static void sdio_uart_port_remove(struct sdio_uart_port *port)  {  	struct sdio_func *func; -	struct tty_struct *tty;  	BUG_ON(sdio_uart_table[port->index] != port); @@ -155,12 +154,8 @@ static void sdio_uart_port_remove(struct sdio_uart_port *port)  	sdio_claim_host(func);  	port->func = NULL;  	mutex_unlock(&port->func_lock); -	tty = tty_port_tty_get(&port->port);  	/* tty_hangup is async so is this safe as is ?? */ -	if (tty) { -		tty_hangup(tty); -		tty_kref_put(tty); -	} +	tty_port_tty_hangup(&port->port, false);  	mutex_unlock(&port->port.mutex);  	sdio_release_irq(func);  	sdio_disable_func(func); @@ -492,11 +487,7 @@ static void sdio_uart_check_modem_status(struct sdio_uart_port *port)  			wake_up_interruptible(&port->port.open_wait);  		else {  			/* DCD drop - hang up if tty attached */ -			tty = tty_port_tty_get(&port->port); -			if (tty) { -				tty_hangup(tty); -				tty_kref_put(tty); -			} +			tty_port_tty_hangup(&port->port, false);  		}  	}  	if (status & UART_MSR_DCTS) { diff --git a/drivers/net/caif/caif_serial.c b/drivers/net/caif/caif_serial.c index 666891a9a24..be90debc7cd 100644 --- a/drivers/net/caif/caif_serial.c +++ b/drivers/net/caif/caif_serial.c @@ -88,11 +88,9 @@ static inline void update_tty_status(struct ser_device *ser)  {  	ser->tty_status =  		ser->tty->stopped << 5 | -		ser->tty->hw_stopped << 4 |  		ser->tty->flow_stopped << 3 |  		ser->tty->packet << 2 | -		ser->tty->port->low_latency << 1 | -		ser->tty->warned; +		ser->tty->port->low_latency << 1;  }  static inline void debugfs_init(struct ser_device *ser, struct tty_struct *tty)  { diff --git a/drivers/net/ppp/ppp_async.c b/drivers/net/ppp/ppp_async.c index a031f6b456b..9c889e0303d 100644 --- a/drivers/net/ppp/ppp_async.c +++ b/drivers/net/ppp/ppp_async.c @@ -314,7 +314,7 @@ ppp_asynctty_ioctl(struct tty_struct *tty, struct file *file,  		/* flush our buffers and the serial port's buffer */  		if (arg == TCIOFLUSH || arg == TCOFLUSH)  			ppp_async_flush_output(ap); -		err = tty_perform_flush(tty, arg); +		err = n_tty_ioctl_helper(tty, file, cmd, arg);  		break;  	case FIONREAD: diff --git a/drivers/net/ppp/ppp_synctty.c b/drivers/net/ppp/ppp_synctty.c index 1a12033d2ef..bdf3b13a71a 100644 --- a/drivers/net/ppp/ppp_synctty.c +++ b/drivers/net/ppp/ppp_synctty.c @@ -355,7 +355,7 @@ ppp_synctty_ioctl(struct tty_struct *tty, struct file *file,  		/* flush our buffers and the serial port's buffer */  		if (arg == TCIOFLUSH || arg == TCOFLUSH)  			ppp_sync_flush_output(ap); -		err = tty_perform_flush(tty, arg); +		err = n_tty_ioctl_helper(tty, file, cmd, arg);  		break;  	case FIONREAD: diff --git a/drivers/net/usb/hso.c b/drivers/net/usb/hso.c index e2dd3249b6b..cba1d46e672 100644 --- a/drivers/net/usb/hso.c +++ b/drivers/net/usb/hso.c @@ -1925,7 +1925,6 @@ static void hso_std_serial_write_bulk_callback(struct urb *urb)  {  	struct hso_serial *serial = urb->context;  	int status = urb->status; -	struct tty_struct *tty;  	/* sanity check */  	if (!serial) { @@ -1941,11 +1940,7 @@ static void hso_std_serial_write_bulk_callback(struct urb *urb)  		return;  	}  	hso_put_activity(serial->parent); -	tty = tty_port_tty_get(&serial->port); -	if (tty) { -		tty_wakeup(tty); -		tty_kref_put(tty); -	} +	tty_port_tty_wakeup(&serial->port);  	hso_kick_transmit(serial);  	D1(" "); @@ -2008,12 +2003,8 @@ 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) { -			tty_wakeup(tty); -			tty_kref_put(tty); -		} +		tty_port_tty_wakeup(&serial->port);  		/* response to a write command */  		hso_kick_transmit(serial);  	} @@ -3133,18 +3124,13 @@ static void hso_serial_ref_free(struct kref *ref)  static void hso_free_interface(struct usb_interface *interface)  {  	struct hso_serial *hso_dev; -	struct tty_struct *tty;  	int i;  	for (i = 0; i < HSO_SERIAL_TTY_MINORS; i++) {  		if (serial_table[i] &&  		    (serial_table[i]->interface == interface)) {  			hso_dev = dev2ser(serial_table[i]); -			tty = tty_port_tty_get(&hso_dev->port); -			if (tty) { -				tty_hangup(tty); -				tty_kref_put(tty); -			} +			tty_port_tty_hangup(&hso_dev->port, false);  			mutex_lock(&hso_dev->parent->mutex);  			hso_dev->parent->usb_gone = 1;  			mutex_unlock(&hso_dev->parent->mutex); diff --git a/drivers/s390/char/sclp_tty.c b/drivers/s390/char/sclp_tty.c index 14b4cb8abcc..7ed7a598781 100644 --- a/drivers/s390/char/sclp_tty.c +++ b/drivers/s390/char/sclp_tty.c @@ -107,7 +107,6 @@ 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; @@ -125,12 +124,8 @@ sclp_ttybuf_callback(struct sclp_buffer *buffer, int rc)  					    struct sclp_buffer, list);  		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 */ -	tty = tty_port_tty_get(&sclp_port); -	if (tty != NULL) { -		tty_wakeup(tty); -		tty_kref_put(tty); -	} + +	tty_port_tty_wakeup(&sclp_port);  }  static inline void diff --git a/drivers/s390/char/sclp_vt220.c b/drivers/s390/char/sclp_vt220.c index 6c92f62623b..5aaaa2ec8df 100644 --- a/drivers/s390/char/sclp_vt220.c +++ b/drivers/s390/char/sclp_vt220.c @@ -114,7 +114,6 @@ 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; @@ -139,12 +138,7 @@ sclp_vt220_process_queue(struct sclp_vt220_request *request)  	} while (__sclp_vt220_emit(request));  	if (request == NULL && sclp_vt220_flush_later)  		sclp_vt220_emit_current(); -	/* Check if the tty needs a wake up call */ -	tty = tty_port_tty_get(&sclp_vt220_port); -	if (tty) { -		tty_wakeup(tty); -		tty_kref_put(tty); -	} +	tty_port_tty_wakeup(&sclp_vt220_port);  }  #define SCLP_BUFFER_MAX_RETRY		1 diff --git a/drivers/staging/fwserial/fwserial.c b/drivers/staging/fwserial/fwserial.c index 5a6fb44f38a..5c64e3a35b2 100644 --- a/drivers/staging/fwserial/fwserial.c +++ b/drivers/staging/fwserial/fwserial.c @@ -744,7 +744,6 @@ static void fwtty_tx_complete(struct fw_card *card, int rcode,  			      struct fwtty_transaction *txn)  {  	struct fwtty_port *port = txn->port; -	struct tty_struct *tty;  	int len;  	fwtty_dbg(port, "rcode: %d", rcode); @@ -769,13 +768,8 @@ static void fwtty_tx_complete(struct fw_card *card, int rcode,  		port->stats.dropped += txn->dma_pended.len;  	} -	if (len < WAKEUP_CHARS) { -		tty = tty_port_tty_get(&port->port); -		if (tty) { -			tty_wakeup(tty); -			tty_kref_put(tty); -		} -	} +	if (len < WAKEUP_CHARS) +		tty_port_tty_wakeup(&port->port);  }  static int fwtty_tx(struct fwtty_port *port, bool drain) diff --git a/drivers/staging/serqt_usb2/serqt_usb2.c b/drivers/staging/serqt_usb2/serqt_usb2.c index b1bb1a6abe8..8a6e5ea476e 100644 --- a/drivers/staging/serqt_usb2/serqt_usb2.c +++ b/drivers/staging/serqt_usb2/serqt_usb2.c @@ -264,7 +264,6 @@ static void ProcessRxChar(struct usb_serial_port *port, unsigned char data)  static void qt_write_bulk_callback(struct urb *urb)  { -	struct tty_struct *tty;  	int status;  	struct quatech_port *quatech_port; @@ -278,11 +277,7 @@ static void qt_write_bulk_callback(struct urb *urb)  	quatech_port = urb->context; -	tty = tty_port_tty_get(&quatech_port->port->port); - -	if (tty) -		tty_wakeup(tty); -	tty_kref_put(tty); +	tty_port_tty_wakeup(&quatech_port->port->port);  }  static void qt_interrupt_callback(struct urb *urb) diff --git a/drivers/tty/amiserial.c b/drivers/tty/amiserial.c index fc700342d43..083710e0236 100644 --- a/drivers/tty/amiserial.c +++ b/drivers/tty/amiserial.c @@ -1798,19 +1798,7 @@ static struct platform_driver amiga_serial_driver = {  	},  }; -static int __init amiga_serial_init(void) -{ -	return platform_driver_probe(&amiga_serial_driver, amiga_serial_probe); -} - -module_init(amiga_serial_init); - -static void __exit amiga_serial_exit(void) -{ -	platform_driver_unregister(&amiga_serial_driver); -} - -module_exit(amiga_serial_exit); +module_platform_driver_probe(amiga_serial_driver, amiga_serial_probe);  #if defined(CONFIG_SERIAL_CONSOLE) && !defined(MODULE) diff --git a/drivers/tty/cyclades.c b/drivers/tty/cyclades.c index 345bd0e0884..33f83fee9fa 100644 --- a/drivers/tty/cyclades.c +++ b/drivers/tty/cyclades.c @@ -1124,14 +1124,8 @@ static void cyz_handle_cmd(struct cyclades_card *cinfo)  					readl(&info->u.cyz.ch_ctrl->rs_status);  				if (dcd & C_RS_DCD)  					wake_up_interruptible(&info->port.open_wait); -				else { -					struct tty_struct *tty; -					tty = tty_port_tty_get(&info->port); -					if (tty) { -						tty_hangup(tty); -						tty_kref_put(tty); -					} -				} +				else +					tty_port_tty_hangup(&info->port, false);  			}  			break;  		case C_CM_MCTS: diff --git a/drivers/tty/ehv_bytechan.c b/drivers/tty/ehv_bytechan.c index ed92622b894..6d0c27cd03d 100644 --- a/drivers/tty/ehv_bytechan.c +++ b/drivers/tty/ehv_bytechan.c @@ -472,13 +472,9 @@ static void ehv_bc_tx_dequeue(struct ehv_bc_data *bc)  static irqreturn_t ehv_bc_tty_tx_isr(int irq, void *data)  {  	struct ehv_bc_data *bc = data; -	struct tty_struct *ttys = tty_port_tty_get(&bc->port);  	ehv_bc_tx_dequeue(bc); -	if (ttys) { -		tty_wakeup(ttys); -		tty_kref_put(ttys); -	} +	tty_port_tty_wakeup(&bc->port);  	return IRQ_HANDLED;  } diff --git a/drivers/tty/hvc/hvsi.c b/drivers/tty/hvc/hvsi.c index ef95a154854..41901997c0d 100644 --- a/drivers/tty/hvc/hvsi.c +++ b/drivers/tty/hvc/hvsi.c @@ -861,7 +861,6 @@ 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; @@ -895,11 +894,7 @@ static void hvsi_write_worker(struct work_struct *work)  		start_j = 0;  #endif /* DEBUG */  		wake_up_all(&hp->emptyq); -		tty = tty_port_tty_get(&hp->port); -		if (tty) { -			tty_wakeup(tty); -			tty_kref_put(tty); -		} +		tty_port_tty_wakeup(&hp->port);  	}  out: diff --git a/drivers/tty/ipwireless/hardware.c b/drivers/tty/ipwireless/hardware.c index 97a511f4185..2c14842541d 100644 --- a/drivers/tty/ipwireless/hardware.c +++ b/drivers/tty/ipwireless/hardware.c @@ -1732,8 +1732,7 @@ void ipwireless_hardware_free(struct ipw_hardware *hw)  	flush_work(&hw->work_rx);  	for (i = 0; i < NL_NUM_OF_ADDRESSES; i++) -		if (hw->packet_assembler[i] != NULL) -			kfree(hw->packet_assembler[i]); +		kfree(hw->packet_assembler[i]);  	for (i = 0; i < NL_NUM_OF_PRIORITIES; i++)  		list_for_each_entry_safe(tp, tq, &hw->tx_queue[i], queue) { diff --git a/drivers/tty/moxa.c b/drivers/tty/moxa.c index adeac255e52..1deaca4674e 100644 --- a/drivers/tty/moxa.c +++ b/drivers/tty/moxa.c @@ -913,16 +913,12 @@ static void moxa_board_deinit(struct moxa_board_conf *brd)  	/* pci hot-un-plug support */  	for (a = 0; a < brd->numPorts; a++) -		if (brd->ports[a].port.flags & ASYNC_INITIALIZED) { -			struct tty_struct *tty = tty_port_tty_get( -						&brd->ports[a].port); -			if (tty) { -				tty_hangup(tty); -				tty_kref_put(tty); -			} -		} +		if (brd->ports[a].port.flags & ASYNC_INITIALIZED) +			tty_port_tty_hangup(&brd->ports[a].port, false); +  	for (a = 0; a < MAX_PORTS_PER_BOARD; a++)  		tty_port_destroy(&brd->ports[a].port); +  	while (1) {  		opened = 0;  		for (a = 0; a < brd->numPorts; a++) @@ -1365,7 +1361,6 @@ static void moxa_hangup(struct tty_struct *tty)  static void moxa_new_dcdstate(struct moxa_port *p, u8 dcd)  { -	struct tty_struct *tty;  	unsigned long flags;  	dcd = !!dcd; @@ -1373,10 +1368,8 @@ static void moxa_new_dcdstate(struct moxa_port *p, u8 dcd)  	if (dcd != p->DCDState) {          	p->DCDState = dcd;          	spin_unlock_irqrestore(&p->port.lock, flags); -		tty = tty_port_tty_get(&p->port); -		if (tty && !C_CLOCAL(tty) && !dcd) -			tty_hangup(tty); -		tty_kref_put(tty); +		if (!dcd) +			tty_port_tty_hangup(&p->port, true);  	}  	else  		spin_unlock_irqrestore(&p->port.lock, flags); diff --git a/drivers/tty/mxser.c b/drivers/tty/mxser.c index 484b6a3c9b0..d996038eacf 100644 --- a/drivers/tty/mxser.c +++ b/drivers/tty/mxser.c @@ -1084,6 +1084,10 @@ static void mxser_close(struct tty_struct *tty, struct file *filp)  	mutex_lock(&port->mutex);  	mxser_close_port(port);  	mxser_flush_buffer(tty); +	if (test_bit(ASYNCB_INITIALIZED, &port->flags)) { +		if (C_HUPCL(tty)) +			tty_port_lower_dtr_rts(port); +	}  	mxser_shutdown_port(port);  	clear_bit(ASYNCB_INITIALIZED, &port->flags);  	mutex_unlock(&port->mutex); diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c index 4a43ef5d796..642239015b4 100644 --- a/drivers/tty/n_gsm.c +++ b/drivers/tty/n_gsm.c @@ -1418,11 +1418,7 @@ static void gsm_dlci_close(struct gsm_dlci *dlci)  		pr_debug("DLCI %d goes closed.\n", dlci->addr);  	dlci->state = DLCI_CLOSED;  	if (dlci->addr != 0) { -		struct tty_struct  *tty = tty_port_tty_get(&dlci->port); -		if (tty) { -			tty_hangup(tty); -			tty_kref_put(tty); -		} +		tty_port_tty_hangup(&dlci->port, false);  		kfifo_reset(dlci->fifo);  	} else  		dlci->gsm->dead = 1; @@ -2968,6 +2964,10 @@ static void gsmtty_close(struct tty_struct *tty, struct file *filp)  	if (tty_port_close_start(&dlci->port, tty, filp) == 0)  		goto out;  	gsm_dlci_begin_close(dlci); +	if (test_bit(ASYNCB_INITIALIZED, &dlci->port.flags)) { +		if (C_HUPCL(tty)) +			tty_port_lower_dtr_rts(&dlci->port); +	}  	tty_port_close_end(&dlci->port, tty);  	tty_port_tty_set(&dlci->port, NULL);  out: diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c index 05e72bea9b0..d655416087b 100644 --- a/drivers/tty/n_tty.c +++ b/drivers/tty/n_tty.c @@ -153,6 +153,12 @@ static void n_tty_set_room(struct tty_struct *tty)  	if (left && !old_left) {  		WARN_RATELIMIT(tty->port->itty == NULL,  				"scheduling with invalid itty\n"); +		/* see if ldisc has been killed - if so, this means that +		 * even though the ldisc has been halted and ->buf.work +		 * cancelled, ->buf.work is about to be rescheduled +		 */ +		WARN_RATELIMIT(test_bit(TTY_LDISC_HALTED, &tty->flags), +			       "scheduling buffer work for halted ldisc\n");  		schedule_work(&tty->port->buf.work);  	}  } @@ -189,34 +195,17 @@ static void put_tty_queue(unsigned char c, struct n_tty_data *ldata)  }  /** - *	check_unthrottle	-	allow new receive data - *	@tty; tty device - * - *	Check whether to call the driver unthrottle functions - * - *	Can sleep, may be called under the atomic_read_lock mutex but - *	this is not guaranteed. - */ -static void check_unthrottle(struct tty_struct *tty) -{ -	if (tty->count) -		tty_unthrottle(tty); -} - -/**   *	reset_buffer_flags	-	reset buffer state   *	@tty: terminal to reset   * - *	Reset the read buffer counters, clear the flags, - *	and make sure the driver is unthrottled. Called - *	from n_tty_open() and n_tty_flush_buffer(). + *	Reset the read buffer counters and clear the flags. + *	Called from n_tty_open() and n_tty_flush_buffer().   *   *	Locking: tty_read_lock for read fields.   */ -static void reset_buffer_flags(struct tty_struct *tty) +static void reset_buffer_flags(struct n_tty_data *ldata)  { -	struct n_tty_data *ldata = tty->disc_data;  	unsigned long flags;  	raw_spin_lock_irqsave(&ldata->read_lock, flags); @@ -229,36 +218,38 @@ static void reset_buffer_flags(struct tty_struct *tty)  	ldata->canon_head = ldata->canon_data = ldata->erasing = 0;  	bitmap_zero(ldata->read_flags, N_TTY_BUF_SIZE); -	n_tty_set_room(tty); +} + +static void n_tty_packet_mode_flush(struct tty_struct *tty) +{ +	unsigned long flags; + +	spin_lock_irqsave(&tty->ctrl_lock, flags); +	if (tty->link->packet) { +		tty->ctrl_status |= TIOCPKT_FLUSHREAD; +		wake_up_interruptible(&tty->link->read_wait); +	} +	spin_unlock_irqrestore(&tty->ctrl_lock, flags);  }  /**   *	n_tty_flush_buffer	-	clean input queue   *	@tty:	terminal device   * - *	Flush the input buffer. Called when the line discipline is - *	being closed, when the tty layer wants the buffer flushed (eg - *	at hangup) or when the N_TTY line discipline internally has to - *	clean the pending queue (for example some signals). + *	Flush the input buffer. Called when the tty layer wants the + *	buffer flushed (eg at hangup) or when the N_TTY line discipline + *	internally has to clean the pending queue (for example some signals).   *   *	Locking: ctrl_lock, read_lock.   */  static void n_tty_flush_buffer(struct tty_struct *tty)  { -	unsigned long flags; -	/* clear everything and unthrottle the driver */ -	reset_buffer_flags(tty); - -	if (!tty->link) -		return; +	reset_buffer_flags(tty->disc_data); +	n_tty_set_room(tty); -	spin_lock_irqsave(&tty->ctrl_lock, flags); -	if (tty->link->packet) { -		tty->ctrl_status |= TIOCPKT_FLUSHREAD; -		wake_up_interruptible(&tty->link->read_wait); -	} -	spin_unlock_irqrestore(&tty->ctrl_lock, flags); +	if (tty->link) +		n_tty_packet_mode_flush(tty);  }  /** @@ -1032,23 +1023,19 @@ static void eraser(unsigned char c, struct tty_struct *tty)   *	isig		-	handle the ISIG optio   *	@sig: signal   *	@tty: terminal - *	@flush: force flush   * - *	Called when a signal is being sent due to terminal input. This - *	may caus terminal flushing to take place according to the termios - *	settings and character used. Called from the driver receive_buf - *	path so serialized. + *	Called when a signal is being sent due to terminal input. + *	Called from the driver receive_buf path so serialized.   * - *	Locking: ctrl_lock, read_lock (both via flush buffer) + *	Locking: ctrl_lock   */ -static inline void isig(int sig, struct tty_struct *tty, int flush) +static inline void isig(int sig, struct tty_struct *tty)  { -	if (tty->pgrp) -		kill_pgrp(tty->pgrp, sig, 1); -	if (flush || !L_NOFLSH(tty)) { -		n_tty_flush_buffer(tty); -		tty_driver_flush_buffer(tty); +	struct pid *tty_pgrp = tty_get_pgrp(tty); +	if (tty_pgrp) { +		kill_pgrp(tty_pgrp, sig, 1); +		put_pid(tty_pgrp);  	}  } @@ -1069,7 +1056,11 @@ static inline void n_tty_receive_break(struct tty_struct *tty)  	if (I_IGNBRK(tty))  		return;  	if (I_BRKINT(tty)) { -		isig(SIGINT, tty, 1); +		isig(SIGINT, tty); +		if (!L_NOFLSH(tty)) { +			n_tty_flush_buffer(tty); +			tty_driver_flush_buffer(tty); +		}  		return;  	}  	if (I_PARMRK(tty)) { @@ -1236,11 +1227,6 @@ static inline void n_tty_receive_char(struct tty_struct *tty, unsigned char c)  		signal = SIGTSTP;  		if (c == SUSP_CHAR(tty)) {  send_signal: -			/* -			 * Note that we do not use isig() here because we want -			 * the order to be: -			 * 1) flush, 2) echo, 3) signal -			 */  			if (!L_NOFLSH(tty)) {  				n_tty_flush_buffer(tty);  				tty_driver_flush_buffer(tty); @@ -1251,8 +1237,7 @@ send_signal:  				echo_char(c, tty);  				process_echoes(tty);  			} -			if (tty->pgrp) -				kill_pgrp(tty->pgrp, signal, 1); +			isig(signal, tty);  			return;  		}  	} @@ -1483,14 +1468,14 @@ static void n_tty_receive_buf(struct tty_struct *tty, const unsigned char *cp,  	 * mode.  We don't want to throttle the driver if we're in  	 * canonical mode and don't have a newline yet!  	 */ -	if (tty->receive_room < TTY_THRESHOLD_THROTTLE) -		tty_throttle(tty); - -        /* FIXME: there is a tiny race here if the receive room check runs -           before the other work executes and empties the buffer (upping -           the receiving room and unthrottling. We then throttle and get -           stuck. This has been observed and traced down by Vincent Pillet/ -           We need to address this when we sort out out the rx path locking */ +	while (1) { +		tty_set_flow_change(tty, TTY_THROTTLE_SAFE); +		if (tty->receive_room >= TTY_THRESHOLD_THROTTLE) +			break; +		if (!tty_throttle_safe(tty)) +			break; +	} +	__tty_set_flow_change(tty, 0);  }  int is_ignored(int sig) @@ -1607,7 +1592,9 @@ static void n_tty_close(struct tty_struct *tty)  {  	struct n_tty_data *ldata = tty->disc_data; -	n_tty_flush_buffer(tty); +	if (tty->link) +		n_tty_packet_mode_flush(tty); +  	kfree(ldata->read_buf);  	kfree(ldata->echo_buf);  	kfree(ldata); @@ -1645,12 +1632,14 @@ static int n_tty_open(struct tty_struct *tty)  		goto err_free_bufs;  	tty->disc_data = ldata; -	reset_buffer_flags(tty); -	tty_unthrottle(tty); +	reset_buffer_flags(tty->disc_data);  	ldata->column = 0; -	n_tty_set_termios(tty, NULL);  	tty->minimum_to_wake = 1;  	tty->closing = 0; +	/* indicate buffer work may resume */ +	clear_bit(TTY_LDISC_HALTED, &tty->flags); +	n_tty_set_termios(tty, NULL); +	tty_unthrottle(tty);  	return 0;  err_free_bufs: @@ -1740,10 +1729,9 @@ extern ssize_t redirected_tty_write(struct file *, const char __user *,   *	and if appropriate send any needed signals and return a negative   *	error code if action should be taken.   * - *	FIXME: - *	Locking: None - redirected write test is safe, testing - *	current->signal should possibly lock current->sighand - *	pgrp locking ? + *	Locking: redirected write test is safe + *		 current->signal->tty check is safe + *		 ctrl_lock to safely reference tty->pgrp   */  static int job_control(struct tty_struct *tty, struct file *file) @@ -1753,19 +1741,22 @@ static int job_control(struct tty_struct *tty, struct file *file)  	/* NOTE: not yet done after every sleep pending a thorough  	   check of the logic of this change. -- jlc */  	/* don't stop on /dev/console */ -	if (file->f_op->write != redirected_tty_write && -	    current->signal->tty == tty) { -		if (!tty->pgrp) -			printk(KERN_ERR "n_tty_read: no tty->pgrp!\n"); -		else if (task_pgrp(current) != tty->pgrp) { -			if (is_ignored(SIGTTIN) || -			    is_current_pgrp_orphaned()) -				return -EIO; -			kill_pgrp(task_pgrp(current), SIGTTIN, 1); -			set_thread_flag(TIF_SIGPENDING); -			return -ERESTARTSYS; -		} +	if (file->f_op->write == redirected_tty_write || +	    current->signal->tty != tty) +		return 0; + +	spin_lock_irq(&tty->ctrl_lock); +	if (!tty->pgrp) +		printk(KERN_ERR "n_tty_read: no tty->pgrp!\n"); +	else if (task_pgrp(current) != tty->pgrp) { +		spin_unlock_irq(&tty->ctrl_lock); +		if (is_ignored(SIGTTIN) || is_current_pgrp_orphaned()) +			return -EIO; +		kill_pgrp(task_pgrp(current), SIGTTIN, 1); +		set_thread_flag(TIF_SIGPENDING); +		return -ERESTARTSYS;  	} +	spin_unlock_irq(&tty->ctrl_lock);  	return 0;  } @@ -1959,10 +1950,17 @@ do_it_again:  		 * longer than TTY_THRESHOLD_UNTHROTTLE in canonical mode,  		 * we won't get any more characters.  		 */ -		if (n_tty_chars_in_buffer(tty) <= TTY_THRESHOLD_UNTHROTTLE) { +		while (1) { +			tty_set_flow_change(tty, TTY_UNTHROTTLE_SAFE); +			if (n_tty_chars_in_buffer(tty) > TTY_THRESHOLD_UNTHROTTLE) +				break; +			if (!tty->count) +				break;  			n_tty_set_room(tty); -			check_unthrottle(tty); +			if (!tty_unthrottle_safe(tty)) +				break;  		} +		__tty_set_flow_change(tty, 0);  		if (b - buf >= minimum)  			break; diff --git a/drivers/tty/nozomi.c b/drivers/tty/nozomi.c index 2dff1979615..d6080c3831e 100644 --- a/drivers/tty/nozomi.c +++ b/drivers/tty/nozomi.c @@ -791,7 +791,6 @@ static int send_data(enum port_type index, struct nozomi *dc)  	const u8 toggle = port->toggle_ul;  	void __iomem *addr = port->ul_addr[toggle];  	const u32 ul_size = port->ul_size[toggle]; -	struct tty_struct *tty = tty_port_tty_get(&port->port);  	/* Get data from tty and place in buf for now */  	size = kfifo_out(&port->fifo_ul, dc->send_buf, @@ -799,7 +798,6 @@ static int send_data(enum port_type index, struct nozomi *dc)  	if (size == 0) {  		DBG4("No more data to send, disable link:"); -		tty_kref_put(tty);  		return 0;  	} @@ -809,10 +807,8 @@ static int send_data(enum port_type index, struct nozomi *dc)  	write_mem32(addr, (u32 *) &size, 4);  	write_mem32(addr + 4, (u32 *) dc->send_buf, size); -	if (tty) -		tty_wakeup(tty); +	tty_port_tty_wakeup(&port->port); -	tty_kref_put(tty);  	return 1;  } @@ -1505,12 +1501,9 @@ static void tty_exit(struct nozomi *dc)  	DBG1(" "); -	for (i = 0; i < MAX_PORT; ++i) { -		struct tty_struct *tty = tty_port_tty_get(&dc->port[i].port); -		if (tty && list_empty(&tty->hangup_work.entry)) -			tty_hangup(tty); -		tty_kref_put(tty); -	} +	for (i = 0; i < MAX_PORT; ++i) +		tty_port_tty_hangup(&dc->port[i].port, false); +  	/* Racy below - surely should wait for scheduled work to be done or  	   complete off a hangup method ? */  	while (dc->open_ttys) diff --git a/drivers/tty/pty.c b/drivers/tty/pty.c index c24b4db243b..71e456aa636 100644 --- a/drivers/tty/pty.c +++ b/drivers/tty/pty.c @@ -413,7 +413,6 @@ static void pty_unix98_shutdown(struct tty_struct *tty)  static void pty_cleanup(struct tty_struct *tty)  { -	tty->port->itty = NULL;  	tty_port_put(tty->port);  } diff --git a/drivers/tty/rocket.c b/drivers/tty/rocket.c index 1d270034bfc..f5abc288882 100644 --- a/drivers/tty/rocket.c +++ b/drivers/tty/rocket.c @@ -449,7 +449,7 @@ static void rp_do_transmit(struct r_port *info)  	/*  Loop sending data to FIFO until done or FIFO full */  	while (1) { -		if (tty->stopped || tty->hw_stopped) +		if (tty->stopped)  			break;  		c = min(info->xmit_fifo_room, info->xmit_cnt);  		c = min(c, XMIT_BUF_SIZE - info->xmit_tail); @@ -521,15 +521,10 @@ static void rp_handle_port(struct r_port *info)  		       (ChanStatus & CD_ACT) ? "on" : "off");  #endif  		if (!(ChanStatus & CD_ACT) && info->cd_status) { -			struct tty_struct *tty;  #ifdef ROCKET_DEBUG_HANGUP  			printk(KERN_INFO "CD drop, calling hangup.\n");  #endif -			tty = tty_port_tty_get(&info->port); -			if (tty) { -				tty_hangup(tty); -				tty_kref_put(tty); -			} +			tty_port_tty_hangup(&info->port, false);  		}  		info->cd_status = (ChanStatus & CD_ACT) ? 1 : 0;  		wake_up_interruptible(&info->port.open_wait); @@ -1111,15 +1106,12 @@ static void rp_set_termios(struct tty_struct *tty,  	/* Handle transition away from B0 status */  	if (!(old_termios->c_cflag & CBAUD) && (tty->termios.c_cflag & CBAUD)) { -		if (!tty->hw_stopped || !(tty->termios.c_cflag & CRTSCTS)) -			sSetRTS(cp); +		sSetRTS(cp);  		sSetDTR(cp);  	} -	if ((old_termios->c_cflag & CRTSCTS) && !(tty->termios.c_cflag & CRTSCTS)) { -		tty->hw_stopped = 0; +	if ((old_termios->c_cflag & CRTSCTS) && !(tty->termios.c_cflag & CRTSCTS))  		rp_start(tty); -	}  }  static int rp_break(struct tty_struct *tty, int break_state) @@ -1575,10 +1567,10 @@ static int rp_put_char(struct tty_struct *tty, unsigned char ch)  	spin_lock_irqsave(&info->slock, flags);  	cp = &info->channel; -	if (!tty->stopped && !tty->hw_stopped && info->xmit_fifo_room == 0) +	if (!tty->stopped && info->xmit_fifo_room == 0)  		info->xmit_fifo_room = TXFIFO_SIZE - sGetTxCnt(cp); -	if (tty->stopped || tty->hw_stopped || info->xmit_fifo_room == 0 || info->xmit_cnt != 0) { +	if (tty->stopped || info->xmit_fifo_room == 0 || info->xmit_cnt != 0) {  		info->xmit_buf[info->xmit_head++] = ch;  		info->xmit_head &= XMIT_BUF_SIZE - 1;  		info->xmit_cnt++; @@ -1619,14 +1611,14 @@ static int rp_write(struct tty_struct *tty,  #endif  	cp = &info->channel; -	if (!tty->stopped && !tty->hw_stopped && info->xmit_fifo_room < count) +	if (!tty->stopped && info->xmit_fifo_room < count)  		info->xmit_fifo_room = TXFIFO_SIZE - sGetTxCnt(cp);          /*  	 *  If the write queue for the port is empty, and there is FIFO space, stuff bytes   	 *  into FIFO.  Use the write queue for temp storage.           */ -	if (!tty->stopped && !tty->hw_stopped && info->xmit_cnt == 0 && info->xmit_fifo_room > 0) { +	if (!tty->stopped && info->xmit_cnt == 0 && info->xmit_fifo_room > 0) {  		c = min(count, info->xmit_fifo_room);  		b = buf; @@ -1674,7 +1666,7 @@ static int rp_write(struct tty_struct *tty,  		retval += c;  	} -	if ((retval > 0) && !tty->stopped && !tty->hw_stopped) +	if ((retval > 0) && !tty->stopped)  		set_bit((info->aiop * 8) + info->chan, (void *) &xmit_flags[info->board]);  end: diff --git a/drivers/tty/serial/68328serial.c b/drivers/tty/serial/68328serial.c index 49399470794..ef2e08e9b59 100644 --- a/drivers/tty/serial/68328serial.c +++ b/drivers/tty/serial/68328serial.c @@ -630,8 +630,7 @@ static void rs_flush_chars(struct tty_struct *tty)  	/* Enable transmitter */  	local_irq_save(flags); -	if (info->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped || -			!info->xmit_buf) { +	if (info->xmit_cnt <= 0 || tty->stopped || !info->xmit_buf) {  		local_irq_restore(flags);  		return;  	} @@ -697,7 +696,7 @@ static int rs_write(struct tty_struct * tty,  		total += c;  	} -	if (info->xmit_cnt && !tty->stopped && !tty->hw_stopped) { +	if (info->xmit_cnt && !tty->stopped) {  		/* Enable transmitter */  		local_irq_disable();		  #ifndef USE_INTS @@ -978,10 +977,8 @@ static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios)  	change_speed(info, tty);  	if ((old_termios->c_cflag & CRTSCTS) && -	    !(tty->termios.c_cflag & CRTSCTS)) { -		tty->hw_stopped = 0; +	    !(tty->termios.c_cflag & CRTSCTS))  		rs_start(tty); -	}  } diff --git a/drivers/tty/serial/8250/8250.h b/drivers/tty/serial/8250/8250.h index 34eb676916f..1ebf8538b4f 100644 --- a/drivers/tty/serial/8250/8250.h +++ b/drivers/tty/serial/8250/8250.h @@ -117,13 +117,6 @@ static inline void serial_dl_write(struct uart_8250_port *up, int value)   * is cleared, the machine locks up with endless interrupts.   */  #define ALPHA_KLUDGE_MCR  (UART_MCR_OUT2 | UART_MCR_OUT1) -#elif defined(CONFIG_SBC8560) -/* - * WindRiver did something similarly broken on their SBC8560 board. The - * UART tristates its IRQ output while OUT2 is clear, but they pulled - * the interrupt line _up_ instead of down, so if we register the IRQ - * while the UART is in that state, we die in an IRQ storm. */ -#define ALPHA_KLUDGE_MCR (UART_MCR_OUT2)  #else  #define ALPHA_KLUDGE_MCR 0  #endif diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c index 35f9c96aada..46528d57be7 100644 --- a/drivers/tty/serial/8250/8250_core.c +++ b/drivers/tty/serial/8250/8250_core.c @@ -2755,7 +2755,7 @@ static void __init serial8250_isa_init_ports(void)  	if (nr_uarts > UART_NR)  		nr_uarts = UART_NR; -	for (i = 0; i < nr_uarts; i++) { +	for (i = 0; i < UART_NR; i++) {  		struct uart_8250_port *up = &serial8250_ports[i];  		struct uart_port *port = &up->port; @@ -2916,7 +2916,7 @@ static int __init serial8250_console_setup(struct console *co, char *options)  	 * if so, search for the first available port that does have  	 * console support.  	 */ -	if (co->index >= nr_uarts) +	if (co->index >= UART_NR)  		co->index = 0;  	port = &serial8250_ports[co->index].port;  	if (!port->iobase && !port->membase) @@ -2957,7 +2957,7 @@ int serial8250_find_port(struct uart_port *p)  	int line;  	struct uart_port *port; -	for (line = 0; line < nr_uarts; line++) { +	for (line = 0; line < UART_NR; line++) {  		port = &serial8250_ports[line].port;  		if (uart_match_port(p, port))  			return line; @@ -3110,7 +3110,7 @@ static int serial8250_remove(struct platform_device *dev)  {  	int i; -	for (i = 0; i < nr_uarts; i++) { +	for (i = 0; i < UART_NR; i++) {  		struct uart_8250_port *up = &serial8250_ports[i];  		if (up->port.dev == &dev->dev) @@ -3178,7 +3178,7 @@ static struct uart_8250_port *serial8250_find_match_or_unused(struct uart_port *  	/*  	 * First, find a port entry which matches.  	 */ -	for (i = 0; i < nr_uarts; i++) +	for (i = 0; i < UART_NR; i++)  		if (uart_match_port(&serial8250_ports[i].port, port))  			return &serial8250_ports[i]; @@ -3187,7 +3187,7 @@ static struct uart_8250_port *serial8250_find_match_or_unused(struct uart_port *  	 * free entry.  We look for one which hasn't been previously  	 * used (indicated by zero iobase).  	 */ -	for (i = 0; i < nr_uarts; i++) +	for (i = 0; i < UART_NR; i++)  		if (serial8250_ports[i].port.type == PORT_UNKNOWN &&  		    serial8250_ports[i].port.iobase == 0)  			return &serial8250_ports[i]; @@ -3196,7 +3196,7 @@ static struct uart_8250_port *serial8250_find_match_or_unused(struct uart_port *  	 * That also failed.  Last resort is to find any entry which  	 * doesn't have a real port associated with it.  	 */ -	for (i = 0; i < nr_uarts; i++) +	for (i = 0; i < UART_NR; i++)  		if (serial8250_ports[i].port.type == PORT_UNKNOWN)  			return &serial8250_ports[i]; @@ -3247,6 +3247,10 @@ int serial8250_register_8250_port(struct uart_8250_port *up)  		uart->tx_loadsz		= up->tx_loadsz;  		uart->capabilities	= up->capabilities; +		/* Take tx_loadsz from fifosize if it wasn't set separately */ +		if (uart->port.fifosize && !uart->tx_loadsz) +			uart->tx_loadsz = uart->port.fifosize; +  		if (up->port.dev)  			uart->port.dev = up->port.dev; diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c index db0e66f6dd0..3dedd2470db 100644 --- a/drivers/tty/serial/8250/8250_dw.c +++ b/drivers/tty/serial/8250/8250_dw.c @@ -26,6 +26,7 @@  #include <linux/platform_device.h>  #include <linux/slab.h>  #include <linux/acpi.h> +#include <linux/clk.h>  #include "8250.h" @@ -55,8 +56,9 @@  struct dw8250_data { -	int	last_lcr; -	int	line; +	int		last_lcr; +	int		line; +	struct clk	*clk;  };  static void dw8250_serial_out(struct uart_port *p, int offset, int value) @@ -136,8 +138,13 @@ static int dw8250_probe_of(struct uart_port *p)  	if (!of_property_read_u32(np, "reg-shift", &val))  		p->regshift = val; +	/* clock got configured through clk api, all done */ +	if (p->uartclk) +		return 0; + +	/* try to find out clock frequency from DT as fallback */  	if (of_property_read_u32(np, "clock-frequency", &val)) { -		dev_err(p->dev, "no clock-frequency property set\n"); +		dev_err(p->dev, "clk or clock-frequency not defined\n");  		return -EINVAL;  	}  	p->uartclk = val; @@ -294,9 +301,20 @@ static int dw8250_probe(struct platform_device *pdev)  	if (!uart.port.membase)  		return -ENOMEM; +	data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); +	if (!data) +		return -ENOMEM; + +	data->clk = devm_clk_get(&pdev->dev, NULL); +	if (!IS_ERR(data->clk)) { +		clk_prepare_enable(data->clk); +		uart.port.uartclk = clk_get_rate(data->clk); +	} +  	uart.port.iotype = UPIO_MEM;  	uart.port.serial_in = dw8250_serial_in;  	uart.port.serial_out = dw8250_serial_out; +	uart.port.private_data = data;  	dw8250_setup_port(&uart); @@ -312,12 +330,6 @@ static int dw8250_probe(struct platform_device *pdev)  		return -ENODEV;  	} -	data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); -	if (!data) -		return -ENOMEM; - -	uart.port.private_data = data; -  	data->line = serial8250_register_8250_port(&uart);  	if (data->line < 0)  		return data->line; @@ -333,6 +345,9 @@ static int dw8250_remove(struct platform_device *pdev)  	serial8250_unregister_port(data->line); +	if (!IS_ERR(data->clk)) +		clk_disable_unprepare(data->clk); +  	return 0;  } diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c index 3ea5408fcbe..b031abf43a7 100644 --- a/drivers/tty/serial/amba-pl011.c +++ b/drivers/tty/serial/amba-pl011.c @@ -29,6 +29,7 @@   * and hooked into this driver.   */ +  #if defined(CONFIG_SERIAL_AMBA_PL011_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)  #define SUPPORT_SYSRQ  #endif @@ -117,6 +118,12 @@ struct pl011_dmarx_data {  	struct pl011_sgbuf	sgbuf_b;  	dma_cookie_t		cookie;  	bool			running; +	struct timer_list	timer; +	unsigned int last_residue; +	unsigned long last_jiffies; +	bool auto_poll_rate; +	unsigned int poll_rate; +	unsigned int poll_timeout;  };  struct pl011_dmatx_data { @@ -223,16 +230,18 @@ static int pl011_fifo_to_tty(struct uart_amba_port *uap)  static int pl011_sgbuf_init(struct dma_chan *chan, struct pl011_sgbuf *sg,  	enum dma_data_direction dir)  { -	sg->buf = kmalloc(PL011_DMA_BUFFER_SIZE, GFP_KERNEL); +	dma_addr_t dma_addr; + +	sg->buf = dma_alloc_coherent(chan->device->dev, +		PL011_DMA_BUFFER_SIZE, &dma_addr, GFP_KERNEL);  	if (!sg->buf)  		return -ENOMEM; -	sg_init_one(&sg->sg, sg->buf, PL011_DMA_BUFFER_SIZE); +	sg_init_table(&sg->sg, 1); +	sg_set_page(&sg->sg, phys_to_page(dma_addr), +		PL011_DMA_BUFFER_SIZE, offset_in_page(dma_addr)); +	sg_dma_address(&sg->sg) = dma_addr; -	if (dma_map_sg(chan->device->dev, &sg->sg, 1, dir) != 1) { -		kfree(sg->buf); -		return -EINVAL; -	}  	return 0;  } @@ -240,8 +249,9 @@ static void pl011_sgbuf_free(struct dma_chan *chan, struct pl011_sgbuf *sg,  	enum dma_data_direction dir)  {  	if (sg->buf) { -		dma_unmap_sg(chan->device->dev, &sg->sg, 1, dir); -		kfree(sg->buf); +		dma_free_coherent(chan->device->dev, +			PL011_DMA_BUFFER_SIZE, sg->buf, +			sg_dma_address(&sg->sg));  	}  } @@ -300,6 +310,29 @@ static void pl011_dma_probe_initcall(struct uart_amba_port *uap)  		dmaengine_slave_config(chan, &rx_conf);  		uap->dmarx.chan = chan; +		if (plat->dma_rx_poll_enable) { +			/* Set poll rate if specified. */ +			if (plat->dma_rx_poll_rate) { +				uap->dmarx.auto_poll_rate = false; +				uap->dmarx.poll_rate = plat->dma_rx_poll_rate; +			} else { +				/* +				 * 100 ms defaults to poll rate if not +				 * specified. This will be adjusted with +				 * the baud rate at set_termios. +				 */ +				uap->dmarx.auto_poll_rate = true; +				uap->dmarx.poll_rate =  100; +			} +			/* 3 secs defaults poll_timeout if not specified. */ +			if (plat->dma_rx_poll_timeout) +				uap->dmarx.poll_timeout = +					plat->dma_rx_poll_timeout; +			else +				uap->dmarx.poll_timeout = 3000; +		} else +			uap->dmarx.auto_poll_rate = false; +  		dev_info(uap->port.dev, "DMA channel RX %s\n",  			 dma_chan_name(uap->dmarx.chan));  	} @@ -701,24 +734,30 @@ static void pl011_dma_rx_chars(struct uart_amba_port *uap,  	struct tty_port *port = &uap->port.state->port;  	struct pl011_sgbuf *sgbuf = use_buf_b ?  		&uap->dmarx.sgbuf_b : &uap->dmarx.sgbuf_a; -	struct device *dev = uap->dmarx.chan->device->dev;  	int dma_count = 0;  	u32 fifotaken = 0; /* only used for vdbg() */ -	/* Pick everything from the DMA first */ +	struct pl011_dmarx_data *dmarx = &uap->dmarx; +	int dmataken = 0; + +	if (uap->dmarx.poll_rate) { +		/* The data can be taken by polling */ +		dmataken = sgbuf->sg.length - dmarx->last_residue; +		/* Recalculate the pending size */ +		if (pending >= dmataken) +			pending -= dmataken; +	} + +	/* Pick the remain data from the DMA */  	if (pending) { -		/* Sync in buffer */ -		dma_sync_sg_for_cpu(dev, &sgbuf->sg, 1, DMA_FROM_DEVICE);  		/*  		 * First take all chars in the DMA pipe, then look in the FIFO.  		 * Note that tty_insert_flip_buf() tries to take as many chars  		 * as it can.  		 */ -		dma_count = tty_insert_flip_string(port, sgbuf->buf, pending); - -		/* Return buffer to device */ -		dma_sync_sg_for_device(dev, &sgbuf->sg, 1, DMA_FROM_DEVICE); +		dma_count = tty_insert_flip_string(port, sgbuf->buf + dmataken, +				pending);  		uap->port.icount.rx += dma_count;  		if (dma_count < pending) @@ -726,6 +765,10 @@ static void pl011_dma_rx_chars(struct uart_amba_port *uap,  				 "couldn't insert all characters (TTY is full?)\n");  	} +	/* Reset the last_residue for Rx DMA poll */ +	if (uap->dmarx.poll_rate) +		dmarx->last_residue = sgbuf->sg.length; +  	/*  	 * Only continue with trying to read the FIFO if all DMA chars have  	 * been taken first. @@ -865,6 +908,57 @@ static inline void pl011_dma_rx_stop(struct uart_amba_port *uap)  	writew(uap->dmacr, uap->port.membase + UART011_DMACR);  } +/* + * Timer handler for Rx DMA polling. + * Every polling, It checks the residue in the dma buffer and transfer + * data to the tty. Also, last_residue is updated for the next polling. + */ +static void pl011_dma_rx_poll(unsigned long args) +{ +	struct uart_amba_port *uap = (struct uart_amba_port *)args; +	struct tty_port *port = &uap->port.state->port; +	struct pl011_dmarx_data *dmarx = &uap->dmarx; +	struct dma_chan *rxchan = uap->dmarx.chan; +	unsigned long flags = 0; +	unsigned int dmataken = 0; +	unsigned int size = 0; +	struct pl011_sgbuf *sgbuf; +	int dma_count; +	struct dma_tx_state state; + +	sgbuf = dmarx->use_buf_b ? &uap->dmarx.sgbuf_b : &uap->dmarx.sgbuf_a; +	rxchan->device->device_tx_status(rxchan, dmarx->cookie, &state); +	if (likely(state.residue < dmarx->last_residue)) { +		dmataken = sgbuf->sg.length - dmarx->last_residue; +		size = dmarx->last_residue - state.residue; +		dma_count = tty_insert_flip_string(port, sgbuf->buf + dmataken, +				size); +		if (dma_count == size) +			dmarx->last_residue =  state.residue; +		dmarx->last_jiffies = jiffies; +	} +	tty_flip_buffer_push(port); + +	/* +	 * If no data is received in poll_timeout, the driver will fall back +	 * to interrupt mode. We will retrigger DMA at the first interrupt. +	 */ +	if (jiffies_to_msecs(jiffies - dmarx->last_jiffies) +			> uap->dmarx.poll_timeout) { + +		spin_lock_irqsave(&uap->port.lock, flags); +		pl011_dma_rx_stop(uap); +		spin_unlock_irqrestore(&uap->port.lock, flags); + +		uap->dmarx.running = false; +		dmaengine_terminate_all(rxchan); +		del_timer(&uap->dmarx.timer); +	} else { +		mod_timer(&uap->dmarx.timer, +			jiffies + msecs_to_jiffies(uap->dmarx.poll_rate)); +	} +} +  static void pl011_dma_startup(struct uart_amba_port *uap)  {  	int ret; @@ -927,6 +1021,16 @@ skip_rx:  		if (pl011_dma_rx_trigger_dma(uap))  			dev_dbg(uap->port.dev, "could not trigger initial "  				"RX DMA job, fall back to interrupt mode\n"); +		if (uap->dmarx.poll_rate) { +			init_timer(&(uap->dmarx.timer)); +			uap->dmarx.timer.function = pl011_dma_rx_poll; +			uap->dmarx.timer.data = (unsigned long)uap; +			mod_timer(&uap->dmarx.timer, +				jiffies + +				msecs_to_jiffies(uap->dmarx.poll_rate)); +			uap->dmarx.last_residue = PL011_DMA_BUFFER_SIZE; +			uap->dmarx.last_jiffies = jiffies; +		}  	}  } @@ -962,6 +1066,8 @@ static void pl011_dma_shutdown(struct uart_amba_port *uap)  		/* Clean up the RX DMA */  		pl011_sgbuf_free(uap->dmarx.chan, &uap->dmarx.sgbuf_a, DMA_FROM_DEVICE);  		pl011_sgbuf_free(uap->dmarx.chan, &uap->dmarx.sgbuf_b, DMA_FROM_DEVICE); +		if (uap->dmarx.poll_rate) +			del_timer_sync(&uap->dmarx.timer);  		uap->using_rx_dma = false;  	}  } @@ -976,7 +1082,6 @@ static inline bool pl011_dma_rx_running(struct uart_amba_port *uap)  	return uap->using_rx_dma && uap->dmarx.running;  } -  #else  /* Blank functions if the DMA engine is not available */  static inline void pl011_dma_probe(struct uart_amba_port *uap) @@ -1088,8 +1193,18 @@ static void pl011_rx_chars(struct uart_amba_port *uap)  			dev_dbg(uap->port.dev, "could not trigger RX DMA job "  				"fall back to interrupt mode again\n");  			uap->im |= UART011_RXIM; -		} else +		} else {  			uap->im &= ~UART011_RXIM; +			/* Start Rx DMA poll */ +			if (uap->dmarx.poll_rate) { +				uap->dmarx.last_jiffies = jiffies; +				uap->dmarx.last_residue	= PL011_DMA_BUFFER_SIZE; +				mod_timer(&uap->dmarx.timer, +					jiffies + +					msecs_to_jiffies(uap->dmarx.poll_rate)); +			} +		} +  		writew(uap->im, uap->port.membase + UART011_IMSC);  	}  	spin_lock(&uap->port.lock); @@ -1164,7 +1279,6 @@ static irqreturn_t pl011_int(int irq, void *dev_id)  	unsigned int dummy_read;  	spin_lock_irqsave(&uap->port.lock, flags); -  	status = readw(uap->port.membase + UART011_MIS);  	if (status) {  		do { @@ -1551,6 +1665,11 @@ pl011_set_termios(struct uart_port *port, struct ktermios *termios,  	 */  	baud = uart_get_baud_rate(port, termios, old, 0,  				  port->uartclk / clkdiv); +	/* +	 * Adjust RX DMA polling rate with baud rate if not specified. +	 */ +	if (uap->dmarx.auto_poll_rate) +		uap->dmarx.poll_rate = DIV_ROUND_UP(10000000, baud);  	if (baud > port->uartclk/16)  		quot = DIV_ROUND_CLOSEST(port->uartclk * 8, baud); diff --git a/drivers/tty/serial/arc_uart.c b/drivers/tty/serial/arc_uart.c index d97e194b6bc..cbf1d155b7b 100644 --- a/drivers/tty/serial/arc_uart.c +++ b/drivers/tty/serial/arc_uart.c @@ -162,7 +162,7 @@ static unsigned int arc_serial_tx_empty(struct uart_port *port)  /*   * Driver internal routine, used by both tty(serial core) as well as tx-isr   *  -Called under spinlock in either cases - *  -also tty->stopped / tty->hw_stopped has already been checked + *  -also tty->stopped has already been checked   *     = by uart_start( ) before calling us   *     = tx_ist checks that too before calling   */ diff --git a/drivers/tty/serial/bfin_uart.c b/drivers/tty/serial/bfin_uart.c index 12dceda9db3..26a3be7ced7 100644 --- a/drivers/tty/serial/bfin_uart.c +++ b/drivers/tty/serial/bfin_uart.c @@ -1011,24 +1011,6 @@ static int bfin_serial_poll_get_char(struct uart_port *port)  }  #endif -#if defined(CONFIG_KGDB_SERIAL_CONSOLE) || \ -	defined(CONFIG_KGDB_SERIAL_CONSOLE_MODULE) -static void bfin_kgdboc_port_shutdown(struct uart_port *port) -{ -	if (kgdboc_break_enabled) { -		kgdboc_break_enabled = 0; -		bfin_serial_shutdown(port); -	} -} - -static int bfin_kgdboc_port_startup(struct uart_port *port) -{ -	kgdboc_port_line = port->line; -	kgdboc_break_enabled = !bfin_serial_startup(port); -	return 0; -} -#endif -  static struct uart_ops bfin_serial_pops = {  	.tx_empty	= bfin_serial_tx_empty,  	.set_mctrl	= bfin_serial_set_mctrl, @@ -1047,11 +1029,6 @@ static struct uart_ops bfin_serial_pops = {  	.request_port	= bfin_serial_request_port,  	.config_port	= bfin_serial_config_port,  	.verify_port	= bfin_serial_verify_port, -#if defined(CONFIG_KGDB_SERIAL_CONSOLE) || \ -	defined(CONFIG_KGDB_SERIAL_CONSOLE_MODULE) -	.kgdboc_port_startup	= bfin_kgdboc_port_startup, -	.kgdboc_port_shutdown	= bfin_kgdboc_port_shutdown, -#endif  #ifdef CONFIG_CONSOLE_POLL  	.poll_put_char	= bfin_serial_poll_put_char,  	.poll_get_char	= bfin_serial_poll_get_char, diff --git a/drivers/tty/serial/crisv10.c b/drivers/tty/serial/crisv10.c index 5f37c31e32b..477f22f773f 100644 --- a/drivers/tty/serial/crisv10.c +++ b/drivers/tty/serial/crisv10.c @@ -169,7 +169,6 @@ static int get_lsr_info(struct e100_serial *info, unsigned int *value);  #define DEF_BAUD 115200   /* 115.2 kbit/s */ -#define STD_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST)  #define DEF_RX 0x20  /* or SERIAL_CTRL_W >> 8 */  /* Default value of tx_ctrl register: has txd(bit 7)=1 (idle) as default */  #define DEF_TX 0x80  /* or SERIAL_CTRL_B */ @@ -246,7 +245,6 @@ static struct e100_serial rs_table[] = {  	  .ifirstadr   = R_DMA_CH7_FIRST,  	  .icmdadr     = R_DMA_CH7_CMD,  	  .idescradr   = R_DMA_CH7_DESCR, -	  .flags       = STD_FLAGS,  	  .rx_ctrl     = DEF_RX,  	  .tx_ctrl     = DEF_TX,  	  .iseteop     = 2, @@ -300,7 +298,6 @@ static struct e100_serial rs_table[] = {  	  .ifirstadr   = R_DMA_CH9_FIRST,  	  .icmdadr     = R_DMA_CH9_CMD,  	  .idescradr   = R_DMA_CH9_DESCR, -	  .flags       = STD_FLAGS,  	  .rx_ctrl     = DEF_RX,  	  .tx_ctrl     = DEF_TX,  	  .iseteop     = 3, @@ -356,7 +353,6 @@ static struct e100_serial rs_table[] = {  	  .ifirstadr   = R_DMA_CH3_FIRST,  	  .icmdadr     = R_DMA_CH3_CMD,  	  .idescradr   = R_DMA_CH3_DESCR, -	  .flags       = STD_FLAGS,  	  .rx_ctrl     = DEF_RX,  	  .tx_ctrl     = DEF_TX,  	  .iseteop     = 0, @@ -410,7 +406,6 @@ static struct e100_serial rs_table[] = {  	  .ifirstadr   = R_DMA_CH5_FIRST,  	  .icmdadr     = R_DMA_CH5_CMD,  	  .idescradr   = R_DMA_CH5_DESCR, -	  .flags       = STD_FLAGS,  	  .rx_ctrl     = DEF_RX,  	  .tx_ctrl     = DEF_TX,  	  .iseteop     = 1, @@ -2263,8 +2258,7 @@ TODO: The break will be delayed until an F or V character is received.  */ -static -struct e100_serial * handle_ser_rx_interrupt_no_dma(struct e100_serial *info) +static void handle_ser_rx_interrupt_no_dma(struct e100_serial *info)  {  	unsigned long data_read; @@ -2370,10 +2364,9 @@ more_data:  	}  	tty_flip_buffer_push(&info->port); -	return info;  } -static struct e100_serial* handle_ser_rx_interrupt(struct e100_serial *info) +static void handle_ser_rx_interrupt(struct e100_serial *info)  {  	unsigned char rstat; @@ -2382,7 +2375,8 @@ static struct e100_serial* handle_ser_rx_interrupt(struct e100_serial *info)  #endif  /*	DEBUG_LOG(info->line, "ser_interrupt stat %03X\n", rstat | (i << 8)); */  	if (!info->uses_dma_in) { -		return handle_ser_rx_interrupt_no_dma(info); +		handle_ser_rx_interrupt_no_dma(info); +		return;  	}  	/* DMA is used */  	rstat = info->ioport[REG_STATUS]; @@ -2489,7 +2483,6 @@ static struct e100_serial* handle_ser_rx_interrupt(struct e100_serial *info)  	/* Restarting the DMA never hurts */  	*info->icmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, restart);  	START_FLUSH_FAST_TIMER(info, "ser_int"); -	return info;  } /* handle_ser_rx_interrupt */  static void handle_ser_tx_interrupt(struct e100_serial *info) @@ -2534,8 +2527,7 @@ static void handle_ser_tx_interrupt(struct e100_serial *info)  	}  	/* Normal char-by-char interrupt */  	if (info->xmit.head == info->xmit.tail -	    || info->port.tty->stopped -	    || info->port.tty->hw_stopped) { +	    || info->port.tty->stopped) {  		DFLOW(DEBUG_LOG(info->line, "tx_int: stopped %i\n",  				info->port.tty->stopped));  		e100_disable_serial_tx_ready_irq(info); @@ -2722,7 +2714,7 @@ startup(struct e100_serial * info)  	/* if it was already initialized, skip this */ -	if (info->flags & ASYNC_INITIALIZED) { +	if (info->port.flags & ASYNC_INITIALIZED) {  		local_irq_restore(flags);  		free_page(xmit_page);  		return 0; @@ -2847,7 +2839,7 @@ startup(struct e100_serial * info)  #endif /* CONFIG_SVINTO_SIM */ -	info->flags |= ASYNC_INITIALIZED; +	info->port.flags |= ASYNC_INITIALIZED;  	local_irq_restore(flags);  	return 0; @@ -2892,7 +2884,7 @@ shutdown(struct e100_serial * info)  #endif /* CONFIG_SVINTO_SIM */ -	if (!(info->flags & ASYNC_INITIALIZED)) +	if (!(info->port.flags & ASYNC_INITIALIZED))  		return;  #ifdef SERIAL_DEBUG_OPEN @@ -2923,7 +2915,7 @@ shutdown(struct e100_serial * info)  	if (info->port.tty)  		set_bit(TTY_IO_ERROR, &info->port.tty->flags); -	info->flags &= ~ASYNC_INITIALIZED; +	info->port.flags &= ~ASYNC_INITIALIZED;  	local_irq_restore(flags);  } @@ -2948,7 +2940,7 @@ change_speed(struct e100_serial *info)  	/* possibly, the tx/rx should be disabled first to do this safely */  	/* change baud-rate and write it to the hardware */ -	if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST) { +	if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST) {  		/* Special baudrate */  		u32 mask = 0xFF << (info->line*8); /* Each port has 8 bits */  		unsigned long alt_source = @@ -3098,7 +3090,6 @@ rs_flush_chars(struct tty_struct *tty)  	if (info->tr_running ||  	    info->xmit.head == info->xmit.tail ||  	    tty->stopped || -	    tty->hw_stopped ||  	    !info->xmit.buf)  		return; @@ -3176,7 +3167,6 @@ static int rs_raw_write(struct tty_struct *tty,  	if (info->xmit.head != info->xmit.tail &&  	    !tty->stopped && -	    !tty->hw_stopped &&  	    !info->tr_running) {  		start_transmit(info);  	} @@ -3400,10 +3390,10 @@ get_serial_info(struct e100_serial * info,  	tmp.line = info->line;  	tmp.port = (int)info->ioport;  	tmp.irq = info->irq; -	tmp.flags = info->flags; +	tmp.flags = info->port.flags;  	tmp.baud_base = info->baud_base; -	tmp.close_delay = info->close_delay; -	tmp.closing_wait = info->closing_wait; +	tmp.close_delay = info->port.close_delay; +	tmp.closing_wait = info->port.closing_wait;  	tmp.custom_divisor = info->custom_divisor;  	if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))  		return -EFAULT; @@ -3425,16 +3415,16 @@ set_serial_info(struct e100_serial *info,  	if (!capable(CAP_SYS_ADMIN)) {  		if ((new_serial.type != info->type) || -		    (new_serial.close_delay != info->close_delay) || +		    (new_serial.close_delay != info->port.close_delay) ||  		    ((new_serial.flags & ~ASYNC_USR_MASK) != -		     (info->flags & ~ASYNC_USR_MASK))) +		     (info->port.flags & ~ASYNC_USR_MASK)))  			return -EPERM; -		info->flags = ((info->flags & ~ASYNC_USR_MASK) | +		info->port.flags = ((info->port.flags & ~ASYNC_USR_MASK) |  			       (new_serial.flags & ASYNC_USR_MASK));  		goto check_and_exit;  	} -	if (info->count > 1) +	if (info->port.count > 1)  		return -EBUSY;  	/* @@ -3443,16 +3433,16 @@ set_serial_info(struct e100_serial *info,  	 */  	info->baud_base = new_serial.baud_base; -	info->flags = ((info->flags & ~ASYNC_FLAGS) | +	info->port.flags = ((info->port.flags & ~ASYNC_FLAGS) |  		       (new_serial.flags & ASYNC_FLAGS));  	info->custom_divisor = new_serial.custom_divisor;  	info->type = new_serial.type; -	info->close_delay = new_serial.close_delay; -	info->closing_wait = new_serial.closing_wait; -	info->port.low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0; +	info->port.close_delay = new_serial.close_delay; +	info->port.closing_wait = new_serial.closing_wait; +	info->port.low_latency = (info->port.flags & ASYNC_LOW_LATENCY) ? 1 : 0;   check_and_exit: -	if (info->flags & ASYNC_INITIALIZED) { +	if (info->port.flags & ASYNC_INITIALIZED) {  		change_speed(info);  	} else  		retval = startup(info); @@ -3733,10 +3723,8 @@ rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios)  	/* Handle turning off CRTSCTS */  	if ((old_termios->c_cflag & CRTSCTS) && -	    !(tty->termios.c_cflag & CRTSCTS)) { -		tty->hw_stopped = 0; +	    !(tty->termios.c_cflag & CRTSCTS))  		rs_start(tty); -	}  } @@ -3772,7 +3760,7 @@ rs_close(struct tty_struct *tty, struct file * filp)  	printk("[%d] rs_close ttyS%d, count = %d\n", current->pid,  	       info->line, info->count);  #endif -	if ((tty->count == 1) && (info->count != 1)) { +	if ((tty->count == 1) && (info->port.count != 1)) {  		/*  		 * Uh, oh.  tty->count is 1, which means that the tty  		 * structure will be freed.  Info->count should always @@ -3782,32 +3770,32 @@ rs_close(struct tty_struct *tty, struct file * filp)  		 */  		printk(KERN_ERR  		       "rs_close: bad serial port count; tty->count is 1, " -		       "info->count is %d\n", info->count); -		info->count = 1; +		       "info->count is %d\n", info->port.count); +		info->port.count = 1;  	} -	if (--info->count < 0) { +	if (--info->port.count < 0) {  		printk(KERN_ERR "rs_close: bad serial port count for ttyS%d: %d\n", -		       info->line, info->count); -		info->count = 0; +		       info->line, info->port.count); +		info->port.count = 0;  	} -	if (info->count) { +	if (info->port.count) {  		local_irq_restore(flags);  		return;  	} -	info->flags |= ASYNC_CLOSING; +	info->port.flags |= ASYNC_CLOSING;  	/*  	 * Save the termios structure, since this port may have  	 * separate termios for callout and dialin.  	 */ -	if (info->flags & ASYNC_NORMAL_ACTIVE) +	if (info->port.flags & ASYNC_NORMAL_ACTIVE)  		info->normal_termios = tty->termios;  	/*  	 * 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 != ASYNC_CLOSING_WAIT_NONE) -		tty_wait_until_sent(tty, info->closing_wait); +	if (info->port.closing_wait != ASYNC_CLOSING_WAIT_NONE) +		tty_wait_until_sent(tty, info->port.closing_wait);  	/*  	 * At this point we stop accepting input.  To do this, we  	 * disable the serial receiver and the DMA receive interrupt. @@ -3820,7 +3808,7 @@ rs_close(struct tty_struct *tty, struct file * filp)  	e100_disable_rx(info);  	e100_disable_rx_irq(info); -	if (info->flags & ASYNC_INITIALIZED) { +	if (info->port.flags & ASYNC_INITIALIZED) {  		/*  		 * Before we drop DTR, make sure the UART transmitter  		 * has completely drained; this is especially @@ -3836,13 +3824,13 @@ rs_close(struct tty_struct *tty, struct file * filp)  	tty->closing = 0;  	info->event = 0;  	info->port.tty = NULL; -	if (info->blocked_open) { -		if (info->close_delay) -			schedule_timeout_interruptible(info->close_delay); -		wake_up_interruptible(&info->open_wait); +	if (info->port.blocked_open) { +		if (info->port.close_delay) +			schedule_timeout_interruptible(info->port.close_delay); +		wake_up_interruptible(&info->port.open_wait);  	} -	info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING); -	wake_up_interruptible(&info->close_wait); +	info->port.flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING); +	wake_up_interruptible(&info->port.close_wait);  	local_irq_restore(flags);  	/* port closed */ @@ -3935,10 +3923,10 @@ rs_hangup(struct tty_struct *tty)  	rs_flush_buffer(tty);  	shutdown(info);  	info->event = 0; -	info->count = 0; -	info->flags &= ~ASYNC_NORMAL_ACTIVE; +	info->port.count = 0; +	info->port.flags &= ~ASYNC_NORMAL_ACTIVE;  	info->port.tty = NULL; -	wake_up_interruptible(&info->open_wait); +	wake_up_interruptible(&info->port.open_wait);  }  /* @@ -3960,11 +3948,11 @@ block_til_ready(struct tty_struct *tty, struct file * filp,  	 * until it's done, and then try again.  	 */  	if (tty_hung_up_p(filp) || -	    (info->flags & ASYNC_CLOSING)) { -		wait_event_interruptible_tty(tty, info->close_wait, -			!(info->flags & ASYNC_CLOSING)); +	    (info->port.flags & ASYNC_CLOSING)) { +		wait_event_interruptible_tty(tty, info->port.close_wait, +			!(info->port.flags & ASYNC_CLOSING));  #ifdef SERIAL_DO_RESTART -		if (info->flags & ASYNC_HUP_NOTIFY) +		if (info->port.flags & ASYNC_HUP_NOTIFY)  			return -EAGAIN;  		else  			return -ERESTARTSYS; @@ -3979,7 +3967,7 @@ block_til_ready(struct tty_struct *tty, struct file * filp,  	 */  	if ((filp->f_flags & O_NONBLOCK) ||  	    (tty->flags & (1 << TTY_IO_ERROR))) { -		info->flags |= ASYNC_NORMAL_ACTIVE; +		info->port.flags |= ASYNC_NORMAL_ACTIVE;  		return 0;  	} @@ -3990,23 +3978,23 @@ block_til_ready(struct tty_struct *tty, struct file * filp,  	/*  	 * 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 +	 * this loop, info->port.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); +	add_wait_queue(&info->port.open_wait, &wait);  #ifdef SERIAL_DEBUG_OPEN  	printk("block_til_ready before block: ttyS%d, count = %d\n", -	       info->line, info->count); +	       info->line, info->port.count);  #endif  	local_irq_save(flags);  	if (!tty_hung_up_p(filp)) {  		extra_count++; -		info->count--; +		info->port.count--;  	}  	local_irq_restore(flags); -	info->blocked_open++; +	info->port.blocked_open++;  	while (1) {  		local_irq_save(flags);  		/* assert RTS and DTR */ @@ -4015,9 +4003,9 @@ block_til_ready(struct tty_struct *tty, struct file * filp,  		local_irq_restore(flags);  		set_current_state(TASK_INTERRUPTIBLE);  		if (tty_hung_up_p(filp) || -		    !(info->flags & ASYNC_INITIALIZED)) { +		    !(info->port.flags & ASYNC_INITIALIZED)) {  #ifdef SERIAL_DO_RESTART -			if (info->flags & ASYNC_HUP_NOTIFY) +			if (info->port.flags & ASYNC_HUP_NOTIFY)  				retval = -EAGAIN;  			else  				retval = -ERESTARTSYS; @@ -4026,7 +4014,7 @@ block_til_ready(struct tty_struct *tty, struct file * filp,  #endif  			break;  		} -		if (!(info->flags & ASYNC_CLOSING) && do_clocal) +		if (!(info->port.flags & ASYNC_CLOSING) && do_clocal)  			/* && (do_clocal || DCD_IS_ASSERTED) */  			break;  		if (signal_pending(current)) { @@ -4035,24 +4023,24 @@ block_til_ready(struct tty_struct *tty, struct file * filp,  		}  #ifdef SERIAL_DEBUG_OPEN  		printk("block_til_ready blocking: ttyS%d, count = %d\n", -		       info->line, info->count); +		       info->line, info->port.count);  #endif  		tty_unlock(tty);  		schedule();  		tty_lock(tty);  	}  	set_current_state(TASK_RUNNING); -	remove_wait_queue(&info->open_wait, &wait); +	remove_wait_queue(&info->port.open_wait, &wait);  	if (extra_count) -		info->count++; -	info->blocked_open--; +		info->port.count++; +	info->port.blocked_open--;  #ifdef SERIAL_DEBUG_OPEN  	printk("block_til_ready after blocking: ttyS%d, count = %d\n", -	       info->line, info->count); +	       info->line, info->port.count);  #endif  	if (retval)  		return retval; -	info->flags |= ASYNC_NORMAL_ACTIVE; +	info->port.flags |= ASYNC_NORMAL_ACTIVE;  	return 0;  } @@ -4086,24 +4074,24 @@ rs_open(struct tty_struct *tty, struct file * filp)  #ifdef SERIAL_DEBUG_OPEN          printk("[%d] rs_open %s, count = %d\n", current->pid, tty->name, - 	       info->count); + 	       info->port.count);  #endif -	info->count++; +	info->port.count++;  	tty->driver_data = info;  	info->port.tty = tty; -	info->port.low_latency = !!(info->flags & ASYNC_LOW_LATENCY); +	info->port.low_latency = !!(info->port.flags & ASYNC_LOW_LATENCY);  	/*  	 * 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(tty, info->close_wait, -			!(info->flags & ASYNC_CLOSING)); +	    (info->port.flags & ASYNC_CLOSING)) { +		wait_event_interruptible_tty(tty, info->port.close_wait, +			!(info->port.flags & ASYNC_CLOSING));  #ifdef SERIAL_DO_RESTART -		return ((info->flags & ASYNC_HUP_NOTIFY) ? +		return ((info->port.flags & ASYNC_HUP_NOTIFY) ?  			-EAGAIN : -ERESTARTSYS);  #else  		return -EAGAIN; @@ -4113,7 +4101,7 @@ rs_open(struct tty_struct *tty, struct file * filp)  	/*  	 * If DMA is enabled try to allocate the irq's.  	 */ -	if (info->count == 1) { +	if (info->port.count == 1) {  		allocated_resources = 1;  		if (info->dma_in_enabled) {  			if (request_irq(info->dma_in_irq_nbr, @@ -4186,7 +4174,7 @@ rs_open(struct tty_struct *tty, struct file * filp)  		if (allocated_resources)  			deinit_port(info); -		/* FIXME Decrease count info->count here too? */ +		/* FIXME Decrease count info->port.count here too? */  		return retval;  	} @@ -4203,7 +4191,7 @@ rs_open(struct tty_struct *tty, struct file * filp)  		return retval;  	} -	if ((info->count == 1) && (info->flags & ASYNC_SPLIT_TERMIOS)) { +	if ((info->port.count == 1) && (info->port.flags & ASYNC_SPLIT_TERMIOS)) {  		tty->termios = info->normal_termios;  		change_speed(info);  	} @@ -4256,9 +4244,6 @@ static void seq_line_info(struct seq_file *m, struct e100_serial *info)  		if (info->port.tty->stopped)  			seq_printf(m, " stopped:%i",  				   (int)info->port.tty->stopped); -		if (info->port.tty->hw_stopped) -			seq_printf(m, " hw_stopped:%i", -				   (int)info->port.tty->hw_stopped);  	}  	{ @@ -4455,16 +4440,9 @@ static int __init rs_init(void)  		info->forced_eop = 0;  		info->baud_base = DEF_BAUD_BASE;  		info->custom_divisor = 0; -		info->flags = 0; -		info->close_delay = 5*HZ/10; -		info->closing_wait = 30*HZ;  		info->x_char = 0;  		info->event = 0; -		info->count = 0; -		info->blocked_open = 0;  		info->normal_termios = driver->init_termios; -		init_waitqueue_head(&info->open_wait); -		init_waitqueue_head(&info->close_wait);  		info->xmit.buf = NULL;  		info->xmit.tail = info->xmit.head = 0;  		info->first_recv_buffer = info->last_recv_buffer = NULL; diff --git a/drivers/tty/serial/crisv10.h b/drivers/tty/serial/crisv10.h index ea0beb46a10..7599014ae03 100644 --- a/drivers/tty/serial/crisv10.h +++ b/drivers/tty/serial/crisv10.h @@ -53,8 +53,6 @@ struct e100_serial {  	volatile u8 *icmdadr;		/* adr to R_DMA_CHx_CMD */  	volatile u32 *idescradr;	/* adr to R_DMA_CHx_DESCR */ -	int flags;	/* defined in tty.h */ -  	u8 rx_ctrl;	/* shadow for R_SERIALx_REC_CTRL */  	u8 tx_ctrl;	/* shadow for R_SERIALx_TR_CTRL */  	u8 iseteop;	/* bit number for R_SET_EOP for the input dma */ @@ -88,19 +86,10 @@ struct e100_serial {  	volatile int		tr_running; /* 1 if output is running */ -	struct tty_struct	*tty; -	int			read_status_mask; -	int			ignore_status_mask;  	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			type;  /* PORT_ETRAX */ -	int			count;	    /* # of fd on device */ -	int			blocked_open; /* # of blocked opens */  	struct circ_buf		xmit;  	struct etrax_recv_buffer *first_recv_buffer;  	struct etrax_recv_buffer *last_recv_buffer; @@ -110,9 +99,6 @@ struct e100_serial {  	struct work_struct	work;  	struct async_icount	icount;   /* error-statistics etc.*/  	struct ktermios		normal_termios; -	struct ktermios		callout_termios; -	wait_queue_head_t	open_wait; -	wait_queue_head_t	close_wait;  	unsigned long char_time_usec;       /* The time for 1 char, in usecs */  	unsigned long flush_time_usec;      /* How often we should flush */ diff --git a/drivers/tty/serial/icom.c b/drivers/tty/serial/icom.c index bc9e6b017b0..18ed5aebb16 100644 --- a/drivers/tty/serial/icom.c +++ b/drivers/tty/serial/icom.c @@ -1415,8 +1415,7 @@ static int icom_alloc_adapter(struct icom_adapter  	struct icom_adapter *cur_adapter_entry;  	struct list_head *tmp; -	icom_adapter = (struct icom_adapter *) -	    kzalloc(sizeof(struct icom_adapter), GFP_KERNEL); +	icom_adapter = kzalloc(sizeof(struct icom_adapter), GFP_KERNEL);  	if (!icom_adapter) {  		return -ENOMEM; diff --git a/drivers/tty/serial/ifx6x60.c b/drivers/tty/serial/ifx6x60.c index 68d7ce997ed..8b1534c424a 100644 --- a/drivers/tty/serial/ifx6x60.c +++ b/drivers/tty/serial/ifx6x60.c @@ -270,23 +270,6 @@ static void mrdy_assert(struct ifx_spi_device *ifx_dev)  }  /** - *	ifx_spi_hangup		-	hang up an IFX device - *	@ifx_dev: our SPI device - * - *	Hang up the tty attached to the IFX device if one is currently - *	open. If not take no action - */ -static void ifx_spi_ttyhangup(struct ifx_spi_device *ifx_dev) -{ -	struct tty_port *pport = &ifx_dev->tty_port; -	struct tty_struct *tty = tty_port_tty_get(pport); -	if (tty) { -		tty_hangup(tty); -		tty_kref_put(tty); -	} -} - -/**   *	ifx_spi_timeout		-	SPI timeout   *	@arg: our SPI device   * @@ -298,7 +281,7 @@ static void ifx_spi_timeout(unsigned long arg)  	struct ifx_spi_device *ifx_dev = (struct ifx_spi_device *)arg;  	dev_warn(&ifx_dev->spi_dev->dev, "*** SPI Timeout ***"); -	ifx_spi_ttyhangup(ifx_dev); +	tty_port_tty_hangup(&ifx_dev->tty_port, false);  	mrdy_set_low(ifx_dev);  	clear_bit(IFX_SPI_STATE_TIMER_PENDING, &ifx_dev->flags);  } @@ -443,25 +426,6 @@ static void ifx_spi_setup_spi_header(unsigned char *txbuffer, int tx_count,  }  /** - *	ifx_spi_wakeup_serial	-	SPI space made - *	@port_data: our SPI device - * - *	We have emptied the FIFO enough that we want to get more data - *	queued into it. Poke the line discipline via tty_wakeup so that - *	it will feed us more bits - */ -static void ifx_spi_wakeup_serial(struct ifx_spi_device *ifx_dev) -{ -	struct tty_struct *tty; - -	tty = tty_port_tty_get(&ifx_dev->tty_port); -	if (!tty) -		return; -	tty_wakeup(tty); -	tty_kref_put(tty); -} - -/**   *	ifx_spi_prepare_tx_buffer	-	prepare transmit frame   *	@ifx_dev: our SPI device   * @@ -506,7 +470,7 @@ static int ifx_spi_prepare_tx_buffer(struct ifx_spi_device *ifx_dev)  			tx_count += temp_count;  			if (temp_count == queue_length)  				/* poke port to get more data */ -				ifx_spi_wakeup_serial(ifx_dev); +				tty_port_tty_wakeup(&ifx_dev->tty_port);  			else /* more data in port, use next SPI message */  				ifx_dev->spi_more = 1;  		} @@ -683,8 +647,6 @@ static void ifx_spi_insert_flip_string(struct ifx_spi_device *ifx_dev,  static void ifx_spi_complete(void *ctx)  {  	struct ifx_spi_device *ifx_dev = ctx; -	struct tty_struct *tty; -	struct tty_ldisc *ldisc = NULL;  	int length;  	int actual_length;  	unsigned char more; @@ -762,15 +724,7 @@ complete_exit:  			 */  			ifx_spi_power_state_clear(ifx_dev,  						  IFX_SPI_POWER_DATA_PENDING); -			tty = tty_port_tty_get(&ifx_dev->tty_port); -			if (tty) { -				ldisc = tty_ldisc_ref(tty); -				if (ldisc) { -					ldisc->ops->write_wakeup(tty); -					tty_ldisc_deref(ldisc); -				} -				tty_kref_put(tty); -			} +			tty_port_tty_wakeup(&ifx_dev->tty_port);  		}  	}  } @@ -962,7 +916,7 @@ static irqreturn_t ifx_spi_reset_interrupt(int irq, void *dev)  		set_bit(MR_INPROGRESS, &ifx_dev->mdm_reset_state);  		if (!solreset) {  			/* unsolicited reset  */ -			ifx_spi_ttyhangup(ifx_dev); +			tty_port_tty_hangup(&ifx_dev->tty_port, false);  		}  	} else {  		/* exited reset */ @@ -1325,30 +1279,6 @@ static void ifx_spi_spi_shutdown(struct spi_device *spi)   */  /** - *	ifx_spi_spi_suspend	-	suspend SPI on system suspend - *	@dev: device being suspended - * - *	Suspend the SPI side. No action needed on Intel MID platforms, may - *	need extending for other systems. - */ -static int ifx_spi_spi_suspend(struct spi_device *spi, pm_message_t msg) -{ -	return 0; -} - -/** - *	ifx_spi_spi_resume	-	resume SPI side on system resume - *	@dev: device being suspended - * - *	Suspend the SPI side. No action needed on Intel MID platforms, may - *	need extending for other systems. - */ -static int ifx_spi_spi_resume(struct spi_device *spi) -{ -	return 0; -} - -/**   *	ifx_spi_pm_suspend	-	suspend modem on system suspend   *	@dev: device being suspended   * @@ -1437,8 +1367,6 @@ static struct spi_driver ifx_spi_driver = {  	.probe = ifx_spi_spi_probe,  	.shutdown = ifx_spi_spi_shutdown,  	.remove = ifx_spi_spi_remove, -	.suspend = ifx_spi_spi_suspend, -	.resume = ifx_spi_spi_resume,  	.id_table = ifx_id_table  }; diff --git a/drivers/tty/serial/jsm/jsm_tty.c b/drivers/tty/serial/jsm/jsm_tty.c index 00f250ae14c..27bb75070c9 100644 --- a/drivers/tty/serial/jsm/jsm_tty.c +++ b/drivers/tty/serial/jsm/jsm_tty.c @@ -596,12 +596,6 @@ void jsm_input(struct jsm_channel *ch)  	jsm_dbg(READ, &ch->ch_bd->pci_dev, "start 2\n"); -	if (data_len <= 0) { -		spin_unlock_irqrestore(&ch->ch_lock, lock_flags); -		jsm_dbg(READ, &ch->ch_bd->pci_dev, "jsm_input 1\n"); -		return; -	} -  	len = tty_buffer_request_room(port, data_len);  	n = len; diff --git a/drivers/tty/serial/max3100.c b/drivers/tty/serial/max3100.c index 32517d4bcea..57da9bbaaab 100644 --- a/drivers/tty/serial/max3100.c +++ b/drivers/tty/serial/max3100.c @@ -849,11 +849,11 @@ static int max3100_remove(struct spi_device *spi)  	return 0;  } -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP -static int max3100_suspend(struct spi_device *spi, pm_message_t state) +static int max3100_suspend(struct device *dev)  { -	struct max3100_port *s = dev_get_drvdata(&spi->dev); +	struct max3100_port *s = dev_get_drvdata(dev);  	dev_dbg(&s->spi->dev, "%s\n", __func__); @@ -874,9 +874,9 @@ static int max3100_suspend(struct spi_device *spi, pm_message_t state)  	return 0;  } -static int max3100_resume(struct spi_device *spi) +static int max3100_resume(struct device *dev)  { -	struct max3100_port *s = dev_get_drvdata(&spi->dev); +	struct max3100_port *s = dev_get_drvdata(dev);  	dev_dbg(&s->spi->dev, "%s\n", __func__); @@ -894,21 +894,21 @@ static int max3100_resume(struct spi_device *spi)  	return 0;  } +static SIMPLE_DEV_PM_OPS(max3100_pm_ops, max3100_suspend, max3100_resume); +#define MAX3100_PM_OPS (&max3100_pm_ops) +  #else -#define max3100_suspend NULL -#define max3100_resume  NULL +#define MAX3100_PM_OPS NULL  #endif  static struct spi_driver max3100_driver = {  	.driver = {  		.name		= "max3100",  		.owner		= THIS_MODULE, +		.pm		= MAX3100_PM_OPS,  	}, -  	.probe		= max3100_probe,  	.remove		= max3100_remove, -	.suspend	= max3100_suspend, -	.resume		= max3100_resume,  };  module_spi_driver(max3100_driver); diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c index 0c2422cb04e..8941e641894 100644 --- a/drivers/tty/serial/max310x.c +++ b/drivers/tty/serial/max310x.c @@ -881,12 +881,14 @@ static struct uart_ops max310x_ops = {  	.verify_port	= max310x_verify_port,  }; -static int max310x_suspend(struct spi_device *spi, pm_message_t state) +#ifdef CONFIG_PM_SLEEP + +static int max310x_suspend(struct device *dev)  {  	int ret; -	struct max310x_port *s = dev_get_drvdata(&spi->dev); +	struct max310x_port *s = dev_get_drvdata(dev); -	dev_dbg(&spi->dev, "Suspend\n"); +	dev_dbg(dev, "Suspend\n");  	ret = uart_suspend_port(&s->uart, &s->port); @@ -905,11 +907,11 @@ static int max310x_suspend(struct spi_device *spi, pm_message_t state)  	return ret;  } -static int max310x_resume(struct spi_device *spi) +static int max310x_resume(struct device *dev)  { -	struct max310x_port *s = dev_get_drvdata(&spi->dev); +	struct max310x_port *s = dev_get_drvdata(dev); -	dev_dbg(&spi->dev, "Resume\n"); +	dev_dbg(dev, "Resume\n");  	if (s->pdata->suspend)  		s->pdata->suspend(0); @@ -928,6 +930,13 @@ static int max310x_resume(struct spi_device *spi)  	return uart_resume_port(&s->uart, &s->port);  } +static SIMPLE_DEV_PM_OPS(max310x_pm_ops, max310x_suspend, max310x_resume); +#define MAX310X_PM_OPS (&max310x_pm_ops) + +#else +#define MAX310X_PM_OPS NULL +#endif +  #ifdef CONFIG_GPIOLIB  static int max310x_gpio_get(struct gpio_chip *chip, unsigned offset)  { @@ -1242,11 +1251,10 @@ static struct spi_driver max310x_driver = {  	.driver = {  		.name	= "max310x",  		.owner	= THIS_MODULE, +		.pm	= MAX310X_PM_OPS,  	},  	.probe		= max310x_probe,  	.remove		= max310x_remove, -	.suspend	= max310x_suspend, -	.resume		= max310x_resume,  	.id_table	= max310x_id_table,  };  module_spi_driver(max310x_driver); diff --git a/drivers/tty/serial/mrst_max3110.c b/drivers/tty/serial/mrst_max3110.c index f641c232bec..9b6ef20420c 100644 --- a/drivers/tty/serial/mrst_max3110.c +++ b/drivers/tty/serial/mrst_max3110.c @@ -743,9 +743,10 @@ static struct uart_driver serial_m3110_reg = {  	.cons		= &serial_m3110_console,  }; -#ifdef CONFIG_PM -static int serial_m3110_suspend(struct spi_device *spi, pm_message_t state) +#ifdef CONFIG_PM_SLEEP +static int serial_m3110_suspend(struct device *dev)  { +	struct spi_device *spi = to_spi_device(dev);  	struct uart_max3110 *max = spi_get_drvdata(spi);  	disable_irq(max->irq); @@ -754,8 +755,9 @@ static int serial_m3110_suspend(struct spi_device *spi, pm_message_t state)  	return 0;  } -static int serial_m3110_resume(struct spi_device *spi) +static int serial_m3110_resume(struct device *dev)  { +	struct spi_device *spi = to_spi_device(dev);  	struct uart_max3110 *max = spi_get_drvdata(spi);  	max3110_out(max, max->cur_conf); @@ -763,9 +765,13 @@ static int serial_m3110_resume(struct spi_device *spi)  	enable_irq(max->irq);  	return 0;  } + +static SIMPLE_DEV_PM_OPS(serial_m3110_pm_ops, serial_m3110_suspend, +			serial_m3110_resume); +#define SERIAL_M3110_PM_OPS (&serial_m3110_pm_ops) +  #else -#define serial_m3110_suspend	NULL -#define serial_m3110_resume	NULL +#define SERIAL_M3110_PM_OPS NULL  #endif  static int serial_m3110_probe(struct spi_device *spi) @@ -872,11 +878,10 @@ static struct spi_driver uart_max3110_driver = {  	.driver = {  			.name	= "spi_max3111",  			.owner	= THIS_MODULE, +			.pm	= SERIAL_M3110_PM_OPS,  	},  	.probe		= serial_m3110_probe,  	.remove		= serial_m3110_remove, -	.suspend	= serial_m3110_suspend, -	.resume		= serial_m3110_resume,  };  static int __init serial_m3110_init(void) diff --git a/drivers/tty/serial/msm_serial_hs.c b/drivers/tty/serial/msm_serial_hs.c index 4a942c78347..4ca2f64861e 100644 --- a/drivers/tty/serial/msm_serial_hs.c +++ b/drivers/tty/serial/msm_serial_hs.c @@ -907,7 +907,6 @@ static void msm_hs_dmov_rx_callback(struct msm_dmov_cmd *cmd_ptr,  	unsigned int error_f = 0;  	unsigned long flags;  	unsigned int flush; -	struct tty_struct *tty;  	struct tty_port *port;  	struct uart_port *uport;  	struct msm_hs_port *msm_uport; @@ -919,7 +918,6 @@ static void msm_hs_dmov_rx_callback(struct msm_dmov_cmd *cmd_ptr,  	clk_enable(msm_uport->clk);  	port = &uport->state->port; -	tty = port->tty;  	msm_hs_write(uport, UARTDM_CR_ADDR, STALE_EVENT_DISABLE); diff --git a/drivers/tty/serial/msm_smd_tty.c b/drivers/tty/serial/msm_smd_tty.c index e722ff163d9..1238ac370bf 100644 --- a/drivers/tty/serial/msm_smd_tty.c +++ b/drivers/tty/serial/msm_smd_tty.c @@ -90,13 +90,13 @@ static void smd_tty_notify(void *priv, unsigned event)  static int smd_tty_port_activate(struct tty_port *tport, struct tty_struct *tty)  { +	struct smd_tty_info *info = container_of(tport, struct smd_tty_info, +			port);  	int i, res = 0; -	int n = tty->index;  	const char *name = NULL; -	struct smd_tty_info *info = smd_tty + n;  	for (i = 0; i < smd_tty_channels_len; i++) { -		if (smd_tty_channels[i].id == n) { +		if (smd_tty_channels[i].id == tty->index) {  			name = smd_tty_channels[i].name;  			break;  		} @@ -117,17 +117,13 @@ static int smd_tty_port_activate(struct tty_port *tport, struct tty_struct *tty)  static void smd_tty_port_shutdown(struct tty_port *tport)  { -	struct smd_tty_info *info; -	struct tty_struct *tty = tty_port_tty_get(tport); +	struct smd_tty_info *info = container_of(tport, struct smd_tty_info, +			port); -	info = tty->driver_data;  	if (info->ch) {  		smd_close(info->ch);  		info->ch = 0;  	} - -	tty->driver_data = 0; -	tty_kref_put(tty);  }  static int smd_tty_open(struct tty_struct *tty, struct file *f) diff --git a/drivers/tty/serial/of_serial.c b/drivers/tty/serial/of_serial.c index b025d543827..39c7ea4cb14 100644 --- a/drivers/tty/serial/of_serial.c +++ b/drivers/tty/serial/of_serial.c @@ -14,7 +14,6 @@  #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> @@ -22,6 +21,8 @@  #include <linux/nwpserial.h>  #include <linux/clk.h> +#include "8250/8250.h" +  struct of_serial_info {  	struct clk *clk;  	int type; @@ -97,6 +98,10 @@ static int of_platform_serial_setup(struct platform_device *ofdev,  	if (of_property_read_u32(np, "reg-shift", &prop) == 0)  		port->regshift = prop; +	/* Check for fifo size */ +	if (of_property_read_u32(np, "fifo-size", &prop) == 0) +		port->fifosize = prop; +  	port->irq = irq_of_parse_and_map(np, 0);  	port->iotype = UPIO_MEM;  	if (of_property_read_u32(np, "reg-io-width", &prop) == 0) { @@ -167,11 +172,17 @@ static int of_platform_serial_probe(struct platform_device *ofdev)  #ifdef CONFIG_SERIAL_8250  	case PORT_8250 ... PORT_MAX_8250:  	{ -		/* For now the of bindings don't support the extra -		   8250 specific bits */  		struct uart_8250_port port8250;  		memset(&port8250, 0, sizeof(port8250));  		port8250.port = port; + +		if (port.fifosize) +			port8250.capabilities = UART_CAP_FIFO; + +		if (of_property_read_bool(ofdev->dev.of_node, +					  "auto-flow-control")) +			port8250.capabilities |= UART_CAP_AFE; +  		ret = serial8250_register_8250_port(&port8250);  		break;  	} diff --git a/drivers/tty/serial/pch_uart.c b/drivers/tty/serial/pch_uart.c index 7a6c989924b..21a7e179edf 100644 --- a/drivers/tty/serial/pch_uart.c +++ b/drivers/tty/serial/pch_uart.c @@ -1493,29 +1493,6 @@ static int pch_uart_verify_port(struct uart_port *port,  	return 0;  } -static struct uart_ops pch_uart_ops = { -	.tx_empty = pch_uart_tx_empty, -	.set_mctrl = pch_uart_set_mctrl, -	.get_mctrl = pch_uart_get_mctrl, -	.stop_tx = pch_uart_stop_tx, -	.start_tx = pch_uart_start_tx, -	.stop_rx = pch_uart_stop_rx, -	.enable_ms = pch_uart_enable_ms, -	.break_ctl = pch_uart_break_ctl, -	.startup = pch_uart_startup, -	.shutdown = pch_uart_shutdown, -	.set_termios = pch_uart_set_termios, -/*	.pm		= pch_uart_pm,		Not supported yet */ -/*	.set_wake	= pch_uart_set_wake,	Not supported yet */ -	.type = pch_uart_type, -	.release_port = pch_uart_release_port, -	.request_port = pch_uart_request_port, -	.config_port = pch_uart_config_port, -	.verify_port = pch_uart_verify_port -}; - -#ifdef CONFIG_SERIAL_PCH_UART_CONSOLE -  /*   *	Wait for transmitter & holding register to empty   */ @@ -1547,6 +1524,84 @@ static void wait_for_xmitr(struct eg20t_port *up, int bits)  	}  } +#ifdef CONFIG_CONSOLE_POLL +/* + * Console polling routines for communicate via uart while + * in an interrupt or debug context. + */ +static int pch_uart_get_poll_char(struct uart_port *port) +{ +	struct eg20t_port *priv = +		container_of(port, struct eg20t_port, port); +	u8 lsr = ioread8(priv->membase + UART_LSR); + +	if (!(lsr & UART_LSR_DR)) +		return NO_POLL_CHAR; + +	return ioread8(priv->membase + PCH_UART_RBR); +} + + +static void pch_uart_put_poll_char(struct uart_port *port, +			 unsigned char c) +{ +	unsigned int ier; +	struct eg20t_port *priv = +		container_of(port, struct eg20t_port, port); + +	/* +	 * First save the IER then disable the interrupts +	 */ +	ier = ioread8(priv->membase + UART_IER); +	pch_uart_hal_disable_interrupt(priv, PCH_UART_HAL_ALL_INT); + +	wait_for_xmitr(priv, UART_LSR_THRE); +	/* +	 * Send the character out. +	 * If a LF, also do CR... +	 */ +	iowrite8(c, priv->membase + PCH_UART_THR); +	if (c == 10) { +		wait_for_xmitr(priv, UART_LSR_THRE); +		iowrite8(13, priv->membase + PCH_UART_THR); +	} + +	/* +	 * Finally, wait for transmitter to become empty +	 * and restore the IER +	 */ +	wait_for_xmitr(priv, BOTH_EMPTY); +	iowrite8(ier, priv->membase + UART_IER); +} +#endif /* CONFIG_CONSOLE_POLL */ + +static struct uart_ops pch_uart_ops = { +	.tx_empty = pch_uart_tx_empty, +	.set_mctrl = pch_uart_set_mctrl, +	.get_mctrl = pch_uart_get_mctrl, +	.stop_tx = pch_uart_stop_tx, +	.start_tx = pch_uart_start_tx, +	.stop_rx = pch_uart_stop_rx, +	.enable_ms = pch_uart_enable_ms, +	.break_ctl = pch_uart_break_ctl, +	.startup = pch_uart_startup, +	.shutdown = pch_uart_shutdown, +	.set_termios = pch_uart_set_termios, +/*	.pm		= pch_uart_pm,		Not supported yet */ +/*	.set_wake	= pch_uart_set_wake,	Not supported yet */ +	.type = pch_uart_type, +	.release_port = pch_uart_release_port, +	.request_port = pch_uart_request_port, +	.config_port = pch_uart_config_port, +	.verify_port = pch_uart_verify_port, +#ifdef CONFIG_CONSOLE_POLL +	.poll_get_char = pch_uart_get_poll_char, +	.poll_put_char = pch_uart_put_poll_char, +#endif +}; + +#ifdef CONFIG_SERIAL_PCH_UART_CONSOLE +  static void pch_console_putchar(struct uart_port *port, int ch)  {  	struct eg20t_port *priv = @@ -1655,7 +1710,7 @@ static struct console pch_console = {  #define PCH_CONSOLE	(&pch_console)  #else  #define PCH_CONSOLE	NULL -#endif +#endif	/* CONFIG_SERIAL_PCH_UART_CONSOLE */  static struct uart_driver pch_uart_driver = {  	.owner = THIS_MODULE, diff --git a/drivers/tty/serial/samsung.c b/drivers/tty/serial/samsung.c index 2769a38d15b..7883f11b8c5 100644 --- a/drivers/tty/serial/samsung.c +++ b/drivers/tty/serial/samsung.c @@ -446,6 +446,8 @@ static void s3c24xx_serial_shutdown(struct uart_port *port)  	/* Clear pending interrupts and mask all interrupts */  	if (s3c24xx_serial_has_interrupt_mask(port)) { +		free_irq(port->irq, ourport); +  		wr_regl(port, S3C64XX_UINTP, 0xf);  		wr_regl(port, S3C64XX_UINTM, 0xf);  	} @@ -505,6 +507,8 @@ static int s3c64xx_serial_startup(struct uart_port *port)  	dbg("s3c64xx_serial_startup: port=%p (%08lx,%p)\n",  	    port->mapbase, port->membase); +	wr_regl(port, S3C64XX_UINTM, 0xf); +  	ret = request_irq(port->irq, s3c64xx_serial_handle_irq, IRQF_SHARED,  			  s3c24xx_serial_portname(port), ourport);  	if (ret) { @@ -1307,9 +1311,29 @@ static int s3c24xx_serial_resume(struct device *dev)  	return 0;  } +static int s3c24xx_serial_resume_noirq(struct device *dev) +{ +	struct uart_port *port = s3c24xx_dev_to_port(dev); + +	if (port) { +		/* restore IRQ mask */ +		if (s3c24xx_serial_has_interrupt_mask(port)) { +			unsigned int uintm = 0xf; +			if (tx_enabled(port)) +				uintm &= ~S3C64XX_UINTM_TXD_MSK; +			if (rx_enabled(port)) +				uintm &= ~S3C64XX_UINTM_RXD_MSK; +			wr_regl(port, S3C64XX_UINTM, uintm); +		} +	} + +	return 0; +} +  static const struct dev_pm_ops s3c24xx_serial_pm_ops = {  	.suspend = s3c24xx_serial_suspend,  	.resume = s3c24xx_serial_resume, +	.resume_noirq = s3c24xx_serial_resume_noirq,  };  #define SERIAL_SAMSUNG_PM_OPS	(&s3c24xx_serial_pm_ops) @@ -1343,6 +1367,13 @@ s3c24xx_serial_console_txrdy(struct uart_port *port, unsigned int ufcon)  	return (utrstat & S3C2410_UTRSTAT_TXE) ? 1 : 0;  } +static bool +s3c24xx_port_configured(unsigned int ucon) +{ +	/* consider the serial port configured if the tx/rx mode set */ +	return (ucon & 0xf) != 0; +} +  #ifdef CONFIG_CONSOLE_POLL  /*   * Console polling routines for writing and reading from the uart while @@ -1365,6 +1396,11 @@ static void s3c24xx_serial_put_poll_char(struct uart_port *port,  		unsigned char c)  {  	unsigned int ufcon = rd_regl(cons_uart, S3C2410_UFCON); +	unsigned int ucon = rd_regl(cons_uart, S3C2410_UCON); + +	/* not possible to xmit on unconfigured port */ +	if (!s3c24xx_port_configured(ucon)) +		return;  	while (!s3c24xx_serial_console_txrdy(port, ufcon))  		cpu_relax(); @@ -1377,6 +1413,12 @@ static void  s3c24xx_serial_console_putchar(struct uart_port *port, int ch)  {  	unsigned int ufcon = rd_regl(cons_uart, S3C2410_UFCON); +	unsigned int ucon = rd_regl(cons_uart, S3C2410_UCON); + +	/* not possible to xmit on unconfigured port */ +	if (!s3c24xx_port_configured(ucon)) +		return; +  	while (!s3c24xx_serial_console_txrdy(port, ufcon))  		barrier();  	wr_regb(cons_uart, S3C2410_UTXH, ch); @@ -1409,9 +1451,7 @@ s3c24xx_serial_get_options(struct uart_port *port, int *baud,  	    "registers: ulcon=%08x, ucon=%08x, ubdriv=%08x\n",  	    port, ulcon, ucon, ubrdiv); -	if ((ucon & 0xf) != 0) { -		/* consider the serial port configured if the tx/rx mode set */ - +	if (s3c24xx_port_configured(ucon)) {  		switch (ulcon & S3C2410_LCON_CSMASK) {  		case S3C2410_LCON_CS5:  			*bits = 5; diff --git a/drivers/tty/serial/serial-tegra.c b/drivers/tty/serial/serial-tegra.c index 372de8ade76..9799d043a9b 100644 --- a/drivers/tty/serial/serial-tegra.c +++ b/drivers/tty/serial/serial-tegra.c @@ -26,6 +26,7 @@  #include <linux/dmaengine.h>  #include <linux/dma-mapping.h>  #include <linux/dmapool.h> +#include <linux/err.h>  #include <linux/io.h>  #include <linux/irq.h>  #include <linux/module.h> @@ -1301,11 +1302,9 @@ static int tegra_uart_probe(struct platform_device *pdev)  	}  	u->mapbase = resource->start; -	u->membase = devm_request_and_ioremap(&pdev->dev, resource); -	if (!u->membase) { -		dev_err(&pdev->dev, "memregion/iomap address req failed\n"); -		return -EADDRNOTAVAIL; -	} +	u->membase = devm_ioremap_resource(&pdev->dev, resource); +	if (IS_ERR(u->membase)) +		return PTR_ERR(u->membase);  	tup->uart_clk = devm_clk_get(&pdev->dev, NULL);  	if (IS_ERR(tup->uart_clk)) { diff --git a/drivers/tty/serial/sh-sci.h b/drivers/tty/serial/sh-sci.h index 4c22a1529aa..5aca7364634 100644 --- a/drivers/tty/serial/sh-sci.h +++ b/drivers/tty/serial/sh-sci.h @@ -15,8 +15,6 @@      defined(CONFIG_CPU_SUBTYPE_SH7720) || \      defined(CONFIG_CPU_SUBTYPE_SH7721) || \      defined(CONFIG_ARCH_SH73A0) || \ -    defined(CONFIG_ARCH_SH7367) || \ -    defined(CONFIG_ARCH_SH7377) || \      defined(CONFIG_ARCH_SH7372) || \      defined(CONFIG_ARCH_R8A7740) diff --git a/drivers/tty/serial/sunsab.c b/drivers/tty/serial/sunsab.c index 8de2213664e..a422c8b55a4 100644 --- a/drivers/tty/serial/sunsab.c +++ b/drivers/tty/serial/sunsab.c @@ -203,7 +203,7 @@ receive_chars(struct uart_sunsab_port *up,  				flag = TTY_FRAME;  		} -		if (uart_handle_sysrq_char(&up->port, ch)) +		if (uart_handle_sysrq_char(&up->port, ch) || !port)  			continue;  		if ((stat->sreg.isr0 & (up->port.ignore_status_mask & 0xff)) == 0 && diff --git a/drivers/tty/serial/sunzilog.c b/drivers/tty/serial/sunzilog.c index 27669ff3d44..813ef8eb8ef 100644 --- a/drivers/tty/serial/sunzilog.c +++ b/drivers/tty/serial/sunzilog.c @@ -388,7 +388,7 @@ sunzilog_receive_chars(struct uart_sunzilog_port *up,  			else if (r1 & CRC_ERR)  				flag = TTY_FRAME;  		} -		if (uart_handle_sysrq_char(&up->port, ch)) +		if (uart_handle_sysrq_char(&up->port, ch) || !port)  			continue;  		if (up->port.ignore_status_mask == 0xff || diff --git a/drivers/tty/serial/vt8500_serial.c b/drivers/tty/serial/vt8500_serial.c index 705240e6c4e..1a8bc2275ea 100644 --- a/drivers/tty/serial/vt8500_serial.c +++ b/drivers/tty/serial/vt8500_serial.c @@ -35,6 +35,7 @@  #include <linux/clk.h>  #include <linux/platform_device.h>  #include <linux/of.h> +#include <linux/err.h>  /*   * UART Register offsets @@ -585,9 +586,9 @@ static int vt8500_serial_probe(struct platform_device *pdev)  	if (!vt8500_port)  		return -ENOMEM; -	vt8500_port->uart.membase = devm_request_and_ioremap(&pdev->dev, mmres); -	if (!vt8500_port->uart.membase) -		return -EADDRNOTAVAIL; +	vt8500_port->uart.membase = devm_ioremap_resource(&pdev->dev, mmres); +	if (IS_ERR(vt8500_port->uart.membase)) +		return PTR_ERR(vt8500_port->uart.membase);  	vt8500_port->clk = of_clk_get(pdev->dev.of_node, 0);  	if (IS_ERR(vt8500_port->clk)) { diff --git a/drivers/tty/serial/xilinx_uartps.c b/drivers/tty/serial/xilinx_uartps.c index f36bbba1ac8..4e5c77834c5 100644 --- a/drivers/tty/serial/xilinx_uartps.c +++ b/drivers/tty/serial/xilinx_uartps.c @@ -585,9 +585,6 @@ static int xuartps_startup(struct uart_port *port)  	xuartps_writel(XUARTPS_IXR_TXEMPTY | XUARTPS_IXR_PARITY |  		XUARTPS_IXR_FRAMING | XUARTPS_IXR_OVERRUN |  		XUARTPS_IXR_RXTRIG | XUARTPS_IXR_TOUT, XUARTPS_IER_OFFSET); -	xuartps_writel(~(XUARTPS_IXR_TXEMPTY | XUARTPS_IXR_PARITY | -		XUARTPS_IXR_FRAMING | XUARTPS_IXR_OVERRUN | -		XUARTPS_IXR_RXTRIG | XUARTPS_IXR_TOUT), XUARTPS_IDR_OFFSET);  	return retval;  } diff --git a/drivers/tty/synclink.c b/drivers/tty/synclink.c index 8983276aa35..72d607101f9 100644 --- a/drivers/tty/synclink.c +++ b/drivers/tty/synclink.c @@ -1058,9 +1058,6 @@ static void mgsl_bh_handler(struct work_struct *work)  		container_of(work, struct mgsl_struct, task);  	int action; -	if (!info) -		return; -		  	if ( debug_level >= DEBUG_LEVEL_BH )  		printk( "%s(%d):mgsl_bh_handler(%s) entry\n",  			__FILE__,__LINE__,info->device_name); diff --git a/drivers/tty/sysrq.c b/drivers/tty/sysrq.c index 3687f0cad64..0a0de333c76 100644 --- a/drivers/tty/sysrq.c +++ b/drivers/tty/sysrq.c @@ -101,7 +101,7 @@ static void sysrq_handle_SAK(int key)  }  static struct sysrq_key_op sysrq_SAK_op = {  	.handler	= sysrq_handle_SAK, -	.help_msg	= "saK", +	.help_msg	= "sak(k)",  	.action_msg	= "SAK",  	.enable_mask	= SYSRQ_ENABLE_KEYBOARD,  }; @@ -117,7 +117,7 @@ static void sysrq_handle_unraw(int key)  static struct sysrq_key_op sysrq_unraw_op = {  	.handler	= sysrq_handle_unraw, -	.help_msg	= "unRaw", +	.help_msg	= "unraw(r)",  	.action_msg	= "Keyboard mode set to system default",  	.enable_mask	= SYSRQ_ENABLE_KEYBOARD,  }; @@ -135,7 +135,7 @@ static void sysrq_handle_crash(int key)  }  static struct sysrq_key_op sysrq_crash_op = {  	.handler	= sysrq_handle_crash, -	.help_msg	= "Crash", +	.help_msg	= "crash(c)",  	.action_msg	= "Trigger a crash",  	.enable_mask	= SYSRQ_ENABLE_DUMP,  }; @@ -148,7 +148,7 @@ static void sysrq_handle_reboot(int key)  }  static struct sysrq_key_op sysrq_reboot_op = {  	.handler	= sysrq_handle_reboot, -	.help_msg	= "reBoot", +	.help_msg	= "reboot(b)",  	.action_msg	= "Resetting",  	.enable_mask	= SYSRQ_ENABLE_BOOT,  }; @@ -159,7 +159,7 @@ static void sysrq_handle_sync(int key)  }  static struct sysrq_key_op sysrq_sync_op = {  	.handler	= sysrq_handle_sync, -	.help_msg	= "Sync", +	.help_msg	= "sync(s)",  	.action_msg	= "Emergency Sync",  	.enable_mask	= SYSRQ_ENABLE_SYNC,  }; @@ -171,7 +171,7 @@ static void sysrq_handle_show_timers(int key)  static struct sysrq_key_op sysrq_show_timers_op = {  	.handler	= sysrq_handle_show_timers, -	.help_msg	= "show-all-timers(Q)", +	.help_msg	= "show-all-timers(q)",  	.action_msg	= "Show clockevent devices & pending hrtimers (no others)",  }; @@ -181,7 +181,7 @@ static void sysrq_handle_mountro(int key)  }  static struct sysrq_key_op sysrq_mountro_op = {  	.handler	= sysrq_handle_mountro, -	.help_msg	= "Unmount", +	.help_msg	= "unmount(u)",  	.action_msg	= "Emergency Remount R/O",  	.enable_mask	= SYSRQ_ENABLE_REMOUNT,  }; @@ -194,7 +194,7 @@ static void sysrq_handle_showlocks(int key)  static struct sysrq_key_op sysrq_showlocks_op = {  	.handler	= sysrq_handle_showlocks, -	.help_msg	= "show-all-locks(D)", +	.help_msg	= "show-all-locks(d)",  	.action_msg	= "Show Locks Held",  };  #else @@ -245,7 +245,7 @@ static void sysrq_handle_showallcpus(int key)  static struct sysrq_key_op sysrq_showallcpus_op = {  	.handler	= sysrq_handle_showallcpus, -	.help_msg	= "show-backtrace-all-active-cpus(L)", +	.help_msg	= "show-backtrace-all-active-cpus(l)",  	.action_msg	= "Show backtrace of all active CPUs",  	.enable_mask	= SYSRQ_ENABLE_DUMP,  }; @@ -260,7 +260,7 @@ static void sysrq_handle_showregs(int key)  }  static struct sysrq_key_op sysrq_showregs_op = {  	.handler	= sysrq_handle_showregs, -	.help_msg	= "show-registers(P)", +	.help_msg	= "show-registers(p)",  	.action_msg	= "Show Regs",  	.enable_mask	= SYSRQ_ENABLE_DUMP,  }; @@ -271,7 +271,7 @@ static void sysrq_handle_showstate(int key)  }  static struct sysrq_key_op sysrq_showstate_op = {  	.handler	= sysrq_handle_showstate, -	.help_msg	= "show-task-states(T)", +	.help_msg	= "show-task-states(t)",  	.action_msg	= "Show State",  	.enable_mask	= SYSRQ_ENABLE_DUMP,  }; @@ -282,7 +282,7 @@ static void sysrq_handle_showstate_blocked(int key)  }  static struct sysrq_key_op sysrq_showstate_blocked_op = {  	.handler	= sysrq_handle_showstate_blocked, -	.help_msg	= "show-blocked-tasks(W)", +	.help_msg	= "show-blocked-tasks(w)",  	.action_msg	= "Show Blocked State",  	.enable_mask	= SYSRQ_ENABLE_DUMP,  }; @@ -296,7 +296,7 @@ static void sysrq_ftrace_dump(int key)  }  static struct sysrq_key_op sysrq_ftrace_dump_op = {  	.handler	= sysrq_ftrace_dump, -	.help_msg	= "dump-ftrace-buffer(Z)", +	.help_msg	= "dump-ftrace-buffer(z)",  	.action_msg	= "Dump ftrace buffer",  	.enable_mask	= SYSRQ_ENABLE_DUMP,  }; @@ -310,7 +310,7 @@ static void sysrq_handle_showmem(int key)  }  static struct sysrq_key_op sysrq_showmem_op = {  	.handler	= sysrq_handle_showmem, -	.help_msg	= "show-memory-usage(M)", +	.help_msg	= "show-memory-usage(m)",  	.action_msg	= "Show Memory",  	.enable_mask	= SYSRQ_ENABLE_DUMP,  }; @@ -341,7 +341,7 @@ static void sysrq_handle_term(int key)  }  static struct sysrq_key_op sysrq_term_op = {  	.handler	= sysrq_handle_term, -	.help_msg	= "terminate-all-tasks(E)", +	.help_msg	= "terminate-all-tasks(e)",  	.action_msg	= "Terminate All Tasks",  	.enable_mask	= SYSRQ_ENABLE_SIGNAL,  }; @@ -360,7 +360,7 @@ static void sysrq_handle_moom(int key)  }  static struct sysrq_key_op sysrq_moom_op = {  	.handler	= sysrq_handle_moom, -	.help_msg	= "memory-full-oom-kill(F)", +	.help_msg	= "memory-full-oom-kill(f)",  	.action_msg	= "Manual OOM execution",  	.enable_mask	= SYSRQ_ENABLE_SIGNAL,  }; @@ -372,7 +372,7 @@ static void sysrq_handle_thaw(int key)  }  static struct sysrq_key_op sysrq_thaw_op = {  	.handler	= sysrq_handle_thaw, -	.help_msg	= "thaw-filesystems(J)", +	.help_msg	= "thaw-filesystems(j)",  	.action_msg	= "Emergency Thaw of all frozen filesystems",  	.enable_mask	= SYSRQ_ENABLE_SIGNAL,  }; @@ -385,7 +385,7 @@ static void sysrq_handle_kill(int key)  }  static struct sysrq_key_op sysrq_kill_op = {  	.handler	= sysrq_handle_kill, -	.help_msg	= "kill-all-tasks(I)", +	.help_msg	= "kill-all-tasks(i)",  	.action_msg	= "Kill All Tasks",  	.enable_mask	= SYSRQ_ENABLE_SIGNAL,  }; @@ -396,7 +396,7 @@ static void sysrq_handle_unrt(int key)  }  static struct sysrq_key_op sysrq_unrt_op = {  	.handler	= sysrq_handle_unrt, -	.help_msg	= "nice-all-RT-tasks(N)", +	.help_msg	= "nice-all-RT-tasks(n)",  	.action_msg	= "Nice All RT Tasks",  	.enable_mask	= SYSRQ_ENABLE_RTNICE,  }; diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index 05400acbc45..cbf5a504090 100644 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c @@ -533,6 +533,60 @@ void tty_wakeup(struct tty_struct *tty)  EXPORT_SYMBOL_GPL(tty_wakeup);  /** + *	tty_signal_session_leader	- sends SIGHUP to session leader + *	@tty		controlling tty + *	@exit_session	if non-zero, signal all foreground group processes + * + *	Send SIGHUP and SIGCONT to the session leader and its process group. + *	Optionally, signal all processes in the foreground process group. + * + *	Returns the number of processes in the session with this tty + *	as their controlling terminal. This value is used to drop + *	tty references for those processes. + */ +static int tty_signal_session_leader(struct tty_struct *tty, int exit_session) +{ +	struct task_struct *p; +	int refs = 0; +	struct pid *tty_pgrp = NULL; + +	read_lock(&tasklist_lock); +	if (tty->session) { +		do_each_pid_task(tty->session, PIDTYPE_SID, p) { +			spin_lock_irq(&p->sighand->siglock); +			if (p->signal->tty == tty) { +				p->signal->tty = NULL; +				/* We defer the dereferences outside fo +				   the tasklist lock */ +				refs++; +			} +			if (!p->signal->leader) { +				spin_unlock_irq(&p->sighand->siglock); +				continue; +			} +			__group_send_sig_info(SIGHUP, SEND_SIG_PRIV, p); +			__group_send_sig_info(SIGCONT, SEND_SIG_PRIV, p); +			put_pid(p->signal->tty_old_pgrp);  /* A noop */ +			spin_lock(&tty->ctrl_lock); +			tty_pgrp = get_pid(tty->pgrp); +			if (tty->pgrp) +				p->signal->tty_old_pgrp = get_pid(tty->pgrp); +			spin_unlock(&tty->ctrl_lock); +			spin_unlock_irq(&p->sighand->siglock); +		} while_each_pid_task(tty->session, PIDTYPE_SID, p); +	} +	read_unlock(&tasklist_lock); + +	if (tty_pgrp) { +		if (exit_session) +			kill_pgrp(tty_pgrp, SIGHUP, exit_session); +		put_pid(tty_pgrp); +	} + +	return refs; +} + +/**   *	__tty_hangup		-	actual handler for hangup events   *	@work: tty device   * @@ -554,15 +608,13 @@ EXPORT_SYMBOL_GPL(tty_wakeup);   *		  tasklist_lock to walk task list for hangup event   *		    ->siglock to protect ->signal/->sighand   */ -static void __tty_hangup(struct tty_struct *tty) +static void __tty_hangup(struct tty_struct *tty, int exit_session)  {  	struct file *cons_filp = NULL;  	struct file *filp, *f = NULL; -	struct task_struct *p;  	struct tty_file_private *priv;  	int    closecount = 0, n; -	unsigned long flags; -	int refs = 0; +	int refs;  	if (!tty)  		return; @@ -599,39 +651,18 @@ static void __tty_hangup(struct tty_struct *tty)  	}  	spin_unlock(&tty_files_lock); +	refs = tty_signal_session_leader(tty, exit_session); +	/* Account for the p->signal references we killed */ +	while (refs--) +		tty_kref_put(tty); +  	/*  	 * it drops BTM and thus races with reopen  	 * we protect the race by TTY_HUPPING  	 */  	tty_ldisc_hangup(tty); -	read_lock(&tasklist_lock); -	if (tty->session) { -		do_each_pid_task(tty->session, PIDTYPE_SID, p) { -			spin_lock_irq(&p->sighand->siglock); -			if (p->signal->tty == tty) { -				p->signal->tty = NULL; -				/* We defer the dereferences outside fo -				   the tasklist lock */ -				refs++; -			} -			if (!p->signal->leader) { -				spin_unlock_irq(&p->sighand->siglock); -				continue; -			} -			__group_send_sig_info(SIGHUP, SEND_SIG_PRIV, p); -			__group_send_sig_info(SIGCONT, SEND_SIG_PRIV, p); -			put_pid(p->signal->tty_old_pgrp);  /* A noop */ -			spin_lock_irqsave(&tty->ctrl_lock, flags); -			if (tty->pgrp) -				p->signal->tty_old_pgrp = get_pid(tty->pgrp); -			spin_unlock_irqrestore(&tty->ctrl_lock, flags); -			spin_unlock_irq(&p->sighand->siglock); -		} while_each_pid_task(tty->session, PIDTYPE_SID, p); -	} -	read_unlock(&tasklist_lock); - -	spin_lock_irqsave(&tty->ctrl_lock, flags); +	spin_lock_irq(&tty->ctrl_lock);  	clear_bit(TTY_THROTTLED, &tty->flags);  	clear_bit(TTY_PUSH, &tty->flags);  	clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); @@ -640,11 +671,7 @@ static void __tty_hangup(struct tty_struct *tty)  	tty->session = NULL;  	tty->pgrp = NULL;  	tty->ctrl_status = 0; -	spin_unlock_irqrestore(&tty->ctrl_lock, flags); - -	/* Account for the p->signal references we killed */ -	while (refs--) -		tty_kref_put(tty); +	spin_unlock_irq(&tty->ctrl_lock);  	/*  	 * If one of the devices matches a console pointer, we @@ -666,7 +693,6 @@ static void __tty_hangup(struct tty_struct *tty)  	 */  	set_bit(TTY_HUPPED, &tty->flags);  	clear_bit(TTY_HUPPING, &tty->flags); -	tty_ldisc_enable(tty);  	tty_unlock(tty); @@ -679,7 +705,7 @@ static void do_tty_hangup(struct work_struct *work)  	struct tty_struct *tty =  		container_of(work, struct tty_struct, hangup_work); -	__tty_hangup(tty); +	__tty_hangup(tty, 0);  }  /** @@ -717,7 +743,7 @@ void tty_vhangup(struct tty_struct *tty)  	printk(KERN_DEBUG "%s vhangup...\n", tty_name(tty, buf));  #endif -	__tty_hangup(tty); +	__tty_hangup(tty, 0);  }  EXPORT_SYMBOL(tty_vhangup); @@ -741,6 +767,27 @@ void tty_vhangup_self(void)  }  /** + *	tty_vhangup_session		-	hangup session leader exit + *	@tty: tty to hangup + * + *	The session leader is exiting and hanging up its controlling terminal. + *	Every process in the foreground process group is signalled SIGHUP. + * + *	We do this synchronously so that when the syscall returns the process + *	is complete. That guarantee is necessary for security reasons. + */ + +static void tty_vhangup_session(struct tty_struct *tty) +{ +#ifdef TTY_DEBUG_HANGUP +	char	buf[64]; + +	printk(KERN_DEBUG "%s vhangup session...\n", tty_name(tty, buf)); +#endif +	__tty_hangup(tty, 1); +} + +/**   *	tty_hung_up_p		-	was tty hung up   *	@filp: file pointer of tty   * @@ -797,18 +844,18 @@ void disassociate_ctty(int on_exit)  	tty = get_current_tty();  	if (tty) { -		struct pid *tty_pgrp = get_pid(tty->pgrp); -		if (on_exit) { -			if (tty->driver->type != TTY_DRIVER_TYPE_PTY) -				tty_vhangup(tty); -		} -		tty_kref_put(tty); -		if (tty_pgrp) { -			kill_pgrp(tty_pgrp, SIGHUP, on_exit); -			if (!on_exit) +		if (on_exit && tty->driver->type != TTY_DRIVER_TYPE_PTY) { +			tty_vhangup_session(tty); +		} else { +			struct pid *tty_pgrp = tty_get_pgrp(tty); +			if (tty_pgrp) { +				kill_pgrp(tty_pgrp, SIGHUP, on_exit);  				kill_pgrp(tty_pgrp, SIGCONT, on_exit); -			put_pid(tty_pgrp); +				put_pid(tty_pgrp); +			}  		} +		tty_kref_put(tty); +  	} else if (on_exit) {  		struct pid *old_pgrp;  		spin_lock_irq(¤t->sighand->siglock); @@ -1344,9 +1391,7 @@ static int tty_reopen(struct tty_struct *tty)  	}  	tty->count++; -	mutex_lock(&tty->ldisc_mutex);  	WARN_ON(!test_bit(TTY_LDISC, &tty->flags)); -	mutex_unlock(&tty->ldisc_mutex);  	return 0;  } @@ -1463,6 +1508,17 @@ void tty_free_termios(struct tty_struct *tty)  }  EXPORT_SYMBOL(tty_free_termios); +/** + *	tty_flush_works		-	flush all works of a tty + *	@tty: tty device to flush works for + * + *	Sync flush all works belonging to @tty. + */ +static void tty_flush_works(struct tty_struct *tty) +{ +	flush_work(&tty->SAK_work); +	flush_work(&tty->hangup_work); +}  /**   *	release_one_tty		-	release tty structure memory @@ -1548,6 +1604,7 @@ static void release_tty(struct tty_struct *tty, int idx)  	tty_free_termios(tty);  	tty_driver_remove_tty(tty->driver, tty);  	tty->port->itty = NULL; +	cancel_work_sync(&tty->port->buf.work);  	if (tty->link)  		tty_kref_put(tty->link); @@ -1777,12 +1834,21 @@ int tty_release(struct inode *inode, struct file *filp)  		return 0;  #ifdef TTY_DEBUG_HANGUP -	printk(KERN_DEBUG "%s: freeing tty structure...\n", __func__); +	printk(KERN_DEBUG "%s: %s: final close\n", __func__, tty_name(tty, buf));  #endif  	/*  	 * Ask the line discipline code to release its structures  	 */  	tty_ldisc_release(tty, o_tty); + +	/* Wait for pending work before tty destruction commmences */ +	tty_flush_works(tty); +	if (o_tty) +		tty_flush_works(o_tty); + +#ifdef TTY_DEBUG_HANGUP +	printk(KERN_DEBUG "%s: %s: freeing structure...\n", __func__, tty_name(tty, buf)); +#endif  	/*  	 * The release_tty function takes care of the details of clearing  	 * the slots and preserving the termios structure. The tty_unlock_pair diff --git a/drivers/tty/tty_ioctl.c b/drivers/tty/tty_ioctl.c index d58b92cc187..d119034877d 100644 --- a/drivers/tty/tty_ioctl.c +++ b/drivers/tty/tty_ioctl.c @@ -106,6 +106,7 @@ void tty_throttle(struct tty_struct *tty)  	if (!test_and_set_bit(TTY_THROTTLED, &tty->flags) &&  	    tty->ops->throttle)  		tty->ops->throttle(tty); +	tty->flow_change = 0;  	mutex_unlock(&tty->termios_mutex);  }  EXPORT_SYMBOL(tty_throttle); @@ -129,11 +130,74 @@ void tty_unthrottle(struct tty_struct *tty)  	if (test_and_clear_bit(TTY_THROTTLED, &tty->flags) &&  	    tty->ops->unthrottle)  		tty->ops->unthrottle(tty); +	tty->flow_change = 0;  	mutex_unlock(&tty->termios_mutex);  }  EXPORT_SYMBOL(tty_unthrottle);  /** + *	tty_throttle_safe	-	flow control + *	@tty: terminal + * + *	Similar to tty_throttle() but will only attempt throttle + *	if tty->flow_change is TTY_THROTTLE_SAFE. Prevents an accidental + *	throttle due to race conditions when throttling is conditional + *	on factors evaluated prior to throttling. + * + *	Returns 0 if tty is throttled (or was already throttled) + */ + +int tty_throttle_safe(struct tty_struct *tty) +{ +	int ret = 0; + +	mutex_lock(&tty->termios_mutex); +	if (!test_bit(TTY_THROTTLED, &tty->flags)) { +		if (tty->flow_change != TTY_THROTTLE_SAFE) +			ret = 1; +		else { +			__set_bit(TTY_THROTTLED, &tty->flags); +			if (tty->ops->throttle) +				tty->ops->throttle(tty); +		} +	} +	mutex_unlock(&tty->termios_mutex); + +	return ret; +} + +/** + *	tty_unthrottle_safe	-	flow control + *	@tty: terminal + * + *	Similar to tty_unthrottle() but will only attempt unthrottle + *	if tty->flow_change is TTY_UNTHROTTLE_SAFE. Prevents an accidental + *	unthrottle due to race conditions when unthrottling is conditional + *	on factors evaluated prior to unthrottling. + * + *	Returns 0 if tty is unthrottled (or was already unthrottled) + */ + +int tty_unthrottle_safe(struct tty_struct *tty) +{ +	int ret = 0; + +	mutex_lock(&tty->termios_mutex); +	if (test_bit(TTY_THROTTLED, &tty->flags)) { +		if (tty->flow_change != TTY_UNTHROTTLE_SAFE) +			ret = 1; +		else { +			__clear_bit(TTY_THROTTLED, &tty->flags); +			if (tty->ops->unthrottle) +				tty->ops->unthrottle(tty); +		} +	} +	mutex_unlock(&tty->termios_mutex); + +	return ret; +} + +/**   *	tty_wait_until_sent	-	wait for I/O to finish   *	@tty: tty we are waiting for   *	@timeout: how long we will wait @@ -415,34 +479,6 @@ void tty_encode_baud_rate(struct tty_struct *tty, speed_t ibaud, speed_t obaud)  EXPORT_SYMBOL_GPL(tty_encode_baud_rate);  /** - *	tty_get_baud_rate	-	get tty bit rates - *	@tty: tty to query - * - *	Returns the baud rate as an integer for this terminal. The - *	termios lock must be held by the caller and the terminal bit - *	flags may be updated. - * - *	Locking: none - */ - -speed_t tty_get_baud_rate(struct tty_struct *tty) -{ -	speed_t baud = tty_termios_baud_rate(&tty->termios); - -	if (baud == 38400 && tty->alt_speed) { -		if (!tty->warned) { -			printk(KERN_WARNING "Use of setserial/setrocket to " -					    "set SPD_* flags is deprecated\n"); -			tty->warned = 1; -		} -		baud = tty->alt_speed; -	} - -	return baud; -} -EXPORT_SYMBOL(tty_get_baud_rate); - -/**   *	tty_termios_copy_hw	-	copy hardware settings   *	@new: New termios   *	@old: Old termios @@ -1086,14 +1122,12 @@ int tty_mode_ioctl(struct tty_struct *tty, struct file *file,  }  EXPORT_SYMBOL_GPL(tty_mode_ioctl); -int tty_perform_flush(struct tty_struct *tty, unsigned long arg) + +/* Caller guarantees ldisc reference is held */ +static int __tty_perform_flush(struct tty_struct *tty, unsigned long arg)  { -	struct tty_ldisc *ld; -	int retval = tty_check_change(tty); -	if (retval) -		return retval; +	struct tty_ldisc *ld = tty->ldisc; -	ld = tty_ldisc_ref_wait(tty);  	switch (arg) {  	case TCIFLUSH:  		if (ld && ld->ops->flush_buffer) { @@ -1111,12 +1145,24 @@ int tty_perform_flush(struct tty_struct *tty, unsigned long arg)  		tty_driver_flush_buffer(tty);  		break;  	default: -		tty_ldisc_deref(ld);  		return -EINVAL;  	} -	tty_ldisc_deref(ld);  	return 0;  } + +int tty_perform_flush(struct tty_struct *tty, unsigned long arg) +{ +	struct tty_ldisc *ld; +	int retval = tty_check_change(tty); +	if (retval) +		return retval; + +	ld = tty_ldisc_ref_wait(tty); +	retval = __tty_perform_flush(tty, arg); +	if (ld) +		tty_ldisc_deref(ld); +	return retval; +}  EXPORT_SYMBOL_GPL(tty_perform_flush);  int n_tty_ioctl_helper(struct tty_struct *tty, struct file *file, @@ -1155,7 +1201,7 @@ int n_tty_ioctl_helper(struct tty_struct *tty, struct file *file,  		}  		return 0;  	case TCFLSH: -		return tty_perform_flush(tty, arg); +		return __tty_perform_flush(tty, arg);  	default:  		/* Try the mode commands */  		return tty_mode_ioctl(tty, file, cmd, arg); diff --git a/drivers/tty/tty_ldisc.c b/drivers/tty/tty_ldisc.c index d794087c327..1afe192bef6 100644 --- a/drivers/tty/tty_ldisc.c +++ b/drivers/tty/tty_ldisc.c @@ -20,6 +20,17 @@  #include <linux/uaccess.h>  #include <linux/ratelimit.h> +#undef LDISC_DEBUG_HANGUP + +#ifdef LDISC_DEBUG_HANGUP +#define tty_ldisc_debug(tty, f, args...) ({				       \ +	char __b[64];							       \ +	printk(KERN_DEBUG "%s: %s: " f, __func__, tty_name(tty, __b), ##args); \ +}) +#else +#define tty_ldisc_debug(tty, f, args...) +#endif +  /*   *	This guards the refcounted line discipline lists. The lock   *	must be taken with irqs off because there are hangup path @@ -31,44 +42,6 @@ static DECLARE_WAIT_QUEUE_HEAD(tty_ldisc_wait);  /* Line disc dispatch table */  static struct tty_ldisc_ops *tty_ldiscs[NR_LDISCS]; -static inline struct tty_ldisc *get_ldisc(struct tty_ldisc *ld) -{ -	if (ld) -		atomic_inc(&ld->users); -	return ld; -} - -static void put_ldisc(struct tty_ldisc *ld) -{ -	unsigned long flags; - -	if (WARN_ON_ONCE(!ld)) -		return; - -	/* -	 * If this is the last user, free the ldisc, and -	 * release the ldisc ops. -	 * -	 * We really want an "atomic_dec_and_raw_lock_irqsave()", -	 * but we don't have it, so this does it by hand. -	 */ -	raw_spin_lock_irqsave(&tty_ldisc_lock, flags); -	if (atomic_dec_and_test(&ld->users)) { -		struct tty_ldisc_ops *ldo = ld->ops; - -		ldo->refcount--; -		module_put(ldo->owner); -		raw_spin_unlock_irqrestore(&tty_ldisc_lock, flags); - -		kfree(ld); -		return; -	} -	raw_spin_unlock_irqrestore(&tty_ldisc_lock, flags); - -	if (waitqueue_active(&ld->wq_idle)) -		wake_up(&ld->wq_idle); -} -  /**   *	tty_register_ldisc	-	install a line discipline   *	@disc: ldisc number @@ -206,6 +179,29 @@ static struct tty_ldisc *tty_ldisc_get(int disc)  	return ld;  } +/** + *	tty_ldisc_put		-	release the ldisc + * + *	Complement of tty_ldisc_get(). + */ +static inline void tty_ldisc_put(struct tty_ldisc *ld) +{ +	unsigned long flags; + +	if (WARN_ON_ONCE(!ld)) +		return; + +	raw_spin_lock_irqsave(&tty_ldisc_lock, flags); + +	/* unreleased reader reference(s) will cause this WARN */ +	WARN_ON(!atomic_dec_and_test(&ld->users)); + +	ld->ops->refcount--; +	module_put(ld->ops->owner); +	kfree(ld); +	raw_spin_unlock_irqrestore(&tty_ldisc_lock, flags); +} +  static void *tty_ldiscs_seq_start(struct seq_file *m, loff_t *pos)  {  	return (*pos < NR_LDISCS) ? pos : NULL; @@ -255,24 +251,6 @@ const struct file_operations tty_ldiscs_proc_fops = {  };  /** - *	tty_ldisc_assign	-	set ldisc on a tty - *	@tty: tty to assign - *	@ld: line discipline - * - *	Install an instance of a line discipline into a tty structure. The - *	ldisc must have a reference count above zero to ensure it remains. - *	The tty instance refcount starts at zero. - * - *	Locking: - *		Caller must hold references - */ - -static void tty_ldisc_assign(struct tty_struct *tty, struct tty_ldisc *ld) -{ -	tty->ldisc = ld; -} - -/**   *	tty_ldisc_try		-	internal helper   *	@tty: the tty   * @@ -289,10 +267,13 @@ static struct tty_ldisc *tty_ldisc_try(struct tty_struct *tty)  	unsigned long flags;  	struct tty_ldisc *ld; +	/* FIXME: this allows reference acquire after TTY_LDISC is cleared */  	raw_spin_lock_irqsave(&tty_ldisc_lock, flags);  	ld = NULL; -	if (test_bit(TTY_LDISC, &tty->flags)) -		ld = get_ldisc(tty->ldisc); +	if (test_bit(TTY_LDISC, &tty->flags) && tty->ldisc) { +		ld = tty->ldisc; +		atomic_inc(&ld->users); +	}  	raw_spin_unlock_irqrestore(&tty_ldisc_lock, flags);  	return ld;  } @@ -352,14 +333,23 @@ EXPORT_SYMBOL_GPL(tty_ldisc_ref);  void tty_ldisc_deref(struct tty_ldisc *ld)  { -	put_ldisc(ld); -} -EXPORT_SYMBOL_GPL(tty_ldisc_deref); +	unsigned long flags; -static inline void tty_ldisc_put(struct tty_ldisc *ld) -{ -	put_ldisc(ld); +	if (WARN_ON_ONCE(!ld)) +		return; + +	raw_spin_lock_irqsave(&tty_ldisc_lock, flags); +	/* +	 * WARNs if one-too-many reader references were released +	 * - the last reference must be released with tty_ldisc_put +	 */ +	WARN_ON(atomic_dec_and_test(&ld->users)); +	raw_spin_unlock_irqrestore(&tty_ldisc_lock, flags); + +	if (waitqueue_active(&ld->wq_idle)) +		wake_up(&ld->wq_idle);  } +EXPORT_SYMBOL_GPL(tty_ldisc_deref);  /**   *	tty_ldisc_enable	-	allow ldisc use @@ -373,8 +363,9 @@ static inline void tty_ldisc_put(struct tty_ldisc *ld)   *	Clearing directly is allowed.   */ -void tty_ldisc_enable(struct tty_struct *tty) +static void tty_ldisc_enable(struct tty_struct *tty)  { +	clear_bit(TTY_LDISC_HALTED, &tty->flags);  	set_bit(TTY_LDISC, &tty->flags);  	clear_bit(TTY_LDISC_CHANGING, &tty->flags);  	wake_up(&tty_ldisc_wait); @@ -479,7 +470,7 @@ static void tty_ldisc_restore(struct tty_struct *tty, struct tty_ldisc *old)  	/* There is an outstanding reference here so this is safe */  	old = tty_ldisc_get(old->ops->num);  	WARN_ON(IS_ERR(old)); -	tty_ldisc_assign(tty, old); +	tty->ldisc = old;  	tty_set_termios_ldisc(tty, old->ops->num);  	if (tty_ldisc_open(tty, old) < 0) {  		tty_ldisc_put(old); @@ -487,7 +478,7 @@ static void tty_ldisc_restore(struct tty_struct *tty, struct tty_ldisc *old)  		new_ldisc = tty_ldisc_get(N_TTY);  		if (IS_ERR(new_ldisc))  			panic("n_tty: get"); -		tty_ldisc_assign(tty, new_ldisc); +		tty->ldisc = new_ldisc;  		tty_set_termios_ldisc(tty, N_TTY);  		r = tty_ldisc_open(tty, new_ldisc);  		if (r < 0) @@ -498,52 +489,98 @@ static void tty_ldisc_restore(struct tty_struct *tty, struct tty_ldisc *old)  }  /** + *	tty_ldisc_wait_idle	-	wait for the ldisc to become idle + *	@tty: tty to wait for + *	@timeout: for how long to wait at most + * + *	Wait for the line discipline to become idle. The discipline must + *	have been halted for this to guarantee it remains idle. + */ +static int tty_ldisc_wait_idle(struct tty_struct *tty, long timeout) +{ +	long ret; +	ret = wait_event_timeout(tty->ldisc->wq_idle, +			atomic_read(&tty->ldisc->users) == 1, timeout); +	return ret > 0 ? 0 : -EBUSY; +} + +/**   *	tty_ldisc_halt		-	shut down the line discipline   *	@tty: tty device + *	@o_tty: paired pty device (can be NULL) + *	@timeout: # of jiffies to wait for ldisc refs to be released   * - *	Shut down the line discipline and work queue for this tty device. - *	The TTY_LDISC flag being cleared ensures no further references can - *	be obtained while the delayed work queue halt ensures that no more - *	data is fed to the ldisc. + *	Shut down the line discipline and work queue for this tty device and + *	its paired pty (if exists). Clearing the TTY_LDISC flag ensures + *	no further references can be obtained, while waiting for existing + *	references to be released ensures no more data is fed to the ldisc.   *   *	You need to do a 'flush_scheduled_work()' (outside the ldisc_mutex)   *	in order to make sure any currently executing ldisc work is also   *	flushed.   */ -static int tty_ldisc_halt(struct tty_struct *tty) +static int tty_ldisc_halt(struct tty_struct *tty, struct tty_struct *o_tty, +			  long timeout)  { +	int retval; +  	clear_bit(TTY_LDISC, &tty->flags); -	return cancel_work_sync(&tty->port->buf.work); -} +	if (o_tty) +		clear_bit(TTY_LDISC, &o_tty->flags); -/** - *	tty_ldisc_flush_works	-	flush all works of a tty - *	@tty: tty device to flush works for - * - *	Sync flush all works belonging to @tty. - */ -static void tty_ldisc_flush_works(struct tty_struct *tty) -{ -	flush_work(&tty->hangup_work); -	flush_work(&tty->SAK_work); -	flush_work(&tty->port->buf.work); +	retval = tty_ldisc_wait_idle(tty, timeout); +	if (!retval && o_tty) +		retval = tty_ldisc_wait_idle(o_tty, timeout); +	if (retval) +		return retval; + +	set_bit(TTY_LDISC_HALTED, &tty->flags); +	if (o_tty) +		set_bit(TTY_LDISC_HALTED, &o_tty->flags); + +	return 0;  }  /** - *	tty_ldisc_wait_idle	-	wait for the ldisc to become idle - *	@tty: tty to wait for - *	@timeout: for how long to wait at most + *	tty_ldisc_hangup_halt - halt the line discipline for hangup + *	@tty: tty being hung up   * - *	Wait for the line discipline to become idle. The discipline must - *	have been halted for this to guarantee it remains idle. + *	Shut down the line discipline and work queue for the tty device + *	being hungup. Clear the TTY_LDISC flag to ensure no further + *	references can be obtained and wait for remaining references to be + *	released to ensure no more data is fed to this ldisc. + *	Caller must hold legacy and ->ldisc_mutex. + * + *	NB: tty_set_ldisc() is prevented from changing the ldisc concurrently + *	with this function by checking the TTY_HUPPING flag.   */ -static int tty_ldisc_wait_idle(struct tty_struct *tty, long timeout) +static bool tty_ldisc_hangup_halt(struct tty_struct *tty)  { -	long ret; -	ret = wait_event_timeout(tty->ldisc->wq_idle, -			atomic_read(&tty->ldisc->users) == 1, timeout); -	return ret > 0 ? 0 : -EBUSY; +	char cur_n[TASK_COMM_LEN], tty_n[64]; +	long timeout = 3 * HZ; + +	clear_bit(TTY_LDISC, &tty->flags); + +	if (tty->ldisc) {	/* Not yet closed */ +		tty_unlock(tty); + +		while (tty_ldisc_wait_idle(tty, timeout) == -EBUSY) { +			timeout = MAX_SCHEDULE_TIMEOUT; +			printk_ratelimited(KERN_WARNING +				"%s: waiting (%s) for %s took too long, but we keep waiting...\n", +				__func__, get_task_comm(cur_n, current), +				tty_name(tty, tty_n)); +		} + +		set_bit(TTY_LDISC_HALTED, &tty->flags); + +		/* must reacquire both locks and preserve lock order */ +		mutex_unlock(&tty->ldisc_mutex); +		tty_lock(tty); +		mutex_lock(&tty->ldisc_mutex); +	} +	return !!tty->ldisc;  }  /** @@ -563,7 +600,6 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)  {  	int retval;  	struct tty_ldisc *o_ldisc, *new_ldisc; -	int work, o_work = 0;  	struct tty_struct *o_tty;  	new_ldisc = tty_ldisc_get(ldisc); @@ -589,15 +625,6 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)  		return 0;  	} -	tty_unlock(tty); -	/* -	 *	Problem: What do we do if this blocks ? -	 *	We could deadlock here -	 */ - -	tty_wait_until_sent(tty, 0); - -	tty_lock(tty);  	mutex_lock(&tty->ldisc_mutex);  	/* @@ -637,20 +664,16 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)  	 *	parallel to the change and re-referencing the tty.  	 */ -	work = tty_ldisc_halt(tty); -	if (o_tty) -		o_work = tty_ldisc_halt(o_tty); +	retval = tty_ldisc_halt(tty, o_tty, 5 * HZ);  	/* -	 * Wait for ->hangup_work and ->buf.work handlers to terminate. +	 * Wait for hangup to complete, if pending.  	 * We must drop the mutex here in case a hangup is also in process.  	 */  	mutex_unlock(&tty->ldisc_mutex); -	tty_ldisc_flush_works(tty); - -	retval = tty_ldisc_wait_idle(tty, 5 * HZ); +	flush_work(&tty->hangup_work);  	tty_lock(tty);  	mutex_lock(&tty->ldisc_mutex); @@ -675,7 +698,7 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)  	tty_ldisc_close(tty, o_ldisc);  	/* Now set up the new line discipline. */ -	tty_ldisc_assign(tty, new_ldisc); +	tty->ldisc = new_ldisc;  	tty_set_termios_ldisc(tty, ldisc);  	retval = tty_ldisc_open(tty, new_ldisc); @@ -705,10 +728,10 @@ enable:  	/* Restart the work queue in case no characters kick it off. Safe if  	   already running */ -	if (work) -		schedule_work(&tty->port->buf.work); -	if (o_work) +	schedule_work(&tty->port->buf.work); +	if (o_tty)  		schedule_work(&o_tty->port->buf.work); +  	mutex_unlock(&tty->ldisc_mutex);  	tty_unlock(tty);  	return retval; @@ -749,11 +772,10 @@ static int tty_ldisc_reinit(struct tty_struct *tty, int ldisc)  	tty_ldisc_close(tty, tty->ldisc);  	tty_ldisc_put(tty->ldisc); -	tty->ldisc = NULL;  	/*  	 *	Switch the line discipline back  	 */ -	tty_ldisc_assign(tty, ld); +	tty->ldisc = ld;  	tty_set_termios_ldisc(tty, ldisc);  	return 0; @@ -780,6 +802,8 @@ void tty_ldisc_hangup(struct tty_struct *tty)  	int reset = tty->driver->flags & TTY_DRIVER_RESET_TERMIOS;  	int err = 0; +	tty_ldisc_debug(tty, "closing ldisc: %p\n", tty->ldisc); +  	/*  	 * FIXME! What are the locking issues here? This may me overdoing  	 * things... This question is especially important now that we've @@ -812,40 +836,12 @@ void tty_ldisc_hangup(struct tty_struct *tty)  	 */  	mutex_lock(&tty->ldisc_mutex); -	/* -	 * this is like tty_ldisc_halt, but we need to give up -	 * the BTM before calling cancel_work_sync, which may -	 * need to wait for another function taking the BTM -	 */ -	clear_bit(TTY_LDISC, &tty->flags); -	tty_unlock(tty); -	cancel_work_sync(&tty->port->buf.work); -	mutex_unlock(&tty->ldisc_mutex); -retry: -	tty_lock(tty); -	mutex_lock(&tty->ldisc_mutex); - -	/* At this point we have a closed ldisc and we want to -	   reopen it. We could defer this to the next open but -	   it means auditing a lot of other paths so this is -	   a FIXME */ -	if (tty->ldisc) {	/* Not yet closed */ -		if (atomic_read(&tty->ldisc->users) != 1) { -			char cur_n[TASK_COMM_LEN], tty_n[64]; -			long timeout = 3 * HZ; -			tty_unlock(tty); - -			while (tty_ldisc_wait_idle(tty, timeout) == -EBUSY) { -				timeout = MAX_SCHEDULE_TIMEOUT; -				printk_ratelimited(KERN_WARNING -					"%s: waiting (%s) for %s took too long, but we keep waiting...\n", -					__func__, get_task_comm(cur_n, current), -					tty_name(tty, tty_n)); -			} -			mutex_unlock(&tty->ldisc_mutex); -			goto retry; -		} +	if (tty_ldisc_hangup_halt(tty)) { +		/* At this point we have a halted ldisc; we want to close it and +		   reopen a new ldisc. We could defer the reopen to the next +		   open but it means auditing a lot of other paths so this is +		   a FIXME */  		if (reset == 0) {  			if (!tty_ldisc_reinit(tty, tty->termios.c_line)) @@ -864,6 +860,8 @@ retry:  	mutex_unlock(&tty->ldisc_mutex);  	if (reset)  		tty_reset_termios(tty); + +	tty_ldisc_debug(tty, "re-opened ldisc: %p\n", tty->ldisc);  }  /** @@ -899,11 +897,6 @@ int tty_ldisc_setup(struct tty_struct *tty, struct tty_struct *o_tty)  static void tty_ldisc_kill(struct tty_struct *tty)  { -	/* There cannot be users from userspace now. But there still might be -	 * drivers holding a reference via tty_ldisc_ref. Do not steal them the -	 * ldisc until they are done. */ -	tty_ldisc_wait_idle(tty, MAX_SCHEDULE_TIMEOUT); -  	mutex_lock(&tty->ldisc_mutex);  	/*  	 * Now kill off the ldisc @@ -931,18 +924,13 @@ static void tty_ldisc_kill(struct tty_struct *tty)  void tty_ldisc_release(struct tty_struct *tty, struct tty_struct *o_tty)  {  	/* -	 * Prevent flush_to_ldisc() from rescheduling the work for later.  Then -	 * kill any delayed work. As this is the final close it does not -	 * race with the set_ldisc code path. +	 * Shutdown this line discipline. As this is the final close, +	 * it does not race with the set_ldisc code path.  	 */ -	tty_ldisc_halt(tty); -	if (o_tty) -		tty_ldisc_halt(o_tty); +	tty_ldisc_debug(tty, "closing ldisc: %p\n", tty->ldisc); -	tty_ldisc_flush_works(tty); -	if (o_tty) -		tty_ldisc_flush_works(o_tty); +	tty_ldisc_halt(tty, o_tty, MAX_SCHEDULE_TIMEOUT);  	tty_lock_pair(tty, o_tty);  	/* This will need doing differently if we need to lock */ @@ -953,6 +941,8 @@ void tty_ldisc_release(struct tty_struct *tty, struct tty_struct *o_tty)  	tty_unlock_pair(tty, o_tty);  	/* And the memory resources remaining (buffers, termios) will be  	   disposed of when the kref hits zero */ + +	tty_ldisc_debug(tty, "ldisc closed\n");  }  /** @@ -968,7 +958,7 @@ void tty_ldisc_init(struct tty_struct *tty)  	struct tty_ldisc *ld = tty_ldisc_get(N_TTY);  	if (IS_ERR(ld))  		panic("n_tty: init_tty"); -	tty_ldisc_assign(tty, ld); +	tty->ldisc = ld;  }  /** @@ -980,8 +970,8 @@ void tty_ldisc_init(struct tty_struct *tty)   */  void tty_ldisc_deinit(struct tty_struct *tty)  { -	put_ldisc(tty->ldisc); -	tty_ldisc_assign(tty, NULL); +	tty_ldisc_put(tty->ldisc); +	tty->ldisc = NULL;  }  void tty_ldisc_begin(void) diff --git a/drivers/tty/tty_port.c b/drivers/tty/tty_port.c index b7ff59d3db8..121aeb9393e 100644 --- a/drivers/tty/tty_port.c +++ b/drivers/tty/tty_port.c @@ -132,6 +132,7 @@ EXPORT_SYMBOL(tty_port_free_xmit_buf);   */  void tty_port_destroy(struct tty_port *port)  { +	cancel_work_sync(&port->buf.work);  	tty_buffer_free_all(port);  }  EXPORT_SYMBOL(tty_port_destroy); @@ -196,12 +197,24 @@ void tty_port_tty_set(struct tty_port *port, struct tty_struct *tty)  }  EXPORT_SYMBOL(tty_port_tty_set); -static void tty_port_shutdown(struct tty_port *port) +static void tty_port_shutdown(struct tty_port *port, struct tty_struct *tty)  {  	mutex_lock(&port->mutex); -	if (port->ops->shutdown && !port->console && -		test_and_clear_bit(ASYNCB_INITIALIZED, &port->flags)) +	if (port->console) +		goto out; + +	if (test_and_clear_bit(ASYNCB_INITIALIZED, &port->flags)) { +		/* +		 * Drop DTR/RTS if HUPCL is set. This causes any attached +		 * modem to hang up the line. +		 */ +		if (tty && C_HUPCL(tty)) +			tty_port_lower_dtr_rts(port); + +		if (port->ops->shutdown)  			port->ops->shutdown(port); +	} +out:  	mutex_unlock(&port->mutex);  } @@ -215,24 +228,58 @@ static void tty_port_shutdown(struct tty_port *port)  void tty_port_hangup(struct tty_port *port)  { +	struct tty_struct *tty;  	unsigned long flags;  	spin_lock_irqsave(&port->lock, flags);  	port->count = 0;  	port->flags &= ~ASYNC_NORMAL_ACTIVE; -	if (port->tty) { -		set_bit(TTY_IO_ERROR, &port->tty->flags); -		tty_kref_put(port->tty); -	} +	tty = port->tty; +	if (tty) +		set_bit(TTY_IO_ERROR, &tty->flags);  	port->tty = NULL;  	spin_unlock_irqrestore(&port->lock, flags); +	tty_port_shutdown(port, tty); +	tty_kref_put(tty);  	wake_up_interruptible(&port->open_wait);  	wake_up_interruptible(&port->delta_msr_wait); -	tty_port_shutdown(port);  }  EXPORT_SYMBOL(tty_port_hangup);  /** + * tty_port_tty_hangup - helper to hang up a tty + * + * @port: tty port + * @check_clocal: hang only ttys with CLOCAL unset? + */ +void tty_port_tty_hangup(struct tty_port *port, bool check_clocal) +{ +	struct tty_struct *tty = tty_port_tty_get(port); + +	if (tty && (!check_clocal || !C_CLOCAL(tty))) { +		tty_hangup(tty); +		tty_kref_put(tty); +	} +} +EXPORT_SYMBOL_GPL(tty_port_tty_hangup); + +/** + * tty_port_tty_wakeup - helper to wake up a tty + * + * @port: tty port + */ +void tty_port_tty_wakeup(struct tty_port *port) +{ +	struct tty_struct *tty = tty_port_tty_get(port); + +	if (tty) { +		tty_wakeup(tty); +		tty_kref_put(tty); +	} +} +EXPORT_SYMBOL_GPL(tty_port_tty_wakeup); + +/**   *	tty_port_carrier_raised	-	carrier raised check   *	@port: tty port   * @@ -350,7 +397,7 @@ int tty_port_block_til_ready(struct tty_port *port,  	while (1) {  		/* Indicate we are open */ -		if (tty->termios.c_cflag & CBAUD) +		if (C_BAUD(tty) && test_bit(ASYNCB_INITIALIZED, &port->flags))  			tty_port_raise_dtr_rts(port);  		prepare_to_wait(&port->open_wait, &wait, TASK_INTERRUPTIBLE); @@ -395,6 +442,20 @@ int tty_port_block_til_ready(struct tty_port *port,  }  EXPORT_SYMBOL(tty_port_block_til_ready); +static void tty_port_drain_delay(struct tty_port *port, struct tty_struct *tty) +{ +	unsigned int bps = tty_get_baud_rate(tty); +	long timeout; + +	if (bps > 1200) { +		timeout = (HZ * 10 * port->drain_delay) / bps; +		timeout = max_t(long, timeout, HZ / 10); +	} else { +		timeout = 2 * HZ; +	} +	schedule_timeout_interruptible(timeout); +} +  int tty_port_close_start(struct tty_port *port,  				struct tty_struct *tty, struct file *filp)  { @@ -427,31 +488,19 @@ int tty_port_close_start(struct tty_port *port,  	set_bit(ASYNCB_CLOSING, &port->flags);  	tty->closing = 1;  	spin_unlock_irqrestore(&port->lock, flags); -	/* Don't block on a stalled port, just pull the chain */ -	if (tty->flow_stopped) -		tty_driver_flush_buffer(tty); -	if (test_bit(ASYNCB_INITIALIZED, &port->flags) && -			port->closing_wait != ASYNC_CLOSING_WAIT_NONE) -		tty_wait_until_sent_from_close(tty, port->closing_wait); -	if (port->drain_delay) { -		unsigned int bps = tty_get_baud_rate(tty); -		long timeout; -		if (bps > 1200) -			timeout = max_t(long, -				(HZ * 10 * port->drain_delay) / bps, HZ / 10); -		else -			timeout = 2 * HZ; -		schedule_timeout_interruptible(timeout); +	if (test_bit(ASYNCB_INITIALIZED, &port->flags)) { +		/* Don't block on a stalled port, just pull the chain */ +		if (tty->flow_stopped) +			tty_driver_flush_buffer(tty); +		if (port->closing_wait != ASYNC_CLOSING_WAIT_NONE) +			tty_wait_until_sent_from_close(tty, port->closing_wait); +		if (port->drain_delay) +			tty_port_drain_delay(port, tty);  	}  	/* Flush the ldisc buffering */  	tty_ldisc_flush(tty); -	/* Drop DTR/RTS if HUPCL is set. This causes any attached modem to -	   hang up the line */ -	if (tty->termios.c_cflag & HUPCL) -		tty_port_lower_dtr_rts(port); -  	/* Don't call port->drop for the last reference. Callers will want  	   to drop the last active reference in ->shutdown() or the tty  	   shutdown path */ @@ -486,7 +535,7 @@ void tty_port_close(struct tty_port *port, struct tty_struct *tty,  {  	if (tty_port_close_start(port, tty, filp) == 0)  		return; -	tty_port_shutdown(port); +	tty_port_shutdown(port, tty);  	set_bit(TTY_IO_ERROR, &tty->flags);  	tty_port_close_end(port, tty);  	tty_port_tty_set(port, NULL); diff --git a/drivers/tty/vt/consolemap.c b/drivers/tty/vt/consolemap.c index 248381b3072..2978ca596a7 100644 --- a/drivers/tty/vt/consolemap.c +++ b/drivers/tty/vt/consolemap.c @@ -194,8 +194,7 @@ static void set_inverse_transl(struct vc_data *conp, struct uni_pagedir *p, int  	q = p->inverse_translations[i];  	if (!q) { -		q = p->inverse_translations[i] = (unsigned char *)  -			kmalloc(MAX_GLYPH, GFP_KERNEL); +		q = p->inverse_translations[i] = kmalloc(MAX_GLYPH, GFP_KERNEL);  		if (!q) return;  	}  	memset(q, 0, MAX_GLYPH); diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index 387dc6c8ad2..c77f7ae48f1 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -292,7 +292,6 @@ static void acm_ctrl_irq(struct urb *urb)  {  	struct acm *acm = urb->context;  	struct usb_cdc_notification *dr = urb->transfer_buffer; -	struct tty_struct *tty;  	unsigned char *data;  	int newctrl;  	int retval; @@ -327,17 +326,12 @@ static void acm_ctrl_irq(struct urb *urb)  		break;  	case USB_CDC_NOTIFY_SERIAL_STATE: -		tty = tty_port_tty_get(&acm->port);  		newctrl = get_unaligned_le16(data); -		if (tty) { -			if (!acm->clocal && -				(acm->ctrlin & ~newctrl & ACM_CTRL_DCD)) { -				dev_dbg(&acm->control->dev, -					"%s - calling hangup\n", __func__); -				tty_hangup(tty); -			} -			tty_kref_put(tty); +		if (!acm->clocal && (acm->ctrlin & ~newctrl & ACM_CTRL_DCD)) { +			dev_dbg(&acm->control->dev, "%s - calling hangup\n", +					__func__); +			tty_port_tty_hangup(&acm->port, false);  		}  		acm->ctrlin = newctrl; @@ -475,15 +469,10 @@ static void acm_write_bulk(struct urb *urb)  static void acm_softint(struct work_struct *work)  {  	struct acm *acm = container_of(work, struct acm, work); -	struct tty_struct *tty;  	dev_vdbg(&acm->data->dev, "%s\n", __func__); -	tty = tty_port_tty_get(&acm->port); -	if (!tty) -		return; -	tty_wakeup(tty); -	tty_kref_put(tty); +	tty_port_tty_wakeup(&acm->port);  }  /* @@ -1519,15 +1508,9 @@ err_out:  static int acm_reset_resume(struct usb_interface *intf)  {  	struct acm *acm = usb_get_intfdata(intf); -	struct tty_struct *tty; -	if (test_bit(ASYNCB_INITIALIZED, &acm->port.flags)) { -		tty = tty_port_tty_get(&acm->port); -		if (tty) { -			tty_hangup(tty); -			tty_kref_put(tty); -		} -	} +	if (test_bit(ASYNCB_INITIALIZED, &acm->port.flags)) +		tty_port_tty_hangup(&acm->port, false);  	return acm_resume(intf);  } diff --git a/drivers/usb/serial/digi_acceleport.c b/drivers/usb/serial/digi_acceleport.c index ebe45fa0ed5..31191581060 100644 --- a/drivers/usb/serial/digi_acceleport.c +++ b/drivers/usb/serial/digi_acceleport.c @@ -210,7 +210,6 @@ struct digi_port {  /* Local Function Declarations */ -static void digi_wakeup_write(struct usb_serial_port *port);  static void digi_wakeup_write_lock(struct work_struct *work);  static int digi_write_oob_command(struct usb_serial_port *port,  	unsigned char *buf, int count, int interruptible); @@ -374,20 +373,10 @@ static void digi_wakeup_write_lock(struct work_struct *work)  	unsigned long flags;  	spin_lock_irqsave(&priv->dp_port_lock, flags); -	digi_wakeup_write(port); +	tty_port_tty_wakeup(&port->port);  	spin_unlock_irqrestore(&priv->dp_port_lock, flags);  } -static void digi_wakeup_write(struct usb_serial_port *port) -{ -	struct tty_struct *tty = tty_port_tty_get(&port->port); -	if (tty) { -		tty_wakeup(tty); -		tty_kref_put(tty); -	} -} - -  /*   *  Digi Write OOB Command   * @@ -1044,7 +1033,7 @@ static void digi_write_bulk_callback(struct urb *urb)  		}  	}  	/* wake up processes sleeping on writes immediately */ -	digi_wakeup_write(port); +	tty_port_tty_wakeup(&port->port);  	/* also queue up a wakeup at scheduler time, in case we */  	/* lost the race in write_chan(). */  	schedule_work(&priv->dp_wakeup_work); @@ -1522,7 +1511,7 @@ static int digi_read_oob_callback(struct urb *urb)  				/* port must be open to use tty struct */  				if (rts) {  					tty->hw_stopped = 0; -					digi_wakeup_write(port); +					tty_port_tty_wakeup(&port->port);  				}  			} else {  				priv->dp_modem_signals &= ~TIOCM_CTS; diff --git a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c index efd8b978128..cf0b0a2f7b5 100644 --- a/drivers/usb/serial/io_edgeport.c +++ b/drivers/usb/serial/io_edgeport.c @@ -564,7 +564,6 @@ static void edge_interrupt_callback(struct urb *urb)  	struct device *dev;  	struct edgeport_port *edge_port;  	struct usb_serial_port *port; -	struct tty_struct *tty;  	unsigned char *data = urb->transfer_buffer;  	int length = urb->actual_length;  	int bytes_avail; @@ -643,12 +642,7 @@ static void edge_interrupt_callback(struct urb *urb)  					/* tell the tty driver that something  					   has changed */ -					tty = tty_port_tty_get( -						&edge_port->port->port); -					if (tty) { -						tty_wakeup(tty); -						tty_kref_put(tty); -					} +					tty_port_tty_wakeup(&edge_port->port->port);  					/* Since we have more credit, check  					   if more data can be sent */  					send_more_port_data(edge_serial, @@ -737,7 +731,6 @@ static void edge_bulk_in_callback(struct urb *urb)  static void edge_bulk_out_data_callback(struct urb *urb)  {  	struct edgeport_port *edge_port = urb->context; -	struct tty_struct *tty;  	int status = urb->status;  	if (status) { @@ -746,14 +739,8 @@ static void edge_bulk_out_data_callback(struct urb *urb)  			__func__, status);  	} -	tty = tty_port_tty_get(&edge_port->port->port); - -	if (tty && edge_port->open) { -		/* let the tty driver wakeup if it has a special -		   write_wakeup function */ -		tty_wakeup(tty); -	} -	tty_kref_put(tty); +	if (edge_port->open) +		tty_port_tty_wakeup(&edge_port->port->port);  	/* Release the Write URB */  	edge_port->write_in_progress = false; @@ -772,7 +759,6 @@ static void edge_bulk_out_data_callback(struct urb *urb)  static void edge_bulk_out_cmd_callback(struct urb *urb)  {  	struct edgeport_port *edge_port = urb->context; -	struct tty_struct *tty;  	int status = urb->status;  	atomic_dec(&CmdUrbs); @@ -793,13 +779,9 @@ static void edge_bulk_out_cmd_callback(struct urb *urb)  		return;  	} -	/* Get pointer to tty */ -	tty = tty_port_tty_get(&edge_port->port->port); -  	/* tell the tty driver that something has changed */ -	if (tty && edge_port->open) -		tty_wakeup(tty); -	tty_kref_put(tty); +	if (edge_port->open) +		tty_port_tty_wakeup(&edge_port->port->port);  	/* we have completed the command */  	edge_port->commandPending = false; diff --git a/drivers/usb/serial/keyspan.c b/drivers/usb/serial/keyspan.c index 1fd1935c831..b011478d2e5 100644 --- a/drivers/usb/serial/keyspan.c +++ b/drivers/usb/serial/keyspan.c @@ -378,7 +378,6 @@ static void	usa26_instat_callback(struct urb *urb)  	struct usb_serial			*serial;  	struct usb_serial_port			*port;  	struct keyspan_port_private	 	*p_priv; -	struct tty_struct			*tty;  	int old_dcd_state, err;  	int status = urb->status; @@ -421,12 +420,8 @@ static void	usa26_instat_callback(struct urb *urb)  	p_priv->dcd_state = ((msg->gpia_dcd) ? 1 : 0);  	p_priv->ri_state = ((msg->ri) ? 1 : 0); -	if (old_dcd_state != p_priv->dcd_state) { -		tty = tty_port_tty_get(&port->port); -		if (tty && !C_CLOCAL(tty)) -			tty_hangup(tty); -		tty_kref_put(tty); -	} +	if (old_dcd_state != p_priv->dcd_state) +		tty_port_tty_hangup(&port->port, true);  	/* Resubmit urb so we continue receiving */  	err = usb_submit_urb(urb, GFP_ATOMIC); @@ -510,7 +505,6 @@ static void	usa28_instat_callback(struct urb *urb)  	struct usb_serial			*serial;  	struct usb_serial_port			*port;  	struct keyspan_port_private	 	*p_priv; -	struct tty_struct			*tty;  	int old_dcd_state;  	int status = urb->status; @@ -551,12 +545,8 @@ static void	usa28_instat_callback(struct urb *urb)  	p_priv->dcd_state = ((msg->dcd) ? 1 : 0);  	p_priv->ri_state = ((msg->ri) ? 1 : 0); -	if (old_dcd_state != p_priv->dcd_state && old_dcd_state) { -		tty = tty_port_tty_get(&port->port); -		if (tty && !C_CLOCAL(tty)) -			tty_hangup(tty); -		tty_kref_put(tty); -	} +	if (old_dcd_state != p_priv->dcd_state && old_dcd_state) +		tty_port_tty_hangup(&port->port, true);  		/* Resubmit urb so we continue receiving */  	err = usb_submit_urb(urb, GFP_ATOMIC); @@ -642,12 +632,8 @@ static void	usa49_instat_callback(struct urb *urb)  	p_priv->dcd_state = ((msg->dcd) ? 1 : 0);  	p_priv->ri_state = ((msg->ri) ? 1 : 0); -	if (old_dcd_state != p_priv->dcd_state && old_dcd_state) { -		struct tty_struct *tty = tty_port_tty_get(&port->port); -		if (tty && !C_CLOCAL(tty)) -			tty_hangup(tty); -		tty_kref_put(tty); -	} +	if (old_dcd_state != p_priv->dcd_state && old_dcd_state) +		tty_port_tty_hangup(&port->port, true);  	/* Resubmit urb so we continue receiving */  	err = usb_submit_urb(urb, GFP_ATOMIC); @@ -851,7 +837,6 @@ static void	usa90_instat_callback(struct urb *urb)  	struct usb_serial			*serial;  	struct usb_serial_port			*port;  	struct keyspan_port_private	 	*p_priv; -	struct tty_struct			*tty;  	int old_dcd_state, err;  	int status = urb->status; @@ -880,12 +865,8 @@ static void	usa90_instat_callback(struct urb *urb)  	p_priv->dcd_state = ((msg->dcd) ? 1 : 0);  	p_priv->ri_state = ((msg->ri) ? 1 : 0); -	if (old_dcd_state != p_priv->dcd_state && old_dcd_state) { -		tty = tty_port_tty_get(&port->port); -		if (tty && !C_CLOCAL(tty)) -			tty_hangup(tty); -		tty_kref_put(tty); -	} +	if (old_dcd_state != p_priv->dcd_state && old_dcd_state) +		tty_port_tty_hangup(&port->port, true);  	/* Resubmit urb so we continue receiving */  	err = usb_submit_urb(urb, GFP_ATOMIC); @@ -953,12 +934,8 @@ static void	usa67_instat_callback(struct urb *urb)  	p_priv->cts_state = ((msg->hskia_cts) ? 1 : 0);  	p_priv->dcd_state = ((msg->gpia_dcd) ? 1 : 0); -	if (old_dcd_state != p_priv->dcd_state && old_dcd_state) { -		struct tty_struct *tty = tty_port_tty_get(&port->port); -		if (tty && !C_CLOCAL(tty)) -			tty_hangup(tty); -		tty_kref_put(tty); -	} +	if (old_dcd_state != p_priv->dcd_state && old_dcd_state) +		tty_port_tty_hangup(&port->port, true);  	/* Resubmit urb so we continue receiving */  	err = usb_submit_urb(urb, GFP_ATOMIC); diff --git a/drivers/usb/serial/keyspan_pda.c b/drivers/usb/serial/keyspan_pda.c index 3b17d5d13dc..2230223978c 100644 --- a/drivers/usb/serial/keyspan_pda.c +++ b/drivers/usb/serial/keyspan_pda.c @@ -104,10 +104,8 @@ static void keyspan_pda_wakeup_write(struct work_struct *work)  	struct keyspan_pda_private *priv =  		container_of(work, struct keyspan_pda_private, wakeup_work);  	struct usb_serial_port *port = priv->port; -	struct tty_struct *tty = tty_port_tty_get(&port->port); -	if (tty) -		tty_wakeup(tty); -	tty_kref_put(tty); + +	tty_port_tty_wakeup(&port->port);  }  static void keyspan_pda_request_unthrottle(struct work_struct *work) diff --git a/drivers/usb/serial/mos7720.c b/drivers/usb/serial/mos7720.c index e0ebec3b5d6..e956eae198f 100644 --- a/drivers/usb/serial/mos7720.c +++ b/drivers/usb/serial/mos7720.c @@ -932,7 +932,6 @@ static void mos7720_bulk_in_callback(struct urb *urb)  static void mos7720_bulk_out_data_callback(struct urb *urb)  {  	struct moschip_port *mos7720_port; -	struct tty_struct *tty;  	int status = urb->status;  	if (status) { @@ -946,11 +945,8 @@ static void mos7720_bulk_out_data_callback(struct urb *urb)  		return ;  	} -	tty = tty_port_tty_get(&mos7720_port->port->port); - -	if (tty && mos7720_port->open) -		tty_wakeup(tty); -	tty_kref_put(tty); +	if (mos7720_port->open) +		tty_port_tty_wakeup(&mos7720_port->port->port);  }  /* diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c index b8051fa6191..2be376a2e0e 100644 --- a/drivers/usb/serial/mos7840.c +++ b/drivers/usb/serial/mos7840.c @@ -816,7 +816,6 @@ static void mos7840_bulk_out_data_callback(struct urb *urb)  {  	struct moschip_port *mos7840_port;  	struct usb_serial_port *port; -	struct tty_struct *tty;  	int status = urb->status;  	int i; @@ -839,10 +838,8 @@ static void mos7840_bulk_out_data_callback(struct urb *urb)  	if (mos7840_port_paranoia_check(port, __func__))  		return; -	tty = tty_port_tty_get(&port->port); -	if (tty && mos7840_port->open) -		tty_wakeup(tty); -	tty_kref_put(tty); +	if (mos7840_port->open) +		tty_port_tty_wakeup(&port->port);  } diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index 558adfc0500..09cd3967b8d 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -1537,13 +1537,8 @@ static void option_instat_callback(struct urb *urb)  			portdata->dsr_state = ((signals & 0x02) ? 1 : 0);  			portdata->ri_state = ((signals & 0x08) ? 1 : 0); -			if (old_dcd_state && !portdata->dcd_state) { -				struct tty_struct *tty = -						tty_port_tty_get(&port->port); -				if (tty && !C_CLOCAL(tty)) -					tty_hangup(tty); -				tty_kref_put(tty); -			} +			if (old_dcd_state && !portdata->dcd_state) +				tty_port_tty_hangup(&port->port, true);  		} else {  			dev_dbg(dev, "%s: type %x req %x\n", __func__,  				req_pkt->bRequestType, req_pkt->bRequest); diff --git a/drivers/usb/serial/quatech2.c b/drivers/usb/serial/quatech2.c index 75f125ddb0c..ef3a7d5eaab 100644 --- a/drivers/usb/serial/quatech2.c +++ b/drivers/usb/serial/quatech2.c @@ -116,7 +116,6 @@ struct qt2_serial_private {  };  struct qt2_port_private { -	bool is_open;  	u8   device_port;  	spinlock_t urb_lock; @@ -397,7 +396,6 @@ static int qt2_open(struct tty_struct *tty, struct usb_serial_port *port)  		return status;  	} -	port_priv->is_open = true;  	port_priv->device_port = (u8) device_port;  	if (tty) @@ -417,8 +415,6 @@ static void qt2_close(struct usb_serial_port *port)  	serial = port->serial;  	port_priv = usb_get_serial_port_data(port); -	port_priv->is_open = false; -  	spin_lock_irqsave(&port_priv->urb_lock, flags);  	usb_kill_urb(port_priv->write_urb);  	port_priv->urb_in_use = false; @@ -664,9 +660,7 @@ void qt2_process_read_urb(struct urb *urb)  						 __func__);  					break;  				} - -				if (port_priv->is_open) -					tty_flip_buffer_push(&port->port); +				tty_flip_buffer_push(&port->port);  				newport = *(ch + 3); @@ -709,8 +703,7 @@ void qt2_process_read_urb(struct urb *urb)  		tty_insert_flip_string(&port->port, ch, 1);  	} -	if (port_priv->is_open) -		tty_flip_buffer_push(&port->port); +	tty_flip_buffer_push(&port->port);  }  static void qt2_write_bulk_callback(struct urb *urb) @@ -910,12 +903,6 @@ static void qt2_break_ctl(struct tty_struct *tty, int break_state)  	port_priv = usb_get_serial_port_data(port); -	if (!port_priv->is_open) { -		dev_err(&port->dev, -			"%s - port is not open\n", __func__); -		return; -	} -  	val = (break_state == -1) ? 1 : 0;  	status = qt2_control_msg(port->serial->dev, QT2_BREAK_CONTROL, diff --git a/drivers/usb/serial/sierra.c b/drivers/usb/serial/sierra.c index c13f6e74774..d66148a17fe 100644 --- a/drivers/usb/serial/sierra.c +++ b/drivers/usb/serial/sierra.c @@ -628,7 +628,6 @@ static void sierra_instat_callback(struct urb *urb)  			unsigned char signals = *((unsigned char *)  					urb->transfer_buffer +  					sizeof(struct usb_ctrlrequest)); -			struct tty_struct *tty;  			dev_dbg(&port->dev, "%s: signal x%x\n", __func__,  				signals); @@ -639,11 +638,8 @@ static void sierra_instat_callback(struct urb *urb)  			portdata->dsr_state = ((signals & 0x02) ? 1 : 0);  			portdata->ri_state = ((signals & 0x08) ? 1 : 0); -			tty = tty_port_tty_get(&port->port); -			if (tty && !C_CLOCAL(tty) && -					old_dcd_state && !portdata->dcd_state) -				tty_hangup(tty); -			tty_kref_put(tty); +			if (old_dcd_state && !portdata->dcd_state) +				tty_port_tty_hangup(&port->port, true);  		} else {  			dev_dbg(&port->dev, "%s: type %x req %x\n",  				__func__, req_pkt->bRequestType, diff --git a/drivers/usb/serial/ti_usb_3410_5052.c b/drivers/usb/serial/ti_usb_3410_5052.c index 73deb029fc0..19a71a9eecf 100644 --- a/drivers/usb/serial/ti_usb_3410_5052.c +++ b/drivers/usb/serial/ti_usb_3410_5052.c @@ -1229,7 +1229,6 @@ static void ti_send(struct ti_port *tport)  {  	int count, result;  	struct usb_serial_port *port = tport->tp_port; -	struct tty_struct *tty = tty_port_tty_get(&port->port);	/* FIXME */  	unsigned long flags;  	spin_lock_irqsave(&tport->tp_lock, flags); @@ -1270,14 +1269,12 @@ static void ti_send(struct ti_port *tport)  	}  	/* more room in the buffer for new writes, wakeup */ -	if (tty) -		tty_wakeup(tty); -	tty_kref_put(tty); +	tty_port_tty_wakeup(&port->port); +  	wake_up_interruptible(&tport->tp_write_wait);  	return;  unlock:  	spin_unlock_irqrestore(&tport->tp_lock, flags); -	tty_kref_put(tty);  	return;  } diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index 5d9b178484f..650be17a68f 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c @@ -542,16 +542,8 @@ static void usb_serial_port_work(struct work_struct *work)  {  	struct usb_serial_port *port =  		container_of(work, struct usb_serial_port, work); -	struct tty_struct *tty; -	tty = tty_port_tty_get(&port->port); -	if (!tty) -		return; - -	dev_dbg(tty->dev, "%s - port %d\n", __func__, port->number); - -	tty_wakeup(tty); -	tty_kref_put(tty); +	tty_port_tty_wakeup(&port->port);  }  static void kill_traffic(struct usb_serial_port *port) diff --git a/include/linux/amba/serial.h b/include/linux/amba/serial.h index f612c783170..62d9303c283 100644 --- a/include/linux/amba/serial.h +++ b/include/linux/amba/serial.h @@ -203,6 +203,9 @@ struct amba_pl011_data {  	bool (*dma_filter)(struct dma_chan *chan, void *filter_param);  	void *dma_rx_param;  	void *dma_tx_param; +	bool dma_rx_poll_enable; +	unsigned int dma_rx_poll_rate; +	unsigned int dma_rx_poll_timeout;          void (*init) (void);  	void (*exit) (void);  }; diff --git a/include/linux/tty.h b/include/linux/tty.h index c75d886b030..367a9dfc4ea 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h @@ -255,9 +255,9 @@ struct tty_struct {  	int count;  	struct winsize winsize;		/* termios mutex */  	unsigned char stopped:1, hw_stopped:1, flow_stopped:1, packet:1; -	unsigned char warned:1;  	unsigned char ctrl_status;	/* ctrl_lock */  	unsigned int receive_room;	/* Bytes free for queue */ +	int flow_change;  	struct tty_struct *link;  	struct fasync_struct *fasync; @@ -315,9 +315,25 @@ struct tty_file_private {  #define TTY_NO_WRITE_SPLIT 	17	/* Preserve write boundaries to driver */  #define TTY_HUPPED 		18	/* Post driver->hangup() */  #define TTY_HUPPING 		21	/* ->hangup() in progress */ +#define TTY_LDISC_HALTED	22	/* Line discipline is halted */  #define TTY_WRITE_FLUSH(tty) tty_write_flush((tty)) +/* Values for tty->flow_change */ +#define TTY_THROTTLE_SAFE 1 +#define TTY_UNTHROTTLE_SAFE 2 + +static inline void __tty_set_flow_change(struct tty_struct *tty, int val) +{ +	tty->flow_change = val; +} + +static inline void tty_set_flow_change(struct tty_struct *tty, int val) +{ +	tty->flow_change = val; +	smp_mb(); +} +  #ifdef CONFIG_TTY  extern void console_init(void);  extern void tty_kref_put(struct tty_struct *tty); @@ -400,6 +416,8 @@ extern int tty_write_room(struct tty_struct *tty);  extern void tty_driver_flush_buffer(struct tty_struct *tty);  extern void tty_throttle(struct tty_struct *tty);  extern void tty_unthrottle(struct tty_struct *tty); +extern int tty_throttle_safe(struct tty_struct *tty); +extern int tty_unthrottle_safe(struct tty_struct *tty);  extern int tty_do_resize(struct tty_struct *tty, struct winsize *ws);  extern void tty_driver_remove_tty(struct tty_driver *driver,  				  struct tty_struct *tty); @@ -419,13 +437,28 @@ extern void tty_flush_to_ldisc(struct tty_struct *tty);  extern void tty_buffer_free_all(struct tty_port *port);  extern void tty_buffer_flush(struct tty_struct *tty);  extern void tty_buffer_init(struct tty_port *port); -extern speed_t tty_get_baud_rate(struct tty_struct *tty);  extern speed_t tty_termios_baud_rate(struct ktermios *termios);  extern speed_t tty_termios_input_baud_rate(struct ktermios *termios);  extern void tty_termios_encode_baud_rate(struct ktermios *termios,  						speed_t ibaud, speed_t obaud);  extern void tty_encode_baud_rate(struct tty_struct *tty,  						speed_t ibaud, speed_t obaud); + +/** + *	tty_get_baud_rate	-	get tty bit rates + *	@tty: tty to query + * + *	Returns the baud rate as an integer for this terminal. The + *	termios lock must be held by the caller and the terminal bit + *	flags may be updated. + * + *	Locking: none + */ +static inline speed_t tty_get_baud_rate(struct tty_struct *tty) +{ +	return tty_termios_baud_rate(&tty->termios); +} +  extern void tty_termios_copy_hw(struct ktermios *new, struct ktermios *old);  extern int tty_termios_hw_change(struct ktermios *a, struct ktermios *b);  extern int tty_set_termios(struct tty_struct *tty, struct ktermios *kt); @@ -502,6 +535,8 @@ extern int tty_port_carrier_raised(struct tty_port *port);  extern void tty_port_raise_dtr_rts(struct tty_port *port);  extern void tty_port_lower_dtr_rts(struct tty_port *port);  extern void tty_port_hangup(struct tty_port *port); +extern void tty_port_tty_hangup(struct tty_port *port, bool check_clocal); +extern void tty_port_tty_wakeup(struct tty_port *port);  extern int tty_port_block_til_ready(struct tty_port *port,  				struct tty_struct *tty, struct file *filp);  extern int tty_port_close_start(struct tty_port *port, @@ -526,8 +561,6 @@ extern void tty_ldisc_release(struct tty_struct *tty, struct tty_struct *o_tty);  extern void tty_ldisc_init(struct tty_struct *tty);  extern void tty_ldisc_deinit(struct tty_struct *tty);  extern void tty_ldisc_begin(void); -/* This last one is just for the tty layer internals and shouldn't be used elsewhere */ -extern void tty_ldisc_enable(struct tty_struct *tty);  /* n_tty.c */ diff --git a/include/linux/tty_ldisc.h b/include/linux/tty_ldisc.h index 455a0d7bf22..58390c73df8 100644 --- a/include/linux/tty_ldisc.h +++ b/include/linux/tty_ldisc.h @@ -9,89 +9,89 @@   *   * int	(*open)(struct tty_struct *);   * - * 	This function is called when the line discipline is associated - * 	with the tty.  The line discipline can use this as an - * 	opportunity to initialize any state needed by the ldisc routines. - *  + *	This function is called when the line discipline is associated + *	with the tty.  The line discipline can use this as an + *	opportunity to initialize any state needed by the ldisc routines. + *   * void	(*close)(struct tty_struct *);   *   *	This function is called when the line discipline is being - * 	shutdown, either because the tty is being closed or because - * 	the tty is being changed to use a new line discipline - *  + *	shutdown, either because the tty is being closed or because + *	the tty is being changed to use a new line discipline + *   * void	(*flush_buffer)(struct tty_struct *tty);   * - * 	This function instructs the line discipline to clear its - * 	buffers of any input characters it may have queued to be - * 	delivered to the user mode process. - *  + *	This function instructs the line discipline to clear its + *	buffers of any input characters it may have queued to be + *	delivered to the user mode process. + *   * ssize_t (*chars_in_buffer)(struct tty_struct *tty);   * - * 	This function returns the number of input characters the line + *	This function returns the number of input characters the line   *	discipline may have queued up to be delivered to the user mode   *	process. - *  + *   * ssize_t (*read)(struct tty_struct * tty, struct file * file,   *		   unsigned char * buf, size_t nr);   * - * 	This function is called when the user requests to read from - * 	the tty.  The line discipline will return whatever characters - * 	it has buffered up for the user.  If this function is not - * 	defined, the user will receive an EIO error. - *  + *	This function is called when the user requests to read from + *	the tty.  The line discipline will return whatever characters + *	it has buffered up for the user.  If this function is not + *	defined, the user will receive an EIO error. + *   * ssize_t (*write)(struct tty_struct * tty, struct file * file, - * 		    const unsigned char * buf, size_t nr); + *		    const unsigned char * buf, size_t nr); + * + *	This function is called when the user requests to write to the + *	tty.  The line discipline will deliver the characters to the + *	low-level tty device for transmission, optionally performing + *	some processing on the characters first.  If this function is + *	not defined, the user will receive an EIO error.   * - * 	This function is called when the user requests to write to the - * 	tty.  The line discipline will deliver the characters to the - * 	low-level tty device for transmission, optionally performing - * 	some processing on the characters first.  If this function is - * 	not defined, the user will receive an EIO error. - *    * int	(*ioctl)(struct tty_struct * tty, struct file * file, - * 		 unsigned int cmd, unsigned long arg); + *		 unsigned int cmd, unsigned long arg);   *   *	This function is called when the user requests an ioctl which - * 	is not handled by the tty layer or the low-level tty driver. - * 	It is intended for ioctls which affect line discpline - * 	operation.  Note that the search order for ioctls is (1) tty - * 	layer, (2) tty low-level driver, (3) line discpline.  So a - * 	low-level driver can "grab" an ioctl request before the line - * 	discpline has a chance to see it. - *  + *	is not handled by the tty layer or the low-level tty driver. + *	It is intended for ioctls which affect line discpline + *	operation.  Note that the search order for ioctls is (1) tty + *	layer, (2) tty low-level driver, (3) line discpline.  So a + *	low-level driver can "grab" an ioctl request before the line + *	discpline has a chance to see it. + *   * long	(*compat_ioctl)(struct tty_struct * tty, struct file * file, - * 		        unsigned int cmd, unsigned long arg); + *		        unsigned int cmd, unsigned long arg);   * - *      Process ioctl calls from 32-bit process on 64-bit system + *	Process ioctl calls from 32-bit process on 64-bit system   *   * void	(*set_termios)(struct tty_struct *tty, struct ktermios * old);   * - * 	This function notifies the line discpline that a change has - * 	been made to the termios structure. - *  + *	This function notifies the line discpline that a change has + *	been made to the termios structure. + *   * int	(*poll)(struct tty_struct * tty, struct file * file, - * 		  poll_table *wait); + *		  poll_table *wait);   * - * 	This function is called when a user attempts to select/poll on a - * 	tty device.  It is solely the responsibility of the line - * 	discipline to handle poll requests. + *	This function is called when a user attempts to select/poll on a + *	tty device.  It is solely the responsibility of the line + *	discipline to handle poll requests.   *   * void	(*receive_buf)(struct tty_struct *, const unsigned char *cp, - * 		       char *fp, int count); + *		       char *fp, int count); + * + *	This function is called by the low-level tty driver to send + *	characters received by the hardware to the line discpline for + *	processing.  <cp> is a pointer to the buffer of input + *	character received by the device.  <fp> is a pointer to a + *	pointer of flag bytes which indicate whether a character was + *	received with a parity error, etc.   * - * 	This function is called by the low-level tty driver to send - * 	characters received by the hardware to the line discpline for - * 	processing.  <cp> is a pointer to the buffer of input - * 	character received by the device.  <fp> is a pointer to a - * 	pointer of flag bytes which indicate whether a character was - * 	received with a parity error, etc. - *    * void	(*write_wakeup)(struct tty_struct *);   * - * 	This function is called by the low-level tty driver to signal - * 	that line discpline should try to send more characters to the - * 	low-level driver for transmission.  If the line discpline does - * 	not have any more data to send, it can just return. + *	This function is called by the low-level tty driver to signal + *	that line discpline should try to send more characters to the + *	low-level driver for transmission.  If the line discpline does + *	not have any more data to send, it can just return.   *   * int (*hangup)(struct tty_struct *)   * @@ -115,7 +115,7 @@ struct tty_ldisc_ops {  	char	*name;  	int	num;  	int	flags; -	 +  	/*  	 * The following routines are called from above.  	 */ @@ -123,19 +123,19 @@ struct tty_ldisc_ops {  	void	(*close)(struct tty_struct *);  	void	(*flush_buffer)(struct tty_struct *tty);  	ssize_t	(*chars_in_buffer)(struct tty_struct *tty); -	ssize_t	(*read)(struct tty_struct * tty, struct file * file, -			unsigned char __user * buf, size_t nr); -	ssize_t	(*write)(struct tty_struct * tty, struct file * file, -			 const unsigned char * buf, size_t nr);	 -	int	(*ioctl)(struct tty_struct * tty, struct file * file, +	ssize_t	(*read)(struct tty_struct *tty, struct file *file, +			unsigned char __user *buf, size_t nr); +	ssize_t	(*write)(struct tty_struct *tty, struct file *file, +			 const unsigned char *buf, size_t nr); +	int	(*ioctl)(struct tty_struct *tty, struct file *file,  			 unsigned int cmd, unsigned long arg); -	long	(*compat_ioctl)(struct tty_struct * tty, struct file * file, +	long	(*compat_ioctl)(struct tty_struct *tty, struct file *file,  				unsigned int cmd, unsigned long arg); -	void	(*set_termios)(struct tty_struct *tty, struct ktermios * old); +	void	(*set_termios)(struct tty_struct *tty, struct ktermios *old);  	unsigned int (*poll)(struct tty_struct *, struct file *,  			     struct poll_table_struct *);  	int	(*hangup)(struct tty_struct *tty); -	 +  	/*  	 * The following routines are called from below.  	 */ @@ -145,7 +145,7 @@ struct tty_ldisc_ops {  	void	(*dcd_change)(struct tty_struct *, unsigned int);  	struct  module *owner; -	 +  	int refcount;  }; diff --git a/net/irda/ircomm/ircomm_tty_attach.c b/net/irda/ircomm/ircomm_tty_attach.c index edab393e0c8..a2a508f5f26 100644 --- a/net/irda/ircomm/ircomm_tty_attach.c +++ b/net/irda/ircomm/ircomm_tty_attach.c @@ -997,12 +997,8 @@ static int ircomm_tty_state_ready(struct ircomm_tty_cb *self,  			self->settings.dce = IRCOMM_DELTA_CD;  			ircomm_tty_check_modem_status(self);  		} else { -			struct tty_struct *tty = tty_port_tty_get(&self->port);  			IRDA_DEBUG(0, "%s(), hanging up!\n", __func__ ); -			if (tty) { -				tty_hangup(tty); -				tty_kref_put(tty); -			} +			tty_port_tty_hangup(&self->port, false);  		}  		break;  	default:  |