Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 6 Sep 2003 18:25:28 -0700 (PDT)
From:      Marcel Moolenaar <marcel@FreeBSD.org>
To:        Perforce Change Reviews <perforce@freebsd.org>
Subject:   PERFORCE change 37696 for review
Message-ID:  <200309070125.h871PSTR095618@repoman.freebsd.org>

next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=37696

Change 37696 by marcel@marcel_nfs on 2003/09/06 18:25:18

	Revert the SIO/ng from this branch (with extreme prejudice).

Affected files ...

.. //depot/projects/ia64/sys/conf/files#98 edit
.. //depot/projects/ia64/sys/conf/files.ia64#47 edit
.. //depot/projects/ia64/sys/dev/sio/sio.c#50 edit
.. //depot/projects/ia64/sys/dev/sio/sio_cons.c#14 delete
.. //depot/projects/ia64/sys/dev/sio/sio_ebus.c#8 edit
.. //depot/projects/ia64/sys/dev/sio/sio_isa.c#18 edit
.. //depot/projects/ia64/sys/dev/sio/sio_pccard.c#12 edit
.. //depot/projects/ia64/sys/dev/sio/sio_pci.c#19 edit
.. //depot/projects/ia64/sys/dev/sio/sio_puc.c#10 edit
.. //depot/projects/ia64/sys/dev/sio/sioreg.h#8 edit
.. //depot/projects/ia64/sys/dev/sio/siovar.h#16 edit
.. //depot/projects/ia64/sys/ia64/ia64/sio_machdep.c#10 delete

Differences ...

==== //depot/projects/ia64/sys/conf/files#98 (text+ko) ====

@@ -677,8 +677,6 @@
 dev/si/si_eisa.c	optional si eisa
 dev/si/si_isa.c		optional si isa
 dev/si/si_pci.c		optional si pci
-dev/sio/sio.c		optional sio
-dev/sio/sio_cons.c	optional sio
 dev/sio/sio_ebus.c	optional sio ebus
 dev/sio/sio_pccard.c	optional sio card
 dev/sio/sio_pccard.c	optional sio pccard

==== //depot/projects/ia64/sys/conf/files.ia64#47 (text+ko) ====

@@ -57,7 +57,7 @@
 dev/kbd/kbd.c			optional	sc
 dev/kbd/kbd.c			optional	ukbd
 dev/ppc/ppc.c			optional	ppc isa
-dev/sio/sio_isa.c		optional	sio acpi
+dev/sio/sio.c			optional	sio
 dev/sio/sio_isa.c		optional	sio isa
 dev/syscons/schistory.c		optional	sc
 dev/syscons/scmouse.c		optional	sc
@@ -115,7 +115,6 @@
 ia64/ia64/sal.c			standard
 ia64/ia64/sapic.c		standard
 ia64/ia64/setjmp.S		standard
-ia64/ia64/sio_machdep.c		optional	sio
 ia64/ia64/ssc.c			optional	ski
 ia64/ia64/sscdisk.c		optional	ski
 ia64/ia64/support.S		standard
@@ -129,8 +128,8 @@
 ia64/isa/isa.c			optional	isa
 ia64/isa/isa_dma.c		optional	isa
 ia64/pci/pci_cfgreg.c		optional	pci
-isa/atkbd_isa.c			optional	isa atkbd
-isa/atkbdc_isa.c		optional	isa atkbdc
+isa/atkbd_isa.c			optional	atkbd isa
+isa/atkbdc_isa.c		optional	atkbdc isa
 isa/fd.c			optional	fdc isa
 isa/psm.c			optional	psm isa
 isa/syscons_isa.c		optional	sc

==== //depot/projects/ia64/sys/dev/sio/sio.c#50 (text+ko) ====

@@ -38,6 +38,7 @@
 __FBSDID("$FreeBSD: src/sys/dev/sio/sio.c,v 1.404 2003/08/28 03:54:49 njl Exp $");
 
 #include "opt_comconsole.h"
+#include "opt_compat.h"
 #include "opt_ddb.h"
 #include "opt_sio.h"
 
@@ -67,6 +68,7 @@
 #include <sys/sysctl.h>
 #include <sys/syslog.h>
 #include <sys/tty.h>
+#include <machine/bus_pio.h>
 #include <machine/bus.h>
 #include <sys/rman.h>
 #include <sys/timepps.h>
@@ -76,12 +78,18 @@
 #include <ddb/ddb.h>
 #endif
 
+#include <isa/isavar.h>
+
 #include <machine/resource.h>
-#include <machine/stdarg.h>
 
 #include <dev/sio/sioreg.h>
 #include <dev/sio/siovar.h>
 
+#ifdef COM_ESP
+#include <dev/ic/esp.h>
+#endif
+#include <dev/ic/ns16550.h>
+
 #define	LOTS_OF_EVENTS	64	/* helps separate urgent events from input */
 
 #define	CALLOUT_MASK		0x80
@@ -94,6 +102,19 @@
 #define	UNIT_TO_MINOR(unit)	((((unit) & ~0x1fU) << (8 + 3)) \
 				 | ((unit) & 0x1f))
 
