1 /*- 2 * Copyright (c) 1999 Cameron Grant <cg@freebsd.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27 #include <dev/sound/pcm/sound.h> 28 29 #include "mixer_if.h" 30 31 SND_DECLARE_FILE("$FreeBSD$"); 32 33 MALLOC_DEFINE(M_MIXER, "mixer", "mixer"); 34 35 #define MIXER_NAMELEN 16 36 struct snd_mixer { 37 KOBJ_FIELDS; 38 const char *type; 39 void *devinfo; 40 int busy; 41 int hwvol_muted; 42 int hwvol_mixer; 43 int hwvol_step; 44 device_t dev; 45 u_int32_t hwvol_mute_level; 46 u_int32_t devs; 47 u_int32_t recdevs; 48 u_int32_t recsrc; 49 u_int16_t level[32]; 50 u_int8_t parent[32]; 51 u_int32_t child[32]; 52 u_int8_t realdev[32]; 53 char name[MIXER_NAMELEN]; 54 struct mtx *lock; 55 oss_mixer_enuminfo enuminfo; 56 /** 57 * Counter is incremented when applications change any of this 58 * mixer's controls. A change in value indicates that persistent 59 * mixer applications should update their displays. 60 */ 61 int modify_counter; 62 }; 63 64 static u_int16_t snd_mixerdefaults[SOUND_MIXER_NRDEVICES] = { 65 [SOUND_MIXER_VOLUME] = 75, 66 [SOUND_MIXER_BASS] = 50, 67 [SOUND_MIXER_TREBLE] = 50, 68 [SOUND_MIXER_SYNTH] = 75, 69 [SOUND_MIXER_PCM] = 75, 70 [SOUND_MIXER_SPEAKER] = 75, 71 [SOUND_MIXER_LINE] = 75, 72 [SOUND_MIXER_MIC] = 0, 73 [SOUND_MIXER_CD] = 75, 74 [SOUND_MIXER_IGAIN] = 0, 75 [SOUND_MIXER_LINE1] = 75, 76 [SOUND_MIXER_VIDEO] = 75, 77 [SOUND_MIXER_RECLEV] = 0, 78 [SOUND_MIXER_OGAIN] = 50, 79 [SOUND_MIXER_MONITOR] = 75, 80 }; 81 82 static char* snd_mixernames[SOUND_MIXER_NRDEVICES] = SOUND_DEVICE_NAMES; 83 84 static d_open_t mixer_open; 85 static d_close_t mixer_close; 86 87 static struct cdevsw mixer_cdevsw = { 88 .d_version = D_VERSION, 89 .d_flags = D_NEEDGIANT, 90 .d_open = mixer_open, 91 .d_close = mixer_close, 92 .d_ioctl = mixer_ioctl, 93 .d_name = "mixer", 94 }; 95 96 /** 97 * Keeps a count of mixer devices; used only by OSSv4 SNDCTL_SYSINFO ioctl. 98 */ 99 int mixer_count = 0; 100 101 #ifdef USING_DEVFS 102 static eventhandler_tag mixer_ehtag; 103 #endif 104 105 static struct cdev * 106 mixer_get_devt(device_t dev) 107 { 108 struct snddev_info *snddev; 109 110 snddev = device_get_softc(dev); 111 112 return snddev->mixer_dev; 113 } 114 115 #ifdef SND_DYNSYSCTL 116 static int 117 mixer_lookup(char *devname) 118 { 119 int i; 120 121 for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) 122 if (strncmp(devname, snd_mixernames[i], 123 strlen(snd_mixernames[i])) == 0) 124 return i; 125 return -1; 126 } 127 #endif 128 129 static int 130 mixer_set_softpcmvol(struct snd_mixer *mixer, struct snddev_info *d, 131 unsigned left, unsigned right) 132 { 133 struct snddev_channel *sce; 134 struct pcm_channel *ch; 135 #ifdef USING_MUTEX 136 int locked = (mixer->lock && mtx_owned((struct mtx *)(mixer->lock))) ? 1 : 0; 137 138 if (locked) 139 snd_mtxunlock(mixer->lock); 140 #endif 141 SLIST_FOREACH(sce, &d->channels, link) { 142 ch = sce->channel; 143 CHN_LOCK(ch); 144 if (ch->direction == PCMDIR_PLAY && 145 (ch->feederflags & (1 << FEEDER_VOLUME))) 146 chn_setvolume(ch, left, right); 147 CHN_UNLOCK(ch); 148 } 149 #ifdef USING_MUTEX 150 if (locked) 151 snd_mtxlock(mixer->lock); 152 #endif 153 return 0; 154 } 155 156 static int 157 mixer_set(struct snd_mixer *m, unsigned dev, unsigned lev) 158 { 159 struct snddev_info *d; 160 unsigned l, r, tl, tr; 161 u_int32_t parent = SOUND_MIXER_NONE, child = 0; 162 u_int32_t realdev; 163 int i; 164 165 if (m == NULL || dev >= SOUND_MIXER_NRDEVICES || 166 (0 == (m->devs & (1 << dev)))) 167 return -1; 168 169 l = min((lev & 0x00ff), 100); 170 r = min(((lev & 0xff00) >> 8), 100); 171 realdev = m->realdev[dev]; 172 173 d = device_get_softc(m->dev); 174 if (d == NULL) 175 return -1; 176 177 /* TODO: recursive handling */ 178 parent = m->parent[dev]; 179 if (parent >= SOUND_MIXER_NRDEVICES) 180 parent = SOUND_MIXER_NONE; 181 if (parent == SOUND_MIXER_NONE) 182 child = m->child[dev]; 183 184 if (parent != SOUND_MIXER_NONE) { 185 tl = (l * (m->level[parent] & 0x00ff)) / 100; 186 tr = (r * ((m->level[parent] & 0xff00) >> 8)) / 100; 187 if (dev == SOUND_MIXER_PCM && (d->flags & SD_F_SOFTPCMVOL)) 188 mixer_set_softpcmvol(m, d, tl, tr); 189 else if (realdev != SOUND_MIXER_NONE && 190 MIXER_SET(m, realdev, tl, tr) < 0) 191 return -1; 192 } else if (child != 0) { 193 for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) { 194 if (!(child & (1 << i)) || m->parent[i] != dev) 195 continue; 196 realdev = m->realdev[i]; 197 tl = (l * (m->level[i] & 0x00ff)) / 100; 198 tr = (r * ((m->level[i] & 0xff00) >> 8)) / 100; 199 if (i == SOUND_MIXER_PCM && (d->flags & SD_F_SOFTPCMVOL)) 200 mixer_set_softpcmvol(m, d, tl, tr); 201 else if (realdev != SOUND_MIXER_NONE) 202 MIXER_SET(m, realdev, tl, tr); 203 } 204 realdev = m->realdev[dev]; 205 if (realdev != SOUND_MIXER_NONE && 206 MIXER_SET(m, realdev, l, r) < 0) 207 return -1; 208 } else { 209 if (dev == SOUND_MIXER_PCM && (d->flags & SD_F_SOFTPCMVOL)) 210 mixer_set_softpcmvol(m, d, l, r); 211 else if (realdev != SOUND_MIXER_NONE && 212 MIXER_SET(m, realdev, l, r) < 0) 213 return -1; 214 } 215 216 m->level[dev] = l | (r << 8); 217 218 return 0; 219 } 220 221 static int 222 mixer_get(struct snd_mixer *mixer, int dev) 223 { 224 if ((dev < SOUND_MIXER_NRDEVICES) && (mixer->devs & (1 << dev))) 225 return mixer->level[dev]; 226 else return -1; 227 } 228 229 static int 230 mixer_setrecsrc(struct snd_mixer *mixer, u_int32_t src) 231 { 232 src &= mixer->recdevs; 233 if (src == 0) 234 src = SOUND_MASK_MIC; 235 mixer->recsrc = MIXER_SETRECSRC(mixer, src); 236 return 0; 237 } 238 239 static int 240 mixer_getrecsrc(struct snd_mixer *mixer) 241 { 242 return mixer->recsrc; 243 } 244 245 /** 246 * @brief Retrieve the route number of the current recording device 247 * 248 * OSSv4 assigns routing numbers to recording devices, unlike the previous 249 * API which relied on a fixed table of device numbers and names. This 250 * function returns the routing number of the device currently selected 251 * for recording. 252 * 253 * For now, this function is kind of a goofy compatibility stub atop the 254 * existing sound system. (For example, in theory, the old sound system 255 * allows multiple recording devices to be specified via a bitmask.) 256 * 257 * @param m mixer context container thing 258 * 259 * @retval 0 success 260 * @retval EIDRM no recording device found (generally not possible) 261 * @todo Ask about error code 262 */ 263 static int 264 mixer_get_recroute(struct snd_mixer *m, int *route) 265 { 266 int i, cnt; 267 268 cnt = 0; 269 270 for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) { 271 /** @todo can user set a multi-device mask? (== or &?) */ 272 if ((1 << i) == m->recsrc) 273 break; 274 if ((1 << i) & m->recdevs) 275 ++cnt; 276 } 277 278 if (i == SOUND_MIXER_NRDEVICES) 279 return EIDRM; 280 281 *route = cnt; 282 return 0; 283 } 284 285 /** 286 * @brief Select a device for recording 287 * 288 * This function sets a recording source based on a recording device's 289 * routing number. Said number is translated to an old school recdev 290 * mask and passed over mixer_setrecsrc. 291 * 292 * @param m mixer context container thing 293 * 294 * @retval 0 success(?) 295 * @retval EINVAL User specified an invalid device number 296 * @retval otherwise error from mixer_setrecsrc 297 */ 298 static int 299 mixer_set_recroute(struct snd_mixer *m, int route) 300 { 301 int i, cnt, ret; 302 303 ret = 0; 304 cnt = 0; 305 306 for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) { 307 if ((1 << i) & m->recdevs) { 308 if (route == cnt) 309 break; 310 ++cnt; 311 } 312 } 313 314 if (i == SOUND_MIXER_NRDEVICES) 315 ret = EINVAL; 316 else 317 ret = mixer_setrecsrc(m, (1 << i)); 318 319 return ret; 320 } 321 322 void 323 mix_setdevs(struct snd_mixer *m, u_int32_t v) 324 { 325 struct snddev_info *d; 326 int i; 327 328 if (m == NULL) 329 return; 330 331 d = device_get_softc(m->dev); 332 if (d != NULL && (d->flags & SD_F_SOFTPCMVOL)) 333 v |= SOUND_MASK_PCM; 334 for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) { 335 if (m->parent[i] < SOUND_MIXER_NRDEVICES) 336 v |= 1 << m->parent[i]; 337 v |= m->child[i]; 338 } 339 m->devs = v; 340 } 341 342 /** 343 * @brief Record mask of available recording devices 344 * 345 * Calling functions are responsible for defining the mask of available 346 * recording devices. This function records that value in a structure 347 * used by the rest of the mixer code. 348 * 349 * This function also populates a structure used by the SNDCTL_DSP_*RECSRC* 350 * family of ioctls that are part of OSSV4. All recording device labels 351 * are concatenated in ascending order corresponding to their routing 352 * numbers. (Ex: a system might have 0 => 'vol', 1 => 'cd', 2 => 'line', 353 * etc.) For now, these labels are just the standard recording device 354 * names (cd, line1, etc.), but will eventually be fully dynamic and user 355 * controlled. 356 * 357 * @param m mixer device context container thing 358 * @param v mask of recording devices 359 */ 360 void 361 mix_setrecdevs(struct snd_mixer *m, u_int32_t v) 362 { 363 oss_mixer_enuminfo *ei; 364 char *loc; 365 int i, nvalues, nwrote, nleft, ncopied; 366 367 ei = &m->enuminfo; 368 369 nvalues = 0; 370 nwrote = 0; 371 nleft = sizeof(ei->strings); 372 loc = ei->strings; 373 374 for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) { 375 if ((1 << i) & v) { 376 ei->strindex[nvalues] = nwrote; 377 ncopied = strlcpy(loc, snd_mixernames[i], nleft) + 1; 378 /* strlcpy retval doesn't include terminator */ 379 380 nwrote += ncopied; 381 nleft -= ncopied; 382 nvalues++; 383 384 /* 385 * XXX I don't think this should ever be possible. 386 * Even with a move to dynamic device/channel names, 387 * each label is limited to ~16 characters, so that'd 388 * take a LOT to fill this buffer. 389 */ 390 if ((nleft <= 0) || (nvalues >= OSS_ENUM_MAXVALUE)) { 391 device_printf(m->dev, 392 "mix_setrecdevs: Not enough room to store device names--please file a bug report.\n"); 393 device_printf(m->dev, 394 "mix_setrecdevs: Please include details about your sound hardware, OS version, etc.\n"); 395 break; 396 } 397 398 loc = &ei->strings[nwrote]; 399 } 400 } 401 402 /* 403 * NB: The SNDCTL_DSP_GET_RECSRC_NAMES ioctl ignores the dev 404 * and ctrl fields. 405 */ 406 ei->nvalues = nvalues; 407 m->recdevs = v; 408 } 409 410 void 411 mix_setparentchild(struct snd_mixer *m, u_int32_t parent, u_int32_t childs) 412 { 413 u_int32_t mask = 0; 414 int i; 415 416 if (m == NULL || parent >= SOUND_MIXER_NRDEVICES) 417 return; 418 for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) { 419 if (i == parent) 420 continue; 421 if (childs & (1 << i)) { 422 mask |= 1 << i; 423 if (m->parent[i] < SOUND_MIXER_NRDEVICES) 424 m->child[m->parent[i]] &= ~(1 << i); 425 m->parent[i] = parent; 426 m->child[i] = 0; 427 } 428 } 429 mask &= ~(1 << parent); 430 m->child[parent] = mask; 431 } 432 433 void 434 mix_setrealdev(struct snd_mixer *m, u_int32_t dev, u_int32_t realdev) 435 { 436 if (m == NULL || dev >= SOUND_MIXER_NRDEVICES || 437 !(realdev == SOUND_MIXER_NONE || realdev < SOUND_MIXER_NRDEVICES)) 438 return; 439 m->realdev[dev] = realdev; 440 } 441 442 u_int32_t 443 mix_getparent(struct snd_mixer *m, u_int32_t dev) 444 { 445 if (m == NULL || dev >= SOUND_MIXER_NRDEVICES) 446 return SOUND_MIXER_NONE; 447 return m->parent[dev]; 448 } 449 450 u_int32_t 451 mix_getchild(struct snd_mixer *m, u_int32_t dev) 452 { 453 if (m == NULL || dev >= SOUND_MIXER_NRDEVICES) 454 return 0; 455 return m->child[dev]; 456 } 457 458 u_int32_t 459 mix_getdevs(struct snd_mixer *m) 460 { 461 return m->devs; 462 } 463 464 u_int32_t 465 mix_getrecdevs(struct snd_mixer *m) 466 { 467 return m->recdevs; 468 } 469 470 void * 471 mix_getdevinfo(struct snd_mixer *m) 472 { 473 return m->devinfo; 474 } 475 476 int 477 mixer_init(device_t dev, kobj_class_t cls, void *devinfo) 478 { 479 struct snddev_info *snddev; 480 struct snd_mixer *m; 481 u_int16_t v; 482 struct cdev *pdev; 483 int i, unit, val; 484 485 m = (struct snd_mixer *)kobj_create(cls, M_MIXER, M_WAITOK | M_ZERO); 486 snprintf(m->name, MIXER_NAMELEN, "%s:mixer", device_get_nameunit(dev)); 487 m->lock = snd_mtxcreate(m->name, "pcm mixer"); 488 m->type = cls->name; 489 m->devinfo = devinfo; 490 m->busy = 0; 491 m->dev = dev; 492 for (i = 0; i < 32; i++) { 493 m->parent[i] = SOUND_MIXER_NONE; 494 m->child[i] = 0; 495 m->realdev[i] = i; 496 } 497 498 if (MIXER_INIT(m)) 499 goto bad; 500 501 for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) { 502 v = snd_mixerdefaults[i]; 503 504 if (resource_int_value(device_get_name(dev), 505 device_get_unit(dev), snd_mixernames[i], &val) == 0) { 506 if (val >= 0 && val <= 100) { 507 v = (u_int16_t) val; 508 } 509 } 510 511 mixer_set(m, i, v | (v << 8)); 512 } 513 514 mixer_setrecsrc(m, SOUND_MASK_MIC); 515 516 unit = device_get_unit(dev); 517 pdev = make_dev(&mixer_cdevsw, PCMMKMINOR(unit, SND_DEV_CTL, 0), 518 UID_ROOT, GID_WHEEL, 0666, "mixer%d", unit); 519 pdev->si_drv1 = m; 520 snddev = device_get_softc(dev); 521 snddev->mixer_dev = pdev; 522 523 ++mixer_count; 524 525 if (bootverbose) { 526 for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) { 527 if (!(m->devs & (1 << i))) 528 continue; 529 if (m->realdev[i] != i) { 530 device_printf(dev, "Mixer \"%s\" -> \"%s\":", 531 snd_mixernames[i], 532 (m->realdev[i] < SOUND_MIXER_NRDEVICES) ? 533 snd_mixernames[m->realdev[i]] : "none"); 534 } else { 535 device_printf(dev, "Mixer \"%s\":", 536 snd_mixernames[i]); 537 } 538 if (m->parent[i] < SOUND_MIXER_NRDEVICES) 539 printf(" parent=\"%s\"", 540 snd_mixernames[m->parent[i]]); 541 if (m->child[i] != 0) 542 printf(" child=0x%08x", m->child[i]); 543 printf("\n"); 544 } 545 if (snddev->flags & SD_F_SOFTPCMVOL) 546 device_printf(dev, "Soft PCM mixer ENABLED\n"); 547 } 548 549 return 0; 550 551 bad: 552 snd_mtxlock(m->lock); 553 snd_mtxfree(m->lock); 554 kobj_delete((kobj_t)m, M_MIXER); 555 return -1; 556 } 557 558 int 559 mixer_uninit(device_t dev) 560 { 561 int i; 562 struct snddev_info *d; 563 struct snd_mixer *m; 564 struct cdev *pdev; 565 566 d = device_get_softc(dev); 567 pdev = mixer_get_devt(dev); 568 if (d == NULL || pdev == NULL || pdev->si_drv1 == NULL) 569 return EBADF; 570 m = pdev->si_drv1; 571 snd_mtxlock(m->lock); 572 573 if (m->busy) { 574 snd_mtxunlock(m->lock); 575 return EBUSY; 576 } 577 578 pdev->si_drv1 = NULL; 579 destroy_dev(pdev); 580 581 for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) 582 mixer_set(m, i, 0); 583 584 mixer_setrecsrc(m, SOUND_MASK_MIC); 585 586 MIXER_UNINIT(m); 587 588 snd_mtxfree(m->lock); 589 kobj_delete((kobj_t)m, M_MIXER); 590 591 d->mixer_dev = NULL; 592 593 --mixer_count; 594 595 return 0; 596 } 597 598 int 599 mixer_reinit(device_t dev) 600 { 601 struct snd_mixer *m; 602 struct cdev *pdev; 603 int i; 604 605 pdev = mixer_get_devt(dev); 606 m = pdev->si_drv1; 607 snd_mtxlock(m->lock); 608 609 i = MIXER_REINIT(m); 610 if (i) { 611 snd_mtxunlock(m->lock); 612 return i; 613 } 614 615 for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) 616 mixer_set(m, i, m->level[i]); 617 618 mixer_setrecsrc(m, m->recsrc); 619 snd_mtxunlock(m->lock); 620 621 return 0; 622 } 623 624 #ifdef SND_DYNSYSCTL 625 static int 626 sysctl_hw_snd_hwvol_mixer(SYSCTL_HANDLER_ARGS) 627 { 628 char devname[32]; 629 int error, dev; 630 struct snd_mixer *m; 631 632 m = oidp->oid_arg1; 633 snd_mtxlock(m->lock); 634 strlcpy(devname, snd_mixernames[m->hwvol_mixer], sizeof(devname)); 635 snd_mtxunlock(m->lock); 636 error = sysctl_handle_string(oidp, &devname[0], sizeof(devname), req); 637 snd_mtxlock(m->lock); 638 if (error == 0 && req->newptr != NULL) { 639 dev = mixer_lookup(devname); 640 if (dev == -1) { 641 snd_mtxunlock(m->lock); 642 return EINVAL; 643 } 644 else if (dev != m->hwvol_mixer) { 645 m->hwvol_mixer = dev; 646 m->hwvol_muted = 0; 647 } 648 } 649 snd_mtxunlock(m->lock); 650 return error; 651 } 652 #endif 653 654 int 655 mixer_hwvol_init(device_t dev) 656 { 657 struct snd_mixer *m; 658 struct cdev *pdev; 659 660 pdev = mixer_get_devt(dev); 661 m = pdev->si_drv1; 662 663 m->hwvol_mixer = SOUND_MIXER_VOLUME; 664 m->hwvol_step = 5; 665 #ifdef SND_DYNSYSCTL 666 SYSCTL_ADD_INT(device_get_sysctl_ctx(dev), 667 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 668 OID_AUTO, "hwvol_step", CTLFLAG_RW, &m->hwvol_step, 0, ""); 669 SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 670 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 671 OID_AUTO, "hwvol_mixer", CTLTYPE_STRING | CTLFLAG_RW, m, 0, 672 sysctl_hw_snd_hwvol_mixer, "A", ""); 673 #endif 674 return 0; 675 } 676 677 void 678 mixer_hwvol_mute(device_t dev) 679 { 680 struct snd_mixer *m; 681 struct cdev *pdev; 682 683 pdev = mixer_get_devt(dev); 684 m = pdev->si_drv1; 685 snd_mtxlock(m->lock); 686 if (m->hwvol_muted) { 687 m->hwvol_muted = 0; 688 mixer_set(m, m->hwvol_mixer, m->hwvol_mute_level); 689 } else { 690 m->hwvol_muted++; 691 m->hwvol_mute_level = mixer_get(m, m->hwvol_mixer); 692 mixer_set(m, m->hwvol_mixer, 0); 693 } 694 snd_mtxunlock(m->lock); 695 } 696 697 void 698 mixer_hwvol_step(device_t dev, int left_step, int right_step) 699 { 700 struct snd_mixer *m; 701 int level, left, right; 702 struct cdev *pdev; 703 704 pdev = mixer_get_devt(dev); 705 m = pdev->si_drv1; 706 snd_mtxlock(m->lock); 707 if (m->hwvol_muted) { 708 m->hwvol_muted = 0; 709 level = m->hwvol_mute_level; 710 } else 711 level = mixer_get(m, m->hwvol_mixer); 712 if (level != -1) { 713 left = level & 0xff; 714 right = level >> 8; 715 left += left_step * m->hwvol_step; 716 if (left < 0) 717 left = 0; 718 right += right_step * m->hwvol_step; 719 if (right < 0) 720 right = 0; 721 mixer_set(m, m->hwvol_mixer, left | right << 8); 722 } 723 snd_mtxunlock(m->lock); 724 } 725 726 /* ----------------------------------------------------------------------- */ 727 728 static int 729 mixer_open(struct cdev *i_dev, int flags, int mode, struct thread *td) 730 { 731 struct snd_mixer *m; 732 733 m = i_dev->si_drv1; 734 snd_mtxlock(m->lock); 735 736 m->busy = 1; 737 738 snd_mtxunlock(m->lock); 739 return 0; 740 } 741 742 static int 743 mixer_close(struct cdev *i_dev, int flags, int mode, struct thread *td) 744 { 745 struct snd_mixer *m; 746 747 m = i_dev->si_drv1; 748 snd_mtxlock(m->lock); 749 750 if (!m->busy) { 751 snd_mtxunlock(m->lock); 752 return EBADF; 753 } 754 m->busy = 0; 755 756 snd_mtxunlock(m->lock); 757 return 0; 758 } 759 760 int 761 mixer_ioctl(struct cdev *i_dev, u_long cmd, caddr_t arg, int mode, struct thread *td) 762 { 763 struct snd_mixer *m; 764 int ret, *arg_i = (int *)arg; 765 int v = -1, j = cmd & 0xff; 766 767 m = i_dev->si_drv1; 768 769 if (m == NULL) 770 return EBADF; 771 772 snd_mtxlock(m->lock); 773 if (mode != -1 && !m->busy) { 774 snd_mtxunlock(m->lock); 775 return EBADF; 776 } 777 778 if (cmd == SNDCTL_MIXERINFO) { 779 snd_mtxunlock(m->lock); 780 return mixer_oss_mixerinfo(i_dev, (oss_mixerinfo *)arg); 781 } 782 783 if ((cmd & MIXER_WRITE(0)) == MIXER_WRITE(0)) { 784 if (j == SOUND_MIXER_RECSRC) 785 ret = mixer_setrecsrc(m, *arg_i); 786 else 787 ret = mixer_set(m, j, *arg_i); 788 snd_mtxunlock(m->lock); 789 return (ret == 0)? 0 : ENXIO; 790 } 791 792 if ((cmd & MIXER_READ(0)) == MIXER_READ(0)) { 793 switch (j) { 794 case SOUND_MIXER_DEVMASK: 795 case SOUND_MIXER_CAPS: 796 case SOUND_MIXER_STEREODEVS: 797 v = mix_getdevs(m); 798 break; 799 800 case SOUND_MIXER_RECMASK: 801 v = mix_getrecdevs(m); 802 break; 803 804 case SOUND_MIXER_RECSRC: 805 v = mixer_getrecsrc(m); 806 break; 807 808 default: 809 v = mixer_get(m, j); 810 } 811 *arg_i = v; 812 snd_mtxunlock(m->lock); 813 return (v != -1)? 0 : ENXIO; 814 } 815 816 ret = 0; 817 818 switch (cmd) { 819 /** @todo Double check return values, error codes. */ 820 case SNDCTL_SYSINFO: 821 sound_oss_sysinfo((oss_sysinfo *)arg); 822 break; 823 case SNDCTL_AUDIOINFO: 824 ret = dsp_oss_audioinfo(i_dev, (oss_audioinfo *)arg); 825 break; 826 case SNDCTL_DSP_GET_RECSRC_NAMES: 827 bcopy((void *)&m->enuminfo, arg, sizeof(oss_mixer_enuminfo)); 828 break; 829 case SNDCTL_DSP_GET_RECSRC: 830 ret = mixer_get_recroute(m, arg_i); 831 break; 832 case SNDCTL_DSP_SET_RECSRC: 833 ret = mixer_set_recroute(m, *arg_i); 834 break; 835 case OSS_GETVERSION: 836 *arg_i = SOUND_VERSION; 837 break; 838 default: 839 ret = ENXIO; 840 } 841 842 snd_mtxunlock(m->lock); 843 return ret; 844 } 845 846 #ifdef USING_DEVFS 847 static void 848 mixer_clone(void *arg, struct ucred *cred, char *name, int namelen, 849 struct cdev **dev) 850 { 851 struct snddev_info *sd; 852 853 if (*dev != NULL) 854 return; 855 if (strcmp(name, "mixer") == 0) { 856 sd = devclass_get_softc(pcm_devclass, snd_unit); 857 if (sd != NULL && sd->mixer_dev != NULL) { 858 *dev = sd->mixer_dev; 859 dev_ref(*dev); 860 } 861 } 862 } 863 864 static void 865 mixer_sysinit(void *p) 866 { 867 mixer_ehtag = EVENTHANDLER_REGISTER(dev_clone, mixer_clone, 0, 1000); 868 } 869 870 static void 871 mixer_sysuninit(void *p) 872 { 873 if (mixer_ehtag != NULL) 874 EVENTHANDLER_DEREGISTER(dev_clone, mixer_ehtag); 875 } 876 877 SYSINIT(mixer_sysinit, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, mixer_sysinit, NULL); 878 SYSUNINIT(mixer_sysuninit, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, mixer_sysuninit, NULL); 879 #endif 880 881 /** 882 * @brief Handler for SNDCTL_MIXERINFO 883 * 884 * This function searches for a mixer based on the numeric ID stored 885 * in oss_miserinfo::dev. If set to -1, then information about the 886 * current mixer handling the request is provided. Note, however, that 887 * this ioctl may be made with any sound device (audio, mixer, midi). 888 * 889 * @note Caller must not hold any PCM device, channel, or mixer locks. 890 * 891 * See http://manuals.opensound.com/developer/SNDCTL_MIXERINFO.html for 892 * more information. 893 * 894 * @param i_dev character device on which the ioctl arrived 895 * @param arg user argument (oss_mixerinfo *) 896 * 897 * @retval EINVAL oss_mixerinfo::dev specified a bad value 898 * @retval 0 success 899 */ 900 int 901 mixer_oss_mixerinfo(struct cdev *i_dev, oss_mixerinfo *mi) 902 { 903 struct snddev_info *d; 904 struct snd_mixer *m; 905 struct cdev *t_cdev; 906 int nmix, ret, pcmunit, i; 907 908 /* 909 * If probing the device handling the ioctl, make sure it's a mixer 910 * device. (This ioctl is valid on audio, mixer, and midi devices.) 911 */ 912 if ((mi->dev == -1) && (i_dev->si_devsw != &mixer_cdevsw)) 913 return EINVAL; 914 915 d = NULL; 916 m = NULL; 917 t_cdev = NULL; 918 nmix = 0; 919 ret = 0; 920 pcmunit = -1; /* pcmX */ 921 922 /* 923 * There's a 1:1 relationship between mixers and PCM devices, so 924 * begin by iterating over PCM devices and search for our mixer. 925 */ 926 for (i = 0; i < devclass_get_maxunit(pcm_devclass); i++) { 927 d = devclass_get_softc(pcm_devclass, i); 928 if (d == NULL) 929 continue; 930 931 /* See the note in function docblock. */ 932 mtx_assert(d->lock, MA_NOTOWNED); 933 pcm_inprog(d, 1); 934 pcm_lock(d); 935 936 if (d->mixer_dev != NULL) { 937 if (((mi->dev == -1) && (d->mixer_dev == i_dev)) || (mi->dev == nmix)) { 938 t_cdev = d->mixer_dev; 939 pcmunit = i; 940 break; 941 } 942 ++nmix; 943 } 944 945 pcm_unlock(d); 946 pcm_inprog(d, -1); 947 } 948 949 /* 950 * If t_cdev is NULL, then search was exhausted and device wasn't 951 * found. No locks are held, so just return. 952 */ 953 if (t_cdev == NULL) 954 return EINVAL; 955 956 m = t_cdev->si_drv1; 957 mtx_lock(m->lock); 958 959 /* 960 * At this point, the following synchronization stuff has happened: 961 * - a specific PCM device is locked and its "in progress 962 * operations" counter has been incremented, so be sure to unlock 963 * and decrement when exiting; 964 * - a specific mixer device has been locked, so be sure to unlock 965 * when existing. 966 */ 967 968 bzero((void *)mi, sizeof(*mi)); 969 970 mi->dev = nmix; 971 snprintf(mi->id, sizeof(mi->id), "mixer%d", dev2unit(t_cdev)); 972 strlcpy(mi->name, m->name, sizeof(mi->name)); 973 mi->modify_counter = m->modify_counter; 974 mi->card_number = pcmunit; 975 /* 976 * Currently, FreeBSD assumes 1:1 relationship between a pcm and 977 * mixer devices, so this is hardcoded to 0. 978 */ 979 mi->port_number = 0; 980 981 /** 982 * @todo Fill in @sa oss_mixerinfo::mixerhandle. 983 * @note From 4Front: "mixerhandle is an arbitrary string that 984 * identifies the mixer better than the device number 985 * (mixerinfo.dev). Device numbers may change depending on 986 * the order the drivers are loaded. However the handle 987 * should remain the same provided that the sound card is 988 * not moved to another PCI slot." 989 */ 990 991 /** 992 * @note 993 * @sa oss_mixerinfo::magic is a reserved field. 994 * 995 * @par 996 * From 4Front: "magic is usually 0. However some devices may have 997 * dedicated setup utilities and the magic field may contain an 998 * unique driver specific value (managed by [4Front])." 999 */ 1000 1001 mi->enabled = device_is_attached(m->dev) ? 1 : 0; 1002 /** 1003 * The only flag for @sa oss_mixerinfo::caps is currently 1004 * MIXER_CAP_VIRTUAL, which I'm not sure we really worry about. 1005 */ 1006 /** 1007 * Mixer extensions currently aren't supported, so leave 1008 * @sa oss_mixerinfo::nrext blank for now. 1009 */ 1010 /** 1011 * @todo Fill in @sa oss_mixerinfo::priority (requires touching 1012 * drivers?) 1013 * @note The priority field is for mixer applets to determine which 1014 * mixer should be the default, with 0 being least preferred and 10 1015 * being most preferred. From 4Front: "OSS drivers like ICH use 1016 * higher values (10) because such chips are known to be used only 1017 * on motherboards. Drivers for high end pro devices use 0 because 1018 * they will never be the default mixer. Other devices use values 1 1019 * to 9 depending on the estimated probability of being the default 1020 * device. 1021 * 1022 * XXX Described by Hannu@4Front, but not found in soundcard.h. 1023 strlcpy(mi->devnode, t_cdev->si_name, sizeof(mi->devnode)); 1024 mi->legacy_device = pcmunit; 1025 */ 1026 1027 mtx_unlock(m->lock); 1028 pcm_unlock(d); 1029 pcm_inprog(d, -1); 1030 1031 return ret; 1032 } 1033