Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 1 Aug 2000 16:26:01 +0400 (MSD)
From:      vak@cronyx.ru
To:        FreeBSD-gnats-submit@freebsd.org
Subject:   kern/20341: [patch] sio driver, support for PCI multiport cards
Message-ID:  <200008011226.QAA00323@crox.cronyx.ru>

next in thread | raw e-mail | index | archive | help

>Number:         20341
>Category:       kern
>Synopsis:       Support for PCI multiport cards for sio driver
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          change-request
>Submitter-Id:   current-users
>Arrival-Date:   Tue Aug 01 05:40:01 PDT 2000
>Closed-Date:
>Last-Modified:
>Originator:     Serge Vakulenko
>Release:        FreeBSD 4.0-RELEASE i386
>Organization:
Cronyx Engineering Ltd.
>Environment:

	FreeBSD 4.0, Cronyx-Omega-PCI serial multiport adapters.

>Description:

	To handle non-intelligent multiport async adapters,
	the sio driver lacks the PCI detection and attachment routines.
	Some rearrangment of the sio.c is also required.

	The patch consists of four parts:
	1) sys/isa/siovar.h (new file)
	2) sys/isa/sio.c (patch)
	3) sys/pci/sio_pci.c (new file)
	4) sys/conf/files.i386 (patch)

>How-To-Repeat:
>Fix:

--- siovar40.h	Thu Jul 27 11:46:05 2000
+++ isa/siovar.h	Fri Jul 28 14:01:20 2000
@@ -0,0 +1,146 @@
+/*-
+ * Copyright (c) 1991 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: src/sys/isa/sio.c,v 1.291 2000/03/11 20:22:09 imp Exp $
+ *	from: @(#)com.c	7.5 (Berkeley) 5/16/91
+ *	from: i386/isa sio.c,v 1.234
+ */
+#define	SIO_MAXUNITS		64	/* max sio ports */
+#define	CE_NTYPES		3
+
+/* 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 */
+
+	Port_t	data_port;	/* i/o ports */
+#ifdef COM_ESP
+	Port_t	esp_port;
+#endif
+	Port_t	int_id_port;
+	Port_t	iobase;
+	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;
+
+	u_long	bytes_in;	/* statistics */
+	u_long	bytes_out;
+	u_int	delta_error_counts[CE_NTYPES];
+	u_long	error_counts[CE_NTYPES];
+
+	struct resource *irqres;
+	struct resource *ioportres;
+	void *cookie;
+
+	/*
+	 * Data area for output buffers.  Someday we should build the output
+	 * buffer queue without copying data.
+	 */
+	u_char	obuf1[256];
+	u_char	obuf2[256];
+};
+
+int	sio_attach_unit	(struct com_s *com, int unit, Port_t iobase, 
+			 u_int flags, bool_t no_irq);
+void	siointr1 (struct com_s *com);

1) Move the struct com_s definition to separate file siovar.h.
2) Split the sioattach() routine. Leave the isa-dependent
   part in sioattach(), and build the (public) bus-independent 
   attachment function sio_attach_unit().
3) Make siointr1 public.

--- sio40.c	Wed Jul 26 17:32:07 2000
+++ isa/sio.c	Fri Jul 28 14:01:54 2000
@@ -82,6 +82,7 @@
 #include <machine/resource.h>
 
 #include <isa/sioreg.h>
+#include <isa/siovar.h>
 
 #ifdef COM_ESP
 #include <isa/ic/esp.h>
@@ -167,113 +168,8 @@
 	"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 */
