1 /**
2  * \file pcm/pcm_generic.c
3  * \ingroup PCM
4  * \brief PCM Interface
5  * \author Jaroslav Kysela <perex@perex.cz>
6  * \date 2004
7  */
8 /*
9  *  PCM - Common generic plugin code
10  *  Copyright (c) 2004 by Jaroslav Kysela <perex@perex.cz>
11  *
12  *
13  *   This library is free software; you can redistribute it and/or modify
14  *   it under the terms of the GNU Lesser General Public License as
15  *   published by the Free Software Foundation; either version 2.1 of
16  *   the License, or (at your option) any later version.
17  *
18  *   This program is distributed in the hope that it will be useful,
19  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
20  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  *   GNU Lesser General Public License for more details.
22  *
23  *   You should have received a copy of the GNU Lesser General Public
24  *   License along with this library; if not, write to the Free Software
25  *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
26  *
27  */
28 
29 #include <sys/ioctl.h>
30 #include <limits.h>
31 #include "pcm_local.h"
32 #include "pcm_generic.h"
33 
34 #ifndef DOC_HIDDEN
35 
snd_pcm_generic_close(snd_pcm_t * pcm)36 int snd_pcm_generic_close(snd_pcm_t *pcm)
37 {
38 	snd_pcm_generic_t *generic = pcm->private_data;
39 	int err = 0;
40 	if (generic->close_slave)
41 		err = snd_pcm_close(generic->slave);
42 	free(generic);
43 	return err;
44 }
45 
snd_pcm_generic_nonblock(snd_pcm_t * pcm,int nonblock)46 int snd_pcm_generic_nonblock(snd_pcm_t *pcm, int nonblock)
47 {
48 	snd_pcm_generic_t *generic = pcm->private_data;
49 	return snd_pcm_nonblock(generic->slave, nonblock);
50 }
51 
snd_pcm_generic_async(snd_pcm_t * pcm,int sig,pid_t pid)52 int snd_pcm_generic_async(snd_pcm_t *pcm, int sig, pid_t pid)
53 {
54 	snd_pcm_generic_t *generic = pcm->private_data;
55 	return snd_pcm_async(generic->slave, sig, pid);
56 }
57 
snd_pcm_generic_poll_descriptors_count(snd_pcm_t * pcm)58 int snd_pcm_generic_poll_descriptors_count(snd_pcm_t *pcm)
59 {
60 	snd_pcm_generic_t *generic = pcm->private_data;
61 	return snd_pcm_poll_descriptors_count(generic->slave);
62 }
63 
snd_pcm_generic_poll_descriptors(snd_pcm_t * pcm,struct pollfd * pfds,unsigned int space)64 int snd_pcm_generic_poll_descriptors(snd_pcm_t *pcm, struct pollfd *pfds, unsigned int space)
65 {
66 	snd_pcm_generic_t *generic = pcm->private_data;
67 	return snd_pcm_poll_descriptors(generic->slave, pfds, space);
68 }
69 
snd_pcm_generic_poll_revents(snd_pcm_t * pcm,struct pollfd * pfds,unsigned int nfds,unsigned short * revents)70 int snd_pcm_generic_poll_revents(snd_pcm_t *pcm, struct pollfd *pfds, unsigned int nfds, unsigned short *revents)
71 {
72 	snd_pcm_generic_t *generic = pcm->private_data;
73 	return snd_pcm_poll_descriptors_revents(generic->slave, pfds, nfds, revents);
74 }
75 
snd_pcm_generic_info(snd_pcm_t * pcm,snd_pcm_info_t * info)76 int snd_pcm_generic_info(snd_pcm_t *pcm, snd_pcm_info_t * info)
77 {
78 	snd_pcm_generic_t *generic = pcm->private_data;
79 	return snd_pcm_info(generic->slave, info);
80 }
81 
snd_pcm_generic_hw_free(snd_pcm_t * pcm)82 int snd_pcm_generic_hw_free(snd_pcm_t *pcm)
83 {
84 	snd_pcm_generic_t *generic = pcm->private_data;
85 	return snd_pcm_hw_free(generic->slave);
86 }
87 
snd_pcm_generic_sw_params(snd_pcm_t * pcm,snd_pcm_sw_params_t * params)88 int snd_pcm_generic_sw_params(snd_pcm_t *pcm, snd_pcm_sw_params_t *params)
89 {
90 	snd_pcm_generic_t *generic = pcm->private_data;
91 	return snd_pcm_sw_params(generic->slave, params);
92 }
93 
snd_pcm_generic_hw_refine(snd_pcm_t * pcm,snd_pcm_hw_params_t * params)94 int snd_pcm_generic_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
95 {
96 	snd_pcm_generic_t *generic = pcm->private_data;
97 	return snd_pcm_hw_refine(generic->slave, params);
98 }
99 
snd_pcm_generic_hw_params(snd_pcm_t * pcm,snd_pcm_hw_params_t * params)100 int snd_pcm_generic_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
101 {
102 	snd_pcm_generic_t *generic = pcm->private_data;
103 	return _snd_pcm_hw_params_internal(generic->slave, params);
104 }
105 
snd_pcm_generic_prepare(snd_pcm_t * pcm)106 int snd_pcm_generic_prepare(snd_pcm_t *pcm)
107 {
108 	snd_pcm_generic_t *generic = pcm->private_data;
109 	return snd_pcm_prepare(generic->slave);
110 }
111 
snd_pcm_generic_channel_info(snd_pcm_t * pcm,snd_pcm_channel_info_t * info)112 int snd_pcm_generic_channel_info(snd_pcm_t *pcm, snd_pcm_channel_info_t *info)
113 {
114 	snd_pcm_generic_t *generic = pcm->private_data;
115 	if (pcm->mmap_shadow) {
116 		/* No own buffer is required - the plugin won't change
117 		 * the data on the buffer, or do safely on-the-place
118 		 * conversion
119 		 */
120 		return snd_pcm_channel_info(generic->slave, info);
121 	} else {
122 		/* Allocate own buffer */
123 		return snd_pcm_channel_info_shm(pcm, info, -1);
124 	}
125 }
126 
snd_pcm_generic_status(snd_pcm_t * pcm,snd_pcm_status_t * status)127 int snd_pcm_generic_status(snd_pcm_t *pcm, snd_pcm_status_t * status)
128 {
129 	snd_pcm_generic_t *generic = pcm->private_data;
130 	return snd_pcm_status(generic->slave, status);
131 }
132 
snd_pcm_generic_state(snd_pcm_t * pcm)133 snd_pcm_state_t snd_pcm_generic_state(snd_pcm_t *pcm)
134 {
135 	snd_pcm_generic_t *generic = pcm->private_data;
136 	return snd_pcm_state(generic->slave);
137 }
138 
snd_pcm_generic_hwsync(snd_pcm_t * pcm)139 int snd_pcm_generic_hwsync(snd_pcm_t *pcm)
140 {
141 	snd_pcm_generic_t *generic = pcm->private_data;
142 	return snd_pcm_hwsync(generic->slave);
143 }
144 
snd_pcm_generic_reset(snd_pcm_t * pcm)145 int snd_pcm_generic_reset(snd_pcm_t *pcm)
146 {
147 	snd_pcm_generic_t *generic = pcm->private_data;
148 	return snd_pcm_reset(generic->slave);
149 }
150 
snd_pcm_generic_start(snd_pcm_t * pcm)151 int snd_pcm_generic_start(snd_pcm_t *pcm)
152 {
153 	snd_pcm_generic_t *generic = pcm->private_data;
154 	return snd_pcm_start(generic->slave);
155 }
156 
snd_pcm_generic_drop(snd_pcm_t * pcm)157 int snd_pcm_generic_drop(snd_pcm_t *pcm)
158 {
159 	snd_pcm_generic_t *generic = pcm->private_data;
160 	return snd_pcm_drop(generic->slave);
161 }
162 
snd_pcm_generic_drain(snd_pcm_t * pcm)163 int snd_pcm_generic_drain(snd_pcm_t *pcm)
164 {
165 	snd_pcm_generic_t *generic = pcm->private_data;
166 	return snd_pcm_drain(generic->slave);
167 }
168 
snd_pcm_generic_pause(snd_pcm_t * pcm,int enable)169 int snd_pcm_generic_pause(snd_pcm_t *pcm, int enable)
170 {
171 	snd_pcm_generic_t *generic = pcm->private_data;
172 	return snd_pcm_pause(generic->slave, enable);
173 }
174 
snd_pcm_generic_resume(snd_pcm_t * pcm)175 int snd_pcm_generic_resume(snd_pcm_t *pcm)
176 {
177 	snd_pcm_generic_t *generic = pcm->private_data;
178 	return snd_pcm_resume(generic->slave);
179 }
180 
snd_pcm_generic_delay(snd_pcm_t * pcm,snd_pcm_sframes_t * delayp)181 int snd_pcm_generic_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp)
182 {
183 	snd_pcm_generic_t *generic = pcm->private_data;
184 	return snd_pcm_delay(generic->slave, delayp);
185 }
186 
snd_pcm_generic_forwardable(snd_pcm_t * pcm)187 snd_pcm_sframes_t snd_pcm_generic_forwardable(snd_pcm_t *pcm)
188 {
189 	snd_pcm_generic_t *generic = pcm->private_data;
190 	return snd_pcm_forwardable(generic->slave);
191 }
192 
snd_pcm_generic_forward(snd_pcm_t * pcm,snd_pcm_uframes_t frames)193 snd_pcm_sframes_t snd_pcm_generic_forward(snd_pcm_t *pcm, snd_pcm_uframes_t frames)
194 {
195 	snd_pcm_generic_t *generic = pcm->private_data;
196 	return INTERNAL(snd_pcm_forward)(generic->slave, frames);
197 }
198 
snd_pcm_generic_rewindable(snd_pcm_t * pcm)199 snd_pcm_sframes_t snd_pcm_generic_rewindable(snd_pcm_t *pcm)
200 {
201 	snd_pcm_generic_t *generic = pcm->private_data;
202 	return snd_pcm_rewindable(generic->slave);
203 }
204 
snd_pcm_generic_rewind(snd_pcm_t * pcm,snd_pcm_uframes_t frames)205 snd_pcm_sframes_t snd_pcm_generic_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t frames)
206 {
207 	snd_pcm_generic_t *generic = pcm->private_data;
208 	return snd_pcm_rewind(generic->slave, frames);
209 }
210 
snd_pcm_generic_link(snd_pcm_t * pcm1,snd_pcm_t * pcm2)211 int snd_pcm_generic_link(snd_pcm_t *pcm1, snd_pcm_t *pcm2)
212 {
213 	snd_pcm_generic_t *generic = pcm1->private_data;
214 	if (generic->slave->fast_ops->link)
215 		return generic->slave->fast_ops->link(generic->slave->fast_op_arg, pcm2);
216 	return -ENOSYS;
217 }
218 
snd_pcm_generic_link_slaves(snd_pcm_t * pcm,snd_pcm_t * master)219 int snd_pcm_generic_link_slaves(snd_pcm_t *pcm, snd_pcm_t *master)
220 {
221 	snd_pcm_generic_t *generic = pcm->private_data;
222 	if (generic->slave->fast_ops->link_slaves)
223 		return generic->slave->fast_ops->link_slaves(generic->slave->fast_op_arg, master);
224 	return -ENOSYS;
225 }
226 
snd_pcm_generic_unlink(snd_pcm_t * pcm)227 int snd_pcm_generic_unlink(snd_pcm_t *pcm)
228 {
229 	snd_pcm_generic_t *generic = pcm->private_data;
230 	if (generic->slave->fast_ops->unlink)
231 		return generic->slave->fast_ops->unlink(generic->slave->fast_op_arg);
232 	return -ENOSYS;
233 }
234 
snd_pcm_generic_writei(snd_pcm_t * pcm,const void * buffer,snd_pcm_uframes_t size)235 snd_pcm_sframes_t snd_pcm_generic_writei(snd_pcm_t *pcm, const void *buffer, snd_pcm_uframes_t size)
236 {
237 	snd_pcm_generic_t *generic = pcm->private_data;
238 	return _snd_pcm_writei(generic->slave, buffer, size);
239 }
240 
snd_pcm_generic_writen(snd_pcm_t * pcm,void ** bufs,snd_pcm_uframes_t size)241 snd_pcm_sframes_t snd_pcm_generic_writen(snd_pcm_t *pcm, void **bufs, snd_pcm_uframes_t size)
242 {
243 	snd_pcm_generic_t *generic = pcm->private_data;
244 	return _snd_pcm_writen(generic->slave, bufs, size);
245 }
246 
snd_pcm_generic_readi(snd_pcm_t * pcm,void * buffer,snd_pcm_uframes_t size)247 snd_pcm_sframes_t snd_pcm_generic_readi(snd_pcm_t *pcm, void *buffer, snd_pcm_uframes_t size)
248 {
249 	snd_pcm_generic_t *generic = pcm->private_data;
250 	return _snd_pcm_readi(generic->slave, buffer, size);
251 }
252 
snd_pcm_generic_readn(snd_pcm_t * pcm,void ** bufs,snd_pcm_uframes_t size)253 snd_pcm_sframes_t snd_pcm_generic_readn(snd_pcm_t *pcm, void **bufs, snd_pcm_uframes_t size)
254 {
255 	snd_pcm_generic_t *generic = pcm->private_data;
256 	return _snd_pcm_readn(generic->slave, bufs, size);
257 }
258 
snd_pcm_generic_mmap_commit(snd_pcm_t * pcm,snd_pcm_uframes_t offset,snd_pcm_uframes_t size)259 snd_pcm_sframes_t snd_pcm_generic_mmap_commit(snd_pcm_t *pcm,
260 					      snd_pcm_uframes_t offset,
261 					      snd_pcm_uframes_t size)
262 {
263 	snd_pcm_generic_t *generic = pcm->private_data;
264 	return snd_pcm_mmap_commit(generic->slave, offset, size);
265 }
266 
snd_pcm_generic_avail_update(snd_pcm_t * pcm)267 snd_pcm_sframes_t snd_pcm_generic_avail_update(snd_pcm_t *pcm)
268 {
269 	snd_pcm_generic_t *generic = pcm->private_data;
270 	return snd_pcm_avail_update(generic->slave);
271 }
272 
snd_pcm_generic_htimestamp(snd_pcm_t * pcm,snd_pcm_uframes_t * avail,snd_htimestamp_t * tstamp)273 int snd_pcm_generic_htimestamp(snd_pcm_t *pcm, snd_pcm_uframes_t *avail,
274 			       snd_htimestamp_t *tstamp)
275 {
276 	snd_pcm_generic_t *generic = pcm->private_data;
277 	return snd_pcm_htimestamp(generic->slave, avail, tstamp);
278 }
279 
280 /* stand-alone version - similar like snd_pcm_hw_htimestamp but
281  * taking the tstamp via gettimestamp().
282  */
snd_pcm_generic_real_htimestamp(snd_pcm_t * pcm,snd_pcm_uframes_t * avail,snd_htimestamp_t * tstamp)283 int snd_pcm_generic_real_htimestamp(snd_pcm_t *pcm, snd_pcm_uframes_t *avail,
284 				    snd_htimestamp_t *tstamp)
285 {
286 	snd_pcm_sframes_t avail1;
287 	int ok = 0;
288 
289 	while (1) {
290 		avail1 = __snd_pcm_avail_update(pcm);
291 		if (avail1 < 0)
292 			return avail1;
293 		if (ok && (snd_pcm_uframes_t)avail1 == *avail)
294 			break;
295 		*avail = avail1;
296 		gettimestamp(tstamp, pcm->tstamp_type);
297 		ok = 1;
298 	}
299 	return 0;
300 }
301 
snd_pcm_generic_mmap(snd_pcm_t * pcm)302 int snd_pcm_generic_mmap(snd_pcm_t *pcm)
303 {
304 	if (pcm->mmap_shadow) {
305 		/* Copy the slave mmapped buffer data */
306 		snd_pcm_generic_t *generic = pcm->private_data;
307 		pcm->mmap_channels = generic->slave->mmap_channels;
308 		pcm->running_areas = generic->slave->running_areas;
309 		pcm->stopped_areas = generic->slave->stopped_areas;
310 	}
311 	return 0;
312 }
313 
snd_pcm_generic_munmap(snd_pcm_t * pcm)314 int snd_pcm_generic_munmap(snd_pcm_t *pcm)
315 {
316 	if (pcm->mmap_shadow) {
317 		/* Clean up */
318 		pcm->mmap_channels = NULL;
319 		pcm->running_areas = NULL;
320 		pcm->stopped_areas = NULL;
321 	}
322 	return 0;
323 }
324 
snd_pcm_generic_query_chmaps(snd_pcm_t * pcm)325 snd_pcm_chmap_query_t **snd_pcm_generic_query_chmaps(snd_pcm_t *pcm)
326 {
327 	snd_pcm_generic_t *generic = pcm->private_data;
328 	return snd_pcm_query_chmaps(generic->slave);
329 }
330 
snd_pcm_generic_get_chmap(snd_pcm_t * pcm)331 snd_pcm_chmap_t *snd_pcm_generic_get_chmap(snd_pcm_t *pcm)
332 {
333 	snd_pcm_generic_t *generic = pcm->private_data;
334 	return snd_pcm_get_chmap(generic->slave);
335 }
336 
snd_pcm_generic_set_chmap(snd_pcm_t * pcm,const snd_pcm_chmap_t * map)337 int snd_pcm_generic_set_chmap(snd_pcm_t *pcm, const snd_pcm_chmap_t *map)
338 {
339 	snd_pcm_generic_t *generic = pcm->private_data;
340 	return snd_pcm_set_chmap(generic->slave, map);
341 }
342 
snd_pcm_generic_may_wait_for_avail_min(snd_pcm_t * pcm,snd_pcm_uframes_t avail ATTRIBUTE_UNUSED)343 int snd_pcm_generic_may_wait_for_avail_min(snd_pcm_t *pcm, snd_pcm_uframes_t avail ATTRIBUTE_UNUSED)
344 {
345 	snd_pcm_generic_t *generic = pcm->private_data;
346 	return snd_pcm_may_wait_for_avail_min(generic->slave, snd_pcm_mmap_avail(generic->slave));
347 }
348 
349 #endif /* DOC_HIDDEN */
350