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.

NetBSD Home
NetBSD PR Database Search

(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.