Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 21 May 2002 13:27:57 +0200 (CEST)
From:      Thomas Brupbacher <thomas.brupbacher@cerberus.ch>
To:        FreeBSD-gnats-submit@FreeBSD.org
Cc:        John Hay <jhay@icomtek.csir.co.za>, Nicolas Souchu <nsouch@FreeBSD.org>
Subject:   kern/38372: patch for puc(4) to support parallel ports
Message-ID:  <20020521112757.4DD61A80D@a0028.cerberus.ch>

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

>Number:         38372
>Category:       kern
>Synopsis:       patch for puc(4) to support parallel ports
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          change-request
>Submitter-Id:   current-users
>Arrival-Date:   Tue May 21 04:50:02 PDT 2002
>Closed-Date:
>Last-Modified:
>Originator:     Thomas Brupbacher
>Release:        FreeBSD 4.6-RC i386
>Organization:
Siemens Building Technologies
>Environment:
System: FreeBSD a0028.cerberus.ch 4.6-RC FreeBSD 4.6-RC #31: Tue May 21 12:58:40 CEST 2002 brp@a0028.cerberus.ch:/usr/src/sys/compile/a0028 i386


	
>Description:
	The puc(4) driver supports only serial ports so far,
	the attached patch adds support for parallel ports. The patch
	below is good enough to print the apsfilter test.ps on my old
	LaserJet via the Oxford OX12PCI840 based card.

	The Oxford puc cards use a second IOPORT for the ECP area.  This
	gives rise to two questions:

	a) the code in puc.c should probably deal with that, maybe one could
	   provide a "generic" puc_attach that deals with most cards (the code
	   that is present now), and additionally add an entry in pucdata.c
	   that contains a pointer to a card specific puc_attach. This would
	   move us away from NetBSD though.

	   I could see something like (not certain about the syntax...)

	struct puc_device_description {
        	const char      *name;
        	uint32_t        rval[4];
        	uint32_t        rmask[4];
        	(int) __P(device_t))    *attach;
        	struct {
                	int     type;
                	int     bar;
                	int     offset;
                	u_int   serialfreq;
        	} ports[PUC_MAX_PORTS];
	};

	b) The code in ppc.c assumes that ECP can be accessed by just adding
	   0x400 to the base IOPORT.  I have no idea what the best way would
	   be to solve that (to enable the full feature set of the puc card).

>How-To-Repeat:
	
>Fix:



--- /usr/src/sys/dev/puc/puc.c	Mon Apr 29 18:59:48 2002
+++ /usr/home/brp/puc/200205211000/puc.c	Tue May 21 12:48:26 2002
@@ -122,7 +122,11 @@
 
 struct puc_device {
 	struct resource_list resources;
+	u_int           type;	/* the type of the port: PUC_TYPE_NONE, _COM,
+				 * _LPT */
 	u_int serialfreq;
+	u_int           ppc_capabilities;	/* flags for the LPT */
+	u_int           baserid;/* address of base register for LPT */
 };
 
 static int puc_pci_probe(device_t dev);
@@ -151,6 +155,32 @@
 static void puc_print_resource_list(struct resource_list *);
 #endif
 
+
+/* allocate the a second IOPORT for LPT devices that need it */
+static void
+puc_alloc_ECP(device_t dev, struct puc_softc * sc, int xrid)
+{
+	struct resource *res;
+	int             rid, bidx;
+
+	rid = xrid;
+	bidx = PUC_PORT_BAR_INDEX(rid);
+	if (sc->sc_bar_mappings[bidx].res != NULL)
+		return;
+	res = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid,
+				 0ul, ~0ul, 1, RF_ACTIVE);
+	if (res == NULL) {
+		printf("could not get resource\n");
+		return;
+	}
+	sc->sc_bar_mappings[bidx].res = res;
+#ifdef PUC_DEBUG
+	printf("port bst %x, start %x, end %x\n",
+	       (u_int) rman_get_bustag(res), (u_int) rman_get_start(res),
+	       (u_int) rman_get_end(res));
+#endif
+}
+
 static int
 puc_pci_probe(device_t dev)
 {
@@ -236,8 +267,15 @@
 		sc->sc_bar_mappings[bidx].res = res;
 #ifdef PUC_DEBUG
 		printf("port bst %x, start %x, end %x\n",
-		    (u_int)rman_get_bustag(res), (u_int)rman_get_start(res),
-		    (u_int)rman_get_end(res));
+		       (u_int) rman_get_bustag(res), (u_int) rman_get_start(res),
+		       (u_int) rman_get_end(res));
+#endif
+#if 0
+		/* for an LPT we allocate a second region */
+		if ((sc->sc_desc->ports[i].type == PUC_PORT_TYPE_LPT)
+		    && (sc->sc_desc->ports[i].serialfreq != 0x00)) {
+			puc_alloc_ECP(dev, sc, 0x14);
+		}
 #endif
 	}
 
