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