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