@@ -251,7 +289,8 @@
 
 		switch (sc->sc_desc->ports[i].type) {
 		case PUC_PORT_TYPE_COM:
-			typestr = "sio";
+			break;
+		case PUC_PORT_TYPE_LPT:
 			break;
 		default:
 			continue;
@@ -286,7 +326,40 @@
 				free(pdev, M_DEVBUF);
 				return (ENOMEM);
 			}
+			rle->res->r_start = rman_get_start(res) +
+				sc->sc_desc->ports[i].offset;
+			rle->res->r_end = rle->res->r_start + 8 - 1;
+			rle->res->r_bustag = rman_get_bustag(res);
+			bus_space_subregion(rle->res->r_bustag,
+					    rman_get_bushandle(res),
+					    sc->sc_desc->ports[i].offset, 8,
+					    &rle->res->r_bushandle);
+		}
+#if 0
+		/*
+		 * if it is an LPT and we have a second IOPORT for ECP
+		 * allocated, then also copy it to the list
+		 */
+		if ((sc->sc_desc->ports[i].type == PUC_PORT_TYPE_LPT)
+		    && (sc->sc_desc->ports[i].type != 0x00)) {
+
+			/* Now fake an IOPORT resource */
+			res = sc->sc_bar_mappings[bidx].res;
+			resource_list_add(&pdev->resources, SYS_RES_IOPORT, 1,
+			 rman_get_start(res) + sc->sc_desc->ports[i].offset,
+					  rman_get_end(res) + sc->sc_desc->ports[i].offset + 8 - 1,
+					  8);
+			rle = resource_list_find(&pdev->resources, SYS_RES_IOPORT, 1);
 
+			if (sc->barmuxed == 0) {
+				rle->res = sc->sc_bar_mappings[bidx].res;
+			} else {
+				rle->res = malloc(sizeof(struct resource), M_DEVBUF,
+						  M_WAITOK | M_ZERO);
+				if (rle->res == NULL) {
+					free(pdev, M_DEVBUF);
+					return (ENOMEM);
+				}
 			rle->res->r_start = rman_get_start(res) +
 			    sc->sc_desc->ports[i].offset;
 			rle->res->r_end = rle->res->r_start + 8 - 1;
@@ -296,9 +369,21 @@
 			    sc->sc_desc->ports[i].offset, 8,
 			    &rle->res->r_bushandle);
 		}
+		}
+#endif
+		pdev->type = sc->sc_desc->ports[i].type;
 
+		switch (pdev->type) {
+		case PUC_PORT_TYPE_COM:
+			typestr = "sio";
 		pdev->serialfreq = sc->sc_desc->ports[i].serialfreq;
-
+			break;
+		case PUC_PORT_TYPE_LPT:
+			typestr = "ppc";
+			pdev->ppc_capabilities = sc->sc_desc->ports[i].serialfreq;
+			pdev->baserid = sc->sc_desc->ports[i].bar;
+			break;
+		}
 		childunit = puc_find_free_unit(typestr);
 		sc->sc_ports[i].dev = device_add_child(dev, typestr, childunit);
 		if (sc->sc_ports[i].dev == NULL) {
@@ -320,7 +405,7 @@
 		    sc->sc_desc->ports[i].type,
 		    sc->sc_desc->ports[i].bar,
 		    sc->sc_desc->ports[i].offset);
