diff options
| author | martin <martin@NetBSD.org> | 2003-12-12 14:30:16 +0000 |
|---|---|---|
| committer | martin <martin@NetBSD.org> | 2003-12-12 14:30:16 +0000 |
| commit | 9489d737cd870109667d8b263cf7626c4b6659a9 (patch) | |
| tree | 1b05b40fcdf9847d6c7d48be120c1c1121698bca /sys/dev | |
| parent | cd805c4cf7d312600f7066b589195b4eafaea7a5 (diff) | |
In parallel to the interrupt handler pckbcintr provide two functions
pckbcintr_hard and pckbcintr_soft, which, together, do the same as
pckbcintr. The first is called from the interrupt handler, the second
from a softinterrupt at arbitrary protection level (lower or equal to
IPL_TTY). They pass data via a small ringbuffer.
The new functions are intended for platforms that, due to
hardware/firmware restrictions are not able to make pckbcintr called at
IPL_TTY, like Krups javastations. Using the monolithic pckbcintr on
these plattforms leads to the input handlers for the slot data to be
run at elevated priority, causing various race conditions.
Diffstat (limited to 'sys/dev')
| -rw-r--r-- | sys/dev/ic/pckbc.c | 96 | ||||
| -rw-r--r-- | sys/dev/ic/pckbcvar.h | 16 |
2 files changed, 109 insertions, 3 deletions
diff --git a/sys/dev/ic/pckbc.c b/sys/dev/ic/pckbc.c index 19158329837..73638d52fd2 100644 --- a/sys/dev/ic/pckbc.c +++ b/sys/dev/ic/pckbc.c @@ -1,4 +1,4 @@ -/* $NetBSD: pckbc.c,v 1.27 2003/11/02 11:07:45 wiz Exp $ */ +/* $NetBSD: pckbc.c,v 1.28 2003/12/12 14:30:16 martin Exp $ */ /* * Copyright (c) 1998 @@ -32,7 +32,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: pckbc.c,v 1.27 2003/11/02 11:07:45 wiz Exp $"); +__KERNEL_RCSID(0, "$NetBSD: pckbc.c,v 1.28 2003/12/12 14:30:16 martin Exp $"); #include <sys/param.h> #include <sys/systm.h> @@ -933,6 +933,98 @@ pckbc_set_inputhandler(self, slot, func, arg, name) } int +pckbcintr_hard(vsc) + void *vsc; +{ + struct pckbc_softc *sc = (struct pckbc_softc *)vsc; + struct pckbc_internal *t = sc->id; + u_char stat; + pckbc_slot_t slot; + struct pckbc_slotdata *q; + int served = 0, data, next, s; + + for(;;) { + stat = bus_space_read_1(t->t_iot, t->t_ioh_c, 0); + if (!(stat & KBS_DIB)) + break; + + served = 1; + + slot = (t->t_haveaux && (stat & 0x20)) ? + PCKBC_AUX_SLOT : PCKBC_KBD_SLOT; + q = t->t_slotdata[slot]; + + if (!q) { + /* XXX do something for live insertion? */ + printf("pckbcintr: no dev for slot %d\n", slot); + KBD_DELAY; + (void) bus_space_read_1(t->t_iot, t->t_ioh_d, 0); + continue; + } + + KBD_DELAY; + data = bus_space_read_1(t->t_iot, t->t_ioh_d, 0); + +#if NRND > 0 + rnd_add_uint32(&q->rnd_source, (stat<<8)|data); +#endif + + if (q->polling) { + q->poll_data = data; + q->poll_stat = stat; + break; /* pckbc_poll_data() will get it */ + } + + if (CMD_IN_QUEUE(q) && pckbc_cmdresponse(t, slot, data)) + continue; + + s = splhigh(); + next = (t->rbuf_write+1) % PCKBC_RBUF_SIZE; + if (next == t->rbuf_read) { + splx(s); + break; + } + t->rbuf[t->rbuf_write].data = data; + t->rbuf[t->rbuf_write].slot = slot; + t->rbuf_write = next; + splx(s); + } + + return (served); +} + +void +pckbcintr_soft(vsc) + void *vsc; +{ + struct pckbc_softc *sc = vsc; + struct pckbc_internal *t = sc->id; + int data, slot, s; +#ifndef __GENERIC_SOFT_INTERRUPTS_ALL_LEVELS + int s; + + s = spltty(); +#endif + + s = splhigh(); + while (t->rbuf_read != t->rbuf_write) { + slot = t->rbuf[t->rbuf_read].slot; + data = t->rbuf[t->rbuf_read].data; + t->rbuf_read = (t->rbuf_read+1) % PCKBC_RBUF_SIZE; + splx(s); + if (sc->inputhandler[slot]) + (*sc->inputhandler[slot])(sc->inputarg[slot], data); + s = splhigh(); + } + splx(s); + + +#ifndef __GENERIC_SOFT_INTERRUPTS_ALL_LEVELS + splx(s); +#endif +} + +int pckbcintr(vsc) void *vsc; { diff --git a/sys/dev/ic/pckbcvar.h b/sys/dev/ic/pckbcvar.h index 3d0af619d66..10aff226b56 100644 --- a/sys/dev/ic/pckbcvar.h +++ b/sys/dev/ic/pckbcvar.h @@ -1,4 +1,4 @@ -/* $NetBSD: pckbcvar.h,v 1.6 2001/07/23 21:03:22 jdolecek Exp $ */ +/* $NetBSD: pckbcvar.h,v 1.7 2003/12/12 14:30:16 martin Exp $ */ /* * Copyright (c) 1998 @@ -43,6 +43,14 @@ typedef int pckbc_slot_t; #define PCKBC_AUX_SLOT 1 #define PCKBC_NSLOTS 2 +/* Simple cmd/slot ringbuffer structure */ +struct pckbc_rbuf_item { + int data; + int slot; +}; + +#define PCKBC_RBUF_SIZE 32 /* number of rbuf entries */ + /* * external representation (pckbc_tag_t), * needed early for console operation @@ -59,6 +67,10 @@ struct pckbc_internal { struct pckbc_softc *t_sc; /* back pointer */ struct callout t_cleanup; + + struct pckbc_rbuf_item rbuf[PCKBC_RBUF_SIZE]; + int rbuf_read; + int rbuf_write; }; typedef void (*pckbc_inputfcn) __P((void *, int)); @@ -106,6 +118,8 @@ int pckbc_cnattach __P((bus_space_tag_t, bus_addr_t, bus_size_t, pckbc_slot_t)); int pckbc_is_console __P((bus_space_tag_t, bus_addr_t)); int pckbcintr __P((void *)); +int pckbcintr_hard __P((void *)); +void pckbcintr_soft __P((void *)); /* md hook for use without mi wscons */ int pckbc_machdep_cnattach __P((pckbc_tag_t, pckbc_slot_t)); |
