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