1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 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 SND_DECLARE_FILE("$FreeBSD$"); 41 42 static MALLOC_DEFINE(M_MIXER, "mixer", "mixer"); 43 44 static int mixer_bypass = 1; 45 SYSCTL_INT(_hw_snd, OID_AUTO, vpc_mixer_bypass, CTLFLAG_RWTUN, 46 &mixer_bypass, 0, 47 "control channel pcm/rec volume, bypassing real mixer device"); 48 49 #define MIXER_NAMELEN 16 50 struct snd_mixer { 51 KOBJ_FIELDS; 52 void *devinfo; 53 int busy; 54 int hwvol_muted; 55 int hwvol_mixer; 56 int hwvol_step; 57 int type; 58 device_t dev; 59 u_int32_t hwvol_mute_level; 60 u_int32_t devs; 61 u_int32_t recdevs; 62 u_int32_t recsrc; 63 u_int16_t level[32]; 64 u_int8_t parent[32]; 65 u_int32_t child[32]; 66 u_int8_t realdev[32]; 67 char name[MIXER_NAMELEN]; 68 struct mtx *lock; 69 oss_mixer_enuminfo enuminfo; 70 /** 71 * Counter is incremented when applications change any of this 72 * mixer's controls. A change in value indicates that persistent 73 * mixer applications should update their displays. 74 */ 75 int modify_counter; 76 }; 77 78 static u_int16_t snd_mixerdefaults[SOUND_MIXER_NRDEVICES] = { 79 [SOUND_MIXER_VOLUME] = 75, 80 [SOUND_MIXER_BASS] = 50, 81 [SOUND_MIXER_TREBLE] = 50, 82 [SOUND_MIXER_SYNTH] = 75, 83 [SOUND_MIXER_PCM] = 75, 84 [SOUND_MIXER_SPEAKER] = 75, 85 [SOUND_MIXER_LINE] = 75, 86 [SOUND_MIXER_MIC] = 25, 87 [SOUND_MIXER_CD] = 75, 88 [SOUND_MIXER_IGAIN] = 0, 89 [SOUND_MIXER_LINE1] = 75, 90 [SOUND_MIXER_VIDEO] = 75, 91 [SOUND_MIXER_RECLEV] = 75, 92 [SOUND_MIXER_OGAIN] = 50, 93 [SOUND_MIXER_MONITOR] = 75, 94 }; 95 96 static char* snd_mixernames[SOUND_MIXER_NRDEVICES] = SOUND_DEVICE_NAMES; 97 98 static d_open_t mixer_open; 99 static d_close_t mixer_close; 100 static d_ioctl_t mixer_ioctl; 101 102 static struct cdevsw mixer_cdevsw = { 103 .d_version = D_VERSION, 104 .d_open = mixer_open, 105 .d_close = mixer_close, 106 .d_ioctl = mixer_ioctl, 107 .d_name = "mixer", 108 }; 109 110 /** 111 * Keeps a count of mixer devices; used only by OSSv4 SNDCTL_SYSINFO ioctl. 112 */ 113 int mixer_count = 0; 114 115 static eventhandler_tag mixer_ehtag = NULL; 116 117 static struct cdev * 118 mixer_get_devt(device_t dev) 119 { 120 struct snddev_info *snddev; 121 122 snddev = device_get_softc(dev); 123 124 return snddev->mixer_dev; 125 } 126 127 static int 128 mixer_lookup(char *devname) 129 { 130 int i; 131 132 for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) 133 if (strncmp(devname, snd_mixernames[i], 134 strlen(snd_mixernames[i])) == 0) 135 return i; 136 return -1; 137 } 138 139 #define MIXER_SET_UNLOCK(x, y) do { \ 140 if ((y) != 0) \ 141 snd_mtxunlock((x)->lock); \ 142 } while (0) 143 144 #define MIXER_SET_LOCK(x, y) do { \ 145 if ((y) != 0) \ 146 snd_mtxlock((x)->lock); \ 147 } while (0) 148 149 static int 150 mixer_set_softpcmvol(struct snd_mixer *m, struct snddev_info *d, 151 u_int left, u_int right) 152 { 153 struct pcm_channel *c; 154 int dropmtx, acquiremtx; 155 156 if (PCM_DETACHING(d) || !PCM_REGISTERED(d)) 157 return (EINVAL); 158 159 if (mtx_owned(m->lock)) 160 dropmtx = 1; 161 else 162 dropmtx = 0; 163 164 if (!(d->flags & SD_F_MPSAFE) || mtx_owned(d->lock) != 0) 165 acquiremtx = 0; 166 else 167 acquiremtx = 1; 168 169 /* 170 * Be careful here. If we're coming from cdev ioctl, it is OK to 171 * not doing locking AT ALL (except on individual channel) since 172 * we've been heavily guarded by pcm cv, or if we're still 173 * under Giant influence. Since we also have mix_* calls, we cannot 174 * assume such protection and just do the lock as usuall. 175 */ 176 MIXER_SET_UNLOCK(m, dropmtx); 177 MIXER_SET_LOCK(d, acquiremtx); 178 179 CHN_FOREACH(c, d, channels.pcm.busy) { 180 CHN_LOCK(c); 181 if (c->direction == PCMDIR_PLAY && 182 (c->feederflags & (1 << FEEDER_VOLUME))) 183 chn_setvolume_multi(c, SND_VOL_C_MASTER, left, right, 184 (left + right) >> 1); 185 CHN_UNLOCK(c); 186 } 187 188 MIXER_SET_UNLOCK(d, acquiremtx); 189 MIXER_SET_LOCK(m, dropmtx); 190 191 return (0); 192 } 193 194 static int 195 mixer_set_eq(struct snd_mixer *m, struct snddev_info *d, 196 u_int dev, u_int level) 197 { 198 struct pcm_channel *c; 199 struct pcm_feeder *f; 200 int tone, dropmtx, acquiremtx; 201 202 if (dev == SOUND_MIXER_TREBLE) 203 tone = FEEDEQ_TREBLE; 204 else if (dev == SOUND_MIXER_BASS) 205 tone = FEEDEQ_BASS; 206 else 207 return (EINVAL); 208 209 if (PCM_DETACHING(d) || !PCM_REGISTERED(d)) 210 return (EINVAL); 211 212 if (mtx_owned(m->lock)) 213 dropmtx = 1; 214 else 215 dropmtx = 0; 216 217 if (!(d->flags & SD_F_MPSAFE) || mtx_owned(d->lock) != 0) 218 acquiremtx = 0; 219 else 220 acquiremtx = 1; 221 222 /* 223 * Be careful here. If we're coming from cdev ioctl, it is OK to 224 * not doing locking AT ALL (except on individual channel) since 225 * we've been heavily guarded by pcm cv, or if we're still 226 * under Giant influence. Since we also have mix_* calls, we cannot 227 * assume such protection and just do the lock as usuall. 228 */ 229 MIXER_SET_UNLOCK(m, dropmtx); 230 MIXER_SET_LOCK(d, acquiremtx); 231 232 CHN_FOREACH(c, d, channels.pcm.busy) { 233 CHN_LOCK(c); 234 f = chn_findfeeder(c, FEEDER_EQ); 235 if (f != NULL) 236 (void)FEEDER_SET(f, tone, level); 237 CHN_UNLOCK(c); 238 } 239 240 MIXER_SET_UNLOCK(d, acquiremtx); 241 MIXER_SET_LOCK(m, dropmtx); 242 243 return (0); 244 } 245 246 static int 247 mixer_set(struct snd_mixer *m, u_int dev, u_int lev) 248 { 249 struct snddev_info *d; 250 u_int l, r, tl, tr; 251 u_int32_t parent = SOUND_MIXER_NONE, child = 0; 252 u_int32_t realdev; 253 int i, dropmtx; 254 255 if (m == NULL || dev >= SOUND_MIXER_NRDEVICES || 256 (0 == (m->devs & (1 << dev)))) 257 return -1; 258 259 l = min((lev & 0x00ff), 100); 260 r = min(((lev & 0xff00) >> 8), 100); 261 realdev = m->realdev[dev]; 262 263 d = device_get_softc(m->dev); 264 if (d == NULL) 265 return -1; 266 267 /* It is safe to drop this mutex due to Giant. */ 268 if (!(d->flags & SD_F_MPSAFE) && mtx_owned(m->lock) != 0) 269 dropmtx = 1; 270 else 271 dropmtx = 0; 272 273 MIXER_SET_UNLOCK(m, dropmtx); 274 275 /* TODO: recursive handling */ 276 parent = m->parent[dev]; 277 if (parent >= SOUND_MIXER_NRDEVICES) 278 parent = SOUND_MIXER_NONE; 279 if (parent == SOUND_MIXER_NONE) 280 child = m->child[dev]; 281 282 if (parent != SOUND_MIXER_NONE) { 283 tl = (l * (m->level[parent] & 0x00ff)) / 100; 284 tr = (r * ((m->level[parent] & 0xff00) >> 8)) / 100; 285 if (dev == SOUND_MIXER_PCM && (d->flags & SD_F_SOFTPCMVOL)) 286 (void)mixer_set_softpcmvol(m, d, tl, tr); 287 else if (realdev != SOUND_MIXER_NONE && 288 MIXER_SET(m, realdev, tl, tr) < 0) { 289 MIXER_SET_LOCK(m, dropmtx); 290 return -1; 291 } 292 } else if (child != 0) { 293 for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) { 294 if (!(child & (1 << i)) || m->parent[i] != dev) 295 continue; 296 realdev = m->realdev[i]; 297 tl = (l * (m->level[i] & 0x00ff)) / 100; 298 tr = (r * ((m->level[i] & 0xff00) >> 8)) / 100; 299 if (i == SOUND_MIXER_PCM && 300 (d->flags & SD_F_SOFTPCMVOL)) 301 (void)mixer_set_softpcmvol(m, d, tl, tr); 302 else if (realdev != SOUND_MIXER_NONE) 303 MIXER_SET(m, realdev, tl, tr); 304 } 305 realdev = m->realdev[dev]; 306 if (realdev != SOUND_MIXER_NONE && 307 MIXER_SET(m, realdev, l, r) < 0) { 308 MIXER_SET_LOCK(m, dropmtx); 309 return -1; 310 } 311 } else { 312 if (dev == SOUND_MIXER_PCM && (d->flags & SD_F_SOFTPCMVOL)) 313 (void)mixer_set_softpcmvol(m, d, l, r); 314 else if ((dev == SOUND_MIXER_TREBLE || 315 dev == SOUND_MIXER_BASS) && (d->flags & SD_F_EQ)) 316 (void)mixer_set_eq(m, d, dev, (l + r) >> 1); 317 else if (realdev != SOUND_MIXER_NONE && 318 MIXER_SET(m, realdev, l, r) < 0) { 319 MIXER_SET_LOCK(m, dropmtx); 320 return -1; 321 } 322 } 323 324 MIXER_SET_LOCK(m, dropmtx); 325 326 m->level[dev] = l | (r << 8); 327 m->modify_counter++; 328 329 return 0; 330 } 331 332 static int 333 mixer_get(struct snd_mixer *mixer, int dev) 334 { 335 if ((dev < SOUND_MIXER_NRDEVICES) && (mixer->devs & (1 << dev))) 336 return mixer->level[dev]; 337 else 338 return -1; 339 } 340 341 static int 342 mixer_setrecsrc(struct snd_mixer *mixer, u_int32_t src) 343 { 344 struct snddev_info *d; 345 u_int32_t recsrc; 346 int dropmtx; 347 348 d = device_get_softc(mixer->dev); 349 if (d == NULL) 350 return -1; 351 if (!(d->flags & SD_F_MPSAFE) && mtx_owned(mixer->lock) != 0) 352 dropmtx = 1; 353 else 354 dropmtx = 0; 355 src &= mixer->recdevs; 356 if (src == 0) 357 src = mixer->recdevs & SOUND_MASK_MIC; 358 if (src == 0) 359 src = mixer->recdevs & SOUND_MASK_MONITOR; 360 if (src == 0) 361 src = mixer->recdevs & SOUND_MASK_LINE; 362 if (src == 0 && mixer->recdevs != 0) 363 src = (1 << (ffs(mixer->recdevs) - 1)); 364 /* It is safe to drop this mutex due to Giant. */ 365 MIXER_SET_UNLOCK(mixer, dropmtx); 366 recsrc = MIXER_SETRECSRC(mixer, src); 367 MIXER_SET_LOCK(mixer, dropmtx); 368 369 mixer->recsrc = recsrc; 370 371 return 0; 372 } 373 374 static int 375 mixer_getrecsrc(struct snd_mixer *mixer) 376 { 377 return mixer->recsrc; 378 } 379 380 /** 381 * @brief Retrieve the route number of the current recording device 382 * 383 * OSSv4 assigns routing numbers to recording devices, unlike the previous 384 * API which relied on a fixed table of device numbers and names. This 385 * function returns the routing number of the device currently selected 386 * for recording. 387 * 388 * For now, this function is kind of a goofy compatibility stub atop the 389 * existing sound system. (For example, in theory, the old sound system 390 * allows multiple recording devices to be specified via a bitmask.) 391 * 392 * @param m mixer context container thing 393 * 394 * @retval 0 success 395 * @retval EIDRM no recording device found (generally not possible) 396 * @todo Ask about error code 397 */ 398 static int 399 mixer_get_recroute(struct snd_mixer *m, int *route) 400 { 401 int i, cnt; 402 403 cnt = 0; 404 405 for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) { 406 /** @todo can user set a multi-device mask? (== or &?) */ 407 if ((1 << i) == m->recsrc) 408 break; 409 if ((1 << i) & m->recdevs) 410 ++cnt; 411 } 412 413 if (i == SOUND_MIXER_NRDEVICES) 414 return EIDRM; 415 416 *route = cnt; 417 return 0; 418 } 419 420 /** 421 * @brief Select a device for recording 422 * 423 * This function sets a recording source based on a recording device's 424 * routing number. Said number is translated to an old school recdev 425 * mask and passed over mixer_setrecsrc. 426 * 427 * @param m mixer context container thing 428 * 429 * @retval 0 success(?) 430 * @retval EINVAL User specified an invalid device number 431 * @retval otherwise error from mixer_setrecsrc 432 */ 433 static int 434 mixer_set_recroute(struct snd_mixer *m, int route) 435 { 436 int i, cnt, ret; 437 438 ret = 0; 439 cnt = 0; 440 441 for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) { 442 if ((1 << i) & m->recdevs) { 443 if (route == cnt) 444 break; 445 ++cnt; 446 } 447 } 448 449 if (i == SOUND_MIXER_NRDEVICES) 450 ret = EINVAL; 451 else 452 ret = mixer_setrecsrc(m, (1 << i)); 453 454 return ret; 455 } 456 457 void 458 mix_setdevs(struct snd_mixer *m, u_int32_t v) 459 { 460 struct snddev_info *d; 461 int i; 462 463 if (m == NULL) 464 return; 465 466 d = device_get_softc(m->dev); 467 if (d != NULL && (d->flags & SD_F_SOFTPCMVOL)) 468 v |= SOUND_MASK_PCM; 469 if (d != NULL && (d->flags & SD_F_EQ)) 470 v |= SOUND_MASK_TREBLE | SOUND_MASK_BASS; 471 for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) { 472 if (m->parent[i] < SOUND_MIXER_NRDEVICES) 473 v |= 1 << m->parent[i]; 474 v |= m->child[i]; 475 } 476 m->devs = v; 477 } 478 479 /** 480 * @brief Record mask of available recording devices 481 * 482 * Calling functions are responsible for defining the mask of available 483 * recording devices. This function records that value in a structure 484 * used by the rest of the mixer code. 485 * 486 * This function also populates a structure used by the SNDCTL_DSP_*RECSRC* 487 * family of ioctls that are part of OSSV4. All recording device labels 488 * are concatenated in ascending order corresponding to their routing 489 * numbers. (Ex: a system might have 0 => 'vol', 1 => 'cd', 2 => 'line', 490 * etc.) For now, these labels are just the standard recording device 491 * names (cd, line1, etc.), but will eventually be fully dynamic and user 492 * controlled. 493 * 494 * @param m mixer device context container thing 495 * @param v mask of recording devices 496 */ 497 void 498 mix_setrecdevs(struct snd_mixer *m, u_int32_t v) 499 { 500 oss_mixer_enuminfo *ei; 501 char *loc; 502 int i, nvalues, nwrote, nleft, ncopied; 503 504 ei = &m->enuminfo; 505 506 nvalues = 0; 507 nwrote = 0; 508 nleft = sizeof(ei->strings); 509 loc = ei->strings; 510 511 for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) { 512 if ((1 << i) & v) { 513 ei->strindex[nvalues] = nwrote; 514 ncopied = strlcpy(loc, snd_mixernames[i], nleft) + 1; 515 /* strlcpy retval doesn't include terminator */ 516 517 nwrote += ncopied; 518 nleft -= ncopied; 519 nvalues++; 520 521 /* 522 * XXX I don't think this should ever be possible. 523 * Even with a move to dynamic device/channel names, 524 * each label is limited to ~16 characters, so that'd 525 * take a LOT to fill this buffer. 526 */ 527 if ((nleft <= 0) || (nvalues >= OSS_ENUM_MAXVALUE)) { 528 device_printf(m->dev, 529 "mix_setrecdevs: Not enough room to store device names--please file a bug report.\n"); 530 device_printf(m->dev, 531 "mix_setrecdevs: Please include details about your sound hardware, OS version, etc.\n"); 532 break; 533 } 534 535 loc = &ei->strings[nwrote]; 536 } 537 } 538 539 /* 540 * NB: The SNDCTL_DSP_GET_RECSRC_NAMES ioctl ignores the dev 541 * and ctrl fields. 542 */ 543 ei->nvalues = nvalues; 544 m->recdevs = v; 545 } 546 547 void 548 mix_setparentchild(struct snd_mixer *m, u_int32_t parent, u_int32_t childs) 549 { 550 u_int32_t mask = 0; 551 int i; 552 553 if (m == NULL || parent >= SOUND_MIXER_NRDEVICES) 554 return; 555 for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) { 556 if (i == parent) 557 continue; 558 if (childs & (1 << i)) { 559 mask |= 1 << i; 560 if (m->parent[i] < SOUND_MIXER_NRDEVICES) 561 m->child[m->parent[i]] &= ~(1 << i); 562 m->parent[i] = parent; 563 m->child[i] = 0; 564 } 565 } 566 mask &= ~(1 << parent); 567 m->child[parent] = mask; 568 } 569 570 void 571 mix_setrealdev(struct snd_mixer *m, u_int32_t dev, u_int32_t realdev) 572 { 573 if (m == NULL || dev >= SOUND_MIXER_NRDEVICES || 574 !(realdev == SOUND_MIXER_NONE || realdev < SOUND_MIXER_NRDEVICES)) 575 return; 576 m->realdev[dev] = realdev; 577 } 578 579 u_int32_t 580 mix_getparent(struct snd_mixer *m, u_int32_t dev) 581 { 582 if (m == NULL || dev >= SOUND_MIXER_NRDEVICES) 583 return SOUND_MIXER_NONE; 584 return m->parent[dev]; 585 } 586 587 u_int32_t 588 mix_getchild(struct snd_mixer *m, u_int32_t dev) 589 { 590 if (m == NULL || dev >= SOUND_MIXER_NRDEVICES) 591 return 0; 592 return m->child[dev]; 593 } 594 595 u_int32_t 596 mix_getdevs(struct snd_mixer *m) 597 { 598 return m->devs; 599 } 600 601 u_int32_t 602 mix_getrecdevs(struct snd_mixer *m) 603 { 604 return m->recdevs; 605 } 606 607 void * 608 mix_getdevinfo(struct snd_mixer *m) 609 { 610 return m->devinfo; 611 } 612 613 static struct snd_mixer * 614 mixer_obj_create(device_t dev, kobj_class_t cls, void *devinfo, 615 int type, const char *desc) 616 { 617 struct snd_mixer *m; 618 int i; 619 620 KASSERT(dev != NULL && cls != NULL && devinfo != NULL, 621 ("%s(): NULL data dev=%p cls=%p devinfo=%p", 622 __func__, dev, cls, devinfo)); 623 KASSERT(type == MIXER_TYPE_PRIMARY || type == MIXER_TYPE_SECONDARY, 624 ("invalid mixer type=%d", type)); 625 626 m = (struct snd_mixer *)kobj_create(cls, M_MIXER, M_WAITOK | M_ZERO); 627 snprintf(m->name, sizeof(m->name), "%s:mixer", 628 device_get_nameunit(dev)); 629 if (desc != NULL) { 630 strlcat(m->name, ":", sizeof(m->name)); 631 strlcat(m->name, desc, sizeof(m->name)); 632 } 633 m->lock = snd_mtxcreate(m->name, (type == MIXER_TYPE_PRIMARY) ? 634 "primary pcm mixer" : "secondary pcm mixer"); 635 m->type = type; 636 m->devinfo = devinfo; 637 m->busy = 0; 638 m->dev = dev; 639 for (i = 0; i < (sizeof(m->parent) / sizeof(m->parent[0])); i++) { 640 m->parent[i] = SOUND_MIXER_NONE; 641 m->child[i] = 0; 642 m->realdev[i] = i; 643 } 644 645 if (MIXER_INIT(m)) { 646 snd_mtxlock(m->lock); 647 snd_mtxfree(m->lock); 648 kobj_delete((kobj_t)m, M_MIXER); 649 return (NULL); 650 } 651 652 return (m); 653 } 654 655 int 656 mixer_delete(struct snd_mixer *m) 657 { 658 KASSERT(m != NULL, ("NULL snd_mixer")); 659 KASSERT(m->type == MIXER_TYPE_SECONDARY, 660 ("%s(): illegal mixer type=%d", __func__, m->type)); 661 662 /* mixer uninit can sleep --hps */ 663 664 MIXER_UNINIT(m); 665 666 snd_mtxfree(m->lock); 667 kobj_delete((kobj_t)m, M_MIXER); 668 669 --mixer_count; 670 671 return (0); 672 } 673 674 struct snd_mixer * 675 mixer_create(device_t dev, kobj_class_t cls, void *devinfo, const char *desc) 676 { 677 struct snd_mixer *m; 678 679 m = mixer_obj_create(dev, cls, devinfo, MIXER_TYPE_SECONDARY, desc); 680 681 if (m != NULL) 682 ++mixer_count; 683 684 return (m); 685 } 686 687 int 688 mixer_init(device_t dev, kobj_class_t cls, void *devinfo) 689 { 690 struct snddev_info *snddev; 691 struct snd_mixer *m; 692 u_int16_t v; 693 struct cdev *pdev; 694 int i, unit, devunit, val; 695 696 snddev = device_get_softc(dev); 697 if (snddev == NULL) 698 return (-1); 699 700 if (resource_int_value(device_get_name(dev), 701 device_get_unit(dev), "eq", &val) == 0 && val != 0) { 702 snddev->flags |= SD_F_EQ; 703 if ((val & SD_F_EQ_MASK) == val) 704 snddev->flags |= val; 705 else 706 snddev->flags |= SD_F_EQ_DEFAULT; 707 snddev->eqpreamp = 0; 708 } 709 710 m = mixer_obj_create(dev, cls, devinfo, MIXER_TYPE_PRIMARY, NULL); 711 if (m == NULL) 712 return (-1); 713 714 for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) { 715 v = snd_mixerdefaults[i]; 716 717 if (resource_int_value(device_get_name(dev), 718 device_get_unit(dev), snd_mixernames[i], &val) == 0) { 719 if (val >= 0 && val <= 100) { 720 v = (u_int16_t) val; 721 } 722 } 723 724 mixer_set(m, i, v | (v << 8)); 725 } 726 727 mixer_setrecsrc(m, 0); /* Set default input. */ 728 729 unit = device_get_unit(dev); 730 devunit = snd_mkunit(unit, SND_DEV_CTL, 0); 731 pdev = make_dev(&mixer_cdevsw, PCMMINOR(devunit), 732 UID_ROOT, GID_WHEEL, 0666, "mixer%d", unit); 733 pdev->si_drv1 = m; 734 snddev->mixer_dev = pdev; 735 736 ++mixer_count; 737 738 if (bootverbose) { 739 for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) { 740 if (!(m->devs & (1 << i))) 741 continue; 742 if (m->realdev[i] != i) { 743 device_printf(dev, "Mixer \"%s\" -> \"%s\":", 744 snd_mixernames[i], 745 (m->realdev[i] < SOUND_MIXER_NRDEVICES) ? 746 snd_mixernames[m->realdev[i]] : "none"); 747 } else { 748 device_printf(dev, "Mixer \"%s\":", 749 snd_mixernames[i]); 750 } 751 if (m->parent[i] < SOUND_MIXER_NRDEVICES) 752 printf(" parent=\"%s\"", 753 snd_mixernames[m->parent[i]]); 754 if (m->child[i] != 0) 755 printf(" child=0x%08x", m->child[i]); 756 printf("\n"); 757 } 758 if (snddev->flags & SD_F_SOFTPCMVOL) 759 device_printf(dev, "Soft PCM mixer ENABLED\n"); 760 if (snddev->flags & SD_F_EQ) 761 device_printf(dev, "EQ Treble/Bass ENABLED\n"); 762 } 763 764 return (0); 765 } 766 767 int 768 mixer_uninit(device_t dev) 769 { 770 int i; 771 struct snddev_info *d; 772 struct snd_mixer *m; 773 struct cdev *pdev; 774 775 d = device_get_softc(dev); 776 pdev = mixer_get_devt(dev); 777 if (d == NULL || pdev == NULL || pdev->si_drv1 == NULL) 778 return EBADF; 779 780 m = pdev->si_drv1; 781 KASSERT(m != NULL, ("NULL snd_mixer")); 782 KASSERT(m->type == MIXER_TYPE_PRIMARY, 783 ("%s(): illegal mixer type=%d", __func__, m->type)); 784 785 snd_mtxlock(m->lock); 786 787 if (m->busy) { 788 snd_mtxunlock(m->lock); 789 return EBUSY; 790 } 791 792 /* destroy dev can sleep --hps */ 793 794 snd_mtxunlock(m->lock); 795 796 pdev->si_drv1 = NULL; 797 destroy_dev(pdev); 798 799 snd_mtxlock(m->lock); 800 801 for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) 802 mixer_set(m, i, 0); 803 804 mixer_setrecsrc(m, SOUND_MASK_MIC); 805 806 snd_mtxunlock(m->lock); 807 808 /* mixer uninit can sleep --hps */ 809 810 MIXER_UNINIT(m); 811 812 snd_mtxfree(m->lock); 813 kobj_delete((kobj_t)m, M_MIXER); 814 815 d->mixer_dev = NULL; 816 817 --mixer_count; 818 819 return 0; 820 } 821 822 int 823 mixer_reinit(device_t dev) 824 { 825 struct snd_mixer *m; 826 struct cdev *pdev; 827 int i; 828 829 pdev = mixer_get_devt(dev); 830 m = pdev->si_drv1; 831 snd_mtxlock(m->lock); 832 833 i = MIXER_REINIT(m); 834 if (i) { 835 snd_mtxunlock(m->lock); 836 return i; 837 } 838 839 for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) 840 mixer_set(m, i, m->level[i]); 841 842 mixer_setrecsrc(m, m->recsrc); 843 snd_mtxunlock(m->lock); 844 845 return 0; 846 } 847 848 static int 849 sysctl_hw_snd_hwvol_mixer(SYSCTL_HANDLER_ARGS) 850 { 851 char devname[32]; 852 int error, dev; 853 struct snd_mixer *m; 854 855 m = oidp->oid_arg1; 856 snd_mtxlock(m->lock); 857 strlcpy(devname, snd_mixernames[m->hwvol_mixer], sizeof(devname)); 858 snd_mtxunlock(m->lock); 859 error = sysctl_handle_string(oidp, &devname[0], sizeof(devname), req); 860 snd_mtxlock(m->lock); 861 if (error == 0 && req->newptr != NULL) { 862 dev = mixer_lookup(devname); 863 if (dev == -1) { 864 snd_mtxunlock(m->lock); 865 return EINVAL; 866 } 867 else if (dev != m->hwvol_mixer) { 868 m->hwvol_mixer = dev; 869 m->hwvol_muted = 0; 870 } 871 } 872 snd_mtxunlock(m->lock); 873 return error; 874 } 875 876 int 877 mixer_hwvol_init(device_t dev) 878 { 879 struct snd_mixer *m; 880 struct cdev *pdev; 881 882 pdev = mixer_get_devt(dev); 883 m = pdev->si_drv1; 884 885 m->hwvol_mixer = SOUND_MIXER_VOLUME; 886 m->hwvol_step = 5; 887 SYSCTL_ADD_INT(device_get_sysctl_ctx(dev), 888 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 889 OID_AUTO, "hwvol_step", CTLFLAG_RWTUN, &m->hwvol_step, 0, ""); 890 SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 891 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, 892 "hwvol_mixer", CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE, 893 m, 0, sysctl_hw_snd_hwvol_mixer, "A", ""); 894 return 0; 895 } 896 897 void 898 mixer_hwvol_mute_locked(struct snd_mixer *m) 899 { 900 if (m->hwvol_muted) { 901 m->hwvol_muted = 0; 902 mixer_set(m, m->hwvol_mixer, m->hwvol_mute_level); 903 } else { 904 m->hwvol_muted++; 905 m->hwvol_mute_level = mixer_get(m, m->hwvol_mixer); 906 mixer_set(m, m->hwvol_mixer, 0); 907 } 908 } 909 910 void 911 mixer_hwvol_mute(device_t dev) 912 { 913 struct snd_mixer *m; 914 struct cdev *pdev; 915 916 pdev = mixer_get_devt(dev); 917 m = pdev->si_drv1; 918 snd_mtxlock(m->lock); 919 mixer_hwvol_mute_locked(m); 920 snd_mtxunlock(m->lock); 921 } 922 923 void 924 mixer_hwvol_step_locked(struct snd_mixer *m, int left_step, int right_step) 925 { 926 int level, left, right; 927 928 if (m->hwvol_muted) { 929 m->hwvol_muted = 0; 930 level = m->hwvol_mute_level; 931 } else 932 level = mixer_get(m, m->hwvol_mixer); 933 if (level != -1) { 934 left = level & 0xff; 935 right = (level >> 8) & 0xff; 936 left += left_step * m->hwvol_step; 937 if (left < 0) 938 left = 0; 939 else if (left > 100) 940 left = 100; 941 right += right_step * m->hwvol_step; 942 if (right < 0) 943 right = 0; 944 else if (right > 100) 945 right = 100; 946 mixer_set(m, m->hwvol_mixer, 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, 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_DETACHING(d) || !PCM_REGISTERED(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_DETACHING(d) || !PCM_REGISTERED(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 case SNDCTL_AUDIOINFO_EX: 1268 case SNDCTL_ENGINEINFO: 1269 return (dsp_oss_audioinfo(i_dev, (oss_audioinfo *)arg)); 1270 case SNDCTL_MIXERINFO: 1271 return (mixer_oss_mixerinfo(i_dev, (oss_mixerinfo *)arg)); 1272 } 1273 return (EINVAL); 1274 } 1275 1276 m = i_dev->si_drv1; 1277 1278 if (m == NULL) 1279 return (EBADF); 1280 1281 snd_mtxlock(m->lock); 1282 if (from == MIXER_CMD_CDEV && !m->busy) { 1283 snd_mtxunlock(m->lock); 1284 return (EBADF); 1285 } 1286 switch (cmd) { 1287 case SNDCTL_DSP_GET_RECSRC_NAMES: 1288 bcopy((void *)&m->enuminfo, arg, sizeof(oss_mixer_enuminfo)); 1289 ret = 0; 1290 goto done; 1291 case SNDCTL_DSP_GET_RECSRC: 1292 ret = mixer_get_recroute(m, arg_i); 1293 goto done; 1294 case SNDCTL_DSP_SET_RECSRC: 1295 ret = mixer_set_recroute(m, *arg_i); 1296 goto done; 1297 case OSS_GETVERSION: 1298 *arg_i = SOUND_VERSION; 1299 ret = 0; 1300 goto done; 1301 case SOUND_MIXER_INFO: 1302 mixer_mixerinfo(m, (mixer_info *)arg); 1303 ret = 0; 1304 goto done; 1305 } 1306 if ((cmd & ~0xff) == MIXER_WRITE(0)) { 1307 if (j == SOUND_MIXER_RECSRC) 1308 ret = mixer_setrecsrc(m, *arg_i); 1309 else 1310 ret = mixer_set(m, j, *arg_i); 1311 snd_mtxunlock(m->lock); 1312 return ((ret == 0) ? 0 : ENXIO); 1313 } 1314 if ((cmd & ~0xff) == MIXER_READ(0)) { 1315 switch (j) { 1316 case SOUND_MIXER_DEVMASK: 1317 case SOUND_MIXER_CAPS: 1318 case SOUND_MIXER_STEREODEVS: 1319 v = mix_getdevs(m); 1320 break; 1321 case SOUND_MIXER_RECMASK: 1322 v = mix_getrecdevs(m); 1323 break; 1324 case SOUND_MIXER_RECSRC: 1325 v = mixer_getrecsrc(m); 1326 break; 1327 default: 1328 v = mixer_get(m, j); 1329 } 1330 *arg_i = v; 1331 snd_mtxunlock(m->lock); 1332 return ((v != -1) ? 0 : ENXIO); 1333 } 1334 done: 1335 snd_mtxunlock(m->lock); 1336 return (ret); 1337 } 1338 1339 static void 1340 mixer_clone(void *arg, 1341 struct ucred *cred, 1342 char *name, int namelen, struct cdev **dev) 1343 { 1344 struct snddev_info *d; 1345 1346 if (*dev != NULL) 1347 return; 1348 if (strcmp(name, "mixer") == 0) { 1349 d = devclass_get_softc(pcm_devclass, snd_unit); 1350 if (PCM_REGISTERED(d) && d->mixer_dev != NULL) { 1351 *dev = d->mixer_dev; 1352 dev_ref(*dev); 1353 } 1354 } 1355 } 1356 1357 static void 1358 mixer_sysinit(void *p) 1359 { 1360 if (mixer_ehtag != NULL) 1361 return; 1362 mixer_ehtag = EVENTHANDLER_REGISTER(dev_clone, mixer_clone, 0, 1000); 1363 } 1364 1365 static void 1366 mixer_sysuninit(void *p) 1367 { 1368 if (mixer_ehtag == NULL) 1369 return; 1370 EVENTHANDLER_DEREGISTER(dev_clone, mixer_ehtag); 1371 mixer_ehtag = NULL; 1372 } 1373 1374 SYSINIT(mixer_sysinit, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, mixer_sysinit, NULL); 1375 SYSUNINIT(mixer_sysuninit, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, mixer_sysuninit, NULL); 1376 1377 /** 1378 * @brief Handler for SNDCTL_MIXERINFO 1379 * 1380 * This function searches for a mixer based on the numeric ID stored 1381 * in oss_miserinfo::dev. If set to -1, then information about the 1382 * current mixer handling the request is provided. Note, however, that 1383 * this ioctl may be made with any sound device (audio, mixer, midi). 1384 * 1385 * @note Caller must not hold any PCM device, channel, or mixer locks. 1386 * 1387 * See http://manuals.opensound.com/developer/SNDCTL_MIXERINFO.html for 1388 * more information. 1389 * 1390 * @param i_dev character device on which the ioctl arrived 1391 * @param arg user argument (oss_mixerinfo *) 1392 * 1393 * @retval EINVAL oss_mixerinfo::dev specified a bad value 1394 * @retval 0 success 1395 */ 1396 int 1397 mixer_oss_mixerinfo(struct cdev *i_dev, oss_mixerinfo *mi) 1398 { 1399 struct snddev_info *d; 1400 struct snd_mixer *m; 1401 int nmix, i; 1402 1403 /* 1404 * If probing the device handling the ioctl, make sure it's a mixer 1405 * device. (This ioctl is valid on audio, mixer, and midi devices.) 1406 */ 1407 if (mi->dev == -1 && i_dev->si_devsw != &mixer_cdevsw) 1408 return (EINVAL); 1409 1410 d = NULL; 1411 m = NULL; 1412 nmix = 0; 1413 1414 /* 1415 * There's a 1:1 relationship between mixers and PCM devices, so 1416 * begin by iterating over PCM devices and search for our mixer. 1417 */ 1418 for (i = 0; pcm_devclass != NULL && 1419 i < devclass_get_maxunit(pcm_devclass); i++) { 1420 d = devclass_get_softc(pcm_devclass, i); 1421 if (PCM_DETACHING(d) || !PCM_REGISTERED(d)) 1422 continue; 1423 1424 /* XXX Need Giant magic entry */ 1425 1426 /* See the note in function docblock. */ 1427 PCM_UNLOCKASSERT(d); 1428 PCM_LOCK(d); 1429 1430 if (d->mixer_dev != NULL && d->mixer_dev->si_drv1 != NULL && 1431 ((mi->dev == -1 && d->mixer_dev == i_dev) || 1432 mi->dev == nmix)) { 1433 m = d->mixer_dev->si_drv1; 1434 mtx_lock(m->lock); 1435 1436 /* 1437 * At this point, the following synchronization stuff 1438 * has happened: 1439 * - a specific PCM device is locked. 1440 * - a specific mixer device has been locked, so be 1441 * sure to unlock when existing. 1442 */ 1443 bzero((void *)mi, sizeof(*mi)); 1444 mi->dev = nmix; 1445 snprintf(mi->id, sizeof(mi->id), "mixer%d", i); 1446 strlcpy(mi->name, m->name, sizeof(mi->name)); 1447 mi->modify_counter = m->modify_counter; 1448 mi->card_number = i; 1449 /* 1450 * Currently, FreeBSD assumes 1:1 relationship between 1451 * a pcm and mixer devices, so this is hardcoded to 0. 1452 */ 1453 mi->port_number = 0; 1454 1455 /** 1456 * @todo Fill in @sa oss_mixerinfo::mixerhandle. 1457 * @note From 4Front: "mixerhandle is an arbitrary 1458 * string that identifies the mixer better than 1459 * the device number (mixerinfo.dev). Device 1460 * numbers may change depending on the order the 1461 * drivers are loaded. However the handle should 1462 * remain the same provided that the sound card 1463 * is not moved to another PCI slot." 1464 */ 1465 1466 /** 1467 * @note 1468 * @sa oss_mixerinfo::magic is a reserved field. 1469 * 1470 * @par 1471 * From 4Front: "magic is usually 0. However some 1472 * devices may have dedicated setup utilities and the 1473 * magic field may contain an unique driver specific 1474 * value (managed by [4Front])." 1475 */ 1476 1477 mi->enabled = device_is_attached(m->dev) ? 1 : 0; 1478 /** 1479 * The only flag for @sa oss_mixerinfo::caps is 1480 * currently MIXER_CAP_VIRTUAL, which I'm not sure we 1481 * really worry about. 1482 */ 1483 /** 1484 * Mixer extensions currently aren't supported, so 1485 * leave @sa oss_mixerinfo::nrext blank for now. 1486 */ 1487 /** 1488 * @todo Fill in @sa oss_mixerinfo::priority (requires 1489 * touching drivers?) 1490 * @note The priority field is for mixer applets to 1491 * determine which mixer should be the default, with 0 1492 * being least preferred and 10 being most preferred. 1493 * From 4Front: "OSS drivers like ICH use higher 1494 * values (10) because such chips are known to be used 1495 * only on motherboards. Drivers for high end pro 1496 * devices use 0 because they will never be the 1497 * default mixer. Other devices use values 1 to 9 1498 * depending on the estimated probability of being the 1499 * default device. 1500 * 1501 * XXX Described by Hannu@4Front, but not found in 1502 * soundcard.h. 1503 strlcpy(mi->devnode, devtoname(d->mixer_dev), 1504 sizeof(mi->devnode)); 1505 mi->legacy_device = i; 1506 */ 1507 mtx_unlock(m->lock); 1508 } else 1509 ++nmix; 1510 1511 PCM_UNLOCK(d); 1512 1513 if (m != NULL) 1514 return (0); 1515 } 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 if (m->lock == NULL) { 1528 return (&Giant); 1529 } 1530 return (m->lock); 1531 } 1532 1533 int 1534 mix_get_locked(struct snd_mixer *m, u_int dev, int *pleft, int *pright) 1535 { 1536 int level; 1537 1538 level = mixer_get(m, dev); 1539 if (level < 0) { 1540 *pright = *pleft = -1; 1541 return (-1); 1542 } 1543 1544 *pleft = level & 0xFF; 1545 *pright = (level >> 8) & 0xFF; 1546 1547 return (0); 1548 } 1549 1550 int 1551 mix_set_locked(struct snd_mixer *m, u_int dev, int left, int right) 1552 { 1553 int level; 1554 1555 level = (left & 0xFF) | ((right & 0xFF) << 8); 1556 1557 return (mixer_set(m, dev, level)); 1558 } 1559