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 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)), 892 OID_AUTO, "hwvol_mixer", CTLTYPE_STRING | CTLFLAG_RWTUN, m, 0, 893 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 /* ----------------------------------------------------------------------- */ 1036 1037 static int 1038 mixer_open(struct cdev *i_dev, int flags, int mode, struct thread *td) 1039 { 1040 struct snddev_info *d; 1041 struct snd_mixer *m; 1042 1043 1044 if (i_dev == NULL || i_dev->si_drv1 == NULL) 1045 return (EBADF); 1046 1047 m = i_dev->si_drv1; 1048 d = device_get_softc(m->dev); 1049 if (!PCM_REGISTERED(d)) 1050 return (EBADF); 1051 1052 /* XXX Need Giant magic entry ??? */ 1053 1054 snd_mtxlock(m->lock); 1055 m->busy = 1; 1056 snd_mtxunlock(m->lock); 1057 1058 return (0); 1059 } 1060 1061 static int 1062 mixer_close(struct cdev *i_dev, int flags, int mode, struct thread *td) 1063 { 1064 struct snddev_info *d; 1065 struct snd_mixer *m; 1066 int ret; 1067 1068 if (i_dev == NULL || i_dev->si_drv1 == NULL) 1069 return (EBADF); 1070 1071 m = i_dev->si_drv1; 1072 d = device_get_softc(m->dev); 1073 if (!PCM_REGISTERED(d)) 1074 return (EBADF); 1075 1076 /* XXX Need Giant magic entry ??? */ 1077 1078 snd_mtxlock(m->lock); 1079 ret = (m->busy == 0) ? EBADF : 0; 1080 m->busy = 0; 1081 snd_mtxunlock(m->lock); 1082 1083 return (ret); 1084 } 1085 1086 static int 1087 mixer_ioctl_channel(struct cdev *dev, u_long cmd, caddr_t arg, int mode, 1088 struct thread *td, int from) 1089 { 1090 struct snddev_info *d; 1091 struct snd_mixer *m; 1092 struct pcm_channel *c, *rdch, *wrch; 1093 pid_t pid; 1094 int j, ret; 1095 1096 if (td == NULL || td->td_proc == NULL) 1097 return (-1); 1098 1099 m = dev->si_drv1; 1100 d = device_get_softc(m->dev); 1101 j = cmd & 0xff; 1102 1103 switch (j) { 1104 case SOUND_MIXER_PCM: 1105 case SOUND_MIXER_RECLEV: 1106 case SOUND_MIXER_DEVMASK: 1107 case SOUND_MIXER_CAPS: 1108 case SOUND_MIXER_STEREODEVS: 1109 break; 1110 default: 1111 return (-1); 1112 break; 1113 } 1114 1115 pid = td->td_proc->p_pid; 1116 rdch = NULL; 1117 wrch = NULL; 1118 c = NULL; 1119 ret = -1; 1120 1121 /* 1122 * This is unfair. Imagine single proc opening multiple 1123 * instances of same direction. What we do right now 1124 * is looking for the first matching proc/pid, and just 1125 * that. Nothing more. Consider it done. 1126 * 1127 * The better approach of controlling specific channel 1128 * pcm or rec volume is by doing mixer ioctl 1129 * (SNDCTL_DSP_[SET|GET][PLAY|REC]VOL / SOUND_MIXER_[PCM|RECLEV] 1130 * on its open fd, rather than cracky mixer bypassing here. 1131 */ 1132 CHN_FOREACH(c, d, channels.pcm.opened) { 1133 CHN_LOCK(c); 1134 if (c->pid != pid || 1135 !(c->feederflags & (1 << FEEDER_VOLUME))) { 1136 CHN_UNLOCK(c); 1137 continue; 1138 } 1139 if (rdch == NULL && c->direction == PCMDIR_REC) { 1140 rdch = c; 1141 if (j == SOUND_MIXER_RECLEV) 1142 goto mixer_ioctl_channel_proc; 1143 } else if (wrch == NULL && c->direction == PCMDIR_PLAY) { 1144 wrch = c; 1145 if (j == SOUND_MIXER_PCM) 1146 goto mixer_ioctl_channel_proc; 1147 } 1148 CHN_UNLOCK(c); 1149 if (rdch != NULL && wrch != NULL) 1150 break; 1151 } 1152 1153 if (rdch == NULL && wrch == NULL) 1154 return (-1); 1155 1156 if ((j == SOUND_MIXER_DEVMASK || j == SOUND_MIXER_CAPS || 1157 j == SOUND_MIXER_STEREODEVS) && 1158 (cmd & ~0xff) == MIXER_READ(0)) { 1159 snd_mtxlock(m->lock); 1160 *(int *)arg = mix_getdevs(m); 1161 snd_mtxunlock(m->lock); 1162 if (rdch != NULL) 1163 *(int *)arg |= SOUND_MASK_RECLEV; 1164 if (wrch != NULL) 1165 *(int *)arg |= SOUND_MASK_PCM; 1166 ret = 0; 1167 } 1168 1169 return (ret); 1170 1171 mixer_ioctl_channel_proc: 1172 1173 KASSERT(c != NULL, ("%s(): NULL channel", __func__)); 1174 CHN_LOCKASSERT(c); 1175 1176 if ((cmd & ~0xff) == MIXER_WRITE(0)) { 1177 int left, right, center; 1178 1179 left = *(int *)arg & 0x7f; 1180 right = (*(int *)arg >> 8) & 0x7f; 1181 center = (left + right) >> 1; 1182 chn_setvolume_multi(c, SND_VOL_C_PCM, left, right, center); 1183 } else if ((cmd & ~0xff) == MIXER_READ(0)) { 1184 *(int *)arg = CHN_GETVOLUME(c, SND_VOL_C_PCM, SND_CHN_T_FL); 1185 *(int *)arg |= 1186 CHN_GETVOLUME(c, SND_VOL_C_PCM, SND_CHN_T_FR) << 8; 1187 } 1188 1189 CHN_UNLOCK(c); 1190 1191 return (0); 1192 } 1193 1194 static int 1195 mixer_ioctl(struct cdev *i_dev, u_long cmd, caddr_t arg, int mode, 1196 struct thread *td) 1197 { 1198 struct snddev_info *d; 1199 int ret; 1200 1201 if (i_dev == NULL || i_dev->si_drv1 == NULL) 1202 return (EBADF); 1203 1204 d = device_get_softc(((struct snd_mixer *)i_dev->si_drv1)->dev); 1205 if (!PCM_REGISTERED(d)) 1206 return (EBADF); 1207 1208 PCM_GIANT_ENTER(d); 1209 PCM_ACQUIRE_QUICK(d); 1210 1211 ret = -1; 1212 1213 if (mixer_bypass != 0 && (d->flags & SD_F_VPC)) 1214 ret = mixer_ioctl_channel(i_dev, cmd, arg, mode, td, 1215 MIXER_CMD_CDEV); 1216 1217 if (ret == -1) 1218 ret = mixer_ioctl_cmd(i_dev, cmd, arg, mode, td, 1219 MIXER_CMD_CDEV); 1220 1221 PCM_RELEASE_QUICK(d); 1222 PCM_GIANT_LEAVE(d); 1223 1224 return (ret); 1225 } 1226 1227 static void 1228 mixer_mixerinfo(struct snd_mixer *m, mixer_info *mi) 1229 { 1230 bzero((void *)mi, sizeof(*mi)); 1231 strlcpy(mi->id, m->name, sizeof(mi->id)); 1232 strlcpy(mi->name, device_get_desc(m->dev), sizeof(mi->name)); 1233 mi->modify_counter = m->modify_counter; 1234 } 1235 1236 /* 1237 * XXX Make sure you can guarantee concurrency safety before calling this 1238 * function, be it through Giant, PCM_*, etc ! 1239 */ 1240 int 1241 mixer_ioctl_cmd(struct cdev *i_dev, u_long cmd, caddr_t arg, int mode, 1242 struct thread *td, int from) 1243 { 1244 struct snd_mixer *m; 1245 int ret = EINVAL, *arg_i = (int *)arg; 1246 int v = -1, j = cmd & 0xff; 1247 1248 /* 1249 * Certain ioctls may be made on any type of device (audio, mixer, 1250 * and MIDI). Handle those special cases here. 1251 */ 1252 if (IOCGROUP(cmd) == 'X') { 1253 switch (cmd) { 1254 case SNDCTL_SYSINFO: 1255 sound_oss_sysinfo((oss_sysinfo *)arg); 1256 return (0); 1257 case SNDCTL_CARDINFO: 1258 return (sound_oss_card_info((oss_card_info *)arg)); 1259 case SNDCTL_AUDIOINFO: 1260 case SNDCTL_AUDIOINFO_EX: 1261 case SNDCTL_ENGINEINFO: 1262 return (dsp_oss_audioinfo(i_dev, (oss_audioinfo *)arg)); 1263 case SNDCTL_MIXERINFO: 1264 return (mixer_oss_mixerinfo(i_dev, (oss_mixerinfo *)arg)); 1265 } 1266 return (EINVAL); 1267 } 1268 1269 m = i_dev->si_drv1; 1270 1271 if (m == NULL) 1272 return (EBADF); 1273 1274 snd_mtxlock(m->lock); 1275 if (from == MIXER_CMD_CDEV && !m->busy) { 1276 snd_mtxunlock(m->lock); 1277 return (EBADF); 1278 } 1279 switch (cmd) { 1280 case SNDCTL_DSP_GET_RECSRC_NAMES: 1281 bcopy((void *)&m->enuminfo, arg, sizeof(oss_mixer_enuminfo)); 1282 ret = 0; 1283 goto done; 1284 case SNDCTL_DSP_GET_RECSRC: 1285 ret = mixer_get_recroute(m, arg_i); 1286 goto done; 1287 case SNDCTL_DSP_SET_RECSRC: 1288 ret = mixer_set_recroute(m, *arg_i); 1289 goto done; 1290 case OSS_GETVERSION: 1291 *arg_i = SOUND_VERSION; 1292 ret = 0; 1293 goto done; 1294 case SOUND_MIXER_INFO: 1295 mixer_mixerinfo(m, (mixer_info *)arg); 1296 ret = 0; 1297 goto done; 1298 } 1299 if ((cmd & ~0xff) == MIXER_WRITE(0)) { 1300 if (j == SOUND_MIXER_RECSRC) 1301 ret = mixer_setrecsrc(m, *arg_i); 1302 else 1303 ret = mixer_set(m, j, *arg_i); 1304 snd_mtxunlock(m->lock); 1305 return ((ret == 0) ? 0 : ENXIO); 1306 } 1307 if ((cmd & ~0xff) == MIXER_READ(0)) { 1308 switch (j) { 1309 case SOUND_MIXER_DEVMASK: 1310 case SOUND_MIXER_CAPS: 1311 case SOUND_MIXER_STEREODEVS: 1312 v = mix_getdevs(m); 1313 break; 1314 case SOUND_MIXER_RECMASK: 1315 v = mix_getrecdevs(m); 1316 break; 1317 case SOUND_MIXER_RECSRC: 1318 v = mixer_getrecsrc(m); 1319 break; 1320 default: 1321 v = mixer_get(m, j); 1322 } 1323 *arg_i = v; 1324 snd_mtxunlock(m->lock); 1325 return ((v != -1) ? 0 : ENXIO); 1326 } 1327 done: 1328 snd_mtxunlock(m->lock); 1329 return (ret); 1330 } 1331 1332 static void 1333 mixer_clone(void *arg, 1334 struct ucred *cred, 1335 char *name, int namelen, struct cdev **dev) 1336 { 1337 struct snddev_info *d; 1338 1339 if (*dev != NULL) 1340 return; 1341 if (strcmp(name, "mixer") == 0) { 1342 d = devclass_get_softc(pcm_devclass, snd_unit); 1343 if (PCM_REGISTERED(d) && d->mixer_dev != NULL) { 1344 *dev = d->mixer_dev; 1345 dev_ref(*dev); 1346 } 1347 } 1348 } 1349 1350 static void 1351 mixer_sysinit(void *p) 1352 { 1353 if (mixer_ehtag != NULL) 1354 return; 1355 mixer_ehtag = EVENTHANDLER_REGISTER(dev_clone, mixer_clone, 0, 1000); 1356 } 1357 1358 static void 1359 mixer_sysuninit(void *p) 1360 { 1361 if (mixer_ehtag == NULL) 1362 return; 1363 EVENTHANDLER_DEREGISTER(dev_clone, mixer_ehtag); 1364 mixer_ehtag = NULL; 1365 } 1366 1367 SYSINIT(mixer_sysinit, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, mixer_sysinit, NULL); 1368 SYSUNINIT(mixer_sysuninit, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, mixer_sysuninit, NULL); 1369 1370 /** 1371 * @brief Handler for SNDCTL_MIXERINFO 1372 * 1373 * This function searches for a mixer based on the numeric ID stored 1374 * in oss_miserinfo::dev. If set to -1, then information about the 1375 * current mixer handling the request is provided. Note, however, that 1376 * this ioctl may be made with any sound device (audio, mixer, midi). 1377 * 1378 * @note Caller must not hold any PCM device, channel, or mixer locks. 1379 * 1380 * See http://manuals.opensound.com/developer/SNDCTL_MIXERINFO.html for 1381 * more information. 1382 * 1383 * @param i_dev character device on which the ioctl arrived 1384 * @param arg user argument (oss_mixerinfo *) 1385 * 1386 * @retval EINVAL oss_mixerinfo::dev specified a bad value 1387 * @retval 0 success 1388 */ 1389 int 1390 mixer_oss_mixerinfo(struct cdev *i_dev, oss_mixerinfo *mi) 1391 { 1392 struct snddev_info *d; 1393 struct snd_mixer *m; 1394 int nmix, i; 1395 1396 /* 1397 * If probing the device handling the ioctl, make sure it's a mixer 1398 * device. (This ioctl is valid on audio, mixer, and midi devices.) 1399 */ 1400 if (mi->dev == -1 && i_dev->si_devsw != &mixer_cdevsw) 1401 return (EINVAL); 1402 1403 d = NULL; 1404 m = NULL; 1405 nmix = 0; 1406 1407 /* 1408 * There's a 1:1 relationship between mixers and PCM devices, so 1409 * begin by iterating over PCM devices and search for our mixer. 1410 */ 1411 for (i = 0; pcm_devclass != NULL && 1412 i < devclass_get_maxunit(pcm_devclass); i++) { 1413 d = devclass_get_softc(pcm_devclass, i); 1414 if (!PCM_REGISTERED(d)) 1415 continue; 1416 1417 /* XXX Need Giant magic entry */ 1418 1419 /* See the note in function docblock. */ 1420 PCM_UNLOCKASSERT(d); 1421 PCM_LOCK(d); 1422 1423 if (d->mixer_dev != NULL && d->mixer_dev->si_drv1 != NULL && 1424 ((mi->dev == -1 && d->mixer_dev == i_dev) || 1425 mi->dev == nmix)) { 1426 m = d->mixer_dev->si_drv1; 1427 mtx_lock(m->lock); 1428 1429 /* 1430 * At this point, the following synchronization stuff 1431 * has happened: 1432 * - a specific PCM device is locked. 1433 * - a specific mixer device has been locked, so be 1434 * sure to unlock when existing. 1435 */ 1436 bzero((void *)mi, sizeof(*mi)); 1437 mi->dev = nmix; 1438 snprintf(mi->id, sizeof(mi->id), "mixer%d", i); 1439 strlcpy(mi->name, m->name, sizeof(mi->name)); 1440 mi->modify_counter = m->modify_counter; 1441 mi->card_number = i; 1442 /* 1443 * Currently, FreeBSD assumes 1:1 relationship between 1444 * a pcm and mixer devices, so this is hardcoded to 0. 1445 */ 1446 mi->port_number = 0; 1447 1448 /** 1449 * @todo Fill in @sa oss_mixerinfo::mixerhandle. 1450 * @note From 4Front: "mixerhandle is an arbitrary 1451 * string that identifies the mixer better than 1452 * the device number (mixerinfo.dev). Device 1453 * numbers may change depending on the order the 1454 * drivers are loaded. However the handle should 1455 * remain the same provided that the sound card 1456 * is not moved to another PCI slot." 1457 */ 1458 1459 /** 1460 * @note 1461 * @sa oss_mixerinfo::magic is a reserved field. 1462 * 1463 * @par 1464 * From 4Front: "magic is usually 0. However some 1465 * devices may have dedicated setup utilities and the 1466 * magic field may contain an unique driver specific 1467 * value (managed by [4Front])." 1468 */ 1469 1470 mi->enabled = device_is_attached(m->dev) ? 1 : 0; 1471 /** 1472 * The only flag for @sa oss_mixerinfo::caps is 1473 * currently MIXER_CAP_VIRTUAL, which I'm not sure we 1474 * really worry about. 1475 */ 1476 /** 1477 * Mixer extensions currently aren't supported, so 1478 * leave @sa oss_mixerinfo::nrext blank for now. 1479 */ 1480 /** 1481 * @todo Fill in @sa oss_mixerinfo::priority (requires 1482 * touching drivers?) 1483 * @note The priority field is for mixer applets to 1484 * determine which mixer should be the default, with 0 1485 * being least preferred and 10 being most preferred. 1486 * From 4Front: "OSS drivers like ICH use higher 1487 * values (10) because such chips are known to be used 1488 * only on motherboards. Drivers for high end pro 1489 * devices use 0 because they will never be the 1490 * default mixer. Other devices use values 1 to 9 1491 * depending on the estimated probability of being the 1492 * default device. 1493 * 1494 * XXX Described by Hannu@4Front, but not found in 1495 * soundcard.h. 1496 strlcpy(mi->devnode, devtoname(d->mixer_dev), 1497 sizeof(mi->devnode)); 1498 mi->legacy_device = i; 1499 */ 1500 mtx_unlock(m->lock); 1501 } else 1502 ++nmix; 1503 1504 PCM_UNLOCK(d); 1505 1506 if (m != NULL) 1507 return (0); 1508 } 1509 1510 return (EINVAL); 1511 } 1512 1513 /* 1514 * Allow the sound driver to use the mixer lock to protect its mixer 1515 * data: 1516 */ 1517 struct mtx * 1518 mixer_get_lock(struct snd_mixer *m) 1519 { 1520 if (m->lock == NULL) { 1521 return (&Giant); 1522 } 1523 return (m->lock); 1524 } 1525 1526 int 1527 mix_get_locked(struct snd_mixer *m, u_int dev, int *pleft, int *pright) 1528 { 1529 int level; 1530 1531 level = mixer_get(m, dev); 1532 if (level < 0) { 1533 *pright = *pleft = -1; 1534 return (-1); 1535 } 1536 1537 *pleft = level & 0xFF; 1538 *pright = (level >> 8) & 0xFF; 1539 1540 return (0); 1541 } 1542 1543 int 1544 mix_set_locked(struct snd_mixer *m, u_int dev, int left, int right) 1545 { 1546 int level; 1547 1548 level = (left & 0xFF) | ((right & 0xFF) << 8); 1549 1550 return (mixer_set(m, dev, level)); 1551 } 1552