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