1 /*- 2 * Copyright (c) 1999 Cameron Grant <cg@freebsd.org> 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 * $FreeBSD: src/sys/dev/sound/pcm/buffer.c,v 1.25.2.3 2007/04/26 08:21:43 ariff Exp $ 27 * $DragonFly: src/sys/dev/sound/pcm/buffer.c,v 1.11 2008/01/06 16:55:51 swildner Exp $ 28 */ 29 30 #include <dev/sound/pcm/sound.h> 31 32 #include "feeder_if.h" 33 34 SND_DECLARE_FILE("$DragonFly: src/sys/dev/sound/pcm/buffer.c,v 1.11 2008/01/06 16:55:51 swildner Exp $"); 35 36 /* 37 * sndbuf_seltask is a taskqueue callback routine, called from 38 * taskqueue_swi, which runs under the MP lock. 39 * 40 * The only purpose is to be able to selwakeup() from a sound 41 * interrupt, which is running without MP lock held and thus 42 * can't call selwakeup() directly. 43 */ 44 static void 45 sndbuf_seltask(void *context, int pending) 46 { 47 struct snd_dbuf *b = context; 48 struct selinfo *si = sndbuf_getsel(b); 49 50 selwakeup(si); 51 KNOTE(&si->si_note, 0); 52 } 53 54 struct snd_dbuf * 55 sndbuf_create(device_t dev, char *drv, char *desc, struct pcm_channel *channel) 56 { 57 struct snd_dbuf *b; 58 59 b = kmalloc(sizeof(*b), M_DEVBUF, M_WAITOK | M_ZERO); 60 ksnprintf(b->name, SNDBUF_NAMELEN, "%s:%s", drv, desc); 61 b->dev = dev; 62 b->channel = channel; 63 TASK_INIT(&b->seltask, 0, sndbuf_seltask, b); 64 65 return b; 66 } 67 68 void 69 sndbuf_destroy(struct snd_dbuf *b) 70 { 71 sndbuf_free(b); 72 kfree(b, M_DEVBUF); 73 } 74 75 bus_addr_t 76 sndbuf_getbufaddr(struct snd_dbuf *buf) 77 { 78 return (buf->buf_addr); 79 } 80 81 static void 82 sndbuf_setmap(void *arg, bus_dma_segment_t *segs, int nseg, int error) 83 { 84 struct snd_dbuf *b = (struct snd_dbuf *)arg; 85 86 if (bootverbose) { 87 device_printf(b->dev, "sndbuf_setmap %lx, %lx; ", 88 (u_long)segs[0].ds_addr, (u_long)segs[0].ds_len); 89 kprintf("%p -> %lx\n", b->buf, (u_long)segs[0].ds_addr); 90 } 91 if (error == 0) 92 b->buf_addr = segs[0].ds_addr; 93 else 94 b->buf_addr = 0; 95 } 96 97 /* 98 * Allocate memory for DMA buffer. If the device does not use DMA transfers, 99 * the driver can call kmalloc(9) and sndbuf_setup() itself. 100 */ 101 102 int 103 sndbuf_alloc(struct snd_dbuf *b, bus_dma_tag_t dmatag, unsigned int size) 104 { 105 int ret; 106 107 b->dmatag = dmatag; 108 b->maxsize = size; 109 b->bufsize = b->maxsize; 110 b->buf_addr = 0; 111 b->flags |= SNDBUF_F_MANAGED; 112 if (bus_dmamem_alloc(b->dmatag, (void **)&b->buf, BUS_DMA_NOWAIT, 113 &b->dmamap)) { 114 sndbuf_free(b); 115 return (ENOMEM); 116 } 117 if (bus_dmamap_load(b->dmatag, b->dmamap, b->buf, b->maxsize, 118 sndbuf_setmap, b, 0) != 0 || b->buf_addr == 0) { 119 sndbuf_free(b); 120 return (ENOMEM); 121 } 122 123 ret = sndbuf_resize(b, 2, b->maxsize / 2); 124 if (ret != 0) 125 sndbuf_free(b); 126 127 return (ret); 128 } 129 130 int 131 sndbuf_setup(struct snd_dbuf *b, void *buf, unsigned int size) 132 { 133 b->flags &= ~SNDBUF_F_MANAGED; 134 if (buf) 135 b->flags |= SNDBUF_F_MANAGED; 136 b->buf = buf; 137 b->maxsize = size; 138 b->bufsize = b->maxsize; 139 return sndbuf_resize(b, 2, b->maxsize / 2); 140 } 141 142 void 143 sndbuf_free(struct snd_dbuf *b) 144 { 145 if (b->tmpbuf) 146 kfree(b->tmpbuf, M_DEVBUF); 147 if (b->buf) { 148 if (b->flags & SNDBUF_F_MANAGED) { 149 if (b->dmamap) 150 bus_dmamap_unload(b->dmatag, b->dmamap); 151 if (b->dmatag) 152 bus_dmamem_free(b->dmatag, b->buf, b->dmamap); 153 } else 154 kfree(b->buf, M_DEVBUF); 155 } 156 157 b->tmpbuf = NULL; 158 b->buf = NULL; 159 b->dmatag = NULL; 160 b->dmamap = NULL; 161 } 162 163 int 164 sndbuf_resize(struct snd_dbuf *b, unsigned int blkcnt, unsigned int blksz) 165 { 166 u_int8_t *tmpbuf, *f2; 167 168 chn_lock(b->channel); 169 if (b->maxsize == 0) 170 goto out; 171 if (blkcnt == 0) 172 blkcnt = b->blkcnt; 173 if (blksz == 0) 174 blksz = b->blksz; 175 if (blkcnt < 2 || blksz < 16 || (blkcnt * blksz > b->maxsize)) { 176 chn_unlock(b->channel); 177 return EINVAL; 178 } 179 if (blkcnt == b->blkcnt && blksz == b->blksz) 180 goto out; 181 182 chn_unlock(b->channel); 183 tmpbuf = kmalloc(blkcnt * blksz, M_DEVBUF, M_NOWAIT); 184 if (tmpbuf == NULL) 185 return ENOMEM; 186 chn_lock(b->channel); 187 b->blkcnt = blkcnt; 188 b->blksz = blksz; 189 b->bufsize = blkcnt * blksz; 190 f2 = b->tmpbuf; 191 b->tmpbuf = tmpbuf; 192 sndbuf_reset(b); 193 chn_unlock(b->channel); 194 if (f2 != NULL) 195 kfree(f2, M_DEVBUF); 196 return 0; 197 out: 198 chn_unlock(b->channel); 199 return 0; 200 } 201 202 int 203 sndbuf_remalloc(struct snd_dbuf *b, unsigned int blkcnt, unsigned int blksz) 204 { 205 u_int8_t *buf, *tmpbuf, *f1, *f2; 206 unsigned int bufsize; 207 int ret; 208 209 if (blkcnt < 2 || blksz < 16) 210 return EINVAL; 211 212 bufsize = blksz * blkcnt; 213 214 chn_unlock(b->channel); 215 buf = kmalloc(bufsize, M_DEVBUF, M_WAITOK); 216 tmpbuf = kmalloc(bufsize, M_DEVBUF, M_WAITOK); 217 chn_lock(b->channel); 218 219 b->blkcnt = blkcnt; 220 b->blksz = blksz; 221 b->bufsize = bufsize; 222 b->maxsize = bufsize; 223 f1 = b->buf; 224 f2 = b->tmpbuf; 225 b->buf = buf; 226 b->tmpbuf = tmpbuf; 227 228 sndbuf_reset(b); 229 230 chn_unlock(b->channel); 231 if (f1) 232 kfree(f1, M_DEVBUF); 233 if (f2) 234 kfree(f2, M_DEVBUF); 235 236 ret = 0; 237 chn_lock(b->channel); 238 return ret; 239 } 240 241 void 242 sndbuf_clear(struct snd_dbuf *b, unsigned int length) 243 { 244 int i; 245 u_char data, *p; 246 247 if (length == 0) 248 return; 249 if (length > b->bufsize) 250 length = b->bufsize; 251 252 if (b->fmt & AFMT_SIGNED) 253 data = 0x00; 254 else 255 data = 0x80; 256 257 i = sndbuf_getfreeptr(b); 258 p = sndbuf_getbuf(b); 259 while (length > 0) { 260 p[i] = data; 261 length--; 262 i++; 263 if (i >= b->bufsize) 264 i = 0; 265 } 266 } 267 268 void 269 sndbuf_fillsilence(struct snd_dbuf *b) 270 { 271 int i; 272 u_char data, *p; 273 274 if (b->fmt & AFMT_SIGNED) 275 data = 0x00; 276 else 277 data = 0x80; 278 279 i = 0; 280 p = sndbuf_getbuf(b); 281 while (i < b->bufsize) 282 p[i++] = data; 283 b->rp = 0; 284 b->rl = b->bufsize; 285 } 286 287 void 288 sndbuf_reset(struct snd_dbuf *b) 289 { 290 b->hp = 0; 291 b->rp = 0; 292 b->rl = 0; 293 b->dl = 0; 294 b->prev_total = 0; 295 b->total = 0; 296 b->xrun = 0; 297 if (b->buf && b->bufsize > 0) 298 sndbuf_clear(b, b->bufsize); 299 } 300 301 u_int32_t 302 sndbuf_getfmt(struct snd_dbuf *b) 303 { 304 return b->fmt; 305 } 306 307 int 308 sndbuf_setfmt(struct snd_dbuf *b, u_int32_t fmt) 309 { 310 b->fmt = fmt; 311 b->bps = 1; 312 b->bps <<= (b->fmt & AFMT_STEREO)? 1 : 0; 313 if (b->fmt & AFMT_16BIT) 314 b->bps <<= 1; 315 else if (b->fmt & AFMT_24BIT) 316 b->bps *= 3; 317 else if (b->fmt & AFMT_32BIT) 318 b->bps <<= 2; 319 return 0; 320 } 321 322 unsigned int 323 sndbuf_getspd(struct snd_dbuf *b) 324 { 325 return b->spd; 326 } 327 328 void 329 sndbuf_setspd(struct snd_dbuf *b, unsigned int spd) 330 { 331 b->spd = spd; 332 } 333 334 unsigned int 335 sndbuf_getalign(struct snd_dbuf *b) 336 { 337 static int align[] = {0, 1, 1, 2, 2, 2, 2, 3}; 338 339 return align[b->bps - 1]; 340 } 341 342 unsigned int 343 sndbuf_getblkcnt(struct snd_dbuf *b) 344 { 345 return b->blkcnt; 346 } 347 348 void 349 sndbuf_setblkcnt(struct snd_dbuf *b, unsigned int blkcnt) 350 { 351 b->blkcnt = blkcnt; 352 } 353 354 unsigned int 355 sndbuf_getblksz(struct snd_dbuf *b) 356 { 357 return b->blksz; 358 } 359 360 void 361 sndbuf_setblksz(struct snd_dbuf *b, unsigned int blksz) 362 { 363 b->blksz = blksz; 364 } 365 366 unsigned int 367 sndbuf_getbps(struct snd_dbuf *b) 368 { 369 return b->bps; 370 } 371 372 void * 373 sndbuf_getbuf(struct snd_dbuf *b) 374 { 375 return b->buf; 376 } 377 378 void * 379 sndbuf_getbufofs(struct snd_dbuf *b, unsigned int ofs) 380 { 381 KASSERT(ofs < b->bufsize, ("%s: ofs invalid %d", __func__, ofs)); 382 383 return b->buf + ofs; 384 } 385 386 unsigned int 387 sndbuf_getsize(struct snd_dbuf *b) 388 { 389 return b->bufsize; 390 } 391 392 unsigned int 393 sndbuf_getmaxsize(struct snd_dbuf *b) 394 { 395 return b->maxsize; 396 } 397 398 unsigned int 399 sndbuf_runsz(struct snd_dbuf *b) 400 { 401 return b->dl; 402 } 403 404 void 405 sndbuf_setrun(struct snd_dbuf *b, int go) 406 { 407 b->dl = go? b->blksz : 0; 408 } 409 410 struct selinfo * 411 sndbuf_getsel(struct snd_dbuf *b) 412 { 413 return &b->sel; 414 } 415 416 /************************************************************/ 417 unsigned int 418 sndbuf_getxrun(struct snd_dbuf *b) 419 { 420 SNDBUF_LOCKASSERT(b); 421 422 return b->xrun; 423 } 424 425 void 426 sndbuf_setxrun(struct snd_dbuf *b, unsigned int cnt) 427 { 428 SNDBUF_LOCKASSERT(b); 429 430 b->xrun = cnt; 431 } 432 433 unsigned int 434 sndbuf_gethwptr(struct snd_dbuf *b) 435 { 436 SNDBUF_LOCKASSERT(b); 437 438 return b->hp; 439 } 440 441 void 442 sndbuf_sethwptr(struct snd_dbuf *b, unsigned int ptr) 443 { 444 SNDBUF_LOCKASSERT(b); 445 446 b->hp = ptr; 447 } 448 449 unsigned int 450 sndbuf_getready(struct snd_dbuf *b) 451 { 452 SNDBUF_LOCKASSERT(b); 453 KASSERT((b->rl >= 0) && (b->rl <= b->bufsize), ("%s: b->rl invalid %d", __func__, b->rl)); 454 455 return b->rl; 456 } 457 458 unsigned int 459 sndbuf_getreadyptr(struct snd_dbuf *b) 460 { 461 SNDBUF_LOCKASSERT(b); 462 KASSERT((b->rp >= 0) && (b->rp <= b->bufsize), ("%s: b->rp invalid %d", __func__, b->rp)); 463 464 return b->rp; 465 } 466 467 unsigned int 468 sndbuf_getfree(struct snd_dbuf *b) 469 { 470 SNDBUF_LOCKASSERT(b); 471 KASSERT((b->rl >= 0) && (b->rl <= b->bufsize), ("%s: b->rl invalid %d", __func__, b->rl)); 472 473 return b->bufsize - b->rl; 474 } 475 476 unsigned int 477 sndbuf_getfreeptr(struct snd_dbuf *b) 478 { 479 SNDBUF_LOCKASSERT(b); 480 KASSERT((b->rp >= 0) && (b->rp <= b->bufsize), ("%s: b->rp invalid %d", __func__, b->rp)); 481 KASSERT((b->rl >= 0) && (b->rl <= b->bufsize), ("%s: b->rl invalid %d", __func__, b->rl)); 482 483 return (b->rp + b->rl) % b->bufsize; 484 } 485 486 unsigned int 487 sndbuf_getblocks(struct snd_dbuf *b) 488 { 489 SNDBUF_LOCKASSERT(b); 490 491 return b->total / b->blksz; 492 } 493 494 unsigned int 495 sndbuf_getprevblocks(struct snd_dbuf *b) 496 { 497 SNDBUF_LOCKASSERT(b); 498 499 return b->prev_total / b->blksz; 500 } 501 502 unsigned int 503 sndbuf_gettotal(struct snd_dbuf *b) 504 { 505 SNDBUF_LOCKASSERT(b); 506 507 return b->total; 508 } 509 510 void 511 sndbuf_updateprevtotal(struct snd_dbuf *b) 512 { 513 SNDBUF_LOCKASSERT(b); 514 515 b->prev_total = b->total; 516 } 517 518 /************************************************************/ 519 520 int 521 sndbuf_acquire(struct snd_dbuf *b, u_int8_t *from, unsigned int count) 522 { 523 int l; 524 525 KASSERT(count <= sndbuf_getfree(b), ("%s: count %d > kfree %d", __func__, count, sndbuf_getfree(b))); 526 KASSERT((b->rl >= 0) && (b->rl <= b->bufsize), ("%s: b->rl invalid %d", __func__, b->rl)); 527 b->total += count; 528 if (from != NULL) { 529 while (count > 0) { 530 l = MIN(count, sndbuf_getsize(b) - sndbuf_getfreeptr(b)); 531 bcopy(from, sndbuf_getbufofs(b, sndbuf_getfreeptr(b)), l); 532 from += l; 533 b->rl += l; 534 count -= l; 535 } 536 } else 537 b->rl += count; 538 KASSERT((b->rl >= 0) && (b->rl <= b->bufsize), ("%s: b->rl invalid %d, count %d", __func__, b->rl, count)); 539 540 return 0; 541 } 542 543 int 544 sndbuf_dispose(struct snd_dbuf *b, u_int8_t *to, unsigned int count) 545 { 546 int l; 547 548 KASSERT(count <= sndbuf_getready(b), ("%s: count %d > ready %d", __func__, count, sndbuf_getready(b))); 549 KASSERT((b->rl >= 0) && (b->rl <= b->bufsize), ("%s: b->rl invalid %d", __func__, b->rl)); 550 if (to != NULL) { 551 while (count > 0) { 552 l = MIN(count, sndbuf_getsize(b) - sndbuf_getreadyptr(b)); 553 bcopy(sndbuf_getbufofs(b, sndbuf_getreadyptr(b)), to, l); 554 to += l; 555 b->rl -= l; 556 b->rp = (b->rp + l) % b->bufsize; 557 count -= l; 558 } 559 } else { 560 b->rl -= count; 561 b->rp = (b->rp + count) % b->bufsize; 562 } 563 KASSERT((b->rl >= 0) && (b->rl <= b->bufsize), ("%s: b->rl invalid %d, count %d", __func__, b->rl, count)); 564 565 return 0; 566 } 567 568 /* count is number of bytes we want added to destination buffer */ 569 int 570 sndbuf_feed(struct snd_dbuf *from, struct snd_dbuf *to, struct pcm_channel *channel, struct pcm_feeder *feeder, unsigned int count) 571 { 572 KASSERT(count > 0, ("can't feed 0 bytes")); 573 574 if (sndbuf_getfree(to) < count) 575 return EINVAL; 576 577 count = FEEDER_FEED(feeder, channel, to->tmpbuf, count, from); 578 if (count) 579 sndbuf_acquire(to, to->tmpbuf, count); 580 /* the root feeder has called sndbuf_dispose(from, , bytes fetched) */ 581 582 return 0; 583 } 584 585 /************************************************************/ 586 587 void 588 sndbuf_dump(struct snd_dbuf *b, char *s, u_int32_t what) 589 { 590 kprintf("%s: [", s); 591 if (what & 0x01) 592 kprintf(" bufsize: %d, maxsize: %d", b->bufsize, b->maxsize); 593 if (what & 0x02) 594 kprintf(" dl: %d, rp: %d, rl: %d, hp: %d", b->dl, b->rp, b->rl, b->hp); 595 if (what & 0x04) 596 kprintf(" total: %d, prev_total: %d, xrun: %d", b->total, b->prev_total, b->xrun); 597 if (what & 0x08) 598 kprintf(" fmt: 0x%x, spd: %d", b->fmt, b->spd); 599 if (what & 0x10) 600 kprintf(" blksz: %d, blkcnt: %d, flags: 0x%x", b->blksz, b->blkcnt, b->flags); 601 kprintf(" ]\n"); 602 } 603 604 /************************************************************/ 605 u_int32_t 606 sndbuf_getflags(struct snd_dbuf *b) 607 { 608 return b->flags; 609 } 610 611 void 612 sndbuf_setflags(struct snd_dbuf *b, u_int32_t flags, int on) 613 { 614 b->flags &= ~flags; 615 if (on) 616 b->flags |= flags; 617 } 618