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
29 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
30
31 #include <linux/pci.h>
32 #include <linux/firmware.h>
33 #include <linux/sched.h>
34 #include "intel_sst_ioctl.h"
35 #include "intel_sst.h"
36 #include "intel_sst_fw_ipc.h"
37 #include "intel_sst_common.h"
38
39 /*
40 * sst_check_device_type - Check the medfield device type
41 *
42 * @device: Device to be checked
43 * @num_ch: Number of channels queried
44 * @pcm_slot: slot to be enabled for this device
45 *
46 * This checks the deivce against the map and calculates pcm_slot value
47 */
sst_check_device_type(u32 device,u32 num_chan,u32 * pcm_slot)48 int sst_check_device_type(u32 device, u32 num_chan, u32 *pcm_slot)
49 {
50 if (device > MAX_NUM_STREAMS_MFLD) {
51 pr_debug("device type invalid %d\n", device);
52 return -EINVAL;
53 }
54 if (sst_drv_ctx->streams[device].status == STREAM_UN_INIT) {
55 if (device == SND_SST_DEVICE_VIBRA && num_chan == 1)
56 *pcm_slot = 0x10;
57 else if (device == SND_SST_DEVICE_HAPTIC && num_chan == 1)
58 *pcm_slot = 0x20;
59 else if (device == SND_SST_DEVICE_IHF && num_chan == 1)
60 *pcm_slot = 0x04;
61 else if (device == SND_SST_DEVICE_IHF && num_chan == 2)
62 *pcm_slot = 0x0C;
63 else if (device == SND_SST_DEVICE_HEADSET && num_chan == 1)
64 *pcm_slot = 0x01;
65 else if (device == SND_SST_DEVICE_HEADSET && num_chan == 2)
66 *pcm_slot = 0x03;
67 else if (device == SND_SST_DEVICE_CAPTURE && num_chan == 1)
68 *pcm_slot = 0x01;
69 else if (device == SND_SST_DEVICE_CAPTURE && num_chan == 2)
70 *pcm_slot = 0x03;
71 else if (device == SND_SST_DEVICE_CAPTURE && num_chan == 3)
72 *pcm_slot = 0x07;
73 else if (device == SND_SST_DEVICE_CAPTURE && num_chan == 4)
74 *pcm_slot = 0x0F;
75 else {
76 pr_debug("No condition satisfied.. ret err\n");
77 return -EINVAL;
78 }
79 } else {
80 pr_debug("this stream state is not uni-init, is %d\n",
81 sst_drv_ctx->streams[device].status);
82 return -EBADRQC;
83 }
84 pr_debug("returning slot %x\n", *pcm_slot);
85 return 0;
86 }
87 /**
88 * get_mrst_stream_id - gets a new stream id for use
89 *
90 * This functions searches the current streams and allocated an empty stream
91 * lock stream_lock required to be held before calling this
92 */
get_mrst_stream_id(void)93 static unsigned int get_mrst_stream_id(void)
94 {
95 int i;
96
97 for (i = 1; i <= MAX_NUM_STREAMS_MRST; i++) {
98 if (sst_drv_ctx->streams[i].status == STREAM_UN_INIT)
99 return i;
100 }
101 pr_debug("Didn't find empty stream for mrst\n");
102 return -EBUSY;
103 }
104
105 /**
106 * sst_alloc_stream - Send msg for a new stream ID
107 *
108 * @params: stream params
109 * @stream_ops: operation of stream PB/capture
110 * @codec: codec for stream
111 * @device: device stream to be allocated for
112 *
113 * This function is called by any function which wants to start
114 * a new stream. This also check if a stream exists which is idle
115 * it initializes idle stream id to this request
116 */
sst_alloc_stream(char * params,unsigned int stream_ops,u8 codec,unsigned int device)117 int sst_alloc_stream(char *params, unsigned int stream_ops,
118 u8 codec, unsigned int device)
119 {
120 struct ipc_post *msg = NULL;
121 struct snd_sst_alloc_params alloc_param;
122 unsigned int pcm_slot = 0, num_ch;
123 int str_id;
124 struct snd_sst_stream_params *sparams;
125 struct stream_info *str_info;
126
127 pr_debug("SST DBG:entering sst_alloc_stream\n");
128 pr_debug("SST DBG:%d %d %d\n", stream_ops, codec, device);
129
130 BUG_ON(!params);
131 sparams = (struct snd_sst_stream_params *)params;
132 num_ch = sparams->uc.pcm_params.num_chan;
133 /*check the device type*/
134 if (sst_drv_ctx->pci_id == SST_MFLD_PCI_ID) {
135 if (sst_check_device_type(device, num_ch, &pcm_slot))
136 return -EINVAL;
137 mutex_lock(&sst_drv_ctx->stream_lock);
138 str_id = device;
139 mutex_unlock(&sst_drv_ctx->stream_lock);
140 pr_debug("SST_DBG: slot %x\n", pcm_slot);
141 } else {
142 mutex_lock(&sst_drv_ctx->stream_lock);
143 str_id = get_mrst_stream_id();
144 mutex_unlock(&sst_drv_ctx->stream_lock);
145 if (str_id <= 0)
146 return -EBUSY;
147 }
148 /*allocate device type context*/
149 sst_init_stream(&sst_drv_ctx->streams[str_id], codec,
150 str_id, stream_ops, pcm_slot, device);
151 /* send msg to FW to allocate a stream */
152 if (sst_create_large_msg(&msg))
153 return -ENOMEM;
154
155 sst_fill_header(&msg->header, IPC_IA_ALLOC_STREAM, 1, str_id);
156 msg->header.part.data = sizeof(alloc_param) + sizeof(u32);
157 alloc_param.str_type.codec_type = codec;
158 alloc_param.str_type.str_type = SST_STREAM_TYPE_MUSIC;
159 alloc_param.str_type.operation = stream_ops;
160 alloc_param.str_type.protected_str = 0; /* non drm */
161 alloc_param.str_type.time_slots = pcm_slot;
162 alloc_param.str_type.result = alloc_param.str_type.reserved = 0;
163 memcpy(&alloc_param.stream_params, params,
164 sizeof(struct snd_sst_stream_params));
165
166 memcpy(msg->mailbox_data, &msg->header, sizeof(u32));
167 memcpy(msg->mailbox_data + sizeof(u32), &alloc_param,
168 sizeof(alloc_param));
169 str_info = &sst_drv_ctx->streams[str_id];
170 str_info->ctrl_blk.condition = false;
171 str_info->ctrl_blk.ret_code = 0;
172 str_info->ctrl_blk.on = true;
173 spin_lock(&sst_drv_ctx->list_spin_lock);
174 list_add_tail(&msg->node, &sst_drv_ctx->ipc_dispatch_list);
175 spin_unlock(&sst_drv_ctx->list_spin_lock);
176 sst_post_message(&sst_drv_ctx->ipc_post_msg_wq);
177 pr_debug("SST DBG:alloc stream done\n");
178 return str_id;
179 }
180
181
182 /*
183 * sst_alloc_stream_response - process alloc reply
184 *
185 * @str_id: stream id for which the stream has been allocated
186 * @resp the stream response from firware
187 *
188 * This function is called by firmware as a response to stream allcoation
189 * request
190 */
sst_alloc_stream_response(unsigned int str_id,struct snd_sst_alloc_response * resp)191 int sst_alloc_stream_response(unsigned int str_id,
192 struct snd_sst_alloc_response *resp)
193 {
194 int retval = 0;
195 struct stream_info *str_info;
196 struct snd_sst_lib_download *lib_dnld;
197
198 pr_debug("SST DEBUG: stream number given = %d\n", str_id);
199 str_info = &sst_drv_ctx->streams[str_id];
200 if (resp->str_type.result == SST_LIB_ERR_LIB_DNLD_REQUIRED) {
201 lib_dnld = kzalloc(sizeof(*lib_dnld), GFP_KERNEL);
202 memcpy(lib_dnld, &resp->lib_dnld, sizeof(*lib_dnld));
203 } else
204 lib_dnld = NULL;
205 if (str_info->ctrl_blk.on == true) {
206 str_info->ctrl_blk.on = false;
207 str_info->ctrl_blk.data = lib_dnld;
208 str_info->ctrl_blk.condition = true;
209 str_info->ctrl_blk.ret_code = resp->str_type.result;
210 pr_debug("SST DEBUG: sst_alloc_stream_response: waking up.\n");
211 wake_up(&sst_drv_ctx->wait_queue);
212 }
213 return retval;
214 }
215
216
217 /**
218 * sst_get_fw_info - Send msg to query for firmware configurations
219 * @info: out param that holds the firmare configurations
220 *
221 * This function is called when the firmware configurations are queiried for
222 */
sst_get_fw_info(struct snd_sst_fw_info * info)223 int sst_get_fw_info(struct snd_sst_fw_info *info)
224 {
225 int retval = 0;
226 struct ipc_post *msg = NULL;
227
228 pr_debug("SST DBG:sst_get_fw_info called\n");
229
230 if (sst_create_short_msg(&msg)) {
231 pr_err("SST ERR: message creation failed\n");
232 return -ENOMEM;
233 }
234
235 sst_fill_header(&msg->header, IPC_IA_GET_FW_INFO, 0, 0);
236 sst_drv_ctx->fw_info_blk.condition = false;
237 sst_drv_ctx->fw_info_blk.ret_code = 0;
238 sst_drv_ctx->fw_info_blk.on = true;
239 sst_drv_ctx->fw_info_blk.data = info;
240 spin_lock(&sst_drv_ctx->list_spin_lock);
241 list_add_tail(&msg->node, &sst_drv_ctx->ipc_dispatch_list);
242 spin_unlock(&sst_drv_ctx->list_spin_lock);
243 sst_post_message(&sst_drv_ctx->ipc_post_msg_wq);
244 retval = sst_wait_interruptible_timeout(sst_drv_ctx,
245 &sst_drv_ctx->fw_info_blk, SST_BLOCK_TIMEOUT);
246 if (retval) {
247 pr_err("SST ERR: error in fw_info = %d\n", retval);
248 retval = -EIO;
249 }
250 return retval;
251 }
252
253
254 /**
255 * sst_pause_stream - Send msg for a pausing stream
256 * @str_id: stream ID
257 *
258 * This function is called by any function which wants to pause
259 * an already running stream.
260 */
sst_start_stream(int str_id)261 int sst_start_stream(int str_id)
262 {
263 int retval = 0;
264 struct ipc_post *msg = NULL;
265 struct stream_info *str_info;
266
267 pr_debug("sst_start_stream for %d\n", str_id);
268 retval = sst_validate_strid(str_id);
269 if (retval)
270 return retval;
271 str_info = &sst_drv_ctx->streams[str_id];
272 if (str_info->status != STREAM_INIT)
273 return -EBADRQC;
274 if (sst_create_short_msg(&msg))
275 return -ENOMEM;
276
277 sst_fill_header(&msg->header, IPC_IA_START_STREAM, 0, str_id);
278 spin_lock(&sst_drv_ctx->list_spin_lock);
279 list_add_tail(&msg->node, &sst_drv_ctx->ipc_dispatch_list);
280 spin_unlock(&sst_drv_ctx->list_spin_lock);
281 sst_post_message(&sst_drv_ctx->ipc_post_msg_wq);
282 return retval;
283 }
284
285 /*
286 * sst_pause_stream - Send msg for a pausing stream
287 * @str_id: stream ID
288 *
289 * This function is called by any function which wants to pause
290 * an already running stream.
291 */
sst_pause_stream(int str_id)292 int sst_pause_stream(int str_id)
293 {
294 int retval = 0;
295 struct ipc_post *msg = NULL;
296 struct stream_info *str_info;
297
298 pr_debug("SST DBG:sst_pause_stream for %d\n", str_id);
299 retval = sst_validate_strid(str_id);
300 if (retval)
301 return retval;
302 str_info = &sst_drv_ctx->streams[str_id];
303 if (str_info->status == STREAM_PAUSED)
304 return 0;
305 if (str_info->status == STREAM_RUNNING ||
306 str_info->status == STREAM_INIT) {
307 if (str_info->prev == STREAM_UN_INIT)
308 return -EBADRQC;
309 if (str_info->ctrl_blk.on == true) {
310 pr_err("SST ERR: control path is in use\n");
311 return -EINVAL;
312 }
313 if (sst_create_short_msg(&msg))
314 return -ENOMEM;
315
316 sst_fill_header(&msg->header, IPC_IA_PAUSE_STREAM, 0, str_id);
317 str_info->ctrl_blk.condition = false;
318 str_info->ctrl_blk.ret_code = 0;
319 str_info->ctrl_blk.on = true;
320 spin_lock(&sst_drv_ctx->list_spin_lock);
321 list_add_tail(&msg->node,
322 &sst_drv_ctx->ipc_dispatch_list);
323 spin_unlock(&sst_drv_ctx->list_spin_lock);
324 sst_post_message(&sst_drv_ctx->ipc_post_msg_wq);
325 retval = sst_wait_interruptible_timeout(sst_drv_ctx,
326 &str_info->ctrl_blk, SST_BLOCK_TIMEOUT);
327 if (retval == 0) {
328 str_info->prev = str_info->status;
329 str_info->status = STREAM_PAUSED;
330 } else if (retval == SST_ERR_INVALID_STREAM_ID) {
331 retval = -EINVAL;
332 mutex_lock(&sst_drv_ctx->stream_lock);
333 sst_clean_stream(str_info);
334 mutex_unlock(&sst_drv_ctx->stream_lock);
335 }
336 } else {
337 retval = -EBADRQC;
338 pr_err("SST ERR: BADQRC for stream\n");
339 }
340
341 return retval;
342 }
343
344 /**
345 * sst_resume_stream - Send msg for resuming stream
346 * @str_id: stream ID
347 *
348 * This function is called by any function which wants to resume
349 * an already paused stream.
350 */
sst_resume_stream(int str_id)351 int sst_resume_stream(int str_id)
352 {
353 int retval = 0;
354 struct ipc_post *msg = NULL;
355 struct stream_info *str_info;
356
357 pr_debug("SST DBG:sst_resume_stream for %d\n", str_id);
358 retval = sst_validate_strid(str_id);
359 if (retval)
360 return retval;
361 str_info = &sst_drv_ctx->streams[str_id];
362 if (str_info->status == STREAM_RUNNING)
363 return 0;
364 if (str_info->status == STREAM_PAUSED) {
365 if (str_info->ctrl_blk.on == true) {
366 pr_err("SST ERR: control path in use\n");
367 return -EINVAL;
368 }
369 if (sst_create_short_msg(&msg)) {
370 pr_err("SST ERR: mem allocation failed\n");
371 return -ENOMEM;
372 }
373 sst_fill_header(&msg->header, IPC_IA_RESUME_STREAM, 0, str_id);
374 str_info->ctrl_blk.condition = false;
375 str_info->ctrl_blk.ret_code = 0;
376 str_info->ctrl_blk.on = true;
377 spin_lock(&sst_drv_ctx->list_spin_lock);
378 list_add_tail(&msg->node,
379 &sst_drv_ctx->ipc_dispatch_list);
380 spin_unlock(&sst_drv_ctx->list_spin_lock);
381 sst_post_message(&sst_drv_ctx->ipc_post_msg_wq);
382 retval = sst_wait_interruptible_timeout(sst_drv_ctx,
383 &str_info->ctrl_blk, SST_BLOCK_TIMEOUT);
384 if (!retval) {
385 if (str_info->prev == STREAM_RUNNING)
386 str_info->status = STREAM_RUNNING;
387 else
388 str_info->status = STREAM_INIT;
389 str_info->prev = STREAM_PAUSED;
390 } else if (retval == -SST_ERR_INVALID_STREAM_ID) {
391 retval = -EINVAL;
392 mutex_lock(&sst_drv_ctx->stream_lock);
393 sst_clean_stream(str_info);
394 mutex_unlock(&sst_drv_ctx->stream_lock);
395 }
396 } else {
397 retval = -EBADRQC;
398 pr_err("SST ERR: BADQRC for stream\n");
399 }
400
401 return retval;
402 }
403
404
405 /**
406 * sst_drop_stream - Send msg for stopping stream
407 * @str_id: stream ID
408 *
409 * This function is called by any function which wants to stop
410 * a stream.
411 */
sst_drop_stream(int str_id)412 int sst_drop_stream(int str_id)
413 {
414 int retval = 0;
415 struct ipc_post *msg = NULL;
416 struct sst_stream_bufs *bufs = NULL, *_bufs;
417 struct stream_info *str_info;
418
419 pr_debug("SST DBG:sst_drop_stream for %d\n", str_id);
420 retval = sst_validate_strid(str_id);
421 if (retval)
422 return retval;
423 str_info = &sst_drv_ctx->streams[str_id];
424
425 if (str_info->status != STREAM_UN_INIT &&
426 str_info->status != STREAM_DECODE) {
427 if (str_info->ctrl_blk.on == true) {
428 pr_err("SST ERR: control path in use\n");
429 return -EINVAL;
430 }
431 if (sst_create_short_msg(&msg)) {
432 pr_err("SST ERR: mem allocation failed\n");
433 return -ENOMEM;
434 }
435 sst_fill_header(&msg->header, IPC_IA_DROP_STREAM, 0, str_id);
436 str_info->ctrl_blk.condition = false;
437 str_info->ctrl_blk.ret_code = 0;
438 str_info->ctrl_blk.on = true;
439 spin_lock(&sst_drv_ctx->list_spin_lock);
440 list_add_tail(&msg->node,
441 &sst_drv_ctx->ipc_dispatch_list);
442 spin_unlock(&sst_drv_ctx->list_spin_lock);
443 sst_post_message(&sst_drv_ctx->ipc_post_msg_wq);
444 retval = sst_wait_interruptible_timeout(sst_drv_ctx,
445 &str_info->ctrl_blk, SST_BLOCK_TIMEOUT);
446 if (!retval) {
447 pr_debug("SST DBG:drop success\n");
448 str_info->prev = STREAM_UN_INIT;
449 str_info->status = STREAM_INIT;
450 if (str_info->src != MAD_DRV) {
451 mutex_lock(&str_info->lock);
452 list_for_each_entry_safe(bufs, _bufs,
453 &str_info->bufs, node) {
454 list_del(&bufs->node);
455 kfree(bufs);
456 }
457 mutex_unlock(&str_info->lock);
458 }
459 str_info->cumm_bytes += str_info->curr_bytes;
460 } else if (retval == -SST_ERR_INVALID_STREAM_ID) {
461 retval = -EINVAL;
462 mutex_lock(&sst_drv_ctx->stream_lock);
463 sst_clean_stream(str_info);
464 mutex_unlock(&sst_drv_ctx->stream_lock);
465 }
466 if (str_info->data_blk.on == true) {
467 str_info->data_blk.condition = true;
468 str_info->data_blk.ret_code = retval;
469 wake_up(&sst_drv_ctx->wait_queue);
470 }
471 } else {
472 retval = -EBADRQC;
473 pr_err("SST ERR: BADQRC for stream\n");
474 }
475 return retval;
476 }
477
478 /**
479 * sst_drain_stream - Send msg for draining stream
480 * @str_id: stream ID
481 *
482 * This function is called by any function which wants to drain
483 * a stream.
484 */
sst_drain_stream(int str_id)485 int sst_drain_stream(int str_id)
486 {
487 int retval = 0;
488 struct ipc_post *msg = NULL;
489 struct stream_info *str_info;
490
491 pr_debug("SST DBG:sst_drain_stream for %d\n", str_id);
492 retval = sst_validate_strid(str_id);
493 if (retval)
494 return retval;
495 str_info = &sst_drv_ctx->streams[str_id];
496
497 if (str_info->status != STREAM_RUNNING &&
498 str_info->status != STREAM_INIT &&
499 str_info->status != STREAM_PAUSED) {
500 pr_err("SST ERR: BADQRC for stream = %d\n",
501 str_info->status);
502 return -EBADRQC;
503 }
504
505 if (str_info->status == STREAM_INIT) {
506 if (sst_create_short_msg(&msg)) {
507 pr_err("SST ERR: mem allocation failed\n");
508 return -ENOMEM;
509 }
510 sst_fill_header(&msg->header, IPC_IA_DRAIN_STREAM, 0, str_id);
511 spin_lock(&sst_drv_ctx->list_spin_lock);
512 list_add_tail(&msg->node, &sst_drv_ctx->ipc_dispatch_list);
513 spin_unlock(&sst_drv_ctx->list_spin_lock);
514 sst_post_message(&sst_drv_ctx->ipc_post_msg_wq);
515 } else
516 str_info->need_draining = true;
517 str_info->data_blk.condition = false;
518 str_info->data_blk.ret_code = 0;
519 str_info->data_blk.on = true;
520 retval = sst_wait_interruptible(sst_drv_ctx, &str_info->data_blk);
521 str_info->need_draining = false;
522 if (retval == -SST_ERR_INVALID_STREAM_ID) {
523 retval = -EINVAL;
524 sst_clean_stream(str_info);
525 }
526 return retval;
527 }
528
529 /**
530 * sst_free_stream - Frees a stream
531 * @str_id: stream ID
532 *
533 * This function is called by any function which wants to free
534 * a stream.
535 */
sst_free_stream(int str_id)536 int sst_free_stream(int str_id)
537 {
538 int retval = 0;
539 struct ipc_post *msg = NULL;
540 struct stream_info *str_info;
541
542 pr_debug("SST DBG:sst_free_stream for %d\n", str_id);
543
544 retval = sst_validate_strid(str_id);
545 if (retval)
546 return retval;
547 str_info = &sst_drv_ctx->streams[str_id];
548
549 if (str_info->status != STREAM_UN_INIT) {
550 if (sst_create_short_msg(&msg)) {
551 pr_err("SST ERR: mem allocation failed\n");
552 return -ENOMEM;
553 }
554 sst_fill_header(&msg->header, IPC_IA_FREE_STREAM, 0, str_id);
555 spin_lock(&sst_drv_ctx->list_spin_lock);
556 list_add_tail(&msg->node, &sst_drv_ctx->ipc_dispatch_list);
557 spin_unlock(&sst_drv_ctx->list_spin_lock);
558 sst_post_message(&sst_drv_ctx->ipc_post_msg_wq);
559 str_info->prev = str_info->status;
560 str_info->status = STREAM_UN_INIT;
561 if (str_info->data_blk.on == true) {
562 str_info->data_blk.condition = true;
563 str_info->data_blk.ret_code = 0;
564 wake_up(&sst_drv_ctx->wait_queue);
565 }
566 mutex_lock(&sst_drv_ctx->stream_lock);
567 sst_clean_stream(str_info);
568 mutex_unlock(&sst_drv_ctx->stream_lock);
569 pr_debug("SST DBG:Stream freed\n");
570 } else {
571 retval = -EBADRQC;
572 pr_debug("SST DBG:BADQRC for stream\n");
573 }
574
575 return retval;
576 }
577
578
579