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 <jmcne...@invisible.ca>
@@ -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 <jmcne...@invisible.ca>
@@ -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 */

Reply via email to