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 * XXX 147 * 148 * We would call KNOTE() here, but as we 149 * are in interrupt context, we'd have to 150 * acquire the MP lock before. 151 * Instead, we'll queue a task in a software 152 * interrupt, which will run with the MP lock 153 * held. 154 * 155 * buffer.c:sndbuf_seltask will then call 156 * KNOTE() from safer context. 157 */ 158 taskqueue_enqueue(taskqueue_swi, &bs->seltask); 159 } 160 } else { 161 SLIST_FOREACH(pce, &c->children, link) { 162 CHN_LOCK(pce->channel); 163 chn_wakeup(pce->channel); 164 CHN_UNLOCK(pce->channel); 165 } 166 } 167 168 wakeup(bs); 169 } 170 171 static int 172 chn_sleep(struct pcm_channel *c, char *str, int timeout) 173 { 174 struct snd_dbuf *bs = c->bufsoft; 175 int ret; 176 177 CHN_LOCKASSERT(c); 178 #ifdef USING_MUTEX 179 ret = snd_mtxsleep(bs, c->lock, PCATCH, str, timeout); 180 #else 181 ret = tsleep(bs, PRIBIO | PCATCH, str, timeout); 182 #endif 183 184 return ret; 185 } 186 187 /* 188 * chn_dmaupdate() tracks the status of a dma transfer, 189 * updating pointers. 190 */ 191 192 static unsigned int 193 chn_dmaupdate(struct pcm_channel *c) 194 { 195 struct snd_dbuf *b = c->bufhard; 196 unsigned int delta, old, hwptr, amt; 197 198 KASSERT(sndbuf_getsize(b) > 0, ("bufsize == 0")); 199 CHN_LOCKASSERT(c); 200 201 old = sndbuf_gethwptr(b); 202 hwptr = chn_getptr(c); 203 delta = (sndbuf_getsize(b) + hwptr - old) % sndbuf_getsize(b); 204 sndbuf_sethwptr(b, hwptr); 205 206 DEB( 207 if (delta >= ((sndbuf_getsize(b) * 15) / 16)) { 208 if (!(c->flags & (CHN_F_CLOSING | CHN_F_ABORTING))) 209 device_printf(c->dev, "hwptr went backwards %d -> %d\n", old, hwptr); 210 } 211 ); 212 213 if (c->direction == PCMDIR_PLAY) { 214 amt = MIN(delta, sndbuf_getready(b)); 215 if (amt > 0) 216 sndbuf_dispose(b, NULL, amt); 217 } else { 218 amt = MIN(delta, sndbuf_getfree(b)); 219 if (amt > 0) 220 sndbuf_acquire(b, NULL, amt); 221 } 222 223 return delta; 224 } 225 226 void 227 chn_wrupdate(struct pcm_channel *c) 228 { 229 int ret; 230 231 CHN_LOCKASSERT(c); 232 KASSERT(c->direction == PCMDIR_PLAY, ("chn_wrupdate on bad channel")); 233 234 if ((c->flags & (CHN_F_MAPPED | CHN_F_VIRTUAL)) || !(c->flags & CHN_F_TRIGGERED)) 235 return; 236 chn_dmaupdate(c); 237 ret = chn_wrfeed(c); 238 /* tell the driver we've updated the primary buffer */ 239 chn_trigger(c, PCMTRIG_EMLDMAWR); 240 DEB(if (ret) 241 kprintf("chn_wrupdate: chn_wrfeed returned %d\n", ret);) 242 243 } 244 245 int 246 chn_wrfeed(struct pcm_channel *c) 247 { 248 struct snd_dbuf *b = c->bufhard; 249 struct snd_dbuf *bs = c->bufsoft; 250 unsigned int ret, amt; 251 252 CHN_LOCKASSERT(c); 253 #if 0 254 DEB( 255 if (c->flags & CHN_F_CLOSING) { 256 sndbuf_dump(b, "b", 0x02); 257 sndbuf_dump(bs, "bs", 0x02); 258 }) 259 #endif 260 261 if (c->flags & CHN_F_MAPPED) 262 sndbuf_acquire(bs, NULL, sndbuf_getfree(bs)); 263 264 amt = sndbuf_getfree(b); 265 KASSERT(amt <= sndbuf_getsize(bs), 266 ("%s(%s): amt %d > source size %d, flags 0x%x", __func__, c->name, 267 amt, sndbuf_getsize(bs), c->flags)); 268 269 ret = (amt > 0) ? sndbuf_feed(bs, b, c, c->feeder, amt) : ENOSPC; 270 /* 271 * Possible xruns. There should be no empty space left in buffer. 272 */ 273 if (sndbuf_getfree(b) > 0) 274 c->xruns++; 275 276 if (ret == 0 && sndbuf_getfree(b) < amt) 277 chn_wakeup(c); 278 279 return ret; 280 } 281 282 static void 283 chn_wrintr(struct pcm_channel *c) 284 { 285 int ret; 286 287 CHN_LOCKASSERT(c); 288 /* update pointers in primary buffer */ 289 chn_dmaupdate(c); 290 /* ...and feed from secondary to primary */ 291 ret = chn_wrfeed(c); 292 /* tell the driver we've updated the primary buffer */ 293 chn_trigger(c, PCMTRIG_EMLDMAWR); 294 DEB(if (ret) 295 kprintf("chn_wrintr: chn_wrfeed returned %d\n", ret);) 296 } 297 298 /* 299 * user write routine - uiomove data into secondary buffer, trigger if necessary 300 * if blocking, sleep, rinse and repeat. 301 * 302 * called externally, so must handle locking 303 */ 304 305 int 306 chn_write(struct pcm_channel *c, struct uio *buf, int ioflags) 307 { 308 int ret, timeout, newsize, count, sz; 309 int nbio; 310 struct snd_dbuf *bs = c->bufsoft; 311 void *off; 312 int t, x,togo,p; 313 314 CHN_LOCKASSERT(c); 315 /* 316 * XXX Certain applications attempt to write larger size 317 * of pcm data than c->blocksize2nd without blocking, 318 * resulting partial write. Expand the block size so that 319 * the write operation avoids blocking. 320 */ 321 nbio = (c->flags & CHN_F_NBIO) || (ioflags & IO_NDELAY); 322 if (nbio && buf->uio_resid > (size_t)sndbuf_getblksz(bs)) { 323 DEB(device_printf(c->dev, "broken app, nbio and tried to write %ld bytes with fragsz %d\n", 324 buf->uio_resid, sndbuf_getblksz(bs))); 325 newsize = 16; 326 while (newsize < (int)szmin(buf->uio_resid, CHN_2NDBUFMAXSIZE / 2)) 327 newsize <<= 1; 328 chn_setblocksize(c, sndbuf_getblkcnt(bs), newsize); 329 DEB(device_printf(c->dev, "frags reset to %d x %d\n", sndbuf_getblkcnt(bs), sndbuf_getblksz(bs))); 330 } 331 332 ret = 0; 333 count = hz; 334 while (!ret && (buf->uio_resid > 0) && (count > 0)) { 335 sz = sndbuf_getfree(bs); 336 if (sz == 0) { 337 if (nbio) 338 ret = EWOULDBLOCK; 339 else { 340 timeout = (hz * sndbuf_getblksz(bs)) / (sndbuf_getspd(bs) * sndbuf_getbps(bs)); 341 if (timeout < 1) 342 timeout = 1; 343 timeout = 1; 344 ret = chn_sleep(c, "pcmwr", timeout); 345 if (ret == EWOULDBLOCK) { 346 count -= timeout; 347 ret = 0; 348 } else if (ret == 0) 349 count = hz; 350 } 351 } else { 352 sz = (int)szmin(sz, buf->uio_resid); 353 KASSERT(sz > 0, ("confusion in chn_write")); 354 /* kprintf("sz: %d\n", sz); */ 355 356 /* 357 * The following assumes that the free space in 358 * the buffer can never be less around the 359 * unlock-uiomove-lock sequence. 360 */ 361 togo = sz; 362 while (ret == 0 && togo> 0) { 363 p = sndbuf_getfreeptr(bs); 364 t = MIN(togo, sndbuf_getsize(bs) - p); 365 off = sndbuf_getbufofs(bs, p); 366 CHN_UNLOCK(c); 367 ret = uiomove(off, t, buf); 368 CHN_LOCK(c); 369 togo -= t; 370 x = sndbuf_acquire(bs, NULL, t); 371 } 372 ret = 0; 373 if (ret == 0 && !(c->flags & CHN_F_TRIGGERED)) 374 chn_start(c, 0); 375 } 376 } 377 /* kprintf("ret: %d left: %d\n", ret, buf->uio_resid); */ 378 379 if (count <= 0) { 380 c->flags |= CHN_F_DEAD; 381 kprintf("%s: play interrupt timeout, channel dead\n", c->name); 382 } 383 384 return ret; 385 } 386 387 #if 0 388 static int 389 chn_rddump(struct pcm_channel *c, unsigned int cnt) 390 { 391 struct snd_dbuf *b = c->bufhard; 392 393 CHN_LOCKASSERT(c); 394 #if 0 395 static uint32_t kk = 0; 396 printf("%u: dumping %d bytes\n", ++kk, cnt); 397 #endif 398 c->xruns++; 399 sndbuf_setxrun(b, sndbuf_getxrun(b) + cnt); 400 return sndbuf_dispose(b, NULL, cnt); 401 } 402 #endif 403 404 /* 405 * Feed new data from the read buffer. Can be called in the bottom half. 406 */ 407 int 408 chn_rdfeed(struct pcm_channel *c) 409 { 410 struct snd_dbuf *b = c->bufhard; 411 struct snd_dbuf *bs = c->bufsoft; 412 unsigned int ret, amt; 413 414 CHN_LOCKASSERT(c); 415 DEB( 416 if (c->flags & CHN_F_CLOSING) { 417 sndbuf_dump(b, "b", 0x02); 418 sndbuf_dump(bs, "bs", 0x02); 419 }) 420 421 #if 0 422 amt = sndbuf_getready(b); 423 if (sndbuf_getfree(bs) < amt) { 424 c->xruns++; 425 amt = sndbuf_getfree(bs); 426 } 427 #endif 428 amt = sndbuf_getfree(bs); 429 ret = (amt > 0)? sndbuf_feed(b, bs, c, c->feeder, amt) : 0; 430 431 amt = sndbuf_getready(b); 432 if (amt > 0) { 433 c->xruns++; 434 sndbuf_dispose(b, NULL, amt); 435 } 436 437 chn_wakeup(c); 438 439 return ret; 440 } 441 442 void 443 chn_rdupdate(struct pcm_channel *c) 444 { 445 int ret; 446 447 CHN_LOCKASSERT(c); 448 KASSERT(c->direction == PCMDIR_REC, ("chn_rdupdate on bad channel")); 449 450 if ((c->flags & CHN_F_MAPPED) || !(c->flags & CHN_F_TRIGGERED)) 451 return; 452 chn_trigger(c, PCMTRIG_EMLDMARD); 453 chn_dmaupdate(c); 454 ret = chn_rdfeed(c); 455 DEB(if (ret) 456 kprintf("chn_rdfeed: %d\n", ret);) 457 } 458 459 /* read interrupt routine. Must be called with interrupts blocked. */ 460 static void 461 chn_rdintr(struct pcm_channel *c) 462 { 463 int ret; 464 465 CHN_LOCKASSERT(c); 466 /* tell the driver to update the primary buffer if non-dma */ 467 chn_trigger(c, PCMTRIG_EMLDMARD); 468 /* update pointers in primary buffer */ 469 chn_dmaupdate(c); 470 /* ...and feed from primary to secondary */ 471 ret = chn_rdfeed(c); 472 } 473 474 /* 475 * user read routine - trigger if necessary, uiomove data from secondary buffer 476 * if blocking, sleep, rinse and repeat. 477 * 478 * called externally, so must handle locking 479 */ 480 481 int 482 chn_read(struct pcm_channel *c, struct uio *buf, int ioflags) 483 { 484 int ret, timeout, sz, count; 485 int nbio; 486 struct snd_dbuf *bs = c->bufsoft; 487 void *off; 488 int t, x,togo,p; 489 490 CHN_LOCKASSERT(c); 491 nbio = (c->flags & CHN_F_NBIO) || (ioflags & IO_NDELAY); 492 if (!(c->flags & CHN_F_TRIGGERED)) 493 chn_start(c, 0); 494 495 ret = 0; 496 count = hz; 497 while (!ret && (buf->uio_resid > 0) && (count > 0)) { 498 sz = (int)szmin(buf->uio_resid, sndbuf_getready(bs)); 499 500 if (sz > 0) { 501 /* 502 * The following assumes that the free space in 503 * the buffer can never be less around the 504 * unlock-uiomove-lock sequence. 505 */ 506 togo = sz; 507 while (ret == 0 && togo> 0) { 508 p = sndbuf_getreadyptr(bs); 509 t = MIN(togo, sndbuf_getsize(bs) - p); 510 off = sndbuf_getbufofs(bs, p); 511 CHN_UNLOCK(c); 512 ret = uiomove(off, t, buf); 513 CHN_LOCK(c); 514 togo -= t; 515 x = sndbuf_dispose(bs, NULL, t); 516 } 517 ret = 0; 518 } else { 519 if (nbio) { 520 ret = EWOULDBLOCK; 521 } else { 522 timeout = (hz * sndbuf_getblksz(bs)) / (sndbuf_getspd(bs) * sndbuf_getbps(bs)); 523 if (timeout < 1) 524 timeout = 1; 525 ret = chn_sleep(c, "pcmrd", timeout); 526 if (ret == EWOULDBLOCK) { 527 count -= timeout; 528 ret = 0; 529 } else { 530 count = hz; 531 } 532 533 } 534 } 535 } 536 537 if (count <= 0) { 538 c->flags |= CHN_F_DEAD; 539 kprintf("%s: record interrupt timeout, channel dead\n", c->name); 540 } 541 542 return ret; 543 } 544 545 void 546 chn_intr(struct pcm_channel *c) 547 { 548 CHN_LOCK(c); 549 c->interrupts++; 550 if (c->direction == PCMDIR_PLAY) 551 chn_wrintr(c); 552 else 553 chn_rdintr(c); 554 CHN_UNLOCK(c); 555 } 556 557 u_int32_t 558 chn_start(struct pcm_channel *c, int force) 559 { 560 u_int32_t i, j; 561 struct snd_dbuf *b = c->bufhard; 562 struct snd_dbuf *bs = c->bufsoft; 563 564 CHN_LOCKASSERT(c); 565 /* if we're running, or if we're prevented from triggering, bail */ 566 if ((c->flags & CHN_F_TRIGGERED) || ((c->flags & CHN_F_NOTRIGGER) && !force)) 567 return EINVAL; 568 569 i = (c->direction == PCMDIR_PLAY)? sndbuf_getready(bs) : sndbuf_getfree(bs); 570 j = (c->direction == PCMDIR_PLAY)? sndbuf_getfree(b) : sndbuf_getready(b); 571 if (force || (i >= j)) { 572 c->flags |= CHN_F_TRIGGERED; 573 /* 574 * if we're starting because a vchan started, don't feed any data 575 * or it becomes impossible to start vchans synchronised with the 576 * first one. the hardbuf should be empty so we top it up with 577 * silence to give it something to chew. the real data will be 578 * fed at the first irq. 579 */ 580 if (c->direction == PCMDIR_PLAY) { 581 /* 582 * Reduce pops during playback startup. 583 */ 584 sndbuf_fillsilence(b); 585 if (SLIST_EMPTY(&c->children)) 586 chn_wrfeed(c); 587 } 588 sndbuf_setrun(b, 1); 589 c->xruns = 0; 590 chn_trigger(c, PCMTRIG_START); 591 return 0; 592 } 593 594 return 0; 595 } 596 597 void 598 chn_resetbuf(struct pcm_channel *c) 599 { 600 struct snd_dbuf *b = c->bufhard; 601 struct snd_dbuf *bs = c->bufsoft; 602 603 c->blocks = 0; 604 sndbuf_reset(b); 605 sndbuf_reset(bs); 606 } 607 608 /* 609 * chn_sync waits until the space in the given channel goes above 610 * a threshold. The threshold is checked against fl or rl respectively. 611 * Assume that the condition can become true, do not check here... 612 */ 613 int 614 chn_sync(struct pcm_channel *c, int threshold) 615 { 616 u_long rdy; 617 int ret; 618 struct snd_dbuf *bs = c->bufsoft; 619 620 CHN_LOCKASSERT(c); 621 622 /* if we haven't yet started and nothing is buffered, else start*/ 623 if (!(c->flags & CHN_F_TRIGGERED)) { 624 if (sndbuf_getready(bs) > 0) { 625 ret = chn_start(c, 1); 626 if (ret) 627 return ret; 628 } else { 629 return 0; 630 } 631 } 632 633 for (;;) { 634 rdy = (c->direction == PCMDIR_PLAY)? sndbuf_getfree(bs) : sndbuf_getready(bs); 635 if (rdy <= threshold) { 636 ret = chn_sleep(c, "pcmsyn", 1); 637 if (ret == ERESTART || ret == EINTR) { 638 DEB(kprintf("chn_sync: tsleep returns %d\n", ret)); 639 return -1; 640 } 641 } else 642 break; 643 } 644 return 0; 645 } 646 647 /* called externally, handle locking */ 648 int 649 chn_poll(struct pcm_channel *c, int ev, struct thread *td) 650 { 651 struct snd_dbuf *bs = c->bufsoft; 652 int ret; 653 654 CHN_LOCKASSERT(c); 655 if (!(c->flags & CHN_F_MAPPED) && !(c->flags & CHN_F_TRIGGERED)) 656 chn_start(c, 1); 657 ret = 0; 658 if (chn_polltrigger(c) && chn_pollreset(c)) 659 ret = ev; 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