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

Cache object: 4a38f27e09ae90689354d07bcaef9644


[ 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.