1*9cab9fdeSChristos Margiolis /*-
2*9cab9fdeSChristos Margiolis * Copyright (c) 2012-2022 Hans Petter Selasky
3*9cab9fdeSChristos Margiolis *
4*9cab9fdeSChristos Margiolis * Redistribution and use in source and binary forms, with or without
5*9cab9fdeSChristos Margiolis * modification, are permitted provided that the following conditions
6*9cab9fdeSChristos Margiolis * are met:
7*9cab9fdeSChristos Margiolis * 1. Redistributions of source code must retain the above copyright
8*9cab9fdeSChristos Margiolis * notice, this list of conditions and the following disclaimer.
9*9cab9fdeSChristos Margiolis * 2. Redistributions in binary form must reproduce the above copyright
10*9cab9fdeSChristos Margiolis * notice, this list of conditions and the following disclaimer in the
11*9cab9fdeSChristos Margiolis * documentation and/or other materials provided with the distribution.
12*9cab9fdeSChristos Margiolis *
13*9cab9fdeSChristos Margiolis * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14*9cab9fdeSChristos Margiolis * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15*9cab9fdeSChristos Margiolis * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16*9cab9fdeSChristos Margiolis * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17*9cab9fdeSChristos Margiolis * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18*9cab9fdeSChristos Margiolis * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19*9cab9fdeSChristos Margiolis * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20*9cab9fdeSChristos Margiolis * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21*9cab9fdeSChristos Margiolis * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22*9cab9fdeSChristos Margiolis * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23*9cab9fdeSChristos Margiolis * SUCH DAMAGE.
24*9cab9fdeSChristos Margiolis */
25*9cab9fdeSChristos Margiolis
26*9cab9fdeSChristos Margiolis #include <sys/types.h>
27*9cab9fdeSChristos Margiolis #include <sys/queue.h>
28*9cab9fdeSChristos Margiolis
29*9cab9fdeSChristos Margiolis #include <stdint.h>
30*9cab9fdeSChristos Margiolis #include <stdlib.h>
31*9cab9fdeSChristos Margiolis #include <string.h>
32*9cab9fdeSChristos Margiolis
33*9cab9fdeSChristos Margiolis #include <cuse.h>
34*9cab9fdeSChristos Margiolis
35*9cab9fdeSChristos Margiolis #include "int.h"
36*9cab9fdeSChristos Margiolis #include "virtual_oss.h"
37*9cab9fdeSChristos Margiolis
38*9cab9fdeSChristos Margiolis int64_t voss_output_peak[VMAX_CHAN];
39*9cab9fdeSChristos Margiolis int64_t voss_input_peak[VMAX_CHAN];
40*9cab9fdeSChristos Margiolis
41*9cab9fdeSChristos Margiolis static int
vctl_open(struct cuse_dev * pdev __unused,int fflags __unused)42*9cab9fdeSChristos Margiolis vctl_open(struct cuse_dev *pdev __unused, int fflags __unused)
43*9cab9fdeSChristos Margiolis {
44*9cab9fdeSChristos Margiolis return (0);
45*9cab9fdeSChristos Margiolis }
46*9cab9fdeSChristos Margiolis
47*9cab9fdeSChristos Margiolis static int
vctl_close(struct cuse_dev * pdev __unused,int fflags __unused)48*9cab9fdeSChristos Margiolis vctl_close(struct cuse_dev *pdev __unused, int fflags __unused)
49*9cab9fdeSChristos Margiolis {
50*9cab9fdeSChristos Margiolis return (0);
51*9cab9fdeSChristos Margiolis }
52*9cab9fdeSChristos Margiolis
53*9cab9fdeSChristos Margiolis static vprofile_t *
vprofile_by_index(const vprofile_head_t * phead,int index)54*9cab9fdeSChristos Margiolis vprofile_by_index(const vprofile_head_t *phead, int index)
55*9cab9fdeSChristos Margiolis {
56*9cab9fdeSChristos Margiolis vprofile_t *pvp;
57*9cab9fdeSChristos Margiolis
58*9cab9fdeSChristos Margiolis TAILQ_FOREACH(pvp, phead, entry) {
59*9cab9fdeSChristos Margiolis if (!index--)
60*9cab9fdeSChristos Margiolis return (pvp);
61*9cab9fdeSChristos Margiolis }
62*9cab9fdeSChristos Margiolis return (NULL);
63*9cab9fdeSChristos Margiolis }
64*9cab9fdeSChristos Margiolis
65*9cab9fdeSChristos Margiolis static vmonitor_t *
vmonitor_by_index(int index,vmonitor_head_t * phead)66*9cab9fdeSChristos Margiolis vmonitor_by_index(int index, vmonitor_head_t *phead)
67*9cab9fdeSChristos Margiolis {
68*9cab9fdeSChristos Margiolis vmonitor_t *pvm;
69*9cab9fdeSChristos Margiolis
70*9cab9fdeSChristos Margiolis TAILQ_FOREACH(pvm, phead, entry) {
71*9cab9fdeSChristos Margiolis if (!index--)
72*9cab9fdeSChristos Margiolis return (pvm);
73*9cab9fdeSChristos Margiolis }
74*9cab9fdeSChristos Margiolis return (NULL);
75*9cab9fdeSChristos Margiolis }
76*9cab9fdeSChristos Margiolis
77*9cab9fdeSChristos Margiolis static int
vctl_ioctl(struct cuse_dev * pdev __unused,int fflags __unused,unsigned long cmd,void * peer_data)78*9cab9fdeSChristos Margiolis vctl_ioctl(struct cuse_dev *pdev __unused, int fflags __unused,
79*9cab9fdeSChristos Margiolis unsigned long cmd, void *peer_data)
80*9cab9fdeSChristos Margiolis {
81*9cab9fdeSChristos Margiolis union {
82*9cab9fdeSChristos Margiolis int val;
83*9cab9fdeSChristos Margiolis struct virtual_oss_io_info io_info;
84*9cab9fdeSChristos Margiolis struct virtual_oss_mon_info mon_info;
85*9cab9fdeSChristos Margiolis struct virtual_oss_io_peak io_peak;
86*9cab9fdeSChristos Margiolis struct virtual_oss_mon_peak mon_peak;
87*9cab9fdeSChristos Margiolis struct virtual_oss_compressor out_lim;
88*9cab9fdeSChristos Margiolis struct virtual_oss_io_limit io_lim;
89*9cab9fdeSChristos Margiolis struct virtual_oss_master_peak master_peak;
90*9cab9fdeSChristos Margiolis struct virtual_oss_audio_delay_locator ad_locator;
91*9cab9fdeSChristos Margiolis struct virtual_oss_fir_filter fir_filter;
92*9cab9fdeSChristos Margiolis struct virtual_oss_system_info sys_info;
93*9cab9fdeSChristos Margiolis char options[VIRTUAL_OSS_OPTIONS_MAX];
94*9cab9fdeSChristos Margiolis } data;
95*9cab9fdeSChristos Margiolis
96*9cab9fdeSChristos Margiolis vprofile_t *pvp;
97*9cab9fdeSChristos Margiolis vmonitor_t *pvm;
98*9cab9fdeSChristos Margiolis
99*9cab9fdeSChristos Margiolis int chan;
100*9cab9fdeSChristos Margiolis int len;
101*9cab9fdeSChristos Margiolis int error;
102*9cab9fdeSChristos Margiolis
103*9cab9fdeSChristos Margiolis len = IOCPARM_LEN(cmd);
104*9cab9fdeSChristos Margiolis
105*9cab9fdeSChristos Margiolis if (len < 0 || len > (int)sizeof(data))
106*9cab9fdeSChristos Margiolis return (CUSE_ERR_INVALID);
107*9cab9fdeSChristos Margiolis
108*9cab9fdeSChristos Margiolis if (cmd & IOC_IN) {
109*9cab9fdeSChristos Margiolis error = cuse_copy_in(peer_data, &data, len);
110*9cab9fdeSChristos Margiolis if (error)
111*9cab9fdeSChristos Margiolis return (error);
112*9cab9fdeSChristos Margiolis } else {
113*9cab9fdeSChristos Margiolis error = 0;
114*9cab9fdeSChristos Margiolis }
115*9cab9fdeSChristos Margiolis
116*9cab9fdeSChristos Margiolis atomic_lock();
117*9cab9fdeSChristos Margiolis switch (cmd) {
118*9cab9fdeSChristos Margiolis case VIRTUAL_OSS_GET_DEV_INFO:
119*9cab9fdeSChristos Margiolis case VIRTUAL_OSS_SET_DEV_INFO:
120*9cab9fdeSChristos Margiolis case VIRTUAL_OSS_GET_DEV_PEAK:
121*9cab9fdeSChristos Margiolis case VIRTUAL_OSS_SET_DEV_LIMIT:
122*9cab9fdeSChristos Margiolis case VIRTUAL_OSS_GET_DEV_LIMIT:
123*9cab9fdeSChristos Margiolis case VIRTUAL_OSS_SET_RX_DEV_FIR_FILTER:
124*9cab9fdeSChristos Margiolis case VIRTUAL_OSS_GET_RX_DEV_FIR_FILTER:
125*9cab9fdeSChristos Margiolis case VIRTUAL_OSS_SET_TX_DEV_FIR_FILTER:
126*9cab9fdeSChristos Margiolis case VIRTUAL_OSS_GET_TX_DEV_FIR_FILTER:
127*9cab9fdeSChristos Margiolis pvp = vprofile_by_index(&virtual_profile_client_head, data.val);
128*9cab9fdeSChristos Margiolis break;
129*9cab9fdeSChristos Margiolis case VIRTUAL_OSS_GET_LOOP_INFO:
130*9cab9fdeSChristos Margiolis case VIRTUAL_OSS_SET_LOOP_INFO:
131*9cab9fdeSChristos Margiolis case VIRTUAL_OSS_GET_LOOP_PEAK:
132*9cab9fdeSChristos Margiolis case VIRTUAL_OSS_SET_LOOP_LIMIT:
133*9cab9fdeSChristos Margiolis case VIRTUAL_OSS_GET_LOOP_LIMIT:
134*9cab9fdeSChristos Margiolis case VIRTUAL_OSS_SET_RX_LOOP_FIR_FILTER:
135*9cab9fdeSChristos Margiolis case VIRTUAL_OSS_GET_RX_LOOP_FIR_FILTER:
136*9cab9fdeSChristos Margiolis case VIRTUAL_OSS_SET_TX_LOOP_FIR_FILTER:
137*9cab9fdeSChristos Margiolis case VIRTUAL_OSS_GET_TX_LOOP_FIR_FILTER:
138*9cab9fdeSChristos Margiolis pvp = vprofile_by_index(&virtual_profile_loopback_head, data.val);
139*9cab9fdeSChristos Margiolis break;
140*9cab9fdeSChristos Margiolis default:
141*9cab9fdeSChristos Margiolis pvp = NULL;
142*9cab9fdeSChristos Margiolis break;
143*9cab9fdeSChristos Margiolis }
144*9cab9fdeSChristos Margiolis
145*9cab9fdeSChristos Margiolis switch (cmd) {
146*9cab9fdeSChristos Margiolis case VIRTUAL_OSS_GET_VERSION:
147*9cab9fdeSChristos Margiolis data.val = VIRTUAL_OSS_VERSION;
148*9cab9fdeSChristos Margiolis break;
149*9cab9fdeSChristos Margiolis case VIRTUAL_OSS_GET_DEV_INFO:
150*9cab9fdeSChristos Margiolis case VIRTUAL_OSS_GET_LOOP_INFO:
151*9cab9fdeSChristos Margiolis if (pvp == NULL ||
152*9cab9fdeSChristos Margiolis data.io_info.channel < 0 ||
153*9cab9fdeSChristos Margiolis data.io_info.channel >= (int)pvp->channels) {
154*9cab9fdeSChristos Margiolis error = CUSE_ERR_INVALID;
155*9cab9fdeSChristos Margiolis break;
156*9cab9fdeSChristos Margiolis }
157*9cab9fdeSChristos Margiolis strlcpy(data.io_info.name, pvp->oss_name, sizeof(data.io_info.name));
158*9cab9fdeSChristos Margiolis chan = data.io_info.channel;
159*9cab9fdeSChristos Margiolis data.io_info.rx_amp = pvp->rx_shift[chan];
160*9cab9fdeSChristos Margiolis data.io_info.tx_amp = pvp->tx_shift[chan];
161*9cab9fdeSChristos Margiolis data.io_info.rx_chan = pvp->rx_src[chan];
162*9cab9fdeSChristos Margiolis data.io_info.tx_chan = pvp->tx_dst[chan];
163*9cab9fdeSChristos Margiolis data.io_info.rx_mute = pvp->rx_mute[chan] ? 1 : 0;
164*9cab9fdeSChristos Margiolis data.io_info.tx_mute = pvp->tx_mute[chan] ? 1 : 0;
165*9cab9fdeSChristos Margiolis data.io_info.rx_pol = pvp->rx_pol[chan] ? 1 : 0;
166*9cab9fdeSChristos Margiolis data.io_info.tx_pol = pvp->tx_pol[chan] ? 1 : 0;
167*9cab9fdeSChristos Margiolis data.io_info.bits = pvp->bits;
168*9cab9fdeSChristos Margiolis data.io_info.rx_delay = pvp->rec_delay;
169*9cab9fdeSChristos Margiolis data.io_info.rx_delay_limit = voss_dsp_sample_rate;
170*9cab9fdeSChristos Margiolis break;
171*9cab9fdeSChristos Margiolis case VIRTUAL_OSS_SET_DEV_INFO:
172*9cab9fdeSChristos Margiolis case VIRTUAL_OSS_SET_LOOP_INFO:
173*9cab9fdeSChristos Margiolis if (pvp == NULL ||
174*9cab9fdeSChristos Margiolis data.io_info.channel < 0 ||
175*9cab9fdeSChristos Margiolis data.io_info.channel >= (int)pvp->channels ||
176*9cab9fdeSChristos Margiolis data.io_info.rx_amp < -31 || data.io_info.rx_amp > 31 ||
177*9cab9fdeSChristos Margiolis data.io_info.tx_amp < -31 || data.io_info.tx_amp > 31 ||
178*9cab9fdeSChristos Margiolis data.io_info.rx_delay < 0 ||
179*9cab9fdeSChristos Margiolis data.io_info.rx_delay > (int)voss_dsp_sample_rate) {
180*9cab9fdeSChristos Margiolis error = CUSE_ERR_INVALID;
181*9cab9fdeSChristos Margiolis break;
182*9cab9fdeSChristos Margiolis }
183*9cab9fdeSChristos Margiolis chan = data.io_info.channel;
184*9cab9fdeSChristos Margiolis pvp->rx_shift[chan] = data.io_info.rx_amp;
185*9cab9fdeSChristos Margiolis pvp->tx_shift[chan] = data.io_info.tx_amp;
186*9cab9fdeSChristos Margiolis pvp->rx_src[chan] = data.io_info.rx_chan;
187*9cab9fdeSChristos Margiolis pvp->tx_dst[chan] = data.io_info.tx_chan;
188*9cab9fdeSChristos Margiolis pvp->rx_mute[chan] = data.io_info.rx_mute ? 1 : 0;
189*9cab9fdeSChristos Margiolis pvp->tx_mute[chan] = data.io_info.tx_mute ? 1 : 0;
190*9cab9fdeSChristos Margiolis pvp->rx_pol[chan] = data.io_info.rx_pol ? 1 : 0;
191*9cab9fdeSChristos Margiolis pvp->tx_pol[chan] = data.io_info.tx_pol ? 1 : 0;
192*9cab9fdeSChristos Margiolis pvp->rec_delay = data.io_info.rx_delay;
193*9cab9fdeSChristos Margiolis break;
194*9cab9fdeSChristos Margiolis case VIRTUAL_OSS_GET_INPUT_MON_INFO:
195*9cab9fdeSChristos Margiolis pvm = vmonitor_by_index(data.mon_info.number,
196*9cab9fdeSChristos Margiolis &virtual_monitor_input);
197*9cab9fdeSChristos Margiolis if (pvm == NULL) {
198*9cab9fdeSChristos Margiolis error = CUSE_ERR_INVALID;
199*9cab9fdeSChristos Margiolis break;
200*9cab9fdeSChristos Margiolis }
201*9cab9fdeSChristos Margiolis data.mon_info.src_chan = pvm->src_chan;
202*9cab9fdeSChristos Margiolis data.mon_info.dst_chan = pvm->dst_chan;
203*9cab9fdeSChristos Margiolis data.mon_info.pol = pvm->pol;
204*9cab9fdeSChristos Margiolis data.mon_info.mute = pvm->mute;
205*9cab9fdeSChristos Margiolis data.mon_info.amp = pvm->shift;
206*9cab9fdeSChristos Margiolis data.mon_info.bits = voss_dsp_bits;
207*9cab9fdeSChristos Margiolis break;
208*9cab9fdeSChristos Margiolis case VIRTUAL_OSS_SET_INPUT_MON_INFO:
209*9cab9fdeSChristos Margiolis pvm = vmonitor_by_index(data.mon_info.number,
210*9cab9fdeSChristos Margiolis &virtual_monitor_input);
211*9cab9fdeSChristos Margiolis if (pvm == NULL ||
212*9cab9fdeSChristos Margiolis data.mon_info.amp < -31 ||
213*9cab9fdeSChristos Margiolis data.mon_info.amp > 31) {
214*9cab9fdeSChristos Margiolis error = CUSE_ERR_INVALID;
215*9cab9fdeSChristos Margiolis break;
216*9cab9fdeSChristos Margiolis }
217*9cab9fdeSChristos Margiolis pvm->src_chan = data.mon_info.src_chan;
218*9cab9fdeSChristos Margiolis pvm->dst_chan = data.mon_info.dst_chan;
219*9cab9fdeSChristos Margiolis pvm->pol = data.mon_info.pol ? 1 : 0;
220*9cab9fdeSChristos Margiolis pvm->mute = data.mon_info.mute ? 1 : 0;
221*9cab9fdeSChristos Margiolis pvm->shift = data.mon_info.amp;
222*9cab9fdeSChristos Margiolis break;
223*9cab9fdeSChristos Margiolis case VIRTUAL_OSS_GET_OUTPUT_MON_INFO:
224*9cab9fdeSChristos Margiolis pvm = vmonitor_by_index(data.mon_info.number,
225*9cab9fdeSChristos Margiolis &virtual_monitor_output);
226*9cab9fdeSChristos Margiolis if (pvm == NULL) {
227*9cab9fdeSChristos Margiolis error = CUSE_ERR_INVALID;
228*9cab9fdeSChristos Margiolis break;
229*9cab9fdeSChristos Margiolis }
230*9cab9fdeSChristos Margiolis data.mon_info.src_chan = pvm->src_chan;
231*9cab9fdeSChristos Margiolis data.mon_info.dst_chan = pvm->dst_chan;
232*9cab9fdeSChristos Margiolis data.mon_info.pol = pvm->pol;
233*9cab9fdeSChristos Margiolis data.mon_info.mute = pvm->mute;
234*9cab9fdeSChristos Margiolis data.mon_info.amp = pvm->shift;
235*9cab9fdeSChristos Margiolis data.mon_info.bits = voss_dsp_bits;
236*9cab9fdeSChristos Margiolis break;
237*9cab9fdeSChristos Margiolis case VIRTUAL_OSS_SET_OUTPUT_MON_INFO:
238*9cab9fdeSChristos Margiolis pvm = vmonitor_by_index(data.mon_info.number,
239*9cab9fdeSChristos Margiolis &virtual_monitor_output);
240*9cab9fdeSChristos Margiolis if (pvm == NULL ||
241*9cab9fdeSChristos Margiolis data.mon_info.amp < -31 ||
242*9cab9fdeSChristos Margiolis data.mon_info.amp > 31) {
243*9cab9fdeSChristos Margiolis error = CUSE_ERR_INVALID;
244*9cab9fdeSChristos Margiolis break;
245*9cab9fdeSChristos Margiolis }
246*9cab9fdeSChristos Margiolis pvm->src_chan = data.mon_info.src_chan;
247*9cab9fdeSChristos Margiolis pvm->dst_chan = data.mon_info.dst_chan;
248*9cab9fdeSChristos Margiolis pvm->pol = data.mon_info.pol ? 1 : 0;
249*9cab9fdeSChristos Margiolis pvm->mute = data.mon_info.mute ? 1 : 0;
250*9cab9fdeSChristos Margiolis pvm->shift = data.mon_info.amp;
251*9cab9fdeSChristos Margiolis break;
252*9cab9fdeSChristos Margiolis case VIRTUAL_OSS_GET_LOCAL_MON_INFO:
253*9cab9fdeSChristos Margiolis pvm = vmonitor_by_index(data.mon_info.number,
254*9cab9fdeSChristos Margiolis &virtual_monitor_local);
255*9cab9fdeSChristos Margiolis if (pvm == NULL) {
256*9cab9fdeSChristos Margiolis error = CUSE_ERR_INVALID;
257*9cab9fdeSChristos Margiolis break;
258*9cab9fdeSChristos Margiolis }
259*9cab9fdeSChristos Margiolis data.mon_info.src_chan = pvm->src_chan;
260*9cab9fdeSChristos Margiolis data.mon_info.dst_chan = pvm->dst_chan;
261*9cab9fdeSChristos Margiolis data.mon_info.pol = pvm->pol;
262*9cab9fdeSChristos Margiolis data.mon_info.mute = pvm->mute;
263*9cab9fdeSChristos Margiolis data.mon_info.amp = pvm->shift;
264*9cab9fdeSChristos Margiolis data.mon_info.bits = voss_dsp_bits;
265*9cab9fdeSChristos Margiolis break;
266*9cab9fdeSChristos Margiolis case VIRTUAL_OSS_SET_LOCAL_MON_INFO:
267*9cab9fdeSChristos Margiolis pvm = vmonitor_by_index(data.mon_info.number,
268*9cab9fdeSChristos Margiolis &virtual_monitor_local);
269*9cab9fdeSChristos Margiolis if (pvm == NULL ||
270*9cab9fdeSChristos Margiolis data.mon_info.amp < -31 ||
271*9cab9fdeSChristos Margiolis data.mon_info.amp > 31) {
272*9cab9fdeSChristos Margiolis error = CUSE_ERR_INVALID;
273*9cab9fdeSChristos Margiolis break;
274*9cab9fdeSChristos Margiolis }
275*9cab9fdeSChristos Margiolis pvm->src_chan = data.mon_info.src_chan;
276*9cab9fdeSChristos Margiolis pvm->dst_chan = data.mon_info.dst_chan;
277*9cab9fdeSChristos Margiolis pvm->pol = data.mon_info.pol ? 1 : 0;
278*9cab9fdeSChristos Margiolis pvm->mute = data.mon_info.mute ? 1 : 0;
279*9cab9fdeSChristos Margiolis pvm->shift = data.mon_info.amp;
280*9cab9fdeSChristos Margiolis break;
281*9cab9fdeSChristos Margiolis case VIRTUAL_OSS_GET_DEV_PEAK:
282*9cab9fdeSChristos Margiolis case VIRTUAL_OSS_GET_LOOP_PEAK:
283*9cab9fdeSChristos Margiolis if (pvp == NULL ||
284*9cab9fdeSChristos Margiolis data.io_peak.channel < 0 ||
285*9cab9fdeSChristos Margiolis data.io_peak.channel >= (int)pvp->channels) {
286*9cab9fdeSChristos Margiolis error = CUSE_ERR_INVALID;
287*9cab9fdeSChristos Margiolis break;
288*9cab9fdeSChristos Margiolis }
289*9cab9fdeSChristos Margiolis strlcpy(data.io_peak.name, pvp->oss_name, sizeof(data.io_peak.name));
290*9cab9fdeSChristos Margiolis chan = data.io_peak.channel;
291*9cab9fdeSChristos Margiolis data.io_peak.rx_peak_value = pvp->rx_peak_value[chan];
292*9cab9fdeSChristos Margiolis pvp->rx_peak_value[chan] = 0;
293*9cab9fdeSChristos Margiolis data.io_peak.tx_peak_value = pvp->tx_peak_value[chan];
294*9cab9fdeSChristos Margiolis pvp->tx_peak_value[chan] = 0;
295*9cab9fdeSChristos Margiolis data.io_peak.bits = pvp->bits;
296*9cab9fdeSChristos Margiolis break;
297*9cab9fdeSChristos Margiolis case VIRTUAL_OSS_GET_INPUT_MON_PEAK:
298*9cab9fdeSChristos Margiolis pvm = vmonitor_by_index(data.mon_peak.number,
299*9cab9fdeSChristos Margiolis &virtual_monitor_input);
300*9cab9fdeSChristos Margiolis if (pvm == NULL) {
301*9cab9fdeSChristos Margiolis error = CUSE_ERR_INVALID;
302*9cab9fdeSChristos Margiolis break;
303*9cab9fdeSChristos Margiolis }
304*9cab9fdeSChristos Margiolis data.mon_peak.peak_value = pvm->peak_value;
305*9cab9fdeSChristos Margiolis data.mon_peak.bits = voss_dsp_bits;
306*9cab9fdeSChristos Margiolis pvm->peak_value = 0;
307*9cab9fdeSChristos Margiolis break;
308*9cab9fdeSChristos Margiolis case VIRTUAL_OSS_GET_OUTPUT_MON_PEAK:
309*9cab9fdeSChristos Margiolis pvm = vmonitor_by_index(data.mon_peak.number,
310*9cab9fdeSChristos Margiolis &virtual_monitor_output);
311*9cab9fdeSChristos Margiolis if (pvm == NULL) {
312*9cab9fdeSChristos Margiolis error = CUSE_ERR_INVALID;
313*9cab9fdeSChristos Margiolis break;
314*9cab9fdeSChristos Margiolis }
315*9cab9fdeSChristos Margiolis data.mon_peak.peak_value = pvm->peak_value;
316*9cab9fdeSChristos Margiolis data.mon_peak.bits = voss_dsp_bits;
317*9cab9fdeSChristos Margiolis pvm->peak_value = 0;
318*9cab9fdeSChristos Margiolis break;
319*9cab9fdeSChristos Margiolis case VIRTUAL_OSS_GET_LOCAL_MON_PEAK:
320*9cab9fdeSChristos Margiolis pvm = vmonitor_by_index(data.mon_peak.number,
321*9cab9fdeSChristos Margiolis &virtual_monitor_local);
322*9cab9fdeSChristos Margiolis if (pvm == NULL) {
323*9cab9fdeSChristos Margiolis error = CUSE_ERR_INVALID;
324*9cab9fdeSChristos Margiolis break;
325*9cab9fdeSChristos Margiolis }
326*9cab9fdeSChristos Margiolis data.mon_peak.peak_value = pvm->peak_value;
327*9cab9fdeSChristos Margiolis data.mon_peak.bits = voss_dsp_bits;
328*9cab9fdeSChristos Margiolis pvm->peak_value = 0;
329*9cab9fdeSChristos Margiolis break;
330*9cab9fdeSChristos Margiolis case VIRTUAL_OSS_ADD_INPUT_MON:
331*9cab9fdeSChristos Margiolis pvm = vmonitor_alloc(&data.val,
332*9cab9fdeSChristos Margiolis &virtual_monitor_input);
333*9cab9fdeSChristos Margiolis if (pvm == NULL)
334*9cab9fdeSChristos Margiolis error = CUSE_ERR_INVALID;
335*9cab9fdeSChristos Margiolis break;
336*9cab9fdeSChristos Margiolis case VIRTUAL_OSS_ADD_OUTPUT_MON:
337*9cab9fdeSChristos Margiolis pvm = vmonitor_alloc(&data.val,
338*9cab9fdeSChristos Margiolis &virtual_monitor_output);
339*9cab9fdeSChristos Margiolis if (pvm == NULL)
340*9cab9fdeSChristos Margiolis error = CUSE_ERR_INVALID;
341*9cab9fdeSChristos Margiolis break;
342*9cab9fdeSChristos Margiolis case VIRTUAL_OSS_ADD_LOCAL_MON:
343*9cab9fdeSChristos Margiolis pvm = vmonitor_alloc(&data.val,
344*9cab9fdeSChristos Margiolis &virtual_monitor_local);
345*9cab9fdeSChristos Margiolis if (pvm == NULL)
346*9cab9fdeSChristos Margiolis error = CUSE_ERR_INVALID;
347*9cab9fdeSChristos Margiolis break;
348*9cab9fdeSChristos Margiolis case VIRTUAL_OSS_SET_OUTPUT_LIMIT:
349*9cab9fdeSChristos Margiolis if (data.out_lim.enabled < 0 ||
350*9cab9fdeSChristos Margiolis data.out_lim.enabled > 1 ||
351*9cab9fdeSChristos Margiolis data.out_lim.knee < VIRTUAL_OSS_KNEE_MIN ||
352*9cab9fdeSChristos Margiolis data.out_lim.knee > VIRTUAL_OSS_KNEE_MAX ||
353*9cab9fdeSChristos Margiolis data.out_lim.attack < VIRTUAL_OSS_ATTACK_MIN ||
354*9cab9fdeSChristos Margiolis data.out_lim.attack > VIRTUAL_OSS_ATTACK_MAX ||
355*9cab9fdeSChristos Margiolis data.out_lim.decay < VIRTUAL_OSS_DECAY_MIN ||
356*9cab9fdeSChristos Margiolis data.out_lim.decay > VIRTUAL_OSS_DECAY_MAX ||
357*9cab9fdeSChristos Margiolis data.out_lim.gain != 0) {
358*9cab9fdeSChristos Margiolis error = CUSE_ERR_INVALID;
359*9cab9fdeSChristos Margiolis break;
360*9cab9fdeSChristos Margiolis }
361*9cab9fdeSChristos Margiolis voss_output_compressor_param.enabled = data.out_lim.enabled;
362*9cab9fdeSChristos Margiolis voss_output_compressor_param.knee = data.out_lim.knee;
363*9cab9fdeSChristos Margiolis voss_output_compressor_param.attack = data.out_lim.attack;
364*9cab9fdeSChristos Margiolis voss_output_compressor_param.decay = data.out_lim.decay;
365*9cab9fdeSChristos Margiolis break;
366*9cab9fdeSChristos Margiolis case VIRTUAL_OSS_GET_OUTPUT_LIMIT:
367*9cab9fdeSChristos Margiolis data.out_lim.enabled = voss_output_compressor_param.enabled;
368*9cab9fdeSChristos Margiolis data.out_lim.knee = voss_output_compressor_param.knee;
369*9cab9fdeSChristos Margiolis data.out_lim.attack = voss_output_compressor_param.attack;
370*9cab9fdeSChristos Margiolis data.out_lim.decay = voss_output_compressor_param.decay;
371*9cab9fdeSChristos Margiolis data.out_lim.gain = 1000;
372*9cab9fdeSChristos Margiolis for (chan = 0; chan != VMAX_CHAN; chan++) {
373*9cab9fdeSChristos Margiolis int gain = voss_output_compressor_gain[chan] * 1000.0;
374*9cab9fdeSChristos Margiolis if (data.out_lim.gain > gain)
375*9cab9fdeSChristos Margiolis data.out_lim.gain = gain;
376*9cab9fdeSChristos Margiolis }
377*9cab9fdeSChristos Margiolis break;
378*9cab9fdeSChristos Margiolis case VIRTUAL_OSS_SET_DEV_LIMIT:
379*9cab9fdeSChristos Margiolis case VIRTUAL_OSS_SET_LOOP_LIMIT:
380*9cab9fdeSChristos Margiolis if (pvp == NULL ||
381*9cab9fdeSChristos Margiolis data.io_lim.param.enabled < 0 ||
382*9cab9fdeSChristos Margiolis data.io_lim.param.enabled > 1 ||
383*9cab9fdeSChristos Margiolis data.io_lim.param.knee < VIRTUAL_OSS_KNEE_MIN ||
384*9cab9fdeSChristos Margiolis data.io_lim.param.knee > VIRTUAL_OSS_KNEE_MAX ||
385*9cab9fdeSChristos Margiolis data.io_lim.param.attack < VIRTUAL_OSS_ATTACK_MIN ||
386*9cab9fdeSChristos Margiolis data.io_lim.param.attack > VIRTUAL_OSS_ATTACK_MAX ||
387*9cab9fdeSChristos Margiolis data.io_lim.param.decay < VIRTUAL_OSS_DECAY_MIN ||
388*9cab9fdeSChristos Margiolis data.io_lim.param.decay > VIRTUAL_OSS_DECAY_MAX ||
389*9cab9fdeSChristos Margiolis data.io_lim.param.gain != 0) {
390*9cab9fdeSChristos Margiolis error = CUSE_ERR_INVALID;
391*9cab9fdeSChristos Margiolis break;
392*9cab9fdeSChristos Margiolis }
393*9cab9fdeSChristos Margiolis pvp->rx_compressor_param.enabled = data.io_lim.param.enabled;
394*9cab9fdeSChristos Margiolis pvp->rx_compressor_param.knee = data.io_lim.param.knee;
395*9cab9fdeSChristos Margiolis pvp->rx_compressor_param.attack = data.io_lim.param.attack;
396*9cab9fdeSChristos Margiolis pvp->rx_compressor_param.decay = data.io_lim.param.decay;
397*9cab9fdeSChristos Margiolis break;
398*9cab9fdeSChristos Margiolis case VIRTUAL_OSS_GET_DEV_LIMIT:
399*9cab9fdeSChristos Margiolis case VIRTUAL_OSS_GET_LOOP_LIMIT:
400*9cab9fdeSChristos Margiolis if (pvp == NULL) {
401*9cab9fdeSChristos Margiolis error = CUSE_ERR_INVALID;
402*9cab9fdeSChristos Margiolis break;
403*9cab9fdeSChristos Margiolis }
404*9cab9fdeSChristos Margiolis data.io_lim.param.enabled = pvp->rx_compressor_param.enabled;
405*9cab9fdeSChristos Margiolis data.io_lim.param.knee = pvp->rx_compressor_param.knee;
406*9cab9fdeSChristos Margiolis data.io_lim.param.attack = pvp->rx_compressor_param.attack;
407*9cab9fdeSChristos Margiolis data.io_lim.param.decay = pvp->rx_compressor_param.decay;
408*9cab9fdeSChristos Margiolis data.io_lim.param.gain = 1000;
409*9cab9fdeSChristos Margiolis
410*9cab9fdeSChristos Margiolis for (chan = 0; chan != VMAX_CHAN; chan++) {
411*9cab9fdeSChristos Margiolis int gain = pvp->rx_compressor_gain[chan] * 1000.0;
412*9cab9fdeSChristos Margiolis if (data.io_lim.param.gain > gain)
413*9cab9fdeSChristos Margiolis data.io_lim.param.gain = gain;
414*9cab9fdeSChristos Margiolis }
415*9cab9fdeSChristos Margiolis break;
416*9cab9fdeSChristos Margiolis case VIRTUAL_OSS_GET_OUTPUT_PEAK:
417*9cab9fdeSChristos Margiolis chan = data.master_peak.channel;
418*9cab9fdeSChristos Margiolis if (chan < 0 ||
419*9cab9fdeSChristos Margiolis chan >= (int)voss_max_channels) {
420*9cab9fdeSChristos Margiolis error = CUSE_ERR_INVALID;
421*9cab9fdeSChristos Margiolis break;
422*9cab9fdeSChristos Margiolis }
423*9cab9fdeSChristos Margiolis data.master_peak.bits = voss_dsp_bits;
424*9cab9fdeSChristos Margiolis data.master_peak.peak_value = voss_output_peak[chan];
425*9cab9fdeSChristos Margiolis voss_output_peak[chan] = 0;
426*9cab9fdeSChristos Margiolis break;
427*9cab9fdeSChristos Margiolis case VIRTUAL_OSS_GET_INPUT_PEAK:
428*9cab9fdeSChristos Margiolis chan = data.master_peak.channel;
429*9cab9fdeSChristos Margiolis if (chan < 0 ||
430*9cab9fdeSChristos Margiolis chan >= (int)voss_dsp_max_channels) {
431*9cab9fdeSChristos Margiolis error = CUSE_ERR_INVALID;
432*9cab9fdeSChristos Margiolis break;
433*9cab9fdeSChristos Margiolis }
434*9cab9fdeSChristos Margiolis data.master_peak.bits = voss_dsp_bits;
435*9cab9fdeSChristos Margiolis data.master_peak.peak_value = voss_input_peak[chan];
436*9cab9fdeSChristos Margiolis voss_input_peak[chan] = 0;
437*9cab9fdeSChristos Margiolis break;
438*9cab9fdeSChristos Margiolis
439*9cab9fdeSChristos Margiolis case VIRTUAL_OSS_SET_RECORDING:
440*9cab9fdeSChristos Margiolis voss_is_recording = data.val ? 1 : 0;
441*9cab9fdeSChristos Margiolis break;
442*9cab9fdeSChristos Margiolis
443*9cab9fdeSChristos Margiolis case VIRTUAL_OSS_GET_RECORDING:
444*9cab9fdeSChristos Margiolis data.val = voss_is_recording;
445*9cab9fdeSChristos Margiolis break;
446*9cab9fdeSChristos Margiolis
447*9cab9fdeSChristos Margiolis case VIRTUAL_OSS_SET_AUDIO_DELAY_LOCATOR:
448*9cab9fdeSChristos Margiolis if (data.ad_locator.channel_output < 0 ||
449*9cab9fdeSChristos Margiolis data.ad_locator.channel_output >= (int)voss_mix_channels) {
450*9cab9fdeSChristos Margiolis error = CUSE_ERR_INVALID;
451*9cab9fdeSChristos Margiolis break;
452*9cab9fdeSChristos Margiolis }
453*9cab9fdeSChristos Margiolis if (data.ad_locator.channel_input < 0 ||
454*9cab9fdeSChristos Margiolis data.ad_locator.channel_input >= (int)voss_mix_channels) {
455*9cab9fdeSChristos Margiolis error = CUSE_ERR_INVALID;
456*9cab9fdeSChristos Margiolis break;
457*9cab9fdeSChristos Margiolis }
458*9cab9fdeSChristos Margiolis if (data.ad_locator.signal_output_level < 0 ||
459*9cab9fdeSChristos Margiolis data.ad_locator.signal_output_level >= 64) {
460*9cab9fdeSChristos Margiolis error = CUSE_ERR_INVALID;
461*9cab9fdeSChristos Margiolis break;
462*9cab9fdeSChristos Margiolis }
463*9cab9fdeSChristos Margiolis voss_ad_enabled = (data.ad_locator.locator_enabled != 0);
464*9cab9fdeSChristos Margiolis voss_ad_output_signal = data.ad_locator.signal_output_level;
465*9cab9fdeSChristos Margiolis voss_ad_output_channel = data.ad_locator.channel_output;
466*9cab9fdeSChristos Margiolis voss_ad_input_channel = data.ad_locator.channel_input;
467*9cab9fdeSChristos Margiolis break;
468*9cab9fdeSChristos Margiolis
469*9cab9fdeSChristos Margiolis case VIRTUAL_OSS_GET_AUDIO_DELAY_LOCATOR:
470*9cab9fdeSChristos Margiolis data.ad_locator.locator_enabled = voss_ad_enabled;
471*9cab9fdeSChristos Margiolis data.ad_locator.signal_output_level = voss_ad_output_signal;
472*9cab9fdeSChristos Margiolis data.ad_locator.channel_output = voss_ad_output_channel;
473*9cab9fdeSChristos Margiolis data.ad_locator.channel_input = voss_ad_input_channel;
474*9cab9fdeSChristos Margiolis data.ad_locator.channel_last = voss_mix_channels - 1;
475*9cab9fdeSChristos Margiolis data.ad_locator.signal_input_delay = voss_ad_last_delay;
476*9cab9fdeSChristos Margiolis data.ad_locator.signal_delay_hz = voss_dsp_sample_rate;
477*9cab9fdeSChristos Margiolis break;
478*9cab9fdeSChristos Margiolis
479*9cab9fdeSChristos Margiolis case VIRTUAL_OSS_RST_AUDIO_DELAY_LOCATOR:
480*9cab9fdeSChristos Margiolis voss_ad_reset();
481*9cab9fdeSChristos Margiolis break;
482*9cab9fdeSChristos Margiolis
483*9cab9fdeSChristos Margiolis case VIRTUAL_OSS_ADD_OPTIONS:
484*9cab9fdeSChristos Margiolis data.options[VIRTUAL_OSS_OPTIONS_MAX - 1] = 0;
485*9cab9fdeSChristos Margiolis voss_add_options(data.options);
486*9cab9fdeSChristos Margiolis break;
487*9cab9fdeSChristos Margiolis
488*9cab9fdeSChristos Margiolis case VIRTUAL_OSS_GET_RX_DEV_FIR_FILTER:
489*9cab9fdeSChristos Margiolis case VIRTUAL_OSS_GET_RX_LOOP_FIR_FILTER:
490*9cab9fdeSChristos Margiolis if (pvp == NULL ||
491*9cab9fdeSChristos Margiolis data.fir_filter.channel < 0 ||
492*9cab9fdeSChristos Margiolis data.fir_filter.channel >= (int)pvp->channels) {
493*9cab9fdeSChristos Margiolis error = CUSE_ERR_INVALID;
494*9cab9fdeSChristos Margiolis } else if (data.fir_filter.filter_data == NULL) {
495*9cab9fdeSChristos Margiolis data.fir_filter.filter_size = pvp->rx_filter_size;
496*9cab9fdeSChristos Margiolis } else if (data.fir_filter.filter_size != (int)pvp->rx_filter_size) {
497*9cab9fdeSChristos Margiolis error = CUSE_ERR_INVALID;
498*9cab9fdeSChristos Margiolis } else if (pvp->rx_filter_data[data.fir_filter.channel] == NULL) {
499*9cab9fdeSChristos Margiolis error = CUSE_ERR_NO_MEMORY; /* filter disabled */
500*9cab9fdeSChristos Margiolis } else {
501*9cab9fdeSChristos Margiolis error = cuse_copy_out(pvp->rx_filter_data[data.fir_filter.channel],
502*9cab9fdeSChristos Margiolis data.fir_filter.filter_data,
503*9cab9fdeSChristos Margiolis sizeof(pvp->rx_filter_data[0][0]) *
504*9cab9fdeSChristos Margiolis data.fir_filter.filter_size);
505*9cab9fdeSChristos Margiolis }
506*9cab9fdeSChristos Margiolis break;
507*9cab9fdeSChristos Margiolis
508*9cab9fdeSChristos Margiolis case VIRTUAL_OSS_GET_TX_DEV_FIR_FILTER:
509*9cab9fdeSChristos Margiolis case VIRTUAL_OSS_GET_TX_LOOP_FIR_FILTER:
510*9cab9fdeSChristos Margiolis if (pvp == NULL ||
511*9cab9fdeSChristos Margiolis data.fir_filter.channel < 0 ||
512*9cab9fdeSChristos Margiolis data.fir_filter.channel >= (int)pvp->channels) {
513*9cab9fdeSChristos Margiolis error = CUSE_ERR_INVALID;
514*9cab9fdeSChristos Margiolis } else if (data.fir_filter.filter_data == NULL) {
515*9cab9fdeSChristos Margiolis data.fir_filter.filter_size = pvp->tx_filter_size;
516*9cab9fdeSChristos Margiolis } else if (data.fir_filter.filter_size != (int)pvp->tx_filter_size) {
517*9cab9fdeSChristos Margiolis error = CUSE_ERR_INVALID;
518*9cab9fdeSChristos Margiolis } else if (pvp->tx_filter_data[data.fir_filter.channel] == NULL) {
519*9cab9fdeSChristos Margiolis error = CUSE_ERR_NO_MEMORY; /* filter disabled */
520*9cab9fdeSChristos Margiolis } else {
521*9cab9fdeSChristos Margiolis error = cuse_copy_out(pvp->tx_filter_data[data.fir_filter.channel],
522*9cab9fdeSChristos Margiolis data.fir_filter.filter_data,
523*9cab9fdeSChristos Margiolis sizeof(pvp->tx_filter_data[0][0]) *
524*9cab9fdeSChristos Margiolis data.fir_filter.filter_size);
525*9cab9fdeSChristos Margiolis }
526*9cab9fdeSChristos Margiolis break;
527*9cab9fdeSChristos Margiolis
528*9cab9fdeSChristos Margiolis case VIRTUAL_OSS_SET_RX_DEV_FIR_FILTER:
529*9cab9fdeSChristos Margiolis case VIRTUAL_OSS_SET_RX_LOOP_FIR_FILTER:
530*9cab9fdeSChristos Margiolis if (pvp == NULL ||
531*9cab9fdeSChristos Margiolis data.fir_filter.channel < 0 ||
532*9cab9fdeSChristos Margiolis data.fir_filter.channel >= (int)pvp->channels) {
533*9cab9fdeSChristos Margiolis error = CUSE_ERR_INVALID;
534*9cab9fdeSChristos Margiolis } else if (data.fir_filter.filter_data == NULL) {
535*9cab9fdeSChristos Margiolis free(pvp->rx_filter_data[data.fir_filter.channel]);
536*9cab9fdeSChristos Margiolis pvp->rx_filter_data[data.fir_filter.channel] = NULL; /* disable filter */
537*9cab9fdeSChristos Margiolis } else if (data.fir_filter.filter_size != (int)pvp->rx_filter_size) {
538*9cab9fdeSChristos Margiolis error = CUSE_ERR_INVALID;
539*9cab9fdeSChristos Margiolis } else if (pvp->rx_filter_size != 0) {
540*9cab9fdeSChristos Margiolis size_t size = sizeof(pvp->rx_filter_data[0][0]) * pvp->rx_filter_size;
541*9cab9fdeSChristos Margiolis if (pvp->rx_filter_data[data.fir_filter.channel] == NULL) {
542*9cab9fdeSChristos Margiolis pvp->rx_filter_data[data.fir_filter.channel] = malloc(size);
543*9cab9fdeSChristos Margiolis if (pvp->rx_filter_data[data.fir_filter.channel] == NULL)
544*9cab9fdeSChristos Margiolis error = CUSE_ERR_NO_MEMORY;
545*9cab9fdeSChristos Margiolis else
546*9cab9fdeSChristos Margiolis memset(pvp->rx_filter_data[data.fir_filter.channel], 0, size);
547*9cab9fdeSChristos Margiolis }
548*9cab9fdeSChristos Margiolis if (pvp->rx_filter_data[data.fir_filter.channel] != NULL) {
549*9cab9fdeSChristos Margiolis error = cuse_copy_in(data.fir_filter.filter_data,
550*9cab9fdeSChristos Margiolis pvp->rx_filter_data[data.fir_filter.channel], size);
551*9cab9fdeSChristos Margiolis }
552*9cab9fdeSChristos Margiolis }
553*9cab9fdeSChristos Margiolis break;
554*9cab9fdeSChristos Margiolis
555*9cab9fdeSChristos Margiolis case VIRTUAL_OSS_SET_TX_DEV_FIR_FILTER:
556*9cab9fdeSChristos Margiolis case VIRTUAL_OSS_SET_TX_LOOP_FIR_FILTER:
557*9cab9fdeSChristos Margiolis if (pvp == NULL ||
558*9cab9fdeSChristos Margiolis data.fir_filter.channel < 0 ||
559*9cab9fdeSChristos Margiolis data.fir_filter.channel >= (int)pvp->channels) {
560*9cab9fdeSChristos Margiolis error = CUSE_ERR_INVALID;
561*9cab9fdeSChristos Margiolis } else if (data.fir_filter.filter_data == NULL) {
562*9cab9fdeSChristos Margiolis free(pvp->tx_filter_data[data.fir_filter.channel]);
563*9cab9fdeSChristos Margiolis pvp->tx_filter_data[data.fir_filter.channel] = NULL; /* disable filter */
564*9cab9fdeSChristos Margiolis } else if (data.fir_filter.filter_size != (int)pvp->tx_filter_size) {
565*9cab9fdeSChristos Margiolis error = CUSE_ERR_INVALID;
566*9cab9fdeSChristos Margiolis } else if (pvp->tx_filter_size != 0) {
567*9cab9fdeSChristos Margiolis size_t size = sizeof(pvp->tx_filter_data[0][0]) * pvp->tx_filter_size;
568*9cab9fdeSChristos Margiolis if (pvp->tx_filter_data[data.fir_filter.channel] == NULL) {
569*9cab9fdeSChristos Margiolis pvp->tx_filter_data[data.fir_filter.channel] = malloc(size);
570*9cab9fdeSChristos Margiolis if (pvp->tx_filter_data[data.fir_filter.channel] == NULL)
571*9cab9fdeSChristos Margiolis error = CUSE_ERR_NO_MEMORY;
572*9cab9fdeSChristos Margiolis else
573*9cab9fdeSChristos Margiolis memset(pvp->tx_filter_data[data.fir_filter.channel], 0, size);
574*9cab9fdeSChristos Margiolis }
575*9cab9fdeSChristos Margiolis if (pvp->tx_filter_data[data.fir_filter.channel] != NULL) {
576*9cab9fdeSChristos Margiolis error = cuse_copy_in(data.fir_filter.filter_data,
577*9cab9fdeSChristos Margiolis pvp->tx_filter_data[data.fir_filter.channel], size);
578*9cab9fdeSChristos Margiolis }
579*9cab9fdeSChristos Margiolis }
580*9cab9fdeSChristos Margiolis break;
581*9cab9fdeSChristos Margiolis
582*9cab9fdeSChristos Margiolis case VIRTUAL_OSS_GET_SAMPLE_RATE:
583*9cab9fdeSChristos Margiolis data.val = voss_dsp_sample_rate;
584*9cab9fdeSChristos Margiolis break;
585*9cab9fdeSChristos Margiolis
586*9cab9fdeSChristos Margiolis case VIRTUAL_OSS_GET_SYSTEM_INFO:
587*9cab9fdeSChristos Margiolis data.sys_info.tx_jitter_up = voss_jitter_up;
588*9cab9fdeSChristos Margiolis data.sys_info.tx_jitter_down = voss_jitter_down;
589*9cab9fdeSChristos Margiolis data.sys_info.sample_rate = voss_dsp_sample_rate;
590*9cab9fdeSChristos Margiolis data.sys_info.sample_bits = voss_dsp_bits;
591*9cab9fdeSChristos Margiolis data.sys_info.sample_channels = voss_mix_channels;
592*9cab9fdeSChristos Margiolis strlcpy(data.sys_info.rx_device_name, voss_dsp_rx_device,
593*9cab9fdeSChristos Margiolis sizeof(data.sys_info.rx_device_name));
594*9cab9fdeSChristos Margiolis strlcpy(data.sys_info.tx_device_name, voss_dsp_tx_device,
595*9cab9fdeSChristos Margiolis sizeof(data.sys_info.tx_device_name));
596*9cab9fdeSChristos Margiolis break;
597*9cab9fdeSChristos Margiolis
598*9cab9fdeSChristos Margiolis default:
599*9cab9fdeSChristos Margiolis error = CUSE_ERR_INVALID;
600*9cab9fdeSChristos Margiolis break;
601*9cab9fdeSChristos Margiolis }
602*9cab9fdeSChristos Margiolis atomic_unlock();
603*9cab9fdeSChristos Margiolis
604*9cab9fdeSChristos Margiolis if (error == 0) {
605*9cab9fdeSChristos Margiolis if (cmd & IOC_OUT)
606*9cab9fdeSChristos Margiolis error = cuse_copy_out(&data, peer_data, len);
607*9cab9fdeSChristos Margiolis }
608*9cab9fdeSChristos Margiolis return (error);
609*9cab9fdeSChristos Margiolis }
610*9cab9fdeSChristos Margiolis
611*9cab9fdeSChristos Margiolis const struct cuse_methods vctl_methods = {
612*9cab9fdeSChristos Margiolis .cm_open = vctl_open,
613*9cab9fdeSChristos Margiolis .cm_close = vctl_close,
614*9cab9fdeSChristos Margiolis .cm_ioctl = vctl_ioctl,
615*9cab9fdeSChristos Margiolis };
616