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