1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2005-2009 Ariff Abdullah <ariff@FreeBSD.org> 5 * Portions Copyright (c) Ryan Beasley <ryan.beasley@gmail.com> - GSoC 2006 6 * Copyright (c) 1999 Cameron Grant <cg@FreeBSD.org> 7 * Copyright (c) 1997 Luigi Rizzo 8 * All rights reserved. 9 * Copyright (c) 2024-2025 The FreeBSD Foundation 10 * 11 * Portions of this software were developed by Christos Margiolis 12 * <christos@FreeBSD.org> under sponsorship from the FreeBSD Foundation. 13 * 14 * Redistribution and use in source and binary forms, with or without 15 * modification, are permitted provided that the following conditions 16 * are met: 17 * 1. Redistributions of source code must retain the above copyright 18 * notice, this list of conditions and the following disclaimer. 19 * 2. Redistributions in binary form must reproduce the above copyright 20 * notice, this list of conditions and the following disclaimer in the 21 * documentation and/or other materials provided with the distribution. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 */ 35 36 #ifdef HAVE_KERNEL_OPTION_HEADERS 37 #include "opt_snd.h" 38 #endif 39 40 #include <dev/sound/pcm/sound.h> 41 #include <dev/sound/pcm/ac97.h> 42 #include <dev/sound/pcm/vchan.h> 43 #include <dev/sound/pcm/dsp.h> 44 #include <dev/sound/sndstat.h> 45 #include <sys/limits.h> 46 #include <sys/sysctl.h> 47 48 #include "feeder_if.h" 49 50 devclass_t pcm_devclass; 51 52 int snd_unit = -1; 53 54 static int snd_unit_auto = -1; 55 SYSCTL_INT(_hw_snd, OID_AUTO, default_auto, CTLFLAG_RWTUN, 56 &snd_unit_auto, 0, "assign default unit to a newly attached device"); 57 58 SYSCTL_NODE(_hw, OID_AUTO, snd, CTLFLAG_RD | CTLFLAG_MPSAFE, 0, 59 "Sound driver"); 60 61 /** 62 * @brief Unit number allocator for syncgroup IDs 63 */ 64 struct unrhdr *pcmsg_unrhdr = NULL; 65 66 int 67 snd_setup_intr(device_t dev, struct resource *res, int flags, driver_intr_t hand, void *param, void **cookiep) 68 { 69 struct snddev_info *d; 70 71 flags &= INTR_MPSAFE; 72 flags |= INTR_TYPE_AV; 73 d = device_get_softc(dev); 74 if (d != NULL && (flags & INTR_MPSAFE)) 75 d->flags |= SD_F_MPSAFE; 76 77 return bus_setup_intr(dev, res, flags, NULL, hand, param, cookiep); 78 } 79 80 static void 81 pcm_hotswap(void) 82 { 83 struct snddev_info *d; 84 char buf[32]; 85 86 bus_topo_assert(); 87 if (snd_unit >= 0) { 88 d = devclass_get_softc(pcm_devclass, snd_unit); 89 if (!PCM_REGISTERED(d)) 90 return; 91 snprintf(buf, sizeof(buf), "cdev=dsp%d", snd_unit); 92 if (d->reccount > 0) 93 devctl_notify("SND", "CONN", "IN", buf); 94 if (d->playcount > 0) 95 devctl_notify("SND", "CONN", "OUT", buf); 96 } else 97 devctl_notify("SND", "CONN", "NODEV", NULL); 98 } 99 100 static int 101 sysctl_hw_snd_default_unit(SYSCTL_HANDLER_ARGS) 102 { 103 struct snddev_info *d; 104 int error, unit; 105 106 unit = snd_unit; 107 error = sysctl_handle_int(oidp, &unit, 0, req); 108 if (error == 0 && req->newptr != NULL) { 109 bus_topo_lock(); 110 d = devclass_get_softc(pcm_devclass, unit); 111 if (!PCM_REGISTERED(d) || CHN_EMPTY(d, channels.pcm)) { 112 bus_topo_unlock(); 113 return EINVAL; 114 } 115 snd_unit = unit; 116 snd_unit_auto = 0; 117 pcm_hotswap(); 118 bus_topo_unlock(); 119 } 120 return (error); 121 } 122 /* XXX: do we need a way to let the user change the default unit? */ 123 SYSCTL_PROC(_hw_snd, OID_AUTO, default_unit, 124 CTLTYPE_INT | CTLFLAG_RWTUN | CTLFLAG_ANYBODY | CTLFLAG_MPSAFE, 0, 125 sizeof(int), sysctl_hw_snd_default_unit, "I", 126 "default sound device"); 127 128 int 129 pcm_addchan(device_t dev, int dir, kobj_class_t cls, void *devinfo) 130 { 131 struct snddev_info *d = device_get_softc(dev); 132 struct pcm_channel *ch; 133 int err = 0; 134 135 PCM_LOCK(d); 136 PCM_WAIT(d); 137 PCM_ACQUIRE(d); 138 ch = chn_init(d, NULL, cls, dir, devinfo); 139 if (!ch) { 140 device_printf(d->dev, "chn_init(%s, %d, %p) failed\n", 141 cls->name, dir, devinfo); 142 err = ENODEV; 143 } 144 PCM_RELEASE(d); 145 PCM_UNLOCK(d); 146 147 return (err); 148 } 149 150 static void 151 pcm_killchans(struct snddev_info *d) 152 { 153 struct pcm_channel *ch; 154 bool again; 155 156 PCM_BUSYASSERT(d); 157 KASSERT(!PCM_REGISTERED(d), ("%s(): still registered\n", __func__)); 158 159 for (;;) { 160 again = false; 161 /* Make sure all channels are stopped. */ 162 CHN_FOREACH(ch, d, channels.pcm) { 163 CHN_LOCK(ch); 164 if (ch->inprog == 0 && ch->sleeping == 0 && 165 CHN_STOPPED(ch)) { 166 CHN_UNLOCK(ch); 167 continue; 168 } 169 chn_shutdown(ch); 170 if (ch->direction == PCMDIR_PLAY) 171 chn_flush(ch); 172 else 173 chn_abort(ch); 174 CHN_UNLOCK(ch); 175 again = true; 176 } 177 /* 178 * Some channels are still active. Sleep for a bit and try 179 * again. 180 */ 181 if (again) 182 pause_sbt("pcmkillchans", mstosbt(5), 0, 0); 183 else 184 break; 185 } 186 187 /* All channels are finally dead. */ 188 while (!CHN_EMPTY(d, channels.pcm)) { 189 ch = CHN_FIRST(d, channels.pcm); 190 chn_kill(ch); 191 } 192 193 if (d->p_unr != NULL) 194 delete_unrhdr(d->p_unr); 195 if (d->vp_unr != NULL) 196 delete_unrhdr(d->vp_unr); 197 if (d->r_unr != NULL) 198 delete_unrhdr(d->r_unr); 199 if (d->vr_unr != NULL) 200 delete_unrhdr(d->vr_unr); 201 } 202 203 static int 204 pcm_best_unit(int old) 205 { 206 struct snddev_info *d; 207 int i, best, bestprio, prio; 208 209 best = -1; 210 bestprio = -100; 211 bus_topo_lock(); 212 for (i = 0; pcm_devclass != NULL && 213 i < devclass_get_maxunit(pcm_devclass); i++) { 214 d = devclass_get_softc(pcm_devclass, i); 215 if (!PCM_REGISTERED(d)) 216 continue; 217 prio = 0; 218 if (d->playcount == 0) 219 prio -= 10; 220 if (d->reccount == 0) 221 prio -= 2; 222 if (prio > bestprio || (prio == bestprio && i == old)) { 223 best = i; 224 bestprio = prio; 225 } 226 } 227 bus_topo_unlock(); 228 229 return (best); 230 } 231 232 uint32_t 233 pcm_getflags(device_t dev) 234 { 235 struct snddev_info *d = device_get_softc(dev); 236 237 return d->flags; 238 } 239 240 void 241 pcm_setflags(device_t dev, uint32_t val) 242 { 243 struct snddev_info *d = device_get_softc(dev); 244 245 d->flags = val; 246 } 247 248 void * 249 pcm_getdevinfo(device_t dev) 250 { 251 struct snddev_info *d = device_get_softc(dev); 252 253 return d->devinfo; 254 } 255 256 unsigned int 257 pcm_getbuffersize(device_t dev, unsigned int minbufsz, unsigned int deflt, unsigned int maxbufsz) 258 { 259 int sz, x; 260 261 sz = 0; 262 if (resource_int_value(device_get_name(dev), device_get_unit(dev), "buffersize", &sz) == 0) { 263 x = sz; 264 RANGE(sz, minbufsz, maxbufsz); 265 if (x != sz) 266 device_printf(dev, "'buffersize=%d' hint is out of range (%d-%d), using %d\n", x, minbufsz, maxbufsz, sz); 267 x = minbufsz; 268 while (x < sz) 269 x <<= 1; 270 if (x > sz) 271 x >>= 1; 272 if (x != sz) { 273 device_printf(dev, "'buffersize=%d' hint is not a power of 2, using %d\n", sz, x); 274 sz = x; 275 } 276 } else { 277 sz = deflt; 278 } 279 280 return sz; 281 } 282 283 static int 284 sysctl_dev_pcm_bitperfect(SYSCTL_HANDLER_ARGS) 285 { 286 struct snddev_info *d; 287 int err, val; 288 289 d = oidp->oid_arg1; 290 if (!PCM_REGISTERED(d)) 291 return (ENODEV); 292 293 PCM_LOCK(d); 294 PCM_WAIT(d); 295 val = (d->flags & SD_F_BITPERFECT) ? 1 : 0; 296 PCM_ACQUIRE(d); 297 PCM_UNLOCK(d); 298 299 err = sysctl_handle_int(oidp, &val, 0, req); 300 301 if (err == 0 && req->newptr != NULL) { 302 if (!(val == 0 || val == 1)) { 303 PCM_RELEASE_QUICK(d); 304 return (EINVAL); 305 } 306 307 PCM_LOCK(d); 308 309 d->flags &= ~SD_F_BITPERFECT; 310 d->flags |= (val != 0) ? SD_F_BITPERFECT : 0; 311 312 PCM_RELEASE(d); 313 PCM_UNLOCK(d); 314 } else 315 PCM_RELEASE_QUICK(d); 316 317 return (err); 318 } 319 320 static int 321 sysctl_dev_pcm_mode(SYSCTL_HANDLER_ARGS) 322 { 323 struct snddev_info *d; 324 int mode = 0; 325 326 d = oidp->oid_arg1; 327 if (!PCM_REGISTERED(d)) 328 return (ENODEV); 329 330 PCM_LOCK(d); 331 if (d->playcount > 0) 332 mode |= PCM_MODE_PLAY; 333 if (d->reccount > 0) 334 mode |= PCM_MODE_REC; 335 if (d->mixer != NULL) 336 mode |= PCM_MODE_MIXER; 337 PCM_UNLOCK(d); 338 339 return (sysctl_handle_int(oidp, &mode, 0, req)); 340 } 341 342 /* 343 * Basic initialization so that drivers can use pcm_addchan() before 344 * pcm_register(). 345 */ 346 void 347 pcm_init(device_t dev, void *devinfo) 348 { 349 struct snddev_info *d; 350 int i; 351 352 d = device_get_softc(dev); 353 d->dev = dev; 354 mtx_init(&d->lock, device_get_nameunit(dev), "sound cdev", MTX_DEF); 355 cv_init(&d->cv, device_get_nameunit(dev)); 356 357 i = 0; 358 if (resource_int_value(device_get_name(dev), device_get_unit(dev), 359 "bitperfect", &i) == 0 && i != 0) 360 d->flags |= SD_F_BITPERFECT; 361 362 d->devinfo = devinfo; 363 d->reccount = 0; 364 d->playcount = 0; 365 d->pvchancount = 0; 366 d->rvchancount = 0; 367 d->pvchanrate = 0; 368 d->pvchanformat = 0; 369 d->rvchanrate = 0; 370 d->rvchanformat = 0; 371 d->p_unr = new_unrhdr(0, INT_MAX, NULL); 372 d->vp_unr = new_unrhdr(0, INT_MAX, NULL); 373 d->r_unr = new_unrhdr(0, INT_MAX, NULL); 374 d->vr_unr = new_unrhdr(0, INT_MAX, NULL); 375 376 CHN_INIT(d, channels.pcm); 377 CHN_INIT(d, channels.pcm.busy); 378 CHN_INIT(d, channels.pcm.opened); 379 CHN_INIT(d, channels.pcm.primary); 380 } 381 382 int 383 pcm_register(device_t dev, char *str) 384 { 385 struct snddev_info *d = device_get_softc(dev); 386 int err; 387 388 /* should only be called once */ 389 if (d->flags & SD_F_REGISTERED) 390 return (EINVAL); 391 392 if (d->playcount == 0 || d->reccount == 0) 393 d->flags |= SD_F_SIMPLEX; 394 if (d->playcount > 0) 395 d->flags |= SD_F_PVCHANS; 396 if (d->reccount > 0) 397 d->flags |= SD_F_RVCHANS; 398 399 strlcpy(d->status, str, SND_STATUSLEN); 400 401 /* Done, we're ready.. */ 402 d->flags |= SD_F_REGISTERED; 403 404 /* 405 * Create all sysctls once SD_F_REGISTERED is set else 406 * tunable sysctls won't work: 407 */ 408 sysctl_ctx_init(&d->play_sysctl_ctx); 409 d->play_sysctl_tree = SYSCTL_ADD_NODE(&d->play_sysctl_ctx, 410 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, "play", 411 CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "playback channels node"); 412 sysctl_ctx_init(&d->rec_sysctl_ctx); 413 d->rec_sysctl_tree = SYSCTL_ADD_NODE(&d->rec_sysctl_ctx, 414 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, "rec", 415 CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "recording channels node"); 416 417 SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 418 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, 419 "bitperfect", CTLTYPE_INT | CTLFLAG_RWTUN | CTLFLAG_MPSAFE, d, 420 sizeof(d), sysctl_dev_pcm_bitperfect, "I", 421 "bit-perfect playback/recording (0=disable, 1=enable)"); 422 SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 423 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, 424 "mode", CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, d, sizeof(d), 425 sysctl_dev_pcm_mode, "I", 426 "mode (1=mixer, 2=play, 4=rec. The values are OR'ed if more than " 427 "one mode is supported)"); 428 vchan_initsys(dev); 429 feeder_eq_initsys(dev); 430 431 sndstat_register(dev, SNDST_TYPE_PCM, d->status); 432 433 err = dsp_make_dev(dev); 434 if (err) 435 return (err); 436 if (d->mixer != NULL) { 437 err = mixer_make_dev(dev); 438 if (err) { 439 dsp_destroy_dev(dev); 440 return (err); 441 } 442 } 443 444 bus_topo_lock(); 445 if (snd_unit_auto < 0) 446 snd_unit_auto = (snd_unit < 0) ? 1 : 0; 447 if (snd_unit < 0 || snd_unit_auto > 1) 448 snd_unit = device_get_unit(dev); 449 else if (snd_unit_auto == 1) 450 snd_unit = pcm_best_unit(snd_unit); 451 452 if (snd_unit == device_get_unit(dev)) 453 pcm_hotswap(); 454 bus_topo_unlock(); 455 456 return (0); 457 } 458 459 int 460 pcm_unregister(device_t dev) 461 { 462 struct snddev_info *d; 463 464 d = device_get_softc(dev); 465 466 if (!PCM_REGISTERED(d)) { 467 device_printf(dev, "unregister: device not configured\n"); 468 return (0); 469 } 470 471 PCM_LOCK(d); 472 PCM_WAIT(d); 473 474 d->flags &= ~SD_F_REGISTERED; 475 476 PCM_ACQUIRE(d); 477 PCM_UNLOCK(d); 478 479 pcm_killchans(d); 480 481 PCM_RELEASE_QUICK(d); 482 483 if (d->play_sysctl_tree != NULL) { 484 sysctl_ctx_free(&d->play_sysctl_ctx); 485 d->play_sysctl_tree = NULL; 486 } 487 if (d->rec_sysctl_tree != NULL) { 488 sysctl_ctx_free(&d->rec_sysctl_ctx); 489 d->rec_sysctl_tree = NULL; 490 } 491 492 sndstat_unregister(dev); 493 if (d->mixer != NULL) 494 mixer_uninit(dev); 495 dsp_destroy_dev(dev); 496 497 cv_destroy(&d->cv); 498 mtx_destroy(&d->lock); 499 500 bus_topo_lock(); 501 if (snd_unit == device_get_unit(dev)) { 502 snd_unit = pcm_best_unit(-1); 503 if (snd_unit_auto == 0) 504 snd_unit_auto = 1; 505 pcm_hotswap(); 506 } 507 bus_topo_unlock(); 508 509 return (0); 510 } 511 512 /************************************************************************/ 513 514 /** 515 * @brief Handle OSSv4 SNDCTL_SYSINFO ioctl. 516 * 517 * @param si Pointer to oss_sysinfo struct where information about the 518 * sound subsystem will be written/copied. 519 * 520 * This routine returns information about the sound system, such as the 521 * current OSS version, number of audio, MIDI, and mixer drivers, etc. 522 * Also includes a bitmask showing which of the above types of devices 523 * are open (busy). 524 * 525 * @note 526 * Calling threads must not hold any snddev_info or pcm_channel locks. 527 * 528 * @author Ryan Beasley <ryanb@FreeBSD.org> 529 */ 530 void 531 sound_oss_sysinfo(oss_sysinfo *si) 532 { 533 static char si_product[] = "FreeBSD native OSS ABI"; 534 static char si_version[] = __XSTRING(__FreeBSD_version); 535 static char si_license[] = "BSD"; 536 static int intnbits = sizeof(int) * 8; /* Better suited as macro? 537 Must pester a C guru. */ 538 539 struct snddev_info *d; 540 struct pcm_channel *c; 541 int j; 542 size_t i; 543 544 strlcpy(si->product, si_product, sizeof(si->product)); 545 strlcpy(si->version, si_version, sizeof(si->version)); 546 si->versionnum = SOUND_VERSION; 547 strlcpy(si->license, si_license, sizeof(si->license)); 548 549 /* 550 * Iterate over PCM devices and their channels, gathering up data 551 * for the numaudioengines and openedaudio fields. 552 */ 553 si->numaudioengines = 0; 554 bzero((void *)&si->openedaudio, sizeof(si->openedaudio)); 555 556 j = 0; 557 558 bus_topo_lock(); 559 for (i = 0; pcm_devclass != NULL && 560 i < devclass_get_maxunit(pcm_devclass); i++) { 561 d = devclass_get_softc(pcm_devclass, i); 562 if (!PCM_REGISTERED(d)) 563 continue; 564 565 /* XXX Need Giant magic entry ??? */ 566 567 /* See note in function's docblock */ 568 PCM_UNLOCKASSERT(d); 569 PCM_LOCK(d); 570 571 si->numaudioengines += PCM_CHANCOUNT(d); 572 573 CHN_FOREACH(c, d, channels.pcm) { 574 CHN_UNLOCKASSERT(c); 575 CHN_LOCK(c); 576 if (c->flags & CHN_F_BUSY) 577 si->openedaudio[j / intnbits] |= 578 (1 << (j % intnbits)); 579 CHN_UNLOCK(c); 580 j++; 581 } 582 583 PCM_UNLOCK(d); 584 } 585 bus_topo_unlock(); 586 587 si->numsynths = 0; /* OSSv4 docs: this field is obsolete */ 588 /** 589 * @todo Collect num{midis,timers}. 590 * 591 * Need access to sound/midi/midi.c::midistat_lock in order 592 * to safely touch midi_devices and get a head count of, well, 593 * MIDI devices. midistat_lock is a global static (i.e., local to 594 * midi.c), but midi_devices is a regular global; should the mutex 595 * be publicized, or is there another way to get this information? 596 * 597 * NB: MIDI/sequencer stuff is currently on hold. 598 */ 599 si->nummidis = 0; 600 si->numtimers = 0; 601 /* 602 * Set this to the maximum unit number so that applications will not 603 * break if they try to loop through all mixers and some of them are 604 * not available. 605 */ 606 bus_topo_lock(); 607 si->nummixers = devclass_get_maxunit(pcm_devclass); 608 si->numcards = devclass_get_maxunit(pcm_devclass); 609 si->numaudios = devclass_get_maxunit(pcm_devclass); 610 bus_topo_unlock(); 611 /* OSSv4 docs: Intended only for test apps; API doesn't 612 really have much of a concept of cards. Shouldn't be 613 used by applications. */ 614 615 /** 616 * @todo Fill in "busy devices" fields. 617 * 618 * si->openedmidi = " MIDI devices 619 */ 620 bzero((void *)&si->openedmidi, sizeof(si->openedmidi)); 621 622 /* 623 * Si->filler is a reserved array, but according to docs each 624 * element should be set to -1. 625 */ 626 for (i = 0; i < nitems(si->filler); i++) 627 si->filler[i] = -1; 628 } 629 630 int 631 sound_oss_card_info(oss_card_info *si) 632 { 633 struct snddev_info *d; 634 int i; 635 636 bus_topo_lock(); 637 for (i = 0; pcm_devclass != NULL && 638 i < devclass_get_maxunit(pcm_devclass); i++) { 639 d = devclass_get_softc(pcm_devclass, i); 640 if (i != si->card) 641 continue; 642 643 if (!PCM_REGISTERED(d)) { 644 snprintf(si->shortname, sizeof(si->shortname), 645 "pcm%d (n/a)", i); 646 strlcpy(si->longname, "Device unavailable", 647 sizeof(si->longname)); 648 si->hw_info[0] = '\0'; 649 si->intr_count = si->ack_count = 0; 650 } else { 651 PCM_UNLOCKASSERT(d); 652 PCM_LOCK(d); 653 654 strlcpy(si->shortname, device_get_nameunit(d->dev), 655 sizeof(si->shortname)); 656 strlcpy(si->longname, device_get_desc(d->dev), 657 sizeof(si->longname)); 658 strlcpy(si->hw_info, d->status, sizeof(si->hw_info)); 659 si->intr_count = si->ack_count = 0; 660 661 PCM_UNLOCK(d); 662 } 663 664 bus_topo_unlock(); 665 return (0); 666 } 667 bus_topo_unlock(); 668 669 return (ENXIO); 670 } 671 672 /************************************************************************/ 673 674 static void 675 sound_global_init(void) 676 { 677 if (snd_verbose < 0 || snd_verbose > 4) 678 snd_verbose = 1; 679 680 if (snd_unit < 0) 681 snd_unit = -1; 682 683 snd_vchans_enable = true; 684 685 if (chn_latency < CHN_LATENCY_MIN || 686 chn_latency > CHN_LATENCY_MAX) 687 chn_latency = CHN_LATENCY_DEFAULT; 688 689 if (chn_latency_profile < CHN_LATENCY_PROFILE_MIN || 690 chn_latency_profile > CHN_LATENCY_PROFILE_MAX) 691 chn_latency_profile = CHN_LATENCY_PROFILE_DEFAULT; 692 693 if (feeder_rate_min < FEEDRATE_MIN || 694 feeder_rate_max < FEEDRATE_MIN || 695 feeder_rate_min > FEEDRATE_MAX || 696 feeder_rate_max > FEEDRATE_MAX || 697 !(feeder_rate_min < feeder_rate_max)) { 698 feeder_rate_min = FEEDRATE_RATEMIN; 699 feeder_rate_max = FEEDRATE_RATEMAX; 700 } 701 702 if (feeder_rate_round < FEEDRATE_ROUNDHZ_MIN || 703 feeder_rate_round > FEEDRATE_ROUNDHZ_MAX) 704 feeder_rate_round = FEEDRATE_ROUNDHZ; 705 706 if (bootverbose) 707 printf("%s: snd_unit=%d snd_vchans_enable=%d " 708 "latency=%d " 709 "feeder_rate_min=%d feeder_rate_max=%d " 710 "feeder_rate_round=%d\n", 711 __func__, snd_unit, snd_vchans_enable, 712 chn_latency, 713 feeder_rate_min, feeder_rate_max, 714 feeder_rate_round); 715 } 716 717 static int 718 sound_modevent(module_t mod, int type, void *data) 719 { 720 int ret; 721 722 ret = 0; 723 switch (type) { 724 case MOD_LOAD: 725 pcm_devclass = devclass_create("pcm"); 726 pcmsg_unrhdr = new_unrhdr(1, INT_MAX, NULL); 727 sound_global_init(); 728 break; 729 case MOD_UNLOAD: 730 if (pcmsg_unrhdr != NULL) { 731 delete_unrhdr(pcmsg_unrhdr); 732 pcmsg_unrhdr = NULL; 733 } 734 break; 735 case MOD_SHUTDOWN: 736 break; 737 default: 738 ret = ENOTSUP; 739 } 740 741 return ret; 742 } 743 744 DEV_MODULE(sound, sound_modevent, NULL); 745 MODULE_VERSION(sound, 1); 746