Tue Jan 24 08:17:11 2023 UTC ()
Pace I/O timing to match the audio interface.
Enable interrupts while copying buffers.


(mlelstv)
diff -r1.78 -r1.79 src/sys/dev/pad/pad.c
diff -r1.16 -r1.17 src/sys/dev/pad/padvar.h

cvs diff -r1.78 -r1.79 src/sys/dev/pad/pad.c (expand / switch to unified diff)

--- src/sys/dev/pad/pad.c 2022/03/31 19:30:16 1.78
+++ src/sys/dev/pad/pad.c 2023/01/24 08:17:11 1.79
@@ -1,14 +1,14 @@ @@ -1,14 +1,14 @@
1/* $NetBSD: pad.c,v 1.78 2022/03/31 19:30:16 pgoyette Exp $ */ 1/* $NetBSD: pad.c,v 1.79 2023/01/24 08:17:11 mlelstv Exp $ */
2 2
3/*- 3/*-
4 * Copyright (c) 2007 Jared D. McNeill <jmcneill@invisible.ca> 4 * Copyright (c) 2007 Jared D. McNeill <jmcneill@invisible.ca>
5 * All rights reserved. 5 * All rights reserved.
6 * 6 *
7 * Redistribution and use in source and binary forms, with or without 7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions 8 * modification, are permitted provided that the following conditions
9 * are met: 9 * are met:
10 * 1. Redistributions of source code must retain the above copyright 10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer. 11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright 12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the 13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution. 14 * documentation and/or other materials provided with the distribution.
@@ -17,27 +17,27 @@ @@ -17,27 +17,27 @@
17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 18 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE. 26 * POSSIBILITY OF SUCH DAMAGE.
27 */ 27 */
28 28
29#include <sys/cdefs.h> 29#include <sys/cdefs.h>
30__KERNEL_RCSID(0, "$NetBSD: pad.c,v 1.78 2022/03/31 19:30:16 pgoyette Exp $"); 30__KERNEL_RCSID(0, "$NetBSD: pad.c,v 1.79 2023/01/24 08:17:11 mlelstv Exp $");
31 31
32#include <sys/param.h> 32#include <sys/param.h>
33#include <sys/types.h> 33#include <sys/types.h>
34 34
35#include <sys/audioio.h> 35#include <sys/audioio.h>
36#include <sys/buf.h> 36#include <sys/buf.h>
37#include <sys/condvar.h> 37#include <sys/condvar.h>
38#include <sys/conf.h> 38#include <sys/conf.h>
39#include <sys/device.h> 39#include <sys/device.h>
40#include <sys/file.h> 40#include <sys/file.h>
41#include <sys/filedesc.h> 41#include <sys/filedesc.h>
42#include <sys/kauth.h> 42#include <sys/kauth.h>
43#include <sys/kernel.h> 43#include <sys/kernel.h>
@@ -138,27 +138,27 @@ static const struct audio_format pad_for @@ -138,27 +138,27 @@ static const struct audio_format pad_for
138 .encoding = AUDIO_ENCODING_SLINEAR_LE, 138 .encoding = AUDIO_ENCODING_SLINEAR_LE,
139 .validbits = PADPREC, 139 .validbits = PADPREC,
140 .precision = PADPREC, 140 .precision = PADPREC,
141 .channels = PADCHAN, 141 .channels = PADCHAN,
142 .channel_mask = AUFMT_STEREO, 142 .channel_mask = AUFMT_STEREO,
143 .frequency_type = 1, 143 .frequency_type = 1,
144 .frequency = { PADFREQ }, 144 .frequency = { PADFREQ },
145 }, 145 },
146}; 146};
147 147
148extern void padattach(int); 148extern void padattach(int);
149 149
150static int pad_add_block(struct pad_softc *, uint8_t *, int); 150static int pad_add_block(struct pad_softc *, uint8_t *, int);
151static int pad_get_block(struct pad_softc *, pad_block_t *, int); 151static int pad_get_block(struct pad_softc *, pad_block_t *, int, int);
152 152
153static dev_type_open(pad_open); 153static dev_type_open(pad_open);
154 154
155const struct cdevsw pad_cdevsw = { 155const struct cdevsw pad_cdevsw = {
156 .d_open = pad_open, 156 .d_open = pad_open,
157 .d_close = noclose, 157 .d_close = noclose,
158 .d_read = noread, 158 .d_read = noread,
159 .d_write = nowrite, 159 .d_write = nowrite,
160 .d_ioctl = noioctl, 160 .d_ioctl = noioctl,
161 .d_stop = nostop, 161 .d_stop = nostop,
162 .d_tty = notty, 162 .d_tty = notty,
163 .d_poll = nopoll, 163 .d_poll = nopoll,
164 .d_mmap = nommap, 164 .d_mmap = nommap,
@@ -270,61 +270,73 @@ static void @@ -270,61 +270,73 @@ static void
270pad_childdet(device_t self, device_t child) 270pad_childdet(device_t self, device_t child)
271{ 271{
272 struct pad_softc *sc = device_private(self); 272 struct pad_softc *sc = device_private(self);
273 273
274 KASSERT(KERNEL_LOCKED_P()); 274 KASSERT(KERNEL_LOCKED_P());
275 275
276 if (child == sc->sc_audiodev) 276 if (child == sc->sc_audiodev)
277 sc->sc_audiodev = NULL; 277 sc->sc_audiodev = NULL;
278} 278}
279 279
280static int 280static int
281pad_add_block(struct pad_softc *sc, uint8_t *blk, int blksize) 281pad_add_block(struct pad_softc *sc, uint8_t *blk, int blksize)
282{ 282{
283 int l; 283 int foff, flen, tlen;
284 284
285 KASSERT(blksize >= 0); 285 KASSERT(blksize >= 0);
286 KASSERT(mutex_owned(&sc->sc_intr_lock)); 286 KASSERT(mutex_owned(&sc->sc_intr_lock));
287 287
288 if (blksize > PAD_BUFSIZE || 288 if (blksize > PAD_BUFSIZE ||
289 sc->sc_buflen > PAD_BUFSIZE - (unsigned)blksize) 289 sc->sc_buflen > PAD_BUFSIZE - (unsigned)blksize)
290 return ENOBUFS; 290 return ENOBUFS;
291 291
292 if (sc->sc_wpos + blksize <= PAD_BUFSIZE) 292 foff = sc->sc_wpos;
293 memcpy(sc->sc_audiobuf + sc->sc_wpos, blk, blksize); 293 if (sc->sc_wpos + blksize <= PAD_BUFSIZE) {
294 else { 294 flen = blksize;
295 l = PAD_BUFSIZE - sc->sc_wpos; 295 tlen = 0;
296 memcpy(sc->sc_audiobuf + sc->sc_wpos, blk, l); 296 } else {
297 memcpy(sc->sc_audiobuf, blk + l, blksize - l); 297 flen = PAD_BUFSIZE - sc->sc_wpos;
 298 tlen = blksize - flen;
298 } 299 }
299 300
300 sc->sc_wpos += blksize; 301 sc->sc_wpos = foff + blksize;
301 if (sc->sc_wpos >= PAD_BUFSIZE) 302 if (sc->sc_wpos >= PAD_BUFSIZE)
302 sc->sc_wpos -= PAD_BUFSIZE; 303 sc->sc_wpos -= PAD_BUFSIZE;
303 304
 305 /*
 306 * release interrupt lock for bulk copy to audio buffer
 307 */
 308 mutex_exit(&sc->sc_intr_lock);
 309 memcpy(sc->sc_audiobuf + foff, blk, flen);
 310 memcpy(sc->sc_audiobuf, blk + flen, tlen);
 311 mutex_enter(&sc->sc_intr_lock);
 312
304 sc->sc_buflen += blksize; 313 sc->sc_buflen += blksize;
305 cv_broadcast(&sc->sc_condvar); 314 cv_broadcast(&sc->sc_condvar);
306 315
307 return 0; 316 return 0;
308} 317}
309 318
310static int 319static int
311pad_get_block(struct pad_softc *sc, pad_block_t *pb, int maxblksize) 320pad_get_block(struct pad_softc *sc, pad_block_t *pb, int maxblksize, int dowait)
312{ 321{
313 int l, blksize, error; 322 int l, blksize, error;
314 323
315 KASSERT(maxblksize > 0); 324 KASSERT(maxblksize > 0);
316 KASSERT(mutex_owned(&sc->sc_intr_lock)); 325 KASSERT(mutex_owned(&sc->sc_intr_lock));
317 326
 327 if (sc->sc_buflen == 0 && !dowait)
 328 return EAGAIN;
 329
318 while (sc->sc_buflen == 0) { 330 while (sc->sc_buflen == 0) {
319 DPRINTF("%s: wait\n", __func__); 331 DPRINTF("%s: wait\n", __func__);
320 error = cv_wait_sig(&sc->sc_condvar, &sc->sc_intr_lock); 332 error = cv_wait_sig(&sc->sc_condvar, &sc->sc_intr_lock);
321 DPRINTF("%s: wake up %d\n", __func__, err); 333 DPRINTF("%s: wake up %d\n", __func__, err);
322 if (error) 334 if (error)
323 return error; 335 return error;
324 } 336 }
325 blksize = uimin(maxblksize, sc->sc_buflen); 337 blksize = uimin(maxblksize, sc->sc_buflen);
326 338
327 pb->pb_ptr = (sc->sc_audiobuf + sc->sc_rpos); 339 pb->pb_ptr = (sc->sc_audiobuf + sc->sc_rpos);
328 if (sc->sc_rpos + blksize < PAD_BUFSIZE) { 340 if (sc->sc_rpos + blksize < PAD_BUFSIZE) {
329 pb->pb_len = blksize; 341 pb->pb_len = blksize;
330 sc->sc_rpos += blksize; 342 sc->sc_rpos += blksize;
@@ -490,34 +502,40 @@ static int @@ -490,34 +502,40 @@ static int
490fops_pad_read(struct file *fp, off_t *offp, struct uio *uio, kauth_cred_t cred, 502fops_pad_read(struct file *fp, off_t *offp, struct uio *uio, kauth_cred_t cred,
491 int ioflag) 503 int ioflag)
492{ 504{
493 struct pad_softc *sc = fp->f_pad; 505 struct pad_softc *sc = fp->f_pad;
494 506
495 return pad_read(sc, offp, uio, cred, ioflag); 507 return pad_read(sc, offp, uio, cred, ioflag);
496} 508}
497 509
498static int 510static int
499pad_read(struct pad_softc *sc, off_t *offp, struct uio *uio, kauth_cred_t cred, 511pad_read(struct pad_softc *sc, off_t *offp, struct uio *uio, kauth_cred_t cred,
500 int ioflag) 512 int ioflag)
501{ 513{
502 pad_block_t pb; 514 pad_block_t pb;
503 int err; 515 int err, first;
504 516
505 err = 0; 517 err = 0;
 518 first = 1;
506 DPRINTF("%s: resid=%zu\n", __func__, uio->uio_resid); 519 DPRINTF("%s: resid=%zu\n", __func__, uio->uio_resid);
507 while (uio->uio_resid > 0) { 520 while (uio->uio_resid > 0) {
508 mutex_enter(&sc->sc_intr_lock); 521 mutex_enter(&sc->sc_intr_lock);
509 err = pad_get_block(sc, &pb, MIN(uio->uio_resid, INT_MAX)); 522 err = pad_get_block(sc, &pb, MIN(uio->uio_resid, INT_MAX), first);
510 mutex_exit(&sc->sc_intr_lock); 523 mutex_exit(&sc->sc_intr_lock);
 524 first = 0;
 525 if (err == EAGAIN) {
 526 err = 0;
 527 break;
 528 }
511 if (err) 529 if (err)
512 break; 530 break;
513 531
514 DPRINTF("%s: move %d\n", __func__, pb.pb_len); 532 DPRINTF("%s: move %d\n", __func__, pb.pb_len);
515 err = uiomove(pb.pb_ptr, pb.pb_len, uio); 533 err = uiomove(pb.pb_ptr, pb.pb_len, uio);
516 if (err) 534 if (err)
517 break; 535 break;
518 } 536 }
519 537
520 return err; 538 return err;
521} 539}
522 540
523static int 541static int
@@ -547,56 +565,68 @@ pad_set_format(void *opaque, int setmode @@ -547,56 +565,68 @@ pad_set_format(void *opaque, int setmode
547 /* XXX playback only */ 565 /* XXX playback only */
548 pfil->codec = pad_swvol_codec; 566 pfil->codec = pad_swvol_codec;
549 pfil->context = sc; 567 pfil->context = sc;
550 568
551 return 0; 569 return 0;
552} 570}
553 571
554static int 572static int
555pad_start_output(void *opaque, void *block, int blksize, 573pad_start_output(void *opaque, void *block, int blksize,
556 void (*intr)(void *), void *intrarg) 574 void (*intr)(void *), void *intrarg)
557{ 575{
558 struct pad_softc *sc = opaque; 576 struct pad_softc *sc = opaque;
559 int err; 577 int err;
560 int ms; 578 u_int framesize;
 579 int ticks;
561 580
562 KASSERT(mutex_owned(&sc->sc_intr_lock)); 581 KASSERT(mutex_owned(&sc->sc_intr_lock));
563 582
564 sc->sc_intr = intr; 583 sc->sc_intr = intr;
565 sc->sc_intrarg = intrarg; 584 sc->sc_intrarg = intrarg;
566 585
567 DPRINTF("%s: blksize=%d\n", __func__, blksize); 586 DPRINTF("%s: blksize=%d\n", __func__, blksize);
568 err = pad_add_block(sc, block, blksize); 587 err = pad_add_block(sc, block, blksize);
 588 if (err) {
 589 DPRINTF("%s: failed: %d\n", __func__, err);
 590 /* "Silently" drop overflows, but keep pace */
 591 err = 0;
 592 }
 593
 594 framesize = PADCHAN * (PADPREC / NBBY) * PADFREQ;
 595
 596 sc->sc_resid += blksize;
 597 ticks = mstohz(sc->sc_resid * 1000 / framesize);
 598 sc->sc_resid -= hztoms(ticks) * framesize / 1000;
569 599
570 ms = blksize * 1000 / PADCHAN / (PADPREC / NBBY) / PADFREQ; 
571 DPRINTF("%s: callout ms=%d\n", __func__, ms); 600 DPRINTF("%s: callout ms=%d\n", __func__, ms);
572 callout_schedule(&sc->sc_pcallout, mstohz(ms)); 601 callout_schedule(&sc->sc_pcallout, ticks);
573 602
574 return err; 603 return err;
575} 604}
576 605
577static int 606static int
578pad_halt_output(void *opaque) 607pad_halt_output(void *opaque)
579{ 608{
580 struct pad_softc *sc = opaque; 609 struct pad_softc *sc = opaque;
581 610
582 DPRINTF("%s\n", __func__); 611 DPRINTF("%s\n", __func__);
583 KASSERT(mutex_owned(&sc->sc_intr_lock)); 612 KASSERT(mutex_owned(&sc->sc_intr_lock));
584 613
585 callout_halt(&sc->sc_pcallout, &sc->sc_intr_lock); 614 callout_halt(&sc->sc_pcallout, &sc->sc_intr_lock);
586 615
587 sc->sc_intr = NULL; 616 sc->sc_intr = NULL;
588 sc->sc_intrarg = NULL; 617 sc->sc_intrarg = NULL;
589 sc->sc_buflen = 0; 618 sc->sc_buflen = 0;
 619 sc->sc_resid = 0;
590 sc->sc_rpos = sc->sc_wpos = 0; 620 sc->sc_rpos = sc->sc_wpos = 0;
591 621
592 return 0; 622 return 0;
593} 623}
594 624
595static void 625static void
596pad_done_output(void *arg) 626pad_done_output(void *arg)
597{ 627{
598 struct pad_softc *sc = arg; 628 struct pad_softc *sc = arg;
599 629
600 DPRINTF("%s\n", __func__); 630 DPRINTF("%s\n", __func__);
601 631
602 mutex_enter(&sc->sc_intr_lock); 632 mutex_enter(&sc->sc_intr_lock);

cvs diff -r1.16 -r1.17 src/sys/dev/pad/padvar.h (expand / switch to unified diff)

--- src/sys/dev/pad/padvar.h 2021/06/14 18:44:45 1.16
+++ src/sys/dev/pad/padvar.h 2023/01/24 08:17:11 1.17
@@ -1,14 +1,14 @@ @@ -1,14 +1,14 @@
1/* $NetBSD: padvar.h,v 1.16 2021/06/14 18:44:45 riastradh Exp $ */ 1/* $NetBSD: padvar.h,v 1.17 2023/01/24 08:17:11 mlelstv Exp $ */
2 2
3/*- 3/*-
4 * Copyright (c) 2007 Jared D. McNeill <jmcneill@invisible.ca> 4 * Copyright (c) 2007 Jared D. McNeill <jmcneill@invisible.ca>
5 * All rights reserved. 5 * All rights reserved.
6 * 6 *
7 * Redistribution and use in source and binary forms, with or without 7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions 8 * modification, are permitted provided that the following conditions
9 * are met: 9 * are met:
10 * 1. Redistributions of source code must retain the above copyright 10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer. 11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright 12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the 13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution. 14 * documentation and/or other materials provided with the distribution.
@@ -47,16 +47,18 @@ struct pad_softc { @@ -47,16 +47,18 @@ struct pad_softc {
47 kmutex_t sc_lock; 47 kmutex_t sc_lock;
48 kmutex_t sc_intr_lock; 48 kmutex_t sc_intr_lock;
49 callout_t sc_pcallout; 49 callout_t sc_pcallout;
50 50
51 device_t sc_audiodev; 51 device_t sc_audiodev;
52 52
53#define PAD_BUFSIZE 65536 53#define PAD_BUFSIZE 65536
54 uint8_t sc_audiobuf[PAD_BUFSIZE]; 54 uint8_t sc_audiobuf[PAD_BUFSIZE];
55 u_int sc_buflen; 55 u_int sc_buflen;
56 u_int sc_rpos; 56 u_int sc_rpos;
57 u_int sc_wpos; 57 u_int sc_wpos;
58 58
59 uint8_t sc_swvol; 59 uint8_t sc_swvol;
 60
 61 u_int sc_resid;
60}; 62};
61 63
62#endif /* !_SYS_DEV_PAD_PADVAR_H */ 64#endif /* !_SYS_DEV_PAD_PADVAR_H */