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