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 --- |