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