-		print_resource_list(&pdev->resources);
+		puc_print_resource_list(&pdev->resources);
 #endif
 		if (device_probe_and_attach(sc->sc_ports[i].dev) != 0) {
 			if (sc->barmuxed) {
@@ -343,8 +428,8 @@
  * This is just an brute force interrupt handler. It just calls all the
  * registered handlers sequencially.
  *
- * Later on we should maybe have a different handler for boards that can
- * tell us which device generated the interrupt.
+ * Later on we should maybe have a different handler for boards that can tell us
+ * which device generated the interrupt.
  */
 static void
 puc_intr(void *arg)
@@ -515,7 +598,8 @@
 #undef rdspio
 #undef wrspio
 
-static int puc_find_free_unit(char *name)
+static int
+puc_find_free_unit(char *name)
 {
 	devclass_t dc;
 	int start;
@@ -543,10 +627,10 @@
 {
 	struct resource_list_entry *rle;
 
-	printf("print_resource_list: rl %p\n", rl);
+	printf("puc_print_resource_list: rl %p\n", rl);
 	SLIST_FOREACH(rle, rl, link)
 		printf("type %x, rid %x\n", rle->type, rle->rid);
-	printf("print_resource_list: end.\n");
+	printf("puc_print_resource_list: end.\n");
 }
 #endif
 
@@ -676,6 +760,18 @@
 	case PUC_IVAR_FREQ:
 		*result = pdev->serialfreq;
 		break;
+	case PUC_IVAR_TYPE:
+		*result = pdev->type;
+		break;
+	case PUC_IVAR_BASERID:
+		*result = pdev->baserid;
+		break;
+		/*
+		 * case PUC_IVAR_EXTREG: result = pdev->extreg; break;
+		 */
+	case PUC_IVAR_PPCCAP:
+		*result = pdev->ppc_capabilities;
+		break;
 	default:
 		return (ENOENT);
 	}
--- /usr/src/sys/dev/puc/pucdata.c	Mon Apr 29 19:00:33 2002
+++ /usr/home/brp/puc/200205211000/pucdata.c	Tue May 21 10:11:16 2002
@@ -39,11 +39,15 @@
  */
 
 #include <sys/param.h>
+#include <sys/bus.h>
+#include <machine/bus.h>
 
 #include <pci/pcireg.h>
 #include <pci/pcivar.h>
 #include <isa/sioreg.h>
+#include <isa/ppcreg.h>
 #include <dev/puc/pucvar.h>
+#include <dev/ppbus/ppbconf.h>
 
 #define COM_FREQ	DEFAULT_RCLK
 
@@ -686,6 +690,15 @@
 		{ PUC_PORT_TYPE_LPT, 0x10, 0x00, 0x00 },
 	    },
 	},
+
+	/* Oxford Semiconductor OX12PCI840 PCI Parallel port */
+        {   "Qxford Semiconductor OX12PCI840 Parallel port",
+            {   0x1415, 0x8403, 0,      0       },
+            {   0xffff, 0xffff, 0,      0       },
+            {
+                { PUC_PORT_TYPE_LPT, 0x10, 0x00, 0x00 },
+            },
+        },
 
 	/* NetMos 2S1P PCI 16C650 : 2S, 1P */
 	{   "NetMos NM9835 Dual UART and 1284 Printer port",
--- /usr/src/sys/dev/puc/pucvar.h	Thu Mar  7 18:48:57 2002
+++ /usr/home/brp/puc/200205211000/pucvar.h	Tue May 21 10:11:27 2002
@@ -74,7 +74,7 @@
 		int	type;
 		int	bar;
 		int	offset;
-		u_int	serialfreq;
+		u_int	serialfreq; /* for LPT devices: capabilities of lpt */
 	} ports[PUC_MAX_PORTS];
 };
 
