LCOV - code coverage report
Current view: top level - dev - audio.c (source / functions) Hit Total Coverage
Test: 6.4 Lines: 0 1072 0.0 %
Date: 2018-10-19 03:25:38 Functions: 0 55 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*      $OpenBSD: audio.c,v 1.172 2018/06/24 23:54:22 ratchov Exp $     */
       2             : /*
       3             :  * Copyright (c) 2015 Alexandre Ratchov <alex@caoua.org>
       4             :  *
       5             :  * Permission to use, copy, modify, and distribute this software for any
       6             :  * purpose with or without fee is hereby granted, provided that the above
       7             :  * copyright notice and this permission notice appear in all copies.
       8             :  *
       9             :  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
      10             :  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
      11             :  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
      12             :  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
      13             :  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
      14             :  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
      15             :  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
      16             :  */
      17             : #include <sys/param.h>
      18             : #include <sys/fcntl.h>
      19             : #include <sys/systm.h>
      20             : #include <sys/ioctl.h>
      21             : #include <sys/conf.h>
      22             : #include <sys/poll.h>
      23             : #include <sys/kernel.h>
      24             : #include <sys/task.h>
      25             : #include <sys/vnode.h>
      26             : #include <sys/malloc.h>
      27             : #include <sys/device.h>
      28             : #include <sys/audioio.h>
      29             : #include <dev/audio_if.h>
      30             : #include <dev/mulaw.h>
      31             : #include "audio.h"
      32             : #include "wskbd.h"
      33             : 
      34             : #ifdef AUDIO_DEBUG
      35             : #define DPRINTF(...)                            \
      36             :         do {                                    \
      37             :                 if (audio_debug)                \
      38             :                         printf(__VA_ARGS__);    \
      39             :         } while(0)
      40             : #define DPRINTFN(n, ...)                        \
      41             :         do {                                    \
      42             :                 if (audio_debug > (n))               \
      43             :                         printf(__VA_ARGS__);    \
      44             :         } while(0)
      45             : #else
      46             : #define DPRINTF(...) do {} while(0)
      47             : #define DPRINTFN(n, ...) do {} while(0)
      48             : #endif
      49             : 
      50             : #define DEVNAME(sc)             ((sc)->dev.dv_xname)
      51             : #define AUDIO_UNIT(n)           (minor(n) & 0x0f)
      52             : #define AUDIO_DEV(n)            (minor(n) & 0xf0)
      53             : #define AUDIO_DEV_AUDIO         0       /* minor of /dev/audio0 */
      54             : #define AUDIO_DEV_MIXER         0x10    /* minor of /dev/mixer0 */
      55             : #define AUDIO_DEV_AUDIOCTL      0xc0    /* minor of /dev/audioctl */
      56             : #define AUDIO_BUFSZ             65536   /* buffer size in bytes */
      57             : 
      58             : /*
      59             :  * mixer entries added by the audio(4) layer
      60             :  */
      61             : #define MIXER_RECORD                    0       /* record class */
      62             : #define MIXER_RECORD_ENABLE             1       /* record.enable control */
      63             : #define  MIXER_RECORD_ENABLE_OFF        0       /* record.enable=off value */
      64             : #define  MIXER_RECORD_ENABLE_ON         1       /* record.enable=on value */
      65             : #define  MIXER_RECORD_ENABLE_SYSCTL     2       /* record.enable=sysctl val */
      66             : 
      67             : /*
      68             :  * dma buffer
      69             :  */
      70             : struct audio_buf {
      71             :         unsigned char *data;            /* DMA memory block */
      72             :         size_t datalen;                 /* size of DMA memory block */
      73             :         size_t len;                     /* size of DMA FIFO */
      74             :         size_t start;                   /* first byte used in the FIFO */
      75             :         size_t used;                    /* bytes used in the FIFO */
      76             :         size_t blksz;                   /* DMA block size */
      77             :         struct selinfo sel;             /* to record & wakeup poll(2) */
      78             :         unsigned int pos;               /* bytes transferred */
      79             :         unsigned int xrun;              /* bytes lost by xruns */
      80             :         int blocking;                   /* read/write blocking */
      81             : };
      82             : 
      83             : #if NWSKBD > 0
      84             : struct wskbd_vol
      85             : {
      86             :         int val;                        /* index of the value control */
      87             :         int mute;                       /* index of the mute control */
      88             :         int step;                       /* increment/decrement step */
      89             :         int nch;                        /* channels in the value control */
      90             :         int val_pending;                /* pending change of val */
      91             :         int mute_pending;               /* pending change of mute */
      92             : #define WSKBD_MUTE_TOGGLE       1
      93             : #define WSKBD_MUTE_DISABLE      2
      94             : #define WSKBD_MUTE_ENABLE       3
      95             : };
      96             : #endif
      97             : 
      98             : /*
      99             :  * device structure
     100             :  */
     101             : struct audio_softc {
     102             :         struct device dev;
     103             :         struct audio_hw_if *ops;        /* driver funcs */
     104             :         void *arg;                      /* first arg to driver funcs */
     105             :         int mode;                       /* bitmask of AUMODE_* */
     106             :         int quiesce;                    /* device suspended */
     107             :         struct audio_buf play, rec;
     108             :         unsigned int sw_enc;            /* user exposed AUDIO_ENCODING_* */
     109             :         unsigned int hw_enc;            /* hardware AUDIO_ENCODING_* */
     110             :         unsigned int bits;              /* bits per sample */
     111             :         unsigned int bps;               /* bytes-per-sample */
     112             :         unsigned int msb;               /* sample are MSB aligned */
     113             :         unsigned int rate;              /* rate in Hz */
     114             :         unsigned int round;             /* block size in frames */
     115             :         unsigned int nblks;             /* number of play blocks */
     116             :         unsigned int pchan, rchan;      /* number of channels */
     117             :         unsigned char silence[4];       /* a sample of silence */
     118             :         int pause;                      /* not trying to start DMA */
     119             :         int active;                     /* DMA in process */
     120             :         int offs;                       /* offset between play & rec dir */
     121             :         void (*conv_enc)(unsigned char *, int); /* encode to native */
     122             :         void (*conv_dec)(unsigned char *, int); /* decode to user */
     123             :         struct mixer_ctrl *mix_ents;    /* mixer state for suspend/resume */
     124             :         int mix_nent;                   /* size of mixer state */
     125             : #if NWSKBD > 0
     126             :         struct wskbd_vol spkr, mic;
     127             :         struct task wskbd_task;
     128             :         int wskbd_taskset;
     129             : #endif
     130             :         int record_enable;              /* mixer record.enable value */
     131             : };
     132             : 
     133             : int audio_match(struct device *, void *, void *);
     134             : void audio_attach(struct device *, struct device *, void *);
     135             : int audio_activate(struct device *, int);
     136             : int audio_detach(struct device *, int);
     137             : void audio_pintr(void *);
     138             : void audio_rintr(void *);
     139             : #if NWSKBD > 0
     140             : void wskbd_mixer_init(struct audio_softc *);
     141             : #endif
     142             : 
     143             : const struct cfattach audio_ca = {
     144             :         sizeof(struct audio_softc), audio_match, audio_attach,
     145             :         audio_detach, audio_activate
     146             : };
     147             : 
     148             : struct cfdriver audio_cd = {
     149             :         NULL, "audio", DV_DULL
     150             : };
     151             : 
     152             : /*
     153             :  * This mutex protects data structures (including registers on the
     154             :  * sound-card) that are manipulated by both the interrupt handler and
     155             :  * syscall code-paths.
     156             :  *
     157             :  * Note that driver methods may sleep (e.g. in malloc); consequently the
     158             :  * audio layer calls them with the mutex unlocked. Driver methods are
     159             :  * responsible for locking the mutex when they manipulate data used by
     160             :  * the interrupt handler and interrupts may occur.
     161             :  *
     162             :  * Similarly, the driver is responsible for locking the mutex in its
     163             :  * interrupt handler and to call the audio layer call-backs (i.e.
     164             :  * audio_{p,r}int()) with the mutex locked.
     165             :  */
     166             : struct mutex audio_lock = MUTEX_INITIALIZER(IPL_AUDIO);
     167             : 
     168             : /*
     169             :  * Global flag to control if audio recording is enabled when the
     170             :  * mixerctl setting is record.enable=sysctl
     171             :  */
     172             : int audio_record_enable = 0;
     173             : 
     174             : #ifdef AUDIO_DEBUG
     175             : /*
     176             :  * 0 - nothing, as if AUDIO_DEBUG isn't defined
     177             :  * 1 - initialisations & setup
     178             :  * 2 - blocks & interrupts
     179             :  */
     180             : int audio_debug = 1;
     181             : #endif
     182             : 
     183             : unsigned int
     184           0 : audio_gcd(unsigned int a, unsigned int b)
     185             : {
     186             :         unsigned int r;
     187             : 
     188           0 :         while (b > 0) {
     189           0 :                 r = a % b;
     190             :                 a = b;
     191             :                 b = r;
     192             :         }
     193           0 :         return a;
     194             : }
     195             : 
     196             : int
     197           0 : audio_buf_init(struct audio_softc *sc, struct audio_buf *buf, int dir)
     198             : {
     199           0 :         if (sc->ops->round_buffersize) {
     200           0 :                 buf->datalen = sc->ops->round_buffersize(sc->arg,
     201             :                     dir, AUDIO_BUFSZ);
     202           0 :         } else
     203           0 :                 buf->datalen = AUDIO_BUFSZ;
     204           0 :         if (sc->ops->allocm) {
     205           0 :                 buf->data = sc->ops->allocm(sc->arg, dir, buf->datalen,
     206             :                     M_DEVBUF, M_WAITOK);
     207           0 :         } else
     208           0 :                 buf->data = malloc(buf->datalen, M_DEVBUF, M_WAITOK);
     209           0 :         if (buf->data == NULL)
     210           0 :                 return ENOMEM;
     211           0 :         return 0;
     212           0 : }
     213             : 
     214             : void
     215           0 : audio_buf_done(struct audio_softc *sc, struct audio_buf *buf)
     216             : {
     217           0 :         if (sc->ops->freem)
     218           0 :                 sc->ops->freem(sc->arg, buf->data, M_DEVBUF);
     219             :         else
     220           0 :                 free(buf->data, M_DEVBUF, buf->datalen);
     221           0 : }
     222             : 
     223             : /*
     224             :  * return the reader pointer and the number of bytes available
     225             :  */
     226             : unsigned char *
     227           0 : audio_buf_rgetblk(struct audio_buf *buf, size_t *rsize)
     228             : {
     229             :         size_t count;
     230             : 
     231           0 :         count = buf->len - buf->start;
     232           0 :         if (count > buf->used)
     233           0 :                 count = buf->used;
     234           0 :         *rsize = count;
     235           0 :         return buf->data + buf->start;
     236             : }
     237             : 
     238             : /*
     239             :  * discard "count" bytes at the start position.
     240             :  */
     241             : void
     242           0 : audio_buf_rdiscard(struct audio_buf *buf, size_t count)
     243             : {
     244             : #ifdef AUDIO_DEBUG
     245             :         if (count > buf->used) {
     246             :                 panic("audio_buf_rdiscard: bad count = %zu, "
     247             :                     "start = %zu, used = %zu\n", count, buf->start, buf->used);
     248             :         }
     249             : #endif
     250           0 :         buf->used -= count;
     251           0 :         buf->start += count;
     252           0 :         if (buf->start >= buf->len)
     253           0 :                 buf->start -= buf->len;
     254           0 : }
     255             : 
     256             : /*
     257             :  * advance the writer pointer by "count" bytes
     258             :  */
     259             : void
     260           0 : audio_buf_wcommit(struct audio_buf *buf, size_t count)
     261             : {
     262             : #ifdef AUDIO_DEBUG
     263             :         if (count > (buf->len - buf->used)) {
     264             :                 panic("audio_buf_wcommit: bad count = %zu, "
     265             :                     "start = %zu, used = %zu\n", count, buf->start, buf->used);
     266             :         }
     267             : #endif
     268           0 :         buf->used += count;
     269           0 : }
     270             : 
     271             : /*
     272             :  * get writer pointer and the number of bytes writable
     273             :  */
     274             : unsigned char *
     275           0 : audio_buf_wgetblk(struct audio_buf *buf, size_t *rsize)
     276             : {
     277             :         size_t end, avail, count;
     278             : 
     279           0 :         end = buf->start + buf->used;
     280           0 :         if (end >= buf->len)
     281           0 :                 end -= buf->len;
     282           0 :         avail = buf->len - buf->used;
     283           0 :         count = buf->len - end;
     284           0 :         if (count > avail)
     285           0 :                 count = avail;
     286           0 :         *rsize = count;
     287           0 :         return buf->data + end;
     288             : }
     289             : 
     290             : void
     291           0 : audio_calc_sil(struct audio_softc *sc)
     292             : {
     293             :         unsigned char *q;
     294             :         unsigned int s, i;
     295             :         int d, e;
     296             : 
     297           0 :         e = sc->sw_enc;
     298             : #ifdef AUDIO_DEBUG
     299             :         switch (e) {
     300             :         case AUDIO_ENCODING_SLINEAR_LE:
     301             :         case AUDIO_ENCODING_ULINEAR_LE:
     302             :         case AUDIO_ENCODING_SLINEAR_BE:
     303             :         case AUDIO_ENCODING_ULINEAR_BE:
     304             :                 break;
     305             :         default:
     306             :                 printf("%s: unhandled play encoding %d\n", DEVNAME(sc), e);
     307             :                 memset(sc->silence, 0, sc->bps);
     308             :                 return;
     309             :         }
     310             : #endif
     311           0 :         if (e == AUDIO_ENCODING_SLINEAR_BE || e == AUDIO_ENCODING_ULINEAR_BE) {
     312             :                 d = -1;
     313           0 :                 q = sc->silence + sc->bps - 1;
     314           0 :         } else {
     315             :                 d = 1;
     316           0 :                 q = sc->silence;
     317             :         }
     318           0 :         if (e == AUDIO_ENCODING_SLINEAR_LE || e == AUDIO_ENCODING_SLINEAR_BE) {
     319             :                 s = 0;
     320           0 :         } else {
     321             :                 s = 0x80000000;
     322           0 :                 if (sc->msb)
     323           0 :                         s >>= 32 - 8 * sc->bps;
     324             :                 else
     325           0 :                         s >>= 32 - sc->bits;
     326             :         }
     327           0 :         for (i = 0; i < sc->bps; i++) {
     328           0 :                 *q = s;
     329           0 :                 q += d;
     330           0 :                 s >>= 8;
     331             :         }
     332           0 :         if (sc->conv_enc)
     333           0 :                 sc->conv_enc(sc->silence, sc->bps);
     334           0 : }
     335             : 
     336             : void
     337           0 : audio_fill_sil(struct audio_softc *sc, unsigned char *ptr, size_t count)
     338             : {
     339             :         unsigned char *q, *p;
     340             :         size_t i, j;
     341             : 
     342             :         q = ptr;
     343           0 :         for (j = count / sc->bps; j > 0; j--) {
     344           0 :                 p = sc->silence;
     345           0 :                 for (i = sc->bps; i > 0; i--)
     346           0 :                         *q++ = *p++;
     347             :         }
     348           0 : }
     349             : 
     350             : void
     351           0 : audio_clear(struct audio_softc *sc)
     352             : {
     353           0 :         if (sc->mode & AUMODE_PLAY) {
     354           0 :                 sc->play.used = sc->play.start = 0;
     355           0 :                 sc->play.pos = sc->play.xrun = 0;
     356           0 :                 audio_fill_sil(sc, sc->play.data, sc->play.len);
     357           0 :         }
     358           0 :         if (sc->mode & AUMODE_RECORD) {
     359           0 :                 sc->rec.used = sc->rec.start = 0;
     360           0 :                 sc->rec.pos = sc->rec.xrun = 0;
     361           0 :                 audio_fill_sil(sc, sc->rec.data, sc->rec.len);
     362           0 :         }
     363           0 : }
     364             : 
     365             : /*
     366             :  * called whenever a block is consumed by the driver
     367             :  */
     368             : void
     369           0 : audio_pintr(void *addr)
     370             : {
     371           0 :         struct audio_softc *sc = addr;
     372             :         unsigned char *ptr;
     373           0 :         size_t count;
     374             :         int error, nblk, todo;
     375             : 
     376           0 :         MUTEX_ASSERT_LOCKED(&audio_lock);
     377           0 :         if (!(sc->mode & AUMODE_PLAY) || !sc->active) {
     378           0 :                 printf("%s: play interrupt but not playing\n", DEVNAME(sc));
     379           0 :                 return;
     380             :         }
     381           0 :         if (sc->quiesce) {
     382             :                 DPRINTF("%s: quiesced, skipping play intr\n", DEVNAME(sc));
     383           0 :                 return;
     384             :         }
     385             : 
     386             :         /*
     387             :          * check if record pointer wrapped, see explanation
     388             :          * in audio_rintr()
     389             :          */
     390           0 :         if (sc->mode & AUMODE_RECORD) {
     391           0 :                 sc->offs--;
     392           0 :                 nblk = sc->rec.len / sc->rec.blksz;
     393           0 :                 todo = -sc->offs;
     394           0 :                 if (todo >= nblk) {
     395           0 :                         todo -= todo % nblk;
     396             :                         DPRINTFN(1, "%s: rec ptr wrapped, moving %d blocks\n",
     397             :                             DEVNAME(sc), todo);
     398           0 :                         while (todo-- > 0)
     399           0 :                                 audio_rintr(sc);
     400             :                 }
     401             :         }
     402             : 
     403           0 :         sc->play.pos += sc->play.blksz;
     404           0 :         audio_fill_sil(sc, sc->play.data + sc->play.start, sc->play.blksz);
     405           0 :         audio_buf_rdiscard(&sc->play, sc->play.blksz);
     406           0 :         if (sc->play.used < sc->play.blksz) {
     407             :                 DPRINTFN(1, "%s: play underrun\n", DEVNAME(sc));
     408           0 :                 sc->play.xrun += sc->play.blksz;
     409           0 :                 audio_buf_wcommit(&sc->play, sc->play.blksz);
     410           0 :         }
     411             : 
     412             :         DPRINTFN(1, "%s: play intr, used -> %zu, start -> %zu\n",
     413             :             DEVNAME(sc), sc->play.used, sc->play.start);
     414             : 
     415           0 :         if (!sc->ops->trigger_output) {
     416           0 :                 ptr = audio_buf_rgetblk(&sc->play, &count);
     417           0 :                 error = sc->ops->start_output(sc->arg,
     418           0 :                     ptr, sc->play.blksz, audio_pintr, (void *)sc);
     419           0 :                 if (error) {
     420           0 :                         printf("%s: play restart failed: %d\n",
     421           0 :                             DEVNAME(sc), error);
     422           0 :                 }
     423             :         }
     424             : 
     425           0 :         if (sc->play.used < sc->play.len) {
     426             :                 DPRINTFN(1, "%s: play wakeup, chan = %d\n",
     427             :                     DEVNAME(sc), sc->play.blocking);
     428           0 :                 if (sc->play.blocking) {
     429           0 :                         wakeup(&sc->play.blocking);
     430           0 :                         sc->play.blocking = 0;
     431           0 :                 }
     432           0 :                 selwakeup(&sc->play.sel);
     433           0 :         }
     434           0 : }
     435             : 
     436             : /*
     437             :  * called whenever a block is produced by the driver
     438             :  */
     439             : void
     440           0 : audio_rintr(void *addr)
     441             : {
     442           0 :         struct audio_softc *sc = addr;
     443             :         unsigned char *ptr;
     444           0 :         size_t count;
     445             :         int error, nblk, todo;
     446             : 
     447           0 :         MUTEX_ASSERT_LOCKED(&audio_lock);
     448           0 :         if (!(sc->mode & AUMODE_RECORD) || !sc->active) {
     449           0 :                 printf("%s: rec interrupt but not recording\n", DEVNAME(sc));
     450           0 :                 return;
     451             :         }
     452           0 :         if (sc->quiesce) {
     453             :                 DPRINTF("%s: quiesced, skipping rec intr\n", DEVNAME(sc));
     454           0 :                 return;
     455             :         }
     456             : 
     457             :         /*
     458             :          * Interrupts may be masked by other sub-systems during 320ms
     459             :          * and more. During such a delay the hardware doesn't stop
     460             :          * playing and the play buffer pointers may wrap, this can't be
     461             :          * detected and corrected by low level drivers. This makes the
     462             :          * record stream ahead of the play stream; this is detected as a
     463             :          * hardware anomaly by userland and cause programs to misbehave.
     464             :          *
     465             :          * We fix this by advancing play position by an integer count of
     466             :          * full buffers, so it reaches the record position.
     467             :          */
     468           0 :         if (sc->mode & AUMODE_PLAY) {
     469           0 :                 sc->offs++;
     470           0 :                 nblk = sc->play.len / sc->play.blksz;
     471             :                 todo = sc->offs;
     472           0 :                 if (todo >= nblk) {
     473           0 :                         todo -= todo % nblk;
     474             :                         DPRINTFN(1, "%s: play ptr wrapped, moving %d blocks\n",
     475             :                             DEVNAME(sc), todo);
     476           0 :                         while (todo-- > 0)
     477           0 :                                 audio_pintr(sc);
     478             :                 }
     479             :         }
     480             : 
     481           0 :         sc->rec.pos += sc->rec.blksz;
     482           0 :         if ((sc->record_enable == MIXER_RECORD_ENABLE_SYSCTL &&
     483           0 :                 !audio_record_enable) ||
     484           0 :             sc->record_enable == MIXER_RECORD_ENABLE_OFF) {
     485           0 :                 ptr = audio_buf_wgetblk(&sc->rec, &count);
     486           0 :                 audio_fill_sil(sc, ptr, sc->rec.blksz);
     487           0 :         }
     488           0 :         audio_buf_wcommit(&sc->rec, sc->rec.blksz);
     489           0 :         if (sc->rec.used > sc->rec.len - sc->rec.blksz) {
     490             :                 DPRINTFN(1, "%s: rec overrun\n", DEVNAME(sc));
     491           0 :                 sc->rec.xrun += sc->rec.blksz;
     492           0 :                 audio_buf_rdiscard(&sc->rec, sc->rec.blksz);
     493           0 :         }
     494             :         DPRINTFN(1, "%s: rec intr, used -> %zu\n", DEVNAME(sc), sc->rec.used);
     495             : 
     496           0 :         if (!sc->ops->trigger_input) {
     497           0 :                 ptr = audio_buf_wgetblk(&sc->rec, &count);
     498           0 :                 error = sc->ops->start_input(sc->arg,
     499           0 :                     ptr, sc->rec.blksz, audio_rintr, (void *)sc);
     500           0 :                 if (error) {
     501           0 :                         printf("%s: rec restart failed: %d\n",
     502           0 :                             DEVNAME(sc), error);
     503           0 :                 }
     504             :         }
     505             : 
     506           0 :         if (sc->rec.used > 0) {
     507             :                 DPRINTFN(1, "%s: rec wakeup, chan = %d\n",
     508             :                     DEVNAME(sc), sc->rec.blocking);
     509           0 :                 if (sc->rec.blocking) {
     510           0 :                         wakeup(&sc->rec.blocking);
     511           0 :                         sc->rec.blocking = 0;
     512           0 :                 }
     513           0 :                 selwakeup(&sc->rec.sel);
     514           0 :         }
     515           0 : }
     516             : 
     517             : int
     518           0 : audio_start_do(struct audio_softc *sc)
     519             : {
     520             :         int error;
     521           0 :         struct audio_params p;
     522             :         unsigned char *ptr;
     523           0 :         size_t count;
     524             : 
     525             :         DPRINTF("%s: starting\n", DEVNAME(sc));
     526             : 
     527             :         error = 0;
     528           0 :         sc->offs = 0;
     529           0 :         if (sc->mode & AUMODE_PLAY) {
     530           0 :                 if (sc->ops->trigger_output) {
     531           0 :                         p.encoding = sc->hw_enc;
     532           0 :                         p.precision = sc->bits;
     533           0 :                         p.bps = sc->bps;
     534           0 :                         p.msb = sc->msb;
     535           0 :                         p.sample_rate = sc->rate;
     536           0 :                         p.channels = sc->pchan;
     537           0 :                         error = sc->ops->trigger_output(sc->arg,
     538           0 :                             sc->play.data,
     539           0 :                             sc->play.data + sc->play.len,
     540           0 :                             sc->play.blksz,
     541           0 :                             audio_pintr, (void *)sc, &p);
     542           0 :                 } else {
     543           0 :                         mtx_enter(&audio_lock);
     544           0 :                         ptr = audio_buf_rgetblk(&sc->play, &count);
     545           0 :                         error = sc->ops->start_output(sc->arg,
     546           0 :                             ptr, sc->play.blksz, audio_pintr, (void *)sc);
     547           0 :                         mtx_leave(&audio_lock);
     548             :                 }
     549           0 :                 if (error)
     550           0 :                         printf("%s: failed to start playback\n", DEVNAME(sc));
     551             :         }
     552           0 :         if (sc->mode & AUMODE_RECORD) {
     553           0 :                 if (sc->ops->trigger_input) {
     554           0 :                         p.encoding = sc->hw_enc;
     555           0 :                         p.precision = sc->bits;
     556           0 :                         p.bps = sc->bps;
     557           0 :                         p.msb = sc->msb;
     558           0 :                         p.sample_rate = sc->rate;
     559           0 :                         p.channels = sc->rchan;
     560           0 :                         error = sc->ops->trigger_input(sc->arg,
     561           0 :                             sc->rec.data,
     562           0 :                             sc->rec.data + sc->rec.len,
     563           0 :                             sc->rec.blksz,
     564           0 :                             audio_rintr, (void *)sc, &p);
     565           0 :                 } else {
     566           0 :                         mtx_enter(&audio_lock);
     567           0 :                         ptr = audio_buf_wgetblk(&sc->rec, &count);
     568           0 :                         error = sc->ops->start_input(sc->arg,
     569           0 :                             ptr, sc->rec.blksz, audio_rintr, (void *)sc);
     570           0 :                         mtx_leave(&audio_lock);
     571             :                 }
     572           0 :                 if (error)
     573           0 :                         printf("%s: failed to start recording\n", DEVNAME(sc));
     574             :         }
     575           0 :         return error;
     576           0 : }
     577             : 
     578             : int
     579           0 : audio_stop_do(struct audio_softc *sc)
     580             : {
     581           0 :         if (sc->mode & AUMODE_PLAY)
     582           0 :                 sc->ops->halt_output(sc->arg);
     583           0 :         if (sc->mode & AUMODE_RECORD)
     584           0 :                 sc->ops->halt_input(sc->arg);
     585             :         DPRINTF("%s: stopped\n", DEVNAME(sc));
     586           0 :         return 0;
     587             : }
     588             : 
     589             : int
     590           0 : audio_start(struct audio_softc *sc)
     591             : {
     592           0 :         sc->active = 1;
     593           0 :         sc->play.xrun = sc->play.pos = sc->rec.xrun = sc->rec.pos = 0;
     594           0 :         return audio_start_do(sc);
     595             : }
     596             : 
     597             : int
     598           0 : audio_stop(struct audio_softc *sc)
     599             : {
     600             :         int error;
     601             : 
     602           0 :         error = audio_stop_do(sc);
     603           0 :         if (error)
     604           0 :                 return error;
     605           0 :         audio_clear(sc);
     606           0 :         sc->active = 0;
     607           0 :         return 0;
     608           0 : }
     609             : 
     610             : int
     611           0 : audio_canstart(struct audio_softc *sc)
     612             : {
     613           0 :         if (sc->active || sc->pause)
     614           0 :                 return 0;
     615           0 :         if ((sc->mode & AUMODE_RECORD) && sc->rec.used != 0)
     616           0 :                 return 0;
     617           0 :         if ((sc->mode & AUMODE_PLAY) && sc->play.used != sc->play.len)
     618           0 :                 return 0;
     619           0 :         return 1;
     620           0 : }
     621             : 
     622             : int
     623           0 : audio_setpar(struct audio_softc *sc)
     624             : {
     625           0 :         struct audio_params p, r;
     626             :         unsigned int nr, np, max, min, mult;
     627             :         unsigned int blk_mult, blk_max;
     628             :         int error;
     629             : 
     630             :         DPRINTF("%s: setpar: req enc=%d bits=%d, bps=%d, msb=%d "
     631             :             "rate=%d, pchan=%d, rchan=%d, round=%u, nblks=%d\n",
     632             :             DEVNAME(sc), sc->sw_enc, sc->bits, sc->bps, sc->msb,
     633             :             sc->rate, sc->pchan, sc->rchan, sc->round, sc->nblks);
     634             : 
     635             :         /*
     636             :          * check if requested parameters are in the allowed ranges
     637             :          */
     638           0 :         if (sc->mode & AUMODE_PLAY) {
     639           0 :                 if (sc->pchan < 1)
     640           0 :                         sc->pchan = 1;
     641           0 :                 else if (sc->pchan > 64)
     642           0 :                         sc->pchan = 64;
     643             :         }
     644           0 :         if (sc->mode & AUMODE_RECORD) {
     645           0 :                 if (sc->rchan < 1)
     646           0 :                         sc->rchan = 1;
     647           0 :                 else if (sc->rchan > 64)
     648           0 :                         sc->rchan = 64;
     649             :         }
     650           0 :         switch (sc->sw_enc) {
     651             :         case AUDIO_ENCODING_ULAW:
     652             :         case AUDIO_ENCODING_ALAW:
     653             :         case AUDIO_ENCODING_SLINEAR_LE:
     654             :         case AUDIO_ENCODING_SLINEAR_BE:
     655             :         case AUDIO_ENCODING_ULINEAR_LE:
     656             :         case AUDIO_ENCODING_ULINEAR_BE:
     657             :                 break;
     658             :         default:
     659           0 :                 sc->sw_enc = AUDIO_ENCODING_SLINEAR_LE;
     660           0 :         }
     661           0 :         if (sc->bits < 8)
     662           0 :                 sc->bits = 8;
     663           0 :         else if (sc->bits > 32)
     664           0 :                 sc->bits = 32;
     665           0 :         if (sc->bps < 1)
     666           0 :                 sc->bps = 1;
     667           0 :         else if (sc->bps > 4)
     668           0 :                 sc->bps = 4;
     669           0 :         if (sc->rate < 4000)
     670           0 :                 sc->rate = 4000;
     671           0 :         else if (sc->rate > 192000)
     672           0 :                 sc->rate = 192000;
     673             : 
     674             :         /*
     675             :          * copy into struct audio_params, required by drivers
     676             :          */
     677           0 :         p.encoding = r.encoding = sc->sw_enc;
     678           0 :         p.precision = r.precision = sc->bits;
     679           0 :         p.bps = r.bps = sc->bps;
     680           0 :         p.msb = r.msb = sc->msb;
     681           0 :         p.sample_rate = r.sample_rate = sc->rate;
     682           0 :         p.channels = sc->pchan;
     683           0 :         r.channels = sc->rchan;
     684             : 
     685             :         /*
     686             :          * set parameters
     687             :          */
     688           0 :         error = sc->ops->set_params(sc->arg, sc->mode, sc->mode, &p, &r);
     689           0 :         if (error)
     690           0 :                 return error;
     691           0 :         if (sc->mode == (AUMODE_PLAY | AUMODE_RECORD)) {
     692           0 :                 if (p.encoding != r.encoding ||
     693           0 :                     p.precision != r.precision ||
     694           0 :                     p.bps != r.bps ||
     695           0 :                     p.msb != r.msb ||
     696           0 :                     p.sample_rate != r.sample_rate) {
     697           0 :                         printf("%s: different play and record parameters "
     698           0 :                             "returned by hardware\n", DEVNAME(sc));
     699           0 :                         return ENODEV;
     700             :                 }
     701             :         }
     702           0 :         if (sc->mode & AUMODE_PLAY) {
     703           0 :                 sc->hw_enc = p.encoding;
     704           0 :                 sc->bits = p.precision;
     705           0 :                 sc->bps = p.bps;
     706           0 :                 sc->msb = p.msb;
     707           0 :                 sc->rate = p.sample_rate;
     708           0 :                 sc->pchan = p.channels;
     709           0 :         }
     710           0 :         if (sc->mode & AUMODE_RECORD) {
     711           0 :                 sc->hw_enc = r.encoding;
     712           0 :                 sc->bits = r.precision;
     713           0 :                 sc->bps = r.bps;
     714           0 :                 sc->msb = r.msb;
     715           0 :                 sc->rate = r.sample_rate;
     716           0 :                 sc->rchan = r.channels;
     717           0 :         }
     718           0 :         if (sc->rate == 0 || sc->bps == 0 || sc->bits == 0) {
     719           0 :                 printf("%s: invalid parameters returned by hardware\n",
     720           0 :                     DEVNAME(sc));
     721           0 :                 return ENODEV;
     722             :         }
     723           0 :         if (sc->ops->commit_settings) {
     724           0 :                 error = sc->ops->commit_settings(sc->arg);
     725           0 :                 if (error)
     726           0 :                         return error;
     727             :         }
     728             : 
     729             :         /*
     730             :          * conversion from/to exotic/dead encoding, for drivers not supporting
     731             :          * linear
     732             :          */
     733           0 :         switch (sc->hw_enc) {
     734             :         case AUDIO_ENCODING_SLINEAR_LE:
     735             :         case AUDIO_ENCODING_SLINEAR_BE:
     736             :         case AUDIO_ENCODING_ULINEAR_LE:
     737             :         case AUDIO_ENCODING_ULINEAR_BE:
     738           0 :                 sc->sw_enc = sc->hw_enc;
     739           0 :                 sc->conv_dec = sc->conv_enc = NULL;
     740           0 :                 break;
     741             :         case AUDIO_ENCODING_ULAW:
     742             : #if BYTE_ORDER == LITTLE_ENDIAN
     743           0 :                 sc->sw_enc = AUDIO_ENCODING_SLINEAR_LE;
     744             : #else
     745             :                 sc->sw_enc = AUDIO_ENCODING_SLINEAR_BE;
     746             : #endif
     747           0 :                 if (sc->bits == 8) {
     748           0 :                         sc->conv_enc = slinear8_to_mulaw;
     749           0 :                         sc->conv_dec = mulaw_to_slinear8;
     750           0 :                 } else if (sc->bits == 24) {
     751           0 :                         sc->conv_enc = slinear24_to_mulaw24;
     752           0 :                         sc->conv_dec = mulaw24_to_slinear24;
     753           0 :                 } else {
     754           0 :                         sc->sw_enc = sc->hw_enc;
     755           0 :                         sc->conv_dec = sc->conv_enc = NULL;
     756             :                 }
     757             :                 break;
     758             :         default:
     759           0 :                 printf("%s: setpar: enc = %d, bits = %d: emulation skipped\n",
     760           0 :                     DEVNAME(sc), sc->hw_enc, sc->bits);
     761           0 :                 sc->sw_enc = sc->hw_enc;
     762           0 :                 sc->conv_dec = sc->conv_enc = NULL;
     763           0 :         }
     764           0 :         audio_calc_sil(sc);
     765             : 
     766             :         /*
     767             :          * get least multiplier of the number of frames per block
     768             :          */
     769           0 :         if (sc->ops->round_blocksize) {
     770           0 :                 blk_mult = sc->ops->round_blocksize(sc->arg, 1);
     771           0 :                 if (blk_mult == 0) {
     772           0 :                         printf("%s: 0x%x: bad block size multiplier\n",
     773           0 :                             DEVNAME(sc), blk_mult);
     774           0 :                         return ENODEV;
     775             :                 }
     776             :         } else
     777             :                 blk_mult = 1;
     778             :         DPRINTF("%s: hw block size multiplier: %u\n", DEVNAME(sc), blk_mult);
     779           0 :         if (sc->mode & AUMODE_PLAY) {
     780           0 :                 np = blk_mult / audio_gcd(sc->pchan * sc->bps, blk_mult);
     781           0 :                 if (!(sc->mode & AUMODE_RECORD))
     782           0 :                         nr = np;
     783             :                 DPRINTF("%s: play number of frames multiplier: %u\n",
     784             :                     DEVNAME(sc), np);
     785             :         }
     786           0 :         if (sc->mode & AUMODE_RECORD) {
     787           0 :                 nr = blk_mult / audio_gcd(sc->rchan * sc->bps, blk_mult);
     788           0 :                 if (!(sc->mode & AUMODE_PLAY))
     789           0 :                         np = nr;
     790             :                 DPRINTF("%s: record number of frames multiplier: %u\n",
     791             :                     DEVNAME(sc), nr);
     792             :         }
     793           0 :         mult = nr * np / audio_gcd(nr, np);
     794             :         DPRINTF("%s: least common number of frames multiplier: %u\n",
     795             :             DEVNAME(sc), mult);
     796             : 
     797             :         /*
     798             :          * get minimum and maximum frames per block
     799             :          */
     800           0 :         if (sc->ops->round_blocksize)
     801           0 :                 blk_max = sc->ops->round_blocksize(sc->arg, AUDIO_BUFSZ);
     802             :         else
     803             :                 blk_max = AUDIO_BUFSZ;
     804           0 :         if ((sc->mode & AUMODE_PLAY) && blk_max > sc->play.datalen / 2)
     805           0 :                 blk_max = sc->play.datalen / 2;
     806           0 :         if ((sc->mode & AUMODE_RECORD) && blk_max > sc->rec.datalen / 2)
     807           0 :                 blk_max = sc->rec.datalen / 2;
     808           0 :         if (sc->mode & AUMODE_PLAY) {
     809           0 :                 np = blk_max / (sc->pchan * sc->bps);
     810           0 :                 if (!(sc->mode & AUMODE_RECORD))
     811           0 :                         nr = np;
     812             :         }
     813           0 :         if (sc->mode & AUMODE_RECORD) {
     814           0 :                 nr = blk_max / (sc->rchan * sc->bps);
     815           0 :                 if (!(sc->mode & AUMODE_PLAY))
     816           0 :                         np = nr;
     817             :         }
     818           0 :         max = np < nr ? np : nr;
     819           0 :         max -= max % mult;
     820           0 :         min = sc->rate / 1000 + mult - 1;
     821           0 :         min -= min % mult;
     822             :         DPRINTF("%s: frame number range: %u..%u\n", DEVNAME(sc), min, max);
     823           0 :         if (max < min) {
     824           0 :                 printf("%s: %u: bad max frame number\n", DEVNAME(sc), max);
     825           0 :                 return EIO;
     826             :         }
     827             : 
     828             :         /*
     829             :          * adjust the frame per block to match our constraints
     830             :          */
     831           0 :         sc->round += mult / 2;
     832           0 :         sc->round -= sc->round % mult;
     833           0 :         if (sc->round > max)
     834           0 :                 sc->round = max;
     835           0 :         else if (sc->round < min)
     836           0 :                 sc->round = min;
     837             : 
     838             :         /*
     839             :          * set buffer size (number of blocks)
     840             :          */
     841           0 :         if (sc->mode & AUMODE_PLAY) {
     842           0 :                 sc->play.blksz = sc->round * sc->pchan * sc->bps;
     843           0 :                 max = sc->play.datalen / sc->play.blksz;
     844           0 :                 if (sc->nblks > max)
     845           0 :                         sc->nblks = max;
     846           0 :                 else if (sc->nblks < 2)
     847           0 :                         sc->nblks = 2;
     848           0 :                 sc->play.len = sc->nblks * sc->play.blksz;
     849           0 :                 sc->nblks = sc->nblks;
     850           0 :         }
     851           0 :         if (sc->mode & AUMODE_RECORD) {
     852             :                 /*
     853             :                  * for recording, buffer size is not the latency (it's
     854             :                  * exactly one block), so let's get the maximum buffer
     855             :                  * size of maximum reliability during xruns
     856             :                  */
     857           0 :                 sc->rec.blksz = sc->round * sc->rchan * sc->bps;
     858           0 :                 sc->rec.len = sc->rec.datalen;
     859           0 :                 sc->rec.len -= sc->rec.datalen % sc->rec.blksz;
     860           0 :         }
     861             : 
     862             :         DPRINTF("%s: setpar: new enc=%d bits=%d, bps=%d, msb=%d "
     863             :             "rate=%d, pchan=%d, rchan=%d, round=%u, nblks=%d\n",
     864             :             DEVNAME(sc), sc->sw_enc, sc->bits, sc->bps, sc->msb,
     865             :             sc->rate, sc->pchan, sc->rchan, sc->round, sc->nblks);
     866           0 :         return 0;
     867           0 : }
     868             : 
     869             : int
     870           0 : audio_ioc_start(struct audio_softc *sc)
     871             : {
     872           0 :         if (!sc->pause) {
     873             :                 DPRINTF("%s: can't start: already started\n", DEVNAME(sc));
     874           0 :                 return EBUSY;
     875             :         }
     876           0 :         if ((sc->mode & AUMODE_PLAY) && sc->play.used != sc->play.len) {
     877             :                 DPRINTF("%s: play buffer not ready\n", DEVNAME(sc));
     878           0 :                 return EBUSY;
     879             :         }
     880           0 :         if ((sc->mode & AUMODE_RECORD) && sc->rec.used != 0) {
     881             :                 DPRINTF("%s: record buffer not ready\n", DEVNAME(sc));
     882           0 :                 return EBUSY;
     883             :         }
     884           0 :         sc->pause = 0;
     885           0 :         return audio_start(sc);
     886           0 : }
     887             : 
     888             : int
     889           0 : audio_ioc_stop(struct audio_softc *sc)
     890             : {
     891           0 :         if (sc->pause) {
     892             :                 DPRINTF("%s: can't stop: not started\n", DEVNAME(sc));
     893           0 :                 return EBUSY;
     894             :         }
     895           0 :         sc->pause = 1;
     896           0 :         if (sc->active)
     897           0 :                 return audio_stop(sc);
     898           0 :         return 0;
     899           0 : }
     900             : 
     901             : int
     902           0 : audio_ioc_getpar(struct audio_softc *sc, struct audio_swpar *p)
     903             : {
     904           0 :         p->rate = sc->rate;
     905           0 :         p->sig = sc->sw_enc == AUDIO_ENCODING_SLINEAR_LE ||
     906           0 :             sc->sw_enc == AUDIO_ENCODING_SLINEAR_BE;
     907           0 :         p->le = sc->sw_enc == AUDIO_ENCODING_SLINEAR_LE ||
     908           0 :             sc->sw_enc == AUDIO_ENCODING_ULINEAR_LE;
     909           0 :         p->bits = sc->bits;
     910           0 :         p->bps = sc->bps;
     911           0 :         p->msb = sc->msb;
     912           0 :         p->pchan = sc->pchan;
     913           0 :         p->rchan = sc->rchan;
     914           0 :         p->nblks = sc->nblks;
     915           0 :         p->round = sc->round;
     916           0 :         return 0;
     917             : }
     918             : 
     919             : int
     920           0 : audio_ioc_setpar(struct audio_softc *sc, struct audio_swpar *p)
     921             : {
     922             :         int error, le, sig;
     923             : 
     924           0 :         if (sc->active) {
     925             :                 DPRINTF("%s: can't change params during dma\n",
     926             :                     DEVNAME(sc));
     927           0 :                 return EBUSY;
     928             :         }
     929             : 
     930             :         /*
     931             :          * copy desired parameters into the softc structure
     932             :          */
     933           0 :         if (p->sig != ~0U || p->le != ~0U || p->bits != ~0U) {
     934             :                 sig = 1;
     935             :                 le = (BYTE_ORDER == LITTLE_ENDIAN);
     936           0 :                 sc->bits = 16;
     937           0 :                 sc->bps = 2;
     938           0 :                 sc->msb = 1;
     939           0 :                 if (p->sig != ~0U)
     940           0 :                         sig = p->sig;
     941           0 :                 if (p->le != ~0U)
     942           0 :                         le = p->le;
     943           0 :                 if (p->bits != ~0U) {
     944           0 :                         sc->bits = p->bits;
     945           0 :                         sc->bps = sc->bits <= 8 ?
     946           0 :                             1 : (sc->bits <= 16 ? 2 : 4);
     947           0 :                         if (p->bps != ~0U)
     948           0 :                                 sc->bps = p->bps;
     949           0 :                         if (p->msb != ~0U)
     950           0 :                                 sc->msb = p->msb ? 1 : 0;
     951             :                 }
     952           0 :                 sc->sw_enc = (sig) ?
     953           0 :                     (le ? AUDIO_ENCODING_SLINEAR_LE :
     954             :                         AUDIO_ENCODING_SLINEAR_BE) :
     955           0 :                     (le ? AUDIO_ENCODING_ULINEAR_LE :
     956             :                         AUDIO_ENCODING_ULINEAR_BE);
     957           0 :         }
     958           0 :         if (p->rate != ~0)
     959           0 :                 sc->rate = p->rate;
     960           0 :         if (p->pchan != ~0)
     961           0 :                 sc->pchan = p->pchan;
     962           0 :         if (p->rchan != ~0)
     963           0 :                 sc->rchan = p->rchan;
     964           0 :         if (p->round != ~0)
     965           0 :                 sc->round = p->round;
     966           0 :         if (p->nblks != ~0)
     967           0 :                 sc->nblks = p->nblks;
     968             : 
     969             :         /*
     970             :          * if the device is not opened for playback or recording don't
     971             :          * touch the hardware yet (ex. if this is /dev/audioctlN)
     972             :          */
     973           0 :         if (sc->mode == 0)
     974           0 :                 return 0;
     975             : 
     976             :         /*
     977             :          * negociate parameters with the hardware
     978             :          */
     979           0 :         error = audio_setpar(sc);
     980           0 :         if (error)
     981           0 :                 return error;
     982           0 :         audio_clear(sc);
     983           0 :         if ((sc->mode & AUMODE_PLAY) && sc->ops->init_output) {
     984           0 :                 error = sc->ops->init_output(sc->arg,
     985           0 :                     sc->play.data, sc->play.len);
     986           0 :                 if (error)
     987           0 :                         return error;
     988             :         }
     989           0 :         if ((sc->mode & AUMODE_RECORD) && sc->ops->init_input) {
     990           0 :                 error = sc->ops->init_input(sc->arg,
     991           0 :                     sc->rec.data, sc->rec.len);
     992           0 :                 if (error)
     993           0 :                         return error;
     994             :         }
     995           0 :         return 0;
     996           0 : }
     997             : 
     998             : int
     999           0 : audio_ioc_getstatus(struct audio_softc *sc, struct audio_status *p)
    1000             : {
    1001           0 :         p->mode = sc->mode;
    1002           0 :         p->pause = sc->pause;
    1003           0 :         p->active = sc->active;
    1004           0 :         return 0;
    1005             : }
    1006             : 
    1007             : int
    1008           0 : audio_match(struct device *parent, void *match, void *aux)
    1009             : {
    1010           0 :         struct audio_attach_args *sa = aux;
    1011             : 
    1012           0 :         return (sa->type == AUDIODEV_TYPE_AUDIO) ? 1 : 0;
    1013             : }
    1014             : 
    1015             : void
    1016           0 : audio_attach(struct device *parent, struct device *self, void *aux)
    1017             : {
    1018           0 :         struct audio_softc *sc = (void *)self;
    1019           0 :         struct audio_attach_args *sa = aux;
    1020           0 :         struct audio_hw_if *ops = sa->hwif;
    1021             :         struct mixer_devinfo *mi;
    1022             :         struct mixer_ctrl *ent;
    1023           0 :         void *arg = sa->hdl;
    1024             :         int error;
    1025             : 
    1026           0 :         printf("\n");
    1027             : 
    1028             : #ifdef DIAGNOSTIC
    1029           0 :         if (ops == 0 ||
    1030           0 :             ops->open == 0 ||
    1031           0 :             ops->close == 0 ||
    1032           0 :             ops->set_params == 0 ||
    1033           0 :             (ops->start_output == 0 && ops->trigger_output == 0) ||
    1034           0 :             (ops->start_input == 0 && ops->trigger_input == 0) ||
    1035           0 :             ops->halt_output == 0 ||
    1036           0 :             ops->halt_input == 0 ||
    1037           0 :             ops->set_port == 0 ||
    1038           0 :             ops->get_port == 0 ||
    1039           0 :             ops->query_devinfo == 0 ||
    1040           0 :             ops->get_props == 0) {
    1041           0 :                 printf("%s: missing method\n", DEVNAME(sc));
    1042           0 :                 sc->ops = 0;
    1043           0 :                 return;
    1044             :         }
    1045             : #endif
    1046           0 :         sc->ops = ops;
    1047           0 :         sc->arg = arg;
    1048             : 
    1049             : #if NWSKBD > 0
    1050           0 :         wskbd_mixer_init(sc);
    1051             : #endif /* NWSKBD > 0 */
    1052             : 
    1053           0 :         error = audio_buf_init(sc, &sc->play, AUMODE_PLAY);
    1054           0 :         if (error) {
    1055           0 :                 sc->ops = 0;
    1056           0 :                 printf("%s: could not allocate play buffer\n", DEVNAME(sc));
    1057           0 :                 return;
    1058             :         }
    1059           0 :         error = audio_buf_init(sc, &sc->rec, AUMODE_RECORD);
    1060           0 :         if (error) {
    1061           0 :                 audio_buf_done(sc, &sc->play);
    1062           0 :                 sc->ops = 0;
    1063           0 :                 printf("%s: could not allocate record buffer\n", DEVNAME(sc));
    1064           0 :                 return;
    1065             :         }
    1066             : 
    1067             :         /* set defaults */
    1068             : #if BYTE_ORDER == LITTLE_ENDIAN
    1069           0 :         sc->sw_enc = AUDIO_ENCODING_SLINEAR_LE;
    1070             : #else
    1071             :         sc->sw_enc = AUDIO_ENCODING_SLINEAR_BE;
    1072             : #endif
    1073           0 :         sc->bits = 16;
    1074           0 :         sc->bps = 2;
    1075           0 :         sc->msb = 1;
    1076           0 :         sc->rate = 48000;
    1077           0 :         sc->pchan = 2;
    1078           0 :         sc->rchan = 2;
    1079           0 :         sc->round = 960;
    1080           0 :         sc->nblks = 2;
    1081           0 :         sc->play.pos = sc->play.xrun = sc->rec.pos = sc->rec.xrun = 0;
    1082           0 :         sc->record_enable = MIXER_RECORD_ENABLE_SYSCTL;
    1083             : 
    1084             :         /*
    1085             :          * allocate an array of mixer_ctrl structures to save the
    1086             :          * mixer state and prefill them.
    1087             :          */
    1088             : 
    1089           0 :         mi = malloc(sizeof(struct mixer_devinfo), M_TEMP, M_WAITOK);
    1090             : 
    1091           0 :         mi->index = 0;
    1092           0 :         while (1) {
    1093           0 :                 if (sc->ops->query_devinfo(sc->arg, mi) != 0)
    1094             :                         break;
    1095           0 :                 mi->index++;
    1096             :         }
    1097           0 :         sc->mix_nent = mi->index;
    1098           0 :         sc->mix_ents = mallocarray(sc->mix_nent,
    1099             :             sizeof(struct mixer_ctrl), M_DEVBUF, M_WAITOK);
    1100             : 
    1101             :         ent = sc->mix_ents;
    1102           0 :         mi->index = 0;
    1103           0 :         while (1) {
    1104           0 :                 if (sc->ops->query_devinfo(sc->arg, mi) != 0)
    1105             :                         break;
    1106           0 :                 switch (mi->type) {
    1107             :                 case AUDIO_MIXER_VALUE:
    1108           0 :                         ent->un.value.num_channels = mi->un.v.num_channels;
    1109             :                         /* FALLTHROUGH */
    1110             :                 case AUDIO_MIXER_SET:
    1111             :                 case AUDIO_MIXER_ENUM:
    1112           0 :                         ent->dev = mi->index;
    1113           0 :                         ent->type = mi->type;
    1114           0 :                 }
    1115           0 :                 mi->index++;
    1116           0 :                 ent++;
    1117             :         }
    1118             : 
    1119           0 :         free(mi, M_TEMP, sizeof(struct mixer_devinfo));
    1120           0 : }
    1121             : 
    1122             : int
    1123           0 : audio_activate(struct device *self, int act)
    1124             : {
    1125           0 :         struct audio_softc *sc = (struct audio_softc *)self;
    1126             :         int i;
    1127             : 
    1128           0 :         switch (act) {
    1129             :         case DVACT_QUIESCE:
    1130             :                 /*
    1131             :                  * good drivers run play and rec handlers in a single
    1132             :                  * interrupt. Grab the lock to ensure we expose the same
    1133             :                  * sc->quiesce value to both play and rec handlers
    1134             :                  */
    1135           0 :                 mtx_enter(&audio_lock);
    1136           0 :                 sc->quiesce = 1;
    1137           0 :                 mtx_leave(&audio_lock);
    1138             : 
    1139             :                 /*
    1140             :                  * once sc->quiesce is set, interrupts may occur, but
    1141             :                  * counters are not advanced and consequently processes
    1142             :                  * keep sleeping.
    1143             :                  *
    1144             :                  * XXX: ensure read/write/ioctl don't start/stop
    1145             :                  * DMA at the same time, this needs a "ready" condvar
    1146             :                  */
    1147           0 :                 if (sc->mode != 0 && sc->active)
    1148           0 :                         audio_stop_do(sc);
    1149             : 
    1150             :                 /*
    1151             :                  * save mixer state
    1152             :                  */
    1153           0 :                 for (i = 0; i != sc->mix_nent; i++)
    1154           0 :                         sc->ops->get_port(sc->arg, sc->mix_ents + i);
    1155             : 
    1156             :                 DPRINTF("%s: quiesce: active = %d\n", DEVNAME(sc), sc->active);
    1157             :                 break;
    1158             :         case DVACT_WAKEUP:
    1159             :                 DPRINTF("%s: wakeup: active = %d\n", DEVNAME(sc), sc->active);
    1160             : 
    1161             :                 /*
    1162             :                  * restore mixer state
    1163             :                  */
    1164           0 :                 for (i = 0; i != sc->mix_nent; i++)
    1165           0 :                         sc->ops->set_port(sc->arg, sc->mix_ents + i);
    1166             : 
    1167             :                 /*
    1168             :                  * keep buffer usage the same, but set start pointer to
    1169             :                  * the beginning of the buffer.
    1170             :                  *
    1171             :                  * No need to grab the audio_lock as DMA is stopped and
    1172             :                  * this is the only thread running (caller ensures this)
    1173             :                  */
    1174           0 :                 sc->quiesce = 0;
    1175           0 :                 wakeup(&sc->quiesce);
    1176             : 
    1177           0 :                 if (sc->mode != 0) {
    1178           0 :                         if (audio_setpar(sc) != 0)
    1179             :                                 break;
    1180           0 :                         if (sc->mode & AUMODE_PLAY) {
    1181           0 :                                 sc->play.start = 0;
    1182           0 :                                 audio_fill_sil(sc, sc->play.data, sc->play.len);
    1183           0 :                         }
    1184           0 :                         if (sc->mode & AUMODE_RECORD) {
    1185           0 :                                 sc->rec.start = sc->rec.len - sc->rec.used;
    1186           0 :                                 audio_fill_sil(sc, sc->rec.data, sc->rec.len);
    1187           0 :                         }
    1188           0 :                         if (sc->active)
    1189           0 :                                 audio_start_do(sc);
    1190             :                 }
    1191             :                 break;
    1192             :         }
    1193           0 :         return 0;
    1194             : }
    1195             : 
    1196             : int
    1197           0 : audio_detach(struct device *self, int flags)
    1198             : {
    1199           0 :         struct audio_softc *sc = (struct audio_softc *)self;
    1200             :         int maj, mn;
    1201             : 
    1202             :         DPRINTF("%s: audio_detach: flags = %d\n", DEVNAME(sc), flags);
    1203             : 
    1204           0 :         wakeup(&sc->quiesce);
    1205             : 
    1206             :         /* locate the major number */
    1207           0 :         for (maj = 0; maj < nchrdev; maj++)
    1208           0 :                 if (cdevsw[maj].d_open == audioopen)
    1209             :                         break;
    1210             :         /*
    1211             :          * Nuke the vnodes for any open instances, calls close but as
    1212             :          * close uses device_lookup, it returns EXIO and does nothing
    1213             :          */
    1214           0 :         mn = self->dv_unit;
    1215           0 :         vdevgone(maj, mn | AUDIO_DEV_AUDIO, mn | AUDIO_DEV_AUDIO, VCHR);
    1216           0 :         vdevgone(maj, mn | AUDIO_DEV_AUDIOCTL, mn | AUDIO_DEV_AUDIOCTL, VCHR);
    1217           0 :         vdevgone(maj, mn | AUDIO_DEV_MIXER, mn | AUDIO_DEV_MIXER, VCHR);
    1218             : 
    1219             :         /*
    1220             :          * The close() method did nothing, quickly halt DMA (normally
    1221             :          * parent is already gone, and code below is no-op), and wake-up
    1222             :          * user-land blocked in read/write/ioctl, which return EIO.
    1223             :          */
    1224           0 :         if (sc->mode != 0) {
    1225           0 :                 if (sc->active) {
    1226           0 :                         wakeup(&sc->play.blocking);
    1227           0 :                         selwakeup(&sc->play.sel);
    1228           0 :                         wakeup(&sc->rec.blocking);
    1229           0 :                         selwakeup(&sc->rec.sel);
    1230           0 :                         audio_stop(sc);
    1231           0 :                 }
    1232           0 :                 sc->ops->close(sc->arg);
    1233           0 :                 sc->mode = 0;
    1234           0 :         }
    1235             : 
    1236             :         /* free resources */
    1237           0 :         free(sc->mix_ents, M_DEVBUF, sc->mix_nent * sizeof(struct mixer_ctrl));
    1238           0 :         audio_buf_done(sc, &sc->play);
    1239           0 :         audio_buf_done(sc, &sc->rec);
    1240           0 :         return 0;
    1241             : }
    1242             : 
    1243             : int
    1244           0 : audio_submatch(struct device *parent, void *match, void *aux)
    1245             : {
    1246           0 :         struct cfdata *cf = match;
    1247             : 
    1248           0 :         return (cf->cf_driver == &audio_cd);
    1249             : }
    1250             : 
    1251             : struct device *
    1252           0 : audio_attach_mi(struct audio_hw_if *ops, void *arg, struct device *dev)
    1253             : {
    1254           0 :         struct audio_attach_args aa;
    1255             : 
    1256           0 :         aa.type = AUDIODEV_TYPE_AUDIO;
    1257           0 :         aa.hwif = ops;
    1258           0 :         aa.hdl = arg;
    1259             : 
    1260             :         /*
    1261             :          * attach this driver to the caller (hardware driver), this
    1262             :          * checks the kernel config and possibly calls audio_attach()
    1263             :          */
    1264           0 :         return config_found_sm(dev, &aa, audioprint, audio_submatch);
    1265           0 : }
    1266             : 
    1267             : int
    1268           0 : audioprint(void *aux, const char *pnp)
    1269             : {
    1270           0 :         struct audio_attach_args *arg = aux;
    1271             :         const char *type;
    1272             : 
    1273           0 :         if (pnp != NULL) {
    1274           0 :                 switch (arg->type) {
    1275             :                 case AUDIODEV_TYPE_AUDIO:
    1276             :                         type = "audio";
    1277           0 :                         break;
    1278             :                 case AUDIODEV_TYPE_OPL:
    1279             :                         type = "opl";
    1280           0 :                         break;
    1281             :                 case AUDIODEV_TYPE_MPU:
    1282             :                         type = "mpu";
    1283           0 :                         break;
    1284             :                 default:
    1285           0 :                         panic("audioprint: unknown type %d", arg->type);
    1286             :                 }
    1287           0 :                 printf("%s at %s", type, pnp);
    1288           0 :         }
    1289           0 :         return UNCONF;
    1290             : }
    1291             : 
    1292             : int
    1293           0 : audio_open(struct audio_softc *sc, int flags)
    1294             : {
    1295             :         int error;
    1296             :         int props;
    1297             : 
    1298           0 :         if (sc->mode)
    1299           0 :                 return EBUSY;
    1300           0 :         error = sc->ops->open(sc->arg, flags);
    1301           0 :         if (error)
    1302           0 :                 return error;
    1303           0 :         sc->active = 0;
    1304           0 :         sc->pause = 1;
    1305           0 :         sc->rec.blocking = 0;
    1306           0 :         sc->play.blocking = 0;
    1307           0 :         sc->mode = 0;
    1308           0 :         if (flags & FWRITE)
    1309           0 :                 sc->mode |= AUMODE_PLAY;
    1310           0 :         if (flags & FREAD)
    1311           0 :                 sc->mode |= AUMODE_RECORD;
    1312           0 :         props = sc->ops->get_props(sc->arg);
    1313           0 :         if (sc->mode == (AUMODE_PLAY | AUMODE_RECORD)) {
    1314           0 :                 if (!(props & AUDIO_PROP_FULLDUPLEX)) {
    1315             :                         error = ENOTTY;
    1316           0 :                         goto bad;
    1317             :                 }
    1318           0 :                 if (sc->ops->setfd) {
    1319           0 :                         error = sc->ops->setfd(sc->arg, 1);
    1320           0 :                         if (error)
    1321             :                                 goto bad;
    1322             :                 }
    1323             :         }
    1324             : 
    1325           0 :         if (sc->ops->speaker_ctl) {
    1326             :                 /*
    1327             :                  * XXX: what is this used for?
    1328             :                  */
    1329           0 :                 sc->ops->speaker_ctl(sc->arg,
    1330           0 :                     (sc->mode & AUMODE_PLAY) ? SPKR_ON : SPKR_OFF);
    1331           0 :         }
    1332             : 
    1333           0 :         error = audio_setpar(sc);
    1334           0 :         if (error)
    1335             :                 goto bad;
    1336           0 :         audio_clear(sc);
    1337             : 
    1338             :         /*
    1339             :          * allow read(2)/write(2) to automatically start DMA, without
    1340             :          * the need for ioctl(), to make /dev/audio usable in scripts
    1341             :          */
    1342           0 :         sc->pause = 0;
    1343           0 :         return 0;
    1344             : bad:
    1345           0 :         sc->ops->close(sc->arg);
    1346           0 :         sc->mode = 0;
    1347           0 :         return error;
    1348           0 : }
    1349             : 
    1350             : int
    1351           0 : audio_drain(struct audio_softc *sc)
    1352             : {
    1353             :         int error, xrun;
    1354             :         unsigned char *ptr;
    1355           0 :         size_t count, bpf;
    1356             : 
    1357             :         DPRINTF("%s: drain: mode = %d, pause = %d, active = %d, used = %zu\n",
    1358             :             DEVNAME(sc), sc->mode, sc->pause, sc->active, sc->play.used);
    1359           0 :         if (!(sc->mode & AUMODE_PLAY) || sc->pause)
    1360           0 :                 return 0;
    1361             : 
    1362             :         /* discard partial samples, required by audio_fill_sil() */
    1363           0 :         mtx_enter(&audio_lock);
    1364           0 :         bpf = sc->pchan * sc->bps;
    1365           0 :         sc->play.used -= sc->play.used % bpf;
    1366           0 :         if (sc->play.used == 0) {
    1367           0 :                 mtx_leave(&audio_lock);
    1368           0 :                 return 0;
    1369             :         }
    1370             : 
    1371           0 :         if (!sc->active) {
    1372             :                 /*
    1373             :                  * dma not started yet because buffer was not full
    1374             :                  * enough to start automatically. Pad it and start now.
    1375             :                  */
    1376           0 :                 for (;;) {
    1377           0 :                         ptr = audio_buf_wgetblk(&sc->play, &count);
    1378           0 :                         if (count == 0)
    1379             :                                 break;
    1380           0 :                         audio_fill_sil(sc, ptr, count);
    1381           0 :                         audio_buf_wcommit(&sc->play, count);
    1382             :                 }
    1383           0 :                 mtx_leave(&audio_lock);
    1384           0 :                 error = audio_start(sc);
    1385           0 :                 if (error)
    1386           0 :                         return error;
    1387           0 :                 mtx_enter(&audio_lock);
    1388           0 :         }
    1389             : 
    1390           0 :         xrun = sc->play.xrun;
    1391           0 :         while (sc->play.xrun == xrun) {
    1392             :                 DPRINTF("%s: drain: used = %zu, xrun = %d\n",
    1393             :                     DEVNAME(sc), sc->play.used, sc->play.xrun);
    1394             : 
    1395             :                 /*
    1396             :                  * set a 5 second timeout, in case interrupts don't
    1397             :                  * work, useful only for debugging drivers
    1398             :                  */
    1399           0 :                 sc->play.blocking = 1;
    1400           0 :                 error = msleep(&sc->play.blocking, &audio_lock,
    1401           0 :                     PWAIT | PCATCH, "au_dr", 5 * hz);
    1402           0 :                 if (!(sc->dev.dv_flags & DVF_ACTIVE))
    1403             :                         error = EIO;
    1404           0 :                 if (error) {
    1405             :                         DPRINTF("%s: drain, err = %d\n", DEVNAME(sc), error);
    1406             :                         break;
    1407             :                 }
    1408             :         }
    1409           0 :         mtx_leave(&audio_lock);
    1410           0 :         return error;
    1411           0 : }
    1412             : 
    1413             : int
    1414           0 : audio_close(struct audio_softc *sc)
    1415             : {
    1416           0 :         audio_drain(sc);
    1417           0 :         if (sc->active)
    1418           0 :                 audio_stop(sc);
    1419           0 :         sc->ops->close(sc->arg);
    1420           0 :         sc->mode = 0;
    1421             :         DPRINTF("%s: close: done\n", DEVNAME(sc));
    1422           0 :         return 0;
    1423             : }
    1424             : 
    1425             : int
    1426           0 : audio_read(struct audio_softc *sc, struct uio *uio, int ioflag)
    1427             : {
    1428             :         unsigned char *ptr;
    1429           0 :         size_t count;
    1430             :         int error;
    1431             : 
    1432             :         DPRINTFN(1, "%s: read: resid = %zd\n", DEVNAME(sc), uio->uio_resid);
    1433             : 
    1434             :         /* block if quiesced */
    1435           0 :         while (sc->quiesce)
    1436           0 :                 tsleep(&sc->quiesce, 0, "au_qrd", 0);
    1437             : 
    1438             :         /* start automatically if audio_ioc_start() was never called */
    1439           0 :         if (audio_canstart(sc)) {
    1440           0 :                 error = audio_start(sc);
    1441           0 :                 if (error)
    1442           0 :                         return error;
    1443             :         }
    1444             : 
    1445           0 :         mtx_enter(&audio_lock);
    1446             : 
    1447             :         /* if there is no data then sleep */
    1448           0 :         while (sc->rec.used == 0) {
    1449           0 :                 if (ioflag & IO_NDELAY) {
    1450           0 :                         mtx_leave(&audio_lock);
    1451           0 :                         return EWOULDBLOCK;
    1452             :                 }
    1453             :                 DPRINTFN(1, "%s: read sleep\n", DEVNAME(sc));
    1454           0 :                 sc->rec.blocking = 1;
    1455           0 :                 error = msleep(&sc->rec.blocking,
    1456             :                     &audio_lock, PWAIT | PCATCH, "au_rd", 0);
    1457           0 :                 if (!(sc->dev.dv_flags & DVF_ACTIVE))
    1458             :                         error = EIO;
    1459           0 :                 if (error) {
    1460             :                         DPRINTF("%s: read woke up error = %d\n",
    1461             :                             DEVNAME(sc), error);
    1462           0 :                         mtx_leave(&audio_lock);
    1463           0 :                         return error;
    1464             :                 }
    1465             :         }
    1466             : 
    1467             :         /* at this stage, there is data to transfer */
    1468           0 :         while (uio->uio_resid > 0 && sc->rec.used > 0) {
    1469           0 :                 ptr = audio_buf_rgetblk(&sc->rec, &count);
    1470           0 :                 if (count > uio->uio_resid)
    1471           0 :                         count = uio->uio_resid;
    1472           0 :                 audio_buf_rdiscard(&sc->rec, count);
    1473           0 :                 mtx_leave(&audio_lock);
    1474             :                 DPRINTFN(1, "%s: read: start = %zu, count = %zu\n",
    1475             :                     DEVNAME(sc), ptr - sc->rec.data, count);
    1476           0 :                 if (sc->conv_dec)
    1477           0 :                         sc->conv_dec(ptr, count);
    1478           0 :                 error = uiomove(ptr, count, uio);
    1479           0 :                 if (error)
    1480           0 :                         return error;
    1481           0 :                 mtx_enter(&audio_lock);
    1482             :         }
    1483           0 :         mtx_leave(&audio_lock);
    1484           0 :         return 0;
    1485           0 : }
    1486             : 
    1487             : int
    1488           0 : audio_write(struct audio_softc *sc, struct uio *uio, int ioflag)
    1489             : {
    1490             :         unsigned char *ptr;
    1491           0 :         size_t count;
    1492             :         int error;
    1493             : 
    1494             :         DPRINTFN(1, "%s: write: resid = %zd\n",  DEVNAME(sc), uio->uio_resid);
    1495             : 
    1496             :         /* block if quiesced */
    1497           0 :         while (sc->quiesce)
    1498           0 :                 tsleep(&sc->quiesce, 0, "au_qwr", 0);
    1499             : 
    1500             :         /*
    1501             :          * if IO_NDELAY flag is set then check if there is enough room
    1502             :          * in the buffer to store at least one byte. If not then don't
    1503             :          * start the write process.
    1504             :          */
    1505           0 :         mtx_enter(&audio_lock);
    1506           0 :         if (uio->uio_resid > 0 && (ioflag & IO_NDELAY)) {
    1507           0 :                 if (sc->play.used == sc->play.len) {
    1508           0 :                         mtx_leave(&audio_lock);
    1509           0 :                         return EWOULDBLOCK;
    1510             :                 }
    1511             :         }
    1512             : 
    1513           0 :         while (uio->uio_resid > 0) {
    1514           0 :                 while (1) {
    1515           0 :                         ptr = audio_buf_wgetblk(&sc->play, &count);
    1516           0 :                         if (count > 0)
    1517             :                                 break;
    1518           0 :                         if (ioflag & IO_NDELAY) {
    1519             :                                 /*
    1520             :                                  * At this stage at least one byte is already
    1521             :                                  * moved so we do not return EWOULDBLOCK
    1522             :                                  */
    1523           0 :                                 mtx_leave(&audio_lock);
    1524           0 :                                 return 0;
    1525             :                         }
    1526             :                         DPRINTFN(1, "%s: write sleep\n", DEVNAME(sc));
    1527           0 :                         sc->play.blocking = 1;
    1528           0 :                         error = msleep(&sc->play.blocking,
    1529             :                             &audio_lock, PWAIT | PCATCH, "au_wr", 0);
    1530           0 :                         if (!(sc->dev.dv_flags & DVF_ACTIVE))
    1531             :                                 error = EIO;
    1532           0 :                         if (error) {
    1533             :                                 DPRINTF("%s: write woke up error = %d\n",
    1534             :                                     DEVNAME(sc), error);
    1535           0 :                                 mtx_leave(&audio_lock);
    1536           0 :                                 return error;
    1537             :                         }
    1538             :                 }
    1539           0 :                 if (count > uio->uio_resid)
    1540           0 :                         count = uio->uio_resid;
    1541           0 :                 audio_buf_wcommit(&sc->play, count);
    1542           0 :                 mtx_leave(&audio_lock);
    1543           0 :                 error = uiomove(ptr, count, uio);
    1544           0 :                 if (error)
    1545           0 :                         return 0;
    1546           0 :                 if (sc->conv_enc) {
    1547           0 :                         sc->conv_enc(ptr, count);
    1548             :                         DPRINTFN(1, "audio_write: converted count = %zu\n",
    1549             :                             count);
    1550           0 :                 }
    1551             : 
    1552             :                 /* start automatically if audio_ioc_start() was never called */
    1553           0 :                 if (audio_canstart(sc)) {
    1554           0 :                         error = audio_start(sc);
    1555           0 :                         if (error)
    1556           0 :                                 return error;
    1557             :                 }
    1558           0 :                 mtx_enter(&audio_lock);
    1559             :         }
    1560           0 :         mtx_leave(&audio_lock);
    1561           0 :         return 0;
    1562           0 : }
    1563             : 
    1564             : int
    1565           0 : audio_getdev(struct audio_softc *sc, struct audio_device *adev)
    1566             : {
    1567           0 :         memset(adev, 0, sizeof(struct audio_device));
    1568           0 :         if (sc->dev.dv_parent == NULL)
    1569           0 :                 return EIO;
    1570           0 :         strlcpy(adev->name, sc->dev.dv_parent->dv_xname, MAX_AUDIO_DEV_LEN);
    1571           0 :         return 0;
    1572           0 : }
    1573             : 
    1574             : int
    1575           0 : audio_ioctl(struct audio_softc *sc, unsigned long cmd, void *addr)
    1576             : {
    1577             :         struct audio_pos *ap;
    1578             :         int error = 0;
    1579             : 
    1580             :         /* block if quiesced */
    1581           0 :         while (sc->quiesce)
    1582           0 :                 tsleep(&sc->quiesce, 0, "au_qio", 0);
    1583             : 
    1584           0 :         switch (cmd) {
    1585             :         case FIONBIO:
    1586             :                 /* All handled in the upper FS layer. */
    1587             :                 break;
    1588             :         case AUDIO_GETPOS:
    1589           0 :                 mtx_enter(&audio_lock);
    1590           0 :                 ap = (struct audio_pos *)addr;
    1591           0 :                 ap->play_pos = sc->play.pos;
    1592           0 :                 ap->play_xrun = sc->play.xrun;
    1593           0 :                 ap->rec_pos = sc->rec.pos;
    1594           0 :                 ap->rec_xrun = sc->rec.xrun;
    1595           0 :                 mtx_leave(&audio_lock);
    1596           0 :                 break;
    1597             :         case AUDIO_START:
    1598           0 :                 return audio_ioc_start(sc);
    1599             :         case AUDIO_STOP:
    1600           0 :                 return audio_ioc_stop(sc);
    1601             :         case AUDIO_SETPAR:
    1602           0 :                 error = audio_ioc_setpar(sc, (struct audio_swpar *)addr);
    1603           0 :                 break;
    1604             :         case AUDIO_GETPAR:
    1605           0 :                 error = audio_ioc_getpar(sc, (struct audio_swpar *)addr);
    1606           0 :                 break;
    1607             :         case AUDIO_GETSTATUS:
    1608           0 :                 error = audio_ioc_getstatus(sc, (struct audio_status *)addr);
    1609           0 :                 break;
    1610             :         case AUDIO_GETDEV:
    1611           0 :                 error = audio_getdev(sc, (struct audio_device *)addr);
    1612           0 :                 break;
    1613             :         default:
    1614             :                 DPRINTF("%s: unknown ioctl 0x%lx\n", DEVNAME(sc), cmd);
    1615             :                 error = ENOTTY;
    1616           0 :                 break;
    1617             :         }
    1618           0 :         return error;
    1619           0 : }
    1620             : 
    1621             : int
    1622           0 : audio_mixer_devinfo(struct audio_softc *sc, struct mixer_devinfo *devinfo)
    1623             : {
    1624           0 :         if (devinfo->index < sc->mix_nent)
    1625           0 :                 return sc->ops->query_devinfo(sc->arg, devinfo);       
    1626             : 
    1627           0 :         devinfo->next = -1;
    1628           0 :         devinfo->prev = -1;
    1629           0 :         switch (devinfo->index - sc->mix_nent) {
    1630             :         case MIXER_RECORD:
    1631           0 :                 strlcpy(devinfo->label.name, AudioCrecord, MAX_AUDIO_DEV_LEN);
    1632           0 :                 devinfo->type = AUDIO_MIXER_CLASS;
    1633           0 :                 devinfo->mixer_class = -1;
    1634           0 :                 break;
    1635             :         case MIXER_RECORD_ENABLE:
    1636           0 :                 strlcpy(devinfo->label.name, "enable", MAX_AUDIO_DEV_LEN);
    1637           0 :                 devinfo->type = AUDIO_MIXER_ENUM;
    1638           0 :                 devinfo->mixer_class = MIXER_RECORD + sc->mix_nent;
    1639           0 :                 devinfo->un.e.num_mem = 3;
    1640           0 :                 devinfo->un.e.member[0].ord = MIXER_RECORD_ENABLE_OFF;
    1641           0 :                 strlcpy(devinfo->un.e.member[0].label.name, "off",
    1642             :                     MAX_AUDIO_DEV_LEN);
    1643           0 :                 devinfo->un.e.member[1].ord = MIXER_RECORD_ENABLE_ON;
    1644           0 :                 strlcpy(devinfo->un.e.member[1].label.name, "on",
    1645             :                     MAX_AUDIO_DEV_LEN);
    1646           0 :                 devinfo->un.e.member[2].ord = MIXER_RECORD_ENABLE_SYSCTL;
    1647           0 :                 strlcpy(devinfo->un.e.member[2].label.name, "sysctl",
    1648             :                     MAX_AUDIO_DEV_LEN);
    1649           0 :                 break;
    1650             :         default:
    1651           0 :                 return EINVAL;
    1652             :         }
    1653             : 
    1654           0 :         return 0;
    1655           0 : }
    1656             : 
    1657             : int
    1658           0 : audio_mixer_read(struct audio_softc *sc, struct mixer_ctrl *c)
    1659             : {
    1660           0 :         if (c->dev < sc->mix_nent)
    1661           0 :                 return sc->ops->get_port(sc->arg, c);
    1662             : 
    1663           0 :         switch (c->dev - sc->mix_nent) {
    1664             :         case MIXER_RECORD:
    1665           0 :                 return EBADF;
    1666             :         case MIXER_RECORD_ENABLE:
    1667           0 :                 c->un.ord = sc->record_enable;
    1668             :                 break;
    1669             :         default:
    1670           0 :                 return EINVAL;
    1671             :         }
    1672             : 
    1673           0 :         return 0;
    1674           0 : }
    1675             : 
    1676             : int
    1677           0 : audio_mixer_write(struct audio_softc *sc, struct mixer_ctrl *c, struct proc *p)
    1678             : {
    1679             :         int error;
    1680             : 
    1681           0 :         if (c->dev < sc->mix_nent) {
    1682           0 :                 error = sc->ops->set_port(sc->arg, c);
    1683           0 :                 if (error)
    1684           0 :                         return error;
    1685           0 :                 if (sc->ops->commit_settings)
    1686           0 :                         return sc->ops->commit_settings(sc->arg);
    1687           0 :                 return 0;
    1688             :         }
    1689             : 
    1690           0 :         switch (c->dev - sc->mix_nent) {
    1691             :         case MIXER_RECORD:
    1692           0 :                 return EBADF;
    1693             :         case MIXER_RECORD_ENABLE:
    1694           0 :                 switch (c->un.ord) {
    1695             :                 case MIXER_RECORD_ENABLE_OFF:
    1696             :                 case MIXER_RECORD_ENABLE_ON:
    1697             :                 case MIXER_RECORD_ENABLE_SYSCTL:
    1698             :                         break;
    1699             :                 default:
    1700           0 :                         return EINVAL;
    1701             :                 }
    1702           0 :                 if (suser(p) == 0)
    1703           0 :                         sc->record_enable = c->un.ord;
    1704             :                 break;
    1705             :         default:
    1706           0 :                 return EINVAL;
    1707             :         }
    1708             : 
    1709           0 :         return 0;
    1710           0 : }
    1711             : 
    1712             : int
    1713           0 : audio_ioctl_mixer(struct audio_softc *sc, unsigned long cmd, void *addr,
    1714             :         struct proc *p)
    1715             : {
    1716             :         /* block if quiesced */
    1717           0 :         while (sc->quiesce)
    1718           0 :                 tsleep(&sc->quiesce, 0, "mix_qio", 0);
    1719             : 
    1720           0 :         switch (cmd) {
    1721             :         case FIONBIO:
    1722             :                 /* All handled in the upper FS layer. */
    1723             :                 break;
    1724             :         case AUDIO_MIXER_DEVINFO:
    1725           0 :                 return audio_mixer_devinfo(sc, addr);
    1726             :         case AUDIO_MIXER_READ:
    1727           0 :                 return audio_mixer_read(sc, addr);
    1728             :         case AUDIO_MIXER_WRITE:
    1729           0 :                 return audio_mixer_write(sc, addr, p);
    1730             :         default:
    1731           0 :                 return ENOTTY;
    1732             :         }
    1733           0 :         return 0;
    1734           0 : }
    1735             : 
    1736             : int
    1737           0 : audio_poll(struct audio_softc *sc, int events, struct proc *p)
    1738             : {
    1739             :         int revents = 0;
    1740             : 
    1741           0 :         mtx_enter(&audio_lock);
    1742           0 :         if ((sc->mode & AUMODE_RECORD) && sc->rec.used > 0)
    1743           0 :                 revents |= events & (POLLIN | POLLRDNORM);
    1744           0 :         if ((sc->mode & AUMODE_PLAY) && sc->play.used < sc->play.len)
    1745           0 :                 revents |= events & (POLLOUT | POLLWRNORM);
    1746           0 :         if (revents == 0) {
    1747           0 :                 if (events & (POLLIN | POLLRDNORM))
    1748           0 :                         selrecord(p, &sc->rec.sel);
    1749           0 :                 if (events & (POLLOUT | POLLWRNORM))
    1750           0 :                         selrecord(p, &sc->play.sel);
    1751             :         }
    1752           0 :         mtx_leave(&audio_lock);
    1753           0 :         return revents;
    1754             : }
    1755             : 
    1756             : int
    1757           0 : audioopen(dev_t dev, int flags, int mode, struct proc *p)
    1758             : {
    1759             :         struct audio_softc *sc;
    1760             :         int error;
    1761             : 
    1762           0 :         sc = (struct audio_softc *)device_lookup(&audio_cd, AUDIO_UNIT(dev));
    1763           0 :         if (sc == NULL)
    1764           0 :                 return ENXIO;
    1765           0 :         if (sc->ops == NULL)
    1766           0 :                 error = ENXIO;
    1767             :         else {
    1768           0 :                 switch (AUDIO_DEV(dev)) {
    1769             :                 case AUDIO_DEV_AUDIO:
    1770           0 :                         error = audio_open(sc, flags);
    1771           0 :                         break;
    1772             :                 case AUDIO_DEV_AUDIOCTL:
    1773             :                 case AUDIO_DEV_MIXER:
    1774             :                         error = 0;
    1775           0 :                         break;
    1776             :                 default:
    1777             :                         error = ENXIO;
    1778           0 :                 }
    1779             :         }
    1780           0 :         device_unref(&sc->dev);
    1781           0 :         return error;
    1782           0 : }
    1783             : 
    1784             : int
    1785           0 : audioclose(dev_t dev, int flags, int ifmt, struct proc *p)
    1786             : {
    1787             :         struct audio_softc *sc;
    1788             :         int error;
    1789             : 
    1790           0 :         sc = (struct audio_softc *)device_lookup(&audio_cd, AUDIO_UNIT(dev));
    1791           0 :         if (sc == NULL)
    1792           0 :                 return ENXIO;
    1793           0 :         switch (AUDIO_DEV(dev)) {
    1794             :         case AUDIO_DEV_AUDIO:
    1795           0 :                 error = audio_close(sc);
    1796           0 :                 break;
    1797             :         case AUDIO_DEV_MIXER:
    1798             :         case AUDIO_DEV_AUDIOCTL:
    1799             :                 error = 0;
    1800           0 :                 break;
    1801             :         default:
    1802             :                 error = ENXIO;
    1803           0 :         }
    1804           0 :         device_unref(&sc->dev);
    1805           0 :         return error;
    1806           0 : }
    1807             : 
    1808             : int
    1809           0 : audioread(dev_t dev, struct uio *uio, int ioflag)
    1810             : {
    1811             :         struct audio_softc *sc;
    1812             :         int error;
    1813             : 
    1814           0 :         sc = (struct audio_softc *)device_lookup(&audio_cd, AUDIO_UNIT(dev));
    1815           0 :         if (sc == NULL)
    1816           0 :                 return ENXIO;
    1817           0 :         switch (AUDIO_DEV(dev)) {
    1818             :         case AUDIO_DEV_AUDIO:
    1819           0 :                 error = audio_read(sc, uio, ioflag);
    1820           0 :                 break;
    1821             :         case AUDIO_DEV_AUDIOCTL:
    1822             :         case AUDIO_DEV_MIXER:
    1823             :                 error = ENODEV;
    1824           0 :                 break;
    1825             :         default:
    1826             :                 error = ENXIO;
    1827           0 :         }
    1828           0 :         device_unref(&sc->dev);
    1829           0 :         return error;
    1830           0 : }
    1831             : 
    1832             : int
    1833           0 : audiowrite(dev_t dev, struct uio *uio, int ioflag)
    1834             : {
    1835             :         struct audio_softc *sc;
    1836             :         int error;
    1837             : 
    1838           0 :         sc = (struct audio_softc *)device_lookup(&audio_cd, AUDIO_UNIT(dev));
    1839           0 :         if (sc == NULL)
    1840           0 :                 return ENXIO;
    1841           0 :         switch (AUDIO_DEV(dev)) {
    1842             :         case AUDIO_DEV_AUDIO:
    1843           0 :                 error = audio_write(sc, uio, ioflag);
    1844           0 :                 break;
    1845             :         case AUDIO_DEV_AUDIOCTL:
    1846             :         case AUDIO_DEV_MIXER:
    1847             :                 error = ENODEV;
    1848           0 :                 break;
    1849             :         default:
    1850             :                 error = ENXIO;
    1851           0 :         }
    1852           0 :         device_unref(&sc->dev);
    1853           0 :         return error;
    1854           0 : }
    1855             : 
    1856             : int
    1857           0 : audioioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p)
    1858             : {
    1859             :         struct audio_softc *sc;
    1860             :         int error;
    1861             : 
    1862           0 :         sc = (struct audio_softc *)device_lookup(&audio_cd, AUDIO_UNIT(dev));
    1863           0 :         if (sc == NULL)
    1864           0 :                 return ENXIO;
    1865           0 :         switch (AUDIO_DEV(dev)) {
    1866             :         case AUDIO_DEV_AUDIO:
    1867           0 :                 error = audio_ioctl(sc, cmd, addr);
    1868           0 :                 break;
    1869             :         case AUDIO_DEV_AUDIOCTL:
    1870           0 :                 if (cmd == AUDIO_SETPAR && sc->mode != 0) {
    1871             :                         error = EBUSY;
    1872           0 :                         break;
    1873             :                 }
    1874           0 :                 if (cmd == AUDIO_START || cmd == AUDIO_STOP) {
    1875             :                         error = ENXIO;
    1876           0 :                         break;
    1877             :                 }
    1878           0 :                 error = audio_ioctl(sc, cmd, addr);
    1879           0 :                 break;
    1880             :         case AUDIO_DEV_MIXER:
    1881           0 :                 error = audio_ioctl_mixer(sc, cmd, addr, p);
    1882           0 :                 break;
    1883             :         default:
    1884             :                 error = ENXIO;
    1885           0 :         }
    1886           0 :         device_unref(&sc->dev);
    1887           0 :         return error;
    1888           0 : }
    1889             : 
    1890             : int
    1891           0 : audiopoll(dev_t dev, int events, struct proc *p)
    1892             : {
    1893             :         struct audio_softc *sc;
    1894             :         int revents;
    1895             : 
    1896           0 :         sc = (struct audio_softc *)device_lookup(&audio_cd, AUDIO_UNIT(dev));
    1897           0 :         if (sc == NULL)
    1898           0 :                 return POLLERR;
    1899           0 :         switch (AUDIO_DEV(dev)) {
    1900             :         case AUDIO_DEV_AUDIO:
    1901           0 :                 revents = audio_poll(sc, events, p);
    1902           0 :                 break;
    1903             :         case AUDIO_DEV_AUDIOCTL:
    1904             :         case AUDIO_DEV_MIXER:
    1905             :         default:
    1906             :                 revents = 0;
    1907           0 :                 break;
    1908             :         }
    1909           0 :         device_unref(&sc->dev);
    1910           0 :         return revents;
    1911           0 : }
    1912             : 
    1913             : #if NWSKBD > 0
    1914             : int
    1915           0 : wskbd_initmute(struct audio_softc *sc, struct mixer_devinfo *vol)
    1916             : {
    1917             :         struct mixer_devinfo *mi;
    1918             :         int index = -1;
    1919             : 
    1920           0 :         mi = malloc(sizeof(struct mixer_devinfo), M_TEMP, M_WAITOK);
    1921             : 
    1922           0 :         for (mi->index = vol->next; mi->index != -1; mi->index = mi->next) {
    1923           0 :                 if (sc->ops->query_devinfo(sc->arg, mi) != 0)
    1924             :                         break;
    1925           0 :                 if (strcmp(mi->label.name, AudioNmute) == 0) {
    1926           0 :                         index = mi->index;
    1927           0 :                         break;
    1928             :                 }
    1929             :         }
    1930             : 
    1931           0 :         free(mi, M_TEMP, sizeof(struct mixer_devinfo));
    1932           0 :         return index;
    1933             : }
    1934             : 
    1935             : int
    1936           0 : wskbd_initvol(struct audio_softc *sc, struct wskbd_vol *vol, char *cn, char *dn)
    1937             : {
    1938             :         struct mixer_devinfo *dev, *cls;
    1939             : 
    1940           0 :         vol->val = vol->mute = -1;
    1941           0 :         dev = malloc(sizeof(struct mixer_devinfo), M_TEMP, M_WAITOK);
    1942           0 :         cls = malloc(sizeof(struct mixer_devinfo), M_TEMP, M_WAITOK);
    1943             : 
    1944           0 :         for (dev->index = 0; ; dev->index++) {
    1945           0 :                 if (sc->ops->query_devinfo(sc->arg, dev) != 0)
    1946             :                         break;
    1947           0 :                 if (dev->type != AUDIO_MIXER_VALUE)
    1948             :                         continue;
    1949           0 :                 cls->index = dev->mixer_class;
    1950           0 :                 if (sc->ops->query_devinfo(sc->arg, cls) != 0)
    1951             :                         continue;
    1952           0 :                 if (strcmp(cls->label.name, cn) == 0 &&
    1953           0 :                     strcmp(dev->label.name, dn) == 0) {
    1954           0 :                         vol->val = dev->index;
    1955           0 :                         vol->nch = dev->un.v.num_channels;
    1956           0 :                         vol->step = dev->un.v.delta > 8 ? dev->un.v.delta : 8;
    1957           0 :                         vol->mute = wskbd_initmute(sc, dev);
    1958           0 :                         vol->val_pending = vol->mute_pending = 0;
    1959             :                         DPRINTF("%s: wskbd using %s.%s%s\n", DEVNAME(sc),
    1960             :                             cn, dn, vol->mute >= 0 ? ", mute control" : "");
    1961           0 :                         break;
    1962             :                 }
    1963             :         }
    1964             : 
    1965           0 :         free(cls, M_TEMP, sizeof(struct mixer_devinfo));
    1966           0 :         free(dev, M_TEMP, sizeof(struct mixer_devinfo));
    1967           0 :         return (vol->val != -1);
    1968             : }
    1969             : 
    1970             : void
    1971           0 : wskbd_mixer_init(struct audio_softc *sc)
    1972             : {
    1973             :         static struct {
    1974             :                 char *cn, *dn;
    1975             :         } spkr_names[] = {
    1976             :                 {AudioCoutputs, AudioNmaster},
    1977             :                 {AudioCinputs,  AudioNdac},
    1978             :                 {AudioCoutputs, AudioNdac},
    1979             :                 {AudioCoutputs, AudioNoutput}
    1980             :         }, mic_names[] = {
    1981             :                 {AudioCrecord, AudioNrecord},
    1982             :                 {AudioCrecord, AudioNvolume},
    1983             :                 {AudioCinputs, AudioNrecord},
    1984             :                 {AudioCinputs, AudioNvolume},
    1985             :                 {AudioCinputs, AudioNinput}
    1986             :         };
    1987             :         int i;
    1988             : 
    1989           0 :         if (sc->dev.dv_unit != 0) {
    1990             :                 DPRINTF("%s: not configuring wskbd keys\n", DEVNAME(sc));
    1991           0 :                 return;
    1992             :         }
    1993           0 :         for (i = 0; i < sizeof(spkr_names) / sizeof(spkr_names[0]); i++) {
    1994           0 :                 if (wskbd_initvol(sc, &sc->spkr,
    1995           0 :                         spkr_names[i].cn, spkr_names[i].dn))
    1996             :                         break;
    1997             :         }
    1998           0 :         for (i = 0; i < sizeof(mic_names) / sizeof(mic_names[0]); i++) {
    1999           0 :                 if (wskbd_initvol(sc, &sc->mic,
    2000           0 :                         mic_names[i].cn, mic_names[i].dn))
    2001             :                         break;
    2002             :         }
    2003           0 : }
    2004             : 
    2005             : void
    2006           0 : wskbd_mixer_update(struct audio_softc *sc, struct wskbd_vol *vol)
    2007             : {
    2008           0 :         struct mixer_ctrl ctrl;
    2009             :         int val_pending, mute_pending, i, gain, error, s;
    2010             : 
    2011           0 :         s = spltty();
    2012           0 :         val_pending = vol->val_pending;
    2013           0 :         vol->val_pending = 0;
    2014           0 :         mute_pending = vol->mute_pending;
    2015           0 :         vol->mute_pending = 0;
    2016           0 :         splx(s);
    2017             : 
    2018           0 :         if (sc->ops == NULL)
    2019           0 :                 return;
    2020           0 :         if (vol->mute >= 0 && mute_pending) {
    2021           0 :                 ctrl.dev = vol->mute;
    2022           0 :                 ctrl.type = AUDIO_MIXER_ENUM;
    2023           0 :                 error = sc->ops->get_port(sc->arg, &ctrl);
    2024           0 :                 if (error) {
    2025             :                         DPRINTF("%s: get mute err = %d\n", DEVNAME(sc), error);
    2026           0 :                         return;
    2027             :                 }
    2028           0 :                 switch (mute_pending) {
    2029             :                 case WSKBD_MUTE_TOGGLE:
    2030           0 :                         ctrl.un.ord = !ctrl.un.ord;
    2031           0 :                         break;
    2032             :                 case WSKBD_MUTE_DISABLE:
    2033           0 :                         ctrl.un.ord = 0;
    2034           0 :                         break;
    2035             :                 case WSKBD_MUTE_ENABLE:
    2036           0 :                         ctrl.un.ord = 1;
    2037           0 :                         break;
    2038             :                 }
    2039             :                 DPRINTFN(1, "%s: wskbd mute setting to %d\n",
    2040             :                     DEVNAME(sc), ctrl.un.ord);
    2041           0 :                 error = sc->ops->set_port(sc->arg, &ctrl);
    2042           0 :                 if (error) {
    2043             :                         DPRINTF("%s: set mute err = %d\n", DEVNAME(sc), error);
    2044           0 :                         return;
    2045             :                 }
    2046             :         }
    2047           0 :         if (vol->val >= 0 && val_pending) {
    2048           0 :                 ctrl.dev = vol->val;
    2049           0 :                 ctrl.type = AUDIO_MIXER_VALUE;
    2050           0 :                 ctrl.un.value.num_channels = vol->nch;
    2051           0 :                 error = sc->ops->get_port(sc->arg, &ctrl);
    2052           0 :                 if (error) {
    2053             :                         DPRINTF("%s: get mute err = %d\n", DEVNAME(sc), error);
    2054           0 :                         return;
    2055             :                 }
    2056           0 :                 for (i = 0; i < vol->nch; i++) {
    2057           0 :                         gain = ctrl.un.value.level[i] + vol->step * val_pending;
    2058           0 :                         if (gain > AUDIO_MAX_GAIN)
    2059           0 :                                 gain = AUDIO_MAX_GAIN;
    2060           0 :                         else if (gain < AUDIO_MIN_GAIN)
    2061           0 :                                 gain = AUDIO_MIN_GAIN;
    2062           0 :                         ctrl.un.value.level[i] = gain;
    2063             :                         DPRINTFN(1, "%s: wskbd level %d set to %d\n",
    2064             :                             DEVNAME(sc), i, gain);
    2065             :                 }
    2066           0 :                 error = sc->ops->set_port(sc->arg, &ctrl);
    2067           0 :                 if (error) {
    2068             :                         DPRINTF("%s: set vol err = %d\n", DEVNAME(sc), error);
    2069           0 :                         return;
    2070             :                 }
    2071             :         }
    2072           0 : }
    2073             : 
    2074             : void
    2075           0 : wskbd_mixer_cb(void *addr)
    2076             : {
    2077           0 :         struct audio_softc *sc = addr;
    2078             :         int s;
    2079             : 
    2080           0 :         wskbd_mixer_update(sc, &sc->spkr);
    2081           0 :         wskbd_mixer_update(sc, &sc->mic);
    2082           0 :         s = spltty();
    2083           0 :         sc->wskbd_taskset = 0;
    2084           0 :         splx(s);
    2085           0 :         device_unref(&sc->dev);
    2086           0 : }
    2087             : 
    2088             : int
    2089           0 : wskbd_set_mixermute(long mute, long out)
    2090             : {
    2091             :         struct audio_softc *sc;
    2092             :         struct wskbd_vol *vol;
    2093             : 
    2094           0 :         sc = (struct audio_softc *)device_lookup(&audio_cd, 0);
    2095           0 :         if (sc == NULL)
    2096           0 :                 return ENODEV;
    2097           0 :         vol = out ? &sc->spkr : &sc->mic;
    2098           0 :         vol->mute_pending = mute ? WSKBD_MUTE_ENABLE : WSKBD_MUTE_DISABLE;
    2099           0 :         if (!sc->wskbd_taskset) {
    2100           0 :                 task_set(&sc->wskbd_task, wskbd_mixer_cb, sc);
    2101           0 :                 task_add(systq, &sc->wskbd_task);
    2102           0 :                 sc->wskbd_taskset = 1;
    2103           0 :         }
    2104           0 :         return 0;
    2105           0 : }
    2106             : 
    2107             : int
    2108           0 : wskbd_set_mixervolume(long dir, long out)
    2109             : {
    2110             :         struct audio_softc *sc;
    2111             :         struct wskbd_vol *vol;
    2112             : 
    2113           0 :         sc = (struct audio_softc *)device_lookup(&audio_cd, 0);
    2114           0 :         if (sc == NULL)
    2115           0 :                 return ENODEV;
    2116           0 :         vol = out ? &sc->spkr : &sc->mic;
    2117           0 :         if (dir == 0)
    2118           0 :                 vol->mute_pending ^= WSKBD_MUTE_TOGGLE;
    2119             :         else
    2120           0 :                 vol->val_pending += dir;
    2121           0 :         if (!sc->wskbd_taskset) {
    2122           0 :                 task_set(&sc->wskbd_task, wskbd_mixer_cb, sc);
    2123           0 :                 task_add(systq, &sc->wskbd_task);
    2124           0 :                 sc->wskbd_taskset = 1;
    2125           0 :         }
    2126           0 :         return 0;
    2127           0 : }
    2128             : #endif /* NWSKBD > 0 */

Generated by: LCOV version 1.13