Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 23 Jan 2010 07:54:07 +0000 (UTC)
From:      Joerg Wunsch <joerg@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r202870 - head/sys/dev/ieee488
Message-ID:  <201001230754.o0N7s70b040987@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: joerg
Date: Sat Jan 23 07:54:06 2010
New Revision: 202870
URL: http://svn.freebsd.org/changeset/base/202870

Log:
  Overhaul of the pcii driver:
  
  . Properly allocate all IO space resources.  These cards scatter their
    IO addresses over a range of 0x1600 bytes, and they require an
    additional address for "special interrupt handling".
  
  . Implement the "special interrupt handling" per the GPIB-PCIIA
    Technical Reference Manual; this was apparently not declared for the
    clone card this driver has been originally implemented for, but it
    turned out to be needed for both, an original NI brand PCII/PCIIA
    card as well as the Axiom AX5488 clone.
  
  . Add some diagnostic messages for various resource allocation etc.
    failures during probe.
  
  . Add some comments about the structure of the IO address space that
    is used by these cards.
  
  MFC after:	1 day

Modified:
  head/sys/dev/ieee488/pcii.c
  head/sys/dev/ieee488/upd7210.c
  head/sys/dev/ieee488/upd7210.h

Modified: head/sys/dev/ieee488/pcii.c
==============================================================================
--- head/sys/dev/ieee488/pcii.c	Sat Jan 23 07:52:44 2010	(r202869)
+++ head/sys/dev/ieee488/pcii.c	Sat Jan 23 07:54:06 2010	(r202870)
@@ -1,5 +1,6 @@
 /*-
  * Copyright (c) 2005 Poul-Henning Kamp <phk@FreeBSD.org>
+ * Copyright (c) 2010 Joerg Wunsch <joerg@FreeBSD.org>
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -33,6 +34,8 @@
  *
  *    Tested and known working:
  *	"B&C Microsystems PC488A-0"
+ *	"National Instruments GPIB-PCII/PCIIA" (in PCIIa mode)
+ *	"Axiom AX5488"
  *
  */
 
@@ -56,7 +59,7 @@ __FBSDID("$FreeBSD$");
 
 struct pcii_softc {
 	int foo;
-	struct resource	*res[3];
+	struct resource	*res[11];
 	void *intr_handler;
 	struct upd7210	upd7210;
 };
@@ -79,6 +82,14 @@ static struct resource_spec pcii_res_spe
 	{ SYS_RES_IRQ,		0, RF_ACTIVE | RF_SHAREABLE},
 	{ SYS_RES_DRQ,		0, RF_ACTIVE | RF_SHAREABLE | RF_OPTIONAL},
 	{ SYS_RES_IOPORT,	0, RF_ACTIVE},
+	{ SYS_RES_IOPORT,	1, RF_ACTIVE},
+	{ SYS_RES_IOPORT,	2, RF_ACTIVE},
+	{ SYS_RES_IOPORT,	3, RF_ACTIVE},
+	{ SYS_RES_IOPORT,	4, RF_ACTIVE},
+	{ SYS_RES_IOPORT,	5, RF_ACTIVE},
+	{ SYS_RES_IOPORT,	6, RF_ACTIVE},
+	{ SYS_RES_IOPORT,	7, RF_ACTIVE},
+	{ SYS_RES_IOPORT,	8, RF_ACTIVE | RF_SHAREABLE},
 	{ -1, 0, 0 }
 };
 
