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