The Z8530 on the MacIO has an interrupt per channel. Deal with this

by having interrupt resource variables per channel. We don't set up
different interrupt handlers per channel, though.
This commit is contained in:
Marcel Moolenaar 2006-04-04 17:33:08 +00:00
parent e57af79821
commit 9cd8d259f0
2 changed files with 57 additions and 32 deletions

View File

@ -85,6 +85,10 @@ struct scc_chan {
struct resource ch_rres;
struct resource_list ch_rlist;
struct resource *ch_ires; /* Interrupt resource. */
void *ch_icookie;
int ch_irid;
struct scc_mode ch_mode[SCC_NMODES];
u_int ch_nr;
@ -119,9 +123,6 @@ struct scc_softc {
struct resource *sc_rres; /* Register resource. */
int sc_rrid;
int sc_rtype; /* SYS_RES_{IOPORT|MEMORY}. */
struct resource *sc_ires; /* Interrupt resource. */
void *sc_icookie;
int sc_irid;
struct scc_chan *sc_chan;

View File

@ -134,17 +134,24 @@ scc_bfe_attach(device_t dev)
sc->sc_bas.bsh = rman_get_bushandle(sc->sc_rres);
sc->sc_bas.bst = rman_get_bustag(sc->sc_rres);
sc->sc_irid = 0;
sc->sc_ires = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->sc_irid,
RF_ACTIVE | RF_SHAREABLE);
/*
* Allocate interrupt resources. There may be a different interrupt
* per channel. We allocate them all...
*/
sc->sc_chan = malloc(sizeof(struct scc_chan) * cl->cl_channels,
M_SCC, M_WAITOK | M_ZERO);
for (c = 0; c < cl->cl_channels; c++) {
ch = &sc->sc_chan[c];
ch->ch_irid = c;
ch->ch_ires = bus_alloc_resource_any(dev, SYS_RES_IRQ,
&ch->ch_irid, RF_ACTIVE | RF_SHAREABLE);
}
/*
* Create the control structures for our children. Probe devices
* and query them to see if we can reset the hardware.
*/
sysdev = 0;
sc->sc_chan = malloc(sizeof(struct scc_chan) * cl->cl_channels,
M_SCC, M_WAITOK | M_ZERO);
base = rman_get_start(sc->sc_rres);
start = base + ((cl->cl_range < 0) ? size * (cl->cl_channels - 1) : 0);
for (c = 0; c < cl->cl_channels; c++) {
@ -163,7 +170,8 @@ scc_bfe_attach(device_t dev)
resource_list_add(&ch->ch_rlist, SYS_RES_IRQ, 0, c, c, 1);
rle = resource_list_find(&ch->ch_rlist, SYS_RES_IRQ, 0);
rle->res = sc->sc_ires;
rle->res = (ch->ch_ires != NULL) ? ch->ch_ires :
sc->sc_chan[0].ch_ires;
for (mode = 0; mode < SCC_NMODES; mode++) {
m = &ch->ch_mode[mode];
@ -204,27 +212,31 @@ scc_bfe_attach(device_t dev)
* Of course, if we can't setup a fast handler, we make it MPSAFE
* right away.
*/
if (sc->sc_ires != NULL) {
error = bus_setup_intr(dev, sc->sc_ires,
for (c = 0; c < cl->cl_channels; c++) {
ch = &sc->sc_chan[c];
if (ch->ch_ires == NULL)
continue;
error = bus_setup_intr(dev, ch->ch_ires,
INTR_TYPE_TTY | INTR_FAST, scc_bfe_intr, sc,
&sc->sc_icookie);
&ch->ch_icookie);
if (error) {
error = bus_setup_intr(dev, sc->sc_ires,
error = bus_setup_intr(dev, ch->ch_ires,
INTR_TYPE_TTY | INTR_MPSAFE, scc_bfe_intr, sc,
&sc->sc_icookie);
&ch->ch_icookie);
} else
sc->sc_fastintr = 1;
if (error) {
device_printf(dev, "could not activate interrupt\n");
bus_release_resource(dev, SYS_RES_IRQ, sc->sc_irid,
sc->sc_ires);
sc->sc_ires = NULL;
bus_release_resource(dev, SYS_RES_IRQ, ch->ch_irid,
ch->ch_ires);
ch->ch_ires = NULL;
}
}
if (sc->sc_ires == NULL) {
/* XXX no interrupt resource. Force polled mode. */
sc->sc_polled = 1;
sc->sc_polled = 1;
for (c = 0; c < cl->cl_channels; c++) {
if (sc->sc_chan[0].ch_ires != NULL)
sc->sc_polled = 0;
}
/*
@ -260,10 +272,12 @@ scc_bfe_attach(device_t dev)
return (0);
fail:
if (sc->sc_ires != NULL) {
bus_teardown_intr(dev, sc->sc_ires, sc->sc_icookie);
bus_release_resource(dev, SYS_RES_IRQ, sc->sc_irid,
sc->sc_ires);
for (c = 0; c < cl->cl_channels; c++) {
ch = &sc->sc_chan[c];
if (ch->ch_ires == NULL)
continue;
bus_release_resource(dev, SYS_RES_IRQ, ch->ch_irid,
ch->ch_ires);
}
bus_release_resource(dev, sc->sc_rtype, sc->sc_rrid, sc->sc_rres);
return (error);
@ -299,10 +313,13 @@ scc_bfe_detach(device_t dev)
if (error)
return (error);
if (sc->sc_ires != NULL) {
bus_teardown_intr(dev, sc->sc_ires, sc->sc_icookie);
bus_release_resource(dev, SYS_RES_IRQ, sc->sc_irid,
sc->sc_ires);
for (chan = 0; chan < cl->cl_channels; chan++) {
ch = &sc->sc_chan[chan];
if (ch->ch_ires == NULL)
continue;
bus_teardown_intr(dev, ch->ch_ires, ch->ch_icookie);
bus_release_resource(dev, SYS_RES_IRQ, ch->ch_irid,
ch->ch_ires);
}
bus_release_resource(dev, sc->sc_rtype, sc->sc_rrid, sc->sc_rres);
@ -480,9 +497,10 @@ int
scc_bus_setup_intr(device_t dev, device_t child, struct resource *r, int flags,
void (*ihand)(void *), void *arg, void **cookiep)
{
struct scc_chan *ch;
struct scc_mode *m;
struct scc_softc *sc;
int i, isrc;
int c, i, isrc;
if (device_get_parent(child) != dev)
return (EINVAL);
@ -497,9 +515,15 @@ scc_bus_setup_intr(device_t dev, device_t child, struct resource *r, int flags,
if (sc->sc_fastintr && !(flags & INTR_FAST)) {
sc->sc_fastintr = 0;
bus_teardown_intr(dev, sc->sc_ires, sc->sc_icookie);
bus_setup_intr(dev, sc->sc_ires, INTR_TYPE_TTY | INTR_MPSAFE,
scc_bfe_intr, sc, &sc->sc_icookie);
for (c = 0; c < sc->sc_class->cl_channels; c++) {
ch = &sc->sc_chan[c];
if (ch->ch_ires == NULL)
continue;
bus_teardown_intr(dev, ch->ch_ires, ch->ch_icookie);
bus_setup_intr(dev, ch->ch_ires,
INTR_TYPE_TTY | INTR_MPSAFE, scc_bfe_intr, sc,
&ch->ch_icookie);
}
}
m = device_get_ivars(child);