Subject: Testers needed for pnpbios code
To: None <port-i386@netbsd.org, tech-kern@netbsd.org>
From: None <jchacon@genuity.net>
List: port-i386
Date: 10/29/2000 01:52:40
I have a laptop that the pnpbios returns i/o mappings which come out as

3f0-3f5
3f7

which is different than what the code was written to expect (Most machines
return 3f2-3f5 and 3f7 I beleive). There are also 2 PR's (10117 and 10602)
out there that show machines only returning the first ranges and not the
2nd controller port. In my machines case because the i/o range is off by 2
the code never probes the floppy drives correctly since it's poking and reading
values from the wrong port.

The attached patches fix all of this by checking carefully the probe values
and lining everything up. (In the case of not returning the controller port
an attempt is made to just map it in anyways).

What I need is anyone with a pnpbios and either a previously non-working fdc
probe (or a currently working one) to give these patches a try and let me
know if they work correctly. I've tested on my system and everything checks
out but I don't have any of the other cases. I especially would like anyone
who has a machine reporting just 1 i/o range and not the control port.

These apply clean against -current and I haven't tried against 1.5.

Thanks

James

--

Index: sys/dev/isa/fd.c
===================================================================
RCS file: /cvsroot/syssrc/sys/dev/isa/fd.c,v
retrieving revision 1.8
diff -u -r1.8 fd.c
--- sys/dev/isa/fd.c	2000/08/24 20:04:28	1.8
+++ sys/dev/isa/fd.c	2000/10/29 06:37:09
@@ -304,10 +304,14 @@
 	struct fdc_softc *fdc;
 {
 	struct fdc_attach_args fa;
+        bus_space_tag_t iot;
+        bus_space_handle_t ioh;
 #if defined(__i386__)
 	int type;
 #endif
 
+        iot = fdc->sc_iot;
+        ioh = fdc->sc_ioh;
 	callout_init(&fdc->sc_timo_ch);
 	callout_init(&fdc->sc_intr_ch);
 
@@ -322,7 +326,26 @@
 		    fdc->sc_dev.dv_xname);
 		return;
 	}
-
+ 
+        /* 
+         * Reset the controller to get it into a known state. Not all
+         * probes necessarily need do this to discover the controller up
+         * front, so don't assume anything.
+         */
+         
+        bus_space_write_1(iot, ioh, fdout, 0);
+        delay(100);
+        bus_space_write_1(iot, ioh, fdout, FDO_FRST);
+ 
+        /* see if it can handle a command */
+        if (out_fdc(iot, ioh, NE7CMD_SPECIFY) < 0) {
+            printf ("%s: can't reset controller\n",
+                    fdc->sc_dev.dv_xname);
+            return;
+        }
+        out_fdc(iot, ioh, 0xdf);
+        out_fdc(iot, ioh, 2);
+  
 #if defined(__i386__)
 	/*
 	 * The NVRAM info only tells us about the first two disks on the
Index: sys/arch/i386/pnpbios/pnpbiosvar.h
===================================================================
RCS file: /cvsroot/syssrc/sys/arch/i386/pnpbios/pnpbiosvar.h,v
retrieving revision 1.4
diff -u -r1.4 pnpbiosvar.h
--- sys/arch/i386/pnpbios/pnpbiosvar.h	2000/04/22 06:38:24	1.4
+++ sys/arch/i386/pnpbios/pnpbiosvar.h	2000/10/29 06:37:09
@@ -94,6 +94,7 @@
 
 int pnpbios_getiobase __P((pnpbios_tag_t, struct pnpresources *, int,
 			   bus_space_tag_t *, int *));
+int pnpbios_getiosize __P((pnpbios_tag_t, struct pnpresources *, int, int *));
 int pnpbios_getirqnum __P((pnpbios_tag_t, struct pnpresources *, int, int *,
 			   int *));
 int pnpbios_getdmachan __P((pnpbios_tag_t, struct pnpresources *, int, int *));
Index: sys/arch/i386/pnpbios/pnpbios.c
===================================================================
RCS file: /cvsroot/syssrc/sys/arch/i386/pnpbios/pnpbios.c,v
retrieving revision 1.20
diff -u -r1.20 pnpbios.c
--- sys/arch/i386/pnpbios/pnpbios.c	2000/06/29 08:44:58	1.20
+++ sys/arch/i386/pnpbios/pnpbios.c	2000/10/29 06:37:10
@@ -1362,6 +1362,26 @@
 	return (0);
 }
 
+int
+pnpbios_getiosize(pbt, resc, idx, sizep)
+        pnpbios_tag_t pbt;
+        struct pnpresources *resc;
+        int idx;
+        int *sizep;
+{
+        struct pnp_io *io;
+
+        if (idx >= resc->numio)
+            return (EINVAL);
+
+        io = SIMPLEQ_FIRST(&resc->io);
+        while (idx--)
+                io = SIMPLEQ_NEXT(io, next);
+        if (sizep)
+                *sizep = io->len;
+        return (0);
+}
+
 void *
 pnpbios_intr_establish(pbt, resc, idx, level, fcn, arg)
 	pnpbios_tag_t pbt;
Index: sys/arch/i386/pnpbios/fdc_pnpbios.c
===================================================================
RCS file: /cvsroot/syssrc/sys/arch/i386/pnpbios/fdc_pnpbios.c,v
retrieving revision 1.1
diff -u -r1.1 fdc_pnpbios.c
--- sys/arch/i386/pnpbios/fdc_pnpbios.c	2000/04/23 17:50:00	1.1
+++ sys/arch/i386/pnpbios/fdc_pnpbios.c	2000/10/29 06:37:10
@@ -65,8 +65,15 @@
 int	fdc_pnpbios_match(struct device *, struct cfdata *, void *);
 void	fdc_pnpbios_attach(struct device *, struct device *, void *);
 
+struct fdc_pnpbios_softc {
+        struct fdc_softc sc_fdc;        /* base fdc device */
+
+        bus_space_handle_t sc_baseioh;  /* base I/O handle */
+};
+
+
 struct cfattach fdc_pnpbios_ca = {
-	sizeof(struct fdc_softc), fdc_pnpbios_match,
+	sizeof(struct fdc_pnpbios_softc), fdc_pnpbios_match,
 	    fdc_pnpbios_attach,
 };
 
