Deleted Added
full compact
channel.c (167644) channel.c (167645)
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:

--- 17 unchanged lines hidden (view full) ---

26 */
27
28#include "opt_isa.h"
29
30#include <dev/sound/pcm/sound.h>
31
32#include "feeder_if.h"
33
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:

--- 17 unchanged lines hidden (view full) ---

26 */
27
28#include "opt_isa.h"
29
30#include <dev/sound/pcm/sound.h>
31
32#include "feeder_if.h"
33
34SND_DECLARE_FILE("$FreeBSD: head/sys/dev/sound/pcm/channel.c 167644 2007-03-16 17:15:33Z ariff $");
34SND_DECLARE_FILE("$FreeBSD: head/sys/dev/sound/pcm/channel.c 167645 2007-03-16 17:16:24Z ariff $");
35
36#define MIN_CHUNK_SIZE 256 /* for uiomove etc. */
37#if 0
38#define DMA_ALIGN_THRESHOLD 4
39#define DMA_ALIGN_MASK (~(DMA_ALIGN_THRESHOLD - 1))
40#endif
41
35
36#define MIN_CHUNK_SIZE 256 /* for uiomove etc. */
37#if 0
38#define DMA_ALIGN_THRESHOLD 4
39#define DMA_ALIGN_MASK (~(DMA_ALIGN_THRESHOLD - 1))
40#endif
41
42#define CANCHANGE(c) (!(c->flags & CHN_F_TRIGGERED))
42#define CHN_STARTED(c) ((c)->flags & CHN_F_TRIGGERED)
43#define CHN_STOPPED(c) (!CHN_STARTED(c))
44#define CHN_DIRSTR(c) (((c)->direction == PCMDIR_PLAY) ? \
45 "PCMDIR_PLAY" : "PCMDIR_REC")
43
44#define BUF_PARENT(c, b) \
45 (((c) != NULL && (c)->parentchannel != NULL && \
46 (c)->parentchannel->bufhard != NULL) ? \
47 (c)->parentchannel->bufhard : (b))
48
46
47#define BUF_PARENT(c, b) \
48 (((c) != NULL && (c)->parentchannel != NULL && \
49 (c)->parentchannel->bufhard != NULL) ? \
50 (c)->parentchannel->bufhard : (b))
51
52#define CHN_TIMEOUT 5
53#define CHN_TIMEOUT_MIN 1
54#define CHN_TIMEOUT_MAX 10
55
49/*
50#define DEB(x) x
51*/
52
53int report_soft_formats = 1;
54SYSCTL_INT(_hw_snd, OID_AUTO, report_soft_formats, CTLFLAG_RW,
55 &report_soft_formats, 1, "report software-emulated formats");
56

--- 34 unchanged lines hidden (view full) ---

91 chn_latency_profile = val;
92
93 return err;
94}
95SYSCTL_PROC(_hw_snd, OID_AUTO, latency_profile, CTLTYPE_INT | CTLFLAG_RW,
96 0, sizeof(int), sysctl_hw_snd_latency_profile, "I",
97 "buffering latency profile (0=aggresive 1=safe)");
98
56/*
57#define DEB(x) x
58*/
59
60int report_soft_formats = 1;
61SYSCTL_INT(_hw_snd, OID_AUTO, report_soft_formats, CTLFLAG_RW,
62 &report_soft_formats, 1, "report software-emulated formats");
63

--- 34 unchanged lines hidden (view full) ---

98 chn_latency_profile = val;
99
100 return err;
101}
102SYSCTL_PROC(_hw_snd, OID_AUTO, latency_profile, CTLTYPE_INT | CTLFLAG_RW,
103 0, sizeof(int), sysctl_hw_snd_latency_profile, "I",
104 "buffering latency profile (0=aggresive 1=safe)");
105
106static int chn_timeout = CHN_TIMEOUT;
107
108#ifdef SND_DEBUG
109static int
110sysctl_hw_snd_timeout(SYSCTL_HANDLER_ARGS)
111{
112 int err, val;
113
114 val = chn_timeout;
115 err = sysctl_handle_int(oidp, &val, sizeof(val), req);
116 if (val < CHN_TIMEOUT_MIN || val > CHN_TIMEOUT_MAX)
117 err = EINVAL;
118 else
119 chn_timeout = val;
120
121 return err;
122}
123SYSCTL_PROC(_hw_snd, OID_AUTO, timeout, CTLTYPE_INT | CTLFLAG_RW,
124 0, sizeof(int), sysctl_hw_snd_timeout, "I",
125 "interrupt timeout (1 - 10)");
126#endif
127
128static int chn_usefrags = 0;
129TUNABLE_INT("hw.snd.usefrags", &chn_usefrags);
130static int chn_syncdelay = -1;
131TUNABLE_INT("hw.snd.syncdelay", &chn_syncdelay);
132#ifdef SND_DEBUG
133SYSCTL_INT(_hw_snd, OID_AUTO, usefrags, CTLFLAG_RW,
134 &chn_usefrags, 1, "prefer setfragments() over setblocksize()");
135SYSCTL_INT(_hw_snd, OID_AUTO, syncdelay, CTLFLAG_RW,
136 &chn_syncdelay, 1,
137 "append (0-1000) millisecond trailing buffer delay on each sync");
138#endif
139
99/**
100 * @brief Channel sync group lock
101 *
102 * Clients should acquire this lock @b without holding any channel locks
103 * before touching syncgroups or the main syncgroup list.
104 */
105struct mtx snd_pcm_syncgroups_mtx;
106MTX_SYSINIT(pcm_syncgroup, &snd_pcm_syncgroups_mtx, "PCM channel sync group lock", MTX_DEF);

--- 81 unchanged lines hidden (view full) ---

