The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/sound/pcm/sound.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: 669065ef00d4df3c18bd4493b883d3df


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.