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"; 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"; 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 d->devcount++; 606 607 return (0); 608 } 609 610 int 611 pcm_chn_remove(struct snddev_info *d, struct pcm_channel *ch) 612 { 613 struct pcm_channel *tmp; 614 615 PCM_BUSYASSERT(d); 616 PCM_LOCKASSERT(d); 617 618 tmp = NULL; 619 620 CHN_FOREACH(tmp, d, channels.pcm) { 621 if (tmp == ch) 622 break; 623 } 624 625 if (tmp != ch) 626 return (EINVAL); 627 628 CHN_REMOVE(d, ch, channels.pcm); 629 630 switch (CHN_DEV(ch)) { 631 case SND_DEV_DSPHW_PLAY: 632 d->playcount--; 633 break; 634 case SND_DEV_DSPHW_VPLAY: 635 d->pvchancount--; 636 break; 637 case SND_DEV_DSPHW_REC: 638 d->reccount--; 639 break; 640 case SND_DEV_DSPHW_VREC: 641 d->rvchancount--; 642 break; 643 default: 644 break; 645 } 646 647 d->devcount--; 648 649 return (0); 650 } 651 652 int 653 pcm_addchan(device_t dev, int dir, kobj_class_t cls, void *devinfo) 654 { 655 struct snddev_info *d = device_get_softc(dev); 656 struct pcm_channel *ch; 657 int err; 658 659 PCM_BUSYASSERT(d); 660 661 PCM_LOCK(d); 662 ch = pcm_chn_create(d, NULL, cls, dir, -1, devinfo); 663 if (!ch) { 664 device_printf(d->dev, "pcm_chn_create(%s, %d, %p) failed\n", 665 cls->name, dir, devinfo); 666 PCM_UNLOCK(d); 667 return (ENODEV); 668 } 669 670 err = pcm_chn_add(d, ch); 671 PCM_UNLOCK(d); 672 if (err) { 673 device_printf(d->dev, "pcm_chn_add(%s) failed, err=%d\n", 674 ch->name, err); 675 pcm_chn_destroy(ch); 676 } 677 678 return (err); 679 } 680 681 static int 682 pcm_killchan(device_t dev) 683 { 684 struct snddev_info *d = device_get_softc(dev); 685 struct pcm_channel *ch; 686 int error; 687 688 PCM_BUSYASSERT(d); 689 690 ch = CHN_FIRST(d, channels.pcm); 691 692 PCM_LOCK(d); 693 error = pcm_chn_remove(d, ch); 694 PCM_UNLOCK(d); 695 if (error) 696 return (error); 697 return (pcm_chn_destroy(ch)); 698 } 699 700 static int 701 pcm_best_unit(int old) 702 { 703 struct snddev_info *d; 704 int i, best, bestprio, prio; 705 706 best = -1; 707 bestprio = -100; 708 for (i = 0; pcm_devclass != NULL && 709 i < devclass_get_maxunit(pcm_devclass); i++) { 710 d = devclass_get_softc(pcm_devclass, i); 711 if (!PCM_REGISTERED(d)) 712 continue; 713 prio = 0; 714 if (d->playcount == 0) 715 prio -= 10; 716 if (d->reccount == 0) 717 prio -= 2; 718 if (prio > bestprio || (prio == bestprio && i == old)) { 719 best = i; 720 bestprio = prio; 721 } 722 } 723 return (best); 724 } 725 726 int 727 pcm_setstatus(device_t dev, char *str) 728 { 729 struct snddev_info *d = device_get_softc(dev); 730 731 /* should only be called once */ 732 if (d->flags & SD_F_REGISTERED) 733 return (EINVAL); 734 735 PCM_BUSYASSERT(d); 736 737 if (d->playcount == 0 || d->reccount == 0) 738 d->flags |= SD_F_SIMPLEX; 739 740 if (d->playcount > 0 || d->reccount > 0) 741 d->flags |= SD_F_AUTOVCHAN; 742 743 pcm_setmaxautovchans(d, snd_maxautovchans); 744 745 strlcpy(d->status, str, SND_STATUSLEN); 746 747 PCM_LOCK(d); 748 749 /* Done, we're ready.. */ 750 d->flags |= SD_F_REGISTERED; 751 752 PCM_RELEASE(d); 753 754 PCM_UNLOCK(d); 755 756 /* 757 * Create all sysctls once SD_F_REGISTERED is set else 758 * tunable sysctls won't work: 759 */ 760 pcm_sysinit(dev); 761 762 if (snd_unit_auto < 0) 763 snd_unit_auto = (snd_unit < 0) ? 1 : 0; 764 if (snd_unit < 0 || snd_unit_auto > 1) 765 snd_unit = device_get_unit(dev); 766 else if (snd_unit_auto == 1) 767 snd_unit = pcm_best_unit(snd_unit); 768 769 return (0); 770 } 771 772 uint32_t 773 pcm_getflags(device_t dev) 774 { 775 struct snddev_info *d = device_get_softc(dev); 776 777 return d->flags; 778 } 779 780 void 781 pcm_setflags(device_t dev, uint32_t val) 782 { 783 struct snddev_info *d = device_get_softc(dev); 784 785 d->flags = val; 786 } 787 788 void * 789 pcm_getdevinfo(device_t dev) 790 { 791 struct snddev_info *d = device_get_softc(dev); 792 793 return d->devinfo; 794 } 795 796 unsigned int 797 pcm_getbuffersize(device_t dev, unsigned int minbufsz, unsigned int deflt, unsigned int maxbufsz) 798 { 799 struct snddev_info *d = device_get_softc(dev); 800 int sz, x; 801 802 sz = 0; 803 if (resource_int_value(device_get_name(dev), device_get_unit(dev), "buffersize", &sz) == 0) { 804 x = sz; 805 RANGE(sz, minbufsz, maxbufsz); 806 if (x != sz) 807 device_printf(dev, "'buffersize=%d' hint is out of range (%d-%d), using %d\n", x, minbufsz, maxbufsz, sz); 808 x = minbufsz; 809 while (x < sz) 810 x <<= 1; 811 if (x > sz) 812 x >>= 1; 813 if (x != sz) { 814 device_printf(dev, "'buffersize=%d' hint is not a power of 2, using %d\n", sz, x); 815 sz = x; 816 } 817 } else { 818 sz = deflt; 819 } 820 821 d->bufsz = sz; 822 823 return sz; 824 } 825 826 static int 827 sysctl_dev_pcm_bitperfect(SYSCTL_HANDLER_ARGS) 828 { 829 struct snddev_info *d; 830 int err, val; 831 832 d = oidp->oid_arg1; 833 if (!PCM_REGISTERED(d)) 834 return (ENODEV); 835 836 PCM_LOCK(d); 837 PCM_WAIT(d); 838 val = (d->flags & SD_F_BITPERFECT) ? 1 : 0; 839 PCM_ACQUIRE(d); 840 PCM_UNLOCK(d); 841 842 err = sysctl_handle_int(oidp, &val, 0, req); 843 844 if (err == 0 && req->newptr != NULL) { 845 if (!(val == 0 || val == 1)) { 846 PCM_RELEASE_QUICK(d); 847 return (EINVAL); 848 } 849 850 PCM_LOCK(d); 851 852 d->flags &= ~SD_F_BITPERFECT; 853 d->flags |= (val != 0) ? SD_F_BITPERFECT : 0; 854 855 PCM_RELEASE(d); 856 PCM_UNLOCK(d); 857 } else 858 PCM_RELEASE_QUICK(d); 859 860 return (err); 861 } 862 863 static u_int8_t 864 pcm_mode_init(struct snddev_info *d) 865 { 866 u_int8_t mode = 0; 867 868 if (d->playcount > 0) 869 mode |= PCM_MODE_PLAY; 870 if (d->reccount > 0) 871 mode |= PCM_MODE_REC; 872 if (d->mixer_dev != NULL) 873 mode |= PCM_MODE_MIXER; 874 875 return (mode); 876 } 877 878 static void 879 pcm_sysinit(device_t dev) 880 { 881 struct snddev_info *d = device_get_softc(dev); 882 u_int8_t mode; 883 884 mode = pcm_mode_init(d); 885 886 /* XXX: a user should be able to set this with a control tool, the 887 sysadmin then needs min+max sysctls for this */ 888 SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev), 889 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 890 OID_AUTO, "buffersize", CTLFLAG_RD, &d->bufsz, 0, "allocated buffer size"); 891 SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 892 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, 893 "bitperfect", CTLTYPE_INT | CTLFLAG_RWTUN | CTLFLAG_MPSAFE, d, 894 sizeof(d), sysctl_dev_pcm_bitperfect, "I", 895 "bit-perfect playback/recording (0=disable, 1=enable)"); 896 SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev), 897 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 898 OID_AUTO, "mode", CTLFLAG_RD, NULL, mode, 899 "mode (1=mixer, 2=play, 4=rec. The values are OR'ed if more than one" 900 "mode is supported)"); 901 if (d->flags & SD_F_AUTOVCHAN) 902 vchan_initsys(dev); 903 if (d->flags & SD_F_EQ) 904 feeder_eq_initsys(dev); 905 } 906 907 int 908 pcm_register(device_t dev, void *devinfo, int numplay, int numrec) 909 { 910 struct snddev_info *d; 911 int i; 912 913 if (pcm_veto_load) { 914 device_printf(dev, "disabled due to an error while initialising: %d\n", pcm_veto_load); 915 916 return EINVAL; 917 } 918 919 if (device_get_unit(dev) > PCMMAXUNIT) { 920 device_printf(dev, "PCMMAXUNIT reached : unit=%d > %d\n", 921 device_get_unit(dev), PCMMAXUNIT); 922 device_printf(dev, 923 "Use 'hw.snd.maxunit' tunable to raise the limit.\n"); 924 return ENODEV; 925 } 926 927 d = device_get_softc(dev); 928 d->dev = dev; 929 d->lock = snd_mtxcreate(device_get_nameunit(dev), "sound cdev"); 930 cv_init(&d->cv, device_get_nameunit(dev)); 931 PCM_ACQUIRE_QUICK(d); 932 #if 0 933 /* 934 * d->flags should be cleared by the allocator of the softc. 935 * We cannot clear this field here because several devices set 936 * this flag before calling pcm_register(). 937 */ 938 d->flags = 0; 939 #endif 940 i = 0; 941 if (resource_int_value(device_get_name(dev), device_get_unit(dev), 942 "vpc", &i) != 0 || i != 0) 943 d->flags |= SD_F_VPC; 944 945 if (resource_int_value(device_get_name(dev), device_get_unit(dev), 946 "bitperfect", &i) == 0 && i != 0) 947 d->flags |= SD_F_BITPERFECT; 948 949 d->devinfo = devinfo; 950 d->devcount = 0; 951 d->reccount = 0; 952 d->playcount = 0; 953 d->pvchancount = 0; 954 d->rvchancount = 0; 955 d->pvchanrate = 0; 956 d->pvchanformat = 0; 957 d->rvchanrate = 0; 958 d->rvchanformat = 0; 959 960 CHN_INIT(d, channels.pcm); 961 CHN_INIT(d, channels.pcm.busy); 962 CHN_INIT(d, channels.pcm.opened); 963 964 /* XXX This is incorrect, but lets play along for now. */ 965 if ((numplay == 0 || numrec == 0) && numplay != numrec) 966 d->flags |= SD_F_SIMPLEX; 967 968 sysctl_ctx_init(&d->play_sysctl_ctx); 969 d->play_sysctl_tree = SYSCTL_ADD_NODE(&d->play_sysctl_ctx, 970 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, "play", 971 CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "playback channels node"); 972 sysctl_ctx_init(&d->rec_sysctl_ctx); 973 d->rec_sysctl_tree = SYSCTL_ADD_NODE(&d->rec_sysctl_ctx, 974 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, "rec", 975 CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "recording channels node"); 976 977 if (numplay > 0 || numrec > 0) 978 d->flags |= SD_F_AUTOVCHAN; 979 980 sndstat_register(dev, d->status); 981 982 return (dsp_make_dev(dev)); 983 } 984 985 int 986 pcm_unregister(device_t dev) 987 { 988 struct snddev_info *d; 989 struct pcm_channel *ch; 990 991 d = device_get_softc(dev); 992 993 if (!PCM_ALIVE(d)) { 994 device_printf(dev, "unregister: device not configured\n"); 995 return (0); 996 } 997 998 PCM_LOCK(d); 999 PCM_WAIT(d); 1000 1001 d->flags |= SD_F_DETACHING; 1002 1003 PCM_ACQUIRE(d); 1004 PCM_UNLOCK(d); 1005 1006 CHN_FOREACH(ch, d, channels.pcm) { 1007 CHN_LOCK(ch); 1008 if (ch->flags & CHN_F_SLEEPING) { 1009 /* 1010 * We are detaching, so do not wait for the timeout in 1011 * chn_read()/chn_write(). Wake up the thread and kill 1012 * the channel immediately. 1013 */ 1014 CHN_BROADCAST(&ch->intr_cv); 1015 ch->flags |= CHN_F_DEAD; 1016 } 1017 chn_abort(ch); 1018 CHN_UNLOCK(ch); 1019 } 1020 1021 dsp_destroy_dev(dev); 1022 1023 (void)mixer_uninit(dev); 1024 1025 /* remove /dev/sndstat entry first */ 1026 sndstat_unregister(dev); 1027 1028 PCM_LOCK(d); 1029 d->flags |= SD_F_DYING; 1030 d->flags &= ~SD_F_REGISTERED; 1031 PCM_UNLOCK(d); 1032 1033 if (d->play_sysctl_tree != NULL) { 1034 sysctl_ctx_free(&d->play_sysctl_ctx); 1035 d->play_sysctl_tree = NULL; 1036 } 1037 if (d->rec_sysctl_tree != NULL) { 1038 sysctl_ctx_free(&d->rec_sysctl_ctx); 1039 d->rec_sysctl_tree = NULL; 1040 } 1041 1042 while (!CHN_EMPTY(d, channels.pcm)) 1043 pcm_killchan(dev); 1044 1045 PCM_LOCK(d); 1046 PCM_RELEASE(d); 1047 cv_destroy(&d->cv); 1048 PCM_UNLOCK(d); 1049 snd_mtxfree(d->lock); 1050 1051 if (snd_unit == device_get_unit(dev)) { 1052 snd_unit = pcm_best_unit(-1); 1053 if (snd_unit_auto == 0) 1054 snd_unit_auto = 1; 1055 } 1056 1057 return (0); 1058 } 1059 1060 /************************************************************************/ 1061 1062 /** 1063 * @brief Handle OSSv4 SNDCTL_SYSINFO ioctl. 1064 * 1065 * @param si Pointer to oss_sysinfo struct where information about the 1066 * sound subsystem will be written/copied. 1067 * 1068 * This routine returns information about the sound system, such as the 1069 * current OSS version, number of audio, MIDI, and mixer drivers, etc. 1070 * Also includes a bitmask showing which of the above types of devices 1071 * are open (busy). 1072 * 1073 * @note 1074 * Calling threads must not hold any snddev_info or pcm_channel locks. 1075 * 1076 * @author Ryan Beasley <ryanb@FreeBSD.org> 1077 */ 1078 void 1079 sound_oss_sysinfo(oss_sysinfo *si) 1080 { 1081 static char si_product[] = "FreeBSD native OSS ABI"; 1082 static char si_version[] = __XSTRING(__FreeBSD_version); 1083 static char si_license[] = "BSD"; 1084 static int intnbits = sizeof(int) * 8; /* Better suited as macro? 1085 Must pester a C guru. */ 1086 1087 struct snddev_info *d; 1088 struct pcm_channel *c; 1089 int i, j, ncards; 1090 1091 ncards = 0; 1092 1093 strlcpy(si->product, si_product, sizeof(si->product)); 1094 strlcpy(si->version, si_version, sizeof(si->version)); 1095 si->versionnum = SOUND_VERSION; 1096 strlcpy(si->license, si_license, sizeof(si->license)); 1097 1098 /* 1099 * Iterate over PCM devices and their channels, gathering up data 1100 * for the numaudios, ncards, and openedaudio fields. 1101 */ 1102 si->numaudios = 0; 1103 bzero((void *)&si->openedaudio, sizeof(si->openedaudio)); 1104 1105 j = 0; 1106 1107 for (i = 0; pcm_devclass != NULL && 1108 i < devclass_get_maxunit(pcm_devclass); i++) { 1109 d = devclass_get_softc(pcm_devclass, i); 1110 if (!PCM_REGISTERED(d)) 1111 continue; 1112 1113 /* XXX Need Giant magic entry ??? */ 1114 1115 /* See note in function's docblock */ 1116 PCM_UNLOCKASSERT(d); 1117 PCM_LOCK(d); 1118 1119 si->numaudios += d->devcount; 1120 ++ncards; 1121 1122 CHN_FOREACH(c, d, channels.pcm) { 1123 CHN_UNLOCKASSERT(c); 1124 CHN_LOCK(c); 1125 if (c->flags & CHN_F_BUSY) 1126 si->openedaudio[j / intnbits] |= 1127 (1 << (j % intnbits)); 1128 CHN_UNLOCK(c); 1129 j++; 1130 } 1131 1132 PCM_UNLOCK(d); 1133 } 1134 si->numaudioengines = si->numaudios; 1135 1136 si->numsynths = 0; /* OSSv4 docs: this field is obsolete */ 1137 /** 1138 * @todo Collect num{midis,timers}. 1139 * 1140 * Need access to sound/midi/midi.c::midistat_lock in order 1141 * to safely touch midi_devices and get a head count of, well, 1142 * MIDI devices. midistat_lock is a global static (i.e., local to 1143 * midi.c), but midi_devices is a regular global; should the mutex 1144 * be publicized, or is there another way to get this information? 1145 * 1146 * NB: MIDI/sequencer stuff is currently on hold. 1147 */ 1148 si->nummidis = 0; 1149 si->numtimers = 0; 1150 si->nummixers = mixer_count; 1151 si->numcards = ncards; 1152 /* OSSv4 docs: Intended only for test apps; API doesn't 1153 really have much of a concept of cards. Shouldn't be 1154 used by applications. */ 1155 1156 /** 1157 * @todo Fill in "busy devices" fields. 1158 * 1159 * si->openedmidi = " MIDI devices 1160 */ 1161 bzero((void *)&si->openedmidi, sizeof(si->openedmidi)); 1162 1163 /* 1164 * Si->filler is a reserved array, but according to docs each 1165 * element should be set to -1. 1166 */ 1167 for (i = 0; i < sizeof(si->filler)/sizeof(si->filler[0]); i++) 1168 si->filler[i] = -1; 1169 } 1170 1171 int 1172 sound_oss_card_info(oss_card_info *si) 1173 { 1174 struct snddev_info *d; 1175 int i, ncards; 1176 1177 ncards = 0; 1178 1179 for (i = 0; pcm_devclass != NULL && 1180 i < devclass_get_maxunit(pcm_devclass); i++) { 1181 d = devclass_get_softc(pcm_devclass, i); 1182 if (!PCM_REGISTERED(d)) 1183 continue; 1184 1185 if (ncards++ != si->card) 1186 continue; 1187 1188 PCM_UNLOCKASSERT(d); 1189 PCM_LOCK(d); 1190 1191 strlcpy(si->shortname, device_get_nameunit(d->dev), 1192 sizeof(si->shortname)); 1193 strlcpy(si->longname, device_get_desc(d->dev), 1194 sizeof(si->longname)); 1195 strlcpy(si->hw_info, d->status, sizeof(si->hw_info)); 1196 si->intr_count = si->ack_count = 0; 1197 1198 PCM_UNLOCK(d); 1199 1200 return (0); 1201 } 1202 return (ENXIO); 1203 } 1204 1205 /************************************************************************/ 1206 1207 static int 1208 sound_modevent(module_t mod, int type, void *data) 1209 { 1210 int ret; 1211 1212 ret = 0; 1213 switch (type) { 1214 case MOD_LOAD: 1215 pcm_devclass = devclass_create("pcm"); 1216 pcmsg_unrhdr = new_unrhdr(1, INT_MAX, NULL); 1217 break; 1218 case MOD_UNLOAD: 1219 if (pcmsg_unrhdr != NULL) { 1220 delete_unrhdr(pcmsg_unrhdr); 1221 pcmsg_unrhdr = NULL; 1222 } 1223 break; 1224 case MOD_SHUTDOWN: 1225 break; 1226 default: 1227 ret = ENOTSUP; 1228 } 1229 1230 return ret; 1231 } 1232 1233 DEV_MODULE(sound, sound_modevent, NULL); 1234 MODULE_VERSION(sound, SOUND_MODVER); 1235