NetBSD Problem Report #46545
From www@NetBSD.org Tue Jun 5 13:01:13 2012
Return-Path: <www@NetBSD.org>
Received: from mail.netbsd.org (mail.netbsd.org [149.20.53.66])
by www.NetBSD.org (Postfix) with ESMTP id 9DAAC63BEE1
for <gnats-bugs@gnats.NetBSD.org>; Tue, 5 Jun 2012 13:01:13 +0000 (UTC)
Message-Id: <20120605130112.DE96F63BA27@www.NetBSD.org>
Date: Tue, 5 Jun 2012 13:01:12 +0000 (UTC)
From: nathanialsloss@yahoo.com.au
Reply-To: nathanialsloss@yahoo.com.au
To: gnats-bugs@NetBSD.org
Subject: pad(4):Support for fullduplex playback/recording polling and nonblocking mode
X-Send-Pr-Version: www-1.0
>Number: 46545
>Category: kern
>Synopsis: pad(4):Support for fullduplex playback/recording polling and nonblocking mode
>Confidential: no
>Severity: serious
>Priority: medium
>Responsible: kern-bug-people
>State: open
>Class: change-request
>Submitter-Id: net
>Arrival-Date: Tue Jun 05 13:05:01 +0000 2012
>Last-Modified: Sat Sep 07 12:00:01 +0000 2013
>Originator: Nat Sloss
>Release: NetBSD Current 6.99.7
>Organization:
>Environment:
NetBSD beast 6.99.7 NetBSD 6.99.7 (LOCKDEBUG) #64: Tue Jun 5 17:42:52 EST 2012 build@beast:/usr/src/sys/arch/i386/compile/obj/LOCKDEBUG i386
>Description:
Hi I have reimplemented bthset to use pad instead of the btsco(4) audio driver (stll not ready for submission). However it is impractical with the current pad as I need it to support recording (full duplex) poll and to be able to be set non blocking. So I have patched pad and padvol to support these.
>How-To-Repeat:
Try to record with pad:
audiorecord -d /dev/'pad audio device' test.snd
>Fix:
I will post the patches in a subsequent email as I'm using the web based sendpr.
Regards,
Nat.
>Audit-Trail:
From: Nat Sloss <nathanialsloss@yahoo.com.au>
To: gnats-bugs@netbsd.org
Cc:
Subject: Re: kern/46545: pad(4):Support for fullduplex playback/recording polling and nonblocking mode
Date: Tue, 5 Jun 2012 23:05:48 +1000
Hi
Here are my patches:
Index: sys/dev/pad/pad.c
===================================================================
RCS file: /cvsroot/src/sys/dev/pad/pad.c,v
retrieving revision 1.19
diff -u -r1.19 pad.c
--- sys/dev/pad/pad.c 24 Nov 2011 01:54:08 -0000 1.19
+++ sys/dev/pad/pad.c 5 Jun 2012 12:27:28 -0000
@@ -33,10 +33,14 @@
#include <sys/param.h>
#include <sys/conf.h>
#include <sys/buf.h>
+#include <sys/errno.h>
+#include <sys/fcntl.h>
+#include <sys/ioctl.h>
#include <sys/kmem.h>
#include <sys/kernel.h>
#include <sys/device.h>
#include <sys/proc.h>
+#include <sys/poll.h>
#include <sys/condvar.h>
#include <sys/select.h>
#include <sys/audioio.h>
@@ -54,7 +58,6 @@
#define PADUNIT(x) minor(x)
extern struct cfdriver pad_cd;
-
typedef struct pad_block {
uint8_t *pb_ptr;
int pb_len;
@@ -63,8 +66,10 @@
enum {
PAD_OUTPUT_CLASS,
PAD_INPUT_CLASS,
+ PAD_RECORD_CLASS,
PAD_OUTPUT_MASTER_VOLUME,
PAD_INPUT_DAC_VOLUME,
+ PAD_INPUT_MIC_VOLUME,
PAD_ENUM_LAST,
};
@@ -84,14 +89,19 @@
static int pad_halt_output(void *);
static int pad_halt_input(void *);
static int pad_getdev(void *, struct audio_device *);
+static int pad_setfd(void *, int);
static int pad_set_port(void *, mixer_ctrl_t *);
static int pad_get_port(void *, mixer_ctrl_t *);
static int pad_query_devinfo(void *, mixer_devinfo_t *);
static int pad_get_props(void *);
static int pad_round_blocksize(void *, int, int, const audio_params_t *);
static void pad_get_locks(void *, kmutex_t **, kmutex_t **);
+static int pad_audio_open(void *,int);
+static void pad_audio_close(void *);
static const struct audio_hw_if pad_hw_if = {
+ .open = pad_audio_open,
+ .close = pad_audio_close,
.query_encoding = pad_query_encoding,
.set_params = pad_set_params,
.start_output = pad_start_output,
@@ -99,6 +109,7 @@
.halt_output = pad_halt_output,
.halt_input = pad_halt_input,
.getdev = pad_getdev,
+ .setfd = pad_setfd,
.set_port = pad_set_port,
.get_port = pad_get_port,
.query_devinfo = pad_query_devinfo,
@@ -115,22 +126,28 @@
extern void padattach(int);
-static int pad_add_block(pad_softc_t *, uint8_t *, int);
-static int pad_get_block(pad_softc_t *, pad_block_t *, int);
+static int pad_add_block_out(pad_softc_t *, uint8_t *, int);
+static int pad_get_block_out(pad_softc_t *, pad_block_t *, int);
+
+static int pad_add_block_in(pad_softc_t *, uint8_t *, int);
+static int pad_get_block_in(pad_softc_t *, pad_block_t *, int);
dev_type_open(pad_open);
dev_type_close(pad_close);
dev_type_read(pad_read);
+dev_type_read(pad_write);
+dev_type_poll(pad_poll);
+dev_type_ioctl(pad_ioctl);
const struct cdevsw pad_cdevsw = {
.d_open = pad_open,
.d_close = pad_close,
.d_read = pad_read,
- .d_write = nowrite,
- .d_ioctl = noioctl,
+ .d_write = pad_write,
+ .d_ioctl = pad_ioctl,
.d_stop = nostop,
.d_tty = notty,
- .d_poll = nopoll,
+ .d_poll = pad_poll,
.d_mmap = nommap,
.d_kqfilter = nokqfilter,
.d_flag = D_OTHER | D_MPSAFE,
@@ -174,47 +191,77 @@
}
static int
-pad_add_block(pad_softc_t *sc, uint8_t *blk, int blksize)
+pad_add_block_out(pad_softc_t *sc, uint8_t *blk, int blksize)
{
int l;
- if (sc->sc_open == 0)
+ if ((sc->sc_open & AUOPEN_READ) == 0)
return EIO;
KASSERT(mutex_owned(&sc->sc_lock));
- if (sc->sc_buflen + blksize > PAD_BUFSIZE)
- return ENOBUFS;
+ if (sc->sc_out_buflen + blksize > PAD_BUFSIZE)
+ return 0;
- if (sc->sc_wpos + blksize <= PAD_BUFSIZE)
- memcpy(sc->sc_audiobuf + sc->sc_wpos, blk, blksize);
+ if (sc->sc_opos + blksize <= PAD_BUFSIZE)
+ memcpy(sc->sc_out_audiobuf + sc->sc_opos, blk, blksize);
else {
- l = PAD_BUFSIZE - sc->sc_wpos;
- memcpy(sc->sc_audiobuf + sc->sc_wpos, blk, l);
- memcpy(sc->sc_audiobuf, blk + l, blksize - l);
+ l = PAD_BUFSIZE - sc->sc_opos;
+ memcpy(sc->sc_out_audiobuf + sc->sc_opos, blk, l);
+ memcpy(sc->sc_out_audiobuf, blk + l, blksize - l);
+ }
+
+ sc->sc_opos += blksize;
+ if (sc->sc_opos > PAD_BUFSIZE)
+ sc->sc_opos -= PAD_BUFSIZE;
+
+ sc->sc_out_buflen += blksize;
+
+ return 0;
+}
+
+static int
+pad_add_block_in(pad_softc_t *sc, uint8_t *blk, int blksize)
+{
+ int l;
+
+ if ((sc->sc_open & AUOPEN_WRITE) == 0)
+ return EIO;
+
+ KASSERT(mutex_owned(&sc->sc_lock));
+
+ if (sc->sc_in_buflen < PAD_BLKSIZE)
+ return 0;
+
+ if (sc->sc_ipos + blksize <= PAD_BUFSIZE)
+ memcpy(blk, sc->sc_in_audiobuf + sc->sc_ipos, blksize);
+ else {
+ l = PAD_BUFSIZE - sc->sc_ipos;
+ memcpy(blk, sc->sc_in_audiobuf + sc->sc_ipos, l);
+ memcpy(blk + l, sc->sc_in_audiobuf, blksize - l);
}
- sc->sc_wpos += blksize;
- if (sc->sc_wpos > PAD_BUFSIZE)
- sc->sc_wpos -= PAD_BUFSIZE;
+ sc->sc_ipos += blksize;
+ if (sc->sc_ipos > PAD_BUFSIZE)
+ sc->sc_ipos -= PAD_BUFSIZE;
- sc->sc_buflen += blksize;
+ sc->sc_in_buflen -= blksize;
return 0;
}
static int
-pad_get_block(pad_softc_t *sc, pad_block_t *pb, int blksize)
+pad_get_block_out(pad_softc_t *sc, pad_block_t *pb, int blksize)
{
int l;
KASSERT(mutex_owned(&sc->sc_lock));
KASSERT(pb != NULL);
- if (sc->sc_buflen < blksize)
+ if (sc->sc_out_buflen < blksize)
return ERESTART;
- pb->pb_ptr = (sc->sc_audiobuf + sc->sc_rpos);
+ pb->pb_ptr = (sc->sc_out_audiobuf + sc->sc_rpos);
if (sc->sc_rpos + blksize < PAD_BUFSIZE) {
pb->pb_len = blksize;
sc->sc_rpos += blksize;
@@ -223,7 +270,32 @@
pb->pb_len = l;
sc->sc_rpos = 0;
}
- sc->sc_buflen -= pb->pb_len;
+ sc->sc_out_buflen -= pb->pb_len;
+
+ return 0;
+}
+
+static int
+pad_get_block_in(pad_softc_t *sc, pad_block_t *pb, int blksize)
+{
+ int l;
+
+ KASSERT(mutex_owned(&sc->sc_lock));
+ KASSERT(pb != NULL);
+
+ if (sc->sc_in_buflen + blksize > PAD_BUFSIZE)
+ return ENOBUFS;
+
+ pb->pb_ptr = (sc->sc_in_audiobuf + sc->sc_wpos);
+ if (sc->sc_wpos + blksize < PAD_BUFSIZE) {
+ pb->pb_len = blksize;
+ sc->sc_wpos += blksize;
+ } else {
+ l = PAD_BUFSIZE - sc->sc_wpos;
+ pb->pb_len = l;
+ sc->sc_wpos = 0;
+ }
+ sc->sc_in_buflen += pb->pb_len;
return 0;
}
@@ -252,19 +324,27 @@
sc->sc_dev = self;
sc->sc_open = 0;
+ sc->sc_flags = 0;
+ sc->sc_mode = 0;
if (auconv_create_encodings(pad_formats, PAD_NFORMATS,
&sc->sc_encodings) != 0) {
aprint_error_dev(self, "couldn't create encodings\n");
return;
}
- cv_init(&sc->sc_condvar, device_xname(self));
+ cv_init(&sc->sc_condvar_in, device_xname(self));
+ cv_init(&sc->sc_condvar_out, device_xname(self));
mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE);
mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_NONE);
sc->sc_swvol = 255;
- sc->sc_buflen = 0;
- sc->sc_rpos = sc->sc_wpos = 0;
+ sc->sc_out_buflen = 0;
+ sc->sc_rpos = sc->sc_opos = 0;
+
+ sc->sc_recvol = 255;
+ sc->sc_in_buflen = 0;
+ sc->sc_wpos = sc->sc_ipos = 0;
+
sc->sc_audiodev = (void *)audio_attach_mi(&pad_hw_if, sc, sc->sc_dev);
if (!pmf_device_register(self, NULL, NULL))
@@ -290,7 +370,8 @@
mutex_destroy(&sc->sc_lock);
mutex_destroy(&sc->sc_intr_lock);
- cv_destroy(&sc->sc_condvar);
+ cv_destroy(&sc->sc_condvar_in);
+ cv_destroy(&sc->sc_condvar_out);
auconv_delete_encodings(sc->sc_encodings);
@@ -306,8 +387,20 @@
if (sc == NULL)
return ENXIO;
- if (atomic_swap_uint(&sc->sc_open, 1) != 0) {
+ if (((flags & FREAD) && (sc->sc_open & AUOPEN_READ)) ||
+ ((flags & FWRITE) && (sc->sc_open & AUOPEN_WRITE)))
return EBUSY;
+
+ if (flags & FREAD) {
+ sc->sc_open |= AUOPEN_READ;
+ sc->sc_out_buflen = 0;
+ sc->sc_rpos = sc->sc_opos = 0;
+ }
+
+ if (flags & FWRITE) {
+ sc->sc_open |= AUOPEN_WRITE;
+ sc->sc_in_buflen = 0;
+ sc->sc_wpos = sc->sc_ipos = 0;
}
return 0;
@@ -323,7 +416,9 @@
return ENXIO;
KASSERT(sc->sc_open > 0);
+
sc->sc_open = 0;
+ sc->sc_flags = 0;
return 0;
}
@@ -335,20 +430,26 @@
pad_block_t pb;
void (*intr)(void *);
void *intrarg;
- int err;
+ int err, timeout;
sc = device_lookup_private(&pad_cd, PADUNIT(dev));
if (sc == NULL)
return ENXIO;
+ if ((sc->sc_open & AUOPEN_READ) == 0)
+ return EIO;
+
err = 0;
+ timeout = mstohz(1000);
+ if (timeout == 0)
+ timeout = 1;
mutex_enter(&sc->sc_lock);
- intr = sc->sc_intr;
- intrarg = sc->sc_intrarg;
+ intr = sc->sc_out_intr;
+ intrarg = sc->sc_out_intrarg;
while (uio->uio_resid > 0 && !err) {
- err = pad_get_block(sc, &pb, min(uio->uio_resid, PAD_BLKSIZE));
+ err = pad_get_block_out(sc, &pb, min(uio->uio_resid, PAD_BLKSIZE));
if (!err) {
mutex_exit(&sc->sc_lock);
err = uiomove(pb.pb_ptr, pb.pb_len, uio);
@@ -360,27 +461,84 @@
mutex_enter(&sc->sc_intr_lock);
(*intr)(intrarg);
mutex_exit(&sc->sc_intr_lock);
- intr = sc->sc_intr;
- intrarg = sc->sc_intrarg;
+ intr = sc->sc_out_intr;
+ intrarg = sc->sc_out_intrarg;
err = 0;
continue;
}
- err = cv_wait_sig(&sc->sc_condvar, &sc->sc_lock);
+
+ if ((sc->sc_flags & O_NONBLOCK) == 0)
+ err = cv_wait_sig(&sc->sc_condvar_out, &sc->sc_lock);
+ else
+ err = cv_timedwait_sig(&sc->sc_condvar_out, &sc->sc_lock, timeout);
+
if (err != 0) {
mutex_exit(&sc->sc_lock);
return err;
}
- intr = sc->sc_intr;
- intrarg = sc->sc_intrarg;
- }
+ intr = sc->sc_out_intr;
+ intrarg = sc->sc_out_intrarg;
- if (intr) {
- mutex_enter(&sc->sc_intr_lock);
- (*intr)(intrarg);
- mutex_exit(&sc->sc_intr_lock);
}
+
mutex_exit(&sc->sc_lock);
+ return err;
+}
+
+int
+pad_write(dev_t dev, struct uio *uio, int flags)
+{
+ pad_softc_t *sc;
+ pad_block_t pb;
+ void (*intr)(void *);
+ void *intrarg;
+ int err;
+
+ sc = device_lookup_private(&pad_cd, PADUNIT(dev));
+ if (sc == NULL)
+ return ENXIO;
+
+ if ((sc->sc_open & AUOPEN_WRITE) == 0)
+ return EIO;
+
+ err = 0;
+
+ mutex_enter(&sc->sc_lock);
+ intr = sc->sc_in_intr;
+ intrarg = sc->sc_in_intrarg;
+
+ while (uio->uio_resid > 0 && !err) {
+ err = pad_get_block_in(sc, &pb, min(uio->uio_resid, PAD_BLKSIZE));
+ if (!err) {
+ mutex_exit(&sc->sc_lock);
+ err = uiomove(pb.pb_ptr, pb.pb_len, uio);
+ if (err != 0)
+ return err;
+ mutex_enter(&sc->sc_lock);
+ continue;
+ }
+
+ if (intr) {
+ mutex_enter(&sc->sc_intr_lock);
+ (*intr)(intrarg);
+ mutex_exit(&sc->sc_intr_lock);
+ intr = sc->sc_in_intr;
+ intrarg = sc->sc_in_intrarg;
+ err = 0;
+ continue;
+ }
+ err = cv_wait_sig(&sc->sc_condvar_in, &sc->sc_lock);
+ if (err != 0) {
+ mutex_exit(&sc->sc_lock);
+ return err;
+ }
+ intr = sc->sc_in_intr;
+ intrarg = sc->sc_in_intrarg;
+
+ }
+
+ mutex_exit(&sc->sc_lock);
return err;
}
@@ -419,11 +577,26 @@
switch (play->encoding) {
case AUDIO_ENCODING_SLINEAR_LE:
if (play->precision == 16 && play->validbits == 16)
- pfil->prepend(pfil, pad_vol_slinear16_le, play);
+ pfil->prepend(pfil, pad_vol_slinear16_le_play, play);
break;
case AUDIO_ENCODING_SLINEAR_BE:
if (play->precision == 16 && play->validbits == 16)
- pfil->prepend(pfil, pad_vol_slinear16_be, play);
+ pfil->prepend(pfil, pad_vol_slinear16_be_play, play);
+ break;
+ default:
+ break;
+ }
+
+ if (rfil->req_size > 0)
+ rec = &rfil->filters[0].param;
+ switch (rec->encoding) {
+ case AUDIO_ENCODING_SLINEAR_LE:
+ if (rec->precision == 16 && rec->validbits == 16)
+ rfil->prepend(rfil, pad_vol_slinear16_le_rec, rec);
+ break;
+ case AUDIO_ENCODING_SLINEAR_BE:
+ if (rec->precision == 16 && rec->validbits == 16)
+ rfil->prepend(rfil, pad_vol_slinear16_be_rec, rec);
break;
default:
break;
@@ -443,13 +616,13 @@
KASSERT(mutex_owned(&sc->sc_lock));
- sc->sc_intr = intr;
- sc->sc_intrarg = intrarg;
+ sc->sc_out_intr = intr;
+ sc->sc_out_intrarg = intrarg;
sc->sc_blksize = blksize;
- err = pad_add_block(sc, block, blksize);
+ err = pad_add_block_out(sc, block, blksize);
- cv_broadcast(&sc->sc_condvar);
+ cv_broadcast(&sc->sc_condvar_out);
return err;
}
@@ -459,12 +632,21 @@
void (*intr)(void *), void *intrarg)
{
pad_softc_t *sc;
+ int err;
sc = (pad_softc_t *)opaque;
KASSERT(mutex_owned(&sc->sc_lock));
- return EOPNOTSUPP;
+ sc->sc_in_intr = intr;
+ sc->sc_in_intrarg = intrarg;
+ sc->sc_blksize = blksize;
+
+ err = pad_add_block_in(sc, block, blksize);
+
+ cv_broadcast(&sc->sc_condvar_in);
+
+ return err;
}
static int
@@ -476,10 +658,10 @@
KASSERT(mutex_owned(&sc->sc_lock));
- sc->sc_intr = NULL;
- sc->sc_intrarg = NULL;
- sc->sc_buflen = 0;
- sc->sc_rpos = sc->sc_wpos = 0;
+ sc->sc_out_intr = NULL;
+ sc->sc_out_intrarg = NULL;
+ sc->sc_out_buflen = 0;
+ sc->sc_rpos = sc->sc_opos = 0;
return 0;
}
@@ -493,6 +675,11 @@
KASSERT(mutex_owned(&sc->sc_lock));
+ sc->sc_in_intr = NULL;
+ sc->sc_in_intrarg = NULL;
+ sc->sc_in_buflen = 0;
+ sc->sc_wpos = sc->sc_ipos = 0;
+
return 0;
}
@@ -507,6 +694,11 @@
}
static int
+pad_setfd(void *hdl, int fd) {
+ return 0;
+}
+
+static int
pad_set_port(void *opaque, mixer_ctrl_t *mc)
{
pad_softc_t *sc;
@@ -520,6 +712,9 @@
case PAD_INPUT_DAC_VOLUME:
sc->sc_swvol = mc->un.value.level[AUDIO_MIXER_LEVEL_MONO];
return 0;
+ case PAD_INPUT_MIC_VOLUME:
+ sc->sc_recvol = mc->un.value.level[AUDIO_MIXER_LEVEL_MONO];
+ return 0;
}
return ENXIO;
@@ -539,6 +734,9 @@
case PAD_INPUT_DAC_VOLUME:
mc->un.value.level[AUDIO_MIXER_LEVEL_MONO] = sc->sc_swvol;
return 0;
+ case PAD_INPUT_MIC_VOLUME:
+ mc->un.value.level[AUDIO_MIXER_LEVEL_MONO] = sc->sc_recvol;
+ return 0;
}
return ENXIO;
@@ -566,6 +764,12 @@
di->type = AUDIO_MIXER_CLASS;
di->next = di->prev = AUDIO_MIXER_LAST;
return 0;
+ case PAD_RECORD_CLASS:
+ di->mixer_class = PAD_RECORD_CLASS;
+ strcpy(di->label.name, AudioCrecord);
+ di->type = AUDIO_MIXER_CLASS;
+ di->next = di->prev = AUDIO_MIXER_LAST;
+ return 0;
case PAD_OUTPUT_MASTER_VOLUME:
di->mixer_class = PAD_OUTPUT_CLASS;
strcpy(di->label.name, AudioNmaster);
@@ -582,6 +786,14 @@
di->un.v.num_channels = 1;
strcpy(di->un.v.units.name, AudioNvolume);
return 0;
+ case PAD_INPUT_MIC_VOLUME:
+ di->mixer_class = PAD_RECORD_CLASS;
+ strcpy(di->label.name, AudioNmicrophone);
+ di->type = AUDIO_MIXER_VALUE;
+ di->next = di->prev = AUDIO_MIXER_LAST;
+ di->un.v.num_channels = 1;
+ strcpy(di->un.v.units.name, AudioNvolume);
+ return 0;
}
return ENXIO;
@@ -596,7 +808,7 @@
KASSERT(mutex_owned(&sc->sc_lock));
- return 0;
+ return AUDIO_PROP_FULLDUPLEX;
}
static int
@@ -622,6 +834,89 @@
*thread = &sc->sc_lock;
}
+int
+pad_poll(dev_t dev, int events, lwp_t *l)
+{
+ pad_softc_t *sc;
+ int revents = 0;
+
+ sc = device_lookup_private(&pad_cd, PADUNIT(dev));
+ if (sc == NULL)
+ return ENXIO;
+
+ mutex_enter(&sc->sc_lock);
+
+ if (events & (POLLIN | POLLRDNORM)) {
+ if ((sc->sc_open & AUOPEN_READ) && (sc->sc_opos > 0)
+ && (sc->sc_mode & AUMODE_PLAY))
+ revents |= events & (POLLIN | POLLRDNORM);
+ }
+
+ if (events & (POLLOUT | POLLWRNORM)) {
+ if ((sc->sc_open & AUOPEN_WRITE) && (sc->sc_mode & AUMODE_RECORD))
+ revents |= events & (POLLOUT | POLLWRNORM);
+ }
+
+ mutex_exit(&sc->sc_lock);
+
+ return revents;
+}
+
+static int
+pad_audio_open(void *hdl, int flags) {
+ struct pad_softc *sc = hdl;
+
+ if (!sc->sc_open)
+ return EIO;
+
+ if (flags & FREAD)
+ sc->sc_mode |= AUMODE_RECORD;
+
+ if (flags & FWRITE)
+ sc->sc_mode |= AUMODE_PLAY;
+
+ sc->sc_out_buflen = 0;
+ sc->sc_rpos = sc->sc_opos = 0;
+
+ sc->sc_in_buflen = 0;
+ sc->sc_wpos = sc->sc_ipos = 0;
+
+ return 0;
+}
+
+static void
+pad_audio_close(void *hdl) {
+ struct pad_softc *sc = hdl;
+
+ sc->sc_mode = 0;
+
+ sc->sc_out_buflen = 0;
+ sc->sc_rpos = sc->sc_opos = 0;
+
+ sc->sc_in_buflen = 0;
+ sc->sc_wpos = sc->sc_ipos = 0;
+
+ return;
+}
+
+int
+pad_ioctl(dev_t dev, u_long cmd, void *addr, int flag, struct lwp *l)
+{
+ pad_softc_t *sc;
+ sc = device_lookup_private(&pad_cd, PADUNIT(dev));
+
+ /* Figure out which lock type we need. */
+ switch (cmd) {
+ case FIONBIO:
+ if (flag == 0)
+ sc->sc_flags &= ~O_NONBLOCK;
+ else
+ sc->sc_flags |= O_NONBLOCK;
+ }
+
+ return 0;
+}
+
#ifdef _MODULE
MODULE(MODULE_CLASS_DRIVER, pad, NULL);
Index: sys/dev/pad/padvar.h
===================================================================
RCS file: /cvsroot/src/sys/dev/pad/padvar.h,v
retrieving revision 1.4
diff -u -r1.4 padvar.h
--- sys/dev/pad/padvar.h 23 Nov 2011 23:07:33 -0000 1.4
+++ sys/dev/pad/padvar.h 5 Jun 2012 12:27:28 -0000
@@ -33,11 +33,16 @@
device_t sc_dev;
u_int sc_open;
+ u_int sc_flags;
+ u_char sc_mode;
struct audio_encoding_set *sc_encodings;
- void (*sc_intr)(void *);
- void *sc_intrarg;
+ void (*sc_out_intr)(void *);
+ void *sc_out_intrarg;
+ void (*sc_in_intr)(void *);
+ void *sc_in_intrarg;
- kcondvar_t sc_condvar;
+ kcondvar_t sc_condvar_in;
+ kcondvar_t sc_condvar_out;
kmutex_t sc_lock;
kmutex_t sc_intr_lock;
@@ -46,11 +51,15 @@
#define PAD_BLKSIZE 1024
#define PAD_BUFSIZE 65536
- uint8_t sc_audiobuf[PAD_BUFSIZE];
- uint32_t sc_buflen;
- uint32_t sc_rpos, sc_wpos;
+ uint8_t sc_out_audiobuf[PAD_BUFSIZE];
+ uint8_t sc_in_audiobuf[PAD_BUFSIZE];
+ uint32_t sc_out_buflen;
+ uint32_t sc_in_buflen;
+ uint32_t sc_rpos, sc_opos;
+ uint32_t sc_wpos, sc_ipos;
u_int sc_swvol;
+ u_int sc_recvol;
} pad_softc_t;
#endif /* !_SYS_DEV_PAD_PADVAR_H */
Index: sys/dev/pad/padvol.c
===================================================================
RCS file: /cvsroot/src/sys/dev/pad/padvol.c,v
retrieving revision 1.6
diff -u -r1.6 padvol.c
--- sys/dev/pad/padvol.c 23 Nov 2011 23:07:33 -0000 1.6
+++ sys/dev/pad/padvol.c 5 Jun 2012 12:27:28 -0000
@@ -72,7 +72,7 @@
return (stream_filter_t *)this;
}
-PAD_DEFINE_FILTER(pad_vol_slinear16_le)
+PAD_DEFINE_FILTER(pad_vol_slinear16_le_play)
{
pad_filter_t *pf;
pad_softc_t *sc;
@@ -98,7 +98,7 @@
return 0;
}
-PAD_DEFINE_FILTER(pad_vol_slinear16_be)
+PAD_DEFINE_FILTER(pad_vol_slinear16_be_play)
{
pad_filter_t *pf;
pad_softc_t *sc;
@@ -123,3 +123,55 @@
return 0;
}
+
+PAD_DEFINE_FILTER(pad_vol_slinear16_le_rec)
+{
+ pad_filter_t *pf;
+ pad_softc_t *sc;
+ stream_filter_t *this;
+ int16_t j, *wp;
+ int m, err;
+
+ pf = (pad_filter_t *)self;
+ sc = device_private(pf->audiosc->sc_dev);
+ this = &pf->base;
+ max_used = (max_used + 1) & ~1;
+
+ if ((err = this->prev->fetch_to(asc, this->prev, this->src, max_used)))
+ return err;
+ m = (dst->end - dst->start) & ~1;
+ m = min(m, max_used);
+ FILTER_LOOP_PROLOGUE(this->src, 2, dst, 2, m) {
+ j = le16dec(s);
+ wp = (int16_t *)d;
+ le16enc(wp, (j * sc->sc_recvol) / 255);
+ } FILTER_LOOP_EPILOGUE(this->src, dst);
+
+ return 0;
+}
+
+PAD_DEFINE_FILTER(pad_vol_slinear16_be_rec)
+{
+ pad_filter_t *pf;
+ pad_softc_t *sc;
+ stream_filter_t *this;
+ int16_t j, *wp;
+ int m, err;
+
+ pf = (pad_filter_t *)self;
+ sc = device_private(pf->audiosc->sc_dev);
+ this = &pf->base;
+ max_used = (max_used + 1) & ~1;
+
+ if ((err = this->prev->fetch_to(asc, this->prev, this->src, max_used)))
+ return err;
+ m = (dst->end - dst->start) & ~1;
+ m = min(m, max_used);
+ FILTER_LOOP_PROLOGUE(this->src, 2, dst, 2, m) {
+ j = be16dec(s);
+ wp = (int16_t *)d;
+ be16enc(wp, (j * sc->sc_recvol) / 255);
+ } FILTER_LOOP_EPILOGUE(this->src, dst);
+
+ return 0;
+}
Index: sys/dev/pad/padvol.h
===================================================================
RCS file: /cvsroot/src/sys/dev/pad/padvol.h,v
retrieving revision 1.3
diff -u -r1.3 padvol.h
--- sys/dev/pad/padvol.h 23 Nov 2011 23:07:33 -0000 1.3
+++ sys/dev/pad/padvol.h 5 Jun 2012 12:27:28 -0000
@@ -29,9 +29,13 @@
#ifndef _SYS_DEV_PAD_PADVOL_H
#define _SYS_DEV_PAD_PADVOL_H
-stream_filter_t * pad_vol_slinear16_le(struct audio_softc *,
+stream_filter_t * pad_vol_slinear16_le_play(struct audio_softc *,
const audio_params_t *, const audio_params_t *);
-stream_filter_t * pad_vol_slinear16_be(struct audio_softc *,
+stream_filter_t * pad_vol_slinear16_be_play(struct audio_softc *,
+ const audio_params_t *, const audio_params_t *);
+stream_filter_t * pad_vol_slinear16_le_rec(struct audio_softc *,
+ const audio_params_t *, const audio_params_t *);
+stream_filter_t * pad_vol_slinear16_be_rec(struct audio_softc *,
const audio_params_t *, const audio_params_t *);
#define PAD_DEFINE_FILTER(name) \
Note: These patches are derived from pad/padvol.c and are my own work which I
submit under the NetBSD license.
Regards,
Nat.
From: Iain Hibbert <plunky@ogmig.net>
To: gnats-bugs@netbsd.org
Cc:
Subject: Re: kern/46545: pad(4):Support for fullduplex playback/recording
polling and nonblocking mode
Date: Thu, 5 Sep 2013 20:32:13 +0100 (BST)
Hi
As this is a prerequisite of PR/48060 I took a look; it seems reasonable
but I'm not sure why but I got a kernel crash when trying out your
example. perhaps locking is not quite right.. unfortunately I have not had
much time to look at it, and this laptop is not very good for
investigating such things (the message buffer is cleared at reset)
regards,
iain
From: Iain Hibbert <plunky@ogmig.net>
To: gnats-bugs@netbsd.org
Cc:
Subject: Re: kern/46545: pad(4):Support for fullduplex playback/recording
polling and nonblocking mode
Date: Thu, 5 Sep 2013 20:33:28 +0100 (BST)
On Thu, 5 Sep 2013, Iain Hibbert wrote:
> As this is a prerequisite of PR/48060 I took a look; it seems reasonable
> but I'm not sure why but I got a kernel crash when trying out your
> example. perhaps locking is not quite right..
I forgot to say, I am running on a dual core i386 machine
regards,
iain
From: Nat Sloss <nathanialsloss@yahoo.com.au>
To: gnats-bugs@netbsd.org
Cc:
Subject: Re: kern/46545: pad(4):Support for fullduplex playback/recording polling and nonblocking mode
Date: Fri, 6 Sep 2013 12:03:49 +1000
Hi Iain,
Sorry to hear about the crash.
I'm still running 5.01 dual core i386 with audio and pad sources from 5.99.
I rewrote my changes to bthset for NetBSD current and they compiled. But I
didn't test thouroughly I'll investigate further.
I have to update.
Do you think the crash is related to my changes to pad or bthset?
You can test changes to pad by recording some audio with pad and piping it
back in.
I'll update my NetBSD current sources, apply the patches and test in qemu.
I'll have to update to 6.11 but I have make a plan to do it.
My laptop has a serial port so I should be able to log the crash.
Regards,
Nat.
From: Nat Sloss <nathanialsloss@yahoo.com.au>
To: gnats-bugs@netbsd.org
Cc: plunky@ogmig.net
Subject: Re: kern/46545: pad(4):Support for fullduplex playback/recording polling and nonblocking mode
Date: Sat, 7 Sep 2013 19:35:26 +1000
Hi
I've just built a stock 6.99.23 and tested pad with and without the patch.
Both break, here is the backtrace with the stock pad driver:
panic: kernel diagnostic assertion "kpreempt_disabled()" failed:
file "/home/build/NetBSD-current_source_tree/src/sys/kern/kern_softint.c",
line 461
cpu0: Begin traceback...
vpanic(c0c04b2c,c8775b00,c8775b18,c05ac07d,c0c04b2c,c0c04cdd,c0c57362,c0c61610,1cd,400)
at netbsd:vpanic+0x11c
kern_assert(c0c04b2c,c0c04cdd,c0c57362,c0c61610,1cd,400,c15f3800,c8775b64,c01fb119,368)
at netbsd:kern_assert+0x23
softint_schedule(368,c160e400,400,c01fadfc,c15f3800,0,c14fddc0,0,c165f430,c165f020)
at netbsd:softint_schedule+0xec
audio_pint(c15f3800,400,c8775c7c,c080787e,bd00,c165f014,c165f024,c15f3800,c01fadfc,0)
at netbsd:audio_pint+0x31d
pad_read(bd00,0,c8775c7c,0,0,c8775be4,c035e6e0,c19dcaf8,0,1) at
netbsd:pad_read+0x158
spec_read(c8775c1c,1,0,c0bf4268,c19dca54,c8775c7c,0,c1398a80,0,c8775c5c) at
netbsd:spec_read+0x21b
VOP_READ(c19dca54,c8775c7c,0,c1398a80,4000,4000,3,bb901000,c8775cac,c082f19d)
at netbsd:VOP_READ+0x38
vn_read(c16b4740,c16b4740,c8775c7c,c1398a80,1,bb900000,c8775c98,1,400,0) at
netbsd:vn_read+0x81
dofileread(3,c16b4740,bb901000,4000,c16b4740,1,c8775d28,c17072a0,c0e5ebe4,c8775d3c)
at netbsd:dofileread+0x6d
sys_read(c17072a0,c8775d00,c8775d28,c15d74f8,0,c8775d00,3,c8775da0,3,bb901000)
at netbsd:sys_read+0x60
syscall() at netbsd:syscall+0x89
--- syscall (number 3) ---
bba99077:
cpu0: End traceback...
So pad in does not work in 6.99.23
Although I've found a problem with my patch whilst attempting to use audio
record and inputting a file into the pad device - an IO error and audiorecord
just exits. This was not a problem in 6.99.7 so I'll try to find out why.
Regards,
Nat.
From: matthew green <mrg@eterna.com.au>
To: gnats-bugs@NetBSD.org
Cc: kern-bug-people@netbsd.org, gnats-admin@netbsd.org,
netbsd-bugs@netbsd.org, nathanialsloss@yahoo.com.au
Subject: re: kern/46545: pad(4):Support for fullduplex playback/recording polling and nonblocking mode
Date: Sat, 07 Sep 2013 20:16:04 +1000
> softint_schedule(368,c160e400,400,c01fadfc,c15f3800,0,c14fddc0,0,c165f430,c165f020)
> at netbsd:softint_schedule+0xec
>
> audio_pint(c15f3800,400,c8775c7c,c080787e,bd00,c165f014,c165f024,c15f3800,c01fadfc,0)
> at netbsd:audio_pint+0x31d
softint_schedule() must be called with kernel preemption disabled.
ie, call kpreempt_disable() before and kpreempt_enable() around
calling softint_schedule().
.mrg.
From: Nat Sloss <nathanialsloss@yahoo.com.au>
To: gnats-bugs@netbsd.org
Cc: plunky@ogmig.net
Subject: Re: kern/46545: pad(4):Support for fullduplex playback/recording polling and nonblocking mode
Date: Sat, 7 Sep 2013 21:32:12 +1000
Hi,
Here is a patch to the patched version of pad (Thanks to mrg for identifying
the problem):
--- pad.c.patched 2013-09-07 21:25:35.000000000 +1000
+++ pad.c 2013-09-07 20:32:57.000000000 +1000
@@ -459,7 +459,9 @@
if (intr) {
mutex_enter(&sc->sc_intr_lock);
+ kpreempt_disable();
(*intr)(intrarg);
+ kpreempt_enable();
mutex_exit(&sc->sc_intr_lock);
intr = sc->sc_out_intr;
intrarg = sc->sc_out_intrarg;
@@ -520,7 +522,9 @@
if (intr) {
mutex_enter(&sc->sc_intr_lock);
+ kpreempt_disable();
(*intr)(intrarg);
+ kpreempt_enable();
mutex_exit(&sc->sc_intr_lock);
intr = sc->sc_in_intr;
intrarg = sc->sc_in_intrarg;
And I found out why I received an IO error whilst using audiorecord with pad
the file that I inputted to pad was small and by the time it was starting to
record the pad device is closed. Hopfully this is not a problem with my
modified bthset.
Regards,
Nat.
(Contact us)
$NetBSD: query-full-pr,v 1.39 2013/11/01 18:47:49 spz Exp $
$NetBSD: gnats_config.sh,v 1.8 2006/05/07 09:23:38 tsutsui Exp $
Copyright © 1994-2007
The NetBSD Foundation, Inc. ALL RIGHTS RESERVED.