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->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->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->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 buffer 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 buffer 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; 636 637 CHN_LOCKASSERT(c); 638 c->flags &= CHN_F_RESET; 639 c->interrupts = 0; 640 c->xruns = 0; 641 642 r = CHANNEL_RESET(c->methods, c->devinfo); 643 if (fmt != 0) { 644 hwspd = DSP_DEFAULT_SPEED; 645 /* only do this on a record channel until feederbuilder works */ 646 if (c->direction == PCMDIR_REC) 647 RANGE(hwspd, chn_getcaps(c)->minspeed, chn_getcaps(c)->maxspeed); 648 c->speed = hwspd; 649 650 if (r == 0) 651 r = chn_setformat(c, fmt); 652 if (r == 0) 653 r = chn_setspeed(c, hwspd); 654 if (r == 0) 655 r = chn_setvolume(c, 100, 100); 656 } 657 if (r == 0) 658 r = chn_setblocksize(c, 0, 0); 659 if (r == 0) { 660 chn_resetbuf(c); 661 r = CHANNEL_RESETDONE(c->methods, c->devinfo); 662 } 663 return r; 664 } 665 666 int 667 chn_init(struct pcm_channel *c, void *devinfo, int dir) 668 { 669 struct feeder_class *fc; 670 struct snd_dbuf *b, *bs; 671 int ret; 672 673 chn_lockinit(c); 674 CHN_LOCK(c); 675 676 b = NULL; 677 bs = NULL; 678 c->devinfo = NULL; 679 c->feeder = NULL; 680 681 ret = EINVAL; 682 fc = feeder_getclass(NULL); 683 if (fc == NULL) 684 goto out; 685 if (chn_addfeeder(c, fc, NULL)) 686 goto out; 687 688 ret = ENOMEM; 689 b = sndbuf_create(c->dev, c->name, "primary"); 690 if (b == NULL) 691 goto out; 692 bs = sndbuf_create(c->dev, c->name, "secondary"); 693 if (bs == NULL) 694 goto out; 695 sndbuf_setup(bs, NULL, 0); 696 c->bufhard = b; 697 c->bufsoft = bs; 698 c->flags = 0; 699 c->feederflags = 0; 700 701 ret = ENODEV; 702 c->devinfo = CHANNEL_INIT(c->methods, devinfo, b, c, dir); 703 if (c->devinfo == NULL) 704 goto out; 705 706 ret = ENOMEM; 707 if ((sndbuf_getsize(b) == 0) && ((c->flags & CHN_F_VIRTUAL) == 0)) 708 goto out; 709 710 ret = chn_setdir(c, dir); 711 if (ret) 712 goto out; 713 714 ret = sndbuf_setfmt(b, AFMT_U8); 715 if (ret) 716 goto out; 717 718 ret = sndbuf_setfmt(bs, AFMT_U8); 719 if (ret) 720 goto out; 721 722 723 out: 724 if (ret) { 725 if (c->devinfo) { 726 if (CHANNEL_FREE(c->methods, c->devinfo)) 727 sndbuf_free(b); 728 } 729 if (bs) 730 sndbuf_destroy(bs); 731 if (b) 732 sndbuf_destroy(b); 733 c->flags |= CHN_F_DEAD; 734 chn_lockdestroy(c); 735 736 return ret; 737 } 738 739 CHN_UNLOCK(c); 740 return 0; 741 } 742 743 int 744 chn_kill(struct pcm_channel *c) 745 { 746 struct snd_dbuf *b = c->bufhard; 747 struct snd_dbuf *bs = c->bufsoft; 748 749 CHN_LOCK(c); 750 if (c->flags & CHN_F_TRIGGERED) 751 chn_trigger(c, PCMTRIG_ABORT); 752 while (chn_removefeeder(c) == 0); 753 if (CHANNEL_FREE(c->methods, c->devinfo)) 754 sndbuf_free(b); 755 c->flags |= CHN_F_DEAD; 756 sndbuf_destroy(bs); 757 sndbuf_destroy(b); 758 chn_lockdestroy(c); 759 return 0; 760 } 761 762 int 763 chn_setdir(struct pcm_channel *c, int dir) 764 { 765 struct snd_dbuf *b = c->bufhard; 766 int r; 767 768 CHN_LOCKASSERT(c); 769 c->direction = dir; 770 r = CHANNEL_SETDIR(c->methods, c->devinfo, c->direction); 771 if (!r && ISA_DMA(b)) 772 sndbuf_isadmasetdir(b, c->direction); 773 return r; 774 } 775 776 int 777 chn_setvolume(struct pcm_channel *c, int left, int right) 778 { 779 CHN_LOCKASSERT(c); 780 /* could add a feeder for volume changing if channel returns -1 */ 781 c->volume = (left << 8) | right; 782 return 0; 783 } 784 785 static int 786 chn_tryspeed(struct pcm_channel *c, int speed) 787 { 788 struct pcm_feeder *f; 789 struct snd_dbuf *b = c->bufhard; 790 struct snd_dbuf *bs = c->bufsoft; 791 struct snd_dbuf *x; 792 int r, delta; 793 794 CHN_LOCKASSERT(c); 795 DEB(printf("setspeed, channel %s\n", c->name)); 796 DEB(printf("want speed %d, ", speed)); 797 if (speed <= 0) 798 return EINVAL; 799 if (CANCHANGE(c)) { 800 r = 0; 801 c->speed = speed; 802 sndbuf_setspd(bs, speed); 803 RANGE(speed, chn_getcaps(c)->minspeed, chn_getcaps(c)->maxspeed); 804 DEB(printf("try speed %d, ", speed)); 805 sndbuf_setspd(b, CHANNEL_SETSPEED(c->methods, c->devinfo, speed)); 806 DEB(printf("got speed %d\n", sndbuf_getspd(b))); 807 808 delta = sndbuf_getspd(b) - sndbuf_getspd(bs); 809 if (delta < 0) 810 delta = -delta; 811 812 c->feederflags &= ~(1 << FEEDER_RATE); 813 if (delta > 500) 814 c->feederflags |= 1 << FEEDER_RATE; 815 else 816 sndbuf_setspd(bs, sndbuf_getspd(b)); 817 818 r = chn_buildfeeder(c); 819 DEB(printf("r = %d\n", r)); 820 if (r) 821 goto out; 822 823 r = chn_setblocksize(c, 0, 0); 824 if (r) 825 goto out; 826 827 if (!(c->feederflags & (1 << FEEDER_RATE))) 828 goto out; 829 830 r = EINVAL; 831 f = chn_findfeeder(c, FEEDER_RATE); 832 DEB(printf("feedrate = %p\n", f)); 833 if (f == NULL) 834 goto out; 835 836 x = (c->direction == PCMDIR_REC)? b : bs; 837 r = FEEDER_SET(f, FEEDRATE_SRC, sndbuf_getspd(x)); 838 DEB(printf("feeder_set(FEEDRATE_SRC, %d) = %d\n", sndbuf_getspd(x), r)); 839 if (r) 840 goto out; 841 842 x = (c->direction == PCMDIR_REC)? bs : b; 843 r = FEEDER_SET(f, FEEDRATE_DST, sndbuf_getspd(x)); 844 DEB(printf("feeder_set(FEEDRATE_DST, %d) = %d\n", sndbuf_getspd(x), r)); 845 out: 846 DEB(printf("setspeed done, r = %d\n", r)); 847 return r; 848 } else 849 return EINVAL; 850 } 851 852 int 853 chn_setspeed(struct pcm_channel *c, int speed) 854 { 855 int r, oldspeed = c->speed; 856 857 r = chn_tryspeed(c, speed); 858 if (r) { 859 DEB(printf("Failed to set speed %d falling back to %d\n", speed, oldspeed)); 860 chn_tryspeed(c, oldspeed); 861 } 862 return r; 863 } 864 865 static int 866 chn_tryformat(struct pcm_channel *c, u_int32_t fmt) 867 { 868 struct snd_dbuf *b = c->bufhard; 869 struct snd_dbuf *bs = c->bufsoft; 870 int r; 871 872 CHN_LOCKASSERT(c); 873 if (CANCHANGE(c)) { 874 DEB(printf("want format %d\n", fmt)); 875 c->format = fmt; 876 r = chn_buildfeeder(c); 877 if (r == 0) { 878 sndbuf_setfmt(bs, c->format); 879 chn_resetbuf(c); 880 r = CHANNEL_SETFORMAT(c->methods, c->devinfo, sndbuf_getfmt(b)); 881 if (r == 0) 882 r = chn_tryspeed(c, c->speed); 883 } 884 return r; 885 } else 886 return EINVAL; 887 } 888 889 int 890 chn_setformat(struct pcm_channel *c, u_int32_t fmt) 891 { 892 u_int32_t oldfmt = c->format; 893 int r; 894 895 r = chn_tryformat(c, fmt); 896 if (r) { 897 DEB(printf("Format change %d failed, reverting to %d\n", fmt, oldfmt)); 898 chn_tryformat(c, oldfmt); 899 } 900 return r; 901 } 902 903 int 904 chn_setblocksize(struct pcm_channel *c, int blkcnt, int blksz) 905 { 906 struct snd_dbuf *b = c->bufhard; 907 struct snd_dbuf *bs = c->bufsoft; 908 int bufsz, irqhz, tmp, ret; 909 910 CHN_LOCKASSERT(c); 911 if (!CANCHANGE(c) || (c->flags & CHN_F_MAPPED)) 912 return EINVAL; 913 914 ret = 0; 915 DEB(printf("%s(%d, %d)\n", __func__, blkcnt, blksz)); 916 if (blksz == 0 || blksz == -1) { 917 if (blksz == -1) 918 c->flags &= ~CHN_F_HAS_SIZE; 919 if (!(c->flags & CHN_F_HAS_SIZE)) { 920 blksz = (sndbuf_getbps(bs) * sndbuf_getspd(bs)) / chn_targetirqrate; 921 tmp = 32; 922 while (tmp <= blksz) 923 tmp <<= 1; 924 tmp >>= 1; 925 blksz = tmp; 926 blkcnt = CHN_2NDBUFMAXSIZE / blksz; 927 928 RANGE(blksz, 16, CHN_2NDBUFMAXSIZE / 2); 929 RANGE(blkcnt, 2, CHN_2NDBUFMAXSIZE / blksz); 930 DEB(printf("%s: defaulting to (%d, %d)\n", __func__, blkcnt, blksz)); 931 } else { 932 blkcnt = sndbuf_getblkcnt(bs); 933 blksz = sndbuf_getblksz(bs); 934 DEB(printf("%s: updating (%d, %d)\n", __func__, blkcnt, blksz)); 935 } 936 } else { 937 ret = EINVAL; 938 if ((blksz < 16) || (blkcnt < 2) || (blkcnt * blksz > CHN_2NDBUFMAXSIZE)) 939 goto out; 940 ret = 0; 941 c->flags |= CHN_F_HAS_SIZE; 942 } 943 944 bufsz = blkcnt * blksz; 945 946 ret = ENOMEM; 947 if (sndbuf_remalloc(bs, blkcnt, blksz)) 948 goto out; 949 ret = 0; 950 951 /* adjust for different hw format/speed */ 952 irqhz = (sndbuf_getbps(bs) * sndbuf_getspd(bs)) / sndbuf_getblksz(bs); 953 DEB(printf("%s: soft bps %d, spd %d, irqhz == %d\n", __func__, sndbuf_getbps(bs), sndbuf_getspd(bs), irqhz)); 954 RANGE(irqhz, 16, 512); 955 956 sndbuf_setblksz(b, (sndbuf_getbps(b) * sndbuf_getspd(b)) / irqhz); 957 958 /* round down to 2^x */ 959 blksz = 32; 960 while (blksz <= sndbuf_getblksz(b)) 961 blksz <<= 1; 962 blksz >>= 1; 963 964 /* round down to fit hw buffer size */ 965 RANGE(blksz, 16, sndbuf_getmaxsize(b) / 2); 966 DEB(printf("%s: hard blksz requested %d (maxsize %d), ", __func__, blksz, sndbuf_getmaxsize(b))); 967 968 sndbuf_setblksz(b, CHANNEL_SETBLOCKSIZE(c->methods, c->devinfo, blksz)); 969 970 irqhz = (sndbuf_getbps(b) * sndbuf_getspd(b)) / sndbuf_getblksz(b); 971 DEB(printf("got %d, irqhz == %d\n", sndbuf_getblksz(b), irqhz)); 972 973 chn_resetbuf(c); 974 out: 975 return ret; 976 } 977 978 int 979 chn_trigger(struct pcm_channel *c, int go) 980 { 981 struct snd_dbuf *b = c->bufhard; 982 int ret; 983 984 CHN_LOCKASSERT(c); 985 if (ISA_DMA(b) && (go == PCMTRIG_EMLDMAWR || go == PCMTRIG_EMLDMARD)) 986 sndbuf_isadmabounce(b); 987 ret = CHANNEL_TRIGGER(c->methods, c->devinfo, go); 988 989 return ret; 990 } 991 992 int 993 chn_getptr(struct pcm_channel *c) 994 { 995 int hwptr; 996 int a = (1 << c->align) - 1; 997 998 CHN_LOCKASSERT(c); 999 hwptr = (c->flags & CHN_F_TRIGGERED)? CHANNEL_GETPTR(c->methods, c->devinfo) : 0; 1000 /* don't allow unaligned values in the hwa ptr */ 1001 #if 1 1002 hwptr &= ~a ; /* Apply channel align mask */ 1003 #endif 1004 hwptr &= DMA_ALIGN_MASK; /* Apply DMA align mask */ 1005 return hwptr; 1006 } 1007 1008 struct pcmchan_caps * 1009 chn_getcaps(struct pcm_channel *c) 1010 { 1011 CHN_LOCKASSERT(c); 1012 return CHANNEL_GETCAPS(c->methods, c->devinfo); 1013 } 1014 1015 u_int32_t 1016 chn_getformats(struct pcm_channel *c) 1017 { 1018 u_int32_t *fmtlist, fmts; 1019 int i; 1020 1021 fmtlist = chn_getcaps(c)->fmtlist; 1022 fmts = 0; 1023 for (i = 0; fmtlist[i]; i++) 1024 fmts |= fmtlist[i]; 1025 1026 return fmts; 1027 } 1028 1029 static int 1030 chn_buildfeeder(struct pcm_channel *c) 1031 { 1032 struct feeder_class *fc; 1033 struct pcm_feederdesc desc; 1034 u_int32_t tmp[2], type, flags, hwfmt; 1035 int err; 1036 1037 CHN_LOCKASSERT(c); 1038 while (chn_removefeeder(c) == 0); 1039 KASSERT((c->feeder == NULL), ("feeder chain not empty")); 1040 1041 c->align = sndbuf_getalign(c->bufsoft); 1042 1043 if (SLIST_EMPTY(&c->children)) { 1044 fc = feeder_getclass(NULL); 1045 KASSERT(fc != NULL, ("can't find root feeder")); 1046 1047 err = chn_addfeeder(c, fc, NULL); 1048 if (err) { 1049 DEB(printf("can't add root feeder, err %d\n", err)); 1050 1051 return err; 1052 } 1053 c->feeder->desc->out = c->format; 1054 } else { 1055 desc.type = FEEDER_MIXER; 1056 desc.in = 0; 1057 desc.out = c->format; 1058 desc.flags = 0; 1059 fc = feeder_getclass(&desc); 1060 if (fc == NULL) { 1061 DEB(printf("can't find vchan feeder\n")); 1062 1063 return EOPNOTSUPP; 1064 } 1065 1066 err = chn_addfeeder(c, fc, &desc); 1067 if (err) { 1068 DEB(printf("can't add vchan feeder, err %d\n", err)); 1069 1070 return err; 1071 } 1072 } 1073 flags = c->feederflags; 1074 1075 DEB(printf("not mapped, feederflags %x\n", flags)); 1076 1077 for (type = FEEDER_RATE; type <= FEEDER_LAST; type++) { 1078 if (flags & (1 << type)) { 1079 desc.type = type; 1080 desc.in = 0; 1081 desc.out = 0; 1082 desc.flags = 0; 1083 DEB(printf("find feeder type %d, ", type)); 1084 fc = feeder_getclass(&desc); 1085 DEB(printf("got %p\n", fc)); 1086 if (fc == NULL) { 1087 DEB(printf("can't find required feeder type %d\n", type)); 1088 1089 return EOPNOTSUPP; 1090 } 1091 1092 if (c->feeder->desc->out != fc->desc->in) { 1093 DEB(printf("build fmtchain from %x to %x: ", c->feeder->desc->out, fc->desc->in)); 1094 tmp[0] = fc->desc->in; 1095 tmp[1] = 0; 1096 if (chn_fmtchain(c, tmp) == 0) { 1097 DEB(printf("failed\n")); 1098 1099 return ENODEV; 1100 } 1101 DEB(printf("ok\n")); 1102 } 1103 1104 err = chn_addfeeder(c, fc, fc->desc); 1105 if (err) { 1106 DEB(printf("can't add feeder %p, output %x, err %d\n", fc, fc->desc->out, err)); 1107 1108 return err; 1109 } 1110 DEB(printf("added feeder %p, output %x\n", fc, c->feeder->desc->out)); 1111 } 1112 } 1113 1114 if (fmtvalid(c->feeder->desc->out, chn_getcaps(c)->fmtlist)) { 1115 hwfmt = c->feeder->desc->out; 1116 } else { 1117 if (c->direction == PCMDIR_REC) { 1118 tmp[0] = c->format; 1119 tmp[1] = NULL; 1120 hwfmt = chn_fmtchain(c, tmp); 1121 } else { 1122 hwfmt = chn_fmtchain(c, chn_getcaps(c)->fmtlist); 1123 } 1124 } 1125 1126 if (hwfmt == 0) 1127 return ENODEV; 1128 1129 sndbuf_setfmt(c->bufhard, hwfmt); 1130 1131 return 0; 1132 } 1133 1134 int 1135 chn_notify(struct pcm_channel *c, u_int32_t flags) 1136 { 1137 struct pcmchan_children *pce; 1138 struct pcm_channel *child; 1139 int run; 1140 1141 if (SLIST_EMPTY(&c->children)) 1142 return ENODEV; 1143 1144 run = (c->flags & CHN_F_TRIGGERED)? 1 : 0; 1145 /* 1146 * if the hwchan is running, we can't change its rate, format or 1147 * blocksize 1148 */ 1149 if (run) 1150 flags &= CHN_N_VOLUME | CHN_N_TRIGGER; 1151 1152 if (flags & CHN_N_RATE) { 1153 /* 1154 * we could do something here, like scan children and decide on 1155 * the most appropriate rate to mix at, but we don't for now 1156 */ 1157 } 1158 if (flags & CHN_N_FORMAT) { 1159 /* 1160 * we could do something here, like scan children and decide on 1161 * the most appropriate mixer feeder to use, but we don't for now 1162 */ 1163 } 1164 if (flags & CHN_N_VOLUME) { 1165 /* 1166 * we could do something here but we don't for now 1167 */ 1168 } 1169 if (flags & CHN_N_BLOCKSIZE) { 1170 int blksz; 1171 /* 1172 * scan the children, find the lowest blocksize and use that 1173 * for the hard blocksize 1174 */ 1175 blksz = sndbuf_getmaxsize(c->bufhard) / 2; 1176 SLIST_FOREACH(pce, &c->children, link) { 1177 child = pce->channel; 1178 if (sndbuf_getblksz(child->bufhard) < blksz) 1179 blksz = sndbuf_getblksz(child->bufhard); 1180 } 1181 chn_setblocksize(c, 2, blksz); 1182 } 1183 if (flags & CHN_N_TRIGGER) { 1184 int nrun; 1185 /* 1186 * scan the children, and figure out if any are running 1187 * if so, we need to be running, otherwise we need to be stopped 1188 * if we aren't in our target sstate, move to it 1189 */ 1190 nrun = 0; 1191 SLIST_FOREACH(pce, &c->children, link) { 1192 child = pce->channel; 1193 if (child->flags & CHN_F_TRIGGERED) 1194 nrun = 1; 1195 } 1196 if (nrun && !run) 1197 chn_start(c, 1); 1198 if (!nrun && run) 1199 chn_abort(c); 1200 } 1201 return 0; 1202 } 1203