@@ -92,7 +103,7 @@ static int
 pcii_probe(device_t dev)
 {
 	int rid, i, j;
-	u_long start, count;
+	u_long start, count, addr;
 	int error = 0;
 	struct pcii_softc *sc;
 
@@ -102,30 +113,89 @@ pcii_probe(device_t dev)
 	rid = 0;
 	if (bus_get_resource(dev, SYS_RES_IOPORT, rid, &start, &count) != 0)
 		return ENXIO;
-	if ((start & 0x3ff) != 0x2e1)
+	/*
+	 * The PCIIA decodes a fixed pattern of 0x2e1 for the lower 10
+	 * address bits A0 ... A9.  Bits A10 through A12 are used by
+	 * the µPD7210 register select lines.  This makes the
+	 * individual 7210 register being 0x400 bytes apart in the ISA
+	 * bus address space.  Address bits A13 and A14 are compared
+	 * to a DIP switch setting on the card, allowing for up to 4
+	 * different cards being installed (at base addresses 0x2e1,
+	 * 0x22e1, 0x42e1, and 0x62e1, respectively).  A15 has been
+	 * used to select an optional on-board time-of-day clock chip
+	 * (MM58167A) on the original PCIIA rather than the µPD7210
+	 * (which is not implemented on later boards).  The
+	 * documentation states the respective addresses for that chip
+	 * should be handled as reserved addresses, which we don't do
+	 * (right now).  Finally, the IO addresses 0x2f0 ... 0x2f7 for
+	 * a "special interrupt handling feature" (re-enable
+	 * interrupts so the IRQ can be shared).
+	 *
+	 * Usually, the user will only set the base address in the
+	 * device hints, so we handle the rest here.
+	 *
+	 * (Source: GPIB-PCIIA Technical Reference Manual, September
+	 * 1989 Edition, National Instruments.)
+	 */
+	if ((start & 0x3ff) != 0x2e1) {
+		printf("pcii_probe: PCIIA base address 0x%lx not "
+		       "0x2e1/0x22e1/0x42e1/0x62e1\n",
+		       start);
 		return (ENXIO);
-	count = 1;
-	if (bus_set_resource(dev, SYS_RES_IOPORT, rid, start, count) != 0)
+	}
+
+	for (rid = 0, addr = start; rid < 8; rid++, addr += 0x400) {
+		if (bus_set_resource(dev, SYS_RES_IOPORT, rid, addr, 1) != 0) {
+			printf("pcii_probe: could not set IO port 0x%lx\n",
+			       addr);
+			return (ENXIO);
+		}
+	}
+	if (bus_get_resource(dev, SYS_RES_IRQ, 0, &start, &count) != 0) {
+		printf("pcii_probe: cannot obtain IRQ level\n");
+		return ENXIO;
+	}
+	if (start > 7) {
+		printf("pcii_probe: IRQ level %lu too high\n", start);
 		return ENXIO;
+	}
+
+	if (bus_set_resource(dev, SYS_RES_IOPORT, 8, 0x2f0 + start, 1) != 0) {
+		printf("pcii_probe: could not set IO port 0x%3lx\n",
+		       0x2f0 + start);
+		return (ENXIO);
+	}
+
 	error = bus_alloc_resources(dev, pcii_res_spec, sc->res);
-	if (error)
+	if (error) {
+		printf("pcii_probe: Could not allocate resources\n");
 		return (error);
+	}
 	error = ENXIO;
+	/*
+	 * Perform some basic tests on the µPD7210 registers.  At
+	 * least *some* register must read different from 0x00 or
+	 * 0xff.
+	 */
 	for (i = 0; i < 8; i++) {
-		j = bus_read_1(sc->res[2], i * 0x400);
+		j = bus_read_1(sc->res[2 + i], 0);
 		if (j != 0x00 && j != 0xff)
 			error = 0;
 	}
+	/* SPSR/SPMR read/write test */
 	if (!error) {
-		bus_write_1(sc->res[2], 3 * 0x400, 0x55);
-		if (bus_read_1(sc->res[2], 3 * 0x400) != 0x55)
+		bus_write_1(sc->res[2 + 3], 0, 0x55);
+		if (bus_read_1(sc->res[2 + 3], 0) != 0x55)
 			error = ENXIO;
 	}
 	if (!error) {
-		bus_write_1(sc->res[2], 3 * 0x400, 0xaa);
-		if (bus_read_1(sc->res[2], 3 * 0x400) != 0xaa)
+		bus_write_1(sc->res[2 + 3], 0, 0xaa);
+		if (bus_read_1(sc->res[2 + 3], 0) != 0xaa)
 			error = ENXIO;
 	}
+	if (error)
+		printf("pcii_probe: probe failure\n");
+
 	bus_release_resources(dev, pcii_res_spec, sc->res);
 	return (error);
 }
@@ -134,6 +204,7 @@ static int
 pcii_attach(device_t dev)
 {
 	struct pcii_softc *sc;
+	u_long		start, count;
 	int		unit;
 	int		rid;
 	int		error = 0;
@@ -144,6 +215,11 @@ pcii_attach(device_t dev)
 
 	device_set_desc(dev, "PCII IEEE-4888 controller");
 
+	if (bus_get_resource(dev, SYS_RES_IRQ, 0, &start, &count) != 0) {
+		printf("pcii_attach: cannot obtain IRQ number\n");
+		return ENXIO;
+	}
+
 	error = bus_alloc_resources(dev, pcii_res_spec, sc->res);
 	if (error)
 		return (error);
@@ -157,9 +233,9 @@ pcii_attach(device_t dev)
 	}
 
 	for (rid = 0; rid < 8; rid++) {
-		sc->upd7210.reg_res[rid] = sc->res[2];
-		sc->upd7210.reg_offset[rid] = 0x400 * rid;
+		sc->upd7210.reg_res[rid] = sc->res[2 + rid];
 	}
