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., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
26 *
27 */
28
29#include <sys/shm.h>
30#include <sys/ioctl.h>
31#include <limits.h>
32#include "pcm_local.h"
33#include "pcm_generic.h"
34
35#ifndef DOC_HIDDEN
36
37int snd_pcm_generic_close(snd_pcm_t *pcm)
38{
39	snd_pcm_generic_t *generic = pcm->private_data;
40	int err = 0;
41	if (generic->close_slave)
42		err = snd_pcm_close(generic->slave);
43	free(generic);
44	return 0;
45}
46
47int snd_pcm_generic_nonblock(snd_pcm_t *pcm, int nonblock)
48{
49	snd_pcm_generic_t *generic = pcm->private_data;
50	return snd_pcm_nonblock(generic->slave, nonblock);
51}
52
53int snd_pcm_generic_async(snd_pcm_t *pcm, int sig, pid_t pid)
54{
55	snd_pcm_generic_t *generic = pcm->private_data;
56	return snd_pcm_async(generic->slave, sig, pid);
57}
58
59int snd_pcm_generic_poll_descriptors_count(snd_pcm_t *pcm)
60{
61	snd_pcm_generic_t *generic = pcm->private_data;
62	return snd_pcm_poll_descriptors_count(generic->slave);
63}
64
65int snd_pcm_generic_poll_descriptors(snd_pcm_t *pcm, struct pollfd *pfds, unsigned int space)
66{
67	snd_pcm_generic_t *generic = pcm->private_data;
68	return snd_pcm_poll_descriptors(generic->slave, pfds, space);
69}
70
71int snd_pcm_generic_poll_revents(snd_pcm_t *pcm, struct pollfd *pfds, unsigned int nfds, unsigned short *revents)
72{
73	snd_pcm_generic_t *generic = pcm->private_data;
74	return snd_pcm_poll_descriptors_revents(generic->slave, pfds, nfds, revents);
75}
76
77int snd_pcm_generic_info(snd_pcm_t *pcm, snd_pcm_info_t * info)
78{
79	snd_pcm_generic_t *generic = pcm->private_data;
80	return snd_pcm_info(generic->slave, info);
81}
82
83int snd_pcm_generic_hw_free(snd_pcm_t *pcm)
84{
85	snd_pcm_generic_t *generic = pcm->private_data;
86	return snd_pcm_hw_free(generic->slave);
87}
88
89int snd_pcm_generic_sw_params(snd_pcm_t *pcm, snd_pcm_sw_params_t *params)
90{
91	snd_pcm_generic_t *generic = pcm->private_data;
92	return snd_pcm_sw_params(generic->slave, params);
93}
94
95int snd_pcm_generic_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
96{
97	snd_pcm_generic_t *generic = pcm->private_data;
98	return snd_pcm_hw_refine(generic->slave, params);
99}
100
101int snd_pcm_generic_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
102{
103	snd_pcm_generic_t *generic = pcm->private_data;
104	return _snd_pcm_hw_params(generic->slave, params);
105}
106
107int snd_pcm_generic_prepare(snd_pcm_t *pcm)
108{
109	snd_pcm_generic_t *generic = pcm->private_data;
110	return snd_pcm_prepare(generic->slave);
111}
112
113int snd_pcm_generic_channel_info(snd_pcm_t *pcm, snd_pcm_channel_info_t *info)
114{
115	snd_pcm_generic_t *generic = pcm->private_data;
116	if (pcm->mmap_shadow) {
117		/* No own buffer is required - the plugin won't change
118		 * the data on the buffer, or do safely on-the-place
119		 * conversion
120		 */
121		return snd_pcm_channel_info(generic->slave, info);
122	} else {
123		/* Allocate own buffer */
124		return snd_pcm_channel_info_shm(pcm, info, -1);
125	}
126}
127
128int snd_pcm_generic_status(snd_pcm_t *pcm, snd_pcm_status_t * status)
129{
130	snd_pcm_generic_t *generic = pcm->private_data;
131	return snd_pcm_status(generic->slave, status);
132}
133
134snd_pcm_state_t snd_pcm_generic_state(snd_pcm_t *pcm)
135{
136	snd_pcm_generic_t *generic = pcm->private_data;
137	return snd_pcm_state(generic->slave);
138}
139
140int snd_pcm_generic_hwsync(snd_pcm_t *pcm)
141{
142	snd_pcm_generic_t *generic = pcm->private_data;
143	return snd_pcm_hwsync(generic->slave);
144}
145
146int snd_pcm_generic_reset(snd_pcm_t *pcm)
147{
148	snd_pcm_generic_t *generic = pcm->private_data;
149	return snd_pcm_reset(generic->slave);
150}
151
152int snd_pcm_generic_start(snd_pcm_t *pcm)
153{
154	snd_pcm_generic_t *generic = pcm->private_data;
155	return snd_pcm_start(generic->slave);
156}
157
158int snd_pcm_generic_drop(snd_pcm_t *pcm)
159{
160	snd_pcm_generic_t *generic = pcm->private_data;
161	return snd_pcm_drop(generic->slave);
162}
163
164int snd_pcm_generic_drain(snd_pcm_t *pcm)
165{
166	snd_pcm_generic_t *generic = pcm->private_data;
167	return snd_pcm_drain(generic->slave);
168}
169
170int snd_pcm_generic_pause(snd_pcm_t *pcm, int enable)
171{
172	snd_pcm_generic_t *generic = pcm->private_data;
173	return snd_pcm_pause(generic->slave, enable);
174}
175
176int snd_pcm_generic_resume(snd_pcm_t *pcm)
177{
178	snd_pcm_generic_t *generic = pcm->private_data;
179	return snd_pcm_resume(generic->slave);
180}
181
182int snd_pcm_generic_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp)
183{
184	snd_pcm_generic_t *generic = pcm->private_data;
185	return snd_pcm_delay(generic->slave, delayp);
186}
187
188snd_pcm_sframes_t snd_pcm_generic_forwardable(snd_pcm_t *pcm)
189{
190	snd_pcm_generic_t *generic = pcm->private_data;
191	return snd_pcm_forwardable(generic->slave);
192}
193
194snd_pcm_sframes_t snd_pcm_generic_forward(snd_pcm_t *pcm, snd_pcm_uframes_t frames)
195{
196	snd_pcm_generic_t *generic = pcm->private_data;
197	return INTERNAL(snd_pcm_forward)(generic->slave, frames);
198}
199
200snd_pcm_sframes_t snd_pcm_generic_rewindable(snd_pcm_t *pcm)
201{
202	snd_pcm_generic_t *generic = pcm->private_data;
203	return snd_pcm_rewindable(generic->slave);
204}
205
206snd_pcm_sframes_t snd_pcm_generic_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t frames)
207{
208	snd_pcm_generic_t *generic = pcm->private_data;
209	return snd_pcm_rewind(generic->slave, frames);
210}
211
212int snd_pcm_generic_link(snd_pcm_t *pcm1, snd_pcm_t *pcm2)
213{
214	snd_pcm_generic_t *generic = pcm1->private_data;
215	if (generic->slave->fast_ops->link)
216		return generic->slave->fast_ops->link(generic->slave->fast_op_arg, pcm2);
217	return -ENOSYS;
218}
219
220int snd_pcm_generic_link_slaves(snd_pcm_t *pcm, snd_pcm_t *master)
221{
222	snd_pcm_generic_t *generic = pcm->private_data;
223	if (generic->slave->fast_ops->link_slaves)
224		return generic->slave->fast_ops->link_slaves(generic->slave->fast_op_arg, master);
225	return -ENOSYS;
226}
227
228int snd_pcm_generic_unlink(snd_pcm_t *pcm)
229{
230	snd_pcm_generic_t *generic = pcm->private_data;
231	if (generic->slave->fast_ops->unlink)
232		return generic->slave->fast_ops->unlink(generic->slave->fast_op_arg);
233	return -ENOSYS;
234}
235
236snd_pcm_sframes_t snd_pcm_generic_writei(snd_pcm_t *pcm, const void *buffer, snd_pcm_uframes_t size)
237{
238	snd_pcm_generic_t *generic = pcm->private_data;
239	return snd_pcm_writei(generic->slave, buffer, size);
240}
241
242snd_pcm_sframes_t snd_pcm_generic_writen(snd_pcm_t *pcm, void **bufs, snd_pcm_uframes_t size)
243{
244	snd_pcm_generic_t *generic = pcm->private_data;
245	return snd_pcm_writen(generic->slave, bufs, size);
246}
247
248snd_pcm_sframes_t snd_pcm_generic_readi(snd_pcm_t *pcm, void *buffer, snd_pcm_uframes_t size)
249{
250	snd_pcm_generic_t *generic = pcm->private_data;
251	return snd_pcm_readi(generic->slave, buffer, size);
252}
253
254snd_pcm_sframes_t snd_pcm_generic_readn(snd_pcm_t *pcm, void **bufs, snd_pcm_uframes_t size)
255{
256	snd_pcm_generic_t *generic = pcm->private_data;
257	return snd_pcm_readn(generic->slave, bufs, size);
258}
259
260snd_pcm_sframes_t snd_pcm_generic_mmap_commit(snd_pcm_t *pcm,
261					      snd_pcm_uframes_t offset,
262					      snd_pcm_uframes_t size)
263{
264	snd_pcm_generic_t *generic = pcm->private_data;
265	return snd_pcm_mmap_commit(generic->slave, offset, size);
266}
267
268snd_pcm_sframes_t snd_pcm_generic_avail_update(snd_pcm_t *pcm)
269{
270	snd_pcm_generic_t *generic = pcm->private_data;
271	return snd_pcm_avail_update(generic->slave);
272}
273
274int snd_pcm_generic_htimestamp(snd_pcm_t *pcm, snd_pcm_uframes_t *avail,
275			       snd_htimestamp_t *tstamp)
276{
277	snd_pcm_generic_t *generic = pcm->private_data;
278	return snd_pcm_htimestamp(generic->slave, avail, tstamp);
279}
280
281/* stand-alone version - similar like snd_pcm_hw_htimestamp but
282 * taking the tstamp via gettimestamp().
283 */
284int snd_pcm_generic_real_htimestamp(snd_pcm_t *pcm, snd_pcm_uframes_t *avail,
285				    snd_htimestamp_t *tstamp)
286{
287	snd_pcm_sframes_t avail1;
288	int ok = 0;
289
290	while (1) {
291		avail1 = snd_pcm_avail_update(pcm);
292		if (avail1 < 0)
293			return avail1;
294		if (ok && (snd_pcm_uframes_t)avail1 == *avail)
295			break;
296		*avail = avail1;
297		gettimestamp(tstamp, pcm->monotonic);
298		ok = 1;
299	}
300	return 0;
301}
302
303int snd_pcm_generic_mmap(snd_pcm_t *pcm)
304{
305	if (pcm->mmap_shadow) {
306		/* Copy the slave mmapped buffer data */
307		snd_pcm_generic_t *generic = pcm->private_data;
308		pcm->mmap_channels = generic->slave->mmap_channels;
309		pcm->running_areas = generic->slave->running_areas;
310		pcm->stopped_areas = generic->slave->stopped_areas;
311	}
312	return 0;
313}
314
315int snd_pcm_generic_munmap(snd_pcm_t *pcm)
316{
317	if (pcm->mmap_shadow) {
318		/* Clean up */
319		pcm->mmap_channels = NULL;
320		pcm->running_areas = NULL;
321		pcm->stopped_areas = NULL;
322	}
323	return 0;
324}
325
326#endif /* DOC_HIDDEN */
327