diff options
Diffstat (limited to 'sys/arch/hppa/gsc/gsckbc.c')
-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); +} |