xref: /freebsd/sys/arm/broadcom/bcm2835/bcm2835_audio.c (revision d9f0ce31900a48d1a2bfc1c8c86f79d1e831451a)
1 /*-
2  * Copyright (c) 2015 Oleksandr Tymoshenko <gonzo@freebsd.org>
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
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.
12  *
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
23  * SUCH DAMAGE.
24  */
25 
26 #ifdef HAVE_KERNEL_OPTION_HEADERS
27 #include "opt_snd.h"
28 #endif
29 
30 #include <dev/sound/pcm/sound.h>
31 #include <dev/sound/chip.h>
32 
33 #include "mixer_if.h"
34 
35 #include "interface/compat/vchi_bsd.h"
36 #include "interface/vchi/vchi.h"
37 #include "interface/vchiq_arm/vchiq.h"
38 
39 #include "vc_vchi_audioserv_defs.h"
40 
41 SND_DECLARE_FILE("$FreeBSD$");
42 
43 #define	DEST_AUTO		0
44 #define	DEST_HEADPHONES		1
45 #define	DEST_HDMI		2
46 
47 #define	VCHIQ_AUDIO_PACKET_SIZE	4000
48 #define	VCHIQ_AUDIO_BUFFER_SIZE	128000
49 #define	VCHIQ_AUDIO_PREBUFFER	10 /* Number of pre-buffered audio messages */
50 
51 #define	VCHIQ_AUDIO_MAX_VOLUME
52 /* volume in terms of 0.01dB */
53 #define VCHIQ_AUDIO_VOLUME_MIN -10239
54 #define VCHIQ_AUDIO_VOLUME(db100) (uint32_t)(-((db100) << 8)/100)
55 
56 /* dB levels with 5% volume step */
57 static int db_levels[] = {
58 	VCHIQ_AUDIO_VOLUME_MIN, -4605, -3794, -3218, -2772,
59 	-2407, -2099, -1832, -1597, -1386,
60 	-1195, -1021, -861, -713, -575,
61 	-446, -325, -210, -102, 0,
62 };
63 
64 static uint32_t bcm2835_audio_playfmt[] = {
65 	SND_FORMAT(AFMT_U8, 1, 0),
66 	SND_FORMAT(AFMT_U8, 2, 0),
67 	SND_FORMAT(AFMT_S8, 1, 0),
68 	SND_FORMAT(AFMT_S8, 2, 0),
69 	SND_FORMAT(AFMT_S16_LE, 1, 0),
70 	SND_FORMAT(AFMT_S16_LE, 2, 0),
71 	SND_FORMAT(AFMT_U16_LE, 1, 0),
72 	SND_FORMAT(AFMT_U16_LE, 2, 0),
73 	0
74 };
75 
76 static struct pcmchan_caps bcm2835_audio_playcaps = {8000, 48000, bcm2835_audio_playfmt, 0};
77 
78 struct bcm2835_audio_info;
79 
80 #define	PLAYBACK_IDLE		0
81 #define	PLAYBACK_STARTING	1
82 #define	PLAYBACK_PLAYING	2
83 #define	PLAYBACK_STOPPING	3
84 
85 struct bcm2835_audio_chinfo {
86 	struct bcm2835_audio_info *parent;
87 	struct pcm_channel *channel;
88 	struct snd_dbuf *buffer;
89 	uint32_t fmt, spd, blksz;
90 
91 	uint32_t complete_pos;
92 	uint32_t free_buffer;
93 	uint32_t buffered_ptr;
94 	int playback_state;
95 	int prebuffered;
96 };
97 
98 struct bcm2835_audio_info {
99 	device_t dev;
100 	unsigned int bufsz;
101     	struct bcm2835_audio_chinfo pch;
102 	uint32_t dest, volume;
103 	struct mtx *lock;
104 	struct intr_config_hook intr_hook;
105 
106 	/* VCHI data */
107 	struct mtx vchi_lock;
108 
109 	VCHI_INSTANCE_T vchi_instance;
110 	VCHI_CONNECTION_T *vchi_connection;
111 	VCHI_SERVICE_HANDLE_T vchi_handle;
112 
113 	struct mtx data_lock;
114 	struct cv data_cv;
115 
116 	/* Unloadign module */
117 	int unloading;
118 };
119 
120 #define bcm2835_audio_lock(_ess) snd_mtxlock((_ess)->lock)
121 #define bcm2835_audio_unlock(_ess) snd_mtxunlock((_ess)->lock)
122 #define bcm2835_audio_lock_assert(_ess) snd_mtxassert((_ess)->lock)
123 
124 #define VCHIQ_VCHI_LOCK(sc)		mtx_lock(&(sc)->vchi_lock)
125 #define VCHIQ_VCHI_UNLOCK(sc)		mtx_unlock(&(sc)->vchi_lock)
126 
127 static const char *
128 dest_description(uint32_t dest)
129 {
130 	switch (dest) {
131 		case DEST_AUTO:
132 			return "AUTO";
133 			break;
134 
135 		case DEST_HEADPHONES:
136 			return "HEADPHONES";
137 			break;
138 
139 		case DEST_HDMI:
140 			return "HDMI";
141 			break;
142 		default:
143 			return "UNKNOWN";
144 			break;
145 	}
146 }
147 
148 static void
149 bcm2835_audio_callback(void *param, const VCHI_CALLBACK_REASON_T reason, void *msg_handle)
150 {
151 	struct bcm2835_audio_info *sc = (struct bcm2835_audio_info *)param;
152 	int32_t status;
153 	uint32_t msg_len;
154 	VC_AUDIO_MSG_T m;
155 
156 	if (reason != VCHI_CALLBACK_MSG_AVAILABLE)
157 		return;
158 
159 	status = vchi_msg_dequeue(sc->vchi_handle,
160 	    &m, sizeof m, &msg_len, VCHI_FLAGS_NONE);
161 	if (m.type == VC_AUDIO_MSG_TYPE_RESULT) {
162 		if (m.u.result.success) {
163 			device_printf(sc->dev,
164 			    "msg type %08x failed\n",
165 			    m.type);
166 		}
167 	} else if (m.type == VC_AUDIO_MSG_TYPE_COMPLETE) {
168 		struct bcm2835_audio_chinfo *ch = m.u.complete.cookie;
169 
170 		int count = m.u.complete.count & 0xffff;
171 		int perr = (m.u.complete.count & (1U << 30)) != 0;
172 
173 		ch->complete_pos = (ch->complete_pos + count) % sndbuf_getsize(ch->buffer);
174 		ch->free_buffer += count;
175 		chn_intr(sc->pch.channel);
176 
177 		if (perr || ch->free_buffer >= VCHIQ_AUDIO_PACKET_SIZE)
178 			cv_signal(&sc->data_cv);
179 	} else
180 		printf("%s: unknown m.type: %d\n", __func__, m.type);
181 }
182 
183 /* VCHIQ stuff */
184 static void
185 bcm2835_audio_init(struct bcm2835_audio_info *sc)
186 {
187 	int status;
188 
189 	/* Initialize and create a VCHI connection */
190 	status = vchi_initialise(&sc->vchi_instance);
191 	if (status != 0) {
192 		printf("vchi_initialise failed: %d\n", status);
193 		return;
194 	}
195 
196 	status = vchi_connect(NULL, 0, sc->vchi_instance);
197 	if (status != 0) {
198 		printf("vchi_connect failed: %d\n", status);
199 		return;
200 	}
201 
202 	SERVICE_CREATION_T params = {
203 	    VCHI_VERSION_EX(VC_AUDIOSERV_VER, VC_AUDIOSERV_MIN_VER),
204 	    VC_AUDIO_SERVER_NAME,   /* 4cc service code */
205 	    sc->vchi_connection,    /* passed in fn pointers */
206 	    0,  /* rx fifo size */
207 	    0,  /* tx fifo size */
208 	    bcm2835_audio_callback,    /* service callback */
209 	    sc,   /* service callback parameter */
210 	    1,
211 	    1,
212 	    0   /* want crc check on bulk transfers */
213 	};
214 
215 	status = vchi_service_open(sc->vchi_instance, &params,
216 	    &sc->vchi_handle);
217 
218 	if (status == 0)
219 		/* Finished with the service for now */
220 		vchi_service_release(sc->vchi_handle);
221 	else
222 		sc->vchi_handle = VCHIQ_SERVICE_HANDLE_INVALID;
223 }
224 
225 static void
226 bcm2835_audio_release(struct bcm2835_audio_info *sc)
227 {
228 	int success;
229 
230 	if (sc->vchi_handle != VCHIQ_SERVICE_HANDLE_INVALID) {
231 		vchi_service_use(sc->vchi_handle);
232 		success = vchi_service_close(sc->vchi_handle);
233 		if (success != 0)
234 			printf("vchi_service_close failed: %d\n", success);
235 		sc->vchi_handle = VCHIQ_SERVICE_HANDLE_INVALID;
236 	}
237 
238 	vchi_disconnect(sc->vchi_instance);
239 }
240 
241 static void
242 bcm2835_audio_reset_channel(struct bcm2835_audio_chinfo *ch)
243 {
244 	ch->free_buffer = VCHIQ_AUDIO_BUFFER_SIZE;
245 	ch->playback_state = 0;
246 	ch->buffered_ptr = 0;
247 	ch->complete_pos = 0;
248 	ch->prebuffered = 0;
249 
250 	sndbuf_reset(ch->buffer);
251 }
252 
253 static void
254 bcm2835_audio_start(struct bcm2835_audio_chinfo *ch)
255 {
256 	VC_AUDIO_MSG_T m;
257 	int ret;
258 	struct bcm2835_audio_info *sc = ch->parent;
259 
260 	VCHIQ_VCHI_LOCK(sc);
261 	if (sc->vchi_handle != VCHIQ_SERVICE_HANDLE_INVALID) {
262 		vchi_service_use(sc->vchi_handle);
263 
264 		bcm2835_audio_reset_channel(ch);
265 
266 		m.type = VC_AUDIO_MSG_TYPE_START;
267 		ret = vchi_msg_queue(sc->vchi_handle,
268 		    &m, sizeof m, VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);
269 
270 		if (ret != 0)
271 			printf("%s: vchi_msg_queue failed (err %d)\n", __func__, ret);
272 
273 		vchi_service_release(sc->vchi_handle);
274 	}
275 	VCHIQ_VCHI_UNLOCK(sc);
276 
277 }
278 
279 static void
280 bcm2835_audio_stop(struct bcm2835_audio_chinfo *ch)
281 {
282 	VC_AUDIO_MSG_T m;
283 	int ret;
284 	struct bcm2835_audio_info *sc = ch->parent;
285 
286 	VCHIQ_VCHI_LOCK(sc);
287 	if (sc->vchi_handle != VCHIQ_SERVICE_HANDLE_INVALID) {
288 		vchi_service_use(sc->vchi_handle);
289 
290 		m.type = VC_AUDIO_MSG_TYPE_STOP;
291 		m.u.stop.draining = 0;
292 
293 		ret = vchi_msg_queue(sc->vchi_handle,
294 		    &m, sizeof m, VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);
295 
296 		if (ret != 0)
297 			printf("%s: vchi_msg_queue failed (err %d)\n", __func__, ret);
298 
299 		vchi_service_release(sc->vchi_handle);
300 	}
301 	VCHIQ_VCHI_UNLOCK(sc);
302 }
303 
304 static void
305 bcm2835_audio_open(struct bcm2835_audio_info *sc)
306 {
307 	VC_AUDIO_MSG_T m;
308 	int ret;
309 
310 	VCHIQ_VCHI_LOCK(sc);
311 	if (sc->vchi_handle != VCHIQ_SERVICE_HANDLE_INVALID) {
312 		vchi_service_use(sc->vchi_handle);
313 
314 		m.type = VC_AUDIO_MSG_TYPE_OPEN;
315 		ret = vchi_msg_queue(sc->vchi_handle,
316 		    &m, sizeof m, VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);
317 
318 		if (ret != 0)
319 			printf("%s: vchi_msg_queue failed (err %d)\n", __func__, ret);
320 
321 		vchi_service_release(sc->vchi_handle);
322 	}
323 	VCHIQ_VCHI_UNLOCK(sc);
324 }
325 
326 static void
327 bcm2835_audio_update_controls(struct bcm2835_audio_info *sc)
328 {
329 	VC_AUDIO_MSG_T m;
330 	int ret, db;
331 
332 	VCHIQ_VCHI_LOCK(sc);
333 	if (sc->vchi_handle != VCHIQ_SERVICE_HANDLE_INVALID) {
334 		vchi_service_use(sc->vchi_handle);
335 
336 		m.type = VC_AUDIO_MSG_TYPE_CONTROL;
337 		m.u.control.dest = sc->dest;
338 		if (sc->volume > 99)
339 			sc->volume = 99;
340 		db = db_levels[sc->volume/5];
341 		m.u.control.volume = VCHIQ_AUDIO_VOLUME(db);
342 
343 		ret = vchi_msg_queue(sc->vchi_handle,
344 		    &m, sizeof m, VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);
345 
346 		if (ret != 0)
347 			printf("%s: vchi_msg_queue failed (err %d)\n", __func__, ret);
348 
349 		vchi_service_release(sc->vchi_handle);
350 	}
351 	VCHIQ_VCHI_UNLOCK(sc);
352 }
353 
354 static void
355 bcm2835_audio_update_params(struct bcm2835_audio_info *sc, struct bcm2835_audio_chinfo *ch)
356 {
357 	VC_AUDIO_MSG_T m;
358 	int ret;
359 
360 	VCHIQ_VCHI_LOCK(sc);
361 	if (sc->vchi_handle != VCHIQ_SERVICE_HANDLE_INVALID) {
362 		vchi_service_use(sc->vchi_handle);
363 
364 		m.type = VC_AUDIO_MSG_TYPE_CONFIG;
365 		m.u.config.channels = AFMT_CHANNEL(ch->fmt);
366 		m.u.config.samplerate = ch->spd;
367 		m.u.config.bps = AFMT_BIT(ch->fmt);
368 
369 		ret = vchi_msg_queue(sc->vchi_handle,
370 		    &m, sizeof m, VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);
371 
372 		if (ret != 0)
373 			printf("%s: vchi_msg_queue failed (err %d)\n", __func__, ret);
374 
375 		vchi_service_release(sc->vchi_handle);
376 	}
377 	VCHIQ_VCHI_UNLOCK(sc);
378 }
379 
380 static __inline uint32_t
381 vchiq_unbuffered_bytes(struct bcm2835_audio_chinfo *ch)
382 {
383 	uint32_t size, ready, readyptr, readyend;
384 
385 	size = sndbuf_getsize(ch->buffer);
386 	readyptr = sndbuf_getreadyptr(ch->buffer);
387 	ready = sndbuf_getready(ch->buffer);
388 
389 	readyend = readyptr + ready;
390 	/* Normal case */
391 	if (ch->buffered_ptr >= readyptr) {
392 		if (readyend > ch->buffered_ptr)
393 			return readyend - ch->buffered_ptr;
394 		else
395 			return 0;
396 	}
397 	else { /* buffered_ptr overflow */
398 		if (readyend > ch->buffered_ptr + size)
399 			return readyend - ch->buffered_ptr - size;
400 		else
401 			return 0;
402 	}
403 }
404 
405 static void
406 bcm2835_audio_write_samples(struct bcm2835_audio_chinfo *ch)
407 {
408 	struct bcm2835_audio_info *sc = ch->parent;
409 	VC_AUDIO_MSG_T m;
410 	void *buf;
411 	uint32_t count, size;
412 	int ret;
413 
414 	VCHIQ_VCHI_LOCK(sc);
415 	if (sc->vchi_handle == VCHIQ_SERVICE_HANDLE_INVALID) {
416 		VCHIQ_VCHI_UNLOCK(sc);
417 		return;
418 	}
419 
420 	vchi_service_use(sc->vchi_handle);
421 
422 	size = sndbuf_getsize(ch->buffer);
423 	count = vchiq_unbuffered_bytes(ch);
424 	buf = (uint8_t*)sndbuf_getbuf(ch->buffer) + ch->buffered_ptr;
425 
426 	if (ch->buffered_ptr + count > size)
427 		count = size - ch->buffered_ptr;
428 
429 	if (count < VCHIQ_AUDIO_PACKET_SIZE)
430 		goto done;
431 
432 	count = min(count, ch->free_buffer);
433 	count -= count % VCHIQ_AUDIO_PACKET_SIZE;
434 
435 	m.type = VC_AUDIO_MSG_TYPE_WRITE;
436 	m.u.write.count = count;
437 	m.u.write.max_packet = VCHIQ_AUDIO_PACKET_SIZE;
438 	m.u.write.callback = NULL;
439 	m.u.write.cookie = ch;
440 	if (buf)
441 		m.u.write.silence = 0;
442 	else
443 		m.u.write.silence = 1;
444 
445 	ret = vchi_msg_queue(sc->vchi_handle,
446 	    &m, sizeof m, VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);
447 
448 	if (ret != 0)
449 		printf("%s: vchi_msg_queue failed (err %d)\n", __func__, ret);
450 
451 	if (buf) {
452 		while (count > 0) {
453 			int bytes = MIN((int)m.u.write.max_packet, (int)count);
454 			ch->free_buffer -= bytes;
455 			ch->buffered_ptr += bytes;
456 			ch->buffered_ptr = ch->buffered_ptr % size;
457 			ret = vchi_msg_queue(sc->vchi_handle,
458 			    buf, bytes, VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);
459 			if (ret != 0)
460 				printf("%s: vchi_msg_queue failed: %d\n",
461 				    __func__, ret);
462 			buf = (char *)buf + bytes;
463 			count -= bytes;
464 		}
465 	}
466 done:
467 
468 	vchi_service_release(sc->vchi_handle);
469 	VCHIQ_VCHI_UNLOCK(sc);
470 }
471 
472 static void
473 bcm2835_audio_worker(void *data)
474 {
475 	struct bcm2835_audio_info *sc = (struct bcm2835_audio_info *)data;
476 	struct bcm2835_audio_chinfo *ch = &sc->pch;
477 	mtx_lock(&sc->data_lock);
478 	while(1) {
479 
480 		if (sc->unloading)
481 			break;
482 
483 		if (ch->playback_state == PLAYBACK_IDLE) {
484 			cv_wait_sig(&sc->data_cv, &sc->data_lock);
485 			continue;
486 		}
487 
488 		if (ch->playback_state == PLAYBACK_STOPPING) {
489 			bcm2835_audio_reset_channel(&sc->pch);
490 			ch->playback_state = PLAYBACK_IDLE;
491 			continue;
492 		}
493 
494 		if (ch->free_buffer < vchiq_unbuffered_bytes(ch)) {
495 			cv_timedwait_sig(&sc->data_cv, &sc->data_lock, 10);
496 			continue;
497 		}
498 
499 
500 		bcm2835_audio_write_samples(ch);
501 
502 		if (ch->playback_state == PLAYBACK_STARTING) {
503 			ch->prebuffered++;
504 			if (ch->prebuffered == VCHIQ_AUDIO_PREBUFFER) {
505 				bcm2835_audio_start(ch);
506 				ch->playback_state = PLAYBACK_PLAYING;
507 			}
508 		}
509 	}
510 	mtx_unlock(&sc->data_lock);
511 
512 	kproc_exit(0);
513 }
514 
515 static void
516 bcm2835_audio_create_worker(struct bcm2835_audio_info *sc)
517 {
518 	struct proc *newp;
519 
520 	if (kproc_create(bcm2835_audio_worker, (void*)sc, &newp, 0, 0,
521 	    "bcm2835_audio_worker") != 0) {
522 		printf("failed to create bcm2835_audio_worker\n");
523 	}
524 }
525 
526 /* -------------------------------------------------------------------- */
527 /* channel interface for VCHI audio */
528 static void *
529 bcmchan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir)
530 {
531 	struct bcm2835_audio_info *sc = devinfo;
532 	struct bcm2835_audio_chinfo *ch = &sc->pch;
533 	void *buffer;
534 
535 	if (dir == PCMDIR_REC)
536 		return NULL;
537 
538 	ch->parent = sc;
539 	ch->channel = c;
540 	ch->buffer = b;
541 
542 	/* default values */
543 	ch->spd = 44100;
544 	ch->fmt = SND_FORMAT(AFMT_S16_LE, 2, 0);
545 	ch->blksz = VCHIQ_AUDIO_PACKET_SIZE;
546 
547 	buffer = malloc(sc->bufsz, M_DEVBUF, M_WAITOK | M_ZERO);
548 
549 	if (sndbuf_setup(ch->buffer, buffer, sc->bufsz) != 0) {
550 		free(buffer, M_DEVBUF);
551 		return NULL;
552 	}
553 
554 	bcm2835_audio_update_params(sc, ch);
555 
556 	return ch;
557 }
558 
559 static int
560 bcmchan_free(kobj_t obj, void *data)
561 {
562 	struct bcm2835_audio_chinfo *ch = data;
563 	void *buffer;
564 
565 	buffer = sndbuf_getbuf(ch->buffer);
566 	if (buffer)
567 		free(buffer, M_DEVBUF);
568 
569 	return (0);
570 }
571 
572 static int
573 bcmchan_setformat(kobj_t obj, void *data, uint32_t format)
574 {
575 	struct bcm2835_audio_chinfo *ch = data;
576 	struct bcm2835_audio_info *sc = ch->parent;
577 
578 	bcm2835_audio_lock(sc);
579 
580 	ch->fmt = format;
581 	bcm2835_audio_update_params(sc, ch);
582 
583 	bcm2835_audio_unlock(sc);
584 
585 	return 0;
586 }
587 
588 static uint32_t
589 bcmchan_setspeed(kobj_t obj, void *data, uint32_t speed)
590 {
591 	struct bcm2835_audio_chinfo *ch = data;
592 	struct bcm2835_audio_info *sc = ch->parent;
593 
594 	bcm2835_audio_lock(sc);
595 
596 	ch->spd = speed;
597 	bcm2835_audio_update_params(sc, ch);
598 
599 	bcm2835_audio_unlock(sc);
600 
601 	return ch->spd;
602 }
603 
604 static uint32_t
605 bcmchan_setblocksize(kobj_t obj, void *data, uint32_t blocksize)
606 {
607 	struct bcm2835_audio_chinfo *ch = data;
608 
609 	return ch->blksz;
610 }
611 
612 static int
613 bcmchan_trigger(kobj_t obj, void *data, int go)
614 {
615 	struct bcm2835_audio_chinfo *ch = data;
616 	struct bcm2835_audio_info *sc = ch->parent;
617 
618 	if (!PCMTRIG_COMMON(go))
619 		return (0);
620 
621 	bcm2835_audio_lock(sc);
622 
623 	switch (go) {
624 	case PCMTRIG_START:
625 		ch->playback_state = PLAYBACK_STARTING;
626 		/* wakeup worker thread */
627 		cv_signal(&sc->data_cv);
628 		break;
629 
630 	case PCMTRIG_STOP:
631 	case PCMTRIG_ABORT:
632 		ch->playback_state = PLAYBACK_STOPPING;
633 		bcm2835_audio_stop(ch);
634 		break;
635 
636 	default:
637 		break;
638 	}
639 
640 	bcm2835_audio_unlock(sc);
641 	return 0;
642 }
643 
644 static uint32_t
645 bcmchan_getptr(kobj_t obj, void *data)
646 {
647 	struct bcm2835_audio_chinfo *ch = data;
648 	struct bcm2835_audio_info *sc = ch->parent;
649 	uint32_t ret;
650 
651 	bcm2835_audio_lock(sc);
652 
653 	ret = ch->complete_pos - (ch->complete_pos % VCHIQ_AUDIO_PACKET_SIZE);
654 
655 	bcm2835_audio_unlock(sc);
656 
657 	return ret;
658 }
659 
660 static struct pcmchan_caps *
661 bcmchan_getcaps(kobj_t obj, void *data)
662 {
663 
664 	return &bcm2835_audio_playcaps;
665 }
666 
667 static kobj_method_t bcmchan_methods[] = {
668     	KOBJMETHOD(channel_init,		bcmchan_init),
669     	KOBJMETHOD(channel_free,		bcmchan_free),
670     	KOBJMETHOD(channel_setformat,		bcmchan_setformat),
671     	KOBJMETHOD(channel_setspeed,		bcmchan_setspeed),
672     	KOBJMETHOD(channel_setblocksize,	bcmchan_setblocksize),
673     	KOBJMETHOD(channel_trigger,		bcmchan_trigger),
674     	KOBJMETHOD(channel_getptr,		bcmchan_getptr),
675     	KOBJMETHOD(channel_getcaps,		bcmchan_getcaps),
676 	KOBJMETHOD_END
677 };
678 CHANNEL_DECLARE(bcmchan);
679 
680 /************************************************************/
681 
682 static int
683 bcmmix_init(struct snd_mixer *m)
684 {
685 
686 	mix_setdevs(m, SOUND_MASK_VOLUME);
687 
688 	return (0);
689 }
690 
691 static int
692 bcmmix_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right)
693 {
694     	struct bcm2835_audio_info *sc = mix_getdevinfo(m);
695 
696 	switch (dev) {
697 	case SOUND_MIXER_VOLUME:
698 		sc->volume = left;
699 		bcm2835_audio_update_controls(sc);
700 		break;
701 
702 	default:
703 		break;
704 	}
705 
706     	return left | (left << 8);
707 }
708 
709 static kobj_method_t bcmmixer_methods[] = {
710     	KOBJMETHOD(mixer_init,		bcmmix_init),
711     	KOBJMETHOD(mixer_set,		bcmmix_set),
712 	KOBJMETHOD_END
713 };
714 
715 MIXER_DECLARE(bcmmixer);
716 
717 static int
718 sysctl_bcm2835_audio_dest(SYSCTL_HANDLER_ARGS)
719 {
720 	struct bcm2835_audio_info *sc = arg1;
721 	int val;
722 	int err;
723 
724 	val = sc->dest;
725 	err = sysctl_handle_int(oidp, &val, 0, req);
726 	if (err || !req->newptr) /* error || read request */
727 		return (err);
728 
729 	if ((val < 0) || (val > 2))
730 		return (EINVAL);
731 
732 	sc->dest = val;
733 	device_printf(sc->dev, "destination set to %s\n", dest_description(val));
734 	bcm2835_audio_update_controls(sc);
735 
736 	return (0);
737 }
738 
739 static void
740 vchi_audio_sysctl_init(struct bcm2835_audio_info *sc)
741 {
742 	struct sysctl_ctx_list *ctx;
743 	struct sysctl_oid *tree_node;
744 	struct sysctl_oid_list *tree;
745 
746 	/*
747 	 * Add system sysctl tree/handlers.
748 	 */
749 	ctx = device_get_sysctl_ctx(sc->dev);
750 	tree_node = device_get_sysctl_tree(sc->dev);
751 	tree = SYSCTL_CHILDREN(tree_node);
752 	SYSCTL_ADD_PROC(ctx, tree, OID_AUTO, "dest",
753 	    CTLFLAG_RW | CTLTYPE_UINT, sc, sizeof(*sc),
754 	    sysctl_bcm2835_audio_dest, "IU", "audio destination, "
755 	    "0 - auto, 1 - headphones, 2 - HDMI");
756 }
757 
758 static void
759 bcm2835_audio_identify(driver_t *driver, device_t parent)
760 {
761 
762 	BUS_ADD_CHILD(parent, 0, "pcm", 0);
763 }
764 
765 static int
766 bcm2835_audio_probe(device_t dev)
767 {
768 
769 	device_set_desc(dev, "VCHIQ audio");
770 	return (BUS_PROBE_DEFAULT);
771 }
772 
773 
774 static void
775 bcm2835_audio_delayed_init(void *xsc)
776 {
777     	struct bcm2835_audio_info *sc;
778     	char status[SND_STATUSLEN];
779 
780 	sc = xsc;
781 
782 	config_intrhook_disestablish(&sc->intr_hook);
783 
784 	bcm2835_audio_init(sc);
785 	bcm2835_audio_open(sc);
786 	sc->volume = 75;
787 	sc->dest = DEST_AUTO;
788 
789     	if (mixer_init(sc->dev, &bcmmixer_class, sc)) {
790 		device_printf(sc->dev, "mixer_init failed\n");
791 		goto no;
792 	}
793 
794     	if (pcm_register(sc->dev, sc, 1, 1)) {
795 		device_printf(sc->dev, "pcm_register failed\n");
796 		goto no;
797 	}
798 
799 	pcm_addchan(sc->dev, PCMDIR_PLAY, &bcmchan_class, sc);
800     	snprintf(status, SND_STATUSLEN, "at VCHIQ");
801 	pcm_setstatus(sc->dev, status);
802 
803 	bcm2835_audio_reset_channel(&sc->pch);
804 	bcm2835_audio_create_worker(sc);
805 
806 	vchi_audio_sysctl_init(sc);
807 
808 no:
809 	;
810 }
811 
812 static int
813 bcm2835_audio_attach(device_t dev)
814 {
815     	struct bcm2835_audio_info *sc;
816 
817 	sc = malloc(sizeof(*sc), M_DEVBUF, M_WAITOK | M_ZERO);
818 
819 	sc->dev = dev;
820 	sc->bufsz = VCHIQ_AUDIO_BUFFER_SIZE;
821 
822 	sc->lock = snd_mtxcreate(device_get_nameunit(dev), "bcm2835_audio softc");
823 
824 	mtx_init(&sc->vchi_lock, "bcm2835_audio", "vchi_lock", MTX_DEF);
825 	mtx_init(&sc->data_lock, "data_mtx", "data_mtx", MTX_DEF);
826 	cv_init(&sc->data_cv, "data_cv");
827 	sc->vchi_handle = VCHIQ_SERVICE_HANDLE_INVALID;
828 
829 	/*
830 	 * We need interrupts enabled for VCHI to work properly,
831 	 * so delay intialization until it happens
832 	 */
833 	sc->intr_hook.ich_func = bcm2835_audio_delayed_init;
834 	sc->intr_hook.ich_arg = sc;
835 
836 	if (config_intrhook_establish(&sc->intr_hook) != 0)
837 		goto no;
838 
839     	return 0;
840 
841 no:
842     	return ENXIO;
843 }
844 
845 static int
846 bcm2835_audio_detach(device_t dev)
847 {
848 	int r;
849 	struct bcm2835_audio_info *sc;
850 	sc = pcm_getdevinfo(dev);
851 
852 	/* Stop worker thread */
853 	sc->unloading = 1;
854 	cv_signal(&sc->data_cv);
855 
856 	r = pcm_unregister(dev);
857 	if (r)
858 		return r;
859 
860 	mtx_destroy(&sc->vchi_lock);
861 	mtx_destroy(&sc->data_lock);
862 	cv_destroy(&sc->data_cv);
863 
864 	bcm2835_audio_release(sc);
865 
866 	if (sc->lock) {
867 		snd_mtxfree(sc->lock);
868 		sc->lock = NULL;
869 	}
870 
871     	free(sc, M_DEVBUF);
872 
873 	return 0;
874 }
875 
876 static device_method_t bcm2835_audio_methods[] = {
877 	/* Device interface */
878 	DEVMETHOD(device_identify,	bcm2835_audio_identify),
879 	DEVMETHOD(device_probe,		bcm2835_audio_probe),
880 	DEVMETHOD(device_attach,	bcm2835_audio_attach),
881 	DEVMETHOD(device_detach,	bcm2835_audio_detach),
882 
883 	{ 0, 0 }
884 };
885 
886 static driver_t bcm2835_audio_driver = {
887 	"pcm",
888 	bcm2835_audio_methods,
889 	PCM_SOFTC_SIZE,
890 };
891 
892 DRIVER_MODULE(bcm2835_audio, vchiq, bcm2835_audio_driver, pcm_devclass, 0, 0);
893 MODULE_DEPEND(bcm2835_audio, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER);
894 MODULE_DEPEND(bcm2835_audio, vchiq, 1, 1, 1);
895 MODULE_VERSION(bcm2835_audio, 1);
896