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/channel.c

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

Cache object: 3bbe8f2d8e0882753794a4bc9976396b


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