Index: sys/dev/speaker/spkr.c =================================================================== --- sys/dev/speaker/spkr.c +++ sys/dev/speaker/spkr.c @@ -21,28 +21,35 @@ #include static d_open_t spkropen; -static d_close_t spkrclose; static d_write_t spkrwrite; static d_ioctl_t spkrioctl; static struct cdevsw spkr_cdevsw = { .d_version = D_VERSION, - .d_flags = D_NEEDGIANT, + .d_flags = 0, .d_open = spkropen, - .d_close = spkrclose, .d_write = spkrwrite, .d_ioctl = spkrioctl, .d_name = "spkr", }; -static MALLOC_DEFINE(M_SPKR, "spkr", "Speaker buffer"); +typedef struct { + int octave; /* currently selected octave */ + int whole; /* whole-note time at current tempo, in ticks */ + int value; /* whole divisor for note time, quarter note = 1 */ + int fill; /* controls spacing of notes */ + bool octtrack; /* octave-tracking on? */ + bool octprefix; /* override current octave-tracking state? */ + char inbuf[DEV_BSIZE]; +} spkr_cdevpriv; +static MALLOC_DEFINE(M_SPKR, "spkr", "Speaker state"); + /* **************** MACHINE DEPENDENT PART STARTS HERE ************************* * This section defines a function tone() which causes a tone of given * frequency and duration from the ISA console speaker. - * Another function endtone() is defined to force sound off, and there is - * also a rest() entry point to do pauses. + * There is also a rest() entry point to do pauses. * * Audible sound is generated using the Programmable Interval Timer (PIT) and * Programmable Peripheral Interface (PPI) attached to the ISA speaker. The @@ -51,57 +58,57 @@ */ #define SPKRPRI PSOCK -static char endtone, endrest; -static void tone(unsigned int thz, unsigned int centisecs); -static void rest(int centisecs); -static void playinit(void); -static void playtone(int pitch, int value, int sustain); -static void playstring(char *cp, size_t slen); +static void spkrdtor(void *data); +static int tone(unsigned int thz, unsigned int centisecs); +static int rest(int centisecs); +static void playinit(spkr_cdevpriv *cdp); +static int playtone(int pitch, int value, int sustain, int whole, int fill); +static int playstring(spkr_cdevpriv *cdp, size_t slen); /* * Emit tone of frequency thz for given number of centisecs */ -static void +static int tone(unsigned int thz, unsigned int centisecs) { - int timo; + int error, timo; + error = 0; + if (thz <= 0) - return; + return (0); #ifdef DEBUG (void) printf("tone: thz=%d centisecs=%d\n", thz, centisecs); #endif /* DEBUG */ - /* set timer to generate clicks at given frequency in Hertz */ - if (timer_spkr_acquire()) { - /* enter list of waiting procs ??? */ - return; - } - disable_intr(); + if (timer_spkr_acquire()) + return (0); + timer_spkr_setfreq(thz); - enable_intr(); /* - * Set timeout to endtone function, then give up the timeslice. - * This is so other processes can execute while the tone is being - * emitted. + * Allow other processes to execute while the tone is being emitted. */ timo = centisecs * hz / 100; if (timo > 0) - tsleep(&endtone, SPKRPRI | PCATCH, "spkrtn", timo); + error = pause_sig("spkrtn", timo); timer_spkr_release(); + + return (error == EWOULDBLOCK ? 0 : error); } /* * Rest for given number of centisecs */ -static void +static int rest(int centisecs) { - int timo; + int error, timo; + error = 0; + /* * Set timeout to endrest function, then give up the timeslice. * This is so other processes can execute while the rest is being @@ -112,7 +119,9 @@ #endif /* DEBUG */ timo = centisecs * hz / 100; if (timo > 0) - tsleep(&endrest, SPKRPRI | PCATCH, "spkrrs", timo); + error = pause_sig("spkrrs", timo); + + return (error == EWOULDBLOCK ? 0 : error); } /* @@ -120,7 +129,7 @@ * Play string interpretation is modelled on IBM BASIC 2.0's PLAY statement; * M[LNS] are missing; the ~ synonym and the _ slur mark and the octave- * tracking facility are added. - * Requires tone(), rest(), and endtone(). String play is not interruptible + * Requires tone() and rest(). String play is not interruptible * except possibly at physical block boundaries. */ @@ -132,13 +141,6 @@ #define dtoi(c) ((c) - '0') -static int octave; /* currently selected octave */ -static int whole; /* whole-note time at current tempo, in ticks */ -static int value; /* whole divisor for note time, quarter note = 1 */ -static int fill; /* controls spacing of notes */ -static bool octtrack; /* octave-tracking on? */ -static bool octprefix; /* override current octave-tracking state? */ - /* * Magic number avoidance... */ @@ -179,24 +181,26 @@ }; static void -playinit() +playinit(spkr_cdevpriv *cdp) { - octave = DFLT_OCTAVE; - whole = (100 * SECS_PER_MIN * WHOLE_NOTE) / DFLT_TEMPO; - fill = NORMAL; - value = DFLT_VALUE; - octtrack = FALSE; - octprefix = TRUE; /* act as though there was an initial O(n) */ + cdp->octave = DFLT_OCTAVE; + cdp->whole = (100 * SECS_PER_MIN * WHOLE_NOTE) / DFLT_TEMPO; + cdp->fill = NORMAL; + cdp->value = DFLT_VALUE; + cdp->octtrack = FALSE; + cdp->octprefix = TRUE; /* act as though there was an initial O(n) */ } /* * Play tone of proper duration for current rhythm signature */ -static void -playtone(int pitch, int value, int sustain) +static int +playtone(int pitch, int value, int sustain, int whole, int fill) { - int sound, silence, snum = 1, sdenom = 1; + int error, sound, silence, snum = 1, sdenom = 1; + error = 0; + /* this weirdness avoids floating-point arithmetic */ for (; sustain; sustain--) { /* See the BUGS section in the man page for discussion */ @@ -205,10 +209,10 @@ } if (value == 0 || sdenom == 0) - return; + return (0); if (pitch == -1) - rest(whole * snum / (value * sdenom)); + error = rest(whole * snum / (value * sdenom)); else { sound = (whole * snum) / (value * sdenom) - (whole * (FILLTIME - fill)) / (value * FILLTIME); @@ -219,23 +223,27 @@ pitch, sound, silence); #endif /* DEBUG */ - tone(pitchtab[pitch], sound); - if (fill != LEGATO) - rest(silence); + error = tone(pitchtab[pitch], sound); + if ((error == 0) && (fill != LEGATO)) + error = rest(silence); } + return (error); } /* * Interpret and play an item from a notation string */ -static void -playstring(char *cp, size_t slen) +static int +playstring(spkr_cdevpriv *cdp, size_t slen) { - int pitch, oldfill, lastpitch = OCTAVE_NOTES * DFLT_OCTAVE; + char *cp = cdp->inbuf; + int error, pitch, oldfill, lastpitch = OCTAVE_NOTES * DFLT_OCTAVE; + error = 0; + #define GETNUM(cp, v) for(v=0; isdigit(cp[1]) && slen > 0; ) \ {v = v * 10 + (*++cp - '0'); slen--;} - for (; slen--; cp++) { + for (; (error == 0) && slen--; cp++) { int sustain, timeval, tempo; char c = toupper(*cp); @@ -252,7 +260,7 @@ case 'F': case 'G': /* compute pitch */ - pitch = notetab[c - 'A'] + octave * OCTAVE_NOTES; + pitch = notetab[c - 'A'] + cdp->octave * OCTAVE_NOTES; /* this may be followed by an accidental sign */ if (cp[1] == '#' || cp[1] == '+') { @@ -270,26 +278,26 @@ * setting prefix, find the version of the current letter note * closest to the last regardless of octave. */ - if (octtrack && !octprefix) { + if (cdp->octtrack && !cdp->octprefix) { if (abs(pitch-lastpitch) > abs(pitch+OCTAVE_NOTES - lastpitch)) { - ++octave; + ++cdp->octave; pitch += OCTAVE_NOTES; } if (abs(pitch-lastpitch) > abs((pitch-OCTAVE_NOTES) - lastpitch)) { - --octave; + --cdp->octave; pitch -= OCTAVE_NOTES; } } - octprefix = FALSE; + cdp->octprefix = FALSE; lastpitch = pitch; /* ...which may in turn be followed by an override time value */ GETNUM(cp, timeval); if (timeval <= 0 || timeval > MIN_VALUE) - timeval = value; + timeval = cdp->value; /* ...and/or sustain dots */ for (sustain = 0; cp[1] == '.'; cp++) { @@ -298,43 +306,43 @@ } /* ...and/or a slur mark */ - oldfill = fill; + oldfill = cdp->fill; if (cp[1] == '_') { - fill = LEGATO; + cdp->fill = LEGATO; ++cp; slen--; } /* time to emit the actual tone */ - playtone(pitch, timeval, sustain); + error = playtone(pitch, timeval, sustain, cdp->whole, cdp->fill); - fill = oldfill; + cdp->fill = oldfill; break; case 'O': if (cp[1] == 'N' || cp[1] == 'n') { - octprefix = octtrack = FALSE; + cdp->octprefix = cdp->octtrack = FALSE; ++cp; slen--; } else if (cp[1] == 'L' || cp[1] == 'l') { - octtrack = TRUE; + cdp->octtrack = TRUE; ++cp; slen--; } else { - GETNUM(cp, octave); - if (octave >= nitems(pitchtab) / OCTAVE_NOTES) - octave = DFLT_OCTAVE; - octprefix = TRUE; + GETNUM(cp, cdp->octave); + if (cdp->octave >= nitems(pitchtab) / OCTAVE_NOTES) + cdp->octave = DFLT_OCTAVE; + cdp->octprefix = TRUE; } break; case '>': - if (octave < nitems(pitchtab) / OCTAVE_NOTES - 1) - octave++; - octprefix = TRUE; + if (cdp->octave < nitems(pitchtab) / OCTAVE_NOTES - 1) + cdp->octave++; + cdp->octprefix = TRUE; break; case '<': - if (octave > 0) - octave--; - octprefix = TRUE; + if (cdp->octave > 0) + cdp->octave--; + cdp->octprefix = TRUE; break; case 'N': GETNUM(cp, pitch); @@ -342,66 +350,65 @@ slen--; sustain++; } - oldfill = fill; + oldfill = cdp->fill; if (cp[1] == '_') { - fill = LEGATO; + cdp->fill = LEGATO; ++cp; slen--; } - playtone(pitch - 1, value, sustain); - fill = oldfill; + error = playtone(pitch - 1, cdp->value, sustain, cdp->whole, cdp->fill); + cdp->fill = oldfill; break; case 'L': - GETNUM(cp, value); - if (value <= 0 || value > MIN_VALUE) - value = DFLT_VALUE; + GETNUM(cp, cdp->value); + if (cdp->value <= 0 || cdp->value > MIN_VALUE) + cdp->value = DFLT_VALUE; break; case 'P': case '~': /* this may be followed by an override time value */ GETNUM(cp, timeval); if (timeval <= 0 || timeval > MIN_VALUE) - timeval = value; + timeval = cdp->value; for (sustain = 0; cp[1] == '.'; cp++) { slen--; sustain++; } - playtone(-1, timeval, sustain); + error = playtone(-1, timeval, sustain, cdp->whole, cdp->fill); break; case 'T': GETNUM(cp, tempo); if (tempo < MIN_TEMPO || tempo > MAX_TEMPO) tempo = DFLT_TEMPO; - whole = (100 * SECS_PER_MIN * WHOLE_NOTE) / tempo; + cdp->whole = (100 * SECS_PER_MIN * WHOLE_NOTE) / tempo; break; case 'M': if (cp[1] == 'N' || cp[1] == 'n') { - fill = NORMAL; + cdp->fill = NORMAL; ++cp; slen--; } else if (cp[1] == 'L' || cp[1] == 'l') { - fill = LEGATO; + cdp->fill = LEGATO; ++cp; slen--; } else if (cp[1] == 'S' || cp[1] == 's') { - fill = STACCATO; + cdp->fill = STACCATO; ++cp; slen--; } break; } } + + return (error); } /* * ****************** UNIX DRIVER HOOKS BEGIN HERE ************************** - * This section implements driver hooks to run playstring() and the tone(), - * endtone(), and rest() functions defined above. + * This section implements driver hooks to run playstring() and the tone() + * and rest() functions defined above. */ -static int spkr_active = FALSE; /* exclusion flag */ -static char *spkr_inbuf; /* incoming buf */ - static int spkropen(dev, flags, fmt, td) struct cdev *dev; @@ -409,21 +416,18 @@ int fmt; struct thread *td; { + int error; #ifdef DEBUG (void) printf("spkropen: entering with dev = %s\n", devtoname(dev)); #endif /* DEBUG */ + spkr_cdevpriv *cdp = malloc(sizeof(*cdp), M_SPKR, M_WAITOK); - if (spkr_active) - return(EBUSY); - else { -#ifdef DEBUG - (void) printf("spkropen: about to perform play initialization\n"); -#endif /* DEBUG */ - playinit(); - spkr_inbuf = malloc(DEV_BSIZE, M_SPKR, M_WAITOK); - spkr_active = TRUE; - return(0); - } + error = devfs_set_cdevpriv(cdp, spkrdtor); + if (error != 0) + free(cdp, M_SPKR); + else + playinit(cdp); + return (error); } static int @@ -432,45 +436,36 @@ struct uio *uio; int ioflag; { + unsigned n; + spkr_cdevpriv *cdp; + int error; #ifdef DEBUG printf("spkrwrite: entering with dev = %s, count = %zd\n", devtoname(dev), uio->uio_resid); #endif /* DEBUG */ - if (uio->uio_resid > (DEV_BSIZE - 1)) /* prevent system crashes */ - return(E2BIG); - else { - unsigned n; - char *cp; - int error; - - n = uio->uio_resid; - cp = spkr_inbuf; - error = uiomove(cp, n, uio); - if (!error) { - cp[n] = '\0'; - playstring(cp, n); - } - return(error); + error = devfs_get_cdevpriv((void**)&cdp); + if (error != 0) + return (error); + if (uio->uio_resid > (sizeof(cdp->inbuf) - 1)) /* prevent system crashes */ + return (E2BIG); + n = uio->uio_resid; + error = uiomove(cdp->inbuf, n, uio); + if (!error) { + cdp->inbuf[n] = '\0'; + error = playstring(cdp, n); } + return (error); } -static int -spkrclose(dev, flags, fmt, td) - struct cdev *dev; - int flags; - int fmt; - struct thread *td; +static void +spkrdtor(void *data) { -#ifdef DEBUG - (void) printf("spkrclose: entering with dev = %s\n", devtoname(dev)); -#endif /* DEBUG */ + spkr_cdevpriv *cdp; + cdp = data; - wakeup(&endtone); - wakeup(&endrest); - free(spkr_inbuf, M_SPKR); - spkr_active = FALSE; - return(0); + KASSERT(cdp != NULL, ("spkr cdevpriv should not be NULL!")); + free(cdp, M_SPKR); } static int @@ -481,6 +476,10 @@ int flags; struct thread *td; { + int error; + + error = 0; + #ifdef DEBUG (void) printf("spkrioctl: entering with dev = %s, cmd = %lx\n", devtoname(dev), cmd); @@ -490,31 +489,28 @@ tone_t *tp = (tone_t *)cmdarg; if (tp->frequency == 0) - rest(tp->duration); + error = rest(tp->duration); else - tone(tp->frequency, tp->duration); - return 0; + error = tone(tp->frequency, tp->duration); } else if (cmd == SPKRTUNE) { tone_t *tp = (tone_t *)(*(caddr_t *)cmdarg); tone_t ttp; - int error; - for (; ; tp++) { + for (; error == 0; tp++) { error = copyin(tp, &ttp, sizeof(tone_t)); if (error) - return(error); + break; if (ttp.duration == 0) break; if (ttp.frequency == 0) - rest(ttp.duration); + error = rest(ttp.duration); else - tone(ttp.frequency, ttp.duration); + error = tone(ttp.frequency, ttp.duration); } - return(0); } - return(EINVAL); + return (error); } static struct cdev *speaker_dev; Index: sys/x86/isa/clock.c =================================================================== --- sys/x86/isa/clock.c +++ sys/x86/isa/clock.c @@ -61,6 +61,7 @@ #include #include +#include #include #include #include @@ -116,7 +117,7 @@ #define ACQUIRED 2 #define ACQUIRE_PENDING 3 -static u_char timer2_state; +static u_int timer2_state; static unsigned i8254_get_timecount(struct timecounter *tc); static void set_i8254_freq(int mode, uint32_t period); @@ -160,9 +161,8 @@ mode = TIMER_SEL2 | TIMER_SQWAVE | TIMER_16BIT; - if (timer2_state != RELEASED) + if (!atomic_cmpset_acq_int(&timer2_state, RELEASED, ACQUIRED)) return (-1); - timer2_state = ACQUIRED; /* * This access to the timer registers is as atomic as possible @@ -181,12 +181,13 @@ timer_spkr_release(void) { - if (timer2_state != ACQUIRED) + if (!atomic_cmpset_int(&timer2_state, ACQUIRED, RELEASE_PENDING)) return (-1); - timer2_state = RELEASED; outb(TIMER_MODE, TIMER_SEL2 | TIMER_SQWAVE | TIMER_16BIT); ppi_spkr_off(); /* disable counter2 output to speaker */ + + atomic_store_rel_int(&timer2_state, RELEASED); return (0); }