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