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