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_dev != 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 437 bus_topo_lock(); 438 if (snd_unit_auto < 0) 439 snd_unit_auto = (snd_unit < 0) ? 1 : 0; 440 if (snd_unit < 0 || snd_unit_auto > 1) 441 snd_unit = device_get_unit(dev); 442 else if (snd_unit_auto == 1) 443 snd_unit = pcm_best_unit(snd_unit); 444 445 if (snd_unit == device_get_unit(dev)) 446 pcm_hotswap(); 447 bus_topo_unlock(); 448 449 return (0); 450 } 451 452 int 453 pcm_unregister(device_t dev) 454 { 455 struct snddev_info *d; 456 457 d = device_get_softc(dev); 458 459 if (!PCM_REGISTERED(d)) { 460 device_printf(dev, "unregister: device not configured\n"); 461 return (0); 462 } 463 464 PCM_LOCK(d); 465 PCM_WAIT(d); 466 467 d->flags &= ~SD_F_REGISTERED; 468 469 PCM_ACQUIRE(d); 470 PCM_UNLOCK(d); 471 472 pcm_killchans(d); 473 474 PCM_RELEASE_QUICK(d); 475 476 if (d->play_sysctl_tree != NULL) { 477 sysctl_ctx_free(&d->play_sysctl_ctx); 478 d->play_sysctl_tree = NULL; 479 } 480 if (d->rec_sysctl_tree != NULL) { 481 sysctl_ctx_free(&d->rec_sysctl_ctx); 482 d->rec_sysctl_tree = NULL; 483 } 484 485 sndstat_unregister(dev); 486 mixer_uninit(dev); 487 dsp_destroy_dev(dev); 488 489 cv_destroy(&d->cv); 490 mtx_destroy(&d->lock); 491 492 bus_topo_lock(); 493 if (snd_unit == device_get_unit(dev)) { 494 snd_unit = pcm_best_unit(-1); 495 if (snd_unit_auto == 0) 496 snd_unit_auto = 1; 497 pcm_hotswap(); 498 } 499 bus_topo_unlock(); 500 501 return (0); 502 } 503 504 /************************************************************************/ 505 506 /** 507 * @brief Handle OSSv4 SNDCTL_SYSINFO ioctl. 508 * 509 * @param si Pointer to oss_sysinfo struct where information about the 510 * sound subsystem will be written/copied. 511 * 512 * This routine returns information about the sound system, such as the 513 * current OSS version, number of audio, MIDI, and mixer drivers, etc. 514 * Also includes a bitmask showing which of the above types of devices 515 * are open (busy). 516 * 517 * @note 518 * Calling threads must not hold any snddev_info or pcm_channel locks. 519 * 520 * @author Ryan Beasley <ryanb@FreeBSD.org> 521 */ 522 void 523 sound_oss_sysinfo(oss_sysinfo *si) 524 { 525 static char si_product[] = "FreeBSD native OSS ABI"; 526 static char si_version[] = __XSTRING(__FreeBSD_version); 527 static char si_license[] = "BSD"; 528 static int intnbits = sizeof(int) * 8; /* Better suited as macro? 529 Must pester a C guru. */ 530 531 struct snddev_info *d; 532 struct pcm_channel *c; 533 int j; 534 size_t i; 535 536 strlcpy(si->product, si_product, sizeof(si->product)); 537 strlcpy(si->version, si_version, sizeof(si->version)); 538 si->versionnum = SOUND_VERSION; 539 strlcpy(si->license, si_license, sizeof(si->license)); 540 541 /* 542 * Iterate over PCM devices and their channels, gathering up data 543 * for the numaudioengines and openedaudio fields. 544 */ 545 si->numaudioengines = 0; 546 bzero((void *)&si->openedaudio, sizeof(si->openedaudio)); 547 548 j = 0; 549 550 bus_topo_lock(); 551 for (i = 0; pcm_devclass != NULL && 552 i < devclass_get_maxunit(pcm_devclass); i++) { 553 d = devclass_get_softc(pcm_devclass, i); 554 if (!PCM_REGISTERED(d)) 555 continue; 556 557 /* XXX Need Giant magic entry ??? */ 558 559 /* See note in function's docblock */ 560 PCM_UNLOCKASSERT(d); 561 PCM_LOCK(d); 562 563 si->numaudioengines += PCM_CHANCOUNT(d); 564 565 CHN_FOREACH(c, d, channels.pcm) { 566 CHN_UNLOCKASSERT(c); 567 CHN_LOCK(c); 568 if (c->flags & CHN_F_BUSY) 569 si->openedaudio[j / intnbits] |= 570 (1 << (j % intnbits)); 571 CHN_UNLOCK(c); 572 j++; 573 } 574 575 PCM_UNLOCK(d); 576 } 577 bus_topo_unlock(); 578 579 si->numsynths = 0; /* OSSv4 docs: this field is obsolete */ 580 /** 581 * @todo Collect num{midis,timers}. 582 * 583 * Need access to sound/midi/midi.c::midistat_lock in order 584 * to safely touch midi_devices and get a head count of, well, 585 * MIDI devices. midistat_lock is a global static (i.e., local to 586 * midi.c), but midi_devices is a regular global; should the mutex 587 * be publicized, or is there another way to get this information? 588 * 589 * NB: MIDI/sequencer stuff is currently on hold. 590 */ 591 si->nummidis = 0; 592 si->numtimers = 0; 593 /* 594 * Set this to the maximum unit number so that applications will not 595 * break if they try to loop through all mixers and some of them are 596 * not available. 597 */ 598 bus_topo_lock(); 599 si->nummixers = devclass_get_maxunit(pcm_devclass); 600 si->numcards = devclass_get_maxunit(pcm_devclass); 601 si->numaudios = devclass_get_maxunit(pcm_devclass); 602 bus_topo_unlock(); 603 /* OSSv4 docs: Intended only for test apps; API doesn't 604 really have much of a concept of cards. Shouldn't be 605 used by applications. */ 606 607 /** 608 * @todo Fill in "busy devices" fields. 609 * 610 * si->openedmidi = " MIDI devices 611 */ 612 bzero((void *)&si->openedmidi, sizeof(si->openedmidi)); 613 614 /* 615 * Si->filler is a reserved array, but according to docs each 616 * element should be set to -1. 617 */ 618 for (i = 0; i < nitems(si->filler); i++) 619 si->filler[i] = -1; 620 } 621 622 int 623 sound_oss_card_info(oss_card_info *si) 624 { 625 struct snddev_info *d; 626 int i; 627 628 bus_topo_lock(); 629 for (i = 0; pcm_devclass != NULL && 630 i < devclass_get_maxunit(pcm_devclass); i++) { 631 d = devclass_get_softc(pcm_devclass, i); 632 if (i != si->card) 633 continue; 634 635 if (!PCM_REGISTERED(d)) { 636 snprintf(si->shortname, sizeof(si->shortname), 637 "pcm%d (n/a)", i); 638 strlcpy(si->longname, "Device unavailable", 639 sizeof(si->longname)); 640 si->hw_info[0] = '\0'; 641 si->intr_count = si->ack_count = 0; 642 } else { 643 PCM_UNLOCKASSERT(d); 644 PCM_LOCK(d); 645 646 strlcpy(si->shortname, device_get_nameunit(d->dev), 647 sizeof(si->shortname)); 648 strlcpy(si->longname, device_get_desc(d->dev), 649 sizeof(si->longname)); 650 strlcpy(si->hw_info, d->status, sizeof(si->hw_info)); 651 si->intr_count = si->ack_count = 0; 652 653 PCM_UNLOCK(d); 654 } 655 656 bus_topo_unlock(); 657 return (0); 658 } 659 bus_topo_unlock(); 660 661 return (ENXIO); 662 } 663 664 /************************************************************************/ 665 666 static void 667 sound_global_init(void) 668 { 669 if (snd_verbose < 0 || snd_verbose > 4) 670 snd_verbose = 1; 671 672 if (snd_unit < 0) 673 snd_unit = -1; 674 675 snd_vchans_enable = true; 676 677 if (chn_latency < CHN_LATENCY_MIN || 678 chn_latency > CHN_LATENCY_MAX) 679 chn_latency = CHN_LATENCY_DEFAULT; 680 681 if (chn_latency_profile < CHN_LATENCY_PROFILE_MIN || 682 chn_latency_profile > CHN_LATENCY_PROFILE_MAX) 683 chn_latency_profile = CHN_LATENCY_PROFILE_DEFAULT; 684 685 if (feeder_rate_min < FEEDRATE_MIN || 686 feeder_rate_max < FEEDRATE_MIN || 687 feeder_rate_min > FEEDRATE_MAX || 688 feeder_rate_max > FEEDRATE_MAX || 689 !(feeder_rate_min < feeder_rate_max)) { 690 feeder_rate_min = FEEDRATE_RATEMIN; 691 feeder_rate_max = FEEDRATE_RATEMAX; 692 } 693 694 if (feeder_rate_round < FEEDRATE_ROUNDHZ_MIN || 695 feeder_rate_round > FEEDRATE_ROUNDHZ_MAX) 696 feeder_rate_round = FEEDRATE_ROUNDHZ; 697 698 if (bootverbose) 699 printf("%s: snd_unit=%d snd_vchans_enable=%d " 700 "latency=%d " 701 "feeder_rate_min=%d feeder_rate_max=%d " 702 "feeder_rate_round=%d\n", 703 __func__, snd_unit, snd_vchans_enable, 704 chn_latency, 705 feeder_rate_min, feeder_rate_max, 706 feeder_rate_round); 707 } 708 709 static int 710 sound_modevent(module_t mod, int type, void *data) 711 { 712 int ret; 713 714 ret = 0; 715 switch (type) { 716 case MOD_LOAD: 717 pcm_devclass = devclass_create("pcm"); 718 pcmsg_unrhdr = new_unrhdr(1, INT_MAX, NULL); 719 sound_global_init(); 720 break; 721 case MOD_UNLOAD: 722 if (pcmsg_unrhdr != NULL) { 723 delete_unrhdr(pcmsg_unrhdr); 724 pcmsg_unrhdr = NULL; 725 } 726 break; 727 case MOD_SHUTDOWN: 728 break; 729 default: 730 ret = ENOTSUP; 731 } 732 733 return ret; 734 } 735 736 DEV_MODULE(sound, sound_modevent, NULL); 737 MODULE_VERSION(sound, SOUND_MODVER); 738