1 /* 2 * Copyright (c) 1999 Cameron Grant <gandalf@vilnya.demon.co.uk> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27 #include <dev/sound/pcm/sound.h> 28 29 #include "feeder_if.h" 30 31 SND_DECLARE_FILE("$FreeBSD$"); 32 33 #define SNDBUF_NAMELEN 48 34 struct snd_dbuf { 35 device_t dev; 36 u_int8_t *buf, *tmpbuf; 37 unsigned int bufsize, maxsize; 38 volatile int dl; /* transfer size */ 39 volatile int rp; /* pointers to the ready area */ 40 volatile int rl; /* length of ready area */ 41 volatile int hp; 42 volatile u_int32_t total, prev_total; 43 int isadmachan, dir; /* dma channel */ 44 u_int32_t fmt, spd, bps; 45 unsigned int blksz, blkcnt; 46 int xrun; 47 u_int32_t flags; 48 bus_dmamap_t dmamap; 49 bus_dma_tag_t dmatag; 50 struct selinfo sel; 51 char name[SNDBUF_NAMELEN]; 52 }; 53 54 struct snd_dbuf * 55 sndbuf_create(device_t dev, char *drv, char *desc) 56 { 57 struct snd_dbuf *b; 58 59 b = malloc(sizeof(*b), M_DEVBUF, M_ZERO); 60 snprintf(b->name, SNDBUF_NAMELEN, "%s:%s", drv, desc); 61 b->dev = dev; 62 63 return b; 64 } 65 66 void 67 sndbuf_destroy(struct snd_dbuf *b) 68 { 69 free(b, M_DEVBUF); 70 } 71 72 static void 73 sndbuf_setmap(void *arg, bus_dma_segment_t *segs, int nseg, int error) 74 { 75 struct snd_dbuf *b = (struct snd_dbuf *)arg; 76 77 if (bootverbose) { 78 device_printf(b->dev, "sndbuf_setmap %lx, %lx; ", (unsigned long)segs->ds_addr, 79 (unsigned long)segs->ds_len); 80 printf("%p -> %lx\n", b->buf, (unsigned long)vtophys(b->buf)); 81 } 82 } 83 84 /* 85 * Allocate memory for DMA buffer. If the device does not use DMA transfers, 86 * the driver can call malloc(9) and sndbuf_setup() itself. 87 */ 88 int 89 sndbuf_alloc(struct snd_dbuf *b, bus_dma_tag_t dmatag, unsigned int size) 90 { 91 b->dmatag = dmatag; 92 b->maxsize = size; 93 b->bufsize = b->maxsize; 94 if (bus_dmamem_alloc(b->dmatag, (void **)&b->buf, BUS_DMA_NOWAIT, &b->dmamap)) 95 return ENOSPC; 96 if (bus_dmamap_load(b->dmatag, b->dmamap, b->buf, b->maxsize, sndbuf_setmap, b, 0)) 97 return ENOSPC; 98 return sndbuf_resize(b, 2, b->maxsize / 2); 99 } 100 101 int 102 sndbuf_setup(struct snd_dbuf *b, void *buf, unsigned int size) 103 { 104 b->buf = buf; 105 b->maxsize = size; 106 b->bufsize = b->maxsize; 107 return sndbuf_resize(b, 2, b->maxsize / 2); 108 } 109 110 void 111 sndbuf_free(struct snd_dbuf *b) 112 { 113 if (b->tmpbuf) 114 free(b->tmpbuf, M_DEVBUF); 115 b->tmpbuf = NULL; 116 117 if (b->dmamap) 118 bus_dmamap_unload(b->dmatag, b->dmamap); 119 120 if (b->dmamap && b->buf) 121 bus_dmamem_free(b->dmatag, b->buf, b->dmamap); 122 b->dmamap = NULL; 123 b->buf = NULL; 124 } 125 126 int 127 sndbuf_resize(struct snd_dbuf *b, unsigned int blkcnt, unsigned int blksz) 128 { 129 if (b->maxsize == 0) 130 return 0; 131 if (blkcnt == 0) 132 blkcnt = b->blkcnt; 133 if (blksz == 0) 134 blksz = b->blksz; 135 if (blkcnt < 2 || blksz < 16 || (blkcnt * blksz > b->maxsize)) 136 return EINVAL; 137 if (blkcnt == b->blkcnt && blksz == b->blksz) 138 return 0; 139 b->blkcnt = blkcnt; 140 b->blksz = blksz; 141 b->bufsize = blkcnt * blksz; 142 if (b->tmpbuf) 143 free(b->tmpbuf, M_DEVBUF); 144 b->tmpbuf = malloc(b->bufsize, M_DEVBUF, M_NOWAIT); 145 sndbuf_reset(b); 146 return 0; 147 } 148 149 int 150 sndbuf_remalloc(struct snd_dbuf *b, unsigned int blkcnt, unsigned int blksz) 151 { 152 u_int8_t *buf, *tmpbuf, *f1, *f2; 153 unsigned int bufsize; 154 155 if (blkcnt < 2 || blksz < 16) 156 return EINVAL; 157 158 bufsize = blksz * blkcnt; 159 160 161 buf = malloc(bufsize, M_DEVBUF, M_NOWAIT); 162 if (buf == NULL) 163 return ENOMEM; 164 165 tmpbuf = malloc(bufsize, M_DEVBUF, M_NOWAIT); 166 if (tmpbuf == NULL) { 167 free(buf, M_DEVBUF); 168 return ENOMEM; 169 } 170 171 b->blkcnt = blkcnt; 172 b->blksz = blksz; 173 b->bufsize = bufsize; 174 b->maxsize = bufsize; 175 f1 = b->buf; 176 f2 = b->tmpbuf; 177 b->buf = buf; 178 b->tmpbuf = tmpbuf; 179 180 if (f1) 181 free(f1, M_DEVBUF); 182 if (f2) 183 free(f2, M_DEVBUF); 184 185 sndbuf_reset(b); 186 return 0; 187 } 188 189 void 190 sndbuf_clear(struct snd_dbuf *b, unsigned int length) 191 { 192 int i; 193 u_char data, *p; 194 195 if (length == 0) 196 return; 197 if (length > b->bufsize) 198 length = b->bufsize; 199 200 if (b->fmt & AFMT_SIGNED) 201 data = 0x00; 202 else 203 data = 0x80; 204 205 i = sndbuf_getfreeptr(b); 206 p = sndbuf_getbuf(b); 207 while (length > 0) { 208 p[i] = data; 209 length--; 210 i++; 211 if (i >= b->bufsize) 212 i = 0; 213 } 214 } 215 216 void 217 sndbuf_fillsilence(struct snd_dbuf *b) 218 { 219 int i; 220 u_char data, *p; 221 222 if (b->fmt & AFMT_SIGNED) 223 data = 0x00; 224 else 225 data = 0x80; 226 227 i = 0; 228 p = sndbuf_getbuf(b); 229 while (i < b->bufsize) 230 p[i++] = data; 231 b->rp = 0; 232 b->rl = b->bufsize; 233 } 234 235 void 236 sndbuf_reset(struct snd_dbuf *b) 237 { 238 b->hp = 0; 239 b->rp = 0; 240 b->rl = 0; 241 b->dl = 0; 242 b->prev_total = 0; 243 b->total = 0; 244 b->xrun = 0; 245 if (b->buf && b->bufsize > 0) 246 sndbuf_clear(b, b->bufsize); 247 } 248 249 u_int32_t 250 sndbuf_getfmt(struct snd_dbuf *b) 251 { 252 return b->fmt; 253 } 254 255 int 256 sndbuf_setfmt(struct snd_dbuf *b, u_int32_t fmt) 257 { 258 b->fmt = fmt; 259 b->bps = 1; 260 b->bps <<= (b->fmt & AFMT_STEREO)? 1 : 0; 261 b->bps <<= (b->fmt & AFMT_16BIT)? 1 : 0; 262 b->bps <<= (b->fmt & AFMT_32BIT)? 2 : 0; 263 return 0; 264 } 265 266 unsigned int 267 sndbuf_getspd(struct snd_dbuf *b) 268 { 269 return b->spd; 270 } 271 272 void 273 sndbuf_setspd(struct snd_dbuf *b, unsigned int spd) 274 { 275 b->spd = spd; 276 } 277 278 unsigned int 279 sndbuf_getalign(struct snd_dbuf *b) 280 { 281 static int align[] = {0, 1, 1, 2, 2, 2, 2, 3}; 282 283 return align[b->bps - 1]; 284 } 285 286 unsigned int 287 sndbuf_getblkcnt(struct snd_dbuf *b) 288 { 289 return b->blkcnt; 290 } 291 292 void 293 sndbuf_setblkcnt(struct snd_dbuf *b, unsigned int blkcnt) 294 { 295 b->blkcnt = blkcnt; 296 } 297 298 unsigned int 299 sndbuf_getblksz(struct snd_dbuf *b) 300 { 301 return b->blksz; 302 } 303 304 void 305 sndbuf_setblksz(struct snd_dbuf *b, unsigned int blksz) 306 { 307 b->blksz = blksz; 308 } 309 310 unsigned int 311 sndbuf_getbps(struct snd_dbuf *b) 312 { 313 return b->bps; 314 } 315 316 void * 317 sndbuf_getbuf(struct snd_dbuf *b) 318 { 319 return b->buf; 320 } 321 322 void * 323 sndbuf_getbufofs(struct snd_dbuf *b, unsigned int ofs) 324 { 325 KASSERT(ofs < b->bufsize, ("%s: ofs invalid %d", __func__, ofs)); 326 327 return b->buf + ofs; 328 } 329 330 unsigned int 331 sndbuf_getsize(struct snd_dbuf *b) 332 { 333 return b->bufsize; 334 } 335 336 unsigned int 337 sndbuf_getmaxsize(struct snd_dbuf *b) 338 { 339 return b->maxsize; 340 } 341 342 unsigned int 343 sndbuf_runsz(struct snd_dbuf *b) 344 { 345 return b->dl; 346 } 347 348 void 349 sndbuf_setrun(struct snd_dbuf *b, int go) 350 { 351 b->dl = go? b->blksz : 0; 352 } 353 354 struct selinfo * 355 sndbuf_getsel(struct snd_dbuf *b) 356 { 357 return &b->sel; 358 } 359 360 /************************************************************/ 361 unsigned int 362 sndbuf_getxrun(struct snd_dbuf *b) 363 { 364 SNDBUF_LOCKASSERT(b); 365 366 return b->xrun; 367 } 368 369 void 370 sndbuf_setxrun(struct snd_dbuf *b, unsigned int cnt) 371 { 372 SNDBUF_LOCKASSERT(b); 373 374 b->xrun = cnt; 375 } 376 377 unsigned int 378 sndbuf_gethwptr(struct snd_dbuf *b) 379 { 380 SNDBUF_LOCKASSERT(b); 381 382 return b->hp; 383 } 384 385 void 386 sndbuf_sethwptr(struct snd_dbuf *b, unsigned int ptr) 387 { 388 SNDBUF_LOCKASSERT(b); 389 390 b->hp = ptr; 391 } 392 393 unsigned int 394 sndbuf_getready(struct snd_dbuf *b) 395 { 396 SNDBUF_LOCKASSERT(b); 397 KASSERT((b->rl >= 0) && (b->rl <= b->bufsize), ("%s: b->rl invalid %d", __func__, b->rl)); 398 399 return b->rl; 400 } 401 402 unsigned int 403 sndbuf_getreadyptr(struct snd_dbuf *b) 404 { 405 SNDBUF_LOCKASSERT(b); 406 KASSERT((b->rp >= 0) && (b->rp <= b->bufsize), ("%s: b->rp invalid %d", __func__, b->rp)); 407 408 return b->rp; 409 } 410 411 unsigned int 412 sndbuf_getfree(struct snd_dbuf *b) 413 { 414 SNDBUF_LOCKASSERT(b); 415 KASSERT((b->rl >= 0) && (b->rl <= b->bufsize), ("%s: b->rl invalid %d", __func__, b->rl)); 416 417 return b->bufsize - b->rl; 418 } 419 420 unsigned int 421 sndbuf_getfreeptr(struct snd_dbuf *b) 422 { 423 SNDBUF_LOCKASSERT(b); 424 KASSERT((b->rp >= 0) && (b->rp <= b->bufsize), ("%s: b->rp invalid %d", __func__, b->rp)); 425 KASSERT((b->rl >= 0) && (b->rl <= b->bufsize), ("%s: b->rl invalid %d", __func__, b->rl)); 426 427 return (b->rp + b->rl) % b->bufsize; 428 } 429 430 unsigned int 431 sndbuf_getblocks(struct snd_dbuf *b) 432 { 433 SNDBUF_LOCKASSERT(b); 434 435 return b->total / b->blksz; 436 } 437 438 unsigned int 439 sndbuf_getprevblocks(struct snd_dbuf *b) 440 { 441 SNDBUF_LOCKASSERT(b); 442 443 return b->prev_total / b->blksz; 444 } 445 446 unsigned int 447 sndbuf_gettotal(struct snd_dbuf *b) 448 { 449 SNDBUF_LOCKASSERT(b); 450 451 return b->total; 452 } 453 454 void 455 sndbuf_updateprevtotal(struct snd_dbuf *b) 456 { 457 SNDBUF_LOCKASSERT(b); 458 459 b->prev_total = b->total; 460 } 461 462 /************************************************************/ 463 464 int 465 sndbuf_acquire(struct snd_dbuf *b, u_int8_t *from, unsigned int count) 466 { 467 int l; 468 469 KASSERT(count <= sndbuf_getfree(b), ("%s: count %d > free %d", __func__, count, sndbuf_getfree(b))); 470 KASSERT((b->rl >= 0) && (b->rl <= b->bufsize), ("%s: b->rl invalid %d", __func__, b->rl)); 471 b->total += count; 472 if (from != NULL) { 473 while (count > 0) { 474 l = MIN(count, sndbuf_getsize(b) - sndbuf_getfreeptr(b)); 475 bcopy(from, sndbuf_getbufofs(b, sndbuf_getfreeptr(b)), l); 476 from += l; 477 b->rl += l; 478 count -= l; 479 } 480 } else 481 b->rl += count; 482 KASSERT((b->rl >= 0) && (b->rl <= b->bufsize), ("%s: b->rl invalid %d, count %d", __func__, b->rl, count)); 483 484 return 0; 485 } 486 487 int 488 sndbuf_dispose(struct snd_dbuf *b, u_int8_t *to, unsigned int count) 489 { 490 int l; 491 492 KASSERT(count <= sndbuf_getready(b), ("%s: count %d > ready %d", __func__, count, sndbuf_getready(b))); 493 KASSERT((b->rl >= 0) && (b->rl <= b->bufsize), ("%s: b->rl invalid %d", __func__, b->rl)); 494 if (to != NULL) { 495 while (count > 0) { 496 l = MIN(count, sndbuf_getsize(b) - sndbuf_getreadyptr(b)); 497 bcopy(sndbuf_getbufofs(b, sndbuf_getreadyptr(b)), to, l); 498 to += l; 499 b->rl -= l; 500 b->rp = (b->rp + l) % b->bufsize; 501 count -= l; 502 } 503 } else { 504 b->rl -= count; 505 b->rp = (b->rp + count) % b->bufsize; 506 } 507 KASSERT((b->rl >= 0) && (b->rl <= b->bufsize), ("%s: b->rl invalid %d, count %d", __func__, b->rl, count)); 508 509 return 0; 510 } 511 512 int 513 sndbuf_uiomove(struct snd_dbuf *b, struct uio *uio, unsigned int count) 514 { 515 int x, c, p, rd, err; 516 517 err = 0; 518 rd = (uio->uio_rw == UIO_READ)? 1 : 0; 519 if (count > uio->uio_resid) 520 return EINVAL; 521 522 if (count > (rd? sndbuf_getready(b) : sndbuf_getfree(b))) { 523 return EINVAL; 524 } 525 526 while (err == 0 && count > 0) { 527 p = rd? sndbuf_getreadyptr(b) : sndbuf_getfreeptr(b); 528 c = MIN(count, sndbuf_getsize(b) - p); 529 x = uio->uio_resid; 530 err = uiomove(sndbuf_getbufofs(b, p), c, uio); 531 x -= uio->uio_resid; 532 count -= x; 533 x = rd? sndbuf_dispose(b, NULL, x) : sndbuf_acquire(b, NULL, x); 534 } 535 536 return 0; 537 } 538 539 /* count is number of bytes we want added to destination buffer */ 540 int 541 sndbuf_feed(struct snd_dbuf *from, struct snd_dbuf *to, struct pcm_channel *channel, struct pcm_feeder *feeder, unsigned int count) 542 { 543 KASSERT(count > 0, ("can't feed 0 bytes")); 544 545 if (sndbuf_getfree(to) < count) 546 return EINVAL; 547 548 count = FEEDER_FEED(feeder, channel, to->tmpbuf, count, from); 549 if (count) 550 sndbuf_acquire(to, to->tmpbuf, count); 551 /* the root feeder has called sndbuf_dispose(from, , bytes fetched) */ 552 553 return 0; 554 } 555 556 /************************************************************/ 557 558 void 559 sndbuf_dump(struct snd_dbuf *b, char *s, u_int32_t what) 560 { 561 printf("%s: [", s); 562 if (what & 0x01) 563 printf(" bufsize: %d, maxsize: %d", b->bufsize, b->maxsize); 564 if (what & 0x02) 565 printf(" dl: %d, rp: %d, rl: %d, hp: %d", b->dl, b->rp, b->rl, b->hp); 566 if (what & 0x04) 567 printf(" total: %d, prev_total: %d, xrun: %d", b->total, b->prev_total, b->xrun); 568 if (what & 0x08) 569 printf(" fmt: 0x%x, spd: %d", b->fmt, b->spd); 570 if (what & 0x10) 571 printf(" blksz: %d, blkcnt: %d, flags: 0x%x", b->blksz, b->blkcnt, b->flags); 572 printf(" ]\n"); 573 } 574 575 /************************************************************/ 576 u_int32_t 577 sndbuf_getflags(struct snd_dbuf *b) 578 { 579 return b->flags; 580 } 581 582 void 583 sndbuf_setflags(struct snd_dbuf *b, u_int32_t flags, int on) 584 { 585 b->flags &= ~flags; 586 if (on) 587 b->flags |= flags; 588 } 589 590 /************************************************************/ 591 592 int 593 sndbuf_isadmasetup(struct snd_dbuf *b, struct resource *drq) 594 { 595 /* should do isa_dma_acquire/isa_dma_release here */ 596 if (drq == NULL) { 597 b->isadmachan = -1; 598 } else { 599 sndbuf_setflags(b, SNDBUF_F_ISADMA, 1); 600 b->isadmachan = rman_get_start(drq); 601 } 602 return 0; 603 } 604 605 int 606 sndbuf_isadmasetdir(struct snd_dbuf *b, int dir) 607 { 608 KASSERT(b, ("sndbuf_isadmasetdir called with b == NULL")); 609 KASSERT(sndbuf_getflags(b) & SNDBUF_F_ISADMA, ("sndbuf_isadmasetdir called on non-ISA buffer")); 610 611 b->dir = (dir == PCMDIR_PLAY)? ISADMA_WRITE : ISADMA_READ; 612 return 0; 613 } 614 615 void 616 sndbuf_isadma(struct snd_dbuf *b, int go) 617 { 618 KASSERT(b, ("sndbuf_isadma called with b == NULL")); 619 KASSERT(sndbuf_getflags(b) & SNDBUF_F_ISADMA, ("sndbuf_isadma called on non-ISA buffer")); 620 621 switch (go) { 622 case PCMTRIG_START: 623 /* isa_dmainit(b->chan, size); */ 624 isa_dmastart(b->dir | ISADMA_RAW, b->buf, b->bufsize, b->isadmachan); 625 break; 626 627 case PCMTRIG_STOP: 628 case PCMTRIG_ABORT: 629 isa_dmastop(b->isadmachan); 630 isa_dmadone(b->dir | ISADMA_RAW, b->buf, b->bufsize, b->isadmachan); 631 break; 632 } 633 634 DEB(printf("buf 0x%p ISA DMA %s, channel %d\n", 635 b, 636 (go == PCMTRIG_START)? "started" : "stopped", 637 b->isadmachan)); 638 } 639 640 int 641 sndbuf_isadmaptr(struct snd_dbuf *b) 642 { 643 int i; 644 645 KASSERT(b, ("sndbuf_isadmaptr called with b == NULL")); 646 KASSERT(sndbuf_getflags(b) & SNDBUF_F_ISADMA, ("sndbuf_isadmaptr called on non-ISA buffer")); 647 648 if (!sndbuf_runsz(b)) 649 return 0; 650 i = isa_dmastatus(b->isadmachan); 651 KASSERT(i >= 0, ("isa_dmastatus returned %d", i)); 652 return b->bufsize - i; 653 } 654 655 void 656 sndbuf_isadmabounce(struct snd_dbuf *b) 657 { 658 KASSERT(b, ("sndbuf_isadmabounce called with b == NULL")); 659 KASSERT(sndbuf_getflags(b) & SNDBUF_F_ISADMA, ("sndbuf_isadmabounce called on non-ISA buffer")); 660 661 /* tell isa_dma to bounce data in/out */ 662 } 663 664