summaryrefslogtreecommitdiffstats
path: root/sys/dev/scc
diff options
context:
space:
mode:
authormarcel <marcel@FreeBSD.org>2006-04-04 17:33:08 +0000
committermarcel <marcel@FreeBSD.org>2006-04-04 17:33:08 +0000
commitb5dd7f5b999f6ccf3785cf36f0a6edfa7029ccd9 (patch)
tree0d9a10f97611d8cf84c8215391b0da48103ed358 /sys/dev/scc
parentbdb7299c15a08759270d0478b7bc15587b9c9c75 (diff)
downloadFreeBSD-src-b5dd7f5b999f6ccf3785cf36f0a6edfa7029ccd9.zip
FreeBSD-src-b5dd7f5b999f6ccf3785cf36f0a6edfa7029ccd9.tar.gz
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.
Diffstat (limited to 'sys/dev/scc')
-rw-r--r--sys/dev/scc/scc_bfe.h7
-rw-r--r--sys/dev/scc/scc_core.c82
2 files changed, 57 insertions, 32 deletions
diff --git a/sys/dev/scc/scc_bfe.h b/sys/dev/scc/scc_bfe.h
index cb59422..0107eae 100644
--- a/sys/dev/scc/scc_bfe.h
+++ b/sys/dev/scc/scc_bfe.h
@@ -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;
diff --git a/sys/dev/scc/scc_core.c b/sys/dev/scc/scc_core.c
index 2cad7ea..c9cda51 100644
--- a/sys/dev/scc/scc_core.c
+++ b/sys/dev/scc/scc_core.c
@@ -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);
OpenPOWER on IntegriCloud