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