Home | History | Annotate | Line # | Download | only in pad
pad.c revision 1.45
      1 /* $NetBSD: pad.c,v 1.45 2017/12/15 23:57:42 pgoyette Exp $ */
      2 
      3 /*-
      4  * Copyright (c) 2007 Jared D. McNeill <jmcneill (at) invisible.ca>
      5  * All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  * 2. Redistributions in binary form must reproduce the above copyright
     13  *    notice, this list of conditions and the following disclaimer in the
     14  *    documentation and/or other materials provided with the distribution.
     15  *
     16  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     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
     19  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     20  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     21  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     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
     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
     26  * POSSIBILITY OF SUCH DAMAGE.
     27  */
     28 
     29 #include <sys/cdefs.h>
     30 __KERNEL_RCSID(0, "$NetBSD: pad.c,v 1.45 2017/12/15 23:57:42 pgoyette Exp $");
     31 
     32 #include <sys/types.h>
     33 #include <sys/param.h>
     34 #include <sys/conf.h>
     35 #include <sys/buf.h>
     36 #include <sys/file.h>
     37 #include <sys/filedesc.h>
     38 #include <sys/vnode.h>
     39 #include <sys/kauth.h>
     40 #include <sys/kmem.h>
     41 #include <sys/kernel.h>
     42 #include <sys/device.h>
     43 #include <sys/proc.h>
     44 #include <sys/condvar.h>
     45 #include <sys/select.h>
     46 #include <sys/stat.h>
     47 #include <sys/audioio.h>
     48 #include <sys/vnode.h>
     49 #include <sys/module.h>
     50 #include <sys/atomic.h>
     51 #include <sys/time.h>
     52 
     53 #include <dev/audio_if.h>
     54 #include <dev/audiovar.h>
     55 #include <dev/auconv.h>
     56 #include <dev/auvolconv.h>
     57 
     58 #include <dev/pad/padvar.h>
     59 
     60 #define MAXDEVS		128
     61 #define PADCLONER	254
     62 #define PADUNIT(x)	minor(x)
     63 
     64 #define PADFREQ		44100
     65 #define PADCHAN		2
     66 #define PADPREC		16
     67 #define PADENC		AUDIO_ENCODING_SLINEAR_LE
     68 
     69 extern struct cfdriver pad_cd;
     70 
     71 typedef struct pad_block {
     72 	uint8_t		*pb_ptr;
     73 	int		pb_len;
     74 } pad_block_t;
     75 
     76 enum {
     77 	PAD_OUTPUT_CLASS,
     78 	PAD_INPUT_CLASS,
     79 	PAD_OUTPUT_MASTER_VOLUME,
     80 	PAD_INPUT_DAC_VOLUME,
     81 	PAD_ENUM_LAST,
     82 };
     83 
     84 static int	pad_match(device_t, cfdata_t, void *);
     85 static void	pad_attach(device_t, device_t, void *);
     86 static int	pad_detach(device_t, int);
     87 static void	pad_childdet(device_t, device_t);
     88 
     89 static int	pad_audio_open(void *, int);
     90 static int	pad_query_encoding(void *, struct audio_encoding *);
     91 static int	pad_set_params(void *, int, int,
     92 				audio_params_t *, audio_params_t *,
     93 				stream_filter_list_t *, stream_filter_list_t *);
     94 static int	pad_start_output(void *, void *, int,
     95 				    void (*)(void *), void *);
     96 static int	pad_start_input(void *, void *, int,
     97 				   void (*)(void *), void *);
     98 static int	pad_halt_output(void *);
     99 static int	pad_halt_input(void *);
    100 static int	pad_getdev(void *, struct audio_device *);
    101 static int	pad_set_port(void *, mixer_ctrl_t *);
    102 static int	pad_get_port(void *, mixer_ctrl_t *);
    103 static int	pad_query_devinfo(void *, mixer_devinfo_t *);
    104 static int	pad_get_props(void *);
    105 static int	pad_round_blocksize(void *, int, int, const audio_params_t *);
    106 static void	pad_get_locks(void *, kmutex_t **, kmutex_t **);
    107 
    108 static stream_filter_t *pad_swvol_filter_le(struct audio_softc *,
    109     const audio_params_t *, const audio_params_t *);
    110 static stream_filter_t *pad_swvol_filter_be(struct audio_softc *,
    111     const audio_params_t *, const audio_params_t *);
    112 static void	pad_swvol_dtor(stream_filter_t *);
    113 
    114 static int pad_close(struct pad_softc *);
    115 static int pad_read(struct pad_softc *, off_t *, struct uio *, kauth_cred_t, int);
    116 
    117 static int fops_pad_close(struct file *);
    118 static int fops_pad_read(struct file *, off_t *, struct uio *, kauth_cred_t, int);
    119 static int pad_write(struct file *, off_t *, struct uio *, kauth_cred_t, int);
    120 static int pad_ioctl(struct file *, u_long, void *);
    121 static int pad_kqfilter(struct file *, struct knote *);
    122 static int pad_poll(struct file *, int);
    123 static int pad_stat(struct file *, struct stat *);
    124 static int pad_mmap(struct file *, off_t *, size_t, int, int *, int *,
    125 			   struct uvm_object **, int *);
    126 
    127 static const struct audio_hw_if pad_hw_if = {
    128 	.open = pad_audio_open,
    129 	.query_encoding = pad_query_encoding,
    130 	.set_params = pad_set_params,
    131 	.start_output = pad_start_output,
    132 	.start_input = pad_start_input,
    133 	.halt_output = pad_halt_output,
    134 	.halt_input = pad_halt_input,
    135 	.getdev = pad_getdev,
    136 	.set_port = pad_set_port,
    137 	.get_port = pad_get_port,
    138 	.query_devinfo = pad_query_devinfo,
    139 	.get_props = pad_get_props,
    140 	.round_blocksize = pad_round_blocksize,
    141 	.get_locks = pad_get_locks,
    142 };
    143 
    144 #define PAD_NFORMATS	1
    145 static const struct audio_format pad_formats[PAD_NFORMATS] = {
    146 	{ NULL, AUMODE_PLAY|AUMODE_RECORD, PADENC, PADPREC, PADPREC,
    147 	  PADCHAN, AUFMT_STEREO, 1, { PADFREQ } },
    148 };
    149 
    150 extern void	padattach(int);
    151 
    152 static int	pad_add_block(pad_softc_t *, uint8_t *, int);
    153 static int	pad_get_block(pad_softc_t *, pad_block_t *, int);
    154 
    155 dev_type_open(pad_open);
    156 dev_type_close(cdev_pad_close);
    157 dev_type_read(cdev_pad_read);
    158 
    159 const struct cdevsw pad_cdevsw = {
    160 	.d_open = pad_open,
    161 	.d_close = cdev_pad_close,
    162 	.d_read = cdev_pad_read,
    163 	.d_write = nowrite,
    164 	.d_ioctl = noioctl,
    165 	.d_stop = nostop,
    166 	.d_tty = notty,
    167 	.d_poll = nopoll,
    168 	.d_mmap = nommap,
    169 	.d_kqfilter = nokqfilter,
    170 	.d_discard = nodiscard,
    171 	.d_flag = D_OTHER | D_MPSAFE,
    172 };
    173 
    174 const struct fileops pad_fileops = {
    175 	.fo_name = "pad",
    176 	.fo_read = fops_pad_read,
    177 	.fo_write = pad_write,
    178 	.fo_ioctl = pad_ioctl,
    179 	.fo_fcntl = fnullop_fcntl,
    180 	.fo_stat = pad_stat,
    181 	.fo_poll = pad_poll,
    182 	.fo_close = fops_pad_close,
    183 	.fo_mmap = pad_mmap,
    184 	.fo_kqfilter = pad_kqfilter,
    185 	.fo_restart = fnullop_restart
    186 };
    187 
    188 CFATTACH_DECL2_NEW(pad, sizeof(pad_softc_t), pad_match, pad_attach, pad_detach,
    189     NULL, NULL, pad_childdet);
    190 
    191 void
    192 padattach(int n)
    193 {
    194 	int error;
    195 
    196 	error = config_cfattach_attach(pad_cd.cd_name, &pad_ca);
    197 	if (error) {
    198 		aprint_error("%s: couldn't register cfattach: %d\n",
    199 		    pad_cd.cd_name, error);
    200 		config_cfdriver_detach(&pad_cd);
    201 		return;
    202 	}
    203 
    204 	return;
    205 }
    206 
    207 static int
    208 pad_add_block(pad_softc_t *sc, uint8_t *blk, int blksize)
    209 {
    210 	int l;
    211 
    212 	if (sc->sc_open == 0)
    213 		return EIO;
    214 
    215 	KASSERT(mutex_owned(&sc->sc_lock));
    216 
    217 	if (sc->sc_buflen + blksize > PAD_BUFSIZE)
    218 		return ENOBUFS;
    219 
    220 	if (sc->sc_wpos + blksize <= PAD_BUFSIZE)
    221 		memcpy(sc->sc_audiobuf + sc->sc_wpos, blk, blksize);
    222 	else {
    223 		l = PAD_BUFSIZE - sc->sc_wpos;
    224 		memcpy(sc->sc_audiobuf + sc->sc_wpos, blk, l);
    225 		memcpy(sc->sc_audiobuf, blk + l, blksize - l);
    226 	}
    227 
    228 	sc->sc_wpos += blksize;
    229 	if (sc->sc_wpos > PAD_BUFSIZE)
    230 		sc->sc_wpos -= PAD_BUFSIZE;
    231 
    232 	sc->sc_buflen += blksize;
    233 
    234 	return 0;
    235 }
    236 
    237 static int
    238 pad_get_block(pad_softc_t *sc, pad_block_t *pb, int blksize)
    239 {
    240 	int l;
    241 
    242 	KASSERT(mutex_owned(&sc->sc_lock));
    243 	KASSERT(pb != NULL);
    244 
    245 	if (sc->sc_buflen < (uint)blksize)
    246 		return ERESTART;
    247 
    248 	pb->pb_ptr = (sc->sc_audiobuf + sc->sc_rpos);
    249 	if (sc->sc_rpos + blksize < PAD_BUFSIZE) {
    250 		pb->pb_len = blksize;
    251 		sc->sc_rpos += blksize;
    252 	} else {
    253 		l = PAD_BUFSIZE - sc->sc_rpos;
    254 		pb->pb_len = l;
    255 		sc->sc_rpos = 0;
    256 	}
    257 	sc->sc_buflen -= pb->pb_len;
    258 
    259 	return 0;
    260 }
    261 
    262 static int
    263 pad_match(device_t parent, cfdata_t data, void *opaque)
    264 {
    265 
    266 	return 1;
    267 }
    268 
    269 static void
    270 pad_childdet(device_t self, device_t child)
    271 {
    272 	pad_softc_t *sc = device_private(self);
    273 
    274 	sc->sc_audiodev = NULL;
    275 }
    276 
    277 static void
    278 pad_attach(device_t parent, device_t self, void *opaque)
    279 {
    280 	aprint_normal_dev(self, "outputs: 44100Hz, 16-bit, stereo\n");
    281 
    282 	return;
    283 }
    284 
    285 static int
    286 pad_detach(device_t self, int flags)
    287 {
    288 	pad_softc_t *sc;
    289 	int cmaj, mn, rc;
    290 
    291 	sc = device_private(self);
    292 	config_deactivate(sc->sc_audiodev);
    293 
    294 	/* Start draining existing accessors of the device. */
    295 	if ((rc = config_detach_children(self, flags)) != 0)
    296 		return rc;
    297 
    298 	mutex_enter(&sc->sc_lock);
    299 	sc->sc_dying = true;
    300 	cv_broadcast(&sc->sc_condvar);
    301 	mutex_exit(&sc->sc_lock);
    302 
    303 	KASSERT(sc->sc_open > 0);
    304 	sc->sc_open = 0;
    305 
    306 	cmaj = cdevsw_lookup_major(&pad_cdevsw);
    307 	mn = device_unit(sc->sc_dev);
    308 	vdevgone(cmaj, mn, mn, VCHR);
    309 
    310 	pmf_device_deregister(sc->sc_dev);
    311 
    312 	mutex_destroy(&sc->sc_lock);
    313 	mutex_destroy(&sc->sc_intr_lock);
    314 	cv_destroy(&sc->sc_condvar);
    315 
    316 	auconv_delete_encodings(sc->sc_encodings);
    317 
    318 	return 0;
    319 }
    320 
    321 int
    322 pad_open(dev_t dev, int flags, int fmt, struct lwp *l)
    323 {
    324 	pad_softc_t *sc;
    325 	struct file *fp;
    326 	device_t paddev;
    327 	cfdata_t cf;
    328 	int error, fd, i;
    329 
    330 	if (PADUNIT(dev) == PADCLONER) {
    331 		for (i = 0; i < MAXDEVS; i++) {
    332 			if (device_lookup(&pad_cd, i) == NULL)
    333 				break;
    334 		}
    335 		if (i == MAXDEVS)
    336 			return ENXIO;
    337 	} else {
    338 		if (PADUNIT(dev) >= MAXDEVS)
    339 			return ENXIO;
    340 		i = PADUNIT(dev);
    341 	}
    342 
    343 	cf = kmem_alloc(sizeof(struct cfdata), KM_SLEEP);
    344 	cf->cf_name = pad_cd.cd_name;
    345 	cf->cf_atname = pad_cd.cd_name;
    346 	cf->cf_unit = i;
    347 	cf->cf_fstate = FSTATE_STAR;
    348 
    349 	if (device_lookup(&pad_cd, minor(dev)) == NULL)
    350 		paddev = config_attach_pseudo(cf);
    351 	else
    352 		paddev = device_lookup(&pad_cd, minor(dev));
    353 
    354 	sc = device_private(paddev);
    355 	if (sc == NULL)
    356 		return ENXIO;
    357 
    358 	if (sc->sc_open == 1)
    359 		return EBUSY;
    360 
    361 	sc->sc_dev = paddev;
    362 	sc->sc_dying = false;
    363 
    364 	if (PADUNIT(dev) == PADCLONER) {
    365 		error = fd_allocfile(&fp, &fd);
    366 		if (error) {
    367 			config_detach(sc->sc_dev, 0);
    368 			return error;
    369 		}
    370 	}
    371 
    372 	if (auconv_create_encodings(pad_formats, PAD_NFORMATS,
    373 	    &sc->sc_encodings) != 0) {
    374 		aprint_error_dev(sc->sc_dev, "couldn't create encodings\n");
    375 		config_detach(sc->sc_dev, 0);
    376 		return EINVAL;
    377 	}
    378 
    379 	cv_init(&sc->sc_condvar, device_xname(sc->sc_dev));
    380 	mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE);
    381 	mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_NONE);
    382 
    383 	sc->sc_swvol = 255;
    384 	sc->sc_buflen = 0;
    385 	sc->sc_rpos = sc->sc_wpos = 0;
    386 	sc->sc_audiodev = audio_attach_mi(&pad_hw_if, sc, sc->sc_dev);
    387 
    388 	if (!pmf_device_register(sc->sc_dev, NULL, NULL))
    389 		aprint_error_dev(sc->sc_dev, "couldn't establish power handler\n");
    390 
    391 	if (PADUNIT(dev) == PADCLONER) {
    392 		error = fd_clone(fp, fd, flags, &pad_fileops, sc);
    393 		KASSERT(error == EMOVEFD);
    394 	}
    395 	sc->sc_open = 1;
    396 
    397 	return error;
    398 }
    399 
    400 static int
    401 pad_close(struct pad_softc *sc)
    402 {
    403 	if (sc == NULL)
    404 		return ENXIO;
    405 
    406 	return config_detach(sc->sc_dev, DETACH_FORCE);
    407 }
    408 
    409 static int
    410 fops_pad_close(struct file *fp)
    411 {
    412 	pad_softc_t *sc;
    413 	int error;
    414 
    415 	sc = fp->f_pad;
    416 
    417 	error = pad_close(sc);
    418 
    419 	if (error == 0)
    420 		fp->f_pad = NULL;
    421 
    422 	return error;
    423 }
    424 
    425 int
    426 cdev_pad_close(dev_t dev, int flags, int ifmt, struct lwp *l)
    427 {
    428 	pad_softc_t *sc;
    429 	sc = device_private(device_lookup(&pad_cd, PADUNIT(dev)));
    430 
    431 	return pad_close(sc);
    432 }
    433 
    434 static int
    435 pad_poll(struct file *fp, int events)
    436 {
    437 	return ENODEV;
    438 }
    439 
    440 static int
    441 pad_kqfilter(struct file *fp, struct knote *kn)
    442 {
    443 	struct pad_softc *sc;
    444 	dev_t dev;
    445 
    446 	sc = fp->f_pad;
    447 	if (sc == NULL)
    448 		return EIO;
    449 
    450 	dev = makedev(cdevsw_lookup_major(&pad_cdevsw), device_unit(sc->sc_dev));
    451 
    452 	return seltrue_kqfilter(dev, kn);
    453 }
    454 
    455 static int
    456 pad_ioctl(struct file *fp, u_long cmd, void *data)
    457 {
    458 	return ENODEV;
    459 }
    460 
    461 static int
    462 pad_stat(struct file *fp, struct stat *st)
    463 {
    464 	struct pad_softc *sc;
    465 
    466 	sc = fp->f_pad;
    467 	if (sc == NULL)
    468 		return EIO;
    469 
    470 	memset(st, 0, sizeof(*st));
    471 
    472 	st->st_dev = makedev(cdevsw_lookup_major(&pad_cdevsw), device_unit(sc->sc_dev));
    473 
    474 	st->st_uid = kauth_cred_geteuid(fp->f_cred);
    475 	st->st_gid = kauth_cred_getegid(fp->f_cred);
    476 	st->st_mode = S_IFCHR;
    477 
    478 	return 0;
    479 }
    480 
    481 static int
    482 pad_mmap(struct file *fp, off_t *offp, size_t len, int prot, int *flagsp,
    483 	     int *advicep, struct uvm_object **uobjp, int *maxprotp)
    484 {
    485 	return 1;
    486 }
    487 
    488 #define PAD_BYTES_PER_SEC   (PADFREQ * PADPREC / NBBY * PADCHAN)
    489 #define BYTESTOSLEEP	    (int64_t)(PAD_BLKSIZE)
    490 #define TIMENEXTREAD	    (int64_t)(BYTESTOSLEEP * 1000000 / PAD_BYTES_PER_SEC)
    491 
    492 int
    493 cdev_pad_read(dev_t dev, struct uio *uio, int ioflag)
    494 {
    495 	pad_softc_t *sc;
    496 	sc = device_private(device_lookup(&pad_cd, PADUNIT(dev)));
    497 	if (sc == NULL)
    498 		return ENXIO;
    499 
    500 	return pad_read(sc, NULL, uio, NULL, ioflag);
    501 }
    502 
    503 static int
    504 fops_pad_read(struct file *fp, off_t *offp, struct uio *uio, kauth_cred_t cred,
    505 	  int ioflag)
    506 {
    507 	pad_softc_t *sc;
    508 
    509 	sc = fp->f_pad;
    510 	if (sc == NULL)
    511 		return ENXIO;
    512 
    513 	return pad_read(sc, offp, uio, cred, ioflag);
    514 }
    515 
    516 static int
    517 pad_read(struct pad_softc *sc, off_t *offp, struct uio *uio, kauth_cred_t cred,
    518 	  int ioflag)
    519 {
    520 	struct timeval now;
    521 	uint64_t nowusec, lastusec;
    522 	pad_block_t pb;
    523 	void (*intr)(void *);
    524 	void *intrarg;
    525 	int err, wait_ticks;
    526 
    527 	err = 0;
    528 
    529 	while (uio->uio_resid > 0 && !err) {
    530 		mutex_enter(&sc->sc_lock);
    531 		if (sc->sc_dying == true) {
    532 			mutex_exit(&sc->sc_lock);
    533 			return EIO;
    534 		}
    535 		intr = sc->sc_intr;
    536 		intrarg = sc->sc_intrarg;
    537 
    538 		getmicrotime(&now);
    539 		nowusec = (now.tv_sec * 1000000) + now.tv_usec;
    540 		lastusec = (sc->sc_last.tv_sec * 1000000) +
    541 		     sc->sc_last.tv_usec;
    542 		if (lastusec + TIMENEXTREAD > nowusec) {
    543 			if (sc->sc_bytes_count >= BYTESTOSLEEP) {
    544 				sc->sc_remainder +=
    545 				    ((lastusec + TIMENEXTREAD) - nowusec);
    546 			}
    547 
    548 			wait_ticks = (hz * sc->sc_remainder) / 1000000;
    549 			if (wait_ticks > 0) {
    550 				sc->sc_remainder -= wait_ticks * 1000000 / hz;
    551 				err = kpause("padwait", TRUE, wait_ticks,
    552 				    &sc->sc_lock);
    553 				if (err != EWOULDBLOCK) {
    554 					mutex_exit(&sc->sc_lock);
    555 					continue;
    556 				}
    557 			}
    558 		}
    559 
    560 		if (sc->sc_bytes_count >= BYTESTOSLEEP)
    561 			sc->sc_bytes_count -= BYTESTOSLEEP;
    562 
    563 		err = pad_get_block(sc, &pb, min(uio->uio_resid, PAD_BLKSIZE));
    564 		if (!err) {
    565 			getmicrotime(&sc->sc_last);
    566 			sc->sc_bytes_count += pb.pb_len;
    567 			mutex_exit(&sc->sc_lock);
    568 			err = uiomove(pb.pb_ptr, pb.pb_len, uio);
    569 			continue;
    570 		}
    571 
    572 		if (intr) {
    573 			mutex_enter(&sc->sc_intr_lock);
    574 			kpreempt_disable();
    575 			(*intr)(intrarg);
    576 			kpreempt_enable();
    577 			mutex_exit(&sc->sc_intr_lock);
    578 			intr = sc->sc_intr;
    579 			intrarg = sc->sc_intrarg;
    580 			err = 0;
    581 			mutex_exit(&sc->sc_lock);
    582 			continue;
    583 		}
    584 		err = cv_wait_sig(&sc->sc_condvar, &sc->sc_lock);
    585 		if (err != 0) {
    586 			mutex_exit(&sc->sc_lock);
    587 			break;
    588 		}
    589 
    590 		mutex_exit(&sc->sc_lock);
    591 	}
    592 
    593 	return err;
    594 }
    595 
    596 static int
    597 pad_write(struct file *fp, off_t *offp, struct uio *uio, kauth_cred_t cred,
    598 	  int ioflag)
    599 {
    600 	return EOPNOTSUPP;
    601 }
    602 
    603 static int
    604 pad_audio_open(void *opaque, int flags)
    605 {
    606 	pad_softc_t *sc;
    607 	sc = opaque;
    608 
    609 	if (sc->sc_open == 0)
    610 		return EIO;
    611 
    612 	getmicrotime(&sc->sc_last);
    613 	sc->sc_bytes_count = 0;
    614 	sc->sc_remainder = 0;
    615 
    616 	return 0;
    617 }
    618 
    619 static int
    620 pad_query_encoding(void *opaque, struct audio_encoding *ae)
    621 {
    622 	pad_softc_t *sc;
    623 
    624 	sc = (pad_softc_t *)opaque;
    625 
    626 	KASSERT(mutex_owned(&sc->sc_lock));
    627 
    628 	return auconv_query_encoding(sc->sc_encodings, ae);
    629 }
    630 
    631 static int
    632 pad_set_params(void *opaque, int setmode, int usemode,
    633     audio_params_t *play, audio_params_t *rec,
    634     stream_filter_list_t *pfil, stream_filter_list_t *rfil)
    635 {
    636 	pad_softc_t *sc __diagused;
    637 
    638 	sc = (pad_softc_t *)opaque;
    639 
    640 	KASSERT(mutex_owned(&sc->sc_lock));
    641 
    642 	if (auconv_set_converter(pad_formats, PAD_NFORMATS, AUMODE_PLAY,
    643 	    play, true, pfil) < 0)
    644 		return EINVAL;
    645 	if (auconv_set_converter(pad_formats, PAD_NFORMATS, AUMODE_RECORD,
    646 	    rec, true, rfil) < 0)
    647 		return EINVAL;
    648 
    649 	if (pfil->req_size > 0)
    650 		play = &pfil->filters[0].param;
    651 	switch (play->encoding) {
    652 	case AUDIO_ENCODING_SLINEAR_LE:
    653 		if (play->precision == 16 && play->validbits == 16)
    654 			pfil->prepend(pfil, pad_swvol_filter_le, play);
    655 		break;
    656 	case AUDIO_ENCODING_SLINEAR_BE:
    657 		if (play->precision == 16 && play->validbits == 16)
    658 			pfil->prepend(pfil, pad_swvol_filter_be, play);
    659 		break;
    660 	default:
    661 		break;
    662 	}
    663 
    664 	return 0;
    665 }
    666 
    667 static int
    668 pad_start_output(void *opaque, void *block, int blksize,
    669     void (*intr)(void *), void *intrarg)
    670 {
    671 	pad_softc_t *sc;
    672 	int err;
    673 
    674 	sc = (pad_softc_t *)opaque;
    675 
    676 	KASSERT(mutex_owned(&sc->sc_lock));
    677 	if (!sc->sc_open)
    678 		return EIO;
    679 
    680 	sc->sc_intr = intr;
    681 	sc->sc_intrarg = intrarg;
    682 	sc->sc_blksize = blksize;
    683 
    684 	err = pad_add_block(sc, block, blksize);
    685 
    686 	cv_broadcast(&sc->sc_condvar);
    687 
    688 	return err;
    689 }
    690 
    691 static int
    692 pad_start_input(void *opaque, void *block, int blksize,
    693     void (*intr)(void *), void *intrarg)
    694 {
    695 	pad_softc_t *sc __diagused;
    696 
    697 	sc = (pad_softc_t *)opaque;
    698 
    699 	KASSERT(mutex_owned(&sc->sc_lock));
    700 
    701 	return EOPNOTSUPP;
    702 }
    703 
    704 static int
    705 pad_halt_output(void *opaque)
    706 {
    707 	pad_softc_t *sc;
    708 
    709 	sc = (pad_softc_t *)opaque;
    710 
    711 	KASSERT(mutex_owned(&sc->sc_lock));
    712 
    713 	sc->sc_intr = NULL;
    714 	sc->sc_intrarg = NULL;
    715 	sc->sc_buflen = 0;
    716 	sc->sc_rpos = sc->sc_wpos = 0;
    717 
    718 	return 0;
    719 }
    720 
    721 static int
    722 pad_halt_input(void *opaque)
    723 {
    724 	pad_softc_t *sc __diagused;
    725 
    726 	sc = (pad_softc_t *)opaque;
    727 
    728 	KASSERT(mutex_owned(&sc->sc_lock));
    729 
    730 	return 0;
    731 }
    732 
    733 static int
    734 pad_getdev(void *opaque, struct audio_device *ret)
    735 {
    736 	strlcpy(ret->name, "Virtual Audio", sizeof(ret->name));
    737 	strlcpy(ret->version, osrelease, sizeof(ret->version));
    738 	strlcpy(ret->config, "pad", sizeof(ret->config));
    739 
    740 	return 0;
    741 }
    742 
    743 static int
    744 pad_set_port(void *opaque, mixer_ctrl_t *mc)
    745 {
    746 	pad_softc_t *sc;
    747 
    748 	sc = (pad_softc_t *)opaque;
    749 
    750 	KASSERT(mutex_owned(&sc->sc_lock));
    751 
    752 	switch (mc->dev) {
    753 	case PAD_OUTPUT_MASTER_VOLUME:
    754 	case PAD_INPUT_DAC_VOLUME:
    755 		sc->sc_swvol = mc->un.value.level[AUDIO_MIXER_LEVEL_MONO];
    756 		return 0;
    757 	}
    758 
    759 	return ENXIO;
    760 }
    761 
    762 static int
    763 pad_get_port(void *opaque, mixer_ctrl_t *mc)
    764 {
    765 	pad_softc_t *sc;
    766 
    767 	sc = (pad_softc_t *)opaque;
    768 
    769 	KASSERT(mutex_owned(&sc->sc_lock));
    770 
    771 	switch (mc->dev) {
    772 	case PAD_OUTPUT_MASTER_VOLUME:
    773 	case PAD_INPUT_DAC_VOLUME:
    774 		mc->un.value.level[AUDIO_MIXER_LEVEL_MONO] = sc->sc_swvol;
    775 		return 0;
    776 	}
    777 
    778 	return ENXIO;
    779 }
    780 
    781 static int
    782 pad_query_devinfo(void *opaque, mixer_devinfo_t *di)
    783 {
    784 	pad_softc_t *sc __diagused;
    785 
    786 	sc = (pad_softc_t *)opaque;
    787 
    788 	KASSERT(mutex_owned(&sc->sc_lock));
    789 
    790 	switch (di->index) {
    791 	case PAD_OUTPUT_CLASS:
    792 		di->mixer_class = PAD_OUTPUT_CLASS;
    793 		strcpy(di->label.name, AudioCoutputs);
    794 		di->type = AUDIO_MIXER_CLASS;
    795 		di->next = di->prev = AUDIO_MIXER_LAST;
    796 		return 0;
    797 	case PAD_INPUT_CLASS:
    798 		di->mixer_class = PAD_INPUT_CLASS;
    799 		strcpy(di->label.name, AudioCinputs);
    800 		di->type = AUDIO_MIXER_CLASS;
    801 		di->next = di->prev = AUDIO_MIXER_LAST;
    802 		return 0;
    803 	case PAD_OUTPUT_MASTER_VOLUME:
    804 		di->mixer_class = PAD_OUTPUT_CLASS;
    805 		strcpy(di->label.name, AudioNmaster);
    806 		di->type = AUDIO_MIXER_VALUE;
    807 		di->next = di->prev = AUDIO_MIXER_LAST;
    808 		di->un.v.num_channels = 1;
    809 		strcpy(di->un.v.units.name, AudioNvolume);
    810 		return 0;
    811 	case PAD_INPUT_DAC_VOLUME:
    812 		di->mixer_class = PAD_INPUT_CLASS;
    813 		strcpy(di->label.name, AudioNdac);
    814 		di->type = AUDIO_MIXER_VALUE;
    815 		di->next = di->prev = AUDIO_MIXER_LAST;
    816 		di->un.v.num_channels = 1;
    817 		strcpy(di->un.v.units.name, AudioNvolume);
    818 		return 0;
    819 	}
    820 
    821 	return ENXIO;
    822 }
    823 
    824 static int
    825 pad_get_props(void *opaque)
    826 {
    827 	pad_softc_t *sc __diagused;
    828 
    829 	sc = (pad_softc_t *)opaque;
    830 
    831 	KASSERT(mutex_owned(&sc->sc_lock));
    832 
    833 	return 0;
    834 }
    835 
    836 static int
    837 pad_round_blocksize(void *opaque, int blksize, int mode,
    838     const audio_params_t *p)
    839 {
    840 	pad_softc_t *sc __diagused;
    841 
    842 	sc = (pad_softc_t *)opaque;
    843 	KASSERT(mutex_owned(&sc->sc_lock));
    844 
    845 	return PAD_BLKSIZE;
    846 }
    847 
    848 static void
    849 pad_get_locks(void *opaque, kmutex_t **intr, kmutex_t **thread)
    850 {
    851 	pad_softc_t *sc;
    852 
    853 	sc = (pad_softc_t *)opaque;
    854 
    855 	*intr = &sc->sc_intr_lock;
    856 	*thread = &sc->sc_lock;
    857 }
    858 
    859 static stream_filter_t *
    860 pad_swvol_filter_le(struct audio_softc *asc,
    861     const audio_params_t *from, const audio_params_t *to)
    862 {
    863 	auvolconv_filter_t *this;
    864 	device_t dev = audio_get_device(asc);
    865 	struct pad_softc *sc = device_private(dev);
    866 
    867 	this = kmem_alloc(sizeof(auvolconv_filter_t), KM_SLEEP);
    868 	this->base.base.fetch_to = auvolconv_slinear16_le_fetch_to;
    869 	this->base.dtor = pad_swvol_dtor;
    870 	this->base.set_fetcher = stream_filter_set_fetcher;
    871 	this->base.set_inputbuffer = stream_filter_set_inputbuffer;
    872 	this->vol = &sc->sc_swvol;
    873 
    874 	return (stream_filter_t *)this;
    875 }
    876 
    877 static stream_filter_t *
    878 pad_swvol_filter_be(struct audio_softc *asc,
    879     const audio_params_t *from, const audio_params_t *to)
    880 {
    881 	auvolconv_filter_t *this;
    882 	device_t dev = audio_get_device(asc);
    883 	struct pad_softc *sc = device_private(dev);
    884 
    885 	this = kmem_alloc(sizeof(auvolconv_filter_t), KM_SLEEP);
    886 	this->base.base.fetch_to = auvolconv_slinear16_be_fetch_to;
    887 	this->base.dtor = pad_swvol_dtor;
    888 	this->base.set_fetcher = stream_filter_set_fetcher;
    889 	this->base.set_inputbuffer = stream_filter_set_inputbuffer;
    890 	this->vol = &sc->sc_swvol;
    891 
    892 	return (stream_filter_t *)this;
    893 }
    894 
    895 static void
    896 pad_swvol_dtor(stream_filter_t *this)
    897 {
    898 	if (this)
    899 		kmem_free(this, sizeof(auvolconv_filter_t));
    900 }
    901 
    902 MODULE(MODULE_CLASS_DRIVER, pad, "audio");
    903 
    904 #ifdef _MODULE
    905 
    906 /* XXX These should really be created by config(1)'s IOCONF mechanism */
    907 
    908 static const struct cfiattrdata audiobuscf_iattrdata = {
    909 	"audiobus", 0, { { NULL, NULL, 0 }, }
    910 };
    911 static const struct cfiattrdata * const pad_attrs[] = {
    912 	&audiobuscf_iattrdata, NULL
    913 };
    914 
    915 CFDRIVER_DECL(pad, DV_DULL, pad_attrs);
    916 extern struct cfattach pad_ca;
    917 static int padloc[] = { -1, -1 };
    918 
    919 static struct cfdata pad_cfdata[] = {
    920 	{
    921 		.cf_name = "pad",
    922 		.cf_atname = "pad",
    923 		.cf_unit = 0,
    924 		.cf_fstate = FSTATE_STAR,
    925 		.cf_loc = padloc,
    926 		.cf_flags = 0,
    927 		.cf_pspec = NULL,
    928 	},
    929 	{ NULL, NULL, 0, 0, NULL, 0, NULL }
    930 };
    931 #endif
    932 
    933 /* provide the vectors required for config_{init,fini}_component() */
    934 
    935 struct cfdriver * const pad_cfdriver[] = { &pad_cd, NULL };
    936 
    937 static struct cfattach * const pad_cfattachinit[] = { &pad_ca, NULL };
    938 
    939 static const struct cfattachinit pad_cfattach[] = {
    940 	{ "pad", pad_cfattachinit },
    941 	{ NULL, NULL }
    942 };
    943 
    944 #endif
    945 
    946 static int
    947 pad_modcmd(modcmd_t cmd, void *arg)
    948 {
    949 #ifdef _MODULE
    950 	devmajor_t cmajor = NODEVMAJOR, bmajor = NODEVMAJOR;
    951 #endif
    952 	int error = 0;
    953 
    954 	switch (cmd) {
    955 	case MODULE_CMD_INIT:
    956 #ifdef _MODULE
    957 		error = config_init_component(pad_cfdriver, pad_cfattach,
    958 		    pad_cfdata);
    959 		if (error)
    960 			break;
    961 
    962 		error = devsw_attach(pad_cd.cd_name, NULL, &bmajor,
    963 			    &pad_cdevsw, &cmajor);
    964 		if (error) {
    965 			config_fini_component(pad_cfdriver, pad_cfattach,
    966 			    pad_cfdata);
    967 			break;
    968 		}
    969 
    970 		(void)config_attach_pseudo(pad_cfdata);
    971 #endif
    972 		break;
    973 
    974 	case MODULE_CMD_FINI:
    975 #ifdef _MODULE
    976 		error = devsw_detach(NULL, &pad_cdevsw);
    977 		if (error)
    978 			break;
    979 
    980 		error = config_fini_component(pad_cfdriver, pad_cfattach,
    981 		    pad_cfdata);
    982 		if (error) {
    983 			error = devsw_attach(pad_cd.cd_name, NULL, &bmajor,
    984 			    &pad_cdevsw, &cmajor);
    985 			break;
    986 		}
    987 #endif
    988 		break;
    989 
    990 	default:
    991 		error = ENOTTY;
    992 	}
    993 
    994 	return error;
    995 }
    996