1 /*- 2 * Copyright (c) 2005-2009 Ariff Abdullah <ariff@FreeBSD.org> 3 * Portions Copyright (c) Ryan Beasley <ryan.beasley@gmail.com> - GSoC 2006 4 * Copyright (c) 1999 Cameron Grant <cg@FreeBSD.org> 5 * Copyright (c) 1997 Luigi Rizzo 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 */ 29 30 #ifdef HAVE_KERNEL_OPTION_HEADERS 31 #include "opt_snd.h" 32 #endif 33 34 #include <dev/sound/pcm/sound.h> 35 #include <dev/sound/pcm/ac97.h> 36 #include <dev/sound/pcm/vchan.h> 37 #include <dev/sound/pcm/dsp.h> 38 #include <dev/sound/pcm/sndstat.h> 39 #include <dev/sound/version.h> 40 #include <sys/devfs.h> 41 #include <sys/limits.h> 42 #include <sys/sysctl.h> 43 44 #include "feeder_if.h" 45 46 SND_DECLARE_FILE("$FreeBSD: head/sys/dev/sound/pcm/sound.c 274035 2014-11-03 11:11:45Z bapt $"); 47 48 devclass_t pcm_devclass; 49 50 int pcm_veto_load = 1; 51 52 int snd_unit = -1; 53 TUNABLE_INT("hw.snd.default_unit", &snd_unit); 54 55 static int snd_unit_auto = -1; 56 TUNABLE_INT("hw.snd.default_auto", &snd_unit_auto); 57 SYSCTL_INT(_hw_snd, OID_AUTO, default_auto, CTLFLAG_RW, 58 &snd_unit_auto, 0, "assign default unit to a newly attached device"); 59 60 int snd_maxautovchans = 16; 61 /* XXX: a tunable implies that we may need more than one sound channel before 62 the system can change a sysctl (/etc/sysctl.conf), do we really need 63 this? */ 64 TUNABLE_INT("hw.snd.maxautovchans", &snd_maxautovchans); 65 66 SYSCTL_NODE(_hw, OID_AUTO, snd, CTLFLAG_RD, 0, "Sound driver"); 67 68 /* 69 * XXX I've had enough with people not telling proper version/arch 70 * while reporting problems, not after 387397913213th questions/requests. 71 */ 72 static char snd_driver_version[] = 73 __XSTRING(SND_DRV_VERSION)"/"MACHINE_ARCH; 74 SYSCTL_STRING(_hw_snd, OID_AUTO, version, CTLFLAG_RD, &snd_driver_version, 75 0, "driver version/arch"); 76 77 /** 78 * @brief Unit number allocator for syncgroup IDs 79 */ 80 struct unrhdr *pcmsg_unrhdr = NULL; 81 82 static int 83 sndstat_prepare_pcm(SNDSTAT_PREPARE_PCM_ARGS) 84 { 85 SNDSTAT_PREPARE_PCM_BEGIN(); 86 SNDSTAT_PREPARE_PCM_END(); 87 } 88 89 void * 90 snd_mtxcreate(const char *desc, const char *type) 91 { 92 struct lock *m; 93 94 m = kmalloc(sizeof(*m), M_DEVBUF, M_WAITOK | M_ZERO); 95 lockinit(m, desc, 0, LK_CANRECURSE); 96 return m; 97 } 98 99 void 100 snd_mtxfree(void *m) 101 { 102 struct lock *mtx = m; 103 104 lockuninit(mtx); 105 kfree(mtx, M_DEVBUF); 106 } 107 108 void 109 snd_mtxassert(void *m) 110 { 111 #ifdef INVARIANTS 112 struct lock *lk = m; 113 114 KKASSERT(lockstatus(lk, curthread) == LK_EXCLUSIVE); 115 #endif 116 } 117 118 int 119 snd_setup_intr(device_t dev, struct resource *res, int flags, driver_intr_t hand, void *param, void **cookiep) 120 { 121 struct snddev_info *d; 122 123 flags &= INTR_MPSAFE; 124 d = device_get_softc(dev); 125 if (d != NULL && (flags & INTR_MPSAFE)) 126 d->flags |= SD_F_MPSAFE; 127 128 return bus_setup_intr(dev, res, flags, hand, param, cookiep, NULL); 129 } 130 131 static void 132 pcm_clonereset(struct snddev_info *d) 133 { 134 int cmax; 135 136 PCM_BUSYASSERT(d); 137 138 cmax = d->playcount + d->reccount - 1; 139 if (d->pvchancount > 0) 140 cmax += max(d->pvchancount, snd_maxautovchans) - 1; 141 if (d->rvchancount > 0) 142 cmax += max(d->rvchancount, snd_maxautovchans) - 1; 143 if (cmax > PCMMAXCLONE) 144 cmax = PCMMAXCLONE; 145 (void)snd_clone_gc(d->clones); 146 (void)snd_clone_setmaxunit(d->clones, cmax); 147 } 148 149 int 150 pcm_setvchans(struct snddev_info *d, int direction, int newcnt, int num) 151 { 152 struct pcm_channel *c, *ch, *nch; 153 struct pcmchan_caps *caps; 154 int i, err, vcnt; 155 156 PCM_BUSYASSERT(d); 157 158 if ((direction == PCMDIR_PLAY && d->playcount < 1) || 159 (direction == PCMDIR_REC && d->reccount < 1)) 160 return (ENODEV); 161 162 if (!(d->flags & SD_F_AUTOVCHAN)) 163 return (EINVAL); 164 165 if (newcnt < 0 || newcnt > SND_MAXVCHANS) 166 return (E2BIG); 167 168 if (direction == PCMDIR_PLAY) 169 vcnt = d->pvchancount; 170 else if (direction == PCMDIR_REC) 171 vcnt = d->rvchancount; 172 else 173 return (EINVAL); 174 175 if (newcnt > vcnt) { 176 KASSERT(num == -1 || 177 (num >= 0 && num < SND_MAXVCHANS && (newcnt - 1) == vcnt), 178 ("bogus vchan_create() request num=%d newcnt=%d vcnt=%d", 179 num, newcnt, vcnt)); 180 /* add new vchans - find a parent channel first */ 181 ch = NULL; 182 CHN_FOREACH(c, d, channels.pcm) { 183 CHN_LOCK(c); 184 if (c->direction == direction && 185 ((c->flags & CHN_F_HAS_VCHAN) || (vcnt == 0 && 186 c->refcount < 1 && 187 !(c->flags & (CHN_F_BUSY | CHN_F_VIRTUAL))))) { 188 /* 189 * Reuse hw channel with vchans already 190 * created. 191 */ 192 if (c->flags & CHN_F_HAS_VCHAN) { 193 ch = c; 194 break; 195 } 196 /* 197 * No vchans ever created, look for 198 * channels with supported formats. 199 */ 200 caps = chn_getcaps(c); 201 if (caps == NULL) { 202 CHN_UNLOCK(c); 203 continue; 204 } 205 for (i = 0; caps->fmtlist[i] != 0; i++) { 206 if (caps->fmtlist[i] & AFMT_CONVERTIBLE) 207 break; 208 } 209 if (caps->fmtlist[i] != 0) { 210 ch = c; 211 break; 212 } 213 } 214 CHN_UNLOCK(c); 215 } 216 if (ch == NULL) 217 return (EBUSY); 218 ch->flags |= CHN_F_BUSY; 219 err = 0; 220 while (err == 0 && newcnt > vcnt) { 221 err = vchan_create(ch, num); 222 if (err == 0) 223 vcnt++; 224 else if (err == E2BIG && newcnt > vcnt) 225 device_printf(d->dev, 226 "%s: err=%d Maximum channel reached.\n", 227 __func__, err); 228 } 229 if (vcnt == 0) 230 ch->flags &= ~CHN_F_BUSY; 231 CHN_UNLOCK(ch); 232 if (err != 0) 233 return (err); 234 else 235 pcm_clonereset(d); 236 } else if (newcnt < vcnt) { 237 KASSERT(num == -1, 238 ("bogus vchan_destroy() request num=%d", num)); 239 CHN_FOREACH(c, d, channels.pcm) { 240 CHN_LOCK(c); 241 if (c->direction != direction || 242 CHN_EMPTY(c, children) || 243 !(c->flags & CHN_F_HAS_VCHAN)) { 244 CHN_UNLOCK(c); 245 continue; 246 } 247 CHN_FOREACH_SAFE(ch, c, nch, children) { 248 CHN_LOCK(ch); 249 if (vcnt == 1 && c->refcount > 0) { 250 CHN_UNLOCK(ch); 251 break; 252 } 253 if (!(ch->flags & CHN_F_BUSY) && 254 ch->refcount < 1) { 255 err = vchan_destroy(ch); 256 if (err == 0) 257 vcnt--; 258 } else 259 CHN_UNLOCK(ch); 260 if (vcnt == newcnt) 261 break; 262 } 263 CHN_UNLOCK(c); 264 break; 265 } 266 pcm_clonereset(d); 267 } 268 269 return (0); 270 } 271 272 /* return error status and a locked channel */ 273 int 274 pcm_chnalloc(struct snddev_info *d, struct pcm_channel **ch, int direction, 275 pid_t pid, char *comm, int devunit) 276 { 277 struct pcm_channel *c; 278 int err, vchancount, vchan_num; 279 280 KASSERT(d != NULL && ch != NULL && (devunit == -1 || 281 !(devunit & ~(SND_U_MASK | SND_D_MASK | SND_C_MASK))) && 282 (direction == PCMDIR_PLAY || direction == PCMDIR_REC), 283 ("%s(): invalid d=%p ch=%p direction=%d pid=%d devunit=%d", 284 __func__, d, ch, direction, pid, devunit)); 285 PCM_BUSYASSERT(d); 286 287 /* Double check again. */ 288 if (devunit != -1) { 289 switch (snd_unit2d(devunit)) { 290 case SND_DEV_DSPHW_PLAY: 291 case SND_DEV_DSPHW_VPLAY: 292 if (direction != PCMDIR_PLAY) 293 return (ENOTSUP); 294 break; 295 case SND_DEV_DSPHW_REC: 296 case SND_DEV_DSPHW_VREC: 297 if (direction != PCMDIR_REC) 298 return (ENOTSUP); 299 break; 300 default: 301 if (!(direction == PCMDIR_PLAY || 302 direction == PCMDIR_REC)) 303 return (ENOTSUP); 304 break; 305 } 306 } 307 308 *ch = NULL; 309 vchan_num = 0; 310 vchancount = (direction == PCMDIR_PLAY) ? d->pvchancount : 311 d->rvchancount; 312 313 retry_chnalloc: 314 err = ENOTSUP; 315 /* scan for a free channel */ 316 CHN_FOREACH(c, d, channels.pcm) { 317 CHN_LOCK(c); 318 if (devunit == -1 && c->direction == direction && 319 (c->flags & CHN_F_VIRTUAL)) { 320 if (vchancount < snd_maxautovchans && 321 vchan_num < CHN_CHAN(c)) { 322 CHN_UNLOCK(c); 323 goto vchan_alloc; 324 } 325 vchan_num++; 326 } 327 if (c->direction == direction && !(c->flags & CHN_F_BUSY) && 328 (devunit == -1 || devunit == -2 || c->unit == devunit)) { 329 c->flags |= CHN_F_BUSY; 330 c->pid = pid; 331 strlcpy(c->comm, (comm != NULL) ? comm : 332 CHN_COMM_UNKNOWN, sizeof(c->comm)); 333 *ch = c; 334 return (0); 335 } else if (c->unit == devunit) { 336 if (c->direction != direction) 337 err = ENOTSUP; 338 else if (c->flags & CHN_F_BUSY) 339 err = EBUSY; 340 else 341 err = EINVAL; 342 CHN_UNLOCK(c); 343 return (err); 344 } else if ((devunit == -1 || devunit == -2) && 345 c->direction == direction && (c->flags & CHN_F_BUSY)) 346 err = EBUSY; 347 CHN_UNLOCK(c); 348 } 349 350 if (devunit == -2) 351 return (err); 352 353 vchan_alloc: 354 /* no channel available */ 355 if (devunit == -1 || snd_unit2d(devunit) == SND_DEV_DSPHW_VPLAY || 356 snd_unit2d(devunit) == SND_DEV_DSPHW_VREC) { 357 if (!(vchancount > 0 && vchancount < snd_maxautovchans) && 358 (devunit == -1 || snd_unit2c(devunit) < snd_maxautovchans)) 359 return (err); 360 err = pcm_setvchans(d, direction, vchancount + 1, 361 (devunit == -1) ? -1 : snd_unit2c(devunit)); 362 if (err == 0) { 363 if (devunit == -1) 364 devunit = -2; 365 goto retry_chnalloc; 366 } 367 } 368 369 return (err); 370 } 371 372 /* release a locked channel and unlock it */ 373 int 374 pcm_chnrelease(struct pcm_channel *c) 375 { 376 PCM_BUSYASSERT(c->parentsnddev); 377 CHN_LOCKASSERT(c); 378 379 c->flags &= ~CHN_F_BUSY; 380 c->pid = -1; 381 strlcpy(c->comm, CHN_COMM_UNUSED, sizeof(c->comm)); 382 CHN_UNLOCK(c); 383 384 return (0); 385 } 386 387 int 388 pcm_chnref(struct pcm_channel *c, int ref) 389 { 390 PCM_BUSYASSERT(c->parentsnddev); 391 CHN_LOCKASSERT(c); 392 393 c->refcount += ref; 394 395 return (c->refcount); 396 } 397 398 int 399 pcm_inprog(struct snddev_info *d, int delta) 400 { 401 PCM_LOCKASSERT(d); 402 403 d->inprog += delta; 404 405 return (d->inprog); 406 } 407 408 static void 409 pcm_setmaxautovchans(struct snddev_info *d, int num) 410 { 411 PCM_BUSYASSERT(d); 412 413 if (num < 0) 414 return; 415 416 if (num >= 0 && d->pvchancount > num) 417 (void)pcm_setvchans(d, PCMDIR_PLAY, num, -1); 418 else if (num > 0 && d->pvchancount == 0) 419 (void)pcm_setvchans(d, PCMDIR_PLAY, 1, -1); 420 421 if (num >= 0 && d->rvchancount > num) 422 (void)pcm_setvchans(d, PCMDIR_REC, num, -1); 423 else if (num > 0 && d->rvchancount == 0) 424 (void)pcm_setvchans(d, PCMDIR_REC, 1, -1); 425 426 pcm_clonereset(d); 427 } 428 429 static void 430 pcm_set_dev_alias(int unit) 431 { 432 struct snddev_info *d; 433 cdev_t old_d; 434 435 if ((old_d = devfs_find_device_by_name("dsp%d", snd_unit))) 436 destroy_dev_alias(old_d, "dsp"); 437 if ((old_d = devfs_find_device_by_name("mixer%d", snd_unit))) 438 destroy_dev_alias(old_d, "mixer"); 439 if (unit >= 0) { 440 d = devclass_get_softc(pcm_devclass, unit); 441 make_dev_alias(d->dsp_clonedev, "dsp"); 442 make_dev_alias(d->mixer_dev, "mixer"); 443 } 444 } 445 446 static int 447 sysctl_hw_snd_default_unit(SYSCTL_HANDLER_ARGS) 448 { 449 struct snddev_info *d; 450 int error, unit; 451 cdev_t old_d; 452 453 unit = snd_unit; 454 error = sysctl_handle_int(oidp, &unit, 0, req); 455 if (error == 0 && req->newptr != NULL) { 456 if ((old_d = devfs_find_device_by_name("dsp%d", snd_unit))) 457 destroy_dev_alias(old_d, "dsp"); 458 if ((old_d = devfs_find_device_by_name("mixer%d", snd_unit))) 459 destroy_dev_alias(old_d, "mixer"); 460 d = devclass_get_softc(pcm_devclass, unit); 461 if (!PCM_REGISTERED(d) || CHN_EMPTY(d, channels.pcm)) 462 return EINVAL; 463 error = make_dev_alias(d->dsp_clonedev, "dsp"); 464 if (error) 465 goto done; 466 error = make_dev_alias(d->mixer_dev, "mixer"); 467 snd_unit = unit; 468 snd_unit_auto = 0; 469 } 470 done: 471 return (error); 472 } 473 474 /* XXX: do we need a way to let the user change the default unit? */ 475 SYSCTL_PROC(_hw_snd, OID_AUTO, default_unit, 476 CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_ANYBODY, 477 0, sizeof(int), sysctl_hw_snd_default_unit, "I", 478 "default sound device"); 479 480 static int 481 sysctl_hw_snd_maxautovchans(SYSCTL_HANDLER_ARGS) 482 { 483 struct snddev_info *d; 484 int i, v, error; 485 486 v = snd_maxautovchans; 487 error = sysctl_handle_int(oidp, &v, 0, req); 488 if (error == 0 && req->newptr != NULL) { 489 if (v < 0) 490 v = 0; 491 if (v > SND_MAXVCHANS) 492 v = SND_MAXVCHANS; 493 snd_maxautovchans = v; 494 for (i = 0; pcm_devclass != NULL && 495 i < devclass_get_maxunit(pcm_devclass); i++) { 496 d = devclass_get_softc(pcm_devclass, i); 497 if (!PCM_REGISTERED(d)) 498 continue; 499 PCM_ACQUIRE_QUICK(d); 500 pcm_setmaxautovchans(d, v); 501 PCM_RELEASE_QUICK(d); 502 } 503 } 504 return (error); 505 } 506 SYSCTL_PROC(_hw_snd, OID_AUTO, maxautovchans, CTLTYPE_INT | CTLFLAG_RW, 507 0, sizeof(int), sysctl_hw_snd_maxautovchans, "I", "maximum virtual channel"); 508 509 struct pcm_channel * 510 pcm_chn_create(struct snddev_info *d, struct pcm_channel *parent, kobj_class_t cls, int dir, int num, void *devinfo) 511 { 512 struct pcm_channel *ch; 513 int direction, err, rpnum, *pnum, max; 514 int udc, device, chan; 515 char *dirs, *devname, buf[CHN_NAMELEN]; 516 517 PCM_BUSYASSERT(d); 518 PCM_LOCKASSERT(d); 519 KASSERT(num >= -1, ("invalid num=%d", num)); 520 521 522 switch (dir) { 523 case PCMDIR_PLAY: 524 dirs = "play"; 525 direction = PCMDIR_PLAY; 526 pnum = &d->playcount; 527 device = SND_DEV_DSPHW_PLAY; 528 max = SND_MAXHWCHAN; 529 break; 530 case PCMDIR_PLAY_VIRTUAL: 531 dirs = "virtual"; 532 direction = PCMDIR_PLAY; 533 pnum = &d->pvchancount; 534 device = SND_DEV_DSPHW_VPLAY; 535 max = SND_MAXVCHANS; 536 break; 537 case PCMDIR_REC: 538 dirs = "record"; 539 direction = PCMDIR_REC; 540 pnum = &d->reccount; 541 device = SND_DEV_DSPHW_REC; 542 max = SND_MAXHWCHAN; 543 break; 544 case PCMDIR_REC_VIRTUAL: 545 dirs = "virtual"; 546 direction = PCMDIR_REC; 547 pnum = &d->rvchancount; 548 device = SND_DEV_DSPHW_VREC; 549 max = SND_MAXVCHANS; 550 break; 551 default: 552 return (NULL); 553 } 554 555 chan = (num == -1) ? 0 : num; 556 557 if (*pnum >= max || chan >= max) 558 return (NULL); 559 560 rpnum = 0; 561 562 CHN_FOREACH(ch, d, channels.pcm) { 563 if (CHN_DEV(ch) != device) 564 continue; 565 if (chan == CHN_CHAN(ch)) { 566 if (num != -1) { 567 device_printf(d->dev, 568 "channel num=%d allocated!\n", chan); 569 return (NULL); 570 } 571 chan++; 572 if (chan >= max) { 573 device_printf(d->dev, 574 "chan=%d > %d\n", chan, max); 575 return (NULL); 576 } 577 } 578 rpnum++; 579 } 580 581 if (*pnum != rpnum) { 582 device_printf(d->dev, 583 "%s(): WARNING: pnum screwed : dirs=%s pnum=%d rpnum=%d\n", 584 __func__, dirs, *pnum, rpnum); 585 return (NULL); 586 } 587 588 udc = snd_mkunit(device_get_unit(d->dev), device, chan); 589 devname = dsp_unit2name(buf, sizeof(buf), udc); 590 591 if (devname == NULL) { 592 device_printf(d->dev, 593 "Failed to query device name udc=0x%08x\n", udc); 594 return (NULL); 595 } 596 597 PCM_UNLOCK(d); 598 ch = kmalloc(sizeof(*ch), M_DEVBUF, M_WAITOK | M_ZERO); 599 ch->methods = kobj_create(cls, M_DEVBUF, M_WAITOK | M_ZERO); 600 ch->unit = udc; 601 ch->pid = -1; 602 strlcpy(ch->comm, CHN_COMM_UNUSED, sizeof(ch->comm)); 603 ch->parentsnddev = d; 604 ch->parentchannel = parent; 605 ch->dev = d->dev; 606 ch->trigger = PCMTRIG_STOP; 607 ksnprintf(ch->name, sizeof(ch->name), "%s:%s:%s", 608 device_get_nameunit(ch->dev), dirs, devname); 609 610 err = chn_init(ch, devinfo, dir, direction); 611 PCM_LOCK(d); 612 if (err) { 613 device_printf(d->dev, "chn_init(%s) failed: err = %d\n", 614 ch->name, err); 615 kobj_delete(ch->methods, M_DEVBUF); 616 kfree(ch, M_DEVBUF); 617 return (NULL); 618 } 619 620 return (ch); 621 } 622 623 int 624 pcm_chn_destroy(struct pcm_channel *ch) 625 { 626 struct snddev_info *d; 627 int err; 628 629 d = ch->parentsnddev; 630 PCM_BUSYASSERT(d); 631 632 err = chn_kill(ch); 633 if (err) { 634 device_printf(ch->dev, "chn_kill(%s) failed, err = %d\n", 635 ch->name, err); 636 return (err); 637 } 638 639 kobj_delete(ch->methods, M_DEVBUF); 640 kfree(ch, M_DEVBUF); 641 642 return (0); 643 } 644 645 int 646 pcm_chn_add(struct snddev_info *d, struct pcm_channel *ch) 647 { 648 PCM_BUSYASSERT(d); 649 PCM_LOCKASSERT(d); 650 KASSERT(ch != NULL && (ch->direction == PCMDIR_PLAY || 651 ch->direction == PCMDIR_REC), ("Invalid pcm channel")); 652 653 CHN_INSERT_SORT_ASCEND(d, ch, channels.pcm); 654 655 switch (CHN_DEV(ch)) { 656 case SND_DEV_DSPHW_PLAY: 657 d->playcount++; 658 break; 659 case SND_DEV_DSPHW_VPLAY: 660 d->pvchancount++; 661 break; 662 case SND_DEV_DSPHW_REC: 663 d->reccount++; 664 break; 665 case SND_DEV_DSPHW_VREC: 666 d->rvchancount++; 667 break; 668 default: 669 break; 670 } 671 672 d->devcount++; 673 674 return (0); 675 } 676 677 int 678 pcm_chn_remove(struct snddev_info *d, struct pcm_channel *ch) 679 { 680 struct pcm_channel *tmp; 681 682 PCM_BUSYASSERT(d); 683 PCM_LOCKASSERT(d); 684 685 tmp = NULL; 686 687 CHN_FOREACH(tmp, d, channels.pcm) { 688 if (tmp == ch) 689 break; 690 } 691 692 if (tmp != ch) 693 return (EINVAL); 694 695 CHN_REMOVE(d, ch, channels.pcm); 696 697 switch (CHN_DEV(ch)) { 698 case SND_DEV_DSPHW_PLAY: 699 d->playcount--; 700 break; 701 case SND_DEV_DSPHW_VPLAY: 702 d->pvchancount--; 703 break; 704 case SND_DEV_DSPHW_REC: 705 d->reccount--; 706 break; 707 case SND_DEV_DSPHW_VREC: 708 d->rvchancount--; 709 break; 710 default: 711 break; 712 } 713 714 d->devcount--; 715 716 return (0); 717 } 718 719 int 720 pcm_addchan(device_t dev, int dir, kobj_class_t cls, void *devinfo) 721 { 722 struct snddev_info *d = device_get_softc(dev); 723 struct pcm_channel *ch; 724 int err; 725 726 PCM_BUSYASSERT(d); 727 728 PCM_LOCK(d); 729 ch = pcm_chn_create(d, NULL, cls, dir, -1, devinfo); 730 if (!ch) { 731 device_printf(d->dev, "pcm_chn_create(%s, %d, %p) failed\n", 732 cls->name, dir, devinfo); 733 PCM_UNLOCK(d); 734 return (ENODEV); 735 } 736 737 err = pcm_chn_add(d, ch); 738 PCM_UNLOCK(d); 739 if (err) { 740 device_printf(d->dev, "pcm_chn_add(%s) failed, err=%d\n", 741 ch->name, err); 742 pcm_chn_destroy(ch); 743 } 744 745 return (err); 746 } 747 748 static int 749 pcm_killchan(device_t dev) 750 { 751 struct snddev_info *d = device_get_softc(dev); 752 struct pcm_channel *ch; 753 int error; 754 755 PCM_BUSYASSERT(d); 756 757 ch = CHN_FIRST(d, channels.pcm); 758 759 PCM_LOCK(d); 760 error = pcm_chn_remove(d, ch); 761 PCM_UNLOCK(d); 762 if (error) 763 return (error); 764 return (pcm_chn_destroy(ch)); 765 } 766 767 static int 768 pcm_best_unit(int old) 769 { 770 struct snddev_info *d; 771 int i, best, bestprio, prio; 772 773 best = -1; 774 bestprio = -100; 775 for (i = 0; pcm_devclass != NULL && 776 i < devclass_get_maxunit(pcm_devclass); i++) { 777 d = devclass_get_softc(pcm_devclass, i); 778 if (!PCM_REGISTERED(d)) 779 continue; 780 prio = 0; 781 if (d->playcount == 0) 782 prio -= 10; 783 if (d->reccount == 0) 784 prio -= 2; 785 if (prio > bestprio || (prio == bestprio && i == old)) { 786 best = i; 787 bestprio = prio; 788 } 789 } 790 791 /* Change default devfs entries to new best device if needed */ 792 if (snd_unit != best) 793 pcm_set_dev_alias(best); 794 795 return (best); 796 } 797 798 int 799 pcm_setstatus(device_t dev, char *str) 800 { 801 struct snddev_info *d = device_get_softc(dev); 802 803 PCM_BUSYASSERT(d); 804 805 if (d->playcount == 0 || d->reccount == 0) 806 d->flags |= SD_F_SIMPLEX; 807 808 if ((d->playcount > 0 || d->reccount > 0) && 809 !(d->flags & SD_F_AUTOVCHAN)) { 810 d->flags |= SD_F_AUTOVCHAN; 811 vchan_initsys(dev); 812 } 813 814 pcm_setmaxautovchans(d, snd_maxautovchans); 815 816 strlcpy(d->status, str, SND_STATUSLEN); 817 818 PCM_LOCK(d); 819 820 /* Last stage, enable cloning. */ 821 if (d->clones != NULL) 822 (void)snd_clone_enable(d->clones); 823 824 /* Done, we're ready.. */ 825 d->flags |= SD_F_REGISTERED; 826 827 PCM_RELEASE(d); 828 829 PCM_UNLOCK(d); 830 831 if (snd_unit_auto < 0) 832 snd_unit_auto = (snd_unit < 0) ? 1 : 0; 833 if (snd_unit < 0 || snd_unit_auto > 1) { 834 if (device_get_unit(dev) != snd_unit) { 835 pcm_set_dev_alias(device_get_unit(dev)); 836 snd_unit = device_get_unit(dev); 837 } 838 } else if (snd_unit_auto == 1) { 839 snd_unit = pcm_best_unit(snd_unit); 840 } 841 842 return (0); 843 } 844 845 uint32_t 846 pcm_getflags(device_t dev) 847 { 848 struct snddev_info *d = device_get_softc(dev); 849 850 return d->flags; 851 } 852 853 void 854 pcm_setflags(device_t dev, uint32_t val) 855 { 856 struct snddev_info *d = device_get_softc(dev); 857 858 d->flags = val; 859 } 860 861 void * 862 pcm_getdevinfo(device_t dev) 863 { 864 struct snddev_info *d = device_get_softc(dev); 865 866 return d->devinfo; 867 } 868 869 unsigned int 870 pcm_getbuffersize(device_t dev, unsigned int minbufsz, unsigned int deflt, unsigned int maxbufsz) 871 { 872 struct snddev_info *d = device_get_softc(dev); 873 int sz, x; 874 875 sz = 0; 876 if (resource_int_value(device_get_name(dev), device_get_unit(dev), "buffersize", &sz) == 0) { 877 x = sz; 878 RANGE(sz, minbufsz, maxbufsz); 879 if (x != sz) 880 device_printf(dev, "'buffersize=%d' hint is out of range (%d-%d), using %d\n", x, minbufsz, maxbufsz, sz); 881 x = minbufsz; 882 while (x < sz) 883 x <<= 1; 884 if (x > sz) 885 x >>= 1; 886 if (x != sz) { 887 device_printf(dev, "'buffersize=%d' hint is not a power of 2, using %d\n", sz, x); 888 sz = x; 889 } 890 } else { 891 sz = deflt; 892 } 893 894 d->bufsz = sz; 895 896 return sz; 897 } 898 899 static int 900 sysctl_dev_pcm_bitperfect(SYSCTL_HANDLER_ARGS) 901 { 902 struct snddev_info *d; 903 int err, val; 904 905 d = oidp->oid_arg1; 906 if (!PCM_REGISTERED(d)) 907 return (ENODEV); 908 909 PCM_LOCK(d); 910 PCM_WAIT(d); 911 val = (d->flags & SD_F_BITPERFECT) ? 1 : 0; 912 PCM_ACQUIRE(d); 913 PCM_UNLOCK(d); 914 915 err = sysctl_handle_int(oidp, &val, 0, req); 916 917 if (err == 0 && req->newptr != NULL) { 918 if (!(val == 0 || val == 1)) { 919 PCM_RELEASE_QUICK(d); 920 return (EINVAL); 921 } 922 923 PCM_LOCK(d); 924 925 d->flags &= ~SD_F_BITPERFECT; 926 d->flags |= (val != 0) ? SD_F_BITPERFECT : 0; 927 928 PCM_RELEASE(d); 929 PCM_UNLOCK(d); 930 } else 931 PCM_RELEASE_QUICK(d); 932 933 return (err); 934 } 935 936 #ifdef SND_DEBUG 937 static int 938 sysctl_dev_pcm_clone_flags(SYSCTL_HANDLER_ARGS) 939 { 940 struct snddev_info *d; 941 uint32_t flags; 942 int err; 943 944 d = oidp->oid_arg1; 945 if (!PCM_REGISTERED(d) || d->clones == NULL) 946 return (ENODEV); 947 948 PCM_ACQUIRE_QUICK(d); 949 950 flags = snd_clone_getflags(d->clones); 951 err = sysctl_handle_int(oidp, &flags, 0, req); 952 953 if (err == 0 && req->newptr != NULL) { 954 if (flags & ~SND_CLONE_MASK) 955 err = EINVAL; 956 else 957 (void)snd_clone_setflags(d->clones, flags); 958 } 959 960 PCM_RELEASE_QUICK(d); 961 962 return (err); 963 } 964 965 static int 966 sysctl_dev_pcm_clone_deadline(SYSCTL_HANDLER_ARGS) 967 { 968 struct snddev_info *d; 969 int err, deadline; 970 971 d = oidp->oid_arg1; 972 if (!PCM_REGISTERED(d) || d->clones == NULL) 973 return (ENODEV); 974 975 PCM_ACQUIRE_QUICK(d); 976 977 deadline = snd_clone_getdeadline(d->clones); 978 err = sysctl_handle_int(oidp, &deadline, 0, req); 979 980 if (err == 0 && req->newptr != NULL) { 981 if (deadline < 0) 982 err = EINVAL; 983 else 984 (void)snd_clone_setdeadline(d->clones, deadline); 985 } 986 987 PCM_RELEASE_QUICK(d); 988 989 return (err); 990 } 991 992 static int 993 sysctl_dev_pcm_clone_gc(SYSCTL_HANDLER_ARGS) 994 { 995 struct snddev_info *d; 996 int err, val; 997 998 d = oidp->oid_arg1; 999 if (!PCM_REGISTERED(d) || d->clones == NULL) 1000 return (ENODEV); 1001 1002 val = 0; 1003 err = sysctl_handle_int(oidp, &val, 0, req); 1004 1005 if (err == 0 && req->newptr != NULL && val != 0) { 1006 PCM_ACQUIRE_QUICK(d); 1007 val = snd_clone_gc(d->clones); 1008 PCM_RELEASE_QUICK(d); 1009 if (bootverbose != 0 || snd_verbose > 3) 1010 device_printf(d->dev, "clone gc: pruned=%d\n", val); 1011 } 1012 1013 return (err); 1014 } 1015 1016 static int 1017 sysctl_hw_snd_clone_gc(SYSCTL_HANDLER_ARGS) 1018 { 1019 struct snddev_info *d; 1020 int i, err, val; 1021 1022 val = 0; 1023 err = sysctl_handle_int(oidp, &val, 0, req); 1024 1025 if (err == 0 && req->newptr != NULL && val != 0) { 1026 for (i = 0; pcm_devclass != NULL && 1027 i < devclass_get_maxunit(pcm_devclass); i++) { 1028 d = devclass_get_softc(pcm_devclass, i); 1029 if (!PCM_REGISTERED(d) || d->clones == NULL) 1030 continue; 1031 PCM_ACQUIRE_QUICK(d); 1032 val = snd_clone_gc(d->clones); 1033 PCM_RELEASE_QUICK(d); 1034 if (bootverbose != 0 || snd_verbose > 3) 1035 device_printf(d->dev, "clone gc: pruned=%d\n", 1036 val); 1037 } 1038 } 1039 1040 return (err); 1041 } 1042 SYSCTL_PROC(_hw_snd, OID_AUTO, clone_gc, CTLTYPE_INT | CTLFLAG_RW, 1043 0, sizeof(int), sysctl_hw_snd_clone_gc, "I", 1044 "global clone garbage collector"); 1045 #endif 1046 1047 extern struct devfs_bitmap devfs_dsp_clone_bitmap; 1048 1049 int 1050 pcm_register(device_t dev, void *devinfo, int numplay, int numrec) 1051 { 1052 struct snddev_info *d; 1053 int i; 1054 1055 if (pcm_veto_load) { 1056 device_printf(dev, "disabled due to an error while initialising: %d\n", pcm_veto_load); 1057 1058 return EINVAL; 1059 } 1060 1061 if (device_get_unit(dev) > PCMMAXUNIT) { 1062 device_printf(dev, "PCMMAXUNIT reached : unit=%d > %d\n", 1063 device_get_unit(dev), PCMMAXUNIT); 1064 device_printf(dev, 1065 "Use 'hw.snd.maxunit' tunable to raise the limit.\n"); 1066 return ENODEV; 1067 } 1068 1069 d = device_get_softc(dev); 1070 d->dev = dev; 1071 d->lock = snd_mtxcreate(device_get_nameunit(dev), "sound cdev"); 1072 cv_init(&d->cv, device_get_nameunit(dev)); 1073 PCM_ACQUIRE_QUICK(d); 1074 dsp_cdevinfo_init(d); 1075 #if 0 1076 /* 1077 * d->flags should be cleared by the allocator of the softc. 1078 * We cannot clear this field here because several devices set 1079 * this flag before calling pcm_register(). 1080 */ 1081 d->flags = 0; 1082 #endif 1083 i = 0; 1084 if (resource_int_value(device_get_name(dev), device_get_unit(dev), 1085 "vpc", &i) != 0 || i != 0) 1086 d->flags |= SD_F_VPC; 1087 1088 if (resource_int_value(device_get_name(dev), device_get_unit(dev), 1089 "bitperfect", &i) == 0 && i != 0) 1090 d->flags |= SD_F_BITPERFECT; 1091 1092 d->devinfo = devinfo; 1093 d->devcount = 0; 1094 d->reccount = 0; 1095 d->playcount = 0; 1096 d->pvchancount = 0; 1097 d->rvchancount = 0; 1098 d->pvchanrate = 0; 1099 d->pvchanformat = 0; 1100 d->rvchanrate = 0; 1101 d->rvchanformat = 0; 1102 d->inprog = 0; 1103 1104 /* 1105 * Create clone manager, disabled by default. Cloning will be 1106 * enabled during final stage of driver initialization through 1107 * pcm_setstatus(). 1108 */ 1109 d->clones = snd_clone_create(SND_U_MASK | SND_D_MASK, PCMMAXCLONE, 1110 SND_CLONE_DEADLINE_DEFAULT, SND_CLONE_WAITOK | 1111 SND_CLONE_GC_ENABLE | SND_CLONE_GC_UNREF | 1112 SND_CLONE_GC_LASTREF | SND_CLONE_GC_EXPIRED); 1113 1114 CHN_INIT(d, channels.pcm); 1115 CHN_INIT(d, channels.pcm.busy); 1116 CHN_INIT(d, channels.pcm.opened); 1117 1118 /* XXX This is incorrect, but lets play along for now. */ 1119 if ((numplay == 0 || numrec == 0) && numplay != numrec) 1120 d->flags |= SD_F_SIMPLEX; 1121 1122 sysctl_ctx_init(&d->play_sysctl_ctx); 1123 d->play_sysctl_tree = SYSCTL_ADD_NODE(&d->play_sysctl_ctx, 1124 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, "play", 1125 CTLFLAG_RD, 0, "playback channels node"); 1126 sysctl_ctx_init(&d->rec_sysctl_ctx); 1127 d->rec_sysctl_tree = SYSCTL_ADD_NODE(&d->rec_sysctl_ctx, 1128 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, "rec", 1129 CTLFLAG_RD, 0, "record channels node"); 1130 /* XXX: an user should be able to set this with a control tool, the 1131 sysadmin then needs min+max sysctls for this */ 1132 SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev), 1133 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 1134 OID_AUTO, "buffersize", CTLFLAG_RD, &d->bufsz, 0, "allocated buffer size"); 1135 SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 1136 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, 1137 "bitperfect", CTLTYPE_INT | CTLFLAG_RW, d, sizeof(d), 1138 sysctl_dev_pcm_bitperfect, "I", 1139 "bit-perfect playback/recording (0=disable, 1=enable)"); 1140 #ifdef SND_DEBUG 1141 SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 1142 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, 1143 "clone_flags", CTLTYPE_UINT | CTLFLAG_RW, d, sizeof(d), 1144 sysctl_dev_pcm_clone_flags, "IU", 1145 "clone flags"); 1146 SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 1147 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, 1148 "clone_deadline", CTLTYPE_INT | CTLFLAG_RW, d, sizeof(d), 1149 sysctl_dev_pcm_clone_deadline, "I", 1150 "clone expiration deadline (ms)"); 1151 SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 1152 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, 1153 "clone_gc", CTLTYPE_INT | CTLFLAG_RW, d, sizeof(d), 1154 sysctl_dev_pcm_clone_gc, "I", 1155 "clone garbage collector"); 1156 #endif 1157 1158 if (numplay > 0 || numrec > 0) { 1159 d->flags |= SD_F_AUTOVCHAN; 1160 vchan_initsys(dev); 1161 } 1162 1163 if (d->flags & SD_F_EQ) 1164 feeder_eq_initsys(dev); 1165 1166 /* XXX use make_autoclone_dev? */ 1167 /* XXX PCMMAXCHAN can be created for regular channels */ 1168 #if 1 1169 d->dsp_clonedev = make_dev(&dsp_ops, 1170 PCMMKMINOR(device_get_unit(dev), SND_DEV_DSP, 0), 1171 UID_ROOT, GID_WHEEL, 0666, "dsp%d", 1172 device_get_unit(dev)); 1173 devfs_clone_handler_add(devtoname(d->dsp_clonedev), dsp_clone); 1174 #else 1175 d->dsp_clonedev = make_autoclone_dev(&dsp_ops, 1176 &DEVFS_CLONE_BITMAP(dsp), dsp_clone, 1177 UID_ROOT, GID_WHEEL, 0666, "dsp%d", 1178 device_get_unit(dev)); 1179 #endif 1180 1181 sndstat_register(dev, d->status, sndstat_prepare_pcm); 1182 1183 return 0; 1184 } 1185 1186 int 1187 pcm_unregister(device_t dev) 1188 { 1189 struct snddev_info *d; 1190 struct pcm_channel *ch; 1191 struct thread *td; 1192 1193 td = curthread; 1194 d = device_get_softc(dev); 1195 1196 if (!PCM_ALIVE(d)) { 1197 device_printf(dev, "unregister: device not configured\n"); 1198 return (0); 1199 } 1200 1201 if (sndstat_acquire(td) != 0) { 1202 device_printf(dev, "unregister: sndstat busy\n"); 1203 return (EBUSY); 1204 } 1205 1206 PCM_LOCK(d); 1207 PCM_WAIT(d); 1208 1209 if (d->inprog != 0) { 1210 device_printf(dev, "unregister: operation in progress\n"); 1211 PCM_UNLOCK(d); 1212 sndstat_release(td); 1213 return (EBUSY); 1214 } 1215 1216 PCM_ACQUIRE(d); 1217 PCM_UNLOCK(d); 1218 1219 CHN_FOREACH(ch, d, channels.pcm) { 1220 CHN_LOCK(ch); 1221 if (ch->refcount > 0) { 1222 device_printf(dev, 1223 "unregister: channel %s busy (pid %d)\n", 1224 ch->name, ch->pid); 1225 CHN_UNLOCK(ch); 1226 PCM_RELEASE_QUICK(d); 1227 sndstat_release(td); 1228 return (EBUSY); 1229 } 1230 CHN_UNLOCK(ch); 1231 } 1232 1233 if (d->clones != NULL) { 1234 if (snd_clone_busy(d->clones) != 0) { 1235 device_printf(dev, "unregister: clone busy\n"); 1236 PCM_RELEASE_QUICK(d); 1237 sndstat_release(td); 1238 return (EBUSY); 1239 } else { 1240 PCM_LOCK(d); 1241 (void)snd_clone_disable(d->clones); 1242 PCM_UNLOCK(d); 1243 } 1244 } 1245 1246 if (mixer_uninit(dev) == EBUSY) { 1247 device_printf(dev, "unregister: mixer busy\n"); 1248 PCM_LOCK(d); 1249 if (d->clones != NULL) 1250 (void)snd_clone_enable(d->clones); 1251 PCM_RELEASE(d); 1252 PCM_UNLOCK(d); 1253 sndstat_release(td); 1254 return (EBUSY); 1255 } 1256 1257 PCM_LOCK(d); 1258 d->flags |= SD_F_DYING; 1259 d->flags &= ~SD_F_REGISTERED; 1260 PCM_UNLOCK(d); 1261 1262 /* 1263 * No lock being held, so this thing can be flushed without 1264 * stucking into devdrn oblivion. 1265 */ 1266 if (d->clones != NULL) { 1267 snd_clone_destroy(d->clones); 1268 d->clones = NULL; 1269 } 1270 devfs_clone_handler_del(devtoname(d->dsp_clonedev)); 1271 destroy_dev(d->dsp_clonedev); 1272 1273 if (d->play_sysctl_tree != NULL) { 1274 sysctl_ctx_free(&d->play_sysctl_ctx); 1275 d->play_sysctl_tree = NULL; 1276 } 1277 if (d->rec_sysctl_tree != NULL) { 1278 sysctl_ctx_free(&d->rec_sysctl_ctx); 1279 d->rec_sysctl_tree = NULL; 1280 } 1281 1282 while (!CHN_EMPTY(d, channels.pcm)) 1283 pcm_killchan(dev); 1284 1285 dsp_cdevinfo_flush(d); 1286 1287 PCM_LOCK(d); 1288 PCM_RELEASE(d); 1289 cv_destroy(&d->cv); 1290 PCM_UNLOCK(d); 1291 snd_mtxfree(d->lock); 1292 sndstat_unregister(dev); 1293 sndstat_release(td); 1294 1295 if (snd_unit == device_get_unit(dev)) { 1296 snd_unit = pcm_best_unit(-1); 1297 if (snd_unit_auto == 0) 1298 snd_unit_auto = 1; 1299 } 1300 1301 return (0); 1302 } 1303 1304 /************************************************************************/ 1305 1306 /** 1307 * @brief Handle OSSv4 SNDCTL_SYSINFO ioctl. 1308 * 1309 * @param si Pointer to oss_sysinfo struct where information about the 1310 * sound subsystem will be written/copied. 1311 * 1312 * This routine returns information about the sound system, such as the 1313 * current OSS version, number of audio, MIDI, and mixer drivers, etc. 1314 * Also includes a bitmask showing which of the above types of devices 1315 * are open (busy). 1316 * 1317 * @note 1318 * Calling threads must not hold any snddev_info or pcm_channel locks. 1319 * 1320 * @author Ryan Beasley <ryanb@FreeBSD.org> 1321 */ 1322 void 1323 sound_oss_sysinfo(oss_sysinfo *si) 1324 { 1325 static char si_product[] = "FreeBSD native OSS ABI"; 1326 static char si_version[] = __XSTRING(__FreeBSD_version); 1327 static char si_license[] = "BSD"; 1328 static int intnbits = sizeof(int) * 8; /* Better suited as macro? 1329 Must pester a C guru. */ 1330 1331 struct snddev_info *d; 1332 struct pcm_channel *c; 1333 int i, j, ncards; 1334 1335 ncards = 0; 1336 1337 strlcpy(si->product, si_product, sizeof(si->product)); 1338 strlcpy(si->version, si_version, sizeof(si->version)); 1339 si->versionnum = SOUND_VERSION; 1340 strlcpy(si->license, si_license, sizeof(si->license)); 1341 1342 /* 1343 * Iterate over PCM devices and their channels, gathering up data 1344 * for the numaudios, ncards, and openedaudio fields. 1345 */ 1346 si->numaudios = 0; 1347 bzero((void *)&si->openedaudio, sizeof(si->openedaudio)); 1348 1349 j = 0; 1350 1351 for (i = 0; pcm_devclass != NULL && 1352 i < devclass_get_maxunit(pcm_devclass); i++) { 1353 d = devclass_get_softc(pcm_devclass, i); 1354 if (!PCM_REGISTERED(d)) 1355 continue; 1356 1357 /* XXX Need Giant magic entry ??? */ 1358 1359 /* See note in function's docblock */ 1360 PCM_UNLOCKASSERT(d); 1361 PCM_LOCK(d); 1362 1363 si->numaudios += d->devcount; 1364 ++ncards; 1365 1366 CHN_FOREACH(c, d, channels.pcm) { 1367 CHN_UNLOCKASSERT(c); 1368 CHN_LOCK(c); 1369 if (c->flags & CHN_F_BUSY) 1370 si->openedaudio[j / intnbits] |= 1371 (1 << (j % intnbits)); 1372 CHN_UNLOCK(c); 1373 j++; 1374 } 1375 1376 PCM_UNLOCK(d); 1377 } 1378 si->numaudioengines = si->numaudios; 1379 1380 si->numsynths = 0; /* OSSv4 docs: this field is obsolete */ 1381 /** 1382 * @todo Collect num{midis,timers}. 1383 * 1384 * Need access to sound/midi/midi.c::midistat_lock in order 1385 * to safely touch midi_devices and get a head count of, well, 1386 * MIDI devices. midistat_lock is a global static (i.e., local to 1387 * midi.c), but midi_devices is a regular global; should the mutex 1388 * be publicized, or is there another way to get this information? 1389 * 1390 * NB: MIDI/sequencer stuff is currently on hold. 1391 */ 1392 si->nummidis = 0; 1393 si->numtimers = 0; 1394 si->nummixers = mixer_count; 1395 si->numcards = ncards; 1396 /* OSSv4 docs: Intended only for test apps; API doesn't 1397 really have much of a concept of cards. Shouldn't be 1398 used by applications. */ 1399 1400 /** 1401 * @todo Fill in "busy devices" fields. 1402 * 1403 * si->openedmidi = " MIDI devices 1404 */ 1405 bzero((void *)&si->openedmidi, sizeof(si->openedmidi)); 1406 1407 /* 1408 * Si->filler is a reserved array, but according to docs each 1409 * element should be set to -1. 1410 */ 1411 for (i = 0; i < sizeof(si->filler)/sizeof(si->filler[0]); i++) 1412 si->filler[i] = -1; 1413 } 1414 1415 int 1416 sound_oss_card_info(oss_card_info *si) 1417 { 1418 struct snddev_info *d; 1419 int i, ncards; 1420 1421 ncards = 0; 1422 1423 for (i = 0; pcm_devclass != NULL && 1424 i < devclass_get_maxunit(pcm_devclass); i++) { 1425 d = devclass_get_softc(pcm_devclass, i); 1426 if (!PCM_REGISTERED(d)) 1427 continue; 1428 1429 if (ncards++ != si->card) 1430 continue; 1431 1432 PCM_UNLOCKASSERT(d); 1433 PCM_LOCK(d); 1434 1435 strlcpy(si->shortname, device_get_nameunit(d->dev), 1436 sizeof(si->shortname)); 1437 strlcpy(si->longname, device_get_desc(d->dev), 1438 sizeof(si->longname)); 1439 strlcpy(si->hw_info, d->status, sizeof(si->hw_info)); 1440 si->intr_count = si->ack_count = 0; 1441 1442 PCM_UNLOCK(d); 1443 1444 return (0); 1445 } 1446 return (ENXIO); 1447 } 1448 1449 /************************************************************************/ 1450 1451 static int 1452 sound_modevent(module_t mod, int type, void *data) 1453 { 1454 int ret; 1455 #if 0 1456 return (midi_modevent(mod, type, data)); 1457 #else 1458 ret = 0; 1459 1460 switch(type) { 1461 case MOD_LOAD: 1462 pcmsg_unrhdr = new_unrhdr(1, INT_MAX, NULL); 1463 break; 1464 case MOD_UNLOAD: 1465 ret = sndstat_acquire(curthread); 1466 if (ret != 0) 1467 break; 1468 if (pcmsg_unrhdr != NULL) { 1469 delete_unrhdr(pcmsg_unrhdr); 1470 pcmsg_unrhdr = NULL; 1471 } 1472 break; 1473 case MOD_SHUTDOWN: 1474 break; 1475 default: 1476 ret = ENOTSUP; 1477 } 1478 1479 return ret; 1480 #endif 1481 } 1482 1483 DEV_MODULE(sound, sound_modevent, NULL); 1484 MODULE_VERSION(sound, SOUND_MODVER); 1485