-
-	Port_t	data_port;	/* i/o ports */
-#ifdef COM_ESP
-	Port_t	esp_port;
-#endif
-	Port_t	int_id_port;
-	Port_t	iobase;
-	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;
-
-	u_long	bytes_in;	/* statistics */
-	u_long	bytes_out;
-	u_int	delta_error_counts[CE_NTYPES];
-	u_long	error_counts[CE_NTYPES];
-
-	struct resource *irqres;
-	struct resource *ioportres;
-	void *cookie;
-
-	/*
-	 * 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	__P((struct com_s *com, Port_t esp_port));
 #endif
@@ -284,7 +180,6 @@
 static	timeout_t siodtrwakeup;
 static	void	comhardclose	__P((struct com_s *com));
 static	void	sioinput	__P((struct com_s *com));
-static	void	siointr1	__P((struct com_s *com));
 static	void	siointr		__P((void *arg));
 static	int	commctl		__P((struct com_s *com, int bits, int how));
 static	int	comparam	__P((struct tty *tp, struct termios *t));
@@ -309,8 +204,8 @@
 
 /* table and macro for fast conversion from a unit number to its com struct */
 static	devclass_t	sio_devclass;
-#define	com_addr(unit)	((struct com_s *) \
-			 devclass_get_softc(sio_devclass, unit))
+static	struct com_s	*p_com_addr[SIO_MAXUNITS];
+#define	com_addr(unit)	(p_com_addr[unit])
 
 static device_method_t sio_isa_methods[] = {
 	/* Device interface */
@@ -969,32 +864,19 @@
 	return (sioattach(dev));
 }
 
-static int
-sioattach(dev)
-	device_t	dev;
-{
+int
+sio_attach_unit(com, unit, iobase, flags, no_irq)
 	struct com_s	*com;
+	int		unit;
+	Port_t		iobase;
+	u_int		flags;
+	bool_t		no_irq;
+{
 #ifdef COM_ESP
 	Port_t		*espp;
 #endif
-	Port_t		iobase;
-	int		unit;
-	u_int		flags;
-	int		rid;
-	struct resource *port;
-	int		ret;
-
-	rid = 0;
-	port = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid,
-				  0, ~0, IO_COMSIZE, RF_ACTIVE);
-	if (!port)
-		return (ENXIO);
-
-	iobase = rman_get_start(port);
-	unit = device_get_unit(dev);
-	com = device_get_softc(dev);
-	flags = device_get_flags(dev);
-
+	if (unit >= SIO_MAXUNITS)
+		return ENXIO;
 	if (unit >= sio_numunits)
 		sio_numunits = unit + 1;
 	/*
@@ -1011,11 +893,10 @@
 	 */
 	bzero(com, sizeof *com);
 	com->unit = unit;
-	com->ioportres = port;
 	com->cfcr_image = CFCR_8BITS;
 	com->dtr_wait = 3 * hz;
 	com->loses_outints = COM_LOSESOUTINTS(flags) != 0;
-	com->no_irq = bus_get_resource(dev, SYS_RES_IRQ, 0, NULL, NULL) != 0;
+	com->no_irq = no_irq;
 	com->tx_fifo_size = 1;
 	com->obufs[0].l_head = com->obuf1;
 	com->obufs[1].l_head = com->obuf2;
@@ -1052,12 +933,6 @@
 		com->it_in.c_ispeed = com->it_in.c_ospeed = TTYDEF_SPEED;
 	if (siosetwater(com, com->it_in.c_ispeed) != 0) {
 		enable_intr();
-		/*
-		 * Leave i/o resources allocated if this is a `cn'-level
-		 * console, so that other devices can't snarf them.
-		 */
-		if (iobase != siocniobase)
-			bus_release_resource(dev, SYS_RES_IOPORT, rid, port);
 		return (ENOMEM);
 	}
 	enable_intr();
@@ -1164,17 +1039,11 @@
 
 #ifdef COM_MULTIPORT
 	if (COM_ISMULTIPORT(flags)) {
-		device_t masterdev;
-
 		com->multiport = TRUE;
 		printf(" (multiport");
 		if (unit == COM_MPMASTER(flags))
 			printf(" master");
 		printf(")");
-		masterdev = devclass_get_device(sio_devclass,
-		    COM_MPMASTER(flags));
-		com->no_irq = (masterdev == NULL || bus_get_resource(masterdev,
-		    SYS_RES_IRQ, 0, NULL, NULL) != 0);
 	 }
 #endif /* COM_MULTIPORT */
 	if (unit == comconsole)
@@ -1183,6 +1052,8 @@
 		printf(" with a bogus IIR_TXRDY register");
 	printf("\n");
 
+	com_addr(unit) = com;
+
 	if (!sio_registered) {
 		register_swi(SWI_TTY, siopoll);
 		sio_registered = TRUE;
@@ -1203,6 +1074,50 @@
 	com->pps.ppscap = PPS_CAPTUREASSERT | PPS_CAPTURECLEAR;
 	pps_init(&com->pps);
 
+	return (0);
+}
+
+static int
+sioattach(dev)
+	device_t	dev;
+{
+	int		rid, ret, no_irq;
+	struct resource *port;
+	struct com_s	*com;
+	Port_t		iobase;
+	u_int		flags;
+
+	rid = 0;
+	port = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid,
+				  0, ~0, IO_COMSIZE, RF_ACTIVE);
+	if (!port)
+		return (ENXIO);
+
+	iobase = rman_get_start(port);
+	com = device_get_softc(dev);
+	flags = device_get_flags(dev);
+
+#ifdef COM_MULTIPORT
+	if (COM_ISMULTIPORT(flags)) {
+		device_t masterdev;
+
+		masterdev = devclass_get_device(sio_devclass,
+		    COM_MPMASTER(flags));
+		no_irq = (masterdev == NULL || bus_get_resource(masterdev,
+		    SYS_RES_IRQ, 0, NULL, NULL) != 0);
+	 } else
+#endif /* COM_MULTIPORT */
+	no_irq = bus_get_resource(dev, SYS_RES_IRQ, 0, NULL, NULL) != 0;
+
+	ret = sio_attach_unit(com, device_get_unit(dev), iobase, flags, no_irq);
+	if (ret != 0) {
+		/* Leave i/o resources allocated if this is a `cn'-level
+		 * console, so that other devices can't snarf them. */
+		if (iobase != siocniobase)
+			bus_release_resource(dev, SYS_RES_IOPORT, rid, port);
+		return ret;
+	}
+
 	rid = 0;
 	com->irqres = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 0ul, ~0ul, 1,
 	    RF_ACTIVE);
