1c15c9315SChristos Margiolis /*-
2c15c9315SChristos Margiolis * SPDX-License-Identifier: BSD-2-Clause
3c15c9315SChristos Margiolis *
4*c824383bSChristos Margiolis * Copyright (c) 2024-2025 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
705bd08172SChristos Margiolis static bool
dummy_active(struct dummy_softc * sc)715bd08172SChristos Margiolis dummy_active(struct dummy_softc *sc)
725bd08172SChristos Margiolis {
735bd08172SChristos Margiolis struct dummy_chan *ch;
745bd08172SChristos Margiolis int i;
755bd08172SChristos Margiolis
765bd08172SChristos Margiolis snd_mtxassert(sc->lock);
775bd08172SChristos Margiolis
785bd08172SChristos Margiolis for (i = 0; i < sc->chnum; i++) {
795bd08172SChristos Margiolis ch = &sc->chans[i];
805bd08172SChristos Margiolis if (ch->run)
815bd08172SChristos Margiolis return (true);
825bd08172SChristos Margiolis }
835bd08172SChristos Margiolis
845bd08172SChristos Margiolis /* No channel is running at the moment. */
855bd08172SChristos Margiolis return (false);
865bd08172SChristos Margiolis }
875bd08172SChristos Margiolis
88c15c9315SChristos Margiolis static void
dummy_chan_io(void * arg)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
955bd08172SChristos Margiolis /* Do not reschedule if no channel is running. */
965bd08172SChristos Margiolis if (!dummy_active(sc))
975bd08172SChristos 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
dummy_chan_free(kobj_t obj,void * data)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 *
dummy_chan_init(kobj_t obj,void * devinfo,struct snd_dbuf * b,struct pcm_channel * c,int dir)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
dummy_chan_setformat(kobj_t obj,void * data,uint32_t format)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
dummy_chan_setspeed(kobj_t obj,void * data,uint32_t speed)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
dummy_chan_setblocksize(kobj_t obj,void * data,uint32_t blocksize)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
dummy_chan_trigger(kobj_t obj,void * data,int go)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;
2025bd08172SChristos 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;
2075bd08172SChristos Margiolis /* If all channels are stopped, stop the callout as well. */
2085bd08172SChristos 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
dummy_chan_getptr(kobj_t obj,void * data)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 *
dummy_chan_getcaps(kobj_t obj,void * data)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
dummy_mixer_init(struct snd_mixer * m)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
dummy_mixer_set(struct snd_mixer * m,unsigned dev,unsigned left,unsigned right)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
dummy_mixer_setrecsrc(struct snd_mixer * m,uint32_t src)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
dummy_identify(driver_t * driver,device_t parent)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
dummy_probe(device_t dev)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
dummy_attach(device_t dev)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");
3135bd08172SChristos 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
dummy_detach(device_t dev)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);
3495bd08172SChristos 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