Move the fdc_alloc_resources function into the bus front end.

This commit is contained in:
Yoshihiro Takahashi 2004-07-15 15:00:02 +00:00
parent 386ecc28e7
commit dc6ea865f7
4 changed files with 166 additions and 412 deletions

View File

@ -259,10 +259,6 @@ struct fd_data {
#endif
};
#ifdef PC98
static bus_addr_t fdc_iat[] = {0, 2, 4};
#endif
struct fdc_ivars {
int fdunit;
int fdtype;
@ -759,199 +755,6 @@ static void pc98_fd_check_type(struct fd_data *fd)
}
#endif /* PC98 */
int
fdc_alloc_resources(struct fdc_data *fdc)
{
device_t dev;
#ifdef PC98
int rid;
#else
int ispnp, ispcmcia, nports;
#endif
dev = fdc->fdc_dev;
#ifndef PC98
ispnp = (fdc->flags & FDC_ISPNP) != 0;
ispcmcia = (fdc->flags & FDC_ISPCMCIA) != 0;
#endif
fdc->rid_ioport = fdc->rid_irq = fdc->rid_drq = 0;
fdc->res_ioport = fdc->res_irq = fdc->res_drq = 0;
#ifndef PC98
fdc->rid_ctl = 1;
#endif
#ifdef PC98
fdc->res_ioport = isa_alloc_resourcev(dev, SYS_RES_IOPORT,
&fdc->rid_ioport, fdc_iat,
3, RF_ACTIVE);
if (fdc->res_ioport == 0) {
device_printf(dev, "cannot reserve I/O port range\n");
return ENXIO;
}
isa_load_resourcev(fdc->res_ioport, fdc_iat, 3);
#else
/*
* 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.
*
* Isn't PC hardware wonderful.
*
* The Y-E Data PCMCIA FDC doesn't have this problem, it
* uses the register with offset 6 for pseudo-DMA, and the
* 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);
if (fdc->res_ioport == 0) {
device_printf(dev, "cannot reserve I/O port range (%d ports)\n",
nports);
return ENXIO;
}
#endif
fdc->portt = rman_get_bustag(fdc->res_ioport);
fdc->porth = rman_get_bushandle(fdc->res_ioport);
#ifdef PC98
rid = 3;
bus_set_resource(dev, SYS_RES_IOPORT, rid, IO_FDPORT, 1);
fdc->res_fdsio = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &rid,
RF_ACTIVE);
if (fdc->res_fdsio == 0)
return ENXIO;
fdc->sc_fdsiot = rman_get_bustag(fdc->res_fdsio);
fdc->sc_fdsioh = rman_get_bushandle(fdc->res_fdsio);
rid = 4;
bus_set_resource(dev, SYS_RES_IOPORT, rid, 0x4be, 1);
fdc->res_fdemsio = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &rid,
RF_ACTIVE);
if (fdc->res_fdemsio == 0)
return ENXIO;
fdc->sc_fdemsiot = rman_get_bustag(fdc->res_fdemsio);
fdc->sc_fdemsioh = rman_get_bushandle(fdc->res_fdemsio);
#endif
#ifndef PC98
if (!ispcmcia) {
/*
* 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.
*/
if (bus_get_resource_count(dev, SYS_RES_IOPORT, 0) == 4)
fdc->port_off = -2;
/*
* 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.
*/
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);
}
/*
* Now (finally!) allocate the control port.
*/
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;
}
fdc->ctlt = rman_get_bustag(fdc->res_ctl);
fdc->ctlh = rman_get_bushandle(fdc->res_ctl);
}
#endif
#ifdef PC98
fdc->res_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &fdc->rid_irq,
RF_ACTIVE);
#else
fdc->res_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &fdc->rid_irq,
RF_ACTIVE | RF_SHAREABLE);
#endif
if (fdc->res_irq == 0) {
device_printf(dev, "cannot reserve interrupt line\n");
return ENXIO;
}
if ((fdc->flags & FDC_NODMA) == 0) {
#ifdef PC98
fdc->res_drq = bus_alloc_resource_any(dev, SYS_RES_DRQ,
&fdc->rid_drq, RF_ACTIVE);
if (fdc->res_drq == 0) {
device_printf(dev, "cannot reserve DMA request line\n");
return ENXIO;
}
fdc->dmachan = rman_get_start(fdc->res_drq);
#else
fdc->res_drq = bus_alloc_resource_any(dev, SYS_RES_DRQ,
&fdc->rid_drq, RF_ACTIVE | RF_SHAREABLE);
if (fdc->res_drq == 0) {
device_printf(dev, "cannot reserve DMA request line\n");
fdc->flags |= FDC_NODMA;
} else
fdc->dmachan = rman_get_start(fdc->res_drq);
#endif
}
return 0;
}
void
fdc_release_resources(struct fdc_data *fdc)
{
@ -1126,15 +929,10 @@ fdc_attach(device_t dev)
{
struct fdc_data *fdc;
const char *name, *dname;
int i, error, dunit;
int i, dunit, error;
fdc = device_get_softc(dev);
fdc->fdc_dev = dev;
error = fdc_alloc_resources(fdc);
if (error) {
device_printf(dev, "cannot re-acquire resources\n");
return error;
}
error = BUS_SETUP_INTR(device_get_parent(dev), dev, fdc->res_irq,
INTR_TYPE_BIO | INTR_ENTROPY, fdc_intr, fdc,
&fdc->fdc_intr);

View File

@ -45,6 +45,69 @@ __FBSDID("$FreeBSD$");
#include <isa/isavar.h>
#include <pc98/pc98/pc98.h>
static bus_addr_t fdc_iat[] = {0, 2, 4};
static int
fdc_cbus_alloc_resources(device_t dev, struct fdc_data *fdc)
{
int rid;
fdc->fdc_dev = dev;
fdc->rid_ioport = 0;
fdc->rid_irq = 0;
fdc->rid_drq = 0;
fdc->res_irq = 0;
fdc->res_drq = 0;
fdc->res_ioport = isa_alloc_resourcev(dev, SYS_RES_IOPORT,
&fdc->rid_ioport, fdc_iat,
3, RF_ACTIVE);
if (fdc->res_ioport == 0) {
device_printf(dev, "cannot reserve I/O port range\n");
return ENXIO;
}
isa_load_resourcev(fdc->res_ioport, fdc_iat, 3);
fdc->portt = rman_get_bustag(fdc->res_ioport);
fdc->porth = rman_get_bushandle(fdc->res_ioport);
rid = 3;
bus_set_resource(dev, SYS_RES_IOPORT, rid, IO_FDPORT, 1);
fdc->res_fdsio = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &rid,
RF_ACTIVE);
if (fdc->res_fdsio == 0)
return ENXIO;
fdc->sc_fdsiot = rman_get_bustag(fdc->res_fdsio);
fdc->sc_fdsioh = rman_get_bushandle(fdc->res_fdsio);
rid = 4;
bus_set_resource(dev, SYS_RES_IOPORT, rid, 0x4be, 1);
fdc->res_fdemsio = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &rid,
RF_ACTIVE);
if (fdc->res_fdemsio == 0)
return ENXIO;
fdc->sc_fdemsiot = rman_get_bustag(fdc->res_fdemsio);
fdc->sc_fdemsioh = rman_get_bushandle(fdc->res_fdemsio);
fdc->res_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &fdc->rid_irq,
RF_ACTIVE);
if (fdc->res_irq == 0) {
device_printf(dev, "cannot reserve interrupt line\n");
return ENXIO;
}
if ((fdc->flags & FDC_NODMA) == 0) {
fdc->res_drq = bus_alloc_resource_any(dev, SYS_RES_DRQ,
&fdc->rid_drq, RF_ACTIVE);
if (fdc->res_drq == 0) {
device_printf(dev, "cannot reserve DMA request line\n");
return ENXIO;
}
fdc->dmachan = rman_get_start(fdc->res_drq);
}
return 0;
}
static int
fdc_cbus_probe(device_t dev)
{
@ -52,14 +115,13 @@ fdc_cbus_probe(device_t dev)
struct fdc_data *fdc;
fdc = device_get_softc(dev);
fdc->fdc_dev = dev;
/* Check pnp ids */
if (isa_get_vendorid(dev))
return (ENXIO);
/* Attempt to allocate our resources for the duration of the probe */
error = fdc_alloc_resources(fdc);
error = fdc_cbus_alloc_resources(dev, fdc);
if (!error)
error = fdc_initial_reset(fdc);
@ -67,10 +129,27 @@ fdc_cbus_probe(device_t dev)
return (error);
}
static int
fdc_cbus_attach(device_t dev)
{
int error;
struct fdc_data *fdc;
fdc = device_get_softc(dev);
if ((error = fdc_cbus_alloc_resources(dev, fdc)) != 0 ||
(error = fdc_attach(dev)) != 0) {
fdc_release_resources(fdc);
return (error);
}
return (0);
}
static device_method_t fdc_methods[] = {
/* Device interface */
DEVMETHOD(device_probe, fdc_cbus_probe),
DEVMETHOD(device_attach, fdc_attach),
DEVMETHOD(device_attach, fdc_cbus_attach),
DEVMETHOD(device_detach, fdc_detach),
DEVMETHOD(device_shutdown, bus_generic_shutdown),
DEVMETHOD(device_suspend, bus_generic_suspend),

View File

@ -259,10 +259,6 @@ struct fd_data {
#endif
};
#ifdef PC98
static bus_addr_t fdc_iat[] = {0, 2, 4};
#endif
struct fdc_ivars {
int fdunit;
int fdtype;
@ -759,199 +755,6 @@ static void pc98_fd_check_type(struct fd_data *fd)
}
#endif /* PC98 */
int
fdc_alloc_resources(struct fdc_data *fdc)
{
device_t dev;
#ifdef PC98
int rid;
#else
int ispnp, ispcmcia, nports;
#endif
dev = fdc->fdc_dev;
#ifndef PC98
ispnp = (fdc->flags & FDC_ISPNP) != 0;
ispcmcia = (fdc->flags & FDC_ISPCMCIA) != 0;
#endif
fdc->rid_ioport = fdc->rid_irq = fdc->rid_drq = 0;
fdc->res_ioport = fdc->res_irq = fdc->res_drq = 0;
#ifndef PC98
fdc->rid_ctl = 1;
#endif
#ifdef PC98
fdc->res_ioport = isa_alloc_resourcev(dev, SYS_RES_IOPORT,
&fdc->rid_ioport, fdc_iat,
3, RF_ACTIVE);
if (fdc->res_ioport == 0) {
device_printf(dev, "cannot reserve I/O port range\n");
return ENXIO;
}
isa_load_resourcev(fdc->res_ioport, fdc_iat, 3);
#else
/*
* 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.
*
* Isn't PC hardware wonderful.
*
* The Y-E Data PCMCIA FDC doesn't have this problem, it
* uses the register with offset 6 for pseudo-DMA, and the
* 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);
if (fdc->res_ioport == 0) {
device_printf(dev, "cannot reserve I/O port range (%d ports)\n",
nports);
return ENXIO;
}
#endif
fdc->portt = rman_get_bustag(fdc->res_ioport);
fdc->porth = rman_get_bushandle(fdc->res_ioport);
#ifdef PC98
rid = 3;
bus_set_resource(dev, SYS_RES_IOPORT, rid, IO_FDPORT, 1);
fdc->res_fdsio = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &rid,
RF_ACTIVE);
if (fdc->res_fdsio == 0)
return ENXIO;
fdc->sc_fdsiot = rman_get_bustag(fdc->res_fdsio);
fdc->sc_fdsioh = rman_get_bushandle(fdc->res_fdsio);
rid = 4;
bus_set_resource(dev, SYS_RES_IOPORT, rid, 0x4be, 1);
fdc->res_fdemsio = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &rid,
RF_ACTIVE);
if (fdc->res_fdemsio == 0)
return ENXIO;
fdc->sc_fdemsiot = rman_get_bustag(fdc->res_fdemsio);
fdc->sc_fdemsioh = rman_get_bushandle(fdc->res_fdemsio);
#endif
#ifndef PC98
if (!ispcmcia) {
/*
* 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.
*/
if (bus_get_resource_count(dev, SYS_RES_IOPORT, 0) == 4)
fdc->port_off = -2;
/*
* 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.
*/
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);
}
/*
* Now (finally!) allocate the control port.
*/
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;
}
fdc->ctlt = rman_get_bustag(fdc->res_ctl);
fdc->ctlh = rman_get_bushandle(fdc->res_ctl);
}
#endif
#ifdef PC98
fdc->res_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &fdc->rid_irq,
RF_ACTIVE);
#else
fdc->res_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &fdc->rid_irq,
RF_ACTIVE | RF_SHAREABLE);
#endif
if (fdc->res_irq == 0) {
device_printf(dev, "cannot reserve interrupt line\n");
return ENXIO;
}
if ((fdc->flags & FDC_NODMA) == 0) {
#ifdef PC98
fdc->res_drq = bus_alloc_resource_any(dev, SYS_RES_DRQ,
&fdc->rid_drq, RF_ACTIVE);
if (fdc->res_drq == 0) {
device_printf(dev, "cannot reserve DMA request line\n");
return ENXIO;
}
fdc->dmachan = rman_get_start(fdc->res_drq);
#else
fdc->res_drq = bus_alloc_resource_any(dev, SYS_RES_DRQ,
&fdc->rid_drq, RF_ACTIVE | RF_SHAREABLE);
if (fdc->res_drq == 0) {
device_printf(dev, "cannot reserve DMA request line\n");
fdc->flags |= FDC_NODMA;
} else
fdc->dmachan = rman_get_start(fdc->res_drq);
#endif
}
return 0;
}
void
fdc_release_resources(struct fdc_data *fdc)
{
@ -1126,15 +929,10 @@ fdc_attach(device_t dev)
{
struct fdc_data *fdc;
const char *name, *dname;
int i, error, dunit;
int i, dunit, error;
fdc = device_get_softc(dev);
fdc->fdc_dev = dev;
error = fdc_alloc_resources(fdc);
if (error) {
device_printf(dev, "cannot re-acquire resources\n");
return error;
}
error = BUS_SETUP_INTR(device_get_parent(dev), dev, fdc->res_irq,
INTR_TYPE_BIO | INTR_ENTROPY, fdc_intr, fdc,
&fdc->fdc_intr);

View File

@ -45,6 +45,69 @@ __FBSDID("$FreeBSD$");
#include <isa/isavar.h>
#include <pc98/pc98/pc98.h>
static bus_addr_t fdc_iat[] = {0, 2, 4};
static int
fdc_cbus_alloc_resources(device_t dev, struct fdc_data *fdc)
{
int rid;
fdc->fdc_dev = dev;
fdc->rid_ioport = 0;
fdc->rid_irq = 0;
fdc->rid_drq = 0;
fdc->res_irq = 0;
fdc->res_drq = 0;
fdc->res_ioport = isa_alloc_resourcev(dev, SYS_RES_IOPORT,
&fdc->rid_ioport, fdc_iat,
3, RF_ACTIVE);
if (fdc->res_ioport == 0) {
device_printf(dev, "cannot reserve I/O port range\n");
return ENXIO;
}
isa_load_resourcev(fdc->res_ioport, fdc_iat, 3);
fdc->portt = rman_get_bustag(fdc->res_ioport);
fdc->porth = rman_get_bushandle(fdc->res_ioport);
rid = 3;
bus_set_resource(dev, SYS_RES_IOPORT, rid, IO_FDPORT, 1);
fdc->res_fdsio = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &rid,
RF_ACTIVE);
if (fdc->res_fdsio == 0)
return ENXIO;
fdc->sc_fdsiot = rman_get_bustag(fdc->res_fdsio);
fdc->sc_fdsioh = rman_get_bushandle(fdc->res_fdsio);
rid = 4;
bus_set_resource(dev, SYS_RES_IOPORT, rid, 0x4be, 1);
fdc->res_fdemsio = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &rid,
RF_ACTIVE);
if (fdc->res_fdemsio == 0)
return ENXIO;
fdc->sc_fdemsiot = rman_get_bustag(fdc->res_fdemsio);
fdc->sc_fdemsioh = rman_get_bushandle(fdc->res_fdemsio);
fdc->res_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &fdc->rid_irq,
RF_ACTIVE);
if (fdc->res_irq == 0) {
device_printf(dev, "cannot reserve interrupt line\n");
return ENXIO;
}
if ((fdc->flags & FDC_NODMA) == 0) {
fdc->res_drq = bus_alloc_resource_any(dev, SYS_RES_DRQ,
&fdc->rid_drq, RF_ACTIVE);
if (fdc->res_drq == 0) {
device_printf(dev, "cannot reserve DMA request line\n");
return ENXIO;
}
fdc->dmachan = rman_get_start(fdc->res_drq);
}
return 0;
}
static int
fdc_cbus_probe(device_t dev)
{
@ -52,14 +115,13 @@ fdc_cbus_probe(device_t dev)
struct fdc_data *fdc;
fdc = device_get_softc(dev);
fdc->fdc_dev = dev;
/* Check pnp ids */
if (isa_get_vendorid(dev))
return (ENXIO);
/* Attempt to allocate our resources for the duration of the probe */
error = fdc_alloc_resources(fdc);
error = fdc_cbus_alloc_resources(dev, fdc);
if (!error)
error = fdc_initial_reset(fdc);
@ -67,10 +129,27 @@ fdc_cbus_probe(device_t dev)
return (error);
}
static int
fdc_cbus_attach(device_t dev)
{
int error;
struct fdc_data *fdc;
fdc = device_get_softc(dev);
if ((error = fdc_cbus_alloc_resources(dev, fdc)) != 0 ||
(error = fdc_attach(dev)) != 0) {
fdc_release_resources(fdc);
return (error);
}
return (0);
}
static device_method_t fdc_methods[] = {
/* Device interface */
DEVMETHOD(device_probe, fdc_cbus_probe),
DEVMETHOD(device_attach, fdc_attach),
DEVMETHOD(device_attach, fdc_cbus_attach),
DEVMETHOD(device_detach, fdc_detach),
DEVMETHOD(device_shutdown, bus_generic_shutdown),
DEVMETHOD(device_suspend, bus_generic_suspend),