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