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