aboutsummaryrefslogtreecommitdiff
path: root/sys/dev/fdc
diff options
context:
space:
mode:
authorWarner Losh <imp@FreeBSD.org>2005-01-19 07:46:38 +0000
committerWarner Losh <imp@FreeBSD.org>2005-01-19 07:46:38 +0000
commit973bfe6c4a9241699e6e256cfa8fd74532adfe97 (patch)
tree2b913234aa2be66ec2ed3171f91718934b9ebcff /sys/dev/fdc
parent33481e9d67da5a3ade37c2f6dbe1dfde3d3d6671 (diff)
downloadsrc-973bfe6c4a9241699e6e256cfa8fd74532adfe97.tar.gz
src-973bfe6c4a9241699e6e256cfa8fd74532adfe97.zip
MFp4: overhaul of resource allocation
Rather than have a twisty maze of special case allocations, move instead to a data driven allocation. This should be the most robust way to cope with the resource problems that the multiplicity of ways of encoding 5 registers that have the misfortune of not being a power of 2 nor contiguous. Also, make it less impossible that pccard will work. I've not been able to get my libretto floppy working, but it now fails later than before. phk and I had similar ideas on this during the 5.3 release cycle, but it wasn't until recently that I could test more than one allocation scenario. MFC After: 1 month (5.4 if possible, 5.5 if not)
Notes
Notes: svn path=/head/; revision=140469
Diffstat (limited to 'sys/dev/fdc')
-rw-r--r--sys/dev/fdc/fdc.c89
-rw-r--r--sys/dev/fdc/fdc_isa.c149
-rw-r--r--sys/dev/fdc/fdc_pccard.c30
-rw-r--r--sys/dev/fdc/fdcvar.h24
4 files changed, 134 insertions, 158 deletions
diff --git a/sys/dev/fdc/fdc.c b/sys/dev/fdc/fdc.c
index 7c515904c223..22124cb7d1e5 100644
--- a/sys/dev/fdc/fdc.c
+++ b/sys/dev/fdc/fdc.c
@@ -110,7 +110,6 @@ __FBSDID("$FreeBSD$");
*
* 2.88M format has 2 x 36 x 512, allow for hacked up density.
*/
-
#define MAX_BYTES_PER_CYL (2 * 40 * 512)
/*
@@ -196,15 +195,22 @@ static struct fd_type *fd_native_types[] = {
#define FDCTL 7 /* Control Register (W) */
/*
- * The YE-DATA PC Card floppies use PIO to read in the data rather than
- * DMA due to the wild variability of DMA for the PC Card devices. In
- * addition, if we cannot setup the DMA resources for the ISA attachment,
- * we'll use this same offset for data transfer.
+ * The YE-DATA PC Card floppies use PIO to read in the data rather
+ * than DMA due to the wild variability of DMA for the PC Card
+ * devices. DMA was deleted from the PC Card specification in version
+ * 7.2 of the standard, but that post-dates the YE-DATA devices by many
+ * years.
+ *
+ * In addition, if we cannot setup the DMA resources for the ISA
+ * attachment, we'll use this same offset for data transfer. However,
+ * that almost certainly won't work.
*
* For this mode, offset 0 and 1 must be used to setup the transfer
- * for this floppy. This means they are only available on those systems
- * that map them to the floppy drive. Newer systems do not do this, and
- * we should likely prohibit access to them (or disallow NODMA to be set).
+ * for this floppy. This is OK for PC Card YE Data devices, but for
+ * ISA this is likely wrong. These registers are only available on
+ * those systems that map them to the floppy drive. Newer systems do
+ * not do this, and we should likely prohibit access to them (or
+ * disallow NODMA to be set).
*/
#define FDBCDR 0 /* And 1 */
#define FD_YE_DATAPORT 6 /* Drive Data port */
@@ -303,46 +309,60 @@ fdsettype(struct fd_data *fd, struct fd_type *ft)
/*
* Bus space handling (access to low-level IO).
*/
+__inline static void
+fdregwr(struct fdc_data *fdc, int reg, uint8_t v)
+{
+
+ bus_space_write_1(fdc->iot, fdc->ioh[reg], fdc->ioff[reg], v);
+}
+
+__inline static uint8_t
+fdregrd(struct fdc_data *fdc, int reg)
+{
+
+ return bus_space_read_1(fdc->iot, fdc->ioh[reg], fdc->ioff[reg]);
+}
+
static void
fdctl_wr(struct fdc_data *fdc, u_int8_t v)
{
- bus_space_write_1(fdc->ctlt, fdc->ctlh, fdc->ctl_off, v);
+ fdregwr(fdc, FDCTL, v);
}
static void
fdout_wr(struct fdc_data *fdc, u_int8_t v)
{
- bus_space_write_1(fdc->portt, fdc->porth, FDOUT+fdc->port_off, v);
+ fdregwr(fdc, FDOUT, 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 fdregrd(fdc, FDSTS);
}
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);
+ fdregwr(fdc, FDDATA, 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 fdregrd(fdc, FDDATA);
}
static u_int8_t
fdin_rd(struct fdc_data *fdc)
{
- return bus_space_read_1(fdc->ctlt, fdc->ctlh, fdc->ctl_off);
+ return fdregrd(fdc, FDCTL);
}
/*
@@ -352,10 +372,9 @@ fdin_rd(struct fdc_data *fdc)
static void
fdbcdr_wr(struct fdc_data *fdc, int iswrite, uint16_t count)
{
- bus_space_write_1(fdc->portt, fdc->porth, fdc->port_off + FDBCDR,
- (count - 1) & 0xff);
- bus_space_write_1(fdc->portt, fdc->porth, fdc->port_off + FDBCDR + 1,
- ((iswrite ? 0x80 : 0) | (((count - 1) >> 8) & 0x7f)));
+ fdregwr(fdc, FDBCDR, (count - 1) & 0xff);
+ fdregwr(fdc, FDBCDR + 1,
+ (iswrite ? 0x80 : 0) | (((count - 1) >> 8) & 0x7f));
}
static int
@@ -669,11 +688,11 @@ fdc_pio(struct fdc_data *fdc)
if (bp->bio_cmd == BIO_READ) {
fdbcdr_wr(fdc, 0, count);
- bus_space_read_multi_1(fdc->portt, fdc->porth, fdc->port_off +
- FD_YE_DATAPORT, cptr, count);
+ bus_space_read_multi_1(fdc->iot, fdc->ioh[FD_YE_DATAPORT],
+ fdc->ioff[FD_YE_DATAPORT], cptr, count);
} else {
- bus_space_write_multi_1(fdc->portt, fdc->porth, fdc->port_off +
- FD_YE_DATAPORT, cptr, count);
+ bus_space_write_multi_1(fdc->iot, fdc->ioh[FD_YE_DATAPORT],
+ fdc->ioff[FD_YE_DATAPORT], cptr, count);
fdbcdr_wr(fdc, 0, count); /* needed? */
}
}
@@ -1519,6 +1538,8 @@ void
fdc_release_resources(struct fdc_data *fdc)
{
device_t dev;
+ struct resource *last;
+ int i;
dev = fdc->fdc_dev;
if (fdc->fdc_intr)
@@ -1528,18 +1549,15 @@ fdc_release_resources(struct fdc_data *fdc)
bus_release_resource(dev, SYS_RES_IRQ, fdc->rid_irq,
fdc->res_irq);
fdc->res_irq = NULL;
- if (fdc->res_ctl != NULL)
- bus_release_resource(dev, SYS_RES_IOPORT, fdc->rid_ctl,
- fdc->res_ctl);
- fdc->res_ctl = NULL;
- if (fdc->res_sts != NULL)
- 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;
+ last = NULL;
+ for (i = 0; i < FDC_MAXREG; i++) {
+ if (fdc->resio[i] != NULL && fdc->resio[i] != last) {
+ bus_release_resource(dev, SYS_RES_IOPORT,
+ fdc->ridio[i], fdc->resio[i]);
+ last = fdc->resio[i];
+ fdc->resio[i] = NULL;
+ }
+ }
if (fdc->res_drq != NULL)
bus_release_resource(dev, SYS_RES_DRQ, fdc->rid_drq,
fdc->res_drq);
@@ -1719,7 +1737,8 @@ fdc_attach(device_t dev)
return (error);
}
error = bus_setup_intr(dev, fdc->res_irq,
- INTR_TYPE_BIO | INTR_ENTROPY | INTR_FAST | INTR_MPSAFE,
+ INTR_TYPE_BIO | INTR_ENTROPY | INTR_MPSAFE |
+ ((fdc->flags & FDC_NOFAST) ? 0 : INTR_FAST),
fdc_intr, fdc, &fdc->fdc_intr);
if (error) {
device_printf(dev, "cannot setup interrupt\n");
diff --git a/sys/dev/fdc/fdc_isa.c b/sys/dev/fdc/fdc_isa.c
index fe4776660c59..a6885a9b02e3 100644
--- a/sys/dev/fdc/fdc_isa.c
+++ b/sys/dev/fdc/fdc_isa.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 2004 M. Warner Losh.
+ * Copyright (c) 2004-2005 M. Warner Losh.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -47,116 +47,73 @@ __FBSDID("$FreeBSD$");
static int fdc_isa_probe(device_t);
static struct isa_pnp_id fdc_ids[] = {
- {0x0007d041, "PC standard floppy disk controller"}, /* PNP0700 */
+ {0x0007d041, "PC standard floppy controller"}, /* PNP0700 */
{0x0107d041, "Standard floppy controller supporting MS Device Bay Spec"}, /* PNP0701 */
{0}
};
+/*
+ * 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. 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:
+ *
+ * 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
+ * 8: 0x3f0-0x3f1,0x3f2-0x3f3,0x3f4-0x3f5,0x3f7
+ * 9: 0x3f0-0x3f3,0x3f4-0x3f5,0x3f7
+ *
+ * The following code is generic for any value of 0x3fx. It is also
+ * generic for all the above cases, as well as cases where things are
+ * even weirder.
+ */
int
fdc_isa_alloc_resources(device_t dev, struct fdc_data *fdc)
{
+ struct resource *res;
int nports = 6;
+ int i, j, rid, newrid;
fdc->fdc_dev = dev;
- fdc->rid_ioport = 0;
- fdc->rid_irq = 0;
- fdc->rid_drq = 0;
- fdc->rid_ctl = 1;
-
- /*
- * 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. 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:
- *
- * 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
- * 8: 0x3f0-0x3f1,0x3f2-0x3f3,0x3f4-0x3f5,0x3f7
- * 9: 0x3f0-0x3f3,0x3f4-0x3f5,0x3f7
- *
- * The following code is generic for any value of 0x3fx :-)
- */
-
- /*
- * 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.
- */
-again_ioport:
- 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 allocate I/O port (%d ports)\n",
- nports);
- return (ENXIO);
- }
- if ((rman_get_end(fdc->res_ioport) & 0x7) == 1) {
- /* Case 8 */
- bus_release_resource(dev, SYS_RES_IOPORT, fdc->rid_ioport,
- fdc->res_ioport);
- fdc->rid_ioport++;
- goto again_ioport;
- }
- fdc->portt = rman_get_bustag(fdc->res_ioport);
- fdc->porth = rman_get_bushandle(fdc->res_ioport);
-
- /*
- * Handle cases 4-8 above
- */
- fdc->port_off = -(fdc->porth & 0x7);
-
- /*
- * Deal with case 6-9: FDSTS and FDDATA.
- */
- if ((rman_get_end(fdc->res_ioport) & 0x7) == 3) {
- fdc->rid_sts = fdc->rid_ioport + 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);
+ rid = 0;
+ for (i = 0; i < FDC_MAXREG; i++)
+ fdc->resio[i] = NULL;
+
+ for (rid = 0; ; rid++) {
+ newrid = rid;
+ res = bus_alloc_resource(dev, SYS_RES_IOPORT,
+ &newrid, 0ul, ~0ul, nports, RF_ACTIVE);
+ if (res == NULL)
+ break;
+ i = rman_get_start(res);
+ for (j = 0; j < rman_get_size(res); j++) {
+ fdc->resio[i + j] = res;
+ fdc->ridio[i + j] = newrid;
+ fdc->ioff[i + j] = j;
+ fdc->ioh[i + j] = rman_get_bushandle(res);
}
- fdc->sts_off = -4;
- fdc->stst = rman_get_bustag(fdc->res_sts);
- fdc->stsh = rman_get_bushandle(fdc->res_sts);
- } else {
- fdc->res_sts = NULL;
- fdc->sts_off = fdc->port_off;
- fdc->stst = fdc->portt;
- fdc->stsh = fdc->porth;
}
-
- /*
- * allocate the control port. For cases 1, 2, 5 and 7, we
- * fake it from the ioports resource. XXX IS THIS THE RIGHT THING
- * TO DO, OR SHOULD WE CREATE A NEW RID? (I think we need a new rid)
- */
- fdc->rid_ctl = fdc->rid_sts + 1;
- fdc->res_ctl = bus_alloc_resource_any(dev, SYS_RES_IOPORT,
- &fdc->rid_ctl, RF_ACTIVE);
- if (fdc->res_ctl == NULL) {
- fdc->ctl_off = 7 + fdc->port_off;
- fdc->res_ctl = NULL;
- fdc->ctlt = fdc->portt;
- fdc->ctlh = fdc->porth;
- } else {
- fdc->ctl_off = 0;
- fdc->ctlt = rman_get_bustag(fdc->res_ctl);
- fdc->ctlh = rman_get_bushandle(fdc->res_ctl);
+ if (fdc->resio[2] == NULL)
+ return (ENXIO);
+ fdc->iot = rman_get_bustag(fdc->resio[2]);
+ if (fdc->resio[7] == NULL) {
+ /* XXX allocate */
+ fdc->resio[7] = fdc->resio[2];
+ fdc->ridio[7] = fdc->ridio[2];
+ fdc->ioff[7] = fdc->ioff[2] + 5;
+ fdc->ioh[7] = fdc->ioh[2];
}
fdc->res_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &fdc->rid_irq,
RF_ACTIVE | RF_SHAREABLE);
- if (fdc->res_irq == 0) {
+ if (fdc->res_irq == NULL) {
device_printf(dev, "cannot reserve interrupt line\n");
return (ENXIO);
}
@@ -164,7 +121,7 @@ again_ioport:
if ((fdc->flags & FDC_NODMA) == 0) {
fdc->res_drq = bus_alloc_resource_any(dev, SYS_RES_DRQ,
&fdc->rid_drq, RF_ACTIVE | RF_SHAREABLE);
- if (fdc->res_drq == 0) {
+ if (fdc->res_drq == NULL) {
device_printf(dev, "cannot reserve DMA request line\n");
/* This is broken and doesn't work for ISA case */
fdc->flags |= FDC_NODMA;
diff --git a/sys/dev/fdc/fdc_pccard.c b/sys/dev/fdc/fdc_pccard.c
index baa0d013cacd..f7b05f80e419 100644
--- a/sys/dev/fdc/fdc_pccard.c
+++ b/sys/dev/fdc/fdc_pccard.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 2004 M. Warner Losh.
+ * Copyright (c) 2004-2005 M. Warner Losh.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -54,21 +54,23 @@ static const struct pccard_product fdc_pccard_products[] = {
static int
fdc_pccard_alloc_resources(device_t dev, struct fdc_data *fdc)
{
- fdc->rid_ioport = 0;
- fdc->res_ioport = bus_alloc_resource(dev, SYS_RES_IOPORT,
- &fdc->rid_ioport, 0ul, ~0ul, 1, RF_ACTIVE);
- if (fdc->res_ioport == NULL) {
+ struct resource *res;
+ int rid, i;
+
+ rid = 0;
+ res = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, 0ul, ~0ul, 1,
+ RF_ACTIVE);
+ if (res == NULL) {
device_printf(dev, "cannot alloc I/O port range\n");
return (ENXIO);
}
- 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;
+ for (i = 0; i < FDC_MAXREG; i++) {
+ fdc->resio[i] = res;
+ fdc->ridio[i] = rid;
+ fdc->ioff[i] = i;
+ fdc->ioh[i] = rman_get_bushandle(res);
+ }
+ fdc->iot = rman_get_bustag(res);
fdc->rid_irq = 0;
fdc->res_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &fdc->rid_irq,
@@ -101,7 +103,7 @@ fdc_pccard_attach(device_t dev)
device_t child;
fdc = device_get_softc(dev);
- fdc->flags = FDC_NODMA;
+ fdc->flags = FDC_NODMA | FDC_NOFAST;
fdc->fdct = FDC_NE765;
error = fdc_pccard_alloc_resources(dev, fdc);
if (error == 0)
diff --git a/sys/dev/fdc/fdcvar.h b/sys/dev/fdc/fdcvar.h
index 42ed32dcf271..5ab60a6a6443 100644
--- a/sys/dev/fdc/fdcvar.h
+++ b/sys/dev/fdc/fdcvar.h
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 2004 M. Warner Losh.
+ * Copyright (c) 2004-2005 M. Warner Losh.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -43,7 +43,8 @@ struct fdc_data {
#define FDC_STAT_VALID 0x08
#define FDC_HAS_FIFO 0x10
#define FDC_NEEDS_RESET 0x20
-#define FDC_NODMA 0x40
+#define FDC_NODMA 0x40 /* Don't do DMA */
+#define FDC_NOFAST 0x80 /* Don't register isr as a fast one */
#define FDC_KTHREAD_EXIT 0x1000 /* request worker thread to stop */
#define FDC_KTHREAD_ALIVE 0x2000 /* worker thread is alive */
struct fd_data *fd; /* The active drive */
@@ -54,17 +55,14 @@ struct fdc_data {
int fdc_errs; /* number of logged errors */
struct bio_queue_head head;
struct bio *bp; /* active buffer */
- 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;
+ struct resource *res_irq, *res_drq;
+ int rid_irq, rid_drq;
+#define FDC_MAXREG 8
+ int ridio[FDC_MAXREG];
+ struct resource *resio[FDC_MAXREG];
+ bus_space_tag_t iot;
+ bus_space_handle_t ioh[FDC_MAXREG];
+ int ioff[FDC_MAXREG];
void *fdc_intr;
struct device *fdc_dev;
struct mtx fdc_mtx;