Subject: Hayes ESP card final(?) patches
To: Robert Dobbs <banshee@gabriella.resort.com>
From: Michael L. VanLoon -- HeadCandy.com <michaelv@HeadCandy.com>
List: port-i386
Date: 09/12/1995 21:53:16
Last night, once again, I just decided I had to get this thing
perfect.  I rearranged the probe logic a little bit so it didn't query
the ESP card on every pass through the comprobe loop.  I also added
code so the automatic FIFO adjust logic wouldn't mess up the ESP.
Here's my latest set of patches.  Patch 1 is against Robert Dobbs' ESP
patch.  Patch 2 is the same code against the standard NetBSD com.c.

Off the top of my head, I don't think anything else needs to be done
to these.  With the possible exception of better configuration code,
where the ESP enhanced I/O address isn't hard-coded.  Maybe eventually
something like the boca and ast drivers where there's a "master", and
the ports themselves are "slaves".  This would have the added benefit
of "just working" with multi-port ESP boards.  That would probably
involve a master esp.c, and a completely separate driver unlrelated to
com.c.  I'm not sure I'm ready to tackle that right away, however.

This code has been running in my machine all day, with a cron job
auto-connecting and disconnecting my PPP connection at various times.
I have seen absolutely no problems.  It *looked* like it was
processing packets a little quicker when I supped, but of course
that's probably purely subjective and my imagination. :-) If Mr. Dobbs
agrees, I'd like to ask Charles to look these over and see if he'd be
willing to incorporate them into /sys/dev/isa/com.c.  And, thanks
Robert for doing the initial work to make this all possible.


Patch 1 (Robert Dobbs' ESP-enhanced com.c vs. my new com.c):

     ----- >8 ---------- Begin patch ---------- 8< -----
--- esp/com.c-esp	Sun Sep 10 20:07:57 1995
+++ com.c	Mon Sep 11 23:04:04 1995
@@ -172,14 +172,25 @@
 	return 1;
 }
 
-void comprobeESP(iobase, sc)
-	int iobase;
+void comprobeESP(esp_iobase, com_iobase, sc)
+	int esp_iobase;
+	int com_iobase;
 	struct com_softc *sc;
 {
 	char	val;
+	char	dips;
+	int	combaselist[] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8 };
+
+	/*
+	 * Hayes ESP cards have two iobases.  One is for compatibility with
+	 * 16550 serial chips, and at the same ISA PC base addresses.  The
+	 * other is for ESP-specific enhanced features, and lies at a
+	 * different addressing range entirely (0x140, 0x180, or 0x280).
+	 * Hence the need for esp_iobase and com_iobase.
+	 */
 
 	/* Test for ESP signature */
-	if ((inb(iobase) & 0xf3) == 0)
+	if ((inb(esp_iobase) & 0xf3) == 0)
 		return;
 
 #define ESP_GETTEST	0x01
@@ -188,31 +199,46 @@
 #define ESP_STATUS1	4
 #define ESP_STATUS2	5
 
+	/*
+	 * ESP is present at ESP enhanced base address; unknown com port
+	 */
+
+	/* Get the dip-switch configurations */
+	outb(esp_iobase + ESP_CMD1, ESP_GETDIPS);
+	dips = inb(esp_iobase + ESP_STATUS1);
+
+	/* Determine which com port this ESP card services: bits 0,1 of  */
+	/*  dips is the port # (0-3); combaselist[val] is the com_iobase */
+	if (com_iobase == combaselist[dips & 0x03]) {
+		printf(": ESP");
+	} else {
+		/* this com port is not us */
+		return;
+	}
+
 	/* Check for ESP version 2.0: bits 4,5,6 == 010 */
-	outb(iobase + ESP_CMD1, ESP_GETTEST);
-	val = inb(iobase + ESP_STATUS1);	/* Clear reg 1 */
-	val = inb(iobase + ESP_STATUS2);
+	outb(esp_iobase + ESP_CMD1, ESP_GETTEST);
+	val = inb(esp_iobase + ESP_STATUS1);	/* Clear reg 1 */
+	val = inb(esp_iobase + ESP_STATUS2);
 	if ((val & 0x70) < 0x20) {
-		printf(": old ESP(%o)", val & 0x70);
+		printf("-old (%o)", val & 0x70);
+		/* we do not support the necessary features */
 		return;
 	}
 
 	/* Check for ability to emulate 16550: bit 8 == 1 */
