From b4046cd7219338692d9226317f2e006bb075dfe2 Mon Sep 17 00:00:00 2001 From: Warner Losh Date: Tue, 14 Sep 2004 07:06:49 +0000 Subject: [PATCH] Checkpoint the fdc resource changes: o Allow for up to 3 resource I/O ranges to be given for the floppy controller, rather than just two that are allowed for now. o Make sure that we can work with either a base address of 0x3f0 or 0x3f2. o Create new inline functions to access the YE DATA's unique BDCR register. o Update pccard attachment to add the fd device. o Do some minor style(9) polishing. # I'm guessing that the fdc pccard attachment broke some time ago, since # there are a number of issues with it still. --- sys/dev/fdc/fdc.c | 93 +++++++++++++++-------------- sys/dev/fdc/fdc_isa.c | 126 ++++++++++++++++++--------------------- sys/dev/fdc/fdc_pccard.c | 14 +++-- sys/dev/fdc/fdcvar.h | 9 ++- 4 files changed, 121 insertions(+), 121 deletions(-) diff --git a/sys/dev/fdc/fdc.c b/sys/dev/fdc/fdc.c index 47f6fa1b6f87..940117fb90d5 100644 --- a/sys/dev/fdc/fdc.c +++ b/sys/dev/fdc/fdc.c @@ -197,9 +197,18 @@ static struct fd_type *fd_native_types[] = { #define FDCTL 7 /* Control Register (W) */ /* - * this is the secret PIO data port (offset from base) + * 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. + * + * 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). */ -#define FDC_YE_DATAPORT 6 +#define FDBCDR 0 /* And 1 */ +#define FD_YE_DATAPORT 6 /* Drive Data port */ #define FDI_DCHG 0x80 /* diskette has been changed */ /* requires drive and motor being selected */ @@ -337,6 +346,19 @@ fdin_rd(struct fdc_data *fdc) return bus_space_read_1(fdc->ctlt, fdc->ctlh, fdc->ctl_off); } +/* + * Magic pseudo-DMA initialization for YE FDC. Sets count and + * direction. + */ +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))); +} + static int fdc_err(struct fdc_data *fdc, const char *s) { @@ -633,18 +655,6 @@ fdc_intr(void *arg) wakeup(arg); } -/* - * Magic pseudo-DMA initialization for YE FDC. Sets count and - * direction. - */ -#define SET_BCDR(fdc,wr,cnt,port) \ - do { \ - bus_space_write_1(fdc->portt, fdc->porth, fdc->port_off + port, \ - ((cnt)-1) & 0xff); \ - bus_space_write_1(fdc->portt, fdc->porth, fdc->port_off + port + 1, \ - ((wr ? 0x80 : 0) | ((((cnt)-1) >> 8) & 0x7f))); \ - } while (0) - /* * fdc_pio(): perform programmed IO read/write for YE PCMCIA floppy. */ @@ -660,13 +670,13 @@ fdc_pio(struct fdc_data *fdc) count = fdc->fd->fd_iosize; if (bp->bio_cmd == BIO_READ) { - SET_BCDR(fdc, 0, count, 0); + fdbcdr_wr(fdc, 0, count); bus_space_read_multi_1(fdc->portt, fdc->porth, fdc->port_off + - FDC_YE_DATAPORT, cptr, count); + FD_YE_DATAPORT, cptr, count); } else { bus_space_write_multi_1(fdc->portt, fdc->porth, fdc->port_off + - FDC_YE_DATAPORT, cptr, count); - SET_BCDR(fdc, 0, count, 0); + FD_YE_DATAPORT, cptr, count); + fdbcdr_wr(fdc, 0, count); /* needed? */ } } @@ -940,7 +950,7 @@ fdc_worker(struct fdc_data *fdc) /* Do PIO if we have to */ if (fdc->flags & FDC_NODMA) { if (bp->bio_cmd & (BIO_READ|BIO_WRITE|BIO_FMT)) - SET_BCDR(fdc, 1, fd->fd_iosize, 0); + fdbcdr_wr(fdc, 1, fd->fd_iosize); if (bp->bio_cmd & (BIO_WRITE|BIO_FMT)) fdc_pio(fdc); } @@ -1484,39 +1494,30 @@ fdc_release_resources(struct fdc_data *fdc) 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) 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) + 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 diff --git a/sys/dev/fdc/fdc_isa.c b/sys/dev/fdc/fdc_isa.c index 90b47e4f29f5..1d04a8108f0e 100644 --- a/sys/dev/fdc/fdc_isa.c +++ b/sys/dev/fdc/fdc_isa.c @@ -57,9 +57,8 @@ static struct isa_pnp_id fdc_ids[] = { 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,89 @@ fdc_isa_alloc_resources(device_t dev, struct fdc_data *fdc) /* * 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; + 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; } /* - * Now (finally!) allocate the control port. + * 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->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; + 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); } - 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 +158,13 @@ fdc_isa_alloc_resources(device_t dev, struct fdc_data *fdc) &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 diff --git a/sys/dev/fdc/fdc_pccard.c b/sys/dev/fdc/fdc_pccard.c index c54d35a6c57f..1f143c75b0cc 100644 --- a/sys/dev/fdc/fdc_pccard.c +++ b/sys/dev/fdc/fdc_pccard.c @@ -65,6 +65,9 @@ fdc_pccard_alloc_resources(device_t dev, struct fdc_data *fdc) } 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; @@ -86,8 +89,7 @@ fdc_pccard_probe(device_t dev) if ((pp = pccard_product_lookup(dev, fdc_pccard_products, sizeof(fdc_pccard_products[0]), NULL)) != NULL) { - if (pp->pp_name != NULL) - device_set_desc(dev, pp->pp_name); + device_set_desc(dev, "PC Card Floppy"); return (0); } return (ENXIO); @@ -98,8 +100,7 @@ fdc_pccard_attach(device_t dev) { int error; struct fdc_data *fdc; - - return ENXIO; + device_t child; fdc = device_get_softc(dev); fdc->flags = FDC_NODMA; @@ -107,6 +108,11 @@ fdc_pccard_attach(device_t dev) error = fdc_pccard_alloc_resources(dev, fdc); if (error == 0) error = fdc_attach(dev); + if (error == 0) { + child = fdc_add_child(dev, "fd", -1); + device_set_flags(child, 0x24); + error = bus_generic_attach(dev); + } if (error) fdc_release_resources(fdc); return (error); diff --git a/sys/dev/fdc/fdcvar.h b/sys/dev/fdc/fdcvar.h index 22a4edda5cab..5cfc3d1a6284 100644 --- a/sys/dev/fdc/fdcvar.h +++ b/sys/dev/fdc/fdcvar.h @@ -57,14 +57,17 @@ 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_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;