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