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