Rewritten mmap_{read,write} following alsa-driver current code

This commit is contained in:
Abramo Bagnara 2001-01-20 12:56:30 +00:00
parent 4086362a33
commit b4e80abc53
2 changed files with 114 additions and 61 deletions

View file

@ -1049,54 +1049,83 @@ snd_pcm_sframes_t snd_pcm_read_areas(snd_pcm_t *pcm, const snd_pcm_channel_area_
snd_pcm_xfer_areas_func_t func) snd_pcm_xfer_areas_func_t func)
{ {
snd_pcm_uframes_t xfer = 0; snd_pcm_uframes_t xfer = 0;
snd_pcm_sframes_t err = 0; int err = 0;
int state = snd_pcm_state(pcm); int state = snd_pcm_state(pcm);
assert(size > 0);
assert(state >= SND_PCM_STATE_PREPARED); if (size == 0)
if (state == SND_PCM_STATE_PREPARED && return 0;
pcm->start_mode != SND_PCM_START_EXPLICIT) { if (size > pcm->xfer_align)
size -= size % pcm->xfer_align;
switch (state) {
case SND_PCM_STATE_PREPARED:
if (pcm->start_mode == SND_PCM_START_DATA) {
err = snd_pcm_start(pcm); err = snd_pcm_start(pcm);
if (err < 0) if (err < 0)
return err; goto _end;
state = SND_PCM_STATE_RUNNING;
} }
while (xfer < size) { break;
snd_pcm_sframes_t avail; case SND_PCM_STATE_DRAINING:
case SND_PCM_STATE_RUNNING:
break;
case SND_PCM_STATE_XRUN:
return -EPIPE;
default:
return -EBADFD;
}
while (size > 0) {
snd_pcm_uframes_t frames; snd_pcm_uframes_t frames;
again: snd_pcm_sframes_t avail;
_again:
avail = snd_pcm_avail_update(pcm); avail = snd_pcm_avail_update(pcm);
if (avail < 0) { if (avail < 0) {
err = avail;
break;
}
if ((snd_pcm_uframes_t)avail < pcm->avail_min) {
if (state != SND_PCM_STATE_RUNNING) {
err = -EPIPE; err = -EPIPE;
break; goto _end;
} }
if (state == SND_PCM_STATE_DRAINING) {
if (avail == 0) {
err = -EPIPE;
goto _end;
}
} else if (avail == 0 ||
(size >= pcm->xfer_align &&
(snd_pcm_uframes_t) avail < pcm->xfer_align)) {
if (pcm->mode & SND_PCM_NONBLOCK) { if (pcm->mode & SND_PCM_NONBLOCK) {
err = -EAGAIN; err = -EAGAIN;
break; goto _end;
} }
err = snd_pcm_wait(pcm, -1); err = snd_pcm_wait(pcm, -1);
if (err < 0) if (err < 0)
break; break;
state = snd_pcm_state(pcm); state = snd_pcm_state(pcm);
goto again; goto _again;
} }
frames = size - xfer; if ((snd_pcm_uframes_t) avail > pcm->xfer_align)
if (frames > (snd_pcm_uframes_t)avail) avail -= avail % pcm->xfer_align;
frames = size;
if (frames > (snd_pcm_uframes_t) avail)
frames = avail; frames = avail;
assert(frames != 0);
err = func(pcm, areas, offset, frames, 0); err = func(pcm, areas, offset, frames, 0);
if (err < 0) if (err < 0)
break; break;
assert((snd_pcm_uframes_t)err == frames); assert((snd_pcm_uframes_t)err == frames);
xfer += err; offset += frames;
offset += err; size -= frames;
xfer += frames;
#if 0
state = snd_pcm_state(pcm);
if (state == SND_PCM_STATE_XRUN) {
err = -EPIPE;
goto _end;
} }
if (xfer > 0) #endif
return xfer; }
return err; _end:
return xfer > 0 ? xfer : err;
} }
snd_pcm_sframes_t snd_pcm_write_areas(snd_pcm_t *pcm, const snd_pcm_channel_area_t *areas, snd_pcm_sframes_t snd_pcm_write_areas(snd_pcm_t *pcm, const snd_pcm_channel_area_t *areas,
@ -1104,58 +1133,82 @@ snd_pcm_sframes_t snd_pcm_write_areas(snd_pcm_t *pcm, const snd_pcm_channel_area
snd_pcm_xfer_areas_func_t func) snd_pcm_xfer_areas_func_t func)
{ {
snd_pcm_uframes_t xfer = 0; snd_pcm_uframes_t xfer = 0;
snd_pcm_sframes_t err = 0; int err = 0;
int state = snd_pcm_state(pcm); int state = snd_pcm_state(pcm);
assert(size > 0);
assert(state >= SND_PCM_STATE_PREPARED); if (size == 0)
while (xfer < size) { return 0;
snd_pcm_sframes_t avail; if (size > pcm->xfer_align)
snd_pcm_uframes_t frames; size -= size % pcm->xfer_align;
again:
if (state == SND_PCM_STATE_XRUN) { switch (state) {
err = -EPIPE; case SND_PCM_STATE_PREPARED:
case SND_PCM_STATE_RUNNING:
break; break;
case SND_PCM_STATE_XRUN:
return -EPIPE;
default:
return -EBADFD;
} }
while (size > 0) {
snd_pcm_uframes_t frames;
snd_pcm_sframes_t avail;
_again:
avail = snd_pcm_avail_update(pcm); avail = snd_pcm_avail_update(pcm);
if (avail < 0) { if (avail < 0) {
err = avail;
break;
}
if ((snd_pcm_uframes_t)avail < pcm->avail_min) {
if (state != SND_PCM_STATE_RUNNING) {
err = -EPIPE; err = -EPIPE;
break; goto _end;
} }
if (state == SND_PCM_STATE_PREPARED) {
if (avail == 0) {
err = -EPIPE;
goto _end;
}
} else if (avail == 0 ||
(size >= pcm->xfer_align &&
(snd_pcm_uframes_t) avail < pcm->xfer_align)) {
if (pcm->mode & SND_PCM_NONBLOCK) { if (pcm->mode & SND_PCM_NONBLOCK) {
err = -EAGAIN; err = -EAGAIN;
break; goto _end;
} }
err = snd_pcm_wait(pcm, -1); err = snd_pcm_wait(pcm, -1);
if (err < 0) if (err < 0)
break; break;
state = snd_pcm_state(pcm); state = snd_pcm_state(pcm);
goto again; goto _again;
} }
frames = size - xfer; if ((snd_pcm_uframes_t) avail > pcm->xfer_align)
if (frames > (snd_pcm_uframes_t)avail) avail -= avail % pcm->xfer_align;
frames = size;
if (frames > (snd_pcm_uframes_t) avail)
frames = avail; frames = avail;
assert(frames != 0);
err = func(pcm, areas, offset, frames, 0); err = func(pcm, areas, offset, frames, 0);
if (err < 0) if (err < 0)
break; break;
assert((snd_pcm_uframes_t)err == frames); assert((snd_pcm_uframes_t)err == frames);
xfer += err; offset += frames;
offset += err; size -= frames;
xfer += frames;
#if 0
state = snd_pcm_state(pcm);
if (state == SND_PCM_STATE_XRUN) {
err = -EPIPE;
goto _end;
}
#endif
if (state == SND_PCM_STATE_PREPARED && if (state == SND_PCM_STATE_PREPARED &&
pcm->start_mode != SND_PCM_START_EXPLICIT) { pcm->start_mode == SND_PCM_START_DATA) {
err = snd_pcm_start(pcm); err = snd_pcm_start(pcm);
if (err < 0) if (err < 0)
break; goto _end;
state = SND_PCM_STATE_RUNNING;
} }
} }
if (xfer > 0) _end:
return xfer; return xfer > 0 ? xfer : err;
return err;
} }
snd_pcm_uframes_t _snd_pcm_mmap_hw_ptr(snd_pcm_t *pcm) snd_pcm_uframes_t _snd_pcm_mmap_hw_ptr(snd_pcm_t *pcm)