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