@@ -94,7 +94,11 @@
 #define PUC_MAX_BAR		6
 
 enum puc_device_ivars {
-	PUC_IVAR_FREQ
+  PUC_IVAR_FREQ,
+  PUC_IVAR_TYPE,
+  PUC_IVAR_BASERID,
+  PUC_IVAR_EXTREG,
+  PUC_IVAR_PPCCAP
 };
 
 extern const struct puc_device_description puc_devices[];
--- /usr/src/sys/isa/ppc.c	Tue Oct  2 07:21:45 2001
+++ /usr/home/brp/puc/200205211000/ppc.c	Tue May 21 11:29:16 2002
@@ -2162,3 +2162,144 @@
 }
 
 DRIVER_MODULE(ppc, isa, ppc_driver, ppc_devclass, 0, 0);
+
+#ifdef __i386__
+#include "puc.h"
+#endif
+
+#if NPUC <= 0
+#error NPUC not defined
+#endif
+
+#if NPUC > 0
+#include <dev/puc/pucvar.h>
+
+static int ppc_puc_probe(device_t dev);
+static int ppc_puc_attach(device_t dev);
+
+
+static device_method_t ppc_puc_methods[] = {
+	/* device interface */
+	DEVMETHOD(device_probe,         ppc_puc_probe),
+	DEVMETHOD(device_attach,        ppc_puc_attach),
+
+	/* bus interface */
+	DEVMETHOD(bus_read_ivar,	ppc_read_ivar),
+	DEVMETHOD(bus_setup_intr,	ppc_setup_intr),
+	DEVMETHOD(bus_teardown_intr,	ppc_teardown_intr),
+
+	/* ppbus interface */
+	DEVMETHOD(ppbus_io,		ppc_io),
+	DEVMETHOD(ppbus_exec_microseq,	ppc_exec_microseq),
+	DEVMETHOD(ppbus_reset_epp,	ppc_reset_epp),
+	DEVMETHOD(ppbus_setmode,	ppc_setmode),
+	DEVMETHOD(ppbus_ecp_sync,	ppc_ecp_sync),
+	DEVMETHOD(ppbus_read,		ppc_read),
+	DEVMETHOD(ppbus_write,		ppc_write),
+
+        { 0, 0 }
+  };
+
+static driver_t ppc_puc_driver = {
+	"ppc",
+	ppc_puc_methods,
+	sizeof(struct ppc_data),
+};
+
+static int ppc_puc_probe(device_t dev)
+{
+  u_int type;
+
+  if (BUS_READ_IVAR(device_get_parent(dev), dev, PUC_IVAR_TYPE,
+		    &type) != 0)
+    type = PUC_PORT_TYPE_NONE;
+  if (type != PUC_PORT_TYPE_LPT)
+    return 1;
+
+  return (0);
+}
+
+static int ppc_puc_attach(device_t dev)
+{
+	struct ppc_data *ppc;
+
+	device_t ppbus;
+
+	/*
+	 * Allocate the ppc_data structure.
+	 */
+	ppc = DEVTOSOFTC(dev);
+	bzero(ppc, sizeof(struct ppc_data));
+
+	ppc->rid_irq = ppc->rid_drq = ppc->rid_ioport = 0;
+	ppc->res_irq = ppc->res_drq = ppc->res_ioport = 0;
+
+	/* IO port is mandatory */
+	ppc->rid_ioport = 0;
+	ppc->res_ioport =
+	  bus_alloc_resource(dev, SYS_RES_IOPORT,
+			     &ppc->rid_ioport, 0, ~0,
+			     1, RF_ACTIVE);
+ 	ppc->ppc_base = rman_get_start(ppc->res_ioport);
+
+	ppc->bsh = rman_get_bushandle(ppc->res_ioport);
+	ppc->bst = rman_get_bustag(ppc->res_ioport);
+
+	BUS_READ_IVAR(device_get_parent(dev), dev, PUC_IVAR_PPCCAP,
+		      &ppc->ppc_avm);
+
+	/* 0x20 enable interrupt */
+	ppc->ppc_flags = PPB_SPP | 0x20;
+
+	ppc->rid_irq = 0;
+	ppc->res_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &ppc->rid_irq,
+					  0ul, ~0ul, 1, RF_SHAREABLE);
+
+	if (ppc->res_irq)
+	  {
+	    ppc->ppc_irq = rman_get_start(ppc->res_irq);
+	  }
+
+	if (ppc->res_drq)
+		ppc->ppc_dmachan = rman_get_start(ppc->res_drq);
+
+	ppc->ppc_unit = device_get_unit(dev);
+	ppc->ppc_model = GENERIC;
+
+	ppc->ppc_mode = PPB_COMPATIBLE;
+	ppc->ppc_epp = (ppc->ppc_flags & 0x10) >> 4;
+
+	ppc->ppc_type = PPC_TYPE_GENERIC;
+
+
+	device_printf(dev, "puc chipset (%s) in %s mode%s\n",
+		      ppc_avms[ppc->ppc_avm],
+		      ppc_modes[ppc->ppc_mode], (PPB_IS_EPP(ppc->ppc_mode)) ?
+		      ppc_epp_protocol[ppc->ppc_epp] : "");
+
+	if (ppc->ppc_fifo)
+		device_printf(dev, "FIFO with %d/%d/%d bytes threshold\n",
+			      ppc->ppc_fifo, ppc->ppc_wthr, ppc->ppc_rthr);
+
+#if 0
+/*  	if ((ppc->ppc_avm & PPB_ECP) && (ppc->ppc_dmachan > 0)) { */
+  		/* acquire the DMA channel forever */	/* XXX */
+/*  		isa_dma_acquire(ppc->ppc_dmachan); */
+  		isa_dmainit(ppc->ppc_dmachan, 1024); /* nlpt.BUFSIZE */
+/*  	} */
+#endif
+
+	/* add ppbus as a child of this isa to parallel bridge */
+	ppbus = device_add_child(dev, "ppbus", -1);
+
+	/*
+	 * Probe the ppbus and attach devices found.
+	 */
+	device_probe_and_attach(ppbus);
+
+	return (0);
+}
+
+
+DRIVER_MODULE(ppc, puc, ppc_puc_driver, ppc_devclass, 0, 0);
+#endif
--- /usr/src/share/man/man4/puc.4	Thu Mar  7 18:48:38 2002
+++ /usr/home/brp/puc/200205211000/puc.4	Tue May 21 12:39:07 2002
@@ -24,7 +24,7 @@
 .\"
 .\" $FreeBSD: src/share/man/man4/puc.4,v 1.1.2.1 2002/03/07 17:48:38 jhay Exp $
 .\"
