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