+#ifdef COM_MULTIPORT
+/* checks in flags for multiport and which is multiport "master chip"
+ * for a given card
+ */
+#define	COM_ISMULTIPORT(flags)	((flags) & 0x01)
+#define	COM_MPMASTER(flags)	(((flags) >> 8) & 0x0ff)
+#define	COM_NOTAST4(flags)	((flags) & 0x04)
+#else
+#define	COM_ISMULTIPORT(flags)	(0)
+#endif /* COM_MULTIPORT */
+
+#define	COM_CONSOLE(flags)	((flags) & 0x10)
+#define	COM_FORCECONSOLE(flags)	((flags) & 0x20)
 #define	COM_LLCONSOLE(flags)	((flags) & 0x40)
 #define	COM_DEBUGGER(flags)	((flags) & 0x80)
 #define	COM_LOSESOUTINTS(flags)	((flags) & 0x08)
@@ -108,6 +129,11 @@
 #define	COM_TI16754(flags)	((flags) & 0x200000)
 #define	COM_FIFOSIZE(flags)	(((flags) & 0xff000000) >> 24)
 
+#define	sio_getreg(com, off) \
+	(bus_space_read_1((com)->bst, (com)->bsh, (off)))
+#define	sio_setreg(com, off, value) \
+	(bus_space_write_1((com)->bst, (com)->bsh, (off), (value)))
+
 /*
  * com state bits.
  * (CS_BUSY | CS_TTGO) and (CS_BUSY | CS_TTGO | CS_ODEVREADY) must be higher
@@ -143,9 +169,129 @@
 	"tty-level buffer overflow",
 };
 
+#define	CE_NTYPES			3
 #define	CE_RECORD(com, errnum)		(++(com)->delta_error_counts[errnum])
 
+/* types.  XXX - should be elsewhere */
+typedef u_int	Port_t;		/* hardware port */
+typedef u_char	bool_t;		/* boolean */
+
+/* queue of linear buffers */
+struct lbq {
+	u_char	*l_head;	/* next char to process */
+	u_char	*l_tail;	/* one past the last char to process */
+	struct lbq *l_next;	/* next in queue */
+	bool_t	l_queued;	/* nonzero if queued */
+};
+
+/* com device structure */
+struct com_s {
+	u_int	flags;		/* Copy isa device flags */
+	u_char	state;		/* miscellaneous flag bits */
+	bool_t  active_out;	/* nonzero if the callout device is open */
+	u_char	cfcr_image;	/* copy of value written to CFCR */
+#ifdef COM_ESP
+	bool_t	esp;		/* is this unit a hayes esp board? */
+#endif
+	u_char	extra_state;	/* more flag bits, separate for order trick */
+	u_char	fifo_image;	/* copy of value written to FIFO */
+	bool_t	hasfifo;	/* nonzero for 16550 UARTs */
+	bool_t	st16650a;	/* Is a Startech 16650A or RTS/CTS compat */
+	bool_t	loses_outints;	/* nonzero if device loses output interrupts */
+	u_char	mcr_image;	/* copy of value written to MCR */
+#ifdef COM_MULTIPORT
+	bool_t	multiport;	/* is this unit part of a multiport device? */
+#endif /* COM_MULTIPORT */
+	bool_t	no_irq;		/* nonzero if irq is not attached */
+	bool_t  gone;		/* hardware disappeared */
+	bool_t	poll;		/* nonzero if polling is required */
+	bool_t	poll_output;	/* nonzero if polling for output is required */
+	int	unit;		/* unit	number */
+	int	dtr_wait;	/* time to hold DTR down on close (* 1/hz) */
+	u_int	tx_fifo_size;
+	u_int	wopeners;	/* # processes waiting for DCD in open() */
+
+	/*
+	 * The high level of the driver never reads status registers directly
+	 * because there would be too many side effects to handle conveniently.
+	 * Instead, it reads copies of the registers stored here by the
+	 * interrupt handler.
+	 */
+	u_char	last_modem_status;	/* last MSR read by intr handler */
+	u_char	prev_modem_status;	/* last MSR handled by high level */
+
+	u_char	hotchar;	/* ldisc-specific char to be handled ASAP */
+	u_char	*ibuf;		/* start of input buffer */
+	u_char	*ibufend;	/* end of input buffer */
+	u_char	*ibufold;	/* old input buffer, to be freed */
+	u_char	*ihighwater;	/* threshold in input buffer */
+	u_char	*iptr;		/* next free spot in input buffer */
+	int	ibufsize;	/* size of ibuf (not include error bytes) */
+	int	ierroff;	/* offset of error bytes in ibuf */
+
+	struct lbq	obufq;	/* head of queue of output buffers */
+	struct lbq	obufs[2];	/* output buffers */
+
+	bus_space_tag_t		bst;
+	bus_space_handle_t	bsh;
+
+	Port_t	data_port;	/* i/o ports */
+#ifdef COM_ESP
+	Port_t	esp_port;
+#endif
+	Port_t	int_id_port;
+	Port_t	modem_ctl_port;
+	Port_t	line_status_port;
+	Port_t	modem_status_port;
+	Port_t	intr_ctl_port;	/* Ports of IIR register */
+
+	struct tty	*tp;	/* cross reference */
+
+	/* Initial state. */
+	struct termios	it_in;	/* should be in struct tty */
+	struct termios	it_out;
+
+	/* Lock state. */
+	struct termios	lt_in;	/* should be in struct tty */
+	struct termios	lt_out;
+
+	bool_t	do_timestamp;
+	bool_t	do_dcd_timestamp;
+	struct timeval	timestamp;
+	struct timeval	dcd_timestamp;
+	struct	pps_state pps;
+	int	pps_bit;
+#ifdef ALT_BREAK_TO_DEBUGGER
+	int	alt_brk_state;
+#endif
+
+	u_long	bytes_in;	/* statistics */
+	u_long	bytes_out;
+	u_int	delta_error_counts[CE_NTYPES];
+	u_long	error_counts[CE_NTYPES];
+
+	u_long	rclk;
+
+	struct resource *irqres;
+	struct resource *ioportres;
+	int	ioportrid;
+	void	*cookie;
+	dev_t	devs[6];
+
+	/*
+	 * Data area for output buffers.  Someday we should build the output
+	 * buffer queue without copying data.
+	 */
+	u_char	obuf1[256];
+	u_char	obuf2[256];
+};
+
+#ifdef COM_ESP
+static	int	espattach(struct com_s *com, Port_t esp_port);
+#endif
+
 static	timeout_t siobusycheck;
