1c15c9315SChristos Margiolis /*- 2c15c9315SChristos Margiolis * SPDX-License-Identifier: BSD-2-Clause 3c15c9315SChristos Margiolis * 4c15c9315SChristos Margiolis * Copyright (c) 2024 The FreeBSD Foundation 5c15c9315SChristos Margiolis * 6c15c9315SChristos Margiolis * This software was developed by Christos Margiolis <christos@FreeBSD.org> 7c15c9315SChristos Margiolis * under sponsorship from the FreeBSD Foundation. 8c15c9315SChristos Margiolis * 9c15c9315SChristos Margiolis * Redistribution and use in source and binary forms, with or without 10c15c9315SChristos Margiolis * modification, are permitted provided that the following conditions 11c15c9315SChristos Margiolis * are met: 12c15c9315SChristos Margiolis * 1. Redistributions of source code must retain the above copyright 13c15c9315SChristos Margiolis * notice, this list of conditions and the following disclaimer. 14c15c9315SChristos Margiolis * 2. Redistributions in binary form must reproduce the above copyright 15c15c9315SChristos Margiolis * notice, this list of conditions and the following disclaimer in the 16c15c9315SChristos Margiolis * documentation and/or other materials provided with the distribution. 17c15c9315SChristos Margiolis * 18c15c9315SChristos Margiolis * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19c15c9315SChristos Margiolis * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20c15c9315SChristos Margiolis * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21c15c9315SChristos Margiolis * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22c15c9315SChristos Margiolis * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23c15c9315SChristos Margiolis * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24c15c9315SChristos Margiolis * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25c15c9315SChristos Margiolis * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26c15c9315SChristos Margiolis * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27c15c9315SChristos Margiolis * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28c15c9315SChristos Margiolis * SUCH DAMAGE. 29c15c9315SChristos Margiolis */ 30c15c9315SChristos Margiolis 31c15c9315SChristos Margiolis #include <sys/cdefs.h> 32c15c9315SChristos Margiolis 33c15c9315SChristos Margiolis #include <sys/param.h> 34c15c9315SChristos Margiolis #include <sys/systm.h> 35c15c9315SChristos Margiolis #include <sys/kernel.h> 36c15c9315SChristos Margiolis #include <sys/bus.h> 37c15c9315SChristos Margiolis 38c15c9315SChristos Margiolis #ifdef HAVE_KERNEL_OPTION_HEADERS 39c15c9315SChristos Margiolis #include "opt_snd.h" 40c15c9315SChristos Margiolis #endif 41c15c9315SChristos Margiolis 42c15c9315SChristos Margiolis #include <dev/sound/pcm/sound.h> 43c15c9315SChristos Margiolis #include <mixer_if.h> 44c15c9315SChristos Margiolis 45c15c9315SChristos Margiolis #define DUMMY_NPCHAN 1 46c15c9315SChristos Margiolis #define DUMMY_NRCHAN 1 47c15c9315SChristos Margiolis #define DUMMY_NCHAN (DUMMY_NPCHAN + DUMMY_NRCHAN) 48c15c9315SChristos Margiolis 49c15c9315SChristos Margiolis struct dummy_chan { 50c15c9315SChristos Margiolis struct dummy_softc *sc; 51c15c9315SChristos Margiolis struct pcm_channel *chan; 52c15c9315SChristos Margiolis struct snd_dbuf *buf; 53c15c9315SChristos Margiolis struct pcmchan_caps *caps; 54c15c9315SChristos Margiolis uint32_t ptr; 55c15c9315SChristos Margiolis int dir; 56c15c9315SChristos Margiolis int run; 57c15c9315SChristos Margiolis }; 58c15c9315SChristos Margiolis 59c15c9315SChristos Margiolis struct dummy_softc { 60c15c9315SChristos Margiolis struct snddev_info info; 61c15c9315SChristos Margiolis device_t dev; 62c15c9315SChristos Margiolis uint32_t cap_fmts[4]; 63c15c9315SChristos Margiolis struct pcmchan_caps caps; 64c15c9315SChristos Margiolis int chnum; 65c15c9315SChristos Margiolis struct dummy_chan chans[DUMMY_NCHAN]; 66c15c9315SChristos Margiolis struct callout callout; 67c15c9315SChristos Margiolis struct mtx *lock; 68c15c9315SChristos Margiolis }; 69c15c9315SChristos Margiolis 70*5bd08172SChristos Margiolis static bool 71*5bd08172SChristos Margiolis dummy_active(struct dummy_softc *sc) 72*5bd08172SChristos Margiolis { 73*5bd08172SChristos Margiolis struct dummy_chan *ch; 74*5bd08172SChristos Margiolis int i; 75*5bd08172SChristos Margiolis 76*5bd08172SChristos Margiolis snd_mtxassert(sc->lock); 77*5bd08172SChristos Margiolis 78*5bd08172SChristos Margiolis for (i = 0; i < sc->chnum; i++) { 79*5bd08172SChristos Margiolis ch = &sc->chans[i]; 80*5bd08172SChristos Margiolis if (ch->run) 81*5bd08172SChristos Margiolis return (true); 82*5bd08172SChristos Margiolis } 83*5bd08172SChristos Margiolis 84*5bd08172SChristos Margiolis /* No channel is running at the moment. */ 85*5bd08172SChristos Margiolis return (false); 86*5bd08172SChristos Margiolis } 87*5bd08172SChristos Margiolis 88c15c9315SChristos Margiolis static void 89c15c9315SChristos Margiolis dummy_chan_io(void *arg) 90c15c9315SChristos Margiolis { 91c15c9315SChristos Margiolis struct dummy_softc *sc = arg; 92c15c9315SChristos Margiolis struct dummy_chan *ch; 93c15c9315SChristos Margiolis int i = 0; 94c15c9315SChristos Margiolis 95*5bd08172SChristos Margiolis /* Do not reschedule if no channel is running. */ 96*5bd08172SChristos Margiolis if (!dummy_active(sc)) 97*5bd08172SChristos Margiolis return; 98c15c9315SChristos Margiolis 99c15c9315SChristos Margiolis for (i = 0; i < sc->chnum; i++) { 100c15c9315SChristos Margiolis ch = &sc->chans[i]; 101c15c9315SChristos Margiolis if (!ch->run) 102c15c9315SChristos Margiolis continue; 103c15c9315SChristos Margiolis if (ch->dir == PCMDIR_PLAY) 104c15c9315SChristos Margiolis ch->ptr += sndbuf_getblksz(ch->buf); 105c15c9315SChristos Margiolis else 106c15c9315SChristos Margiolis sndbuf_fillsilence(ch->buf); 107c15c9315SChristos Margiolis snd_mtxunlock(sc->lock); 108c15c9315SChristos Margiolis chn_intr(ch->chan); 109c15c9315SChristos Margiolis snd_mtxlock(sc->lock); 110c15c9315SChristos Margiolis } 111c15c9315SChristos Margiolis callout_schedule(&sc->callout, 1); 112c15c9315SChristos Margiolis } 113c15c9315SChristos Margiolis 114c15c9315SChristos Margiolis static int 115c15c9315SChristos Margiolis dummy_chan_free(kobj_t obj, void *data) 116c15c9315SChristos Margiolis { 117c15c9315SChristos Margiolis struct dummy_chan *ch =data; 118c15c9315SChristos Margiolis uint8_t *buf; 119c15c9315SChristos Margiolis 120c15c9315SChristos Margiolis buf = sndbuf_getbuf(ch->buf); 121c15c9315SChristos Margiolis if (buf != NULL) 122c15c9315SChristos Margiolis free(buf, M_DEVBUF); 123c15c9315SChristos Margiolis 124c15c9315SChristos Margiolis return (0); 125c15c9315SChristos Margiolis } 126c15c9315SChristos Margiolis 127c15c9315SChristos Margiolis static void * 128c15c9315SChristos Margiolis dummy_chan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, 129c15c9315SChristos Margiolis struct pcm_channel *c, int dir) 130c15c9315SChristos Margiolis { 131c15c9315SChristos Margiolis struct dummy_softc *sc; 132c15c9315SChristos Margiolis struct dummy_chan *ch; 133c15c9315SChristos Margiolis uint8_t *buf; 134c15c9315SChristos Margiolis size_t bufsz; 135c15c9315SChristos Margiolis 136c15c9315SChristos Margiolis sc = devinfo; 137c15c9315SChristos Margiolis 138c15c9315SChristos Margiolis snd_mtxlock(sc->lock); 139c15c9315SChristos Margiolis 140c15c9315SChristos Margiolis ch = &sc->chans[sc->chnum++]; 141c15c9315SChristos Margiolis ch->sc = sc; 142c15c9315SChristos Margiolis ch->dir = dir; 143c15c9315SChristos Margiolis ch->chan = c; 144c15c9315SChristos Margiolis ch->buf = b; 145c15c9315SChristos Margiolis ch->caps = &sc->caps; 146c15c9315SChristos Margiolis 147c15c9315SChristos Margiolis snd_mtxunlock(sc->lock); 148c15c9315SChristos Margiolis 149c15c9315SChristos Margiolis bufsz = pcm_getbuffersize(sc->dev, 2048, 2048, 65536); 150c15c9315SChristos Margiolis buf = malloc(bufsz, M_DEVBUF, M_WAITOK | M_ZERO); 151c15c9315SChristos Margiolis if (sndbuf_setup(ch->buf, buf, bufsz) != 0) { 152c15c9315SChristos Margiolis dummy_chan_free(obj, ch); 153c15c9315SChristos Margiolis return (NULL); 154c15c9315SChristos Margiolis } 155c15c9315SChristos Margiolis 156c15c9315SChristos Margiolis return (ch); 157c15c9315SChristos Margiolis } 158c15c9315SChristos Margiolis 159c15c9315SChristos Margiolis static int 160c15c9315SChristos Margiolis dummy_chan_setformat(kobj_t obj, void *data, uint32_t format) 161c15c9315SChristos Margiolis { 162c15c9315SChristos Margiolis struct dummy_chan *ch = data; 163c15c9315SChristos Margiolis int i; 164c15c9315SChristos Margiolis 165c15c9315SChristos Margiolis for (i = 0; ch->caps->fmtlist[i]; i++) 166c15c9315SChristos Margiolis if (format == ch->caps->fmtlist[i]) 167c15c9315SChristos Margiolis return (0); 168c15c9315SChristos Margiolis 169c15c9315SChristos Margiolis return (EINVAL); 170c15c9315SChristos Margiolis } 171c15c9315SChristos Margiolis 172c15c9315SChristos Margiolis static uint32_t 173c15c9315SChristos Margiolis dummy_chan_setspeed(kobj_t obj, void *data, uint32_t speed) 174c15c9315SChristos Margiolis { 175c15c9315SChristos Margiolis struct dummy_chan *ch = data; 176c15c9315SChristos Margiolis 177c15c9315SChristos Margiolis RANGE(speed, ch->caps->minspeed, ch->caps->maxspeed); 178c15c9315SChristos Margiolis 179c15c9315SChristos Margiolis return (speed); 180c15c9315SChristos Margiolis } 181c15c9315SChristos Margiolis 182c15c9315SChristos Margiolis static uint32_t 183c15c9315SChristos Margiolis dummy_chan_setblocksize(kobj_t obj, void *data, uint32_t blocksize) 184c15c9315SChristos Margiolis { 185c15c9315SChristos Margiolis struct dummy_chan *ch = data; 186c15c9315SChristos Margiolis 187c15c9315SChristos Margiolis return (sndbuf_getblksz(ch->buf)); 188c15c9315SChristos Margiolis } 189c15c9315SChristos Margiolis 190c15c9315SChristos Margiolis static int 191c15c9315SChristos Margiolis dummy_chan_trigger(kobj_t obj, void *data, int go) 192c15c9315SChristos Margiolis { 193c15c9315SChristos Margiolis struct dummy_chan *ch = data; 194c15c9315SChristos Margiolis struct dummy_softc *sc = ch->sc; 195c15c9315SChristos Margiolis 196c15c9315SChristos Margiolis snd_mtxlock(sc->lock); 197c15c9315SChristos Margiolis 198c15c9315SChristos Margiolis switch (go) { 199c15c9315SChristos Margiolis case PCMTRIG_START: 200c15c9315SChristos Margiolis ch->ptr = 0; 201c15c9315SChristos Margiolis ch->run = 1; 202*5bd08172SChristos Margiolis callout_reset(&sc->callout, 1, dummy_chan_io, sc); 203c15c9315SChristos Margiolis break; 204c15c9315SChristos Margiolis case PCMTRIG_STOP: 205c15c9315SChristos Margiolis case PCMTRIG_ABORT: 206c15c9315SChristos Margiolis ch->run = 0; 207*5bd08172SChristos Margiolis /* If all channels are stopped, stop the callout as well. */ 208*5bd08172SChristos Margiolis if (!dummy_active(sc)) 209c15c9315SChristos Margiolis callout_stop(&sc->callout); 210c15c9315SChristos Margiolis default: 211c15c9315SChristos Margiolis break; 212c15c9315SChristos Margiolis } 213c15c9315SChristos Margiolis 214c15c9315SChristos Margiolis snd_mtxunlock(sc->lock); 215c15c9315SChristos Margiolis 216c15c9315SChristos Margiolis return (0); 217c15c9315SChristos Margiolis } 218c15c9315SChristos Margiolis 219c15c9315SChristos Margiolis static uint32_t 220c15c9315SChristos Margiolis dummy_chan_getptr(kobj_t obj, void *data) 221c15c9315SChristos Margiolis { 222c15c9315SChristos Margiolis struct dummy_chan *ch = data; 223c15c9315SChristos Margiolis 224c15c9315SChristos Margiolis return (ch->run ? ch->ptr : 0); 225c15c9315SChristos Margiolis } 226c15c9315SChristos Margiolis 227c15c9315SChristos Margiolis static struct pcmchan_caps * 228c15c9315SChristos Margiolis dummy_chan_getcaps(kobj_t obj, void *data) 229c15c9315SChristos Margiolis { 230c15c9315SChristos Margiolis struct dummy_chan *ch = data; 231c15c9315SChristos Margiolis 232c15c9315SChristos Margiolis return (ch->caps); 233c15c9315SChristos Margiolis } 234c15c9315SChristos Margiolis 235c15c9315SChristos Margiolis static kobj_method_t dummy_chan_methods[] = { 236c15c9315SChristos Margiolis KOBJMETHOD(channel_init, dummy_chan_init), 237c15c9315SChristos Margiolis KOBJMETHOD(channel_free, dummy_chan_free), 238c15c9315SChristos Margiolis KOBJMETHOD(channel_setformat, dummy_chan_setformat), 239c15c9315SChristos Margiolis KOBJMETHOD(channel_setspeed, dummy_chan_setspeed), 240c15c9315SChristos Margiolis KOBJMETHOD(channel_setblocksize,dummy_chan_setblocksize), 241c15c9315SChristos Margiolis KOBJMETHOD(channel_trigger, dummy_chan_trigger), 242c15c9315SChristos Margiolis KOBJMETHOD(channel_getptr, dummy_chan_getptr), 243c15c9315SChristos Margiolis KOBJMETHOD(channel_getcaps, dummy_chan_getcaps), 244c15c9315SChristos Margiolis KOBJMETHOD_END 245c15c9315SChristos Margiolis }; 246c15c9315SChristos Margiolis 247c15c9315SChristos Margiolis CHANNEL_DECLARE(dummy_chan); 248c15c9315SChristos Margiolis 249c15c9315SChristos Margiolis static int 250c15c9315SChristos Margiolis dummy_mixer_init(struct snd_mixer *m) 251c15c9315SChristos Margiolis { 252c15c9315SChristos Margiolis struct dummy_softc *sc; 253c15c9315SChristos Margiolis 254c15c9315SChristos Margiolis sc = mix_getdevinfo(m); 255c15c9315SChristos Margiolis if (sc == NULL) 256c15c9315SChristos Margiolis return (-1); 257c15c9315SChristos Margiolis 258c15c9315SChristos Margiolis pcm_setflags(sc->dev, pcm_getflags(sc->dev) | SD_F_SOFTPCMVOL); 259c15c9315SChristos Margiolis mix_setdevs(m, SOUND_MASK_PCM | SOUND_MASK_VOLUME | SOUND_MASK_RECLEV); 260c15c9315SChristos Margiolis mix_setrecdevs(m, SOUND_MASK_RECLEV); 261c15c9315SChristos Margiolis 262c15c9315SChristos Margiolis return (0); 263c15c9315SChristos Margiolis } 264c15c9315SChristos Margiolis 265c15c9315SChristos Margiolis static int 266c15c9315SChristos Margiolis dummy_mixer_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right) 267c15c9315SChristos Margiolis { 268c15c9315SChristos Margiolis return (0); 269c15c9315SChristos Margiolis } 270c15c9315SChristos Margiolis 271c15c9315SChristos Margiolis static uint32_t 272c15c9315SChristos Margiolis dummy_mixer_setrecsrc(struct snd_mixer *m, uint32_t src) 273c15c9315SChristos Margiolis { 274c15c9315SChristos Margiolis return (src == SOUND_MASK_RECLEV ? src : 0); 275c15c9315SChristos Margiolis } 276c15c9315SChristos Margiolis 277c15c9315SChristos Margiolis static kobj_method_t dummy_mixer_methods[] = { 278c15c9315SChristos Margiolis KOBJMETHOD(mixer_init, dummy_mixer_init), 279c15c9315SChristos Margiolis KOBJMETHOD(mixer_set, dummy_mixer_set), 280c15c9315SChristos Margiolis KOBJMETHOD(mixer_setrecsrc, dummy_mixer_setrecsrc), 281c15c9315SChristos Margiolis KOBJMETHOD_END 282c15c9315SChristos Margiolis }; 283c15c9315SChristos Margiolis 284c15c9315SChristos Margiolis MIXER_DECLARE(dummy_mixer); 285c15c9315SChristos Margiolis 286c15c9315SChristos Margiolis static void 287c15c9315SChristos Margiolis dummy_identify(driver_t *driver, device_t parent) 288c15c9315SChristos Margiolis { 289c15c9315SChristos Margiolis if (device_find_child(parent, driver->name, -1) != NULL) 290c15c9315SChristos Margiolis return; 291c15c9315SChristos Margiolis if (BUS_ADD_CHILD(parent, 0, driver->name, -1) == NULL) 292c15c9315SChristos Margiolis device_printf(parent, "add child failed\n"); 293c15c9315SChristos Margiolis } 294c15c9315SChristos Margiolis 295c15c9315SChristos Margiolis static int 296c15c9315SChristos Margiolis dummy_probe(device_t dev) 297c15c9315SChristos Margiolis { 298c15c9315SChristos Margiolis device_set_desc(dev, "Dummy Audio Device"); 299c15c9315SChristos Margiolis 300c15c9315SChristos Margiolis return (0); 301c15c9315SChristos Margiolis } 302c15c9315SChristos Margiolis 303c15c9315SChristos Margiolis static int 304c15c9315SChristos Margiolis dummy_attach(device_t dev) 305c15c9315SChristos Margiolis { 306c15c9315SChristos Margiolis struct dummy_softc *sc; 307c15c9315SChristos Margiolis char status[SND_STATUSLEN]; 308c15c9315SChristos Margiolis int i = 0; 309c15c9315SChristos Margiolis 310c15c9315SChristos Margiolis sc = device_get_softc(dev); 311c15c9315SChristos Margiolis sc->dev = dev; 312c15c9315SChristos Margiolis sc->lock = snd_mtxcreate(device_get_nameunit(dev), "snd_dummy softc"); 313*5bd08172SChristos Margiolis callout_init_mtx(&sc->callout, sc->lock, 0); 314c15c9315SChristos Margiolis 315c15c9315SChristos Margiolis sc->cap_fmts[0] = SND_FORMAT(AFMT_S32_LE, 2, 0); 316c15c9315SChristos Margiolis sc->cap_fmts[1] = SND_FORMAT(AFMT_S24_LE, 2, 0); 317c15c9315SChristos Margiolis sc->cap_fmts[2] = SND_FORMAT(AFMT_S16_LE, 2, 0); 318c15c9315SChristos Margiolis sc->cap_fmts[3] = 0; 319c15c9315SChristos Margiolis sc->caps = (struct pcmchan_caps){ 320c15c9315SChristos Margiolis 8000, /* minspeed */ 321c15c9315SChristos Margiolis 96000, /* maxspeed */ 322c15c9315SChristos Margiolis sc->cap_fmts, /* fmtlist */ 323c15c9315SChristos Margiolis 0, /* caps */ 324c15c9315SChristos Margiolis }; 325c15c9315SChristos Margiolis 326c15c9315SChristos Margiolis pcm_setflags(dev, pcm_getflags(dev) | SD_F_MPSAFE); 327516a9c02SChristos Margiolis pcm_init(dev, sc); 328c15c9315SChristos Margiolis for (i = 0; i < DUMMY_NPCHAN; i++) 329c15c9315SChristos Margiolis pcm_addchan(dev, PCMDIR_PLAY, &dummy_chan_class, sc); 330c15c9315SChristos Margiolis for (i = 0; i < DUMMY_NRCHAN; i++) 331c15c9315SChristos Margiolis pcm_addchan(dev, PCMDIR_REC, &dummy_chan_class, sc); 332c15c9315SChristos Margiolis 333c15c9315SChristos Margiolis snprintf(status, SND_STATUSLEN, "on %s", 334c15c9315SChristos Margiolis device_get_nameunit(device_get_parent(dev))); 335516a9c02SChristos Margiolis if (pcm_register(dev, status)) 336516a9c02SChristos Margiolis return (ENXIO); 337c15c9315SChristos Margiolis mixer_init(dev, &dummy_mixer_class, sc); 338c15c9315SChristos Margiolis 339c15c9315SChristos Margiolis return (0); 340c15c9315SChristos Margiolis } 341c15c9315SChristos Margiolis 342c15c9315SChristos Margiolis static int 343c15c9315SChristos Margiolis dummy_detach(device_t dev) 344c15c9315SChristos Margiolis { 345c15c9315SChristos Margiolis struct dummy_softc *sc = device_get_softc(dev); 346c15c9315SChristos Margiolis int err; 347c15c9315SChristos Margiolis 348c15c9315SChristos Margiolis err = pcm_unregister(dev); 349*5bd08172SChristos Margiolis callout_drain(&sc->callout); 350c15c9315SChristos Margiolis snd_mtxfree(sc->lock); 351c15c9315SChristos Margiolis 352c15c9315SChristos Margiolis return (err); 353c15c9315SChristos Margiolis } 354c15c9315SChristos Margiolis 355c15c9315SChristos Margiolis static device_method_t dummy_methods[] = { 356c15c9315SChristos Margiolis /* Device interface */ 357c15c9315SChristos Margiolis DEVMETHOD(device_identify, dummy_identify), 358c15c9315SChristos Margiolis DEVMETHOD(device_probe, dummy_probe), 359c15c9315SChristos Margiolis DEVMETHOD(device_attach, dummy_attach), 360c15c9315SChristos Margiolis DEVMETHOD(device_detach, dummy_detach), 361c15c9315SChristos Margiolis DEVMETHOD_END 362c15c9315SChristos Margiolis }; 363c15c9315SChristos Margiolis 364c15c9315SChristos Margiolis static driver_t dummy_driver = { 365c15c9315SChristos Margiolis "pcm", 366c15c9315SChristos Margiolis dummy_methods, 367c15c9315SChristos Margiolis sizeof(struct dummy_softc), 368c15c9315SChristos Margiolis }; 369c15c9315SChristos Margiolis 370c15c9315SChristos Margiolis DRIVER_MODULE(snd_dummy, nexus, dummy_driver, 0, 0); 371c15c9315SChristos Margiolis MODULE_DEPEND(snd_dummy, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER); 372c15c9315SChristos Margiolis MODULE_VERSION(snd_dummy, 1); 373