+	sc->upd7210.irq_clear_res = sc->res[10];
 
 	if (sc->res[1] == NULL)
 		sc->upd7210.dmachan = -1;

Modified: head/sys/dev/ieee488/upd7210.c
==============================================================================
--- head/sys/dev/ieee488/upd7210.c	Sat Jan 23 07:52:44 2010	(r202869)
+++ head/sys/dev/ieee488/upd7210.c	Sat Jan 23 07:54:06 2010	(r202870)
@@ -1,5 +1,6 @@
 /*-
  * Copyright (c) 2005 Poul-Henning Kamp <phk@FreeBSD.org>
+ * Copyright (c) 2010 Joerg Wunsch <joerg@FreeBSD.org>
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -71,7 +72,7 @@ upd7210_rd(struct upd7210 *u, enum upd72
 {
 	u_int r;
 
-	r = bus_read_1(u->reg_res[reg], u->reg_offset[reg]);
+	r = bus_read_1(u->reg_res[reg], 0);
 	u->rreg[reg] = r;
 	return (r);
 }
@@ -80,7 +81,7 @@ void
 upd7210_wr(struct upd7210 *u, enum upd7210_wreg reg, u_int val)
 {
 
-	bus_write_1(u->reg_res[reg], u->reg_offset[reg], val);
+	bus_write_1(u->reg_res[reg], 0, val);
 	u->wreg[reg] = val;
 	if (reg == AUXMR)
 		u->wreg[8 + (val >> 5)] = val & 0x1f;
@@ -96,19 +97,35 @@ upd7210intr(void *arg)
 	mtx_lock(&u->mutex);
 	isr1 = upd7210_rd(u, ISR1);
 	isr2 = upd7210_rd(u, ISR2);
-	if (u->busy == 0 || u->irq == NULL || !u->irq(u, 1)) {
+	if (isr1 != 0 || isr2 != 0) {
+		if (u->busy == 0 || u->irq == NULL || !u->irq(u, 1)) {
 #if 0
-		printf("upd7210intr [%02x %02x %02x",
-		    upd7210_rd(u, DIR), isr1, isr2);
-		printf(" %02x %02x %02x %02x %02x] ",
-		    upd7210_rd(u, SPSR),
-		    upd7210_rd(u, ADSR),
-		    upd7210_rd(u, CPTR),
-		    upd7210_rd(u, ADR0),
+			printf("upd7210intr [%02x %02x %02x",
+			       upd7210_rd(u, DIR), isr1, isr2);
+			printf(" %02x %02x %02x %02x %02x] ",
+			       upd7210_rd(u, SPSR),
+			       upd7210_rd(u, ADSR),
+			       upd7210_rd(u, CPTR),
+			       upd7210_rd(u, ADR0),
 		    upd7210_rd(u, ADR1));
-		upd7210_print_isr(isr1, isr2);
-		printf("\n");
+			upd7210_print_isr(isr1, isr2);
+			printf("\n");
 #endif
+		}
+		/*
+		 * "special interrupt handling"
+		 *
+		 * In order to implement shared IRQs, the original
+		 * PCIIa uses IO locations 0x2f0 + (IRQ#) as an output
+		 * location.  If an ISR for a particular card has
+		 * detected this card triggered the IRQ, it must reset
+		 * the card's IRQ by writing (anything) to that IO
+		 * location.
+		 *
+		 * Some clones apparently don't implement this
+		 * feature, but National Instrument cards do.
+		 */
+		bus_write_1(u->irq_clear_res, 0, 42);
 	}
 	mtx_unlock(&u->mutex);
 }

Modified: head/sys/dev/ieee488/upd7210.h
==============================================================================
--- head/sys/dev/ieee488/upd7210.h	Sat Jan 23 07:52:44 2010	(r202869)
+++ head/sys/dev/ieee488/upd7210.h	Sat Jan 23 07:54:06 2010	(r202870)
@@ -1,5 +1,6 @@
 /*-
  * Copyright (c) 2005 Poul-Henning Kamp <phk@FreeBSD.org>
+ * Copyright (c) 2010 Joerg Wunsch <joerg@FreeBSD.org>
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -48,7 +49,7 @@ typedef int upd7210_irq_t(struct upd7210
 
 struct upd7210 {
 	struct resource		*reg_res[8];
-	u_int			reg_offset[8];
+	struct resource		*irq_clear_res;
 	int			dmachan;
 	int			unit;
 



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