+static	u_int	siodivisor(u_long rclk, speed_t speed);
 static	timeout_t siodtrwakeup;
 static	void	comhardclose(struct com_s *com);
 static	void	sioinput(struct com_s *com);
@@ -191,16 +337,18 @@
 	.d_kqfilter =	ttykqfilter,
 };
 
-speed_t comdefaultrate = CONSPEED;
-
-u_long comdefaultrclk = DEFAULT_RCLK;
+int	comconsole = -1;
+static	volatile speed_t	comdefaultrate = CONSPEED;
+static	u_long			comdefaultrclk = DEFAULT_RCLK;
 SYSCTL_ULONG(_machdep, OID_AUTO, conrclk, CTLFLAG_RW, &comdefaultrclk, 0, "");
-
-static speed_t gdbdefaultrate = GDBSPEED;
-SYSCTL_ULONG(_machdep, OID_AUTO, gdbspeed, CTLFLAG_RW, &gdbdefaultrate,
-    GDBSPEED, "");
-
+static	speed_t			gdbdefaultrate = GDBSPEED;
+SYSCTL_UINT(_machdep, OID_AUTO, gdbspeed, CTLFLAG_RW,
+	    &gdbdefaultrate, GDBSPEED, "");
 static	u_int	com_events;	/* input chars + weighted output completions */
+static	Port_t	siocniobase;
+static	int	siocnunit = -1;
+static	Port_t	siogdbiobase;
+static	int	siogdbunit = -1;
 static	void	*sio_slow_ih;
 static	void	*sio_fast_ih;
 static	int	sio_timeout;
@@ -209,6 +357,13 @@
     = CALLOUT_HANDLE_INITIALIZER(&sio_timeout_handle);
 static	int	sio_numunits;
 
+#ifdef COM_ESP
+/* XXX configure this properly. */
+/* XXX quite broken for new-bus. */
+static	Port_t	likely_com_ports[] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, };
+static	Port_t	likely_esp_ports[] = { 0x140, 0x180, 0x280, 0 };
+#endif
+
 /*
  * handle sysctl read/write requests for console speed
  * 
@@ -235,10 +390,13 @@
 
 	comdefaultrate = newspeed;
 
-	com = &sio_console;
-	if (com->consdev == NULL)
+	if (comconsole < 0)		/* serial console not selected? */
 		return (0);
 
+	com = com_addr(comconsole);
+	if (com == NULL)
+		return (ENXIO);
+
 	/*
 	 * set the initial and lock rates for /dev/ttydXX and /dev/cuaXX
 	 * (note, the lock rates really are boolean -- if non-zero, disallow
@@ -267,497 +425,545 @@
 	    0, 0, sysctl_machdep_comdefaultrate, "I", "");
 /* TUNABLE_INT("machdep.conspeed", &comdefaultrate); */
 
-#ifdef SIO_DEBUG
-static void
-siodebug(struct com_s *com, const char *fmt, ...)
-{
-	va_list ap;
+#define SET_FLAG(dev, bit) device_set_flags(dev, device_get_flags(dev) | (bit))
+#define CLR_FLAG(dev, bit) device_set_flags(dev, device_get_flags(dev) & ~(bit))
 
-	va_start(ap, fmt);
-	if (com != NULL)
-		device_print_prettyname(com->dev);
-	vprintf(fmt, ap);
-	va_end(ap);
-}
-#else
-static __inline void
-siodebug(struct com_s *com, const char *fmt, ...)
-{
-}
-#endif
-
 /*
- * Flush the UART. Flush the transmitter FIFO and shift register first, then
- * flush the receiver FIFO. In this order flushing works correctly even when
- * the UART is in loopback mode. Bad timing may cause at most one character
- * to remain in the receiver FIFO/buffer after we're done flushing. This
- * would be the character that is (partly) in the receiver shift register.
+ *	Unload the driver and clear the table.
+ *	XXX this is mostly wrong.
+ *	XXX TODO:
+ *	This is usually called when the card is ejected, but
+ *	can be caused by a kldunload of a controller driver.
+ *	The idea is to reset the driver's view of the device
+ *	and ensure that any driver entry points such as
+ *	read and write do not hang.
  */
