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 (SLIST_FIRST(&sndbuf_getkq(bs)->ki_note) && 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_kqtask will then call 156 * KNOTE() from safer context. 157 */ 158 taskqueue_enqueue(taskqueue_swi, &bs->kqtask); 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 int ret; 652 653 CHN_LOCKASSERT(c); 654 if (!(c->flags & CHN_F_MAPPED) && !(c->flags & CHN_F_TRIGGERED)) 655 chn_start(c, 1); 656 ret = 0; 657 if (chn_polltrigger(c) && chn_pollreset(c)) 658 ret = ev; 659 return ret; 660 } 661 662 /* 663 * chn_abort terminates a running dma transfer. it may sleep up to 200ms. 664 * it returns the number of bytes that have not been transferred. 665 * 666 * called from: dsp_close, dsp_ioctl, with channel locked 667 */ 668 int 669 chn_abort(struct pcm_channel *c) 670 { 671 int missing = 0; 672 struct snd_dbuf *b = c->bufhard; 673 struct snd_dbuf *bs = c->bufsoft; 674 675 CHN_LOCKASSERT(c); 676 if (!(c->flags & CHN_F_TRIGGERED)) 677 return 0; 678 c->flags |= CHN_F_ABORTING; 679 680 c->flags &= ~CHN_F_TRIGGERED; 681 /* kill the channel */ 682 chn_trigger(c, PCMTRIG_ABORT); 683 sndbuf_setrun(b, 0); 684 if (!(c->flags & CHN_F_VIRTUAL)) 685 chn_dmaupdate(c); 686 missing = sndbuf_getready(bs) + sndbuf_getready(b); 687 688 c->flags &= ~CHN_F_ABORTING; 689 return missing; 690 } 691 692 /* 693 * this routine tries to flush the dma transfer. It is called 694 * on a close of a playback channel. 695 * first, if there is data in the buffer, but the dma has not yet 696 * begun, we need to start it. 697 * next, we wait for the play buffer to drain 698 * finally, we stop the dma. 699 * 700 * called from: dsp_close, not valid for record channels. 701 */ 702 703 int 704 chn_flush(struct pcm_channel *c) 705 { 706 int ret, count, resid, resid_p; 707 struct snd_dbuf *b = c->bufhard; 708 struct snd_dbuf *bs = c->bufsoft; 709 710 CHN_LOCKASSERT(c); 711 KASSERT(c->direction == PCMDIR_PLAY, ("chn_flush on bad channel")); 712 DEB(kprintf("chn_flush: c->flags 0x%08x\n", c->flags)); 713 714 /* if we haven't yet started and nothing is buffered, else start*/ 715 if (!(c->flags & CHN_F_TRIGGERED)) { 716 if (sndbuf_getready(bs) > 0) { 717 ret = chn_start(c, 1); 718 if (ret) 719 return ret; 720 } else { 721 return 0; 722 } 723 } 724 725 c->flags |= CHN_F_CLOSING; 726 resid = sndbuf_getready(bs) + sndbuf_getready(b); 727 resid_p = resid; 728 count = 10; 729 ret = 0; 730 while ((count > 0) && (resid > sndbuf_getsize(b)) && (ret == 0)) { 731 /* still pending output data. */ 732 ret = chn_sleep(c, "pcmflu", hz / 10); 733 if (ret == EWOULDBLOCK) 734 ret = 0; 735 if (ret == 0) { 736 resid = sndbuf_getready(bs) + sndbuf_getready(b); 737 if (resid == resid_p) 738 count--; 739 if (resid > resid_p) 740 DEB(printf("chn_flush: buffer length increasind %d -> %d\n", resid_p, resid)); 741 resid_p = resid; 742 } 743 } 744 if (count == 0) 745 DEB(kprintf("chn_flush: timeout, hw %d, sw %d\n", 746 sndbuf_getready(b), sndbuf_getready(bs))); 747 748 c->flags &= ~CHN_F_TRIGGERED; 749 /* kill the channel */ 750 chn_trigger(c, PCMTRIG_ABORT); 751 sndbuf_setrun(b, 0); 752 753 c->flags &= ~CHN_F_CLOSING; 754 return 0; 755 } 756 757 int 758 fmtvalid(u_int32_t fmt, u_int32_t *fmtlist) 759 { 760 int i; 761 762 for (i = 0; fmtlist[i]; i++) 763 if (fmt == fmtlist[i]) 764 return 1; 765 return 0; 766 } 767 768 int 769 chn_reset(struct pcm_channel *c, u_int32_t fmt) 770 { 771 int hwspd, r; 772 773 CHN_LOCKASSERT(c); 774 c->flags &= CHN_F_RESET; 775 c->interrupts = 0; 776 c->xruns = 0; 777 778 r = CHANNEL_RESET(c->methods, c->devinfo); 779 if (fmt != 0) { 780 #if 0 781 hwspd = DSP_DEFAULT_SPEED; 782 /* only do this on a record channel until feederbuilder works */ 783 if (c->direction == PCMDIR_REC) 784 RANGE(hwspd, chn_getcaps(c)->minspeed, chn_getcaps(c)->maxspeed); 785 c->speed = hwspd; 786 #endif 787 hwspd = chn_getcaps(c)->minspeed; 788 c->speed = hwspd; 789 790 if (r == 0) 791 r = chn_setformat(c, fmt); 792 if (r == 0) 793 r = chn_setspeed(c, hwspd); 794 #if 0 795 if (r == 0) 796 r = chn_setvolume(c, 100, 100); 797 #endif 798 } 799 if (r == 0) 800 r = chn_setblocksize(c, 0, 0); 801 if (r == 0) { 802 chn_resetbuf(c); 803 r = CHANNEL_RESETDONE(c->methods, c->devinfo); 804 } 805 return r; 806 } 807 808 int 809 chn_init(struct pcm_channel *c, void *devinfo, int dir, int direction) 810 { 811 struct feeder_class *fc; 812 struct snd_dbuf *b, *bs; 813 int ret; 814 815 chn_lockinit(c, dir); 816 817 b = NULL; 818 bs = NULL; 819 c->devinfo = NULL; 820 c->feeder = NULL; 821 822 ret = ENOMEM; 823 b = sndbuf_create(c->dev, c->name, "primary", c); 824 if (b == NULL) 825 goto out; 826 bs = sndbuf_create(c->dev, c->name, "secondary", c); 827 if (bs == NULL) 828 goto out; 829 830 CHN_LOCK(c); 831 832 ret = EINVAL; 833 fc = feeder_getclass(NULL); 834 if (fc == NULL) 835 goto out; 836 if (chn_addfeeder(c, fc, NULL)) 837 goto out; 838 839 /* 840 * XXX - sndbuf_setup() & sndbuf_resize() expect to be called 841 * with the channel unlocked because they are also called 842 * from driver methods that don't know about locking 843 */ 844 CHN_UNLOCK(c); 845 sndbuf_setup(bs, NULL, 0); 846 CHN_LOCK(c); 847 c->bufhard = b; 848 c->bufsoft = bs; 849 c->flags = 0; 850 c->feederflags = 0; 851 852 ret = ENODEV; 853 CHN_UNLOCK(c); /* XXX - Unlock for CHANNEL_INIT() kmalloc() call */ 854 c->devinfo = CHANNEL_INIT(c->methods, devinfo, b, c, direction); 855 CHN_LOCK(c); 856 if (c->devinfo == NULL) 857 goto out; 858 859 ret = ENOMEM; 860 if ((sndbuf_getsize(b) == 0) && ((c->flags & CHN_F_VIRTUAL) == 0)) 861 goto out; 862 863 ret = chn_setdir(c, direction); 864 if (ret) 865 goto out; 866 867 ret = sndbuf_setfmt(b, AFMT_U8); 868 if (ret) 869 goto out; 870 871 ret = sndbuf_setfmt(bs, AFMT_U8); 872 if (ret) 873 goto out; 874 875 ret = chn_setvolume(c, 100, 100); 876 if (ret) 877 goto out; 878 879 880 out: 881 CHN_UNLOCK(c); 882 if (ret) { 883 if (c->devinfo) { 884 if (CHANNEL_FREE(c->methods, c->devinfo)) 885 sndbuf_free(b); 886 } 887 if (bs) 888 sndbuf_destroy(bs); 889 if (b) 890 sndbuf_destroy(b); 891 c->flags |= CHN_F_DEAD; 892 chn_lockdestroy(c); 893 894 return ret; 895 } 896 897 return 0; 898 } 899 900 int 901 chn_kill(struct pcm_channel *c) 902 { 903 struct snd_dbuf *b = c->bufhard; 904 struct snd_dbuf *bs = c->bufsoft; 905 906 if (c->flags & CHN_F_TRIGGERED) 907 chn_trigger(c, PCMTRIG_ABORT); 908 while (chn_removefeeder(c) == 0); 909 if (CHANNEL_FREE(c->methods, c->devinfo)) 910 sndbuf_free(b); 911 c->flags |= CHN_F_DEAD; 912 sndbuf_destroy(bs); 913 sndbuf_destroy(b); 914 chn_lockdestroy(c); 915 return 0; 916 } 917 918 int 919 chn_setdir(struct pcm_channel *c, int dir) 920 { 921 #if NISA > 0 922 struct snd_dbuf *b = c->bufhard; 923 #endif 924 int r; 925 926 CHN_LOCKASSERT(c); 927 c->direction = dir; 928 r = CHANNEL_SETDIR(c->methods, c->devinfo, c->direction); 929 #if NISA > 0 930 if (!r && SND_DMA(b)) 931 sndbuf_dmasetdir(b, c->direction); 932 #endif 933 return r; 934 } 935 936 int 937 chn_setvolume(struct pcm_channel *c, int left, int right) 938 { 939 CHN_LOCKASSERT(c); 940 /* should add a feeder for volume changing if channel returns -1 */ 941 if (left > 100) 942 left = 100; 943 if (left < 0) 944 left = 0; 945 if (right > 100) 946 right = 100; 947 if (right < 0) 948 right = 0; 949 c->volume = left | (right << 8); 950 return 0; 951 } 952 953 static int 954 chn_tryspeed(struct pcm_channel *c, int speed) 955 { 956 struct pcm_feeder *f; 957 struct snd_dbuf *b = c->bufhard; 958 struct snd_dbuf *bs = c->bufsoft; 959 struct snd_dbuf *x; 960 int r, delta; 961 962 CHN_LOCKASSERT(c); 963 DEB(kprintf("setspeed, channel %s\n", c->name)); 964 DEB(kprintf("want speed %d, ", speed)); 965 if (speed <= 0) 966 return EINVAL; 967 if (CANCHANGE(c)) { 968 r = 0; 969 c->speed = speed; 970 sndbuf_setspd(bs, speed); 971 RANGE(speed, chn_getcaps(c)->minspeed, chn_getcaps(c)->maxspeed); 972 DEB(kprintf("try speed %d, ", speed)); 973 sndbuf_setspd(b, CHANNEL_SETSPEED(c->methods, c->devinfo, speed)); 974 DEB(kprintf("got speed %d\n", sndbuf_getspd(b))); 975 976 delta = sndbuf_getspd(b) - sndbuf_getspd(bs); 977 if (delta < 0) 978 delta = -delta; 979 980 c->feederflags &= ~(1 << FEEDER_RATE); 981 /* 982 * Used to be 500. It was too big! 983 */ 984 if (delta > 25) 985 c->feederflags |= 1 << FEEDER_RATE; 986 else 987 sndbuf_setspd(bs, sndbuf_getspd(b)); 988 989 r = chn_buildfeeder(c); 990 DEB(kprintf("r = %d\n", r)); 991 if (r) 992 goto out; 993 994 r = chn_setblocksize(c, 0, 0); 995 if (r) 996 goto out; 997 998 if (!(c->feederflags & (1 << FEEDER_RATE))) 999 goto out; 1000 1001 r = EINVAL; 1002 f = chn_findfeeder(c, FEEDER_RATE); 1003 DEB(kprintf("feedrate = %p\n", f)); 1004 if (f == NULL) 1005 goto out; 1006 1007 x = (c->direction == PCMDIR_REC)? b : bs; 1008 r = FEEDER_SET(f, FEEDRATE_SRC, sndbuf_getspd(x)); 1009 DEB(kprintf("feeder_set(FEEDRATE_SRC, %d) = %d\n", sndbuf_getspd(x), r)); 1010 if (r) 1011 goto out; 1012 1013 x = (c->direction == PCMDIR_REC)? bs : b; 1014 r = FEEDER_SET(f, FEEDRATE_DST, sndbuf_getspd(x)); 1015 DEB(kprintf("feeder_set(FEEDRATE_DST, %d) = %d\n", sndbuf_getspd(x), r)); 1016 out: 1017 if (!r) 1018 r = CHANNEL_SETFORMAT(c->methods, c->devinfo, 1019 sndbuf_getfmt(b)); 1020 if (!r) 1021 sndbuf_setfmt(bs, c->format); 1022 DEB(kprintf("setspeed done, r = %d\n", r)); 1023 return r; 1024 } else 1025 return EINVAL; 1026 } 1027 1028 int 1029 chn_setspeed(struct pcm_channel *c, int speed) 1030 { 1031 int r, oldspeed = c->speed; 1032 1033 r = chn_tryspeed(c, speed); 1034 if (r) { 1035 DEB(kprintf("Failed to set speed %d falling back to %d\n", speed, oldspeed)); 1036 r = chn_tryspeed(c, oldspeed); 1037 } 1038 return r; 1039 } 1040 1041 static int 1042 chn_tryformat(struct pcm_channel *c, u_int32_t fmt) 1043 { 1044 struct snd_dbuf *b = c->bufhard; 1045 struct snd_dbuf *bs = c->bufsoft; 1046 int r; 1047 1048 CHN_LOCKASSERT(c); 1049 if (CANCHANGE(c)) { 1050 DEB(kprintf("want format %d\n", fmt)); 1051 c->format = fmt; 1052 r = chn_buildfeeder(c); 1053 if (r == 0) { 1054 sndbuf_setfmt(bs, c->format); 1055 chn_resetbuf(c); 1056 r = CHANNEL_SETFORMAT(c->methods, c->devinfo, sndbuf_getfmt(b)); 1057 if (r == 0) 1058 r = chn_tryspeed(c, c->speed); 1059 } 1060 return r; 1061 } else 1062 return EINVAL; 1063 } 1064 1065 int 1066 chn_setformat(struct pcm_channel *c, u_int32_t fmt) 1067 { 1068 u_int32_t oldfmt = c->format; 1069 int r; 1070 1071 r = chn_tryformat(c, fmt); 1072 if (r) { 1073 DEB(kprintf("Format change %d failed, reverting to %d\n", fmt, oldfmt)); 1074 chn_tryformat(c, oldfmt); 1075 } 1076 return r; 1077 } 1078 1079 /* 1080 * given a bufsz value, round it to a power of 2 in the min-max range 1081 * XXX only works if min and max are powers of 2 1082 */ 1083 static int 1084 round_bufsz(int bufsz, int min, int max) 1085 { 1086 int tmp = min * 2; 1087 1088 KASSERT((min & (min-1)) == 0, ("min %d must be power of 2\n", min)); 1089 KASSERT((max & (max-1)) == 0, ("max %d must be power of 2\n", max)); 1090 while (tmp <= bufsz) 1091 tmp <<= 1; 1092 tmp >>= 1; 1093 if (tmp > max) 1094 tmp = max; 1095 return tmp; 1096 } 1097 1098 /* 1099 * set the channel's blocksize both for soft and hard buffers. 1100 * 1101 * blksz should be a power of 2 between 2**4 and 2**16 -- it is useful 1102 * that it has the same value for both bufsoft and bufhard. 1103 * blksz == -1 computes values according to a target irq rate. 1104 * blksz == 0 reuses previous values if available, otherwise 1105 * behaves as for -1 1106 * 1107 * blkcnt is set by the user, between 2 and (2**17)/blksz for bufsoft, 1108 * but should be a power of 2 for bufhard to simplify life to low 1109 * level drivers. 1110 * Note, for the rec channel a large blkcnt is ok, 1111 * but for the play channel we want blksz as small as possible to keep 1112 * the delay small, because routines in the write path always try to 1113 * keep bufhard full. 1114 * 1115 * Unless we have good reason to, use the values suggested by the caller. 1116 */ 1117 int 1118 chn_setblocksize(struct pcm_channel *c, int blkcnt, int blksz) 1119 { 1120 struct snd_dbuf *b = c->bufhard; 1121 struct snd_dbuf *bs = c->bufsoft; 1122 int irqhz, ret, maxsz, maxsize, reqblksz; 1123 1124 CHN_LOCKASSERT(c); 1125 if (!CANCHANGE(c) || (c->flags & CHN_F_MAPPED)) { 1126 KASSERT(sndbuf_getsize(bs) == 0 || 1127 sndbuf_getsize(bs) >= sndbuf_getsize(b), 1128 ("%s(%s): bufsoft size %d < bufhard size %d", __func__, 1129 c->name, sndbuf_getsize(bs), sndbuf_getsize(b))); 1130 return EINVAL; 1131 } 1132 c->flags |= CHN_F_SETBLOCKSIZE; 1133 1134 ret = 0; 1135 DEB(kprintf("%s(%d, %d)\n", __func__, blkcnt, blksz)); 1136 if (blksz == 0 || blksz == -1) { /* let the driver choose values */ 1137 if (blksz == -1) /* delete previous values */ 1138 c->flags &= ~CHN_F_HAS_SIZE; 1139 if (!(c->flags & CHN_F_HAS_SIZE)) { /* no previous value */ 1140 /* 1141 * compute a base blksz according to the target irq 1142 * rate, then round to a suitable power of 2 1143 * in the range 16.. 2^17/2. 1144 * Finally compute a suitable blkcnt. 1145 */ 1146 blksz = round_bufsz( (sndbuf_getbps(bs) * 1147 sndbuf_getspd(bs)) / chn_targetirqrate, 1148 16, CHN_2NDBUFMAXSIZE / 2); 1149 blkcnt = CHN_2NDBUFMAXSIZE / blksz; 1150 } else { /* use previously defined value */ 1151 blkcnt = sndbuf_getblkcnt(bs); 1152 blksz = sndbuf_getblksz(bs); 1153 } 1154 } else { 1155 /* 1156 * use supplied values if reasonable. Note that here we 1157 * might have blksz which is not a power of 2 if the 1158 * ioctl() to compute it allows such values. 1159 */ 1160 ret = EINVAL; 1161 if ((blksz < 16) || (blkcnt < 2) || (blkcnt * blksz > CHN_2NDBUFMAXSIZE)) 1162 goto out; 1163 ret = 0; 1164 c->flags |= CHN_F_HAS_SIZE; 1165 } 1166 1167 reqblksz = blksz; 1168 if (reqblksz < sndbuf_getbps(bs)) 1169 reqblksz = sndbuf_getbps(bs); 1170 if (reqblksz % sndbuf_getbps(bs)) 1171 reqblksz -= reqblksz % sndbuf_getbps(bs); 1172 1173 /* adjust for different hw format/speed */ 1174 /* 1175 * Now compute the approx irq rate for the given (soft) blksz, 1176 * reduce to the acceptable range and compute a corresponding blksz 1177 * for the hard buffer. Then set the channel's blocksize and 1178 * corresponding hardbuf value. The number of blocks used should 1179 * be set by the device-specific routine. In fact, even the 1180 * call to sndbuf_setblksz() should not be here! XXX 1181 */ 1182 1183 irqhz = (sndbuf_getbps(bs) * sndbuf_getspd(bs)) / blksz; 1184 RANGE(irqhz, 16, 512); 1185 1186 maxsz = sndbuf_getmaxsize(b); 1187 if (maxsz == 0) /* virtual channels don't appear to allocate bufhard */ 1188 maxsz = CHN_2NDBUFMAXSIZE; 1189 blksz = round_bufsz( (sndbuf_getbps(b) * sndbuf_getspd(b)) / irqhz, 1190 16, maxsz / 2); 1191 1192 /* Increase the size of bufsoft if before increasing bufhard. */ 1193 maxsize = sndbuf_getsize(b); 1194 if (sndbuf_getsize(bs) > maxsize) 1195 maxsize = sndbuf_getsize(bs); 1196 if (reqblksz * blkcnt > maxsize) 1197 maxsize = reqblksz * blkcnt; 1198 if (sndbuf_getsize(bs) != maxsize || sndbuf_getblksz(bs) != reqblksz) { 1199 ret = sndbuf_remalloc(bs, maxsize/reqblksz, reqblksz); 1200 if (ret) 1201 goto out1; 1202 } 1203 1204 CHN_UNLOCK(c); 1205 sndbuf_setblksz(b, CHANNEL_SETBLOCKSIZE(c->methods, c->devinfo, blksz)); 1206 CHN_LOCK(c); 1207 1208 /* Decrease the size of bufsoft after decreasing bufhard. */ 1209 maxsize = sndbuf_getsize(b); 1210 if (reqblksz * blkcnt > maxsize) 1211 maxsize = reqblksz * blkcnt; 1212 if (maxsize > sndbuf_getsize(bs)) 1213 kprintf("Danger! %s bufsoft size increasing from %d to %d after CHANNEL_SETBLOCKSIZE()\n", 1214 c->name, sndbuf_getsize(bs), maxsize); 1215 if (sndbuf_getsize(bs) != maxsize || sndbuf_getblksz(bs) != reqblksz) { 1216 ret = sndbuf_remalloc(bs, maxsize/reqblksz, reqblksz); 1217 if (ret) 1218 goto out1; 1219 } 1220 1221 chn_resetbuf(c); 1222 out1: 1223 KASSERT(sndbuf_getsize(bs) == 0 || 1224 sndbuf_getsize(bs) >= sndbuf_getsize(b), 1225 ("%s(%s): bufsoft size %d < bufhard size %d, reqblksz=%d blksz=%d maxsize=%d blkcnt=%d", 1226 __func__, c->name, sndbuf_getsize(bs), sndbuf_getsize(b), reqblksz, 1227 blksz, maxsize, blkcnt)); 1228 out: 1229 c->flags &= ~CHN_F_SETBLOCKSIZE; 1230 #if 0 1231 if (1) { 1232 static uint32_t kk = 0; 1233 printf("%u: b %d/%d/%d : (%d)%d/0x%0x | bs %d/%d/%d : (%d)%d/0x%0x\n", ++kk, 1234 sndbuf_getsize(b), sndbuf_getblksz(b), sndbuf_getblkcnt(b), 1235 sndbuf_getbps(b), 1236 sndbuf_getspd(b), sndbuf_getfmt(b), 1237 sndbuf_getsize(bs), sndbuf_getblksz(bs), sndbuf_getblkcnt(bs), 1238 sndbuf_getbps(bs), 1239 sndbuf_getspd(bs), sndbuf_getfmt(bs)); 1240 if (sndbuf_getsize(b) % sndbuf_getbps(b) || 1241 sndbuf_getblksz(b) % sndbuf_getbps(b) || 1242 sndbuf_getsize(bs) % sndbuf_getbps(bs) || 1243 sndbuf_getblksz(b) % sndbuf_getbps(b)) { 1244 printf("%u: bps/blksz alignment screwed!\n", kk); 1245 } 1246 } 1247 #endif 1248 return ret; 1249 } 1250 1251 int 1252 chn_trigger(struct pcm_channel *c, int go) 1253 { 1254 #if NISA > 0 1255 struct snd_dbuf *b = c->bufhard; 1256 #endif 1257 int ret; 1258 1259 CHN_LOCKASSERT(c); 1260 #if NISA > 0 1261 if (SND_DMA(b) && (go == PCMTRIG_EMLDMAWR || go == PCMTRIG_EMLDMARD)) 1262 sndbuf_dmabounce(b); 1263 #endif 1264 ret = CHANNEL_TRIGGER(c->methods, c->devinfo, go); 1265 1266 return ret; 1267 } 1268 1269 int 1270 chn_getptr(struct pcm_channel *c) 1271 { 1272 #if 0 1273 int hwptr; 1274 int a = (1 << c->align) - 1; 1275 1276 CHN_LOCKASSERT(c); 1277 hwptr = (c->flags & CHN_F_TRIGGERED)? CHANNEL_GETPTR(c->methods, c->devinfo) : 0; 1278 /* don't allow unaligned values in the hwa ptr */ 1279 #if 1 1280 hwptr &= ~a ; /* Apply channel align mask */ 1281 #endif 1282 hwptr &= DMA_ALIGN_MASK; /* Apply DMA align mask */ 1283 return hwptr; 1284 #endif 1285 int hwptr; 1286 1287 CHN_LOCKASSERT(c); 1288 hwptr = (c->flags & CHN_F_TRIGGERED)? CHANNEL_GETPTR(c->methods, c->devinfo) : 0; 1289 return (hwptr - (hwptr % sndbuf_getbps(c->bufhard))); 1290 } 1291 1292 struct pcmchan_caps * 1293 chn_getcaps(struct pcm_channel *c) 1294 { 1295 CHN_LOCKASSERT(c); 1296 return CHANNEL_GETCAPS(c->methods, c->devinfo); 1297 } 1298 1299 u_int32_t 1300 chn_getformats(struct pcm_channel *c) 1301 { 1302 u_int32_t *fmtlist, fmts; 1303 int i; 1304 1305 fmtlist = chn_getcaps(c)->fmtlist; 1306 fmts = 0; 1307 for (i = 0; fmtlist[i]; i++) 1308 fmts |= fmtlist[i]; 1309 1310 /* report software-supported formats */ 1311 if (report_soft_formats) 1312 fmts |= AFMT_MU_LAW|AFMT_A_LAW|AFMT_U32_LE|AFMT_U32_BE| 1313 AFMT_S32_LE|AFMT_S32_BE|AFMT_U24_LE|AFMT_U24_BE| 1314 AFMT_S24_LE|AFMT_S24_BE|AFMT_U16_LE|AFMT_U16_BE| 1315 AFMT_S16_LE|AFMT_S16_BE|AFMT_U8|AFMT_S8; 1316 1317 return fmts; 1318 } 1319 1320 static int 1321 chn_buildfeeder(struct pcm_channel *c) 1322 { 1323 struct feeder_class *fc; 1324 struct pcm_feederdesc desc; 1325 u_int32_t tmp[2], type, flags, hwfmt, *fmtlist; 1326 int err; 1327 1328 CHN_LOCKASSERT(c); 1329 while (chn_removefeeder(c) == 0); 1330 KASSERT((c->feeder == NULL), ("feeder chain not empty")); 1331 1332 c->align = sndbuf_getalign(c->bufsoft); 1333 1334 if (SLIST_EMPTY(&c->children)) { 1335 fc = feeder_getclass(NULL); 1336 KASSERT(fc != NULL, ("can't find root feeder")); 1337 1338 err = chn_addfeeder(c, fc, NULL); 1339 if (err) { 1340 DEB(kprintf("can't add root feeder, err %d\n", err)); 1341 1342 return err; 1343 } 1344 c->feeder->desc->out = c->format; 1345 } else { 1346 if (c->flags & CHN_F_HAS_VCHAN) { 1347 desc.type = FEEDER_MIXER; 1348 desc.in = 0; 1349 } else { 1350 DEB(printf("can't decide which feeder type to use!\n")); 1351 return EOPNOTSUPP; 1352 } 1353 desc.out = c->format; 1354 desc.flags = 0; 1355 fc = feeder_getclass(&desc); 1356 if (fc == NULL) { 1357 DEB(kprintf("can't find vchan feeder\n")); 1358 1359 return EOPNOTSUPP; 1360 } 1361 1362 err = chn_addfeeder(c, fc, &desc); 1363 if (err) { 1364 DEB(kprintf("can't add vchan feeder, err %d\n", err)); 1365 1366 return err; 1367 } 1368 } 1369 c->feederflags &= ~(1 << FEEDER_VOLUME); 1370 if (c->direction == PCMDIR_PLAY && 1371 !(c->flags & CHN_F_VIRTUAL) && 1372 c->parentsnddev && (c->parentsnddev->flags & SD_F_SOFTPCMVOL) && 1373 c->parentsnddev->mixer_dev) 1374 c->feederflags |= 1 << FEEDER_VOLUME; 1375 flags = c->feederflags; 1376 fmtlist = chn_getcaps(c)->fmtlist; 1377 1378 DEB(kprintf("feederflags %x\n", flags)); 1379 1380 for (type = FEEDER_RATE; type <= FEEDER_LAST; type++) { 1381 if (flags & (1 << type)) { 1382 desc.type = type; 1383 desc.in = 0; 1384 desc.out = 0; 1385 desc.flags = 0; 1386 DEB(kprintf("find feeder type %d, ", type)); 1387 fc = feeder_getclass(&desc); 1388 DEB(kprintf("got %p\n", fc)); 1389 if (fc == NULL) { 1390 DEB(kprintf("can't find required feeder type %d\n", type)); 1391 1392 return EOPNOTSUPP; 1393 } 1394 1395 DEB(kprintf("build fmtchain from 0x%08x to 0x%08x: ", c->feeder->desc->out, fc->desc->in)); 1396 tmp[0] = fc->desc->in; 1397 tmp[1] = 0; 1398 if (chn_fmtchain(c, tmp) == 0) { 1399 DEB(printf("failed\n")); 1400 1401 return ENODEV; 1402 } 1403 DEB(printf("ok\n")); 1404 1405 err = chn_addfeeder(c, fc, fc->desc); 1406 if (err) { 1407 DEB(kprintf("can't add feeder %p, output 0x%x, err %d\n", fc, fc->desc->out, err)); 1408 1409 return err; 1410 } 1411 DEB(kprintf("added feeder %p, output 0x%x\n", fc, c->feeder->desc->out)); 1412 } 1413 } 1414 1415 if (c->direction == PCMDIR_REC) { 1416 tmp[0] = c->format; 1417 tmp[1] = 0; 1418 hwfmt = chn_fmtchain(c, tmp); 1419 } else 1420 hwfmt = chn_fmtchain(c, fmtlist); 1421 1422 if (hwfmt == 0 || !fmtvalid(hwfmt, fmtlist)) { 1423 DEB(printf("Invalid hardware format: 0x%08x\n", hwfmt)); 1424 return ENODEV; 1425 } 1426 1427 sndbuf_setfmt(c->bufhard, hwfmt); 1428 1429 if ((flags & (1 << FEEDER_VOLUME))) { 1430 struct dev_ioctl_args map; 1431 u_int32_t parent = SOUND_MIXER_NONE; 1432 int vol, left, right; 1433 1434 vol = 100 | (100 << 8); 1435 1436 CHN_UNLOCK(c); 1437 /* 1438 * XXX This is ugly! The way mixer subs being so secretive 1439 * about its own internals force us to use this silly 1440 * monkey trick. 1441 */ 1442 map.a_head.a_dev = c->parentsnddev->mixer_dev; 1443 map.a_cmd = MIXER_READ(SOUND_MIXER_PCM); 1444 map.a_data = (caddr_t)&vol; 1445 map.a_fflag = -1; 1446 map.a_cred = NULL; 1447 map.a_sysmsg = NULL; 1448 if (mixer_ioctl(&map) != 0) 1449 device_printf(c->dev, "Soft PCM Volume: Failed to read default value\n"); 1450 left = vol & 0x7f; 1451 right = (vol >> 8) & 0x7f; 1452 if (c->parentsnddev != NULL && 1453 c->parentsnddev->mixer_dev != NULL && 1454 c->parentsnddev->mixer_dev->si_drv1 != NULL) 1455 parent = mix_getparent( 1456 c->parentsnddev->mixer_dev->si_drv1, 1457 SOUND_MIXER_PCM); 1458 if (parent != SOUND_MIXER_NONE) { 1459 vol = 100 | (100 << 8); 1460 map.a_head.a_dev = c->parentsnddev->mixer_dev; 1461 map.a_cmd = MIXER_READ(parent); 1462 map.a_data = (caddr_t)&vol; 1463 map.a_fflag = -1; 1464 map.a_cred = NULL; 1465 if (mixer_ioctl(&map) != 0) 1466 device_printf(c->dev, "Soft Volume: Failed to read parent default value\n"); 1467 left = (left * (vol & 0x7f)) / 100; 1468 right = (right * ((vol >> 8) & 0x7f)) / 100; 1469 } 1470 1471 CHN_LOCK(c); 1472 chn_setvolume(c, left, right); 1473 } 1474 1475 return 0; 1476 } 1477 1478 int 1479 chn_notify(struct pcm_channel *c, u_int32_t flags) 1480 { 1481 struct pcmchan_children *pce; 1482 struct pcm_channel *child; 1483 int run; 1484 1485 CHN_LOCK(c); 1486 1487 if (SLIST_EMPTY(&c->children)) { 1488 CHN_UNLOCK(c); 1489 return ENODEV; 1490 } 1491 1492 run = (c->flags & CHN_F_TRIGGERED)? 1 : 0; 1493 /* 1494 * if the hwchan is running, we can't change its rate, format or 1495 * blocksize 1496 */ 1497 if (run) 1498 flags &= CHN_N_VOLUME | CHN_N_TRIGGER; 1499 1500 if (flags & CHN_N_RATE) { 1501 /* 1502 * we could do something here, like scan children and decide on 1503 * the most appropriate rate to mix at, but we don't for now 1504 */ 1505 } 1506 if (flags & CHN_N_FORMAT) { 1507 /* 1508 * we could do something here, like scan children and decide on 1509 * the most appropriate mixer feeder to use, but we don't for now 1510 */ 1511 } 1512 if (flags & CHN_N_VOLUME) { 1513 /* 1514 * we could do something here but we don't for now 1515 */ 1516 } 1517 if (flags & CHN_N_BLOCKSIZE) { 1518 int blksz; 1519 /* 1520 * scan the children, find the lowest blocksize and use that 1521 * for the hard blocksize 1522 */ 1523 blksz = sndbuf_getmaxsize(c->bufhard) / 2; 1524 SLIST_FOREACH(pce, &c->children, link) { 1525 child = pce->channel; 1526 CHN_LOCK(child); 1527 if (sndbuf_getblksz(child->bufhard) < blksz) 1528 blksz = sndbuf_getblksz(child->bufhard); 1529 CHN_UNLOCK(child); 1530 } 1531 chn_setblocksize(c, 2, blksz); 1532 } 1533 if (flags & CHN_N_TRIGGER) { 1534 int nrun; 1535 /* 1536 * scan the children, and figure out if any are running 1537 * if so, we need to be running, otherwise we need to be stopped 1538 * if we aren't in our target sstate, move to it 1539 */ 1540 nrun = 0; 1541 SLIST_FOREACH(pce, &c->children, link) { 1542 child = pce->channel; 1543 CHN_LOCK(child); 1544 if (child->flags & CHN_F_TRIGGERED) 1545 nrun = 1; 1546 CHN_UNLOCK(child); 1547 } 1548 if (nrun && !run) 1549 chn_start(c, 1); 1550 if (!nrun && run) 1551 chn_abort(c); 1552 } 1553 CHN_UNLOCK(c); 1554 return 0; 1555 } 1556 1557 void 1558 chn_lock(struct pcm_channel *c) 1559 { 1560 CHN_LOCK(c); 1561 } 1562 1563 void 1564 chn_unlock(struct pcm_channel *c) 1565 { 1566 CHN_UNLOCK(c); 1567 } 1568