2 * Helper functions for indirect PCM data transfer
4 * Copyright (c) by Takashi Iwai <tiwai@suse.de>
5 * Jaroslav Kysela <perex@perex.cz>
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 #ifndef __SOUND_PCM_INDIRECT_H
23 #define __SOUND_PCM_INDIRECT_H
25 #include <sound/pcm.h>
27 struct snd_pcm_indirect
{
28 unsigned int hw_buffer_size
; /* Byte size of hardware buffer */
29 unsigned int hw_queue_size
; /* Max queue size of hw buffer (0 = buffer size) */
30 unsigned int hw_data
; /* Offset to next dst (or src) in hw ring buffer */
31 unsigned int hw_io
; /* Ring buffer hw pointer */
32 int hw_ready
; /* Bytes ready for play (or captured) in hw ring buffer */
33 unsigned int sw_buffer_size
; /* Byte size of software buffer */
34 unsigned int sw_data
; /* Offset to next dst (or src) in sw ring buffer */
35 unsigned int sw_io
; /* Current software pointer in bytes */
36 int sw_ready
; /* Bytes ready to be transferred to/from hw */
37 snd_pcm_uframes_t appl_ptr
; /* Last seen appl_ptr */
40 typedef void (*snd_pcm_indirect_copy_t
)(struct snd_pcm_substream
*substream
,
41 struct snd_pcm_indirect
*rec
, size_t bytes
);
44 * helper function for playback ack callback
47 snd_pcm_indirect_playback_transfer(struct snd_pcm_substream
*substream
,
48 struct snd_pcm_indirect
*rec
,
49 snd_pcm_indirect_copy_t copy
)
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
;
57 if (diff
< -(snd_pcm_sframes_t
) (runtime
->boundary
/ 2))
58 diff
+= runtime
->boundary
;
61 rec
->sw_ready
+= (int)frames_to_bytes(runtime
, diff
);
62 rec
->appl_ptr
= appl_ptr
;
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
)
73 if (sw_to_end
< bytes
)
77 copy(substream
, rec
, bytes
);
78 rec
->hw_data
+= bytes
;
79 if (rec
->hw_data
== rec
->hw_buffer_size
)
81 rec
->sw_data
+= bytes
;
82 if (rec
->sw_data
== rec
->sw_buffer_size
)
84 rec
->hw_ready
+= bytes
;
85 rec
->sw_ready
-= bytes
;
91 * helper function for playback pointer callback
92 * ptr = current byte pointer
94 static inline snd_pcm_uframes_t
95 snd_pcm_indirect_playback_pointer(struct snd_pcm_substream
*substream
,
96 struct snd_pcm_indirect
*rec
, unsigned int ptr
)
98 int bytes
= ptr
- rec
->hw_io
;
100 bytes
+= rec
->hw_buffer_size
;
102 rec
->hw_ready
-= 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
);
113 * helper function for capture ack callback
116 snd_pcm_indirect_capture_transfer(struct snd_pcm_substream
*substream
,
117 struct snd_pcm_indirect
*rec
,
118 snd_pcm_indirect_copy_t copy
)
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
;
125 if (diff
< -(snd_pcm_sframes_t
) (runtime
->boundary
/ 2))
126 diff
+= runtime
->boundary
;
129 rec
->sw_ready
-= frames_to_bytes(runtime
, diff
);
130 rec
->appl_ptr
= appl_ptr
;
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
)
141 if (sw_to_end
< bytes
)
145 copy(substream
, rec
, bytes
);
146 rec
->hw_data
+= bytes
;
147 if ((int)rec
->hw_data
== rec
->hw_buffer_size
)
149 rec
->sw_data
+= bytes
;
150 if (rec
->sw_data
== rec
->sw_buffer_size
)
152 rec
->hw_ready
-= bytes
;
153 rec
->sw_ready
+= bytes
;
159 * helper function for capture pointer callback,
160 * ptr = current byte pointer
162 static inline snd_pcm_uframes_t
163 snd_pcm_indirect_capture_pointer(struct snd_pcm_substream
*substream
,
164 struct snd_pcm_indirect
*rec
, unsigned int ptr
)
167 int bytes
= ptr
- rec
->hw_io
;
169 bytes
+= rec
->hw_buffer_size
;
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
;
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
);
183 #endif /* __SOUND_PCM_INDIRECT_H */