xref: /freebsd/sys/arm/broadcom/bcm2835/bcm2835_audio.c (revision 97e24b41d2d224cfb4043f1ae84fc23d9033d0a1)
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 	struct bcm_log_vars {
117 		unsigned int bsize ;
118 		int slept_for_lack_of_space ;
119 	} log_vars;
120 #define DEFAULT_LOG_VALUES \
121 	((struct bcm_log_vars) { .bsize = 0 , .slept_for_lack_of_space = 0 })
122 };
123 
124 struct bcm2835_audio_info {
125 	device_t dev;
126 	unsigned int bufsz;
127     	struct bcm2835_audio_chinfo pch;
128 	uint32_t dest, volume;
129 	struct intr_config_hook intr_hook;
130 
131 	/* VCHI data */
132 	VCHI_INSTANCE_T vchi_instance;
133 	VCHI_CONNECTION_T *vchi_connection;
134 	VCHI_SERVICE_HANDLE_T vchi_handle;
135 
136 	struct mtx lock;
137 	struct cv worker_cv;
138 
139 	uint32_t flags_pending;
140 
141 	int verbose_trace;
142 	/* Worker thread state */
143 	int worker_state;
144 };
145 
146 #define BCM2835_AUDIO_LOCK(sc)		mtx_lock(&(sc)->lock)
147 #define BCM2835_AUDIO_LOCKED(sc)	mtx_assert(&(sc)->lock, MA_OWNED)
148 #define BCM2835_AUDIO_UNLOCK(sc)	mtx_unlock(&(sc)->lock)
149 
150 #define BCM2835_LOG_ERROR(sc,...)				\
151 	do {							\
152 		device_printf((sc)->dev, __VA_ARGS__);		\
153 	} while(0)
154 
155 #define BCM2835_LOG_INFO(sc,...)				\
156 	do {							\
157 		if (sc->verbose_trace > 0)			\
158 			device_printf((sc)->dev, __VA_ARGS__);	\
159 	} while(0)
160 
161 #define BCM2835_LOG_WARN(sc,...) \
162 	do {							\
163 		if (sc->verbose_trace > 1)			\
164 			device_printf((sc)->dev, __VA_ARGS__);	\
165 	} while(0)
166 
167 #define BCM2835_LOG_TRACE(sc,...)				\
168 	do {							\
169 		if(sc->verbose_trace > 2)			\
170 			device_printf((sc)->dev, __VA_ARGS__);	\
171 	} while(0)
172 
173 /* Useful for circular buffer calcs */
174 #define MOD_DIFF(front,rear,mod) (((mod) + (front) - (rear)) % (mod))
175 
176 static ssize_t
bcm2835_memcpy_wrapper(void * _src,void * _dst,size_t offset,size_t size)177 bcm2835_memcpy_wrapper(void *_src, void *_dst, size_t offset, size_t size)
178 {
179 	uint8_t *src = _src;
180 	uint8_t *dst = _dst;
181 
182 	memcpy(dst + offset, src + offset, size);
183 
184 	return (size);
185 }
186 
187 static const char *
dest_description(uint32_t dest)188 dest_description(uint32_t dest)
189 {
190 	switch (dest) {
191 		case DEST_AUTO:
192 			return "AUTO";
193 			break;
194 
195 		case DEST_HEADPHONES:
196 			return "HEADPHONES";
197 			break;
198 
199 		case DEST_HDMI:
200 			return "HDMI";
201 			break;
202 		default:
203 			return "UNKNOWN";
204 			break;
205 	}
206 }
207 
208 static void
bcm2835_worker_update_params(struct bcm2835_audio_info * sc)209 bcm2835_worker_update_params(struct bcm2835_audio_info *sc)
210 {
211 
212 	BCM2835_AUDIO_LOCKED(sc);
213 
214 	sc->flags_pending |= AUDIO_PARAMS;
215 	cv_signal(&sc->worker_cv);
216 }
217 
218 static void
bcm2835_worker_play_start(struct bcm2835_audio_info * sc)219 bcm2835_worker_play_start(struct bcm2835_audio_info *sc)
220 {
221 	BCM2835_AUDIO_LOCK(sc);
222 	sc->flags_pending &= ~(AUDIO_STOP);
223 	sc->flags_pending |= AUDIO_PLAY;
224 	cv_signal(&sc->worker_cv);
225 	BCM2835_AUDIO_UNLOCK(sc);
226 }
227 
228 static void
bcm2835_worker_play_stop(struct bcm2835_audio_info * sc)229 bcm2835_worker_play_stop(struct bcm2835_audio_info *sc)
230 {
231 	BCM2835_AUDIO_LOCK(sc);
232 	sc->flags_pending &= ~(AUDIO_PLAY);
233 	sc->flags_pending |= AUDIO_STOP;
234 	cv_signal(&sc->worker_cv);
235 	BCM2835_AUDIO_UNLOCK(sc);
236 }
237 
238 static void
bcm2835_audio_callback(void * param,const VCHI_CALLBACK_REASON_T reason,void * msg_handle)239 bcm2835_audio_callback(void *param, const VCHI_CALLBACK_REASON_T reason, void *msg_handle)
240 {
241 	struct bcm2835_audio_info *sc = (struct bcm2835_audio_info *)param;
242 	int32_t status;
243 	uint32_t msg_len;
244 	VC_AUDIO_MSG_T m;
245 
246 	if (reason != VCHI_CALLBACK_MSG_AVAILABLE)
247 		return;
248 
249 	status = vchi_msg_dequeue(sc->vchi_handle,
250 	    &m, sizeof m, &msg_len, VCHI_FLAGS_NONE);
251 	if (status != 0)
252 		return;
253 	if (m.type == VC_AUDIO_MSG_TYPE_RESULT) {
254 		if (m.u.result.success) {
255 			device_printf(sc->dev,
256 			    "msg type %08x failed\n",
257 			    m.type);
258 		}
259 	} else if (m.type == VC_AUDIO_MSG_TYPE_COMPLETE) {
260 		unsigned int signaled = 0;
261 		struct bcm2835_audio_chinfo *ch ;
262 #if defined(__aarch64__)
263 		ch = (void *) ((((size_t)m.u.complete.callback) << 32)
264 		    | ((size_t)m.u.complete.cookie));
265 #else
266 		ch = (void *) (m.u.complete.cookie);
267 #endif
268 
269 		int count = m.u.complete.count & 0xffff;
270 		int perr = (m.u.complete.count & (1U << 30)) != 0;
271 
272 		BCM2835_LOG_TRACE(sc, "in:: count:0x%x perr:%d\n",
273 		    m.u.complete.count, perr);
274 
275 		ch->callbacks++;
276 		if (perr)
277 			ch->underruns++;
278 
279 		BCM2835_AUDIO_LOCK(sc);
280 		if (ch->playback_state != PLAYBACK_IDLE) {
281 			/* Prevent LOR */
282 			BCM2835_AUDIO_UNLOCK(sc);
283 			chn_intr(sc->pch.channel);
284 			BCM2835_AUDIO_LOCK(sc);
285 		}
286 		/* We should check again, state might have changed */
287 		if (ch->playback_state != PLAYBACK_IDLE) {
288 			if (!perr) {
289 				if ((ch->available_space + count)> VCHIQ_AUDIO_BUFFER_SIZE) {
290 					device_printf(sc->dev, "inconsistent data in callback:\n");
291 					device_printf(sc->dev, "available_space == %d, count = %d, perr=%d\n",
292 					    ch->available_space, count, perr);
293 					device_printf(sc->dev,
294 					    "retrieved_samples = %ju, submitted_samples = %ju\n",
295 					    (uintmax_t)ch->retrieved_samples,
296 					    (uintmax_t)ch->submitted_samples);
297 				}
298 			}
299 			ch->available_space += count;
300 			ch->retrieved_samples += count;
301 			/*
302 			 *  XXXMDC
303 			 *  Experimental: if VC says it's empty, believe it
304 			 *  Has to come after the usual adjustments
305 			 */
306 			if(perr){
307 				ch->available_space = VCHIQ_AUDIO_BUFFER_SIZE;
308 				perr = ch->retrieved_samples; // shd be != 0
309 			}
310 
311 			if ((ch->available_space >= 1*VCHIQ_AUDIO_PACKET_SIZE)){
312 					cv_signal(&sc->worker_cv);
313 				signaled = 1;
314 			}
315 		}
316 		BCM2835_AUDIO_UNLOCK(sc);
317 		if(perr){
318 			BCM2835_LOG_WARN(sc,
319 			    "VC starved; reported %u for a total of %u\n"
320 			    "worker %s\n", count, perr,
321 			    (signaled ? "signaled": "not signaled"));
322 		}
323 	} else
324 		BCM2835_LOG_WARN(sc, "%s: unknown m.type: %d\n", __func__,
325 		    m.type);
326 }
327 
328 /* VCHIQ stuff */
329 static void
bcm2835_audio_init(struct bcm2835_audio_info * sc)330 bcm2835_audio_init(struct bcm2835_audio_info *sc)
331 {
332 	int status;
333 
334 	/* Initialize and create a VCHI connection */
335 	status = vchi_initialise(&sc->vchi_instance);
336 	if (status != 0) {
337 		BCM2835_LOG_ERROR(sc, "vchi_initialise failed: %d\n", status);
338 		return;
339 	}
340 
341 	status = vchi_connect(NULL, 0, sc->vchi_instance);
342 	if (status != 0) {
343 		BCM2835_LOG_ERROR(sc, "vchi_connect failed: %d\n", status);
344 		return;
345 	}
346 
347 	SERVICE_CREATION_T params = {
348 	    VCHI_VERSION_EX(VC_AUDIOSERV_VER, VC_AUDIOSERV_MIN_VER),
349 	    VC_AUDIO_SERVER_NAME,   /* 4cc service code */
350 	    sc->vchi_connection,    /* passed in fn pointers */
351 	    0,  /* rx fifo size */
352 	    0,  /* tx fifo size */
353 	    bcm2835_audio_callback,    /* service callback */
354 	    sc,   /* service callback parameter */
355 	    1,
356 	    1,
357 	    0   /* want crc check on bulk transfers */
358 	};
359 
360 	status = vchi_service_open(sc->vchi_instance, &params,
361 	    &sc->vchi_handle);
362 
363 	if (status != 0)
364 		sc->vchi_handle = VCHIQ_SERVICE_HANDLE_INVALID;
365 }
366 
367 static void
bcm2835_audio_release(struct bcm2835_audio_info * sc)368 bcm2835_audio_release(struct bcm2835_audio_info *sc)
369 {
370 	int success;
371 
372 	if (sc->vchi_handle != VCHIQ_SERVICE_HANDLE_INVALID) {
373 		/* XXX vchi_service_release(sc->vchi_handle)? */
374 		success = vchi_service_close(sc->vchi_handle);
375 		if (success != 0)
376 			BCM2835_LOG_ERROR(sc, "vchi_service_close failed: %d\n",
377 			    success);
378 		sc->vchi_handle = VCHIQ_SERVICE_HANDLE_INVALID;
379 	}
380 
381 	vchi_disconnect(sc->vchi_instance);
382 }
383 
384 static void
bcm2835_audio_reset_channel(struct bcm2835_audio_chinfo * ch)385 bcm2835_audio_reset_channel(struct bcm2835_audio_chinfo *ch)
386 {
387 
388 	ch->available_space = VCHIQ_AUDIO_BUFFER_SIZE;
389 	ch->unsubmittedptr = 0;
390 	sndbuf_reset(ch->buffer);
391 }
392 
393 static void
bcm2835_audio_start(struct bcm2835_audio_chinfo * ch)394 bcm2835_audio_start(struct bcm2835_audio_chinfo *ch)
395 {
396 	VC_AUDIO_MSG_T m;
397 	int ret;
398 	struct bcm2835_audio_info *sc = ch->parent;
399 
400 	if (sc->vchi_handle != VCHIQ_SERVICE_HANDLE_INVALID) {
401 		m.type = VC_AUDIO_MSG_TYPE_START;
402 		ret = vchi_msg_queue(sc->vchi_handle, bcm2835_memcpy_wrapper,
403 		    &m, sizeof m);
404 
405 		if (ret != 0)
406 			BCM2835_LOG_ERROR(sc,
407 			    "%s: vchi_msg_queue failed (err %d)\n", __func__,
408 			    ret);
409 	}
410 }
411 
412 static void
bcm2835_audio_stop(struct bcm2835_audio_chinfo * ch)413 bcm2835_audio_stop(struct bcm2835_audio_chinfo *ch)
414 {
415 	VC_AUDIO_MSG_T m;
416 	int ret;
417 	struct bcm2835_audio_info *sc = ch->parent;
418 
419 	if (sc->vchi_handle != VCHIQ_SERVICE_HANDLE_INVALID) {
420 		m.type = VC_AUDIO_MSG_TYPE_STOP;
421 		m.u.stop.draining = 0;
422 
423 		BCM2835_LOG_INFO(sc,"sending stop\n");
424 		ret = vchi_msg_queue(sc->vchi_handle, bcm2835_memcpy_wrapper,
425 		    &m, sizeof m);
426 
427 		if (ret != 0)
428 			BCM2835_LOG_ERROR(sc,
429 			    "%s: vchi_msg_queue failed (err %d)\n", __func__,
430 			    ret);
431 	}
432 }
433 
434 static void
bcm2835_audio_open(struct bcm2835_audio_info * sc)435 bcm2835_audio_open(struct bcm2835_audio_info *sc)
436 {
437 	VC_AUDIO_MSG_T m;
438 	int ret;
439 
440 	if (sc->vchi_handle != VCHIQ_SERVICE_HANDLE_INVALID) {
441 		m.type = VC_AUDIO_MSG_TYPE_OPEN;
442 		ret = vchi_msg_queue(sc->vchi_handle, bcm2835_memcpy_wrapper,
443 		    &m, sizeof m);
444 
445 		if (ret != 0)
446 			BCM2835_LOG_ERROR(sc,
447 			    "%s: vchi_msg_queue failed (err %d)\n", __func__,
448 			    ret);
449 	}
450 }
451 
452 static void
bcm2835_audio_update_controls(struct bcm2835_audio_info * sc,uint32_t volume,uint32_t dest)453 bcm2835_audio_update_controls(struct bcm2835_audio_info *sc, uint32_t volume, uint32_t dest)
454 {
455 	VC_AUDIO_MSG_T m;
456 	int ret, db;
457 
458 	if (sc->vchi_handle != VCHIQ_SERVICE_HANDLE_INVALID) {
459 		m.type = VC_AUDIO_MSG_TYPE_CONTROL;
460 		m.u.control.dest = dest;
461 		if (volume > 99)
462 			volume = 99;
463 		db = db_levels[volume/5];
464 		m.u.control.volume = VCHIQ_AUDIO_VOLUME(db);
465 
466 		ret = vchi_msg_queue(sc->vchi_handle, bcm2835_memcpy_wrapper,
467 		    &m, sizeof m);
468 
469 		if (ret != 0)
470 			BCM2835_LOG_ERROR(sc,
471 			    "%s: vchi_msg_queue failed (err %d)\n", __func__,
472 			    ret);
473 	}
474 }
475 
476 static void
bcm2835_audio_update_params(struct bcm2835_audio_info * sc,uint32_t fmt,uint32_t speed)477 bcm2835_audio_update_params(struct bcm2835_audio_info *sc, uint32_t fmt, uint32_t speed)
478 {
479 	VC_AUDIO_MSG_T m;
480 	int ret;
481 
482 	if (sc->vchi_handle != VCHIQ_SERVICE_HANDLE_INVALID) {
483 		m.type = VC_AUDIO_MSG_TYPE_CONFIG;
484 		m.u.config.channels = AFMT_CHANNEL(fmt);
485 		m.u.config.samplerate = speed;
486 		m.u.config.bps = AFMT_BIT(fmt);
487 
488 		ret = vchi_msg_queue(sc->vchi_handle, bcm2835_memcpy_wrapper,
489 		    &m, sizeof m);
490 
491 		if (ret != 0)
492 			BCM2835_LOG_ERROR(sc,
493 			    "%s: vchi_msg_queue failed (err %d)\n", __func__,
494 			    ret);
495 	}
496 }
497 
498 static bool
bcm2835_audio_buffer_should_sleep(struct bcm2835_audio_chinfo * ch)499 bcm2835_audio_buffer_should_sleep(struct bcm2835_audio_chinfo *ch)
500 {
501 
502 	ch->log_vars.slept_for_lack_of_space = 0;
503 	if (ch->playback_state != PLAYBACK_PLAYING)
504 		return (true);
505 
506 	/* Not enough data */
507 	/* XXXMDC Take unsubmitted stuff into account */
508 	if (sndbuf_getready(ch->buffer)
509 			- MOD_DIFF(
510 				ch->unsubmittedptr,
511 				sndbuf_getreadyptr(ch->buffer),
512 				ch->buffer->bufsize
513 			) < VCHIQ_AUDIO_PACKET_SIZE) {
514 		ch->starved++;
515 		return (true);
516 	}
517 
518 	/* Not enough free space */
519 	if (ch->available_space < VCHIQ_AUDIO_PACKET_SIZE) {
520 		ch->log_vars.slept_for_lack_of_space = 1;
521 		return (true);
522 	}
523 
524 	return (false);
525 }
526 
527 static void
bcm2835_audio_write_samples(struct bcm2835_audio_chinfo * ch,void * buf,uint32_t count)528 bcm2835_audio_write_samples(struct bcm2835_audio_chinfo *ch, void *buf, uint32_t count)
529 {
530 	struct bcm2835_audio_info *sc = ch->parent;
531 	VC_AUDIO_MSG_T m;
532 	int ret;
533 
534 	if (sc->vchi_handle == VCHIQ_SERVICE_HANDLE_INVALID) {
535 		return;
536 	}
537 
538 	m.type = VC_AUDIO_MSG_TYPE_WRITE;
539 	m.u.write.count = count;
540 	m.u.write.max_packet = VCHIQ_AUDIO_PACKET_SIZE;
541 #if defined(__aarch64__)
542 	m.u.write.callback = (uint32_t)(((size_t) ch) >> 32) & 0xffffffff;
543 	m.u.write.cookie = (uint32_t)(((size_t) ch) & 0xffffffff);
544 #else
545 	m.u.write.callback = (uint32_t) NULL;
546 	m.u.write.cookie = (uint32_t) ch;
547 #endif
548 	m.u.write.silence = 0;
549 
550 	ret = vchi_msg_queue(sc->vchi_handle, bcm2835_memcpy_wrapper,
551 	    &m, sizeof m);
552 
553 	if (ret != 0)
554 		BCM2835_LOG_ERROR(sc, "%s: vchi_msg_queue failed (err %d)\n",
555 		    __func__, ret);
556 
557 	while (count > 0) {
558 		int bytes = MIN((int)m.u.write.max_packet, (int)count);
559 		ret = vchi_msg_queue(sc->vchi_handle, bcm2835_memcpy_wrapper,
560 		    buf, bytes);
561 		if (ret != 0)
562 			BCM2835_LOG_ERROR(sc, "%s: vchi_msg_queue failed: %d\n",
563 			    __func__, ret);
564 		buf = (char *)buf + bytes;
565 		count -= bytes;
566 	}
567 }
568 
569 static void
bcm2835_audio_worker(void * data)570 bcm2835_audio_worker(void *data)
571 {
572 	struct bcm2835_audio_info *sc = (struct bcm2835_audio_info *)data;
573 	struct bcm2835_audio_chinfo *ch = &sc->pch;
574 	uint32_t speed, format;
575 	uint32_t volume, dest;
576 	uint32_t flags;
577 	uint32_t count, size, readyptr;
578 	uint8_t *buf;
579 
580 	ch->playback_state = PLAYBACK_IDLE;
581 
582 	while (1) {
583 		if (sc->worker_state != WORKER_RUNNING)
584 			break;
585 
586 		BCM2835_AUDIO_LOCK(sc);
587 		/*
588 		 * wait until there are flags set or buffer is ready
589 		 * to consume more samples
590 		 */
591 		while ((sc->flags_pending == 0) &&
592 		    bcm2835_audio_buffer_should_sleep(ch)) {
593 			cv_wait_sig(&sc->worker_cv, &sc->lock);
594 			if ((sc->flags_pending == 0) &&
595 			    (ch->log_vars.slept_for_lack_of_space)) {
596 				BCM2835_LOG_TRACE(sc,
597 				    "slept for lack of space\n");
598 			}
599 		}
600 		flags = sc->flags_pending;
601 		/* Clear pending flags */
602 		sc->flags_pending = 0;
603 		BCM2835_AUDIO_UNLOCK(sc);
604 
605 		/* Requested to change parameters */
606 		if (flags & AUDIO_PARAMS) {
607 			BCM2835_AUDIO_LOCK(sc);
608 			speed = ch->spd;
609 			format = ch->fmt;
610 			volume = sc->volume;
611 			dest = sc->dest;
612 			BCM2835_AUDIO_UNLOCK(sc);
613 			if (ch->playback_state == PLAYBACK_IDLE)
614 				bcm2835_audio_update_params(sc, format, speed);
615 			bcm2835_audio_update_controls(sc, volume, dest);
616 		}
617 
618 		/* Requested to stop playback */
619 		if ((flags & AUDIO_STOP) &&
620 		    (ch->playback_state == PLAYBACK_PLAYING)) {
621 			bcm2835_audio_stop(ch);
622 			BCM2835_AUDIO_LOCK(sc);
623 			bcm2835_audio_reset_channel(&sc->pch);
624 			ch->playback_state = PLAYBACK_IDLE;
625 			long sub_total = ch->submitted_samples;
626 			long retd = ch->retrieved_samples;
627 			BCM2835_AUDIO_UNLOCK(sc);
628 			BCM2835_LOG_INFO(sc,
629 			    "stopped audio. submitted a total of %lu "
630 			    "having been acked %lu\n", sub_total, retd);
631 			continue;
632 		}
633 
634 		/* Requested to start playback */
635 		if ((flags & AUDIO_PLAY) &&
636 		    (ch->playback_state == PLAYBACK_IDLE)) {
637 			BCM2835_LOG_INFO(sc, "starting audio\n");
638 			unsigned int bsize = ch->buffer->bufsize;
639 			BCM2835_AUDIO_LOCK(sc);
640 			ch->playback_state = PLAYBACK_PLAYING;
641 			ch->log_vars.bsize = bsize;
642 			BCM2835_AUDIO_UNLOCK(sc);
643 			BCM2835_LOG_INFO(sc, "buffer size is %u\n", bsize);
644 			bcm2835_audio_start(ch);
645 		}
646 
647 		if (ch->playback_state == PLAYBACK_IDLE)
648 			continue;
649 
650 		if (sndbuf_getready(ch->buffer) == 0)
651 			continue;
652 
653 		uint32_t i_count;
654 
655 		/* XXXMDC Take unsubmitted stuff into account */
656 		count = i_count = sndbuf_getready(ch->buffer)
657 		    - MOD_DIFF(ch->unsubmittedptr,
658 		     sndbuf_getreadyptr(ch->buffer),
659 		     ch->buffer->bufsize);
660 		size = ch->buffer->bufsize;
661 		readyptr = ch->unsubmittedptr;
662 
663 		int size_changed = 0;
664 		unsigned int available;
665 
666 		BCM2835_AUDIO_LOCK(sc);
667 		if (size != ch->log_vars.bsize) {
668 			ch->log_vars.bsize = size;
669 			size_changed = 1;
670 		}
671 		available = ch->available_space;
672 		/*
673 		 *  XXXMDC
674 		 *
675 		 *  On arm64, got into situations where
676 		 *  readyptr was less than a packet away
677 		 *  from the end of the buffer, which led
678 		 *  to count being set to 0 and, inexorably, starvation.
679 		 *  Code below tries to take that into account.
680 		 *  The problem might have been fixed with some of the
681 		 *  other changes that were made in the meantime,
682 		 *  but for now this works fine.
683 		 */
684 		if (readyptr + count > size) {
685 			count = size - readyptr;
686 		}
687 		if(count > ch->available_space){
688 			count = ch->available_space;
689 			count -= (count % VCHIQ_AUDIO_PACKET_SIZE);
690 		}else if (count > VCHIQ_AUDIO_PACKET_SIZE){
691 			count -= (count % VCHIQ_AUDIO_PACKET_SIZE);
692 		}else if (size > count + readyptr) {
693 			count = 0;
694 		}
695 		BCM2835_AUDIO_UNLOCK(sc);
696 
697 		if (count % VCHIQ_AUDIO_PACKET_SIZE != 0) {
698 			BCM2835_LOG_WARN(sc, "count: %u  initial count: %u  "
699 			    "size: %u  readyptr: %u  available: %u\n", count,
700 			    i_count,size,readyptr,available);
701 		}
702 		if (size_changed)
703 		    BCM2835_LOG_INFO(sc, "bsize changed to %u\n", size);
704 
705 		if (count == 0) {
706 			BCM2835_LOG_WARN(sc,
707 			    "not enough room for a packet: count %d,"
708 			    " i_count %d, rptr %d, size %d\n",
709 			    count, i_count, readyptr, size);
710 			continue;
711 		}
712 
713 		buf = ch->buffer->buf + readyptr;
714 
715 		bcm2835_audio_write_samples(ch, buf, count);
716 		BCM2835_AUDIO_LOCK(sc);
717 		ch->unsubmittedptr = (ch->unsubmittedptr + count) %
718 		    ch->buffer->bufsize;
719 		ch->available_space -= count;
720 		ch->submitted_samples += count;
721 		long sub = count;
722 		long sub_total = ch->submitted_samples;
723 		long retd = ch->retrieved_samples;
724 		KASSERT(ch->available_space >= 0, ("ch->available_space == %d\n", ch->available_space));
725 		BCM2835_AUDIO_UNLOCK(sc);
726 
727 		BCM2835_LOG_TRACE(sc,
728 		    "submitted %lu for a total of %lu having been acked %lu; "
729 		    "rptr %d, had %u available\n", sub, sub_total, retd,
730 		    readyptr, available);
731 	}
732 
733 	BCM2835_AUDIO_LOCK(sc);
734 	sc->worker_state = WORKER_STOPPED;
735 	cv_signal(&sc->worker_cv);
736 	BCM2835_AUDIO_UNLOCK(sc);
737 
738 	kproc_exit(0);
739 }
740 
741 static void
bcm2835_audio_create_worker(struct bcm2835_audio_info * sc)742 bcm2835_audio_create_worker(struct bcm2835_audio_info *sc)
743 {
744 	struct proc *newp;
745 
746 	sc->worker_state = WORKER_RUNNING;
747 	if (kproc_create(bcm2835_audio_worker, (void*)sc, &newp, 0, 0,
748 	    "bcm2835_audio_worker") != 0) {
749 		BCM2835_LOG_ERROR(sc,
750 		    "failed to create bcm2835_audio_worker\n");
751 	}
752 }
753 
754 /* -------------------------------------------------------------------- */
755 /* channel interface for VCHI audio */
756 static void *
bcmchan_init(kobj_t obj,void * devinfo,struct snd_dbuf * b,struct pcm_channel * c,int dir)757 bcmchan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir)
758 {
759 	struct bcm2835_audio_info *sc = devinfo;
760 	struct bcm2835_audio_chinfo *ch = &sc->pch;
761 	void *buffer;
762 
763 	if (dir == PCMDIR_REC)
764 		return NULL;
765 
766 	ch->parent = sc;
767 	ch->channel = c;
768 	ch->buffer = b;
769 
770 	/* default values */
771 	ch->spd = 44100;
772 	ch->fmt = SND_FORMAT(AFMT_S16_LE, 2, 0);
773 	ch->blksz = VCHIQ_AUDIO_PACKET_SIZE;
774 
775 	buffer = malloc(sc->bufsz, M_DEVBUF, M_WAITOK | M_ZERO);
776 
777 	if (sndbuf_setup(ch->buffer, buffer, sc->bufsz) != 0) {
778 		device_printf(sc->dev, "sndbuf_setup failed\n");
779 		free(buffer, M_DEVBUF);
780 		return NULL;
781 	}
782 
783 	ch->log_vars = DEFAULT_LOG_VALUES;
784 
785 	BCM2835_AUDIO_LOCK(sc);
786 	bcm2835_worker_update_params(sc);
787 	BCM2835_AUDIO_UNLOCK(sc);
788 
789 	return ch;
790 }
791 
792 static int
bcmchan_free(kobj_t obj,void * data)793 bcmchan_free(kobj_t obj, void *data)
794 {
795 	struct bcm2835_audio_chinfo *ch = data;
796 	void *buffer;
797 
798 	buffer = ch->buffer->buf;
799 	if (buffer)
800 		free(buffer, M_DEVBUF);
801 
802 	return (0);
803 }
804 
805 static int
bcmchan_setformat(kobj_t obj,void * data,uint32_t format)806 bcmchan_setformat(kobj_t obj, void *data, uint32_t format)
807 {
808 	struct bcm2835_audio_chinfo *ch = data;
809 	struct bcm2835_audio_info *sc = ch->parent;
810 
811 	BCM2835_AUDIO_LOCK(sc);
812 	ch->fmt = format;
813 	bcm2835_worker_update_params(sc);
814 	BCM2835_AUDIO_UNLOCK(sc);
815 
816 	return 0;
817 }
818 
819 static uint32_t
bcmchan_setspeed(kobj_t obj,void * data,uint32_t speed)820 bcmchan_setspeed(kobj_t obj, void *data, uint32_t speed)
821 {
822 	struct bcm2835_audio_chinfo *ch = data;
823 	struct bcm2835_audio_info *sc = ch->parent;
824 
825 	BCM2835_AUDIO_LOCK(sc);
826 	ch->spd = speed;
827 	bcm2835_worker_update_params(sc);
828 	BCM2835_AUDIO_UNLOCK(sc);
829 
830 	return ch->spd;
831 }
832 
833 static uint32_t
bcmchan_setblocksize(kobj_t obj,void * data,uint32_t blocksize)834 bcmchan_setblocksize(kobj_t obj, void *data, uint32_t blocksize)
835 {
836 	struct bcm2835_audio_chinfo *ch = data;
837 
838 	return ch->blksz;
839 }
840 
841 static int
bcmchan_trigger(kobj_t obj,void * data,int go)842 bcmchan_trigger(kobj_t obj, void *data, int go)
843 {
844 	struct bcm2835_audio_chinfo *ch = data;
845 	struct bcm2835_audio_info *sc = ch->parent;
846 
847 	if (!PCMTRIG_COMMON(go))
848 		return (0);
849 
850 	switch (go) {
851 	case PCMTRIG_START:
852 		/* kickstart data flow */
853 		ch->submitted_samples = 0;
854 		ch->retrieved_samples = 0;
855 		bcm2835_worker_play_start(sc);
856 		break;
857 
858 	case PCMTRIG_STOP:
859 	case PCMTRIG_ABORT:
860 		bcm2835_worker_play_stop(sc);
861 		break;
862 
863 	default:
864 		break;
865 	}
866 	return 0;
867 }
868 
869 static uint32_t
bcmchan_getptr(kobj_t obj,void * data)870 bcmchan_getptr(kobj_t obj, void *data)
871 {
872 	struct bcm2835_audio_chinfo *ch = data;
873 	struct bcm2835_audio_info *sc = ch->parent;
874 	uint32_t ret;
875 
876 	BCM2835_AUDIO_LOCK(sc);
877 	ret = ch->unsubmittedptr;
878 	BCM2835_AUDIO_UNLOCK(sc);
879 
880 	return ret;
881 }
882 
883 static struct pcmchan_caps *
bcmchan_getcaps(kobj_t obj,void * data)884 bcmchan_getcaps(kobj_t obj, void *data)
885 {
886 
887 	return &bcm2835_audio_playcaps;
888 }
889 
890 static kobj_method_t bcmchan_methods[] = {
891     	KOBJMETHOD(channel_init,		bcmchan_init),
892     	KOBJMETHOD(channel_free,		bcmchan_free),
893     	KOBJMETHOD(channel_setformat,		bcmchan_setformat),
894     	KOBJMETHOD(channel_setspeed,		bcmchan_setspeed),
895     	KOBJMETHOD(channel_setblocksize,	bcmchan_setblocksize),
896     	KOBJMETHOD(channel_trigger,		bcmchan_trigger),
897     	KOBJMETHOD(channel_getptr,		bcmchan_getptr),
898     	KOBJMETHOD(channel_getcaps,		bcmchan_getcaps),
899 	KOBJMETHOD_END
900 };
901 CHANNEL_DECLARE(bcmchan);
902 
903 /************************************************************/
904 
905 static int
bcmmix_init(struct snd_mixer * m)906 bcmmix_init(struct snd_mixer *m)
907 {
908 
909 	mix_setdevs(m, SOUND_MASK_VOLUME);
910 
911 	return (0);
912 }
913 
914 static int
bcmmix_set(struct snd_mixer * m,unsigned dev,unsigned left,unsigned right)915 bcmmix_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right)
916 {
917     	struct bcm2835_audio_info *sc = mix_getdevinfo(m);
918 
919 	switch (dev) {
920 	case SOUND_MIXER_VOLUME:
921 		BCM2835_AUDIO_LOCK(sc);
922 		sc->volume = left;
923 		bcm2835_worker_update_params(sc);
924 		BCM2835_AUDIO_UNLOCK(sc);
925 
926 		break;
927 
928 	default:
929 		break;
930 	}
931 
932     	return left | (left << 8);
933 }
934 
935 static kobj_method_t bcmmixer_methods[] = {
936     	KOBJMETHOD(mixer_init,		bcmmix_init),
937     	KOBJMETHOD(mixer_set,		bcmmix_set),
938 	KOBJMETHOD_END
939 };
940 
941 MIXER_DECLARE(bcmmixer);
942 
943 static int
sysctl_bcm2835_audio_dest(SYSCTL_HANDLER_ARGS)944 sysctl_bcm2835_audio_dest(SYSCTL_HANDLER_ARGS)
945 {
946 	struct bcm2835_audio_info *sc = arg1;
947 	int val;
948 	int err;
949 
950 	val = sc->dest;
951 	err = sysctl_handle_int(oidp, &val, 0, req);
952 	if (err || !req->newptr) /* error || read request */
953 		return (err);
954 
955 	if ((val < 0) || (val > 2))
956 		return (EINVAL);
957 
958 	BCM2835_AUDIO_LOCK(sc);
959 	sc->dest = val;
960 	bcm2835_worker_update_params(sc);
961 	BCM2835_AUDIO_UNLOCK(sc);
962 
963 	if (bootverbose)
964 		device_printf(sc->dev, "destination set to %s\n", dest_description(val));
965 
966 	return (0);
967 }
968 
969 static void
vchi_audio_sysctl_init(struct bcm2835_audio_info * sc)970 vchi_audio_sysctl_init(struct bcm2835_audio_info *sc)
971 {
972 	struct sysctl_ctx_list *ctx;
973 	struct sysctl_oid *tree_node;
974 	struct sysctl_oid_list *tree;
975 
976 	/*
977 	 * Add system sysctl tree/handlers.
978 	 */
979 	ctx = device_get_sysctl_ctx(sc->dev);
980 	tree_node = device_get_sysctl_tree(sc->dev);
981 	tree = SYSCTL_CHILDREN(tree_node);
982 	SYSCTL_ADD_PROC(ctx, tree, OID_AUTO, "dest",
983 	    CTLFLAG_RW | CTLTYPE_UINT | CTLFLAG_NEEDGIANT, sc, sizeof(*sc),
984 	    sysctl_bcm2835_audio_dest, "IU", "audio destination, "
985 	    "0 - auto, 1 - headphones, 2 - HDMI");
986 	SYSCTL_ADD_UQUAD(ctx, tree, OID_AUTO, "callbacks",
987 			CTLFLAG_RD, &sc->pch.callbacks,
988 			"callbacks total");
989 	SYSCTL_ADD_UQUAD(ctx, tree, OID_AUTO, "submitted",
990 			CTLFLAG_RD, &sc->pch.submitted_samples,
991 			"last play submitted samples");
992 	SYSCTL_ADD_UQUAD(ctx, tree, OID_AUTO, "retrieved",
993 			CTLFLAG_RD, &sc->pch.retrieved_samples,
994 			"last play retrieved samples");
995 	SYSCTL_ADD_UQUAD(ctx, tree, OID_AUTO, "underruns",
996 			CTLFLAG_RD, &sc->pch.underruns,
997 			"callback underruns");
998 	SYSCTL_ADD_INT(ctx, tree, OID_AUTO, "freebuffer",
999 			CTLFLAG_RD, &sc->pch.available_space,
1000 			sc->pch.available_space, "callbacks total");
1001 	SYSCTL_ADD_INT(ctx, tree, OID_AUTO, "starved",
1002 			CTLFLAG_RD, &sc->pch.starved,
1003 			sc->pch.starved, "number of starved conditions");
1004 	SYSCTL_ADD_INT(ctx, tree, OID_AUTO, "trace",
1005 			CTLFLAG_RW, &sc->verbose_trace,
1006 			sc->verbose_trace, "enable tracing of transfers");
1007 }
1008 
1009 static void
bcm2835_audio_identify(driver_t * driver,device_t parent)1010 bcm2835_audio_identify(driver_t *driver, device_t parent)
1011 {
1012 
1013 	BUS_ADD_CHILD(parent, 0, "pcm", 0);
1014 }
1015 
1016 static int
bcm2835_audio_probe(device_t dev)1017 bcm2835_audio_probe(device_t dev)
1018 {
1019 
1020 	device_set_desc(dev, "VCHIQ audio");
1021 	return (BUS_PROBE_DEFAULT);
1022 }
1023 
1024 static void
bcm2835_audio_delayed_init(void * xsc)1025 bcm2835_audio_delayed_init(void *xsc)
1026 {
1027     	struct bcm2835_audio_info *sc;
1028     	char status[SND_STATUSLEN];
1029 
1030 	sc = xsc;
1031 
1032 	config_intrhook_disestablish(&sc->intr_hook);
1033 
1034 	bcm2835_audio_init(sc);
1035 	bcm2835_audio_open(sc);
1036 	sc->volume = 75;
1037 	sc->dest = DEST_AUTO;
1038 	sc->verbose_trace = 0;
1039 
1040     	if (mixer_init(sc->dev, &bcmmixer_class, sc)) {
1041 		device_printf(sc->dev, "mixer_init failed\n");
1042 		goto no;
1043 	}
1044 
1045 	pcm_init(sc->dev, sc);
1046 
1047 	pcm_addchan(sc->dev, PCMDIR_PLAY, &bcmchan_class, sc);
1048     	snprintf(status, SND_STATUSLEN, "at VCHIQ");
1049 	if (pcm_register(sc->dev, status)) {
1050 		device_printf(sc->dev, "pcm_register failed\n");
1051 		goto no;
1052 	}
1053 
1054 	bcm2835_audio_reset_channel(&sc->pch);
1055 	bcm2835_audio_create_worker(sc);
1056 
1057 	vchi_audio_sysctl_init(sc);
1058 
1059 no:
1060 	;
1061 }
1062 
1063 static int
bcm2835_audio_attach(device_t dev)1064 bcm2835_audio_attach(device_t dev)
1065 {
1066     	struct bcm2835_audio_info *sc;
1067 
1068 	sc = malloc(sizeof(*sc), M_DEVBUF, M_WAITOK | M_ZERO);
1069 
1070 	sc->dev = dev;
1071 	sc->bufsz = VCHIQ_AUDIO_BUFFER_SIZE;
1072 
1073 	mtx_init(&sc->lock, device_get_nameunit(dev),
1074 	    "bcm_audio_lock", MTX_DEF);
1075 	cv_init(&sc->worker_cv, "worker_cv");
1076 	sc->vchi_handle = VCHIQ_SERVICE_HANDLE_INVALID;
1077 
1078 	/*
1079 	 * We need interrupts enabled for VCHI to work properly,
1080 	 * so delay initialization until it happens.
1081 	 */
1082 	sc->intr_hook.ich_func = bcm2835_audio_delayed_init;
1083 	sc->intr_hook.ich_arg = sc;
1084 
1085 	if (config_intrhook_establish(&sc->intr_hook) != 0)
1086 		goto no;
1087 
1088     	return 0;
1089 
1090 no:
1091     	return ENXIO;
1092 }
1093 
1094 static int
bcm2835_audio_detach(device_t dev)1095 bcm2835_audio_detach(device_t dev)
1096 {
1097 	int r;
1098 	struct bcm2835_audio_info *sc;
1099 	sc = pcm_getdevinfo(dev);
1100 
1101 	/* Stop worker thread */
1102 	BCM2835_AUDIO_LOCK(sc);
1103 	sc->worker_state = WORKER_STOPPING;
1104 	cv_signal(&sc->worker_cv);
1105 	/* Wait for thread to exit */
1106 	while (sc->worker_state != WORKER_STOPPED)
1107 		cv_wait_sig(&sc->worker_cv, &sc->lock);
1108 	BCM2835_AUDIO_UNLOCK(sc);
1109 
1110 	r = pcm_unregister(dev);
1111 	if (r)
1112 		return r;
1113 
1114 	mtx_destroy(&sc->lock);
1115 	cv_destroy(&sc->worker_cv);
1116 
1117 	bcm2835_audio_release(sc);
1118 
1119     	free(sc, M_DEVBUF);
1120 
1121 	return 0;
1122 }
1123 
1124 static device_method_t bcm2835_audio_methods[] = {
1125 	/* Device interface */
1126 	DEVMETHOD(device_identify,	bcm2835_audio_identify),
1127 	DEVMETHOD(device_probe,		bcm2835_audio_probe),
1128 	DEVMETHOD(device_attach,	bcm2835_audio_attach),
1129 	DEVMETHOD(device_detach,	bcm2835_audio_detach),
1130 	{ 0, 0 }
1131 };
1132 
1133 static driver_t bcm2835_audio_driver = {
1134 	"pcm",
1135 	bcm2835_audio_methods,
1136 	PCM_SOFTC_SIZE,
1137 };
1138 
1139 DRIVER_MODULE(bcm2835_audio, vchiq, bcm2835_audio_driver, 0, 0);
1140 MODULE_DEPEND(bcm2835_audio, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER);
1141 MODULE_DEPEND(bcm2835_audio, vchiq, 1, 1, 1);
1142 MODULE_VERSION(bcm2835_audio, 1);
1143