summaryrefslogtreecommitdiffstats
path: root/sys/dev/ppbus
diff options
context:
space:
mode:
authorjhb <jhb@FreeBSD.org>2008-01-10 23:43:47 +0000
committerjhb <jhb@FreeBSD.org>2008-01-10 23:43:47 +0000
commite6f3a3dd9a84c04b9db256e5e18ea41579e779d2 (patch)
treec7838dbd4142ca2d07f627aafe036d8eccf3d8fb /sys/dev/ppbus
parent3bcad4568ebd32003f346391dd549bc429018056 (diff)
downloadFreeBSD-src-e6f3a3dd9a84c04b9db256e5e18ea41579e779d2.zip
FreeBSD-src-e6f3a3dd9a84c04b9db256e5e18ea41579e779d2.tar.gz
Work around problems with the ppbus(4)'s interesting way of managing
interrupt handlers for child devices by adding a dummy handler that is always present so that the underlying interrupt thread is always around avoiding panics from stray interrupts. MFC after: 3 days
Diffstat (limited to 'sys/dev/ppbus')
-rw-r--r--sys/dev/ppbus/ppbconf.c37
-rw-r--r--sys/dev/ppbus/ppbconf.h3
2 files changed, 40 insertions, 0 deletions
diff --git a/sys/dev/ppbus/ppbconf.c b/sys/dev/ppbus/ppbconf.c
index cb5da93..2ad164c 100644
--- a/sys/dev/ppbus/ppbconf.c
+++ b/sys/dev/ppbus/ppbconf.c
@@ -36,6 +36,9 @@ __FBSDID("$FreeBSD$");
#include <sys/module.h>
#include <sys/bus.h>
#include <sys/malloc.h>
+#include <sys/rman.h>
+
+#include <machine/resource.h>
#include <dev/ppbus/ppbconf.h>
#include <dev/ppbus/ppb_1284.h>
@@ -380,9 +383,38 @@ end_scan:
#endif /* !DONTPROBE_1284 */
+static void
+ppbus_dummy_intr(void *arg)
+{
+}
+
static int
ppbus_attach(device_t dev)
{
+ struct ppb_data *ppb = (struct ppb_data *)device_get_softc(dev);
+ uintptr_t irq;
+ int error, rid;
+
+ /* Attach a dummy interrupt handler to suck up any stray interrupts. */
+ BUS_READ_IVAR(device_get_parent(dev), dev, PPC_IVAR_IRQ, &irq);
+
+ if (irq > 0) {
+ rid = 0;
+ ppb->irq_res = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, irq,
+ irq, 1, RF_SHAREABLE);
+ if (ppb->irq_res != NULL) {
+ error = bus_setup_intr(dev, ppb->irq_res,
+ INTR_TYPE_TTY | INTR_MPSAFE, NULL, ppbus_dummy_intr,
+ ppb, &ppb->intr_cookie);
+ if (error) {
+ device_printf(dev,
+ "failed to setup interrupt handler\n");
+ bus_release_resource(dev, SYS_RES_IRQ, 0,
+ ppb->irq_res);
+ return (error);
+ }
+ }
+ }
/* Locate our children */
bus_generic_probe(dev);
@@ -401,6 +433,7 @@ ppbus_attach(device_t dev)
static int
ppbus_detach(device_t dev)
{
+ struct ppb_data *ppb = (struct ppb_data *)device_get_softc(dev);
device_t *children;
int nchildren, i;
@@ -412,6 +445,10 @@ ppbus_detach(device_t dev)
free(children, M_TEMP);
}
+ if (ppb->irq_res != NULL) {
+ bus_teardown_intr(dev, ppb->irq_res, ppb->intr_cookie);
+ bus_release_resource(dev, SYS_RES_IRQ, 0, ppb->irq_res);
+ }
return (0);
}
diff --git a/sys/dev/ppbus/ppbconf.h b/sys/dev/ppbus/ppbconf.h
index eb1f64e..5f7a201 100644
--- a/sys/dev/ppbus/ppbconf.h
+++ b/sys/dev/ppbus/ppbconf.h
@@ -248,6 +248,9 @@ struct ppb_data {
* NIBBLE, PS2, EPP or ECP */
void *ppb_owner; /* device which owns the bus */
+
+ struct resource *irq_res;
+ void *intr_cookie;
};
#ifdef _KERNEL
OpenPOWER on IntegriCloud