diff options
author | njl <njl@FreeBSD.org> | 2004-02-15 20:30:22 +0000 |
---|---|---|
committer | njl <njl@FreeBSD.org> | 2004-02-15 20:30:22 +0000 |
commit | d3d228237561f16ad427ffaf3b036f2339ed0104 (patch) | |
tree | da963b00c528fe150a945f07858b39366577ba28 /sys | |
parent | 70edb52ffb2f8713bd2ea0249d357cf5d49809c4 (diff) | |
download | FreeBSD-src-d3d228237561f16ad427ffaf3b036f2339ed0104.zip FreeBSD-src-d3d228237561f16ad427ffaf3b036f2339ed0104.tar.gz |
Workaround some ACPI BIOSen which break the IO port into multiple
resources. (Note that the correct range is 0x3f7,0x3f0-0x3f5.) Such
devices will be detected as follows:
fdc0: <Enhanced floppy controller (i82077, NE72065 or clone)> port
0x3f7,0x3f4-0x3f5,0x3f2-0x3f3,0x3f0-0x3f1 irq 6 drq 2 on acpi0
To do this, we find the minimum and maximum start addresses for the
resources and use them as the base for the IO and control ports.
Help from: jhb
Diffstat (limited to 'sys')
-rw-r--r-- | sys/dev/fdc/fdc.c | 36 | ||||
-rw-r--r-- | sys/isa/fd.c | 36 |
2 files changed, 70 insertions, 2 deletions
diff --git a/sys/dev/fdc/fdc.c b/sys/dev/fdc/fdc.c index fe88b94..5cc9408 100644 --- a/sys/dev/fdc/fdc.c +++ b/sys/dev/fdc/fdc.c @@ -686,6 +686,7 @@ fdc_alloc_resources(struct fdc_data *fdc) ispcmcia = (fdc->flags & FDC_ISPCMCIA) != 0; fdc->rid_ioport = fdc->rid_irq = fdc->rid_drq = 0; fdc->res_ioport = fdc->res_irq = fdc->res_drq = 0; + fdc->rid_ctl = 1; /* * On standard ISA, we don't just use an 8 port range @@ -699,6 +700,40 @@ fdc_alloc_resources(struct fdc_data *fdc) * one with offset 7 as control register. */ nports = ispcmcia ? 8 : (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. + */ + 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; + } + } + if (min_start + 7 != max_start) { + device_printf(dev, "I/O to control range incorrect\n"); + return (ENXIO); + } + } + fdc->res_ioport = bus_alloc_resource(dev, SYS_RES_IOPORT, &fdc->rid_ioport, 0ul, ~0ul, nports, RF_ACTIVE); @@ -746,7 +781,6 @@ fdc_alloc_resources(struct fdc_data *fdc) /* * Now (finally!) allocate the control port. */ - fdc->rid_ctl = 1; fdc->res_ctl = bus_alloc_resource(dev, SYS_RES_IOPORT, &fdc->rid_ctl, 0ul, ~0ul, 1, RF_ACTIVE); diff --git a/sys/isa/fd.c b/sys/isa/fd.c index fe88b94..5cc9408 100644 --- a/sys/isa/fd.c +++ b/sys/isa/fd.c @@ -686,6 +686,7 @@ fdc_alloc_resources(struct fdc_data *fdc) ispcmcia = (fdc->flags & FDC_ISPCMCIA) != 0; fdc->rid_ioport = fdc->rid_irq = fdc->rid_drq = 0; fdc->res_ioport = fdc->res_irq = fdc->res_drq = 0; + fdc->rid_ctl = 1; /* * On standard ISA, we don't just use an 8 port range @@ -699,6 +700,40 @@ fdc_alloc_resources(struct fdc_data *fdc) * one with offset 7 as control register. */ nports = ispcmcia ? 8 : (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. + */ + 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; + } + } + if (min_start + 7 != max_start) { + device_printf(dev, "I/O to control range incorrect\n"); + return (ENXIO); + } + } + fdc->res_ioport = bus_alloc_resource(dev, SYS_RES_IOPORT, &fdc->rid_ioport, 0ul, ~0ul, nports, RF_ACTIVE); @@ -746,7 +781,6 @@ fdc_alloc_resources(struct fdc_data *fdc) /* * Now (finally!) allocate the control port. */ - fdc->rid_ctl = 1; fdc->res_ctl = bus_alloc_resource(dev, SYS_RES_IOPORT, &fdc->rid_ctl, 0ul, ~0ul, 1, RF_ACTIVE); |