1 /* 2 * Copyright (c) 1999 Cameron Grant <gandalf@vilnya.demon.co.uk> 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 28 #include <dev/sound/pcm/sound.h> 29 30 #include "feeder_if.h" 31 32 SND_DECLARE_FILE("$FreeBSD$"); 33 34 #define MIN_CHUNK_SIZE 256 /* for uiomove etc. */ 35 #define DMA_ALIGN_THRESHOLD 4 36 #define DMA_ALIGN_MASK (~(DMA_ALIGN_THRESHOLD - 1)) 37 38 #define MIN(x, y) (((x) < (y))? (x) : (y)) 39 #define CANCHANGE(c) (!(c->flags & CHN_F_TRIGGERED)) 40 41 /* 42 #define DEB(x) x 43 */ 44 45 static int chn_targetirqrate = 32; 46 TUNABLE_INT("hw.snd.targetirqrate", &chn_targetirqrate); 47 48 static int 49 sysctl_hw_snd_targetirqrate(SYSCTL_HANDLER_ARGS) 50 { 51 int err, val; 52 53 val = chn_targetirqrate; 54 err = sysctl_handle_int(oidp, &val, sizeof(val), req); 55 if (val < 16 || val > 512) 56 err = EINVAL; 57 else 58 chn_targetirqrate = val; 59 60 return err; 61 } 62 SYSCTL_PROC(_hw_snd, OID_AUTO, targetirqrate, CTLTYPE_INT | CTLFLAG_RW, 63 0, sizeof(int), sysctl_hw_snd_targetirqrate, "I", ""); 64 65 static int chn_buildfeeder(struct pcm_channel *c); 66 67 static void 68 chn_lockinit(struct pcm_channel *c) 69 { 70 c->lock = snd_mtxcreate(c->name); 71 } 72 73 static void 74 chn_lockdestroy(struct pcm_channel *c) 75 { 76 snd_mtxfree(c->lock); 77 } 78 79 static int 80 chn_polltrigger(struct pcm_channel *c) 81 { 82 struct snd_dbuf *bs = c->bufsoft; 83 unsigned amt, lim; 84 85 CHN_LOCKASSERT(c); 86 if (c->flags & CHN_F_MAPPED) { 87 if (sndbuf_getprevblocks(bs) == 0) 88 return 1; 89 else 90 return (sndbuf_getblocks(bs) > sndbuf_getprevblocks(bs))? 1 : 0; 91 } else { 92 amt = (c->direction == PCMDIR_PLAY)? sndbuf_getfree(bs) : sndbuf_getready(bs); 93 lim = (c->flags & CHN_F_HAS_SIZE)? sndbuf_getblksz(bs) : 1; 94 lim = 1; 95 return (amt >= lim)? 1 : 0; 96 } 97 return 0; 98 } 99 100 static int 101 chn_pollreset(struct pcm_channel *c) 102 { 103 struct snd_dbuf *bs = c->bufsoft; 104 105 CHN_LOCKASSERT(c); 106 sndbuf_updateprevtotal(bs); 107 return 1; 108 } 109 110 static void 111 chn_wakeup(struct pcm_channel *c) 112 { 113 struct snd_dbuf *bs = c->bufsoft; 114 115 CHN_LOCKASSERT(c); 116 if (sndbuf_getsel(bs)->si_pid && chn_polltrigger(c)) 117 selwakeup(sndbuf_getsel(bs)); 118 wakeup(bs); 119 } 120 121 static int 122 chn_sleep(struct pcm_channel *c, char *str, int timeout) 123 { 124 struct snd_dbuf *bs = c->bufsoft; 125 int ret; 126 127 CHN_LOCKASSERT(c); 128 #ifdef USING_MUTEX 129 ret = msleep(bs, c->lock, PRIBIO | PCATCH, str, timeout); 130 #else 131 ret = tsleep(bs, PRIBIO | PCATCH, str, timeout); 132 #endif 133 134 return ret; 135 } 136 137 /* 138 * chn_dmaupdate() tracks the status of a dma transfer, 139 * updating pointers. It must be called at spltty(). 140 */ 141 142 static unsigned int 143 chn_dmaupdate(struct pcm_channel *c) 144 { 145 struct snd_dbuf *b = c->bufhard; 146 unsigned int delta, old, hwptr, amt; 147 148 KASSERT(sndbuf_getsize(b) > 0, ("bufsize == 0")); 149 CHN_LOCKASSERT(c); 150 151 old = sndbuf_gethwptr(b); 152 hwptr = chn_getptr(c); 153 delta = (sndbuf_getsize(b) + hwptr - old) % sndbuf_getsize(b); 154 sndbuf_sethwptr(b, hwptr); 155 156 DEB( 157 if (delta >= ((sndbuf_getsize(b) * 15) / 16)) { 158 if (!(c->flags & (CHN_F_CLOSING | CHN_F_ABORTING))) 159 device_printf(c->parentsnddev->dev, "hwptr went backwards %d -> %d\n", old, hwptr); 160 } 161 ); 162 163 if (c->direction == PCMDIR_PLAY) { 164 amt = MIN(delta, sndbuf_getready(b)); 165 if (amt > 0) 166 sndbuf_dispose(b, NULL, amt); 167 } else { 168 amt = MIN(delta, sndbuf_getfree(b)); 169 if (amt > 0) 170 sndbuf_acquire(b, NULL, amt); 171 } 172 173 return delta; 174 } 175 176 void 177 chn_wrupdate(struct pcm_channel *c) 178 { 179 int ret; 180 181 CHN_LOCKASSERT(c); 182 KASSERT(c->direction == PCMDIR_PLAY, ("chn_wrupdate on bad channel")); 183 184 if ((c->flags & (CHN_F_MAPPED | CHN_F_VIRTUAL)) || !(c->flags & CHN_F_TRIGGERED)) 185 return; 186 chn_dmaupdate(c); 187 ret = chn_wrfeed(c); 188 /* tell the driver we've updated the primary buffer */ 189 chn_trigger(c, PCMTRIG_EMLDMAWR); 190 DEB(if (ret) 191 printf("chn_wrupdate: chn_wrfeed returned %d\n", ret);) 192 193 } 194 195 int 196 chn_wrfeed(struct pcm_channel *c) 197 { 198 struct snd_dbuf *b = c->bufhard; 199 struct snd_dbuf *bs = c->bufsoft; 200 unsigned int ret, amt; 201 202 CHN_LOCKASSERT(c); 203 DEB( 204 if (c->flags & CHN_F_CLOSING) { 205 sndbuf_dump(b, "b", 0x02); 206 sndbuf_dump(bs, "bs", 0x02); 207 }) 208 209 if (c->flags & CHN_F_MAPPED) 210 sndbuf_acquire(bs, NULL, sndbuf_getfree(bs)); 211 212 amt = sndbuf_getfree(b); 213 if (sndbuf_getready(bs) < amt) 214 c->xruns++; 215 216 ret = (amt > 0)? sndbuf_feed(bs, b, c, c->feeder, amt) : ENOSPC; 217 if (ret == 0 && sndbuf_getfree(b) < amt) 218 chn_wakeup(c); 219 220 return ret; 221 } 222 223 static void 224 chn_wrintr(struct pcm_channel *c) 225 { 226 int ret; 227 228 CHN_LOCKASSERT(c); 229 /* update pointers in primary buffer */ 230 chn_dmaupdate(c); 231 /* ...and feed from secondary to primary */ 232 ret = chn_wrfeed(c); 233 /* tell the driver we've updated the primary buffer */ 234 chn_trigger(c, PCMTRIG_EMLDMAWR); 235 DEB(if (ret) 236 printf("chn_wrintr: chn_wrfeed returned %d\n", ret);) 237 } 238 239 /* 240 * user write routine - uiomove data into secondary buffer, trigger if necessary 241 * if blocking, sleep, rinse and repeat. 242 * 243 * called externally, so must handle locking 244 */ 245 246 int 247 chn_write(struct pcm_channel *c, struct uio *buf) 248 { 249 int ret, timeout, newsize, count, sz; 250 struct snd_dbuf *bs = c->bufsoft; 251 252 CHN_LOCKASSERT(c); 253 /* 254 * XXX Certain applications attempt to write larger size 255 * of pcm data than c->blocksize2nd without blocking, 256 * resulting partial write. Expand the block size so that 257 * the write operation avoids blocking. 258 */ 259 if ((c->flags & CHN_F_NBIO) && buf->uio_resid > sndbuf_getblksz(bs)) { 260 DEB(device_printf(c->parentsnddev->dev, "broken app, nbio and tried to write %d bytes with fragsz %d\n", 261 buf->uio_resid, sndbuf_getblksz(bs))); 262 newsize = 16; 263 while (newsize < min(buf->uio_resid, CHN_2NDBUFMAXSIZE / 2)) 264 newsize <<= 1; 265 chn_setblocksize(c, sndbuf_getblkcnt(bs), newsize); 266 DEB(device_printf(c->parentsnddev->dev, "frags reset to %d x %d\n", sndbuf_getblkcnt(bs), sndbuf_getblksz(bs))); 267 } 268 269 ret = 0; 270 count = hz; 271 while (!ret && (buf->uio_resid > 0) && (count > 0)) { 272 sz = sndbuf_getfree(bs); 273 if (sz == 0) { 274 if (c->flags & CHN_F_NBIO) 275 ret = EWOULDBLOCK; 276 else { 277 timeout = (hz * sndbuf_getblksz(bs)) / (sndbuf_getspd(bs) * sndbuf_getbps(bs)); 278 if (timeout < 1) 279 timeout = 1; 280 timeout = 1; 281 ret = chn_sleep(c, "pcmwr", timeout); 282 if (ret == EWOULDBLOCK) { 283 count -= timeout; 284 ret = 0; 285 } else if (ret == 0) 286 count = hz; 287 } 288 } else { 289 sz = MIN(sz, buf->uio_resid); 290 KASSERT(sz > 0, ("confusion in chn_write")); 291 /* printf("sz: %d\n", sz); */ 292 ret = sndbuf_uiomove(bs, buf, sz); 293 if (ret == 0 && !(c->flags & CHN_F_TRIGGERED)) 294 chn_start(c, 0); 295 } 296 } 297 /* printf("ret: %d left: %d\n", ret, buf->uio_resid); */ 298 299 if (count <= 0) { 300 c->flags |= CHN_F_DEAD; 301 printf("%s: play interrupt timeout, channel dead\n", c->name); 302 } 303 304 return ret; 305 } 306 307 static int 308 chn_rddump(struct pcm_channel *c, unsigned int cnt) 309 { 310 struct snd_dbuf *b = c->bufhard; 311 312 CHN_LOCKASSERT(c); 313 sndbuf_setxrun(b, sndbuf_getxrun(b) + cnt); 314 return sndbuf_dispose(b, NULL, cnt); 315 } 316 317 /* 318 * Feed new data from the read buffer. Can be called in the bottom half. 319 * Hence must be called at spltty. 320 */ 321 int 322 chn_rdfeed(struct pcm_channel *c) 323 { 324 struct snd_dbuf *b = c->bufhard; 325 struct snd_dbuf *bs = c->bufsoft; 326 unsigned int ret, amt; 327 328 CHN_LOCKASSERT(c); 329 DEB( 330 if (c->flags & CHN_F_CLOSING) { 331 sndbuf_dump(b, "b", 0x02); 332 sndbuf_dump(bs, "bs", 0x02); 333 }) 334 335 amt = sndbuf_getready(b); 336 if (sndbuf_getfree(bs) < amt) { 337 c->xruns++; 338 amt = sndbuf_getfree(bs); 339 } 340 ret = (amt > 0)? sndbuf_feed(b, bs, c, c->feeder, amt) : 0; 341 342 amt = sndbuf_getready(b); 343 if (amt > 0) 344 chn_rddump(c, amt); 345 346 chn_wakeup(c); 347 348 return ret; 349 } 350 351 void 352 chn_rdupdate(struct pcm_channel *c) 353 { 354 int ret; 355 356 CHN_LOCKASSERT(c); 357 KASSERT(c->direction == PCMDIR_REC, ("chn_rdupdate on bad channel")); 358 359 if ((c->flags & CHN_F_MAPPED) || !(c->flags & CHN_F_TRIGGERED)) 360 return; 361 chn_trigger(c, PCMTRIG_EMLDMARD); 362 chn_dmaupdate(c); 363 ret = chn_rdfeed(c); 364 if (ret) 365 printf("chn_rdfeed: %d\n", ret); 366 367 } 368 369 /* read interrupt routine. Must be called with interrupts blocked. */ 370 static void 371 chn_rdintr(struct pcm_channel *c) 372 { 373 int ret; 374 375 CHN_LOCKASSERT(c); 376 /* tell the driver to update the primary buffer if non-dma */ 377 chn_trigger(c, PCMTRIG_EMLDMARD); 378 /* update pointers in primary buffer */ 379 chn_dmaupdate(c); 380 /* ...and feed from primary to secondary */ 381 ret = chn_rdfeed(c); 382 } 383 384 /* 385 * user read routine - trigger if necessary, uiomove data from secondary bufhard 386 * if blocking, sleep, rinse and repeat. 387 * 388 * called externally, so must handle locking 389 */ 390 391 int 392 chn_read(struct pcm_channel *c, struct uio *buf) 393 { 394 int ret, timeout, sz, count; 395 struct snd_dbuf *bs = c->bufsoft; 396 397 CHN_LOCKASSERT(c); 398 if (!(c->flags & CHN_F_TRIGGERED)) 399 chn_start(c, 0); 400 401 ret = 0; 402 count = hz; 403 while (!ret && (buf->uio_resid > 0) && (count > 0)) { 404 sz = MIN(buf->uio_resid, sndbuf_getready(bs)); 405 406 if (sz > 0) { 407 ret = sndbuf_uiomove(bs, buf, sz); 408 } else { 409 if (c->flags & CHN_F_NBIO) { 410 ret = EWOULDBLOCK; 411 } else { 412 timeout = (hz * sndbuf_getblksz(bs)) / (sndbuf_getspd(bs) * sndbuf_getbps(bs)); 413 if (timeout < 1) 414 timeout = 1; 415 ret = chn_sleep(c, "pcmrd", timeout); 416 if (ret == EWOULDBLOCK) { 417 count -= timeout; 418 ret = 0; 419 } else { 420 count = hz; 421 } 422 423 } 424 } 425 } 426 427 if (count <= 0) { 428 c->flags |= CHN_F_DEAD; 429 printf("%s: record interrupt timeout, channel dead\n", c->name); 430 } 431 432 return ret; 433 } 434 435 void 436 chn_intr(struct pcm_channel *c) 437 { 438 CHN_LOCK(c); 439 c->interrupts++; 440 if (c->direction == PCMDIR_PLAY) 441 chn_wrintr(c); 442 else 443 chn_rdintr(c); 444 CHN_UNLOCK(c); 445 } 446 447 u_int32_t 448 chn_start(struct pcm_channel *c, int force) 449 { 450 u_int32_t i, j; 451 struct snd_dbuf *b = c->bufhard; 452 struct snd_dbuf *bs = c->bufsoft; 453 454 CHN_LOCKASSERT(c); 455 /* if we're running, or if we're prevented from triggering, bail */ 456 if ((c->flags & CHN_F_TRIGGERED) || ((c->flags & CHN_F_NOTRIGGER) && !force)) 457 return EINVAL; 458 459 i = (c->direction == PCMDIR_PLAY)? sndbuf_getready(bs) : sndbuf_getfree(bs); 460 j = (c->direction == PCMDIR_PLAY)? sndbuf_getfree(b) : sndbuf_getready(b); 461 if (force || (i >= j)) { 462 c->flags |= CHN_F_TRIGGERED; 463 /* 464 * if we're starting because a vchan started, don't feed any data 465 * or it becomes impossible to start vchans synchronised with the 466 * first one. the hardbuf should be empty so we top it up with 467 * silence to give it something to chew. the real data will be 468 * fed at the first irq. 469 */ 470 if (c->direction == PCMDIR_PLAY) { 471 if (SLIST_EMPTY(&c->children)) 472 chn_wrfeed(c); 473 else 474 sndbuf_fillsilence(b); 475 } 476 sndbuf_setrun(b, 1); 477 c->xruns = 0; 478 chn_trigger(c, PCMTRIG_START); 479 return 0; 480 } 481 482 return 0; 483 } 484 485 void 486 chn_resetbuf(struct pcm_channel *c) 487 { 488 struct snd_dbuf *b = c->bufhard; 489 struct snd_dbuf *bs = c->bufsoft; 490 491 c->blocks = 0; 492 sndbuf_reset(b); 493 sndbuf_reset(bs); 494 } 495 496 /* 497 * chn_sync waits until the space in the given channel goes above 498 * a threshold. The threshold is checked against fl or rl respectively. 499 * Assume that the condition can become true, do not check here... 500 */ 501 int 502 chn_sync(struct pcm_channel *c, int threshold) 503 { 504 u_long rdy; 505 int ret; 506 struct snd_dbuf *bs = c->bufsoft; 507 508 CHN_LOCKASSERT(c); 509 for (;;) { 510 rdy = (c->direction == PCMDIR_PLAY)? sndbuf_getfree(bs) : sndbuf_getready(bs); 511 if (rdy <= threshold) { 512 ret = chn_sleep(c, "pcmsyn", 1); 513 if (ret == ERESTART || ret == EINTR) { 514 DEB(printf("chn_sync: tsleep returns %d\n", ret)); 515 return -1; 516 } 517 } else 518 break; 519 } 520 return 0; 521 } 522 523 /* called externally, handle locking */ 524 int 525 chn_poll(struct pcm_channel *c, int ev, struct thread *td) 526 { 527 struct snd_dbuf *bs = c->bufsoft; 528 int ret; 529 530 CHN_LOCKASSERT(c); 531 if (!(c->flags & CHN_F_MAPPED) && !(c->flags & CHN_F_TRIGGERED)) 532 chn_start(c, 1); 533 ret = 0; 534 if (chn_polltrigger(c) && chn_pollreset(c)) 535 ret = ev; 536 else 537 selrecord(td, sndbuf_getsel(bs)); 538 return ret; 539 } 540 541 /* 542 * chn_abort terminates a running dma transfer. it may sleep up to 200ms. 543 * it returns the number of bytes that have not been transferred. 544 * 545 * called from: dsp_close, dsp_ioctl, with channel locked 546 */ 547 int 548 chn_abort(struct pcm_channel *c) 549 { 550 int missing = 0; 551 struct snd_dbuf *b = c->bufhard; 552 struct snd_dbuf *bs = c->bufsoft; 553 554 CHN_LOCKASSERT(c); 555 if (!(c->flags & CHN_F_TRIGGERED)) 556 return 0; 557 c->flags |= CHN_F_ABORTING; 558 559 c->flags &= ~CHN_F_TRIGGERED; 560 /* kill the channel */ 561 chn_trigger(c, PCMTRIG_ABORT); 562 sndbuf_setrun(b, 0); 563 if (!(c->flags & CHN_F_VIRTUAL)) 564 chn_dmaupdate(c); 565 missing = sndbuf_getready(bs) + sndbuf_getready(b); 566 567 c->flags &= ~CHN_F_ABORTING; 568 return missing; 569 } 570 571 /* 572 * this routine tries to flush the dma transfer. It is called 573 * on a close. We immediately abort any read DMA 574 * operation, and then wait for the play bufhard to drain. 575 * 576 * called from: dsp_close 577 */ 578 579 int 580 chn_flush(struct pcm_channel *c) 581 { 582 int ret, count, resid, resid_p; 583 struct snd_dbuf *b = c->bufhard; 584 struct snd_dbuf *bs = c->bufsoft; 585 586 CHN_LOCKASSERT(c); 587 KASSERT(c->direction == PCMDIR_PLAY, ("chn_wrupdate on bad channel")); 588 DEB(printf("chn_flush c->flags 0x%08x\n", c->flags)); 589 if (!(c->flags & CHN_F_TRIGGERED)) 590 return 0; 591 592 c->flags |= CHN_F_CLOSING; 593 resid = sndbuf_getready(bs) + sndbuf_getready(b); 594 resid_p = resid; 595 count = 10; 596 ret = 0; 597 while ((count > 0) && (resid > sndbuf_getsize(b)) && (ret == 0)) { 598 /* still pending output data. */ 599 ret = chn_sleep(c, "pcmflu", hz / 10); 600 if (ret == EWOULDBLOCK) 601 ret = 0; 602 if (ret == 0) { 603 resid = sndbuf_getready(bs) + sndbuf_getready(b); 604 if (resid >= resid_p) 605 count--; 606 resid_p = resid; 607 } 608 } 609 if (count == 0) 610 DEB(printf("chn_flush: timeout\n")); 611 612 c->flags &= ~CHN_F_TRIGGERED; 613 /* kill the channel */ 614 chn_trigger(c, PCMTRIG_ABORT); 615 sndbuf_setrun(b, 0); 616 617 c->flags &= ~CHN_F_CLOSING; 618 return 0; 619 } 620 621 int 622 fmtvalid(u_int32_t fmt, u_int32_t *fmtlist) 623 { 624 int i; 625 626 for (i = 0; fmtlist[i]; i++) 627 if (fmt == fmtlist[i]) 628 return 1; 629 return 0; 630 } 631 632 int 633 chn_reset(struct pcm_channel *c, u_int32_t fmt) 634 { 635 int hwspd, r = 0; 636 637 CHN_LOCKASSERT(c); 638 c->flags &= CHN_F_RESET; 639 c->interrupts = 0; 640 c->xruns = 0; 641 CHANNEL_RESET(c->methods, c->devinfo); 642 if (fmt) { 643 hwspd = DSP_DEFAULT_SPEED; 644 /* only do this on a record channel until feederbuilder works */ 645 if (c->direction == PCMDIR_REC) 646 RANGE(hwspd, chn_getcaps(c)->minspeed, chn_getcaps(c)->maxspeed); 647 c->speed = hwspd; 648 649 r = chn_setformat(c, fmt); 650 if (r == 0) 651 r = chn_setspeed(c, hwspd); 652 if (r == 0) 653 r = chn_setvolume(c, 100, 100); 654 } 655 r = chn_setblocksize(c, 0, 0); 656 if (r == 0) { 657 chn_resetbuf(c); 658 CHANNEL_RESETDONE(c->methods, c->devinfo); 659 } 660 return r; 661 } 662 663 int 664 chn_init(struct pcm_channel *c, void *devinfo, int dir) 665 { 666 struct feeder_class *fc; 667 struct snd_dbuf *b, *bs; 668 669 chn_lockinit(c); 670 CHN_LOCK(c); 671 672 c->feeder = NULL; 673 fc = feeder_getclass(NULL); 674 if (fc == NULL) 675 return EINVAL; 676 if (chn_addfeeder(c, fc, NULL)) 677 return EINVAL; 678 679 b = sndbuf_create(c->name, "primary"); 680 if (b == NULL) 681 return ENOMEM; 682 bs = sndbuf_create(c->name, "secondary"); 683 if (bs == NULL) { 684 sndbuf_destroy(b); 685 return ENOMEM; 686 } 687 sndbuf_setup(bs, NULL, 0); 688 c->bufhard = b; 689 c->bufsoft = bs; 690 c->flags = 0; 691 c->feederflags = 0; 692 c->devinfo = CHANNEL_INIT(c->methods, devinfo, b, c, dir); 693 if (c->devinfo == NULL) { 694 sndbuf_destroy(bs); 695 sndbuf_destroy(b); 696 return ENODEV; 697 } 698 if ((sndbuf_getsize(b) == 0) && ((c->flags & CHN_F_VIRTUAL) == 0)) { 699 sndbuf_destroy(bs); 700 sndbuf_destroy(b); 701 return ENOMEM; 702 } 703 chn_setdir(c, dir); 704 705 /* And the secondary buffer. */ 706 sndbuf_setfmt(b, AFMT_U8); 707 sndbuf_setfmt(bs, AFMT_U8); 708 CHN_UNLOCK(c); 709 return 0; 710 } 711 712 int 713 chn_kill(struct pcm_channel *c) 714 { 715 struct snd_dbuf *b = c->bufhard; 716 struct snd_dbuf *bs = c->bufsoft; 717 718 CHN_LOCK(c); 719 if (c->flags & CHN_F_TRIGGERED) 720 chn_trigger(c, PCMTRIG_ABORT); 721 while (chn_removefeeder(c) == 0); 722 if (CHANNEL_FREE(c->methods, c->devinfo)) 723 sndbuf_free(c->bufhard); 724 c->flags |= CHN_F_DEAD; 725 sndbuf_destroy(bs); 726 sndbuf_destroy(b); 727 chn_lockdestroy(c); 728 return 0; 729 } 730 731 int 732 chn_setdir(struct pcm_channel *c, int dir) 733 { 734 struct snd_dbuf *b = c->bufhard; 735 int r; 736 737 CHN_LOCKASSERT(c); 738 c->direction = dir; 739 r = CHANNEL_SETDIR(c->methods, c->devinfo, c->direction); 740 if (!r && ISA_DMA(b)) 741 sndbuf_isadmasetdir(b, c->direction); 742 return r; 743 } 744 745 int 746 chn_setvolume(struct pcm_channel *c, int left, int right) 747 { 748 CHN_LOCKASSERT(c); 749 /* could add a feeder for volume changing if channel returns -1 */ 750 c->volume = (left << 8) | right; 751 return 0; 752 } 753 754 static int 755 chn_tryspeed(struct pcm_channel *c, int speed) 756 { 757 struct pcm_feeder *f; 758 struct snd_dbuf *b = c->bufhard; 759 struct snd_dbuf *bs = c->bufsoft; 760 int r, delta; 761 762 CHN_LOCKASSERT(c); 763 DEB(printf("setspeed, channel %s\n", c->name)); 764 DEB(printf("want speed %d, ", speed)); 765 if (speed <= 0) 766 return EINVAL; 767 if (CANCHANGE(c)) { 768 r = 0; 769 c->speed = speed; 770 sndbuf_setspd(bs, speed); 771 RANGE(speed, chn_getcaps(c)->minspeed, chn_getcaps(c)->maxspeed); 772 DEB(printf("try speed %d, ", speed)); 773 sndbuf_setspd(b, CHANNEL_SETSPEED(c->methods, c->devinfo, speed)); 774 DEB(printf("got speed %d\n", sndbuf_getspd(b))); 775 776 delta = sndbuf_getspd(b) - sndbuf_getspd(bs); 777 if (delta < 0) 778 delta = -delta; 779 780 c->feederflags &= ~(1 << FEEDER_RATE); 781 if (delta > 500) 782 c->feederflags |= 1 << FEEDER_RATE; 783 else 784 sndbuf_setspd(bs, sndbuf_getspd(b)); 785 786 r = chn_buildfeeder(c); 787 DEB(printf("r = %d\n", r)); 788 if (r) 789 goto out; 790 791 r = chn_setblocksize(c, 0, 0); 792 if (r) 793 goto out; 794 795 if (!(c->feederflags & (1 << FEEDER_RATE))) 796 goto out; 797 798 r = EINVAL; 799 f = chn_findfeeder(c, FEEDER_RATE); 800 DEB(printf("feedrate = %p\n", f)); 801 if (f == NULL) 802 goto out; 803 804 r = FEEDER_SET(f, FEEDRATE_SRC, sndbuf_getspd(bs)); 805 DEB(printf("feeder_set(FEEDRATE_SRC, %d) = %d\n", sndbuf_getspd(bs), r)); 806 if (r) 807 goto out; 808 809 r = FEEDER_SET(f, FEEDRATE_DST, sndbuf_getspd(b)); 810 DEB(printf("feeder_set(FEEDRATE_DST, %d) = %d\n", sndbuf_getspd(b), r)); 811 out: 812 DEB(printf("setspeed done, r = %d\n", r)); 813 return r; 814 } else 815 return EINVAL; 816 } 817 818 int 819 chn_setspeed(struct pcm_channel *c, int speed) 820 { 821 int r, oldspeed = c->speed; 822 823 r = chn_tryspeed(c, speed); 824 if (r) { 825 DEB(printf("Failed to set speed %d falling back to %d\n", speed, oldspeed)); 826 chn_tryspeed(c, oldspeed); 827 } 828 return r; 829 } 830 831 static int 832 chn_tryformat(struct pcm_channel *c, u_int32_t fmt) 833 { 834 struct snd_dbuf *b = c->bufhard; 835 struct snd_dbuf *bs = c->bufsoft; 836 int r; 837 838 CHN_LOCKASSERT(c); 839 if (CANCHANGE(c)) { 840 DEB(printf("want format %d\n", fmt)); 841 c->format = fmt; 842 r = chn_buildfeeder(c); 843 if (r == 0) { 844 sndbuf_setfmt(b, c->feeder->desc->out); 845 sndbuf_setfmt(bs, fmt); 846 chn_resetbuf(c); 847 CHANNEL_SETFORMAT(c->methods, c->devinfo, sndbuf_getfmt(b)); 848 r = chn_tryspeed(c, c->speed); 849 } 850 return r; 851 } else 852 return EINVAL; 853 } 854 855 int 856 chn_setformat(struct pcm_channel *c, u_int32_t fmt) 857 { 858 u_int32_t oldfmt = c->format; 859 int r; 860 861 r = chn_tryformat(c, fmt); 862 if (r) { 863 DEB(printf("Format change %d failed, reverting to %d\n", fmt, oldfmt)); 864 chn_tryformat(c, oldfmt); 865 } 866 return r; 867 } 868 869 int 870 chn_setblocksize(struct pcm_channel *c, int blkcnt, int blksz) 871 { 872 struct snd_dbuf *b = c->bufhard; 873 struct snd_dbuf *bs = c->bufsoft; 874 int bufsz, irqhz, tmp, ret; 875 876 CHN_LOCKASSERT(c); 877 if (!CANCHANGE(c) || (c->flags & CHN_F_MAPPED)) 878 return EINVAL; 879 880 ret = 0; 881 DEB(printf("%s(%d, %d)\n", __func__, blkcnt, blksz)); 882 if (blksz == 0 || blksz == -1) { 883 if (blksz == -1) 884 c->flags &= ~CHN_F_HAS_SIZE; 885 if (!(c->flags & CHN_F_HAS_SIZE)) { 886 blksz = (sndbuf_getbps(bs) * sndbuf_getspd(bs)) / chn_targetirqrate; 887 tmp = 32; 888 while (tmp <= blksz) 889 tmp <<= 1; 890 tmp >>= 1; 891 blksz = tmp; 892 blkcnt = CHN_2NDBUFMAXSIZE / blksz; 893 894 RANGE(blksz, 16, CHN_2NDBUFMAXSIZE / 2); 895 RANGE(blkcnt, 2, CHN_2NDBUFMAXSIZE / blksz); 896 DEB(printf("%s: defaulting to (%d, %d)\n", __func__, blkcnt, blksz)); 897 } else { 898 blkcnt = sndbuf_getblkcnt(bs); 899 blksz = sndbuf_getblksz(bs); 900 DEB(printf("%s: updating (%d, %d)\n", __func__, blkcnt, blksz)); 901 } 902 } else { 903 ret = EINVAL; 904 if ((blksz < 16) || (blkcnt < 2) || (blkcnt * blksz > CHN_2NDBUFMAXSIZE)) 905 goto out; 906 ret = 0; 907 c->flags |= CHN_F_HAS_SIZE; 908 } 909 910 bufsz = blkcnt * blksz; 911 912 ret = ENOMEM; 913 if (sndbuf_remalloc(bs, blkcnt, blksz)) 914 goto out; 915 ret = 0; 916 917 /* adjust for different hw format/speed */ 918 irqhz = (sndbuf_getbps(bs) * sndbuf_getspd(bs)) / sndbuf_getblksz(bs); 919 DEB(printf("%s: soft bps %d, spd %d, irqhz == %d\n", __func__, sndbuf_getbps(bs), sndbuf_getspd(bs), irqhz)); 920 RANGE(irqhz, 16, 512); 921 922 sndbuf_setblksz(b, (sndbuf_getbps(b) * sndbuf_getspd(b)) / irqhz); 923 924 /* round down to 2^x */ 925 blksz = 32; 926 while (blksz <= sndbuf_getblksz(b)) 927 blksz <<= 1; 928 blksz >>= 1; 929 930 /* round down to fit hw bufhard size */ 931 RANGE(blksz, 16, sndbuf_getmaxsize(b) / 2); 932 DEB(printf("%s: hard blksz requested %d (maxsize %d), ", __func__, blksz, sndbuf_getmaxsize(b))); 933 934 sndbuf_setblksz(b, CHANNEL_SETBLOCKSIZE(c->methods, c->devinfo, blksz)); 935 936 irqhz = (sndbuf_getbps(b) * sndbuf_getspd(b)) / sndbuf_getblksz(b); 937 DEB(printf("got %d, irqhz == %d\n", sndbuf_getblksz(b), irqhz)); 938 939 chn_resetbuf(c); 940 out: 941 return ret; 942 } 943 944 int 945 chn_trigger(struct pcm_channel *c, int go) 946 { 947 struct snd_dbuf *b = c->bufhard; 948 int ret; 949 950 CHN_LOCKASSERT(c); 951 if (ISA_DMA(b) && (go == PCMTRIG_EMLDMAWR || go == PCMTRIG_EMLDMARD)) 952 sndbuf_isadmabounce(b); 953 ret = CHANNEL_TRIGGER(c->methods, c->devinfo, go); 954 955 return ret; 956 } 957 958 int 959 chn_getptr(struct pcm_channel *c) 960 { 961 int hwptr; 962 int a = (1 << c->align) - 1; 963 964 CHN_LOCKASSERT(c); 965 hwptr = (c->flags & CHN_F_TRIGGERED)? CHANNEL_GETPTR(c->methods, c->devinfo) : 0; 966 /* don't allow unaligned values in the hwa ptr */ 967 #if 1 968 hwptr &= ~a ; /* Apply channel align mask */ 969 #endif 970 hwptr &= DMA_ALIGN_MASK; /* Apply DMA align mask */ 971 return hwptr; 972 } 973 974 struct pcmchan_caps * 975 chn_getcaps(struct pcm_channel *c) 976 { 977 CHN_LOCKASSERT(c); 978 return CHANNEL_GETCAPS(c->methods, c->devinfo); 979 } 980 981 u_int32_t 982 chn_getformats(struct pcm_channel *c) 983 { 984 u_int32_t *fmtlist, fmts; 985 int i; 986 987 fmtlist = chn_getcaps(c)->fmtlist; 988 fmts = 0; 989 for (i = 0; fmtlist[i]; i++) 990 fmts |= fmtlist[i]; 991 992 return fmts; 993 } 994 995 static int 996 chn_buildfeeder(struct pcm_channel *c) 997 { 998 struct feeder_class *fc; 999 struct pcm_feederdesc desc; 1000 u_int32_t tmp[2], type, flags; 1001 1002 CHN_LOCKASSERT(c); 1003 while (chn_removefeeder(c) == 0); 1004 KASSERT((c->feeder == NULL), ("feeder chain not empty")); 1005 1006 c->align = sndbuf_getalign(c->bufsoft); 1007 1008 if (SLIST_EMPTY(&c->children)) { 1009 fc = feeder_getclass(NULL); 1010 if (fc == NULL) { 1011 DEB(printf("can't find root feeder\n")); 1012 return EINVAL; 1013 } 1014 if (chn_addfeeder(c, fc, NULL)) { 1015 DEB(printf("can't add root feeder\n")); 1016 return EINVAL; 1017 } 1018 c->feeder->desc->out = c->format; 1019 } else { 1020 desc.type = FEEDER_MIXER; 1021 desc.in = 0; 1022 desc.out = c->format; 1023 desc.flags = 0; 1024 fc = feeder_getclass(&desc); 1025 if (fc == NULL) { 1026 DEB(printf("can't find vchan feeder\n")); 1027 return EINVAL; 1028 } 1029 if (chn_addfeeder(c, fc, &desc)) { 1030 DEB(printf("can't add vchan feeder\n")); 1031 return EINVAL; 1032 } 1033 } 1034 flags = c->feederflags; 1035 1036 if ((c->flags & CHN_F_MAPPED) && (flags != 0)) { 1037 DEB(printf("can't build feeder chain on mapped channel\n")); 1038 return EINVAL; 1039 } 1040 DEB(printf("not mapped, flags %x\n", flags)); 1041 1042 for (type = FEEDER_RATE; type <= FEEDER_LAST; type++) { 1043 if (flags & (1 << type)) { 1044 desc.type = type; 1045 desc.in = 0; 1046 desc.out = 0; 1047 desc.flags = 0; 1048 DEB(printf("find feeder type %d, ", type)); 1049 fc = feeder_getclass(&desc); 1050 DEB(printf("got %p\n", fc)); 1051 if (fc == NULL) { 1052 DEB(printf("can't find required feeder type %d\n", type)); 1053 return EINVAL; 1054 } 1055 1056 if (c->feeder->desc->out != fc->desc->in) { 1057 DEB(printf("build fmtchain from %x to %x: ", c->feeder->desc->out, fc->desc->in)); 1058 tmp[0] = fc->desc->in; 1059 tmp[1] = 0; 1060 if (chn_fmtchain(c, tmp) == 0) { 1061 DEB(printf("failed\n")); 1062 return EINVAL; 1063 } 1064 DEB(printf("ok\n")); 1065 } 1066 1067 if (chn_addfeeder(c, fc, fc->desc)) { 1068 DEB(printf("can't add feeder %p, output %x\n", fc, fc->desc->out)); 1069 return EINVAL; 1070 } 1071 DEB(printf("added feeder %p, output %x\n", fc, c->feeder->desc->out)); 1072 } 1073 } 1074 1075 if (!fmtvalid(c->feeder->desc->out, chn_getcaps(c)->fmtlist)) { 1076 if (chn_fmtchain(c, chn_getcaps(c)->fmtlist) == 0) { 1077 DEB(printf("can't build fmtchain from %x\n", c->feeder->desc->out)); 1078 return EINVAL; 1079 } 1080 DEB(printf("built fmtchain from %x\n", c->feeder->desc->out)); 1081 } 1082 1083 return 0; 1084 } 1085 1086 int 1087 chn_notify(struct pcm_channel *c, u_int32_t flags) 1088 { 1089 struct pcmchan_children *pce; 1090 struct pcm_channel *child; 1091 int run; 1092 1093 if (SLIST_EMPTY(&c->children)) 1094 return ENODEV; 1095 1096 run = (c->flags & CHN_F_TRIGGERED)? 1 : 0; 1097 /* 1098 * if the hwchan is running, we can't change its rate, format or 1099 * blocksize 1100 */ 1101 if (run) 1102 flags &= CHN_N_VOLUME | CHN_N_TRIGGER; 1103 1104 if (flags & CHN_N_RATE) { 1105 /* 1106 * we could do something here, like scan children and decide on 1107 * the most appropriate rate to mix at, but we don't for now 1108 */ 1109 } 1110 if (flags & CHN_N_FORMAT) { 1111 /* 1112 * we could do something here, like scan children and decide on 1113 * the most appropriate mixer feeder to use, but we don't for now 1114 */ 1115 } 1116 if (flags & CHN_N_VOLUME) { 1117 /* 1118 * we could do something here but we don't for now 1119 */ 1120 } 1121 if (flags & CHN_N_BLOCKSIZE) { 1122 int blksz; 1123 /* 1124 * scan the children, find the lowest blocksize and use that 1125 * for the hard blocksize 1126 */ 1127 blksz = sndbuf_getmaxsize(c->bufhard) / 2; 1128 SLIST_FOREACH(pce, &c->children, link) { 1129 child = pce->channel; 1130 if (sndbuf_getblksz(child->bufhard) < blksz) 1131 blksz = sndbuf_getblksz(child->bufhard); 1132 } 1133 chn_setblocksize(c, 2, blksz); 1134 } 1135 if (flags & CHN_N_TRIGGER) { 1136 int nrun; 1137 /* 1138 * scan the children, and figure out if any are running 1139 * if so, we need to be running, otherwise we need to be stopped 1140 * if we aren't in our target sstate, move to it 1141 */ 1142 nrun = 0; 1143 SLIST_FOREACH(pce, &c->children, link) { 1144 child = pce->channel; 1145 if (child->flags & CHN_F_TRIGGERED) 1146 nrun = 1; 1147 } 1148 if (nrun && !run) 1149 chn_start(c, 1); 1150 if (!nrun && run) 1151 chn_abort(c); 1152 } 1153 return 0; 1154 } 1155