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