@@ -89,18 +96,72 @@
     void *aux)
 {
 	struct fdc_softc *fdc = (void *) self;
+        struct fdc_pnpbios_softc *pdc = (void *) self;
 	struct pnpbiosdev_attach_args *aa = aux;
-
+        int size;
+        
 	printf("\n");
 
 	fdc->sc_ic = aa->ic;
 
-	if (pnpbios_io_map(aa->pbt, aa->resc, 0, &fdc->sc_iot, &fdc->sc_ioh)) {
+	if (pnpbios_io_map(aa->pbt, aa->resc, 0, &fdc->sc_iot,
+            &pdc->sc_baseioh)) {
 		printf("%s: unable to map I/O space\n", fdc->sc_dev.dv_xname);
 		return;
 	}
 
-	if (pnpbios_io_map(aa->pbt, aa->resc, 1, &fdc->sc_iot,
+	/* 
+         * Start accounting for "odd" pnpbios's. Some probe as 4 ports,
+         * some as 6 and some don't give the ctl port back. 
+         */
+
+        if (pnpbios_getiosize(aa->pbt, aa->resc, 0, &size)) {
+                printf("%s: can't get iobase size\n", fdc->sc_dev.dv_xname);
+                return;
+        }
+
+        switch (size) {
+
+        /* Easy case. This matches right up with what the fdc code expects. */
+        case 4:
+                fdc->sc_ioh = pdc->sc_baseioh;
+                break;
+
+        /* Map a subregion so this all lines up with the fdc code. */
+        case 6:
+                if (bus_space_subregion(fdc->sc_iot, pdc->sc_baseioh, 2, 4,
+                    &fdc->sc_ioh)) {
+                        printf("%s: unable to subregion I/O space\n",
+                            fdc->sc_dev.dv_xname);
+                        return;
+                }
+                break;
+        default:
+                printf ("%s: unknown size: %d of io mapping\n",
+                    fdc->sc_dev.dv_xname, size);
+                return;
+        }
+        
+        /* 
+         * XXX: This is bad. If the pnpbios claims only 1 I/O range then it's
+         * omitting the controller I/O port. (One has to exist for there to
+         * be a working fdc). Just try and force the mapping in. 
+         */
+
+        if (aa->resc->numio == 0) {
+            int base;
+
+            if (pnpbios_getiobase (aa->pbt, aa->resc, 0, 0, &base)) {
+                    printf ("%s: can't get iobase\n", fdc->sc_dev.dv_xname);
+                    return;
+            }
+            if (bus_space_map(fdc->sc_iot, base + size + 1, 1, 0,
+                &fdc->sc_fdctlioh)) {
+                    printf("%s: unable to force map CTL I/O space\n", 
+                        fdc->sc_dev.dv_xname);
+                    return;
+            }
+        } else if (pnpbios_io_map(aa->pbt, aa->resc, 1, &fdc->sc_iot,
 	    &fdc->sc_fdctlioh)) {
 		printf("%s: unable to map CTL I/O space\n",
 		    fdc->sc_dev.dv_xname);