188{
189 struct snd_dbuf *bs = c->bufsoft;
190 struct pcmchan_children *pce;
191
192 CHN_LOCKASSERT(c);
193 if (SLIST_EMPTY(&c->children)) {
194 if (SEL_WAITING(sndbuf_getsel(bs)) && chn_polltrigger(c))
195 selwakeuppri(sndbuf_getsel(bs), PRIBIO);
140/**
141 * @brief Channel sync group lock
142 *
143 * Clients should acquire this lock @b without holding any channel locks
144 * before touching syncgroups or the main syncgroup list.
145 */
146struct mtx snd_pcm_syncgroups_mtx;
147MTX_SYSINIT(pcm_syncgroup, &snd_pcm_syncgroups_mtx, "PCM channel sync group lock", MTX_DEF);

--- 81 unchanged lines hidden (view full) ---

229{
230 struct snd_dbuf *bs = c->bufsoft;
231 struct pcmchan_children *pce;
232
233 CHN_LOCKASSERT(c);
234 if (SLIST_EMPTY(&c->children)) {
235 if (SEL_WAITING(sndbuf_getsel(bs)) && chn_polltrigger(c))
236 selwakeuppri(sndbuf_getsel(bs), PRIBIO);
237 wakeup_one(bs);
196 } else {
197 SLIST_FOREACH(pce, &c->children, link) {
198 CHN_LOCK(pce->channel);
199 chn_wakeup(pce->channel);
200 CHN_UNLOCK(pce->channel);
201 }
202 }
238 } else {
239 SLIST_FOREACH(pce, &c->children, link) {
240 CHN_LOCK(pce->channel);
241 chn_wakeup(pce->channel);
242 CHN_UNLOCK(pce->channel);
243 }
244 }
203
204 wakeup_one(bs);
205}
206
207static int
208chn_sleep(struct pcm_channel *c, char *str, int timeout)
209{
210 struct snd_dbuf *bs = c->bufsoft;
211 int ret;
212

--- 29 unchanged lines hidden (view full) ---

242 DEB(
243 if (delta >= ((sndbuf_getsize(b) * 15) / 16)) {
244 if (!(c->flags & (CHN_F_CLOSING | CHN_F_ABORTING)))
245 device_printf(c->dev, "hwptr went backwards %d -> %d\n", old, hwptr);
246 }
247 );
248
249 if (c->direction == PCMDIR_PLAY) {
245}
246
247static int
248chn_sleep(struct pcm_channel *c, char *str, int timeout)
249{
250 struct snd_dbuf *bs = c->bufsoft;
251 int ret;
252

--- 29 unchanged lines hidden (view full) ---

282 DEB(
283 if (delta >= ((sndbuf_getsize(b) * 15) / 16)) {
284 if (!(c->flags & (CHN_F_CLOSING | CHN_F_ABORTING)))
285 device_printf(c->dev, "hwptr went backwards %d -> %d\n", old, hwptr);
286 }
287 );
288
289 if (c->direction == PCMDIR_PLAY) {
250 amt = MIN(delta, sndbuf_getready(b));
290 amt = min(delta, sndbuf_getready(b));
251 amt -= amt % sndbuf_getbps(b);
252 if (amt > 0)
253 sndbuf_dispose(b, NULL, amt);
254 } else {
291 amt -= amt % sndbuf_getbps(b);
292 if (amt > 0)
293 sndbuf_dispose(b, NULL, amt);
294 } else {
255 amt = MIN(delta, sndbuf_getfree(b));
295 amt = min(delta, sndbuf_getfree(b));
256 amt -= amt % sndbuf_getbps(b);
257 if (amt > 0)
258 sndbuf_acquire(b, NULL, amt);
259 }
296 amt -= amt % sndbuf_getbps(b);
297 if (amt > 0)
298 sndbuf_acquire(b, NULL, amt);
299 }
260 if (snd_verbose > 2 && (c->flags & CHN_F_TRIGGERED) && delta == 0) {
261 device_printf(c->dev, "WARNING: PCMDIR_%s DMA completion "
300 if (snd_verbose > 3 && CHN_STARTED(c) && delta == 0) {
301 device_printf(c->dev, "WARNING: %s DMA completion "
262 "too fast/slow ! hwptr=%u, old=%u "
263 "delta=%u amt=%u ready=%u free=%u\n",
302 "too fast/slow ! hwptr=%u, old=%u "
303 "delta=%u amt=%u ready=%u free=%u\n",
264 (c->direction == PCMDIR_PLAY) ? "PLAY" : "REC",
265 hwptr, old, delta, amt,
304 CHN_DIRSTR(c), hwptr, old, delta, amt,
266 sndbuf_getready(b), sndbuf_getfree(b));
267 }
268
269 return delta;
270}
271
272void
273chn_wrupdate(struct pcm_channel *c)
274{
275 int ret;
276
277 CHN_LOCKASSERT(c);
278 KASSERT(c->direction == PCMDIR_PLAY, ("chn_wrupdate on bad channel"));
279
305 sndbuf_getready(b), sndbuf_getfree(b));
306 }
307
308 return delta;
309}
310
311void
312chn_wrupdate(struct pcm_channel *c)
313{
314 int ret;
315
316 CHN_LOCKASSERT(c);
317 KASSERT(c->direction == PCMDIR_PLAY, ("chn_wrupdate on bad channel"));
318
280 if ((c->flags & (CHN_F_MAPPED | CHN_F_VIRTUAL)) || !(c->flags & CHN_F_TRIGGERED))
319 if ((c->flags & (CHN_F_MAPPED | CHN_F_VIRTUAL)) || CHN_STOPPED(c))
281 return;
282 chn_dmaupdate(c);
283 ret = chn_wrfeed(c);
284 /* tell the driver we've updated the primary buffer */
285 chn_trigger(c, PCMTRIG_EMLDMAWR);
286 DEB(if (ret)
287 printf("chn_wrupdate: chn_wrfeed returned %d\n", ret);)
288

--- 27 unchanged lines hidden (view full) ---

316
317 ret = (amt > 0) ? sndbuf_feed(bs, b, c, c->feeder, amt) : ENOSPC;
318 /*
319 * Possible xruns. There should be no empty space left in buffer.
320 */
321 if (sndbuf_getfree(b) > 0)
322 c->xruns++;
323
320 return;
321 chn_dmaupdate(c);
322 ret = chn_wrfeed(c);
323 /* tell the driver we've updated the primary buffer */
324 chn_trigger(c, PCMTRIG_EMLDMAWR);
325 DEB(if (ret)
326 printf("chn_wrupdate: chn_wrfeed returned %d\n", ret);)
327

--- 27 unchanged lines hidden (view full) ---

355
356 ret = (amt > 0) ? sndbuf_feed(bs, b, c, c->feeder, amt) : ENOSPC;
357 /*
358 * Possible xruns. There should be no empty space left in buffer.
359 */
360 if (sndbuf_getfree(b) > 0)
361 c->xruns++;
362
363#if 0
324 if (ret == 0 && sndbuf_getfree(b) < amt)
325 chn_wakeup(c);
364 if (ret == 0 && sndbuf_getfree(b) < amt)
365 chn_wakeup(c);
366#endif
367 chn_wakeup(c);
326
327 return ret;
328}
329
330static void
331chn_wrintr(struct pcm_channel *c)
332{
333 int ret;

--- 14 unchanged lines hidden (view full) ---

348 * if blocking, sleep, rinse and repeat.
349 *
350 * called externally, so must handle locking
351 */
352
353int
354chn_write(struct pcm_channel *c, struct uio *buf)
355{
368
369 return ret;
370}
371
372static void
373chn_wrintr(struct pcm_channel *c)
374{
375 int ret;

--- 14 unchanged lines hidden (view full) ---

390 * if blocking, sleep, rinse and repeat.
391 *
392 * called externally, so must handle locking
393 */
394
395int
396chn_write(struct pcm_channel *c, struct uio *buf)
397{
356 int ret, count, sz;
357 struct snd_dbuf *bs = c->bufsoft;
358 void *off;
398 struct snd_dbuf *bs = c->bufsoft;
399 void *off;
359 int t, x, togo, p;
400 int ret, timeout, sz, t, p;
360
361 CHN_LOCKASSERT(c);
362
363 ret = 0;
401
402 CHN_LOCKASSERT(c);
403
404 ret = 0;
364 count = hz;
405 timeout = chn_timeout * hz;
365
406
366 while (!ret && (buf->uio_resid > 0) && (count > 0)) {
367 sz = sndbuf_getfree(bs);
368 if (sz == 0) {
369 if (c->flags & CHN_F_NBIO)
370 ret = EWOULDBLOCK;
371 else if (c->flags & CHN_F_NOTRIGGER) {
372 /**
373 * @todo Evaluate whether EAGAIN is truly desirable.
374 * 4Front drivers behave like this, but I'm
375 * not sure if it at all violates the "write
376 * should be allowed to block" model.
377 *
378 * The idea is that, while set with CHN_F_NOTRIGGER,
379 * a channel isn't playing, *but* without this we
380 * end up with "interrupt timeout / channel dead".
381 */
382 ret = EAGAIN;
383 } else {
384 ret = chn_sleep(c, "pcmwr", c->timeout);
385 if (ret == EWOULDBLOCK) {
386 count -= c->timeout;
387 ret = 0;
388 } else if (ret == ERESTART || ret == EINTR) {
389 c->flags |= CHN_F_ABORTING;
390 return ret;
391 } else if (ret == 0)
392 count = hz;
393 }
394 } else {
395 sz = MIN(sz, buf->uio_resid);
396 KASSERT(sz > 0, ("confusion in chn_write"));
397 /* printf("sz: %d\n", sz); */
398
407 while (ret == 0 && buf->uio_resid > 0) {
408 sz = min(buf->uio_resid, sndbuf_getfree(bs));
409 if (sz > 0) {
399 /*
400 * The following assumes that the free space in
401 * the buffer can never be less around the
402 * unlock-uiomove-lock sequence.
403 */
410 /*
411 * The following assumes that the free space in
412 * the buffer can never be less around the
413 * unlock-uiomove-lock sequence.
414 */
404 togo = sz;
405 while (ret == 0 && togo > 0) {
415 while (ret == 0 && sz > 0) {
406 p = sndbuf_getfreeptr(bs);
416 p = sndbuf_getfreeptr(bs);
407 t = MIN(togo, sndbuf_getsize(bs) - p);
417 t = min(sz, sndbuf_getsize(bs) - p);
408 off = sndbuf_getbufofs(bs, p);
409 CHN_UNLOCK(c);
410 ret = uiomove(off, t, buf);
411 CHN_LOCK(c);
418 off = sndbuf_getbufofs(bs, p);
419 CHN_UNLOCK(c);
420 ret = uiomove(off, t, buf);
421 CHN_LOCK(c);
412 togo -= t;
413 x = sndbuf_acquire(bs, NULL, t);
422 sz -= t;
423 sndbuf_acquire(bs, NULL, t);
414 }
415 ret = 0;
424 }
425 ret = 0;
416 if (!(c->flags & CHN_F_TRIGGERED))
426 if (CHN_STOPPED(c))
417 chn_start(c, 0);
427 chn_start(c, 0);
428 } else if (c->flags & (CHN_F_NBIO | CHN_F_NOTRIGGER)) {
429 /**
430 * @todo Evaluate whether EAGAIN is truly desirable.
431 * 4Front drivers behave like this, but I'm
432 * not sure if it at all violates the "write
433 * should be allowed to block" model.
434 *
435 * The idea is that, while set with CHN_F_NOTRIGGER,
436 * a channel isn't playing, *but* without this we
437 * end up with "interrupt timeout / channel dead".
438 */
439 ret = EAGAIN;
440 } else {
441 ret = chn_sleep(c, "pcmwr", timeout);
442 if (ret == EAGAIN) {
443 ret = EINVAL;
444 c->flags |= CHN_F_DEAD;
445 printf("%s: play interrupt timeout, "
446 "channel dead\n", c->name);
447 } else if (ret == ERESTART || ret == EINTR)
448 c->flags |= CHN_F_ABORTING;
418 }
419 }
449 }
450 }
420 /* printf("ret: %d left: %d\n", ret, buf->uio_resid); */
421
451
422 if (count <= 0) {
423 c->flags |= CHN_F_DEAD;
424 printf("%s: play interrupt timeout, channel dead\n", c->name);
425 }
426
427 return ret;
428}
429
430#if 0
431static int
432chn_rddump(struct pcm_channel *c, unsigned int cnt)
433{
434 struct snd_dbuf *b = c->bufhard;

--- 50 unchanged lines hidden (view full) ---

485void
486chn_rdupdate(struct pcm_channel *c)
487{
488 int ret;
489
490 CHN_LOCKASSERT(c);
491 KASSERT(c->direction == PCMDIR_REC, ("chn_rdupdate on bad channel"));
492
452 return ret;
453}
454
455#if 0
456static int
457chn_rddump(struct pcm_channel *c, unsigned int cnt)
458{
459 struct snd_dbuf *b = c->bufhard;

--- 50 unchanged lines hidden (view full) ---

510void
511chn_rdupdate(struct pcm_channel *c)
512{
513 int ret;
514
515 CHN_LOCKASSERT(c);
516 KASSERT(c->direction == PCMDIR_REC, ("chn_rdupdate on bad channel"));
517
493 if ((c->flags & CHN_F_MAPPED) || !(c->flags & CHN_F_TRIGGERED))
518 if ((c->flags & CHN_F_MAPPED) || CHN_STOPPED(c))
494 return;
495 chn_trigger(c, PCMTRIG_EMLDMARD);
496 chn_dmaupdate(c);
497 ret = chn_rdfeed(c);
498 DEB(if (ret)
499 printf("chn_rdfeed: %d\n", ret);)
500
501}

--- 18 unchanged lines hidden (view full) ---

520 * if blocking, sleep, rinse and repeat.
521 *
522 * called externally, so must handle locking
523 */
524
525int
526chn_read(struct pcm_channel *c, struct uio *buf)
527{
519 return;
520 chn_trigger(c, PCMTRIG_EMLDMARD);
521 chn_dmaupdate(c);
522 ret = chn_rdfeed(c);
523 DEB(if (ret)
524 printf("chn_rdfeed: %d\n", ret);)
525
526}

--- 18 unchanged lines hidden (view full) ---

545 * if blocking, sleep, rinse and repeat.
546 *
547 * called externally, so must handle locking
548 */
549
550int
551chn_read(struct pcm_channel *c, struct uio *buf)
552{
528 int ret, sz, count;
529 struct snd_dbuf *bs = c->bufsoft;
530 void *off;
553 struct snd_dbuf *bs = c->bufsoft;
554 void *off;
531 int t, x, togo, p;
555 int ret, timeout, sz, t, p;
532
533 CHN_LOCKASSERT(c);
556
557 CHN_LOCKASSERT(c);
534 if (!(c->flags & CHN_F_TRIGGERED))
558
559 if (CHN_STOPPED(c))
535 chn_start(c, 0);
536
537 ret = 0;
560 chn_start(c, 0);
561
562 ret = 0;
538 count = hz;
539 while (!ret && (buf->uio_resid > 0) && (count > 0)) {
540 sz = MIN(buf->uio_resid, sndbuf_getready(bs));
563 timeout = chn_timeout * hz;
541
564
565 while (ret == 0 && buf->uio_resid > 0) {
566 sz = min(buf->uio_resid, sndbuf_getready(bs));
542 if (sz > 0) {
543 /*
544 * The following assumes that the free space in
545 * the buffer can never be less around the
546 * unlock-uiomove-lock sequence.
547 */
567 if (sz > 0) {
568 /*
569 * The following assumes that the free space in
570 * the buffer can never be less around the
571 * unlock-uiomove-lock sequence.
572 */
548 togo = sz;
549 while (ret == 0 && togo > 0) {
573 while (ret == 0 && sz > 0) {
550 p = sndbuf_getreadyptr(bs);
574 p = sndbuf_getreadyptr(bs);
551 t = MIN(togo, sndbuf_getsize(bs) - p);
575 t = min(sz, sndbuf_getsize(bs) - p);
552 off = sndbuf_getbufofs(bs, p);
553 CHN_UNLOCK(c);
554 ret = uiomove(off, t, buf);
555 CHN_LOCK(c);
576 off = sndbuf_getbufofs(bs, p);
577 CHN_UNLOCK(c);
578 ret = uiomove(off, t, buf);
579 CHN_LOCK(c);
556 togo -= t;
557 x = sndbuf_dispose(bs, NULL, t);
580 sz -= t;
581 sndbuf_dispose(bs, NULL, t);
558 }
559 ret = 0;
582 }
583 ret = 0;
560 } else {
561 if (c->flags & CHN_F_NBIO)
562 ret = EWOULDBLOCK;
563 else {
564 ret = chn_sleep(c, "pcmrd", c->timeout);
565 if (ret == EWOULDBLOCK) {
566 count -= c->timeout;
567 ret = 0;
568 } else if (ret == ERESTART || ret == EINTR) {
569 c->flags |= CHN_F_ABORTING;
570 return ret;
571 } else
572 count = hz;
573 }
584 } else if (c->flags & (CHN_F_NBIO | CHN_F_NOTRIGGER))
585 ret = EAGAIN;
586 else {
587 ret = chn_sleep(c, "pcmrd", timeout);
588 if (ret == EAGAIN) {
589 ret = EINVAL;
590 c->flags |= CHN_F_DEAD;
591 printf("%s: record interrupt timeout, "
592 "channel dead\n", c->name);
593 } else if (ret == ERESTART || ret == EINTR)
594 c->flags |= CHN_F_ABORTING;
574 }
575 }
576
595 }
596 }
597
577 if (count <= 0) {
578 c->flags |= CHN_F_DEAD;
579 printf("%s: record interrupt timeout, channel dead\n", c->name);
580 }
581
582 return ret;
583}
584
585void
586chn_intr(struct pcm_channel *c)
587{
588 CHN_LOCK(c);
589 c->interrupts++;

--- 8 unchanged lines hidden (view full) ---

598chn_start(struct pcm_channel *c, int force)
599{
600 u_int32_t i, j;
601 struct snd_dbuf *b = c->bufhard;
602 struct snd_dbuf *bs = c->bufsoft;
603
604 CHN_LOCKASSERT(c);
605 /* if we're running, or if we're prevented from triggering, bail */
598 return ret;
599}
600
601void
602chn_intr(struct pcm_channel *c)
603{
604 CHN_LOCK(c);
605 c->interrupts++;

--- 8 unchanged lines hidden (view full) ---

614chn_start(struct pcm_channel *c, int force)
615{
616 u_int32_t i, j;
617 struct snd_dbuf *b = c->bufhard;
618 struct snd_dbuf *bs = c->bufsoft;
619
620 CHN_LOCKASSERT(c);
621 /* if we're running, or if we're prevented from triggering, bail */
606 if ((c->flags & CHN_F_TRIGGERED) || ((c->flags & CHN_F_NOTRIGGER) && !force))
622 if (CHN_STARTED(c) || ((c->flags & CHN_F_NOTRIGGER) && !force))
607 return EINVAL;
608
609 if (force) {
610 i = 1;
611 j = 0;
612 } else {
613 if (c->direction == PCMDIR_REC) {
614 i = sndbuf_getfree(bs);
623 return EINVAL;
624
625 if (force) {
626 i = 1;
627 j = 0;
628 } else {
629 if (c->direction == PCMDIR_REC) {
630 i = sndbuf_getfree(bs);
615 j = sndbuf_getready(b);
631 j = (i > 0) ? 1 : sndbuf_getready(b);
616 } else {
632 } else {
617 struct snd_dbuf *pb;
633 if (sndbuf_getfree(bs) == 0) {
634 i = 1;
635 j = 0;
636 } else {
637 struct snd_dbuf *pb;
618
638
619 i = sndbuf_getready(bs);
620
621 pb = BUF_PARENT(c, b);
622 j = min(sndbuf_xbytes(sndbuf_getsize(pb), pb, bs),
623 sndbuf_getsize(bs));
639 pb = BUF_PARENT(c, b);
640 i = sndbuf_xbytes(sndbuf_getready(bs), bs, pb);
641 j = sndbuf_getbps(pb);
642 }
624 }
625 if (snd_verbose > 3 && SLIST_EMPTY(&c->children))
643 }
644 if (snd_verbose > 3 && SLIST_EMPTY(&c->children))
626 printf("%s: PCMDIR_%s (%s) threshold i=%d j=%d\n",
627 __func__,
628 (c->direction == PCMDIR_PLAY) ? "PLAY" : "REC",
645 printf("%s: %s (%s) threshold i=%d j=%d\n",
646 __func__, CHN_DIRSTR(c),
629 (c->flags & CHN_F_VIRTUAL) ? "virtual" : "hardware",
630 i, j);
631 }
632
633 if (i >= j) {
634 c->flags |= CHN_F_TRIGGERED;
635 sndbuf_setrun(b, 1);
636 c->feedcount = (c->flags & CHN_F_CLOSING) ? 2 : 0;
637 c->interrupts = 0;
638 c->xruns = 0;
639 if (c->direction == PCMDIR_PLAY && c->parentchannel == NULL) {
647 (c->flags & CHN_F_VIRTUAL) ? "virtual" : "hardware",
648 i, j);
649 }
650
651 if (i >= j) {
652 c->flags |= CHN_F_TRIGGERED;
653 sndbuf_setrun(b, 1);
654 c->feedcount = (c->flags & CHN_F_CLOSING) ? 2 : 0;
655 c->interrupts = 0;
656 c->xruns = 0;
657 if (c->direction == PCMDIR_PLAY && c->parentchannel == NULL) {
640 chn_wrfeed(c);
658 sndbuf_fillsilence(b);
641 if (snd_verbose > 3)
642 printf("%s: %s starting! (%s) (ready=%d "
659 if (snd_verbose > 3)
660 printf("%s: %s starting! (%s) (ready=%d "
643 "force=%d i=%d j=%d intrtimeout=%u)\n",
661 "force=%d i=%d j=%d intrtimeout=%u "
662 "latency=%dms)\n",
644 __func__,
645 (c->flags & CHN_F_HAS_VCHAN) ?
646 "VCHAN" : "HW",
647 (c->flags & CHN_F_CLOSING) ? "closing" :
648 "running",
649 sndbuf_getready(b),
663 __func__,
664 (c->flags & CHN_F_HAS_VCHAN) ?
665 "VCHAN" : "HW",
666 (c->flags & CHN_F_CLOSING) ? "closing" :
667 "running",
668 sndbuf_getready(b),
650 force, i, j, c->timeout);
669 force, i, j, c->timeout,
670 (sndbuf_getsize(b) * 1000) /
671 (sndbuf_getbps(b) * sndbuf_getspd(b)));
651 }
652 chn_trigger(c, PCMTRIG_START);
653 return 0;
654 }
655
656 return 0;
657}
658

--- 13 unchanged lines hidden (view full) ---

672 * a threshold. The threshold is checked against fl or rl respectively.
673 * Assume that the condition can become true, do not check here...
674 */
675int
676chn_sync(struct pcm_channel *c, int threshold)
677{
678 int ret, count, hcount, minflush, resid, residp;
679 struct snd_dbuf *b, *bs;
672 }
673 chn_trigger(c, PCMTRIG_START);
674 return 0;
675 }
676
677 return 0;
678}
679

--- 13 unchanged lines hidden (view full) ---

693 * a threshold. The threshold is checked against fl or rl respectively.
694 * Assume that the condition can become true, do not check here...
695 */
696int
697chn_sync(struct pcm_channel *c, int threshold)
698{
699 int ret, count, hcount, minflush, resid, residp;
700 struct snd_dbuf *b, *bs;
701 int syncdelay, blksz;
680
681 CHN_LOCKASSERT(c);
682
702
703 CHN_LOCKASSERT(c);
704
683 if (c->flags & (CHN_F_DEAD | CHN_F_ABORTING))
705 bs = c->bufsoft;
706
707 if ((c->flags & (CHN_F_DEAD | CHN_F_ABORTING)) ||
708 (threshold < 1 && sndbuf_getready(bs) < 1))
684 return 0;
685
686 if (c->direction != PCMDIR_PLAY)
687 return EINVAL;
688
709 return 0;
710
711 if (c->direction != PCMDIR_PLAY)
712 return EINVAL;
713
689 bs = c->bufsoft;
690
691 /* if we haven't yet started and nothing is buffered, else start*/
714 /* if we haven't yet started and nothing is buffered, else start*/
692 if (!(c->flags & CHN_F_TRIGGERED)) {
693 if (sndbuf_getready(bs) > 0) {
715 if (CHN_STOPPED(c)) {
716 if (threshold > 0 || sndbuf_getready(bs) > 0) {
694 ret = chn_start(c, 1);
695 if (ret)
696 return ret;
697 } else
698 return 0;
699 }
700
701 b = BUF_PARENT(c, c->bufhard);
702
717 ret = chn_start(c, 1);
718 if (ret)
719 return ret;
720 } else
721 return 0;
722 }
723
724 b = BUF_PARENT(c, c->bufhard);
725
703 threshold += sndbuf_getready(b);
704 minflush = sndbuf_xbytes(threshold, b, bs);
726 minflush = threshold + sndbuf_xbytes(sndbuf_getready(b), b, bs);
727
728 syncdelay = chn_syncdelay;
729
730 if (syncdelay < 0 && (threshold > 0 || sndbuf_getready(bs) > 0))
731 minflush += sndbuf_xbytes(sndbuf_getsize(b), b, bs);
732
733 /*
734 * Append (0-1000) millisecond trailing buffer (if needed)
735 * for slower / high latency hardwares (notably USB audio)
736 * to avoid audible truncation.
737 */
738 if (syncdelay > 0)
739 minflush += (sndbuf_getbps(bs) * sndbuf_getspd(bs) *
740 ((syncdelay > 1000) ? 1000 : syncdelay)) / 1000;
741
705 minflush -= minflush % sndbuf_getbps(bs);
706
707 if (minflush > 0) {
708 threshold = min(minflush, sndbuf_getfree(bs));
709 sndbuf_clear(bs, threshold);
710 sndbuf_acquire(bs, NULL, threshold);
711 minflush -= threshold;
712 }
713
714 resid = sndbuf_getready(bs);
715 residp = resid;
742 minflush -= minflush % sndbuf_getbps(bs);
743
744 if (minflush > 0) {
745 threshold = min(minflush, sndbuf_getfree(bs));
746 sndbuf_clear(bs, threshold);
747 sndbuf_acquire(bs, NULL, threshold);
748 minflush -= threshold;
749 }
750
751 resid = sndbuf_getready(bs);
752 residp = resid;
716 count = sndbuf_xbytes(minflush + resid, bs, b) / sndbuf_getblksz(b);
753 blksz = sndbuf_getblksz(b);
754 if (blksz < 1) {
755 printf("%s: WARNING: blksz < 1 ! maxsize=%d [%d/%d/%d]\n",
756 __func__, sndbuf_getmaxsize(b), sndbuf_getsize(b),
757 sndbuf_getblksz(b), sndbuf_getblkcnt(b));
758 if (sndbuf_getblkcnt(b) > 0)
759 blksz = sndbuf_getsize(b) / sndbuf_getblkcnt(b);
760 if (blksz < 1)
761 blksz = 1;
762 }
763 count = sndbuf_xbytes(minflush + resid, bs, b) / blksz;
717 hcount = count;
718 ret = 0;
719
764 hcount = count;
765 ret = 0;
766
720 while (count > 0 && resid > 0) {
767 if (snd_verbose > 3)
768 printf("%s: [begin] timeout=%d count=%d "
769 "minflush=%d resid=%d\n", __func__, c->timeout, count,
770 minflush, resid);
771
772 while (count > 0 && (resid > 0 || minflush > 0)) {
721 ret = chn_sleep(c, "pcmsyn", c->timeout);
722 if (ret == ERESTART || ret == EINTR) {
723 c->flags |= CHN_F_ABORTING;
724 break;
725 }
773 ret = chn_sleep(c, "pcmsyn", c->timeout);
774 if (ret == ERESTART || ret == EINTR) {
775 c->flags |= CHN_F_ABORTING;
776 break;
777 }
726 if (ret == 0 || ret == EWOULDBLOCK) {
778 if (ret == 0 || ret == EAGAIN) {
727 resid = sndbuf_getready(bs);
728 if (resid == residp) {
729 --count;
730 if (snd_verbose > 3)
731 printf("%s: [stalled] timeout=%d "
732 "count=%d hcount=%d "
733 "resid=%d minflush=%d\n",
734 __func__, c->timeout, count,

--- 31 unchanged lines hidden (view full) ---

766/* called externally, handle locking */
767int
768chn_poll(struct pcm_channel *c, int ev, struct thread *td)
769{
770 struct snd_dbuf *bs = c->bufsoft;
771 int ret;
772
773 CHN_LOCKASSERT(c);
779 resid = sndbuf_getready(bs);
780 if (resid == residp) {
781 --count;
782 if (snd_verbose > 3)
783 printf("%s: [stalled] timeout=%d "
784 "count=%d hcount=%d "
785 "resid=%d minflush=%d\n",
786 __func__, c->timeout, count,

--- 31 unchanged lines hidden (view full) ---

818/* called externally, handle locking */
819int
820chn_poll(struct pcm_channel *c, int ev, struct thread *td)
821{
822 struct snd_dbuf *bs = c->bufsoft;
823 int ret;
824
825 CHN_LOCKASSERT(c);
774 if (!(c->flags & CHN_F_MAPPED) && !(c->flags & CHN_F_TRIGGERED))
826 if (!(c->flags & (CHN_F_MAPPED | CHN_F_TRIGGERED)))
775 chn_start(c, 1);
776 ret = 0;
777 if (chn_polltrigger(c) && chn_pollreset(c))
778 ret = ev;
779 else
780 selrecord(td, sndbuf_getsel(bs));
781 return ret;
782}

--- 7 unchanged lines hidden (view full) ---

790int
791chn_abort(struct pcm_channel *c)
792{
793 int missing = 0;
794 struct snd_dbuf *b = c->bufhard;
795 struct snd_dbuf *bs = c->bufsoft;
796
797 CHN_LOCKASSERT(c);
827 chn_start(c, 1);
828 ret = 0;
829 if (chn_polltrigger(c) && chn_pollreset(c))
830 ret = ev;
831 else
832 selrecord(td, sndbuf_getsel(bs));
833 return ret;
834}

--- 7 unchanged lines hidden (view full) ---

842int
843chn_abort(struct pcm_channel *c)
844{
845 int missing = 0;
846 struct snd_dbuf *b = c->bufhard;
847 struct snd_dbuf *bs = c->bufsoft;
848
849 CHN_LOCKASSERT(c);
798 if (!(c->flags & CHN_F_TRIGGERED))
850 if (CHN_STOPPED(c))
799 return 0;
800 c->flags |= CHN_F_ABORTING;
801
802 c->flags &= ~CHN_F_TRIGGERED;
803 /* kill the channel */
804 chn_trigger(c, PCMTRIG_ABORT);
805 sndbuf_setrun(b, 0);
806 if (!(c->flags & CHN_F_VIRTUAL))
807 chn_dmaupdate(c);
851 return 0;
852 c->flags |= CHN_F_ABORTING;
853
854 c->flags &= ~CHN_F_TRIGGERED;
855 /* kill the channel */
856 chn_trigger(c, PCMTRIG_ABORT);
857 sndbuf_setrun(b, 0);
858 if (!(c->flags & CHN_F_VIRTUAL))
859 chn_dmaupdate(c);
808 missing = sndbuf_getready(bs) + sndbuf_getready(b);
860 missing = sndbuf_getready(bs);
809
810 c->flags &= ~CHN_F_ABORTING;
811 return missing;
812}
813
814/*
815 * this routine tries to flush the dma transfer. It is called
816 * on a close of a playback channel.

--- 308 unchanged lines hidden (view full) ---

1125}
1126
1127int
1128chn_kill(struct pcm_channel *c)
1129{
1130 struct snd_dbuf *b = c->bufhard;
1131 struct snd_dbuf *bs = c->bufsoft;
1132
861
862 c->flags &= ~CHN_F_ABORTING;
863 return missing;
864}
865
866/*
867 * this routine tries to flush the dma transfer. It is called
868 * on a close of a playback channel.

--- 308 unchanged lines hidden (view full) ---

1177}
1178
1179int
1180chn_kill(struct pcm_channel *c)
1181{
1182 struct snd_dbuf *b = c->bufhard;
1183 struct snd_dbuf *bs = c->bufsoft;
1184
1133 if (c->flags & CHN_F_TRIGGERED)
1185 if (CHN_STARTED(c))
1134 chn_trigger(c, PCMTRIG_ABORT);
1135 while (chn_removefeeder(c) == 0);
1136 if (CHANNEL_FREE(c->methods, c->devinfo))
1137 sndbuf_free(b);
1138 c->flags |= CHN_F_DEAD;
1139 sndbuf_destroy(bs);
1140 sndbuf_destroy(b);
1141 chn_lockdestroy(c);

--- 46 unchanged lines hidden (view full) ---

1188 while (v >> ret)
1189 ret++;
1190 ret = 1 << (ret - 1);
1191 while (ret < v)
1192 ret <<= 1;
1193 return ret;
1194}
1195
1186 chn_trigger(c, PCMTRIG_ABORT);
1187 while (chn_removefeeder(c) == 0);
1188 if (CHANNEL_FREE(c->methods, c->devinfo))
1189 sndbuf_free(b);
1190 c->flags |= CHN_F_DEAD;
1191 sndbuf_destroy(bs);
1192 sndbuf_destroy(b);
1193 chn_lockdestroy(c);

--- 46 unchanged lines hidden (view full) ---

1240 while (v >> ret)
1241 ret++;
1242 ret = 1 << (ret - 1);
1243 while (ret < v)
1244 ret <<= 1;
1245 return ret;
1246}
1247
1248static u_int32_t
1249round_blksz(u_int32_t v, int round)
1250{
1251 u_int32_t ret, tmp;
1252
1253 if (round < 1)
1254 round = 1;
1255
1256 ret = min(round_pow2(v), CHN_2NDBUFMAXSIZE >> 1);
1257
1258 if (ret > v && (ret >> 1) > 0 && (ret >> 1) >= ((v * 3) >> 2))
1259 ret >>= 1;
1260
1261 tmp = ret - (ret % round);
1262 while (tmp < 16 || tmp < round) {
1263 ret <<= 1;
1264 tmp = ret - (ret % round);
1265 }
1266
1267 return ret;
1268}
1269
1196/*
1197 * 4Front call it DSP Policy, while we call it "Latency Profile". The idea
1198 * is to keep 2nd buffer short so that it doesn't cause long queue during
1199 * buffer transfer.
1200 *
1201 * Latency reference table for 48khz stereo 16bit: (PLAY)
1202 *
1203 * +---------+------------+-----------+------------+

--- 76 unchanged lines hidden (view full) ---

1280 {15, 15, 15, 15, 15, 16, 16, 16, 16, 16, 17}}
1281
1282#define CHN_LATENCY_DATA_REF 192000 /* 48khz stereo 16bit ~ 48000 x 2 x 2 */
1283
1284static int
1285chn_calclatency(int dir, int latency, int bps, u_int32_t datarate,
1286 u_int32_t max, int *rblksz, int *rblkcnt)
1287{
1270/*
1271 * 4Front call it DSP Policy, while we call it "Latency Profile". The idea
1272 * is to keep 2nd buffer short so that it doesn't cause long queue during
1273 * buffer transfer.
1274 *
1275 * Latency reference table for 48khz stereo 16bit: (PLAY)
1276 *
1277 * +---------+------------+-----------+------------+

--- 76 unchanged lines hidden (view full) ---

1354 {15, 15, 15, 15, 15, 16, 16, 16, 16, 16, 17}}
1355
1356#define CHN_LATENCY_DATA_REF 192000 /* 48khz stereo 16bit ~ 48000 x 2 x 2 */
1357
1358static int
1359chn_calclatency(int dir, int latency, int bps, u_int32_t datarate,
1360 u_int32_t max, int *rblksz, int *rblkcnt)
1361{
1288 u_int32_t bufsz;
1289 int blksz, blkcnt;
1290 static int pblkcnts[CHN_LATENCY_PROFILE_MAX+1][CHN_LATENCY_MAX+1] =
1362 static int pblkcnts[CHN_LATENCY_PROFILE_MAX + 1][CHN_LATENCY_MAX + 1] =
1291 CHN_LATENCY_PBLKCNT_REF;
1363 CHN_LATENCY_PBLKCNT_REF;
1292 static int pbufszs[CHN_LATENCY_PROFILE_MAX+1][CHN_LATENCY_MAX+1] =
1364 static int pbufszs[CHN_LATENCY_PROFILE_MAX + 1][CHN_LATENCY_MAX + 1] =
1293 CHN_LATENCY_PBUFSZ_REF;
1365 CHN_LATENCY_PBUFSZ_REF;
1294 static int rblkcnts[CHN_LATENCY_PROFILE_MAX+1][CHN_LATENCY_MAX+1] =
1366 static int rblkcnts[CHN_LATENCY_PROFILE_MAX + 1][CHN_LATENCY_MAX + 1] =
1295 CHN_LATENCY_RBLKCNT_REF;
1367 CHN_LATENCY_RBLKCNT_REF;
1296 static int rbufszs[CHN_LATENCY_PROFILE_MAX+1][CHN_LATENCY_MAX+1] =
1368 static int rbufszs[CHN_LATENCY_PROFILE_MAX + 1][CHN_LATENCY_MAX + 1] =
1297 CHN_LATENCY_RBUFSZ_REF;
1369 CHN_LATENCY_RBUFSZ_REF;
1370 u_int32_t bufsz;
1371 int lprofile, blksz, blkcnt;
1298
1372
1299 if (CHN_LATENCY_MIN != 0 || CHN_LATENCY_MAX != 10 ||
1300 latency < CHN_LATENCY_MIN || latency > CHN_LATENCY_MAX ||
1373 if (latency < CHN_LATENCY_MIN || latency > CHN_LATENCY_MAX ||
1301 bps < 1 || datarate < 1 ||
1302 !(dir == PCMDIR_PLAY || dir == PCMDIR_REC)) {
1303 if (rblksz != NULL)
1304 *rblksz = CHN_2NDBUFMAXSIZE >> 1;
1305 if (rblkcnt != NULL)
1306 *rblkcnt = 2;
1307 printf("%s: FAILED dir=%d latency=%d bps=%d "
1308 "datarate=%u max=%u\n",
1309 __func__, dir, latency, bps, datarate, max);
1310 return CHN_2NDBUFMAXSIZE;
1311 }
1312
1374 bps < 1 || datarate < 1 ||
1375 !(dir == PCMDIR_PLAY || dir == PCMDIR_REC)) {
1376 if (rblksz != NULL)
1377 *rblksz = CHN_2NDBUFMAXSIZE >> 1;
1378 if (rblkcnt != NULL)
1379 *rblkcnt = 2;
1380 printf("%s: FAILED dir=%d latency=%d bps=%d "
1381 "datarate=%u max=%u\n",
1382 __func__, dir, latency, bps, datarate, max);
1383 return CHN_2NDBUFMAXSIZE;
1384 }
1385
1386 lprofile = chn_latency_profile;
1387
1313 if (dir == PCMDIR_PLAY) {
1388 if (dir == PCMDIR_PLAY) {
1314 blkcnt = pblkcnts[chn_latency_profile][latency];
1315 bufsz = pbufszs[chn_latency_profile][latency];
1389 blkcnt = pblkcnts[lprofile][latency];
1390 bufsz = pbufszs[lprofile][latency];
1316 } else {
1391 } else {
1317 blkcnt = rblkcnts[chn_latency_profile][latency];
1318 bufsz = rbufszs[chn_latency_profile][latency];
1392 blkcnt = rblkcnts[lprofile][latency];
1393 bufsz = rbufszs[lprofile][latency];
1319 }
1394 }
1320 bufsz = snd_xbytes(1 << bufsz, CHN_LATENCY_DATA_REF, datarate);
1395
1396 bufsz = round_pow2(snd_xbytes(1 << bufsz, CHN_LATENCY_DATA_REF,
1397 datarate));
1321 if (bufsz > max)
1322 bufsz = max;
1398 if (bufsz > max)
1399 bufsz = max;
1323 if (bufsz < 32)
1324 bufsz = 32;
1325 blksz = bufsz >> blkcnt;
1326 blksz -= blksz % bps;
1327 while (blksz < 16 || blksz < bps)
1328 blksz += bps;
1329 while ((blksz << blkcnt) > bufsz && blkcnt > 1)
1330 blkcnt--;
1400 blksz = round_blksz(bufsz >> blkcnt, bps);
1401
1331 if (rblksz != NULL)
1332 *rblksz = blksz;
1333 if (rblkcnt != NULL)
1334 *rblkcnt = 1 << blkcnt;
1335
1336 return blksz << blkcnt;
1337}
1338
1402 if (rblksz != NULL)
1403 *rblksz = blksz;
1404 if (rblkcnt != NULL)
1405 *rblkcnt = 1 << blkcnt;
1406
1407 return blksz << blkcnt;
1408}
1409
1339/*
1340 * Note that there is no strict requirement to align blksz to the
1341 * nearest ^2, except for hardware CHANNEL_SETBLOCKSIZE. If the application
1342 * trying to act smarter and requesting for specific blksz/blkcnt, so be it.
1343 */
1344static int
1345chn_resizebuf(struct pcm_channel *c, int latency,
1346 int blkcnt, int blksz)
1347{
1348 struct snd_dbuf *b, *bs, *pb;
1410static int
1411chn_resizebuf(struct pcm_channel *c, int latency,
1412 int blkcnt, int blksz)
1413{
1414 struct snd_dbuf *b, *bs, *pb;
1349 int sblksz, sblkcnt, hblksz, limit = 1;
1415 int sblksz, sblkcnt, hblksz, hblkcnt, limit = 1;
1350 int ret;
1351
1352 CHN_LOCKASSERT(c);
1353
1416 int ret;
1417
1418 CHN_LOCKASSERT(c);
1419
1354 if (!CANCHANGE(c) || (c->flags & CHN_F_MAPPED) ||
1420 if ((c->flags & (CHN_F_MAPPED | CHN_F_TRIGGERED)) ||
1355 !(c->direction == PCMDIR_PLAY || c->direction == PCMDIR_REC))
1356 return EINVAL;
1357
1358 if (latency == -1) {
1359 c->latency = -1;
1360 latency = chn_latency;
1361 } else if (latency == -2) {
1362 latency = c->latency;

--- 31 unchanged lines hidden (view full) ---

1394 if (c->flags & CHN_F_HAS_SIZE) {
1395 /*
1396 * The application has requested their own blksz/blkcnt.
1397 * Just obey with it, and let them toast alone. We can
1398 * clamp it to the nearest latency profile, but that would
1399 * defeat the purpose of having custom control. The least
1400 * we can do is round it to the nearest ^2 and align it.
1401 */
1421 !(c->direction == PCMDIR_PLAY || c->direction == PCMDIR_REC))
1422 return EINVAL;
1423
1424 if (latency == -1) {
1425 c->latency = -1;
1426 latency = chn_latency;
1427 } else if (latency == -2) {
1428 latency = c->latency;

--- 31 unchanged lines hidden (view full) ---

1460 if (c->flags & CHN_F_HAS_SIZE) {
1461 /*
1462 * The application has requested their own blksz/blkcnt.
1463 * Just obey with it, and let them toast alone. We can
1464 * clamp it to the nearest latency profile, but that would
1465 * defeat the purpose of having custom control. The least
1466 * we can do is round it to the nearest ^2 and align it.
1467 */
1402 sblksz = round_pow2(blksz);
1403 sblksz -= sblksz % sndbuf_getbps(bs);
1404 sblkcnt = blkcnt;
1405 while (sblksz < 16 || sblksz < sndbuf_getbps(bs))
1406 sblksz += sndbuf_getbps(bs);
1407 if (snd_verbose > 3 && !(blksz == 0 || blkcnt == -1))
1408 printf("%s: requested blksz=%d blkcnt=%d -> %d/%d\n",
1409 __func__, blksz, blkcnt, sblksz, sblkcnt);
1468 sblksz = round_blksz(blksz, sndbuf_getbps(bs));
1469 sblkcnt = round_pow2(blkcnt);
1410 limit = 0;
1411 }
1412
1413 if (c->parentchannel != NULL) {
1414 pb = BUF_PARENT(c, NULL);
1415 CHN_UNLOCK(c);
1416 chn_notify(c->parentchannel, CHN_N_BLOCKSIZE);
1417 CHN_LOCK(c);
1418 limit = (limit != 0 && pb != NULL) ?
1419 sndbuf_xbytes(sndbuf_getsize(pb), pb, bs) : 0;
1420 c->timeout = c->parentchannel->timeout;
1421 } else {
1470 limit = 0;
1471 }
1472
1473 if (c->parentchannel != NULL) {
1474 pb = BUF_PARENT(c, NULL);
1475 CHN_UNLOCK(c);
1476 chn_notify(c->parentchannel, CHN_N_BLOCKSIZE);
1477 CHN_LOCK(c);
1478 limit = (limit != 0 && pb != NULL) ?
1479 sndbuf_xbytes(sndbuf_getsize(pb), pb, bs) : 0;
1480 c->timeout = c->parentchannel->timeout;
1481 } else {
1482 hblkcnt = 2;
1422 if (c->flags & CHN_F_HAS_SIZE) {
1483 if (c->flags & CHN_F_HAS_SIZE) {
1423 hblksz = sndbuf_xbytes(sblksz, bs, b);
1424 if (snd_verbose > 3)
1425 printf("%s: sblksz=%d -> hblksz=%d\n",
1426 __func__, sblksz, hblksz);
1484 hblksz = round_blksz(sndbuf_xbytes(sblksz, bs, b),
1485 sndbuf_getbps(b));
1486 hblkcnt = round_pow2(sndbuf_getblkcnt(bs));
1427 } else
1428 chn_calclatency(c->direction, latency,
1429 sndbuf_getbps(b),
1430 sndbuf_getbps(b) * sndbuf_getspd(b),
1487 } else
1488 chn_calclatency(c->direction, latency,
1489 sndbuf_getbps(b),
1490 sndbuf_getbps(b) * sndbuf_getspd(b),
1431 CHN_2NDBUFMAXSIZE, &hblksz, NULL);
1491 CHN_2NDBUFMAXSIZE, &hblksz, &hblkcnt);
1432
1492
1433 hblksz = round_pow2(hblksz);
1434 if ((hblksz << 1) > sndbuf_getmaxsize(b))
1493 if ((hblksz << 1) > sndbuf_getmaxsize(b))
1435 hblksz = sndbuf_getmaxsize(b) >> 1;
1494 hblksz = round_blksz(sndbuf_getmaxsize(b) >> 1,
1495 sndbuf_getbps(b));
1496
1497 while ((hblksz * hblkcnt) > sndbuf_getmaxsize(b)) {
1498 if (hblkcnt < 4)
1499 hblksz >>= 1;
1500 else
1501 hblkcnt >>= 1;
1502 }
1503
1436 hblksz -= hblksz % sndbuf_getbps(b);
1504 hblksz -= hblksz % sndbuf_getbps(b);
1437 while (hblksz < 16 || hblksz < sndbuf_getbps(b))
1438 hblksz += sndbuf_getbps(b);
1439
1440#if 0
1441 hblksz = sndbuf_getmaxsize(b) >> 1;
1505
1506#if 0
1507 hblksz = sndbuf_getmaxsize(b) >> 1;
1508 hblksz -= hblksz % sndbuf_getbps(b);
1509 hblkcnt = 2;
1442#endif
1510#endif
1511
1443 CHN_UNLOCK(c);
1512 CHN_UNLOCK(c);
1444 sndbuf_setblksz(b, CHANNEL_SETBLOCKSIZE(c->methods,
1445 c->devinfo, hblksz));
1513 if (chn_usefrags == 0 ||
1514 CHANNEL_SETFRAGMENTS(c->methods, c->devinfo,
1515 hblksz, hblkcnt) < 1)
1516 sndbuf_setblksz(b, CHANNEL_SETBLOCKSIZE(c->methods,
1517 c->devinfo, hblksz));
1446 CHN_LOCK(c);
1447
1448 if (!SLIST_EMPTY(&c->children)) {
1518 CHN_LOCK(c);
1519
1520 if (!SLIST_EMPTY(&c->children)) {
1449 /*
1450 * Virtual channels underneath. Set the biggest
1451 * possible value for their mixing space.
1452 */
1453 sblksz = CHN_2NDBUFMAXSIZE >> 1;
1454 sblksz -= sblksz % sndbuf_getbps(bs);
1521 sblksz = round_blksz(
1522 sndbuf_xbytes(sndbuf_getsize(b) >> 1, b, bs),
1523 sndbuf_getbps(bs));
1455 sblkcnt = 2;
1456 limit = 0;
1457 } else if (limit != 0)
1458 limit = sndbuf_xbytes(sndbuf_getsize(b), b, bs);
1459
1460 /*
1461 * Interrupt timeout
1462 */
1524 sblkcnt = 2;
1525 limit = 0;
1526 } else if (limit != 0)
1527 limit = sndbuf_xbytes(sndbuf_getsize(b), b, bs);
1528
1529 /*
1530 * Interrupt timeout
1531 */
1463 c->timeout = ((u_int64_t)hz * sndbuf_getblksz(b)) /
1532 c->timeout = ((u_int64_t)hz * sndbuf_getsize(b)) /
1464 ((u_int64_t)sndbuf_getspd(b) * sndbuf_getbps(b));
1465 if (c->timeout < 1)
1466 c->timeout = 1;
1533 ((u_int64_t)sndbuf_getspd(b) * sndbuf_getbps(b));
1534 if (c->timeout < 1)
1535 c->timeout = 1;
1467 c->timeout <<= 1;
1468 }
1469
1470 if (limit > CHN_2NDBUFMAXSIZE)
1471 limit = CHN_2NDBUFMAXSIZE;
1472
1536 }
1537
1538 if (limit > CHN_2NDBUFMAXSIZE)
1539 limit = CHN_2NDBUFMAXSIZE;
1540
1473 hblksz = sblksz;
1474 while ((sblksz * sblkcnt) < limit) {
1475 sblksz += hblksz;
1476 if ((sblksz * sblkcnt) > CHN_2NDBUFMAXSIZE) {
1477 sblksz -= hblksz;
1541#if 0
1542 while (limit > 0 && (sblksz * sblkcnt) > limit) {
1543 if (sblkcnt < 4)
1478 break;
1544 break;
1479 }
1545 sblkcnt >>= 1;
1480 }
1546 }
1547#endif
1481
1548
1549 while ((sblksz * sblkcnt) < limit)
1550 sblkcnt <<= 1;
1551
1552 while ((sblksz * sblkcnt) > CHN_2NDBUFMAXSIZE) {
1553 if (sblkcnt < 4)
1554 sblksz >>= 1;
1555 else
1556 sblkcnt >>= 1;
1557 }
1558
1559 sblksz -= sblksz % sndbuf_getbps(bs);
1560
1482 if (sndbuf_getblkcnt(bs) != sblkcnt || sndbuf_getblksz(bs) != sblksz ||
1483 sndbuf_getsize(bs) != (sblkcnt * sblksz)) {
1484 ret = sndbuf_remalloc(bs, sblkcnt, sblksz);
1485 if (ret != 0) {
1486 printf("%s: Failed: %d %d\n", __func__,
1487 sblkcnt, sblksz);
1488 return ret;
1489 }
1490 }
1491
1492 /*
1493 * OSSv4 docs: "By default OSS will set the low water level equal
1494 * to the fragment size which is optimal in most cases."
1495 */
1496 c->lw = sndbuf_getblksz(bs);
1497 chn_resetbuf(c);
1498
1499 if (snd_verbose > 3)
1561 if (sndbuf_getblkcnt(bs) != sblkcnt || sndbuf_getblksz(bs) != sblksz ||
1562 sndbuf_getsize(bs) != (sblkcnt * sblksz)) {
1563 ret = sndbuf_remalloc(bs, sblkcnt, sblksz);
1564 if (ret != 0) {
1565 printf("%s: Failed: %d %d\n", __func__,
1566 sblkcnt, sblksz);
1567 return ret;
1568 }
1569 }
1570
1571 /*
1572 * OSSv4 docs: "By default OSS will set the low water level equal
1573 * to the fragment size which is optimal in most cases."
1574 */
1575 c->lw = sndbuf_getblksz(bs);
1576 chn_resetbuf(c);
1577
1578 if (snd_verbose > 3)
1500 printf("%s: PCMDIR_%s (%s) timeout=%u "
1579 printf("%s: %s (%s) timeout=%u "
1501 "b[%d/%d/%d] bs[%d/%d/%d] limit=%d\n",
1580 "b[%d/%d/%d] bs[%d/%d/%d] limit=%d\n",
1502 __func__, (c->direction == PCMDIR_REC) ? "REC" : "PLAY",
1581 __func__, CHN_DIRSTR(c),
1503 (c->flags & CHN_F_VIRTUAL) ? "virtual" : "hardware",
1504 c->timeout,
1505 sndbuf_getsize(b), sndbuf_getblksz(b),
1506 sndbuf_getblkcnt(b),
1507 sndbuf_getsize(bs), sndbuf_getblksz(bs),
1508 sndbuf_getblkcnt(bs), limit);
1509
1510 return 0;

--- 24 unchanged lines hidden (view full) ---

1535 struct snd_dbuf *x;
1536 int r, delta;
1537
1538 CHN_LOCKASSERT(c);
1539 DEB(printf("setspeed, channel %s\n", c->name));
1540 DEB(printf("want speed %d, ", speed));
1541 if (speed <= 0)
1542 return EINVAL;
1582 (c->flags & CHN_F_VIRTUAL) ? "virtual" : "hardware",
1583 c->timeout,
1584 sndbuf_getsize(b), sndbuf_getblksz(b),
1585 sndbuf_getblkcnt(b),
1586 sndbuf_getsize(bs), sndbuf_getblksz(bs),
1587 sndbuf_getblkcnt(bs), limit);
1588
1589 return 0;

--- 24 unchanged lines hidden (view full) ---

1614 struct snd_dbuf *x;
1615 int r, delta;
1616
1617 CHN_LOCKASSERT(c);
1618 DEB(printf("setspeed, channel %s\n", c->name));
1619 DEB(printf("want speed %d, ", speed));
1620 if (speed <= 0)
1621 return EINVAL;
1543 if (CANCHANGE(c)) {
1622 if (CHN_STOPPED(c)) {
1544 r = 0;
1545 c->speed = speed;
1546 sndbuf_setspd(bs, speed);
1547 RANGE(speed, chn_getcaps(c)->minspeed, chn_getcaps(c)->maxspeed);
1548 DEB(printf("try speed %d, ", speed));
1549 sndbuf_setspd(b, CHANNEL_SETSPEED(c->methods, c->devinfo, speed));
1550 DEB(printf("got speed %d\n", sndbuf_getspd(b)));
1551

--- 65 unchanged lines hidden (view full) ---

1617static int
1618chn_tryformat(struct pcm_channel *c, u_int32_t fmt)
1619{
1620 struct snd_dbuf *b = c->bufhard;
1621 struct snd_dbuf *bs = c->bufsoft;
1622 int r;
1623
1624 CHN_LOCKASSERT(c);
1623 r = 0;
1624 c->speed = speed;
1625 sndbuf_setspd(bs, speed);
1626 RANGE(speed, chn_getcaps(c)->minspeed, chn_getcaps(c)->maxspeed);
1627 DEB(printf("try speed %d, ", speed));
1628 sndbuf_setspd(b, CHANNEL_SETSPEED(c->methods, c->devinfo, speed));
1629 DEB(printf("got speed %d\n", sndbuf_getspd(b)));
1630

--- 65 unchanged lines hidden (view full) ---

1696static int
1697chn_tryformat(struct pcm_channel *c, u_int32_t fmt)
1698{
1699 struct snd_dbuf *b = c->bufhard;
1700 struct snd_dbuf *bs = c->bufsoft;
1701 int r;
1702
1703 CHN_LOCKASSERT(c);
1625 if (CANCHANGE(c)) {
1704 if (CHN_STOPPED(c)) {
1626 DEB(printf("want format %d\n", fmt));
1627 c->format = fmt;
1628 r = chn_buildfeeder(c);
1629 if (r == 0) {
1630 sndbuf_setfmt(bs, c->format);
1631 chn_resetbuf(c);
1632 r = CHANNEL_SETFORMAT(c->methods, c->devinfo, sndbuf_getfmt(b));
1633 if (r == 0)

--- 63 unchanged lines hidden (view full) ---

1697 hwptr &= ~a ; /* Apply channel align mask */
1698#endif
1699 hwptr &= DMA_ALIGN_MASK; /* Apply DMA align mask */
1700 return hwptr;
1701#endif
1702 int hwptr;
1703
1704 CHN_LOCKASSERT(c);
1705 DEB(printf("want format %d\n", fmt));
1706 c->format = fmt;
1707 r = chn_buildfeeder(c);
1708 if (r == 0) {
1709 sndbuf_setfmt(bs, c->format);
1710 chn_resetbuf(c);
1711 r = CHANNEL_SETFORMAT(c->methods, c->devinfo, sndbuf_getfmt(b));
1712 if (r == 0)

--- 63 unchanged lines hidden (view full) ---

1776 hwptr &= ~a ; /* Apply channel align mask */
1777#endif
1778 hwptr &= DMA_ALIGN_MASK; /* Apply DMA align mask */
1779 return hwptr;
1780#endif
1781 int hwptr;
1782
1783 CHN_LOCKASSERT(c);
1705 hwptr = (c->flags & CHN_F_TRIGGERED)? CHANNEL_GETPTR(c->methods, c->devinfo) : 0;
1784 hwptr = (CHN_STARTED(c)) ? CHANNEL_GETPTR(c->methods, c->devinfo) : 0;
1706 return (hwptr - (hwptr % sndbuf_getbps(c->bufhard)));
1707}
1708
1709struct pcmchan_caps *
1710chn_getcaps(struct pcm_channel *c)
1711{
1712 CHN_LOCKASSERT(c);
1713 return CHANNEL_GETCAPS(c->methods, c->devinfo);

--- 25 unchanged lines hidden (view full) ---

1739{
1740 struct feeder_class *fc;
1741 struct pcm_feederdesc desc;
1742 u_int32_t tmp[2], type, flags, hwfmt, *fmtlist;
1743 int err;
1744 char fmtstr[AFMTSTR_MAXSZ];
1745
1746 CHN_LOCKASSERT(c);
1785 return (hwptr - (hwptr % sndbuf_getbps(c->bufhard)));
1786}
1787
1788struct pcmchan_caps *
1789chn_getcaps(struct pcm_channel *c)
1790{
1791 CHN_LOCKASSERT(c);
1792 return CHANNEL_GETCAPS(c->methods, c->devinfo);

--- 25 unchanged lines hidden (view full) ---

1818{
1819 struct feeder_class *fc;
1820 struct pcm_feederdesc desc;
1821 u_int32_t tmp[2], type, flags, hwfmt, *fmtlist;
1822 int err;
1823 char fmtstr[AFMTSTR_MAXSZ];
1824
1825 CHN_LOCKASSERT(c);
1747 while (chn_removefeeder(c) == 0);
1826 while (chn_removefeeder(c) == 0)
1827 ;
1748 KASSERT((c->feeder == NULL), ("feeder chain not empty"));
1749
1750 c->align = sndbuf_getalign(c->bufsoft);
1751
1752 if (SLIST_EMPTY(&c->children)) {
1753 fc = feeder_getclass(NULL);
1754 KASSERT(fc != NULL, ("can't find root feeder"));
1755

--- 25 unchanged lines hidden (view full) ---

1781 if (err) {
1782 DEB(printf("can't add vchan feeder, err %d\n", err));
1783
1784 return err;
1785 }
1786 }
1787 c->feederflags &= ~(1 << FEEDER_VOLUME);
1788 if (c->direction == PCMDIR_PLAY &&
1828 KASSERT((c->feeder == NULL), ("feeder chain not empty"));
1829
1830 c->align = sndbuf_getalign(c->bufsoft);
1831
1832 if (SLIST_EMPTY(&c->children)) {
1833 fc = feeder_getclass(NULL);
1834 KASSERT(fc != NULL, ("can't find root feeder"));
1835

--- 25 unchanged lines hidden (view full) ---

1861 if (err) {
1862 DEB(printf("can't add vchan feeder, err %d\n", err));
1863
1864 return err;
1865 }
1866 }
1867 c->feederflags &= ~(1 << FEEDER_VOLUME);
1868 if (c->direction == PCMDIR_PLAY &&
1789 !(c->flags & CHN_F_VIRTUAL) &&
1790 c->parentsnddev && (c->parentsnddev->flags & SD_F_SOFTPCMVOL) &&
1791 c->parentsnddev->mixer_dev)
1869 !(c->flags & CHN_F_VIRTUAL) && c->parentsnddev &&
1870 (c->parentsnddev->flags & SD_F_SOFTPCMVOL) &&
1871 c->parentsnddev->mixer_dev)
1792 c->feederflags |= 1 << FEEDER_VOLUME;
1872 c->feederflags |= 1 << FEEDER_VOLUME;
1873 if (!(c->flags & CHN_F_VIRTUAL) && c->parentsnddev &&
1874 ((c->direction == PCMDIR_PLAY &&
1875 (c->parentsnddev->flags & SD_F_PSWAPLR)) ||
1876 (c->direction == PCMDIR_REC &&
1877 (c->parentsnddev->flags & SD_F_RSWAPLR))))
1878 c->feederflags |= 1 << FEEDER_SWAPLR;
1793 flags = c->feederflags;
1794 fmtlist = chn_getcaps(c)->fmtlist;
1795
1796 DEB(printf("feederflags %x\n", flags));
1797
1798 for (type = FEEDER_RATE; type < FEEDER_LAST; type++) {
1799 if (flags & (1 << type)) {
1800 desc.type = type;

--- 24 unchanged lines hidden (view full) ---

1825 desc.in = afmtstr2afmt(NULL, fmtstr, AFMTSTR_MONO_RETURN);
1826 if (desc.in == 0)
1827 desc.in = AFMT_S16_LE;
1828 /* feeder_volume need stereo processing */
1829 if (type == FEEDER_VOLUME ||
1830 c->feeder->desc->out & AFMT_STEREO)
1831 desc.in |= AFMT_STEREO;
1832 desc.out = desc.in;
1879 flags = c->feederflags;
1880 fmtlist = chn_getcaps(c)->fmtlist;
1881
1882 DEB(printf("feederflags %x\n", flags));
1883
1884 for (type = FEEDER_RATE; type < FEEDER_LAST; type++) {
1885 if (flags & (1 << type)) {
1886 desc.type = type;

--- 24 unchanged lines hidden (view full) ---

1911 desc.in = afmtstr2afmt(NULL, fmtstr, AFMTSTR_MONO_RETURN);
1912 if (desc.in == 0)
1913 desc.in = AFMT_S16_LE;
1914 /* feeder_volume need stereo processing */
1915 if (type == FEEDER_VOLUME ||
1916 c->feeder->desc->out & AFMT_STEREO)
1917 desc.in |= AFMT_STEREO;
1918 desc.out = desc.in;
1833 fc = feeder_getclass(&desc);
1834 if (fc != NULL && fc->desc != NULL)
1835 desc.flags = fc->desc->flags;
1836 } else {
1837 fc = feeder_getclass(&desc);
1838 if (fc != NULL && fc->desc != NULL)
1839 desc = *fc->desc;
1919 } else if (type == FEEDER_SWAPLR) {
1920 desc.in = c->feeder->desc->out;
1921 desc.in |= AFMT_STEREO;
1922 desc.out = desc.in;
1840 }
1923 }
1924
1925 fc = feeder_getclass(&desc);
1841 DEB(printf("got %p\n", fc));
1842 if (fc == NULL) {
1843 DEB(printf("can't find required feeder type %d\n", type));
1844
1845 return EOPNOTSUPP;
1846 }
1847
1926 DEB(printf("got %p\n", fc));
1927 if (fc == NULL) {
1928 DEB(printf("can't find required feeder type %d\n", type));
1929
1930 return EOPNOTSUPP;
1931 }
1932
1933 if (desc.in == 0 || desc.out == 0)
1934 desc = *fc->desc;
1935
1848 DEB(printf("build fmtchain from 0x%08x to 0x%08x: ", c->feeder->desc->out, fc->desc->in));
1849 tmp[0] = desc.in;
1850 tmp[1] = 0;
1851 if (chn_fmtchain(c, tmp) == 0) {
1852 DEB(printf("failed\n"));
1853
1854 return ENODEV;
1855 }

--- 71 unchanged lines hidden (view full) ---

1927
1928 CHN_LOCK(c);
1929
1930 if (SLIST_EMPTY(&c->children)) {
1931 CHN_UNLOCK(c);
1932 return ENODEV;
1933 }
1934
1936 DEB(printf("build fmtchain from 0x%08x to 0x%08x: ", c->feeder->desc->out, fc->desc->in));
1937 tmp[0] = desc.in;
1938 tmp[1] = 0;
1939 if (chn_fmtchain(c, tmp) == 0) {
1940 DEB(printf("failed\n"));
1941
1942 return ENODEV;
1943 }

--- 71 unchanged lines hidden (view full) ---

2015
2016 CHN_LOCK(c);
2017
2018 if (SLIST_EMPTY(&c->children)) {
2019 CHN_UNLOCK(c);
2020 return ENODEV;
2021 }
2022
1935 run = (c->flags & CHN_F_TRIGGERED)? 1 : 0;
2023 run = (CHN_STARTED(c)) ? 1 : 0;
1936 /*
1937 * if the hwchan is running, we can't change its rate, format or
1938 * blocksize
1939 */
1940 if (run)
1941 flags &= CHN_N_VOLUME | CHN_N_TRIGGER;
1942
1943 if (flags & CHN_N_RATE) {

--- 25 unchanged lines hidden (view full) ---

1969 * scan the children, and figure out if any are running
1970 * if so, we need to be running, otherwise we need to be stopped
1971 * if we aren't in our target sstate, move to it
1972 */
1973 nrun = 0;
1974 SLIST_FOREACH(pce, &c->children, link) {
1975 child = pce->channel;
1976 CHN_LOCK(child);
2024 /*
2025 * if the hwchan is running, we can't change its rate, format or
2026 * blocksize
2027 */
2028 if (run)
2029 flags &= CHN_N_VOLUME | CHN_N_TRIGGER;
2030
2031 if (flags & CHN_N_RATE) {

--- 25 unchanged lines hidden (view full) ---

2057 * scan the children, and figure out if any are running
2058 * if so, we need to be running, otherwise we need to be stopped
2059 * if we aren't in our target sstate, move to it
2060 */
2061 nrun = 0;
2062 SLIST_FOREACH(pce, &c->children, link) {
2063 child = pce->channel;
2064 CHN_LOCK(child);
1977 if (child->flags & CHN_F_TRIGGERED)
1978 nrun = 1;
2065 nrun = CHN_STARTED(child);
1979 CHN_UNLOCK(child);
2066 CHN_UNLOCK(child);
2067 if (nrun)
2068 break;
1980 }
1981 if (nrun && !run)
1982 chn_start(c, 1);
1983 if (!nrun && run)
1984 chn_abort(c);
1985 }
1986 CHN_UNLOCK(c);
1987 return 0;

--- 93 unchanged lines hidden ---
2069 }
2070 if (nrun && !run)
2071 chn_start(c, 1);
2072 if (!nrun && run)
2073 chn_abort(c);
2074 }
2075 CHN_UNLOCK(c);
2076 return 0;

--- 93 unchanged lines hidden ---