@@ -1220,8 +1135,8 @@
 		if (ret)
 			device_printf(dev, "could not activate interrupt\n");
 	}
-
-	return (0);
+	com->ioportres = port;
+	return 0;
 }
 
 static int
@@ -1713,7 +1628,7 @@
 #endif /* COM_MULTIPORT */
 }
 
-static void
+void
 siointr1(com)
 	struct com_s	*com;
 {
--- /dev/null	Tue Aug  1 10:55:27 2000
+++ pci/sio_pci.c	Tue Aug  1 11:38:12 2000
@@ -0,0 +1,277 @@
+/*
+ * Serial driver for non-intelligent PCI multiport adapters.
+ * Implements the probe, attach and interrupt dispatcher,
+ * and uses sio.c for the most part of work.
+ * The PCI ports get unit numbers _after_ the ISA sio ports.
+ * Option COM_MULTIPORT is not necessary.
+ *
+ * Copyright (C) 2000 Cronyx Engineering Ltd.
+ * Author: Serge Vakulenko <vak@cronyx.ru>
+ *
+ * Supports:
+ *	Cronyx Omega-PCI adapter, by Serge Vakulenko <vak@cronyx.ru>
+ *
+ * This software is distributed with NO WARRANTIES, not even the implied
+ * warranties for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Authors grant any other persons or organisations permission to use
+ * or modify this software as long as this message is kept with the software,
+ * all derivative works or modified versions.
+ */
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/timepps.h>
+#include <sys/tty.h>
+#include <vm/vm.h>
+#include <vm/pmap.h>
+#include <machine/bus.h>
+#ifndef SMP
+#include <machine/lock.h>
+#endif
+#include <machine/resource.h>
+#include <sys/bus.h>
+#include <sys/rman.h>
+#include <pci/pcivar.h>
+#if __FreeBSD_version >= 400000
+#include <isa/siovar.h>
+#include <isa/sioreg.h>
+#else
+#include <sys/malloc.h>
+#include <sys/interrupt.h>
+#include <i386/isa/siovar.h>
+#include <i386/isa/sioreg.h>
+#endif
+#include <isa/ic/ns16550.h>
+
+#include "sio.h"
+
+#define MAXCHAN		8
+
+#ifndef __i386__
+#define disable_intr()
+#define enable_intr()
+#endif
+
+#ifdef SMP
+#define disable_intr()	COM_DISABLE_INTR()
+#define enable_intr()	COM_ENABLE_INTR()
+#endif /* SMP */
+
+typedef struct _sio_pci_t {
+	int		nchan;
+	int		fifo_size;
+	int		base_reg;
+	int		hw_rts_cts;
+	Port_t		iobase;
+	Port_t		iostep;
+	struct resource	*res;
+	struct resource	*irq;
+	void		*intrhand;
+	struct com_s	com [MAXCHAN];
+} sio_pci_t;
+
+static void sio_pci_intr	__P((void *arg));
+
+static int sio_pci_numunits = NSIO;
+
+#if __FreeBSD_version >= 400000
+/*
+ * FreeBSD version 4.x
+ */
+static int sio_pci_probe	__P((device_t));
+static int sio_pci_attach	__P((device_t));
+
+static devclass_t siopci_devclass;
+
+static device_method_t sio_pci_methods[] = {
+	/* Device interface */
+	DEVMETHOD(device_probe,		sio_pci_probe),
+	DEVMETHOD(device_attach,	sio_pci_attach),
+	{ 0, 0 }
+};
+
+static driver_t sio_pci_driver = {
+	"siopci",
+	sio_pci_methods,
+	sizeof(sio_pci_t)
+};
+DRIVER_MODULE(sio_pci, pci, sio_pci_driver, siopci_devclass, 0, 0);
+
+#else
+/*
+ * FreeBSD version 3.x
+ */
+static const char *sio_pci_probe	__P((pcici_t, pcidi_t));
+static void sio_pci_attach		__P((pcici_t, int));
+
+static u_long sio_pci_count;
+
+static struct pci_device sio_pci_device = {
+        "siopci",
+        sio_pci_probe,
+        sio_pci_attach,
+        &sio_pci_count,
+        NULL
+};
+DATA_SET(pcidevice_set, sio_pci_device);
+
+#endif /* __FreeBSD_version >= 400000 */
+
+#if __FreeBSD_version >= 400000
+static int
+sio_pci_probe(dev)
+	device_t	dev;
+{
+	u_long device_id = pci_get_vendor(dev) | pci_get_device(dev) << 16;
+#else
+static const char *
+sio_pci_probe(config_id, device_id)
+	pcici_t config_id;
+	pcidi_t device_id;
+{
+#endif
+	const char *desc = 0;
+
+	if (device_id == 0xc00110b5)
+		desc = "Cronyx-Omega-PCI Serial Adapter";
+#ifdef notyet
+	/* Add your device here. */
+	else if (device_id == 0xXXXXXXXX)
+		desc = "XXX";
+#endif
+
+#if __FreeBSD_version >= 400000
+	if (! desc)
+		return ENXIO;
+	device_set_desc(dev, desc);
+	return 0;
+#else
+	return desc;
+#endif
+}
+
+#if __FreeBSD_version >= 400000
+static int
+sio_pci_attach(dev)
+	device_t	dev;
+{
+	u_long		device_id = pci_get_vendor(dev) |
+				    pci_get_device(dev) << 16;
+	sio_pci_t	*d = device_get_softc(dev);
+	int		rid;
+#define PCI_READ_CONFIG(reg) pci_read_config(dev, reg, 4)
+#else
+static void
+sio_pci_attach(config_id, unit)
+	pcici_t config_id;
+	int unit;
+{
+	u_long device_id = config_id->vendor | config_id->device << 16;
+	sio_pci_t	*d = malloc(sizeof *d, M_DEVBUF, M_WAITOK);
+#define PCI_READ_CONFIG(reg) pci_conf_read(config_id, reg)
+#endif
+	struct com_s	*com;
+	int		s, err = 0;
+
+	bzero((char*)d, sizeof(*d));
+	s = splimp();
+
+	/* Default values. */
+	d->nchan = 8;			/* channels per adapter */
+	d->iostep = 8;			/* addresses per channel */
+	d->base_reg = 0x18;		/* pci register: base addr2 */
+
+	/* Device dependent values. */
+	if (device_id == 0xc00110b5) {
+		d->fifo_size = 64;	/* fifo size in bytes */
+		d->hw_rts_cts = 1;	/* hardware rts/cts support */
+	}
+#ifdef notyet
+	else if (device_id == 0xXXXXXXXX) {
+		/* Add your device here. */
+	}
+#endif
+
+#if __FreeBSD_version >= 400000
+	/* Allocate i/o region. */
+	rid = d->base_reg;
+	d->res = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, 0, ~0, 1,
+		RF_ACTIVE);
+	if (! d->res) {
+		printf("sio%d: couldn't map ports/memory\n", sio_pci_numunits);
+		err = ENXIO;
+		goto fail;
+	}
+
+	/* Allocate interrupt. */
+	rid = 0;
+	d->irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 0, ~0, 1,
+		RF_SHAREABLE | RF_ACTIVE);
+	if (! d->irq) {
+		printf("sio%d: couldn't map interrupt\n", sio_pci_numunits);
+		err = ENXIO;
+		goto fail;
+	}
+
+	/* Register the interrupt handler. */
+	err = bus_setup_intr(dev, d->irq, INTR_TYPE_TTY | INTR_TYPE_FAST,
+		sio_pci_intr, d, &d->intrhand);
+#else
+	err = ! pci_map_int_right(config_id, sio_pci_intr, d, &tty_imask,
+		INTR_FAST);
+#endif
+	if (err) {
+		printf("sio%d: couldn't set up irq\n", sio_pci_numunits);
+#if __FreeBSD_version >= 400000
+fail:		if (d->res)
+			bus_release_resource(dev, SYS_RES_IOPORT,
+				d->base_reg, d->res);
+		if (d->irq)
+			bus_release_resource(dev, SYS_RES_IRQ, 0, d->irq);
+#endif
+		goto done;
+	}
+
+	/* Attach sio ports. */
+	d->iobase = PCI_READ_CONFIG (d->base_reg) & ~3;
+	for (com=d->com; com<d->com+d->nchan; ++com) {
+		com->iobase = d->iobase + (com - d->com) * d->iostep;
+
+		/* Interrupt enable, do it _before_ sio_attach_unit. */
+		outb(com->iobase + com_mcr, MCR_IENABLE);
+
+		if (sio_attach_unit(com, sio_pci_numunits++, com->iobase,
+		    d->fifo_size << 24, 0) != 0)
+			printf("sio%d: cannot attach\n", sio_pci_numunits);
+
+		/* Must do this _after_ sio_attach_unit. */
+		com->st16650a = d->hw_rts_cts;
+	}
+done:
+	splx (s);
+#if __FreeBSD_version >= 400000
+	return err;
+#endif
+}
+
+static void
+sio_pci_intr(arg)
+	void		*arg;
+{
+	sio_pci_t	*d = arg;
+	struct com_s	*com;
+	bool_t		possibly_more_intrs;
+
+	disable_intr();
+	do {
+		possibly_more_intrs = FALSE;
+		for (com=d->com; com<d->com+d->nchan; ++com) {
+			if ((inb(com->int_id_port) & IIR_IMASK) != IIR_NOPEND) {
+				siointr1(com);
+				possibly_more_intrs = TRUE;
+			}
+		}
+	} while (possibly_more_intrs);
+	enable_intr();
+}
--- files40.i386	Fri Jul 28 17:11:26 2000
+++ conf/files.i386	Fri Jul 28 17:12:17 2000
@@ -389,6 +389,7 @@
 isa/ppc.c			optional	ppc
 isa/psm.c			optional	psm
 isa/sio.c			optional	sio
+pci/sio_pci.c			optional	sio pci
 isa/syscons_isa.c		optional	sc
 isa/vga_isa.c			optional	vga
 kern/subr_diskmbr.c		standard

>Release-Note:
>Audit-Trail:
>Unformatted:


To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-bugs" in the body of the message




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