linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [ patch 2/7] drivers/serial/jsm: new serial device driver
@ 2005-02-27 23:38 Wen Xiong
  2005-02-28  0:25 ` Jeff Garzik
  2005-02-28  6:37 ` Greg KH
  0 siblings, 2 replies; 4+ messages in thread
From: Wen Xiong @ 2005-02-27 23:38 UTC (permalink / raw)
  To: linux-kernel, linux-serial

[-- Attachment #1: Type: text/plain, Size: 142 bytes --]

This second patch is for jsm_tty.c and included all handling TTY layer 
functions.

Signed-off-by: Wen Xiong <wendyx@us.ltcfwd.linux.ibm.com>

[-- Attachment #2: patch2.jasmine --]
[-- Type: text/plain, Size: 31964 bytes --]

diff -Nuar linux-2.6.9.orig/drivers/serial/jsm/jsm_tty.c linux-2.6.9.new/drivers/serial/jsm/jsm_tty.c
--- linux-2.6.9.orig/drivers/serial/jsm/jsm_tty.c	1969-12-31 18:00:00.000000000 -0600
+++ linux-2.6.9.new/drivers/serial/jsm/jsm_tty.c	2005-02-27 17:09:43.456960832 -0600
@@ -0,0 +1,1273 @@
+/*
+ * Copyright 2003 Digi International (www.digi.com)
+ *	Scott H Kilau <Scott_Kilau at digi dot com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; without even the
+ * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE.  See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ *	NOTE TO LINUX KERNEL HACKERS:  DO NOT REFORMAT THIS CODE! 
+ *
+ *	This is shared code between Digi's CVS archive and the
+ *	Linux Kernel sources.
+ *	Changing the source just for reformatting needlessly breaks
+ *	our CVS diff history.
+ *
+ *	Send any bug fixes/changes to:  Eng.Linux at digi dot com. 
+ *	Thank you. 
+ */
+
+/************************************************************************
+ * 
+ * This file implements the tty driver functionality for the
+ * Neo and ClassicBoard PCI based product lines.
+ * 
+ ************************************************************************
+ *
+ * $Id: jsm_tty.c,v 1.79 2004/09/25 07:01:46 scottk Exp $
+ */
+
+#include <linux/kernel.h>
+#include <linux/version.h>
+#include <linux/sched.h>	/* For jiffies, task states */
+#include <linux/interrupt.h>	/* For tasklet and interrupt structs/defines */
+#include <linux/module.h>
+#include <linux/ctype.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/serial_reg.h>
+#include <linux/slab.h>
+#include <linux/delay.h>	/* For udelay */
+#include <linux/device.h>	/* For udelay */
+#include <asm/uaccess.h>	/* For copy_from_user/copy_to_user */
+
+#include "jsm_driver.h"
+#include "jsm_tty.h"
+#include "jsm_types.h"
+#include "jsm_neo.h"
+#include "dpacompat.h"
+
+/*
+ * internal variables
+ */
+#define JSM_CHANNEL ((struct channel_t *)port)
+
+/*
+ * Define a local default termios struct. All ports will be created
+ * with this termios initially.
+ *
+ * This defines a raw port at 9600 baud, 8 data bits, no parity,
+ * 1 stop bit.
+ */
+
+/*Begin Serial_core API*/
+
+static inline int jsm_get_mstat(struct channel_t *ch)
+{
+	unsigned char mstat;
+	unsigned char result;
+
+	DPR_IOCTL(("jsm_getmstat 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;
+
+	DPR_IOCTL(("jsm_getmstat 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;
+
+	DPR_IOCTL(("jsm_get_modem_info start\n"));
+
+	result = jsm_get_mstat(JSM_CHANNEL);
+
+	if (result < 0)
+		return -ENXIO;
+
+	DPR_IOCTL(("jsm_get_modem_info 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)
+{
+	DPR_IOCTL(("jsm_set_modem_info() start\n"));
+
+	if (mctrl & TIOCM_RTS)
+		JSM_CHANNEL->ch_mostat |= UART_MCR_RTS;
+	else
+		JSM_CHANNEL->ch_mostat &= ~UART_MCR_RTS;

+	if (mctrl & TIOCM_DTR)
+		JSM_CHANNEL->ch_mostat |= UART_MCR_DTR;
+	else
+		JSM_CHANNEL->ch_mostat &= ~UART_MCR_DTR;
+
+	JSM_CHANNEL->ch_bd->bd_ops->assert_modem_signals(JSM_CHANNEL);
+
+	DPR_IOCTL(("jsm_set_modem_info finish\n"));
+
+	udelay(10);
+
+}
+
+static void jsm_tty_start_tx(struct uart_port *port, unsigned int tty_start)
+{
+	DPR_IOCTL(("dgcn_tty_start start\n"));
+
+	JSM_CHANNEL->ch_flags &= ~(CH_STOP);
+
+	jsm_tty_write(port);
+
+	DPR_IOCTL(("jsm_tty_start finish\n"));
+
+}
+
+static void jsm_tty_stop_tx(struct uart_port *port, unsigned int tty_stop)
+{
+	DPR_IOCTL(("jsm_tty_stop start\n"));
+
+	JSM_CHANNEL->ch_flags |= (CH_STOP);
+
+	DPR_IOCTL(("jsm_tty_stop finish\n"));
+}
+
+static void jsm_tty_send_xchar(struct uart_port *port, char ch)
+{
+	unsigned long lock_flags;
+
+	spin_lock_irqsave(&port->lock, lock_flags);
+	if (ch == port->info->tty->termios->c_cc[VSTART])
+		JSM_CHANNEL->ch_bd->bd_ops->send_start_character(JSM_CHANNEL);
+
+	if (ch == port->info->tty->termios->c_cc[VSTOP])
+		JSM_CHANNEL->ch_bd->bd_ops->send_stop_character(JSM_CHANNEL);
+	spin_unlock_irqrestore(&port->lock, lock_flags);
+}
+
+static void jsm_tty_stop_rx(struct uart_port *port)
+{
+
+	JSM_CHANNEL->ch_bd->bd_ops->disable_receiver(JSM_CHANNEL);
+
+}
+
+static void jsm_tty_break(struct uart_port *port, int break_state)
+{
+	unsigned long lock_flags;
+	spin_lock_irqsave(&port->lock, lock_flags);
+	if (break_state == -1)
+		JSM_CHANNEL->ch_bd->bd_ops->send_break(JSM_CHANNEL);
+	else
+		neo_clear_break(JSM_CHANNEL,0);
+
+	spin_unlock_irqrestore(&port->lock, lock_flags);
+}
+
+static int jsm_tty_open(struct uart_port *port)
+{
+	struct board_t	*brd;
+	struct un_t	*un;
+	int		rc = 0;
+
+	/* Get board pointer from our array of majors we have allocated */
+	brd = JSM_CHANNEL->ch_bd;
+
+	un = &JSM_CHANNEL->ch_tun;
+	un->un_type = JSM_SERIAL;
+
+	/*
+	 * Initialize tty's
+	 */
+	if (!(un->un_flags & UN_ISOPEN)) {
+		/* Store important variables. */
+		un->un_ch = JSM_CHANNEL;
+		un->un_dev = JSM_CHANNEL->ch_portnum;
+
+		/* Maybe do something here to the TTY struct as well? */
+	}
+
+	/*
+	 * Allocate channel buffers for read/write/error.
+	 * Set flag, so we don't get trounced on.
+	 */
+	JSM_CHANNEL->ch_flags |= (CH_OPENING);
+
+	/* Drop locks, as malloc with GFP_KERNEL can sleep */
+
+	if (!JSM_CHANNEL->ch_rqueue) {
+		JSM_CHANNEL->ch_rqueue = (uchar *) kmalloc(RQUEUESIZE, GFP_KERNEL);
+		if (!JSM_CHANNEL->ch_rqueue) {
+			DPR_INIT(("unable to allocate read queue buf"));
+			return -ENOMEM;
+		}
+		memset(JSM_CHANNEL->ch_rqueue, 0, RQUEUESIZE);
+	}
+	if (!JSM_CHANNEL->ch_equeue) {
+		JSM_CHANNEL->ch_equeue = (uchar *) kmalloc(EQUEUESIZE, GFP_KERNEL);
+		if (!JSM_CHANNEL->ch_equeue) {
+			DPR_INIT(("unable to allocate error queue buf"));
+			return -ENOMEM;
+		}
+		memset(JSM_CHANNEL->ch_equeue, 0, EQUEUESIZE);
+	}
+	if (!JSM_CHANNEL->ch_wqueue) {
+		JSM_CHANNEL->ch_wqueue = (uchar *) kmalloc(WQUEUESIZE, GFP_KERNEL);
+		if (!JSM_CHANNEL->ch_wqueue) {
+			DPR_INIT(("unable to allocate write queue buf"));
+			return -ENOMEM;
+		}
+		memset(JSM_CHANNEL->ch_wqueue, 0, WQUEUESIZE);
+	}
+
+	JSM_CHANNEL->ch_flags &= ~(CH_OPENING);
+	/*
+	 * Initialize if neither terminal is open.
+	 */
+	if (!(un->un_flags & UN_ISOPEN)) {
+		DPR_OPEN(("jsm_open: initializing channel in open...\n"));
+
+		/*
+		 * Flush input queues.
+		 */
+		JSM_CHANNEL->ch_r_head = JSM_CHANNEL->ch_r_tail = 0;
+		JSM_CHANNEL->ch_e_head = JSM_CHANNEL->ch_e_tail = 0;
+		JSM_CHANNEL->ch_w_head = JSM_CHANNEL->ch_w_tail = 0;
+
+		brd->bd_ops->flush_uart_write(JSM_CHANNEL);
+		brd->bd_ops->flush_uart_read(JSM_CHANNEL);
+
+		JSM_CHANNEL->ch_flags = 0;
+		JSM_CHANNEL->ch_cached_lsr = 0;
+		JSM_CHANNEL->ch_stops_sent = 0;
+
+		JSM_CHANNEL->ch_c_cflag   = port->info->tty->termios->c_cflag;
+		JSM_CHANNEL->ch_c_iflag   = port->info->tty->termios->c_iflag;
+		JSM_CHANNEL->ch_c_oflag   = port->info->tty->termios->c_oflag;
+		JSM_CHANNEL->ch_c_lflag   = port->info->tty->termios->c_lflag;
+		JSM_CHANNEL->ch_startc = port->info->tty->termios->c_cc[VSTART];
+		JSM_CHANNEL->ch_stopc  = port->info->tty->termios->c_cc[VSTOP];
+
+		/* Tell UART to init itself */
+		brd->bd_ops->uart_init(JSM_CHANNEL);
+	}
+	/*
+	 * Run param in case we changed anything
+	 */
+	brd->bd_ops->param(JSM_CHANNEL);
+
+	jsm_carrier(JSM_CHANNEL);
+	un->un_open_count++;
+	un->un_flags |= (UN_ISOPEN);
+
+	DPR_OPEN(("jsm_tty_open finished\n"));
+	return rc;
+}
+
+static void jsm_tty_close(struct uart_port *port)
+{
+	struct board_t *bd;
+	struct un_t *un;
+	struct termios *ts;
+	int rc = 0;
+
+	un = &JSM_CHANNEL->ch_tun;
+	
+	bd = JSM_CHANNEL->ch_bd;
+
+	ts = JSM_CHANNEL->uart_port.info->tty->termios;
+
+	DPR_CLOSE(("Close called\n"));
+
+	un->un_flags |= UN_CLOSING;
+
+	if ((JSM_CHANNEL->ch_open_count == 0)) {
+
+		JSM_CHANNEL->ch_flags &= ~(CH_STOPI);
+
+		/* wait for output to drain */
+		/* This will also return if we take an interrupt */
+
+		DPR_CLOSE(("Calling wait_for_drain\n"));
+		rc = bd->bd_ops->drain(port->info->tty, 0);
+
+		DPR_CLOSE(("After calling wait_for_drain\n"));
+
+		if (rc)
+			DPR_BASIC(("jsm_tty_close - bad return: %d ", rc));
+
+		/*
+		 * If we have HUPCL set, lower DTR and RTS
+		 */
+		if (JSM_CHANNEL->ch_c_cflag & HUPCL) {
+			DPR_CLOSE(("Close. HUPCL set, dropping DTR/RTS\n"));
+
+			/* Drop RTS/DTR */
+			JSM_CHANNEL->ch_mostat &= ~(UART_MCR_DTR | UART_MCR_RTS);
+			bd->bd_ops->assert_modem_signals(JSM_CHANNEL);
+
+			/*
+			 * Go to sleep to ensure RTS/DTR 
+			 * have been dropped for modems to see it.
+			 */
+		}
+
+		JSM_CHANNEL->ch_old_baud = 0;
+
+		/* Turn off UART interrupts for this port */
+		JSM_CHANNEL->ch_bd->bd_ops->uart_off(JSM_CHANNEL);
+	}
+
+	un->un_tty = NULL;
+	un->un_flags &= ~(UN_ISOPEN | UN_CLOSING);
+
+	DPR_CLOSE(("Close. Doing wakeups\n"));
+
+	DPR_BASIC(("jsm_tty_close - complete\n"));
+}
+
+static void jsm_tty_set_termios(struct uart_port *port,
+				 struct termios *termios,
+				 struct termios *old_termios)
+{
+	unsigned long lock_flags;
+
+	spin_lock_irqsave(&port->lock, lock_flags);
+	JSM_CHANNEL->ch_c_cflag   = termios->c_cflag;
+	JSM_CHANNEL->ch_c_iflag   = termios->c_iflag;
+	JSM_CHANNEL->ch_c_oflag   = termios->c_oflag;
+	JSM_CHANNEL->ch_c_lflag   = termios->c_lflag;
+	JSM_CHANNEL->ch_startc	= termios->c_cc[VSTART];
+	JSM_CHANNEL->ch_stopc	= termios->c_cc[VSTOP];
+
+	JSM_CHANNEL->ch_bd->bd_ops->param(JSM_CHANNEL);
+	jsm_carrier(JSM_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 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_register()
+ *
+ * Init the tty subsystem for this board.
+ */
+int jsm_tty_register(struct board_t *brd)
+{
+	int rc = 0;
+
+	DPR_INIT(("tty_register start\n"));
+
+	if (!brd->jsm_Major_Serial_Registered) {
+		if (rc < 0) {
+			APR(("Can't register tty device (%d)\n", rc));
+			return rc;
+		}
+		brd->jsm_Major_Serial_Registered = TRUE;
+		brd->jsm_Serial_Major = jsm_uart_driver.major;
+	}
+
+	DPR_INIT(("JSM REGISTER TTY: MAJOR: %d\n", jsm_uart_driver.major));
+
+	return rc;
+}
+
+/*
+ * jsm_tty_init()
+ *
+ * Init the tty subsystem.  Called once per board after board has been
+ * downloaded and init'ed.
+ */
+int jsm_tty_init(struct board_t *brd)
+{
+	int i;
+	uchar *vaddr;
+	struct channel_t *ch;
+
+	if (!brd)
+		return -ENXIO;
+
+	DPR_INIT(("jsm_tty_init start\n"));
+
+	/*
+	 * Initialize board structure elements.
+	 */
+
+	vaddr = brd->re_map_membase;
+
+	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] = kmalloc(sizeof(struct channel_t), GFP_KERNEL);
+			if (!brd->channels[i]) {
+				DPR_CORE(("%s:%d Unable to allocate memory for channel struct\n",
+				__FILE__, __LINE__));
+			}
+			memset(brd->channels[i], 0, sizeof(struct channel_t));
+		}
+	}
+
+	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);
+
+		/* Store all our magic numbers */
+		ch->magic = JSM_CHANNEL_MAGIC;
+		ch->ch_tun.magic = JSM_UNIT_MAGIC;
+		ch->ch_pun.magic = JSM_UNIT_MAGIC;
+
+		if (brd->bd_uart_offset == 0x200)
+			ch->ch_neo_uart = (struct neo_uart_struct *) ((ulong) 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);
+		init_waitqueue_head(&ch->ch_tun.un_flags_wait);
+		init_waitqueue_head(&ch->ch_pun.un_flags_wait);
+		init_waitqueue_head(&ch->ch_sniff_wait);
+	}
+
+	DPR_INIT(("jsm_tty_init finish\n"));
+
+	return 0;
+}
+
+int jsm_uart_port_init(struct board_t *brd)
+{
+	int i;
+	uchar *vaddr;
+	struct channel_t *ch;
+
+	if (!brd)
+		return -ENXIO;
+
+	DPR_INIT(("jsm_uart_port_init start\n"));
+
+	/*
+	 * Initialize board structure elements.
+	 */
+
+	vaddr = brd->re_map_membase;
+
+	brd->nasync = brd->maxports;
+
+	/* Set up channel variables */
+	for (i = 0; i < brd->nasync; i++, ch = brd->channels[i]) {
+
+		if (!brd->channels[i])
+			continue;
+
+		brd->channels[i]->uart_port.irq = brd->irq;
+		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;
+		brd->channels[i]->uart_port.line = brd->channels[i]->ch_portnum + brd->boardnum * 2;
+		if (uart_add_one_port (&jsm_uart_driver, &brd->channels[i]->uart_port)) 
+			printk(KERN_INFO "Added device failed\n");
+		else
+			printk(KERN_INFO "Added device \n");
+	}
+
+	DPR_INIT(("jsm_uart_port_init finish\n"));
+
+	return 0;
+}
+
+int jsm_remove_uart_port(struct board_t *brd)
+{
+	int i;
+	struct channel_t *ch;
+
+	if (!brd)
+		return -ENXIO;
+
+	DPR_INIT(("jsm_uart_port_init 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];
+
+		uart_remove_one_port(&jsm_uart_driver, &brd->channels[i]->uart_port);  
+	}
+
+	DPR_INIT(("jsm_uart_port_init finish\n"));
+
+	return 0;
+}
+
+/*
+ * jsm_tty_uninit()
+ *
+ * Uninitialize the TTY portion of this driver.  Free all memory and
+ * resources. 
+ */
+
+void jsm_tty_uninit(struct board_t *brd)
+{
+
+	if (brd->jsm_Major_Serial_Registered)
+		brd->jsm_Major_Serial_Registered = FALSE;
+}
+
+#define TMPBUFLEN (1024)
+
+/*
+ * jsm_sniff - Dump data out to the "sniff" buffer if the
+ * proc sniff file is opened...
+ */
+
+void jsm_sniff_nowait_nolock(struct channel_t *ch, uchar *text, uchar *buf, int len)
+{
+	struct timeval tv;
+	int n;
+	int r;
+	int nbuf;
+	int i;
+	int tmpbuflen;
+	char tmpbuf[TMPBUFLEN];
+	char *p = tmpbuf;
+	int too_much_data;
+
+	/* Leave if sniff not open */
+	if (!(ch->ch_sniff_flags & SNIFF_OPEN))
+		return;
+
+	do_gettimeofday(&tv);
+
+	/* Create our header for data dump */
+	p += sprintf(p, "<%ld %ld><%s><", tv.tv_sec, tv.tv_usec, text);
+	tmpbuflen = p - tmpbuf;
+
+	do {
+		too_much_data = 0;
+
+		for (i = 0; i < len && tmpbuflen < (TMPBUFLEN - 4); i++) {
+			p += sprintf(p, "%02x ", *buf);
+			buf++;
+			tmpbuflen = p - tmpbuf;
+		}
+
+		if (tmpbuflen < (TMPBUFLEN - 4)) {
+			if (i > 0)
+				p += sprintf(p - 1, "%s\n", ">");
+			else
+				p += sprintf(p, "%s\n", ">");
+		} else {
+			too_much_data = 1;
+			len -= i;
+		}
+
+		nbuf = strlen(tmpbuf);
+		p = tmpbuf;
+
+		/*
+		 *  Loop while data remains.
+		 */
+		while (nbuf > 0 && ch->ch_sniff_buf != 0) {
+			/*
+			 *  Determine the amount of available space left in the
+			 *  buffer.  If there's none, wait until some appears.
+			 */
+			n = (ch->ch_sniff_out - ch->ch_sniff_in - 1) & SNIFF_MASK;
+
+			/*
+			 * If there is no space left to write to in our sniff buffer,
+			 * we have no choice but to drop the data.
+			 * We *cannot* sleep here waiting for space, because this
+			 * function was probably called by the interrupt/timer routines!
+			 */
+			if (n == 0)
+				return;
+	
+			/*
+			 * Copy as much data as will fit.
+			 */
+
+			if (n > nbuf)
+				n = nbuf;
+
+			r = SNIFF_MAX - ch->ch_sniff_in;
+
+			if (r <= n) {
+				memcpy(ch->ch_sniff_buf + ch->ch_sniff_in, p, r);
+
+				n -= r;
+				ch->ch_sniff_in = 0;
+				p += r;
+				nbuf -= r;
+			}
+
+			memcpy(ch->ch_sniff_buf + ch->ch_sniff_in, p, n);
+
+			ch->ch_sniff_in += n;
+			p += n;
+			nbuf -= n;
+
+			/*
+			 *  Wakeup any thread waiting for data
+			 */
+			if (ch->ch_sniff_flags & SNIFF_WAIT_DATA) {
+				ch->ch_sniff_flags &= ~SNIFF_WAIT_DATA;
+				wake_up_interruptible(&ch->ch_sniff_wait);
+			}
+		}
+
+		/*
+		 * If the user sent us too much data to push into our tmpbuf,
+		 * we need to keep looping around on all the data.
+		 */
+		if (too_much_data) {
+			p = tmpbuf;
+			tmpbuflen = 0;
+		}
+
+	} while (too_much_data);
+}
+
+/*
+ *
+ *jsm_input - Process received data.
+ * 
+ *ch - Pointer to channel structure.
+ * 
+ */
+
+void jsm_input(struct channel_t *ch)
+{
+	struct board_t *bd;
+	struct tty_struct *tp;
+	uint	rmask;
+	ushort	head;
+	ushort	tail;
+	int	data_len;
+	ulong	lock_flags;
+	int flip_len;
+	int len = 0;
+	int n = 0;
+	char *buf = NULL;
+	char *buf2 = NULL;
+	int s = 0;
+	int i = 0;
+
+	if (!ch || ch->magic != JSM_CHANNEL_MAGIC)
+		return;
+
+	tp = ch->uart_port.info->tty;
+
+	bd = ch->ch_bd;
+	if(!bd || bd->magic != JSM_BOARD_MAGIC)
+		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;
+	}
+
+	DPR_READ(("jsm_input start\n"));
+
+	/*
+	 *If the device is not open, or CREAD is off, flush
+	 *input data and return immediately.
+	 */
+	if (!tp || !(ch->ch_tun.un_flags & UN_ISOPEN) || 
+		!(tp->termios->c_cflag & CREAD) || (ch->ch_tun.un_flags & UN_CLOSING)) {
+
+		DPR_READ(("input. dropping %d bytes on port %d...\n", data_len, ch->ch_portnum));
+		DPR_READ(("input. tp: %p tp->magic: %x MAGIC:%x ch flags: %x\n",
+			tp, tp ? tp->magic : 0, TTY_MAGIC, ch->ch_tun.un_flags));
+
+		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);
+		DPR_READ(("Port %d throttled, not reading any data. head: %x tail: %x\n",
+			ch->ch_portnum, head, tail));
+		return;
+	}
+
+	DPR_READ(("jsm_input start 2\n"));
+
+	/*
+	 * If the rxbuf is empty and we are not throttled, put as much
+	 * as we can directly into the linux TTY flip buffer.  
+	 * The jsm_rawreadok case takes advantage of carnal knowledge that
+	 * the char_buf and the flag_buf are next to each other and
+	 * are each of (2 * TTY_FLIPBUF_SIZE) size.
+	 *
+	 * NOTE: if(!tty->real_raw), the call to ldisc.receive_buf
+	 *actually still uses the flag buffer, so you can't
+	 *use it for input data
+	 */
+	if (jsm_rawreadok) {
+		if (tp->real_raw)
+			flip_len = MYFLIPLEN;
+		else
+			flip_len = 2 * TTY_FLIPBUF_SIZE;
+	} else
+		flip_len = TTY_FLIPBUF_SIZE - tp->flip.count;
+
+	len = min(data_len, flip_len);
+	len = min(len, (N_TTY_BUF_SIZE - 1) - tp->read_cnt);
+
+	if (len <= 0) {
+		spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
+		DPR_READ(("jsm_input 1 - finish\n"));
+		return;
+	}
+
+	/*
+	 * If we're bypassing flip buffers on rx, we can blast it
+	 * right into the beginning of the buffer.
+	 */ 
+	if (jsm_rawreadok) {
+		if (tp->real_raw) {
+			if (ch->ch_flags & CH_FLIPBUF_IN_USE) {
+				DPR_READ(("JSM - FLIPBUF in use. delaying input\n"));
+				spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
+				return;
+			}
+			ch->ch_flags |= CH_FLIPBUF_IN_USE;
+			buf = ch->ch_bd->flipbuf;
+			buf2 = NULL;
+		} else {
+			buf  = tp->flip.char_buf;
+			buf2 = tp->flip.flag_buf;
+		}
+	} else {
+		buf  = tp->flip.char_buf_ptr;
+		buf2 = tp->flip.flag_buf_ptr;
+	}
+
+	n = len;
+
+	/*
+	 * n 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 (n) {
+		s = ((head >= tail) ? head : RQUEUESIZE) - tail;
+		s = min(s, n);
+
+		if (s <= 0)
+			break;
+
+		memcpy(buf, ch->ch_rqueue + tail, s);
+		jsm_sniff_nowait_nolock(ch, "USER READ", ch->ch_rqueue + tail, s);
+
+		/* buf2 is only set when port isn't raw */
+		if (buf2)
+			memcpy(buf2, ch->ch_equeue + tail, s);
+
+
+
+		tail += s;
+		buf += s;
+		if (buf2)
+			buf2 += s;
+		n -= s;
+		/* Flip queue if needed */
+		tail &= rmask;
+	}
+
+	/*  
+	 * In high performance mode, we don't have to update
+	 * flag_buf or any of the counts or pointers into flip buf.
+	 */
+	if (!jsm_rawreadok) {
+		if (I_PARMRK(tp) || I_BRKINT(tp) || I_INPCK(tp)) {
+			for (i = 0; i < len; i++) {
+				/*
+				 * Give the Linux ld the flags in the
+				 * format it likes.
+				 */
+				if (tp->flip.flag_buf_ptr[i] & UART_LSR_BI)
+					tp->flip.flag_buf_ptr[i] = TTY_BREAK;
+				else if (tp->flip.flag_buf_ptr[i] & UART_LSR_PE)
+					tp->flip.flag_buf_ptr[i] = TTY_PARITY;
+				else if (tp->flip.flag_buf_ptr[i] & UART_LSR_FE)
+					tp->flip.flag_buf_ptr[i] = TTY_FRAME;
+				else 
+					tp->flip.flag_buf_ptr[i] = TTY_NORMAL;
+			}
+		} else  {
+			memset(tp->flip.flag_buf_ptr, 0, len);
+		}
+
+		tp->flip.char_buf_ptr += len;
+		tp->flip.flag_buf_ptr += len;
+		tp->flip.count += len;
+	}
+	else if (!tp->real_raw) {
+		if (I_PARMRK(tp) || I_BRKINT(tp) || I_INPCK(tp)) {
+			for (i = 0; i < len; i++) {
+				/*
+				 * Give the Linux ld the flags in the
+				 * format it likes.
+				 */
+				if (tp->flip.flag_buf_ptr[i] & UART_LSR_BI)
+					tp->flip.flag_buf_ptr[i] = TTY_BREAK;
+				else if (tp->flip.flag_buf_ptr[i] & UART_LSR_PE)
+					tp->flip.flag_buf_ptr[i] = TTY_PARITY;
+				else if (tp->flip.flag_buf_ptr[i] & UART_LSR_FE)
+					tp->flip.flag_buf_ptr[i] = TTY_FRAME;
+				else 
+					tp->flip.flag_buf_ptr[i] = TTY_NORMAL;
+			}
+		} else
+			memset(tp->flip.flag_buf, 0, len);
+	}
+
+	/*
+	 * If we're doing raw reads, jam it right into the
+	 * line disc bypassing the flip buffers.
+	 */
+	if (jsm_rawreadok) {
+		if (tp->real_raw) {
+			ch->ch_r_tail = tail & rmask;
+			ch->ch_e_tail = tail & rmask;
+
+			jsm_check_queue_flow_control(ch);
+
+			/* !!! WE *MUST* LET GO OF ALL LOCKS BEFORE CALLING RECEIVE BUF !!! */
+
+			spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
+
+			DPR_READ(("jsm_input. %d real_raw len:%d calling receive_buf for buffer for board %d\n", 
+				 __LINE__, len, ch->ch_bd->boardnum));
+			tp->ldisc.receive_buf(tp, ch->ch_bd->flipbuf, NULL, len);
+
+			/* Allow use of channel flip buffer again */
+			spin_lock_irqsave(&ch->ch_lock, lock_flags);
+			ch->ch_flags &= ~CH_FLIPBUF_IN_USE;
+			spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
+
+		} else {
+			ch->ch_r_tail = tail & rmask;
+			ch->ch_e_tail = tail & rmask;
+
+			jsm_check_queue_flow_control(ch);
+
+			/* !!! WE *MUST* LET GO OF ALL LOCKS BEFORE CALLING RECEIVE BUF !!! */
+			spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
+
+			DPR_READ(("jsm_input. %d not real_raw len:%d calling receive_buf for buffer for board %d\n", 
+				 __LINE__, len, ch->ch_bd->boardnum));
+
+			tp->ldisc.receive_buf(tp, tp->flip.char_buf, tp->flip.flag_buf, len);
+		}
+	} else  {
+		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);
+
+		DPR_READ(("jsm_input. %d not jsm_read raw okay scheduling flip\n", __LINE__)); 
+		tty_schedule_flip(tp);
+	}
+
+	DPR_READ(("jsm_input - finish\n"));
+}
+
+void jsm_carrier(struct channel_t *ch)
+{
+	struct board_t *bd;
+
+	int virt_carrier = 0;
+	int phys_carrier = 0;
+ 
+	DPR_CARR(("jsm_carrier called...\n"));
+
+	if (!ch || ch->magic != JSM_CHANNEL_MAGIC)
+		return;
+
+	bd = ch->ch_bd;
+
+	if (!bd || bd->magic != JSM_BOARD_MAGIC)
+		return;
+
+	if (ch->ch_mistat & UART_MSR_DCD) {
+		DPR_CARR(("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;
+
+	DPR_CARR(("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.
+		 */
+
+		DPR_CARR(("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.
+		 */
+
+		DPR_CARR(("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);
+
+		if (ch->ch_tun.un_open_count > 0) {
+			DPR_CARR(("Sending tty hangup\n"));
+			tty_hangup(ch->ch_tun.un_tty);
+		}
+
+		if (ch->ch_pun.un_open_count > 0) { 
+			DPR_CARR(("Sending pr hangup\n"));
+			tty_hangup(ch->ch_pun.un_tty);
+		}
+	}
+
+	/*
+	 *  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 channel_t *ch)
+{
+	int qleft = 0;
+
+	/* 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)) {
+				ch->ch_bd->bd_ops->disable_receiver(ch);
+				ch->ch_flags |= (CH_RECEIVER_OFF);
+				DPR_READ(("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) {
+				ch->ch_bd->bd_ops->send_stop_character(ch);
+				ch->ch_stops_sent++;
+				DPR_READ(("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) {
+				ch->ch_bd->bd_ops->enable_receiver(ch);
+				ch->ch_flags &= ~(CH_RECEIVER_OFF);
+				DPR_READ(("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;
+			ch->ch_bd->bd_ops->send_start_character(ch);
+			DPR_READ(("Sending start char!\n"));
+		}
+	}
+}
+
+/*
+ * 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.
+ */
+int jsm_tty_write(struct uart_port *port)
+{
+	struct un_t *un = NULL;
+	int bufcount = 0, n = 0;
+	int data_count = 0,data_count1 =0;
+	ushort head;
+	ushort tail;
+	ushort tmask;
+	uint remain;
+	int temp_tail = port->info->xmit.tail;
+
+	un = &JSM_CHANNEL->ch_tun;
+
+	tmask = WQUEUEMASK;
+	head = (JSM_CHANNEL->ch_w_head) & tmask;
+	tail = (JSM_CHANNEL->ch_w_tail) & tmask;
+
+	if ((bufcount = tail - head - 1) < 0)
+		bufcount += WQUEUESIZE;
+
+	n = bufcount;
+
+	n = min(n, 56);
+	remain = WQUEUESIZE - head;
+
+	data_count = 0;
+	if (n >= remain) {
+		n -= remain;
+		while ((port->info->xmit.head != temp_tail) &&
+		(data_count < remain)) {
+			JSM_CHANNEL->ch_wqueue[head++] =
+			port->info->xmit.buf[temp_tail];
+
+			temp_tail++;
+			temp_tail &= (UART_XMIT_SIZE - 1);
+			data_count++;
+		}
+		if (data_count == remain) head = 0;
+	}
+
+	data_count1 = 0;
+	if (n > 0) {
+		remain = n;
+		while ((port->info->xmit.head != temp_tail) &&
+			(data_count1 < remain)) {
+			JSM_CHANNEL->ch_wqueue[head++] =
+				port->info->xmit.buf[temp_tail];
+
+			temp_tail++;
+			temp_tail &= (UART_XMIT_SIZE - 1);
+			data_count1++;
+
+		}
+	}
+
+	port->info->xmit.tail = temp_tail;
+
+	data_count += data_count1;
+	if (data_count) {
+		head &= tmask;
+		JSM_CHANNEL->ch_w_head = head;
+	}
+
+	if (data_count) {
+		JSM_CHANNEL->ch_bd->bd_ops->copy_data_from_queue_to_uart(JSM_CHANNEL);
+	}
+
+	return data_count;
+}

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [ patch 2/7] drivers/serial/jsm: new serial device driver
  2005-02-27 23:38 [ patch 2/7] drivers/serial/jsm: new serial device driver Wen Xiong
@ 2005-02-28  0:25 ` Jeff Garzik
  2005-02-28  6:37 ` Greg KH
  1 sibling, 0 replies; 4+ messages in thread
From: Jeff Garzik @ 2005-02-28  0:25 UTC (permalink / raw)
  To: Wen Xiong; +Cc: linux-kernel, linux-serial, Andrew Morton

Wen Xiong wrote:
> +#define TMPBUFLEN (1024)
> +
> +/*
> + * jsm_sniff - Dump data out to the "sniff" buffer if the
> + * proc sniff file is opened...
> + */
> +
> +void jsm_sniff_nowait_nolock(struct channel_t *ch, uchar *text, uchar *buf, int len)
> +{
> +	struct timeval tv;
> +	int n;
> +	int r;
> +	int nbuf;
> +	int i;
> +	int tmpbuflen;
> +	char tmpbuf[TMPBUFLEN];

Uses WAY too much stack space.

	Jeff



^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [ patch 2/7] drivers/serial/jsm: new serial device driver
  2005-02-27 23:38 [ patch 2/7] drivers/serial/jsm: new serial device driver Wen Xiong
  2005-02-28  0:25 ` Jeff Garzik
@ 2005-02-28  6:37 ` Greg KH
  2005-03-04 21:07   ` Wen Xiong
  1 sibling, 1 reply; 4+ messages in thread
From: Greg KH @ 2005-02-28  6:37 UTC (permalink / raw)
  To: Wen Xiong; +Cc: linux-kernel, linux-serial

On Sun, Feb 27, 2005 at 06:38:44PM -0500, Wen Xiong wrote:

> diff -Nuar linux-2.6.9.orig/drivers/serial/jsm/jsm_tty.c linux-2.6.9.new/drivers/serial/jsm/jsm_tty.c
> --- linux-2.6.9.orig/drivers/serial/jsm/jsm_tty.c	1969-12-31 18:00:00.000000000 -0600
> +++ linux-2.6.9.new/drivers/serial/jsm/jsm_tty.c	2005-02-27 17:09:43.456960832 -0600
> @@ -0,0 +1,1273 @@
> +/*
> + * Copyright 2003 Digi International (www.digi.com)
> + *	Scott H Kilau <Scott_Kilau at digi dot com>

But didn't you do a lot of work on this code too?  Shouldn't you be
adding your copyright?

> + *	NOTE TO LINUX KERNEL HACKERS:  DO NOT REFORMAT THIS CODE! 
> + *
> + *	This is shared code between Digi's CVS archive and the
> + *	Linux Kernel sources.
> + *	Changing the source just for reformatting needlessly breaks
> + *	our CVS diff history.
> + *
> + *	Send any bug fixes/changes to:  Eng.Linux at digi dot com. 
> + *	Thank you. 

Is this still true?  The formatting looks sane, so you can probably take
this all out.  And put a real email address in there please...


> + * $Id: jsm_tty.c,v 1.79 2004/09/25 07:01:46 scottk Exp $

Take these out, not needed.

> +#include <linux/device.h>	/* For udelay */

Comment is incorrect.  What do you need device.h for?

> +	DPR_IOCTL(("jsm_getmstat start\n"));

You have odd macros with two "((", what's up with that?  Please use the
standard macros dev_dbg() and friends.  It's a way to get a standard
message out of the kernel.

> +static void jsm_tty_set_mctrl(struct uart_port *port, unsigned int mctrl)
> +{
> +	DPR_IOCTL(("jsm_set_modem_info() start\n"));

Oh, and why not just use __FUNCTION__?

> +static void jsm_tty_stop_rx(struct uart_port *port)
> +{
> +
> +	JSM_CHANNEL->ch_bd->bd_ops->disable_receiver(JSM_CHANNEL);
> +
> +}

I think you can drop the extra lines here...

And what's with the all uppercase JSM_CHANNEL?  Why not just use the
structure pointer.

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [ patch 2/7] drivers/serial/jsm: new serial device driver
  2005-02-28  6:37 ` Greg KH
@ 2005-03-04 21:07   ` Wen Xiong
  0 siblings, 0 replies; 4+ messages in thread
From: Wen Xiong @ 2005-03-04 21:07 UTC (permalink / raw)
  To: Greg KH; +Cc: Wen Xiong, linux-kernel

[-- Attachment #1: Type: text/plain, Size: 2482 bytes --]

Greg KH wrote:

>On Sun, Feb 27, 2005 at 06:38:44PM -0500, Wen Xiong wrote:
>
>  
>
>>diff -Nuar linux-2.6.9.orig/drivers/serial/jsm/jsm_tty.c linux-2.6.9.new/drivers/serial/jsm/jsm_tty.c
>>--- linux-2.6.9.orig/drivers/serial/jsm/jsm_tty.c	1969-12-31 18:00:00.000000000 -0600
>>+++ linux-2.6.9.new/drivers/serial/jsm/jsm_tty.c	2005-02-27 17:09:43.456960832 -0600
>>@@ -0,0 +1,1273 @@
>>+/*
>>+ * Copyright 2003 Digi International (www.digi.com)
>>+ *	Scott H Kilau <Scott_Kilau at digi dot com>
>>    
>>
>
>But didn't you do a lot of work on this code too?  Shouldn't you be
>adding your copyright?
>
>  
>
>>+ *	NOTE TO LINUX KERNEL HACKERS:  DO NOT REFORMAT THIS CODE! 
>>+ *
>>+ *	This is shared code between Digi's CVS archive and the
>>+ *	Linux Kernel sources.
>>+ *	Changing the source just for reformatting needlessly breaks
>>+ *	our CVS diff history.
>>+ *
>>+ *	Send any bug fixes/changes to:  Eng.Linux at digi dot com. 
>>+ *	Thank you. 
>>    
>>
>
>Is this still true?  The formatting looks sane, so you can probably take
>this all out.  And put a real email address in there please...
>
>
>  
>
>>+ * $Id: jsm_tty.c,v 1.79 2004/09/25 07:01:46 scottk Exp $
>>    
>>
>
>Take these out, not needed.
>
>  
>
>>+#include <linux/device.h>	/* For udelay */
>>    
>>
>
>Comment is incorrect.  What do you need device.h for?
>
>  
>
>>+	DPR_IOCTL(("jsm_getmstat start\n"));
>>    
>>
>
>You have odd macros with two "((", what's up with that?  Please use the
>standard macros dev_dbg() and friends.  It's a way to get a standard
>message out of the kernel.
>
>  
>
>>+static void jsm_tty_set_mctrl(struct uart_port *port, unsigned int mctrl)
>>+{
>>+	DPR_IOCTL(("jsm_set_modem_info() start\n"));
>>    
>>
>
>Oh, and why not just use __FUNCTION__?
>
>  
>
>>+static void jsm_tty_stop_rx(struct uart_port *port)
>>+{
>>+
>>+	JSM_CHANNEL->ch_bd->bd_ops->disable_receiver(JSM_CHANNEL);
>>+
>>+}
>>    
>>
>
>I think you can drop the extra lines here...
>
>And what's with the all uppercase JSM_CHANNEL?  Why not just use the
>structure pointer.
>
>thanks,
>
>greg k-h
>-
>To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
>the body of a message to majordomo@vger.kernel.org
>More majordomo info at  http://vger.kernel.org/majordomo-info.html
>Please read the FAQ at  http://www.tux.org/lkml/
>
>  
>
Hi All,
For patch2, the major changes are debug informaion.

Thanks for your help!
wendy

Signed-off-by: Wen Xiong <wendyx@us.ltcfwd.linux.ibm.com>



[-- Attachment #2: patch2.jasmine --]
[-- Type: text/plain, Size: 28845 bytes --]

diff -Nuar linux-2.6.11.org/drivers/serial/jsm/jsm_tty.c linux-2.6.11.new/drivers/serial/jsm/jsm_tty.c
--- linux-2.6.11.org/drivers/serial/jsm/jsm_tty.c	1969-12-31 18:00:00.000000000 -0600
+++ linux-2.6.11.new/drivers/serial/jsm/jsm_tty.c	2005-03-04 11:39:47.423875624 -0600
@@ -0,0 +1,1113 @@
+/************************************************************************
+ * Copyright 2003 Digi International (www.digi.com)
+ *
+ * Copyright (C) 2004 IBM Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; without even the 
+ * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
+ * PURPOSE.  See the GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License 
+ * along with this program; if not, write to the Free Software 
+ * Foundation, Inc., 59 * Temple Place - Suite 330, Boston,
+ * MA  02111-1307, USA.
+ *
+ * Contact Information:
+ * Scott H Kilau <Scott_Kilau@digi.com>
+ * Wendy Xiong   <wendyx@us.ltcfwd.linux.ibm.com>
+ *
+ ***********************************************************************/
+
+/************************************************************************
+ * 
+ * This file implements the tty driver functionality for the
+ * Neo and ClassicBoard PCI based product lines.
+ * 
+ ************************************************************************
+ */
+
+#include <linux/sched.h>	/* For jiffies, task states */
+#include <linux/interrupt.h>	/* For tasklet and interrupt structs/defines */
+#include <linux/ctype.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/delay.h>	/* For udelay */
+#include <asm/uaccess.h>	/* For copy_from_user/copy_to_user */
+
+#include "jsm_driver.h"
+
+/*Begin Serial_core API*/
+
+static inline int jsm_get_mstat(struct jsm_channel *ch)
+{
+	unsigned char mstat;
+	unsigned char result;
+
+	DPRINTK(IOCTL, INFO, "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;
+
+	DPRINTK(IOCTL, INFO, "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;
+
+	DPRINTK(IOCTL, INFO, "start\n");
+
+	result = jsm_get_mstat((struct jsm_channel *)port);
+
+	if (result < 0)
+		return -ENXIO;
+
+	DPRINTK(IOCTL, INFO, "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 = (struct jsm_channel *)port;
+
+	DPRINTK(IOCTL, INFO, "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);
+
+	DPRINTK(IOCTL, INFO, "finish\n");
+	udelay(10);
+}
+
+static void jsm_tty_start_tx(struct uart_port *port, unsigned int tty_start)
+{
+	struct jsm_channel *channel = (struct jsm_channel *)port;
+
+	DPRINTK(IOCTL, INFO, "start\n");
+
+	channel->ch_flags &= ~(CH_STOP);
+	jsm_tty_write(port);
+
+	DPRINTK(IOCTL, INFO, "finish\n");
+}
+
+static void jsm_tty_stop_tx(struct uart_port *port, unsigned int tty_stop)
+{
+	struct jsm_channel *channel = (struct jsm_channel *)port;
+	DPRINTK(IOCTL, INFO, "start\n");
+
+	channel->ch_flags |= (CH_STOP);
+
+	DPRINTK(IOCTL, INFO, "finish\n");
+}
+
+static void jsm_tty_send_xchar(struct uart_port *port, char ch)
+{
+	unsigned long lock_flags;
+	struct jsm_channel *channel = (struct jsm_channel *)port;
+
+	spin_lock_irqsave(&port->lock, lock_flags);
+	if (ch == port->info->tty->termios->c_cc[VSTART])
+		channel->ch_bd->bd_ops->send_start_character(channel);
+
+	if (ch == port->info->tty->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 =  (struct jsm_channel *)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 = (struct jsm_channel *)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, 0);
+
+	spin_unlock_irqrestore(&port->lock, lock_flags);
+}
+
+static int jsm_tty_open(struct uart_port *port)
+{
+	struct jsm_board *brd;
+	int rc = 0;
+	struct jsm_channel *channel = (struct jsm_channel *)port;
+
+	/* 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 = (u8 *) kmalloc(RQUEUESIZE, GFP_KERNEL);
+		if (!channel->ch_rqueue) {
+			DPRINTK(INIT, ERR, "unable to allocate read queue buf");
+			return -ENOMEM;
+		}
+		memset(channel->ch_rqueue, 0, RQUEUESIZE);
+	}
+	if (!channel->ch_equeue) {
+		channel->ch_equeue = (u8 *) kmalloc(EQUEUESIZE, GFP_KERNEL);
+		if (!channel->ch_equeue) {
+			DPRINTK(INIT, ERR, "unable to allocate error queue buf");
+			return -ENOMEM;
+		}
+		memset(channel->ch_equeue, 0, EQUEUESIZE);
+	}
+	if (!channel->ch_wqueue) {
+		channel->ch_wqueue = (u8 *) kmalloc(WQUEUESIZE, GFP_KERNEL);
+		if (!channel->ch_wqueue) {
+			DPRINTK(INIT, ERR, "unable to allocate write queue buf");
+			return -ENOMEM;
+		}
+		memset(channel->ch_wqueue, 0, WQUEUESIZE);
+	}
+
+	channel->ch_flags &= ~(CH_OPENING);
+	/*
+	 * Initialize if neither terminal is open.
+	 */
+	DPRINTK(OPEN, INFO, "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;
+	channel->ch_w_head = channel->ch_w_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;
+
+	channel->ch_c_cflag	= port->info->tty->termios->c_cflag;
+	channel->ch_c_iflag	= port->info->tty->termios->c_iflag;
+	channel->ch_c_oflag	= port->info->tty->termios->c_oflag;
+	channel->ch_c_lflag	= port->info->tty->termios->c_lflag;
+	channel->ch_startc = port->info->tty->termios->c_cc[VSTART];
+	channel->ch_stopc  = port->info->tty->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++;
+
+	DPRINTK(OPEN, INFO, "finished\n");
+	return rc;
+}
+
+static void jsm_tty_close(struct uart_port *port)
+{
+	struct jsm_board *bd;
+	struct termios *ts;
+	struct jsm_channel *channel = (struct jsm_channel *)port;
+
+	DPRINTK(CLOSE, INFO, "start \n");
+
+	bd = channel->ch_bd;
+	ts = channel->uart_port.info->tty->termios;
+
+	channel->ch_flags &= ~(CH_STOPI);
+
+	channel->ch_open_count--;
+
+	/*
+	 * If we have HUPCL set, lower DTR and RTS
+	 */
+	if (channel->ch_c_cflag & HUPCL) {
+		DPRINTK(CLOSE, INFO, "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);
+	}
+
+	channel->ch_old_baud = 0;
+
+	/* Turn off UART interrupts for this port */
+	channel->ch_bd->bd_ops->uart_off(channel);
+
+	DPRINTK(CLOSE, INFO, "finish\n");
+}
+
+static void jsm_tty_set_termios(struct uart_port *port,
+				 struct termios *termios,
+				 struct termios *old_termios)
+{
+	unsigned long lock_flags;
+	struct jsm_channel *channel = (struct jsm_channel *)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 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_register()
+ *
+ * Init the tty subsystem for this board.
+ */
+int jsm_tty_register(struct jsm_board *brd)
+{
+	int rc = 0;
+
+	DPRINTK(INIT, INFO, "start\n");
+
+	if (!brd->jsm_major_serial_registered) {
+		if (rc < 0) {
+			printk(KERN_ERR "Can't register tty device (%d)\n", rc);
+			return rc;
+		}
+		brd->jsm_major_serial_registered = 1;
+		brd->jsm_serial_major = jsm_uart_driver.major;
+	}
+
+	DPRINTK(INIT, INFO, "JSM REGISTER TTY: MAJOR: %d\n", jsm_uart_driver.major);
+
+	return rc;
+}
+
+/*
+ * 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;
+	u8 *vaddr;
+	struct jsm_channel *ch;
+
+	if (!brd)
+		return -ENXIO;
+
+	DPRINTK(INIT, INFO, "start\n");
+
+	/*
+	 * Initialize board structure elements.
+	 */
+
+	vaddr = brd->re_map_membase;
+
+	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] = kmalloc(sizeof(struct jsm_channel), GFP_KERNEL);
+			if (!brd->channels[i]) {
+				DPRINTK(CORE, ERR, "%s:%d Unable to allocate memory for channel struct\n",
+							 __FILE__, __LINE__);
+			}
+			memset(brd->channels[i], 0, sizeof(struct jsm_channel));
+		}
+	}
+
+	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 = (struct neo_uart_struct *) ((u64) 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);
+	}
+
+	DPRINTK(INIT, INFO, "finish\n");
+	return 0;
+}
+
+int jsm_uart_port_init(struct jsm_board *brd)
+{
+	int i;
+	u8 *vaddr;
+	struct jsm_channel *ch;
+
+	if (!brd)
+		return -ENXIO;
+
+	DPRINTK(INIT, INFO, "start\n");
+
+	/*
+	 * Initialize board structure elements.
+	 */
+
+	vaddr = brd->re_map_membase;
+	brd->nasync = brd->maxports;
+
+	/* Set up channel variables */
+	for (i = 0; i < brd->nasync; i++, ch = brd->channels[i]) {
+
+		if (!brd->channels[i])
+			continue;
+
+		brd->channels[i]->uart_port.irq = brd->irq;
+		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;
+		brd->channels[i]->uart_port.line = brd->channels[i]->ch_portnum + brd->boardnum * 2;
+		if (uart_add_one_port (&jsm_uart_driver, &brd->channels[i]->uart_port)) 
+			printk(KERN_INFO "Added device failed\n");
+		else
+			printk(KERN_INFO "Added device \n");
+	}
+
+	DPRINTK(INIT, INFO, "finish\n");
+	return 0;
+}
+
+int jsm_remove_uart_port(struct jsm_board *brd)
+{
+	int i;
+	struct jsm_channel *ch;
+
+	if (!brd)
+		return -ENXIO;
+
+	DPRINTK(INIT, INFO, "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];
+
+		uart_remove_one_port(&jsm_uart_driver, &brd->channels[i]->uart_port);  
+	}
+
+	DPRINTK(INIT, INFO, "finish\n");
+	return 0;
+}
+
+/*
+ * jsm_tty_uninit()
+ *
+ * Uninitialize the TTY portion of this driver.  Free all memory and
+ * resources. 
+ */
+
+void jsm_tty_uninit(struct jsm_board *brd)
+{
+	if (brd->jsm_major_serial_registered)
+		brd->jsm_major_serial_registered = 1;
+}
+
+/*
+ *
+ *jsm_input - Process received data.
+ * 
+ *ch - Pointer to channel structure.
+ * 
+ */
+
+void jsm_input(struct jsm_channel *ch)
+{
+	struct jsm_board *bd;
+	struct tty_struct *tp;
+	u32 rmask;
+	u16 head;
+	u16 tail;
+	int data_len;
+	u64 lock_flags;
+	int flip_len;
+	int len = 0;
+	int n = 0;
+	char *buf = NULL;
+	char *buf2 = NULL;
+	int s = 0;
+	int i = 0;
+
+	DPRINTK(READ, INFO, "strat\n");
+	if (!ch)
+		return;
+
+	tp = ch->uart_port.info->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;
+	}
+
+	DPRINTK(READ, INFO, "start\n");
+
+	/*
+	 *If the device is not open, or CREAD is off, flush
+	 *input data and return immediately.
+	 */
+	if (!tp || 
+		!(tp->termios->c_cflag & CREAD) ) {
+
+		DPRINTK(READ, INFO, "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);
+		DPRINTK(READ, INFO, "Port %d throttled, not reading any data. head: %x tail: %x\n",
+			ch->ch_portnum, head, tail);
+		return;
+	}
+
+	DPRINTK(READ, INFO, "start 2\n");
+
+	/*
+	 * If the rxbuf is empty and we are not throttled, put as much
+	 * as we can directly into the linux TTY flip buffer.  
+	 * The jsm_rawreadok case takes advantage of carnal knowledge that
+	 * the char_buf and the flag_buf are next to each other and
+	 * are each of (2 * TTY_FLIPBUF_SIZE) size.
+	 *
+	 * NOTE: if(!tty->real_raw), the call to ldisc.receive_buf
+	 *actually still uses the flag buffer, so you can't
+	 *use it for input data
+	 */
+	if (rawreadok) {
+		if (tp->real_raw)
+			flip_len = MYFLIPLEN;
+		else
+			flip_len = 2 * TTY_FLIPBUF_SIZE;
+	} else
+		flip_len = TTY_FLIPBUF_SIZE - tp->flip.count;
+
+	len = min(data_len, flip_len);
+	len = min(len, (N_TTY_BUF_SIZE - 1) - tp->read_cnt);
+
+	if (len <= 0) {
+		spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
+		DPRINTK(READ, INFO, "jsm_input 1 - finish\n");
+		return;
+	}
+
+	/*
+	 * If we're bypassing flip buffers on rx, we can blast it
+	 * right into the beginning of the buffer.
+	 */ 
+	if (rawreadok) {
+		if (tp->real_raw) {
+			if (ch->ch_flags & CH_FLIPBUF_IN_USE) {
+				DPRINTK(READ, INFO, "JSM - FLIPBUF in use. delaying input\n");
+				spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
+				return;
+			}
+			ch->ch_flags |= CH_FLIPBUF_IN_USE;
+			buf = ch->ch_bd->flipbuf;
+			buf2 = NULL;
+		} else {
+			buf  = tp->flip.char_buf;
+			buf2 = tp->flip.flag_buf;
+		}
+	} else {
+		buf  = tp->flip.char_buf_ptr;
+		buf2 = tp->flip.flag_buf_ptr;
+	}
+
+	n = len;
+
+	/*
+	 * n 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 (n) {
+		s = ((head >= tail) ? head : RQUEUESIZE) - tail;
+		s = min(s, n);
+
+		if (s <= 0)
+			break;
+
+		memcpy(buf, ch->ch_rqueue + tail, s);
+
+		/* buf2 is only set when port isn't raw */
+		if (buf2)
+			memcpy(buf2, ch->ch_equeue + tail, s);
+
+		tail += s;
+		buf += s;
+		if (buf2)
+			buf2 += s;
+		n -= s;
+		/* Flip queue if needed */
+		tail &= rmask;
+	}
+
+	/*  
+	 * In high performance mode, we don't have to update
+	 * flag_buf or any of the counts or pointers into flip buf.
+	 */
+	if (!rawreadok) {
+		if (I_PARMRK(tp) || I_BRKINT(tp) || I_INPCK(tp)) {
+			for (i = 0; i < len; i++) {
+				/*
+				 * Give the Linux ld the flags in the
+				 * format it likes.
+				 */
+				if (tp->flip.flag_buf_ptr[i] & UART_LSR_BI)
+					tp->flip.flag_buf_ptr[i] = TTY_BREAK;
+				else if (tp->flip.flag_buf_ptr[i] & UART_LSR_PE)
+					tp->flip.flag_buf_ptr[i] = TTY_PARITY;
+				else if (tp->flip.flag_buf_ptr[i] & UART_LSR_FE)
+					tp->flip.flag_buf_ptr[i] = TTY_FRAME;
+				else 
+					tp->flip.flag_buf_ptr[i] = TTY_NORMAL;
+			}
+		} else  {
+			memset(tp->flip.flag_buf_ptr, 0, len);
+		}
+
+		tp->flip.char_buf_ptr += len;
+		tp->flip.flag_buf_ptr += len;
+		tp->flip.count += len;
+	}
+	else if (!tp->real_raw) {
+		if (I_PARMRK(tp) || I_BRKINT(tp) || I_INPCK(tp)) {
+			for (i = 0; i < len; i++) {
+				/*
+				 * Give the Linux ld the flags in the
+				 * format it likes.
+				 */
+				if (tp->flip.flag_buf_ptr[i] & UART_LSR_BI)
+					tp->flip.flag_buf_ptr[i] = TTY_BREAK;
+				else if (tp->flip.flag_buf_ptr[i] & UART_LSR_PE)
+					tp->flip.flag_buf_ptr[i] = TTY_PARITY;
+				else if (tp->flip.flag_buf_ptr[i] & UART_LSR_FE)
+					tp->flip.flag_buf_ptr[i] = TTY_FRAME;
+				else 
+					tp->flip.flag_buf_ptr[i] = TTY_NORMAL;
+			}
+		} else
+			memset(tp->flip.flag_buf, 0, len);
+	}
+
+	/*
+	 * If we're doing raw reads, jam it right into the
+	 * line disc bypassing the flip buffers.
+	 */
+	if (rawreadok) {
+		if (tp->real_raw) {
+			ch->ch_r_tail = tail & rmask;
+			ch->ch_e_tail = tail & rmask;
+
+			jsm_check_queue_flow_control(ch);
+
+			/* !!! WE *MUST* LET GO OF ALL LOCKS BEFORE CALLING RECEIVE BUF !!! */
+
+			spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
+
+			DPRINTK(READ, INFO, 
+				"jsm_input. %d real_raw len:%d calling receive_buf for board %d\n",
+				__LINE__, len, ch->ch_bd->boardnum);
+			tp->ldisc.receive_buf(tp, ch->ch_bd->flipbuf, NULL, len);
+
+			/* Allow use of channel flip buffer again */
+			spin_lock_irqsave(&ch->ch_lock, lock_flags);
+			ch->ch_flags &= ~CH_FLIPBUF_IN_USE;
+			spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
+
+		} else {
+			ch->ch_r_tail = tail & rmask;
+			ch->ch_e_tail = tail & rmask;
+
+			jsm_check_queue_flow_control(ch);
+
+			/* !!! WE *MUST* LET GO OF ALL LOCKS BEFORE CALLING RECEIVE BUF !!! */
+			spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
+
+			DPRINTK(READ, INFO,
+				"jsm_input. %d not real_raw len:%d calling receive_buf for board %d\n", 
+				__LINE__, len, ch->ch_bd->boardnum);
+
+			tp->ldisc.receive_buf(tp, tp->flip.char_buf, tp->flip.flag_buf, len);
+		}
+	} else  {
+		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);
+
+		DPRINTK(READ, INFO, "jsm_input. %d not jsm_read raw okay scheduling flip\n", __LINE__); 
+		tty_schedule_flip(tp);
+	}
+
+	DPRINTK(READ, INFO, "finish\n");
+}
+
+void jsm_carrier(struct jsm_channel *ch)
+{
+	struct jsm_board *bd;
+
+	int virt_carrier = 0;
+	int phys_carrier = 0;
+ 
+	DPRINTK(CARR, INFO, "start...\n");
+	if (!ch)
+   		return;
+
+	bd = ch->ch_bd;
+
+	if (!bd)
+		return;
+
+	if (ch->ch_mistat & UART_MSR_DCD) {
+		DPRINTK(CARR, INFO, "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;
+
+	DPRINTK(CARR, INFO, "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.
+		 */
+
+		DPRINTK(CARR, INFO, "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.
+		 */
+
+		DPRINTK(CARR, INFO, "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)
+{
+	int qleft = 0;
+
+	/* 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)) {
+				ch->ch_bd->bd_ops->disable_receiver(ch);
+				ch->ch_flags |= (CH_RECEIVER_OFF);
+				DPRINTK(READ, INFO, "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) {
+				ch->ch_bd->bd_ops->send_stop_character(ch);
+				ch->ch_stops_sent++;
+				DPRINTK(READ, INFO, "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) {
+				ch->ch_bd->bd_ops->enable_receiver(ch);
+				ch->ch_flags &= ~(CH_RECEIVER_OFF);
+				DPRINTK(READ, INFO, "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;
+			ch->ch_bd->bd_ops->send_start_character(ch);
+			DPRINTK(READ, INFO, "Sending start char!\n");
+		}
+	}
+}
+
+/*
+ * 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.
+ */
+int jsm_tty_write(struct uart_port *port)
+{
+	int bufcount = 0, n = 0;
+	int data_count = 0,data_count1 =0;
+	u16 head;
+	u16 tail;
+	u16 tmask;
+	u32 remain;
+	int temp_tail = port->info->xmit.tail;
+	struct jsm_channel *channel = (struct jsm_channel *)port;
+
+	tmask = WQUEUEMASK;
+	head = (channel->ch_w_head) & tmask;
+	tail = (channel->ch_w_tail) & tmask;
+
+	if ((bufcount = tail - head - 1) < 0)
+		bufcount += WQUEUESIZE;
+
+	n = bufcount;
+
+	n = min(n, 56);
+	remain = WQUEUESIZE - head;
+
+	data_count = 0;
+	if (n >= remain) {
+		n -= remain;
+		while ((port->info->xmit.head != temp_tail) &&
+		(data_count < remain)) {
+			channel->ch_wqueue[head++] =
+			port->info->xmit.buf[temp_tail];
+
+			temp_tail++;
+			temp_tail &= (UART_XMIT_SIZE - 1);
+			data_count++;
+		}
+		if (data_count == remain) head = 0;
+	}
+
+	data_count1 = 0;
+	if (n > 0) {
+		remain = n;
+		while ((port->info->xmit.head != temp_tail) &&
+			(data_count1 < remain)) {
+			channel->ch_wqueue[head++] =
+				port->info->xmit.buf[temp_tail];
+
+			temp_tail++;
+			temp_tail &= (UART_XMIT_SIZE - 1);
+			data_count1++;
+
+		}
+	}
+
+	port->info->xmit.tail = temp_tail;
+
+	data_count += data_count1;
+	if (data_count) {
+		head &= tmask;
+		channel->ch_w_head = head;
+	}
+
+	if (data_count) {
+		channel->ch_bd->bd_ops->copy_data_from_queue_to_uart(channel);
+	}
+
+	return data_count;
+}
+#if TRC_TO_IOCTL
+/*
+ * jsm_ioctl_name()
+ *
+ * Returns a text version of each ioctl value.
+ */
+char *jsm_ioctl_name(int cmd)
+{
+	switch(cmd) {
+
+	case TCGETA:		return("TCGETA");
+	case TCGETS:		return("TCGETS");
+	case TCSETA:		return("TCSETA");
+	case TCSETS:		return("TCSETS");
+	case TCSETAW:		return("TCSETAW");
+	case TCSETSW:		return("TCSETSW");
+	case TCSETAF:		return("TCSETAF");
+	case TCSETSF:		return("TCSETSF");
+	case TCSBRK:		return("TCSBRK");
+	case TCXONC:		return("TCXONC");
+	case TCFLSH:		return("TCFLSH");
+	case TIOCGSID:		return("TIOCGSID");
+
+	case TIOCGETD:		return("TIOCGETD");
+	case TIOCSETD:		return("TIOCSETD");
+	case TIOCGWINSZ:	return("TIOCGWINSZ");
+	case TIOCSWINSZ:	return("TIOCSWINSZ");
+
+	case TIOCMGET:		return("TIOCMGET");
+	case TIOCMSET:		return("TIOCMSET");
+	case TIOCMBIS:		return("TIOCMBIS");
+	case TIOCMBIC:		return("TIOCMBIC");
+
+	/* from digi.h */
+	case DIGI_SETA:		return("DIGI_SETA");
+	case DIGI_SETAW:	return("DIGI_SETAW");
+	case DIGI_SETAF:	return("DIGI_SETAF");
+	case DIGI_SETFLOW:	return("DIGI_SETFLOW");
+	case DIGI_SETAFLOW:	return("DIGI_SETAFLOW");
+	case DIGI_GETFLOW:	return("DIGI_GETFLOW");
+	case DIGI_GETAFLOW:	return("DIGI_GETAFLOW");
+	case DIGI_GETA:		return("DIGI_GETA");
+	case DIGI_GEDELAY:	return("DIGI_GEDELAY");
+	case DIGI_SEDELAY:	return("DIGI_SEDELAY");
+	case DIGI_GETCUSTOMBAUD: return("DIGI_GETCUSTOMBAUD");
+	case DIGI_SETCUSTOMBAUD: return("DIGI_SETCUSTOMBAUD");
+	case TIOCMODG:		return("TIOCMODG");
+	case TIOCMODS:		return("TIOCMODS");
+	case TIOCSDTR:		return("TIOCSDTR");
+	case TIOCCDTR:		return("TIOCCDTR");
+
+	default:		return("unknown");
+	}
+}
+#endif

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2005-03-04 22:48 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2005-02-27 23:38 [ patch 2/7] drivers/serial/jsm: new serial device driver Wen Xiong
2005-02-28  0:25 ` Jeff Garzik
2005-02-28  6:37 ` Greg KH
2005-03-04 21:07   ` Wen Xiong

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).