1 /* $NetBSD: bcm2835_vcaudio.c,v 1.11 2016/10/14 20:29:45 nat Exp $ */ 2 3 /*- 4 * Copyright (c) 2013 Jared D. McNeill <jmcneill@invisible.ca> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 18 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 /* 30 * VideoCore audio interface 31 */ 32 33 #include <sys/cdefs.h> 34 __KERNEL_RCSID(0, "$NetBSD: bcm2835_vcaudio.c,v 1.11 2016/10/14 20:29:45 nat Exp $"); 35 36 #include <sys/param.h> 37 #include <sys/types.h> 38 #include <sys/systm.h> 39 #include <sys/device.h> 40 #include <sys/conf.h> 41 #include <sys/bus.h> 42 #include <sys/kmem.h> 43 44 #include <sys/audioio.h> 45 #include <dev/audio_if.h> 46 #include <dev/auconv.h> 47 #include <dev/auvolconv.h> 48 49 #include <interface/compat/vchi_bsd.h> 50 #include <interface/vchiq_arm/vchiq_netbsd.h> 51 #include <interface/vchi/vchi.h> 52 53 #include "bcm2835_vcaudioreg.h" 54 55 /* levels with 5% volume step */ 56 static int vcaudio_levels[] = { 57 -10239, -4605, -3794, -3218, -2772, 58 -2407, -2099, -1832, -1597, -1386, 59 -1195, -1021, -861, -713, -575, 60 -446, -325, -210, -102, 0, 61 }; 62 63 #define vol2db(vol) vcaudio_levels[((vol) * 20) >> 8] 64 #define vol2vc(vol) ((uint32_t)(-(vol2db((vol)) << 8) / 100)) 65 66 enum { 67 VCAUDIO_OUTPUT_CLASS, 68 VCAUDIO_INPUT_CLASS, 69 VCAUDIO_OUTPUT_MASTER_VOLUME, 70 VCAUDIO_INPUT_DAC_VOLUME, 71 VCAUDIO_OUTPUT_AUTO_VOLUME, 72 VCAUDIO_OUTPUT_HEADPHONE_VOLUME, 73 VCAUDIO_OUTPUT_HDMI_VOLUME, 74 VCAUDIO_OUTPUT_SELECT, 75 VCAUDIO_ENUM_LAST, 76 }; 77 78 enum vcaudio_dest { 79 VCAUDIO_DEST_AUTO = 0, 80 VCAUDIO_DEST_HP = 1, 81 VCAUDIO_DEST_HDMI = 2, 82 }; 83 84 /* 85 * Maximum message size is 4000 bytes and VCHIQ can accept 16 messages. 86 * 87 * 4000 bytes of 16bit 48kHz stereo is approximately 21ms. 88 * 89 * We get complete messages at ~10ms intervals. 90 * 91 * Setting blocksize to 4 x 1600 means that we send approx 33ms of audio. We 92 * prefill by two blocks before starting audio meaning we have 50ms of latency. 93 * 94 * Six messages of 1600 bytes was chosen working back from a desired latency of 95 * 50ms. 96 */ 97 98 #define VCAUDIO_MSGSIZE 1600 99 #define VCAUDIO_NUMMSGS 4 100 #define VCAUDIO_BLOCKSIZE (VCAUDIO_MSGSIZE * VCAUDIO_NUMMSGS) 101 #define VCAUDIO_BUFFERSIZE 128000 102 #define VCAUDIO_PREFILLCOUNT 2 103 104 struct vcaudio_softc { 105 device_t sc_dev; 106 device_t sc_audiodev; 107 108 lwp_t *sc_lwp; 109 110 kmutex_t sc_lock; 111 kmutex_t sc_intr_lock; 112 kcondvar_t sc_datacv; 113 114 kmutex_t sc_msglock; 115 kcondvar_t sc_msgcv; 116 117 struct audio_format sc_format; 118 struct audio_encoding_set *sc_encodings; 119 120 void (*sc_pint)(void *); 121 void *sc_pintarg; 122 audio_params_t sc_pparam; 123 bool sc_started; 124 int sc_pblkcnt; // prefill block count 125 int sc_abytes; // available bytes 126 int sc_pbytes; // played bytes 127 off_t sc_ppos; 128 void *sc_pstart; 129 void *sc_pend; 130 int sc_pblksize; 131 132 bool sc_msgdone; 133 int sc_success; 134 135 VCHI_INSTANCE_T sc_instance; 136 VCHI_CONNECTION_T sc_connection; 137 VCHI_SERVICE_HANDLE_T sc_service; 138 139 short sc_peer_version; 140 141 int sc_hwvol[3]; 142 enum vcaudio_dest sc_dest; 143 144 uint8_t sc_swvol; 145 }; 146 147 static int vcaudio_match(device_t, cfdata_t, void *); 148 static void vcaudio_attach(device_t, device_t, void *); 149 static int vcaudio_rescan(device_t, const char *, const int *); 150 static void vcaudio_childdet(device_t, device_t); 151 152 static int vcaudio_init(struct vcaudio_softc *); 153 static void vcaudio_service_callback(void *, 154 const VCHI_CALLBACK_REASON_T, void *); 155 static int vcaudio_msg_sync(struct vcaudio_softc *, VC_AUDIO_MSG_T *, 156 size_t); 157 static void vcaudio_worker(void *); 158 159 static int vcaudio_open(void *, int); 160 static void vcaudio_close(void *); 161 static int vcaudio_query_encoding(void *, struct audio_encoding *); 162 static int vcaudio_set_params(void *, int, int, 163 audio_params_t *, audio_params_t *, 164 stream_filter_list_t *, stream_filter_list_t *); 165 static int vcaudio_halt_output(void *); 166 static int vcaudio_halt_input(void *); 167 static int vcaudio_set_port(void *, mixer_ctrl_t *); 168 static int vcaudio_get_port(void *, mixer_ctrl_t *); 169 static int vcaudio_query_devinfo(void *, mixer_devinfo_t *); 170 static int vcaudio_getdev(void *, struct audio_device *); 171 static int vcaudio_get_props(void *); 172 173 static int vcaudio_round_blocksize(void *, int, int, 174 const audio_params_t *); 175 static size_t vcaudio_round_buffersize(void *, int, size_t); 176 177 static int vcaudio_trigger_output(void *, void *, void *, int, 178 void (*)(void *), void *, const audio_params_t *); 179 static int vcaudio_trigger_input(void *, void *, void *, int, 180 void (*)(void *), void *, const audio_params_t *); 181 182 static void vcaudio_get_locks(void *, kmutex_t **, kmutex_t **); 183 184 static stream_filter_t *vcaudio_swvol_filter(struct audio_softc *, 185 const audio_params_t *, const audio_params_t *); 186 static void vcaudio_swvol_dtor(stream_filter_t *); 187 188 static const struct audio_hw_if vcaudio_hw_if = { 189 .open = vcaudio_open, 190 .close = vcaudio_close, 191 .query_encoding = vcaudio_query_encoding, 192 .set_params = vcaudio_set_params, 193 .halt_output = vcaudio_halt_output, 194 .halt_input = vcaudio_halt_input, 195 .getdev = vcaudio_getdev, 196 .set_port = vcaudio_set_port, 197 .get_port = vcaudio_get_port, 198 .query_devinfo = vcaudio_query_devinfo, 199 .get_props = vcaudio_get_props, 200 .round_blocksize = vcaudio_round_blocksize, 201 .round_buffersize = vcaudio_round_buffersize, 202 .trigger_output = vcaudio_trigger_output, 203 .trigger_input = vcaudio_trigger_input, 204 .get_locks = vcaudio_get_locks, 205 }; 206 207 CFATTACH_DECL2_NEW(vcaudio, sizeof(struct vcaudio_softc), 208 vcaudio_match, vcaudio_attach, NULL, NULL, vcaudio_rescan, 209 vcaudio_childdet); 210 211 static int 212 vcaudio_match(device_t parent, cfdata_t match, void *aux) 213 { 214 struct vchiq_attach_args *vaa = aux; 215 216 return !strcmp(vaa->vaa_name, "AUDS"); 217 } 218 219 static void 220 vcaudio_attach(device_t parent, device_t self, void *aux) 221 { 222 struct vcaudio_softc *sc = device_private(self); 223 int error; 224 225 sc->sc_dev = self; 226 mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE); 227 mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_NONE); 228 mutex_init(&sc->sc_msglock, MUTEX_DEFAULT, IPL_NONE); 229 cv_init(&sc->sc_msgcv, "msg"); 230 cv_init(&sc->sc_datacv, "data"); 231 sc->sc_success = -1; 232 233 error = kthread_create(PRI_BIO, KTHREAD_MPSAFE, NULL, vcaudio_worker, 234 sc, &sc->sc_lwp, "vcaudio"); 235 if (error) { 236 aprint_error(": couldn't create thread (%d)\n", error); 237 return; 238 } 239 240 aprint_naive("\n"); 241 aprint_normal(": auds\n"); 242 243 error = vcaudio_rescan(self, NULL, NULL); 244 if (error) 245 aprint_error_dev(self, "not configured\n"); 246 247 } 248 249 static int 250 vcaudio_rescan(device_t self, const char *ifattr, const int *locs) 251 { 252 struct vcaudio_softc *sc = device_private(self); 253 int error; 254 255 if (ifattr_match(ifattr, "audiobus") && sc->sc_audiodev == NULL) { 256 error = vcaudio_init(sc); 257 if (error) { 258 return error; 259 } 260 261 sc->sc_audiodev = audio_attach_mi(&vcaudio_hw_if, 262 sc, sc->sc_dev); 263 } 264 return 0; 265 } 266 267 static void 268 vcaudio_childdet(device_t self, device_t child) 269 { 270 struct vcaudio_softc *sc = device_private(self); 271 272 if (sc->sc_audiodev == child) 273 sc->sc_audiodev = NULL; 274 } 275 276 static int 277 vcaudio_init(struct vcaudio_softc *sc) 278 { 279 VC_AUDIO_MSG_T msg; 280 int error; 281 282 sc->sc_swvol = 255; 283 sc->sc_hwvol[VCAUDIO_DEST_AUTO] = 255; 284 sc->sc_hwvol[VCAUDIO_DEST_HP] = 255; 285 sc->sc_hwvol[VCAUDIO_DEST_HDMI] = 255; 286 sc->sc_dest = VCAUDIO_DEST_AUTO; 287 288 sc->sc_format.mode = AUMODE_PLAY|AUMODE_RECORD; 289 sc->sc_format.encoding = AUDIO_ENCODING_SLINEAR_LE; 290 sc->sc_format.validbits = 16; 291 sc->sc_format.precision = 16; 292 sc->sc_format.channels = 2; 293 sc->sc_format.channel_mask = AUFMT_STEREO; 294 sc->sc_format.frequency_type = 0; 295 sc->sc_format.frequency[0] = 48000; 296 sc->sc_format.frequency[1] = 48000; 297 298 error = auconv_create_encodings(&sc->sc_format, 1, &sc->sc_encodings); 299 if (error) { 300 aprint_error_dev(sc->sc_dev, 301 "couldn't create encodings (error=%d)\n", error); 302 return error; 303 } 304 305 error = vchi_initialise(&sc->sc_instance); 306 if (error) { 307 aprint_error_dev(sc->sc_dev, 308 "couldn't init vchi instance (%d)\n", error); 309 return EIO; 310 } 311 312 error = vchi_connect(NULL, 0, sc->sc_instance); 313 if (error) { 314 aprint_error_dev(sc->sc_dev, 315 "couldn't connect vchi (%d)\n", error); 316 return EIO; 317 } 318 319 SERVICE_CREATION_T setup = { 320 .version = VCHI_VERSION(VC_AUDIOSERV_VER), 321 .service_id = VC_AUDIO_SERVER_NAME, 322 .connection = &sc->sc_connection, 323 .rx_fifo_size = 0, 324 .tx_fifo_size = 0, 325 .callback = vcaudio_service_callback, 326 .callback_param = sc, 327 .want_unaligned_bulk_rx = 1, 328 .want_unaligned_bulk_tx = 1, 329 .want_crc = 0, 330 }; 331 332 error = vchi_service_open(sc->sc_instance, &setup, &sc->sc_service); 333 if (error) { 334 aprint_error_dev(sc->sc_dev, "couldn't open service (%d)\n", 335 error); 336 return EIO; 337 } 338 339 vchi_get_peer_version(sc->sc_service, &sc->sc_peer_version); 340 341 if (sc->sc_peer_version < 2) { 342 aprint_error_dev(sc->sc_dev, 343 "peer version (%d) is less than the required version (2)\n", 344 sc->sc_peer_version); 345 return EINVAL; 346 } 347 348 memset(&msg, 0, sizeof(msg)); 349 msg.type = VC_AUDIO_MSG_TYPE_OPEN; 350 error = vchi_msg_queue(sc->sc_service, &msg, sizeof(msg), 351 VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL); 352 if (error) { 353 aprint_error_dev(sc->sc_dev, 354 "couldn't send OPEN message (%d)\n", error); 355 } 356 357 memset(&msg, 0, sizeof(msg)); 358 msg.type = VC_AUDIO_MSG_TYPE_CONFIG; 359 msg.u.config.channels = 2; 360 msg.u.config.samplerate = 48000; 361 msg.u.config.bps = 16; 362 error = vcaudio_msg_sync(sc, &msg, sizeof(msg)); 363 if (error) { 364 aprint_error_dev(sc->sc_dev, 365 "couldn't send CONFIG message (%d)\n", error); 366 } 367 368 memset(&msg, 0, sizeof(msg)); 369 msg.type = VC_AUDIO_MSG_TYPE_CONTROL; 370 msg.u.control.volume = vol2vc(sc->sc_hwvol[sc->sc_dest]); 371 msg.u.control.dest = sc->sc_dest; 372 error = vcaudio_msg_sync(sc, &msg, sizeof(msg)); 373 if (error) { 374 aprint_error_dev(sc->sc_dev, 375 "couldn't send CONTROL message (%d)\n", error); 376 } 377 378 vchi_service_release(sc->sc_service); 379 380 return 0; 381 } 382 383 static void 384 vcaudio_service_callback(void *priv, const VCHI_CALLBACK_REASON_T reason, 385 void *msg_handle) 386 { 387 struct vcaudio_softc *sc = priv; 388 VC_AUDIO_MSG_T msg; 389 int32_t msglen = 0; 390 int error; 391 void (*intr)(void *) = NULL; 392 void *intrarg = NULL; 393 394 if (sc == NULL || reason != VCHI_CALLBACK_MSG_AVAILABLE) 395 return; 396 397 memset(&msg, 0, sizeof(msg)); 398 error = vchi_msg_dequeue(sc->sc_service, &msg, sizeof(msg), &msglen, 399 VCHI_FLAGS_NONE); 400 if (error) { 401 device_printf(sc->sc_dev, "couldn't dequeue msg (%d)\n", 402 error); 403 return; 404 } 405 406 switch (msg.type) { 407 case VC_AUDIO_MSG_TYPE_RESULT: 408 mutex_enter(&sc->sc_msglock); 409 sc->sc_success = msg.u.result.success; 410 sc->sc_msgdone = true; 411 cv_broadcast(&sc->sc_msgcv); 412 mutex_exit(&sc->sc_msglock); 413 break; 414 415 case VC_AUDIO_MSG_TYPE_COMPLETE: 416 intr = msg.u.complete.callback; 417 intrarg = msg.u.complete.cookie; 418 if (intr && intrarg) { 419 int count = msg.u.complete.count & 0xffff; 420 int perr = (msg.u.complete.count & __BIT(30)) != 0; 421 bool sched = false; 422 423 mutex_enter(&sc->sc_intr_lock); 424 425 if (count > 0) { 426 sc->sc_pbytes += count; 427 } 428 if (perr && sc->sc_started) { 429 #ifdef VCAUDIO_DEBUG 430 device_printf(sc->sc_dev, "underrun\n"); 431 #endif 432 sched = true; 433 } 434 if (sc->sc_pbytes >= sc->sc_pblksize) { 435 sc->sc_pbytes -= sc->sc_pblksize; 436 sched = true; 437 } 438 439 if (sched && sc->sc_pint) { 440 intr(intrarg); 441 sc->sc_abytes += sc->sc_pblksize; 442 cv_signal(&sc->sc_datacv); 443 } 444 mutex_exit(&sc->sc_intr_lock); 445 } 446 break; 447 default: 448 break; 449 } 450 } 451 452 static void 453 vcaudio_worker(void *priv) 454 { 455 struct vcaudio_softc *sc = priv; 456 VC_AUDIO_MSG_T msg; 457 void (*intr)(void *); 458 void *intrarg; 459 void *block; 460 int error, resid, off, nb, count; 461 462 mutex_enter(&sc->sc_intr_lock); 463 464 while (true) { 465 intr = sc->sc_pint; 466 intrarg = sc->sc_pintarg; 467 468 if (intr == NULL || intrarg == NULL) { 469 cv_wait_sig(&sc->sc_datacv, &sc->sc_intr_lock); 470 continue; 471 } 472 473 KASSERT(sc->sc_pblksize != 0); 474 475 if (sc->sc_abytes < sc->sc_pblksize) { 476 cv_wait_sig(&sc->sc_datacv, &sc->sc_intr_lock); 477 continue; 478 } 479 count = sc->sc_pblksize; 480 481 memset(&msg, 0, sizeof(msg)); 482 msg.type = VC_AUDIO_MSG_TYPE_WRITE; 483 msg.u.write.max_packet = VCAUDIO_MSGSIZE; 484 msg.u.write.count = count; 485 msg.u.write.callback = intr; 486 msg.u.write.cookie = intrarg; 487 msg.u.write.silence = 0; 488 489 block = (uint8_t *)sc->sc_pstart + sc->sc_ppos; 490 resid = count; 491 off = 0; 492 493 vchi_service_use(sc->sc_service); 494 495 error = vchi_msg_queue(sc->sc_service, &msg, sizeof(msg), 496 VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL); 497 if (error) { 498 printf("%s: failed to write (%d)\n", __func__, error); 499 goto done; 500 } 501 502 while (resid > 0) { 503 nb = min(resid, msg.u.write.max_packet); 504 error = vchi_msg_queue(sc->sc_service, 505 (char *)block + off, nb, 506 VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL); 507 if (error) { 508 /* XXX What to do here? */ 509 device_printf(sc->sc_dev, 510 "failed to queue data (%d)\n", error); 511 goto done; 512 } 513 off += nb; 514 resid -= nb; 515 } 516 517 sc->sc_abytes -= count; 518 sc->sc_ppos += count; 519 if ((uint8_t *)sc->sc_pstart + sc->sc_ppos >= 520 (uint8_t *)sc->sc_pend) 521 sc->sc_ppos = 0; 522 523 if (!sc->sc_started) { 524 ++sc->sc_pblkcnt; 525 526 if (sc->sc_pblkcnt == VCAUDIO_PREFILLCOUNT) { 527 528 memset(&msg, 0, sizeof(msg)); 529 msg.type = VC_AUDIO_MSG_TYPE_START; 530 error = vchi_msg_queue(sc->sc_service, &msg, 531 sizeof(msg), VCHI_FLAGS_BLOCK_UNTIL_QUEUED, 532 NULL); 533 if (error) { 534 device_printf(sc->sc_dev, 535 "failed to start (%d)\n", error); 536 goto done; 537 } 538 sc->sc_started = true; 539 sc->sc_pbytes = 0; 540 } else { 541 intr(intrarg); 542 sc->sc_abytes += sc->sc_pblksize; 543 } 544 } 545 546 done: 547 vchi_service_release(sc->sc_service); 548 } 549 } 550 551 static int 552 vcaudio_msg_sync(struct vcaudio_softc *sc, VC_AUDIO_MSG_T *msg, size_t msglen) 553 { 554 int error = 0; 555 556 mutex_enter(&sc->sc_msglock); 557 558 sc->sc_success = -1; 559 sc->sc_msgdone = false; 560 561 error = vchi_msg_queue(sc->sc_service, msg, msglen, 562 VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL); 563 if (error) { 564 printf("%s: failed to queue message (%d)\n", __func__, error); 565 goto done; 566 } 567 568 while (!sc->sc_msgdone) { 569 error = cv_wait_sig(&sc->sc_msgcv, &sc->sc_msglock); 570 if (error) 571 break; 572 } 573 if (sc->sc_success != 0) 574 error = EIO; 575 done: 576 mutex_exit(&sc->sc_msglock); 577 578 return error; 579 } 580 581 static int 582 vcaudio_open(void *priv, int flags) 583 { 584 return 0; 585 } 586 587 static void 588 vcaudio_close(void *priv) 589 { 590 } 591 592 static int 593 vcaudio_query_encoding(void *priv, struct audio_encoding *ae) 594 { 595 struct vcaudio_softc *sc = priv; 596 597 return auconv_query_encoding(sc->sc_encodings, ae); 598 } 599 600 static int 601 vcaudio_set_params(void *priv, int setmode, int usemode, 602 audio_params_t *play, audio_params_t *rec, 603 stream_filter_list_t *pfil, stream_filter_list_t *rfil) 604 { 605 struct vcaudio_softc *sc = priv; 606 int index; 607 608 if (play && (setmode & AUMODE_PLAY)) { 609 index = auconv_set_converter(&sc->sc_format, 1, 610 AUMODE_PLAY, play, true, pfil); 611 if (index < 0) 612 return EINVAL; 613 if (pfil->req_size > 0) 614 play = &pfil->filters[0].param; 615 pfil->prepend(pfil, vcaudio_swvol_filter, play); 616 } 617 618 return 0; 619 } 620 621 static int 622 vcaudio_halt_output(void *priv) 623 { 624 struct vcaudio_softc *sc = priv; 625 VC_AUDIO_MSG_T msg; 626 int error = 0; 627 628 KASSERT(mutex_owned(&sc->sc_intr_lock)); 629 630 vchi_service_use(sc->sc_service); 631 memset(&msg, 0, sizeof(msg)); 632 msg.type = VC_AUDIO_MSG_TYPE_STOP; 633 msg.u.stop.draining = 0; 634 error = vchi_msg_queue(sc->sc_service, &msg, sizeof(msg), 635 VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL); 636 if (error) { 637 device_printf(sc->sc_dev, "couldn't send STOP message (%d)\n", 638 error); 639 } 640 vchi_service_release(sc->sc_service); 641 642 sc->sc_pint = NULL; 643 sc->sc_pintarg = NULL; 644 sc->sc_started = false; 645 646 #ifdef VCAUDIO_DEBUG 647 device_printf(sc->sc_dev, "halting output\n"); 648 #endif 649 650 return error; 651 } 652 653 static int 654 vcaudio_halt_input(void *priv) 655 { 656 return EINVAL; 657 } 658 659 static int 660 vcaudio_set_volume(struct vcaudio_softc *sc, enum vcaudio_dest dest, 661 int hwvol) 662 { 663 VC_AUDIO_MSG_T msg; 664 int error; 665 666 sc->sc_hwvol[dest] = hwvol; 667 if (dest != sc->sc_dest) 668 return 0; 669 670 vchi_service_use(sc->sc_service); 671 672 memset(&msg, 0, sizeof(msg)); 673 msg.type = VC_AUDIO_MSG_TYPE_CONTROL; 674 msg.u.control.volume = vol2vc(hwvol); 675 msg.u.control.dest = dest; 676 677 error = vcaudio_msg_sync(sc, &msg, sizeof(msg)); 678 if (error) { 679 device_printf(sc->sc_dev, 680 "couldn't send CONTROL message (%d)\n", error); 681 } 682 683 vchi_service_release(sc->sc_service); 684 685 return error; 686 } 687 688 static int 689 vcaudio_set_port(void *priv, mixer_ctrl_t *mc) 690 { 691 struct vcaudio_softc *sc = priv; 692 693 switch (mc->dev) { 694 case VCAUDIO_OUTPUT_MASTER_VOLUME: 695 case VCAUDIO_INPUT_DAC_VOLUME: 696 sc->sc_swvol = mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT]; 697 return 0; 698 case VCAUDIO_OUTPUT_AUTO_VOLUME: 699 return vcaudio_set_volume(sc, VCAUDIO_DEST_AUTO, 700 mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT]); 701 case VCAUDIO_OUTPUT_HEADPHONE_VOLUME: 702 return vcaudio_set_volume(sc, VCAUDIO_DEST_HP, 703 mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT]); 704 case VCAUDIO_OUTPUT_HDMI_VOLUME: 705 return vcaudio_set_volume(sc, VCAUDIO_DEST_HDMI, 706 mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT]); 707 case VCAUDIO_OUTPUT_SELECT: 708 if (mc->un.ord < 0 || mc->un.ord > 2) 709 return EINVAL; 710 sc->sc_dest = mc->un.ord; 711 return vcaudio_set_volume(sc, mc->un.ord, 712 sc->sc_hwvol[mc->un.ord]); 713 } 714 return ENXIO; 715 } 716 717 static int 718 vcaudio_get_port(void *priv, mixer_ctrl_t *mc) 719 { 720 struct vcaudio_softc *sc = priv; 721 722 switch (mc->dev) { 723 case VCAUDIO_OUTPUT_MASTER_VOLUME: 724 case VCAUDIO_INPUT_DAC_VOLUME: 725 mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT] = 726 mc->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = 727 sc->sc_swvol; 728 return 0; 729 case VCAUDIO_OUTPUT_AUTO_VOLUME: 730 mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT] = 731 mc->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = 732 sc->sc_hwvol[VCAUDIO_DEST_AUTO]; 733 return 0; 734 case VCAUDIO_OUTPUT_HEADPHONE_VOLUME: 735 mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT] = 736 mc->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = 737 sc->sc_hwvol[VCAUDIO_DEST_HP]; 738 return 0; 739 case VCAUDIO_OUTPUT_HDMI_VOLUME: 740 mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT] = 741 mc->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = 742 sc->sc_hwvol[VCAUDIO_DEST_HDMI]; 743 return 0; 744 case VCAUDIO_OUTPUT_SELECT: 745 mc->un.ord = sc->sc_dest; 746 return 0; 747 } 748 return ENXIO; 749 } 750 751 static int 752 vcaudio_query_devinfo(void *priv, mixer_devinfo_t *di) 753 { 754 switch (di->index) { 755 case VCAUDIO_OUTPUT_CLASS: 756 di->mixer_class = VCAUDIO_OUTPUT_CLASS; 757 strcpy(di->label.name, AudioCoutputs); 758 di->type = AUDIO_MIXER_CLASS; 759 di->next = di->prev = AUDIO_MIXER_LAST; 760 return 0; 761 case VCAUDIO_INPUT_CLASS: 762 di->mixer_class = VCAUDIO_INPUT_CLASS; 763 strcpy(di->label.name, AudioCinputs); 764 di->type = AUDIO_MIXER_CLASS; 765 di->next = di->prev = AUDIO_MIXER_LAST; 766 return 0; 767 case VCAUDIO_OUTPUT_MASTER_VOLUME: 768 di->mixer_class = VCAUDIO_OUTPUT_CLASS; 769 strcpy(di->label.name, AudioNmaster); 770 di->type = AUDIO_MIXER_VALUE; 771 di->next = di->prev = AUDIO_MIXER_LAST; 772 di->un.v.num_channels = 2; 773 strcpy(di->un.v.units.name, AudioNvolume); 774 return 0; 775 case VCAUDIO_OUTPUT_AUTO_VOLUME: 776 di->mixer_class = VCAUDIO_OUTPUT_CLASS; 777 strcpy(di->label.name, "auto"); 778 di->type = AUDIO_MIXER_VALUE; 779 di->next = di->prev = AUDIO_MIXER_LAST; 780 di->un.v.num_channels = 2; 781 di->un.v.delta = 13; 782 strcpy(di->un.v.units.name, AudioNvolume); 783 return 0; 784 case VCAUDIO_OUTPUT_HEADPHONE_VOLUME: 785 di->mixer_class = VCAUDIO_OUTPUT_CLASS; 786 strcpy(di->label.name, AudioNheadphone); 787 di->type = AUDIO_MIXER_VALUE; 788 di->next = di->prev = AUDIO_MIXER_LAST; 789 di->un.v.num_channels = 2; 790 di->un.v.delta = 13; 791 strcpy(di->un.v.units.name, AudioNvolume); 792 return 0; 793 case VCAUDIO_OUTPUT_HDMI_VOLUME: 794 di->mixer_class = VCAUDIO_OUTPUT_CLASS; 795 strcpy(di->label.name, "hdmi"); 796 di->type = AUDIO_MIXER_VALUE; 797 di->next = di->prev = AUDIO_MIXER_LAST; 798 di->un.v.num_channels = 2; 799 di->un.v.delta = 13; 800 strcpy(di->un.v.units.name, AudioNvolume); 801 return 0; 802 case VCAUDIO_INPUT_DAC_VOLUME: 803 di->mixer_class = VCAUDIO_INPUT_CLASS; 804 strcpy(di->label.name, AudioNdac); 805 di->type = AUDIO_MIXER_VALUE; 806 di->next = di->prev = AUDIO_MIXER_LAST; 807 di->un.v.num_channels = 2; 808 strcpy(di->un.v.units.name, AudioNvolume); 809 return 0; 810 case VCAUDIO_OUTPUT_SELECT: 811 di->mixer_class = VCAUDIO_OUTPUT_CLASS; 812 strcpy(di->label.name, AudioNselect); 813 di->type = AUDIO_MIXER_ENUM; 814 di->next = di->prev = AUDIO_MIXER_LAST; 815 di->un.e.num_mem = 3; 816 di->un.e.member[0].ord = 0; 817 strcpy(di->un.e.member[0].label.name, "auto"); 818 di->un.e.member[1].ord = 1; 819 strcpy(di->un.e.member[1].label.name, AudioNheadphone); 820 di->un.e.member[2].ord = 2; 821 strcpy(di->un.e.member[2].label.name, "hdmi"); 822 return 0; 823 } 824 825 return ENXIO; 826 } 827 828 static int 829 vcaudio_getdev(void *priv, struct audio_device *audiodev) 830 { 831 struct vcaudio_softc *sc = priv; 832 833 snprintf(audiodev->name, sizeof(audiodev->name), "vchiq auds"); 834 snprintf(audiodev->version, sizeof(audiodev->version), 835 "%d", sc->sc_peer_version); 836 snprintf(audiodev->config, sizeof(audiodev->config), "vcaudio"); 837 838 return 0; 839 } 840 841 static int 842 vcaudio_get_props(void *priv) 843 { 844 return AUDIO_PROP_PLAYBACK|AUDIO_PROP_CAPTURE|AUDIO_PROP_INDEPENDENT; 845 } 846 847 static int 848 vcaudio_round_blocksize(void *priv, int bs, int mode, 849 const audio_params_t *params) 850 { 851 return VCAUDIO_BLOCKSIZE; 852 } 853 854 static size_t 855 vcaudio_round_buffersize(void *priv, int direction, size_t bufsize) 856 { 857 858 return VCAUDIO_BUFFERSIZE; 859 } 860 861 static int 862 vcaudio_trigger_output(void *priv, void *start, void *end, int blksize, 863 void (*intr)(void *), void *intrarg, const audio_params_t *params) 864 { 865 struct vcaudio_softc *sc = priv; 866 867 ASSERT_SLEEPABLE(); 868 KASSERT(mutex_owned(&sc->sc_intr_lock)); 869 870 sc->sc_pparam = *params; 871 sc->sc_pint = intr; 872 sc->sc_pintarg = intrarg; 873 sc->sc_ppos = 0; 874 sc->sc_pstart = start; 875 sc->sc_pend = end; 876 sc->sc_pblksize = blksize; 877 sc->sc_pblkcnt = 0; 878 sc->sc_pbytes = 0; 879 sc->sc_abytes = blksize; 880 881 cv_signal(&sc->sc_datacv); 882 883 return 0; 884 } 885 886 static int 887 vcaudio_trigger_input(void *priv, void *start, void *end, int blksize, 888 void (*intr)(void *), void *intrarg, const audio_params_t *params) 889 { 890 return EINVAL; 891 } 892 893 static void 894 vcaudio_get_locks(void *priv, kmutex_t **intr, kmutex_t **thread) 895 { 896 struct vcaudio_softc *sc = priv; 897 898 *intr = &sc->sc_intr_lock; 899 *thread = &sc->sc_lock; 900 } 901 902 static stream_filter_t * 903 vcaudio_swvol_filter(struct audio_softc *asc, 904 const audio_params_t *from, const audio_params_t *to) 905 { 906 auvolconv_filter_t *this; 907 device_t dev = audio_get_device(asc); 908 struct vcaudio_softc *sc = device_private(dev); 909 910 this = kmem_alloc(sizeof(auvolconv_filter_t), KM_SLEEP); 911 this->base.base.fetch_to = auvolconv_slinear16_le_fetch_to; 912 this->base.dtor = vcaudio_swvol_dtor; 913 this->base.set_fetcher = stream_filter_set_fetcher; 914 this->base.set_inputbuffer = stream_filter_set_inputbuffer; 915 this->vol = &sc->sc_swvol; 916 917 return (stream_filter_t *)this; 918 } 919 920 static void 921 vcaudio_swvol_dtor(stream_filter_t *this) 922 { 923 if (this) 924 kmem_free(this, sizeof(auvolconv_filter_t)); 925 } 926