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