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 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/version.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 pcm_veto_load = 1; 53 54 int snd_unit = -1; 55 56 static int snd_unit_auto = -1; 57 SYSCTL_INT(_hw_snd, OID_AUTO, default_auto, CTLFLAG_RWTUN, 58 &snd_unit_auto, 0, "assign default unit to a newly attached device"); 59 60 int snd_maxautovchans = 16; 61 62 SYSCTL_NODE(_hw, OID_AUTO, snd, CTLFLAG_RD | CTLFLAG_MPSAFE, 0, 63 "Sound driver"); 64 65 static void pcm_sysinit(device_t); 66 67 /* 68 * XXX I've had enough with people not telling proper version/arch 69 * while reporting problems, not after 387397913213th questions/requests. 70 */ 71 static char snd_driver_version[] = 72 __XSTRING(SND_DRV_VERSION)"/"MACHINE_ARCH; 73 SYSCTL_STRING(_hw_snd, OID_AUTO, version, CTLFLAG_RD, &snd_driver_version, 74 0, "driver version/arch"); 75 76 /** 77 * @brief Unit number allocator for syncgroup IDs 78 */ 79 struct unrhdr *pcmsg_unrhdr = NULL; 80 81 void * 82 snd_mtxcreate(const char *desc, const char *type) 83 { 84 struct mtx *m; 85 86 m = malloc(sizeof(*m), M_DEVBUF, M_WAITOK | M_ZERO); 87 mtx_init(m, desc, type, MTX_DEF); 88 return m; 89 } 90 91 void 92 snd_mtxfree(void *m) 93 { 94 struct mtx *mtx = m; 95 96 mtx_destroy(mtx); 97 free(mtx, M_DEVBUF); 98 } 99 100 void 101 snd_mtxassert(void *m) 102 { 103 #ifdef INVARIANTS 104 struct mtx *mtx = m; 105 106 mtx_assert(mtx, MA_OWNED); 107 #endif 108 } 109 110 int 111 snd_setup_intr(device_t dev, struct resource *res, int flags, driver_intr_t hand, void *param, void **cookiep) 112 { 113 struct snddev_info *d; 114 115 flags &= INTR_MPSAFE; 116 flags |= INTR_TYPE_AV; 117 d = device_get_softc(dev); 118 if (d != NULL && (flags & INTR_MPSAFE)) 119 d->flags |= SD_F_MPSAFE; 120 121 return bus_setup_intr(dev, res, flags, NULL, hand, param, cookiep); 122 } 123 124 int 125 pcm_setvchans(struct snddev_info *d, int direction, int newcnt, int num) 126 { 127 struct pcm_channel *c, *ch, *nch; 128 struct pcmchan_caps *caps; 129 int i, err, vcnt; 130 131 PCM_BUSYASSERT(d); 132 133 if ((direction == PCMDIR_PLAY && d->playcount < 1) || 134 (direction == PCMDIR_REC && d->reccount < 1)) 135 return (ENODEV); 136 137 if (!(d->flags & SD_F_AUTOVCHAN)) 138 return (EINVAL); 139 140 if (newcnt < 0 || newcnt > SND_MAXVCHANS) 141 return (E2BIG); 142 143 if (direction == PCMDIR_PLAY) 144 vcnt = d->pvchancount; 145 else if (direction == PCMDIR_REC) 146 vcnt = d->rvchancount; 147 else 148 return (EINVAL); 149 150 if (newcnt > vcnt) { 151 KASSERT(num == -1 || 152 (num >= 0 && num < SND_MAXVCHANS && (newcnt - 1) == vcnt), 153 ("bogus vchan_create() request num=%d newcnt=%d vcnt=%d", 154 num, newcnt, vcnt)); 155 /* add new vchans - find a parent channel first */ 156 ch = NULL; 157 CHN_FOREACH(c, d, channels.pcm) { 158 CHN_LOCK(c); 159 if (c->direction == direction && 160 ((c->flags & CHN_F_HAS_VCHAN) || (vcnt == 0 && 161 c->refcount < 1 && 162 !(c->flags & (CHN_F_BUSY | CHN_F_VIRTUAL))))) { 163 /* 164 * Reuse hw channel with vchans already 165 * created. 166 */ 167 if (c->flags & CHN_F_HAS_VCHAN) { 168 ch = c; 169 break; 170 } 171 /* 172 * No vchans ever created, look for 173 * channels with supported formats. 174 */ 175 caps = chn_getcaps(c); 176 if (caps == NULL) { 177 CHN_UNLOCK(c); 178 continue; 179 } 180 for (i = 0; caps->fmtlist[i] != 0; i++) { 181 if (caps->fmtlist[i] & AFMT_CONVERTIBLE) 182 break; 183 } 184 if (caps->fmtlist[i] != 0) { 185 ch = c; 186 break; 187 } 188 } 189 CHN_UNLOCK(c); 190 } 191 if (ch == NULL) 192 return (EBUSY); 193 ch->flags |= CHN_F_BUSY; 194 err = 0; 195 while (err == 0 && newcnt > vcnt) { 196 err = vchan_create(ch, num); 197 if (err == 0) 198 vcnt++; 199 else if (err == E2BIG && newcnt > vcnt) 200 device_printf(d->dev, 201 "%s: err=%d Maximum channel reached.\n", 202 __func__, err); 203 } 204 if (vcnt == 0) 205 ch->flags &= ~CHN_F_BUSY; 206 CHN_UNLOCK(ch); 207 if (err != 0) 208 return (err); 209 } else if (newcnt < vcnt) { 210 KASSERT(num == -1, 211 ("bogus vchan_destroy() request num=%d", num)); 212 CHN_FOREACH(c, d, channels.pcm) { 213 CHN_LOCK(c); 214 if (c->direction != direction || 215 CHN_EMPTY(c, children) || 216 !(c->flags & CHN_F_HAS_VCHAN)) { 217 CHN_UNLOCK(c); 218 continue; 219 } 220 CHN_FOREACH_SAFE(ch, c, nch, children) { 221 CHN_LOCK(ch); 222 if (vcnt == 1 && c->refcount > 0) { 223 CHN_UNLOCK(ch); 224 break; 225 } 226 if (!(ch->flags & CHN_F_BUSY) && 227 ch->refcount < 1) { 228 err = vchan_destroy(ch); 229 if (err == 0) 230 vcnt--; 231 } else 232 CHN_UNLOCK(ch); 233 if (vcnt == newcnt) 234 break; 235 } 236 CHN_UNLOCK(c); 237 break; 238 } 239 } 240 241 return (0); 242 } 243 244 /* return error status and a locked channel */ 245 int 246 pcm_chnalloc(struct snddev_info *d, struct pcm_channel **ch, int direction, 247 pid_t pid, char *comm) 248 { 249 struct pcm_channel *c; 250 int err, vchancount, vchan_num; 251 bool retry; 252 253 KASSERT(d != NULL && ch != NULL && 254 (direction == PCMDIR_PLAY || direction == PCMDIR_REC), 255 ("%s(): invalid d=%p ch=%p direction=%d pid=%d", 256 __func__, d, ch, direction, pid)); 257 PCM_BUSYASSERT(d); 258 259 *ch = NULL; 260 vchan_num = 0; 261 vchancount = (direction == PCMDIR_PLAY) ? d->pvchancount : 262 d->rvchancount; 263 264 retry = false; 265 retry_chnalloc: 266 err = ENOTSUP; 267 /* scan for a free channel */ 268 CHN_FOREACH(c, d, channels.pcm) { 269 CHN_LOCK(c); 270 if (c->direction == direction && (c->flags & CHN_F_VIRTUAL)) { 271 if (vchancount < snd_maxautovchans && 272 vchan_num < c->unit) { 273 CHN_UNLOCK(c); 274 goto vchan_alloc; 275 } 276 vchan_num++; 277 } 278 if (c->direction == direction && !(c->flags & CHN_F_BUSY)) { 279 c->flags |= CHN_F_BUSY; 280 c->pid = pid; 281 strlcpy(c->comm, (comm != NULL) ? comm : 282 CHN_COMM_UNKNOWN, sizeof(c->comm)); 283 *ch = c; 284 return (0); 285 } else if (c->direction == direction && (c->flags & CHN_F_BUSY)) 286 err = EBUSY; 287 CHN_UNLOCK(c); 288 } 289 290 /* 291 * We came from retry_chnalloc and still didn't find a free channel. 292 */ 293 if (retry) 294 return (err); 295 296 vchan_alloc: 297 /* no channel available */ 298 if (!(vchancount > 0 && vchancount < snd_maxautovchans)) 299 return (err); 300 err = pcm_setvchans(d, direction, vchancount + 1, -1); 301 if (err == 0) { 302 retry = true; 303 goto retry_chnalloc; 304 } 305 306 return (err); 307 } 308 309 static void 310 pcm_setmaxautovchans(struct snddev_info *d, int num) 311 { 312 PCM_BUSYASSERT(d); 313 314 if (num < 0) 315 return; 316 317 if (num >= 0 && d->pvchancount > num) 318 (void)pcm_setvchans(d, PCMDIR_PLAY, num, -1); 319 else if (num > 0 && d->pvchancount == 0) 320 (void)pcm_setvchans(d, PCMDIR_PLAY, 1, -1); 321 322 if (num >= 0 && d->rvchancount > num) 323 (void)pcm_setvchans(d, PCMDIR_REC, num, -1); 324 else if (num > 0 && d->rvchancount == 0) 325 (void)pcm_setvchans(d, PCMDIR_REC, 1, -1); 326 } 327 328 static int 329 sysctl_hw_snd_default_unit(SYSCTL_HANDLER_ARGS) 330 { 331 struct snddev_info *d; 332 int error, unit; 333 334 unit = snd_unit; 335 error = sysctl_handle_int(oidp, &unit, 0, req); 336 if (error == 0 && req->newptr != NULL) { 337 d = devclass_get_softc(pcm_devclass, unit); 338 if (!PCM_REGISTERED(d) || CHN_EMPTY(d, channels.pcm)) 339 return EINVAL; 340 snd_unit = unit; 341 snd_unit_auto = 0; 342 } 343 return (error); 344 } 345 /* XXX: do we need a way to let the user change the default unit? */ 346 SYSCTL_PROC(_hw_snd, OID_AUTO, default_unit, 347 CTLTYPE_INT | CTLFLAG_RWTUN | CTLFLAG_ANYBODY | CTLFLAG_NEEDGIANT, 0, 348 sizeof(int), sysctl_hw_snd_default_unit, "I", 349 "default sound device"); 350 351 static int 352 sysctl_hw_snd_maxautovchans(SYSCTL_HANDLER_ARGS) 353 { 354 struct snddev_info *d; 355 int i, v, error; 356 357 v = snd_maxautovchans; 358 error = sysctl_handle_int(oidp, &v, 0, req); 359 if (error == 0 && req->newptr != NULL) { 360 if (v < 0) 361 v = 0; 362 if (v > SND_MAXVCHANS) 363 v = SND_MAXVCHANS; 364 snd_maxautovchans = v; 365 for (i = 0; pcm_devclass != NULL && 366 i < devclass_get_maxunit(pcm_devclass); i++) { 367 d = devclass_get_softc(pcm_devclass, i); 368 if (!PCM_REGISTERED(d)) 369 continue; 370 PCM_ACQUIRE_QUICK(d); 371 pcm_setmaxautovchans(d, v); 372 PCM_RELEASE_QUICK(d); 373 } 374 } 375 return (error); 376 } 377 SYSCTL_PROC(_hw_snd, OID_AUTO, maxautovchans, 378 CTLTYPE_INT | CTLFLAG_RWTUN | CTLFLAG_NEEDGIANT, 0, sizeof(int), 379 sysctl_hw_snd_maxautovchans, "I", 380 "maximum virtual channel"); 381 382 struct pcm_channel * 383 pcm_chn_create(struct snddev_info *d, struct pcm_channel *parent, kobj_class_t cls, int dir, int num, void *devinfo) 384 { 385 struct pcm_channel *ch; 386 int direction, err, rpnum, *pnum, max; 387 int type, unit; 388 char *dirs, *devname, buf[CHN_NAMELEN]; 389 390 PCM_BUSYASSERT(d); 391 PCM_LOCKASSERT(d); 392 KASSERT(num >= -1, ("invalid num=%d", num)); 393 394 switch (dir) { 395 case PCMDIR_PLAY: 396 dirs = "play"; 397 direction = PCMDIR_PLAY; 398 pnum = &d->playcount; 399 type = SND_DEV_DSPHW_PLAY; 400 max = SND_MAXHWCHAN; 401 break; 402 case PCMDIR_PLAY_VIRTUAL: 403 dirs = "virtual_play"; 404 direction = PCMDIR_PLAY; 405 pnum = &d->pvchancount; 406 type = SND_DEV_DSPHW_VPLAY; 407 max = SND_MAXVCHANS; 408 break; 409 case PCMDIR_REC: 410 dirs = "record"; 411 direction = PCMDIR_REC; 412 pnum = &d->reccount; 413 type = SND_DEV_DSPHW_REC; 414 max = SND_MAXHWCHAN; 415 break; 416 case PCMDIR_REC_VIRTUAL: 417 dirs = "virtual_record"; 418 direction = PCMDIR_REC; 419 pnum = &d->rvchancount; 420 type = SND_DEV_DSPHW_VREC; 421 max = SND_MAXVCHANS; 422 break; 423 default: 424 return (NULL); 425 } 426 427 unit = (num == -1) ? 0 : num; 428 429 if (*pnum >= max || unit >= max) 430 return (NULL); 431 432 rpnum = 0; 433 434 CHN_FOREACH(ch, d, channels.pcm) { 435 if (ch->type != type) 436 continue; 437 if (unit == ch->unit && num != -1) { 438 device_printf(d->dev, 439 "channel num=%d allocated!\n", unit); 440 return (NULL); 441 } 442 unit++; 443 if (unit >= max) { 444 device_printf(d->dev, 445 "chan=%d > %d\n", unit, max); 446 return (NULL); 447 } 448 rpnum++; 449 } 450 451 if (*pnum != rpnum) { 452 device_printf(d->dev, 453 "%s(): WARNING: pnum screwed : dirs=%s pnum=%d rpnum=%d\n", 454 __func__, dirs, *pnum, rpnum); 455 return (NULL); 456 } 457 458 PCM_UNLOCK(d); 459 ch = malloc(sizeof(*ch), M_DEVBUF, M_WAITOK | M_ZERO); 460 ch->methods = kobj_create(cls, M_DEVBUF, M_WAITOK | M_ZERO); 461 ch->type = type; 462 ch->unit = unit; 463 ch->pid = -1; 464 strlcpy(ch->comm, CHN_COMM_UNUSED, sizeof(ch->comm)); 465 ch->parentsnddev = d; 466 ch->parentchannel = parent; 467 ch->dev = d->dev; 468 ch->trigger = PCMTRIG_STOP; 469 devname = dsp_unit2name(buf, sizeof(buf), ch); 470 if (devname == NULL) { 471 device_printf(d->dev, "Failed to query device name"); 472 kobj_delete(ch->methods, M_DEVBUF); 473 free(ch, M_DEVBUF); 474 return (NULL); 475 } 476 snprintf(ch->name, sizeof(ch->name), "%s:%s:%s", 477 device_get_nameunit(ch->dev), dirs, devname); 478 479 err = chn_init(ch, devinfo, dir, direction); 480 PCM_LOCK(d); 481 if (err) { 482 device_printf(d->dev, "chn_init(%s) failed: err = %d\n", 483 ch->name, err); 484 kobj_delete(ch->methods, M_DEVBUF); 485 free(ch, M_DEVBUF); 486 return (NULL); 487 } 488 489 return (ch); 490 } 491 492 int 493 pcm_chn_add(struct snddev_info *d, struct pcm_channel *ch) 494 { 495 PCM_BUSYASSERT(d); 496 PCM_LOCKASSERT(d); 497 KASSERT(ch != NULL && (ch->direction == PCMDIR_PLAY || 498 ch->direction == PCMDIR_REC), ("Invalid pcm channel")); 499 500 CHN_INSERT_SORT_ASCEND(d, ch, channels.pcm); 501 502 switch (ch->type) { 503 case SND_DEV_DSPHW_PLAY: 504 d->playcount++; 505 break; 506 case SND_DEV_DSPHW_VPLAY: 507 d->pvchancount++; 508 break; 509 case SND_DEV_DSPHW_REC: 510 d->reccount++; 511 break; 512 case SND_DEV_DSPHW_VREC: 513 d->rvchancount++; 514 break; 515 default: 516 break; 517 } 518 519 return (0); 520 } 521 522 int 523 pcm_chn_remove(struct snddev_info *d, struct pcm_channel *ch) 524 { 525 struct pcm_channel *tmp; 526 527 PCM_BUSYASSERT(d); 528 PCM_LOCKASSERT(d); 529 530 tmp = NULL; 531 532 CHN_FOREACH(tmp, d, channels.pcm) { 533 if (tmp == ch) 534 break; 535 } 536 537 if (tmp != ch) 538 return (EINVAL); 539 540 CHN_REMOVE(d, ch, channels.pcm); 541 542 switch (ch->type) { 543 case SND_DEV_DSPHW_PLAY: 544 d->playcount--; 545 break; 546 case SND_DEV_DSPHW_VPLAY: 547 d->pvchancount--; 548 break; 549 case SND_DEV_DSPHW_REC: 550 d->reccount--; 551 break; 552 case SND_DEV_DSPHW_VREC: 553 d->rvchancount--; 554 break; 555 default: 556 break; 557 } 558 559 return (0); 560 } 561 562 int 563 pcm_addchan(device_t dev, int dir, kobj_class_t cls, void *devinfo) 564 { 565 struct snddev_info *d = device_get_softc(dev); 566 struct pcm_channel *ch; 567 int err; 568 569 PCM_BUSYASSERT(d); 570 571 PCM_LOCK(d); 572 ch = pcm_chn_create(d, NULL, cls, dir, -1, devinfo); 573 if (!ch) { 574 device_printf(d->dev, "pcm_chn_create(%s, %d, %p) failed\n", 575 cls->name, dir, devinfo); 576 PCM_UNLOCK(d); 577 return (ENODEV); 578 } 579 580 err = pcm_chn_add(d, ch); 581 PCM_UNLOCK(d); 582 if (err) { 583 device_printf(d->dev, "pcm_chn_add(%s) failed, err=%d\n", 584 ch->name, err); 585 chn_kill(ch); 586 } 587 588 return (err); 589 } 590 591 static void 592 pcm_killchans(struct snddev_info *d) 593 { 594 struct pcm_channel *ch; 595 int error; 596 bool found; 597 598 PCM_BUSYASSERT(d); 599 do { 600 found = false; 601 CHN_FOREACH(ch, d, channels.pcm) { 602 CHN_LOCK(ch); 603 /* 604 * Make sure no channel has went to sleep in the 605 * meantime. 606 */ 607 chn_shutdown(ch); 608 /* 609 * We have to give a thread sleeping in chn_sleep() a 610 * chance to observe that the channel is dead. 611 */ 612 if ((ch->flags & CHN_F_SLEEPING) == 0) { 613 found = true; 614 CHN_UNLOCK(ch); 615 break; 616 } 617 CHN_UNLOCK(ch); 618 } 619 620 /* 621 * All channels are still sleeping. Sleep for a bit and try 622 * again to see if any of them is awake now. 623 */ 624 if (!found) { 625 pause_sbt("pcmkillchans", SBT_1MS * 5, 0, 0); 626 continue; 627 } 628 629 PCM_LOCK(d); 630 error = pcm_chn_remove(d, ch); 631 PCM_UNLOCK(d); 632 if (error == 0) 633 chn_kill(ch); 634 } while (!CHN_EMPTY(d, channels.pcm)); 635 } 636 637 static int 638 pcm_best_unit(int old) 639 { 640 struct snddev_info *d; 641 int i, best, bestprio, prio; 642 643 best = -1; 644 bestprio = -100; 645 for (i = 0; pcm_devclass != NULL && 646 i < devclass_get_maxunit(pcm_devclass); i++) { 647 d = devclass_get_softc(pcm_devclass, i); 648 if (!PCM_REGISTERED(d)) 649 continue; 650 prio = 0; 651 if (d->playcount == 0) 652 prio -= 10; 653 if (d->reccount == 0) 654 prio -= 2; 655 if (prio > bestprio || (prio == bestprio && i == old)) { 656 best = i; 657 bestprio = prio; 658 } 659 } 660 return (best); 661 } 662 663 int 664 pcm_setstatus(device_t dev, char *str) 665 { 666 struct snddev_info *d = device_get_softc(dev); 667 668 /* should only be called once */ 669 if (d->flags & SD_F_REGISTERED) 670 return (EINVAL); 671 672 PCM_BUSYASSERT(d); 673 674 if (d->playcount == 0 || d->reccount == 0) 675 d->flags |= SD_F_SIMPLEX; 676 677 if (d->playcount > 0 || d->reccount > 0) 678 d->flags |= SD_F_AUTOVCHAN; 679 680 pcm_setmaxautovchans(d, snd_maxautovchans); 681 682 strlcpy(d->status, str, SND_STATUSLEN); 683 684 PCM_LOCK(d); 685 686 /* Done, we're ready.. */ 687 d->flags |= SD_F_REGISTERED; 688 689 PCM_RELEASE(d); 690 691 PCM_UNLOCK(d); 692 693 /* 694 * Create all sysctls once SD_F_REGISTERED is set else 695 * tunable sysctls won't work: 696 */ 697 pcm_sysinit(dev); 698 699 if (snd_unit_auto < 0) 700 snd_unit_auto = (snd_unit < 0) ? 1 : 0; 701 if (snd_unit < 0 || snd_unit_auto > 1) 702 snd_unit = device_get_unit(dev); 703 else if (snd_unit_auto == 1) 704 snd_unit = pcm_best_unit(snd_unit); 705 706 return (0); 707 } 708 709 uint32_t 710 pcm_getflags(device_t dev) 711 { 712 struct snddev_info *d = device_get_softc(dev); 713 714 return d->flags; 715 } 716 717 void 718 pcm_setflags(device_t dev, uint32_t val) 719 { 720 struct snddev_info *d = device_get_softc(dev); 721 722 d->flags = val; 723 } 724 725 void * 726 pcm_getdevinfo(device_t dev) 727 { 728 struct snddev_info *d = device_get_softc(dev); 729 730 return d->devinfo; 731 } 732 733 unsigned int 734 pcm_getbuffersize(device_t dev, unsigned int minbufsz, unsigned int deflt, unsigned int maxbufsz) 735 { 736 struct snddev_info *d = device_get_softc(dev); 737 int sz, x; 738 739 sz = 0; 740 if (resource_int_value(device_get_name(dev), device_get_unit(dev), "buffersize", &sz) == 0) { 741 x = sz; 742 RANGE(sz, minbufsz, maxbufsz); 743 if (x != sz) 744 device_printf(dev, "'buffersize=%d' hint is out of range (%d-%d), using %d\n", x, minbufsz, maxbufsz, sz); 745 x = minbufsz; 746 while (x < sz) 747 x <<= 1; 748 if (x > sz) 749 x >>= 1; 750 if (x != sz) { 751 device_printf(dev, "'buffersize=%d' hint is not a power of 2, using %d\n", sz, x); 752 sz = x; 753 } 754 } else { 755 sz = deflt; 756 } 757 758 d->bufsz = sz; 759 760 return sz; 761 } 762 763 static int 764 sysctl_dev_pcm_bitperfect(SYSCTL_HANDLER_ARGS) 765 { 766 struct snddev_info *d; 767 int err, val; 768 769 d = oidp->oid_arg1; 770 if (!PCM_REGISTERED(d)) 771 return (ENODEV); 772 773 PCM_LOCK(d); 774 PCM_WAIT(d); 775 val = (d->flags & SD_F_BITPERFECT) ? 1 : 0; 776 PCM_ACQUIRE(d); 777 PCM_UNLOCK(d); 778 779 err = sysctl_handle_int(oidp, &val, 0, req); 780 781 if (err == 0 && req->newptr != NULL) { 782 if (!(val == 0 || val == 1)) { 783 PCM_RELEASE_QUICK(d); 784 return (EINVAL); 785 } 786 787 PCM_LOCK(d); 788 789 d->flags &= ~SD_F_BITPERFECT; 790 d->flags |= (val != 0) ? SD_F_BITPERFECT : 0; 791 792 PCM_RELEASE(d); 793 PCM_UNLOCK(d); 794 } else 795 PCM_RELEASE_QUICK(d); 796 797 return (err); 798 } 799 800 static u_int8_t 801 pcm_mode_init(struct snddev_info *d) 802 { 803 u_int8_t mode = 0; 804 805 if (d->playcount > 0) 806 mode |= PCM_MODE_PLAY; 807 if (d->reccount > 0) 808 mode |= PCM_MODE_REC; 809 if (d->mixer_dev != NULL) 810 mode |= PCM_MODE_MIXER; 811 812 return (mode); 813 } 814 815 static void 816 pcm_sysinit(device_t dev) 817 { 818 struct snddev_info *d = device_get_softc(dev); 819 u_int8_t mode; 820 821 mode = pcm_mode_init(d); 822 823 /* XXX: a user should be able to set this with a control tool, the 824 sysadmin then needs min+max sysctls for this */ 825 SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev), 826 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 827 OID_AUTO, "buffersize", CTLFLAG_RD, &d->bufsz, 0, "allocated buffer size"); 828 SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 829 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, 830 "bitperfect", CTLTYPE_INT | CTLFLAG_RWTUN | CTLFLAG_MPSAFE, d, 831 sizeof(d), sysctl_dev_pcm_bitperfect, "I", 832 "bit-perfect playback/recording (0=disable, 1=enable)"); 833 SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev), 834 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 835 OID_AUTO, "mode", CTLFLAG_RD, NULL, mode, 836 "mode (1=mixer, 2=play, 4=rec. The values are OR'ed if more than " 837 "one mode is supported)"); 838 if (d->flags & SD_F_AUTOVCHAN) 839 vchan_initsys(dev); 840 if (d->flags & SD_F_EQ) 841 feeder_eq_initsys(dev); 842 } 843 844 int 845 pcm_register(device_t dev, void *devinfo, int numplay, int numrec) 846 { 847 struct snddev_info *d; 848 int i; 849 850 if (pcm_veto_load) { 851 device_printf(dev, "disabled due to an error while initialising: %d\n", pcm_veto_load); 852 853 return EINVAL; 854 } 855 856 d = device_get_softc(dev); 857 d->dev = dev; 858 d->lock = snd_mtxcreate(device_get_nameunit(dev), "sound cdev"); 859 cv_init(&d->cv, device_get_nameunit(dev)); 860 PCM_ACQUIRE_QUICK(d); 861 #if 0 862 /* 863 * d->flags should be cleared by the allocator of the softc. 864 * We cannot clear this field here because several devices set 865 * this flag before calling pcm_register(). 866 */ 867 d->flags = 0; 868 #endif 869 i = 0; 870 if (resource_int_value(device_get_name(dev), device_get_unit(dev), 871 "vpc", &i) != 0 || i != 0) 872 d->flags |= SD_F_VPC; 873 874 if (resource_int_value(device_get_name(dev), device_get_unit(dev), 875 "bitperfect", &i) == 0 && i != 0) 876 d->flags |= SD_F_BITPERFECT; 877 878 d->devinfo = devinfo; 879 d->reccount = 0; 880 d->playcount = 0; 881 d->pvchancount = 0; 882 d->rvchancount = 0; 883 d->pvchanrate = 0; 884 d->pvchanformat = 0; 885 d->rvchanrate = 0; 886 d->rvchanformat = 0; 887 888 CHN_INIT(d, channels.pcm); 889 CHN_INIT(d, channels.pcm.busy); 890 CHN_INIT(d, channels.pcm.opened); 891 892 /* XXX This is incorrect, but lets play along for now. */ 893 if ((numplay == 0 || numrec == 0) && numplay != numrec) 894 d->flags |= SD_F_SIMPLEX; 895 896 sysctl_ctx_init(&d->play_sysctl_ctx); 897 d->play_sysctl_tree = SYSCTL_ADD_NODE(&d->play_sysctl_ctx, 898 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, "play", 899 CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "playback channels node"); 900 sysctl_ctx_init(&d->rec_sysctl_ctx); 901 d->rec_sysctl_tree = SYSCTL_ADD_NODE(&d->rec_sysctl_ctx, 902 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, "rec", 903 CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "recording channels node"); 904 905 if (numplay > 0 || numrec > 0) 906 d->flags |= SD_F_AUTOVCHAN; 907 908 sndstat_register(dev, d->status); 909 910 return (dsp_make_dev(dev)); 911 } 912 913 int 914 pcm_unregister(device_t dev) 915 { 916 struct snddev_info *d; 917 struct pcm_channel *ch; 918 919 d = device_get_softc(dev); 920 921 if (!PCM_ALIVE(d)) { 922 device_printf(dev, "unregister: device not configured\n"); 923 return (0); 924 } 925 926 PCM_LOCK(d); 927 PCM_WAIT(d); 928 929 d->flags |= SD_F_DETACHING; 930 931 PCM_ACQUIRE(d); 932 PCM_UNLOCK(d); 933 934 CHN_FOREACH(ch, d, channels.pcm) { 935 CHN_LOCK(ch); 936 /* 937 * Do not wait for the timeout in chn_read()/chn_write(). Wake 938 * up the sleeping thread and kill the channel. 939 */ 940 chn_shutdown(ch); 941 chn_abort(ch); 942 CHN_UNLOCK(ch); 943 } 944 945 /* remove /dev/sndstat entry first */ 946 sndstat_unregister(dev); 947 948 PCM_LOCK(d); 949 d->flags |= SD_F_DYING; 950 d->flags &= ~SD_F_REGISTERED; 951 PCM_UNLOCK(d); 952 953 if (d->play_sysctl_tree != NULL) { 954 sysctl_ctx_free(&d->play_sysctl_ctx); 955 d->play_sysctl_tree = NULL; 956 } 957 if (d->rec_sysctl_tree != NULL) { 958 sysctl_ctx_free(&d->rec_sysctl_ctx); 959 d->rec_sysctl_tree = NULL; 960 } 961 962 dsp_destroy_dev(dev); 963 (void)mixer_uninit(dev); 964 965 pcm_killchans(d); 966 967 PCM_LOCK(d); 968 PCM_RELEASE(d); 969 cv_destroy(&d->cv); 970 PCM_UNLOCK(d); 971 snd_mtxfree(d->lock); 972 973 if (snd_unit == device_get_unit(dev)) { 974 snd_unit = pcm_best_unit(-1); 975 if (snd_unit_auto == 0) 976 snd_unit_auto = 1; 977 } 978 979 return (0); 980 } 981 982 /************************************************************************/ 983 984 /** 985 * @brief Handle OSSv4 SNDCTL_SYSINFO ioctl. 986 * 987 * @param si Pointer to oss_sysinfo struct where information about the 988 * sound subsystem will be written/copied. 989 * 990 * This routine returns information about the sound system, such as the 991 * current OSS version, number of audio, MIDI, and mixer drivers, etc. 992 * Also includes a bitmask showing which of the above types of devices 993 * are open (busy). 994 * 995 * @note 996 * Calling threads must not hold any snddev_info or pcm_channel locks. 997 * 998 * @author Ryan Beasley <ryanb@FreeBSD.org> 999 */ 1000 void 1001 sound_oss_sysinfo(oss_sysinfo *si) 1002 { 1003 static char si_product[] = "FreeBSD native OSS ABI"; 1004 static char si_version[] = __XSTRING(__FreeBSD_version); 1005 static char si_license[] = "BSD"; 1006 static int intnbits = sizeof(int) * 8; /* Better suited as macro? 1007 Must pester a C guru. */ 1008 1009 struct snddev_info *d; 1010 struct pcm_channel *c; 1011 int i, j, ncards; 1012 1013 ncards = 0; 1014 1015 strlcpy(si->product, si_product, sizeof(si->product)); 1016 strlcpy(si->version, si_version, sizeof(si->version)); 1017 si->versionnum = SOUND_VERSION; 1018 strlcpy(si->license, si_license, sizeof(si->license)); 1019 1020 /* 1021 * Iterate over PCM devices and their channels, gathering up data 1022 * for the numaudios, ncards, and openedaudio fields. 1023 */ 1024 si->numaudios = 0; 1025 bzero((void *)&si->openedaudio, sizeof(si->openedaudio)); 1026 1027 j = 0; 1028 1029 for (i = 0; pcm_devclass != NULL && 1030 i < devclass_get_maxunit(pcm_devclass); i++) { 1031 d = devclass_get_softc(pcm_devclass, i); 1032 if (!PCM_REGISTERED(d)) 1033 continue; 1034 1035 /* XXX Need Giant magic entry ??? */ 1036 1037 /* See note in function's docblock */ 1038 PCM_UNLOCKASSERT(d); 1039 PCM_LOCK(d); 1040 1041 si->numaudios += PCM_CHANCOUNT(d); 1042 ++ncards; 1043 1044 CHN_FOREACH(c, d, channels.pcm) { 1045 CHN_UNLOCKASSERT(c); 1046 CHN_LOCK(c); 1047 if (c->flags & CHN_F_BUSY) 1048 si->openedaudio[j / intnbits] |= 1049 (1 << (j % intnbits)); 1050 CHN_UNLOCK(c); 1051 j++; 1052 } 1053 1054 PCM_UNLOCK(d); 1055 } 1056 si->numaudioengines = si->numaudios; 1057 1058 si->numsynths = 0; /* OSSv4 docs: this field is obsolete */ 1059 /** 1060 * @todo Collect num{midis,timers}. 1061 * 1062 * Need access to sound/midi/midi.c::midistat_lock in order 1063 * to safely touch midi_devices and get a head count of, well, 1064 * MIDI devices. midistat_lock is a global static (i.e., local to 1065 * midi.c), but midi_devices is a regular global; should the mutex 1066 * be publicized, or is there another way to get this information? 1067 * 1068 * NB: MIDI/sequencer stuff is currently on hold. 1069 */ 1070 si->nummidis = 0; 1071 si->numtimers = 0; 1072 si->nummixers = mixer_count; 1073 si->numcards = ncards; 1074 /* OSSv4 docs: Intended only for test apps; API doesn't 1075 really have much of a concept of cards. Shouldn't be 1076 used by applications. */ 1077 1078 /** 1079 * @todo Fill in "busy devices" fields. 1080 * 1081 * si->openedmidi = " MIDI devices 1082 */ 1083 bzero((void *)&si->openedmidi, sizeof(si->openedmidi)); 1084 1085 /* 1086 * Si->filler is a reserved array, but according to docs each 1087 * element should be set to -1. 1088 */ 1089 for (i = 0; i < sizeof(si->filler)/sizeof(si->filler[0]); i++) 1090 si->filler[i] = -1; 1091 } 1092 1093 int 1094 sound_oss_card_info(oss_card_info *si) 1095 { 1096 struct snddev_info *d; 1097 int i, ncards; 1098 1099 ncards = 0; 1100 1101 for (i = 0; pcm_devclass != NULL && 1102 i < devclass_get_maxunit(pcm_devclass); i++) { 1103 d = devclass_get_softc(pcm_devclass, i); 1104 if (!PCM_REGISTERED(d)) 1105 continue; 1106 1107 if (ncards++ != si->card) 1108 continue; 1109 1110 PCM_UNLOCKASSERT(d); 1111 PCM_LOCK(d); 1112 1113 strlcpy(si->shortname, device_get_nameunit(d->dev), 1114 sizeof(si->shortname)); 1115 strlcpy(si->longname, device_get_desc(d->dev), 1116 sizeof(si->longname)); 1117 strlcpy(si->hw_info, d->status, sizeof(si->hw_info)); 1118 si->intr_count = si->ack_count = 0; 1119 1120 PCM_UNLOCK(d); 1121 1122 return (0); 1123 } 1124 return (ENXIO); 1125 } 1126 1127 /************************************************************************/ 1128 1129 static int 1130 sound_modevent(module_t mod, int type, void *data) 1131 { 1132 int ret; 1133 1134 ret = 0; 1135 switch (type) { 1136 case MOD_LOAD: 1137 pcm_devclass = devclass_create("pcm"); 1138 pcmsg_unrhdr = new_unrhdr(1, INT_MAX, NULL); 1139 break; 1140 case MOD_UNLOAD: 1141 if (pcmsg_unrhdr != NULL) { 1142 delete_unrhdr(pcmsg_unrhdr); 1143 pcmsg_unrhdr = NULL; 1144 } 1145 break; 1146 case MOD_SHUTDOWN: 1147 break; 1148 default: 1149 ret = ENOTSUP; 1150 } 1151 1152 return ret; 1153 } 1154 1155 DEV_MODULE(sound, sound_modevent, NULL); 1156 MODULE_VERSION(sound, SOUND_MODVER); 1157