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