Commit | Line | Data |
---|---|---|
fffa1cca VK |
1 | /* |
2 | * intel_sst_stream.c - Intel SST Driver for audio engine | |
3 | * | |
4 | * Copyright (C) 2008-10 Intel Corp | |
5 | * Authors: Vinod Koul <vinod.koul@intel.com> | |
6 | * Harsha Priya <priya.harsha@intel.com> | |
7 | * Dharageswari R <dharageswari.r@intel.com> | |
8 | * KP Jeeja <jeeja.kp@intel.com> | |
9 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | |
10 | * | |
11 | * This program is free software; you can redistribute it and/or modify | |
12 | * it under the terms of the GNU General Public License as published by | |
13 | * the Free Software Foundation; version 2 of the License. | |
14 | * | |
15 | * This program is distributed in the hope that it will be useful, but | |
16 | * WITHOUT ANY WARRANTY; without even the implied warranty of | |
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
18 | * General Public License for more details. | |
19 | * | |
20 | * You should have received a copy of the GNU General Public License along | |
21 | * with this program; if not, write to the Free Software Foundation, Inc., | |
22 | * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. | |
23 | * | |
24 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | |
25 | * | |
26 | * This file contains the stream operations of SST driver | |
27 | */ | |
28 | ||
d0f40c50 JP |
29 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
30 | ||
fffa1cca VK |
31 | #include <linux/pci.h> |
32 | #include <linux/syscalls.h> | |
33 | #include <linux/firmware.h> | |
34 | #include <linux/sched.h> | |
fffa1cca | 35 | #ifdef CONFIG_MRST_RAR_HANDLER |
6f6ffec1 VK |
36 | #include <linux/rar_register.h> |
37 | #include "../memrar/memrar.h" | |
fffa1cca VK |
38 | #endif |
39 | #include "intel_sst_ioctl.h" | |
40 | #include "intel_sst.h" | |
41 | #include "intel_sst_fw_ipc.h" | |
42 | #include "intel_sst_common.h" | |
43 | /** | |
44 | * sst_get_stream_params - Send msg to query for stream parameters | |
45 | * @str_id: stream id for which the parameters are queried for | |
46 | * @get_params: out parameters to which the parameters are copied to | |
47 | * | |
48 | * This function is called when the stream parameters are queiried for | |
49 | */ | |
50 | int sst_get_stream_params(int str_id, | |
51 | struct snd_sst_get_stream_params *get_params) | |
52 | { | |
53 | int retval = 0; | |
54 | struct ipc_post *msg = NULL; | |
55 | struct stream_info *str_info; | |
56 | struct snd_sst_fw_get_stream_params *fw_params; | |
57 | ||
d0f40c50 | 58 | pr_debug("get_stream for %d\n", str_id); |
fffa1cca VK |
59 | retval = sst_validate_strid(str_id); |
60 | if (retval) | |
61 | return retval; | |
62 | ||
63 | str_info = &sst_drv_ctx->streams[str_id]; | |
64 | if (str_info->status != STREAM_UN_INIT) { | |
65 | if (str_info->ctrl_blk.on == true) { | |
d0f40c50 | 66 | pr_err("control path in use\n"); |
fffa1cca VK |
67 | return -EINVAL; |
68 | } | |
69 | if (sst_create_short_msg(&msg)) { | |
d0f40c50 | 70 | pr_err("message creation failed\n"); |
fffa1cca VK |
71 | return -ENOMEM; |
72 | } | |
73 | fw_params = kzalloc(sizeof(*fw_params), GFP_ATOMIC); | |
74 | if (!fw_params) { | |
d0f40c50 | 75 | pr_err("mem allocation failed\n"); |
fffa1cca VK |
76 | kfree(msg); |
77 | return -ENOMEM; | |
78 | } | |
79 | ||
80 | sst_fill_header(&msg->header, IPC_IA_GET_STREAM_PARAMS, | |
81 | 0, str_id); | |
82 | str_info->ctrl_blk.condition = false; | |
83 | str_info->ctrl_blk.ret_code = 0; | |
84 | str_info->ctrl_blk.on = true; | |
85 | str_info->ctrl_blk.data = (void *) fw_params; | |
86 | spin_lock(&sst_drv_ctx->list_spin_lock); | |
87 | list_add_tail(&msg->node, &sst_drv_ctx->ipc_dispatch_list); | |
88 | spin_unlock(&sst_drv_ctx->list_spin_lock); | |
89 | sst_post_message(&sst_drv_ctx->ipc_post_msg_wq); | |
90 | retval = sst_wait_interruptible_timeout(sst_drv_ctx, | |
91 | &str_info->ctrl_blk, SST_BLOCK_TIMEOUT); | |
92 | if (retval) { | |
93 | get_params->codec_params.result = retval; | |
94 | kfree(fw_params); | |
95 | return -EIO; | |
96 | } | |
97 | memcpy(&get_params->pcm_params, &fw_params->pcm_params, | |
98 | sizeof(fw_params->pcm_params)); | |
99 | memcpy(&get_params->codec_params.sparams, | |
100 | &fw_params->codec_params, | |
101 | sizeof(fw_params->codec_params)); | |
102 | get_params->codec_params.result = 0; | |
103 | get_params->codec_params.stream_id = str_id; | |
104 | get_params->codec_params.codec = str_info->codec; | |
105 | get_params->codec_params.ops = str_info->ops; | |
106 | get_params->codec_params.stream_type = str_info->str_type; | |
107 | kfree(fw_params); | |
108 | } else { | |
d0f40c50 | 109 | pr_debug("Stream is not in the init state\n"); |
fffa1cca VK |
110 | } |
111 | return retval; | |
112 | } | |
113 | ||
114 | /** | |
115 | * sst_set_stream_param - Send msg for setting stream parameters | |
116 | * | |
117 | * @str_id: stream id | |
118 | * @str_param: stream params | |
119 | * | |
120 | * This function sets stream params during runtime | |
121 | */ | |
122 | int sst_set_stream_param(int str_id, struct snd_sst_params *str_param) | |
123 | { | |
124 | int retval = 0; | |
125 | struct ipc_post *msg = NULL; | |
126 | struct stream_info *str_info; | |
127 | ||
128 | BUG_ON(!str_param); | |
129 | if (sst_drv_ctx->streams[str_id].ops != str_param->ops) { | |
d0f40c50 | 130 | pr_err("Invalid operation\n"); |
fffa1cca VK |
131 | return -EINVAL; |
132 | } | |
133 | retval = sst_validate_strid(str_id); | |
134 | if (retval) | |
135 | return retval; | |
d0f40c50 | 136 | pr_debug("set_stream for %d\n", str_id); |
fffa1cca VK |
137 | str_info = &sst_drv_ctx->streams[str_id]; |
138 | if (sst_drv_ctx->streams[str_id].status == STREAM_INIT) { | |
139 | if (str_info->ctrl_blk.on == true) { | |
d0f40c50 | 140 | pr_err("control path in use\n"); |
fffa1cca VK |
141 | return -EAGAIN; |
142 | } | |
143 | if (sst_create_large_msg(&msg)) | |
144 | return -ENOMEM; | |
145 | ||
146 | sst_fill_header(&msg->header, | |
147 | IPC_IA_SET_STREAM_PARAMS, 1, str_id); | |
148 | str_info->ctrl_blk.condition = false; | |
149 | str_info->ctrl_blk.ret_code = 0; | |
150 | str_info->ctrl_blk.on = true; | |
151 | msg->header.part.data = sizeof(u32) + | |
152 | sizeof(str_param->sparams); | |
153 | memcpy(msg->mailbox_data, &msg->header, sizeof(u32)); | |
154 | memcpy(msg->mailbox_data + sizeof(u32), &str_param->sparams, | |
155 | sizeof(str_param->sparams)); | |
156 | spin_lock(&sst_drv_ctx->list_spin_lock); | |
157 | list_add_tail(&msg->node, &sst_drv_ctx->ipc_dispatch_list); | |
158 | spin_unlock(&sst_drv_ctx->list_spin_lock); | |
159 | sst_post_message(&sst_drv_ctx->ipc_post_msg_wq); | |
160 | retval = sst_wait_interruptible_timeout(sst_drv_ctx, | |
161 | &str_info->ctrl_blk, SST_BLOCK_TIMEOUT); | |
162 | if (retval < 0) { | |
163 | retval = -EIO; | |
164 | sst_clean_stream(str_info); | |
165 | } | |
166 | } else { | |
167 | retval = -EBADRQC; | |
d0f40c50 | 168 | pr_err("BADQRC for stream\n"); |
fffa1cca VK |
169 | } |
170 | return retval; | |
171 | } | |
172 | ||
173 | /** | |
1bf8240c | 174 | * sst_get_vol - This function allows to get the premix gain or gain of a stream |
fffa1cca VK |
175 | * |
176 | * @get_vol: this is an output param through which the volume | |
177 | * structure is passed back to user | |
178 | * | |
179 | * This function is called when the premix gain or stream gain is queried for | |
180 | */ | |
181 | int sst_get_vol(struct snd_sst_vol *get_vol) | |
182 | { | |
183 | int retval = 0; | |
184 | struct ipc_post *msg = NULL; | |
185 | struct snd_sst_vol *fw_get_vol; | |
186 | int str_id = get_vol->stream_id; | |
187 | ||
d0f40c50 | 188 | pr_debug("get vol called\n"); |
fffa1cca VK |
189 | |
190 | if (sst_create_short_msg(&msg)) | |
191 | return -ENOMEM; | |
192 | ||
193 | sst_fill_header(&msg->header, | |
194 | IPC_IA_GET_STREAM_VOL, 0, str_id); | |
195 | sst_drv_ctx->vol_info_blk.condition = false; | |
196 | sst_drv_ctx->vol_info_blk.ret_code = 0; | |
197 | sst_drv_ctx->vol_info_blk.on = true; | |
198 | fw_get_vol = kzalloc(sizeof(*fw_get_vol), GFP_ATOMIC); | |
199 | if (!fw_get_vol) { | |
d0f40c50 | 200 | pr_err("mem allocation failed\n"); |
fffa1cca VK |
201 | kfree(msg); |
202 | return -ENOMEM; | |
203 | } | |
204 | sst_drv_ctx->vol_info_blk.data = (void *)fw_get_vol; | |
205 | spin_lock(&sst_drv_ctx->list_spin_lock); | |
206 | list_add_tail(&msg->node, &sst_drv_ctx->ipc_dispatch_list); | |
207 | spin_unlock(&sst_drv_ctx->list_spin_lock); | |
208 | sst_post_message(&sst_drv_ctx->ipc_post_msg_wq); | |
209 | retval = sst_wait_interruptible_timeout(sst_drv_ctx, | |
210 | &sst_drv_ctx->vol_info_blk, SST_BLOCK_TIMEOUT); | |
211 | if (retval) | |
212 | retval = -EIO; | |
213 | else { | |
d0f40c50 JP |
214 | pr_debug("stream id %d\n", fw_get_vol->stream_id); |
215 | pr_debug("volume %d\n", fw_get_vol->volume); | |
216 | pr_debug("ramp duration %d\n", fw_get_vol->ramp_duration); | |
217 | pr_debug("ramp_type %d\n", fw_get_vol->ramp_type); | |
fffa1cca VK |
218 | memcpy(get_vol, fw_get_vol, sizeof(*fw_get_vol)); |
219 | } | |
220 | return retval; | |
221 | } | |
222 | ||
223 | /** | |
1bf8240c | 224 | * sst_set_vol - This function allows to set the premix gain or gain of a stream |
fffa1cca VK |
225 | * |
226 | * @set_vol: this holds the volume structure that needs to be set | |
227 | * | |
228 | * This function is called when premix gain or stream gain is requested to be set | |
229 | */ | |
230 | int sst_set_vol(struct snd_sst_vol *set_vol) | |
231 | { | |
232 | ||
233 | int retval = 0; | |
234 | struct ipc_post *msg = NULL; | |
235 | ||
d0f40c50 | 236 | pr_debug("set vol called\n"); |
fffa1cca VK |
237 | |
238 | if (sst_create_large_msg(&msg)) { | |
d0f40c50 | 239 | pr_err("message creation failed\n"); |
fffa1cca VK |
240 | return -ENOMEM; |
241 | } | |
242 | sst_fill_header(&msg->header, IPC_IA_SET_STREAM_VOL, 1, | |
243 | set_vol->stream_id); | |
244 | ||
245 | msg->header.part.data = sizeof(u32) + sizeof(*set_vol); | |
246 | memcpy(msg->mailbox_data, &msg->header, sizeof(u32)); | |
247 | memcpy(msg->mailbox_data + sizeof(u32), set_vol, sizeof(*set_vol)); | |
248 | sst_drv_ctx->vol_info_blk.condition = false; | |
249 | sst_drv_ctx->vol_info_blk.ret_code = 0; | |
250 | sst_drv_ctx->vol_info_blk.on = true; | |
251 | sst_drv_ctx->vol_info_blk.data = set_vol; | |
252 | spin_lock(&sst_drv_ctx->list_spin_lock); | |
253 | list_add_tail(&msg->node, &sst_drv_ctx->ipc_dispatch_list); | |
254 | spin_unlock(&sst_drv_ctx->list_spin_lock); | |
255 | sst_post_message(&sst_drv_ctx->ipc_post_msg_wq); | |
256 | retval = sst_wait_interruptible_timeout(sst_drv_ctx, | |
257 | &sst_drv_ctx->vol_info_blk, SST_BLOCK_TIMEOUT); | |
258 | if (retval) { | |
d0f40c50 | 259 | pr_err("error in set_vol = %d\n", retval); |
fffa1cca VK |
260 | retval = -EIO; |
261 | } | |
262 | return retval; | |
263 | } | |
264 | ||
265 | /** | |
1bf8240c | 266 | * sst_set_mute - This function sets premix mute or soft mute of a stream |
fffa1cca VK |
267 | * |
268 | * @set_mute: this holds the mute structure that needs to be set | |
269 | * | |
270 | * This function is called when premix mute or stream mute requested to be set | |
271 | */ | |
272 | int sst_set_mute(struct snd_sst_mute *set_mute) | |
273 | { | |
274 | ||
275 | int retval = 0; | |
276 | struct ipc_post *msg = NULL; | |
277 | ||
d0f40c50 | 278 | pr_debug("set mute called\n"); |
fffa1cca VK |
279 | |
280 | if (sst_create_large_msg(&msg)) { | |
d0f40c50 | 281 | pr_err("message creation failed\n"); |
fffa1cca VK |
282 | return -ENOMEM; |
283 | } | |
284 | sst_fill_header(&msg->header, IPC_IA_SET_STREAM_MUTE, 1, | |
285 | set_mute->stream_id); | |
286 | sst_drv_ctx->mute_info_blk.condition = false; | |
287 | sst_drv_ctx->mute_info_blk.ret_code = 0; | |
288 | sst_drv_ctx->mute_info_blk.on = true; | |
289 | sst_drv_ctx->mute_info_blk.data = set_mute; | |
290 | ||
291 | msg->header.part.data = sizeof(u32) + sizeof(*set_mute); | |
292 | memcpy(msg->mailbox_data, &msg->header, sizeof(u32)); | |
293 | memcpy(msg->mailbox_data + sizeof(u32), set_mute, | |
294 | sizeof(*set_mute)); | |
295 | spin_lock(&sst_drv_ctx->list_spin_lock); | |
296 | list_add_tail(&msg->node, &sst_drv_ctx->ipc_dispatch_list); | |
297 | spin_unlock(&sst_drv_ctx->list_spin_lock); | |
298 | sst_post_message(&sst_drv_ctx->ipc_post_msg_wq); | |
299 | retval = sst_wait_interruptible_timeout(sst_drv_ctx, | |
300 | &sst_drv_ctx->mute_info_blk, SST_BLOCK_TIMEOUT); | |
301 | if (retval) { | |
d0f40c50 | 302 | pr_err("error in set_mute = %d\n", retval); |
fffa1cca VK |
303 | retval = -EIO; |
304 | } | |
305 | return retval; | |
306 | } | |
307 | ||
308 | int sst_prepare_target(struct snd_sst_slot_info *slot) | |
309 | { | |
310 | if (slot->target_device == SND_SST_TARGET_PMIC | |
311 | && slot->device_instance == 1) { | |
312 | /*music mode*/ | |
313 | if (sst_drv_ctx->pmic_port_instance == 0) | |
314 | sst_drv_ctx->scard_ops->set_voice_port( | |
315 | DEACTIVATE); | |
316 | } else if ((slot->target_device == SND_SST_TARGET_PMIC || | |
317 | slot->target_device == SND_SST_TARGET_MODEM) && | |
318 | slot->device_instance == 0) { | |
319 | /*voip mode where pcm0 is active*/ | |
320 | if (sst_drv_ctx->pmic_port_instance == 1) | |
321 | sst_drv_ctx->scard_ops->set_audio_port( | |
322 | DEACTIVATE); | |
323 | } | |
324 | return 0; | |
325 | } | |
326 | ||
327 | int sst_activate_target(struct snd_sst_slot_info *slot) | |
328 | { | |
329 | if (slot->target_device == SND_SST_TARGET_PMIC && | |
330 | slot->device_instance == 1) { | |
331 | /*music mode*/ | |
332 | sst_drv_ctx->pmic_port_instance = 1; | |
333 | sst_drv_ctx->scard_ops->set_audio_port(ACTIVATE); | |
334 | sst_drv_ctx->scard_ops->set_pcm_audio_params( | |
335 | slot->pcm_params.sfreq, | |
336 | slot->pcm_params.pcm_wd_sz, | |
337 | slot->pcm_params.num_chan); | |
338 | if (sst_drv_ctx->pb_streams) | |
339 | sst_drv_ctx->scard_ops->power_up_pmic_pb(1); | |
340 | if (sst_drv_ctx->cp_streams) | |
341 | sst_drv_ctx->scard_ops->power_up_pmic_cp(1); | |
342 | } else if ((slot->target_device == SND_SST_TARGET_PMIC || | |
343 | slot->target_device == SND_SST_TARGET_MODEM) && | |
344 | slot->device_instance == 0) { | |
345 | /*voip mode where pcm0 is active*/ | |
346 | sst_drv_ctx->pmic_port_instance = 0; | |
347 | sst_drv_ctx->scard_ops->set_voice_port( | |
348 | ACTIVATE); | |
349 | sst_drv_ctx->scard_ops->power_up_pmic_pb(0); | |
350 | /*sst_drv_ctx->scard_ops->power_up_pmic_cp(0);*/ | |
351 | } | |
352 | return 0; | |
353 | } | |
354 | ||
355 | int sst_parse_target(struct snd_sst_slot_info *slot) | |
356 | { | |
357 | int retval = 0; | |
358 | ||
359 | if (slot->action == SND_SST_PORT_ACTIVATE && | |
360 | slot->device_type == SND_SST_DEVICE_PCM) { | |
361 | retval = sst_activate_target(slot); | |
362 | if (retval) | |
d0f40c50 | 363 | pr_err("SST_Activate_target_fail\n"); |
fffa1cca | 364 | else |
d0f40c50 | 365 | pr_err("SST_Activate_target_pass\n"); |
fffa1cca VK |
366 | return retval; |
367 | } else if (slot->action == SND_SST_PORT_PREPARE && | |
368 | slot->device_type == SND_SST_DEVICE_PCM) { | |
369 | retval = sst_prepare_target(slot); | |
370 | if (retval) | |
d0f40c50 | 371 | pr_err("SST_prepare_target_fail\n"); |
fffa1cca | 372 | else |
d0f40c50 | 373 | pr_err("SST_prepare_target_pass\n"); |
fffa1cca VK |
374 | return retval; |
375 | } else { | |
d0f40c50 | 376 | pr_err("slot_action : %d, device_type: %d\n", |
fffa1cca VK |
377 | slot->action, slot->device_type); |
378 | return retval; | |
379 | } | |
380 | } | |
381 | ||
382 | int sst_send_target(struct snd_sst_target_device *target) | |
383 | { | |
384 | int retval; | |
385 | struct ipc_post *msg; | |
386 | ||
387 | if (sst_create_large_msg(&msg)) { | |
d0f40c50 | 388 | pr_err("message creation failed\n"); |
fffa1cca VK |
389 | return -ENOMEM; |
390 | } | |
391 | sst_fill_header(&msg->header, IPC_IA_TARGET_DEV_SELECT, 1, 0); | |
392 | sst_drv_ctx->tgt_dev_blk.condition = false; | |
393 | sst_drv_ctx->tgt_dev_blk.ret_code = 0; | |
394 | sst_drv_ctx->tgt_dev_blk.on = true; | |
395 | ||
396 | msg->header.part.data = sizeof(u32) + sizeof(*target); | |
397 | memcpy(msg->mailbox_data, &msg->header, sizeof(u32)); | |
398 | memcpy(msg->mailbox_data + sizeof(u32), target, | |
399 | sizeof(*target)); | |
400 | spin_lock(&sst_drv_ctx->list_spin_lock); | |
401 | list_add_tail(&msg->node, &sst_drv_ctx->ipc_dispatch_list); | |
402 | spin_unlock(&sst_drv_ctx->list_spin_lock); | |
403 | sst_post_message(&sst_drv_ctx->ipc_post_msg_wq); | |
d0f40c50 | 404 | pr_debug("message sent- waiting\n"); |
fffa1cca VK |
405 | retval = sst_wait_interruptible_timeout(sst_drv_ctx, |
406 | &sst_drv_ctx->tgt_dev_blk, TARGET_DEV_BLOCK_TIMEOUT); | |
407 | if (retval) | |
d0f40c50 | 408 | pr_err("target device ipc failed = 0x%x\n", retval); |
fffa1cca VK |
409 | return retval; |
410 | ||
411 | } | |
412 | ||
413 | int sst_target_device_validate(struct snd_sst_target_device *target) | |
414 | { | |
415 | int retval = 0; | |
416 | int i; | |
417 | ||
418 | for (i = 0; i < SST_MAX_TARGET_DEVICES; i++) { | |
419 | if (target->devices[i].device_type == SND_SST_DEVICE_PCM) { | |
420 | /*pcm device, check params*/ | |
421 | if (target->devices[i].device_instance == 1) { | |
422 | if ((target->devices[i].device_mode != | |
423 | SND_SST_DEV_MODE_PCM_MODE4_I2S) && | |
424 | (target->devices[i].device_mode != | |
425 | SND_SST_DEV_MODE_PCM_MODE4_RIGHT_JUSTIFIED) | |
426 | && (target->devices[i].device_mode != | |
427 | SND_SST_DEV_MODE_PCM_MODE1)) | |
428 | goto err; | |
429 | } else if (target->devices[i].device_instance == 0) { | |
430 | if ((target->devices[i].device_mode != | |
431 | SND_SST_DEV_MODE_PCM_MODE2) | |
432 | && (target->devices[i].device_mode != | |
433 | SND_SST_DEV_MODE_PCM_MODE4_I2S) | |
434 | && (target->devices[i].device_mode != | |
435 | SND_SST_DEV_MODE_PCM_MODE1)) | |
436 | goto err; | |
437 | if (target->devices[i].pcm_params.sfreq != 8000 | |
438 | || target->devices[i].pcm_params.num_chan != 1 | |
439 | || target->devices[i].pcm_params.pcm_wd_sz != | |
440 | 16) | |
441 | goto err; | |
442 | } else { | |
443 | err: | |
d0f40c50 | 444 | pr_err("i/p params incorrect\n"); |
fffa1cca VK |
445 | return -EINVAL; |
446 | } | |
447 | } | |
448 | } | |
449 | return retval; | |
450 | } | |
451 | ||
452 | /** | |
1bf8240c | 453 | * sst_target_device_select - This function sets the target device configurations |
fffa1cca VK |
454 | * |
455 | * @target: this parameter holds the configurations to be set | |
456 | * | |
457 | * This function is called when the user layer wants to change the target | |
458 | * device's configurations | |
459 | */ | |
460 | ||
461 | int sst_target_device_select(struct snd_sst_target_device *target) | |
462 | { | |
463 | int retval, i, prepare_count = 0; | |
464 | ||
d0f40c50 | 465 | pr_debug("Target Device Select\n"); |
fffa1cca VK |
466 | |
467 | if (target->device_route < 0 || target->device_route > 2) { | |
d0f40c50 | 468 | pr_err("device route is invalid\n"); |
fffa1cca VK |
469 | return -EINVAL; |
470 | } | |
471 | ||
472 | if (target->device_route != 0) { | |
d0f40c50 | 473 | pr_err("Unsupported config\n"); |
fffa1cca VK |
474 | return -EIO; |
475 | } | |
476 | retval = sst_target_device_validate(target); | |
477 | if (retval) | |
478 | return retval; | |
479 | ||
480 | retval = sst_send_target(target); | |
481 | if (retval) | |
482 | return retval; | |
483 | for (i = 0; i < SST_MAX_TARGET_DEVICES; i++) { | |
484 | if (target->devices[i].action == SND_SST_PORT_ACTIVATE) { | |
d0f40c50 | 485 | pr_debug("activate called in %d\n", i); |
fffa1cca VK |
486 | retval = sst_parse_target(&target->devices[i]); |
487 | if (retval) | |
488 | return retval; | |
489 | } else if (target->devices[i].action == SND_SST_PORT_PREPARE) { | |
d0f40c50 | 490 | pr_debug("PREPARE in %d, Forwarding\n", i); |
fffa1cca VK |
491 | retval = sst_parse_target(&target->devices[i]); |
492 | if (retval) { | |
d0f40c50 | 493 | pr_err("Parse Target fail %d\n", retval); |
fffa1cca VK |
494 | return retval; |
495 | } | |
d0f40c50 | 496 | pr_debug("Parse Target successful %d\n", retval); |
fffa1cca VK |
497 | if (target->devices[i].device_type == |
498 | SND_SST_DEVICE_PCM) | |
499 | prepare_count++; | |
500 | } | |
501 | } | |
502 | if (target->devices[0].action == SND_SST_PORT_PREPARE && | |
503 | prepare_count == 0) | |
504 | sst_drv_ctx->scard_ops->power_down_pmic(); | |
505 | ||
506 | return retval; | |
507 | } | |
508 | #ifdef CONFIG_MRST_RAR_HANDLER | |
509 | /*This function gets the physical address of the secure memory from the handle*/ | |
510 | static inline int sst_get_RAR(struct RAR_buffer *buffers, int count) | |
511 | { | |
512 | int retval = 0, rar_status = 0; | |
513 | ||
514 | rar_status = rar_handle_to_bus(buffers, count); | |
515 | ||
516 | if (count != rar_status) { | |
d0f40c50 | 517 | pr_err("The rar CALL Failed"); |
fffa1cca VK |
518 | retval = -EIO; |
519 | } | |
520 | if (buffers->info.type != RAR_TYPE_AUDIO) { | |
d0f40c50 | 521 | pr_err("Invalid RAR type\n"); |
fffa1cca VK |
522 | return -EINVAL; |
523 | } | |
524 | return retval; | |
525 | } | |
526 | ||
527 | #endif | |
528 | ||
529 | /* This function creates the scatter gather list to be sent to firmware to | |
530 | capture/playback data*/ | |
531 | static int sst_create_sg_list(struct stream_info *stream, | |
532 | struct sst_frame_info *sg_list) | |
533 | { | |
534 | struct sst_stream_bufs *kbufs = NULL; | |
535 | #ifdef CONFIG_MRST_RAR_HANDLER | |
536 | struct RAR_buffer rar_buffers; | |
537 | int retval = 0; | |
538 | #endif | |
539 | int i = 0; | |
540 | list_for_each_entry(kbufs, &stream->bufs, node) { | |
541 | if (kbufs->in_use == false) { | |
542 | #ifdef CONFIG_MRST_RAR_HANDLER | |
543 | if (stream->ops == STREAM_OPS_PLAYBACK_DRM) { | |
d0f40c50 | 544 | pr_debug("DRM playback handling\n"); |
fffa1cca VK |
545 | rar_buffers.info.handle = (__u32)kbufs->addr; |
546 | rar_buffers.info.size = kbufs->size; | |
d0f40c50 | 547 | pr_debug("rar handle 0x%x size=0x%x\n", |
fffa1cca VK |
548 | rar_buffers.info.handle, |
549 | rar_buffers.info.size); | |
550 | retval = sst_get_RAR(&rar_buffers, 1); | |
551 | ||
552 | if (retval) | |
553 | return retval; | |
554 | sg_list->addr[i].addr = rar_buffers.bus_address; | |
555 | /* rar_buffers.info.size; */ | |
556 | sg_list->addr[i].size = (__u32)kbufs->size; | |
d0f40c50 | 557 | pr_debug("phyaddr[%d] 0x%x Size:0x%x\n" |
fffa1cca VK |
558 | , i, sg_list->addr[i].addr, |
559 | sg_list->addr[i].size); | |
560 | } | |
561 | #endif | |
562 | if (stream->ops != STREAM_OPS_PLAYBACK_DRM) { | |
563 | sg_list->addr[i].addr = | |
564 | virt_to_phys((void *) | |
565 | kbufs->addr + kbufs->offset); | |
566 | sg_list->addr[i].size = kbufs->size; | |
d0f40c50 | 567 | pr_debug("phyaddr[%d]:0x%x Size:0x%x\n" |
fffa1cca VK |
568 | , i , sg_list->addr[i].addr, kbufs->size); |
569 | } | |
570 | stream->curr_bytes += sg_list->addr[i].size; | |
571 | kbufs->in_use = true; | |
572 | i++; | |
573 | } | |
574 | if (i >= MAX_NUM_SCATTER_BUFFERS) | |
575 | break; | |
576 | } | |
577 | ||
578 | sg_list->num_entries = i; | |
d0f40c50 | 579 | pr_debug("sg list entries = %d\n", sg_list->num_entries); |
fffa1cca VK |
580 | return i; |
581 | } | |
582 | ||
583 | ||
584 | /** | |
585 | * sst_play_frame - Send msg for sending stream frames | |
586 | * | |
587 | * @str_id: ID of stream | |
588 | * | |
589 | * This function is called to send data to be played out | |
590 | * to the firmware | |
591 | */ | |
592 | int sst_play_frame(int str_id) | |
593 | { | |
594 | int i = 0, retval = 0; | |
595 | struct ipc_post *msg = NULL; | |
596 | struct sst_frame_info sg_list = {0}; | |
597 | struct sst_stream_bufs *kbufs = NULL, *_kbufs; | |
598 | struct stream_info *stream; | |
599 | ||
d0f40c50 | 600 | pr_debug("play frame for %d\n", str_id); |
fffa1cca VK |
601 | retval = sst_validate_strid(str_id); |
602 | if (retval) | |
603 | return retval; | |
604 | ||
605 | stream = &sst_drv_ctx->streams[str_id]; | |
606 | /* clear prev sent buffers */ | |
607 | list_for_each_entry_safe(kbufs, _kbufs, &stream->bufs, node) { | |
608 | if (kbufs->in_use == true) { | |
609 | spin_lock(&stream->pcm_lock); | |
610 | list_del(&kbufs->node); | |
611 | spin_unlock(&stream->pcm_lock); | |
612 | kfree(kbufs); | |
613 | } | |
614 | } | |
615 | /* update bytes sent */ | |
616 | stream->cumm_bytes += stream->curr_bytes; | |
617 | stream->curr_bytes = 0; | |
618 | if (list_empty(&stream->bufs)) { | |
619 | /* no user buffer available */ | |
d0f40c50 | 620 | pr_debug("Null buffer stream status %d\n", stream->status); |
fffa1cca VK |
621 | stream->prev = stream->status; |
622 | stream->status = STREAM_INIT; | |
d0f40c50 | 623 | pr_debug("new stream status = %d\n", stream->status); |
fffa1cca | 624 | if (stream->need_draining == true) { |
d0f40c50 | 625 | pr_debug("draining stream\n"); |
fffa1cca | 626 | if (sst_create_short_msg(&msg)) { |
d0f40c50 | 627 | pr_err("mem allocation failed\n"); |
fffa1cca VK |
628 | return -ENOMEM; |
629 | } | |
630 | sst_fill_header(&msg->header, IPC_IA_DRAIN_STREAM, | |
631 | 0, str_id); | |
632 | spin_lock(&sst_drv_ctx->list_spin_lock); | |
633 | list_add_tail(&msg->node, | |
634 | &sst_drv_ctx->ipc_dispatch_list); | |
635 | spin_unlock(&sst_drv_ctx->list_spin_lock); | |
636 | sst_post_message(&sst_drv_ctx->ipc_post_msg_wq); | |
637 | } else if (stream->data_blk.on == true) { | |
d0f40c50 | 638 | pr_debug("user list empty.. wake\n"); |
fffa1cca VK |
639 | /* unblock */ |
640 | stream->data_blk.ret_code = 0; | |
641 | stream->data_blk.condition = true; | |
642 | stream->data_blk.on = false; | |
643 | wake_up(&sst_drv_ctx->wait_queue); | |
644 | } | |
645 | return 0; | |
646 | } | |
647 | ||
648 | /* create list */ | |
649 | i = sst_create_sg_list(stream, &sg_list); | |
650 | ||
651 | /* post msg */ | |
652 | if (sst_create_large_msg(&msg)) | |
653 | return -ENOMEM; | |
654 | ||
655 | sst_fill_header(&msg->header, IPC_IA_PLAY_FRAMES, 1, str_id); | |
656 | msg->header.part.data = sizeof(u32) + sizeof(sg_list); | |
657 | memcpy(msg->mailbox_data, &msg->header, sizeof(u32)); | |
658 | memcpy(msg->mailbox_data + sizeof(u32), &sg_list, sizeof(sg_list)); | |
659 | spin_lock(&sst_drv_ctx->list_spin_lock); | |
660 | list_add_tail(&msg->node, &sst_drv_ctx->ipc_dispatch_list); | |
661 | spin_unlock(&sst_drv_ctx->list_spin_lock); | |
662 | sst_post_message(&sst_drv_ctx->ipc_post_msg_wq); | |
663 | return 0; | |
664 | ||
665 | } | |
666 | ||
667 | /** | |
668 | * sst_capture_frame - Send msg for sending stream frames | |
669 | * | |
670 | * @str_id: ID of stream | |
671 | * | |
672 | * This function is called to capture data from the firmware | |
673 | */ | |
674 | int sst_capture_frame(int str_id) | |
675 | { | |
676 | int i = 0, retval = 0; | |
677 | struct ipc_post *msg = NULL; | |
678 | struct sst_frame_info sg_list = {0}; | |
679 | struct sst_stream_bufs *kbufs = NULL, *_kbufs; | |
680 | struct stream_info *stream; | |
681 | ||
682 | ||
d0f40c50 | 683 | pr_debug("capture frame for %d\n", str_id); |
fffa1cca VK |
684 | retval = sst_validate_strid(str_id); |
685 | if (retval) | |
686 | return retval; | |
687 | stream = &sst_drv_ctx->streams[str_id]; | |
688 | /* clear prev sent buffers */ | |
689 | list_for_each_entry_safe(kbufs, _kbufs, &stream->bufs, node) { | |
690 | if (kbufs->in_use == true) { | |
691 | list_del(&kbufs->node); | |
692 | kfree(kbufs); | |
d0f40c50 | 693 | pr_debug("del node\n"); |
fffa1cca VK |
694 | } |
695 | } | |
696 | if (list_empty(&stream->bufs)) { | |
697 | /* no user buffer available */ | |
d0f40c50 | 698 | pr_debug("Null buffer!!!!stream status %d\n", |
fffa1cca VK |
699 | stream->status); |
700 | stream->prev = stream->status; | |
701 | stream->status = STREAM_INIT; | |
d0f40c50 | 702 | pr_debug("new stream status = %d\n", |
fffa1cca VK |
703 | stream->status); |
704 | if (stream->data_blk.on == true) { | |
d0f40c50 | 705 | pr_debug("user list empty.. wake\n"); |
fffa1cca VK |
706 | /* unblock */ |
707 | stream->data_blk.ret_code = 0; | |
708 | stream->data_blk.condition = true; | |
709 | stream->data_blk.on = false; | |
710 | wake_up(&sst_drv_ctx->wait_queue); | |
711 | ||
712 | } | |
713 | return 0; | |
714 | } | |
715 | /* create new sg list */ | |
716 | i = sst_create_sg_list(stream, &sg_list); | |
717 | ||
718 | /* post msg */ | |
719 | if (sst_create_large_msg(&msg)) | |
720 | return -ENOMEM; | |
721 | ||
722 | sst_fill_header(&msg->header, IPC_IA_CAPT_FRAMES, 1, str_id); | |
723 | msg->header.part.data = sizeof(u32) + sizeof(sg_list); | |
724 | memcpy(msg->mailbox_data, &msg->header, sizeof(u32)); | |
725 | memcpy(msg->mailbox_data + sizeof(u32), &sg_list, sizeof(sg_list)); | |
726 | spin_lock(&sst_drv_ctx->list_spin_lock); | |
727 | list_add_tail(&msg->node, &sst_drv_ctx->ipc_dispatch_list); | |
728 | spin_unlock(&sst_drv_ctx->list_spin_lock); | |
729 | sst_post_message(&sst_drv_ctx->ipc_post_msg_wq); | |
730 | ||
731 | ||
732 | /*update bytes recevied*/ | |
733 | stream->cumm_bytes += stream->curr_bytes; | |
734 | stream->curr_bytes = 0; | |
735 | ||
d0f40c50 | 736 | pr_debug("Cum bytes = %d\n", stream->cumm_bytes); |
fffa1cca VK |
737 | return 0; |
738 | } | |
739 | ||
740 | /*This function is used to calculate the minimum size of input buffers given*/ | |
741 | static unsigned int calculate_min_size(struct snd_sst_buffs *bufs) | |
742 | { | |
743 | int i, min_val = bufs->buff_entry[0].size; | |
744 | for (i = 1 ; i < bufs->entries; i++) { | |
745 | if (bufs->buff_entry[i].size < min_val) | |
746 | min_val = bufs->buff_entry[i].size; | |
747 | } | |
d0f40c50 | 748 | pr_debug("min_val = %d\n", min_val); |
fffa1cca VK |
749 | return min_val; |
750 | } | |
751 | ||
752 | static unsigned int calculate_max_size(struct snd_sst_buffs *bufs) | |
753 | { | |
754 | int i, max_val = bufs->buff_entry[0].size; | |
755 | for (i = 1 ; i < bufs->entries; i++) { | |
756 | if (bufs->buff_entry[i].size > max_val) | |
757 | max_val = bufs->buff_entry[i].size; | |
758 | } | |
d0f40c50 | 759 | pr_debug("max_val = %d\n", max_val); |
fffa1cca VK |
760 | return max_val; |
761 | } | |
762 | ||
763 | /*This function is used to allocate input and output buffers to be sent to | |
764 | the firmware that will take encoded data and return decoded data*/ | |
765 | static int sst_allocate_decode_buf(struct stream_info *str_info, | |
766 | struct snd_sst_dbufs *dbufs, | |
767 | unsigned int cum_input_given, | |
768 | unsigned int cum_output_given) | |
769 | { | |
770 | #ifdef CONFIG_MRST_RAR_HANDLER | |
771 | if (str_info->ops == STREAM_OPS_PLAYBACK_DRM) { | |
772 | ||
773 | if (dbufs->ibufs->type == SST_BUF_RAR && | |
774 | dbufs->obufs->type == SST_BUF_RAR) { | |
775 | if (dbufs->ibufs->entries == dbufs->obufs->entries) | |
776 | return 0; | |
777 | else { | |
d0f40c50 | 778 | pr_err("RAR entries dont match\n"); |
fffa1cca VK |
779 | return -EINVAL; |
780 | } | |
781 | } else | |
782 | str_info->decode_osize = cum_output_given; | |
783 | return 0; | |
784 | ||
785 | } | |
786 | #endif | |
787 | if (!str_info->decode_ibuf) { | |
d0f40c50 | 788 | pr_debug("no i/p buffers, trying full size\n"); |
fffa1cca VK |
789 | str_info->decode_isize = cum_input_given; |
790 | str_info->decode_ibuf = kzalloc(str_info->decode_isize, | |
791 | GFP_KERNEL); | |
792 | str_info->idecode_alloc = str_info->decode_isize; | |
793 | } | |
794 | if (!str_info->decode_ibuf) { | |
d0f40c50 | 795 | pr_debug("buff alloc failed, try max size\n"); |
fffa1cca VK |
796 | str_info->decode_isize = calculate_max_size(dbufs->ibufs); |
797 | str_info->decode_ibuf = kzalloc( | |
798 | str_info->decode_isize, GFP_KERNEL); | |
799 | str_info->idecode_alloc = str_info->decode_isize; | |
800 | } | |
801 | if (!str_info->decode_ibuf) { | |
d0f40c50 | 802 | pr_debug("buff alloc failed, try min size\n"); |
fffa1cca VK |
803 | str_info->decode_isize = calculate_min_size(dbufs->ibufs); |
804 | str_info->decode_ibuf = kzalloc(str_info->decode_isize, | |
805 | GFP_KERNEL); | |
806 | if (!str_info->decode_ibuf) { | |
d0f40c50 | 807 | pr_err("mem allocation failed\n"); |
fffa1cca VK |
808 | return -ENOMEM; |
809 | } | |
810 | str_info->idecode_alloc = str_info->decode_isize; | |
811 | } | |
812 | str_info->decode_osize = cum_output_given; | |
813 | if (str_info->decode_osize > sst_drv_ctx->mmap_len) | |
814 | str_info->decode_osize = sst_drv_ctx->mmap_len; | |
815 | return 0; | |
816 | } | |
817 | ||
818 | /*This function is used to send the message to firmware to decode the data*/ | |
819 | static int sst_send_decode_mess(int str_id, struct stream_info *str_info, | |
820 | struct snd_sst_decode_info *dec_info) | |
821 | { | |
822 | struct ipc_post *msg = NULL; | |
823 | int retval = 0; | |
824 | ||
d0f40c50 | 825 | pr_debug("SST DBG:sst_set_mute:called\n"); |
fffa1cca VK |
826 | |
827 | if (str_info->decode_ibuf_type == SST_BUF_RAR) { | |
828 | #ifdef CONFIG_MRST_RAR_HANDLER | |
829 | dec_info->frames_in.addr[0].addr = | |
830 | (unsigned long)str_info->decode_ibuf; | |
831 | dec_info->frames_in.addr[0].size = | |
832 | str_info->decode_isize; | |
833 | #endif | |
834 | ||
835 | } else { | |
836 | dec_info->frames_in.addr[0].addr = virt_to_phys((void *) | |
837 | str_info->decode_ibuf); | |
838 | dec_info->frames_in.addr[0].size = str_info->decode_isize; | |
839 | } | |
840 | ||
841 | ||
842 | if (str_info->decode_obuf_type == SST_BUF_RAR) { | |
843 | #ifdef CONFIG_MRST_RAR_HANDLER | |
844 | dec_info->frames_out.addr[0].addr = | |
845 | (unsigned long)str_info->decode_obuf; | |
846 | dec_info->frames_out.addr[0].size = str_info->decode_osize; | |
847 | #endif | |
848 | ||
849 | } else { | |
850 | dec_info->frames_out.addr[0].addr = virt_to_phys((void *) | |
851 | str_info->decode_obuf) ; | |
852 | dec_info->frames_out.addr[0].size = str_info->decode_osize; | |
853 | } | |
854 | ||
855 | dec_info->frames_in.num_entries = 1; | |
856 | dec_info->frames_out.num_entries = 1; | |
857 | dec_info->frames_in.rsrvd = 0; | |
858 | dec_info->frames_out.rsrvd = 0; | |
859 | dec_info->input_bytes_consumed = 0; | |
860 | dec_info->output_bytes_produced = 0; | |
861 | if (sst_create_large_msg(&msg)) { | |
d0f40c50 | 862 | pr_err("message creation failed\n"); |
fffa1cca VK |
863 | return -ENOMEM; |
864 | } | |
865 | ||
866 | sst_fill_header(&msg->header, IPC_IA_DECODE_FRAMES, 1, str_id); | |
867 | msg->header.part.data = sizeof(u32) + sizeof(*dec_info); | |
868 | memcpy(msg->mailbox_data, &msg->header, sizeof(u32)); | |
869 | memcpy(msg->mailbox_data + sizeof(u32), dec_info, | |
870 | sizeof(*dec_info)); | |
871 | spin_lock(&sst_drv_ctx->list_spin_lock); | |
872 | list_add_tail(&msg->node, &sst_drv_ctx->ipc_dispatch_list); | |
873 | spin_unlock(&sst_drv_ctx->list_spin_lock); | |
874 | str_info->data_blk.condition = false; | |
875 | str_info->data_blk.ret_code = 0; | |
876 | str_info->data_blk.on = true; | |
877 | str_info->data_blk.data = dec_info; | |
878 | sst_post_message(&sst_drv_ctx->ipc_post_msg_wq); | |
879 | retval = sst_wait_interruptible(sst_drv_ctx, &str_info->data_blk); | |
880 | return retval; | |
881 | } | |
882 | ||
6f6ffec1 | 883 | #ifdef CONFIG_MRST_RAR_HANDLER |
fffa1cca VK |
884 | static int sst_prepare_input_buffers_rar(struct stream_info *str_info, |
885 | struct snd_sst_dbufs *dbufs, | |
886 | int *input_index, int *in_copied, | |
887 | int *input_index_valid_size, int *new_entry_flag) | |
888 | { | |
889 | int retval = 0; | |
fffa1cca VK |
890 | int i; |
891 | ||
892 | if (str_info->ops == STREAM_OPS_PLAYBACK_DRM) { | |
893 | struct RAR_buffer rar_buffers; | |
894 | __u32 info; | |
895 | retval = copy_from_user((void *) &info, | |
896 | dbufs->ibufs->buff_entry[i].buffer, | |
897 | sizeof(__u32)); | |
898 | if (retval) { | |
d0f40c50 | 899 | pr_err("cpy from user fail\n"); |
fffa1cca VK |
900 | return -EAGAIN; |
901 | } | |
902 | rar_buffers.info.type = dbufs->ibufs->type; | |
903 | rar_buffers.info.size = dbufs->ibufs->buff_entry[i].size; | |
904 | rar_buffers.info.handle = info; | |
905 | pr_debug("rar in DnR(input buffer function)=0x%x size=0x%x", | |
906 | rar_buffers.info.handle, | |
907 | rar_buffers.info.size); | |
908 | retval = sst_get_RAR(&rar_buffers, 1); | |
909 | if (retval) { | |
910 | pr_debug("SST ERR: RAR API failed\n"); | |
911 | return retval; | |
912 | } | |
913 | str_info->decode_ibuf = | |
914 | (void *) ((unsigned long) rar_buffers.bus_address); | |
915 | pr_debug("RAR buf addr in DnR (input buffer function)0x%lu", | |
916 | (unsigned long) str_info->decode_ibuf); | |
25985edc | 917 | pr_debug("rar in DnR decode function/output b_add rar =0x%lu", |
fffa1cca VK |
918 | (unsigned long) rar_buffers.bus_address); |
919 | *input_index = i + 1; | |
920 | str_info->decode_isize = dbufs->ibufs->buff_entry[i].size; | |
921 | str_info->decode_ibuf_type = dbufs->ibufs->type; | |
922 | *in_copied = str_info->decode_isize; | |
923 | } | |
fffa1cca VK |
924 | return retval; |
925 | } | |
6f6ffec1 VK |
926 | #endif |
927 | ||
fffa1cca VK |
928 | /*This function is used to prepare the kernel input buffers with contents |
929 | before sending for decode*/ | |
930 | static int sst_prepare_input_buffers(struct stream_info *str_info, | |
931 | struct snd_sst_dbufs *dbufs, | |
932 | int *input_index, int *in_copied, | |
933 | int *input_index_valid_size, int *new_entry_flag) | |
934 | { | |
935 | int i, cpy_size, retval = 0; | |
936 | ||
d0f40c50 | 937 | pr_debug("input_index = %d, input entries = %d\n", |
fffa1cca VK |
938 | *input_index, dbufs->ibufs->entries); |
939 | for (i = *input_index; i < dbufs->ibufs->entries; i++) { | |
940 | #ifdef CONFIG_MRST_RAR_HANDLER | |
941 | retval = sst_prepare_input_buffers_rar(str_info, | |
942 | dbufs, input_index, in_copied, | |
943 | input_index_valid_size, new_entry_flag); | |
944 | if (retval) { | |
d0f40c50 | 945 | pr_err("In prepare input buffers for RAR\n"); |
fffa1cca VK |
946 | return -EIO; |
947 | } | |
948 | #endif | |
949 | *input_index = i; | |
950 | if (*input_index_valid_size == 0) | |
951 | *input_index_valid_size = | |
952 | dbufs->ibufs->buff_entry[i].size; | |
d0f40c50 | 953 | pr_debug("inout addr = %p, size = %d\n", |
fffa1cca VK |
954 | dbufs->ibufs->buff_entry[i].buffer, |
955 | *input_index_valid_size); | |
d0f40c50 | 956 | pr_debug("decode_isize = %d, in_copied %d\n", |
fffa1cca VK |
957 | str_info->decode_isize, *in_copied); |
958 | if (*input_index_valid_size <= | |
959 | (str_info->decode_isize - *in_copied)) | |
960 | cpy_size = *input_index_valid_size; | |
961 | else | |
962 | cpy_size = str_info->decode_isize - *in_copied; | |
963 | ||
d0f40c50 | 964 | pr_debug("cpy size = %d\n", cpy_size); |
fffa1cca | 965 | if (!dbufs->ibufs->buff_entry[i].buffer) { |
d0f40c50 | 966 | pr_err("i/p buffer is null\n"); |
fffa1cca VK |
967 | return -EINVAL; |
968 | } | |
d0f40c50 | 969 | pr_debug("Try copy To %p, From %p, size %d\n", |
fffa1cca VK |
970 | str_info->decode_ibuf + *in_copied, |
971 | dbufs->ibufs->buff_entry[i].buffer, cpy_size); | |
972 | ||
973 | retval = | |
974 | copy_from_user((void *)(str_info->decode_ibuf + *in_copied), | |
975 | (void *) dbufs->ibufs->buff_entry[i].buffer, | |
976 | cpy_size); | |
977 | if (retval) { | |
d0f40c50 | 978 | pr_err("copy from user failed\n"); |
fffa1cca VK |
979 | return -EIO; |
980 | } | |
981 | *in_copied += cpy_size; | |
982 | *input_index_valid_size -= cpy_size; | |
d0f40c50 | 983 | pr_debug("in buff size = %d, in_copied = %d\n", |
fffa1cca VK |
984 | *input_index_valid_size, *in_copied); |
985 | if (*input_index_valid_size != 0) { | |
d0f40c50 | 986 | pr_debug("more input buffers left\n"); |
fffa1cca VK |
987 | dbufs->ibufs->buff_entry[i].buffer += cpy_size; |
988 | break; | |
989 | } | |
990 | if (*in_copied == str_info->decode_isize && | |
991 | *input_index_valid_size == 0 && | |
992 | (i+1) <= dbufs->ibufs->entries) { | |
d0f40c50 | 993 | pr_debug("all input buffers copied\n"); |
fffa1cca VK |
994 | *new_entry_flag = true; |
995 | *input_index = i + 1; | |
996 | break; | |
997 | } | |
998 | } | |
999 | return retval; | |
1000 | } | |
1001 | ||
1002 | /* This function is used to copy the decoded data from kernel buffers to | |
1003 | the user output buffers with contents after decode*/ | |
1004 | static int sst_prepare_output_buffers(struct stream_info *str_info, | |
1005 | struct snd_sst_dbufs *dbufs, | |
1006 | int *output_index, int output_size, | |
1007 | int *out_copied) | |
1008 | ||
1009 | { | |
1010 | int i, cpy_size, retval = 0; | |
d0f40c50 | 1011 | pr_debug("output_index = %d, output entries = %d\n", |
fffa1cca VK |
1012 | *output_index, |
1013 | dbufs->obufs->entries); | |
1014 | for (i = *output_index; i < dbufs->obufs->entries; i++) { | |
1015 | *output_index = i; | |
d0f40c50 | 1016 | pr_debug("output addr = %p, size = %d\n", |
fffa1cca VK |
1017 | dbufs->obufs->buff_entry[i].buffer, |
1018 | dbufs->obufs->buff_entry[i].size); | |
d0f40c50 | 1019 | pr_debug("output_size = %d, out_copied = %d\n", |
fffa1cca VK |
1020 | output_size, *out_copied); |
1021 | if (dbufs->obufs->buff_entry[i].size < | |
1022 | (output_size - *out_copied)) | |
1023 | cpy_size = dbufs->obufs->buff_entry[i].size; | |
1024 | else | |
1025 | cpy_size = output_size - *out_copied; | |
d0f40c50 JP |
1026 | pr_debug("cpy size = %d\n", cpy_size); |
1027 | pr_debug("Try copy To: %p, From %p, size %d\n", | |
fffa1cca VK |
1028 | dbufs->obufs->buff_entry[i].buffer, |
1029 | sst_drv_ctx->mmap_mem + *out_copied, | |
1030 | cpy_size); | |
1031 | retval = copy_to_user(dbufs->obufs->buff_entry[i].buffer, | |
1032 | sst_drv_ctx->mmap_mem + *out_copied, | |
1033 | cpy_size); | |
1034 | if (retval) { | |
d0f40c50 | 1035 | pr_err("copy to user failed\n"); |
fffa1cca VK |
1036 | return -EIO; |
1037 | } else | |
d0f40c50 | 1038 | pr_debug("copy to user passed\n"); |
fffa1cca VK |
1039 | *out_copied += cpy_size; |
1040 | dbufs->obufs->buff_entry[i].size -= cpy_size; | |
d0f40c50 | 1041 | pr_debug("o/p buff size %d, out_copied %d\n", |
fffa1cca VK |
1042 | dbufs->obufs->buff_entry[i].size, *out_copied); |
1043 | if (dbufs->obufs->buff_entry[i].size != 0) { | |
1044 | *output_index = i; | |
1045 | dbufs->obufs->buff_entry[i].buffer += cpy_size; | |
1046 | break; | |
1047 | } else if (*out_copied == output_size) { | |
1048 | *output_index = i + 1; | |
1049 | break; | |
1050 | } | |
1051 | } | |
1052 | return retval; | |
1053 | } | |
1054 | ||
1055 | /** | |
1056 | * sst_decode - Send msg for decoding frames | |
1057 | * | |
1058 | * @str_id: ID of stream | |
1059 | * @dbufs: param that holds the user input and output buffers and size | |
1060 | * | |
1061 | * This function is called to decode data from the firmware | |
1062 | */ | |
1063 | int sst_decode(int str_id, struct snd_sst_dbufs *dbufs) | |
1064 | { | |
1065 | int retval = 0, i; | |
1066 | unsigned long long total_input = 0 , total_output = 0; | |
1067 | unsigned int cum_input_given = 0 , cum_output_given = 0; | |
1068 | int copy_in_done = false, copy_out_done = false; | |
1069 | int input_index = 0, output_index = 0; | |
1070 | int input_index_valid_size = 0; | |
1071 | int in_copied, out_copied; | |
1072 | int new_entry_flag; | |
1073 | u64 output_size; | |
1074 | struct stream_info *str_info; | |
1075 | struct snd_sst_decode_info dec_info; | |
1076 | unsigned long long input_bytes, output_bytes; | |
1077 | ||
1078 | sst_drv_ctx->scard_ops->power_down_pmic(); | |
d0f40c50 | 1079 | pr_debug("Powering_down_PMIC...\n"); |
fffa1cca VK |
1080 | |
1081 | retval = sst_validate_strid(str_id); | |
1082 | if (retval) | |
1083 | return retval; | |
1084 | ||
1085 | str_info = &sst_drv_ctx->streams[str_id]; | |
1086 | if (str_info->status != STREAM_INIT) { | |
d0f40c50 | 1087 | pr_err("invalid stream state = %d\n", |
fffa1cca VK |
1088 | str_info->status); |
1089 | return -EINVAL; | |
1090 | } | |
1091 | ||
1092 | str_info->prev = str_info->status; | |
1093 | str_info->status = STREAM_DECODE; | |
1094 | ||
1095 | for (i = 0; i < dbufs->ibufs->entries; i++) | |
1096 | cum_input_given += dbufs->ibufs->buff_entry[i].size; | |
1097 | for (i = 0; i < dbufs->obufs->entries; i++) | |
1098 | cum_output_given += dbufs->obufs->buff_entry[i].size; | |
1099 | ||
1100 | /* input and output buffer allocation */ | |
1101 | retval = sst_allocate_decode_buf(str_info, dbufs, | |
1102 | cum_input_given, cum_output_given); | |
1103 | if (retval) { | |
d0f40c50 | 1104 | pr_err("mem allocation failed, abort!!!\n"); |
fffa1cca VK |
1105 | retval = -ENOMEM; |
1106 | goto finish; | |
1107 | } | |
1108 | ||
1109 | str_info->decode_isize = str_info->idecode_alloc; | |
1110 | str_info->decode_ibuf_type = dbufs->ibufs->type; | |
1111 | str_info->decode_obuf_type = dbufs->obufs->type; | |
1112 | ||
1113 | while ((copy_out_done == false) && (copy_in_done == false)) { | |
1114 | in_copied = 0; | |
1115 | new_entry_flag = false; | |
1116 | retval = sst_prepare_input_buffers(str_info,\ | |
1117 | dbufs, &input_index, &in_copied, | |
1118 | &input_index_valid_size, &new_entry_flag); | |
1119 | if (retval) { | |
d0f40c50 | 1120 | pr_err("prepare in buffers failed\n"); |
fffa1cca VK |
1121 | goto finish; |
1122 | } | |
1123 | ||
1124 | if (str_info->ops != STREAM_OPS_PLAYBACK_DRM) | |
1125 | str_info->decode_obuf = sst_drv_ctx->mmap_mem; | |
1126 | ||
1127 | #ifdef CONFIG_MRST_RAR_HANDLER | |
1128 | else { | |
1129 | if (dbufs->obufs->type == SST_BUF_RAR) { | |
1130 | struct RAR_buffer rar_buffers; | |
1131 | __u32 info; | |
1132 | ||
1133 | pr_debug("DRM"); | |
1134 | retval = copy_from_user((void *) &info, | |
1135 | dbufs->obufs-> | |
1136 | buff_entry[output_index].buffer, | |
1137 | sizeof(__u32)); | |
1138 | ||
1139 | rar_buffers.info.size = dbufs->obufs-> | |
1140 | buff_entry[output_index].size; | |
1141 | rar_buffers.info.handle = info; | |
1142 | retval = sst_get_RAR(&rar_buffers, 1); | |
1143 | if (retval) | |
1144 | return retval; | |
1145 | ||
1146 | str_info->decode_obuf = (void *)((unsigned long) | |
1147 | rar_buffers.bus_address); | |
1148 | str_info->decode_osize = dbufs->obufs-> | |
1149 | buff_entry[output_index].size; | |
1150 | str_info->decode_obuf_type = dbufs->obufs->type; | |
d0f40c50 JP |
1151 | pr_debug("DRM handling\n"); |
1152 | pr_debug("o/p_add=0x%lu Size=0x%x\n", | |
fffa1cca VK |
1153 | (unsigned long) str_info->decode_obuf, |
1154 | str_info->decode_osize); | |
1155 | } else { | |
1156 | str_info->decode_obuf = sst_drv_ctx->mmap_mem; | |
1157 | str_info->decode_osize = dbufs->obufs-> | |
1158 | buff_entry[output_index].size; | |
1159 | ||
1160 | } | |
1161 | } | |
1162 | #endif | |
1163 | if (str_info->ops != STREAM_OPS_PLAYBACK_DRM) { | |
1164 | if (str_info->decode_isize > in_copied) { | |
1165 | str_info->decode_isize = in_copied; | |
d0f40c50 | 1166 | pr_debug("i/p size = %d\n", |
fffa1cca VK |
1167 | str_info->decode_isize); |
1168 | } | |
1169 | } | |
1170 | ||
1171 | ||
1172 | retval = sst_send_decode_mess(str_id, str_info, &dec_info); | |
1173 | if (retval || dec_info.input_bytes_consumed == 0) { | |
d0f40c50 | 1174 | pr_err("SST ERR: mess failed or no input consumed\n"); |
fffa1cca VK |
1175 | goto finish; |
1176 | } | |
1177 | input_bytes = dec_info.input_bytes_consumed; | |
1178 | output_bytes = dec_info.output_bytes_produced; | |
1179 | ||
d0f40c50 | 1180 | pr_debug("in_copied=%d, con=%lld, prod=%lld\n", |
fffa1cca VK |
1181 | in_copied, input_bytes, output_bytes); |
1182 | if (dbufs->obufs->type == SST_BUF_RAR) { | |
1183 | output_index += 1; | |
1184 | if (output_index == dbufs->obufs->entries) { | |
1185 | copy_in_done = true; | |
d0f40c50 | 1186 | pr_debug("all i/p cpy done\n"); |
fffa1cca VK |
1187 | } |
1188 | total_output += output_bytes; | |
1189 | } else { | |
1190 | out_copied = 0; | |
1191 | output_size = output_bytes; | |
1192 | retval = sst_prepare_output_buffers(str_info, dbufs, | |
1193 | &output_index, output_size, &out_copied); | |
1194 | if (retval) { | |
d0f40c50 | 1195 | pr_err("prep out buff fail\n"); |
fffa1cca VK |
1196 | goto finish; |
1197 | } | |
1198 | if (str_info->ops != STREAM_OPS_PLAYBACK_DRM) { | |
1199 | if (in_copied != input_bytes) { | |
1200 | int bytes_left = in_copied - | |
1201 | input_bytes; | |
d0f40c50 | 1202 | pr_debug("bytes %d\n", |
fffa1cca VK |
1203 | bytes_left); |
1204 | if (new_entry_flag == true) | |
1205 | input_index--; | |
1206 | while (bytes_left) { | |
1207 | struct snd_sst_buffs *ibufs; | |
1208 | struct snd_sst_buff_entry | |
1209 | *buff_entry; | |
1210 | unsigned int size_sent; | |
1211 | ||
1212 | ibufs = dbufs->ibufs; | |
1213 | buff_entry = | |
1214 | &ibufs->buff_entry[input_index]; | |
1215 | size_sent = buff_entry->size -\ | |
1216 | input_index_valid_size; | |
1217 | if (bytes_left == size_sent) { | |
1218 | bytes_left = 0; | |
1219 | } else if (bytes_left < | |
1220 | size_sent) { | |
1221 | buff_entry->buffer += | |
1222 | (size_sent - | |
1223 | bytes_left); | |
1224 | buff_entry->size -= | |
1225 | (size_sent - | |
1226 | bytes_left); | |
1227 | bytes_left = 0; | |
1228 | } else { | |
1229 | bytes_left -= size_sent; | |
1230 | input_index--; | |
1231 | input_index_valid_size = | |
1232 | 0; | |
1233 | } | |
1234 | } | |
1235 | ||
1236 | } | |
1237 | } | |
1238 | ||
1239 | total_output += out_copied; | |
1240 | if (str_info->decode_osize != out_copied) { | |
1241 | str_info->decode_osize -= out_copied; | |
d0f40c50 | 1242 | pr_debug("output size modified = %d\n", |
fffa1cca VK |
1243 | str_info->decode_osize); |
1244 | } | |
1245 | } | |
1246 | total_input += input_bytes; | |
1247 | ||
1248 | if (str_info->ops == STREAM_OPS_PLAYBACK_DRM) { | |
1249 | if (total_input == cum_input_given) | |
1250 | copy_in_done = true; | |
1251 | copy_out_done = true; | |
1252 | ||
1253 | } else { | |
1254 | if (total_output == cum_output_given) { | |
1255 | copy_out_done = true; | |
d0f40c50 | 1256 | pr_debug("all o/p cpy done\n"); |
fffa1cca VK |
1257 | } |
1258 | ||
1259 | if (total_input == cum_input_given) { | |
1260 | copy_in_done = true; | |
d0f40c50 | 1261 | pr_debug("all i/p cpy done\n"); |
fffa1cca VK |
1262 | } |
1263 | } | |
1264 | ||
d0f40c50 | 1265 | pr_debug("copy_out = %d, copy_in = %d\n", |
fffa1cca VK |
1266 | copy_out_done, copy_in_done); |
1267 | } | |
1268 | ||
1269 | finish: | |
1270 | dbufs->input_bytes_consumed = total_input; | |
1271 | dbufs->output_bytes_produced = total_output; | |
1272 | str_info->status = str_info->prev; | |
1273 | str_info->prev = STREAM_DECODE; | |
fffa1cca | 1274 | kfree(str_info->decode_ibuf); |
3251627c | 1275 | str_info->decode_ibuf = NULL; |
fffa1cca VK |
1276 | return retval; |
1277 | } |