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