xref: /freebsd/sys/dev/sound/pcm/sound.c (revision 5ca8e32633c4ffbbcd6762e5888b6a4ba0708c6c)
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  * Copyright (c) 1997 Luigi Rizzo
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/ac97.h>
38 #include <dev/sound/pcm/vchan.h>
39 #include <dev/sound/pcm/dsp.h>
40 #include <dev/sound/version.h>
41 #include <sys/limits.h>
42 #include <sys/sysctl.h>
43 
44 #include "feeder_if.h"
45 
46 devclass_t pcm_devclass;
47 
48 int pcm_veto_load = 1;
49 
50 int snd_unit = -1;
51 
52 static int snd_unit_auto = -1;
53 SYSCTL_INT(_hw_snd, OID_AUTO, default_auto, CTLFLAG_RWTUN,
54     &snd_unit_auto, 0, "assign default unit to a newly attached device");
55 
56 int snd_maxautovchans = 16;
57 
58 SYSCTL_NODE(_hw, OID_AUTO, snd, CTLFLAG_RD | CTLFLAG_MPSAFE, 0,
59     "Sound driver");
60 
61 static void pcm_sysinit(device_t);
62 
63 /*
64  * XXX I've had enough with people not telling proper version/arch
65  *     while reporting problems, not after 387397913213th questions/requests.
66  */
67 static char snd_driver_version[] =
68     __XSTRING(SND_DRV_VERSION)"/"MACHINE_ARCH;
69 SYSCTL_STRING(_hw_snd, OID_AUTO, version, CTLFLAG_RD, &snd_driver_version,
70     0, "driver version/arch");
71 
72 /**
73  * @brief Unit number allocator for syncgroup IDs
74  */
75 struct unrhdr *pcmsg_unrhdr = NULL;
76 
77 static int
78 sndstat_prepare_pcm(struct sbuf *s, device_t dev, int verbose)
79 {
80 	struct snddev_info *d;
81 	struct pcm_channel *c;
82 	struct pcm_feeder *f;
83 
84 	d = device_get_softc(dev);
85 	PCM_BUSYASSERT(d);
86 
87 	if (CHN_EMPTY(d, channels.pcm)) {
88 		sbuf_printf(s, " (mixer only)");
89 		return (0);
90 	}
91 
92 	if (verbose < 1) {
93 		sbuf_printf(s, " (%s%s%s",
94 		    d->playcount ? "play" : "",
95 		    (d->playcount && d->reccount) ? "/" : "",
96 		    d->reccount ? "rec" : "");
97 	} else {
98 		sbuf_printf(s, " (%dp:%dv/%dr:%dv",
99 		    d->playcount, d->pvchancount,
100 		    d->reccount, d->rvchancount);
101 	}
102 	sbuf_printf(s, "%s)%s",
103 	    ((d->playcount != 0 && d->reccount != 0) &&
104 	    (d->flags & SD_F_SIMPLEX)) ? " simplex" : "",
105 	    (device_get_unit(dev) == snd_unit) ? " default" : "");
106 
107 	if (verbose <= 1)
108 		return (0);
109 
110 	sbuf_printf(s, "\n\t");
111 	sbuf_printf(s, "snddev flags=0x%b", d->flags, SD_F_BITS);
112 
113 	CHN_FOREACH(c, d, channels.pcm) {
114 		KASSERT(c->bufhard != NULL && c->bufsoft != NULL,
115 		    ("hosed pcm channel setup"));
116 
117 		sbuf_printf(s, "\n\t");
118 
119 		sbuf_printf(s, "%s[%s]: ",
120 		    (c->parentchannel != NULL) ?
121 		    c->parentchannel->name : "", c->name);
122 		sbuf_printf(s, "spd %d", c->speed);
123 		if (c->speed != sndbuf_getspd(c->bufhard)) {
124 			sbuf_printf(s, "/%d",
125 			    sndbuf_getspd(c->bufhard));
126 		}
127 		sbuf_printf(s, ", fmt 0x%08x", c->format);
128 		if (c->format != sndbuf_getfmt(c->bufhard)) {
129 			sbuf_printf(s, "/0x%08x",
130 			    sndbuf_getfmt(c->bufhard));
131 		}
132 		sbuf_printf(s, ", flags 0x%08x, 0x%08x",
133 		    c->flags, c->feederflags);
134 		if (c->pid != -1) {
135 			sbuf_printf(s, ", pid %d (%s)",
136 			    c->pid, c->comm);
137 		}
138 		sbuf_printf(s, "\n\t");
139 
140 		sbuf_printf(s, "interrupts %d, ", c->interrupts);
141 
142 		if (c->direction == PCMDIR_REC)	{
143 			sbuf_printf(s,
144 			    "overruns %d, feed %u, hfree %d, "
145 			    "sfree %d [b:%d/%d/%d|bs:%d/%d/%d]",
146 				c->xruns, c->feedcount,
147 				sndbuf_getfree(c->bufhard),
148 				sndbuf_getfree(c->bufsoft),
149 				sndbuf_getsize(c->bufhard),
150 				sndbuf_getblksz(c->bufhard),
151 				sndbuf_getblkcnt(c->bufhard),
152 				sndbuf_getsize(c->bufsoft),
153 				sndbuf_getblksz(c->bufsoft),
154 				sndbuf_getblkcnt(c->bufsoft));
155 		} else {
156 			sbuf_printf(s,
157 			    "underruns %d, feed %u, ready %d "
158 			    "[b:%d/%d/%d|bs:%d/%d/%d]",
159 				c->xruns, c->feedcount,
160 				sndbuf_getready(c->bufsoft),
161 				sndbuf_getsize(c->bufhard),
162 				sndbuf_getblksz(c->bufhard),
163 				sndbuf_getblkcnt(c->bufhard),
164 				sndbuf_getsize(c->bufsoft),
165 				sndbuf_getblksz(c->bufsoft),
166 				sndbuf_getblkcnt(c->bufsoft));
167 		}
168 		sbuf_printf(s, "\n\t");
169 
170 		sbuf_printf(s, "channel flags=0x%b", c->flags, CHN_F_BITS);
171 		sbuf_printf(s, "\n\t");
172 
173 		sbuf_printf(s, "{%s}",
174 		    (c->direction == PCMDIR_REC) ? "hardware" : "userland");
175 		sbuf_printf(s, " -> ");
176 		f = c->feeder;
177 		while (f->source != NULL)
178 			f = f->source;
179 		while (f != NULL) {
180 			sbuf_printf(s, "%s", f->class->name);
181 			if (f->desc->type == FEEDER_FORMAT) {
182 				sbuf_printf(s, "(0x%08x -> 0x%08x)",
183 				    f->desc->in, f->desc->out);
184 			} else if (f->desc->type == FEEDER_MATRIX) {
185 				sbuf_printf(s, "(%d.%d -> %d.%d)",
186 				    AFMT_CHANNEL(f->desc->in) -
187 				    AFMT_EXTCHANNEL(f->desc->in),
188 				    AFMT_EXTCHANNEL(f->desc->in),
189 				    AFMT_CHANNEL(f->desc->out) -
190 				    AFMT_EXTCHANNEL(f->desc->out),
191 				    AFMT_EXTCHANNEL(f->desc->out));
192 			} else if (f->desc->type == FEEDER_RATE) {
193 				sbuf_printf(s,
194 				    "(0x%08x q:%d %d -> %d)",
195 				    f->desc->out,
196 				    FEEDER_GET(f, FEEDRATE_QUALITY),
197 				    FEEDER_GET(f, FEEDRATE_SRC),
198 				    FEEDER_GET(f, FEEDRATE_DST));
199 			} else {
200 				sbuf_printf(s, "(0x%08x)",
201 				    f->desc->out);
202 			}
203 			sbuf_printf(s, " -> ");
204 			f = f->parent;
205 		}
206 		sbuf_printf(s, "{%s}",
207 		    (c->direction == PCMDIR_REC) ? "userland" : "hardware");
208 	}
209 
210 	return (0);
211 }
212 
213 void *
214 snd_mtxcreate(const char *desc, const char *type)
215 {
216 	struct mtx *m;
217 
218 	m = malloc(sizeof(*m), M_DEVBUF, M_WAITOK | M_ZERO);
219 	mtx_init(m, desc, type, MTX_DEF);
220 	return m;
221 }
222 
223 void
224 snd_mtxfree(void *m)
225 {
226 	struct mtx *mtx = m;
227 
228 	mtx_destroy(mtx);
229 	free(mtx, M_DEVBUF);
230 }
231 
232 void
233 snd_mtxassert(void *m)
234 {
235 #ifdef INVARIANTS
236 	struct mtx *mtx = m;
237 
238 	mtx_assert(mtx, MA_OWNED);
239 #endif
240 }
241 
242 int
243 snd_setup_intr(device_t dev, struct resource *res, int flags, driver_intr_t hand, void *param, void **cookiep)
244 {
245 	struct snddev_info *d;
246 
247 	flags &= INTR_MPSAFE;
248 	flags |= INTR_TYPE_AV;
249 	d = device_get_softc(dev);
250 	if (d != NULL && (flags & INTR_MPSAFE))
251 		d->flags |= SD_F_MPSAFE;
252 
253 	return bus_setup_intr(dev, res, flags, NULL, hand, param, cookiep);
254 }
255 
256 static void
257 pcm_clonereset(struct snddev_info *d)
258 {
259 	int cmax;
260 
261 	PCM_BUSYASSERT(d);
262 
263 	cmax = d->playcount + d->reccount - 1;
264 	if (d->pvchancount > 0)
265 		cmax += max(d->pvchancount, snd_maxautovchans) - 1;
266 	if (d->rvchancount > 0)
267 		cmax += max(d->rvchancount, snd_maxautovchans) - 1;
268 	if (cmax > PCMMAXCLONE)
269 		cmax = PCMMAXCLONE;
270 	(void)snd_clone_gc(d->clones);
271 	(void)snd_clone_setmaxunit(d->clones, cmax);
272 }
273 
274 int
275 pcm_setvchans(struct snddev_info *d, int direction, int newcnt, int num)
276 {
277 	struct pcm_channel *c, *ch, *nch;
278 	struct pcmchan_caps *caps;
279 	int i, err, vcnt;
280 
281 	PCM_BUSYASSERT(d);
282 
283 	if ((direction == PCMDIR_PLAY && d->playcount < 1) ||
284 	    (direction == PCMDIR_REC && d->reccount < 1))
285 		return (ENODEV);
286 
287 	if (!(d->flags & SD_F_AUTOVCHAN))
288 		return (EINVAL);
289 
290 	if (newcnt < 0 || newcnt > SND_MAXVCHANS)
291 		return (E2BIG);
292 
293 	if (direction == PCMDIR_PLAY)
294 		vcnt = d->pvchancount;
295 	else if (direction == PCMDIR_REC)
296 		vcnt = d->rvchancount;
297 	else
298 		return (EINVAL);
299 
300 	if (newcnt > vcnt) {
301 		KASSERT(num == -1 ||
302 		    (num >= 0 && num < SND_MAXVCHANS && (newcnt - 1) == vcnt),
303 		    ("bogus vchan_create() request num=%d newcnt=%d vcnt=%d",
304 		    num, newcnt, vcnt));
305 		/* add new vchans - find a parent channel first */
306 		ch = NULL;
307 		CHN_FOREACH(c, d, channels.pcm) {
308 			CHN_LOCK(c);
309 			if (c->direction == direction &&
310 			    ((c->flags & CHN_F_HAS_VCHAN) || (vcnt == 0 &&
311 			    c->refcount < 1 &&
312 			    !(c->flags & (CHN_F_BUSY | CHN_F_VIRTUAL))))) {
313 				/*
314 				 * Reuse hw channel with vchans already
315 				 * created.
316 				 */
317 				if (c->flags & CHN_F_HAS_VCHAN) {
318 					ch = c;
319 					break;
320 				}
321 				/*
322 				 * No vchans ever created, look for
323 				 * channels with supported formats.
324 				 */
325 				caps = chn_getcaps(c);
326 				if (caps == NULL) {
327 					CHN_UNLOCK(c);
328 					continue;
329 				}
330 				for (i = 0; caps->fmtlist[i] != 0; i++) {
331 					if (caps->fmtlist[i] & AFMT_CONVERTIBLE)
332 						break;
333 				}
334 				if (caps->fmtlist[i] != 0) {
335 					ch = c;
336 				    	break;
337 				}
338 			}
339 			CHN_UNLOCK(c);
340 		}
341 		if (ch == NULL)
342 			return (EBUSY);
343 		ch->flags |= CHN_F_BUSY;
344 		err = 0;
345 		while (err == 0 && newcnt > vcnt) {
346 			err = vchan_create(ch, num);
347 			if (err == 0)
348 				vcnt++;
349 			else if (err == E2BIG && newcnt > vcnt)
350 				device_printf(d->dev,
351 				    "%s: err=%d Maximum channel reached.\n",
352 				    __func__, err);
353 		}
354 		if (vcnt == 0)
355 			ch->flags &= ~CHN_F_BUSY;
356 		CHN_UNLOCK(ch);
357 		if (err != 0)
358 			return (err);
359 		else
360 			pcm_clonereset(d);
361 	} else if (newcnt < vcnt) {
362 		KASSERT(num == -1,
363 		    ("bogus vchan_destroy() request num=%d", num));
364 		CHN_FOREACH(c, d, channels.pcm) {
365 			CHN_LOCK(c);
366 			if (c->direction != direction ||
367 			    CHN_EMPTY(c, children) ||
368 			    !(c->flags & CHN_F_HAS_VCHAN)) {
369 				CHN_UNLOCK(c);
370 				continue;
371 			}
372 			CHN_FOREACH_SAFE(ch, c, nch, children) {
373 				CHN_LOCK(ch);
374 				if (vcnt == 1 && c->refcount > 0) {
375 					CHN_UNLOCK(ch);
376 					break;
377 				}
378 				if (!(ch->flags & CHN_F_BUSY) &&
379 				    ch->refcount < 1) {
380 					err = vchan_destroy(ch);
381 					if (err == 0)
382 						vcnt--;
383 				} else
384 					CHN_UNLOCK(ch);
385 				if (vcnt == newcnt)
386 					break;
387 			}
388 			CHN_UNLOCK(c);
389 			break;
390 		}
391 		pcm_clonereset(d);
392 	}
393 
394 	return (0);
395 }
396 
397 /* return error status and a locked channel */
398 int
399 pcm_chnalloc(struct snddev_info *d, struct pcm_channel **ch, int direction,
400     pid_t pid, char *comm, int devunit)
401 {
402 	struct pcm_channel *c;
403 	int err, vchancount, vchan_num;
404 
405 	KASSERT(d != NULL && ch != NULL && (devunit == -1 ||
406 	    !(devunit & ~(SND_U_MASK | SND_D_MASK | SND_C_MASK))) &&
407 	    (direction == PCMDIR_PLAY || direction == PCMDIR_REC),
408 	    ("%s(): invalid d=%p ch=%p direction=%d pid=%d devunit=%d",
409 	    __func__, d, ch, direction, pid, devunit));
410 	PCM_BUSYASSERT(d);
411 
412 	/* Double check again. */
413 	if (devunit != -1) {
414 		switch (snd_unit2d(devunit)) {
415 		case SND_DEV_DSPHW_PLAY:
416 		case SND_DEV_DSPHW_VPLAY:
417 			if (direction != PCMDIR_PLAY)
418 				return (ENOTSUP);
419 			break;
420 		case SND_DEV_DSPHW_REC:
421 		case SND_DEV_DSPHW_VREC:
422 			if (direction != PCMDIR_REC)
423 				return (ENOTSUP);
424 			break;
425 		default:
426 			if (!(direction == PCMDIR_PLAY ||
427 			    direction == PCMDIR_REC))
428 				return (ENOTSUP);
429 			break;
430 		}
431 	}
432 
433 	*ch = NULL;
434 	vchan_num = 0;
435 	vchancount = (direction == PCMDIR_PLAY) ? d->pvchancount :
436 	    d->rvchancount;
437 
438 retry_chnalloc:
439 	err = ENOTSUP;
440 	/* scan for a free channel */
441 	CHN_FOREACH(c, d, channels.pcm) {
442 		CHN_LOCK(c);
443 		if (devunit == -1 && c->direction == direction &&
444 		    (c->flags & CHN_F_VIRTUAL)) {
445 			if (vchancount < snd_maxautovchans &&
446 			    vchan_num < CHN_CHAN(c)) {
447 			    	CHN_UNLOCK(c);
448 				goto vchan_alloc;
449 			}
450 			vchan_num++;
451 		}
452 		if (c->direction == direction && !(c->flags & CHN_F_BUSY) &&
453 		    (devunit == -1 || devunit == -2 || c->unit == devunit)) {
454 			c->flags |= CHN_F_BUSY;
455 			c->pid = pid;
456 			strlcpy(c->comm, (comm != NULL) ? comm :
457 			    CHN_COMM_UNKNOWN, sizeof(c->comm));
458 			*ch = c;
459 			return (0);
460 		} else if (c->unit == devunit) {
461 			if (c->direction != direction)
462 				err = ENOTSUP;
463 			else if (c->flags & CHN_F_BUSY)
464 				err = EBUSY;
465 			else
466 				err = EINVAL;
467 			CHN_UNLOCK(c);
468 			return (err);
469 		} else if ((devunit == -1 || devunit == -2) &&
470 		    c->direction == direction && (c->flags & CHN_F_BUSY))
471 			err = EBUSY;
472 		CHN_UNLOCK(c);
473 	}
474 
475 	if (devunit == -2)
476 		return (err);
477 
478 vchan_alloc:
479 	/* no channel available */
480 	if (devunit == -1 || snd_unit2d(devunit) == SND_DEV_DSPHW_VPLAY ||
481 	    snd_unit2d(devunit) == SND_DEV_DSPHW_VREC) {
482 		if (!(vchancount > 0 && vchancount < snd_maxautovchans) &&
483 		    (devunit == -1 || snd_unit2c(devunit) < snd_maxautovchans))
484 			return (err);
485 		err = pcm_setvchans(d, direction, vchancount + 1,
486 		    (devunit == -1) ? -1 : snd_unit2c(devunit));
487 		if (err == 0) {
488 			if (devunit == -1)
489 				devunit = -2;
490 			goto retry_chnalloc;
491 		}
492 	}
493 
494 	return (err);
495 }
496 
497 /* release a locked channel and unlock it */
498 int
499 pcm_chnrelease(struct pcm_channel *c)
500 {
501 	PCM_BUSYASSERT(c->parentsnddev);
502 	CHN_LOCKASSERT(c);
503 
504 	c->flags &= ~CHN_F_BUSY;
505 	c->pid = -1;
506 	strlcpy(c->comm, CHN_COMM_UNUSED, sizeof(c->comm));
507 	CHN_UNLOCK(c);
508 
509 	return (0);
510 }
511 
512 int
513 pcm_chnref(struct pcm_channel *c, int ref)
514 {
515 	PCM_BUSYASSERT(c->parentsnddev);
516 	CHN_LOCKASSERT(c);
517 
518 	c->refcount += ref;
519 
520 	return (c->refcount);
521 }
522 
523 static void
524 pcm_setmaxautovchans(struct snddev_info *d, int num)
525 {
526 	PCM_BUSYASSERT(d);
527 
528 	if (num < 0)
529 		return;
530 
531 	if (num >= 0 && d->pvchancount > num)
532 		(void)pcm_setvchans(d, PCMDIR_PLAY, num, -1);
533 	else if (num > 0 && d->pvchancount == 0)
534 		(void)pcm_setvchans(d, PCMDIR_PLAY, 1, -1);
535 
536 	if (num >= 0 && d->rvchancount > num)
537 		(void)pcm_setvchans(d, PCMDIR_REC, num, -1);
538 	else if (num > 0 && d->rvchancount == 0)
539 		(void)pcm_setvchans(d, PCMDIR_REC, 1, -1);
540 
541 	pcm_clonereset(d);
542 }
543 
544 static int
545 sysctl_hw_snd_default_unit(SYSCTL_HANDLER_ARGS)
546 {
547 	struct snddev_info *d;
548 	int error, unit;
549 
550 	unit = snd_unit;
551 	error = sysctl_handle_int(oidp, &unit, 0, req);
552 	if (error == 0 && req->newptr != NULL) {
553 		d = devclass_get_softc(pcm_devclass, unit);
554 		if (!PCM_REGISTERED(d) || CHN_EMPTY(d, channels.pcm))
555 			return EINVAL;
556 		snd_unit = unit;
557 		snd_unit_auto = 0;
558 	}
559 	return (error);
560 }
561 /* XXX: do we need a way to let the user change the default unit? */
562 SYSCTL_PROC(_hw_snd, OID_AUTO, default_unit,
563     CTLTYPE_INT | CTLFLAG_RWTUN | CTLFLAG_ANYBODY | CTLFLAG_NEEDGIANT, 0,
564     sizeof(int), sysctl_hw_snd_default_unit, "I",
565     "default sound device");
566 
567 static int
568 sysctl_hw_snd_maxautovchans(SYSCTL_HANDLER_ARGS)
569 {
570 	struct snddev_info *d;
571 	int i, v, error;
572 
573 	v = snd_maxautovchans;
574 	error = sysctl_handle_int(oidp, &v, 0, req);
575 	if (error == 0 && req->newptr != NULL) {
576 		if (v < 0)
577 			v = 0;
578 		if (v > SND_MAXVCHANS)
579 			v = SND_MAXVCHANS;
580 		snd_maxautovchans = v;
581 		for (i = 0; pcm_devclass != NULL &&
582 		    i < devclass_get_maxunit(pcm_devclass); i++) {
583 			d = devclass_get_softc(pcm_devclass, i);
584 			if (!PCM_REGISTERED(d))
585 				continue;
586 			PCM_ACQUIRE_QUICK(d);
587 			pcm_setmaxautovchans(d, v);
588 			PCM_RELEASE_QUICK(d);
589 		}
590 	}
591 	return (error);
592 }
593 SYSCTL_PROC(_hw_snd, OID_AUTO, maxautovchans,
594     CTLTYPE_INT | CTLFLAG_RWTUN | CTLFLAG_NEEDGIANT, 0, sizeof(int),
595     sysctl_hw_snd_maxautovchans, "I",
596     "maximum virtual channel");
597 
598 struct pcm_channel *
599 pcm_chn_create(struct snddev_info *d, struct pcm_channel *parent, kobj_class_t cls, int dir, int num, void *devinfo)
600 {
601 	struct pcm_channel *ch;
602 	int direction, err, rpnum, *pnum, max;
603 	int udc, device, chan;
604 	char *dirs, *devname, buf[CHN_NAMELEN];
605 
606 	PCM_BUSYASSERT(d);
607 	PCM_LOCKASSERT(d);
608 	KASSERT(num >= -1, ("invalid num=%d", num));
609 
610 	switch (dir) {
611 	case PCMDIR_PLAY:
612 		dirs = "play";
613 		direction = PCMDIR_PLAY;
614 		pnum = &d->playcount;
615 		device = SND_DEV_DSPHW_PLAY;
616 		max = SND_MAXHWCHAN;
617 		break;
618 	case PCMDIR_PLAY_VIRTUAL:
619 		dirs = "virtual";
620 		direction = PCMDIR_PLAY;
621 		pnum = &d->pvchancount;
622 		device = SND_DEV_DSPHW_VPLAY;
623 		max = SND_MAXVCHANS;
624 		break;
625 	case PCMDIR_REC:
626 		dirs = "record";
627 		direction = PCMDIR_REC;
628 		pnum = &d->reccount;
629 		device = SND_DEV_DSPHW_REC;
630 		max = SND_MAXHWCHAN;
631 		break;
632 	case PCMDIR_REC_VIRTUAL:
633 		dirs = "virtual";
634 		direction = PCMDIR_REC;
635 		pnum = &d->rvchancount;
636 		device = SND_DEV_DSPHW_VREC;
637 		max = SND_MAXVCHANS;
638 		break;
639 	default:
640 		return (NULL);
641 	}
642 
643 	chan = (num == -1) ? 0 : num;
644 
645 	if (*pnum >= max || chan >= max)
646 		return (NULL);
647 
648 	rpnum = 0;
649 
650 	CHN_FOREACH(ch, d, channels.pcm) {
651 		if (CHN_DEV(ch) != device)
652 			continue;
653 		if (chan == CHN_CHAN(ch)) {
654 			if (num != -1) {
655 				device_printf(d->dev,
656 				    "channel num=%d allocated!\n", chan);
657 				return (NULL);
658 			}
659 			chan++;
660 			if (chan >= max) {
661 				device_printf(d->dev,
662 				    "chan=%d > %d\n", chan, max);
663 				return (NULL);
664 			}
665 		}
666 		rpnum++;
667 	}
668 
669 	if (*pnum != rpnum) {
670 		device_printf(d->dev,
671 		    "%s(): WARNING: pnum screwed : dirs=%s pnum=%d rpnum=%d\n",
672 		    __func__, dirs, *pnum, rpnum);
673 		return (NULL);
674 	}
675 
676 	udc = snd_mkunit(device_get_unit(d->dev), device, chan);
677 	devname = dsp_unit2name(buf, sizeof(buf), udc);
678 
679 	if (devname == NULL) {
680 		device_printf(d->dev,
681 		    "Failed to query device name udc=0x%08x\n", udc);
682 		return (NULL);
683 	}
684 
685 	PCM_UNLOCK(d);
686 	ch = malloc(sizeof(*ch), M_DEVBUF, M_WAITOK | M_ZERO);
687 	ch->methods = kobj_create(cls, M_DEVBUF, M_WAITOK | M_ZERO);
688 	ch->unit = udc;
689 	ch->pid = -1;
690 	strlcpy(ch->comm, CHN_COMM_UNUSED, sizeof(ch->comm));
691 	ch->parentsnddev = d;
692 	ch->parentchannel = parent;
693 	ch->dev = d->dev;
694 	ch->trigger = PCMTRIG_STOP;
695 	snprintf(ch->name, sizeof(ch->name), "%s:%s:%s",
696 	    device_get_nameunit(ch->dev), dirs, devname);
697 
698 	err = chn_init(ch, devinfo, dir, direction);
699 	PCM_LOCK(d);
700 	if (err) {
701 		device_printf(d->dev, "chn_init(%s) failed: err = %d\n",
702 		    ch->name, err);
703 		kobj_delete(ch->methods, M_DEVBUF);
704 		free(ch, M_DEVBUF);
705 		return (NULL);
706 	}
707 
708 	return (ch);
709 }
710 
711 int
712 pcm_chn_destroy(struct pcm_channel *ch)
713 {
714 	struct snddev_info *d __diagused;
715 	int err;
716 
717 	d = ch->parentsnddev;
718 	PCM_BUSYASSERT(d);
719 
720 	err = chn_kill(ch);
721 	if (err) {
722 		device_printf(ch->dev, "chn_kill(%s) failed, err = %d\n",
723 		    ch->name, err);
724 		return (err);
725 	}
726 
727 	kobj_delete(ch->methods, M_DEVBUF);
728 	free(ch, M_DEVBUF);
729 
730 	return (0);
731 }
732 
733 int
734 pcm_chn_add(struct snddev_info *d, struct pcm_channel *ch)
735 {
736 	PCM_BUSYASSERT(d);
737 	PCM_LOCKASSERT(d);
738 	KASSERT(ch != NULL && (ch->direction == PCMDIR_PLAY ||
739 	    ch->direction == PCMDIR_REC), ("Invalid pcm channel"));
740 
741 	CHN_INSERT_SORT_ASCEND(d, ch, channels.pcm);
742 
743 	switch (CHN_DEV(ch)) {
744 	case SND_DEV_DSPHW_PLAY:
745 		d->playcount++;
746 		break;
747 	case SND_DEV_DSPHW_VPLAY:
748 		d->pvchancount++;
749 		break;
750 	case SND_DEV_DSPHW_REC:
751 		d->reccount++;
752 		break;
753 	case SND_DEV_DSPHW_VREC:
754 		d->rvchancount++;
755 		break;
756 	default:
757 		break;
758 	}
759 
760 	d->devcount++;
761 
762 	return (0);
763 }
764 
765 int
766 pcm_chn_remove(struct snddev_info *d, struct pcm_channel *ch)
767 {
768 	struct pcm_channel *tmp;
769 
770 	PCM_BUSYASSERT(d);
771 	PCM_LOCKASSERT(d);
772 
773 	tmp = NULL;
774 
775 	CHN_FOREACH(tmp, d, channels.pcm) {
776 		if (tmp == ch)
777 			break;
778 	}
779 
780 	if (tmp != ch)
781 		return (EINVAL);
782 
783 	CHN_REMOVE(d, ch, channels.pcm);
784 
785 	switch (CHN_DEV(ch)) {
786 	case SND_DEV_DSPHW_PLAY:
787 		d->playcount--;
788 		break;
789 	case SND_DEV_DSPHW_VPLAY:
790 		d->pvchancount--;
791 		break;
792 	case SND_DEV_DSPHW_REC:
793 		d->reccount--;
794 		break;
795 	case SND_DEV_DSPHW_VREC:
796 		d->rvchancount--;
797 		break;
798 	default:
799 		break;
800 	}
801 
802 	d->devcount--;
803 
804 	return (0);
805 }
806 
807 int
808 pcm_addchan(device_t dev, int dir, kobj_class_t cls, void *devinfo)
809 {
810 	struct snddev_info *d = device_get_softc(dev);
811 	struct pcm_channel *ch;
812 	int err;
813 
814 	PCM_BUSYASSERT(d);
815 
816 	PCM_LOCK(d);
817 	ch = pcm_chn_create(d, NULL, cls, dir, -1, devinfo);
818 	if (!ch) {
819 		device_printf(d->dev, "pcm_chn_create(%s, %d, %p) failed\n",
820 		    cls->name, dir, devinfo);
821 		PCM_UNLOCK(d);
822 		return (ENODEV);
823 	}
824 
825 	err = pcm_chn_add(d, ch);
826 	PCM_UNLOCK(d);
827 	if (err) {
828 		device_printf(d->dev, "pcm_chn_add(%s) failed, err=%d\n",
829 		    ch->name, err);
830 		pcm_chn_destroy(ch);
831 	}
832 
833 	return (err);
834 }
835 
836 static int
837 pcm_killchan(device_t dev)
838 {
839 	struct snddev_info *d = device_get_softc(dev);
840 	struct pcm_channel *ch;
841 	int error;
842 
843 	PCM_BUSYASSERT(d);
844 
845 	ch = CHN_FIRST(d, channels.pcm);
846 
847 	PCM_LOCK(d);
848 	error = pcm_chn_remove(d, ch);
849 	PCM_UNLOCK(d);
850 	if (error)
851 		return (error);
852 	return (pcm_chn_destroy(ch));
853 }
854 
855 static int
856 pcm_best_unit(int old)
857 {
858 	struct snddev_info *d;
859 	int i, best, bestprio, prio;
860 
861 	best = -1;
862 	bestprio = -100;
863 	for (i = 0; pcm_devclass != NULL &&
864 	    i < devclass_get_maxunit(pcm_devclass); i++) {
865 		d = devclass_get_softc(pcm_devclass, i);
866 		if (!PCM_REGISTERED(d))
867 			continue;
868 		prio = 0;
869 		if (d->playcount == 0)
870 			prio -= 10;
871 		if (d->reccount == 0)
872 			prio -= 2;
873 		if (prio > bestprio || (prio == bestprio && i == old)) {
874 			best = i;
875 			bestprio = prio;
876 		}
877 	}
878 	return (best);
879 }
880 
881 int
882 pcm_setstatus(device_t dev, char *str)
883 {
884 	struct snddev_info *d = device_get_softc(dev);
885 
886 	/* should only be called once */
887 	if (d->flags & SD_F_REGISTERED)
888 		return (EINVAL);
889 
890 	PCM_BUSYASSERT(d);
891 
892 	if (d->playcount == 0 || d->reccount == 0)
893 		d->flags |= SD_F_SIMPLEX;
894 
895 	if (d->playcount > 0 || d->reccount > 0)
896 		d->flags |= SD_F_AUTOVCHAN;
897 
898 	pcm_setmaxautovchans(d, snd_maxautovchans);
899 
900 	strlcpy(d->status, str, SND_STATUSLEN);
901 
902 	PCM_LOCK(d);
903 
904 	/* Last stage, enable cloning. */
905 	if (d->clones != NULL)
906 		(void)snd_clone_enable(d->clones);
907 
908 	/* Done, we're ready.. */
909 	d->flags |= SD_F_REGISTERED;
910 
911 	PCM_RELEASE(d);
912 
913 	PCM_UNLOCK(d);
914 
915 	/*
916 	 * Create all sysctls once SD_F_REGISTERED is set else
917 	 * tunable sysctls won't work:
918 	 */
919 	pcm_sysinit(dev);
920 
921 	if (snd_unit_auto < 0)
922 		snd_unit_auto = (snd_unit < 0) ? 1 : 0;
923 	if (snd_unit < 0 || snd_unit_auto > 1)
924 		snd_unit = device_get_unit(dev);
925 	else if (snd_unit_auto == 1)
926 		snd_unit = pcm_best_unit(snd_unit);
927 
928 	return (0);
929 }
930 
931 uint32_t
932 pcm_getflags(device_t dev)
933 {
934 	struct snddev_info *d = device_get_softc(dev);
935 
936 	return d->flags;
937 }
938 
939 void
940 pcm_setflags(device_t dev, uint32_t val)
941 {
942 	struct snddev_info *d = device_get_softc(dev);
943 
944 	d->flags = val;
945 }
946 
947 void *
948 pcm_getdevinfo(device_t dev)
949 {
950 	struct snddev_info *d = device_get_softc(dev);
951 
952 	return d->devinfo;
953 }
954 
955 unsigned int
956 pcm_getbuffersize(device_t dev, unsigned int minbufsz, unsigned int deflt, unsigned int maxbufsz)
957 {
958 	struct snddev_info *d = device_get_softc(dev);
959 	int sz, x;
960 
961 	sz = 0;
962 	if (resource_int_value(device_get_name(dev), device_get_unit(dev), "buffersize", &sz) == 0) {
963 		x = sz;
964 		RANGE(sz, minbufsz, maxbufsz);
965 		if (x != sz)
966 			device_printf(dev, "'buffersize=%d' hint is out of range (%d-%d), using %d\n", x, minbufsz, maxbufsz, sz);
967 		x = minbufsz;
968 		while (x < sz)
969 			x <<= 1;
970 		if (x > sz)
971 			x >>= 1;
972 		if (x != sz) {
973 			device_printf(dev, "'buffersize=%d' hint is not a power of 2, using %d\n", sz, x);
974 			sz = x;
975 		}
976 	} else {
977 		sz = deflt;
978 	}
979 
980 	d->bufsz = sz;
981 
982 	return sz;
983 }
984 
985 static int
986 sysctl_dev_pcm_bitperfect(SYSCTL_HANDLER_ARGS)
987 {
988 	struct snddev_info *d;
989 	int err, val;
990 
991 	d = oidp->oid_arg1;
992 	if (!PCM_REGISTERED(d))
993 		return (ENODEV);
994 
995 	PCM_LOCK(d);
996 	PCM_WAIT(d);
997 	val = (d->flags & SD_F_BITPERFECT) ? 1 : 0;
998 	PCM_ACQUIRE(d);
999 	PCM_UNLOCK(d);
1000 
1001 	err = sysctl_handle_int(oidp, &val, 0, req);
1002 
1003 	if (err == 0 && req->newptr != NULL) {
1004 		if (!(val == 0 || val == 1)) {
1005 			PCM_RELEASE_QUICK(d);
1006 			return (EINVAL);
1007 		}
1008 
1009 		PCM_LOCK(d);
1010 
1011 		d->flags &= ~SD_F_BITPERFECT;
1012 		d->flags |= (val != 0) ? SD_F_BITPERFECT : 0;
1013 
1014 		PCM_RELEASE(d);
1015 		PCM_UNLOCK(d);
1016 	} else
1017 		PCM_RELEASE_QUICK(d);
1018 
1019 	return (err);
1020 }
1021 
1022 #ifdef SND_DEBUG
1023 static int
1024 sysctl_dev_pcm_clone_flags(SYSCTL_HANDLER_ARGS)
1025 {
1026 	struct snddev_info *d;
1027 	uint32_t flags;
1028 	int err;
1029 
1030 	d = oidp->oid_arg1;
1031 	if (!PCM_REGISTERED(d) || d->clones == NULL)
1032 		return (ENODEV);
1033 
1034 	PCM_ACQUIRE_QUICK(d);
1035 
1036 	flags = snd_clone_getflags(d->clones);
1037 	err = sysctl_handle_int(oidp, &flags, 0, req);
1038 
1039 	if (err == 0 && req->newptr != NULL) {
1040 		if (flags & ~SND_CLONE_MASK)
1041 			err = EINVAL;
1042 		else
1043 			(void)snd_clone_setflags(d->clones, flags);
1044 	}
1045 
1046 	PCM_RELEASE_QUICK(d);
1047 
1048 	return (err);
1049 }
1050 
1051 static int
1052 sysctl_dev_pcm_clone_deadline(SYSCTL_HANDLER_ARGS)
1053 {
1054 	struct snddev_info *d;
1055 	int err, deadline;
1056 
1057 	d = oidp->oid_arg1;
1058 	if (!PCM_REGISTERED(d) || d->clones == NULL)
1059 		return (ENODEV);
1060 
1061 	PCM_ACQUIRE_QUICK(d);
1062 
1063 	deadline = snd_clone_getdeadline(d->clones);
1064 	err = sysctl_handle_int(oidp, &deadline, 0, req);
1065 
1066 	if (err == 0 && req->newptr != NULL) {
1067 		if (deadline < 0)
1068 			err = EINVAL;
1069 		else
1070 			(void)snd_clone_setdeadline(d->clones, deadline);
1071 	}
1072 
1073 	PCM_RELEASE_QUICK(d);
1074 
1075 	return (err);
1076 }
1077 
1078 static int
1079 sysctl_dev_pcm_clone_gc(SYSCTL_HANDLER_ARGS)
1080 {
1081 	struct snddev_info *d;
1082 	int err, val;
1083 
1084 	d = oidp->oid_arg1;
1085 	if (!PCM_REGISTERED(d) || d->clones == NULL)
1086 		return (ENODEV);
1087 
1088 	val = 0;
1089 	err = sysctl_handle_int(oidp, &val, 0, req);
1090 
1091 	if (err == 0 && req->newptr != NULL && val != 0) {
1092 		PCM_ACQUIRE_QUICK(d);
1093 		val = snd_clone_gc(d->clones);
1094 		PCM_RELEASE_QUICK(d);
1095 		if (bootverbose != 0 || snd_verbose > 3)
1096 			device_printf(d->dev, "clone gc: pruned=%d\n", val);
1097 	}
1098 
1099 	return (err);
1100 }
1101 
1102 static int
1103 sysctl_hw_snd_clone_gc(SYSCTL_HANDLER_ARGS)
1104 {
1105 	struct snddev_info *d;
1106 	int i, err, val;
1107 
1108 	val = 0;
1109 	err = sysctl_handle_int(oidp, &val, 0, req);
1110 
1111 	if (err == 0 && req->newptr != NULL && val != 0) {
1112 		for (i = 0; pcm_devclass != NULL &&
1113 		    i < devclass_get_maxunit(pcm_devclass); i++) {
1114 			d = devclass_get_softc(pcm_devclass, i);
1115 			if (!PCM_REGISTERED(d) || d->clones == NULL)
1116 				continue;
1117 			PCM_ACQUIRE_QUICK(d);
1118 			val = snd_clone_gc(d->clones);
1119 			PCM_RELEASE_QUICK(d);
1120 			if (bootverbose != 0 || snd_verbose > 3)
1121 				device_printf(d->dev, "clone gc: pruned=%d\n",
1122 				    val);
1123 		}
1124 	}
1125 
1126 	return (err);
1127 }
1128 SYSCTL_PROC(_hw_snd, OID_AUTO, clone_gc,
1129     CTLTYPE_INT | CTLFLAG_RWTUN | CTLFLAG_NEEDGIANT, 0, sizeof(int),
1130     sysctl_hw_snd_clone_gc, "I",
1131     "global clone garbage collector");
1132 #endif
1133 
1134 static u_int8_t
1135 pcm_mode_init(struct snddev_info *d)
1136 {
1137 	u_int8_t mode = 0;
1138 
1139 	if (d->playcount > 0)
1140 		mode |= PCM_MODE_PLAY;
1141 	if (d->reccount > 0)
1142 		mode |= PCM_MODE_REC;
1143 	if (d->mixer_dev != NULL)
1144 		mode |= PCM_MODE_MIXER;
1145 
1146 	return (mode);
1147 }
1148 
1149 static void
1150 pcm_sysinit(device_t dev)
1151 {
1152   	struct snddev_info *d = device_get_softc(dev);
1153 	u_int8_t mode;
1154 
1155 	mode = pcm_mode_init(d);
1156 
1157 	/* XXX: a user should be able to set this with a control tool, the
1158 	   sysadmin then needs min+max sysctls for this */
1159 	SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev),
1160 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
1161             OID_AUTO, "buffersize", CTLFLAG_RD, &d->bufsz, 0, "allocated buffer size");
1162 	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
1163 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO,
1164 	    "bitperfect", CTLTYPE_INT | CTLFLAG_RWTUN | CTLFLAG_MPSAFE, d,
1165 	    sizeof(d), sysctl_dev_pcm_bitperfect, "I",
1166 	    "bit-perfect playback/recording (0=disable, 1=enable)");
1167 	SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev),
1168 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
1169 	    OID_AUTO, "mode", CTLFLAG_RD, NULL, mode,
1170 	    "mode (1=mixer, 2=play, 4=rec. The values are OR'ed if more than one"
1171 	    "mode is supported)");
1172 #ifdef SND_DEBUG
1173 	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
1174 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO,
1175 	    "clone_flags", CTLTYPE_UINT | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
1176 	    d, sizeof(d), sysctl_dev_pcm_clone_flags, "IU",
1177 	    "clone flags");
1178 	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
1179 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO,
1180 	    "clone_deadline", CTLTYPE_INT | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
1181 	    d, sizeof(d), sysctl_dev_pcm_clone_deadline, "I",
1182 	    "clone expiration deadline (ms)");
1183 	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
1184 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO,
1185 	    "clone_gc",
1186 	    CTLTYPE_INT | CTLFLAG_RWTUN | CTLFLAG_MPSAFE, d, sizeof(d),
1187 	    sysctl_dev_pcm_clone_gc, "I", "clone garbage collector");
1188 #endif
1189 	if (d->flags & SD_F_AUTOVCHAN)
1190 		vchan_initsys(dev);
1191 	if (d->flags & SD_F_EQ)
1192 		feeder_eq_initsys(dev);
1193 }
1194 
1195 int
1196 pcm_register(device_t dev, void *devinfo, int numplay, int numrec)
1197 {
1198 	struct snddev_info *d;
1199 	int i;
1200 
1201 	if (pcm_veto_load) {
1202 		device_printf(dev, "disabled due to an error while initialising: %d\n", pcm_veto_load);
1203 
1204 		return EINVAL;
1205 	}
1206 
1207 	if (device_get_unit(dev) > PCMMAXUNIT) {
1208 		device_printf(dev, "PCMMAXUNIT reached : unit=%d > %d\n",
1209 		    device_get_unit(dev), PCMMAXUNIT);
1210 		device_printf(dev,
1211 		    "Use 'hw.snd.maxunit' tunable to raise the limit.\n");
1212 		return ENODEV;
1213 	}
1214 
1215 	d = device_get_softc(dev);
1216 	d->dev = dev;
1217 	d->lock = snd_mtxcreate(device_get_nameunit(dev), "sound cdev");
1218 	cv_init(&d->cv, device_get_nameunit(dev));
1219 	PCM_ACQUIRE_QUICK(d);
1220 	dsp_cdevinfo_init(d);
1221 #if 0
1222 	/*
1223 	 * d->flags should be cleared by the allocator of the softc.
1224 	 * We cannot clear this field here because several devices set
1225 	 * this flag before calling pcm_register().
1226 	 */
1227 	d->flags = 0;
1228 #endif
1229 	i = 0;
1230 	if (resource_int_value(device_get_name(dev), device_get_unit(dev),
1231 	    "vpc", &i) != 0 || i != 0)
1232 		d->flags |= SD_F_VPC;
1233 
1234 	if (resource_int_value(device_get_name(dev), device_get_unit(dev),
1235 	    "bitperfect", &i) == 0 && i != 0)
1236 		d->flags |= SD_F_BITPERFECT;
1237 
1238 	d->devinfo = devinfo;
1239 	d->devcount = 0;
1240 	d->reccount = 0;
1241 	d->playcount = 0;
1242 	d->pvchancount = 0;
1243 	d->rvchancount = 0;
1244 	d->pvchanrate = 0;
1245 	d->pvchanformat = 0;
1246 	d->rvchanrate = 0;
1247 	d->rvchanformat = 0;
1248 
1249 	/*
1250 	 * Create clone manager, disabled by default. Cloning will be
1251 	 * enabled during final stage of driver initialization through
1252 	 * pcm_setstatus().
1253 	 */
1254 	d->clones = snd_clone_create(SND_U_MASK | SND_D_MASK, PCMMAXCLONE,
1255 	    SND_CLONE_DEADLINE_DEFAULT, SND_CLONE_WAITOK |
1256 	    SND_CLONE_GC_ENABLE | SND_CLONE_GC_UNREF |
1257 	    SND_CLONE_GC_LASTREF | SND_CLONE_GC_EXPIRED);
1258 
1259 	CHN_INIT(d, channels.pcm);
1260 	CHN_INIT(d, channels.pcm.busy);
1261 	CHN_INIT(d, channels.pcm.opened);
1262 
1263 	/* XXX This is incorrect, but lets play along for now. */
1264 	if ((numplay == 0 || numrec == 0) && numplay != numrec)
1265 		d->flags |= SD_F_SIMPLEX;
1266 
1267 	sysctl_ctx_init(&d->play_sysctl_ctx);
1268 	d->play_sysctl_tree = SYSCTL_ADD_NODE(&d->play_sysctl_ctx,
1269 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, "play",
1270 	    CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "playback channels node");
1271 	sysctl_ctx_init(&d->rec_sysctl_ctx);
1272 	d->rec_sysctl_tree = SYSCTL_ADD_NODE(&d->rec_sysctl_ctx,
1273 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, "rec",
1274 	    CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "recording channels node");
1275 
1276 	if (numplay > 0 || numrec > 0)
1277 		d->flags |= SD_F_AUTOVCHAN;
1278 
1279 	sndstat_register(dev, d->status, sndstat_prepare_pcm);
1280 
1281 	return 0;
1282 }
1283 
1284 int
1285 pcm_unregister(device_t dev)
1286 {
1287 	struct snddev_info *d;
1288 	struct pcm_channel *ch;
1289 
1290 	d = device_get_softc(dev);
1291 
1292 	if (!PCM_ALIVE(d)) {
1293 		device_printf(dev, "unregister: device not configured\n");
1294 		return (0);
1295 	}
1296 
1297 	PCM_LOCK(d);
1298 	PCM_WAIT(d);
1299 
1300 	d->flags |= SD_F_DETACHING;
1301 
1302 	PCM_ACQUIRE(d);
1303 	PCM_UNLOCK(d);
1304 
1305 	CHN_FOREACH(ch, d, channels.pcm) {
1306 		CHN_LOCK(ch);
1307 		if (ch->refcount > 0) {
1308 			device_printf(dev,
1309 			    "unregister: channel %s busy (pid %d)\n",
1310 			    ch->name, ch->pid);
1311 			CHN_UNLOCK(ch);
1312 			PCM_RELEASE_QUICK(d);
1313 			return (EBUSY);
1314 		}
1315 		CHN_UNLOCK(ch);
1316 	}
1317 
1318 	if (d->clones != NULL) {
1319 		if (snd_clone_busy(d->clones) != 0) {
1320 			device_printf(dev, "unregister: clone busy\n");
1321 			PCM_RELEASE_QUICK(d);
1322 			return (EBUSY);
1323 		} else {
1324 			PCM_LOCK(d);
1325 			(void)snd_clone_disable(d->clones);
1326 			PCM_UNLOCK(d);
1327 		}
1328 	}
1329 
1330 	if (mixer_uninit(dev) == EBUSY) {
1331 		device_printf(dev, "unregister: mixer busy\n");
1332 		PCM_LOCK(d);
1333 		if (d->clones != NULL)
1334 			(void)snd_clone_enable(d->clones);
1335 		PCM_RELEASE(d);
1336 		PCM_UNLOCK(d);
1337 		return (EBUSY);
1338 	}
1339 
1340 	/* remove /dev/sndstat entry first */
1341 	sndstat_unregister(dev);
1342 
1343 	PCM_LOCK(d);
1344 	d->flags |= SD_F_DYING;
1345 	d->flags &= ~SD_F_REGISTERED;
1346 	PCM_UNLOCK(d);
1347 
1348 	/*
1349 	 * No lock being held, so this thing can be flushed without
1350 	 * stucking into devdrn oblivion.
1351 	 */
1352 	if (d->clones != NULL) {
1353 		snd_clone_destroy(d->clones);
1354 		d->clones = NULL;
1355 	}
1356 
1357 	if (d->play_sysctl_tree != NULL) {
1358 		sysctl_ctx_free(&d->play_sysctl_ctx);
1359 		d->play_sysctl_tree = NULL;
1360 	}
1361 	if (d->rec_sysctl_tree != NULL) {
1362 		sysctl_ctx_free(&d->rec_sysctl_ctx);
1363 		d->rec_sysctl_tree = NULL;
1364 	}
1365 
1366 	while (!CHN_EMPTY(d, channels.pcm))
1367 		pcm_killchan(dev);
1368 
1369 	dsp_cdevinfo_flush(d);
1370 
1371 	PCM_LOCK(d);
1372 	PCM_RELEASE(d);
1373 	cv_destroy(&d->cv);
1374 	PCM_UNLOCK(d);
1375 	snd_mtxfree(d->lock);
1376 
1377 	if (snd_unit == device_get_unit(dev)) {
1378 		snd_unit = pcm_best_unit(-1);
1379 		if (snd_unit_auto == 0)
1380 			snd_unit_auto = 1;
1381 	}
1382 
1383 	return (0);
1384 }
1385 
1386 /************************************************************************/
1387 
1388 /**
1389  * @brief	Handle OSSv4 SNDCTL_SYSINFO ioctl.
1390  *
1391  * @param si	Pointer to oss_sysinfo struct where information about the
1392  * 		sound subsystem will be written/copied.
1393  *
1394  * This routine returns information about the sound system, such as the
1395  * current OSS version, number of audio, MIDI, and mixer drivers, etc.
1396  * Also includes a bitmask showing which of the above types of devices
1397  * are open (busy).
1398  *
1399  * @note
1400  * Calling threads must not hold any snddev_info or pcm_channel locks.
1401  *
1402  * @author	Ryan Beasley <ryanb@FreeBSD.org>
1403  */
1404 void
1405 sound_oss_sysinfo(oss_sysinfo *si)
1406 {
1407 	static char si_product[] = "FreeBSD native OSS ABI";
1408 	static char si_version[] = __XSTRING(__FreeBSD_version);
1409 	static char si_license[] = "BSD";
1410 	static int intnbits = sizeof(int) * 8;	/* Better suited as macro?
1411 						   Must pester a C guru. */
1412 
1413 	struct snddev_info *d;
1414 	struct pcm_channel *c;
1415 	int i, j, ncards;
1416 
1417 	ncards = 0;
1418 
1419 	strlcpy(si->product, si_product, sizeof(si->product));
1420 	strlcpy(si->version, si_version, sizeof(si->version));
1421 	si->versionnum = SOUND_VERSION;
1422 	strlcpy(si->license, si_license, sizeof(si->license));
1423 
1424 	/*
1425 	 * Iterate over PCM devices and their channels, gathering up data
1426 	 * for the numaudios, ncards, and openedaudio fields.
1427 	 */
1428 	si->numaudios = 0;
1429 	bzero((void *)&si->openedaudio, sizeof(si->openedaudio));
1430 
1431 	j = 0;
1432 
1433 	for (i = 0; pcm_devclass != NULL &&
1434 	    i < devclass_get_maxunit(pcm_devclass); i++) {
1435 		d = devclass_get_softc(pcm_devclass, i);
1436 		if (!PCM_REGISTERED(d))
1437 			continue;
1438 
1439 		/* XXX Need Giant magic entry ??? */
1440 
1441 		/* See note in function's docblock */
1442 		PCM_UNLOCKASSERT(d);
1443 		PCM_LOCK(d);
1444 
1445 		si->numaudios += d->devcount;
1446 		++ncards;
1447 
1448 		CHN_FOREACH(c, d, channels.pcm) {
1449 			CHN_UNLOCKASSERT(c);
1450 			CHN_LOCK(c);
1451 			if (c->flags & CHN_F_BUSY)
1452 				si->openedaudio[j / intnbits] |=
1453 				    (1 << (j % intnbits));
1454 			CHN_UNLOCK(c);
1455 			j++;
1456 		}
1457 
1458 		PCM_UNLOCK(d);
1459 	}
1460 	si->numaudioengines = si->numaudios;
1461 
1462 	si->numsynths = 0;	/* OSSv4 docs:  this field is obsolete */
1463 	/**
1464 	 * @todo	Collect num{midis,timers}.
1465 	 *
1466 	 * Need access to sound/midi/midi.c::midistat_lock in order
1467 	 * to safely touch midi_devices and get a head count of, well,
1468 	 * MIDI devices.  midistat_lock is a global static (i.e., local to
1469 	 * midi.c), but midi_devices is a regular global; should the mutex
1470 	 * be publicized, or is there another way to get this information?
1471 	 *
1472 	 * NB:	MIDI/sequencer stuff is currently on hold.
1473 	 */
1474 	si->nummidis = 0;
1475 	si->numtimers = 0;
1476 	si->nummixers = mixer_count;
1477 	si->numcards = ncards;
1478 		/* OSSv4 docs:	Intended only for test apps; API doesn't
1479 		   really have much of a concept of cards.  Shouldn't be
1480 		   used by applications. */
1481 
1482 	/**
1483 	 * @todo	Fill in "busy devices" fields.
1484 	 *
1485 	 *  si->openedmidi = " MIDI devices
1486 	 */
1487 	bzero((void *)&si->openedmidi, sizeof(si->openedmidi));
1488 
1489 	/*
1490 	 * Si->filler is a reserved array, but according to docs each
1491 	 * element should be set to -1.
1492 	 */
1493 	for (i = 0; i < sizeof(si->filler)/sizeof(si->filler[0]); i++)
1494 		si->filler[i] = -1;
1495 }
1496 
1497 int
1498 sound_oss_card_info(oss_card_info *si)
1499 {
1500 	struct snddev_info *d;
1501 	int i, ncards;
1502 
1503 	ncards = 0;
1504 
1505 	for (i = 0; pcm_devclass != NULL &&
1506 	    i < devclass_get_maxunit(pcm_devclass); i++) {
1507 		d = devclass_get_softc(pcm_devclass, i);
1508 		if (!PCM_REGISTERED(d))
1509 			continue;
1510 
1511 		if (ncards++ != si->card)
1512 			continue;
1513 
1514 		PCM_UNLOCKASSERT(d);
1515 		PCM_LOCK(d);
1516 
1517 		strlcpy(si->shortname, device_get_nameunit(d->dev),
1518 		    sizeof(si->shortname));
1519 		strlcpy(si->longname, device_get_desc(d->dev),
1520 		    sizeof(si->longname));
1521 		strlcpy(si->hw_info, d->status, sizeof(si->hw_info));
1522 		si->intr_count = si->ack_count = 0;
1523 
1524 		PCM_UNLOCK(d);
1525 
1526 		return (0);
1527 	}
1528 	return (ENXIO);
1529 }
1530 
1531 /************************************************************************/
1532 
1533 static int
1534 sound_modevent(module_t mod, int type, void *data)
1535 {
1536 	int ret;
1537 
1538 	ret = 0;
1539 	switch (type) {
1540 		case MOD_LOAD:
1541 			pcm_devclass = devclass_create("pcm");
1542 			pcmsg_unrhdr = new_unrhdr(1, INT_MAX, NULL);
1543 			break;
1544 		case MOD_UNLOAD:
1545 			if (pcmsg_unrhdr != NULL) {
1546 				delete_unrhdr(pcmsg_unrhdr);
1547 				pcmsg_unrhdr = NULL;
1548 			}
1549 			break;
1550 		case MOD_SHUTDOWN:
1551 			break;
1552 		default:
1553 			ret = ENOTSUP;
1554 	}
1555 
1556 	return ret;
1557 }
1558 
1559 DEV_MODULE(sound, sound_modevent, NULL);
1560 MODULE_VERSION(sound, SOUND_MODVER);
1561