2 * Copyright (c) 2015 Oleksandr Tymoshenko <gonzo@freebsd.org>
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 #ifdef HAVE_KERNEL_OPTION_HEADERS
30 #include <dev/sound/pcm/sound.h>
31 #include <dev/sound/chip.h>
35 #include "interface/compat/vchi_bsd.h"
36 #include "interface/vchi/vchi.h"
37 #include "interface/vchiq_arm/vchiq.h"
39 #include "vc_vchi_audioserv_defs.h"
41 SND_DECLARE_FILE("$FreeBSD$");
44 #define DEST_HEADPHONES 1
47 #define VCHIQ_AUDIO_PACKET_SIZE 4000
48 #define VCHIQ_AUDIO_BUFFER_SIZE 128000
50 #define VCHIQ_AUDIO_MAX_VOLUME
51 /* volume in terms of 0.01dB */
52 #define VCHIQ_AUDIO_VOLUME_MIN -10239
53 #define VCHIQ_AUDIO_VOLUME(db100) (uint32_t)(-((db100) << 8)/100)
55 /* dB levels with 5% volume step */
56 static int db_levels[] = {
57 VCHIQ_AUDIO_VOLUME_MIN, -4605, -3794, -3218, -2772,
58 -2407, -2099, -1832, -1597, -1386,
59 -1195, -1021, -861, -713, -575,
60 -446, -325, -210, -102, 0,
63 static uint32_t bcm2835_audio_playfmt[] = {
64 SND_FORMAT(AFMT_U8, 1, 0),
65 SND_FORMAT(AFMT_U8, 2, 0),
66 SND_FORMAT(AFMT_S8, 1, 0),
67 SND_FORMAT(AFMT_S8, 2, 0),
68 SND_FORMAT(AFMT_S16_LE, 1, 0),
69 SND_FORMAT(AFMT_S16_LE, 2, 0),
70 SND_FORMAT(AFMT_U16_LE, 1, 0),
71 SND_FORMAT(AFMT_U16_LE, 2, 0),
75 static struct pcmchan_caps bcm2835_audio_playcaps = {8000, 48000, bcm2835_audio_playfmt, 0};
77 struct bcm2835_audio_info;
79 #define PLAYBACK_IDLE 0
80 #define PLAYBACK_STARTING 1
81 #define PLAYBACK_PLAYING 2
82 #define PLAYBACK_STOPPING 3
84 struct bcm2835_audio_chinfo {
85 struct bcm2835_audio_info *parent;
86 struct pcm_channel *channel;
87 struct snd_dbuf *buffer;
88 uint32_t fmt, spd, blksz;
90 uint32_t complete_pos;
92 uint32_t buffered_ptr;
96 struct bcm2835_audio_info {
99 struct bcm2835_audio_chinfo pch;
100 uint32_t dest, volume;
102 struct intr_config_hook intr_hook;
105 struct mtx vchi_lock;
107 VCHI_INSTANCE_T vchi_instance;
108 VCHI_CONNECTION_T *vchi_connection;
109 VCHI_SERVICE_HANDLE_T vchi_handle;
111 struct mtx data_lock;
114 /* Unloadign module */
118 #define bcm2835_audio_lock(_ess) snd_mtxlock((_ess)->lock)
119 #define bcm2835_audio_unlock(_ess) snd_mtxunlock((_ess)->lock)
120 #define bcm2835_audio_lock_assert(_ess) snd_mtxassert((_ess)->lock)
122 #define VCHIQ_VCHI_LOCK(sc) mtx_lock(&(sc)->vchi_lock)
123 #define VCHIQ_VCHI_UNLOCK(sc) mtx_unlock(&(sc)->vchi_lock)
126 dest_description(uint32_t dest)
133 case DEST_HEADPHONES:
147 bcm2835_audio_callback(void *param, const VCHI_CALLBACK_REASON_T reason, void *msg_handle)
149 struct bcm2835_audio_info *sc = (struct bcm2835_audio_info *)param;
154 if (reason != VCHI_CALLBACK_MSG_AVAILABLE)
157 status = vchi_msg_dequeue(sc->vchi_handle,
158 &m, sizeof m, &msg_len, VCHI_FLAGS_NONE);
159 if (m.type == VC_AUDIO_MSG_TYPE_RESULT) {
160 if (m.u.result.success) {
161 device_printf(sc->dev,
162 "msg type %08x failed\n",
165 } else if (m.type == VC_AUDIO_MSG_TYPE_COMPLETE) {
166 struct bcm2835_audio_chinfo *ch = m.u.complete.cookie;
168 int count = m.u.complete.count & 0xffff;
169 int perr = (m.u.complete.count & (1U << 30)) != 0;
171 ch->complete_pos = (ch->complete_pos + count) % sndbuf_getsize(ch->buffer);
172 ch->free_buffer += count;
174 if (perr || ch->free_buffer >= VCHIQ_AUDIO_PACKET_SIZE) {
175 chn_intr(ch->channel);
176 cv_signal(&sc->data_cv);
179 printf("%s: unknown m.type: %d\n", __func__, m.type);
184 bcm2835_audio_init(struct bcm2835_audio_info *sc)
188 /* Initialize and create a VCHI connection */
189 status = vchi_initialise(&sc->vchi_instance);
191 printf("vchi_initialise failed: %d\n", status);
195 status = vchi_connect(NULL, 0, sc->vchi_instance);
197 printf("vchi_connect failed: %d\n", status);
201 SERVICE_CREATION_T params = {
202 VCHI_VERSION_EX(VC_AUDIOSERV_VER, VC_AUDIOSERV_MIN_VER),
203 VC_AUDIO_SERVER_NAME, /* 4cc service code */
204 sc->vchi_connection, /* passed in fn pointers */
205 0, /* rx fifo size */
206 0, /* tx fifo size */
207 bcm2835_audio_callback, /* service callback */
208 sc, /* service callback parameter */
211 0 /* want crc check on bulk transfers */
214 status = vchi_service_open(sc->vchi_instance, ¶ms,
218 /* Finished with the service for now */
219 vchi_service_release(sc->vchi_handle);
221 sc->vchi_handle = VCHIQ_SERVICE_HANDLE_INVALID;
225 bcm2835_audio_release(struct bcm2835_audio_info *sc)
229 if (sc->vchi_handle != VCHIQ_SERVICE_HANDLE_INVALID) {
230 vchi_service_use(sc->vchi_handle);
231 success = vchi_service_close(sc->vchi_handle);
233 printf("vchi_service_close failed: %d\n", success);
234 sc->vchi_handle = VCHIQ_SERVICE_HANDLE_INVALID;
237 vchi_disconnect(sc->vchi_instance);
241 bcm2835_audio_reset_channel(struct bcm2835_audio_chinfo *ch)
243 ch->free_buffer = VCHIQ_AUDIO_BUFFER_SIZE;
244 ch->playback_state = 0;
245 ch->buffered_ptr = 0;
246 ch->complete_pos = 0;
248 sndbuf_reset(ch->buffer);
252 bcm2835_audio_start(struct bcm2835_audio_chinfo *ch)
256 struct bcm2835_audio_info *sc = ch->parent;
259 if (sc->vchi_handle != VCHIQ_SERVICE_HANDLE_INVALID) {
260 vchi_service_use(sc->vchi_handle);
262 bcm2835_audio_reset_channel(ch);
264 m.type = VC_AUDIO_MSG_TYPE_START;
265 ret = vchi_msg_queue(sc->vchi_handle,
266 &m, sizeof m, VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);
269 printf("%s: vchi_msg_queue failed (err %d)\n", __func__, ret);
271 vchi_service_release(sc->vchi_handle);
273 VCHIQ_VCHI_UNLOCK(sc);
278 bcm2835_audio_stop(struct bcm2835_audio_chinfo *ch)
282 struct bcm2835_audio_info *sc = ch->parent;
285 if (sc->vchi_handle != VCHIQ_SERVICE_HANDLE_INVALID) {
286 vchi_service_use(sc->vchi_handle);
288 m.type = VC_AUDIO_MSG_TYPE_STOP;
289 m.u.stop.draining = 0;
291 ret = vchi_msg_queue(sc->vchi_handle,
292 &m, sizeof m, VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);
295 printf("%s: vchi_msg_queue failed (err %d)\n", __func__, ret);
297 vchi_service_release(sc->vchi_handle);
299 VCHIQ_VCHI_UNLOCK(sc);
303 bcm2835_audio_open(struct bcm2835_audio_info *sc)
309 if (sc->vchi_handle != VCHIQ_SERVICE_HANDLE_INVALID) {
310 vchi_service_use(sc->vchi_handle);
312 m.type = VC_AUDIO_MSG_TYPE_OPEN;
313 ret = vchi_msg_queue(sc->vchi_handle,
314 &m, sizeof m, VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);
317 printf("%s: vchi_msg_queue failed (err %d)\n", __func__, ret);
319 vchi_service_release(sc->vchi_handle);
321 VCHIQ_VCHI_UNLOCK(sc);
325 bcm2835_audio_update_controls(struct bcm2835_audio_info *sc)
331 if (sc->vchi_handle != VCHIQ_SERVICE_HANDLE_INVALID) {
332 vchi_service_use(sc->vchi_handle);
334 m.type = VC_AUDIO_MSG_TYPE_CONTROL;
335 m.u.control.dest = sc->dest;
338 db = db_levels[sc->volume/5];
339 m.u.control.volume = VCHIQ_AUDIO_VOLUME(db);
341 ret = vchi_msg_queue(sc->vchi_handle,
342 &m, sizeof m, VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);
345 printf("%s: vchi_msg_queue failed (err %d)\n", __func__, ret);
347 vchi_service_release(sc->vchi_handle);
349 VCHIQ_VCHI_UNLOCK(sc);
353 bcm2835_audio_update_params(struct bcm2835_audio_info *sc, struct bcm2835_audio_chinfo *ch)
359 if (sc->vchi_handle != VCHIQ_SERVICE_HANDLE_INVALID) {
360 vchi_service_use(sc->vchi_handle);
362 m.type = VC_AUDIO_MSG_TYPE_CONFIG;
363 m.u.config.channels = AFMT_CHANNEL(ch->fmt);
364 m.u.config.samplerate = ch->spd;
365 m.u.config.bps = AFMT_BIT(ch->fmt);
367 ret = vchi_msg_queue(sc->vchi_handle,
368 &m, sizeof m, VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);
371 printf("%s: vchi_msg_queue failed (err %d)\n", __func__, ret);
373 vchi_service_release(sc->vchi_handle);
375 VCHIQ_VCHI_UNLOCK(sc);
378 static __inline uint32_t
379 vchiq_unbuffered_bytes(struct bcm2835_audio_chinfo *ch)
381 uint32_t size, ready, readyptr, readyend;
383 size = sndbuf_getsize(ch->buffer);
384 readyptr = sndbuf_getreadyptr(ch->buffer);
385 ready = sndbuf_getready(ch->buffer);
387 readyend = readyptr + ready;
389 if (ch->buffered_ptr >= readyptr) {
390 if (readyend > ch->buffered_ptr)
391 return readyend - ch->buffered_ptr;
395 else { /* buffered_ptr overflow */
396 if (readyend > ch->buffered_ptr + size)
397 return readyend - ch->buffered_ptr - size;
404 bcm2835_audio_write_samples(struct bcm2835_audio_chinfo *ch)
406 struct bcm2835_audio_info *sc = ch->parent;
409 uint32_t count, size;
413 if (sc->vchi_handle == VCHIQ_SERVICE_HANDLE_INVALID) {
414 VCHIQ_VCHI_UNLOCK(sc);
418 vchi_service_use(sc->vchi_handle);
420 size = sndbuf_getsize(ch->buffer);
421 count = vchiq_unbuffered_bytes(ch);
422 buf = (uint8_t*)sndbuf_getbuf(ch->buffer) + ch->buffered_ptr;
424 if (ch->buffered_ptr + count > size)
425 count = size - ch->buffered_ptr;
427 if (count < VCHIQ_AUDIO_PACKET_SIZE)
430 count = min(count, ch->free_buffer);
431 count -= count % VCHIQ_AUDIO_PACKET_SIZE;
433 m.type = VC_AUDIO_MSG_TYPE_WRITE;
434 m.u.write.count = count;
435 m.u.write.max_packet = VCHIQ_AUDIO_PACKET_SIZE;
436 m.u.write.callback = NULL;
437 m.u.write.cookie = ch;
439 m.u.write.silence = 0;
441 m.u.write.silence = 1;
443 ret = vchi_msg_queue(sc->vchi_handle,
444 &m, sizeof m, VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);
447 printf("%s: vchi_msg_queue failed (err %d)\n", __func__, ret);
451 int bytes = MIN((int)m.u.write.max_packet, (int)count);
452 ch->free_buffer -= bytes;
453 ch->buffered_ptr += bytes;
454 ch->buffered_ptr = ch->buffered_ptr % size;
455 ret = vchi_msg_queue(sc->vchi_handle,
456 buf, bytes, VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);
458 printf("%s: vchi_msg_queue failed: %d\n",
460 buf = (char *)buf + bytes;
466 vchi_service_release(sc->vchi_handle);
467 VCHIQ_VCHI_UNLOCK(sc);
471 bcm2835_audio_worker(void *data)
473 struct bcm2835_audio_info *sc = (struct bcm2835_audio_info *)data;
474 struct bcm2835_audio_chinfo *ch = &sc->pch;
475 mtx_lock(&sc->data_lock);
481 if ((ch->playback_state == PLAYBACK_PLAYING) &&
482 (vchiq_unbuffered_bytes(ch) >= VCHIQ_AUDIO_PACKET_SIZE)
483 && (ch->free_buffer >= VCHIQ_AUDIO_PACKET_SIZE)) {
484 bcm2835_audio_write_samples(ch);
486 if (ch->playback_state == PLAYBACK_STOPPING) {
487 bcm2835_audio_reset_channel(&sc->pch);
488 ch->playback_state = PLAYBACK_IDLE;
491 cv_wait_sig(&sc->data_cv, &sc->data_lock);
493 if (ch->playback_state == PLAYBACK_STARTING) {
494 /* Give it initial kick */
495 chn_intr(sc->pch.channel);
496 ch->playback_state = PLAYBACK_PLAYING;
500 mtx_unlock(&sc->data_lock);
506 bcm2835_audio_create_worker(struct bcm2835_audio_info *sc)
510 if (kproc_create(bcm2835_audio_worker, (void*)sc, &newp, 0, 0,
511 "bcm2835_audio_worker") != 0) {
512 printf("failed to create bcm2835_audio_worker\n");
516 /* -------------------------------------------------------------------- */
517 /* channel interface for ESS18xx */
519 bcmchan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir)
521 struct bcm2835_audio_info *sc = devinfo;
522 struct bcm2835_audio_chinfo *ch = &sc->pch;
525 if (dir == PCMDIR_REC)
534 ch->fmt = SND_FORMAT(AFMT_S16_LE, 2, 0);
535 ch->blksz = VCHIQ_AUDIO_PACKET_SIZE;
537 buffer = malloc(sc->bufsz, M_DEVBUF, M_WAITOK | M_ZERO);
539 if (sndbuf_setup(ch->buffer, buffer, sc->bufsz) != 0) {
540 free(buffer, M_DEVBUF);
544 bcm2835_audio_update_params(sc, ch);
550 bcmchan_free(kobj_t obj, void *data)
552 struct bcm2835_audio_chinfo *ch = data;
555 buffer = sndbuf_getbuf(ch->buffer);
557 free(buffer, M_DEVBUF);
563 bcmchan_setformat(kobj_t obj, void *data, uint32_t format)
565 struct bcm2835_audio_chinfo *ch = data;
566 struct bcm2835_audio_info *sc = ch->parent;
568 bcm2835_audio_lock(sc);
571 bcm2835_audio_update_params(sc, ch);
573 bcm2835_audio_unlock(sc);
579 bcmchan_setspeed(kobj_t obj, void *data, uint32_t speed)
581 struct bcm2835_audio_chinfo *ch = data;
582 struct bcm2835_audio_info *sc = ch->parent;
584 bcm2835_audio_lock(sc);
587 bcm2835_audio_update_params(sc, ch);
589 bcm2835_audio_unlock(sc);
595 bcmchan_setblocksize(kobj_t obj, void *data, uint32_t blocksize)
597 struct bcm2835_audio_chinfo *ch = data;
603 bcmchan_trigger(kobj_t obj, void *data, int go)
605 struct bcm2835_audio_chinfo *ch = data;
606 struct bcm2835_audio_info *sc = ch->parent;
608 if (!PCMTRIG_COMMON(go))
611 bcm2835_audio_lock(sc);
615 bcm2835_audio_start(ch);
616 ch->playback_state = PLAYBACK_STARTING;
617 /* wakeup worker thread */
618 cv_signal(&sc->data_cv);
623 ch->playback_state = 1;
624 bcm2835_audio_stop(ch);
631 bcm2835_audio_unlock(sc);
636 bcmchan_getptr(kobj_t obj, void *data)
638 struct bcm2835_audio_chinfo *ch = data;
639 struct bcm2835_audio_info *sc = ch->parent;
642 bcm2835_audio_lock(sc);
644 ret = ch->complete_pos - (ch->complete_pos % VCHIQ_AUDIO_PACKET_SIZE);
646 bcm2835_audio_unlock(sc);
651 static struct pcmchan_caps *
652 bcmchan_getcaps(kobj_t obj, void *data)
655 return &bcm2835_audio_playcaps;
658 static kobj_method_t bcmchan_methods[] = {
659 KOBJMETHOD(channel_init, bcmchan_init),
660 KOBJMETHOD(channel_free, bcmchan_free),
661 KOBJMETHOD(channel_setformat, bcmchan_setformat),
662 KOBJMETHOD(channel_setspeed, bcmchan_setspeed),
663 KOBJMETHOD(channel_setblocksize, bcmchan_setblocksize),
664 KOBJMETHOD(channel_trigger, bcmchan_trigger),
665 KOBJMETHOD(channel_getptr, bcmchan_getptr),
666 KOBJMETHOD(channel_getcaps, bcmchan_getcaps),
669 CHANNEL_DECLARE(bcmchan);
671 /************************************************************/
674 bcmmix_init(struct snd_mixer *m)
677 mix_setdevs(m, SOUND_MASK_VOLUME);
683 bcmmix_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right)
685 struct bcm2835_audio_info *sc = mix_getdevinfo(m);
688 case SOUND_MIXER_VOLUME:
690 bcm2835_audio_update_controls(sc);
697 return left | (left << 8);
700 static kobj_method_t bcmmixer_methods[] = {
701 KOBJMETHOD(mixer_init, bcmmix_init),
702 KOBJMETHOD(mixer_set, bcmmix_set),
706 MIXER_DECLARE(bcmmixer);
709 sysctl_bcm2835_audio_dest(SYSCTL_HANDLER_ARGS)
711 struct bcm2835_audio_info *sc = arg1;
716 err = sysctl_handle_int(oidp, &val, 0, req);
717 if (err || !req->newptr) /* error || read request */
720 if ((val < 0) || (val > 2))
724 device_printf(sc->dev, "destination set to %s\n", dest_description(val));
725 bcm2835_audio_update_controls(sc);
731 vchi_audio_sysctl_init(struct bcm2835_audio_info *sc)
733 struct sysctl_ctx_list *ctx;
734 struct sysctl_oid *tree_node;
735 struct sysctl_oid_list *tree;
738 * Add system sysctl tree/handlers.
740 ctx = device_get_sysctl_ctx(sc->dev);
741 tree_node = device_get_sysctl_tree(sc->dev);
742 tree = SYSCTL_CHILDREN(tree_node);
743 SYSCTL_ADD_PROC(ctx, tree, OID_AUTO, "dest",
744 CTLFLAG_RW | CTLTYPE_UINT, sc, sizeof(*sc),
745 sysctl_bcm2835_audio_dest, "IU", "audio destination, "
746 "0 - auto, 1 - headphones, 2 - HDMI");
750 bcm2835_audio_identify(driver_t *driver, device_t parent)
753 BUS_ADD_CHILD(parent, 0, "pcm", 0);
757 bcm2835_audio_probe(device_t dev)
760 device_set_desc(dev, "VCHQI audio");
761 return (BUS_PROBE_DEFAULT);
766 bcm2835_audio_delayed_init(void *xsc)
768 struct bcm2835_audio_info *sc;
769 char status[SND_STATUSLEN];
773 config_intrhook_disestablish(&sc->intr_hook);
775 bcm2835_audio_init(sc);
776 bcm2835_audio_open(sc);
778 sc->dest = DEST_AUTO;
780 if (mixer_init(sc->dev, &bcmmixer_class, sc)) {
781 device_printf(sc->dev, "mixer_init failed\n");
785 if (pcm_register(sc->dev, sc, 1, 1)) {
786 device_printf(sc->dev, "pcm_register failed\n");
790 pcm_addchan(sc->dev, PCMDIR_PLAY, &bcmchan_class, sc);
791 snprintf(status, SND_STATUSLEN, "at VCHIQ");
792 pcm_setstatus(sc->dev, status);
794 bcm2835_audio_reset_channel(&sc->pch);
795 bcm2835_audio_create_worker(sc);
797 vchi_audio_sysctl_init(sc);
804 bcm2835_audio_attach(device_t dev)
806 struct bcm2835_audio_info *sc;
808 sc = malloc(sizeof(*sc), M_DEVBUF, M_WAITOK | M_ZERO);
811 sc->bufsz = VCHIQ_AUDIO_BUFFER_SIZE;
813 sc->lock = snd_mtxcreate(device_get_nameunit(dev), "bcm2835_audio softc");
815 mtx_init(&sc->vchi_lock, "bcm2835_audio", "vchi_lock", MTX_DEF);
816 mtx_init(&sc->data_lock, "data_mtx", "data_mtx", MTX_DEF);
817 cv_init(&sc->data_cv, "data_cv");
818 sc->vchi_handle = VCHIQ_SERVICE_HANDLE_INVALID;
821 * We need interrupts enabled for VCHI to work properly,
822 * so delay intialization until it happens
824 sc->intr_hook.ich_func = bcm2835_audio_delayed_init;
825 sc->intr_hook.ich_arg = sc;
827 if (config_intrhook_establish(&sc->intr_hook) != 0)
837 bcm2835_audio_detach(device_t dev)
840 struct bcm2835_audio_info *sc;
841 sc = pcm_getdevinfo(dev);
843 /* Stop worker thread */
845 cv_signal(&sc->data_cv);
847 r = pcm_unregister(dev);
851 mtx_destroy(&sc->vchi_lock);
852 mtx_destroy(&sc->data_lock);
853 cv_destroy(&sc->data_cv);
855 bcm2835_audio_release(sc);
858 snd_mtxfree(sc->lock);
867 static device_method_t bcm2835_audio_methods[] = {
868 /* Device interface */
869 DEVMETHOD(device_identify, bcm2835_audio_identify),
870 DEVMETHOD(device_probe, bcm2835_audio_probe),
871 DEVMETHOD(device_attach, bcm2835_audio_attach),
872 DEVMETHOD(device_detach, bcm2835_audio_detach),
877 static driver_t bcm2835_audio_driver = {
879 bcm2835_audio_methods,
883 DRIVER_MODULE(bcm2835_audio, vchiq, bcm2835_audio_driver, pcm_devclass, 0, 0);
884 MODULE_DEPEND(bcm2835_audio, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER);
885 MODULE_DEPEND(bcm2835_audio, vchiq, 1, 1, 1);
886 MODULE_VERSION(bcm2835_audio, 1);