1 /*
2 * Copyright (c) 2019-2025 Allwinner Technology Co., Ltd. ALL rights reserved.
3 *
4 * Allwinner is a trademark of Allwinner Technology Co.,Ltd., registered in
5 * the the people's Republic of China and other countries.
6 * All Allwinner Technology Co.,Ltd. trademarks are used with permission.
7 *
8 * DISCLAIMER
9 * THIRD PARTY LICENCES MAY BE REQUIRED TO IMPLEMENT THE SOLUTION/PRODUCT.
10 * IF YOU NEED TO INTEGRATE THIRD PARTY’S TECHNOLOGY (SONY, DTS, DOLBY, AVS OR MPEGLA, ETC.)
11 * IN ALLWINNERS’SDK OR PRODUCTS, YOU SHALL BE SOLELY RESPONSIBLE TO OBTAIN
12 * ALL APPROPRIATELY REQUIRED THIRD PARTY LICENCES.
13 * ALLWINNER SHALL HAVE NO WARRANTY, INDEMNITY OR OTHER OBLIGATIONS WITH RESPECT TO MATTERS
14 * COVERED UNDER ANY REQUIRED THIRD PARTY LICENSE.
15 * YOU ARE SOLELY RESPONSIBLE FOR YOUR USAGE OF THIRD PARTY’S TECHNOLOGY.
16 *
17 *
18 * THIS SOFTWARE IS PROVIDED BY ALLWINNER"AS IS" AND TO THE MAXIMUM EXTENT
19 * PERMITTED BY LAW, ALLWINNER EXPRESSLY DISCLAIMS ALL WARRANTIES OF ANY KIND,
20 * WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING WITHOUT LIMITATION REGARDING
21 * THE TITLE, NON-INFRINGEMENT, ACCURACY, CONDITION, COMPLETENESS, PERFORMANCE
22 * OR MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
23 * IN NO EVENT SHALL ALLWINNER BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26 * LOSS OF USE, DATA, OR PROFITS, OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
28 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
30 * OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32 #ifndef __AW_ALSA_PCM_DIRECT_H
33 #define __AW_ALSA_PCM_DIRECT_H
34 
35 #include <aw-alsa-lib/pcm.h>
36 #include <aw-alsa-lib/plugin/pcm_direct_config.h>
37 #include <semaphore.h>
38 
39 #define DIRECT_IPC_SEMS     1
40 #define DIRECT_IPC_SEM_CLIENT   0
41 
42 typedef void (mix_areas_t)(unsigned int size,
43                volatile void *dst, void *src,
44                volatile signed int *sum, size_t dst_step,
45                size_t src_step, size_t sum_step);
46 
47 typedef void (mix_areas_16_t)(unsigned int size,
48                   volatile signed short *dst, signed short *src,
49                   volatile signed int *sum, size_t dst_step,
50                   size_t src_step, size_t sum_step);
51 
52 typedef void (mix_areas_32_t)(unsigned int size,
53                   volatile signed int *dst, signed int *src,
54                   volatile signed int *sum, size_t dst_step,
55                   size_t src_step, size_t sum_step);
56 
57 typedef void (mix_areas_24_t)(unsigned int size,
58                   volatile unsigned char *dst, unsigned char *src,
59                   volatile signed int *sum, size_t dst_step,
60                   size_t src_step, size_t sum_step);
61 
62 typedef void (mix_areas_u8_t)(unsigned int size,
63                   volatile unsigned char *dst, unsigned char *src,
64                   volatile signed int *sum, size_t dst_step,
65                   size_t src_step, size_t sum_step);
66 
67 typedef struct snd_pcm_direct snd_pcm_direct_t;
68 
69 /* shared among direct plugin clients - be careful to be 32/64bit compatible! */
70 typedef struct {
71     unsigned int magic;         /* magic number */
72     snd_pcm_type_t type;            /* PCM type (currently only hw) */
73     struct {
74         snd_pcm_format_t format;
75         snd_interval_t rate;
76         snd_interval_t period_size;
77         snd_interval_t period_time;
78         snd_interval_t periods;
79         snd_interval_t buffer_size;
80         snd_interval_t buffer_time;
81     } hw;
82     struct {
83         /* copied to slave PCMs */
84         snd_pcm_access_t access;
85         snd_pcm_format_t format;
86         unsigned int channels;
87         unsigned int rate;
88         unsigned int period_size;
89         unsigned int period_time;
90         unsigned int periods;
91 
92         unsigned int avail_min;
93         unsigned int start_threshold;
94         unsigned int stop_threshold;
95         unsigned int silence_threshold;
96         unsigned int silence_size;
97 
98         unsigned int recoveries;    /* no of executed recoveries on slave*/
99 
100         unsigned long long boundary;
101 
102         unsigned int info;
103         unsigned int msbits;
104         unsigned int rate_num;
105         unsigned int rate_den;
106         unsigned int hw_flags;
107         unsigned int fifo_size;
108         unsigned int buffer_size;
109         unsigned int buffer_time;
110 
111         unsigned int sample_bits;
112         unsigned int frame_bits;
113     } s;
114     union {
115         struct {
116             unsigned long long chn_mask;
117         } dshare;
118     } u;
119 } snd_pcm_direct_share_t;
120 
121 struct snd_pcm_direct {
122     snd_pcm_type_t type;
123     key_t ipc_key;
124 
125     sem_t *semid;
126     int poll_index;
127 
128     int locked[DIRECT_IPC_SEMS];
129     snd_pcm_t *spcm;
130     snd_pcm_direct_share_t *shmptr;
131     snd_pcm_uframes_t appl_ptr;
132     snd_pcm_uframes_t last_appl_ptr;
133     snd_pcm_uframes_t hw_ptr;
134     snd_pcm_uframes_t avail_max;
135         snd_pcm_uframes_t slave_appl_ptr;
136         snd_pcm_uframes_t slave_hw_ptr;
137         snd_pcm_uframes_t slave_period_size;
138         snd_pcm_uframes_t slave_buffer_size;
139         snd_pcm_uframes_t slave_boundary;
140 
141     int (*sync_ptr)(snd_pcm_t *pcm);
142 
143     snd_pcm_state_t state;
144 
145     int interleaved;
146     int slowptr;
147     int max_periods;        /* max periods (-1 = fixed periods, 0 = max buffer size) */
148     int var_periodsize;     /* allow variable period size if max_periods is != -1*/
149 
150     unsigned int channels;
151     unsigned int *bindings;
152     unsigned int recoveries;    /* mirror of executed recoveries on slave */
153 
154     union {
155         struct {
156             int shmid_sum;          /* IPC global sum ring buffer memory identification */
157             int *shm_sum_id;        /* IPC global sum ring buffer memory identification */
158             signed int *sum_buffer;     /* shared sum buffer */
159             mix_areas_16_t *mix_areas_16;
160             mix_areas_32_t *mix_areas_32;
161             mix_areas_24_t *mix_areas_24;
162             mix_areas_u8_t *mix_areas_u8;
163             mix_areas_16_t *remix_areas_16;
164             mix_areas_32_t *remix_areas_32;
165             mix_areas_24_t *remix_areas_24;
166             mix_areas_u8_t *remix_areas_u8;
167         } dmix;
168         struct {
169         } dsnoop;
170         struct {
171             unsigned long long chn_mask;
172         } dshare;
173     } u;
174 };
175 
176 struct slave_params {
177     snd_pcm_format_t format;
178         int rate;
179         int channels;
180         int period_time;
181         int buffer_time;
182         snd_pcm_sframes_t period_size;
183         snd_pcm_sframes_t buffer_size;
184         unsigned int periods;
185 };
186 
snd_pcm_direct_semaphore_down(snd_pcm_direct_t * dmix,int sem_num)187 static inline int snd_pcm_direct_semaphore_down(snd_pcm_direct_t *dmix, int sem_num)
188 {
189     int ret;
190 
191     ret = sem_wait(dmix->semid);
192     if (ret != 0) {
193         awalsa_err("sem_wait failed, ret=%d\n", ret);
194         return -1;
195     }
196     dmix->locked[sem_num]++;
197 
198     return ret;
199 }
200 
snd_pcm_direct_semaphore_up(snd_pcm_direct_t * dmix,int sem_num)201 static inline int snd_pcm_direct_semaphore_up(snd_pcm_direct_t *dmix, int sem_num)
202 {
203     int ret;
204 
205     ret = sem_post(dmix->semid);
206     if (ret != 0) {
207         awalsa_err("sem_post failed, ret=%d\n", ret);
208         return -1;
209     }
210 
211     dmix->locked[sem_num]--;
212 
213     return ret;
214 }
215 
216 
217 int snd_pcm_slave_conf_hw_params(const snd_pcm_direct_slave_config_t *conf, struct slave_params *params);
218 
219 int snd_pcm_direct_semaphore_shm_create_or_connect(snd_pcm_direct_t *dmix);
220 int snd_pcm_direct_semaphore_shm_discard(snd_pcm_direct_t *dmix);
221 
222 int snd_pcm_direct_initialize_slave(snd_pcm_direct_t *dmix, snd_pcm_t *spcm, struct slave_params *params);
223 int snd_pcm_direct_initialize_secondary_slave(snd_pcm_direct_t *dmix,
224                         snd_pcm_t *spcm,
225                         struct slave_params *params);
226 
227 int snd_pcm_direct_last_pcm(snd_pcm_direct_t *dmix);
228 
229 int snd_pcm_direct_check_interleave(snd_pcm_direct_t *dmix, snd_pcm_t *pcm);
230 
231 int snd_pcm_direct_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params);
232 int snd_pcm_direct_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params);
233 int snd_pcm_direct_hw_free(snd_pcm_t *pcm);
234 int snd_pcm_direct_sw_params(snd_pcm_t *pcm, snd_pcm_sw_params_t * params);
235 int snd_pcm_direct_channel_info(snd_pcm_t *pcm, snd_pcm_channel_info_t * info);
236 int snd_pcm_direct_mmap(snd_pcm_t *pcm);
237 int snd_pcm_direct_munmap(snd_pcm_t *pcm);
238 int snd_pcm_direct_prepare(snd_pcm_t *pcm);
239 
240 int snd_pcm_direct_slave_recover(snd_pcm_direct_t *direct);
241 int snd_pcm_direct_client_chk_xrun(snd_pcm_direct_t *direct, snd_pcm_t *pcm);
242 int snd_pcm_direct_wait(snd_pcm_t *pcm, int timeout);
243 
244 /*TODO*/
245 int snd_pcm_hw_wait_with_index(snd_pcm_t *hw_pcm, int index, int timeout);
246 int snd_pcm_hw_poll_index_init(snd_pcm_t *hw_pcm);
247 int snd_pcm_hw_poll_index_release(snd_pcm_t *hw_pcm, int index);
248 
249 int snd_pcm_direct_initialize_poll_index(snd_pcm_direct_t *dmix);
250 int snd_pcm_direct_destroy_poll_index(snd_pcm_direct_t *dmix);
251 
252 int snd_pcm_direct_last_pcm_drop(snd_pcm_direct_t *dmix);
253 #endif /* __AW_ALSA_PCM_DIRECT_H */
254