Module Name: src
Committed By: nat
Date: Fri Feb 26 13:17:04 UTC 2016
Modified Files:
src/sys/dev/pad: pad.c padvar.h
Log Message:
Allow reads from pad(4) less or greater than PAD_BLKSIZE.
Ensure that audio data is ready before reading.
Addresses PR 39204.
OK jmcneil@.
To generate a diff of this commit:
cvs rdiff -u -r1.23 -r1.24 src/sys/dev/pad/pad.c
cvs rdiff -u -r1.5 -r1.6 src/sys/dev/pad/padvar.h
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/sys/dev/pad/pad.c
diff -u src/sys/dev/pad/pad.c:1.23 src/sys/dev/pad/pad.c:1.24
--- src/sys/dev/pad/pad.c:1.23 Fri Jul 10 21:58:56 2015
+++ src/sys/dev/pad/pad.c Fri Feb 26 13:17:04 2016
@@ -1,4 +1,4 @@
-/* $NetBSD: pad.c,v 1.23 2015/07/10 21:58:56 nat Exp $ */
+/* $NetBSD: pad.c,v 1.24 2016/02/26 13:17:04 nat Exp $ */
/*-
* Copyright (c) 2007 Jared D. McNeill <[email protected]>
@@ -27,7 +27,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: pad.c,v 1.23 2015/07/10 21:58:56 nat Exp $");
+__KERNEL_RCSID(0, "$NetBSD: pad.c,v 1.24 2016/02/26 13:17:04 nat Exp $");
#include <sys/types.h>
#include <sys/param.h>
@@ -43,6 +43,7 @@ __KERNEL_RCSID(0, "$NetBSD: pad.c,v 1.23
#include <sys/vnode.h>
#include <sys/module.h>
#include <sys/atomic.h>
+#include <sys/time.h>
#include <dev/audio_if.h>
#include <dev/audiovar.h>
@@ -316,6 +317,9 @@ pad_open(dev_t dev, int flags, int fmt,
if (atomic_swap_uint(&sc->sc_open, 1) != 0) {
return EBUSY;
}
+
+ getmicrotime(&sc->sc_last);
+ sc->sc_bytes_count = 0;
return 0;
}
@@ -335,14 +339,20 @@ pad_close(dev_t dev, int flags, int fmt,
return 0;
}
+#define PAD_BYTES_PER_SEC (44100 * sizeof(int16_t) * 2)
+#define TIMENEXTREAD (20 * 1000)
+#define BYTESTOSLEEP (PAD_BYTES_PER_SEC / (1000000 / TIMENEXTREAD))
+
int
pad_read(dev_t dev, struct uio *uio, int flags)
{
+ struct timeval now;
+ uint64_t nowusec, lastusec;
pad_softc_t *sc;
pad_block_t pb;
void (*intr)(void *);
void *intrarg;
- int err;
+ int err, wait_ticks;
sc = device_lookup_private(&pad_cd, PADUNIT(dev));
if (sc == NULL)
@@ -354,10 +364,32 @@ pad_read(dev_t dev, struct uio *uio, int
intr = sc->sc_intr;
intrarg = sc->sc_intrarg;
- kpreempt_disable();
while (uio->uio_resid > 0 && !err) {
+ getmicrotime(&now);
+ nowusec = (now.tv_sec * 1000000) + now.tv_usec;
+ lastusec = (sc->sc_last.tv_sec * 1000000) +
+ sc->sc_last.tv_usec;
+ if (lastusec + TIMENEXTREAD > nowusec &&
+ sc->sc_bytes_count >= BYTESTOSLEEP) {
+ wait_ticks = (hz * ((lastusec + TIMENEXTREAD) -
+ nowusec)) / 1000000;
+ if (wait_ticks > 0) {
+ kpause("padwait", TRUE, wait_ticks,
+ &sc->sc_lock);
+ }
+
+ sc->sc_bytes_count -= BYTESTOSLEEP;
+ getmicrotime(&sc->sc_last);
+ } else if (sc->sc_bytes_count >= BYTESTOSLEEP) {
+ sc->sc_bytes_count -= BYTESTOSLEEP;
+ getmicrotime(&sc->sc_last);
+ } else if (lastusec + TIMENEXTREAD <= nowusec)
+ getmicrotime(&sc->sc_last);
+
err = pad_get_block(sc, &pb, min(uio->uio_resid, PAD_BLKSIZE));
if (!err) {
+ sc->sc_bytes_count += pb.pb_len;
+
mutex_exit(&sc->sc_lock);
err = uiomove(pb.pb_ptr, pb.pb_len, uio);
mutex_enter(&sc->sc_lock);
@@ -366,7 +398,9 @@ pad_read(dev_t dev, struct uio *uio, int
if (intr) {
mutex_enter(&sc->sc_intr_lock);
+ kpreempt_disable();
(*intr)(intrarg);
+ kpreempt_enable();
mutex_exit(&sc->sc_intr_lock);
intr = sc->sc_intr;
intrarg = sc->sc_intrarg;
@@ -374,22 +408,13 @@ pad_read(dev_t dev, struct uio *uio, int
continue;
}
err = cv_wait_sig(&sc->sc_condvar, &sc->sc_lock);
- if (err != 0) {
- mutex_exit(&sc->sc_lock);
- kpreempt_enable();
- return err;
- }
+ if (err != 0)
+ break;
+
intr = sc->sc_intr;
intrarg = sc->sc_intrarg;
}
-
- if (intr) {
- mutex_enter(&sc->sc_intr_lock);
- (*intr)(intrarg);
- mutex_exit(&sc->sc_intr_lock);
- }
mutex_exit(&sc->sc_lock);
- kpreempt_enable();
return err;
}
Index: src/sys/dev/pad/padvar.h
diff -u src/sys/dev/pad/padvar.h:1.5 src/sys/dev/pad/padvar.h:1.6
--- src/sys/dev/pad/padvar.h:1.5 Tue Nov 18 01:53:17 2014
+++ src/sys/dev/pad/padvar.h Fri Feb 26 13:17:04 2016
@@ -1,4 +1,4 @@
-/* $NetBSD: padvar.h,v 1.5 2014/11/18 01:53:17 jmcneill Exp $ */
+/* $NetBSD: padvar.h,v 1.6 2016/02/26 13:17:04 nat Exp $ */
/*-
* Copyright (c) 2007 Jared D. McNeill <[email protected]>
@@ -51,6 +51,8 @@ typedef struct pad_softc {
uint32_t sc_rpos, sc_wpos;
uint8_t sc_swvol;
+ struct timeval sc_last;
+ int sc_bytes_count;
} pad_softc_t;
#endif /* !_SYS_DEV_PAD_PADVAR_H */