xref: /aosp_15_r20/external/tinyalsa_new/src/pcm_plugin.c (revision 02e95f1a335b55495d41ca67eaf42361f13704fa)
1*02e95f1aSMarcin Radomski /* pcm_plugin.c
2*02e95f1aSMarcin Radomski ** Copyright (c) 2019, The Linux Foundation.
3*02e95f1aSMarcin Radomski **
4*02e95f1aSMarcin Radomski ** Redistribution and use in source and binary forms, with or without
5*02e95f1aSMarcin Radomski ** modification, are permitted provided that the following conditions are
6*02e95f1aSMarcin Radomski ** met:
7*02e95f1aSMarcin Radomski **   * Redistributions of source code must retain the above copyright
8*02e95f1aSMarcin Radomski **     notice, this list of conditions and the following disclaimer.
9*02e95f1aSMarcin Radomski **   * Redistributions in binary form must reproduce the above
10*02e95f1aSMarcin Radomski **     copyright notice, this list of conditions and the following
11*02e95f1aSMarcin Radomski **     disclaimer in the documentation and/or other materials provided
12*02e95f1aSMarcin Radomski **     with the distribution.
13*02e95f1aSMarcin Radomski **   * Neither the name of The Linux Foundation nor the names of its
14*02e95f1aSMarcin Radomski **     contributors may be used to endorse or promote products derived
15*02e95f1aSMarcin Radomski **     from this software without specific prior written permission.
16*02e95f1aSMarcin Radomski **
17*02e95f1aSMarcin Radomski ** THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
18*02e95f1aSMarcin Radomski ** WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19*02e95f1aSMarcin Radomski ** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
20*02e95f1aSMarcin Radomski ** ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
21*02e95f1aSMarcin Radomski ** BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22*02e95f1aSMarcin Radomski ** CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23*02e95f1aSMarcin Radomski ** SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
24*02e95f1aSMarcin Radomski ** BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25*02e95f1aSMarcin Radomski ** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
26*02e95f1aSMarcin Radomski ** OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
27*02e95f1aSMarcin Radomski ** IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28*02e95f1aSMarcin Radomski **/
29*02e95f1aSMarcin Radomski 
30*02e95f1aSMarcin Radomski #include <stdio.h>
31*02e95f1aSMarcin Radomski #include <stdlib.h>
32*02e95f1aSMarcin Radomski #include <stdint.h>
33*02e95f1aSMarcin Radomski #include <fcntl.h>
34*02e95f1aSMarcin Radomski #include <stdarg.h>
35*02e95f1aSMarcin Radomski #include <string.h>
36*02e95f1aSMarcin Radomski #include <errno.h>
37*02e95f1aSMarcin Radomski #include <unistd.h>
38*02e95f1aSMarcin Radomski #include <poll.h>
39*02e95f1aSMarcin Radomski #include <dlfcn.h>
40*02e95f1aSMarcin Radomski 
41*02e95f1aSMarcin Radomski #include <sys/ioctl.h>
42*02e95f1aSMarcin Radomski #include <linux/ioctl.h>
43*02e95f1aSMarcin Radomski #include <time.h>
44*02e95f1aSMarcin Radomski #include <sound/asound.h>
45*02e95f1aSMarcin Radomski #include <tinyalsa/asoundlib.h>
46*02e95f1aSMarcin Radomski #include <tinyalsa/plugin.h>
47*02e95f1aSMarcin Radomski 
48*02e95f1aSMarcin Radomski #include "pcm_io.h"
49*02e95f1aSMarcin Radomski #include "snd_card_plugin.h"
50*02e95f1aSMarcin Radomski 
51*02e95f1aSMarcin Radomski /* 2 words of uint32_t = 64 bits of mask */
52*02e95f1aSMarcin Radomski #define PCM_MASK_SIZE (2)
53*02e95f1aSMarcin Radomski #define ARRAY_SIZE(a)         \
54*02e95f1aSMarcin Radomski     (sizeof(a) / sizeof(a[0]))
55*02e95f1aSMarcin Radomski 
56*02e95f1aSMarcin Radomski #define PCM_PARAM_GET_MASK(p, n)    \
57*02e95f1aSMarcin Radomski     &p->masks[n - SNDRV_PCM_HW_PARAM_FIRST_MASK];
58*02e95f1aSMarcin Radomski 
59*02e95f1aSMarcin Radomski enum {
60*02e95f1aSMarcin Radomski     PCM_PLUG_HW_PARAM_SELECT_MIN,
61*02e95f1aSMarcin Radomski     PCM_PLUG_HW_PARAM_SELECT_MAX,
62*02e95f1aSMarcin Radomski     PCM_PLUG_HW_PARAM_SELECT_VAL,
63*02e95f1aSMarcin Radomski };
64*02e95f1aSMarcin Radomski 
65*02e95f1aSMarcin Radomski enum {
66*02e95f1aSMarcin Radomski     PCM_PLUG_STATE_OPEN,
67*02e95f1aSMarcin Radomski     PCM_PLUG_STATE_SETUP,
68*02e95f1aSMarcin Radomski     PCM_PLUG_STATE_PREPARED,
69*02e95f1aSMarcin Radomski     PCM_PLUG_STATE_RUNNING,
70*02e95f1aSMarcin Radomski };
71*02e95f1aSMarcin Radomski 
72*02e95f1aSMarcin Radomski struct pcm_plug_data {
73*02e95f1aSMarcin Radomski     unsigned int card;
74*02e95f1aSMarcin Radomski     unsigned int device;
75*02e95f1aSMarcin Radomski     unsigned int fd;
76*02e95f1aSMarcin Radomski     unsigned int flags;
77*02e95f1aSMarcin Radomski 
78*02e95f1aSMarcin Radomski     void *dl_hdl;
79*02e95f1aSMarcin Radomski     /** pointer to plugin operation */
80*02e95f1aSMarcin Radomski     const struct pcm_plugin_ops *ops;
81*02e95f1aSMarcin Radomski     struct pcm_plugin *plugin;
82*02e95f1aSMarcin Radomski     void *dev_node;
83*02e95f1aSMarcin Radomski };
84*02e95f1aSMarcin Radomski 
85*02e95f1aSMarcin Radomski static unsigned int param_list[] = {
86*02e95f1aSMarcin Radomski     SNDRV_PCM_HW_PARAM_SAMPLE_BITS,
87*02e95f1aSMarcin Radomski     SNDRV_PCM_HW_PARAM_CHANNELS,
88*02e95f1aSMarcin Radomski     SNDRV_PCM_HW_PARAM_RATE,
89*02e95f1aSMarcin Radomski     SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
90*02e95f1aSMarcin Radomski     SNDRV_PCM_HW_PARAM_PERIODS,
91*02e95f1aSMarcin Radomski };
92*02e95f1aSMarcin Radomski 
convert_plugin_to_pcm_state(int plugin_state)93*02e95f1aSMarcin Radomski static int convert_plugin_to_pcm_state(int plugin_state)
94*02e95f1aSMarcin Radomski {
95*02e95f1aSMarcin Radomski     switch (plugin_state) {
96*02e95f1aSMarcin Radomski     case PCM_PLUG_STATE_SETUP:
97*02e95f1aSMarcin Radomski         return PCM_STATE_SETUP;
98*02e95f1aSMarcin Radomski     case PCM_PLUG_STATE_RUNNING:
99*02e95f1aSMarcin Radomski         return PCM_STATE_RUNNING;
100*02e95f1aSMarcin Radomski     case PCM_PLUG_STATE_PREPARED:
101*02e95f1aSMarcin Radomski         return PCM_STATE_PREPARED;
102*02e95f1aSMarcin Radomski     case PCM_PLUG_STATE_OPEN:
103*02e95f1aSMarcin Radomski         return PCM_STATE_OPEN;
104*02e95f1aSMarcin Radomski     default:
105*02e95f1aSMarcin Radomski         break;
106*02e95f1aSMarcin Radomski     }
107*02e95f1aSMarcin Radomski 
108*02e95f1aSMarcin Radomski     return PCM_STATE_OPEN;
109*02e95f1aSMarcin Radomski }
110*02e95f1aSMarcin Radomski 
pcm_plug_close(void * data)111*02e95f1aSMarcin Radomski static void pcm_plug_close(void *data)
112*02e95f1aSMarcin Radomski {
113*02e95f1aSMarcin Radomski     struct pcm_plug_data *plug_data = data;
114*02e95f1aSMarcin Radomski     struct pcm_plugin *plugin = plug_data->plugin;
115*02e95f1aSMarcin Radomski 
116*02e95f1aSMarcin Radomski     plug_data->ops->close(plugin);
117*02e95f1aSMarcin Radomski     dlclose(plug_data->dl_hdl);
118*02e95f1aSMarcin Radomski 
119*02e95f1aSMarcin Radomski     free(plug_data);
120*02e95f1aSMarcin Radomski }
121*02e95f1aSMarcin Radomski 
pcm_plug_info(struct pcm_plug_data * plug_data,struct snd_pcm_info * info)122*02e95f1aSMarcin Radomski static int pcm_plug_info(struct pcm_plug_data *plug_data,
123*02e95f1aSMarcin Radomski                 struct snd_pcm_info *info)
124*02e95f1aSMarcin Radomski {
125*02e95f1aSMarcin Radomski     int stream = SNDRV_PCM_STREAM_PLAYBACK;
126*02e95f1aSMarcin Radomski     int ret = 0, val = -1;
127*02e95f1aSMarcin Radomski     char *name;
128*02e95f1aSMarcin Radomski 
129*02e95f1aSMarcin Radomski     memset(info, 0, sizeof(*info));
130*02e95f1aSMarcin Radomski 
131*02e95f1aSMarcin Radomski     if (plug_data->flags & PCM_IN) {
132*02e95f1aSMarcin Radomski         stream = SNDRV_PCM_STREAM_CAPTURE;
133*02e95f1aSMarcin Radomski         ret = snd_utils_get_int(plug_data->dev_node, "capture", &val);
134*02e95f1aSMarcin Radomski         if (ret || !val) {
135*02e95f1aSMarcin Radomski             fprintf(stderr, "%s: not a capture device\n", __func__);
136*02e95f1aSMarcin Radomski             return -EINVAL;
137*02e95f1aSMarcin Radomski         }
138*02e95f1aSMarcin Radomski     } else {
139*02e95f1aSMarcin Radomski         stream = SNDRV_PCM_STREAM_PLAYBACK;
140*02e95f1aSMarcin Radomski         ret = snd_utils_get_int(plug_data->dev_node, "playback", &val);
141*02e95f1aSMarcin Radomski         if (ret || !val) {
142*02e95f1aSMarcin Radomski             fprintf(stderr, "%s: not a playback device\n", __func__);
143*02e95f1aSMarcin Radomski             return -EINVAL;
144*02e95f1aSMarcin Radomski         }
145*02e95f1aSMarcin Radomski     }
146*02e95f1aSMarcin Radomski 
147*02e95f1aSMarcin Radomski     info->stream = stream;
148*02e95f1aSMarcin Radomski     info->card = plug_data->card;
149*02e95f1aSMarcin Radomski     info->device = plug_data->device;
150*02e95f1aSMarcin Radomski 
151*02e95f1aSMarcin Radomski     ret = snd_utils_get_str(plug_data->dev_node, "name", &name);
152*02e95f1aSMarcin Radomski     if (ret) {
153*02e95f1aSMarcin Radomski         fprintf(stderr, "%s: failed to get pcm device name\n", __func__);
154*02e95f1aSMarcin Radomski         return ret;
155*02e95f1aSMarcin Radomski     }
156*02e95f1aSMarcin Radomski 
157*02e95f1aSMarcin Radomski     strncpy((char *)info->id, name, sizeof(info->id) - 1);
158*02e95f1aSMarcin Radomski     ((char *)info->id)[sizeof(info->id) - 1] = '\0';
159*02e95f1aSMarcin Radomski     strncpy((char *)info->name, name, sizeof(info->name) - 1);
160*02e95f1aSMarcin Radomski     ((char *)info->name)[sizeof(info->name) - 1] = '\0';
161*02e95f1aSMarcin Radomski     strncpy((char *)info->subname, name, sizeof(info->subname) - 1);
162*02e95f1aSMarcin Radomski     ((char *)info->subname)[sizeof(info->subname) - 1] = '\0';
163*02e95f1aSMarcin Radomski 
164*02e95f1aSMarcin Radomski     info->subdevices_count = 1;
165*02e95f1aSMarcin Radomski 
166*02e95f1aSMarcin Radomski     return ret;
167*02e95f1aSMarcin Radomski }
168*02e95f1aSMarcin Radomski 
pcm_plug_set_mask(struct snd_pcm_hw_params * p,int n,uint64_t v)169*02e95f1aSMarcin Radomski static void pcm_plug_set_mask(struct snd_pcm_hw_params *p, int n, uint64_t v)
170*02e95f1aSMarcin Radomski {
171*02e95f1aSMarcin Radomski     struct snd_mask *mask;
172*02e95f1aSMarcin Radomski 
173*02e95f1aSMarcin Radomski     mask = PCM_PARAM_GET_MASK(p, n);
174*02e95f1aSMarcin Radomski 
175*02e95f1aSMarcin Radomski     mask->bits[0] |= (v & 0xFFFFFFFF);
176*02e95f1aSMarcin Radomski     mask->bits[1] |= ((v >> 32) & 0xFFFFFFFF);
177*02e95f1aSMarcin Radomski     /*
178*02e95f1aSMarcin Radomski      * currently only supporting 64 bits, may need to update to support
179*02e95f1aSMarcin Radomski      * more than 64 bits
180*02e95f1aSMarcin Radomski      */
181*02e95f1aSMarcin Radomski }
182*02e95f1aSMarcin Radomski 
pcm_plug_set_interval(struct snd_pcm_hw_params * params,int p,struct pcm_plugin_min_max * v,int is_integer)183*02e95f1aSMarcin Radomski static void pcm_plug_set_interval(struct snd_pcm_hw_params *params,
184*02e95f1aSMarcin Radomski                     int p, struct pcm_plugin_min_max *v, int is_integer)
185*02e95f1aSMarcin Radomski {
186*02e95f1aSMarcin Radomski     struct snd_interval *i;
187*02e95f1aSMarcin Radomski 
188*02e95f1aSMarcin Radomski     i = &params->intervals[p - SNDRV_PCM_HW_PARAM_FIRST_INTERVAL];
189*02e95f1aSMarcin Radomski 
190*02e95f1aSMarcin Radomski     i->min = v->min;
191*02e95f1aSMarcin Radomski     i->max = v->max;
192*02e95f1aSMarcin Radomski 
193*02e95f1aSMarcin Radomski     if (is_integer)
194*02e95f1aSMarcin Radomski         i->integer = 1;
195*02e95f1aSMarcin Radomski }
196*02e95f1aSMarcin Radomski 
pcm_plug_frames_to_bytes(unsigned int frames,unsigned int frame_bits)197*02e95f1aSMarcin Radomski static int pcm_plug_frames_to_bytes(unsigned int frames,
198*02e95f1aSMarcin Radomski                                     unsigned int frame_bits)
199*02e95f1aSMarcin Radomski {
200*02e95f1aSMarcin Radomski     return (frames * (frame_bits / 8));
201*02e95f1aSMarcin Radomski }
202*02e95f1aSMarcin Radomski 
pcm_plug_bytes_to_frames(unsigned int size,unsigned int frame_bits)203*02e95f1aSMarcin Radomski static int pcm_plug_bytes_to_frames(unsigned int size,
204*02e95f1aSMarcin Radomski                                     unsigned int frame_bits)
205*02e95f1aSMarcin Radomski {
206*02e95f1aSMarcin Radomski     return (size * 8)  / frame_bits;
207*02e95f1aSMarcin Radomski }
208*02e95f1aSMarcin Radomski 
pcm_plug_get_params(struct pcm_plugin * plugin,struct snd_pcm_hw_params * params)209*02e95f1aSMarcin Radomski static int pcm_plug_get_params(struct pcm_plugin *plugin,
210*02e95f1aSMarcin Radomski                 struct snd_pcm_hw_params *params)
211*02e95f1aSMarcin Radomski {
212*02e95f1aSMarcin Radomski     struct pcm_plugin_min_max bw, ch, pb, periods;
213*02e95f1aSMarcin Radomski     struct pcm_plugin_min_max val;
214*02e95f1aSMarcin Radomski     struct pcm_plugin_min_max frame_bits, buffer_bytes;
215*02e95f1aSMarcin Radomski 
216*02e95f1aSMarcin Radomski     /*
217*02e95f1aSMarcin Radomski      * populate the struct snd_pcm_hw_params structure
218*02e95f1aSMarcin Radomski      * using the hw_param constraints provided by plugin
219*02e95f1aSMarcin Radomski      * via the plugin->constraints
220*02e95f1aSMarcin Radomski      */
221*02e95f1aSMarcin Radomski 
222*02e95f1aSMarcin Radomski     /* Set the mask params */
223*02e95f1aSMarcin Radomski     pcm_plug_set_mask(params, SNDRV_PCM_HW_PARAM_ACCESS,
224*02e95f1aSMarcin Radomski                       plugin->constraints->access);
225*02e95f1aSMarcin Radomski     pcm_plug_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
226*02e95f1aSMarcin Radomski                       plugin->constraints->format);
227*02e95f1aSMarcin Radomski     pcm_plug_set_mask(params, SNDRV_PCM_HW_PARAM_SUBFORMAT,
228*02e95f1aSMarcin Radomski                       SNDRV_PCM_SUBFORMAT_STD);
229*02e95f1aSMarcin Radomski 
230*02e95f1aSMarcin Radomski     /* Set the standard interval params */
231*02e95f1aSMarcin Radomski     pcm_plug_set_interval(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS,
232*02e95f1aSMarcin Radomski                           &plugin->constraints->bit_width, 1);
233*02e95f1aSMarcin Radomski     pcm_plug_set_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS,
234*02e95f1aSMarcin Radomski                           &plugin->constraints->channels, 1);
235*02e95f1aSMarcin Radomski     pcm_plug_set_interval(params, SNDRV_PCM_HW_PARAM_RATE,
236*02e95f1aSMarcin Radomski                           &plugin->constraints->rate, 1);
237*02e95f1aSMarcin Radomski     pcm_plug_set_interval(params, SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
238*02e95f1aSMarcin Radomski                           &plugin->constraints->period_bytes, 0);
239*02e95f1aSMarcin Radomski     pcm_plug_set_interval(params, SNDRV_PCM_HW_PARAM_PERIODS,
240*02e95f1aSMarcin Radomski                           &plugin->constraints->periods, 1);
241*02e95f1aSMarcin Radomski 
242*02e95f1aSMarcin Radomski     /* set the calculated interval params */
243*02e95f1aSMarcin Radomski 
244*02e95f1aSMarcin Radomski     bw.min = plugin->constraints->bit_width.min;
245*02e95f1aSMarcin Radomski     bw.max = plugin->constraints->bit_width.max;
246*02e95f1aSMarcin Radomski 
247*02e95f1aSMarcin Radomski     ch.min = plugin->constraints->channels.min;
248*02e95f1aSMarcin Radomski     ch.max = plugin->constraints->channels.max;
249*02e95f1aSMarcin Radomski 
250*02e95f1aSMarcin Radomski     pb.min = plugin->constraints->period_bytes.min;
251*02e95f1aSMarcin Radomski     pb.max = plugin->constraints->period_bytes.max;
252*02e95f1aSMarcin Radomski 
253*02e95f1aSMarcin Radomski     periods.min = plugin->constraints->periods.min;
254*02e95f1aSMarcin Radomski     periods.max = plugin->constraints->periods.max;
255*02e95f1aSMarcin Radomski 
256*02e95f1aSMarcin Radomski     /* Calculate and set frame bits */
257*02e95f1aSMarcin Radomski     frame_bits.min = bw.min * ch.min;
258*02e95f1aSMarcin Radomski     frame_bits.max = bw.max * ch.max;
259*02e95f1aSMarcin Radomski     pcm_plug_set_interval(params, SNDRV_PCM_HW_PARAM_FRAME_BITS,
260*02e95f1aSMarcin Radomski                           &frame_bits, 1);
261*02e95f1aSMarcin Radomski 
262*02e95f1aSMarcin Radomski 
263*02e95f1aSMarcin Radomski     /* Calculate and set period_size in frames */
264*02e95f1aSMarcin Radomski     val.min = pcm_plug_bytes_to_frames(pb.min, frame_bits.min);
265*02e95f1aSMarcin Radomski     val.max = pcm_plug_bytes_to_frames(pb.max, frame_bits.min);
266*02e95f1aSMarcin Radomski     pcm_plug_set_interval(params, SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
267*02e95f1aSMarcin Radomski                           &val, 1);
268*02e95f1aSMarcin Radomski 
269*02e95f1aSMarcin Radomski     /* Calculate and set buffer_bytes */
270*02e95f1aSMarcin Radomski     buffer_bytes.min = pb.min * periods.min;
271*02e95f1aSMarcin Radomski     buffer_bytes.max = pb.max * periods.max;
272*02e95f1aSMarcin Radomski     pcm_plug_set_interval(params, SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
273*02e95f1aSMarcin Radomski                           &buffer_bytes, 1);
274*02e95f1aSMarcin Radomski 
275*02e95f1aSMarcin Radomski     /* Calculate and set buffer_size in frames */
276*02e95f1aSMarcin Radomski     val.min = pcm_plug_bytes_to_frames(buffer_bytes.min, frame_bits.min);
277*02e95f1aSMarcin Radomski     val.max = pcm_plug_bytes_to_frames(buffer_bytes.max, frame_bits.min);
278*02e95f1aSMarcin Radomski     pcm_plug_set_interval(params, SNDRV_PCM_HW_PARAM_BUFFER_SIZE,
279*02e95f1aSMarcin Radomski                           &val, 1);
280*02e95f1aSMarcin Radomski     return 0;
281*02e95f1aSMarcin Radomski }
282*02e95f1aSMarcin Radomski 
pcm_plug_masks_refine(struct snd_pcm_hw_params * p,struct snd_pcm_hw_params * c)283*02e95f1aSMarcin Radomski static int pcm_plug_masks_refine(struct snd_pcm_hw_params *p,
284*02e95f1aSMarcin Radomski                 struct snd_pcm_hw_params *c)
285*02e95f1aSMarcin Radomski {
286*02e95f1aSMarcin Radomski     struct snd_mask *req_mask;
287*02e95f1aSMarcin Radomski     struct snd_mask *con_mask;
288*02e95f1aSMarcin Radomski     unsigned int idx, i, masks;
289*02e95f1aSMarcin Radomski 
290*02e95f1aSMarcin Radomski     masks = SNDRV_PCM_HW_PARAM_LAST_MASK - SNDRV_PCM_HW_PARAM_FIRST_MASK;
291*02e95f1aSMarcin Radomski 
292*02e95f1aSMarcin Radomski     for (idx = 0; idx <= masks; idx++) {
293*02e95f1aSMarcin Radomski 
294*02e95f1aSMarcin Radomski         if (!(p->rmask & (1 << (idx + SNDRV_PCM_HW_PARAM_FIRST_MASK))))
295*02e95f1aSMarcin Radomski             continue;
296*02e95f1aSMarcin Radomski 
297*02e95f1aSMarcin Radomski         req_mask = PCM_PARAM_GET_MASK(p, idx);
298*02e95f1aSMarcin Radomski         con_mask = PCM_PARAM_GET_MASK(c, idx);
299*02e95f1aSMarcin Radomski 
300*02e95f1aSMarcin Radomski         /*
301*02e95f1aSMarcin Radomski          * set the changed mask if requested mask value is not the same as
302*02e95f1aSMarcin Radomski          * constrained mask value
303*02e95f1aSMarcin Radomski          */
304*02e95f1aSMarcin Radomski         if (memcmp(req_mask, con_mask, PCM_MASK_SIZE * sizeof(uint32_t)))
305*02e95f1aSMarcin Radomski             p->cmask |= 1 << (idx + SNDRV_PCM_HW_PARAM_FIRST_MASK);
306*02e95f1aSMarcin Radomski 
307*02e95f1aSMarcin Radomski         /* Actually change the requested mask to constrained mask */
308*02e95f1aSMarcin Radomski         for (i = 0; i < PCM_MASK_SIZE; i++)
309*02e95f1aSMarcin Radomski             req_mask->bits[i] &= con_mask->bits[i];
310*02e95f1aSMarcin Radomski     }
311*02e95f1aSMarcin Radomski 
312*02e95f1aSMarcin Radomski     return 0;
313*02e95f1aSMarcin Radomski }
314*02e95f1aSMarcin Radomski 
pcm_plug_interval_refine(struct snd_pcm_hw_params * p,struct snd_pcm_hw_params * c)315*02e95f1aSMarcin Radomski static int pcm_plug_interval_refine(struct snd_pcm_hw_params *p,
316*02e95f1aSMarcin Radomski                 struct snd_pcm_hw_params *c)
317*02e95f1aSMarcin Radomski {
318*02e95f1aSMarcin Radomski     struct snd_interval *ri;
319*02e95f1aSMarcin Radomski     struct snd_interval *ci;
320*02e95f1aSMarcin Radomski     unsigned int idx;
321*02e95f1aSMarcin Radomski     unsigned int intervals;
322*02e95f1aSMarcin Radomski     int changed = 0;
323*02e95f1aSMarcin Radomski 
324*02e95f1aSMarcin Radomski     intervals = SNDRV_PCM_HW_PARAM_LAST_INTERVAL -
325*02e95f1aSMarcin Radomski                 SNDRV_PCM_HW_PARAM_FIRST_INTERVAL;
326*02e95f1aSMarcin Radomski 
327*02e95f1aSMarcin Radomski     for (idx = 0; idx <= intervals; idx++) {
328*02e95f1aSMarcin Radomski         ri = &p->intervals[idx];
329*02e95f1aSMarcin Radomski         ci = &c->intervals[idx];
330*02e95f1aSMarcin Radomski 
331*02e95f1aSMarcin Radomski         if (!(p->rmask & (1 << (idx + SNDRV_PCM_HW_PARAM_FIRST_INTERVAL)) ))
332*02e95f1aSMarcin Radomski             continue;
333*02e95f1aSMarcin Radomski 
334*02e95f1aSMarcin Radomski         if (ri->min < ci->min) {
335*02e95f1aSMarcin Radomski             ri->min = ci->min;
336*02e95f1aSMarcin Radomski             ri->openmin = ci->openmin;
337*02e95f1aSMarcin Radomski             changed = 1;
338*02e95f1aSMarcin Radomski         } else if (ri->min == ci->min && !ri->openmin && ci->openmin) {
339*02e95f1aSMarcin Radomski             ri->openmin = 1;
340*02e95f1aSMarcin Radomski             changed = 1;
341*02e95f1aSMarcin Radomski         }
342*02e95f1aSMarcin Radomski 
343*02e95f1aSMarcin Radomski         if (ri->max > ci->max) {
344*02e95f1aSMarcin Radomski             ri->max = ci->max;
345*02e95f1aSMarcin Radomski             ri->openmax = ci->openmax;
346*02e95f1aSMarcin Radomski             changed = 1;
347*02e95f1aSMarcin Radomski         } else if (ri->max == ci->max && !ri->openmax && ci->openmax) {
348*02e95f1aSMarcin Radomski             ri->openmax = 1;
349*02e95f1aSMarcin Radomski             changed = 1;
350*02e95f1aSMarcin Radomski         };
351*02e95f1aSMarcin Radomski 
352*02e95f1aSMarcin Radomski         if (!ri->integer && ci->integer) {
353*02e95f1aSMarcin Radomski             ri->integer = 1;
354*02e95f1aSMarcin Radomski             changed = 1;
355*02e95f1aSMarcin Radomski         }
356*02e95f1aSMarcin Radomski 
357*02e95f1aSMarcin Radomski         if (ri->integer) {
358*02e95f1aSMarcin Radomski             if (ri->openmin) {
359*02e95f1aSMarcin Radomski                 ri->min++;
360*02e95f1aSMarcin Radomski                 ri->openmin = 0;
361*02e95f1aSMarcin Radomski             }
362*02e95f1aSMarcin Radomski             if (ri->openmax) {
363*02e95f1aSMarcin Radomski                 ri->max--;
364*02e95f1aSMarcin Radomski                 ri->openmax = 0;
365*02e95f1aSMarcin Radomski             }
366*02e95f1aSMarcin Radomski         } else if (!ri->openmin && !ri->openmax && ri->min == ri->max) {
367*02e95f1aSMarcin Radomski             ri->integer = 1;
368*02e95f1aSMarcin Radomski         }
369*02e95f1aSMarcin Radomski 
370*02e95f1aSMarcin Radomski         /* Set the changed mask */
371*02e95f1aSMarcin Radomski         if (changed)
372*02e95f1aSMarcin Radomski             p->cmask |= (1 << (idx + SNDRV_PCM_HW_PARAM_FIRST_INTERVAL));
373*02e95f1aSMarcin Radomski     }
374*02e95f1aSMarcin Radomski 
375*02e95f1aSMarcin Radomski     return 0;
376*02e95f1aSMarcin Radomski }
377*02e95f1aSMarcin Radomski 
378*02e95f1aSMarcin Radomski 
pcm_plug_hw_params_refine(struct snd_pcm_hw_params * p,struct snd_pcm_hw_params * c)379*02e95f1aSMarcin Radomski static int pcm_plug_hw_params_refine(struct snd_pcm_hw_params *p,
380*02e95f1aSMarcin Radomski                 struct snd_pcm_hw_params *c)
381*02e95f1aSMarcin Radomski {
382*02e95f1aSMarcin Radomski     int rc;
383*02e95f1aSMarcin Radomski 
384*02e95f1aSMarcin Radomski     rc = pcm_plug_masks_refine(p, c);
385*02e95f1aSMarcin Radomski     if (rc) {
386*02e95f1aSMarcin Radomski         fprintf(stderr, "%s: masks refine failed %d\n", __func__, rc);
387*02e95f1aSMarcin Radomski         return rc;
388*02e95f1aSMarcin Radomski     }
389*02e95f1aSMarcin Radomski 
390*02e95f1aSMarcin Radomski     rc = pcm_plug_interval_refine(p, c);
391*02e95f1aSMarcin Radomski     if (rc) {
392*02e95f1aSMarcin Radomski         fprintf(stderr, "%s: interval refine failed %d\n", __func__, rc);
393*02e95f1aSMarcin Radomski         return rc;
394*02e95f1aSMarcin Radomski     }
395*02e95f1aSMarcin Radomski 
396*02e95f1aSMarcin Radomski     /* clear the requested params */
397*02e95f1aSMarcin Radomski     p->rmask = 0;
398*02e95f1aSMarcin Radomski 
399*02e95f1aSMarcin Radomski     return rc;
400*02e95f1aSMarcin Radomski }
401*02e95f1aSMarcin Radomski 
__pcm_plug_hrefine(struct pcm_plug_data * plug_data,struct snd_pcm_hw_params * params)402*02e95f1aSMarcin Radomski static int __pcm_plug_hrefine(struct pcm_plug_data *plug_data,
403*02e95f1aSMarcin Radomski                 struct snd_pcm_hw_params *params)
404*02e95f1aSMarcin Radomski {
405*02e95f1aSMarcin Radomski     struct pcm_plugin *plugin = plug_data->plugin;
406*02e95f1aSMarcin Radomski     struct snd_pcm_hw_params plug_params;
407*02e95f1aSMarcin Radomski     int rc;
408*02e95f1aSMarcin Radomski 
409*02e95f1aSMarcin Radomski     memset(&plug_params, 0, sizeof(plug_params));
410*02e95f1aSMarcin Radomski     rc = pcm_plug_get_params(plugin, &plug_params);
411*02e95f1aSMarcin Radomski     if (rc) {
412*02e95f1aSMarcin Radomski         fprintf(stderr, "%s: pcm_plug_get_params failed %d\n",
413*02e95f1aSMarcin Radomski                __func__, rc);
414*02e95f1aSMarcin Radomski         return -EINVAL;
415*02e95f1aSMarcin Radomski     }
416*02e95f1aSMarcin Radomski 
417*02e95f1aSMarcin Radomski     return pcm_plug_hw_params_refine(params, &plug_params);
418*02e95f1aSMarcin Radomski 
419*02e95f1aSMarcin Radomski }
420*02e95f1aSMarcin Radomski 
pcm_plug_hrefine(struct pcm_plug_data * plug_data,struct snd_pcm_hw_params * params)421*02e95f1aSMarcin Radomski static int pcm_plug_hrefine(struct pcm_plug_data *plug_data,
422*02e95f1aSMarcin Radomski                 struct snd_pcm_hw_params *params)
423*02e95f1aSMarcin Radomski {
424*02e95f1aSMarcin Radomski     return __pcm_plug_hrefine(plug_data, params);
425*02e95f1aSMarcin Radomski }
426*02e95f1aSMarcin Radomski 
pcm_plug_interval_select(struct snd_pcm_hw_params * p,unsigned int param,unsigned int select,unsigned int val)427*02e95f1aSMarcin Radomski static int pcm_plug_interval_select(struct snd_pcm_hw_params *p,
428*02e95f1aSMarcin Radomski         unsigned int param, unsigned int select, unsigned int val)
429*02e95f1aSMarcin Radomski {
430*02e95f1aSMarcin Radomski     struct snd_interval *i;
431*02e95f1aSMarcin Radomski 
432*02e95f1aSMarcin Radomski     if (param < SNDRV_PCM_HW_PARAM_FIRST_INTERVAL ||
433*02e95f1aSMarcin Radomski         param > SNDRV_PCM_HW_PARAM_LAST_INTERVAL)
434*02e95f1aSMarcin Radomski         return -EINVAL;
435*02e95f1aSMarcin Radomski 
436*02e95f1aSMarcin Radomski     i = &p->intervals[param - SNDRV_PCM_HW_PARAM_FIRST_INTERVAL];
437*02e95f1aSMarcin Radomski 
438*02e95f1aSMarcin Radomski     if (!i->min)
439*02e95f1aSMarcin Radomski         return -EINVAL;
440*02e95f1aSMarcin Radomski 
441*02e95f1aSMarcin Radomski     switch (select) {
442*02e95f1aSMarcin Radomski 
443*02e95f1aSMarcin Radomski     case PCM_PLUG_HW_PARAM_SELECT_MIN:
444*02e95f1aSMarcin Radomski         i->max = i->min;
445*02e95f1aSMarcin Radomski         break;
446*02e95f1aSMarcin Radomski 
447*02e95f1aSMarcin Radomski     case PCM_PLUG_HW_PARAM_SELECT_MAX:
448*02e95f1aSMarcin Radomski         i->min = i->max;
449*02e95f1aSMarcin Radomski         break;
450*02e95f1aSMarcin Radomski 
451*02e95f1aSMarcin Radomski     case PCM_PLUG_HW_PARAM_SELECT_VAL:
452*02e95f1aSMarcin Radomski         i->min = i->max = val;
453*02e95f1aSMarcin Radomski         break;
454*02e95f1aSMarcin Radomski 
455*02e95f1aSMarcin Radomski     default:
456*02e95f1aSMarcin Radomski         return -EINVAL;
457*02e95f1aSMarcin Radomski     }
458*02e95f1aSMarcin Radomski 
459*02e95f1aSMarcin Radomski     return 0;
460*02e95f1aSMarcin Radomski }
461*02e95f1aSMarcin Radomski 
pcm_plug_hw_params_set(struct snd_pcm_hw_params * p)462*02e95f1aSMarcin Radomski static void pcm_plug_hw_params_set(struct snd_pcm_hw_params *p)
463*02e95f1aSMarcin Radomski {
464*02e95f1aSMarcin Radomski     unsigned int i, select;
465*02e95f1aSMarcin Radomski     unsigned int bw, ch, period_sz, periods;
466*02e95f1aSMarcin Radomski     unsigned int val1, val2, offset;
467*02e95f1aSMarcin Radomski 
468*02e95f1aSMarcin Radomski     offset = SNDRV_PCM_HW_PARAM_FIRST_INTERVAL;
469*02e95f1aSMarcin Radomski 
470*02e95f1aSMarcin Radomski     /* Select the min values first */
471*02e95f1aSMarcin Radomski     select = PCM_PLUG_HW_PARAM_SELECT_MIN;
472*02e95f1aSMarcin Radomski     for (i = 0; i < ARRAY_SIZE(param_list); i++)
473*02e95f1aSMarcin Radomski         pcm_plug_interval_select(p, param_list[i], select, 0);
474*02e95f1aSMarcin Radomski 
475*02e95f1aSMarcin Radomski     /* Select calculated values */
476*02e95f1aSMarcin Radomski     select = PCM_PLUG_HW_PARAM_SELECT_VAL;
477*02e95f1aSMarcin Radomski     bw = (p->intervals[SNDRV_PCM_HW_PARAM_SAMPLE_BITS - offset]).min;
478*02e95f1aSMarcin Radomski     ch = (p->intervals[SNDRV_PCM_HW_PARAM_CHANNELS - offset]).min;
479*02e95f1aSMarcin Radomski     period_sz = (p->intervals[SNDRV_PCM_HW_PARAM_PERIOD_SIZE - offset]).min;
480*02e95f1aSMarcin Radomski     periods = (p->intervals[SNDRV_PCM_HW_PARAM_PERIODS - offset]).min;
481*02e95f1aSMarcin Radomski 
482*02e95f1aSMarcin Radomski     val1 = bw * ch;        // frame_bits;
483*02e95f1aSMarcin Radomski     pcm_plug_interval_select(p, SNDRV_PCM_HW_PARAM_FRAME_BITS, select, val1);
484*02e95f1aSMarcin Radomski 
485*02e95f1aSMarcin Radomski     val2 = pcm_plug_frames_to_bytes(period_sz, val1); // period_bytes;
486*02e95f1aSMarcin Radomski     pcm_plug_interval_select(p, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, select,
487*02e95f1aSMarcin Radomski                              val2);
488*02e95f1aSMarcin Radomski 
489*02e95f1aSMarcin Radomski     val2 = period_sz * periods; //buffer_size;
490*02e95f1aSMarcin Radomski     pcm_plug_interval_select(p, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, select, val2);
491*02e95f1aSMarcin Radomski 
492*02e95f1aSMarcin Radomski     val2 = pcm_plug_frames_to_bytes(period_sz * periods, val1); //buffer_bytes;
493*02e95f1aSMarcin Radomski     pcm_plug_interval_select(p, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, select, val2);
494*02e95f1aSMarcin Radomski }
495*02e95f1aSMarcin Radomski 
pcm_plug_hparams(struct pcm_plug_data * plug_data,struct snd_pcm_hw_params * params)496*02e95f1aSMarcin Radomski static int pcm_plug_hparams(struct pcm_plug_data *plug_data,
497*02e95f1aSMarcin Radomski                 struct snd_pcm_hw_params *params)
498*02e95f1aSMarcin Radomski {
499*02e95f1aSMarcin Radomski     struct pcm_plugin *plugin = plug_data->plugin;
500*02e95f1aSMarcin Radomski     int rc;
501*02e95f1aSMarcin Radomski 
502*02e95f1aSMarcin Radomski     if (plugin->state != PCM_PLUG_STATE_OPEN)
503*02e95f1aSMarcin Radomski             return -EBADFD;
504*02e95f1aSMarcin Radomski 
505*02e95f1aSMarcin Radomski     params->rmask = ~0U;
506*02e95f1aSMarcin Radomski 
507*02e95f1aSMarcin Radomski     rc = __pcm_plug_hrefine(plug_data, params);
508*02e95f1aSMarcin Radomski     if (rc) {
509*02e95f1aSMarcin Radomski         fprintf(stderr, "%s: __pcm_plug_hrefine failed %d\n",
510*02e95f1aSMarcin Radomski                __func__, rc);
511*02e95f1aSMarcin Radomski         return rc;
512*02e95f1aSMarcin Radomski     }
513*02e95f1aSMarcin Radomski 
514*02e95f1aSMarcin Radomski     pcm_plug_hw_params_set(params);
515*02e95f1aSMarcin Radomski 
516*02e95f1aSMarcin Radomski     rc = plug_data->ops->hw_params(plugin, params);
517*02e95f1aSMarcin Radomski     if (!rc)
518*02e95f1aSMarcin Radomski         plugin->state = PCM_PLUG_STATE_SETUP;
519*02e95f1aSMarcin Radomski 
520*02e95f1aSMarcin Radomski     return rc;
521*02e95f1aSMarcin Radomski }
522*02e95f1aSMarcin Radomski 
pcm_plug_sparams(struct pcm_plug_data * plug_data,struct snd_pcm_sw_params * params)523*02e95f1aSMarcin Radomski static int pcm_plug_sparams(struct pcm_plug_data *plug_data,
524*02e95f1aSMarcin Radomski                 struct snd_pcm_sw_params *params)
525*02e95f1aSMarcin Radomski {
526*02e95f1aSMarcin Radomski     struct pcm_plugin *plugin = plug_data->plugin;
527*02e95f1aSMarcin Radomski 
528*02e95f1aSMarcin Radomski     if (plugin->state != PCM_PLUG_STATE_SETUP)
529*02e95f1aSMarcin Radomski         return -EBADFD;
530*02e95f1aSMarcin Radomski 
531*02e95f1aSMarcin Radomski     return plug_data->ops->sw_params(plugin, params);
532*02e95f1aSMarcin Radomski }
533*02e95f1aSMarcin Radomski 
pcm_plug_sync_ptr(struct pcm_plug_data * plug_data,struct snd_pcm_sync_ptr * sync_ptr)534*02e95f1aSMarcin Radomski static int pcm_plug_sync_ptr(struct pcm_plug_data *plug_data,
535*02e95f1aSMarcin Radomski                 struct snd_pcm_sync_ptr *sync_ptr)
536*02e95f1aSMarcin Radomski {
537*02e95f1aSMarcin Radomski     struct pcm_plugin *plugin = plug_data->plugin;
538*02e95f1aSMarcin Radomski     int ret = -EBADFD;
539*02e95f1aSMarcin Radomski 
540*02e95f1aSMarcin Radomski     if (plugin->state >= PCM_PLUG_STATE_SETUP) {
541*02e95f1aSMarcin Radomski         ret = plug_data->ops->sync_ptr(plugin, sync_ptr);
542*02e95f1aSMarcin Radomski         if (ret == 0)
543*02e95f1aSMarcin Radomski             sync_ptr->s.status.state = convert_plugin_to_pcm_state(plugin->state);
544*02e95f1aSMarcin Radomski     }
545*02e95f1aSMarcin Radomski 
546*02e95f1aSMarcin Radomski     return ret;
547*02e95f1aSMarcin Radomski }
548*02e95f1aSMarcin Radomski 
pcm_plug_writei_frames(struct pcm_plug_data * plug_data,struct snd_xferi * x)549*02e95f1aSMarcin Radomski static int pcm_plug_writei_frames(struct pcm_plug_data *plug_data,
550*02e95f1aSMarcin Radomski                 struct snd_xferi *x)
551*02e95f1aSMarcin Radomski {
552*02e95f1aSMarcin Radomski     struct pcm_plugin *plugin = plug_data->plugin;
553*02e95f1aSMarcin Radomski 
554*02e95f1aSMarcin Radomski     if (plugin->state != PCM_PLUG_STATE_PREPARED &&
555*02e95f1aSMarcin Radomski         plugin->state != PCM_PLUG_STATE_RUNNING)
556*02e95f1aSMarcin Radomski         return -EBADFD;
557*02e95f1aSMarcin Radomski 
558*02e95f1aSMarcin Radomski     return plug_data->ops->writei_frames(plugin, x);
559*02e95f1aSMarcin Radomski }
560*02e95f1aSMarcin Radomski 
pcm_plug_readi_frames(struct pcm_plug_data * plug_data,struct snd_xferi * x)561*02e95f1aSMarcin Radomski static int pcm_plug_readi_frames(struct pcm_plug_data *plug_data,
562*02e95f1aSMarcin Radomski                 struct snd_xferi *x)
563*02e95f1aSMarcin Radomski {
564*02e95f1aSMarcin Radomski     struct pcm_plugin *plugin = plug_data->plugin;
565*02e95f1aSMarcin Radomski 
566*02e95f1aSMarcin Radomski     if (plugin->state != PCM_PLUG_STATE_RUNNING)
567*02e95f1aSMarcin Radomski         return -EBADFD;
568*02e95f1aSMarcin Radomski 
569*02e95f1aSMarcin Radomski     return plug_data->ops->readi_frames(plugin, x);
570*02e95f1aSMarcin Radomski }
571*02e95f1aSMarcin Radomski 
pcm_plug_ttstamp(struct pcm_plug_data * plug_data,int * tstamp)572*02e95f1aSMarcin Radomski static int pcm_plug_ttstamp(struct pcm_plug_data *plug_data,
573*02e95f1aSMarcin Radomski                 int *tstamp)
574*02e95f1aSMarcin Radomski {
575*02e95f1aSMarcin Radomski     struct pcm_plugin *plugin = plug_data->plugin;
576*02e95f1aSMarcin Radomski 
577*02e95f1aSMarcin Radomski     if (plugin->state < PCM_PLUG_STATE_SETUP)
578*02e95f1aSMarcin Radomski         return -EBADFD;
579*02e95f1aSMarcin Radomski 
580*02e95f1aSMarcin Radomski     return plug_data->ops->ttstamp(plugin, tstamp);
581*02e95f1aSMarcin Radomski }
582*02e95f1aSMarcin Radomski 
pcm_plug_prepare(struct pcm_plug_data * plug_data)583*02e95f1aSMarcin Radomski static int pcm_plug_prepare(struct pcm_plug_data *plug_data)
584*02e95f1aSMarcin Radomski {
585*02e95f1aSMarcin Radomski     struct pcm_plugin *plugin = plug_data->plugin;
586*02e95f1aSMarcin Radomski     int rc;
587*02e95f1aSMarcin Radomski 
588*02e95f1aSMarcin Radomski     if (plugin->state != PCM_PLUG_STATE_SETUP)
589*02e95f1aSMarcin Radomski         return -EBADFD;
590*02e95f1aSMarcin Radomski 
591*02e95f1aSMarcin Radomski     rc = plug_data->ops->prepare(plugin);
592*02e95f1aSMarcin Radomski     if (!rc)
593*02e95f1aSMarcin Radomski         plugin->state = PCM_PLUG_STATE_PREPARED;
594*02e95f1aSMarcin Radomski 
595*02e95f1aSMarcin Radomski     return rc;
596*02e95f1aSMarcin Radomski }
597*02e95f1aSMarcin Radomski 
pcm_plug_start(struct pcm_plug_data * plug_data)598*02e95f1aSMarcin Radomski static int pcm_plug_start(struct pcm_plug_data *plug_data)
599*02e95f1aSMarcin Radomski {
600*02e95f1aSMarcin Radomski     struct pcm_plugin *plugin = plug_data->plugin;
601*02e95f1aSMarcin Radomski     int rc;
602*02e95f1aSMarcin Radomski 
603*02e95f1aSMarcin Radomski     if (plugin->state != PCM_PLUG_STATE_PREPARED)
604*02e95f1aSMarcin Radomski         return -EBADFD;
605*02e95f1aSMarcin Radomski 
606*02e95f1aSMarcin Radomski     rc = plug_data->ops->start(plugin);
607*02e95f1aSMarcin Radomski     if (!rc)
608*02e95f1aSMarcin Radomski         plugin->state = PCM_PLUG_STATE_RUNNING;
609*02e95f1aSMarcin Radomski 
610*02e95f1aSMarcin Radomski     return rc;
611*02e95f1aSMarcin Radomski }
612*02e95f1aSMarcin Radomski 
pcm_plug_drop(struct pcm_plug_data * plug_data)613*02e95f1aSMarcin Radomski static int pcm_plug_drop(struct pcm_plug_data *plug_data)
614*02e95f1aSMarcin Radomski {
615*02e95f1aSMarcin Radomski     struct pcm_plugin *plugin = plug_data->plugin;
616*02e95f1aSMarcin Radomski     int rc;
617*02e95f1aSMarcin Radomski 
618*02e95f1aSMarcin Radomski     rc = plug_data->ops->drop(plugin);
619*02e95f1aSMarcin Radomski     if (!rc)
620*02e95f1aSMarcin Radomski         plugin->state = PCM_PLUG_STATE_SETUP;
621*02e95f1aSMarcin Radomski 
622*02e95f1aSMarcin Radomski     return rc;
623*02e95f1aSMarcin Radomski }
624*02e95f1aSMarcin Radomski 
pcm_plug_drain(struct pcm_plug_data * plug_data)625*02e95f1aSMarcin Radomski static int pcm_plug_drain(struct pcm_plug_data *plug_data)
626*02e95f1aSMarcin Radomski {
627*02e95f1aSMarcin Radomski     struct pcm_plugin *plugin = plug_data->plugin;
628*02e95f1aSMarcin Radomski 
629*02e95f1aSMarcin Radomski     if (plugin->state != PCM_PLUG_STATE_RUNNING)
630*02e95f1aSMarcin Radomski         return -EBADFD;
631*02e95f1aSMarcin Radomski 
632*02e95f1aSMarcin Radomski     return plug_data->ops->drain(plugin);
633*02e95f1aSMarcin Radomski }
634*02e95f1aSMarcin Radomski 
pcm_plug_ioctl(void * data,unsigned int cmd,...)635*02e95f1aSMarcin Radomski static int pcm_plug_ioctl(void *data, unsigned int cmd, ...)
636*02e95f1aSMarcin Radomski {
637*02e95f1aSMarcin Radomski     struct pcm_plug_data *plug_data = data;
638*02e95f1aSMarcin Radomski     struct pcm_plugin *plugin = plug_data->plugin;
639*02e95f1aSMarcin Radomski     int ret;
640*02e95f1aSMarcin Radomski     va_list ap;
641*02e95f1aSMarcin Radomski     void *arg;
642*02e95f1aSMarcin Radomski 
643*02e95f1aSMarcin Radomski     va_start(ap, cmd);
644*02e95f1aSMarcin Radomski     arg = va_arg(ap, void *);
645*02e95f1aSMarcin Radomski     va_end(ap);
646*02e95f1aSMarcin Radomski 
647*02e95f1aSMarcin Radomski     switch (cmd) {
648*02e95f1aSMarcin Radomski     case SNDRV_PCM_IOCTL_INFO:
649*02e95f1aSMarcin Radomski         ret = pcm_plug_info(plug_data, arg);
650*02e95f1aSMarcin Radomski         break;
651*02e95f1aSMarcin Radomski     case SNDRV_PCM_IOCTL_TTSTAMP:
652*02e95f1aSMarcin Radomski         ret = pcm_plug_ttstamp(plug_data, arg);
653*02e95f1aSMarcin Radomski         break;
654*02e95f1aSMarcin Radomski     case SNDRV_PCM_IOCTL_HW_REFINE:
655*02e95f1aSMarcin Radomski         ret = pcm_plug_hrefine(plug_data, arg);
656*02e95f1aSMarcin Radomski         break;
657*02e95f1aSMarcin Radomski     case SNDRV_PCM_IOCTL_HW_PARAMS:
658*02e95f1aSMarcin Radomski         ret = pcm_plug_hparams(plug_data, arg);
659*02e95f1aSMarcin Radomski         break;
660*02e95f1aSMarcin Radomski     case SNDRV_PCM_IOCTL_SW_PARAMS:
661*02e95f1aSMarcin Radomski         ret = pcm_plug_sparams(plug_data, arg);
662*02e95f1aSMarcin Radomski         break;
663*02e95f1aSMarcin Radomski     case SNDRV_PCM_IOCTL_SYNC_PTR:
664*02e95f1aSMarcin Radomski         ret = pcm_plug_sync_ptr(plug_data, arg);
665*02e95f1aSMarcin Radomski         break;
666*02e95f1aSMarcin Radomski     case SNDRV_PCM_IOCTL_PREPARE:
667*02e95f1aSMarcin Radomski         ret = pcm_plug_prepare(plug_data);
668*02e95f1aSMarcin Radomski         break;
669*02e95f1aSMarcin Radomski     case SNDRV_PCM_IOCTL_START:
670*02e95f1aSMarcin Radomski         ret = pcm_plug_start(plug_data);
671*02e95f1aSMarcin Radomski         break;
672*02e95f1aSMarcin Radomski     case SNDRV_PCM_IOCTL_DRAIN:
673*02e95f1aSMarcin Radomski         ret = pcm_plug_drain(plug_data);
674*02e95f1aSMarcin Radomski         break;
675*02e95f1aSMarcin Radomski     case SNDRV_PCM_IOCTL_DROP:
676*02e95f1aSMarcin Radomski         ret = pcm_plug_drop(plug_data);
677*02e95f1aSMarcin Radomski         break;
678*02e95f1aSMarcin Radomski     case SNDRV_PCM_IOCTL_WRITEI_FRAMES:
679*02e95f1aSMarcin Radomski         ret = pcm_plug_writei_frames(plug_data, arg);
680*02e95f1aSMarcin Radomski         break;
681*02e95f1aSMarcin Radomski     case SNDRV_PCM_IOCTL_READI_FRAMES:
682*02e95f1aSMarcin Radomski         ret = pcm_plug_readi_frames(plug_data, arg);
683*02e95f1aSMarcin Radomski         break;
684*02e95f1aSMarcin Radomski     default:
685*02e95f1aSMarcin Radomski         ret = plug_data->ops->ioctl(plugin, cmd, arg);
686*02e95f1aSMarcin Radomski         break;
687*02e95f1aSMarcin Radomski     }
688*02e95f1aSMarcin Radomski 
689*02e95f1aSMarcin Radomski     return ret;
690*02e95f1aSMarcin Radomski }
691*02e95f1aSMarcin Radomski 
pcm_plug_poll(void * data,struct pollfd * pfd,nfds_t nfds,int timeout)692*02e95f1aSMarcin Radomski static int pcm_plug_poll(void *data, struct pollfd *pfd, nfds_t nfds,
693*02e95f1aSMarcin Radomski         int timeout)
694*02e95f1aSMarcin Radomski {
695*02e95f1aSMarcin Radomski     struct pcm_plug_data *plug_data = data;
696*02e95f1aSMarcin Radomski     struct pcm_plugin *plugin = plug_data->plugin;
697*02e95f1aSMarcin Radomski 
698*02e95f1aSMarcin Radomski     return plug_data->ops->poll(plugin, pfd, nfds, timeout);
699*02e95f1aSMarcin Radomski }
700*02e95f1aSMarcin Radomski 
pcm_plug_mmap(void * data,void * addr,size_t length,int prot,int flags,off_t offset)701*02e95f1aSMarcin Radomski static void *pcm_plug_mmap(void *data, void *addr, size_t length, int prot,
702*02e95f1aSMarcin Radomski                        int flags, off_t offset)
703*02e95f1aSMarcin Radomski {
704*02e95f1aSMarcin Radomski     struct pcm_plug_data *plug_data = data;
705*02e95f1aSMarcin Radomski     struct pcm_plugin *plugin = plug_data->plugin;
706*02e95f1aSMarcin Radomski 
707*02e95f1aSMarcin Radomski     if (plugin->state != PCM_PLUG_STATE_SETUP)
708*02e95f1aSMarcin Radomski         return NULL;
709*02e95f1aSMarcin Radomski 
710*02e95f1aSMarcin Radomski     return plug_data->ops->mmap(plugin, addr, length, prot, flags, offset);
711*02e95f1aSMarcin Radomski }
712*02e95f1aSMarcin Radomski 
pcm_plug_munmap(void * data,void * addr,size_t length)713*02e95f1aSMarcin Radomski static int pcm_plug_munmap(void *data, void *addr, size_t length)
714*02e95f1aSMarcin Radomski {
715*02e95f1aSMarcin Radomski     struct pcm_plug_data *plug_data = data;
716*02e95f1aSMarcin Radomski     struct pcm_plugin *plugin = plug_data->plugin;
717*02e95f1aSMarcin Radomski 
718*02e95f1aSMarcin Radomski     if (plugin->state != PCM_PLUG_STATE_SETUP)
719*02e95f1aSMarcin Radomski         return -EBADFD;
720*02e95f1aSMarcin Radomski 
721*02e95f1aSMarcin Radomski     return plug_data->ops->munmap(plugin, addr, length);
722*02e95f1aSMarcin Radomski }
723*02e95f1aSMarcin Radomski 
pcm_plug_open(unsigned int card,unsigned int device,unsigned int flags,void ** data,struct snd_node * pcm_node)724*02e95f1aSMarcin Radomski static int pcm_plug_open(unsigned int card, unsigned int device,
725*02e95f1aSMarcin Radomski                          unsigned int flags, void **data, struct snd_node *pcm_node)
726*02e95f1aSMarcin Radomski {
727*02e95f1aSMarcin Radomski     struct pcm_plug_data *plug_data;
728*02e95f1aSMarcin Radomski     void *dl_hdl;
729*02e95f1aSMarcin Radomski     int rc = 0;
730*02e95f1aSMarcin Radomski     char *so_name;
731*02e95f1aSMarcin Radomski 
732*02e95f1aSMarcin Radomski     plug_data = calloc(1, sizeof(*plug_data));
733*02e95f1aSMarcin Radomski     if (!plug_data) {
734*02e95f1aSMarcin Radomski         return -ENOMEM;
735*02e95f1aSMarcin Radomski     }
736*02e95f1aSMarcin Radomski 
737*02e95f1aSMarcin Radomski     rc = snd_utils_get_str(pcm_node, "so-name", &so_name);
738*02e95f1aSMarcin Radomski     if (rc) {
739*02e95f1aSMarcin Radomski         fprintf(stderr, "%s: failed to get plugin lib name\n", __func__);
740*02e95f1aSMarcin Radomski         goto err_get_lib;
741*02e95f1aSMarcin Radomski     }
742*02e95f1aSMarcin Radomski 
743*02e95f1aSMarcin Radomski     dl_hdl = dlopen(so_name, RTLD_NOW);
744*02e95f1aSMarcin Radomski     if (!dl_hdl) {
745*02e95f1aSMarcin Radomski         fprintf(stderr, "%s: unable to open %s\n", __func__, so_name);
746*02e95f1aSMarcin Radomski         goto err_dl_open;
747*02e95f1aSMarcin Radomski     } else {
748*02e95f1aSMarcin Radomski         fprintf(stderr, "%s: dlopen successful for %s\n", __func__, so_name);
749*02e95f1aSMarcin Radomski     }
750*02e95f1aSMarcin Radomski 
751*02e95f1aSMarcin Radomski     dlerror();
752*02e95f1aSMarcin Radomski 
753*02e95f1aSMarcin Radomski     plug_data->ops = dlsym(dl_hdl, "pcm_plugin_ops");
754*02e95f1aSMarcin Radomski     if (!plug_data->ops) {
755*02e95f1aSMarcin Radomski         fprintf(stderr, "%s: dlsym to open fn failed, err = '%s'\n",
756*02e95f1aSMarcin Radomski                 __func__, dlerror());
757*02e95f1aSMarcin Radomski         goto err_dlsym;
758*02e95f1aSMarcin Radomski     }
759*02e95f1aSMarcin Radomski 
760*02e95f1aSMarcin Radomski     rc = plug_data->ops->open(&plug_data->plugin, card, device, flags);
761*02e95f1aSMarcin Radomski     if (rc) {
762*02e95f1aSMarcin Radomski         fprintf(stderr, "%s: failed to open plugin\n", __func__);
763*02e95f1aSMarcin Radomski         goto err_open;
764*02e95f1aSMarcin Radomski     }
765*02e95f1aSMarcin Radomski 
766*02e95f1aSMarcin Radomski     plug_data->dl_hdl = dl_hdl;
767*02e95f1aSMarcin Radomski     plug_data->card = card;
768*02e95f1aSMarcin Radomski     plug_data->device = device;
769*02e95f1aSMarcin Radomski     plug_data->dev_node = pcm_node;
770*02e95f1aSMarcin Radomski     plug_data->flags = flags;
771*02e95f1aSMarcin Radomski 
772*02e95f1aSMarcin Radomski     *data = plug_data;
773*02e95f1aSMarcin Radomski 
774*02e95f1aSMarcin Radomski     plug_data->plugin->state = PCM_PLUG_STATE_OPEN;
775*02e95f1aSMarcin Radomski 
776*02e95f1aSMarcin Radomski     return 0;
777*02e95f1aSMarcin Radomski 
778*02e95f1aSMarcin Radomski err_open:
779*02e95f1aSMarcin Radomski err_dlsym:
780*02e95f1aSMarcin Radomski     dlclose(dl_hdl);
781*02e95f1aSMarcin Radomski err_get_lib:
782*02e95f1aSMarcin Radomski err_dl_open:
783*02e95f1aSMarcin Radomski     free(plug_data);
784*02e95f1aSMarcin Radomski 
785*02e95f1aSMarcin Radomski     return rc;
786*02e95f1aSMarcin Radomski }
787*02e95f1aSMarcin Radomski 
788*02e95f1aSMarcin Radomski const struct pcm_ops plug_ops = {
789*02e95f1aSMarcin Radomski     .open = pcm_plug_open,
790*02e95f1aSMarcin Radomski     .close = pcm_plug_close,
791*02e95f1aSMarcin Radomski     .ioctl = pcm_plug_ioctl,
792*02e95f1aSMarcin Radomski     .mmap = pcm_plug_mmap,
793*02e95f1aSMarcin Radomski     .munmap = pcm_plug_munmap,
794*02e95f1aSMarcin Radomski     .poll = pcm_plug_poll,
795*02e95f1aSMarcin Radomski };
796