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