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 <sys/limits.h> 45 #include <sys/sysctl.h> 46 47 #include "feeder_if.h" 48 49 devclass_t pcm_devclass; 50 51 int snd_unit = -1; 52 53 static int snd_unit_auto = -1; 54 SYSCTL_INT(_hw_snd, OID_AUTO, default_auto, CTLFLAG_RWTUN, 55 &snd_unit_auto, 0, "assign default unit to a newly attached device"); 56 57 SYSCTL_NODE(_hw, OID_AUTO, snd, CTLFLAG_RD | CTLFLAG_MPSAFE, 0, 58 "Sound driver"); 59 60 /** 61 * @brief Unit number allocator for syncgroup IDs 62 */ 63 struct unrhdr *pcmsg_unrhdr = NULL; 64 65 void * 66 snd_mtxcreate(const char *desc, const char *type) 67 { 68 struct mtx *m; 69 70 m = malloc(sizeof(*m), M_DEVBUF, M_WAITOK | M_ZERO); 71 mtx_init(m, desc, type, MTX_DEF); 72 return m; 73 } 74 75 void 76 snd_mtxfree(void *m) 77 { 78 struct mtx *mtx = m; 79 80 mtx_destroy(mtx); 81 free(mtx, M_DEVBUF); 82 } 83 84 void 85 snd_mtxassert(void *m) 86 { 87 #ifdef INVARIANTS 88 struct mtx *mtx = m; 89 90 mtx_assert(mtx, MA_OWNED); 91 #endif 92 } 93 94 int 95 snd_setup_intr(device_t dev, struct resource *res, int flags, driver_intr_t hand, void *param, void **cookiep) 96 { 97 struct snddev_info *d; 98 99 flags &= INTR_MPSAFE; 100 flags |= INTR_TYPE_AV; 101 d = device_get_softc(dev); 102 if (d != NULL && (flags & INTR_MPSAFE)) 103 d->flags |= SD_F_MPSAFE; 104 105 return bus_setup_intr(dev, res, flags, NULL, hand, param, cookiep); 106 } 107 108 static int 109 sysctl_hw_snd_default_unit(SYSCTL_HANDLER_ARGS) 110 { 111 struct snddev_info *d; 112 int error, unit; 113 114 unit = snd_unit; 115 error = sysctl_handle_int(oidp, &unit, 0, req); 116 if (error == 0 && req->newptr != NULL) { 117 bus_topo_lock(); 118 d = devclass_get_softc(pcm_devclass, unit); 119 if (!PCM_REGISTERED(d) || CHN_EMPTY(d, channels.pcm)) { 120 bus_topo_unlock(); 121 return EINVAL; 122 } 123 snd_unit = unit; 124 snd_unit_auto = 0; 125 bus_topo_unlock(); 126 } 127 return (error); 128 } 129 /* XXX: do we need a way to let the user change the default unit? */ 130 SYSCTL_PROC(_hw_snd, OID_AUTO, default_unit, 131 CTLTYPE_INT | CTLFLAG_RWTUN | CTLFLAG_ANYBODY | CTLFLAG_MPSAFE, 0, 132 sizeof(int), sysctl_hw_snd_default_unit, "I", 133 "default sound device"); 134 135 int 136 pcm_addchan(device_t dev, int dir, kobj_class_t cls, void *devinfo) 137 { 138 struct snddev_info *d = device_get_softc(dev); 139 struct pcm_channel *ch; 140 int err = 0; 141 142 PCM_LOCK(d); 143 PCM_WAIT(d); 144 PCM_ACQUIRE(d); 145 ch = chn_init(d, NULL, cls, dir, devinfo); 146 if (!ch) { 147 device_printf(d->dev, "chn_init(%s, %d, %p) failed\n", 148 cls->name, dir, devinfo); 149 err = ENODEV; 150 } 151 PCM_RELEASE(d); 152 PCM_UNLOCK(d); 153 154 return (err); 155 } 156 157 static void 158 pcm_killchans(struct snddev_info *d) 159 { 160 struct pcm_channel *ch; 161 bool again; 162 163 PCM_BUSYASSERT(d); 164 KASSERT(!PCM_REGISTERED(d), ("%s(): still registered\n", __func__)); 165 166 for (;;) { 167 again = false; 168 /* Make sure all channels are stopped. */ 169 CHN_FOREACH(ch, d, channels.pcm) { 170 CHN_LOCK(ch); 171 if (ch->inprog == 0 && ch->sleeping == 0 && 172 CHN_STOPPED(ch)) { 173 CHN_UNLOCK(ch); 174 continue; 175 } 176 chn_shutdown(ch); 177 if (ch->direction == PCMDIR_PLAY) 178 chn_flush(ch); 179 else 180 chn_abort(ch); 181 CHN_UNLOCK(ch); 182 again = true; 183 } 184 /* 185 * Some channels are still active. Sleep for a bit and try 186 * again. 187 */ 188 if (again) 189 pause_sbt("pcmkillchans", mstosbt(5), 0, 0); 190 else 191 break; 192 } 193 194 /* All channels are finally dead. */ 195 while (!CHN_EMPTY(d, channels.pcm)) { 196 ch = CHN_FIRST(d, channels.pcm); 197 chn_kill(ch); 198 } 199 200 if (d->p_unr != NULL) 201 delete_unrhdr(d->p_unr); 202 if (d->vp_unr != NULL) 203 delete_unrhdr(d->vp_unr); 204 if (d->r_unr != NULL) 205 delete_unrhdr(d->r_unr); 206 if (d->vr_unr != NULL) 207 delete_unrhdr(d->vr_unr); 208 } 209 210 static int 211 pcm_best_unit(int old) 212 { 213 struct snddev_info *d; 214 int i, best, bestprio, prio; 215 216 best = -1; 217 bestprio = -100; 218 bus_topo_lock(); 219 for (i = 0; pcm_devclass != NULL && 220 i < devclass_get_maxunit(pcm_devclass); i++) { 221 d = devclass_get_softc(pcm_devclass, i); 222 if (!PCM_REGISTERED(d)) 223 continue; 224 prio = 0; 225 if (d->playcount == 0) 226 prio -= 10; 227 if (d->reccount == 0) 228 prio -= 2; 229 if (prio > bestprio || (prio == bestprio && i == old)) { 230 best = i; 231 bestprio = prio; 232 } 233 } 234 bus_topo_unlock(); 235 236 return (best); 237 } 238 239 uint32_t 240 pcm_getflags(device_t dev) 241 { 242 struct snddev_info *d = device_get_softc(dev); 243 244 return d->flags; 245 } 246 247 void 248 pcm_setflags(device_t dev, uint32_t val) 249 { 250 struct snddev_info *d = device_get_softc(dev); 251 252 d->flags = val; 253 } 254 255 void * 256 pcm_getdevinfo(device_t dev) 257 { 258 struct snddev_info *d = device_get_softc(dev); 259 260 return d->devinfo; 261 } 262 263 unsigned int 264 pcm_getbuffersize(device_t dev, unsigned int minbufsz, unsigned int deflt, unsigned int maxbufsz) 265 { 266 struct snddev_info *d = device_get_softc(dev); 267 int sz, x; 268 269 sz = 0; 270 if (resource_int_value(device_get_name(dev), device_get_unit(dev), "buffersize", &sz) == 0) { 271 x = sz; 272 RANGE(sz, minbufsz, maxbufsz); 273 if (x != sz) 274 device_printf(dev, "'buffersize=%d' hint is out of range (%d-%d), using %d\n", x, minbufsz, maxbufsz, sz); 275 x = minbufsz; 276 while (x < sz) 277 x <<= 1; 278 if (x > sz) 279 x >>= 1; 280 if (x != sz) { 281 device_printf(dev, "'buffersize=%d' hint is not a power of 2, using %d\n", sz, x); 282 sz = x; 283 } 284 } else { 285 sz = deflt; 286 } 287 288 d->bufsz = sz; 289 290 return sz; 291 } 292 293 static int 294 sysctl_dev_pcm_bitperfect(SYSCTL_HANDLER_ARGS) 295 { 296 struct snddev_info *d; 297 int err, val; 298 299 d = oidp->oid_arg1; 300 if (!PCM_REGISTERED(d)) 301 return (ENODEV); 302 303 PCM_LOCK(d); 304 PCM_WAIT(d); 305 val = (d->flags & SD_F_BITPERFECT) ? 1 : 0; 306 PCM_ACQUIRE(d); 307 PCM_UNLOCK(d); 308 309 err = sysctl_handle_int(oidp, &val, 0, req); 310 311 if (err == 0 && req->newptr != NULL) { 312 if (!(val == 0 || val == 1)) { 313 PCM_RELEASE_QUICK(d); 314 return (EINVAL); 315 } 316 317 PCM_LOCK(d); 318 319 d->flags &= ~SD_F_BITPERFECT; 320 d->flags |= (val != 0) ? SD_F_BITPERFECT : 0; 321 322 PCM_RELEASE(d); 323 PCM_UNLOCK(d); 324 } else 325 PCM_RELEASE_QUICK(d); 326 327 return (err); 328 } 329 330 static int 331 sysctl_dev_pcm_mode(SYSCTL_HANDLER_ARGS) 332 { 333 struct snddev_info *d; 334 int mode = 0; 335 336 d = oidp->oid_arg1; 337 if (!PCM_REGISTERED(d)) 338 return (ENODEV); 339 340 PCM_LOCK(d); 341 if (d->playcount > 0) 342 mode |= PCM_MODE_PLAY; 343 if (d->reccount > 0) 344 mode |= PCM_MODE_REC; 345 if (d->mixer_dev != NULL) 346 mode |= PCM_MODE_MIXER; 347 PCM_UNLOCK(d); 348 349 return (sysctl_handle_int(oidp, &mode, 0, req)); 350 } 351 352 /* 353 * Basic initialization so that drivers can use pcm_addchan() before 354 * pcm_register(). 355 */ 356 void 357 pcm_init(device_t dev, void *devinfo) 358 { 359 struct snddev_info *d; 360 int i; 361 362 d = device_get_softc(dev); 363 d->dev = dev; 364 d->lock = snd_mtxcreate(device_get_nameunit(dev), "sound cdev"); 365 cv_init(&d->cv, device_get_nameunit(dev)); 366 367 i = 0; 368 if (resource_int_value(device_get_name(dev), device_get_unit(dev), 369 "vpc", &i) != 0 || i != 0) 370 d->flags |= SD_F_VPC; 371 372 if (resource_int_value(device_get_name(dev), device_get_unit(dev), 373 "bitperfect", &i) == 0 && i != 0) 374 d->flags |= SD_F_BITPERFECT; 375 376 d->devinfo = devinfo; 377 d->reccount = 0; 378 d->playcount = 0; 379 d->pvchancount = 0; 380 d->rvchancount = 0; 381 d->pvchanrate = 0; 382 d->pvchanformat = 0; 383 d->rvchanrate = 0; 384 d->rvchanformat = 0; 385 d->p_unr = new_unrhdr(0, INT_MAX, NULL); 386 d->vp_unr = new_unrhdr(0, INT_MAX, NULL); 387 d->r_unr = new_unrhdr(0, INT_MAX, NULL); 388 d->vr_unr = new_unrhdr(0, INT_MAX, NULL); 389 390 CHN_INIT(d, channels.pcm); 391 CHN_INIT(d, channels.pcm.busy); 392 CHN_INIT(d, channels.pcm.opened); 393 CHN_INIT(d, channels.pcm.primary); 394 } 395 396 int 397 pcm_register(device_t dev, char *str) 398 { 399 struct snddev_info *d = device_get_softc(dev); 400 401 /* should only be called once */ 402 if (d->flags & SD_F_REGISTERED) 403 return (EINVAL); 404 405 if (d->playcount == 0 || d->reccount == 0) 406 d->flags |= SD_F_SIMPLEX; 407 if (d->playcount > 0) 408 d->flags |= SD_F_PVCHANS; 409 if (d->reccount > 0) 410 d->flags |= SD_F_RVCHANS; 411 412 strlcpy(d->status, str, SND_STATUSLEN); 413 414 /* Done, we're ready.. */ 415 d->flags |= SD_F_REGISTERED; 416 417 /* 418 * Create all sysctls once SD_F_REGISTERED is set else 419 * tunable sysctls won't work: 420 */ 421 sysctl_ctx_init(&d->play_sysctl_ctx); 422 d->play_sysctl_tree = SYSCTL_ADD_NODE(&d->play_sysctl_ctx, 423 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, "play", 424 CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "playback channels node"); 425 sysctl_ctx_init(&d->rec_sysctl_ctx); 426 d->rec_sysctl_tree = SYSCTL_ADD_NODE(&d->rec_sysctl_ctx, 427 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, "rec", 428 CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "recording channels node"); 429 430 /* XXX: a user should be able to set this with a control tool, the 431 sysadmin then needs min+max sysctls for this */ 432 SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev), 433 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 434 OID_AUTO, "buffersize", CTLFLAG_RD, &d->bufsz, 0, 435 "allocated buffer size"); 436 SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 437 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, 438 "bitperfect", CTLTYPE_INT | CTLFLAG_RWTUN | CTLFLAG_MPSAFE, d, 439 sizeof(d), sysctl_dev_pcm_bitperfect, "I", 440 "bit-perfect playback/recording (0=disable, 1=enable)"); 441 SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 442 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, 443 "mode", CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, d, sizeof(d), 444 sysctl_dev_pcm_mode, "I", 445 "mode (1=mixer, 2=play, 4=rec. The values are OR'ed if more than " 446 "one mode is supported)"); 447 vchan_initsys(dev); 448 if (d->flags & SD_F_EQ) 449 feeder_eq_initsys(dev); 450 451 if (snd_unit_auto < 0) 452 snd_unit_auto = (snd_unit < 0) ? 1 : 0; 453 if (snd_unit < 0 || snd_unit_auto > 1) 454 snd_unit = device_get_unit(dev); 455 else if (snd_unit_auto == 1) 456 snd_unit = pcm_best_unit(snd_unit); 457 458 sndstat_register(dev, d->status); 459 460 return (dsp_make_dev(dev)); 461 } 462 463 int 464 pcm_unregister(device_t dev) 465 { 466 struct snddev_info *d; 467 468 d = device_get_softc(dev); 469 470 if (!PCM_ALIVE(d)) { 471 device_printf(dev, "unregister: device not configured\n"); 472 return (0); 473 } 474 475 PCM_LOCK(d); 476 PCM_WAIT(d); 477 478 d->flags &= ~SD_F_REGISTERED; 479 480 PCM_ACQUIRE(d); 481 PCM_UNLOCK(d); 482 483 pcm_killchans(d); 484 485 PCM_RELEASE_QUICK(d); 486 487 if (d->play_sysctl_tree != NULL) { 488 sysctl_ctx_free(&d->play_sysctl_ctx); 489 d->play_sysctl_tree = NULL; 490 } 491 if (d->rec_sysctl_tree != NULL) { 492 sysctl_ctx_free(&d->rec_sysctl_ctx); 493 d->rec_sysctl_tree = NULL; 494 } 495 496 sndstat_unregister(dev); 497 mixer_uninit(dev); 498 dsp_destroy_dev(dev); 499 500 cv_destroy(&d->cv); 501 snd_mtxfree(d->lock); 502 503 if (snd_unit == device_get_unit(dev)) { 504 snd_unit = pcm_best_unit(-1); 505 if (snd_unit_auto == 0) 506 snd_unit_auto = 1; 507 } 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, SOUND_MODVER); 746