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 #include <dev/sound/chip.h> 32 33 #include "mixer_if.h" 34 35 #include "interface/compat/vchi_bsd.h" 36 #include "interface/vchi/vchi.h" 37 #include "interface/vchiq_arm/vchiq.h" 38 39 #include "vc_vchi_audioserv_defs.h" 40 41 SND_DECLARE_FILE("$FreeBSD$"); 42 43 /* Audio destination */ 44 #define DEST_AUTO 0 45 #define DEST_HEADPHONES 1 46 #define DEST_HDMI 2 47 48 /* Playback state */ 49 #define PLAYBACK_IDLE 0 50 #define PLAYBACK_PLAYING 1 51 #define PLAYBACK_STOPPING 2 52 53 /* Worker thread state */ 54 #define WORKER_RUNNING 0 55 #define WORKER_STOPPING 1 56 #define WORKER_STOPPED 2 57 58 /* 59 * Worker thread flags, set to 1 in flags_pending 60 * when driver requests one or another operation 61 * from worker. Cleared to 0 once worker performs 62 * the operations. 63 */ 64 #define AUDIO_PARAMS (1 << 0) 65 #define AUDIO_PLAY (1 << 1) 66 #define AUDIO_STOP (1 << 2) 67 68 #define VCHIQ_AUDIO_PACKET_SIZE 4000 69 #define VCHIQ_AUDIO_BUFFER_SIZE 10*VCHIQ_AUDIO_PACKET_SIZE 70 71 #define VCHIQ_AUDIO_MAX_VOLUME 72 /* volume in terms of 0.01dB */ 73 #define VCHIQ_AUDIO_VOLUME_MIN -10239 74 #define VCHIQ_AUDIO_VOLUME(db100) (uint32_t)(-((db100) << 8)/100) 75 76 /* dB levels with 5% volume step */ 77 static int db_levels[] = { 78 VCHIQ_AUDIO_VOLUME_MIN, -4605, -3794, -3218, -2772, 79 -2407, -2099, -1832, -1597, -1386, 80 -1195, -1021, -861, -713, -575, 81 -446, -325, -210, -102, 0, 82 }; 83 84 static uint32_t bcm2835_audio_playfmt[] = { 85 SND_FORMAT(AFMT_U8, 1, 0), 86 SND_FORMAT(AFMT_U8, 2, 0), 87 SND_FORMAT(AFMT_S8, 1, 0), 88 SND_FORMAT(AFMT_S8, 2, 0), 89 SND_FORMAT(AFMT_S16_LE, 1, 0), 90 SND_FORMAT(AFMT_S16_LE, 2, 0), 91 SND_FORMAT(AFMT_U16_LE, 1, 0), 92 SND_FORMAT(AFMT_U16_LE, 2, 0), 93 0 94 }; 95 96 static struct pcmchan_caps bcm2835_audio_playcaps = {8000, 48000, bcm2835_audio_playfmt, 0}; 97 98 struct bcm2835_audio_info; 99 100 struct bcm2835_audio_chinfo { 101 struct bcm2835_audio_info *parent; 102 struct pcm_channel *channel; 103 struct snd_dbuf *buffer; 104 uint32_t fmt, spd, blksz; 105 106 /* Pointer to first unsubmitted sample */ 107 uint32_t unsubmittedptr; 108 /* 109 * Number of bytes in "submitted but not played" 110 * pseudo-buffer 111 */ 112 int available_space; 113 int playback_state; 114 uint64_t callbacks; 115 uint64_t submitted_samples; 116 uint64_t retrieved_samples; 117 uint64_t underruns; 118 int starved; 119 }; 120 121 struct bcm2835_audio_info { 122 device_t dev; 123 unsigned int bufsz; 124 struct bcm2835_audio_chinfo pch; 125 uint32_t dest, volume; 126 struct intr_config_hook intr_hook; 127 128 /* VCHI data */ 129 VCHI_INSTANCE_T vchi_instance; 130 VCHI_CONNECTION_T *vchi_connection; 131 VCHI_SERVICE_HANDLE_T vchi_handle; 132 133 struct mtx lock; 134 struct cv worker_cv; 135 136 uint32_t flags_pending; 137 138 /* Worker thread state */ 139 int worker_state; 140 }; 141 142 #define BCM2835_AUDIO_LOCK(sc) mtx_lock(&(sc)->lock) 143 #define BCM2835_AUDIO_LOCKED(sc) mtx_assert(&(sc)->lock, MA_OWNED) 144 #define BCM2835_AUDIO_UNLOCK(sc) mtx_unlock(&(sc)->lock) 145 146 static const char * 147 dest_description(uint32_t dest) 148 { 149 switch (dest) { 150 case DEST_AUTO: 151 return "AUTO"; 152 break; 153 154 case DEST_HEADPHONES: 155 return "HEADPHONES"; 156 break; 157 158 case DEST_HDMI: 159 return "HDMI"; 160 break; 161 default: 162 return "UNKNOWN"; 163 break; 164 } 165 } 166 167 static void 168 bcm2835_worker_update_params(struct bcm2835_audio_info *sc) 169 { 170 171 BCM2835_AUDIO_LOCKED(sc); 172 173 sc->flags_pending |= AUDIO_PARAMS; 174 cv_signal(&sc->worker_cv); 175 } 176 177 static void 178 bcm2835_worker_play_start(struct bcm2835_audio_info *sc) 179 { 180 BCM2835_AUDIO_LOCK(sc); 181 sc->flags_pending &= ~(AUDIO_STOP); 182 sc->flags_pending |= AUDIO_PLAY; 183 cv_signal(&sc->worker_cv); 184 BCM2835_AUDIO_UNLOCK(sc); 185 } 186 187 static void 188 bcm2835_worker_play_stop(struct bcm2835_audio_info *sc) 189 { 190 BCM2835_AUDIO_LOCK(sc); 191 sc->flags_pending &= ~(AUDIO_PLAY); 192 sc->flags_pending |= AUDIO_STOP; 193 cv_signal(&sc->worker_cv); 194 BCM2835_AUDIO_UNLOCK(sc); 195 } 196 197 static void 198 bcm2835_audio_callback(void *param, const VCHI_CALLBACK_REASON_T reason, void *msg_handle) 199 { 200 struct bcm2835_audio_info *sc = (struct bcm2835_audio_info *)param; 201 int32_t status; 202 uint32_t msg_len; 203 VC_AUDIO_MSG_T m; 204 205 if (reason != VCHI_CALLBACK_MSG_AVAILABLE) 206 return; 207 208 status = vchi_msg_dequeue(sc->vchi_handle, 209 &m, sizeof m, &msg_len, VCHI_FLAGS_NONE); 210 if (status != 0) 211 return; 212 if (m.type == VC_AUDIO_MSG_TYPE_RESULT) { 213 if (m.u.result.success) { 214 device_printf(sc->dev, 215 "msg type %08x failed\n", 216 m.type); 217 } 218 } else if (m.type == VC_AUDIO_MSG_TYPE_COMPLETE) { 219 struct bcm2835_audio_chinfo *ch = m.u.complete.cookie; 220 221 int count = m.u.complete.count & 0xffff; 222 int perr = (m.u.complete.count & (1U << 30)) != 0; 223 ch->callbacks++; 224 if (perr) 225 ch->underruns++; 226 227 BCM2835_AUDIO_LOCK(sc); 228 if (ch->playback_state != PLAYBACK_IDLE) { 229 /* Prevent LOR */ 230 BCM2835_AUDIO_UNLOCK(sc); 231 chn_intr(sc->pch.channel); 232 BCM2835_AUDIO_LOCK(sc); 233 } 234 /* We should check again, state might have changed */ 235 if (ch->playback_state != PLAYBACK_IDLE) { 236 if (!perr) { 237 if ((ch->available_space + count)> VCHIQ_AUDIO_BUFFER_SIZE) { 238 device_printf(sc->dev, "inconsistent data in callback:\n"); 239 device_printf(sc->dev, "available_space == %d, count = %d, perr=%d\n", 240 ch->available_space, count, perr); 241 device_printf(sc->dev, 242 "retrieved_samples = %lld, submitted_samples = %lld\n", 243 ch->retrieved_samples, ch->submitted_samples); 244 } 245 ch->available_space += count; 246 ch->retrieved_samples += count; 247 } 248 if (perr || (ch->available_space >= VCHIQ_AUDIO_PACKET_SIZE)) 249 cv_signal(&sc->worker_cv); 250 } 251 BCM2835_AUDIO_UNLOCK(sc); 252 } else 253 printf("%s: unknown m.type: %d\n", __func__, m.type); 254 } 255 256 /* VCHIQ stuff */ 257 static void 258 bcm2835_audio_init(struct bcm2835_audio_info *sc) 259 { 260 int status; 261 262 /* Initialize and create a VCHI connection */ 263 status = vchi_initialise(&sc->vchi_instance); 264 if (status != 0) { 265 printf("vchi_initialise failed: %d\n", status); 266 return; 267 } 268 269 status = vchi_connect(NULL, 0, sc->vchi_instance); 270 if (status != 0) { 271 printf("vchi_connect failed: %d\n", status); 272 return; 273 } 274 275 SERVICE_CREATION_T params = { 276 VCHI_VERSION_EX(VC_AUDIOSERV_VER, VC_AUDIOSERV_MIN_VER), 277 VC_AUDIO_SERVER_NAME, /* 4cc service code */ 278 sc->vchi_connection, /* passed in fn pointers */ 279 0, /* rx fifo size */ 280 0, /* tx fifo size */ 281 bcm2835_audio_callback, /* service callback */ 282 sc, /* service callback parameter */ 283 1, 284 1, 285 0 /* want crc check on bulk transfers */ 286 }; 287 288 status = vchi_service_open(sc->vchi_instance, ¶ms, 289 &sc->vchi_handle); 290 291 if (status != 0) 292 sc->vchi_handle = VCHIQ_SERVICE_HANDLE_INVALID; 293 } 294 295 static void 296 bcm2835_audio_release(struct bcm2835_audio_info *sc) 297 { 298 int success; 299 300 if (sc->vchi_handle != VCHIQ_SERVICE_HANDLE_INVALID) { 301 success = vchi_service_close(sc->vchi_handle); 302 if (success != 0) 303 printf("vchi_service_close failed: %d\n", success); 304 vchi_service_release(sc->vchi_handle); 305 sc->vchi_handle = VCHIQ_SERVICE_HANDLE_INVALID; 306 } 307 308 vchi_disconnect(sc->vchi_instance); 309 } 310 311 static void 312 bcm2835_audio_reset_channel(struct bcm2835_audio_chinfo *ch) 313 { 314 315 ch->available_space = VCHIQ_AUDIO_BUFFER_SIZE; 316 ch->unsubmittedptr = 0; 317 sndbuf_reset(ch->buffer); 318 } 319 320 static void 321 bcm2835_audio_start(struct bcm2835_audio_chinfo *ch) 322 { 323 VC_AUDIO_MSG_T m; 324 int ret; 325 struct bcm2835_audio_info *sc = ch->parent; 326 327 if (sc->vchi_handle != VCHIQ_SERVICE_HANDLE_INVALID) { 328 m.type = VC_AUDIO_MSG_TYPE_START; 329 ret = vchi_msg_queue(sc->vchi_handle, 330 &m, sizeof m, VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL); 331 332 if (ret != 0) 333 printf("%s: vchi_msg_queue failed (err %d)\n", __func__, ret); 334 } 335 } 336 337 static void 338 bcm2835_audio_stop(struct bcm2835_audio_chinfo *ch) 339 { 340 VC_AUDIO_MSG_T m; 341 int ret; 342 struct bcm2835_audio_info *sc = ch->parent; 343 344 if (sc->vchi_handle != VCHIQ_SERVICE_HANDLE_INVALID) { 345 m.type = VC_AUDIO_MSG_TYPE_STOP; 346 m.u.stop.draining = 0; 347 348 ret = vchi_msg_queue(sc->vchi_handle, 349 &m, sizeof m, VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL); 350 351 if (ret != 0) 352 printf("%s: vchi_msg_queue failed (err %d)\n", __func__, ret); 353 } 354 } 355 356 static void 357 bcm2835_audio_open(struct bcm2835_audio_info *sc) 358 { 359 VC_AUDIO_MSG_T m; 360 int ret; 361 362 if (sc->vchi_handle != VCHIQ_SERVICE_HANDLE_INVALID) { 363 m.type = VC_AUDIO_MSG_TYPE_OPEN; 364 ret = vchi_msg_queue(sc->vchi_handle, 365 &m, sizeof m, VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL); 366 367 if (ret != 0) 368 printf("%s: vchi_msg_queue failed (err %d)\n", __func__, ret); 369 } 370 } 371 372 static void 373 bcm2835_audio_update_controls(struct bcm2835_audio_info *sc, uint32_t volume, uint32_t dest) 374 { 375 VC_AUDIO_MSG_T m; 376 int ret, db; 377 378 if (sc->vchi_handle != VCHIQ_SERVICE_HANDLE_INVALID) { 379 m.type = VC_AUDIO_MSG_TYPE_CONTROL; 380 m.u.control.dest = dest; 381 if (volume > 99) 382 volume = 99; 383 db = db_levels[volume/5]; 384 m.u.control.volume = VCHIQ_AUDIO_VOLUME(db); 385 386 ret = vchi_msg_queue(sc->vchi_handle, 387 &m, sizeof m, VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL); 388 389 if (ret != 0) 390 printf("%s: vchi_msg_queue failed (err %d)\n", __func__, ret); 391 } 392 } 393 394 static void 395 bcm2835_audio_update_params(struct bcm2835_audio_info *sc, uint32_t fmt, uint32_t speed) 396 { 397 VC_AUDIO_MSG_T m; 398 int ret; 399 400 if (sc->vchi_handle != VCHIQ_SERVICE_HANDLE_INVALID) { 401 m.type = VC_AUDIO_MSG_TYPE_CONFIG; 402 m.u.config.channels = AFMT_CHANNEL(fmt); 403 m.u.config.samplerate = speed; 404 m.u.config.bps = AFMT_BIT(fmt); 405 406 ret = vchi_msg_queue(sc->vchi_handle, 407 &m, sizeof m, VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL); 408 409 if (ret != 0) 410 printf("%s: vchi_msg_queue failed (err %d)\n", __func__, ret); 411 } 412 } 413 414 static bool 415 bcm2835_audio_buffer_should_sleep(struct bcm2835_audio_chinfo *ch) 416 { 417 418 if (ch->playback_state != PLAYBACK_PLAYING) 419 return (true); 420 421 /* Not enough data */ 422 if (sndbuf_getready(ch->buffer) < VCHIQ_AUDIO_PACKET_SIZE) { 423 printf("starve\n"); 424 ch->starved++; 425 return (true); 426 } 427 428 /* Not enough free space */ 429 if (ch->available_space < VCHIQ_AUDIO_PACKET_SIZE) { 430 return (true); 431 } 432 433 return (false); 434 } 435 436 static void 437 bcm2835_audio_write_samples(struct bcm2835_audio_chinfo *ch, void *buf, uint32_t count) 438 { 439 struct bcm2835_audio_info *sc = ch->parent; 440 VC_AUDIO_MSG_T m; 441 int ret; 442 443 if (sc->vchi_handle == VCHIQ_SERVICE_HANDLE_INVALID) { 444 return; 445 } 446 447 m.type = VC_AUDIO_MSG_TYPE_WRITE; 448 m.u.write.count = count; 449 m.u.write.max_packet = VCHIQ_AUDIO_PACKET_SIZE; 450 m.u.write.callback = NULL; 451 m.u.write.cookie = ch; 452 m.u.write.silence = 0; 453 454 ret = vchi_msg_queue(sc->vchi_handle, 455 &m, sizeof m, VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL); 456 457 if (ret != 0) 458 printf("%s: vchi_msg_queue failed (err %d)\n", __func__, ret); 459 460 while (count > 0) { 461 int bytes = MIN((int)m.u.write.max_packet, (int)count); 462 ret = vchi_msg_queue(sc->vchi_handle, 463 buf, bytes, VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL); 464 if (ret != 0) 465 printf("%s: vchi_msg_queue failed: %d\n", 466 __func__, ret); 467 buf = (char *)buf + bytes; 468 count -= bytes; 469 } 470 } 471 472 static void 473 bcm2835_audio_worker(void *data) 474 { 475 struct bcm2835_audio_info *sc = (struct bcm2835_audio_info *)data; 476 struct bcm2835_audio_chinfo *ch = &sc->pch; 477 uint32_t speed, format; 478 uint32_t volume, dest; 479 uint32_t flags; 480 uint32_t count, size, readyptr; 481 uint8_t *buf; 482 483 ch->playback_state = PLAYBACK_IDLE; 484 485 while (1) { 486 if (sc->worker_state != WORKER_RUNNING) 487 break; 488 489 BCM2835_AUDIO_LOCK(sc); 490 /* 491 * wait until there are flags set or buffer is ready 492 * to consume more samples 493 */ 494 while ((sc->flags_pending == 0) && 495 bcm2835_audio_buffer_should_sleep(ch)) { 496 cv_wait_sig(&sc->worker_cv, &sc->lock); 497 } 498 flags = sc->flags_pending; 499 /* Clear pending flags */ 500 sc->flags_pending = 0; 501 BCM2835_AUDIO_UNLOCK(sc); 502 503 /* Requested to change parameters */ 504 if (flags & AUDIO_PARAMS) { 505 BCM2835_AUDIO_LOCK(sc); 506 speed = ch->spd; 507 format = ch->fmt; 508 volume = sc->volume; 509 dest = sc->dest; 510 BCM2835_AUDIO_UNLOCK(sc); 511 if (ch->playback_state == PLAYBACK_IDLE) 512 bcm2835_audio_update_params(sc, format, speed); 513 bcm2835_audio_update_controls(sc, volume, dest); 514 } 515 516 /* Requested to stop playback */ 517 if ((flags & AUDIO_STOP) && 518 (ch->playback_state == PLAYBACK_PLAYING)) { 519 bcm2835_audio_stop(ch); 520 BCM2835_AUDIO_LOCK(sc); 521 bcm2835_audio_reset_channel(&sc->pch); 522 ch->playback_state = PLAYBACK_IDLE; 523 BCM2835_AUDIO_UNLOCK(sc); 524 continue; 525 } 526 527 /* Requested to start playback */ 528 if ((flags & AUDIO_PLAY) && 529 (ch->playback_state == PLAYBACK_IDLE)) { 530 BCM2835_AUDIO_LOCK(sc); 531 ch->playback_state = PLAYBACK_PLAYING; 532 BCM2835_AUDIO_UNLOCK(sc); 533 bcm2835_audio_start(ch); 534 } 535 536 if (ch->playback_state == PLAYBACK_IDLE) 537 continue; 538 539 if (sndbuf_getready(ch->buffer) == 0) 540 continue; 541 542 count = sndbuf_getready(ch->buffer); 543 size = sndbuf_getsize(ch->buffer); 544 readyptr = sndbuf_getreadyptr(ch->buffer); 545 546 BCM2835_AUDIO_LOCK(sc); 547 if (readyptr + count > size) 548 count = size - readyptr; 549 count = min(count, ch->available_space); 550 count -= (count % VCHIQ_AUDIO_PACKET_SIZE); 551 BCM2835_AUDIO_UNLOCK(sc); 552 553 if (count < VCHIQ_AUDIO_PACKET_SIZE) 554 continue; 555 556 buf = (uint8_t*)sndbuf_getbuf(ch->buffer) + readyptr; 557 558 bcm2835_audio_write_samples(ch, buf, count); 559 BCM2835_AUDIO_LOCK(sc); 560 ch->unsubmittedptr = (ch->unsubmittedptr + count) % sndbuf_getsize(ch->buffer); 561 ch->available_space -= count; 562 ch->submitted_samples += count; 563 KASSERT(ch->available_space >= 0, ("ch->available_space == %d\n", ch->available_space)); 564 BCM2835_AUDIO_UNLOCK(sc); 565 } 566 567 BCM2835_AUDIO_LOCK(sc); 568 sc->worker_state = WORKER_STOPPED; 569 cv_signal(&sc->worker_cv); 570 BCM2835_AUDIO_UNLOCK(sc); 571 572 kproc_exit(0); 573 } 574 575 static void 576 bcm2835_audio_create_worker(struct bcm2835_audio_info *sc) 577 { 578 struct proc *newp; 579 580 sc->worker_state = WORKER_RUNNING; 581 if (kproc_create(bcm2835_audio_worker, (void*)sc, &newp, 0, 0, 582 "bcm2835_audio_worker") != 0) { 583 printf("failed to create bcm2835_audio_worker\n"); 584 } 585 } 586 587 /* -------------------------------------------------------------------- */ 588 /* channel interface for VCHI audio */ 589 static void * 590 bcmchan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir) 591 { 592 struct bcm2835_audio_info *sc = devinfo; 593 struct bcm2835_audio_chinfo *ch = &sc->pch; 594 void *buffer; 595 596 if (dir == PCMDIR_REC) 597 return NULL; 598 599 ch->parent = sc; 600 ch->channel = c; 601 ch->buffer = b; 602 603 /* default values */ 604 ch->spd = 44100; 605 ch->fmt = SND_FORMAT(AFMT_S16_LE, 2, 0); 606 ch->blksz = VCHIQ_AUDIO_PACKET_SIZE; 607 608 buffer = malloc(sc->bufsz, M_DEVBUF, M_WAITOK | M_ZERO); 609 610 if (sndbuf_setup(ch->buffer, buffer, sc->bufsz) != 0) { 611 device_printf(sc->dev, "sndbuf_setup failed\n"); 612 free(buffer, M_DEVBUF); 613 return NULL; 614 } 615 616 BCM2835_AUDIO_LOCK(sc); 617 bcm2835_worker_update_params(sc); 618 BCM2835_AUDIO_UNLOCK(sc); 619 620 return ch; 621 } 622 623 static int 624 bcmchan_free(kobj_t obj, void *data) 625 { 626 struct bcm2835_audio_chinfo *ch = data; 627 void *buffer; 628 629 buffer = sndbuf_getbuf(ch->buffer); 630 if (buffer) 631 free(buffer, M_DEVBUF); 632 633 return (0); 634 } 635 636 static int 637 bcmchan_setformat(kobj_t obj, void *data, uint32_t format) 638 { 639 struct bcm2835_audio_chinfo *ch = data; 640 struct bcm2835_audio_info *sc = ch->parent; 641 642 BCM2835_AUDIO_LOCK(sc); 643 ch->fmt = format; 644 bcm2835_worker_update_params(sc); 645 BCM2835_AUDIO_UNLOCK(sc); 646 647 return 0; 648 } 649 650 static uint32_t 651 bcmchan_setspeed(kobj_t obj, void *data, uint32_t speed) 652 { 653 struct bcm2835_audio_chinfo *ch = data; 654 struct bcm2835_audio_info *sc = ch->parent; 655 656 BCM2835_AUDIO_LOCK(sc); 657 ch->spd = speed; 658 bcm2835_worker_update_params(sc); 659 BCM2835_AUDIO_UNLOCK(sc); 660 661 return ch->spd; 662 } 663 664 static uint32_t 665 bcmchan_setblocksize(kobj_t obj, void *data, uint32_t blocksize) 666 { 667 struct bcm2835_audio_chinfo *ch = data; 668 669 return ch->blksz; 670 } 671 672 static int 673 bcmchan_trigger(kobj_t obj, void *data, int go) 674 { 675 struct bcm2835_audio_chinfo *ch = data; 676 struct bcm2835_audio_info *sc = ch->parent; 677 678 if (!PCMTRIG_COMMON(go)) 679 return (0); 680 681 switch (go) { 682 case PCMTRIG_START: 683 /* kickstart data flow */ 684 chn_intr(sc->pch.channel); 685 ch->submitted_samples = 0; 686 ch->retrieved_samples = 0; 687 bcm2835_worker_play_start(sc); 688 break; 689 690 case PCMTRIG_STOP: 691 case PCMTRIG_ABORT: 692 bcm2835_worker_play_stop(sc); 693 break; 694 695 default: 696 break; 697 } 698 return 0; 699 } 700 701 static uint32_t 702 bcmchan_getptr(kobj_t obj, void *data) 703 { 704 struct bcm2835_audio_chinfo *ch = data; 705 struct bcm2835_audio_info *sc = ch->parent; 706 uint32_t ret; 707 708 BCM2835_AUDIO_LOCK(sc); 709 ret = ch->unsubmittedptr; 710 BCM2835_AUDIO_UNLOCK(sc); 711 712 return ret; 713 } 714 715 static struct pcmchan_caps * 716 bcmchan_getcaps(kobj_t obj, void *data) 717 { 718 719 return &bcm2835_audio_playcaps; 720 } 721 722 static kobj_method_t bcmchan_methods[] = { 723 KOBJMETHOD(channel_init, bcmchan_init), 724 KOBJMETHOD(channel_free, bcmchan_free), 725 KOBJMETHOD(channel_setformat, bcmchan_setformat), 726 KOBJMETHOD(channel_setspeed, bcmchan_setspeed), 727 KOBJMETHOD(channel_setblocksize, bcmchan_setblocksize), 728 KOBJMETHOD(channel_trigger, bcmchan_trigger), 729 KOBJMETHOD(channel_getptr, bcmchan_getptr), 730 KOBJMETHOD(channel_getcaps, bcmchan_getcaps), 731 KOBJMETHOD_END 732 }; 733 CHANNEL_DECLARE(bcmchan); 734 735 /************************************************************/ 736 737 static int 738 bcmmix_init(struct snd_mixer *m) 739 { 740 741 mix_setdevs(m, SOUND_MASK_VOLUME); 742 743 return (0); 744 } 745 746 static int 747 bcmmix_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right) 748 { 749 struct bcm2835_audio_info *sc = mix_getdevinfo(m); 750 751 switch (dev) { 752 case SOUND_MIXER_VOLUME: 753 BCM2835_AUDIO_LOCK(sc); 754 sc->volume = left; 755 bcm2835_worker_update_params(sc); 756 BCM2835_AUDIO_UNLOCK(sc); 757 758 break; 759 760 default: 761 break; 762 } 763 764 return left | (left << 8); 765 } 766 767 static kobj_method_t bcmmixer_methods[] = { 768 KOBJMETHOD(mixer_init, bcmmix_init), 769 KOBJMETHOD(mixer_set, bcmmix_set), 770 KOBJMETHOD_END 771 }; 772 773 MIXER_DECLARE(bcmmixer); 774 775 static int 776 sysctl_bcm2835_audio_dest(SYSCTL_HANDLER_ARGS) 777 { 778 struct bcm2835_audio_info *sc = arg1; 779 int val; 780 int err; 781 782 val = sc->dest; 783 err = sysctl_handle_int(oidp, &val, 0, req); 784 if (err || !req->newptr) /* error || read request */ 785 return (err); 786 787 if ((val < 0) || (val > 2)) 788 return (EINVAL); 789 790 BCM2835_AUDIO_LOCK(sc); 791 sc->dest = val; 792 bcm2835_worker_update_params(sc); 793 BCM2835_AUDIO_UNLOCK(sc); 794 795 if (bootverbose) 796 device_printf(sc->dev, "destination set to %s\n", dest_description(val)); 797 798 return (0); 799 } 800 801 static void 802 vchi_audio_sysctl_init(struct bcm2835_audio_info *sc) 803 { 804 struct sysctl_ctx_list *ctx; 805 struct sysctl_oid *tree_node; 806 struct sysctl_oid_list *tree; 807 808 /* 809 * Add system sysctl tree/handlers. 810 */ 811 ctx = device_get_sysctl_ctx(sc->dev); 812 tree_node = device_get_sysctl_tree(sc->dev); 813 tree = SYSCTL_CHILDREN(tree_node); 814 SYSCTL_ADD_PROC(ctx, tree, OID_AUTO, "dest", 815 CTLFLAG_RW | CTLTYPE_UINT | CTLFLAG_NEEDGIANT, sc, sizeof(*sc), 816 sysctl_bcm2835_audio_dest, "IU", "audio destination, " 817 "0 - auto, 1 - headphones, 2 - HDMI"); 818 SYSCTL_ADD_UQUAD(ctx, tree, OID_AUTO, "callbacks", 819 CTLFLAG_RD, &sc->pch.callbacks, 820 "callbacks total"); 821 SYSCTL_ADD_UQUAD(ctx, tree, OID_AUTO, "submitted", 822 CTLFLAG_RD, &sc->pch.submitted_samples, 823 "last play submitted samples"); 824 SYSCTL_ADD_UQUAD(ctx, tree, OID_AUTO, "retrieved", 825 CTLFLAG_RD, &sc->pch.retrieved_samples, 826 "last play retrieved samples"); 827 SYSCTL_ADD_UQUAD(ctx, tree, OID_AUTO, "underruns", 828 CTLFLAG_RD, &sc->pch.underruns, 829 "callback underruns"); 830 SYSCTL_ADD_INT(ctx, tree, OID_AUTO, "freebuffer", 831 CTLFLAG_RD, &sc->pch.available_space, 832 sc->pch.available_space, "callbacks total"); 833 SYSCTL_ADD_INT(ctx, tree, OID_AUTO, "starved", 834 CTLFLAG_RD, &sc->pch.starved, 835 sc->pch.starved, "number of starved conditions"); 836 } 837 838 static void 839 bcm2835_audio_identify(driver_t *driver, device_t parent) 840 { 841 842 BUS_ADD_CHILD(parent, 0, "pcm", 0); 843 } 844 845 static int 846 bcm2835_audio_probe(device_t dev) 847 { 848 849 device_set_desc(dev, "VCHIQ audio"); 850 return (BUS_PROBE_DEFAULT); 851 } 852 853 static void 854 bcm2835_audio_delayed_init(void *xsc) 855 { 856 struct bcm2835_audio_info *sc; 857 char status[SND_STATUSLEN]; 858 859 sc = xsc; 860 861 config_intrhook_disestablish(&sc->intr_hook); 862 863 bcm2835_audio_init(sc); 864 bcm2835_audio_open(sc); 865 sc->volume = 75; 866 sc->dest = DEST_AUTO; 867 868 if (mixer_init(sc->dev, &bcmmixer_class, sc)) { 869 device_printf(sc->dev, "mixer_init failed\n"); 870 goto no; 871 } 872 873 if (pcm_register(sc->dev, sc, 1, 0)) { 874 device_printf(sc->dev, "pcm_register failed\n"); 875 goto no; 876 } 877 878 pcm_addchan(sc->dev, PCMDIR_PLAY, &bcmchan_class, sc); 879 snprintf(status, SND_STATUSLEN, "at VCHIQ"); 880 pcm_setstatus(sc->dev, status); 881 882 bcm2835_audio_reset_channel(&sc->pch); 883 bcm2835_audio_create_worker(sc); 884 885 vchi_audio_sysctl_init(sc); 886 887 no: 888 ; 889 } 890 891 static int 892 bcm2835_audio_attach(device_t dev) 893 { 894 struct bcm2835_audio_info *sc; 895 896 sc = malloc(sizeof(*sc), M_DEVBUF, M_WAITOK | M_ZERO); 897 898 sc->dev = dev; 899 sc->bufsz = VCHIQ_AUDIO_BUFFER_SIZE; 900 901 mtx_init(&sc->lock, device_get_nameunit(dev), 902 "bcm_audio_lock", MTX_DEF); 903 cv_init(&sc->worker_cv, "worker_cv"); 904 sc->vchi_handle = VCHIQ_SERVICE_HANDLE_INVALID; 905 906 /* 907 * We need interrupts enabled for VCHI to work properly, 908 * so delay initialization until it happens. 909 */ 910 sc->intr_hook.ich_func = bcm2835_audio_delayed_init; 911 sc->intr_hook.ich_arg = sc; 912 913 if (config_intrhook_establish(&sc->intr_hook) != 0) 914 goto no; 915 916 return 0; 917 918 no: 919 return ENXIO; 920 } 921 922 static int 923 bcm2835_audio_detach(device_t dev) 924 { 925 int r; 926 struct bcm2835_audio_info *sc; 927 sc = pcm_getdevinfo(dev); 928 929 /* Stop worker thread */ 930 BCM2835_AUDIO_LOCK(sc); 931 sc->worker_state = WORKER_STOPPING; 932 cv_signal(&sc->worker_cv); 933 /* Wait for thread to exit */ 934 while (sc->worker_state != WORKER_STOPPED) 935 cv_wait_sig(&sc->worker_cv, &sc->lock); 936 BCM2835_AUDIO_UNLOCK(sc); 937 938 r = pcm_unregister(dev); 939 if (r) 940 return r; 941 942 mtx_destroy(&sc->lock); 943 cv_destroy(&sc->worker_cv); 944 945 bcm2835_audio_release(sc); 946 947 free(sc, M_DEVBUF); 948 949 return 0; 950 } 951 952 static device_method_t bcm2835_audio_methods[] = { 953 /* Device interface */ 954 DEVMETHOD(device_identify, bcm2835_audio_identify), 955 DEVMETHOD(device_probe, bcm2835_audio_probe), 956 DEVMETHOD(device_attach, bcm2835_audio_attach), 957 DEVMETHOD(device_detach, bcm2835_audio_detach), 958 { 0, 0 } 959 }; 960 961 static driver_t bcm2835_audio_driver = { 962 "pcm", 963 bcm2835_audio_methods, 964 PCM_SOFTC_SIZE, 965 }; 966 967 DRIVER_MODULE(bcm2835_audio, vchiq, bcm2835_audio_driver, pcm_devclass, 0, 0); 968 MODULE_DEPEND(bcm2835_audio, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER); 969 MODULE_DEPEND(bcm2835_audio, vchiq, 1, 1, 1); 970 MODULE_VERSION(bcm2835_audio, 1); 971