summaryrefslogtreecommitdiff
path: root/sys/arch/hppa/gsc/gsckbc.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/arch/hppa/gsc/gsckbc.c')
-rw-r--r--sys/arch/hppa/gsc/gsckbc.c62
1 files changed, 56 insertions, 6 deletions
diff --git a/sys/arch/hppa/gsc/gsckbc.c b/sys/arch/hppa/gsc/gsckbc.c
index 1e145b2760c..d814c8e3897 100644
--- a/sys/arch/hppa/gsc/gsckbc.c
+++ b/sys/arch/hppa/gsc/gsckbc.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: gsckbc.c,v 1.2 2003/02/15 23:42:45 miod Exp $ */
+/* $OpenBSD: gsckbc.c,v 1.3 2003/02/17 23:06:31 miod Exp $ */
/*
* Copyright (c) 2003, Miodrag Vallat.
* All rights reserved.
@@ -99,6 +99,8 @@ struct gsckbc_softc {
int sc_irq;
void *sc_ih;
int sc_type;
+
+ struct device *sc_sibling;
};
struct cfattach gsckbc_ca = {
@@ -156,6 +158,7 @@ void pckbc_cleanqueue(struct pckbc_slotdata *);
void pckbc_cleanup(void *);
int pckbc_cmdresponse(struct pckbc_internal *, pckbc_slot_t, u_char);
void pckbc_start(struct pckbc_internal *, pckbc_slot_t);
+int gsckbcintr(struct gsckbc_softc *);
const char *pckbc_slot_names[] = { "kbd", "mouse" };
@@ -360,9 +363,10 @@ gsckbc_attach(struct device *parent, struct device *self, void *aux)
struct gsckbc_softc *gsc = (void *)self;
struct pckbc_softc *sc = &gsc->sc_pckbc;
struct pckbc_internal *t;
+ struct device *tdev;
bus_space_tag_t iot;
bus_space_handle_t ioh;
- int ident;
+ int ident, dev;
iot = ga->ga_ca.ca_iot;
gsc->sc_irq = ga->ga_ca.ca_irq;
@@ -395,6 +399,35 @@ gsckbc_attach(struct device *parent, struct device *self, void *aux)
timeout_set(&t->t_cleanup, pckbc_cleanup, t);
sc->id = t;
+ /*
+ * Several gsckbc attachments might share the same interrupt.
+ * Try to find existing gsckbc devices, and associate them
+ * together. We do not expect more than two gsckbc devices to
+ * share an interrupt.
+ */
+ for (dev = 0; dev < gsckbc_cd.cd_ndevs; dev++) {
+ tdev = gsckbc_cd.cd_devs[dev];
+ if (tdev != NULL && tdev != self &&
+ tdev->dv_parent == parent &&
+ strcmp(tdev->dv_cfdata->cf_driver->cd_name,
+ gsckbc_cd.cd_name) == 0) {
+ struct gsckbc_softc *alter = (void *)tdev;
+ if (alter->sc_irq == gsc->sc_irq) {
+#ifdef PCKBCDEBUG
+ if (alter->sc_sibling != NULL) {
+ printf(": more than two ps/2 ports"
+ " sharing the same interrupt???\n");
+ bus_space_unmap(iot, ioh, KBMAPSIZE);
+ return;
+ }
+#endif
+ gsc->sc_sibling = (void *)alter;
+ alter->sc_sibling = self;
+ printf(" (shared with %s)", tdev->dv_xname);
+ }
+ }
+ }
+
printf("\n");
/*
@@ -975,11 +1008,9 @@ pckbc_set_inputhandler(self, slot, func, arg, name)
}
int
-pckbcintr(vsc)
- void *vsc;
+gsckbcintr(struct gsckbc_softc *gsc)
{
- struct pckbc_softc *sc = (struct pckbc_softc *)vsc;
- struct gsckbc_softc *gsc = (void *)sc;
+ struct pckbc_softc *sc = (struct pckbc_softc *)gsc;
struct pckbc_internal *t = sc->id;
pckbc_slot_t slot;
struct pckbc_slotdata *q;
@@ -1020,3 +1051,22 @@ pckbcintr(vsc)
return (served);
}
+
+int
+pckbcintr(void *vsc)
+{
+ struct gsckbc_softc *gsc = vsc;
+ int claimed;
+
+ claimed = gsckbcintr(gsc);
+
+ /*
+ * We also need to handle interrupts for the associated slot device,
+ * if any
+ */
+ gsc = (struct gsckbc_softc *)gsc->sc_sibling;
+ if (gsc != NULL)
+ claimed |= gsckbcintr(gsc);
+
+ return (claimed);
+}