diff options
author | Takashi Iwai <tiwai@suse.de> | 2008-01-08 12:08:14 -0500 |
---|---|---|
committer | Jaroslav Kysela <perex@perex.cz> | 2008-01-31 11:29:47 -0500 |
commit | 130755108ba03461f69da990e54e02a254accd23 (patch) | |
tree | 57d71dc89dc83b87d3e33541bcfe47d045ff82fe /sound | |
parent | d948035a928400ae127c873fbf771389bee18949 (diff) |
[ALSA] PCM - clean up snd_pcm_lib_read/write
Introduce a common helper function for snd_pcm_lib_read and snd_pcm_lib_write
for cleaning up the code.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Signed-off-by: Jaroslav Kysela <perex@perex.cz>
Diffstat (limited to 'sound')
-rw-r--r-- | sound/core/pcm_lib.c | 216 |
1 files changed, 76 insertions, 140 deletions
diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index c1c1556105c0..b406630d8fdf 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c | |||
@@ -1591,6 +1591,71 @@ void snd_pcm_period_elapsed(struct snd_pcm_substream *substream) | |||
1591 | 1591 | ||
1592 | EXPORT_SYMBOL(snd_pcm_period_elapsed); | 1592 | EXPORT_SYMBOL(snd_pcm_period_elapsed); |
1593 | 1593 | ||
1594 | /* | ||
1595 | * Wait until avail_min data becomes available | ||
1596 | * Returns a negative error code if any error occurs during operation. | ||
1597 | * The available space is stored on availp. When err = 0 and avail = 0 | ||
1598 | * on the capture stream, it indicates the stream is in DRAINING state. | ||
1599 | */ | ||
1600 | static int wait_for_avail_min(struct snd_pcm_substream *substream, | ||
1601 | snd_pcm_uframes_t *availp) | ||
1602 | { | ||
1603 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
1604 | int is_playback = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; | ||
1605 | wait_queue_t wait; | ||
1606 | int err = 0; | ||
1607 | snd_pcm_uframes_t avail = 0; | ||
1608 | long tout; | ||
1609 | |||
1610 | init_waitqueue_entry(&wait, current); | ||
1611 | add_wait_queue(&runtime->sleep, &wait); | ||
1612 | for (;;) { | ||
1613 | if (signal_pending(current)) { | ||
1614 | err = -ERESTARTSYS; | ||
1615 | break; | ||
1616 | } | ||
1617 | set_current_state(TASK_INTERRUPTIBLE); | ||
1618 | snd_pcm_stream_unlock_irq(substream); | ||
1619 | tout = schedule_timeout(msecs_to_jiffies(10000)); | ||
1620 | snd_pcm_stream_lock_irq(substream); | ||
1621 | switch (runtime->status->state) { | ||
1622 | case SNDRV_PCM_STATE_SUSPENDED: | ||
1623 | err = -ESTRPIPE; | ||
1624 | goto _endloop; | ||
1625 | case SNDRV_PCM_STATE_XRUN: | ||
1626 | err = -EPIPE; | ||
1627 | goto _endloop; | ||
1628 | case SNDRV_PCM_STATE_DRAINING: | ||
1629 | if (is_playback) | ||
1630 | err = -EPIPE; | ||
1631 | else | ||
1632 | avail = 0; /* indicate draining */ | ||
1633 | goto _endloop; | ||
1634 | case SNDRV_PCM_STATE_OPEN: | ||
1635 | case SNDRV_PCM_STATE_SETUP: | ||
1636 | case SNDRV_PCM_STATE_DISCONNECTED: | ||
1637 | err = -EBADFD; | ||
1638 | goto _endloop; | ||
1639 | } | ||
1640 | if (!tout) { | ||
1641 | snd_printd("%s write error (DMA or IRQ trouble?)\n", | ||
1642 | is_playback ? "playback" : "capture"); | ||
1643 | err = -EIO; | ||
1644 | break; | ||
1645 | } | ||
1646 | if (is_playback) | ||
1647 | avail = snd_pcm_playback_avail(runtime); | ||
1648 | else | ||
1649 | avail = snd_pcm_capture_avail(runtime); | ||
1650 | if (avail >= runtime->control->avail_min) | ||
1651 | break; | ||
1652 | } | ||
1653 | _endloop: | ||
1654 | remove_wait_queue(&runtime->sleep, &wait); | ||
1655 | *availp = avail; | ||
1656 | return err; | ||
1657 | } | ||
1658 | |||
1594 | static int snd_pcm_lib_write_transfer(struct snd_pcm_substream *substream, | 1659 | static int snd_pcm_lib_write_transfer(struct snd_pcm_substream *substream, |
1595 | unsigned int hwoff, | 1660 | unsigned int hwoff, |
1596 | unsigned long data, unsigned int off, | 1661 | unsigned long data, unsigned int off, |
@@ -1653,79 +1718,14 @@ static snd_pcm_sframes_t snd_pcm_lib_write1(struct snd_pcm_substream *substream, | |||
1653 | if (runtime->sleep_min == 0 && runtime->status->state == SNDRV_PCM_STATE_RUNNING) | 1718 | if (runtime->sleep_min == 0 && runtime->status->state == SNDRV_PCM_STATE_RUNNING) |
1654 | snd_pcm_update_hw_ptr(substream); | 1719 | snd_pcm_update_hw_ptr(substream); |
1655 | avail = snd_pcm_playback_avail(runtime); | 1720 | avail = snd_pcm_playback_avail(runtime); |
1656 | if (!avail || | 1721 | if (!avail) { |
1657 | (snd_pcm_running(substream) && | ||
1658 | (avail < runtime->control->avail_min && size > avail))) { | ||
1659 | wait_queue_t wait; | ||
1660 | enum { READY, SIGNALED, ERROR, SUSPENDED, EXPIRED, DROPPED } state; | ||
1661 | long tout; | ||
1662 | |||
1663 | if (nonblock) { | 1722 | if (nonblock) { |
1664 | err = -EAGAIN; | 1723 | err = -EAGAIN; |
1665 | goto _end_unlock; | 1724 | goto _end_unlock; |
1666 | } | 1725 | } |
1667 | 1726 | err = wait_for_avail_min(substream, &avail); | |
1668 | init_waitqueue_entry(&wait, current); | 1727 | if (err < 0) |
1669 | add_wait_queue(&runtime->sleep, &wait); | ||
1670 | while (1) { | ||
1671 | if (signal_pending(current)) { | ||
1672 | state = SIGNALED; | ||
1673 | break; | ||
1674 | } | ||
1675 | set_current_state(TASK_INTERRUPTIBLE); | ||
1676 | snd_pcm_stream_unlock_irq(substream); | ||
1677 | tout = schedule_timeout(10 * HZ); | ||
1678 | snd_pcm_stream_lock_irq(substream); | ||
1679 | if (tout == 0) { | ||
1680 | if (runtime->status->state != SNDRV_PCM_STATE_PREPARED && | ||
1681 | runtime->status->state != SNDRV_PCM_STATE_PAUSED) { | ||
1682 | state = runtime->status->state == SNDRV_PCM_STATE_SUSPENDED ? SUSPENDED : EXPIRED; | ||
1683 | break; | ||
1684 | } | ||
1685 | } | ||
1686 | switch (runtime->status->state) { | ||
1687 | case SNDRV_PCM_STATE_XRUN: | ||
1688 | case SNDRV_PCM_STATE_DRAINING: | ||
1689 | state = ERROR; | ||
1690 | goto _end_loop; | ||
1691 | case SNDRV_PCM_STATE_SUSPENDED: | ||
1692 | state = SUSPENDED; | ||
1693 | goto _end_loop; | ||
1694 | case SNDRV_PCM_STATE_SETUP: | ||
1695 | state = DROPPED; | ||
1696 | goto _end_loop; | ||
1697 | default: | ||
1698 | break; | ||
1699 | } | ||
1700 | avail = snd_pcm_playback_avail(runtime); | ||
1701 | if (avail >= runtime->control->avail_min) { | ||
1702 | state = READY; | ||
1703 | break; | ||
1704 | } | ||
1705 | } | ||
1706 | _end_loop: | ||
1707 | remove_wait_queue(&runtime->sleep, &wait); | ||
1708 | |||
1709 | switch (state) { | ||
1710 | case ERROR: | ||
1711 | err = -EPIPE; | ||
1712 | goto _end_unlock; | ||
1713 | case SUSPENDED: | ||
1714 | err = -ESTRPIPE; | ||
1715 | goto _end_unlock; | ||
1716 | case SIGNALED: | ||
1717 | err = -ERESTARTSYS; | ||
1718 | goto _end_unlock; | ||
1719 | case EXPIRED: | ||
1720 | snd_printd("playback write error (DMA or IRQ trouble?)\n"); | ||
1721 | err = -EIO; | ||
1722 | goto _end_unlock; | ||
1723 | case DROPPED: | ||
1724 | err = -EBADFD; | ||
1725 | goto _end_unlock; | 1728 | goto _end_unlock; |
1726 | default: | ||
1727 | break; | ||
1728 | } | ||
1729 | } | 1729 | } |
1730 | frames = size > avail ? avail : size; | 1730 | frames = size > avail ? avail : size; |
1731 | cont = runtime->buffer_size - runtime->control->appl_ptr % runtime->buffer_size; | 1731 | cont = runtime->buffer_size - runtime->control->appl_ptr % runtime->buffer_size; |
@@ -1925,86 +1925,22 @@ static snd_pcm_sframes_t snd_pcm_lib_read1(struct snd_pcm_substream *substream, | |||
1925 | snd_pcm_uframes_t cont; | 1925 | snd_pcm_uframes_t cont; |
1926 | if (runtime->sleep_min == 0 && runtime->status->state == SNDRV_PCM_STATE_RUNNING) | 1926 | if (runtime->sleep_min == 0 && runtime->status->state == SNDRV_PCM_STATE_RUNNING) |
1927 | snd_pcm_update_hw_ptr(substream); | 1927 | snd_pcm_update_hw_ptr(substream); |
1928 | __draining: | ||
1929 | avail = snd_pcm_capture_avail(runtime); | 1928 | avail = snd_pcm_capture_avail(runtime); |
1930 | if (runtime->status->state == SNDRV_PCM_STATE_DRAINING) { | 1929 | if (!avail) { |
1931 | if (!avail) { | 1930 | if (runtime->status->state == |
1932 | err = -EPIPE; | 1931 | SNDRV_PCM_STATE_DRAINING) { |
1932 | snd_pcm_stop(substream, SNDRV_PCM_STATE_SETUP); | ||
1933 | goto _end_unlock; | 1933 | goto _end_unlock; |
1934 | } | 1934 | } |
1935 | } else if (avail < runtime->control->avail_min && | ||
1936 | size > avail) { | ||
1937 | wait_queue_t wait; | ||
1938 | enum { READY, SIGNALED, ERROR, SUSPENDED, EXPIRED, DROPPED } state; | ||
1939 | long tout; | ||
1940 | |||
1941 | if (nonblock) { | 1935 | if (nonblock) { |
1942 | err = -EAGAIN; | 1936 | err = -EAGAIN; |
1943 | goto _end_unlock; | 1937 | goto _end_unlock; |
1944 | } | 1938 | } |
1945 | 1939 | err = wait_for_avail_min(substream, &avail); | |
1946 | init_waitqueue_entry(&wait, current); | 1940 | if (err < 0) |
1947 | add_wait_queue(&runtime->sleep, &wait); | ||
1948 | while (1) { | ||
1949 | if (signal_pending(current)) { | ||
1950 | state = SIGNALED; | ||
1951 | break; | ||
1952 | } | ||
1953 | set_current_state(TASK_INTERRUPTIBLE); | ||
1954 | snd_pcm_stream_unlock_irq(substream); | ||
1955 | tout = schedule_timeout(10 * HZ); | ||
1956 | snd_pcm_stream_lock_irq(substream); | ||
1957 | if (tout == 0) { | ||
1958 | if (runtime->status->state != SNDRV_PCM_STATE_PREPARED && | ||
1959 | runtime->status->state != SNDRV_PCM_STATE_PAUSED) { | ||
1960 | state = runtime->status->state == SNDRV_PCM_STATE_SUSPENDED ? SUSPENDED : EXPIRED; | ||
1961 | break; | ||
1962 | } | ||
1963 | } | ||
1964 | switch (runtime->status->state) { | ||
1965 | case SNDRV_PCM_STATE_XRUN: | ||
1966 | state = ERROR; | ||
1967 | goto _end_loop; | ||
1968 | case SNDRV_PCM_STATE_SUSPENDED: | ||
1969 | state = SUSPENDED; | ||
1970 | goto _end_loop; | ||
1971 | case SNDRV_PCM_STATE_DRAINING: | ||
1972 | goto __draining; | ||
1973 | case SNDRV_PCM_STATE_SETUP: | ||
1974 | state = DROPPED; | ||
1975 | goto _end_loop; | ||
1976 | default: | ||
1977 | break; | ||
1978 | } | ||
1979 | avail = snd_pcm_capture_avail(runtime); | ||
1980 | if (avail >= runtime->control->avail_min) { | ||
1981 | state = READY; | ||
1982 | break; | ||
1983 | } | ||
1984 | } | ||
1985 | _end_loop: | ||
1986 | remove_wait_queue(&runtime->sleep, &wait); | ||
1987 | |||
1988 | switch (state) { | ||
1989 | case ERROR: | ||
1990 | err = -EPIPE; | ||
1991 | goto _end_unlock; | ||
1992 | case SUSPENDED: | ||
1993 | err = -ESTRPIPE; | ||
1994 | goto _end_unlock; | ||
1995 | case SIGNALED: | ||
1996 | err = -ERESTARTSYS; | ||
1997 | goto _end_unlock; | ||
1998 | case EXPIRED: | ||
1999 | snd_printd("capture read error (DMA or IRQ trouble?)\n"); | ||
2000 | err = -EIO; | ||
2001 | goto _end_unlock; | ||
2002 | case DROPPED: | ||
2003 | err = -EBADFD; | ||
2004 | goto _end_unlock; | 1941 | goto _end_unlock; |
2005 | default: | 1942 | if (!avail) |
2006 | break; | 1943 | continue; /* draining */ |
2007 | } | ||
2008 | } | 1944 | } |
2009 | frames = size > avail ? avail : size; | 1945 | frames = size > avail ? avail : size; |
2010 | cont = runtime->buffer_size - runtime->control->appl_ptr % runtime->buffer_size; | 1946 | cont = runtime->buffer_size - runtime->control->appl_ptr % runtime->buffer_size; |