2 * Copyright (c) 1999 Cameron Grant <cg@freebsd.org>
3 * (C) 1997 Luigi Rizzo (luigi@iet.unipi.it)
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * $FreeBSD: src/sys/dev/sound/pcm/sound.c,v 1.93.2.5 2007/06/04 09:06:05 ariff Exp $
30 #include <dev/sound/pcm/sound.h>
31 #include <dev/sound/pcm/vchan.h>
32 #include <dev/sound/pcm/dsp.h>
33 #include <sys/sysctl.h>
34 #include <sys/devfs.h>
36 #include "feeder_if.h"
38 SND_DECLARE_FILE("$DragonFly: src/sys/dev/sound/pcm/sound.c,v 1.12 2008/01/06 16:55:51 swildner Exp $");
40 devclass_t pcm_devclass;
42 int pcm_veto_load = 1;
44 int snd_maxautovchans = 4;
45 TUNABLE_INT("hw.snd.maxautovchans", &snd_maxautovchans);
47 SYSCTL_NODE(_hw, OID_AUTO, snd, CTLFLAG_RD, 0, "Sound driver");
49 static int sndstat_prepare_pcm(struct sbuf *s, device_t dev, int verbose);
51 struct sysctl_ctx_list *
52 snd_sysctl_tree(device_t dev)
54 struct snddev_info *d = device_get_softc(dev);
56 return &d->sysctl_tree;
60 snd_sysctl_tree_top(device_t dev)
62 struct snddev_info *d = device_get_softc(dev);
64 return d->sysctl_tree_top;
68 snd_mtxcreate(const char *desc, const char *type)
73 m = kmalloc(sizeof(*m), M_DEVBUF, M_WAITOK | M_ZERO);
74 lockinit(m, __DECONST(char *, type), 0, LK_CANRECURSE);
77 return (void *)0xcafebabe;
92 snd_mtxassert(void *m)
107 lockmgr(lk, LK_EXCLUSIVE | LK_RETRY);
112 snd_mtxunlock(void *m)
117 lockmgr(lk, LK_RELEASE);
122 snd_mtxsleep(void *addr, sndlock_t lock, int flags, const char *wmesg, int timo)
126 tsleep_interlock(addr, flags);
128 r = tsleep(addr, flags | PINTERLOCKED, wmesg, timo);
136 snd_setup_intr(device_t dev, struct resource *res, int flags, driver_intr_t hand, void *param, void **cookiep)
139 flags &= INTR_MPSAFE;
140 flags |= INTR_TYPE_AV;
142 flags = INTR_TYPE_AV;
144 return bus_setup_intr(dev, res, flags, hand, param, cookiep, NULL);
147 #ifndef PCM_DEBUG_MTX
149 pcm_lock(struct snddev_info *d)
151 snd_mtxlock(d->lock);
155 pcm_unlock(struct snddev_info *d)
157 snd_mtxunlock(d->lock);
162 pcm_getfakechan(struct snddev_info *d)
168 pcm_setvchans(struct snddev_info *d, int newcnt)
170 struct snddev_channel *sce = NULL;
171 struct pcm_channel *c = NULL;
172 int err = 0, vcnt, dcnt, i;
176 if (!(d->flags & SD_F_AUTOVCHAN)) {
181 vcnt = d->vchancount;
182 dcnt = d->playcount + d->reccount;
184 if (newcnt < 0 || (dcnt + newcnt) > (PCMMAXCHAN + 1)) {
192 /* add new vchans - find a parent channel first */
193 SLIST_FOREACH(sce, &d->channels, link) {
196 if (c->direction == PCMDIR_PLAY &&
197 ((c->flags & CHN_F_HAS_VCHAN) ||
199 !(c->flags & (CHN_F_BUSY | CHN_F_VIRTUAL)))))
206 c->flags |= CHN_F_BUSY;
207 while (err == 0 && newcnt > vcnt) {
208 if (dcnt > PCMMAXCHAN) {
209 device_printf(d->dev, "%s: Maximum channel reached.\n", __func__);
212 err = vchan_create(c);
216 } else if (err == E2BIG && newcnt > vcnt)
217 device_printf(d->dev, "%s: err=%d Maximum channel reached.\n", __func__, err);
220 c->flags &= ~CHN_F_BUSY;
222 } else if (newcnt < vcnt) {
223 #define ORPHAN_CDEVT(cdevt) \
224 ((cdevt) == NULL || ((cdevt)->si_drv1 == NULL && \
225 (cdevt)->si_drv2 == NULL))
226 while (err == 0 && newcnt < vcnt) {
228 SLIST_FOREACH(sce, &d->channels, link) {
231 if (c->direction == PCMDIR_PLAY &&
232 (c->flags & CHN_F_VIRTUAL) &&
234 if (!(c->flags & CHN_F_BUSY) &&
235 ORPHAN_CDEVT(sce->dsp_dev))
238 * Either we're busy, or our cdev
239 * has been stolen by dsp_clone().
240 * Skip, and increase newcnt.
242 if (!(c->flags & CHN_F_BUSY))
243 device_printf(d->dev,
244 "%s: <%s> somebody steal my cdev!\n",
255 err = vchan_destroy(c);
259 device_printf(d->dev,
260 "%s: WARNING: vchan_destroy() failed!",
270 /* return error status and a locked channel */
272 pcm_chnalloc(struct snddev_info *d, struct pcm_channel **ch, int direction,
273 pid_t pid, int chnum)
275 struct pcm_channel *c;
276 struct snddev_channel *sce;
280 /* scan for a free channel */
281 SLIST_FOREACH(sce, &d->channels, link) {
284 if (c->direction == direction && !(c->flags & CHN_F_BUSY)) {
285 if (chnum < 0 || sce->chan_num == chnum) {
286 c->flags |= CHN_F_BUSY;
292 if (sce->chan_num == chnum) {
293 if (c->direction != direction)
295 else if (c->flags & CHN_F_BUSY)
301 } else if (c->direction == direction && (c->flags & CHN_F_BUSY))
309 /* release a locked channel and unlock it */
311 pcm_chnrelease(struct pcm_channel *c)
314 c->flags &= ~CHN_F_BUSY;
321 pcm_chnref(struct pcm_channel *c, int ref)
332 pcm_inprog(struct snddev_info *d, int delta)
348 pcm_setmaxautovchans(struct snddev_info *d, int num)
350 if (num > 0 && d->vchancount == 0)
352 else if (num == 0 && d->vchancount > 0)
358 sysctl_hw_snd_unit(SYSCTL_HANDLER_ARGS)
360 struct snddev_info *d;
364 error = sysctl_handle_int(oidp, &unit, 0, req);
365 if (error == 0 && req->newptr != NULL) {
366 if (unit < 0 || (pcm_devclass != NULL &&
367 unit >= devclass_get_maxunit(pcm_devclass)))
369 d = devclass_get_softc(pcm_devclass, unit);
370 if (d == NULL || SLIST_EMPTY(&d->channels))
376 SYSCTL_PROC(_hw_snd, OID_AUTO, unit, CTLTYPE_INT | CTLFLAG_RW,
377 0, sizeof(int), sysctl_hw_snd_unit, "I", "");
381 sysctl_hw_snd_maxautovchans(SYSCTL_HANDLER_ARGS)
383 struct snddev_info *d;
386 v = snd_maxautovchans;
387 error = sysctl_handle_int(oidp, &v, 0, req);
388 if (error == 0 && req->newptr != NULL) {
389 if (v < 0 || v > PCMMAXCHAN)
391 if (pcm_devclass != NULL && v != snd_maxautovchans) {
392 for (i = 0; i < devclass_get_maxunit(pcm_devclass); i++) {
393 d = devclass_get_softc(pcm_devclass, i);
396 pcm_setmaxautovchans(d, v);
399 snd_maxautovchans = v;
403 SYSCTL_PROC(_hw_snd, OID_AUTO, maxautovchans, CTLTYPE_INT | CTLFLAG_RW,
404 0, sizeof(int), sysctl_hw_snd_maxautovchans, "I", "");
407 pcm_chn_create(struct snddev_info *d, struct pcm_channel *parent, kobj_class_t cls, int dir, void *devinfo)
409 struct snddev_channel *sce;
410 struct pcm_channel *ch, *c;
412 uint32_t flsearch = 0;
413 int direction, err, rpnum, *pnum;
418 direction = PCMDIR_PLAY;
419 pnum = &d->playcount;
424 direction = PCMDIR_REC;
430 direction = PCMDIR_PLAY;
431 pnum = &d->vchancount;
432 flsearch = CHN_F_VIRTUAL;
439 ch = kmalloc(sizeof(*ch), M_DEVBUF, M_WAITOK | M_ZERO);
441 ch->methods = kobj_create(cls, M_DEVBUF, M_WAITOK);
448 snd_mtxlock(d->lock);
451 SLIST_FOREACH(sce, &d->channels, link) {
453 if (direction != c->direction ||
454 (c->flags & CHN_F_VIRTUAL) != flsearch)
456 if (ch->num == c->num)
460 device_printf(d->dev,
461 "%s: %s channel numbering screwed (Expect: %d, Got: %d)\n",
462 __func__, dirs, ch->num, c->num);
464 goto retry_num_search;
468 goto retry_num_search_out;
471 SLIST_FOREACH(sce, &d->channels, link) {
473 if (direction != c->direction ||
474 (c->flags & CHN_F_VIRTUAL) != flsearch)
476 if (ch->num == c->num) {
478 goto retry_num_search;
482 retry_num_search_out:
483 if (*pnum != rpnum) {
484 device_printf(d->dev,
485 "%s: WARNING: pnum screwed : dirs=%s, pnum=%d, rpnum=%d\n",
486 __func__, dirs, *pnum, rpnum);
490 snd_mtxunlock(d->lock);
493 ch->parentsnddev = d;
494 ch->parentchannel = parent;
496 ksnprintf(ch->name, CHN_NAMELEN, "%s:%s:%d", device_get_nameunit(ch->dev), dirs, ch->num);
498 err = chn_init(ch, devinfo, dir, direction);
500 device_printf(d->dev, "chn_init(%s) failed: err = %d\n", ch->name, err);
501 kobj_delete(ch->methods, M_DEVBUF);
503 snd_mtxlock(d->lock);
505 snd_mtxunlock(d->lock);
514 pcm_chn_iterate(struct snddev_info *d, void **cookie)
516 struct snddev_channel **last = (struct snddev_channel **)cookie;
519 *last = SLIST_FIRST(&d->channels);
521 *last = SLIST_NEXT(*last, link);
526 return (*last)->channel;
530 pcm_chn_destroy(struct pcm_channel *ch)
532 struct snddev_info *d;
535 d = ch->parentsnddev;
538 device_printf(d->dev, "chn_kill(%s) failed, err = %d\n", ch->name, err);
542 kobj_delete(ch->methods, M_DEVBUF);
549 pcm_chn_add(struct snddev_info *d, struct pcm_channel *ch)
551 struct snddev_channel *sce, *tmp, *after;
553 int device = device_get_unit(d->dev);
557 * Note it's confusing nomenclature.
559 * device -> pcm_device
560 * unit -> pcm_channel
561 * channel -> snddev_channel
566 sce = kmalloc(sizeof(*sce), M_DEVBUF, M_WAITOK | M_ZERO);
568 snd_mtxlock(d->lock);
573 SLIST_FOREACH(tmp, &d->channels, link) {
574 if (sce->chan_num == tmp->chan_num)
578 device_printf(d->dev,
579 "%s: cdev numbering screwed (Expect: %d, Got: %d)\n",
580 __func__, sce->chan_num, tmp->chan_num);
582 goto retry_chan_num_search;
587 goto retry_chan_num_search_out;
588 retry_chan_num_search:
590 * Look for possible channel numbering collision. This may not
591 * be optimized, but it will ensure that no collision occured.
592 * Can be considered cheap since none of the locking/unlocking
593 * operations involved.
597 SLIST_FOREACH(tmp, &d->channels, link) {
598 if (sce->chan_num == tmp->chan_num) {
600 goto retry_chan_num_search;
602 if (sce->chan_num > tmp->chan_num)
606 retry_chan_num_search_out:
608 * Don't overflow PCMMKMINOR / PCMMAXCHAN.
610 if (sce->chan_num > PCMMAXCHAN) {
611 snd_mtxunlock(d->lock);
612 device_printf(d->dev,
613 "%s: WARNING: sce->chan_num overflow! (%d)\n",
614 __func__, sce->chan_num);
615 kfree(sce, M_DEVBUF);
618 if (d->devcount != rdevcount) {
619 device_printf(d->dev,
620 "%s: WARNING: devcount screwed! d->devcount=%u, rdevcount=%u\n",
621 __func__, d->devcount, rdevcount);
622 d->devcount = rdevcount;
626 SLIST_INSERT_HEAD(&d->channels, sce, link);
628 SLIST_INSERT_AFTER(after, sce, link);
633 SLIST_FOREACH(tmp, &d->channels, link) {
634 if (cnum != tmp->chan_num)
635 device_printf(d->dev,
636 "%s: WARNING: inconsistent cdev numbering! (Expect: %d, Got: %d)\n",
637 __func__, cnum, tmp->chan_num);
643 namelen = strlen(ch->name);
644 if ((CHN_NAMELEN - namelen) > 10) { /* ":dspXX.YYY" */
645 ksnprintf(ch->name + namelen,
646 CHN_NAMELEN - namelen, ":dsp%d.%d",
647 device, sce->chan_num);
649 snd_mtxunlock(d->lock);
655 pcm_chn_remove(struct snddev_info *d, struct pcm_channel *ch)
657 struct snddev_channel *sce;
662 if (!mtx_owned(d->lock)) {
663 snd_mtxlock(d->lock);
668 SLIST_FOREACH(sce, &d->channels, link) {
669 if (sce->channel == ch)
674 snd_mtxunlock(d->lock);
678 SLIST_REMOVE(&d->channels, sce, snddev_channel, link);
680 if (ch->flags & CHN_F_VIRTUAL)
682 else if (ch->direction == PCMDIR_REC)
689 snd_mtxunlock(d->lock);
691 kfree(sce, M_DEVBUF);
697 pcm_addchan(device_t dev, int dir, kobj_class_t cls, void *devinfo)
699 struct snddev_info *d = device_get_softc(dev);
700 struct pcm_channel *ch;
703 ch = pcm_chn_create(d, NULL, cls, dir, devinfo);
705 device_printf(d->dev, "pcm_chn_create(%s, %d, %p) failed\n", cls->name, dir, devinfo);
709 err = pcm_chn_add(d, ch);
711 device_printf(d->dev, "pcm_chn_add(%s) failed, err=%d\n", ch->name, err);
720 pcm_killchan(device_t dev)
722 struct snddev_info *d = device_get_softc(dev);
723 struct snddev_channel *sce;
724 struct pcm_channel *ch;
727 sce = SLIST_FIRST(&d->channels);
730 error = pcm_chn_remove(d, sce->channel);
733 return (pcm_chn_destroy(ch));
737 pcm_setstatus(device_t dev, char *str)
739 struct snddev_info *d = device_get_softc(dev);
741 snd_mtxlock(d->lock);
742 strncpy(d->status, str, SND_STATUSLEN);
743 snd_mtxunlock(d->lock);
744 if (snd_maxautovchans > 0)
750 pcm_getflags(device_t dev)
752 struct snddev_info *d = device_get_softc(dev);
758 pcm_setflags(device_t dev, uint32_t val)
760 struct snddev_info *d = device_get_softc(dev);
766 pcm_getdevinfo(device_t dev)
768 struct snddev_info *d = device_get_softc(dev);
774 pcm_getbuffersize(device_t dev, unsigned int min, unsigned int deflt, unsigned int max)
776 struct snddev_info *d = device_get_softc(dev);
780 if (resource_int_value(device_get_name(dev), device_get_unit(dev), "buffersize", &sz) == 0) {
784 device_printf(dev, "'buffersize=%d' hint is out of range (%d-%d), using %d\n", x, min, max, sz);
791 device_printf(dev, "'buffersize=%d' hint is not a power of 2, using %d\n", sz, x);
804 pcm_register(device_t dev, void *devinfo, int numplay, int numrec)
806 struct snddev_info *d = device_get_softc(dev);
809 device_printf(dev, "disabled due to an error while initialising: %d\n", pcm_veto_load);
814 d->lock = snd_mtxcreate(device_get_nameunit(dev), "sound cdev");
818 * d->flags should be cleared by the allocator of the softc.
819 * We cannot clear this field here because several devices set
820 * this flag before calling pcm_register().
825 d->devinfo = devinfo;
832 SLIST_INIT(&d->channels);
834 if ((numplay == 0 || numrec == 0) && numplay != numrec)
835 d->flags |= SD_F_SIMPLEX;
837 d->fakechan = fkchan_setup(dev);
838 chn_init(d->fakechan, NULL, 0, 0);
841 sysctl_ctx_init(&d->sysctl_tree);
842 d->sysctl_tree_top = SYSCTL_ADD_NODE(&d->sysctl_tree,
843 SYSCTL_STATIC_CHILDREN(_hw_snd), OID_AUTO,
844 device_get_nameunit(dev), CTLFLAG_RD, 0, "");
845 if (d->sysctl_tree_top == NULL) {
846 sysctl_ctx_free(&d->sysctl_tree);
849 SYSCTL_ADD_INT(snd_sysctl_tree(dev), SYSCTL_CHILDREN(snd_sysctl_tree_top(dev)),
850 OID_AUTO, "buffersize", CTLFLAG_RD, &d->bufsz, 0, "");
853 d->flags |= SD_F_AUTOVCHAN;
857 /* XXX use make_autoclone_dev? */
858 /* XXX PCMMAXCHAN can be created for regular channels */
859 d->dsp_clonedev = make_dev(&dsp_ops,
860 PCMMKMINOR(device_get_unit(dev), PCMMAXCHAN),
861 UID_ROOT, GID_WHEEL, 0666, "dsp%d",
862 device_get_unit(dev));
863 devfs_clone_handler_add(devtoname(d->dsp_clonedev), dsp_clone);
865 sndstat_register(dev, d->status, sndstat_prepare_pcm);
868 snd_mtxfree(d->lock);
873 pcm_unregister(device_t dev)
875 struct snddev_info *d = device_get_softc(dev);
876 struct snddev_channel *sce;
877 struct pcmchan_children *pce;
878 struct pcm_channel *ch;
880 if (sndstat_acquire() != 0) {
881 device_printf(dev, "unregister: sndstat busy\n");
885 snd_mtxlock(d->lock);
887 device_printf(dev, "unregister: operation in progress\n");
888 snd_mtxunlock(d->lock);
893 SLIST_FOREACH(sce, &d->channels, link) {
895 if (ch->refcount > 0) {
896 device_printf(dev, "unregister: channel %s busy (pid %d)\n", ch->name, ch->pid);
897 snd_mtxunlock(d->lock);
903 if (mixer_uninit(dev) == EBUSY) {
904 device_printf(dev, "unregister: mixer busy\n");
905 snd_mtxunlock(d->lock);
910 SLIST_FOREACH(sce, &d->channels, link) {
912 destroy_dev(sce->dsp_dev);
919 pce = SLIST_FIRST(&ch->children);
920 while (pce != NULL) {
922 device_printf(d->dev, "<%s> removing <%s>\n",
923 ch->name, (pce->channel != NULL) ?
924 pce->channel->name : "unknown");
926 SLIST_REMOVE(&ch->children, pce, pcmchan_children, link);
927 kfree(pce, M_DEVBUF);
928 pce = SLIST_FIRST(&ch->children);
933 d->sysctl_tree_top = NULL;
934 sysctl_ctx_free(&d->sysctl_tree);
938 SLIST_FOREACH(sce, &d->channels, link) {
942 if (!SLIST_EMPTY(&ch->children))
943 device_printf(d->dev, "%s: WARNING: <%s> dangling child!\n",
947 while (!SLIST_EMPTY(&d->channels))
950 chn_kill(d->fakechan);
951 fkchan_kill(d->fakechan);
953 destroy_autoclone_dev(d->dsp_clonedev, NULL);
956 device_printf(d->dev, "%s: devcount=%u, playcount=%u, "
957 "reccount=%u, vchancount=%u\n",
958 __func__, d->devcount, d->playcount, d->reccount,
961 snd_mtxunlock(d->lock);
962 snd_mtxfree(d->lock);
963 sndstat_unregister(dev);
968 /************************************************************************/
971 sndstat_prepare_pcm(struct sbuf *s, device_t dev, int verbose)
973 struct snddev_info *d;
974 struct snddev_channel *sce;
975 struct pcm_channel *c;
976 struct pcm_feeder *f;
982 d = device_get_softc(dev);
986 snd_mtxlock(d->lock);
987 if (!SLIST_EMPTY(&d->channels)) {
989 SLIST_FOREACH(sce, &d->channels, link) {
991 if (c->direction == PCMDIR_PLAY) {
992 if (c->flags & CHN_F_VIRTUAL)
999 sbuf_printf(s, " (%dp/%dr/%dv channels%s%s)", d->playcount, d->reccount, d->vchancount,
1000 (d->flags & SD_F_SIMPLEX)? "" : " duplex",
1002 (device_get_unit(dev) == snd_unit)? " default" : ""
1009 snd_mtxunlock(d->lock);
1013 SLIST_FOREACH(sce, &d->channels, link) {
1016 KASSERT(c->bufhard != NULL && c->bufsoft != NULL,
1017 ("hosed pcm channel setup"));
1019 sbuf_printf(s, "\n\t");
1021 /* it would be better to indent child channels */
1022 sbuf_printf(s, "%s[%s]: ", c->parentchannel? c->parentchannel->name : "", c->name);
1023 sbuf_printf(s, "spd %d", c->speed);
1024 if (c->speed != sndbuf_getspd(c->bufhard))
1025 sbuf_printf(s, "/%d", sndbuf_getspd(c->bufhard));
1026 sbuf_printf(s, ", fmt 0x%08x", c->format);
1027 if (c->format != sndbuf_getfmt(c->bufhard))
1028 sbuf_printf(s, "/0x%08x", sndbuf_getfmt(c->bufhard));
1029 sbuf_printf(s, ", flags 0x%08x, 0x%08x", c->flags, c->feederflags);
1031 sbuf_printf(s, ", pid %d", c->pid);
1032 sbuf_printf(s, "\n\t");
1034 sbuf_printf(s, "interrupts %d, ", c->interrupts);
1035 if (c->direction == PCMDIR_REC)
1036 sbuf_printf(s, "overruns %d, hfree %d, sfree %d [b:%d/%d/%d|bs:%d/%d/%d]",
1037 c->xruns, sndbuf_getfree(c->bufhard), sndbuf_getfree(c->bufsoft),
1038 sndbuf_getsize(c->bufhard), sndbuf_getblksz(c->bufhard),
1039 sndbuf_getblkcnt(c->bufhard),
1040 sndbuf_getsize(c->bufsoft), sndbuf_getblksz(c->bufsoft),
1041 sndbuf_getblkcnt(c->bufsoft));
1043 sbuf_printf(s, "underruns %d, ready %d [b:%d/%d/%d|bs:%d/%d/%d]",
1044 c->xruns, sndbuf_getready(c->bufsoft),
1045 sndbuf_getsize(c->bufhard), sndbuf_getblksz(c->bufhard),
1046 sndbuf_getblkcnt(c->bufhard),
1047 sndbuf_getsize(c->bufsoft), sndbuf_getblksz(c->bufsoft),
1048 sndbuf_getblkcnt(c->bufsoft));
1049 sbuf_printf(s, "\n\t");
1051 sbuf_printf(s, "{%s}", (c->direction == PCMDIR_REC)? "hardware" : "userland");
1052 sbuf_printf(s, " -> ");
1054 while (f->source != NULL)
1057 sbuf_printf(s, "%s", f->class->name);
1058 if (f->desc->type == FEEDER_FMT)
1059 sbuf_printf(s, "(0x%08x -> 0x%08x)", f->desc->in, f->desc->out);
1060 if (f->desc->type == FEEDER_RATE)
1061 sbuf_printf(s, "(%d -> %d)", FEEDER_GET(f, FEEDRATE_SRC), FEEDER_GET(f, FEEDRATE_DST));
1062 if (f->desc->type == FEEDER_ROOT || f->desc->type == FEEDER_MIXER ||
1063 f->desc->type == FEEDER_VOLUME)
1064 sbuf_printf(s, "(0x%08x)", f->desc->out);
1065 sbuf_printf(s, " -> ");
1068 sbuf_printf(s, "{%s}", (c->direction == PCMDIR_REC)? "userland" : "hardware");
1071 sbuf_printf(s, " (mixer only)");
1072 snd_mtxunlock(d->lock);
1077 /************************************************************************/
1079 #ifdef SND_DYNSYSCTL
1081 sysctl_hw_snd_vchans(SYSCTL_HANDLER_ARGS)
1083 struct snddev_info *d;
1088 newcnt = d->vchancount;
1089 err = sysctl_handle_int(oidp, &newcnt, 0, req);
1091 if (err == 0 && req->newptr != NULL && d->vchancount != newcnt)
1092 err = pcm_setvchans(d, newcnt);
1098 /************************************************************************/
1101 sound_modevent(module_t mod, int type, void *data)
1104 return (midi_modevent(mod, type, data));
1110 DEV_MODULE(sound, sound_modevent, NULL);
1111 MODULE_VERSION(sound, SOUND_MODVER);