| @@ -1,14 +1,14 @@ | | | @@ -1,14 +1,14 @@ |
1 | /* $NetBSD: audio.c,v 1.297 2017/01/26 04:15:38 nat Exp $ */ | | 1 | /* $NetBSD: audio.c,v 1.298 2017/01/27 05:05:51 nat Exp $ */ |
2 | | | 2 | |
3 | /*- | | 3 | /*- |
4 | * Copyright (c) 2016 Nathanial Sloss <nathanialsloss@yahoo.com.au> | | 4 | * Copyright (c) 2016 Nathanial Sloss <nathanialsloss@yahoo.com.au> |
5 | * All rights reserved. | | 5 | * All rights reserved. |
6 | * | | 6 | * |
7 | * Copyright (c) 2008 The NetBSD Foundation, Inc. | | 7 | * Copyright (c) 2008 The NetBSD Foundation, Inc. |
8 | * All rights reserved. | | 8 | * All rights reserved. |
9 | * | | 9 | * |
10 | * This code is derived from software contributed to The NetBSD Foundation | | 10 | * This code is derived from software contributed to The NetBSD Foundation |
11 | * by Andrew Doran. | | 11 | * by Andrew Doran. |
12 | * | | 12 | * |
13 | * Redistribution and use in source and binary forms, with or without | | 13 | * Redistribution and use in source and binary forms, with or without |
14 | * modification, are permitted provided that the following conditions | | 14 | * modification, are permitted provided that the following conditions |
| @@ -138,27 +138,27 @@ | | | @@ -138,27 +138,27 @@ |
138 | * query_devinfo - x | | 138 | * query_devinfo - x |
139 | * allocm - - Called at attach time | | 139 | * allocm - - Called at attach time |
140 | * freem - - Called at attach time | | 140 | * freem - - Called at attach time |
141 | * round_buffersize - x | | 141 | * round_buffersize - x |
142 | * mappage - - Mem. unchanged after attach | | 142 | * mappage - - Mem. unchanged after attach |
143 | * get_props - x | | 143 | * get_props - x |
144 | * trigger_output x x | | 144 | * trigger_output x x |
145 | * trigger_input x x | | 145 | * trigger_input x x |
146 | * dev_ioctl - x | | 146 | * dev_ioctl - x |
147 | * get_locks - - Called at attach time | | 147 | * get_locks - - Called at attach time |
148 | */ | | 148 | */ |
149 | | | 149 | |
150 | #include <sys/cdefs.h> | | 150 | #include <sys/cdefs.h> |
151 | __KERNEL_RCSID(0, "$NetBSD: audio.c,v 1.297 2017/01/26 04:15:38 nat Exp $"); | | 151 | __KERNEL_RCSID(0, "$NetBSD: audio.c,v 1.298 2017/01/27 05:05:51 nat Exp $"); |
152 | | | 152 | |
153 | #include "audio.h" | | 153 | #include "audio.h" |
154 | #if NAUDIO > 0 | | 154 | #if NAUDIO > 0 |
155 | | | 155 | |
156 | #include <sys/types.h> | | 156 | #include <sys/types.h> |
157 | #include <sys/param.h> | | 157 | #include <sys/param.h> |
158 | #include <sys/ioctl.h> | | 158 | #include <sys/ioctl.h> |
159 | #include <sys/fcntl.h> | | 159 | #include <sys/fcntl.h> |
160 | #include <sys/vnode.h> | | 160 | #include <sys/vnode.h> |
161 | #include <sys/select.h> | | 161 | #include <sys/select.h> |
162 | #include <sys/poll.h> | | 162 | #include <sys/poll.h> |
163 | #include <sys/kmem.h> | | 163 | #include <sys/kmem.h> |
164 | #include <sys/malloc.h> | | 164 | #include <sys/malloc.h> |
| @@ -1751,27 +1751,27 @@ audio_init_ringbuffer(struct audio_softc | | | @@ -1751,27 +1751,27 @@ audio_init_ringbuffer(struct audio_softc |
1751 | DPRINTF(("audio_init_ringbuffer: final blksize=%d\n", blksize)); | | 1751 | DPRINTF(("audio_init_ringbuffer: final blksize=%d\n", blksize)); |
1752 | rp->blksize = blksize; | | 1752 | rp->blksize = blksize; |
1753 | rp->maxblks = nblks; | | 1753 | rp->maxblks = nblks; |
1754 | rp->s.end = rp->s.start + nblks * blksize; | | 1754 | rp->s.end = rp->s.start + nblks * blksize; |
1755 | rp->s.outp = rp->s.inp = rp->s.start; | | 1755 | rp->s.outp = rp->s.inp = rp->s.start; |
1756 | rp->s.used = 0; | | 1756 | rp->s.used = 0; |
1757 | rp->stamp = 0; | | 1757 | rp->stamp = 0; |
1758 | rp->stamp_last = 0; | | 1758 | rp->stamp_last = 0; |
1759 | rp->fstamp = 0; | | 1759 | rp->fstamp = 0; |
1760 | rp->drops = 0; | | 1760 | rp->drops = 0; |
1761 | rp->copying = false; | | 1761 | rp->copying = false; |
1762 | rp->needfill = false; | | 1762 | rp->needfill = false; |
1763 | rp->mmapped = false; | | 1763 | rp->mmapped = false; |
1764 | memset(rp->s.start, 0, blksize * 2); | | 1764 | memset(rp->s.start, 0, AU_RING_SIZE); |
1765 | } | | 1765 | } |
1766 | | | 1766 | |
1767 | int | | 1767 | int |
1768 | audio_initbufs(struct audio_softc *sc, int n) | | 1768 | audio_initbufs(struct audio_softc *sc, int n) |
1769 | { | | 1769 | { |
1770 | const struct audio_hw_if *hw; | | 1770 | const struct audio_hw_if *hw; |
1771 | struct virtual_channel *vc; | | 1771 | struct virtual_channel *vc; |
1772 | int error; | | 1772 | int error; |
1773 | | | 1773 | |
1774 | DPRINTF(("audio_initbufs: mode=0x%x\n", sc->sc_vchan[n]->sc_mode)); | | 1774 | DPRINTF(("audio_initbufs: mode=0x%x\n", sc->sc_vchan[n]->sc_mode)); |
1775 | vc = sc->sc_vchan[0]; | | 1775 | vc = sc->sc_vchan[0]; |
1776 | hw = sc->hw_if; | | 1776 | hw = sc->hw_if; |
1777 | if (audio_can_capture(sc) || (sc->sc_vchan[n]->sc_open & AUOPEN_READ)) { | | 1777 | if (audio_can_capture(sc) || (sc->sc_vchan[n]->sc_open & AUOPEN_READ)) { |
| @@ -3215,65 +3215,58 @@ audiostartr(struct audio_softc *sc, int | | | @@ -3215,65 +3215,58 @@ audiostartr(struct audio_softc *sc, int |
3215 | if (sc->sc_rec_started == false) { | | 3215 | if (sc->sc_rec_started == false) { |
3216 | mix_read(sc); | | 3216 | mix_read(sc); |
3217 | cv_broadcast(&sc->sc_rcondvar); | | 3217 | cv_broadcast(&sc->sc_rcondvar); |
3218 | } | | 3218 | } |
3219 | vc->sc_rbus = true; | | 3219 | vc->sc_rbus = true; |
3220 | | | 3220 | |
3221 | return 0; | | 3221 | return 0; |
3222 | } | | 3222 | } |
3223 | | | 3223 | |
3224 | int | | 3224 | int |
3225 | audiostartp(struct audio_softc *sc, int n) | | 3225 | audiostartp(struct audio_softc *sc, int n) |
3226 | { | | 3226 | { |
3227 | struct virtual_channel *vc = sc->sc_vchan[n]; | | 3227 | struct virtual_channel *vc = sc->sc_vchan[n]; |
3228 | int used, error; | | 3228 | int error, used; |
3229 | | | 3229 | |
3230 | KASSERT(mutex_owned(sc->sc_lock)); | | 3230 | KASSERT(mutex_owned(sc->sc_lock)); |
3231 | KASSERT(mutex_owned(sc->sc_intr_lock)); | | 3231 | KASSERT(mutex_owned(sc->sc_intr_lock)); |
3232 | | | 3232 | |
3233 | error = 0; | | 3233 | error = 0; |
3234 | used = audio_stream_get_used(&vc->sc_mpr.s); | | 3234 | used = audio_stream_get_used(&vc->sc_mpr.s); |
3235 | DPRINTF(("audiostartp: start=%p used=%d(hi=%d blk=%d) mmapped=%d\n", | | 3235 | DPRINTF(("audiostartp: start=%p used=%d(hi=%d blk=%d) mmapped=%d\n", |
3236 | vc->sc_mpr.s.start, used, vc->sc_mpr.usedhigh, | | 3236 | vc->sc_mpr.s.start, used, vc->sc_mpr.usedhigh, |
3237 | vc->sc_mpr.blksize, vc->sc_mpr.mmapped)); | | 3237 | vc->sc_mpr.blksize, vc->sc_mpr.mmapped)); |
3238 | | | 3238 | |
3239 | if (!audio_can_playback(sc)) | | 3239 | if (!audio_can_playback(sc)) |
3240 | return EINVAL; | | 3240 | return EINVAL; |
3241 | | | 3241 | |
3242 | if (!vc->sc_mpr.mmapped && used < vc->sc_mpr.blksize) { | | 3242 | if (!vc->sc_mpr.mmapped && used < vc->sc_mpr.blksize) { |
3243 | cv_broadcast(&sc->sc_wchan); | | 3243 | cv_broadcast(&sc->sc_wchan); |
3244 | DPRINTF(("%s: wakeup and return\n", __func__)); | | 3244 | DPRINTF(("%s: wakeup and return\n", __func__)); |
3245 | return 0; | | 3245 | return 0; |
3246 | } | | 3246 | } |
3247 | | | 3247 | |
3248 | vc->sc_pbus = true; | | 3248 | vc->sc_pbus = true; |
3249 | if (sc->sc_opens > 0) { | | 3249 | if (sc->sc_trigger_started == false) { |
3250 | mix_func(sc, &vc->sc_mpr, n); | | 3250 | audio_mix(sc); |
3251 | | | 3251 | mix_write(sc); |
3252 | if (sc->sc_trigger_started == false) { | | | |
3253 | sc->sc_pr.s.inp = audio_stream_add_inp(&sc->sc_pr.s, | | | |
3254 | sc->sc_pr.s.inp, vc->sc_mpr.blksize); | | | |
3255 | mix_write(sc); | | | |
3256 | audio_mix(sc); | | | |
3257 | vc = sc->sc_vchan[0]; | | | |
3258 | if (sc->hw_if->trigger_output == NULL) { | | | |
3259 | vc->sc_mpr.s.outp = | | | |
3260 | audio_stream_add_outp(&vc->sc_mpr.s, | | | |
3261 | vc->sc_mpr.s.outp, vc->sc_mpr.blksize); | | | |
3262 | } | | | |
3263 | mix_write(sc); | | | |
3264 | | | 3252 | |
3265 | cv_broadcast(&sc->sc_condvar); | | 3253 | vc = sc->sc_vchan[0]; |
3266 | } | | 3254 | vc->sc_mpr.s.outp = |
| | | 3255 | audio_stream_add_outp(&vc->sc_mpr.s, |
| | | 3256 | vc->sc_mpr.s.outp, vc->sc_mpr.blksize); |
| | | 3257 | audio_mix(sc); |
| | | 3258 | mix_write(sc); |
| | | 3259 | cv_broadcast(&sc->sc_condvar); |
3267 | } | | 3260 | } |
3268 | | | 3261 | |
3269 | return error; | | 3262 | return error; |
3270 | } | | 3263 | } |
3271 | | | 3264 | |
3272 | /* | | 3265 | /* |
3273 | * When the play interrupt routine finds that the write isn't keeping | | 3266 | * When the play interrupt routine finds that the write isn't keeping |
3274 | * the buffer filled it will insert silence in the buffer to make up | | 3267 | * the buffer filled it will insert silence in the buffer to make up |
3275 | * for this. The part of the buffer that is filled with silence | | 3268 | * for this. The part of the buffer that is filled with silence |
3276 | * is kept track of in a very approximate way: it starts at sc_sil_start | | 3269 | * is kept track of in a very approximate way: it starts at sc_sil_start |
3277 | * and extends sc_sil_count bytes. If there is already silence in | | 3270 | * and extends sc_sil_count bytes. If there is already silence in |
3278 | * the requested area nothing is done; so when the whole buffer is | | 3271 | * the requested area nothing is done; so when the whole buffer is |
3279 | * silent nothing happens. When the writer starts again sc_sil_count | | 3272 | * silent nothing happens. When the writer starts again sc_sil_count |
| @@ -3407,41 +3400,41 @@ audio_mix(void *v) | | | @@ -3407,41 +3400,41 @@ audio_mix(void *v) |
3407 | int n, i; | | 3400 | int n, i; |
3408 | | | 3401 | |
3409 | sc = v; | | 3402 | sc = v; |
3410 | | | 3403 | |
3411 | DPRINTF(("PINT MIX\n")); | | 3404 | DPRINTF(("PINT MIX\n")); |
3412 | sc->schedule_rih = false; | | 3405 | sc->schedule_rih = false; |
3413 | sc->schedule_wih = false; | | 3406 | sc->schedule_wih = false; |
3414 | sc->sc_writeme = false; | | 3407 | sc->sc_writeme = false; |
3415 | | | 3408 | |
3416 | if (sc->sc_dying == true) | | 3409 | if (sc->sc_dying == true) |
3417 | return; | | 3410 | return; |
3418 | | | 3411 | |
3419 | i = sc->sc_opens; | | 3412 | i = sc->sc_opens; |
| | | 3413 | blksize = sc->sc_vchan[0]->sc_mpr.blksize; |
3420 | for (n = 1; n < VAUDIOCHANS; n++) { | | 3414 | for (n = 1; n < VAUDIOCHANS; n++) { |
3421 | if (!sc->sc_opens || i <= 0) | | 3415 | if (!sc->sc_opens || i <= 0) |
3422 | break; /* ignore interrupt if not open */ | | 3416 | break; /* ignore interrupt if not open */ |
3423 | | | 3417 | |
3424 | if (sc->sc_audiopid[n].pid == -1) | | 3418 | if (sc->sc_audiopid[n].pid == -1) |
3425 | continue; | | 3419 | continue; |
3426 | i--; | | 3420 | i--; |
3427 | vc = sc->sc_vchan[n]; | | 3421 | vc = sc->sc_vchan[n]; |
3428 | if (!vc->sc_open) | | 3422 | if (!vc->sc_open) |
3429 | continue; | | 3423 | continue; |
3430 | if (!vc->sc_pbus) | | 3424 | if (!vc->sc_pbus) |
3431 | continue; | | 3425 | continue; |
3432 | | | 3426 | |
3433 | cb = &vc->sc_mpr; | | 3427 | cb = &vc->sc_mpr; |
3434 | blksize = sc->sc_vchan[0]->sc_mpr.blksize; | | | |
3435 | | | 3428 | |
3436 | sc->sc_writeme = true; | | 3429 | sc->sc_writeme = true; |
3437 | | | 3430 | |
3438 | inp = cb->s.inp; | | 3431 | inp = cb->s.inp; |
3439 | cb->stamp += blksize; | | 3432 | cb->stamp += blksize; |
3440 | if (cb->mmapped) { | | 3433 | if (cb->mmapped) { |
3441 | DPRINTF(("audio_pint: mmapped outp=%p cc=%d inp=%p\n", | | 3434 | DPRINTF(("audio_pint: mmapped outp=%p cc=%d inp=%p\n", |
3442 | cb->s.outp, blksize, cb->s.inp)); | | 3435 | cb->s.outp, blksize, cb->s.inp)); |
3443 | mix_func(sc, cb, n); | | 3436 | mix_func(sc, cb, n); |
3444 | continue; | | 3437 | continue; |
3445 | } | | 3438 | } |
3446 | | | 3439 | |
3447 | #ifdef AUDIO_INTR_TIME | | 3440 | #ifdef AUDIO_INTR_TIME |
| @@ -3522,47 +3515,47 @@ audio_mix(void *v) | | | @@ -3522,47 +3515,47 @@ audio_mix(void *v) |
3522 | cc); | | 3515 | cc); |
3523 | | | 3516 | |
3524 | /* Clear next block to keep ahead of the DMA. */ | | 3517 | /* Clear next block to keep ahead of the DMA. */ |
3525 | used = audio_stream_get_used(&cb->s); | | 3518 | used = audio_stream_get_used(&cb->s); |
3526 | if (used + blksize < cb->s.end - cb->s.start) { | | 3519 | if (used + blksize < cb->s.end - cb->s.start) { |
3527 | audio_pint_silence(sc, cb, cb->s.inp, | | 3520 | audio_pint_silence(sc, cb, cb->s.inp, |
3528 | blksize, n); | | 3521 | blksize, n); |
3529 | } | | 3522 | } |
3530 | } | | 3523 | } |
3531 | } | | 3524 | } |
3532 | | | 3525 | |
3533 | DPRINTFN(5, ("audio_pint: outp=%p cc=%d\n", cb->s.outp, | | 3526 | DPRINTFN(5, ("audio_pint: outp=%p cc=%d\n", cb->s.outp, |
3534 | blksize)); | | 3527 | blksize)); |
3535 | cb->s.outp = audio_stream_add_outp(&cb->s, cb->s.outp, blksize); | | | |
3536 | mix_func(sc, cb, n); | | 3528 | mix_func(sc, cb, n); |
| | | 3529 | cb->s.outp = audio_stream_add_outp(&cb->s, cb->s.outp, blksize); |
3537 | | | 3530 | |
3538 | DPRINTFN(2, ("audio_pint: mode=%d pause=%d used=%d lowat=%d\n", | | 3531 | DPRINTFN(2, ("audio_pint: mode=%d pause=%d used=%d lowat=%d\n", |
3539 | vc->sc_mode, cb->pause, | | 3532 | vc->sc_mode, cb->pause, |
3540 | audio_stream_get_used(vc->sc_pustream), | | 3533 | audio_stream_get_used(vc->sc_pustream), |
3541 | cb->usedlow)); | | 3534 | cb->usedlow)); |
3542 | | | 3535 | |
3543 | if ((vc->sc_mode & AUMODE_PLAY) && !cb->pause) { | | 3536 | if ((vc->sc_mode & AUMODE_PLAY) && !cb->pause) { |
3544 | if (audio_stream_get_used(&cb->s) <= cb->usedlow) | | 3537 | if (audio_stream_get_used(&cb->s) <= cb->usedlow) |
3545 | sc->schedule_wih = true; | | 3538 | sc->schedule_wih = true; |
3546 | } | | 3539 | } |
3547 | /* Possible to return one or more "phantom blocks" now. */ | | 3540 | /* Possible to return one or more "phantom blocks" now. */ |
3548 | if (!vc->sc_full_duplex && vc->sc_mode & AUMODE_RECORD) | | 3541 | if (!vc->sc_full_duplex && vc->sc_mode & AUMODE_RECORD) |
3549 | sc->schedule_rih = true; | | 3542 | sc->schedule_rih = true; |
3550 | } | | 3543 | } |
3551 | if (sc->sc_saturate == true && sc->sc_opens > 1) | | 3544 | if (sc->sc_saturate == true && sc->sc_opens > 1) |
3552 | saturate_func(sc); | | 3545 | saturate_func(sc); |
3553 | | | 3546 | |
3554 | cb = &sc->sc_pr; | | 3547 | cb = &sc->sc_pr; |
3555 | cb->s.inp = audio_stream_add_inp(&cb->s, cb->s.inp, cb->blksize); | | 3548 | cb->s.inp = audio_stream_add_inp(&cb->s, cb->s.inp, blksize); |
3556 | | | 3549 | |
3557 | kpreempt_disable(); | | 3550 | kpreempt_disable(); |
3558 | if (sc->schedule_wih == true) | | 3551 | if (sc->schedule_wih == true) |
3559 | softint_schedule(sc->sc_sih_wr); | | 3552 | softint_schedule(sc->sc_sih_wr); |
3560 | | | 3553 | |
3561 | if (sc->schedule_rih == true) | | 3554 | if (sc->schedule_rih == true) |
3562 | softint_schedule(sc->sc_sih_rd); | | 3555 | softint_schedule(sc->sc_sih_rd); |
3563 | kpreempt_enable(); | | 3556 | kpreempt_enable(); |
3564 | | | 3557 | |
3565 | cc = sc->sc_vchan[0]->sc_mpr.blksize; | | 3558 | cc = sc->sc_vchan[0]->sc_mpr.blksize; |
3566 | if (sc->sc_writeme == false) { | | 3559 | if (sc->sc_writeme == false) { |
3567 | sc->sc_vchan[0]->sc_mpr.drops += cc; | | 3560 | sc->sc_vchan[0]->sc_mpr.drops += cc; |
3568 | cv_broadcast(&sc->sc_wchan); | | 3561 | cv_broadcast(&sc->sc_wchan); |