0001
0002
0003
0004
0005
0006
0007
0008
0009 #ifndef __SOUND_PCM_INDIRECT_H
0010 #define __SOUND_PCM_INDIRECT_H
0011
0012 #include <sound/pcm.h>
0013
0014 struct snd_pcm_indirect {
0015 unsigned int hw_buffer_size;
0016 unsigned int hw_queue_size;
0017 unsigned int hw_data;
0018 unsigned int hw_io;
0019 int hw_ready;
0020 unsigned int sw_buffer_size;
0021 unsigned int sw_data;
0022 unsigned int sw_io;
0023 int sw_ready;
0024 snd_pcm_uframes_t appl_ptr;
0025 };
0026
0027 typedef void (*snd_pcm_indirect_copy_t)(struct snd_pcm_substream *substream,
0028 struct snd_pcm_indirect *rec, size_t bytes);
0029
0030
0031
0032
0033 static inline int
0034 snd_pcm_indirect_playback_transfer(struct snd_pcm_substream *substream,
0035 struct snd_pcm_indirect *rec,
0036 snd_pcm_indirect_copy_t copy)
0037 {
0038 struct snd_pcm_runtime *runtime = substream->runtime;
0039 snd_pcm_uframes_t appl_ptr = runtime->control->appl_ptr;
0040 snd_pcm_sframes_t diff = appl_ptr - rec->appl_ptr;
0041 int qsize;
0042
0043 if (diff) {
0044 if (diff < -(snd_pcm_sframes_t) (runtime->boundary / 2))
0045 diff += runtime->boundary;
0046 if (diff < 0)
0047 return -EINVAL;
0048 rec->sw_ready += (int)frames_to_bytes(runtime, diff);
0049 rec->appl_ptr = appl_ptr;
0050 }
0051 qsize = rec->hw_queue_size ? rec->hw_queue_size : rec->hw_buffer_size;
0052 while (rec->hw_ready < qsize && rec->sw_ready > 0) {
0053 unsigned int hw_to_end = rec->hw_buffer_size - rec->hw_data;
0054 unsigned int sw_to_end = rec->sw_buffer_size - rec->sw_data;
0055 unsigned int bytes = qsize - rec->hw_ready;
0056 if (rec->sw_ready < (int)bytes)
0057 bytes = rec->sw_ready;
0058 if (hw_to_end < bytes)
0059 bytes = hw_to_end;
0060 if (sw_to_end < bytes)
0061 bytes = sw_to_end;
0062 if (! bytes)
0063 break;
0064 copy(substream, rec, bytes);
0065 rec->hw_data += bytes;
0066 if (rec->hw_data == rec->hw_buffer_size)
0067 rec->hw_data = 0;
0068 rec->sw_data += bytes;
0069 if (rec->sw_data == rec->sw_buffer_size)
0070 rec->sw_data = 0;
0071 rec->hw_ready += bytes;
0072 rec->sw_ready -= bytes;
0073 }
0074 return 0;
0075 }
0076
0077
0078
0079
0080
0081 static inline snd_pcm_uframes_t
0082 snd_pcm_indirect_playback_pointer(struct snd_pcm_substream *substream,
0083 struct snd_pcm_indirect *rec, unsigned int ptr)
0084 {
0085 int bytes = ptr - rec->hw_io;
0086 if (bytes < 0)
0087 bytes += rec->hw_buffer_size;
0088 rec->hw_io = ptr;
0089 rec->hw_ready -= bytes;
0090 rec->sw_io += bytes;
0091 if (rec->sw_io >= rec->sw_buffer_size)
0092 rec->sw_io -= rec->sw_buffer_size;
0093 if (substream->ops->ack)
0094 substream->ops->ack(substream);
0095 return bytes_to_frames(substream->runtime, rec->sw_io);
0096 }
0097
0098
0099
0100
0101
0102 static inline int
0103 snd_pcm_indirect_capture_transfer(struct snd_pcm_substream *substream,
0104 struct snd_pcm_indirect *rec,
0105 snd_pcm_indirect_copy_t copy)
0106 {
0107 struct snd_pcm_runtime *runtime = substream->runtime;
0108 snd_pcm_uframes_t appl_ptr = runtime->control->appl_ptr;
0109 snd_pcm_sframes_t diff = appl_ptr - rec->appl_ptr;
0110
0111 if (diff) {
0112 if (diff < -(snd_pcm_sframes_t) (runtime->boundary / 2))
0113 diff += runtime->boundary;
0114 if (diff < 0)
0115 return -EINVAL;
0116 rec->sw_ready -= frames_to_bytes(runtime, diff);
0117 rec->appl_ptr = appl_ptr;
0118 }
0119 while (rec->hw_ready > 0 &&
0120 rec->sw_ready < (int)rec->sw_buffer_size) {
0121 size_t hw_to_end = rec->hw_buffer_size - rec->hw_data;
0122 size_t sw_to_end = rec->sw_buffer_size - rec->sw_data;
0123 size_t bytes = rec->sw_buffer_size - rec->sw_ready;
0124 if (rec->hw_ready < (int)bytes)
0125 bytes = rec->hw_ready;
0126 if (hw_to_end < bytes)
0127 bytes = hw_to_end;
0128 if (sw_to_end < bytes)
0129 bytes = sw_to_end;
0130 if (! bytes)
0131 break;
0132 copy(substream, rec, bytes);
0133 rec->hw_data += bytes;
0134 if ((int)rec->hw_data == rec->hw_buffer_size)
0135 rec->hw_data = 0;
0136 rec->sw_data += bytes;
0137 if (rec->sw_data == rec->sw_buffer_size)
0138 rec->sw_data = 0;
0139 rec->hw_ready -= bytes;
0140 rec->sw_ready += bytes;
0141 }
0142 return 0;
0143 }
0144
0145
0146
0147
0148
0149 static inline snd_pcm_uframes_t
0150 snd_pcm_indirect_capture_pointer(struct snd_pcm_substream *substream,
0151 struct snd_pcm_indirect *rec, unsigned int ptr)
0152 {
0153 int qsize;
0154 int bytes = ptr - rec->hw_io;
0155 if (bytes < 0)
0156 bytes += rec->hw_buffer_size;
0157 rec->hw_io = ptr;
0158 rec->hw_ready += bytes;
0159 qsize = rec->hw_queue_size ? rec->hw_queue_size : rec->hw_buffer_size;
0160 if (rec->hw_ready > qsize)
0161 return SNDRV_PCM_POS_XRUN;
0162 rec->sw_io += bytes;
0163 if (rec->sw_io >= rec->sw_buffer_size)
0164 rec->sw_io -= rec->sw_buffer_size;
0165 if (substream->ops->ack)
0166 substream->ops->ack(substream);
0167 return bytes_to_frames(substream->runtime, rec->sw_io);
0168 }
0169
0170 #endif