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