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