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