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