Preliminary fdc patches

M. Warner Losh imp at bsdimp.com
Sun Sep 12 22:39:42 PDT 2004


Can people test these?  I seem to have only good, well behaved fdc
devices :-)  These patches should be considered experimental.  I've
tried them on one machine only.

Warner
-------------- next part --------------
Index: fdc.c
===================================================================
RCS file: /cache/ncvs/src/sys/dev/fdc/fdc.c,v
retrieving revision 1.286
diff -u -r1.286 fdc.c
--- fdc.c	27 Aug 2004 17:08:24 -0000	1.286
+++ fdc.c	13 Sep 2004 05:24:10 -0000
@@ -306,28 +306,28 @@
 fdout_wr(struct fdc_data *fdc, u_int8_t v)
 {
 
-	bus_space_write_1(fdc->portt, fdc->porth, FDOUT+fdc->port_off, v);
+	bus_space_write_1(fdc->portt, fdc->porth, FDOUT + fdc->port_off, v);
 }
 
 static u_int8_t
 fdsts_rd(struct fdc_data *fdc)
 {
 
-	return bus_space_read_1(fdc->portt, fdc->porth, FDSTS+fdc->port_off);
+	return (bus_space_read_1(fdc->stst, fdc->stsh, FDSTS + fdc->sts_off));
 }
 
 static void
 fddata_wr(struct fdc_data *fdc, u_int8_t v)
 {
 
-	bus_space_write_1(fdc->portt, fdc->porth, FDDATA+fdc->port_off, v);
+	bus_space_write_1(fdc->stst, fdc->stsh, FDDATA + fdc->sts_off, v);
 }
 
 static u_int8_t
 fddata_rd(struct fdc_data *fdc)
 {
 
-	return bus_space_read_1(fdc->portt, fdc->porth, FDDATA+fdc->port_off);
+	return (bus_space_read_1(fdc->stst, fdc->stsh, FDDATA + fdc->sts_off));
 }
 
 static u_int8_t
@@ -1484,39 +1484,30 @@
 	device_t dev;
 
 	dev = fdc->fdc_dev;
-	if (fdc->fdc_intr) {
+	if (fdc->fdc_intr)
 		BUS_TEARDOWN_INTR(device_get_parent(dev), dev, fdc->res_irq,
 		    fdc->fdc_intr);
-		fdc->fdc_intr = NULL;
-	}
-	if (fdc->res_irq != 0) {
-		bus_deactivate_resource(dev, SYS_RES_IRQ, fdc->rid_irq,
-					fdc->res_irq);
+	fdc->fdc_intr = NULL;
+	if (fdc->res_irq != NULL)
 		bus_release_resource(dev, SYS_RES_IRQ, fdc->rid_irq,
-				     fdc->res_irq);
-		fdc->res_irq = NULL;
-	}
-	if (fdc->res_ctl != 0) {
-		bus_deactivate_resource(dev, SYS_RES_IOPORT, fdc->rid_ctl,
-					fdc->res_ctl);
+		    fdc->res_irq);
+	fdc->res_irq = NULL;
+	if (fdc->res_ctl != NULL && fdc->rid_ctl != -1)
 		bus_release_resource(dev, SYS_RES_IOPORT, fdc->rid_ctl,
-				     fdc->res_ctl);
-		fdc->res_ctl = NULL;
-	}
-	if (fdc->res_ioport != 0) {
-		bus_deactivate_resource(dev, SYS_RES_IOPORT, fdc->rid_ioport,
-					fdc->res_ioport);
+		    fdc->res_ctl);
+	fdc->res_ctl = NULL;
+	if (fdc->res_sts != NULL && fdc->rid_sts != -1)
+		bus_release_resource(dev, SYS_RES_IOPORT, fdc->rid_sts,
+		    fdc->res_sts);
+	fdc->res_sts = NULL;
+	if (fdc->res_ioport != NULL)
 		bus_release_resource(dev, SYS_RES_IOPORT, fdc->rid_ioport,
-				     fdc->res_ioport);
-		fdc->res_ioport = NULL;
-	}
-	if (fdc->res_drq != 0) {
-		bus_deactivate_resource(dev, SYS_RES_DRQ, fdc->rid_drq,
-					fdc->res_drq);
+		    fdc->res_ioport);
+	fdc->res_ioport = NULL;
+	if (fdc->res_drq != NULL)
 		bus_release_resource(dev, SYS_RES_DRQ, fdc->rid_drq,
-				     fdc->res_drq);
-		fdc->res_drq = NULL;
-	}
+		    fdc->res_drq);
+	fdc->res_drq = NULL;
 }
 
 int
