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