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