1 /*- 2 * Copyright (c) 1999 Cameron Grant <cg@freebsd.org> 3 * Portions Copyright by Luigi Rizzo - 1997-99 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 */ 27 28 #include "opt_isa.h" 29 30 #include <dev/sound/pcm/sound.h> 31 32 #include "feeder_if.h" 33 34 SND_DECLARE_FILE("$FreeBSD$"); 35 36 #define MIN_CHUNK_SIZE 256 /* for uiomove etc. */ 37 #define DMA_ALIGN_THRESHOLD 4 38 #define DMA_ALIGN_MASK (~(DMA_ALIGN_THRESHOLD - 1)) 39 40 #define CANCHANGE(c) (!(c->flags & CHN_F_TRIGGERED)) 41 42 /* 43 #define DEB(x) x 44 */ 45 46 static int chn_targetirqrate = 32; 47 TUNABLE_INT("hw.snd.targetirqrate", &chn_targetirqrate); 48 49 static int 50 sysctl_hw_snd_targetirqrate(SYSCTL_HANDLER_ARGS) 51 { 52 int err, val; 53 54 val = chn_targetirqrate; 55 err = sysctl_handle_int(oidp, &val, sizeof(val), req); 56 if (val < 16 || val > 512) 57 err = EINVAL; 58 else 59 chn_targetirqrate = val; 60 61 return err; 62 } 63 SYSCTL_PROC(_hw_snd, OID_AUTO, targetirqrate, CTLTYPE_INT | CTLFLAG_RW, 64 0, sizeof(int), sysctl_hw_snd_targetirqrate, "I", ""); 65 static int report_soft_formats = 1; 66 SYSCTL_INT(_hw_snd, OID_AUTO, report_soft_formats, CTLFLAG_RW, 67 &report_soft_formats, 1, "report software-emulated formats"); 68 69 static int chn_buildfeeder(struct pcm_channel *c); 70 71 static void 72 chn_lockinit(struct pcm_channel *c, int dir) 73 { 74 switch(dir) { 75 case PCMDIR_PLAY: 76 c->lock = snd_mtxcreate(c->name, "pcm play channel"); 77 break; 78 case PCMDIR_REC: 79 c->lock = snd_mtxcreate(c->name, "pcm record channel"); 80 break; 81 case PCMDIR_VIRTUAL: 82 c->lock = snd_mtxcreate(c->name, "pcm virtual play channel"); 83 break; 84 case 0: 85 c->lock = snd_mtxcreate(c->name, "pcm fake channel"); 86 break; 87 } 88 } 89 90 static void 91 chn_lockdestroy(struct pcm_channel *c) 92 { 93 snd_mtxfree(c->lock); 94 } 95 96 static int 97 chn_polltrigger(struct pcm_channel *c) 98 { 99 struct snd_dbuf *bs = c->bufsoft; 100 unsigned amt, lim; 101 102 CHN_LOCKASSERT(c); 103 if (c->flags & CHN_F_MAPPED) { 104 if (sndbuf_getprevblocks(bs) == 0) 105 return 1; 106 else 107 return (sndbuf_getblocks(bs) > sndbuf_getprevblocks(bs))? 1 : 0; 108 } else { 109 amt = (c->direction == PCMDIR_PLAY)? sndbuf_getfree(bs) : sndbuf_getready(bs); 110 #if 0 111 lim = (c->flags & CHN_F_HAS_SIZE)? sndbuf_getblksz(bs) : 1; 112 #endif 113 lim = 1; 114 return (amt >= lim)? 1 : 0; 115 } 116 return 0; 117 } 118 119 static int 120 chn_pollreset(struct pcm_channel *c) 121 { 122 struct snd_dbuf *bs = c->bufsoft; 123 124 CHN_LOCKASSERT(c); 125 sndbuf_updateprevtotal(bs); 126 return 1; 127 } 128 129 static void 130 chn_wakeup(struct pcm_channel *c) 131 { 132 struct snd_dbuf *bs = c->bufsoft; 133 struct pcmchan_children *pce; 134 135 CHN_LOCKASSERT(c); 136 if (SLIST_EMPTY(&c->children)) { 137 if (SEL_WAITING(sndbuf_getsel(bs)) && chn_polltrigger(c)) 138 selwakeuppri(sndbuf_getsel(bs), PRIBIO); 139 } else { 140 SLIST_FOREACH(pce, &c->children, link) { 141 CHN_LOCK(pce->channel); 142 chn_wakeup(pce->channel); 143 CHN_UNLOCK(pce->channel); 144 } 145 } 146 147 wakeup(bs); 148 } 149 150 static int 151 chn_sleep(struct pcm_channel *c, char *str, int timeout) 152 { 153 struct snd_dbuf *bs = c->bufsoft; 154 int ret; 155 156 CHN_LOCKASSERT(c); 157 #ifdef USING_MUTEX 158 ret = msleep(bs, c->lock, PRIBIO | PCATCH, str, timeout); 159 #else 160 ret = tsleep(bs, PRIBIO | PCATCH, str, timeout); 161 #endif 162 163 return ret; 164 } 165 166 /* 167 * chn_dmaupdate() tracks the status of a dma transfer, 168 * updating pointers. 169 */ 170 171 static unsigned int 172 chn_dmaupdate(struct pcm_channel *c) 173 { 174 struct snd_dbuf *b = c->bufhard; 175 unsigned int delta, old, hwptr, amt; 176 177 KASSERT(sndbuf_getsize(b) > 0, ("bufsize == 0")); 178 CHN_LOCKASSERT(c); 179 180 old = sndbuf_gethwptr(b); 181 hwptr = chn_getptr(c); 182 delta = (sndbuf_getsize(b) + hwptr - old) % sndbuf_getsize(b); 183 sndbuf_sethwptr(b, hwptr); 184 185 DEB( 186 if (delta >= ((sndbuf_getsize(b) * 15) / 16)) { 187 if (!(c->flags & (CHN_F_CLOSING | CHN_F_ABORTING))) 188 device_printf(c->dev, "hwptr went backwards %d -> %d\n", old, hwptr); 189 } 190 ); 191 192 if (c->direction == PCMDIR_PLAY) { 193 amt = MIN(delta, sndbuf_getready(b)); 194 if (amt > 0) 195 sndbuf_dispose(b, NULL, amt); 196 } else { 197 amt = MIN(delta, sndbuf_getfree(b)); 198 if (amt > 0) 199 sndbuf_acquire(b, NULL, amt); 200 } 201 202 return delta; 203 } 204 205 void 206 chn_wrupdate(struct pcm_channel *c) 207 { 208 int ret; 209 210 CHN_LOCKASSERT(c); 211 KASSERT(c->direction == PCMDIR_PLAY, ("chn_wrupdate on bad channel")); 212 213 if ((c->flags & (CHN_F_MAPPED | CHN_F_VIRTUAL)) || !(c->flags & CHN_F_TRIGGERED)) 214 return; 215 chn_dmaupdate(c); 216 ret = chn_wrfeed(c); 217 /* tell the driver we've updated the primary buffer */ 218 chn_trigger(c, PCMTRIG_EMLDMAWR); 219 DEB(if (ret) 220 printf("chn_wrupdate: chn_wrfeed returned %d\n", ret);) 221 222 } 223 224 int 225 chn_wrfeed(struct pcm_channel *c) 226 { 227 struct snd_dbuf *b = c->bufhard; 228 struct snd_dbuf *bs = c->bufsoft; 229 unsigned int ret, amt; 230 231 CHN_LOCKASSERT(c); 232 #if 0 233 DEB( 234 if (c->flags & CHN_F_CLOSING) { 235 sndbuf_dump(b, "b", 0x02); 236 sndbuf_dump(bs, "bs", 0x02); 237 }) 238 #endif 239 240 if (c->flags & CHN_F_MAPPED) 241 sndbuf_acquire(bs, NULL, sndbuf_getfree(bs)); 242 243 amt = sndbuf_getfree(b); 244 KASSERT(amt <= sndbuf_getsize(bs), 245 ("%s(%s): amt %d > source size %d, flags 0x%x", __func__, c->name, 246 amt, sndbuf_getsize(bs), c->flags)); 247 248 ret = (amt > 0) ? sndbuf_feed(bs, b, c, c->feeder, amt) : ENOSPC; 249 /* 250 * Possible xruns. There should be no empty space left in buffer. 251 */ 252 if (sndbuf_getfree(b) > 0) 253 c->xruns++; 254 255 if (ret == 0 && sndbuf_getfree(b) < amt) 256 chn_wakeup(c); 257 258 return ret; 259 } 260 261 static void 262 chn_wrintr(struct pcm_channel *c) 263 { 264 int ret; 265 266 CHN_LOCKASSERT(c); 267 /* update pointers in primary buffer */ 268 chn_dmaupdate(c); 269 /* ...and feed from secondary to primary */ 270 ret = chn_wrfeed(c); 271 /* tell the driver we've updated the primary buffer */ 272 chn_trigger(c, PCMTRIG_EMLDMAWR); 273 DEB(if (ret) 274 printf("chn_wrintr: chn_wrfeed returned %d\n", ret);) 275 } 276 277 /* 278 * user write routine - uiomove data into secondary buffer, trigger if necessary 279 * if blocking, sleep, rinse and repeat. 280 * 281 * called externally, so must handle locking 282 */ 283 284 int 285 chn_write(struct pcm_channel *c, struct uio *buf) 286 { 287 int ret, timeout, newsize, count, sz; 288 struct snd_dbuf *bs = c->bufsoft; 289 void *off; 290 int t, x,togo,p; 291 292 CHN_LOCKASSERT(c); 293 /* 294 * XXX Certain applications attempt to write larger size 295 * of pcm data than c->blocksize2nd without blocking, 296 * resulting partial write. Expand the block size so that 297 * the write operation avoids blocking. 298 */ 299 if ((c->flags & CHN_F_NBIO) && buf->uio_resid > sndbuf_getblksz(bs)) { 300 DEB(device_printf(c->dev, "broken app, nbio and tried to write %d bytes with fragsz %d\n", 301 buf->uio_resid, sndbuf_getblksz(bs))); 302 newsize = 16; 303 while (newsize < min(buf->uio_resid, CHN_2NDBUFMAXSIZE / 2)) 304 newsize <<= 1; 305 chn_setblocksize(c, sndbuf_getblkcnt(bs), newsize); 306 DEB(device_printf(c->dev, "frags reset to %d x %d\n", sndbuf_getblkcnt(bs), sndbuf_getblksz(bs))); 307 } 308 309 ret = 0; 310 count = hz; 311 while (!ret && (buf->uio_resid > 0) && (count > 0)) { 312 sz = sndbuf_getfree(bs); 313 if (sz == 0) { 314 if (c->flags & CHN_F_NBIO) 315 ret = EWOULDBLOCK; 316 else { 317 timeout = (hz * sndbuf_getblksz(bs)) / (sndbuf_getspd(bs) * sndbuf_getbps(bs)); 318 if (timeout < 1) 319 timeout = 1; 320 timeout = 1; 321 ret = chn_sleep(c, "pcmwr", timeout); 322 if (ret == EWOULDBLOCK) { 323 count -= timeout; 324 ret = 0; 325 } else if (ret == 0) 326 count = hz; 327 } 328 } else { 329 sz = MIN(sz, buf->uio_resid); 330 KASSERT(sz > 0, ("confusion in chn_write")); 331 /* printf("sz: %d\n", sz); */ 332 333 /* 334 * The following assumes that the free space in 335 * the buffer can never be less around the 336 * unlock-uiomove-lock sequence. 337 */ 338 togo = sz; 339 while (ret == 0 && togo> 0) { 340 p = sndbuf_getfreeptr(bs); 341 t = MIN(togo, sndbuf_getsize(bs) - p); 342 off = sndbuf_getbufofs(bs, p); 343 CHN_UNLOCK(c); 344 ret = uiomove(off, t, buf); 345 CHN_LOCK(c); 346 togo -= t; 347 x = sndbuf_acquire(bs, NULL, t); 348 } 349 ret = 0; 350 if (ret == 0 && !(c->flags & CHN_F_TRIGGERED)) 351 chn_start(c, 0); 352 } 353 } 354 /* printf("ret: %d left: %d\n", ret, buf->uio_resid); */ 355 356 if (count <= 0) { 357 c->flags |= CHN_F_DEAD; 358 printf("%s: play interrupt timeout, channel dead\n", c->name); 359 } 360 361 return ret; 362 } 363 364 #if 0 365 static int 366 chn_rddump(struct pcm_channel *c, unsigned int cnt) 367 { 368 struct snd_dbuf *b = c->bufhard; 369 370 CHN_LOCKASSERT(c); 371 #if 0 372 static uint32_t kk = 0; 373 printf("%u: dumping %d bytes\n", ++kk, cnt); 374 #endif 375 c->xruns++; 376 sndbuf_setxrun(b, sndbuf_getxrun(b) + cnt); 377 return sndbuf_dispose(b, NULL, cnt); 378 } 379 #endif 380 381 /* 382 * Feed new data from the read buffer. Can be called in the bottom half. 383 */ 384 int 385 chn_rdfeed(struct pcm_channel *c) 386 { 387 struct snd_dbuf *b = c->bufhard; 388 struct snd_dbuf *bs = c->bufsoft; 389 unsigned int ret, amt; 390 391 CHN_LOCKASSERT(c); 392 DEB( 393 if (c->flags & CHN_F_CLOSING) { 394 sndbuf_dump(b, "b", 0x02); 395 sndbuf_dump(bs, "bs", 0x02); 396 }) 397 398 #if 0 399 amt = sndbuf_getready(b); 400 if (sndbuf_getfree(bs) < amt) { 401 c->xruns++; 402 amt = sndbuf_getfree(bs); 403 } 404 #endif 405 amt = sndbuf_getfree(bs); 406 ret = (amt > 0)? sndbuf_feed(b, bs, c, c->feeder, amt) : 0; 407 408 amt = sndbuf_getready(b); 409 if (amt > 0) { 410 c->xruns++; 411 sndbuf_dispose(b, NULL, amt); 412 } 413 414 chn_wakeup(c); 415 416 return ret; 417 } 418 419 void 420 chn_rdupdate(struct pcm_channel *c) 421 { 422 int ret; 423 424 CHN_LOCKASSERT(c); 425 KASSERT(c->direction == PCMDIR_REC, ("chn_rdupdate on bad channel")); 426 427 if ((c->flags & CHN_F_MAPPED) || !(c->flags & CHN_F_TRIGGERED)) 428 return; 429 chn_trigger(c, PCMTRIG_EMLDMARD); 430 chn_dmaupdate(c); 431 ret = chn_rdfeed(c); 432 DEB(if (ret) 433 printf("chn_rdfeed: %d\n", ret);) 434 435 } 436 437 /* read interrupt routine. Must be called with interrupts blocked. */ 438 static void 439 chn_rdintr(struct pcm_channel *c) 440 { 441 int ret; 442 443 CHN_LOCKASSERT(c); 444 /* tell the driver to update the primary buffer if non-dma */ 445 chn_trigger(c, PCMTRIG_EMLDMARD); 446 /* update pointers in primary buffer */ 447 chn_dmaupdate(c); 448 /* ...and feed from primary to secondary */ 449 ret = chn_rdfeed(c); 450 } 451 452 /* 453 * user read routine - trigger if necessary, uiomove data from secondary buffer 454 * if blocking, sleep, rinse and repeat. 455 * 456 * called externally, so must handle locking 457 */ 458 459 int 460 chn_read(struct pcm_channel *c, struct uio *buf) 461 { 462 int ret, timeout, sz, count; 463 struct snd_dbuf *bs = c->bufsoft; 464 void *off; 465 int t, x,togo,p; 466 467 CHN_LOCKASSERT(c); 468 if (!(c->flags & CHN_F_TRIGGERED)) 469 chn_start(c, 0); 470 471 ret = 0; 472 count = hz; 473 while (!ret && (buf->uio_resid > 0) && (count > 0)) { 474 sz = MIN(buf->uio_resid, sndbuf_getready(bs)); 475 476 if (sz > 0) { 477 /* 478 * The following assumes that the free space in 479 * the buffer can never be less around the 480 * unlock-uiomove-lock sequence. 481 */ 482 togo = sz; 483 while (ret == 0 && togo> 0) { 484 p = sndbuf_getreadyptr(bs); 485 t = MIN(togo, sndbuf_getsize(bs) - p); 486 off = sndbuf_getbufofs(bs, p); 487 CHN_UNLOCK(c); 488 ret = uiomove(off, t, buf); 489 CHN_LOCK(c); 490 togo -= t; 491 x = sndbuf_dispose(bs, NULL, t); 492 } 493 ret = 0; 494 } else { 495 if (c->flags & CHN_F_NBIO) { 496 ret = EWOULDBLOCK; 497 } else { 498 timeout = (hz * sndbuf_getblksz(bs)) / (sndbuf_getspd(bs) * sndbuf_getbps(bs)); 499 if (timeout < 1) 500 timeout = 1; 501 ret = chn_sleep(c, "pcmrd", timeout); 502 if (ret == EWOULDBLOCK) { 503 count -= timeout; 504 ret = 0; 505 } else { 506 count = hz; 507 } 508 509 } 510 } 511 } 512 513 if (count <= 0) { 514 c->flags |= CHN_F_DEAD; 515 printf("%s: record interrupt timeout, channel dead\n", c->name); 516 } 517 518 return ret; 519 } 520 521 void 522 chn_intr(struct pcm_channel *c) 523 { 524 CHN_LOCK(c); 525 c->interrupts++; 526 if (c->direction == PCMDIR_PLAY) 527 chn_wrintr(c); 528 else 529 chn_rdintr(c); 530 CHN_UNLOCK(c); 531 } 532 533 u_int32_t 534 chn_start(struct pcm_channel *c, int force) 535 { 536 u_int32_t i, j; 537 struct snd_dbuf *b = c->bufhard; 538 struct snd_dbuf *bs = c->bufsoft; 539 540 CHN_LOCKASSERT(c); 541 /* if we're running, or if we're prevented from triggering, bail */ 542 if ((c->flags & CHN_F_TRIGGERED) || ((c->flags & CHN_F_NOTRIGGER) && !force)) 543 return EINVAL; 544 545 i = (c->direction == PCMDIR_PLAY)? sndbuf_getready(bs) : sndbuf_getfree(bs); 546 j = (c->direction == PCMDIR_PLAY)? sndbuf_getfree(b) : sndbuf_getready(b); 547 if (force || (i >= j)) { 548 c->flags |= CHN_F_TRIGGERED; 549 /* 550 * if we're starting because a vchan started, don't feed any data 551 * or it becomes impossible to start vchans synchronised with the 552 * first one. the hardbuf should be empty so we top it up with 553 * silence to give it something to chew. the real data will be 554 * fed at the first irq. 555 */ 556 if (c->direction == PCMDIR_PLAY) { 557 /* 558 * Reduce pops during playback startup. 559 */ 560 sndbuf_fillsilence(b); 561 if (SLIST_EMPTY(&c->children)) 562 chn_wrfeed(c); 563 } 564 sndbuf_setrun(b, 1); 565 c->xruns = 0; 566 chn_trigger(c, PCMTRIG_START); 567 return 0; 568 } 569 570 return 0; 571 } 572 573 void 574 chn_resetbuf(struct pcm_channel *c) 575 { 576 struct snd_dbuf *b = c->bufhard; 577 struct snd_dbuf *bs = c->bufsoft; 578 579 c->blocks = 0; 580 sndbuf_reset(b); 581 sndbuf_reset(bs); 582 } 583 584 /* 585 * chn_sync waits until the space in the given channel goes above 586 * a threshold. The threshold is checked against fl or rl respectively. 587 * Assume that the condition can become true, do not check here... 588 */ 589 int 590 chn_sync(struct pcm_channel *c, int threshold) 591 { 592 u_long rdy; 593 int ret; 594 struct snd_dbuf *bs = c->bufsoft; 595 596 CHN_LOCKASSERT(c); 597 598 /* if we haven't yet started and nothing is buffered, else start*/ 599 if (!(c->flags & CHN_F_TRIGGERED)) { 600 if (sndbuf_getready(bs) > 0) { 601 ret = chn_start(c, 1); 602 if (ret) 603 return ret; 604 } else { 605 return 0; 606 } 607 } 608 609 for (;;) { 610 rdy = (c->direction == PCMDIR_PLAY)? sndbuf_getfree(bs) : sndbuf_getready(bs); 611 if (rdy <= threshold) { 612 ret = chn_sleep(c, "pcmsyn", 1); 613 if (ret == ERESTART || ret == EINTR) { 614 DEB(printf("chn_sync: tsleep returns %d\n", ret)); 615 return -1; 616 } 617 } else 618 break; 619 } 620 return 0; 621 } 622 623 /* called externally, handle locking */ 624 int 625 chn_poll(struct pcm_channel *c, int ev, struct thread *td) 626 { 627 struct snd_dbuf *bs = c->bufsoft; 628 int ret; 629 630 CHN_LOCKASSERT(c); 631 if (!(c->flags & CHN_F_MAPPED) && !(c->flags & CHN_F_TRIGGERED)) 632 chn_start(c, 1); 633 ret = 0; 634 if (chn_polltrigger(c) && chn_pollreset(c)) 635 ret = ev; 636 else 637 selrecord(td, sndbuf_getsel(bs)); 638 return ret; 639 } 640 641 /* 642 * chn_abort terminates a running dma transfer. it may sleep up to 200ms. 643 * it returns the number of bytes that have not been transferred. 644 * 645 * called from: dsp_close, dsp_ioctl, with channel locked 646 */ 647 int 648 chn_abort(struct pcm_channel *c) 649 { 650 int missing = 0; 651 struct snd_dbuf *b = c->bufhard; 652 struct snd_dbuf *bs = c->bufsoft; 653 654 CHN_LOCKASSERT(c); 655 if (!(c->flags & CHN_F_TRIGGERED)) 656 return 0; 657 c->flags |= CHN_F_ABORTING; 658 659 c->flags &= ~CHN_F_TRIGGERED; 660 /* kill the channel */ 661 chn_trigger(c, PCMTRIG_ABORT); 662 sndbuf_setrun(b, 0); 663 if (!(c->flags & CHN_F_VIRTUAL)) 664 chn_dmaupdate(c); 665 missing = sndbuf_getready(bs) + sndbuf_getready(b); 666 667 c->flags &= ~CHN_F_ABORTING; 668 return missing; 669 } 670 671 /* 672 * this routine tries to flush the dma transfer. It is called 673 * on a close of a playback channel. 674 * first, if there is data in the buffer, but the dma has not yet 675 * begun, we need to start it. 676 * next, we wait for the play buffer to drain 677 * finally, we stop the dma. 678 * 679 * called from: dsp_close, not valid for record channels. 680 */ 681 682 int 683 chn_flush(struct pcm_channel *c) 684 { 685 int ret, count, resid, resid_p; 686 struct snd_dbuf *b = c->bufhard; 687 struct snd_dbuf *bs = c->bufsoft; 688 689 CHN_LOCKASSERT(c); 690 KASSERT(c->direction == PCMDIR_PLAY, ("chn_flush on bad channel")); 691 DEB(printf("chn_flush: c->flags 0x%08x\n", c->flags)); 692 693 /* if we haven't yet started and nothing is buffered, else start*/ 694 if (!(c->flags & CHN_F_TRIGGERED)) { 695 if (sndbuf_getready(bs) > 0) { 696 ret = chn_start(c, 1); 697 if (ret) 698 return ret; 699 } else { 700 return 0; 701 } 702 } 703 704 c->flags |= CHN_F_CLOSING; 705 resid = sndbuf_getready(bs) + sndbuf_getready(b); 706 resid_p = resid; 707 count = 10; 708 ret = 0; 709 while ((count > 0) && (resid > sndbuf_getsize(b)) && (ret == 0)) { 710 /* still pending output data. */ 711 ret = chn_sleep(c, "pcmflu", hz / 10); 712 if (ret == EWOULDBLOCK) 713 ret = 0; 714 if (ret == 0) { 715 resid = sndbuf_getready(bs) + sndbuf_getready(b); 716 if (resid == resid_p) 717 count--; 718 if (resid > resid_p) 719 DEB(printf("chn_flush: buffer length increasind %d -> %d\n", resid_p, resid)); 720 resid_p = resid; 721 } 722 } 723 if (count == 0) 724 DEB(printf("chn_flush: timeout, hw %d, sw %d\n", 725 sndbuf_getready(b), sndbuf_getready(bs))); 726 727 c->flags &= ~CHN_F_TRIGGERED; 728 /* kill the channel */ 729 chn_trigger(c, PCMTRIG_ABORT); 730 sndbuf_setrun(b, 0); 731 732 c->flags &= ~CHN_F_CLOSING; 733 return 0; 734 } 735 736 int 737 fmtvalid(u_int32_t fmt, u_int32_t *fmtlist) 738 { 739 int i; 740 741 for (i = 0; fmtlist[i]; i++) 742 if (fmt == fmtlist[i]) 743 return 1; 744 return 0; 745 } 746 747 int 748 chn_reset(struct pcm_channel *c, u_int32_t fmt) 749 { 750 int hwspd, r; 751 752 CHN_LOCKASSERT(c); 753 c->flags &= CHN_F_RESET; 754 c->interrupts = 0; 755 c->xruns = 0; 756 757 r = CHANNEL_RESET(c->methods, c->devinfo); 758 if (fmt != 0) { 759 #if 0 760 hwspd = DSP_DEFAULT_SPEED; 761 /* only do this on a record channel until feederbuilder works */ 762 if (c->direction == PCMDIR_REC) 763 RANGE(hwspd, chn_getcaps(c)->minspeed, chn_getcaps(c)->maxspeed); 764 c->speed = hwspd; 765 #endif 766 hwspd = chn_getcaps(c)->minspeed; 767 c->speed = hwspd; 768 769 if (r == 0) 770 r = chn_setformat(c, fmt); 771 if (r == 0) 772 r = chn_setspeed(c, hwspd); 773 #if 0 774 if (r == 0) 775 r = chn_setvolume(c, 100, 100); 776 #endif 777 } 778 if (r == 0) 779 r = chn_setblocksize(c, 0, 0); 780 if (r == 0) { 781 chn_resetbuf(c); 782 r = CHANNEL_RESETDONE(c->methods, c->devinfo); 783 } 784 return r; 785 } 786 787 int 788 chn_init(struct pcm_channel *c, void *devinfo, int dir, int direction) 789 { 790 struct feeder_class *fc; 791 struct snd_dbuf *b, *bs; 792 int ret; 793 794 chn_lockinit(c, dir); 795 796 b = NULL; 797 bs = NULL; 798 c->devinfo = NULL; 799 c->feeder = NULL; 800 801 ret = ENOMEM; 802 b = sndbuf_create(c->dev, c->name, "primary", c); 803 if (b == NULL) 804 goto out; 805 bs = sndbuf_create(c->dev, c->name, "secondary", c); 806 if (bs == NULL) 807 goto out; 808 809 CHN_LOCK(c); 810 811 ret = EINVAL; 812 fc = feeder_getclass(NULL); 813 if (fc == NULL) 814 goto out; 815 if (chn_addfeeder(c, fc, NULL)) 816 goto out; 817 818 /* 819 * XXX - sndbuf_setup() & sndbuf_resize() expect to be called 820 * with the channel unlocked because they are also called 821 * from driver methods that don't know about locking 822 */ 823 CHN_UNLOCK(c); 824 sndbuf_setup(bs, NULL, 0); 825 CHN_LOCK(c); 826 c->bufhard = b; 827 c->bufsoft = bs; 828 c->flags = 0; 829 c->feederflags = 0; 830 831 ret = ENODEV; 832 CHN_UNLOCK(c); /* XXX - Unlock for CHANNEL_INIT() malloc() call */ 833 c->devinfo = CHANNEL_INIT(c->methods, devinfo, b, c, direction); 834 CHN_LOCK(c); 835 if (c->devinfo == NULL) 836 goto out; 837 838 ret = ENOMEM; 839 if ((sndbuf_getsize(b) == 0) && ((c->flags & CHN_F_VIRTUAL) == 0)) 840 goto out; 841 842 ret = chn_setdir(c, direction); 843 if (ret) 844 goto out; 845 846 ret = sndbuf_setfmt(b, AFMT_U8); 847 if (ret) 848 goto out; 849 850 ret = sndbuf_setfmt(bs, AFMT_U8); 851 if (ret) 852 goto out; 853 854 855 out: 856 CHN_UNLOCK(c); 857 if (ret) { 858 if (c->devinfo) { 859 if (CHANNEL_FREE(c->methods, c->devinfo)) 860 sndbuf_free(b); 861 } 862 if (bs) 863 sndbuf_destroy(bs); 864 if (b) 865 sndbuf_destroy(b); 866 c->flags |= CHN_F_DEAD; 867 chn_lockdestroy(c); 868 869 return ret; 870 } 871 872 return 0; 873 } 874 875 int 876 chn_kill(struct pcm_channel *c) 877 { 878 struct snd_dbuf *b = c->bufhard; 879 struct snd_dbuf *bs = c->bufsoft; 880 881 if (c->flags & CHN_F_TRIGGERED) 882 chn_trigger(c, PCMTRIG_ABORT); 883 while (chn_removefeeder(c) == 0); 884 if (CHANNEL_FREE(c->methods, c->devinfo)) 885 sndbuf_free(b); 886 c->flags |= CHN_F_DEAD; 887 sndbuf_destroy(bs); 888 sndbuf_destroy(b); 889 chn_lockdestroy(c); 890 return 0; 891 } 892 893 int 894 chn_setdir(struct pcm_channel *c, int dir) 895 { 896 #ifdef DEV_ISA 897 struct snd_dbuf *b = c->bufhard; 898 #endif 899 int r; 900 901 CHN_LOCKASSERT(c); 902 c->direction = dir; 903 r = CHANNEL_SETDIR(c->methods, c->devinfo, c->direction); 904 #ifdef DEV_ISA 905 if (!r && SND_DMA(b)) 906 sndbuf_dmasetdir(b, c->direction); 907 #endif 908 return r; 909 } 910 911 int 912 chn_setvolume(struct pcm_channel *c, int left, int right) 913 { 914 CHN_LOCKASSERT(c); 915 /* should add a feeder for volume changing if channel returns -1 */ 916 if (left > 100) 917 left = 100; 918 if (left < 0) 919 left = 0; 920 if (right > 100) 921 right = 100; 922 if (right < 0) 923 right = 0; 924 c->volume = left | (right << 8); 925 return 0; 926 } 927 928 static int 929 chn_tryspeed(struct pcm_channel *c, int speed) 930 { 931 struct pcm_feeder *f; 932 struct snd_dbuf *b = c->bufhard; 933 struct snd_dbuf *bs = c->bufsoft; 934 struct snd_dbuf *x; 935 int r, delta; 936 937 CHN_LOCKASSERT(c); 938 DEB(printf("setspeed, channel %s\n", c->name)); 939 DEB(printf("want speed %d, ", speed)); 940 if (speed <= 0) 941 return EINVAL; 942 if (CANCHANGE(c)) { 943 r = 0; 944 c->speed = speed; 945 sndbuf_setspd(bs, speed); 946 RANGE(speed, chn_getcaps(c)->minspeed, chn_getcaps(c)->maxspeed); 947 DEB(printf("try speed %d, ", speed)); 948 sndbuf_setspd(b, CHANNEL_SETSPEED(c->methods, c->devinfo, speed)); 949 DEB(printf("got speed %d\n", sndbuf_getspd(b))); 950 951 delta = sndbuf_getspd(b) - sndbuf_getspd(bs); 952 if (delta < 0) 953 delta = -delta; 954 955 c->feederflags &= ~(1 << FEEDER_RATE); 956 /* 957 * Used to be 500. It was too big! 958 */ 959 if (delta > 25) 960 c->feederflags |= 1 << FEEDER_RATE; 961 else 962 sndbuf_setspd(bs, sndbuf_getspd(b)); 963 964 r = chn_buildfeeder(c); 965 DEB(printf("r = %d\n", r)); 966 if (r) 967 goto out; 968 969 r = chn_setblocksize(c, 0, 0); 970 if (r) 971 goto out; 972 973 if (!(c->feederflags & (1 << FEEDER_RATE))) 974 goto out; 975 976 r = EINVAL; 977 f = chn_findfeeder(c, FEEDER_RATE); 978 DEB(printf("feedrate = %p\n", f)); 979 if (f == NULL) 980 goto out; 981 982 x = (c->direction == PCMDIR_REC)? b : bs; 983 r = FEEDER_SET(f, FEEDRATE_SRC, sndbuf_getspd(x)); 984 DEB(printf("feeder_set(FEEDRATE_SRC, %d) = %d\n", sndbuf_getspd(x), r)); 985 if (r) 986 goto out; 987 988 x = (c->direction == PCMDIR_REC)? bs : b; 989 r = FEEDER_SET(f, FEEDRATE_DST, sndbuf_getspd(x)); 990 DEB(printf("feeder_set(FEEDRATE_DST, %d) = %d\n", sndbuf_getspd(x), r)); 991 out: 992 if (!r) 993 r = CHANNEL_SETFORMAT(c->methods, c->devinfo, 994 sndbuf_getfmt(b)); 995 if (!r) 996 sndbuf_setfmt(bs, c->format); 997 DEB(printf("setspeed done, r = %d\n", r)); 998 return r; 999 } else 1000 return EINVAL; 1001 } 1002 1003 int 1004 chn_setspeed(struct pcm_channel *c, int speed) 1005 { 1006 int r, oldspeed = c->speed; 1007 1008 r = chn_tryspeed(c, speed); 1009 if (r) { 1010 DEB(printf("Failed to set speed %d falling back to %d\n", speed, oldspeed)); 1011 r = chn_tryspeed(c, oldspeed); 1012 } 1013 return r; 1014 } 1015 1016 static int 1017 chn_tryformat(struct pcm_channel *c, u_int32_t fmt) 1018 { 1019 struct snd_dbuf *b = c->bufhard; 1020 struct snd_dbuf *bs = c->bufsoft; 1021 int r; 1022 1023 CHN_LOCKASSERT(c); 1024 if (CANCHANGE(c)) { 1025 DEB(printf("want format %d\n", fmt)); 1026 c->format = fmt; 1027 r = chn_buildfeeder(c); 1028 if (r == 0) { 1029 sndbuf_setfmt(bs, c->format); 1030 chn_resetbuf(c); 1031 r = CHANNEL_SETFORMAT(c->methods, c->devinfo, sndbuf_getfmt(b)); 1032 if (r == 0) 1033 r = chn_tryspeed(c, c->speed); 1034 } 1035 return r; 1036 } else 1037 return EINVAL; 1038 } 1039 1040 int 1041 chn_setformat(struct pcm_channel *c, u_int32_t fmt) 1042 { 1043 u_int32_t oldfmt = c->format; 1044 int r; 1045 1046 r = chn_tryformat(c, fmt); 1047 if (r) { 1048 DEB(printf("Format change %d failed, reverting to %d\n", fmt, oldfmt)); 1049 chn_tryformat(c, oldfmt); 1050 } 1051 return r; 1052 } 1053 1054 /* 1055 * given a bufsz value, round it to a power of 2 in the min-max range 1056 * XXX only works if min and max are powers of 2 1057 */ 1058 static int 1059 round_bufsz(int bufsz, int min, int max) 1060 { 1061 int tmp = min * 2; 1062 1063 KASSERT((min & (min-1)) == 0, ("min %d must be power of 2\n", min)); 1064 KASSERT((max & (max-1)) == 0, ("max %d must be power of 2\n", max)); 1065 while (tmp <= bufsz) 1066 tmp <<= 1; 1067 tmp >>= 1; 1068 if (tmp > max) 1069 tmp = max; 1070 return tmp; 1071 } 1072 1073 /* 1074 * set the channel's blocksize both for soft and hard buffers. 1075 * 1076 * blksz should be a power of 2 between 2**4 and 2**16 -- it is useful 1077 * that it has the same value for both bufsoft and bufhard. 1078 * blksz == -1 computes values according to a target irq rate. 1079 * blksz == 0 reuses previous values if available, otherwise 1080 * behaves as for -1 1081 * 1082 * blkcnt is set by the user, between 2 and (2**17)/blksz for bufsoft, 1083 * but should be a power of 2 for bufhard to simplify life to low 1084 * level drivers. 1085 * Note, for the rec channel a large blkcnt is ok, 1086 * but for the play channel we want blksz as small as possible to keep 1087 * the delay small, because routines in the write path always try to 1088 * keep bufhard full. 1089 * 1090 * Unless we have good reason to, use the values suggested by the caller. 1091 */ 1092 int 1093 chn_setblocksize(struct pcm_channel *c, int blkcnt, int blksz) 1094 { 1095 struct snd_dbuf *b = c->bufhard; 1096 struct snd_dbuf *bs = c->bufsoft; 1097 int irqhz, ret, maxsz, maxsize, reqblksz; 1098 1099 CHN_LOCKASSERT(c); 1100 if (!CANCHANGE(c) || (c->flags & CHN_F_MAPPED)) { 1101 KASSERT(sndbuf_getsize(bs) == 0 || 1102 sndbuf_getsize(bs) >= sndbuf_getsize(b), 1103 ("%s(%s): bufsoft size %d < bufhard size %d", __func__, 1104 c->name, sndbuf_getsize(bs), sndbuf_getsize(b))); 1105 return EINVAL; 1106 } 1107 c->flags |= CHN_F_SETBLOCKSIZE; 1108 1109 ret = 0; 1110 DEB(printf("%s(%d, %d)\n", __func__, blkcnt, blksz)); 1111 if (blksz == 0 || blksz == -1) { /* let the driver choose values */ 1112 if (blksz == -1) /* delete previous values */ 1113 c->flags &= ~CHN_F_HAS_SIZE; 1114 if (!(c->flags & CHN_F_HAS_SIZE)) { /* no previous value */ 1115 /* 1116 * compute a base blksz according to the target irq 1117 * rate, then round to a suitable power of 2 1118 * in the range 16.. 2^17/2. 1119 * Finally compute a suitable blkcnt. 1120 */ 1121 blksz = round_bufsz( (sndbuf_getbps(bs) * 1122 sndbuf_getspd(bs)) / chn_targetirqrate, 1123 16, CHN_2NDBUFMAXSIZE / 2); 1124 blkcnt = CHN_2NDBUFMAXSIZE / blksz; 1125 } else { /* use previously defined value */ 1126 blkcnt = sndbuf_getblkcnt(bs); 1127 blksz = sndbuf_getblksz(bs); 1128 } 1129 } else { 1130 /* 1131 * use supplied values if reasonable. Note that here we 1132 * might have blksz which is not a power of 2 if the 1133 * ioctl() to compute it allows such values. 1134 */ 1135 ret = EINVAL; 1136 if ((blksz < 16) || (blkcnt < 2) || (blkcnt * blksz > CHN_2NDBUFMAXSIZE)) 1137 goto out; 1138 ret = 0; 1139 c->flags |= CHN_F_HAS_SIZE; 1140 } 1141 1142 reqblksz = blksz; 1143 if (reqblksz < sndbuf_getbps(bs)) 1144 reqblksz = sndbuf_getbps(bs); 1145 if (reqblksz % sndbuf_getbps(bs)) 1146 reqblksz -= reqblksz % sndbuf_getbps(bs); 1147 1148 /* adjust for different hw format/speed */ 1149 /* 1150 * Now compute the approx irq rate for the given (soft) blksz, 1151 * reduce to the acceptable range and compute a corresponding blksz 1152 * for the hard buffer. Then set the channel's blocksize and 1153 * corresponding hardbuf value. The number of blocks used should 1154 * be set by the device-specific routine. In fact, even the 1155 * call to sndbuf_setblksz() should not be here! XXX 1156 */ 1157 1158 irqhz = (sndbuf_getbps(bs) * sndbuf_getspd(bs)) / blksz; 1159 RANGE(irqhz, 16, 512); 1160 1161 maxsz = sndbuf_getmaxsize(b); 1162 if (maxsz == 0) /* virtual channels don't appear to allocate bufhard */ 1163 maxsz = CHN_2NDBUFMAXSIZE; 1164 blksz = round_bufsz( (sndbuf_getbps(b) * sndbuf_getspd(b)) / irqhz, 1165 16, maxsz / 2); 1166 1167 /* Increase the size of bufsoft if before increasing bufhard. */ 1168 maxsize = sndbuf_getsize(b); 1169 if (sndbuf_getsize(bs) > maxsize) 1170 maxsize = sndbuf_getsize(bs); 1171 if (reqblksz * blkcnt > maxsize) 1172 maxsize = reqblksz * blkcnt; 1173 if (sndbuf_getsize(bs) != maxsize || sndbuf_getblksz(bs) != reqblksz) { 1174 ret = sndbuf_remalloc(bs, maxsize/reqblksz, reqblksz); 1175 if (ret) 1176 goto out1; 1177 } 1178 1179 CHN_UNLOCK(c); 1180 sndbuf_setblksz(b, CHANNEL_SETBLOCKSIZE(c->methods, c->devinfo, blksz)); 1181 CHN_LOCK(c); 1182 1183 /* Decrease the size of bufsoft after decreasing bufhard. */ 1184 maxsize = sndbuf_getsize(b); 1185 if (reqblksz * blkcnt > maxsize) 1186 maxsize = reqblksz * blkcnt; 1187 if (maxsize > sndbuf_getsize(bs)) 1188 printf("Danger! %s bufsoft size increasing from %d to %d after CHANNEL_SETBLOCKSIZE()\n", 1189 c->name, sndbuf_getsize(bs), maxsize); 1190 if (sndbuf_getsize(bs) != maxsize || sndbuf_getblksz(bs) != reqblksz) { 1191 ret = sndbuf_remalloc(bs, maxsize/reqblksz, reqblksz); 1192 if (ret) 1193 goto out1; 1194 } 1195 1196 chn_resetbuf(c); 1197 out1: 1198 KASSERT(sndbuf_getsize(bs) == 0 || 1199 sndbuf_getsize(bs) >= sndbuf_getsize(b), 1200 ("%s(%s): bufsoft size %d < bufhard size %d, reqblksz=%d blksz=%d maxsize=%d blkcnt=%d", 1201 __func__, c->name, sndbuf_getsize(bs), sndbuf_getsize(b), reqblksz, 1202 blksz, maxsize, blkcnt)); 1203 out: 1204 c->flags &= ~CHN_F_SETBLOCKSIZE; 1205 #if 0 1206 if (1) { 1207 static uint32_t kk = 0; 1208 printf("%u: b %d/%d/%d : (%d)%d/0x%0x | bs %d/%d/%d : (%d)%d/0x%0x\n", ++kk, 1209 sndbuf_getsize(b), sndbuf_getblksz(b), sndbuf_getblkcnt(b), 1210 sndbuf_getbps(b), 1211 sndbuf_getspd(b), sndbuf_getfmt(b), 1212 sndbuf_getsize(bs), sndbuf_getblksz(bs), sndbuf_getblkcnt(bs), 1213 sndbuf_getbps(bs), 1214 sndbuf_getspd(bs), sndbuf_getfmt(bs)); 1215 if (sndbuf_getsize(b) % sndbuf_getbps(b) || 1216 sndbuf_getblksz(b) % sndbuf_getbps(b) || 1217 sndbuf_getsize(bs) % sndbuf_getbps(bs) || 1218 sndbuf_getblksz(b) % sndbuf_getbps(b)) { 1219 printf("%u: bps/blksz alignment screwed!\n", kk); 1220 } 1221 } 1222 #endif 1223 return ret; 1224 } 1225 1226 int 1227 chn_trigger(struct pcm_channel *c, int go) 1228 { 1229 #ifdef DEV_ISA 1230 struct snd_dbuf *b = c->bufhard; 1231 #endif 1232 int ret; 1233 1234 CHN_LOCKASSERT(c); 1235 #ifdef DEV_ISA 1236 if (SND_DMA(b) && (go == PCMTRIG_EMLDMAWR || go == PCMTRIG_EMLDMARD)) 1237 sndbuf_dmabounce(b); 1238 #endif 1239 ret = CHANNEL_TRIGGER(c->methods, c->devinfo, go); 1240 1241 return ret; 1242 } 1243 1244 int 1245 chn_getptr(struct pcm_channel *c) 1246 { 1247 int hwptr; 1248 int a = (1 << c->align) - 1; 1249 1250 CHN_LOCKASSERT(c); 1251 hwptr = (c->flags & CHN_F_TRIGGERED)? CHANNEL_GETPTR(c->methods, c->devinfo) : 0; 1252 /* don't allow unaligned values in the hwa ptr */ 1253 #if 1 1254 hwptr &= ~a ; /* Apply channel align mask */ 1255 #endif 1256 hwptr &= DMA_ALIGN_MASK; /* Apply DMA align mask */ 1257 return hwptr; 1258 } 1259 1260 struct pcmchan_caps * 1261 chn_getcaps(struct pcm_channel *c) 1262 { 1263 CHN_LOCKASSERT(c); 1264 return CHANNEL_GETCAPS(c->methods, c->devinfo); 1265 } 1266 1267 u_int32_t 1268 chn_getformats(struct pcm_channel *c) 1269 { 1270 u_int32_t *fmtlist, fmts; 1271 int i; 1272 1273 fmtlist = chn_getcaps(c)->fmtlist; 1274 fmts = 0; 1275 for (i = 0; fmtlist[i]; i++) 1276 fmts |= fmtlist[i]; 1277 1278 /* report software-supported formats */ 1279 if (report_soft_formats) 1280 fmts |= AFMT_MU_LAW|AFMT_A_LAW|AFMT_U32_LE|AFMT_U32_BE| 1281 AFMT_S32_LE|AFMT_S32_BE|AFMT_U24_LE|AFMT_U24_BE| 1282 AFMT_S24_LE|AFMT_S24_BE|AFMT_U16_LE|AFMT_U16_BE| 1283 AFMT_S16_LE|AFMT_S16_BE|AFMT_U8|AFMT_S8; 1284 1285 return fmts; 1286 } 1287 1288 static int 1289 chn_buildfeeder(struct pcm_channel *c) 1290 { 1291 struct feeder_class *fc; 1292 struct pcm_feederdesc desc; 1293 u_int32_t tmp[2], type, flags, hwfmt, *fmtlist; 1294 int err; 1295 1296 CHN_LOCKASSERT(c); 1297 while (chn_removefeeder(c) == 0); 1298 KASSERT((c->feeder == NULL), ("feeder chain not empty")); 1299 1300 c->align = sndbuf_getalign(c->bufsoft); 1301 1302 if (SLIST_EMPTY(&c->children)) { 1303 fc = feeder_getclass(NULL); 1304 KASSERT(fc != NULL, ("can't find root feeder")); 1305 1306 err = chn_addfeeder(c, fc, NULL); 1307 if (err) { 1308 DEB(printf("can't add root feeder, err %d\n", err)); 1309 1310 return err; 1311 } 1312 c->feeder->desc->out = c->format; 1313 } else { 1314 if (c->flags & CHN_F_HAS_VCHAN) { 1315 desc.type = FEEDER_MIXER; 1316 desc.in = 0; 1317 } else { 1318 DEB(printf("can't decide which feeder type to use!\n")); 1319 return EOPNOTSUPP; 1320 } 1321 desc.out = c->format; 1322 desc.flags = 0; 1323 fc = feeder_getclass(&desc); 1324 if (fc == NULL) { 1325 DEB(printf("can't find vchan feeder\n")); 1326 1327 return EOPNOTSUPP; 1328 } 1329 1330 err = chn_addfeeder(c, fc, &desc); 1331 if (err) { 1332 DEB(printf("can't add vchan feeder, err %d\n", err)); 1333 1334 return err; 1335 } 1336 } 1337 c->feederflags &= ~(1 << FEEDER_VOLUME); 1338 if (c->direction == PCMDIR_PLAY && 1339 !(c->flags & CHN_F_VIRTUAL) && 1340 c->parentsnddev && (c->parentsnddev->flags & SD_F_SOFTVOL) && 1341 c->parentsnddev->mixer_dev) 1342 c->feederflags |= 1 << FEEDER_VOLUME; 1343 flags = c->feederflags; 1344 fmtlist = chn_getcaps(c)->fmtlist; 1345 1346 DEB(printf("feederflags %x\n", flags)); 1347 1348 for (type = FEEDER_RATE; type <= FEEDER_LAST; type++) { 1349 if (flags & (1 << type)) { 1350 desc.type = type; 1351 desc.in = 0; 1352 desc.out = 0; 1353 desc.flags = 0; 1354 DEB(printf("find feeder type %d, ", type)); 1355 fc = feeder_getclass(&desc); 1356 DEB(printf("got %p\n", fc)); 1357 if (fc == NULL) { 1358 DEB(printf("can't find required feeder type %d\n", type)); 1359 1360 return EOPNOTSUPP; 1361 } 1362 1363 if ((type == FEEDER_RATE && 1364 !fmtvalid(fc->desc->in, fmtlist)) 1365 || c->feeder->desc->out != fc->desc->in) { 1366 DEB(printf("build fmtchain from 0x%x to 0x%x: ", c->feeder->desc->out, fc->desc->in)); 1367 tmp[0] = fc->desc->in; 1368 tmp[1] = 0; 1369 if (chn_fmtchain(c, tmp) == 0) { 1370 DEB(printf("failed\n")); 1371 1372 return ENODEV; 1373 } 1374 DEB(printf("ok\n")); 1375 } 1376 1377 err = chn_addfeeder(c, fc, fc->desc); 1378 if (err) { 1379 DEB(printf("can't add feeder %p, output 0x%x, err %d\n", fc, fc->desc->out, err)); 1380 1381 return err; 1382 } 1383 DEB(printf("added feeder %p, output 0x%x\n", fc, c->feeder->desc->out)); 1384 } 1385 } 1386 1387 if (fmtvalid(c->feeder->desc->out, fmtlist) 1388 && !(c->direction == PCMDIR_REC && 1389 c->format != c->feeder->desc->out)) 1390 hwfmt = c->feeder->desc->out; 1391 else { 1392 if (c->direction == PCMDIR_REC) { 1393 tmp[0] = c->format; 1394 tmp[1] = 0; 1395 hwfmt = chn_fmtchain(c, tmp); 1396 } else 1397 hwfmt = chn_fmtchain(c, fmtlist); 1398 } 1399 1400 if (hwfmt == 0 || !fmtvalid(hwfmt, fmtlist)) { 1401 DEB(printf("Invalid hardware format: 0x%x\n", hwfmt)); 1402 return ENODEV; 1403 } 1404 1405 sndbuf_setfmt(c->bufhard, hwfmt); 1406 1407 if ((flags & (1 << FEEDER_VOLUME))) { 1408 int vol = 100 | (100 << 8); 1409 1410 CHN_UNLOCK(c); 1411 /* 1412 * XXX This is ugly! The way mixer subs being so secretive 1413 * about its own internals force us to use this silly 1414 * monkey trick. 1415 */ 1416 if (mixer_ioctl(c->parentsnddev->mixer_dev, 1417 MIXER_READ(SOUND_MIXER_PCM), (caddr_t)&vol, -1, NULL) != 0) 1418 device_printf(c->dev, "Soft Volume: Failed to read default value\n"); 1419 CHN_LOCK(c); 1420 chn_setvolume(c, vol & 0x7f, (vol >> 8) & 0x7f); 1421 } 1422 1423 return 0; 1424 } 1425 1426 int 1427 chn_notify(struct pcm_channel *c, u_int32_t flags) 1428 { 1429 struct pcmchan_children *pce; 1430 struct pcm_channel *child; 1431 int run; 1432 1433 CHN_LOCK(c); 1434 1435 if (SLIST_EMPTY(&c->children)) { 1436 CHN_UNLOCK(c); 1437 return ENODEV; 1438 } 1439 1440 run = (c->flags & CHN_F_TRIGGERED)? 1 : 0; 1441 /* 1442 * if the hwchan is running, we can't change its rate, format or 1443 * blocksize 1444 */ 1445 if (run) 1446 flags &= CHN_N_VOLUME | CHN_N_TRIGGER; 1447 1448 if (flags & CHN_N_RATE) { 1449 /* 1450 * we could do something here, like scan children and decide on 1451 * the most appropriate rate to mix at, but we don't for now 1452 */ 1453 } 1454 if (flags & CHN_N_FORMAT) { 1455 /* 1456 * we could do something here, like scan children and decide on 1457 * the most appropriate mixer feeder to use, but we don't for now 1458 */ 1459 } 1460 if (flags & CHN_N_VOLUME) { 1461 /* 1462 * we could do something here but we don't for now 1463 */ 1464 } 1465 if (flags & CHN_N_BLOCKSIZE) { 1466 int blksz; 1467 /* 1468 * scan the children, find the lowest blocksize and use that 1469 * for the hard blocksize 1470 */ 1471 blksz = sndbuf_getmaxsize(c->bufhard) / 2; 1472 SLIST_FOREACH(pce, &c->children, link) { 1473 child = pce->channel; 1474 CHN_LOCK(child); 1475 if (sndbuf_getblksz(child->bufhard) < blksz) 1476 blksz = sndbuf_getblksz(child->bufhard); 1477 CHN_UNLOCK(child); 1478 } 1479 chn_setblocksize(c, 2, blksz); 1480 } 1481 if (flags & CHN_N_TRIGGER) { 1482 int nrun; 1483 /* 1484 * scan the children, and figure out if any are running 1485 * if so, we need to be running, otherwise we need to be stopped 1486 * if we aren't in our target sstate, move to it 1487 */ 1488 nrun = 0; 1489 SLIST_FOREACH(pce, &c->children, link) { 1490 child = pce->channel; 1491 CHN_LOCK(child); 1492 if (child->flags & CHN_F_TRIGGERED) 1493 nrun = 1; 1494 CHN_UNLOCK(child); 1495 } 1496 if (nrun && !run) 1497 chn_start(c, 1); 1498 if (!nrun && run) 1499 chn_abort(c); 1500 } 1501 CHN_UNLOCK(c); 1502 return 0; 1503 } 1504 1505 void 1506 chn_lock(struct pcm_channel *c) 1507 { 1508 CHN_LOCK(c); 1509 } 1510 1511 void 1512 chn_unlock(struct pcm_channel *c) 1513 { 1514 CHN_UNLOCK(c); 1515 } 1516