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