1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2005-2009 Ariff Abdullah <ariff@FreeBSD.org> 5 * Portions Copyright (c) Ryan Beasley <ryan.beasley@gmail.com> - GSoC 2006 6 * Copyright (c) 1999 Cameron Grant <cg@FreeBSD.org> 7 * All rights reserved. 8 * Copyright (c) 2026 The FreeBSD Foundation 9 * 10 * Portions of this software were developed by Christos Margiolis 11 * <christos@FreeBSD.org> under sponsorship from the FreeBSD Foundation. 12 * 13 * Redistribution and use in source and binary forms, with or without 14 * modification, are permitted provided that the following conditions 15 * are met: 16 * 1. Redistributions of source code must retain the above copyright 17 * notice, this list of conditions and the following disclaimer. 18 * 2. Redistributions in binary form must reproduce the above copyright 19 * notice, this list of conditions and the following disclaimer in the 20 * documentation and/or other materials provided with the distribution. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 */ 34 35 #ifdef HAVE_KERNEL_OPTION_HEADERS 36 #include "opt_snd.h" 37 #endif 38 39 #include <dev/sound/pcm/sound.h> 40 41 #include "feeder_if.h" 42 #include "mixer_if.h" 43 44 static u_int16_t snd_mixerdefaults[SOUND_MIXER_NRDEVICES] = { 45 [SOUND_MIXER_VOLUME] = 75, 46 [SOUND_MIXER_BASS] = 50, 47 [SOUND_MIXER_TREBLE] = 50, 48 [SOUND_MIXER_SYNTH] = 75, 49 [SOUND_MIXER_PCM] = 75, 50 [SOUND_MIXER_SPEAKER] = 75, 51 [SOUND_MIXER_LINE] = 75, 52 [SOUND_MIXER_MIC] = 25, 53 [SOUND_MIXER_CD] = 75, 54 [SOUND_MIXER_IGAIN] = 0, 55 [SOUND_MIXER_LINE1] = 75, 56 [SOUND_MIXER_VIDEO] = 75, 57 [SOUND_MIXER_RECLEV] = 75, 58 [SOUND_MIXER_OGAIN] = 50, 59 [SOUND_MIXER_MONITOR] = 75, 60 }; 61 62 static char* snd_mixernames[SOUND_MIXER_NRDEVICES] = SOUND_DEVICE_NAMES; 63 64 static d_open_t mixer_open; 65 static d_close_t mixer_close; 66 static d_ioctl_t mixer_ioctl; 67 68 static struct cdevsw mixer_cdevsw = { 69 .d_version = D_VERSION, 70 .d_open = mixer_open, 71 .d_close = mixer_close, 72 .d_ioctl = mixer_ioctl, 73 .d_name = "mixer", 74 }; 75 76 static eventhandler_tag mixer_ehtag = NULL; 77 78 static struct cdev * 79 mixer_get_devt(device_t dev) 80 { 81 struct snddev_info *snddev; 82 83 snddev = device_get_softc(dev); 84 85 return snddev->mixer_dev; 86 } 87 88 static int 89 mixer_lookup(char *devname) 90 { 91 int i; 92 93 for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) 94 if (strncmp(devname, snd_mixernames[i], 95 strlen(snd_mixernames[i])) == 0) 96 return i; 97 return -1; 98 } 99 100 #define MIXER_SET_UNLOCK(x, y) do { \ 101 if ((y) != 0) \ 102 mtx_unlock(&(x)->lock); \ 103 } while (0) 104 105 #define MIXER_SET_LOCK(x, y) do { \ 106 if ((y) != 0) \ 107 mtx_lock(&(x)->lock); \ 108 } while (0) 109 110 static int 111 mixer_set_softpcmvol(struct snd_mixer *m, struct snddev_info *d, 112 u_int left, u_int right) 113 { 114 struct pcm_channel *c; 115 int dropmtx, acquiremtx; 116 117 if (!PCM_REGISTERED(d)) 118 return (EINVAL); 119 120 if (mtx_owned(&m->lock)) 121 dropmtx = 1; 122 else 123 dropmtx = 0; 124 125 if (!(d->flags & SD_F_MPSAFE) || mtx_owned(&d->lock) != 0) 126 acquiremtx = 0; 127 else 128 acquiremtx = 1; 129 130 /* 131 * Be careful here. If we're coming from cdev ioctl, it is OK to 132 * not doing locking AT ALL (except on individual channel) since 133 * we've been heavily guarded by pcm cv, or if we're still 134 * under Giant influence. Since we also have mix_* calls, we cannot 135 * assume such protection and just do the lock as usuall. 136 */ 137 MIXER_SET_UNLOCK(m, dropmtx); 138 MIXER_SET_LOCK(d, acquiremtx); 139 140 CHN_FOREACH(c, d, channels.pcm.busy) { 141 CHN_LOCK(c); 142 if (c->direction == PCMDIR_PLAY && 143 (c->feederflags & (1 << FEEDER_VOLUME))) 144 chn_setvolume_multi(c, SND_VOL_C_MASTER, left, right, 145 (left + right) >> 1); 146 CHN_UNLOCK(c); 147 } 148 149 MIXER_SET_UNLOCK(d, acquiremtx); 150 MIXER_SET_LOCK(m, dropmtx); 151 152 return (0); 153 } 154 155 static int 156 mixer_set_eq(struct snd_mixer *m, struct snddev_info *d, 157 u_int dev, u_int level) 158 { 159 struct pcm_channel *c; 160 struct pcm_feeder *f; 161 int tone, dropmtx, acquiremtx; 162 163 if (dev == SOUND_MIXER_TREBLE) 164 tone = FEEDEQ_TREBLE; 165 else if (dev == SOUND_MIXER_BASS) 166 tone = FEEDEQ_BASS; 167 else 168 return (EINVAL); 169 170 if (!PCM_REGISTERED(d)) 171 return (EINVAL); 172 173 if (mtx_owned(&m->lock)) 174 dropmtx = 1; 175 else 176 dropmtx = 0; 177 178 if (!(d->flags & SD_F_MPSAFE) || mtx_owned(&d->lock) != 0) 179 acquiremtx = 0; 180 else 181 acquiremtx = 1; 182 183 /* 184 * Be careful here. If we're coming from cdev ioctl, it is OK to 185 * not doing locking AT ALL (except on individual channel) since 186 * we've been heavily guarded by pcm cv, or if we're still 187 * under Giant influence. Since we also have mix_* calls, we cannot 188 * assume such protection and just do the lock as usuall. 189 */ 190 MIXER_SET_UNLOCK(m, dropmtx); 191 MIXER_SET_LOCK(d, acquiremtx); 192 193 CHN_FOREACH(c, d, channels.pcm.busy) { 194 CHN_LOCK(c); 195 f = feeder_find(c, FEEDER_EQ); 196 if (f != NULL) 197 (void)FEEDER_SET(f, tone, level); 198 CHN_UNLOCK(c); 199 } 200 201 MIXER_SET_UNLOCK(d, acquiremtx); 202 MIXER_SET_LOCK(m, dropmtx); 203 204 return (0); 205 } 206 207 static int 208 mixer_set(struct snd_mixer *m, u_int dev, u_int32_t muted, u_int lev) 209 { 210 struct snddev_info *d; 211 u_int l, r, tl, tr; 212 u_int32_t parent = SOUND_MIXER_NONE, child = 0; 213 u_int32_t realdev; 214 int i, dropmtx; 215 216 if (m == NULL || dev >= SOUND_MIXER_NRDEVICES || 217 (0 == (m->devs & (1 << dev)))) 218 return (-1); 219 220 l = min((lev & 0x00ff), 100); 221 r = min(((lev & 0xff00) >> 8), 100); 222 realdev = m->realdev[dev]; 223 224 d = device_get_softc(m->dev); 225 if (d == NULL) 226 return (-1); 227 228 /* It is safe to drop this mutex due to Giant. */ 229 if (!(d->flags & SD_F_MPSAFE) && mtx_owned(&m->lock) != 0) 230 dropmtx = 1; 231 else 232 dropmtx = 0; 233 234 /* Allow the volume to be "changed" while muted. */ 235 if (muted & (1 << dev)) { 236 m->level_muted[dev] = l | (r << 8); 237 return (0); 238 } 239 MIXER_SET_UNLOCK(m, dropmtx); 240 241 /* TODO: recursive handling */ 242 parent = m->parent[dev]; 243 if (parent >= SOUND_MIXER_NRDEVICES) 244 parent = SOUND_MIXER_NONE; 245 if (parent == SOUND_MIXER_NONE) 246 child = m->child[dev]; 247 248 if (parent != SOUND_MIXER_NONE) { 249 tl = (l * (m->level[parent] & 0x00ff)) / 100; 250 tr = (r * ((m->level[parent] & 0xff00) >> 8)) / 100; 251 if (dev == SOUND_MIXER_PCM && (d->flags & SD_F_SOFTPCMVOL)) 252 (void)mixer_set_softpcmvol(m, d, tl, tr); 253 else if (realdev != SOUND_MIXER_NONE && 254 MIXER_SET(m, realdev, tl, tr) < 0) { 255 MIXER_SET_LOCK(m, dropmtx); 256 return (-1); 257 } 258 } else if (child != 0) { 259 for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) { 260 if (!(child & (1 << i)) || m->parent[i] != dev) 261 continue; 262 realdev = m->realdev[i]; 263 tl = (l * (m->level[i] & 0x00ff)) / 100; 264 tr = (r * ((m->level[i] & 0xff00) >> 8)) / 100; 265 if (i == SOUND_MIXER_PCM && 266 (d->flags & SD_F_SOFTPCMVOL)) 267 (void)mixer_set_softpcmvol(m, d, tl, tr); 268 else if (realdev != SOUND_MIXER_NONE) 269 MIXER_SET(m, realdev, tl, tr); 270 } 271 realdev = m->realdev[dev]; 272 if (realdev != SOUND_MIXER_NONE && 273 MIXER_SET(m, realdev, l, r) < 0) { 274 MIXER_SET_LOCK(m, dropmtx); 275 return (-1); 276 } 277 } else { 278 if (dev == SOUND_MIXER_PCM && (d->flags & SD_F_SOFTPCMVOL)) 279 (void)mixer_set_softpcmvol(m, d, l, r); 280 else if ((dev == SOUND_MIXER_TREBLE || 281 dev == SOUND_MIXER_BASS) && (d->flags & SD_F_EQ)) 282 (void)mixer_set_eq(m, d, dev, (l + r) >> 1); 283 else if (realdev != SOUND_MIXER_NONE && 284 MIXER_SET(m, realdev, l, r) < 0) { 285 MIXER_SET_LOCK(m, dropmtx); 286 return (-1); 287 } 288 } 289 290 MIXER_SET_LOCK(m, dropmtx); 291 292 m->level[dev] = l | (r << 8); 293 m->modify_counter++; 294 295 return (0); 296 } 297 298 static int 299 mixer_get(struct snd_mixer *mixer, int dev) 300 { 301 if ((dev < SOUND_MIXER_NRDEVICES) && (mixer->devs & (1 << dev))) { 302 if (mixer->mutedevs & (1 << dev)) 303 return (mixer->level_muted[dev]); 304 else 305 return (mixer->level[dev]); 306 } else { 307 return (-1); 308 } 309 } 310 311 void 312 mix_setmutedevs(struct snd_mixer *mixer, u_int32_t mutedevs) 313 { 314 u_int32_t delta; 315 316 /* Filter out invalid values. */ 317 mutedevs &= mixer->devs; 318 delta = (mixer->mutedevs ^ mutedevs) & mixer->devs; 319 mixer->mutedevs = mutedevs; 320 321 for (int i = 0; i < SOUND_MIXER_NRDEVICES; i++) { 322 if (!(delta & (1 << i))) 323 continue; 324 if (mutedevs & (1 << i)) { 325 mixer->level_muted[i] = mixer->level[i]; 326 mixer_set(mixer, i, 0, 0); 327 } else { 328 mixer_set(mixer, i, 0, mixer->level_muted[i]); 329 } 330 } 331 } 332 333 static int 334 mixer_setrecsrc(struct snd_mixer *mixer, u_int32_t src) 335 { 336 struct snddev_info *d; 337 u_int32_t recsrc; 338 int dropmtx; 339 340 d = device_get_softc(mixer->dev); 341 if (d == NULL) 342 return -1; 343 if (!(d->flags & SD_F_MPSAFE) && mtx_owned(&mixer->lock) != 0) 344 dropmtx = 1; 345 else 346 dropmtx = 0; 347 src &= mixer->recdevs; 348 if (src == 0) 349 src = mixer->recdevs & SOUND_MASK_MIC; 350 if (src == 0) 351 src = mixer->recdevs & SOUND_MASK_MONITOR; 352 if (src == 0) 353 src = mixer->recdevs & SOUND_MASK_LINE; 354 if (src == 0 && mixer->recdevs != 0) 355 src = (1 << (ffs(mixer->recdevs) - 1)); 356 /* It is safe to drop this mutex due to Giant. */ 357 MIXER_SET_UNLOCK(mixer, dropmtx); 358 recsrc = MIXER_SETRECSRC(mixer, src); 359 MIXER_SET_LOCK(mixer, dropmtx); 360 361 mixer->recsrc = recsrc; 362 363 return 0; 364 } 365 366 static int 367 mixer_getrecsrc(struct snd_mixer *mixer) 368 { 369 return mixer->recsrc; 370 } 371 372 /** 373 * @brief Retrieve the route number of the current recording device 374 * 375 * OSSv4 assigns routing numbers to recording devices, unlike the previous 376 * API which relied on a fixed table of device numbers and names. This 377 * function returns the routing number of the device currently selected 378 * for recording. 379 * 380 * For now, this function is kind of a goofy compatibility stub atop the 381 * existing sound system. (For example, in theory, the old sound system 382 * allows multiple recording devices to be specified via a bitmask.) 383 * 384 * @param m mixer context container thing 385 * 386 * @retval 0 success 387 * @retval EIDRM no recording device found (generally not possible) 388 * @todo Ask about error code 389 */ 390 static int 391 mixer_get_recroute(struct snd_mixer *m, int *route) 392 { 393 int i, cnt; 394 395 cnt = 0; 396 397 for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) { 398 /** @todo can user set a multi-device mask? (== or &?) */ 399 if ((1 << i) == m->recsrc) 400 break; 401 if ((1 << i) & m->recdevs) 402 ++cnt; 403 } 404 405 if (i == SOUND_MIXER_NRDEVICES) 406 return EIDRM; 407 408 *route = cnt; 409 return 0; 410 } 411 412 /** 413 * @brief Select a device for recording 414 * 415 * This function sets a recording source based on a recording device's 416 * routing number. Said number is translated to an old school recdev 417 * mask and passed over mixer_setrecsrc. 418 * 419 * @param m mixer context container thing 420 * 421 * @retval 0 success(?) 422 * @retval EINVAL User specified an invalid device number 423 * @retval otherwise error from mixer_setrecsrc 424 */ 425 static int 426 mixer_set_recroute(struct snd_mixer *m, int route) 427 { 428 int i, cnt, ret; 429 430 ret = 0; 431 cnt = 0; 432 433 for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) { 434 if ((1 << i) & m->recdevs) { 435 if (route == cnt) 436 break; 437 ++cnt; 438 } 439 } 440 441 if (i == SOUND_MIXER_NRDEVICES) 442 ret = EINVAL; 443 else 444 ret = mixer_setrecsrc(m, (1 << i)); 445 446 return ret; 447 } 448 449 void 450 mix_setdevs(struct snd_mixer *m, u_int32_t v) 451 { 452 struct snddev_info *d; 453 int i; 454 455 if (m == NULL) 456 return; 457 458 d = device_get_softc(m->dev); 459 if (d != NULL && (d->flags & SD_F_SOFTPCMVOL)) 460 v |= SOUND_MASK_PCM; 461 v |= SOUND_MASK_TREBLE | SOUND_MASK_BASS; 462 for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) { 463 if (m->parent[i] < SOUND_MIXER_NRDEVICES) 464 v |= 1 << m->parent[i]; 465 v |= m->child[i]; 466 } 467 m->devs = v; 468 } 469 470 /** 471 * @brief Record mask of available recording devices 472 * 473 * Calling functions are responsible for defining the mask of available 474 * recording devices. This function records that value in a structure 475 * used by the rest of the mixer code. 476 * 477 * @param m mixer device context container thing 478 * @param v mask of recording devices 479 */ 480 void 481 mix_setrecdevs(struct snd_mixer *m, u_int32_t v) 482 { 483 m->recdevs = v; 484 } 485 486 void 487 mix_setparentchild(struct snd_mixer *m, u_int32_t parent, u_int32_t childs) 488 { 489 u_int32_t mask = 0; 490 int i; 491 492 if (m == NULL || parent >= SOUND_MIXER_NRDEVICES) 493 return; 494 for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) { 495 if (i == parent) 496 continue; 497 if (childs & (1 << i)) { 498 mask |= 1 << i; 499 if (m->parent[i] < SOUND_MIXER_NRDEVICES) 500 m->child[m->parent[i]] &= ~(1 << i); 501 m->parent[i] = parent; 502 m->child[i] = 0; 503 } 504 } 505 mask &= ~(1 << parent); 506 m->child[parent] = mask; 507 } 508 509 void 510 mix_setrealdev(struct snd_mixer *m, u_int32_t dev, u_int32_t realdev) 511 { 512 if (m == NULL || dev >= SOUND_MIXER_NRDEVICES || 513 !(realdev == SOUND_MIXER_NONE || realdev < SOUND_MIXER_NRDEVICES)) 514 return; 515 m->realdev[dev] = realdev; 516 } 517 518 u_int32_t 519 mix_getparent(struct snd_mixer *m, u_int32_t dev) 520 { 521 if (m == NULL || dev >= SOUND_MIXER_NRDEVICES) 522 return SOUND_MIXER_NONE; 523 return m->parent[dev]; 524 } 525 526 u_int32_t 527 mix_getdevs(struct snd_mixer *m) 528 { 529 return m->devs; 530 } 531 532 u_int32_t 533 mix_getmutedevs(struct snd_mixer *m) 534 { 535 return m->mutedevs; 536 } 537 538 u_int32_t 539 mix_getrecdevs(struct snd_mixer *m) 540 { 541 return m->recdevs; 542 } 543 544 void * 545 mix_getdevinfo(struct snd_mixer *m) 546 { 547 return m->devinfo; 548 } 549 550 static struct snd_mixer * 551 mixer_obj_create(device_t dev, kobj_class_t cls, void *devinfo, 552 int type, const char *desc) 553 { 554 struct snd_mixer *m; 555 size_t i; 556 557 KASSERT(dev != NULL && cls != NULL && devinfo != NULL, 558 ("%s(): NULL data dev=%p cls=%p devinfo=%p", 559 __func__, dev, cls, devinfo)); 560 KASSERT(type == MIXER_TYPE_PRIMARY || type == MIXER_TYPE_SECONDARY, 561 ("invalid mixer type=%d", type)); 562 563 m = (struct snd_mixer *)kobj_create(cls, M_DEVBUF, M_WAITOK | M_ZERO); 564 snprintf(m->name, sizeof(m->name), "%s:mixer", 565 device_get_nameunit(dev)); 566 if (desc != NULL) { 567 strlcat(m->name, ":", sizeof(m->name)); 568 strlcat(m->name, desc, sizeof(m->name)); 569 } 570 mtx_init(&m->lock, m->name, (type == MIXER_TYPE_PRIMARY) ? 571 "primary pcm mixer" : "secondary pcm mixer", MTX_DEF); 572 m->type = type; 573 m->devinfo = devinfo; 574 m->dev = dev; 575 for (i = 0; i < nitems(m->parent); i++) { 576 m->parent[i] = SOUND_MIXER_NONE; 577 m->child[i] = 0; 578 m->realdev[i] = i; 579 } 580 581 if (MIXER_INIT(m)) { 582 mtx_destroy(&m->lock); 583 kobj_delete((kobj_t)m, M_DEVBUF); 584 return (NULL); 585 } 586 587 return (m); 588 } 589 590 int 591 mixer_delete(struct snd_mixer *m) 592 { 593 KASSERT(m != NULL, ("NULL snd_mixer")); 594 KASSERT(m->type == MIXER_TYPE_SECONDARY, 595 ("%s(): illegal mixer type=%d", __func__, m->type)); 596 597 /* mixer uninit can sleep --hps */ 598 599 MIXER_UNINIT(m); 600 601 mtx_destroy(&m->lock); 602 kobj_delete((kobj_t)m, M_DEVBUF); 603 604 return (0); 605 } 606 607 struct snd_mixer * 608 mixer_create(device_t dev, kobj_class_t cls, void *devinfo, const char *desc) 609 { 610 return (mixer_obj_create(dev, cls, devinfo, MIXER_TYPE_SECONDARY, desc)); 611 } 612 613 int 614 mixer_init(device_t dev, kobj_class_t cls, void *devinfo) 615 { 616 struct snddev_info *snddev; 617 struct snd_mixer *m; 618 u_int16_t v; 619 struct cdev *pdev; 620 const char *name; 621 int i, unit, val; 622 623 snddev = device_get_softc(dev); 624 if (snddev == NULL) 625 return (-1); 626 627 name = device_get_name(dev); 628 unit = device_get_unit(dev); 629 630 m = mixer_obj_create(dev, cls, devinfo, MIXER_TYPE_PRIMARY, NULL); 631 if (m == NULL) 632 return (-1); 633 634 for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) { 635 v = snd_mixerdefaults[i]; 636 637 if (resource_int_value(name, unit, snd_mixernames[i], 638 &val) == 0) { 639 if (val >= 0 && val <= 100) { 640 v = (u_int16_t) val; 641 } 642 } 643 644 mixer_set(m, i, 0, v | (v << 8)); 645 } 646 647 mixer_setrecsrc(m, 0); /* Set default input. */ 648 649 pdev = make_dev(&mixer_cdevsw, 0, UID_ROOT, GID_AUDIO, 0660, "mixer%d", 650 unit); 651 pdev->si_drv1 = m; 652 snddev->mixer_dev = pdev; 653 654 if (bootverbose) { 655 for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) { 656 if (!(m->devs & (1 << i))) 657 continue; 658 if (m->realdev[i] != i) { 659 device_printf(dev, "Mixer \"%s\" -> \"%s\":", 660 snd_mixernames[i], 661 (m->realdev[i] < SOUND_MIXER_NRDEVICES) ? 662 snd_mixernames[m->realdev[i]] : "none"); 663 } else { 664 device_printf(dev, "Mixer \"%s\":", 665 snd_mixernames[i]); 666 } 667 if (m->parent[i] < SOUND_MIXER_NRDEVICES) 668 printf(" parent=\"%s\"", 669 snd_mixernames[m->parent[i]]); 670 if (m->child[i] != 0) 671 printf(" child=0x%08x", m->child[i]); 672 printf("\n"); 673 } 674 if (snddev->flags & SD_F_SOFTPCMVOL) 675 device_printf(dev, "Soft PCM mixer ENABLED\n"); 676 device_printf(dev, "EQ Treble/Bass ENABLED\n"); 677 } 678 679 return (0); 680 } 681 682 int 683 mixer_uninit(device_t dev) 684 { 685 int i; 686 struct snddev_info *d; 687 struct snd_mixer *m; 688 struct cdev *pdev; 689 690 d = device_get_softc(dev); 691 pdev = mixer_get_devt(dev); 692 if (d == NULL || pdev == NULL || pdev->si_drv1 == NULL) 693 return EBADF; 694 695 m = pdev->si_drv1; 696 KASSERT(m != NULL, ("NULL snd_mixer")); 697 KASSERT(m->type == MIXER_TYPE_PRIMARY, 698 ("%s(): illegal mixer type=%d", __func__, m->type)); 699 700 pdev->si_drv1 = NULL; 701 destroy_dev(pdev); 702 703 mtx_lock(&m->lock); 704 705 for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) 706 mixer_set(m, i, 0, 0); 707 708 mixer_setrecsrc(m, SOUND_MASK_MIC); 709 710 mtx_unlock(&m->lock); 711 712 /* mixer uninit can sleep --hps */ 713 714 MIXER_UNINIT(m); 715 716 mtx_destroy(&m->lock); 717 kobj_delete((kobj_t)m, M_DEVBUF); 718 719 d->mixer_dev = NULL; 720 721 return 0; 722 } 723 724 int 725 mixer_reinit(device_t dev) 726 { 727 struct snd_mixer *m; 728 struct cdev *pdev; 729 int i; 730 731 pdev = mixer_get_devt(dev); 732 m = pdev->si_drv1; 733 mtx_lock(&m->lock); 734 735 i = MIXER_REINIT(m); 736 if (i) { 737 mtx_unlock(&m->lock); 738 return i; 739 } 740 741 for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) { 742 if (m->mutedevs & (1 << i)) 743 mixer_set(m, i, 0, 0); 744 else 745 mixer_set(m, i, 0, m->level[i]); 746 } 747 748 mixer_setrecsrc(m, m->recsrc); 749 mtx_unlock(&m->lock); 750 751 return 0; 752 } 753 754 static int 755 sysctl_hw_snd_hwvol_mixer(SYSCTL_HANDLER_ARGS) 756 { 757 char devname[32]; 758 int error, dev; 759 struct snd_mixer *m; 760 761 m = oidp->oid_arg1; 762 mtx_lock(&m->lock); 763 strlcpy(devname, snd_mixernames[m->hwvol_mixer], sizeof(devname)); 764 mtx_unlock(&m->lock); 765 error = sysctl_handle_string(oidp, &devname[0], sizeof(devname), req); 766 mtx_lock(&m->lock); 767 if (error == 0 && req->newptr != NULL) { 768 dev = mixer_lookup(devname); 769 if (dev == -1) { 770 mtx_unlock(&m->lock); 771 return EINVAL; 772 } else { 773 m->hwvol_mixer = dev; 774 } 775 } 776 mtx_unlock(&m->lock); 777 return error; 778 } 779 780 int 781 mixer_hwvol_init(device_t dev) 782 { 783 struct snd_mixer *m; 784 struct cdev *pdev; 785 786 pdev = mixer_get_devt(dev); 787 m = pdev->si_drv1; 788 789 m->hwvol_mixer = SOUND_MIXER_VOLUME; 790 m->hwvol_step = 5; 791 SYSCTL_ADD_INT(device_get_sysctl_ctx(dev), 792 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 793 OID_AUTO, "hwvol_step", CTLFLAG_RWTUN, &m->hwvol_step, 0, ""); 794 SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 795 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, 796 "hwvol_mixer", CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE, 797 m, 0, sysctl_hw_snd_hwvol_mixer, "A", ""); 798 return 0; 799 } 800 801 void 802 mixer_hwvol_mute_locked(struct snd_mixer *m) 803 { 804 mix_setmutedevs(m, m->mutedevs ^ (1 << m->hwvol_mixer)); 805 } 806 807 void 808 mixer_hwvol_mute(device_t dev) 809 { 810 struct snd_mixer *m; 811 struct cdev *pdev; 812 813 pdev = mixer_get_devt(dev); 814 m = pdev->si_drv1; 815 mtx_lock(&m->lock); 816 mixer_hwvol_mute_locked(m); 817 mtx_unlock(&m->lock); 818 } 819 820 void 821 mixer_hwvol_step_locked(struct snd_mixer *m, int left_step, int right_step) 822 { 823 int level, left, right; 824 825 level = mixer_get(m, m->hwvol_mixer); 826 827 if (level != -1) { 828 left = level & 0xff; 829 right = (level >> 8) & 0xff; 830 left += left_step * m->hwvol_step; 831 if (left < 0) 832 left = 0; 833 else if (left > 100) 834 left = 100; 835 right += right_step * m->hwvol_step; 836 if (right < 0) 837 right = 0; 838 else if (right > 100) 839 right = 100; 840 841 mixer_set(m, m->hwvol_mixer, m->mutedevs, left | right << 8); 842 } 843 } 844 845 void 846 mixer_hwvol_step(device_t dev, int left_step, int right_step) 847 { 848 struct snd_mixer *m; 849 struct cdev *pdev; 850 851 pdev = mixer_get_devt(dev); 852 m = pdev->si_drv1; 853 mtx_lock(&m->lock); 854 mixer_hwvol_step_locked(m, left_step, right_step); 855 mtx_unlock(&m->lock); 856 } 857 858 int 859 mix_set(struct snd_mixer *m, u_int dev, u_int left, u_int right) 860 { 861 int ret; 862 863 KASSERT(m != NULL, ("NULL snd_mixer")); 864 865 mtx_lock(&m->lock); 866 ret = mixer_set(m, dev, m->mutedevs, left | (right << 8)); 867 mtx_unlock(&m->lock); 868 869 return ((ret != 0) ? ENXIO : 0); 870 } 871 872 int 873 mix_get(struct snd_mixer *m, u_int dev) 874 { 875 int ret; 876 877 KASSERT(m != NULL, ("NULL snd_mixer")); 878 879 mtx_lock(&m->lock); 880 ret = mixer_get(m, dev); 881 mtx_unlock(&m->lock); 882 883 return (ret); 884 } 885 886 int 887 mix_setrecsrc(struct snd_mixer *m, u_int32_t src) 888 { 889 int ret; 890 891 KASSERT(m != NULL, ("NULL snd_mixer")); 892 893 mtx_lock(&m->lock); 894 ret = mixer_setrecsrc(m, src); 895 mtx_unlock(&m->lock); 896 897 return ((ret != 0) ? ENXIO : 0); 898 } 899 900 u_int32_t 901 mix_getrecsrc(struct snd_mixer *m) 902 { 903 u_int32_t ret; 904 905 KASSERT(m != NULL, ("NULL snd_mixer")); 906 907 mtx_lock(&m->lock); 908 ret = mixer_getrecsrc(m); 909 mtx_unlock(&m->lock); 910 911 return (ret); 912 } 913 914 device_t 915 mix_get_dev(struct snd_mixer *m) 916 { 917 KASSERT(m != NULL, ("NULL snd_mixer")); 918 919 return (m->dev); 920 } 921 922 /* ----------------------------------------------------------------------- */ 923 924 static int 925 mixer_open(struct cdev *i_dev, int flags, int mode, struct thread *td) 926 { 927 struct snddev_info *d; 928 struct snd_mixer *m; 929 930 if (i_dev == NULL || i_dev->si_drv1 == NULL) 931 return (EBADF); 932 933 m = i_dev->si_drv1; 934 d = device_get_softc(m->dev); 935 if (!PCM_REGISTERED(d)) 936 return (EBADF); 937 938 return (0); 939 } 940 941 static int 942 mixer_close(struct cdev *i_dev, int flags, int mode, struct thread *td) 943 { 944 struct snddev_info *d; 945 struct snd_mixer *m; 946 947 if (i_dev == NULL || i_dev->si_drv1 == NULL) 948 return (EBADF); 949 950 m = i_dev->si_drv1; 951 d = device_get_softc(m->dev); 952 if (!PCM_REGISTERED(d)) 953 return (EBADF); 954 955 return (0); 956 } 957 958 static int 959 mixer_ioctl(struct cdev *i_dev, u_long cmd, caddr_t arg, int mode, 960 struct thread *td) 961 { 962 struct snddev_info *d; 963 int ret; 964 965 if (i_dev == NULL || i_dev->si_drv1 == NULL) 966 return (EBADF); 967 968 d = device_get_softc(((struct snd_mixer *)i_dev->si_drv1)->dev); 969 if (!PCM_REGISTERED(d)) 970 return (EBADF); 971 972 PCM_GIANT_ENTER(d); 973 PCM_ACQUIRE_QUICK(d); 974 975 ret = mixer_ioctl_cmd(i_dev, cmd, arg, mode, td); 976 977 PCM_RELEASE_QUICK(d); 978 PCM_GIANT_LEAVE(d); 979 980 return (ret); 981 } 982 983 static void 984 mixer_mixerinfo(struct snd_mixer *m, mixer_info *mi) 985 { 986 bzero((void *)mi, sizeof(*mi)); 987 strlcpy(mi->id, m->name, sizeof(mi->id)); 988 strlcpy(mi->name, device_get_desc(m->dev), sizeof(mi->name)); 989 mi->modify_counter = m->modify_counter; 990 } 991 992 /* 993 * XXX Make sure you can guarantee concurrency safety before calling this 994 * function, be it through Giant, PCM_*, etc ! 995 */ 996 int 997 mixer_ioctl_cmd(struct cdev *i_dev, u_long cmd, caddr_t arg, int mode, 998 struct thread *td) 999 { 1000 struct snd_mixer *m; 1001 int ret = EINVAL, *arg_i = (int *)arg; 1002 int v = -1, j = cmd & 0xff; 1003 1004 /* 1005 * Certain ioctls may be made on any type of device (audio, mixer, 1006 * and MIDI). Handle those special cases here. 1007 */ 1008 if (IOCGROUP(cmd) == 'X') { 1009 switch (cmd) { 1010 case SNDCTL_SYSINFO: 1011 sound_oss_sysinfo((oss_sysinfo *)arg); 1012 return (0); 1013 case SNDCTL_CARDINFO: 1014 return (sound_oss_card_info((oss_card_info *)arg)); 1015 case SNDCTL_AUDIOINFO: 1016 return (dsp_oss_audioinfo(i_dev, (oss_audioinfo *)arg, 1017 false)); 1018 case SNDCTL_AUDIOINFO_EX: 1019 return (dsp_oss_audioinfo(i_dev, (oss_audioinfo *)arg, 1020 true)); 1021 case SNDCTL_ENGINEINFO: 1022 return (dsp_oss_engineinfo(i_dev, (oss_audioinfo *)arg)); 1023 case SNDCTL_MIXERINFO: 1024 return (mixer_oss_mixerinfo(i_dev, (oss_mixerinfo *)arg)); 1025 } 1026 return (EINVAL); 1027 } 1028 1029 m = i_dev->si_drv1; 1030 1031 if (m == NULL) 1032 return (EBADF); 1033 1034 mtx_lock(&m->lock); 1035 switch (cmd) { 1036 case SNDCTL_DSP_GET_RECSRC_NAMES: { 1037 oss_mixer_enuminfo *ei = (oss_mixer_enuminfo *)arg; 1038 char *loc; 1039 int i, nvalues, nwrote, nleft, ncopied; 1040 1041 nvalues = 0; 1042 nwrote = 0; 1043 nleft = sizeof(ei->strings); 1044 loc = ei->strings; 1045 1046 for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) { 1047 if (!((1 << i) & m->recdevs)) 1048 continue; 1049 ei->strindex[nvalues] = nwrote; 1050 ncopied = strlcpy(loc, snd_mixernames[i], nleft) + 1; 1051 nwrote += ncopied; 1052 nleft -= ncopied; 1053 nvalues++; 1054 loc = &ei->strings[nwrote]; 1055 } 1056 ei->nvalues = nvalues; 1057 1058 ret = 0; 1059 goto done; 1060 } 1061 case SNDCTL_DSP_GET_RECSRC: 1062 ret = mixer_get_recroute(m, arg_i); 1063 goto done; 1064 case SNDCTL_DSP_SET_RECSRC: 1065 ret = mixer_set_recroute(m, *arg_i); 1066 goto done; 1067 case OSS_GETVERSION: 1068 *arg_i = SOUND_VERSION; 1069 ret = 0; 1070 goto done; 1071 case SOUND_MIXER_INFO: 1072 mixer_mixerinfo(m, (mixer_info *)arg); 1073 ret = 0; 1074 goto done; 1075 } 1076 if ((cmd & ~0xff) == MIXER_WRITE(0)) { 1077 switch (j) { 1078 case SOUND_MIXER_RECSRC: 1079 ret = mixer_setrecsrc(m, *arg_i); 1080 break; 1081 case SOUND_MIXER_MUTE: 1082 mix_setmutedevs(m, *arg_i); 1083 ret = 0; 1084 break; 1085 default: 1086 ret = mixer_set(m, j, m->mutedevs, *arg_i); 1087 break; 1088 } 1089 mtx_unlock(&m->lock); 1090 return ((ret == 0) ? 0 : ENXIO); 1091 } 1092 if ((cmd & ~0xff) == MIXER_READ(0)) { 1093 switch (j) { 1094 case SOUND_MIXER_DEVMASK: 1095 case SOUND_MIXER_CAPS: 1096 case SOUND_MIXER_STEREODEVS: 1097 v = mix_getdevs(m); 1098 break; 1099 case SOUND_MIXER_MUTE: 1100 v = mix_getmutedevs(m); 1101 break; 1102 case SOUND_MIXER_RECMASK: 1103 v = mix_getrecdevs(m); 1104 break; 1105 case SOUND_MIXER_RECSRC: 1106 v = mixer_getrecsrc(m); 1107 break; 1108 default: 1109 v = mixer_get(m, j); 1110 break; 1111 } 1112 *arg_i = v; 1113 mtx_unlock(&m->lock); 1114 return ((v != -1) ? 0 : ENXIO); 1115 } 1116 done: 1117 mtx_unlock(&m->lock); 1118 return (ret); 1119 } 1120 1121 static void 1122 mixer_clone(void *arg, 1123 struct ucred *cred, 1124 char *name, int namelen, struct cdev **dev) 1125 { 1126 struct snddev_info *d; 1127 1128 if (*dev != NULL) 1129 return; 1130 if (strcmp(name, "mixer") == 0) { 1131 bus_topo_lock(); 1132 d = devclass_get_softc(pcm_devclass, snd_unit); 1133 /* See related comment in dsp_clone(). */ 1134 if (PCM_REGISTERED(d) && d->mixer_dev != NULL) { 1135 *dev = d->mixer_dev; 1136 dev_ref(*dev); 1137 } 1138 bus_topo_unlock(); 1139 } 1140 } 1141 1142 static void 1143 mixer_sysinit(void *p) 1144 { 1145 if (mixer_ehtag != NULL) 1146 return; 1147 mixer_ehtag = EVENTHANDLER_REGISTER(dev_clone, mixer_clone, 0, 1000); 1148 } 1149 1150 static void 1151 mixer_sysuninit(void *p) 1152 { 1153 if (mixer_ehtag == NULL) 1154 return; 1155 EVENTHANDLER_DEREGISTER(dev_clone, mixer_ehtag); 1156 mixer_ehtag = NULL; 1157 } 1158 1159 SYSINIT(mixer_sysinit, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, mixer_sysinit, NULL); 1160 SYSUNINIT(mixer_sysuninit, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, mixer_sysuninit, NULL); 1161 1162 static void 1163 mixer_oss_mixerinfo_unavail(oss_mixerinfo *mi, int unit) 1164 { 1165 bzero(mi, sizeof(*mi)); 1166 mi->dev = unit; 1167 snprintf(mi->id, sizeof(mi->id), "mixer%d (n/a)", unit); 1168 snprintf(mi->name, sizeof(mi->name), "pcm%d:mixer (unavailable)", unit); 1169 mi->card_number = unit; 1170 mi->legacy_device = unit; 1171 } 1172 1173 /** 1174 * @brief Handler for SNDCTL_MIXERINFO 1175 * 1176 * This function searches for a mixer based on the numeric ID stored 1177 * in oss_miserinfo::dev. If set to -1, then information about the 1178 * current mixer handling the request is provided. Note, however, that 1179 * this ioctl may be made with any sound device (audio, mixer, midi). 1180 * 1181 * @note Caller must not hold any PCM device, channel, or mixer locks. 1182 * 1183 * See http://manuals.opensound.com/developer/SNDCTL_MIXERINFO.html for 1184 * more information. 1185 * 1186 * @param i_dev character device on which the ioctl arrived 1187 * @param arg user argument (oss_mixerinfo *) 1188 * 1189 * @retval EINVAL oss_mixerinfo::dev specified a bad value 1190 * @retval 0 success 1191 */ 1192 int 1193 mixer_oss_mixerinfo(struct cdev *i_dev, oss_mixerinfo *mi) 1194 { 1195 struct snddev_info *d; 1196 struct snd_mixer *m; 1197 int i; 1198 1199 /* 1200 * If probing the device handling the ioctl, make sure it's a mixer 1201 * device. (This ioctl is valid on audio, mixer, and midi devices.) 1202 */ 1203 if (mi->dev == -1 && i_dev->si_devsw != &mixer_cdevsw) 1204 return (EINVAL); 1205 1206 d = NULL; 1207 m = NULL; 1208 1209 /* 1210 * There's a 1:1 relationship between mixers and PCM devices, so 1211 * begin by iterating over PCM devices and search for our mixer. 1212 */ 1213 bus_topo_lock(); 1214 for (i = 0; pcm_devclass != NULL && 1215 i < devclass_get_maxunit(pcm_devclass); i++) { 1216 d = devclass_get_softc(pcm_devclass, i); 1217 if (!PCM_REGISTERED(d)) { 1218 if ((mi->dev == -1 && i == snd_unit) || mi->dev == i) { 1219 mixer_oss_mixerinfo_unavail(mi, i); 1220 bus_topo_unlock(); 1221 return (0); 1222 } else 1223 continue; 1224 } 1225 1226 /* XXX Need Giant magic entry */ 1227 1228 /* See the note in function docblock. */ 1229 PCM_UNLOCKASSERT(d); 1230 PCM_LOCK(d); 1231 1232 if (!((d->mixer_dev == i_dev && mi->dev == -1) || 1233 mi->dev == i)) { 1234 PCM_UNLOCK(d); 1235 continue; 1236 } 1237 1238 if (d->mixer_dev->si_drv1 == NULL) { 1239 mixer_oss_mixerinfo_unavail(mi, i); 1240 PCM_UNLOCK(d); 1241 bus_topo_unlock(); 1242 return (0); 1243 } 1244 1245 m = d->mixer_dev->si_drv1; 1246 mtx_lock(&m->lock); 1247 1248 /* 1249 * At this point, the following synchronization stuff 1250 * has happened: 1251 * - a specific PCM device is locked. 1252 * - a specific mixer device has been locked, so be 1253 * sure to unlock when existing. 1254 */ 1255 bzero((void *)mi, sizeof(*mi)); 1256 mi->dev = i; 1257 snprintf(mi->id, sizeof(mi->id), "mixer%d", i); 1258 strlcpy(mi->name, m->name, sizeof(mi->name)); 1259 /** 1260 * Counter is incremented when applications change any of this 1261 * mixer's controls. A change in value indicates that 1262 * persistent mixer applications should update their displays. 1263 */ 1264 mi->modify_counter = m->modify_counter; 1265 mi->card_number = i; 1266 /* 1267 * Currently, FreeBSD assumes 1:1 relationship between 1268 * a pcm and mixer devices, so this is hardcoded to 0. 1269 */ 1270 mi->port_number = 0; 1271 1272 /** 1273 * @todo Fill in @sa oss_mixerinfo::mixerhandle. 1274 * @note From 4Front: "mixerhandle is an arbitrary 1275 * string that identifies the mixer better than 1276 * the device number (mixerinfo.dev). Device 1277 * numbers may change depending on the order the 1278 * drivers are loaded. However the handle should 1279 * remain the same provided that the sound card 1280 * is not moved to another PCI slot." 1281 */ 1282 1283 /** 1284 * @note 1285 * @sa oss_mixerinfo::magic is a reserved field. 1286 * 1287 * @par 1288 * From 4Front: "magic is usually 0. However some 1289 * devices may have dedicated setup utilities and the 1290 * magic field may contain an unique driver specific 1291 * value (managed by [4Front])." 1292 */ 1293 1294 mi->enabled = device_is_attached(m->dev) ? 1 : 0; 1295 /** 1296 * The only flag for @sa oss_mixerinfo::caps is 1297 * currently MIXER_CAP_VIRTUAL, which I'm not sure we 1298 * really worry about. 1299 */ 1300 /** 1301 * Mixer extensions currently aren't supported, so 1302 * leave @sa oss_mixerinfo::nrext blank for now. 1303 */ 1304 1305 /** 1306 * @todo Fill in @sa oss_mixerinfo::priority (requires 1307 * touching drivers?) 1308 * @note The priority field is for mixer applets to 1309 * determine which mixer should be the default, with 0 1310 * being least preferred and 10 being most preferred. 1311 * From 4Front: "OSS drivers like ICH use higher 1312 * values (10) because such chips are known to be used 1313 * only on motherboards. Drivers for high end pro 1314 * devices use 0 because they will never be the 1315 * default mixer. Other devices use values 1 to 9 1316 * depending on the estimated probability of being the 1317 * default device. 1318 */ 1319 1320 snprintf(mi->devnode, sizeof(mi->devnode), "/dev/mixer%d", i); 1321 mi->legacy_device = i; 1322 1323 mtx_unlock(&m->lock); 1324 1325 PCM_UNLOCK(d); 1326 1327 bus_topo_unlock(); 1328 return (0); 1329 } 1330 bus_topo_unlock(); 1331 1332 return (EINVAL); 1333 } 1334