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