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