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