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