xref: /freebsd/sys/dev/sound/dummy.c (revision 516a9c0212b003e1da0c6f4476dbe4f3f431606c)
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 
70c15c9315SChristos Margiolis static void
71c15c9315SChristos Margiolis dummy_chan_io(void *arg)
72c15c9315SChristos Margiolis {
73c15c9315SChristos Margiolis 	struct dummy_softc *sc = arg;
74c15c9315SChristos Margiolis 	struct dummy_chan *ch;
75c15c9315SChristos Margiolis 	int i = 0;
76c15c9315SChristos Margiolis 
77c15c9315SChristos Margiolis 	snd_mtxlock(sc->lock);
78c15c9315SChristos Margiolis 
79c15c9315SChristos Margiolis 	for (i = 0; i < sc->chnum; i++) {
80c15c9315SChristos Margiolis 		ch = &sc->chans[i];
81c15c9315SChristos Margiolis 		if (!ch->run)
82c15c9315SChristos Margiolis 			continue;
83c15c9315SChristos Margiolis 		if (ch->dir == PCMDIR_PLAY)
84c15c9315SChristos Margiolis 			ch->ptr += sndbuf_getblksz(ch->buf);
85c15c9315SChristos Margiolis 		else
86c15c9315SChristos Margiolis 			sndbuf_fillsilence(ch->buf);
87c15c9315SChristos Margiolis 		snd_mtxunlock(sc->lock);
88c15c9315SChristos Margiolis 		chn_intr(ch->chan);
89c15c9315SChristos Margiolis 		snd_mtxlock(sc->lock);
90c15c9315SChristos Margiolis 	}
91c15c9315SChristos Margiolis 	callout_schedule(&sc->callout, 1);
92c15c9315SChristos Margiolis 
93c15c9315SChristos Margiolis 	snd_mtxunlock(sc->lock);
94c15c9315SChristos Margiolis }
95c15c9315SChristos Margiolis 
96c15c9315SChristos Margiolis static int
97c15c9315SChristos Margiolis dummy_chan_free(kobj_t obj, void *data)
98c15c9315SChristos Margiolis {
99c15c9315SChristos Margiolis 	struct dummy_chan *ch =data;
100c15c9315SChristos Margiolis 	uint8_t *buf;
101c15c9315SChristos Margiolis 
102c15c9315SChristos Margiolis 	buf = sndbuf_getbuf(ch->buf);
103c15c9315SChristos Margiolis 	if (buf != NULL)
104c15c9315SChristos Margiolis 		free(buf, M_DEVBUF);
105c15c9315SChristos Margiolis 
106c15c9315SChristos Margiolis 	return (0);
107c15c9315SChristos Margiolis }
108c15c9315SChristos Margiolis 
109c15c9315SChristos Margiolis static void *
110c15c9315SChristos Margiolis dummy_chan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b,
111c15c9315SChristos Margiolis     struct pcm_channel *c, int dir)
112c15c9315SChristos Margiolis {
113c15c9315SChristos Margiolis 	struct dummy_softc *sc;
114c15c9315SChristos Margiolis 	struct dummy_chan *ch;
115c15c9315SChristos Margiolis 	uint8_t *buf;
116c15c9315SChristos Margiolis 	size_t bufsz;
117c15c9315SChristos Margiolis 
118c15c9315SChristos Margiolis 	sc = devinfo;
119c15c9315SChristos Margiolis 
120c15c9315SChristos Margiolis 	snd_mtxlock(sc->lock);
121c15c9315SChristos Margiolis 
122c15c9315SChristos Margiolis 	ch = &sc->chans[sc->chnum++];
123c15c9315SChristos Margiolis 	ch->sc = sc;
124c15c9315SChristos Margiolis 	ch->dir = dir;
125c15c9315SChristos Margiolis 	ch->chan = c;
126c15c9315SChristos Margiolis 	ch->buf = b;
127c15c9315SChristos Margiolis 	ch->caps = &sc->caps;
128c15c9315SChristos Margiolis 
129c15c9315SChristos Margiolis 	snd_mtxunlock(sc->lock);
130c15c9315SChristos Margiolis 
131c15c9315SChristos Margiolis 	bufsz = pcm_getbuffersize(sc->dev, 2048, 2048, 65536);
132c15c9315SChristos Margiolis 	buf = malloc(bufsz, M_DEVBUF, M_WAITOK | M_ZERO);
133c15c9315SChristos Margiolis 	if (sndbuf_setup(ch->buf, buf, bufsz) != 0) {
134c15c9315SChristos Margiolis 		dummy_chan_free(obj, ch);
135c15c9315SChristos Margiolis 		return (NULL);
136c15c9315SChristos Margiolis 	}
137c15c9315SChristos Margiolis 
138c15c9315SChristos Margiolis 	return (ch);
139c15c9315SChristos Margiolis }
140c15c9315SChristos Margiolis 
141c15c9315SChristos Margiolis static int
142c15c9315SChristos Margiolis dummy_chan_setformat(kobj_t obj, void *data, uint32_t format)
143c15c9315SChristos Margiolis {
144c15c9315SChristos Margiolis 	struct dummy_chan *ch = data;
145c15c9315SChristos Margiolis 	int i;
146c15c9315SChristos Margiolis 
147c15c9315SChristos Margiolis 	for (i = 0; ch->caps->fmtlist[i]; i++)
148c15c9315SChristos Margiolis 		if (format == ch->caps->fmtlist[i])
149c15c9315SChristos Margiolis 			return (0);
150c15c9315SChristos Margiolis 
151c15c9315SChristos Margiolis 	return (EINVAL);
152c15c9315SChristos Margiolis }
153c15c9315SChristos Margiolis 
154c15c9315SChristos Margiolis static uint32_t
155c15c9315SChristos Margiolis dummy_chan_setspeed(kobj_t obj, void *data, uint32_t speed)
156c15c9315SChristos Margiolis {
157c15c9315SChristos Margiolis 	struct dummy_chan *ch = data;
158c15c9315SChristos Margiolis 
159c15c9315SChristos Margiolis 	RANGE(speed, ch->caps->minspeed, ch->caps->maxspeed);
160c15c9315SChristos Margiolis 
161c15c9315SChristos Margiolis 	return (speed);
162c15c9315SChristos Margiolis }
163c15c9315SChristos Margiolis 
164c15c9315SChristos Margiolis static uint32_t
165c15c9315SChristos Margiolis dummy_chan_setblocksize(kobj_t obj, void *data, uint32_t blocksize)
166c15c9315SChristos Margiolis {
167c15c9315SChristos Margiolis 	struct dummy_chan *ch = data;
168c15c9315SChristos Margiolis 
169c15c9315SChristos Margiolis 	return (sndbuf_getblksz(ch->buf));
170c15c9315SChristos Margiolis }
171c15c9315SChristos Margiolis 
172c15c9315SChristos Margiolis static int
173c15c9315SChristos Margiolis dummy_chan_trigger(kobj_t obj, void *data, int go)
174c15c9315SChristos Margiolis {
175c15c9315SChristos Margiolis 	struct dummy_chan *ch = data;
176c15c9315SChristos Margiolis 	struct dummy_softc *sc = ch->sc;
177c15c9315SChristos Margiolis 
178c15c9315SChristos Margiolis 	snd_mtxlock(sc->lock);
179c15c9315SChristos Margiolis 
180c15c9315SChristos Margiolis 	switch (go) {
181c15c9315SChristos Margiolis 	case PCMTRIG_START:
182c15c9315SChristos Margiolis 		if (!callout_active(&sc->callout))
183c15c9315SChristos Margiolis 			callout_reset(&sc->callout, 1, dummy_chan_io, sc);
184c15c9315SChristos Margiolis 		ch->ptr = 0;
185c15c9315SChristos Margiolis 		ch->run = 1;
186c15c9315SChristos Margiolis 		break;
187c15c9315SChristos Margiolis 	case PCMTRIG_STOP:
188c15c9315SChristos Margiolis 	case PCMTRIG_ABORT:
189c15c9315SChristos Margiolis 		ch->run = 0;
190c15c9315SChristos Margiolis 		if (callout_active(&sc->callout))
191c15c9315SChristos Margiolis 			callout_stop(&sc->callout);
192c15c9315SChristos Margiolis 	default:
193c15c9315SChristos Margiolis 		break;
194c15c9315SChristos Margiolis 	}
195c15c9315SChristos Margiolis 
196c15c9315SChristos Margiolis 	snd_mtxunlock(sc->lock);
197c15c9315SChristos Margiolis 
198c15c9315SChristos Margiolis 	return (0);
199c15c9315SChristos Margiolis }
200c15c9315SChristos Margiolis 
201c15c9315SChristos Margiolis static uint32_t
202c15c9315SChristos Margiolis dummy_chan_getptr(kobj_t obj, void *data)
203c15c9315SChristos Margiolis {
204c15c9315SChristos Margiolis 	struct dummy_chan *ch = data;
205c15c9315SChristos Margiolis 
206c15c9315SChristos Margiolis 	return (ch->run ? ch->ptr : 0);
207c15c9315SChristos Margiolis }
208c15c9315SChristos Margiolis 
209c15c9315SChristos Margiolis static struct pcmchan_caps *
210c15c9315SChristos Margiolis dummy_chan_getcaps(kobj_t obj, void *data)
211c15c9315SChristos Margiolis {
212c15c9315SChristos Margiolis 	struct dummy_chan *ch = data;
213c15c9315SChristos Margiolis 
214c15c9315SChristos Margiolis 	return (ch->caps);
215c15c9315SChristos Margiolis }
216c15c9315SChristos Margiolis 
217c15c9315SChristos Margiolis static kobj_method_t dummy_chan_methods[] = {
218c15c9315SChristos Margiolis 	KOBJMETHOD(channel_init,	dummy_chan_init),
219c15c9315SChristos Margiolis 	KOBJMETHOD(channel_free,	dummy_chan_free),
220c15c9315SChristos Margiolis 	KOBJMETHOD(channel_setformat,	dummy_chan_setformat),
221c15c9315SChristos Margiolis 	KOBJMETHOD(channel_setspeed,	dummy_chan_setspeed),
222c15c9315SChristos Margiolis 	KOBJMETHOD(channel_setblocksize,dummy_chan_setblocksize),
223c15c9315SChristos Margiolis 	KOBJMETHOD(channel_trigger,	dummy_chan_trigger),
224c15c9315SChristos Margiolis 	KOBJMETHOD(channel_getptr,	dummy_chan_getptr),
225c15c9315SChristos Margiolis 	KOBJMETHOD(channel_getcaps,	dummy_chan_getcaps),
226c15c9315SChristos Margiolis 	KOBJMETHOD_END
227c15c9315SChristos Margiolis };
228c15c9315SChristos Margiolis 
229c15c9315SChristos Margiolis CHANNEL_DECLARE(dummy_chan);
230c15c9315SChristos Margiolis 
231c15c9315SChristos Margiolis static int
232c15c9315SChristos Margiolis dummy_mixer_init(struct snd_mixer *m)
233c15c9315SChristos Margiolis {
234c15c9315SChristos Margiolis 	struct dummy_softc *sc;
235c15c9315SChristos Margiolis 
236c15c9315SChristos Margiolis 	sc = mix_getdevinfo(m);
237c15c9315SChristos Margiolis 	if (sc == NULL)
238c15c9315SChristos Margiolis 		return (-1);
239c15c9315SChristos Margiolis 
240c15c9315SChristos Margiolis 	pcm_setflags(sc->dev, pcm_getflags(sc->dev) | SD_F_SOFTPCMVOL);
241c15c9315SChristos Margiolis 	mix_setdevs(m, SOUND_MASK_PCM | SOUND_MASK_VOLUME | SOUND_MASK_RECLEV);
242c15c9315SChristos Margiolis 	mix_setrecdevs(m, SOUND_MASK_RECLEV);
243c15c9315SChristos Margiolis 
244c15c9315SChristos Margiolis 	return (0);
245c15c9315SChristos Margiolis }
246c15c9315SChristos Margiolis 
247c15c9315SChristos Margiolis static int
248c15c9315SChristos Margiolis dummy_mixer_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right)
249c15c9315SChristos Margiolis {
250c15c9315SChristos Margiolis 	return (0);
251c15c9315SChristos Margiolis }
252c15c9315SChristos Margiolis 
253c15c9315SChristos Margiolis static uint32_t
254c15c9315SChristos Margiolis dummy_mixer_setrecsrc(struct snd_mixer *m, uint32_t src)
255c15c9315SChristos Margiolis {
256c15c9315SChristos Margiolis 	return (src == SOUND_MASK_RECLEV ? src : 0);
257c15c9315SChristos Margiolis }
258c15c9315SChristos Margiolis 
259c15c9315SChristos Margiolis static kobj_method_t dummy_mixer_methods[] = {
260c15c9315SChristos Margiolis 	KOBJMETHOD(mixer_init,		dummy_mixer_init),
261c15c9315SChristos Margiolis 	KOBJMETHOD(mixer_set,		dummy_mixer_set),
262c15c9315SChristos Margiolis 	KOBJMETHOD(mixer_setrecsrc,	dummy_mixer_setrecsrc),
263c15c9315SChristos Margiolis 	KOBJMETHOD_END
264c15c9315SChristos Margiolis };
265c15c9315SChristos Margiolis 
266c15c9315SChristos Margiolis MIXER_DECLARE(dummy_mixer);
267c15c9315SChristos Margiolis 
268c15c9315SChristos Margiolis static void
269c15c9315SChristos Margiolis dummy_identify(driver_t *driver, device_t parent)
270c15c9315SChristos Margiolis {
271c15c9315SChristos Margiolis 	if (device_find_child(parent, driver->name, -1) != NULL)
272c15c9315SChristos Margiolis 		return;
273c15c9315SChristos Margiolis 	if (BUS_ADD_CHILD(parent, 0, driver->name, -1) == NULL)
274c15c9315SChristos Margiolis 		device_printf(parent, "add child failed\n");
275c15c9315SChristos Margiolis }
276c15c9315SChristos Margiolis 
277c15c9315SChristos Margiolis static int
278c15c9315SChristos Margiolis dummy_probe(device_t dev)
279c15c9315SChristos Margiolis {
280c15c9315SChristos Margiolis 	device_set_desc(dev, "Dummy Audio Device");
281c15c9315SChristos Margiolis 
282c15c9315SChristos Margiolis 	return (0);
283c15c9315SChristos Margiolis }
284c15c9315SChristos Margiolis 
285c15c9315SChristos Margiolis static int
286c15c9315SChristos Margiolis dummy_attach(device_t dev)
287c15c9315SChristos Margiolis {
288c15c9315SChristos Margiolis 	struct dummy_softc *sc;
289c15c9315SChristos Margiolis 	char status[SND_STATUSLEN];
290c15c9315SChristos Margiolis 	int i = 0;
291c15c9315SChristos Margiolis 
292c15c9315SChristos Margiolis 	sc = device_get_softc(dev);
293c15c9315SChristos Margiolis 	sc->dev = dev;
294c15c9315SChristos Margiolis 	sc->lock = snd_mtxcreate(device_get_nameunit(dev), "snd_dummy softc");
295c15c9315SChristos Margiolis 
296c15c9315SChristos Margiolis 	sc->cap_fmts[0] = SND_FORMAT(AFMT_S32_LE, 2, 0);
297c15c9315SChristos Margiolis 	sc->cap_fmts[1] = SND_FORMAT(AFMT_S24_LE, 2, 0);
298c15c9315SChristos Margiolis 	sc->cap_fmts[2] = SND_FORMAT(AFMT_S16_LE, 2, 0);
299c15c9315SChristos Margiolis 	sc->cap_fmts[3] = 0;
300c15c9315SChristos Margiolis 	sc->caps = (struct pcmchan_caps){
301c15c9315SChristos Margiolis 		8000,		/* minspeed */
302c15c9315SChristos Margiolis 		96000,		/* maxspeed */
303c15c9315SChristos Margiolis 		sc->cap_fmts,	/* fmtlist */
304c15c9315SChristos Margiolis 		0,		/* caps */
305c15c9315SChristos Margiolis 	};
306c15c9315SChristos Margiolis 
307c15c9315SChristos Margiolis 	pcm_setflags(dev, pcm_getflags(dev) | SD_F_MPSAFE);
308*516a9c02SChristos Margiolis 	pcm_init(dev, sc);
309c15c9315SChristos Margiolis 	for (i = 0; i < DUMMY_NPCHAN; i++)
310c15c9315SChristos Margiolis 		pcm_addchan(dev, PCMDIR_PLAY, &dummy_chan_class, sc);
311c15c9315SChristos Margiolis 	for (i = 0; i < DUMMY_NRCHAN; i++)
312c15c9315SChristos Margiolis 		pcm_addchan(dev, PCMDIR_REC, &dummy_chan_class, sc);
313c15c9315SChristos Margiolis 
314c15c9315SChristos Margiolis 	snprintf(status, SND_STATUSLEN, "on %s",
315c15c9315SChristos Margiolis 	    device_get_nameunit(device_get_parent(dev)));
316*516a9c02SChristos Margiolis 	if (pcm_register(dev, status))
317*516a9c02SChristos Margiolis 		return (ENXIO);
318c15c9315SChristos Margiolis 	mixer_init(dev, &dummy_mixer_class, sc);
319c15c9315SChristos Margiolis 	callout_init(&sc->callout, 1);
320c15c9315SChristos Margiolis 
321c15c9315SChristos Margiolis 	return (0);
322c15c9315SChristos Margiolis }
323c15c9315SChristos Margiolis 
324c15c9315SChristos Margiolis static int
325c15c9315SChristos Margiolis dummy_detach(device_t dev)
326c15c9315SChristos Margiolis {
327c15c9315SChristos Margiolis 	struct dummy_softc *sc = device_get_softc(dev);
328c15c9315SChristos Margiolis 	int err;
329c15c9315SChristos Margiolis 
330e42c8267SChristos Margiolis 	callout_drain(&sc->callout);
331c15c9315SChristos Margiolis 	err = pcm_unregister(dev);
332c15c9315SChristos Margiolis 	snd_mtxfree(sc->lock);
333c15c9315SChristos Margiolis 
334c15c9315SChristos Margiolis 	return (err);
335c15c9315SChristos Margiolis }
336c15c9315SChristos Margiolis 
337c15c9315SChristos Margiolis static device_method_t dummy_methods[] = {
338c15c9315SChristos Margiolis 	/* Device interface */
339c15c9315SChristos Margiolis 	DEVMETHOD(device_identify,	dummy_identify),
340c15c9315SChristos Margiolis 	DEVMETHOD(device_probe,		dummy_probe),
341c15c9315SChristos Margiolis 	DEVMETHOD(device_attach,	dummy_attach),
342c15c9315SChristos Margiolis 	DEVMETHOD(device_detach,	dummy_detach),
343c15c9315SChristos Margiolis 	DEVMETHOD_END
344c15c9315SChristos Margiolis };
345c15c9315SChristos Margiolis 
346c15c9315SChristos Margiolis static driver_t dummy_driver = {
347c15c9315SChristos Margiolis 	"pcm",
348c15c9315SChristos Margiolis 	dummy_methods,
349c15c9315SChristos Margiolis 	sizeof(struct dummy_softc),
350c15c9315SChristos Margiolis };
351c15c9315SChristos Margiolis 
352c15c9315SChristos Margiolis DRIVER_MODULE(snd_dummy, nexus, dummy_driver, 0, 0);
353c15c9315SChristos Margiolis MODULE_DEPEND(snd_dummy, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER);
354c15c9315SChristos Margiolis MODULE_VERSION(snd_dummy, 1);
355