linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Giuseppe Guerrini <giusguerrini@racine.ra.it>
To: linux-kernel@vger.kernel.org, linux-kernel-patch@vger.kernel.org
Subject: [PATCH] serial.c, kernel 2.2.14
Date: Sun, 10 Dec 2000 23:54:58 +0100 (CET)	[thread overview]
Message-ID: <Pine.LNX.4.21.0012102350390.1084-300000@gaia.localdomain> (raw)

[-- Attachment #1: Type: TEXT/PLAIN, Size: 974 bytes --]



 Hi, Linux community!

 Some time ago I had to add a proprietary multiport card to my Linux box,
and found a small incompatibility with the standard Linux serial
driver. The driver confuses the NEC NS1655x-family UARTs with Startch
ST16550, and decide not to use the FIFO, although the NEC UARTs fully
support it. In addition, the identifying algorithm is able to mess up the
state of NEC16552 Dual UART. The patch in attachment solved my problem. I
generated and tested it only on my RedHat 6.2 Linux box with kernel
2.2.14. The patch adds an item in the kernel configuration menu
("CONFIG_NEC_DUART_SUPPORT"). Although it should be harmless, I suggest to
use it only if really needed.

	Bye

P.S. Please answer at my personal address, because I am not subscribed to
the mailing list.

-- 


-- 


		Giuseppe Guerrini <giusguerrini@racine.ra.it>
------------------------------------------------------------
L'ordine non e` che una configurazione particolare del caos.




[-- Attachment #2: Type: TEXT/PLAIN, Size: 1095 bytes --]



Sun Dec 10 23:25:24 CET 2000

 The NEC-DUART patch corrects a bug in Linux-2.2.14' serial driver
(file linux/drivers/char/serial.c). The chipset probe algorithm
doesn't identify as full-compatible 16550A UART the chips of the NEC
NS1655x family: the FIFO is not enabled, although present and fully working.
In addition, with the DUAL UART NS16552A, the chip state is messed up.
 Although harmful, the patch should be applied only if really needed.
Use it only if you are sure that you are using a NEC NS1655x UART and
are experiencing loss of characters. 
 I have developed and tested my patch on Linux 2.2.14. I can't guaratee
that it works well with other kernels.
 The patch must be applied as follows:
(I assume that there is a complete kernel source tree
in /usr/src/linux-2.2.14)

su
cd /usr/src
patch -p0 < patch-NecDuart

 A new configuration item will be added in "character devices" section:

   Bugfix for NEC UARTs (NS16C55x)
 
 Enable it, save the new configuration and rebuild the kernel.

 Enjoy,

	Giuseppe Guerrini <giusguerrini@racine.ra.it>


[-- Attachment #3: Type: TEXT/PLAIN, Size: 6781 bytes --]

diff -Naur linux-2.2.14/Documentation/Configure.help linux-2.2.14-NecDuart/Documentation/Configure.help
--- linux-2.2.14/Documentation/Configure.help	Tue Apr 25 16:21:15 2000
+++ linux-2.2.14-NecDuart/Documentation/Configure.help	Sun Dec 10 13:39:52 2000
@@ -1343,6 +1343,20 @@
 
   Most people can say N here.
 
+Bugfix for NEC NS16C55x UARTs
+CONFIG_NEC_DUART_SUPPORT
+  Say Y here if you have a NEC NS1655x-family UART (NS16550Ax,
+  NS16C552x), and are experiencing problems (characters loss).
+  The standard serial driver is used to confuse the NEC UARTs
+  with Startech UARTs without FIFO support (NEC UARTs have
+  full 16550A FIFO). Use the "setserial" command to know if the
+  kernel has detected the wrong chip model.
+
+  You must say Y also if you are using the SER2 or IOSPC64 cards
+  produced by CNi (www.cnisrl.it).
+
+  If unsure, say N.
+
 Extended dumb serial driver options
 CONFIG_SERIAL_EXTENDED
   If you wish to use any non-standard features of the standard "dumb"
diff -Naur linux-2.2.14/drivers/char/Config.in linux-2.2.14-NecDuart/drivers/char/Config.in
--- linux-2.2.14/drivers/char/Config.in	Tue Apr 25 16:21:14 2000
+++ linux-2.2.14-NecDuart/drivers/char/Config.in	Sun Dec 10 13:35:29 2000
@@ -10,6 +10,7 @@
 fi
 tristate 'Standard/generic (dumb) serial support' CONFIG_SERIAL
 if [ "$CONFIG_SERIAL" = "y" ]; then
+   bool '   Bugfix for NEC UARTs (NS16C55x)' CONFIG_NEC_DUART_SUPPORT
    bool '   Support for console on serial port' CONFIG_SERIAL_CONSOLE
 fi
 bool 'Extended dumb serial driver options' CONFIG_SERIAL_EXTENDED
diff -Naur linux-2.2.14/drivers/char/serial.c linux-2.2.14-NecDuart/drivers/char/serial.c
--- linux-2.2.14/drivers/char/serial.c	Tue Apr 25 16:21:13 2000
+++ linux-2.2.14-NecDuart/drivers/char/serial.c	Sun Dec 10 13:43:17 2000
@@ -154,8 +154,13 @@
 #define _INLINE_ inline
 #endif
 	
+
 static char *serial_name = "Serial driver";
-static char *serial_version = "4.27";
+static char *serial_version = "4.27"
+#ifdef CONFIG_NEC_DUART_SUPPORT
+	" - NECDUART fix 1.0"
+#endif
+					;
 
 static DECLARE_TASK_QUEUE(tq_serial);
 
@@ -199,6 +204,18 @@
 	{ "ST16650V2", 32, UART_CLEAR_FIFO | UART_USE_FIFO |
 		  UART_STARTECH }, 
 	{ "TI16750", 64, UART_CLEAR_FIFO | UART_USE_FIFO},
+#ifdef CONFIG_NEC_DUART_SUPPORT
+	  /* The NEC NS16C55x is actually a 16550A. If I added
+	   * a specific record for this particular chipset in "uart_config",
+	   * I would have to change both "serial.h" and the "setserial"
+	   * utility. I don't think it's worth. Anyway, this source is
+	   * ready to accept the change. */
+#ifndef PORT_NS16C550AF
+#define PORT_NS16C550AF (PORT_MAX + 1)
+#else
+	{ "NS16C55x", 16, UART_CLEAR_FIFO | UART_USE_FIFO }, 
+#endif
+#endif
 	{ 0, 0}
 };
 
@@ -2821,6 +2838,10 @@
 static _INLINE_ void show_serial_version(void)
 {
  	printk(KERN_INFO "%s version %s with", serial_name, serial_version);
+#ifdef CONFIG_NEC_DUART_SUPPORT
+	printk(" NEC_DUART");
+#define SERIAL_OPT
+#endif
 #ifdef CONFIG_HUB6
 	printk(" HUB-6");
 #define SERIAL_OPT
@@ -2959,8 +2980,8 @@
 	scratch2 = serial_inp(info, UART_IER);
 	serial_outp(info, UART_IER, scratch);
 	if (scratch2) {
-		restore_flags(flags);
-		return;		/* We failed; there's nothing here */
+		/* We failed; there's nothing here */
+		goto autoconfig_END_fail;
 	}
 
 	/* 
@@ -2979,8 +3000,7 @@
 		status1 = serial_inp(info, UART_MSR) & 0xF0;
 		serial_outp(info, UART_MCR, scratch);
 		if (status1 != 0x90) {
-			restore_flags(flags);
-			return;
+			goto autoconfig_END_fail;
 		}
 	} 
 	
@@ -3008,13 +3028,61 @@
 		/* Check for Startech UART's */
 		serial_outp(info, UART_LCR, scratch2 | UART_LCR_DLAB);
 		if (serial_in(info, UART_EFR) == 0) {
+#ifdef CONFIG_NEC_DUART_SUPPORT
+		  /* giusguerrini@racine.ra.it: Both ST16650 and NS16C55x
+		   * behaves the same, so the ortiginal algorithm is not
+		   * enough to detect them. We have to do something
+		   * smarter. */
+		  /* OK, there could be an ST16650 or a NEC NS16C55x.
+		   * The former uses many bits in EFR(=FCR+DLAB), the latter
+		   * uses only bits 0, 1 and 2, and zeroes other bits.
+		   * So, we'll try to detect an ST16650 by setting some
+		   * high bit in EFR (e.g. the CTS protocol enabler), and
+		   * then verifying if it has really been set. */
+			serial_outp(info, UART_LCR, 0xBF);
+			serial_outp(info, UART_EFR, UART_EFR_CTS);
+			serial_outp(info, UART_LCR, 0xBF);
+			if (serial_in(info, UART_EFR) & UART_EFR_CTS) {
+			  /* bit set succeeded. It's an ST16650. */
+				state->type = PORT_16650;
+				serial_outp(info, UART_LCR, 0xBF);
+				serial_outp(info, UART_EFR, 0);
+			}
+			else {
+			  /* bit set unsuccesful. Perhaps we are using a NEC double UART.
+			   * We must remeber it, because
+			   *  - this chip fully supports the 166550A mode,
+			   *  - this chip doesn't like the TI 16750
+			   *    detection algorithm, so we must avoid it. */
+				state->type = PORT_NS16C550AF;
+				serial_outp(info, UART_LCR, scratch2);
+			}
+#else /* CONFIG_NEC_DUART_SUPPORT */
 			state->type = PORT_16650;
+#endif /* CONFIG_NEC_DUART_SUPPORT */
 		} else {
 			serial_outp(info, UART_LCR, 0xBF);
 			if (serial_in(info, UART_EFR) == 0)
 				state->type = PORT_16650V2;
 		}
 	}
+#ifdef CONFIG_NEC_DUART_SUPPORT
+	if (state->type == PORT_NS16C550AF) {
+#if PORT_NS16C550AF == (PORT_MAX + 1)
+	  /* Hide the "internal" type code. I'm too lazy to change
+	   * serail.h, setserial,... But the code is ready. */
+		state->type = PORT_16550A;
+#endif
+		serial_outp(info, UART_FCR, UART_FCR_ENABLE_FIFO);
+	}
+	else
+	/* giusguerrini@racine.ra.it: Arrrgh! This messes up the NEC
+	 * NS16C552A dual UART. Bit 0 of FCR+DLAB enables concurrent write
+	 * on registers of BOTH UARTs. So, with this chip we can't write
+	 * the ENABLE_FIFO bit when DLAB is set. That's why we won't
+	 * execute this code if we detected a NS16C55x (and, anyway,
+	 * we have already detected the chip!). */
+#endif /* CONFIG_NEC_DUART_SUPPORT */
 	if (state->type == PORT_16550A) {
 		/* Check for TI 16750 */
 		serial_outp(info, UART_LCR, scratch2 | UART_LCR_DLAB);
@@ -3044,8 +3112,7 @@
 	state->xmit_fifo_size =	uart_config[state->type].dfl_xmit_fifo_size;
 
 	if (state->type == PORT_UNKNOWN) {
-		restore_flags(flags);
-		return;
+		goto autoconfig_END_fail;
 	}
 
 	request_region(info->port,8,"serial(auto)");
@@ -3066,8 +3133,13 @@
 				     UART_FCR_CLEAR_XMIT));
 	(void)serial_in(info, UART_RX);
 	serial_outp(info, UART_IER, 0);
-	
+
+autoconfig_END:
 	restore_flags(flags);
+	return;
+
+autoconfig_END_fail:
+	goto autoconfig_END;
 }
 
 int register_serial(struct serial_struct *req);

                 reply	other threads:[~2000-12-11  0:31 UTC|newest]

Thread overview: [no followups] expand[flat|nested]  mbox.gz  Atom feed

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=Pine.LNX.4.21.0012102350390.1084-300000@gaia.localdomain \
    --to=giusguerrini@racine.ra.it \
    --cc=linux-kernel-patch@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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).