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