diff options
author | Miod Vallat <miod@cvs.openbsd.org> | 2003-02-17 23:06:32 +0000 |
---|---|---|
committer | Miod Vallat <miod@cvs.openbsd.org> | 2003-02-17 23:06:32 +0000 |
commit | 137a0f31e269263744dfab2e91fc44774923a5bf (patch) | |
tree | 7ffdfe312fb6ab3498f4519757d9ae01fdf846e6 /sys/arch/hppa/gsc | |
parent | becfa62f65c6f332b9a1a2c794cee39d310b7458 (diff) |
Since the ps/2 input ports show up as two different devices, with the same
irq, but hppa has no generic shared interrupt code, we need to make sure
that gsckbc devices using the same irq know each other, and will pass
the interrupt notification to each other.
This allow a mouse and a keyboard to work together...
Diffstat (limited to 'sys/arch/hppa/gsc')
-rw-r--r-- | sys/arch/hppa/gsc/gsckbc.c | 62 |
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); +} |