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, int devunit) 248 { 249 struct pcm_channel *c; 250 int err, vchancount, vchan_num; 251 252 KASSERT(d != NULL && ch != NULL && (devunit == -1 || 253 !(devunit & ~(SND_U_MASK | SND_D_MASK | SND_C_MASK))) && 254 (direction == PCMDIR_PLAY || direction == PCMDIR_REC), 255 ("%s(): invalid d=%p ch=%p direction=%d pid=%d devunit=%d", 256 __func__, d, ch, direction, pid, devunit)); 257 PCM_BUSYASSERT(d); 258 259 /* Double check again. */ 260 if (devunit != -1) { 261 switch (snd_unit2d(devunit)) { 262 case SND_DEV_DSPHW_PLAY: 263 case SND_DEV_DSPHW_VPLAY: 264 if (direction != PCMDIR_PLAY) 265 return (ENOTSUP); 266 break; 267 case SND_DEV_DSPHW_REC: 268 case SND_DEV_DSPHW_VREC: 269 if (direction != PCMDIR_REC) 270 return (ENOTSUP); 271 break; 272 default: 273 if (!(direction == PCMDIR_PLAY || 274 direction == PCMDIR_REC)) 275 return (ENOTSUP); 276 break; 277 } 278 } 279 280 *ch = NULL; 281 vchan_num = 0; 282 vchancount = (direction == PCMDIR_PLAY) ? d->pvchancount : 283 d->rvchancount; 284 285 retry_chnalloc: 286 err = ENOTSUP; 287 /* scan for a free channel */ 288 CHN_FOREACH(c, d, channels.pcm) { 289 CHN_LOCK(c); 290 if (devunit == -1 && c->direction == direction && 291 (c->flags & CHN_F_VIRTUAL)) { 292 if (vchancount < snd_maxautovchans && 293 vchan_num < CHN_CHAN(c)) { 294 CHN_UNLOCK(c); 295 goto vchan_alloc; 296 } 297 vchan_num++; 298 } 299 if (c->direction == direction && !(c->flags & CHN_F_BUSY) && 300 (devunit == -1 || devunit == -2 || c->unit == devunit)) { 301 c->flags |= CHN_F_BUSY; 302 c->pid = pid; 303 strlcpy(c->comm, (comm != NULL) ? comm : 304 CHN_COMM_UNKNOWN, sizeof(c->comm)); 305 *ch = c; 306 return (0); 307 } else if (c->unit == devunit) { 308 if (c->direction != direction) 309 err = ENOTSUP; 310 else if (c->flags & CHN_F_BUSY) 311 err = EBUSY; 312 else 313 err = EINVAL; 314 CHN_UNLOCK(c); 315 return (err); 316 } else if ((devunit == -1 || devunit == -2) && 317 c->direction == direction && (c->flags & CHN_F_BUSY)) 318 err = EBUSY; 319 CHN_UNLOCK(c); 320 } 321 322 if (devunit == -2) 323 return (err); 324 325 vchan_alloc: 326 /* no channel available */ 327 if (devunit == -1 || snd_unit2d(devunit) == SND_DEV_DSPHW_VPLAY || 328 snd_unit2d(devunit) == SND_DEV_DSPHW_VREC) { 329 if (!(vchancount > 0 && vchancount < snd_maxautovchans) && 330 (devunit == -1 || snd_unit2c(devunit) < snd_maxautovchans)) 331 return (err); 332 err = pcm_setvchans(d, direction, vchancount + 1, 333 (devunit == -1) ? -1 : snd_unit2c(devunit)); 334 if (err == 0) { 335 if (devunit == -1) 336 devunit = -2; 337 goto retry_chnalloc; 338 } 339 } 340 341 return (err); 342 } 343 344 /* release a locked channel and unlock it */ 345 int 346 pcm_chnrelease(struct pcm_channel *c) 347 { 348 PCM_BUSYASSERT(c->parentsnddev); 349 CHN_LOCKASSERT(c); 350 351 c->flags &= ~CHN_F_BUSY; 352 c->pid = -1; 353 strlcpy(c->comm, CHN_COMM_UNUSED, sizeof(c->comm)); 354 CHN_UNLOCK(c); 355 356 return (0); 357 } 358 359 int 360 pcm_chnref(struct pcm_channel *c, int ref) 361 { 362 PCM_BUSYASSERT(c->parentsnddev); 363 CHN_LOCKASSERT(c); 364 365 c->refcount += ref; 366 367 return (c->refcount); 368 } 369 370 static void 371 pcm_setmaxautovchans(struct snddev_info *d, int num) 372 { 373 PCM_BUSYASSERT(d); 374 375 if (num < 0) 376 return; 377 378 if (num >= 0 && d->pvchancount > num) 379 (void)pcm_setvchans(d, PCMDIR_PLAY, num, -1); 380 else if (num > 0 && d->pvchancount == 0) 381 (void)pcm_setvchans(d, PCMDIR_PLAY, 1, -1); 382 383 if (num >= 0 && d->rvchancount > num) 384 (void)pcm_setvchans(d, PCMDIR_REC, num, -1); 385 else if (num > 0 && d->rvchancount == 0) 386 (void)pcm_setvchans(d, PCMDIR_REC, 1, -1); 387 } 388 389 static int 390 sysctl_hw_snd_default_unit(SYSCTL_HANDLER_ARGS) 391 { 392 struct snddev_info *d; 393 int error, unit; 394 395 unit = snd_unit; 396 error = sysctl_handle_int(oidp, &unit, 0, req); 397 if (error == 0 && req->newptr != NULL) { 398 d = devclass_get_softc(pcm_devclass, unit); 399 if (!PCM_REGISTERED(d) || CHN_EMPTY(d, channels.pcm)) 400 return EINVAL; 401 snd_unit = unit; 402 snd_unit_auto = 0; 403 } 404 return (error); 405 } 406 /* XXX: do we need a way to let the user change the default unit? */ 407 SYSCTL_PROC(_hw_snd, OID_AUTO, default_unit, 408 CTLTYPE_INT | CTLFLAG_RWTUN | CTLFLAG_ANYBODY | CTLFLAG_NEEDGIANT, 0, 409 sizeof(int), sysctl_hw_snd_default_unit, "I", 410 "default sound device"); 411 412 static int 413 sysctl_hw_snd_maxautovchans(SYSCTL_HANDLER_ARGS) 414 { 415 struct snddev_info *d; 416 int i, v, error; 417 418 v = snd_maxautovchans; 419 error = sysctl_handle_int(oidp, &v, 0, req); 420 if (error == 0 && req->newptr != NULL) { 421 if (v < 0) 422 v = 0; 423 if (v > SND_MAXVCHANS) 424 v = SND_MAXVCHANS; 425 snd_maxautovchans = v; 426 for (i = 0; pcm_devclass != NULL && 427 i < devclass_get_maxunit(pcm_devclass); i++) { 428 d = devclass_get_softc(pcm_devclass, i); 429 if (!PCM_REGISTERED(d)) 430 continue; 431 PCM_ACQUIRE_QUICK(d); 432 pcm_setmaxautovchans(d, v); 433 PCM_RELEASE_QUICK(d); 434 } 435 } 436 return (error); 437 } 438 SYSCTL_PROC(_hw_snd, OID_AUTO, maxautovchans, 439 CTLTYPE_INT | CTLFLAG_RWTUN | CTLFLAG_NEEDGIANT, 0, sizeof(int), 440 sysctl_hw_snd_maxautovchans, "I", 441 "maximum virtual channel"); 442 443 struct pcm_channel * 444 pcm_chn_create(struct snddev_info *d, struct pcm_channel *parent, kobj_class_t cls, int dir, int num, void *devinfo) 445 { 446 struct pcm_channel *ch; 447 int direction, err, rpnum, *pnum, max; 448 int udc, device, chan; 449 char *dirs, *devname, buf[CHN_NAMELEN]; 450 451 PCM_BUSYASSERT(d); 452 PCM_LOCKASSERT(d); 453 KASSERT(num >= -1, ("invalid num=%d", num)); 454 455 switch (dir) { 456 case PCMDIR_PLAY: 457 dirs = "play"; 458 direction = PCMDIR_PLAY; 459 pnum = &d->playcount; 460 device = SND_DEV_DSPHW_PLAY; 461 max = SND_MAXHWCHAN; 462 break; 463 case PCMDIR_PLAY_VIRTUAL: 464 dirs = "virtual_play"; 465 direction = PCMDIR_PLAY; 466 pnum = &d->pvchancount; 467 device = SND_DEV_DSPHW_VPLAY; 468 max = SND_MAXVCHANS; 469 break; 470 case PCMDIR_REC: 471 dirs = "record"; 472 direction = PCMDIR_REC; 473 pnum = &d->reccount; 474 device = SND_DEV_DSPHW_REC; 475 max = SND_MAXHWCHAN; 476 break; 477 case PCMDIR_REC_VIRTUAL: 478 dirs = "virtual_record"; 479 direction = PCMDIR_REC; 480 pnum = &d->rvchancount; 481 device = SND_DEV_DSPHW_VREC; 482 max = SND_MAXVCHANS; 483 break; 484 default: 485 return (NULL); 486 } 487 488 chan = (num == -1) ? 0 : num; 489 490 if (*pnum >= max || chan >= max) 491 return (NULL); 492 493 rpnum = 0; 494 495 CHN_FOREACH(ch, d, channels.pcm) { 496 if (CHN_DEV(ch) != device) 497 continue; 498 if (chan == CHN_CHAN(ch)) { 499 if (num != -1) { 500 device_printf(d->dev, 501 "channel num=%d allocated!\n", chan); 502 return (NULL); 503 } 504 chan++; 505 if (chan >= max) { 506 device_printf(d->dev, 507 "chan=%d > %d\n", chan, max); 508 return (NULL); 509 } 510 } 511 rpnum++; 512 } 513 514 if (*pnum != rpnum) { 515 device_printf(d->dev, 516 "%s(): WARNING: pnum screwed : dirs=%s pnum=%d rpnum=%d\n", 517 __func__, dirs, *pnum, rpnum); 518 return (NULL); 519 } 520 521 udc = snd_mkunit(device_get_unit(d->dev), device, chan); 522 devname = dsp_unit2name(buf, sizeof(buf), udc); 523 524 if (devname == NULL) { 525 device_printf(d->dev, 526 "Failed to query device name udc=0x%08x\n", udc); 527 return (NULL); 528 } 529 530 PCM_UNLOCK(d); 531 ch = malloc(sizeof(*ch), M_DEVBUF, M_WAITOK | M_ZERO); 532 ch->methods = kobj_create(cls, M_DEVBUF, M_WAITOK | M_ZERO); 533 ch->unit = udc; 534 ch->pid = -1; 535 strlcpy(ch->comm, CHN_COMM_UNUSED, sizeof(ch->comm)); 536 ch->parentsnddev = d; 537 ch->parentchannel = parent; 538 ch->dev = d->dev; 539 ch->trigger = PCMTRIG_STOP; 540 snprintf(ch->name, sizeof(ch->name), "%s:%s:%s", 541 device_get_nameunit(ch->dev), dirs, devname); 542 543 err = chn_init(ch, devinfo, dir, direction); 544 PCM_LOCK(d); 545 if (err) { 546 device_printf(d->dev, "chn_init(%s) failed: err = %d\n", 547 ch->name, err); 548 kobj_delete(ch->methods, M_DEVBUF); 549 free(ch, M_DEVBUF); 550 return (NULL); 551 } 552 553 return (ch); 554 } 555 556 int 557 pcm_chn_destroy(struct pcm_channel *ch) 558 { 559 struct snddev_info *d __diagused; 560 int err; 561 562 d = ch->parentsnddev; 563 PCM_BUSYASSERT(d); 564 565 err = chn_kill(ch); 566 if (err) { 567 device_printf(ch->dev, "chn_kill(%s) failed, err = %d\n", 568 ch->name, err); 569 return (err); 570 } 571 572 kobj_delete(ch->methods, M_DEVBUF); 573 free(ch, M_DEVBUF); 574 575 return (0); 576 } 577 578 int 579 pcm_chn_add(struct snddev_info *d, struct pcm_channel *ch) 580 { 581 PCM_BUSYASSERT(d); 582 PCM_LOCKASSERT(d); 583 KASSERT(ch != NULL && (ch->direction == PCMDIR_PLAY || 584 ch->direction == PCMDIR_REC), ("Invalid pcm channel")); 585 586 CHN_INSERT_SORT_ASCEND(d, ch, channels.pcm); 587 588 switch (CHN_DEV(ch)) { 589 case SND_DEV_DSPHW_PLAY: 590 d->playcount++; 591 break; 592 case SND_DEV_DSPHW_VPLAY: 593 d->pvchancount++; 594 break; 595 case SND_DEV_DSPHW_REC: 596 d->reccount++; 597 break; 598 case SND_DEV_DSPHW_VREC: 599 d->rvchancount++; 600 break; 601 default: 602 break; 603 } 604 605 return (0); 606 } 607 608 int 609 pcm_chn_remove(struct snddev_info *d, struct pcm_channel *ch) 610 { 611 struct pcm_channel *tmp; 612 613 PCM_BUSYASSERT(d); 614 PCM_LOCKASSERT(d); 615 616 tmp = NULL; 617 618 CHN_FOREACH(tmp, d, channels.pcm) { 619 if (tmp == ch) 620 break; 621 } 622 623 if (tmp != ch) 624 return (EINVAL); 625 626 CHN_REMOVE(d, ch, channels.pcm); 627 628 switch (CHN_DEV(ch)) { 629 case SND_DEV_DSPHW_PLAY: 630 d->playcount--; 631 break; 632 case SND_DEV_DSPHW_VPLAY: 633 d->pvchancount--; 634 break; 635 case SND_DEV_DSPHW_REC: 636 d->reccount--; 637 break; 638 case SND_DEV_DSPHW_VREC: 639 d->rvchancount--; 640 break; 641 default: 642 break; 643 } 644 645 return (0); 646 } 647 648 int 649 pcm_addchan(device_t dev, int dir, kobj_class_t cls, void *devinfo) 650 { 651 struct snddev_info *d = device_get_softc(dev); 652 struct pcm_channel *ch; 653 int err; 654 655 PCM_BUSYASSERT(d); 656 657 PCM_LOCK(d); 658 ch = pcm_chn_create(d, NULL, cls, dir, -1, devinfo); 659 if (!ch) { 660 device_printf(d->dev, "pcm_chn_create(%s, %d, %p) failed\n", 661 cls->name, dir, devinfo); 662 PCM_UNLOCK(d); 663 return (ENODEV); 664 } 665 666 err = pcm_chn_add(d, ch); 667 PCM_UNLOCK(d); 668 if (err) { 669 device_printf(d->dev, "pcm_chn_add(%s) failed, err=%d\n", 670 ch->name, err); 671 pcm_chn_destroy(ch); 672 } 673 674 return (err); 675 } 676 677 static int 678 pcm_killchan(device_t dev) 679 { 680 struct snddev_info *d = device_get_softc(dev); 681 struct pcm_channel *ch; 682 int error; 683 684 PCM_BUSYASSERT(d); 685 686 ch = CHN_FIRST(d, channels.pcm); 687 688 PCM_LOCK(d); 689 error = pcm_chn_remove(d, ch); 690 PCM_UNLOCK(d); 691 if (error) 692 return (error); 693 return (pcm_chn_destroy(ch)); 694 } 695 696 static int 697 pcm_best_unit(int old) 698 { 699 struct snddev_info *d; 700 int i, best, bestprio, prio; 701 702 best = -1; 703 bestprio = -100; 704 for (i = 0; pcm_devclass != NULL && 705 i < devclass_get_maxunit(pcm_devclass); i++) { 706 d = devclass_get_softc(pcm_devclass, i); 707 if (!PCM_REGISTERED(d)) 708 continue; 709 prio = 0; 710 if (d->playcount == 0) 711 prio -= 10; 712 if (d->reccount == 0) 713 prio -= 2; 714 if (prio > bestprio || (prio == bestprio && i == old)) { 715 best = i; 716 bestprio = prio; 717 } 718 } 719 return (best); 720 } 721 722 int 723 pcm_setstatus(device_t dev, char *str) 724 { 725 struct snddev_info *d = device_get_softc(dev); 726 727 /* should only be called once */ 728 if (d->flags & SD_F_REGISTERED) 729 return (EINVAL); 730 731 PCM_BUSYASSERT(d); 732 733 if (d->playcount == 0 || d->reccount == 0) 734 d->flags |= SD_F_SIMPLEX; 735 736 if (d->playcount > 0 || d->reccount > 0) 737 d->flags |= SD_F_AUTOVCHAN; 738 739 pcm_setmaxautovchans(d, snd_maxautovchans); 740 741 strlcpy(d->status, str, SND_STATUSLEN); 742 743 PCM_LOCK(d); 744 745 /* Done, we're ready.. */ 746 d->flags |= SD_F_REGISTERED; 747 748 PCM_RELEASE(d); 749 750 PCM_UNLOCK(d); 751 752 /* 753 * Create all sysctls once SD_F_REGISTERED is set else 754 * tunable sysctls won't work: 755 */ 756 pcm_sysinit(dev); 757 758 if (snd_unit_auto < 0) 759 snd_unit_auto = (snd_unit < 0) ? 1 : 0; 760 if (snd_unit < 0 || snd_unit_auto > 1) 761 snd_unit = device_get_unit(dev); 762 else if (snd_unit_auto == 1) 763 snd_unit = pcm_best_unit(snd_unit); 764 765 return (0); 766 } 767 768 uint32_t 769 pcm_getflags(device_t dev) 770 { 771 struct snddev_info *d = device_get_softc(dev); 772 773 return d->flags; 774 } 775 776 void 777 pcm_setflags(device_t dev, uint32_t val) 778 { 779 struct snddev_info *d = device_get_softc(dev); 780 781 d->flags = val; 782 } 783 784 void * 785 pcm_getdevinfo(device_t dev) 786 { 787 struct snddev_info *d = device_get_softc(dev); 788 789 return d->devinfo; 790 } 791 792 unsigned int 793 pcm_getbuffersize(device_t dev, unsigned int minbufsz, unsigned int deflt, unsigned int maxbufsz) 794 { 795 struct snddev_info *d = device_get_softc(dev); 796 int sz, x; 797 798 sz = 0; 799 if (resource_int_value(device_get_name(dev), device_get_unit(dev), "buffersize", &sz) == 0) { 800 x = sz; 801 RANGE(sz, minbufsz, maxbufsz); 802 if (x != sz) 803 device_printf(dev, "'buffersize=%d' hint is out of range (%d-%d), using %d\n", x, minbufsz, maxbufsz, sz); 804 x = minbufsz; 805 while (x < sz) 806 x <<= 1; 807 if (x > sz) 808 x >>= 1; 809 if (x != sz) { 810 device_printf(dev, "'buffersize=%d' hint is not a power of 2, using %d\n", sz, x); 811 sz = x; 812 } 813 } else { 814 sz = deflt; 815 } 816 817 d->bufsz = sz; 818 819 return sz; 820 } 821 822 static int 823 sysctl_dev_pcm_bitperfect(SYSCTL_HANDLER_ARGS) 824 { 825 struct snddev_info *d; 826 int err, val; 827 828 d = oidp->oid_arg1; 829 if (!PCM_REGISTERED(d)) 830 return (ENODEV); 831 832 PCM_LOCK(d); 833 PCM_WAIT(d); 834 val = (d->flags & SD_F_BITPERFECT) ? 1 : 0; 835 PCM_ACQUIRE(d); 836 PCM_UNLOCK(d); 837 838 err = sysctl_handle_int(oidp, &val, 0, req); 839 840 if (err == 0 && req->newptr != NULL) { 841 if (!(val == 0 || val == 1)) { 842 PCM_RELEASE_QUICK(d); 843 return (EINVAL); 844 } 845 846 PCM_LOCK(d); 847 848 d->flags &= ~SD_F_BITPERFECT; 849 d->flags |= (val != 0) ? SD_F_BITPERFECT : 0; 850 851 PCM_RELEASE(d); 852 PCM_UNLOCK(d); 853 } else 854 PCM_RELEASE_QUICK(d); 855 856 return (err); 857 } 858 859 static u_int8_t 860 pcm_mode_init(struct snddev_info *d) 861 { 862 u_int8_t mode = 0; 863 864 if (d->playcount > 0) 865 mode |= PCM_MODE_PLAY; 866 if (d->reccount > 0) 867 mode |= PCM_MODE_REC; 868 if (d->mixer_dev != NULL) 869 mode |= PCM_MODE_MIXER; 870 871 return (mode); 872 } 873 874 static void 875 pcm_sysinit(device_t dev) 876 { 877 struct snddev_info *d = device_get_softc(dev); 878 u_int8_t mode; 879 880 mode = pcm_mode_init(d); 881 882 /* XXX: a user should be able to set this with a control tool, the 883 sysadmin then needs min+max sysctls for this */ 884 SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev), 885 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 886 OID_AUTO, "buffersize", CTLFLAG_RD, &d->bufsz, 0, "allocated buffer size"); 887 SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 888 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, 889 "bitperfect", CTLTYPE_INT | CTLFLAG_RWTUN | CTLFLAG_MPSAFE, d, 890 sizeof(d), sysctl_dev_pcm_bitperfect, "I", 891 "bit-perfect playback/recording (0=disable, 1=enable)"); 892 SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev), 893 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 894 OID_AUTO, "mode", CTLFLAG_RD, NULL, mode, 895 "mode (1=mixer, 2=play, 4=rec. The values are OR'ed if more than one" 896 "mode is supported)"); 897 if (d->flags & SD_F_AUTOVCHAN) 898 vchan_initsys(dev); 899 if (d->flags & SD_F_EQ) 900 feeder_eq_initsys(dev); 901 } 902 903 int 904 pcm_register(device_t dev, void *devinfo, int numplay, int numrec) 905 { 906 struct snddev_info *d; 907 int i; 908 909 if (pcm_veto_load) { 910 device_printf(dev, "disabled due to an error while initialising: %d\n", pcm_veto_load); 911 912 return EINVAL; 913 } 914 915 if (device_get_unit(dev) > PCMMAXUNIT) { 916 device_printf(dev, "PCMMAXUNIT reached : unit=%d > %d\n", 917 device_get_unit(dev), PCMMAXUNIT); 918 device_printf(dev, 919 "Use 'hw.snd.maxunit' tunable to raise the limit.\n"); 920 return ENODEV; 921 } 922 923 d = device_get_softc(dev); 924 d->dev = dev; 925 d->lock = snd_mtxcreate(device_get_nameunit(dev), "sound cdev"); 926 cv_init(&d->cv, device_get_nameunit(dev)); 927 PCM_ACQUIRE_QUICK(d); 928 #if 0 929 /* 930 * d->flags should be cleared by the allocator of the softc. 931 * We cannot clear this field here because several devices set 932 * this flag before calling pcm_register(). 933 */ 934 d->flags = 0; 935 #endif 936 i = 0; 937 if (resource_int_value(device_get_name(dev), device_get_unit(dev), 938 "vpc", &i) != 0 || i != 0) 939 d->flags |= SD_F_VPC; 940 941 if (resource_int_value(device_get_name(dev), device_get_unit(dev), 942 "bitperfect", &i) == 0 && i != 0) 943 d->flags |= SD_F_BITPERFECT; 944 945 d->devinfo = devinfo; 946 d->reccount = 0; 947 d->playcount = 0; 948 d->pvchancount = 0; 949 d->rvchancount = 0; 950 d->pvchanrate = 0; 951 d->pvchanformat = 0; 952 d->rvchanrate = 0; 953 d->rvchanformat = 0; 954 955 CHN_INIT(d, channels.pcm); 956 CHN_INIT(d, channels.pcm.busy); 957 CHN_INIT(d, channels.pcm.opened); 958 959 /* XXX This is incorrect, but lets play along for now. */ 960 if ((numplay == 0 || numrec == 0) && numplay != numrec) 961 d->flags |= SD_F_SIMPLEX; 962 963 sysctl_ctx_init(&d->play_sysctl_ctx); 964 d->play_sysctl_tree = SYSCTL_ADD_NODE(&d->play_sysctl_ctx, 965 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, "play", 966 CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "playback channels node"); 967 sysctl_ctx_init(&d->rec_sysctl_ctx); 968 d->rec_sysctl_tree = SYSCTL_ADD_NODE(&d->rec_sysctl_ctx, 969 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, "rec", 970 CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "recording channels node"); 971 972 if (numplay > 0 || numrec > 0) 973 d->flags |= SD_F_AUTOVCHAN; 974 975 sndstat_register(dev, d->status); 976 977 return (dsp_make_dev(dev)); 978 } 979 980 int 981 pcm_unregister(device_t dev) 982 { 983 struct snddev_info *d; 984 struct pcm_channel *ch; 985 986 d = device_get_softc(dev); 987 988 if (!PCM_ALIVE(d)) { 989 device_printf(dev, "unregister: device not configured\n"); 990 return (0); 991 } 992 993 PCM_LOCK(d); 994 PCM_WAIT(d); 995 996 d->flags |= SD_F_DETACHING; 997 998 PCM_ACQUIRE(d); 999 PCM_UNLOCK(d); 1000 1001 CHN_FOREACH(ch, d, channels.pcm) { 1002 CHN_LOCK(ch); 1003 if (ch->flags & CHN_F_SLEEPING) { 1004 /* 1005 * We are detaching, so do not wait for the timeout in 1006 * chn_read()/chn_write(). Wake up the thread and kill 1007 * the channel immediately. 1008 */ 1009 CHN_BROADCAST(&ch->intr_cv); 1010 ch->flags |= CHN_F_DEAD; 1011 } 1012 chn_abort(ch); 1013 CHN_UNLOCK(ch); 1014 } 1015 1016 dsp_destroy_dev(dev); 1017 1018 (void)mixer_uninit(dev); 1019 1020 /* remove /dev/sndstat entry first */ 1021 sndstat_unregister(dev); 1022 1023 PCM_LOCK(d); 1024 d->flags |= SD_F_DYING; 1025 d->flags &= ~SD_F_REGISTERED; 1026 PCM_UNLOCK(d); 1027 1028 if (d->play_sysctl_tree != NULL) { 1029 sysctl_ctx_free(&d->play_sysctl_ctx); 1030 d->play_sysctl_tree = NULL; 1031 } 1032 if (d->rec_sysctl_tree != NULL) { 1033 sysctl_ctx_free(&d->rec_sysctl_ctx); 1034 d->rec_sysctl_tree = NULL; 1035 } 1036 1037 while (!CHN_EMPTY(d, channels.pcm)) 1038 pcm_killchan(dev); 1039 1040 PCM_LOCK(d); 1041 PCM_RELEASE(d); 1042 cv_destroy(&d->cv); 1043 PCM_UNLOCK(d); 1044 snd_mtxfree(d->lock); 1045 1046 if (snd_unit == device_get_unit(dev)) { 1047 snd_unit = pcm_best_unit(-1); 1048 if (snd_unit_auto == 0) 1049 snd_unit_auto = 1; 1050 } 1051 1052 return (0); 1053 } 1054 1055 /************************************************************************/ 1056 1057 /** 1058 * @brief Handle OSSv4 SNDCTL_SYSINFO ioctl. 1059 * 1060 * @param si Pointer to oss_sysinfo struct where information about the 1061 * sound subsystem will be written/copied. 1062 * 1063 * This routine returns information about the sound system, such as the 1064 * current OSS version, number of audio, MIDI, and mixer drivers, etc. 1065 * Also includes a bitmask showing which of the above types of devices 1066 * are open (busy). 1067 * 1068 * @note 1069 * Calling threads must not hold any snddev_info or pcm_channel locks. 1070 * 1071 * @author Ryan Beasley <ryanb@FreeBSD.org> 1072 */ 1073 void 1074 sound_oss_sysinfo(oss_sysinfo *si) 1075 { 1076 static char si_product[] = "FreeBSD native OSS ABI"; 1077 static char si_version[] = __XSTRING(__FreeBSD_version); 1078 static char si_license[] = "BSD"; 1079 static int intnbits = sizeof(int) * 8; /* Better suited as macro? 1080 Must pester a C guru. */ 1081 1082 struct snddev_info *d; 1083 struct pcm_channel *c; 1084 int i, j, ncards; 1085 1086 ncards = 0; 1087 1088 strlcpy(si->product, si_product, sizeof(si->product)); 1089 strlcpy(si->version, si_version, sizeof(si->version)); 1090 si->versionnum = SOUND_VERSION; 1091 strlcpy(si->license, si_license, sizeof(si->license)); 1092 1093 /* 1094 * Iterate over PCM devices and their channels, gathering up data 1095 * for the numaudios, ncards, and openedaudio fields. 1096 */ 1097 si->numaudios = 0; 1098 bzero((void *)&si->openedaudio, sizeof(si->openedaudio)); 1099 1100 j = 0; 1101 1102 for (i = 0; pcm_devclass != NULL && 1103 i < devclass_get_maxunit(pcm_devclass); i++) { 1104 d = devclass_get_softc(pcm_devclass, i); 1105 if (!PCM_REGISTERED(d)) 1106 continue; 1107 1108 /* XXX Need Giant magic entry ??? */ 1109 1110 /* See note in function's docblock */ 1111 PCM_UNLOCKASSERT(d); 1112 PCM_LOCK(d); 1113 1114 si->numaudios += PCM_CHANCOUNT(d); 1115 ++ncards; 1116 1117 CHN_FOREACH(c, d, channels.pcm) { 1118 CHN_UNLOCKASSERT(c); 1119 CHN_LOCK(c); 1120 if (c->flags & CHN_F_BUSY) 1121 si->openedaudio[j / intnbits] |= 1122 (1 << (j % intnbits)); 1123 CHN_UNLOCK(c); 1124 j++; 1125 } 1126 1127 PCM_UNLOCK(d); 1128 } 1129 si->numaudioengines = si->numaudios; 1130 1131 si->numsynths = 0; /* OSSv4 docs: this field is obsolete */ 1132 /** 1133 * @todo Collect num{midis,timers}. 1134 * 1135 * Need access to sound/midi/midi.c::midistat_lock in order 1136 * to safely touch midi_devices and get a head count of, well, 1137 * MIDI devices. midistat_lock is a global static (i.e., local to 1138 * midi.c), but midi_devices is a regular global; should the mutex 1139 * be publicized, or is there another way to get this information? 1140 * 1141 * NB: MIDI/sequencer stuff is currently on hold. 1142 */ 1143 si->nummidis = 0; 1144 si->numtimers = 0; 1145 si->nummixers = mixer_count; 1146 si->numcards = ncards; 1147 /* OSSv4 docs: Intended only for test apps; API doesn't 1148 really have much of a concept of cards. Shouldn't be 1149 used by applications. */ 1150 1151 /** 1152 * @todo Fill in "busy devices" fields. 1153 * 1154 * si->openedmidi = " MIDI devices 1155 */ 1156 bzero((void *)&si->openedmidi, sizeof(si->openedmidi)); 1157 1158 /* 1159 * Si->filler is a reserved array, but according to docs each 1160 * element should be set to -1. 1161 */ 1162 for (i = 0; i < sizeof(si->filler)/sizeof(si->filler[0]); i++) 1163 si->filler[i] = -1; 1164 } 1165 1166 int 1167 sound_oss_card_info(oss_card_info *si) 1168 { 1169 struct snddev_info *d; 1170 int i, ncards; 1171 1172 ncards = 0; 1173 1174 for (i = 0; pcm_devclass != NULL && 1175 i < devclass_get_maxunit(pcm_devclass); i++) { 1176 d = devclass_get_softc(pcm_devclass, i); 1177 if (!PCM_REGISTERED(d)) 1178 continue; 1179 1180 if (ncards++ != si->card) 1181 continue; 1182 1183 PCM_UNLOCKASSERT(d); 1184 PCM_LOCK(d); 1185 1186 strlcpy(si->shortname, device_get_nameunit(d->dev), 1187 sizeof(si->shortname)); 1188 strlcpy(si->longname, device_get_desc(d->dev), 1189 sizeof(si->longname)); 1190 strlcpy(si->hw_info, d->status, sizeof(si->hw_info)); 1191 si->intr_count = si->ack_count = 0; 1192 1193 PCM_UNLOCK(d); 1194 1195 return (0); 1196 } 1197 return (ENXIO); 1198 } 1199 1200 /************************************************************************/ 1201 1202 static int 1203 sound_modevent(module_t mod, int type, void *data) 1204 { 1205 int ret; 1206 1207 ret = 0; 1208 switch (type) { 1209 case MOD_LOAD: 1210 pcm_devclass = devclass_create("pcm"); 1211 pcmsg_unrhdr = new_unrhdr(1, INT_MAX, NULL); 1212 break; 1213 case MOD_UNLOAD: 1214 if (pcmsg_unrhdr != NULL) { 1215 delete_unrhdr(pcmsg_unrhdr); 1216 pcmsg_unrhdr = NULL; 1217 } 1218 break; 1219 case MOD_SHUTDOWN: 1220 break; 1221 default: 1222 ret = ENOTSUP; 1223 } 1224 1225 return ret; 1226 } 1227 1228 DEV_MODULE(sound, sound_modevent, NULL); 1229 MODULE_VERSION(sound, SOUND_MODVER); 1230