Index: fdc_isa.c
===================================================================
RCS file: /cache/ncvs/src/sys/dev/fdc/fdc_isa.c,v
retrieving revision 1.12
diff -u -r1.12 fdc_isa.c
--- fdc_isa.c	31 Aug 2004 20:37:10 -0000	1.12
+++ fdc_isa.c	13 Sep 2004 05:33:58 -0000
@@ -57,9 +57,8 @@
 int
 fdc_isa_alloc_resources(device_t dev, struct fdc_data *fdc)
 {
-	int ispnp, nports;
+	int nports = 6;
 
-	ispnp = (fdc->flags & FDC_ISPNP) != 0;
 	fdc->fdc_dev = dev;
 	fdc->rid_ioport = 0;
 	fdc->rid_irq = 0;
@@ -69,99 +68,84 @@
 	/*
 	 * On standard ISA, we don't just use an 8 port range
 	 * (e.g. 0x3f0-0x3f7) since that covers an IDE control
-	 * register at 0x3f6.
+	 * register at 0x3f6.  So, on older hardware, we use
+	 * 0x3f0-0x3f5 and 0x3f7.  However, some BIOSs omit the
+	 * control port, while others start at 0x3f2.  Of the latter,
+	 * sometimes we have two resources, other times we have one.
+	 * We have to deal with the following cases:
 	 *
-	 * Isn't PC hardware wonderful.
+	 * 1:	0x3f0-0x3f5			# very rare
+	 * 2:	0x3f0				# hints -> 0x3f0-0x3f5,0x3f7
+	 * 3:	0x3f0-0x3f5,0x3f7		# Most common
+	 * 4:	0x3f2-0x3f5,0x3f7		# Second most common
+	 * 5:	0x3f2-0x3f5			# implies 0x3f7 too.
+	 * 6:	0x3f2-0x3f3,0x3f4-0x3f5,0x3f7	# becoming common
+	 * 7:	0x3f2-0x3f3,0x3f4-0x3f5		# rare
+	 *
+	 * The following code is generic for any value of 0x3fx :-)
 	 */
-	nports = ispnp ? 1 : 6;
 
 	/*
-	 * Some ACPI BIOSen have _CRS objects for the floppy device that
-	 * split the I/O port resource into several resources.  We detect
-	 * this case by checking if there are more than 2 IOPORT resources.
-	 * If so, we use the resource with the smallest start address as
-	 * the port RID and the largest start address as the control RID.
+	 * First, allocated the main range of ports.  In the best of
+	 * worlds, this is 4 or 6 ports.  In others, well, that's
+	 * why this function is so complicated.
 	 */
-	if (bus_get_resource_count(dev, SYS_RES_IOPORT, 2) != 0) {
-		u_long min_start, max_start, tmp;
-		int i;
-
-		/* Find the min/max start addresses and their RIDs. */
-		max_start = 0ul;
-		min_start = ~0ul;
-		for (i = 0; bus_get_resource_count(dev, SYS_RES_IOPORT, i) > 0;
-		    i++) {
-			tmp = bus_get_resource_start(dev, SYS_RES_IOPORT, i);
-			KASSERT(tmp != 0, ("bogus resource"));
-			if (tmp < min_start) {
-				min_start = tmp;
-				fdc->rid_ioport = i;
-			}
-			if (tmp > max_start) {
-				max_start = tmp;
-				fdc->rid_ctl = i;
-			}
-		}
-	}
-
 	fdc->res_ioport = bus_alloc_resource(dev, SYS_RES_IOPORT,
 	    &fdc->rid_ioport, 0ul, ~0ul, nports, RF_ACTIVE);
 	if (fdc->res_ioport == 0) {
-		device_printf(dev, "cannot reserve I/O port range (%d ports)\n",
-			      nports);
-		return ENXIO;
+		device_printf(dev, "cannot allocate I/O port (%d ports)\n",
+		    nports);
+		return (ENXIO);
 	}
 	fdc->portt = rman_get_bustag(fdc->res_ioport);
 	fdc->porth = rman_get_bushandle(fdc->res_ioport);
 
 	/*
-	 * Some BIOSen report the device at 0x3f2-0x3f5,0x3f7
-	 * and some at 0x3f0-0x3f5,0x3f7. We detect the former
-	 * by checking the size and adjust the port address
-	 * accordingly.
+	 * Handle cases 4-7 above
 	 */
-	if (bus_get_resource_count(dev, SYS_RES_IOPORT, 0) == 4)
-		fdc->port_off = -2;
+	fdc->port_off = -(fdc->porth & 0x7);
 
 	/*
-	 * Register the control port range as rid 1 if it
-	 * isn't there already. Most PnP BIOSen will have
-	 * already done this but non-PnP configurations don't.
-	 *
-	 * And some (!!) report 0x3f2-0x3f5 and completely
-	 * leave out the control register!  It seems that some
-	 * non-antique controller chips have a different
-	 * method of programming the transfer speed which
-	 * doesn't require the control register, but it's
-	 * mighty bogus as the chip still responds to the
-	 * address for the control register.
+	 * Deal with case 6 and 7: FDSTS and FDSATA are in rid 1.
 	 */
-	if (bus_get_resource_count(dev, SYS_RES_IOPORT, 1) == 0) {
-		u_long ctlstart;
-		/* Find the control port, usually 0x3f7 */
-		ctlstart = rman_get_start(fdc->res_ioport) + fdc->port_off + 7;
-		bus_set_resource(dev, SYS_RES_IOPORT, 1, ctlstart, 1);
+	if (rman_get_size(fdc->res_ioport) == 2) {
+		fdc->rid_sts = 1;
+		fdc->res_sts = bus_alloc_resource_any(dev, SYS_RES_IOPORT,
+		    &fdc->rid_sts, RF_ACTIVE);
+		if (fdc->res_sts == NULL) {
+			device_printf(dev, "Can't alloc rid 1");
+			fdc_release_resources(fdc);
+			return (ENXIO);
+		}
+		fdc->rid_ctl++;
+		fdc->sts_off = -4;
+	} else {
+		fdc->res_sts = NULL;
+		fdc->sts_off = fdc->port_off;
 	}
+	fdc->stst = rman_get_bustag(fdc->res_sts);
+	fdc->stsh = rman_get_bushandle(fdc->res_sts);
 
 	/*
-	 * Now (finally!) allocate the control port.
+	 * allocate the control port.  For cases 1, 2, 5 and 7, we
+	 * fake it from the ioports resource.
 	 */
 	fdc->res_ctl = bus_alloc_resource_any(dev, SYS_RES_IOPORT,
 	    &fdc->rid_ctl, RF_ACTIVE);
-	if (fdc->res_ctl == 0) {
-		device_printf(dev,
-		    "cannot reserve control I/O port range (control port)\n");
-		return ENXIO;
+	if (fdc->res_ctl == NULL) {
+		fdc->ctl_off = 7 + fdc->port_off;
+		fdc->res_ctl = NULL;
+	} else {
+		fdc->ctl_off = 0;
 	}
 	fdc->ctlt = rman_get_bustag(fdc->res_ctl);
 	fdc->ctlh = rman_get_bushandle(fdc->res_ctl);
-	fdc->ctl_off = 0;
 
 	fdc->res_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &fdc->rid_irq,
-					      RF_ACTIVE | RF_SHAREABLE);
+	    RF_ACTIVE | RF_SHAREABLE);
 	if (fdc->res_irq == 0) {
 		device_printf(dev, "cannot reserve interrupt line\n");
-		return ENXIO;
+		return (ENXIO);
 	}
 
 	if ((fdc->flags & FDC_NODMA) == 0) {
@@ -169,12 +153,13 @@
 		    &fdc->rid_drq, RF_ACTIVE | RF_SHAREABLE);
 		if (fdc->res_drq == 0) {
 			device_printf(dev, "cannot reserve DMA request line\n");
+			/* This is broken and doesn't work for ISA case */
 			fdc->flags |= FDC_NODMA;
 		} else
 			fdc->dmachan = rman_get_start(fdc->res_drq);
 	}
 
