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