-.Dd February 7, 2002
+.Dd 21 May 2002
 .Dt PUC 4
 .Os
 .Sh NAME
@@ -34,11 +34,13 @@
 .Cd device pci
 .Cd device puc
 .Cd device sio
+.Cd device ppc
 .Cd options PUC_FASTINTR
 .Sh DESCRIPTION
 This driver acts as a shim to connect pci serial ports to the
 .Xr sio 4
-driver.
+driver and to connect pci parallel ports to the
+.Xr ppc 4 driver.
 .Pp
 The list of supported devices is in 
 .Em src/sys/dev/puc/pucdata.c.
@@ -51,8 +53,15 @@
 .Em silo overflow
 errors.
 It cannot be used if the interrupt is shared.
+.Pp
+The parallel port driver hooks into the
+.Xr ppc 4
+layer and therefore allows the port to be used by all devices that
+interact with the parallel bus device.
 .Sh SEE ALSO
 .Xr sio 4
+.Xr ppc 4
+.Xr ppbus 4
 .Sh HISTORY
 This driver took the idea from the
 .Nx
@@ -60,9 +69,4 @@
 driver and still use the same structure to describe cards to ease exchanging
 card info.
 .Sh BUGS
-Only serial ports are supported through the
-.Xr sio 4
-driver at the moment.
-Someone should write support for parallel ports using the
-.Xr lpt 4
-driver.
+Parallel ports are only supported in compatibility mode.
>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?20020521112757.4DD61A80D>