ASR_BASE

Change-Id: Icf3719cc0afe3eeb3edc7fa80a2eb5199ca9dda1
diff --git a/marvell/linux/drivers/tty/serial/jsm/jsm_tty.c b/marvell/linux/drivers/tty/serial/jsm/jsm_tty.c
new file mode 100644
index 0000000..8438454
--- /dev/null
+++ b/marvell/linux/drivers/tty/serial/jsm/jsm_tty.c
@@ -0,0 +1,823 @@
+// SPDX-License-Identifier: GPL-2.0+
+/************************************************************************
+ * Copyright 2003 Digi International (www.digi.com)
+ *
+ * Copyright (C) 2004 IBM Corporation. All rights reserved.
+ *
+ * Contact Information:
+ * Scott H Kilau <Scott_Kilau@digi.com>
+ * Ananda Venkatarman <mansarov@us.ibm.com>
+ * Modifications:
+ * 01/19/06:	changed jsm_input routine to use the dynamically allocated
+ *		tty_buffer changes. Contributors: Scott Kilau and Ananda V.
+ ***********************************************************************/
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/serial_reg.h>
+#include <linux/delay.h>	/* For udelay */
+#include <linux/pci.h>
+#include <linux/slab.h>
+
+#include "jsm.h"
+
+static DECLARE_BITMAP(linemap, MAXLINES);
+
+static void jsm_carrier(struct jsm_channel *ch);
+
+static inline int jsm_get_mstat(struct jsm_channel *ch)
+{
+	unsigned char mstat;
+	int result;
+
+	jsm_dbg(IOCTL, &ch->ch_bd->pci_dev, "start\n");
+
+	mstat = (ch->ch_mostat | ch->ch_mistat);
+
+	result = 0;
+
+	if (mstat & UART_MCR_DTR)
+		result |= TIOCM_DTR;
+	if (mstat & UART_MCR_RTS)
+		result |= TIOCM_RTS;
+	if (mstat & UART_MSR_CTS)
+		result |= TIOCM_CTS;
+	if (mstat & UART_MSR_DSR)
+		result |= TIOCM_DSR;
+	if (mstat & UART_MSR_RI)
+		result |= TIOCM_RI;
+	if (mstat & UART_MSR_DCD)
+		result |= TIOCM_CD;
+
+	jsm_dbg(IOCTL, &ch->ch_bd->pci_dev, "finish\n");
+	return result;
+}
+
+static unsigned int jsm_tty_tx_empty(struct uart_port *port)
+{
+	return TIOCSER_TEMT;
+}
+
+/*
+ * Return modem signals to ld.
+ */
+static unsigned int jsm_tty_get_mctrl(struct uart_port *port)
+{
+	int result;
+	struct jsm_channel *channel =
+		container_of(port, struct jsm_channel, uart_port);
+
+	jsm_dbg(IOCTL, &channel->ch_bd->pci_dev, "start\n");
+
+	result = jsm_get_mstat(channel);
+
+	if (result < 0)
+		return -ENXIO;
+
+	jsm_dbg(IOCTL, &channel->ch_bd->pci_dev, "finish\n");
+
+	return result;
+}
+
+/*
+ * jsm_set_modem_info()
+ *
+ * Set modem signals, called by ld.
+ */
+static void jsm_tty_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+	struct jsm_channel *channel =
+		container_of(port, struct jsm_channel, uart_port);
+
+	jsm_dbg(IOCTL, &channel->ch_bd->pci_dev, "start\n");
+
+	if (mctrl & TIOCM_RTS)
+		channel->ch_mostat |= UART_MCR_RTS;
+	else
+		channel->ch_mostat &= ~UART_MCR_RTS;
+
+	if (mctrl & TIOCM_DTR)
+		channel->ch_mostat |= UART_MCR_DTR;
+	else
+		channel->ch_mostat &= ~UART_MCR_DTR;
+
+	channel->ch_bd->bd_ops->assert_modem_signals(channel);
+
+	jsm_dbg(IOCTL, &channel->ch_bd->pci_dev, "finish\n");
+	udelay(10);
+}
+
+/*
+ * jsm_tty_write()
+ *
+ * Take data from the user or kernel and send it out to the FEP.
+ * In here exists all the Transparent Print magic as well.
+ */
+static void jsm_tty_write(struct uart_port *port)
+{
+	struct jsm_channel *channel;
+
+	channel = container_of(port, struct jsm_channel, uart_port);
+	channel->ch_bd->bd_ops->copy_data_from_queue_to_uart(channel);
+}
+
+static void jsm_tty_start_tx(struct uart_port *port)
+{
+	struct jsm_channel *channel =
+		container_of(port, struct jsm_channel, uart_port);
+
+	jsm_dbg(IOCTL, &channel->ch_bd->pci_dev, "start\n");
+
+	channel->ch_flags &= ~(CH_STOP);
+	jsm_tty_write(port);
+
+	jsm_dbg(IOCTL, &channel->ch_bd->pci_dev, "finish\n");
+}
+
+static void jsm_tty_stop_tx(struct uart_port *port)
+{
+	struct jsm_channel *channel =
+		container_of(port, struct jsm_channel, uart_port);
+
+	jsm_dbg(IOCTL, &channel->ch_bd->pci_dev, "start\n");
+
+	channel->ch_flags |= (CH_STOP);
+
+	jsm_dbg(IOCTL, &channel->ch_bd->pci_dev, "finish\n");
+}
+
+static void jsm_tty_send_xchar(struct uart_port *port, char ch)
+{
+	unsigned long lock_flags;
+	struct jsm_channel *channel =
+		container_of(port, struct jsm_channel, uart_port);
+	struct ktermios *termios;
+
+	spin_lock_irqsave(&port->lock, lock_flags);
+	termios = &port->state->port.tty->termios;
+	if (ch == termios->c_cc[VSTART])
+		channel->ch_bd->bd_ops->send_start_character(channel);
+
+	if (ch == termios->c_cc[VSTOP])
+		channel->ch_bd->bd_ops->send_stop_character(channel);
+	spin_unlock_irqrestore(&port->lock, lock_flags);
+}
+
+static void jsm_tty_stop_rx(struct uart_port *port)
+{
+	struct jsm_channel *channel =
+		container_of(port, struct jsm_channel, uart_port);
+
+	channel->ch_bd->bd_ops->disable_receiver(channel);
+}
+
+static void jsm_tty_break(struct uart_port *port, int break_state)
+{
+	unsigned long lock_flags;
+	struct jsm_channel *channel =
+		container_of(port, struct jsm_channel, uart_port);
+
+	spin_lock_irqsave(&port->lock, lock_flags);
+	if (break_state == -1)
+		channel->ch_bd->bd_ops->send_break(channel);
+	else
+		channel->ch_bd->bd_ops->clear_break(channel);
+
+	spin_unlock_irqrestore(&port->lock, lock_flags);
+}
+
+static int jsm_tty_open(struct uart_port *port)
+{
+	unsigned long lock_flags;
+	struct jsm_board *brd;
+	struct jsm_channel *channel =
+		container_of(port, struct jsm_channel, uart_port);
+	struct ktermios *termios;
+
+	/* Get board pointer from our array of majors we have allocated */
+	brd = channel->ch_bd;
+
+	/*
+	 * Allocate channel buffers for read/write/error.
+	 * Set flag, so we don't get trounced on.
+	 */
+	channel->ch_flags |= (CH_OPENING);
+
+	/* Drop locks, as malloc with GFP_KERNEL can sleep */
+
+	if (!channel->ch_rqueue) {
+		channel->ch_rqueue = kzalloc(RQUEUESIZE, GFP_KERNEL);
+		if (!channel->ch_rqueue) {
+			jsm_dbg(INIT, &channel->ch_bd->pci_dev,
+				"unable to allocate read queue buf\n");
+			return -ENOMEM;
+		}
+	}
+	if (!channel->ch_equeue) {
+		channel->ch_equeue = kzalloc(EQUEUESIZE, GFP_KERNEL);
+		if (!channel->ch_equeue) {
+			jsm_dbg(INIT, &channel->ch_bd->pci_dev,
+				"unable to allocate error queue buf\n");
+			return -ENOMEM;
+		}
+	}
+
+	channel->ch_flags &= ~(CH_OPENING);
+	/*
+	 * Initialize if neither terminal is open.
+	 */
+	jsm_dbg(OPEN, &channel->ch_bd->pci_dev,
+		"jsm_open: initializing channel in open...\n");
+
+	/*
+	 * Flush input queues.
+	 */
+	channel->ch_r_head = channel->ch_r_tail = 0;
+	channel->ch_e_head = channel->ch_e_tail = 0;
+
+	brd->bd_ops->flush_uart_write(channel);
+	brd->bd_ops->flush_uart_read(channel);
+
+	channel->ch_flags = 0;
+	channel->ch_cached_lsr = 0;
+	channel->ch_stops_sent = 0;
+
+	spin_lock_irqsave(&port->lock, lock_flags);
+	termios = &port->state->port.tty->termios;
+	channel->ch_c_cflag	= termios->c_cflag;
+	channel->ch_c_iflag	= termios->c_iflag;
+	channel->ch_c_oflag	= termios->c_oflag;
+	channel->ch_c_lflag	= termios->c_lflag;
+	channel->ch_startc	= termios->c_cc[VSTART];
+	channel->ch_stopc	= termios->c_cc[VSTOP];
+
+	/* Tell UART to init itself */
+	brd->bd_ops->uart_init(channel);
+
+	/*
+	 * Run param in case we changed anything
+	 */
+	brd->bd_ops->param(channel);
+
+	jsm_carrier(channel);
+
+	channel->ch_open_count++;
+	spin_unlock_irqrestore(&port->lock, lock_flags);
+
+	jsm_dbg(OPEN, &channel->ch_bd->pci_dev, "finish\n");
+	return 0;
+}
+
+static void jsm_tty_close(struct uart_port *port)
+{
+	struct jsm_board *bd;
+	struct jsm_channel *channel =
+		container_of(port, struct jsm_channel, uart_port);
+
+	jsm_dbg(CLOSE, &channel->ch_bd->pci_dev, "start\n");
+
+	bd = channel->ch_bd;
+
+	channel->ch_flags &= ~(CH_STOPI);
+
+	channel->ch_open_count--;
+
+	/*
+	 * If we have HUPCL set, lower DTR and RTS
+	 */
+	if (channel->ch_c_cflag & HUPCL) {
+		jsm_dbg(CLOSE, &channel->ch_bd->pci_dev,
+			"Close. HUPCL set, dropping DTR/RTS\n");
+
+		/* Drop RTS/DTR */
+		channel->ch_mostat &= ~(UART_MCR_DTR | UART_MCR_RTS);
+		bd->bd_ops->assert_modem_signals(channel);
+	}
+
+	/* Turn off UART interrupts for this port */
+	channel->ch_bd->bd_ops->uart_off(channel);
+
+	jsm_dbg(CLOSE, &channel->ch_bd->pci_dev, "finish\n");
+}
+
+static void jsm_tty_set_termios(struct uart_port *port,
+				 struct ktermios *termios,
+				 struct ktermios *old_termios)
+{
+	unsigned long lock_flags;
+	struct jsm_channel *channel =
+		container_of(port, struct jsm_channel, uart_port);
+
+	spin_lock_irqsave(&port->lock, lock_flags);
+	channel->ch_c_cflag	= termios->c_cflag;
+	channel->ch_c_iflag	= termios->c_iflag;
+	channel->ch_c_oflag	= termios->c_oflag;
+	channel->ch_c_lflag	= termios->c_lflag;
+	channel->ch_startc	= termios->c_cc[VSTART];
+	channel->ch_stopc	= termios->c_cc[VSTOP];
+
+	channel->ch_bd->bd_ops->param(channel);
+	jsm_carrier(channel);
+	spin_unlock_irqrestore(&port->lock, lock_flags);
+}
+
+static const char *jsm_tty_type(struct uart_port *port)
+{
+	return "jsm";
+}
+
+static void jsm_tty_release_port(struct uart_port *port)
+{
+}
+
+static int jsm_tty_request_port(struct uart_port *port)
+{
+	return 0;
+}
+
+static void jsm_config_port(struct uart_port *port, int flags)
+{
+	port->type = PORT_JSM;
+}
+
+static const struct uart_ops jsm_ops = {
+	.tx_empty	= jsm_tty_tx_empty,
+	.set_mctrl	= jsm_tty_set_mctrl,
+	.get_mctrl	= jsm_tty_get_mctrl,
+	.stop_tx	= jsm_tty_stop_tx,
+	.start_tx	= jsm_tty_start_tx,
+	.send_xchar	= jsm_tty_send_xchar,
+	.stop_rx	= jsm_tty_stop_rx,
+	.break_ctl	= jsm_tty_break,
+	.startup	= jsm_tty_open,
+	.shutdown	= jsm_tty_close,
+	.set_termios	= jsm_tty_set_termios,
+	.type		= jsm_tty_type,
+	.release_port	= jsm_tty_release_port,
+	.request_port	= jsm_tty_request_port,
+	.config_port	= jsm_config_port,
+};
+
+/*
+ * jsm_tty_init()
+ *
+ * Init the tty subsystem.  Called once per board after board has been
+ * downloaded and init'ed.
+ */
+int jsm_tty_init(struct jsm_board *brd)
+{
+	int i;
+	void __iomem *vaddr;
+	struct jsm_channel *ch;
+
+	if (!brd)
+		return -ENXIO;
+
+	jsm_dbg(INIT, &brd->pci_dev, "start\n");
+
+	/*
+	 * Initialize board structure elements.
+	 */
+
+	brd->nasync = brd->maxports;
+
+	/*
+	 * Allocate channel memory that might not have been allocated
+	 * when the driver was first loaded.
+	 */
+	for (i = 0; i < brd->nasync; i++) {
+		if (!brd->channels[i]) {
+
+			/*
+			 * Okay to malloc with GFP_KERNEL, we are not at
+			 * interrupt context, and there are no locks held.
+			 */
+			brd->channels[i] = kzalloc(sizeof(struct jsm_channel), GFP_KERNEL);
+			if (!brd->channels[i]) {
+				jsm_dbg(CORE, &brd->pci_dev,
+					"%s:%d Unable to allocate memory for channel struct\n",
+					__FILE__, __LINE__);
+			}
+		}
+	}
+
+	ch = brd->channels[0];
+	vaddr = brd->re_map_membase;
+
+	/* Set up channel variables */
+	for (i = 0; i < brd->nasync; i++, ch = brd->channels[i]) {
+
+		if (!brd->channels[i])
+			continue;
+
+		spin_lock_init(&ch->ch_lock);
+
+		if (brd->bd_uart_offset == 0x200)
+			ch->ch_neo_uart =  vaddr + (brd->bd_uart_offset * i);
+		else
+			ch->ch_cls_uart =  vaddr + (brd->bd_uart_offset * i);
+
+		ch->ch_bd = brd;
+		ch->ch_portnum = i;
+
+		/* .25 second delay */
+		ch->ch_close_delay = 250;
+
+		init_waitqueue_head(&ch->ch_flags_wait);
+	}
+
+	jsm_dbg(INIT, &brd->pci_dev, "finish\n");
+	return 0;
+}
+
+int jsm_uart_port_init(struct jsm_board *brd)
+{
+	int i, rc;
+	unsigned int line;
+
+	if (!brd)
+		return -ENXIO;
+
+	jsm_dbg(INIT, &brd->pci_dev, "start\n");
+
+	/*
+	 * Initialize board structure elements.
+	 */
+
+	brd->nasync = brd->maxports;
+
+	/* Set up channel variables */
+	for (i = 0; i < brd->nasync; i++) {
+
+		if (!brd->channels[i])
+			continue;
+
+		brd->channels[i]->uart_port.irq = brd->irq;
+		brd->channels[i]->uart_port.uartclk = 14745600;
+		brd->channels[i]->uart_port.type = PORT_JSM;
+		brd->channels[i]->uart_port.iotype = UPIO_MEM;
+		brd->channels[i]->uart_port.membase = brd->re_map_membase;
+		brd->channels[i]->uart_port.fifosize = 16;
+		brd->channels[i]->uart_port.ops = &jsm_ops;
+		line = find_first_zero_bit(linemap, MAXLINES);
+		if (line >= MAXLINES) {
+			printk(KERN_INFO "jsm: linemap is full, added device failed\n");
+			continue;
+		} else
+			set_bit(line, linemap);
+		brd->channels[i]->uart_port.line = line;
+		rc = uart_add_one_port(&jsm_uart_driver, &brd->channels[i]->uart_port);
+		if (rc) {
+			printk(KERN_INFO "jsm: Port %d failed. Aborting...\n", i);
+			return rc;
+		} else
+			printk(KERN_INFO "jsm: Port %d added\n", i);
+	}
+
+	jsm_dbg(INIT, &brd->pci_dev, "finish\n");
+	return 0;
+}
+
+int jsm_remove_uart_port(struct jsm_board *brd)
+{
+	int i;
+	struct jsm_channel *ch;
+
+	if (!brd)
+		return -ENXIO;
+
+	jsm_dbg(INIT, &brd->pci_dev, "start\n");
+
+	/*
+	 * Initialize board structure elements.
+	 */
+
+	brd->nasync = brd->maxports;
+
+	/* Set up channel variables */
+	for (i = 0; i < brd->nasync; i++) {
+
+		if (!brd->channels[i])
+			continue;
+
+		ch = brd->channels[i];
+
+		clear_bit(ch->uart_port.line, linemap);
+		uart_remove_one_port(&jsm_uart_driver, &brd->channels[i]->uart_port);
+	}
+
+	jsm_dbg(INIT, &brd->pci_dev, "finish\n");
+	return 0;
+}
+
+void jsm_input(struct jsm_channel *ch)
+{
+	struct jsm_board *bd;
+	struct tty_struct *tp;
+	struct tty_port *port;
+	u32 rmask;
+	u16 head;
+	u16 tail;
+	int data_len;
+	unsigned long lock_flags;
+	int len = 0;
+	int s = 0;
+	int i = 0;
+
+	jsm_dbg(READ, &ch->ch_bd->pci_dev, "start\n");
+
+	port = &ch->uart_port.state->port;
+	tp = port->tty;
+
+	bd = ch->ch_bd;
+	if (!bd)
+		return;
+
+	spin_lock_irqsave(&ch->ch_lock, lock_flags);
+
+	/*
+	 *Figure the number of characters in the buffer.
+	 *Exit immediately if none.
+	 */
+
+	rmask = RQUEUEMASK;
+
+	head = ch->ch_r_head & rmask;
+	tail = ch->ch_r_tail & rmask;
+
+	data_len = (head - tail) & rmask;
+	if (data_len == 0) {
+		spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
+		return;
+	}
+
+	jsm_dbg(READ, &ch->ch_bd->pci_dev, "start\n");
+
+	/*
+	 *If the device is not open, or CREAD is off, flush
+	 *input data and return immediately.
+	 */
+	if (!tp || !C_CREAD(tp)) {
+
+		jsm_dbg(READ, &ch->ch_bd->pci_dev,
+			"input. dropping %d bytes on port %d...\n",
+			data_len, ch->ch_portnum);
+		ch->ch_r_head = tail;
+
+		/* Force queue flow control to be released, if needed */
+		jsm_check_queue_flow_control(ch);
+
+		spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
+		return;
+	}
+
+	/*
+	 * If we are throttled, simply don't read any data.
+	 */
+	if (ch->ch_flags & CH_STOPI) {
+		spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
+		jsm_dbg(READ, &ch->ch_bd->pci_dev,
+			"Port %d throttled, not reading any data. head: %x tail: %x\n",
+			ch->ch_portnum, head, tail);
+		return;
+	}
+
+	jsm_dbg(READ, &ch->ch_bd->pci_dev, "start 2\n");
+
+	len = tty_buffer_request_room(port, data_len);
+
+	/*
+	 * len now contains the most amount of data we can copy,
+	 * bounded either by the flip buffer size or the amount
+	 * of data the card actually has pending...
+	 */
+	while (len) {
+		s = ((head >= tail) ? head : RQUEUESIZE) - tail;
+		s = min(s, len);
+
+		if (s <= 0)
+			break;
+
+			/*
+			 * If conditions are such that ld needs to see all
+			 * UART errors, we will have to walk each character
+			 * and error byte and send them to the buffer one at
+			 * a time.
+			 */
+
+		if (I_PARMRK(tp) || I_BRKINT(tp) || I_INPCK(tp)) {
+			for (i = 0; i < s; i++) {
+				/*
+				 * Give the Linux ld the flags in the
+				 * format it likes.
+				 */
+				if (*(ch->ch_equeue +tail +i) & UART_LSR_BI)
+					tty_insert_flip_char(port, *(ch->ch_rqueue +tail +i),  TTY_BREAK);
+				else if (*(ch->ch_equeue +tail +i) & UART_LSR_PE)
+					tty_insert_flip_char(port, *(ch->ch_rqueue +tail +i), TTY_PARITY);
+				else if (*(ch->ch_equeue +tail +i) & UART_LSR_FE)
+					tty_insert_flip_char(port, *(ch->ch_rqueue +tail +i), TTY_FRAME);
+				else
+					tty_insert_flip_char(port, *(ch->ch_rqueue +tail +i), TTY_NORMAL);
+			}
+		} else {
+			tty_insert_flip_string(port, ch->ch_rqueue + tail, s);
+		}
+		tail += s;
+		len -= s;
+		/* Flip queue if needed */
+		tail &= rmask;
+	}
+
+	ch->ch_r_tail = tail & rmask;
+	ch->ch_e_tail = tail & rmask;
+	jsm_check_queue_flow_control(ch);
+	spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
+
+	/* Tell the tty layer its okay to "eat" the data now */
+	tty_flip_buffer_push(port);
+
+	jsm_dbg(IOCTL, &ch->ch_bd->pci_dev, "finish\n");
+}
+
+static void jsm_carrier(struct jsm_channel *ch)
+{
+	struct jsm_board *bd;
+
+	int virt_carrier = 0;
+	int phys_carrier = 0;
+
+	jsm_dbg(CARR, &ch->ch_bd->pci_dev, "start\n");
+
+	bd = ch->ch_bd;
+	if (!bd)
+		return;
+
+	if (ch->ch_mistat & UART_MSR_DCD) {
+		jsm_dbg(CARR, &ch->ch_bd->pci_dev, "mistat: %x D_CD: %x\n",
+			ch->ch_mistat, ch->ch_mistat & UART_MSR_DCD);
+		phys_carrier = 1;
+	}
+
+	if (ch->ch_c_cflag & CLOCAL)
+		virt_carrier = 1;
+
+	jsm_dbg(CARR, &ch->ch_bd->pci_dev, "DCD: physical: %d virt: %d\n",
+		phys_carrier, virt_carrier);
+
+	/*
+	 * Test for a VIRTUAL carrier transition to HIGH.
+	 */
+	if (((ch->ch_flags & CH_FCAR) == 0) && (virt_carrier == 1)) {
+
+		/*
+		 * When carrier rises, wake any threads waiting
+		 * for carrier in the open routine.
+		 */
+
+		jsm_dbg(CARR, &ch->ch_bd->pci_dev, "carrier: virt DCD rose\n");
+
+		if (waitqueue_active(&(ch->ch_flags_wait)))
+			wake_up_interruptible(&ch->ch_flags_wait);
+	}
+
+	/*
+	 * Test for a PHYSICAL carrier transition to HIGH.
+	 */
+	if (((ch->ch_flags & CH_CD) == 0) && (phys_carrier == 1)) {
+
+		/*
+		 * When carrier rises, wake any threads waiting
+		 * for carrier in the open routine.
+		 */
+
+		jsm_dbg(CARR, &ch->ch_bd->pci_dev,
+			"carrier: physical DCD rose\n");
+
+		if (waitqueue_active(&(ch->ch_flags_wait)))
+			wake_up_interruptible(&ch->ch_flags_wait);
+	}
+
+	/*
+	 *  Test for a PHYSICAL transition to low, so long as we aren't
+	 *  currently ignoring physical transitions (which is what "virtual
+	 *  carrier" indicates).
+	 *
+	 *  The transition of the virtual carrier to low really doesn't
+	 *  matter... it really only means "ignore carrier state", not
+	 *  "make pretend that carrier is there".
+	 */
+	if ((virt_carrier == 0) && ((ch->ch_flags & CH_CD) != 0)
+			&& (phys_carrier == 0)) {
+		/*
+		 *	When carrier drops:
+		 *
+		 *	Drop carrier on all open units.
+		 *
+		 *	Flush queues, waking up any task waiting in the
+		 *	line discipline.
+		 *
+		 *	Send a hangup to the control terminal.
+		 *
+		 *	Enable all select calls.
+		 */
+		if (waitqueue_active(&(ch->ch_flags_wait)))
+			wake_up_interruptible(&ch->ch_flags_wait);
+	}
+
+	/*
+	 *  Make sure that our cached values reflect the current reality.
+	 */
+	if (virt_carrier == 1)
+		ch->ch_flags |= CH_FCAR;
+	else
+		ch->ch_flags &= ~CH_FCAR;
+
+	if (phys_carrier == 1)
+		ch->ch_flags |= CH_CD;
+	else
+		ch->ch_flags &= ~CH_CD;
+}
+
+
+void jsm_check_queue_flow_control(struct jsm_channel *ch)
+{
+	struct board_ops *bd_ops = ch->ch_bd->bd_ops;
+	int qleft;
+
+	/* Store how much space we have left in the queue */
+	if ((qleft = ch->ch_r_tail - ch->ch_r_head - 1) < 0)
+		qleft += RQUEUEMASK + 1;
+
+	/*
+	 * Check to see if we should enforce flow control on our queue because
+	 * the ld (or user) isn't reading data out of our queue fast enuf.
+	 *
+	 * NOTE: This is done based on what the current flow control of the
+	 * port is set for.
+	 *
+	 * 1) HWFLOW (RTS) - Turn off the UART's Receive interrupt.
+	 *	This will cause the UART's FIFO to back up, and force
+	 *	the RTS signal to be dropped.
+	 * 2) SWFLOW (IXOFF) - Keep trying to send a stop character to
+	 *	the other side, in hopes it will stop sending data to us.
+	 * 3) NONE - Nothing we can do.  We will simply drop any extra data
+	 *	that gets sent into us when the queue fills up.
+	 */
+	if (qleft < 256) {
+		/* HWFLOW */
+		if (ch->ch_c_cflag & CRTSCTS) {
+			if (!(ch->ch_flags & CH_RECEIVER_OFF)) {
+				bd_ops->disable_receiver(ch);
+				ch->ch_flags |= (CH_RECEIVER_OFF);
+				jsm_dbg(READ, &ch->ch_bd->pci_dev,
+					"Internal queue hit hilevel mark (%d)! Turning off interrupts\n",
+					qleft);
+			}
+		}
+		/* SWFLOW */
+		else if (ch->ch_c_iflag & IXOFF) {
+			if (ch->ch_stops_sent <= MAX_STOPS_SENT) {
+				bd_ops->send_stop_character(ch);
+				ch->ch_stops_sent++;
+				jsm_dbg(READ, &ch->ch_bd->pci_dev,
+					"Sending stop char! Times sent: %x\n",
+					ch->ch_stops_sent);
+			}
+		}
+	}
+
+	/*
+	 * Check to see if we should unenforce flow control because
+	 * ld (or user) finally read enuf data out of our queue.
+	 *
+	 * NOTE: This is done based on what the current flow control of the
+	 * port is set for.
+	 *
+	 * 1) HWFLOW (RTS) - Turn back on the UART's Receive interrupt.
+	 *	This will cause the UART's FIFO to raise RTS back up,
+	 *	which will allow the other side to start sending data again.
+	 * 2) SWFLOW (IXOFF) - Send a start character to
+	 *	the other side, so it will start sending data to us again.
+	 * 3) NONE - Do nothing. Since we didn't do anything to turn off the
+	 *	other side, we don't need to do anything now.
+	 */
+	if (qleft > (RQUEUESIZE / 2)) {
+		/* HWFLOW */
+		if (ch->ch_c_cflag & CRTSCTS) {
+			if (ch->ch_flags & CH_RECEIVER_OFF) {
+				bd_ops->enable_receiver(ch);
+				ch->ch_flags &= ~(CH_RECEIVER_OFF);
+				jsm_dbg(READ, &ch->ch_bd->pci_dev,
+					"Internal queue hit lowlevel mark (%d)! Turning on interrupts\n",
+					qleft);
+			}
+		}
+		/* SWFLOW */
+		else if (ch->ch_c_iflag & IXOFF && ch->ch_stops_sent) {
+			ch->ch_stops_sent = 0;
+			bd_ops->send_start_character(ch);
+			jsm_dbg(READ, &ch->ch_bd->pci_dev,
+				"Sending start char!\n");
+		}
+	}
+}