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