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, ¶ms,
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