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