45f5d8f261da9bad77b54deae602aacfe30fef4e
[dragonfly.git] / sys / dev / sound / pcm / channel.c
1 /*-
2  * Copyright (c) 1999 Cameron Grant <cg@freebsd.org>
3  * Portions Copyright by Luigi Rizzo - 1997-99
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  *
27  * $FreeBSD: src/sys/dev/sound/pcm/channel.c,v 1.99.2.5 2007/05/13 20:53:39 ariff Exp $
28  * $DragonFly: src/sys/dev/sound/pcm/channel.c,v 1.15 2008/01/05 13:34:22 corecode Exp $
29  */
30
31 #include "use_isa.h"
32
33 #include <dev/sound/pcm/sound.h>
34 #include <sys/vnode.h>          /* IO_NDELAY */
35
36 #include "feeder_if.h"
37
38 SND_DECLARE_FILE("$DragonFly: src/sys/dev/sound/pcm/channel.c,v 1.15 2008/01/05 13:34:22 corecode Exp $");
39
40 #define MIN_CHUNK_SIZE          256     /* for uiomove etc. */
41 #if 0
42 #define DMA_ALIGN_THRESHOLD     4
43 #define DMA_ALIGN_MASK          (~(DMA_ALIGN_THRESHOLD - 1))
44 #endif
45
46 #define CANCHANGE(c) (!(c->flags & CHN_F_TRIGGERED))
47
48 /*
49 #define DEB(x) x
50 */
51
52 static int chn_targetirqrate = 32;
53 TUNABLE_INT("hw.snd.targetirqrate", &chn_targetirqrate);
54
55 static int
56 sysctl_hw_snd_targetirqrate(SYSCTL_HANDLER_ARGS)
57 {
58         int err, val;
59
60         val = chn_targetirqrate;
61         err = sysctl_handle_int(oidp, &val, sizeof(val), req);
62         if (val < 16 || val > 512)
63                 err = EINVAL;
64         else
65                 chn_targetirqrate = val;
66
67         return err;
68 }
69 SYSCTL_PROC(_hw_snd, OID_AUTO, targetirqrate, CTLTYPE_INT | CTLFLAG_RW,
70         0, sizeof(int), sysctl_hw_snd_targetirqrate, "I", "");
71 static int report_soft_formats = 1;
72 SYSCTL_INT(_hw_snd, OID_AUTO, report_soft_formats, CTLFLAG_RW,
73         &report_soft_formats, 1, "report software-emulated formats");
74
75 static int chn_buildfeeder(struct pcm_channel *c);
76
77 static void
78 chn_lockinit(struct pcm_channel *c, int dir)
79 {
80         switch(dir) {
81         case PCMDIR_PLAY:
82                 c->lock = snd_mtxcreate(c->name, "pcm play channel");
83                 break;
84         case PCMDIR_REC:
85                 c->lock = snd_mtxcreate(c->name, "pcm record channel");
86                 break;
87         case PCMDIR_VIRTUAL:
88                 c->lock = snd_mtxcreate(c->name, "pcm virtual play channel");
89                 break;
90         case 0:
91                 c->lock = snd_mtxcreate(c->name, "pcm fake channel");
92                 break;
93         }
94 }
95
96 static void
97 chn_lockdestroy(struct pcm_channel *c)
98 {
99         snd_mtxfree(c->lock);
100 }
101
102 static int
103 chn_polltrigger(struct pcm_channel *c)
104 {
105         struct snd_dbuf *bs = c->bufsoft;
106         unsigned amt, lim;
107
108         CHN_LOCKASSERT(c);
109         if (c->flags & CHN_F_MAPPED) {
110                 if (sndbuf_getprevblocks(bs) == 0)
111                         return 1;
112                 else
113                         return (sndbuf_getblocks(bs) > sndbuf_getprevblocks(bs))? 1 : 0;
114         } else {
115                 amt = (c->direction == PCMDIR_PLAY)? sndbuf_getfree(bs) : sndbuf_getready(bs);
116 #if 0
117                 lim = (c->flags & CHN_F_HAS_SIZE)? sndbuf_getblksz(bs) : 1;
118 #endif
119                 lim = 1;
120                 return (amt >= lim)? 1 : 0;
121         }
122         return 0;
123 }
124
125 static int
126 chn_pollreset(struct pcm_channel *c)
127 {
128         struct snd_dbuf *bs = c->bufsoft;
129
130         CHN_LOCKASSERT(c);
131         sndbuf_updateprevtotal(bs);
132         return 1;
133 }
134
135 static void
136 chn_wakeup(struct pcm_channel *c)
137 {
138         struct snd_dbuf *bs = c->bufsoft;
139         struct pcmchan_children *pce;
140
141         CHN_LOCKASSERT(c);
142         if (SLIST_EMPTY(&c->children)) {
143                 /*if (SEL_WAITING(sndbuf_getsel(bs)) && chn_polltrigger(c))*/
144                 if (SLIST_FIRST(&sndbuf_getkq(bs)->ki_note) && chn_polltrigger(c)) {
145                         /*
146                          * XXX
147                          *
148                          * We would call KNOTE() here, but as we
149                          * are in interrupt context, we'd have to
150                          * acquire the MP lock before.
151                          * Instead, we'll queue a task in a software
152                          * interrupt, which will run with the MP lock
153                          * held.
154                          *
155                          * buffer.c:sndbuf_kqtask will then call
156                          * KNOTE() from safer context.
157                          */
158                         taskqueue_enqueue(taskqueue_swi, &bs->kqtask);
159                 }
160         } else {
161                 SLIST_FOREACH(pce, &c->children, link) {
162                         CHN_LOCK(pce->channel);
163                         chn_wakeup(pce->channel);
164                         CHN_UNLOCK(pce->channel);
165                 }
166         }
167
168         wakeup(bs);
169 }
170
171 static int
172 chn_sleep(struct pcm_channel *c, char *str, int timeout)
173 {
174         struct snd_dbuf *bs = c->bufsoft;
175         int ret;
176
177         CHN_LOCKASSERT(c);
178 #ifdef USING_MUTEX
179         ret = snd_mtxsleep(bs, c->lock, PCATCH, str, timeout);
180 #else
181         ret = tsleep(bs, PRIBIO | PCATCH, str, timeout);
182 #endif
183
184         return ret;
185 }
186
187 /*
188  * chn_dmaupdate() tracks the status of a dma transfer,
189  * updating pointers.
190  */
191
192 static unsigned int
193 chn_dmaupdate(struct pcm_channel *c)
194 {
195         struct snd_dbuf *b = c->bufhard;
196         unsigned int delta, old, hwptr, amt;
197
198         KASSERT(sndbuf_getsize(b) > 0, ("bufsize == 0"));
199         CHN_LOCKASSERT(c);
200
201         old = sndbuf_gethwptr(b);
202         hwptr = chn_getptr(c);
203         delta = (sndbuf_getsize(b) + hwptr - old) % sndbuf_getsize(b);
204         sndbuf_sethwptr(b, hwptr);
205
206         DEB(
207         if (delta >= ((sndbuf_getsize(b) * 15) / 16)) {
208                 if (!(c->flags & (CHN_F_CLOSING | CHN_F_ABORTING)))
209                         device_printf(c->dev, "hwptr went backwards %d -> %d\n", old, hwptr);
210         }
211         );
212
213         if (c->direction == PCMDIR_PLAY) {
214                 amt = MIN(delta, sndbuf_getready(b));
215                 if (amt > 0)
216                         sndbuf_dispose(b, NULL, amt);
217         } else {
218                 amt = MIN(delta, sndbuf_getfree(b));
219                 if (amt > 0)
220                        sndbuf_acquire(b, NULL, amt);
221         }
222
223         return delta;
224 }
225
226 void
227 chn_wrupdate(struct pcm_channel *c)
228 {
229         int ret;
230
231         CHN_LOCKASSERT(c);
232         KASSERT(c->direction == PCMDIR_PLAY, ("chn_wrupdate on bad channel"));
233
234         if ((c->flags & (CHN_F_MAPPED | CHN_F_VIRTUAL)) || !(c->flags & CHN_F_TRIGGERED))
235                 return;
236         chn_dmaupdate(c);
237         ret = chn_wrfeed(c);
238         /* tell the driver we've updated the primary buffer */
239         chn_trigger(c, PCMTRIG_EMLDMAWR);
240         DEB(if (ret)
241                 kprintf("chn_wrupdate: chn_wrfeed returned %d\n", ret);)
242
243 }
244
245 int
246 chn_wrfeed(struct pcm_channel *c)
247 {
248         struct snd_dbuf *b = c->bufhard;
249         struct snd_dbuf *bs = c->bufsoft;
250         unsigned int ret, amt;
251
252         CHN_LOCKASSERT(c);
253 #if 0
254         DEB(
255         if (c->flags & CHN_F_CLOSING) {
256                 sndbuf_dump(b, "b", 0x02);
257                 sndbuf_dump(bs, "bs", 0x02);
258         })
259 #endif
260
261         if (c->flags & CHN_F_MAPPED)
262                 sndbuf_acquire(bs, NULL, sndbuf_getfree(bs));
263
264         amt = sndbuf_getfree(b);
265         KASSERT(amt <= sndbuf_getsize(bs),
266             ("%s(%s): amt %d > source size %d, flags 0x%x", __func__, c->name,
267            amt, sndbuf_getsize(bs), c->flags));
268
269         ret = (amt > 0) ? sndbuf_feed(bs, b, c, c->feeder, amt) : ENOSPC;
270         /*
271          * Possible xruns. There should be no empty space left in buffer.
272          */
273         if (sndbuf_getfree(b) > 0)
274                 c->xruns++;
275
276         if (ret == 0 && sndbuf_getfree(b) < amt)
277                 chn_wakeup(c);
278
279         return ret;
280 }
281
282 static void
283 chn_wrintr(struct pcm_channel *c)
284 {
285         int ret;
286
287         CHN_LOCKASSERT(c);
288         /* update pointers in primary buffer */
289         chn_dmaupdate(c);
290         /* ...and feed from secondary to primary */
291         ret = chn_wrfeed(c);
292         /* tell the driver we've updated the primary buffer */
293         chn_trigger(c, PCMTRIG_EMLDMAWR);
294         DEB(if (ret)
295                 kprintf("chn_wrintr: chn_wrfeed returned %d\n", ret);)
296 }
297
298 /*
299  * user write routine - uiomove data into secondary buffer, trigger if necessary
300  * if blocking, sleep, rinse and repeat.
301  *
302  * called externally, so must handle locking
303  */
304
305 int
306 chn_write(struct pcm_channel *c, struct uio *buf, int ioflags)
307 {
308         int ret, timeout, newsize, count, sz;
309         int nbio;
310         struct snd_dbuf *bs = c->bufsoft;
311         void *off;
312         int t, x,togo,p;
313
314         CHN_LOCKASSERT(c);
315         /*
316          * XXX Certain applications attempt to write larger size
317          * of pcm data than c->blocksize2nd without blocking,
318          * resulting partial write. Expand the block size so that
319          * the write operation avoids blocking.
320          */
321         nbio = (c->flags & CHN_F_NBIO) || (ioflags & IO_NDELAY);
322         if (nbio && buf->uio_resid > (size_t)sndbuf_getblksz(bs)) {
323                 DEB(device_printf(c->dev, "broken app, nbio and tried to write %ld bytes with fragsz %d\n",
324                         buf->uio_resid, sndbuf_getblksz(bs)));
325                 newsize = 16;
326                 while (newsize < (int)szmin(buf->uio_resid, CHN_2NDBUFMAXSIZE / 2))
327                         newsize <<= 1;
328                 chn_setblocksize(c, sndbuf_getblkcnt(bs), newsize);
329                 DEB(device_printf(c->dev, "frags reset to %d x %d\n", sndbuf_getblkcnt(bs), sndbuf_getblksz(bs)));
330         }
331
332         ret = 0;
333         count = hz;
334         while (!ret && (buf->uio_resid > 0) && (count > 0)) {
335                 sz = sndbuf_getfree(bs);
336                 if (sz == 0) {
337                         if (nbio)
338                                 ret = EWOULDBLOCK;
339                         else {
340                                 timeout = (hz * sndbuf_getblksz(bs)) / (sndbuf_getspd(bs) * sndbuf_getbps(bs));
341                                 if (timeout < 1)
342                                         timeout = 1;
343                                 timeout = 1;
344                                 ret = chn_sleep(c, "pcmwr", timeout);
345                                 if (ret == EWOULDBLOCK) {
346                                         count -= timeout;
347                                         ret = 0;
348                                 } else if (ret == 0)
349                                         count = hz;
350                         }
351                 } else {
352                         sz = (int)szmin(sz, buf->uio_resid);
353                         KASSERT(sz > 0, ("confusion in chn_write"));
354                         /* kprintf("sz: %d\n", sz); */
355
356                         /*
357                          * The following assumes that the free space in
358                          * the buffer can never be less around the
359                          * unlock-uiomove-lock sequence.
360                          */
361                         togo = sz;
362                         while (ret == 0 && togo> 0) {
363                                 p = sndbuf_getfreeptr(bs);
364                                 t = MIN(togo, sndbuf_getsize(bs) - p);
365                                 off = sndbuf_getbufofs(bs, p);
366                                 CHN_UNLOCK(c);
367                                 ret = uiomove(off, t, buf);
368                                 CHN_LOCK(c);
369                                 togo -= t;
370                                 x = sndbuf_acquire(bs, NULL, t);
371                         }
372                         ret = 0;
373                         if (ret == 0 && !(c->flags & CHN_F_TRIGGERED))
374                                 chn_start(c, 0);
375                 }
376         }
377         /* kprintf("ret: %d left: %d\n", ret, buf->uio_resid); */
378
379         if (count <= 0) {
380                 c->flags |= CHN_F_DEAD;
381                 kprintf("%s: play interrupt timeout, channel dead\n", c->name);
382         }
383
384         return ret;
385 }
386
387 #if 0
388 static int
389 chn_rddump(struct pcm_channel *c, unsigned int cnt)
390 {
391         struct snd_dbuf *b = c->bufhard;
392
393         CHN_LOCKASSERT(c);
394 #if 0
395         static uint32_t kk = 0;
396         printf("%u: dumping %d bytes\n", ++kk, cnt);
397 #endif
398         c->xruns++;
399         sndbuf_setxrun(b, sndbuf_getxrun(b) + cnt);
400         return sndbuf_dispose(b, NULL, cnt);
401 }
402 #endif
403
404 /*
405  * Feed new data from the read buffer. Can be called in the bottom half.
406  */
407 int
408 chn_rdfeed(struct pcm_channel *c)
409 {
410         struct snd_dbuf *b = c->bufhard;
411         struct snd_dbuf *bs = c->bufsoft;
412         unsigned int ret, amt;
413
414         CHN_LOCKASSERT(c);
415         DEB(
416         if (c->flags & CHN_F_CLOSING) {
417                 sndbuf_dump(b, "b", 0x02);
418                 sndbuf_dump(bs, "bs", 0x02);
419         })
420
421 #if 0
422         amt = sndbuf_getready(b);
423         if (sndbuf_getfree(bs) < amt) {
424                 c->xruns++;
425                 amt = sndbuf_getfree(bs);
426         }
427 #endif
428         amt = sndbuf_getfree(bs);
429         ret = (amt > 0)? sndbuf_feed(b, bs, c, c->feeder, amt) : 0;
430
431         amt = sndbuf_getready(b);
432         if (amt > 0) {
433                 c->xruns++;
434                 sndbuf_dispose(b, NULL, amt);
435         }
436
437         chn_wakeup(c);
438
439         return ret;
440 }
441
442 void
443 chn_rdupdate(struct pcm_channel *c)
444 {
445         int ret;
446
447         CHN_LOCKASSERT(c);
448         KASSERT(c->direction == PCMDIR_REC, ("chn_rdupdate on bad channel"));
449
450         if ((c->flags & CHN_F_MAPPED) || !(c->flags & CHN_F_TRIGGERED))
451                 return;
452         chn_trigger(c, PCMTRIG_EMLDMARD);
453         chn_dmaupdate(c);
454         ret = chn_rdfeed(c);
455         DEB(if (ret)
456                 kprintf("chn_rdfeed: %d\n", ret);)
457 }
458
459 /* read interrupt routine. Must be called with interrupts blocked. */
460 static void
461 chn_rdintr(struct pcm_channel *c)
462 {
463         int ret;
464
465         CHN_LOCKASSERT(c);
466         /* tell the driver to update the primary buffer if non-dma */
467         chn_trigger(c, PCMTRIG_EMLDMARD);
468         /* update pointers in primary buffer */
469         chn_dmaupdate(c);
470         /* ...and feed from primary to secondary */
471         ret = chn_rdfeed(c);
472 }
473
474 /*
475  * user read routine - trigger if necessary, uiomove data from secondary buffer
476  * if blocking, sleep, rinse and repeat.
477  *
478  * called externally, so must handle locking
479  */
480
481 int
482 chn_read(struct pcm_channel *c, struct uio *buf, int ioflags)
483 {
484         int             ret, timeout, sz, count;
485         int nbio;
486         struct snd_dbuf       *bs = c->bufsoft;
487         void *off;
488         int t, x,togo,p;
489
490         CHN_LOCKASSERT(c);
491         nbio = (c->flags & CHN_F_NBIO) || (ioflags & IO_NDELAY);
492         if (!(c->flags & CHN_F_TRIGGERED))
493                 chn_start(c, 0);
494
495         ret = 0;
496         count = hz;
497         while (!ret && (buf->uio_resid > 0) && (count > 0)) {
498                 sz = (int)szmin(buf->uio_resid, sndbuf_getready(bs));
499
500                 if (sz > 0) {
501                         /*
502                          * The following assumes that the free space in
503                          * the buffer can never be less around the
504                          * unlock-uiomove-lock sequence.
505                          */
506                         togo = sz;
507                         while (ret == 0 && togo> 0) {
508                                 p = sndbuf_getreadyptr(bs);
509                                 t = MIN(togo, sndbuf_getsize(bs) - p);
510                                 off = sndbuf_getbufofs(bs, p);
511                                 CHN_UNLOCK(c);
512                                 ret = uiomove(off, t, buf);
513                                 CHN_LOCK(c);
514                                 togo -= t;
515                                 x = sndbuf_dispose(bs, NULL, t);
516                         }
517                         ret = 0;
518                 } else {
519                         if (nbio) {
520                                 ret = EWOULDBLOCK;
521                         } else {
522                                 timeout = (hz * sndbuf_getblksz(bs)) / (sndbuf_getspd(bs) * sndbuf_getbps(bs));
523                                 if (timeout < 1)
524                                         timeout = 1;
525                                 ret = chn_sleep(c, "pcmrd", timeout);
526                                 if (ret == EWOULDBLOCK) {
527                                         count -= timeout;
528                                         ret = 0;
529                                 } else {
530                                         count = hz;
531                                 }
532
533                         }
534                 }
535         }
536
537         if (count <= 0) {
538                 c->flags |= CHN_F_DEAD;
539                 kprintf("%s: record interrupt timeout, channel dead\n", c->name);
540         }
541
542         return ret;
543 }
544
545 void
546 chn_intr(struct pcm_channel *c)
547 {
548         CHN_LOCK(c);
549         c->interrupts++;
550         if (c->direction == PCMDIR_PLAY)
551                 chn_wrintr(c);
552         else
553                 chn_rdintr(c);
554         CHN_UNLOCK(c);
555 }
556
557 u_int32_t
558 chn_start(struct pcm_channel *c, int force)
559 {
560         u_int32_t i, j;
561         struct snd_dbuf *b = c->bufhard;
562         struct snd_dbuf *bs = c->bufsoft;
563
564         CHN_LOCKASSERT(c);
565         /* if we're running, or if we're prevented from triggering, bail */
566         if ((c->flags & CHN_F_TRIGGERED) || ((c->flags & CHN_F_NOTRIGGER) && !force))
567                 return EINVAL;
568
569         i = (c->direction == PCMDIR_PLAY)? sndbuf_getready(bs) : sndbuf_getfree(bs);
570         j = (c->direction == PCMDIR_PLAY)? sndbuf_getfree(b) : sndbuf_getready(b);
571         if (force || (i >= j)) {
572                 c->flags |= CHN_F_TRIGGERED;
573                 /*
574                  * if we're starting because a vchan started, don't feed any data
575                  * or it becomes impossible to start vchans synchronised with the
576                  * first one.  the hardbuf should be empty so we top it up with
577                  * silence to give it something to chew.  the real data will be
578                  * fed at the first irq.
579                  */
580                 if (c->direction == PCMDIR_PLAY) {
581                         /*
582                          * Reduce pops during playback startup.
583                          */
584                         sndbuf_fillsilence(b);
585                         if (SLIST_EMPTY(&c->children))
586                                 chn_wrfeed(c);
587                 }
588                 sndbuf_setrun(b, 1);
589                 c->xruns = 0;
590                 chn_trigger(c, PCMTRIG_START);
591                 return 0;
592         }
593
594         return 0;
595 }
596
597 void
598 chn_resetbuf(struct pcm_channel *c)
599 {
600         struct snd_dbuf *b = c->bufhard;
601         struct snd_dbuf *bs = c->bufsoft;
602
603         c->blocks = 0;
604         sndbuf_reset(b);
605         sndbuf_reset(bs);
606 }
607
608 /*
609  * chn_sync waits until the space in the given channel goes above
610  * a threshold. The threshold is checked against fl or rl respectively.
611  * Assume that the condition can become true, do not check here...
612  */
613 int
614 chn_sync(struct pcm_channel *c, int threshold)
615 {
616         u_long rdy;
617         int ret;
618         struct snd_dbuf *bs = c->bufsoft;
619
620         CHN_LOCKASSERT(c);
621
622         /* if we haven't yet started and nothing is buffered, else start*/
623         if (!(c->flags & CHN_F_TRIGGERED)) {
624                 if (sndbuf_getready(bs) > 0) {
625                         ret = chn_start(c, 1);
626                         if (ret)
627                                 return ret;
628                 } else {
629                         return 0;
630                 }
631         }
632
633         for (;;) {
634                 rdy = (c->direction == PCMDIR_PLAY)? sndbuf_getfree(bs) : sndbuf_getready(bs);
635                 if (rdy <= threshold) {
636                         ret = chn_sleep(c, "pcmsyn", 1);
637                         if (ret == ERESTART || ret == EINTR) {
638                                 DEB(kprintf("chn_sync: tsleep returns %d\n", ret));
639                                 return -1;
640                         }
641                 } else
642                         break;
643         }
644         return 0;
645 }
646
647 /* called externally, handle locking */
648 int
649 chn_poll(struct pcm_channel *c, int ev, struct thread *td)
650 {
651         int ret;
652
653         CHN_LOCKASSERT(c);
654         if (!(c->flags & CHN_F_MAPPED) && !(c->flags & CHN_F_TRIGGERED))
655                 chn_start(c, 1);
656         ret = 0;
657         if (chn_polltrigger(c) && chn_pollreset(c))
658                 ret = ev;
659         return ret;
660 }
661
662 /*
663  * chn_abort terminates a running dma transfer.  it may sleep up to 200ms.
664  * it returns the number of bytes that have not been transferred.
665  *
666  * called from: dsp_close, dsp_ioctl, with channel locked
667  */
668 int
669 chn_abort(struct pcm_channel *c)
670 {
671         int missing = 0;
672         struct snd_dbuf *b = c->bufhard;
673         struct snd_dbuf *bs = c->bufsoft;
674
675         CHN_LOCKASSERT(c);
676         if (!(c->flags & CHN_F_TRIGGERED))
677                 return 0;
678         c->flags |= CHN_F_ABORTING;
679
680         c->flags &= ~CHN_F_TRIGGERED;
681         /* kill the channel */
682         chn_trigger(c, PCMTRIG_ABORT);
683         sndbuf_setrun(b, 0);
684         if (!(c->flags & CHN_F_VIRTUAL))
685                 chn_dmaupdate(c);
686         missing = sndbuf_getready(bs) + sndbuf_getready(b);
687
688         c->flags &= ~CHN_F_ABORTING;
689         return missing;
690 }
691
692 /*
693  * this routine tries to flush the dma transfer. It is called
694  * on a close of a playback channel.
695  * first, if there is data in the buffer, but the dma has not yet
696  * begun, we need to start it.
697  * next, we wait for the play buffer to drain
698  * finally, we stop the dma.
699  *
700  * called from: dsp_close, not valid for record channels.
701  */
702
703 int
704 chn_flush(struct pcm_channel *c)
705 {
706         int ret, count, resid, resid_p;
707         struct snd_dbuf *b = c->bufhard;
708         struct snd_dbuf *bs = c->bufsoft;
709
710         CHN_LOCKASSERT(c);
711         KASSERT(c->direction == PCMDIR_PLAY, ("chn_flush on bad channel"));
712         DEB(kprintf("chn_flush: c->flags 0x%08x\n", c->flags));
713
714         /* if we haven't yet started and nothing is buffered, else start*/
715         if (!(c->flags & CHN_F_TRIGGERED)) {
716                 if (sndbuf_getready(bs) > 0) {
717                         ret = chn_start(c, 1);
718                         if (ret)
719                                 return ret;
720                 } else {
721                         return 0;
722                 }
723         }
724
725         c->flags |= CHN_F_CLOSING;
726         resid = sndbuf_getready(bs) + sndbuf_getready(b);
727         resid_p = resid;
728         count = 10;
729         ret = 0;
730         while ((count > 0) && (resid > sndbuf_getsize(b)) && (ret == 0)) {
731                 /* still pending output data. */
732                 ret = chn_sleep(c, "pcmflu", hz / 10);
733                 if (ret == EWOULDBLOCK)
734                         ret = 0;
735                 if (ret == 0) {
736                         resid = sndbuf_getready(bs) + sndbuf_getready(b);
737                         if (resid == resid_p)
738                                 count--;
739                         if (resid > resid_p)
740                                 DEB(printf("chn_flush: buffer length increasind %d -> %d\n", resid_p, resid));
741                         resid_p = resid;
742                 }
743         }
744         if (count == 0)
745                 DEB(kprintf("chn_flush: timeout, hw %d, sw %d\n",
746                         sndbuf_getready(b), sndbuf_getready(bs)));
747
748         c->flags &= ~CHN_F_TRIGGERED;
749         /* kill the channel */
750         chn_trigger(c, PCMTRIG_ABORT);
751         sndbuf_setrun(b, 0);
752
753         c->flags &= ~CHN_F_CLOSING;
754         return 0;
755 }
756
757 int
758 fmtvalid(u_int32_t fmt, u_int32_t *fmtlist)
759 {
760         int i;
761
762         for (i = 0; fmtlist[i]; i++)
763                 if (fmt == fmtlist[i])
764                         return 1;
765         return 0;
766 }
767
768 int
769 chn_reset(struct pcm_channel *c, u_int32_t fmt)
770 {
771         int hwspd, r;
772
773         CHN_LOCKASSERT(c);
774         c->flags &= CHN_F_RESET;
775         c->interrupts = 0;
776         c->xruns = 0;
777
778         r = CHANNEL_RESET(c->methods, c->devinfo);
779         if (fmt != 0) {
780 #if 0
781                 hwspd = DSP_DEFAULT_SPEED;
782                 /* only do this on a record channel until feederbuilder works */
783                 if (c->direction == PCMDIR_REC)
784                         RANGE(hwspd, chn_getcaps(c)->minspeed, chn_getcaps(c)->maxspeed);
785                 c->speed = hwspd;
786 #endif
787                 hwspd = chn_getcaps(c)->minspeed;
788                 c->speed = hwspd;
789
790                 if (r == 0)
791                         r = chn_setformat(c, fmt);
792                 if (r == 0)
793                         r = chn_setspeed(c, hwspd);
794 #if 0
795                 if (r == 0)
796                         r = chn_setvolume(c, 100, 100);
797 #endif
798         }
799         if (r == 0)
800                 r = chn_setblocksize(c, 0, 0);
801         if (r == 0) {
802                 chn_resetbuf(c);
803                 r = CHANNEL_RESETDONE(c->methods, c->devinfo);
804         }
805         return r;
806 }
807
808 int
809 chn_init(struct pcm_channel *c, void *devinfo, int dir, int direction)
810 {
811         struct feeder_class *fc;
812         struct snd_dbuf *b, *bs;
813         int ret;
814
815         chn_lockinit(c, dir);
816
817         b = NULL;
818         bs = NULL;
819         c->devinfo = NULL;
820         c->feeder = NULL;
821
822         ret = ENOMEM;
823         b = sndbuf_create(c->dev, c->name, "primary", c);
824         if (b == NULL)
825                 goto out;
826         bs = sndbuf_create(c->dev, c->name, "secondary", c);
827         if (bs == NULL)
828                 goto out;
829
830         CHN_LOCK(c);
831
832         ret = EINVAL;
833         fc = feeder_getclass(NULL);
834         if (fc == NULL)
835                 goto out;
836         if (chn_addfeeder(c, fc, NULL))
837                 goto out;
838
839         /*
840          * XXX - sndbuf_setup() & sndbuf_resize() expect to be called
841          *       with the channel unlocked because they are also called
842          *       from driver methods that don't know about locking
843          */
844         CHN_UNLOCK(c);
845         sndbuf_setup(bs, NULL, 0);
846         CHN_LOCK(c);
847         c->bufhard = b;
848         c->bufsoft = bs;
849         c->flags = 0;
850         c->feederflags = 0;
851
852         ret = ENODEV;
853         CHN_UNLOCK(c); /* XXX - Unlock for CHANNEL_INIT() kmalloc() call */
854         c->devinfo = CHANNEL_INIT(c->methods, devinfo, b, c, direction);
855         CHN_LOCK(c);
856         if (c->devinfo == NULL)
857                 goto out;
858
859         ret = ENOMEM;
860         if ((sndbuf_getsize(b) == 0) && ((c->flags & CHN_F_VIRTUAL) == 0))
861                 goto out;
862
863         ret = chn_setdir(c, direction);
864         if (ret)
865                 goto out;
866
867         ret = sndbuf_setfmt(b, AFMT_U8);
868         if (ret)
869                 goto out;
870
871         ret = sndbuf_setfmt(bs, AFMT_U8);
872         if (ret)
873                 goto out;
874
875         ret = chn_setvolume(c, 100, 100);
876         if (ret)
877                 goto out;
878
879
880 out:
881         CHN_UNLOCK(c);
882         if (ret) {
883                 if (c->devinfo) {
884                         if (CHANNEL_FREE(c->methods, c->devinfo))
885                                 sndbuf_free(b);
886                 }
887                 if (bs)
888                         sndbuf_destroy(bs);
889                 if (b)
890                         sndbuf_destroy(b);
891                 c->flags |= CHN_F_DEAD;
892                 chn_lockdestroy(c);
893
894                 return ret;
895         }
896
897         return 0;
898 }
899
900 int
901 chn_kill(struct pcm_channel *c)
902 {
903         struct snd_dbuf *b = c->bufhard;
904         struct snd_dbuf *bs = c->bufsoft;
905
906         if (c->flags & CHN_F_TRIGGERED)
907                 chn_trigger(c, PCMTRIG_ABORT);
908         while (chn_removefeeder(c) == 0);
909         if (CHANNEL_FREE(c->methods, c->devinfo))
910                 sndbuf_free(b);
911         c->flags |= CHN_F_DEAD;
912         sndbuf_destroy(bs);
913         sndbuf_destroy(b);
914         chn_lockdestroy(c);
915         return 0;
916 }
917
918 int
919 chn_setdir(struct pcm_channel *c, int dir)
920 {
921 #if NISA > 0
922         struct snd_dbuf *b = c->bufhard;
923 #endif
924         int r;
925
926         CHN_LOCKASSERT(c);
927         c->direction = dir;
928         r = CHANNEL_SETDIR(c->methods, c->devinfo, c->direction);
929 #if NISA > 0
930         if (!r && SND_DMA(b))
931                 sndbuf_dmasetdir(b, c->direction);
932 #endif
933         return r;
934 }
935
936 int
937 chn_setvolume(struct pcm_channel *c, int left, int right)
938 {
939         CHN_LOCKASSERT(c);
940         /* should add a feeder for volume changing if channel returns -1 */
941         if (left > 100)
942                 left = 100;
943         if (left < 0)
944                 left = 0;
945         if (right > 100)
946                 right = 100;
947         if (right < 0)
948                 right = 0;
949         c->volume = left | (right << 8);
950         return 0;
951 }
952
953 static int
954 chn_tryspeed(struct pcm_channel *c, int speed)
955 {
956         struct pcm_feeder *f;
957         struct snd_dbuf *b = c->bufhard;
958         struct snd_dbuf *bs = c->bufsoft;
959         struct snd_dbuf *x;
960         int r, delta;
961
962         CHN_LOCKASSERT(c);
963         DEB(kprintf("setspeed, channel %s\n", c->name));
964         DEB(kprintf("want speed %d, ", speed));
965         if (speed <= 0)
966                 return EINVAL;
967         if (CANCHANGE(c)) {
968                 r = 0;
969                 c->speed = speed;
970                 sndbuf_setspd(bs, speed);
971                 RANGE(speed, chn_getcaps(c)->minspeed, chn_getcaps(c)->maxspeed);
972                 DEB(kprintf("try speed %d, ", speed));
973                 sndbuf_setspd(b, CHANNEL_SETSPEED(c->methods, c->devinfo, speed));
974                 DEB(kprintf("got speed %d\n", sndbuf_getspd(b)));
975
976                 delta = sndbuf_getspd(b) - sndbuf_getspd(bs);
977                 if (delta < 0)
978                         delta = -delta;
979
980                 c->feederflags &= ~(1 << FEEDER_RATE);
981                 /*
982                  * Used to be 500. It was too big!
983                  */
984                 if (delta > 25)
985                         c->feederflags |= 1 << FEEDER_RATE;
986                 else
987                         sndbuf_setspd(bs, sndbuf_getspd(b));
988
989                 r = chn_buildfeeder(c);
990                 DEB(kprintf("r = %d\n", r));
991                 if (r)
992                         goto out;
993
994                 r = chn_setblocksize(c, 0, 0);
995                 if (r)
996                         goto out;
997
998                 if (!(c->feederflags & (1 << FEEDER_RATE)))
999                         goto out;
1000
1001                 r = EINVAL;
1002                 f = chn_findfeeder(c, FEEDER_RATE);
1003                 DEB(kprintf("feedrate = %p\n", f));
1004                 if (f == NULL)
1005                         goto out;
1006
1007                 x = (c->direction == PCMDIR_REC)? b : bs;
1008                 r = FEEDER_SET(f, FEEDRATE_SRC, sndbuf_getspd(x));
1009                 DEB(kprintf("feeder_set(FEEDRATE_SRC, %d) = %d\n", sndbuf_getspd(x), r));
1010                 if (r)
1011                         goto out;
1012
1013                 x = (c->direction == PCMDIR_REC)? bs : b;
1014                 r = FEEDER_SET(f, FEEDRATE_DST, sndbuf_getspd(x));
1015                 DEB(kprintf("feeder_set(FEEDRATE_DST, %d) = %d\n", sndbuf_getspd(x), r));
1016 out:
1017                 if (!r)
1018                         r = CHANNEL_SETFORMAT(c->methods, c->devinfo,
1019                                                         sndbuf_getfmt(b));
1020                 if (!r)
1021                         sndbuf_setfmt(bs, c->format);
1022                 DEB(kprintf("setspeed done, r = %d\n", r));
1023                 return r;
1024         } else
1025                 return EINVAL;
1026 }
1027
1028 int
1029 chn_setspeed(struct pcm_channel *c, int speed)
1030 {
1031         int r, oldspeed = c->speed;
1032
1033         r = chn_tryspeed(c, speed);
1034         if (r) {
1035                 DEB(kprintf("Failed to set speed %d falling back to %d\n", speed, oldspeed));
1036                 r = chn_tryspeed(c, oldspeed);
1037         }
1038         return r;
1039 }
1040
1041 static int
1042 chn_tryformat(struct pcm_channel *c, u_int32_t fmt)
1043 {
1044         struct snd_dbuf *b = c->bufhard;
1045         struct snd_dbuf *bs = c->bufsoft;
1046         int r;
1047
1048         CHN_LOCKASSERT(c);
1049         if (CANCHANGE(c)) {
1050                 DEB(kprintf("want format %d\n", fmt));
1051                 c->format = fmt;
1052                 r = chn_buildfeeder(c);
1053                 if (r == 0) {
1054                         sndbuf_setfmt(bs, c->format);
1055                         chn_resetbuf(c);
1056                         r = CHANNEL_SETFORMAT(c->methods, c->devinfo, sndbuf_getfmt(b));
1057                         if (r == 0)
1058                                 r = chn_tryspeed(c, c->speed);
1059                 }
1060                 return r;
1061         } else
1062                 return EINVAL;
1063 }
1064
1065 int
1066 chn_setformat(struct pcm_channel *c, u_int32_t fmt)
1067 {
1068         u_int32_t oldfmt = c->format;
1069         int r;
1070
1071         r = chn_tryformat(c, fmt);
1072         if (r) {
1073                 DEB(kprintf("Format change %d failed, reverting to %d\n", fmt, oldfmt));
1074                 chn_tryformat(c, oldfmt);
1075         }
1076         return r;
1077 }
1078
1079 /*
1080  * given a bufsz value, round it to a power of 2 in the min-max range
1081  * XXX only works if min and max are powers of 2
1082  */
1083 static int
1084 round_bufsz(int bufsz, int min, int max)
1085 {
1086         int tmp = min * 2;
1087
1088         KASSERT((min & (min-1)) == 0, ("min %d must be power of 2\n", min));
1089         KASSERT((max & (max-1)) == 0, ("max %d must be power of 2\n", max));
1090         while (tmp <= bufsz)
1091                 tmp <<= 1;
1092         tmp >>= 1;
1093         if (tmp > max)
1094                 tmp = max;
1095         return tmp;
1096 }
1097
1098 /*
1099  * set the channel's blocksize both for soft and hard buffers.
1100  *
1101  * blksz should be a power of 2 between 2**4 and 2**16 -- it is useful
1102  * that it has the same value for both bufsoft and bufhard.
1103  * blksz == -1 computes values according to a target irq rate.
1104  * blksz == 0 reuses previous values if available, otherwise
1105  * behaves as for -1
1106  *
1107  * blkcnt is set by the user, between 2 and (2**17)/blksz for bufsoft,
1108  * but should be a power of 2 for bufhard to simplify life to low
1109  * level drivers.
1110  * Note, for the rec channel a large blkcnt is ok,
1111  * but for the play channel we want blksz as small as possible to keep
1112  * the delay small, because routines in the write path always try to
1113  * keep bufhard full.
1114  *
1115  * Unless we have good reason to, use the values suggested by the caller.
1116  */
1117 int
1118 chn_setblocksize(struct pcm_channel *c, int blkcnt, int blksz)
1119 {
1120         struct snd_dbuf *b = c->bufhard;
1121         struct snd_dbuf *bs = c->bufsoft;
1122         int irqhz, ret, maxsz, maxsize, reqblksz;
1123
1124         CHN_LOCKASSERT(c);
1125         if (!CANCHANGE(c) || (c->flags & CHN_F_MAPPED)) {
1126                 KASSERT(sndbuf_getsize(bs) ==  0 ||
1127                     sndbuf_getsize(bs) >= sndbuf_getsize(b),
1128                     ("%s(%s): bufsoft size %d < bufhard size %d", __func__,
1129                     c->name, sndbuf_getsize(bs), sndbuf_getsize(b)));
1130                 return EINVAL;
1131         }
1132         c->flags |= CHN_F_SETBLOCKSIZE;
1133
1134         ret = 0;
1135         DEB(kprintf("%s(%d, %d)\n", __func__, blkcnt, blksz));
1136         if (blksz == 0 || blksz == -1) { /* let the driver choose values */
1137                 if (blksz == -1)        /* delete previous values */
1138                         c->flags &= ~CHN_F_HAS_SIZE;
1139                 if (!(c->flags & CHN_F_HAS_SIZE)) { /* no previous value */
1140                         /*
1141                          * compute a base blksz according to the target irq
1142                          * rate, then round to a suitable power of 2
1143                          * in the range 16.. 2^17/2.
1144                          * Finally compute a suitable blkcnt.
1145                          */
1146                         blksz = round_bufsz( (sndbuf_getbps(bs) *
1147                                 sndbuf_getspd(bs)) / chn_targetirqrate,
1148                                 16, CHN_2NDBUFMAXSIZE / 2);
1149                         blkcnt = CHN_2NDBUFMAXSIZE / blksz;
1150                 } else { /* use previously defined value */
1151                         blkcnt = sndbuf_getblkcnt(bs);
1152                         blksz = sndbuf_getblksz(bs);
1153                 }
1154         } else {
1155                 /*
1156                  * use supplied values if reasonable. Note that here we
1157                  * might have blksz which is not a power of 2 if the
1158                  * ioctl() to compute it allows such values.
1159                  */
1160                 ret = EINVAL;
1161                 if ((blksz < 16) || (blkcnt < 2) || (blkcnt * blksz > CHN_2NDBUFMAXSIZE))
1162                         goto out;
1163                 ret = 0;
1164                 c->flags |= CHN_F_HAS_SIZE;
1165         }
1166
1167         reqblksz = blksz;
1168         if (reqblksz < sndbuf_getbps(bs))
1169                 reqblksz = sndbuf_getbps(bs);
1170         if (reqblksz % sndbuf_getbps(bs))
1171                 reqblksz -= reqblksz % sndbuf_getbps(bs);
1172
1173         /* adjust for different hw format/speed */
1174         /*
1175          * Now compute the approx irq rate for the given (soft) blksz,
1176          * reduce to the acceptable range and compute a corresponding blksz
1177          * for the hard buffer. Then set the channel's blocksize and
1178          * corresponding hardbuf value. The number of blocks used should
1179          * be set by the device-specific routine. In fact, even the
1180          * call to sndbuf_setblksz() should not be here! XXX
1181          */
1182
1183         irqhz = (sndbuf_getbps(bs) * sndbuf_getspd(bs)) / blksz;
1184         RANGE(irqhz, 16, 512);
1185
1186         maxsz = sndbuf_getmaxsize(b);
1187         if (maxsz == 0) /* virtual channels don't appear to allocate bufhard */
1188                 maxsz = CHN_2NDBUFMAXSIZE;
1189         blksz = round_bufsz( (sndbuf_getbps(b) * sndbuf_getspd(b)) / irqhz,
1190                         16, maxsz / 2);
1191
1192         /* Increase the size of bufsoft if before increasing bufhard. */
1193         maxsize = sndbuf_getsize(b);
1194         if (sndbuf_getsize(bs) > maxsize)
1195                 maxsize = sndbuf_getsize(bs);
1196         if (reqblksz * blkcnt > maxsize)
1197                 maxsize = reqblksz * blkcnt;
1198         if (sndbuf_getsize(bs) != maxsize || sndbuf_getblksz(bs) != reqblksz) {
1199                 ret = sndbuf_remalloc(bs, maxsize/reqblksz, reqblksz);
1200                 if (ret)
1201                         goto out1;
1202         }
1203
1204         CHN_UNLOCK(c);
1205         sndbuf_setblksz(b, CHANNEL_SETBLOCKSIZE(c->methods, c->devinfo, blksz));
1206         CHN_LOCK(c);
1207
1208         /* Decrease the size of bufsoft after decreasing bufhard. */
1209         maxsize = sndbuf_getsize(b);
1210         if (reqblksz * blkcnt > maxsize)
1211                 maxsize = reqblksz * blkcnt;
1212         if (maxsize > sndbuf_getsize(bs))
1213                 kprintf("Danger! %s bufsoft size increasing from %d to %d after CHANNEL_SETBLOCKSIZE()\n",
1214                     c->name, sndbuf_getsize(bs), maxsize);
1215         if (sndbuf_getsize(bs) != maxsize || sndbuf_getblksz(bs) != reqblksz) {
1216                 ret = sndbuf_remalloc(bs, maxsize/reqblksz, reqblksz);
1217                 if (ret)
1218                         goto out1;
1219         }
1220
1221         chn_resetbuf(c);
1222 out1:
1223         KASSERT(sndbuf_getsize(bs) ==  0 ||
1224             sndbuf_getsize(bs) >= sndbuf_getsize(b),
1225             ("%s(%s): bufsoft size %d < bufhard size %d, reqblksz=%d blksz=%d maxsize=%d blkcnt=%d",
1226             __func__, c->name, sndbuf_getsize(bs), sndbuf_getsize(b), reqblksz,
1227             blksz, maxsize, blkcnt));
1228 out:
1229         c->flags &= ~CHN_F_SETBLOCKSIZE;
1230 #if 0
1231         if (1) {
1232                 static uint32_t kk = 0;
1233                 printf("%u: b %d/%d/%d : (%d)%d/0x%0x | bs %d/%d/%d : (%d)%d/0x%0x\n", ++kk,
1234                         sndbuf_getsize(b), sndbuf_getblksz(b), sndbuf_getblkcnt(b),
1235                         sndbuf_getbps(b),
1236                         sndbuf_getspd(b), sndbuf_getfmt(b),
1237                         sndbuf_getsize(bs), sndbuf_getblksz(bs), sndbuf_getblkcnt(bs),
1238                         sndbuf_getbps(bs),
1239                         sndbuf_getspd(bs), sndbuf_getfmt(bs));
1240                 if (sndbuf_getsize(b) % sndbuf_getbps(b) ||
1241                                 sndbuf_getblksz(b) % sndbuf_getbps(b) ||
1242                                 sndbuf_getsize(bs) % sndbuf_getbps(bs) ||
1243                                 sndbuf_getblksz(b) % sndbuf_getbps(b)) {
1244                         printf("%u: bps/blksz alignment screwed!\n", kk);
1245                 }
1246         }
1247 #endif
1248         return ret;
1249 }
1250
1251 int
1252 chn_trigger(struct pcm_channel *c, int go)
1253 {
1254 #if NISA > 0
1255         struct snd_dbuf *b = c->bufhard;
1256 #endif
1257         int ret;
1258
1259         CHN_LOCKASSERT(c);
1260 #if NISA > 0
1261         if (SND_DMA(b) && (go == PCMTRIG_EMLDMAWR || go == PCMTRIG_EMLDMARD))
1262                 sndbuf_dmabounce(b);
1263 #endif
1264         ret = CHANNEL_TRIGGER(c->methods, c->devinfo, go);
1265
1266         return ret;
1267 }
1268
1269 int
1270 chn_getptr(struct pcm_channel *c)
1271 {
1272 #if 0
1273         int hwptr;
1274         int a = (1 << c->align) - 1;
1275
1276         CHN_LOCKASSERT(c);
1277         hwptr = (c->flags & CHN_F_TRIGGERED)? CHANNEL_GETPTR(c->methods, c->devinfo) : 0;
1278         /* don't allow unaligned values in the hwa ptr */
1279 #if 1
1280         hwptr &= ~a ; /* Apply channel align mask */
1281 #endif
1282         hwptr &= DMA_ALIGN_MASK; /* Apply DMA align mask */
1283         return hwptr;
1284 #endif
1285         int hwptr;
1286
1287         CHN_LOCKASSERT(c);
1288         hwptr = (c->flags & CHN_F_TRIGGERED)? CHANNEL_GETPTR(c->methods, c->devinfo) : 0;
1289         return (hwptr - (hwptr % sndbuf_getbps(c->bufhard)));
1290 }
1291
1292 struct pcmchan_caps *
1293 chn_getcaps(struct pcm_channel *c)
1294 {
1295         CHN_LOCKASSERT(c);
1296         return CHANNEL_GETCAPS(c->methods, c->devinfo);
1297 }
1298
1299 u_int32_t
1300 chn_getformats(struct pcm_channel *c)
1301 {
1302         u_int32_t *fmtlist, fmts;
1303         int i;
1304
1305         fmtlist = chn_getcaps(c)->fmtlist;
1306         fmts = 0;
1307         for (i = 0; fmtlist[i]; i++)
1308                 fmts |= fmtlist[i];
1309
1310         /* report software-supported formats */
1311         if (report_soft_formats)
1312                 fmts |= AFMT_MU_LAW|AFMT_A_LAW|AFMT_U32_LE|AFMT_U32_BE|
1313                     AFMT_S32_LE|AFMT_S32_BE|AFMT_U24_LE|AFMT_U24_BE|
1314                     AFMT_S24_LE|AFMT_S24_BE|AFMT_U16_LE|AFMT_U16_BE|
1315                     AFMT_S16_LE|AFMT_S16_BE|AFMT_U8|AFMT_S8;
1316
1317         return fmts;
1318 }
1319
1320 static int
1321 chn_buildfeeder(struct pcm_channel *c)
1322 {
1323         struct feeder_class *fc;
1324         struct pcm_feederdesc desc;
1325         u_int32_t tmp[2], type, flags, hwfmt, *fmtlist;
1326         int err;
1327
1328         CHN_LOCKASSERT(c);
1329         while (chn_removefeeder(c) == 0);
1330         KASSERT((c->feeder == NULL), ("feeder chain not empty"));
1331
1332         c->align = sndbuf_getalign(c->bufsoft);
1333
1334         if (SLIST_EMPTY(&c->children)) {
1335                 fc = feeder_getclass(NULL);
1336                 KASSERT(fc != NULL, ("can't find root feeder"));
1337
1338                 err = chn_addfeeder(c, fc, NULL);
1339                 if (err) {
1340                         DEB(kprintf("can't add root feeder, err %d\n", err));
1341
1342                         return err;
1343                 }
1344                 c->feeder->desc->out = c->format;
1345         } else {
1346                 if (c->flags & CHN_F_HAS_VCHAN) {
1347                         desc.type = FEEDER_MIXER;
1348                         desc.in = 0;
1349                 } else {
1350                         DEB(printf("can't decide which feeder type to use!\n"));
1351                         return EOPNOTSUPP;
1352                 }
1353                 desc.out = c->format;
1354                 desc.flags = 0;
1355                 fc = feeder_getclass(&desc);
1356                 if (fc == NULL) {
1357                         DEB(kprintf("can't find vchan feeder\n"));
1358
1359                         return EOPNOTSUPP;
1360                 }
1361
1362                 err = chn_addfeeder(c, fc, &desc);
1363                 if (err) {
1364                         DEB(kprintf("can't add vchan feeder, err %d\n", err));
1365
1366                         return err;
1367                 }
1368         }
1369         c->feederflags &= ~(1 << FEEDER_VOLUME);
1370         if (c->direction == PCMDIR_PLAY &&
1371                         !(c->flags & CHN_F_VIRTUAL) &&
1372                         c->parentsnddev && (c->parentsnddev->flags & SD_F_SOFTPCMVOL) &&
1373                         c->parentsnddev->mixer_dev)
1374                 c->feederflags |= 1 << FEEDER_VOLUME;
1375         flags = c->feederflags;
1376         fmtlist = chn_getcaps(c)->fmtlist;
1377
1378         DEB(kprintf("feederflags %x\n", flags));
1379
1380         for (type = FEEDER_RATE; type <= FEEDER_LAST; type++) {
1381                 if (flags & (1 << type)) {
1382                         desc.type = type;
1383                         desc.in = 0;
1384                         desc.out = 0;
1385                         desc.flags = 0;
1386                         DEB(kprintf("find feeder type %d, ", type));
1387                         fc = feeder_getclass(&desc);
1388                         DEB(kprintf("got %p\n", fc));
1389                         if (fc == NULL) {
1390                                 DEB(kprintf("can't find required feeder type %d\n", type));
1391
1392                                 return EOPNOTSUPP;
1393                         }
1394
1395                         DEB(kprintf("build fmtchain from 0x%08x to 0x%08x: ", c->feeder->desc->out, fc->desc->in));
1396                         tmp[0] = fc->desc->in;
1397                         tmp[1] = 0;
1398                         if (chn_fmtchain(c, tmp) == 0) {
1399                                 DEB(printf("failed\n"));
1400
1401                                 return ENODEV;
1402                         }
1403                         DEB(printf("ok\n"));
1404
1405                         err = chn_addfeeder(c, fc, fc->desc);
1406                         if (err) {
1407                                 DEB(kprintf("can't add feeder %p, output 0x%x, err %d\n", fc, fc->desc->out, err));
1408
1409                                 return err;
1410                         }
1411                         DEB(kprintf("added feeder %p, output 0x%x\n", fc, c->feeder->desc->out));
1412                 }
1413         }
1414
1415         if (c->direction == PCMDIR_REC) {
1416                 tmp[0] = c->format;
1417                 tmp[1] = 0;
1418                 hwfmt = chn_fmtchain(c, tmp);
1419         } else
1420                 hwfmt = chn_fmtchain(c, fmtlist);
1421
1422         if (hwfmt == 0 || !fmtvalid(hwfmt, fmtlist)) {
1423                 DEB(printf("Invalid hardware format: 0x%08x\n", hwfmt));
1424                 return ENODEV;
1425         }
1426
1427         sndbuf_setfmt(c->bufhard, hwfmt);
1428
1429         if ((flags & (1 << FEEDER_VOLUME))) {
1430                 struct dev_ioctl_args map;
1431                 u_int32_t parent = SOUND_MIXER_NONE;
1432                 int vol, left, right;
1433
1434                 vol = 100 | (100 << 8);
1435
1436                 CHN_UNLOCK(c);
1437                 /*
1438                  * XXX This is ugly! The way mixer subs being so secretive
1439                  * about its own internals force us to use this silly
1440                  * monkey trick.
1441                  */
1442                 map.a_head.a_dev = c->parentsnddev->mixer_dev;
1443                 map.a_cmd = MIXER_READ(SOUND_MIXER_PCM);
1444                 map.a_data = (caddr_t)&vol;
1445                 map.a_fflag = -1;
1446                 map.a_cred = NULL;
1447                 map.a_sysmsg = NULL;
1448                 if (mixer_ioctl(&map) != 0)
1449                         device_printf(c->dev, "Soft PCM Volume: Failed to read default value\n");
1450                 left = vol & 0x7f;
1451                 right = (vol >> 8) & 0x7f;
1452                 if (c->parentsnddev != NULL &&
1453                     c->parentsnddev->mixer_dev != NULL &&
1454                     c->parentsnddev->mixer_dev->si_drv1 != NULL)
1455                         parent = mix_getparent(
1456                             c->parentsnddev->mixer_dev->si_drv1,
1457                             SOUND_MIXER_PCM);
1458                 if (parent != SOUND_MIXER_NONE) {
1459                         vol = 100 | (100 << 8);
1460                         map.a_head.a_dev = c->parentsnddev->mixer_dev;
1461                         map.a_cmd = MIXER_READ(parent);
1462                         map.a_data = (caddr_t)&vol;
1463                         map.a_fflag = -1;
1464                         map.a_cred = NULL;
1465                         if (mixer_ioctl(&map) != 0)
1466                                 device_printf(c->dev, "Soft Volume: Failed to read parent default value\n");
1467                         left = (left * (vol & 0x7f)) / 100;
1468                         right = (right * ((vol >> 8) & 0x7f)) / 100;
1469                 }
1470
1471                 CHN_LOCK(c);
1472                 chn_setvolume(c, left, right);
1473         }
1474
1475         return 0;
1476 }
1477
1478 int
1479 chn_notify(struct pcm_channel *c, u_int32_t flags)
1480 {
1481         struct pcmchan_children *pce;
1482         struct pcm_channel *child;
1483         int run;
1484
1485         CHN_LOCK(c);
1486
1487         if (SLIST_EMPTY(&c->children)) {
1488                 CHN_UNLOCK(c);
1489                 return ENODEV;
1490         }
1491
1492         run = (c->flags & CHN_F_TRIGGERED)? 1 : 0;
1493         /*
1494          * if the hwchan is running, we can't change its rate, format or
1495          * blocksize
1496          */
1497         if (run)
1498                 flags &= CHN_N_VOLUME | CHN_N_TRIGGER;
1499
1500         if (flags & CHN_N_RATE) {
1501                 /*
1502                  * we could do something here, like scan children and decide on
1503                  * the most appropriate rate to mix at, but we don't for now
1504                  */
1505         }
1506         if (flags & CHN_N_FORMAT) {
1507                 /*
1508                  * we could do something here, like scan children and decide on
1509                  * the most appropriate mixer feeder to use, but we don't for now
1510                  */
1511         }
1512         if (flags & CHN_N_VOLUME) {
1513                 /*
1514                  * we could do something here but we don't for now
1515                  */
1516         }
1517         if (flags & CHN_N_BLOCKSIZE) {
1518                 int blksz;
1519                 /*
1520                  * scan the children, find the lowest blocksize and use that
1521                  * for the hard blocksize
1522                  */
1523                 blksz = sndbuf_getmaxsize(c->bufhard) / 2;
1524                 SLIST_FOREACH(pce, &c->children, link) {
1525                         child = pce->channel;
1526                         CHN_LOCK(child);
1527                         if (sndbuf_getblksz(child->bufhard) < blksz)
1528                                 blksz = sndbuf_getblksz(child->bufhard);
1529                         CHN_UNLOCK(child);
1530                 }
1531                 chn_setblocksize(c, 2, blksz);
1532         }
1533         if (flags & CHN_N_TRIGGER) {
1534                 int nrun;
1535                 /*
1536                  * scan the children, and figure out if any are running
1537                  * if so, we need to be running, otherwise we need to be stopped
1538                  * if we aren't in our target sstate, move to it
1539                  */
1540                 nrun = 0;
1541                 SLIST_FOREACH(pce, &c->children, link) {
1542                         child = pce->channel;
1543                         CHN_LOCK(child);
1544                         if (child->flags & CHN_F_TRIGGERED)
1545                                 nrun = 1;
1546                         CHN_UNLOCK(child);
1547                 }
1548                 if (nrun && !run)
1549                         chn_start(c, 1);
1550                 if (!nrun && run)
1551                         chn_abort(c);
1552         }
1553         CHN_UNLOCK(c);
1554         return 0;
1555 }
1556
1557 void
1558 chn_lock(struct pcm_channel *c)
1559 {
1560         CHN_LOCK(c);
1561 }
1562
1563 void
1564 chn_unlock(struct pcm_channel *c)
1565 {
1566         CHN_UNLOCK(c);
1567 }