-static int
-sioflush(struct com_s *com)
+int
+siodetach(dev)
+	device_t	dev;
 {
-	int delay, limit;
+	struct com_s	*com;
+	int i;
 
-	/* 1/10th the time to transmit 1 character (estimate). */
-	delay = 16000000 * com->reg_dl / com->rclk;
-
-	/* Flush the transmitter. */
-	limit = (com->fifosize) ? com->fifosize : 1;
-	limit = (limit + 2) * 10;
-	while ((sio_getreg(com, com_lsr) & LSR_TEMT) == 0 && --limit)
-		DELAY(delay);
-	if (limit == 0) {
-		siodebug(NULL, "transmitter appears stuck... ");
-		return (EIO);
+	com = (struct com_s *) device_get_softc(dev);
+	if (com == NULL) {
+		device_printf(dev, "NULL com in siounload\n");
+		return (0);
 	}
-
-	DELAY(10*delay);
-
-	/*
-	 * Flush the receiver. Pick an arbitrary high limit to avoid
-	 * getting stuck in an infinite loop when the hardware is
-	 * broken.
-	 */
-	limit=32768;
-	while ((sio_getreg(com, com_lsr) & LSR_RXRDY) && --limit) {
-		(void)sio_getreg(com, com_data);
-		/* XXX barrier */
-		DELAY(5*delay);
+	com->gone = 1;
+	for (i = 0 ; i < 6; i++)
+		destroy_dev(com->devs[i]);
+	if (com->irqres) {
+		bus_teardown_intr(dev, com->irqres, com->cookie);
+		bus_release_resource(dev, SYS_RES_IRQ, 0, com->irqres);
 	}
-	if (limit == 0) {
-		siodebug(NULL, "receiver appears broken... ");
-		return (EIO);
+	if (com->ioportres)
+		bus_release_resource(dev, SYS_RES_IOPORT, com->ioportrid,
+				     com->ioportres);
+	if (com->tp && (com->tp->t_state & TS_ISOPEN)) {
+		device_printf(dev, "still open, forcing close\n");
+		(*linesw[com->tp->t_line].l_close)(com->tp, 0);
+		com->tp->t_gen++;
+		ttyclose(com->tp);
+		ttwakeup(com->tp);
+		ttwwakeup(com->tp);
+	} else {
+		if (com->ibuf != NULL)
+			free(com->ibuf, M_DEVBUF);
+		device_set_softc(dev, NULL);
+		free(com, M_DEVBUF);
 	}
-
 	return (0);
 }
 
-/*
- * Initialize the FIFOs and determine the size of the receiver FIFO. We
- * assume that the transmitter FIFO has the same size. First we set DMA
- * mode (mode 1) with the highest trigger level. In combination with
- * loopback this allows us to determine the size of the receiver FIFO.
- * After that we re-initialize with a medium high trigger level. This
- * function is expected to be called with FIFOs disabled.
- */
-static int
-sioinitfifo(struct com_s *com)
+int
+sioprobe(dev, xrid, rclk, noprobe)
+	device_t	dev;
+	int		xrid;
+	u_long		rclk;
+	int		noprobe;
 {
-	int count, delay, limit;
+#if 0
+	static bool_t	already_init;
+	device_t	xdev;
+#endif
+	struct com_s	*com;
+	u_int		divisor;
+	bool_t		failures[10];
+	int		fn;
+	device_t	idev;
+	Port_t		iobase;
+	intrmask_t	irqmap[4];
+	intrmask_t	irqs;
+	u_char		mcr_image;
+	int		result;
+	u_long		xirq;
+	u_int		flags = device_get_flags(dev);
+	int		rid;
+	struct resource *port;
+
+	rid = xrid;
+	port = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid,
+				  0, ~0, IO_COMSIZE, RF_ACTIVE);
+	if (!port)
+		return (ENXIO);
 
-	com->hasfifo = 0;
-	com->fifosize = 0;
+	com = malloc(sizeof(*com), M_DEVBUF, M_NOWAIT | M_ZERO);
+	if (com == NULL)
+		return (ENOMEM);
+	device_set_softc(dev, com);
+	com->bst = rman_get_bustag(port);
+	com->bsh = rman_get_bushandle(port);
+	if (rclk == 0)
+		rclk = DEFAULT_RCLK;
+	com->rclk = rclk;
 
-	/* 1/10th the time to transmit 1 character (estimate). */
-	delay = 16000000 * com->reg_dl / com->rclk;
+	while (sio_inited != 2)
+		if (atomic_cmpset_int(&sio_inited, 0, 1)) {
+			mtx_init(&sio_lock, sio_driver_name, NULL,
+			    (comconsole != -1) ?
+			    MTX_SPIN | MTX_QUIET : MTX_SPIN);
+			atomic_store_rel_int(&sio_inited, 2);
+		}
 
+#if 0
 	/*
-	 * Make sure the transmitter is idle before we play with the
-	 * FIFOs. We don't wait more than roughly three times as long
-	 * as needed to send a single character. Given that we may need
-	 * to wait for both the THR and the TSR to clear, this leaves
-	 * us roughly 1 character time slack.
+	 * XXX this is broken - when we are first called, there are no
+	 * previously configured IO ports.  We could hard code
+	 * 0x3f8, 0x2f8, 0x3e8, 0x2e8 etc but that's probably worse.
+	 * This code has been doing nothing since the conversion since
+	 * "count" is zero the first time around.
 	 */
-	limit = 30;
-	while ((sio_getreg(com, com_lsr) & LSR_TEMT) == 0 && --limit) {
-		if (delay)
-			DELAY(delay);
+	if (!already_init) {
+		/*
+		 * Turn off MCR_IENABLE for all likely serial ports.  An unused
+		 * port with its MCR_IENABLE gate open will inhibit interrupts
+		 * from any used port that shares the interrupt vector.
+		 * XXX the gate enable is elsewhere for some multiports.
+		 */
+		device_t *devs;
+		int count, i, xioport;
+
+		devclass_get_devices(sio_devclass, &devs, &count);
+		for (i = 0; i < count; i++) {
+			xdev = devs[i];
+			if (device_is_enabled(xdev) &&
+			    bus_get_resource(xdev, SYS_RES_IOPORT, 0, &xioport,
+					     NULL) == 0)
+				outb(xioport + com_mcr, 0);
+		}
+		free(devs, M_TEMP);
+		already_init = TRUE;
 	}
-	if (limit == 0) {
-		siodebug(NULL, "transmitter appears stuck");
-		return (EIO);
+#endif
+
+	if (COM_LLCONSOLE(flags)) {
+		printf("sio%d: reserved for low-level i/o\n",
+		       device_get_unit(dev));
+		bus_release_resource(dev, SYS_RES_IOPORT, rid, port);
+		device_set_softc(dev, NULL);
+		free(com, M_DEVBUF);
+		return (ENXIO);
 	}
 
 	/*
-	 * Set loopback mode. This avoids having garbage on the wire and
-	 * also allows us send and receive data. We set DTR and RTS to
-	 * avoid the possibility that automatic flow-control prevents
-	 * any data from being sent.
+	 * If the device is on a multiport card and has an AST/4
+	 * compatible interrupt control register, initialize this
+	 * register and prepare to leave MCR_IENABLE clear in the mcr.
+	 * Otherwise, prepare to set MCR_IENABLE in the mcr.
+	 * Point idev to the device struct giving the correct id_irq.
+	 * This is the struct for the master device if there is one.
 	 */
-	sio_setreg(com, com_mcr, com->reg_mcr | MCR_LOOPBACK|MCR_DTR|MCR_RTS);
-	/* XXX barrier */
+	idev = dev;
+	mcr_image = MCR_IENABLE;
+#ifdef COM_MULTIPORT
+	if (COM_ISMULTIPORT(flags)) {
+		Port_t xiobase;
+		u_long io;
+
+		idev = devclass_get_device(sio_devclass, COM_MPMASTER(flags));
+		if (idev == NULL) {
+			printf("sio%d: master device %d not configured\n",
+			       device_get_unit(dev), COM_MPMASTER(flags));
+			idev = dev;
+		}
+		if (!COM_NOTAST4(flags)) {
+			if (bus_get_resource(idev, SYS_RES_IOPORT, 0, &io,
+					     NULL) == 0) {
+				xiobase = io;
+				if (bus_get_resource(idev, SYS_RES_IRQ, 0,
+				    NULL, NULL) == 0)
+					outb(xiobase + com_scr, 0x80);
+				else
+					outb(xiobase + com_scr, 0);
+			}
+			mcr_image = 0;
+		}
+	}
+#endif /* COM_MULTIPORT */
+	if (bus_get_resource(idev, SYS_RES_IRQ, 0, NULL, NULL) != 0)
+		mcr_image = 0;
+
+	bzero(failures, sizeof failures);
+	iobase = rman_get_start(port);
 
 	/*
-	 * Enable FIFOs. Set DMA mode with the highest trigger level so
-	 * that we can determine the FIFO size. Since this is the first
-	 * time we enable the FIFOs, reset them.
+	 * We don't want to get actual interrupts, just masked ones.
+	 * Interrupts from this line should already be masked in the ICU,
+	 * but mask them in the processor as well in case there are some
+	 * (misconfigured) shared interrupts.
 	 */
-	com->reg_fcr = FCR_ENABLE | FCR_DMA_MODE | FCR_RX_HIGH;
-	sio_setreg(com, com_fcr, com->reg_fcr | FCR_XMT_RST | FCR_RCV_RST);
-	/* XXX barrier */
+	mtx_lock_spin(&sio_lock);
+/* EXTRA DELAY? */
 
-	/* Check if the UART has FIFOs. If not, we're done. */
-	com->hasfifo = (sio_getreg(com, com_iir) & IIR_FIFO_MASK) ? 1 : 0;
-	if (!com->hasfifo) {
-		sio_setreg(com, com_mcr, com->reg_mcr);
-		/* XXX barrier */
-		siodebug(NULL, "no FIFOs... ");
-		return (0);
-	}
+	/*
+	 * For the TI16754 chips, set prescaler to 1 (4 is often the
+	 * default after-reset value) as otherwise it's impossible to
+	 * get highest baudrates.
+	 */
+	if (COM_TI16754(flags)) {
+		u_char cfcr, efr;
 
-	/* We have FIFOs. Flush the transmitter and receiver. */
-	if (sioflush(com)) {
-		sio_setreg(com, com_mcr, com->reg_mcr);
-		/* XXX barrier */
-		goto fallback;
+		cfcr = sio_getreg(com, com_cfcr);
+		sio_setreg(com, com_cfcr, CFCR_EFR_ENABLE);
+		efr = sio_getreg(com, com_efr);
+		/* Unlock extended features to turn off prescaler. */
+		sio_setreg(com, com_efr, efr | EFR_EFE);
+		/* Disable EFR. */
+		sio_setreg(com, com_cfcr, (cfcr != CFCR_EFR_ENABLE) ? cfcr : 0);
+		/* Turn off prescaler. */
+		sio_setreg(com, com_mcr,
+			   sio_getreg(com, com_mcr) & ~MCR_PRESCALE);
+		sio_setreg(com, com_cfcr, CFCR_EFR_ENABLE);
+		sio_setreg(com, com_efr, efr);
+		sio_setreg(com, com_cfcr, cfcr);
 	}
 
-	sio_setreg(com, com_ier, IER_ERXRDY);
-	/* XXX barrier */
-
 	/*
-	 * We should have a sufficiently clean "pipe" to determine the
-	 * size of the FIFOs. We send as much characters as is reasonable
-	 * and wait for the the RX interrupt to be asserted, counting the
-	 * characters as we send them. Based on that count we know the
-	 * FIFO size.
+	 * Initialize the speed and the word size and wait long enough to
+	 * drain the maximum of 16 bytes of junk in device output queues.
+	 * The speed is undefined after a master reset and must be set
+	 * before relying on anything related to output.  There may be
+	 * junk after a (very fast) soft reboot and (apparently) after
+	 * master reset.
+	 * XXX what about the UART bug avoided by waiting in comparam()?
+	 * We don't want to to wait long enough to drain at 2 bps.
 	 */
-	count = 0;
-	while ((sio_getreg(com, com_iir) & IIR_RXRDY) == 0 && count < 1030) {
-		sio_setreg(com, com_data, 0);
-		/* XXX barrier */
-		count++;
-
-		limit = 30;
-		while ((sio_getreg(com, com_lsr) & LSR_TEMT) == 0 && --limit) {
-			if (delay)
-				DELAY(delay);
-		}
-		if (limit == 0) {
-			sio_setreg(com, com_ier, 0);
-			/* XXX barrier */
-			sio_setreg(com, com_mcr, com->reg_mcr);
-			/* XXX barrier */
-			siodebug(NULL, "can't determine FIFO size... ");
-			goto fallback;
-		}
+	if (iobase == siocniobase)
+		DELAY((16 + 1) * 1000000 / (comdefaultrate / 10));
+	else {
+		sio_setreg(com, com_cfcr, CFCR_DLAB | CFCR_8BITS);
+		divisor = siodivisor(rclk, SIO_TEST_SPEED);
+		sio_setreg(com, com_dlbl, divisor & 0xff);
+		sio_setreg(com, com_dlbh, divisor >> 8);
+		sio_setreg(com, com_cfcr, CFCR_8BITS);
+		DELAY((16 + 1) * 1000000 / (SIO_TEST_SPEED / 10));
 	}
 
+	/*
+	 * Enable the interrupt gate and disable device interupts.  This
+	 * should leave the device driving the interrupt line low and
+	 * guarantee an edge trigger if an interrupt can be generated.
+	 */
+/* EXTRA DELAY? */
+	sio_setreg(com, com_mcr, mcr_image);
 	sio_setreg(com, com_ier, 0);
-	/* XXX barrier */
+	DELAY(1000);		/* XXX */
+	irqmap[0] = isa_irq_pending();
 
-	/* Reset FIFOs. */
-	com->reg_fcr = FCR_ENABLE;
-	sio_setreg(com, com_fcr, com->reg_fcr | FCR_XMT_RST | FCR_RCV_RST);
-	/* XXX barrier */
+	/*
+	 * Attempt to set loopback mode so that we can send a null byte
+	 * without annoying any external device.
+	 */
+/* EXTRA DELAY? */
+	sio_setreg(com, com_mcr, mcr_image | MCR_LOOPBACK);
 
-	sio_setreg(com, com_mcr, com->reg_mcr);
-	/* XXX barrier */
+	/*
+	 * Attempt to generate an output interrupt.  On 8250's, setting
+	 * IER_ETXRDY generates an interrupt independent of the current
+	 * setting and independent of whether the THR is empty.  On 16450's,
+	 * setting IER_ETXRDY generates an interrupt independent of the
+	 * current setting.  On 16550A's, setting IER_ETXRDY only
+	 * generates an interrupt when IER_ETXRDY is not already set.
+	 */
+	sio_setreg(com, com_ier, IER_ETXRDY);
 
-	if (count >= 14 && count < 16)
-		com->fifosize = 16;		/* 16550 */
-	else if (count >= 28 && count < 32)
-		com->fifosize = 32;		/* 16650 */
-	else if (count >= 56 && count < 64)
-		com->fifosize = 64;		/* 16750 */
-	else if (count >= 112 && count < 128)
-		com->fifosize = 128;		/* 16950 */
-	else
-		com->fifosize = 1;		/* XXX */
+	/*
+	 * On some 16x50 incompatibles, setting IER_ETXRDY doesn't generate
+	 * an interrupt.  They'd better generate one for actually doing
+	 * output.  Loopback may be broken on the same incompatibles but
+	 * it's unlikely to do more than allow the null byte out.
+	 */
+	sio_setreg(com, com_data, 0);
+	DELAY((1 + 2) * 1000000 / (SIO_TEST_SPEED / 10));
 
-	siodebug(NULL, "count=%d; FIFO=%d... ", count, com->fifosize);
-	return (0);
+	/*
+	 * Turn off loopback mode so that the interrupt gate works again
+	 * (MCR_IENABLE was hidden).  This should leave the device driving
+	 * an interrupt line high.  It doesn't matter if the interrupt
+	 * line oscillates while we are not looking at it, since interrupts
+	 * are disabled.
+	 */
+/* EXTRA DELAY? */
+	sio_setreg(com, com_mcr, mcr_image);
+ 
+	/*
+	 * It seems my Xircom CBEM56G Cardbus modem wants to be reset
+	 * to 8 bits *again*, or else probe test 0 will fail.
+	 * gwk@sgi.com, 4/19/2001
+	 */
+	sio_setreg(com, com_cfcr, CFCR_8BITS);
 
-fallback:
-	siodebug(NULL, "disabling FIFOs... ");
-	com->hasfifo = 0;
-	return (0);
-}
-
-static void
-siodescribe(struct com_s *com)
-{
-	int has_spr;
-	u_char spr;
-
-	if (com->hasfifo) {
-		/*
-		 * NS16550 or higher. The minimum FIFO size is 16 bytes for
-		 * the NS16550. The ST16C650 has 32 bytes FIFOs and the
-		 * NS16750 has 64 bytes FIFOs.
-		 */
-		switch (com->fifosize) {
-		case 16:
-			/*
-			 * XXX Should we try to see if we have a broken
-			 * 16550 or a fixed 16550A?
-			 */
-			device_set_desc(com->dev, "16550 or compatible");
-			break;
-		case 32:
-			/* XXX Should we check features? */
-			device_set_desc(com->dev, "16650 or compatible");
-			break;
-		case 64:
-			/* XXX Should we check features? */
-			device_set_desc(com->dev, "16750 or compatible");
-			break;
-		case 128:
-			/* XXX Should we check features? */
-			device_set_desc(com->dev, "16950 or compatible");
-			break;
-		default:
-			/* XXX Probably not right. */
-			device_set_desc(com->dev,
-			    "Non-standard or broken UART with FIFO");
-			break;
+	/*
+	 * Some pcmcia cards have the "TXRDY bug", so we check everyone
+	 * for IIR_TXRDY implementation ( Palido 321s, DC-1S... )
+	 */
+	if (noprobe) {
+		/* Reading IIR register twice */
+		for (fn = 0; fn < 2; fn ++) {
+			DELAY(10000);
+			failures[6] = sio_getreg(com, com_iir);
+		}
+		/* Check IIR_TXRDY clear ? */
+		result = 0;
+		if (failures[6] & IIR_TXRDY) {
+			/* No, Double check with clearing IER */
+			sio_setreg(com, com_ier, 0);
+			if (sio_getreg(com, com_iir) & IIR_NOPEND) {
+				/* Ok. We discovered TXRDY bug! */
+				SET_FLAG(dev, COM_C_IIR_TXRDYBUG);
+			} else {
+				/* Unknown, Just omit this chip.. XXX */
+				result = ENXIO;
+				sio_setreg(com, com_mcr, 0);
+			}
+		} else {
+			/* OK. this is well-known guys */
+			CLR_FLAG(dev, COM_C_IIR_TXRDYBUG);
+		}
+		sio_setreg(com, com_ier, 0);
+		sio_setreg(com, com_cfcr, CFCR_8BITS);
+		mtx_unlock_spin(&sio_lock);
+		bus_release_resource(dev, SYS_RES_IOPORT, rid, port);
+		if (iobase == siocniobase)
+			result = 0;
+		if (result != 0) {
+			device_set_softc(dev, NULL);
+			free(com, M_DEVBUF);
 		}
-	} else {
-		/*
-		 * NS16450 or lower. Use the Scratch Pad Register (SPR) to
-		 * differentiate the NS16450 from the INS8250.
-		 */
-		spr = sio_getreg(com, com_scr);
-		sio_setreg(com, com_scr, ~spr);
-		/* XXX barrier */
-		has_spr = (sio_getreg(com, com_scr) == ~spr) ? 1 : 0;
-		/* XXX barrier */
-		sio_setreg(com, com_scr, spr);
-		/* XXX barrier */
-		if (!has_spr)
-			device_set_desc(com->dev, "8250 or compatible");
-		else
-			device_set_desc(com->dev, "16450 or compatible");
+		return (result);
 	}
-}
 
-u_int
-siodivisor(u_long rclk, u_long speed)
-{
-	long	actual_speed;
-	u_int	divisor;
-	int	error;
+	/*
+	 * Check that
+	 *	o the CFCR, IER and MCR in UART hold the values written to them
+	 *	  (the values happen to be all distinct - this is good for
+	 *	  avoiding false positive tests from bus echoes).
+	 *	o an output interrupt is generated and its vector is correct.
+	 *	o the interrupt goes away when the IIR in the UART is read.
+	 */
+/* EXTRA DELAY? */
+	failures[0] = sio_getreg(com, com_cfcr) - CFCR_8BITS;
+	failures[1] = sio_getreg(com, com_ier) - IER_ETXRDY;
+	failures[2] = sio_getreg(com, com_mcr) - mcr_image;
+	DELAY(10000);		/* Some internal modems need this time */
+	irqmap[1] = isa_irq_pending();
+	failures[4] = (sio_getreg(com, com_iir) & IIR_IMASK) - IIR_TXRDY;
+	DELAY(1000);		/* XXX */
+	irqmap[2] = isa_irq_pending();
+	failures[6] = (sio_getreg(com, com_iir) & IIR_IMASK) - IIR_NOPEND;
 
-	if (speed == 0)
-		return (0);
-#if UINT_MAX > (ULONG_MAX - 1) / 8
-	if (speed > (ULONG_MAX - 1) / 8)
-		return (0);
-#endif
-	divisor = (rclk / (8UL * speed) + 1) / 2;
-	if (divisor == 0 || divisor >= 65536)
-		return (0);
-	actual_speed = rclk / (16UL * divisor);
-
-	/* 10 times error in percent: */
-	error = ((actual_speed - (long)speed) * 2000 / (long)speed + 1) / 2;
-
-	/* 3.0% maximum error tolerance: */
-	if (error < -30 || error > 30)
-		return (0);
-
-	return (divisor);
-}
-
-/*
- * Do some non-destructive (for this device that is) tests
- * to make sure we have something that looks like an UART.
- */
-int sioprobe1(struct com_s *com)
-{
-	u_char lcr, val;
-
-	lcr = sio_getreg(com, com_lcr);
-	sio_setreg(com, com_lcr, lcr & ~LCR_DLAB);
-
-	/* Check known 0 bits that don't depend on DLAB. */
-	val = sio_getreg(com, com_iir);
-	if (val & 0x30)
-		goto fail;
-	val = sio_getreg(com, com_mcr);
-	if (val & 0xe0)
-		goto fail;
-
-	/* Check known 0 bits that depend on !DLAB. */
-	val = sio_getreg(com, com_ier);
-	if (val & 0xf0)
-		goto fail;
-
-	/* XXX we can do more. */
-
+	/*
+	 * Turn off all device interrupts and check that they go off properly.
+	 * Leave MCR_IENABLE alone.  For ports without a master port, it gates
+	 * the OUT2 output of the UART to
+	 * the ICU input.  Closing the gate would give a floating ICU input
+	 * (unless there is another device driving it) and spurious interrupts.
+	 * (On the system that this was first tested on, the input floats high
+	 * and gives a (masked) interrupt as soon as the gate is closed.)
+	 */
 	sio_setreg(com, com_ier, 0);
-	/* XXX barrier */
-	sio_setreg(com, com_lcr, lcr);
-	/* XXX barrier */
-	return (0);
+	sio_setreg(com, com_cfcr, CFCR_8BITS);	/* dummy to avoid bus echo */
+	failures[7] = sio_getreg(com, com_ier);
+	DELAY(1000);		/* XXX */
+	irqmap[3] = isa_irq_pending();
+	failures[9] = (sio_getreg(com, com_iir) & IIR_IMASK) - IIR_NOPEND;
 
- fail:
-	sio_setreg(com, com_lcr, lcr);
-	/* XXX barrier */
-	return (ENXIO);
-}
+	mtx_unlock_spin(&sio_lock);
 
-/*
- *	Unload the driver and clear the table.
- *	XXX this is mostly wrong.
- *	XXX TODO:
- *	This is usually called when the card is ejected, but
- *	can be caused by a kldunload of a controller driver.
- *	The idea is to reset the driver's view of the device
- *	and ensure that any driver entry points such as
- *	read and write do not hang.
- */
-int
-siodetach(device_t dev)
-{
-	struct com_s *com;
-	int i;
+	irqs = irqmap[1] & ~irqmap[0];
+	if (bus_get_resource(idev, SYS_RES_IRQ, 0, &xirq, NULL) == 0 &&
+	    ((1 << xirq) & irqs) == 0) {
+		printf(
+		"sio%d: configured irq %ld not in bitmap of probed irqs %#x\n",
+		    device_get_unit(dev), xirq, irqs);
+		printf(
+		"sio%d: port may not be enabled\n",
+		    device_get_unit(dev));
+	}
+	if (bootverbose)
+		printf("sio%d: irq maps: %#x %#x %#x %#x\n",
+		    device_get_unit(dev),
+		    irqmap[0], irqmap[1], irqmap[2], irqmap[3]);
 
-	com = (struct com_s *)device_get_softc(dev);
-	com->gone = 1;
-
-	if (com->tp && (com->tp->t_state & TS_ISOPEN)) {
-		device_printf(dev, "still open, forcing close\n");

>>> TRUNCATED FOR MAIL (1000 lines) <<<



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200309070125.h871PSTR095618>