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