diff --git a/sys/dev/speaker/spkr.c b/sys/dev/speaker/spkr.c --- a/sys/dev/speaker/spkr.c +++ b/sys/dev/speaker/spkr.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -24,7 +25,6 @@ static struct cdevsw spkr_cdevsw = { .d_version = D_VERSION, - .d_flags = D_NEEDGIANT, .d_open = spkropen, .d_close = spkrclose, .d_write = spkrwrite, @@ -392,51 +392,58 @@ static bool spkr_active = false; /* exclusion flag */ static char *spkr_inbuf; /* incoming buf */ +static struct sx spkr_lock; static int spkropen(struct cdev *dev, int flags, int fmt, struct thread *td) { + int error; + #ifdef DEBUG (void) printf("spkropen: entering with dev = %s\n", devtoname(dev)); #endif /* DEBUG */ - if (spkr_active) - return(EBUSY); - else { + error = 0; + sx_xlock(&spkr_lock); + if (spkr_active) { + error = 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); - } + } + sx_xunlock(&spkr_lock); + return (error); } static int spkrwrite(struct cdev *dev, struct uio *uio, int ioflag) { + unsigned n; + char *cp; + 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); + return(E2BIG); + + sx_xlock(&spkr_lock); + n = uio->uio_resid; + cp = spkr_inbuf; + error = uiomove(cp, n, uio); + if (!error) { + cp[n] = '\0'; + playstring(cp, n); } + sx_xunlock(&spkr_lock); + return (error); } static int @@ -446,10 +453,12 @@ (void) printf("spkrclose: entering with dev = %s\n", devtoname(dev)); #endif /* DEBUG */ + sx_xlock(&spkr_lock); wakeup(&endtone); wakeup(&endrest); free(spkr_inbuf, M_SPKR); spkr_active = false; + sx_xunlock(&spkr_lock); return(0); } @@ -457,28 +466,30 @@ spkrioctl(struct cdev *dev, unsigned long cmd, caddr_t cmdarg, int flags, struct thread *td) { + tone_t *tp, ttp; + int error; + #ifdef DEBUG (void) printf("spkrioctl: entering with dev = %s, cmd = %lx\n", devtoname(dev), cmd); #endif /* DEBUG */ + error = 0; + sx_xlock(&spkr_lock); if (cmd == SPKRTONE) { - tone_t *tp = (tone_t *)cmdarg; + tp = (tone_t *)cmdarg; if (tp->frequency == 0) rest(tp->duration); else tone(tp->frequency, tp->duration); - return 0; } else if (cmd == SPKRTUNE) { - tone_t *tp = (tone_t *)(*(caddr_t *)cmdarg); - tone_t ttp; - int error; + tp = (tone_t *)(*(caddr_t *)cmdarg); for (; ; tp++) { error = copyin(tp, &ttp, sizeof(tone_t)); if (error) - return(error); + break; if (ttp.duration == 0) break; @@ -488,9 +499,11 @@ else tone(ttp.frequency, ttp.duration); } - return(0); + } else { + error = EINVAL; } - return(EINVAL); + sx_xunlock(&spkr_lock); + return (error); } static struct cdev *speaker_dev; @@ -504,13 +517,15 @@ int error = 0; switch(type) { - case MOD_LOAD: + case MOD_LOAD: + sx_init(&spkr_lock, "speaker"); speaker_dev = make_dev(&spkr_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600, "speaker"); break; case MOD_SHUTDOWN: case MOD_UNLOAD: destroy_dev(speaker_dev); + sx_destroy(&spkr_lock); break; default: error = EOPNOTSUPP; diff --git a/sys/x86/isa/clock.c b/sys/x86/isa/clock.c --- a/sys/x86/isa/clock.c +++ b/sys/x86/isa/clock.c @@ -163,8 +163,11 @@ mode = TIMER_SEL2 | TIMER_SQWAVE | TIMER_16BIT; - if (timer2_state != RELEASED) + mtx_lock_spin(&clock_lock); + if (timer2_state != RELEASED) { + mtx_unlock_spin(&clock_lock); return (-1); + } timer2_state = ACQUIRED; /* @@ -175,6 +178,7 @@ * careful with it as with timer0. */ outb(TIMER_MODE, TIMER_SEL2 | (mode & 0x3f)); + mtx_unlock_spin(&clock_lock); ppi_spkr_on(); /* enable counter2 output to speaker */ return (0); @@ -184,10 +188,14 @@ timer_spkr_release(void) { - if (timer2_state != ACQUIRED) + mtx_lock_spin(&clock_lock); + if (timer2_state != ACQUIRED) { + mtx_unlock_spin(&clock_lock); return (-1); + } timer2_state = RELEASED; outb(TIMER_MODE, TIMER_SEL2 | TIMER_SQWAVE | TIMER_16BIT); + mtx_unlock_spin(&clock_lock); ppi_spkr_off(); /* disable counter2 output to speaker */ return (0);