1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22#ifndef __SOUND_PCM_INDIRECT_H
23#define __SOUND_PCM_INDIRECT_H
24
25#include <sound/pcm.h>
26
27struct snd_pcm_indirect {
28 unsigned int hw_buffer_size;
29 unsigned int hw_queue_size;
30 unsigned int hw_data;
31 unsigned int hw_io;
32 int hw_ready;
33 unsigned int sw_buffer_size;
34 unsigned int sw_data;
35 unsigned int sw_io;
36 int sw_ready;
37 snd_pcm_uframes_t appl_ptr;
38};
39
40typedef void (*snd_pcm_indirect_copy_t)(struct snd_pcm_substream *substream,
41 struct snd_pcm_indirect *rec, size_t bytes);
42
43
44
45
46static inline int
47snd_pcm_indirect_playback_transfer(struct snd_pcm_substream *substream,
48 struct snd_pcm_indirect *rec,
49 snd_pcm_indirect_copy_t copy)
50{
51 struct snd_pcm_runtime *runtime = substream->runtime;
52 snd_pcm_uframes_t appl_ptr = runtime->control->appl_ptr;
53 snd_pcm_sframes_t diff = appl_ptr - rec->appl_ptr;
54 int qsize;
55
56 if (diff) {
57 if (diff < -(snd_pcm_sframes_t) (runtime->boundary / 2))
58 diff += runtime->boundary;
59 if (diff < 0)
60 return -EINVAL;
61 rec->sw_ready += (int)frames_to_bytes(runtime, diff);
62 rec->appl_ptr = appl_ptr;
63 }
64 qsize = rec->hw_queue_size ? rec->hw_queue_size : rec->hw_buffer_size;
65 while (rec->hw_ready < qsize && rec->sw_ready > 0) {
66 unsigned int hw_to_end = rec->hw_buffer_size - rec->hw_data;
67 unsigned int sw_to_end = rec->sw_buffer_size - rec->sw_data;
68 unsigned int bytes = qsize - rec->hw_ready;
69 if (rec->sw_ready < (int)bytes)
70 bytes = rec->sw_ready;
71 if (hw_to_end < bytes)
72 bytes = hw_to_end;
73 if (sw_to_end < bytes)
74 bytes = sw_to_end;
75 if (! bytes)
76 break;
77 copy(substream, rec, bytes);
78 rec->hw_data += bytes;
79 if (rec->hw_data == rec->hw_buffer_size)
80 rec->hw_data = 0;
81 rec->sw_data += bytes;
82 if (rec->sw_data == rec->sw_buffer_size)
83 rec->sw_data = 0;
84 rec->hw_ready += bytes;
85 rec->sw_ready -= bytes;
86 }
87 return 0;
88}
89
90
91
92
93
94static inline snd_pcm_uframes_t
95snd_pcm_indirect_playback_pointer(struct snd_pcm_substream *substream,
96 struct snd_pcm_indirect *rec, unsigned int ptr)
97{
98 int bytes = ptr - rec->hw_io;
99 if (bytes < 0)
100 bytes += rec->hw_buffer_size;
101 rec->hw_io = ptr;
102 rec->hw_ready -= bytes;
103 rec->sw_io += bytes;
104 if (rec->sw_io >= rec->sw_buffer_size)
105 rec->sw_io -= rec->sw_buffer_size;
106 if (substream->ops->ack)
107 substream->ops->ack(substream);
108 return bytes_to_frames(substream->runtime, rec->sw_io);
109}
110
111
112
113
114
115static inline int
116snd_pcm_indirect_capture_transfer(struct snd_pcm_substream *substream,
117 struct snd_pcm_indirect *rec,
118 snd_pcm_indirect_copy_t copy)
119{
120 struct snd_pcm_runtime *runtime = substream->runtime;
121 snd_pcm_uframes_t appl_ptr = runtime->control->appl_ptr;
122 snd_pcm_sframes_t diff = appl_ptr - rec->appl_ptr;
123
124 if (diff) {
125 if (diff < -(snd_pcm_sframes_t) (runtime->boundary / 2))
126 diff += runtime->boundary;
127 if (diff < 0)
128 return -EINVAL;
129 rec->sw_ready -= frames_to_bytes(runtime, diff);
130 rec->appl_ptr = appl_ptr;
131 }
132 while (rec->hw_ready > 0 &&
133 rec->sw_ready < (int)rec->sw_buffer_size) {
134 size_t hw_to_end = rec->hw_buffer_size - rec->hw_data;
135 size_t sw_to_end = rec->sw_buffer_size - rec->sw_data;
136 size_t bytes = rec->sw_buffer_size - rec->sw_ready;
137 if (rec->hw_ready < (int)bytes)
138 bytes = rec->hw_ready;
139 if (hw_to_end < bytes)
140 bytes = hw_to_end;
141 if (sw_to_end < bytes)
142 bytes = sw_to_end;
143 if (! bytes)
144 break;
145 copy(substream, rec, bytes);
146 rec->hw_data += bytes;
147 if ((int)rec->hw_data == rec->hw_buffer_size)
148 rec->hw_data = 0;
149 rec->sw_data += bytes;
150 if (rec->sw_data == rec->sw_buffer_size)
151 rec->sw_data = 0;
152 rec->hw_ready -= bytes;
153 rec->sw_ready += bytes;
154 }
155 return 0;
156}
157
158
159
160
161
162static inline snd_pcm_uframes_t
163snd_pcm_indirect_capture_pointer(struct snd_pcm_substream *substream,
164 struct snd_pcm_indirect *rec, unsigned int ptr)
165{
166 int qsize;
167 int bytes = ptr - rec->hw_io;
168 if (bytes < 0)
169 bytes += rec->hw_buffer_size;
170 rec->hw_io = ptr;
171 rec->hw_ready += bytes;
172 qsize = rec->hw_queue_size ? rec->hw_queue_size : rec->hw_buffer_size;
173 if (rec->hw_ready > qsize)
174 return SNDRV_PCM_POS_XRUN;
175 rec->sw_io += bytes;
176 if (rec->sw_io >= rec->sw_buffer_size)
177 rec->sw_io -= rec->sw_buffer_size;
178 if (substream->ops->ack)
179 substream->ops->ack(substream);
180 return bytes_to_frames(substream->runtime, rec->sw_io);
181}
182
183#endif
184