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) 1999 Cameron Grant <cg@freebsd.org>
    3  * Portions Copyright by Luigi Rizzo - 1997-99
    4  * All rights reserved.
    5  *
    6  * Redistribution and use in source and binary forms, with or without
    7  * modification, are permitted provided that the following conditions
    8  * are met:
    9  * 1. Redistributions of source code must retain the above copyright
   10  *    notice, this list of conditions and the following disclaimer.
   11  * 2. Redistributions in binary form must reproduce the above copyright
   12  *    notice, this list of conditions and the following disclaimer in the
   13  *    documentation and/or other materials provided with the distribution.
   14  *
   15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   25  * SUCH DAMAGE.
   26  */
   27 
   28 #include "opt_isa.h"
   29 
   30 #include <dev/sound/pcm/sound.h>
   31 
   32 #include "feeder_if.h"
   33 
   34 SND_DECLARE_FILE("$FreeBSD$");
   35 
   36 int report_soft_formats = 1;
   37 SYSCTL_INT(_hw_snd, OID_AUTO, report_soft_formats, CTLFLAG_RW,
   38         &report_soft_formats, 1, "report software-emulated formats");
   39 
   40 int chn_latency = CHN_LATENCY_DEFAULT;
   41 TUNABLE_INT("hw.snd.latency", &chn_latency);
   42 
   43 static int
   44 sysctl_hw_snd_latency(SYSCTL_HANDLER_ARGS)
   45 {
   46         int err, val;
   47 
   48         val = chn_latency;
   49         err = sysctl_handle_int(oidp, &val, 0, req);
   50         if (err != 0 || req->newptr == NULL)
   51                 return err;
   52         if (val < CHN_LATENCY_MIN || val > CHN_LATENCY_MAX)
   53                 err = EINVAL;
   54         else
   55                 chn_latency = val;
   56 
   57         return err;
   58 }
   59 SYSCTL_PROC(_hw_snd, OID_AUTO, latency, CTLTYPE_INT | CTLFLAG_RW,
   60         0, sizeof(int), sysctl_hw_snd_latency, "I",
   61         "buffering latency (0=low ... 10=high)");
   62 
   63 int chn_latency_profile = CHN_LATENCY_PROFILE_DEFAULT;
   64 TUNABLE_INT("hw.snd.latency_profile", &chn_latency_profile);
   65 
   66 static int
   67 sysctl_hw_snd_latency_profile(SYSCTL_HANDLER_ARGS)
   68 {
   69         int err, val;
   70 
   71         val = chn_latency_profile;
   72         err = sysctl_handle_int(oidp, &val, 0, req);
   73         if (err != 0 || req->newptr == NULL)
   74                 return err;
   75         if (val < CHN_LATENCY_PROFILE_MIN || val > CHN_LATENCY_PROFILE_MAX)
   76                 err = EINVAL;
   77         else
   78                 chn_latency_profile = val;
   79 
   80         return err;
   81 }
   82 SYSCTL_PROC(_hw_snd, OID_AUTO, latency_profile, CTLTYPE_INT | CTLFLAG_RW,
   83         0, sizeof(int), sysctl_hw_snd_latency_profile, "I",
   84         "buffering latency profile (0=aggresive 1=safe)");
   85 
   86 static int chn_timeout = CHN_TIMEOUT;
   87 TUNABLE_INT("hw.snd.timeout", &chn_timeout);
   88 #ifdef SND_DEBUG
   89 static int
   90 sysctl_hw_snd_timeout(SYSCTL_HANDLER_ARGS)
   91 {
   92         int err, val;
   93 
   94         val = chn_timeout;
   95         err = sysctl_handle_int(oidp, &val, 0, req);
   96         if (err != 0 || req->newptr == NULL)
   97                 return err;
   98         if (val < CHN_TIMEOUT_MIN || val > CHN_TIMEOUT_MAX)
   99                 err = EINVAL;
  100         else
  101                 chn_timeout = val;
  102 
  103         return err;
  104 }
  105 SYSCTL_PROC(_hw_snd, OID_AUTO, timeout, CTLTYPE_INT | CTLFLAG_RW,
  106         0, sizeof(int), sysctl_hw_snd_timeout, "I",
  107         "interrupt timeout (1 - 10) seconds");
  108 #endif
  109 
  110 static int chn_usefrags = 0;
  111 TUNABLE_INT("hw.snd.usefrags", &chn_usefrags);
  112 static int chn_syncdelay = -1;
  113 TUNABLE_INT("hw.snd.syncdelay", &chn_syncdelay);
  114 #ifdef SND_DEBUG
  115 SYSCTL_INT(_hw_snd, OID_AUTO, usefrags, CTLFLAG_RW,
  116         &chn_usefrags, 1, "prefer setfragments() over setblocksize()");
  117 SYSCTL_INT(_hw_snd, OID_AUTO, syncdelay, CTLFLAG_RW,
  118         &chn_syncdelay, 1,
  119         "append (0-1000) millisecond trailing buffer delay on each sync");
  120 #endif
  121 
  122 /**
  123  * @brief Channel sync group lock
  124  *
  125  * Clients should acquire this lock @b without holding any channel locks
  126  * before touching syncgroups or the main syncgroup list.
  127  */
  128 struct mtx snd_pcm_syncgroups_mtx;
  129 MTX_SYSINIT(pcm_syncgroup, &snd_pcm_syncgroups_mtx, "PCM channel sync group lock", MTX_DEF);
  130 /**
  131  * @brief syncgroups' master list
  132  *
  133  * Each time a channel syncgroup is created, it's added to this list.  This
  134  * list should only be accessed with @sa snd_pcm_syncgroups_mtx held.
  135  *
  136  * See SNDCTL_DSP_SYNCGROUP for more information.
  137  */
  138 struct pcm_synclist snd_pcm_syncgroups = SLIST_HEAD_INITIALIZER(head);
  139 
  140 static int chn_buildfeeder(struct pcm_channel *c);
  141 
  142 static void
  143 chn_lockinit(struct pcm_channel *c, int dir)
  144 {
  145         switch (dir) {
  146         case PCMDIR_PLAY:
  147                 c->lock = snd_mtxcreate(c->name, "pcm play channel");
  148                 cv_init(&c->intr_cv, "pcmwr");
  149                 break;
  150         case PCMDIR_PLAY_VIRTUAL:
  151                 c->lock = snd_mtxcreate(c->name, "pcm virtual play channel");
  152                 cv_init(&c->intr_cv, "pcmwrv");
  153                 break;
  154         case PCMDIR_REC:
  155                 c->lock = snd_mtxcreate(c->name, "pcm record channel");
  156                 cv_init(&c->intr_cv, "pcmrd");
  157                 break;
  158         case PCMDIR_REC_VIRTUAL:
  159                 c->lock = snd_mtxcreate(c->name, "pcm virtual record channel");
  160                 cv_init(&c->intr_cv, "pcmrdv");
  161                 break;
  162         case 0:
  163                 c->lock = snd_mtxcreate(c->name, "pcm fake channel");
  164                 cv_init(&c->intr_cv, "pcmfk");
  165                 break;
  166         }
  167 
  168         cv_init(&c->cv, "pcmchn");
  169 }
  170 
  171 static void
  172 chn_lockdestroy(struct pcm_channel *c)
  173 {
  174         CHN_LOCKASSERT(c);
  175 
  176         CHN_BROADCAST(&c->cv);
  177         CHN_BROADCAST(&c->intr_cv);
  178 
  179         cv_destroy(&c->cv);
  180         cv_destroy(&c->intr_cv);
  181 
  182         snd_mtxfree(c->lock);
  183 }
  184 
  185 /**
  186  * @brief Determine channel is ready for I/O
  187  *
  188  * @retval 1 = ready for I/O
  189  * @retval 0 = not ready for I/O
  190  */
  191 static int
  192 chn_polltrigger(struct pcm_channel *c)
  193 {
  194         struct snd_dbuf *bs = c->bufsoft;
  195         unsigned amt, lim;
  196 
  197         CHN_LOCKASSERT(c);
  198         if (c->flags & CHN_F_MAPPED) {
  199                 if (sndbuf_getprevblocks(bs) == 0)
  200                         return 1;
  201                 else
  202                         return (sndbuf_getblocks(bs) > sndbuf_getprevblocks(bs))? 1 : 0;
  203         } else {
  204                 amt = (c->direction == PCMDIR_PLAY)? sndbuf_getfree(bs) : sndbuf_getready(bs);
  205 #if 0
  206                 lim = (c->flags & CHN_F_HAS_SIZE)? sndbuf_getblksz(bs) : 1;
  207 #endif
  208                 lim = c->lw;
  209                 return (amt >= lim) ? 1 : 0;
  210         }
  211         return 0;
  212 }
  213 
  214 static int
  215 chn_pollreset(struct pcm_channel *c)
  216 {
  217         struct snd_dbuf *bs = c->bufsoft;
  218 
  219         CHN_LOCKASSERT(c);
  220         sndbuf_updateprevtotal(bs);
  221         return 1;
  222 }
  223 
  224 static void
  225 chn_wakeup(struct pcm_channel *c)
  226 {
  227         struct snd_dbuf *bs;
  228         struct pcm_channel *ch;
  229 
  230         CHN_LOCKASSERT(c);
  231 
  232         bs = c->bufsoft;
  233 
  234         if (CHN_EMPTY(c, children.busy)) {
  235                 if (SEL_WAITING(sndbuf_getsel(bs)) && chn_polltrigger(c))
  236                         selwakeuppri(sndbuf_getsel(bs), PRIBIO);
  237                 if (c->flags & CHN_F_SLEEPING) {
  238                         /*
  239                          * Ok, I can just panic it right here since it is
  240                          * quite obvious that we never allow multiple waiters
  241                          * from userland. I'm too generous...
  242                          */
  243                         CHN_BROADCAST(&c->intr_cv);
  244                 }
  245         } else {
  246                 CHN_FOREACH(ch, c, children.busy) {
  247                         CHN_LOCK(ch);
  248                         chn_wakeup(ch);
  249                         CHN_UNLOCK(ch);
  250                 }
  251         }
  252 }
  253 
  254 static int
  255 chn_sleep(struct pcm_channel *c, int timeout)
  256 {
  257         int ret;
  258 
  259         CHN_LOCKASSERT(c);
  260 
  261         if (c->flags & CHN_F_DEAD)
  262                 return (EINVAL);
  263 
  264         c->flags |= CHN_F_SLEEPING;
  265         ret = cv_timedwait_sig(&c->intr_cv, c->lock, timeout);
  266         c->flags &= ~CHN_F_SLEEPING;
  267 
  268         return ((c->flags & CHN_F_DEAD) ? EINVAL : ret);
  269 }
  270 
  271 /*
  272  * chn_dmaupdate() tracks the status of a dma transfer,
  273  * updating pointers.
  274  */
  275 
  276 static unsigned int
  277 chn_dmaupdate(struct pcm_channel *c)
  278 {
  279         struct snd_dbuf *b = c->bufhard;
  280         unsigned int delta, old, hwptr, amt;
  281 
  282         KASSERT(sndbuf_getsize(b) > 0, ("bufsize == 0"));
  283         CHN_LOCKASSERT(c);
  284 
  285         old = sndbuf_gethwptr(b);
  286         hwptr = chn_getptr(c);
  287         delta = (sndbuf_getsize(b) + hwptr - old) % sndbuf_getsize(b);
  288         sndbuf_sethwptr(b, hwptr);
  289 
  290         if (c->direction == PCMDIR_PLAY) {
  291                 amt = min(delta, sndbuf_getready(b));
  292                 amt -= amt % sndbuf_getbps(b);
  293                 if (amt > 0)
  294                         sndbuf_dispose(b, NULL, amt);
  295         } else {
  296                 amt = min(delta, sndbuf_getfree(b));
  297                 amt -= amt % sndbuf_getbps(b);
  298                 if (amt > 0)
  299                        sndbuf_acquire(b, NULL, amt);
  300         }
  301         if (snd_verbose > 3 && CHN_STARTED(c) && delta == 0) {
  302                 device_printf(c->dev, "WARNING: %s DMA completion "
  303                         "too fast/slow ! hwptr=%u, old=%u "
  304                         "delta=%u amt=%u ready=%u free=%u\n",
  305                         CHN_DIRSTR(c), hwptr, old, delta, amt,
  306                         sndbuf_getready(b), sndbuf_getfree(b));
  307         }
  308 
  309         return delta;
  310 }
  311 
  312 void
  313 chn_wrupdate(struct pcm_channel *c)
  314 {
  315         int ret;
  316 
  317         CHN_LOCKASSERT(c);
  318         KASSERT(c->direction == PCMDIR_PLAY, ("chn_wrupdate on bad channel"));
  319 
  320         if ((c->flags & (CHN_F_MAPPED | CHN_F_VIRTUAL)) || CHN_STOPPED(c))
  321                 return;
  322         chn_dmaupdate(c);
  323         ret = chn_wrfeed(c);
  324         /* tell the driver we've updated the primary buffer */
  325         chn_trigger(c, PCMTRIG_EMLDMAWR);
  326         DEB(if (ret)
  327                 printf("chn_wrupdate: chn_wrfeed returned %d\n", ret);)
  328 
  329 }
  330 
  331 int
  332 chn_wrfeed(struct pcm_channel *c)
  333 {
  334         struct snd_dbuf *b = c->bufhard;
  335         struct snd_dbuf *bs = c->bufsoft;
  336         unsigned int ret, amt;
  337 
  338         CHN_LOCKASSERT(c);
  339 
  340         if ((c->flags & CHN_F_MAPPED) && !(c->flags & CHN_F_CLOSING))
  341                 sndbuf_acquire(bs, NULL, sndbuf_getfree(bs));
  342 
  343         amt = sndbuf_getfree(b);
  344 
  345         ret = (amt > 0) ? sndbuf_feed(bs, b, c, c->feeder, amt) : ENOSPC;
  346         /*
  347          * Possible xruns. There should be no empty space left in buffer.
  348          */
  349         if (sndbuf_getfree(b) > 0)
  350                 c->xruns++;
  351 
  352         if (sndbuf_getfree(b) < amt)
  353                 chn_wakeup(c);
  354 
  355         return ret;
  356 }
  357 
  358 static void
  359 chn_wrintr(struct pcm_channel *c)
  360 {
  361         int ret;
  362 
  363         CHN_LOCKASSERT(c);
  364         /* update pointers in primary buffer */
  365         chn_dmaupdate(c);
  366         /* ...and feed from secondary to primary */
  367         ret = chn_wrfeed(c);
  368         /* tell the driver we've updated the primary buffer */
  369         chn_trigger(c, PCMTRIG_EMLDMAWR);
  370         DEB(if (ret)
  371                 printf("chn_wrintr: chn_wrfeed returned %d\n", ret);)
  372 }
  373 
  374 /*
  375  * user write routine - uiomove data into secondary buffer, trigger if necessary
  376  * if blocking, sleep, rinse and repeat.
  377  *
  378  * called externally, so must handle locking
  379  */
  380 
  381 int
  382 chn_write(struct pcm_channel *c, struct uio *buf)
  383 {
  384         struct snd_dbuf *bs = c->bufsoft;
  385         void *off;
  386         int ret, timeout, sz, t, p;
  387 
  388         CHN_LOCKASSERT(c);
  389 
  390         ret = 0;
  391         timeout = chn_timeout * hz;
  392 
  393         while (ret == 0 && buf->uio_resid > 0) {
  394                 sz = min(buf->uio_resid, sndbuf_getfree(bs));
  395                 if (sz > 0) {
  396                         /*
  397                          * The following assumes that the free space in
  398                          * the buffer can never be less around the
  399                          * unlock-uiomove-lock sequence.
  400                          */
  401                         while (ret == 0 && sz > 0) {
  402                                 p = sndbuf_getfreeptr(bs);
  403                                 t = min(sz, sndbuf_getsize(bs) - p);
  404                                 off = sndbuf_getbufofs(bs, p);
  405                                 CHN_UNLOCK(c);
  406                                 ret = uiomove(off, t, buf);
  407                                 CHN_LOCK(c);
  408                                 sz -= t;
  409                                 sndbuf_acquire(bs, NULL, t);
  410                         }
  411                         ret = 0;
  412                         if (CHN_STOPPED(c) && !(c->flags & CHN_F_NOTRIGGER)) {
  413                                 ret = chn_start(c, 0);
  414                                 if (ret != 0)
  415                                         c->flags |= CHN_F_DEAD;
  416                         }
  417                 } else if (c->flags & (CHN_F_NBIO | CHN_F_NOTRIGGER)) {
  418                         /**
  419                          * @todo Evaluate whether EAGAIN is truly desirable.
  420                          *       4Front drivers behave like this, but I'm
  421                          *       not sure if it at all violates the "write
  422                          *       should be allowed to block" model.
  423                          *
  424                          *       The idea is that, while set with CHN_F_NOTRIGGER,
  425                          *       a channel isn't playing, *but* without this we
  426                          *       end up with "interrupt timeout / channel dead".
  427                          */
  428                         ret = EAGAIN;
  429                 } else {
  430                         ret = chn_sleep(c, timeout);
  431                         if (ret == EAGAIN) {
  432                                 ret = EINVAL;
  433                                 c->flags |= CHN_F_DEAD;
  434                                 printf("%s: play interrupt timeout, "
  435                                     "channel dead\n", c->name);
  436                         } else if (ret == ERESTART || ret == EINTR)
  437                                 c->flags |= CHN_F_ABORTING;
  438                 }
  439         }
  440 
  441         return (ret);
  442 }
  443 
  444 /*
  445  * Feed new data from the read buffer. Can be called in the bottom half.
  446  */
  447 int
  448 chn_rdfeed(struct pcm_channel *c)
  449 {
  450         struct snd_dbuf *b = c->bufhard;
  451         struct snd_dbuf *bs = c->bufsoft;
  452         unsigned int ret, amt;
  453 
  454         CHN_LOCKASSERT(c);
  455 
  456         if (c->flags & CHN_F_MAPPED)
  457                 sndbuf_dispose(bs, NULL, sndbuf_getready(bs));
  458 
  459         amt = sndbuf_getfree(bs);
  460         ret = (amt > 0) ? sndbuf_feed(b, bs, c, c->feeder, amt) : ENOSPC;
  461 
  462         amt = sndbuf_getready(b);
  463         if (amt > 0) {
  464                 c->xruns++;
  465                 sndbuf_dispose(b, NULL, amt);
  466         }
  467 
  468         if (sndbuf_getready(bs) > 0)
  469                 chn_wakeup(c);
  470 
  471         return ret;
  472 }
  473 
  474 void
  475 chn_rdupdate(struct pcm_channel *c)
  476 {
  477         int ret;
  478 
  479         CHN_LOCKASSERT(c);
  480         KASSERT(c->direction == PCMDIR_REC, ("chn_rdupdate on bad channel"));
  481 
  482         if ((c->flags & (CHN_F_MAPPED | CHN_F_VIRTUAL)) || CHN_STOPPED(c))
  483                 return;
  484         chn_trigger(c, PCMTRIG_EMLDMARD);
  485         chn_dmaupdate(c);
  486         ret = chn_rdfeed(c);
  487         DEB(if (ret)
  488                 printf("chn_rdfeed: %d\n", ret);)
  489 
  490 }
  491 
  492 /* read interrupt routine. Must be called with interrupts blocked. */
  493 static void
  494 chn_rdintr(struct pcm_channel *c)
  495 {
  496         int ret;
  497 
  498         CHN_LOCKASSERT(c);
  499         /* tell the driver to update the primary buffer if non-dma */
  500         chn_trigger(c, PCMTRIG_EMLDMARD);
  501         /* update pointers in primary buffer */
  502         chn_dmaupdate(c);
  503         /* ...and feed from primary to secondary */
  504         ret = chn_rdfeed(c);
  505 }
  506 
  507 /*
  508  * user read routine - trigger if necessary, uiomove data from secondary buffer
  509  * if blocking, sleep, rinse and repeat.
  510  *
  511  * called externally, so must handle locking
  512  */
  513 
  514 int
  515 chn_read(struct pcm_channel *c, struct uio *buf)
  516 {
  517         struct snd_dbuf *bs = c->bufsoft;
  518         void *off;
  519         int ret, timeout, sz, t, p;
  520 
  521         CHN_LOCKASSERT(c);
  522 
  523         if (CHN_STOPPED(c) && !(c->flags & CHN_F_NOTRIGGER)) {
  524                 ret = chn_start(c, 0);
  525                 if (ret != 0) {
  526                         c->flags |= CHN_F_DEAD;
  527                         return (ret);
  528                 }
  529         }
  530 
  531         ret = 0;
  532         timeout = chn_timeout * hz;
  533 
  534         while (ret == 0 && buf->uio_resid > 0) {
  535                 sz = min(buf->uio_resid, sndbuf_getready(bs));
  536                 if (sz > 0) {
  537                         /*
  538                          * The following assumes that the free space in
  539                          * the buffer can never be less around the
  540                          * unlock-uiomove-lock sequence.
  541                          */
  542                         while (ret == 0 && sz > 0) {
  543                                 p = sndbuf_getreadyptr(bs);
  544                                 t = min(sz, sndbuf_getsize(bs) - p);
  545                                 off = sndbuf_getbufofs(bs, p);
  546                                 CHN_UNLOCK(c);
  547                                 ret = uiomove(off, t, buf);
  548                                 CHN_LOCK(c);
  549                                 sz -= t;
  550                                 sndbuf_dispose(bs, NULL, t);
  551                         }
  552                         ret = 0;
  553                 } else if (c->flags & (CHN_F_NBIO | CHN_F_NOTRIGGER))
  554                         ret = EAGAIN;
  555                 else {
  556                         ret = chn_sleep(c, timeout);
  557                         if (ret == EAGAIN) {
  558                                 ret = EINVAL;
  559                                 c->flags |= CHN_F_DEAD;
  560                                 printf("%s: record interrupt timeout, "
  561                                     "channel dead\n", c->name);
  562                         } else if (ret == ERESTART || ret == EINTR)
  563                                 c->flags |= CHN_F_ABORTING;
  564                 }
  565         }
  566 
  567         return (ret);
  568 }
  569 
  570 void
  571 chn_intr(struct pcm_channel *c)
  572 {
  573         CHN_LOCK(c);
  574         c->interrupts++;
  575         if (c->direction == PCMDIR_PLAY)
  576                 chn_wrintr(c);
  577         else
  578                 chn_rdintr(c);
  579         CHN_UNLOCK(c);
  580 }
  581 
  582 u_int32_t
  583 chn_start(struct pcm_channel *c, int force)
  584 {
  585         u_int32_t i, j;
  586         struct snd_dbuf *b = c->bufhard;
  587         struct snd_dbuf *bs = c->bufsoft;
  588         int err;
  589 
  590         CHN_LOCKASSERT(c);
  591         /* if we're running, or if we're prevented from triggering, bail */
  592         if (CHN_STARTED(c) || ((c->flags & CHN_F_NOTRIGGER) && !force))
  593                 return (EINVAL);
  594 
  595         err = 0;
  596 
  597         if (force) {
  598                 i = 1;
  599                 j = 0;
  600         } else {
  601                 if (c->direction == PCMDIR_REC) {
  602                         i = sndbuf_getfree(bs);
  603                         j = (i > 0) ? 1 : sndbuf_getready(b);
  604                 } else {
  605                         if (sndbuf_getfree(bs) == 0) {
  606                                 i = 1;
  607                                 j = 0;
  608                         } else {
  609                                 struct snd_dbuf *pb;
  610 
  611                                 pb = CHN_BUF_PARENT(c, b);
  612                                 i = sndbuf_xbytes(sndbuf_getready(bs), bs, pb);
  613                                 j = sndbuf_getbps(pb);
  614                         }
  615                 }
  616                 if (snd_verbose > 3 && CHN_EMPTY(c, children))
  617                         printf("%s: %s (%s) threshold i=%d j=%d\n",
  618                             __func__, CHN_DIRSTR(c),
  619                             (c->flags & CHN_F_VIRTUAL) ? "virtual" : "hardware",
  620                             i, j);
  621         }
  622 
  623         if (i >= j) {
  624                 c->flags |= CHN_F_TRIGGERED;
  625                 sndbuf_setrun(b, 1);
  626                 c->feedcount = (c->flags & CHN_F_CLOSING) ? 2 : 0;
  627                 c->interrupts = 0;
  628                 c->xruns = 0;
  629                 if (c->direction == PCMDIR_PLAY && c->parentchannel == NULL) {
  630                         sndbuf_fillsilence(b);
  631                         if (snd_verbose > 3)
  632                                 printf("%s: %s starting! (%s) (ready=%d "
  633                                     "force=%d i=%d j=%d intrtimeout=%u "
  634                                     "latency=%dms)\n",
  635                                     __func__,
  636                                     (c->flags & CHN_F_HAS_VCHAN) ?
  637                                     "VCHAN" : "HW",
  638                                     (c->flags & CHN_F_CLOSING) ? "closing" :
  639                                     "running",
  640                                     sndbuf_getready(b),
  641                                     force, i, j, c->timeout,
  642                                     (sndbuf_getsize(b) * 1000) /
  643                                     (sndbuf_getbps(b) * sndbuf_getspd(b)));
  644                 }
  645                 err = chn_trigger(c, PCMTRIG_START);
  646         }
  647 
  648         return (err);
  649 }
  650 
  651 void
  652 chn_resetbuf(struct pcm_channel *c)
  653 {
  654         struct snd_dbuf *b = c->bufhard;
  655         struct snd_dbuf *bs = c->bufsoft;
  656 
  657         c->blocks = 0;
  658         sndbuf_reset(b);
  659         sndbuf_reset(bs);
  660 }
  661 
  662 /*
  663  * chn_sync waits until the space in the given channel goes above
  664  * a threshold. The threshold is checked against fl or rl respectively.
  665  * Assume that the condition can become true, do not check here...
  666  */
  667 int
  668 chn_sync(struct pcm_channel *c, int threshold)
  669 {
  670         struct snd_dbuf *b, *bs;
  671         int ret, count, hcount, minflush, resid, residp, syncdelay, blksz;
  672         u_int32_t cflag;
  673 
  674         CHN_LOCKASSERT(c);
  675 
  676         if (c->direction != PCMDIR_PLAY)
  677                 return (EINVAL);
  678 
  679         bs = c->bufsoft;
  680 
  681         if ((c->flags & (CHN_F_DEAD | CHN_F_ABORTING)) ||
  682             (threshold < 1 && sndbuf_getready(bs) < 1))
  683                 return (0);
  684 
  685         /* if we haven't yet started and nothing is buffered, else start*/
  686         if (CHN_STOPPED(c)) {
  687                 if (threshold > 0 || sndbuf_getready(bs) > 0) {
  688                         ret = chn_start(c, 1);
  689                         if (ret != 0)
  690                                 return (ret);
  691                 } else
  692                         return (0);
  693         }
  694 
  695         b = CHN_BUF_PARENT(c, c->bufhard);
  696 
  697         minflush = threshold + sndbuf_xbytes(sndbuf_getready(b), b, bs);
  698 
  699         syncdelay = chn_syncdelay;
  700 
  701         if (syncdelay < 0 && (threshold > 0 || sndbuf_getready(bs) > 0))
  702                 minflush += sndbuf_xbytes(sndbuf_getsize(b), b, bs);
  703 
  704         /*
  705          * Append (0-1000) millisecond trailing buffer (if needed)
  706          * for slower / high latency hardwares (notably USB audio)
  707          * to avoid audible truncation.
  708          */
  709         if (syncdelay > 0)
  710                 minflush += (sndbuf_getbps(bs) * sndbuf_getspd(bs) *
  711                     ((syncdelay > 1000) ? 1000 : syncdelay)) / 1000;
  712 
  713         minflush -= minflush % sndbuf_getbps(bs);
  714 
  715         if (minflush > 0) {
  716                 threshold = min(minflush, sndbuf_getfree(bs));
  717                 sndbuf_clear(bs, threshold);
  718                 sndbuf_acquire(bs, NULL, threshold);
  719                 minflush -= threshold;
  720         }
  721 
  722         resid = sndbuf_getready(bs);
  723         residp = resid;
  724         blksz = sndbuf_getblksz(b);
  725         if (blksz < 1) {
  726                 printf("%s: WARNING: blksz < 1 ! maxsize=%d [%d/%d/%d]\n",
  727                     __func__, sndbuf_getmaxsize(b), sndbuf_getsize(b),
  728                     sndbuf_getblksz(b), sndbuf_getblkcnt(b));
  729                 if (sndbuf_getblkcnt(b) > 0)
  730                         blksz = sndbuf_getsize(b) / sndbuf_getblkcnt(b);
  731                 if (blksz < 1)
  732                         blksz = 1;
  733         }
  734         count = sndbuf_xbytes(minflush + resid, bs, b) / blksz;
  735         hcount = count;
  736         ret = 0;
  737 
  738         if (snd_verbose > 3)
  739                 printf("%s: [begin] timeout=%d count=%d "
  740                     "minflush=%d resid=%d\n", __func__, c->timeout, count,
  741                     minflush, resid);
  742 
  743         cflag = c->flags & CHN_F_CLOSING;
  744         c->flags |= CHN_F_CLOSING;
  745         while (count > 0 && (resid > 0 || minflush > 0)) {
  746                 ret = chn_sleep(c, c->timeout);
  747                 if (ret == ERESTART || ret == EINTR) {
  748                         c->flags |= CHN_F_ABORTING;
  749                         break;
  750                 } else if (ret == 0 || ret == EAGAIN) {
  751                         resid = sndbuf_getready(bs);
  752                         if (resid == residp) {
  753                                 --count;
  754                                 if (snd_verbose > 3)
  755                                         printf("%s: [stalled] timeout=%d "
  756                                             "count=%d hcount=%d "
  757                                             "resid=%d minflush=%d\n",
  758                                             __func__, c->timeout, count,
  759                                             hcount, resid, minflush);
  760                         } else if (resid < residp && count < hcount) {
  761                                 ++count;
  762                                 if (snd_verbose > 3)
  763                                         printf("%s: [resume] timeout=%d "
  764                                             "count=%d hcount=%d "
  765                                             "resid=%d minflush=%d\n",
  766                                             __func__, c->timeout, count,
  767                                             hcount, resid, minflush);
  768                         }
  769                         if (minflush > 0 && sndbuf_getfree(bs) > 0) {
  770                                 threshold = min(minflush,
  771                                     sndbuf_getfree(bs));
  772                                 sndbuf_clear(bs, threshold);
  773                                 sndbuf_acquire(bs, NULL, threshold);
  774                                 resid = sndbuf_getready(bs);
  775                                 minflush -= threshold;
  776                         }
  777                         residp = resid;
  778                 } else
  779                         break;
  780         }
  781         c->flags &= ~CHN_F_CLOSING;
  782         c->flags |= cflag;
  783 
  784         if (snd_verbose > 3)
  785                 printf("%s: timeout=%d count=%d hcount=%d resid=%d residp=%d "
  786                     "minflush=%d ret=%d\n",
  787                     __func__, c->timeout, count, hcount, resid, residp,
  788                     minflush, ret);
  789 
  790         return (0);
  791 }
  792 
  793 /* called externally, handle locking */
  794 int
  795 chn_poll(struct pcm_channel *c, int ev, struct thread *td)
  796 {
  797         struct snd_dbuf *bs = c->bufsoft;
  798         int ret;
  799 
  800         CHN_LOCKASSERT(c);
  801         if (!(c->flags & (CHN_F_MAPPED | CHN_F_TRIGGERED))) {
  802                 ret = chn_start(c, 1);
  803                 if (ret != 0)
  804                         return (0);
  805         }
  806         ret = 0;
  807         if (chn_polltrigger(c) && chn_pollreset(c))
  808                 ret = ev;
  809         else
  810                 selrecord(td, sndbuf_getsel(bs));
  811         return (ret);
  812 }
  813 
  814 /*
  815  * chn_abort terminates a running dma transfer.  it may sleep up to 200ms.
  816  * it returns the number of bytes that have not been transferred.
  817  *
  818  * called from: dsp_close, dsp_ioctl, with channel locked
  819  */
  820 int
  821 chn_abort(struct pcm_channel *c)
  822 {
  823         int missing = 0;
  824         struct snd_dbuf *b = c->bufhard;
  825         struct snd_dbuf *bs = c->bufsoft;
  826 
  827         CHN_LOCKASSERT(c);
  828         if (CHN_STOPPED(c))
  829                 return 0;
  830         c->flags |= CHN_F_ABORTING;
  831 
  832         c->flags &= ~CHN_F_TRIGGERED;
  833         /* kill the channel */
  834         chn_trigger(c, PCMTRIG_ABORT);
  835         sndbuf_setrun(b, 0);
  836         if (!(c->flags & CHN_F_VIRTUAL))
  837                 chn_dmaupdate(c);
  838         missing = sndbuf_getready(bs);
  839 
  840         c->flags &= ~CHN_F_ABORTING;
  841         return missing;
  842 }
  843 
  844 /*
  845  * this routine tries to flush the dma transfer. It is called
  846  * on a close of a playback channel.
  847  * first, if there is data in the buffer, but the dma has not yet
  848  * begun, we need to start it.
  849  * next, we wait for the play buffer to drain
  850  * finally, we stop the dma.
  851  *
  852  * called from: dsp_close, not valid for record channels.
  853  */
  854 
  855 int
  856 chn_flush(struct pcm_channel *c)
  857 {
  858         struct snd_dbuf *b = c->bufhard;
  859 
  860         CHN_LOCKASSERT(c);
  861         KASSERT(c->direction == PCMDIR_PLAY, ("chn_flush on bad channel"));
  862         DEB(printf("chn_flush: c->flags 0x%08x\n", c->flags));
  863 
  864         c->flags |= CHN_F_CLOSING;
  865         chn_sync(c, 0);
  866         c->flags &= ~CHN_F_TRIGGERED;
  867         /* kill the channel */
  868         chn_trigger(c, PCMTRIG_ABORT);
  869         sndbuf_setrun(b, 0);
  870 
  871         c->flags &= ~CHN_F_CLOSING;
  872         return 0;
  873 }
  874 
  875 int
  876 fmtvalid(u_int32_t fmt, u_int32_t *fmtlist)
  877 {
  878         int i;
  879 
  880         for (i = 0; fmtlist[i]; i++)
  881                 if (fmt == fmtlist[i])
  882                         return 1;
  883         return 0;
  884 }
  885 
  886 static struct afmtstr_table default_afmtstr_table[] = {
  887         {  "alaw", AFMT_A_LAW  }, { "mulaw", AFMT_MU_LAW },
  888         {    "u8", AFMT_U8     }, {    "s8", AFMT_S8     },
  889         { "s16le", AFMT_S16_LE }, { "s16be", AFMT_S16_BE },
  890         { "u16le", AFMT_U16_LE }, { "u16be", AFMT_U16_BE },
  891         { "s24le", AFMT_S24_LE }, { "s24be", AFMT_S24_BE },
  892         { "u24le", AFMT_U24_LE }, { "u24be", AFMT_U24_BE },
  893         { "s32le", AFMT_S32_LE }, { "s32be", AFMT_S32_BE },
  894         { "u32le", AFMT_U32_LE }, { "u32be", AFMT_U32_BE },
  895         {    NULL, 0           },
  896 };
  897 
  898 int
  899 afmtstr_swap_sign(char *s)
  900 {
  901         if (s == NULL || strlen(s) < 2) /* full length of "s8" */
  902                 return 0;
  903         if (*s == 's')
  904                 *s = 'u';
  905         else if (*s == 'u')
  906                 *s = 's';
  907         else
  908                 return 0;
  909         return 1;
  910 }
  911 
  912 int
  913 afmtstr_swap_endian(char *s)
  914 {
  915         if (s == NULL || strlen(s) < 5) /* full length of "s16le" */
  916                 return 0;
  917         if (s[3] == 'l')
  918                 s[3] = 'b';
  919         else if (s[3] == 'b')
  920                 s[3] = 'l';
  921         else
  922                 return 0;
  923         return 1;
  924 }
  925 
  926 u_int32_t
  927 afmtstr2afmt(struct afmtstr_table *tbl, const char *s, int stereo)
  928 {
  929         size_t fsz, sz;
  930 
  931         sz = (s == NULL) ? 0 : strlen(s);
  932 
  933         if (sz > 1) {
  934 
  935                 if (tbl == NULL)
  936                         tbl = default_afmtstr_table;
  937 
  938                 for (; tbl->fmtstr != NULL; tbl++) {
  939                         fsz = strlen(tbl->fmtstr);
  940                         if (sz < fsz)
  941                                 continue;
  942                         if (strncmp(s, tbl->fmtstr, fsz) != 0)
  943                                 continue;
  944                         if (fsz == sz)
  945                                 return tbl->format |
  946                                             ((stereo) ? AFMT_STEREO : 0);
  947                         if ((sz - fsz) < 2 || s[fsz] != ':')
  948                                 break;
  949                         /*
  950                          * For now, just handle mono/stereo.
  951                          */
  952                         if ((s[fsz + 2] == '\0' && (s[fsz + 1] == 'm' ||
  953                                     s[fsz + 1] == '1')) ||
  954                                     strcmp(s + fsz + 1, "mono") == 0)
  955                                 return tbl->format;
  956                         if ((s[fsz + 2] == '\0' && (s[fsz + 1] == 's' ||
  957                                     s[fsz + 1] == '2')) ||
  958                                     strcmp(s + fsz + 1, "stereo") == 0)
  959                                 return tbl->format | AFMT_STEREO;
  960                         break;
  961                 }
  962         }
  963 
  964         return 0;
  965 }
  966 
  967 u_int32_t
  968 afmt2afmtstr(struct afmtstr_table *tbl, u_int32_t afmt, char *dst,
  969                                         size_t len, int type, int stereo)
  970 {
  971         u_int32_t fmt = 0;
  972         char *fmtstr = NULL, *tag = "";
  973 
  974         if (tbl == NULL)
  975                 tbl = default_afmtstr_table;
  976 
  977         for (; tbl->format != 0; tbl++) {
  978                 if (tbl->format == 0)
  979                         break;
  980                 if ((afmt & ~AFMT_STEREO) != tbl->format)
  981                         continue;
  982                 fmt = afmt;
  983                 fmtstr = tbl->fmtstr;
  984                 break;
  985         }
  986 
  987         if (fmt != 0 && fmtstr != NULL && dst != NULL && len > 0) {
  988                 strlcpy(dst, fmtstr, len);
  989                 switch (type) {
  990                 case AFMTSTR_SIMPLE:
  991                         tag = (fmt & AFMT_STEREO) ? ":s" : ":m";
  992                         break;
  993                 case AFMTSTR_NUM:
  994                         tag = (fmt & AFMT_STEREO) ? ":2" : ":1";
  995                         break;
  996                 case AFMTSTR_FULL:
  997                         tag = (fmt & AFMT_STEREO) ? ":stereo" : ":mono";
  998                         break;
  999                 case AFMTSTR_NONE:
 1000                 default:
 1001                         break;
 1002                 }
 1003                 if (strlen(tag) > 0 && ((stereo && !(fmt & AFMT_STEREO)) || \
 1004                             (!stereo && (fmt & AFMT_STEREO))))
 1005                         strlcat(dst, tag, len);
 1006         }
 1007 
 1008         return fmt;
 1009 }
 1010 
 1011 int
 1012 chn_reset(struct pcm_channel *c, u_int32_t fmt)
 1013 {
 1014         int hwspd, r;
 1015 
 1016         CHN_LOCKASSERT(c);
 1017         c->feedcount = 0;
 1018         c->flags &= CHN_F_RESET;
 1019         c->interrupts = 0;
 1020         c->timeout = 1;
 1021         c->xruns = 0;
 1022 
 1023         r = CHANNEL_RESET(c->methods, c->devinfo);
 1024         if (fmt != 0) {
 1025 #if 0
 1026                 hwspd = DSP_DEFAULT_SPEED;
 1027                 /* only do this on a record channel until feederbuilder works */
 1028                 if (c->direction == PCMDIR_REC)
 1029                         RANGE(hwspd, chn_getcaps(c)->minspeed, chn_getcaps(c)->maxspeed);
 1030                 c->speed = hwspd;
 1031 #endif
 1032                 hwspd = chn_getcaps(c)->minspeed;
 1033                 c->speed = hwspd;
 1034 
 1035                 if (r == 0)
 1036                         r = chn_setformat(c, fmt);
 1037                 if (r == 0)
 1038                         r = chn_setspeed(c, hwspd);
 1039 #if 0
 1040                 if (r == 0)
 1041                         r = chn_setvolume(c, 100, 100);
 1042 #endif
 1043         }
 1044         if (r == 0)
 1045                 r = chn_setlatency(c, chn_latency);
 1046         if (r == 0) {
 1047                 chn_resetbuf(c);
 1048                 r = CHANNEL_RESETDONE(c->methods, c->devinfo);
 1049         }
 1050         return r;
 1051 }
 1052 
 1053 int
 1054 chn_init(struct pcm_channel *c, void *devinfo, int dir, int direction)
 1055 {
 1056         struct feeder_class *fc;
 1057         struct snd_dbuf *b, *bs;
 1058         int ret;
 1059 
 1060         if (chn_timeout < CHN_TIMEOUT_MIN || chn_timeout > CHN_TIMEOUT_MAX)
 1061                 chn_timeout = CHN_TIMEOUT;
 1062 
 1063         chn_lockinit(c, dir);
 1064 
 1065         b = NULL;
 1066         bs = NULL;
 1067         CHN_INIT(c, children);
 1068         CHN_INIT(c, children.busy);
 1069         c->devinfo = NULL;
 1070         c->feeder = NULL;
 1071         c->latency = -1;
 1072         c->timeout = 1;
 1073 
 1074         ret = ENOMEM;
 1075         b = sndbuf_create(c->dev, c->name, "primary", c);
 1076         if (b == NULL)
 1077                 goto out;
 1078         bs = sndbuf_create(c->dev, c->name, "secondary", c);
 1079         if (bs == NULL)
 1080                 goto out;
 1081 
 1082         CHN_LOCK(c);
 1083 
 1084         ret = EINVAL;
 1085         fc = feeder_getclass(NULL);
 1086         if (fc == NULL)
 1087                 goto out;
 1088         if (chn_addfeeder(c, fc, NULL))
 1089                 goto out;
 1090 
 1091         /*
 1092          * XXX - sndbuf_setup() & sndbuf_resize() expect to be called
 1093          *       with the channel unlocked because they are also called
 1094          *       from driver methods that don't know about locking
 1095          */
 1096         CHN_UNLOCK(c);
 1097         sndbuf_setup(bs, NULL, 0);
 1098         CHN_LOCK(c);
 1099         c->bufhard = b;
 1100         c->bufsoft = bs;
 1101         c->flags = 0;
 1102         c->feederflags = 0;
 1103         c->sm = NULL;
 1104 
 1105         ret = ENODEV;
 1106         CHN_UNLOCK(c); /* XXX - Unlock for CHANNEL_INIT() malloc() call */
 1107         c->devinfo = CHANNEL_INIT(c->methods, devinfo, b, c, direction);
 1108         CHN_LOCK(c);
 1109         if (c->devinfo == NULL)
 1110                 goto out;
 1111 
 1112         ret = ENOMEM;
 1113         if ((sndbuf_getsize(b) == 0) && ((c->flags & CHN_F_VIRTUAL) == 0))
 1114                 goto out;
 1115 
 1116         ret = chn_setdir(c, direction);
 1117         if (ret)
 1118                 goto out;
 1119 
 1120         ret = sndbuf_setfmt(b, AFMT_U8);
 1121         if (ret)
 1122                 goto out;
 1123 
 1124         ret = sndbuf_setfmt(bs, AFMT_U8);
 1125         if (ret)
 1126                 goto out;
 1127 
 1128         /**
 1129          * @todo Should this be moved somewhere else?  The primary buffer
 1130          *       is allocated by the driver or via DMA map setup, and tmpbuf
 1131          *       seems to only come into existence in sndbuf_resize().
 1132          */
 1133         if (c->direction == PCMDIR_PLAY) {
 1134                 bs->sl = sndbuf_getmaxsize(bs);
 1135                 bs->shadbuf = malloc(bs->sl, M_DEVBUF, M_NOWAIT);
 1136                 if (bs->shadbuf == NULL) {
 1137                         ret = ENOMEM;
 1138                         goto out;
 1139                 }
 1140         }
 1141 
 1142 out:
 1143         CHN_UNLOCK(c);
 1144         if (ret) {
 1145                 if (c->devinfo) {
 1146                         if (CHANNEL_FREE(c->methods, c->devinfo))
 1147                                 sndbuf_free(b);
 1148                 }
 1149                 if (bs)
 1150                         sndbuf_destroy(bs);
 1151                 if (b)
 1152                         sndbuf_destroy(b);
 1153                 CHN_LOCK(c);
 1154                 c->flags |= CHN_F_DEAD;
 1155                 chn_lockdestroy(c);
 1156 
 1157                 return ret;
 1158         }
 1159 
 1160         return 0;
 1161 }
 1162 
 1163 int
 1164 chn_kill(struct pcm_channel *c)
 1165 {
 1166         struct snd_dbuf *b = c->bufhard;
 1167         struct snd_dbuf *bs = c->bufsoft;
 1168 
 1169         if (CHN_STARTED(c)) {
 1170                 CHN_LOCK(c);
 1171                 chn_trigger(c, PCMTRIG_ABORT);
 1172                 CHN_UNLOCK(c);
 1173         }
 1174         while (chn_removefeeder(c) == 0)
 1175                 ;
 1176         if (CHANNEL_FREE(c->methods, c->devinfo))
 1177                 sndbuf_free(b);
 1178         sndbuf_destroy(bs);
 1179         sndbuf_destroy(b);
 1180         CHN_LOCK(c);
 1181         c->flags |= CHN_F_DEAD;
 1182         chn_lockdestroy(c);
 1183 
 1184         return (0);
 1185 }
 1186 
 1187 int
 1188 chn_setdir(struct pcm_channel *c, int dir)
 1189 {
 1190 #ifdef DEV_ISA
 1191         struct snd_dbuf *b = c->bufhard;
 1192 #endif
 1193         int r;
 1194 
 1195         CHN_LOCKASSERT(c);
 1196         c->direction = dir;
 1197         r = CHANNEL_SETDIR(c->methods, c->devinfo, c->direction);
 1198 #ifdef DEV_ISA
 1199         if (!r && SND_DMA(b))
 1200                 sndbuf_dmasetdir(b, c->direction);
 1201 #endif
 1202         return r;
 1203 }
 1204 
 1205 int
 1206 chn_setvolume(struct pcm_channel *c, int left, int right)
 1207 {
 1208         CHN_LOCKASSERT(c);
 1209         /* should add a feeder for volume changing if channel returns -1 */
 1210         if (left > 100)
 1211                 left = 100;
 1212         if (left < 0)
 1213                 left = 0;
 1214         if (right > 100)
 1215                 right = 100;
 1216         if (right < 0)
 1217                 right = 0;
 1218         c->volume = left | (right << 8);
 1219         return 0;
 1220 }
 1221 
 1222 static u_int32_t
 1223 round_pow2(u_int32_t v)
 1224 {
 1225         u_int32_t ret;
 1226 
 1227         if (v < 2)
 1228                 v = 2;
 1229         ret = 0;
 1230         while (v >> ret)
 1231                 ret++;
 1232         ret = 1 << (ret - 1);
 1233         while (ret < v)
 1234                 ret <<= 1;
 1235         return ret;
 1236 }
 1237 
 1238 static u_int32_t
 1239 round_blksz(u_int32_t v, int round)
 1240 {
 1241         u_int32_t ret, tmp;
 1242 
 1243         if (round < 1)
 1244                 round = 1;
 1245 
 1246         ret = min(round_pow2(v), CHN_2NDBUFMAXSIZE >> 1);
 1247 
 1248         if (ret > v && (ret >> 1) > 0 && (ret >> 1) >= ((v * 3) >> 2))
 1249                 ret >>= 1;
 1250 
 1251         tmp = ret - (ret % round);
 1252         while (tmp < 16 || tmp < round) {
 1253                 ret <<= 1;
 1254                 tmp = ret - (ret % round);
 1255         }
 1256 
 1257         return ret;
 1258 }
 1259 
 1260 /*
 1261  * 4Front call it DSP Policy, while we call it "Latency Profile". The idea
 1262  * is to keep 2nd buffer short so that it doesn't cause long queue during
 1263  * buffer transfer.
 1264  *
 1265  *    Latency reference table for 48khz stereo 16bit: (PLAY)
 1266  *
 1267  *      +---------+------------+-----------+------------+
 1268  *      | Latency | Blockcount | Blocksize | Buffersize |
 1269  *      +---------+------------+-----------+------------+
 1270  *      |     0   |       2    |   64      |    128     |
 1271  *      +---------+------------+-----------+------------+
 1272  *      |     1   |       4    |   128     |    512     |
 1273  *      +---------+------------+-----------+------------+
 1274  *      |     2   |       8    |   512     |    4096    |
 1275  *      +---------+------------+-----------+------------+
 1276  *      |     3   |      16    |   512     |    8192    |
 1277  *      +---------+------------+-----------+------------+
 1278  *      |     4   |      32    |   512     |    16384   |
 1279  *      +---------+------------+-----------+------------+
 1280  *      |     5   |      32    |   1024    |    32768   |
 1281  *      +---------+------------+-----------+------------+
 1282  *      |     6   |      16    |   2048    |    32768   |
 1283  *      +---------+------------+-----------+------------+
 1284  *      |     7   |       8    |   4096    |    32768   |
 1285  *      +---------+------------+-----------+------------+
 1286  *      |     8   |       4    |   8192    |    32768   |
 1287  *      +---------+------------+-----------+------------+
 1288  *      |     9   |       2    |   16384   |    32768   |
 1289  *      +---------+------------+-----------+------------+
 1290  *      |    10   |       2    |   32768   |    65536   |
 1291  *      +---------+------------+-----------+------------+
 1292  *
 1293  * Recording need a different reference table. All we care is
 1294  * gobbling up everything within reasonable buffering threshold.
 1295  *
 1296  *    Latency reference table for 48khz stereo 16bit: (REC)
 1297  *
 1298  *      +---------+------------+-----------+------------+
 1299  *      | Latency | Blockcount | Blocksize | Buffersize |
 1300  *      +---------+------------+-----------+------------+
 1301  *      |     0   |     512    |   32      |    16384   |
 1302  *      +---------+------------+-----------+------------+
 1303  *      |     1   |     256    |   64      |    16384   |
 1304  *      +---------+------------+-----------+------------+
 1305  *      |     2   |     128    |   128     |    16384   |
 1306  *      +---------+------------+-----------+------------+
 1307  *      |     3   |      64    |   256     |    16384   |
 1308  *      +---------+------------+-----------+------------+
 1309  *      |     4   |      32    |   512     |    16384   |
 1310  *      +---------+------------+-----------+------------+
 1311  *      |     5   |      32    |   1024    |    32768   |
 1312  *      +---------+------------+-----------+------------+
 1313  *      |     6   |      16    |   2048    |    32768   |
 1314  *      +---------+------------+-----------+------------+
 1315  *      |     7   |       8    |   4096    |    32768   |
 1316  *      +---------+------------+-----------+------------+
 1317  *      |     8   |       4    |   8192    |    32768   |
 1318  *      +---------+------------+-----------+------------+
 1319  *      |     9   |       2    |   16384   |    32768   |
 1320  *      +---------+------------+-----------+------------+
 1321  *      |    10   |       2    |   32768   |    65536   |
 1322  *      +---------+------------+-----------+------------+
 1323  *
 1324  * Calculations for other data rate are entirely based on these reference
 1325  * tables. For normal operation, Latency 5 seems give the best, well
 1326  * balanced performance for typical workload. Anything below 5 will
 1327  * eat up CPU to keep up with increasing context switches because of
 1328  * shorter buffer space and usually require the application to handle it
 1329  * aggresively through possibly real time programming technique.
 1330  *
 1331  */
 1332 #define CHN_LATENCY_PBLKCNT_REF                         \
 1333         {{1, 2, 3, 4, 5, 5, 4, 3, 2, 1, 1},             \
 1334         {1, 2, 3, 4, 5, 5, 4, 3, 2, 1, 1}}
 1335 #define CHN_LATENCY_PBUFSZ_REF                          \
 1336         {{7, 9, 12, 13, 14, 15, 15, 15, 15, 15, 16},    \
 1337         {11, 12, 13, 14, 15, 16, 16, 16, 16, 16, 17}}
 1338 
 1339 #define CHN_LATENCY_RBLKCNT_REF                         \
 1340         {{9, 8, 7, 6, 5, 5, 4, 3, 2, 1, 1},             \
 1341         {9, 8, 7, 6, 5, 5, 4, 3, 2, 1, 1}}
 1342 #define CHN_LATENCY_RBUFSZ_REF                          \
 1343         {{14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 16},  \
 1344         {15, 15, 15, 15, 15, 16, 16, 16, 16, 16, 17}}
 1345 
 1346 #define CHN_LATENCY_DATA_REF    192000 /* 48khz stereo 16bit ~ 48000 x 2 x 2 */
 1347 
 1348 static int
 1349 chn_calclatency(int dir, int latency, int bps, u_int32_t datarate,
 1350                                 u_int32_t max, int *rblksz, int *rblkcnt)
 1351 {
 1352         static int pblkcnts[CHN_LATENCY_PROFILE_MAX + 1][CHN_LATENCY_MAX + 1] =
 1353             CHN_LATENCY_PBLKCNT_REF;
 1354         static int  pbufszs[CHN_LATENCY_PROFILE_MAX + 1][CHN_LATENCY_MAX + 1] =
 1355             CHN_LATENCY_PBUFSZ_REF;
 1356         static int rblkcnts[CHN_LATENCY_PROFILE_MAX + 1][CHN_LATENCY_MAX + 1] =
 1357             CHN_LATENCY_RBLKCNT_REF;
 1358         static int  rbufszs[CHN_LATENCY_PROFILE_MAX + 1][CHN_LATENCY_MAX + 1] =
 1359             CHN_LATENCY_RBUFSZ_REF;
 1360         u_int32_t bufsz;
 1361         int lprofile, blksz, blkcnt;
 1362 
 1363         if (latency < CHN_LATENCY_MIN || latency > CHN_LATENCY_MAX ||
 1364             bps < 1 || datarate < 1 ||
 1365             !(dir == PCMDIR_PLAY || dir == PCMDIR_REC)) {
 1366                 if (rblksz != NULL)
 1367                         *rblksz = CHN_2NDBUFMAXSIZE >> 1;
 1368                 if (rblkcnt != NULL)
 1369                         *rblkcnt = 2;
 1370                 printf("%s: FAILED dir=%d latency=%d bps=%d "
 1371                     "datarate=%u max=%u\n",
 1372                     __func__, dir, latency, bps, datarate, max);
 1373                 return CHN_2NDBUFMAXSIZE;
 1374         }
 1375 
 1376         lprofile = chn_latency_profile;
 1377 
 1378         if (dir == PCMDIR_PLAY) {
 1379                 blkcnt = pblkcnts[lprofile][latency];
 1380                 bufsz = pbufszs[lprofile][latency];
 1381         } else {
 1382                 blkcnt = rblkcnts[lprofile][latency];
 1383                 bufsz = rbufszs[lprofile][latency];
 1384         }
 1385 
 1386         bufsz = round_pow2(snd_xbytes(1 << bufsz, CHN_LATENCY_DATA_REF,
 1387             datarate));
 1388         if (bufsz > max)
 1389                 bufsz = max;
 1390         blksz = round_blksz(bufsz >> blkcnt, bps);
 1391 
 1392         if (rblksz != NULL)
 1393                 *rblksz = blksz;
 1394         if (rblkcnt != NULL)
 1395                 *rblkcnt = 1 << blkcnt;
 1396 
 1397         return blksz << blkcnt;
 1398 }
 1399 
 1400 static int
 1401 chn_resizebuf(struct pcm_channel *c, int latency,
 1402                                         int blkcnt, int blksz)
 1403 {
 1404         struct snd_dbuf *b, *bs, *pb;
 1405         int sblksz, sblkcnt, hblksz, hblkcnt, limit = 1;
 1406         int ret;
 1407 
 1408         CHN_LOCKASSERT(c);
 1409 
 1410         if ((c->flags & (CHN_F_MAPPED | CHN_F_TRIGGERED)) ||
 1411             !(c->direction == PCMDIR_PLAY || c->direction == PCMDIR_REC))
 1412                 return EINVAL;
 1413 
 1414         if (latency == -1) {
 1415                 c->latency = -1;
 1416                 latency = chn_latency;
 1417         } else if (latency == -2) {
 1418                 latency = c->latency;
 1419                 if (latency < CHN_LATENCY_MIN || latency > CHN_LATENCY_MAX)
 1420                         latency = chn_latency;
 1421         } else if (latency < CHN_LATENCY_MIN || latency > CHN_LATENCY_MAX)
 1422                 return EINVAL;
 1423         else {
 1424                 c->latency = latency;
 1425                 limit = 0;
 1426         }
 1427 
 1428         bs = c->bufsoft;
 1429         b = c->bufhard;
 1430 
 1431         if (!(blksz == 0 || blkcnt == -1) &&
 1432             (blksz < 16 || blksz < sndbuf_getbps(bs) || blkcnt < 2 ||
 1433             (blksz * blkcnt) > CHN_2NDBUFMAXSIZE))
 1434                 return EINVAL;
 1435 
 1436         chn_calclatency(c->direction, latency, sndbuf_getbps(bs),
 1437             sndbuf_getbps(bs) * sndbuf_getspd(bs), CHN_2NDBUFMAXSIZE,
 1438             &sblksz, &sblkcnt);
 1439 
 1440         if (blksz == 0 || blkcnt == -1) {
 1441                 if (blkcnt == -1)
 1442                         c->flags &= ~CHN_F_HAS_SIZE;
 1443                 if (c->flags & CHN_F_HAS_SIZE) {
 1444                         blksz = sndbuf_getblksz(bs);
 1445                         blkcnt = sndbuf_getblkcnt(bs);
 1446                 }
 1447         } else
 1448                 c->flags |= CHN_F_HAS_SIZE;
 1449 
 1450         if (c->flags & CHN_F_HAS_SIZE) {
 1451                 /*
 1452                  * The application has requested their own blksz/blkcnt.
 1453                  * Just obey with it, and let them toast alone. We can
 1454                  * clamp it to the nearest latency profile, but that would
 1455                  * defeat the purpose of having custom control. The least
 1456                  * we can do is round it to the nearest ^2 and align it.
 1457                  */
 1458                 sblksz = round_blksz(blksz, sndbuf_getbps(bs));
 1459                 sblkcnt = round_pow2(blkcnt);
 1460                 limit = 0;
 1461         }
 1462 
 1463         if (c->parentchannel != NULL) {
 1464                 pb = CHN_BUF_PARENT(c, NULL);
 1465                 CHN_UNLOCK(c);
 1466                 CHN_LOCK(c->parentchannel);
 1467                 chn_notify(c->parentchannel, CHN_N_BLOCKSIZE);
 1468                 CHN_UNLOCK(c->parentchannel);
 1469                 CHN_LOCK(c);
 1470                 limit = (limit != 0 && pb != NULL) ?
 1471                     sndbuf_xbytes(sndbuf_getsize(pb), pb, bs) : 0;
 1472                 c->timeout = c->parentchannel->timeout;
 1473         } else {
 1474                 hblkcnt = 2;
 1475                 if (c->flags & CHN_F_HAS_SIZE) {
 1476                         hblksz = round_blksz(sndbuf_xbytes(sblksz, bs, b),
 1477                             sndbuf_getbps(b));
 1478                         hblkcnt = round_pow2(sndbuf_getblkcnt(bs));
 1479                 } else
 1480                         chn_calclatency(c->direction, latency,
 1481                             sndbuf_getbps(b),
 1482                             sndbuf_getbps(b) * sndbuf_getspd(b),
 1483                             CHN_2NDBUFMAXSIZE, &hblksz, &hblkcnt);
 1484 
 1485                 if ((hblksz << 1) > sndbuf_getmaxsize(b))
 1486                         hblksz = round_blksz(sndbuf_getmaxsize(b) >> 1,
 1487                             sndbuf_getbps(b));
 1488 
 1489                 while ((hblksz * hblkcnt) > sndbuf_getmaxsize(b)) {
 1490                         if (hblkcnt < 4)
 1491                                 hblksz >>= 1;
 1492                         else
 1493                                 hblkcnt >>= 1;
 1494                 }
 1495 
 1496                 hblksz -= hblksz % sndbuf_getbps(b);
 1497 
 1498 #if 0
 1499                 hblksz = sndbuf_getmaxsize(b) >> 1;
 1500                 hblksz -= hblksz % sndbuf_getbps(b);
 1501                 hblkcnt = 2;
 1502 #endif
 1503 
 1504                 CHN_UNLOCK(c);
 1505                 if (chn_usefrags == 0 ||
 1506                     CHANNEL_SETFRAGMENTS(c->methods, c->devinfo,
 1507                     hblksz, hblkcnt) < 1)
 1508                         sndbuf_setblksz(b, CHANNEL_SETBLOCKSIZE(c->methods,
 1509                             c->devinfo, hblksz));
 1510                 CHN_LOCK(c);
 1511 
 1512                 if (!CHN_EMPTY(c, children)) {
 1513                         sblksz = round_blksz(
 1514                             sndbuf_xbytes(sndbuf_getsize(b) >> 1, b, bs),
 1515                             sndbuf_getbps(bs));
 1516                         sblkcnt = 2;
 1517                         limit = 0;
 1518                 } else if (limit != 0)
 1519                         limit = sndbuf_xbytes(sndbuf_getsize(b), b, bs);
 1520 
 1521                 /*
 1522                  * Interrupt timeout
 1523                  */
 1524                 c->timeout = ((u_int64_t)hz * sndbuf_getsize(b)) /
 1525                     ((u_int64_t)sndbuf_getspd(b) * sndbuf_getbps(b));
 1526                 if (c->timeout < 1)
 1527                         c->timeout = 1;
 1528         }
 1529 
 1530         if (limit > CHN_2NDBUFMAXSIZE)
 1531                 limit = CHN_2NDBUFMAXSIZE;
 1532 
 1533 #if 0
 1534         while (limit > 0 && (sblksz * sblkcnt) > limit) {
 1535                 if (sblkcnt < 4)
 1536                         break;
 1537                 sblkcnt >>= 1;
 1538         }
 1539 #endif
 1540 
 1541         while ((sblksz * sblkcnt) < limit)
 1542                 sblkcnt <<= 1;
 1543 
 1544         while ((sblksz * sblkcnt) > CHN_2NDBUFMAXSIZE) {
 1545                 if (sblkcnt < 4)
 1546                         sblksz >>= 1;
 1547                 else
 1548                         sblkcnt >>= 1;
 1549         }
 1550 
 1551         sblksz -= sblksz % sndbuf_getbps(bs);
 1552 
 1553         if (sndbuf_getblkcnt(bs) != sblkcnt || sndbuf_getblksz(bs) != sblksz ||
 1554             sndbuf_getsize(bs) != (sblkcnt * sblksz)) {
 1555                 ret = sndbuf_remalloc(bs, sblkcnt, sblksz);
 1556                 if (ret != 0) {
 1557                         printf("%s: Failed: %d %d\n", __func__,
 1558                             sblkcnt, sblksz);
 1559                         return ret;
 1560                 }
 1561         }
 1562 
 1563         /*
 1564          * OSSv4 docs: "By default OSS will set the low water level equal
 1565          * to the fragment size which is optimal in most cases."
 1566          */
 1567         c->lw = sndbuf_getblksz(bs);
 1568         chn_resetbuf(c);
 1569 
 1570         if (snd_verbose > 3)
 1571                 printf("%s: %s (%s) timeout=%u "
 1572                     "b[%d/%d/%d] bs[%d/%d/%d] limit=%d\n",
 1573                     __func__, CHN_DIRSTR(c),
 1574                     (c->flags & CHN_F_VIRTUAL) ? "virtual" : "hardware",
 1575                     c->timeout,
 1576                     sndbuf_getsize(b), sndbuf_getblksz(b),
 1577                     sndbuf_getblkcnt(b),
 1578                     sndbuf_getsize(bs), sndbuf_getblksz(bs),
 1579                     sndbuf_getblkcnt(bs), limit);
 1580 
 1581         return 0;
 1582 }
 1583 
 1584 int
 1585 chn_setlatency(struct pcm_channel *c, int latency)
 1586 {
 1587         CHN_LOCKASSERT(c);
 1588         /* Destroy blksz/blkcnt, enforce latency profile. */
 1589         return chn_resizebuf(c, latency, -1, 0);
 1590 }
 1591 
 1592 int
 1593 chn_setblocksize(struct pcm_channel *c, int blkcnt, int blksz)
 1594 {
 1595         CHN_LOCKASSERT(c);
 1596         /* Destroy latency profile, enforce blksz/blkcnt */
 1597         return chn_resizebuf(c, -1, blkcnt, blksz);
 1598 }
 1599 
 1600 static int
 1601 chn_tryspeed(struct pcm_channel *c, int speed)
 1602 {
 1603         struct pcm_feeder *f;
 1604         struct snd_dbuf *b = c->bufhard;
 1605         struct snd_dbuf *bs = c->bufsoft;
 1606         struct snd_dbuf *x;
 1607         int r, delta;
 1608 
 1609         CHN_LOCKASSERT(c);
 1610         DEB(printf("setspeed, channel %s\n", c->name));
 1611         DEB(printf("want speed %d, ", speed));
 1612         if (speed <= 0)
 1613                 return EINVAL;
 1614         if (CHN_STOPPED(c)) {
 1615                 r = 0;
 1616                 c->speed = speed;
 1617                 sndbuf_setspd(bs, speed);
 1618                 RANGE(speed, chn_getcaps(c)->minspeed, chn_getcaps(c)->maxspeed);
 1619                 DEB(printf("try speed %d, ", speed));
 1620                 sndbuf_setspd(b, CHANNEL_SETSPEED(c->methods, c->devinfo, speed));
 1621                 DEB(printf("got speed %d\n", sndbuf_getspd(b)));
 1622 
 1623                 delta = sndbuf_getspd(b) - sndbuf_getspd(bs);
 1624                 if (delta < 0)
 1625                         delta = -delta;
 1626 
 1627                 c->feederflags &= ~(1 << FEEDER_RATE);
 1628                 /*
 1629                  * Used to be 500. It was too big!
 1630                  */
 1631                 if (delta > feeder_rate_round)
 1632                         c->feederflags |= 1 << FEEDER_RATE;
 1633                 else
 1634                         sndbuf_setspd(bs, sndbuf_getspd(b));
 1635 
 1636                 r = chn_buildfeeder(c);
 1637                 DEB(printf("r = %d\n", r));
 1638                 if (r)
 1639                         goto out;
 1640 
 1641                 if (!(c->feederflags & (1 << FEEDER_RATE)))
 1642                         goto out;
 1643 
 1644                 r = EINVAL;
 1645                 f = chn_findfeeder(c, FEEDER_RATE);
 1646                 DEB(printf("feedrate = %p\n", f));
 1647                 if (f == NULL)
 1648                         goto out;
 1649 
 1650                 x = (c->direction == PCMDIR_REC)? b : bs;
 1651                 r = FEEDER_SET(f, FEEDRATE_SRC, sndbuf_getspd(x));
 1652                 DEB(printf("feeder_set(FEEDRATE_SRC, %d) = %d\n", sndbuf_getspd(x), r));
 1653                 if (r)
 1654                         goto out;
 1655 
 1656                 x = (c->direction == PCMDIR_REC)? bs : b;
 1657                 r = FEEDER_SET(f, FEEDRATE_DST, sndbuf_getspd(x));
 1658                 DEB(printf("feeder_set(FEEDRATE_DST, %d) = %d\n", sndbuf_getspd(x), r));
 1659 out:
 1660                 if (!r)
 1661                         r = CHANNEL_SETFORMAT(c->methods, c->devinfo,
 1662                                                         sndbuf_getfmt(b));
 1663                 if (!r)
 1664                         sndbuf_setfmt(bs, c->format);
 1665                 if (!r)
 1666                         r = chn_resizebuf(c, -2, 0, 0);
 1667                 DEB(printf("setspeed done, r = %d\n", r));
 1668                 return r;
 1669         } else
 1670                 return EINVAL;
 1671 }
 1672 
 1673 int
 1674 chn_setspeed(struct pcm_channel *c, int speed)
 1675 {
 1676         int r, oldspeed = c->speed;
 1677 
 1678         r = chn_tryspeed(c, speed);
 1679         if (r) {
 1680                 if (snd_verbose > 3)
 1681                         printf("Failed to set speed %d falling back to %d\n",
 1682                             speed, oldspeed);
 1683                 r = chn_tryspeed(c, oldspeed);
 1684         }
 1685         return r;
 1686 }
 1687 
 1688 static int
 1689 chn_tryformat(struct pcm_channel *c, u_int32_t fmt)
 1690 {
 1691         struct snd_dbuf *b = c->bufhard;
 1692         struct snd_dbuf *bs = c->bufsoft;
 1693         int r;
 1694 
 1695         CHN_LOCKASSERT(c);
 1696         if (CHN_STOPPED(c)) {
 1697                 DEB(printf("want format %d\n", fmt));
 1698                 c->format = fmt;
 1699                 r = chn_buildfeeder(c);
 1700                 if (r == 0) {
 1701                         sndbuf_setfmt(bs, c->format);
 1702                         chn_resetbuf(c);
 1703                         r = CHANNEL_SETFORMAT(c->methods, c->devinfo, sndbuf_getfmt(b));
 1704                         if (r == 0)
 1705                                 r = chn_tryspeed(c, c->speed);
 1706                 }
 1707                 return r;
 1708         } else
 1709                 return EINVAL;
 1710 }
 1711 
 1712 int
 1713 chn_setformat(struct pcm_channel *c, u_int32_t fmt)
 1714 {
 1715         u_int32_t oldfmt = c->format;
 1716         int r;
 1717 
 1718         r = chn_tryformat(c, fmt);
 1719         if (r) {
 1720                 if (snd_verbose > 3)
 1721                         printf("Format change 0x%08x failed, reverting to 0x%08x\n",
 1722                             fmt, oldfmt);
 1723                 chn_tryformat(c, oldfmt);
 1724         }
 1725         return r;
 1726 }
 1727 
 1728 int
 1729 chn_trigger(struct pcm_channel *c, int go)
 1730 {
 1731 #ifdef DEV_ISA
 1732         struct snd_dbuf *b = c->bufhard;
 1733 #endif
 1734         struct snddev_info *d = c->parentsnddev;
 1735         int ret;
 1736 
 1737         CHN_LOCKASSERT(c);
 1738 #ifdef DEV_ISA
 1739         if (SND_DMA(b) && (go == PCMTRIG_EMLDMAWR || go == PCMTRIG_EMLDMARD))
 1740                 sndbuf_dmabounce(b);
 1741 #endif
 1742         if (!PCMTRIG_COMMON(go))
 1743                 return (CHANNEL_TRIGGER(c->methods, c->devinfo, go));
 1744 
 1745         if (go == c->trigger)
 1746                 return (0);
 1747 
 1748         ret = CHANNEL_TRIGGER(c->methods, c->devinfo, go);
 1749         if (ret != 0)
 1750                 return (ret);
 1751 
 1752         switch (go) {
 1753         case PCMTRIG_START:
 1754                 if (snd_verbose > 3)
 1755                         device_printf(c->dev,
 1756                             "%s() %s: calling go=0x%08x , "
 1757                             "prev=0x%08x\n", __func__, c->name, go,
 1758                             c->trigger);
 1759                 if (c->trigger != PCMTRIG_START) {
 1760                         c->trigger = go;
 1761                         CHN_UNLOCK(c);
 1762                         pcm_lock(d);
 1763                         CHN_INSERT_HEAD(d, c, channels.pcm.busy);
 1764                         pcm_unlock(d);
 1765                         CHN_LOCK(c);
 1766                 }
 1767                 break;
 1768         case PCMTRIG_STOP:
 1769         case PCMTRIG_ABORT:
 1770                 if (snd_verbose > 3)
 1771                         device_printf(c->dev,
 1772                             "%s() %s: calling go=0x%08x , "
 1773                             "prev=0x%08x\n", __func__, c->name, go,
 1774                             c->trigger);
 1775                 if (c->trigger == PCMTRIG_START) {
 1776                         c->trigger = go;
 1777                         CHN_UNLOCK(c);
 1778                         pcm_lock(d);
 1779                         CHN_REMOVE(d, c, channels.pcm.busy);
 1780                         pcm_unlock(d);
 1781                         CHN_LOCK(c);
 1782                 }
 1783                 break;
 1784         default:
 1785                 break;
 1786         }
 1787 
 1788         return (0);
 1789 }
 1790 
 1791 /**
 1792  * @brief Queries sound driver for sample-aligned hardware buffer pointer index
 1793  *
 1794  * This function obtains the hardware pointer location, then aligns it to
 1795  * the current bytes-per-sample value before returning.  (E.g., a channel
 1796  * running in 16 bit stereo mode would require 4 bytes per sample, so a
 1797  * hwptr value ranging from 32-35 would be returned as 32.)
 1798  *
 1799  * @param c     PCM channel context     
 1800  * @returns     sample-aligned hardware buffer pointer index
 1801  */
 1802 int
 1803 chn_getptr(struct pcm_channel *c)
 1804 {
 1805         int hwptr;
 1806 
 1807         CHN_LOCKASSERT(c);
 1808         hwptr = (CHN_STARTED(c)) ? CHANNEL_GETPTR(c->methods, c->devinfo) : 0;
 1809         return (hwptr - (hwptr % sndbuf_getbps(c->bufhard)));
 1810 }
 1811 
 1812 struct pcmchan_caps *
 1813 chn_getcaps(struct pcm_channel *c)
 1814 {
 1815         CHN_LOCKASSERT(c);
 1816         return CHANNEL_GETCAPS(c->methods, c->devinfo);
 1817 }
 1818 
 1819 u_int32_t
 1820 chn_getformats(struct pcm_channel *c)
 1821 {
 1822         u_int32_t *fmtlist, fmts;
 1823         int i;
 1824 
 1825         fmtlist = chn_getcaps(c)->fmtlist;
 1826         fmts = 0;
 1827         for (i = 0; fmtlist[i]; i++)
 1828                 fmts |= fmtlist[i];
 1829 
 1830         /* report software-supported formats */
 1831         if (report_soft_formats)
 1832                 fmts |= AFMT_MU_LAW|AFMT_A_LAW|AFMT_U32_LE|AFMT_U32_BE|
 1833                     AFMT_S32_LE|AFMT_S32_BE|AFMT_U24_LE|AFMT_U24_BE|
 1834                     AFMT_S24_LE|AFMT_S24_BE|AFMT_U16_LE|AFMT_U16_BE|
 1835                     AFMT_S16_LE|AFMT_S16_BE|AFMT_U8|AFMT_S8;
 1836 
 1837         return fmts;
 1838 }
 1839 
 1840 static int
 1841 chn_buildfeeder(struct pcm_channel *c)
 1842 {
 1843         struct feeder_class *fc;
 1844         struct pcm_feederdesc desc;
 1845         struct snd_mixer *m;
 1846         u_int32_t tmp[2], type, flags, hwfmt, *fmtlist;
 1847         int err;
 1848         char fmtstr[AFMTSTR_MAXSZ];
 1849 
 1850         CHN_LOCKASSERT(c);
 1851         while (chn_removefeeder(c) == 0)
 1852                 ;
 1853         KASSERT((c->feeder == NULL), ("feeder chain not empty"));
 1854 
 1855         c->align = sndbuf_getalign(c->bufsoft);
 1856 
 1857         if (CHN_EMPTY(c, children) || c->direction == PCMDIR_REC) {
 1858                 /*
 1859                  * Virtual rec need this.
 1860                  */
 1861                 fc = feeder_getclass(NULL);
 1862                 KASSERT(fc != NULL, ("can't find root feeder"));
 1863 
 1864                 err = chn_addfeeder(c, fc, NULL);
 1865                 if (err) {
 1866                         DEB(printf("can't add root feeder, err %d\n", err));
 1867 
 1868                         return err;
 1869                 }
 1870                 c->feeder->desc->out = c->format;
 1871         } else if (c->direction == PCMDIR_PLAY) {
 1872                 if (c->flags & CHN_F_HAS_VCHAN) {
 1873                         desc.type = FEEDER_MIXER;
 1874                         desc.in = c->format;
 1875                 } else {
 1876                         DEB(printf("can't decide which feeder type to use!\n"));
 1877                         return EOPNOTSUPP;
 1878                 }
 1879                 desc.out = c->format;
 1880                 desc.flags = 0;
 1881                 fc = feeder_getclass(&desc);
 1882                 if (fc == NULL) {
 1883                         DEB(printf("can't find vchan feeder\n"));
 1884 
 1885                         return EOPNOTSUPP;
 1886                 }
 1887 
 1888                 err = chn_addfeeder(c, fc, &desc);
 1889                 if (err) {
 1890                         DEB(printf("can't add vchan feeder, err %d\n", err));
 1891 
 1892                         return err;
 1893                 }
 1894         } else
 1895                 return EOPNOTSUPP;
 1896 
 1897         /* XXX These are too much.. */
 1898         if (c->parentsnddev != NULL && c->parentsnddev->mixer_dev != NULL &&
 1899             c->parentsnddev->mixer_dev->si_drv1 != NULL)
 1900                 m = c->parentsnddev->mixer_dev->si_drv1;
 1901         else
 1902                 m = NULL;
 1903 
 1904         c->feederflags &= ~(1 << FEEDER_VOLUME);
 1905         if (c->direction == PCMDIR_PLAY && !(c->flags & CHN_F_VIRTUAL) && m &&
 1906             (c->parentsnddev->flags & SD_F_SOFTPCMVOL))
 1907                 c->feederflags |= 1 << FEEDER_VOLUME;
 1908 
 1909         if (!(c->flags & CHN_F_VIRTUAL) && c->parentsnddev &&
 1910             ((c->direction == PCMDIR_PLAY &&
 1911             (c->parentsnddev->flags & SD_F_PSWAPLR)) ||
 1912             (c->direction == PCMDIR_REC &&
 1913             (c->parentsnddev->flags & SD_F_RSWAPLR))))
 1914                 c->feederflags |= 1 << FEEDER_SWAPLR;
 1915 
 1916         flags = c->feederflags;
 1917         fmtlist = chn_getcaps(c)->fmtlist;
 1918 
 1919         DEB(printf("feederflags %x\n", flags));
 1920 
 1921         for (type = FEEDER_RATE; type < FEEDER_LAST; type++) {
 1922                 if (flags & (1 << type)) {
 1923                         desc.type = type;
 1924                         desc.in = 0;
 1925                         desc.out = 0;
 1926                         desc.flags = 0;
 1927                         DEB(printf("find feeder type %d, ", type));
 1928                         if (type == FEEDER_VOLUME || type == FEEDER_RATE) {
 1929                                 if (c->feeder->desc->out & AFMT_32BIT)
 1930                                         strlcpy(fmtstr,"s32le", sizeof(fmtstr));
 1931                                 else if (c->feeder->desc->out & AFMT_24BIT)
 1932                                         strlcpy(fmtstr, "s24le", sizeof(fmtstr));
 1933                                 else {
 1934                                         /*
 1935                                          * 8bit doesn't provide enough headroom
 1936                                          * for proper processing without
 1937                                          * creating too much noises. Force to
 1938                                          * 16bit instead.
 1939                                          */
 1940                                         strlcpy(fmtstr, "s16le", sizeof(fmtstr));
 1941                                 }
 1942                                 if (!(c->feeder->desc->out & AFMT_8BIT) &&
 1943                                             c->feeder->desc->out & AFMT_BIGENDIAN)
 1944                                         afmtstr_swap_endian(fmtstr);
 1945                                 if (!(c->feeder->desc->out & (AFMT_A_LAW | AFMT_MU_LAW)) &&
 1946                                             !(c->feeder->desc->out & AFMT_SIGNED))
 1947                                         afmtstr_swap_sign(fmtstr);
 1948                                 desc.in = afmtstr2afmt(NULL, fmtstr, AFMTSTR_MONO_RETURN);
 1949                                 if (desc.in == 0)
 1950                                         desc.in = AFMT_S16_LE;
 1951                                 /* feeder_volume need stereo processing */
 1952                                 if (type == FEEDER_VOLUME ||
 1953                                             c->feeder->desc->out & AFMT_STEREO)
 1954                                         desc.in |= AFMT_STEREO;
 1955                                 desc.out = desc.in;
 1956                         } else if (type == FEEDER_SWAPLR) {
 1957                                 desc.in = c->feeder->desc->out;
 1958                                 desc.in |= AFMT_STEREO;
 1959                                 desc.out = desc.in;
 1960                         }
 1961 
 1962                         fc = feeder_getclass(&desc);
 1963                         DEB(printf("got %p\n", fc));
 1964                         if (fc == NULL) {
 1965                                 DEB(printf("can't find required feeder type %d\n", type));
 1966 
 1967                                 return EOPNOTSUPP;
 1968                         }
 1969 
 1970                         if (desc.in == 0 || desc.out == 0)
 1971                                 desc = *fc->desc;
 1972 
 1973                         DEB(printf("build fmtchain from 0x%08x to 0x%08x: ", c->feeder->desc->out, fc->desc->in));
 1974                         tmp[0] = desc.in;
 1975                         tmp[1] = 0;
 1976                         if (chn_fmtchain(c, tmp) == 0) {
 1977                                 DEB(printf("failed\n"));
 1978 
 1979                                 return ENODEV;
 1980                         }
 1981                         DEB(printf("ok\n"));
 1982 
 1983                         err = chn_addfeeder(c, fc, &desc);
 1984                         if (err) {
 1985                                 DEB(printf("can't add feeder %p, output 0x%x, err %d\n", fc, fc->desc->out, err));
 1986 
 1987                                 return err;
 1988                         }
 1989                         DEB(printf("added feeder %p, output 0x%x\n", fc, c->feeder->desc->out));
 1990                 }
 1991         }
 1992 
 1993         if (c->direction == PCMDIR_REC) {
 1994                 tmp[0] = c->format;
 1995                 tmp[1] = 0;
 1996                 hwfmt = chn_fmtchain(c, tmp);
 1997         } else
 1998                 hwfmt = chn_fmtchain(c, fmtlist);
 1999 
 2000         if (hwfmt == 0 || !fmtvalid(hwfmt, fmtlist)) {
 2001                 DEB(printf("Invalid hardware format: 0x%08x\n", hwfmt));
 2002                 return ENODEV;
 2003         } else if (c->direction == PCMDIR_REC && !CHN_EMPTY(c, children)) {
 2004                 /*
 2005                  * Kind of awkward. This whole "MIXER" concept need a
 2006                  * rethinking, I guess :) . Recording is the inverse
 2007                  * of Playback, which is why we push mixer vchan down here.
 2008                  */
 2009                 if (c->flags & CHN_F_HAS_VCHAN) {
 2010                         desc.type = FEEDER_MIXER;
 2011                         desc.in = c->format;
 2012                 } else
 2013                         return EOPNOTSUPP;
 2014                 desc.out = c->format;
 2015                 desc.flags = 0;
 2016                 fc = feeder_getclass(&desc);
 2017                 if (fc == NULL)
 2018                         return EOPNOTSUPP;
 2019 
 2020                 err = chn_addfeeder(c, fc, &desc);
 2021                 if (err != 0)
 2022                         return err;
 2023         }
 2024 
 2025         sndbuf_setfmt(c->bufhard, hwfmt);
 2026 
 2027         if ((flags & (1 << FEEDER_VOLUME))) {
 2028                 u_int32_t parent;
 2029                 int vol, left, right;
 2030 
 2031                 CHN_UNLOCK(c);
 2032                 vol = mix_get(m, SOUND_MIXER_PCM);
 2033                 if (vol == -1) {
 2034                         device_printf(c->dev,
 2035                             "Soft PCM Volume: Failed to read default value\n");
 2036                         vol = 100 | (100 << 8);
 2037                 }
 2038                 left = vol & 0x7f;
 2039                 right = (vol >> 8) & 0x7f;
 2040                 parent = mix_getparent(m, SOUND_MIXER_PCM);
 2041                 if (parent != SOUND_MIXER_NONE) {
 2042                         vol = mix_get(m, parent);
 2043                         if (vol == -1) {
 2044                                 device_printf(c->dev,
 2045                                     "Soft Volume: Failed to read parent "
 2046                                     "default value\n");
 2047                                 vol = 100 | (100 << 8);
 2048                         }
 2049                         left = (left * (vol & 0x7f)) / 100;
 2050                         right = (right * ((vol >> 8) & 0x7f)) / 100;
 2051                 }
 2052                 CHN_LOCK(c);
 2053                 chn_setvolume(c, left, right);
 2054         }
 2055 
 2056         return 0;
 2057 }
 2058 
 2059 int
 2060 chn_notify(struct pcm_channel *c, u_int32_t flags)
 2061 {
 2062         int err, run, nrun;
 2063 
 2064         CHN_LOCKASSERT(c);
 2065 
 2066         if (CHN_EMPTY(c, children))
 2067                 return (ENODEV);
 2068 
 2069         err = 0;
 2070 
 2071         /*
 2072          * If the hwchan is running, we can't change its rate, format or
 2073          * blocksize
 2074          */
 2075         run = (CHN_STARTED(c)) ? 1 : 0;
 2076         if (run)
 2077                 flags &= CHN_N_VOLUME | CHN_N_TRIGGER;
 2078 
 2079         if (flags & CHN_N_RATE) {
 2080                 /* XXX I'll make good use of this someday. */
 2081         }
 2082         if (flags & CHN_N_FORMAT) {
 2083                 /* XXX I'll make good use of this someday. */
 2084         }
 2085         if (flags & CHN_N_VOLUME) {
 2086                 /* XXX I'll make good use of this someday. */
 2087         }
 2088         if (flags & CHN_N_BLOCKSIZE) {
 2089                 /*
 2090                  * Set to default latency profile
 2091                  */
 2092                 chn_setlatency(c, chn_latency);
 2093         }
 2094         if (flags & CHN_N_TRIGGER) {
 2095                 nrun = CHN_EMPTY(c, children.busy) ? 0 : 1;
 2096                 if (nrun && !run)
 2097                         err = chn_start(c, 1);
 2098                 if (!nrun && run)
 2099                         chn_abort(c);
 2100         }
 2101 
 2102         return (err);
 2103 }
 2104 
 2105 /**
 2106  * @brief Fetch array of supported discrete sample rates
 2107  *
 2108  * Wrapper for CHANNEL_GETRATES.  Please see channel_if.m:getrates() for
 2109  * detailed information.
 2110  *
 2111  * @note If the operation isn't supported, this function will just return 0
 2112  *       (no rates in the array), and *rates will be set to NULL.  Callers
 2113  *       should examine rates @b only if this function returns non-zero.
 2114  *
 2115  * @param c     pcm channel to examine
 2116  * @param rates pointer to array of integers; rate table will be recorded here
 2117  *
 2118  * @return number of rates in the array pointed to be @c rates
 2119  */
 2120 int
 2121 chn_getrates(struct pcm_channel *c, int **rates)
 2122 {
 2123         KASSERT(rates != NULL, ("rates is null"));
 2124         CHN_LOCKASSERT(c);
 2125         return CHANNEL_GETRATES(c->methods, c->devinfo, rates);
 2126 }
 2127 
 2128 /**
 2129  * @brief Remove channel from a sync group, if there is one.
 2130  *
 2131  * This function is initially intended for the following conditions:
 2132  *   - Starting a syncgroup (@c SNDCTL_DSP_SYNCSTART ioctl)
 2133  *   - Closing a device.  (A channel can't be destroyed if it's still in use.)
 2134  *
 2135  * @note Before calling this function, the syncgroup list mutex must be
 2136  * held.  (Consider pcm_channel::sm protected by the SG list mutex
 2137  * whether @c c is locked or not.)
 2138  *
 2139  * @param c     channel device to be started or closed
 2140  * @returns     If this channel was the only member of a group, the group ID
 2141  *              is returned to the caller so that the caller can release it
 2142  *              via free_unr() after giving up the syncgroup lock.  Else it
 2143  *              returns 0.
 2144  */
 2145 int
 2146 chn_syncdestroy(struct pcm_channel *c)
 2147 {
 2148         struct pcmchan_syncmember *sm;
 2149         struct pcmchan_syncgroup *sg;
 2150         int sg_id;
 2151 
 2152         sg_id = 0;
 2153 
 2154         PCM_SG_LOCKASSERT(MA_OWNED);
 2155 
 2156         if (c->sm != NULL) {
 2157                 sm = c->sm;
 2158                 sg = sm->parent;
 2159                 c->sm = NULL;
 2160 
 2161                 KASSERT(sg != NULL, ("syncmember has null parent"));
 2162 
 2163                 SLIST_REMOVE(&sg->members, sm, pcmchan_syncmember, link);
 2164                 free(sm, M_DEVBUF);
 2165 
 2166                 if (SLIST_EMPTY(&sg->members)) {
 2167                         SLIST_REMOVE(&snd_pcm_syncgroups, sg, pcmchan_syncgroup, link);
 2168                         sg_id = sg->id;
 2169                         free(sg, M_DEVBUF);
 2170                 }
 2171         }
 2172 
 2173         return sg_id;
 2174 }
 2175 
 2176 void
 2177 chn_lock(struct pcm_channel *c)
 2178 {
 2179         CHN_LOCK(c);
 2180 }
 2181 
 2182 void
 2183 chn_unlock(struct pcm_channel *c)
 2184 {
 2185         CHN_UNLOCK(c);
 2186 }
 2187 
 2188 #ifdef OSSV4_EXPERIMENT
 2189 int
 2190 chn_getpeaks(struct pcm_channel *c, int *lpeak, int *rpeak)
 2191 {
 2192         CHN_LOCKASSERT(c);
 2193         return CHANNEL_GETPEAKS(c->methods, c->devinfo, lpeak, rpeak);
 2194 }
 2195 #endif

Cache object: 2cec50d2b0f9ecdf4e793f6e044930cd


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