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