1/*-
2 * SPDX-License-Identifier: BSD-2-Clause
3 *
4 * Copyright (c) 2005-2009 Ariff Abdullah <ariff@FreeBSD.org>
5 * Portions Copyright (c) Ryan Beasley <ryan.beasley@gmail.com> - GSoC 2006
6 * Copyright (c) 1999 Cameron Grant <cg@FreeBSD.org>
7 * Portions Copyright (c) Luigi Rizzo <luigi@FreeBSD.org> - 1997-99
8 * All rights reserved.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 *    notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in the
17 *    documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32#ifdef HAVE_KERNEL_OPTION_HEADERS
33#include "opt_snd.h"
34#endif
35
36#include <dev/sound/pcm/sound.h>
37#include <dev/sound/pcm/vchan.h>
38
39#include "feeder_if.h"
40
41int report_soft_formats = 1;
42SYSCTL_INT(_hw_snd, OID_AUTO, report_soft_formats, CTLFLAG_RW,
43	&report_soft_formats, 0, "report software-emulated formats");
44
45int report_soft_matrix = 1;
46SYSCTL_INT(_hw_snd, OID_AUTO, report_soft_matrix, CTLFLAG_RW,
47	&report_soft_matrix, 0, "report software-emulated channel matrixing");
48
49int chn_latency = CHN_LATENCY_DEFAULT;
50
51static int
52sysctl_hw_snd_latency(SYSCTL_HANDLER_ARGS)
53{
54	int err, val;
55
56	val = chn_latency;
57	err = sysctl_handle_int(oidp, &val, 0, req);
58	if (err != 0 || req->newptr == NULL)
59		return err;
60	if (val < CHN_LATENCY_MIN || val > CHN_LATENCY_MAX)
61		err = EINVAL;
62	else
63		chn_latency = val;
64
65	return err;
66}
67SYSCTL_PROC(_hw_snd, OID_AUTO, latency,
68    CTLTYPE_INT | CTLFLAG_RWTUN | CTLFLAG_MPSAFE, 0, sizeof(int),
69    sysctl_hw_snd_latency, "I",
70    "buffering latency (0=low ... 10=high)");
71
72int chn_latency_profile = CHN_LATENCY_PROFILE_DEFAULT;
73
74static int
75sysctl_hw_snd_latency_profile(SYSCTL_HANDLER_ARGS)
76{
77	int err, val;
78
79	val = chn_latency_profile;
80	err = sysctl_handle_int(oidp, &val, 0, req);
81	if (err != 0 || req->newptr == NULL)
82		return err;
83	if (val < CHN_LATENCY_PROFILE_MIN || val > CHN_LATENCY_PROFILE_MAX)
84		err = EINVAL;
85	else
86		chn_latency_profile = val;
87
88	return err;
89}
90SYSCTL_PROC(_hw_snd, OID_AUTO, latency_profile,
91    CTLTYPE_INT | CTLFLAG_RWTUN | CTLFLAG_MPSAFE, 0, sizeof(int),
92    sysctl_hw_snd_latency_profile, "I",
93    "buffering latency profile (0=aggressive 1=safe)");
94
95static int chn_timeout = CHN_TIMEOUT;
96
97static int
98sysctl_hw_snd_timeout(SYSCTL_HANDLER_ARGS)
99{
100	int err, val;
101
102	val = chn_timeout;
103	err = sysctl_handle_int(oidp, &val, 0, req);
104	if (err != 0 || req->newptr == NULL)
105		return err;
106	if (val < CHN_TIMEOUT_MIN || val > CHN_TIMEOUT_MAX)
107		err = EINVAL;
108	else
109		chn_timeout = val;
110
111	return err;
112}
113SYSCTL_PROC(_hw_snd, OID_AUTO, timeout,
114    CTLTYPE_INT | CTLFLAG_RWTUN | CTLFLAG_MPSAFE, 0, sizeof(int),
115    sysctl_hw_snd_timeout, "I",
116    "interrupt timeout (1 - 10) seconds");
117
118static int chn_vpc_autoreset = 1;
119SYSCTL_INT(_hw_snd, OID_AUTO, vpc_autoreset, CTLFLAG_RWTUN,
120	&chn_vpc_autoreset, 0, "automatically reset channels volume to 0db");
121
122static int chn_vol_0db_pcm = SND_VOL_0DB_PCM;
123
124static void
125chn_vpc_proc(int reset, int db)
126{
127	struct snddev_info *d;
128	struct pcm_channel *c;
129	int i;
130
131	for (i = 0; pcm_devclass != NULL &&
132	    i < devclass_get_maxunit(pcm_devclass); i++) {
133		d = devclass_get_softc(pcm_devclass, i);
134		if (!PCM_REGISTERED(d))
135			continue;
136		PCM_LOCK(d);
137		PCM_WAIT(d);
138		PCM_ACQUIRE(d);
139		CHN_FOREACH(c, d, channels.pcm) {
140			CHN_LOCK(c);
141			CHN_SETVOLUME(c, SND_VOL_C_PCM, SND_CHN_T_VOL_0DB, db);
142			if (reset != 0)
143				chn_vpc_reset(c, SND_VOL_C_PCM, 1);
144			CHN_UNLOCK(c);
145		}
146		PCM_RELEASE(d);
147		PCM_UNLOCK(d);
148	}
149}
150
151static int
152sysctl_hw_snd_vpc_0db(SYSCTL_HANDLER_ARGS)
153{
154	int err, val;
155
156	val = chn_vol_0db_pcm;
157	err = sysctl_handle_int(oidp, &val, 0, req);
158	if (err != 0 || req->newptr == NULL)
159		return (err);
160	if (val < SND_VOL_0DB_MIN || val > SND_VOL_0DB_MAX)
161		return (EINVAL);
162
163	chn_vol_0db_pcm = val;
164	chn_vpc_proc(0, val);
165
166	return (0);
167}
168SYSCTL_PROC(_hw_snd, OID_AUTO, vpc_0db,
169    CTLTYPE_INT | CTLFLAG_RWTUN | CTLFLAG_NEEDGIANT, 0, sizeof(int),
170    sysctl_hw_snd_vpc_0db, "I",
171    "0db relative level");
172
173static int
174sysctl_hw_snd_vpc_reset(SYSCTL_HANDLER_ARGS)
175{
176	int err, val;
177
178	val = 0;
179	err = sysctl_handle_int(oidp, &val, 0, req);
180	if (err != 0 || req->newptr == NULL || val == 0)
181		return (err);
182
183	chn_vol_0db_pcm = SND_VOL_0DB_PCM;
184	chn_vpc_proc(1, SND_VOL_0DB_PCM);
185
186	return (0);
187}
188SYSCTL_PROC(_hw_snd, OID_AUTO, vpc_reset,
189    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NEEDGIANT, 0, sizeof(int),
190    sysctl_hw_snd_vpc_reset, "I",
191    "reset volume on all channels");
192
193static int chn_usefrags = 0;
194static int chn_syncdelay = -1;
195
196SYSCTL_INT(_hw_snd, OID_AUTO, usefrags, CTLFLAG_RWTUN,
197	&chn_usefrags, 0, "prefer setfragments() over setblocksize()");
198SYSCTL_INT(_hw_snd, OID_AUTO, syncdelay, CTLFLAG_RWTUN,
199	&chn_syncdelay, 0,
200	"append (0-1000) millisecond trailing buffer delay on each sync");
201
202/**
203 * @brief Channel sync group lock
204 *
205 * Clients should acquire this lock @b without holding any channel locks
206 * before touching syncgroups or the main syncgroup list.
207 */
208struct mtx snd_pcm_syncgroups_mtx;
209MTX_SYSINIT(pcm_syncgroup, &snd_pcm_syncgroups_mtx, "PCM channel sync group lock", MTX_DEF);
210/**
211 * @brief syncgroups' master list
212 *
213 * Each time a channel syncgroup is created, it's added to this list.  This
214 * list should only be accessed with @sa snd_pcm_syncgroups_mtx held.
215 *
216 * See SNDCTL_DSP_SYNCGROUP for more information.
217 */
218struct pcm_synclist snd_pcm_syncgroups = SLIST_HEAD_INITIALIZER(snd_pcm_syncgroups);
219
220static void
221chn_lockinit(struct pcm_channel *c, int dir)
222{
223	switch (dir) {
224	case PCMDIR_PLAY:
225		c->lock = snd_mtxcreate(c->name, "pcm play channel");
226		cv_init(&c->intr_cv, "pcmwr");
227		break;
228	case PCMDIR_PLAY_VIRTUAL:
229		c->lock = snd_mtxcreate(c->name, "pcm virtual play channel");
230		cv_init(&c->intr_cv, "pcmwrv");
231		break;
232	case PCMDIR_REC:
233		c->lock = snd_mtxcreate(c->name, "pcm record channel");
234		cv_init(&c->intr_cv, "pcmrd");
235		break;
236	case PCMDIR_REC_VIRTUAL:
237		c->lock = snd_mtxcreate(c->name, "pcm virtual record channel");
238		cv_init(&c->intr_cv, "pcmrdv");
239		break;
240	default:
241		panic("%s(): Invalid direction=%d", __func__, dir);
242		break;
243	}
244
245	cv_init(&c->cv, "pcmchn");
246}
247
248static void
249chn_lockdestroy(struct pcm_channel *c)
250{
251	CHN_LOCKASSERT(c);
252
253	CHN_BROADCAST(&c->cv);
254	CHN_BROADCAST(&c->intr_cv);
255
256	cv_destroy(&c->cv);
257	cv_destroy(&c->intr_cv);
258
259	snd_mtxfree(c->lock);
260}
261
262/**
263 * @brief Determine channel is ready for I/O
264 *
265 * @retval 1 = ready for I/O
266 * @retval 0 = not ready for I/O
267 */
268static int
269chn_polltrigger(struct pcm_channel *c)
270{
271	struct snd_dbuf *bs = c->bufsoft;
272	u_int delta;
273
274	CHN_LOCKASSERT(c);
275
276	if (c->flags & CHN_F_MMAP) {
277		if (sndbuf_getprevtotal(bs) < c->lw)
278			delta = c->lw;
279		else
280			delta = sndbuf_gettotal(bs) - sndbuf_getprevtotal(bs);
281	} else {
282		if (c->direction == PCMDIR_PLAY)
283			delta = sndbuf_getfree(bs);
284		else
285			delta = sndbuf_getready(bs);
286	}
287
288	return ((delta < c->lw) ? 0 : 1);
289}
290
291static void
292chn_pollreset(struct pcm_channel *c)
293{
294
295	CHN_LOCKASSERT(c);
296	sndbuf_updateprevtotal(c->bufsoft);
297}
298
299static void
300chn_wakeup(struct pcm_channel *c)
301{
302	struct snd_dbuf *bs;
303	struct pcm_channel *ch;
304
305	CHN_LOCKASSERT(c);
306
307	bs = c->bufsoft;
308
309	if (CHN_EMPTY(c, children.busy)) {
310		if (SEL_WAITING(sndbuf_getsel(bs)) && chn_polltrigger(c))
311			selwakeuppri(sndbuf_getsel(bs), PRIBIO);
312		if (c->flags & CHN_F_SLEEPING) {
313			/*
314			 * Ok, I can just panic it right here since it is
315			 * quite obvious that we never allow multiple waiters
316			 * from userland. I'm too generous...
317			 */
318			CHN_BROADCAST(&c->intr_cv);
319		}
320	} else {
321		CHN_FOREACH(ch, c, children.busy) {
322			CHN_LOCK(ch);
323			chn_wakeup(ch);
324			CHN_UNLOCK(ch);
325		}
326	}
327}
328
329static int
330chn_sleep(struct pcm_channel *c, int timeout)
331{
332	int ret;
333
334	CHN_LOCKASSERT(c);
335	KASSERT((c->flags & CHN_F_SLEEPING) == 0,
336	    ("%s(): entered with CHN_F_SLEEPING", __func__));
337
338	if (c->flags & CHN_F_DEAD)
339		return (EINVAL);
340
341	c->flags |= CHN_F_SLEEPING;
342	ret = cv_timedwait_sig(&c->intr_cv, c->lock, timeout);
343	c->flags &= ~CHN_F_SLEEPING;
344
345	return ((c->flags & CHN_F_DEAD) ? EINVAL : ret);
346}
347
348/*
349 * chn_dmaupdate() tracks the status of a dma transfer,
350 * updating pointers.
351 */
352
353static unsigned int
354chn_dmaupdate(struct pcm_channel *c)
355{
356	struct snd_dbuf *b = c->bufhard;
357	unsigned int delta, old, hwptr, amt;
358
359	KASSERT(sndbuf_getsize(b) > 0, ("bufsize == 0"));
360	CHN_LOCKASSERT(c);
361
362	old = sndbuf_gethwptr(b);
363	hwptr = chn_getptr(c);
364	delta = (sndbuf_getsize(b) + hwptr - old) % sndbuf_getsize(b);
365	sndbuf_sethwptr(b, hwptr);
366
367	if (c->direction == PCMDIR_PLAY) {
368		amt = min(delta, sndbuf_getready(b));
369		amt -= amt % sndbuf_getalign(b);
370		if (amt > 0)
371			sndbuf_dispose(b, NULL, amt);
372	} else {
373		amt = min(delta, sndbuf_getfree(b));
374		amt -= amt % sndbuf_getalign(b);
375		if (amt > 0)
376		       sndbuf_acquire(b, NULL, amt);
377	}
378	if (snd_verbose > 3 && CHN_STARTED(c) && delta == 0) {
379		device_printf(c->dev, "WARNING: %s DMA completion "
380			"too fast/slow ! hwptr=%u, old=%u "
381			"delta=%u amt=%u ready=%u free=%u\n",
382			CHN_DIRSTR(c), hwptr, old, delta, amt,
383			sndbuf_getready(b), sndbuf_getfree(b));
384	}
385
386	return delta;
387}
388
389static void
390chn_wrfeed(struct pcm_channel *c)
391{
392    	struct snd_dbuf *b = c->bufhard;
393    	struct snd_dbuf *bs = c->bufsoft;
394	unsigned int amt, want, wasfree;
395
396	CHN_LOCKASSERT(c);
397
398	if ((c->flags & CHN_F_MMAP) && !(c->flags & CHN_F_CLOSING))
399		sndbuf_acquire(bs, NULL, sndbuf_getfree(bs));
400
401	wasfree = sndbuf_getfree(b);
402	want = min(sndbuf_getsize(b),
403	    imax(0, sndbuf_xbytes(sndbuf_getsize(bs), bs, b) -
404	     sndbuf_getready(b)));
405	amt = min(wasfree, want);
406	if (amt > 0)
407		sndbuf_feed(bs, b, c, c->feeder, amt);
408
409	/*
410	 * Possible xruns. There should be no empty space left in buffer.
411	 */
412	if (sndbuf_getready(b) < want)
413		c->xruns++;
414
415	if (sndbuf_getfree(b) < wasfree)
416		chn_wakeup(c);
417}
418
419#if 0
420static void
421chn_wrupdate(struct pcm_channel *c)
422{
423
424	CHN_LOCKASSERT(c);
425	KASSERT(c->direction == PCMDIR_PLAY, ("%s(): bad channel", __func__));
426
427	if ((c->flags & (CHN_F_MMAP | CHN_F_VIRTUAL)) || CHN_STOPPED(c))
428		return;
429	chn_dmaupdate(c);
430	chn_wrfeed(c);
431	/* tell the driver we've updated the primary buffer */
432	chn_trigger(c, PCMTRIG_EMLDMAWR);
433}
434#endif
435
436static void
437chn_wrintr(struct pcm_channel *c)
438{
439
440	CHN_LOCKASSERT(c);
441	/* update pointers in primary buffer */
442	chn_dmaupdate(c);
443	/* ...and feed from secondary to primary */
444	chn_wrfeed(c);
445	/* tell the driver we've updated the primary buffer */
446	chn_trigger(c, PCMTRIG_EMLDMAWR);
447}
448
449/*
450 * user write routine - uiomove data into secondary buffer, trigger if necessary
451 * if blocking, sleep, rinse and repeat.
452 *
453 * called externally, so must handle locking
454 */
455
456int
457chn_write(struct pcm_channel *c, struct uio *buf)
458{
459	struct snd_dbuf *bs = c->bufsoft;
460	void *off;
461	int ret, timeout, sz, t, p;
462
463	CHN_LOCKASSERT(c);
464
465	ret = 0;
466	timeout = chn_timeout * hz;
467
468	while (ret == 0 && buf->uio_resid > 0) {
469		sz = min(buf->uio_resid, sndbuf_getfree(bs));
470		if (sz > 0) {
471			/*
472			 * The following assumes that the free space in
473			 * the buffer can never be less around the
474			 * unlock-uiomove-lock sequence.
475			 */
476			while (ret == 0 && sz > 0) {
477				p = sndbuf_getfreeptr(bs);
478				t = min(sz, sndbuf_getsize(bs) - p);
479				off = sndbuf_getbufofs(bs, p);
480				CHN_UNLOCK(c);
481				ret = uiomove(off, t, buf);
482				CHN_LOCK(c);
483				sz -= t;
484				sndbuf_acquire(bs, NULL, t);
485			}
486			ret = 0;
487			if (CHN_STOPPED(c) && !(c->flags & CHN_F_NOTRIGGER)) {
488				ret = chn_start(c, 0);
489				if (ret != 0)
490					c->flags |= CHN_F_DEAD;
491			}
492		} else if (c->flags & (CHN_F_NBIO | CHN_F_NOTRIGGER)) {
493			/**
494			 * @todo Evaluate whether EAGAIN is truly desirable.
495			 * 	 4Front drivers behave like this, but I'm
496			 * 	 not sure if it at all violates the "write
497			 * 	 should be allowed to block" model.
498			 *
499			 * 	 The idea is that, while set with CHN_F_NOTRIGGER,
500			 * 	 a channel isn't playing, *but* without this we
501			 * 	 end up with "interrupt timeout / channel dead".
502			 */
503			ret = EAGAIN;
504		} else {
505   			ret = chn_sleep(c, timeout);
506			if (ret == EAGAIN) {
507				ret = EINVAL;
508				c->flags |= CHN_F_DEAD;
509				device_printf(c->dev, "%s(): %s: "
510				    "play interrupt timeout, channel dead\n",
511				    __func__, c->name);
512			} else if (ret == ERESTART || ret == EINTR)
513				c->flags |= CHN_F_ABORTING;
514		}
515	}
516
517	return (ret);
518}
519
520/*
521 * Feed new data from the read buffer. Can be called in the bottom half.
522 */
523static void
524chn_rdfeed(struct pcm_channel *c)
525{
526    	struct snd_dbuf *b = c->bufhard;
527    	struct snd_dbuf *bs = c->bufsoft;
528	unsigned int amt;
529
530	CHN_LOCKASSERT(c);
531
532	if (c->flags & CHN_F_MMAP)
533		sndbuf_dispose(bs, NULL, sndbuf_getready(bs));
534
535	amt = sndbuf_getfree(bs);
536	if (amt > 0)
537		sndbuf_feed(b, bs, c, c->feeder, amt);
538
539	amt = sndbuf_getready(b);
540	if (amt > 0) {
541		c->xruns++;
542		sndbuf_dispose(b, NULL, amt);
543	}
544
545	if (sndbuf_getready(bs) > 0)
546		chn_wakeup(c);
547}
548
549#if 0
550static void
551chn_rdupdate(struct pcm_channel *c)
552{
553
554	CHN_LOCKASSERT(c);
555	KASSERT(c->direction == PCMDIR_REC, ("chn_rdupdate on bad channel"));
556
557	if ((c->flags & (CHN_F_MMAP | CHN_F_VIRTUAL)) || CHN_STOPPED(c))
558		return;
559	chn_trigger(c, PCMTRIG_EMLDMARD);
560	chn_dmaupdate(c);
561	chn_rdfeed(c);
562}
563#endif
564
565/* read interrupt routine. Must be called with interrupts blocked. */
566static void
567chn_rdintr(struct pcm_channel *c)
568{
569
570	CHN_LOCKASSERT(c);
571	/* tell the driver to update the primary buffer if non-dma */
572	chn_trigger(c, PCMTRIG_EMLDMARD);
573	/* update pointers in primary buffer */
574	chn_dmaupdate(c);
575	/* ...and feed from primary to secondary */
576	chn_rdfeed(c);
577}
578
579/*
580 * user read routine - trigger if necessary, uiomove data from secondary buffer
581 * if blocking, sleep, rinse and repeat.
582 *
583 * called externally, so must handle locking
584 */
585
586int
587chn_read(struct pcm_channel *c, struct uio *buf)
588{
589	struct snd_dbuf *bs = c->bufsoft;
590	void *off;
591	int ret, timeout, sz, t, p;
592
593	CHN_LOCKASSERT(c);
594
595	if (CHN_STOPPED(c) && !(c->flags & CHN_F_NOTRIGGER)) {
596		ret = chn_start(c, 0);
597		if (ret != 0) {
598			c->flags |= CHN_F_DEAD;
599			return (ret);
600		}
601	}
602
603	ret = 0;
604	timeout = chn_timeout * hz;
605
606	while (ret == 0 && buf->uio_resid > 0) {
607		sz = min(buf->uio_resid, sndbuf_getready(bs));
608		if (sz > 0) {
609			/*
610			 * The following assumes that the free space in
611			 * the buffer can never be less around the
612			 * unlock-uiomove-lock sequence.
613			 */
614			while (ret == 0 && sz > 0) {
615				p = sndbuf_getreadyptr(bs);
616				t = min(sz, sndbuf_getsize(bs) - p);
617				off = sndbuf_getbufofs(bs, p);
618				CHN_UNLOCK(c);
619				ret = uiomove(off, t, buf);
620				CHN_LOCK(c);
621				sz -= t;
622				sndbuf_dispose(bs, NULL, t);
623			}
624			ret = 0;
625		} else if (c->flags & (CHN_F_NBIO | CHN_F_NOTRIGGER))
626			ret = EAGAIN;
627		else {
628   			ret = chn_sleep(c, timeout);
629			if (ret == EAGAIN) {
630				ret = EINVAL;
631				c->flags |= CHN_F_DEAD;
632				device_printf(c->dev, "%s(): %s: "
633				    "record interrupt timeout, channel dead\n",
634				    __func__, c->name);
635			} else if (ret == ERESTART || ret == EINTR)
636				c->flags |= CHN_F_ABORTING;
637		}
638	}
639
640	return (ret);
641}
642
643void
644chn_intr_locked(struct pcm_channel *c)
645{
646
647	CHN_LOCKASSERT(c);
648
649	c->interrupts++;
650
651	if (c->direction == PCMDIR_PLAY)
652		chn_wrintr(c);
653	else
654		chn_rdintr(c);
655}
656
657void
658chn_intr(struct pcm_channel *c)
659{
660
661	if (CHN_LOCKOWNED(c)) {
662		chn_intr_locked(c);
663		return;
664	}
665
666	CHN_LOCK(c);
667	chn_intr_locked(c);
668	CHN_UNLOCK(c);
669}
670
671u_int32_t
672chn_start(struct pcm_channel *c, int force)
673{
674	u_int32_t i, j;
675	struct snd_dbuf *b = c->bufhard;
676	struct snd_dbuf *bs = c->bufsoft;
677	int err;
678
679	CHN_LOCKASSERT(c);
680	/* if we're running, or if we're prevented from triggering, bail */
681	if (CHN_STARTED(c) || ((c->flags & CHN_F_NOTRIGGER) && !force))
682		return (EINVAL);
683
684	err = 0;
685
686	if (force) {
687		i = 1;
688		j = 0;
689	} else {
690		if (c->direction == PCMDIR_REC) {
691			i = sndbuf_getfree(bs);
692			j = (i > 0) ? 1 : sndbuf_getready(b);
693		} else {
694			if (sndbuf_getfree(bs) == 0) {
695				i = 1;
696				j = 0;
697			} else {
698				struct snd_dbuf *pb;
699
700				pb = CHN_BUF_PARENT(c, b);
701				i = sndbuf_xbytes(sndbuf_getready(bs), bs, pb);
702				j = sndbuf_getalign(pb);
703			}
704		}
705		if (snd_verbose > 3 && CHN_EMPTY(c, children))
706			device_printf(c->dev, "%s(): %s (%s) threshold "
707			    "i=%d j=%d\n", __func__, CHN_DIRSTR(c),
708			    (c->flags & CHN_F_VIRTUAL) ? "virtual" :
709			    "hardware", i, j);
710	}
711
712	if (i >= j) {
713		c->flags |= CHN_F_TRIGGERED;
714		sndbuf_setrun(b, 1);
715		if (c->flags & CHN_F_CLOSING)
716			c->feedcount = 2;
717		else {
718			c->feedcount = 0;
719			c->interrupts = 0;
720			c->xruns = 0;
721		}
722		if (c->parentchannel == NULL) {
723			if (c->direction == PCMDIR_PLAY)
724				sndbuf_fillsilence_rl(b,
725				    sndbuf_xbytes(sndbuf_getsize(bs), bs, b));
726			if (snd_verbose > 3)
727				device_printf(c->dev,
728				    "%s(): %s starting! (%s/%s) "
729				    "(ready=%d force=%d i=%d j=%d "
730				    "intrtimeout=%u latency=%dms)\n",
731				    __func__,
732				    (c->flags & CHN_F_HAS_VCHAN) ?
733				    "VCHAN PARENT" : "HW", CHN_DIRSTR(c),
734				    (c->flags & CHN_F_CLOSING) ? "closing" :
735				    "running",
736				    sndbuf_getready(b),
737				    force, i, j, c->timeout,
738				    (sndbuf_getsize(b) * 1000) /
739				    (sndbuf_getalign(b) * sndbuf_getspd(b)));
740		}
741		err = chn_trigger(c, PCMTRIG_START);
742	}
743
744	return (err);
745}
746
747void
748chn_resetbuf(struct pcm_channel *c)
749{
750	struct snd_dbuf *b = c->bufhard;
751	struct snd_dbuf *bs = c->bufsoft;
752
753	c->blocks = 0;
754	sndbuf_reset(b);
755	sndbuf_reset(bs);
756}
757
758/*
759 * chn_sync waits until the space in the given channel goes above
760 * a threshold. The threshold is checked against fl or rl respectively.
761 * Assume that the condition can become true, do not check here...
762 */
763int
764chn_sync(struct pcm_channel *c, int threshold)
765{
766    	struct snd_dbuf *b, *bs;
767	int ret, count, hcount, minflush, resid, residp, syncdelay, blksz;
768	u_int32_t cflag;
769
770	CHN_LOCKASSERT(c);
771
772	if (c->direction != PCMDIR_PLAY)
773		return (EINVAL);
774
775	bs = c->bufsoft;
776
777	if ((c->flags & (CHN_F_DEAD | CHN_F_ABORTING)) ||
778	    (threshold < 1 && sndbuf_getready(bs) < 1))
779		return (0);
780
781	/* if we haven't yet started and nothing is buffered, else start*/
782	if (CHN_STOPPED(c)) {
783		if (threshold > 0 || sndbuf_getready(bs) > 0) {
784			ret = chn_start(c, 1);
785			if (ret != 0)
786				return (ret);
787		} else
788			return (0);
789	}
790
791	b = CHN_BUF_PARENT(c, c->bufhard);
792
793	minflush = threshold + sndbuf_xbytes(sndbuf_getready(b), b, bs);
794
795	syncdelay = chn_syncdelay;
796
797	if (syncdelay < 0 && (threshold > 0 || sndbuf_getready(bs) > 0))
798		minflush += sndbuf_xbytes(sndbuf_getsize(b), b, bs);
799
800	/*
801	 * Append (0-1000) millisecond trailing buffer (if needed)
802	 * for slower / high latency hardwares (notably USB audio)
803	 * to avoid audible truncation.
804	 */
805	if (syncdelay > 0)
806		minflush += (sndbuf_getalign(bs) * sndbuf_getspd(bs) *
807		    ((syncdelay > 1000) ? 1000 : syncdelay)) / 1000;
808
809	minflush -= minflush % sndbuf_getalign(bs);
810
811	if (minflush > 0) {
812		threshold = min(minflush, sndbuf_getfree(bs));
813		sndbuf_clear(bs, threshold);
814		sndbuf_acquire(bs, NULL, threshold);
815		minflush -= threshold;
816	}
817
818	resid = sndbuf_getready(bs);
819	residp = resid;
820	blksz = sndbuf_getblksz(b);
821	if (blksz < 1) {
822		device_printf(c->dev,
823		    "%s(): WARNING: blksz < 1 ! maxsize=%d [%d/%d/%d]\n",
824		    __func__, sndbuf_getmaxsize(b), sndbuf_getsize(b),
825		    sndbuf_getblksz(b), sndbuf_getblkcnt(b));
826		if (sndbuf_getblkcnt(b) > 0)
827			blksz = sndbuf_getsize(b) / sndbuf_getblkcnt(b);
828		if (blksz < 1)
829			blksz = 1;
830	}
831	count = sndbuf_xbytes(minflush + resid, bs, b) / blksz;
832	hcount = count;
833	ret = 0;
834
835	if (snd_verbose > 3)
836		device_printf(c->dev, "%s(): [begin] timeout=%d count=%d "
837		    "minflush=%d resid=%d\n", __func__, c->timeout, count,
838		    minflush, resid);
839
840	cflag = c->flags & CHN_F_CLOSING;
841	c->flags |= CHN_F_CLOSING;
842	while (count > 0 && (resid > 0 || minflush > 0)) {
843		ret = chn_sleep(c, c->timeout);
844    		if (ret == ERESTART || ret == EINTR) {
845			c->flags |= CHN_F_ABORTING;
846			break;
847		} else if (ret == 0 || ret == EAGAIN) {
848			resid = sndbuf_getready(bs);
849			if (resid == residp) {
850				--count;
851				if (snd_verbose > 3)
852					device_printf(c->dev,
853					    "%s(): [stalled] timeout=%d "
854					    "count=%d hcount=%d "
855					    "resid=%d minflush=%d\n",
856					    __func__, c->timeout, count,
857					    hcount, resid, minflush);
858			} else if (resid < residp && count < hcount) {
859				++count;
860				if (snd_verbose > 3)
861					device_printf(c->dev,
862					    "%s((): [resume] timeout=%d "
863					    "count=%d hcount=%d "
864					    "resid=%d minflush=%d\n",
865					    __func__, c->timeout, count,
866					    hcount, resid, minflush);
867			}
868			if (minflush > 0 && sndbuf_getfree(bs) > 0) {
869				threshold = min(minflush,
870				    sndbuf_getfree(bs));
871				sndbuf_clear(bs, threshold);
872				sndbuf_acquire(bs, NULL, threshold);
873				resid = sndbuf_getready(bs);
874				minflush -= threshold;
875			}
876			residp = resid;
877		} else
878			break;
879	}
880	c->flags &= ~CHN_F_CLOSING;
881	c->flags |= cflag;
882
883	if (snd_verbose > 3)
884		device_printf(c->dev,
885		    "%s(): timeout=%d count=%d hcount=%d resid=%d residp=%d "
886		    "minflush=%d ret=%d\n",
887		    __func__, c->timeout, count, hcount, resid, residp,
888		    minflush, ret);
889
890    	return (0);
891}
892
893/* called externally, handle locking */
894int
895chn_poll(struct pcm_channel *c, int ev, struct thread *td)
896{
897	struct snd_dbuf *bs = c->bufsoft;
898	int ret;
899
900	CHN_LOCKASSERT(c);
901
902    	if (!(c->flags & (CHN_F_MMAP | CHN_F_TRIGGERED))) {
903		ret = chn_start(c, 1);
904		if (ret != 0)
905			return (0);
906	}
907
908	ret = 0;
909	if (chn_polltrigger(c)) {
910		chn_pollreset(c);
911		ret = ev;
912	} else
913		selrecord(td, sndbuf_getsel(bs));
914
915	return (ret);
916}
917
918/*
919 * chn_abort terminates a running dma transfer.  it may sleep up to 200ms.
920 * it returns the number of bytes that have not been transferred.
921 *
922 * called from: dsp_close, dsp_ioctl, with channel locked
923 */
924int
925chn_abort(struct pcm_channel *c)
926{
927    	int missing = 0;
928    	struct snd_dbuf *b = c->bufhard;
929    	struct snd_dbuf *bs = c->bufsoft;
930
931	CHN_LOCKASSERT(c);
932	if (CHN_STOPPED(c))
933		return 0;
934	c->flags |= CHN_F_ABORTING;
935
936	c->flags &= ~CHN_F_TRIGGERED;
937	/* kill the channel */
938	chn_trigger(c, PCMTRIG_ABORT);
939	sndbuf_setrun(b, 0);
940	if (!(c->flags & CHN_F_VIRTUAL))
941		chn_dmaupdate(c);
942    	missing = sndbuf_getready(bs);
943
944	c->flags &= ~CHN_F_ABORTING;
945	return missing;
946}
947
948/*
949 * this routine tries to flush the dma transfer. It is called
950 * on a close of a playback channel.
951 * first, if there is data in the buffer, but the dma has not yet
952 * begun, we need to start it.
953 * next, we wait for the play buffer to drain
954 * finally, we stop the dma.
955 *
956 * called from: dsp_close, not valid for record channels.
957 */
958
959int
960chn_flush(struct pcm_channel *c)
961{
962    	struct snd_dbuf *b = c->bufhard;
963
964	CHN_LOCKASSERT(c);
965	KASSERT(c->direction == PCMDIR_PLAY, ("chn_flush on bad channel"));
966    	DEB(printf("chn_flush: c->flags 0x%08x\n", c->flags));
967
968	c->flags |= CHN_F_CLOSING;
969	chn_sync(c, 0);
970	c->flags &= ~CHN_F_TRIGGERED;
971	/* kill the channel */
972	chn_trigger(c, PCMTRIG_ABORT);
973	sndbuf_setrun(b, 0);
974
975    	c->flags &= ~CHN_F_CLOSING;
976    	return 0;
977}
978
979int
980snd_fmtvalid(uint32_t fmt, uint32_t *fmtlist)
981{
982	int i;
983
984	for (i = 0; fmtlist[i] != 0; i++) {
985		if (fmt == fmtlist[i] ||
986		    ((fmt & AFMT_PASSTHROUGH) &&
987		    (AFMT_ENCODING(fmt) & fmtlist[i])))
988			return (1);
989	}
990
991	return (0);
992}
993
994static const struct {
995	char *name, *alias1, *alias2;
996	uint32_t afmt;
997} afmt_tab[] = {
998	{  "alaw",  NULL, NULL, AFMT_A_LAW  },
999	{ "mulaw",  NULL, NULL, AFMT_MU_LAW },
1000	{    "u8",   "8", NULL, AFMT_U8     },
1001	{    "s8",  NULL, NULL, AFMT_S8     },
1002#if BYTE_ORDER == LITTLE_ENDIAN
1003	{ "s16le", "s16", "16", AFMT_S16_LE },
1004	{ "s16be",  NULL, NULL, AFMT_S16_BE },
1005#else
1006	{ "s16le",  NULL, NULL, AFMT_S16_LE },
1007	{ "s16be", "s16", "16", AFMT_S16_BE },
1008#endif
1009	{ "u16le",  NULL, NULL, AFMT_U16_LE },
1010	{ "u16be",  NULL, NULL, AFMT_U16_BE },
1011	{ "s24le",  NULL, NULL, AFMT_S24_LE },
1012	{ "s24be",  NULL, NULL, AFMT_S24_BE },
1013	{ "u24le",  NULL, NULL, AFMT_U24_LE },
1014	{ "u24be",  NULL, NULL, AFMT_U24_BE },
1015#if BYTE_ORDER == LITTLE_ENDIAN
1016	{ "s32le", "s32", "32", AFMT_S32_LE },
1017	{ "s32be",  NULL, NULL, AFMT_S32_BE },
1018#else
1019	{ "s32le",  NULL, NULL, AFMT_S32_LE },
1020	{ "s32be", "s32", "32", AFMT_S32_BE },
1021#endif
1022	{ "u32le",  NULL, NULL, AFMT_U32_LE },
1023	{ "u32be",  NULL, NULL, AFMT_U32_BE },
1024	{   "ac3",  NULL, NULL, AFMT_AC3    },
1025	{    NULL,  NULL, NULL, 0           }
1026};
1027
1028uint32_t
1029snd_str2afmt(const char *req)
1030{
1031	int ext;
1032	int ch;
1033	int i;
1034	char b1[8];
1035	char b2[8];
1036
1037	memset(b1, 0, sizeof(b1));
1038	memset(b2, 0, sizeof(b2));
1039
1040	i = sscanf(req, "%5[^:]:%6s", b1, b2);
1041
1042	if (i == 1) {
1043		if (strlen(req) != strlen(b1))
1044			return (0);
1045		strlcpy(b2, "2.0", sizeof(b2));
1046	} else if (i == 2) {
1047		if (strlen(req) != (strlen(b1) + 1 + strlen(b2)))
1048			return (0);
1049	} else
1050		return (0);
1051
1052	i = sscanf(b2, "%d.%d", &ch, &ext);
1053
1054	if (i == 0) {
1055		if (strcasecmp(b2, "mono") == 0) {
1056			ch = 1;
1057			ext = 0;
1058		} else if (strcasecmp(b2, "stereo") == 0) {
1059			ch = 2;
1060			ext = 0;
1061		} else if (strcasecmp(b2, "quad") == 0) {
1062			ch = 4;
1063			ext = 0;
1064		} else
1065			return (0);
1066	} else if (i == 1) {
1067		if (ch < 1 || ch > AFMT_CHANNEL_MAX)
1068			return (0);
1069		ext = 0;
1070	} else if (i == 2) {
1071		if (ext < 0 || ext > AFMT_EXTCHANNEL_MAX)
1072			return (0);
1073		if (ch < 1 || (ch + ext) > AFMT_CHANNEL_MAX)
1074			return (0);
1075	} else
1076		return (0);
1077
1078	for (i = 0; afmt_tab[i].name != NULL; i++) {
1079		if (strcasecmp(afmt_tab[i].name, b1) != 0) {
1080			if (afmt_tab[i].alias1 == NULL)
1081				continue;
1082			if (strcasecmp(afmt_tab[i].alias1, b1) != 0) {
1083				if (afmt_tab[i].alias2 == NULL)
1084					continue;
1085				if (strcasecmp(afmt_tab[i].alias2, b1) != 0)
1086					continue;
1087			}
1088		}
1089		/* found a match */
1090		return (SND_FORMAT(afmt_tab[i].afmt, ch + ext, ext));
1091	}
1092	/* not a valid format */
1093	return (0);
1094}
1095
1096uint32_t
1097snd_afmt2str(uint32_t afmt, char *buf, size_t len)
1098{
1099	uint32_t enc;
1100	uint32_t ext;
1101	uint32_t ch;
1102	int i;
1103
1104	if (buf == NULL || len < AFMTSTR_LEN)
1105		return (0);
1106
1107	memset(buf, 0, len);
1108
1109	enc = AFMT_ENCODING(afmt);
1110	ch = AFMT_CHANNEL(afmt);
1111	ext = AFMT_EXTCHANNEL(afmt);
1112	/* check there is at least one channel */
1113	if (ch <= ext)
1114		return (0);
1115	for (i = 0; afmt_tab[i].name != NULL; i++) {
1116		if (enc != afmt_tab[i].afmt)
1117			continue;
1118		/* found a match */
1119		snprintf(buf, len, "%s:%d.%d",
1120		    afmt_tab[i].name, ch - ext, ext);
1121		return (SND_FORMAT(enc, ch, ext));
1122	}
1123	return (0);
1124}
1125
1126int
1127chn_reset(struct pcm_channel *c, uint32_t fmt, uint32_t spd)
1128{
1129	int r;
1130
1131	CHN_LOCKASSERT(c);
1132	c->feedcount = 0;
1133	c->flags &= CHN_F_RESET;
1134	c->interrupts = 0;
1135	c->timeout = 1;
1136	c->xruns = 0;
1137
1138	c->flags |= (pcm_getflags(c->dev) & SD_F_BITPERFECT) ?
1139	    CHN_F_BITPERFECT : 0;
1140
1141	r = CHANNEL_RESET(c->methods, c->devinfo);
1142	if (r == 0 && fmt != 0 && spd != 0) {
1143		r = chn_setparam(c, fmt, spd);
1144		fmt = 0;
1145		spd = 0;
1146	}
1147	if (r == 0 && fmt != 0)
1148		r = chn_setformat(c, fmt);
1149	if (r == 0 && spd != 0)
1150		r = chn_setspeed(c, spd);
1151	if (r == 0)
1152		r = chn_setlatency(c, chn_latency);
1153	if (r == 0) {
1154		chn_resetbuf(c);
1155		r = CHANNEL_RESETDONE(c->methods, c->devinfo);
1156	}
1157	return r;
1158}
1159
1160struct pcm_channel *
1161chn_init(struct snddev_info *d, struct pcm_channel *parent, kobj_class_t cls,
1162    int dir, void *devinfo)
1163{
1164	struct pcm_channel *c;
1165	struct feeder_class *fc;
1166	struct snd_dbuf *b, *bs;
1167	char *dirs, *devname, buf[CHN_NAMELEN];
1168	int i, ret, direction, rpnum, *pnum, max, type, unit;
1169
1170	PCM_BUSYASSERT(d);
1171	PCM_LOCKASSERT(d);
1172
1173	switch (dir) {
1174	case PCMDIR_PLAY:
1175		dirs = "play";
1176		direction = PCMDIR_PLAY;
1177		pnum = &d->playcount;
1178		type = SND_DEV_DSPHW_PLAY;
1179		max = SND_MAXHWCHAN;
1180		break;
1181	case PCMDIR_PLAY_VIRTUAL:
1182		dirs = "virtual_play";
1183		direction = PCMDIR_PLAY;
1184		pnum = &d->pvchancount;
1185		type = SND_DEV_DSPHW_VPLAY;
1186		max = SND_MAXVCHANS;
1187		break;
1188	case PCMDIR_REC:
1189		dirs = "record";
1190		direction = PCMDIR_REC;
1191		pnum = &d->reccount;
1192		type = SND_DEV_DSPHW_REC;
1193		max = SND_MAXHWCHAN;
1194		break;
1195	case PCMDIR_REC_VIRTUAL:
1196		dirs = "virtual_record";
1197		direction = PCMDIR_REC;
1198		pnum = &d->rvchancount;
1199		type = SND_DEV_DSPHW_VREC;
1200		max = SND_MAXVCHANS;
1201		break;
1202	default:
1203		device_printf(d->dev,
1204		    "%s(): invalid channel direction: %d\n",
1205		    __func__, dir);
1206		goto out1;
1207	}
1208
1209	unit = 0;
1210
1211	if (*pnum >= max || unit >= max) {
1212		device_printf(d->dev, "%s(): unit=%d or pnum=%d >= than "
1213		    "max=%d\n", __func__, unit, *pnum, max);
1214		goto out1;
1215	}
1216
1217	rpnum = 0;
1218
1219	CHN_FOREACH(c, d, channels.pcm) {
1220		if (c->type != type)
1221			continue;
1222		unit++;
1223		if (unit >= max) {
1224			device_printf(d->dev,
1225			    "%s(): chan=%d >= max=%d\n", __func__, unit, max);
1226			goto out1;
1227		}
1228		rpnum++;
1229	}
1230
1231	if (*pnum != rpnum) {
1232		device_printf(d->dev,
1233		    "%s(): pnum screwed: dirs=%s pnum=%d rpnum=%d\n",
1234		    __func__, dirs, *pnum, rpnum);
1235		goto out1;
1236	}
1237
1238	PCM_UNLOCK(d);
1239	b = NULL;
1240	bs = NULL;
1241	c = malloc(sizeof(*c), M_DEVBUF, M_WAITOK | M_ZERO);
1242	c->methods = kobj_create(cls, M_DEVBUF, M_WAITOK | M_ZERO);
1243	c->type = type;
1244	c->unit = unit;
1245	c->pid = -1;
1246	strlcpy(c->comm, CHN_COMM_UNUSED, sizeof(c->comm));
1247	c->parentsnddev = d;
1248	c->parentchannel = parent;
1249	c->dev = d->dev;
1250	c->trigger = PCMTRIG_STOP;
1251	chn_lockinit(c, dir);
1252	devname = dsp_unit2name(buf, sizeof(buf), c);
1253	if (devname == NULL) {
1254		ret = EINVAL;
1255		device_printf(d->dev, "%s(): failed to create channel name",
1256		    __func__);
1257		goto out2;
1258	}
1259	snprintf(c->name, sizeof(c->name), "%s:%s:%s",
1260	    device_get_nameunit(c->dev), dirs, devname);
1261
1262	CHN_INIT(c, children);
1263	CHN_INIT(c, children.busy);
1264	c->latency = -1;
1265	c->timeout = 1;
1266
1267	ret = ENOMEM;
1268	b = sndbuf_create(c->dev, c->name, "primary", c);
1269	if (b == NULL) {
1270		device_printf(d->dev, "%s(): failed to create hardware buffer\n",
1271		    __func__);
1272		goto out2;
1273	}
1274	bs = sndbuf_create(c->dev, c->name, "secondary", c);
1275	if (bs == NULL) {
1276		device_printf(d->dev, "%s(): failed to create software buffer\n",
1277		    __func__);
1278		goto out2;
1279	}
1280
1281	CHN_LOCK(c);
1282
1283	ret = EINVAL;
1284	fc = feeder_getclass(NULL);
1285	if (fc == NULL) {
1286		device_printf(d->dev, "%s(): failed to get feeder class\n",
1287		    __func__);
1288		goto out2;
1289	}
1290	if (chn_addfeeder(c, fc, NULL)) {
1291		device_printf(d->dev, "%s(): failed to add feeder\n", __func__);
1292		goto out2;
1293	}
1294
1295	/*
1296	 * XXX - sndbuf_setup() & sndbuf_resize() expect to be called
1297	 *	 with the channel unlocked because they are also called
1298	 *	 from driver methods that don't know about locking
1299	 */
1300	CHN_UNLOCK(c);
1301	sndbuf_setup(bs, NULL, 0);
1302	CHN_LOCK(c);
1303	c->bufhard = b;
1304	c->bufsoft = bs;
1305	c->flags = 0;
1306	c->feederflags = 0;
1307	c->sm = NULL;
1308	c->format = SND_FORMAT(AFMT_U8, 1, 0);
1309	c->speed = DSP_DEFAULT_SPEED;
1310
1311	c->matrix = *feeder_matrix_id_map(SND_CHN_MATRIX_1_0);
1312	c->matrix.id = SND_CHN_MATRIX_PCMCHANNEL;
1313
1314	for (i = 0; i < SND_CHN_T_MAX; i++) {
1315		c->volume[SND_VOL_C_MASTER][i] = SND_VOL_0DB_MASTER;
1316	}
1317
1318	c->volume[SND_VOL_C_MASTER][SND_CHN_T_VOL_0DB] = SND_VOL_0DB_MASTER;
1319	c->volume[SND_VOL_C_PCM][SND_CHN_T_VOL_0DB] = chn_vol_0db_pcm;
1320
1321	memset(c->muted, 0, sizeof(c->muted));
1322
1323	chn_vpc_reset(c, SND_VOL_C_PCM, 1);
1324
1325	ret = ENODEV;
1326	CHN_UNLOCK(c); /* XXX - Unlock for CHANNEL_INIT() malloc() call */
1327	c->devinfo = CHANNEL_INIT(c->methods, devinfo, b, c, direction);
1328	CHN_LOCK(c);
1329	if (c->devinfo == NULL) {
1330		device_printf(d->dev, "%s(): NULL devinfo\n", __func__);
1331		goto out2;
1332	}
1333
1334	ret = ENOMEM;
1335	if ((sndbuf_getsize(b) == 0) && ((c->flags & CHN_F_VIRTUAL) == 0)) {
1336		device_printf(d->dev, "%s(): hardware buffer's size is 0\n",
1337		    __func__);
1338		goto out2;
1339	}
1340
1341	ret = 0;
1342	c->direction = direction;
1343
1344	sndbuf_setfmt(b, c->format);
1345	sndbuf_setspd(b, c->speed);
1346	sndbuf_setfmt(bs, c->format);
1347	sndbuf_setspd(bs, c->speed);
1348
1349	/**
1350	 * @todo Should this be moved somewhere else?  The primary buffer
1351	 * 	 is allocated by the driver or via DMA map setup, and tmpbuf
1352	 * 	 seems to only come into existence in sndbuf_resize().
1353	 */
1354	if (c->direction == PCMDIR_PLAY) {
1355		bs->sl = sndbuf_getmaxsize(bs);
1356		bs->shadbuf = malloc(bs->sl, M_DEVBUF, M_NOWAIT);
1357		if (bs->shadbuf == NULL) {
1358			ret = ENOMEM;
1359			device_printf(d->dev, "%s(): failed to create shadow "
1360			    "buffer\n", __func__);
1361			goto out2;
1362		}
1363	}
1364out2:
1365	if (CHN_LOCKOWNED(c))
1366		CHN_UNLOCK(c);
1367	if (ret) {
1368		if (c->devinfo) {
1369			if (CHANNEL_FREE(c->methods, c->devinfo))
1370				sndbuf_free(b);
1371		}
1372		if (bs)
1373			sndbuf_destroy(bs);
1374		if (b)
1375			sndbuf_destroy(b);
1376		CHN_LOCK(c);
1377		c->flags |= CHN_F_DEAD;
1378		chn_lockdestroy(c);
1379
1380		PCM_LOCK(d);
1381
1382		kobj_delete(c->methods, M_DEVBUF);
1383		free(c, M_DEVBUF);
1384
1385		return (NULL);
1386	}
1387
1388	PCM_LOCK(d);
1389
1390	return (c);
1391out1:
1392	return (NULL);
1393}
1394
1395void
1396chn_kill(struct pcm_channel *c)
1397{
1398	struct snd_dbuf *b = c->bufhard;
1399	struct snd_dbuf *bs = c->bufsoft;
1400
1401	PCM_BUSYASSERT(c->parentsnddev);
1402
1403	if (CHN_STARTED(c)) {
1404		CHN_LOCK(c);
1405		chn_trigger(c, PCMTRIG_ABORT);
1406		CHN_UNLOCK(c);
1407	}
1408	while (chn_removefeeder(c) == 0)
1409		;
1410	if (CHANNEL_FREE(c->methods, c->devinfo))
1411		sndbuf_free(b);
1412	sndbuf_destroy(bs);
1413	sndbuf_destroy(b);
1414	CHN_LOCK(c);
1415	c->flags |= CHN_F_DEAD;
1416	chn_lockdestroy(c);
1417	kobj_delete(c->methods, M_DEVBUF);
1418	free(c, M_DEVBUF);
1419}
1420
1421void
1422chn_shutdown(struct pcm_channel *c)
1423{
1424	CHN_LOCKASSERT(c);
1425
1426	chn_wakeup(c);
1427	c->flags |= CHN_F_DEAD;
1428}
1429
1430/* release a locked channel and unlock it */
1431int
1432chn_release(struct pcm_channel *c)
1433{
1434	PCM_BUSYASSERT(c->parentsnddev);
1435	CHN_LOCKASSERT(c);
1436
1437	c->flags &= ~CHN_F_BUSY;
1438	c->pid = -1;
1439	strlcpy(c->comm, CHN_COMM_UNUSED, sizeof(c->comm));
1440	CHN_UNLOCK(c);
1441
1442	return (0);
1443}
1444
1445int
1446chn_ref(struct pcm_channel *c, int ref)
1447{
1448	PCM_BUSYASSERT(c->parentsnddev);
1449	CHN_LOCKASSERT(c);
1450	KASSERT((c->refcount + ref) >= 0,
1451	    ("%s(): new refcount will be negative", __func__));
1452
1453	c->refcount += ref;
1454
1455	return (c->refcount);
1456}
1457
1458int
1459chn_setvolume_multi(struct pcm_channel *c, int vc, int left, int right,
1460    int center)
1461{
1462	int i, ret;
1463
1464	ret = 0;
1465
1466	for (i = 0; i < SND_CHN_T_MAX; i++) {
1467		if ((1 << i) & SND_CHN_LEFT_MASK)
1468			ret |= chn_setvolume_matrix(c, vc, i, left);
1469		else if ((1 << i) & SND_CHN_RIGHT_MASK)
1470			ret |= chn_setvolume_matrix(c, vc, i, right) << 8;
1471		else
1472			ret |= chn_setvolume_matrix(c, vc, i, center) << 16;
1473	}
1474
1475	return (ret);
1476}
1477
1478int
1479chn_setvolume_matrix(struct pcm_channel *c, int vc, int vt, int val)
1480{
1481	int i;
1482
1483	KASSERT(c != NULL && vc >= SND_VOL_C_MASTER && vc < SND_VOL_C_MAX &&
1484	    (vc == SND_VOL_C_MASTER || (vc & 1)) &&
1485	    (vt == SND_CHN_T_VOL_0DB || (vt >= SND_CHN_T_BEGIN &&
1486	    vt <= SND_CHN_T_END)) && (vt != SND_CHN_T_VOL_0DB ||
1487	    (val >= SND_VOL_0DB_MIN && val <= SND_VOL_0DB_MAX)),
1488	    ("%s(): invalid volume matrix c=%p vc=%d vt=%d val=%d",
1489	    __func__, c, vc, vt, val));
1490	CHN_LOCKASSERT(c);
1491
1492	if (val < 0)
1493		val = 0;
1494	if (val > 100)
1495		val = 100;
1496
1497	c->volume[vc][vt] = val;
1498
1499	/*
1500	 * Do relative calculation here and store it into class + 1
1501	 * to ease the job of feeder_volume.
1502	 */
1503	if (vc == SND_VOL_C_MASTER) {
1504		for (vc = SND_VOL_C_BEGIN; vc <= SND_VOL_C_END;
1505		    vc += SND_VOL_C_STEP)
1506			c->volume[SND_VOL_C_VAL(vc)][vt] =
1507			    SND_VOL_CALC_VAL(c->volume, vc, vt);
1508	} else if (vc & 1) {
1509		if (vt == SND_CHN_T_VOL_0DB)
1510			for (i = SND_CHN_T_BEGIN; i <= SND_CHN_T_END;
1511			    i += SND_CHN_T_STEP) {
1512				c->volume[SND_VOL_C_VAL(vc)][i] =
1513				    SND_VOL_CALC_VAL(c->volume, vc, i);
1514			}
1515		else
1516			c->volume[SND_VOL_C_VAL(vc)][vt] =
1517			    SND_VOL_CALC_VAL(c->volume, vc, vt);
1518	}
1519
1520	return (val);
1521}
1522
1523int
1524chn_getvolume_matrix(struct pcm_channel *c, int vc, int vt)
1525{
1526	KASSERT(c != NULL && vc >= SND_VOL_C_MASTER && vc < SND_VOL_C_MAX &&
1527	    (vt == SND_CHN_T_VOL_0DB ||
1528	    (vt >= SND_CHN_T_BEGIN && vt <= SND_CHN_T_END)),
1529	    ("%s(): invalid volume matrix c=%p vc=%d vt=%d",
1530	    __func__, c, vc, vt));
1531	CHN_LOCKASSERT(c);
1532
1533	return (c->volume[vc][vt]);
1534}
1535
1536int
1537chn_setmute_multi(struct pcm_channel *c, int vc, int mute)
1538{
1539	int i, ret;
1540
1541	ret = 0;
1542
1543	for (i = 0; i < SND_CHN_T_MAX; i++) {
1544		if ((1 << i) & SND_CHN_LEFT_MASK)
1545			ret |= chn_setmute_matrix(c, vc, i, mute);
1546		else if ((1 << i) & SND_CHN_RIGHT_MASK)
1547			ret |= chn_setmute_matrix(c, vc, i, mute) << 8;
1548		else
1549			ret |= chn_setmute_matrix(c, vc, i, mute) << 16;
1550	}
1551	return (ret);
1552}
1553
1554int
1555chn_setmute_matrix(struct pcm_channel *c, int vc, int vt, int mute)
1556{
1557	int i;
1558
1559	KASSERT(c != NULL && vc >= SND_VOL_C_MASTER && vc < SND_VOL_C_MAX &&
1560	    (vc == SND_VOL_C_MASTER || (vc & 1)) &&
1561	    (vt == SND_CHN_T_VOL_0DB || (vt >= SND_CHN_T_BEGIN && vt <= SND_CHN_T_END)),
1562	    ("%s(): invalid mute matrix c=%p vc=%d vt=%d mute=%d",
1563	    __func__, c, vc, vt, mute));
1564
1565	CHN_LOCKASSERT(c);
1566
1567	mute = (mute != 0);
1568
1569	c->muted[vc][vt] = mute;
1570
1571	/*
1572	 * Do relative calculation here and store it into class + 1
1573	 * to ease the job of feeder_volume.
1574	 */
1575	if (vc == SND_VOL_C_MASTER) {
1576		for (vc = SND_VOL_C_BEGIN; vc <= SND_VOL_C_END;
1577		    vc += SND_VOL_C_STEP)
1578			c->muted[SND_VOL_C_VAL(vc)][vt] = mute;
1579	} else if (vc & 1) {
1580		if (vt == SND_CHN_T_VOL_0DB) {
1581			for (i = SND_CHN_T_BEGIN; i <= SND_CHN_T_END;
1582			    i += SND_CHN_T_STEP) {
1583				c->muted[SND_VOL_C_VAL(vc)][i] = mute;
1584			}
1585		} else {
1586			c->muted[SND_VOL_C_VAL(vc)][vt] = mute;
1587		}
1588	}
1589	return (mute);
1590}
1591
1592int
1593chn_getmute_matrix(struct pcm_channel *c, int vc, int vt)
1594{
1595	KASSERT(c != NULL && vc >= SND_VOL_C_MASTER && vc < SND_VOL_C_MAX &&
1596	    (vt == SND_CHN_T_VOL_0DB ||
1597	    (vt >= SND_CHN_T_BEGIN && vt <= SND_CHN_T_END)),
1598	    ("%s(): invalid mute matrix c=%p vc=%d vt=%d",
1599	    __func__, c, vc, vt));
1600	CHN_LOCKASSERT(c);
1601
1602	return (c->muted[vc][vt]);
1603}
1604
1605struct pcmchan_matrix *
1606chn_getmatrix(struct pcm_channel *c)
1607{
1608
1609	KASSERT(c != NULL, ("%s(): NULL channel", __func__));
1610	CHN_LOCKASSERT(c);
1611
1612	if (!(c->format & AFMT_CONVERTIBLE))
1613		return (NULL);
1614
1615	return (&c->matrix);
1616}
1617
1618int
1619chn_setmatrix(struct pcm_channel *c, struct pcmchan_matrix *m)
1620{
1621
1622	KASSERT(c != NULL && m != NULL,
1623	    ("%s(): NULL channel or matrix", __func__));
1624	CHN_LOCKASSERT(c);
1625
1626	if (!(c->format & AFMT_CONVERTIBLE))
1627		return (EINVAL);
1628
1629	c->matrix = *m;
1630	c->matrix.id = SND_CHN_MATRIX_PCMCHANNEL;
1631
1632	return (chn_setformat(c, SND_FORMAT(c->format, m->channels, m->ext)));
1633}
1634
1635/*
1636 * XXX chn_oss_* exists for the sake of compatibility.
1637 */
1638int
1639chn_oss_getorder(struct pcm_channel *c, unsigned long long *map)
1640{
1641
1642	KASSERT(c != NULL && map != NULL,
1643	    ("%s(): NULL channel or map", __func__));
1644	CHN_LOCKASSERT(c);
1645
1646	if (!(c->format & AFMT_CONVERTIBLE))
1647		return (EINVAL);
1648
1649	return (feeder_matrix_oss_get_channel_order(&c->matrix, map));
1650}
1651
1652int
1653chn_oss_setorder(struct pcm_channel *c, unsigned long long *map)
1654{
1655	struct pcmchan_matrix m;
1656	int ret;
1657
1658	KASSERT(c != NULL && map != NULL,
1659	    ("%s(): NULL channel or map", __func__));
1660	CHN_LOCKASSERT(c);
1661
1662	if (!(c->format & AFMT_CONVERTIBLE))
1663		return (EINVAL);
1664
1665	m = c->matrix;
1666	ret = feeder_matrix_oss_set_channel_order(&m, map);
1667	if (ret != 0)
1668		return (ret);
1669
1670	return (chn_setmatrix(c, &m));
1671}
1672
1673#define SND_CHN_OSS_FRONT	(SND_CHN_T_MASK_FL | SND_CHN_T_MASK_FR)
1674#define SND_CHN_OSS_SURR	(SND_CHN_T_MASK_SL | SND_CHN_T_MASK_SR)
1675#define SND_CHN_OSS_CENTER_LFE	(SND_CHN_T_MASK_FC | SND_CHN_T_MASK_LF)
1676#define SND_CHN_OSS_REAR	(SND_CHN_T_MASK_BL | SND_CHN_T_MASK_BR)
1677
1678int
1679chn_oss_getmask(struct pcm_channel *c, uint32_t *retmask)
1680{
1681	struct pcmchan_matrix *m;
1682	struct pcmchan_caps *caps;
1683	uint32_t i, format;
1684
1685	KASSERT(c != NULL && retmask != NULL,
1686	    ("%s(): NULL channel or retmask", __func__));
1687	CHN_LOCKASSERT(c);
1688
1689	caps = chn_getcaps(c);
1690	if (caps == NULL || caps->fmtlist == NULL)
1691		return (ENODEV);
1692
1693	for (i = 0; caps->fmtlist[i] != 0; i++) {
1694		format = caps->fmtlist[i];
1695		if (!(format & AFMT_CONVERTIBLE)) {
1696			*retmask |= DSP_BIND_SPDIF;
1697			continue;
1698		}
1699		m = CHANNEL_GETMATRIX(c->methods, c->devinfo, format);
1700		if (m == NULL)
1701			continue;
1702		if (m->mask & SND_CHN_OSS_FRONT)
1703			*retmask |= DSP_BIND_FRONT;
1704		if (m->mask & SND_CHN_OSS_SURR)
1705			*retmask |= DSP_BIND_SURR;
1706		if (m->mask & SND_CHN_OSS_CENTER_LFE)
1707			*retmask |= DSP_BIND_CENTER_LFE;
1708		if (m->mask & SND_CHN_OSS_REAR)
1709			*retmask |= DSP_BIND_REAR;
1710	}
1711
1712	/* report software-supported binding mask */
1713	if (!CHN_BITPERFECT(c) && report_soft_matrix)
1714		*retmask |= DSP_BIND_FRONT | DSP_BIND_SURR |
1715		    DSP_BIND_CENTER_LFE | DSP_BIND_REAR;
1716
1717	return (0);
1718}
1719
1720void
1721chn_vpc_reset(struct pcm_channel *c, int vc, int force)
1722{
1723	int i;
1724
1725	KASSERT(c != NULL && vc >= SND_VOL_C_BEGIN && vc <= SND_VOL_C_END,
1726	    ("%s(): invalid reset c=%p vc=%d", __func__, c, vc));
1727	CHN_LOCKASSERT(c);
1728
1729	if (force == 0 && chn_vpc_autoreset == 0)
1730		return;
1731
1732	for (i = SND_CHN_T_BEGIN; i <= SND_CHN_T_END; i += SND_CHN_T_STEP)
1733		CHN_SETVOLUME(c, vc, i, c->volume[vc][SND_CHN_T_VOL_0DB]);
1734}
1735
1736static u_int32_t
1737round_pow2(u_int32_t v)
1738{
1739	u_int32_t ret;
1740
1741	if (v < 2)
1742		v = 2;
1743	ret = 0;
1744	while (v >> ret)
1745		ret++;
1746	ret = 1 << (ret - 1);
1747	while (ret < v)
1748		ret <<= 1;
1749	return ret;
1750}
1751
1752static u_int32_t
1753round_blksz(u_int32_t v, int round)
1754{
1755	u_int32_t ret, tmp;
1756
1757	if (round < 1)
1758		round = 1;
1759
1760	ret = min(round_pow2(v), CHN_2NDBUFMAXSIZE >> 1);
1761
1762	if (ret > v && (ret >> 1) > 0 && (ret >> 1) >= ((v * 3) >> 2))
1763		ret >>= 1;
1764
1765	tmp = ret - (ret % round);
1766	while (tmp < 16 || tmp < round) {
1767		ret <<= 1;
1768		tmp = ret - (ret % round);
1769	}
1770
1771	return ret;
1772}
1773
1774/*
1775 * 4Front call it DSP Policy, while we call it "Latency Profile". The idea
1776 * is to keep 2nd buffer short so that it doesn't cause long queue during
1777 * buffer transfer.
1778 *
1779 *    Latency reference table for 48khz stereo 16bit: (PLAY)
1780 *
1781 *      +---------+------------+-----------+------------+
1782 *      | Latency | Blockcount | Blocksize | Buffersize |
1783 *      +---------+------------+-----------+------------+
1784 *      |     0   |       2    |   64      |    128     |
1785 *      +---------+------------+-----------+------------+
1786 *      |     1   |       4    |   128     |    512     |
1787 *      +---------+------------+-----------+------------+
1788 *      |     2   |       8    |   512     |    4096    |
1789 *      +---------+------------+-----------+------------+
1790 *      |     3   |      16    |   512     |    8192    |
1791 *      +---------+------------+-----------+------------+
1792 *      |     4   |      32    |   512     |    16384   |
1793 *      +---------+------------+-----------+------------+
1794 *      |     5   |      32    |   1024    |    32768   |
1795 *      +---------+------------+-----------+------------+
1796 *      |     6   |      16    |   2048    |    32768   |
1797 *      +---------+------------+-----------+------------+
1798 *      |     7   |       8    |   4096    |    32768   |
1799 *      +---------+------------+-----------+------------+
1800 *      |     8   |       4    |   8192    |    32768   |
1801 *      +---------+------------+-----------+------------+
1802 *      |     9   |       2    |   16384   |    32768   |
1803 *      +---------+------------+-----------+------------+
1804 *      |    10   |       2    |   32768   |    65536   |
1805 *      +---------+------------+-----------+------------+
1806 *
1807 * Recording need a different reference table. All we care is
1808 * gobbling up everything within reasonable buffering threshold.
1809 *
1810 *    Latency reference table for 48khz stereo 16bit: (REC)
1811 *
1812 *      +---------+------------+-----------+------------+
1813 *      | Latency | Blockcount | Blocksize | Buffersize |
1814 *      +---------+------------+-----------+------------+
1815 *      |     0   |     512    |   32      |    16384   |
1816 *      +---------+------------+-----------+------------+
1817 *      |     1   |     256    |   64      |    16384   |
1818 *      +---------+------------+-----------+------------+
1819 *      |     2   |     128    |   128     |    16384   |
1820 *      +---------+------------+-----------+------------+
1821 *      |     3   |      64    |   256     |    16384   |
1822 *      +---------+------------+-----------+------------+
1823 *      |     4   |      32    |   512     |    16384   |
1824 *      +---------+------------+-----------+------------+
1825 *      |     5   |      32    |   1024    |    32768   |
1826 *      +---------+------------+-----------+------------+
1827 *      |     6   |      16    |   2048    |    32768   |
1828 *      +---------+------------+-----------+------------+
1829 *      |     7   |       8    |   4096    |    32768   |
1830 *      +---------+------------+-----------+------------+
1831 *      |     8   |       4    |   8192    |    32768   |
1832 *      +---------+------------+-----------+------------+
1833 *      |     9   |       2    |   16384   |    32768   |
1834 *      +---------+------------+-----------+------------+
1835 *      |    10   |       2    |   32768   |    65536   |
1836 *      +---------+------------+-----------+------------+
1837 *
1838 * Calculations for other data rate are entirely based on these reference
1839 * tables. For normal operation, Latency 5 seems give the best, well
1840 * balanced performance for typical workload. Anything below 5 will
1841 * eat up CPU to keep up with increasing context switches because of
1842 * shorter buffer space and usually require the application to handle it
1843 * aggressively through possibly real time programming technique.
1844 *
1845 */
1846#define CHN_LATENCY_PBLKCNT_REF				\
1847	{{1, 2, 3, 4, 5, 5, 4, 3, 2, 1, 1},		\
1848	{1, 2, 3, 4, 5, 5, 4, 3, 2, 1, 1}}
1849#define CHN_LATENCY_PBUFSZ_REF				\
1850	{{7, 9, 12, 13, 14, 15, 15, 15, 15, 15, 16},	\
1851	{11, 12, 13, 14, 15, 16, 16, 16, 16, 16, 17}}
1852
1853#define CHN_LATENCY_RBLKCNT_REF				\
1854	{{9, 8, 7, 6, 5, 5, 4, 3, 2, 1, 1},		\
1855	{9, 8, 7, 6, 5, 5, 4, 3, 2, 1, 1}}
1856#define CHN_LATENCY_RBUFSZ_REF				\
1857	{{14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 16},	\
1858	{15, 15, 15, 15, 15, 16, 16, 16, 16, 16, 17}}
1859
1860#define CHN_LATENCY_DATA_REF	192000 /* 48khz stereo 16bit ~ 48000 x 2 x 2 */
1861
1862static int
1863chn_calclatency(int dir, int latency, int bps, u_int32_t datarate,
1864				u_int32_t max, int *rblksz, int *rblkcnt)
1865{
1866	static int pblkcnts[CHN_LATENCY_PROFILE_MAX + 1][CHN_LATENCY_MAX + 1] =
1867	    CHN_LATENCY_PBLKCNT_REF;
1868	static int  pbufszs[CHN_LATENCY_PROFILE_MAX + 1][CHN_LATENCY_MAX + 1] =
1869	    CHN_LATENCY_PBUFSZ_REF;
1870	static int rblkcnts[CHN_LATENCY_PROFILE_MAX + 1][CHN_LATENCY_MAX + 1] =
1871	    CHN_LATENCY_RBLKCNT_REF;
1872	static int  rbufszs[CHN_LATENCY_PROFILE_MAX + 1][CHN_LATENCY_MAX + 1] =
1873	    CHN_LATENCY_RBUFSZ_REF;
1874	u_int32_t bufsz;
1875	int lprofile, blksz, blkcnt;
1876
1877	if (latency < CHN_LATENCY_MIN || latency > CHN_LATENCY_MAX ||
1878	    bps < 1 || datarate < 1 ||
1879	    !(dir == PCMDIR_PLAY || dir == PCMDIR_REC)) {
1880		if (rblksz != NULL)
1881			*rblksz = CHN_2NDBUFMAXSIZE >> 1;
1882		if (rblkcnt != NULL)
1883			*rblkcnt = 2;
1884		printf("%s(): FAILED dir=%d latency=%d bps=%d "
1885		    "datarate=%u max=%u\n",
1886		    __func__, dir, latency, bps, datarate, max);
1887		return CHN_2NDBUFMAXSIZE;
1888	}
1889
1890	lprofile = chn_latency_profile;
1891
1892	if (dir == PCMDIR_PLAY) {
1893		blkcnt = pblkcnts[lprofile][latency];
1894		bufsz = pbufszs[lprofile][latency];
1895	} else {
1896		blkcnt = rblkcnts[lprofile][latency];
1897		bufsz = rbufszs[lprofile][latency];
1898	}
1899
1900	bufsz = round_pow2(snd_xbytes(1 << bufsz, CHN_LATENCY_DATA_REF,
1901	    datarate));
1902	if (bufsz > max)
1903		bufsz = max;
1904	blksz = round_blksz(bufsz >> blkcnt, bps);
1905
1906	if (rblksz != NULL)
1907		*rblksz = blksz;
1908	if (rblkcnt != NULL)
1909		*rblkcnt = 1 << blkcnt;
1910
1911	return blksz << blkcnt;
1912}
1913
1914static int
1915chn_resizebuf(struct pcm_channel *c, int latency,
1916					int blkcnt, int blksz)
1917{
1918	struct snd_dbuf *b, *bs, *pb;
1919	int sblksz, sblkcnt, hblksz, hblkcnt, limit = 0, nsblksz, nsblkcnt;
1920	int ret;
1921
1922	CHN_LOCKASSERT(c);
1923
1924	if ((c->flags & (CHN_F_MMAP | CHN_F_TRIGGERED)) ||
1925	    !(c->direction == PCMDIR_PLAY || c->direction == PCMDIR_REC))
1926		return EINVAL;
1927
1928	if (latency == -1) {
1929		c->latency = -1;
1930		latency = chn_latency;
1931	} else if (latency == -2) {
1932		latency = c->latency;
1933		if (latency < CHN_LATENCY_MIN || latency > CHN_LATENCY_MAX)
1934			latency = chn_latency;
1935	} else if (latency < CHN_LATENCY_MIN || latency > CHN_LATENCY_MAX)
1936		return EINVAL;
1937	else {
1938		c->latency = latency;
1939	}
1940
1941	bs = c->bufsoft;
1942	b = c->bufhard;
1943
1944	if (!(blksz == 0 || blkcnt == -1) &&
1945	    (blksz < 16 || blksz < sndbuf_getalign(bs) || blkcnt < 2 ||
1946	    (blksz * blkcnt) > CHN_2NDBUFMAXSIZE))
1947		return EINVAL;
1948
1949	chn_calclatency(c->direction, latency, sndbuf_getalign(bs),
1950	    sndbuf_getalign(bs) * sndbuf_getspd(bs), CHN_2NDBUFMAXSIZE,
1951	    &sblksz, &sblkcnt);
1952
1953	if (blksz == 0 || blkcnt == -1) {
1954		if (blkcnt == -1)
1955			c->flags &= ~CHN_F_HAS_SIZE;
1956		if (c->flags & CHN_F_HAS_SIZE) {
1957			blksz = sndbuf_getblksz(bs);
1958			blkcnt = sndbuf_getblkcnt(bs);
1959		}
1960	} else
1961		c->flags |= CHN_F_HAS_SIZE;
1962
1963	if (c->flags & CHN_F_HAS_SIZE) {
1964		/*
1965		 * The application has requested their own blksz/blkcnt.
1966		 * Just obey with it, and let them toast alone. We can
1967		 * clamp it to the nearest latency profile, but that would
1968		 * defeat the purpose of having custom control. The least
1969		 * we can do is round it to the nearest ^2 and align it.
1970		 */
1971		sblksz = round_blksz(blksz, sndbuf_getalign(bs));
1972		sblkcnt = round_pow2(blkcnt);
1973	}
1974
1975	if (c->parentchannel != NULL) {
1976		pb = c->parentchannel->bufsoft;
1977		CHN_UNLOCK(c);
1978		CHN_LOCK(c->parentchannel);
1979		chn_notify(c->parentchannel, CHN_N_BLOCKSIZE);
1980		CHN_UNLOCK(c->parentchannel);
1981		CHN_LOCK(c);
1982		if (c->direction == PCMDIR_PLAY) {
1983			limit = (pb != NULL) ?
1984			    sndbuf_xbytes(sndbuf_getsize(pb), pb, bs) : 0;
1985		} else {
1986			limit = (pb != NULL) ?
1987			    sndbuf_xbytes(sndbuf_getblksz(pb), pb, bs) * 2 : 0;
1988		}
1989	} else {
1990		hblkcnt = 2;
1991		if (c->flags & CHN_F_HAS_SIZE) {
1992			hblksz = round_blksz(sndbuf_xbytes(sblksz, bs, b),
1993			    sndbuf_getalign(b));
1994			hblkcnt = round_pow2(sndbuf_getblkcnt(bs));
1995		} else
1996			chn_calclatency(c->direction, latency,
1997			    sndbuf_getalign(b),
1998			    sndbuf_getalign(b) * sndbuf_getspd(b),
1999			    CHN_2NDBUFMAXSIZE, &hblksz, &hblkcnt);
2000
2001		if ((hblksz << 1) > sndbuf_getmaxsize(b))
2002			hblksz = round_blksz(sndbuf_getmaxsize(b) >> 1,
2003			    sndbuf_getalign(b));
2004
2005		while ((hblksz * hblkcnt) > sndbuf_getmaxsize(b)) {
2006			if (hblkcnt < 4)
2007				hblksz >>= 1;
2008			else
2009				hblkcnt >>= 1;
2010		}
2011
2012		hblksz -= hblksz % sndbuf_getalign(b);
2013
2014#if 0
2015		hblksz = sndbuf_getmaxsize(b) >> 1;
2016		hblksz -= hblksz % sndbuf_getalign(b);
2017		hblkcnt = 2;
2018#endif
2019
2020		CHN_UNLOCK(c);
2021		if (chn_usefrags == 0 ||
2022		    CHANNEL_SETFRAGMENTS(c->methods, c->devinfo,
2023		    hblksz, hblkcnt) != 0)
2024			sndbuf_setblksz(b, CHANNEL_SETBLOCKSIZE(c->methods,
2025			    c->devinfo, hblksz));
2026		CHN_LOCK(c);
2027
2028		if (!CHN_EMPTY(c, children)) {
2029			nsblksz = round_blksz(
2030			    sndbuf_xbytes(sndbuf_getblksz(b), b, bs),
2031			    sndbuf_getalign(bs));
2032			nsblkcnt = sndbuf_getblkcnt(b);
2033			if (c->direction == PCMDIR_PLAY) {
2034				do {
2035					nsblkcnt--;
2036				} while (nsblkcnt >= 2 &&
2037				    nsblksz * nsblkcnt >= sblksz * sblkcnt);
2038				nsblkcnt++;
2039			}
2040			sblksz = nsblksz;
2041			sblkcnt = nsblkcnt;
2042			limit = 0;
2043		} else
2044			limit = sndbuf_xbytes(sndbuf_getblksz(b), b, bs) * 2;
2045	}
2046
2047	if (limit > CHN_2NDBUFMAXSIZE)
2048		limit = CHN_2NDBUFMAXSIZE;
2049
2050#if 0
2051	while (limit > 0 && (sblksz * sblkcnt) > limit) {
2052		if (sblkcnt < 4)
2053			break;
2054		sblkcnt >>= 1;
2055	}
2056#endif
2057
2058	while ((sblksz * sblkcnt) < limit)
2059		sblkcnt <<= 1;
2060
2061	while ((sblksz * sblkcnt) > CHN_2NDBUFMAXSIZE) {
2062		if (sblkcnt < 4)
2063			sblksz >>= 1;
2064		else
2065			sblkcnt >>= 1;
2066	}
2067
2068	sblksz -= sblksz % sndbuf_getalign(bs);
2069
2070	if (sndbuf_getblkcnt(bs) != sblkcnt || sndbuf_getblksz(bs) != sblksz ||
2071	    sndbuf_getsize(bs) != (sblkcnt * sblksz)) {
2072		ret = sndbuf_remalloc(bs, sblkcnt, sblksz);
2073		if (ret != 0) {
2074			device_printf(c->dev, "%s(): Failed: %d %d\n",
2075			    __func__, sblkcnt, sblksz);
2076			return ret;
2077		}
2078	}
2079
2080	/*
2081	 * Interrupt timeout
2082	 */
2083	c->timeout = ((u_int64_t)hz * sndbuf_getsize(bs)) /
2084	    ((u_int64_t)sndbuf_getspd(bs) * sndbuf_getalign(bs));
2085	if (c->parentchannel != NULL)
2086		c->timeout = min(c->timeout, c->parentchannel->timeout);
2087	if (c->timeout < 1)
2088		c->timeout = 1;
2089
2090	/*
2091	 * OSSv4 docs: "By default OSS will set the low water level equal
2092	 * to the fragment size which is optimal in most cases."
2093	 */
2094	c->lw = sndbuf_getblksz(bs);
2095	chn_resetbuf(c);
2096
2097	if (snd_verbose > 3)
2098		device_printf(c->dev, "%s(): %s (%s) timeout=%u "
2099		    "b[%d/%d/%d] bs[%d/%d/%d] limit=%d\n",
2100		    __func__, CHN_DIRSTR(c),
2101		    (c->flags & CHN_F_VIRTUAL) ? "virtual" : "hardware",
2102		    c->timeout,
2103		    sndbuf_getsize(b), sndbuf_getblksz(b),
2104		    sndbuf_getblkcnt(b),
2105		    sndbuf_getsize(bs), sndbuf_getblksz(bs),
2106		    sndbuf_getblkcnt(bs), limit);
2107
2108	return 0;
2109}
2110
2111int
2112chn_setlatency(struct pcm_channel *c, int latency)
2113{
2114	CHN_LOCKASSERT(c);
2115	/* Destroy blksz/blkcnt, enforce latency profile. */
2116	return chn_resizebuf(c, latency, -1, 0);
2117}
2118
2119int
2120chn_setblocksize(struct pcm_channel *c, int blkcnt, int blksz)
2121{
2122	CHN_LOCKASSERT(c);
2123	/* Destroy latency profile, enforce blksz/blkcnt */
2124	return chn_resizebuf(c, -1, blkcnt, blksz);
2125}
2126
2127int
2128chn_setparam(struct pcm_channel *c, uint32_t format, uint32_t speed)
2129{
2130	struct pcmchan_caps *caps;
2131	uint32_t hwspeed, delta;
2132	int ret;
2133
2134	CHN_LOCKASSERT(c);
2135
2136	if (speed < 1 || format == 0 || CHN_STARTED(c))
2137		return (EINVAL);
2138
2139	c->format = format;
2140	c->speed = speed;
2141
2142	caps = chn_getcaps(c);
2143
2144	hwspeed = speed;
2145	RANGE(hwspeed, caps->minspeed, caps->maxspeed);
2146
2147	sndbuf_setspd(c->bufhard, CHANNEL_SETSPEED(c->methods, c->devinfo,
2148	    hwspeed));
2149	hwspeed = sndbuf_getspd(c->bufhard);
2150
2151	delta = (hwspeed > speed) ? (hwspeed - speed) : (speed - hwspeed);
2152
2153	if (delta <= feeder_rate_round)
2154		c->speed = hwspeed;
2155
2156	ret = feeder_chain(c);
2157
2158	if (ret == 0)
2159		ret = CHANNEL_SETFORMAT(c->methods, c->devinfo,
2160		    sndbuf_getfmt(c->bufhard));
2161
2162	if (ret == 0)
2163		ret = chn_resizebuf(c, -2, 0, 0);
2164
2165	return (ret);
2166}
2167
2168int
2169chn_setspeed(struct pcm_channel *c, uint32_t speed)
2170{
2171	uint32_t oldformat, oldspeed, format;
2172	int ret;
2173
2174#if 0
2175	/* XXX force 48k */
2176	if (c->format & AFMT_PASSTHROUGH)
2177		speed = AFMT_PASSTHROUGH_RATE;
2178#endif
2179
2180	oldformat = c->format;
2181	oldspeed = c->speed;
2182	format = oldformat;
2183
2184	ret = chn_setparam(c, format, speed);
2185	if (ret != 0) {
2186		if (snd_verbose > 3)
2187			device_printf(c->dev,
2188			    "%s(): Setting speed %d failed, "
2189			    "falling back to %d\n",
2190			    __func__, speed, oldspeed);
2191		chn_setparam(c, c->format, oldspeed);
2192	}
2193
2194	return (ret);
2195}
2196
2197int
2198chn_setformat(struct pcm_channel *c, uint32_t format)
2199{
2200	uint32_t oldformat, oldspeed, speed;
2201	int ret;
2202
2203	/* XXX force stereo */
2204	if ((format & AFMT_PASSTHROUGH) && AFMT_CHANNEL(format) < 2) {
2205		format = SND_FORMAT(format, AFMT_PASSTHROUGH_CHANNEL,
2206		    AFMT_PASSTHROUGH_EXTCHANNEL);
2207	}
2208
2209	oldformat = c->format;
2210	oldspeed = c->speed;
2211	speed = oldspeed;
2212
2213	ret = chn_setparam(c, format, speed);
2214	if (ret != 0) {
2215		if (snd_verbose > 3)
2216			device_printf(c->dev,
2217			    "%s(): Format change 0x%08x failed, "
2218			    "falling back to 0x%08x\n",
2219			    __func__, format, oldformat);
2220		chn_setparam(c, oldformat, oldspeed);
2221	}
2222
2223	return (ret);
2224}
2225
2226void
2227chn_syncstate(struct pcm_channel *c)
2228{
2229	struct snddev_info *d;
2230	struct snd_mixer *m;
2231
2232	d = (c != NULL) ? c->parentsnddev : NULL;
2233	m = (d != NULL && d->mixer_dev != NULL) ? d->mixer_dev->si_drv1 :
2234	    NULL;
2235
2236	if (d == NULL || m == NULL)
2237		return;
2238
2239	CHN_LOCKASSERT(c);
2240
2241	if (c->feederflags & (1 << FEEDER_VOLUME)) {
2242		uint32_t parent;
2243		int vol, pvol, left, right, center;
2244
2245		if (c->direction == PCMDIR_PLAY &&
2246		    (d->flags & SD_F_SOFTPCMVOL)) {
2247			/* CHN_UNLOCK(c); */
2248			vol = mix_get(m, SOUND_MIXER_PCM);
2249			parent = mix_getparent(m, SOUND_MIXER_PCM);
2250			if (parent != SOUND_MIXER_NONE)
2251				pvol = mix_get(m, parent);
2252			else
2253				pvol = 100 | (100 << 8);
2254			/* CHN_LOCK(c); */
2255		} else {
2256			vol = 100 | (100 << 8);
2257			pvol = vol;
2258		}
2259
2260		if (vol == -1) {
2261			device_printf(c->dev,
2262			    "Soft PCM Volume: Failed to read pcm "
2263			    "default value\n");
2264			vol = 100 | (100 << 8);
2265		}
2266
2267		if (pvol == -1) {
2268			device_printf(c->dev,
2269			    "Soft PCM Volume: Failed to read parent "
2270			    "default value\n");
2271			pvol = 100 | (100 << 8);
2272		}
2273
2274		left = ((vol & 0x7f) * (pvol & 0x7f)) / 100;
2275		right = (((vol >> 8) & 0x7f) * ((pvol >> 8) & 0x7f)) / 100;
2276		center = (left + right) >> 1;
2277
2278		chn_setvolume_multi(c, SND_VOL_C_MASTER, left, right, center);
2279	}
2280
2281	if (c->feederflags & (1 << FEEDER_EQ)) {
2282		struct pcm_feeder *f;
2283		int treble, bass, state;
2284
2285		/* CHN_UNLOCK(c); */
2286		treble = mix_get(m, SOUND_MIXER_TREBLE);
2287		bass = mix_get(m, SOUND_MIXER_BASS);
2288		/* CHN_LOCK(c); */
2289
2290		if (treble == -1)
2291			treble = 50;
2292		else
2293			treble = ((treble & 0x7f) +
2294			    ((treble >> 8) & 0x7f)) >> 1;
2295
2296		if (bass == -1)
2297			bass = 50;
2298		else
2299			bass = ((bass & 0x7f) + ((bass >> 8) & 0x7f)) >> 1;
2300
2301		f = chn_findfeeder(c, FEEDER_EQ);
2302		if (f != NULL) {
2303			if (FEEDER_SET(f, FEEDEQ_TREBLE, treble) != 0)
2304				device_printf(c->dev,
2305				    "EQ: Failed to set treble -- %d\n",
2306				    treble);
2307			if (FEEDER_SET(f, FEEDEQ_BASS, bass) != 0)
2308				device_printf(c->dev,
2309				    "EQ: Failed to set bass -- %d\n",
2310				    bass);
2311			if (FEEDER_SET(f, FEEDEQ_PREAMP, d->eqpreamp) != 0)
2312				device_printf(c->dev,
2313				    "EQ: Failed to set preamp -- %d\n",
2314				    d->eqpreamp);
2315			if (d->flags & SD_F_EQ_BYPASSED)
2316				state = FEEDEQ_BYPASS;
2317			else if (d->flags & SD_F_EQ_ENABLED)
2318				state = FEEDEQ_ENABLE;
2319			else
2320				state = FEEDEQ_DISABLE;
2321			if (FEEDER_SET(f, FEEDEQ_STATE, state) != 0)
2322				device_printf(c->dev,
2323				    "EQ: Failed to set state -- %d\n", state);
2324		}
2325	}
2326}
2327
2328int
2329chn_trigger(struct pcm_channel *c, int go)
2330{
2331	struct snddev_info *d = c->parentsnddev;
2332	int ret;
2333
2334	CHN_LOCKASSERT(c);
2335	if (!PCMTRIG_COMMON(go))
2336		return (CHANNEL_TRIGGER(c->methods, c->devinfo, go));
2337
2338	if (go == c->trigger)
2339		return (0);
2340
2341	ret = CHANNEL_TRIGGER(c->methods, c->devinfo, go);
2342	if (ret != 0)
2343		return (ret);
2344
2345	switch (go) {
2346	case PCMTRIG_START:
2347		if (snd_verbose > 3)
2348			device_printf(c->dev,
2349			    "%s() %s: calling go=0x%08x , "
2350			    "prev=0x%08x\n", __func__, c->name, go,
2351			    c->trigger);
2352		if (c->trigger != PCMTRIG_START) {
2353			c->trigger = go;
2354			CHN_UNLOCK(c);
2355			PCM_LOCK(d);
2356			CHN_INSERT_HEAD(d, c, channels.pcm.busy);
2357			PCM_UNLOCK(d);
2358			CHN_LOCK(c);
2359			chn_syncstate(c);
2360		}
2361		break;
2362	case PCMTRIG_STOP:
2363	case PCMTRIG_ABORT:
2364		if (snd_verbose > 3)
2365			device_printf(c->dev,
2366			    "%s() %s: calling go=0x%08x , "
2367			    "prev=0x%08x\n", __func__, c->name, go,
2368			    c->trigger);
2369		if (c->trigger == PCMTRIG_START) {
2370			c->trigger = go;
2371			CHN_UNLOCK(c);
2372			PCM_LOCK(d);
2373			CHN_REMOVE(d, c, channels.pcm.busy);
2374			PCM_UNLOCK(d);
2375			CHN_LOCK(c);
2376		}
2377		break;
2378	default:
2379		break;
2380	}
2381
2382	return (0);
2383}
2384
2385/**
2386 * @brief Queries sound driver for sample-aligned hardware buffer pointer index
2387 *
2388 * This function obtains the hardware pointer location, then aligns it to
2389 * the current bytes-per-sample value before returning.  (E.g., a channel
2390 * running in 16 bit stereo mode would require 4 bytes per sample, so a
2391 * hwptr value ranging from 32-35 would be returned as 32.)
2392 *
2393 * @param c	PCM channel context
2394 * @returns 	sample-aligned hardware buffer pointer index
2395 */
2396int
2397chn_getptr(struct pcm_channel *c)
2398{
2399	int hwptr;
2400
2401	CHN_LOCKASSERT(c);
2402	hwptr = (CHN_STARTED(c)) ? CHANNEL_GETPTR(c->methods, c->devinfo) : 0;
2403	return (hwptr - (hwptr % sndbuf_getalign(c->bufhard)));
2404}
2405
2406struct pcmchan_caps *
2407chn_getcaps(struct pcm_channel *c)
2408{
2409	CHN_LOCKASSERT(c);
2410	return CHANNEL_GETCAPS(c->methods, c->devinfo);
2411}
2412
2413u_int32_t
2414chn_getformats(struct pcm_channel *c)
2415{
2416	u_int32_t *fmtlist, fmts;
2417	int i;
2418
2419	fmtlist = chn_getcaps(c)->fmtlist;
2420	fmts = 0;
2421	for (i = 0; fmtlist[i]; i++)
2422		fmts |= fmtlist[i];
2423
2424	/* report software-supported formats */
2425	if (!CHN_BITPERFECT(c) && report_soft_formats)
2426		fmts |= AFMT_CONVERTIBLE;
2427
2428	return (AFMT_ENCODING(fmts));
2429}
2430
2431int
2432chn_notify(struct pcm_channel *c, u_int32_t flags)
2433{
2434	struct pcm_channel *ch;
2435	struct pcmchan_caps *caps;
2436	uint32_t bestformat, bestspeed, besthwformat, *vchanformat, *vchanrate;
2437	uint32_t vpflags;
2438	int dirty, err, run, nrun;
2439
2440	CHN_LOCKASSERT(c);
2441
2442	if (CHN_EMPTY(c, children))
2443		return (ENODEV);
2444
2445	err = 0;
2446
2447	/*
2448	 * If the hwchan is running, we can't change its rate, format or
2449	 * blocksize
2450	 */
2451	run = (CHN_STARTED(c)) ? 1 : 0;
2452	if (run)
2453		flags &= CHN_N_VOLUME | CHN_N_TRIGGER;
2454
2455	if (flags & CHN_N_RATE) {
2456		/*
2457		 * XXX I'll make good use of this someday.
2458		 *     However this is currently being superseded by
2459		 *     the availability of CHN_F_VCHAN_DYNAMIC.
2460		 */
2461	}
2462
2463	if (flags & CHN_N_FORMAT) {
2464		/*
2465		 * XXX I'll make good use of this someday.
2466		 *     However this is currently being superseded by
2467		 *     the availability of CHN_F_VCHAN_DYNAMIC.
2468		 */
2469	}
2470
2471	if (flags & CHN_N_VOLUME) {
2472		/*
2473		 * XXX I'll make good use of this someday, though
2474		 *     soft volume control is currently pretty much
2475		 *     integrated.
2476		 */
2477	}
2478
2479	if (flags & CHN_N_BLOCKSIZE) {
2480		/*
2481		 * Set to default latency profile
2482		 */
2483		chn_setlatency(c, chn_latency);
2484	}
2485
2486	if ((flags & CHN_N_TRIGGER) && !(c->flags & CHN_F_VCHAN_DYNAMIC)) {
2487		nrun = CHN_EMPTY(c, children.busy) ? 0 : 1;
2488		if (nrun && !run)
2489			err = chn_start(c, 1);
2490		if (!nrun && run)
2491			chn_abort(c);
2492		flags &= ~CHN_N_TRIGGER;
2493	}
2494
2495	if (flags & CHN_N_TRIGGER) {
2496		if (c->direction == PCMDIR_PLAY) {
2497			vchanformat = &c->parentsnddev->pvchanformat;
2498			vchanrate = &c->parentsnddev->pvchanrate;
2499		} else {
2500			vchanformat = &c->parentsnddev->rvchanformat;
2501			vchanrate = &c->parentsnddev->rvchanrate;
2502		}
2503
2504		/* Dynamic Virtual Channel */
2505		if (!(c->flags & CHN_F_VCHAN_ADAPTIVE)) {
2506			bestformat = *vchanformat;
2507			bestspeed = *vchanrate;
2508		} else {
2509			bestformat = 0;
2510			bestspeed = 0;
2511		}
2512
2513		besthwformat = 0;
2514		nrun = 0;
2515		caps = chn_getcaps(c);
2516		dirty = 0;
2517		vpflags = 0;
2518
2519		CHN_FOREACH(ch, c, children.busy) {
2520			CHN_LOCK(ch);
2521			if ((ch->format & AFMT_PASSTHROUGH) &&
2522			    snd_fmtvalid(ch->format, caps->fmtlist)) {
2523				bestformat = ch->format;
2524				bestspeed = ch->speed;
2525				CHN_UNLOCK(ch);
2526				vpflags = CHN_F_PASSTHROUGH;
2527				nrun++;
2528				break;
2529			}
2530			if ((ch->flags & CHN_F_EXCLUSIVE) && vpflags == 0) {
2531				if (c->flags & CHN_F_VCHAN_ADAPTIVE) {
2532					bestspeed = ch->speed;
2533					RANGE(bestspeed, caps->minspeed,
2534					    caps->maxspeed);
2535					besthwformat = snd_fmtbest(ch->format,
2536					    caps->fmtlist);
2537					if (besthwformat != 0)
2538						bestformat = besthwformat;
2539				}
2540				CHN_UNLOCK(ch);
2541				vpflags = CHN_F_EXCLUSIVE;
2542				nrun++;
2543				continue;
2544			}
2545			if (!(c->flags & CHN_F_VCHAN_ADAPTIVE) ||
2546			    vpflags != 0) {
2547				CHN_UNLOCK(ch);
2548				nrun++;
2549				continue;
2550			}
2551			if (ch->speed > bestspeed) {
2552				bestspeed = ch->speed;
2553				RANGE(bestspeed, caps->minspeed,
2554				    caps->maxspeed);
2555			}
2556			besthwformat = snd_fmtbest(ch->format, caps->fmtlist);
2557			if (!(besthwformat & AFMT_VCHAN)) {
2558				CHN_UNLOCK(ch);
2559				nrun++;
2560				continue;
2561			}
2562			if (AFMT_CHANNEL(besthwformat) >
2563			    AFMT_CHANNEL(bestformat))
2564				bestformat = besthwformat;
2565			else if (AFMT_CHANNEL(besthwformat) ==
2566			    AFMT_CHANNEL(bestformat) &&
2567			    AFMT_BIT(besthwformat) > AFMT_BIT(bestformat))
2568				bestformat = besthwformat;
2569			CHN_UNLOCK(ch);
2570			nrun++;
2571		}
2572
2573		if (bestformat == 0)
2574			bestformat = c->format;
2575		if (bestspeed == 0)
2576			bestspeed = c->speed;
2577
2578		if (bestformat != c->format || bestspeed != c->speed)
2579			dirty = 1;
2580
2581		c->flags &= ~(CHN_F_PASSTHROUGH | CHN_F_EXCLUSIVE);
2582		c->flags |= vpflags;
2583
2584		if (nrun && !run) {
2585			if (dirty) {
2586				bestspeed = CHANNEL_SETSPEED(c->methods,
2587				    c->devinfo, bestspeed);
2588				err = chn_reset(c, bestformat, bestspeed);
2589			}
2590			if (err == 0 && dirty) {
2591				CHN_FOREACH(ch, c, children.busy) {
2592					CHN_LOCK(ch);
2593					if (VCHAN_SYNC_REQUIRED(ch))
2594						vchan_sync(ch);
2595					CHN_UNLOCK(ch);
2596				}
2597			}
2598			if (err == 0) {
2599				if (dirty)
2600					c->flags |= CHN_F_DIRTY;
2601				err = chn_start(c, 1);
2602			}
2603		}
2604
2605		if (nrun && run && dirty) {
2606			chn_abort(c);
2607			bestspeed = CHANNEL_SETSPEED(c->methods, c->devinfo,
2608			    bestspeed);
2609			err = chn_reset(c, bestformat, bestspeed);
2610			if (err == 0) {
2611				CHN_FOREACH(ch, c, children.busy) {
2612					CHN_LOCK(ch);
2613					if (VCHAN_SYNC_REQUIRED(ch))
2614						vchan_sync(ch);
2615					CHN_UNLOCK(ch);
2616				}
2617			}
2618			if (err == 0) {
2619				c->flags |= CHN_F_DIRTY;
2620				err = chn_start(c, 1);
2621			}
2622		}
2623
2624		if (err == 0 && !(bestformat & AFMT_PASSTHROUGH) &&
2625		    (bestformat & AFMT_VCHAN)) {
2626			*vchanformat = bestformat;
2627			*vchanrate = bestspeed;
2628		}
2629
2630		if (!nrun && run) {
2631			c->flags &= ~(CHN_F_PASSTHROUGH | CHN_F_EXCLUSIVE);
2632			bestformat = *vchanformat;
2633			bestspeed = *vchanrate;
2634			chn_abort(c);
2635			if (c->format != bestformat || c->speed != bestspeed)
2636				chn_reset(c, bestformat, bestspeed);
2637		}
2638	}
2639
2640	return (err);
2641}
2642
2643/**
2644 * @brief Fetch array of supported discrete sample rates
2645 *
2646 * Wrapper for CHANNEL_GETRATES.  Please see channel_if.m:getrates() for
2647 * detailed information.
2648 *
2649 * @note If the operation isn't supported, this function will just return 0
2650 *       (no rates in the array), and *rates will be set to NULL.  Callers
2651 *       should examine rates @b only if this function returns non-zero.
2652 *
2653 * @param c	pcm channel to examine
2654 * @param rates	pointer to array of integers; rate table will be recorded here
2655 *
2656 * @return number of rates in the array pointed to be @c rates
2657 */
2658int
2659chn_getrates(struct pcm_channel *c, int **rates)
2660{
2661	KASSERT(rates != NULL, ("rates is null"));
2662	CHN_LOCKASSERT(c);
2663	return CHANNEL_GETRATES(c->methods, c->devinfo, rates);
2664}
2665
2666/**
2667 * @brief Remove channel from a sync group, if there is one.
2668 *
2669 * This function is initially intended for the following conditions:
2670 *   - Starting a syncgroup (@c SNDCTL_DSP_SYNCSTART ioctl)
2671 *   - Closing a device.  (A channel can't be destroyed if it's still in use.)
2672 *
2673 * @note Before calling this function, the syncgroup list mutex must be
2674 * held.  (Consider pcm_channel::sm protected by the SG list mutex
2675 * whether @c c is locked or not.)
2676 *
2677 * @param c	channel device to be started or closed
2678 * @returns	If this channel was the only member of a group, the group ID
2679 * 		is returned to the caller so that the caller can release it
2680 * 		via free_unr() after giving up the syncgroup lock.  Else it
2681 * 		returns 0.
2682 */
2683int
2684chn_syncdestroy(struct pcm_channel *c)
2685{
2686	struct pcmchan_syncmember *sm;
2687	struct pcmchan_syncgroup *sg;
2688	int sg_id;
2689
2690	sg_id = 0;
2691
2692	PCM_SG_LOCKASSERT(MA_OWNED);
2693
2694	if (c->sm != NULL) {
2695		sm = c->sm;
2696		sg = sm->parent;
2697		c->sm = NULL;
2698
2699		KASSERT(sg != NULL, ("syncmember has null parent"));
2700
2701		SLIST_REMOVE(&sg->members, sm, pcmchan_syncmember, link);
2702		free(sm, M_DEVBUF);
2703
2704		if (SLIST_EMPTY(&sg->members)) {
2705			SLIST_REMOVE(&snd_pcm_syncgroups, sg, pcmchan_syncgroup, link);
2706			sg_id = sg->id;
2707			free(sg, M_DEVBUF);
2708		}
2709	}
2710
2711	return sg_id;
2712}
2713
2714#ifdef OSSV4_EXPERIMENT
2715int
2716chn_getpeaks(struct pcm_channel *c, int *lpeak, int *rpeak)
2717{
2718	CHN_LOCKASSERT(c);
2719	return CHANNEL_GETPEAKS(c->methods, c->devinfo, lpeak, rpeak);
2720}
2721#endif
2722