-	return 0;
+	return (0);
 }
 
 static int
Index: fdc_pccard.c
===================================================================
RCS file: /cache/ncvs/src/sys/dev/fdc/fdc_pccard.c,v
retrieving revision 1.9
diff -u -r1.9 fdc_pccard.c
--- fdc_pccard.c	20 Aug 2004 15:14:25 -0000	1.9
+++ fdc_pccard.c	13 Sep 2004 05:34:23 -0000
@@ -65,6 +65,9 @@
 	}
 	fdc->portt = rman_get_bustag(fdc->res_ioport);
 	fdc->porth = rman_get_bushandle(fdc->res_ioport);
+	fdc->stst = fdc->portt;
+	fdc->stsh = fdc->porth;
+	fdc->sts_off = 0;
 	fdc->ctlt = fdc->portt;
 	fdc->ctlh = fdc->porth;
 	fdc->ctl_off = 7;
Index: fdcvar.h
===================================================================
RCS file: /cache/ncvs/src/sys/dev/fdc/fdcvar.h,v
retrieving revision 1.4
diff -u -r1.4 fdcvar.h
--- fdcvar.h	20 Aug 2004 15:14:25 -0000	1.4
+++ fdcvar.h	13 Sep 2004 05:30:09 -0000
@@ -57,14 +57,17 @@
 	int	fdc_errs;	/* number of logged errors */
 	struct	bio_queue_head head;
 	struct	bio *bp;	/* active buffer */
-	struct	resource *res_ioport, *res_ctl, *res_irq, *res_drq;
-	int	rid_ioport, rid_ctl, rid_irq, rid_drq;
-	int	port_off;
+	struct	resource *res_ioport, *res_sts, *res_ctl, *res_irq, *res_drq;
+	int	rid_ioport, rid_sts, rid_ctl, rid_irq, rid_drq;
 	bus_space_tag_t portt;
 	bus_space_handle_t porth;
+	bus_space_tag_t stst;
+	bus_space_handle_t stsh;
 	bus_space_tag_t ctlt;
 	bus_space_handle_t ctlh;
+	int	port_off;
 	int	ctl_off;
+	int	sts_off;
 	void	*fdc_intr;
 	struct	device *fdc_dev;
 	struct mtx fdc_mtx;


More information about the freebsd-hackers mailing list