-	outb(iobase + ESP_CMD1, ESP_GETDIPS);
-	val = inb(iobase + ESP_STATUS1);
-	if ((val & 0x80) == 0) {
-		printf(": ESP slave");
+	if ((dips & 0x80) == 0) {
+		printf(" slave");
+		/* XXX Does slave really mean no 16550 support?? */
 		return;
 	}
 
-	/* Determine which com port this ESP card services: bits 0,1 */
-	val &= 0x03;	/* Mask off all but bits 0,1 */
+	/*
+	 * If we made it this far, we are a full-featured ESP v2.0 (or
+	 * better), at the correct com port address.
+	 */
 
-	/* sc->sc_dev.dv_unit is the com port: 0..3 */
-	if (sc->sc_dev.dv_unit == val) {
-		sc->sc_hwflags |= COM_HW_ESP;
-		printf(": ESP");
-	}
+	sc->sc_hwflags |= COM_HW_ESP;
 }
 
 int
@@ -250,7 +276,7 @@
 		delay(1000);
 
 	/* look for a Hayes ESP board at ESP_PORT */
-	comprobeESP(ESP_PORT, sc);
+	comprobeESP(ESP_PORT, iobase, sc);
 
 	/* look for a NS 16550AF UART with FIFOs */
 	outb(iobase + com_fifo,
@@ -673,7 +699,7 @@
 	 * Set the FIFO threshold based on the receive speed, if we are
 	 * changing it.
 	 */
-	if (tp->t_ispeed != t->c_ispeed) {
+	if ((tp->t_ispeed != t->c_ispeed) && !(sc->sc_hwflags & COM_HW_ESP)) {
 		if (sc->sc_hwflags & COM_HW_FIFO)
 			outb(iobase + com_fifo,
 			    FIFO_ENABLE |
     ----- >8 ----------  End patch  ---------- 8< -----


Patch 2 (standard NetBSD com.c vs. my new com.c):

     ----- >8 ---------- Begin patch ---------- 8< -----
--- esp/com.c-orig	Tue Jul  4 00:04:29 1995
+++ com.c	Mon Sep 11 23:04:04 1995
@@ -62,7 +62,9 @@
 #include <dev/isa/comreg.h>
 #include <dev/ic/ns16550reg.h>
 
-#define	COM_IBUFSIZE	(2 * 256)
+#define ESP_PORT	0x140	/* IO Address for ESP (jumpered on card) */
+
+#define	COM_IBUFSIZE	(2 * 512)
 #define	COM_IHIGHWATER	((3 * COM_IBUFSIZE) / 4)
 
 struct com_softc {
@@ -78,6 +80,7 @@
 	u_char sc_hwflags;
 #define	COM_HW_NOIEN	0x01
 #define	COM_HW_FIFO	0x02
+#define	COM_HW_ESP	0x04
 #define	COM_HW_CONSOLE	0x40
 	u_char sc_swflags;
 #define	COM_SW_SOFTCAR	0x01
@@ -169,6 +172,75 @@
 	return 1;
 }
 
+void comprobeESP(esp_iobase, com_iobase, sc)
+	int esp_iobase;
+	int com_iobase;
+	struct com_softc *sc;
+{
+	char	val;
+	char	dips;
+	int	combaselist[] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8 };
+
+	/*
+	 * Hayes ESP cards have two iobases.  One is for compatibility with
+	 * 16550 serial chips, and at the same ISA PC base addresses.  The
+	 * other is for ESP-specific enhanced features, and lies at a
+	 * different addressing range entirely (0x140, 0x180, or 0x280).
+	 * Hence the need for esp_iobase and com_iobase.
+	 */
+
+	/* Test for ESP signature */
+	if ((inb(esp_iobase) & 0xf3) == 0)
+		return;
+
+#define ESP_GETTEST	0x01
+#define ESP_GETDIPS	0x02
+#define ESP_CMD1	4
+#define ESP_STATUS1	4
+#define ESP_STATUS2	5
+
+	/*
+	 * ESP is present at ESP enhanced base address; unknown com port
+	 */
+
+	/* Get the dip-switch configurations */
+	outb(esp_iobase + ESP_CMD1, ESP_GETDIPS);
+	dips = inb(esp_iobase + ESP_STATUS1);
+
+	/* Determine which com port this ESP card services: bits 0,1 of  */
+	/*  dips is the port # (0-3); combaselist[val] is the com_iobase */
+	if (com_iobase == combaselist[dips & 0x03]) {
+		printf(": ESP");
+	} else {
+		/* this com port is not us */
+		return;
+	}
+
+	/* Check for ESP version 2.0: bits 4,5,6 == 010 */
+	outb(esp_iobase + ESP_CMD1, ESP_GETTEST);
+	val = inb(esp_iobase + ESP_STATUS1);	/* Clear reg 1 */
+	val = inb(esp_iobase + ESP_STATUS2);
+	if ((val & 0x70) < 0x20) {
+		printf("-old (%o)", val & 0x70);
+		/* we do not support the necessary features */
+		return;
+	}
+
+	/* Check for ability to emulate 16550: bit 8 == 1 */
+	if ((dips & 0x80) == 0) {
+		printf(" slave");
+		/* XXX Does slave really mean no 16550 support?? */
+		return;
+	}
+
+	/*
+	 * If we made it this far, we are a full-featured ESP v2.0 (or
+	 * better), at the correct com port address.
+	 */
+
+	sc->sc_hwflags |= COM_HW_ESP;
+}
+
 int
 comprobe(parent, match, aux)
 	struct device *parent;
@@ -203,6 +275,9 @@
 	if (sc->sc_dev.dv_unit == comconsole)
 		delay(1000);
 
+	/* look for a Hayes ESP board at ESP_PORT */
+	comprobeESP(ESP_PORT, iobase, sc);
+
 	/* look for a NS 16550AF UART with FIFOs */
 	outb(iobase + com_fifo,
 	    FIFO_ENABLE | FIFO_RCV_RST | FIFO_XMT_RST | FIFO_TRIGGER_14);
@@ -311,6 +386,30 @@
 		sc->sc_ibufend = sc->sc_ibuf + COM_IBUFSIZE;
 
 		iobase = sc->sc_iobase;
+		/* Setup the ESP board */
+		if (sc->sc_hwflags & COM_HW_ESP) {
+			outb(iobase + com_fifo,
+			    FIFO_DMA_MODE | FIFO_ENABLE | FIFO_RCV_RST | FIFO_XMT_RST | FIFO_TRIGGER_8);
+#define ESP_SETMODE	0x10
+#define ESP_CMD2	5
+			/* Set 16550 compatibility mode */
+			outb(ESP_PORT + ESP_CMD1, ESP_SETMODE);
+			outb(ESP_PORT + ESP_CMD2, 0x80 | 0x04 | 0x02);
+#define ESP_SETFLOWTYPE	0x0A
+			/* Set RTS/CTS flow control */
+			outb(ESP_PORT + ESP_CMD1, ESP_SETFLOWTYPE);
+			outb(ESP_PORT + ESP_CMD2, 0x04);
+			outb(ESP_PORT + ESP_CMD2, 0x10);
+#define ESP_SETRXFLOW	0x0A
+#define HIBYTE(w)       ((char)(((short)(w) >> 8) & 0xff))
+#define LOBYTE(w)       ((char)(w))
+			/* Set flow control levels */
+			outb(ESP_PORT + ESP_CMD1, ESP_SETRXFLOW);
+			outb(ESP_PORT + ESP_CMD2, HIBYTE(768));
+			outb(ESP_PORT + ESP_CMD2, LOBYTE(768));
+			outb(ESP_PORT + ESP_CMD2, HIBYTE(512));
+			outb(ESP_PORT + ESP_CMD2, LOBYTE(512));
+		} else
 		/* Set the FIFO threshold based on the receive speed. */
 		if (sc->sc_hwflags & COM_HW_FIFO)
 			outb(iobase + com_fifo,
@@ -600,7 +699,7 @@
 	 * Set the FIFO threshold based on the receive speed, if we are
 	 * changing it.
 	 */
-	if (tp->t_ispeed != t->c_ispeed) {
+	if ((tp->t_ispeed != t->c_ispeed) && !(sc->sc_hwflags & COM_HW_ESP)) {
 		if (sc->sc_hwflags & COM_HW_FIFO)
 			outb(iobase + com_fifo,
 			    FIFO_ENABLE |
@@ -674,6 +773,13 @@
 		selwakeup(&tp->t_wsel);
 	}
 	tp->t_state |= TS_BUSY;
+	if (sc->sc_hwflags & COM_HW_ESP) {
+		u_char buffer[1024], *cp = buffer;
+		int n = q_to_b(&tp->t_outq, cp, sizeof buffer);
+		do {
+			outb(iobase + com_data, *cp++);
+		} while (--n);
+	} else
 	if (sc->sc_hwflags & COM_HW_FIFO) {
 		u_char buffer[16], *cp = buffer;
 		int n = q_to_b(&tp->t_outq, cp, sizeof buffer);
     ----- >8 ----------  End patch  ---------- 8< -----


-----------------------------------------------------------------------------
  Michael L. VanLoon                                 michaelv@HeadCandy.com
       --<  Free your mind and your machine -- NetBSD free un*x  >--
     NetBSD working ports: 386+PC, Mac, Amiga, HP300, Sun3, Sun4, PC532,
                           DEC pmax (MIPS R2k/3k), DEC/AXP (Alpha)
     NetBSD ports in progress: VAX and others...
-----------------------------------------------------------------------------